[Pkg-voip-commits] [asterisk] 01/03: Imported Upstream version 11.20.0~dfsg

Jeremy Lainé sharky at moszumanska.debian.org
Tue Dec 8 11:45:52 UTC 2015


This is an automated email from the git hooks/post-receive script.

sharky pushed a commit to branch review-ast1120
in repository asterisk.

commit cd6900cd75800234a352084b2fafd5ebc76838b6
Author: Jeremy Lainé <jeremy.laine at m4x.org>
Date:   Mon Dec 7 20:41:44 2015 +0100

    Imported Upstream version 11.20.0~dfsg
---
 .gitignore                                         |    36 +
 .gitreview                                         |     4 +
 .version                                           |     2 +-
 CHANGES                                            |  2013 +-
 CREDITS                                            |   398 +-
 ChangeLog                                          | 55872 ++++++++++++-------
 LICENSE                                            |    18 +-
 Makefile                                           |   190 +-
 Makefile.moddir_rules                              |     3 +-
 Makefile.rules                                     |    14 +-
 README                                             |     6 +-
 README-SERIOUSLY.bestpractices.txt                 |     3 +-
 UPGRADE-11.txt                                     |   280 -
 UPGRADE-12.txt                                     |   478 -
 UPGRADE.txt                                        |   769 +-
 addons/.gitignore                                  |     1 +
 addons/Makefile                                    |     3 +-
 addons/app_mysql.c                                 |    76 +-
 addons/app_saycountpl.c                            |   138 +
 addons/cdr_mysql.c                                 |    25 +-
 addons/chan_mobile.c                               |   264 +-
 addons/chan_ooh323.c                               |   500 +-
 addons/chan_ooh323.h                               |     5 +-
 addons/format_mp3.c                                |    11 +-
 addons/ooh323c/src/ooSocket.c                      |     2 +-
 addons/ooh323c/src/ooh245.c                        |     2 +-
 addons/ooh323c/src/ooq931.c                        |     6 +-
 addons/ooh323c/src/printHandler.c                  |     2 +-
 addons/ooh323cDriver.c                             |   159 +-
 addons/ooh323cDriver.h                             |     6 +-
 addons/res_config_mysql.c                          |   267 +-
 agi/.gitignore                                     |     3 +
 agi/Makefile                                       |     2 +-
 apps/Makefile                                      |     7 +-
 apps/app_adsiprog.c                                |    24 +-
 apps/app_agent_pool.c                              |  2707 -
 apps/app_alarmreceiver.c                           |  1016 +-
 apps/app_amd.c                                     |    47 +-
 apps/app_authenticate.c                            |    10 +-
 apps/app_bridgewait.c                              |   514 -
 apps/app_cdr.c                                     |   212 +-
 apps/app_celgenuserevent.c                         |    12 +-
 apps/app_chanisavail.c                             |     7 +-
 apps/app_channelredirect.c                         |     6 +-
 apps/app_chanspy.c                                 |   207 +-
 apps/app_confbridge.c                              |  2342 +-
 apps/app_controlplayback.c                         |   129 +-
 apps/app_dahdibarge.c                              |   311 +
 apps/app_dahdiras.c                                |     9 +-
 apps/app_db.c                                      |     2 +-
 apps/app_dial.c                                    |   410 +-
 apps/app_dictate.c                                 |    23 +-
 apps/app_directed_pickup.c                         |   208 +-
 apps/app_directory.c                               |   142 +-
 apps/app_disa.c                                    |    18 +-
 apps/app_dumpchan.c                                |    39 +-
 apps/app_echo.c                                    |     7 +-
 apps/app_exec.c                                    |     2 +-
 apps/app_externalivr.c                             |     7 +-
 apps/app_fax.c                                     |   104 +-
 apps/app_festival.c                                |    50 +-
 apps/app_flash.c                                   |     2 +-
 apps/app_followme.c                                |   101 +-
 apps/app_forkcdr.c                                 |   288 +-
 apps/app_getcpeid.c                                |    13 +-
 apps/app_ices.c                                    |    21 +-
 apps/app_image.c                                   |     5 +-
 apps/app_ivrdemo.c                                 |     5 +-
 apps/app_jack.c                                    |    70 +-
 apps/app_macro.c                                   |    38 +-
 apps/app_meetme.c                                  |   648 +-
 apps/app_milliwatt.c                               |    17 +-
 apps/app_minivm.c                                  |    79 +-
 apps/app_mixmonitor.c                              |   327 +-
 apps/app_morsecode.c                               |     5 +-
 apps/app_mp3.c                                     |    36 +-
 apps/app_nbscat.c                                  |    37 +-
 apps/app_originate.c                               |    35 +-
 apps/app_osplookup.c                               |   118 +-
 apps/app_page.c                                    |    44 +-
 apps/app_parkandannounce.c                         |   249 +
 apps/app_playback.c                                |    20 +-
 apps/app_playtones.c                               |     2 +-
 apps/app_privacy.c                                 |     2 +-
 apps/app_queue.c                                   |  3392 +-
 apps/app_read.c                                    |     2 +-
 apps/app_readexten.c                               |     2 +-
 apps/app_readfile.c                                |   134 +
 apps/app_record.c                                  |    69 +-
 apps/app_saycounted.c                              |     5 +-
 apps/app_sayunixtime.c                             |    16 +-
 apps/app_senddtmf.c                                |    17 +-
 apps/app_sendtext.c                                |     2 +-
 apps/app_setcallerid.c                             |     5 +-
 apps/app_skel.c                                    |    72 +-
 apps/app_sms.c                                     |    36 +-
 apps/app_softhangup.c                              |     2 +-
 apps/app_speech_utils.c                            |    31 +-
 apps/app_stack.c                                   |    90 +-
 apps/app_stasis.c                                  |   114 -
 apps/app_system.c                                  |     2 +-
 apps/app_talkdetect.c                              |    21 +-
 apps/app_test.c                                    |    22 +-
 apps/app_transfer.c                                |     2 +-
 apps/app_url.c                                     |     5 +-
 apps/app_userevent.c                               |    77 +-
 apps/app_verbose.c                                 |     2 +-
 apps/app_voicemail.c                               |   957 +-
 apps/app_waitforring.c                             |     5 +-
 apps/app_waitforsilence.c                          |    18 +-
 apps/app_waituntil.c                               |     2 +-
 apps/app_while.c                                   |     2 +-
 apps/app_zapateller.c                              |     5 +-
 apps/confbridge/conf_chan_announce.c               |   210 -
 apps/confbridge/conf_chan_record.c                 |   104 -
 apps/confbridge/conf_config_parser.c               |   907 +-
 apps/confbridge/conf_state.c                       |    40 +-
 apps/confbridge/conf_state_empty.c                 |    44 +-
 apps/confbridge/conf_state_inactive.c              |    41 +-
 apps/confbridge/conf_state_multi.c                 |    39 +-
 apps/confbridge/conf_state_multi_marked.c          |   146 +-
 apps/confbridge/conf_state_single.c                |    50 +-
 apps/confbridge/conf_state_single_marked.c         |    46 +-
 apps/confbridge/confbridge_manager.c               |   549 -
 apps/confbridge/include/conf_state.h               |    36 +-
 apps/confbridge/include/confbridge.h               |   307 +-
 asterisk-11.20.0-summary.html                      |   126 +
 asterisk-11.20.0-summary.txt                       |   399 +
 asterisk-13.1.1-summary.html                       |    65 -
 asterisk-13.1.1-summary.txt                        |    96 -
 autoconf/ast_check_raii.m4                         |    56 +
 autoconf/ast_check_strsep_array_bounds.m4          |    81 +
 autoconf/ast_ext_tool_check.m4                     |     1 -
 autoconf/ast_gcc_attribute.m4                      |     2 +-
 bridges/Makefile                                   |     2 +-
 bridges/bridge_builtin_features.c                  |   545 +-
 bridges/bridge_builtin_interval_features.c         |   217 -
 bridges/bridge_holding.c                           |   449 -
 bridges/bridge_multiplexed.c                       |   432 +
 bridges/bridge_native_rtp.c                        |   493 -
 bridges/bridge_simple.c                            |    62 +-
 bridges/bridge_softmix.c                           |   790 +-
 build_tools/.gitignore                             |     1 +
 build_tools/cflags-devmode.xml                     |     3 +
 build_tools/cflags.xml                             |    18 +-
 build_tools/install_subst                          |    43 -
 build_tools/make_buildopts_h                       |    35 +-
 build_tools/make_linker_version_script             |     3 +-
 build_tools/make_version                           |    14 +-
 build_tools/menuselect-deps.in                     |     6 +-
 build_tools/mkpkgconfig                            |    10 +-
 build_tools/post_process_documentation.py          |     9 +-
 cdr/Makefile                                       |     2 +-
 cdr/cdr_adaptive_odbc.c                            |    31 +-
 cdr/cdr_csv.c                                      |    27 +-
 cdr/cdr_custom.c                                   |    28 +-
 cdr/cdr_manager.c                                  |    38 +-
 cdr/cdr_odbc.c                                     |    70 +-
 cdr/cdr_pgsql.c                                    |   150 +-
 cdr/cdr_radius.c                                   |    22 +-
 cdr/cdr_sqlite.c                                   |    10 +-
 cdr/cdr_sqlite3_custom.c                           |     9 +-
 cdr/cdr_syslog.c                                   |    30 +-
 cdr/cdr_tds.c                                      |    17 +-
 cel/Makefile                                       |     2 +-
 cel/cel_custom.c                                   |    18 +-
 cel/cel_manager.c                                  |    22 +-
 cel/cel_odbc.c                                     |    31 +-
 cel/cel_pgsql.c                                    |    96 +-
 cel/cel_radius.c                                   |    19 +-
 cel/cel_sqlite3_custom.c                           |    20 +-
 cel/cel_tds.c                                      |    18 +-
 channels/Makefile                                  |    90 +-
 channels/chan_agent.c                              |  2593 +
 channels/chan_alsa.c                               |    70 +-
 channels/chan_bridge.c                             |   235 +
 channels/chan_bridge_media.c                       |   221 -
 channels/chan_console.c                            |    76 +-
 channels/chan_dahdi.c                              |  4090 +-
 channels/chan_dahdi.h                              |   825 -
 channels/chan_gtalk.c                              |  2415 +
 channels/chan_h323.c                               |  3505 ++
 channels/chan_iax2.c                               |  3707 +-
 channels/chan_jingle.c                             |  2051 +
 channels/chan_local.c                              |  1491 +
 channels/chan_mgcp.c                               |   692 +-
 channels/chan_misdn.c                              |   337 +-
 channels/chan_motif.c                              |   407 +-
 channels/chan_multicast_rtp.c                      |    49 +-
 channels/chan_nbs.c                                |    72 +-
 channels/chan_oss.c                                |    83 +-
 channels/chan_phone.c                              |   243 +-
 channels/chan_pjsip.c                              |  2332 -
 channels/chan_sip.c                                |  6018 +-
 channels/chan_skinny.c                             |  3800 +-
 channels/chan_unistim.c                            |   837 +-
 channels/chan_vpb.cc                               |   197 +-
 channels/console_board.c                           |     4 +-
 channels/console_gui.c                             |     2 +-
 channels/console_video.c                           |     4 +-
 channels/console_video.h                           |     2 +-
 channels/dahdi/bridge_native_dahdi.c               |   925 -
 channels/dahdi/bridge_native_dahdi.h               |    47 -
 channels/h323/.gitignore                           |     3 +
 channels/h323/ChangeLog                            |    43 +
 channels/h323/INSTALL.openh323                     |    18 +
 channels/h323/Makefile.in                          |    53 +
 channels/h323/README                               |   144 +
 channels/h323/TODO                                 |     9 +
 channels/h323/ast_h323.cxx                         |  2678 +
 channels/h323/ast_h323.h                           |   187 +
 .../h323/ast_ptlib.h                               |    36 +-
 channels/h323/caps_h323.cxx                        |   383 +
 channels/h323/caps_h323.h                          |   172 +
 channels/h323/chan_h323.h                          |   275 +
 channels/h323/cisco-h225.asn                       |    74 +
 channels/h323/cisco-h225.cxx                       |   853 +
 channels/h323/cisco-h225.h                         |   300 +
 channels/h323/compat_h323.cxx                      |   139 +
 channels/h323/compat_h323.h                        |    96 +
 channels/h323/noexport.map                         |     5 +
 channels/{iax2/parser.c => iax2-parser.c}          |    91 +-
 channels/{iax2/include/parser.h => iax2-parser.h}  |    10 +-
 channels/{iax2/provision.c => iax2-provision.c}    |    18 +-
 .../{iax2/include/provision.h => iax2-provision.h} |     7 +-
 channels/{iax2/include => }/iax2.h                 |     2 +-
 channels/iax2/codec_pref.c                         |   534 -
 channels/iax2/firmware.c                           |   340 -
 channels/iax2/format_compatibility.c               |   136 -
 channels/iax2/include/codec_pref.h                 |   150 -
 channels/iax2/include/firmware.h                   |   105 -
 channels/iax2/include/format_compatibility.h       |    65 -
 channels/misdn/Makefile                            |     2 +-
 channels/misdn/ie.c                                |    14 +-
 channels/misdn_config.c                            |     2 +-
 channels/pjsip/dialplan_functions.c                |   912 -
 channels/pjsip/include/chan_pjsip.h                |    58 -
 channels/pjsip/include/dialplan_functions.h        |    76 -
 channels/sig_analog.c                              |   521 +-
 channels/sig_analog.h                              |     1 +
 channels/sig_pri.c                                 |   943 +-
 channels/sig_pri.h                                 |    54 +-
 channels/sig_ss7.c                                 |  1983 +-
 channels/sig_ss7.h                                 |   108 +-
 channels/sip/config_parser.c                       |    62 +-
 channels/sip/dialplan_functions.c                  |    10 +-
 channels/sip/include/config_parser.h               |     2 +-
 channels/sip/include/reqresp_parser.h              |    24 -
 channels/sip/include/route.h                       |   120 -
 channels/sip/include/sdp_crypto.h                  |    84 +
 channels/sip/include/security_events.h             |     3 +-
 channels/sip/include/sip.h                         |   141 +-
 channels/sip/include/srtp.h                        |    59 +
 channels/sip/reqresp_parser.c                      |   109 +-
 channels/sip/route.c                               |   205 -
 main/sdp_srtp.c => channels/sip/sdp_crypto.c       |   235 +-
 channels/sip/security_events.c                     |    26 +-
 channels/sip/srtp.c                                |    55 +
 channels/sip/utils.c                               |     2 +-
 channels/vcodecs.c                                 |     8 +-
 channels/vgrabbers.c                               |     4 +-
 codecs/Makefile                                    |     2 +-
 codecs/codec_a_mu.c                                |    42 +-
 codecs/codec_adpcm.c                               |    53 +-
 codecs/codec_alaw.c                                |    52 +-
 codecs/codec_dahdi.c                               |   433 +-
 codecs/codec_g722.c                                |    65 +-
 codecs/codec_g726.c                                |    65 +-
 codecs/codec_gsm.c                                 |    85 +-
 codecs/codec_ilbc.c                                |    74 +-
 codecs/codec_lpc10.c                               |    94 +-
 codecs/codec_resample.c                            |    78 +-
 codecs/codec_speex.c                               |   183 +-
 codecs/codec_ulaw.c                                |    80 +-
 codecs/ex_adpcm.h                                  |     3 +-
 codecs/ex_alaw.h                                   |     2 +-
 codecs/ex_g722.h                                   |     2 +-
 codecs/ex_g726.h                                   |     2 +-
 codecs/ex_gsm.h                                    |     3 +-
 codecs/ex_ilbc.h                                   |     3 +-
 codecs/ex_lpc10.h                                  |     2 +-
 codecs/ex_speex.h                                  |     5 +-
 codecs/ex_ulaw.h                                   |     3 +-
 codecs/g722/g722.h                                 |     2 +-
 codecs/g722/g722_decode.c                          |     2 +-
 codecs/g722/g722_encode.c                          |     2 +-
 codecs/gsm/src/gsm_create.c                        |     2 -
 codecs/log2comp.h                                  |     2 +-
 codecs/speex/speex_resampler.h                     |    20 +-
 config.guess                                       |   329 +-
 config.sub                                         |    85 +-
 configs/{samples => }/acl.conf.sample              |     0
 configs/{samples => }/adsi.conf.sample             |     0
 configs/agents.conf.sample                         |    97 +
 configs/{samples => }/alarmreceiver.conf.sample    |    11 -
 configs/{samples => }/alsa.conf.sample             |     0
 configs/{samples => }/amd.conf.sample              |     1 +
 configs/{samples => }/app_mysql.conf.sample        |     0
 configs/{samples => }/app_skel.conf.sample         |     0
 configs/{samples => }/asterisk.adsi                |     0
 configs/{samples => }/asterisk.conf.sample         |     7 +-
 configs/{samples => }/calendar.conf.sample         |     0
 configs/{samples => }/ccss.conf.sample             |     0
 configs/{samples => }/cdr.conf.sample              |    23 +-
 .../{samples => }/cdr_adaptive_odbc.conf.sample    |     0
 configs/{samples => }/cdr_custom.conf.sample       |     0
 configs/{samples => }/cdr_manager.conf.sample      |     0
 configs/{samples => }/cdr_mysql.conf.sample        |     0
 configs/{samples => }/cdr_odbc.conf.sample         |     1 +
 configs/{samples => }/cdr_pgsql.conf.sample        |     1 -
 .../{samples => }/cdr_sqlite3_custom.conf.sample   |     0
 configs/{samples => }/cdr_syslog.conf.sample       |     0
 configs/{samples => }/cdr_tds.conf.sample          |     0
 configs/{samples => }/cel.conf.sample              |    20 +-
 configs/{samples => }/cel_custom.conf.sample       |     0
 configs/{samples => }/cel_odbc.conf.sample         |     0
 configs/{samples => }/cel_pgsql.conf.sample        |     1 -
 .../{samples => }/cel_sqlite3_custom.conf.sample   |     0
 configs/{samples => }/cel_tds.conf.sample          |     0
 configs/{samples => }/chan_dahdi.conf.sample       |   199 +-
 configs/{samples => }/chan_mobile.conf.sample      |     0
 configs/{samples => }/cli.conf.sample              |     0
 configs/{samples => }/cli_aliases.conf.sample      |    20 +-
 configs/{samples => }/cli_permissions.conf.sample  |     0
 configs/{samples => }/codecs.conf.sample           |     0
 configs/{samples => }/confbridge.conf.sample       |     5 -
 configs/{samples => }/config_test.conf.sample      |     0
 configs/{samples => }/console.conf.sample          |     0
 configs/{samples => }/dbsep.conf.sample            |     0
 configs/{samples => }/dnsmgr.conf.sample           |     0
 configs/{samples => }/dsp.conf.sample              |     0
 configs/{samples => }/dundi.conf.sample            |     0
 configs/{samples => }/enum.conf.sample             |     0
 configs/{samples => }/extconfig.conf.sample        |     9 +-
 configs/{samples => }/extensions.ael.sample        |     0
 configs/{samples => }/extensions.conf.sample       |    11 +-
 configs/{samples => }/extensions.lua.sample        |     0
 .../{samples => }/extensions_minivm.conf.sample    |     2 +-
 configs/features.conf.sample                       |   238 +
 configs/{samples => }/festival.conf.sample         |     0
 configs/{samples => }/followme.conf.sample         |     0
 configs/{samples => }/func_odbc.conf.sample        |     0
 configs/gtalk.conf.sample                          |    27 +
 configs/h323.conf.sample                           |   210 +
 configs/{samples => }/http.conf.sample             |    12 +-
 configs/{samples => }/iax.conf.sample              |    10 +-
 configs/{samples => }/iaxprov.conf.sample          |     0
 configs/{samples => }/indications.conf.sample      |     0
 .../xmpp.conf.sample => jabber.conf.sample}        |     3 -
 configs/jingle.conf.sample                         |    20 +
 configs/{samples => }/logger.conf.sample           |     7 -
 configs/{samples => }/manager.conf.sample          |    14 +-
 configs/{samples => }/meetme.conf.sample           |     0
 configs/{samples => }/mgcp.conf.sample             |     0
 configs/{samples => }/minivm.conf.sample           |     0
 configs/{samples => }/misdn.conf.sample            |     0
 configs/{samples => }/modules.conf.sample          |     0
 configs/{samples => }/motif.conf.sample            |    27 +-
 configs/{samples => }/musiconhold.conf.sample      |     0
 configs/{samples => }/muted.conf.sample            |     0
 configs/{samples => }/ooh323.conf.sample           |     4 -
 configs/{samples => }/osp.conf.sample              |     0
 configs/{samples => }/oss.conf.sample              |     0
 configs/{samples => }/phone.conf.sample            |     0
 configs/{samples => }/phoneprov.conf.sample        |    10 +-
 configs/{samples => }/queuerules.conf.sample       |    11 -
 configs/{samples => }/queues.conf.sample           |    43 +-
 configs/{samples => }/res_config_mysql.conf.sample |     0
 .../{samples => }/res_config_sqlite.conf.sample    |     0
 .../{samples => }/res_config_sqlite3.conf.sample   |     0
 configs/{samples => }/res_corosync.conf.sample     |     0
 configs/{samples => }/res_curl.conf.sample         |     0
 configs/{samples => }/res_fax.conf.sample          |     4 +
 configs/{samples => }/res_ldap.conf.sample         |     1 -
 configs/{samples => }/res_odbc.conf.sample         |    12 +-
 configs/{samples => }/res_pgsql.conf.sample        |     1 -
 configs/{samples => }/res_pktccops.conf.sample     |     0
 configs/{samples => }/res_snmp.conf.sample         |     0
 configs/{samples => }/res_stun_monitor.conf.sample |     0
 configs/{samples => }/rtp.conf.sample              |     0
 configs/samples/agents.conf.sample                 |    70 -
 configs/samples/ari.conf.sample                    |    31 -
 configs/samples/features.conf.sample               |   119 -
 configs/samples/hep.conf.sample                    |    16 -
 configs/samples/pjsip.conf.sample                  |   927 -
 configs/samples/pjsip_notify.conf.sample           |    57 -
 configs/samples/res_parking.conf.sample            |   121 -
 configs/samples/sorcery.conf.sample                |    67 -
 configs/samples/ss7.timers.sample                  |    65 -
 configs/samples/stasis.conf.sample                 |   132 -
 configs/samples/statsd.conf.sample                 |     8 -
 configs/samples/test_sorcery.conf.sample           |    14 -
 configs/{samples => }/say.conf.sample              |     0
 configs/{samples => }/sip.conf.sample              |    32 +-
 configs/{samples => }/sip_notify.conf.sample       |     0
 configs/{samples => }/skinny.conf.sample           |    19 +-
 configs/{samples => }/sla.conf.sample              |     0
 configs/{samples => }/smdi.conf.sample             |     0
 configs/{samples => }/telcordia-1.adsi             |     0
 configs/{samples => }/udptl.conf.sample            |     0
 configs/{samples => }/unistim.conf.sample          |     4 +-
 configs/{samples => }/users.conf.sample            |     0
 configs/{samples => }/voicemail.conf.sample        |    21 +-
 configs/{samples => }/vpb.conf.sample              |     0
 configs/{samples => }/xmpp.conf.sample             |     3 -
 configure                                          |  2902 +-
 configure.ac                                       |   246 +-
 contrib/ast-db-manage/README.md                    |    63 -
 contrib/ast-db-manage/cdr.ini.sample               |    57 -
 contrib/ast-db-manage/cdr/env.py                   |    74 -
 contrib/ast-db-manage/cdr/script.py.mako           |    22 -
 .../cdr/versions/210693f3123d_create_cdr_table.py  |    64 -
 contrib/ast-db-manage/config.ini.sample            |    57 -
 contrib/ast-db-manage/config/env.py                |    74 -
 contrib/ast-db-manage/config/script.py.mako        |    22 -
 .../versions/10aedae86a32_add_outgoing_enum_va.py  |    83 -
 .../1758e8bbf6b_increase_useragent_column_size.py  |    41 -
 .../versions/1d50859ed02e_create_accountcode.py    |    20 -
 .../21e526ad3040_add_pjsip_debug_option.py         |    21 -
 .../versions/28887f25a46f_create_queue_tables.py   |   141 -
 ...930b41b3_add_pjsip_endpoint_options_for_12_1.py |   176 -
 .../3855ee4e5f85_add_missing_pjsip_options.py      |    24 -
 .../versions/43956d550a44_add_tables_for_pjsip.py  |   189 -
 .../versions/4c573e7135bd_fix_tos_field_types.py   |    61 -
 .../config/versions/4da0c5f79a9c_create_tables.py  |   330 -
 .../5139253c0423_make_q_member_uniqueid_autoinc.py |    60 -
 .../51f8cb66540e_add_further_dtls_options.py       |    32 -
 .../versions/581a4264e537_adding_extensions.py     |    50 -
 .../5950038a6ead_fix_pjsip_verifiy_typo.py         |    29 -
 ...b23a8_create_pjsip_subscription_persistence_.py |    36 -
 .../versions/d39508cb8d8_create_queue_rules.py     |    31 -
 .../e96a0b8071c_increase_pjsip_column_size.py      |    39 -
 ...f2a_add_media_encryption_optimistic_to_pjsip.py |    31 -
 contrib/ast-db-manage/voicemail.ini.sample         |    57 -
 contrib/ast-db-manage/voicemail/env.py             |    74 -
 contrib/ast-db-manage/voicemail/script.py.mako     |    22 -
 .../39428242f7f5_increase_recording_column_size.py |    44 -
 .../versions/a2e9769475e_create_tables.py          |    58 -
 contrib/editors/asterisk.vim                       |     4 +-
 contrib/init.d/rc.debian.asterisk                  |     2 +-
 contrib/init.d/rc.gentoo.asterisk                  |     2 +-
 contrib/init.d/rc.mandriva.asterisk                |     2 +-
 contrib/init.d/rc.mandriva.zaptel                  |     2 +-
 contrib/init.d/rc.redhat.asterisk                  |     2 +-
 contrib/init.d/rc.slackware.asterisk               |     2 +-
 contrib/realtime/mysql/iaxfriends.sql              |    56 +
 contrib/realtime/mysql/meetme.sql                  |    21 +
 contrib/realtime/mysql/musiconhold.sql             |    19 +
 contrib/realtime/mysql/mysql_cdr.sql               |    32 -
 contrib/realtime/mysql/mysql_config.sql            |   705 -
 contrib/realtime/mysql/mysql_voicemail.sql         |    34 -
 contrib/realtime/mysql/queue_log.sql               |    24 +
 contrib/realtime/mysql/sippeers.sql                |    97 +
 contrib/realtime/mysql/voicemail.sql               |    70 +
 contrib/realtime/mysql/voicemail_data.sql          |    29 +
 contrib/realtime/mysql/voicemail_messages.sql      |    31 +
 contrib/realtime/oracle/oracle_cdr.sql             |    46 -
 contrib/realtime/oracle/oracle_config.sql          |   994 -
 contrib/realtime/oracle/oracle_voicemail.sql       |    52 -
 contrib/realtime/postgresql/postgresql_cdr.sql     |    36 -
 contrib/realtime/postgresql/postgresql_config.sql  |   739 -
 .../realtime/postgresql/postgresql_voicemail.sql   |    36 -
 contrib/realtime/postgresql/realtime.sql           |   164 +
 contrib/realtime/sqlserver/mssql_cdr.sql           |    42 -
 contrib/realtime/sqlserver/mssql_config.sql        |   990 -
 contrib/realtime/sqlserver/mssql_voicemail.sql     |    48 -
 contrib/scripts/ast_grab_core                      |     2 +-
 contrib/scripts/ast_tls_cert                       |     8 +-
 contrib/scripts/asterisk.ldap-schema               |    12 +-
 contrib/scripts/asterisk.ldif                      |    11 +-
 contrib/scripts/autosupport                        |    95 +-
 contrib/scripts/clang-scan-build                   |   136 +
 contrib/scripts/dahdi_span_config_hook             |    32 -
 contrib/scripts/dbsep.cgi                          |     2 +-
 contrib/scripts/get_swagger_ui.sh                  |    36 -
 contrib/scripts/install_prereq                     |   141 +-
 contrib/scripts/live_ast                           |     6 +-
 contrib/scripts/retrieve_extensions_from_sql.pl    |     2 +-
 contrib/scripts/safe_asterisk                      |    13 +-
 contrib/scripts/sip_to_pjsip/astconfigparser.py    |   467 -
 contrib/scripts/sip_to_pjsip/astdicts.py           |   298 -
 contrib/scripts/sip_to_pjsip/sip_to_pjsip.py       |  1159 -
 contrib/utils/eagi_proxy.c                         |     2 +-
 doc/.gitignore                                     |     3 +
 doc/Asterisk-11-Reference.pdf                      |   Bin 0 -> 1790999 bytes
 doc/README.txt                                     |     6 +-
 doc/appdocsxml.dtd                                 |    59 +-
 doc/appdocsxml.xslt                                |   140 -
 .../asterisk-ng-doxygen.in                         |  1610 +-
 formats/Makefile                                   |     2 +-
 formats/format_g719.c                              |    18 +-
 formats/format_g723.c                              |    17 +-
 formats/format_g726.c                              |    18 +-
 formats/format_g729.c                              |    18 +-
 formats/format_gsm.c                               |    17 +-
 formats/format_h263.c                              |    29 +-
 formats/format_h264.c                              |    29 +-
 formats/format_ilbc.c                              |    17 +-
 formats/format_jpeg.c                              |    16 +-
 formats/format_ogg_vorbis.c                        |    25 +-
 formats/format_pcm.c                               |    34 +-
 formats/format_siren14.c                           |    17 +-
 formats/format_siren7.c                            |    17 +-
 formats/format_sln.c                               |    81 +-
 formats/format_vox.c                               |    17 +-
 formats/format_wav.c                               |    82 +-
 formats/format_wav_gsm.c                           |    47 +-
 funcs/Makefile                                     |     2 +-
 funcs/func_aes.c                                   |     3 +-
 funcs/func_audiohookinherit.c                      |   252 +-
 funcs/func_base64.c                                |     2 +-
 funcs/func_blacklist.c                             |     2 +-
 funcs/func_callcompletion.c                        |     2 +-
 funcs/func_callerid.c                              |    53 +-
 funcs/func_cdr.c                                   |   591 +-
 funcs/func_channel.c                               |    95 +-
 funcs/func_config.c                                |     2 +-
 funcs/func_curl.c                                  |     8 +-
 funcs/func_cut.c                                   |     2 +-
 funcs/func_db.c                                    |     2 +-
 funcs/func_devstate.c                              |     3 +-
 funcs/func_dialgroup.c                             |     2 +-
 funcs/func_dialplan.c                              |     3 +-
 funcs/func_enum.c                                  |     2 +-
 funcs/func_env.c                                   |     6 +-
 funcs/func_extstate.c                              |     2 +-
 funcs/func_frame_trace.c                           |    56 +-
 funcs/func_global.c                                |    45 +-
 funcs/func_groupcount.c                            |     4 +-
 funcs/func_hangupcause.c                           |     4 +-
 funcs/func_iconv.c                                 |     2 +-
 funcs/func_jitterbuffer.c                          |   360 +-
 funcs/func_lock.c                                  |     2 +-
 funcs/func_logic.c                                 |     2 +-
 funcs/func_math.c                                  |    14 +-
 funcs/func_md5.c                                   |     2 +-
 funcs/func_module.c                                |     2 +-
 funcs/func_odbc.c                                  |     3 +-
 funcs/func_periodic_hook.c                         |   527 -
 funcs/func_periodic_hook.exports.in                |     7 -
 funcs/func_pitchshift.c                            |    11 +-
 funcs/func_pjsip_endpoint.c                        |   161 -
 funcs/func_presencestate.c                         |   192 +-
 funcs/func_rand.c                                  |     2 +-
 funcs/func_realtime.c                              |     2 +-
 funcs/func_sha1.c                                  |     2 +-
 funcs/func_shell.c                                 |     2 +-
 funcs/func_sorcery.c                               |   221 -
 funcs/func_speex.c                                 |     8 +-
 funcs/func_sprintf.c                               |     2 +-
 funcs/func_srv.c                                   |     2 +-
 funcs/func_strings.c                               |     8 +-
 funcs/func_sysinfo.c                               |     2 +-
 funcs/func_talkdetect.c                            |   405 -
 funcs/func_timeout.c                               |     4 +-
 funcs/func_uri.c                                   |     2 +-
 funcs/func_version.c                               |     2 +-
 funcs/func_vmcount.c                               |    23 +-
 funcs/func_volume.c                                |     2 +-
 include/asterisk.h                                 |    41 +-
 include/asterisk/.gitignore                        |     3 +
 include/asterisk/_private.h                        |    72 +-
 include/asterisk/abstract_jb.h                     |    30 +-
 include/asterisk/acl.h                             |    30 +-
 include/asterisk/aoc.h                             |     5 +-
 include/asterisk/app.h                             |   722 +-
 include/asterisk/ari.h                             |   243 -
 include/asterisk/astdb.h                           |    27 +-
 include/asterisk/astobj.h                          |     6 +-
 include/asterisk/astobj2.h                         |   814 +-
 include/asterisk/audiohook.h                       |    35 +-
 include/asterisk/autochan.h                        |     5 +-
 include/asterisk/autoconfig.h.in                   |    81 +-
 include/asterisk/backtrace.h                       |    97 -
 include/asterisk/beep.h                            |    45 -
 include/asterisk/bridge.h                          |  1075 -
 include/asterisk/bridge_after.h                    |   244 -
 include/asterisk/bridge_basic.h                    |   150 -
 include/asterisk/bridge_channel.h                  |   679 -
 include/asterisk/bridge_channel_internal.h         |   211 -
 include/asterisk/bridge_features.h                 |   866 -
 include/asterisk/bridge_internal.h                 |   216 -
 include/asterisk/bridge_roles.h                    |   173 -
 include/asterisk/bridging.h                        |   590 +
 include/asterisk/bridging_features.h               |   354 +
 .../{bridge_technology.h => bridging_technology.h} |   182 +-
 include/asterisk/bucket.h                          |   397 -
 include/asterisk/callerid.h                        |    10 +-
 include/asterisk/ccss.h                            |    18 +-
 include/asterisk/cdr.h                             |   694 +-
 include/asterisk/cel.h                             |   234 +-
 include/asterisk/channel.h                         |  1133 +-
 include/asterisk/channel_internal.h                |     5 +-
 include/asterisk/channelstate.h                    |     5 +-
 include/asterisk/chanvars.h                        |    18 -
 include/asterisk/cli.h                             |    16 +-
 include/asterisk/codec.h                           |   186 -
 include/asterisk/compat.h                          |    10 +-
 include/asterisk/compiler.h                        |     6 -
 include/asterisk/config.h                          |   345 +-
 include/asterisk/config_options.h                  |   150 +-
 include/asterisk/core_local.h                      |   137 -
 include/asterisk/core_unreal.h                     |   246 -
 include/asterisk/crypto.h                          |     6 +-
 include/asterisk/data.h                            |     1 -
 include/asterisk/datastore.h                       |    17 +-
 include/asterisk/devicestate.h                     |   120 +-
 include/asterisk/dial.h                            |    35 +-
 include/asterisk/dns.h                             |     3 -
 include/asterisk/doxygen/architecture.h            |    24 +-
 include/asterisk/doxygen/asterisk-git-howto.h      |    16 +-
 include/asterisk/doxygen/commits.h                 |    46 +-
 include/asterisk/doxygen/licensing.h               |     2 +-
 include/asterisk/doxygen/mantisworkflow.h          |   206 +
 include/asterisk/doxygen/releases.h                |    18 +-
 include/asterisk/doxygen/reviewboard.h             |    50 +-
 include/asterisk/doxyref.h                         |   451 +-
 include/asterisk/endpoints.h                       |   204 -
 include/asterisk/event.h                           |   450 +-
 include/asterisk/event_defs.h                      |    75 +-
 include/asterisk/features.h                        |   248 +-
 include/asterisk/features_config.h                 |   244 -
 include/asterisk/file.h                            |    60 +-
 include/asterisk/format.h                          |   558 +-
 include/asterisk/format_cache.h                    |   296 -
 include/asterisk/format_cap.h                      |   389 +-
 include/asterisk/format_compatibility.h            |   129 -
 include/asterisk/format_pref.h                     |   114 +
 include/asterisk/frame.h                           |   171 +-
 include/asterisk/frame_defs.h                      |     0
 include/asterisk/framehook.h                       |   304 +-
 include/asterisk/heap.h                            |     3 -
 include/asterisk/http.h                            |   189 +-
 include/asterisk/http_websocket.h                  |   165 +-
 include/asterisk/image.h                           |     2 +-
 include/asterisk/inline_api.h                      |    14 +-
 include/asterisk/jabber.h                          |   224 +
 include/asterisk/jingle.h                          |    66 +
 include/asterisk/json.h                            |  1036 -
 include/asterisk/localtime.h                       |     7 +-
 include/asterisk/lock.h                            |   173 +-
 include/asterisk/logger.h                          |   110 +-
 include/asterisk/manager.h                         |   285 +-
 include/asterisk/md5.h                             |     3 +-
 include/asterisk/media_index.h                     |   108 -
 include/asterisk/message.h                         |   147 +-
 include/asterisk/mixmonitor.h                      |   105 -
 include/asterisk/mod_format.h                      |    10 +-
 include/asterisk/module.h                          |   166 +-
 include/asterisk/monitor.h                         |     4 +-
 include/asterisk/musiconhold.h                     |     7 +-
 include/asterisk/netsock.h                         |     2 -
 include/asterisk/netsock2.h                        |    78 +-
 include/asterisk/optional_api.h                    |   287 +-
 include/asterisk/options.h                         |    21 +-
 include/asterisk/opus.h                            |    41 -
 include/asterisk/parking.h                         |   289 -
 include/asterisk/paths.h                           |     3 +-
 include/asterisk/pbx.h                             |   116 +-
 include/asterisk/phoneprov.h                       |   124 -
 include/asterisk/pickup.h                          |    91 -
 include/asterisk/poll-compat.h                     |     2 +-
 include/asterisk/presencestate.h                   |    53 +-
 include/asterisk/res_fax.h                         |    17 +-
 include/asterisk/res_hep.h                         |   111 -
 include/asterisk/res_mwi_external.h                |   226 -
 include/asterisk/res_odbc.h                        |    14 +-
 include/asterisk/res_pjsip.h                       |  1959 -
 include/asterisk/res_pjsip_body_generator_types.h  |    70 -
 include/asterisk/res_pjsip_cli.h                   |   110 -
 include/asterisk/res_pjsip_outbound_publish.h      |   165 -
 include/asterisk/res_pjsip_presence_xml.h          |   115 -
 include/asterisk/res_pjsip_pubsub.h                |   686 -
 include/asterisk/res_pjsip_session.h               |   650 -
 include/asterisk/rtp_engine.h                      |   349 +-
 include/asterisk/say.h                             |    14 +-
 include/asterisk/sched.h                           |    13 +-
 include/asterisk/sdp_srtp.h                        |   127 -
 include/asterisk/security_events.h                 |    30 -
 include/asterisk/security_events_defs.h            |    17 +-
 include/asterisk/sem.h                             |   157 -
 include/asterisk/sip_api.h                         |     3 +-
 include/asterisk/slin.h                            |    10 +-
 include/asterisk/slinfactory.h                     |     6 +-
 include/asterisk/smdi.h                            |    56 +-
 include/asterisk/smoother.h                        |    89 -
 include/asterisk/sorcery.h                         |  1167 -
 include/asterisk/sounds_index.h                    |    55 -
 include/asterisk/speech.h                          |     6 +-
 include/asterisk/spinlock.h                        |   488 -
 include/asterisk/srv.h                             |    51 +-
 include/asterisk/stasis.h                          |  1313 -
 include/asterisk/stasis_app.h                      |   842 -
 include/asterisk/stasis_app_device_state.h         |    95 -
 include/asterisk/stasis_app_impl.h                 |   108 -
 include/asterisk/stasis_app_mailbox.h              |    91 -
 include/asterisk/stasis_app_playback.h             |   157 -
 include/asterisk/stasis_app_recording.h            |   297 -
 include/asterisk/stasis_app_snoop.h                |    60 -
 include/asterisk/stasis_bridges.h                  |   520 -
 include/asterisk/stasis_cache_pattern.h            |   153 -
 include/asterisk/stasis_channels.h                 |   634 -
 include/asterisk/stasis_endpoints.h                |   229 -
 include/asterisk/stasis_internal.h                 |    70 -
 include/asterisk/stasis_message_router.h           |   227 -
 include/asterisk/stasis_system.h                   |   131 -
 include/asterisk/stasis_test.h                     |   142 -
 include/asterisk/statsd.h                          |    85 -
 include/asterisk/stringfields.h                    |   113 +-
 include/asterisk/strings.h                         |   264 +-
 include/asterisk/syslog.h                          |     2 +
 include/asterisk/taskprocessor.h                   |   198 +-
 include/asterisk/tcptls.h                          |     3 +-
 include/asterisk/term.h                            |    73 +-
 include/asterisk/test.h                            |   175 +-
 include/asterisk/threadpool.h                      |   226 -
 include/asterisk/threadstorage.h                   |    53 +-
 include/asterisk/time.h                            |    11 -
 include/asterisk/timing.h                          |    61 +-
 include/asterisk/translate.h                       |    39 +-
 include/asterisk/udptl.h                           |    18 +-
 include/asterisk/uri.h                             |   181 -
 include/asterisk/utils.h                           |   143 +-
 include/asterisk/uuid.h                            |   118 -
 include/asterisk/xml.h                             |    39 -
 include/asterisk/xmldoc.h                          |    65 +-
 include/asterisk/xmpp.h                            |    24 +-
 main/.gitignore                                    |     3 +
 main/Makefile                                      |    33 +-
 main/abstract_jb.c                                 |   340 +-
 main/acl.c                                         |    91 +-
 main/alaw.c                                        |     2 +-
 main/aoc.c                                         |   432 +-
 main/app.c                                         |  1249 +-
 main/ast_expr2.c                                   |     2 +-
 main/ast_expr2.fl                                  |     2 +-
 main/ast_expr2.y                                   |     2 +-
 main/ast_expr2f.c                                  |     6 +-
 main/asterisk.c                                    |   659 +-
 main/asterisk.dynamics                             |     1 -
 main/asterisk.exports.in                           |     3 -
 main/astfd.c                                       |    63 +-
 main/astmm.c                                       |    70 +-
 main/astobj2.c                                     |   990 +-
 main/astobj2_container.c                           |  1219 -
 main/astobj2_container_private.h                   |   345 -
 main/astobj2_hash.c                                |  1153 -
 main/astobj2_private.h                             |    49 -
 main/astobj2_rbtree.c                              |  2096 -
 main/audiohook.c                                   |   414 +-
 main/autochan.c                                    |     2 +-
 main/autoservice.c                                 |    50 +-
 main/backtrace.c                                   |   225 -
 main/bridge.c                                      |  5312 --
 main/bridge_after.c                                |   648 -
 main/bridge_basic.c                                |  3443 --
 main/bridge_channel.c                              |  2777 -
 main/bridge_roles.c                                |   499 -
 main/bridging.c                                    |  1692 +
 main/bucket.c                                      |   965 -
 main/callerid.c                                    |    12 +-
 main/ccss.c                                        |   335 +-
 main/cdr.c                                         |  4663 +-
 main/cel.c                                         |  1837 +-
 main/channel.c                                     |  4214 +-
 main/channel_internal_api.c                        |   384 +-
 main/chanvars.c                                    |    68 +-
 main/cli.c                                         |   362 +-
 main/codec.c                                       |   381 -
 main/codec_builtin.c                               |   845 -
 main/config.c                                      |  1209 +-
 main/config_options.c                              |   638 +-
 main/core_local.c                                  |  1071 -
 main/core_unreal.c                                 |  1042 -
 main/crypt.c                                       |   202 -
 main/data.c                                        |   107 +-
 main/datastore.c                                   |    18 +-
 main/db.c                                          |     7 +-
 main/devicestate.c                                 |   673 +-
 main/dial.c                                        |   265 +-
 main/dns.c                                         |    53 +-
 main/dnsmgr.c                                      |    16 +-
 main/dsp.c                                         |   195 +-
 main/editline/.gitignore                           |    13 +
 main/editline/np/strlcat.c                         |     8 -
 main/editline/np/strlcpy.c                         |    10 -
 main/endpoints.c                                   |   523 -
 main/enum.c                                        |    16 +-
 main/event.c                                       |  1773 +-
 main/features.c                                    |  9267 ++-
 main/features_config.c                             |  1980 -
 main/file.c                                        |   353 +-
 main/fixedjitterbuf.c                              |     2 +-
 main/format.c                                      |  1468 +-
 main/format_cache.c                                |   515 -
 main/format_cap.c                                  |   925 +-
 main/format_compatibility.c                        |   274 -
 main/format_pref.c                                 |   344 +
 main/frame.c                                       |   608 +-
 main/framehook.c                                   |   157 +-
 main/fskmodem_float.c                              |     2 +-
 main/fskmodem_int.c                                |     2 +-
 main/global_datastores.c                           |     2 +-
 main/hashtab.c                                     |     6 +-
 main/heap.c                                        |     2 +-
 main/http.c                                        |  1665 +-
 main/image.c                                       |     8 +-
 main/indications.c                                 |    31 +-
 main/io.c                                          |     2 +-
 main/jitterbuf.c                                   |     4 +-
 main/json.c                                        |   913 -
 main/libasteriskssl.c                              |    37 +-
 main/loader.c                                      |   508 +-
 main/lock.c                                        |   572 +-
 main/logger.c                                      |   541 +-
 main/manager.c                                     |  2026 +-
 main/manager_bridges.c                             |   650 -
 main/manager_channels.c                            |  1198 -
 main/manager_endpoints.c                           |    89 -
 main/manager_mwi.c                                 |   200 -
 main/manager_system.c                              |    81 -
 main/md5.c                                         |     2 +-
 main/media_index.c                                 |   597 -
 main/message.c                                     |   553 +-
 main/mixmonitor.c                                  |    98 -
 main/named_acl.c                                   |   124 +-
 main/netsock.c                                     |   113 +-
 main/netsock2.c                                    |    89 +-
 main/optional_api.c                                |   350 -
 main/parking.c                                     |   249 -
 main/pbx.c                                         |  2703 +-
 main/pickup.c                                      |   409 -
 main/plc.c                                         |     2 +-
 main/poll.c                                        |     2 +-
 main/presencestate.c                               |   225 +-
 main/privacy.c                                     |     2 +-
 main/rtp_engine.c                                  |  1866 +-
 main/say.c                                         |   584 +-
 main/sched.c                                       |   301 +-
 main/security_events.c                             |   684 +-
 main/sem.c                                         |   116 -
 main/sha1.c                                        |     4 +-
 main/slinfactory.c                                 |    36 +-
 main/smoother.c                                    |   227 -
 main/sorcery.c                                     |  2197 -
 main/sounds_index.c                                |   333 -
 main/srv.c                                         |     4 +-
 main/stasis.c                                      |  1635 -
 main/stasis_bridges.c                              |  1256 -
 main/stasis_cache.c                                |   933 -
 main/stasis_cache_pattern.c                        |   201 -
 main/stasis_channels.c                             |  1615 -
 main/stasis_endpoints.c                            |   317 -
 main/stasis_message.c                              |   201 -
 main/stasis_message_router.c                       |   368 -
 main/stasis_system.c                               |   426 -
 main/stdtime/localtime.c                           |   295 +-
 main/strings.c                                     |    56 +-
 main/stun.c                                        |     4 +-
 main/syslog.c                                      |    10 +-
 main/taskprocessor.c                               |   590 +-
 main/tcptls.c                                      |    83 +-
 main/tdd.c                                         |     7 +-
 main/term.c                                        |    60 +-
 main/test.c                                        |   262 +-
 main/threadpool.c                                  |  1218 -
 main/threadstorage.c                               |     4 +-
 main/timing.c                                      |    60 +-
 main/translate.c                                   |   816 +-
 main/udptl.c                                       |   228 +-
 main/ulaw.c                                        |     2 +-
 main/uri.c                                         |   323 -
 main/utils.c                                       |   424 +-
 main/uuid.c                                        |   231 -
 main/xml.c                                         |    76 +-
 main/xmldoc.c                                      |  1226 +-
 makeopts.in                                        |    24 +-
 menuselect/.gitignore                              |     7 +
 menuselect/configure                               |     8 +-
 menuselect/configure.ac                            |     2 +-
 mkinstalldirs                                      |     2 +-
 pbx/Makefile                                       |     4 +-
 pbx/dundi-parser.c                                 |    10 +-
 pbx/pbx_ael.c                                      |    15 +-
 pbx/pbx_config.c                                   |   227 +-
 pbx/pbx_dundi.c                                    |    12 +-
 pbx/pbx_loopback.c                                 |     2 +-
 pbx/pbx_lua.c                                      |     4 +-
 pbx/pbx_realtime.c                                 |    68 +-
 pbx/pbx_spool.c                                    |    52 +-
 res/Makefile                                       |    49 +-
 res/ael/.gitignore                                 |     1 +
 res/ael/ael.flex                                   |     4 +-
 res/ael/ael.tab.c                                  |     2 +-
 res/ael/ael.y                                      |     2 +-
 res/ael/ael_lex.c                                  |     4 +-
 res/ael/pval.c                                     |    45 +-
 res/ari.make                                       |    63 -
 res/ari/ari_model_validators.c                     |  5198 --
 res/ari/ari_model_validators.h                     |  1513 -
 res/ari/ari_websockets.c                           |   190 -
 res/ari/cli.c                                      |   267 -
 res/ari/config.c                                   |   351 -
 res/ari/internal.h                                 |   167 -
 res/ari/resource_applications.c                    |   172 -
 res/ari/resource_applications.h                    |   131 -
 res/ari/resource_asterisk.c                        |   193 -
 res/ari/resource_asterisk.h                        |   121 -
 res/ari/resource_bridges.c                         |   990 -
 res/ari/resource_bridges.h                         |   357 -
 res/ari/resource_channels.c                        |  1123 -
 res/ari/resource_channels.h                        |   673 -
 res/ari/resource_device_states.c                   |   111 -
 res/ari/resource_device_states.h                   |   106 -
 res/ari/resource_endpoints.c                       |   281 -
 res/ari/resource_endpoints.h                       |   142 -
 res/ari/resource_events.c                          |   275 -
 res/ari/resource_events.h                          |    94 -
 res/ari/resource_mailboxes.c                       |    93 -
 res/ari/resource_mailboxes.h                       |   108 -
 res/ari/resource_playbacks.c                       |   139 -
 res/ari/resource_playbacks.h                       |    95 -
 res/ari/resource_recordings.c                      |   313 -
 res/ari/resource_recordings.h                      |   201 -
 res/ari/resource_sounds.c                          |   226 -
 res/ari/resource_sounds.h                          |    82 -
 res/parking/parking_applications.c                 |   889 -
 res/parking/parking_bridge.c                       |   464 -
 res/parking/parking_bridge_features.c              |   740 -
 res/parking/parking_controller.c                   |   281 -
 res/parking/parking_devicestate.c                  |   124 -
 res/parking/parking_manager.c                      |   697 -
 res/parking/parking_tests.c                        |   877 -
 res/parking/parking_ui.c                           |   208 -
 res/parking/res_parking.h                          |   571 -
 res/res_adsi.c                                     |    57 +-
 res/res_ael_share.c                                |     3 +-
 res/res_agi.c                                      |   559 +-
 res/res_ari.c                                      |  1109 -
 res/res_ari.exports.in                             |     6 -
 res/res_ari_applications.c                         |   548 -
 res/res_ari_asterisk.c                             |   449 -
 res/res_ari_bridges.c                              |  1419 -
 res/res_ari_channels.c                             |  2597 -
 res/res_ari_device_states.c                        |   364 -
 res/res_ari_endpoints.c                            |   503 -
 res/res_ari_events.c                               |   378 -
 res/res_ari_mailboxes.c                            |   370 -
 res/res_ari_model.c                                |   211 -
 res/res_ari_model.exports.in                       |     6 -
 res/res_ari_playbacks.c                            |   321 -
 res/res_ari_recordings.c                           |   845 -
 res/res_ari_sounds.c                               |   250 -
 res/res_calendar.c                                 |    65 +-
 res/res_calendar_caldav.c                          |     4 +-
 res/res_calendar_ews.c                             |     4 +-
 res/res_calendar_exchange.c                        |   107 +-
 res/res_calendar_icalendar.c                       |     4 +-
 res/res_chan_stats.c                               |   187 -
 res/res_clialiases.c                               |    23 +-
 res/res_clioriginate.c                             |    21 +-
 res/res_config_curl.c                              |   141 +-
 res/res_config_ldap.c                              |   310 +-
 res/res_config_odbc.c                              |   215 +-
 res/res_config_pgsql.c                             |   195 +-
 res/res_config_sqlite.c                            |   324 +-
 res/res_config_sqlite3.c                           |   104 +-
 res/res_convert.c                                  |     2 +-
 res/res_corosync.c                                 |   394 +-
 res/res_crypto.c                                   |     7 +-
 res/res_curl.c                                     |    44 +-
 res/res_fax.c                                      |  1012 +-
 res/res_fax.exports.in                             |     1 -
 res/res_fax_spandsp.c                              |   124 +-
 res/res_format_attr_celt.c                         |   208 +-
 res/res_format_attr_h263.c                         |   352 +-
 res/res_format_attr_h264.c                         |   403 +-
 res/res_format_attr_opus.c                         |   260 -
 res/res_format_attr_silk.c                         |   231 +-
 res/res_hep.c                                      |   628 -
 res/res_hep.exports.in                             |     7 -
 res/res_hep_pjsip.c                                |   179 -
 res/res_hep_rtcp.c                                 |   144 -
 res/res_http_post.c                                |   136 +-
 res/res_http_websocket.c                           |   771 +-
 res/res_http_websocket.exports.in                  |    14 +-
 res/res_jabber.c                                   |  4830 ++
 res/res_limit.c                                    |     4 +-
 res/res_manager_devicestate.c                      |   154 -
 res/res_manager_presencestate.c                    |   153 -
 res/res_monitor.c                                  |   152 +-
 res/res_musiconhold.c                              |   298 +-
 res/res_mutestream.c                               |   192 +-
 res/res_mwi_external.c                             |   959 -
 res/res_mwi_external.exports.in                    |     6 -
 res/res_mwi_external_ami.c                         |   380 -
 res/res_odbc.c                                     |    63 +-
 res/res_odbc.exports.in                            |     1 +
 res/res_parking.c                                  |  1271 -
 res/res_phoneprov.c                                |  1501 +-
 res/res_phoneprov.exports.in                       |     6 -
 res/res_pjsip.c                                    |  3209 --
 res/res_pjsip.exports.in                           |     8 -
 res/res_pjsip/config_auth.c                        |   342 -
 res/res_pjsip/config_domain_aliases.c              |    67 -
 res/res_pjsip/config_global.c                      |   140 -
 res/res_pjsip/config_system.c                      |   251 -
 res/res_pjsip/config_transport.c                   |   790 -
 res/res_pjsip/include/res_pjsip_private.h          |   115 -
 res/res_pjsip/location.c                           |   912 -
 res/res_pjsip/pjsip_cli.c                          |   347 -
 res/res_pjsip/pjsip_configuration.c                |  1992 -
 res/res_pjsip/pjsip_distributor.c                  |   397 -
 res/res_pjsip/pjsip_global_headers.c               |   171 -
 res/res_pjsip/pjsip_options.c                      |  1122 -
 res/res_pjsip/pjsip_outbound_auth.c                |    96 -
 res/res_pjsip/presence_xml.c                       |   175 -
 res/res_pjsip/security_events.c                    |   286 -
 res/res_pjsip_acl.c                                |   308 -
 res/res_pjsip_authenticator_digest.c               |   494 -
 res/res_pjsip_caller_id.c                          |   750 -
 res/res_pjsip_dialog_info_body_generator.c         |   214 -
 res/res_pjsip_diversion.c                          |   350 -
 res/res_pjsip_dtmf_info.c                          |   170 -
 res/res_pjsip_endpoint_identifier_anonymous.c      |   128 -
 res/res_pjsip_endpoint_identifier_ip.c             |   539 -
 res/res_pjsip_endpoint_identifier_user.c           |   134 -
 res/res_pjsip_exten_state.c                        |   502 -
 res/res_pjsip_exten_state.exports.in               |     7 -
 res/res_pjsip_header_funcs.c                       |   626 -
 res/res_pjsip_log_forwarder.c                      |   125 -
 res/res_pjsip_logger.c                             |   267 -
 res/res_pjsip_messaging.c                          |   762 -
 res/res_pjsip_multihomed.c                         |   235 -
 res/res_pjsip_mwi.c                                |   924 -
 res/res_pjsip_mwi_body_generator.c                 |   116 -
 res/res_pjsip_nat.c                                |   305 -
 res/res_pjsip_notify.c                             |  1034 -
 res/res_pjsip_one_touch_record_info.c              |   131 -
 res/res_pjsip_outbound_authenticator_digest.c      |   168 -
 res/res_pjsip_outbound_publish.c                   |  1015 -
 res/res_pjsip_outbound_publish.exports.in          |     6 -
 res/res_pjsip_outbound_registration.c              |  1448 -
 res/res_pjsip_path.c                               |   253 -
 res/res_pjsip_phoneprov_provider.c                 |   419 -
 res/res_pjsip_pidf_body_generator.c                |   139 -
 res/res_pjsip_pidf_digium_body_supplement.c        |   117 -
 res/res_pjsip_pidf_eyebeam_body_supplement.c       |   116 -
 res/res_pjsip_publish_asterisk.c                   |   929 -
 res/res_pjsip_pubsub.c                             |  4307 --
 res/res_pjsip_pubsub.exports.in                    |    42 -
 res/res_pjsip_refer.c                              |  1043 -
 res/res_pjsip_registrar.c                          |   832 -
 res/res_pjsip_registrar_expire.c                   |   230 -
 res/res_pjsip_rfc3326.c                            |   150 -
 res/res_pjsip_sdp_rtp.c                            |  1353 -
 res/res_pjsip_send_to_voicemail.c                  |   231 -
 res/res_pjsip_session.c                            |  2374 -
 res/res_pjsip_session.exports.in                   |    25 -
 res/res_pjsip_t38.c                                |   881 -
 res/res_pjsip_transport_websocket.c                |   402 -
 res/res_pjsip_xpidf_body_generator.c               |   181 -
 res/res_pktccops.c                                 |     9 +-
 res/res_realtime.c                                 |     2 +-
 res/res_rtp_asterisk.c                             |  1521 +-
 res/res_rtp_multicast.c                            |    11 +-
 res/res_security_log.c                             |   102 +-
 res/res_smdi.c                                     |   340 +-
 res/res_snmp.c                                     |    24 +-
 res/res_sorcery_astdb.c                            |   392 -
 res/res_sorcery_config.c                           |   387 -
 res/res_sorcery_memory.c                           |   242 -
 res/res_sorcery_realtime.c                         |   289 -
 res/res_speech.c                                   |    45 +-
 res/res_speech.exports.in                          |    17 +-
 res/res_srtp.c                                     |     3 +-
 res/res_stasis.c                                   |  2049 -
 res/res_stasis.exports.in                          |     6 -
 res/res_stasis_answer.c                            |    78 -
 res/res_stasis_answer.exports.in                   |     6 -
 res/res_stasis_device_state.c                      |   417 -
 res/res_stasis_device_state.exports.in             |     6 -
 res/res_stasis_mailbox.c                           |   166 -
 res/res_stasis_mailbox.exports.in                  |     6 -
 res/res_stasis_playback.c                          |   688 -
 res/res_stasis_playback.exports.in                 |     6 -
 res/res_stasis_recording.c                         |   660 -
 res/res_stasis_recording.exports.in                |     6 -
 res/res_stasis_snoop.c                             |   414 -
 res/res_stasis_snoop.exports.in                    |     6 -
 res/res_stasis_test.c                              |   287 -
 res/res_stasis_test.exports.in                     |     6 -
 res/res_statsd.c                                   |   325 -
 res/res_statsd.exports.in                          |     8 -
 res/res_stun_monitor.c                             |    46 +-
 res/res_timing_dahdi.c                             |    89 +-
 res/res_timing_kqueue.c                            |   206 +-
 res/res_timing_pthread.c                           |   117 +-
 res/res_timing_timerfd.c                           |   248 +-
 res/res_xmpp.c                                     |   361 +-
 res/snmp/agent.c                                   |    10 +-
 res/stasis/app.c                                   |  1321 -
 res/stasis/app.h                                   |   272 -
 res/stasis/command.c                               |   166 -
 res/stasis/command.h                               |    76 -
 res/stasis/control.c                               |  1054 -
 res/stasis/control.h                               |   112 -
 res/stasis/messaging.c                             |   531 -
 res/stasis/messaging.h                             |    83 -
 res/stasis/stasis_bridge.c                         |   231 -
 res/stasis/stasis_bridge.h                         |    74 -
 res/stasis_recording/stored.c                      |   528 -
 rest-api-templates/README.txt                      |    15 -
 rest-api-templates/api.wiki.mustache               |    63 -
 rest-api-templates/ari.make.mustache               |    26 -
 rest-api-templates/ari_model_validators.c.mustache |   122 -
 rest-api-templates/ari_model_validators.h.mustache |   191 -
 rest-api-templates/ari_resource.c.mustache         |    53 -
 rest-api-templates/ari_resource.h.mustache         |   109 -
 rest-api-templates/asterisk_processor.py           |   245 -
 rest-api-templates/body_parsing.mustache           |    71 -
 rest-api-templates/do-not-edit.mustache            |     4 -
 rest-api-templates/make_ari_stubs.py               |    95 -
 rest-api-templates/models.wiki.mustache            |    22 -
 rest-api-templates/odict.py                        |   261 -
 rest-api-templates/param_parsing.mustache          |   113 -
 rest-api-templates/res_ari_resource.c.mustache     |   250 -
 rest-api-templates/rest_handler.mustache           |    40 -
 rest-api-templates/swagger_model.py                |   756 -
 rest-api-templates/transform.py                    |    62 -
 rest-api/README.txt                                |     9 -
 rest-api/api-docs/applications.json                |   172 -
 rest-api/api-docs/asterisk.json                    |   259 -
 rest-api/api-docs/bridges.json                     |   656 -
 rest-api/api-docs/channels.json                    |  1456 -
 rest-api/api-docs/deviceStates.json                |   151 -
 rest-api/api-docs/endpoints.json                   |   275 -
 rest-api/api-docs/events.json                      |   729 -
 rest-api/api-docs/mailboxes.json                   |   134 -
 rest-api/api-docs/playbacks.json                   |   155 -
 rest-api/api-docs/recordings.json                  |   378 -
 rest-api/api-docs/sounds.json                      |    99 -
 rest-api/resources.json                            |    54 -
 sounds/Makefile                                    |     7 +-
 sounds/sounds.xml                                  |    27 +
 static-http/ajamdemo.html                          |    17 -
 static-http/astman.css                             |    18 -
 static-http/mantest.html                           |    20 +-
 tests/Makefile                                     |     2 +-
 tests/test_abstract_jb.c                           |    77 +-
 tests/test_acl.c                                   |    47 +-
 tests/test_amihooks.c                              |     2 +-
 tests/test_aoc.c                                   |     2 +-
 tests/test_app.c                                   |    30 +-
 tests/test_ari.c                                   |   570 -
 tests/test_ari_model.c                             |   457 -
 tests/test_ast_format_str_reduce.c                 |     2 +-
 tests/test_astobj2.c                               |  1656 +-
 tests/test_astobj2_thrash.c                        |     2 +-
 tests/test_bucket.c                                |   873 -
 tests/test_callerid.c                              |     2 +-
 tests/test_cdr.c                                   |  2630 -
 tests/test_cel.c                                   |  2226 -
 tests/test_channel_feature_hooks.c                 |   345 -
 tests/test_config.c                                |   614 +-
 tests/test_core_codec.c                            |   369 -
 tests/test_core_format.c                           |   975 -
 tests/test_devicestate.c                           |   570 +-
 tests/test_dlinklists.c                            |     2 +-
 tests/test_endpoints.c                             |   157 -
 tests/test_event.c                                 |   801 +-
 tests/test_expr.c                                  |     2 +-
 tests/test_format_api.c                            |   859 +
 tests/test_format_cache.c                          |   281 -
 tests/test_format_cap.c                            |  1479 -
 tests/test_func_file.c                             |     8 +-
 tests/test_gosub.c                                 |    14 +-
 tests/test_hashtab_thrash.c                        |    15 +-
 tests/test_heap.c                                  |     2 +-
 tests/test_jitterbuf.c                             |    52 +-
 tests/test_json.c                                  |  1810 -
 tests/test_linkedlists.c                           |     2 +-
 tests/test_locale.c                                |     2 +-
 tests/test_logger.c                                |     2 +-
 tests/test_message.c                               |   888 -
 tests/test_optional_api.c                          |   187 -
 tests/test_pbx.c                                   |    11 +-
 tests/test_poll.c                                  |     2 +-
 tests/test_res_stasis.c                            |   198 -
 tests/test_sched.c                                 |     4 +-
 tests/test_scoped_lock.c                           |   281 -
 tests/test_security_events.c                       |    64 +-
 tests/test_skel.c                                  |     2 +-
 tests/test_sorcery.c                               |  3451 --
 tests/test_sorcery_astdb.c                         |   638 -
 tests/test_sorcery_realtime.c                      |   898 -
 tests/test_stasis.c                                |  2109 -
 tests/test_stasis_channels.c                       |   331 -
 tests/test_stasis_endpoints.c                      |   310 -
 tests/test_stringfields.c                          |   110 +-
 tests/test_strings.c                               |   149 +-
 tests/test_substitution.c                          |     5 +-
 tests/test_taskprocessor.c                         |   750 -
 tests/test_threadpool.c                            |  1646 -
 tests/test_time.c                                  |     2 +-
 tests/test_uri.c                                   |   154 -
 tests/test_utils.c                                 |   133 +-
 tests/test_uuid.c                                  |   152 -
 tests/test_voicemail_api.c                         |   271 +-
 tests/test_websocket_client.c                      |   161 -
 tests/test_xml_escape.c                            |     2 +-
 utils/.gitignore                                   |    30 +
 utils/Makefile                                     |    41 +-
 utils/ael_main.c                                   |     9 +-
 utils/astdb2sqlite3.c                              |     2 +-
 utils/astman.c                                     |     4 +-
 utils/check_expr.c                                 |    10 +-
 utils/clicompat.c                                  |     9 +-
 utils/conf2ael.c                                   |    20 +-
 utils/extconf.c                                    |   367 +-
 utils/muted.c                                      |     9 -
 utils/refcounter.c                                 |   324 +
 utils/smsq.c                                       |     8 +-
 utils/utils.xml                                    |     4 +
 1224 files changed, 125065 insertions(+), 291861 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8426c0a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+# See .gitignore in subdirectories for more ignored files
+
+*~
+*.[oadi]
+*.gz
+*.ii
+*.oo
+*.eo
+*.so
+*.exports
+*.moduleinfo
+*.makeopts
+*.makedeps
+aclocal.m4
+autom4te.cache
+makeopts
+.lastclean
+config.log
+config.status
+defaults.h
+makeopts.embed_rules
+menuselect-tree
+*.sha1
+*.pyc
+*.gcno
+*.gcda
+latex
+doxygen.log
+
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..f9ef050
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.asterisk.org
+port=29418
+project=asterisk.git
diff --git a/.version b/.version
index 21b80e9..1eacb37 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-13.1.1
+11.20.0
\ No newline at end of file
diff --git a/CHANGES b/CHANGES
index ae368f1..449c2e7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,504 +7,22 @@
 === and the other UPGRADE files for older releases.
 ===
 ==============================================================================
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 13.0.0 to Asterisk 13.1.0 ------------
-------------------------------------------------------------------------------
-
-AMI
-------------------
- * Event NewConnectedLine is emitted when the connected line information on
-   a channel changes.
-
- * The version of AMI has been bumped to 2.6.0 to account for the backwards
-   compatible feature listed above.
-
-ARI
-------------------
- * Event ChannelConnectedLine is emitted when the connected line information
-   on a channel changes.
-
- * The version of ARI has been bumped to 1.6.0 to account for the backwards
-   compatible feature listed above.
-
-Core Transfers
------------------
-
-The features.conf general section has three new configurable options:
-    * transferdialattempts
-	* transferretrysound
-	* transferinvalidsound
-For more information on what these options do, see the Asterisk wiki:
-	https://wiki.asterisk.org/wiki/x/W4fAAQ
-
-Channel Drivers
-------------------
-
-chan_pjsip
-------------------
- * New 'media_encryption_optimistic' endpoint setting. This will use SRTP
-   when possible but does not consider lack of it a failure.
-
-res_pjsip_endpoint_identifer_ip
-------------------
- * New CLI commands have been added: "pjsip show identif(y|ies)", which lists
-   all configured PJSIP identify objects
-   
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12 to Asterisk 13 --------------------
-------------------------------------------------------------------------------
-
-Overview
-------------------
-
-Asterisk 13 is the next Long Term Support (LTS) release of Asterisk. As such,
-the focus of development for this release of Asterisk was on improving the
-usability and features developed in the previous Standard release, Asterisk 12.
-Beyond a general refinement of end user features, development focussed heavily
-on the Asterisk APIs - the Asterisk Manager Interface (AMI) and the Asterisk
-REST Interface (ARI) - and the PJSIP stack in Asterisk. Some highlights of the
-new features include:
-
-* Asterisk security events are now provided via AMI, allowing end users to
-  monitor their Asterisk system in real time for security related issues.
-* External control of Message Waiting Indicators (MWI) through both AMI and ARI.
-* Reception/transmission of out of call text messages using any supported
-  channel driver/protocol stack through ARI.
-* Resource List Server support in the PJSIP stack, providing subscriptions to
-  lists of resources and batched delivery of NOTIFY requests.
-* Inter-Asterisk distributed device state and mailbox state using the PJSIP
-  stack.
-
-It is important to note that Asterisk 13 is built on the architecture developed
-during the previous Standard release, Asterisk 12. Users upgrading to
-Asterisk 13 should read about the new features in Asterisk 12 later in this file
-(see Functionality changes from Asterisk 11 to Asterisk 12), as well as the
-UPGRADE-12.txt delivered with this release. In particular, users upgrading to
-Asterisk 13 from a release prior to Asterisk 12 should read the specifications
-on AMI, CDRs, and CEL on the Asterisk wiki:
- * AMI - https://wiki.asterisk.org/wiki/x/dAFRAQ
- * CEL - https://wiki.asterisk.org/wiki/x/4ICLAQ
- * CDRs - https://wiki.asterisk.org/wiki/x/pwpRAQ
-
-Many new featuers in Asterisk 13 were introduced in point releases of
-Asterisk 12. Following this section - which documents the changes from all
-versions of Asterisk 12 to Asterisk 13 - users should examine the new features
-that were introduced in the point releases of Asterisk 12, as they are also
-included in Asterisk 13.
-
-Finally, all users upgrading to Asterisk 13 should read the UPGRADE.txt file
-delivered with this release.
-
-
-Build System
-------------------
- * Sample config files have been moved from configs/ to a sub-folder of that
-   directory, samples.
-
- * The menuselect utility has been pulled into the Asterisk repository. As a
-   result, the libxml2 development library is now a required dependency for
-   Asterisk.
-
- * A new Compiler Flag, REF_DEBUG, has been added. When enabled, reference
-   counted objects will emit additional debug information to the refs log file
-   located in the standard Asterisk log file directory. This log file is useful
-   in tracking down object leaks and other reference counting issues. Prior to
-   this version, this option was only available by modifying the source code
-   directly. This change also includes a new script, refcounter.py, in the
-   contrib folder that will process the refs log file. Note that this replaces
-   the refcounter utility that could be built from the utils directory.
-
-
-Applications
-------------------
-
-DahdiBarge
-------------------
- * This module was deprecated and has been removed. Users of app_dahdibarge
-   should use ChanSpy instead.
-
-MixMonitor
-------------------
- * New options to play a beep when starting a recording and stopping a recording
-   have been added.  The option "p" will play a beep to the channel that starts
-   the recording.  The option "P" will play a beep to the channel that stops the
-   recording.
-
-Queue
-------------------
- * Queue rules can now be stored in a database table, queue_rules. Unlike other
-   RealTime tables, the queue_rules table is only examined on module load or
-   module reload. A new general setting has been added to queuerules.conf,
-   'realtime_rules', which, when set to 'yes', will cause app_queue to look in
-   RealTime for additional queue rules to parse. Note that both the file and
-   the database can be used as a provide of queue rules when 'realtime_rules'
-   is set to 'yes'.
-
-   When app_queue is reloaded, all rules are re-parsed and loaded into memory.
-   There is no caching of RealTime queue rules.
-
-ReadFile
-------------------
- * This module was deprecated and has been removed. Users of app_readfile
-   should use func_env's FILE function instead.
-
-Say
-------------------
- * The 'say' family of dialplan applications now support the Japanese
-   language. The 'language' parameter in say.conf now recognizes a setting of
-   'ja', which will enable Japanese language specific mechanisms for playing
-   back numbers, dates, and other items.
-
-SayCountPL
-------------------
- * This module was deprecated and has been removed. Users of app_saycountpl
-   should use the Say family of applications.
-
-SetMusicOnHold
-------------------
- * The SetMusicOnHold dialplan application was deprecated and has been removed.
-   Users of the application should use the CHANNEL function's musicclass
-   setting instead.
-
-WaitMusicOnHold
-------------------
- * The WaitMusicOnHold dialplan application was deprecated and has been
-   removed. Users of the application should use MusicOnHold with a duration
-   parameter instead.
-
-VoiceMail
-------------------
- * VoiceMail and VoiceMailMain now support the Japanese language. The
-   'language' parameter in voicemail.conf now recognizes a setting of 'ja',
-   which will enable prompts to be played back using a Japanese grammatical
-   structure. Additional prompts are necessary for this functionality,
-   including:
-   - jb-arimasu: there is
-   - jb-arimasen: there is not
-   - jb-oshitekudasai: please press
-   - jb-ni: article ni
-   - jb-ga: article ga
-   - jb-wa: article wa
-   - jb-wo: article wo
-
- * Add the ability to specify multiple email addresses in configuration,
-   separated by a |.
-
-
-CDR Backends
-------------------
-
-cdr_sqlite
------------------
- * This module was deprecated and has been removed. Users of cdr_sqlite
-   should use cdr_sqlite3_custom.
-
-cdr_pgsql
-------------------
- * Added the ability to support PostgreSQL application_name on connections.
-   This allows PostgreSQL to display the configured name in the
-   pg_stat_activity view and CSV log entries. This setting is configurable
-   for cdr_pgsql via the appname configuration setting in cdr_pgsql.conf.
-
-
-CEL Backends
-------------------
-
-cel_pgsql
-------------------
- * Added the ability to support PostgreSQL application_name on connections.
-   This allows PostgreSQL to display the configured name in the
-   pg_stat_activity view and CSV log entries. This setting is configurable
-   for cel_pgsql via the appname configuration setting in cel_pgsql.conf.
-
-
-Channel Drivers
-------------------
-
-chan_dahdi
-------------------
- * SS7 support now requires libss7 v2.0 or later.
-
- * Added SS7 support for connected line and redirecting.
-
- * Most SS7 CLI commands are reworked as well as new SS7 commands added.
-   See online CLI help.
-
- * Added several SS7 config option parameters described in
-   chan_dahdi.conf.sample.
-
-chan_gtalk
-------------------
- * This module was deprecated and has been removed. Users of chan_gtalk
-   should use chan_motif.
-
-chan_h323
-------------------
- * This module was deprecated and has been removed. Users of chan_h323
-   should use chan_ooh323.
-
-chan_jingle
-------------------
- * This module was deprecated and has been removed. Users of chan_jingle
-   should use chan_motif.
-
-chan_pjsip
-------------------
- * Added the CLI command 'pjsip list ciphers' so a user can know what
-   OpenSSL names are available on their system for the pjsip.conf cipher
-   option.
-
-chan_sip
-------------------
- * The SIPPEER dialplan function no longer supports using a colon as a
-   delimiter for parameters. The parameters for the function should be
-   delimited using a comma.
-
- * The SIPCHANINFO dialplan function was deprecated and has been removed. Users
-   of the function should use the CHANNEL function instead.
-
-
-Core
-------------------
-
-Account Codes
-------------------
- * Added functional peeraccount support.  Except for Queue, the
-   accountcode propagation is now consistently propagated to outgoing
-   channels before dialing.  The channel accountcode can change from its
-   original non-empty value on channel creation for the following specific
-   reasons.  One, dialplan sets it using CHANNEL(accountcode).  Two, an
-   originate method that can specify an accountcode value.  Three, the
-   calling channel propagates its peeraccount or accountcode to the
-   outgoing channel's accountcode before dialing.  The change has two
-   visible effects.  One, local channels now cross accountcode and
-   peeraccount across the special bridge between the ;1 and ;2 channels
-   just like channels between normal bridges.  Two, the
-   CHANNEL(peeraccount) value can now be set before Dial and FollowMe to
-   set the accountcode on the outgoing channel(s).
-
-   For Queue, an outgoing channel's non-empty accountcode will not change
-   unless explicitly set by CHANNEL(accountcode).  The change has three
-   visible effects.  One, local channels now cross accountcode and
-   peeraccount across the special bridge between the ;1 and ;2 channels
-   just like channels between normal bridges.  Two, the queue member will
-   get an accountcode if it doesn't have one and one is available from the
-   calling channel's peeraccount.  Three, accountcode propagation includes
-   local channel members where the accountcodes are propagated early
-   enough to be available on the ;2 channel.
-
-AMI
-------------------
- * New DeviceStateChanged and PresenceStateChanged AMI events have been added.
-   These events are emitted whenever a device state or presence state change
-   occurs. The events are controlled by res_manager_device_state.so and
-   res_manager_presence_state.so. If the high frequency of these events is
-   problematic for you, do not load these modules.
-
- * Added DialplanExtensionAdd and DialplanExtensionRemove AMI commands. They
-   work in basically the same way as the 'dialplan add extension' and
-   'dialplan remove extension' CLI commands respectively.
-
- * New AMI action LoggerRotate reloads and rotates logger in the same manner
-   as CLI command 'logger rotate'
-
- * New AMI Actions FAXSessions, FAXSession, and FAXStats replicate the
-   functionality of CLI commands 'fax show sessions', 'fax show session',
-   and fax show stats' respectively.
-
- * New AMI actions PRIDebugSet, PRIDebugFileSet, and PRIDebugFileUnset
-   enable manager control over PRI debugging levels and file output.
-
- * AMI action PJSIPNotify may now send to a URI instead of only to a PJSIP
-   endpoint as long as a default outbound endpoint is set. This also applies
-   to the equivalent CLI command (pjsip send notify)
- 
- * The AMI action PJSIPShowEndpoint now includes ContactStatusDetail sections
-   that give information on Asterisk's attempts to qualify the endpoint.
-
- * The DialEnd event will now contain a Forward header if the dial is ending
-   due to the call being forwarded. The contents of the Forward header is the
-   extension in the number to which the call is being forwarded.
-
-CEL
-------------------
- * The "bridge_technology" extra field key has been added to BRIDGE_ENTER
-   and BRIDGE_EXIT events.
-
-Features
-------------------
- * Channel variables are now substituted in arguments passed to applications
-   run by using dynamic features.
-
-TLS
-------------------
- * The TLS core in Asterisk now supports Perfect Forward Secrecy (PFS).
-   Enabling PFS is attempted by default, and is dependent on the configuration
-   of the module using TLS.
-   - Ephemeral ECDH (ECDHE) is enabled by default. To disable it, do not
-     specify a ECDHE cipher suite in sip.conf, for example:
-       tlscipher=AES128-SHA:DES-CBC3-SHA
-   - Ephemeral DH (DHE) is disabled by default. To enable it, add DH parameters
-     into the private key file, e.g., sip.conf tlsprivatekey. For example, the
-     default dh2048.pem - see
-     http://www.opensource.apple.com/source/OpenSSL098/OpenSSL098-35.1/src/apps/dh2048.pem?txt
-   - Because clients expect the server to prefer PFS, and because OpenSSL sorts
-     its cipher suites by bit strength, see "openssl ciphers -v DEFAULT".
-     Consider re-ordering your cipher suites in the respective configuration
-     file. For example:
-       tlscipher=AES128+kEECDH:AES128+kEDH:3DES+kEDH:AES128-SHA:DES-CBC3-SHA:-ADH:-AECDH
-     will use PFS when offered by the client. Clients which do not offer PFS
-     fall-back to AES-128 (or even 3DES, as recommended by RFC 3261).
-
-
-Functions
-------------------
-
-JACK_HOOK
-------------------
- * The JACK_HOOK function now supports audio with a sample rate higher than
-   8kHz.
-
-
-Resources
-------------------
-
-res_config_pgsql
-------------------
- * Added the ability to support PostgreSQL application_name on connections.
-   This allows PostgreSQL to display the configured name in the
-   pg_stat_activity view and CSV log entries. This setting is configurable
-   for res_config_pgsql via the dbappname configuration setting in
-   res_pgsql.conf.
-
-res_pjsip_outbound_publish
-------------------
- * A new module, res_pjsip_outbound_publish provides the mechanisms for sending
-   PUBLISH requests for specific event packages to another SIP User Agent.
-
-res_pjsip_pubsub
-------------------
- * The publish/subscribe core module has been updated to support RFC 4662
-   Resource Lists, allowing Asterisk to act as a Resource List Server (RLS).
-   Resource lists are configured in pjsip.conf under a new object type,
-   resource_list. Resource lists can contain either message-summary or presence
-   events, and can be composed of specific resources that provide the event or
-   other resource lists.
-
- * Inbound publication support is provided by a new object, inbound-publication.
-   This configures res_pjsip_pubsub to accept PUBLISH requests from a particular
-   resource. Which events are accepted is constructed dynamically; see
-   res_pjsip_publish_asterisk for more information.
-
-res_pjsip_publish_asterisk
-------------------
- * A new module, res_pjsip_publish_asterisk adds support for PUBLISH requests of
-   Asterisk information to other Asterisk servers. This module is intended only
-   for Asterisk to Asterisk exchanges of information. Currently, this includes
-   both mailbox state and device state information.
 
 ------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12.4.0 to Asterisk 12.5.0 ------------
+--- Functionality changes since Asterisk 11.15 --------------------------------
 ------------------------------------------------------------------------------
 
-ARI
-------------------
- * Stored recordings now support a new operation, copy. This will take an
-   existing stored recording and copy it to a new location in the recordings
-   directory.
-
- * LiveRecording objects now have three additional fields that can be reported
-   in a RecordingFinished ARI event:
-   - total_duration: the duration of the recording
-   - talking_duration: optional. The duration of talking detected in the
-     recording. This is only available if max_silence_seconds was specified
-     when the recording was started.
-   - silence_duration: optional. The duration of silence detected in the
-     recording. This is only available if max_silence_seconds was specified
-     when the recording was started.
-   Note that all duration values are reported in seconds.
-
- * Users of ARI can now send and receive out of call text messages. Messages
-   can be sent directly to a particular endpoint, or can be sent to the
-   endpoints resource directly and inferred from the URI scheme. Text
-   messages are passed to ARI clients as TextMessageReceived events. ARI
-   clients can choose to receive text messages by subscribing to the particular
-   endpoint technology or endpoints that they are interested in.
-
- * The applications resource now supports subscriptions to all endpoints of
-   a particular channel technology. For example, subscribing to an eventSource
-   of 'endpoint:PJSIP' will subscribe to all PJSIP endpoints.
-
-res_pjsip
-------------------
- * The endpoint configuration object now supports 'accountcode'. Any channel
-   created for an endpoint with this setting will have its accountcode set
-   to the specified value.
-
-res_hep_rtcp
-------------------
- * A new module, res_hep_rtcp, has been added that will forward RTCP call
-   statistics to a HEP capture server. See res_hep for more information.
-
-Functions
-------------------
- * Function AUDIOHOOK_INHERIT has been deprecated. Audiohooks are now
-   unconditionally inhereted through masquerades. As a side benefit, more
-   than one audiohook of a given type may persist through a masquerade now.
-
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12.3.0 to Asterisk 12.4.0 ------------
-------------------------------------------------------------------------------
-
-AgentRequest
-------------------
- * Returns new AGENT_STATUS value "NOT_CONNECTED" if the agent fails to
-   connect with an incoming caller after being alerted to the presence
-   of the incoming caller.  The most likely reason this would happen is
-   the agent did not acknowledge the call in time.
-
-AMI
-------------------
- * New events have been added for the TALK_DETECT function. When the function
-   is used on a channel, ChannelTalkingStart/ChannelTalkingStop events will be
-   emitted to connected AMI clients indicating the start/stop of talking on
-   the channel.
-
-ARI
-------------------
- * New event models have been aded for the TALK_DETECT function. When the
-   function is used on a channel, ChannelTalkingStarted/ChannelTalkingFinished
-   events will be emitted to connected WebSockets subscribed to the channel,
-   indicating the start/stop of talking on the channel.
-
-Functions
-------------------
- * A new function, TALK_DETECT, has been added. When set on a channel, this
-   fucntion causes events indicating the starting/stoping of talking on said
-   channel to be emitted to both AMI and ARI clients.
+res_fax
+-----------
+ * The T.38 negotiation timeout was previously hard coded at 5000 milliseconds
+   and is now configurable via the 't38timeout' configuration option in
+   res_fax.conf and via the fax options dialplan function 'FAXOPT(t38timeout)'.
+   The default remains at 5000 milliseconds.
 
 ------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12.2.0 to Asterisk 12.3.0 ------------
+--- Functionality changes since Asterisk 11.8 --------------------------------
 ------------------------------------------------------------------------------
 
-ARI
-------------------
- * A new Playback URI 'tone' has been added. Tones are specified either as
-   an indication name (e.g. 'tone:busy') from indications.conf or as a tone
-   pattern (e.g. 'tone:240/250,0/250'). Tones differ from normal playback
-   URIs in that they must be stopped manually and will continue to occupy
-   a channel's ARI control queue until they are stopped. They also can not
-   be rewound or fastforwarded.
-
- * User events can now be generated from ARI.  Events can be signalled with
-   arbitrary json variables, and include one or more of channel, bridge, or
-   endpoint snapshots.  An application must be specified which will receive
-   the event message (other applications can subscribe to it).  The message
-   will also be delivered via AMI provided a channel is attached.  Dialplan
-   generated user event messages are still transmitted via the channel, and
-   will only be received by a stasis application they are attached to or if
-   the channel is subscribed to.
-
 chan_sip
 -----------
  * SIP peers can now specify 'trust_id_outbound' which affects RPID/PAI
@@ -524,1496 +42,6 @@ chan_sip
      calling information to communicate that the private information should
      not be relayed to untrusted parties.
 
-res_parking
-------------------
- * Manager action 'Park' now takes an additional argument 'AnnounceChannel'
-   which can be used to announce the parked call's location to an arbitrary
-   channel in a bridge. If 'Channel' and 'TimeoutChannel' are now the two
-   parties in a one to one bridge, 'TimeoutChannel' is treated as having
-   parked 'Channel' like with the Park Call DTMF feature and will receive
-   announcements prior to being hung up.
-
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12.1.0 to Asterisk 12.2.0 ------------
-------------------------------------------------------------------------------
-
-Record
-------------------
- * Record application now has an option 'o' which allows 0 to act as an exit
-   key setting the RECORD_STATUS variable to 'OPERATOR' instead of 'DTMF'
-
-ChanSpy
---------------------------
- * ChanSpy now accepts a channel uniqueid or a fully specified channel name
-   as the chanprefix parameter if the 'u' option is specified.
-
-ConfBridge
---------------------------
- * CONFBRIDGE dialplan function is now capable of creating/modifying dynamic
-   conference user menus.
-
- * CONFBRIDGE dialplan function is now capable of removing dynamic conference
-   menus, bridge settings, and user settings that have been applied by the
-   CONFBRIDGE dialplan function.
-
- * The ConfBridge dialplan application now sets a channel variable,
-   CONFBRIGE_RESULT, upon exiting. This variable can be used to determine
-   how a channel exited the conference.
-
- * Added conference user option 'announce_join_leave_review'. This option
-   implies 'announce_join_leave' with the added effect that the user will
-   be asked if they want to confirm or re-record the recording of their
-   name when entering the conference
-
-Directory
---------------------------
- * At exit, the Directory application now sets a channel variable
-   DIRECTORY_RESULT to one of the following based on the reason for exiting:
-     OPERATOR    user requested operator by pressing '0' for operator
-     ASSISTANT   user requested assistant by pressing '*' for assistant
-     TIMEOUT     user pressed nothing and Directory stopped waiting
-     HANGUP      user's channel hung up
-     SELECTED    user selected a user from the directory and is routed
-     USEREXIT    user pressed '#' from the selection prompt to exit
-     FAILED      directory failed in a way that wasn't accounted for. Dang.
-
-Monitor
-------------------
- * Monitor() - A new option, B(), has been added that will turn on a periodic
-   beep while the call is being recorded.
-
-MusicOnHold
---------------------------
- * MusicOnHold streams (all modes other than "files") now support wide band
-   audio too.
-
-Page
---------------------------
- * Added options 'b' and 'B' to apply predial handlers for outgoing calls
-   and for the channel executing Page respectively.
-
-PickupChan
---------------------------
- * PickupChan now accepts channel uniqueids of channels to pickup.
-
-Say
---------------------------
- * If a channel variable SAY_DTMF_INTERRUPT is present on a channel and set
-   to 'true' (case insensitive), then any Say application (SayNumber,
-   SayDigits, SayAlpha, SayAlphaCase, SayUnixTime, and SayCounted) will
-   anticipate DTMF. If DTMF is received, these applications will behave like
-   the background application and jump to the received extension once a match
-   is established or after a short period of inactivity.
-
-MixMonitor
--------------------------
- * A new function, MIXMONITOR, has been added to allow access to individual
-   instances of MixMonitor on a channel.
-
- * A new option, B(), has been added that will turn on a periodic beep while the
-   call is being recorded.
-
-
-Channel Drivers
--------------------------
-
-chan_sip
--------------------------
- * TEL URI support for inbound INVITE requests has been added. chan_sip will
-   now handle TEL schemes in the Request and From URIs. The phone-context in
-   the Request URI will be stored in the SIPURIPHONECONTEXT channel variable on
-   the inbound channel.
-
-Core
-------------------
- * Exposed sorcery-based configuration files like pjsip.conf to dialplans via
-   the new AST_SORCERY diaplan function.
-
- * Core Show Locks output now includes Thread/LWP ID if the platform
-   supports this feature.
-
- * New "logger add channel" and "logger remove channel" CLI commands have
-   been added to allow creation and deletion of dynamic logger channels
-   without configuration changes. These dynamic logger channels will only
-   exist until the next restart of asterisk.
-
-ARI
-------------------
- * The live recording object on recording events now contains a target_uri
-   field which contains the URI of what is being recorded.
-
- * The bridge type used when creating a bridge is now a comma separated list of
-   bridge properties. Valid options are: mixing, holding, dtmf_events, and
-   proxy_media.
-
- * A channelId can now be provided when creating a channel, either in the
-   uri (POST channels/my-channel-id) or as query parameter.  A local channel
-   will suffix the second channel id with ';2' unless provided as query
-   parameter otherChannelId.
-
- * A bridgeId can now be provided when creating a bridge, either in the uri
-   (POST bridges/my-bridge-id) or as a query parameter.
-
- * A playbackId can be provided when starting a playback, either in the uri
-   (POST channels/my-channel-id/play/my-playback-id /
-    POST bridges/my-bridge-id/play/my-playback-id)  or as a query parameter.
-
- * A snoop channel can be started with a snoopId, in the uri or query.
-
-AMI
-------------------
- * Originate now takes optional parameters ChannelId and OtherChannelId,
-   used to set the UniqueId on creation.  The other id is assigned to the
-   second channel when dialing LOCAL, or defaults to appending ;2 if only
-   the single Id is given.
-
- * The Mixmonitor action now has a "Command" header that can be used to
-   indicate a post-process command to run once recording finishes.
-
-RealTime
-------------------
- * A new set of Alembic scripts has been added for CDR tables. This will create
-   a 'cdr' table with the default schema that Asterisk expects.
-
-
-Functions
-------------------
- * A new function was added: PERIODIC_HOOK.  This allows running a periodic
-   dialplan hook on a channel.  Any audio generated by this hook will be
-   injected into the call.
-
-
-Resources
-------------------
-
-res_hep
-------------------
- * A new module, res_hep, has been added, that acts as a generic packet
-   capture agent for the Homer Encapsulation Protocol (HEP) version 3.
-   It can be configured via hep.conf. Other modules can use res_hep to send
-   message traffic to a HEP capture server.
-
-res_hep_pjsip
-------------------
- * A new module, res_hep_pjsip, has been added that will forward PJSIP
-   message traffic to a HEP capture server. See res_hep for more
-   information.
-
-res_pjsip
-------------------
- * transport and endpoint ToS options (tos, tos_audio, and tos_video) may now
-   be set as the named set of ToS values (cs0-cs7, af11-af43, ef).
-
- * Added the following new CLI commands:
-   - "pjsip show contacts" - list all current PJSIP contacts.
-   - "pjsip show contact" - show specific information about a current PJSIP
-     contact.
-   - "pjsip show channel" - show detailed information about a PJSIP channel.
-
-res_pjsip_multihomed
-------------------
- * A new module, res_pjsip_multihomed handles situations where the system
-   Asterisk is running out has multiple interfaces. res_pjsip_multihomed
-   determines which interface should be used during message sending.
-
-res_pjsip_pidf_digium_body_supplement
-------------------
- * A new module, res_pjsip_pidf_digium_body_supplement provides NOTIFY
-   request body formatting for presence support in Digium phones.
-
-res_pjsip_send_to_voicemail
-------------------
- * A new module, res_pjsip_send_to_voicemail allows for REFER requests with
-   particular headers to transfer a PJSIP channel directly to a particular
-   extension that has VoiceMail. This is intended to be used with Digium
-   phones that support this feature.
-
-res_pjsip_outbound_registration
-------------------
- * A new CLI command has been added: "pjsip show registrations", which lists
-   all configured PJSIP registrations
-
-
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 12.0.0 to Asterisk 12.1.0 ------------
-------------------------------------------------------------------------------
-
-AMI
-------------------
- * Added a new module that provides AMI control over MWI within Asterisk,
-   res_mwi_external_ami. Note that this module depends on res_mwi_external;
-   for more information on enabling this module, see res_mwi_external.
-   This module provides the MWIGet/MWIUpdate/MWIDelete actions, as well as
-   the MWIGet/MWIGetComplete events.
-
- * The DialStatus field in the DialEnd event can now contain additional
-   statuses that convey how the dial operation terminated. This includes
-   ABORT, CONTINUE, and GOTO.
-
- * AMI will now emit security events. A new class authorization has been
-   added in manager.conf for the security events, 'security'. The new events
-   are:
-    - FailedACL - raised when a request violates an ACL check
-    - InvalidAccountID - raised when a request fails an authentication
-      check due to an invalid account ID
-    - SessionLimit - raised when a request fails due to exceeding the
-      number of allowed concurrent sessions for a service
-    - MemoryLimit - raised when a request fails due to an internal memory
-      allocation failure
-    - LoadAverageLimit - raised when a request fails because a configured
-      load average limit has been reached
-    - RequestNotAllowed - raised when a request is not allowed by
-      the service
-    - AuthMethodNotAllowed - raised when a request used an authentication
-      method not allowed by the service
-    - RequestBadFormat - raised when a request is received with bad formatting
-    - SuccessfulAuth - raised when a request successfully authenticates
-    - UnexpectedAddress - raised when a request has a different source address
-      then what is expected for a session already in progress with a service
-    - ChallengeResponseFailed - raised when a request's attempt to authenticate
-      has been challenged, and the request failed the authentication challenge
-    - InvalidPassword - raised when a request provides an invalid password
-      during an authentication attempt
-    - ChallengeSent - raised when an Asterisk service send an authentication
-      challenge to a request
-    - InvalidTransport - raised when a request attempts to use a transport not
-      allowed by the Asterisk service
-
- * Bridge related events now have two additional fields: BridgeName and
-   BridgeCreator. BridgeName is a descriptive name for the bridge;
-   BridgeCreator is the name of the entity that created the bridge. This
-   affects the following events: ConfbridgeStart, ConfbridgeEnd,
-   ConfbridgeJoin, ConfbridgeLeave, ConfbridgeRecord, ConfbridgeStopRecord,
-   ConfbridgeMute, ConfbridgeUnmute, ConfbridgeTalking, BlindTransfer,
-   AttendedTransfer, BridgeCreate, BridgeDestroy, BridgeEnter, BridgeLeave
-
-ARI
-------------------
- * The Bridge data model now contains the additional fields 'name' and
-   'creator'. The 'name' field conveys a descriptive name for the bridge;
-   the 'creator' field conveys the name of the entity that created the bridge.
-   This affects all responses to HTTP requests that return a Bridge data model
-   as well as all event derived data models that contain a Bridge data model.
-   The POST /bridges operation may now optionally specify a name to give to
-   the bridge being created.
-
- * Added a new ARI resource 'mailboxes' which allows the creation and
-   modification of mailboxes managed by external MWI. Modules res_mwi_external
-   and res_stasis_mailbox must be enabled to use this resource. For more
-   information on external MWI control, see res_mwi_external.
-
- * Added new events for externally initiated transfers. The event
-   BridgeBlindTransfer is now raised when a channel initiates a blind transfer
-   of a bridge in the ARI controlled application to the dialplan; the
-   BridgeAttendedTransfer event is raised when a channel initiates an
-   attended transfer of a bridge in the ARI controlled application to the
-   dialplan.
-
- * Channel variables may now be specified as a body parameter to the
-   POST /channels operation. The 'variables' key in the JSON is interpreted
-   as a sequence of key/value pairs that will be added to the created channel
-   as channel variables. Other parameters in the JSON body are treated as
-   query parameters of the same name.
-
-HTTP
-------------------
- * Asterisk's HTTP server now supports chunked Transfer-Encoding. This will be
-   automatically handled by the HTTP server if a request is received with a
-   Transfer-Encoding type of "chunked".
-
-res_pjsip
-------------------
- * Path support has been added with the 'support_path' option in registration
-   and aor sections.
-
- * A 'debug' option has been added to the globals section that will allow
-   sip messages to be logged.
-
- * A 'set_var' option has been added to endpoints that will automatically
-   set the desired variable(s) on a channel created for that endpoint.
-
- * Several new tables and columns have been added to the realtime schema for
-   the res_pjsip related modules. See the UPGRADE.txt notes for updating
-   the database schema.
-
-res_mwi_external
-------------------
- * A new module, res_mwi_external, has been added to Asterisk. This module
-   acts as a base framework that other modules can build on top of to allow
-   an external system to control MWI within Asterisk. For implementations
-   that make use of res_mwi_external, see res_mwi_external_ami and
-   res_ari_mailboxes. Note that res_mwi_external canflicts with other modules
-   that may produce MWI themselves, such as app_voicemail. res_mwi_external
-   and other modules that depend on it cannot be built or loaded with
-   app_voicemail present.
-
-res_pjsip
-------------------
- * DNS functionality will now automatically be enabled if the system configured
-   nameservers can be retrieved. If the system configured nameservers can not be
-   retrieved the functionality will resort to using system resolution. Functionalty
-   such as SRV records and failover will not be available if system resolution
-   is in use.
-
-------------------------------------------------------------------------------
---- Functionality changes from Asterisk 11 to Asterisk 12 --------------------
-------------------------------------------------------------------------------
-
-Overview
-------------------
-
-Asterisk 12 is a standard release of the Asterisk project. As such, the
-focus of development for this release was on core architectural changes and
-major new features. This includes:
- * A more flexible bridging core based on the Bridging API
- * A new internal message bus, Stasis
- * Major standardization and consistency improvements to AMI
- * Addition of the Asterisk RESTful Interface (ARI)
- * A new SIP channel driver, chan_pjsip
-In addition, as the vast majority of bridging in Asterisk was migrated to the
-Bridging API used by ConfBridge, major changes were made to most of the
-interfaces in Asterisk. This includes not only AMI, but also CDRs and CEL.
-
-Specifications have been written for the affected interfaces. These
-specifications are available on the Asterisk wiki:
- * AMI - https://wiki.asterisk.org/wiki/x/dAFRAQ
- * CEL - https://wiki.asterisk.org/wiki/x/4ICLAQ
- * CDRs - https://wiki.asterisk.org/wiki/x/pwpRAQ
-
-It is *highly* recommended that anyone migrating to Asterisk 12 read the
-information regarding its release both in this file and in the accompanying
-UPGRADE.txt file. More detailed information on the major changes can be found
-on the Asterisk wiki at https://wiki.asterisk.org/wiki/x/0YCLAQ.
-
-
-Build System
-------------------
- * Added build option DISABLE_INLINE. This option can be used to work around a
-   bug in gcc. For more information, see
-   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47816
-
- * Removed the CHANNEL_TRACE development mode build option. Certain aspects of
-   the CHANNEL_TRACE build option were incompatible with the new bridging
-   architecture.
-
- * Asterisk now optionally uses libxslt to improve XML documentation generation
-   and maintainability. If libxslt is not available on the system, some XML
-   documentation will be incomplete.
-
- * Asterisk now depends on libjansson. If a package of libjansson is not
-   available on your distro, please see http://www.digip.org/jansson/.
-
- * Asterisk now depends on libuuid and, optionally, uriparser. It is
-   recommended that you install uriparser, even if it is optional.
-
- * The new SIP stack and channel driver uses a particular version of PJSIP.
-   Please see https://wiki.asterisk.org/wiki/x/J4GLAQ for more information on
-   configuring and installing PJSIP for usage with Asterisk.
-
- * Optional API was re-implemented to be more portable, and no longer requires
-   weak reference support from the compiler. The build option OPTIONAL_API may
-   be disabled to disable Optional API support.
-
-Applications
-------------------
-
-AgentLogin
-------------------
- * Along with AgentRequest, this application has been modified to be a
-   replacement for chan_agent. The act of a channel calling the AgentLogin
-   application places the channel into a pool of agents that can be
-   requested by the AgentRequest application. Note that this application, as
-   well as all other agent related functionality, is now provided by the
-   app_agent_pool module. See chan_agent and AgentRequest for more information.
-
- * This application no longer performs agent authentication. If authentication
-   is desired, the dialplan needs to perform this function using the
-   Authenticate or VMAuthenticate application or through an AGI script before
-   running AgentLogin.
-
- * If this application is called and the agent is already logged in, the
-   dialplan will continue exection with the AGENT_STATUS channel variable set
-   to ALREADY_LOGGED_IN.
-
- * The agents.conf schema has changed. Rather than specifying agents on a
-   single line in comma delineated fashion, each agent is defined in a separate
-   context. This allows agents to use the power of context templates in their
-   definition.
-
- * A number of parameters from agents.conf have been removed. This includes
-   maxloginretries, autologoffunavail, updatecdr, goodbye, group, recordformat,
-   urlprefix, and savecallsin. These options were obsoleted by the move from
-   a channel driver model to the bridging/application model provided by
-   app_agent_pool.
-
-AgentRequest
-------------------
- * A new application, this will request a logged in agent from the pool and
-   bridge the requested channel with the channel calling this application.
-   Logged in agents are those channels that called the AgentLogin application.
-   If an agent cannot be requested from the pool, the AGENT_STATUS dialplan
-   application will be set with an appropriate error value.
-
-AgentMonitorOutgoing
-------------------
- * This application has been removed. It was a holdover from when
-   AgentCallbackLogin was removed.
-
-AlarmReceiver
-------------------
- * Added support for additional Ademco DTMF signalling formats, including
-   Express 4+1, Express 4+2, High Speed and Super Fast.
-
- * Added channel variable ALARMRECEIVER_CALL_LIMIT. This sets the maximum
-   call time, in milliseconds, to run the application.
-
- * Added channel variable ALARMRECEIVER_RETRIES_LIMIT. This sets the
-   maximum number of times to retry the call.
-
- * Added a new configuration option answait. If set, the AlarmReceiver
-   application will wait the number of milliseconds specified by answait
-   after the channel has answered. Valid values range between 500
-   milliseconds and 10000 milliseconds.
-
- * Added configuration option no_group_meta. If enabled, grouping of metadata
-   information in the AlarmReceiver log file will be skipped.
-
-Answer
-------------------
- * It is now no longer possible to bypass updating the CDR on the channel
-   when answering. CDRs reflect the state of the channel and will always
-   reflect the time they were Answered.
-
-BridgeWait
-------------------
- * A new application in Asterisk, this will place the calling channel
-   into a holding bridge, optionally entertaining them with some form of
-   media. Channels participating in a holding bridge do not interact with
-   other channels in the same holding bridge. Optionally, however, a channel
-   may join as an announcer. Any media passed from an announcer channel is
-   played to all channels in the holding bridge. Channels leave a holding
-   bridge either when an optional timer expires, or via the ChannelRedirect
-   application or AMI Redirect action.
-
-ConfBridge
-------------------
- * All participants in a bridge can now be kicked out of a conference room
-   by specifying the channel parameter as 'all' in the ConfBridge kick CLI
-   command, i.e., 'confbridge kick <conference> all'
-
- * CLI output for the 'confbridge list' command has been improved. When
-   displaying information about a particular bridge, flags will now be shown
-   for the participating users indicating properties of that user.
-
- * The ConfbridgeList event now contains the following fields: WaitMarked,
-   EndMarked, and Waiting. This displays additional properties about the
-   user's profile, as well as whether or not the user is waiting for a
-   Marked user to enter the conference.
-
- * Added a new option for conference recording, record_file_append. If enabled,
-   when the recording is stopped and then re-started, the existing recording
-   will be used and appended to.
-
- * ConfBridge now has the ability to set the language of announcements to the
-   conference.  The language can be set on a bridge profile in confbridge.conf
-   or by the dialplan function CONFBRIDGE(bridge,language)=en.
-
-ControlPlayback
-------------------
- * The channel variable CPLAYBACKSTATUS may now return the value
-   'REMOTESTOPPED'. This occurs when playback is stopped by a remote interface,
-   such as AMI. See the AMI action ControlPlayback for more information.
-
-Directory
-------------------
- * Added the 'a' option, which allows the caller to enter in an additional
-   alias for the user in the directory. This option must be used in conjunction
-   with the 'f', 'l', or 'b' options. Note that the alias for a user can be
-   specified in voicemail.conf.
-
-DumpChan
-------------------
- * The output of DumpChan no longer includes the DirectBridge or IndirectBridge
-   fields. Instead, if a channel is in a bridge, it includes a BridgeID field
-   containing the unique ID of the bridge that the channel happens to be in.
-
-ForkCDR
-------------------
- * ForkCDR no longer automatically resets the forked CDR. See the 'r' option
-   for more information.
-
- * Variables are no longer purged from the original CDR. See the 'v' option for
-   more information.
-
- * The 'A' option has been removed. The Answer time on a CDR is never updated
-   once set.
-
- * The 'd' option has been removed. The disposition on a CDR is a function of
-   the state of the channel and cannot be altered.
-
- * The 'D' option has been removed. Who the Party B is on a CDR is a function
-   of the state of the respective channels involved in the CDR and cannot be
-   altered.
-
- * The 'r' option has been changed. Previously, ForkCDR always reset the CDR
-   such that the start time and, if applicable, the answer time was updated.
-   Now, by default, ForkCDR simply forks the CDR, maintaining any times. The
-   'r' option now triggers the Reset, setting the start time (and answer time
-   if applicable) to the current time. Note that the 'a' option still sets
-   the answer time to the current time if the channel was already answered.
-
- * The 's' option has been removed. A variable can be set on the original CDR
-   if desired using the CDR function, and removed from a forked CDR using the
-   same function.
-
- * The 'T' option has been removed. The concept of DONT_TOUCH and LOCKED no
-   longer applies in the CDR engine.
-
- * The 'v' option now prevents the copy of the variables from the original CDR
-   to the forked CDR. Previously the variables were always copied but were
-   removed from the original. This was changed as removing variables from a CDR
-   can have unintended side effects - this option allows the user to prevent
-   propagation of variables from the original to the forked without modifying
-   the original.
-
-MeetMe
--------------------
- * Added the 'n' option to MeetMe to prevent application of the DENOISE
-   function to a channel joining a conference. Some channel drivers that vary
-   the number of audio samples in a voice frame will experience significant
-   quality problems if a denoiser is attached to the channel; this option gives
-   them the ability to remove the denoiser without having to unload func_speex.
-
-MixMonitor
-------------------
- * The 'b' option now includes conferences as well as sounds played to the
-   participants.
-
- * The AUDIOHOOK_INHERIT function is no longer needed to keep a MixMonitor
-   running during a transfer. If a MixMonitor is started on a channel,
-   the MixMonitor will continue to record the audio passing through the
-   channel even in the presence of transfers.
-
-NoCDR
-------------------
- * The NoCDR application is deprecated. Please use the CDR_PROP function to
-   disable CDRs.
-
- * While the NoCDR application will prevent CDRs for a channel from being
-   propagated to registered CDR backends, it will not prevent that data from
-   being collected. Hence, a subsequent call to ResetCDR or the CDR_PROP
-   function that enables CDRs on a channel will restore those records that have
-   not yet been finalized.
-
-ParkAndAnnounce
--------------------
- * The app_parkandannounce module has been removed. The application
-   ParkAndAnnounce is now provided by the res_parking module. See the
-   res_parking changes for more information.
-
-Queue
--------------------
- * Added queue available hint. The hint can be added to the dialplan using the
-   following syntax: exten,hint,Queue:{queue_name}_avail
-   For example, if the name of the queue is 'markq':
-        exten => 8501,hint,Queue:markq_avail
-   This will report 'InUse' if there are no logged in agents or no free agents.
-   It will report 'Idle' when an agent is free.
-
- * Queues now support a hint for member paused state. The hint uses the form
-   'Queue:{queue_name}_pause_{member_name}', where {queue_name} and {member_name}
-   are the name of the queue and the name of the member to subscribe to,
-   respectively. For example: exten => 8501,hint,Queue:sales_pause_mark.
-   Members will show as In Use when paused.
-
- * The configuration options eventwhencalled and eventmemberstatus have been
-   removed.  As a result, the AMI events QueueMemberStatus, AgentCalled,
-   AgentConnect, AgentComplete, AgentDump, and AgentRingNoAnswer will always be
-   sent.  The "Variable" fields will also no longer exist on the Agent* events.
-   These events can be filtered out from a connected AMI client using the
-   eventfilter setting in manager.conf.
-
- * The queue log now differentiates between blind and attended transfers. A
-   blind transfer will result in a BLINDTRANSFER message with the destination
-   context and extension. An attended transfer will result in an
-   ATTENDEDTRANSFER message. This message will indicate the method by which
-   the attended transfer was completed: "BRIDGE" for a bridge merge, "APP"
-   for running an application on a bridge or channel, or "LINK" for linking
-   two bridges together with local channels. The queue log will also now detect
-   externally initiated blind and attended transfers and record the transfer
-   status accordingly.
-
- * When performing queue pause/unpause on an interface without specifying an
-   individual queue, the PAUSEALL/UNPAUSEALL event will only be logged if at
-   least one member of any queue exists for that interface.
-
- * Added the 'queue_log_realtime_use_gmt' option to have timestamps in GMT
-   for realtime queue log entries.
-
-ResetCDR
-------------------
- * The 'e' option has been deprecated. Use the CDR_PROP function to re-enable
-   CDRs when they were previously disabled on a channel.
-
- * The 'w' and 'a' options have been removed. Dispatching CDRs to registered
-   backends occurs on an as-needed basis in order to preserve linkedid
-   propagation and other needed behavior.
-
-SayAlphaCase
-------------------
- * A new application, this is similar to SayAlpha except that it supports
-   case sensitive playback of the specified characters. For example,
-   SayAlphaCase(u,aBc) will result in 'a uppercase b c'.
-
-SetAMAFlags
-------------------
- * This application is deprecated in favor of CHANNEL(amaflags).
-
-SendDTMF
-------------------
- * The SendDTMF application will now accept 'W' as valid input. This will cause
-   the application to delay one second while streaming DTMF.
-
-Stasis
-------------------
- * A new application in Asterisk 12, this hands control of the channel calling
-   the application over to an external system. Currently, external systems
-   manipulate channels in Stasis through the Asterisk RESTful Interface (ARI).
-
-UserEvent
-------------------
- * UserEvent will now handle duplicate keys by overwriting the previous value
-   assigned to the key.
-
- * In addition to AMI, UserEvent invocations will now be distributed to any
-   interested Stasis applications.
-
-VoiceMail
-------------------
- * Mailboxes defined by app_voicemail MUST be referenced by the rest of the
-   system as mailbox at context.  The rest of the system cannot add @default
-   to mailbox identifiers for app_voicemail that do not specify a context
-   any longer.  It is a mailbox identifier format that should only be
-   interpreted by app_voicemail.
-
- * The voicemail.conf configuration file now has an 'alias' configuration
-   parameter for use with the Directory application. The voicemail realtime
-   database table schema has also been updated with an 'alias' column.
-
-
-Codecs
-------------------
- * Pass through support has been added for both VP8 and Opus.
-
- * Added format attribute negotiation for the Opus codec. Format attribute
-   negotiation is provided by the res_format_attr_opus module.
-
-
-Core
-------------------
- * Masquerades as an operation inside Asterisk have been effectively hidden
-   by the migration to the Bridging API. As such, many 'quirks' of Asterisk
-   no longer occur. This includes renaming of channels, "<ZOMBIE>" channels,
-   dropping of frame/audio hooks, and other internal implementation details
-   that users had to deal with. This fundamental change has large implications
-   throughout the changes documented for this version. For more information
-   about the new core architecture of Asterisk, please see the Asterisk wiki.
-
- * Multiple parties in a bridge may now be transferred. If a participant in a
-   multi-party bridge initiates a blind transfer, a Local channel will be used
-   to execute the dialplan location that the transferer sent the parties to. If
-   a participant in a multi-party bridge initiates an attended transfer,
-   several options are possible. If the attended transfer results in a transfer
-   to an application, a Local channel is used. If the attended transfer results
-   in a transfer to another channel, the resulting channels will be merged into
-   a single bridge.
-
- * The channel variable ATTENDED_TRANSFER_COMPLETE_SOUND is no longer channel
-   driver specific.  If the channel variable is set on the transferrer channel,
-   the sound will be played to the target of an attended transfer.
-
- * The channel variable BRIDGEPEER becomes a comma separated list of peers in
-   a multi-party bridge.  The BRIDGEPEER value can have a maximum of 10 peers
-   listed.  Any more peers in the bridge will not be included in the list.
-   BRIDGEPEER is not valid in holding bridges like parking since those channels
-   do not talk to each other even though they are in a bridge.
-
- * The channel variable BRIDGEPVTCALLID is only valid for two party bridges
-   and will contain a value if the BRIDGEPEER's channel driver supports it.
-
- * A channel variable ATTENDEDTRANSFER is now set which indicates which channel
-   was responsible for an attended transfer in a similar fashion to
-   BLINDTRANSFER.
-
- * Modules using the Configuration Framework or Sorcery must have XML
-   configuration documentation. This configuration documentation is included
-   with the rest of Asterisk's XML documentation, and is accessible via CLI
-   commands. See the CLI changes for more information.
-
-AMI (Asterisk Manager Interface)
-------------------
- * Major changes were made to both the syntax as well as the semantics of the
-   AMI protocol. In particular, AMI events have been substantially improved
-   in this version of Asterisk. For more information, please see the AMI
-   specification at https://wiki.asterisk.org/wiki/x/dAFRAQ
-
- * AMI events that reference a particular channel or bridge will now always
-   contain a standard set of fields. When multiple channels or bridges are
-   referenced in an event, fields for at least some subset of the channels
-   and bridges in the event will be prefixed with a descriptive name to avoid
-   name collisions. See the AMI event documentation on the Asterisk wiki for
-   more information.
-
- * The CLI command 'manager show commands' no longer truncates command names
-   longer than 15 characters and no longer shows authorization requirement
-   for commands. 'manager show command' now displays the privileges needed
-   for using a given manager command instead.
-
- * The SIPshowpeer action will now include a 'SubscribeContext' field for a
-   peer in its response if the peer has a subscribe context set.
-
- * The SIPqualifypeer action now acknowledges the request once it has
-   established that the request is against a known peer. It also issues a new
-   event, 'SIPQualifyPeerDone', once the qualify action has been completed.
-
- * The PlayDTMF action now supports an optional 'Duration' parameter.  This
-   specifies the duration of the digit to be played, in milliseconds.
-
- * Added VoicemailRefresh action to allow an external entity to trigger mailbox
-   updates when changes occur instead of requiring the use of pollmailboxes.
-
- * Added a new action 'ControlPlayback'. The ControlPlayback action allows an
-   AMI client to manipulate audio currently being played back on a channel. The
-   supported operations depend on the application being used to send audio to
-   the channel. When the audio playback was initiated using the ControlPlayback
-   application or CONTROL STREAM FILE AGI command, the audio can be paused,
-   stopped, restarted, reversed, or skipped forward. When initiated by other
-   mechanisms (such as the Playback application), the audio can be stopped,
-   reversed, or skipped forward.
-
- * Channel related events now contain a snapshot of channel state, adding new
-   fields to many of these events.
-
- * The AMI event 'Newexten' field 'Extension' is deprecated, and may be removed
-   in a future release. Please use the common 'Exten' field instead.
-
- * The AMI event 'UserEvent' from app_userevent now contains the channel state
-   fields. The channel state fields will come before the body fields.
-
- * The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
-   'UnParkedCall' have changed significantly in the new res_parking module.
-
-   The 'Channel' and 'From' headers are gone. For the channel that was parked
-   or is coming out of parking, a 'Parkee' channel snapshot is issued and it
-   has a number of fields associated with it. The old 'Channel' header relayed
-   the same data as the new 'ParkeeChannel' header.
-
-   The 'From' field was ambiguous and changed meaning depending on the event.
-   for most of these, it was the name of the channel that parked the call
-   (the 'Parker'). There is no longer a header that provides this channel name,
-   however the 'ParkerDialString' will contain a dialstring to redial the
-   device that parked the call.
-
-   On UnParkedCall events, the 'From' header would instead represent the
-   channel responsible for retrieving the parkee. It receives a channel
-   snapshot labeled 'Retriever'. The 'from' field is is replaced with
-   'RetrieverChannel'.
-
-   Lastly, the 'Exten' field has been replaced with 'ParkingSpace'.
-
- * The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar
-   fashion has changed the field names 'StartExten' and 'StopExten' to
-   'StartSpace' and 'StopSpace' respectively.
-
- * The deprecated use of | (pipe) as a separator in the channelvars setting in
-   manager.conf has been removed.
-
- * Channel Variables conveyed with a channel no longer contain the name of the
-   channel as part of the key field, i.e., ChanVariable(SIP/foo): bar=baz is now
-   ChanVariable: bar=baz. When multiple channels are present in a single AMI
-   event, the various ChanVariable fields will contain a suffix that specifies
-   which channel they correspond to.
-
- * The NewPeerAccount AMI event is no longer raised. The NewAccountCode AMI
-   event always conveys the AMI event for a particular channel.
-
- * All 'Reload' events have been consolidated into a single event type. This
-   event will always contain a Module field specifying the name of the module
-   and a Status field denoting the result of the reload. All modules now issue
-   this event when being reloaded.
-
- * The 'ModuleLoadReport' event has been removed. Most AMI connections would
-   fail to receive this event due to being connected after modules have loaded.
-   AMI connections that want to know when Asterisk is ready should listen for
-   the 'FullyBooted' event.
-
- * app_fax now sends the same send fax/receive fax events as res_fax. The
-   'FaxSent' event is now the 'SendFAX' event, and the 'FaxReceived' event is
-   now the 'ReceiveFAX' event.
-
- * The 'MusicOnHold' event is now two events: 'MusicOnHoldStart' and
-   'MusicOnHoldStop'. The sub type field has been removed.
-
- * The 'JabberEvent' event has been removed. It is not AMI's purpose to be a
-   carrier for another protocol.
-
- * The Bridge Manager action's 'Playtone' header now accepts more fine-grained
-   options. 'Channel1' and 'Channel2' may be specified in order to play a tone
-   to the specific channel. 'Both' may be specified to play a tone to both
-   channels. The old 'yes' option is still accepted as a way of playing the
-   tone to Channel2 only.
-
- * The AMI 'Status' response event to the AMI Status action replaces the
-   'BridgedChannel' and 'BridgedUniqueid' headers with the 'BridgeID' header to
-   indicate what bridge the channel is currently in.
-
- * The AMI 'Hold' event has been moved out of individual channel drivers, into
-   core, and is now two events: 'Hold' and 'Unhold'.  The status field has been
-   removed.
-
- * The AMI events in app_queue have been made more consistent with each other.
-   Events that reference channels (QueueCaller* and Agent*) will show
-   information about each channel.  The (infamous) 'Join' and 'Leave' AMI
-   events have been changed to 'QueueCallerJoin' and 'QueueCallerLeave'.
-
- * The 'MCID' AMI event now publishes a channel snapshot when available and
-   its non-channel-snapshot parameters now use either the "MCallerID" or
-   'MConnectedID' prefixes with Subaddr*, Name*, and Num* suffixes instead
-   of 'CallerID' and 'ConnectedID' to avoid confusion with similarly named
-   parameters in the channel snapshot.
-
- * The AMI events 'Agentlogin' and 'Agentlogoff' have been renamed
-   'AgentLogin' and 'AgentLogoff' respectively.
-
- * The 'Channel' key used in the 'AlarmClear', 'Alarm', and 'DNDState' has been
-   renamed "DAHDIChannel" since it does not convey an Asterisk channel name.
-
- * 'ChannelUpdate' events have been removed.
-
- * All AMI events now contain a 'SystemName' field, if available.
-
- * Local channel optimization is now conveyed in two events:
-   'LocalOptimizationBegin' and 'LocalOptimizationEnd'. The Begin event is sent
-   when the Local channel driver begins attempting to optimize itself out of
-   the media path; the End event is sent after the channel halves have
-   successfully optimized themselves out of the media path.
-
- * Local channel information in events is now prefixed with 'LocalOne' and
-   'LocalTwo'. This replaces the suffix of '1' and '2' for the two halves of
-   the Local channel. This affects the 'LocalBridge', 'LocalOptimizationBegin',
-   and 'LocalOptimizationEnd' events.
-
- * The option 'allowmultiplelogin' can now be set or overriden in a particular
-   account. When set in the general context, it will act as the default
-   setting for defined accounts.
-
- * The 'BridgeAction' event was removed. It technically added no value, as the
-   Bridge Action already receives confirmation of the bridge through a
-   successful completion Event.
-
- * The 'BridgeExec' events were removed. These events duplicated the events that
-   occur in the Briding API, and are conveyed now through BridgeCreate,
-   BridgeEnter, and BridgeLeave events.
-
- * The 'RTCPSent'/'RTCPReceived' events have been significantly modified from
-   previous versions. They now report all SR/RR packets sent/received, and
-   have been restructured to better reflect the data sent in a SR/RR. In
-   particular, the event structure now supports multiple report blocks.
-
- * Added 'BlindTransfer' and 'AttendedTransfer' events. These events are
-   raised when a blind transfer/attended transfer completes successfully.
-   They contain information about the transfer that just completed, including
-   the location of the transfered channel.
-
- * Added a 'security' class to AMI which outputs the required fields for
-   security messages similar to the log messages from res_security_log
-
- * The AMI event 'ExtensionStatus' now contains a 'StatusText' field
-   that describes the status value in a human readable string.
-
-CDR (Call Detail Records)
-------------------
- * Significant changes have been made to the behavior of CDRs. The CDR engine
-   was effectively rewritten and built on the Stasis message bus. For a full
-   definition of CDR behavior in Asterisk 12, please read the specification
-   on the Asterisk wiki (wiki.asterisk.org).
-
- * CDRs will now be created between all participants in a bridge. For each
-   pair of channels in a bridge, a CDR is created to represent the path of
-   communication between those two endpoints. This lets an end user choose who
-   to bill for what during bridge operations with multiple parties.
-
- * The duration, billsec, start, answer, and end times now reflect the times
-   associated with the current CDR for the channel, as opposed to a cumulative
-   measurement of all CDRs for that channel.
-
- * When a CDR is dispatched, user defined CDR variables from both parties are
-   included in the resulting CDR. If both parties have the same variable, only
-   the Party A value is provided.
-
- * Added a new option to cdr.conf, 'debug'. When enabled, significantly more
-   information regarding the CDR engine is logged as verbose messages. This
-   option should only be used if the behavior of the CDR engine needs to be
-   debugged.
-
- * Added CLI command 'cdr set debug {on|off}'. This toggles the 'debug' setting
-   normally configured in cdr.conf.
-
- * Added CLI command 'cdr show active {channel}'. When {channel} is not
-   specified, this command provides a summary of the channels with CDR
-   information and their statistics. When {channel} is specified, it shows
-   detailed information about all records associated with {channel}.
-
-CEL (Channel Event Logging)
-------------------
- * CEL has undergone significant rework in Asterisk 12, and is now built on the
-   Stasis message bus. Please see the specification for CEL on the Asterisk
-   wiki at https://wiki.asterisk.org/wiki/x/4ICLAQ for more detailed
-   information.
-
- * The 'extra' field of all CEL events that use it now consists of a JSON blob
-   with key/value pairs which are defined in the Asterisk 12 CEL documentation.
-
- * BLINDTRANSFER events now report the transferee bridge unique
-   identifier, extension, and context in a JSON blob as the extra string
-   instead of the transferee channel name as the peer.
-
- * ATTENDEDTRANSFER events now report the peer as NULL and additional
-   information in the 'extra' string as a JSON blob. For transfers that occur
-   between two bridged channels, the 'extra' JSON blob contains the primary
-   bridge unique identifier, the secondary channel name, and the secondary
-   bridge unique identifier. For transfers that occur between a bridged channel
-   and a channel running an app, the 'extra' JSON blob contains the primary
-   bridge unique identifier, the secondary channel name, and the app name.
-
- * LOCAL_OPTIMIZE events have been added to convey local channel
-   optimizations with the record occurring for the semi-one channel and
-   the semi-two channel name in the peer field.
-
- * BRIDGE_START, BRIDGE_END, BRIDGE_UPDATE, 3WAY_START, 3WAY_END, CONF_ENTER,
-   CONF_EXIT, CONF_START, and CONF_END events have all been removed. These
-   events have been replaced by BRIDGE_ENTER/BRIDGE_EXIT. The BRIDGE_ENTER
-   and BRIDGE_EXIT events are raised when a channel enters/exits any bridge,
-   regardless of whether or not that bridge happens to contain multiple
-   parties.
-
-CLI
--------------------
- * When compiled with '--enable-dev-mode', the astobj2 library will now add
-   several CLI commands that allow for inspection of ao2 containers that
-   register themselves with astobj2. The CLI commands are 'astobj2 container
-   dump', 'astobj2 container stats', and 'astobj2 container check'.
-
- * Added specific CLI commands for bridge inspection. This includes 'bridge
-   show all', which lists all bridges in the system, and 'bridge show {id}',
-   which provides specific information about a bridge.
-
- * Added CLI command 'bridge destroy'. This will destroy the specified bridge,
-   ejecting the channels currently in the bridge. If the channels cannot
-   continue in the dialplan or application that put them in the bridge, they
-   will be hung up.
-
- * Added command 'bridge kick'. This will eject a single channel from a bridge.
-
- * Added commands to inspect and manipulate the registered bridge technologies.
-   This include 'bridge technology show', which lists the registered bridge
-   technologies, as well as 'bridge technology {suspend|unsuspend} {tech}',
-   which controls whether or not a registered bridge technology can be used
-   during smart bridge operations. If a technology is suspended, it will not
-   be used when a bridge technology is picked for channels; when unsuspended,
-   it can be used again.
-
- * The command 'config show help {module} {type} {option}' will show
-   configuration documentation for modules with XML configuration
-   documentation. When {module}, {type}, and {option} are omitted, a listing
-   of all modules with registered documentation is displayed. When {module}
-   is specified, a listing of all configuration types for that module is
-   displayed, along with their synopsis. When {module} and {type} are
-   specified, a listing of all configuration options for that type are
-   displayed along with their synopsis. When {module}, {type}, and {option}
-   are specified, detailed information for that configuration option is
-   displayed.
-
- * Added 'core show sounds' and 'core show sound' CLI commands. These display
-   a listing of all installed media sounds available on the system and
-   detailed information about a sound, respectively.
-
- * 'xmldoc dump' has been added. This CLI command will dump the XML
-   documentation DOM as a string to the specified file. The Asterisk core
-   will populate certain XML elements pulled from the source files with
-   additional run-time information; this command lets a user produce the
-   XML documentation with all information.
-
-Features
--------------------
- * Parking has been pulled from core and placed into a separate module called
-   res_parking. See Parking changes below for more details. Configuration for
-   parking should now be performed in res_parking.conf. Configuration for
-   parking in features.conf is now unsupported.
-
- * Core attended transfers now have several new options. While performing an
-   attended transfer, the transferer now has the following options:
-   - *1 - cancel the attended transfer (configurable via atxferabort)
-   - *2 - complete the attended transfer, dropping out of the call
-          (configurable via atxfercomplete)
-   - *3 - complete the attended transfer, but stay in the call. This will turn
-          the call into a multi-party bridge (configurable via atxferthreeway)
-   - *4 - swap to the other party. Once an attended transfer has begun, this
-          options may be used multiple times (configurable via atxferswap)
-
- * For DTMF blind and attended transfers, the channel variable TRANSFER_CONTEXT
-   must be on the channel initiating the transfer to have any effect.
-
- * The BRIDGE_FEATURES channel variable would previously only set features for
-   the calling party and would set this feature regardless of whether the
-   feature was in caps or in lowercase. Use of a caps feature for a letter
-   will now apply the feature to the calling party while use of a lowercase
-   letter will apply that feature to the called party.
-
- * Add support for automixmon to the BRIDGE_FEATURES channel variable.
-
- * The channel variable DYNAMIC_PEERNAME is redundant with BRIDGEPEER and is
-   removed.  The more useful DYNAMIC_WHO_ACTIVATED gives the channel name that
-   activated the dynamic feature.
-
- * The channel variables DYNAMIC_FEATURENAME and DYNAMIC_WHO_ACTIVATED are set
-   only on the channel executing the dynamic feature.  Executing a dynamic
-   feature on the bridge peer in a multi-party bridge will execute it on all
-   peers of the activating channel.
-
- * You can now have the settings for a channel updated using the FEATURE()
-   and FEATUREMAP() functions inherited to child channels by setting
-   FEATURE(inherit)=yes.
-
- * automixmon now supports additional channel variables from automon including:
-   TOUCH_MIXMONITOR_PREFIX, TOUCH_MIXMONITOR_MESSAGE_START,
-   and TOUCH_MIXMONITOR_MESSAGE_STOP
-
- * A new general features.conf option 'recordingfailsound' has been added which
-   allowssetting a failure sound for a user tries to invoke a recording feature
-   such as automon or automixmon and it fails.
-
- * It is no longer necessary (or possible) to define the ATXFER_NULL_TECH in
-   features.c for atxferdropcall=no to work properly. This option now just
-   works.
-
-Logging
--------------------
- * Added log rotation strategy 'none'. If set, no log rotation strategy will
-   be used. Given that this can cause the Asterisk log files to grow quickly,
-   this option should only be used if an external mechanism for log management
-   is preferred.
-
-Realtime
-------------------
- * Dynamic realtime tables for SIP Users can now include a 'path' field. This
-   will store the path information for that peer when it registers. Realtime
-   tables can also use the 'supportpath' field to enable Path header support.
-
- * LDAP realtime configurations for SIP Users now have the AstAccountPathSupport
-   objectIdentifier. This maps to the supportpath option in sip.conf.
-
-Sorcery
-------------------
- * Sorcery is a new data abstraction and object persistence API in Asterisk. It
-   provides modules a useful abstraction on top of the many storage mechanisms
-   in Asterisk, including the Asterisk Database, static configuration files,
-   static Realtime, and dynamic Realtime. It also provides a caching service.
-   Users can configure a hierarchy of data storage layers for specific modules
-   in sorcery.conf.
-
- * All future modules which utilize Sorcery for object persistence must have a
-   column named "id" within their schema when using the Sorcery realtime module.
-   This column must be able to contain a string of up to 128 characters in length.
-
-Security Events Framework
-------------------
- * Security Event timestamps now use ISO 8601 formatted date/time instead of
-   the "seconds-microseconds" format that it was using previously.
-
-Stasis Message Bus
-------------------
- * The Stasis message bus is a publish/subscribe message bus internal to
-   Asterisk. Many services in Asterisk are built on the Stasis message bus,
-   including AMI, ARI, CDRs, and CEL. Parameters controlling the operation of
-   Stasis can be configured in stasis.conf. Note that these parameters operate
-   at a very low level in Asterisk, and generally will not require changes.
-
-Channel Drivers
-------------------
- * When a channel driver is configured to enable jiterbuffers, they are now
-   applied unconditionally when a channel joins a bridge. If a jitterbuffer
-   is already set for that channel when it enters, such as by the JITTERBUFFER
-   function, then the existing jitterbuffer will be used and the one set by
-   the channel driver will not be applied.
-
-chan_agent
-------------------
- * chan_agent has been removed and replaced with AgentLogin and AgentRequest
-   dialplan applications provided by the app_agent_pool module. Agents are
-   connected with callers using the new AgentRequest dialplan application.
-   The Agents:<agent-id> device state is available to monitor the status of an
-   agent. See agents.conf.sample for valid configuration options.
-
- * The updatecdr option has been removed. Altering the names of channels on a
-   CDR is not supported - the name of the channel is the name of the channel,
-   and pretending otherwise helps no one. The AGENTUPDATECDR channel variable
-   has also been removed, for the same reason.
-
- * The endcall and enddtmf configuration options are removed.  Use the
-   dialplan function CHANNEL(dtmf-features) to set DTMF features on the agent
-   channel before calling AgentLogin.
-
-chan_bridge
-------------------
- * chan_bridge has been removed. Its functionality has been incorporated
-   directly into the ConfBridge application itself.
-
-chan_dahdi
-------------------
- * Added the CLI command 'pri destroy span'. This will destroy the D-channel
-   of the specified span and its B-channels. Note that this command should
-   only be used if you understand the risks it entails.
-
- * The CLI command 'dahdi destroy channel' is now 'dahdi destroy channels'.
-   A range of channels can be specified to be destroyed. Note that this command
-   should only be used if you understand the risks it entails.
-
- * Added the CLI command 'dahdi create channels'. A range of channels can be
-   specified to be created, or the keyword 'new' can be used to add channels
-   not yet created.
-
- * The script specified by the chan_dahdi.conf mwimonitornotify option now gets
-   the exact configured mailbox name.  For app_voicemail mailboxes this is
-   mailbox at context.
-
- * Added mwi_vm_boxes that also must be configured for ISDN MWI to be enabled.
-
-chan_iax2
-------------------
- * IPv6 support has been added.  We are now able to bind to and
-   communicate using IPv6 addresses.
-
-chan_local
-------------------
- * The /b option has been removed.
-
- * chan_local moved into the system core and is no longer a loadable module.
-
-chan_mobile
-------------------
- * Added general support for busy detection.
-
- * Added ECAM command support for Sony Ericsson phones.
-
-chan_pjsip
-------------------
- * A new SIP channel driver for Asterisk, chan_pjsip is built on the PJSIP
-   SIP stack. A collection of resource modules provides the bulk of the SIP
-   functionality. For more information on the new SIP channel driver, see
-   https://wiki.asterisk.org/wiki/x/JYGLAQ
-
-chan_sip
-------------------
- * Added support for RFC 3327 "Path" headers. This can be enabled in sip.conf
-   using the 'supportpath' setting, either on a global basis or on a peer basis.
-   This setting enables Asterisk to route outgoing out-of-dialog requests via a
-   set of proxies by using a pre-loaded route-set defined by the Path headers in
-   the REGISTER request. See Realtime updates for more configuration information.
-
- * The SIP_CODEC family of variables may now specify more than one codec. Each
-   codec must be separated by a comma. The first codec specified is the
-   preferred codec for the offer. This allows a dialplan writer to specify both
-   audio and video codecs, e.g., Set(SIP_CODEC=ulaw,h264)
-
- * The 'callevents' parameter has been removed. Hold AMI events are now raised
-   in the core, and can be filtered out using the 'eventfilter' parameter
-   in manager.conf.
-
- * Added 'ignore_requested_pref'. When enabled, this will use the preferred
-   codecs configured for a peer instead of the requested codec.
-
- * The option "register_retry_403" has been added to chan_sip to work around
-   servers that are known to erroneously send 403 in response to valid
-   REGISTER requests and allows Asterisk to continue attepmting to connect.
-
-chan_skinny
-------------------
- * Added the 'immeddialkey' parameter. If set, when the user presses the
-   configured key the already entered number will be immediately dialed. This
-   is useful when the dialplan allows for variable length pattern matching.
-   Valid options are '*' and '#'.
-
- * Added the 'callfwdtimeout' parameter. This configures the amount of time (in
-   milliseconds) before a call forward is considered to not be answered.
-
- * The 'serviceurl' parameter allows Service URLs to be attached to line
-   buttons.
-
-
-Functions
-------------------
-
-AGENT
-------------------
- * The password option has been disabled, as the AgentLogin application no
-   longer provides authentication.
-
-AUDIOHOOK_INHERIT
-------------------
- * Due to changes in the Asterisk core, this function is no longer needed to
-   preserve a MixMonitor on a channel during transfer operations and dialplan
-   execution. It is effectively obsolete.
-
-CDR (function)
-------------------
- * The 'amaflags' and 'accountcode' attributes for the CDR function are
-   deprecated. Use the CHANNEL function instead to access these attributes.
-
- * The 'l' option has been removed. When reading a CDR attribute, the most
-   recent record is always used. When writing a CDR attribute, all non-finalized
-   CDRs are updated.
-
- * The 'r' option has been removed, for the same reason as the 'l' option.
-
- * The 's' option has been removed, as LOCKED semantics no longer exist in the
-   CDR engine.
-
-CDR_PROP
-------------------
- * A new function CDR_PROP has been added. This function lets you set properties
-   on a channel's active CDRs. This function is write-only. Properties accept
-   boolean values to set/clear them on the channel's CDRs. Valid properties
-   include:
-   - 'party_a' - make this channel the preferred Party A in any CDR between two
-     channels. If two channels have this property set, the creation time of the
-     channel is used to determine who is Party A. Note that dialed channels are
-     never Party A in a CDR.
-   - 'disable' - disable CDRs on this channel. This is analogous to the NoCDR
-     application when set to True, and analogous to the 'e' option in ResetCDR
-     when set to False.
-
-CHANNEL
-------------------
- * Added the argument 'dtmf_features'. This sets the DTMF features that will be
-   enabled on a channel when it enters a bridge. Allowed values are 'T', 'K',
-   'H', 'W', and 'X', and are analogous to the parameters passed to the Dial
-   application.
-
- * Added the argument 'after_bridge_goto'. This can be set to a parseable Goto
-   string, i.e., [[context],extension],priority. If set on a channel, if a
-   channel leaves a bridge but is not hung up it will resume dialplan execution
-   at that location.
-
-JITTERBUFFER
-------------------
- * JITTERBUFFER now accepts an argument of 'disabled' which can be used
-   to remove jitterbuffers previously set on a channel with JITTERBUFFER.
-   The value of this setting is ignored when disabled is used for the argument.
-
-PJSIP_DIAL_CONTACTS
-------------------
- * A new function provided by chan_pjsip, this function can be used in
-   conjunction with the Dial application to construct a dial string that will
-   dial all contacts on an Address of Record associated with a chan_pjsip
-   endpoint.
-
-PJSIP_MEDIA_OFFER
-------------------
- * Provided by chan_pjsip, this function sets the codecs to be offerred on the
-   outbound channel prior to dialing.
-
-REDIRECTING
-------------------
- * Redirecting reasons can now be set to arbitrary strings. This means
-   that the REDIRECTING dialplan function can be used to set the redirecting
-   reason to any string. It also allows for custom strings to be read as the
-   redirecting reason from SIP Diversion headers.
-
-SPEECH_ENGINE
-------------------
- * The SPEECH_ENGINE function now supports read operations. When read from, it
-   will return the current value of the requested attribute.
-
-VMCOUNT:
-------------------
- * Mailboxes defined by app_voicemail MUST be referenced by the rest of the
-   system as mailbox at context.  The rest of the system cannot add @default
-   to mailbox identifiers for app_voicemail that do not specify a context
-   any longer.  It is a mailbox identifier format that should only be
-   interpreted by app_voicemail.
-
-
-Resources
-------------------
-
-res_agi (Asterisk Gateway Interface)
-------------------
- * The manager event AGIExec has been split into AGIExecStart and AGIExecEnd.
-
- * The manager event AsyncAGI has been split into AsyncAGIStart, AsyncAGIExec,
-   and AsyncAGIEnd.
-
- * The CONTROL STREAM FILE command now accepts an offsetms parameter. This
-   will start the playback of the audio at the position specified. It will
-   also return the final position of the file in 'endpos'.
-
- * The CONTROL STREAM FILE command will now populate the CPLAYBACKSTATUS
-   channel variable if the user stopped the file playback or if a remote
-   entity stopped the playback. If neither stopped the playback, it will
-   indicate the overall success/failure of the playback. If stopped early,
-   the final offset of the file will be set in the CPLAYBACKOFFSET channel
-   variable.
-
- * The SAY ALPHA command now accepts an additional parameter to control
-   whether it specifies the case of uppercase, lowercase, or all letters to
-   provide functionality similar to SayAlphaCase.
-
-res_ari (Asterisk RESTful Interface) (and others)
-------------------
- * The Asterisk RESTful Interface (ARI) provides a mechanism to expose and
-   control telephony primitives in Asterisk by remote client. This includes
-   channels, bridges, endpoints, media, and other fundamental concepts. Users
-   of ARI can develop their own communications applications, controlling
-   multiple channels using an HTTP RESTful interface and receiving JSON events
-   about the objects via a WebSocket connection. ARI can be configured in
-   Asterisk via ari.conf. For more information on ARI, see
-   https://wiki.asterisk.org/wiki/x/0YCLAQ
-
-res_parking
--------------------
- * Parking has been extracted from the Asterisk core as a loadable module,
-   res_parking. Configuration for parking is now provided by res_parking.conf.
-   Configuration through features.conf is no longer supported.
-
- * res_parking uses the configuration framework. If an invalid configuration is
-   supplied, res_parking will fail to load or fail to reload. Previously,
-   invalid configurations would generally be accepted, with certain errors
-   resulting in individually disabled parking lots.
-
- * Parked calls are now placed in bridges. While this is largely an
-   architectural change, it does have implications on how channels in a parking
-   lot are viewed. For example, commands that display channels in bridges will
-   now also display the channels in a parking lot.
-
- * The order of arguments for the new parking applications have been modified.
-   Timeout and return context/exten/priority are now implemented as options,
-   while the name of the parking lot is now the first parameter. See the
-   application documentation for Park, ParkedCall, and ParkAndAnnounce for more
-   in-depth information as well as syntax.
-
- * Extensions are by default no longer automatically created in the dialplan to
-   park calls or pickup parked calls. Generation of dialplan extensions can be
-   enabled using the 'parkext' configuration option.
-
- * ADSI functionality for parking is no longer supported. The 'adsipark'
-   configuration option has been removed as a result.
-
- * The PARKINGSLOT channel variable has been deprecated in favor of
-   PARKING_SPACE to match the naming scheme of the new system.
-
- * PARKING_SPACE and PARKEDLOT channel variables will now be set for a parked
-   channel even when the configuration option 'comebactoorigin' is enabled.
-
- * A new CLI command 'parking show' has been added. This allows a user to
-   inspect the parking lots that are currently in use.
-   'parking show <parkinglot>' will also show the parked calls in a specific
-   parking lot.
-
- * The CLI command 'parkedcalls' is now deprecated in favor of
-   'parking show <parkinglot>'.
-
- * The AMI command 'ParkedCalls' will now accept a 'ParkingLot' argument which
-   can be used to get a list of parked calls for a specific parking lot.
-
- * The AMI command 'Park' field 'Channel2' has been deprecated and replaced
-   with 'TimeoutChannel'. If both 'Channel2' and 'TimeoutChannel' are
-   specified, 'TimeoutChannel' will be used. The field 'TimeoutChannel' is no
-   longer a required argument.
-
- * The ParkAndAnnounce application is now provided through res_parking instead
-   of through the separate app_parkandannounce module.
-
- * ParkAndAnnounce will no longer go to the next position in dialplan on timeout
-   by default. Instead, it will follow the timeout rules of the parking lot. The
-   old behavior can be reproduced by using the 'c' option.
-
- * Dynamic parking lots will now fail to be created under the following
-   conditions:
-   - if the parking lot specified by PARKINGDYNAMIC does not exist
-   - if they require exclusive park and parkedcall extensions which overlap
-     with existing parking lots.
-
- * Dynamic parking lots will be cleared on reload for dynamic parking lots that
-   currently contain no calls. Dynamic parking lots containing parked calls
-   will persist through the reloads without alteration.
-
- * If 'parkext_exclusive' is set for a parking lot and that extension is
-   already in use when that parking lot tries to register it, this is now
-   considered a parking system configuration error. Configurations which do
-   this will be rejected.
-
- * Added channel variable PARKER_FLAT. This contains the name of the extension
-   that would be used if 'comebacktoorigin' is enabled. This can be useful when
-   comebacktoorigin is disabled, but the dialplan or an external control
-   mechanism wants to use the extension in the park-dial context that was
-   generated to re-dial the parker on timeout.
-
-res_pjsip (and many others)
-------------------
- * A large number of resource modules make up the SIP stack based on pjsip.
-   The chan_pjsip channel driver users these resource modules to provide
-   various SIP functionality in Asterisk. The majority of configuration for
-   these modules is performed in pjsip.conf. Other modules may use their
-   own configuration files.
-
- * Added 'set_var' option for an endpoint. For each variable specified that
-   variable gets set upon creation of a channel involving the endpoint.
-
-res_rtp_asterisk
-------------------
- * ICE/STUN/TURN support in res_rtp_asterisk has been made optional.  To enable
-   them, an Asterisk-specific version of PJSIP needs to be installed.
-   Tarballs are available from https://github.com/asterisk/pjproject/tags/.
-
-res_statsd/res_chan_stats
-------------------
- * A new resource module, res_statsd, has been added, which acts as a statsd
-   client. This module allows Asterisk to publish statistics to a statsd
-   server. In conjunction with res_chan_stats, it will publish statistics about
-   channels to the statsd server. It can be configured via res_statsd.conf.
-
-res_xmpp
-------------------
- * Device state for XMPP buddies is now available using the following format:
-   XMPP/<client name>/<buddy address>
-   If any resource is available the device state is considered to be not in use.
-   If no resources exist or all are unavailable the device state is considered
-   to be unavailable.
-
-
-Scripts
-------------------
-
-Realtime/Database Scripts
-------------------
- * Asterisk previously included example db schemas in the contrib/realtime/
-   directory of the source tree.  This has been replaced by a set of database
-   migrations using the Alembic framework.  This allows you to use alembic to
-   initialize the database for you.  It will also serve as a database migration
-   tool when upgrading Asterisk in the future.
-
-   See contrib/ast-db-manage/README.md for more details.
-
-sip_to_res_pjsip.py
--------------------
- * A new script has been added in the contrib/scripts/sip_to_res_pjsip folder.
-   This python script will convert an existing sip.conf file to a
-   pjsip.conf file, for use with the chan_pjsip channel driver. This script
-   is meant to be an aid in converting an existing chan_sip configuration to
-   a chan_pjsip configuration, but it is expected that configuration beyond
-   what the script provides will be needed.
-
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 10 to Asterisk 11 --------------------
 ------------------------------------------------------------------------------
@@ -2073,9 +101,6 @@ ConfBridge
    file will be played to the user, and only the user, upon joining the
    conference bridge.
 
- * Added record_file_append option that defaults to "yes", but if set to no
-   will create a new file between each start/stop recording.
-
 
 Dial
 -------------------
@@ -2162,9 +187,6 @@ Queue
 
  * Add queue monitoring hints.  exten => 8501,hint,Queue:markq.
 
- * App_queue will now play periodic announcements for the caller that
-   holds the first position in the queue while waiting for answer.
-
 SayUnixTime
 ------------------
  * Added 'j' option to SayUnixTime. SayUnixTime no longer auto jumps to extension
@@ -2379,9 +401,6 @@ chan_sip
 
  * Added support to use private party ID information with calls.
 
- * Adds an option discard_remote_hold_retrieval that when set stops telling
-   the peer to start music on hold.
-
 
 chan_skinny
 ------------------
@@ -2390,15 +409,6 @@ chan_skinny
 
 chan_unistim
 --------------------
- * Added option 'dtmf_duration' allowing playback time of DTMF tones to be set
-
- * Modified option 'date_format' to allow options to display date in 31Jan and Jan31
-   formats as options 0 and 1. The previous options 0 and 1 now map to options 2 and 3
-   as per the UNISTIM protocol.
-
- * Fixed issues with dialtone not matching indications.conf and mute stopping rx
-   as well as tx. Also fixed issue with call "Timer" displaying as French "Dur\E9e"
-
  * Added ability to use multiple lines for a single phone.  This allows multiple
    calls to occur on a single phone, using callwaiting and switching between calls.
 
@@ -2718,6 +728,13 @@ Scripts
    the source tree.  If the variable is not set, it defaults to the current
    behavior and uses the current working directory.
 
+Queue
+-------------------
+ * Add queue available hint.  exten => 8501,hint,Queue:markq_avail
+   Note: the suffix '_avail' after the queuename.
+   Reports 'InUse' for no logged in agents or no free agents.
+   Reports 'Idle' when an agent is free.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.8 to Asterisk 10 -------------------
 ------------------------------------------------------------------------------
diff --git a/CREDITS b/CREDITS
index 6560976..b93044d 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,321 +1,255 @@
 
 === DEVELOPMENT SUPPORT ===
+We'd like to thank the following companies for helping fund development of
+Asterisk:
 
- We'd like to thank the following companies for helping fund development of
- Asterisk.
+Pilosoft, Inc. - for supporting ADSI development in Asterisk
 
-	* Pilosoft, Inc. - for supporting ADSI development in Asterisk
+Asterlink, Inc. - for supporting broad Asterisk development
 
-	* Asterlink, Inc. - for supporting broad Asterisk development
+GFS - for supporting ALSA development
 
-	* GFS - for supporting ALSA development
+Telesthetic - for supporting SIP development
 
-	* Telesthetic - for supporting SIP development
+Christos Ricudis - for substantial code contributions
 
-	* Christos Ricudis - for substantial code contributions
+nic.at - ENUM support in Asterisk
 
-	* nic.at - ENUM support in Asterisk
+Paul Bagyenda, Digital Solutions - for initial Voicetronix driver development
 
-	* Paul Bagyenda, Digital Solutions - for initial Voicetronix driver
-		development.
+John Todd, TalkPlus, Inc.  and JR Richardson, Ntegrated Solutions. - for funding
+    the development of SIP Session Timers support.
 
-	* John Todd, TalkPlus, Inc.  and JR Richardson, Ntegrated Solutions. 
-		for funding the development of SIP Session Timers support.
-
-	* Omnitor AB, Gunnar Hellstr�m, for funding work with videocaps, 
-		T.140 RED, originate with video/text and many more 
-		contributions.
-
-	* ClearIT AB for work with meetme, res_mutestream, RTCP, manager and 
-		tonezones.
-
-	* NetNation Communications (www.netnation.com)
-		Kevin Lindsay <kevinl at netnation.com>
-		Persistent Dynamic Queue Members
-
-	* inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr)
-		Priorities in queues
-
-	* Voop AS, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - funding for
-		rewrite of SIP transfers
+Omnitor AB, Gunnar Hellstr�m, for funding work with videocaps, T.140 RED,
+originate with video/text and many more contributions.
 
+ClearIT AB for work with meetme, res_mutestream, RTCP, manager and tonezones
 
 === WISHLIST CONTRIBUTERS ===
-
- We'd like to thank the following for contributing to our wishlist
-
-	* Jeremy McNamara - SpeeX support
-
-	* Nick Seraphin - RDNIS support
-
-	* Gary - Phonejack ADSI (in progress)
-
-	* Wasim - Hangup detect
+Jeremy McNamara - SpeeX support
+Nick Seraphin - RDNIS support
+Gary - Phonejack ADSI (in progress)
+Wasim - Hangup detect
 
 === HARDWARE DONORS === 
+* Thanks to QuickNet Technologies for their donation of an Internet
+PhoneJack and Linejack card to the project.  (http://www.quicknet.net)
 
- We'd like to thank the following for granting access to hardware for testing.
-
-	* Thanks to QuickNet Technologies for their donation of an Internet
-		PhoneJack and Linejack card to the project.  
-		(http://www.quicknet.net)
+* Thanks to VoipSupply for their donation of Sipura ATAs to the project for
+T.38 testing. (http://www.voipsupply.com)
 
-	* Thanks to VoipSupply for their donation of Sipura ATAs to the project
-		for T.38 testing. (http://www.voipsupply.com)
-
-	* Thanks to Grandstream for their donation of ATAs to the project for
-		T.38 testing. (http://www.grandstream.com)
+* Thanks to Grandstream for their donation of ATAs to the project for
+T.38 testing. (http://www.grandstream.com)
 
 === MISCELLANEOUS PATCHES ===
+Jim Dixon - Zapata Telephony and app_rpt
+	http://www.zapatatelephony.org/app_rpt.html
 
- We'd like to thank the following for their patches
-
-	* Jim Dixon - Zapata Telephony and app_rpt
-		http://www.zapatatelephony.org/app_rpt.html
-
-	* Russell Bryant - Asterisk release manager and countless enhancements
-		and bug fixes. russell(AT)digium.com
+Russell Bryant - Asterisk release manager and countless enhancements and bug
+	fixes.
+	russell(AT)digium.com
 
-	* Anthony Minessale II - Countless big and small fixes, and relentless
-		forward	push. ChanSpy, ForkCDR, ControlPlayback, While/EndWhile,
-		DumpChan, Dictate, MacroIf, ExecIf, ExecIfTime, RetryDial, 
-		MixMonitor applications; many realtime concepts and 
-		implementation pieces, including res_config_odbc; format_slin; 
-		cdr_custom; several features in Dial including L(), G() and 
-		enhancements to M() and D(); several CDR enhancements including
-		CDR variables; attended transfer; one touch record; native MOH;
-		manager eventmask; command line '-t' flag to allow 
-		recording/voicemail on nfs shares; #exec command and multiline 
-		comments in config files; setvar in iax and sip configs.
-		anthmct(AT)yahoo.com http://www.asterlink.com
+Anthony Minessale II - Countless big and small fixes, and relentless forward
+	push. ChanSpy, ForkCDR, ControlPlayback, While/EndWhile, DumpChan, Dictate,
+	MacroIf, ExecIf, ExecIfTime, RetryDial, MixMonitor applications; many
+	realtime concepts and implementation pieces, including res_config_odbc;
+	format_slin; cdr_custom; several features in Dial including L(), G() and
+	enhancements to M() and D(); several CDR enhancements including CDR
+	variables; attended transfer; one touch record; native MOH; manager
+	eventmask; command line '-t' flag to allow recording/voicemail on nfs
+	shares; #exec command and multiline comments in config files; setvar in iax
+	and sip configs.
+	anthmct(AT)yahoo.com              http://www.asterlink.com
 
-	* James Golovich - Innumerable contributions, including SIP TCP and TLS
-		support. You can find him and asterisk-perl at 
-		http://asterisk.gnuinter.net
+James Golovich - Innumerable contributions, including SIP TCP and TLS support.
+	You can find him and asterisk-perl at http://asterisk.gnuinter.net
 
-	* Andre Bierwirth - Extension hints and status
+Andre Bierwirth - Extension hints and status
 
-	* Jean-Denis Girard - Various contributions from the South Pacific
-		Islands jd-girard(AT)sysnux.pf http://www.sysnux.pf
+Jean-Denis Girard - Various contributions from the South Pacific Islands
+	jd-girard(AT)esoft.pf             http://www.esoft.pf
 
-	* William Jordan / Vonage - MySQL enhancements to Voicemail
-		wjordan(AT)vonage.com
+William Jordan / Vonage - MySQL enhancements to Voicemail
+	wjordan(AT)vonage.com
 
-	* Jac Kersing - Various fixes
+Jac Kersing - Various fixes
 
-	* Steven Critchfield - Seek and Trunc functions for playback and 
-		recording critch(AT)basesys.com
+Steven Critchfield - Seek and Trunc functions for playback and recording
+	critch(AT)basesys.com
 
-	* Jefferson Noxon - app_lookupcidname, app_db, and various other
-		contributions
+Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
 
-	* Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
+Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
 
-	* Ross Finlayson - Dynamic RTP payload support
+Ross Finlayson - Dynamic RTP payload support
 
-	* Mahmut Fettahlioglu - Audio recording, music-on-hold changes, alaw
-		file format, and various fixes. Can be contacted at 
-		mahmut(AT)oa.com.au
+Mahmut Fettahlioglu - Audio recording, music-on-hold changes, alaw file
+	format, and various fixes. Can be contacted at mahmut(AT)oa.com.au
 
-	* James Dennis - Cisco SIP compatibility patches to work with SIP
-		service providers. Can be contacted at asterisk(AT)jdennis.net
+James Dennis - Cisco SIP compatibility patches to work with SIP service
+	providers. Can be contacted at asterisk(AT)jdennis.net
 
-	* Tilghman Lesher - ast_localtime(); ast_say_date_with_format(); 
-		GotoIfTime, SayUnixTime, HasNewVoicemail applications;
-		CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, some QUEUE* 
-		functions; func_odbc, cdr_adaptive_odbc, and other innumerable
-		bug fixes. tilghman(AT)digium.com 
-		http://asterisk.drunkcoder.com
+Tilghman Lesher - ast_localtime(); ast_say_date_with_format(); 
+	GotoIfTime, SayUnixTime, HasNewVoicemail applications;
+	CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, some QUEUE* functions;
+	func_odbc, cdr_adaptive_odbc, and other innumerable bug fixes.
+	tilghman(AT)digium.com            http://asterisk.drunkcoder.com/
 
-	* Jayson Vantuyl - Manager protocol changes, various other bugs.
-		jvantuyl(AT)computingedge.net
+Jayson Vantuyl - Manager protocol changes, various other bugs.
+	jvantuyl(AT)computingedge.net
 
-	* Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on
-		10.3, dialplan include verification, route lookup on OpenBSD,
-		SNMP agent support (res_snmp), various other bugs. 
-		tholo(AT)sigmasoft.com
+Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on 10.3,
+	dialplan include verification, route lookup on OpenBSD, SNMP agent
+	support (res_snmp), various other bugs. tholo(AT)sigmasoft.com
 
-	* Josh Roberson - chan_zap reload support, Advanced Voicemail Features,
-		& other misc. patches. josh(AT)asteriasgi.com 
-		http://www.asteriasgi.com
+Josh Roberson - chan_zap reload support, Advanced Voicemail Features, & other
+	misc. patches. - josh(AT)asteriasgi.com, http://www.asteriasgi.com
 
-	* William Waites - syslog support, SIP NAT traversal for SIP-UA. 
-		ww(AT)styx.org
+William Waites - syslog support, SIP NAT traversal for SIP-UA. ww(AT)styx.org
 
-	* Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
-		rich(AT)whiteoaklabs.com  http://whiteoaklabs.com
+Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
+	rich(AT)whiteoaklabs.com  http://whiteoaklabs.com
 
-	* Simon Lockhart - Porting to Solaris (based on work of Logan ???)	
-		simon(AT)slimey.org
+Simon Lockhart - Porting to Solaris (based on work of Logan ???)	
+	simon(AT)slimey.org
 
-	* Olle E. Johansson - SIP RFC compliance, documentation and testing,
-		testing, SIP outbound proxy support, Manager 1.1 update, SIP 
-		transfer support, SIP presence support, SIP call state updates
-		(dialog-info), QUEUE_EXISTS function, device state provider
-		architecture, multiparking (together with mvanbaak), meetme and
-		parking device states, MiniVM - the small voicemail system,
-		many documentation updates/corrections, and many bug fixes.
-		oej(AT)edvina.net, http://edvina.net
+Olle E. Johansson - SIP RFC compliance, documentation and testing, testing,
+	SIP outbound proxy support, Manager 1.1 update, SIP transfer support,
+	SIP presence support, SIP call state updates (dialog-info), 
+	QUEUE_EXISTS function, device state provider architecture,
+	multiparking (together with mvanbaak), meetme and parking device states,
+	MiniVM - the small voicemail system, many documentation
+	updates/corrections, and many bug fixes.
+	oej(AT)edvina.net, http://edvina.net
 
-	* Steve Kann - new jitter buffer for IAX2
-		stevek(AT)stevek.com
+Steve Kann - new jitter buffer for IAX2
+	stevek(AT)stevek.com
 
-	* Constantine Filin - major contributions to the Asterisk Realtime
-		Architecture
+Constantine Filin - major contributions to the Asterisk Realtime Architecture
 
-	* Steve Murphy - privacy support, $[ ] parser upgrade, AEL2 parser
-		upgrade. murf(AT)digium.com
+Steve Murphy - privacy support, $[ ] parser upgrade, AEL2 parser upgrade.
+	murf(AT)digium.com
 
-	* Claude Patry - bug fixes, feature enhancements, and bug marshalling
-		cpatry(AT)gmail.com
+Claude Patry - bug fixes, feature enhancements, and bug marshalling
+	cpatry(AT)gmail.com
 
-	* Miroslav Nachev, miro(AT)space-comm.com 
-		COSMOS Software Enterprises, Ltd.
-		Variable for No Answer Timeout for Attended Transfer
+Miroslav Nachev, miro(AT)space-comm.com COSMOS Software Enterprises, Ltd.
+	- for Variable for No Answer Timeout for Attended Transfer
 
-	* Slav Klenov & Vanheuverzwijn Joachim - development of the generic
-		jitterbuffer Securax Ltd. info(AT)securax.be
+Slav Klenov & Vanheuverzwijn Joachim - development of the generic jitterbuffer
+	Securax Ltd. info(AT)securax.be
 
-	* Roy Sigurd Karlsbakk - providing funding for generic jitterbuffer
-		development roy(AT)karlsbakk.net, Briiz Telecom AS
+Roy Sigurd Karlsbakk - providing funding for generic jitterbuffer development
+	roy(AT)karlsbakk.net, Briiz Telecom AS
 
-	* Voop AS, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - rewrite
-		of SIP transfers
+Voop AS, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - funding for rewrite
+	of SIP transfers
 
-	* Philippe Sultan - RADIUS CDR module, many fixes to res_jabber and 
-		gtalk/jingle channel drivers. INRIA, http://www.inria.fr/
+Philippe Sultan - RADIUS CDR module, many fixes to res_jabber and gtalk/jingle
+	channel drivers.
+	INRIA, http://www.inria.fr/
 
-	* John Martin, Aupix - Improved video support in the SIP channel
-		T.140 text support in RTP/SIP
+John Martin, Aupix - Improved video support in the SIP channel
+	T.140 text support in RTP/SIP
 
-	* Steve Underwood - Provided T.38 pass through support.
+Steve Underwood - Provided T.38 pass through support.
 
-	* George Konstantoulakis - Support for Greek in voicemail added by 
-		InAccess Networks (work funded by HOL, www.hol.gr) 
-		gkon(AT)inaccessnetworks.com
+George Konstantoulakis - Support for Greek in voicemail added by InAccess
+	Networks (work funded by HOL, www.hol.gr) gkon(AT)inaccessnetworks.com
 
-	* Daniel Nylander - Support for Swedish and Norwegian languages in
-		voicemail. http://www.danielnylander.se/
+Daniel Nylander - Support for Swedish and Norwegian languages in voicemail.
+	http://www.danielnylander.se/
 
-	* Stojan Sljivic - An option for maximum number of messsages per
-		mailbox in voicemail.  Also an issue with voicemail 
-		synchronization has been fixed. GDS Partners 
-		www.gdspartners.com stojan.sljivic(AT)gdspartners.com
+Stojan Sljivic - An option for maximum number of messsages per mailbox in
+	voicemail.  Also an issue with voicemail synchronization has been fixed.
+	GDS Partners www.gdspartners.com .  stojan.sljivic(AT)gdspartners.com
 
-	* Bartosz Supczinski - Support for Polish added by DIR (www.dir.pl)
-		Bartosz.Supczinski(AT)dir.pl
+Bartosz Supczinski - Support for Polish added by DIR (www.dir.pl)
+	Bartosz.Supczinski(AT)dir.pl
 
-	* James Rothenberger - Support for IMAP storage integration added by
-		OneBizTone LLC Work funded by University of Pennsylvania 
-		jar(AT)onebiztone.com
+James Rothenberger - Support for IMAP storage integration added by
+	OneBizTone LLC Work funded by University of Pennsylvania jar(AT)onebiztone.com
 
-	* Paul Cadach - Bringing chan_h323 up to date, bug fixes, and more!
+Paul Cadach - Bringing chan_h323 up to date, bug fixes, and more!
 
-	* Voop AS - Financial support for a lot of work with the SIP driver 
-		and the IAX trunk MTU patch
+Voop AS - Financial support for a lot of work with the SIP driver and the IAX
+	trunk MTU patch
 
-	* Cedric Hans - Development of chan_unistim cedric.hans(AT)mlkj.net
+Cedric Hans - Development of chan_unistim
+  cedric.hans(AT)mlkj.net
 
-	* Takao Takahashi & Mina Naguib - chan_unistim improvements for 
-		smaller devices
+Takao Takahashi & Mina Naguib - chan_unistim improvements for smaller devices
 
-	* Sergio Fadda - console_video: video support for chan_oss and 
-		chan_alsa
+Sergio Fadda - console_video: video support for chan_oss and chan_alsa
 
-	* Marta Carbone - console_video and the astobj2 framework
+Marta Carbone - console_video and the astobj2 framework
 
-	* Luigi Rizzo - astobj2, console_video, windows build, chan_oss cleanup,
-		and a bunch of infrastructure work (loader, new_cli, ...)
+Luigi Rizzo - astobj2, console_video, windows build, chan_oss cleanup,
+	and a bunch of infrastructure work (loader, new_cli, ...)
 
-	* Brett Bryant - digit option for musiconhold selection, ENUMQUERY and 
-		ENUMRESULT functions, feature group configuration for 
-		features.conf, per-file CLI debug and verbose settings, TCP and
-		TLS support for SIP, and various bug fixes.
-		brettbryant(AT)gmail.com
+Brett Bryant - digit option for musiconhold selection, ENUMQUERY and ENUMRESULT functions,
+	feature group configuration for features.conf, per-file CLI debug and verbose settings,
+	TCP and TLS support for SIP, and various bug fixes.
+	brettbryant(AT)gmail.com
 
-	* Sergey Tamkovich - Realtime support for MusicOnHold, store and destroy
-		realtime methods and implementations for odbc, sqlite, and pgsql
-		realtime drivers, attended transfer updates, multiple speeds for
-		ControlPlayback, and multiple bug fixes See 
-		http://voip-info.org/users/view/sergee serg(AT)voipsolutions.ru
+Sergey Tamkovich - Realtime support for MusicOnHold, store and destroy realtime methods and
+	implementations for odbc, sqlite, and pgsql realtime drivers, attended transfer updates,
+	multiple speeds for ControlPlayback, and multiple bug fixes
+	- See http://voip-info.org/users/view/sergee
+	serg(AT)voipsolutions.ru
 
-	* Klaus Darillon - the SIPremoveHeader function in chan_sip and SIP Path
-		Support.
+Klaus Darillon - the SIPremoveHeader function in chan_sip
 
-	* Moises Silva (moy) - for writing LibOpenR2, and providing support for
-		it in chan_dahdi moises.silva(AT)gmail.com
+Moises Silva (moy) - for writing LibOpenR2, and providing support for it in chan_dahdi
+     moises.silva(AT)gmail.com
 
-	* Eliel C. Sardanons - XML documentation implementation, and various
-		other contributions eliels(AT)gmail.com
+Eliel C. Sardanons - XML documentation implementation, and various other contributions
+     eliels(AT)gmail.com
 
-	* Sean Bright - Snom call pickup, newt interface for menuselect,
-		cdr_tds rewrite, countless other improvements, fixes, and good
-		ideas. sean(AT)malleable.com
+Sean Bright - Snom call pickup, newt interface for menuselect, cdr_tds rewrite,
+	countless other improvements, fixes, and good ideas.
+	sean(AT)malleable.com
 
-	* Jan Kal�b - Calendaring support for Exchange Server 2007+ via 
-		Exchange Web Services.
+Jan Kal�b - Calendaring support for Exchange Server 2007+ via Exchange Web Services.
 
-	* University of Oslo (uio.no), Norway - SIP Max-Forwards setting 
-		support (developed by oej)
+University of Oslo (uio.no), Norway - SIP Max-Forwards setting support (developed by oej)
 
-	* FCCN, Lissabon, Portugal - SIP show channels CLI command 
-		(developed by oej)
+FCCN, Lissabon, Portugal - SIP show channels CLI command (developed by oej)
 
-	* Viagenie, Canada - IPv6 support in socket layers and SIP 
-		implementation Developers: Marc Blanchet, Simon Perreault and 
-		Jean-Philippe Dionne
+Viagenie, Canada - IPv6 support in socket layers and SIP implementation
+	Developers: Marc Blanchet, Simon Perreault and Jean-Philippe Dionne
 
-	* ClearIT AB, Sweden - res_mutestream, queue_exists and various other
-		patches (developed by oej)
+ClearIT AB, Sweden - res_mutestream, queue_exists and various other patches (developed by oej)
 
-	* Despegar.com, Argentina - AstData API implementation, also sponsored
-		by Google as part of the gsoc/2009 program (developed by Eliel)
+Despegar.com, Argentina - AstData API implementation, also sponsored by Google as part of the
+	gsoc/2009 program (developed by Eliel)
 
-	* Philippe Lindheimer - DEV_STATE additions to CCSS
-
-	* Andrew "lathama" Latham <lathama at gmail dot com>
-		Doxygen, HTTP-Static, Phoneprov, make update
-
-	* George Joseph - PJSIP CLI commands, PJSIP_HEADER dialplan function
+Philippe Lindheimer - DEV_STATE additions to CCSS
 
 === OTHER CONTRIBUTIONS ===
-
- We'd like to thank the following for their listed contributions.
-
-	* John Todd - Monkey sounds and associated teletorture prompt
-
-	* Michael Jerris - bug marshaling
-	
-	* Leif Madsen, Jared Smith and Jim van Meggelen - the Asterisk book
-		available under a Creative Commons License at
-		http://www.asteriskdocs.org
-
-	* Brian M. Clapper - poll.c emulation 
-		This product includes software developed by 
-		Brian M. Clapper <bmc(AT)clapper.org>
+John Todd - Monkey sounds and associated teletorture prompt
+Michael Jerris - bug marshaling
+Leif Madsen, Jared Smith and Jim van Meggelen - the Asterisk book
+	available under a Creative Commons License at http://www.asteriskdocs.org
+Brian M. Clapper - poll.c emulation
+	This product includes software developed by Brian M. Clapper <bmc(AT)clapper.org>
 
 === HOLD MUSIC ===
-
- We'd like to thank the following for hold music
-
-	* Music provided by www.opsound.org
+Music provided by www.opsound.org
 
 === OTHER SOURCE CODE IN ASTERISK ===
+Asterisk uses libedit, the lightweight readline replacement from NetBSD.
+The cdr_radius module uses libradiusclient-ng, which is also from NetBSD.
+They are BSD-licensed and require the following statement:
 
- We'd like to thank the following for their code use
+      This product includes software developed by the NetBSD
+      Foundation, Inc. and its contributors.
 
-	* Asterisk uses libedit, the lightweight readline replacement from
-		NetBSD.
-	* The cdr_radius module uses libradiusclient-ng, which is also from
-		NetBSD.
-	* They are BSD-licensed and require the following statement:
-		This product includes software developed by the NetBSD
-		Foundation, Inc. and its contributors.
+Digium did not implement the codecs in Asterisk.  Here is the copyright on the
+GSM source:
 
-	* Digium did not implement the codecs in Asterisk.
-		Here is the copyright on the GSM source:
-		Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
-		Technische Universitaet Berlin
+Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+Technische Universitaet Berlin
 
 Any use of this software is permitted provided that this notice is not
 removed and that neither the authors nor the Technische Universitaet Berlin
diff --git a/ChangeLog b/ChangeLog
index 287d52e..bd0c6c5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,20909 +1,36401 @@
-2015-01-28  Asterisk Development Team <asteriskteam at digium.com>
+2015-10-09 22:23 +0000  Asterisk Development Team <asteriskteam at digium.com>
 
-	* Asterisk 13.1.1 Released.
+	* asterisk 11.20.0 Released.
 
-	* Mitigate possible HTTP injection attacks using CURL() function in
-	  Asterisk.
+2015-10-09 17:23 +0000 [940c530e34]  Kevin Harwell <kharwell at lunkwill>
 
-	  CVE-2014-8150 disclosed a vulnerability in libcURL where HTTP request
-	  injection can be performed given properly-crafted URLs.
+	* Release summaries: Add summaries for 11.20.0
 
-	  Since Asterisk makes use of libcURL, and it is possible that users of
-	  Asterisk may get cURL URLs from user input or remote sources, we have
-	  made a patch to Asterisk to prevent such HTTP injection attacks from
-	  originating from Asterisk.
+2015-10-09 17:21 +0000 [cf32d3dd19]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-	  ASTERISK-24676 #close
-	  Reported by: Matt Jordan, Olle Johansson
+	* Release summaries: Remove previous versions
 
-	  Review: https://reviewboard.asterisk.org/r/4364
+2015-10-09 17:21 +0000 [aa049e16e5]  Kevin Harwell <kharwell at lunkwill>
 
-	  AST-2015-002
+	* .version: Update for 11.20.0
 
-	* Fix file descriptor leak in RTP code.
+2015-10-09 17:21 +0000 [625fc1fc2c]  Kevin Harwell <kharwell at lunkwill>
 
-	  SIP requests that offered codecs incompatible with configured values
-	  could result in the allocation of RTP and RTCP ports that would not
-	  get reclaimed later.
+	* .lastclean: Update for 11.20.0
 
-	  ASTERISK-24666 #close
-	  Reported by Y Ateya
+2015-10-09 16:32 +0000 [5f8c0fb6c9]  Kevin Harwell <kharwell at lunkwill>
 
-	  Review: https://reviewboard.asterisk.org/r/4323
+	* ChangeLog: Updated for 11.20.0
 
-	  AST-2015-001
+2015-10-09 16:31 +0000 [5638b89f37]  Kevin Harwell <kharwell at lunkwill>
 
-2014-12-15  Asterisk Development Team <asteriskteam at digium.com>
+	* Release summaries: Add summaries for 11.20.0
 
-	* Asterisk 13.1.0 Released.
+2015-10-09 16:30 +0000 [5ab7cac6e2]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-2014-12-10  Asterisk Development Team <asteriskteam at digium.com>
+	* Release summaries: Remove previous versions
 
-	* Asterisk 13.1.0-rc2 Released.
+2015-10-09 16:30 +0000 [5130fa4854]  Kevin Harwell <kharwell at lunkwill>
 
-	* AST-2014-019: Fix crash when receiving a WebSocket packet with a
-	  payload length of zero.
+	* .version: Update for 11.20.0
 
-	  Frames with a payload length of 0 were incorrectly handled in
-	  res_http_websocket. Provided a frame with a payload had been
-	  received prior it was possible for a double free to occur. The
-	  realloc operation would succeed (thus freeing the payload) but be
-	  treated as an error. When the session was then torn down the payload
-	  would be freed again causing a crash. The read function now takes
-	  this into account.
+2015-10-09 16:30 +0000 [779180b1f4]  Kevin Harwell <kharwell at lunkwill>
 
-	  This change also fixes assumptions made by users of
-	  res_http_websocket. There is no guarantee that a frame received from
-	  it will be NULL terminated.
+	* .lastclean: Update for 11.20.0
 
-	  ASTERISK-24472 #close
-	  Reported by: Badalian Vyacheslav
+2015-10-09 16:28 +0000 [4980a406a1]  Kevin Harwell <kharwell at lunkwill>
 
-2014-12-08  Asterisk Development Team <asteriskteam at digium.com>
+	* ChangeLog: Updated for 11.20.0
 
-	* Asterisk 13.1.0-rc1 Released.
-
-2014-12-08 16:53 +0000 [r429091]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/playbacks.json, UPGRADE.txt,
-	  rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/resources.json, CHANGES, include/asterisk/manager.h,
-	  rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json,
-	  rest-api/api-docs/mailboxes.json, rest-api/api-docs/events.json,
-	  rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json: AMI/ARI: Update version to
-	  2.6.0/1.6.0 respectively for new features AMI/ARI are getting a
-	  few enhancements in the next release of Asterisk 13. Per semantic
-	  versioning, that warrants a bump in the minor version number, as
-	  it reflects a backwards compatible change. Hence, this commit.
-
-2014-12-08 16:41 +0000 [r429064-429089]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_session.c: Fix a crash that would occur when
-	  receiving a 491 response to a reinvite. The reviewboard
-	  description does a fine job of summarizing this, so here it is: A
-	  reporter discovered that Asterisk would crash when attempting to
-	  retransmit a reinvite that had previously received a 491
-	  response. The crash occurred because a pjsip_tx_data structure
-	  was being saved for reuse, but its reference count was not being
-	  increased. The result was that the pjsip_tx_data was being freed
-	  before we were actually done with it. When we attempted to re-use
-	  the structure when re-sending the reinvite, Asterisk would crash.
-	  The fix implemented here is not to try holding onto the
-	  pjsip_tx_data at all. Instead, when we reschedule sending the
-	  reinvite, we create a brand new pjsip_tx_data and send that
-	  instead. Because of this change, there is no need for an
-	  ast_sip_session_delayed_request structure to have a pjsip_tx_data
-	  on it any more. So any code referencing its use has been removed.
-	  When this initial fix was introduced, I encountered a second
-	  crash when processing a subsequent 200 OK on a rescheduled
-	  reinvite. The reason was that when rescheduling the reinvite, we
-	  gave the wrong location for a response callback. This has been
-	  fixed in this patch as well. ASTERISK-24556 #close Reported by
-	  Abhay Gupta Review: https://reviewboard.asterisk.org/r/4233
-
-	* main/stasis_channels.c, CHANGES, res/ari/ari_model_validators.c,
-	  main/manager_channels.c, main/channel.c,
-	  res/ari/ari_model_validators.h,
-	  include/asterisk/stasis_channels.h,
-	  rest-api/api-docs/events.json, res/stasis/app.c: Add new AMI and
-	  ARI events for connected line changes on a channel. The AMI event
-	  is called NewConnectedLine and the ARI event is called
-	  ChannelConnectedLine. ASTERISK-24554 #close Reported by Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/4231
-
-2014-12-08 15:43 +0000 [r429062]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/stasis/app.c, main/channel_internal_api.c,
-	  res/stasis/stasis_bridge.c, res/stasis/app.h,
-	  include/asterisk/channel.h, res/res_stasis.c, main/channel.c:
-	  Stasis: Fix StasisStart/End order and missing events This
-	  corrects several bugs that currently exist in the stasis
-	  application code. * After a masquerade, the resulting channels
-	  have channel topics that do not match their uniqueids **
-	  Masquerades now swap channel topics appropriately * StasisStart
-	  and StasisEnd messages are leaked to observer applications due to
-	  being published on channel topics ** StasisStart and StasisEnd
-	  publishing is now properly restricted to controlling apps via app
-	  topics * Race conditions exist where StasisStart and StasisEnd
-	  messages due to a masquerade may be received out of order due to
-	  being published on different topics ** These messages are now
-	  published directly on the app topic so this is now a non-issue *
-	  StasisEnds are sometimes missing when sent due to masquerades and
-	  bridge swaps into and out of Stasis() ** This was due to
-	  StasisEnd processing adjusting message-sent flags after Stasis()
-	  had already exited and Stasis() had been re-entered ** This was
-	  corrected by adjusting these flags prior to sending the message
-	  while the initial Stasis() application was still shutting down
-	  Review: https://reviewboard.asterisk.org/r/4213/ ASTERISK-24537
-	  #close Reported by: Matt DiMeo ........ Merged revisions 429061
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-06 18:16 +0000 [r429029-429033]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_monitor.c, /: res/res_monitor: Reset in/out sample counts
-	  on Monitor start When repeatedly starting/stopping a Monitor on a
-	  channel, the accumulated in/out sample counts are never reset to
-	  0. This can cause inadvertent jumps in the recordings, as the
-	  code in the channel core will determine incorrectly that a jump
-	  in the recorded file position should occur. Setting the sample
-	  counts to 0 simply reflects the initial state a Monitor should be
-	  in when it is started, as this is the initial count that would be
-	  on the channels at that time. ASTERISK-24573 #close Reported by:
-	  Nuno Borges patches: 24573.patch uploaded by Nuno Borges (License
-	  6116) ........ Merged revisions 429031 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 429032 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 16:28 +0000 [ad4e910368]  Kevin Harwell <kharwell at lunkwill>
 
-	* /, apps/app_meetme.c: apps/app_meetme: Apply default values on
-	  initial load with no config file When the app_meetme module is
-	  loaded without its configuration file, the module settings aren't
-	  initialized. In particular, this impacts the use of logging
-	  realtime members. This patch guarantees that we always set the
-	  default module settings on initial load. Review:
-	  https://reviewboard.asterisk.org/r/4242/ ASTERISK-24572 #close
-	  Reported by: Nuno Borges patches: 24572.patch uploaded by Nuno
-	  Borges (License 6116) ........ Merged revisions 429027 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 429028 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-05 17:06 +0000 [r429000]  George Joseph <george.joseph at fairview5.com>
-
-	* tests/test_sorcery.c, main/sorcery.c, include/asterisk/test.h, /,
-	  include/asterisk/sorcery.h: sorcery: Add additional observer
-	  capabilities. Add new global, instance and wizard observers.
-	  instance_created wizard_registered wizard_unregistered
-	  instance_destroying instance_loading instance_loaded
-	  wizard_mapped object_type_registered object_type_loading
-	  object_type_loaded wizard_loading wizard_loaded Tested-by: George
-	  Joseph Review: https://reviewboard.asterisk.org/r/4215/ ........
-	  Merged revisions 428999 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-04 17:13 +0000 [r428865-428973]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/test.c: main/test: Fix compilation issue on 32-bit
-	  systems On a 32-bit system, a type of intmax_t will result in a
-	  compilation warning when formatted as a 'long int'. Use the
-	  format specifier of %jd (which was what was used originally in
-	  manager.c) to format the JSON extracted integer on both
-	  32-/64-bit systems. ........ Merged revisions 428972 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /, main/test.c: main/test: Fix race condition
-	  between AMI topic and Test Suite topic This patch fixes a race
-	  condition between the raising of test AMI events (which drive
-	  many tests in the Asterisk Test Suite) and other AMI events.
-	  Prior to this patch, the Stasis messages published to the test
-	  topic were not forwarded to the AMI topic. Instead, the code in
-	  manager had a dedicated handler for test messages that was
-	  independent of the topics forwarded to the AMI topic. This
-	  results in no synchronization between the test messages and the
-	  rest of the Stasis messages published out over AMI. In some test
-	  with very tight timing constraints, this can result in out of
-	  order messages and spurious test failures. Properly forwarding
-	  the Test Suite topic to the AMI topic ensures that the messages
-	  are synchronized properly. This patch does that, and moves the
-	  message handling to the Stasis definition of the Test Suite
-	  message in test.c as well. Review:
-	  https://reviewboard.asterisk.org/r/4221/ ........ Merged
-	  revisions 428945 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* tests/test_cel.c, /: tests/test_cel: Add
-	  test_cel_attended_transfer_bridges_link to racey tests Despite
-	  failing less often, the ordering of the ATTENDEDTRANSFER event
-	  and the BRIDGE_EXIT event for the Alice and David channels is not
-	  defined. This makes the test still fail. ........ Merged
-	  revisions 428918 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* tests/test_cel.c, /: tests/test_cel: Fix CEL unit test failures
-	  caused by attended transfer changes When the publication of
-	  attended transfer messages were pushed to another thread, some
-	  subtle race conditions were introduced with the CEL unit tests.
-	  This patch fixes one of them, and pushes the other to
-	  ASTERISK-22367, which already exists to fix another bouncy CEL
-	  unit test. In particular, this patch fixes the
-	  test_cel_attended_transfer_bridges_link test, and defers the
-	  test_cel_attended_transfer_bridges_swap test to the
-	  aforementioned JIRA issue. ASTERISK-22367 ........ Merged
-	  revisions 428891 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_voicemail.c, /: apps/app_voicemail: Fix crash with IMAP
-	  when streams are opened simultaneously The UW IMAP library is
-	  instrinsically not thread-safe, and relies upon higher level
-	  applications to guarantee thread safety. For the most part, this
-	  is provided by the vms object, which provides locking for
-	  individual streams. Unfortunately, this is not sufficient for
-	  calls to mail_open which create the IMAP stream. mail_open can,
-	  on some systems, call into a UW IMAP specific function for
-	  determining the address of a system based on a hostname,
-	  ip_nametoaddr. In the ip6_unix implementation of this function,
-	  static variables are used to hold parsing buffers. This can cause
-	  a crash if multiple threads attempt to convert a hostname to an
-	  address at the same time. Locking on a single mail stream is not
-	  sufficient to prevent simultaneous access to these static
-	  variables. In the IMAP library, this function can be called from
-	  the mail_open and imap_status functions. As the imap_status
-	  function is not used by app_voicemail, locking on access to
-	  mail_open is sufficient to prevent any mangling of the buffers.
-	  Review: https://reviewboard.asterisk.org/r/4188/ ASTERISK-24516
-	  #close Reported by: David Duncan Ross Palmer Tested by: David
-	  Duncan Ross Palmer patches: ASTERISK-24516.diff uploaded by David
-	  Duncan Ross Palmer (License 6660) ........ Merged revisions
-	  428863 from http://svn.asterisk.org/svn/asterisk/branches/11
-	  ........ Merged revisions 428864 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* Release summaries: Add summaries for 11.20.0
 
-2014-12-02 21:53 +0000 [r428837]  George Joseph <george.joseph at fairview5.com>
+2015-10-09 16:26 +0000 [1b7a210bb8]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-	* CHANGES, /: CHANGES: Add item for new 'pjsip show identif(y|ies)
-	  commands Tested-by: George Joseph ........ Merged revisions
-	  428836 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* Release summaries: Remove previous versions
 
-2014-12-02 19:03 +0000 [r428789-428815]  Matthew Jordan <mjordan at digium.com>
+2015-10-09 16:26 +0000 [edd82562ba]  Kevin Harwell <kharwell at lunkwill>
 
-	* tests/test_stasis.c: tests/test_stasis: Resolve compilation
-	  issues from Asterisk 12 merge When merging the changes up stream
-	  in r428687, I missed the fact that the signature for
-	  stasis_message_type_create was changed. This patch fixes the
-	  compilation issues introduced by that merge.
+	* .version: Update for 11.20.0
 
-	* pbx/pbx_loopback.c, /: pbx/pbx_loopback: Speed up switches by
-	  avoiding unneeded lookups This patch makes a small rearrangement
-	  to only do dialplan lookups during loopback switches if the
-	  pattern matches. Prior to this patch, the dialplan lookups were
-	  always performed, even when the result would be discarded.
-	  Dialplan lookups can be very costly if remote switches - like
-	  DUNDi - are present. In those cases extension matching is sped up
-	  considerably, making the issue of lost digits more manageable. As
-	  collateral damage, 6 trailing spaces were killed. Review:
-	  https://reviewboard.asterisk.org/r/4211 ASTERISK-24577 #close
-	  Reported by: Birger Harzenetter patches: ast-loopback.patch
-	  uploaded by Birger Harzenetter (License 5870) ........ Merged
-	  revisions 428787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428788 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-02 12:20 +0000 [r428761]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_refer.c, /: res_pjsip_refer: Fix issue where native
-	  bridge may not occur upon completion of a transfer. There are two
-	  methods within res_pjsip_refer for keeping track of the state of
-	  a transfer. The first is a framehook which looks at frames
-	  passing by to determine the state. The second subscribes to know
-	  when the channel joins a bridge. In the case when the channel
-	  joins the bridge the framehook is *NOT* removed and this prevents
-	  the native RTP bridging technology from getting used. This change
-	  gets the channel and if it still exists remove the framehook.
-	  Review: https://reviewboard.asterisk.org/r/4218/ ........ Merged
-	  revisions 428760 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-02 00:38 +0000 [r428731-428734]  George Joseph <george.joseph at fairview5.com>
-
-	* /, include/asterisk/config.h, main/config.c: config: Create
-	  ast_variable_find_in_list() Add const char
-	  *ast_variable_find_in_list(const struct ast_variable *list, const
-	  char *variable); ast_variable_find() requires a config category
-	  to search whereas ast_variable_find_in_list() just needs the root
-	  list element which is useful if you don't have a category.
-	  Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4217/ ........ Merged
-	  revisions 428733 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c,
-	  res/res_pjsip/pjsip_cli.c: res_pjsip_endpoint_identifier_ip: Add
-	  'show identify(ies)' cli commands While troubleshooting other
-	  things I realized there were no pjsip cli commands for identify.
-	  This patch adds them. It also also fixes a reference leak when a
-	  'show endpoint' displayed identifies and properly sets the return
-	  code if load_module can't allocate a cli formatter structure.
-	  Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4212/ ........ Merged
-	  revisions 428725 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-01 17:57 +0000 [r428687]  Matthew Jordan <mjordan at digium.com>
-
-	* channels/chan_skinny.c, res/res_pjsip_mwi.c, tests/test_stasis.c,
-	  res/res_pjsip_pubsub.c, res/res_pjsip_refer.c,
-	  channels/chan_mgcp.c, main/stasis_cache.c, channels/chan_sip.c,
-	  include/asterisk/stasis_internal.h, /, include/asterisk/stasis.h,
-	  UPGRADE.txt, configs/samples/stasis.conf.sample,
-	  res/parking/parking_applications.c, res/res_xmpp.c,
-	  channels/chan_iax2.c, apps/app_queue.c,
-	  res/res_stasis_device_state.c, channels/sig_pri.c,
-	  include/asterisk/stasis_message_router.h, main/endpoints.c,
-	  res/parking/parking_bridge_features.c, main/stasis.c,
-	  channels/chan_dahdi.c, main/stasis_message_router.c: main/stasis:
-	  Allow subscriptions to use a threadpool for message delivery
-	  Prior to this patch, all Stasis subscriptions would receive a
-	  dedicated thread for servicing published messages. In contrast,
-	  prior to r400178 (see review
-	  https://reviewboard.asterisk.org/r/2881/), the subscriptions
-	  shared a thread pool. It was discovered during some initial work
-	  on Stasis that, for a low subscription count with high message
-	  throughput, the threadpool was not as performant as simply having
-	  a dedicated thread per subscriber. For situations where a
-	  subscriber receives a substantial number of messages and is
-	  always present, the model of having a dedicated thread per
-	  subscriber makes sense. While we still have plenty of
-	  subscriptions that would follow this model, e.g., AMI, CDRs, CEL,
-	  etc., there are plenty that also fall into the following two
-	  categories: * Large number of subscriptions, specifically those
-	  tied to endpoints/peers. * Low number of messages. Some
-	  subscriptions exist specifically to coordinate a single message -
-	  the subscription is created, a message is published, the delivery
-	  is synchronized, and the subscription is destroyed. In both of
-	  the latter two cases, creating a dedicated thread is wasteful
-	  (and in the case of a large number of peers/endpoints, harmful).
-	  In those cases, having shared delivery threads is far more
-	  performant. This patch adds the ability of a subscriber to Stasis
-	  to choose whether or not their messages are dispatched on a
-	  dedicated thread or on a threadpool. The threadpool is
-	  configurable through stasis.conf. Review:
-	  https://reviewboard.asterisk.org/r/4193 ASTERISK-24533 #close
-	  Reported by: xrobau Tested by: xrobau ........ Merged revisions
-	  428681 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-12-01 13:41 +0000 [r428632-428655]  Joshua Colp <jcolp at digium.com>
-
-	* /, apps/app_record.c: app_record: Fix bug where using the 'k'
-	  option and hanging up would trim 1/4 of a second of the
-	  recording. The Record dialplan function trims 1/4 of a second
-	  from the end of recordings in case they are terminated because of
-	  DTMF. When hanging up, however, you don't want this to happen.
-	  This change makes it so on hangup this does not occur.
-	  ASTERISK-24530 #close Reported by: Ben Smithurst patches:
-	  app_record_v2.diff submitted by Ben Smithurst (license 6529)
-	  Review: https://reviewboard.asterisk.org/r/4201/ ........ Merged
-	  revisions 428653 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428654 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/channel.c: channel: Extend size of buffer for codecs in
-	  "core show channeltype" CLI command. The static buffer for codecs
-	  when invoking the "core show channeltype" CLI command did not
-	  have enough room for all codecs. This has been extended so it
-	  does. ASTERISK-24542 #close Reported by: snuffy patches:
-	  channeltype-tech.diff submitted by snuffy (license 5024) Review:
-	  https://reviewboard.asterisk.org/r/4204/
-
-2014-11-24 20:37 +0000 [r428602-428604]  Richard Mudgett <rmudgett at digium.com>
-
-	* tests/test_channel_feature_hooks.c: test_channel_feature_hooks.c:
-	  Fix unit test for DTMF hooks. Fix the failing
-	  /channels/features/test_features_channel_dtmf unit test. DTMF
-	  emulation does not work without a stream of packets to prod the
-	  emulation code. Review: https://reviewboard.asterisk.org/r/4199/
-
-	* /, main/bridge.c, main/bridge_channel.c: DTMF hooks: Leaving
-	  channels need to push any collected digits into the bridge. Any
-	  partially collected DTMF digits for a DTMF hook need to be pushed
-	  into the bridge when a channel leaves the bridging system as if
-	  there were a timeout. Review:
-	  https://reviewboard.asterisk.org/r/4199/ ........ Merged
-	  revisions 428601 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-21 19:09 +0000 [r428572]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/manager.c, /: manager: Fix could not extend string messages.
-	  When shutting down Asterisk that has an active AMI connection,
-	  you get several "failed to extend from %d to %d" messages because
-	  use of the EVENT_FLAG_SHUTDOWN attempts to add all AMI permission
-	  strings to the event. * Created MAX_AUTH_PERM_STRING to use when
-	  creating stack based struct ast_str variables used with the
-	  authority_to_str() and user_authority_to_str() functions instead
-	  of a variety of magic numbers that could be too small. * Added a
-	  special check for EVENT_FLAG_SHUTDOWN to authority_to_str() so it
-	  will not attempt to add all permission level strings. Review:
-	  https://reviewboard.asterisk.org/r/4200/ ........ Merged
-	  revisions 428570 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428571 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-21 17:45 +0000 [r428544]  George Joseph <george.joseph at fairview5.com>
-
-	* main/sorcery.c, /, res/res_pjsip_phoneprov_provider.c,
-	  tests/test_sorcery.c: sorcery: Make is_object_field_registered
-	  handle field names that are regexes. As a result of
-	  https://reviewboard.asterisk.org/r/3305, res_sorcery_realtime was
-	  tossing database fields that didn't have an exact match to a
-	  sorcery registered field. This broke the ability to use regexes
-	  as field names which manifested itself as a failure of
-	  res_pjsip_phoneprov_provider which uses this capability. It also
-	  broke handling of fields that start with '@' in realtime but I
-	  don't think anyone noticed. This patch does the following... *
-	  Modifies ast_sorcery_fields_register to pre-compile the name
-	  regex. * Modifies ast_sorcery_is_object_field_registered to test
-	  the regex if it exists instead of doing an exact strcmp. *
-	  Modifies res_pjsip_phoneprov_provider with a few tweaks to get it
-	  to work with realtime. Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4185/ ........ Merged
-	  revisions 428543 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-21 02:16 +0000 [r428505]  Matthew Jordan <mjordan at digium.com>
-
-	* main/bridge_basic.c: main/bridge_basic: Fix features regressions
-	  introduced by r428165 In r428165, two bugs were introduced: *
-	  Prior to entering the features retry loop, the buffer that holds
-	  the collected digits is wiped. However, this inadvertently wipes
-	  out the first collected digit on the first pass through, which is
-	  obtained in ast_stream_and_wait. This caused all of the features
-	  tests to fail. * If ast_app_dtget returns a hangup (-1), the loop
-	  would retry incorrectly. If we detect a hangup, we have to stop
-	  trying the feature. This patch fixes both issues. Review:
-	  https://reviewboard.asterisk.org/r/4196/
-
-2014-11-20 16:36 +0000 [r428425]  Mark Michelson <mmichelson at digium.com>
-
-	* main/acl.c, /: Fix error with mixed address family ACLs. Prior to
-	  this commit, the address family of the first item in an ACL was
-	  used to compare all incoming traffic. This could lead to traffic
-	  of other IP address families bypassing ACLs. ASTERISK-24469
-	  #close Reported by Matt Jordan Patches: ASTERISK-24469-11.diff
-	  uploaded by Matt Jordan (License #6283) AST-2014-012 ........
-	  Merged revisions 428402 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 428417 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428422 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 16:26 +0000 [495a482281]  Kevin Harwell <kharwell at lunkwill>
 
-2014-11-20 16:34 +0000 [r428413]  Kevin Harwell <kharwell at digium.com>
+	* .lastclean: Update for 11.20.0
 
-	* funcs/func_db.c, /: AST-2014-018 - func_db: DB Dialplan function
-	  permission escalation via AMI. The DB dialplan function when
-	  executed from an external protocol (for instance AMI), could
-	  result in a privilege escalation. Asterisk now inhibits the DB
-	  function from being executed from an external interface if the
-	  live_dangerously option is set to no. ASTERISK-24534 Reported by:
-	  Gareth Palmer patches: submitted by Gareth Palmer (license 5169)
-	  ........ Merged revisions 428331 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 428363 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428409 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-20 16:13 +0000 [r428343]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_acl.c, /: PJSIP ACLs: Fix ACLs not loading on
-	  startup and apply/acl issues on contact The biggest problem this
-	  patch fixes is that ACLs weren't previously being loaded when the
-	  res_pjsip_acl module was loaded. Yikes. In addition, the ACL
-	  options contact_permit and contact_acl were effectively
-	  interpreted as contact_deny and this patch fixes that as well.
-	  AST-1418 #close Reported by: Thomas Thompson Review:
-	  https://reviewboard.asterisk.org/r/4120/ ASTERISK-24531 #close
-	  Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/4171/ ........ Merged
-	  revisions 428333 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:56 +0000 [74b5c009bc]  Kevin Harwell <kharwell at lunkwill>
 
-2014-11-20 15:50 +0000 [r428339]  Kevin Harwell <kharwell at digium.com>
+	* ChangeLog: Updated for 11.20.0
 
-	* apps/app_confbridge.c, /: AST-2014-017 - app_confbridge:
-	  permission escalation/ class authorization. Confbridge dialplan
-	  function permission escalation via AMI and inappropriate class
-	  authorization on the ConfbridgeStartRecord action. The CONFBRIDGE
-	  dialplan function when executed from an external protocol (for
-	  instance AMI), could result in a privilege escalation. Also, the
-	  AMI action “ConfbridgeStartRecord” could also be used to execute
-	  arbitrary system commands without first checking for system
-	  access. Asterisk now inhibits the CONFBRIDGE function from being
-	  executed from an external interface if the live_dangerously
-	  option is set to no. Also, the “ConfbridgeStartRecord” AMI action
-	  is now only allowed to execute under a user with system level
-	  access. ASTERISK-24490 Reported by: Gareth Palmer ........ Merged
-	  revisions 428332 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428334 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-20 14:55 +0000 [r428302-428305]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_refer.c, /: AST-2014-016: Fix crash when receiving
-	  an in-dialog INVITE with Replaces in res_pjsip_refer. The
-	  implementation of INVITE with Replaces in res_pjsip_refer did not
-	  expect them to occur in-dialog. As a result it would incorrectly
-	  attempt to hang up a channel it thought was under its control. In
-	  reality the channel would be under the control of another thread.
-	  When the other thread accessed the channel it would be accessing
-	  freed memory and could crash. This change makes res_pjsip_refer
-	  not act on an in-dialog INVITE with Replaces. ASTERISK-24528
-	  #close Reported by: Joshua Colp ........ Merged revisions 428304
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_pjsip.c, /: AST-2014-015: Fix race condition in
-	  chan_pjsip when sending responses after a CANCEL has been
-	  received. Due to the serialized architecture of chan_pjsip there
-	  exists a race condition where a CANCEL may be received and
-	  processed before responses (such as 180 Ringing, 183 Session
-	  Progress, and 200 OK) are sent. Since the session is in an
-	  unexpected state PJSIP will assert when this is attempted. This
-	  change makes it so that these responses are not sent on
-	  disconnected sessions. ASTERISK-24471 #close Reported by: yaron
-	  nahum ........ Merged revisions 428301 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-19 19:31 +0000 [r428273]  Corey Farrell <git at cfware.com>
-
-	* include/asterisk/stringfields.h, /: stringfields: Fix bug in
-	  ast_string_fields_copy. ast_string_fields_copy relies on the fact
-	  that __ast_string_field_release_active never previously zeroed
-	  pool->used, so keeping the existing pointer was "ok". Now that
-	  existing pools can be reset to 'empty', it is important to set
-	  each field to __ast_string_field_empty after releasing the
-	  memory. ASTERISK-24535 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4186/ ........ Merged
-	  revisions 428272 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-19 17:13 +0000 [r428246]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_calendar.c, main/manager.c, /, channels/chan_sip.c,
-	  channels/sip/security_events.c: ast_str: Fix improper member
-	  access to struct ast_str members. Accessing members of struct
-	  ast_str outside of the string manipulation API routines is
-	  invalid since struct ast_str is supposed to be treated as opaque.
-	  Review: https://reviewboard.asterisk.org/r/4194/ ........ Merged
-	  revisions 428244 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428245 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-19 12:40 +0000 [r428196-428222]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, include/asterisk/res_pjsip.h,
-	  include/asterisk/res_pjsip_session.h, res/res_pjsip_sdp_rtp.c,
-	  res/res_pjsip/pjsip_configuration.c,
-	  configs/samples/pjsip.conf.sample,
-	  contrib/ast-db-manage/config/versions/eb88a14f2a_add_media_encryption_optimistic_to_pjsip.py
-	  (added), CHANGES, res/res_pjsip.c: res_pjsip_sdp_rtp: Add support
-	  for optimistic SRTP. Optimistic SRTP is the ability to enable
-	  SRTP but not have it be a fatal requirement. If SRTP can be used
-	  it will be, if not it won't be. This gives you a better chance of
-	  using it without having your sessions fail when it can't be.
-	  Encrypt all the things! Review:
-	  https://reviewboard.asterisk.org/r/3992/
-
-	* res/res_pjsip_refer.c, /: res_pjsip_refer: Ensure Refer-To is
-	  NULL terminated and parse it as a URI. There is no guarantee that
-	  when we get a Refer-To that it will be NULL terminated. As the
-	  URI parsing function requires it to be we now NULL terminate it.
-	  Additionally parsing the Refer-To as a 'To' header is needless
-	  and it can simply be done as a URI. This also fixes a problem
-	  where certain Refer-To headers would not be parsed as a 'To'
-	  header causing the REFER to fail. ASTERISK-24508 #close Reported
-	  by: Beppo Mazzucato Review:
-	  https://reviewboard.asterisk.org/r/4187/ ........ Merged
-	  revisions 428195 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-18 18:54 +0000 [r428169]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/parking/parking_tests.c: parking_tests.c: Add missing
-	  newline on a unit test message. ........ Merged revisions 428168
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-17 16:51 +0000 [r428145]  Mark Michelson <mmichelson at digium.com>
-
-	* CHANGES, main/features_config.c,
-	  configs/samples/features.conf.sample,
-	  include/asterisk/features_config.h, main/bridge_basic.c: Allow
-	  for transferer to retry when dialing an invalid extension. This
-	  allows for a configurable number of attempts for a transferer to
-	  dial an extension to transfer the call to. For Asterisk 13, the
-	  default values are such that upgrading between versions will not
-	  cause a behaivour change. For trunk, though, the defaults will be
-	  changed to be more user-friendly. Review:
-	  https://reviewboard.asterisk.org/r/4167
-
-2014-11-17 16:00 +0000 [r428119]  Corey Farrell <git at cfware.com>
-
-	* /, channels/chan_sip.c: chan_sip: Fix theoretical leak of
-	  p->refer. If transmit_refer is called when p->refer is already
-	  allocated, it leaks the previous allocation. Updated code to
-	  always free previous allocation during a new allocation. Also
-	  instead of checking if we have a previous allocation, always
-	  create a clean record. ASTERISK-15242 #close Reported by: David
-	  Woolley Review: https://reviewboard.asterisk.org/r/4160/ ........
-	  Merged revisions 428117 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428118 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-17 15:27 +0000 [r428079-428115]  Matthew Jordan <mjordan at digium.com>
-
-	* /, apps/confbridge/conf_state_multi_marked.c:
-	  apps/app_confbridge: Ensure 'normal' users hear message when last
-	  marked leaves When r428077 was made for ASTERISK-24522, it failed
-	  to take into account users who are neither wait_marked nor
-	  end_marked. These users are *also* supposed to hear the 'leader
-	  has left the conference' message. Granted, this behaviour is a
-	  bit odd; however, that is how it used to work... and behaviour
-	  changes are not good. This patch ensures that if there are any
-	  'normal' users present when the last marked user leaves the
-	  conference, the message will still be played to them. Note that
-	  this regression was caught by the Asterisk Test Suite's
-	  confbridge_nominal test, which has a quirky combination of users.
-	  ........ Merged revisions 428113 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428114 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, apps/confbridge/conf_state_multi_marked.c: app_confbridge:
-	  Don't play leader leaving prompt if no one will hear it Consider
-	  the following: - A marked user in a conference - One or more
-	  end_marked only users in the conference When the marked users
-	  leaves, we will be in the conf_state_multi_marked state. This
-	  currently will traverse the users, kicking out any who have the
-	  end_marked flags. When they are kicked, a full ast_bridge_remove
-	  is immediately called on the channels. At this time, we also
-	  unilaterally set the need_prompt flag. When the need_prompt flag
-	  is set, we then playback a sound to the bridge informing everyone
-	  that the leader has left; however, no one is left in the bridge.
-	  This causes some odd behaviour for the end_marked users - they
-	  are stuck waiting for the bridge to be unlocked. This results in
-	  them waiting for 5 or 6 seconds of dead air before hearing that
-	  they've been kicked. Unfortunately, we do have to keep the bridge
-	  locked while we're playing back the 'leader-has-left' prompt. If
-	  there are any wait_marked users in the conference, this behaviour
-	  can't be easily changed - but we do make the case of the
-	  end_marked users better with this patch. Review:
-	  https://reviewboard.asterisk.org/r/4184/ ASTERISK-24522 #close
-	  Reported by: Matt Jordan ........ Merged revisions 428077 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 428078 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-16 21:12 +0000 [r427979-428052]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_pjsip.c, /: chan_pjsip: Remove AOR check when
-	  dialing and one is specified. The AOR value may contain the name
-	  of an AOR or a full SIP URI. Checking if the AOR exists can't be
-	  done as a result of this. ........ Merged revisions 428051 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_pjsip.c: chan_pjsip: Add additional log message
-	  when an AOR is specified when dialing and it does not exist.
-	  ASTERISK-24499 #close Reported by: Rusty Newton ........ Merged
-	  revisions 428007 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_motif.c, channels/chan_pjsip.c, /: chan_motif /
-	  chan_pjsip: Fix incorrect "No such module" messages when
-	  reloading. For chan_motif the direct return value of the
-	  underlying config options framework was passed back. This can
-	  relay various states which the module loader would not interpet
-	  as success. It has been changed so only on errors will it report
-	  back an error. For chan_pjsip the code implemented a dummy reload
-	  function which always returned an error. This has been removed as
-	  all configuration is held within res_pjsip instead.
-	  ASTERISK-23651 #close Reported by: Rusty Newton ........ Merged
-	  revisions 427981 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_configuration.c: res_pjsip: Enforce
-	  requirements for session timer minimum expiration period and
-	  normal expiration period. This change enforces the requirements
-	  in PJSIP for session timer configuration. The minimum expiration
-	  period must be 90 seconds or higher and the normal expiration
-	  period can not be lower than the minimum expiration period. If
-	  either of these were done the code would assert at session setup
-	  time. ASTERISK-24336 #close Reported by: Leon Rowland ........
-	  Merged revisions 427978 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-15 16:56 +0000 [r427927-427954]  Matthew Jordan <mjordan at digium.com>
-
-	* cel/cel_odbc.c, /: cel/cel_odbc: Provide microsecond precision in
-	  'eventtime' column when possible This patch adds microsecond
-	  precision when inserting a CEL record into a table with an
-	  "eventtime" column of type timestamp, instead of second
-	  precision. The documentation (configs/cel_odbc.conf.sample) was
-	  already saying that the eventtime column included microseconds
-	  precision, but that was not the case. Also, without this patch,
-	  if you had a table with an "eventtime" column of type varchar,
-	  you had millisecond precision. With this patch, you also get
-	  microsecond precision in this case. Review:
-	  https://reviewboard.asterisk.org/r/3980 ASTERISK-24283 #close
-	  Reported by: Etienne Lessard patches:
-	  cel_odbc_time_precision.patch uploaded by Etienne Lessard
-	  (License 6394) ........ Merged revisions 427952 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427953 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* tests/test_cel.c: tests/test_cel: Unlock bridge on off nominal
-	  paths If the test fails due to memory allocation errors, we may
-	  as well attempt to unlock the bridge on the way out.
-
-2014-11-14 17:45 +0000 [r427902]  Jonathan Rose <jrose at digium.com>
-
-	* configs/samples/cdr.conf.sample, main/cdr.c, /: Documentation:
-	  Revise explanation of cdr.conf option 'Unanswered' ASTERISK-24279
-	  #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/4109/ ........ Merged
-	  revisions 427901 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-14 15:51 +0000 [r427876]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, main/stun.c: stun: correct attribute string padding to match
-	  rfc When sending the USERNAME attribute in an RTP STUN response,
-	  the implementation in append_attr_string passed the actual
-	  length, instead of padding it up to a multiple of four bytes as
-	  required by the RFC 3489. This change adds separate variables for
-	  the string and padded attributed lengths, and performs padding
-	  correctly. Reported by: Thomas Arimont Review:
-	  https://reviewboard.asterisk.org/r/4139/ ........ Merged
-	  revisions 427874 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427875 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-14 15:24 +0000 [r427870]  Mark Michelson <mmichelson at digium.com>
-
-	* main/bridge.c, main/bridge_basic.c,
-	  include/asterisk/stasis_bridges.h, tests/test_cel.c,
-	  apps/app_queue.c, main/cel.c, main/stasis_bridges.c, /,
-	  res/stasis/app.c: Fix race condition that could result in ARI
-	  transfer messages not being sent. From reviewboard: "During blind
-	  transfer testing, it was noticed that tests were failing
-	  occasionally because the ARI blind transfer event was not being
-	  sent. After investigating, I detected a race condition in the
-	  blind transfer code. When blind transferring a single channel,
-	  the actual transfer operation (i.e. removing the transferee from
-	  the bridge and directing them to the proper dialplan location) is
-	  queued onto the transferee bridge channel. After queuing the
-	  transfer operation, the blind transfer Stasis message is
-	  published. At the time of publication, snapshots of the channels
-	  and bridge involved are created. The ARI subscriber to the blind
-	  transfer Stasis message then attempts to determine if the bridge
-	  or any of the involved channels are subscribed to by ARI
-	  applications. If so, then the blind transfer message is sent to
-	  the applications. The way that the ARI blind transfer message
-	  handler works is to first see if the transferer channel is
-	  subscribed to. If not, then iterate over all the channel IDs in
-	  the bridge snapshot and determine if any of those are subscribed
-	  to. In the test we were running, the lone transferee channel was
-	  subscribed to, so an ARI event should have been sent to our
-	  application. Occasionally, though, the bridge snapshot did not
-	  have any channels IDs on it at all. Why? The problem is that
-	  since the blind transfer operation is handled by a separate
-	  thread, it is possible that the transfer will have completed and
-	  the channels removed from the bridge before we publish the blind
-	  transfer Stasis message. Since the blind transfer has completed,
-	  the bridge on which the transfer occurred no longer has any
-	  channels on it, so the resulting bridge snapshot has no channels
-	  on it. Through investigation of the code, I found that attended
-	  transfers can have this issue too for the case where a transferee
-	  is transferred to an application." The fix employed here is to
-	  decouple the creation of snapshots for the transfer messages from
-	  the publication of the transfer messages. This way, snapshots can
-	  be created to reflect what they are at the time of the transfer
-	  operation. Review: https://reviewboard.asterisk.org/r/4135
-	  ........ Merged revisions 427848 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-14 14:56 +0000 [r427846]  Joshua Colp <jcolp at digium.com>
-
-	* /, apps/confbridge/conf_state_multi_marked.c: app_confbridge:
-	  Play "leader has left" sound even when musiconhold is enabled.
-	  Currently if the leader of a conference bridge leaves any
-	  participant that has musiconhold enabled will not hear the
-	  "leader has left" sound. This is because musiconhold is started
-	  and THEN the sound is played. This change makes it so that the
-	  sound is played and THEN musiconhold is started. This provides a
-	  better experience for users as they may not have known previously
-	  why they went back to musiconhold. Review:
-	  https://reviewboard.asterisk.org/r/4177/ ........ Merged
-	  revisions 427844 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427845 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-14 14:24 +0000 [r427841]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip.c, res/res_pjsip_pubsub.c, res/res_pjsip_session.c,
-	  include/asterisk/res_pjsip.h: Fix race condition where duplicated
-	  requests may be handled by multiple threads. This is the Asterisk
-	  13 version of the patch. The main difference is in the pubsub
-	  code since it was completely refactored between Asterisk 12 and
-	  13. Review: https://reviewboard.asterisk.org/r/4175
-
-2014-11-13 22:03 +0000 [r427815]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip_outbound_registration.c: res_pjsip_exten_state:
-	  PJSIPShowSubscriptionsInbound causes crash When using a
-	  non-default sorcery wizard (in this instance realtime) for
-	  outbound registrations and after adding in an appropriate call to
-	  ast_sorcery_apply_config() (since it is missing) Asterisk will
-	  crash after a stack overflow occurs due to the code infinitely
-	  recursing. The fix entails removing the outbound registration
-	  state dependency from the outbound registration sorcery object
-	  and instead keeping an in memory container that can be used to
-	  lookup the state when needed. ASTERISK-24514 Reported by: Mark
-	  Michelson Review: https://reviewboard.asterisk.org/r/4164/
-	  ........ Merged revisions 427814 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-13 15:44 +0000 [r427789]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/stasis.h, include/asterisk/stasis_app.h,
-	  res/stasis/app.h, res/res_stasis.c, /, res/stasis/app.c,
-	  res/stasis/stasis_bridge.c: Stasis: Fix StasisEnd message
-	  ordering This change corrects message ordering in cases where a
-	  channel-related message can be received after a Stasis/ARI
-	  application has received the StasisEnd message. The StasisEnd
-	  message was being passed to applications directly without waiting
-	  for the channel topic to empty. As a result of this fix, other
-	  bugs were also identified and fixed: * StasisStart messages were
-	  also being sent directly to apps and are now routed through the
-	  stasis message bus properly * Masquerade monitor datastores were
-	  being removed at the incorrect time in some cases and were
-	  causing StasisEnd messages to not be sent * General refactoring
-	  where necessary for the above * Unsubscription on StasisEnd
-	  timing changes to prevent additional messages from following the
-	  StasisEnd when they shouldn't A channel sanitization function
-	  pointer was added to reduce processing and AO2 lookups. Review:
-	  https://reviewboard.asterisk.org/r/4163/ ASTERISK-24501 #close
-	  Reported by: Matt Jordan ........ Merged revisions 427788 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-13 00:00 +0000 [r427763]  Matthew Jordan <mjordan at digium.com>
-
-	* main/rtp_engine.c, /: main/rtp_engine: Fix crash when processing
-	  more than one RTCP report info block Asterisk - in
-	  res_rtp_asterisk - only understands a single RTCP report info
-	  block. When the RTCP information was refactored in the RTP Engine
-	  to be pushed over the Stasis message bus, I put in the hooks into
-	  the engine to handle multiple RTCP report info blocks, in the
-	  hope that a future RTP implementation would be able to provide
-	  that data. Unfortunately, res_rtp_asterisk has a tendency to
-	  "lie": (1) It will send RTCP reports with a
-	  reception_report_count greater than 1 (which is pulled directly
-	  from the RTCP packet itself, so that part is correct) (2) It will
-	  only provide a single report block When the rtp_engine goes to
-	  convert this to a JSON blob, hilarity ensues as it looks for a
-	  report block that doesn't exist. This patch updates the
-	  rtp_engine to be a bit more skeptical about what it is presented
-	  with. While this could also be fixed in res_rtp_asterisk, this
-	  patch prefers to fix it in the engine for two reasons: (1) The
-	  engine is designed to work with multiple RTP implementation, and
-	  hence having it be more robust is a good thing (tm) (2)
-	  res_rtp_asterisk's handling of RTCP information is "fun". It
-	  should report the correct reception_report_count; ideally it
-	  should also be giving us all of the blocks - but it is
-	  *definitely* not designed to do that. Going down that road is a
-	  non-trivial effort. Review:
-	  https://reviewboard.asterisk.org/r/4158/ ASTERISK-24489 #close
-	  Reported by: Gregory Malsack Tested by: Gregory Malsack
-	  ASTERISK-24498 #close Reported by: Beppo Mazzucato Tested by:
-	  Beppo Maazucato ........ Merged revisions 427762 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-12 20:39 +0000 [r427737]  Corey Farrell <git at cfware.com>
-
-	* /, main/features.c: Fix leak in AMI Action Bridge Add missing
-	  reference cleanup for newly created bridge. ASTERISK-24281
-	  Reported by: Stefan Engström Review:
-	  https://reviewboard.asterisk.org/r/4154/ ........ Merged
-	  revisions 427736 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-12 16:12 +0000 [r427711]  Joshua Colp <jcolp at digium.com>
-
-	* main/pbx.c, /: pbx: Fix off-nominal case where a freed extension
-	  may still be used. If during the operation of adding an extension
-	  a priority is added but fails it is possible for the extension to
-	  be freed but still exist in the PBX core. If this occurs
-	  subsequent lookups may try to access the extension and end up in
-	  freed memory. This change removes the extension from the PBX core
-	  when the priority addition fails and then frees the extension.
-	  ASTERISK-24444 #close Reported by: Leandro Dardini Review:
-	  https://reviewboard.asterisk.org/r/4162/ ........ Merged
-	  revisions 427709 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427710 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:55 +0000 [7f4408940e]  Kevin Harwell <kharwell at lunkwill>
 
-2014-11-12 13:46 +0000 [r427684]  Corey Farrell <git at cfware.com>
+	* Release summaries: Add summaries for 11.20.0
 
-	* codecs/ilbc, /, tests, codecs/speex, apps/confbridge,
-	  Makefile.rules: Fix compiler error when using ./configure
-	  --enable-dev-mode --enable-coverage When DONT_OPTIMIZE is enabled
-	  with dev-mode, it causes a shadow compilation to be done with
-	  output to /dev/null. This can cause errors with coverage when GCC
-	  attempts to write to /dev/null.gcno. This change disables
-	  coverage for the shadow compilation. ASTERISK-24502 #close
-	  Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4151/ ........ Merged
-	  revisions 427682 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427683 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:54 +0000 [38d8bb41e4]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-2014-11-09 08:00 +0000 [r427643]  Corey Farrell <git at cfware.com>
+	* Release summaries: Remove previous versions
 
-	* main/manager.c, /: manager: Fix HTTP connection reference leaks.
-	  Fix reference leak that happens if (session && !blastaway).
-	  ASTERISK-24505 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4153/ ........ Merged
-	  revisions 427641 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427642 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:54 +0000 [25a701c398]  Kevin Harwell <kharwell at lunkwill>
 
-2014-11-09 00:38 +0000 [r427583-427615]  Matthew Jordan <mjordan at digium.com>
+	* .version: Update for 11.20.0
 
-	* channels/chan_mgcp.c, /: channels/chan_mgcp: Fix regression which
-	  causes gateways to be skipped In r227276, a while loop was turned
-	  into a for loop. Unfortunately, a portion of the while loop was
-	  left in the code such that, when a static gateway is encountered
-	  in the list of MGCP gateways, the next gateway would be skipped.
-	  At best, we would simply flip past a gateway; at worst, this
-	  could lead to a crash. ASTERISK-24500 #close Reported by: Xavier
-	  Hienne patches: chan_mgcp.patch uploaded by Xavier Hienne
-	  (License 6657) ........ Merged revisions 427613 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427614 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, addons/chan_mobile.c: addons/chan_mobile: Increase buffer size
-	  of UCS2 encoded SMS messages When UCS2 character encoding is
-	  used, one symbol in national language can be expanded to 4 bytes.
-	  The current buffer used for receiving message in do_monitor_phone
-	  is 256 bytes, which is not large enough for incoming messages.
-	  For example: * AT+CMGR phone response prefix '+CMGR: "REC
-	  UNREAD","+7**********",,"14/10/29,13:31:39+12"\r\n' - 60 bytes *
-	  SMS body with UCS2 encoding (max) - 280 bytes * AT+CMGR phone
-	  response suffix '\r\n\r\nOK\r\n' - 8 bytes * Terminating null
-	  character - 1 byte This results in a needed buffer size of 349
-	  bytes. Hence, this patch opts for a 350 byte buffer.
-	  ASTERISK-24468 #close Reported by: Dmitriy Bubnov patches:
-	  chan_mobile-1_8.diff uploaded by Dmitriy Bubnov (License 6651)
-	  chan_mobile-trunk.diff uploaded by Dmitry Bubnov (License 6651)
-	  ........ Merged revisions 427607 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427610 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_voicemail.c: app_voicemail: Fix enhancement that allowed
-	  multiple recipients in To: header An issue existed in r420577,
-	  which added multiple recipients to voicemail emails. The patch,
-	  when looking at the intended recipients, looked ahead for the '|'
-	  character inside a while loop which already had pulled out the
-	  appropriate field parsing on the '|' character. This would cause
-	  it to skip the recipients. This patch fixes it such that it
-	  relies completely on the while loop to parse through the e-mail
-	  fields. Note that the original author of the patch looked at this
-	  fix and approved it. ASTERISK-24250 #close Reported by: abelbeck
-	  patches: voicemail-420577-to-comma-fix.diff uploaded by abelbeck
-	  (License 5903)
-
-	* /, bridges/bridge_native_rtp.c: bridge_native_rtp: Fix T.38
-	  issues with remote bridges After r425242 the
-	  fax/sip/directmedia_reinvite_t38 test started failing due to the
-	  surviving channel not being re-INVITEd back from T.38 to audio.
-	  This patch fixes that bug - a deeper explanation of what happened
-	  follows. When two RTP channels are in a native bridge, the
-	  bridging layer will investigate each via the get_rtp_info glue
-	  callback. This callback returns the native bridge preference of
-	  the channel *at that moment in time* (that part is key). At
-	  different points during the bridging, the native bridging layer
-	  will inform the RTP capable channels of the status of the bridge
-	  via the update_peer glue callback. In a T.38 scenario with audio
-	  direct media, the sequence of events will often look like the
-	  following: * SIP/A and SIP/B both have audio and enter a native
-	  bridge. * Asterisk re-INVITEs audio between SIP/A and SIP/B
-	  directly (via an update_peer callback). * SIP/A sends a re-INVITE
-	  to T.38, which causes Asterisk to send a re-INVITE to T.38 to
-	  SIP/B. Assuming everyone 200 OKs the process, the UDPTL stack
-	  receives UDPTL packets in Asterisk from both endpoints. From the
-	  perspective of the channels, we are now in a local bridge for
-	  T.38, even though we are technically still in a remote bridge in
-	  bridge_native_rtp. (YAY!) * When one side hangs up,
-	  bridge_native_rtp is told to stop bridging. It then re-evaluates
-	  the channels and asks them how they are bridged - and since T.38
-	  is enabled, they reply with a Local bridge (which is correct),
-	  but is wrong because the audio portion is still technically in a
-	  remote bridge. * Asterisk releases the surviving channel, whose
-	  audio is *not* re-INVITED back to Asterisk as bridge_native_rtp
-	  incorrectly assumes that it was in a local bridge. Ironically,
-	  prior to r425242, this used to work mostly due to a fluke in the
-	  bridging layer. The purpose of the get_rtp_info callback
-	  shouldn't be modified: it should tell the bridging layer what
-	  kind of bridge the channel prefers at that moment in time. If you
-	  have T.38 enabled, that *must* be a local bridge, as the UDPTPL
-	  stack must be in the media path. As such, this patch does not
-	  modify that part of the code. However, we have to tell the
-	  channels to re-evaluate themselves when they come out of a native
-	  bridge, since we can no longer trust the get_rtp_info callbacks
-	  when the native bridge is being stopped. Something else may have
-	  changed in the channels, and they may now be lying to us. As
-	  such, this patch makes it so that we unilaterally tell the
-	  channels that they are no longer bridged via the update_peer
-	  callback. This is actually what the channels expect anyway: code
-	  in both chan_sip and chan_pjsip's callbacks look at the T.38
-	  state and - if they were in T.38 - send a re-INVITE to get the
-	  audio back to Asterisk. Review:
-	  https://reviewboard.asterisk.org/r/4157/ ........ Merged
-	  revisions 427582 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-08 18:17 +0000 [r427557]  Corey Farrell <git at cfware.com>
-
-	* /, channels/chan_console.c: chan_console: Fix reference leaks to
-	  pvt. Fix a bunch of calls to get_active_pvt where the reference
-	  is never released. ASTERISK-24504 #close Reported by: Corey
-	  Farrell Review: https://reviewboard.asterisk.org/r/4152/ ........
-	  Merged revisions 427554 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427555 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-06 19:22 +0000 [r427494-427512]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_agent_pool.c, /: app_agent_pool: Made agent alert
-	  interruptable by DTMF. Made agent able to interrupt the alerting
-	  beep playback with DTMF. Any digit can interrupt if the call does
-	  not need to be acknowledged. Only the first digit of the
-	  acknowledgement can interrupt if the call needs to be
-	  acknowledged. The agent interrupting the alerting playback builds
-	  on the ASTERISK-24447 patch because it knows what digit
-	  interrupted the playback and needs to be able to pass that digit
-	  to the DTMF hook digit collection code. ASTERISK-24257 #close
-	  Reported by: Steve Pitts Review:
-	  https://reviewboard.asterisk.org/r/4123/ ........ Merged
-	  revisions 427508 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, include/asterisk/bridge_channel.h, main/bridge_channel.c:
-	  Bridge DTMF hooks: Made audio pass from the bridge while waiting
-	  for more matching digits. * Made collecting DTMF digits for the
-	  DTMF feature hooks pass frames from the bridge. * Made collecting
-	  DTMF digits possible by other bridge hooks if there is a need.
-	  ASTERISK-24447 #close Reported by: Richard Mudgett Review:
-	  https://reviewboard.asterisk.org/r/4123/ ........ Merged
-	  revisions 427493 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-06 18:20 +0000 [r427491]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/pjsip_distributor.c: res_pjsip: Ensure in-dialog
-	  responses have an endpoint associated. When handling incoming
-	  messages we determine if it is associated with a dialog. If so we
-	  use that to determine what serializer and endpoint to use for the
-	  message. Previously this would pass the endpoint to the endpoint
-	  lookup module to actually place the endpoint completely on the
-	  message. For in-dialog responses, however, this did not occur as
-	  dialog processing took over and the endpoint lookup did not
-	  occur. This change just places the endpoint in the expected spot
-	  immediately instead of relying on the endpoint lookup module.
-	  In-dialog responses thus have the expected endpoint. AST-1459
-	  #close Review: https://reviewboard.asterisk.org/r/4146/ ........
-	  Merged revisions 427490 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-06 12:13 +0000 [r427384-427466]  Corey Farrell <git at cfware.com>
-
-	* main/file.c, /: main/file.c: fix possible extra ast_module_unref
-	  to format modules. fn_wrapper only adds a reference to the
-	  format's module if the file was able to be opened. If not this
-	  causes an unmatched ast_module_unref in filestream_destructor.
-	  Move ast_module_ref to get_stream. ASTERISK-24492 #close Reported
-	  by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4149/ ........ Merged
-	  revisions 427464 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427465 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_hep.c, /: res_hep: fix major leak that occurs when config
-	  is missing or enabled=no. Add missing unreference in
-	  hepv3_send_packet. ASTERISK-24491 #close Reported by: Zane Conkle
-	  Tested by: Zane Conkle Review:
-	  https://reviewboard.asterisk.org/r/4150/ ........ Merged
-	  revisions 427400 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/utils.c, include/asterisk/stringfields.h: Fix unintential
-	  memory retention in stringfields. * Fix missing / unreachable
-	  calls to __ast_string_field_release_active. * Reset pool->used to
-	  zero when the current pool->active reaches zero. ASTERISK-24307
-	  #close Reported by: Etienne Lessard Tested by: ibercom, Etienne
-	  Lessard Review: https://reviewboard.asterisk.org/r/4114/ ........
-	  Merged revisions 427380 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 427381 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427382 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:54 +0000 [1fb284225e]  Kevin Harwell <kharwell at lunkwill>
 
-2014-11-06 02:37 +0000 [r427356]  George Joseph <george.joseph at fairview5.com>
+	* .lastclean: Update for 11.20.0
 
-	* tests/test_strings.c, /: test_strings: Remove string tests that
-	  exercise asserts. Since unit tests are run with DO_CRASH, those
-	  tests were causing the test to fail. Tested-by: George Joseph
-	  ........ Merged revisions 427354 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427355 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-05 19:52 +0000 [r427334]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip/config_system.c, configs/samples/pjsip.conf.sample,
-	  res/res_pjsip.c: Make the disable_tcp_switch PJSIP system object
-	  enabled by default. Testing has shown repeatedly that PJSIP's
-	  default behavior of switching automatically to TCP for large
-	  messages can cause issues. The most common issues are that
-	  devices that we are communicating with do not handle the switch
-	  to TCP gracefully, thus causing situations such as broken calls
-	  or broken subscriptions. Now, in order to have this behavior
-	  happen, you must opt into it. The sample file has been updated to
-	  warn that enabling the TCP switch behavior may cause issues for
-	  you, so use at your own risk.
-
-2014-11-05 12:18 +0000 [r427303]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_multihomed.c, /: res_pjsip_multihomed: Add logging
-	  during startup to aid debugging if local DNS is misbehaving. This
-	  change adds a bit of logging so if the local DNS is misbehaving
-	  it is easier to track down what is going on and where Asterisk
-	  may be hanging. ASTERISK-24438 #close Reported by: Melissa
-	  Shepherd Review: https://reviewboard.asterisk.org/r/4148/
-	  ........ Merged revisions 427300 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-05 00:15 +0000 [r427228-427276]  George Joseph <george.joseph at fairview5.com>
-
-	* pbx/pbx_config.c, main/config.c, tests/test_strings.c,
-	  include/asterisk/utils.h, /, main/utils.c: config: Make
-	  text_file_save and 'dialplan save' escape semicolons in values.
-	  When a config file is read, an unescaped semicolon signals
-	  comments which are stripped from the value before it's stored.
-	  Escaped semicolons are then unescaped and become part of the
-	  value. Both of these behaviors are normal and expected. When the
-	  config is serialized either by 'dialplan save' or
-	  AMI/UpdateConfig however, the now unescaped semicolons are
-	  written as-is. If you actually reload the file just saved, the
-	  unescaped semicolons are now treated as start of comments. Since
-	  true comments are stripped on read, any semicolons in
-	  ast_variable.value must have been escaped originally. This patch
-	  re-escapes semicolons in ast_variable.values before they're
-	  written to file either by 'dialplan save' or
-	  config/ast_config_text_file_save which is called by
-	  AMI/UpdateConfig. I also fixed a few pre-existing formatting
-	  issues nearby in pbx_config.c Tested-by: George Joseph
-	  ASTERISK-20127 #close Review:
-	  https://reviewboard.asterisk.org/r/4132/ ........ Merged
-	  revisions 427275 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/config.c, /: config: BUG: Restore ability for non-templ to
-	  be used as base objs in config. My recent refactor of config.c
-	  accidentally removed the capability for an object to inherit from
-	  a non-template object. This patch restores the capability to
-	  inherit from both template and non-template objects. Tested-by:
-	  George Joseph Reported-by: Scott Griepentrog ASTERISK-24487
-	  #close Review: https://reviewboard.asterisk.org/r/4147/ ........
-	  Merged revisions 427227 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-04 19:44 +0000 [r427181-427204]  Corey Farrell <git at cfware.com>
-
-	* funcs/func_talkdetect.c, /: func_talkdetect: Fix stasis message
-	  leak in audiohook callback. ASTERISK-24482 #close Reported by:
-	  Corey Farrell Review: https://reviewboard.asterisk.org/r/4142/
-	  ........ Merged revisions 427203 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_http_websocket.c: res_http_websockets: Fix extra unref
-	  of module In websocket_add_protocol_internal is used to add the
-	  "echo" protocol, but ast_websocket_remove_protocol is used to
-	  remove it. This causes an extra call to ast_module_unref.
-	  ASTERISK-24480 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4140/ ........ Merged
-	  revisions 427200 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/app.c: Fix crash caused by merge error on review 4138 When
-	  merging from 12 to 13 there were conflicts, I mistakenly had the
-	  loop run ast_closestream(others[0]) when it should be
-	  ast_closestream(others[x]).
-
-2014-11-03 18:15 +0000 [r427130]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_pjsip/config_system.c, UPGRADE.txt,
-	  configs/samples/pjsip.conf.sample, res/res_pjsip.c: res_pjsip:
-	  Add disable_tcp_switch option. When a packet exceeds the MTU,
-	  pjproject will switch from UDP to TCP. In some circumstances (on
-	  some networks), this can cause some issues with messages not
-	  getting sent to the correct destination - and can also cause
-	  connections to get dropped due to quirks in pjproject deciding to
-	  terminate TCP connections with no messages. While fixing the
-	  routing/messaging issues is important, having a configuration
-	  option in Asterisk that tells pjproject to not switch over to TCP
-	  would be useful. That way, if some glitch is discovered on some
-	  other network/site, we can at least disable the behavior until a
-	  fix is put into place. AFS-197 #close Review:
-	  https://reviewboard.asterisk.org/r/4137/ ........ Merged
-	  revisions 427129 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-03 02:34 +0000 [r427021-427089]  Corey Farrell <git at cfware.com>
-
-	* apps/app_voicemail.c, /: Fix compile error caused by review 4138
-	  There is no procedure called ast_closeframe, fix code to use
-	  ast_closestream. Reported By: Matt Jordan ........ Merged
-	  revisions 427087 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427088 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:22 +0000 [9643010356]  Kevin Harwell <kharwell at lunkwill>
 
-	* main/app.c, apps/app_voicemail.c, /: Fix ast_writestream leaks
-	  Fix cleanup in __ast_play_and_record where others[x] may be
-	  leaked. This was caught where prepend != NULL && outmsg != NULL,
-	  once realfile[x] == NULL any further others[x] would be leaked. A
-	  cleanup block was also added for prepend != NULL && outmsg ==
-	  NULL. 11+: Fix leak of ast_writestream recording_fs in
-	  app_voicemail:leave_voicemail. ASTERISK-24476 #close Reported by:
-	  Corey Farrell Review: https://reviewboard.asterisk.org/r/4138/
-	  ........ Merged revisions 427023 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 427024 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427025 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/abstract_jb.c: func_jitterbuffer: fix frame leaks. Fix
-	  code paths where it is possible for frames to leak. Fix
-	  uninitialized variable in jb_get_fixed and jb_get_adaptive.
-	  ASTERISK-22409 #related Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4128/ ........ Merged
-	  revisions 427019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 427020 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-11-02 01:01 +0000 [r426996]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_stasis.c: res/res_stasis: Fix crash on module unload
-	  while performing operation When the res_stasis module is
-	  unloaded, it will dispose of the apps_registry container. This is
-	  a problem if an ARI operation is in flight that attempts to use
-	  the registry, as the shutdown occurs in a separate thread. This
-	  patch adds some sanity checks to the various routines that access
-	  the registry which cause the operations to fail if the
-	  apps_registry does not exist. Crash caught by the Asterisk Test
-	  Suite. ........ Merged revisions 426995 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-31 16:50 +0000 [r426934]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+	* ChangeLog: Updated for 11.20.0
 
-	* Makefile, /: install init.d files on GNU/kFreeBSD Review:
-	  https://reviewboard.asterisk.org/r/4118/ ........ Merged
-	  revisions 426926 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426927 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426933 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-31 16:40 +0000 [r426924-426930]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, configs/samples/pjsip.conf.sample, res/res_pjsip.c: pjsip:
-	  clarify tls cert and key file usage A question arose as to
-	  whether a .pem file could be provided in place of the .crt and
-	  .key files in a PJSIP TLS configuration. I tested this and
-	  discovered that although a cert will be read from the pem file, a
-	  key will not, and thus the priv_key_file entry is still required.
-	  This update to the fine documentation clarifies the option usage.
-	  AST-1448 #close Review: https://reviewboard.asterisk.org/r/4129/
-	  Reported by: John Bigelow ........ Merged revisions 426928 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_outbound_registration.c: pjsip: Handle outbound
-	  unregister correctly This updates the status of the outbound
-	  registration to reflect when it has been unregistered. Since the
-	  registration is unregistered but is not stopped, the registration
-	  schedule remains active as before. The patch also updates the
-	  documentation of both the AMI and CLI commands. ASTERISK-24411
-	  #close Review: https://reviewboard.asterisk.org/r/4119/ Reported
-	  by: John Bigelow patches: unregister-patch1.txt uploaded by John
-	  Bigelow (License 5091) ........ Merged revisions 426923 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-31 03:26 +0000 [r426865]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/sip/reqresp_parser.c,
-	  channels/sip/include/reqresp_parser.h:
-	  channels/sip/reqresp_parser: Fix unit tests for r426594 When
-	  r426594 was made, it did not take into account a unit test that
-	  verified that the function properly populated the unsupported
-	  buffer. The function would previously memset the buffer if it
-	  detected it had any contents; since this function can now be
-	  called iteratively on successive headers, the unit tests would
-	  now fail. This patch updates the unit tests to reset the buffer
-	  themselves between successive calls, and updates the
-	  documentation of the function to note that this is now required.
-	  ........ Merged revisions 426858 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426860 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426863 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-31 03:08 +0000 [r426803-426833]  Corey Farrell <git at cfware.com>
-
-	* contrib/Makefile (added), Makefile, /: REF_DEBUG: Install
-	  refcounter.py to $(ASTDATADIR)/scripts This change ensures
-	  refcounter.py is installed to a place where it can be found by
-	  the Asterisk testsuite if REF_DEBUG is enabled. ASTERISK-24432
-	  #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4094/ ........ Merged
-	  revisions 426830 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426831 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426832 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:21 +0000 [ac23a5511d]  Kevin Harwell <kharwell at lunkwill>
 
-	* /, apps/app_queue.c: app_queue: fix a couple leaks to struct
-	  call_queue in set_member_value set_member_value has a couple
-	  leaks to references in the variable q found through testsuite
-	  tests/queues/set_penalty. Also remove the REF_DEBUG_ONLY_QUEUES
-	  compiler declaration, this is no longer possible with the updated
-	  REF_DEBUG code. ASTERISK-24466 #close Reported by: Corey Farrell
-	  Review: https://reviewboard.asterisk.org/r/4125/ ........ Merged
-	  revisions 426805 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426806 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/audiohook.c: audiohooks: Clean references to formats Cleanup
-	  references to in_translate[x].format and out_translate[x].format
-	  in ast_audiohook_detach_list. ASTERISK-24465 #close Reported by:
-	  Corey Farrell Review: https://reviewboard.asterisk.org/r/4124/
-
-2014-10-30 21:13 +0000 [r426757-426780]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_exten_state.c, /: res_pjsip_exten_state:
-	  PJSIPShowSubscriptionsInbound causes crash Currently, it is
-	  possible for some subscriptions to get into a NULL state. When
-	  this occurs and the PJSIPShowSubscriptionsInbound ami action is
-	  issued and a device is subscribed for extension state then the
-	  associated subscription state object can't be located. The code
-	  then attempts to dereference a NULL object. Added a NULL check to
-	  avoid the problem. Reported by: John Bigelow ........ Merged
-	  revisions 426779 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip/pjsip_options.c, /: res_pjsip: incorrect qualify
-	  statistics after disabling for contact When removing the
-	  qualify_frequency from an AoR or a contact the statistics shown
-	  when issuing "pjsip show aors" from the CLI are incorrect. This
-	  patch deletes the contact's status object from sorcery,
-	  disassociating it from the contact, if the qualify_freqency is
-	  removed from configuration. ASTERISK-24462 #close Reported by:
-	  Mark Michelson Review: https://reviewboard.asterisk.org/r/4116/
-	  ........ Merged revisions 426755 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-30 09:20 +0000 [r426702]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* apps/app_voicemail.c, /: app_voicemail: Fix unchecked bounds of
-	  myArray in IMAP_STORAGE. In update_messages_by_imapuser(),
-	  messages were appended to a finite array which resulted in a
-	  crash when an IMAP mailbox contained more than 256 entries. This
-	  memory is now dynamically increased as needed. Observe that this
-	  patch adds a bunch of XXX's to questionable code. See the review
-	  (url below) for more information. ASTERISK-24190 #close Reported
-	  by: Nick Adams Tested by: Nick Adams Review:
-	  https://reviewboard.asterisk.org/r/4126/ ........ Merged
-	  revisions 426691 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426692 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426696 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* Release summaries: Add summaries for 11.20.0
 
-2014-10-30 06:09 +0000 [r426668]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+2015-10-09 15:20 +0000 [5036db7bad]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-	* channels/chan_unistim.c, /: Add additional checks for NULL
-	  pointers to fix several crashes reported. ASTERISK-24304 #close
-	  Reported by: dhanapathy sathya ........ Merged revisions 426666
-	  from http://svn.asterisk.org/svn/asterisk/branches/11 ........
-	  Merged revisions 426667 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* Release summaries: Remove previous versions
 
-2014-10-30 01:59 +0000 [r426597-426602]  Matthew Jordan <mjordan at digium.com>
+2015-10-09 15:20 +0000 [ab3078d664]  Kevin Harwell <kharwell at lunkwill>
 
-	* /, channels/chan_sip.c: channels/chan_sip: Add improved support
-	  for 4xx error codes This patch adds support for 414, 493, 479,
-	  and a stray 400 response in REGISTER response handling. This
-	  helps interoperability in a number of scenarios. Review:
-	  https://reviewboard.asterisk.org/r/3437 patches: rb3437.patch
-	  uploaded by oej (License 5267) ........ Merged revisions 426599
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 426600 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426601 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* .version: Update for 11.20.0
 
-	* channels/sip/reqresp_parser.c, /, channels/chan_sip.c:
-	  channels/chan_sip: Support mutltiple Supported and Required
-	  headers A SIP request may contain multiple Supported: and
-	  Required: headers. Currently, chan_sip only parses the first
-	  Supported/Required header it finds. This patch adds support for
-	  multiple Supported/Required headers for INVITE requests. Review:
-	  https://reviewboard.asterisk.org/r/2478 ASTERISK-21721 #close
-	  Reported by: Olle Johansson patches: rb2478.patch uploaded by oej
-	  (License 5267) ........ Merged revisions 426594 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426595 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426596 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-09 15:20 +0000 [502b4c9786]  Kevin Harwell <kharwell at lunkwill>
 
-2014-10-29 10:33 +0000 [r426570]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+	* .lastclean: Update for 11.20.0
 
-	* channels/chan_phone.c: Fix building chan_phone on big endian
-	  systems A left over from the formats conversion (Corey Farrell).
-	  ASTERISK-24458 #close Review:
-	  https://reviewboard.asterisk.org/r/4117/
+2015-10-07 18:14 +0000  Asterisk Development Team <asteriskteam at digium.com>
 
-2014-10-28 21:26 +0000 [r426552]  Richard Mudgett <rmudgett at digium.com>
+	* asterisk 11.20.0-rc3 Released.
 
-	* /, bridges/bridge_builtin_features.c: bridge_builtin_features:
-	  Add missing channel locks around
-	  ast_get_chan_features_general_config(). The feature_automonitor()
-	  and feature_automixmonitor() functions were not locking the
-	  channel around ast_get_chan_features_general_config(). Accessing
-	  the channel datastore list without the channel locked is a good
-	  way to corrupt the list or follow the pointer chain into
-	  oblivion. ........ Merged revisions 426531 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-07 13:14 +0000 [a42c71a4a4]  Kevin Harwell <kharwell at lunkwill>
 
-2014-10-28 21:05 +0000 [r426525-426529]  Corey Farrell <git at cfware.com>
+	* Release summaries: Add summaries for 11.20.0-rc3
 
-	* /, res/res_fax.c: res_fax: Resolve T38 gateway frame leak. When
-	  frames are translated by a fax gateway they need to be freed. The
-	  existing call to ast_frfree was unreachable. This change
-	  reorganizes fax_gateway_framehook to ensure that ast_frfree is
-	  called when needed. ASTERISK-24457 #close Reported by: Corey
-	  Farrell Review: https://reviewboard.asterisk.org/r/4115/ ........
-	  Merged revisions 426527 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426528 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /: manager: Unsubscribe from acl_change_sub at
-	  shutdown. ASTERISK-24453 #close Reported by: Corey Farrell
-	  Review: https://reviewboard.asterisk.org/r/4110/ ........ Merged
-	  revisions 426524 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-28 18:09 +0000 [r426459]  mdavenport <mdavenport at localhost>:
-
-	* configs/samples/manager.conf.sample: ASTERISK-23512, correct
-	  inaccurate comment in manager.conf.sample
-
-2014-10-28 16:40 +0000 [r426368-426432]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/bridge.c: main/bridge: Destroy features struct on off
-	  nominal path during bridge impart When a channel is imparted to a
-	  bridge, the invocation of the function may provide an
-	  ast_bridge_features struct. Upon passing this to
-	  ast_bridge_impart, the caller must assume that ownership has
-	  passed to the function, as in all paths the function destroys the
-	  struct prior to returning (as its purpose is to configure the
-	  behavior of the channel while in the bridge). On one off nominal
-	  path - where the channel already has a PBX thread - the struct
-	  was not being destroyed. This patch fixes that glitch.
-	  ASTERISK-24437 #close Reported by: Scott Griepentrog ........
-	  Merged revisions 426431 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /: main/manager: Fix typo in AMI event
-	  documentation of "OriginateResponse" The parameter name is
-	  "Response", not "Resonse". ASTERISK-24430 #close Reported by:
-	  Dafi Ni ........ Merged revisions 426366 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426367 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-28 14:56 +0000 [r426294-426362]  mdavenport <mdavenport at localhost>:
+2015-10-07 13:14 +0000 [01c9b5457c]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-	* res/res_agi.c: ASTERISK-24323, fix bug in documentation of AGI
-	  STREAM FILE CONTROL
+	* Release summaries: Remove previous versions
 
-	* configs/samples/extensions.conf.sample: ASTERISK-24419, fix
-	  incorrect syntax for setting language in extensions.conf.sample
+2015-10-07 13:14 +0000 [7d71131289]  Kevin Harwell <kharwell at lunkwill>
 
-2014-10-28 11:20 +0000 [r426252-426266]  Corey Farrell <git at cfware.com>
+	* .version: Update for 11.20.0-rc3
 
-	* apps/app_queue.c, /: app_queue: Cleanup ao2_iterator Clean
-	  ao2_iterator, resolving reference leak to queue members.
-	  ASTERISK-24454 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4111/ ........ Merged
-	  revisions 426255 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426260 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* funcs/func_cdr.c: func_cdr: Fix CDR_PROP payload leak Remove
-	  duplicate allocation of payload, preventing leak. ASTERISK-24455
-	  #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4113/
+2015-10-07 13:14 +0000 [19fea93816]  Kevin Harwell <kharwell at lunkwill>
 
-2014-10-27 17:54 +0000 [r426234]  Sean Bright <sean at malleable.com>
+	* .lastclean: Update for 11.20.0-rc3
 
-	* build_tools/menuselect-deps.in, configure,
-	  include/asterisk/autoconfig.h.in, configure.ac, makeopts.in:
-	  configure: Add autoconf check for libopus. Because opus
-	  transcoding support cannot be included in the standard Asterisk
-	  distribution, a few codec_opus implementations have popped up. To
-	  make it easier for people to drop in opus support in their own
-	  installations, this patch adds configure checks for libopus.
-	  Review: https://reviewboard.asterisk.org/r/4106/
-
-2014-10-27 02:46 +0000 [r426143-426211]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_http_websocket.c, /: res/res_http_websocket: Fix minor
-	  nits found by wdoekes on r409681 When Moises committed the fixes
-	  for WSS (which was a great patch), wdoekes had a few style nits
-	  that were on the review that got missed. This patch resolves what
-	  I *think* were all of the ones that were still on the review.
-	  Thanks to both moy for the patch, and wdoekes for the reviews.
-	  Review: https://reviewboard.asterisk.org/r/3248/ ........ Merged
-	  revisions 426209 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426210 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_phoneprov.c: res/res_phoneprov: Fix crash on shutdown
-	  caused by container cleanup In res_phoneprov, unloading the
-	  module first destroys the http_routes container, followed by the
-	  users. However, users may have a route in the http_routes
-	  container; the validity of this container is not checked in the
-	  users destructor. Hence, we hit an assert as the container has
-	  already been set to NULL. This patch does two things: (1) It adds
-	  a sanity check in the user destructor (because why not) (2) It
-	  switches the order of destruction, so that users are disposed of
-	  prior to the HTTP routes they may hold a reference to. Note that
-	  this crash was caught by the Test Suite (go go testing!) ........
-	  Merged revisions 426174 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-06 20:43 +0000 [984ff78ec7]  Matt Jordan <mjordan at digium.com>
 
-	* res/res_srtp.c, /: res/res_srtp: Fix include issue for libsrtp
-	  1.5.0 In libsrtp 1.5.0, crypto_get_random is no longer resolved
-	  simply by including srtp.h. Now, one must include crypto_kernel.h
-	  as well. As it turns out, this header file has been provided by
-	  the library since 2006, so this is a relatively benign change.
-	  ASTERISK-24436 #close Reported by: Patrick Laimbock ........
-	  Merged revisions 426140 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 426141 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 426142 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-24 15:17 +0000 [r426120]  Jonathan Rose <jrose at digium.com>
-
-	* main/manager.c: Documentation: Improve documentation for
-	  ExtensionStatus AMI events Review:
-	  https://reviewboard.asterisk.org/r/4085/
-
-2014-10-24  Asterisk Development Team <asteriskteam at digium.com>
-
-	* Asterisk 13.0.0 Released.
-
-2014-10-22 21:27 +0000 [r426097]  Shaun Ruffell <sruffell at digium.com>
-
-	* codecs/codec_dahdi.c: codec_dahdi: Cannot use struct
-	  ast_translator.core_{src,src}_codec. This fixes a Segmentation
-	  fault introduced in r419044 "media formats: re-architect handling
-	  of media for performance improvements". The problem is that
-	  codec_dahdi was using core_src_codec and core_dst_codec in the
-	  ast_translator structure when these fields were never set. Now
-	  instead of trying to map the new core codec descriptions to the
-	  way DAHDI defines different codecs, we will store the DAHDI
-	  specific formats in 'struct translator' directly so we can refer
-	  to them without mapping. This also allows us to remove the
-	  "global_format_map" structure, since we can now query the list of
-	  translators directly to make sure we do not ever register a DAHDI
-	  based translator for a specific path more than once and eliminate
-	  the need to keep the list and the map in sync. ASTERISK-24435
-	  #close Reported by: Marian Koniuszko Review:
-	  https://reviewboard.asterisk.org/r/4105/
-
-2014-10-21 17:47 +0000 [r426079]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/translate.c: translage.c: Fix regression when generating
-	  translation path strings. Fix the AMI Status action read and
-	  write translation path strings from growing for each channel in
-	  the status event list by reseting the ast string given to
-	  ast_translate_path_to_str() to fill in the given translation
-	  path.
-
-2014-10-20 14:15 +0000 [r425991]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_xmpp.c, main/tcptls.c, /: AST-2014-011: Fix POODLE
-	  security issues There are two aspects to the vulnerability: (1)
-	  res_jabber/res_xmpp use SSLv3 only. This patch updates the module
-	  to use TLSv1+. At this time, it does not refactor
-	  res_jabber/res_xmpp to use the TCP/TLS core, which should be done
-	  as an improvement at a latter date. (2) The TCP/TLS core, when
-	  tlsclientmethod/sslclientmethod is left unspecified, will default
-	  to the OpenSSL SSLv23_method. This method allows for all
-	  encryption methods, including SSLv2/SSLv3. A MITM can exploit
-	  this by forcing a fallback to SSLv3, which leaves the server
-	  vulnerable to POODLE. This patch adds WARNINGS if a user uses
-	  SSLv2/SSLv3 in their configuration, and explicitly disables
-	  SSLv2/SSLv3 if using SSLv23_method. For TLS clients, Asterisk
-	  will default to TLSv1+ and WARN if SSLv2 or SSLv3 is explicitly
-	  chosen. For TLS servers, Asterisk will no longer support SSLv2 or
-	  SSLv3. Much thanks to abelbeck for reporting the vulnerability
-	  and providing a patch for the res_jabber/res_xmpp modules.
-	  Review: https://reviewboard.asterisk.org/r/4096/ ASTERISK-24425
-	  #close Reported by: abelbeck Tested by: abelbeck, opsmonitor,
-	  gtjoseph patches: asterisk-1.8-jabber-tls.patch uploaded by
-	  abelbeck (License 5903) asterisk-11-jabber-xmpp-tls.patch
-	  uploaded by abelbeck (License 5903) AST-2014-011-1.8.diff
-	  uploaded by mjordan (License 6283) AST-2014-011-11.diff uploaded
-	  by mjordan (License 6283) ........ Merged revisions 425987 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-19 17:07 +0000 [r425965]  George Joseph <george.joseph at fairview5.com>
+	* res/res_rtp_asterisk: Fix assignment after ao2 decrement
 
-	* Makefile, /, configure, include/asterisk/autoconfig.h.in,
-	  configure.ac, makeopts.in: build: Force -fsigned-char on
-	  platforms where the default for char is unsigned gcc on the ARM
-	  platform defaults 'char' to 'unsigned char' whereas Intel and
-	  SPARC default to 'signed char'. This is only an issue in the rare
-	  cases where negative values are assigned to a 'char' but this
-	  this patch insures compatibility by detecting platforms that
-	  default to 'unsigned' and adding an '-fsigned-char' flag to
-	  _ASTCFLAGS. If compiling for ARM (native or cross-compile) be
-	  sure to run ./bootstrap.sh and ./configure to regenerate the
-	  build files. You shouldn't have to do this for Intel or SPARC.
-	  Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4091/ ........ Merged
-	  revisions 425964 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-19 04:01 +0000 [r425923-425944]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c: res/res_pjsip_sdp_rtp: Revert 425922
-	  This patch for r425922 introduced a bug, wherein sending an
-	  INVITE request with no SDP would cause Asterisk to not send an
-	  SDP Offer in the 200 OK. The current structure of
-	  res_pjsip_sdp_rtp is a bit hard to deal with to fix this, as
-	  create_outgoing_sdp has no knowledge of whether or not it is
-	  creating an SDP as a new Offer or an Answer. This is something of
-	  an oversight in the callback definition, as the caller of it does
-	  have this information.
-
-	* res/res_pjsip_sdp_rtp.c: res/res_pjsip_sdp_rtp: Remove left over
-	  reference to override_prefs The usage of the local override_prefs
-	  variable in create_outgoing_sdp_stream was previously to track an
-	  override format preference set by PJSIP_MEDIA_OFFER. Now,
-	  however, that function simply sets the joint capabilities
-	  structure, session->req_caps. During the media format rework, the
-	  override_prefs was instead used to check if there were any
-	  formats in session->req_caps. However, this usage isn't useful in
-	  create_outgoing_sdp_stream. session->req_caps contains the
-	  negotiated formats for *all* streams, not just the current one
-	  being created. Thus, so long as any stream of any type has
-	  provided a format, override_prefs will be non-zero. Hence, its
-	  usage in checking whether or not we should look at the formats on
-	  the endpoint or the joint capabilities is generally useless.
-	  There's only two things useful to check: (1) Does the endpoint
-	  have a format for the media type? (2) Did we negotiate a format
-	  for the media type? If either of those is a 'no', then we must
-	  kill the media stream.
-
-2014-10-17 22:43 +0000 [r425905]  Jonathan Rose <jrose at digium.com>
-
-	* configs/samples/cli_aliases.conf.sample: Sample Configurations:
-	  make 'pjsip reload' reload all reloadable pjsip modules AST-1432
-	  #close Reported by: John Bigelow
-
-2014-10-17 13:35 +0000 [r425821-425879]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, res/res_pjsip.c,
-	  res/res_pjsip_session.c, /: res_pjsip_session/res_pjsip_sdp_rtp:
-	  Be more tolerant of offers When an inbound SDP offer is received,
-	  Asterisk currently makes a few incorrection assumptions: (1) If
-	  the offer contains more than a single audio/video stream,
-	  Asterisk will reject the entire stream with a 488. This is an
-	  overly strict response; generally, Asterisk should accept the
-	  media streams that it can accept and decline the others. (2) If
-	  the offer contains a declined media stream, Asterisk will attempt
-	  to process it anyway. This can result in attempting to match
-	  format capabilities on a declined media stream, leading to a 488.
-	  Asterisk should simply ignore declined media streams. (3)
-	  Asterisk will currently attempt to handle offers with AVPF with
-	  use_avpf=No/AVP with use_avpf=Yes. This mismatch results in
-	  invalid SDP answers being sent in response. If there is a
-	  mismatch between the media type being offered and the
-	  configuration, Asterisk must reject the offer with a 488. This
-	  patch does the following: * Asterisk will accept SDP offers with
-	  at least one media stream that it can use. Some WARNING messages
-	  have been dropped to NOTICEs as a result. * Asterisk will not
-	  accept an offer with a media type that doesn't match its
-	  configuration. * Asterisk will ignore declined media streams
-	  properly. #SIPit31 Review:
-	  https://reviewboard.asterisk.org/r/4063/ ASTERISK-24122 #close
-	  Reported by: James Van Vleet ASTERISK-24381 #close Reported by:
-	  Matt Jordan ........ Merged revisions 425868 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  When we decide we will no longer schedule an RTCP write, we remove the
+	  reference to the RTP instance, then assign -1 to the stored scheduler ID
+	  in case something else comes along and wants to see if anything is scheduled.
 
-	* /, channels/chan_sip.c: channels/chan_sip: Respect outboundproxy
-	  setting when sending qualify requests The outboundproxy setting
-	  is currently ignored when sending OPTIONS requests as a result of
-	  the qualify setting. This means that if an Asterisk server is
-	  unable to send the packet directly to a peer, it is unable to
-	  qualify any non-inbound registered peer (e.g. a peer SIP Trunk).
-	  This patch grabs the outboundproxy information for a peer when a
-	  qualify attempt is being constructed and, if it finds the
-	  information, uses it when sending the OPTIONS request. Review:
-	  https://reviewboard.asterisk.org/r/3948 ASTERISK-24063 #close
-	  Reported by: Damian Ivereigh patches: outboundproxy-dai.patch
-	  uploaded by Damian Ivereigh (License 6632) ........ Merged
-	  revisions 425818 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425819 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425820 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-17 02:41 +0000 [r425783]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/core_unreal.c, main/channel.c, /: AMI: Add missing VarSet
-	  events when a channel inherits variables. There should be AMI
-	  VarSet events when channel variables are inherited by an outgoing
-	  channel. Also local;2 should generate VarSet events when it gets
-	  all of its channel variables from channel local;1. ASTERISK-24415
-	  #close Reported by: Richard Mudgett Patches:
-	  jira_asterisk_24415_v12.patch (license #5621) patch uploaded by
-	  Richard Mudgett Review: https://reviewboard.asterisk.org/r/4074/
-	  ........ Merged revisions 425782 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-17 01:57 +0000 [r425736-425761]  Matthew Jordan <mjordan at digium.com>
-
-	* /, bridges/bridge_native_rtp.c: bridge_native_rtp: Fix audio
-	  issues when moving from remote bridge to softmix When a native
-	  RTP bridge that is remotely bridging its participants switches to
-	  a softmix bridge, it may not properly re-INVITE the media for one
-	  or both participants back to Asterisk. This is due to the current
-	  bridge_native_rtp code only re-INVITEs if it believes the channel
-	  will survive the bridge operation. Currently, that code is
-	  failing, as it expects the channels to have a soft hangup flag
-	  set on it indicating that a redirect has occurred or that the
-	  channel is going to leave the bridge. (The code did not take into
-	  account a smart bridge operation). This patch also renames a few
-	  things to be more reflective of the underlying types. Review:
-	  https://reviewboard.asterisk.org/r/3997/ ASTERISK-24327 #close
-	  ........ Merged revisions 425760 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, tests/test_cel.c: test_cel: Update pickup test to expect
-	  CANCEL instead of ANSWSER The CEL pickup test previously looked
-	  for a disposition of ANSWER between the original caller/peer when
-	  the call is picked up. This is actually incorrect: the
-	  disposition should, at the very least, not be ANSWER as the call
-	  was never ANSWERed. The disposition is now CANCEL; this patch
-	  updates the test accordingly. ........ Merged revisions 425757
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: main/cdr: Use 'time' when rescheduling batched
-	  CDRs as opposed to 'size' When refactoring CDRs to use the
-	  configuration framework, a 'whoops' was introduced where the CDR
-	  batch size was used when rescheduling a batch, as opposed to the
-	  time duration. This patch corrects that obvious mistake.
-	  ASTERISK-24426 #close Reported by: Shane Blaser ........ Merged
-	  revisions 425735 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-16 17:30 +0000 [r425714]  George Joseph <george.joseph at fairview5.com>
-
-	* include/asterisk/config.h, tests/test_config.c, main/config.c, /:
-	  config: Fix inf loop using ast_category_browse and
-	  ast_variable_retrieve Fix infinite loop when calling
-	  ast_variable_retrieve inside an ast_category_browse loop when
-	  there is more than 1 category with the same name. Tested-by:
-	  George Joseph Review: https://reviewboard.asterisk.org/r/4089/
-	  ........ Merged revisions 425713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-16 14:35 +0000 [r425691]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip_t38.c, res/res_pjsip_registrar_expire.c,
-	  res/res_pjsip_mwi_body_generator.c,
-	  res/res_pjsip_endpoint_identifier_user.c,
-	  res/res_pjsip_send_to_voicemail.c,
-	  include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_outbound_authenticator_digest.c,
-	  res/res_pjsip_outbound_registration.c,
-	  res/res_pjsip_endpoint_identifier_anonymous.c,
-	  res/res_pjsip_path.c, res/res_pjsip_one_touch_record_info.c,
-	  res/res_pjsip_acl.c, res/res_pjsip_pubsub.c,
-	  res/res_pjsip_diversion.c, res/res_pjsip_refer.c,
-	  include/asterisk/res_pjsip.h,
-	  res/res_pjsip_pidf_body_generator.c, res/res_pjsip_dtmf_info.c,
-	  res/res_pjsip_multihomed.c, res/res_pjsip_authenticator_digest.c,
-	  res/res_pjsip_sdp_rtp.c, res/res_hep_pjsip.c,
-	  res/res_pjsip_messaging.c, res/res_pjsip_caller_id.c,
-	  res/res_pjsip_logger.c, res/res_pjsip_nat.c,
-	  res/res_pjsip_session.c, res/res_pjsip_exten_state.c,
-	  res/res_pjsip_header_funcs.c, res/res_pjsip_rfc3326.c,
-	  res/res_pjsip_phoneprov_provider.c, res/res_pjsip_mwi.c,
-	  res/res_pjsip_dialog_info_body_generator.c,
-	  res/res_pjsip_xpidf_body_generator.c, res/res_pjsip_registrar.c,
-	  channels/chan_pjsip.c, res/res_pjsip_transport_websocket.c,
-	  res/res_pjsip_pidf_eyebeam_body_supplement.c,
-	  include/asterisk/res_pjsip_session.h, /, res/res_pjsip_notify.c,
-	  res/res_pjsip_pidf_digium_body_supplement.c,
-	  res/res_pjsip_endpoint_identifier_ip.c,
-	  res/res_pjsip_publish_asterisk.c: PJSIP: Enforce module load
-	  dependencies This enforces that res_pjsip, res_pjsip_session, and
-	  res_pjsip_pubsub have loaded properly before attempting to load
-	  any modules that depend on them since the module loader system is
-	  not currently capable of resolving module dependencies on its
-	  own. ASTERISK-24312 #close Reported by: Dafi Ni Review:
-	  https://reviewboard.asterisk.org/r/4062/ ........ Merged
-	  revisions 425690 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-16 06:11 +0000 [r425669]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
-
-	* channels/chan_unistim.c, /: Fix loss of voice after second call
-	  drops (on a second line) in case using multiple lines on unistim
-	  phones. There is regression was introduced in r391379. Reported
-	  by: Rustam Khankishyiev (closes issue ASTERISK-23846) ........
-	  Merged revisions 425667 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425668 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  That scheduler ID is on the RTP instance. After 60a9172d7ef2 was merged to
+	  fix the regression introduced by 3cf0f29310, this improper assignment on a
+	  potentially destroyed object started getting tripped on the build agents.
 
-2014-10-16 01:25 +0000 [r425646]  Joshua Colp <jcolp at digium.com>
+	  Frankly, this should have been crashing a lot more often earlier. I can only
+	  assume that the timing was changed just enough by both changes to start
+	  actually hitting this problem.
 
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix a bug where ICE
-	  state would get reset when it shouldn't. In the case where the
-	  ICE negotiation had not yet started current state would get wiped
-	  when it shouldn't. This also removes channel binding as in
-	  practice this does not work well with other implementations.
-	  ........ Merged revisions 425644 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425645 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  As it is, simply moving the assignment prior to the ao2 deference is sufficient
+	  to keep the RTP instance from being referenced when it is very, truly,
+	  aboslutely dead.
 
-2014-10-15 19:31 +0000 [r425627]  Richard Mudgett <rmudgett at digium.com>
+	  (Note that it is still good practice to assign -1 to the scheduler ID when we
+	  know we won't be scheduling it again, as the ao2 deref *may* not always destroy
+	  the ao2 object.)
 
-	* channels/chan_motif.c: chan_motif: Cleanup
-	  jingle_tech.capabilities only once.
+	  ASTERISK-25449
 
-2014-10-15 19:05 +0000 [r425611]  Jonathan Rose <jrose at digium.com>
+	  Change-Id: Ie6d3cb4adc7b1a6c078b1c38c19fc84cf787cda7
 
-	* res/parking/parking_tests.c: parking_tests: Fix assertions and
-	  possibly crashes in res_parking unit tests Assertions were caused
-	  by attempting to play music on hold to a channel with no formats.
-	  Parking unit test channels were given formats and a technology so
-	  that they would be able to pretend to read/write frames.
-	  ASTERISK-24413 #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/4075/
+2015-09-30 13:42 +0000 [72d3a65706]  Joshua Colp <jcolp at digium.com>
 
-2014-10-15 09:59 +0000 [r425590]  Alexandr Anikin <may at telecom-service.ru>
+	* res_rtp_asterisk: Move "Set role" warning to be debug.
 
-	* addons/chan_ooh323.c, /: chan_ooh323: fix rtptimeout general
-	  value checking correct condition to check rtptimeout in [general]
-	  config section ASTERISK-24393 #close Reported by: Dmitry Melekhov
-	  Tested by: Dmitry Melekhov Patches: ASTERISK-24393.patch ........
-	  Merged revisions 425547 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425548 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425589 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 20:46 +0000 [r425526]  George Joseph <george.joseph at fairview5.com>
-
-	* /, include/asterisk/config.h, tests/test_config.c, main/config.c:
-	  config: Fix SEGV in unit test with MALLOC_DEBUG With MALLOC_DEBUG
-	  the /main/config config_basic_ops test was causing a SEGV while
-	  doing an ast_category_delete in an ast_category_browse loop.
-	  Apparently this never worked but was also never tested. I removed
-	  the test, added 2 notes to config.h indicating that it's not
-	  supported and added a few lines of code to ast_category_delete to
-	  prevent the SEGV should someone attempt it in the future.
-	  Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4078/ ........ Merged
-	  revisions 425525 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 19:00 +0000 [r425504]  Jonathan Rose <jrose at digium.com>
-
-	* main/sched.c, /: Scheduler: Fix a nasty scheduler caching bug
-	  which makes new tasks not execute Tasks that were marked for
-	  pending deletion in the scheduler would be moved to the cache for
-	  later reuse, but after being recycled the deleted mark wouldn't
-	  be removed resulting in fresh tasks being deleted without
-	  reason... and immediately moved back into the cache where they
-	  could be reused again. This could cause horrendous things to
-	  happen in just about anything that used a scheduler.
-	  ASTERISK-24321 #close Reported by: Steve Pitts Review:
-	  https://reviewboard.asterisk.org/r/4071/ ........ Merged
-	  revisions 425503 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 18:12 +0000 [r425481]  George Joseph <george.joseph at fairview5.com>
-
-	* res/res_phoneprov.c, include/asterisk/phoneprov.h, /,
-	  res/res_pjsip_phoneprov_provider.c: res_phoneprov: Create
-	  accessor for ast_phoneprov_std_variable_lookup Based on feedback
-	  from Richard, I created an accessor for
-	  res_phoneprov/ast_phoneprov_std_variable_lookup and added load
-	  priority to AST_MODULE_INFO. Tested-by: George Joseph Tested-by:
-	  Richard Mudgett Review: https://reviewboard.asterisk.org/r/4076/
-	  ........ Merged revisions 425480 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 16:46 +0000 [r425459]  Corey Farrell <git at cfware.com>
-
-	* /, res/res_fax.c: res_fax: Fix reference leak caused by gateway
-	  sessions Fax gateway session objects can be re-used, causing the
-	  same gateway session to be added to faxregistry.container more
-	  than once. This change causes fax_session_new to remove the
-	  reserved session from the container before it's id is changed,
-	  ensuring it's possible for the session to be freed.
-	  ASTERISK-24392 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4049/ ........ Merged
-	  revisions 425457 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 16:35 +0000 [r425455]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/stasis_channels.c: stasis_channels.c: Resolve unfinished
-	  Dials when doing masquerades (Part 2) Masquerades into and out of
-	  channels that are involved in a dial operation don't create the
-	  expected dial end event. The missing dial end event goes against
-	  the model for things like CDRs and generating Dial end manager
-	  actions and such. There are four cases: 1) A channel masquerades
-	  into the caller channel. The case happens when performing a
-	  blonde transfer using the channel driver's protocol. 2) A channel
-	  masquerades into a callee channel. The case happens when
-	  performing a directed call pickup. 3) The caller channel
-	  masquerades out of dial. The case happens when using the Bridge
-	  application on the caller channel. 4) A callee channel
-	  masquerades out of dial. The case happens when using the Bridge
-	  application on a peer channel. As it turned out, all four cases
-	  need to be handled instead of just the first one. ASTERISK-24237
-	  Reported by: Richard Mudgett ASTERISK-24394 #close Reported by:
-	  Richard Mudgett Review: https://reviewboard.asterisk.org/r/4066/
-	  ........ Merged revisions 425430 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-14 16:19 +0000 [r425415]  Corey Farrell <git at cfware.com>
+	  In practice the set_role API callback can be invoked even
+	  when no ICE is present on an RTP instance. This can occur
+	  if ICE has not been enabled on it.
 
-	* /, res/res_fax.c: res_fax: Resolve module reference leak caused
-	  by reserved sessions Remove reference to module providing
-	  reserved session after adding a reference to the final module.
-	  This re-reference is done to ensure that module references are
-	  correct even if the final session selects a different module than
-	  the reserved session. ASTERISK-18923 #close Reported by: Grigoriy
-	  Puzankin Review: https://reviewboard.asterisk.org/r/4048/
-	  ........ Merged revisions 425405 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425407 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425411 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-13 16:10 +0000 [r425384]  George Joseph <george.joseph at fairview5.com>
-
-	* apps/app_directory.c, tests/test_sorcery.c, main/config.c,
-	  tests/test_sorcery_realtime.c, res/res_sorcery_realtime.c,
-	  apps/app_voicemail.c, res/res_sorcery_config.c, main/manager.c,
-	  /, include/asterisk/config.h, pbx/pbx_realtime.c,
-	  tests/test_config.c: manager/config: Support templates and
-	  non-unique category names via AMI This patch provides the
-	  capability to manipulate templates and categories with non-unique
-	  names via AMI. Summary of changes: GetConfig and GetConfigJSON:
-	  Added "Filter" parameter: A comma separated list of
-	  name_regex=value_regex expressions which will cause only
-	  categories whose variables match all expressions to be
-	  considered. The special variable name TEMPLATES can be used to
-	  control whether templates are included. Passing 'include' as the
-	  value will include templates along with normal categories.
-	  Passing 'restrict' as the value will restrict the operation to
-	  ONLY templates. Not specifying a TEMPLATES expression results in
-	  the current default behavior which is to not include templates.
-	  UpdateConfig: NewCat now includes options for allowing duplicate
-	  category names, indicating if the category should be created as a
-	  template, and specifying templates the category should inherit
-	  from. The rest of the actions now accept a filter string as
-	  defined above. If there are non-unique category names, you can
-	  now update specific ones based on variable values. To facilitate
-	  the new capabilities in manager, corresponding changes had to be
-	  made to config, most notably the addition of filter criteria to
-	  many of the APIs. In some cases it was easy to change the
-	  references to use the new prototype but others would have
-	  required touching too many files for this patch so a wrapper with
-	  the original prototype was created. Macros couldn't be used in
-	  this case because it would break binary compatibility with
-	  modules such as res_digium_phone that are linked to real symbols.
-	  Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4033/ ........ Merged
-	  revisions 425383 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25438 #close
 
-2014-10-12 21:09 +0000 [r425362]  Joshua Colp <jcolp at digium.com>
+	  Change-Id: I0e17e4316f0f0d7f095c78c3d4fd73a913b6ba69
+	  (cherry picked from commit fa0985851aba9bc8ca234b66cd47c50e45eae61f)
 
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Make the ICE
-	  transport check case insensitive as some implementations use
-	  'udp'. ........ Merged revisions 425360 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425361 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-05 21:34 +0000 [33c945f471]  Matt Jordan <mjordan at digium.com>
 
-2014-10-12 08:15 +0000 [r425289-425299]  Walter Doekes <walter+asterisk at wjd.nu>
+	* Fix improper usage of scheduler exposed by 5c713fdf18f
 
-	* /, channels/chan_sip.c: chan_sip: Fix so asterisk won't send
-	  reINVITE after a BYE. After a reINVITE glare situation, Asterisk
-	  would re-send the reINVITE even though the call had been hung up
-	  in the mean time. This patch unschedules the reinvite when
-	  handling the BYE. ASTERISK-22791 #close Reported by: Paolo
-	  Compagnini Tested by: Paolo Compagnini Review:
-	  https://reviewboard.asterisk.org/r/4056/ (testcase is in review
-	  r4055) ........ Merged revisions 425296 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425297 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425298 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  When 5c713fdf18f was merged, it allowed for scheduled items to have an ID of
+	  '0' returned. While this was valid per the documentation for the API, it was
+	  apparently never returned previously. As a result, several users of the
+	  scheduler API viewed the result as being invalid, causing them to reschedule
+	  already scheduled items or otherwise fail in interesting ways.
 
-	* /, Makefile: build: Relax badshell tilde test to allow for ~ in
-	  middle of DESTDIR. The main Makefile has a target test called
-	  'badshell' that tests if DESTDIR does not happen to have an
-	  an-expanded tilde (~). This might be the case if you run: make
-	  install DESTDIR=~/somewhere/ That test also disallowed valid
-	  tildes in directory names. The test is now changed to only
-	  trigger on a tilde at the start of the path. ASTERISK-13797
-	  #close Reported by: Tzafrir Cohen Review:
-	  https://reviewboard.asterisk.org/r/4064/ ........ Merged
-	  revisions 425291 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425292 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425293 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This patch corrects the users such that they view '0' as valid, and a returned
+	  ID of -1 as being invalid.
 
-	* /, res/res_calendar_ews.c: res_calendar_ews: Relax neon version
-	  check to work with 0.30 too. Allow res_calendar_ews to work not
-	  only with libneon-0.29 but also with 0.30. ASTERISK-24325 #close
-	  Reported by: Tzafrir Cohen Review:
-	  https://reviewboard.asterisk.org/r/4068/ ........ Merged
-	  revisions 425286 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425287 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425288 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-11 21:08 +0000 [r425265]  George Joseph <george.joseph at fairview5.com>
-
-	* /, res/res_phoneprov.c: res_phoneprov: Cleanup module load error
-	  handling Tested module load/reload interaction between
-	  res_phoneprov and res_pjsip_phoneprov_provider in cases where
-	  res_phoneprov didn't load correctly (usually misconfiguration or
-	  missing phoneprov.conf) Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/4069/ ........ Merged
-	  revisions 425264 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-10 20:48 +0000 [r425243]  Joshua Colp <jcolp at digium.com>
-
-	* /, main/bridge.c, bridges/bridge_native_rtp.c: bridge: During a
-	  smart bridge operation provide a more complete bridge to the old
-	  technology. When a smart bridge operation occurs and a bridge
-	  transitions from one technology to another the old technology is
-	  provided the channels formerly in it and told that they are
-	  leaving. Unfortunately the bridge provided along with them is
-	  incomplete. The bridge, despite there being channels in it,
-	  contains none. This forces technology implementations to have
-	  additional logic when channels are leaving or to store their own
-	  duplicated state. This change makes the bridge more complete so
-	  it contains the expected channels. Now that the bridge is
-	  complete special logic within bridge_native_rtp is no longer
-	  needed and has been removed. Review:
-	  https://reviewboard.asterisk.org/r/4057/ ........ Merged
-	  revisions 425242 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-10 14:31 +0000 [r425221]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_phoneprov.c: res/res_phoneprov: Bail on registration
-	  if res_phoneprov didn't load If res_phoneprov failed to fully
-	  load (due to not being configured), the providers container will
-	  be NULL. If a module attempts to register a phone provisioning
-	  provider, it should check for the presence of the container. If
-	  there is no providers container, it should return an error. This
-	  patch makes the ast_phoneprov_provider_register function do
-	  that... otherwise this would be a silly commit message. ........
-	  Merged revisions 425220 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-10 14:23 +0000 [r425217]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_phoneprov_provider.c:
-	  res_pjsip_phoneprov_provider: Add missing dependency on
-	  pjproject. ........ Merged revisions 425216 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-10 13:01 +0000 [r425155]  Kinsey Moore <kmoore at digium.com>
+	  Note that the failing HEP RTCP tests now pass with this patch. These tests
+	  failed due to a duplicate scheduling of the RTCP transmissions.
 
-	* /, tests/test_callerid.c, main/callerid.c: CallerID: Fix parsing
-	  regression This fixes a regression in callerid parsing introduced
-	  when another bug was fixed. This bug occurred when the name was
-	  composed entirely of DTMF keys and quoted without a number
-	  section (<>). ASTERISK-24406 #close Reported by: Etienne Lessard
-	  Tested by: Etienne Lessard Patches: callerid_fix.diff uploaded by
-	  Kinsey Moore Review: https://reviewboard.asterisk.org/r/4067/
-	  ........ Merged revisions 425152 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425153 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425154 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25449 #close
 
-2014-10-10 12:10 +0000 [r425132]  Joshua Colp <jcolp at digium.com>
+	  Change-Id: I019a9aa8b6997584f66876331675981ac9e07e39
 
-	* res/res_pjsip_nat.c, /: res_pjsip_nat: Place source port into
-	  rport of responses if 'force_rport' is on. When the 'force_rport'
-	  option is enabled the behavior should be the same as if the
-	  remote side placed rport into the message themselves. Therefore
-	  any responses we send should include the source port of the
-	  request in the rport of the Via header. #SIPit31 ASTERISK-24387
-	  #close Reported by: Matt Jordan ........ Merged revisions 425131
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-06 18:09 +0000  Asterisk Development Team <asteriskteam at digium.com>
 
-2014-10-10 07:32 +0000 [r425071]  Walter Doekes <walter+asterisk at wjd.nu>
+	* asterisk 11.20.0-rc2 Released.
 
-	* /, channels/chan_sip.c: chan_sip: Fix dialog leak resulting from
-	  missing ACK to re-INVITE. If a device re-INVITEs at the same time
-	  as the dialog is hung up, and if then the ACK to the re-INVITE
-	  never reaches Asterisk, chan_sip would fail to destroy the dialog
-	  after a while. This resulted in (most prominently) file handle
-	  leaks. (Patch reindented by me.) ASTERISK-20784 #close
-	  ASTERISK-15879 #close Reported by: Torrey Searle, Nitesh Bansal
-	  Patches: reinvite_ack_timeout.patch uploaded by Torrey Searle
-	  (License #5334) patch_asterisk_20784.txt uploaded by Nitesh
-	  Bansal (License #6418) Reviewboard:
-	  https://reviewboard.asterisk.org/r/4052/ (testcase can be found
-	  at r4051) ........ Merged revisions 425068 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 425069 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 425070 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 23:35 +0000 [r425052]  George Joseph <george.joseph at fairview5.com>
-
-	* res/res_pjsip_phoneprov_provider.c: res_pjsip_phoneprov_provider:
-	  fix compile breakage on AST_VECTOR endpoint->inbound_auths was
-	  changed to a vector in 13 and I committed the 12 patch instead of
-	  the 13 patch. Tested-by: George Joseph
-
-2014-10-09 21:38 +0000 [r425031]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Crash if no
-	  candidates received for component When starting ice if there is
-	  not at least one remote ice candidate with an RTP component
-	  asterisk will crash. This is due to an assertion in pjnath as it
-	  expects at least one candidate with an RTP component. Added a
-	  check to make sure at least one candidate contains an RTP
-	  component and at least one candidate has an RTCP component.
-	  ASTERISK-24383 #close Review:
-	  https://reviewboard.asterisk.org/r/4039/ ........ Merged
-	  revisions 425030 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 20:54 +0000 [r425008]  George Joseph <george.joseph at fairview5.com>
-
-	* /, res/res_pjsip_phoneprov_provider.c (added),
-	  configs/samples/pjsip.conf.sample: res_pjsip_phoneprov_provider:
-	  Provides pjsip integration with res_phoneprov This module allows
-	  res_pjsip to integrate with res_phoneprov. It handles the pjsip
-	  'phoneprov' object type. Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3976/ ........ Merged
-	  revisions 425007 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 18:37 +0000 [r424986]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_phoneprov.c: res/res_phoneprov: Don't cancel Asterisk
-	  load on module load failure ........ Merged revisions 424985 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 17:45 +0000 [r424964]  George Joseph <george.joseph at fairview5.com>
-
-	* include/asterisk/phoneprov.h (added), /,
-	  configs/samples/phoneprov.conf.sample,
-	  include/asterisk/chanvars.h, res/res_phoneprov.c,
-	  res/res_phoneprov.exports.in (added), main/chanvars.c:
-	  res_phoneprov: Refactor phoneprov to allow pluggable config
-	  providers This patch makes res_phoneprov more modular so other
-	  modules (like pjsip) can provide configuration information
-	  instead of res_phoneprov relying solely on users.conf and
-	  sip.conf. To accomplish this a new ast_phoneprov public API is
-	  now exposed which allows config providers to register themselves,
-	  set defaults (server profile, etc) and add user extensions. *
-	  ast_phoneprov_provider_register registers the provider and
-	  provides callbacks for loading default settings and loading
-	  users. * ast_phoneprov_provider_unregister clears the defaults
-	  and users. * ast_phoneprov_add_extension should be called once
-	  for each user/extension by the provider's load_users callback to
-	  add them. * ast_phoneprov_delete_extension deletes one extension.
-	  * ast_phoneprov_delete_extensions deletes all extensions for the
-	  provider. Tested-by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3970/ ........ Merged
-	  revisions 424963 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 16:36 +0000 [r424942]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/cdr.c: cdr.c: Make turning on CDR debug a one step
-	  process instead of two. Now "cdr set debug on" doesn't also
-	  require "core set verbose 1" to see CDR debug output. ........
-	  Merged revisions 424941 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-09 08:08 +0000 [r424880]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /, contrib/scripts/safe_asterisk: safe_asterisk: Don't
-	  automatically exceed MAXFILES value of 2^20. On systems with lots
-	  of RAM (e.g. 24GB) /proc/sys/fs/file-max divided by two can
-	  exceed the per-process file limit of 2^20. This patch ensures the
-	  value is capped. (Patch cleaned up by me.) ASTERISK-24011 #close
-	  Reported by: Michael Myles Patches: safe_asterisk-ulimit.diff
-	  uploaded by Michael Myles (License #6626) ........ Merged
-	  revisions 424875 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 424878 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424879 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-06 13:08 +0000 [967e8ac5a9]  Kevin Harwell <kharwell at lunkwill>
 
-2014-10-08 18:46 +0000 [r424854]  Joshua Colp <jcolp at digium.com>
+	* Release summaries: Add summaries for 11.20.0-rc2
 
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Allow only UDP ICE
-	  candidates. The underlying library, pjnath, that res_rtp_asterisk
-	  uses for ICE support does not have support for ICE-TCP. As
-	  candidates are passed through directly to it this can cause error
-	  messages to occur when it receives something unexpected (such as
-	  a TCP candidate). This change merely ignores all non-UDP
-	  candidates so they never reach pjnath. ASTERISK-24326 #close
-	  Reported by: Joshua Colp ........ Merged revisions 424852 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424853 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-08 18:24 +0000 [r424769-424850]  Kinsey Moore <kmoore at digium.com>
-
-	* main/stasis.c: Stasis: Relegate log message to dev-mode This
-	  error message primarily applies to development tasks and will now
-	  only show up when dev-mode is enabled via configure.
-
-	* main/sounds_index.c: Indexer: Format message types may not exist
-	  In Asterisk 13+, any given message type is not guaranteed to
-	  exist even if Asterisk comes up correctly since creation of the
-	  message type could be declined. The indexer should not prevent
-	  Asterisk from starting under these conditions.
-
-	* main/stasis.c: Stasis: Only log errors for non-declined types
-	  When message type creation is declined via stasis.conf, certain
-	  operations log errors assuming that the declined type is being
-	  used before initialization or after destruction. These error
-	  messages get quite spammy for oft used message types and should
-	  not be logged in the first place since the message type is
-	  validly NULL. Reported by: Matt DiMeo
-
-2014-10-07 18:33 +0000 [r424752]  Joshua Colp <jcolp at digium.com>
-
-	* main/data.c: data: Properly access formats in capabilities
-	  structure when adding codecs. Formats within a capabilities
-	  structure are addressed starting at 0, not 1. Assuming 1 causes
-	  it to exceed an array. ASTERISK-24389 #close Reported by: Kevin
-	  Harwell
-
-2014-10-07 17:41 +0000 [r424692-424731]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_pjsip_outbound_registration.c:
-	  res/res_pjsip_outbound_registration: Initialize
-	  auth_reject_permanent parameter Prior to this patch, the
-	  auth_reject_permanent parameter was not initialized on the
-	  registration client state, leading to the parameter being
-	  disabled regardless of the value specified in pjsip.conf. This
-	  patch initialized the setting on the registration client state to
-	  the provided configuration value. ASTERISK-24398 #close ........
-	  Merged revisions 424730 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pubsub.c: res/res_pjsip_pubsub: Fix typo in WARNING
-	  message
-
-	* main/message.c, /: message: Don't close an AMI connection on
-	  SendMessage action error If SendMessage encounters an error (such
-	  as incorrect input provided to the action), it will currently
-	  return -1. Actions should only return -1 if the connection to the
-	  AMI client should be closed. In this case, SendMessage causing
-	  the client to disconnect is inappropriate. This patch causes the
-	  action to return 0, which simply causes the action to fail.
-	  Review: https://reviewboard.asterisk.org/r/4024 ASTERISK-24354
-	  #close Reported by: Peter Katzmann patches: sendMessage.patch
-	  uploaded by Peter Katzmann (License 5968) ........ Merged
-	  revisions 424690 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424691 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-06 15:38 +0000 [r424669]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/features.c, /: features.c: Fix lingering channel ref while
-	  Bridge() application is active. Using the Bridge application to
-	  bridge a channel that is executing an applicaiton such as Wait
-	  results in a lingering Surrogate channel in the CLI "core show
-	  channels" output even though it has already hungup. * Fix
-	  bridge_exec() to not hold onto the current_dest_chan ref once it
-	  has been put into the bridge. * Eliminated bridge_exec()'s use of
-	  RAII_VAR(). ASTERISK-24224 #close Reported by: Mark Michelson
-	  Review: https://reviewboard.asterisk.org/r/4041/ ........ Merged
-	  revisions 424668 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-06 12:38 +0000 [r424601-424647]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/sdp_srtp.c: sdp_srtp: Add new lines to some WARNING
-	  messages ........ Merged revisions 424646 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_options.c: res_pjsip/pjsip_options: Do not
-	  404 an OPTIONS request not sent to an endpoint An OPTIONS request
-	  that is sent to Asterisk but not to a specific endpoint is
-	  currently sent a 404 in response. This is because, not
-	  surprisingly, an empty extension is never going to be found in
-	  the dialplan. This patch makes it so that we only attempt to look
-	  up the endpoint in the dialplan if it is specified in the OPTIONS
-	  request URI. #SIPit31 ASTERISK-24370 #close Reported by: Matt
-	  Jordan ........ Merged revisions 424624 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/pjsip/dialplan_functions.c, /: pjsip/dialplan_functions:
-	  Handle PJSIP_MEDIA_OFFER called on non-PJSIP channels Calling
-	  PJSIP_MEDIA_OFFER on a non-PJSIP channel is hazardous to your
-	  health. It will treat the channels as a PJSIP channel, eventually
-	  hitting an ao2 error, FRACKing on assertion error, and quite
-	  likely crashing. This patch adds checks to the read/write
-	  callbacks that ensure that the channel technology is of type
-	  'PJSIP' before attempting to operate on the channel. #SIPit31
-	  ASTERISK-24382 #close Reported by: Matt Jordan ........ Merged
-	  revisions 424621 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_hep_pjsip.c, res/res_pjsip/pjsip_distributor.c,
-	  res/res_pjsip_logger.c: res_pjsip: Prevent crashes when PJPROJECT
-	  presents an rdata with no message When a message that exceeds the
-	  PJ_MAX_PKT_SIZE is sent over a reliable transport, it is possible
-	  (although it shouldn't occur) for pjproject to pass up an rdata
-	  object with a NULL msg in the msg_info. Needless to say, things
-	  that attempt to dereference this are in for a rough ride. In
-	  particular, this caused crashes in three different locations, all
-	  of which are 'low level' enough to intercept an rdata object
-	  early in processing: (1) res_pjsip_logger (2) res_hep_pjsip (3)
-	  res_pjsip/distributor Anything that can intercept an rdata object
-	  before res_pjsip/distributor should be defensive when looking at
-	  the received packet. #SIPit31 ASTERISK-24369 #close Reported by:
-	  Matt Jordan ........ Merged revisions 424618 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pubsub.c: res/res_pjsip_pubsub: Gracefully handle
-	  errors when re-creating subscriptions A subscription that has
-	  been persisted can - for various reasons - fail to be re-created
-	  on startup. This patch resolves a number of crashes that occurred
-	  when a subscription cannot be re-created on several off-nominal
-	  paths. #SIPit31 ASTERISK-24368 #close Reported by: Matt Jordan
-
-2014-10-05 00:48 +0000 [r424552-424580]  Corey Farrell <git at cfware.com>
-
-	* main/manager.c, /: Release AMI connections on shutdown.
-	  ASTERISK-24378 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4037/ ........ Merged
-	  revisions 424578 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_motif.c: chan_motif: Correct last commit to use
-	  ao2_cleanup to free format cap This fix applies to 13 and trunk.
-	  ASTERISK-24384 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4043/
+2015-10-06 13:08 +0000 [41af944b79]  Kevin Harwell <kharwell at lunkwill.digium.internal>
 
-	* /, channels/chan_motif.c: chan_motif: Release format capabilities
-	  and config on module load error ASTERISK-24384 #close Reported
-	  by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/4043/ ........ Merged
-	  revisions 424550 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424551 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-03 21:56 +0000 [r424472-424529]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, CHANGES, res/res_pjsip.c: res_pjsip: Fix XML typo and update
-	  CHANGES. ASTERISK-24199 ........ Merged revisions 424528 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/audiohook.c, apps/app_chanspy.c, apps/app_mixmonitor.c, /,
-	  main/framehook.c: audiohooks: Reevaluate the bridge technology
-	  when an audiohook is added or removed. Adding a mixmonitor to a
-	  channel causes the bridge to change technologies from native to
-	  simple_bridge so the call can be recorded. However, when the
-	  mixmonitor is stopped the bridge does not switch back to the
-	  native technology. * Added unbridge requests to reevaluate the
-	  bridge when a channel audiohook is removed. * Moved the unbridge
-	  request into ast_audiohook_attach() ensure that the bridge
-	  reevaluates whenever an audiohook is attached. This simplified
-	  the mixmonitor and chan_spy start code as well. * Added defensive
-	  code to stop_mixmonitor_full() in case additional arguments are
-	  ever added to the StopMixMonitor application. * Made
-	  ast_framehook_detach() not do an unbridge request if the
-	  framehook does not exist. * Made ast_framehook_list_fixup() do an
-	  unbridge request if there are any framehooks. Also simplified the
-	  loop. ASTERISK-24195 #close Reported by: Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/4046/ ........ Merged
-	  revisions 424506 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/core_unreal.c, main/taskprocessor.c, channels/chan_iax2.c,
-	  res/res_pjsip_session.c, main/channel.c, channels/chan_misdn.c,
-	  channels/chan_skinny.c, funcs/func_frame_trace.c,
-	  channels/chan_motif.c, include/asterisk/frame.h,
-	  main/bridge_channel.c, channels/chan_pjsip.c,
-	  channels/chan_unistim.c, include/asterisk/res_pjsip_session.h,
-	  addons/chan_ooh323.c, /, include/asterisk/taskprocessor.h,
-	  channels/chan_sip.c, res/res_pjsip_session.exports.in:
-	  chan_pjsip: Fix deadlock when masquerading PJSIP channels.
-	  Performing a directed call pickup resulted in a deadlock when
-	  PJSIP channels were involved. A masquerade needs to hold onto the
-	  channel locks while it swaps channel information between the two
-	  channels involved in the masquerade. With PJSIP channels, the
-	  fixup routine needed to push a fixup task onto the PJSIP
-	  channel's serializer. Unfortunately, if the serializer was also
-	  processing a task that needed to lock the channel, you get
-	  deadlock. * Added a new control frame that is used to notify the
-	  channels that a masquerade is about to start and when it has
-	  completed. * Added the ability to query taskprocessors if the
-	  current thread is the taskprocessor thread. * Added the ability
-	  to suspend/unsuspend the PJSIP serializer thread so a masquerade
-	  could fixup the PJSIP channel without using the serializer.
-	  ASTERISK-24356 #close Reported by: rmudgett Review:
-	  https://reviewboard.asterisk.org/r/4034/ ........ Merged
-	  revisions 424471 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-03 15:54 +0000 [r424448]  George Joseph <george.joseph at fairview5.com>
-
-	* /, main/sorcery.c: sorcery: Prevent SEGV in sorcery_wizard_create
-	  when there's no create function When you call
-	  ast_sorcery_create() you don't necessarily know which wizard is
-	  going to be invoked. If it happens to be a wizard like 'config'
-	  that doesn't have a 'create' virtual function you get a segfault
-	  in the sorcery_wizard_create callback. This patch catches the
-	  null function pointer, does an ast_assert, and logs an error.
-	  Review: https://reviewboard.asterisk.org/r/4044/ ........ Merged
-	  revisions 424447 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-03 13:58 +0000 [r424424-424427]  Kinsey Moore <kmoore at digium.com>
-
-	* configs/samples/pjsip.conf.sample, /,
-	  res/res_pjsip/pjsip_configuration.c: PJSIP: Restore functional
-	  default for callerid_privacy The pjsip config option default
-	  fixups from r424263 altered the functional default from
-	  "allowed_not_screened" to "allowed". This change restores the
-	  functional default value when none is provided. ........ Merged
-	  revisions 424426 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /: Manager: Add missing fields and documentation
-	  for CoreShowChannels This corrects some issues introduced in the
-	  responses to the CoreShowChannels AMI command as well as adding
-	  documentation for the responses. The command in Asterisk 12 was
-	  missing the following fields: Duration, Application,
-	  ApplicationData, and BridgedChannel and BridgedUniqueID (replaced
-	  with BridgeId). ASTERISK-24262 #close Reported by: Mitch Claborn
-	  Review: https://reviewboard.asterisk.org/r/4040/ ........ Merged
-	  revisions 424423 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-03 07:54 +0000 [r424415]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Reduce SDP size by
-	  removing duplicate connection lines. Due to the architecture of
-	  how media streams are handled each individual handler adds
-	  connection details (IP address) for it. The first media stream is
-	  then used as the top level SDP connection line. In practice each
-	  line ends up being the same so to reduce the SDP size
-	  stream-level connection information is also added to the SDP if
-	  it differs from the top level SDP connection line. ........
-	  Merged revisions 424414 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-02 21:52 +0000 [r424394]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, configs/samples/pjsip.conf.sample, res/res_pjsip.c,
-	  res/res_pjsip/config_transport.c: res_pjsip: Make transport
-	  cipher option accept a comma separated list of cipher names.
-	  Improvements to the res_pjsip transport cipher option. * Made the
-	  cipher option accept a comma separated list of OpenSSL cipher
-	  names. Users of realtime will be glad if they have more than one
-	  name to list. * Added the CLI command 'pjsip list ciphers' so a
-	  user can know what OpenSSL names are available for the cipher
-	  option. * Updated the cipher option online XML documentation to
-	  specify what is expected for the value. * Updated
-	  pjsip.conf.sample to not indicate that ALL is acceptable since
-	  ALL does not imply a preference order for the ciphers and PJSIP
-	  does not simply pass the string to OpenSSL for interpretation.
-	  ASTERISK-24199 #close Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/4018/ ........ Merged
-	  revisions 424393 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-02 20:15 +0000 [r424373]  Jonathan Rose <jrose at digium.com>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
-	  (added): Alembic: Add enumerator value to sippeers -> directmedia
-	  - 'outgoing' The 'outgoing' value was left off of the enumerator
-	  when first creating the column. This patch adds it, and should
-	  gracefully upgrade keeping the existing data in tact.
-	  ASTERISK-23781 #close Reported by: Stephen More Review:
-	  https://reviewboard.asterisk.org/r/4013/ ........ Merged
-	  revisions 424372 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-02 13:35 +0000 [r424338]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, configs/samples/pjsip.conf.sample: res_pjsip: document use of
-	  rewrite_contact in sample conf Without setting rewrite_contact,
-	  an invite to an endpoint behind NAT will not reach it - unless
-	  the endpoint itself uses STUN or TURN to discover it's public
-	  URI. Thus, the use of this should be in the sample documentation.
-	  Review: https://reviewboard.asterisk.org/r/4036/ ........ Merged
-	  revisions 424337 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-01 22:52 +0000 [r424333]  Jonathan Rose <jrose at digium.com>
-
-	* channels/chan_pjsip.c: chan_pjsip: Fix an assertion for channels
-	  that lack formats on creation ASTERISK-24222 #close Reported by:
-	  Mark Michelson Review: https://reviewboard.asterisk.org/r/4017/
-
-2014-10-01 20:36 +0000 [r424313]  Corey Farrell <git at cfware.com>
-
-	* res/res_hep.c, /: res_hep: Release allocation reference to
-	  configuration. ASTERISK-24362 #close Reported by: Corey Farrell
-	  Review: https://reviewboard.asterisk.org/r/4026/ ........ Merged
-	  revisions 424312 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-01 16:37 +0000 [r424288-424291]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/pjsip_configuration.c,
-	  configs/samples/pjsip.conf.sample, res/res_pjsip.c: res_pjsip:
-	  Add 'dtls_fingerprint' option to configure DTLS fingerprint hash.
-	  During the latest update to DTLS-SRTP support the ability to
-	  configure the hash used for fingerprints was added. This gave us
-	  two supported ones: SHA-1 and SHA-256. The default was
-	  accordingly updated to SHA-256. Unfortunately this configuration
-	  ability was not exposed within res_pjsip. This change adds a
-	  dtls_fingerprint option that controls it. #SIPit31 ........
-	  Merged revisions 424290 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_sdp_rtp.c: res_pjsip_sdp_rtp: Accept DTLS
-	  attributes in top level, not just media session. #SIPit31
-	  ........ Merged revisions 424287 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-01 12:27 +0000 [r424245-424266]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip/config_transport.c, /, res/res_pjsip/location.c,
-	  res/res_pjsip_endpoint_identifier_ip.c,
-	  res/res_pjsip/pjsip_configuration.c,
-	  configs/samples/pjsip.conf.sample: PJSIP: Handle defaults
-	  properly This updates the code behind PJSIP configuration options
-	  with custom handlers to deal with the assigned default values
-	  properly where it makes sense and adjusting the default value
-	  where it doesn't. Before applying this patch, there were several
-	  cases where the default value for an option would prevent that
-	  config section from loading properly. Reported by: Thomas
-	  Thompson Review: https://reviewboard.asterisk.org/r/4019/
-	  ........ Merged revisions 424263 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_nat.c: PJSIP: Force transport on contact rewrite
-	  If contact rewriting is enabled but the contact differs in
-	  transport from what is actually being used, messages after the
-	  initial INVITE transaction can be sent to an incorrect
-	  transport/port combination. In the case where this bug occurred
-	  the remote party never received a BYE since it was sent to the
-	  remote party's TCP port over UDP. Review:
-	  https://reviewboard.asterisk.org/r/4032/ ........ Merged
-	  revisions 424244 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-10-01 10:09 +0000 [r424179-424184]  Walter Doekes <walter+asterisk at wjd.nu>
+	* Release summaries: Remove previous versions
 
-	* /, channels/chan_sip.c: chan_sip: Simplify some unref code by
-	  removing unlink_peer_from_tables. ASTERISK-22945 #related
-	  Reported by: ibercom Patches:
-	  asterisk11-chan_sip-simplifies.patch uploaded by ibercom (License
-	  #6599) ........ Merged revisions 424181 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 424182 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424183 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-06 13:08 +0000 [0c43fbfe03]  Kevin Harwell <kharwell at lunkwill>
 
-	* /, channels/chan_sip.c: chan_sip: Remove excess ref of realtime
-	  peer before sip_poke_peer. The peer is referenced at the end of
-	  sip_poke_peer, it should not get an extra ref before the call to
-	  sip_poke_peer. This fixes a memory leak. ASTERISK-22945 #close
-	  Reported by: ibercom Tested by: Yuriy Gorlichenko Patches:
-	  asterisk11.patch uploaded by ibercom (License #6599) Review:
-	  https://reviewboard.asterisk.org/r/4031/ ........ Merged
-	  revisions 424176 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 424177 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424178 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* .version: Update for 11.20.0-rc2
 
-2014-09-30 11:40 +0000 [r424153-424156]  Joshua Colp <jcolp at digium.com>
+2015-10-06 13:08 +0000 [6cc9188f58]  Kevin Harwell <kharwell at lunkwill>
 
-	* res/res_pjsip_sdp_rtp.c, /: res_pjsip_sdp_rtp: Don't place an
-	  extra whitespace before 'rport' and don't put IPv6 addresses in
-	  brackets. #SIPit31 ........ Merged revisions 424155 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* .lastclean: Update for 11.20.0-rc2
 
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Ensure that the base
-	  and mapped address for candidates is present in SDP. This change
-	  fixes an issue where ICE candidates put into the SDP did not
-	  contain the 'raddr' and 'rport' information for server reflexive
-	  and relay candidates. #SIPit31 ........ Merged revisions 424151
-	  from http://svn.asterisk.org/svn/asterisk/branches/11 ........
-	  Merged revisions 424152 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-10-05 21:34 +0000 [60a9172d7e]  Matt Jordan <mjordan at digium.com>
 
-2014-09-29 21:59 +0000 [r424129]  George Joseph <george.joseph at fairview5.com>
+	* Fix improper usage of scheduler exposed by 5c713fdf18f
 
-	* /, res/res_pjsip/pjsip_cli.c: pjsip_cli: Suppress header print on
-	  error or no objects If there's an error on the pjsip command line
-	  or there are no objects, don't print the column headers.
-	  ASTERISK-24350 #close Reported-by: Brad Latus Tested-by: George
-	  Joseph Tested-by: Brad Latus Review:
-	  https://reviewboard.asterisk.org/r/4025/ ........ Merged
-	  revisions 424128 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  When 5c713fdf18f was merged, it allowed for scheduled items to have an ID of
+	  '0' returned. While this was valid per the documentation for the API, it was
+	  apparently never returned previously. As a result, several users of the
+	  scheduler API viewed the result as being invalid, causing them to reschedule
+	  already scheduled items or otherwise fail in interesting ways.
 
-2014-09-29 21:26 +0000 [r424126]  Walter Doekes <walter+asterisk at wjd.nu>
+	  This patch corrects the users such that they view '0' as valid, and a returned
+	  ID of -1 as being invalid.
 
-	* /, contrib/scripts/autosupport: autosupport: Fix bashism. '==' is
-	  bashism (bashspecific, fails when dash is /bin/sh). Anyway, a
-	  'case' works better there. Originally committed in r375059 and
-	  r375060 on 2012-10-16 21:13:08. ASTERISK-20567 #close Reported
-	  by: Tzafrir Cohen ........ Merged revisions 424117 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 424125 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-29 21:17 +0000 [r424097-424105]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_pjsip.c, res/res_pjsip_pubsub.c, res/res_pjsip_session.c,
-	  /, res/res_pjsip_authenticator_digest.c: Simplify UUID generation
-	  in several places. Replace code using ast_uuid_generate() with
-	  simpler and faster code using ast_uuid_generate_str(). The new
-	  code avoids a malloc(), free(), and copy. ........ Merged
-	  revisions 424103 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/threadpool.c: threadpool.c: Minor cleanup fixes. * Fix
-	  threadpool_alloc() prototype. * Add missing off-nominal NULL
-	  check of pool in threadpool_alloc(). * searializer_create() does
-	  not need to create the object with a lock as the lock is not
-	  used. ........ Merged revisions 424096 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-27 12:43 +0000 [r424057]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_pjsip.c, res/res_pjsip_session.c, /:
-	  res_pjsip_session: Add additional checks for delaying session
-	  refreshes. There are certain situations which no checks existed
-	  for which need to prevent session refreshes. This includes
-	  sending a session refresh with SDP before SDP negotiation has
-	  completed and sending a session refresh before the dialog itself
-	  has been established. Checks for these have been added.
-	  Additionally COLP related UPDATEs were including SDP when it is
-	  not needed. Review: https://reviewboard.asterisk.org/r/4008/
-	  ........ Merged revisions 424056 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-26 15:21 +0000 [r423992]  Richard Mudgett <rmudgett at digium.com>
+	  Note that the failing HEP RTCP tests now pass with this patch. These tests
+	  failed due to a duplicate scheduling of the RTCP transmissions.
 
-	* /, res/res_fax.c: res_fax: Fix out of bounds error in
-	  update_modem_bits(). ASTERISK-24357 #close Reported by: Jeremy
-	  Laine Patches: res_fax_bounds.patch (license #6561) patch
-	  uploaded by Jeremy Laine Modified patch to not use magic numbers.
-	  ........ Merged revisions 423979 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423983 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423987 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25449 #close
 
-2014-09-26 08:25 +0000 [r423918]  Walter Doekes <walter+asterisk at wjd.nu>
+	  Change-Id: I019a9aa8b6997584f66876331675981ac9e07e39
+2015-10-03 06:27 +0000 [b66f1eef41]  Ivan Poddubny <ivan.poddubny at gmail.com>
 
-	* /, doc/asterisk.8: docs: Escape unescaped minus sign in
-	  asterisk.8 manpage. ASTERISK-23768 #close Reported by: Jeremy
-	  Lainé Patches: escape_manpage_hyphen.patch uploaded by Jeremy
-	  Lainé (License #6561) ........ Merged revisions 423915 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423916 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423917 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-25 21:01 +0000 [r423895]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_pjsip.c, /: res_pjsip.c: Add missing off nominal cleanup
-	  in ast_sip_push_task_synchronous(). * Made memset the std struct
-	  in ast_sip_push_task_synchronous() because if DEBUG_THREADS is
-	  enabled then uninitialized lock tracking data is used. ........
-	  Merged revisions 423894 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-24 18:32 +0000 [r423867]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_pjsip/pjsip_options.c, res/res_pjsip.c:
-	  pjsip_options.c: Fix race condition stopping periodic out of
-	  dialog OPTIONS request. The crash on the issues is a result of an
-	  invalid transport configuration change when asterisk is
-	  restarted. The attempt to send the qualify request fails and we
-	  cleaned up. However, the callback is also called which results in
-	  a double unref of the objects involved. * Put a wrapper around
-	  pjsip_endpt_send_request() to detect when the passed in callback
-	  is called because of an error so callers can know to not cleanup.
-	  * Made send_request_cb() able to handle repeated challenges (Up
-	  to 10). * Fix periodic endpoint qualify OPTIONS sched deletion
-	  race by avoiding it. The sched entry will no longer self stop and
-	  must be externally stopped. * Added REF_DEBUG description tags to
-	  struct sched_data in pjsip_options.c. * Fix some off-nominal ref
-	  leaks in schedule_qualify(), qualify_and_schedule(). * Reordered
-	  pjsip_options.c module start/stop code to cleanup better on
-	  error. ASTERISK-24295 #close Reported by: Rogger Padilla Review:
-	  https://reviewboard.asterisk.org/r/3954/ ........ Merged
-	  revisions 423866 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-24 08:53 +0000 [r423803]  Walter Doekes <walter+asterisk at wjd.nu>
+	* manager: Fix GetConfigJSON returning invalid JSON
 
-	* /, channels/chan_sip.c: chan_sip: Unref outbound proxy structure
-	  on dialog/pvt destruction. Make sure outbound proxy refs are
-	  always unreffed on dialog destruction. Review:
-	  https://reviewboard.asterisk.org/r/4016/ ........ Merged
-	  revisions 423800 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423801 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423802 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-23 14:29 +0000 [r423783]  Mark Michelson <mmichelson at digium.com>
-
-	* tests/test_cel.c, tests/test_cdr.c: Make CDR and CEL unit tests
-	  less FRACKy. Prior to this commit, CDR and CEL tests were
-	  expected to trigger FRACKs (i.e. assertions) due to the fact that
-	  the channels they create have no formats on them. Some code was
-	  independently added recently that attempts to prevent FRACKs from
-	  occurring by failing early when attempting to set up translation
-	  paths if one or both channels support no formats. Unfortunately,
-	  this attempt to be helpful made the CDR and CEL tests go from
-	  simply FRACKing to outright failing and in some cases, failing so
-	  badly as to crash Asterisk. This commit seeks to correct past
-	  mistakes by adding the ulaw format to channels created by the CDR
-	  and CEL unit tests. This makes setting up translation paths
-	  succeed, eliminates previously-seen FRACKs, and ultimately causes
-	  the unit tests to succeed again. Review:
-	  https://reviewboard.asterisk.org/r/4014
-
-2014-09-22 19:48 +0000 [r423660-423723]  Walter Doekes <walter+asterisk at wjd.nu>
+	  When GetConfigJSON was introduced back in 1.6, it returned each
+	  section as an array of strings: ["key=value", "key2=value2"].
+	  Afterwards, it was changed a few times and became
+	  ["key": "value", "key2": "value2"], which is not a correct JSON.
+	  This patch fixes that by constructing a JSON object {} instead of
+	  an array [].
 
-	* /, channels/chan_sip.c: chan_sip: On INVITE retransmission, don't
-	  add an extra 503 response. INVITE arrives to asterisk, asterisk
-	  responds Busy(). If the INVITE is retransmitted, asterisk would
-	  generate a 503 in addition to the 486. Thanks Torrey Searle for
-	  providing a working regression test. ASTERISK-24335 #close
-	  Review: https://reviewboard.asterisk.org/r/4003/ Patches:
-	  retrans_486_invite.patch uploaded by Torrey Searle (License
-	  #5334) ........ Merged revisions 423720 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423721 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423722 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25391 #close
+	  Reported by: Bojan Nemčić
 
-	* /, main/editline/readline.c: cli.c: Fix tab completion "module
-	  load" when MALLOC_DEBUG is enabled. r421600 conflicted with
-	  r155763. ASTERISK-24348 #close ........ Merged revisions 423657
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 423658 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423659 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-21 01:15 +0000 [r423618-423641]  Matthew Jordan <mjordan at digium.com>
-
-	* main/channel.c: main/channel: Unlock channel in off-nominal path
-	  In r423414 (13) / r423415 (trunk), an API call that determines if
-	  a format capability structure is empty was added. This returns
-	  true if the format capability structure is completely empty or
-	  "none". A check for this was added in channel.c's set_format
-	  call. Unfortunately, when this check was true, it returned from
-	  the function while still holding the channel lock. This caused
-	  the CDR unit tests - which have a tendency to create channels
-	  with no formats - to deadlock. Whoops. This patch unlocks the
-	  channel on the off-nominal path.
-
-	* rest-api/api-docs/events.json, /: rest-api/api-docs/events.json:
-	  Remove non-compliant 'extends' attribute Prior to the release of
-	  Swagger 1.2, the attribute 'extends' was being promoted as a
-	  possible way to show that a particular object extends an existing
-	  object. Instead, the Swagger specification went with the
-	  'subTypes' attribute in the base object. This patch removes the
-	  unsupported attribute; the object that the offending objects
-	  proposed to extend already lists them in its 'subTypes'
-	  attribute. ASTERISK-24300 #close Reported by: Bradley Watkins
-	  ........ Merged revisions 423620 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json,
-	  rest-api/api-docs/mailboxes.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json,
-	  rest-api/api-docs/playbacks.json: rest-api/api-docs: Correct
-	  basePath in resources to match top resources file The
-	  resources.json file that defines the resource JSON files used
-	  with ARI references a basePath of 'http://localhost:8088/ari'.
-	  This does not match what is defined in the resource files
-	  themselves, 'http://localhost:8088/stasis'. The correct base path
-	  is the one that includes 'ari' in the URL; this patch updates the
-	  various resource JSON files to have the correct basePath.
-	  ASTERISK-24339 #close Reported by: Bradley Watkins ........
-	  Merged revisions 423617 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-19 19:51 +0000 [r423580]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_notify.c: res_pjsip_notify: Fix crash on
-	  unload/load and don't say the module doesn't exist on reload.
-	  When unloading the module did not unregister the CLI commands
-	  causing a crash upon load when they were registered again. When
-	  reloading the module the return value from the config options
-	  framework was not checked to determine if an error occurred or
-	  not. This caused a message to be output saying the module did not
-	  exist when reloading if no changes were present. AST-1433 #close
-	  AST-1434 #close ........ Merged revisions 423579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-19 17:08 +0000 [r423561]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_pjsip.c, res/res_pjsip_sdp_rtp.c:
-	  res_pjsip_sdp_rtp.c: Fix native formats containing formats that
-	  were not negotiated. Outgoing PJSIP calls can result in
-	  non-negotiated formats listed in the channel's native formats if
-	  video formats are listed in the endpoint's configuration. The
-	  resulting call could then use a non-negotiated format resulting
-	  in one way audio. * Simplified the update of session->req_caps in
-	  set_caps(). Why do something in five steps when only one is
-	  needed? AFS-162 #close Review:
-	  https://reviewboard.asterisk.org/r/4000/
-
-2014-09-19 15:18 +0000 [r423524-423530]  Jonathan Rose <jrose at digium.com>
-
-	* /, main/stasis_channels.c: Stasis_channels: Resolve unfinished
-	  Dials when doing masquerades Masquerades into channels that are
-	  in the dialing state don't end their dial and this goes against
-	  the model for things like CDRs and generating Dial end manager
-	  actions and such. ASTERISK-24237 #close Reported by: Richard
-	  Mudgett Review: https://reviewboard.asterisk.org/r/3990/ ........
-	  Merged revisions 423525 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_iax2.c: chan_iax2: Fix a crash when using chan_iax2
-	  jitterbuffer settings Caused by format changes in Asterisk 13
-	  ASTERISK-24265 #close Reported by: Dafi Ni Review:
-	  https://reviewboard.asterisk.org/r/3999/
-
-2014-09-19 12:45 +0000 [r423504]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/framehook.h, /, main/framehook.c,
-	  res/res_pjsip_t38.c: PJSIP: Prevent T38 framehook being put on
-	  wrong channel This change gives framehooks a reverse-direction
-	  masquerade callback in addition to chan_fixup_cb similar to the
-	  callback added to datastores to handle the same situation. The
-	  new callback provides the same parameters as the fixup callback,
-	  but is called on the new channel's framehooks before moving
-	  framehooks from the old channel to the new channel. This gives
-	  the framehooks an oppurtunity to decide whether they should
-	  remain on the new channel or be removed. This new callback is
-	  used to prevent the PJSIP T.38 framehook from remaining on a
-	  masqueraded channel if the new channel is not also a PJSIP
-	  channel. This was causing a crash when a local channel was
-	  masqueraded into a PJSIP channel and the framehook was executed
-	  on the local channel since the channel's tech private data was
-	  not structured as expected. Review:
-	  https://reviewboard.asterisk.org/r/4001/ ........ Merged
-	  revisions 423503 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 19:30 +0000 [r423482]  Sean Bright <sean at malleable.com>
-
-	* res/res_pjsip/config_auth.c, /: res_pjsip: Don't require a
-	  password when doing userpass authentication. An empty password is
-	  valid for username/password authentication so we should allow
-	  password to be empty/not supplied. Review:
-	  https://reviewboard.asterisk.org/r/3988 ........ Merged revisions
-	  423481 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 19:22 +0000 [r423478]  George Joseph <george.joseph at fairview5.com>
-
-	* tests/test_strings.c, /, main/utils.c,
-	  include/asterisk/strings.h: utils: Create ast_strsep function
-	  that ignores separators inside quotes This function acts like
-	  strsep with three exceptions... * The separator is a single
-	  character instead of a string. * Separators inside quotes are
-	  treated literally instead of like separators. * You can elect to
-	  have leading and trailing whitespace and quotes stripped from the
-	  result and have '\' sequences unescaped. Like strsep, ast_strsep
-	  maintains no internal state and you can call it recursively using
-	  different separators on the same storage. Also like strsep, for
-	  consistent results, consecutive separators are not collapsed so
-	  you may get an empty string as a valid result. Tested by: George
-	  Joseph Review: https://reviewboard.asterisk.org/r/3989/ ........
-	  Merged revisions 423476 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 18:31 +0000 [r423462]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pubsub.c: Add subscription state test events. These
-	  are needed for a set of batched notification RLS tests that are
-	  about to be committed to the testsuite. Review:
-	  https://reviewboard.asterisk.org/r/3967
-
-2014-09-18 17:11 +0000 [r423425]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_endpoint_identifier_ip.c, /:
-	  res_pjsip_endpoint_identifier_ip: Fix parsing of match value with
-	  CIDR Also fixes comma separates match lists ASTERISK-24290 #close
-	  Reported by: Ray Crumrine Review:
-	  https://reviewboard.asterisk.org/r/3995/ ........ Merged
-	  revisions 423417 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 17:09 +0000 [r423418-423423]  Richard Mudgett <rmudgett at digium.com>
-
-	* bridges/bridge_softmix.c: bridge_softmix.c: Made use
-	  ao2_replace() instead of the inline equivalent. * Clarified some
-	  read/write format comments. * Fixed a doxygen tag typo.
-
-	* main/astobj2.c, contrib/scripts/refcounter.py, /:
-	  astobj2.c/refcounter.py: Fix to deal with invalid object refs. *
-	  Make astob2 REF_DEBUG output an invalid object line when an
-	  invalid ao2 object ref/unref is attempted. This is similar to the
-	  constructor/destructor lines. * Fixed refcounter.py to handle
-	  skewed objects that have constructor/destructor states. * Made
-	  refcounter.py highlight the invalid ao2 object refs by putting
-	  them in their own section of the processed output file. * Made
-	  refcounter.py highlight unreffing an object by more than one that
-	  results in a negative ref count and the object being destroyed.
-	  The abnormally destroyed object is reported in the invalid and
-	  finalized object sections of the output. Review:
-	  https://reviewboard.asterisk.org/r/3971/ ........ Merged
-	  revisions 423349 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423400 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423416 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 16:37 +0000 [r423348-423414]  Mark Michelson <mmichelson at digium.com>
-
-	* include/asterisk/format_cap.h, main/channel.c, main/format_cap.c,
-	  main/translate.c: Add API call to determine if format capability
-	  structure is "empty". Empty here means that there are no formats
-	  in the format_cap structure or the only format in it is the
-	  "none" format. I've added calls to check the emptiness of a
-	  format_cap in a few places in order to short-circuit operations
-	  that would otherwise be pointless as well as to prevent some
-	  assertions from being triggered in cases where channels with no
-	  formats are used.
-
-	* /, res/res_fax_spandsp.c: res_fax_spandsp: Properly handle
-	  cleanup before starting FAXes. If faxing fails at a very early
-	  stage, then it is possible for us to pass a NULL t30 state
-	  pointer to spandsp, which spandsp is none too pleased with. This
-	  patch ensures that we pass the correct pointer to spandsp in the
-	  situation where we have not yet set our local t30 state pointer.
-	  ASTERISK-24301 #close Reported by Matt Jordan Patches:
-	  ASTERISK-24301-fax.diff Uploaded by Mark Michelson (License
-	  #5049) ........ Merged revisions 423360 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423365 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_mwi.c,
-	  res/res_pjsip_dialog_info_body_generator.c,
-	  res/res_pjsip_xpidf_body_generator.c,
-	  res/res_pjsip_mwi_body_generator.c, res/res_pjsip_pubsub.c,
-	  res/res_pjsip_exten_state.c, include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_pidf_body_generator.c: res_pjsip_pubsub: Add some
-	  type safety when generating NOTIFY bodies. res_pjsip_pubsub has
-	  two separate checks that it makes when a SUBSCRIBE arrives. * It
-	  checks that there is a subscription handler for the Event * It
-	  checks that there are body generators for the types in the Accept
-	  header The problem is, there's nothing that ensures that these
-	  two things will actually mesh with each other. For instance,
-	  Asterisk will accept a subscription to MWI that accepts pidf+xml
-	  bodies. That doesn't make sense. With this commit, we add some
-	  type information to the mix. Subscription handlers state they
-	  generate data of type X, and body generators state that they
-	  consume data of type X. This way, Asterisk doesn't end up in some
-	  hilariously mismatched situation like the one in the previous
-	  paragraph. ASTERISK-24136 #close Reported by Mark Michelson
-	  Review: https://reviewboard.asterisk.org/r/3877 Review:
-	  https://reviewboard.asterisk.org/r/3878 ........ Merged revisions
-	  423344 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 15:13 +0000 [r423284]  George Joseph <george.joseph at fairview5.com>
-
-	* /, res/res_pjsip/location.c,
-	  res/res_pjsip_endpoint_identifier_ip.c,
-	  res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/pjsip_options.c, res/res_pjsip/config_transport.c,
-	  include/asterisk/res_pjsip.h, res/res_pjsip/config_auth.c:
-	  res_pjsip: ami: Fix error in AMI output when an endpoint has no
-	  transport When no transport is associated to an endpoint, the AMI
-	  output for PJSIPShowEndpoint indicates an error instead of
-	  silently ignoring the missing transport. This patch causes the
-	  error to appear only if a transport was specified on the endpoint
-	  and the transport doesn't exist. It also fixes an issue with
-	  counting the objects that were actually found. ASTERISK-24161
-	  #close ASTERISK-24331 #close Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3998/ ........ Merged
-	  revisions 423282 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-18 15:00 +0000 [r423281]  David M. Lee <dlee at digium.com>
-
-	* makeopts.in, Makefile: Only install dahdi_span_config_hook if
-	  DAHDI is enabled This patch changes the install to only install
-	  the hook script if DAHDI is enabled. It also adds the script to
-	  the uninstall task, and moves the DAHDI_UDEV_HOOK_DIR variable so
-	  that it's not between the _MAKEOPTS variables and their comment.
-	  This allows installs which specify a --prefix to work normally,
-	  as long as they don't enable DAHDI. Review:
-	  https://reviewboard.asterisk.org/r/3972/
-
-2014-09-18 14:45 +0000 [r423279]  George Joseph <george.joseph at fairview5.com>
-
-	* main/manager.c, /, include/asterisk/config.h, main/config.c:
-	  config: bug: Fix SEGV in ast_category_insert when matching
-	  category isn't found If you call ast_category_insert with a match
-	  category that doesn't exist, the list traverse runs out of 'next'
-	  categories and you get a SEGV. This patch adds check for the
-	  end-of-list condition and changes the signature to return an int
-	  for success/failure indication instead of a void. The only
-	  consumer of this function is manager and it was also changed to
-	  use the return value. Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3993/ ........ Merged
-	  revisions 423276 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423277 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423278 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-17 18:05 +0000 [r423209-423255]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Ensure that the
-	  thread terminating pj stuff is registered. ........ Merged
-	  revisions 423253 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423254 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix 100% CPU usage
-	  due to timer heap thread spinning. Side note: I need a vacation.
-	  ........ Merged revisions 423210 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423211 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix building when
-	  pjproject is not used. ........ Merged revisions 423207 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423208 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-16 16:32 +0000 [r423192]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* apps/app_voicemail.c, include/asterisk/file.h, main/file.c:
-	  Voicemail: get correct duration when copying file to vm Changes
-	  made during format improvements resulted in the recording to
-	  voicemail option 'm' of the MixMonitor app writing a zero length
-	  duration in the msgXXXX.txt file. This change introduces a new
-	  function ast_ratestream(), which provides the sample rate of the
-	  format associated with the stream, and updates the app_voicemail
-	  function for ast_app_copy_recording_to_vm to calculate the right
-	  duration. Review: https://reviewboard.asterisk.org/r/3996/
-	  ASTERISK-24328 #close
-
-2014-09-16 12:12 +0000 [r423152-423173]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Fix usage of wrong
-	  memory pool when creating local SDP. ........ Merged revisions
-	  423172 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/rtp_engine.h, res/res_rtp_asterisk.c, /:
-	  res_rtp_asterisk: Fix a myriad of TURN client issues. 1. The
-	  number of file descriptors an ioqueue instance can handle is
-	  fixed, so we now spawn the required number to handle the load. 2.
-	  Our transport identifiers were exceeding the range supported by
-	  pjnath. 3. The TURN client did not set up client binding causing
-	  needless bandwidth usage. 4. The code no longer updates address
-	  information on each packet. 5. STUN traffic was getting looped
-	  back to Asterisk instead of going through the TURN server. 6.
-	  Synchronization now ensures things are completely setup or
-	  destroyed. 7. Logging now reflects the target the TURN server is
-	  sending to/receiving from on our behalf. ASTERISK-23577 #close
-	  Reported by: Jay Jideliov ASTERISK-23634 #close Reported by:
-	  Roman Skvirsky Review: https://reviewboard.asterisk.org/r/3982/
-	  ........ Merged revisions 423150 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423151 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-15 10:49 +0000 [r423069-423129]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
-	  (added): contrib: Fix verifyi typo in alembic DB script
-	  ps_transport table. Reported by: Zogot (on IRC) Patches: tmp.diff
-	  uploaded by Zogot, cleaned up by me. ........ Merged revisions
-	  423128 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* configs/samples/sip.conf.sample, /: chan_sip: Clarify that
-	  sipdebug=yes cannot be undone by the CLI. Document it in
-	  sip.conf. ASTERISK-24249 #close Reported by: Avinash Mohod
-	  Review: https://reviewboard.asterisk.org/r/3926/ ........ Merged
-	  revisions 423066 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 423067 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 423068 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-12 16:09 +0000 [r422985]  Jonathan Rose <jrose at digium.com>
-
-	* main/config.c, /: Realtime: Fix a bug that caused realtime
-	  destroy command to crash Also has could affect with anything that
-	  goes through ast_destroy_realtime. If a CLI user used the command
-	  'realtime destroy <family>' with only a single column/value pair,
-	  Asterisk would crash when trying to create a variable list from a
-	  NULL value. ASTERISK-24231 #close Reported by: Niklas Larsson
-	  Review: https://reviewboard.asterisk.org/r/3985/ ........ Merged
-	  revisions 422984 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-11 22:16 +0000 [r422965]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/app.c: Remove undocumented default behavior of
-	  ast_play_and_record_full acceptdtmf. ast_play_and_record_full()
-	  has a parameter called "acceptdtmf" that is a string of
-	  acceptable DTMF digits that may be pressed by a caller to end and
-	  accept the recording. ARI uses this function in order to perform
-	  recording, and it provides options for what is passed as
-	  acceptdtmf to ast_play_and_record_full(). By default, ARI passes
-	  an empty string, with the intention that no DTMF can be used to
-	  end the recording. The problem is that ast_play_and_record_full()
-	  attempts to be "helpful" by setting "#" as the acceptdtmf if an
-	  empty string or NULL pointer has been passed in. With ARI, this
-	  results in unexpected behavior occurring if you have attempted to
-	  intercept "#" yourself in order to perform some other
-	  manipulation of the live recording. This change removes the
-	  "helpful" behavior by no longer accepting "#" as a default
-	  acceptdtmf if none is specified by the caller of
-	  ast_play_and_record_full(). This makes the ARI scenario work as
-	  expected. The other callers of ast_play_and_record_full() are
-	  app_voicemail and app_minivm, and in both cases, they pass an
-	  explicit "#" to ast_play_and_record_full() as acceptdtmf, so they
-	  are unaffected by this change. ........ Merged revisions 422964
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-10 16:04 +0000 [r422905]  George Joseph <george.joseph at fairview5.com>
+	  Change-Id: Ibbe93c6a227dff14d4a54b0d152341857bcf6ad8
 
-	* /, main/config.c: config: bug: fix truncation of included config
-	  files on permissions error ast_config_text_file_save() currently
-	  truncates include files as they are processed. If a subsequent
-	  include file or the main config file has a permissions error that
-	  prevents writing, earlier include files are left truncated
-	  resulting in a frantic search for backups. This patch causes
-	  ast_config_text_file_save to check for write access on all files
-	  before it truncates any of them. Will be applied 1.8 > trunk.
-	  Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3986/ ........ Merged
-	  revisions 422900 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422903 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422904 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-28 15:31 +0000 [6803444ac1]  Richard Mudgett <rmudgett at digium.com>
 
-2014-09-10 15:59 +0000 [r422901]  Sean Bright <sean at malleable.com>
+	* sched.c: Add warning about negative time interval request.
 
-	* res/res_pjsip/config_auth.c, /: pjsip/config_auth.c: Add missing
-	  whitespace to log messages. The errors generated when validating
-	  'auth' settings are missing a space which makes the messages a
-	  little confusing. ........ Merged revisions 422899 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Ib91435fb45b7f5f7c0fc83d0eec20b88098707bc
 
-2014-09-09 20:01 +0000 [r422883]  Rusty Newton <rnewton at digium.com>
+2015-09-30 13:42 +0000 [fa0985851a]  Joshua Colp <jcolp at digium.com>
 
-	* /, sounds/sounds.xml, sounds/Makefile: Sounds/BuildSystem:
-	  Modifications to include new releases and Japanese language.
-	  Modifying Makefile and sounds.xml to include new core 1.4.26 and
-	  extra 1.4.15 sound prompt releases, plus the new Japanese core
-	  sound prompts contributed by QLOOG. ASTERISK-23324 Reported by:
-	  Kevin McCoy Tested by: Rusty Newton ........ Merged revisions
-	  422789 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 422790 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422791 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-08 18:03 +0000 [r422851-422855]  Mark Michelson <mmichelson at digium.com>
-
-	* configs/samples/pjsip.conf.sample: Add note about configuring
-	  list_items on a single line.
-
-	* configs/samples/pjsip.conf.sample: Add sample configuration for
-	  resource lists. On review /r/3977, it was recommended to note in
-	  the sample configuration about the size limitation for resource
-	  lists. However, since there was no section in the sample
-	  configuration at all for resource list subscriptions, I decided
-	  to make a separate commit where I have added the necessary sample
-	  configuration as well as the size limitation warning.
-
-	* res/res_pjsip_pubsub.c: Pre-allocate transmission data buffer for
-	  RLS NOTIFY requests. PJSIP, unless a constant is modified at
-	  compilation time, limits SIP requests to 4000 bytes. Full-state
-	  RLS notifications can easily exceed this limit with moderately
-	  small lists. This changeset allows for Asterisk to work around
-	  this size limit by performing its own allocation of the
-	  transmission data buffer. This way, Asterisk can allocate a
-	  buffer that exceeds the built-in maximum. We still impose our own
-	  limit of 64000 bytes, mainly because making allocations larger
-	  than that is a bit absurd. ASTERISK-24181 #close Reported by Mark
-	  Michelson Review: https://reviewboard.asterisk.org/r/3977
-
-2014-09-08 15:41 +0000 [r422836]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_pubsub.c: res_pjsip_pubsub: Check supported headers
-	  for eventlist when subscribing to resource list
-	  https://wiki.asterisk.org/wiki/display/AST/Resource+List+Subscription+Test+Plan
-	  According to the off-nominal plan, if evenlist support is not
-	  specified in a SUBSCRIBE's supported header(s), that subscription
-	  should be rejected with an error. ASTERISK-23871 Reported by:
-	  Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3960/diff/#index_header
-
-2014-09-06 22:49 +0000 [r422767-422770]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/cdr.c: main/cdr: Copy over location information during a
-	  fork When a CDR is forked, a new CDR is created and appended to
-	  the CDR chain for the Party A. The forked CDR starts life off as
-	  a clone of the last non-finalized for the particular Party A. In
-	  the past, merely copying over the snapshots for Party A/Party B
-	  would be sufficient. However, as the CDRs now contain cached
-	  information from Party A - specifically application/data,
-	  context, and extension - we need to copy that over during a fork
-	  as well. Huzzah for unit tests catching this when the
-	  context/extension were derived from a cached value on the CDR
-	  instead of on Party A. ........ Merged revisions 422769 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/rtp_engine.c, /: main/rtp_engine: Format NTP timestamps as
-	  unsigned ints On some systems, a timeval's tv_sec/tv_usec will be
-	  unsigned lont ints, as opposed to long ints. When the RTP engine
-	  formats these as strings, it was previously formatting them as
-	  signed integers, which can result in some odd negative timestamp
-	  values (particularly on 32-bit systems). This patch formats the
-	  values as unsigned long integers. ........ Merged revisions
-	  422766 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-06 19:12 +0000 [r422747]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, /: res_pjsip_sdp_rtp: Fix retrieval of
-	  "ice-pwd" attribute if in session and not media stream. ........
-	  Merged revisions 422746 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-05 22:03 +0000 [r422716-422719]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /, apps/app_macro.c, include/asterisk/channel.h,
-	  apps/app_stack.c: main/cdrs: Preserve context/extension when
-	  executing a Macro or GoSub The context/extension in a CDR is
-	  generally considered the destination of a call. When looking at a
-	  2-party call CDR, users will typically be presented with the
-	  following: context exten channel dest_channel app data default
-	  1000 SIP/8675309 SIP/1000 Dial SIP/1000,,20 However, if the Dial
-	  actually takes place in a Macro, the current behaviour in 12 will
-	  result in the following CDR: context exten channel dest_channel
-	  app data macro-dial s SIP/8675309 SIP/1000 Dial SIP/1000,,20 The
-	  same is true of a GoSub: context exten channel dest_channel app
-	  data subs dial_stuff SIP/8675309 SIP/1000 Dial SIP/1000,,20 This
-	  generally makes the context/exten fields less than useful. It
-	  isn't hard to preserve these values in the CDR state machine;
-	  however, we need to have something that informs us when a channel
-	  is executing a subroutine. Prior to this patch, there isn't
-	  anything that does this. This patch solves this problem by adding
-	  a new channel flag, AST_FLAG_SUBROUTINE_EXEC. This flag is set on
-	  a channel when it executes a Macro or a GoSub. The CDR engine
-	  looks for this value when updating a Party A snapshot; if the
-	  flag is present, we don't override the context/exten on the main
-	  CDR object. In a funny quirk, executing a hangup handler must
-	  *not* abide by this logic, as the endbeforehexten logic assumes
-	  that the user wants to see data that occurs in hangup logic,
-	  which includes those subroutines. Since those execute outside of
-	  a typical Dial operation (and will typically have their own
-	  dedicated CDR anyway), this is unlikely to cause any heartburn.
-	  Review: https://reviewboard.asterisk.org/r/3962/ ASTERISK-24254
-	  #close Reported by: tm1000, Tony Lewis Tested by: Tony Lewis
-	  ........ Merged revisions 422718 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: main/cdr: Fix crash/memory consumption in CDRs in
-	  multi-party bridge scenarios This patch fixes an issue where CDRs
-	  would get stuck generating an infinite number of CDRs, eventually
-	  crashing Asterisk (and consuming a lot of memory along the way).
-	  When a channel enters into a multi-party bridge, the CDR engine
-	  creates mappings of each participant to each other participant,
-	  picking the 'A' party as it goes. So, if we have four channels in
-	  a multi-party bridge (Alice, Bob, Charlie, Denise), we would have
-	  something like: Alice => Bob Alice => Charlie Alice => Denise Bob
-	  => Charlie Bob => Denise Charlie => Denise This works fine when
-	  participants enter the bridge a single time. When a participant
-	  leaves a bridge, the CDRs for that channel are transitioned to a
-	  finalized state. The bug occurs if Bob rejoins. When the CDR
-	  engine creates mappings between the channels, it walks through
-	  all the participants currently in the bridge, and realizes that
-	  no one in the bridge can create a CDR with the channel (Bob). As
-	  such it creates a new CDR for the candidate and appends it to
-	  that candidate's chain. Unfortunately, on this particular code
-	  path, it doesn't stop traversing the candidate's chain. Since we
-	  just added ourselves to the chain, this causes the loop to keep
-	  going, constantly adding new CDRs. This patch makes it so the
-	  engine bails when it creates a CDR match in this case. Review:
-	  https://reviewboard.asterisk.org/r/3964/ ASTERISK-24241 #close
-	  Reported by: Deepak Singh Rawat Tested by: Deepak Singh Rawat
-	  ASTERISK-24208 Reported by: Frankie Chin ........ Merged
-	  revisions 422715 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-05 20:35 +0000 [r422700]  Richard Mudgett <rmudgett at digium.com>
-
-	* funcs/func_channel.c: func_channel.c: Add missing locking to some
-	  CHANNEL() requests. * The CHANNEL() audionativeformat,
-	  videonativeformat, audioreadformat, and audiowriteformat now need
-	  locking since the media format rework when accessing the
-	  channel's format pointers. * Increased the buffer size for
-	  CHANNEL() audionativeformat and videonativeformat output strings
-	  since the allow=all can be a lengthy list. * Tweaked the
-	  CHANNEL() XML documentation for secure_bridge_signaling,
-	  secure_bridge_media, and state. * Ensured the output buffer is
-	  initialized for secure_bridge_signaling and secure_bridge_media.
-	  * Made use the locked_copy_string() macro instead of inlining it
-	  for trace and checkhangup.
-
-2014-09-05 20:11 +0000 [r422665-422684]  Jonathan Rose <jrose at digium.com>
-
-	* main/dial.c, include/asterisk/dial.h: Dial API: Add a dial option
-	  to indicate the dialed channel will replace dialer Adds an option
-	  to the dial API that marks an outgoing dial as replacing the
-	  dialing channel for the purpose of propagating accountcode. When
-	  it is used, AST_CHANNEL_REQUESTOR_REPLACEMENT is used instead of
-	  AST_CHANNEL_REQUESTOR_BRIDGE_PEER when setting accountcodes on
-	  the involved channels with ast_channel_req_accountcodes. Review:
-	  https://reviewboard.asterisk.org/r/3968/
-
-	* main/cli.c, /: Call IDs: Fix appearance of call ID in core show
-	  channels when NULL NULL call IDs were meant to appear as '(none)'
-	  but instead were showing the contents of an uninitialized
-	  character buffer. ASTERISK-24223 Review:
-	  https://reviewboard.asterisk.org/r/3979/ ........ Merged
-	  revisions 422664 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-05 17:36 +0000 [r422661]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/devicestate.c, channels/chan_iax2.c: devicestate.c: Minor
-	  tweaks * In ast_state_chan2dev() use ARRAY_LEN() instead of a
-	  sentinel value in chan2dev[]. * Fix some comments in chan_iax2.c.
-
-2014-09-05 13:28 +0000 [r422646]  Kinsey Moore <kmoore at digium.com>
-
-	* menuselect/menuselect.c: Menuselect: Fix incorrect enabling on
-	  failed deps This corrects a situation where menuselect can
-	  incorrectly enable a module by default that has defaultenabled
-	  set to "no" and has failed/non-selected dependencies. The bug is
-	  due to an inverted test when checking for whether the given
-	  module should be set to enabled by default on load. Review:
-	  https://reviewboard.asterisk.org/r/3975/ Reported by: John
-	  Bigelow
+	* res_rtp_asterisk: Move "Set role" warning to be debug.
 
-2014-09-04 21:23 +0000 [r422631]  Jonathan Rose <jrose at digium.com>
+	  In practice the set_role API callback can be invoked even
+	  when no ICE is present on an RTP instance. This can occur
+	  if ICE has not been enabled on it.
 
-	* main/manager.c, /: Manager: Require read permission for SYSTEM in
-	  order to send FullyBooted Review:
-	  https://reviewboard.asterisk.org/r/3969/ ........ Merged
-	  revisions 422584 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422625 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422626 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-03 14:05 +0000 [r422558]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_transport_websocket.c, /:
-	  res_pjsip_transport_websocket: Fix crash when the Contact header
-	  is not a URI. The code for changing the Contact header wrongly
-	  assumed that the Contact would always contain a URI. This is
-	  incorrect. ASTERISK-24271 Reported by: Dafi Ni ........ Merged
-	  revisions 422557 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-02 20:29 +0000 [r422542]  Mark Michelson <mmichelson at digium.com>
-
-	* /, channels/chan_pjsip.c, res/res_pjsip_diversion.c,
-	  res/res_pjsip_session.c, include/asterisk/res_pjsip_session.h:
-	  Resolve race condition where channels enter dialplan application
-	  before media has been negotiated. Testsuite tests will
-	  occasionally fail because on reception of a 200 OK SIP response,
-	  an AST_CONTROL_ANSWER frame is queued prior to when media has
-	  finished being negotiated. This is because session supplements
-	  are called into before PJSIP's inv_session code has told us that
-	  media has been updated. Sometimes the queued answer frame is
-	  handled by the PBX thread before the ensuing media negotiations
-	  occur, causing a test failure. As it turns out, there is another
-	  place that session supplements could be called into, which is
-	  after media has finished getting negotiated. What this commit
-	  introduces is a means for session supplements to indicate when
-	  they wish to be called into when handling an incoming SIP
-	  response. By default, all session supplements will be run at the
-	  same point that they were prior to this commit. However, session
-	  supplements may indicate that they wish to be handled earlier
-	  than normal on redirects, or they may indicate they wish to be
-	  handled after media has been negotiated. In this changeset, two
-	  session supplements have been updated to indicate a preference
-	  for when they should be run: res_pjsip_diversion executes before
-	  handling redirection in order to get information from the
-	  Diversion header, and chan_pjsip now handles responses to INVITEs
-	  after media negotiation to fix the race condition mentioned
-	  previously. ASTERISK-24212 #close Reported by Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3930 ........ Merged revisions
-	  422536 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-09-01 14:16 +0000 [r422504-422507]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cli.c, /: main/cli: Do not attempt to show CDR data for
-	  internal channels Internal channels don't have CDRs. Querying the
-	  CDR engine for their variables will make it cranky. ........
-	  Merged revisions 422506 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis.c, /, res/stasis/stasis_bridge.c: res_stasis:
-	  Don't play MoH to channels by default when added to holding
-	  bridges When ARI manipulates a bridge, it generally doesn't care
-	  what the mixing technology is. Operations on a bridge initiated
-	  through ARI should perform their action in generally the same
-	  way, regardless of the bridge's mixing technology. While the
-	  mixing technology may determine how media flows to channels, the
-	  actual operations on a bridge themselves should be the same.
-	  Currently, this isn't the case with holding bridges. When a
-	  channel joins without a role, MoH is started on that channel
-	  automatically. Subsequent bridge operations that would stop MoH
-	  would fail (as there is no Announcer channel playing MoH to the
-	  bridge). Starting MoH on the bridge will also create two MoH
-	  streams: one from the MoH being played on the participant
-	  channel, and one from the announcer channel. From the perspective
-	  of ARI users, this is counter-intuitive - I would not expect MoH
-	  to be started for me. The mixing technology determines how media
-	  is shared between participants, not the application experience.
-	  This patch does the following: * The Stasis bridge class now
-	  inspects channels as they are going into a bridge. If the bridge
-	  has a holding capability, and the channel has no roles, we give
-	  it a participant role and mark the default behaviour to have no
-	  entertainment. This allows addChannel operations to continue to
-	  set a participant role with an entertainment option if it felt
-	  like it (or could do it). * The music on hold channel is now
-	  Stasis approved (tm) Review:
-	  https://reviewboard.asterisk.org/r/3929/ ASTERISK-24264 #close
-	  Reported by: Samuel Galarneau Tested by: Samuel Galarneau
-	  ........ Merged revisions 422503 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-30 17:32 +0000 [r422442-422445]  George Joseph <george.joseph at fairview5.com>
-
-	* apps/app_confbridge.c, /: confbridge: Add Duration to
-	  ConfbridgeList event The ConfbridgeList event doesn't include how
-	  long the user has been a member of the conference. This patch
-	  adds Duration (seconds) which is based on user->chan->answertime.
-	  Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3955/ ........ Merged
-	  revisions 422444 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25438 #close
 
-	* main/manager.c, /: manager: Make WaitEvent action respect
-	  eventfilters A WaitEvent issued via an http session isn't
-	  respecting eventfilters defined for the user. I just added a
-	  match_filter to the predicate that controls astman_append. Tested
-	  by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3958/ ........ Merged
-	  revisions 422439 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422440 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422441 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I0e17e4316f0f0d7f095c78c3d4fd73a913b6ba69
 
-2014-08-29 19:40 +0000 [r422374-422379]  Matthew Jordan <mjordan at digium.com>
+2015-09-29 20:58 +0000  Asterisk Development Team <asteriskteam at digium.com>
 
-	* doc/smsq.8 (added), /: doc: Add a manpage for the smsq utility
-	  This patch adds a manpage for the smsq utility. Note that this is
-	  one of the patches the Debian distro applies for the Asterisk
-	  project, as per ASTERISK-24191. Review:
-	  https://reviewboard.asterisk.org/r/3895/ ASTERISK-24171 #close
-	  Reported by: Jeremy Laine patches: smsq.8 uploaded by Jeremy
-	  Laine (License 6561) ........ Merged revisions 422376 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422377 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422378 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* asterisk 11.20.0-rc1 Released.
 
-	* doc/aelparse.8 (added), /: doc: Add a manpage for the aelparse
-	  utility This patch adds a manpage for the aelparse utility. Note
-	  that this is one of the patches the Debian distro applies for the
-	  Asterisk project, as per ASTERISK-24191. Review:
-	  https://reviewboard.asterisk.org/r/3896/ ASTERISK-24171 #close
-	  Reported by: Jeremy Laine patches: aelparse.8 uploaded by Jeremy
-	  Laine (License 6561) ........ Merged revisions 422371 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422372 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422373 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-29 15:57 +0000 [e4ef76777f]  Kevin Harwell <kharwell at lunkwill>
 
-2014-08-29 19:05 +0000 [r422359]  Scott Griepentrog <sgriepentrog at digium.com>
+	* Release summaries: Add summaries for 11.20.0-rc1
 
-	* channels/chan_sip.c: The assertion that peer was not found on
-	  final event message was being triggered on configuration reload.
-	  This patch changes that case to just return instead. Review:
-	  https://reviewboard.asterisk.org/r/3953/ Commited in trunk
-	  revision 422358
+2015-09-29 15:56 +0000 [db337a8a50]  Kevin Harwell <kharwell at lunkwill>
 
-2014-08-28 21:54 +0000 [r422296]  Matthew Jordan <mjordan at digium.com>
+	* .version: Update for 11.20.0-rc1
 
-	* LICENSE, /: LICENSE: Clarify language in Asterisk's LICENSE to
-	  allow for linking to UniMRCP The UniMRCP project distributes
-	  Asterisk modules that integrate Asterisk with UniMRCP, and other
-	  Asterisk users use the UniMRCP library as well. Unfortunately,
-	  the UniMRCP license is Apache 2.0, which per the Free Software
-	  Foundation, is not a compatible license with the GPLv2. "Please
-	  note that this license is not compatible with GPL version 2,
-	  because it has some requirements that are not in that GPL
-	  version. These include certain patent termination and
-	  indemnification provisions. The patent termination provision is a
-	  good thing, which is why we recommend the Apache 2.0 license for
-	  substantial programs over other lax permissive licenses." On the
-	  other hand, UniMRCP is a great project and we'd like to let
-	  people use it with Asterisk. This patch updates the LICENSE text
-	  to allow users to link Asterisk with UniMRCP and distribute the
-	  resulting binaries. ........ Merged revisions 422293 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422294 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422295 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-28 20:30 +0000 [r422276]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, channels/chan_iax2.c: chan_iax2: Fix Dynamic IAX2
-	  Registrations After Temporary DNS Failure The reporter on the
-	  issue found some issues when upgrading from version 10 to 11 on
-	  55 hosts. Two situations that can occur with dynamic
-	  registrations. 1. With dnsmgr disabled, if the host is not
-	  resolvable we are not trying to resolve the host again when it is
-	  time to attempt to register again. This results in never
-	  registering to the host. 2. With dnsmgr enabled, when the host is
-	  temporarily not resolvable the address is set to 0.0.0.0:0 and
-	  then when the host is resolvable the port is not being restored
-	  and stays set to 0. This patch resolves these two issues by: *
-	  Storing the hostname so that it can be used for resolving with
-	  DNS. * Resolve the hostname on the next scheduled attempt to
-	  register. * Storing the port used to reach the host so that when
-	  the hostname is resolvable again, we can set the port again if
-	  the port is still unset after looking up the host. ASTERISK-23767
-	  #close Reported by: David Herselman Tested by: David Herselman,
-	  Michael L. Young Patches:
-	  asterisk-23767-dns_reg_retry_and_set_port_11_v3.diff uploaded by
-	  Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/3856/ ........ Merged
-	  revisions 422274 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422275 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-29 15:56 +0000 [1db02c4e56]  Kevin Harwell <kharwell at lunkwill>
 
-2014-08-28 17:25 +0000 [r422256]  Richard Mudgett <rmudgett at digium.com>
+	* .lastclean: Update for 11.20.0-rc1
 
-	* /, UPGRADE.txt: Added ConfBridge AMI event note to UPGRADE.txt.
-	  ........ Merged revisions 422255 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-28 01:36 +0000 [8d2e1ecdca]  Ivan Poddubny <ivan.poddubny at gmail.com>
 
-2014-08-28 15:49 +0000 [r422239]  Mark Michelson <mmichelson at digium.com>
+	* channel.c: Fix NewCallerid AMI event not been sent on Caller ID change
 
-	* res/res_pjsip_pubsub.c: Fix bug that did not allow for multiple
-	  batched RLS notifications to be sent. A misunderstanding of how
-	  the scheduler worked caused further batched notifications beyond
-	  the first not to get scheduled. Now we reset our scheduler ID to
-	  -1 after the batched notification is sent. This way, further
-	  notifications can be scheduled when they arise.
+	  Currently, NewCallerid is sent only when pointers to number or name
+	  strings change, which is not always the case. The newly allocated string
+	  may use the same memory, so pointers match, while the content
+	  is different. As a result, Caller ID updates are often not reported.
 
-2014-08-28 00:36 +0000 [r422200-422215]  Richard Mudgett <rmudgett at digium.com>
+	  With this patch, actual strings are compared, not the pointers.
 
-	* res/res_pjsip/pjsip_options.c, /: res/res_pjsip/pjsip_options.c:
-	  Eliminate excessive RAII_VAR usage. * Fix off nominal ref leak in
-	  find_or_create_contact_status(). * Add missing NULL check of
-	  status in update_contact_status() and init_start_time(). ........
-	  Merged revisions 422214 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25427 #close
+	  Reported by: Ivan Poddubny
 
-	* main/sched.c, include/asterisk/sched.h: sched: Fix typo and
-	  whitespace change.
+	  Change-Id: I2a1ac3a842f0e092c6058d1cd3e35443bece1b36
 
-2014-08-27 17:29 +0000 [r422177]  George Joseph <george.joseph at fairview5.com>
+2015-09-21 08:16 +0000 [29694eb2aa]  Elazar Broad <elazar at thebroadfamily.com>
 
-	* /, apps/confbridge/confbridge_manager.c, apps/app_confbridge.c:
-	  confbridge: Add 'Admin' param to join, leave, mute, unmute and
-	  talking events Currently there's no way to tell if a user is an
-	  admin or not when receiving the join, leave, mute, unmute and
-	  talking events. This patch adds that capability. Tested by:
-	  George Joseph Review: https://reviewboard.asterisk.org/r/3950/
-	  ........ Merged revisions 422176 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* core/logging: Fix logging to more than one syslog channel
 
-2014-08-27 15:31 +0000 [r422154]  Kinsey Moore <kmoore at digium.com>
+	  Currently, Asterisk will log to the last configured syslog
+	  channel in logger.conf. This is due to the fact that the
+	  final call to openlog() supersedes all of the previous calls.
+	  This commit removes the call to openlog() and passes the
+	  facility to ast_log_vsyslog(), along with utilizing the
+	  LOG_MAKEPRI macro to ensure that the message is routed to
+	  the correct facility and with the correct priority.
 
-	* include/asterisk/utils.h, /, channels/chan_sip.c,
-	  tests/test_callerid.c (added), tests/test_utils.c,
-	  main/callerid.c, main/utils.c, res/res_pjsip_caller_id.c:
-	  CallerID: Fix parsing of malformed callerid This allows the
-	  callerid parsing function to handle malformed input strings and
-	  strings containing escaped and unescaped double quotes. This also
-	  adds a unittest to cover many of the cases where the parsing
-	  algorithm previously failed. Review:
-	  https://reviewboard.asterisk.org/r/3923/ Review:
-	  https://reviewboard.asterisk.org/r/3933/ ........ Merged
-	  revisions 422112 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 422113 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 422114 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-26 23:28 +0000 [r422091]  George Joseph <george.joseph at fairview5.com>
-
-	* apps/app_confbridge.c, /: confbridge: Make kick, mute and unmute
-	  handle channel targets consistently. Kick, mute and unmute were a
-	  little inconsistent in their handling of channel targets. This
-	  patch cleans that up by insuring they all handle the 'all' target
-	  consistently and adds the 'participants' target which acts on
-	  non-admins. Documentation for kick was also cleaned up as it
-	  never supported partial channel names. Tested by: George Joseph
-	  Review: https://reviewboard.asterisk.org/r/3944/ ........ Merged
-	  revisions 422090 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-26 22:13 +0000 [r422071]  Mark Michelson <mmichelson at digium.com>
-
-	* main/sched.c, /: Fix race condition in the scheduler when
-	  deleting a running entry. When scheduled tasks run, they are
-	  removed from the heap (or hashtab). When a scheduled task is
-	  deleted, if the task can't be found in the heap (or hashtab), an
-	  assertion is triggered. If DO_CRASH is enabled, this assertion
-	  causes a crash. The problem is, sometimes it just so happens that
-	  someone attempts to delete a scheduled task at the time that it
-	  is running, leading to a crash. This change corrects the issue by
-	  tracking which task is currently running. If that task is
-	  attempted to be deleted, then we mark the task, and then wait for
-	  the task to complete. This way, we can be sure to coordinate task
-	  deletion and memory freeing. ASTERISK-24212 Reported by Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/3927 ........
-	  Merged revisions 422070 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-25 16:44 +0000 [r421979-422037]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_musiconhold.c: res_musiconhold.c: Release any format refs
-	  before memset(). * Clear the channel music_state pointer before
-	  destroying the music_state object for safety.
-
-	* res/res_musiconhold.c, /: res_musiconhold: Fix MOH restarting
-	  where it left off from the last hold. Restore code removed by
-	  https://reviewboard.asterisk.org/r/3536/ that introduced a
-	  regression that prevents MOH from restarting were it left off the
-	  last time. ASTERISK-24019 #close Reported by: Jason Richards
-	  Patches: jira_asterisk_24019_v1.8.patch (license #5621) patch
-	  uploaded by rmudgett Review:
-	  https://reviewboard.asterisk.org/r/3928/ ........ Merged
-	  revisions 421976 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421977 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421978 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-24 19:36 +0000 [r421911-421956]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_transport_websocket.c, /:
-	  res_pjsip_transport_websocket: Attach the Websocket module on
-	  outgoing INVITEs. In order to alter the Contact header on
-	  in-dialog requests and responses the Websocket module must be
-	  attached on outgoing INVITEs. The Contact header is modified so
-	  that the PJSIP transport layer can find and use the existing
-	  Websocket connection based on the source IP address, port, and
-	  transport. ASTERISK-24143 #close Reported by: Aleksei Kulakov
-	  ........ Merged revisions 421955 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_transport_websocket.c:
-	  res_pjsip_transport_websocket: Fix a progressive memory growth.
-	  The packet structure used to receive messages was using the
-	  transport pool. This meant that for each parsing the pool would
-	  grow accordingly. Since memory can not be reclaimed without
-	  resetting it this would cause the memory pool to grow and grow.
-	  This change uses a specific memory pool for the packet structure
-	  and resets it to a fresh state after the message has been
-	  received and handled. ........ Merged revisions 421939 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_transport_websocket.c:
-	  res_pjsip_transport_websocket: Ensure secure Websocket clients
-	  can be called. This change enforces the transport in the Contact
-	  header for Websocket clients. Previously a client may provide a
-	  transport of 'ws' when it is actually using a transport of 'wss'.
-	  This would cause outgoing calls to fail as the existing
-	  connection could not be found. ........ Merged revisions 421931
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_sip.c: chan_sip: Use the server reflexive ICE
-	  candidate RTCP port as provided. This code originally worked
-	  around an issue within res_rtp_asterisk itself. The wrong socket
-	  was being used for the STUN check for RTCP, causing the port to
-	  be the same as RTP. This was subsequently fixed and the RTCP port
-	  provided for the ICE candidate is correct and does not need to be
-	  incremented. ASTERISK-23997 #close Reported by: Badalian
-	  Vyacheslav Patches: plus1.diff submitted by Badalian Vyacheslav
-	  (license 5249) ........ Merged revisions 421909 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421910 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25407 #close
+	  Reported by: Elazar Broad
+	  Tested by: Elazar Broad
 
-2014-08-22 16:56 +0000 [r421882]  Mark Michelson <mmichelson at digium.com>
+	  Change-Id: Ie2a2416bc00cce1b04e99ef40917c2011953ddd2
 
-	* apps/app_mixmonitor.c: Fix a locking inversion in MixMonitor. We
-	  need to unlock the audiohook before trying to lock the channel,
-	  since the correct locking order is channel then audiohook.
+2015-09-21 18:06 +0000 [455a31476b]  Kevin Harwell <kharwell at digium.com>
 
-2014-08-22 16:44 +0000 [r421880]  Jonathan Rose <jrose at digium.com>
+	* app_record: RECORDED_FILE variable not being populated
 
-	* res/res_stasis_answer.c, res/res_stasis.c, res/stasis/command.c,
-	  res/res_stasis_playback.c, /, res/stasis/control.c,
-	  res/stasis/stasis_bridge.c, res/stasis/command.h,
-	  include/asterisk/stasis_app_impl.h, res/res_stasis_recording.c:
-	  ARI: Fix a crash caused by hanging during playback to a channel
-	  in a bridge ASTERISK-24147 #close Reported by: Edvin Vidmar
-	  Review: https://reviewboard.asterisk.org/r/3908/ ........ Merged
-	  revisions 421879 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  The RECORDED_FILE variable is empty unless a '%d' is specified in the filename.
+	  This patch makes it so the variable is always set to the filename.
 
-2014-08-22 14:08 +0000 [r421860]  Matthew Jordan <mjordan at digium.com>
+	  ASTERISK-25410 #close
 
-	* main/message.c, /: main/message: Add a new-line to a DEBUG
-	  message ........ Merged revisions 421859 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I4ec826d8eb582ae2ad184e717be8668b74d37653
 
-2014-08-21 22:07 +0000 [r421802]  Richard Mudgett <rmudgett at digium.com>
+2015-09-16 08:22 +0000 [51013b052d]  Joshua Colp <jcolp at digium.com>
 
-	* /, res/res_musiconhold.c: res_musiconhold.c: Remove obsolete
-	  REF_DEBUG code. Remove unneeded code that writes to the wrong
-	  file location in an obsolete format. ........ Merged revisions
-	  421799 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 421800 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421801 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-21 21:42 +0000 [r421790-421797]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_session.c, /: Switch from hostname to an IP address
-	  in the SDP origin line. Using the hostname in the SDP origin line
-	  may not satisfy the requirement of RFC 4566 that we use a FQDN or
-	  IP address. This change has us use the same information from the
-	  SDP connection line if possible. If not possible, we'll use the
-	  configured media address. And if that's not possible, we use the
-	  result of a PJLIB call to get the IP address of ourself.
-	  ASTERISK-23994 #close Reported by Private Name Review:
-	  https://reviewboard.asterisk.org/r/3925 ........ Merged revisions
-	  421796 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/stasis/control.c: Ensure after-bridge behavior is correct
-	  when moving from Stasis to a non-Stasis bridge. Because of the
-	  departable state of channels that enter Stasis bridges, Stasis
-	  has to take responsibility for directing the channel to its
-	  intended after-bridge destination if the channel moves from a
-	  Stasis bridge to a non-Stasis bridge. This change ensures that
-	  when such a move occurs, when the channel leaves the bridging
-	  system, any after bridge gotos are honored. Review:
-	  https://reviewboard.asterisk.org/r/3920 ........ Merged revisions
-	  421792 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_caller_id.c, /: Let's try checking the name and
-	  number, instead of the name twice. ........ Merged revisions
-	  421789 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-21 21:25 +0000 [r421788]  Jonathan Rose <jrose at digium.com>
-
-	* /, res/res_musiconhold.c: res_musiconhold: Fix reference leaks
-	  caused when reloading with REF_DEBUG set Due to a faulty function
-	  for debugging reference decrementing, it was possible to reduce
-	  the refcount on the wrong object if two moh classes of the same
-	  name were in the moh class container. (closes issue
-	  ASTERISK-22252) Reported by: Walter Doekes Patches:
-	  18_moh_debug_ref_patch.diff Uploaded by Jonathan Rose (license
-	  6182) ........ Merged revisions 398937 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421777 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421779 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* pbx: Update device and presence state when changing a hint extension.
 
-2014-08-21 21:18 +0000 [r421783]  Mark Michelson <mmichelson at digium.com>
+	  When changing a hint extension without removing the hint first the
+	  device state and presence state is not updated. This causes the state
+	  of the hint to be that of the previous extension and not the current
+	  one. This state is kept until a state change occurs as a result of
+	  something (presence state change, device state change).
 
-	* /, res/res_pjsip_caller_id.c: Improve consistency of party ID
-	  privacy usage. Prior to this change, the Remote-Party-ID header
-	  took the position of "If caller name and number are not
-	  explicitly allowed, then they are private" and
-	  P-Asserted-Identity took the position of "Caller name and number
-	  are only private if marked explicitly so" Now both mechanisms of
-	  conveying party identification use the former approach. ........
-	  Merged revisions 421778 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This change updates the hint with the current device and presence
+	  state of the new extension when it is changed. Any state callbacks
+	  which may have been added before the hint extension is changed are
+	  also informed of the new device and presence state if either have
+	  changed.
 
-2014-08-21 17:34 +0000 [r421675-421720]  Matthew Jordan <mjordan at digium.com>
+	  ASTERISK-25394 #close
 
-	* /, channels/chan_sip.c: chan_sip: Don't use port derived from
-	  fromdomain if it isn't set If a user does not provide a port in
-	  the fromdomain setting, chan_sip will set the fromdomainport to
-	  STANDARD_SIP_PORT (5060). The fromdomainport value will then get
-	  used unilaterally in certain places. This causes issues with TLS,
-	  where the default port is expected to be 5061. This patch
-	  modifies chan_sip such that fromdomainport is only used if it is
-	  not the standard SIP port; otherwise, the port from the SIP pvt's
-	  recorded self IP address is used. Review:
-	  https://reviewboard.asterisk.org/r/3893/ ASTERISK-24178 #close
-	  Reported by: Elazar Broad patches: fromdomainport_fix.diff
-	  uploaded by Elazar Broad (License 5835) ........ Merged revisions
-	  421717 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 421718 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421719 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, UPGRADE.txt, main/app.c: ARI: Fix implicit answer when
-	  playback is initiated on unanswered channel When issuing a POST
-	  /channels/{channel_id}/play on a channel that is not yet
-	  answered, ARI is supposed to: * Queue up an AST_CONTROL_PROGRESS
-	  on the channel * Start up the playback of the media Instead, we
-	  sneak an answer on the channel right before starting playing
-	  media. This is due to ARI's usage of control_streamfile. This
-	  function implicitly answers the channel (and doesn't give ARI the
-	  option to stop it). The answering of the channel here is probably
-	  unnecessary: * app_voicemail, by far the biggest consumer of this
-	  function, always answers the channels anyway * control stream
-	  file (in res_agi) and ControlPlayback probably shouldn't be
-	  implicitly answering the channel. Answering should not be tied
-	  directly to playing back media. As it turns out, the answering of
-	  the channel here is pretty old: 356042 twilson if
-	  (ast_channel_state(chan) != AST_STATE_UP) { 3087 anthm res =
-	  ast_answer(chan); 180259 tilghman } (As in, ancient?) Note that
-	  others ran into this problem and commented about it on various
-	  mailing lists. Review: https://reviewboard.asterisk.org/r/3907/
-	  ASTERISK-24229 #close Reported by: Matt Jordan ........ Merged
-	  revisions 421695 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/stasis/messaging.h, main/dns.c, /, main/format_cache.c: Clean
-	  up files that do not end with newlines Trivial patch to add new
-	  lines to several files missing them. This fixes warnings when
-	  compiling with gcc 4.1.2 on CentOS 5. ASTERISK-24245 #close
-	  Reported by: Shaun Ruffell patches:
-	  0002-Trivial-addition-of-newlines-at-end-of-three-files.patch
-	  uploaded by Shaun Ruffell (License 5417) ........ Merged
-	  revisions 421677 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/uri.h, main/uri.c: uri: Quiet warning about type
-	  qualifiers ignored on function return type This patch fixes gcc
-	  warnings that occur due to the type qualifier 'const' being
-	  ignored on a return type of int. ASTERISK-24246 #close Reported
-	  by: Shaun Ruffell patches:
-	  0001-main-uri-Quiet-warning-about-ignored-attribute-on-re.patch
-	  uploaded by Shaun Ruffell (License 5417)
-
-2014-08-20 22:49 +0000 [r421616-421645]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/bridge.c, res/res_pjsip_sdp_rtp.c, main/file.c,
-	  main/bridge_channel.c, channels/chan_pjsip.c, main/channel.c:
-	  chan_pjsip: Update media translation paths when new SDP
-	  negotiated. On a SIP reinvite that changes media strams, the
-	  PJSIP channel driver was flooding the log with "Asked to transmit
-	  frame type %s, while native formats is %s" warnings. * Fixes
-	  PJSIP not setting up translation paths when the formats change on
-	  a reinvite. AFS-63 was effectively reintroduced because of the
-	  media formats work. res_pjsip_sdp_rtp.c:set_caps() * Improved the
-	  unexpected frame format WARNING message to include more
-	  information. * Added protective locking while altering formats on
-	  a channel. Reworked set_format() to simplify and protect the
-	  formats under manipulation. * Restored some code that got lost in
-	  the media_formats work. (channel.c:set_format() and
-	  res_pjsip_sdp_rtp.c:set_caps()) AFS-137 #close Reported by: Mark
-	  Michelson Review: https://reviewboard.asterisk.org/r/3906/
+	  Change-Id: If268f1110290e502c73dd289c9e7e7b27bc8432f
 
-	* /, main/cli.c: cli.c: Fix tab completion of "module load" when
-	  MALLOC_DEBUG is enabled. filename_completion_function() returns
-	  memory that was not allocated by the MALLOC_DEBUG allocation
-	  tracker so the memory must be freed by ast_std_free(). ........
-	  Merged revisions 421600 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421602 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421608 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-20 20:40 +0000 [r421566-421585]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pubsub.c: Set the role for inbound subscriptions
-	  correctly. This was causing the AMI show_subscriptions test in
-	  the testsuite to fail since all subscriptions were being seen as
-	  subscribers instead of notifiers.
-
-	* /, channels/chan_pjsip.c: Move evaluation of set_var options in
-	  pjsip to the end of channel initialization. This allows for
-	  set_var to override certain defaults such as caller ID and codec
-	  values. This also fixes a test suite regression. The "set_var"
-	  test suite test attempted to use set_var to override caller ID,
-	  but a recent change caused that to no longer work. ........
-	  Merged revisions 421565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-20 13:04 +0000 [r421538]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/stasis_bridges.h, tests/test_cel.c,
-	  res/ari/ari_model_validators.c, main/stasis_bridges.c,
-	  res/ari/ari_model_validators.h, rest-api/api-docs/events.json, /,
-	  res/stasis/app.c, main/bridge.c: Stasis: Add information to blind
-	  transfer event When a blind transfer occurs that is forced to
-	  create a local channel pair to satisfy the transfer request,
-	  information about the local channel pair is not published. This
-	  adds a field to describe that channel to the blind transfer
-	  message struct so that this information is conveyed properly to
-	  consumers of the blind transfer message. This also fixes a bug in
-	  which Stasis() was unable to properly identify the channel that
-	  was replacing an existing Stasis-controlled channel due to a
-	  blind transfer. Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3921/ ........ Merged
-	  revisions 421537 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-19 20:28 +0000 [r421448-421488]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip.c: Alter documentation for callerid_privacy to
-	  use correct values. ........ Merged revisions 421485 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis.c, /: Fix compilation error on certain versions of
-	  GCC. ........ Merged revisions 421447 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-19 19:42 +0000 [r421445]  Kinsey Moore <kmoore at digium.com>
+2015-09-17 04:52 +0000 [2fcf45e9cf]  Walter Doekes <walter+asterisk at wjd.nu>
 
-	* main/manager.c, /: AMI Docs: Fix Status channel parameter
-	  optionality ........ Merged revisions 421442 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421443 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421444 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-19 16:28 +0000 [r421423]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_stasis.c, /: ARI: Fix a bug where
-	  /channels/{channelID}/continue doesn't execute PBX If
-	  /channels/{channelID}/continue is called on a channel that was
-	  originated without a PBX (such as the ARI command POST channel
-	  with a stasis application argument), the channel will not start
-	  dialplan execution. This patch will now run the PBX out of the
-	  stasis execution if the channel doesn't currently have an active
-	  PBX upon continuing. ASTERISK-24043 #close Reported by: Krandon
-	  Bruse Review: https://reviewboard.asterisk.org/r/3917/ Patches:
-	  stasis-continue.diff submitted by Krandon Bruse (license 6631)
-	  ........ Merged revisions 421416 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-19 16:11 +0000 [r421403]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_pjsip_caller_id.c, channels/chan_pjsip.c,
-	  res/res_pjsip_session.c: chan_pjsip: Fix attended transfer
-	  connected line name update. A calls B B answers B SIP attended
-	  transfers to C C answers, B and C can see each other's connected
-	  line information B completes the transfer A has number but no
-	  name connected line information about C while C has the full
-	  information about A I examined the incoming and outgoing party id
-	  information handling of chan_pjsip and found several issues: *
-	  Fixed ast_sip_session_create_outgoing() not setting up the
-	  configured endpoint id as the new channel's caller id. This is
-	  why party A got default connected line information. * Made
-	  update_initial_connected_line() use the channel's CALLERID(id)
-	  information. The core, app_dial, or predial routine may have
-	  filled in or changed the endpoint caller id information. * Fixed
-	  chan_pjsip_new() not setting the full party id information
-	  available on the caller id and ANI party id. This includes the
-	  configured callerid_tag string and other party id fields. * Fixed
-	  accessing channel party id information without the channel lock
-	  held. * Fixed using the effective connected line id without doing
-	  a deep copy outside of holding the channel lock. Shallow copy
-	  string pointers can become stale if the channel lock is not held.
-	  * Made queue_connected_line_update() also update the channel's
-	  CALLERID(id) information. Moving the channel to another bridge
-	  would need the information there for the new bridge peer. * Fixed
-	  off nominal memory leak in update_incoming_connected_line(). *
-	  Added pjsip.conf callerid_tag string to party id information from
-	  enabled trust_inbound endpoint in caller_id_incoming_request().
-	  AFS-98 #close Reported by: Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3913/ ........ Merged
-	  revisions 421400 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-18 21:10 +0000 [r421376]  Damien Wedhorn <voip at facts.com.au>
-
-	* channels/chan_skinny.c: Skinny: Fixup compile warning for non
-	  dev-mode.
-
-2014-08-18 20:19 +0000 [r421337]  George Joseph <george.joseph at fairview5.com>
+	* chan_sip: Fix From header truncation for extremely long CALLERID(name).
 
-	* funcs/func_config.c, /: func_config: Change 'Not Found' message
-	  from ERROR to DEBUG When you call the CONFIG dialplan function
-	  with the name of a variable that doesn't exist in the target
-	  context you get an ERROR. This does nothing but clutter up the
-	  logs with messages that may be perfectly acceptable. Just because
-	  a variable wasn't in the context doesn't mean it's an error.
-	  Maybei t's optional or just needs to be defaulted or ignored.
-	  This patch changes the log level from ERROR to DEBUG. If a
-	  dialplan developer wants to debug their dialplan they still canby
-	  setting the console debug level as needed. Tested by: George
-	  Joseph Review: https://reviewboard.asterisk.org/r/3919/ ........
-	  Merged revisions 421327 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421328 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421329 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-18 01:13 +0000 [r421230-421312]  Matthew Jordan <mjordan at digium.com>
-
-	* res/ari/resource_channels.c: res/ari/resource_channels: Fix
-	  compilation issue Forgot a parameter. Whoops.
-
-	* res/ari/resource_channels.c: res/ari/resource_channels: Don't
-	  return allocation failure on failed function If a function fails
-	  to execute, it is most likely due to one of two reasons: (1) The
-	  function doesn't exist or can't be read from (2) The function is
-	  dangerous and is restricted based on the user's permissions
-	  Currently we return allocation failure, which is incorrect. This
-	  updates the reason code to more accurately reflect why the
-	  request failed. ASTERISK-24215
-
-	* /, apps/app_meetme.c: apps/app_meetme: Fix crash when publishing
-	  MeetMe messages with no channel The same function,
-	  meetme_stasis_generate_msg, handles creating and publishing
-	  Stasis message both when there are channels in the MeetMe
-	  conference and when there are no channels in the conference. When
-	  the performance improvement was made to use cached snapshots,
-	  this created a situation where Asterisk would crash: obtaining a
-	  cached snapshot is not NULL tolerant. This patch restores the
-	  previous implementation, which used a NULL safe set of routines
-	  to produce a blob containing the channel snapshot (if available)
-	  and information about the MeetMe conference. ASTERISK-24234
-	  #close Reported by: Shaun Ruffell Tested by: Shaun Ruffell
-	  ........ Merged revisions 421270 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  The CALLERID(num) and CALLERID(name) and other info are placed into the
+	  `char from[256]` in initreqprep. If the name was too long, the addr-spec
+	  and params wouldn't fit.
 
-	* apps/app_dial.c, /: apps/app_dial: Fix Dial 'z' option The 'z'
-	  option is supposed to disable the dial timeout in the case of a
-	  call forward. Unfortunately, the wrong timeout timer was passed
-	  to the do_forward function, resulting in the option not working.
-	  ASTERISK-24225 #close Reported by: dimitripietro Tested by:
-	  dimitripietro patches: jira_asterisk_24225_v1.8.patch uploaded by
-	  rmudgett (License 5621) jira_asterisk_24225_v11.patch uploaded by
-	  rmudgett (License 5621) ........ Merged revisions 421232 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421233 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421234 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Code is moved around so the addr-spec with params is placed there first,
+	  and then fitting in as much of the display-name as possible.
 
-	* /, configure, configure.ac: configure: Undefine FORTIFY_SOURCE
-	  prior to defining it for patched gcc Some distributions of Linux
-	  patch gcc to define FORTIFY_SOURCE when gcc is executed with
-	  optimization. This "help" unfortunately results in re-definition
-	  warnings when FORTIFY_SOURCE is later defined in Asterisk's build
-	  system. This patch undefines FORTIFY_SOURCE prior to defining it
-	  to prevent this warning. Review:
-	  https://reviewboard.asterisk.org/r/3912/ ASTERISK-24032 #close
-	  Reported by: Kilburn Tested by: Kilburn, wdoekes patches:
-	  1.8.diff uploaded by cloos (License 5956) 10.diff uploaded by
-	  cloos (License 5956) 11.diff uploaded by cloos (License 5956)
-	  12.diff uploaded by cloos (License 5956) 13.diff uploaded by
-	  cloos (License 5956) ........ Merged revisions 421227 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421228 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421229 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25396 #close
 
-2014-08-17 16:10 +0000 [r421210]  Joshua Colp <jcolp at digium.com>
+	  Change-Id: I33632baf024f01b6a00f8c7f35c91e5f68c40260
 
-	* res/res_http_websocket.c: res_http_websocket: Include query
-	  parameters in client connection requests. Review:
-	  https://reviewboard.asterisk.org/r/3914/
+2015-08-28 16:06 +0000 [c7f8c8c35d]  Alexander Traud <pabstraud at compuserve.com>
 
-2014-08-15 17:08 +0000 [r421187]  Jonathan Rose <jrose at digium.com>
+	* translate: Fix transcoding while different in frame size.
 
-	* main/channel.c, /: Bridging: Fix a behavioral change when
-	  checking if a channel is leaving a bridge r420934 introduced some
-	  failures in the test suite. Upon investigating, it was discovered
-	  that differences in the way we were evaluating whether a channel
-	  was in the process of leaving a bridge were causing some
-	  reinvites not to occur (mostly reinvites back to Asterisk when
-	  ending a call). This patch fixes that behavioral change.
-	  ASTERISK-24027 #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3910/ ........ Merged
-	  revisions 421186 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  When Asterisk translates between codecs each with a different frame size (for
+	  example between iLBC 30 and Speex-WB), too large frames were created by
+	  ast_trans_frameout. Now, ast_trans_frameout is called with the correct frame
+	  length, creating several frames when necessary. Affects all transcoding modules
+	  which used ast_trans_frameout: GSM, iLBC, LPC10, and Speex.
 
-2014-08-15 15:45 +0000 [r421042-421166]  Matthew Jordan <mjordan at digium.com>
+	  ASTERISK-25353 #close
 
-	* apps/app_voicemail.c, /, main/app.c: app_voicemail/app: Remove
-	  test events that were duplicated by r421059 Moving the test event
-	  raised when a file is played back (which occurred in r421059)
-	  broke the ever loving snot out of the voicemail tests. This
-	  caused duplicate test events to get raised, as app_voicemail and
-	  main/app were raising events prior to call ast_streamfile. The
-	  voicemail tests did not enjoy getting multiple events. Since
-	  raising the playback event in ast_streamfile is far more useful
-	  to the vast majority of tests, this patch keeps the call there
-	  and simply removes the extraneous calls that duplicated the
-	  event. ........ Merged revisions 421125 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421164 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421165 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_hep_rtcp.c, /: res/res_hep_rtcp: Remove dependency on
-	  PJSIP The res_hep_rtcp module was incorrectly including
-	  <pjsip.h>. This didn't need to be included, as the module does
-	  not using PJPROJECT any fashion. Unfortunately, because
-	  res_hep_rtcp did not include pjsip in its MODULEINFO as a
-	  dependency, this also meant that res_hep_rtcp will fail to
-	  compile on a system without PJPROJECT. This patch removes the
-	  include. Thanks to Damien Wedhorn for pointing this out in
-	  #asterisk-dev. ASTERISK-24236 #close Reported by: Damien Wedhorn,
-	  Matt Jordan Tested by: Damien Wedhorn ........ Merged revisions
-	  421064 from http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I84b59f7a745955820f10e20f5999eb69495a68b9
 
-	* /, main/file.c, main/app.c: main/file: Move test event to emit
-	  PLAYBACK event more consistently This is being done in advance of
-	  the test for ASTERISK-23953 ........ Merged revisions 421059 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 421060 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 421061 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* tests/test_cel.c, main/cel.c, /: cel: Make sure channels in extra
-	  fields include their unique IDs as well CEL typically tracks a
-	  lot of information using the unique ID of the channel. This is
-	  typically needed due to tying events together using the linked ID
-	  of the various channels involved in a "call", which is derived
-	  from the channel ID of the oldest channel involved in a bridge
-	  (or in the case of a Dial, the parent channel). Previously, we
-	  had updated the extra fields to include the involved channel
-	  names, but forgot to put in the unique ID. This patch corrects
-	  that error. ........ Merged revisions 421037 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-14 16:32 +0000 [r420957-421010]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/ari/resource_channels.c: ARI: Originate to app local
-	  channel subscription code optimization. Reduce the scope of
-	  local_peer and only get it if the ARI originate is subscribing to
-	  the channels. Review: https://reviewboard.asterisk.org/r/3905/
-	  ........ Merged revisions 421009 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/channel_internal_api.c, main/channel.c:
-	  channel_internal_api.c: Replace some code with ao2_replace(). Use
-	  ao2_replace() instead of ao2_cleanup(); ao2_bump(). ao2_replace()
-	  has the advantange of not altering the ref count if the replaced
-	  pointer is the same. Review:
-	  https://reviewboard.asterisk.org/r/3904/
-
-	* /, res/res_pjsip_send_to_voicemail.c:
-	  res_pjsip_send_to_voicemail.c: Fix svn file properties. ........
-	  Merged revisions 420956 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-13 16:53 +0000 [r420950]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip.c, /: PJSIP: Prevent crash no-URI contacts This
-	  prevents a crash from occurring when a contact with no URI is
-	  used for the creation of an outbound out-of-dialog request with
-	  no associated endpoint. ........ Merged revisions 420949 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-13 16:07 +0000 [r420940]  Jonathan Rose <jrose at digium.com>
-
-	* main/bridge_after.c, main/channel_internal_api.c,
-	  include/asterisk/channel.h, apps/app_chanspy.c,
-	  apps/app_mixmonitor.c, apps/app_stack.c, main/bridge_channel.c,
-	  main/channel.c, main/pbx.c, /, main/framehook.c: Bridges: Fix
-	  feature interruption/unintended kick caused by external actions
-	  If a manager or CLI user attached a mixmonitor to a call running
-	  a dynamic bridge feature while in a bridge, the feature would be
-	  interrupted and the channel would be forcibly kicked out of the
-	  bridge (usually ending the call during a simple 1 to 1 call).
-	  This would also occur during any similar action that could set
-	  the unbridge soft hangup flag, so the fix for this was to remove
-	  unbridge from the soft hangup flags and make it a separate thing
-	  all together. ASTERISK-24027 #close Reported by: mjordan Review:
-	  https://reviewboard.asterisk.org/r/3900/ ........ Merged
-	  revisions 420934 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-13 14:24 +0000 [r420919]  Kinsey Moore <kmoore at digium.com>
-
-	* main/manager.c: AMI: Improve documentation for Status action
-
-2014-08-13 07:52 +0000 [r420899]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /, main/logger.c: logger: Don't store verbose-magic in the log
-	  files. In r399267, the verbose2magic stuff was edited. This time
-	  it results in magic characters in the log files for multiline
-	  messages. In trunk (and 13) this was fixed by the "stripping" of
-	  those characters from multiline messages (in r414798). This fix
-	  is altered to actually strip the characters and not replace them
-	  with blanks. Review: https://reviewboard.asterisk.org/r/3901/
-	  Review: https://reviewboard.asterisk.org/r/3902/ ........ Merged
-	  revisions 420897 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 420898 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-12 23:43 +0000 [r420879-420881]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_sip.c: chan_sip: Fix type mismatch when the format
-	  is changed. Symptom is most likely an invalid ao2 object bad
-	  magic number message or a less likely crash.
-
-	* res/res_stasis_snoop.c: res_stasis_snoop.c: Fix off nominial exit
-	  path leaving Snoop channel locked and not hungup. * Made use
-	  ast_copy_string() instead of strcpy() for snoop uniqueid for
-	  safety. There is no guarantee that the max channel uniqueid
-	  length will remain the same as the snoop uniqueid space.
-
-2014-08-12 11:17 +0000 [r420856]  Joshua Colp <jcolp at digium.com>
-
-	* apps/app_voicemail.c: app_voicemail: Fix the
-	  "test_voicemail_vm_info" unit test.
-
-2014-08-11 20:53 +0000 [r420837]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/stasis/command.c, /: res/stasis/command.c: Fix recent commit
-	  using spaces instead of tabs. ........ Merged revisions 420836
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-11 18:50 +0000 [r420808]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/playbacks.json,
-	  rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/resources.json, include/asterisk/manager.h,
-	  rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json,
-	  rest-api/api-docs/mailboxes.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json: AMI/ARI: Update version to
-	  2.5.0/1.5.0 respectively This is to support the backwards
-	  compatible changes made in the next version of Asterisk. ........
-	  Merged revisions 420805 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-11 18:46 +0000 [r420796-420803]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_stasis.c: Stasis: Use the correct return value Return
-	  the correct value instead of always returning 0 when setting
-	  internal status on unreal channels. Reported by: Richard Mudgett
-	  ........ Merged revisions 420802 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis.c, res/ari/resource_bridges.c, /,
-	  res/stasis/stasis_bridge.c, include/asterisk/stasis_app.h:
-	  Stasis: Allow internal channels directly into bridges The patch
-	  to catch channels being shoehorned into Stasis() via external
-	  mechanisms also happens to catch Announcer and Recorder channels
-	  because they aren't known to be stasis-controlled channels in the
-	  usual sense. This marks those channels as Stasis()-internal
-	  channels and allows them directly into bridges. Review:
-	  https://reviewboard.asterisk.org/r/3903/ ........ Merged
-	  revisions 420795 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-11 18:32 +0000 [r420758-420794]  Mark Michelson <mmichelson at digium.com>
-
-	* include/asterisk/stasis_app.h, main/stasis_channels.c,
-	  res/ari/resource_channels.c, CHANGES, res/res_pjsip_pubsub.c,
-	  main/manager_channels.c, apps/app_dial.c, res/stasis/app.c,
-	  res/stasis/control.c: Improve call forwarding reporting,
-	  especially with regards to ARI. This patch addresses a few
-	  issues: 1) The order of Dial events have been changed when
-	  performing a call forward. The order has now been altered to 1)
-	  Dial begins dialing channel A. 2) When A forwards the call to B,
-	  we issue the dial end event to channel A, indicating the dial is
-	  being canceled due to a forward to B. 3) When the call to channel
-	  B occurs, we then issue a new dial begin to channel B. 2) Call
-	  forwards are now reported on the calling channel, not the peer
-	  channel. 3) AMI DialEnd events have been altered to display the
-	  extension the call is being forwarded to when relevant. 4) You
-	  can now get the values of channel variables for channels that are
-	  not currently in the Stasis application. This brings the
-	  retrieval of channel variables more in line with the rest of
-	  channel read operations since they may be performed on channels
-	  not in Stasis. ASTERISK-24134 #close Reported by Matt Jordan
-	  ASTERISK-24138 #close Reported by Matt Jordan Patches:
-	  forward-shenanigans.diff uploaded by Matt Jordan (License #6283)
-	  Review: https://reviewboard.asterisk.org/r/3899
-
-	* res/res_pjsip_pubsub.c: Fix crashing unit tests with regards to
-	  RLS. The unit tests require a sorcery.conf file that has been set
-	  up to store resource lists in memory rather than retrieving from
-	  configuration. With a setup that is not conducive to running the
-	  tests, a fault in sorcery currently causes Asterisk to crash when
-	  attempting to run any of the tests. To get around the crash, this
-	  adds a function that verifies the current environment and marks
-	  the tests as "not run" if the setup is not correct.
-
-	* res/res_pjsip_pubsub.c: Fix crash encountered by the testsuite.
-	  Running testsuite tests locally produced no errors, but when run
-	  using the continuous integration framework, crashes occurred. The
-	  crashes occurred due to a refcounting error that had been fixed
-	  for a similar situation.
-
-2014-08-11 13:57 +0000 [r420742]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_hep.c, res/res_hep_pjsip.c, res/res_hep_rtcp.c: res_hep:
-	  Remove disabling of modules These modules were originally
-	  specified as being disabled, as they were introduced midstream in
-	  Asterisk 12. That makes it nicer for folks who are upgrading to a
-	  new release in the middle of Asterisk 12. That's not the case for
-	  Asterisk 13: it's a brand new release. There's no reason to have
-	  the modules disabled by default in that case.
-
-2014-08-11 10:40 +0000 [r420657-420717]  Walter Doekes <walter+asterisk at wjd.nu>
+2015-09-10 17:19 +0000 [3cf0f29310]  Mark Michelson <mmichelson at digium.com>
 
-	* /, main/utils.c: general: Fix memory Corruption in
-	  __ast_string_field_ptr_build_va. If the space left in a
-	  stringfield is between 0 and
-	  (alignof(ast_string_field_allocation)-1) adding new data would
-	  cause memory corruption, because we would assume enough space
-	  (unsigned underrun). Thanks Arnd Schmitter for reporting and
-	  finding out the cause! ASTERISK-23508 #close Reported by: Arnd
-	  Schmitter Tested by: Arnd Schmitter, JoshE Review:
-	  https://reviewboard.asterisk.org/r/3898/ ........ Merged
-	  revisions 420680 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 420715 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 420716 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* scheduler: Use queue for allocating sched IDs.
 
-	* main/tcptls.c, /: tcptls: Avoid compiler warning on non-dev-mode.
-	  ........ Merged revisions 420654 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 420655 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 420656 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-11 01:31 +0000 [r420607-420639]  Matthew Jordan <mjordan at digium.com>
-
-	* funcs/func_jitterbuffer.c: funcs/func_jitterbuffer: Tweak
-	  documentation This patch merely reformats and cleans up a bit of
-	  the jitterbuffer documentation for the wiki.
-
-	* UPGRADE.txt, configs/samples/extconfig.conf.sample, CHANGES,
-	  apps/app_queue.c,
-	  contrib/ast-db-manage/config/versions/d39508cb8d8_create_queue_rules.py
-	  (added), configs/samples/queuerules.conf.sample: app_queue: Add
-	  RealTime support for queue rules This patch gives the optional
-	  ability to keep queue rules in RealTime. It is important to note
-	  that with this patch: (a) Queue rules in RealTime are only
-	  examined on module load/reload (b) Queue rules are loaded both
-	  from the queuerules.conf file as well as the RealTime backend To
-	  inform app_queue to examine RealTime for queue rules, a new
-	  setting has been added to queuerules.conf's general section
-	  "realtime_rules". RealTime queue rules will only be used when
-	  this setting is set to "yes". The schema for the database table
-	  supports a rule_name, time, min_penalty, and max_penalty columns.
-	  min_penalty and max_penalty can be relative, if a '-' or '+'
-	  literal is provided. Otherwise, the penalties are treated as
-	  constants. For example: rule_name, time, min_penalty, max_penalty
-	  'default', '10', '20', '30' 'test2', '20', '30', '55' 'test2',
-	  '25', '-11', '+1111' 'test2', '400', '112', '333' 'test3', '0',
-	  '4564', '46546' 'test_rule', '40', '15', '50' which would result
-	  in : Rule: default - After 10 seconds, adjust QUEUE_MAX_PENALTY
-	  to 30 and adjust QUEUE_MIN_PENALTY to 20 Rule: test2 - After 20
-	  seconds, adjust QUEUE_MAX_PENALTY to 55 and adjust
-	  QUEUE_MIN_PENALTY to 30 - After 25 seconds, adjust
-	  QUEUE_MAX_PENALTY by 1111 and adjust QUEUE_MIN_PENALTY by -11 -
-	  After 400 seconds, adjust QUEUE_MAX_PENALTY to 333 and adjust
-	  QUEUE_MIN_PENALTY to 112 Rule: test3 - After 0 seconds, adjust
-	  QUEUE_MAX_PENALTY to 46546 and adjust QUEUE_MIN_PENALTY to 4564
-	  Rule: test_rule - After 40 seconds, adjust QUEUE_MAX_PENALTY to
-	  50 and adjust QUEUE_MIN_PENALTY to 15 If you use RealTime, the
-	  queue rules will be always reloaded on a module reload, even if
-	  the underlying file did not change. With the option disabled, the
-	  rules will only be reloaded if the file was modified. Review:
-	  https://reviewboard.asterisk.org/r/3607/ ASTERISK-23823 #close
-	  Reported by: Michael K patches: app_queue.c_realtime_trunk.patch
-	  uploaded by Michael K (License 6621)
-
-	* CHANGES: Update CHANGES file
-
-	* UPGRADE.txt: Update UPGRADE.txt file
-
-2014-08-08 20:08 +0000 [r420577-420592]  Jason Parker <jparker at digium.com>
-
-	* apps/app_voicemail.c: Fix build in devmode.
-
-	* CHANGES, configs/samples/voicemail.conf.sample,
-	  apps/app_voicemail.c: app_voicemail: Add the ability to specify
-	  multiple email addresses. ASTERISK-24045 Reported by: Jacob
-	  Barber Review: https://reviewboard.asterisk.org/r/3833/
-
-2014-08-08 17:53 +0000 [r420534-420562]  Matthew Jordan <mjordan at digium.com>
+	  It has been observed that on long-running busy systems, a scheduler
+	  context can eventually hit INT_MAX for its assigned IDs and end up
+	  overflowing into a very low negative number. When this occurs, this can
+	  result in odd behaviors, because a negative return is interpreted by
+	  callers as being a failure. However, the item actually was successfully
+	  scheduled. The result may be that a freed item remains in the scheduler,
+	  resulting in a crash at some point in the future.
 
-	* channels/chan_sip.c, channels/sip/security_events.c,
-	  channels/sip/dialplan_functions.c, channels/sip/reqresp_parser.c,
-	  channels/sip/route.c, channels/sip/utils.c,
-	  channels/sip/config_parser.c: chan_sip: Mark chan_sip and its
-	  files as extended support
+	  The scheduler can overflow because every time that an item is added to
+	  the scheduler, a counter is bumped and that counter's current value is
+	  assigned as the new item's ID.
 
-	* rest-api-templates/make_ari_stubs.py: make_ari_stubs: Update wiki
-	  prefix to '13'
+	  This patch introduces a new method for assigning scheduler IDs. Instead
+	  of assigning from a counter, a queue of available IDs is maintained.
+	  When assigning a new ID, an ID is pulled from the queue. When a
+	  scheduler item is released, its ID is pushed back onto the queue. This
+	  way, IDs may be reused when they become available, and the growth of ID
+	  numbers is directly related to concurrent activity within a scheduler
+	  context rather than the uptime of the system.
 
-	* rest-api-templates/res_ari_resource.c.mustache:
-	  res_ari_resource.c.mustache: Update template to emit module
-	  support level
+	  Change-Id: I532708eef8f669d823457d7fefdad9a6078b99b2
 
-	* main/message.c, /: main/message: remove debug message ........
-	  Merged revisions 420533 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-09 16:46 +0000 [198a1cab8e]  Alexander Anikin <may213 at yandex.ru>
 
-2014-08-08 03:03 +0000 [r420514]  Kinsey Moore <kmoore at digium.com>
+	* chan_ooh323: Add ProgressIndicator IE with inband info available
 
-	* tests/test_cel.c, /: CEL: Update unit tests for additional
-	  information This updates the CEL unit tests for the new
-	  information contained in the attended transfer CEL extra field.
-	  ........ Merged revisions 420513 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Add ProgressIndicator IE with inband info present to Progress and
+	  Alerting Q.931 message
 
-2014-08-08 01:31 +0000 [r420494-420496]  Matthew Jordan <mjordan at digium.com>
+	  ASTERISK-25227 #close
+	  Reported by: Alexandr Dranchuk
 
-	* UPGRADE.txt: Update UPGRADE file for 13 branch
+	  Change-Id: I326ad13cb1db9a72b3fd902bafed3c28a3684203
+2015-09-04 16:33 +0000 [819760baec]  David M. Lee <dlee at respoke.io>
 
-	* /: Remove old properties
+	* res_rtp_asterisk: Add more ICE debugging
 
-	* / (added): ___ _ _ _ __ _____ / _ \ | | (_) | | / ||____ | / /_\
-	  \___| |_ ___ _ __ _ ___| | __ `| | / / | _ / __| __/ _ | '__| /
-	  __| |/ / | | \ \ | | | \__ | || __| | | \__ | < _| |.___/ / \_|
-	  |_|___/\__\___|_| |_|___|_|\_\ \___\____/
+	  In working through a recent ICE negotiation bug, I found the debug
+	  logging in res_rtp_asterisk to be lacking. This patch adds a number of
+	  debug and warning statements that were helpful.
 
-2014-08-07 21:58 +0000 [r420437]  Richard Mudgett <rmudgett at digium.com>
+	  Change-Id: I950c6d8f13a41f14b3d6334b4cafe7d4e997be80
 
-	* /, channels/chan_sip.c: chan_sip: Replace sip_tls_read() and
-	  resolve the large SDP poll issue. Replace sip_tls_read() and
-	  sip_tcp_read() with a single function and resolve the poll/wait
-	  issue with large SDP payloads. ASTERISK-18345 #close Reported by:
-	  Stephane Chazelas Patches: tcptls_pollv4.diff (license #5835)
-	  patch uploaded by Elazar Broad Review:
-	  https://reviewboard.asterisk.org/r/3882/ ........ Merged
-	  revisions 420434 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 420435 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 420436 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-07 21:17 +0000 [r420389-420415]  Kinsey Moore <kmoore at digium.com>
-
-	* main/stasis_bridges.c, /: Stasis: Correct blind transfer message
-	  generation This fixes the json object creation format string and
-	  key name for the BridgeBlindTransfer Stasis event allowing it to
-	  be published properly. ........ Merged revisions 420414 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_bridges.c, /: Stasis: Ensure transfer messages follow
-	  validation rules This makes Stasis() event generation for
-	  transfer messages follow validation rules. Currently,
-	  ast_json_null() is being used in place of omitting a key entirely
-	  which falls afoul of these validation rules.
-	  https://reviewboard.asterisk.org/r/3892/ ........ Merged
-	  revisions 420408 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pubsub.c: Fix build in dev mode
-
-2014-08-07 19:44 +0000 [r420384-420388]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/bridge.c: Ensure bridges exist when trying to determine
-	  bridged parties when publishing transfer information. ........
-	  Merged revisions 420387 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/strings.c, include/asterisk/res_pjsip_presence_xml.h,
-	  res/res_pjsip_mwi.c, res/res_pjsip_dialog_info_body_generator.c,
-	  res/res_pjsip_xpidf_body_generator.c, include/asterisk/strings.h,
-	  res/res_pjsip_pubsub.c, res/res_pjsip_exten_state.c,
-	  include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_pidf_body_generator.c: Add support for RFC 4662
-	  resource list subscriptions. This commit adds the ability for a
-	  user to configure a resource list in pjsip.conf. Subscribing to
-	  this list simultaneously subscribes the subscriber to all
-	  resources listed. This has the potential to reduce the amount of
-	  SIP traffic when loads of subscribers on a system attempt to
-	  subscribe to each others' states.
-
-2014-08-07 18:51 +0000 [r420364]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/format_compatibility.h,
-	  channels/iax2/format_compatibility.c,
-	  channels/iax2/include/codec_pref.h, main/format_compatibility.c,
-	  channels/chan_iax2.c, channels/iax2/codec_pref.c,
-	  channels/iax2/include/format_compatibility.h: chan_iax2: Several
-	  media format fixes. * Fixed the iax.conf bandwidth option. This
-	  is the root cause of ASTERISK-24150. * Added checks in
-	  iax2_request() to ensure that there are actual formats requested
-	  for the new channel to prevent any more fracks from issues like
-	  ASTERISK-24150. This is a consequence of the iax.conf bandwidth
-	  option not working. * Fixed struct iax2_codec_pref.order member
-	  size mismatch issue when converting to and from the codec
-	  preference order list passed over the wire. In addition the
-	  values sent over the wire are now compatible with previous
-	  Asterisk versions. * Fixed several issues dealing with the struct
-	  iax2_codec_pref members. Off-by-one, array limit errors, and the
-	  order/framing members always need to be updated together. * Made
-	  iax2_request() setup the channel's native format preference order
-	  according to the user's wishes. The new media format strategy
-	  needs the order specified earler. * Fixed usage of
-	  ast_format_compatibility_bitfield2format(). The function can
-	  return NULL if the bitfield was not associated with a function. *
-	  Deleted dead code iax2_codec_pref_getsize() and
-	  iax2_codec_pref_setsize(). * Made iax2_parse_allow_disallow() and
-	  iax2_codec_pref_string() call iax2_codec_pref_to_cap() instead of
-	  inlining it. * Made IAX_CAPABILITY_MEDBANDWIDTH,
-	  IAX_CAPABILITY_LOWBANDWIDTH, and IAX_CAPABILITY_LOWFREE constants
-	  again as they were in Asterisk v1.8. * Renamed prefs to
-	  prefs_global so it won't get confused with the local pref
-	  versions. * Fixed too small buffer in
-	  handle_cli_iax2_show_peer(). * Fixed ast_cli() calls in
-	  handle_cli_iax2_show_peer() to output complete lines. * Changed
-	  struct create_addr_info.prefs to be struct iax2_codec_pref as an
-	  optimization so iax2_request() and iax2_call() do less work. *
-	  Fixed a potential deadlock in ast_iax2_new() on an off-nominal
-	  path when the pbx could not get started. * Made set_config()
-	  setup a local prefs list along side the local capability format
-	  bitfield. Once the config is loaded, then the local copies are
-	  put into the global versions. * Fix unininialized codec_buf in
-	  function_iaxpeer(). ASTERISK-24150 #close Reported by: Scott
-	  Griepentrog Review: https://reviewboard.asterisk.org/r/3890/
-
-2014-08-07 15:30 +0000 [r420338]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/bridge_features.h, res/res_stasis.c,
-	  res/stasis/command.c, rest-api/api-docs/events.json, /,
-	  res/stasis/app.c, res/stasis/control.c, main/bridge.c,
-	  main/bridge_basic.c, res/stasis/stasis_bridge.c,
-	  include/asterisk/stasis_bridges.h, res/stasis/command.h,
-	  include/asterisk/stasis_app.h, res/stasis/app.h,
-	  res/stasis/control.h, apps/app_queue.c,
-	  res/ari/ari_model_validators.c, main/cel.c,
-	  main/stasis_bridges.c, res/ari/ari_model_validators.h,
-	  main/channel.c, include/asterisk/datastore.h, tests/test_cel.c:
-	  Stasis: Convey transfer information to applications This fixes a
-	  class of issues where Stasis applications were not made aware
-	  that their channels were being manipulated or replaced by
-	  external entitiessuch as transfers, AMI commands, or dialplan
-	  applications such as Bridge(). Inconsistent information such as
-	  StasisEnd events with unknown channels as a result of masquerades
-	  has also been corrected. To accomplish these fixes, several new
-	  fields were added to blind and attended transfer messages as well
-	  as StasisStart and BridgeAttendedTransfer Stasis events.
-	  ASTERISK-23941 #close Review:
-	  https://reviewboard.asterisk.org/r/3865/ Review:
-	  https://reviewboard.asterisk.org/r/3857/ Review:
-	  https://reviewboard.asterisk.org/r/3852/ Review:
-	  https://reviewboard.asterisk.org/r/3816/ Review:
-	  https://reviewboard.asterisk.org/r/3731/ Review:
-	  https://reviewboard.asterisk.org/r/3729/ Review:
-	  https://reviewboard.asterisk.org/r/3728/ ........ Merged
-	  revisions 420325 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-07 14:37 +0000 [r420314-420315]  Joshua Colp <jcolp at digium.com>
-
-	* include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_pubsub.exports.in, res/res_pjsip_publish_asterisk.c
-	  (added), res/res_pjsip_pubsub.c: res_pjsip_publish_asterisk: Add
-	  support for exchanging device and mailbox state using SIP. This
-	  module uses the inbound and outbound PUBLISH support to exchange
-	  device and mailbox state between Asterisk instances. Each
-	  instance is configured to publish to the other and requires no
-	  intermediary server. The functionality provided is similar to the
-	  XMPP and Corosync support. Review:
-	  https://reviewboard.asterisk.org/r/3780/
-
-	* include/asterisk/res_pjsip_outbound_publish.h (added),
-	  res/res_pjsip_outbound_publish.exports.in (added),
-	  res/res_pjsip_outbound_publish.c (added):
-	  res_pjsip_outbound_publish: Add module which provides outbound
-	  PUBLISH support. This module implements the core parts required
-	  for doing outbound PUBLISH. It takes care of configuration,
-	  lifetime management, and authentication. Additional modules
-	  implement the specific events that are published. Review:
-	  https://reviewboard.asterisk.org/r/3780/
-
-2014-08-07 14:17 +0000 [r420289-420309]  Matthew Jordan <mjordan at digium.com>
-
-	* main/pbx.c: pbx: Filter out pattern matching hints in responses
-	  sent to ExtensionStateList Hints that are a pattern match are
-	  technically stored in the hint container in the same fashion as
-	  concrete implementations of hints. The pattern matching hints,
-	  however, are not "real" in the sense that things can subscribe to
-	  them: rather, they are stored in the hints container so that when
-	  a subscription is made a "real" hint can be generated for the
-	  subscription if one does not yet exist. The extension state core
-	  takes care of this correctly by matching against non-pattern
-	  matching extensions prior to pattern matching extensions. Because
-	  of this, however, the ExtensionStateList AMI action was returning
-	  pattern matching hints when executed. These hints are meaningless
-	  from the perspective of AMI clients: their state will never
-	  change, they cannot be subscribed to, and events would never
-	  normally be generated from them. As such, we now filter these out
-	  of the response.
-
-	* build_tools/post_process_documentation.py: build_tools: Skip
-	  managerEvent combining for AMI action responses AMI action
-	  responses can (and will) reference AMI events that they return.
-	  These event references and definitions should not be combined
-	  with AMI events raised elsewhere in the code, as they are
-	  specifically tied to the AMI action that raised them.
-	  ASTERISK-24156 #close Reported by: Rusty Newton
-
-2014-08-06 18:12 +0000 [r420212-420237]  Richard Mudgett <rmudgett at digium.com>
-
-	* contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py,
-	  /: Fix alembic script to work properly in offline mode. When run
-	  in offline mode, this would attempt to check the database for the
-	  presence of a type it was going to try to create. I now check the
-	  context to see if we're running in offline mode and change a
-	  parameter accordingly. ........ Merged revisions 407567 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
-	  (added), /: Add alembic script that adds contact user_agent and
-	  endpoint message_context. ........ Merged revisions 411514 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py
-	  (added), /,
-	  contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py,
-	  contrib/ast-db-manage/config.ini.sample,
-	  contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
-	  (added),
-	  contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
-	  (added), contrib/ast-db-manage/cdr.ini.sample,
-	  contrib/ast-db-manage/voicemail.ini.sample: alembic: Adjust
-	  sippeers, queue_members, and voicemail_messages tables. *
-	  Increased the sippeers useragent max string size to 255. *
-	  Changed the queue_members uniqueid to an auto incremented integer
-	  instead of a string. * Increased the voicemail_messages BLOB size
-	  to LONGBLOB on mysql. * Fixed the add_tables_for_pjsip config
-	  change version downgrade actions to drop a table it created. *
-	  Adjusted the sample alembic.ini files cdr.ini.sample,
-	  config.ini.sample, and voicemail.ini.sample to give a mysql and
-	  postgres sqlalchemy.url lines. ASTERISK-23847 #close Reported by:
-	  Stephen More ASTERISK-23825 #close Reported by: Stephen More
-	  ASTERISK-23909 #close Reported by: Stephen More Review:
-	  https://reviewboard.asterisk.org/r/3870/ ........ Merged
-	  revisions 420211 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-06 16:12 +0000 [r420149]  George Joseph <george.joseph at fairview5.com>
-
-	* /, pbx/pbx_lua.c, main/pbx.c: pbx_lua: fix regression with global
-	  sym export and context clash by pbx_config. ASTERISK-23818 (lua
-	  contexts being overwritten by contexts of the same name in
-	  pbx_config) surfaced because pbx_lua, having the
-	  AST_MODFLAG_GLOBAL_SYMBOLS set, was always force loaded before
-	  pbx_config. Since I couldn't find any reason for pbx_lua to
-	  export it's symbols to the rest of Asterisk, I simply changed the
-	  flag to AST_MODFLAG_DEFAULT. Problem solved. What I didn't
-	  realize was that the symbols need to be exported not because
-	  Asterisk needs them but because any external Lua modules like
-	  luasql.mysql need the base Lua language APIs exported
-	  (ASTERISK-17279). Back to ASTERISK-23818... It looks like there's
-	  an issue in pbx.c where context_merge was only merging includes,
-	  switches and ignore patterns if the context was already existing
-	  AND has extensions, or if the context was brand new. If pbx_lua
-	  is loaded before pbx_config, the context will exist BUT pbx_lua,
-	  being implemented as a switch, will never place extensions in it,
-	  just the switch statement. The result is that when pbx_config
-	  loads, it never merges the switch statement created by pbx_lua
-	  into the final context. This patch sets pbx_lua's modflag back to
-	  AST_MODFLAG_GLOBAL_SYMBOLS and adds an "else if" in context_merge
-	  that catches the case where an existing context has includes,
-	  switchs or ingore patterns but no actual extensions.
-	  ASTERISK-23818 #close Reported by: Dennis Guse Reported by: Timo
-	  Teräs Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3891/ ........ Merged
-	  revisions 420146 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 420147 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 420148 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-06 15:32 +0000 [r420144]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* funcs/func_channel.c: Add documentation to the ability to
-	  retrieve the source port of a SIP call. (belongs with r419970)
-	  ASTERISK-24040 #close Patches: func_channel.c.diff uploaded by
-	  dtryba Review: https://reviewboard.asterisk.org/r/3781/
-
-2014-08-06 12:55 +0000 [r420124]  Kinsey Moore <kmoore at digium.com>
-
-	* configs/samples/stasis.conf.sample (added), main/named_acl.c,
-	  apps/app_queue.c, main/stasis_bridges.c, main/loader.c,
-	  main/stasis.c, apps/app_forkcdr.c, main/stasis_message.c,
-	  funcs/func_cdr.c, res/res_corosync.c, res/res_stun_monitor.c,
-	  res/res_stasis_test.c, res/res_stasis.c, apps/app_chanspy.c,
-	  main/stasis_cache.c, main/pickup.c, main/security_events.c,
-	  include/asterisk/stasis.h, main/devicestate.c, main/core_local.c,
-	  res/res_stasis_snoop.c, main/endpoints.c, main/presencestate.c,
-	  main/cdr.c, main/channel.c, main/stasis_system.c, main/manager.c,
-	  main/test.c, main/file.c, main/app.c, pbx/pbx_realtime.c,
-	  main/stasis_channels.c, tests/test_stasis.c,
-	  res/parking/parking_manager.c, main/stasis_endpoints.c,
-	  main/rtp_engine.c, main/ccss.c, main/bridge.c,
-	  tests/test_stasis_channels.c: Stasis: Allow message types to be
-	  blocked This introduces stasis.conf and a mechanism to prevent
-	  certain message types from being published. Internally, this
-	  works by preventing the chosen message types from being created
-	  which ensures that those message types can never be published.
-	  This patch also adjusts message publishers such that message
-	  payloads are not created if the related message type is not
-	  available. ASTERISK-23943 #close Review:
-	  https://reviewboard.asterisk.org/r/3823/
-
-2014-08-05 21:48 +0000 [r420098-420100]  Matthew Jordan <mjordan at digium.com>
-
-	* res/stasis/messaging.c, /: stasis: Fix compilation issue with ao2
-	  tagged objects ........ Merged revisions 420099 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_endpoints.c, rest-api/api-docs/events.json, /,
-	  channels/chan_sip.c, res/stasis/app.c, res/stasis/messaging.h
-	  (added), res/ari/resource_endpoints.h, res/res_pjsip_messaging.c,
-	  tests/test_message.c (added), res/res_xmpp.c,
-	  include/asterisk/json.h, CHANGES, include/asterisk/manager.h,
-	  res/ari/ari_model_validators.c, res/ari/ari_model_validators.h,
-	  main/json.c, res/res_ari_endpoints.c, include/asterisk/message.h,
-	  res/ari/resource_channels.c, main/message.c, res/res_stasis.c,
-	  res/stasis/messaging.c (added), rest-api/api-docs/endpoints.json:
-	  Multiple revisions 420089-420090,420097 ........ r420089 |
-	  mjordan | 2014-08-05 15:10:52 -0500 (Tue, 05 Aug 2014) | 72 lines
-	  ARI: Add channel technology agnostic out of call text messaging
-	  This patch adds the ability to send and receive text messages
-	  from various technology stacks in Asterisk through ARI. This
-	  includes chan_sip (sip), res_pjsip_messaging (pjsip), and
-	  res_xmpp (xmpp). Messages are sent using the endpoints resource,
-	  and can be sent directly through that resource, or to a
-	  particular endpoint. For example, the following would send the
-	  message "Hello there" to PJSIP endpoint alice with a display URI
-	  of sip:asterisk at mycooldomain.org:
-	  ari/endpoints/sendMessage?to=pjsip:alice&from=sip:asterisk at mycooldomain.org&body=Hello+There
-	  This is equivalent to the following as well:
-	  ari/endpoints/PJSIP/alice/sendMessage?from=sip:asterisk at mycooldomain.org&body=Hello+There
-	  Both forms are available for message technologies that allow for
-	  arbitrary destinations, such as chan_sip. Inbound messages can
-	  now be received over ARI as well. An ARI application that
-	  subscribes to endpoints will receive messages from those
-	  endpoints: { "type": "TextMessageReceived", "timestamp":
-	  "2014-07-12T22:53:13.494-0500", "endpoint": { "technology":
-	  "PJSIP", "resource": "alice", "state": "online", "channel_ids":
-	  [] }, "message": { "from": "\"alice\" <sip:alice at 127.0.0.1>",
-	  "to": "pjsip:asterisk at 127.0.0.1", "body": "Watson, come here.",
-	  "variables": [] }, "application": "testsuite" } The above was
-	  made possible due to some rather major changes in the message
-	  core. This includes (but is not limited to): - Users of the
-	  message API can now register message handlers. A handler has two
-	  callbacks: one to determine if the handler has a destination for
-	  the message, and another to handle it. - All dialplan
-	  functionality of handling a message was moved into a message
-	  handler provided by the message API. - Messages can now have the
-	  technology/endpoint associated with them. Various other
-	  properties are also now more easily accessible. - A number of ao2
-	  containers that weren't really needed were replaced with vectors.
-	  Iteration over ao2_containers is expensive and pointless when the
-	  lifetime of things is well defined and the number of things is
-	  very small. res_stasis now has a new file that makes up its
-	  structure, messaging. The messaging functionality implements a
-	  message handler, and passes received messages that match an
-	  interested endpoint over to the app for processing. Note that
-	  inadvertently while testing this, I reproduced ASTERISK-23969.
-	  res_pjsip_messaging was incorrectly parsing out the 'to' field,
-	  such that arbitrary SIP URIs mangled the endpoint lookup. This
-	  patch includes the fix for that as well. Review:
-	  https://reviewboard.asterisk.org/r/3726 ASTERISK-23692 #close
-	  Reported by: Matt Jordan ASTERISK-23969 #close Reported by:
-	  Andrew Nagy ........ r420090 | mjordan | 2014-08-05 15:16:37
-	  -0500 (Tue, 05 Aug 2014) | 2 lines Remove automerge properties
-	  :-( ........ r420097 | mjordan | 2014-08-05 16:36:25 -0500 (Tue,
-	  05 Aug 2014) | 2 lines test_message: Fix strict-aliasing
-	  compilation issue ........ Merged revisions 420089-420090,420097
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-05 13:59 +0000 [r420028]  Jonathan Rose <jrose at digium.com>
-
-	* main/format.c: chan_iax2: Fix a crash that occurs when using
-	  allow=all for an IAX2 peer Or any combination of codecs that
-	  includes Opus. ASTERISK-24107 #close Review:
-	  https://reviewboard.asterisk.org/r/3885/
-
-2014-08-04 21:00 +0000 [r420007]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/format_cache.c, include/asterisk/format_cache.h: Remove
-	  duplicate definitions of ast_format_vp8.
-
-2014-08-04 20:25 +0000 [r419970]  Mark Michelson <mmichelson at digium.com>
-
-	* channels/sip/dialplan_functions.c: Add the ability to retrieve
-	  the source port of a SIP call. This adds the ability to call
-	  CHANNEL(recvport) on chan_sip channels to see the port on which
-	  an INVITE was received. ASTERISK-24040 #close Reported by dtryba
-	  Patches: dialplan_functions.patch uploaded by dtryba (License
-	  #6628) Review: https://reviewboard.asterisk.org/r/3781
-
-2014-08-04 19:47 +0000 [r419945]  Rusty Newton <rnewton at digium.com>
+2015-09-01 10:16 +0000 [ffa26a0c2e]  Guido Falsi <madpilot at freebsd.org>
 
-	* main/manager.c, /: Manager - Improve documentation for manager
-	  commands Getvar and Setvar. The documentation for these commands
-	  did not make it clear that they could accept expressions and
-	  functions. Modified to make this clear, but tried not to be
-	  overly explicit. ASTERISK-21178 #close Reported by: Rusty Newton
-	  Tested by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/3854 ........ Merged revisions
-	  419942 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 419943 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 419944 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-08-02 03:37 +0000 [r419914]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip.c: Manager: Add PJSIPShowEndpoint[s] documentation
-	  This adds a large swath of response documentation for
-	  PJSIPShowEndpoint and PJSIPShowEndpoints AMI commands. It relies
-	  heavily on the existing text in the configInfo documentation via
-	  xi:include tags to avoid documentation duplication. Review:
-	  https://reviewboard.asterisk.org/r/3888/
-
-2014-08-01 14:48 +0000 [r419888]  Mark Michelson <mmichelson at digium.com>
-
-	* CHANGES, res/res_pjsip/pjsip_options.c: Add ContactStatusDetail
-	  to PJSIPShowEndpoint AMI output. Now when running
-	  PJSIPShowEndpoint, you will receive a ContactStatusDetail for
-	  each bound contact that Asterisk is qualifying. This information
-	  includes the URI of the contact, current reachability, and
-	  roundtrip time. AFS-91 #close Reported by Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3797
-
-2014-07-31 16:19 +0000 [r419851]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES, res/res_pjsip_notify.c: PJSIP: Send Notify AMI and CLI
-	  commands can now send to URI instead of endpoint Review:
-	  https://reviewboard.asterisk.org/r/3817/
-
-2014-07-31 11:57 +0000 [r419822-419825]  Matthew Jordan <mjordan at digium.com>
-
-	* main/rtp_engine.c, /, res/res_hep_rtcp.c (added), CHANGES,
-	  channels/chan_pjsip.c, res/res_rtp_asterisk.c: res_hep_rtcp: Add
-	  module that sends RTCP information to a Homer Server This patch
-	  adds a new module to Asterisk, res_hep_rtcp. The module
-	  subscribes to the RTCP topics in Stasis and receives RTCP
-	  information back from the message bus. It encodes into HEPv3
-	  packets and sends the information to the res_hep module for
-	  transmission. Using this, someone with a Homer server can get
-	  live call quality monitoring for all RTP-based channels in their
-	  Asterisk 12+ systems. In addition, there were a few bugs in the
-	  RTP engine, res_rtp_asterisk, and chan_pjsip that were uncovered
-	  by the tests written for the Asterisk Test Suite. This patch
-	  fixes the following: 1) chan_pjsip failed to set its channel
-	  unique ids on its RTP instance on outbound calls. It now does
-	  this in the appropriate location, in the serialized call
-	  callback. 2) The rtp_engine was overflowing some values when
-	  packed into JSON. Specifically, some longs and unsigned ints
-	  can't be be packed into integer values, for obvious reasons.
-	  Since libjansson only supports integers, floats, strings,
-	  booleans, and objects, we print these values into strings. 3)
-	  res_rtp_asterisk had a few problems: (a) it would emit a source
-	  IP address of 0.0.0.0 if bound to that IP address. We now use
-	  ast_find_ourip to get a better IP address, and properly marshal
-	  the result into an ast_strdupa'd string. (b) Reports can be
-	  generated with no report bodies. In particular, this occurs when
-	  a sender is transmitting information to a receiver (who will send
-	  no RTP back to the sender). As such, the sender has no report
-	  body for what it received. We now properly handle this case, and
-	  the sender will emit SR reports with no body. Likewise, if we
-	  receive an RTCP packet with no report body, we will still
-	  generate the appropriate events. ASTERISK-24119 #close ........
-	  Merged revisions 419823 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* funcs/func_jitterbuffer.c, doc/appdocsxml.dtd, main/xmldoc.c:
-	  xmldocs: Add support for an <example> tag in the Asterisk XML
-	  Documentation This patch adds support for an <example /> tag in
-	  the XML documentation schema. For CLI help, this doesn't change
-	  the formatting too much: - Preceeding white space is removed -
-	  Unlike with para elements, new lines are preserved However,
-	  having an <example /> tag in the XML schema allows for the wiki
-	  documentation generation script to surround the documentation
-	  with {code} or {noformat} tags, generating much better content
-	  for the wiki - and allowing us to put dialplan examples (and
-	  other code snippets, if desired) into the documentation for an
-	  application/function/AMI command/etc. Review:
-	  https://reviewboard.asterisk.org/r/3807/
-
-2014-07-30 18:32 +0000 [r419806]  Kinsey Moore <kmoore at digium.com>
-
-	* main/manager.c, res/res_manager_presencestate.c,
-	  res/res_manager_devicestate.c, main/pbx.c: manager: Add state
-	  list commands This patch adds three new AMI commands: *
-	  ExtensionStateList (pbx.c) - list all known extension state hints
-	  and their current statuses. Events emitted by the list action are
-	  equivalent to the ExtensionStatus events. * PresenceStateList
-	  (res_manager_presencestate) - list all known presence state
-	  values. Events emitted are generated by the stasis message type,
-	  and hence are PresenceStateChange events. * DeviceStateList
-	  (res_manager_devicestate) - list all known device state values.
-	  Events emitted are generated by the stasis message type, and
-	  hence are DeviceStateChange events. Patch-by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3799/
-
-2014-07-29 19:41 +0000 [r419789]  Mark Michelson <mmichelson at digium.com>
-
-	* main/manager.c: Do not omit the first header of a UserEvent AMI
-	  action from the corresponding emitted UserEvent. ASTERISK-24124
-	  #close Reported by Matt Jordan AFS-131 #close Reported by Matt
-	  Jordan Patches: userevent.patch uploaded by Matt Jordan (License
-	  #6283)
-
-2014-07-29 10:56 +0000 [r419751-419766]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Fix race condition
-	  where redirecting information may not be set. Since the PJSIP
-	  INVITE session module is invoked before any session supplements
-	  it was possible for it to handle a redirect before the
-	  res_pjsip_diversion module interpreted and set redirecting
-	  information on the channel. This would cause the redirecting
-	  information to get lost. This patch ensures that session
-	  supplements are *always* invoked before a redirect occurs by
-	  explicitly calling them in the redirect handler. Review:
-	  https://reviewboard.asterisk.org/r/3850/ ........ Merged
-	  revisions 419764 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_xpidf_body_generator.c,
-	  res/res_pjsip_pidf_body_generator.c:
-	  res_pjsip_pidf_body_generator / res_pjsip_xpidf_body_generator:
-	  Ensure local entity is unquoted. The local entity as provided by
-	  PJSIP is quoted within '<' and '>'. As a result placing this
-	  value into XML will result in malformed XML being produced. This
-	  patch now unquotes the local entity so it can go safely into the
-	  XML. Review: https://reviewboard.asterisk.org/r/3851/ ........
-	  Merged revisions 419750 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-28 18:58 +0000 [r419688]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_speech_utils.c, main/channel.c, /,
-	  funcs/func_frame_trace.c, main/abstract_jb.c: datastores: Audit
-	  ast_channel_datastore_remove usage. Audit of v1.8 usage of
-	  ast_channel_datastore_remove() for datastore memory leaks. *
-	  Fixed leaks in app_speech_utils and func_frame_trace. * Fixed
-	  app_speech_utils not locking the channel when accessing the
-	  channel datastore list. Review:
-	  https://reviewboard.asterisk.org/r/3859/ Audit of v11 usage of
-	  ast_channel_datastore_remove() for datastore memory leaks. *
-	  Fixed leak in func_jitterbuffer. (Was not in v12) Review:
-	  https://reviewboard.asterisk.org/r/3860/ Audit of v12 usage of
-	  ast_channel_datastore_remove() for datastore memory leaks. *
-	  Fixed leaks in abstract_jb. * Fixed leak in
-	  ast_channel_unsuppress(). Used by ARI mute control and
-	  res_mutestream. * Fixed ref leak in ast_channel_suppress(). Used
-	  by ARI mute control and res_mutestream. Review:
-	  https://reviewboard.asterisk.org/r/3861/ ........ Merged
-	  revisions 419684 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 419685 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 419686 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-25 18:09 +0000 [r419612]  Joshua Colp <jcolp at digium.com>
-
-	* main/loader.c: loader: Fix an infinite loop when printing modules
-	  using "module show". When creating the alphabetical sorted list
-	  each module is added to a list temporarily. On the second
-	  iteration each module already has a pointer to another module,
-	  causing stuff to go into a loop. ASTERISK-24123 #close Reported
-	  by: Malcolm Davenport
-
-2014-07-25 16:47 +0000 [r419592]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_ari_sounds.c, res/res_stasis.c, res/res_fax_spandsp.c,
-	  res/res_timing_kqueue.c, res/res_odbc.c,
-	  res/res_pjsip_transport_websocket.c, apps/app_voicemail.c,
-	  res/res_calendar.c, channels/chan_unistim.c, cel/cel_radius.c,
-	  channels/chan_multicast_rtp.c, res/res_pjsip_notify.c,
-	  res/res_snmp.c, formats/format_sln.c, apps/app_meetme.c,
-	  apps/app_dictate.c, codecs/codec_gsm.c, res/res_stasis_snoop.c,
-	  res/res_musiconhold.c, res/res_format_attr_h264.c,
-	  res/res_http_websocket.c, apps/app_followme.c,
-	  res/res_config_sqlite.c, formats/format_siren7.c, cdr/cdr_csv.c,
-	  formats/format_ilbc.c, channels/chan_phone.c,
-	  apps/app_setcallerid.c, apps/app_osplookup.c, cel/cel_custom.c,
-	  apps/app_mp3.c, res/res_agi.c, channels/chan_motif.c,
-	  res/res_timing_timerfd.c, apps/app_confbridge.c,
-	  res/res_format_attr_silk.c, formats/format_siren14.c,
-	  res/res_sorcery_realtime.c, channels/chan_mgcp.c,
-	  apps/app_jack.c, codecs/codec_lpc10.c,
-	  res/res_pjsip_pidf_body_generator.c, res/res_config_pgsql.c,
-	  funcs/func_dialplan.c, apps/app_nbscat.c, cdr/cdr_syslog.c,
-	  res/res_pjsip_authenticator_digest.c, apps/app_festival.c,
-	  res/res_fax.c, apps/app_waitforsilence.c, res/res_adsi.c,
-	  res/res_crypto.c, res/res_ari_applications.c,
-	  res/res_hep_pjsip.c, pbx/pbx_lua.c, res/res_pjsip_messaging.c,
-	  res/res_pjsip_caller_id.c, channels/chan_console.c,
-	  apps/app_getcpeid.c, res/res_stasis_answer.c,
-	  channels/chan_oss.c, res/res_pjsip_nat.c,
-	  res/res_pjsip_session.c, cdr/cdr_tds.c,
-	  res/res_pjsip_header_funcs.c, res/res_parking.c,
-	  formats/format_vox.c, res/res_pjsip_rfc3326.c,
-	  res/res_ari_endpoints.c, res/res_stun_monitor.c,
-	  res/res_pjsip_mwi.c, res/res_stasis_recording.c,
-	  res/res_pjsip_xpidf_body_generator.c, apps/app_sms.c,
-	  codecs/codec_ulaw.c, channels/chan_nbs.c, apps/app_stack.c,
-	  channels/chan_pjsip.c, formats/format_g729.c, cel/cel_pgsql.c,
-	  res/res_sorcery_config.c, res/res_ari.c, addons/chan_ooh323.c,
-	  cdr/cdr_sqlite3_custom.c, codecs/codec_adpcm.c,
-	  res/res_ari_asterisk.c, res/res_calendar_caldav.c,
-	  apps/app_image.c, apps/app_ices.c, formats/format_wav_gsm.c,
-	  main/cli.c, res/res_format_attr_celt.c, res/res_rtp_multicast.c,
-	  channels/chan_dahdi.c, funcs/func_pitchshift.c, res/res_smdi.c,
-	  res/res_pjsip_one_touch_record_info.c, pbx/pbx_ael.c,
-	  pbx/pbx_realtime.c, apps/app_amd.c, channels/chan_alsa.c,
-	  formats/format_h263.c, apps/app_url.c, res/res_pjsip_acl.c,
-	  apps/app_externalivr.c, res/res_curl.c, formats/format_gsm.c,
-	  res/res_speech.c, cdr/cdr_manager.c, res/res_calendar_exchange.c,
-	  codecs/codec_g722.c, res/res_pjsip_multihomed.c,
-	  res/res_ari_mailboxes.c, cel/cel_tds.c, res/res_sorcery_memory.c,
-	  apps/app_fax.c, codecs/codec_speex.c, res/res_pjsip_sdp_rtp.c,
-	  codecs/codec_g726.c, formats/format_ogg_vorbis.c,
-	  apps/app_talkdetect.c, res/res_ari_channels.c,
-	  res/res_pjsip_exten_state.c, apps/app_speech_utils.c,
-	  apps/app_agent_pool.c, apps/app_waitforring.c, res/res_statsd.c,
-	  addons/cdr_mysql.c, formats/format_g726.c, res/res_ari_bridges.c,
-	  addons/app_mysql.c, res/res_stasis_playback.c,
-	  addons/format_mp3.c, res/res_pjsip_endpoint_identifier_ip.c,
-	  res/res_phoneprov.c, res/res_pjsip_t38.c,
-	  res/res_pjsip_registrar_expire.c, cdr/cdr_pgsql.c,
-	  cdr/cdr_radius.c, res/res_chan_stats.c,
-	  res/res_format_attr_opus.c, res/res_config_odbc.c,
-	  funcs/func_audiohookinherit.c,
-	  res/res_pjsip_outbound_registration.c, cel/cel_manager.c,
-	  funcs/func_odbc.c, res/res_pjsip_endpoint_identifier_anonymous.c,
-	  funcs/func_frame_trace.c, funcs/func_aes.c, cdr/cdr_sqlite.c,
-	  apps/app_minivm.c, res/res_pjsip_log_forwarder.c,
-	  formats/format_h264.c, res/res_config_ldap.c, apps/app_ivrdemo.c,
-	  addons/chan_mobile.c, apps/app_stasis.c,
-	  res/res_pjsip_diversion.c, cdr/cdr_custom.c, apps/app_adsiprog.c,
-	  res/res_pjsip_dtmf_info.c, res/res_rtp_asterisk.c,
-	  res/res_calendar_icalendar.c, res/res_hep.c, channels/chan_sip.c,
-	  channels/chan_bridge_media.c, codecs/codec_alaw.c,
-	  apps/app_queue.c, res/res_srtp.c, funcs/func_presencestate.c,
-	  res/res_timing_pthread.c, res/res_manager_presencestate.c,
-	  res/res_corosync.c, apps/app_celgenuserevent.c,
-	  cel/cel_sqlite3_custom.c, res/snmp/agent.c, pbx/pbx_dundi.c,
-	  formats/format_g723.c, funcs/func_devstate.c,
-	  res/res_pjsip_registrar.c,
-	  res/res_pjsip_pidf_eyebeam_body_supplement.c,
-	  addons/res_config_mysql.c,
-	  res/res_pjsip_pidf_digium_body_supplement.c, apps/app_test.c,
-	  res/res_timing_dahdi.c, cdr/cdr_adaptive_odbc.c,
-	  apps/app_alarmreceiver.c, apps/app_chanisavail.c,
-	  res/res_format_attr_h263.c, res/res_pjsip_mwi_body_generator.c,
-	  res/res_xmpp.c, res/res_http_post.c, channels/chan_iax2.c,
-	  res/res_pjsip_endpoint_identifier_user.c, res/res_pjsip.c,
-	  res/res_pktccops.c, res/res_pjsip_send_to_voicemail.c,
-	  main/loader.c, cel/cel_odbc.c, res/res_ari_model.c,
-	  channels/chan_skinny.c,
-	  res/res_pjsip_outbound_authenticator_digest.c,
-	  res/res_mwi_external.c, apps/app_skel.c, formats/format_pcm.c,
-	  include/asterisk/module.h, res/res_pjsip_path.c,
-	  res/res_ari_playbacks.c, res/res_pjsip_pubsub.c, cdr/cdr_odbc.c,
-	  funcs/func_periodic_hook.c, res/res_stasis_test.c,
-	  formats/format_jpeg.c, res/res_pjsip_refer.c,
-	  formats/format_g719.c, res/res_clialiases.c,
-	  res/res_config_sqlite3.c, res/res_ari_device_states.c,
-	  formats/format_wav.c, apps/app_saycounted.c, apps/app_dahdiras.c,
-	  apps/app_morsecode.c, res/res_stasis_mailbox.c,
-	  res/res_ael_share.c, res/res_mwi_external_ami.c,
-	  res/res_pjsip_logger.c, res/res_stasis_device_state.c,
-	  res/res_calendar_ews.c, res/res_monitor.c, apps/app_playback.c,
-	  res/res_ari_recordings.c, res/res_manager_devicestate.c,
-	  res/res_config_curl.c, channels/chan_misdn.c, funcs/func_curl.c,
-	  res/res_ari_events.c, res/res_pjsip_dialog_info_body_generator.c,
-	  res/res_sorcery_astdb.c, codecs/codec_dahdi.c,
-	  apps/app_zapateller.c, pbx/pbx_config.c: Add module support level
-	  to ast_module_info structure. Print it in CLI "module show" .
-	  ASTERISK-23919 #close Reported by Malcolm Davenport Review:
-	  https://reviewboard.asterisk.org/r/3802
-
-2014-07-25 14:47 +0000 [r419563-419567]  Matthew Jordan <mjordan at digium.com>
-
-	* CHANGES, res/ari/ari_model_validators.c,
-	  rest-api/api-docs/recordings.json,
-	  res/ari/ari_model_validators.h, /, res/res_stasis_recording.c:
-	  Multiple revisions 419565-419566 ........ r419565 | mjordan |
-	  2014-07-25 09:41:23 -0500 (Fri, 25 Jul 2014) | 21 lines ARI:
-	  report duration values in LiveRecording objects This patch adds
-	  three new fields to the LiveRecording model: - total_duration:
-	  the total length of the live recording - talking_duration:
-	  optional. The duration of talking energy that was detected while
-	  the recording was made. - silence_duration: optional. The
-	  duration of silence that was detected while the recording was
-	  made. These values are reported in the RecordingFinished ARI
-	  event. When a DSP is enabled on the channel during the recording
-	  - which occurs when the recording is created with
-	  max_silence_seconds (indicating that the user actually cares
-	  about how much silence is in the file), we will report the
-	  talking_duration and silence_duration in addition to the
-	  total_duration. Review: https://reviewboard.asterisk.org/r/3770/
-	  ASTERISK-24037 #close Reported by: Samuel Galarneau ........
-	  r419566 | mjordan | 2014-07-25 09:46:15 -0500 (Fri, 25 Jul 2014)
-	  | 1 line Update CHANGES for r419565 ........ Merged revisions
-	  419565-419566 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/loader.c, res/res_calendar.c: module loader: Unload modules
-	  in reverse order of their start order When Asterisk starts a
-	  module (calling its load_module function), it re-orders the
-	  module list, sorting it alphabetically. Ostensibly, this was done
-	  so that the output of 'module show' listed modules in alphabetic
-	  order. This had the unfortunate side effect of making modules
-	  with complex usage patterns unloadable. A module that has a large
-	  number of modules that depend on it is typically abandoned during
-	  the unloading process. This results in its memory not being
-	  reclaimed during exit. Generally, this isn't harmful - when the
-	  process is destroyed, the operating system will reclaim all
-	  memory allocated by the process. Prior to Asterisk 12, we also
-	  didn't have many modules with complex dependencies. However, with
-	  the advent of ARI and PJSIP, this can make make unloading those
-	  modules successfully nearly impossible, and thus tracking memory
-	  leaks or ref debug leaks a real pain. While this patch is not a
-	  complete overhaul of the module loader - such an effort would be
-	  beyond the scope of what could be done for Asterisk 13 - this
-	  does make some marginal improvements to the loader such that
-	  modules like res_pjsip or res_stasis *may* be made properly
-	  un-loadable in the future. 1. The linked list of modules has been
-	  replaced with a doubly linked list. This allows traversal of the
-	  module list to occur backwards. The module shutdown routine now
-	  walks the global list backwards when it attempts to unload
-	  modules. 2. The alphabetic reorganization of the module list on
-	  startup has been removed. Instead, a started module is placed at
-	  the end of the module list. 3. The ast_update_module_list
-	  function - which is used by the CLI to display the modules - now
-	  does the sorting alphabetically itself. It creates its own linked
-	  list and inserts the modules into it in alphabetic order. This
-	  allows for the intent of the previous code to be maintained. This
-	  patch also contains a fix for res_calendar. Without
-	  calendar.conf, the calendar modules were improperly bumping the
-	  use count of res_calendar, then failing to load themselves. This
-	  patch makes it so that we detect whether or not calendaring is
-	  enabled before altering the use count. Review:
-	  https://reviewboard.asterisk.org/r/3777/
-
-2014-07-25 10:54 +0000 [r419537-419539]  Joshua Colp <jcolp at digium.com>
-
-	* apps/app_bridgewait.c, /: app_bridgewait: Remove possibility of
-	  race condition between channels leaving/joining. Bridges created
-	  by app_bridgewait previously had the "dissolve when empty" flag
-	  set. This caused the bridge core to destroy them when the last
-	  channel had left. This introduced a race condition where we may
-	  have a reference to the bridge but it is not actually joinable
-	  when we try to join it. This flag has now been removed and the
-	  bridge is guaranteed to be joinable at all times. ASTERISK-23987
-	  #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3836/ ........ Merged
-	  revisions 419538 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/bridge.c: bridge: Make "bridge destroy" only available in
-	  developer mode and add "all" to "bridge kick". The "bridge
-	  destroy" CLI command is invasive to bridges and can leave them in
-	  an unexpected state for the users of them. Since this command may
-	  be useful for developers it is now only available when developer
-	  mode is available. To take its place "all" has been added as a
-	  valid option to the "bridge kick" CLI command. It will kick all
-	  of the channels in the bridge out. ASTERISK-23987 Reported by:
-	  Matt Jordan Review: https://reviewboard.asterisk.org/r/3840/
-	  ........ Merged revisions 419536 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-24 22:48 +0000 [r419520]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/bridge.c, main/bridge_basic.c, main/core_unreal.c,
-	  UPGRADE.txt, include/asterisk/channel.h, CHANGES,
-	  apps/app_followme.c, apps/app_queue.c, main/cel.c,
-	  res/parking/parking_bridge_features.c, apps/app_dial.c,
-	  main/channel.c, main/dial.c, main/pbx.c: accountcode: Slightly
-	  change accountcode propagation. The previous behavior was to
-	  simply set the accountcode of an outgoing channel to the
-	  accountcode of the channel initiating the call. It was done this
-	  way a long time ago to allow the accountcode set on the SIP/100
-	  channel to be propagated to a local channel so the dialplan
-	  execution on the Local;2 channel would have the SIP/100
-	  accountcode available. SIP/100 -> Local;1/Local;2 -> SIP/200
-	  Propagating the SIP/100 accountcode to the local channels is very
-	  useful. Without any dialplan manipulation, all channels in this
-	  call would have the same accountcode. Using dialplan, you can set
-	  a different accountcode on the SIP/200 channel either by setting
-	  the accountcode on the Local;2 channel or by the Dial
-	  application's b(pre-dial), M(macro) or U(gosub) options, or by
-	  the FollowMe application's b(pre-dial) option, or by the Queue
-	  application's macro or gosub options. Before Asterisk v12, the
-	  altered accountcode on SIP/200 will remain until the local
-	  channels optimize out and the accountcode would change to the
-	  SIP/100 accountcode. Asterisk v1.8 attempted to add peeraccount
-	  support but ultimately had to punt on the support. The
-	  peeraccount support was rendered useless because of how the CDR
-	  code needed to unconditionally force the caller's accountcode
-	  onto the peer channel's accountcode. The CEL events were thus
-	  intentionally made to always use the channel's accountcode as the
-	  peeraccount value. With the arrival of Asterisk v12, the
-	  situation has improved somewhat so peeraccount support can be
-	  made to work. Using the indicated example, the the accountcode
-	  values become as follows when the peeraccount is set on SIP/100
-	  before calling SIP/200: SIP/100 ---> Local;1 ---- Local;2 --->
-	  SIP/200 acct: 100 \/ acct: 200 \/ acct: 100 \/ acct: 200 peer:
-	  200 /\ peer: 100 /\ peer: 200 /\ peer: 100 If a channel already
-	  has an accountcode it can only change by the following explicit
-	  user actions: 1) A channel originate method that can specify an
-	  accountcode to use. 2) The calling channel propagating its
-	  non-empty peeraccount or its non-empty accountcode if the
-	  peeraccount was empty to the outgoing channel's accountcode
-	  before initiating the dial. e.g., Dial and FollowMe. The
-	  exception to this propagation method is Queue. Queue will only
-	  propagate peeraccounts this way only if the outgoing channel does
-	  not have an accountcode. 3) Dialplan using CHANNEL(accountcode).
-	  4) Dialplan using CHANNEL(peeraccount) on the other end of a
-	  local channel pair. If a channel does not have an accountcode it
-	  can get one from the following places: 1) The channel driver's
-	  configuration at channel creation. 2) Explicit user action as
-	  already indicated. 3) Entering a basic or stasis-mixing bridge
-	  from a peer channel's peeraccount value. You can specify the
-	  accountcode for an outgoing channel by setting the
-	  CHANNEL(peeraccount) before using the Dial, FollowMe, and Queue
-	  applications. Queue adds the wrinkle that it will not overwrite
-	  an existing accountcode on the outgoing channel with the calling
-	  channels values. Accountcode and peeraccount values propagate to
-	  an outgoing channel before dialing. Accountcodes also propagate
-	  when channels enter or leave a basic or stasis-mixing bridge. The
-	  peeraccount value only makes sense for mixing bridges with two
-	  channels; it is meaningless otherwise. * Made peeraccount
-	  functional by changing accountcode propagation as described
-	  above. * Fixed CEL extracting the wrong ie value for the
-	  peeraccount. This was done intentionally in Asterisk v1.8 when
-	  that version had to punt on peeraccount. * Fixed a few places
-	  dealing with accountcodes that were reading from channels without
-	  the lock held. AFS-65 #close Review:
-	  https://reviewboard.asterisk.org/r/3601/
-
-2014-07-24 21:01 +0000 [r419504]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* main/db.c, include/asterisk/astdb.h: core/db: Revert Patch Added
-	  In Attempt To Improve I/O Performance Reverting the patch since
-	  it was causing a regression and after fixing the regression,
-	  there were no performance gains. At least based on my method for
-	  measurement. ASTERISK-24050 Review:
-	  https://reviewboard.asterisk.org/r/3841/
-
-2014-07-24 17:50 +0000 [r419438-419439]  Corey Farrell <git at cfware.com>
-
-	* include/asterisk/astobj.h: Deprecate astobj.h This flags astobj.h
-	  as deprecated, warns people to use astobj2.h instead. Only
-	  netsock.c (also deprecated) still uses astobj.h. ASTERISK-24069
-	  #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3818/
+	* Core/General: Add #ifdef needed on FreeBSD.
 
-	* channels/sip/include/sip.h, channels/chan_sip.c: chan_sip:
-	  complete upgrade to ao2 This change upgrades sip_registry and
-	  sip_subscription_mwi to astobj2. ASTERISK-24067 #close Reported
-	  by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3759/
+	  pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED on FreeBSD
+	  too.
 
-2014-07-24 16:52 +0000 [r419377]  Jason Parker <jparker at digium.com>
+	  ASTERISK-25310 #close
+	  Reported by: Guido Falsi
 
-	* addons/chan_ooh323.c, /: Don't cause Asterisk to exit if
-	  ooh323.conf not found. (closes issue ASTERISK-23814) ........
-	  Merged revisions 419374 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 419375 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 419376 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-24 15:20 +0000 [r419358]  Matthew Jordan <mjordan at digium.com>
-
-	* main/devicestate.c, channels/chan_pjsip.c: device state: Update
-	  the core to report ONHOLD if a channel is on hold In Asterisk, it
-	  is possible for a device to have a status of ONHOLD. This is not
-	  typically an easy thing to determine, as a channel being on hold
-	  is not a direct channel state. Typically, this has to be
-	  calculated outside of the core independently in channel drivers,
-	  notably, chan_sip and chan_pjsip. Both of these channel drivers
-	  already have to calculate device state in a fashion more complex
-	  than the core can handle, as they aggregate all state of all
-	  channels associated with a peer/endpoint; they also independently
-	  track whether or not one of those channels is currently on hold
-	  and mark the device state appropriately. In 12+, we now have the
-	  ability to report an AST_DEVICE_ONHOLD state for all channels
-	  that defer their device state to the core. This is due to channel
-	  hold state actually now being tracked on the channel itself. If a
-	  channel driver defers its device state to the core (which many,
-	  such as DAHDI, IAX2, and others do in most situations), the
-	  device state core already goes out to get a channel associated
-	  with the device. As such, it can now also factor the channel hold
-	  state in its calculation. This patch adds this logic to the
-	  device state core. It also uses an existing mapping between
-	  device state and channel state to handle more channel states.
-	  chan_pjsip has been updated slightly as well to make use of this
-	  (as it was, for some reason, reporting a channel state of BUSY as
-	  a device state of INUSE, which feels slightly wrong). Review:
-	  https://reviewboard.asterisk.org/r/3771/ ASTERISK-24038 #close
-
-2014-07-24 13:00 +0000 [r419342]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/manager.h, doc/appdocsxml.dtd, main/xmldoc.c,
-	  main/manager_bridges.c, main/manager.c,
-	  include/asterisk/xmldoc.h, main/config_options.c: AMI: Allow for
-	  command response documentation Allow for responses to AMI
-	  actions/commands to be documented properly in XML and displayed
-	  via the CLI. Response events are documented exactly as standard
-	  AMI events are documented. Review:
-	  https://reviewboard.asterisk.org/r/3812/
-
-2014-07-23 16:46 +0000 [r419319]  Matthew Jordan <mjordan at digium.com>
-
-	* main/endpoints.c, tests/test_stasis_endpoints.c, /: endpoints:
-	  Fix failing unit tests from r419196 This patch does two things:
-	  (1) It updates the unit tests to expect additional stasis
-	  messages. More messages are now sent to the endpoint topic, due
-	  to forwarding all channel messages and the forwarding
-	  relationship set up between endpoints themselves. (2) Remove the
-	  technology forwarding subscription during ast_endpoint_shutdown.
-	  This prevents an improper double shutdown of an endpoint from
-	  occurring. ........ Merged revisions 419318 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-23 14:00 +0000 [r419286]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* apps/app_voicemail.c, /: app_voicemail: use a consistent
-	  generator string When updating voicemail.conf when a user changes
-	  their pin, change the generator string to be the same as the
-	  module name when reading so that the same config_hook will be
-	  called. Review: https://reviewboard.asterisk.org/r/3837/ ........
-	  Merged revisions 419284 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 419285 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-23 01:28 +0000 [r419268]  Corey Farrell <git at cfware.com>
-
-	* main/manager.c, res/res_fax.c: res_fax: unregister manager
-	  actions on unload * Unregister manager actions FAXSessions,
-	  FAXSession and FAXStats at unload. * Update ast_manager_register2
-	  use ao2_t_alloc tagged with the action name. ASTERISK-24058
-	  #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3831/
-
-2014-07-22 20:22 +0000 [r419222-419252]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* CHANGES, main/bridge_channel.c: core/bridge_channel: Substitute
-	  Variables In Features Application Map Say you wanted to include
-	  variables in an application map and have those variables
-	  substituted and passed along to the application being executed;
-	  currently this does not happen. This patch adds this ability to
-	  pass channel variable values to an application before being
-	  executed. ASTERISK-22608 #close Reported by: Michael L. Young
-	  patches: features_substitute_arguments_v2.diff uploaded by
-	  Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/3819/
-
-	* CHANGES, apps/app_mixmonitor.c: apps/app_mixmonitor: Add Options
-	  To Play Beep At Start Or Stop We have a new periodic beep feature
-	  but sometimes a user needs some sort of feedback, without the
-	  need to have a periodic beep during the recording, to let them
-	  know that MixMonitor started recording or ended the recording.
-	  The use case where this patch is being used is when using Dynamic
-	  Features to start and end MixMonitor. This patch adds an option
-	  to play a beep when MixMonitor starts and an option to play a
-	  beep when MixMonitor ends. ASTERISK-24051 #close Reported by:
-	  Michael L. Young patches: mixmonitor-play-beep-start-stop.diff
-	  uploaded by Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/3820/
-
-	* main/db.c, include/asterisk/astdb.h: core/db: Improve I/O When
-	  Updating Rows When updating a row, we are currently doing an
-	  INSERT OR REPLACE INTO. The downside to this is that the row is
-	  deleted if it exists and then a new row is inserted. So, we are
-	  hitting the disk twice. One for the deletion and one for the
-	  insertion. This patch changes this statement to an INSERT INTO
-	  and if the insert fails because a row with that key exists, we
-	  will IGNORE the failure. Then we will attempt to perform an
-	  UPDATE on the existing row if that row wasn't just INSERTed.
-	  ASTERISK-24050 #close Reported by: Michael L. Young patches:
-	  astdb-insert-update-io-help_trunk_v2.diff uploaded by Michael L.
-	  Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/3815/
-
-2014-07-22 17:10 +0000 [r419206]  Richard Mudgett <rmudgett at digium.com>
-
-	* codecs/codec_speex.c: codec_speex: Fix trashing normal static
-	  frame for AST_FRAME_CNG. Made use a local static frame to
-	  generate the AST_FRAME_CNG frame when silence starts. I don't
-	  think the handling of the AST_FRAME_CNG has ever really worked
-	  because there doesn't seem to be any consumers of it. Review:
-	  https://reviewboard.asterisk.org/r/3813/
-
-2014-07-22 16:20 +0000 [r419203]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/endpoints.h,
-	  rest-api/api-docs/applications.json, include/asterisk/xmpp.h,
-	  main/channel_internal_api.c, channels/chan_motif.c,
-	  include/asterisk/channel.h, res/ari/resource_applications.h,
-	  res/res_xmpp.c, channels/chan_iax2.c, main/endpoints.c,
-	  channels/chan_pjsip.c, main/channel.c,
-	  res/ari/resource_endpoints.c, /, channels/chan_sip.c: ARI: Fix
-	  endpoint/channel subscription issues; allow for subscriptions to
-	  tech This patch serves two purposes: (1) It fixes some bugs with
-	  endpoint subscriptions not reporting all of the channel events
-	  (2) It serves as the preliminary work needed for ASTERISK-23692,
-	  which allows for sending/receiving arbitrary out of call text
-	  messages through ARI in a technology agnostic fashion. The
-	  messaging functionality described on ASTERISK-23692 requires two
-	  things: (1) The ability to send/receive messages associated with
-	  an endpoint. This is relatively straight forwards with the
-	  endpoint core in Asterisk now. (2) The ability to send/receive
-	  messages associated with a technology and an arbitrary technology
-	  defined URI. This is less straight forward, as endpoints are
-	  formed from a tech + resource pair. We don't have a mechanism to
-	  note that a technology that *may* have endpoints exists. This
-	  patch provides such a mechanism, and fixes a few bugs along the
-	  way. The first major bug this patch fixes is the forwarding of
-	  channel messages to their respective endpoints. Prior to this
-	  patch, there were two problems: (1) Channel caching messages
-	  weren't forwarded. Thus, the endpoints missed most of the
-	  interesting bits (such as channel creation, destruction, state
-	  changes, etc.) (2) Channels weren't associated with their
-	  endpoint until after creation. This resulted in endpoints missing
-	  the channel creation message, which limited the usefulness of the
-	  subscription in the first place (a major use case being 'tell me
-	  when this endpoint has a channel'). Unfortunately, this meant
-	  another parameter to ast_channel_alloc. Since not all channel
-	  technologies support an ast_endpoint, this patch makes such a
-	  call optional and opts for a new function,
-	  ast_channel_alloc_with_endpoint. When endpoints are created, they
-	  will implicitly create a technology endpoint for their technology
-	  (if one does not already exist). A technology endpoint is special
-	  in that it has no state, cannot have channels created for it,
-	  cannot be created explicitly, and cannot be destroyed except on
-	  shutdown. It does, however, have all messages from other
-	  endpoints in its technology forwarded to it. Combined with the
-	  bug fixes, we now have Stasis messages being properly forwarded.
-	  Consider the following scenario: two PJSIP endpoints (foo and
-	  bar), where bar has a single channel associated with it and foo
-	  has two channels associated with it. The messages would be
-	  forwarded as follows: channel PJSIP/foo-1 -- \ --> endpoint
-	  PJSIP/foo -- / \ channel PJSIP/foo-2 -- \ ---- > endpoint PJSIP /
-	  channel PJSIP/bar-1 -----> endpoint PJSIP/bar -- ARI, through the
-	  applications resource, can: - subscribe to endpoint:PJSIP/foo and
-	  get notifications for channels PJSIP/foo-1,PJSIP/foo-2 and
-	  endpoint PJSIP/foo - subscribe to endpoint:PJSIP/bar and get
-	  notifications for channels PJSIP/bar-1 and endpoint PJSIP/bar -
-	  subscribe to endpoint:PJSIP and get notifications for channels
-	  PJSIP/foo-1,PJSIP/foo-2,PJSIP/bar-1 and endpoints
-	  PJSIP/foo,PJSIP/bar Note that since endpoint PJSIP never changes,
-	  it never has events itself. It merely provides an aggregation
-	  point for all other endpoints in its technology (which in turn
-	  aggregate all channel messages associated with that endpoint).
-	  This patch also adds endpoints to res_xmpp and chan_motif,
-	  because the actual messaging work will need it (messaging without
-	  XMPP is just sad). Review:
-	  https://reviewboard.asterisk.org/r/3760/ ASTERISK-23692 ........
-	  Merged revisions 419196 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-22 14:36 +0000 [r419180]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_iax2.c: chan_iax2: Restore previous behavior of
-	  iax2_best_codec. The iax2_best_codec function was changed to
-	  convert the formats into a format compatibilities structure and
-	  grab the first format from it. The resulting order differs from
-	  the previous order of iax2_best_codec which causes unexpected
-	  formats to get chosen (such as g723). This commit brings back the
-	  old behavior of iax2_best_codec by having a specified preference
-	  list. Review: https://reviewboard.asterisk.org/r/3835/
-
-2014-07-22 14:22 +0000 [r419110-419175]  Kinsey Moore <kmoore at digium.com>
-
-	* addons/ooh323c/src/printHandler.c, tests/test_sorcery_realtime.c,
-	  tests/test_json.c, addons/ooh323c/src/ooq931.c,
-	  tests/test_astobj2_thrash.c, addons/chan_ooh323.c, /,
-	  tests/test_optional_api.c, tests/test_abstract_jb.c,
-	  apps/app_meetme.c, tests/test_logger.c, tests/test_event.c,
-	  tests/test_hashtab_thrash.c, res/res_mwi_external_ami.c,
-	  tests/test_sorcery.c, res/res_corosync.c,
-	  tests/test_voicemail_api.c, tests/test_aoc.c,
-	  tests/test_astobj2.c, tests/test_config.c: Fix more dev-mode
-	  build issues ........ Merged revisions 419129 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 419162 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 419163 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/dial.c: Dial API: Prevent crash on NULL cap This prevents a
-	  crash in the Dial API triggered by use of the Page() application
-	  where a format capability struct was used before checking whether
-	  it was NULL. ASTERISK-24074 #close
-
-	* channels/chan_skinny.c, tests/test_core_format.c: Fix build in
-	  dev-mode
-
-2014-07-21 16:26 +0000 [r419109]  Jonathan Rose <jrose at digium.com>
-
-	* channels/chan_iax2.c: chan_iax2: Restore codec choice behavior
-	  from media formats branch After merging the media formats branch,
-	  chan_iax2 was discarding codec preferences for the purpose of
-	  choosing which codec a channel would use once a call started.
-	  This patch restores the Asterisk 1.8-12 codec choice behaviors.
-	  ASTERISK-23958 #close Review:
-	  https://reviewboard.asterisk.org/r/3800/
-
-2014-07-21 16:09 +0000 [r419093]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_iax2.c: chan_iax2: Only send mini frames if the
-	  underlying format has not changed, not if it has. ASTERISK-24072
-	  #close Reported by: Matt Jordan
-
-2014-07-21 14:49 +0000 [r419077]  Sean Bright <sean at malleable.com>
-
-	* configure, configure.ac: Fix build when pjproject is installed in
-	  a non-standard location. When configuring Asterisk to build
-	  against a version of pjproject installed in a non-standard
-	  location, the checks for "PJSIP Transaction Group Lock Support"
-	  and "PJSIP Media Stream Replacement Support" fail. This is
-	  because these secondary checks are not taking the CFLAGS and LIBS
-	  returned by the pkg-config check into account. Review:
-	  https://reviewboard.asterisk.org/r/3830
-
-2014-07-21 08:41 +0000 [r419060]  Corey Farrell <git at cfware.com>
-
-	* channels/sig_analog.c, res/res_smdi.c, channels/chan_motif.c,
-	  include/asterisk/smdi.h, apps/app_voicemail.c,
-	  channels/chan_dahdi.c: res_smdi: convert to astobj2 Remove
-	  functions: ast_smdi_interface_unref ast_smdi_md_message_putback
-	  ast_smdi_mwi_message_putback ast_smdi_md_message destructor
-	  ast_smdi_mwi_message destructor Includes for astobj.h are removed
-	  everywhere it's possible. ASTERISK-24066 #close Review:
-	  https://reviewboard.asterisk.org/r/3758/
-
-2014-07-20 22:06 +0000 [r419044]  Matthew Jordan <mjordan at digium.com>
-
-	* apps/app_confbridge.c, res/ari/resource_channels.c,
-	  include/asterisk/rtp_engine.h, include/asterisk/slinfactory.h,
-	  res/res_calendar.c, codecs/codec_g722.c,
-	  include/asterisk/res_pjsip_session.h, main/frame.c,
-	  codecs/ex_lpc10.h, apps/app_dictate.c, res/res_fax.c,
-	  apps/app_echo.c, include/asterisk/slin.h, codecs/codec_g726.c,
-	  formats/format_ogg_vorbis.c, codecs/codec_gsm.c,
-	  codecs/ex_alaw.h, formats/format_wav_gsm.c,
-	  channels/iax2/provision.c, channels/chan_iax2.c,
-	  res/res_format_attr_h264.c, main/data.c, main/manager.c,
-	  include/asterisk/audiohook.h, formats/format_pcm.c,
-	  main/config_options.c, res/res_format_attr_silk.c,
-	  main/bridge_channel.c, res/res_speech.c, channels/chan_pjsip.c,
-	  res/res_clioriginate.c, formats/format_g729.c,
-	  channels/chan_unistim.c, res/res_rtp_asterisk.c,
-	  include/asterisk/smoother.h (added), main/rtp_engine.c,
-	  addons/format_mp3.c, formats/format_wav.c,
-	  apps/confbridge/conf_chan_record.c, include/asterisk/speech.h,
-	  codecs/ex_adpcm.h, channels/iax2/codec_pref.c (added),
-	  include/asterisk/codec.h (added), formats/format_siren7.c,
-	  include/asterisk/file.h, channels/chan_dahdi.c,
-	  include/asterisk/image.h, funcs/func_channel.c,
-	  main/abstract_jb.c, formats/format_h263.c, codecs/codec_dahdi.c,
-	  main/dsp.c, apps/app_voicemail.c, apps/app_jack.c,
-	  funcs/func_talkdetect.c, channels/chan_vpb.cc,
-	  channels/chan_sip.c, formats/format_sln.c,
-	  tests/test_abstract_jb.c, codecs/codec_alaw.c, UPGRADE.txt,
-	  main/smoother.c (added), codecs/ex_speex.h,
-	  channels/chan_console.c, apps/app_talkdetect.c,
-	  main/format_pref.c (removed), main/indications.c,
-	  include/asterisk/format_cap.h, main/media_index.c,
-	  apps/app_agent_pool.c, res/res_pjsip_session.c, main/cli.c,
-	  res/res_format_attr_celt.c, channels/chan_skinny.c,
-	  tests/test_core_format.c (added), funcs/func_frame_trace.c,
-	  res/res_pjsip/pjsip_configuration.c, main/file.c,
-	  include/asterisk/frame.h, formats/format_g726.c,
-	  apps/app_mixmonitor.c, channels/chan_mgcp.c, main/sorcery.c,
-	  codecs/ex_ilbc.h, codecs/codec_lpc10.c, tests/test_format_cache.c
-	  (added), apps/app_meetme.c, main/translate.c,
-	  apps/app_originate.c, res/parking/parking_applications.c,
-	  apps/app_ices.c, channels/iax2/parser.c, res/res_rtp_multicast.c,
-	  pbx/pbx_spool.c, funcs/func_pitchshift.c, formats/format_vox.c,
-	  main/format_cap.c, tests/test_cel.c, include/asterisk/format.h,
-	  formats/format_h264.c, apps/app_chanspy.c, apps/app_nbscat.c,
-	  addons/chan_ooh323.c, bridges/bridge_holding.c,
-	  channels/iax2/include/codec_pref.h (added), codecs/codec_adpcm.c,
-	  apps/app_waitforsilence.c, res/res_pjsip_sdp_rtp.c,
-	  addons/chan_ooh323.h, bridges/bridge_simple.c,
-	  apps/app_alarmreceiver.c, bridges/bridge_softmix.c,
-	  res/res_stasis_snoop.c, main/sounds_index.c, main/core_local.c,
-	  main/codec_builtin.c (added), include/asterisk/format_cache.h
-	  (added), apps/app_speech_utils.c, res/res_format_attr_opus.c,
-	  include/asterisk/abstract_jb.h, main/channel.c,
-	  include/asterisk/format_compatibility.h (added), apps/app_mp3.c,
-	  tests/test_voicemail_api.c, channels/chan_alsa.c, main/app.c,
-	  formats/format_g723.c, codecs/codec_ilbc.c, tests/test_config.c,
-	  formats/format_gsm.c, apps/app_milliwatt.c, codecs/ex_ulaw.h,
-	  main/asterisk.c, include/asterisk/res_pjsip.h, main/format.c,
-	  main/ccss.c, main/bridge.c, codecs/codec_speex.c,
-	  include/asterisk/format_pref.h (removed), apps/app_record.c,
-	  main/slinfactory.c, res/res_adsi.c, main/core_unreal.c,
-	  res/ari/resource_bridges.c, include/asterisk/callerid.h,
-	  channels/pjsip/dialplan_functions.c, main/dial.c,
-	  channels/dahdi/bridge_native_dahdi.c, main/format_cache.c
-	  (added), include/asterisk/mod_format.h, apps/app_sms.c,
-	  codecs/codec_resample.c, main/format_compatibility.c (added),
-	  main/audiohook.c, formats/format_jpeg.c, res/res_stasis.c,
-	  formats/format_g719.c, include/asterisk/translate.h,
-	  funcs/func_speex.c, codecs/codec_a_mu.c,
-	  channels/iax2/format_compatibility.c (added),
-	  apps/app_festival.c, main/channel_internal_api.c,
-	  tests/test_format_api.c (removed), codecs/ex_g722.h,
-	  main/utils.c, res/ari/resource_sounds.c,
-	  res/res_format_attr_h263.c, codecs/ex_g726.h,
-	  include/asterisk/_private.h, channels/chan_oss.c,
-	  channels/chan_misdn.c, main/codec.c (added), main/callerid.c,
-	  addons/ooh323cDriver.c, apps/app_amd.c, codecs/codec_ulaw.c,
-	  main/image.c, channels/chan_nbs.c, bridges/bridge_native_rtp.c,
-	  channels/iax2/include/format_compatibility.h (added),
-	  formats/format_siren14.c, res/res_fax_spandsp.c,
-	  addons/chan_mobile.c, addons/ooh323cDriver.h,
-	  channels/sip/include/sip.h, tests/test_format_cap.c (added),
-	  channels/chan_multicast_rtp.c, include/asterisk/vector.h,
-	  channels/chan_bridge_media.c, apps/app_fax.c,
-	  main/bridge_basic.c, apps/app_test.c, include/asterisk/channel.h,
-	  include/asterisk/data.h, tests/test_core_codec.c (added),
-	  res/res_musiconhold.c, codecs/ex_gsm.h, formats/format_ilbc.c,
-	  include/asterisk/config_options.h, channels/chan_phone.c,
-	  include/asterisk/bridge_channel.h, apps/app_dumpchan.c,
-	  channels/chan_motif.c, res/res_agi.c: media formats: re-architect
-	  handling of media for performance improvements In the old times
-	  media formats were represented using a bit field. This was fast
-	  but had a few limitations. 1. Asterisk was limited in how many
-	  formats it could handle. 2. Formats, being a bit field, could not
-	  include any attribute information. A format was strictly its
-	  type, e.g., "this is ulaw". This was changed in Asterisk 10 (see
-	  https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal
-	  for notes on that work) which led to the creation of the
-	  ast_format structure. This structure allowed Asterisk to handle
-	  attributes and bundle information with a format. Additionally,
-	  ast_format_cap was created to act as a container for multiple
-	  formats that, together, formed the capability of some entity.
-	  Another mechanism was added to allow logic to be registered which
-	  performed format attribute negotiation. Everywhere throughout the
-	  codebase Asterisk was changed to use this strategy.
-	  Unfortunately, in software, there is no free lunch. These new
-	  capabilities came at a cost. Performance analysis and profiling
-	  showed that we spend an inordinate amount of time comparing,
-	  copying, and generally manipulating formats and their related
-	  structures. Basic prototyping has shown that a reasonably large
-	  performance improvement could be made in this area. This patch is
-	  the result of that project, which overhauled the media format
-	  architecture and its usage in Asterisk to improve performance.
-	  Generally, the new philosophy for handling formats is as follows:
-	  * The ast_format structure is reference counted. This removed a
-	  large amount of the memory allocations and copying that was done
-	  in prior versions. * In order to prevent race conditions while
-	  keeping things performant, the ast_format structure is immutable
-	  by convention and lock-free. Violate this tenet at your peril! *
-	  Because formats are reference counted, codecs are also reference
-	  counted. The Asterisk core generally provides built-in codecs and
-	  caches the ast_format structures created to represent them.
-	  Generally, to prevent inordinate amounts of module reference
-	  bumping, codecs and formats can be added at run-time but cannot
-	  be removed. * All compatibility with the bit field representation
-	  of codecs/formats has been moved to a compatibility API. The
-	  primary user of this representation is chan_iax2, which must
-	  continue to maintain its bit-field usage of formats for
-	  interoperability concerns. * When a format is negotiated with
-	  attributes, or when a format cannot be represented by one of the
-	  cached formats, a new format object is created or cloned from an
-	  existing format. That format may have the same codec underlying
-	  it, but is a different format than a version of the format with
-	  different attributes or without attributes. * While formats are
-	  reference counted objects, the reference count maintained on the
-	  format should be manipulated with care. Formats are generally
-	  cached and will persist for the lifetime of Asterisk and do not
-	  explicitly need to have their lifetime modified. An exception to
-	  this is when the user of a format does not know where the format
-	  came from *and* the user may outlive the provider of the format.
-	  This occurs, for example, when a format is read from a channel:
-	  the channel may have a format with attributes (hence, non-cached)
-	  and the user of the format may last longer than the channel (if
-	  the reference to the channel is released prior to the format's
-	  reference). For more information on this work, see the API design
-	  notes:
-	  https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
-	  Finally, this work was the culmination of a large number of
-	  developer's efforts. Extra thanks goes to Corey Farrell, who took
-	  on a large amount of the work in the Asterisk core, chan_sip, and
-	  was an invaluable resource in peer reviews throughout this
-	  project. There were a substantial number of patches contributed
-	  during this work; the following issues/patch names simply reflect
-	  some of the work (and will cause the release scripts to give
-	  attribution to the individuals who work on them). Reviews:
-	  https://reviewboard.asterisk.org/r/3814
-	  https://reviewboard.asterisk.org/r/3808
-	  https://reviewboard.asterisk.org/r/3805
-	  https://reviewboard.asterisk.org/r/3803
-	  https://reviewboard.asterisk.org/r/3801
-	  https://reviewboard.asterisk.org/r/3798
-	  https://reviewboard.asterisk.org/r/3800
-	  https://reviewboard.asterisk.org/r/3794
-	  https://reviewboard.asterisk.org/r/3793
-	  https://reviewboard.asterisk.org/r/3792
-	  https://reviewboard.asterisk.org/r/3791
-	  https://reviewboard.asterisk.org/r/3790
-	  https://reviewboard.asterisk.org/r/3789
-	  https://reviewboard.asterisk.org/r/3788
-	  https://reviewboard.asterisk.org/r/3787
-	  https://reviewboard.asterisk.org/r/3786
-	  https://reviewboard.asterisk.org/r/3784
-	  https://reviewboard.asterisk.org/r/3783
-	  https://reviewboard.asterisk.org/r/3778
-	  https://reviewboard.asterisk.org/r/3774
-	  https://reviewboard.asterisk.org/r/3775
-	  https://reviewboard.asterisk.org/r/3772
-	  https://reviewboard.asterisk.org/r/3761
-	  https://reviewboard.asterisk.org/r/3754
-	  https://reviewboard.asterisk.org/r/3753
-	  https://reviewboard.asterisk.org/r/3751
-	  https://reviewboard.asterisk.org/r/3750
-	  https://reviewboard.asterisk.org/r/3748
-	  https://reviewboard.asterisk.org/r/3747
-	  https://reviewboard.asterisk.org/r/3746
-	  https://reviewboard.asterisk.org/r/3742
-	  https://reviewboard.asterisk.org/r/3740
-	  https://reviewboard.asterisk.org/r/3739
-	  https://reviewboard.asterisk.org/r/3738
-	  https://reviewboard.asterisk.org/r/3737
-	  https://reviewboard.asterisk.org/r/3736
-	  https://reviewboard.asterisk.org/r/3734
-	  https://reviewboard.asterisk.org/r/3722
-	  https://reviewboard.asterisk.org/r/3713
-	  https://reviewboard.asterisk.org/r/3703
-	  https://reviewboard.asterisk.org/r/3689
-	  https://reviewboard.asterisk.org/r/3687
-	  https://reviewboard.asterisk.org/r/3674
-	  https://reviewboard.asterisk.org/r/3671
-	  https://reviewboard.asterisk.org/r/3667
-	  https://reviewboard.asterisk.org/r/3665
-	  https://reviewboard.asterisk.org/r/3625
-	  https://reviewboard.asterisk.org/r/3602
-	  https://reviewboard.asterisk.org/r/3519
-	  https://reviewboard.asterisk.org/r/3518
-	  https://reviewboard.asterisk.org/r/3516
-	  https://reviewboard.asterisk.org/r/3515
-	  https://reviewboard.asterisk.org/r/3512
-	  https://reviewboard.asterisk.org/r/3506
-	  https://reviewboard.asterisk.org/r/3413
-	  https://reviewboard.asterisk.org/r/3410
-	  https://reviewboard.asterisk.org/r/3387
-	  https://reviewboard.asterisk.org/r/3388
-	  https://reviewboard.asterisk.org/r/3389
-	  https://reviewboard.asterisk.org/r/3390
-	  https://reviewboard.asterisk.org/r/3321
-	  https://reviewboard.asterisk.org/r/3320
-	  https://reviewboard.asterisk.org/r/3319
-	  https://reviewboard.asterisk.org/r/3318
-	  https://reviewboard.asterisk.org/r/3266
-	  https://reviewboard.asterisk.org/r/3265
-	  https://reviewboard.asterisk.org/r/3234
-	  https://reviewboard.asterisk.org/r/3178 ASTERISK-23114 #close
-	  Reported by: mjordan media_formats_translation_core.diff uploaded
-	  by kharwell (License 6464) rb3506.diff uploaded by mjordan
-	  (License 6283) media_format_app_file.diff uploaded by kharwell
-	  (License 6464) misc-2.diff uploaded by file (License 5000)
-	  chan_mild-3.diff uploaded by file (License 5000)
-	  chan_obscure.diff uploaded by file (License 5000) jingle.diff
-	  uploaded by file (License 5000) funcs.diff uploaded by file
-	  (License 5000) formats.diff uploaded by file (License 5000)
-	  core.diff uploaded by file (License 5000) bridges.diff uploaded
-	  by file (License 5000) mf-codecs-2.diff uploaded by file (License
-	  5000) mf-app_fax.diff uploaded by file (License 5000)
-	  mf-apps-3.diff uploaded by file (License 5000)
-	  media-formats-3.diff uploaded by file (License 5000)
-	  ASTERISK-23715 rb3713.patch uploaded by coreyfarrell (License
-	  5909) rb3689.patch uploaded by mjordan (License 6283)
-	  ASTERISK-23957 rb3722.patch uploaded by mjordan (License 6283)
-	  mf-attributes-3.diff uploaded by file (License 5000)
-	  ASTERISK-23958 Tested by: jrose rb3822.patch uploaded by
-	  coreyfarrell (License 5909) rb3800.patch uploaded by jrose
-	  (License 6182) chan_sip.diff uploaded by mjordan (License 6283)
-	  rb3747.patch uploaded by jrose (License 6182) ASTERISK-23959
-	  #close Tested by: sgriepentrog, mjordan, coreyfarrell
-	  sip_cleanup.diff uploaded by opticron (License 6273)
-	  chan_sip_caps.diff uploaded by mjordan (License 6283)
-	  rb3751.patch uploaded by coreyfarrell (License 5909)
-	  chan_sip-3.diff uploaded by file (License 5000) ASTERISK-23960
-	  #close Tested by: opticron direct_media.diff uploaded by opticron
-	  (License 6273) pjsip-direct-media.diff uploaded by file (License
-	  5000) format_cap_remove.diff uploaded by opticron (License 6273)
-	  media_format_fixes.diff uploaded by opticron (License 6273)
-	  chan_pjsip-2.diff uploaded by file (License 5000) ASTERISK-23966
-	  #close Tested by: rmudgett rb3803.patch uploaded by rmudgetti
-	  (License 5621) chan_dahdi.diff uploaded by file (License 5000)
-	  ASTERISK-24064 #close Tested by: coreyfarrell, mjordan, opticron,
-	  file, rmudgett, sgriepentrog, jrose rb3814.patch uploaded by
-	  rmudgett (License 5621) moh_cleanup.diff uploaded by opticron
-	  (License 6273) bridge_leak.diff uploaded by opticron (License
-	  6273) translate.diff uploaded by file (License 5000) rb3795.patch
-	  uploaded by rmudgett (License 5621) tls_fix.diff uploaded by
-	  mjordan (License 6283) fax-mf-fix-2.diff uploaded by file
-	  (License 5000) rtp_transfer_stuff uploaded by mjordan (License
-	  6283) rb3787.patch uploaded by rmudgett (License 5621)
-	  media-formats-explicit-translate-format-3.diff uploaded by file
-	  (License 5000) format_cache_case_fix.diff uploaded by opticron
-	  (License 6273) rb3774.patch uploaded by rmudgett (License 5621)
-	  rb3775.patch uploaded by rmudgett (License 5621)
-	  rtp_engine_fix.diff uploaded by opticron (License 6273)
-	  rtp_crash_fix.diff uploaded by opticron (License 6273)
-	  rb3753.patch uploaded by mjordan (License 6283) rb3750.patch
-	  uploaded by mjordan (License 6283) rb3748.patch uploaded by
-	  rmudgett (License 5621) media_format_fixes.diff uploaded by
-	  opticron (License 6273) rb3740.patch uploaded by mjordan (License
-	  6283) rb3739.patch uploaded by mjordan (License 6283)
-	  rb3734.patch uploaded by mjordan (License 6283) rb3689.patch
-	  uploaded by mjordan (License 6283) rb3674.patch uploaded by
-	  coreyfarrell (License 5909) rb3671.patch uploaded by coreyfarrell
-	  (License 5909) rb3667.patch uploaded by coreyfarrell (License
-	  5909) rb3665.patch uploaded by mjordan (License 6283)
-	  rb3625.patch uploaded by coreyfarrell (License 5909) rb3602.patch
-	  uploaded by coreyfarrell (License 5909)
-	  format_compatibility-2.diff uploaded by file (License 5000)
-	  core.diff uploaded by file (License 5000)
-
-2014-07-18 21:48 +0000 [r419022]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/recordings.json, res/ari/resource_recordings.c,
-	  res/stasis_recording/stored.c, res/res_ari_recordings.c, /,
-	  include/asterisk/stasis_app_recording.h,
-	  res/ari/resource_recordings.h, CHANGES: ari: Add a copy operation
-	  for stored recordings This patch adds a new operation for stored
-	  recordings, copy. It takes an existing stored recording and makes
-	  a copy of it in the same directory or a relative directory under
-	  the stored recording directory.
-	  /ari/recordings/stored/{recordingName}/copy?destinationRecordingName={copy_name}
-	  This is particularly useful for voicemail-esque applications,
-	  which may need to copy or move recordings around a directory
-	  structure. Review: https://reviewboard.asterisk.org/r/3768/
-	  ASTERISK-24036 #close Reported by: Sam Galarneau Tested by: Sam
-	  Galarneau ........ Merged revisions 419021 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-18 21:25 +0000 [r418997-419020]  Corey Farrell <git at cfware.com>
-
-	* main/stasis_message_router.c, /: stasis: fix call to ao2_t_alloc
-	  for stasis_message_router_create This fixes a build failure
-	  introduced by r3821. struct stasis_topic is opaque, so
-	  topic->name is unavailable. Switch to using stasis_topic_name().
-	  ........ Merged revisions 419019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis.c, main/stasis_cache_pattern.c,
-	  main/stasis_message.c, main/stasis_message_router.c, /: stasis:
-	  use ao2_t_alloc for certain object allocators Add tags to stasis
-	  objects using the name. This makes it easier to track the source
-	  of certain stasis ref leaks. Review:
-	  https://reviewboard.asterisk.org/r/3821/ ........ Merged
-	  revisions 418996 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-18 19:07 +0000 [r418980]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_fax_spandsp.c: Fix build in dev-mode
-
-2014-07-18 17:55 +0000 [r418961-418963]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* res/res_pjsip_pubsub.c, main/astobj2.c,
-	  include/asterisk/astobj2.h, main/logger.c, main/utils.c: astobj2:
-	  assert on invalid ref and backtrace cleanup If a reference count
-	  goes negative, instead of just logging that fact, be more helpful
-	  with a backtrace and an assert that will DO_CRASH. This patch
-	  also removes the duplicate ao2_bt() function and cleans up
-	  extraneous usage of the ast_log_backtrace() call. Review:
-	  https://reviewboard.asterisk.org/r/3765/
-
-	* /, channels/chan_sip.c: media formats: fix ref leak of peer for
-	  mwi subscription Holding a reference to the peer during mwi
-	  subscriptions resulted in a circular reference because the final
-	  event message would not be sent until destruction of the peer.
-	  Instead, pass the name of the peer to the event callback so that
-	  it can fail gracefully after the peer has gone. ASTERISK-23959
-	  Review: https://reviewboard.asterisk.org/r/3754/ ........ Merged
-	  revisions 418636 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/features_config.c: feature_config: insure featuregroups
-	  and applicationmaps are initialized If the features.conf is
-	  missing, the cfg->featurgroups and cfg->applicationmaps is not
-	  initialized, resulting in assert on ao2_find of a null container.
-	  This patch changes the initialization call and adds asserts for a
-	  safeguard. Review: https://reviewboard.asterisk.org/r/3809/
-	  ........ Merged revisions 418886 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-18 16:47 +0000 [r418938]  Richard Mudgett <rmudgett at digium.com>
-
-	* funcs/func_audiohookinherit.c, /: func_audiohookinherit.c: Fixup
-	  some XML documentation wording. ........ Merged revisions 418937
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-18 16:28 +0000 [r418911-418936]  Jonathan Rose <jrose at digium.com>
-
-	* main/channel.c, funcs/func_audiohookinherit.c, /,
-	  include/asterisk/audiohook.h, main/framehook.c, res/res_fax.c,
-	  main/bridge_basic.c, include/asterisk/res_fax.h,
-	  bridges/bridge_native_rtp.c, main/audiohook.c, CHANGES,
-	  include/asterisk/framehook.h, res/res_pjsip_refer.c: Channels:
-	  Masquerades to automatically move frame/audio hooks Whenever
-	  possible, audiohooks and framehooks will now be copied over to
-	  the channel that the masquerading channel gets cloned into. This
-	  should occur for all audiohooks and most framehooks. As a result,
-	  in Asterisk 12.5 and up, the AUDIOHOOK_INHERIT function is now
-	  deprecated and its behavior is essentially the new default for
-	  all audiohooks, plus some additional audiohooks/framehooks.
-	  Review: https://reviewboard.asterisk.org/r/3721/ ........ Merged
-	  revisions 418914 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_fax.c, include/asterisk/res_fax.h, CHANGES,
-	  res/res_fax.exports.in, res/res_fax_spandsp.c: res_fax: Provide
-	  AMI equivalents for fax CLI commands Specifically the following
-	  equivalents were created: fax show session -> FAXSession fax show
-	  sessions -> FAXSessions fax show stats -> FAXStats Review:
-	  https://reviewboard.asterisk.org/r/3666/
-
-2014-07-18 00:11 +0000 [r418893-418895]  Sean Bright <sean at malleable.com>
-
-	* config.sub, menuselect/config.guess, menuselect/config.sub,
-	  config.guess: Update config.guess and config.sub
-
-	* autoconf/ast_ext_tool_check.m4: Add missing file from previous
-	  commit.
+	  Change-Id: Iae6befac9028b5b9795f86986a4a08a1ae6ab7c4
 
-	* menuselect/aclocal.m4, menuselect/configure,
-	  menuselect/acinclude.m4 (removed), menuselect/bootstrap.sh,
-	  menuselect/autoconfig.h.in: Import Asterisk's autoconf magic
-	  instead of using our own.
-
-2014-07-17 21:17 +0000 [r418832-418870]  Matthew Jordan <mjordan at digium.com>
-
-	* configs/samples/acl.conf.sample (added),
-	  configs/samples/extensions.conf.sample (added),
-	  configs/res_parking.conf.sample (removed),
-	  configs/samples/cel_sqlite3_custom.conf.sample (added),
-	  configs/cdr_sqlite3_custom.conf.sample (removed),
-	  configs/modules.conf.sample (removed),
-	  configs/samples/cli_aliases.conf.sample (added),
-	  configs/meetme.conf.sample (removed),
-	  configs/cdr_pgsql.conf.sample (removed),
-	  configs/samples/extensions.ael.sample (added),
-	  configs/samples/cdr_adaptive_odbc.conf.sample (added),
-	  configs/samples/motif.conf.sample (added),
-	  configs/samples/extensions_minivm.conf.sample (added),
-	  configs/samples/res_curl.conf.sample (added),
-	  configs/res_config_sqlite3.conf.sample (removed),
-	  configs/mgcp.conf.sample (removed), configs/dsp.conf.sample
-	  (removed), configs/udptl.conf.sample (removed),
-	  configs/sip.conf.sample (removed), configs/dbsep.conf.sample
-	  (removed), configs/queuerules.conf.sample (removed),
-	  configs/samples/cdr_mysql.conf.sample (added),
-	  configs/confbridge.conf.sample (removed),
-	  configs/samples/cdr_odbc.conf.sample (added),
-	  configs/samples/minivm.conf.sample (added),
-	  configs/enum.conf.sample (removed),
-	  configs/samples/codecs.conf.sample (added),
-	  configs/samples/chan_dahdi.conf.sample (added),
-	  configs/samples/cdr_custom.conf.sample (added),
-	  configs/samples/res_config_mysql.conf.sample (added),
-	  configs/samples/dundi.conf.sample (added),
-	  configs/samples/oss.conf.sample (added),
-	  configs/samples/app_mysql.conf.sample (added),
-	  configs/samples/queues.conf.sample (added),
-	  configs/samples/cdr.conf.sample (added),
-	  configs/samples/cdr_syslog.conf.sample (added),
-	  configs/festival.conf.sample (removed),
-	  configs/samples/cel_pgsql.conf.sample (added),
-	  configs/http.conf.sample (removed), configs/phoneprov.conf.sample
-	  (removed), configs/alarmreceiver.conf.sample (removed),
-	  configs/samples/features.conf.sample (added),
-	  configs/cdr_tds.conf.sample (removed),
-	  configs/func_odbc.conf.sample (removed),
-	  configs/samples/logger.conf.sample (added),
-	  configs/samples/res_odbc.conf.sample (added),
-	  configs/samples/agents.conf.sample (added),
-	  configs/res_fax.conf.sample (removed),
-	  configs/samples/xmpp.conf.sample (added),
-	  configs/iaxprov.conf.sample (removed),
-	  configs/res_pgsql.conf.sample (removed),
-	  configs/extensions.conf.sample (removed),
-	  configs/chan_mobile.conf.sample (removed), configs/asterisk.adsi
-	  (removed), configs/cel_sqlite3_custom.conf.sample (removed),
-	  configs/users.conf.sample (removed),
-	  configs/samples/res_pktccops.conf.sample (added),
-	  configs/samples/amd.conf.sample (added), configs/rtp.conf.sample
-	  (removed), configs/samples/res_parking.conf.sample (added),
-	  configs/hep.conf.sample (removed),
-	  configs/samples/modules.conf.sample (added),
-	  configs/cel_tds.conf.sample (removed),
-	  configs/res_curl.conf.sample (removed),
-	  configs/samples/skinny.conf.sample (added),
-	  configs/samples/cdr_pgsql.conf.sample (added),
-	  configs/samples/sip_notify.conf.sample (added),
-	  configs/samples/test_sorcery.conf.sample (added),
-	  configs/samples/dsp.conf.sample (added),
-	  configs/ss7.timers.sample (removed),
-	  configs/samples/udptl.conf.sample (added),
-	  configs/cdr_odbc.conf.sample (removed),
-	  configs/samples/sip.conf.sample (added),
-	  configs/minivm.conf.sample (removed),
-	  configs/res_config_sqlite.conf.sample (removed),
-	  configs/codecs.conf.sample (removed), configs/osp.conf.sample
-	  (removed), configs/samples/cel_custom.conf.sample (added),
-	  configs/samples/dbsep.conf.sample (added),
-	  configs/samples/app_skel.conf.sample (added),
-	  configs/console.conf.sample (removed),
-	  configs/cdr_manager.conf.sample (removed),
-	  configs/cdr_custom.conf.sample (removed),
-	  configs/chan_dahdi.conf.sample (removed),
-	  configs/res_config_mysql.conf.sample (removed),
-	  configs/samples/statsd.conf.sample (added),
-	  configs/cli.conf.sample (removed), configs/queues.conf.sample
-	  (removed), configs/cdr_syslog.conf.sample (removed), UPGRADE.txt,
-	  configs/manager.conf.sample (removed),
-	  configs/samples/res_corosync.conf.sample (added),
-	  configs/features.conf.sample (removed), configs/sla.conf.sample
-	  (removed), configs/logger.conf.sample (removed),
-	  configs/res_odbc.conf.sample (removed),
-	  configs/agents.conf.sample (removed),
-	  configs/samples/ooh323.conf.sample (added), Makefile,
-	  configs/xmpp.conf.sample (removed),
-	  configs/samples/phoneprov.conf.sample (added),
-	  configs/samples/alarmreceiver.conf.sample (added),
-	  configs/samples/cdr_tds.conf.sample (added),
-	  configs/extconfig.conf.sample (removed),
-	  configs/samples/func_odbc.conf.sample (added),
-	  configs/samples/res_fax.conf.sample (added),
-	  configs/samples/iaxprov.conf.sample (added),
-	  configs/samples/res_ldap.conf.sample (added),
-	  configs/samples/dnsmgr.conf.sample (added),
-	  configs/res_pktccops.conf.sample (removed),
-	  configs/cel.conf.sample (removed),
-	  configs/samples/res_pgsql.conf.sample (added),
-	  configs/samples/chan_mobile.conf.sample (added),
-	  configs/samples/asterisk.adsi (added),
-	  configs/samples/users.conf.sample (added),
-	  configs/samples/rtp.conf.sample (added),
-	  configs/phone.conf.sample (removed), configs/skinny.conf.sample
-	  (removed), configs/muted.conf.sample (removed),
-	  configs/samples/hep.conf.sample (added), configs/iax.conf.sample
-	  (removed), configs/samples/cel_tds.conf.sample (added),
-	  configs/sip_notify.conf.sample (removed),
-	  configs/samples/telcordia-1.adsi (added),
-	  configs/samples/alsa.conf.sample (added),
-	  configs/samples/adsi.conf.sample (added),
-	  configs/test_sorcery.conf.sample (removed),
-	  configs/samples/followme.conf.sample (added),
-	  configs/samples/asterisk.conf.sample (added),
-	  configs/extensions.lua.sample (removed), configs/say.conf.sample
-	  (removed), configs/cel_custom.conf.sample (removed),
-	  configs/samples/ss7.timers.sample (added),
-	  configs/samples/cel_odbc.conf.sample (added),
-	  configs/app_skel.conf.sample (removed),
-	  configs/samples/ccss.conf.sample (added),
-	  configs/cli_permissions.conf.sample (removed),
-	  configs/statsd.conf.sample (removed),
-	  configs/samples/res_config_sqlite.conf.sample (added),
-	  configs/config_test.conf.sample (removed),
-	  configs/indications.conf.sample (removed),
-	  configs/samples/osp.conf.sample (added),
-	  configs/samples/cdr_manager.conf.sample (added),
-	  configs/samples/console.conf.sample (added),
-	  configs/voicemail.conf.sample (removed),
-	  configs/res_corosync.conf.sample (removed),
-	  configs/misdn.conf.sample (removed),
-	  configs/samples/cli.conf.sample (added), configs/ari.conf.sample
-	  (removed), configs/ooh323.conf.sample (removed),
-	  configs/samples/calendar.conf.sample (added),
-	  configs/samples/res_stun_monitor.conf.sample (added),
-	  configs/samples/manager.conf.sample (added),
-	  configs/samples/pjsip_notify.conf.sample (added),
-	  configs/samples/sla.conf.sample (added),
-	  configs/musiconhold.conf.sample (removed),
-	  configs/pjsip.conf.sample (removed), configs/sorcery.conf.sample
-	  (removed), configs/vpb.conf.sample (removed),
-	  configs/unistim.conf.sample (removed),
-	  configs/res_ldap.conf.sample (removed),
-	  configs/dnsmgr.conf.sample (removed),
-	  configs/samples/extconfig.conf.sample (added),
-	  configs/samples/res_snmp.conf.sample (added),
-	  configs/acl.conf.sample (removed),
-	  configs/samples/smdi.conf.sample (added),
-	  configs/samples/cel.conf.sample (added),
-	  configs/cli_aliases.conf.sample (removed),
-	  configs/samples/cdr_sqlite3_custom.conf.sample (added),
-	  configs/extensions.ael.sample (removed),
-	  configs/cdr_adaptive_odbc.conf.sample (removed),
-	  configs/samples/phone.conf.sample (added),
-	  configs/extensions_minivm.conf.sample (removed),
-	  configs/motif.conf.sample (removed), configs/telcordia-1.adsi
-	  (removed), configs/samples/meetme.conf.sample (added),
-	  configs/adsi.conf.sample (removed), configs/alsa.conf.sample
-	  (removed), configs/samples/muted.conf.sample (added),
-	  configs/followme.conf.sample (removed),
-	  configs/asterisk.conf.sample (removed),
-	  configs/samples/iax.conf.sample (added),
-	  configs/samples/res_config_sqlite3.conf.sample (added),
-	  configs/samples/mgcp.conf.sample (added),
-	  configs/cel_odbc.conf.sample (removed), configs/ccss.conf.sample
-	  (removed), configs/cdr_mysql.conf.sample (removed),
-	  configs/samples/extensions.lua.sample (added),
-	  configs/samples/say.conf.sample (added),
-	  configs/dundi.conf.sample (removed),
-	  configs/samples/queuerules.conf.sample (added),
-	  configs/oss.conf.sample (removed), configs/app_mysql.conf.sample
-	  (removed), configs/samples/confbridge.conf.sample (added),
-	  configs/samples/cli_permissions.conf.sample (added),
-	  configs/samples/enum.conf.sample (added),
-	  configs/samples/config_test.conf.sample (added),
-	  configs/cdr.conf.sample (removed),
-	  configs/samples/indications.conf.sample (added),
-	  configs/cel_pgsql.conf.sample (removed),
-	  configs/res_stun_monitor.conf.sample (removed),
-	  configs/calendar.conf.sample (removed),
-	  configs/samples/voicemail.conf.sample (added),
-	  configs/pjsip_notify.conf.sample (removed),
-	  configs/samples/misdn.conf.sample (added),
-	  configs/samples/ari.conf.sample (added),
-	  configs/samples/festival.conf.sample (added),
-	  configs/samples/http.conf.sample (added),
-	  configs/res_snmp.conf.sample (removed),
-	  configs/samples/musiconhold.conf.sample (added),
-	  configs/samples/pjsip.conf.sample (added),
-	  configs/samples/sorcery.conf.sample (added),
-	  configs/samples/vpb.conf.sample (added), configs/smdi.conf.sample
-	  (removed), configs/samples/unistim.conf.sample (added),
-	  configs/samples (added), configs/amd.conf.sample (removed):
-	  configs: Move sample config files into a subdirectory of configs
-	  This moves all samples configs from configs/ to configs/samples.
-	  This allows for additional sets of sample configuration files to
-	  be added in the future. Review:
-	  https://reviewboard.asterisk.org/r/3804/
-
-	* channels/chan_sip.c, UPGRADE.txt: chan_sip: Make
-	  progressinband=never really mean 'never' progressinband=never in
-	  sip.conf is easily defeated if an onward trunk sends a progress
-	  indication of its own. This is almost certain to happen if the
-	  onward trunk is ISDN or IAX as these technologies send a progress
-	  indication even if early media is not required. This progress
-	  message is passed to the caller, and causes the "never" option to
-	  be rather badly named. This patch changes the behaviour of this
-	  setting in the following ways: 1) In sip_write(), do not pass the
-	  media unless we have either progressed beyond INV_EARLY_MEDIA, or
-	  we are in INV_EARLY_MEDIA state, and early media is both set-up
-	  and wanted. This helps resolve double-ringing on some buggy
-	  handsets. 2) In sip_indicate(), if we see AST_CONTROL_PROGRESS,
-	  but SIP_PROG_INBAND_NEVER is set, send a 180 Ringing instead to
-	  avoid implicitly enabling early media. Avoid sending double ring
-	  indications. NOTE: the meaning of the SIP_PROGRESS_SENT flag
-	  changes slightly in this patch to also encapsulate the fact that
-	  a channel has *sent or received* a 183 Progress indication. This
-	  makes the updated code in sip_write() much more simple. Review:
-	  https://reviewboard.asterisk.org/r/3700 ASTERISK-23972 #close
-	  Reported by: Steve Davies patches:
-	  inband_never_present_early_media2 uploaded by Steve Davies
-	  (License 5012)
-
-	* menuselect: Add svn:ignore property
-
-	* UPGRADE.txt, menuselect/configure, menuselect/configure.ac,
-	  configure, configure.ac: configure: Fix libxml2 development
-	  library dependency checking The commit that added libxml2 support
-	  didn't fully check for the libxml2 development script in the
-	  Asterisk configure file. As a result, Asterisk could be
-	  configured, then fail on menuselect. This patch fixes it so that
-	  Asterisk should detect the libxml2 dependency failure first.
-
-	* menuselect/makeopts.in, menuselect/autoconfig.h.in,
-	  menuselect/menuselect.h, menuselect/example_menuselect-tree,
-	  configure, include/asterisk/autoconfig.h.in, menuselect/Makefile,
-	  menuselect/README, menuselect/aclocal.m4, configure.ac,
-	  UPGRADE.txt, menuselect/configure, menuselect/configure.ac,
-	  menuselect/menuselect.c, menuselect/acinclude.m4: menuselect: Add
-	  libxml2 support (Patch 3) This is the final patch in adding
-	  menuselect to Asterisk. - The first patch (r418832) added
-	  menuselect along with mxml - The second patch (r418833) removed
-	  mxml from menuselect This patch adds support for libxml2 to
-	  menuselect, and makes libxml2 a required library for Asterisk.
-	  Note that the libxml2 portion of this patch was written by Sean
-	  Bright, and was made available on a team branch:
-	  http://svn.digium.com/svn/menuselect/team/seanbright/libxml2/
-	  Review: https://reviewboard.asterisk.org/r/3773/ ASTERISK-20703
-	  #close patches: some_mysterious_team_branch uploaded by
-	  seanbright (License 5060)
-
-	* menuselect/mxml (removed): menuselect: Remove mxml from
-	  menuselect (Patch 2) This is the second patch that adds
-	  menuselect to Asterisk trunk. The previous commit (r418832) added
-	  menuselect along with mxml; this patch removes mxml completely
-	  from Menuselect. A subsequent patch will switch menuselect over
-	  to using libxml2, and make libxml2 a required dependency for
-	  Asterisk. ASTERISK-20703
-
-	* menuselect/mxml/configure.in (added), menuselect/acinclude.m4
-	  (added), menuselect/mxml/mxml.list.in (added),
-	  menuselect/mxml/README (added), menuselect/linkedlists.h (added),
-	  menuselect/mxml (added), menuselect/mxml/config.h.in (added),
-	  menuselect/aclocal.m4 (added), menuselect/install-sh (added),
-	  menuselect/mxml/mxml-string.c (added),
-	  menuselect/menuselect_stub.c (added), menuselect/make_version
-	  (added), menuselect/mxml/mxml-entity.c (added),
-	  menuselect/bootstrap.sh (added), menuselect/makeopts.in (added),
-	  menuselect/autoconfig.h.in (added), menuselect/config.guess
-	  (added), menuselect/mxml/install-sh (added),
-	  menuselect/test/build_tools/menuselect-deps (added), /,
-	  menuselect/contrib/menuselect-dummy (added),
-	  menuselect/config.sub (added), menuselect/mxml/configure (added),
-	  menuselect/mxml/Makefile.in (added), menuselect (added),
-	  menuselect/contrib (added), menuselect/mxml/mxml.pc.in (added),
-	  menuselect/configure.ac (added), menuselect/mxml/mxml-set.c
-	  (added), menuselect/contrib/Makefile-dummy (added),
-	  menuselect/mxml/ANNOUNCEMENT (added), menuselect/missing (added),
-	  menuselect/menuselect_curses.c (added),
-	  menuselect/example_menuselect-tree (added), menuselect/Makefile
-	  (added), menuselect/mxml/mxml-search.c (added), menuselect/test
-	  (added), menuselect/test/menuselect-tree (added),
-	  menuselect/mxml/mxml.h (added), menuselect/mxml/mxml-index.c
-	  (added), menuselect/configure (added),
-	  menuselect/menuselect_newt.c (added), menuselect/mxml/mxml-attr.c
-	  (added), menuselect/mxml/mxml-private.c (added),
-	  menuselect/menuselect.c (added), menuselect/mxml/CHANGES (added),
-	  menuselect/mxml/COPYING (added), menuselect/mxml/mxml-file.c
-	  (added), menuselect/menuselect.h (added),
-	  menuselect/menuselect_gtk.c (added), menuselect/README (added),
-	  menuselect/strcompat.c (added), menuselect/mxml/mxml-node.c
-	  (added), menuselect/test/build_tools (added): menuselect: Add
-	  menuselect to Asterisk trunk (Patch 1) This is the first patch
-	  that adds menuselect to Asterisk trunk, and removes the
-	  svn:externals property. This is being done for two reasons: (1)
-	  The removal of external repositories eases a future migration to
-	  git (2) Asterisk is now the only thing that uses menuselect; as a
-	  result, there's little need to keep it in an external repository
-	  Subsequent patches will remove the mxml dependency from
-	  menuselect and tidy up the build system. ASTERISK-20703
-
-2014-07-17 14:28 +0000 [r418811]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/bridge_channel.c: TEST_FRAMEWORK: Fix threewaytransfer
-	  reporting Ensure that three-way transfers can be reported even if
-	  featuremap is non-NULL. ........ Merged revisions 418810 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-16 23:08 +0000 [r418788]  Corey Farrell <git at cfware.com>
-
-	* /, channels/dahdi/bridge_native_dahdi.c: Remove include of
-	  astobj.h from channels/dahdi/bridge_native_dahdi.c. The include
-	  was unneeded, this is split off from r3758 as it applies to 12.
-	  ........ Merged revisions 418787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-16 14:03 +0000 [r418717-418757]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip/pjsip_configuration.c, CHANGES, res/res_pjsip.c,
-	  channels/chan_pjsip.c, include/asterisk/res_pjsip.h,
-	  contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
-	  (added), /, configs/pjsip.conf.sample: res_pjsip: Support setting
-	  a default accountcode on endpoints Most channel drivers let you
-	  specify a default accountcode to be set on channels associated
-	  with a particular peer/endpoint/object. Prior to this patch,
-	  chan_pjsip/res_pjsip did not support such a setting. This patch
-	  adds a new setting to the res_pjsip endpoint object,
-	  'accountcode'. When a channel is created that is associated with
-	  an endpoint with this value set, the channel will automatically
-	  have its accountcode property set to the value configured for the
-	  endpoint. Review: https://reviewboard.asterisk.org/r/3724/
-	  ASTERISK-24000 #close Reported by: Matt Jordan ........ Merged
-	  revisions 418756 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* cdr/cdr_pgsql.c, CHANGES, configs/cdr_pgsql.conf.sample,
-	  configs/res_pgsql.conf.sample, cel/cel_pgsql.c,
-	  res/res_config_pgsql.c, configs/cel_pgsql.conf.sample: cel_pgsql,
-	  cdr_pgsql, res_config_pgsql: Add PostgreSQL application_name
-	  support This patch adds support for the PostgreSQL
-	  application_name connection setting. When the appropriate
-	  PostgreSQL module's configuration is set with an application
-	  name, the name will be passed to PostgreSQL on connection and
-	  displayed in the database's pg_stat_activity view, as well as in
-	  CSV logs. This aids in managing which applications/servers are
-	  connected to a PostgreSQL database, as well as tracing the
-	  activity of those connections. Review:
-	  https://reviewboard.asterisk.org/r/3591 ASTERISK-23737 #close
-	  Reported by: Gergely Domodi patches: pgsql_application_name.patch
-	  uploaded by Gergely Domodi (License 6610)
-
-	* codecs/codec_adpcm.c, main/format.c: codec_adpcm: Change
-	  description of codec "ADPCM" to "Dialogic ADPCM" Technically,
-	  ADPCM is a method that can be applied to several codecs.
-	  Asterisk's ADPCM codec is the Dialogic ADPCM or VOX codec. See
-	  http://en.wikipedia.org/wiki/Dialogic_ADPCM for more information
-	  about said codec. Review: https://reviewboard.asterisk.org/r/3744
-	  patches: rb3744.patch uploaded by dennis.guse (License 6513)
-
-	* UPGRADE.txt, main/manager.c, /: manager: Return ActionID on
-	  nominal responses to PresenceState action When the PresenceState
-	  action is executed, the nominal path fails to include the
-	  ActionID in the successful response. This patch adds a call to
-	  astman_start_ack, which guarantees that an ActionID (if provided)
-	  will be sent back to the AMI client. Unlike the Asterisk 11 and
-	  12 patches, this patch also deprecates the duplicate Message key
-	  in the response to the action, replacing it with the key
-	  'PresenceMessage'. Review:
-	  https://reviewboard.asterisk.org/r/3776/ ASTERISK-23985 #close
-	  ........ Merged revisions 418713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418714 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-15 23:03 +0000 [r418716]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/bridge_channel.c: TEST_FRAMEWORK: Fix ref leak in feature
-	  activation This fixes two reference leaks that would occur when
-	  TEST_FRAMEWORK was enabled and features were successfully
-	  executed. ........ Merged revisions 418715 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-15 17:57 +0000 [r418654]  Jonathan Rose <jrose at digium.com>
+2015-09-07 13:19 +0000 [07b25a2312]  Alexander Anikin <may213 at yandex.ru>
 
-	* funcs/func_uri.c, /: func_uri: URIENCODE/URIDECODE - allow empty
-	  strings as argument Previously these two dialplan functions would
-	  issue warnings and return failure when an empty string is used as
-	  the argument. Now they will not issue a warning and will
-	  successfully return an empty string. ASTERISK-23911 #close
-	  Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3745/ ........ Merged
-	  revisions 418641 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 418649 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418650 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	*     chan_ooh323: call ast_rtp_instance_stop on ooh323_destroy
 
-2014-07-15 12:11 +0000 [r418616]  Sean Bright <sean at malleable.com>
+	      Call ast_rtp_instance_stop on ooh323_destroy to free resources
+	      allocated by rtp instance
 
-	* main/asterisk.c: Update Asterisk copyright year in
-	  main/asterisk.c It's been 2014 for like... 6 months.
+	      ASTERISK-25299 #close
+	      Report by: Alexandr Dranchuk
 
-2014-07-14 14:55 +0000 [r418566-418587]  Richard Mudgett <rmudgett at digium.com>
+	  Change-Id: I455096bd7da016b871afe90af86067c2c7c9f33f
 
-	* include/asterisk/logger.h, /: logger.h: Extract DEBUG_ATLEAST()
-	  to complement VERBOSITY_ATLEAST(). ........ Merged revisions
-	  418586 from http://svn.asterisk.org/svn/asterisk/branches/12
+2015-09-04 16:06 +0000 [94b764c8f3]  David M. Lee <dlee at respoke.io>
 
-	* include/asterisk/jabber.h (removed), include/asterisk/jingle.h
-	  (removed), include/asterisk/frame_defs.h (removed),
-	  configs/h323.conf.sample (removed): Actually delete the removed
-	  files.
+	* Fix when remote candidates exceed PJ_ICE_MAX_CAND
 
-2014-07-13 21:57 +0000 [r418507]  Corey Farrell <git at cfware.com>
+	  We were passing the wrong count into pj_ice_sess_create_check_list(),
+	  causing the create to fail if we ever received more than PJ_ICE_MAX_CAND
+	  candidates.
 
-	* /, main/astobj2.c, contrib/scripts/refcounter.py: astobj2: work
-	  around REF_DEBUG race which causes out of order log entries *
-	  Update refcounter.py to use delta's to track the current
-	  reference count. * Use result from internal_ao2_ref to write
-	  old_refcount to refs_log. Review:
-	  https://reviewboard.asterisk.org/r/3756/ ........ Merged
-	  revisions 418504 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 418505 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418506 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-13 20:08 +0000 [r418488]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* include/asterisk/astobj2.h: astobj2: correct define for
-	  ao2_t_cleanup This change maps the ao2_t_cleanup() function to
-	  the correct debug function so that it can be used. Review:
-	  https://reviewboard.asterisk.org/r/3764/
-
-2014-07-13 16:48 +0000 [r418448-418467]  Corey Farrell <git at cfware.com>
-
-	* main/manager.c, /, apps/app_skel.c: Fix minor reference leaks in
-	  app_skel and TEST_FRAMEWORK * Cleanup games object in app_skel. *
-	  Cleanup stasis subscription to TEST_FRAMEWORK in manager.c (12+).
-	  Review: https://reviewboard.asterisk.org/r/3757/ ........ Merged
-	  revisions 418465 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418466 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/jabber.h, include/asterisk/jingle.h,
-	  configs/h323.conf.sample: Remove files left behind on removal of
-	  h323, jingle and jabber. This change removes h323.conf.sample,
-	  jingle.h, jabber.h left behind by r3698. Review:
-	  https://reviewboard.asterisk.org/r/3755/
-
-2014-07-11 23:00 +0000 [r418419]  Matthew Jordan <mjordan at digium.com>
-
-	* main/astobj2.c, include/asterisk/astobj2.h: astobj2: Add tag
-	  variants for ao2_bump, ao2_cleanup, and ao2_replace Tags are
-	  useful in hunting down ref imbalances; this patch adds tag
-	  variants for these commonly used macros/functions. Review:
-	  https://reviewboard.asterisk.org/r/3750/
-
-2014-07-11 21:10 +0000 [r418397]  Corey Farrell <git at cfware.com>
-
-	* /, include/asterisk/astobj2.h: astobj2: tweak ao2_replace to do
-	  nothing when it would be a NoOp This change causes ao2_replace to
-	  do nothing when src == dst. This avoids REF_DEBUG logging when
-	  we're not actually doing anything. Review:
-	  https://reviewboard.asterisk.org/r/3743/ ........ Merged
-	  revisions 418396 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-11 16:42 +0000 [r418370]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, main/config.c: config: inform config hook of change when
-	  writing file When updated configuration is written back to the
-	  conf file - for example when a user changes their voicemail pin,
-	  make sure that any config hook that wants to know of changes is
-	  informed. Review: https://reviewboard.asterisk.org/r/3708/
-	  ........ Merged revisions 418366 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418369 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-10 15:36 +0000 [r418325]  Matthew Jordan <mjordan at digium.com>
-
-	* /, include/asterisk/xmpp.h: include/asterisk/xmpp.h: Convert
-	  indentation to tabs This is a whitespace only change. ........
-	  Merged revisions 418323 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418324 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-10 01:59 +0000 [r418226-418264]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/sig_pri.c, /: chan_dahdi/sig_pri: Fix type mismatch in
-	  the idledial feature's channel creation. Square pegs in round
-	  holes don't work very well. ........ Merged revisions 418261 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 418262 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 418263 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/stasis/stasis_bridge.h (added), main/bridge_channel.c,
-	  res/res_stasis.c, /, res/stasis/stasis_bridge.c (added),
-	  include/asterisk/bridge_channel.h, main/bridge_basic.c: ARI: Make
-	  mixing bridges propagate linkedids and accountcodes. * Create a
-	  Stasis bridge sub-class to propagate linkedids and accountcodes.
-	  * Fixed the basic bridge sub-class to update peeraccount codes
-	  when the number of channels in the bridge drops back down to two
-	  parties. * Refactored ast_bridge_channel_update_accountcodes() to
-	  handle channels joining/leaving the bridge. * Fixed the basic
-	  bridge sub-class to not call the base bridge class pull method
-	  twice. AFS-105 #close ASTERISK-23852 #close Reported by: Richard
-	  Mudgett Review: https://reviewboard.asterisk.org/r/3720/ ........
-	  Merged revisions 418225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-08 14:48 +0000 [r418174-418183]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json,
-	  rest-api/api-docs/mailboxes.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json,
-	  rest-api/api-docs/playbacks.json,
-	  rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/resources.json, include/asterisk/manager.h,
-	  rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json: manager/ARI: Update version to
-	  2.4.0/1.4.0; Update UPGRADE.txt ........ Merged revisions 418182
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix undefined
-	  function when PJPROJECT is not installed The
-	  dtls_perform_handshake function was mistakenly placed under the
-	  guards for USE_PJPROJECT. If PJPROJECT was not installed, the
-	  function would not be defined, while other functions would
-	  attempt to still use it. This prevented res_rtp_asterisk from
-	  being loaded. ASTERISK-24001 #close Reported by: Don Fanning
-	  ........ Merged revisions 418172 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-07 16:08 +0000 [r418117]  Joshua Colp <jcolp at digium.com>
-
-	* include/asterisk/res_pjsip_body_generator_types.h,
-	  res/res_pjsip_dialog_info_body_generator.c (added),
-	  res/res_pjsip_exten_state.c, res/res_pjsip/presence_xml.c, /,
-	  include/asterisk/res_pjsip_presence_xml.h:
-	  res_pjsip_dialog_info_body_generator: Add dialog-info+xml support
-	  for presence. This module implements dialog-info+xml for the
-	  purposes of presence. This means that phones such as Grandstreams
-	  can now subscribe to receive presence information for an
-	  extension. ASTERISK-21443 #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3705/ ........ Merged
-	  revisions 418116 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-07 02:15 +0000 [r418090]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/stasis_app.h, res/ari/resource_channels.c,
-	  res/res_stasis.c, /, res/stasis/app.c: ARI/res_stasis: Subscribe
-	  to both Local channel halves when originating to app This patch
-	  fixes two bugs: 1. When originating a channel into a Stasis
-	  application, we already create a subscription for the channel
-	  that is going into our Stasis app. Unfortunately, when you create
-	  a Local channel and pass it off to a Stasis app, you really
-	  aren't creating just one channel: you're creating two. This patch
-	  snags the second half of the Local channel pair (assuming it is a
-	  Local channel pair, but luckily core_local is kind about such
-	  assumptions) and subscribes to it as well. 2. Subscriptions are a
-	  bit sticky right now. If a subscription is made, the 'interest'
-	  count gets bumped on the Stasis subscription - but unless
-	  something explicitly unsubscribes the channel, said subscription
-	  sticks around. This is not much of a problem is a user is
-	  creating the subscription - if they made it, they must want it.
-	  However, when we are creating implicit subscriptions, we need to
-	  make sure something clears them out. This patch takes a
-	  pessimistic approach: it watches the cache updates coming from
-	  Stasis and, if we notice that the cache just cleared out an
-	  object, we delete our subscription object. This keeps our ao2
-	  container of Stasis forwards in an application from growing out
-	  of hand; it also is a bit more forgiving for end users who may
-	  not realize they were supposed to unsubscribe from that channel
-	  that just hung up. Review:
-	  https://reviewboard.asterisk.org/r/3710/ #ASTERISK-23939 #close
-	  ........ Merged revisions 418089 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-07 01:22 +0000 [r418067-418084]  Kinsey Moore <kmoore at digium.com>
-
-	* tests/test_cel.c, main/cel.c, channels/chan_pjsip.c,
-	  res/res_pjsip_session.c, /: CEL: Fix incorrect/missing extra
-	  field information This corrects two issues with the extra field
-	  information in Asterisk 12+ in channel event logs. It is possible
-	  to inject custom values into the dialstatus provided by
-	  ast_channel_dial_type() Stasis messages that fall outside the
-	  enumeration allowed for the DIALSTATUS channel variable. CEL now
-	  filters for the allowed values and ignores other values. The
-	  "hangupsource" extra field key is always blank if the far end
-	  channel is a chan_pjsip channel. This is because the hangupsource
-	  is never set for the pjsip channel driver. This change sets the
-	  hangupsource whenever a hangup is queued for chan_pjsip channels.
-	  This corrects an issue with the pjsip channel driver where the
-	  hangupcause information was not being set properly. Review:
-	  https://reviewboard.asterisk.org/r/3690/ ........ Merged
-	  revisions 418071 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/http.c: HTTP: Fix build for gcc 4.10 ........ Merged
-	  revisions 418066 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-04 15:26 +0000 [r418019-418050]  Matthew Jordan <mjordan at digium.com>
-
-	* main/Makefile: main/Makefile: fix compilation error of buildinfo
-	  occurring on 'make install' Egads. Another bad deletion of too
-	  much when attempting to remove h323 stuff.
-
-	* configure.ac, build_tools/menuselect-deps.in, configure,
-	  main/Makefile: configure: Remove last vestiges of h323; DO create
-	  menuselect-deps The previous patch (r418034) fixed the 'glitch'
-	  that the channels/h323 Makefile no longer existed. Unfortunately,
-	  removing the entire line was a bit of a blunder, as it meant that
-	  build_tools/menuselect-deps was never generated. Hilarity ensued
-	  when actually trying to compile. But hey! At least configure
-	  worked. This patch fixes *that* glitch, and removes some more of
-	  the vestiges of h323. (It had tendrils in the main Makefile?
-	  Crazy.)
-
-	* configure.ac, configure: configure: Update script to pass if
-	  channels/h323/Makefile.in does not exist This simply removes that
-	  check from the configure script, as r418019 removed chan_h323.
-
-	* apps/app_dahdibarge.c (removed), configs/gtalk.conf.sample
-	  (removed), main/pbx.c, apps/app_readfile.c (removed),
-	  channels/chan_sip.c, configs/jingle.conf.sample (removed),
-	  UPGRADE.txt, res/res_musiconhold.c, channels/chan_gtalk.c
-	  (removed), channels/Makefile, CHANGES, res/res_jabber.c
-	  (removed), channels/h323 (removed), utils/conf2ael.c,
-	  channels/chan_jingle.c (removed), res/ael/pval.c,
-	  configs/jabber.conf.sample (removed),
-	  configs/asterisk.conf.sample, res/res_agi.c, channels/chan_h323.c
-	  (removed), addons/Makefile, pbx/pbx_realtime.c, utils/ael_main.c,
-	  include/asterisk/options.h, main/asterisk.c,
-	  addons/app_saycountpl.c (removed): Remove many deprecated modules
-	  Billing records are fair, To get paid is quite bright, You should
-	  really use ODBC; Good-bye cdr_sqlite. Microsoft did once push
-	  H.323, Hell, we all remember NetMeeting. But try to compile
-	  chan_h323 now And you will take quite a beating. The XMPP and SIP
-	  war was fierce, And in the distant fray Was birthed
-	  res_jabber/chan_jingle; But neither to stay. For everyone did
-	  care and chase what Google professed. "Free Internet Calling" was
-	  what devotees cried, But Google did change the specs so often
-	  That the developers were happy the day chan_gtalk died. And then
-	  there was that odd application Dedicated to the Polish tongue.
-	  app_saycountpl was subsumed by Say; One could say its bell was
-	  rung. To read and parse a file from the dialplan You could (I
-	  guess) use an application. app_readfile did fill that purpose,
-	  but I think A function is perhaps better in its creation. Barging
-	  is rude, I'm not sure why we do it. Inwardly, the caller will
-	  probably sigh. But if you really must do it, Don't use
-	  app_dahdibarge, use ChanSpy. We all despise the sound of tinny
-	  robots It makes our queues so cold. To control such an
-	  abomination It's better to not use Wait/SetMusicOnHold. It's
-	  often nice to know properties of a channel It makes our calls
-	  right We have a nice function called CHANNEL And so SIPCHANINFO
-	  is sent off into the night. And now things get odd; Apparently
-	  one could delimit with a colon Properties from the SIPPEER
-	  function! Commas are in; all others are done. Finally, a word on
-	  pipes and commas. We're sorry. We can't say it enough. But those
-	  compatibility options in asterisk.conf; To maintain them forever
-	  was just too tough. This patch removes: * cdr_sqlite * chan_gtalk
-	  * chan_jingle * chan_h323 * res_jabber * app_saycountpl *
-	  app_readfile * app_dahdibarge It removes the following
-	  applications/functions: * WaitMusicOnHold * SetMusicOnHold *
-	  SIPCHANINFO It removes the colon delimiter from the SIPPEER
-	  function. Finally, it also removes all compatibility options that
-	  were configurable from asterisk.conf, as these all applied to
-	  compatibility with Asterisk 1.4 systems. Review:
-	  https://reviewboard.asterisk.org/r/3698/
-
-2014-07-03 22:22 +0000 [r417933-417976]  Richard Mudgett <rmudgett at digium.com>
+	  Change-Id: I0303d8e1ecb20a8de9fe629a3209d216c4028378
 
-	* channels/sig_pri.h, channels/chan_dahdi.c,
-	  configs/chan_dahdi.conf.sample, /, UPGRADE.txt,
-	  channels/sig_pri.c: chan_dahdi: Add inband_on_setup_ack
-	  compatibility option. The new inband_on_setup_ack option causes
-	  Asterisk to assume inband audio may be present when a
-	  SETUP_ACKNOWLEDGE message is received. Q.931 Section 5.1.3 says
-	  that in scenarios with overlap dialing, when a dialtone is sent
-	  from the network side, progress indicator 8 "Inband info now
-	  available" MAY be sent to the CPE if no digits were received with
-	  the SETUP. It is thus implied that the ie is mandatory if digits
-	  came with the SETUP and dialtone is needed. This option should be
-	  enabled, when the network sends dialtone and you want to hear it,
-	  but the network doesn't send the progress indicator when needed.
-	  NOTE: For Q.SIG setups this option should be enabled when
-	  outgoing overlap dialing is also enabled because Q.SIG does not
-	  send the progress indicator with the SETUP ACK. The commit
-	  -r413714 (AST-1338) which causes this issue was dealing with a
-	  SIP-to-ISDN interoperability issue. This commit is a merge of the
-	  two patches indicated below. ASTERISK-23897 #close Reported by:
-	  Pavel Troller Patches: pri-4.diff (license #6302) patch uploaded
-	  by Pavel Troller jira_asterisk_23897_v11.patch (license #5621)
-	  patch uploaded by rmudgett Review:
-	  https://reviewboard.asterisk.org/r/3633/ ........ Merged
-	  revisions 417956 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417957 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417958 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_channels.c, res/res_ari.c, main/manager.c, /:
-	  res_ari: Fix some off-nominal paths just dropping the HTTP
-	  connection. * Removed some incorrect newlines on ast_http_error()
-	  messages in manager.c. * Removed an incorrect newline in
-	  res_ari_channels.c. Addendum to ASTERISK-23552 ........ Merged
-	  revisions 417932 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-03 17:34 +0000 [r417910-417916]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES, channels/chan_dahdi.c: chan_dahdi: Add AMI commands for
-	  controlling PRI debugging output Adds the following AMI commands:
-	  PRIDebugSet - Set PRI debug levels for a specific span
-	  PRIDebugFileSet - Set the file used for PRI debug message output
-	  PRIDebugFileUnset - Disables file output for PRI debug messages
-	  Review: https://reviewboard.asterisk.org/r/3681/
-
-	* CHANGES, pbx/pbx_config.c, main/pbx.c: pbx_config: Add manager
-	  actions to add/remove extensions Adds two new manager commands to
-	  pbx_config - DialplanExtensionAdd and DialplanExtensionRemove
-	  which allow manager users to create and delete extensions
-	  respectively. Review: https://reviewboard.asterisk.org/r/3650/
-
-2014-07-03 17:16 +0000 [r417901]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_phoneprov.c, main/http.c, UPGRADE.txt,
-	  include/asterisk/tcptls.h, res/res_http_post.c,
-	  res/res_http_websocket.c, configs/http.conf.sample,
-	  include/asterisk/http.h, main/tcptls.c, res/res_ari.c,
-	  main/manager.c, /: HTTP: Add persistent connection support.
-	  Persistent HTTP connection support is needed due to the increased
-	  usage of the Asterisk core HTTP transport and the frequency at
-	  which REST API calls are going to be issued. * Add http.conf
-	  session_keep_alive option to enable persistent connections. *
-	  Parse and discard optional chunked body extension information and
-	  trailing request headers. * Increased the maximum
-	  application/json and application/x-www-form-urlencoded body size
-	  allowed to 4k. The previous 1k was kind of small. * Removed a
-	  couple inlined versions of ast_http_manid_from_vars() by calling
-	  the function. manager.c:generic_http_callback() and
-	  res_http_post.c:http_post_callback() * Add missing va_end() in
-	  ast_ari_response_error(). * Eliminated unnecessary RAII_VAR() use
-	  in http.c:auth_create(). ASTERISK-23552 #close Reported by: Scott
-	  Griepentrog Review: https://reviewboard.asterisk.org/r/3691/
-	  ........ Merged revisions 417880 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-03 16:55 +0000 [r417900]  Matthew Jordan <mjordan at digium.com>
-
-	* main/tcptls.c, configure, include/asterisk/autoconfig.h.in,
-	  configure.ac: main/tcptls: Add checks for OpenSSL Elliptic Curve
-	  support The patch for ASTERISK-23905 that added PFS support in
-	  Asterisk depends on the elliptic curve library support being
-	  present in OpenSSL. As it turns out, some versions of OpenSSL
-	  don't have this library - notably the version running on our
-	  build agents. This patch fixes the build by providing a configure
-	  check for the specific library calls that the PFS patch relies
-	  on. Review: https://reviewboard.asterisk.org/r/3709/
-
-2014-07-03 16:14 +0000 [r417877-417879]  sgalarneau <sgalarneau at localhost>:
-
-	* res/ari/resource_events.h, rest-api/api-docs/channels.json,
-	  res/ari/resource_channels.h, rest-api/api-docs/events.json, /:
-	  ARI: Improvements to body parameters documentation The variables
-	  body parameter under the originate and originate with id
-	  operations of the channel resource showed invalid JSON in its
-	  description. The variables body parameter under the userEvent
-	  operation of the event resource made no mention that the custom
-	  key/value pairs should be wrapped in a variables key in order to
-	  be added to the custom user event. ASTERISK-23975 #close Review:
-	  https://reviewboard.asterisk.org/r/3692/ ........ Merged
-	  revisions 417878 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* rest-api-templates/api.wiki.mustache,
-	  rest-api-templates/swagger_model.py, /: api.wiki.mustache: Update
-	  wiki template to support body parameters This patch updates the
-	  api.wiki.mustache template and the swagger_model python script to
-	  understand if an operation has a body parameter. If an operation
-	  does have a body parameter, it will now be displayed in the
-	  corresponding wiki entry. ........ Merged revisions 407389 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-03 14:08 +0000 [r417863]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* Makefile, contrib/scripts/dahdi_span_config_hook (added):
-	  dahdi_span_config_hook: automatically register new dahdi channels
-	  Install a hook script for DAHDI to register new spans with
-	  Asterisk automatically by running: asterisk -rx 'dahdi create
-	  channel FIRST LAST' Review:
-	  https://reviewboard.asterisk.org/r/3157/
-
-2014-07-03 12:10 +0000 [r417800-417803]  Matthew Jordan <mjordan at digium.com>
-
-	* main/tcptls.c, CHANGES: main/tcptls: Add support for Perfect
-	  Forward Secrecy This patch enables Perfect Forward Secrecy (PFS)
-	  in Asterisk's core TLS API. Modules that wish to enable PFS
-	  should consider the following: - Ephemeral ECDH (ECDHE) is
-	  enabled by default. To disable it, do not specify a ECDHE cipher
-	  suite in a module's configuration, for example:
-	  tlscipher=AES128-SHA:DES-CBC3-SHA - Ephemeral DH (DHE) is
-	  disabled by default. To enable it, add DH parameters into the
-	  private key file, i.e., tlsprivatekey. For an example, see the
-	  default dh2048.pem at
-	  http://www.opensource.apple.com/source/OpenSSL098/OpenSSL098-35.1/src/apps/dh2048.pem?txt
-	  - Because clients expect the server to prefer PFS, and because
-	  OpenSSL sorts its cipher suites by bit strength, (see "openssl
-	  ciphers -v DEFAULT") consider re-ordering your cipher suites in
-	  the conf file. For example:
-	  tlscipher=AES128+kEECDH:AES128+kEDH:3DES+kEDH:AES128-SHA:DES-CBC3-SHA:-ADH:-AECDH
-	  will use PFS when offered by the client. Clients which do not
-	  offer PFS fall-back to AES-128 (or even 3DES as recommend by RFC
-	  3261). Review: https://reviewboard.asterisk.org/r/3647/
-	  ASTERISK-23905 #close Reported by: Alexander Traud patches:
-	  tlsPFS_for_HEAD.patch uploaded by Alexander Traud (License 6520)
-	  tlsPFS.patch uploaded by Alexander Traud (License 6520)
+2015-08-26 05:40 +0000 [59636e82b2]  Joshua Colp <jcolp at digium.com>
 
-	* /, main/utils.c: main/untils: Prevent potential infinite loop in
-	  ast_careful_fwrite A loop in ast_careful_fwrite exists that will
-	  continually attempt to write to a file stream, even in the
-	  presence of EAGAIN/EINTR errors. However, if a connection that
-	  uses ast_careful_fwrite closes suddenly, ast_careful_fwrite's
-	  call to fflush may return EAGAIN/EINTER along with EOF. A
-	  subsequent call to fflush will return EOF but not clear errno,
-	  resulting in an infinite loop. This patch clears errno after it
-	  is detected and handled the loop, such that any subsequent call
-	  to fflush will not get erroneously stuck. Review:
-	  https://reviewboard.asterisk.org/r/3704 #ASTERISK-23984 #close
-	  Reported by: Steve Davies patches: fflush_loop_fix uploaded by
-	  one47 (License 5012) ........ Merged revisions 417797 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417798 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417799 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-02 21:13 +0000 [r417770]  Jonathan Rose <jrose at digium.com>
-
-	* res/ari/resource_events.h, res/ari/resource_asterisk.h,
-	  res/ari/resource_applications.h, res/ari/resource_playbacks.h,
-	  res/ari/resource_channels.h, res/ari/resource_sounds.h, /,
-	  res/ari/resource_bridges.h, res/ari/resource_recordings.h,
-	  rest-api-templates/ari_resource.h.mustache,
-	  res/ari/resource_device_states.h, res/ari/resource_endpoints.h,
-	  res/ari/resource_mailboxes.h: ARI: Remove unnecessary \briefs
-	  from automatically generated documentation Review:
-	  https://reviewboard.asterisk.org/r/3440/ ........ Merged
-	  revisions 412653 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-07-01 14:42 +0000 [r417679-417706]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Don't leak memory or
-	  reset state if DTLS configuration is set multiple times. ........
-	  Merged revisions 417705 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_rtp_asterisk.c,
-	  contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
-	  (added), include/asterisk/res_pjsip_session.h, main/rtp_engine.c,
-	  /, channels/chan_sip.c, main/sdp_srtp.c, res/res_pjsip_sdp_rtp.c,
-	  res/res_pjsip/pjsip_configuration.c, configs/sip.conf.sample,
-	  include/asterisk/rtp_engine.h, res/res_pjsip.c,
-	  channels/sip/include/sip.h, include/asterisk/res_pjsip.h,
-	  include/asterisk/sdp_srtp.h: Recorded merge of revisions 417677
-	  from http://svn.asterisk.org/svn/asterisk/branches/11 ........
-	  res_rtp_asterisk: Add SHA-256 support for DTLS and perform DTLS
-	  negotiation on RTCP. This change fixes up DTLS support in
-	  res_rtp_asterisk so it can accept and provide a SHA-256
-	  fingerprint, so it occurs on RTCP, and so it occurs after ICE
-	  negotiation completes. Configuration options to chan_sip and
-	  chan_pjsip have also been added to allow behavior to be tweaked
-	  (such as forcing the AVP type media transports in SDP).
-	  ASTERISK-22961 #close Reported by: Jay Jideliov Review:
-	  https://reviewboard.asterisk.org/r/3679/ Review:
-	  https://reviewboard.asterisk.org/r/3686/ ........ Merged
-	  revisions 417678 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-30 18:39 +0000 [r417663]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pubsub.c: Reverse logic during subscription
-	  persistence recreation. In the abstraction effort, this bit of
-	  logic got messed up. We want to recreate the persistence if
-	  things go well, not if things fail.
-
-2014-06-30 13:02 +0000 [r417590-417649]  Matthew Jordan <mjordan at digium.com>
-
-	* apps/app_voicemail.c: apps/app_voicemail: Fix compilation error
-	  introduced in r417591 Not sure why that change to
-	  ast_channel_alloc was made but ... okay.
-
-	* apps/app_voicemail.c, main/say.c, CHANGES: app_voicemail, say:
-	  Add support for Japanese Language This patch adds support for the
-	  Japanese language to both the say family of applications, as well
-	  as for VoiceMail and VoiceMailMain. A new pack of language sounds
-	  will be released at the same time as the next major version of
-	  Asterisk to support the new language features. The language
-	  features can be enabled using a language code of 'ja'. Review:
-	  https://reviewboard.asterisk.org/r/3477 ASTERISK-23324 #close
-	  Reported by: Kevin McCoy patches:
-	  app_voicemail.c.20140226.jb.patch uploaded by Kevin McCoy
-	  (License 6586) say.c.20140226.jb.patch uploaded by Kevin McCoy
-	  (License 6586)
+	* chan_sip: Allow call pickup to set the hangup cause.
 
-	* /, channels/chan_sip.c: chan_sip: be more tolerant of whitespace
-	  between attributes in SDP fmtp line This patch is essentially a
-	  backport of a small portion of r397526 from ASTERISK-21981. In
-	  that patch, pass through support and format attribute negotiation
-	  was added for Opus. Part of that included being more tolerant to
-	  whitespace in the fmtp line of an SDP; that part of the patch is
-	  being applied here. As the author of the backport pointed out, in
-	  SDP, the fmtp line is allowed to include whitespace between
-	  attributes. RFC 3267 chapter 8.3 (from 2001) includes an example
-	  for this. This was not removed in the updated RFC 4867 in 2007.
-	  Review: https://reviewboard.asterisk.org/r/3658 #ASTERISK-23916
-	  #close Reported by: Alexander Traud patches:
-	  sdpFMTPspace_Asterisk11.patch uploaded by Alexander Traud
-	  (License 6520) ........ Merged revisions 417587 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417588 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417589 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  The call pickup implementation in chan_sip currently sets the channel
+	  hangup cause to "normal clearing" if call pickup is successfully
+	  performed. This action overwrites the "answered elsewhere" hangup cause
+	  set by the call pickup code and can result in the SIP device in
+	  question showing a missed call when it should not.
 
-2014-06-27 23:21 +0000 [r417571]  Richard Mudgett <rmudgett at digium.com>
+	  This change sets the hangup cause to "normal clearing" as a
+	  default initially but allows the call pickup to change it as
+	  needed.
 
-	* /, main/event.c: event.c: Fix type mismatch errors in ie_maps[].
-	  In v12+ the type values from the table are only used by the CEL
-	  unit tests. Since the unit tests were only comparing a generated
-	  expected event with a real event to see if the ie contents
-	  matched and using the same table IE_PLTYPE values to read the
-	  event contents, the type mismatches were not detected. ........
-	  Merged revisions 417565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25346 #close
 
-2014-06-27 19:27 +0000 [r417485-417511]  Corey Farrell <git at cfware.com>
+	  Change-Id: I00ac2c269cee9e29586ee2c65e83c70e52a02cff
 
-	* /, main/astobj2.c: Ensure REF_DEBUG records entrys for attempts
-	  to ao2_ref an invalid object This change ensures that
-	  __ao2_ref_debug writes to ref_log when given a non-NULL pointer
-	  to an invalid ao2 object. This is to ensure that we record any
-	  attempt manipulate references of already freed objects.
-	  ASTERISK-23948 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3677/ ........ Merged
-	  revisions 417500 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417505 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417509 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-08-19 10:30 +0000 [b4535b0e59]  Scott Griepentrog <scott at griepentrog.com>
 
-	* /, contrib/scripts/refcounter.py: refcounter.py: prevent use of
-	  excessive RAM with large refs logs When processing a 212MB refs
-	  file, refcounter.py used over 3GB of RAM. This change greatly
-	  reduces memory usage in two ways: * Saving object history in
-	  whole lines instead of separated values. * Not saving
-	  normal/skewed/leaked object lists unless they are requested.
-	  ASTERISK-23921 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3668/ ........ Merged
-	  revisions 417480 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417481 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417483 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* contrib: script install_prereq should install sqlite3
 
-2014-06-27 13:50 +0000 [r417461]  Matthew Jordan <mjordan at digium.com>
+	  Asterisk needs the sqlite 3 library, which is package
+	  sqlite-devel in CentOS. By adding this package to the
+	  script, a problem with configure failing is resolved.
 
-	* res/res_pjsip/pjsip_configuration.c, res/res_pjsip_pubsub.c,
-	  res/res_pjsip_registrar.c, include/asterisk/res_pjsip.h, /,
-	  res/res_pjsip_outbound_registration.c: res_pjsip: Add ActionID to
-	  events created as a result of PJSIP AMI actions A number of
-	  various PJSIP AMI actions were failing to parse out and place the
-	  ActionID into their responses. This patch updates the various
-	  PJSIP actions such that the passed in ActionID is emitted on any
-	  event list complete events, as well as any intermediate events
-	  created as a result of the action. #ASTERISK-23947 #close
-	  Reported by: Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3675/ ........ Merged
-	  revisions 417460 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25331 #close
+	  Reported by: Kevin Harwell
 
-2014-06-27 02:04 +0000 [r417423-417447]  Kinsey Moore <kmoore at digium.com>
+	  Change-Id: I90efaf6a01914fea03f21e5cdbd91c348f44b0ec
 
-	* tests/test_cel.c: CEL: Update unit tests for bridge tech field
-	  Update the CEL unit tests that handle BRIDGE_ENTER and
-	  BRIDGE_EXIT events to expect the "bridge_technology" extra field
-	  key.
+2015-08-17 16:41 +0000 [6a364807f4]  Richard Mudgett <rmudgett at digium.com>
 
-	* CHANGES: CHANGES: Add missing changes Add missing CHANGES changes
-	  from r417361 and r417383.
+	* app_queue.c: Extract some functions for simpler code.
 
-2014-06-26 18:27 +0000 [r417400-417421]  Matthew Jordan <mjordan at digium.com>
+	  * Extract set_queue_member_pause() from set_member_paused() for simpler
+	  and more consistent code.
 
-	* res/res_http_websocket.exports.in, /: res_http_websocket: Export
-	  symbol for ast_websocket_set_timeout Thanks to Sean Bright for
-	  pointing out that this was missed in #asterisk-dev. ........
-	  Merged revisions 417419 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417420 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_pjsip.c, /: chan_pjsip: Add a test event for fast
-	  picture updates This will drive the test on review r3419. Note
-	  that the patch for this was done by Ben Ford, although it was
-	  slightly modified for this commit. ASTERISK-23562 Reported by:
-	  Matt Jordan ........ Merged revisions 417399 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-26 14:48 +0000 [r417361-417383]  Kinsey Moore <kmoore at digium.com>
-
-	* main/cel.c: CEL: Add bridge tech to relevant CEL records Add the
-	  "bridge_technology" extra field key to BRIDGE_ENTER and
-	  BRIDGE_EXIT CEL events to convey the bridge technology in use at
-	  the time the record was generated.
-
-	* main/bridge.c, include/asterisk/channel.h,
-	  include/asterisk/bridge_features.h,
-	  tests/test_channel_feature_hooks.c (added),
-	  main/bridge_channel.c, main/channel.c: Bridging: Allow channels
-	  to define bridging hooks This patch allows the current owner of a
-	  channel to define various feature hooks to be made available once
-	  the channel has entered a bridge. This includes any hooks that
-	  are setup on the ast_bridge_features struct such as DTMF hooks,
-	  bridge event hooks (join, leave, etc.), and interval hooks.
-	  Review: https://reviewboard.asterisk.org/r/3649/
-
-2014-06-26 12:43 +0000 [r417317-417360]  Matthew Jordan <mjordan at digium.com>
-
-	* CHANGES, apps/app_jack.c: app_jack: Support audio with a sampling
-	  rate higher than 8kHz This patch enables the jack-audiohook to
-	  cope with dynamic sampling rates from and to Asterisk.
-	  Information from the channel is taken to derive the channel's
-	  sampling rate, suiting SLINxx format and frame->datalen. There
-	  are stil a few limitations after this patch: * Required
-	  information is taken from the channel during initialization as
-	  the audiohook does not provide this information.
-	  Audiohook.internal_sampl_rate(...) is set later, but no callback
-	  is available to inform app_jack. * Frame.datalen is computed
-	  using "rate / 50" assuming a ptime of 20ms. There is no internal
-	  API available to determine datalen for a SLINxx. * Ringbuffer
-	  size is now dynamic depending on the value of frame.datalen (see
-	  above) and the number of frames, which are in
-	  RINGBUFFER_FRAME_CAPACITY, that need to fit. Review:
-	  https://reviewboard.asterisk.org/r/3618 Note that the patch being
-	  committed here is based on the patch posted on ASTERISK-23836.
-	  However, Matthis Schmieder also provided a patch to enable this
-	  functionality, and that patch is noted below. ASTERISK-20696
-	  #close Reported by: Matthis Schmieder patches: app_jack.patch
-	  uploaded by Matthis Schmieder (License 6445) ASTERISK-23836
-	  #close Reported by: Dennis Guse patches: patch-app_jack.c
-	  uploaded by Dennis Guse (License 6513)
+	  * Extract set_queue_member_ringinuse() from
+	  set_member_ringinuse_help_members() for simpler code.
 
-	* main/udptl.c, /: udptl: Correct FEC to not consider negative
-	  sequence numbers as missing When using FEC, with span=3 and
-	  entries=4 Asterisk will attempt to repair the packet with
-	  sequence number 5, as it will see that packet -4 is missing. The
-	  result is Asterisk sending garbage packets that can kill a fax.
-	  This patch adds a check to see if the sequence number is valid
-	  before checking if the packet is missing. Review:
-	  https://reviewboard.asterisk.org/r/3657/ #ASTERISK-23908 #close
-	  Reported by: Torrey Searle patches: udptl_fec.patch uploaded by
-	  Torrey Searle (License 5334) ........ Merged revisions 417318
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 417320 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417324 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/internal.h, configs/ari.conf.sample,
-	  res/res_http_websocket.c, res/res_pjsip.c,
-	  configs/pjsip.conf.sample, include/asterisk/http_websocket.h,
-	  configs/sip.conf.sample, res/res_pjsip/config_transport.c,
-	  res/ari/ari_websockets.c, res/res_pjsip_transport_websocket.c,
-	  res/ari/config.c, channels/sip/include/sip.h,
-	  include/asterisk/res_pjsip.h, res/res_ari.c, /,
-	  channels/chan_sip.c, UPGRADE.txt: res_http_websocket: Close
-	  websocket correctly and use careful fwrite When a client takes a
-	  long time to process information received from Asterisk, a write
-	  operation using fwrite may fail to write all information. This
-	  causes the underlying file stream to be in an unknown state, such
-	  that the socket must be disconnected. Unfortunately, there are
-	  two problems with this in Asterisk's existing websocket code: 1.
-	  Periodically, during the read loop, Asterisk must write to the
-	  connected websocket to respond to pings. As such, Asterisk
-	  maintains a reference to the session during the loop. When
-	  ast_http_websocket_write fails, it may cause the session to
-	  decrement its ref count, but this in and of itself does not break
-	  the read loop. The read loop's write, on the other hand, does not
-	  break the loop if it fails. This causes the socket to get in a
-	  'stuck' state, preventing the client from reconnecting to the
-	  server. 2. More importantly, however, is that the fwrite in
-	  ast_http_websocket_write fails with a large volume of data when
-	  the client takes awhile to process the information. When it does
-	  fail, it fails writing only a portion of the bytes. With some
-	  debugging, it was shown that this was failing in a similar
-	  fashion to ASTERISK-12767. Switching this over to
-	  ast_careful_fwrite with a long enough timeout solved the problem.
-	  Note that this version of the patch, unlike r417310 in Asterisk
-	  11, exposes configuration options beyond just chan_sip's
-	  sip.conf. Configuration options to configure the write timeout
-	  have also been added to pjsip.conf and ari.conf. #ASTERISK-23917
-	  #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3624/ ........ Merged
-	  revisions 417310 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-26 10:06 +0000 [r417251]  Corey Farrell <git at cfware.com>
+	  NOTE: This may fix a consistency issue with realtime ringinuse
+	  because the ordering of things was backported from v13.  It is
+	  similar to how set_member_paused() treats realtime for paused.
 
-	* /, channels/chan_sip.c: chan_sip: Fix handling of "From" headers
-	  longer than 256 characters From headers were processed using a
-	  256 character buffer on the stack. This change replaces that with
-	  a heap allocation by ast_strdup. ASTERISK-23790 #close Reported
-	  by: uniken1 Tested by: uniken1 Review:
-	  https://reviewboard.asterisk.org/r/3669/ Patches:
-	  chan_sip-large-from-header-1.8-r3.patch uploaded by wdoekes
-	  (license 5674) ........ Merged revisions 417248 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 417249 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 417250 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-25 20:57 +0000 [r417233]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pubsub.c, res/res_pjsip_exten_state.c,
-	  include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_pidf_body_generator.c,
-	  res/res_pjsip_pubsub.exports.in, res/res_pjsip_mwi.c,
-	  res/res_pjsip_xpidf_body_generator.c: Abstract PJSIP-specific
-	  elements from the pubsub API. This helps to pave the way for RLS
-	  work that is to come. Since this is a self-contained change and
-	  subscription tests still pass, this work is being committed
-	  directly to trunk instead of a working branch. ASTERISK-23865
-	  #close Review: https://reviewboard.asterisk.org/r/3628
-
-2014-06-25 18:57 +0000 [r417213]  Corey Farrell <git at cfware.com>
-
-	* main/astobj2_container.c, /: ao2_container node object ignores
-	  REF_DEBUG in all places except one Almost every reference
-	  operation against container node's uses __ao2_alloc or __ao2_ref,
-	  thereby preventing ref logging for the nodes. One node reference
-	  is released with ao2_t_ref, causing refcounter.py to falsely
-	  report skews and leaks for many nodes. ASTERISK-23922 #close
-	  Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3670/ ........ Merged
-	  revisions 417212 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Iecc1f4119c63347341d7ea6b65f5fc4963706306
 
-2014-06-25 00:45 +0000 [r417193]  Damien Wedhorn <voip at facts.com.au>
+2015-08-17 13:34 +0000 [a56da797d9]  Richard Mudgett <rmudgett at digium.com>
 
-	* channels/chan_skinny.c: Skinny: cleanup some log messages around
-	  sessions.
+	* app_queue.c: Fix error checking in QUEUE_MEMBER() read.
 
-2014-06-24 02:50 +0000 [r417167]  Corey Farrell <git at cfware.com>
+	  Change-Id: I7294e13d27875851c2f4ef6818adba507509d224
 
-	* include/asterisk/netsock.h, main/utils.c, main/netsock.c,
-	  include/asterisk/res_pjsip_session.h: Move eid functions to
-	  utils.c, mark netsock.h deprecated Move eid functions from
-	  netsock.c to utils.c. These functions were already published by
-	  utils.h. Flag netsock.h as deprecated and switch
-	  res_pjsip_session.h to use netsock2.h. The only code that still
-	  uses netsock.h is chan_iax2. ASTERISK-23920 #close Reported by:
-	  Corey Farrell Review: https://reviewboard.asterisk.org/r/3661/
+2015-08-14 12:55 +0000 [43150cc58d]  Richard Mudgett <rmudgett at digium.com>
 
-2014-06-23 18:50 +0000 [r417143]  Joshua Colp <jcolp at digium.com>
+	* app_queue.c: Fix setting QUEUE_MEMBER 'paused' and 'ringinuse'.
 
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Return the length of
-	  data written when sending via ICE instead of 0. ASTERISK-23834
-	  #close Reported by: Richard Kenner ........ Merged revisions
-	  417141 from http://svn.asterisk.org/svn/asterisk/branches/11
-	  ........ Merged revisions 417142 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-23 16:04 +0000 [r417120]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/core_unreal.c: core_unreal: Fix off by one buffer
-	  overwrite error. Appending the ;2 to the user supplied ;1
-	  uniqueid to create the ;2 version if the user did not also supply
-	  an extra uniqueid for the ;2 channel resulted in allocating a
-	  buffer that was one byte too small. * Fix off by one error in
-	  ast_unreal_new_channels() when generating the ;2 uniqueid from
-	  the user suppled ;1 version. * Pulled some long assignment lines
-	  from if tests to improve line break readability in
-	  ast_unreal_new_channels(). ........ Merged revisions 417119 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-23 07:44 +0000 [r417059]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* channels/sig_pri.c, channels/sig_pri.h, channels/chan_dahdi.c:
-	  suspended destructions of pri spans on events If a DAHDI span
-	  disappears, we wish for its representation in Asterisk to be
-	  destroyed as well. The information about the span's removal may
-	  come from several paths: 1. DAHDI sends DAHDI_EVENT_REMOVE on
-	  every channel. 2. An extra DAHDI_EVENT_REMOVED is sent on every
-	  subsequent call to DAHDI_GET_EVENT. 3. Every read (including the
-	  internal one by libpri on the D-channel) returns -ENODEV.
-	  Asterisk responsds to DAHDI_EVENT_REMOVE on a channel by
-	  destroying it. Destroying a channel requires holding the channel
-	  list lock (iflock). Destroying a channel that is part of a span
-	  requires holding the span's lock. Destroying a channel from a
-	  context that holds the span lock, while at the same time another
-	  channel is destroyed directly, leads to a deadlock. Solution:
-	  don't destroy span while holding the channels list lock. Thus
-	  changes in this patch: * Deferring removal of PRI spans in
-	  response to events: doomed spans are collected on a list. *
-	  Doomed spans are removed periodically by the monitor thread. *
-	  ENODEV reads from the D-channel will warant the same deferred
-	  removal. Review: https://reviewboard.asterisk.org/r/3548/
-
-2014-06-22 18:53 +0000 [r416996]  George Joseph <george.joseph at fairview5.com>
-
-	* include/asterisk/astobj2.h, Makefile.rules, Makefile, /: astobj2:
-	  Add an ao2_replace macro to astobj2.h This macro replaces one
-	  object reference with another cleaning up the original. param dst
-	  Pointer to the object that will be cleaned up. param src Pointer
-	  to the object replacing it. src's ref count is bumped if it's
-	  non-NULL. dst's ref count is decremented if it's non-NULL. src is
-	  assigned to dst, This patch was reviewed on IRC by coreyfarrell
-	  and mjordan. Tested by: George Joseph ........ Merged revisions
-	  416995 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-20 23:18 +0000 [r416872-416935]  George Joseph <george.joseph at fairview5.com>
+	  Setting the 'paused' and 'ringinuse' options on a queue member using the
+	  dialplan function QUEUE_MEMBER did not behave the same way as the
+	  equivalent dialplan applications or AMI actions.
 
-	* /, configure, include/asterisk/autoconfig.h.in: build: Allow
-	  autoconf/ast_ext_tool_check to handle cross-compiling better.
-	  ast_ext_tool_check.m4 isn't handling cases where a path to a
-	  package is provided (E.G. --with-mysqlclient=/some/sysroot) and
-	  the package has a config tool (E.G. mysql_config) and the package
-	  has its own subdirectories in include or lib. For example,
-	  mysql's libraries are in ${MYSQLCLIENT_DIR}/usr/lib/mysql but
-	  ast_ext_tool_check sets MYSQLCLIENT_LIB to
-	  ${MYSQLCLIENT_DIR}/usr/lib. libxml2 has the same problem with its
-	  includes. They're in ${LIBXML2_DIR}/usr/include/libxml2 not
-	  directly in ${LIBXML2_DIR}/usr/include. Both cause configure to
-	  fail and there are others in the same boat. The problem is caused
-	  by logic in ast_ext_tool_check that overrides the result of the
-	  config tool's --cflags and --libs options if package_DIR is set.
-	  This patch prepends package_DIR (if specified) to the -L and -I
-	  results from the package's config tool instead of overriding
-	  them. A regenerated ./configure and
-	  include/asterisk/autoconfig.h.in are included but can be
-	  regenerated by running ./bootstrap.sh at any time. Tested by:
-	  George Joseph Tested by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3550/ ........ Merged
-	  revisions 416929 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416930 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416931 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  * Made queue_function_mem_write() call the set_member_paused() and
+	  set_member_value() for the 'paused' and 'ringinuse' options respectively.
+	  A beneficial side effect is that the queue name is now optional and sets
+	  the value in all queues the interface is a member.
 
-	* autoconf/ast_ext_tool_check.m4, /: build: Allow
-	  autoconf/ast_ext_tool_check to handle cross-compiling better.
-	  ast_ext_tool_check.m4 isn't handling cases where a path to a
-	  package is provided (E.G. --with-mysqlclient=/some/sysroot) and
-	  the package has a config tool (E.G. mysql_config) and the package
-	  has its own subdirectories in include or lib. For example,
-	  mysql's libraries are in ${MYSQLCLIENT_DIR}/usr/lib/mysql but
-	  ast_ext_tool_check sets MYSQLCLIENT_LIB to
-	  ${MYSQLCLIENT_DIR}/usr/lib. libxml2 has the same problem with its
-	  includes. They're in ${LIBXML2_DIR}/usr/include/libxml2 not
-	  directly in ${LIBXML2_DIR}/usr/include. Both cause configure to
-	  fail and there are others in the same boat. The problem is caused
-	  by logic in ast_ext_tool_check that overrides the result of the
-	  config tool's --cflags and --libs options if package_DIR is set.
-	  This patch prepends package_DIR (if specified) to the -L and -I
-	  results from the package's config tool instead of overriding
-	  them. Tested by: George Joseph Tested by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3550/ ........ Merged
-	  revisions 416870 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416871 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-20 20:57 +0000 [r416848-416850]  Jonathan Rose <jrose at digium.com>
-
-	* res/parking/parking_manager.c, /: res_parking: Make manager
-	  commands register with module information Previously module
-	  information was not included due to an oversight. Review:
-	  https://reviewboard.asterisk.org/r/3626/ ........ Merged
-	  revisions 416849 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/logger.c, CHANGES, include/asterisk/logger.h,
-	  main/manager.c: Logger: Add manager command 'LoggerRotate' to
-	  rotate logger Part of a series of AMI command equivalents to
-	  existing CLI commands Review:
-	  https://reviewboard.asterisk.org/r/3651/
-
-2014-06-20 17:06 +0000 [r416830]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_voicemail.c, include/asterisk/app.h, main/app.c,
-	  apps/app_directory.c, apps/app_chanspy.c: voicemail API
-	  callbacks: Extract the sayname API call to its own registerd
-	  callback. * Extract the sayname API call to its own registerd
-	  callback. This allows the app_directory and app_chanspy
-	  applications to say a mailbox owner's name using an alternate
-	  provider when app_voicemail is not available because you are
-	  using res_mwi_external. app_directory still uses the
-	  voicemail.conf file. AFS-64 #close Reported by: Mark Michelson
-
-2014-06-20 15:27 +0000 [r416738-416807]  George Joseph <george.joseph at fairview5.com>
-
-	* main/astobj2_private.h, main/astobj2_container_private.h,
-	  main/astobj2_container.c, main/astobj2_hash.c,
-	  main/astobj2_rbtree.c, build_tools/cflags.xml, /,
-	  tests/test_astobj2.c: astobj2: Additional refactoring to push
-	  impl specific code down into the impls. Move some implementation
-	  specific code from astobj2_container.c into astobj2_hash.c and
-	  astobj2_rbtree.c. This completely removes the need for
-	  astobj2_container to switch on RTTI and it no longer has any
-	  knowledge of the implementation details. Also adds AO2_DEBUG as a
-	  new compile option in menuselect which controls astobj2 debugging
-	  independently of AST_DEVMODE and REF_DEBUG. Tested by: George
-	  Joseph Review: https://reviewboard.asterisk.org/r/3593/ ........
-	  Merged revisions 416806 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c, main/acl.c,
-	  include/asterisk/netsock2.h, include/asterisk/acl.h,
-	  main/netsock2.c: pjsip cli: Change Identify to show CIDR notation
-	  instead of netmasks. * Added ast_sockaddr_cidr_bits() to count
-	  the 1 bits in an ast_sockaddr. * Added ast_ha_join_cidr() which
-	  uses ast_sockaddr_cidr_bits() for the netmask instead of
-	  ast_sockaddr_stringify_addr. * Changed
-	  res_pjsip_endpoint_identifier_ip to call ast_ha_join_cidr()
-	  instead of ast_ha_join() for the CLI output. This is a CLI change
-	  only. AMI was not affected. Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3652/ ........ Merged
-	  revisions 416737 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-19 19:40 +0000 [r416736]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/bridge.c, res/parking/parking_tests.c,
-	  channels/sip/reqresp_parser.c, main/logger.c, main/test.c: Fix
-	  build warnings with TEST_FRAMEWORK enabled ........ Merged
-	  revisions 416732 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416733 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416734 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-19 16:04 +0000 [r416589-416670]  George Joseph <george.joseph at fairview5.com>
-
-	* pbx/pbx_lua.c, /: Remove the problematic and unneeded
-	  AST_MODFLAG_GLOBAL_SYMBOLS from pbx_lua.c
-	  AST_MODFLAG_GLOBAL_SYMBOLS was causing the module to be
-	  incorrectly loaded before pbx_config. pbx_config was therefore
-	  blowing away contexts that were created by pbx_lua. With
-	  AST_MODFLAG_DEFAULT the load order is now correct and contexs are
-	  being properly merged. AST_MODFLAG_GLOBAL_SYMBOLS was not needed
-	  anyway since no other modules needed its global symbols that
-	  early. ASTERISK-23818 #close Reported by: Dennis Guse Tested by:
-	  Dennis Guse Tested by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3629/ ........ Merged
-	  revisions 416668 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416669 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* configs/extensions.lua.sample, /: Update extensions.lua.sample
-	  with naming conflict guidance. The sample extensions.lua was
-	  causing pbx_lua to fail to load when parsing 'app.goto("default",
-	  "s", 1)' because in Lua 5.2, 'goto' is now a reserved word. This
-	  patch adds guidance to extensions.lua.sample and changed
-	  'app.goto("default", "s", 1)' to 'app.['goto']("default", "s",
-	  1)'. ASTERISK-23844 #close Reported by: rnewton Tested by:
-	  gtjoseph Review: https://reviewboard.asterisk.org/r/3627/
-	  ........ Merged revisions 416581 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416582 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-18 04:22 +0000 [r416561]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/stasis_channels.c: stasis_channels: Update the stasis
-	  cache if manager variables are needed In r416211, the publishing
-	  of variable changes was modified such that a cached channel
-	  snapshot was used if manager variables were not requested with
-	  each AMI event. This was done to reduce the amount of channel
-	  snapshots created. However, an assumption was made that
-	  generating a channel snapshot and publishing the snapshot to the
-	  channel topic was sufficient to ensure that the cache would be
-	  updated; this is not the case. The channel snapshot type must be
-	  used to force a snapshot update. This patch updates the
-	  publication of channel variables such that the cache is updated
-	  prior to publication of the channel variable message if manager
-	  variables are in use. This ensures that all AMI events receive
-	  the variable update when they are supposed to. Note that this
-	  issue was caught by the Asterisk Test Suite (go go testing)
-	  ........ Merged revisions 416557 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-17 18:45 +0000 [r416444-416503]  Mark Michelson <mmichelson at digium.com>
+	  NOTE: This may fix a consistency issue with the realtime paused setting
+	  since how the value is set is controlled by set_member_paused() which
+	  treats realtime a little better.
 
-	* /, funcs/func_strings.c: Allow the PUSH and UNSHIFT functions to
-	  set inheritable channel variables. ........ Merged revisions
-	  416500 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 416501 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416502 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pidf_body_generator.c, /,
-	  res/res_pjsip_xpidf_body_generator.c: Fix string growth algorithm
-	  for XML presence bodies. pjpidf_print() does not return < 0 if
-	  there is not enough room for the document to be printed. Rather,
-	  it returns 39, the length of the XML prolog. The algorithm also
-	  had a bug in that it would return if it attempted to grow the
-	  string larger. ........ Merged revisions 416442 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-17 16:33 +0000 [r416443]  Kinsey Moore <kmoore at digium.com>
+	  * Update QUEUE_MEMBER XML documentation.
 
-	* res/res_musiconhold.c, /: MoH: Don't restart stream on repeated
-	  start calls Currently, music on hold will stop and then start
-	  again from the beginning if ast_moh_start() is called multiple
-	  times. This can happen if a call is put on hold repeatedly (the
-	  channel receives multiple HOLD control frames) and can be
-	  triggered from ARI by starting MoH on a channel multiple times.
-	  This is fairly jarring/annoying to users. This change prevents
-	  MoH from being restarted if the requested music class is the same
-	  as the one currently playing. This includes an extra check to
-	  prevent the errors previously experienced in the testsuite and
-	  has 100+ test runs behind it. Review:
-	  https://reviewboard.asterisk.org/r/3615/ ........ Merged
-	  revisions 416439 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416440 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416441 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-16 18:27 +0000 [r416416]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_dahdi.c, configs/chan_dahdi.conf.sample,
-	  channels/sig_ss7.h, configure, channels/chan_dahdi.h,
-	  configure.ac, UPGRADE.txt, configs/ss7.timers.sample (added),
-	  CHANGES, channels/sig_ss7.c: chan_dahdi: Adds support for major
-	  update to libss7. * SS7 support now requires libss7 v2.0 or
-	  later. The new libss7 is not backwards compatible. * Added SS7
-	  support for connected line and redirecting. * Most SS7 CLI
-	  commands are reworked as well as new SS7 commands added. See
-	  online CLI help. * Added several SS7 config option parameters
-	  described in chan_dahdi.conf.sample. * ISUP timer support
-	  reworked and now requires explicit configuration. See
-	  ss7.timers.sample. Special thanks to Kaloyan Kovachev for his
-	  support and persistence in getting the original patch by adomjan
-	  updated and ready for release. SS7-27 #close Reported by: adomjan
-
-2014-06-16 16:22 +0000 [r416394]  Kevin Harwell <kharwell at digium.com>
-
-	* include/asterisk/http_websocket.h, tests/test_websocket_client.c,
-	  res/res_http_websocket.c: res_http_websocket: read/write string
-	  fixup There was a problem when reading a string from the
-	  websocket. It assumed the received data had a null terminator and
-	  tried to write the data to an ast_str. This of course could/would
-	  read past the end of the given buffer while writing the data to
-	  the internal buffer of ast_str. Modified the the code to
-	  correctly place a null terminator on the result string.
-
-2014-06-16 09:04 +0000 [r416339]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+	  * Fix error checking in QUEUE_MEMBER() write.
 
-	* cel/cel_sqlite3_custom.c, main/db.c, res/res_config_sqlite3.c,
-	  cdr/cdr_sqlite3_custom.c, /: We have faced situation when using
-	  CDR and CEL by sqlite3 modules. With system having high load
-	  (~100 concurrent calls created by sipp) we found many cdr and cel
-	  records missed. There is special finction in sqlite3, that make
-	  able to fix this situation - sqlite3_wait_timeout, that also can
-	  replace awful code cdr_sqlite3 ad cel_sqlite3 modules. Also this
-	  function can be used for aastdb and res_config_sqlite3 to avoid
-	  missed writes to sqlite db. #ASTERISK-23766 #close Reported by:
-	  Igor Goncharovsky Review:
-	  https://reviewboard.asterisk.org/r/3559/ ........ Merged
-	  revisions 416336 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416337 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416338 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-16 02:40 +0000 [r416267-416319]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/chan_sip.c: channels/chan_sip: Forbid remote bridging
-	  if T.38 is negotiated When a framehook is removed - such as the
-	  fax gateway framehook - the bridge framework will re-evaluate the
-	  bridge mixing technologies to see if it can improve the bridging.
-	  When this occurs, get_rtp_info will be called to determine if
-	  local or remote bridging can be used. Using remote bridging will
-	  cause a fax to fail, as direct media negotiation will cause some
-	  small number of packets to not arrive at the remote endpoint.
-	  This patch forces local native bridging if T.38 negotiation is in
-	  progress or has been established. ........ Merged revisions
-	  416318 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/channel_internal_api.c: channel_internal_api: Publish a
-	  snapshot change when linkedids change Snapshots are now not
-	  published *quite* as much as they used to. One instance where
-	  they are not published any longer is during bridge enter and exit
-	  - the state of the channel doesn't change, the bridge does.
-	  However, channels are changed when a linkedid is propagated;
-	  previously, the channel's state would be updated and published
-	  during the bridge enter event. Now this must be explicitly done.
-	  ........ Merged revisions 416300 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, tests/test_stasis_endpoints.c: test_stasis_endpoints: Remove
-	  expected channel snapshot We no longer publish a channel snapshot
-	  when it is associated with an endpoint; after all, the channel
-	  itself hasn't changed - the endpoint state has changed. This
-	  updates the channel_messages unit test accordingly. ........
-	  Merged revisions 416298 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25215 #close
+	  Reported by: Lorne Gaetz
 
-	* /, res/res_musiconhold.c: MoH: Undo commit r416150 (1.8) This
-	  patch reverts r416150. When the comparison between mohclass->name
-	  and state->class->name is made, you are not guaranteed that (a)
-	  state->class is non-NULL or that state or state->class are in a
-	  safe state. Crashes caught by the bridges/transfer_capabilities
-	  test. ........ Merged revisions 416251 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416252 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416255 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-14 19:26 +0000 [r416237]  Corey Farrell <git at cfware.com>
-
-	* res/res_manager_devicestate.c, res/res_manager_presencestate.c:
-	  res_manager_devicestate and res_manager_presencestate missing
-	  support level Add MODULEINFO comment block to define support
-	  level core for these new modules. Review:
-	  https://reviewboard.asterisk.org/r/3620/
-
-2014-06-13 18:24 +0000 [r416216]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_agi.c, res/res_pjsip/pjsip_configuration.c,
-	  main/stasis_channels.c, res/ari/resource_channels.c,
-	  main/bridge_channel.c, main/pbx.c, main/stasis_cache.c, /,
-	  apps/app_meetme.c, main/pickup.c, main/channel_internal_api.c,
-	  include/asterisk/channel.h, main/core_local.c, main/aoc.c,
-	  main/endpoints.c, main/cel.c, apps/app_queue.c,
-	  main/stasis_bridges.c, apps/app_agent_pool.c, main/cli.c,
-	  main/channel.c, main/dial.c, main/manager.c,
-	  include/asterisk/stasis_channels.h: stasis: Reduce creation of
-	  channel snapshots to improve performance During some performance
-	  testing of Asterisk with AGI, ARI, and lots of Local channels, we
-	  noticed that there's quite a hit in performance during channel
-	  creation and releasing to the dialplan (ARI continue). After
-	  investigating the performance spike that occurs during channel
-	  creation, we discovered that we create a lot of channel snapshots
-	  that are technically unnecessary. This includes creating
-	  snapshots during: * AGI execution * Returning objects for ARI
-	  commands * During some Local channel operations * During some
-	  dialling operations * During variable setting * During some
-	  bridging operations And more. This patch does the following: - It
-	  removes a number of fields from channel snapshots. These fields
-	  were rarely used, were expensive to have on the snapshot, and
-	  hurt performance. This included formats, translation paths, Log
-	  Call ID, callgroup, pickup group, and all channel variables. As a
-	  result, AMI Status, "core show channel", "core show channelvar",
-	  and "pjsip show channel" were modified to either hit the live
-	  channel or not show certain pieces of data. While this is
-	  unfortunate, the performance gain from this patch is worth the
-	  loss in behaviour. - It adds a mechanism to publish a cached
-	  snapshot + blob. A large number of publications were changed to
-	  use this, including: - During Dial begin - During Variable
-	  assignment (if no AMI variables are emitted - if AMI variables
-	  are set, we have to make snapshots when a variable is changed) -
-	  During channel pickup - When a channel is put on hold/unhold -
-	  When a DTMF digit is begun/ended - When creating a bridge
-	  snapshot - When an AOC event is raised - During Local channel
-	  optimization/Local bridging - When endpoint snapshots are
-	  generated - All AGI events - All ARI responses that return a
-	  channel - Events in the AgentPool, MeetMe, and some in Queue -
-	  Additionally, some extraneous channel snapshots were being made
-	  that were unnecessary. These were removed. - The result of
-	  ast_hashtab_hash_string is now cached in stasis_cache. This
-	  reduces a large number of calls to ast_hashtab_hash_string, which
-	  reduced the amount of time spent in this function in gprof by
-	  around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan
-	  Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged
-	  revisions 416211 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-13 13:11 +0000 [r416149-416153]  Kinsey Moore <kmoore at digium.com>
+	  Change-Id: I3a016be8dc94d63a9cc155295ff9c9afa5f707cb
 
-	* res/res_musiconhold.c, /: MoH: Don't restart stream on repeated
-	  start calls Currently, music on hold will stop and then start
-	  again from the beginning if ast_moh_start() is called multiple
-	  times. This can happen if a call is put on hold repeatedly (the
-	  channel receives multiple HOLD control frames) and can be
-	  triggered from ARI by starting MoH on a channel multiple times.
-	  This is fairly jarring/annoying to users. This change prevents
-	  MoH from being restarted if the requested music class is the same
-	  as the one currently playing. Review:
-	  https://reviewboard.asterisk.org/r/3615/ ........ Merged
-	  revisions 416150 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416151 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416152 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-08-12 12:59 +0000 [430db4333e]  Kevin Harwell <kharwell at digium.com>
 
-	* main/cel.c, /: CEL: Expose parking retreiver in extra field This
-	  exposes the retreiver of a parked call under the "retreiver" key
-	  of the extra field when this information is available. Review:
-	  https://reviewboard.asterisk.org/r/3608/ ........ Merged
-	  revisions 416148 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* chan_sip.c: wrong peer searched in sip_report_security_event
 
-2014-06-13 05:16 +0000 [r416071]  Richard Mudgett <rmudgett at digium.com>
+	  In chan_sip, after handling an incoming invite a security event is raised
+	  describing authorization (success, failure, etc...). However, it was doing
+	  a lookup of the peer by extension. This is fine for register messages, but
+	  in the case of an invite it may search and find the wrong peer, or a non
+	  existent one (for instance, in the case of call pickup). Also, if the peers
+	  are configured through realtime this may cause an unnecessary database lookup
+	  when caching is enabled.
 
-	* main/http.c, include/asterisk/tcptls.h, main/tcptls.c,
-	  main/manager.c, /, channels/chan_sip.c: AST-2014-007: Fix of fix
-	  to allow AMI and SIP TCP to send messages. ASTERISK-23673 #close
-	  Reported by: Richard Mudgett Review:
-	  https://reviewboard.asterisk.org/r/3617/ ........ Merged
-	  revisions 416066 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 416067 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 416070 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This patch makes it so that sip_report_security_event searches by IP address
+	  when looking for a peer instead of by extension after an invite is processed.
 
-2014-06-12 21:27 +0000 [r416024]  Rusty Newton <rnewton at digium.com>
+	  ASTERISK-25320 #close
 
-	* main/pbx.c: main/pbx - documentation - enhance 'core show hints'
-	  and 'core show hint' help text Adds descriptive help text to
-	  'core show hints' and 'core show hint'. The text describes the
-	  various columns for the sake of clarity. It takes into account
-	  recent changes to the content displayed by the commands
-	  https://reviewboard.asterisk.org/r/3604/ and
-	  https://reviewboard.asterisk.org/r/3611/. ASTERISK-23764 Review:
-	  https://reviewboard.asterisk.org/r/3610/
+	  Change-Id: I9b3f11549efb475b6561c64f0e6da1a481d98bc4
+2015-08-10 13:43 +0000 [c777c9565d]  Richard Mudgett <rmudgett at digium.com>
 
-2014-06-12 20:17 +0000 [r415982]  Kinsey Moore <kmoore at digium.com>
+	* chan_dahdi.c: Flush the DAHDI write buffer after starting DTMF.
 
-	* res/res_pjsip_pubsub.c, /: Fix build in devmode for GCC 4.10
-	  ........ Merged revisions 415980 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Pressing DTMF digits on a phone to go out on a DAHDI channel can result in
+	  the digit not being recognized or even heard by the peer.
 
-2014-06-12 17:00 +0000 [r415907]  Richard Mudgett <rmudgett at digium.com>
+	  Phone -> Asterisk -> DAHDI/channel
 
-	* include/asterisk/utils.h, main/tcptls.c, main/manager.c, /,
-	  channels/chan_sip.c, main/http.c, UPGRADE.txt, main/utils.c,
-	  include/asterisk/tcptls.h, res/res_http_websocket.c,
-	  configs/http.conf.sample: AST-2014-007: Fix DOS by consuming the
-	  number of allowed HTTP connections. Simply establishing a TCP
-	  connection and never sending anything to the configured HTTP port
-	  in http.conf will tie up a HTTP connection. Since there is a
-	  maximum number of open HTTP sessions allowed at a time you can
-	  block legitimate connections. A similar problem exists if a HTTP
-	  request is started but never finished. * Added http.conf
-	  session_inactivity timer option to close HTTP connections that
-	  aren't doing anything. Defaults to 30000 ms. * Removed the
-	  undocumented manager.conf block-sockets option. It interferes
-	  with TCP/TLS inactivity timeouts. * AMI and SIP TLS connections
-	  now have better authentication timeout protection. Though I
-	  didn't remove the bizzare TLS timeout polling code from chan_sip.
-	  * chan_sip can now handle SSL certificate renegotiations in the
-	  middle of a session. It couldn't do that before because the
-	  socket was non-blocking and the SSL calls were not restarted as
-	  documented by the OpenSSL documentation. * Fixed an off nominal
-	  leak of the ssl struct in handle_tcptls_connection() if the FILE
-	  stream failed to open and the SSL certificate negotiations
-	  failed. The patch creates a custom FILE stream handler to give
-	  the created FILE streams inactivity timeout and timeout after a
-	  specific moment in time capability. This approach eliminates the
-	  need for code using the FILE stream to be redesigned to deal with
-	  the timeouts. This patch indirectly fixes most of ASTERISK-18345
-	  by fixing the usage of the SSL_read/SSL_write operations.
-	  ASTERISK-23673 #close Reported by: Richard Mudgett ........
-	  Merged revisions 415841 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415854 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415896 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Turns out the DAHDI behavior with DTMF generation (and any other generated
+	  tones) is exposed by the "buffers=" setting in chan_dahdi.conf.  When
+	  Asterisk requests to start sending DTMF then DAHDI waits until its write
+	  buffer is empty before generating any samples for the DTMF tones.  When
+	  Asterisk subsequently requests DAHDI to stop sending DTMF then DAHDI
+	  immediately stops generating the DTMF samples.  As a result, the more
+	  samples there are in the DAHDI write buffer the shorter the time DTMF
+	  actually gets sent on the wire.  If there are more samples in the write
+	  buffer than the time DTMF is supposed to be sent then no DTMF gets sent on
+	  the wire.  With the "buffers=12,half" setting and each buffer representing
+	  20 ms of samples then the DAHDI write buffer is going to contain around
+	  120 ms of samples.  For DTMF to be recognized by the peer the actual sent
+	  DTMF duration needs to be a minimum of 40 ms.  Therefore, the intended
+	  duration needs to be a minimum of 160 ms for the peer to receive the
+	  minimum DTMF digit duration to recognize it.
 
-2014-06-12 15:50 +0000 [r415839]  Scott Griepentrog <sgriepentrog at digium.com>
+	  A simple and effective solution to work around the DAHDI behavior is for
+	  Asterisk to flush the DAHDI write buffer when sending DTMF so the full
+	  duration of DTMF is actually sent on the wire.  When someone is going to
+	  send DTMF they are not likely to be talking before sending the tones so
+	  the flushed write samples are expected to just contain silence.
 
-	* /, apps/app_queue.c: app_queue: delayed state can cause early
-	  leavewhenempty ringing In app_queue, device state changes arrive
-	  in event messages and update the queue member status value. That
-	  value is checked in get_member_status() to decide that the caller
-	  should leave when there are no available members. Although event
-	  messages can be delayed by other activity, there is no adverse
-	  affect by lagged status except in one specific case: there is
-	  only one available member, it was just rung, and leavewhenempty
-	  is enabled set for ringing members. This change adds a direct
-	  check of the device state only under this condition where the
-	  caller may be dropped incorrectly, resolving this issue without
-	  affecting performance of app_queue normally. AST-1248 #close
-	  Review: https://reviewboard.asterisk.org/r/3595/ Reported by:
-	  Thomas Arimont ........ Merged revisions 415833 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415835 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415836 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  * Made dahdi_digit_begin() flush the DAHDI write buffer after requesting
+	  to send a DTMF digit.
 
-2014-06-12 15:39 +0000 [r415834]  Jonathan Rose <jrose at digium.com>
+	  ASTERISK-25315 #close
+	  Reported by John Hardin
 
-	* apps/app_mixmonitor.c, /, UPGRADE.txt: MixMontior: Add class
-	  authorization requirements to MixMonitor AMI commands MixMonitor
-	  AMI commands StartMixMonitor and StopMixMonitor lacked class
-	  authorization. StopMixMonitor now requires that the manager user
-	  either have the call or system class authorization.
-	  StartMixMonitor is a slightly larger issue since it can execute
-	  shell commands if the right arguments are passed into it, and we
-	  consider this a permission escalation. A security release will be
-	  issued for problem this shortly. ASTERISK-23609 #close Reported
-	  by: Corey Farrell ........ Merged revisions 415825 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415832 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-12 14:39 +0000 [r415813]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_pubsub.c, /: res_pjsip_pubsub: unauthenticated
-	  remote crash in PJSIP pub/sub framework A remotely exploitable
-	  crash vulnerability exists in the PJSIP channel driver's pub/sub
-	  framework. If an attempt is made to unsubscribe when not
-	  currently subscribed and the endpoint's "sub_min_expiry" is set
-	  to zero, Asterisk tries to create an expiration timer with zero
-	  seconds, which is not allowed, so an assertion raised. The fix
-	  was to reject a subscription that is attempting to unsubscribe
-	  when not being already subscribed. Asterisk now checks for this
-	  situation appropriately and responds with a 400 instead of
-	  crashing. AST-2014-005 ASTERISK-23489 #close ........ Merged
-	  revisions 415812 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-12 14:15 +0000 [r415795]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip.c, /: Fix potential deadlock situation in
-	  res_pjsip. SIP transaction timeouts are handled in the PJSIP
-	  monitor thread. When this happens on a subscription, and the
-	  subscription is destroyed, the subscription destruction is
-	  dispatched synchronously to the threadpool. The issue is that the
-	  PJSIP dialog is locked by the monitor thread, and then the
-	  dispatched task attempts to lock the dialog. This leads to a
-	  deadlock that causes SIP traffic to no longer be accepted on the
-	  Asterisk server. The fix here is to treat the monitor thread as
-	  if it were a threadpool thread when it attempts to dispatch
-	  synchronous tasks. This way, the dispatched task turns into a
-	  simple function call within the same thread, and the locking
-	  issue is averted. AST-2014-008 ASTERISK-23802 #close ........
-	  Merged revisions 415794 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-12 11:34 +0000 [r415767]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip.c, res/res_pjsip_pubsub.c,
-	  res/res_pjsip_exten_state.c, include/asterisk/res_pjsip.h,
-	  include/asterisk/res_pjsip_pubsub.h,
-	  res/res_pjsip_pubsub.exports.in, /,
-	  contrib/ast-db-manage/config/versions/c6d929b23a8_create_pjsip_subscription_persistence_.py
-	  (added), res/res_pjsip_mwi.c: res_pjsip_pubsub: Persist
-	  subscriptions in sorcery so they are recreated on startup. This
-	  change makes res_pjsip_pubsub persist inbound subscriptions in
-	  sorcery. By default this uses the local astdb but it can also be
-	  configured to store within an outside database. When Asterisk is
-	  started these subscriptions are recreated if they have not
-	  expired. Notifications are sent to the devices which have
-	  subscribed and they are none the wiser that the system has
-	  restarted. Review: https://reviewboard.asterisk.org/r/3598/
-	  ........ Merged revisions 415766 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-12 07:52 +0000 [r415749]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* UPGRADE.txt, contrib/scripts/safe_asterisk, Makefile, /:
-	  safe_asterisk: Overwrite old safe_asterisk on make install. From
-	  now on, make install will overwrite safe_asterisk with the latest
-	  version. You need to move any local modifications to files inside
-	  /etc/asterisk/startup.d, if you have any. See also commits
-	  r394939 and r397938. ASTERISK-21965 #close Patches:
-	  safe_asterisk.patch uploaded by jkister (License 6232, modified
-	  by me) ........ Merged revisions 415748 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-11 23:01 +0000 [r415730]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/format.c, /: format.c: Fix misuse of hash container
-	  function. The supplied hash function to a container must be
-	  idempotent given the object's key value to figure out which
-	  container bucket the object belongs in. Returning a random number
-	  or the current container count is not idempotent. The "computed
-	  hash" value doesn't help find the object later in those cases. *
-	  Fixed the format_list container to actually be a list since that
-	  is how the container is used. Conceptually, if more than 283
-	  formats were added to the format_list then odd things may have
-	  happened before the fix. ........ Merged revisions 415728 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415729 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-11 20:22 +0000 [r415698-415715]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/pbx.c: CLI: correct presence information on core show hints
-	  Adds presence to core show hint and changes presence string
-	  conversion to use the correct function. ASTERISK-23858 #close
-	  Review: https://reviewboard.asterisk.org/r/3611/
-
-	* main/pbx.c: CLI: add presence information to core show hints Adds
-	  presence state value to output of core show hints. Also reformats
-	  the output slightly so it doesn't use as much space as it would
-	  otherwise. Was: 1000 at demo : SIP/1000 State:Unavailable Watchers 0
-	  Now: 1000 at demo : SIP/1000 State:Unavailable Presence:Idle
-	  Watchers 0 AFS-53 #close Review:
-	  https://reviewboard.asterisk.org/r/3604/
-
-2014-06-10 18:32 +0000 [r415679]  Kinsey Moore <kmoore at digium.com>
-
-	* main/channel.c, /: Fix build in dev mode due to signed/unsigned
-	  mismatch ........ Merged revisions 415678 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-10 16:06 +0000 [r415659]  Jonathan Rose <jrose at digium.com>
-
-	* main/message.c, /, res/res_pjsip_notify.c: PJSIP: PJSIPNotify -
-	  Strip content-length headers and add documentation Documentation
-	  for how to add custom headers/content to notifies created with
-	  the PJSIPNotify manager action was a little sparse and it also
-	  wasn't vetting application of Content-length headers like its
-	  chan_sip equivalent was (so two Content-length headers could be
-	  applied... and PJSIP determines the content length anyway, so it
-	  just opens people up for error). This patch also flips the
-	  variable order so that the variables are interpreted in the same
-	  order as they are put in the AMI action. Review:
-	  https://reviewboard.asterisk.org/r/3587/ ........ Merged
-	  revisions 415658 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-10 09:28 +0000 [r415630]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/chan_ooh323.c, /: chan_ooh323: fix loading module failure
-	  if there no accessible h323_log or ooh323 config file change
-	  return 1 to return AST_MODULE_LOAD_FAILURE on module load routine
-	  few cosmetic changes ASTERISK-23814 #close (closes issue
-	  ASTERISK-23814) Reported by: Igor Goncharovsky Patches:
-	  ASTERISK-23814-ast11.patch ........ Merged revisions 415599 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415602 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-09 20:21 +0000 [r415580]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_header_funcs.c, /: chan_pjsip: Fix bug where custom
-	  SIP headers could be duplicated on outgoing INVITEs. When using
-	  PJSIP_HEADER() to add custom headers to outgoing INVITE requests,
-	  certain situations could result in the headers being duplicated.
-	  For instance, if the request were retransmitted, or if the INVITE
-	  were re-sent with authentication credentials, the custom headers
-	  would be re-added to the request. The fix here is to, after
-	  adding the custom headers to the outbound INVITE, remove the
-	  datastore that holds the custom headers to add. This way, there
-	  is no risk in accidentally adding them if the session supplement
-	  is called into a second or third time. ........ Merged revisions
-	  415579 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-09 12:12 +0000 [r415524]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /, UPGRADE.txt, contrib/scripts/safe_asterisk: safe_asterisk:
-	  Cleanup additions to r415132. * Replaced a stray echo that
-	  should've been a message call in safe_asterisk. This replaces a
-	  conditional log message by a slightly different message. Please
-	  update your log parsing scripts. * Made the $NOTIFY mail Subject
-	  more verbose by adding the machine name and exitstatus. (Note
-	  that a 'make install' still won't overwrite your old
-	  safe_asterisk if it exists. See ASTERISK-21965.) ASTERISK-23492
-	  #close ........ Merged revisions 415521 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415522 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415523 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Ib56262c708cb7858082156bfc70ebd0a220efa6a
 
-2014-06-09 03:50 +0000 [r415466]  Corey Farrell <git at cfware.com>
+2015-08-05 14:21 +0000 [f43ea74e9e]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, main/autoservice.c: autoservice: stop thread on graceful
-	  shutdown This change adds thread shutdown to autoservice for
-	  graceful shutdowns only. ast_register_cleanup is backported to
-	  1.8 to allow this. The logger callid is also released on shutdown
-	  in 11+. ASTERISK-23827 #close Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3594/ ........ Merged
-	  revisions 415463 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415464 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415465 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-08 18:12 +0000 [r415444]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  main/bridge_channel.c, main/channel.c, main/pbx.c, /,
-	  main/framehook.c, main/bridge_after.c: bridges/bridge_native_rtp:
-	  Reconfigure bridge on removal of framehook This patch is a re-do
-	  of r414122. When r414122 was merged, a major problem with it was
-	  uncovered. UNBRIDGE soft hangup flags have a catastrophic effect
-	  on the pbx core if they leak out from the bridge layer: the
-	  channel gets hung up. With the number of threads involved in a
-	  blind transfer, and with the initial patch, it was likely that
-	  this would occur. This caused a large number of test failures
-	  This patch is nearly identical with the one proposed in r414122,
-	  save for the following changes: - We explicitly clear the
-	  UNBRIDGE flag when setting an after goto on a channel in a bridge
-	  - Defensively, if we encounter an UNBRIDGE flag in the pbx core,
-	  we handle it https://reviewboard.asterisk.org/r/3585/ ........
-	  Merged revisions 415443 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-07 00:42 +0000 [r415428]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/bridge.h, /: bridge.h: Remove redundant struct
-	  ast_bridge_channel forward declaration. ........ Merged revisions
-	  415427 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-06 21:44 +0000 [r415411]  Jonathan Rose <jrose at digium.com>
+	* chan_dahdi.c: Lock private struct for ast_write().
 
-	* include/asterisk/manager.h, main/config.c, main/manager.c, /,
-	  channels/chan_sip.c, include/asterisk/config.h: chan_sip: Fix
-	  order of variables specified in SIPNotify action Prior to this
-	  patch, sequential variables would be ordered in reverse from the
-	  order specified in the manager action. Review:
-	  https://reviewboard.asterisk.org/r/3588/ ........ Merged
-	  revisions 415359 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415390 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415410 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-06 20:45 +0000 [r415358]  Kevin Harwell <kharwell at digium.com>
-
-	* main/uri.c, tests/test_websocket_client.c: core uri: Custom uri
-	  parsing error when no query parameters If using the custom URI
-	  parsing code (not external uriparser lib) and there was no query
-	  parameters the resulting pointer would be NULL and then an
-	  attempt was made to subtract from it. The pointer is now set to a
-	  valid value if there is no query parameter(s). Also, in the
-	  'ast_uri_make_host_with_port' function when setting the
-	  terminator on the resulting string it was writing it one past the
-	  end of allocated memory. It now writes the string terminator
-	  appropriately.
-
-2014-06-06 19:13 +0000 [r415343]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip_sdp_rtp.c: PJSIP: Remove premature write of raw
-	  formats Currently, there are situations that can occur when using
-	  chan_pjsip and certain dialplan applications (notably ChanSpy())
-	  that can cause the channel to get no audio with scrolling
-	  warnings about format mismatches. This is caused by a failure to
-	  update translation paths on a mid-call native format update since
-	  the raw formats have already been updated by res_pjsip_sdp_rtp.c
-	  in set_caps(). Removing the premature raw format updates allows
-	  the translation paths to be setup correctly and the raw read and
-	  write formats with them. AFS-63 #close ........ Merged revisions
-	  415342 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-06 14:12 +0000 [r415319]  George Joseph <george.joseph at fairview5.com>
-
-	* tests/test_astobj2.c, main/astobj2_private.h (added),
-	  main/astobj2.c, main/astobj2_container_private.h (added),
-	  main/astobj2_container.c (added), main/astobj2_hash.c (added),
-	  main/astobj2_rbtree.c (added), /, include/asterisk/astobj2.h:
-	  Split astobj2.c into more maintainable components. Split
-	  astobj2.c into the following files to improve maintainability.
-	  astobj2.c - object primitives, object primitive misc and
-	  initialization code. astobj2_private.h - internal object
-	  declarations needed by the containers. astobj2_container.c -
-	  generic conainer and container misc code.
-	  astobj2_container_hash.c - hash container specific code.
-	  astobj2_container_rbtree.c - rbtree container specific code.
-	  astobj2_container_private.h - generic container definitions and
-	  rtti prototypes. https://reviewboard.asterisk.org/r/3576/
-	  ........ Merged revisions 415317 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-06 12:49 +0000 [r415302]  Rusty Newton <rnewton at digium.com>
-
-	* /, configs/cli_aliases.conf.sample: configs/cli_aliases.conf: Two
-	  new aliases, plus enhancements for context names. Changed naming
-	  of included alias templates to avoid confusion between version
-	  names. For example, asterisk12 was for asterisk 1.2, so I changed
-	  it to asterisk_1dot2, so that later we can use asterisk_12 for
-	  Asterisk 12. Added alias for "features reload" to the template
-	  for Asterisk 11 style syntax template, as features reload was
-	  removed in 12, but you can still do "module reload features"
-	  Added alias for "pjsip reload" to the friendly template. It is
-	  shorter than "module reload res_pjsip.so" and if some are like
-	  me; I constantly forget that reloading chan_pjsip doesn't parse
-	  config. Remembering "pjsip reload" is just easier. ASTERISK-23654
-	  #close ASTERISK-23654 #comment Fixed by adding two new aliases
-	  and enhancements for context names. Review:
-	  https://reviewboard.asterisk.org/r/3572/ ........ Merged
-	  revisions 415301 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-05 19:04 +0000 [r415231-415288]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/config.c: config: Fix indentation and missing curlies in
-	  config_text_file_load().
+	  There is a window of opportunity for DTMF to not go out if an audio frame
+	  is in the process of being written to DAHDI while another thread starts
+	  sending DTMF.  The thread sending the audio frame could be past the
+	  currently dialing check before being preempted by another thread starting
+	  a DTMF generation request.  When the thread sending the audio frame
+	  resumes it will then cause DAHDI to stop the DTMF tone generation.  The
+	  result is no DTMF goes out.
 
-	* main/config.c, /: config: Fix config files not reloading when
-	  only an included file changes. The twisted logic determining if a
-	  config file should be reloaded was mostly broken and disabled.
-	  The incorrect test that ASTERISK-23383 fixed actually reenabled
-	  the broken logic. The incorrect test was causing the timestamp to
-	  always be cleared which caused config files with includes to
-	  always be reloaded. * Made wildcard includes always cause a
-	  reload. Determining if a file was deleted cannot be determined
-	  without restructuring the cache to determine if any files are
-	  missing from the last files actually loaded. Also without
-	  refactoring config_text_file_load(), the glob loop couldn't check
-	  more than one file for changes anyway. * Made remove the cache
-	  entry if the file no longer exists when trying to get its
-	  timestamp or it is no longer a regular file. This fixes the
-	  corner case where the file was loaded, then deleted, then the
-	  config reloaded, then the file restored with the same timestamp,
-	  and then the config reloaded again. * Made remove the cache entry
-	  include list when actually loading the file. This gets rid of any
-	  stale includes the file had from the last time the file was
-	  loaded. ASTERISK-23683 #close Reported by: tootai Review:
-	  https://reviewboard.asterisk.org/r/3575/ ........ Merged
-	  revisions 415225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415229 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415230 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-05 17:22 +0000 [r415223]  Kevin Harwell <kharwell at digium.com>
-
-	* tests/test_uri.c (added), include/asterisk/http_websocket.h,
-	  main/http.c, main/uri.c (added), tests/test_websocket_client.c
-	  (added), res/res_http_websocket.c, include/asterisk/http.h,
-	  include/asterisk/uri.h (added),
-	  res/res_http_websocket.exports.in: res_http_websocket: Create a
-	  websocket client Added a websocket server client in Asterisk.
-	  Asterisk has a websocket server, but not a client. The ability to
-	  have Asterisk be able to connect to a websocket server can
-	  potentially be useful for future work (for instance this could
-	  allow ARI to connect back to some external system, although more
-	  work would be needed in order to incorporate that). Also a couple
-	  of things to note - proxy connection support has not been
-	  implemented and there is limited http response code handling
-	  (basically, it is connect or not). Also added an initial new URI
-	  handling mechanism to core. Internet type URI's are parsed into a
-	  data structure that contains pointers to the various parts of the
-	  URI. (closes issue ASTERISK-23742) Reported by: Kevin Harwell
-	  Review: https://reviewboard.asterisk.org/r/3541/
-
-2014-06-05 14:49 +0000 [r415208]  Matthew Jordan <mjordan at digium.com>
-
-	* /, apps/app_confbridge.c: app_confbridge: Allow muting of users
-	  waiting to enter a ConfBridge Prior to this patch, users waiting
-	  to enter a ConfBridge were not considered when muted via the CLI
-	  or via AMI. Instead, a confusing message would be emitted stating
-	  that the channel did not exist. This patch allows a user to be
-	  muted when waiting to enter a ConfBridge conference. This is
-	  equivalent to start when muted, only toggled via the CLI or AMI.
-	  Review: https://reviewboard.asterisk.org/r/3582 #ASTERISK-23824
-	  #close patches: rb3582.patch uploaded by tm1000 (License 6524)
-	  ........ Merged revisions 415206 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415207 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  * Made dahdi_write() lock the private struct before writing to the DAHDI
+	  file descriptor.
 
-2014-06-05 11:59 +0000 [r415192]  Kinsey Moore <kmoore at digium.com>
+	  ASTERISK-25315
+	  Reported by John Hardin
 
-	* /, channels/chan_pjsip.c: PJSIP: Send initial connected line
-	  information This makes chan_pjsip send connected line information
-	  when it is called so that connected line information is available
-	  on the connected channel. (closes issue DPMA-442) Reported by:
-	  John Bigelow Review: https://reviewboard.asterisk.org/r/3584/
-	  ........ Merged revisions 415191 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Ib4e0264cf63305ed5da701188447668e72ec9abb
 
-2014-06-04 20:16 +0000 [r415173]  Walter Doekes <walter+asterisk at wjd.nu>
+2015-08-11 05:24 +0000 [b9bd3c1435]  Joshua Colp <jcolp at digium.com>
 
-	* /, contrib/scripts/safe_asterisk: safe_asterisk: Cleanup and
-	  debian compatibility. Cleans up the safe_asterisk script and adds
-	  the ASTSAFE_FOREGROUND option that allows the debian asterisk
-	  init script to capture the right pid. * Drop the vim #modeline
-	  which wasn't used. Use test consistently without the odd
-	  configure xno syntax. Double quote all paths. General cleanup. *
-	  Don't output message()s to the console but only to TTY if set. *
-	  Allow TTY to be "no" as well as empty (debian compatibility with
-	  debian/patches/safe_asterisk-config). * Add option to export
-	  ASTSAFE_FOREGROUND=1 from the init script that calls this to
-	  disable backgrounding. Debian uses a similar method in
-	  debian/patches/safe_asterisk-nobg). ASTERISK-23492 #close Review:
-	  https://reviewboard.asterisk.org/r/3574/ ........ Merged
-	  revisions 415132 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415171 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415172 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res_http_websocket: Forcefully terminate on write errors.
 
-2014-06-04 14:13 +0000 [r415116-415118]  Matthew Jordan <mjordan at digium.com>
+	  The res_http_websocket module will currently attempt to close
+	  the WebSocket connection if fatal cases occur, such as when
+	  attempting to write out data and being unable to. When the
+	  fatal cases occur the code attempts to write a WebSocket close
+	  frame out to have the remote side close the connection. If
+	  writing this fails then the connection is not terminated.
 
-	* /, channels/chan_pjsip.c: chan_pjsip: Add debug in RTP Engine
-	  glue callback This patch adds some debug statements that aid with
-	  determining why a direct media request may or may not be
-	  initiated. ........ Merged revisions 415117 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This change forcefully terminates the connection if the
+	  WebSocket is to be closed but is unable to send the close frame.
 
-	* res/res_pjsip_session.c, /: res_pjsip_session: Add debug
-	  statement for session refreshes This small patch adds a debug
-	  level 3 statement indicating how a session refresh is being sent
-	  - either as a re-INVITE or as an UPDATE - and where the session
-	  refresh is going. ........ Merged revisions 415115 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25312 #close
 
-2014-06-04 07:27 +0000 [r415080]  Corey Farrell <git at cfware.com>
+	  Change-Id: I10973086671cc192a76424060d9ec8e688602845
 
-	* /, apps/confbridge/include/confbridge.h, apps/app_confbridge.c:
-	  app_confbridge: Correct verification of conference name length
-	  Conference names were not checked for maximum length, allowing
-	  unexpected behaviour. This change adds checking to ensure the
-	  maximum length is not exceeded. The maximum length is also
-	  changed from 32 to AST_MAX_EXTENSION. ASTERISK-23035 #close
-	  Reported by: Iñaki Cívico Tested by: Iñaki Cívico Patches:
-	  confbridge-enforce_max-1.8.patch uploaded by coreyfarrell
-	  (license 5909) confbridge-enforce_max-11up.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 415060 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 415066 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 415078 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-08-07 22:11 +0000 [06b464ab1b]  David M. Lee <dlee at respoke.io>
 
-2014-06-03 07:36 +0000 [r415000]  Walter Doekes <walter+asterisk at wjd.nu>
+	* Replace htobe64 with htonll
 
-	* /, funcs/func_odbc.c: func_odbc: Fix fixed size buffers fix
-	  (r414968). The change that removed the fixed size buffers in
-	  odbc-related code -- removing arbitrary column width limits --
-	  was incomplete. This change adds: no segfault on writesql without
-	  insertsql and return value checks after strdup. While I was in
-	  the vicinity I cleaned up the linefeeds in the odbc function
-	  descriptions, moved some code for clarity, removed some blobs and
-	  noted (but didn't fix) that the 'odbc write ... exec' CLI command
-	  doesn't behave as the dialplan equivalent when insertsql= is
-	  used. ASTERISK-23582 #close Review:
-	  https://reviewboard.asterisk.org/r/3579/ ........ Merged
-	  revisions 414997 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414998 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414999 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-06-01 15:32 +0000 [r414976]  Joshua Colp <jcolp at digium.com>
-
-	* /, bridges/bridge_native_rtp.c: bridge_native_rtp: Take the
-	  bridge type choice of both channels into account. The
-	  bridge_native_rtp module currently uses the bridge result of the
-	  first channel that joins a bridge as the ultimate result. This
-	  means that if the first channel has direct media enabled but the
-	  second does not a direct media bridge will still occur. This
-	  change makes it so that both sides are taken into account. If
-	  either side forbids the bridge or responds with a local bridge
-	  result then either a generic or local bridge occurs.
-	  ASTERISK-23541 #close Reported by: Justin E Review:
-	  https://reviewboard.asterisk.org/r/3577/ ........ Merged
-	  revisions 414975 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-30 14:53 +0000 [r414949]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip_refer.c, /: PJSIP: Prevent crash on blind transfer
-	  Blind transfers don't go too well with NULL channels which can
-	  occur if the channel has already been transferred away. (closes
-	  issue ASTERISK-23718) Reported by: Jonathan Rose ........ Merged
-	  revisions 414948 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-30 12:42 +0000 [r414883-414935]  Matthew Jordan <mjordan at digium.com>
-
-	* main/audiohook.c, CHANGES, res/ari/ari_model_validators.c,
-	  res/ari/ari_model_validators.h, funcs/func_talkdetect.c (added),
-	  include/asterisk/stasis_channels.h,
-	  rest-api/api-docs/events.json, /, main/stasis_channels.c:
-	  TALK_DETECT: A channel function that raises events when talking
-	  is detected This patch adds a new channel function TALK_DETECT
-	  that, when set on a channel, causes events indicating the
-	  start/stop of talking on a channel to be emitted to both AMI and
-	  ARI clients. The function allows setting both the silence
-	  threshold (the length of silence after which we decide no one is
-	  talking) as well as the talking threshold (the amount of energy
-	  that counts as talking). Parameters can be updated on a channel
-	  after talk detection has been enabled, and talk detection can be
-	  removed at any time. The events raised by the function use a
-	  nomenclature similar to existing AMI/ARI events. For AMI:
-	  ChannelTalkingStart/ChannelTalkingStop For ARI:
-	  ChannelTalkingStarted/ChannelTalkingFinished Review:
-	  https://reviewboard.asterisk.org/r/3563/ #ASTERISK-23786 #close
-	  Reported by: Matt Jordan ........ Merged revisions 414934 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  We don't have a compatability function to fill in a missing htobe64; but
+	  we already have one for the identical htonll.
 
-	* main/config.c, /: main/config.c: AMI action UpdateConfig EmptyCat
-	  clears all categories When invoking UpdateConfig AMI action with
-	  Action set to EmptyCat, Asterisk will make all categories empty
-	  in the config but the one requested with a Cat variable. This is
-	  due to a bug in ast_category_empty (main/config.c) that makes an
-	  incorrect comparison for a category name. This patch corrects the
-	  comparison such that only the requested category is cleared.
-	  Review: https://reviewboard.asterisk.org/r/3573/ #ASTERISK-23803
-	  #close Reported by: zvision patches: manager.c.diff uploaded by
-	  zvision (License 5755) ........ Merged revisions 414880 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414881 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414882 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Ic0a95db1c5b0041e14e6b127432fb533b97e4cac
 
-2014-05-29 18:51 +0000 [r414861]  Kinsey Moore <kmoore at digium.com>
+2015-08-05 05:23 +0000 [c7a1dca4ba]  Joshua Colp <jcolp at digium.com>
 
-	* main/pbx.c, /: PBX: Prevent incorrect hint parsing Dynamic and
-	  pattern matching hints should not be checked for their last known
-	  state until they are instantiated by subscribers. (closes issue
-	  AFS-56) Reported by: John Hardin Patch AFS-56-pbx.diff submitted
-	  by Matt Jordan (license 6283) ........ Merged revisions 414813
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 414859 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414860 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-28 22:54 +0000 [r414798]  Matthew Jordan <mjordan at digium.com>
-
-	* main/loader.c, include/asterisk/logger.h, res/res_config_curl.c,
-	  cel/cel_odbc.c, res/res_config_odbc.c,
-	  bridges/bridge_builtin_features.c, main/optional_api.c,
-	  main/logger.c, main/config_options.c, cdr/cdr_odbc.c,
-	  apps/app_mixmonitor.c, main/asterisk.c, res/res_odbc.c,
-	  main/xmldoc.c, apps/app_voicemail.c, cel/cel_pgsql.c,
-	  channels/chan_unistim.c, res/res_config_pgsql.c, main/pbx.c,
-	  cdr/cdr_sqlite3_custom.c, res/res_fax.c, main/bridge.c,
-	  apps/app_waitforsilence.c, cdr/cdr_adaptive_odbc.c,
-	  res/parking/parking_applications.c, cdr/cdr_pgsql.c,
-	  res/res_jabber.c: Logger/CLI/etc.: Fix some aesthetic issues;
-	  reduce chatty verbose messages This patch addresses some
-	  aesthetic issues in Asterisk. These are all just minor tweaks to
-	  improve the look of the CLI when used in a variety of settings.
-	  Specifically: * A number of chatty verbose messages were removed
-	  or demoted to DEBUG messages. Verbose messages with a verbosity
-	  level of 5 or higher were - if kept as verbose messages - demoted
-	  to level 4. Several messages that were emitted at verbose level 3
-	  were demoted to 4, as announcement of dialplan applications being
-	  executed occur at level 3 (and so the effects of those
-	  applications should generally be less). * Some verbose messages
-	  that only appear when their respective 'debug' options are
-	  enabled were bumped up to always be displayed. *
-	  Prefix/timestamping of verbose messages were moved to the
-	  verboser handlers. This was done to prevent duplication of
-	  prefixes when the timestamp option (-T) is used with the CLI. *
-	  Verbose magic is removed from messages before being emitted to
-	  non-verboser handlers. This prevents the magic in multi-line
-	  verbose messages (such as SIP debug traces or the output of
-	  DumpChan) from being written to files. * _Slightly_ better
-	  support for the "light background" option (-W) was added. This
-	  includes using ast_term_quit in the output of XML documentation
-	  help, as well as changing the "Asterisk Ready" prompt to bright
-	  green on the default background (which stands a better chance of
-	  being displayed properly than bright white). Review:
-	  https://reviewboard.asterisk.org/r/3547/
-
-2014-05-28 20:53 +0000 [r414781]  Rusty Newton <rnewton at digium.com>
-
-	* /, configs/pjsip.conf.sample: pjsip.conf: privkey_file should be
-	  priv_key_file, mediaencryption=yes should be mediaencryption=sdes
-	  privkey_file was missed in the snake case update. An example
-	  included an invalid value for the mediaencryption option.
-	  ........ Merged revisions 414780 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-28 17:46 +0000 [r414764-414766]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json,
-	  rest-api/api-docs/mailboxes.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json,
-	  rest-api/api-docs/playbacks.json,
-	  rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/resources.json, include/asterisk/manager.h,
-	  rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json: AMI/ARI: Update version
-	  numbers Update the semantic versioning of ARI to 1.3.0 and AMI to
-	  2.3.0 to account for backwards compatible changes going from
-	  12.2.0 to 12.3.0. ........ Merged revisions 414765 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* contrib/ast-db-manage/cdr/env.py, /: ast-db-manage/cdr/env.py:
-	  Don't fail if a config file can't be loaded When generating SQL
-	  files via the repotools alembic_creator.py script, a
-	  configuration object is used programatically with SQLAlechemy, as
-	  opposed to a configuration file. This patch ignores failures to
-	  interpret a config file, as ... there isn't one in this case.
-	  ........ Merged revisions 414763 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-28 16:56 +0000 [r414748-414750]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_pjsip_session.c, include/asterisk/res_pjsip_session.h, /,
-	  res/res_pjsip_t38.c: res_pjsip_session: Fix leaked video RTP
-	  ports. Simply enabling PJSIP to negotiage a video codec (e.g.,
-	  h264) would leak video RTP ports if the codec were not negotiated
-	  by an incoming call. * Made add_sdp_streams() associate the
-	  handler with the media stream if the handler handled the media
-	  stream. Otherwise, when the ast_sip_session_media object was
-	  destroyed it didn't know how to clean up the RTP resources. *
-	  Fixed sdp_requires_deferral() associating the handler with the
-	  media stream when deciding if the SDP processing needs to be
-	  deferred for T.38. Like the leaked video RTP ports, the T.38
-	  handler needs to clean up allocated resources from deciding if
-	  SDP processing needs to be deffered. * Cleaned up some dead code
-	  in handle_incoming_sdp() and sdp_requires_deferral().
-	  ASTERISK-23721 #close Reported by: cervajs Review:
-	  https://reviewboard.asterisk.org/r/3571/ ........ Merged
-	  revisions 414749 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, CHANGES, apps/app_agent_pool.c: app_agent_pool: Return to
-	  dialplan if the agent fails to ack the call. Improvements to the
-	  agent pool functionality. * AgentRequest no longer hangs up the
-	  caller if the agent fails to connect with the caller. It now
-	  continues in the dialplan. * AgentRequest returns AGENT_STATUS
-	  set to NOT_CONNECTED if the agent failed to connect with the
-	  call. Most likely because the agent did not acknowledge the call
-	  in time or got disconnected. * The agent alerting play file
-	  configured by the agent.conf custom_beep option can now be
-	  disabled by setting the option to an empty string. The agent is
-	  effectively alerted to a call presence when MOH stops. * Fixed
-	  bridge reference leak when the agent connects with a caller.
-	  ASTERISK-23499 #close Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3551/ ........ Merged
-	  revisions 414747 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-28 11:37 +0000 [r414696]  Joshua Colp <jcolp at digium.com>
+	* res_rtp_asterisk: Don't leak temporary key when enabling PFS.
 
-	* res/res_config_odbc.c, /, funcs/func_odbc.c: res_config_odbc: Use
-	  dynamically sized buffers to store row data so values do not get
-	  truncated. ASTERISK-23582 #close ASTERISk-23582 #comment Reported
-	  by: Walter Doekes Review:
-	  https://reviewboard.asterisk.org/r/3557/ ........ Merged
-	  revisions 414693 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414694 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414695 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  A change recently went in which enabled perfect forward secrecy for
+	  DTLS in res_rtp_asterisk. This was accomplished two different ways
+	  depending on the availability of a feature in OpenSSL. The fallback
+	  method created a temporary instance of a key but did not free it.
+	  This change fixes that.
 
-2014-05-28 09:43 +0000 [r414567-414679]  Walter Doekes <walter+asterisk at wjd.nu>
+	  ASTERISK-25265
 
-	* /, channels/chan_unistim.c: chan_unistim: Unlock mutex in rare
-	  OOM condition. #ASTERISK-23792 #close Reported by: Peter Whisker
-	  Review: https://reviewboard.asterisk.org/r/3567/ ........ Merged
-	  revisions 414677 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414678 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: Iadc031b67a91410bbefb17ffb4218d615d051396
+2015-07-28 05:33 +0000 [2d2e741905]  Mark Duncan <mark at syon.co.jp>
 
-	* /, channels/chan_sip.c: chan_sip: Start session timer at 200, not
-	  at INVITE. Asterisk started counting the session timer at INVITE
-	  while the other end correctly started at 200. This meant that for
-	  short session-expiries (90 seconds) combined with long ringing
-	  times (e.g. 30 seconds), asterisk would wrongly assume that the
-	  timer was hit before the other end thought it was time to send a
-	  session refresh. This resulted in prematurely ended calls. This
-	  changes the session timer to start counting first at 200 like RFC
-	  says it should. (Also removed a few excess NULL checks that would
-	  never hit, because if they did, asterisk would have crashed
-	  already.) ASTERISK-22551 #close Reported by: i2045 Review:
-	  https://reviewboard.asterisk.org/r/3562/ ........ Merged
-	  revisions 414620 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414628 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414636 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res/res_rtp_asterisk: Add ECDH support
 
-	* res/res_config_odbc.c, /: res_config_odbc: Fix old and new
-	  ast_string_field memory leaks. The ODBC realtime driver uses ^NN
-	  parameter encoding to cope with the special meaning of the
-	  semi-colon. A semi-colon in a field is interpreted as if the key
-	  was supplied twice, something which isn't otherwise possible with
-	  fixed database columns. E.g. allow=alaw;ulaw is parsed as
-	  allow=alaw and allow=ulaw. A literal semi-colon is rewritten to
-	  ^3B when stored in the database. The module uses a stringfield to
-	  efficiently store the encoded parameters. However, this
-	  stringfield wasn't always freed in some off-nominal cases. Commit
-	  r413241 fixed initialization so the encoding for INSERT and
-	  DELETE queries wouldn't crash. (Only SELECTs and UPDATEs worked
-	  apparently.) But that commit forgot the frees. This change cleans
-	  that up. Review: https://reviewboard.asterisk.org/r/3555/
-	  ........ Merged revisions 414564 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414566 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-25 02:37 +0000 [r414543]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/core_unreal.c: core_unreal: Prevent double free of
-	  core_unreal pvt When a channel is destroyed (such as via
-	  ast_channel_release in off nominal paths in core_unreal), it will
-	  attempt to free (via ast_free) the channel tech pvt. This is
-	  problematic for a few reasons: 1. The channel tech pvt is an ao2
-	  object in core_unreal. Free'ing the pvt directly is no good. 2.
-	  The channel tech pvt's reference count is dropped just prior to
-	  calling ast_channel_release, resulting in the pvt's destruction.
-	  Hence, the channel destructor is free'ing an invalid pointer.
-	  This patch keeps the dropping of the reference count, but sets
-	  the pvt to NULL on the channel prior to releasing it. This models
-	  what would occur if the channel was hung up directly. ........
-	  Merged revisions 414542 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-23 17:36 +0000 [r414529]  Matthew Jordan <mjordan at digium.com>
-
-	* tests/test_cel.c, /: test_cel: Fix unit tests broken due to event
-	  def changes from res_corosync This patch instructs test_cel to
-	  skip any IE types it doesn't care about. The addition of the raw
-	  and bitfield types caused the tests to fail. ........ Merged
-	  revisions 414528 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-23 14:36 +0000 [r414475]  Kinsey Moore <kmoore at digium.com>
-
-	* main/event.c, /: Fix signed/unsigned build warnings ........
-	  Merged revisions 414474 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-22 16:19 +0000 [r414417]  Richard Mudgett <rmudgett at digium.com>
+	  This will add ECDH support to Asterisk. It will
+	  detect auto ECDH support in OpenSSL
+	  (1.0.2b and above) during ./configure. If this is
+	  available, it will use it,
+	  otherwise it will fall back to prime256v1 (this
+	  behavior is consistent with
+	  other projects such as Apache and nginx).
 
-	* /, apps/app_meetme.c: app_meetme: Don't interrupt MOH for
-	  waitmarked users. Occasionally, when the last marked user leaves
-	  the conference, waitmarked users don't get MOH if MOH is supposed
-	  to be played while a waitmarked user is waiting for another
-	  marked user. * Made not interrupt MOH when the user is a
-	  waitmarked user. The waitmarked user doesn't need to hear any
-	  leave announcements from the conference as the user would have
-	  already heard different leave announcements if they were enabled.
-	  Apparently DAHDI occasionally sends unending non-silent streams
-	  to these users or a normal user still in the conference has
-	  continuous high background noise. These non-silent streams cause
-	  MOH to be suspended while the never ending "announcement" is
-	  played. Issue caused by ASTERISK-13680. AST-1349 #close Reported
-	  by: Tyler Stewart Review:
-	  https://reviewboard.asterisk.org/r/3543/ ........ Merged
-	  revisions 414401 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414402 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414404 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-22 16:09 +0000 [r414406]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* rest-api/api-docs/events.json, /, res/stasis/app.c,
-	  res/ari/resource_events.c, include/asterisk/stasis_app.h,
-	  include/asterisk/stasis.h, apps/app_userevent.c,
-	  res/ari/resource_events.h, res/ari/ari_model_validators.c,
-	  CHANGES, main/stasis.c, res/ari/ari_model_validators.h,
-	  include/asterisk/stasis_channels.h, res/res_ari_events.c,
-	  main/stasis_channels.c, res/res_stasis.c,
-	  main/manager_channels.c, main/stasis_endpoints.c: ARI: Add
-	  ability to raise arbitrary User Events User events can now be
-	  generated from ARI. Events can be signalled with arbitrary json
-	  variables, and include one or more of channel, bridge, or
-	  endpoint snapshots. An application must be specified which will
-	  receive the event message (other applications can subscribe to
-	  it). The message will also be delivered via AMI provided a
-	  channel is attached. Dialplan generated user event messages are
-	  still transmitted via the channel, and will only be received by a
-	  stasis application they are attached to or if the channel is
-	  subscribed to. This change also introduces the multi object blob
-	  mechanism used to send multiple snapshot types in a single
-	  message. The dialplan app UserEvent was also changed to use multi
-	  object blob, and a new stasis message type created to handle
-	  them. ASTERISK-22697 #close Review:
-	  https://reviewboard.asterisk.org/r/3494/ ........ Merged
-	  revisions 414405 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-22 15:52 +0000 [r414403]  Jonathan Rose <jrose at digium.com>
-
-	* include/asterisk/bridge.h, res/parking/parking_bridge_features.c,
-	  channels/chan_mgcp.c, res/res_pjsip_refer.c,
-	  channels/chan_dahdi.c, channels/sig_analog.c, /,
-	  channels/chan_sip.c, main/parking.c, main/bridge.c,
-	  main/bridge_basic.c, res/parking/parking_applications.c,
-	  include/asterisk/parking.h: res_pjsip_refer: Fix bugs involving
-	  Parking/PJSIP/transfers PJSIP would never send the final 200
-	  Notify for a blind transfer when transferring to parking. This
-	  patch fixes that. In addition, it fixes a reference leak when
-	  performing blind transfers to non-bridging extensions. Review:
-	  https://reviewboard.asterisk.org/r/3485/ ........ Merged
-	  revisions 414400 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-22 14:02 +0000 [r414331-414348]  Matthew Jordan <mjordan at digium.com>
-
-	* /, UPGRADE.txt: UPGRADE: Add note for REF_DEBUG flag ........
-	  Merged revisions 414345 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414346 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414347 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_corosync.c, include/asterisk/stasis.h, main/app.c,
-	  main/devicestate.c, main/event.c, main/stasis.c,
-	  include/asterisk/devicestate.h, include/asterisk/event.h,
-	  main/stasis_message.c, /, include/asterisk/event_defs.h:
-	  res_corosync: Update module to work with Stasis (and compile)
-	  This patch fixes res_corosync such that it works with Asterisk
-	  12. This restores the functionality that was present in previous
-	  versions of Asterisk, and ensures compatibility with those
-	  versions by restoring the binary message format needed to pass
-	  information from/to them. The following changes were made in the
-	  core to support this: * The event system has been partially
-	  restored. All event definition and event types in this patch were
-	  pulled from Asterisk 11. Previously, we had hoped that this
-	  information would live in res_corosync; however, the approach in
-	  this patch seems to be better for a few reasons: (1)
-	  Theoretically, ast_events can be used by any module as a binary
-	  representation of a Stasis message. Given the structure of an
-	  ast_event object, that information has to live in the core to be
-	  used universally. For example, defining the payload of a device
-	  state ast_event in res_corosync could result in an incompatible
-	  device state representation in another module. (2) Much of this
-	  representation already lived in the core, and was not easily
-	  extensible. (3) The code already existed. :-) * Stasis message
-	  types now have a message formatter that converts their payload to
-	  an ast_event object. * Stasis message forwarders now handle
-	  forwarding to themselves. Previously this would result in an
-	  infinite recursive call. Now, this simply creates a new
-	  forwarding object with no forwards set up (as it is the thing it
-	  is forwarding to). This is advantageous for res_corosync, as
-	  returning NULL would also imply an unrecoverable error. Returning
-	  a subscription in this case allows for easier handling of message
-	  types that are published directly to an aggregate topic that has
-	  forwarders. Review: https://reviewboard.asterisk.org/r/3486/
-	  ASTERISK-22912 #close ASTERISK-22372 #close ........ Merged
-	  revisions 414330 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-21 22:24 +0000 [r414297]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/core_unreal.c: core_unreal: Only block media frames when
-	  a generator is on both ends of an unreal channel. The fix for
-	  ASTERISK-12292 was a bit too aggressive. You could have
-	  generators pointed at each other on local channels but need to
-	  get other kinds of frames such as DTMF or CONNECTED_LINE frames
-	  accross. ........ Merged revisions 414269 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414270 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414272 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This fixes WebRTC being broken in Firefox 38+ due
+	  to Firefox now only supporting
+	  ciphers with perfect forward secrecy.
 
-2014-05-21 19:08 +0000 [r414217]  Scott Griepentrog <sgriepentrog at digium.com>
+	  ASTERISK-25265 #close
 
-	* /, funcs/func_strings.c: pbx.c: prevent potential crash from
-	  recursive replace() Recurisve usage of replace() resulted in
-	  corruption of the temporary string storage and potential crash.
-	  By changing the string to be allocated separtely per instance,
-	  this is eliminated. ASTERISK-23650 #comment Reported by: Roel van
-	  Meer ASTERISK-23650 #close Review:
-	  https://reviewboard.asterisk.org/r/3539/ ........ Merged
-	  revisions 414214 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414215 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414216 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-19 19:52 +0000 [r414196]  Paul Belanger <paul.belanger at polybeacon.com>
-
-	* res/res_stasis_answer.c, /: Replace __ast_answer with
-	  ast_raw_answer in app_control_answer While load testing an ARI
-	  application, I noticed asterisk was returning HTTP 500 internal
-	  server errors on channels/:id/answer. After talking to
-	  #asterisk-dev, the issue appeared to be a lack of media flowing
-	  after __ast_answer() was called. So now, we call ast_raw_answer
-	  instead and no longer wait for media. ASTERISK-23758 #close
-	  Review: https://reviewboard.asterisk.org/r/3549/ ........ Merged
-	  revisions 414195 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-19 01:10 +0000 [r414123-414138]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  main/bridge_channel.c, res/res_pjsip_refer.c,
-	  res/res_pjsip_session.c, main/channel.c, /, main/framehook.c:
-	  Undo r414123 The Test Suite caught a few problems, undoing until
-	  those are resolved
-
-	* include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  main/bridge_channel.c, res/res_pjsip_session.c, main/channel.c,
-	  /, main/framehook.c: bridge_native_rtp/bridge_channel: Fix direct
-	  media issues due to frame hook This patch fixes issues with
-	  direct media bridges that occur after a blind transfer. These
-	  issues were caught by the (currently failing)
-	  pjsip/transfers/blind_transfer/caller_direct_media test. The test
-	  currently fails primarily for two reasons: (1) When Bob and
-	  Charlie (the transfer target and the transfer destination) enter
-	  a bridge together, the framehook remains on the transfer target
-	  channel until both channels are in the bridge. As it consumes
-	  voice frames, the initial bridge type is a simple bridge. The
-	  framehook is removed when both channels are in the bridge;
-	  however, this does not currently cause the bridging framework to
-	  re-evaluate the bridge. This patch adds a AST_SOFTHANGUP_UNBRIDGE
-	  poke to the transfer target channel when a framehook is removed
-	  so the bridge can re-evaluate itself. (2) When a channel leaves a
-	  native RTP bridge, it may be leaving due to being hung up.
-	  Sending a re-INVITE to a channel that is about to be hung up is
-	  not nice - in fact, there's a good chance we'll send the BYE
-	  request before the channel has had a chance to send back a 200
-	  OK. To be somewhat nicer, this patch adds a function to channel.h
-	  that allows the bridging framework to query for exactly why a
-	  channel is leaving a bridge via the channel's soft hangup flags.
-	  This allows it to only send the re-INVITE if there's a chance the
-	  channel will survive the native bridging experience. Review:
-	  https://reviewboard.asterisk.org/r/3535/ ........ Merged
-	  revisions 414122 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-16 20:06 +0000 [r413994-414070]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, channels/chan_dahdi.c: chan_dahdi: Fix analog dialtone
-	  detection. * Check if waitingfordt (waitfordialtone) is enabled
-	  in dahdi_read() to allow the DSP to operate early enough to
-	  detect dialtone. * Made use the correct variable in
-	  my_check_waitingfordt(). ASTERISK-23709 #close Reported by: Steve
-	  Davies Patches: dialtone_detect_fix (license #5012) patch
-	  uploaded by Steve Davies Review:
-	  https://reviewboard.asterisk.org/r/3534/ ........ Merged
-	  revisions 414067 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 414068 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414069 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I8c13b33a2a79c0bde2e69e4ba6afa5ab9351465b
 
-	* channels/sig_pri.c, /: sig_pri.c: Pull the pri_dchannel()
-	  PRI_EVENT_RING case into its own function. * Populate the
-	  CALLERID(ani2) value (and the special CALLINGANI2 channel
-	  variable) with the ANI2 value in addition to the PRI specific
-	  ANI2 channel variable. * Made complete snapshot staging with the
-	  channel lock held. All channel snapshots need to be done while
-	  the channel lock is held. ........ Merged revisions 414050 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 414051 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-07-21 15:41 +0000 [5311d18101]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, apps/app_meetme.c: app_meetme: Fix overwrite of DAHDI
-	  conference data structure. Starting a conference recording using
-	  the admin menu overwrites the DAHDI conference data structure
-	  used to modify the admin user's conference mute mode. * Made no
-	  longer pass the user's DAHDI conference data structure into the
-	  menu functions. The menu now uses its own DAHDI conference data
-	  structure to start the recording channel. * Moved the unlock
-	  conf->playlock to before playing the conf-full message. No sense
-	  keeping the lock while that prompt is playing. The user is never
-	  going to get into the conference at that point. ........ Merged
-	  revisions 413991 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413992 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413993 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* chan_sip.c: Move NULL check to where it will do some good.
 
-2014-05-14 15:41 +0000 [r413897]  Walter Doekes <walter+asterisk at wjd.nu>
+	  v11 only fix.
 
-	* /, res/res_musiconhold.c: res_musiconhold: Minor cleanup. Fix a
-	  few free()'s that should be ast_free()'s. Reverted an old
-	  workaround that isn't necessary. Reorder a tiny bit of code.
-	  Remove a bit of commented-out code. Review:
-	  https://reviewboard.asterisk.org/r/3536/ ........ Merged
-	  revisions 413894 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413895 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413896 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I340512f86cfd3a6f7703971fa8acfffc7d47132b
 
-2014-05-13 18:09 +0000 [r413878]  Jonathan Rose <jrose at digium.com>
+2015-07-17 15:54 +0000 [75185c5d8f]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/netsock2.c, /, channels/chan_sip.c,
-	  include/asterisk/netsock2.h: chan_sip: Add TLS and SRTP status to
-	  CLI command 'sip show channel' ASTERISK-23564 #close Reported by:
-	  Patrick Laimbock Review: https://reviewboard.asterisk.org/r/3474/
-	  ........ Merged revisions 413876 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413877 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* rtp_engine.c: Fix off nominal ref leak and some minor tweaks.
 
-2014-05-13 13:53 +0000 [r413790-413793]  Walter Doekes <walter+asterisk at wjd.nu>
+	  v11 only fix.
 
-	* res/res_format_attr_h264.c, /: h264: Fix H264 SDP payload format.
-	  https://tools.ietf.org/html/rfc3984#section-8.1 says
-	  profile-level-id takes 3 bytes in base16 (6 hex digits). This
-	  fixes video setup in certain cases. ASTERISK-23664 #close
-	  ASTERISK-23664 #comment Patch r3530.patch uploaded by Guillaume
-	  Maudoux. Review: https://reviewboard.asterisk.org/r/3530/
-	  ........ Merged revisions 413791 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413792 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I97885946ebc7eda19f1c18d08698117cf6a7f14f
 
-	* /, main/rtp_engine.c: rtp: Fix case typo in H263+ mime.
-	  http://tools.ietf.org/html/rfc3555#section-4.2.6 says the
-	  canonical mime subtype is "H263-1998", not "h263-1998". Original
-	  code was added in r183101 on 2009-03-19 02:26:50 +0100. This
-	  fixes issues with Polycom phones. ASTERISK-23665 #close
-	  ASTERISK-23665 #comment Patch r3529.patch uploaded by Guillaume
-	  Maudoux, backported by me. Review:
-	  https://reviewboard.asterisk.org/r/3529/ ........ Merged
-	  revisions 413787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413788 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413789 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-13 00:35 +0000 [r413770-413772]  Richard Mudgett <rmudgett at digium.com>
-
-	* configure.ac, channels/sig_pri.c, /, configure,
-	  include/asterisk/autoconfig.h.in: chan_dahdi/sig_pri: Prevent
-	  unnecessary PROGRESS events when overlap dialing is enabled. When
-	  overlap dialing is enabled, the lack of inband audio available
-	  information in the SETUP_ACKNOWLEDGE events causes an
-	  interoperability problem with SIP. sig_pri doesn't know if there
-	  is dialtone present when a SETUP_ACKNOWLEDGE is received so it
-	  assumes it is there and posts an AST_CONTROL_PROGRESS frame. The
-	  SIP channel driver then sends out a 183 Session Progress and
-	  blocks the desired 180 Ringing message when the ALERTING message
-	  comes in. * Made the configure script detect if the installed
-	  version of libpri supports the SETUP_ACKNOWLEDGE enhancements. *
-	  Using the new API, made generate an AST_CONTROL_PROGRESS frame on
-	  an incoming SETUP_ACKNOWLEDGE message when the message indicates
-	  inband audio is present instead of assuming that dialtone is
-	  present. * Using the new API, made SETUP_ACKNOWLEDGE send out an
-	  inband audio available indication only if dialtone is expected.
-	  The change also makes the fallback behaviour of sending the
-	  PROGRESS message better by sending it only if dialtone is
-	  expected. * Changed receiving a PROCEEDING message to not
-	  generate an AST_CONTROL_PROGRESS frame if the progress indication
-	  ie indicates non-end-to-end-ISDN. This helps interoperability
-	  with SIP. * Changed sending a PROCEEDING message in response to
-	  an AST_CONTROL_PROCEEDING frame to not indicate inband audio
-	  available. It was silly to do so anyway because the channel
-	  driver doesn't know if inband audio is even available. This helps
-	  interoperability with SIP. This patch and a corresponding change
-	  in libpri work together to allow Asterisk to control the inband
-	  audio available progress indication ie on the SETUP_ACKNOWLEDGE
-	  message when dialtone is present. AST-1338 #close Reported by:
-	  Tyler Stewart Review: https://reviewboard.asterisk.org/r/3521/
-	  ........ Merged revisions 413714 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413765 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413771 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/sig_pri.c: Fix compiler warning from GCC 4.10 fixup.
-	  ........ Merged revisions 413766 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-12 22:33 +0000 [r413713]  Jonathan Rose <jrose at digium.com>
-
-	* apps/app_chanspy.c, /: app_chanspy: Fix a test that was failing
-	  on account of r413551 ASTERISK-23381 #close ASTERISK-23381
-	  #comment Reported by: Robert Moss Review:
-	  https://reviewboard.asterisk.org/r/3505/ ........ Merged
-	  revisions 413710 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413712 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-11 02:09 +0000 [r413651-413682]  Joshua Colp <jcolp at digium.com>
-
-	* main/bridge_basic.c, include/asterisk/channel.h,
-	  bridges/bridge_native_rtp.c, include/asterisk/framehook.h,
-	  main/channel.c, /, main/framehook.c: framehooks: Add callback for
-	  determining if a hook is consuming frames of a specific type. In
-	  the past framehooks have had no capability to determine what
-	  frame types a hook is actually interested in consuming. This has
-	  meant that code has had to assume they want all frames, thus
-	  preventing native bridging. This change adds a callback which
-	  allows a framehook to be queried for whether it is consuming a
-	  frame of a specific type. The native RTP bridging module has also
-	  been updated to take advantange of this, allowing native bridging
-	  to occur when previously it would not. ASTERISK-23497 #comment
-	  Reported by: Etienne Lessard ASTERISK-23497 #close Review:
-	  https://reviewboard.asterisk.org/r/3522/ ........ Merged
-	  revisions 413681 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  include/asterisk/framehook.h, main/channel.c, /,
-	  main/framehook.c, main/bridge_basic.c: Undoing framehook support.
-	  Issues were uncovered by Bamboo.
-
-	* /, main/framehook.c, main/bridge_basic.c,
-	  include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  include/asterisk/framehook.h, main/channel.c: framehooks: Add
-	  callback for determining if a hook is consuming frames of a
-	  specific type. In the past framehooks have had no capability to
-	  determine what frame types a hook is actually interested in
-	  consuming. This has meant that code has had to assume they want
-	  all frames, thus preventing native bridging. This change adds a
-	  callback which allows a framehook to be queried for whether it is
-	  consuming a frame of a specific type. The native RTP bridging
-	  module has also been updated to take advantange of this, allowing
-	  native bridging to occur when previously it would not.
-	  ASTERISK-23497 #comment Reported by: Etienne Lessard
-	  ASTERISK-23497 #close Review:
-	  https://reviewboard.asterisk.org/r/3522/ ........ Merged
-	  revisions 413650 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-09 23:18 +0000 [r413589-413599]  Kinsey Moore <kmoore at digium.com>
+2015-07-16 17:40 +0000 [1b51b5efb6]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, funcs/func_env.c: Fix 32bit build for func_env ........ Merged
-	  revisions 413592 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413595 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413597 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_festival.c, pbx/dundi-parser.c, apps/app_getcpeid.c,
-	  main/netsock.c, funcs/func_channel.c, main/audiohook.c,
-	  pbx/pbx_config.c, res/res_pjsip_registrar.c, main/xmldoc.c,
-	  channels/iax2/firmware.c, apps/app_voicemail.c, main/format.c,
-	  cel/cel_pgsql.c, main/rtp_engine.c, main/parking.c,
-	  main/bridge.c, res/res_jabber.c, res/res_http_websocket.c,
-	  main/config.c, res/res_format_attr_opus.c, main/loader.c,
-	  res/parking/parking_bridge.c, main/cdr.c, main/manager.c,
-	  include/asterisk/astobj.h, main/bucket.c, apps/app_dumpchan.c,
-	  main/app.c, res/res_pjsip/config_transport.c,
-	  res/res_pjsip_refer.c, channels/chan_mgcp.c,
-	  res/res_rtp_asterisk.c, main/slinfactory.c, main/core_unreal.c,
-	  res/res_pjsip_sdp_rtp.c, res/res_crypto.c, main/acl.c,
-	  channels/sig_pri.c, res/res_monitor.c, res/res_srtp.c,
-	  main/data.c, res/res_corosync.c, channels/sip/config_parser.c,
-	  res/res_fax_spandsp.c, apps/app_stack.c, main/asterisk.c,
-	  main/udptl.c, res/res_sorcery_config.c, main/security_events.c,
-	  res/res_timing_dahdi.c, res/res_pjsip_t38.c,
-	  res/res_musiconhold.c, main/taskprocessor.c,
-	  res/res_format_attr_h263.c, res/res_xmpp.c, res/res_pktccops.c,
-	  funcs/func_hangupcause.c, channels/chan_phone.c,
-	  main/manager_bridges.c, cel/cel_odbc.c, channels/chan_skinny.c,
-	  channels/chan_motif.c, res/res_agi.c, main/logger.c,
-	  funcs/func_srv.c, channels/chan_alsa.c, apps/app_confbridge.c,
-	  res/res_pjsip_pubsub.c, channels/sip/include/sip.h, main/sched.c,
-	  apps/app_adsiprog.c, main/pbx.c, channels/chan_sip.c,
-	  res/res_fax.c, main/aoc.c, res/res_calendar_ews.c,
-	  res/parking/parking_bridge_features.c, channels/iax2/parser.c,
-	  main/callerid.c, main/file.c,
-	  res/res_pjsip/pjsip_configuration.c, main/adsi.c,
-	  main/config_options.c, pbx/pbx_dundi.c, funcs/func_iconv.c,
-	  main/bridge_channel.c, res/res_odbc.c, channels/chan_pjsip.c,
-	  res/parking/parking_manager.c, res/res_calendar.c, /,
-	  funcs/func_sysinfo.c, main/utils.c, cdr/cdr_adaptive_odbc.c,
-	  res/res_calendar_caldav.c, res/res_stasis_snoop.c,
-	  res/res_format_attr_h264.c, main/channel.c, res/ael/pval.c,
-	  res/res_ari_model.c, channels/chan_dahdi.c,
-	  channels/sig_analog.c, funcs/func_frame_trace.c,
-	  res/res_format_attr_silk.c, main/manager_channels.c,
-	  apps/app_dial.c, res/res_calendar_icalendar.c, main/translate.c,
-	  apps/app_queue.c, channels/chan_jingle.c, res/res_stun_monitor.c,
-	  main/abstract_jb.c, res/res_stasis_recording.c, apps/app_sms.c,
-	  main/event.c, apps/app_verbose.c, main/dsp.c,
-	  channels/chan_unistim.c, main/frame.c, res/res_stasis_playback.c,
-	  main/ccss.c, funcs/func_env.c, main/devicestate.c,
-	  bridges/bridge_softmix.c, channels/chan_gtalk.c,
-	  channels/chan_iax2.c, main/enum.c, main/cli.c,
-	  res/res_format_attr_celt.c, apps/confbridge/conf_config_parser.c,
-	  main/io.c, channels/pjsip/dialplan_functions.c,
-	  res/res_config_odbc.c, res/res_pjsip/location.c,
-	  res/res_pjsip_outbound_registration.c, formats/format_pcm.c,
-	  apps/app_minivm.c, main/stdtime/localtime.c, main/stun.c: Allow
-	  Asterisk to compile under GCC 4.10 This resolves a large number
-	  of compiler warnings from GCC 4.10 which cause the build to fail
-	  under dev mode. The vast majority are signed/unsigned mismatches
-	  in printf-style format strings. ........ Merged revisions 413586
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 413587 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413588 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* rtp_engine.c: Tweak glue->update_peer() parameter nil value.
 
-2014-05-09 18:15 +0000 [r413572]  Richard Mudgett <rmudgett at digium.com>
+	  Change glue->update_peer() parameter from 0 to NULL to better indicate it
+	  is a pointer.
 
-	* main/http.c: http.c: Remove dead code.
+	  Change-Id: Iefbf9d4a708f2b64b7ad2b4e6c33bfaa12ccfa9d
 
-2014-05-09 17:03 +0000 [r413557]  Jonathan Rose <jrose at digium.com>
+2015-07-17 16:23 +0000 [f5cd1fa0df]  Richard Mudgett <rmudgett at digium.com>
 
-	* apps/app_chanspy.c, /: app_chanspy: Fix a bug where Barge mode
-	  could fail If the barge audiohook was attached prior to the spyee
-	  and its peer actually being bridged, the audiohook would not be
-	  applied and the connected peer would not be able to hear audio
-	  from the spy when the spy is in barge mode. (closes issue
-	  ASTERISK-23381) Reported by: Robert Moss Review:
-	  https://reviewboard.asterisk.org/r/3505/ ........ Merged
-	  revisions 413551 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413556 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* chan_sip.c: Tweak glue->update_peer() parameter nil value.
 
-2014-05-08 00:36 +0000 [r413488]  Joshua Colp <jcolp at digium.com>
+	  Change glue->update_peer() parameter from 0 to NULL to better indicate it
+	  is a pointer.
 
-	* apps/app_queue.c, main/manager.c, /: app_queue: Extend
-	  documentation for various Manager actions and events. ........
-	  Merged revisions 413485 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413486 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413487 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-07 21:58 +0000 [r413469]  Mark Michelson <mmichelson at digium.com>
-
-	* funcs/func_presencestate.c: Ensure that presence state is decoded
-	  properly on Asterisk startup. The CustomPresence provider
-	  callback will automatically base64 decode stored data if the 'e'
-	  option was present when the state was set. However, since the
-	  provider callback was bypassed on Asterisk startup, encoded
-	  presence subtypes and messages were being sent instead. This fix
-	  makes it so the provider callback is always used when providing
-	  presence state updates.
-
-2014-05-07 20:59 +0000 [r413453-413455]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_confbridge.c, /: app_confbridge: Fixed "CBAnn" channels
-	  not going away. Fixed a ref leak in conf_handle_talker_cb()
-	  everytime the conference bridge was found to report a channel's
-	  talker status change. The resulting leak caused the "CBAnn"
-	  channels and the conference bridge to never be destroyed. Thanks
-	  to Richard Kenner on the asterisk-user's list for locating the
-	  problem. Reported by: Richard Kenner ........ Merged revisions
-	  413454 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_confbridge.c, /: app_confbridge: Fix ref leak in CLI
-	  "confbridge kick" command. Fixed ref leak in the CLI "confbridge
-	  kick" command when the channel to be kicked was not in the
-	  conference. ........ Merged revisions 413451 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413452 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Change-Id: I8ff2e5087f0e19f6998e3488a712a2470cc823bd
 
-2014-05-07 17:56 +0000 [r413307-413399]  Mark Michelson <mmichelson at digium.com>
+2015-07-29 14:35 +0000 [f2089dce3d]  Mark Michelson <mmichelson at digium.com>
 
-	* res/res_config_odbc.c, /: Fix encoding of custom prepare extra
-	  data. Patches: res_config_odbc-take2.patch by John Hardin
-	  (License #6512) ........ Merged revisions 413396 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413397 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413398 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip/presence_xml.c, /,
-	  res/res_pjsip_pidf_digium_body_supplement.c: Improve XML
-	  sanitization in NOTIFYs, especially for presence subtypes and
-	  messages. Embedded carriage return line feed combinations may
-	  appear in presence subtypes and messages since they may be
-	  derived from user input in an instant messenger client. As such,
-	  they need to be properly escaped so that XML parsers do not vomit
-	  when the messages are received. ........ Merged revisions 413372
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_registrar.c, /: Check for an act on failures to
-	  update contacts during registration. There was an underlying
-	  issue in a realtime backend where database updates would fail.
-	  Since we were not checking for failure, we would end up in a
-	  strange state where the old database entry was still present but
-	  Asterisk thought that it had been updated. Now when an entry
-	  fails to update, we print a warning and delete the old contact
-	  from sorcery so there is no mismatch between foreground and
-	  backend state. Patches: res_pjsip_registrar.patch by John Hardin
-	  (License #6512) ........ Merged revisions 413358 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res_http_websocket: Properly encode 64 bit payload
 
-	* res/res_config_odbc.c, /: Ensure that all parts of SQL UPDATEs
-	  and DELETEs are encoded. Patches: res_config_odbc.patch by John
-	  Hardin (License #6512) ........ Merged revisions 413304 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413305 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413306 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  A test agent was continuously failing all ARI tests when run against
+	  Asterisk 13. As it turns out, the reason for this is that on those test
+	  runs, for some reason we decided to use the super extended 64 bit
+	  payload length for websocket text frames instead of the extended 16 bit
+	  payload length. For 64-bit payloads, the expected byte order over the
+	  network is
 
-2014-05-02 20:28 +0000 [r413227-413263]  Mark Michelson <mmichelson at digium.com>
+	  7, 6, 5, 4, 3, 2, 1, 0
 
-	* /, res/res_config_odbc.c: Prevent crashes in res_config_odbc due
-	  to uninitialized string fields. Patches: odbc-crash.patch by John
-	  Hardin (License #6512) ........ Merged revisions 413241 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413251 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413258 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  However, we were sending the payload as
 
-	* res/res_config_pgsql.c, /: Return the number of rows affected by
-	  a SQL insert, rather than an object ID. The realtime API
-	  specifies that the store callback is supposed to return the
-	  number of rows affected. res_config_pgsql was instead returning
-	  an Oid cast as an int, which during any nominal execution would
-	  be cast to 0. Returning 0 when more than 0 rows were inserted
-	  causes problems to the function's callers. To give an idea of how
-	  strange code can be, this is the necessary code change to fix a
-	  device state issue reported against chan_pjsip in Asterisk 12+.
-	  The issue was that the registrar would attempt to insert contacts
-	  into the database. Because of the 0 return from res_config_pgsql,
-	  the registrar would think that the contact was not successfully
-	  inserted, even though it actually was. As such, even though the
-	  contact was query-able and it was possible to call the endpoint,
-	  Asterisk would "think" the endpoint was unregistered, meaning it
-	  would report the device state as UNAVAILABLE instead of
-	  NOT_INUSE. The necessary fix applies to all versions of Asterisk,
-	  so even though the bug reported only applies to Asterisk 12+, the
-	  code correction is being inserted into 1.8+. Closes issue
-	  ASTERISK-23707 Reported by Mark Michelson ........ Merged
-	  revisions 413224 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 413225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413226 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-02 16:39 +0000 [r413211]  Richard Mudgett <rmudgett at digium.com>
-
-	* UPGRADE.txt, res/res_pjsip_refer.c, /, channels/chan_sip.c:
-	  res_pjsip_refer: Add Referred-By header on INVITE for blind
-	  transfers. Per rfc3892, the Referred-By header in a REFER must be
-	  copied into the referenced request (IE. The outgoing INVITE to
-	  the transfer target). * Automatically put the Referred-By header
-	  in the outgoing INVITE message if the SIPREFERREDBYHDR channel
-	  variable is defined with a value. * Made
-	  chan_sip.c:get_refer_info() set SIPREFERREDBYHDR for inheritance
-	  so chan_pjsip has a better chance to interoperate. * Fixed
-	  refer_blind_callback() and refer_incoming_refer_request() to not
-	  modify the data in the pointer returned by
-	  pjsip_msg_find_hdr_by_name(). It seems wrong to modify that data
-	  since the calling routine doesn't own the buffer. ASTERISK-23501
-	  #close Reported by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/3514/ ........ Merged
-	  revisions 413210 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-02 16:06 +0000 [r413197]  Jonathan Rose <jrose at digium.com>
-
-	* res/parking/res_parking.h, /, CHANGES,
-	  res/parking/parking_bridge_features.c,
-	  res/parking/parking_manager.c: Parking: Add 'AnnounceChannel'
-	  argument to manager action 'Park' (closes ASTERISK-23397)
-	  Reported by: Denis Review:
-	  https://reviewboard.asterisk.org/r/3446/ ........ Merged
-	  revisions 413196 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-01 16:21 +0000 [r413174-413183]  Mark Michelson <mmichelson at digium.com>
-
-	* funcs/func_presencestate.c: Make behavior of the PRESENCE_STATE
-	  'e' option more consistent. When writing presence state, if 'e'
-	  is specified, then the presence state will be stored in the astdb
-	  encoded. However, consumers of presence state events or those
-	  that query for the presence state will be given decoded
-	  information. If base64 encoding is desired for consumers, then
-	  the information can be base64-encoded manually and the 'e' option
-	  can be omitted. closes issue ASTERISK-23671 Reported by Mark
-	  Michelson Review: https://reviewboard.asterisk.org/r/3482
-
-	* res/res_pjsip_exten_state.c, /: Remove unnecessary repetition
-	  checks from res_pjsip_exten_state The PBX core already takes care
-	  of ensuring that repeated state changes are not communicated to
-	  exten state consumers. Because the check in res_pjsip_exten_state
-	  was incomplete, it was causing valid presence state changes not
-	  to be sent out. For instance, if the presence state did not
-	  change but the message or subtype did, then no presence-related
-	  NOTIFY request would be sent out. closes issue ASTERISK-23672
-	  Reported by Mark Michelson ........ Merged revisions 413173 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-05-01 12:31 +0000 [r413160]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip/config_transport.c, /: res_pjsip: Add the ability
-	  to configure ciphers based on name. Previously this code would
-	  only accept the OpenSSL identifier instead of the documented
-	  name. ASTERISK-23498 #close ASTERISK-23498 #comment Reported by:
-	  Anthony Messina Review: https://reviewboard.asterisk.org/r/3491/
-	  ........ Merged revisions 413159 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-30 21:03 +0000 [r413144]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/message.c, /, channels/chan_sip.c,
-	  include/asterisk/message.h, res/res_pjsip_messaging.c:
-	  chan_sip.c: Fixed off-nominal message iterator ref count and
-	  alloc fail issues. * Fixed early exit in sip_msg_send() not
-	  destroying the message iterator. * Made
-	  ast_msg_var_iterator_next() and ast_msg_var_iterator_destroy()
-	  tolerant of a NULL iter parameter in case
-	  ast_msg_var_iterator_init() fails. * Made
-	  ast_msg_var_iterator_destroy() clean up any current message data
-	  ref. * Made struct ast_msg_var_iterator,
-	  ast_msg_var_iterator_init(), ast_msg_var_iterator_next(),
-	  ast_msg_var_unref_current(), and ast_msg_var_iterator_destroy()
-	  use iter instead of i. * Eliminated RAII_VAR usage in
-	  res_pjsip_messaging.c:vars_to_headers(). ........ Merged
-	  revisions 413139 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413142 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-30 20:39 +0000 [r413141]  Joshua Colp <jcolp at digium.com>
-
-	* /, channels/chan_pjsip.c: chan_pjsip: Fix deadlock when
-	  retrieving call-id of channel. If a task was in-flight which
-	  required the channel or bridge lock it was possible for the
-	  synchronous task retrieving the call-id to deadlock as it holds
-	  those locks. After discussing with Mark Michelson the synchronous
-	  task was removed and the call-id accessed directly. This should
-	  be safe as each object involved is guaranteed to exist and the
-	  call-id will never change. ........ Merged revisions 413140 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-30 13:08 +0000 [r413125]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_http_websocket.c, /: Websocket: Add session locking and
-	  delay close This resolves a race condition where data could be
-	  written to a NULL FILE pointer causing a crash as a websocket
-	  connection was in the process of shutting down by adding locking
-	  to websocket session writes and by deferring session teardown
-	  until session destruction. (closes issue ASTERISK-23605) Review:
-	  https://reviewboard.asterisk.org/r/3481/ Reported by: Matt Jordan
-	  ........ Merged revisions 413123 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413124 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-30 12:42 +0000 [r413118-413122]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/stasis/control.c: res_stasis: Add progress indications to
-	  operations which perform media. This change fixes operations
-	  which did not account for the fact that they may be executed on
-	  channels which have not been answered. These operations will now
-	  indicate progress when invoked. ASTERISK-23560 #close
-	  ASTERISk-23560 #comment Reported by: Jan Svoboda Review:
-	  https://reviewboard.asterisk.org/r/3495/ ........ Merged
-	  revisions 413121 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_sdp_rtp.c: res_pjsip_sdp_rtp: Fix issue where
-	  sending a hold SDP twice could cause an unhold. This change fixes
-	  a bug where if an SDP with media address and sendonly was
-	  received twice the underlying call would go off hold, instead of
-	  remaining on hold. This occured because the code did not properly
-	  take into account that the SDP may contain both a valid media
-	  address and the sendonly attribute. The code now examines the
-	  sendonly attribute and media address first, so if the SDP is
-	  received again no change will occur. ASTERISK-23558 #comment
-	  Reported by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/3472/ ........ Merged
-	  revisions 413119 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_pjsip.c, res/res_pjsip_session.c, /: chan_pjsip:
-	  Add support for picking up calls in the configured pickup group.
-	  AST-1363 Review: https://reviewboard.asterisk.org/r/3478/
-	  ........ Merged revisions 413117 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-29 15:10 +0000 [r413103]  George Joseph <george.joseph at fairview5.com>
-
-	* /, include/asterisk/spinlock.h: Add "destroy" implementation for
-	  spinlock. The original commit for spinlock was missing "destroy"
-	  implementations. Most of them are no-ops but phtread_spin and
-	  pthread_mutex do need their locks destroyed. ........ Merged
-	  revisions 413102 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-29 11:27 +0000 [r413089]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_pjsip.c, /: chan_pjsip: Implement core ability to
-	  get Call-ID of a channel. This changes implement the
-	  "get_pvt_uniqueid" which is used to return the technology
-	  specific unique identifier. In the case of SIP this is the
-	  Call-ID of the dialog. Review:
-	  https://reviewboard.asterisk.org/r/3480/ ........ Merged
-	  revisions 413088 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-28 20:07 +0000 [r413074]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/bridge.c, main/bridge_basic.c: Bridging: Don't lock NULL
-	  bridges When bridge locking was added for bridge snapshot
-	  creation, some locations where bridge locking was added were not
-	  guaranteed to actually have a bridge and locking NULL AO2 objects
-	  tends to cause segfaults. This ensures that NULL bridges aren't
-	  locked. ........ Merged revisions 413073 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-28 14:40 +0000 [r413060]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_manager_presencestate.c (added), main/devicestate.c,
-	  CHANGES, main/presencestate.c, res/res_manager_devicestate.c
-	  (added): Add DeviceStateChanged and PresenceStateChanged AMI
-	  events. These events are controlled by two new modules,
-	  res_manager_devicestate and res_manager_presencestate. Review:
-	  https://reviewboard.asterisk.org/r/3417
-
-2014-04-28 07:43 +0000 [r413048]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
-
-	* UPGRADE.txt, CHANGES, channels/chan_unistim.c,
-	  configs/unistim.conf.sample: Introducing changes proposed to
-	  chan_unistim driver: 1) Added the unistim.conf variable
-	  dtmf_duration which can select the DTMF playback duration from
-	  0ms to 150ms (0 is off and is the new default) 2) Enabled the
-	  transmission of month names, which are sent with the date and
-	  changed the dateformat variable to accept the values 0-3 as per
-	  the UNISTIM standard (2 & 3 match the previous 1 & 2 formats). 3)
-	  Enabled the "Mute" packet so muting microphone works as expected
-	  and microphone muted for all calls while LED light on 4) Changed
-	  Duree to Timer on i2004 display (closes issue ASTERISK-23592)
-
-2014-04-27 19:29 +0000 [r413036]  Olle Johansson <oej at edvina.net>
-
-	* main/tcptls.c: tcptls.c : Log errors as ERROR, not warning or
-	  something else.
-
-2014-04-25 19:26 +0000 [r413012]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Add support for DTLS
-	  handshake retransmissions On congested networks, it is possible
-	  for the DTLS handshake messages to get lost. This patch adds a
-	  timer to res_rtp_asterisk that will periodically check to see if
-	  the handshake has succeeded. If not, it will retransmit the DTLS
-	  handshake. Review: https://reviewboard.asterisk.org/r/3337
-	  ASTERISK-23649 #close Reported by: Nitesh Bansal patches:
-	  dtls_retransmission.patch uploaded by Nitesh Bansal (License
-	  6418) ........ Merged revisions 413008 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 413009 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-24 14:37 +0000 [r412993]  Kevin Harwell <kharwell at digium.com>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
-	  (added): pjsip realtime: increase the size of some columns The
-	  string lengths on certain columns created through alembic for
-	  PJSIP were too short. For instance, columns containing URIs are
-	  currently set to 40 characters, but this can be too small and
-	  result in truncated values. Added an alembic migration script
-	  that increases the size of these columns and a few others to 255.
-	  ASTERISK-23639 #close Reported by: Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3475/ ........ Merged
-	  revisions 412992 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-23 20:13 +0000 [r412977]  George Joseph <george.joseph at fairview5.com>
-
-	* include/asterisk/spinlock.h (added), /, configure,
-	  include/asterisk/autoconfig.h.in, configure.ac: This patch adds
-	  support for spinlocks in Asterisk. There are cases in Asterisk
-	  where it might be desirable to lock a short critical code section
-	  but not incur the context switch and yield penalty of a mutex or
-	  rwlock. The primary spinlock implementations execute exclusively
-	  in userspace and therefore don't incur those penalties. Spinlocks
-	  are NOT meant to be a general replacement for mutexes. They
-	  should be used only for protecting short blocks of critical code
-	  such as simple compares and assignments. Operations that may
-	  block, hold a lock, or cause the thread to give up it's timeslice
-	  should NEVER be attempted in a spinlock. The first use case for
-	  spinlocks is in astobj2 - internal_ao2_ref. Currently the
-	  manipulation of the reference counter is done with an
-	  ast_atomic_fetchadd_int which works fine. When weak reference
-	  containers are introduced however, there's an additional
-	  comparison and assignment that'll need to be done while the lock
-	  is held. A mutex would be way too expensive here, hence the
-	  spinlock. Given that lock contention in this situation would be
-	  infrequent, the overhead of the spinlock is only a few more
-	  machine instructions than the current ast_atomic_fetchadd_int
-	  call. ASTERISK-23553 #close Review:
-	  https://reviewboard.asterisk.org/r/3405/ ........ Merged
-	  revisions 412976 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-23 18:03 +0000 [r412925]  Richard Mudgett <rmudgett at digium.com>
+	  3, 2, 1, 0, 7, 6, 5, 4
 
-	* /, main/http.c: http: Fix spurious ERROR message in responses
-	  with no content. Backport -r411687 and fix the fix because
-	  content_length is the length of out plus the length of the file
-	  controlled by fd. When a response has an out content length of 0,
-	  fwrite would be called to write a buffer with no data in it. This
-	  resulted in the following classic error message: [Apr 3 11:49:17]
-	  ERROR[26421] http.c: fwrite() failed: Success This patch makes it
-	  so that we only attempt to write the content of out if the out
-	  string is non-zero. ........ Merged revisions 412922 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412923 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412924 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This meant that we were saying to expect an absolutely MASSIVE payload
+	  to arrive. Since we did not follow through on this expected payload
+	  size, the client would sit patiently waiting for the rest of the payload
+	  to arrive until the test would time out.
 
-2014-04-23 15:02 +0000 [r412910]  Russell Bryant <russell at russellbryant.com>
+	  With this change, we use the htobe64() function instead of htonl() so
+	  that a 64-bit byte-swap is performed instead of a 32 bit byte-swap.
 
-	* res/res_monitor.c, funcs/func_periodic_hook.exports.in (added),
-	  main/asterisk.dynamics, funcs/func_periodic_hook.c: Fix error
-	  loading res_monitor. For some odd reason, loading app_mixmonitor
-	  was fine, but res_monitor was not. This patch fixes a set of
-	  issues related to func_periodic_hook exporting the beep functions
-	  that gets res_monitor working again.
+	  Change-Id: Ibcd8552392845fbcdd017a8c8c1043b7fe35964a
 
-2014-04-22 10:09 +0000 [r412883]  Joshua Colp <jcolp at digium.com>
+2015-07-24 22:06 +0000  Asterisk Development Team <asteriskteam at digium.com>
 
-	* /, res/stasis/app.c: res_stasis: Fix crash when handling a failed
-	  blind transfer message. This changes fixes a crash that occurs
-	  when stasis determines if it should send a message out to an
-	  application or not. The code incorrectly assumed that a bridge
-	  snapshot would always be present when in reality for failure
-	  cases it may not be. ASTERISK-23573 #close ........ Merged
-	  revisions 412882 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* asterisk 11.19.0-rc1 Released.
 
-2014-04-21 17:56 +0000 [r412759-412824]  Jonathan Rose <jrose at digium.com>
+2015-07-24 17:04 +0000 [53694b8537]  Matt Jordan <mjordan at digium.com>
 
-	* CHANGES, /: chan_sip: trust_id_outbound CHANGES message
-	  improvement (closes issue AST-1301) (closes issue ASTERISK-19465)
-	  Reported by: Krzysztof Chmielewski ........ Merged revisions
-	  412821 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 412822 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412823 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_sip.c, configs/sip.conf.sample, CHANGES,
-	  channels/sip/include/sip.h: chan_sip: Add sendrpid trust options
-	  In r411189, some behavior was changed which made sendrpid
-	  behavior act in a more trusting manner by sending full user data
-	  for peers set with private caller presence in P-Asserted-Identity
-	  headers. Since this changed long time expected behaviors, we
-	  decided to pull that patch when that was pointed out by the
-	  community. Instead, this patch provides a trust_id_outbound
-	  setting which will expose the data per RFC-3325 if set to 'yes'
-	  and simply not send the PAI/RPID headers at all if set to 'no'.
-	  By default trust_id_outbound will be set to 'legacy' which will
-	  preserve the behavior prior to these patches. Extra special
-	  thanks to Walter Doekes for providing advice and feedback.
-	  (closes issue AST-1301) (closes issue ASTERISK-19465) Reported
-	  by: Krzysztof Chmielewski Review:
-	  https://reviewboard.asterisk.org/r/3447/ ........ Merged
-	  revisions 412744 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412746 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412747 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* Release summaries: Add summaries for 11.19.0-rc1
 
-2014-04-21 16:16 +0000 [r412729-412750]  Kinsey Moore <kmoore at digium.com>
+2015-07-24 17:03 +0000 [78df850c89]  Matt Jordan <mjordan at digium.com>
 
-	* main/http.c, main/manager.c, /: HTTP: Add TCP_NODELAY to accepted
-	  connections This adds the TCP_NODELAY option to accepted
-	  connections on the HTTP server built into Asterisk. This option
-	  disables the Nagle algorithm which controls queueing of outbound
-	  data and in some cases can cause delays on receipt of response by
-	  the client due to how the Nagle algorithm interacts with TCP
-	  delayed ACK. This option is already set on all non-HTTP AMI
-	  connections and this change would cover standard HTTP requests,
-	  manager HTTP connections, and ARI HTTP requests and websockets in
-	  Asterisk 12+ along with any future use of the HTTP server.
-	  Review: https://reviewboard.asterisk.org/r/3466/ ........ Merged
-	  revisions 412745 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412748 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412749 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_confbridge.c, /: Confbridge: Fix ConfbridgeKick AMI
-	  documentation This adds documentation for the "all" channel
-	  option for the ConfbridgeKick AMI action and adjusts AMI
-	  responses accordingly. (issue ASTERISK-23282) Reported by: Dorian
-	  Logan ........ Merged revisions 412730 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, apps/app_confbridge.c: Confbridge: Add references for kick all
-	  option After the ability to kick all attendees from a conference
-	  was added, a rework removed the comment about that feature from
-	  the CLI documentation. This adds that documentation and adds
-	  "all" to the participant tab completion list for the confbridge
-	  kick command. (closes issue ASTERISK-23282) Reported by: Dorian
-	  Logan ........ Merged revisions 412728 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-21 08:36 +0000 [r412714]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
-
-	* /, channels/chan_unistim.c: Fix wrong dialtone. The "modulation"
-	  should not be referenced for tone+tone as it refers to the on-off
-	  characteristic - this often resulted in a single tone rather than
-	  the multitone as in the UK. ........ Merged revisions 412712 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-19 02:14 +0000 [r412697-412699]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/asterisk.c: main/asterisk: Fix startup sequence for
-	  realtime features When ASTERISK-23265/ASTERISK-23320 was fixed,
-	  it inadvertently led to realtime features breaking. This was due
-	  to features loading prior to realtime. This patch fixes this by
-	  loading features after loading dynamic modules. ASTERISK-23487
-	  #close Reported by: Denis Tested by: Denis ........ Merged
-	  revisions 412698 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* .version: Update for 11.19.0-rc1
 
-	* /, apps/app_sms.c: app_sms: Fix uninitialized values; hangup
-	  channel when REL is sent successfully This patch fixes two issues
-	  in app_sms: (1) Firstly, the 'flags' field on the stack in
-	  sms_exec() is uninitialised, causing it to use the wrong protocol
-	  in some cases. This patch correctly initializes the flags fields.
-	  (2) Secondly, when disconnect supervision is not working or
-	  inbanddisconnect=yes is set in chan_dahdi.conf, app_sms was
-	  failing to terminate the call after it sent the REL(ease) message
-	  and the peer stopped talking to it. This patch fixes the code to
-	  handle the 'bad stop bit' message more gracefully in that case,
-	  and hang up the call. Review:
-	  https://reviewboard.asterisk.org/r/1392/ ASTERISK-18331 #close
-	  Reported by: David Woodhouse patches: asterisk-fix-sms.patch
-	  uploaded by David Woodhouse (License 5754) ........ Merged
-	  revisions 412655 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412656 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412657 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-18 20:09 +0000 [r412641]  Jonathan Rose <jrose at digium.com>
-
-	* /, res/ari/resource_bridges.h, res/stasis/control.c,
-	  include/asterisk/stasis_app.h, res/stasis/control.h,
-	  res/ari/resource_channels.c, CHANGES, res/res_stasis.c,
-	  rest-api/api-docs/bridges.json, res/ari/resource_bridges.c,
-	  res/res_ari_bridges.c, res/res_stasis_playback.c: ARI: Make
-	  bridges/{bridgeID}/play queue sound files Previously multiple
-	  play actions against a bridge at one time would cause the sounds
-	  to play simultaneously on the bridge. Now if a sound is already
-	  playing, the play action will queue playback to occur after the
-	  completion of other sounds currently on the queue. (closes issue
-	  ASTERISK-22677) Reported by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/3379/ ........ Merged
-	  revisions 412639 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-18 17:17 +0000 [r412589]  Rusty Newton <rnewton at digium.com>
-
-	* sounds/sounds.xml, sounds/Makefile, /: sounds: Fix Sounds
-	  Makefile and XML that didn't support new sound prompt sets In
-	  sounds/Makefile 1 Adds and moves some lines necessary for the
-	  en_GB core set. I'm just following how the other sets are defined
-	  here. 2 removes the ES extra sounds related lines as we don't
-	  have ES extra sound sets. In sounds/sounds.xml 3 Adds member
-	  definitons for EN_AU, EN_GB, IT for core sound sets, and EN_GB in
-	  extra sound sets ASTERISK-23550 #close Review:
-	  https://reviewboard.asterisk.org/r/3464/ ........ Merged
-	  revisions 412586 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412587 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-18 17:02 +0000 [r412584]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip/location.c: Allow for multiple contacts to be
-	  configured in a single contact= line. This is useful for
-	  configuring multiple permanent contacts for an AOR when using
-	  realtime AORs. Review: https://reviewboard.asterisk.org/r/3462
-	  ........ Merged revisions 412582 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-18 16:44 +0000 [r412580-412583]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/dial.c, main/pbx.c, /, apps/app_originate.c,
-	  include/asterisk/pbx.h: Originated calls: Fix several originate
-	  call problems. * Restore the reason value set by
-	  pbx_outgoing_attempt() to use AST_CONTROL_xxx values as all the
-	  consumers were expecting rather than cause codes. * Fixed the
-	  dial routines to set cause codes for more than just ast_request()
-	  so pbx_outgoing_attempt() reason codes will function. * Fix
-	  inconsistent locked_channel return status in
-	  pbx_outgoing_attempt(). The chanel may not have been locked or
-	  the channel may have been a stale pointer. * Fixed the
-	  OutgoingSpoolFailed channel to run dialplan whenever the dialing
-	  fails for an originate exten and 1 < synchronous. * Fix incorrect
-	  ast_cond_wait() usage in pbx_outgoing_attempt(). Indroduced by
-	  issue ASTERISK-22212 patch. * Made struct pbx_outgoing use the
-	  ao2 lock instead of its own lock for the cond wait mutex. No
-	  sense in having two locks associated with the same struct when
-	  only one is needed. Review:
-	  https://reviewboard.asterisk.org/r/3421/ ........ Merged
-	  revisions 412581 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_channels.c, apps/app_queue.c, apps/app_dial.c, /:
-	  app_dial and app_queue: Make lock the forwarding channel while
-	  taking the channel snapshot. * Fixed
-	  ast_channel_publish_dial_forward() not locking the forwarded
-	  channel when taking the channel snapshot. * Fixed
-	  app_dial.c:do_forward() using the wrong channel to get the
-	  original call forwarding string. * Removed unnecessary locking
-	  when calling ast_channel_publish_dial() and
-	  ast_channel_publish_dial_forward() in app_dial and app_queue.
-	  Holding channel locks when calling
-	  ast_channel_publish_dial_forward() with a forwarded channel could
-	  result in pausing the system while the stasis bus completes
-	  processsing a forwarded channel subscription. Review:
-	  https://reviewboard.asterisk.org/r/3451/ ........ Merged
-	  revisions 412579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-18 14:25 +0000 [r412566]  Kinsey Moore <kmoore at digium.com>
-
-	* res/ari/ari_websockets.c, res/res_ari.c, main/manager.c, /: ARI:
-	  Add debug logging for events and responses This adds DEBUG level
-	  logging for ARI websocket events and HTTP responses similar to
-	  what is available for AMI. Logging for ARI HTTP requests is
-	  already adequate for debugging purposes. ........ Merged
-	  revisions 412565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-17 22:50 +0000 [r412552]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/location.c, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/pjsip_options.c, res/res_pjsip.c,
-	  res/res_pjsip_registrar.c: res_pjsip: Handle reloading when
-	  permanent contacts exist and qualify is configured. This change
-	  fixes a problem where permanent contacts being qualified were not
-	  being updated. This was caused by the permanent contacts getting
-	  a uuid and not a known identifier, causing an inability to look
-	  them up when updating in the qualify code. A bug also existed
-	  where the new configuration may not be available immediately when
-	  updating qualifies. (closes issue ASTERISK-23514) Reported by:
-	  Richard Mudgett Review: https://reviewboard.asterisk.org/r/3448/
-	  ........ Merged revisions 412551 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-17 22:42 +0000 [r412536-412550]  Jonathan Rose <jrose at digium.com>
-
-	* /, main/app.c: Fix a silly shadowed variable mistake that was
-	  missed from play tones patch ........ Merged revisions 412549
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/ari/resource_bridges.h, main/app.c,
-	  rest-api/api-docs/channels.json, CHANGES,
-	  rest-api/api-docs/bridges.json, res/ari/resource_channels.h,
-	  include/asterisk/app.h, res/res_stasis_playback.c: ARI: Add tones
-	  playback resource Adds a tones URI type to the playback resource.
-	  The tone can be specified by name (from indications.conf) or by a
-	  tone pattern. In addition, tonezone can be specified in the URI
-	  (by appending ;tonezone=<zone>). Tones must be stopped manually
-	  in order for a stasis control to move on from playback of the
-	  tone. Tones may be paused, resumed, restarted, and stopped. They
-	  may not be rewound or fast forwarded (tones can't be controlled
-	  in a way that lets you skip around from note to note and pausing
-	  and resuming will also restart the tone from the beginning).
-	  Tests are currently in development for this feature
-	  (https://reviewboard.asterisk.org/r/3428/). (closes issue
-	  ASTERISK-23433) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3427/ ........ Merged
-	  revisions 412535 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-17 20:25 +0000 [r412467-412484]  Matthew Jordan <mjordan at digium.com>
-
-	* channels/chan_oss.c, /, main/Makefile: main/Makefile: Fix build
-	  failure on SmartOS/Illumos/SunOS This patch fixes two issues when
-	  building on SmartOS: - channels/chan_oss.c: it makes sure
-	  soundcard.h is found - main/Makefile: only use
-	  "-Wl,--version-script" when GNU LD is used as the Sun Linker
-	  doesn't support that. Similar checks are already used elswhere in
-	  the Makefile Review: https://reviewboard.asterisk.org/r/3426
-	  ASTERISK-23576 #close Reported by: Sebastian Wiedenroth patches:
-	  fix-sunos.diff uploaded by Sebastian Wiedenroth (License 6597)
-	  ........ Merged revisions 412468 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412483 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/sip/include/sip.h, channels/chan_sip.c, CHANGES:
-	  chan_sip: Add SIPURIPHONECONTEXT channel variable for Request TEL
-	  URIs This patch is a continuation of
-	  https://reviewboard.asterisk.org/r/3349/, committed in r412303.
-	  It resolves a finding oej had that the phone-context be available
-	  in a channel variable separate from SIPDOMAIN. This patch adds
-	  that variable as SIPURIPHONECONTEXT. It also allows a local
-	  number (or global number specified in the TEL URI) to be used to
-	  look up as a peer. (issue ASTERISK-17179) Review:
-	  https://reviewboard.asterisk.org/r/3349/
-
-2014-04-17 15:17 +0000 [r412454]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_refer.c, /: res_pjsip_refer: Channel variable
-	  SIPREFERTOHDR not being set during blind transfer The
-	  SIPREFERTOHDR channel variable is not being set on any channel
-	  when performing a blind transfer using PJSIP. The
-	  'refer->refer_to' was not being set during a blind transfer.
-	  Updated so the 'refer_to' is set to the target uri on a blind
-	  transfer. (closes issue ASTERISK-23502) Reported by: John Bigelow
-	  Review: https://reviewboard.asterisk.org/r/3445/ ........ Merged
-	  revisions 412453 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-16 19:14 +0000 [r412440]  Kinsey Moore <kmoore at digium.com>
-
-	* /, include/asterisk/stasis_app.h: Stasis: Add a usage note on
-	  stasis_app_get_bridge This function returns an ast_bridge without
-	  a refcount bump and the caller must increment the count if it
-	  intends to hold the pointer. (closes issue ASTERISK-23588)
-	  Review: https://reviewboard.asterisk.org/r/3450/ Reported by:
-	  Matt Jordan ........ Merged revisions 412439 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-15 23:21 +0000 [r412427]  Russell Bryant <russell at russellbryant.com>
-
-	* bridges/bridge_builtin_features.c, include/asterisk/monitor.h,
-	  CHANGES, apps/app_queue.c, funcs/func_periodic_hook.c,
-	  apps/app_mixmonitor.c, include/asterisk/beep.h (added),
-	  res/res_monitor.c: (mix)monitor: Add options to enable a periodic
-	  beep Add an option to enable a periodic beep to be played into a
-	  call if it is being recorded. If enabled, it uses the
-	  PERIODIC_HOOK() function internally to play the 'beep' prompt
-	  into the call at a specified interval. This option is provided
-	  for both Monitor() and MixMonitor(). Review:
-	  https://reviewboard.asterisk.org/r/3424/
-
-2014-04-15 18:30 +0000 [r412384-412414]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/stasis_channels.c, main/features_config.c,
-	  res/res_parking.c, main/rtp_engine.c, /: Eliminate some more
-	  unnecessary RAII_VAR() uses. RAII_VAR() is not a hammer
-	  appropriate to pound all nails. ........ Merged revisions 412413
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_playback.c, /, res/stasis/app.c, res/res_fax.c,
-	  res/res_pjsip/security_events.c,
-	  res/parking/parking_applications.c, channels/chan_oss.c,
-	  main/stasis_bridges.c, res/res_pjsip_session.c,
-	  res/stasis_recording/stored.c, main/cdr.c, res/res_parking.c,
-	  channels/chan_skinny.c, res/res_pjsip/location.c,
-	  res/res_stasis_recording.c, main/stasis_channels.c,
-	  res/ari/resource_channels.c, res/parking/parking_manager.c,
-	  res/ari/resource_recordings.c, res/res_pjsip_refer.c,
-	  res/res_ari.c, main/pbx.c: Remove unused RAII_VAR() declarations.
-	  * Remove unused RAII_VAR() declarations. The compiler cannot
-	  catch these because the cleanup function "references" the unused
-	  variable. Some actually allocated and released resources that
-	  were never used. * Fixed some whitespace issues in
-	  stasis_bridges.c. ........ Merged revisions 412399 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/rtp_engine.h, main/rtp_engine.c, /,
-	  channels/chan_sip.c: chan_sip.c: Fix channel staging assertion
-	  failure. The failing assertion ensures that the final snapshot
-	  gets generated so CDR records can get finalized. The only place
-	  where a channel staging snapshot flag could be left set is in
-	  chan_sip.c:handle_request_bye(). The function could return before
-	  clearing the flag because the channel could dissappear while the
-	  function had to have the channel unlocked. * Fixed
-	  handle_request_bye() channel snapshot staging coverage area to
-	  not have a return in the middle of it and be unable to clear the
-	  staging flag. * Pushed the channel snapshot staging coverage area
-	  into ast_rtp_instance_set_stats_vars() to ensure that the staging
-	  is not interrutped. * Made callers of
-	  ast_rtp_instance_set_stats_vars() not call it with any channels
-	  or channel driver private locks held to eliminate the deadlock
-	  potential. The callers must hold references to the passed in
-	  channel and rtp objects. * Eliminated sip_hangup() trying to get
-	  the bridge peer. It is futile at this point because the channel
-	  could never be in a bridge. Review:
-	  https://reviewboard.asterisk.org/r/3431/ ........ Merged
-	  revisions 412385 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_sip.c: chan_sip.c: Moved some sip_pvt unrefs
-	  after their last use. * Moved sip_pvt unref in ast_hangup() and
-	  handle_request_do() to the end of the function. The unref needs
-	  to happen after the last use of the pointer. ........ Merged
-	  revisions 412348 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412383 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-07-24 17:03 +0000 [b0e5e30a0d]  Matt Jordan <mjordan at digium.com>
 
-2014-04-15 16:13 +0000 [r412331]  Jonathan Rose <jrose at digium.com>
+	* .lastclean: Update for 11.19.0-rc1
 
-	* configs/sip.conf.sample, /, channels/chan_sip.c: Reverting
-	  r411189 so that it can be put up for public review --- r411189 |
-	  jrose | 2014-03-26 10:50:48 -0500 (Wed, 26 Mar 2014) | 12 lines
-	  chan_sip: Send real CallerID information with
-	  P-Assserted-Identity (RFC-3325) Prior to this patch, the
-	  P-Asserted-Identity header would include anonymous caller id
-	  information which seems to go against the point of the
-	  P-Asserted-Identity header. Now the real caller ID information
-	  will be included in this header. Also, no privacy header would be
-	  included. This patch adds 'Privacy: id' to outgoing SIP messages
-	  that include the P-Asserted-Identity header. (closes issue
-	  AST-1301) --- ........ Merged revisions 412328 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412329 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412330 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-07-23 13:11 +0000 [7e8916908d]  Mark Michelson <mmichelson at digium.com>
 
-2014-04-14 15:54 +0000 [r412307]  Corey Farrell <git at cfware.com>
+	* Local channels: Alternate solution to ringback problem.
 
-	* main/autoservice.c, /: autoservice: fix reference leak of logger
-	  callid. autoservice acquires a local reference to the logger
-	  callid of each channel in a loop. This local reference was not
-	  released, causing the callid of every channel in autoservice to
-	  leak. This change moves the callid unref inside the loop.
-	  ASTERISK-23616 #close Reported by: ibercom ........ Merged
-	  revisions 412305 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412306 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-12 02:27 +0000 [r412292]  Matthew Jordan <mjordan at digium.com>
-
-	* channels/sip/reqresp_parser.c, CHANGES, channels/chan_sip.c:
-	  chan_sip: Support RFC-3966 TEL URIs in inbound INVITE requests
-	  This patch adds support for handling TEL URIs in inbound INVITE
-	  requests. This includes the Request URI and the From URI. The
-	  number specified in the Request URI will be the destination of
-	  the inbound channel in the dialplan. The phone-context specified
-	  in the Request URI will be stored in the TELPHONECONTEXT channel
-	  variable. Review: https://reviewboard.asterisk.org/r/3349
-	  ASTERISK-17179 #close Reported by: Geert Van Pamel Tested by:
-	  Geert Van Pamel patches:
-	  asterisk-12.0.0-chan_sip-RFC3966_patch.txt uploaded by Geert Van
-	  Pamel (License 6140)
-	  asterisk-12.0.0-reqresp_parser-RFC3966_patch.txt uploaded by
-	  Geert Van Pamel (License 6140)
-
-2014-04-12 01:35 +0000 [r412279-412280]  Russell Bryant <russell at russellbryant.com>
-
-	* funcs/func_periodic_hook.c: func_periodic_hook: move module ref
-	  The previous code left one error path where the module would be
-	  unref'd twice instead of once. It was done once in the error
-	  handling block, and again inside of datastore destruction. Now
-	  the module ref is only released in the datastore destructor and
-	  only acquired when the datastore has been successfully allocated.
-
-	* funcs/func_periodic_hook.c: func_periodic_hook: add module ref
-	  counting This module lacked necessary module ref count
-	  incrementing and decrementing when used. This patch adds it.
-	  There's already a datastore used, so doing the ref counting along
-	  with the lifetime of the datastore provides a convenient place to
-	  do it.
-
-2014-04-11 21:43 +0000 [r412213-412228]  Richard Mudgett <rmudgett at digium.com>
+	  Commit 54b25c80c8387aea9eb20f9f4f077486cbdf3e5d solved an issue where a
+	  specific scenario involving local channels and a native local RTP bridge
+	  could result in ringback still being heard on a calling channel even
+	  after the call is bridged.
 
-	* apps/app_stack.c, /: app_stack: Add missing unlock in off-nominal
-	  path of STACK_PEEK function. ASTERISK-23620 #close Reported by:
-	  Bradley Watkins Patches: ASTERISK-23620_unlock_oldlist.patch
-	  (license #5021) patch uploaded by Bradley Watkins ........ Merged
-	  revisions 412225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412226 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412227 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* utils/Makefile, utils: utils dir: Remove no longer needed traces
-	  of refcounter except in the clean make target. * Removed no
-	  longer needed files from the svn:ignore property to make them
-	  visible.
-
-2014-04-11 12:43 +0000 [r412194]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/bridge.c, main/bridge_basic.c,
-	  include/asterisk/stasis_bridges.h, tests/test_cel.c,
-	  apps/app_confbridge.c, res/ari/resource_bridges.c: bridging:
-	  Ensure locking during snapshot creation While the vast majority
-	  of bridge snapshot creation is locked properly, there are
-	  currently some instances that are not. This adds the missing
-	  locking to ensure bridge state is not malleable during snapshot
-	  creation. (closes issue ASTERISK-22904) Review:
-	  https://reviewboard.asterisk.org/r/3415/ Reported by: Matt Jordan
-	  ........ Merged revisions 412193 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-11 08:28 +0000 [r412168-412180]  Olle Johansson <oej at edvina.net>
-
-	* main/audiohook.c: Formatting: Remove invisible characters
-
-	* main/audiohook.c: Formatting only.
-
-2014-04-11 02:59 +0000 [r412154]  Matthew Jordan <mjordan at digium.com>
-
-	* main/astobj2.c, contrib/scripts/refcounter.py (added),
-	  main/asterisk.c, utils/refcounter.c (removed),
-	  build_tools/cflags.xml, utils/utils.xml, /, channels/chan_sip.c,
-	  channels/sip/security_events.c, include/asterisk/astobj2.h,
-	  UPGRADE.txt: main/astobj2: Make REF_DEBUG a menuselect item;
-	  improve REF_DEBUG output This patch does the following: (1) It
-	  makes REF_DEBUG a meneselect item. Enabling REF_DEBUG now enables
-	  REF_DEBUG globally throughout Asterisk. (2) The ref debug log
-	  file is now created in the AST_LOG_DIR directory. Every run will
-	  now blow away the previous run (as large ref files sometimes
-	  caused issues). We now also no longer open/close the file on each
-	  write, instead relying on fflush to make sure data gets written
-	  to the file (in case the ao2 call being performed is about to
-	  cause a crash) (3) It goes with a comma delineated format for the
-	  ref debug file. This makes parsing much easier. This also now
-	  includes the thread ID of the thread that caused ref change. (4)
-	  A new python script instead for refcounting has been added in the
-	  contrib/scripts folder. (5) The old refcounter implementation in
-	  utils/ has been removed. Review:
-	  https://reviewboard.asterisk.org/r/3377/ ........ Merged
-	  revisions 412114 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 412115 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 412153 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-11 01:12 +0000 [r412102]  Russell Bryant <russell at russellbryant.com>
-
-	* res/res_monitor.c: monitor: use app options parsing helper code
-	  This app is pretty ancient, so it was never converted to use the
-	  option parsing helper code. I'd like to add an option to this app
-	  that takes an argument, and that's a pain to do when not using
-	  this helper, so start by doing this conversion. Review:
-	  https://reviewboard.asterisk.org/r/3429/
-
-2014-04-10 21:28 +0000 [r412089]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_hep_pjsip.c: res_hep_pjsip: Use the channel name
-	  instead of the call ID when it is available During discussions
-	  with Alexandr Dubovikov at Kamailio World, it became apparent
-	  that while the SIP call ID is a useful identifier prior to an
-	  Asterisk channel being created, it is far more preferable to use
-	  the channel name (or some channel based identifier) when the
-	  channel is available. Homer is smart enough to tie the various
-	  messages together. This patch opts to use the channel name when
-	  it is available, falling back to the call ID otherwise. ........
-	  Merged revisions 412088 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-10 21:10 +0000 [r412075]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip_pubsub.c: res_pjsip_pubsub: Set the body
-	  generation result to 0 for a valid path The result of the
-	  "ast_sip_pubsub_generate_body_content" was not set/initialized.
-	  Consequently, the nominal path potentially returned an invalid
-	  value, thus not sending mwi notifications. ........ Merged
-	  revisions 412074 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-09 21:43 +0000 [r412050]  Mark Michelson <mmichelson at digium.com>
-
-	* /, CHANGES, apps/app_mixmonitor.c: Add a Command header to the
-	  AMI Mixmonitor action. This fixes a parsing error that occurred
-	  during the processing of the AMI action. The error did not result
-	  in MixMonitor itself misbehaving, but it could result in the AMI
-	  response not giving correct information back. The new header
-	  allows for one to specify a post-process command to run when
-	  recording finishes. Previously, in order to do this, the
-	  post-process command would have to be placed at the end of the
-	  Options: header. Patches: mixmonitor_command_2.patch by jhardin
-	  (License #6512) ........ Merged revisions 412048 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-09 18:17 +0000 [r412035]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_stasis_answer.c: res_stasis_answer: Add missing
-	  newlines ........ Merged revisions 412034 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-08 21:25 +0000 [r411946-411990]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/asterisk.c: Internal timing: Add notice that the -I and
-	  internal_timing option are no longer needed. Add notice messages
-	  during execution that the -I command line option and the
-	  astersik.conf internal_timing option are no longer needed. The
-	  internal timing functionality is now always enabled if there is a
-	  timing module loaded. NOTE: Since the command line options and
-	  the asterisk.conf config file are processed before the logging
-	  system is initialized, the messages are output to stderr. Change
-	  requested as a result of asterisk-dev list comments about the
-	  commit for ASTERISK-22846 that removed the -I and internal_timing
-	  options. Review: https://reviewboard.asterisk.org/r/3423/
-	  ........ Merged revisions 411964 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411974 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411985 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  That commit caused many tests in the testsuite to fail with alarming
+	  consequences, such as not sending DialBegin and DialEnd events, and
+	  giving incorrect hangup causes during calls.
 
-	* main/config.c, /: config: Fix CB_ADD_LEN() to work as originally
-	  intended. Fix a long standing bug in CB_ADD_LEN() behaving like
-	  CB_ADD(). ASTERISK-23546 #close Reported by: Walter Doekes
-	  ........ Merged revisions 411960 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411961 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411962 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  This commit reverts the previous commit and implements and alternate
+	  solution. This new solution involves only passing AST_CONTROL_RINGING
+	  frames across local channels if the local channel is in AST_STATE_RING.
+	  Otherwise, the frame does not traverse the local channels. By doing
+	  this, we can ensure that a playtones generator does not get started on
+	  the calling channel but rather is started on the local channel on which
+	  the ringing frame was initially indicated.
 
-	* apps/confbridge/conf_config_parser.c, /: app_confbridge: Fix
-	  confbridge.conf dsp_talking_threshold option setting wrong
-	  parameter. Fixed copy pasta error. ASTERISK-23545 #close Reported
-	  by: John Knott ........ Merged revisions 411944 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411945 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-08 14:49 +0000 [r411928]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip.c: res_pjsip: Ignore explicit transport
-	  configuration if a WebSocket transport is specified. This change
-	  makes it so if a transport is configured on an endpoint that is a
-	  WebSocket type the option will be ignored. In practice this is
-	  fine because the WebSocket transport can not create outgoing
-	  connections, it can only reuse existing ones. By ignoring the
-	  option the existing PJSIP logic for using the existing connection
-	  will be invoked and stuff will proceed. (closes issue
-	  ASTERISK-23584) Reported by: Rusty Newton ........ Merged
-	  revisions 411927 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-08 00:26 +0000 [r411897]  Russell Bryant <russell at russellbryant.com>
-
-	* funcs/func_periodic_hook.c: func_periodic_hook: List more modules
-	  as dependencies This module makes use of some existing Asterisk
-	  components. app_chanspy was already listed as a dependency. There
-	  are a few function modules used, as well, so list them.
-
-2014-04-07 20:41 +0000 [r411884]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip_pubsub.c: PJSIP: Ensure test event has new state
-	  The change that fixed the pubsub test event's use of a dangling
-	  pointer also changed when it was processed relative to the pjsip
-	  subscription state change processing. This change corrects the
-	  order of events while holding a reference to the pointer that was
-	  previously dangling. ........ Merged revisions 411883 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-07 16:15 +0000 [r411870]  Jonathan Rose <jrose at digium.com>
-
-	* main/manager_channels.c, /: AGI/Manager: Prevent multiple
-	  NewExten events during AGI application changes AGI applications
-	  would trigger NewExten events every time the state of the AGI
-	  application changed. This has historically not been the behavior
-	  and this behavior was introduced with a CDR patch. This patch
-	  corrects that. (closes issue ASTERISK-23390) Reported by:
-	  Benjamin Keith Ford Review:
-	  https://reviewboard.asterisk.org/r/3406/ ........ Merged
-	  revisions 411868 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-07 14:57 +0000 [r411812]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* apps/app_queue.c, /: app_queue: Re-add HoldTime to
-	  QueueCallerAbandon event (simple typo during ast12 refactor).
-	  Reported by: Ibrahim22 (on IRC) Tested by: Ibrahim22 ........
-	  Merged revisions 411811 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-07 14:29 +0000 [r411791-411806]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_stasis.c: Stasis: Fix Stasis() bridge refcount issue
-	  The Stasis() dialplan application monitors what bridge a channel
-	  is in and so necessarily holds on to a bridge pointer. This
-	  change ensures that it also holds on to a reference for that
-	  bridge to prevent the bridge pointer from becoming a dangling
-	  pointer. ........ Merged revisions 411804 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pubsub.c, /: PJSIP: Fix crash introduced in r411671
-	  The test event introduced in revision 411671 uses a dangling
-	  pointer to access information about pubsub state changes. This
-	  moves the event to within the lifetime of the pointer. ........
-	  Merged revisions 411790 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-05 13:06 +0000 [r411768]  Russell Bryant <russell at russellbryant.com>
-
-	* CHANGES, funcs/func_periodic_hook.c (added): func_periodic_hook:
-	  New function for periodic hooks. This commit introduces a new
-	  dialplan function, PERIODIC_HOOK(). It allows you run to a
-	  dialplan hook on a channel periodically. The original use case
-	  that inspired this was the ability to play a beep periodically
-	  into a call being recorded. The implementation is much more
-	  generic though and could be used for many other things. The
-	  implementation makes heavy use of existing Asterisk components.
-	  It uses a combination of Local channels and ChanSpy() to run some
-	  custom dialplan and inject any audio it generates into an active
-	  call. The other important bit of the implementation is how it
-	  figures out when to trigger the beep playback. This
-	  implementation uses the audiohook API, even though it's not
-	  actually touching the audio in any way. It's a convenient way to
-	  get a callback and check if it's time to kick off another beep.
-	  It would be nice if this was timer event based instead of polling
-	  based, but unfortunately I don't see a way to do it that won't
-	  interfere with other things. Review:
-	  https://reviewboard.asterisk.org/r/3362/
-
-2014-04-04 19:19 +0000 [r411702-411724]  Richard Mudgett <rmudgett at digium.com>
+	  ASTERISK-25250 #close
+	  Reported by Etienne Lessard
 
-	* include/asterisk/options.h, main/asterisk.c, main/channel.c, /,
-	  channels/chan_sip.c, configs/asterisk.conf.sample, UPGRADE.txt,
-	  include/asterisk/channel.h, utils/extconf.c: internal_timing:
-	  Remove the option and always make it enabled if a timing module
-	  is loaded. The masquerade supertest frequently fails because
-	  either the local channel chain doesn't completely optimize out or
-	  the DTMF handshake doesn't completely get accross. Local channel
-	  optimization requires frames flowing to trigger when optimization
-	  can happen. When optimization happens the media frame that
-	  triggered the optimization is dropped. Sending DTMF requires
-	  frames to flow in the other direction for timing purposes while
-	  sending nothing. If internal timing is not enabled when MOH is
-	  playing, Asterisk switches to received timing when an audio frame
-	  is received. With optimization dropping media frames and MOH not
-	  sending frames unless it receives frames, occasionaly there are
-	  no more frames being passed and the test fails. * The asterisk
-	  command line -I option and the asterisk.conf internal_timing
-	  option are removed. Asterisk now always uses internal timing when
-	  needed if any timing module is loaded. The issue ASTERISK-14861
-	  did this quite awhile ago in v1.4 but effectively is broken if
-	  other internal timing modules besides DAHDI are used. The
-	  ast_read_generator_actions() now only does received timing if it
-	  has no choice for frame generators like MOH, silence, and
-	  playback streaming. * Cleaned up some code dealing with frame
-	  generators in ast_deactivate_generator(),
-	  generator_write_format_change(), ast_activate_generator(), and
-	  ast_channel_stop_silence_generator(). * Removed
-	  ast_internal_timing_enabled(), AST_OPT_FLAG_INTERNAL_TIMING, and
-	  ast_opt_internal_timing. ASTERISK-22846 #close Reported by: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/3414/ ........
-	  Merged revisions 411715 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411716 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411717 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/utils.c, res/res_musiconhold.c, main/channel.c,
-	  main/stasis_cache.c, /: Add some asserts that were handy when
-	  looking for a stasis cache problem. * Assert if a channel is
-	  destroyed but has the snapshot staging flag set. In this case the
-	  final channel destruction snapshot would never get taken. *
-	  Assert if what we just got out of the stasis cache is not what we
-	  were looking for. This assert would have saved several days
-	  searching for a bug and a lot of my hair. * Assert if the music
-	  on hold message posts could not find the associated channel. A
-	  crash will happen later when manager tries to send the MOH AMI
-	  message. This assert catches the problem when the stasis message
-	  is posted instead of by the thread processing the defective
-	  message. * Always generate a backtrace when an ast_assert()
-	  fails. Review: https://reviewboard.asterisk.org/r/3411/ ........
-	  Merged revisions 411701 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-04 15:13 +0000 [r411688]  Matthew Jordan <mjordan at digium.com>
+	  Change-Id: I3bc87a18a38eb2b68064f732d098edceb5c19f39
 
-	* /, main/http.c: http: Fix spurious ERROR message in responses
-	  with no content When a response has a content length of 0, fwrite
-	  would be called to write a buffer with no data in it. This
-	  resulted in the following classic error message: [Apr 3 11:49:17]
-	  ERROR[26421] http.c: fwrite() failed: Success This patch makes it
-	  so that we only attempt to write out the content if the
-	  calculated content_length is non-zero. ........ Merged revisions
-	  411687 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-03 12:06 +0000 [r411671]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip_pubsub.c: res_pjsip_pubsub: Add test event for
-	  state change This adds a test event when subscription state
-	  changes so that integration tests may trigger new actions at the
-	  appropriate times. Review:
-	  https://reviewboard.asterisk.org/r/3383/ ........ Merged
-	  revisions 411670 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-03 11:47 +0000 [r411669]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_hep.c, /: res_hep: Fix crash when hep.conf not available
-	  Parts of res_hep properly checked for a valid configuration
-	  object before attempting to access the configuration. A check,
-	  however, was missed when a packet is sent. This patch fixes the
-	  crash caused by not checking if the configuration object is
-	  valid. ........ Merged revisions 411668 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-02 18:57 +0000 [r411656]  Mark Michelson <mmichelson at digium.com>
-
-	* main/sorcery.c, /, res/res_mwi_external.c,
-	  res/res_pjsip/config_system.c, configs/sorcery.conf.sample,
-	  main/bucket.c, include/asterisk/sorcery.h,
-	  res/res_pjsip/pjsip_configuration.c, tests/test_sorcery_astdb.c,
-	  tests/test_sorcery.c, tests/test_sorcery_realtime.c: Prevent
-	  duplicate sorcery wizards from being applied to sorcery object
-	  types. This commit contains several changes to sorcery: 1)
-	  Application of sorcery configuration based on module name is
-	  automatically performed when sorcery is opened for a module. 2)
-	  Sorcery will not attempt to apply the same wizard to an object
-	  type more than once. 3) Sorcery gives more exact results when
-	  attempting to apply a wizard, whether as the default or based on
-	  configuration. Sorcery unit tests still pass for me after making
-	  these changes. Review: https://reviewboard.asterisk.org/r/3326
-	  ........ Merged revisions 411159 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-01 22:42 +0000 [r411637-411639]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/parking/parking_bridge.c, /: res_parking: Minor tweaks. * Use
-	  ast_bridge_channel_lock()/ast_bridge_channel_unlock() instead of
-	  ao2_lock()/ao2_unlock() for struct ast_bridge_channel variables.
-	  * Use ast_copy_string() instead of inlining it. * Remove an
-	  already done TODO comment. * Some whitespace tweaks. ........
-	  Merged revisions 411638 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_channels.c, /: stasis_channels.c: Eliminate another
-	  overuse of RAII_VAR(). ........ Merged revisions 411636 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-04-01 16:52 +0000 [r411587]  Joshua Colp <jcolp at digium.com>
-
-	* /, apps/app_queue.c: app_queue: Fix a bug where realtime members
-	  would be deleted during reload causing waiting callers to get
-	  ejected. This patch causes realtime queue members to remain in
-	  queues during the reload process. Previously these members would
-	  be removed causing any waiting callers to be ejected from the
-	  queue with a reason of "EXITEMPTY". ASTERISK-23547 #close
-	  ASTERISK-23547 #comment Patch
-	  app_queue_fix_realtime_reload_1.8_trunk.patch submitted by Italo
-	  Rossi (license 6409) Review:
-	  https://reviewboard.asterisk.org/r/3404/ ........ Merged
-	  revisions 411584 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411585 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411586 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-28 18:32 +0000 [r411556]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/res_hep.h (added), res/res_hep_pjsip.c (added),
-	  res/res_hep.exports.in (added), configs/hep.conf.sample (added),
-	  CHANGES, res/res_hep.c (added), /: res_hep/res_hep_pjsip: Add a
-	  HEPv3 capture agent module and a logger for PJSIP This patch adds
-	  the following: (1) A new module, res_hep, which implements a
-	  generic packet capture agent for the Homer Encapsulation Protocol
-	  (HEP) version 3. Note that this code is based on a patch provided
-	  by Alexandr Dubovikov; I basically just wrapped it up, added
-	  configuration via the configuration framework, and threw in a
-	  taskprocessor. (2) A new module, res_hep_pjsip, which forwards
-	  all SIP message traffic that passes through the res_pjsip stack
-	  over to res_hep for encapsulation and transmission to a HEPv3
-	  capture server. Much thanks to Alexandr for his Asterisk patch
-	  for this code and for a *lot* of patience waiting for me to port
-	  it to 12/trunk. Due to some dithering on my part, this has taken
-	  the better part of a year to port forward (I still blame CDRs for
-	  the delay). ASTERISK-23557 #close Review:
-	  https://reviewboard.asterisk.org/r/3207/ ........ Merged
-	  revisions 411534 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-28 18:00 +0000 [r411533]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/ooh323c/src/ooh323.c, addons/ooh323c/src/ooGkClient.c,
-	  addons/chan_ooh323.c, /, addons/ooh323c/src/oochannels.c,
-	  addons/ooh323c/src/ooCmdChannel.c, addons/ooh323c/src/ooq931.c:
-	  process stack command even if gatekeeper client isn't register
-	  don't destroy gatekeeper client if it is not started don't
-	  destroy gatekeeper client in some sort of gatekeeper errors
-	  signal rtp create condition when call cleared before rtp
-	  structure created (closes issue ASTERISK-23460) Reported by:
-	  Dmitry Melekhov Patches: ASTERISK-23460-2.patch Tested by: Dmitry
-	  Melekhov ........ Merged revisions 411531 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411532 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-28 17:41 +0000 [r411515-411530]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/channels.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/endpoints.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/playbacks.json, UPGRADE.txt,
-	  rest-api/api-docs/sounds.json, rest-api/resources.json, CHANGES,
-	  include/asterisk/manager.h, rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/mailboxes.json,
-	  rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json: Update API versions and
-	  UPGRADE/CHANGES for 12.2.0 This patch does the following: * It
-	  updates the AMI version to 2.2.0 to indicate backwards compatible
-	  changes have been made since the last release * It updates the
-	  ARI version to 1.2.0 to indicate backwards compatible changes
-	  have been made since the last release * It updates the
-	  UPGRADE/CHANGES files with changes that were not mentioned
-	  ........ Merged revisions 411529 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* UPGRADE.txt, res/res_config_odbc.c: res_config_odbc: Fix for
-	  nullable integer columns and keyfield existence check in
-	  update_odbc. This patch fixes setting nullable integer columns to
-	  NULL instead of an empty string, which fails for PostgreSQL, for
-	  example. The current code is supposed to do so, but the check is
-	  broken. The patch also allows the first column in the list to be
-	  a nullable integer. Also, the check for existence of a mandatory
-	  column checked for the first column in the list instead of the
-	  key field lookup column. This patch fixes that issue as well.
-	  Finally, the compatibility option allow_empty_string_in_nontext,
-	  which was added to previous revisions to allow for some database
-	  backends with certain schemas to function, has been removed.
-	  Review: https://reviewboard.asterisk.org/r/3335 ASTERISK-23459
-	  #close ASTERISK-23351 #close (closes issue ASTERISK-23459)
-	  Reported by: zvision patches: res_config_odbc.diff uploaded by
-	  zvision (License 5755)
-
-2014-03-28 16:18 +0000 [r411469]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/tcptls.c, main/manager.c, /, main/http.c: http: response
-	  body often missing after specific request This patch works around
-	  a problem with the HTTP body being dropped from the response to a
-	  specific client and under specific circumstances: a) Client
-	  request comes from node.js user agent "Shred" via use of
-	  swagger-client library. b) Asterisk and Client are *not* on the
-	  same host or TCP/IP stack In testing this problem, it has been
-	  determined that the write of the HTTP body is lost, even if the
-	  data is written using low level write function. The only solution
-	  found is to instruct the TCP stack with the shutdown function to
-	  flush the last write and finish the transmission. See review for
-	  more details. ASTERISK-23548 #close (closes issue ASTERISK-23548)
-	  Reported by: Sam Galarneau Review:
-	  https://reviewboard.asterisk.org/r/3402/ ........ Merged
-	  revisions 411462 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411463 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411465 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-07-22 09:46 +0000 [525bbf7d4e]  Mark Michelson <mmichelson at digium.com>
 
-2014-03-28 15:48 +0000 [r411375-411460]  Matthew Jordan <mjordan at digium.com>
+	* Local channels: Do not block control -1 payloads.
 
-	* UPGRADE.txt, /: UPGRADE: Note IAX2 compatibility issue between
-	  1.4 and 1.8+ systems. ........ Merged revisions 411457 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411459 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* contrib/realtime/mysql/voicemail_messages.sql (removed),
-	  contrib/realtime/postgresql/realtime.sql (removed),
-	  contrib/realtime/mysql/voicemail_data.sql (removed),
-	  contrib/realtime/mysql/musiconhold.sql (removed),
-	  contrib/realtime/mysql/queue_log.sql (removed),
-	  contrib/realtime/mysql/voicemail.sql (removed),
-	  contrib/realtime/mysql/sippeers.sql (removed), /,
-	  contrib/realtime/mysql/iaxfriends.sql (removed),
-	  contrib/realtime/mysql/meetme.sql (removed): contrib/realtime:
-	  Remove empty SQL script files Since the relatime scripts are now
-	  managed by Alembic, the previous realtime scripts were previously
-	  removed. However, the removal process messed up, as the files
-	  were still in the repository. The contents were just empty. This
-	  removes the files from the tree. ........ Merged revisions 411442
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/sip/include/sip.h: chan_sip: Add MESSAGE request to
-	  allowed methods The allowed methods advertised by chan_sip did
-	  not previously note the MESSAGE request. Even in Asterisk 1.8, we
-	  do accept in-dialog MESSAGE requests; we should advertise that we
-	  support MESSAGE requests. ASTERISK-23504 #close ASTERISK-23504
-	  #comment Reported by: Martin Kontsek ASTERISK-23504 #comment
-	  Patch sip.h_patch.diff uploaded by Martin Kontsek (license 6587)
-	  Review: https://reviewboard.asterisk.org/r/3396/ ........ Merged
-	  revisions 411372 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411373 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411374 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Control frames with a -1 payload are used as a special signal to stop
+	  playtones generators on channels. This indication is sent both by
+	  app_dial as well as by ast_answer() when a call is answered in case any
+	  tones were being generated on a calling channel.
 
-2014-03-27 19:21 +0000 [r411312-411328]  Corey Farrell <git at cfware.com>
+	  This control frame type was made to stop traversing local channel pairs
+	  as an optimization, because it was thought that it was unnecessary to
+	  send these indications, and allowing such unnecessary control frames to
+	  traverse the local channels would cause the local channels to optimize
+	  away less quickly.
 
-	* funcs/func_global.c, apps/app_speech_utils.c,
-	  apps/confbridge/conf_config_parser.c,
-	  funcs/func_callcompletion.c, funcs/func_frame_trace.c,
-	  funcs/func_callerid.c, main/message.c, /, res/res_mutestream.c,
-	  channels/pjsip/dialplan_functions.c,
-	  res/res_pjsip_header_funcs.c, funcs/func_pitchshift.c,
-	  funcs/func_groupcount.c, funcs/func_volume.c, funcs/func_odbc.c,
-	  funcs/func_channel.c, funcs/func_cdr.c, funcs/func_blacklist.c,
-	  apps/app_stack.c, apps/app_voicemail.c, res/res_calendar.c,
-	  apps/app_jack.c, funcs/func_dialplan.c, funcs/func_speex.c,
-	  channels/chan_sip.c, funcs/func_math.c, funcs/func_strings.c,
-	  funcs/func_jitterbuffer.c, res/res_xmpp.c, channels/chan_iax2.c,
-	  main/features_config.c, res/res_jabber.c: Fix dialplan function
-	  NULL channel safety issues (closes issue ASTERISK-23391) Reported
-	  by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3386/ ........ Merged
-	  revisions 411313 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411314 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411315 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/format.c, include/asterisk.h, /: main/formats: Fix crash in
-	  ast_format_cmp during non-clean shutdown. * Update asterisk.h to
-	  reflect availability of ast_register_cleanup in 11.9. * Use
-	  ast_register_cleanup for format_attr_shutdown. (closes issue
-	  ASTERISK-23103) Reported by: JoshE ........ Merged revisions
-	  411310 from http://svn.asterisk.org/svn/asterisk/branches/11
-	  ........ Merged revisions 411311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-27 14:21 +0000 [r411296]  Mark Michelson <mmichelson at digium.com>
-
-	* main/sorcery.c, /: Give sorcery instances a reference to their
-	  wizards. On graceful shutdown, sorcery wizards are all killed
-	  off, but it is possible for sorcery instances to still have
-	  dangling pointers after this, possibly causing a crash. Giving
-	  the sorcery instances a reference to their wizards ensures that
-	  the wizard reference will remain valid for the lifetime of the
-	  sorcery instance. Review: https://reviewboard.asterisk.org/r/3401
-	  ........ Merged revisions 411295 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-26 22:45 +0000 [r411246]  Joshua Colp <jcolp at digium.com>
+	  As it turns out, through some special magic dialplan code, it is
+	  possible to have a tones being played on a non-local channel, and it is
+	  important for the local channel to convey that the tones should be
+	  stopped. The result of having tones continue to be played on the
+	  non-local channel is that the tones play even once the channel has been
+	  bridged. By not blocking the -1 control frame type, we can ensure that
+	  this situation does not happen.
 
-	* /, main/say.c: say: Fix a bug where SayNumber in Polish tries to
-	  play incorrect sound. This change fixes a bug where calling
-	  SayNumber with a number divisible by 100 using the Polish
-	  language would cause the code to attempt to play a sound file
-	  with an empty name. (closes issue ASTERISK-23509) Reported by:
-	  zvision Review: https://reviewboard.asterisk.org/r/3378/ ........
-	  Merged revisions 411243 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411244 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411245 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  ASTERISK-25250 #close
+	  Reported by Etienne Lessard
 
-2014-03-26 16:15 +0000 [r411194]  Jonathan Rose <jrose at digium.com>
+	  Change-Id: I40227e4249d6d61dc6a9b08bbe9ee3aa18be7e30
 
-	* /, channels/chan_sip.c, configs/sip.conf.sample: chan_sip: Send
-	  real CallerID information with P-Assserted-Identity (RFC-3325)
-	  Prior too this patch, the P-Asserted-Identity header would
-	  include anonymous caller id information which seems to go against
-	  the point of the P-Asserted-Identity header. Now the real caller
-	  ID information will be included in this header. Also, no privacy
-	  header would be included. This patch adds 'Privacy: id' to
-	  outgoing SIP messages that include the P-Asserted-Identity
-	  header. (closes issue AST-1301) ........ Merged revisions 411189
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 411190 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411193 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-26 16:05 +0000 [r411192]  Richard Mudgett <rmudgett at digium.com>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py:
-	  Fix 'alembic branches' merge conflict as described by the web
-	  page. ........ Merged revisions 411191 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-25 18:44 +0000 [r411174]  Sean Bright <sean at malleable.com>
-
-	* /, res/ari/config.c: ARI: Don't complain about missing ARI users
-	  when we aren't enabled Currently, if ARI is not enabled it will
-	  still complain that there are no configured users. This patch
-	  checks to see if ARI is enabled before logging and error or
-	  iterating the container to validate the users. Review:
-	  https://reviewboard.asterisk.org/r/3391/ ........ Merged
-	  revisions 411173 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-25 17:40 +0000 [r411158]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip/pjsip_configuration.c, UPGRADE.txt,
-	  res/res_pjsip_messaging.c, res/res_pjsip.c,
-	  include/asterisk/res_pjsip.h: Add a "message_context" option for
-	  PJSIP endpoints. ........ Merged revisions 411157 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-25 16:57 +0000 [r411142]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_pjsip/pjsip_options.c, res/res_pjsip.c,
-	  include/asterisk/res_pjsip.h, /: res_pjsip: Fix contact
-	  authenticate_qualify endpoint lookup when qualifing a contact. *
-	  Fixed bad use of ao2_find() in on_endpoint(). * Replaced use of
-	  find_endpoints() with find_an_endpoint() since only the first
-	  found endpoint is ever needed. * Fixed qualify_contact_cb() to
-	  update the contact with the aor authenticate_qualify setting.
-	  Otherwise, permanent contacts in the aor type sections would have
-	  a config line order dependancy. * Fixed off nominal path contact
-	  ref leak in qualify_contact(). The comment saying the unref is
-	  not needed was wrong. * Fixed off nominal path use of the
-	  endpoint parameter if it is NULL in send_out_of_dialog_request().
-	  * Added missing off nominal path unref of pjsip tdata in
-	  send_out_of_dialog_request(). * Fixed off nominal path failing to
-	  call the callback in send_request_cb() when the request is
-	  challenged for authentication. * Eliminated silly RAII_VAR() use
-	  in qualify_contact_cb(). * Updated ast_sip_send_request() doxygen
-	  to better reflect reality. (closes issue ASTERISK-23254) Reported
-	  by: rmudgett Review: https://reviewboard.asterisk.org/r/3381/
-	  ........ Merged revisions 411141 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-25 16:06 +0000 [r411092]  Kinsey Moore <kmoore at digium.com>
+2015-07-22 05:16 +0000 [5606da754a]  Joshua Colp <jcolp at digium.com>
 
-	* /, channels/chan_sip.c: chan_sip: Fix incorrect use of timers If
-	  update_provisional_keepalive() is called while
-	  send_provisional_keepalive_full() is waiting on the PVT lock,
-	  then pvt->provisional_keepalive_sched_id will be changed to a new
-	  sched_id value by update_provisional_keepalive(), but that new
-	  sched_id then may be overwritten with -1 by
-	  send_provisional_keepalive_full(), killing the pvt's reference to
-	  a schedule and "leaking" the reference. (closes issue
-	  ASTERISK-22079) Review: https://reviewboard.asterisk.org/r/3368/
-	  Reported by: Jamuel Starkey, Matteo, Leif Madsen, Steve Davies
-	  Patches: provisional_keepalive_fix.diff uploaded by Steve Davies
-	  (license 5012) ........ Merged revisions 411088 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411089 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411091 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* audiohook: Read the correct number of samples based on audiohook format.
 
-2014-03-25 15:56 +0000 [r411090]  Jonathan Rose <jrose at digium.com>
+	  Due to changes in audiohooks to support different sample rates the
+	  underlying storage of samples is in the format of the audiohook
+	  itself and not of the format being requested. This means that if a
+	  channel is using G722 the samples stored will be at 16kHz. If
+	  something subsequently reads from the audiohook at a format which
+	  is not the same sample rate as the audiohook the number of samples
+	  needs to be adjusted.
 
-	* /, res/res_stasis.c: ARI: Resolve a subscription leak against
-	  implicit bridge subscriptions When a channel in a stasis
-	  application is joined to a bridge, a subscription for that bridge
-	  is created implicitly for the stasis application serving the
-	  channel. Prior to this patch, subsequent removals of the channel
-	  from the bridge would leave the subscription open. Review:
-	  https://reviewboard.asterisk.org/r/3380/ ........ Merged
-	  revisions 411086 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Given the following example:
+	  1. Channel writing into audiohook at 16kHz (as it is using G722).
+	  2. Chanspy reading from audiohook at 8kHz.
 
-2014-03-25 15:47 +0000 [r411073-411087]  Richard Mudgett <rmudgett at digium.com>
+	  The original code would read 160 samples from the audiohook for
+	  each 20ms of audio. This is incorrect. Since the audio in the
+	  audiohook is at 16kHz the actual number needing to be read is 320.
+	  Failure to read this much would cause the audiohook to reset
+	  itself constantly as the buffer became full.
 
-	* utils/conf2ael.c, main/lock.c, utils/ael_main.c: Revert -r411073.
-	  It didn't help and blew up the system.
+	  This change adjusts the requested number of samples by determining
+	  the duration of audio requested and then calculating how many
+	  samples that would be in the audiohook format.
 
-	* utils/ael_main.c, utils/conf2ael.c, main/lock.c: locking: Add
-	  temporary sanity checks. Add some temporary sanity checks to hunt
-	  for locking problems with the masquerade supertest.
+	  ASTERISK-25247 #close
 
-2014-03-24 21:39 +0000 [r411024]  Joshua Colp <jcolp at digium.com>
+	  Change-Id: Ia91ce516121882387a315fd8ee116b118b90653d
 
-	* /, channels/chan_sip.c: chan_sip: Always use fromdomain if set
-	  for domain, even if callerid is set to restricted. (closes issue
-	  ASTERISK-20841) Reported by: Kelly Goedert ........ Merged
-	  revisions 411021 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 411022 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 411023 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2015-07-20 17:16 +0000 [43a52df20d]  Rusty Newton <rnewton at digium.com>
 
-2014-03-21 16:04 +0000 [r410996]  Richard Mudgett <rmudgett at digium.com>
+	* Documentation: chan_sip doesn't support WS or WSS in outbound register.
 
-	* /, res/res_pjsip_registrar.c: res_pjsip_registrar.c:
-	  Miscellaneous cleanup in rx_task(). * Fix variable shadowing of
-	  'updated' by renaming it to 'contact_update'. * Checked
-	  'contact_update' for ast_sorcery_copy() failure. * Removed silly
-	  use of RAII_VAR() for 'contact_update'. ........ Merged revisions
-	  410995 from http://svn.asterisk.org/svn/asterisk/branches/12
+	   * In sip.conf.sample fix sentence where we said that WS or WSS are supported
+	     transports for use in an outbound register definition. They are not
+	     supported in that case.
 
-2014-03-21 15:50 +0000 [r410981-410994]  Sean Bright <sean at malleable.com>
+	  ASTERISK-24853 #close
+	  Reported by: PSDK
 
-	* res/ael/ael.flex, utils/Makefile, pbx/pbx_ael.c,
-	  res/ael/ael_lex.c: Make the AEL load process less chatty.
-	  Switched a bunch of LOG_NOTICEs to ast_debug. This time without
-	  breaking the build.
+	  Change-Id: I3d698bc6302b9d00a0a995b5c4ad9a42d69b48ca
+2015-07-16 09:13 +0000 [bd6fd55ea4]  Michael Cargile <mikec at vicidial.com>
 
-	* pbx/pbx_ael.c, res/ael/ael_lex.c, res/ael/ael.flex: Revert
-	  r410981. aelparse blew up.
+	* res/res_musiconhold: Add a warning when MOH does not exist
 
-	* main/config.c: Remove a LOG_NOTICE from
-	  ast_config_engine_register. There is enough indication from the
-	  CLI that we are loading a realtime engine as it is.
+	  Change-Id: Ifdfbd0b97cf31478d29923ec30aabce28d01740b
 
-	* pbx/pbx_ael.c, res/ael/ael_lex.c, res/ael/ael.flex: Make the AEL
-	  load process less chatty. Switched a bunch of LOG_NOTICEs to
-	  ast_debug.
+2015-07-17 04:59 +0000 [0433f08903]  Patric Marschall <patric.marschall at 1und1.de>
 
-2014-03-20 23:02 +0000 [r410967]  Jonathan Rose <jrose at digium.com>
+	* sig_pri.h: force_restart_unavailable_chans in wrong scope
 
-	* apps/app_confbridge.c, /: app_confbridge: Fix bug - users with
-	  startmuted set don't start muted (closes issue ASTERISK-23461)
-	  Reported by: Chico Manobela Review:
-	  https://reviewboard.asterisk.org/r/3373/ ........ Merged
-	  revisions 410965 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410966 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-20 16:35 +0000 [r410950]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/rtp_engine.h, main/dial.c, main/manager.c, /,
-	  main/channel_internal_api.c, main/core_unreal.c,
-	  include/asterisk/channel.h, res/ari/resource_channels.c,
-	  res/res_stasis_snoop.c: assigned-uniqueids: Miscellaneous cleanup
-	  and fixes. * Fix memory leak in ast_unreal_new_channels(). Made
-	  it generate the ;2 uniqueid on a stack variable instead of
-	  mallocing it. * Made send error response to ARI and AMI requests
-	  instead of just logging excessive uniqueid length and allowing
-	  truncation. action_originate() and
-	  ari_channels_handle_originate_with_id(). * Fixed minor truncating
-	  uniqueid hole when generating the ;2 uniqueid string length.
-	  Created public and internal lengths of uniqueid. The internal
-	  length can handle a max public uniqueid plus an appended ;2. *
-	  free() and ast_free() are NULL tolerant so they don't need a NULL
-	  test before calling. * Made use better struct initialization
-	  format instead of the position dependent initialization format.
-	  Also anything not explicitly initialized in the struct is
-	  initialized to zero by the compiler. * Made
-	  ast_channel_internal_set_fake_ids() use the safer
-	  ast_copy_string() instead of strncpy(). Review:
-	  https://reviewboard.asterisk.org/r/3371/ ........ Merged
-	  revisions 410949 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-19 17:27 +0000 [r410934]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c: PJSIP: Allow for
-	  identify sections to be specified in sorcery.conf. "identify" is
-	  a special type of configuration object in PJSIP because unlike
-	  the other objects, it is not provided by the base res_pjsip
-	  module. Instead, it is provided by the
-	  res_pjsip_endpoint_identifier_ip module. If using the default
-	  sorcery wizard (config,criteria=type=identify) then things work
-	  because the module that applies the default wizard is the correct
-	  module. However, if attempting to use sorcery.conf to apply an
-	  alternate wizard, it was not possible. If you attempted to
-	  specify the identify object type in the res_pjsip section, then
-	  the object could not be registered since the object was
-	  undocumented for the res_pjsip module. There was no alternate
-	  configuration section defined for it, so you were out of luck if
-	  you wanted to override the default wizard. With this change, the
-	  identify section will properly have a sorcery.conf-based wizard
-	  applied when the identify definition is within the
-	  res_pjsip_endpoint_identifier_ip section. ........ Merged
-	  revisions 410933 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-19 14:25 +0000 [r410905-410919]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_stasis.c, /: res_stasis: Fix a bug where the default
-	  bridge type was not set. ........ Merged revisions 410918 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* CHANGES, res/res_stasis.c, rest-api/api-docs/bridges.json, /,
-	  res/ari/resource_bridges.h: res_stasis: Extend bridge type to be
-	  a comma separated list of bridge attributes. This change turns
-	  the bridge type field into a comma separated list of attributes.
-	  These attributes include: mixing, holding, dtmf_events, and
-	  proxy_media. By setting the various attributes a user can control
-	  the type of bridge created with the behavior they need for their
-	  application. (closes issue ASTERISK-23437) Reported by: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/3359/ ........
-	  Merged revisions 410904 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-19 02:33 +0000 [r410891]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_ari.c, /: res_ari: Fix documentation schema error
-	  ........ Merged revisions 410890 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 23:32 +0000 [r410877]  Rusty Newton <rnewton at digium.com>
-
-	* res/res_ari.c, /: res_ari: Add notes about Asterisk HTTP server
-	  to the "enabled" config option for the res_ari general section
-	  Added note and see-also reminding user to enable the HTTP server.
-	  (closes issue ASTERISK-22499) Reported by: Rusty Newton ........
-	  Merged revisions 410876 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 15:45 +0000 [r410863]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, main/http.c: ARI: allow json content type with zero length
-	  body When a request was received with a Content-type of json, the
-	  body was sent for json parsing - even if it was zero length. This
-	  resulted in ARI requests failing that were valid, such as a
-	  channel DELETE with no parameters. The code has now been changed
-	  to skip json parsing with zero content length. (closes issue
-	  SWP-6748) Reported by: Samuel Galarneau Review:
-	  https://reviewboard.asterisk.org/r/3360/ ........ Merged
-	  revisions 410858 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 15:28 +0000 [r410862]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: cdr: Add asserts for when we don't know about a
-	  CDR for a channel In the CDR core, every channel should either be
-	  filtered out (due to being an 'internal' channel used as an
-	  implementation detail, such as playing media back into a bridge)
-	  or it should get a CDR. Even if that CDR ends up being discarded,
-	  we still give the channel a CDR in case we end up needing it. If
-	  we hit a situation where a channel does not have a CDR, we should
-	  blow up in -dev-mode. Asserts are appropriate for that. This
-	  patch adds those asserts, as they would have quickly caught the
-	  error fixed by r410814. ........ Merged revisions 410861 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 12:45 +0000 [r410845]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/config_system.c: res_pjsip: Fix memory leak of
-	  nameservers in off-nominal resolver creation failure. Thanks
-	  Walter Doekes! ........ Merged revisions 410844 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 11:52 +0000 [r410831]  Sean Bright <sean at malleable.com>
-
-	* res/res_fax_spandsp.c, /: res_fax_spandsp: Use g711_free() when
-	  available. Per Johann Steinwendtner on the asterisk-dev mailing
-	  list:
-	  http://lists.digium.com/pipermail/asterisk-dev/2014-March/066102.html
-	  g711_free() was introduced in spandsp 0.0.6pre4 and
-	  g711_release() became a noop. I opted not to remove the call to
-	  g711_release() since it is harmless and to call g711_free() if we
-	  have a sufficiently recent version of spandsp. (issue
-	  ASTERISK-20149) Reported by: Alexandr Gordeev ........ Merged
-	  revisions 410829 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410830 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-18 02:09 +0000 [r410814]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/stasis_cache.c, /: stasis_cache: Use the right variable in
-	  the cache entry ao2 cmp function. ........ Merged revisions
-	  410813 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-17 22:54 +0000 [r410794-410796]  Joshua Colp <jcolp at digium.com>
-
-	* include/asterisk/dns.h, CHANGES,
-	  res/res_pjsip/include/res_pjsip_private.h, res/res_pjsip.c,
-	  main/dns.c, /, res/res_pjsip/config_system.c: res_pjsip: Enable
-	  PJSIP DNS client support. This change enables DNS client support
-	  within PJSIP. System nameservers are automatically discovered
-	  using res_init or res_ninit. If this fails then PJSIP will resort
-	  to using gethostbyname for resolution. By enabling this support
-	  we gain SRV support, failover, and weight support. (closes issue
-	  ASTERISK-23435) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3343/ ........ Merged
-	  revisions 410795 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_multihomed.c, /: res_pjsip_multihomed: Make address
-	  replacement less aggressive. This change makes the
-	  res_pjsip_multihomed module less aggressive when changing the
-	  address in messages. It will now only occur if the transport in
-	  use is bound to the any address OR if the system determined
-	  source address matches the bound address of the transport in use.
-	  Review: https://reviewboard.asterisk.org/r/3369/ ........ Merged
-	  revisions 410793 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-17 22:24 +0000 [r410775]  Russ Meyerriecks <rmeyerreicks at digium.com>
+	  In channels/sig_pri.h, struct sig_pri_span, the field
+	  force_restart_unavailable_chans is only defined if
 
-	* /, main/callerid.c: callerid: Logic error in checksum processing
-	  Callerid checksum-ing was being handled incorrectly here. When
-	  the checksum is calculated to be 0x00, it will perform 0x100-0x00
-	  which results in 0x100. This value will then fail the otherwise
-	  correct callerid message. This patch changes the logic to simply
-	  add the calculated checksum to the transmitted 2's compliment
-	  checksum. Review: https://reviewboard.asterisk.org/r/3356/
-	  (closes issue ASTERISK-23488) ........ This is a merge of merged
-	  revisions 410750 410747 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12 I didn't want a
-	  broken patch to be comitted to trunk so I pre-merge merged them.
-
-2014-03-17 19:35 +0000 [r410684-410699]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_mwi_external.c, res/res_pjsip/config_system.c,
-	  configs/sorcery.conf.sample, include/asterisk/sorcery.h,
-	  res/res_pjsip/pjsip_configuration.c, tests/test_sorcery_astdb.c,
-	  tests/test_sorcery.c, tests/test_sorcery_realtime.c,
-	  main/sorcery.c, /: Revert changes to sorcery that accidentally
-	  got committed. These changes were still up for review and have
-	  not been approved yet. I must have had the changes in my working
-	  copy when making a different change. ........ Merged revisions
-	  410696 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* bridges/bridge_softmix.c, tests/test_sorcery.c, main/channel.c,
-	  res/res_pjsip/config_system.c, res/res_mwi_external.c,
-	  include/asterisk/bridge_channel.h, funcs/func_frame_trace.c,
-	  configs/sorcery.conf.sample, res/res_pjsip/pjsip_configuration.c,
-	  include/asterisk/sorcery.h, tests/test_sorcery_astdb.c,
-	  include/asterisk/frame.h, main/bridge_channel.c,
-	  tests/test_sorcery_realtime.c, main/sorcery.c,
-	  res/res_stasis_playback.c, main/frame.c, /: Fix stuck channel in
-	  ARI through the introduction of synchronous bridge actions.
-	  Playing back a file to a channel in an ARI bridge would attempt
-	  to wait until the playback concluded before returning. The method
-	  used involved signaling the waiting thread in the ARI custom
-	  playback function. The problem with this is that there were some
-	  corner cases that were not accounted for: * If a bridge channel
-	  could not be found, then we never would attempt the playback but
-	  would still attempt to wait for the playback to complete. * If
-	  the bridge playfile action failed to queue, we would still
-	  attempt to wait for the playback to complete. * If the bridge
-	  playfile action were queued but some circumstance caused the
-	  playback not to occur (the bridge dies, the channel is removed
-	  from the bridge), then we would never be notified. The solution
-	  to this is to move the waiting logic into the bridge code. A new
-	  bridge API function is added to queue a synchronous action on a
-	  bridge. The waiting thread is notified when the queued frame has
-	  been freed, either due to an error occurring or due to successful
-	  playback. As a failsafe, the waiting thread has a 10 minute
-	  timeout just in case there is a frame leak somewhere. Review:
-	  https://reviewboard.asterisk.org/r/3338 ........ Merged revisions
-	  410673 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-17 16:48 +0000 [r410672]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, apps/confbridge/conf_chan_announce.c: app_confbridge: Add
-	  missing destructor call to announcer channel destructor. ........
-	  Merged revisions 410671 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-16 20:27 +0000 [r410651]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/stasis/app.c: stasis/app.c: Add some extra debugging for
-	  subscription counts Events are sent to a connected ARI
-	  application based on the things that ARI application cares about.
-	  These subscriptions can be set up implicitly - such as when that
-	  ARI application creates a new object - or explicitly, via the
-	  application resource's subscription operations. Debugging *why*
-	  something was being sent to an application - or why something was
-	  not being sent to an application - was a bit tricky, as there was
-	  no debug information for the subscriptions. This patch adds some
-	  debug level 3 statements that show the subscription counts for
-	  applications. (Level 3 was chosen as it matches the verbose level
-	  3 statements elsewhere) ........ Merged revisions 410650 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-15 15:24 +0000 [r410639]  Russell Bryant <russell at russellbryant.com>
-
-	* include/asterisk/framehook.h: framehook.h: Fix some doc typos.
-	  There were a number of instances in this header file where
-	  "function all" was intended to be "function call". This patch
-	  fixes that up.
-
-2014-03-14 21:56 +0000 [r410626]  Mark Michelson <mmichelson at digium.com>
-
-	* /, tests/test_sorcery_realtime.c: Fix failing realtime sorcery
-	  tests. The store realtime callback needs to return a positive
-	  value for sorcery to treat the store as a success. ........
-	  Merged revisions 410625 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 21:36 +0000 [r410624]  Jonathan Rose <jrose at digium.com>
-
-	* main/manager.c, /: manager: fix memory leak in manager_add_filter
-	  function (closes issue ASTERISK-23420) Reported by: Etienne
-	  Lessard Patches: manager_eventfilter_leak uploaded by Etienne
-	  Lessard (license 6394) ........ Merged revisions 410609 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410623 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 20:55 +0000 [r410591-410608]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/db.c: Remove an extra ast_cond_wait() that slipped
-	  through the patch. ........ Merged revisions 410606 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410607 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/config.c, res/res_sorcery_realtime.c: Handle the return
-	  values of realtime updates and stores more accurately. Realtime
-	  backends' update and store callbacks return the number of rows
-	  affected, or -1 if there was a failure. There were a couple of
-	  issues: * The config API was treating 0 as a successful return,
-	  and positive values as a failure. Now the config API treats
-	  anything >= 0 as a success. * res_sorcery_realtime was treating 0
-	  as a successful return from the store procedure, and any positive
-	  values as a failure. Now sorcery treats anything > 0 as a
-	  success. It still considers 0 a "failure" since there is no
-	  change to report to observers. Review:
-	  https://reviewboard.asterisk.org/r/3341 ........ Merged revisions
-	  410592 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_mwi.c: Prevent conflicts regarding unsolicited
-	  and solicited MWI to an endpoint. If an endpoint is receiving
-	  unsolicited MWI for a mailbox and then attempts to subscribe to
-	  an AOR that provides MWI for the same mailbox, then the SUBSCRIBE
-	  is rejected with a 500 response. Review:
-	  https://reviewboard.asterisk.org/r/3345 ........ Merged revisions
-	  410590 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 17:56 +0000 [r410589]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, CHANGES: uniqueid: Update CHANGES to reflect new features Note
-	  the new features provided by uniqueid in the CHANGES file. (issue
-	  ASTERISK-23120) Review: https://reviewboard.asterisk.org/r/3316/
-	  ........ Merged revisions 410588 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 16:42 +0000 [r410575]  Jonathan Rose <jrose at digium.com>
-
-	* /, main/acl.c, res/res_pjsip/pjsip_configuration.c,
-	  contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py,
-	  CHANGES, res/res_pjsip/config_transport.c,
-	  include/asterisk/acl.h: PJSIP: TOS values should be represented
-	  as decimals in sorcery objects (closes issue ASTERISK-23235)
-	  Reported by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3324/ ........ Merged
-	  revisions 410574 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 16:19 +0000 [r410567]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/db.c: Prevent delayed astdb syncs. The syncing thread
-	  sleeps for a second before waiting to be told to attempt to sync
-	  again. If a signal were sent during this sleeping period, we
-	  would end up having to wait until the next sync signal occurred
-	  in order to sync up the astdb. This code rearrangement also
-	  ensures that any pending transactions will be synced prior to
-	  Asterisk shutting down. Patches: db_sync.patch by John Hardin
-	  (License #6512) ........ Merged revisions 410556 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410559 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 16:17 +0000 [r410560]  Jonathan Rose <jrose at digium.com>
-
-	* res/ari/resource_bridges.c, /: ARI/bridges: Forward
-	  Playback/Recording Started/Finished to bridge topic (closes issue
-	  ASTERISK-23444) Reported by: Ben Merrills Review:
-	  https://reviewboard.asterisk.org/r/3340/ ........ Merged
-	  revisions 410558 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-14 16:01 +0000 [r410542-410557]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/app.h, /, res/res_mwi_external.c, main/app.c:
-	  res_mwi_external: Clear the stasis cache entry when the external
-	  MWI is deleted. One of the things missing when external MWI
-	  support was added was the ability to clear the stasis cache entry
-	  of deleted external MWI mailboxes. Review:
-	  https://reviewboard.asterisk.org/r/3325/ ........ Merged
-	  revisions 410555 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/cdr.c: cdr.c: Add missing aow_unlock(cdr) in off nominal
-	  path of handle_dial_message(). * Trivial common code hoisting in
-	  handle_bridge_leave_message(). * Some whitespace fixing. ........
-	  Merged revisions 410541 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-13 19:33 +0000 [r410528]  Kinsey Moore <kmoore at digium.com>
-
-	* res/stasis/control.h, res/res_stasis.c, /, res/stasis/control.c:
-	  ARI: Ensure managing application receives ChannelEnteredBridge
-	  messages This fixes an issue where a Stasis application running
-	  over ARI and subscribed to ari/events could miss the
-	  ChannelEnteredBridge event because it did not subscribe to the
-	  new bridge fast enough. To accomplish this, it subscribes the
-	  application controlling the channel to the new bridge before
-	  adding it to that bridge which required the stasis_app_control
-	  structure to maintain a reference to the stasis_app. (closes
-	  issue ASTERISK-23295) Review:
-	  https://reviewboard.asterisk.org/r/3336/ ........ Merged
-	  revisions 410527 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-13 13:25 +0000 [r410511]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_multihomed.c, /: Multiple revisions 410509-410510
-	  ........ r410509 | file | 2014-03-13 06:23:14 -0700 (Thu, 13 Mar
-	  2014) | 2 lines res_pjsip_multihomed: Fix a bug where the 200 OK
-	  for a REGISTER would contain the wrong contact. ........ r410510
-	  | file | 2014-03-13 06:24:17 -0700 (Thu, 13 Mar 2014) | 2 lines
-	  res_pjsip_multihomed: Remove change for testing fix. ........
-	  Merged revisions 410509-410510 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-12 19:06 +0000 [r410492-410494]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_musiconhold.c, main/channel.c, /: res_musiconhold.c:
-	  Generate MOH start/stop events whenever the MOH stream is
-	  started/stopped. * Made res_musiconhold.c always post the
-	  MusicOnHoldStart/MusicOnHoldStop events when it actually
-	  starts/stops the music streams. This allows the events to always
-	  happen when MOH starts/stops. The event posting code was moved to
-	  the MOH alloc/release routines. * Made channel_do_masquerade()
-	  stop any MOH on the original channel before masquerading so the
-	  original channel will get a stop event with correct information.
-	  * Cleaned up a couple odd codings in moh_files_alloc() and
-	  moh_alloc() dealing with the music state variable. (issue
-	  ASTERISK-23311) Reported by: Benjamin Keith Ford Review:
-	  https://reviewboard.asterisk.org/r/3306/ ........ Merged
-	  revisions 410493 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  #if defined(HAVE_PRI_MCID) is true.
 
-	* apps/confbridge/conf_state.c,
-	  apps/confbridge/conf_state_single.c,
-	  apps/confbridge/conf_state_inactive.c,
-	  apps/confbridge/conf_state_single_marked.c, /: app_confbridge:
-	  Make explicitly stop MOH if a user is kicked or hangs up while
-	  MOH is playing. When MOH is playing to a user in a conference and
-	  the user is kicked or hangs up from the conference then the AMI
-	  MusicOnHoldStop events didn't happen. (Asterisk v11 AMI event:
-	  MusicOnHold, state:Stop) (closes issue ASTERISK-23311) Reported
-	  by: Benjamin Keith Ford Review:
-	  https://reviewboard.asterisk.org/r/3306/ ........ Merged
-	  revisions 410490 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410491 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-12 12:51 +0000 [r410452-410472]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_multihomed.c, /: res_pjsip_multihomed: Fix a bug
-	  where outgoing messages for TCP would go out using UDP. This
-	  change fixes a bug where the code which changes the transport did
-	  not check whether the message is going out over UDP or not before
-	  changing it. For TCP and TLS transports we don't need to change
-	  the transport as the correct one is already chosen. ........
-	  Merged revisions 410471 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_multihomed.c (added), /: res_pjsip_multihomed: Add
-	  module which places the correct address within messages. Due to
-	  how messages are handled within PJSIP it is not until a message
-	  is actually sent that the destination is reliably known. This
-	  means that the addresses placed within the message may not be of
-	  the interface the message is being sent out on. This module
-	  determines what interface a message is being sent on and updates
-	  the message to contain the correct address if applicable. This
-	  module was tested by myself in a virtualized environment with
-	  multiple interfaces and also by Kinsey Moore in the following
-	  configuration: Networks: * 10.24.16.0/21 ** hard phone ** default
-	  gateway * 10.24.64.0/21 ** softphone with pjsip-based stack
-	  Transport details: bind address: 0.0.0.0 protocol: UDP All
-	  endpoints were tested with explicitly configured transports and
-	  unconfigured transports. This was tested with inbound and
-	  outbound calls, both of which were experiencing detrimental
-	  effects from incorrect IP addresses in SIP messages. These
-	  effects were only experienced by the soft phone on the 10.24.64.0
-	  network since the messages to the hard phone on the 10.24.16.0
-	  network had the correct IP address. (closes issue ASTERISK-23020)
-	  Reported by: xrobau Review:
-	  https://reviewboard.asterisk.org/r/3102/ ........ Merged
-	  revisions 410451 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-10 17:21 +0000 [r410395]  Richard Mudgett <rmudgett at digium.com>
+	  All other occurences of force_restart_unavailable_chans are outside of the
 
-	* /, main/http.c: AST-2014-001: Stack overflow in HTTP processing
-	  of Cookie headers. Sending a HTTP request that is handled by
-	  Asterisk with a large number of Cookie headers could overflow the
-	  stack. Another vulnerability along similar lines is any HTTP
+	  #if defined(HAVE_PRI_MCID)
+	  endif
+
+	  scope.
+
+	  ASTERISK-25257 #close
+	  Reported by: Patric Marschall
+
+	  Change-Id: I071de89cc2cd0d85927a013036e235851f672549
+2015-07-15 10:31 +0000 [b36d670dc1]  Matt Jordan <mjordan at digium.com>
+
+	* apps/app_dictate: Fix typo in attribution
+
+	  Last time I checked, it's "Sangoma", not "Samgoma". Thanks to Brian
+	  (GameGamer43) for pointing that out.
+
+	  Change-Id: I43d7b196f6d7a2b2517b84915e3a8dfbc2894106
+
+2015-06-27 17:53 +0000 [883f6f5d21]  Matt Jordan <mjordan at digium.com>
+
+	* tests/test_devicestate: Add additional tests for the device state API
+
+	  This patch adds more tests that exercise the device state API. This includes:
+
+	  * Tests that cover adding a device state provider, as well as deleting a
+	    device state provider. This also verifies that you cannot add an
+	    already added device state provider, and cannot delete an already
+	    deleted device state provider.
+	  * A test that covers changing device state and receiving said updates
+	    from a device state subscriber. This also covers hitting both the
+	    device state cache as well as a custom device state provider.
+	  * A test that covers converting device state to channel state and device
+	    state values to a string representation and back.
+	  * A test that covers obtaining device state from an active channel and a
+	    channel driver that provides its own device state.
+
+	  Change-Id: I2adca67ffb405cd8625a5d6df1e3f9b3d945c08d
+
+2015-06-27 17:51 +0000 [e545c05e35]  Matt Jordan <mjordan at digium.com>
+
+	* main/devicestate: Prevent duplicate registration of device state providers
+
+	  Currently, the device state provider API will allow you to register a
+	  device state provider with the same case insensitive name more than
+	  once. This could cause strange issues, as the duplicate device state
+	  providers will not be queried when a device's state has to be polled.
+	  This patch updates the API such that a device state provider with the
+	  same name as one that has already registered will be rejected.
+
+	  Change-Id: I4a418a12280b7b6e4960bd44f302e27cd036ceb2
+
+2015-07-08 04:21 +0000 [47ebab959e]  Joshua Colp <jcolp at digium.com>
+
+	* res_rtp_asterisk: Ensure DTLS timeout timer is -1 if DTLS is not used.
+
+	  This change fixes a bug where the DTLS timeout timer would be
+	  initialized to 0 if DTLS was not used for an RTP session.
+
+	  ASTERISK-25103
+
+	  Change-Id: If8d26bb054f1d300838850da5b8db9044c2fe2ac
+
+2015-07-01 07:55 +0000 [1ad827327a]  Joshua Colp <jcolp at digium.com>
+
+	* res_rtp_asterisk: Prevent simultaneous access to DTLS SSL context.
+
+	  This change moves logic for setting up the DTLS SSL contexts to
+	  when the SDP is done being processed instead of when ICE negotiation
+	  completes. It also stops handshakes from being initiated when we
+	  are acting as a server.
+
+	  Manipulating the SSL context when ICE negotiation has completed
+	  is problematic as the SSL context is not protected and if acting
+	  as a client the remote side may have started DTLS negotiation
+	  already.
+
+	  The retransmission timeout timer code has also been split up
+	  and simplified some. Both RTP and RTCP now have their own timers
+	  and the points at which the timer is stopped and started is now
+	  more specific. When a packet is sent the timer is started. When
+	  a response is received but before it is processed the timer is
+	  stopped. This provides a guarantee that the timeout is not
+	  occurring while the response is processed.
+
+	  ASTERISK-22805 #close
+	  ASTERISK-24550 #close
+	  ASTERISK-24651 #close
+	  ASTERISK-24832 #close
+	  ASTERISK-25103 #close
+	  ASTERISK-25127 #close
+
+	  Change-Id: Ib75ea2546f29d6efc3d2d37c58df6986c7bd9b91
+
+2015-07-02 06:25 +0000 [0e6d3f5ee5]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* chan_sip: Fix early call pickup caused deadlock.
+
+	  If non-magic pickup (no "pickup-" in callid) is used, chan_sip locks the
+	  channel it wants to pick up, and a bit further down, it locks the
+	  channel list when allocating a new channel.
+
+	  That causes a deadlock when another part of the code traverses over the
+	  channel list, locking all the channels one by one.
+
+	  This changeset fixes it by releasing the locks before calling sip_new
+	  and reacquiring them afterwards.  Unfortunately this involves doing the
+	  checks we already did again (because the channel may have changed).
+
+	  While trying to avoid duplicate code, I did some refactoring for
+	  readability:
+	  - if refer_locked == 1, we guarantee there is a locked channel
+	  - magic_callid holds a cached version of !ast_strlen_zero(pickup.exten)
+
+	  This is for branch 11 only. It appears that the changed code in 13 does
+	  not lock the components like it does in 11 and below. Reproducing the
+	  deadlock on 13 has thusfar failed.
+
+	  ASTERISK-25213 #close
+
+	  Change-Id: Ie1d15bec7d634035f48892e1ed6227411d7de2c1
+2015-07-02 06:19 +0000 [f6bbc4f16e]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* chan_mgcp: Don't call close on fd -1.
+
+	  ASTERISK-25220 #close
+
+	  Change-Id: Ic48f3a82f51ada87f2fb0e016c9efe0ad56f1ee3
+
+2015-07-02 06:10 +0000 [c139956e95]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* rtp_engine: Skip useless self-assignment in ast_rtp_engine_unload_format.
+
+	  When running valgrind on Asterisk, it complained about:
+
+	      ==32423== Source and destination overlap in memcpy(0x85a920, 0x85a920, 304)
+	      ==32423==    at 0x4C2F71C: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/...)
+	      ==32423==    by 0x55BA91: ast_rtp_engine_unload_format (rtp_engine.c:2292)
+	      ==32423==    by 0x4EEFB7: ast_format_attr_unreg_interface (format.c:1437)
+
+	  The code in question is a struct assignment, which may be performed by
+	  memcpy as a compiler optimization. It is changed to only copy the struct
+	  contents if source and destination are different.
+
+	  ASTERISK-25219 #close
+
+	  Change-Id: I6d3546c326b03378ca8e9b8cefd41c16e0088b9a
+
+2015-07-02 05:16 +0000 [028554faab]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* astfd: Fix buffer overflow in DEBUG_FD_LEAKS.
+
+	  If DEBUG_FD_LEAKS was used and more file descriptors than the default of
+	  1024 were available, some DEBUG_FD_LEAKS-patched functions would
+	  overwrite memory past the fixed-size (1024) fdleaks buffer.
+
+	  This change:
+	  - adds bounds checks to __ast_fdleak_fopen and __ast_fdleak_pipe
+	  - consistently uses ARRAY_LEN() instead of sizeof() or 1023 or 1024
+	  - stores pointers to constants instead of copying the contents
+	  - reorders the fdleaks struct for possibly tighter packing
+	  - adds a tiny bit of documentation
+
+	  ASTERISK-25212 #close
+
+	  Change-Id: Iacb69e7701c0f0a113786bd946cea5b6335a85e5
+
+2015-07-02 04:57 +0000 [b090a8d40b]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* res_timing: Don't close FD 0 when out of open files.
+
+	  This fixes so a failure to get a timer file descriptor does not cascade
+	  to closing FD 0.
+
+	  On error, both res_timing_kqueue and res_timing_timerfd would call the
+	  destructor before setting the file handle. The file handle had been
+	  initialized to 0, causing FD 0 to be closed. This in turn, resulted in
+	  floods of "CLI>" messages and an unusable terminal.
+
+	  ASTERISK-19277 #close
+	  Reported by: Barry Chern
+
+	  Change-Id: I147d7e33726c6e5a2751928d56561494f5800350
+
+2015-07-01 17:25 +0000 [1e186dc857]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_vpb.cc: Fix compiler warning Jenkins found.
+
+	  Change-Id: I0ec7fd10d56d90d5a60b12b5a7d6807f265ac5e0
+
+2015-07-01 13:34 +0000 [8874d5fc94]  Scott Griepentrog <scott at griepentrog.com>
+
+	* Channel alert pipe: improve diagnostic error return
+
+	  When a frame is queued on a channel, any failure in
+	  ast_channel_alert_write is logged along with errno.
+
+	  This change improves the diagnostic message through
+	  aligning the errno value with actual failure cases.
+
+	  ASTERISK-25224
+	  Reported by: Andrey Biglari
+
+	  Change-Id: I1bf7b3337ad392789a9f02c650589cd065d20b5b
+
+2015-06-27 18:47 +0000 [9b74dcb687]  Matt Jordan <mjordan at digium.com>
+
+	* Makefile: Remove coverage files on 'make clean'
+
+	  This patch updates a variety of Makefiles in Asterisk's build system to
+	  remove .gcda and .gcno files when 'make clean' is executed. These files
+	  are generated when '--enable-coverage' is passed to the Asterisk
+	  configure script.
+
+	  Change-Id: Ib70b41eea2ee2908885bff02e80faf9f40c84602
+
+2015-06-26 20:38 +0000 [96bbcf495a]  Matt Jordan <mjordan at digium.com>
+
+	* main/pbx: Resolve case sensitivity regression in PBX hints
+
+	  When 8297136f was merged for ASTERISK-25040, a regression was introduced
+	  surrounding the case sensitivity of device names within hints.
+	  Previously, device names - such as 'sip/foo' - were compared in a case
+	  insensitive fashion. Thus, 'sip/foo' was equivalent to 'SIP/foo'. After
+	  that patch, only the case sensitive name would match, i.e., 'SIP/foo'.
+	  As a result, some dialplan hints stopped working.
+
+	  This patch re-introduces case insensitive matching for device names in
+	  hints.
+
+	  ASTERISK-25040
+
+	  ASTERISK-25202 #close
+
+	  Change-Id: If5046a7d14097e1e3c12b63092b9584bb1e9cb4c
+
+2015-06-11 08:18 +0000 [8b60998d29]  Damian Ivereigh <damo at launtel.net.au>
+
+	* chan_sip.c: Update dialog fromtag after request with auth
+
+	  If a client sends and INVITE which is 401 rejected, then subsequently
+	  sends a new INVITE with the auth info and uses a different fromtag
+	  from the first INVITE, Asterisk will accept the new INVITE as part of
+	  the original dialog - match_req_to_dialog() specifically ignores the
+	  fromtag. However it does not update the stored dialog with the new
+	  fromtag.
+
+	  This results in Asterisk being unable to match future packets that are
+	  part of this dialog (such as the ACK to the OK or the OK to the BYE),
+	  and the call is dropped.
+
+	  This problem was originally found when using an NEC-i SV8100-GE (NEC SIP
+	  Card).
+
+	  * After a successful match of a packet to the dialog, if the packet is
+	    not a SIP_RESPONSE, authentication is present and the fromtags are
+	    different, the stored fromtag is updated with the one from the recent
+	    INVITE.
+
+	  ASTERISK-25154 #close
+	  Reported by: Damian Ivereigh
+	  Tested by: Damian Ivereigh
+
+	  Change-Id: I5c16cf3b409e5ef9f2b2fe974b6bd2a45a6aa17e
+
+2015-06-11 16:44 +0000 [d821f56b02]  Mark Michelson <mmichelson at digium.com>
+
+	* chan_sip: Prevent deadlock when performing BYE with Also transfer.
+
+	  When a BYE with an Also header is successfully processed, and the sender
+	  of the BYE is bridged with another channel, chan_sip will unlock the
+	  owner of the dialog on which the BYE was received, call ast_async_goto()
+	  on the bridged channel, and then re-lock the owner. The reason for this
+	  locking behavior is that ast_async_goto() can result in a masquerade,
+	  which requires that the involved channels are unlocked.
+
+	  The problem here is that this causes a locking inversion since the
+	  dialog's lock is held when re-locking the owner channel after the async
+	  goto. The lock order is supposed to be channel and then sip_pvt.
+
+	  The fix proposed is simple. In addition to unlocking the owner channel
+	  before the ast_async_goto() call, also unlock the sip_pvt. Then relock
+	  both after ast_async_goto() returns, being sure to lock the channel and
+	  then the sip_pvt.
+
+	  ASTERISK-25139 #close
+	  Reported by Gregory Massel
+
+	  Change-Id: I72c4fc295ec8573bee599e8e9213c5350a3cd224
+2015-05-16 23:04 +0000 [53658a14cc]  Corey Farrell <git at cfware.com>
+
+	* Fix unsafe uses of ast_context pointers.
+
+	  Although ast_context_find, ast_context_find_or_create and
+	  ast_context_destroy perform locking of the contexts table,
+	  any context pointer can become invalid at any time that the
+	  contexts table is unlocked. This change adds locking around
+	  all complete operations involving these functions.
+
+	  Places where ast_context_find was followed by ast_context_destroy
+	  have been replaced with calls ast_context_destroy_by_name.
+
+	  ASTERISK-25094 #close
+	  Reported by: Corey Farrell
+
+	  Change-Id: I1866b6787730c9c4f3f836b6133ffe9c820734fa
+
+2015-06-04 07:14 +0000 [eed9b1ce52]  ibercom <ibercom123 at gmail.com>
+
+	* CLI: Cosmetic issue - core show uptime
+
+	  Show uptime information ends with an unnecessary space.
+
+	  Now NEEDCOMMA is better defined.
+
+	  Change-Id: I11b360504a0703309ff51772ff8f672287f3c5a1
+
+2015-06-02 19:06 +0000 [f98c458c92]  ibercom <ibercom123 at gmail.com>
+
+	* weakref attribute detection broken with gcc 4.6 and higher
+
+	  GCC 4.7 Manual:
+	  http://gcc.gnu.org/onlinedocs/gcc-4.7.4/gcc/Function-Attributes.html
+
+	  weakref ("target")
+
+	  A weak reference is an alias that does not by itself require a definition
+	  to be given for the target symbol.
+
+	  ASTERISK-22559 #close
+	  Reported by: Ibercom
+
+	  Change-Id: I36a136cae947b65187a697533416f9ff9a0b8cdf
+
+2015-05-31 11:33 +0000 [99c54fe42d]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* Fix buffer overflow in slin sample frames generation.
+
+	  The length of frames retured by sample functions was twice as large as
+	  real, what caused global buffer overflow caught by AddressSanitizer.
+
+	  ASTERISK-24717 #close
+	  Reported by: Badalian Vyacheslav
+
+	  Change-Id: Iec2fe682aef13e556684912f906bedf7c18229c6
+
+2015-05-24 13:47 +0000 [f9877139df]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* Astobj2: Correctly treat hash_fn returning INT_MIN
+
+	  The code in astobj2_hash.c wrongly assumed that abs(int) is always > 0.
+	  However, abs(INT_MIN) = INT_MIN and is still negative, as well as
+	  abs(INT_MIN) % num_buckets, and as a result this led to a crash.
+
+	  One way to trigger the bug is using host=::80 or 0.0.0.128 in peer
+	  configuration section in chan_sip or chan_iax.
+
+	  This patch takes the remainder before applying abs, so that bucket
+	  number is always in range.
+
+	  ASTERISK-25100 #close
+	  Reported by: Mark Petersen
+
+	  Change-Id: Id6981400ad526f47e10bcf7b847b62bd2785e899
+
+2015-05-21 20:03 +0000  Asterisk Development Team <asteriskteam at digium.com>
+
+	* asterisk 11.18.0-rc1 Released.
+
+2015-05-21 15:02 +0000 [797ca94299]  Matt Jordan <mjordan at digium.com>
+
+	* .version: Update for 11.18.0-rc1
+
+2015-05-21 15:02 +0000 [6c98593b5a]  Matt Jordan <mjordan at digium.com>
+
+	* .lastclean: Update for 11.18.0-rc1
+
+2015-05-21 07:22 +0000 [8f431d679f]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "audiohook.c: Difference in read/write rates caused continuous buffer resets" into 11
+2015-05-21 07:21 +0000 [5c047d4b0d]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "Logger: Reset defaults before processing config." into 11
+2015-05-20 20:53 +0000 [58de286467]  Corey Farrell <git at cfware.com>
+
+	* Logger: Reset defaults before processing config.
+
+	  Reset options to default values before reloading config.  This ensures
+	  that if a setting is removed or commented out of the configuration file
+	  it is unset on reload.
+
+	  ASTERISK-25112 #close
+	  Reported by: Corey Farrell
+
+	  Change-Id: Id24bb1fb0885c2c14cf8bd6f69a0c2ee7cd6c5bd
+
+2015-05-20 14:45 +0000 [2d297c7b9a]  Corey Edwards <tensai at zmonkey.org>
+
+	* chan_sip/sdp_crypto.c: allow SDP crypto tag to be up to 9 digits
+
+	  ASTERISK-24887 #close
+	  Reported by: Makoto Dei
+	  Tested by: tensai
+
+	  Change-Id: I6a96f572adb17f76b3acafe503a01c48eb5dd9bf
+2015-05-14 15:13 +0000 [58970f1475]  Kevin Harwell <kharwell at digium.com>
+
+	* audiohook.c: Difference in read/write rates caused continuous buffer resets
+
+	  Currently, everytime a sample rate change occurs (on read or write) the
+	  associated factory buffers are reset. If the requested sample rate on a
+	  read differed from that of a write then the buffers are continually reset
+	  on every read and write. This has the side effect of emptying the buffer,
+	  thus there being no data to read and then write to a file in the case of
+	  call recording.
+
+	  This patch fixes it so that an audiohook_list's rate always maintains the
+	  maximum sample rate among hooks and formats. Audiohook sample rates are
+	  only overwritten by this value when slin native compatibility is turned on.
+	  Also, the audiohook sample rate can only overwrite the list's sample rate
+	  when its rate is greater than that of the list or if compatibility is
+	  turned off. This keeps the rate from constantly switching/resetting.
+
+	  ASTERISK-24944 #close
+	  Reported by: Ronald Raikes
+
+	  Change-Id: Idab4dfef068a7922c09cc631dda27bc920a6c76f
+
+2015-05-13 15:41 +0000 [cf1190cc6b]  Jonathan Rose <jrose at digium.com>
+
+	* Message.c: Clear message channel frames on cleanup
+
+	  The message channel is a special channel that doesn't actually process frames.
+	  However, certain actions can cause frames to be placed in the channel's read
+	  queue including the Hangup application which is called on the channel after
+	  each message is processed. Since the channel will continually be reused for
+	  many messages, it's necessary to flush these frames at some point.
+
+	  ASTERISK-25083 #close
+	  Reported by: Jonathan Rose
+
+	  Change-Id: Idf18df73ccd8c220be38743335b5c79c2a4c0d0f
+
+2015-05-14 05:03 +0000 [81b0789906]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "main/manager.c: Bugfix sort action_manager by alphabetically" into 11
+2015-05-13 14:21 +0000 [3bc8c96443]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "General: Fix recent menuselect-related cross compile regression" into 11
+2015-05-13 12:55 +0000 [ffb60909a3]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "chan_dahdi/sig_pri: Fix crash on ISDN call hangup collision." into 11
+2015-05-13 12:26 +0000 [63d9ae01ee]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "res_config_mysql: Fix broken column type checking" into 11
+2015-05-04 20:11 +0000 [be7255b563]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* main/manager.c: Bugfix sort action_manager by alphabetically
+
+	  Fix the alphabetic order added on ast_manager_register_struct. The order
+	  for struct manager_action added is not working, this change fixes the
+	  problem.
+
+	  Change-Id: I149da0cd06c3c4445d7516cc303358e9f26f8b4b
+
+2015-05-08 18:01 +0000 [9370db107a]  Alexandre Fournier <alexandre.fournier at kiplink.fr>
+
+	* res_config_mysql: Fix broken column type checking
+
+	  MySQL configuration engine contains a bug in require_mysql(). This
+	  function is used for column type checking in tables. This bug only
+	  affects DATETIME, DATE and FLOAT types.
+
+	  It came from mixing the first condition (switch-case-like
+	  if/then/else), to check the expected column type, with the second
+	  condition, to check the actual column type against the expected column
+	  type. Both conditions must be checked separately in order to avoid the
+	  execution of the wrong block.
+
+	  ASTERISK-18252 #comment This patch might fix the issue
+	  Reported by: Gareth Blades
+
+	  ASTERISK-25041 #close
+	  Reported by: Alexandre Fournier
+	  Tested by: Alexandre Fournier
+
+	  Change-Id: I0b8bf7e68ab938be8e6525a249260cb648cb0bfa
+
+2015-05-10 07:37 +0000 [e3129b84b1]  Yousf Ateya <y.ateya at starkbits.com>
+
+	* res_rtp_asterisk: Correction for the limit which detects that a packet is DTLS.
+
+	  First byte of DTLS packet shall be in range 20-63, not 20-64. Refer to RFC
+	  https://tools.ietf.org/html/rfc5764#section-5.1.2 for correct values.
+
+	  Change-Id: Iae6fa0d72b37c36a27fe40686e0ae6fba3afec31
+
+2015-05-13 04:36 +0000 [735d337d88]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "cdr_pgsql: Use PQescapeStringConn for escaping names." into 11
+2015-05-12 17:34 +0000 [bedc7bf825]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_dahdi/sig_pri: Fix crash on ISDN call hangup collision.
+
+	  If an ISDN call is hungup by both sides at the same time a crash could
+	  happen.
+
+	  * Added missing NULL checks for the owner channel after calling
+	  pri_queue_pvt_cause_data() in two places.  Code after those calls need to
+	  check the owner channel pointer for NULL before use because
+	  pri_queue_pvt_cause_data() needs to do deadlock avoidance to lock the
+	  owner and the owner may get hung up.
+
+	  ASTERISK-21893 #close
+	  Reported by:  Alexandr Gordeev
+
+	  Change-Id: Ica3e266ebc7a894b41d762326f08653e1904bb9a
+
+2015-05-10 02:26 +0000 [53326e7ab0]  Sebastian Kemper <sebastian_ml at gmx.net>
+
+	* General: Fix recent menuselect-related cross compile regression
+
+	  MAKE_MENUSELECT currently sets CC to CC, which is the compiler for the
+	  target platform. But menuselect is to be run on the build system, so
+	  BUILD_CC needs to be used instead - like it was in the past, before the
+	  recent changes (https://reviewboard.asterisk.org/r/4370/). This is the
+	  patch for ASTERISK-25074.
+
+	  ASTERISK-25074 #close
+	  Reported by: Sebastian Kemper
+	  Tested by: Sebastian Kemper
+
+	  Change-Id: I8a2b1fc5deb6ad2b80f49baca35b1b13d468ebf8
+
+2015-05-12 11:57 +0000 [cd3e851a35]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "Fix processing of asterisk.conf debug=yes." into 11
+2015-05-12 01:31 +0000 [57144feed4]  Corey Farrell <git at cfware.com>
+
+	* Fix processing of asterisk.conf debug=yes.
+
+	  The code which reads asterisk.conf supports processing the debug
+	  option with ast_true, but ast_true returns -1.  This causes debug
+	  to still be off, convert to 1 so debug will be on as requested.
+
+	  ASTERISK-25042
+	  Reported by: Corey Farrell
+
+	  Change-Id: I3c898b7d082d914b057e111b9357fde46bad9ed6
+
+2015-05-01 23:43 +0000 [4c0eb9d4fb]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* cdr_pgsql: Use PQescapeStringConn for escaping names.
+
+	  Use function PQescapeStringConn for escaping the name
+	  of the table and schema instead of doing it manually.
+
+	  Change-Id: I6709165e2d00463e9c813d24f17830ad4910b599
+
+2015-05-11 07:07 +0000 [cc39cfa213]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* pbx/pbx_spool: Fix issue when call files were executed too early
+
+	  pbx_spool used to delete/move the call file upon successful outgoing
+	  call completion, but did not delete it from in-memory list of files
+	  (dirlist, used only when compiled with inotify/kqueue support).
+	  That resulted in an extra attempt to process that filename after
+	  retrytime seconds.
+	  Then, if a new file with the same name appears that is scheduled
+	  in future further than the completed one plus its retrytime,
+	  then it gets executed earlier than expected.
+
+	  This patch fixes remove_from_queue function to also remove the entry
+	  from the dirlist.
+
+	  ASTERISK-17069 #close
+	  Reported by: Jeremy Kister
+
+	  ASTERISK-24442 #close
+	  Reported by: tootai
+
+	  Change-Id: If9ec9b88073661ce485d6b008fd0b2612e49a28b
+
+2015-05-08 15:55 +0000 [fb27395f75]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "tcptls: Avoiding ERR_remove_state in OpenSSL." into 11
+2015-05-08 15:54 +0000 [767d96cf7e]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "res_rtp_asterisk: Issue ERROR if res_srtp is not found." into 11
+2015-05-08 10:39 +0000 [151c3316d5]  Sean Bright <sean at malleable.com>
+
+	* res_rtp_asterisk: Issue ERROR if res_srtp is not found.
+
+	  While trying to get WebRTC working with chan_pjsip, I was running
+	  into the following error:
+
+	      Attempted to set an invalid DTLS-SRTP configuration on RTP
+	      instance...
+
+	  Josh helpfully pointed out that res_srtp.so might not be loaded, and
+	  sure enough, it wasn't. This patch adds a ERROR indiciating as much
+	  to hopefully help others having a similar problem.
+
+	  Change-Id: I13aa477b47b299876728a21b130998a0ea6cd19f
+
+2015-05-07 17:49 +0000 [a2f96d3c1a]  Rusty Newton <rnewton at digium.com>
+
+	* sounds: Add Swedish sounds to Makefile and XML
+
+	  Added the necessary lines to the Makefile and sounds.xml so we'll have the
+	  Swedish sounds in all available formats in menuselect.
+
+	  See also: Swedish sounds were added into the core sounds release 1.4.27.
+
+	  ASTERISK-24744 #close
+
+	  Reported by: Tove Hjelm
+	  Tested by: Rusty Newton
+
+	  Change-Id: Ib6f4fd177afd1667b2402735034001d4d055a908
+
+2015-05-05 11:35 +0000 [5cca9a66bc]  Alexander Traud (License 6520)
+
+	* tcptls: Avoiding ERR_remove_state in OpenSSL.
+
+	  ERR_remove_state was deprecated with OpenSSL 1.0.0 and was replaced by 
+	  ERR_remove_thread_state. ERR_load_SSL_strings and ERR_load_BIO_strings were 
+	  called by SSL_load_error_strings already and got removed. These changes allow 
+	  OpenSSL forks like BoringSSL to be used with Asterisk.
+
+	  ASTERISK-25043 #close
+	  Reported by: Alexander Traud
+	  patches:
+	    asterisk_with_BoringSSL.patch uploaded by Alexander Traud (License 6520)
+
+	  Change-Id: If1c0871ece21a7e0763fafbd2fa023ae49d4d629
+	  (cherry picked from commit 247fef66537b59649e7571d64e2c574a106dbd65)
+
+2015-05-07 14:54 +0000 [7de043e43d]  George Joseph <george.joseph at fairview5.com>
+
+	* doc: Make progdocs play nice with git
+
+	  Moved contrib/asterisk-ng-doxygen to doc/asterisk-ng-doxygen.in
+
+	  Changed /Makefile to copy asterisk-ng-doxygen.in to
+	  asterisk-ng-doxygen then modify it with version instead of
+	  modifying asterisk-ng-doxygen directly.  Updated clean
+	  targets as well.
+
+	  Updated /.gitignore and doc/.gitignore.
+
+	  Change-Id: I38712d3e334fa4baec19d30d05de8c6f28137622
+
+2015-05-04 14:43 +0000 [97101bd481]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* contrib/editors: Fix vim syntax highlighting of comments in config files
+
+	   * Added a lookbehind to one-line comment matcher to skip escaped
+	     semicolons.
+	   * Added support for block comments.
+
+	  Change-Id: Id17dfaeda8ed4be572e8107a0c010066584aaee7
+
+2015-05-06 16:00 +0000 [d5db203024]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_dahdi: Improve force_restart_unavailable_chans option description.
+
+	  ASTERISK-25034
+	  Reported by: Richard Mudgett
+
+	  Change-Id: I1ff8f02124d2f4abd632a050da52c64285bb7f30
+
+2015-05-05 14:48 +0000 [8d927fad0d]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* app_queue: Fix queue_log EXITWITHTIMEOUT containing only 1 parameter
+
+	  This patch fixes EXITWITHTIMEOUT queue_log entry to always come with 3
+	  parameters: position, original position and waiting time.
+
+	  ASTERISK-25038 #close
+	  Reported by: Etienne Lessard
+
+	  Change-Id: I0c62045922e26bee2125e93aee1dee17eee79618
+
+2015-05-04 09:25 +0000 [e823fc9f9b]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "cdr/cdr_csv.c: Add a new option to enable columns added in Asterisk 1.8" into 11
+2015-05-04 07:46 +0000 [2ed57f3ab1]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "res_odbc: Use negative connection cache for all connections" into 11
+2015-04-21 11:52 +0000 [7c32cb27b7]  Martin Tomec <tomec.martin at gmail.com>
+
+	* res_odbc: Use negative connection cache for all connections
+
+	  Apply the negative connection cache setting to all connections,
+	  even those that are not pooled. This ensures that the connection
+	  will not be re-established before the negative connection cache
+	  time is met.
+
+	  ASTERISK-22708 #close
+
+	  Change-Id: I431cc2e8584ab0b6908b3523d0a0e18c9a527271
+2015-05-04 04:03 +0000 [8fed642764]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "Update configure.ac/Makefile for clang" into 11
+2015-04-20 13:03 +0000 [f70f2c6252]  Diederik de Groot <ddegroot at talon.nl>
+
+	* Update configure.ac/Makefile for clang
+
+	  Created autoconf/ast_check_raii.m4: contains AST_CHECK_RAII which
+	  checks compiler requirements for RAII:
+	  gcc: -fnested-functions support
+	  clang: -fblocks (and if required -lBlocksRuntime)
+	  The original check was implemented in configure.ac and now has it's
+	  own file. This function also sets C_COMPILER_FAMILY to either gcc or
+	  clang for use by makefile
+
+	  Created autoconf/ast_check_strsep_array_bounds.m4 (contains
+	  AST_CHECK_STRSEP_ARRAY_BOUNDS):
+	  which checks if clang is able to handle the optimized strsep & strcmp
+	  functions (linux). If not, the standard libc implementation should be
+	  used instead. Clang + the optimized macro's work with:
+	  strsep(char *, char []), but not with strsepo(char *, char *).
+	  Instead of replacing all the occurences throughout the source code,
+	  not using the optimized macro version seemed easier
+
+	  See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h':
+	  llvm-comment: Normally, this array-bounds warning are suppressed for
+	  macros, so that unused paths like the one that accesses __s1[3] are
+	  not warned about.  But if you preprocess manually, and feed the
+	  result to another instance of clang, it will warn about all the
+	  possible forks of this particular if statement. Instead of switching
+	  of this optimization, another solution would be to run the preproces-
+	  sing step with -frewrite-includes, which should preserve enough
+	  information so that clang should still be able to suppress the diag-
+	  nostic at the compile step later on.
+
+	  See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
+	  See also "https://llvm.org/bugs/show_bug.cgi?id=11536"
+
+	  Makefile.rules: If C_COMPILER_FAMILY=clang then add two warning
+	  suppressions:
+	  -Wno-unused-value
+	  -Wno-parentheses-equality
+	  In an earlier review (reviewboard: 4550 and 4554), they were deemed a
+	  nuisace and less than benefitial.
+
+	  configure.ac:
+	  Added AST_CHECK_RAII() see earlier
+	  Added AST_CHECK_STRSEP_ARRAY_BOUNDS() see earlier
+	  Removed moved content
+
+	  ASTERISK-24917
+	  Change-Id: I12ea29d3bda2254ad3908e279b7effbbac6a97cb
+	  (cherry picked from commit 9c3ed428759a83a2b80106e605fe43dda0569425)
+
+2015-05-03 09:20 +0000 [9764918afb]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "Build System: Prevent unneeded changes to asterisk/buildopts.h." into 11
+2015-05-02 10:20 +0000 [5e986ddea0]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "v11: More files to ignore." into 11
+2015-05-02 10:16 +0000 [494c7a98eb]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "main/pbx: Improve performance of dialplan reloads with a large number of hints" into 11
+2015-04-29 03:03 +0000 [ce86340403]  Corey Farrell <git at cfware.com>
+
+	* Build System: Prevent unneeded changes to asterisk/buildopts.h.
+
+	  * Add AST_DEVMODE to BUILDOPTS
+	  * Remove CFLAGS that do not effect ABI from BUILDOPTS.
+	  * Use BUILDOPTS to generate AST_BUILDOPT_SUM.
+	  * Remove loop that defined AST_MODULE_*
+
+	  These changes ensure that only ABI effecting options are considered for
+	  AST_BUILDOPT_SUM.  This also reduces unneeded full system rebuilds caused
+	  by enabling or disabling one module that another is dependent on.
+
+	  ASTERISK-25028 #close
+	  Reported by: Corey Farrell
+
+	  Change-Id: I2c516d93df9f6aaa09ae079a8168c887a6ff93a2
+
+2015-05-01 12:23 +0000 [f3bc0cc70f]  Richard Mudgett <rmudgett at digium.com>
+
+	* v11: More files to ignore.
+
+	  Change-Id: If5eef47d03399ff93e3f2f490780144971f6b64a
+
+2015-04-29 14:49 +0000 [8297136fdf]  Matt Jordan <mjordan at digium.com>
+
+	* main/pbx: Improve performance of dialplan reloads with a large number of hints
+
+	  The PBX core maintains two hash tables for hints: a container of the
+	  actual hints (hints), along with a container of devices that are watching that
+	  hint (hintdevices). When a dialplan reload occurs, each hint in the hints
+	  container is destroyed; this requires a lookup in the container of devices to
+	  find the device => hint mapping object. In the current code, this performs an
+	  ao2_callback, iterating over each of the device to hint objects in the
+	  hintdevices container. For a large number of hints, this is extremely
+	  expensive: dialplan reloads with 20000 hints could take several minutes
+	  in just this phase.
+
+	  This patch improves the performance of this step in the dialplan reloads
+	  by caching which devices are watching a hint on the hint object itself.
+	  Since we don't want to create a circular reference, we just cache the
+	  name of the device. This allows us to perform a smarter ao2_callback on
+	  the hintdevices container during hint removal, hashing on the name of the
+	  device and returning an iterator to the matching names. The overall
+	  performance improvement is rather large, taking this step down to a number of
+	  seconds as opposed to minutes.
+
+	  In addition, this patch also registers the hint containers in the PBX
+	  core with the astobj2 library. This allows for reasonable debugging to
+	  hash collisions in those containers.
+
+	  ASTERISK-25040 #close
+	  Reported by: Matt Jordan
+
+	  Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
+	  (cherry picked from commit 80c0756f7386452fddab3324fa6a71933cde006e)
+
+2015-04-30 11:57 +0000 [50d8aea753]  Mark Michelson <mmichelson at digium.com>
+
+	* Merge "include/asterisk/vector.h: Backport vector.h to Asterisk 11" into 11
+2015-04-30 11:04 +0000 [176cb0d45b]  Matt Jordan <mjordan at digium.com>
+
+	* include/asterisk/vector.h: Backport vector.h to Asterisk 11
+
+	  Vectors are very useful constructs. As a container, they prevent having
+	  to calloc/realloc arrays manually. They also have advantages over linked
+	  lists, which require elements in the list to be a struct. This patch
+	  backports vectors to Asterisk 11 for use in future patches.
+
+	  Change-Id: Idc9d74d246a0158b0b36ccb250e7acc71bab078d
+
+2015-04-29 17:28 +0000 [b54f5fda05]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_dahdi: Add the chan_dahdi.conf force_restart_unavailable_chans option.
+
+	  Some telco switches occasionally ignore ISDN RESTART requests.  The fix
+	  for ASTERISK-19608 added an escape clause for B channels in the restarting
+	  state if the telco ignores a RESTART request.  If the telco fails to
+	  acknowledge the RESTART then Asterisk will assume the telco acknowledged
+	  the RESTART on the second call attempt requesting the B channel by the
+	  telco.  The escape clause is good for dealing with RESTART requests in
+	  general but it does cause the next call for the restarting B channel to be
+	  rejected if the telco insists the call must go on that B channel.
+
+	  chan_dahdi doesn't really need to issue a RESTART request in response to
+	  receiving a cause 44 (Requested channel not available) code.  Sending the
+	  RESTART in such a situation is not required (nor prohibited) by the
+	  standards.  I think chan_dahdi does this for historical reasons to deal
+	  with buggy peers to get channels unstuck in a similar fashion as the
+	  chan_dahdi.conf resetinterval option.
+
+	  * Add the chan_dahdi.conf force_restart_unavailable_chans compatability
+	  option that when disabled will prevent chan_dahdi from trying to RESTART
+	  the channel in response to a cause 44 code.
+
+	  ASTERISK-25034 #close
+	  Reported by: Richard Mudgett
+
+	  Change-Id: Ib8b17a438799920f4a2038826ff99a1884042f65
+2015-04-30 06:34 +0000 [a78774325b]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* cdr/cdr_csv.c: Add a new option to enable columns added in Asterisk 1.8
+
+	  This patch adds a new option to cdr.conf, 'newcdrcolumns', that will handle CDR
+	  columns added in Asterisk 1.8. The columns are:
+	   * peeraccount
+	   * linkedid
+	   * sequence
+	  When enabled, the columns in the database entry will be populated with the data
+	  from the CDR.
+
+	  ASTERISK-24976 #close
+
+	  Change-Id: I51a57063f4ae5e194a9d933a8df45dc8a4534f0b
+
+2015-04-29 16:42 +0000 [acced2b88b]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "res_fax: allow 2400 transmission rate according to v.27ter standard" into 11
+2015-04-29 16:15 +0000 [28fd06bdcd]  Matt Jordan <mjordan at digium.com>
+
+	* main/rtp_engine: Fix DTLS double-free introduced by 0b6410c4f8
+
+	  The patch in 0b6410c4f8 did correctly fix a memory leak of the DTLS
+	  structures in the RTP engine. However, when a 'core reload' is issued, a
+	  double free of the memory pointed to by the char *'s in the DTLS
+	  configuration struct can occur, as ast_rtp_dtls_cfg_free does not set
+	  the pointers to NULL when they are freed.
+
+	  This patch sets those pointers to NULL, preventing a second call to
+	  ast_rtp_dtls_cfg_free from corrupting memory.
+
+	  ASTERISK-25022
+
+	  Change-Id: I820471e6070a37e3c26f760118c86770e12f6115
+
+2015-04-29 13:19 +0000 [f60915250f]  Kevin Harwell <kharwell at digium.com>
+
+	* res_fax: allow 2400 transmission rate according to v.27ter standard
+
+	  A previous set of patches (see: ASTERISK-22790 & ASTERISK-23231) made it so
+	  a v.27 modem was not allowed to have a minimum transmission rate of 2400 bits
+	  per second. This reverts all or some of those patches since according to the
+	  v.27ter standard a rate of 2400 bits per second is also supported.
+
+	  One of the original patches also added 9600 bits per second support for v.27.
+	  This patch also removes that since v.27ter only supports 2400/4800 bits per
+	  second.
+
+	  Also, since Asterisk specifically supports v.27ter the enum was renamed to
+	  better reflect this.
+
+	  ASTERISK-24955 #close
+	  Reported by: Matt Jordan
+
+	  Change-Id: I4b9dfb6bf7eff08463ab47ee1a74224f27cae733
+
+2015-04-29 15:03 +0000 [32cab65020]  Richard Mudgett <rmudgett at digium.com>
+
+	* Fixup UPGRADE.txt so new notes go in correct section for next release.
+
+	  Change-Id: I7080d32b559f8c5d06ddd3198e0cd6e342bac841
+
+2015-04-29 14:13 +0000 [b1b0aeffe8]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "rtp_engine: Prevent unnecessary memory increases during calls." into 11
+2015-04-29 11:46 +0000 [c87b0d7375]  Mark Michelson <mmichelson at digium.com>
+
+	* rtp_engine: Prevent unnecessary memory increases during calls.
+
+	  The doxygen for ast_rtp_codecs_payloads_copy() states:
+
+	  "This copies the payloads from the codecs0 structure to the codecs1
+	  structure, overwriting any current values."
+
+	  However, in practice, the overwriting of current values was not
+	  happening. Instead, a new RTP codec payload object would be appended to
+	  the codecs1 structure instead of replacing the corresponding object.
+
+	  This patch corrects this behavior by overwriting the object in the
+	  codecs1 structure if it exists already. If it does not already exist,
+	  then create a new copy and link it in.
+
+	  Tests of "memory show summary rtp_engine.c" had previously shown
+	  additional allocations being performed any time that Asterisk processed
+	  an incoming SDP. Scenarios involving lots of reinvites resulted in lots
+	  of allocations. With this patch, I can perform as many reinvites as
+	  I want and see no memory increases from the RTP engine.
+
+	  ASTERISK-24916 #close
+	  Reported by Christophe Osuna
+
+	  Change-Id: I9a90bc3f564535bc767bf2fc0c455d5f065cea75
+
+2015-04-29 01:24 +0000 [41bf52315a]  Ivan Poddubny <ivan.poddubny at gmail.com>
+
+	* addons/res_config_mysql: Don't mutate va_list parameters
+
+	  The realtime API passes down the va_list argument to each RT engine in
+	  failover chain until one succeeds. MySQL engine used to access the
+	  variable argument list with va_arg, which mutates the va_list, so the
+	  next engine in failover chain gets invalid agrument list.
+	  This patch uses va_copy to preserve the original va_list argument intact.
+
+	  ASTERISK-19538 #close
+	  Reported by: alexat
+	  Tested by: Ivan Poddubny
+
+	  Change-Id: I7738b9f98bde81ddfbc2c0fa579d85a0c3e580ae
+
+2015-04-28 07:15 +0000 [9bee1cae12]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "Example script for scan-build (the llvm static analyzer)" into 11
+2015-04-28 07:11 +0000 [345cb1ea27]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "res_rtp_asterisk: Resolve 2 discrete memory leaks in DTLS" into 11
+2015-04-28 05:38 +0000 [a9b25f035e]  Steve Davies <steve at one47.co.uk>
+
+	* res_rtp_asterisk: Resolve 2 discrete memory leaks in DTLS
+
+	  ao2 ref leak in res_rtp_asterisk.c when a DTLS policy is created.
+	  The resources are linked into a table, but the original alloc refs
+	  are never released. ast_strdup leak in rtp_engine.c. If
+	  ast_rtp_dtls_cfg_copy() is called twice on the same destination struct,
+	  a pointer to an alloc'd string is overwritten before the string is free'd.
+
+	  ASTERISK-25022
+	  Reported by: one47
+
+	  Change-Id: I62a8ceb8679709f6c3769136dc6aa9a68202ff9b
+2015-04-28 06:55 +0000 [08b307c96b]  Joshua Colp <jcolp at digium.com>
+
+	* Merge "cdr/cdr_odbc.c: Added to record new columns add on CDR 1.8 Asterisk Version" into 11
+2015-04-15 18:55 +0000 [d6e208a80d]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* cdr/cdr_odbc.c: Added to record new columns add on CDR 1.8 Asterisk Version
+
+	  Add new column to INSERT new columns added in cdr 1.8 version. The columns are:
+	   * peeraccount
+	   * linkedid
+	   * sequence
+	  This feature is configurable in cdr_odbc.conf using a new configuration
+	  option, 'newcdrcolumns'.
+
+	  ASTERISK-24976 #close
+
+	  Change-Id: Ibe0c7540a88305c6012786f438a0813ad8b19127
+2015-04-26 15:53 +0000 [be468b2627]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "Clang: Fix some more tautological-compare warnings." into 11
+2015-04-24 13:06 +0000 [ca7ad5d339]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "app_confbridge: Default the template option to a compatible default profile." into 11
+2015-04-23 15:05 +0000 [019695b49d]  Kevin Harwell <kharwell at digium.com>
+
+	* app_confbridge: Default the template option to a compatible default profile.
+
+	  Confbridge dynamic profiles did not have a default profile unless you
+	  explicitly used Set(CONFBRIDGE(bridge,template)=default_bridge). If a
+	  template was not set prior to the bridge being created then some
+	  options were left with no default values set. This patch makes it so
+	  the default templates are set to the default bridge and user profiles.
+
+	  ASTERISK-24749 #close
+	  Reported by: philippebolduc
+
+	  Change-Id: I1bd6e94b38701ac2112d842db68de63d46f60e0a
+
+2015-04-24 10:23 +0000 [3bb1e967cb]  Matt Jordan <mjordan at digium.com>
+
+	* Clang: Fix some more tautological-compare warnings.
+
+	  clang can warn about a so called tautological-compare, when it finds
+	  comparisons which are logically always true, and are therefore deemed
+	  unnecessary.
+
+	  Example:
+	  unsigned int x = 4;
+	  if (x > 0) // x is always going to be bigger than 0
+
+	  Enum Case:
+	  Each enumeration is its own type. Enums are an integer type but they do not
+	  have to be *signed*. C leaves it up to the compiler as an implementation
+	  option what to consider the integer type of a particular enumeration is.
+	  Gcc treats an enum without negative values as an int while clang treats this
+	  enum as an unsigned int.
+
+	  rmudgett & mmichelson:
+	  cast the enum to (unsigned int) in assert. The cast does have an effect.
+	  For gcc, which seems to treat all enums as int, the cast to unsigned int
+	  will eliminate the possibility of negative values being allowed. For
+	  clang, which seems to treat enums without any negative members as
+	  unsigned int, the cast will have no effect. If for some reason in the
+	  future a negative value is ever added to the enum the assert will still
+	  catch the negative value.
+
+	  ASTERISK-24917
+
+	  Change-Id: Ief23ef68916192b9b72dabe702b543ecfeca0b62
+
+2015-04-20 13:06 +0000 [82387f7d27]  Diederik de Groot <ddegroot at talon.nl>
+
+	* Example script for scan-build (the llvm static analyzer)
+
+	   - Added Pre-amble (Options / Flags / Usage Example / GNU License)
+	   - Extended Configurability
+	   - Made Executable
+
+	  ASTERISK-24917
+	  Change-Id: I70405fe54e4be7dbfbcb62e291690069b88617a8
+
+2015-04-23 08:00 +0000 [9c61245061]  Diederik de Groot <ddegroot at talon.nl>
+
+	* Clang: change previous tautological-compare fixes.
+
+	  clang can warn about a so called tautological-compare, when it finds
+	  comparisons which are logically always true, and are therefor deemed
+	  unnecessary.
+
+	  Exanple:
+	  unsigned int x = 4;
+	  if (x > 0)    // x is always going to be bigger than 0
+
+	  Enum Case:
+	  Each enumeration is its own type. Enums are an integer type but they
+	  do not have to be *signed*. C leaves it up to the compiler as an
+	  implementation option what to consider the integer type of a particu-
+	  lar enumeration is. Gcc treats an enum without negative values as
+	  an int while clang treats this enum as an unsigned int.
+
+	  rmudgett & mmichelson: cast the enum to (unsigned int) in assert.
+	  The cast does have an effect. For gcc, which seems to treat all enums
+	  as int, the cast to unsigned int will eliminate the possibility of
+	  negative values being allowed. For clang, which seems to treat enums
+	  without any negative members as unsigned int, the cast will have no
+	  effect. If for some reason in the future a negative value is ever
+	  added to the enum the assert will still catch the negative value.
+
+	  ASTERISK-24917
+
+	  Change-Id: I0557ae0154a0b7de68883848a609309cdf0aee6a
+
+2015-04-22 16:32 +0000 [f56c5f1aa2]  George Joseph <george.joseph at fairview5.com>
+
+	* .gitignore:  Add .gcno and .gcda
+
+	  Products of --enable-coverage
+
+	  Change-Id: Ie20882d64b60692e2c941ea8872ab82a86ce77a3
+
+2015-04-20 13:01 +0000 [4295582511]  Diederik de Groot <ddegroot at talon.nl>
+
+	* Fix/Update clang-RAII macro implementation
+
+	  - When you need to refer to 'variable XXX' outside a block, it needs
+	  to be declared as '__block XXX', otherwise it will not be available with-
+	  in the block, making updating that variable hard to do, and ast_free
+	  lead to issues.
+
+	  - Removed the #error message
+	  because it creates complications when compiling external projects
+	  against asterisk For example when using a different compiler than the
+	  one used to compile asterisk. The warning/error should be generated
+	  during the configure process not the compilation process
+
+	  ASTERISK-24917
+	  Change-Id: I12091228090e90831bf2b498293858f46ea7a8c2
+
+2015-04-21 15:17 +0000 [fc79cae5d5]  Corey Farrell <git at cfware.com>
+
+	* Check for ao2_alloc failure in __ast_channel_internal_alloc.
+
+	  Fix a crash that could occur in __ast_channel_internal_alloc if
+	  ao2_alloc fails.
+
+	  ASTERISK-24991 #close
+
+	  Change-Id: I4ca89189eb22f907408cb87d0a1645cfe1314a90
+
+2015-04-20 18:00 +0000 [e4b956b186]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_dahdi/sig_pri: Make post AMI HangupRequest events on PRI channels.
+
+	  The chan_dahdi channel driver is a very old driver.  The ability for it to
+	  support ISDN was added well after the initial analog support.  Setting the
+	  softhangup flags is a carry over from the original analog code.  The
+	  driver was not updated to call ast_queue_hangup() which will post the AMI
+	  HangupRequest event.
+
+	  * Changed sig_pri.c to call ast_queue_hangup() instead of setting the
+	  softhangup flag when the remote party initiates a hangup.
+
+	  ASTERISK-24895 #close
+	  Reported by: Andrew Zherdin
+
+	  Change-Id: I5fe2e48556507785fd8ab8e1c960683fd5d20325
+
+2015-04-20 06:30 +0000 [4384136c46]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "UPGRADE: Fix upgrade notes" into 11
+2015-04-20 06:29 +0000 [82bd20ed9c]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "main/pbx: Don't attempt to destroy a previously destroyed exten/priority tuple" into 11
+2015-04-19 15:49 +0000 [6ed37a7f38]  Matt Jordan <mjordan at digium.com>
+
+	* main/pbx: Don't attempt to destroy a previously destroyed exten/priority tuple
+
+	  When a PBX registrar is unloaded, it will fail to remove its extension from
+	  the context root_table if a dialplan application used by that extension is
+	  still loaded. This can be the case for AGI, which can be unloaded after several
+	  of the standard PBX providers. Often, this is harmless; however, if the
+	  extension's priorities are removed during the failed unloading *and* the
+	  dialplan application later unregisters, it leaves a ticking timebomb for the
+	  next PBX provider that attempts to iterate over the extensions. When that
+	  occurs, the peer_table pointer on the extension will already be set to NULL.
+	  The current code does not check to see if the pointer is NULL before passing
+	  it to a hashtab function this is not NULL tolerant.
+
+	  Since it is possible for the peer_table to be NULL when we normally would not
+	  expect that to be the case, the solution in this patch is to simply skip over
+	  processing an extension's priorities if peer_table is NULL.
+
+	  Prior to this patch, the tests/pbx/callerid_match test would crash during
+	  module unload. With this patch, the test no longer crashes after running.
+
+	  ASTERISK-24774 #close
+	  Reported by: Corey Farrell
+
+	  Change-Id: I2bbeecb7e0f77bac303a1b9135e4cdb4db6d4c40
+
+2015-04-18 23:49 +0000 [e2520715c2]  Matt Jordan <mjordan at digium.com>
+
+	* UPGRADE: Fix upgrade notes
+
+	  The next expected release from the 11 branch is 11.18.0. This patch
+	  updates the UPGRADE notes to reflect that.
+
+	  Change-Id: I8e6e9d62b3916484a68733cfc8d64b3709adb0c2
+
+2015-04-17 16:19 +0000 [8fc07492cc]  Corey Farrell <git at cfware.com>
+
+	* Fix issue with AST_THREADSTORAGE_RAW when DEBUG_THREADLOCALS is enabled.
+
+	  When DEBUG_THREADLOCALS is enabled it causes the threadlocal cleanup to be
+	  called as a function.  This causes a compile error with raw threadstorage as
+	  it uses NULL for cleanup.  This fix uses a macro that provides NULL when
+	  DEBUG_THREADLOCALS is disabled, and replaces the call to "c_cleanup(data);"
+	  with "{};" when DEBUG_THREADLOCALS is enabled.
+
+	  ASTERISK-24975 #close
+	  Reported by: Ashley Sanders
+
+	  Change-Id: I3ef7428ee402816d9fcefa1b3b95830c00d5c402
+
+2015-04-15 16:08 +0000 [c9891666bf]  George Joseph <george.joseph at fairview5.com>
+
+	* More .gitignore updates
+
+	  Added .pyc and .sha1 to the top-level .gitignore.
+
+	  Change-Id: I7dfc4f554d54d22947b38140d3305007503cc16a
+	  Tested-by: George Joseph <george.joseph at fairview5.com>
+
+2015-04-15 13:35 +0000 [ccad749449]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "Build System: Replace comment about setting menuselect defaults." into 11
+2015-04-14 13:16 +0000 [fb601a5a7a]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* cel_pgsql: Fix name string for log on unable allocate memory.
+
+	  The LOG_ERROR has reference to CDR instead of CEL  for LENGTHEN_BUF1 and
+	  LENGTHEN_BUF2.
+
+	  ASTERISK-24965 #close
+	  Reported by: Rodrigo Ramirez Norambuena
+
+	  Change-Id: Icc818697d7d66d34bfe3048cdd15ca2b06c89744
+2015-04-14 13:48 +0000 [29c7068a89]  Corey Farrell <git at cfware.com>
+
+	* Build System: Replace comment about setting menuselect defaults.
+
+	  The Makefile claims that you can set default menuselect options by creating
+	  ~/.asterisk.makeopts or /etc/asterisk.makeopts, but those files have never
+	  been respected in Asterisk 11 or 13.  This changes the comment to accurately
+	  reflect that these files are not automatically used by the build system.
+
+	  ASTERISK-13721 #close
+	  Reported by: pj
+
+	  Change-Id: Ibde804ff196283def49ccb9432fbf224a22586e2
+
+2015-04-12 09:08 +0000 [57b7e2c51c]  Rodrigo Ramírez Norambuena <decipher.hk at gmail.com>
+
+	* cdr_pgsql: Fix CLI "cdr show pgsql status" command.
+
+	  The command always showed the usage information.
+
+	  * Fix the error in command validation for CLI_SHOWUSAGE.
+
+	  ASTERISK-24959 #close
+	  Reported by: Rodrigo Ramirez Norambuena
+
+	  Change-Id: I584f0936bb01001336a468a55c1d05d79fe795d5
+	  (cherry picked from commit 23a180cade51e84b9def65b05759c3cb9feba225)
+
+2015-04-14 12:38 +0000 [54ce7cc857]  Matt Jordan <mjordan at digium.com>
+
+	* Merge ".gitignore updates for 11" into 11
+2015-04-13 19:34 +0000 [65eb7d5425]  George Joseph <george.joseph at fairview5.com>
+
+	* Backport menuselect to 12,11,1.8
+
+	  Backport menuselect from 13->12->11->1.8
+
+	  Change-Id: I54c4dd2bdacd3c9d858be3acab08706941f2e585
+
+2015-04-13 20:17 +0000 [b44aeb6998]  George Joseph <george.joseph at fairview5.com>
+
+	* .gitignore updates for 11
+
+	  Added bootstrap products
+	  Added channels/h323/Makefile
+	  Added res/pjproject
+
+	  Change-Id: I6b3bc56bf7bdaee0554f36fc2ce3a77e9eaf8aa3
+
+2015-04-13 14:41 +0000 [e540034f22]  David M. Lee <dlee at respoke.io>
+
+	* Fixing extconf compile
+
+	  During the mass code deletion for clang support, a stray backslash was
+	  left behind that was causing utils to fail to compile.
+
+	  Change-Id: I60e5fa58c9a5b248bde23aaada79ff663f87a2a1
+
+2015-04-13 12:03 +0000 [736a3cef01]  Matt Jordan <mjordan at digium.com>
+
+	* Merge "build_tools/make_version: Update version parsing for Git migration" into 11
+2015-04-13 09:54 +0000 [0f627c2015]  Matt Jordan <mjordan at digium.com>
+
+	* build_tools/make_version: Update version parsing for Git migration
+
+	  External systems - such as the Asterisk Test Suite - require knowledge of the
+	  upstream branch. Unfortunately, after moving to Git, the Asterisk version
+	  currently consists of only a 'GIT" prefix followed by an object blob,
+	  e.g., GIT-as08d7. This makes it difficult for such systems to know what
+	  features are available in a particular check out of Asterisk.
+
+	  This patch fixes this by hardcoding the branch in a variable in the
+	  make_version script. Since the mainline branches are not changed often -
+	  typically only once a year - this is a reasonable approach to solving
+	  the problem, and is more reliable than parsing the output of 'git branch
+	  -vv'. Branches that track off of an upstream primary branch will then get the
+	  benefit of knowing which mainline branch they are currently based off
+	  of.
+
+	  ASTERISK-24954 #close
+
+	  Change-Id: I8090d5d548b6d19e917157ed530b914b7eaf9799
+
+2015-04-12 12:59 +0000 [552fa861c7]  Matt Jordan <mjordan at digium.com>
+
+	* git migration: Remove support for file versions
+
+	  Git does not support the ability to replace a token with a version
+	  string during check-in. While it does have support for replacing a
+	  token on clone, this is somewhat sub-optimal: the token is replaced
+	  with the object hash, which is not particularly easy for human
+	  consumption. What's more, in practice, the source file version was often
+	  not terribly useful. Generally, when triaging bugs, the overall version
+	  of Asterisk is far more useful than an individual SVN version of a file.
+	  As a result, this patch removes Asterisk's support for showing source file
+	  versions.
+
+	  Specifically, it does the following:
+	  * main/asterisk:
+	    - Refactor the file_version structure to reflect that it no longer
+	      tracks a version field.
+	    - Alter the "core show file version" CLI command such that it always
+	      reports the version of Asterisk. The file version is no longer
+	      available.
+
+	  * main/manager: The Version key now always reports the Asterisk version.
+
+	  * UPGRADE: Add notes for:
+	    - Modification to the ModuleCheck AMI Action.
+	    - Modification to the CLI "core show file version" command.
+
+	  Change-Id: Ia932d3c64cd18a14a3c894109baa657ec0a85d28
+
+2015-04-12 15:27 +0000 [6b9e0a9db2]  Matt Jordan <mjordan at digium.com>
+
+	* Merge topic '11-git-ignore' into 11
+
+	  * changes:
+	    .gitignore: Ignore tarballs (*.gz)
+	    Add .gitignore and .gitreview files
+
+2015-04-12 06:12 +0000 [50c1ae4053]  Corey Farrell <git at cfware.com>
+
+	* main/editline: Add .gitignore.
+
+	  This patch adds a .gitignore for main/editline to ignore all build results.
+
+	  Change-Id: I68c7bf375ea46282689e5a706534b69fca233b5d
+
+2015-04-11 23:22 +0000 [9ca89baf20]  Matt Jordan <mjordan at digium.com>
+
+	* .gitignore: Ignore tarballs (*.gz)
+
+	  This patch updates the root .gitignore file to ignore files with a .gz
+	  extension. This will cause git to ignore downloaded sound tarballs in
+	  the the sounds/ directory.
+
+	  Change-Id: Ic153642236ea8aee100443b94c563d0318711af3
+
+2015-04-11 13:20 +0000 [7079f53a40]  George Joseph <george.joseph at fairview5.com>
+
+	* Add .gitignore and .gitreview files
+
+	  Add the .gitignore and .gitreview files to the asterisk repo.
+
+	  NB:  You can add local ignores to the .git/info/exclude file
+	  without having to do a commit.
+
+	  Common ignore patterns are in the top-level .gitignore file.
+	  Subdirectory-specific ignore patterns are in their own .gitignore
+	  files.
+
+	  Change-Id: I2b7513fc9acf5d432cf9587c25faa9786af14abf
+	  Tested-by: George Joseph
+
+2015-04-11 10:34 +0000 [e5c5fe70d6]  Matthew Jordan <mjordan at digium.com>
+
+	* main/event: Remove unnecessary assignment of negative value to enum
+
+	  When cleaning up some clang compiler warnings, the comparison of a negative
+	  value to an unsigned enum was removed. However, the initial assignment of a
+	  negative value to said enum remained in the variable declaration. This patch
+	  removes that assignment.
+
+	  Thanks to ibercom in #asterisk-bugs for pointing it out.
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434708 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-11 10:26 +0000 [68f974978d]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix various warnings for tests
+
+	  This patch fixes a variety of clang compiler warnings for unit tests. This
+	  includes autological comparison issues, ignored return values, and
+	  interestingly enough, one embedded function. Fun!
+
+	  Review: https://reviewboard.asterisk.org/r/4555
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4555.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434705 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-10 11:25 +0000 [7bee716f86]  Richard Mudgett <rmudgett at digium.com>
+
+	* translate.c: Only select audio codecs to determine the best translation choice.
+
+	  Given a source capability of h264 and ulaw, a destination capability of
+	  h264 and g722 then ast_translator_best_choice() would pick h264 as the
+	  best choice even though h264 is a video codec and Asterisk only supports
+	  translation of audio codecs.  When the audio starts flowing, there are
+	  warnings about a codec mismatch when the channel tries to write a frame to
+	  the peer.
+
+	  * Made ast_translator_best_choice() only select audio codecs.
+
+	  * Restore a check in channel.c:set_format() lost after v1.8 to prevent
+	  trying to set a non-audio codec.
+
+	  This is an intermediate patch for a series of patches aimed at improving
+	  translation path choices for ASTERISK-24841.
+
+	  This patch is a complete enough fix for ASTERISK-21777 as the v11 version
+	  of ast_translator_best_choice() does the same thing.  However, chan_sip.c
+	  still somehow tries to call ast_codec_choose() which then calls
+	  ast_best_codec() with a capability set that doesn't contain any audio
+	  formats for the incoming call.  The remaining warning message seems to be
+	  a benign transient.
+
+	  ASTERISK-21777 #close
+	  Reported by: Nick Ruggles
+
+	  ASTERISK-24380 #close
+	  Reported by: Matt Jordan
+
+	  Review: https://reviewboard.asterisk.org/r/4605/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434614 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-10 07:35 +0000 [efef678411]  Y Ateya (License 6693)
+
+	* channels/chan_iax2: Improve POKE expiration time calculation for lossy networks
+
+	  POKE is used to check for peer availability; however, in networks with packet
+	  loss, the current calculations may result in POKE expiration times that are too
+	  short. This patch alters the expiration/retry time logic to take into account
+	  the last known qualify round trip time, as opposed to always using a static
+	  value for each peer.
+
+	  Review: https://reviewboard.asterisk.org/r/4536
+
+	  ASTERISK-22352 #close
+	  Reported by: Frederic Van Espen
+
+	  ASTERISK-24894 #close
+	  Reported by: Y Ateya
+	  patches:
+	    poke_noanswer_duration.diff submitted by Y Ateya (License 6693)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434564 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-09 07:47 +0000 [7c4efc490a]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix autological comparisons
+
+	  This fixes autological comparison warnings in the following:
+	   * chan_skinny: letohl may return a signed or unsigned value, depending on the
+	     macro chosen
+	   * func_curl: Provide a specific cast to CURLoption to prevent mismatch
+	   * cel: Fix enum comparisons where the enum can never be negative
+	   * enum: Fix comparison of return result of dn_expand, which returns a signed
+	     int value
+	   * event: Fix enum comparisons where the enum can never be negative
+	   * indications: tone_data.freq1 and freq2 are unsigned, and hence can never be
+	     negative
+	   * presencestate: Use the actual enum value for INVALID state
+	   * security_events: Fix enum comparisons where the enum can never be negative
+	   * udptl: Don't bother to check if the return value from encode_length is less
+	     than 0, as it returns an unsigned int
+	   * translate: Since the parameters are unsigned int, don't bother checking
+	     to see if they are negative. The cast to unsigned int would already blow
+	     past the matrix bounds.
+
+	  Review: https://reviewboard.asterisk.org/r/4533
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4533.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434469 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 21:03 +0000 [6b399f72dc]  Stefan Engström (License 6691)
+
+	* apps/app_queue: Prevent possible crash when evaluating queue penalty rules
+
+	  Although it only occurred once, a crash occurred when a queue attempted to
+	  evaluate a queue penalty rule that appeared to have already been destroyed.
+	  In many locations in app_queue, a test is done to see if qe->pr is NULL;
+	  however, when we dispose of a queue's penalty rules, we don't set the pointer
+	  to NULL after free'ing it. This patch does that to prevent any dangling
+	  pointers from lingering on the queue object.
+
+	  Review: https://reviewboard.asterisk.org/r/4522
+
+	  ASTERISK-23319 #close
+	  Reported by: Vadim
+	  patches:
+	    rb4552.patch submitted by Stefan Engström (License 6691)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434448 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 11:11 +0000 [f69e1b4a17]  mhej (license 6085)
+
+	* Security/tcptls: MitM Attack potential from certificate with NULL byte in CN.
+
+	  When registering to a SIP server with TLS, Asterisk will accept CA signed
+	  certificates with a common name that was signed for a domain other than the
+	  one requested if it contains a null character in the common name portion of
+	  the cert. This patch fixes that by checking that the common name length
+	  matches the the length of the content we actually read from the common name
+	  segment. Some certificate authorities automatically sign CA requests when
+	  the requesting CN isn't already taken, so an attacker could potentially
+	  register a CN with something like www.google.com\x00www.secretlyevil.net
+	  and have their certificate signed and Asterisk would accept that certificate
+	  as though it had been for www.google.com - this is a security fix and is
+	  noted in AST-2015-003.
+
+	  ASTERISK-24847 #close
+	  Reported by: Maciej Szmigiero
+	  Patches:
+	   asterisk-null-in-cn.patch submitted by mhej (license 6085)
+	  ........
+
+	  Merged revisions 434337 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434338 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 09:53 +0000 [ed191ca32c]  Matthew Jordan <mjordan at digium.com>
+
+	* chan_iax2: Fix mixup of code/declarations
+
+	  Interestingly enough, clang doesn't care about this.
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434334 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 06:59 +0000 [e61628db7b]  Jaco Kroon (License 5671)
+
+	* chan_iax2: Fix crash caused by unprotected access to iaxs[peer->callno]
+
+	  This patch fixes an access to the peer callnumber that is unprotected by a
+	  corresponding mutex. The peer->callno value can be changed by multiple threads,
+	  and all data inside the iaxs array must be procted by a corresponding lock
+	  of iaxsl.
+
+	  The patch moves the unprotected access to a location where the mutex is
+	  safely obtained.
+
+	  Review: https://reviewboard.asterisk.org/r/4599/
+
+	  ASTERISK-21211 #close
+	  Reported by: Jaco Kroon
+	  patches:
+	    asterisk-11.2.1-iax2_poke-segfault.diff submitted by Jaco Kroon (License 5671)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434291 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 06:51 +0000 [7dd8c34e82]  Valentin Vidić (License 6697)
+
+	* chan_sip: Handle IPv4 mapped IPv6 clients when NAT is enabled
+
+	  When udpbindaddr is set to the IPv6 bind all address of '::', Asterisk will
+	  attempt to handle both IPv4 and IPv6 addresses, although the information will
+	  be stored in a struct with an AF_INET6 address type. However, the current
+	  NAT handling code won't handle the IPv4 mapped IPv6 addresses correctly.
+	  This patch adds an additional check for the mapped address case, allowing
+	  the NAT code to handle clients even when the address is IPv6.
+
+	  Review: https://reviewboard.asterisk.org/r/4563/
+
+	  ASTERISK-18032 #close
+	  Reported by: Christoph Timm
+	  patches:
+	    nat_with_ipv6.diff submitted by Valentin Vidić (License 6697)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434288 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-08 06:42 +0000 [97c68d8d3a]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix pointer-bool-converesion warnings
+
+	  This patch fixes several warnings pointed out by the clang compiler.
+	  * app_minivm: Fixed evaluation of etemplate->locale, which will always
+	    evaluate to 'true'. This patch changes the evaluation to use
+	    ast_strlen_zero.
+	  * app_queue:
+	    - Fixed evaluation of qe->parent->monfmt, which always evaluates to
+	      true. Instead, we just check to see if the dereferenced pointer
+	      evaluates to true.
+	    - Fixed evaluation of mem->state_interface, wrapping it with a call to
+	      ast_strlen_zero.
+
+	  Review: https://reviewboard.asterisk.org/r/4541
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4541.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434285 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-07 14:34 +0000 [3ade8a146a]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* Voicemail API: fix handling of full mailbox
+
+	  Changes to an error code in svn r115582 was
+	  the accidental cause of message deletion on
+	  a full (by maxmsg) Old mailbox folder.
+
+	  This restores the original handling marking
+	  the message to be left in the Inbox.
+
+	  ASTERISK-24942 #close
+	  Review: https://reviewboard.asterisk.org/r/4595/
+
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434260 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 21:09 +0000 [dc63b9fcbc]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix sometimes-initialized warning in func_math
+
+	  This patch fixes a bug in a unit test in func_math where a variable could be
+	  passed to ast_free that wasn't allocated. This patch corrects the issue and
+	  ensures that we only attempt to free a variable if we previously allocated
+	  it.
+
+	  Review: https://reviewboard.asterisk.org/r/4552
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4552.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434190 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 20:58 +0000 [c224c44a16]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix non-literal-null-conversion warnings
+
+	  Clang will flag errors when a char pointer is set to '\0', as opposed to a
+	  value that the char pointer points to. This patch fixes this warning
+	  in a variety of locations.
+
+	  Review: https://reviewboard.asterisk.org/r/4551
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4551.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434187 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 13:58 +0000 [5e46127e17]  George Joseph <george.joseph at fairview5.com>
+
+	* build: Fixes for gcc 5 compilation
+
+	  These are fixes for compilation under gcc 5.0...
+
+	  chan_sip.c:    In parse_request needed to make 'lim' unsigned.
+	  inline_api.h:  Needed to add a check for '__GNUC_STDC_INLINE__' to detect C99 
+	                 inline semantics (same as clang).
+	  ccss.c:        In ast_cc_set_parm, needed to fix weird comparison.
+	  dsp.c:         Needed to work around a possible compiler bug.  It was throwing 
+	                 an array-bounds error but neither
+	                 sgriepentrog, rmudgett nor I could figure out why.
+	  manager.c:     In action_atxfer, needed to correct an array allocation.
+
+	  This patch will go to 11, 13, trunk.
+
+	  Review: https://reviewboard.asterisk.org/r/4581/
+	  Reported-by: Jeffrey Ollie
+	  Tested-by: George Joseph
+	  ASTERISK-24932 #close
+
+
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434113 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 13:07 +0000 [84948d5969]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Remove large chunks of unused code from extconf
+
+	  This patch fixes a warning caught by clang, in which it detected that large
+	  chunks of extconf were unused. Frankly, I wish we could pretend that all of
+	  extconf was unused, but alas, that is not yet the case.
+
+	  Review: https://reviewboard.asterisk.org/r/4553
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4553.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434093 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 13:03 +0000 [a061688239]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix sometimes-uninitialized warning in pbx_config
+
+	  This patch fixes a warning caught by clang, in which a char pointer could be
+	  assigned to before it was initialized. The patch re-organizes the code to
+	  ensure that the pointer is always initialized, even on off nominal paths.
+
+	  Review: https://reviewboard.asterisk.org/r/4529
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4529.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434090 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-06 12:51 +0000 [0437fd7330]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix format specified in framehook
+
+	  This patch fixes an invalid format specifier used in the formatting of an
+	  ERROR message in the framehook code. The format specifier specifies a
+	  type of 'unsigned short', but the argument passed to it is of type 'int'.
+	  The patch changes the format specifier to 'i'.
+
+	  Review: https://reviewboard.asterisk.org/r/4540
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4535.patch submitted by dkdegroot (License 6600)
+
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@434087 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-04-01 15:43 +0000 [695dcfbf8b]  Mark Michelson <mmichelson at digium.com>
+
+	* Backport revision 429223 from Asterisk 13
+
+	  The bug fixed by that patch exists in Asterisk 11 as
+	  well, so the fix should be applied there.
+
+	  When connecting to a remote Asterisk console, the buffer
+	  used to read the initial hostname/pid/version from the
+	  main Asterisk process did not ensure the input was
+	  NULL-terminated, and the buffer was small for certain
+	  use cases. This patch expands the buffer to be 256
+	  bytes and ensures the input it reads is NULL-terminated.
+
+	  ASTERISK-21854 #close
+	  Reported by klaus3000
+
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433919 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-31 11:47 +0000 [e159080c45]  Richard Mudgett <rmudgett at digium.com>
+
+	* chan_sip: Fix expression in unit test /channels/chan_sip/test_sip_rtpqos.
+
+	  Fix misplaced parentheses in original fabs() expression.
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433816 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-30 06:40 +0000 [2430daa931]  Corey Farrell <git at cfware.com>
+
+	* Fix an ABI compatibility issue with ast_log_safe for modules.
+
+	  Binary modules are sometimes built against the latest release of
+	  Asterisk in each branch, and need to be compatible with all
+	  releases of that branch.  This change ensures that utils.h only
+	  uses ast_log_safe from the core.  For modules and utilities ast_log
+	  is used instead.
+
+	  Review: https://reviewboard.asterisk.org/r/4548/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433772 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-29 21:44 +0000 [297b8df31b]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix -Wabsolute-value warnings
+
+	  This patch fixes several warnings caught by clang - in this case, usage of the
+	  abs function on non-integer values. This patch uses labs and fabs, as
+	  appropriate, in the various affected files.
+
+	  Review: https://reviewboard.asterisk.org/r/4525
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4525.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433749 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-29 21:35 +0000 [b8d7aa442d]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix invalid enum conversion
+
+	  This patch fixes some invalid enum conversion warnings caught by clang. In
+	  particular, several functions in chan_sip mixed usage of the st_refresher_param
+	  enum and st_refresher enum. This patch corrects that.
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4535.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433746 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-29 21:28 +0000 [03ab5de700]  Matthew Jordan <mjordan at digium.com>
+
+	* main/stdtime/localtime: Fix warning introduced in r433720
+
+	  The patch in r433720 caused a warning to be kicked back by gcc. It occurred
+	  due to this check in unistd.h:
+
+	      if (__nbytes > __bos0 (__buf))
+	          return __read_chk_warn (__fd, __buf, __nbytes, __bos0 (__buf));
+
+	  That is, if __nbytes is greater than the result of GCC's built-in object size
+	  for the struct, we'll kick back a warning.
+
+	  As it turns out, this is because there is an error in the code in the patch.
+	  We are passing the address of the pointer to the struct, not iev, which is a
+	  pointer to the struct. Hence, the number of bytes is probably going to be lot
+	  larger than the number of bytes that make up a pointer! This patch changes
+	  the code just read from the pointer to the struct - which fixes the warning.
+
+	  ASTERISK-24917
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433743 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-29 20:56 +0000 [05183c0025]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Ignore -Wunused-command-line-argument
+
+	  Asterisk's build system has a tendency to pass include directives for libraries
+	  to everything compiled within a particular group of source files. This means
+	  we pass the header for libxml2 to things that don't necessarily need it. As a
+	  result, we ignore this particular warning.
+
+	  Review: https://reviewboard.asterisk.org/r/4545/
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4545.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433720 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-29 20:51 +0000 [af0a60c0f7]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix warning for -Wgnu-variable-sized-type-not-at-end
+
+	  This patch fixes a warning caught by clang, wherein a variable sized struct is
+	  not located at the end of a struct. While the code in question actually
+	  expected this, this is a good warning to watch for. Hence, this patch refactors
+	  the code in question to not have two variable length elements in the same
+	  struct.
+
+	  Review: https://reviewboard.asterisk.org/r/4530/
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4530.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433717 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-28 07:53 +0000 [29e6597f0b]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix a variety of "unused" warnings
+
+	  This patch fixes the -Wunused-value -Wunused-variable -Wunused-const-variable
+	  errors caught by clang. Specifically:
+
+	  * apps/app_queue.c: removed unused qpm_cmd_usage[], qum_cmd_usage[],
+	                      qsmp_cmd_usage[]
+	  * cel/cel_sqlite3_custom.c: removed unused name[] = "cel_sqlite3_custom"
+	  * codecs/gsm/src/gsm_create.c: removed unused ident[] = "$Header$"
+	  * funcs/func_env.c:729: Fixed ast_str_append_substr.
+	  * main/editline/np/strlcat.c: removed unused rcsid variable
+	  * main/editline/np/strlcpy.c: removed unused rcsid variable
+	  * utils/conf2ael.c: removed unused cfextension_states
+	  * utils/extconf.c: removed unused cfextension_states
+
+	  Review: https://reviewboard.asterisk.org/r/4526
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4526.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433693 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-28 07:47 +0000 [baa010e83d]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix -Wself-assign
+
+	  Assigning a variable to itself isn't super useful. However, the WAV format
+	  modules make use of this in order to perform byte endian checks. This patch
+	  works around the warning by only performing the self assignment if we are
+	  going to do more than just assign it to ourselves. Which is odd, but true.
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4544.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433690 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-28 07:39 +0000 [844be81760]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix -Wparantheses-equality warnings
+
+	  Clang will treat ((a == b)) as a warning, as it reasonably expects that the
+	  developer may have intended to write (a == b) or ((a = b)). This patch cleans
+	  up all instances where equality, not assignment, was intended between two
+	  parantheses.
+
+	  Review: https://reviewboard.asterisk.org/r/4531/
+
+	  ASTERISK-24917
+	  Repoted by: dkdegroot
+	  patches:
+	    rb4531.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433687 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-28 07:30 +0000 [dc6249a271]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix -Wbitfield-constant-conversion warning
+
+	  In chan_iax2, we attempt to assign a -1 to a bitfield. This gets caught by
+	  clang, as it will truncate the -1 to a 1 implicitly.
+
+	  Instead, we just assign the value a '1'.
+
+	  Review: https://reviewboard.asterisk.org/r/4537/
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4537.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433683 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-28 07:17 +0000 [297f7b16ff]  dkdegroot (License 6600)
+
+	* clang compiler warnings: Fix -Wunused-function
+
+	  This patch fixes clang compilers warnings for unused functions. Specifically:
+	   * channels/chan_iax2: removed user_ref function
+	   * main/dsp.c: removed goertzel_update function
+
+	  Review: https://reviewboard.asterisk.org/r/4527
+
+	  ASTERISK-24917
+	  Reported by: dkdegroot
+	  patches:
+	    rb4527.patch submitted by dkdegroot (License 6600)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433678 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-27 07:25 +0000 [cd421a61ad]  Corey Farrell <git at cfware.com>
+
+	* Fix link error for utils/aelparse.
+
+	  Use the standard ast_log instead of ast_log_safe for STANDALONE programs.
+
+	  Review: https://reviewboard.asterisk.org/r/4538/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433549 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-27 02:06 +0000 [327e29df6c]  Corey Farrell <git at cfware.com>
+
+	* Improved and portable ast_log recursion avoidance
+
+	  This introduces a new logger routine ast_log_safe.  This routine should be
+	  used for all error messages in code that can be run as a result of ast_log.
+	  ast_log_safe does nothing if run recursively.  All error logging in
+	  astobj2.c, strings.c and utils.h have been switched to ast_log_safe.
+
+	  This required adding support for raw threadstorage.  This provides direct
+	  access to the void* pointer in threadstorage.  In ast_log_safe, NULL is used
+	  to signify that this thread is not already running ast_log_safe, (void*)1 when
+	  it is already running.  This was done since it's critical that ast_log_safe
+	  do nothing that could log during recursion checking.
+
+	  ASTERISK-24155 #close
+	  Reported by: Timo Teräs
+	  Review: https://reviewboard.asterisk.org/r/4502/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-26 18:04 +0000 [3e85c1d2dd]  Corey Farrell <git at cfware.com>
+
+	* Fix compile errors caused by r4500 / r4501.
+
+	  * Add ast_register_cleanup to utils/clicompat.c to deal with
+	    any utils that copy sources from main.
+	  * Asterisk 13+: remove unused variables from core_local.c.
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433499 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-26 17:16 +0000 [aad1694fd4]  Corey Farrell <git at cfware.com>
+
+	* Replace most uses of ast_register_atexit with ast_register_cleanup.
+
+	  Since 'core stop now' and 'core restart now' do not stop modules,
+	  it is unsafe for most of the core to run cleanups.  Originally all
+	  cleanups used ast_register_atexit, and were only changed when it
+	  was shown to be unsafe.  ast_register_atexit is now used only when
+	  absolutely required to prevent corruption and close child processes.
+
+	  Exceptions that need to use ast_register_atexit:
+	  * CDR: Flush records.
+	  * res_musiconhold: Kill external applications.
+	  * AstDB: Close the DB.
+	  * canary_exit: Kill canary process.
+
+	  ASTERISK-24142 #close
+	  Reported by: David Brillert
+
+	  ASTERISK-24683 #close
+	  Reported by: Peter Katzmann
+
+	  ASTERISK-24805 #close
+	  Reported by: Badalian Vyacheslav
+
+	  ASTERISK-24881 #close
+	  Reported by: Corey Farrell
+
+	  Review: https://reviewboard.asterisk.org/r/4500/
+	  Review: https://reviewboard.asterisk.org/r/4501/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433495 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-26 12:00 +0000 [6ceccec5b3]  Kevin Harwell <kharwell at digium.com>
+
+	* app_confbridge: file playback blocks dtmf
+
+	  Attempting to execute DTMF in a confbridge while file playback (prompt,
+	  announcement, etc) is occurring is not allowed. You have to wait until
+	  the sound file has completed before entering DTMF. This patch fixes it
+	  so that app_confbridge now monitors for dtmf key presses during menu
+	  driven file playback. If a key is pressed playback stops and it executes
+	  the matched menu option.
+
+	  ASTERISK-24864 #close
+	  Reported by: Steve Pitts
+	  Review: https://reviewboard.asterisk.org/r/4477/
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433445 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-25 10:29 +0000 [e1b35138b9]  Simon Arlott (License 5756)
+
+	* res_xmpp: Buddies are always auto-registered when processing the roster
+
+	  Due to a quirk in the configuration handling of res_xmpp, the 'autoregister'
+	  setting was never actually processed. This was due to not properly copying
+	  over the global settings to the client settings when applying the
+	  configuration to the run-time object.
+
+	  ASTERISK-14233
+	  ASTERISK-24780 #close
+	  Reported by: Simon Arlott
+	  patches:
+	    asterisk-13.1.0-24780 uploaded by Simon Arlott (License 5756)
+
+
+	  git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@433395 65c4cc65-6c06-0410-ace0-fbb531ad65f3
+
+2015-03-23  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.17.0-rc1 Released.
+
+2015-03-22 23:55 +0000 [r433245-433268]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_queue.c: Fix compilations errors on 64-bit OpenBSD
+	  systems In versiong 5.5, OpenBSD went to 64-bit time values. This
+	  requires a cast to (long) when printing members of certain time
+	  structs. Review: https://reviewboard.asterisk.org/r/4507
+	  ASTERISK-24879 #close Reported by: snuffy Tested by: snuffy
+	  patches: openbsd-time64.diff uploaded by snuffy (License 5024)
+
+	* main/asterisk.c, main/xmldoc.c: Fix compilation issues for
+	  OpenBSD This patch addresses compilation issues for OpenBSD.
+	  Specifically, it addresses: * It allows including <sys/vmmeter.h>
+	  in asterisk.c * Provides a needed (size_t) cast in xmldoc.c In
+	  13+, it also addresses a conditional inclusion in loader.c.
+	  Review: https://reviewboard.asterisk.org/r/4506 ASTERISK-24880
+	  #close Reported by: snuffy Tested by: snuffy patches:
+	  misc-openbsd.diff uploaded by snuffy (License 5024)
+
+2015-03-19 19:19 +0000 [r433173]  Matthew Jordan <mjordan at digium.com>
+
+	* tests/test_func_file.c, funcs/func_env.c: funcs/func_env: Fix
+	  regression caused in FILE read operation When r432935 was merged,
+	  it did correctly fix a situation where a FILE read operation on
+	  the middle of a file buffer would not read the requested length
+	  in the parameters passed to the FILE function. Unfortunately, it
+	  would also allow the FILE function to append more bytes than what
+	  was available in the buffer if the length exceeded the end of the
+	  buffer length. This patch takes the minimum of the remaining
+	  bytes in the buffer along with the calculated length to append
+	  provided by the original patch, and uses that as the length to
+	  append in the return result. This patch also updates the unit
+	  tests with the scenarios that were originally pointed out in
+	  ASTERISK-21765 that the original implementation treated
+	  incorrectly. ASTERISK-21765
+
+2015-03-19 10:19 +0000 [r433112-433122]  Corey Farrell <git at cfware.com>
+
+	* main/logger.c: logger: Apply default console logging when
+	  configuration cannot be loaded. When logger.conf is missing or
+	  invalid enable console logging and display an error message.
+	  ASTERISK-24817 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4497/
+
+	* channels/chan_sip.c: chan_sip: Fix dialog reference leaked to
+	  scheduler for reinvite_timeout. Release the scheduler reference
+	  to the dialog for reinvite timeout during dialog_unlink_all.
+	  ASTERISK-24876 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4491/
+
+2015-03-17 22:28 +0000 [r433086]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/utils.c, main/asterisk.c, main/xmldoc.c: Various: backport
+	  of bugfixes found via chaos Using DEBUG_CHAOS several instances
+	  of a null pointer crash, and one uninitialized variable were
+	  uncovered and fixed. Also added details on why Asterisk failed to
+	  initialize. This is a backport of the fixes from Asterisk 13.
+	  Review: https://reviewboard.asterisk.org/r/4468/
+
+2015-03-17 21:43 +0000 [r433056]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_externalivr.c, main/netsock2.c: Audit
+	  ast_sockaddr_resolve() usage for memory leaks. Valgrind found
+	  some memory leaks associated with ast_sockaddr_resolve(). Most of
+	  the leaks had already been fixed by earlier memory leak hunt
+	  patches. This patch performs an audit of ast_sockaddr_resolve()
+	  and found one more. * Fix ast_sockaddr_resolve() memory leak in
+	  apps/app_externalivr.c:app_exec(). * Made
+	  main/netsock2.c:ast_sockaddr_resolve() always set the addrs
+	  parameter for safety so the pointer will never be uninitialized
+	  on return. The same goes for
+	  res/res_pjsip_acl.c:extract_contact_addr(). Review:
+	  https://reviewboard.asterisk.org/r/4509/
+
+2015-03-14 02:27 +0000 [r432970]  Matthew Jordan <mjordan at digium.com>
+
+	* main/frame.c: main/frame: Don't report empty disallow values as
+	  an error In realtime, it is normal to have a database with both
+	  'allow' and 'disallow' columns in the schema. It is perfectly
+	  valid to have an 'allow' value of '!all,g722,ulaw,alaw' and no
+	  'disallow' value. Unlike in static conf files, you can't *not*
+	  provide the disallow value. Thus, the empty disallow value causes
+	  a spurious WARNING message, which is kind of annoying. This patch
+	  makes it so that a 'disallow' value with no ... value ... is
+	  ignored. Granted, you can still screw this up as well, as
+	  technically specifying 'disallow=all,!ulaw' allows only ulaw, and
+	  then you would have no 'allow' value in your database. But
+	  really, why would you do that? WHY? ASTERISK-16779 #close
+	  Reported by: Atis Lezdins
+
+2015-03-14 01:59 +0000 [r432944-432948]  Joshua Colp <jcolp at digium.com>
+
+	* funcs/func_curl.c: func_curl: Don't hold exclusive lock when
+	  performing HTTP request. This code originally kept a lock held
+	  when performing the HTTP request to ensure that the options
+	  provided to curl remain valid. This doesn't seem to be necessary
+	  these days and holding the lock caused requests to happen
+	  sequentially instead of in parallel. ASTERISK-18708 #close
+	  Reported by: Dave Cabot
+
+	* main/cli.c: core: Fix tab completion of "core set debug channel"
+	  CLI command. The "core set debug channel" CLI command mistakenly
+	  had source filenames added to its tab completion. This occurred
+	  because the CLI generator fell back to the "core set debug"
+	  command which permits setting debug at a source filename level.
+	  ASTERISK-21038 #close Reported by: Richard Kenner
+
+2015-03-14 01:21 +0000 [r432918-432935]  Matthew Jordan <mjordan at digium.com>
+
+	* funcs/func_env.c: FILE: fix retrieval of file contents when
+	  offset is specified The loop that reads in a file was not
+	  correctly using the offset when determining what bytes to append
+	  to the output. This patch corrects the logic such that the
+	  correct portion of the file is extracted when an offset is
+	  specified. ASTERISK-21765 Reported by: John Zhong Tested by: Matt
+	  Jordan, Di-Shi Sun patches: file_read_390821.patch uploaded by
+	  Di-Shi Sun (License 5076)
+
+	* apps/app_amd.c, configs/amd.conf.sample: apps/app_amd: Document
+	  maximum_word_length option; fix AMDCAUSE documentation This patch
+	  corrects the documentation for the AMD application. Specifically:
+	  * It documents the maximum_word_length option, which limits the
+	  maximum allowed length of a single utterance. * It clarifies the
+	  AMDCAUSE values MAXWORDS and MAXWORDLENGTH. MAXWORDLENGTH was
+	  documented as MAXWORDS, while MAXWORDS was undocumented. Thanks
+	  to the issue reporter, Frank DiGennaro, for pointing out the
+	  issues. ASTERISK-19470 #close Reported by: Frank DiGennaro
+
+2015-03-12 12:57 +0000 [r432807-432810]  Matthew Jordan <mjordan at digium.com>
+
+	* main/audiohook.c: main/audiohook: Update internal sample rate on
+	  reads When an audiohook is created (which is used by the various
+	  Spy applications and Snoop channel in Asterisk 13+), it initially
+	  is given a sample rate of 8kHz. It is expected, however, that
+	  this rate may change based on the media that passes through the
+	  audiohook. However, the read/write operations on the audiohook
+	  behave very differently. When a frame is written to the
+	  audiohook, the format of the frame is checked against the
+	  internal sample rate. If the rate of the format does not match
+	  the internal sample rate, the internal sample rate is updated and
+	  a new SLIN format is chosen based on that sample rate. This works
+	  just fine. When a frame is read, however, we do something quite
+	  different. If the format rate matches the internal sample rate,
+	  all is fine. However, if the rates don't match, the audiohook
+	  attempts to "fix up" the number of samples that were requested.
+	  This can result in some seriously large number of samples being
+	  requested from the read/write factories. Consider the worst case
+	  - 192kHz SLIN. If we attempt to read 20ms worth of audio produced
+	  at that rate, we'd request 3840 samples (192000 / (1000 / 20)).
+	  However, if the audiohook is still expecting an internal sample
+	  rate of 8000, we'll attempt to "fix up" the requested samples to:
+	  samples_converted = samples * (ast_format_get_sample_rate(format)
+	  / (float) audiohook->hook_internal_samp_rate); which is: 92160 =
+	  3840 * (192000 / 8000) This results in us attempting to read
+	  92160 samples from our factories, as opposed to the 3840 that we
+	  actually wanted. On a 64-bit machine, this miraculously survives
+	  - despite allocating up to two buffers of length 92160 on the
+	  stack. The 32-bit machines aren't quite so lucky. Even in the
+	  case where this works, we will either (a) get way more samples
+	  than we wanted; or (b) get about 3840 samples, assuming the
+	  timing is pretty good on the machine. Either way, the calculation
+	  being performed is wrong, based on the API users expectations. My
+	  first inclination was to allocate the buffers on the heap. As it
+	  is, however, there's at least two drawbacks with doing this: (1)
+	  It's a bit complicated, as the size of the buffers may change
+	  during the lifetime of the audiohook (ew). (2) The stack is
+	  faster (yay); the heap is slower (boo). Since our calculation is
+	  flat out wrong in the first place, this patch fixes this issue by
+	  instead updating the internal sample rate based on the format
+	  passed into the read operation. This causes us to read the
+	  correct number of samples, and has the added benefit of setting
+	  the audihook with the right SLIN format. Note that this issue was
+	  caught by the Asterisk Test Suite as a result of r432195 in the
+	  13 branch. Because this issue is also theoretically possible in
+	  Asterisk 11, the change is being made here as well. Review:
+	  https://reviewboard.asterisk.org/r/4475/
+
+	* makeopts.in, Makefile, include/asterisk/utils.h, configure,
+	  main/Makefile, configure.ac, include/asterisk/inline_api.h: Add
+	  support for the clang compiler; update RAII_VAR to use
+	  BlocksRuntime RAII_VAR, which is used extensively in Asterisk to
+	  manage reference counted resources, uses a GCC extension to
+	  automatically invoke a cleanup function when a variable loses
+	  scope. While this functionality is incredibly useful and has
+	  prevented a large number of memory leaks, it also prevents
+	  Asterisk from being compiled with clang. This patch updates the
+	  RAII_VAR macro such that it can be compiled with clang. It makes
+	  use of the BlocksRuntime, which allows for a closure to be
+	  created that performs the actual cleanup. Note that this does not
+	  attempt to address the numerous warnings that the clang compiler
+	  catches in Asterisk. Much thanks for this patch goes to: * The
+	  folks on StackOverflow who asked this question and Leushenko for
+	  providing the answer that formed the basis of this code:
+	  http://stackoverflow.com/questions/24959440/rewrite-gcc-cleanup-macro-with-nested-function-for-clang
+	  * Diederik de Groot, who has been extremely patient in working on
+	  getting this patch into Asterisk. Review:
+	  https://reviewboard.asterisk.org/r/4370/ ASTERISK-24133
+	  ASTERISK-23666 ASTERISK-20399 ASTERISK-20850 #close Reported by:
+	  Diederik de Groot patches: RAII_CLANG.patch uploaded by Diederik
+	  de Groot (License 6600)
+
+2015-03-10 21:32 +0000 [r432691-432720]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_config_odbc.c: res/res_config_odbc: Fix improper escaping
+	  of backslashes with MySQL When escaping backslashes with MySQL,
+	  the proper way to escape the characters in a LIKE clause is to
+	  escape the '\' four times, i.e., '\\\\'. To quote the MySQL
+	  manual: "Because MySQL uses C escape syntax in strings (for
+	  example, “\n” to represent a newline character), you must double
+	  any “\” that you use in LIKE strings. For example, to search for
+	  “\n”, specify it as “\\n”. To search for “\”, specify it as
+	  “\\\\”; this is because the backslashes are stripped once by the
+	  parser and again when the pattern match is made, leaving a single
+	  backslash to be matched against." ASTERISK-24808 #close Reported
+	  by: Javier Acosta patches: res_config_odbc.diff uploaded by
+	  Javier Acosta (License 6690)
+
+	* apps/app_voicemail.c: app_voicemail: Fix crash with IMAP backends
+	  when greetings aren't present When an IMAP backend is in use and
+	  greetings are set to be used, but aren't present for a user in
+	  their IMAP folder, Asterisk will crash. This occurs due to the
+	  mailstream being set to the 'greetings' folder and being left in
+	  that particular state, regardless of the success/failure of the
+	  attempt to access the folder the mailstream points to. Later
+	  access of the mailstream assumes that it points to the 'INBOX'
+	  (or some other folder), resulting in either a crash (if the
+	  greetings folder didn't exist and the mailstream is invalid) or
+	  an inability to read messages from the 'INBOX' folder. This patch
+	  restores the mailstream to its correct state after accessing the
+	  greetings. This fixes the crash, and sets the mailstream to the
+	  state that VoiceMailMain expects. Note that while ASTERISK-23390
+	  also contained a patch for this issue, the patch on
+	  ASTERISK-24786 is the one being merged here. Review:
+	  https://reviewboard.asterisk.org/r/4459/ ASTERISK-23390 #close
+	  Reported by: Ben Smithurst ASTERISK-24786 #close Reported by:
+	  Graham Barnett Tested by: Graham Barnett patches:
+	  app_voicemail.c.patch.SIGSEGV3rev2 uploaded by Graham Barnett
+	  (License 6685)
+
+	* main/stdtime/localtime.c: localtime: Fix file descriptor leak on
+	  kqueue(2) systems The localtime management in the Asterisk core
+	  contains a thread that watches for changes in the local timezone.
+	  On systems where the directory containing /etc/localtime is
+	  modified frequently, the thread monitoring the changes will be
+	  woken up to determine if any changes in timezone have occurred.
+	  When using kqueue(2), this can cause a leak of file descriptors
+	  due to some improper management of resources. This patch updates
+	  the kqueue(2) handling in localtime, such that is no longer leaks
+	  resources. Review: https://reviewboard.asterisk.org/r/4450/
+	  ASTERISK-24739 #close Reported by: Ed Hynan patches:
+	  11.15.0-u.diff uploaded by Ed Hynan (Licnese 6680) 11.7.0-u.diff
+	  uploaded by Ed Hynan (License 6680) svn-trunk-Jan-26-2015-u.diff
+	  uploaded by Ed Hynan (License 6680)
+
+2015-03-06 19:52 +0000 [r432526-432530]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/sig_analog.h, UPGRADE.txt: chan_dahdi/sig_analog: Fix
+	  distinctive ring detection to suck less. The distinctive ring
+	  feature interferes with detecting Caller ID and appears to have
+	  been broken for years. What happens is if you have a ring-ring
+	  cadence as used in the UK you get too many DAHDI events for the
+	  distinctive ring pattern array and Caller ID detection is
+	  aborted. I think when Zapata/DAHDI added the ring begin event it
+	  broke distinctive ring. More events happen than before and the
+	  code does no filtering of which event times are recorded in the
+	  pattern array. * Made distinctive ring only record the ringt
+	  count when the ring ends instead of on just any DAHDI event.
+	  Distinctive ring can be ring, ring-ring, ring-ring-ring, or
+	  different ring durations for the up to three rings. * Fixed the
+	  distinctive ring detection enable (chan_dahdi.conf option
+	  usedistinctiveringdetection) to be per port instead of somewhat
+	  per port and somewhat global. This has been broken since v1.8. *
+	  Fixed using the default distinctive ring context when the
+	  detected pattern does not match any configured dringX patterns.
+	  The default context did not get set when the previous call was a
+	  matched distinctive ring pattern and the current call is not
+	  matched. This has been broken since v1.8. * Made distinctive ring
+	  have no effect on Caller ID detection when it is disabled. Caller
+	  ID detection just monitors for 10 seconds before giving up. *
+	  Fixed leak of struct callerid_state memory when a polarity
+	  reversal during Caller ID detection causes the incoming call to
+	  be aborted. DAHDI-1143 AST-1545 ASTERISK-24825 #close Reported
+	  by: Richard Mudgett ASTERISK-17588 Reported by: Daniel Flounders
+	  Review: https://reviewboard.asterisk.org/r/4444/
+
+	* channels/chan_sip.c: chan_sip: Fix realtime locking inversion
+	  when poking a just built peer. When a realtime peer is built it
+	  can cause a locking inversion when the just built peer is poked.
+	  If the CLI command "sip show channels" is periodically executed
+	  then a deadlock can happen because of the locking inversion. *
+	  Push the peer poke off onto the scheduler thread to avoid the
+	  locking inversion of the just built realtime peer. AST-1540
+	  ASTERISK-24838 #close Reported by: Richard Mudgett Review:
+	  https://reviewboard.asterisk.org/r/4454/
+
+2015-03-05 16:35 +0000 [r432484]  George Joseph <george.joseph at fairview5.com>
+
+	* apps/app_voicemail.c: app_voicemail: Fix compile breaking in
+	  app_voicemail with IMAP_STORAGE. There is a leftover "assert" in
+	  app_voicemail/__messagecount that references variables that don't
+	  exist. This causes the compile to fail when --enable-dev-mode and
+	  IMAP_STORAGE are selected. This patch removes the assert.
+	  Tested-by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/4461/
+
+2015-02-26 17:06 +0000 [r432362]  Kevin Harwell <kharwell at digium.com>
+
+	* apps/app_chanspy.c, main/channel.c: app_chanspy, channel: fix
+	  frame leaks Fixed a couple of frame leaks that were found during
+	  testing. ASTERISK-24828 #close Reported by: John Hardin Review:
+	  https://reviewboard.asterisk.org/r/4445/
+
+2015-02-26 04:56 +0000 [r432239-432341]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/Makefile, apps/Makefile: make: Remove 'res_features'
+	  from libraries to link against with cygwin/mingw32 Both the apps
+	  and channels Makefiles still listed 'res_features' as modules to
+	  link against when compiling for cygwin or mingw32. This module
+	  hasn't existed for quite some time. ASTERISK-18105 #close
+	  Reported by: feyfre
+
+	* channels/chan_sip.c: channels/chan_sip: Don't send a BYE after
+	  final response when PBX thread fails When Asterisk fails to start
+	  a PBX thread for a new channel - for example, when the maxcalls
+	  setting in asterisk.conf is exceeded - we currently send a final
+	  response, and then attempt to send a BYE request to the UA. Since
+	  that's all sorts of wrong, this patch fixes that by setting
+	  sipalreadygone on the sip_pvt such that we don't get stuck
+	  sending BYE requests to something that does not want it. Note
+	  that this patch is a slight modification of the one on
+	  ASTERISK-15434. For clarity, it explicitly calls sipalreadygone
+	  with the calls to transmit a final response. ASTERISK-21845
+	  ASTERISK-15434 #close Reported by: Makoto Dei Tested by: Matt
+	  Jordan patches: sip-pbxstart-failed.patch uploaded by Makoto Dei
+	  (License 5027)
+
+	* configure, configure.ac: configure: Promote SQLite3 "not
+	  installed" warning to error Since Asterisk won't build without
+	  the library, not having it is definitely an error. Thanks to Kyle
+	  Kurz for pointing this out.
+
+	* channels/chan_sip.c: channels/chan_sip: Clarify WARNING message
+	  in mismatched SRTP scenario When we receive an SDP as part of an
+	  offer/answer for a peer/friend has been configured to require
+	  encryption, and that SDP offer/answer failed to provide
+	  acceptable crypto attributes, we currently issue a WARNING that
+	  uses the phrase "we" and "requested". In this case, both of those
+	  terms are ambiguous - the user will probably think "we" is
+	  Asterisk (it most likely isn't) and it may not be a "request", so
+	  much as an SDP that was received in some fashion. This patch
+	  makes the WARNING messages slightly less bad and a bit more
+	  accurate as well. ASTERISK-23214 #close Reported by: Rusty Newton
+
+	* channels/sip/sdp_crypto.c: channels/sip/sdp_crypto: Handle SRTP
+	  keys negotiated with key lifetime/MKI Prior to this patch, SDP
+	  offers negotiating SDES-SRTP crypto attributes would be rejected
+	  if those crypto attributes contained either a key lifetime or a
+	  MKI parameter. While from a theoretical point of view this was
+	  defensible - Asterisk does not support key lifetimes or multiple
+	  crypto keys - from a practical point of view, this is quite a
+	  problem. A large number of endpoints offer lifetimes/MKI, which
+	  Asterisk can tolerate so long as it doesn't actually have to
+	  support anything more than a single key or refresh the key. In
+	  reality, this is (so far as we've seen) always the case. This
+	  patch is a forward port of Olle's work in the
+	  lingon-srtp-key-lifetime-1.8 branch. To quote Olle from
+	  ASTERISK-17721, it handles lifetime/MKI parameters in the
+	  following fashion: > The Lingon branch now handle lifetime and
+	  MKI parameters. > > We only accept lifetimes up to max for the
+	  crypto and higher than 10 hours > for packetization of 20 ms (50
+	  pps). > > We only handle MKI with index 1. > > We do not really
+	  bother with counting packets and reinviting at end of > lifetime,
+	  so the min of 10 hours kind of takes care of most calls. If there
+	  > are longer ones, we rely on the other side for re-invites. > >
+	  It's still not perfect, but I personally think this is an
+	  improvement. A > configuration option for minimum lifetime
+	  accepted could be added. When the patch was ported forward, I
+	  decided against adding a configuration option as Olle's handling
+	  was more than sufficient for every case I've seen come through
+	  the issue tracker or through interoperability testing. We can
+	  revisit that decision if it proves to be false. A few small other
+	  tweaks were made to the surrounding code to reduce indentation
+	  and provide better type safety for the 'tag' parameter. Review:
+	  https://reviewboard.asterisk.org/r/4419/ Review:
+	  https://reviewboard.asterisk.org/r/4418/ ASTERISK-17721 #close
+	  Reported by: Terry Wilson ASTERISK-17899 #close Reported by:
+	  Dwayne Hubbard patches: lingon-srtp-key-lifetime-1.8.diff
+	  uploaded by oej (License 5267) ASTERISK-20233 Reported by: tootai
+	  ASTERISK-22748 Reported by: Alejandro Mejia
+
+2015-02-25 20:43 +0000 [r432236]  David M. Lee <dlee at digium.com>
+
+	* res/res_http_websocket.c: Increase WebSocket frame size and
+	  improve large read handling Some WebSocket applications, like
+	  [chan_respoke][], require a larger frame size than the default
+	  8k; this patch bumps the default to 16k. This patch also fixes
+	  some problems exacerbated by large frames. The sanity counter was
+	  decremented on every fread attempt in ws_safe_read(), regardless
+	  of whether data was read from the socket or not. For large
+	  frames, this could result in loss of sanity prior to reading the
+	  entire frame. (16k frame / 1448 bytes per segment = 12 segments).
+	  This patch changes the sanity counter so that it only decrements
+	  when fread() doesn't read any bytes. This more closely matches
+	  the original intention of ws_safe_read(), given that the error
+	  message is "Websocket seems unresponsive". This patch also
+	  properly logs EOF conditions, so disconnects are no longer
+	  confused with unresponsive connections. [chan_respoke]:
+	  https://github.com/respoke/chan_respoke Review:
+	  https://reviewboard.asterisk.org/r/4431/
+
+2015-02-24 22:14 +0000 [r432198]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: channels/chan_sip: Fix crash when
+	  transmitting packet after thread shutdown When the monitor thread
+	  is stopped, its pthread ID is set to a specific value
+	  (AST_PTHREADT_STOP) so that later portions of the code can
+	  determine whether or not it is safe to manipulate the thread.
+	  Unfortunately, __sip_reliable_xmit failed to check for that
+	  value, checking instead only for AST_PTHREAD_STOP. Passing the
+	  invalid yet very specific value to pthread_kill causes a crash.
+	  This patch adds a check for AST_PTHREADT_STOP in
+	  __sip_reliable_xmit such that it doesn't attempt to poke the
+	  thread if the thread has already been stopped. ASTERISK-24800
+	  #close Reported by: JoshE
+
+2015-02-24 18:22 +0000 [r432174]  Kevin Harwell <kharwell at digium.com>
+
+	* bridges/bridge_softmix.c: bridge_softmix: G.729 codec license
+	  held When more than one call using the same codec type enters
+	  into a softmix bridge and no audio is present for a channel the
+	  bridge optimizes the out frame by using the same one for all
+	  channels with the same codec type. Unfortunately, when that
+	  number (channels with same codec type) dropped to <= 1 the codec
+	  was not dereferenced. At least not until all parties left the
+	  bridge. Thus in the case of G.729 the license was not released.
+	  This patch ensures that the codec is dereferenced immediately
+	  when the optimization no longer applies. ASTERISK-24797 #close
+	  Reported by: Luke Hulsey Review:
+	  https://reviewboard.asterisk.org/r/4429/
+
+2015-02-21 17:34 +0000 [r432098]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: apps/app_voicemail: Demote an ERROR message
+	  to a WARNING message When using IMAP voicemail with FreePBX, you
+	  will often get ERROR messages complaining about not being able to
+	  find a mailbox. This is due to how FreePBX handles voicemail
+	  mailboxes. Unfortunately, app_voicemail has to consider this a
+	  configuration error, as in any other system it would be
+	  indicative of someone misconfiguring their system. Regardless, a
+	  misconfiguration is a WARNING, and not an ERROR. This patch
+	  demotes the message so that system administrators can hopefully
+	  reduce some of the noise in their log files. Note that in the
+	  original patch this was made into a NOTICE, but that's a too
+	  forgiving. ASTERISK-24790 #close Reported by: Graham Barnett
+	  patches: app_voicemail.c.patch_noise uploaded by Graham Barnett
+	  (License 6685)
+
+2015-02-21 14:04 +0000 [r432078]  Joshua Colp <jcolp at digium.com>
+
+	* main/http.c: http: Add missing html tag to 'httpstatus'
+	  functionality. ASTERISK-24724 #close Reported by: Ashley Sanders
+
+2015-02-21 02:55 +0000 [r432054-432058]  Corey Farrell <git at cfware.com>
+
+	* main/loader.c: Allow shutdown to unload modules that register
+	  bucket scheme's or codec's. * Change __ast_module_shutdown_ref to
+	  be NULL safe (11+). * Allow modules that call
+	  ast_bucket_scheme_register or ast_codec_register to be unloaded
+	  during graceful shutdown only (13+ only). ASTERISK-24796 #close
+	  Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4428/
+
+	* include/asterisk/lock.h: asterisk/lock.h: Fix syntax errors for
+	  non-gcc OSX with 64-bit integers. Add a couple of missing closing
+	  brackets / parenthesis. ASTERISK-24814 #close Reported by: Corey
+	  Farrell Review: https://reviewboard.asterisk.org/r/4436/
+
+2015-02-20 17:43 +0000 [r432032]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_analog.c: chan_dahdi/sig_analog: Put log message
+	  strings on one line. With the log messages on one line, you can
+	  search for the log message seen in the log and expect to find it.
+
+2015-02-20 15:45 +0000 [r432012]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: apps/app_voicemail: Fix IMAP header
+	  compatibility issue with Microsoft Exchange When interfacing with
+	  Microsoft Exchange, custom headers will be returned as all lower
+	  case. Currently, the IMAP header code will fail to parse the
+	  returned custom headers, as it will be performing a case
+	  sensitive comparison. This can cause playback of messages to
+	  fail, as needed information - such as origtime - will not be
+	  present. This patch updates app_voicemail's header parsing code
+	  to perform a case insensitive lookup for the requested custom
+	  headers. Since the headers are specific to Asterisk, e.g.,
+	  'x-asterisk-vm-orig-time', and headers should be unique in an
+	  IMAP message, this should cause no issues with other systems.
+	  ASTERISK-24787 #close Reported by: Graham Barnett patches:
+	  app_voicemail.c.patch_MSExchange uploaded by Graham Barnett
+	  (License 6685)
+
+2015-02-19 21:23 +0000 [r431992]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c: chan_dahdi: Remove
+	  some dead code.
+
+2015-02-19 15:21 +0000 [r431936]  Matthew Jordan <mjordan at digium.com>
+
+	* main/tcptls.c: tcptls: Handle new OpenSSL compile time option to
+	  disable SSLv3 Some distributions are going to disable SSLv3 at
+	  compile time. This option can be checked using the directive
+	  OPENSSL_NO_SSL3_METHOD. This patch updates the TCP/TLS handling
+	  in Asterisk to look for that directive before attempting to use
+	  the SSLv3 specific methods. ASTERISK-24799 #close Reported by:
+	  Alexander Traud patches: no-ssl3-method.patch uploaded by
+	  Alexander Traud (License 6520)
+
+2015-02-19 01:59 +0000 [r431916]  Corey Farrell <git at cfware.com>
+
+	* channels/chan_iax2.c, main/sched.c, include/asterisk/sched.h:
+	  Create work around for scheduler leaks during shutdown. * Added
+	  ast_sched_clean_by_callback for cleanup of scheduled events that
+	  have not yet fired. * Run all pending peercnt_remove_cb and
+	  replace_callno events in chan_iax2. Cleanup of replace_callno
+	  events is only run 11, since it no longer releases any references
+	  or allocations in 13+. ASTERISK-24451 #close Reported by: Corey
+	  Farrell Review: https://reviewboard.asterisk.org/r/4425/
+
+2015-02-15 00:31 +0000 [r431788]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_mixmonitor.c: apps/app_mixmonitor: Move Test Event for
+	  MIXMONITOR_END to after it finishes The Test Event for
+	  MIXMONITOR_END - which signals that a MixMonitor has completed -
+	  technically fired before the filestream was closed. If a test
+	  used this to trigger a condition to verify that the file was
+	  written, it could result in a race condition where the file size
+	  would not be what the test expected. Luckily, no tests were using
+	  this (although they should have been). Since the test event
+	  needed to be moved after the point where the MixMonitor autochan
+	  has been destroyed, the test event no longer emits the channel
+	  name. Luckily, nothing needs it.
+
+2015-02-11 17:11 +0000 [r431673]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: channels/chan_sip: Fix RealTime error during
+	  SIP unregistration with MariaDB When a SIP device that has its
+	  registration stored in RealTime unregisters, the entry for that
+	  device is updated with blank values, i.e., "", indicating that it
+	  is no longer registered. Unfortunately, one of those values that
+	  is 'blanked' is the device's port. If the column type for the
+	  port is not a string datatype (the recommended type is integer),
+	  an ODBC or database error will be thrown. MariaDB does not coerce
+	  empty strings to a valid integer value. This patch updates the
+	  query run from chan_sip such that it replaces the port value with
+	  a value of '0', as opposed to a blank value. This is the value
+	  that other database backends coerce the empty string ("") to
+	  already, and the handling of reading a RealTime registration
+	  value from a backend already anticipates receiving a port of '0'
+	  from the backends. ASTERISK-24772 #close Reported by: Richard
+	  Miller patches: chan_sip.diff uploaded by Richard Miller (License
+	  5685)
+
+2015-02-11 16:46 +0000 [r431669]  Kevin Harwell <kharwell at digium.com>
+
+	* res/res_http_websocket.c: res_http_websocket: websocket write
+	  timeout fails to fully disconnect When writing to a websocket if
+	  a timeout occurred the underlying socket did not get
+	  closed/disconnected. This patch makes sure the websocket gets
+	  disconnected on a write timeout. ASTERISK-24701 #close Reported
+	  by: Matt Jordan Review: https://reviewboard.asterisk.org/r/4412/
+
+2015-02-11 15:38 +0000 [r431662]  Corey Farrell <git at cfware.com>
+
+	* bridges/bridge_builtin_features.c, include/asterisk/module.h,
+	  main/loader.c: Enable REF_DEBUG for ast_module_ref /
+	  ast_module_unref. Add ast_module_shutdown_ref for use by modules
+	  that can only be unloaded during graceful shutdown. When
+	  REF_DEBUG is enabled: * Add an empty ao2 object to struct
+	  ast_module. * Allocate ao2 object when the module is loaded. *
+	  Perform an ao2_ref in each place where mod->usecount is
+	  manipulated. * ao2_cleanup on module unload. ASTERISK-24479
+	  #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4141/
+
+2015-02-09 02:44 +0000 [r431617-431620]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/sip/include/sip.h, channels/chan_sip.c:
+	  channels/chan_sip: Ensure that a BYE is sent during INVITE
+	  w/Replaces transfer Consider a scenario where Alice and Bob have
+	  an established dialog with each other external to Asterisk. Bob
+	  decides to perform an attended transfer of Alice to Asterisk. In
+	  this case, Alice will send an INVITE with Replaces to Asterisk,
+	  where the Replaces specifies Bob's dialog with Asterisk. In this
+	  particular scenario, Asterisk will complete the transfer, but -
+	  since Bob's channel has had Alice masqueraded into it and is now
+	  a Zombie - a BYE request will not be sent. This patch fixes that
+	  issue by adding a new flag to chan_sip that tracks whether or not
+	  we have an INVITE with Replaces. If we do, the flag is used on
+	  the sip_pvt to ensure that a BYE request is sent, even if the
+	  channel has been masqueraded away. Review:
+	  https://reviewboard.asterisk.org/r/4362/ ASTERISK-22436 #close
+	  Reported by: Eelco Brolman Tested by: Jeremiah Gowdy, Kristian
+	  Høgh patches: asterisk-11-hangup-replaced-3.diff uploaded by
+	  Jeremiah Gowdy (License 6358)
+
+	* res/res_odbc.c: res/res_odbc: Remove unneeded queries when
+	  determining if a table exists This patch modifies the
+	  ast_odbc_find_table function such that it only performs a lookup
+	  of the requested table if the table is not already known. Prior
+	  to this patch, a queries would be executed against the database
+	  even if the table was already known and cached. Review:
+	  https://reviewboard.asterisk.org/r/4405/ ASTERISK-24742 #close
+	  Reported by: ibercom patches: patch.diff uploaded by ibercom
+	  (License 6599)
+
+2015-02-06 21:26 +0000 [r431582]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/config.c: config hooks: correct ref leaks This small patch
+	  fixes a ref leak when adding a config hook and cleans up the
+	  container on shutdown. Review:
+	  https://reviewboard.asterisk.org/r/4407
+
+2015-02-06  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.16.0 Released.
+
+2015-01-30  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.16.0-rc1 Released.
+
+2015-01-30 16:55 +0000 [r431423-431472]  Mark Michelson <mmichelson at digium.com>
+
+	* main/pbx.c: Backport memory leak fix in pbx.c from branch 13
+	  revision 431468
+
+	* channels/chan_sip.c: Use SIPS URIs in Contact headers when
+	  appropriate. RFC 3261 sections 8.1.1.8 and 12.1.1 dictate
+	  specific scenarios when we are required to use SIPS URIs in
+	  Contact headers. Asterisk's non-compliance with this could
+	  actually cause calls to get dropped when communicating with
+	  clients that are strict about checking the Contact header. Both
+	  of the SIP stacks in Asterisk suffered from this issue. This
+	  changeset corrects the behavior in chan_sip. ASTERISK-24646
+	  #close Reported by Stephan Eisvogel Review:
+	  https://reviewboard.asterisk.org/r/4346
+
+2015-01-29 12:08 +0000 [r431384]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix DTLS when used with
+	  OpenSSL 1.0.1k A recent security fix for OpenSSL broke DTLS
+	  negotiation for many applications. This was caused by read ahead
+	  not being enabled when it should be. While a commit has gone into
+	  OpenSSL to force read ahead on for DTLS it may take some time for
+	  a release to be made and the change to be present in
+	  distributions (if at all). As enabling read ahead is a simple one
+	  line change this commit does that and fixes the issue.
+	  ASTERISK-24711 #close Reported by: Jared Biel
+
+2015-01-28 17:12 +0000 [r431297-431298]  Mark Michelson <mmichelson at digium.com>
+
+	* funcs/func_curl.c: Fix compilation error from previous patch.
+
+	* funcs/func_curl.c: Mitigate possible HTTP injection attacks using
+	  CURL() function in Asterisk. CVE-2014-8150 disclosed a
+	  vulnerability in libcURL where HTTP request injection can be
+	  performed given properly-crafted URLs. Since Asterisk makes use
+	  of libcURL, and it is possible that users of Asterisk may get
+	  cURL URLs from user input or remote sources, we have made a patch
+	  to Asterisk to prevent such HTTP injection attacks from
+	  originating from Asterisk. ASTERISK-24676 #close Reported by Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/4364
+	  AST-2015-002
+
+2015-01-27 22:53 +0000 [r431187-431218]  Kevin Harwell <kharwell at digium.com>
+
+	* main/tcptls.c: tcptls: Bad file descriptor error when reloading
+	  chan_sip While running through some scenarios using chan_sip and
+	  tcp a problem would occur that resulted in a flood of bad file
+	  descriptor messages on the cli: tcptls.c:712
+	  ast_tcptls_server_root: Accept failed: Bad file descriptor The
+	  message is received because the underlying socket has been
+	  closed, so is valid. This is probably happening because unloading
+	  of chan_sip is not atomic. That however is outside the scope of
+	  this patch. This patch simply stops the logging of multiple
+	  occurrences of that message. ASTERISK-24728 #close Reported by:
+	  Thomas Thompson Review: https://reviewboard.asterisk.org/r/4380/
+
+	* channels/chan_sip.c: chan_sip: stale nonce causes failure When
+	  refreshing (with a small expiration) a registration that was sent
+	  to chan_sip the nonce would be considered stale and reject the
+	  registration. What was happening was that the initial
+	  registration's "dialog" still existed in the dialogs container
+	  and upon refresh the dialog match algorithm would choose that as
+	  the "dialog" instead of the newly created one. This occurred
+	  because the algorithm did not check to see if the from tag
+	  matched if authentication info was available after the 401. So,
+	  it ended up assuming the original "dialog" was a match and
+	  stopped the search. The old "dialog" of course had an old nonce,
+	  thus the stale nonce message. This fix attempts to leave the
+	  original functionality alone except in the case of a REGISTER. If
+	  a REGISTER is received if searches for an existing "dialog"
+	  matching only on the callid. If the expires value is low enough
+	  it will reuse dialog that is there, otherwise it will create a
+	  new one. ASTERISK-24715 #close Reported by: John Bigelow Review:
+	  https://reviewboard.asterisk.org/r/4367/
+
+2015-01-27 17:11 +0000 [r431135]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/include/confbridge.h, apps/app_confbridge.c:
+	  app_confbridge: Repeatedly starting and stopping recording ref
+	  leaks the recording channel. Starting and stopping conference
+	  recording more than once causes the recording channels to be
+	  leaked. For v13 the channels also show up in the CLI "core show
+	  channels" output. * Reworked and simplified the recording channel
+	  code to use ast_bridge_impart() instead of managing the recording
+	  thread in the ConfBridge code. The recording channel's ref
+	  handling easily falls into place and other off nominal code paths
+	  get handled better as a result. ASTERISK-24719 #close Reported
+	  by: John Bigelow Review: https://reviewboard.asterisk.org/r/4368/
+	  Review: https://reviewboard.asterisk.org/r/4369/
+
+2015-01-23 19:34 +0000 [r431049]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_confbridge.c: app_confbridge: Whitespace Because there
+	  is sometimes no sence to any whitespace.
+
+2015-01-23 14:55 +0000 [r430993-430997]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* include/asterisk/channel.h: Typo's (missed a spot in r430996).
+
+	* apps/app_minivm.c, contrib/utils/eagi_proxy.c,
+	  res/pjproject/pjsip/include/pjsip/sip_transport_tcp.h,
+	  res/pjproject/pjsip-apps/src/pjsua/pjsua_app.c,
+	  apps/app_voicemail.c, channels/chan_unistim.c,
+	  channels/chan_sip.c, channels/h323/ast_h323.cxx, res/res_fax.c,
+	  res/pjproject/pjlib-util/include/pjlib-util/http_client.h,
+	  apps/app_alarmreceiver.c,
+	  res/pjproject/pjlib/include/pj/activesock.h,
+	  include/asterisk/channel.h, funcs/func_hangupcause.c,
+	  res/pjproject/pjmedia/src/pjmedia/stream.c,
+	  res/pjproject/pjmedia/include/pjmedia/stream.h,
+	  funcs/func_groupcount.c, channels/chan_misdn.c,
+	  addons/ooh323c/src/ooh245.c,
+	  res/pjproject/pjnath/src/pjnath/stun_sock.c: Fix typo's
+	  (retrieve, specified, address).
+
+	* channels/chan_sip.c: chan_sip: Case insensitive comparison of
+	  "defaultuser" parameter. All the other configuration options are
+	  case insensitive, so this one should be too. ASTERISK-24355
+	  #close Reported by: HZMI8gkCvPpom0tM patches: ast.patch uploaded
+	  by HZMI8gkCvPpom0tM (License 6658)
+
+2015-01-22 14:22 +0000 [r430920]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: apps/app_voicemail: Trigger MWI
+	  notification with MixMonitor m() option The MixMonitor m() option
+	  allows a recording to be pushed to a specific voicemail mailbox.
+	  If the message is delivered to the mailbox's INBOX, however, no
+	  MWI notification is currently raised. This patch corrects the
+	  issue by properly calling notify_new_state from the
+	  msg_create_from_file function. This will cause MWI to be
+	  triggered if the message was placed in the mailbox's INBOX.
+	  ASTERISK-24709 #close Reported by: Gareth Palmer patches:
+	  app_voicemail-430919.patch uploaded by Gareth Palmer (License
+	  5169)
+
+2015-01-20 02:38 +0000 [r430795-430798]  Matthew Jordan <mjordan at digium.com>
+
+	* contrib/scripts/install_prereq: contrib/scripts/install_prereq:
+	  Don't install 32-bit packages on 64-bit hosts On Debian based
+	  systems, the install_prereq tool uses a search command on Debian
+	  that results in selecting both 64-bit and 32-bit packages.
+	  Besides the waste of disk space, this can actually cause aptitude
+	  use 100% of memory on a VM with 1GB of RAM as it tried to work
+	  out all of the 32-bit package dependencies. This patch filters
+	  out the 32-bit packages on a 64-bit machine, and leaves 32-bit
+	  machines alone. ASTERISK-24048 #close Reported by: Ben Klang
+	  Tested by: Ben Klang, Matt Jordan patches:
+	  install_prereq_64-bit_compat.patch uploaded by Ben Klang (License
+	  5876)
+
+	* apps/app_voicemail.c: app_voicemail: Temp message left after
+	  review/hangup with ODBC/IMAP backend When using ODBC or IMAP
+	  storage, temporary files created on the file system must be
+	  disposed of using the DISPOSE macro. The DELETE macro will map to
+	  a deletion function for the backend storage, but does not clean
+	  up any local files created as a result of the operation. When
+	  using voicemail with the operator and review options enabled,
+	  pressing 0 to enter the menu, followed by 1 to save the message,
+	  followed by any other DTMF press to delete the message, will
+	  result in the temporary file lingering on the file system. This
+	  patch properly calls DISPOSE after the DELETE. This causes the
+	  local file to be disposed of. ASTERISK-24288 #close Reported by:
+	  LEI FU patches: voicemail_odbc_review_fix.diff uploaded by LEI FU
+	  (License 6640)
+
+2015-01-14 15:34 +0000 [r430589]  Matthew Jordan <mjordan at digium.com>
+
+	* build_tools/mkpkgconfig: build_tools/mkpkgconfig: Fix Cflags
+	  concatenation error in asterisk.pc The mkpkgconfig script
+	  incorrectly concatenates Cflags options together. As an example,
+	  the following: Cflags: -I/usr/include/libxml2 -g3 Is instead
+	  generated as: Cflags: -I/usr/include/libxml2-g3 This patch
+	  corrects the generation of Cflags in mkpkgconfig such that the
+	  Cflags options are output correctly. Review:
+	  https://reviewboard.asterisk.org/r/3707/ ASTERISK-23991 #close
+	  Reported by: Diederik de Groot patches: fix_mkpkgconfig.diff
+	  uploaded by Diederik de Groot (License 6600)
+
+2015-01-13 18:06 +0000 [r430564]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_macro.c: app_macro: Don't restore the calling location
+	  on a channel redirect. v11: If a channel redirect to a macro
+	  exten of a macro that is active happens, the redirect location
+	  doesn't get executed. Instead the original macro location is
+	  restored and gets reexecuted. v13: An additional effect happens
+	  if a parked call times out to an extension in the macro that
+	  parked the call then the macro is reexecuted instead of the
+	  expected park return location. * Made not restore the macro
+	  calling location on an AST_SOFTHANGUP_ASYNCGOTO. * Increased the
+	  locked channel range when setting up the macro execution
+	  environment to cover things that should be done while the channel
+	  is locked. * Removed unnecessary NULL tests before calling
+	  ast_free() in _macro_exec(). ASTERISK-23850 #close Reported by:
+	  Andrew Nagy Review: https://reviewboard.asterisk.org/r/4292/
+
+2015-01-12 18:00 +0000 [r430487-430506]  Matthew Jordan <mjordan at digium.com>
+
+	* include/asterisk/syslog.h, main/syslog.c: main/syslog: Allow
+	  dynamic logs, such as security events, to log to the syslog The
+	  security event log uses a dynamic log level (SECURITY) that is
+	  registered with the Asterisk logging core. Unfortunately, the
+	  syslog would ignore log statements that had a dynamic log level
+	  associated with them. Because the syslog cannot handle ad hoc
+	  dynamic log levels, this patch treats any dynamic log entries
+	  sent to the syslog as logs with a level of NOTICE. ASTERISK-20744
+	  #close Reported by: Michael Keuter Tested by: Michael L. Young,
+	  Jacek Konieczny patches:
+	  asterisk-20744-syslog-dynamic-logging_trunk.diff uploaded by
+	  Michael L. Young (license 5026)
+
+	* funcs/func_curl.c: funcs/func_curl: Fix memory leak when CURLOPT
+	  channel datastore is destroyed When the channel datastore
+	  associated with the usage of CURLOPT on a specific channel is
+	  freed, the underlying structure holding the list of options is
+	  not disposed of. This patch properly frees the structure in the
+	  datastore .destroy callback. ASTERISK-24672 #close Reported by:
+	  Kristian Hogh patches: func_curl-memory-leak.diff uploaded by
+	  Kristian Hogh (License 6639)
+
+2015-01-09 14:40 +0000 [r430415]  Kinsey Moore <kmoore at digium.com>
+
+	* include/asterisk/res_fax.h, CHANGES, res/res_fax.c,
+	  configs/res_fax.conf.sample: res_fax: Add T.38 negotiation
+	  timeout option This change makes the T.38 negotiation timeout
+	  configurable via 't38timeout' in res_fax.conf or
+	  FAXOPT(t38timeout). It was previously hard coded to be 5000
+	  milliseconds. This change also handles T.38 switch failures by
+	  aborting the fax since in the case where this can happen, both
+	  sides have agreed to switch to T.38 and Asterisk is unable to do
+	  so. Review: https://reviewboard.asterisk.org/r/4320/
+
+2014-12-24 21:18 +0000 [r430126]  Kevin Harwell <kharwell at digium.com>
+
+	* configs/queues.conf.sample: app_queue: Update sample conf
+	  documenation Updated the queues.conf.sample file to explicitly
+	  state which channel queue variables are propagated to.
+	  ASTERISK-24267 Reported by: Mitch Claborn
+
+2014-12-22 19:38 +0000 [r430009]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/asterisk.c, main/logger.c, include/asterisk/_private.h:
+	  queue_log: Post QUEUESTART entry when Asterisk fully boots. The
+	  QUEUESTART log entry has historically acted like a fully booted
+	  event for the queue_log file. When the QUEUESTART entry was
+	  posted to the log was broken by the change made by
+	  ASTERISK-15863. * Made post the QUEUESTART queue_log entry when
+	  Asterisk fully boots. This restores the intent of that log entry
+	  and happens after realtime has had a chance to load. AST-1444
+	  #close Reported by: Denis Martinez Review:
+	  https://reviewboard.asterisk.org/r/4282/
+
+2014-12-22 15:39 +0000 [r429982]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Send CANCEL via original INVITE
+	  destination even after UPDATE request Given the following
+	  scenario: * Three SIP phones (A, B, C), all communicating via a
+	  proxy with Asterisk * A call is established between A and B. B
+	  performs a SIP attended transfer of A to C. B sets the call on
+	  hold (A is hearing MOH) and dials the extension of C. While phone
+	  C is ringing, B transfers the call (that is, what we typically
+	  call a 'blond transfer'). * When the transfer completes, A hears
+	  the ringing of phone C, while B is idle. In the SIP messaging for
+	  the above scenario, a REFER request is sent to transfer the call.
+	  When "sendrpid=yes" is set in sip.conf, Asterisk may send an
+	  UPDATE request to phone C to update party information. This
+	  update is sent directly to phone C, not through the intervening
+	  proxy. This has the unfortunate side effect of providing route
+	  information, which is then set on the sip_pvt structure for C. If
+	  someone (e.g. B) is trying to get the call back (through a
+	  directed pickup), Asterisk will send a CANCEL request to C.
+	  However, since we have now updated the route set, the CANCEL
+	  request will be sent directly to C and not through the proxy. The
+	  phone ignores this CANCEL according to RFC3261 (Section 9.1).
+	  This patch updates reqprep such that the route is not updated if
+	  an UPDATE request is being sent while the INVITE state is
+	  INV_PROCEEDING or INV_EARLY_MEDIA. This ensures that a subsequent
+	  CANCEL request is still sent to the correct location. Review:
+	  https://reviewboard.asterisk.org/r/4279 ASTERISK-24628 #close
+	  Reported by: Karsten Wemheuer patches: issue.patch uploaded by
+	  Karsten Wemheuer (License 5930)
+
+2014-12-20 20:56 +0000 [r429893]  Joshua Colp <jcolp at digium.com>
+
+	* main/named_acl.c: acl: Fix reloading of configuration if
+	  configuration file does not exist at startup. The named ACL code
+	  incorrectly destroyed the config options information if loading
+	  of the configuration file failed at startup. This would result in
+	  reloading also failing even if a valid configuration file was put
+	  in place. ASTERISK-23733 #close Reported by: Richard Kenner
+
+2014-12-19 20:51 +0000 [r429783-429867]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_http_websocket.c: res_http_websocket.c: Fix incorrect use
+	  of sizeof in ast_websocket_write(). This won't fix the reported
+	  issue but it is an incorrect use of sizeof. ASTERISK-24566
+	  Reported by: Badalian Vyacheslav
+
+	* channels/chan_dahdi.c: chan_dahdi: Don't ignore setvar when using
+	  configuration section scheme. When the configuration section
+	  scheme of chan_dahdi.conf is used (keyword dahdichan instead of
+	  channel) all setvar= options are completely ignored. No variable
+	  defined this way appears in the created DAHDI channels. * Move
+	  the clearing of setvar values to after the deferred processing of
+	  dahdichan. AST-1378 #close Reported by: Guenther Kelleter Patch
+	  by: Guenther Kelleter
+
+	* res/res_rtp_asterisk.c, channels/chan_dahdi.c: chan_dahdi.c,
+	  res_rtp_asterisk.c: Change some spammy debug messages to level 5.
+	  ASTERISK-24337 #close Reported by: Rusty Newton
+
+	* channels/sig_analog.c, UPGRADE.txt: chan_dahdi: Populate
+	  CALLERID(ani2) for incoming calls in featdmf signaling mode. For
+	  the featdmf signaling mode the incoming MF Caller-ID information
+	  is formatted as follows:
+	  *${CALLERID(ani2)}${CALLERID(ani)}#*${EXTEN}# Rather than
+	  discarding the ani2 digits, populate the CALLERID(ani2) value
+	  with what is received instead. AST-1368 #close Reported by: Denis
+	  Martinez Patches: extract_ani2_for_featdmf_v11.patch (license
+	  #5621) patch uploaded by Richard Mudgett
+
+2014-12-17 09:24 +0000 [r429673]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* main/netsock.c, main/loader.c, channels/chan_misdn.c,
+	  main/manager.c, apps/app_osplookup.c,
+	  res/pjproject/pjlib/src/pj/ssl_sock_dump.c,
+	  res/pjproject/pjnath/src/pjnath-test/stun.c,
+	  res/pjproject/pjnath/src/pjnath/turn_sock.c, channels/misdn/ie.c,
+	  channels/chan_h323.c, apps/app_sms.c,
+	  addons/ooh323c/src/printHandler.c, apps/app_adsiprog.c,
+	  res/res_rtp_asterisk.c,
+	  res/pjproject/pjnath/src/pjnath/stun_msg_dump.c, main/udptl.c,
+	  channels/chan_unistim.c,
+	  res/pjproject/pjlib-util/src/pjlib-util-test/encryption.c,
+	  channels/chan_sip.c, channels/vcodecs.c, res/res_crypto.c,
+	  utils/astman.c, utils/smsq.c, main/utils.c, pbx/dundi-parser.c,
+	  apps/app_getcpeid.c, res/pjproject/pjnath/src/pjnath/stun_msg.c,
+	  channels/chan_iax2.c, channels/sig_pri.c, res/res_pktccops.c,
+	  channels/iax2-parser.c: Fix printf problems with high ascii
+	  characters after r413586 (1.8). In r413586 (1.8) various casts
+	  were added to silence gcc 4.10 warnings. Those fixes included
+	  things like: -out += sprintf(out, "%%%02X", (unsigned char)
+	  *ptr); +out += sprintf(out, "%%%02X", (unsigned) *ptr); That
+	  works for low ascii characters, but for the high range that
+	  yields e.g. FFFFFFC3 when C3 is expected. This changeset: - fixes
+	  those casts to use the 'hh' unsigned char modifier instead -
+	  consistently uses %02x instead of %2.2x (or other non-standard
+	  usage) - adds a few 'h' modifiers in various places - fixes a
+	  'replcaes' typo - dev/urandon typo (in 13+ patch) Review:
+	  https://reviewboard.asterisk.org/r/4263/ ASTERISK-24619 #close
+	  Reported by: Stefan27 (on IRC)
+
+2014-12-16 16:35 +0000 [r429632]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Allow T.38 switch-over when SRTP
+	  is in use. Previously when SRTP was enabled on a channel it was
+	  not possible to switch to T.38 as no crypto attributes would be
+	  present. This change makes it so it is now possible. If a T.38
+	  re-invite comes in SRTP is terminated since in practice you can't
+	  encrypt a UDPTL stream. Now... if we were doing T.38 over RTP
+	  (which does exist) then we'd have a chance but almost nobody does
+	  that so here we are. ASTERISK-24449 #close Reported by: Andreas
+	  Steinmetz patches: udptl-ignore-srtp-v2.patch submitted by
+	  Andreas Steinmetz (license 6523)
+
+2014-12-12 23:31 +0000 [r429539]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/lock.c, include/asterisk/lock.h: DEBUG_THREADS: Fix
+	  regression and lock tracking initialization problems. This patch
+	  started with David Lee's patch at
+	  https://reviewboard.asterisk.org/r/2826/ and includes a
+	  regression fix introduced by the ASTERISK-22455 patch. The
+	  initialization of a mutex's lock tracking structure was not
+	  protected in a critical section. This is fine for any mutex that
+	  is explicitly initialized, but a static mutex may have its lock
+	  tracking double initialized if multiple threads attempt the first
+	  lock simultaneously. * Added a global mutex to properly serialize
+	  initialization of the lock tracking structure. The painful global
+	  lock can be mitigated by adding a double checked lock flag as
+	  discussed on the original review request. * Defer lock tracking
+	  initialization until first use. * Don't be "helpful" and
+	  initialize an uninitialized lock when DEBUG_THREADS is enabled.
+	  Debug code is not supposed to fix or change normal code behavior.
+	  We don't need a lock initialization race that would force a
+	  re-setup of lock tracking. Lock tracking already handles
+	  initialization on first use. * Properly handle allocation
+	  failures of the lock tracking structure. * No need to initialize
+	  tracking data in __ast_pthread_mutex_destroy() just to turn
+	  around and destroy it. The regression introduced by
+	  ASTERISK-22455 is the result of manipulating a pthread_mutex_t
+	  struct outside of the pthread library code. The pthread_mutex_t
+	  struct seems to have a global linked list pointer member that can
+	  get changed by other threads. Therefore, saving and restoring the
+	  contents of a pthread_mutex_t struct is a bad thing. Thanks to
+	  Thomas Airmont for finding this obscure regression. * Don't
+	  overwrite the struct ast_lock_track.reentr_mutex member to
+	  restore tracking data in __ast_cond_wait() and
+	  __ast_cond_timedwait(). The pthread_mutex_t struct must be
+	  treated as a read-only opaque variable. Miscellaneous other items
+	  fixed by this patch: * Match ast_suspend_lock_info() with
+	  ast_restore_lock_info() in __ast_cond_timedwait(). * Made some
+	  uninitialized lock sanity checks return EINVAL and try a
+	  DO_THREAD_CRASH. * Fix bad canlog initialization expressions.
+	  ASTERISK-24614 #close Reported by: Thomas Airmont Review:
+	  https://reviewboard.asterisk.org/r/4247/ Review:
+	  https://reviewboard.asterisk.org/r/2826/
+
+2014-12-12 22:42 +0000 [r429517]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_agi.c: res/res_agi: Make Verbose message for 'stream
+	  file' match other playbacks The Verbose message displayed when a
+	  file is played back via 'stream file' was formatted differently
+	  than other playbacks: * It didn't include the channel name * It
+	  didn't include the channel language It does, however, include the
+	  playback offset as well as any escape digits. That information
+	  was kept; however, this patch updates the formatting to more
+	  closely match the Verbose messages displayed when a file is
+	  played back by 'control stream file', Playback, ControlPlayback,
+	  or any other file playback operation.
+
+2014-12-10 13:30 +0000 [r429270]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c, res/res_http_websocket.c:
+	  res_http_websocket: Fix crash due to double freeing memory when
+	  receiving a payload length of zero. Frames with a payload length
+	  of 0 were incorrectly handled in res_http_websocket. Provided a
+	  frame with a payload had been received prior it was possible for
+	  a double free to occur. The realloc operation would succeed (thus
+	  freeing the payload) but be treated as an error. When the session
+	  was then torn down the payload would be freed again causing a
+	  crash. The read function now takes this into account. This change
+	  also fixes assumptions made by users of res_http_websocket. There
+	  is no guarantee that a frame received from it will be NULL
+	  terminated. ASTERISK-24472 #close Reported by: Badalian
+	  Vyacheslav Review: https://reviewboard.asterisk.org/r/4220/
+	  Review: https://reviewboard.asterisk.org/r/4219/
+
+2014-12-15  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.15.0 Released.
+
+2014-12-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.15.0-rc2 Released.
+
+	* AST-2014-019: Fix crash when receiving a WebSocket packet with a
+	  payload length of zero.
+
+	  Frames with a payload length of 0 were incorrectly handled in
+	  res_http_websocket. Provided a frame with a payload had been
+	  received prior it was possible for a double free to occur. The
+	  realloc operation would succeed (thus freeing the payload) but be
+	  treated as an error. When the session was then torn down the payload
+	  would be freed again causing a crash. The read function now takes
+	  this into account.
+
+	  This change also fixes assumptions made by users of
+	  res_http_websocket. There is no guarantee that a frame received from
+	  it will be NULL terminated.
+
+	  ASTERISK-24472 #close
+	  Reported by: Badalian Vyacheslav
+
+2014-12-08  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.15.0-rc1 Released.
+
+2014-12-06 18:15 +0000 [r429027-429031]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_monitor.c: res/res_monitor: Reset in/out sample counts on
+	  Monitor start When repeatedly starting/stopping a Monitor on a
+	  channel, the accumulated in/out sample counts are never reset to
+	  0. This can cause inadvertent jumps in the recordings, as the
+	  code in the channel core will determine incorrectly that a jump
+	  in the recorded file position should occur. Setting the sample
+	  counts to 0 simply reflects the initial state a Monitor should be
+	  in when it is started, as this is the initial count that would be
+	  on the channels at that time. ASTERISK-24573 #close Reported by:
+	  Nuno Borges patches: 24573.patch uploaded by Nuno Borges (License
+	  6116)
+
+	* apps/app_meetme.c: apps/app_meetme: Apply default values on
+	  initial load with no config file When the app_meetme module is
+	  loaded without its configuration file, the module settings aren't
+	  initialized. In particular, this impacts the use of logging
+	  realtime members. This patch guarantees that we always set the
+	  default module settings on initial load. Review:
+	  https://reviewboard.asterisk.org/r/4242/ ASTERISK-24572 #close
+	  Reported by: Nuno Borges patches: 24572.patch uploaded by Nuno
+	  Borges (License 6116)
+
+2014-12-03 16:43 +0000 [r428787-428863]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: apps/app_voicemail: Fix crash with IMAP
+	  when streams are opened simultaneously The UW IMAP library is
+	  instrinsically not thread-safe, and relies upon higher level
+	  applications to guarantee thread safety. For the most part, this
+	  is provided by the vms object, which provides locking for
+	  individual streams. Unfortunately, this is not sufficient for
+	  calls to mail_open which create the IMAP stream. mail_open can,
+	  on some systems, call into a UW IMAP specific function for
+	  determining the address of a system based on a hostname,
+	  ip_nametoaddr. In the ip6_unix implementation of this function,
+	  static variables are used to hold parsing buffers. This can cause
+	  a crash if multiple threads attempt to convert a hostname to an
+	  address at the same time. Locking on a single mail stream is not
+	  sufficient to prevent simultaneous access to these static
+	  variables. In the IMAP library, this function can be called from
+	  the mail_open and imap_status functions. As the imap_status
+	  function is not used by app_voicemail, locking on access to
+	  mail_open is sufficient to prevent any mangling of the buffers.
+	  Review: https://reviewboard.asterisk.org/r/4188/ ASTERISK-24516
+	  #close Reported by: David Duncan Ross Palmer Tested by: David
+	  Duncan Ross Palmer patches: ASTERISK-24516.diff uploaded by David
+	  Duncan Ross Palmer (License 6660)
+
+	* pbx/pbx_loopback.c: pbx/pbx_loopback: Speed up switches by
+	  avoiding unneeded lookups This patch makes a small rearrangement
+	  to only do dialplan lookups during loopback switches if the
+	  pattern matches. Prior to this patch, the dialplan lookups were
+	  always performed, even when the result would be discarded.
+	  Dialplan lookups can be very costly if remote switches - like
+	  DUNDi - are present. In those cases extension matching is sped up
+	  considerably, making the issue of lost digits more manageable. As
+	  collateral damage, 6 trailing spaces were killed. Review:
+	  https://reviewboard.asterisk.org/r/4211 ASTERISK-24577 #close
+	  Reported by: Birger Harzenetter patches: ast-loopback.patch
+	  uploaded by Birger Harzenetter (License 5870)
+
+2014-12-01 13:39 +0000 [r428653]  Joshua Colp <jcolp at digium.com>
+
+	* apps/app_record.c: app_record: Fix bug where using the 'k' option
+	  and hanging up would trim 1/4 of a second of the recording. The
+	  Record dialplan function trims 1/4 of a second from the end of
+	  recordings in case they are terminated because of DTMF. When
+	  hanging up, however, you don't want this to happen. This change
+	  makes it so on hangup this does not occur. ASTERISK-24530 #close
+	  Reported by: Ben Smithurst patches: app_record_v2.diff submitted
+	  by Ben Smithurst (license 6529) Review:
+	  https://reviewboard.asterisk.org/r/4201/
+
+2014-11-21 18:47 +0000 [r428570]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c: manager: Fix could not extend string messages.
+	  When shutting down Asterisk that has an active AMI connection,
+	  you get several "failed to extend from %d to %d" messages because
+	  use of the EVENT_FLAG_SHUTDOWN attempts to add all AMI permission
+	  strings to the event. * Created MAX_AUTH_PERM_STRING to use when
+	  creating stack based struct ast_str variables used with the
+	  authority_to_str() and user_authority_to_str() functions instead
+	  of a variety of magic numbers that could be too small. * Added a
+	  special check for EVENT_FLAG_SHUTDOWN to authority_to_str() so it
+	  will not attempt to add all permission level strings. Review:
+	  https://reviewboard.asterisk.org/r/4200/
+
+2014-11-20 16:35 +0000 [r428417]  Mark Michelson <mmichelson at digium.com>
+
+	* /, main/acl.c: Fix error with mixed address family ACLs. Prior to
+	  this commit, the address family of the first item in an ACL was
+	  used to compare all incoming traffic. This could lead to traffic
+	  of other IP address families bypassing ACLs. ASTERISK-24469
+	  #close Reported by Matt Jordan Patches: ASTERISK-24469-11.diff
+	  uploaded by Matt Jordan (License #6283) AST-2014-012 ........
+	  Merged revisions 428402 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-11-20 16:22 +0000 [r428332-428363]  Kevin Harwell <kharwell at digium.com>
+
+	* funcs/func_db.c, /: AST-2014-018 - func_db: DB Dialplan function
+	  permission escalation via AMI. The DB dialplan function when
+	  executed from an external protocol (for instance AMI), could
+	  result in a privilege escalation. Asterisk now inhibits the DB
+	  function from being executed from an external interface if the
+	  live_dangerously option is set to no. ASTERISK-24534 Reported by:
+	  Gareth Palmer patches: submitted by Gareth Palmer (license 5169)
+	  ........ Merged revisions 428331 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_confbridge.c: AST-2014-017 - app_confbridge: permission
+	  escalation/ class authorization. Confbridge dialplan function
+	  permission escalation via AMI and inappropriate class
+	  authorization on the ConfbridgeStartRecord action. The CONFBRIDGE
+	  dialplan function when executed from an external protocol (for
+	  instance AMI), could result in a privilege escalation. Also, the
+	  AMI action “ConfbridgeStartRecord” could also be used to execute
+	  arbitrary system commands without first checking for system
+	  access. Asterisk now inhibits the CONFBRIDGE function from being
+	  executed from an external interface if the live_dangerously
+	  option is set to no. Also, the “ConfbridgeStartRecord” AMI action
+	  is now only allowed to execute under a user with system level
+	  access. ASTERISK-24490 Reported by: Gareth Palmer
+
+2014-11-20 14:20 +0000 [r428299]  Joshua Colp <jcolp at digium.com>
+
+	* main/bridging.c: AST-2014-014: Fix race condition where channels
+	  may get stuck in ConfBridge under load. Under load it was
+	  possible for the bridging API, and thus ConfBridge, to get
+	  channels that may have hung up stuck in it. This is because
+	  handling of state transitions for a bridged channel within a
+	  bridge was not protected and simply set the new state without
+	  regard to the existing state. If the existing state had been hung
+	  up this would get overwritten. This change adds locking to
+	  protect changing of the state and also takes into consideration
+	  the existing state. ASTERISK-24440 #close Reported by: Ben Klang
+	  Review: https://reviewboard.asterisk.org/r/4173/
+
+2014-11-19 16:38 +0000 [r428244]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_calendar.c, channels/chan_sip.c,
+	  channels/sip/security_events.c: ast_str: Fix improper member
+	  access to struct ast_str members. Accessing members of struct
+	  ast_str outside of the string manipulation API routines is
+	  invalid since struct ast_str is supposed to be treated as opaque.
+	  Review: https://reviewboard.asterisk.org/r/4194/
+
+2014-11-17 15:56 +0000 [r428117]  Corey Farrell <git at cfware.com>
+
+	* channels/chan_sip.c: chan_sip: Fix theoretical leak of p->refer.
+	  If transmit_refer is called when p->refer is already allocated,
+	  it leaks the previous allocation. Updated code to always free
+	  previous allocation during a new allocation. Also instead of
+	  checking if we have a previous allocation, always create a clean
+	  record. ASTERISK-15242 #close Reported by: David Woolley Review:
+	  https://reviewboard.asterisk.org/r/4160/
+
+2014-11-17 15:26 +0000 [r428077-428113]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/confbridge/conf_state_multi_marked.c: apps/app_confbridge:
+	  Ensure 'normal' users hear message when last marked leaves When
+	  r428077 was made for ASTERISK-24522, it failed to take into
+	  account users who are neither wait_marked nor end_marked. These
+	  users are *also* supposed to hear the 'leader has left the
+	  conference' message. Granted, this behaviour is a bit odd;
+	  however, that is how it used to work... and behaviour changes are
+	  not good. This patch ensures that if there are any 'normal' users
+	  present when the last marked user leaves the conference, the
+	  message will still be played to them. Note that this regression
+	  was caught by the Asterisk Test Suite's confbridge_nominal test,
+	  which has a quirky combination of users.
+
+	* apps/confbridge/conf_state_multi_marked.c: app_confbridge: Don't
+	  play leader leaving prompt if no one will hear it Consider the
+	  following: - A marked user in a conference - One or more
+	  end_marked only users in the conference When the marked users
+	  leaves, we will be in the conf_state_multi_marked state. This
+	  currently will traverse the users, kicking out any who have the
+	  end_marked flags. When they are kicked, a full ast_bridge_remove
+	  is immediately called on the channels. At this time, we also
+	  unilaterally set the need_prompt flag. When the need_prompt flag
+	  is set, we then playback a sound to the bridge informing everyone
+	  that the leader has left; however, no one is left in the bridge.
+	  This causes some odd behaviour for the end_marked users - they
+	  are stuck waiting for the bridge to be unlocked. This results in
+	  them waiting for 5 or 6 seconds of dead air before hearing that
+	  they've been kicked. Unfortunately, we do have to keep the bridge
+	  locked while we're playing back the 'leader-has-left' prompt. If
+	  there are any wait_marked users in the conference, this behaviour
+	  can't be easily changed - but we do make the case of the
+	  end_marked users better with this patch. Review:
+	  https://reviewboard.asterisk.org/r/4184/ ASTERISK-24522 #close
+	  Reported by: Matt Jordan
+
+2014-11-15 16:51 +0000 [r427952]  Matthew Jordan <mjordan at digium.com>
+
+	* cel/cel_odbc.c: cel/cel_odbc: Provide microsecond precision in
+	  'eventtime' column when possible This patch adds microsecond
+	  precision when inserting a CEL record into a table with an
+	  "eventtime" column of type timestamp, instead of second
+	  precision. The documentation (configs/cel_odbc.conf.sample) was
+	  already saying that the eventtime column included microseconds
+	  precision, but that was not the case. Also, without this patch,
+	  if you had a table with an "eventtime" column of type varchar,
+	  you had millisecond precision. With this patch, you also get
+	  microsecond precision in this case. Review:
+	  https://reviewboard.asterisk.org/r/3980 ASTERISK-24283 #close
+	  Reported by: Etienne Lessard patches:
+	  cel_odbc_time_precision.patch uploaded by Etienne Lessard
+	  (License 6394)
+
+2014-11-14 15:46 +0000 [r427874]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/stun.c: stun: correct attribute string padding to match rfc
+	  When sending the USERNAME attribute in an RTP STUN response, the
+	  implementation in append_attr_string passed the actual length,
+	  instead of padding it up to a multiple of four bytes as required
+	  by the RFC 3489. This change adds separate variables for the
+	  string and padded attributed lengths, and performs padding
+	  correctly. Reported by: Thomas Arimont Review:
+	  https://reviewboard.asterisk.org/r/4139/
+
+2014-11-14 14:54 +0000 [r427844]  Joshua Colp <jcolp at digium.com>
+
+	* apps/confbridge/conf_state_multi_marked.c: app_confbridge: Play
+	  "leader has left" sound even when musiconhold is enabled.
+	  Currently if the leader of a conference bridge leaves any
+	  participant that has musiconhold enabled will not hear the
+	  "leader has left" sound. This is because musiconhold is started
+	  and THEN the sound is played. This change makes it so that the
+	  sound is played and THEN musiconhold is started. This provides a
+	  better experience for users as they may not have known previously
+	  why they went back to musiconhold. Review:
+	  https://reviewboard.asterisk.org/r/4177/
+
+2014-11-12 16:10 +0000 [r427709]  Joshua Colp <jcolp at digium.com>
+
+	* main/pbx.c: pbx: Fix off-nominal case where a freed extension may
+	  still be used. If during the operation of adding an extension a
+	  priority is added but fails it is possible for the extension to
+	  be freed but still exist in the PBX core. If this occurs
+	  subsequent lookups may try to access the extension and end up in
+	  freed memory. This change removes the extension from the PBX core
+	  when the priority addition fails and then frees the extension.
+	  ASTERISK-24444 #close Reported by: Leandro Dardini Review:
+	  https://reviewboard.asterisk.org/r/4162/
+
+2014-11-12 13:44 +0000 [r427682]  Corey Farrell <git at cfware.com>
+
+	* codecs/ilbc, tests, codecs/speex, apps/confbridge,
+	  Makefile.rules: Fix compiler error when using ./configure
+	  --enable-dev-mode --enable-coverage When DONT_OPTIMIZE is enabled
+	  with dev-mode, it causes a shadow compilation to be done with
+	  output to /dev/null. This can cause errors with coverage when GCC
+	  attempts to write to /dev/null.gcno. This change disables
+	  coverage for the shadow compilation. ASTERISK-24502 #close
+	  Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4151/
+
+2014-11-09 07:56 +0000 [r427641]  Corey Farrell <git at cfware.com>
+
+	* main/manager.c: manager: Fix HTTP connection reference leaks. Fix
+	  reference leak that happens if (session && !blastaway).
+	  ASTERISK-24505 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4153/
+
+2014-11-09 00:59 +0000 [r427607-427617]  Matthew Jordan <mjordan at digium.com>
+
+	* configs/features.conf.sample: configs/features.conf: Add
+	  documentation noting potential chan_agent conflict In chan_agent,
+	  a '*' is used by default to terminate a bridge with a caller.
+	  This can lead to all sorts of problems if '*' is used by a
+	  feature in features.conf, as the chan_agent disconnect '*' may be
+	  detected first. This patch adds a documentation snippet to
+	  features.conf so that users who attempt to use features with
+	  agents know of the potential conflict. ASTERISK-20402 #close
+	  Reported by: Matt Riddell patches: features.conf.diff uploaded by
+	  Matt Riddell (License 5023)
+
+	* channels/chan_mgcp.c: channels/chan_mgcp: Fix regression which
+	  causes gateways to be skipped In r227276, a while loop was turned
+	  into a for loop. Unfortunately, a portion of the while loop was
+	  left in the code such that, when a static gateway is encountered
+	  in the list of MGCP gateways, the next gateway would be skipped.
+	  At best, we would simply flip past a gateway; at worst, this
+	  could lead to a crash. ASTERISK-24500 #close Reported by: Xavier
+	  Hienne patches: chan_mgcp.patch uploaded by Xavier Hienne
+	  (License 6657)
+
+	* addons/chan_mobile.c: addons/chan_mobile: Increase buffer size of
+	  UCS2 encoded SMS messages When UCS2 character encoding is used,
+	  one symbol in national language can be expanded to 4 bytes. The
+	  current buffer used for receiving message in do_monitor_phone is
+	  256 bytes, which is not large enough for incoming messages. For
+	  example: * AT+CMGR phone response prefix '+CMGR: "REC
+	  UNREAD","+7**********",,"14/10/29,13:31:39+12"\r\n' - 60 bytes *
+	  SMS body with UCS2 encoding (max) - 280 bytes * AT+CMGR phone
+	  response suffix '\r\n\r\nOK\r\n' - 8 bytes * Terminating null
+	  character - 1 byte This results in a needed buffer size of 349
+	  bytes. Hence, this patch opts for a 350 byte buffer.
+	  ASTERISK-24468 #close Reported by: Dmitriy Bubnov patches:
+	  chan_mobile-1_8.diff uploaded by Dmitriy Bubnov (License 6651)
+	  chan_mobile-trunk.diff uploaded by Dmitry Bubnov (License 6651)
+
+2014-11-08 17:28 +0000 [r427554]  Corey Farrell <git at cfware.com>
+
+	* channels/chan_console.c: chan_console: Fix reference leaks to
+	  pvt. Fix a bunch of calls to get_active_pvt where the reference
+	  is never released. ASTERISK-24504 #close Reported by: Corey
+	  Farrell Review: https://reviewboard.asterisk.org/r/4152/
+
+2014-11-06 12:10 +0000 [r427381-427464]  Corey Farrell <git at cfware.com>
+
+	* main/file.c: main/file.c: fix possible extra ast_module_unref to
+	  format modules. fn_wrapper only adds a reference to the format's
+	  module if the file was able to be opened. If not this causes an
+	  unmatched ast_module_unref in filestream_destructor. Move
+	  ast_module_ref to get_stream. ASTERISK-24492 #close Reported by:
+	  Corey Farrell Review: https://reviewboard.asterisk.org/r/4149/
+
+	* include/asterisk/stringfields.h, /, main/utils.c: Fix unintential
+	  memory retention in stringfields. * Fix missing / unreachable
+	  calls to __ast_string_field_release_active. * Reset pool->used to
+	  zero when the current pool->active reaches zero. ASTERISK-24307
+	  #close Reported by: Etienne Lessard Tested by: ibercom, Etienne
+	  Lessard Review: https://reviewboard.asterisk.org/r/4114/ ........
+	  Merged revisions 427380 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-11-06 02:26 +0000 [r427328-427354]  George Joseph <george.joseph at fairview5.com>
+
+	* tests/test_strings.c: test_strings: Remove string tests that
+	  exercise asserts. Since unit tests are run with DO_CRASH, those
+	  tests were causing the test to fail. Tested-by: George Joseph
+
+	* main/config.c, tests/test_strings.c, include/asterisk/test.h,
+	  include/asterisk/utils.h, main/utils.c, pbx/pbx_config.c: config:
+	  Make text_file_save and 'dialplan save' escape semicolons in
+	  values. When a config file is read, an unescaped semicolon
+	  signals comments which are stripped from the value before it's
+	  stored. Escaped semicolons are then unescaped and become part of
+	  the value. Both of these behaviors are normal and expected. When
+	  the config is serialized either by 'dialplan save' or
+	  AMI/UpdateConfig however, the now unescaped semicolons are
+	  written as-is. If you actually reload the file just saved, the
+	  unescaped semicolons are now treated as start of comments. Since
+	  true comments are stripped on read, any semicolons in
+	  ast_variable.value must have been escaped originally. This patch
+	  re-escapes semicolons in ast_variable.values before they're
+	  written to file either by 'dialplan save' or
+	  config/ast_config_text_file_save which is called by
+	  AMI/UpdateConfig. I also fixed a few pre-existing formatting
+	  issues nearby in pbx_config.c Tested-by: George Joseph
+	  ASTERISK-20127 #close Review:
+	  https://reviewboard.asterisk.org/r/4132/
+
+2014-11-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.14.0 Released.
+
+2014-11-07  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.14.0-rc2 Released.
+
+2014-11-06 09:05 +0000 [r427381]  Corey Farrell <git at cfware.com>
+
+	* Fix unintential memory retention in stringfields.
+
+	  * Fix missing / unreachable calls to
+	    __ast_string_field_release_active.
+	  * Reset pool->used to zero when the current pool->active reaches
+	    zero.
+
+	ASTERISK-24307 #close
+	Reported by: Etienne Lessard
+	Tested by: ibercom, Etienne Lessard
+	Review: https://reviewboard.asterisk.org/r/4114/
+
+2014-11-03  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.14.0-rc1 Released.
+
+2014-11-03 02:31 +0000 [r427019-427087]  Corey Farrell <git at cfware.com>
+
+	* apps/app_voicemail.c: Fix compile error caused by review 4138
+	  There is no procedure called ast_closeframe, fix code to use
+	  ast_closestream. Reported By: Matt Jordan
+
+	* apps/app_voicemail.c, /, main/app.c: Fix ast_writestream leaks
+	  Fix cleanup in __ast_play_and_record where others[x] may be
+	  leaked. This was caught where prepend != NULL && outmsg != NULL,
+	  once realfile[x] == NULL any further others[x] would be leaked. A
+	  cleanup block was also added for prepend != NULL && outmsg ==
+	  NULL. 11+: Fix leak of ast_writestream recording_fs in
+	  app_voicemail:leave_voicemail. ASTERISK-24476 #close Reported by:
+	  Corey Farrell Review: https://reviewboard.asterisk.org/r/4138/
+	  ........ Merged revisions 427023 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* funcs/func_jitterbuffer.c, main/abstract_jb.c: func_jitterbuffer:
+	  fix frame leaks. Fix code paths where it is possible for frames
+	  to leak. Fix uninitialized variable in jb_get_fixed and
+	  jb_get_adaptive. ASTERISK-22409 #related Reported by: Corey
+	  Farrell Review: https://reviewboard.asterisk.org/r/4128/
+
+2014-10-31 16:40 +0000 [r426927-426931]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* Makefile, /: Fix syntax from commit r426927
+
+	* Makefile, /: install init.d files on GNU/kFreeBSD Review:
+	  https://reviewboard.asterisk.org/r/4118/ ........ Merged
+	  revisions 426926 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-31 03:25 +0000 [r426860]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/sip/include/reqresp_parser.h, /,
+	  channels/sip/reqresp_parser.c: channels/sip/reqresp_parser: Fix
+	  unit tests for r426594 When r426594 was made, it did not take
+	  into account a unit test that verified that the function properly
+	  populated the unsupported buffer. The function would previously
+	  memset the buffer if it detected it had any contents; since this
+	  function can now be called iteratively on successive headers, the
+	  unit tests would now fail. This patch updates the unit tests to
+	  reset the buffer themselves between successive calls, and updates
+	  the documentation of the function to note that this is now
+	  required. ........ Merged revisions 426858 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-31 03:05 +0000 [r426805-426831]  Corey Farrell <git at cfware.com>
+
+	* /, contrib/Makefile (added), Makefile: REF_DEBUG: Install
+	  refcounter.py to $(ASTDATADIR)/scripts This change ensures
+	  refcounter.py is installed to a place where it can be found by
+	  the Asterisk testsuite if REF_DEBUG is enabled. ASTERISK-24432
+	  #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4094/ ........ Merged
+	  revisions 426830 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_queue.c: app_queue: fix a couple leaks to struct
+	  call_queue in set_member_value set_member_value has a couple
+	  leaks to references in the variable q found through testsuite
+	  tests/queues/set_penalty. Also remove the REF_DEBUG_ONLY_QUEUES
+	  compiler declaration, this is no longer possible with the updated
+	  REF_DEBUG code. ASTERISK-24466 #close Reported by: Corey Farrell
+	  Review: https://reviewboard.asterisk.org/r/4125/
+
+2014-10-30 09:16 +0000 [r426692]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, apps/app_voicemail.c: app_voicemail: Fix unchecked bounds of
+	  myArray in IMAP_STORAGE. In update_messages_by_imapuser(),
+	  messages were appended to a finite array which resulted in a
+	  crash when an IMAP mailbox contained more than 256 entries. This
+	  memory is now dynamically increased as needed. Observe that this
+	  patch adds a bunch of XXX's to questionable code. See the review
+	  (url below) for more information. ASTERISK-24190 #close Reported
+	  by: Nick Adams Tested by: Nick Adams Review:
+	  https://reviewboard.asterisk.org/r/4126/ ........ Merged
+	  revisions 426691 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-30 05:56 +0000 [r426666]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Add additional checks for NULL pointers
+	  to fix several crashes reported. ASTERISK-24304 #close Reported
+	  by: dhanapathy sathya
+
+2014-10-30 01:58 +0000 [r426595-426600]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: channels/chan_sip: Add improved support
+	  for 4xx error codes This patch adds support for 414, 493, 479,
+	  and a stray 400 response in REGISTER response handling. This
+	  helps interoperability in a number of scenarios. Review:
+	  https://reviewboard.asterisk.org/r/3437 patches: rb3437.patch
+	  uploaded by oej (License 5267) ........ Merged revisions 426599
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c, channels/sip/reqresp_parser.c:
+	  channels/chan_sip: Support mutltiple Supported and Required
+	  headers A SIP request may contain multiple Supported: and
+	  Required: headers. Currently, chan_sip only parses the first
+	  Supported/Required header it finds. This patch adds support for
+	  multiple Supported/Required headers for INVITE requests. Review:
+	  https://reviewboard.asterisk.org/r/2478 ASTERISK-21721 #close
+	  Reported by: Olle Johansson patches: rb2478.patch uploaded by oej
+	  (License 5267) ........ Merged revisions 426594 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-28 20:50 +0000 [r426527]  Corey Farrell <git at cfware.com>
+
+	* res/res_fax.c: res_fax: Resolve T38 gateway frame leak. When
+	  frames are translated by a fax gateway they need to be freed. The
+	  existing call to ast_frfree was unreachable. This change
+	  reorganizes fax_gateway_framehook to ensure that ast_frfree is
+	  called when needed. ASTERISK-24457 #close Reported by: Corey
+	  Farrell Review: https://reviewboard.asterisk.org/r/4115/
+
+2014-10-28 18:08 +0000 [r426456]  mdavenport <mdavenport at localhost>:
+
+	* configs/manager.conf.sample: ASTERISK-23512, correct inaccurate
+	  comment in manager.conf.sample
+
+2014-10-28 14:57 +0000 [r426366]  Matthew Jordan <mjordan at digium.com>
+
+	* main/manager.c: main/manager: Fix typo in AMI event documentation
+	  of "OriginateResponse" The parameter name is "Response", not
+	  "Resonse". ASTERISK-24430 #close Reported by: Dafi Ni
+
+2014-10-28 14:55 +0000 [r426291-426359]  mdavenport <mdavenport at localhost>:
+
+	* res/res_agi.c: ASTERISK-24323, fix bug in documentation of AGI
+	  STREAM FILE CONTROL
+
+	* configs/extensions.conf.sample: ASTERISK-24419, fix incorrect
+	  syntax for setting language in extensions.conf.sample
+
+2014-10-28 11:17 +0000 [r426255]  Corey Farrell <git at cfware.com>
+
+	* apps/app_queue.c: app_queue: Cleanup ao2_iterator Clean
+	  ao2_iterator, resolving reference leak to queue members.
+	  ASTERISK-24454 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4111/
+
+2014-10-27 02:45 +0000 [r426141-426209]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_http_websocket.c: res/res_http_websocket: Fix minor nits
+	  found by wdoekes on r409681 When Moises committed the fixes for
+	  WSS (which was a great patch), wdoekes had a few style nits that
+	  were on the review that got missed. This patch resolves what I
+	  *think* were all of the ones that were still on the review.
+	  Thanks to both moy for the patch, and wdoekes for the reviews.
+	  Review: https://reviewboard.asterisk.org/r/3248/
+
+	* res/res_srtp.c, /: res/res_srtp: Fix include issue for libsrtp
+	  1.5.0 In libsrtp 1.5.0, crypto_get_random is no longer resolved
+	  simply by including srtp.h. Now, one must include crypto_kernel.h
+	  as well. As it turns out, this header file has been provided by
+	  the library since 2006, so this is a relatively benign change.
+	  ASTERISK-24436 #close Reported by: Patrick Laimbock ........
+	  Merged revisions 426140 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-20 14:10 +0000 [r425986]  Matthew Jordan <mjordan at digium.com>
+
+	* UPGRADE.txt, res/res_xmpp.c, res/res_jabber.c, main/tcptls.c:
+	  AST-2014-011: Fix POODLE security issues There are two aspects to
+	  the vulnerability: (1) res_jabber/res_xmpp use SSLv3 only. This
+	  patch updates the module to use TLSv1+. At this time, it does not
+	  refactor res_jabber/res_xmpp to use the TCP/TLS core, which
+	  should be done as an improvement at a latter date. (2) The
+	  TCP/TLS core, when tlsclientmethod/sslclientmethod is left
+	  unspecified, will default to the OpenSSL SSLv23_method. This
+	  method allows for all encryption methods, including SSLv2/SSLv3.
+	  A MITM can exploit this by forcing a fallback to SSLv3, which
+	  leaves the server vulnerable to POODLE. This patch adds WARNINGS
+	  if a user uses SSLv2/SSLv3 in their configuration, and explicitly
+	  disables SSLv2/SSLv3 if using SSLv23_method. For TLS clients,
+	  Asterisk will default to TLSv1+ and WARN if SSLv2 or SSLv3 is
+	  explicitly chosen. For TLS servers, Asterisk will no longer
+	  support SSLv2 or SSLv3. Much thanks to abelbeck for reporting the
+	  vulnerability and providing a patch for the res_jabber/res_xmpp
+	  modules. Review: https://reviewboard.asterisk.org/r/4096/
+	  ASTERISK-24425 #close Reported by: abelbeck Tested by: abelbeck,
+	  opsmonitor, gtjoseph patches: asterisk-1.8-jabber-tls.patch
+	  uploaded by abelbeck (License 5903)
+	  asterisk-11-jabber-xmpp-tls.patch uploaded by abelbeck (License
+	  5903) AST-2014-011-1.8.diff uploaded by mjordan (License 6283)
+	  AST-2014-011-11.diff uploaded by mjordan (License 6283)
+
+2014-10-17 13:09 +0000 [r425819]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: channels/chan_sip: Respect outboundproxy
+	  setting when sending qualify requests The outboundproxy setting
+	  is currently ignored when sending OPTIONS requests as a result of
+	  the qualify setting. This means that if an Asterisk server is
+	  unable to send the packet directly to a peer, it is unable to
+	  qualify any non-inbound registered peer (e.g. a peer SIP Trunk).
+	  This patch grabs the outboundproxy information for a peer when a
+	  qualify attempt is being constructed and, if it finds the
+	  information, uses it when sending the OPTIONS request. Review:
+	  https://reviewboard.asterisk.org/r/3948 ASTERISK-24063 #close
+	  Reported by: Damian Ivereigh patches: outboundproxy-dai.patch
+	  uploaded by Damian Ivereigh (License 6632) ........ Merged
+	  revisions 425818 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-16 06:04 +0000 [r425667]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix loss of voice after second call
+	  drops (on a second line) in case using multiple lines on unistim
+	  phones. There is regression was introduced in r391379. Reported
+	  by: Rustam Khankishyiev (closes issue ASTERISK-23846)
+
+2014-10-16 01:24 +0000 [r425644]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix a bug where ICE
+	  state would get reset when it shouldn't. In the case where the
+	  ICE negotiation had not yet started current state would get wiped
+	  when it shouldn't. This also removes channel binding as in
+	  practice this does not work well with other implementations.
+
+2014-10-15 09:02 +0000 [r425548]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: chan_ooh323: fix rtptimeout general
+	  value checking correct condition to check rtptimeout in [general]
+	  config section ASTERISK-24393 #close Reported by: Dmitry Melekhov
+	  Tested by: Dmitry Melekhov Patches: ASTERISK-24393.patch ........
+	  Merged revisions 425547 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-14 16:44 +0000 [r425407-425457]  Corey Farrell <git at cfware.com>
+
+	* res/res_fax.c: res_fax: Fix reference leak caused by gateway
+	  sessions Fax gateway session objects can be re-used, causing the
+	  same gateway session to be added to faxregistry.container more
+	  than once. This change causes fax_session_new to remove the
+	  reserved session from the container before it's id is changed,
+	  ensuring it's possible for the session to be freed.
+	  ASTERISK-24392 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4049/
+
+	* /, res/res_fax.c: res_fax: Resolve module reference leak caused
+	  by reserved sessions Remove reference to module providing
+	  reserved session after adding a reference to the final module.
+	  This re-reference is done to ensure that module references are
+	  correct even if the final session selects a different module than
+	  the reserved session. ASTERISK-18923 #close Reported by: Grigoriy
+	  Puzankin Review: https://reviewboard.asterisk.org/r/4048/
+	  ........ Merged revisions 425405 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-12 21:08 +0000 [r425360]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Make the ICE transport
+	  check case insensitive as some implementations use 'udp'.
+
+2014-10-12 08:13 +0000 [r425287-425297]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: Fix so asterisk won't send
+	  reINVITE after a BYE. After a reINVITE glare situation, Asterisk
+	  would re-send the reINVITE even though the call had been hung up
+	  in the mean time. This patch unschedules the reinvite when
+	  handling the BYE. ASTERISK-22791 #close Reported by: Paolo
+	  Compagnini Tested by: Paolo Compagnini Review:
+	  https://reviewboard.asterisk.org/r/4056/ (testcase is in review
+	  r4055) ........ Merged revisions 425296 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* Makefile, /: build: Relax badshell tilde test to allow for ~ in
+	  middle of DESTDIR. The main Makefile has a target test called
+	  'badshell' that tests if DESTDIR does not happen to have an
+	  an-expanded tilde (~). This might be the case if you run: make
+	  install DESTDIR=~/somewhere/ That test also disallowed valid
+	  tildes in directory names. The test is now changed to only
+	  trigger on a tilde at the start of the path. ASTERISK-13797
+	  #close Reported by: Tzafrir Cohen Review:
+	  https://reviewboard.asterisk.org/r/4064/ ........ Merged
+	  revisions 425291 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_calendar_ews.c, /: res_calendar_ews: Relax neon version
+	  check to work with 0.30 too. Allow res_calendar_ews to work not
+	  only with libneon-0.29 but also with 0.30. ASTERISK-24325 #close
+	  Reported by: Tzafrir Cohen Review:
+	  https://reviewboard.asterisk.org/r/4068/ ........ Merged
+	  revisions 425286 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-10 12:55 +0000 [r425153]  Kinsey Moore <kmoore at digium.com>
+
+	* /, tests/test_callerid.c, main/callerid.c: CallerID: Fix parsing
+	  regression This fixes a regression in callerid parsing introduced
+	  when another bug was fixed. This bug occurred when the name was
+	  composed entirely of DTMF keys and quoted without a number
+	  section (<>). ASTERISK-24406 #close Reported by: Etienne Lessard
+	  Tested by: Etienne Lessard Patches: callerid_fix.diff uploaded by
+	  Kinsey Moore Review: https://reviewboard.asterisk.org/r/4067/
+	  ........ Merged revisions 425152 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-10 07:25 +0000 [r425069]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: Fix dialog leak resulting from
+	  missing ACK to re-INVITE. If a device re-INVITEs at the same time
+	  as the dialog is hung up, and if then the ACK to the re-INVITE
+	  never reaches Asterisk, chan_sip would fail to destroy the dialog
+	  after a while. This resulted in (most prominently) file handle
+	  leaks. (Patch reindented by me.) ASTERISK-20784 #close
+	  ASTERISK-15879 #close Reported by: Torrey Searle, Nitesh Bansal
+	  Patches: reinvite_ack_timeout.patch uploaded by Torrey Searle
+	  (License #5334) patch_asterisk_20784.txt uploaded by Nitesh
+	  Bansal (License #6418) Reviewboard:
+	  https://reviewboard.asterisk.org/r/4052/ (testcase can be found
+	  at r4051) ........ Merged revisions 425068 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-09 21:26 +0000 [r425029]  Kevin Harwell <kharwell at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Crash if no candidates
+	  received for component When starting ice if there is not at least
+	  one remote ice candidate with an RTP component asterisk will
+	  crash. This is due to an assertion in pjnath as it expects at
+	  least one candidate with an RTP component. Added a check to make
+	  sure at least one candidate contains an RTP component and at
+	  least one candidate has an RTCP component. ASTERISK-24383 #close
+	  Review: https://reviewboard.asterisk.org/r/4039/
+
+2014-10-09 08:06 +0000 [r424878]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* contrib/scripts/safe_asterisk, /: safe_asterisk: Don't
+	  automatically exceed MAXFILES value of 2^20. On systems with lots
+	  of RAM (e.g. 24GB) /proc/sys/fs/file-max divided by two can
+	  exceed the per-process file limit of 2^20. This patch ensures the
+	  value is capped. (Patch cleaned up by me.) ASTERISK-24011 #close
+	  Reported by: Michael Myles Patches: safe_asterisk-ulimit.diff
+	  uploaded by Michael Myles (License #6626) ........ Merged
+	  revisions 424875 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-08 18:44 +0000 [r424852]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Allow only UDP ICE
+	  candidates. The underlying library, pjnath, that res_rtp_asterisk
+	  uses for ICE support does not have support for ICE-TCP. As
+	  candidates are passed through directly to it this can cause error
+	  messages to occur when it receives something unexpected (such as
+	  a TCP candidate). This change merely ignores all non-UDP
+	  candidates so they never reach pjnath. ASTERISK-24326 #close
+	  Reported by: Joshua Colp
+
+2014-10-07 21:30 +0000 [r424787]  Corey Farrell <git at cfware.com>
+
+	* /, main/astobj2.c: astobj2: Correct REF_DEBUG false leak report
+	  When ao2_callback is run with OBJ_MULTIPLE and not OBJ_NODATA it
+	  allocates a temporary container in a way that does not record
+	  REF_DEBUG log entries. This changes that container to correctly
+	  record unref's when the container is freed. ASTERISK-24390 #close
+	  Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4047/ ........ Merged
+	  revisions 424786 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-10-06 18:36 +0000 [r424690]  Matthew Jordan <mjordan at digium.com>
+
+	* main/message.c: message: Don't close an AMI connection on
+	  SendMessage action error If SendMessage encounters an error (such
+	  as incorrect input provided to the action), it will currently
+	  return -1. Actions should only return -1 if the connection to the
+	  AMI client should be closed. In this case, SendMessage causing
+	  the client to disconnect is inappropriate. This patch causes the
+	  action to return 0, which simply causes the action to fail.
+	  Review: https://reviewboard.asterisk.org/r/4024 ASTERISK-24354
+	  #close Reported by: Peter Katzmann patches: sendMessage.patch
+	  uploaded by Peter Katzmann (License 5968)
+
+2014-10-05 00:41 +0000 [r424550-424578]  Corey Farrell <git at cfware.com>
+
+	* main/manager.c: Release AMI connections on shutdown.
+	  ASTERISK-24378 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4037/
+
+	* channels/chan_sip.c: chan_sip: Clean leak on error path of
+	  process_sdp Resolve leak in process_sdp that occurs in 2 error
+	  path's where crypto lines are expected but not provided.
+	  ASTERISK-24385 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4045/
+
+	* channels/chan_motif.c: chan_motif: Release format capabilities
+	  and config on module load error ASTERISK-24384 #close Reported
+	  by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/4043/
+
+2014-10-01 10:08 +0000 [r424177-424182]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: Simplify some unref code by
+	  removing unlink_peer_from_tables. ASTERISK-22945 #related
+	  Reported by: ibercom Patches:
+	  asterisk11-chan_sip-simplifies.patch uploaded by ibercom (License
+	  #6599) ........ Merged revisions 424181 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: chan_sip: Remove excess ref of realtime
+	  peer before sip_poke_peer. The peer is referenced at the end of
+	  sip_poke_peer, it should not get an extra ref before the call to
+	  sip_poke_peer. This fixes a memory leak. ASTERISK-22945 #close
+	  Reported by: ibercom Tested by: Yuriy Gorlichenko Patches:
+	  asterisk11.patch uploaded by ibercom (License #6599) Review:
+	  https://reviewboard.asterisk.org/r/4031/ ........ Merged
+	  revisions 424176 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-30 11:31 +0000 [r424151]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Ensure that the base
+	  and mapped address for candidates is present in SDP. This change
+	  fixes an issue where ICE candidates put into the SDP did not
+	  contain the 'raddr' and 'rport' information for server reflexive
+	  and relay candidates. #SIPit31
+
+2014-09-29 21:21 +0000 [r424117]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* contrib/scripts/autosupport: autosupport: Fix bashism. '==' is
+	  bashism (bashspecific, fails when dash is /bin/sh). Anyway, a
+	  'case' works better there. Originally committed in r375059 and
+	  r375060 on 2012-10-16 21:13:08. ASTERISK-20567 #close Reported
+	  by: Tzafrir Cohen
+
+2014-09-26 15:18 +0000 [r423983]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, res/res_fax.c: res_fax: Fix out of bounds error in
+	  update_modem_bits(). ASTERISK-24357 #close Reported by: Jeremy
+	  Laine Patches: res_fax_bounds.patch (license #6561) patch
+	  uploaded by Jeremy Laine Modified patch to not use magic numbers.
+	  ........ Merged revisions 423979 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-26 08:23 +0000 [r423916]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, doc/asterisk.8: docs: Escape unescaped minus sign in
+	  asterisk.8 manpage. ASTERISK-23768 #close Reported by: Jeremy
+	  Lainé Patches: escape_manpage_hyphen.patch uploaded by Jeremy
+	  Lainé (License #6561) ........ Merged revisions 423915 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-24 08:49 +0000 [r423801]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: Unref outbound proxy structure
+	  on dialog/pvt destruction. Make sure outbound proxy refs are
+	  always unreffed on dialog destruction. Review:
+	  https://reviewboard.asterisk.org/r/4016/ ........ Merged
+	  revisions 423800 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-22 19:46 +0000 [r423658-423721]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: On INVITE retransmission, don't
+	  add an extra 503 response. INVITE arrives to asterisk, asterisk
+	  responds Busy(). If the INVITE is retransmitted, asterisk would
+	  generate a 503 in addition to the 486. Thanks Torrey Searle for
+	  providing a working regression test. ASTERISK-24335 #close
+	  Review: https://reviewboard.asterisk.org/r/4003/ Patches:
+	  retrans_486_invite.patch uploaded by Torrey Searle (License
+	  #5334) ........ Merged revisions 423720 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/editline/readline.c: cli.c: Fix tab completion "module
+	  load" when MALLOC_DEBUG is enabled. r421600 conflicted with
+	  r155763. ASTERISK-24348 #close ........ Merged revisions 423657
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-24  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.13.0 Released.
+
+2014-09-19  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.13.0-rc1 Released.
+
+2014-09-18 16:30 +0000 [r423400]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/astobj2.c, contrib/scripts/refcounter.py:
+	  astobj2.c/refcounter.py: Fix to deal with invalid object refs. *
+	  Make astob2 REF_DEBUG output an invalid object line when an
+	  invalid ao2 object ref/unref is attempted. This is similar to the
+	  constructor/destructor lines. * Fixed refcounter.py to handle
+	  skewed objects that have constructor/destructor states. * Made
+	  refcounter.py highlight the invalid ao2 object refs by putting
+	  them in their own section of the processed output file. * Made
+	  refcounter.py highlight unreffing an object by more than one that
+	  results in a negative ref count and the object being destroyed.
+	  The abnormally destroyed object is reported in the invalid and
+	  finalized object sections of the output. Review:
+	  https://reviewboard.asterisk.org/r/3971/ ........ Merged
+	  revisions 423349 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-18 16:19 +0000 [r423360]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_fax_spandsp.c: res_fax_spandsp: Properly handle cleanup
+	  before starting FAXes. If faxing fails at a very early stage,
+	  then it is possible for us to pass a NULL t30 state pointer to
+	  spandsp, which spandsp is none too pleased with. This patch
+	  ensures that we pass the correct pointer to spandsp in the
+	  situation where we have not yet set our local t30 state pointer.
+	  ASTERISK-24301 #close Reported by Matt Jordan Patches:
+	  ASTERISK-24301-fax.diff Uploaded by Mark Michelson (License
+	  #5049)
+
+2014-09-18 14:42 +0000 [r423277]  George Joseph <george.joseph at fairview5.com>
+
+	* main/config.c, main/manager.c, /, include/asterisk/config.h:
+	  config: bug: Fix SEGV in ast_category_insert when matching
+	  category isn't found If you call ast_category_insert with a match
+	  category that doesn't exist, the list traverse runs out of 'next'
+	  categories and you get a SEGV. This patch adds check for the
+	  end-of-list condition and changes the signature to return an int
+	  for success/failure indication instead of a void. The only
+	  consumer of this function is manager and it was also changed to
+	  use the return value. Tested by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/3993/ ........ Merged
+	  revisions 423276 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-17 18:02 +0000 [r423150-423253]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Ensure that the thread
+	  terminating pj stuff is registered.
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix 100% CPU usage due
+	  to timer heap thread spinning. Side note: I need a vacation.
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix building when
+	  pjproject is not used.
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix a myriad of TURN
+	  client issues. 1. The number of file descriptors an ioqueue
+	  instance can handle is fixed, so we now spawn the required number
+	  to handle the load. 2. Our transport identifiers were exceeding
+	  the range supported by pjnath. 3. The TURN client did not set up
+	  client binding causing needless bandwidth usage. 4. The code no
+	  longer updates address information on each packet. 5. STUN
+	  traffic was getting looped back to Asterisk instead of going
+	  through the TURN server. 6. Synchronization now ensures things
+	  are completely setup or destroyed. 7. Logging now reflects the
+	  target the TURN server is sending to/receiving from on our
+	  behalf. ASTERISK-23577 #close Reported by: Jay Jideliov
+	  ASTERISK-23634 #close Reported by: Roman Skvirsky Review:
+	  https://reviewboard.asterisk.org/r/3982/
+
+2014-09-14 15:49 +0000 [r423067]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* configs/sip.conf.sample, /: chan_sip: Clarify that sipdebug=yes
+	  cannot be undone by the CLI. Document it in sip.conf.
+	  ASTERISK-24249 #close Reported by: Avinash Mohod Review:
+	  https://reviewboard.asterisk.org/r/3926/ ........ Merged
+	  revisions 423066 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-12 18:18 +0000 [r423010]  Kinsey Moore <kmoore at digium.com>
+
+	* main/channel.c, /: Bridging: Fix bouncing native bridge This
+	  fixes a situation in Asterisk 1.8 and 11 where ast_channel_bridge
+	  could cause a bouncing native bridge. In the case of the
+	  dial_LS_options test, this was a remote RTP bridge which caused
+	  the audio path to continually cycle between Asterisk and the
+	  remote endpoints generating a large number of SIP messages and
+	  delaying the test long enough to cause it to fail (checking
+	  timing was part of the test). The root cause was that the code to
+	  decide whether to use native bridging was expecting a
+	  time-remaining value of 0 to be the default instead of the actual
+	  default value of -1. A value of 0 or negative numbers could also
+	  be generated by preceding code in some circumstances. Both issues
+	  are addressed in this patch. ASTERISK-24211 #close Reported by:
+	  Matt Jordan Review: https://reviewboard.asterisk.org/r/3987/
+	  ........ Merged revisions 423006 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-10 16:01 +0000 [r422903]  George Joseph <george.joseph at fairview5.com>
+
+	* /, main/config.c: config: bug: fix truncation of included config
+	  files on permissions error ast_config_text_file_save() currently
+	  truncates include files as they are processed. If a subsequent
+	  include file or the main config file has a permissions error that
+	  prevents writing, earlier include files are left truncated
+	  resulting in a frantic search for backups. This patch causes
+	  ast_config_text_file_save to check for write access on all files
+	  before it truncates any of them. Will be applied 1.8 > trunk.
+	  Tested by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/3986/ ........ Merged
+	  revisions 422900 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-07 00:08 +0000 [r422790]  Rusty Newton <rnewton at digium.com>
+
+	* sounds/sounds.xml, sounds/Makefile, /: Sounds/BuildSystem:
+	  Modifications to include new releases and Japanese language.
+	  Modifying Makefile and sounds.xml to include new core 1.4.26 and
+	  extra 1.4.15 sound prompt releases, plus the new Japanese core
+	  sound prompts contributed by QLOOG. ASTERISK-23324 Reported by:
+	  Kevin McCoy Tested by: Rusty Newton ........ Merged revisions
+	  422789 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-09-04 20:39 +0000 [r422625]  Jonathan Rose <jrose at digium.com>
+
+	* main/manager.c, /: Manager: Require read permission for SYSTEM in
+	  order to send FullyBooted Review:
+	  https://reviewboard.asterisk.org/r/3969/ ........ Merged
+	  revisions 422584 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-30 17:22 +0000 [r422440]  George Joseph <george.joseph at fairview5.com>
+
+	* main/manager.c, /: manager: Make WaitEvent action respect
+	  eventfilters A WaitEvent issued via an http session isn't
+	  respecting eventfilters defined for the user. I just added a
+	  match_filter to the predicate that controls astman_append. Tested
+	  by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/3958/ ........ Merged
+	  revisions 422439 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-29 19:39 +0000 [r422294-422377]  Matthew Jordan <mjordan at digium.com>
+
+	* doc/smsq.8 (added), /: doc: Add a manpage for the smsq utility
+	  This patch adds a manpage for the smsq utility. Note that this is
+	  one of the patches the Debian distro applies for the Asterisk
+	  project, as per ASTERISK-24191. Review:
+	  https://reviewboard.asterisk.org/r/3895/ ASTERISK-24171 #close
+	  Reported by: Jeremy Laine patches: smsq.8 uploaded by Jeremy
+	  Laine (License 6561) ........ Merged revisions 422376 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* doc/aelparse.8 (added), /: doc: Add a manpage for the aelparse
+	  utility This patch adds a manpage for the aelparse utility. Note
+	  that this is one of the patches the Debian distro applies for the
+	  Asterisk project, as per ASTERISK-24191. Review:
+	  https://reviewboard.asterisk.org/r/3896/ ASTERISK-24171 #close
+	  Reported by: Jeremy Laine patches: aelparse.8 uploaded by Jeremy
+	  Laine (License 6561) ........ Merged revisions 422371 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, LICENSE: LICENSE: Clarify language in Asterisk's LICENSE to
+	  allow for linking to UniMRCP The UniMRCP project distributes
+	  Asterisk modules that integrate Asterisk with UniMRCP, and other
+	  Asterisk users use the UniMRCP library as well. Unfortunately,
+	  the UniMRCP license is Apache 2.0, which per the Free Software
+	  Foundation, is not a compatible license with the GPLv2. "Please
+	  note that this license is not compatible with GPL version 2,
+	  because it has some requirements that are not in that GPL
+	  version. These include certain patent termination and
+	  indemnification provisions. The patent termination provision is a
+	  good thing, which is why we recommend the Apache 2.0 license for
+	  substantial programs over other lax permissive licenses." On the
+	  other hand, UniMRCP is a great project and we'd like to let
+	  people use it with Asterisk. This patch updates the LICENSE text
+	  to allow users to link Asterisk with UniMRCP and distribute the
+	  resulting binaries. ........ Merged revisions 422293 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-28 20:26 +0000 [r422274]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_iax2.c: chan_iax2: Fix Dynamic IAX2 Registrations
+	  After Temporary DNS Failure The reporter on the issue found some
+	  issues when upgrading from version 10 to 11 on 55 hosts. Two
+	  situations that can occur with dynamic registrations. 1. With
+	  dnsmgr disabled, if the host is not resolvable we are not trying
+	  to resolve the host again when it is time to attempt to register
+	  again. This results in never registering to the host. 2. With
+	  dnsmgr enabled, when the host is temporarily not resolvable the
+	  address is set to 0.0.0.0:0 and then when the host is resolvable
+	  the port is not being restored and stays set to 0. This patch
+	  resolves these two issues by: * Storing the hostname so that it
+	  can be used for resolving with DNS. * Resolve the hostname on the
+	  next scheduled attempt to register. * Storing the port used to
+	  reach the host so that when the hostname is resolvable again, we
+	  can set the port again if the port is still unset after looking
+	  up the host. ASTERISK-23767 #close Reported by: David Herselman
+	  Tested by: David Herselman, Michael L. Young Patches:
+	  asterisk-23767-dns_reg_retry_and_set_port_11_v3.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/3856/
+
+2014-08-27 15:01 +0000 [r422113]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c, tests/test_callerid.c (added),
+	  tests/test_utils.c, main/callerid.c, main/utils.c,
+	  include/asterisk/utils.h: CallerID: Fix parsing of malformed
+	  callerid This allows the callerid parsing function to handle
+	  malformed input strings and strings containing escaped and
+	  unescaped double quotes. This also adds a unittest to cover many
+	  of the cases where the parsing algorithm previously failed.
+	  Review: https://reviewboard.asterisk.org/r/3923/ ........ Merged
+	  revisions 422112 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-25 16:07 +0000 [r421977]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, res/res_musiconhold.c: res_musiconhold: Fix MOH restarting
+	  where it left off from the last hold. Restore code removed by
+	  https://reviewboard.asterisk.org/r/3536/ that introduced a
+	  regression that prevents MOH from restarting were it left off the
+	  last time. ASTERISK-24019 #close Reported by: Jason Richards
+	  Patches: jira_asterisk_24019_v1.8.patch (license #5621) patch
+	  uploaded by rmudgett Review:
+	  https://reviewboard.asterisk.org/r/3928/ ........ Merged
+	  revisions 421976 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-24 17:19 +0000 [r421909]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Use the server reflexive ICE
+	  candidate RTCP port as provided. This code originally worked
+	  around an issue within res_rtp_asterisk itself. The wrong socket
+	  was being used for the STUN check for RTCP, causing the port to
+	  be the same as RTP. This was subsequently fixed and the RTCP port
+	  provided for the ICE candidate is correct and does not need to be
+	  incremented. ASTERISK-23997 #close Reported by: Badalian
+	  Vyacheslav Patches: plus1.diff submitted by Badalian Vyacheslav
+	  (license 5249)
+
+2014-08-21 22:03 +0000 [r421800]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, res/res_musiconhold.c: res_musiconhold.c: Remove obsolete
+	  REF_DEBUG code. Remove unneeded code that writes to the wrong
+	  file location in an obsolete format. ........ Merged revisions
+	  421799 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-21 21:00 +0000 [r421777]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_musiconhold.c, /: res_musiconhold: Fix reference leaks
+	  caused when reloading with REF_DEBUG set Due to a faulty function
+	  for debugging reference decrementing, it was possible to reduce
+	  the refcount on the wrong object if two moh classes of the same
+	  name were in the moh class container. (closes issue
+	  ASTERISK-22252) Reported by: Walter Doekes Patches:
+	  18_moh_debug_ref_patch.diff Uploaded by Jonathan Rose (license
+	  6182) ........ Merged revisions 398937 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-21 17:32 +0000 [r421718]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Don't use port derived from
+	  fromdomain if it isn't set If a user does not provide a port in
+	  the fromdomain setting, chan_sip will set the fromdomainport to
+	  STANDARD_SIP_PORT (5060). The fromdomainport value will then get
+	  used unilaterally in certain places. This causes issues with TLS,
+	  where the default port is expected to be 5061. This patch
+	  modifies chan_sip such that fromdomainport is only used if it is
+	  not the standard SIP port; otherwise, the port from the SIP pvt's
+	  recorded self IP address is used. Review:
+	  https://reviewboard.asterisk.org/r/3893/ ASTERISK-24178 #close
+	  Reported by: Elazar Broad patches: fromdomainport_fix.diff
+	  uploaded by Elazar Broad (License 5835) ........ Merged revisions
+	  421717 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-20 22:17 +0000 [r421602]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/cli.c: cli.c: Fix tab completion of "module load" when
+	  MALLOC_DEBUG is enabled. filename_completion_function() returns
+	  memory that was not allocated by the MALLOC_DEBUG allocation
+	  tracker so the memory must be freed by ast_std_free(). ........
+	  Merged revisions 421600 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-19 19:41 +0000 [r421443]  Kinsey Moore <kmoore at digium.com>
+
+	* main/manager.c, /: AMI Docs: Fix Status channel parameter
+	  optionality ........ Merged revisions 421442 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-18 20:16 +0000 [r421328]  George Joseph <george.joseph at fairview5.com>
+
+	* funcs/func_config.c, /: func_config: Change 'Not Found' message
+	  from ERROR to DEBUG When you call the CONFIG dialplan function
+	  with the name of a variable that doesn't exist in the target
+	  context you get an ERROR. This does nothing but clutter up the
+	  logs with messages that may be perfectly acceptable. Just because
+	  a variable wasn't in the context doesn't mean it's an error.
+	  Maybei t's optional or just needs to be defaulted or ignored.
+	  This patch changes the log level from ERROR to DEBUG. If a
+	  dialplan developer wants to debug their dialplan they still canby
+	  setting the console debug level as needed. Tested by: George
+	  Joseph Review: https://reviewboard.asterisk.org/r/3919/ ........
+	  Merged revisions 421327 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-17 23:07 +0000 [r421228-421233]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_dial.c, /: apps/app_dial: Fix Dial 'z' option The 'z'
+	  option is supposed to disable the dial timeout in the case of a
+	  call forward. Unfortunately, the wrong timeout timer was passed
+	  to the do_forward function, resulting in the option not working.
+	  ASTERISK-24225 #close Reported by: dimitripietro Tested by:
+	  dimitripietro patches: jira_asterisk_24225_v1.8.patch uploaded by
+	  rmudgett (License 5621) jira_asterisk_24225_v11.patch uploaded by
+	  rmudgett (License 5621) ........ Merged revisions 421232 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, configure, configure.ac: configure: Undefine FORTIFY_SOURCE
+	  prior to defining it for patched gcc Some distributions of Linux
+	  patch gcc to define FORTIFY_SOURCE when gcc is executed with
+	  optimization. This "help" unfortunately results in re-definition
+	  warnings when FORTIFY_SOURCE is later defined in Asterisk's build
+	  system. This patch undefines FORTIFY_SOURCE prior to defining it
+	  to prevent this warning. Review:
+	  https://reviewboard.asterisk.org/r/3912/ ASTERISK-24032 #close
+	  Reported by: Kilburn Tested by: Kilburn, wdoekes patches:
+	  1.8.diff uploaded by cloos (License 5956) 10.diff uploaded by
+	  cloos (License 5956) 11.diff uploaded by cloos (License 5956)
+	  12.diff uploaded by cloos (License 5956) 13.diff uploaded by
+	  cloos (License 5956) ........ Merged revisions 421227 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-15 15:36 +0000 [r421060-421164]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c, main/app.c: app_voicemail/app: Remove test
+	  events that were duplicated by r421059 Moving the test event
+	  raised when a file is played back (which occurred in r421059)
+	  broke the ever loving snot out of the voicemail tests. This
+	  caused duplicate test events to get raised, as app_voicemail and
+	  main/app were raising events prior to call ast_streamfile. The
+	  voicemail tests did not enjoy getting multiple events. Since
+	  raising the playback event in ast_streamfile is far more useful
+	  to the vast majority of tests, this patch keeps the call there
+	  and simply removes the extraneous calls that duplicated the
+	  event. ........ Merged revisions 421125 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/file.c, main/app.c: main/file: Move test event to emit
+	  PLAYBACK event more consistently This is being done in advance of
+	  the test for ASTERISK-23953 ........ Merged revisions 421059 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-13 07:47 +0000 [r420897]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* main/logger.c: logger: Don't store verbose-magic in the log
+	  files. In r399267, the verbose2magic stuff was edited. This time
+	  it results in magic characters in the log files for multiline
+	  messages. In trunk (and 13) this was fixed by the "stripping" of
+	  those characters from multiline messages (in r414798). This is a
+	  backport of that fix to 11. That fix is altered to actually strip
+	  the characters and not replace them with blanks. Review:
+	  https://reviewboard.asterisk.org/r/3901/ Review:
+	  https://reviewboard.asterisk.org/r/3902/
+
+2014-08-19  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.12.0 Released.
+
+2014-08-11  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.12.0-rc1 Released.
+
+2014-08-11 10:36 +0000 [r420655-420715]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, main/utils.c: general: Fix memory Corruption in
+	  __ast_string_field_ptr_build_va. If the space left in a
+	  stringfield is between 0 and
+	  (alignof(ast_string_field_allocation)-1) adding new data would
+	  cause memory corruption, because we would assume enough space
+	  (unsigned underrun). Thanks Arnd Schmitter for reporting and
+	  finding out the cause! ASTERISK-23508 #close Reported by: Arnd
+	  Schmitter Tested by: Arnd Schmitter, JoshE Review:
+	  https://reviewboard.asterisk.org/r/3898/ ........ Merged
+	  revisions 420680 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/tcptls.c, /: tcptls: Avoid compiler warning on non-dev-mode.
+	  ........ Merged revisions 420654 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-07 21:37 +0000 [r420435]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Replace sip_tls_read() and
+	  resolve the large SDP poll issue. Replace sip_tls_read() and
+	  sip_tcp_read() with a single function and resolve the poll/wait
+	  issue with large SDP payloads. ASTERISK-18345 #close Reported by:
+	  Stephane Chazelas Patches: tcptls_pollv4.diff (license #5835)
+	  patch uploaded by Elazar Broad Review:
+	  https://reviewboard.asterisk.org/r/3882/ ........ Merged
+	  revisions 420434 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-06 16:08 +0000 [r420147]  George Joseph <george.joseph at fairview5.com>
+
+	* pbx/pbx_lua.c, main/pbx.c, /: pbx_lua: fix regression with global
+	  sym export and context clash by pbx_config. ASTERISK-23818 (lua
+	  contexts being overwritten by contexts of the same name in
+	  pbx_config) surfaced because pbx_lua, having the
+	  AST_MODFLAG_GLOBAL_SYMBOLS set, was always force loaded before
+	  pbx_config. Since I couldn't find any reason for pbx_lua to
+	  export it's symbols to the rest of Asterisk, I simply changed the
+	  flag to AST_MODFLAG_DEFAULT. Problem solved. What I didn't
+	  realize was that the symbols need to be exported not because
+	  Asterisk needs them but because any external Lua modules like
+	  luasql.mysql need the base Lua language APIs exported
+	  (ASTERISK-17279). Back to ASTERISK-23818... It looks like there's
+	  an issue in pbx.c where context_merge was only merging includes,
+	  switches and ignore patterns if the context was already existing
+	  AND has extensions, or if the context was brand new. If pbx_lua
+	  is loaded before pbx_config, the context will exist BUT pbx_lua,
+	  being implemented as a switch, will never place extensions in it,
+	  just the switch statement. The result is that when pbx_config
+	  loads, it never merges the switch statement created by pbx_lua
+	  into the final context. This patch sets pbx_lua's modflag back to
+	  AST_MODFLAG_GLOBAL_SYMBOLS and adds an "else if" in context_merge
+	  that catches the case where an existing context has includes,
+	  switchs or ingore patterns but no actual extensions.
+	  ASTERISK-23818 #close Reported by: Dennis Guse Reported by: Timo
+	  Teräs Tested by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/3891/ ........ Merged
+	  revisions 420146 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-08-05 18:23 +0000 [r420054]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/format.c: format.c: Add reason comments for the format_list
+	  ordering.
+
+2014-08-04 19:44 +0000 [r419943]  Rusty Newton <rnewton at digium.com>
+
+	* main/manager.c, /: Manager - Improve documentation for manager
+	  commands Getvar and Setvar. The documentation for these commands
+	  did not make it clear that they could accept expressions and
+	  functions. Modified to make this clear, but tried not to be
+	  overly explicit. ASTERISK-21178 #close Reported by: Rusty Newton
+	  Tested by: Rusty Newton Review:
+	  https://reviewboard.asterisk.org/r/3854 ........ Merged revisions
+	  419942 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-28 18:34 +0000 [r419685]  Richard Mudgett <rmudgett at digium.com>
+
+	* funcs/func_jitterbuffer.c, apps/app_queue.c,
+	  apps/app_speech_utils.c, /, funcs/func_frame_trace.c: datastores:
+	  Audit ast_channel_datastore_remove usage. Audit of v1.8 usage of
+	  ast_channel_datastore_remove() for datastore memory leaks. *
+	  Fixed leaks in app_speech_utils and func_frame_trace. * Fixed
+	  app_speech_utils not locking the channel when accessing the
+	  channel datastore list. Review:
+	  https://reviewboard.asterisk.org/r/3859/ Audit of v11 usage of
+	  ast_channel_datastore_remove() for datastore memory leaks. *
+	  Fixed leak in func_jitterbuffer. Review:
+	  https://reviewboard.asterisk.org/r/3860/ ........ Merged
+	  revisions 419684 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-25 23:13 +0000 [r419631]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/features.c, /: features.c: Allow appliationmap to use Gosub.
+	  Using DYNAMIC_FEATURES with a Gosub application as the mapped
+	  application does not work. It does not work because Gosub just
+	  pushes the current dialplan context, exten, and priority onto a
+	  stack and sets the specified Gosub location. Gosub does not have
+	  a dialplan execution loop to run dialplan like Macro. * Made the
+	  DYNAMIC_FEATURES application mapping feature call
+	  ast_app_exec_macro() and ast_app_exec_sub() for the Macro and
+	  Gosub applications respectively. * Backported
+	  ast_app_exec_macro() and ast_app_exec_sub() from v11 to execute
+	  dialplan routines from the DYNAMIC_FEATURES application mapping
+	  feature. NOTE: This issue does not affect v12+ because it already
+	  does what this patch implements. AST-1391 #close Reported by:
+	  Guenther Kelleter Review:
+	  https://reviewboard.asterisk.org/r/3844/ ........ Merged
+	  revisions 419630 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-24 17:56 +0000 [r419441]  Corey Farrell <git at cfware.com>
+
+	* /, channels/chan_sip.c: chan_sip: sip_subscribe_mwi_destroy
+	  should not call sip_destroy sip_subscribe_mwi_destroy calls
+	  sip_destroy on the reference counted mwi->call. This results in
+	  the fields of mwi->call being freed, but mwi->call itself it
+	  leaked. If other code is still using mwi->call it can cause
+	  problems. This change uses dialog_unref instead, to balance the
+	  ref provided by sip_alloc(). ASTERISK-24087 #close Reported by:
+	  Corey Farrell Review: https://reviewboard.asterisk.org/r/3834/
+	  ........ Merged revisions 419440 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-24 16:49 +0000 [r419375]  Jason Parker <jparker at digium.com>
+
+	* addons/chan_ooh323.c, /: Don't cause Asterisk to exit if
+	  ooh323.conf not found. (closes issue ASTERISK-23814) ........
+	  Merged revisions 419374 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-23 13:21 +0000 [r419284]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* apps/app_voicemail.c: app_voicemail: use a consistent generator
+	  string When updating voicemail.conf when a user changes their
+	  pin, change the generator string to be the same as the module
+	  name when reading so that the same config_hook will be called.
+	  Review: https://reviewboard.asterisk.org/r/3837/
+
+2014-07-22 14:00 +0000 [r419162]  Kinsey Moore <kmoore at digium.com>
+
+	* tests/test_voicemail_api.c, tests/test_aoc.c,
+	  tests/test_astobj2.c, tests/test_config.c,
+	  addons/ooh323c/src/printHandler.c, addons/ooh323c/src/ooq931.c,
+	  addons/chan_ooh323.c, tests/test_astobj2_thrash.c, /,
+	  apps/app_meetme.c, tests/test_abstract_jb.c, tests/test_logger.c,
+	  tests/test_event.c, tests/test_format_api.c,
+	  tests/test_hashtab_thrash.c, res/res_jabber.c: Fix more dev-mode
+	  build issues ........ Merged revisions 419129 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-15 22:05 +0000 [r418713]  Matthew Jordan <mjordan at digium.com>
+
+	* main/manager.c: manager: Return ActionID on nominal responses to
+	  PresenceState action When the PresenceState action is executed,
+	  the nominal path fails to include the ActionID in the successful
+	  response. This patch adds a call to astman_start_ack, which
+	  guarantees that an ActionID (if provided) will be sent back to
+	  the AMI client. Review: https://reviewboard.asterisk.org/r/3776/
+	  ASTERISK-23985 #close
+
+2014-07-15 17:32 +0000 [r418649]  Jonathan Rose <jrose at digium.com>
+
+	* funcs/func_uri.c, /: func_uri: URIENCODE/URIDECODE - allow empty
+	  strings as argument Previously these two dialplan functions would
+	  issue warnings and return failure when an empty string is used as
+	  the argument. Now they will not issue a warning and will
+	  successfully return an empty string. ASTERISK-23911 #close
+	  Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/3745/ ........ Merged
+	  revisions 418641 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-13 21:51 +0000 [r418465-418505]  Corey Farrell <git at cfware.com>
+
+	* /, main/astobj2.c, contrib/scripts/refcounter.py: astobj2: work
+	  around REF_DEBUG race which causes out of order log entries *
+	  Update refcounter.py to use delta's to track the current
+	  reference count. * Use result from internal_ao2_ref to write
+	  old_refcount to refs_log. Review:
+	  https://reviewboard.asterisk.org/r/3756/ ........ Merged
+	  revisions 418504 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_skel.c: Fix minor reference leaks in app_skel and
+	  TEST_FRAMEWORK * Cleanup games object in app_skel. * Cleanup
+	  stasis subscription to TEST_FRAMEWORK in manager.c (12+). Review:
+	  https://reviewboard.asterisk.org/r/3757/
+
+2014-07-11 14:23 +0000 [r418366]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/config.c: config: inform config hook of change when writing
+	  file When updated configuration is written back to the conf file
+	  - for example when a user changes their voicemail pin, make sure
+	  that any config hook that wants to know of changes is informed.
+	  Review: https://reviewboard.asterisk.org/r/3708/
+
+2014-07-10 15:35 +0000 [r418323]  Matthew Jordan <mjordan at digium.com>
+
+	* include/asterisk/xmpp.h: include/asterisk/xmpp.h: Convert
+	  indentation to tabs This is a whitespace only change.
+
+2014-07-10 01:42 +0000 [r418262]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: chan_dahdi/sig_pri: Fix type mismatch in
+	  the idledial feature's channel creation. Square pegs in round
+	  holes don't work very well. ........ Merged revisions 418261 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.11.0 Released.
+
+2014-07-08  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.11.0-rc1 Released.
+
+2014-07-03 21:48 +0000 [r417957]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_pri.h, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, /, UPGRADE.txt,
+	  channels/sig_pri.c: chan_dahdi: Add inband_on_setup_ack
+	  compatibility option. The new inband_on_setup_ack option causes
+	  Asterisk to assume inband audio may be present when a
+	  SETUP_ACKNOWLEDGE message is received. Q.931 Section 5.1.3 says
+	  that in scenarios with overlap dialing, when a dialtone is sent
+	  from the network side, progress indicator 8 "Inband info now
+	  available" MAY be sent to the CPE if no digits were received with
+	  the SETUP. It is thus implied that the ie is mandatory if digits
+	  came with the SETUP and dialtone is needed. This option should be
+	  enabled, when the network sends dialtone and you want to hear it,
+	  but the network doesn't send the progress indicator when needed.
+	  NOTE: For Q.SIG setups this option should be enabled when
+	  outgoing overlap dialing is also enabled because Q.SIG does not
+	  send the progress indicator with the SETUP ACK. The commit
+	  -r413714 (AST-1338) which causes this issue was dealing with a
+	  SIP-to-ISDN interoperability issue. This commit is a merge of the
+	  two patches indicated below. ASTERISK-23897 #close Reported by:
+	  Pavel Troller Patches: pri-4.diff (license #6302) patch uploaded
+	  by Pavel Troller jira_asterisk_23897_v11.patch (license #5621)
+	  patch uploaded by rmudgett Review:
+	  https://reviewboard.asterisk.org/r/3633/ ........ Merged
+	  revisions 417956 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-07-03 11:24 +0000 [r417798]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/utils.c: main/untils: Prevent potential infinite loop in
+	  ast_careful_fwrite A loop in ast_careful_fwrite exists that will
+	  continually attempt to write to a file stream, even in the
+	  presence of EAGAIN/EINTR errors. However, if a connection that
+	  uses ast_careful_fwrite closes suddenly, ast_careful_fwrite's
+	  call to fflush may return EAGAIN/EINTER along with EOF. A
+	  subsequent call to fflush will return EOF but not clear errno,
+	  resulting in an infinite loop. This patch clears errno after it
+	  is detected and handled the loop, such that any subsequent call
+	  to fflush will not get erroneously stuck. Review:
+	  https://reviewboard.asterisk.org/r/3704 #ASTERISK-23984 #close
+	  Reported by: Steve Davies patches: fflush_loop_fix uploaded by
+	  one47 (License 5012) ........ Merged revisions 417797 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-30 19:42 +0000 [r417677]  Joshua Colp <jcolp at digium.com>
+
+	* channels/sip/include/sip.h, res/res_rtp_asterisk.c,
+	  main/rtp_engine.c, channels/chan_sip.c, UPGRADE.txt,
+	  configs/sip.conf.sample, include/asterisk/rtp_engine.h:
+	  res_rtp_asterisk: Add SHA-256 support for DTLS and perform DTLS
+	  negotiation on RTCP. This change fixes up DTLS support in
+	  res_rtp_asterisk so it can accept and provide a SHA-256
+	  fingerprint, so it occurs on RTCP, and so it occurs after ICE
+	  negotiation completes. Configuration options to chan_sip have
+	  also been added to allow behavior to be tweaked (such as forcing
+	  the AVP type media transports in SDP). ASTERISK-22961 #close
+	  Reported by: Jay Jideliov Review:
+	  https://reviewboard.asterisk.org/r/3679/
+
+2014-06-30 03:23 +0000 [r417588]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: be more tolerant of whitespace
+	  between attributes in SDP fmtp line This patch is essentially a
+	  backport of a small portion of r397526 from ASTERISK-21981. In
+	  that patch, pass through support and format attribute negotiation
+	  was added for Opus. Part of that included being more tolerant to
+	  whitespace in the fmtp line of an SDP; that part of the patch is
+	  being applied here. As the author of the backport pointed out, in
+	  SDP, the fmtp line is allowed to include whitespace between
+	  attributes. RFC 3267 chapter 8.3 (from 2001) includes an example
+	  for this. This was not removed in the updated RFC 4867 in 2007.
+	  Review: https://reviewboard.asterisk.org/r/3658 ASTERISK-23916
+	  #close Reported by: Alexander Traud patches:
+	  sdpFMTPspace_Asterisk11.patch uploaded by Alexander Traud
+	  (License 6520) ........ Merged revisions 417587 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-27 19:26 +0000 [r417481-417505]  Corey Farrell <git at cfware.com>
+
+	* /, main/astobj2.c: Ensure REF_DEBUG records entrys for attempts
+	  to ao2_ref an invalid object This change ensures that
+	  __ao2_ref_debug writes to ref_log when given a non-NULL pointer
+	  to an invalid ao2 object. This is to ensure that we record any
+	  attempt manipulate references of already freed objects.
+	  ASTERISK-23948 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/3677/ ........ Merged
+	  revisions 417500 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, contrib/scripts/refcounter.py: refcounter.py: prevent use of
+	  excessive RAM with large refs logs When processing a 212MB refs
+	  file, refcounter.py used over 3GB of RAM. This change greatly
+	  reduces memory usage in two ways: * Saving object history in
+	  whole lines instead of separated values. * Not saving
+	  normal/skewed/leaked object lists unless they are requested.
+	  ASTERISK-23921 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/3668/ ........ Merged
+	  revisions 417480 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-26 18:25 +0000 [r417310-417419]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_http_websocket.exports.in: res_http_websocket: Export
+	  symbol for ast_websocket_set_timeout Thanks to Sean Bright for
+	  pointing out that this was missed in #asterisk-dev.
+
+	* main/udptl.c, /: udptl: Correct FEC to not consider negative
+	  sequence numbers as missing When using FEC, with span=3 and
+	  entries=4 Asterisk will attempt to repair the packet with
+	  sequence number 5, as it will see that packet -4 is missing. The
+	  result is Asterisk sending garbage packets that can kill a fax.
+	  This patch adds a check to see if the sequence number is valid
+	  before checking if the packet is missing. Review:
+	  https://reviewboard.asterisk.org/r/3657/ #ASTERISK-23908 #close
+	  Reported by: Torrey Searle patches: udptl_fec.patch uploaded by
+	  Torrey Searle (License 5334) ........ Merged revisions 417318
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* UPGRADE.txt, configs/sip.conf.sample, res/res_http_websocket.c,
+	  channels/sip/include/sip.h, channels/chan_sip.c,
+	  include/asterisk/http_websocket.h: res_http_websocket: Close
+	  websocket correctly and use careful fwrite When a client takes a
+	  long time to process information received from Asterisk, a write
+	  operation using fwrite may fail to write all information. This
+	  causes the underlying file stream to be in an unknown state, such
+	  that the socket must be disconnected. Unfortunately, there are
+	  two problems with this in Asterisk's existing websocket code: 1.
+	  Periodically, during the read loop, Asterisk must write to the
+	  connected websocket to respond to pings. As such, Asterisk
+	  maintains a reference to the session during the loop. When
+	  ast_http_websocket_write fails, it may cause the session to
+	  decrement its ref count, but this in and of itself does not break
+	  the read loop. The read loop's write, on the other hand, does not
+	  break the loop if it fails. This causes the socket to get in a
+	  'stuck' state, preventing the client from reconnecting to the
+	  server. 2. More importantly, however, is that the fwrite in
+	  ast_http_websocket_write fails with a large volume of data when
+	  the client takes awhile to process the information. When it does
+	  fail, it fails writing only a portion of the bytes. With some
+	  debugging, it was shown that this was failing in a similar
+	  fashion to ASTERISK-12767. Switching this over to
+	  ast_careful_fwrite with a long enough timeout solved the problem.
+	  ASTERISK-23917 #close Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/3624/
+
+2014-06-26 10:04 +0000 [r417249]  Corey Farrell <git at cfware.com>
+
+	* /, channels/chan_sip.c: chan_sip: Fix handling of "From" headers
+	  longer than 256 characters From headers were processed using a
+	  256 character buffer on the stack. This change replaces that with
+	  a heap allocation by ast_strdup. ASTERISK-23790 #close Reported
+	  by: uniken1 Tested by: uniken1 Review:
+	  https://reviewboard.asterisk.org/r/3669/ Patches:
+	  chan_sip-large-from-header-1.8-r3.patch uploaded by wdoekes
+	  (license 5674) ........ Merged revisions 417248 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-23 18:49 +0000 [r417141]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Return the length of
+	  data written when sending via ICE instead of 0. ASTERISK-23834
+	  #close Reported by: Richard Kenner
+
+2014-06-23 14:35 +0000 [r417077]  Rusty Newton <rnewton at digium.com>
+
+	* configs/features.conf.sample: main/features - documentation -
+	  reformat examples and options in features.conf.sample to show
+	  clearly which options apply in which section The features.conf
+	  sample can be a bit confusing about what parking options can be
+	  set only in the general context, or both in the general context
+	  (for the default parking lot) and in other parking lot contexts.
+	  A bug was filed due to confusion and a little googling will show
+	  lots of other confused users. Despite some comments on the
+	  individual options, it still reads in a confusing way. In this
+	  patch I separate out those options with some headings in to
+	  attempt a better layout. I went ahead and modified other headings
+	  in the file, or added them to facilitate better visual scanning.
+	  ASTERISK-23667 Review: https://reviewboard.asterisk.org/r/3622/
+
+2014-06-22 20:52 +0000 [r417017]  George Joseph <george.joseph at fairview5.com>
+
+	* Makefile.rules, Makefile, /: build: Turn FORTIFY_SOURCE off if
+	  DONT_OPTIMIZE is set. AST_FORTIFY_SOURCE is automatically set in
+	  ./Makefile even if DONT_OPTIMIZE is set in menuselect. This
+	  causes gcc to complain that _FORTIFY_SOURCE requires optimization
+	  and the build will fail. You can specify "make
+	  AST_FORTIFY_SOURCE=''" but I always forget. This patch moves the
+	  set of AST_FORTIFY_SOURCE to Makefile.rules and only sets it if
+	  DONT_OPTIMIZE is "no". The move is necessary because the
+	  top-level Makefile doesn't include menuselect.makeopts. This
+	  doesn't solve the entire problem however because res_config_mysql
+	  seems to force _FORTIFY_SOURCE so res_config_mysql has to be
+	  disabled for now if DONT_OPTIMIZE is set. Tested by: George
+	  Joseph Review: https://reviewboard.asterisk.org/r/3664/ ........
+	  Merged revisions 417016 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-20 23:14 +0000 [r416870-416930]  George Joseph <george.joseph at fairview5.com>
+
+	* /, configure, include/asterisk/autoconfig.h.in: build: Allow
+	  autoconf/ast_ext_tool_check to handle cross-compiling better.
+	  ast_ext_tool_check.m4 isn't handling cases where a path to a
+	  package is provided (E.G. --with-mysqlclient=/some/sysroot) and
+	  the package has a config tool (E.G. mysql_config) and the package
+	  has its own subdirectories in include or lib. For example,
+	  mysql's libraries are in ${MYSQLCLIENT_DIR}/usr/lib/mysql but
+	  ast_ext_tool_check sets MYSQLCLIENT_LIB to
+	  ${MYSQLCLIENT_DIR}/usr/lib. libxml2 has the same problem with its
+	  includes. They're in ${LIBXML2_DIR}/usr/include/libxml2 not
+	  directly in ${LIBXML2_DIR}/usr/include. Both cause configure to
+	  fail and there are others in the same boat. The problem is caused
+	  by logic in ast_ext_tool_check that overrides the result of the
+	  config tool's --cflags and --libs options if package_DIR is set.
+	  This patch prepends package_DIR (if specified) to the -L and -I
+	  results from the package's config tool instead of overriding
+	  them. A regenerated ./configure and
+	  include/asterisk/autoconfig.h.in are included but can be
+	  regenerated by running ./bootstrap.sh at any time. Tested by:
+	  George Joseph Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/3550/ ........ Merged
+	  revisions 416929 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* autoconf/ast_ext_tool_check.m4: build: Allow
+	  autoconf/ast_ext_tool_check to handle cross-compiling better.
+	  ast_ext_tool_check.m4 isn't handling cases where a path to a
+	  package is provided (E.G. --with-mysqlclient=/some/sysroot) and
+	  the package has a config tool (E.G. mysql_config) and the package
+	  has its own subdirectories in include or lib. For example,
+	  mysql's libraries are in ${MYSQLCLIENT_DIR}/usr/lib/mysql but
+	  ast_ext_tool_check sets MYSQLCLIENT_LIB to
+	  ${MYSQLCLIENT_DIR}/usr/lib. libxml2 has the same problem with its
+	  includes. They're in ${LIBXML2_DIR}/usr/include/libxml2 not
+	  directly in ${LIBXML2_DIR}/usr/include. Both cause configure to
+	  fail and there are others in the same boat. The problem is caused
+	  by logic in ast_ext_tool_check that overrides the result of the
+	  config tool's --cflags and --libs options if package_DIR is set.
+	  This patch prepends package_DIR (if specified) to the -L and -I
+	  results from the package's config tool instead of overriding
+	  them. Tested by: George Joseph Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/3550/
+
+2014-06-19 19:34 +0000 [r416733]  Kinsey Moore <kmoore at digium.com>
+
+	* main/bridging.c, /, channels/sip/reqresp_parser.c, main/logger.c,
+	  main/test.c: Fix build warnings with TEST_FRAMEWORK enabled
+	  ........ Merged revisions 416732 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-19 16:02 +0000 [r416581-416668]  George Joseph <george.joseph at fairview5.com>
+
+	* pbx/pbx_lua.c: Remove the problematic and unneeded
+	  AST_MODFLAG_GLOBAL_SYMBOLS from pbx_lua.c
+	  AST_MODFLAG_GLOBAL_SYMBOLS was causing the module to be
+	  incorrectly loaded before pbx_config. pbx_config was therefore
+	  blowing away contexts that were created by pbx_lua. With
+	  AST_MODFLAG_DEFAULT the load order is now correct and contexs are
+	  being properly merged. AST_MODFLAG_GLOBAL_SYMBOLS was not needed
+	  anyway since no other modules needed its global symbols that
+	  early. ASTERISK-23818 #close Reported by: Dennis Guse Tested by:
+	  Dennis Guse Tested by: George Joseph Review:
+	  https://reviewboard.asterisk.org/r/3629/
+
+	* configs/extensions.lua.sample: Update extensions.lua.sample with
+	  naming conflict guidance. The sample extensions.lua was causing
+	  pbx_lua to fail to load when parsing 'app.goto("default", "s",
+	  1)' because in Lua 5.2, 'goto' is now a reserved word. This patch
+	  adds guidance to extensions.lua.sample and changed
+	  'app.goto("default", "s", 1)' to 'app.['goto']("default", "s",
+	  1)'. ASTERISK-23844 #close Reported by: rnewton Tested by:
+	  gtjoseph Review: https://reviewboard.asterisk.org/r/3627/
+
+2014-06-17 18:40 +0000 [r416501]  Mark Michelson <mmichelson at digium.com>
+
+	* /, funcs/func_strings.c: Allow the PUSH and UNSHIFT functions to
+	  set inheritable channel variables. ........ Merged revisions
+	  416500 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-17 16:21 +0000 [r416440]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_musiconhold.c, /: MoH: Don't restart stream on repeated
+	  start calls Currently, music on hold will stop and then start
+	  again from the beginning if ast_moh_start() is called multiple
+	  times. This can happen if a call is put on hold repeatedly (the
+	  channel receives multiple HOLD control frames) and can be
+	  triggered from ARI by starting MoH on a channel multiple times.
+	  This is fairly jarring/annoying to users. This change prevents
+	  MoH from being restarted if the requested music class is the same
+	  as the one currently playing. This includes an extra check to
+	  prevent the errors previously experienced in the testsuite and
+	  has 100+ test runs behind it. Review:
+	  https://reviewboard.asterisk.org/r/3615/ ........ Merged
+	  revisions 416439 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-16 09:00 +0000 [r416337]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* cel/cel_sqlite3_custom.c, main/db.c, res/res_config_sqlite3.c,
+	  cdr/cdr_sqlite3_custom.c, /: We have faced situation when using
+	  CDR and CEL by sqlite3 modules. With system having high load
+	  (~100 concurrent calls created by sipp) we found many cdr and cel
+	  records missed. There is special finction in sqlite3, that make
+	  able to fix this situation - sqlite3_wait_timeout, that also can
+	  replace awful code cdr_sqlite3 ad cel_sqlite3 modules. Also this
+	  function can be used for aastdb and res_config_sqlite3 to avoid
+	  missed writes to sqlite db. #ASTERISK-23766 #close Reported by:
+	  Igor Goncharovsky Review:
+	  https://reviewboard.asterisk.org/r/3559/ ........ Merged
+	  revisions 416336 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-15 21:17 +0000 [r416252]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_musiconhold.c: MoH: Undo commit r416150 (1.8) This
+	  patch reverts r416150. When the comparison between mohclass->name
+	  and state->class->name is made, you are not guaranteed that (a)
+	  state->class is non-NULL or that state or state->class are in a
+	  safe state. Crashes caught by the bridges/transfer_capabilities
+	  test. ........ Merged revisions 416251 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-13 13:08 +0000 [r416151]  Kinsey Moore <kmoore at digium.com>
+
+	* /, res/res_musiconhold.c: MoH: Don't restart stream on repeated
+	  start calls Currently, music on hold will stop and then start
+	  again from the beginning if ast_moh_start() is called multiple
+	  times. This can happen if a call is put on hold repeatedly (the
+	  channel receives multiple HOLD control frames) and can be
+	  triggered from ARI by starting MoH on a channel multiple times.
+	  This is fairly jarring/annoying to users. This change prevents
+	  MoH from being restarted if the requested music class is the same
+	  as the one currently playing. Review:
+	  https://reviewboard.asterisk.org/r/3615/ ........ Merged
+	  revisions 416150 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-13 05:06 +0000 [r416067]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/tcptls.c, main/manager.c, /, channels/chan_sip.c,
+	  main/http.c, include/asterisk/tcptls.h: AST-2014-007: Fix of fix
+	  to allow AMI and SIP TCP to send messages. ASTERISK-23673 #close
+	  Reported by: Richard Mudgett Review:
+	  https://reviewboard.asterisk.org/r/3617/ ........ Merged
+	  revisions 416066 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-12 21:16 +0000 [r415999]  Rusty Newton <rnewton at digium.com>
+
+	* main/pbx.c, /: main/pbx - documentation - enhance 'core show
+	  hints' and 'core show hint' help text Adds descriptive help text
+	  to 'core show hints' and 'core show hint'. The text describes the
+	  various columns for the sake of clarity. ASTERISK-23764 Review:
+	  https://reviewboard.asterisk.org/r/3610/ ........ Merged
+	  revisions 415998 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-12 17:20 +0000 [r415915]  Corey Farrell <git at cfware.com>
+
+	* channels/sip/sdp_crypto.c, /: chan_sip: DEBUG messages in
+	  sdp_crypto.c display despite a DEBUG level of zero Change debug
+	  level for messages in sdp_crypto.c from zero to one. This ensures
+	  the messages are not displayed when debugging is disabled. Change
+	  does not apply to 12+ as it was already fixed in those versions.
+	  ASTERISK-23246 #close Reported by: Rusty Newton Review:
+	  https://reviewboard.asterisk.org/r/3605/ ........ Merged
+	  revisions 415908 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-12 16:22 +0000 [r415854]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_http_websocket.c, configs/http.conf.sample,
+	  include/asterisk/utils.h, main/tcptls.c, main/manager.c, /,
+	  channels/chan_sip.c, main/http.c, UPGRADE.txt, main/utils.c,
+	  include/asterisk/tcptls.h: AST-2014-007: Fix DOS by consuming the
+	  number of allowed HTTP connections. Simply establishing a TCP
+	  connection and never sending anything to the configured HTTP port
+	  in http.conf will tie up a HTTP connection. Since there is a
+	  maximum number of open HTTP sessions allowed at a time you can
+	  block legitimate connections. A similar problem exists if a HTTP
+	  request is started but never finished. * Added http.conf
+	  session_inactivity timer option to close HTTP connections that
+	  aren't doing anything. Defaults to 30000 ms. * Removed the
+	  undocumented manager.conf block-sockets option. It interferes
+	  with TCP/TLS inactivity timeouts. * AMI and SIP TLS connections
+	  now have better authentication timeout protection. Though I
+	  didn't remove the bizzare TLS timeout polling code from chan_sip.
+	  * chan_sip can now handle SSL certificate renegotiations in the
+	  middle of a session. It couldn't do that before because the
+	  socket was non-blocking and the SSL calls were not restarted as
+	  documented by the OpenSSL documentation. * Fixed an off nominal
+	  leak of the ssl struct in handle_tcptls_connection() if the FILE
+	  stream failed to open and the SSL certificate negotiations
+	  failed. The patch creates a custom FILE stream handler to give
+	  the created FILE streams inactivity timeout and timeout after a
+	  specific moment in time capability. This approach eliminates the
+	  need for code using the FILE stream to be redesigned to deal with
+	  the timeouts. This patch indirectly fixes most of ASTERISK-18345
+	  by fixing the usage of the SSL_read/SSL_write operations.
+	  ASTERISK-23673 #close Reported by: Richard Mudgett ........
+	  Merged revisions 415841 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-12 15:42 +0000 [r415837]  Jonathan Rose <jrose at digium.com>
+
+	* UPGRADE.txt: Correct UPGRADE.txt notes in r415825 The change was
+	  marked against the wrong version of Asterisk. My apologies.
+
+2014-06-12 15:40 +0000 [r415835]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, apps/app_queue.c: app_queue: delayed state can cause early
+	  leavewhenempty ringing In app_queue, device state changes arrive
+	  in event messages and update the queue member status value. That
+	  value is checked in get_member_status() to decide that the caller
+	  should leave when there are no available members. Although event
+	  messages can be delayed by other activity, there is no adverse
+	  affect by lagged status except in one specific case: there is
+	  only one available member, it was just rung, and leavewhenempty
+	  is enabled set for ringing members. This change adds a direct
+	  check of the device state only under this condition where the
+	  caller may be dropped incorrectly, resolving this issue without
+	  affecting performance of app_queue normally. AST-1248 #close
+	  Review: https://reviewboard.asterisk.org/r/3595/ Reported by:
+	  Thomas Arimont ........ Merged revisions 415833 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-12 15:22 +0000 [r415825]  Jonathan Rose <jrose at digium.com>
+
+	* UPGRADE.txt, apps/app_mixmonitor.c: MixMonitor: Add class
+	  authorization requirements to MixMonitor AMI commands MixMonitor
+	  AMI commands StartMixMonitor and StopMixMonitor lacked class
+	  authorization. StopMixMonitor now requires that the manager user
+	  either have the call or system class authorization.
+	  StartMixMonitor is a slightly larger issue since it can execute
+	  shell commands if the right arguments are passed into it, and we
+	  consider this a permission escalation. A security release will be
+	  issued for problem this shortly. ASTERISK-23609 #close Reported
+	  by: Corey Farrell
+
+2014-06-11 22:44 +0000 [r415728]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/format.c: format.c: Fix misuse of hash container function.
+	  The supplied hash function to a container must be idempotent
+	  given the object's key value to figure out which container bucket
+	  the object belongs in. Returning a random number or the current
+	  container count is not idempotent. The "computed hash" value
+	  doesn't help find the object later in those cases. * Fixed the
+	  format_list container to actually be a list since that is how the
+	  container is used. Conceptually, if more than 283 formats were
+	  added to the format_list then odd things may have happened before
+	  the fix.
+
+2014-06-10 09:13 +0000 [r415599]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: chan_ooh323: fix loading module failure if
+	  there no accessible h323_log or ooh323 config file change return
+	  1 to return AST_MODULE_LOAD_FAILURE on module load routine few
+	  cosmetic changes ASTERISK-23814 #close (closes issue
+	  ASTERISK-23814) Reported by: Igor Goncharovsky Patches:
+	  ASTERISK-23814-ast11.patch
+
+2014-06-09 11:57 +0000 [r415522]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* contrib/scripts/safe_asterisk, /: safe_asterisk: Cleanup
+	  additions to r415132. Replaced a stray echo that should've been a
+	  message call in safe_asterisk. I'm using the contents of the old
+	  message inside the if $NOTIFY so peoples log parsing scripts
+	  won't get confused by new messages. I'll clean that up in trunk.
+	  (Note that a 'make install' still won't overwrite your old
+	  safe_asterisk if it exists. See ASTERISK-21965.) ASTERISK-23492
+	  #close ........ Merged revisions 415521 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-09 03:47 +0000 [r415464]  Corey Farrell <git at cfware.com>
+
+	* main/autoservice.c, /: autoservice: stop thread on graceful
+	  shutdown This change adds thread shutdown to autoservice for
+	  graceful shutdowns only. ast_register_cleanup is backported to
+	  1.8 to allow this. The logger callid is also released on shutdown
+	  in 11+. ASTERISK-23827 #close Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/3594/ ........ Merged
+	  revisions 415463 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-06 21:27 +0000 [r415390]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/manager.h, main/config.c, main/manager.c, /,
+	  channels/chan_sip.c, include/asterisk/config.h: chan_sip: Fix
+	  order of variables specified in SIPNotify action Prior to this
+	  patch, sequential variables would be ordered in reverse from the
+	  order specified in the manager action. Review:
+	  https://reviewboard.asterisk.org/r/3588/ ........ Merged
+	  revisions 415359 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-05 17:45 +0000 [r415229]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/config.c, /: config: Fix config files not reloading when
+	  only an included file changes. The twisted logic determining if a
+	  config file should be reloaded was mostly broken and disabled.
+	  The incorrect test that ASTERISK-23383 fixed actually reenabled
+	  the broken logic. The incorrect test was causing the timestamp to
+	  always be cleared which caused config files with includes to
+	  always be reloaded. * Made wildcard includes always cause a
+	  reload. Determining if a file was deleted cannot be determined
+	  without restructuring the cache to determine if any files are
+	  missing from the last files actually loaded. Also without
+	  refactoring config_text_file_load(), the glob loop couldn't check
+	  more than one file for changes anyway. * Made remove the cache
+	  entry if the file no longer exists when trying to get its
+	  timestamp or it is no longer a regular file. This fixes the
+	  corner case where the file was loaded, then deleted, then the
+	  config reloaded, then the file restored with the same timestamp,
+	  and then the config reloaded again. * Made remove the cache entry
+	  include list when actually loading the file. This gets rid of any
+	  stale includes the file had from the last time the file was
+	  loaded. ASTERISK-23683 #close Reported by: tootai Review:
+	  https://reviewboard.asterisk.org/r/3575/ ........ Merged
+	  revisions 415225 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-05 14:32 +0000 [r415206]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_confbridge.c: app_confbridge: Allow muting of users
+	  waiting to enter a ConfBridge Prior to this patch, users waiting
+	  to enter a ConfBridge were not considered when muted via the CLI
+	  or via AMI. Instead, a confusing message would be emitted stating
+	  that the channel did not exist. This patch allows a user to be
+	  muted when waiting to enter a ConfBridge conference. This is
+	  equivalent to start when muted, only toggled via the CLI or AMI.
+	  Review: https://reviewboard.asterisk.org/r/3582 ASTERISK-23824
+	  #close patches: rb3582.patch uploaded by tm1000 (License 6524)
+
+2014-06-04 20:12 +0000 [r415171]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* contrib/scripts/safe_asterisk, /: safe_asterisk: Cleanup and
+	  debian compatibility. Cleans up the safe_asterisk script and adds
+	  the ASTSAFE_FOREGROUND option that allows the debian asterisk
+	  init script to capture the right pid. * Drop the vim #modeline
+	  which wasn't used. Use test consistently without the odd
+	  configure xno syntax. Double quote all paths. General cleanup. *
+	  Don't output message()s to the console but only to TTY if set. *
+	  Allow TTY to be "no" as well as empty (debian compatibility with
+	  debian/patches/safe_asterisk-config). * Add option to export
+	  ASTSAFE_FOREGROUND=1 from the init script that calls this to
+	  disable backgrounding. Debian uses a similar method in
+	  debian/patches/safe_asterisk-nobg). ASTERISK-23492 #close Review:
+	  https://reviewboard.asterisk.org/r/3574/ ........ Merged
+	  revisions 415132 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-04 07:20 +0000 [r415066]  Corey Farrell <git at cfware.com>
+
+	* /, apps/confbridge/include/confbridge.h, apps/app_confbridge.c:
+	  app_confbridge: Correct verification of conference name length
+	  Conference names were not checked for maximum length, allowing
+	  unexpected behaviour. This change adds checking to ensure the
+	  maximum length is not exceeded. The maximum length is also
+	  changed from 32 to AST_MAX_EXTENSION. ASTERISK-23035 #close
+	  Reported by: Iñaki Cívico Tested by: Iñaki Cívico Patches:
+	  confbridge-enforce_max-1.8.patch uploaded by coreyfarrell
+	  (license 5909) confbridge-enforce_max-11up.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 415060 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-06-03 07:32 +0000 [r414998]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, funcs/func_odbc.c: func_odbc: Fix fixed size buffers fix
+	  (r414968). The change that removed the fixed size buffers in
+	  odbc-related code -- removing arbitrary column width limits --
+	  was incomplete. This change adds: no segfault on writesql without
+	  insertsql and return value checks after strdup. While I was in
+	  the vicinity I cleaned up the linefeeds in the odbc function
+	  descriptions, moved some code for clarity, removed some blobs and
+	  noted (but didn't fix) that the 'odbc write ... exec' CLI command
+	  doesn't behave as the dialplan equivalent when insertsql= is
+	  used. #ASTERISK-23582 #close Review:
+	  https://reviewboard.asterisk.org/r/3579/ ........ Merged
+	  revisions 414997 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-30 11:59 +0000 [r414881]  Matthew Jordan <mjordan at digium.com>
+
+	* main/config.c, /: main/config.c: AMI action UpdateConfig EmptyCat
+	  clears all categories When invoking UpdateConfig AMI action with
+	  Action set to EmptyCat, Asterisk will make all categories empty
+	  in the config but the one requested with a Cat variable. This is
+	  due to a bug in ast_category_empty (main/config.c) that makes an
+	  incorrect comparison for a category name. This patch corrects the
+	  comparison such that only the requested category is cleared.
+	  Review: https://reviewboard.asterisk.org/r/3573/ ASTERISK-23803
+	  #close Reported by: zvision patches: manager.c.diff uploaded by
+	  zvision (License 5755) ........ Merged revisions 414880 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-29 18:33 +0000 [r414859]  Kinsey Moore <kmoore at digium.com>
+
+	* main/pbx.c, /: PBX: Prevent incorrect hint parsing Dynamic and
+	  pattern matching hints should not be checked for their last known
+	  state until they are instantiated by subscribers. (closes issue
+	  AFS-56) Reported by: John Hardin Patch AFS-56-pbx.diff submitted
+	  by Matt Jordan (license 6283) ........ Merged revisions 414813
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-28 11:36 +0000 [r414694]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_config_odbc.c, /, funcs/func_odbc.c: res_config_odbc: Use
+	  dynamically sized buffers to store row data so values do not get
+	  truncated. ASTERISK-23582 #close ASTERISk-23582 #comment Reported
+	  by: Walter Doekes Review:
+	  https://reviewboard.asterisk.org/r/3557/ ........ Merged
+	  revisions 414693 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-28 09:41 +0000 [r414565-414677]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* channels/chan_unistim.c: chan_unistim: Unlock mutex in rare OOM
+	  condition. ASTERISK-23792 #close Reported by: Peter Whisker
+	  Review: https://reviewboard.asterisk.org/r/3567/
+
+	* /, channels/chan_sip.c: chan_sip: Start session timer at 200, not
+	  at INVITE. Asterisk started counting the session timer at INVITE
+	  while the other end correctly started at 200. This meant that for
+	  short session-expiries (90 seconds) combined with long ringing
+	  times (e.g. 30 seconds), asterisk would wrongly assume that the
+	  timer was hit before the other end thought it was time to send a
+	  session refresh. This resulted in prematurely ended calls. This
+	  changes the session timer to start counting first at 200 like RFC
+	  says it should. (Also removed a few excess NULL checks that would
+	  never hit, because if they did, asterisk would have crashed
+	  already.) ASTERISK-22551 #close Reported by: i2045 Review:
+	  https://reviewboard.asterisk.org/r/3562/ ........ Merged
+	  revisions 414620 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_config_odbc.c, /: res_config_odbc: Fix old and new
+	  ast_string_field memory leaks. The ODBC realtime driver uses ^NN
+	  parameter encoding to cope with the special meaning of the
+	  semi-colon. A semi-colon in a field is interpreted as if the key
+	  was supplied twice, something which isn't otherwise possible with
+	  fixed database columns. E.g. allow=alaw;ulaw is parsed as
+	  allow=alaw and allow=ulaw. A literal semi-colon is rewritten to
+	  ^3B when stored in the database. The module uses a stringfield to
+	  efficiently store the encoded parameters. However, this
+	  stringfield wasn't always freed in some off-nominal cases. Commit
+	  r413241 fixed initialization so the encoding for INSERT and
+	  DELETE queries wouldn't crash. (Only SELECTs and UPDATEs worked
+	  apparently.) But that commit forgot the frees. This change cleans
+	  that up. Review: https://reviewboard.asterisk.org/r/3555/
+	  ........ Merged revisions 414564 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-29  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.10.0 Released.
+
+2014-05-22  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.10.0-rc1 Released.
+
+2014-05-22 15:50 +0000 [r414402]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_meetme.c: app_meetme: Don't interrupt MOH for
+	  waitmarked users. Occasionally, when the last marked user leaves
+	  the conference, waitmarked users don't get MOH if MOH is supposed
+	  to be played while a waitmarked user is waiting for another
+	  marked user. * Made not interrupt MOH when the user is a
+	  waitmarked user. The waitmarked user doesn't need to hear any
+	  leave announcements from the conference as the user would have
+	  already heard different leave announcements if they were enabled.
+	  Apparently DAHDI occasionally sends unending non-silent streams
+	  to these users or a normal user still in the conference has
+	  continuous high background noise. These non-silent streams cause
+	  MOH to be suspended while the never ending "announcement" is
+	  played. Issue caused by ASTERISK-13680. AST-1349 #close Reported
+	  by: Tyler Stewart Review:
+	  https://reviewboard.asterisk.org/r/3543/ ........ Merged
+	  revisions 414401 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-22 13:59 +0000 [r414346]  Matthew Jordan <mjordan at digium.com>
+
+	* UPGRADE.txt, /: UPGRADE: Add note for REF_DEBUG flag ........
+	  Merged revisions 414345 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-21 22:05 +0000 [r414270]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_local.c, /: chan_local: Only block media frames
+	  when a generator is on both ends of a local channel. The fix for
+	  ASTERISK-12292 was a bit too aggressive. You could have
+	  generators pointed at each other on local channels but need to
+	  get other kinds of frames such as DTMF or CONNECTED_LINE frames
+	  accross. ........ Merged revisions 414269 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-21 19:05 +0000 [r414215]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, funcs/func_strings.c: pbx.c: prevent potential crash from
+	  recursive replace() Recurisve usage of replace() resulted in
+	  corruption of the temporary string storage and potential crash.
+	  By changing the string to be allocated separtely per instance,
+	  this is eliminated. ASTERISK-23650 #comment Reported by: Roel van
+	  Meer ASTEIRSK-23650 #close Review:
+	  https://reviewboard.asterisk.org/r/3539/ ........ Merged
+	  revisions 414214 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-19 13:37 +0000 [r414153]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: chan_ooh323: fix h323_log full path name
+	  * fix to use astlogdir option for h323_log file instead of
+	  hardcoded ASTERISK-23754 #close Reported by: Igor Goncharovsky
+	  Patches: ooh323_logger_patch.diff ........ Merged revisions
+	  414152 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-16 20:03 +0000 [r413992-414068]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Fix analog dialtone
+	  detection. * Check if waitingfordt (waitfordialtone) is enabled
+	  in dahdi_read() to allow the DSP to operate early enough to
+	  detect dialtone. * Made use the correct variable in
+	  my_check_waitingfordt(). ASTERISK-23709 #close Reported by: Steve
+	  Davies Patches: dialtone_detect_fix (license #5012) patch
+	  uploaded by Steve Davies Review:
+	  https://reviewboard.asterisk.org/r/3534/ ........ Merged
+	  revisions 414067 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/sig_pri.c: sig_pri.c: Pull the pri_dchannel()
+	  PRI_EVENT_RING case into its own function. * Populate the
+	  CALLERID(ani2) value (and the special CALLINGANI2 channel
+	  variable) with the ANI2 value in addition to the PRI specific
+	  ANI2 channel variable.
+
+	* /, apps/app_meetme.c: app_meetme: Fix overwrite of DAHDI
+	  conference data structure. Starting a conference recording using
+	  the admin menu overwrites the DAHDI conference data structure
+	  used to modify the admin user's conference mute mode. * Made no
+	  longer pass the user's DAHDI conference data structure into the
+	  menu functions. The menu now uses its own DAHDI conference data
+	  structure to start the recording channel. * Moved the unlock
+	  conf->playlock to before playing the conf-full message. No sense
+	  keeping the lock while that prompt is playing. The user is never
+	  going to get into the conference at that point. ........ Merged
+	  revisions 413991 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-14 15:31 +0000 [r413895]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, res/res_musiconhold.c: res_musiconhold: Minor cleanup. Fix a
+	  few free()'s that should be ast_free()'s. Reverted an old
+	  workaround that isn't necessary. Reorder a tiny bit of code.
+	  Remove a bit of commented-out code. Review:
+	  https://reviewboard.asterisk.org/r/3536/ ........ Merged
+	  revisions 413894 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-13 17:40 +0000 [r413876]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Add TLS and SRTP status to CLI
+	  command 'sip show channel' ASTERISK-23564 #close Reported by:
+	  Patrick Laimbock Review: https://reviewboard.asterisk.org/r/3474/
+
+2014-05-13 14:34 +0000 [r413788-413838]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip+CEL: Add missing ANSWER and
+	  PICKUP events to INVITE/w/replaces pickup. When doing a
+	  "BLF-style call pickup" -- an INVITE with Replaces: header -- the
+	  CEL log would lack the ANSWER and PICKUP events. This patch adds
+	  the two missing events to the handle_invite_replaces() function.
+	  ASTERISK-22977 #close Review:
+	  https://reviewboard.asterisk.org/r/3073/ ........ Merged
+	  revisions 413832 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_format_attr_h264.c: h264: Fix H264 SDP payload format.
+	  https://tools.ietf.org/html/rfc3984#section-8.1 says
+	  profile-level-id takes 3 bytes in base16 (6 hex digits). This
+	  fixes video setup in certain cases. ASTERISK-23664 #close
+	  ASTERISK-23664 #comment Patch r3530.patch uploaded by Guillaume
+	  Maudoux. Review: https://reviewboard.asterisk.org/r/3530/
+
+	* main/rtp_engine.c, /: rtp: Fix case typo in H263+ mime.
+	  http://tools.ietf.org/html/rfc3555#section-4.2.6 says the
+	  canonical mime subtype is "H263-1998", not "h263-1998". Original
+	  code was added in r183101 on 2009-03-19 02:26:50 +0100. This
+	  fixes issues with Polycom phones. ASTERISK-23665 #close
+	  ASTERISK-23665 #comment Patch r3529.patch uploaded by Guillaume
+	  Maudoux, backported by me. Review:
+	  https://reviewboard.asterisk.org/r/3529/ ........ Merged
+	  revisions 413787 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-12 23:48 +0000 [r413765]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_pri.c, /, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac:
+	  chan_dahdi/sig_pri: Prevent unnecessary PROGRESS events when
+	  overlap dialing is enabled. When overlap dialing is enabled, the
+	  lack of inband audio available information in the
+	  SETUP_ACKNOWLEDGE events causes an interoperability problem with
+	  SIP. sig_pri doesn't know if there is dialtone present when a
+	  SETUP_ACKNOWLEDGE is received so it assumes it is there and posts
+	  an AST_CONTROL_PROGRESS frame. The SIP channel driver then sends
+	  out a 183 Session Progress and blocks the desired 180 Ringing
+	  message when the ALERTING message comes in. * Made the configure
+	  script detect if the installed version of libpri supports the
+	  SETUP_ACKNOWLEDGE enhancements. * Using the new API, made
+	  generate an AST_CONTROL_PROGRESS frame on an incoming
+	  SETUP_ACKNOWLEDGE message when the message indicates inband audio
+	  is present instead of assuming that dialtone is present. * Using
+	  the new API, made SETUP_ACKNOWLEDGE send out an inband audio
+	  available indication only if dialtone is expected. The change
+	  also makes the fallback behaviour of sending the PROGRESS message
+	  better by sending it only if dialtone is expected. * Changed
+	  receiving a PROCEEDING message to not generate an
+	  AST_CONTROL_PROGRESS frame if the progress indication ie
+	  indicates non-end-to-end-ISDN. This helps interoperability with
+	  SIP. * Changed sending a PROCEEDING message in response to an
+	  AST_CONTROL_PROCEEDING frame to not indicate inband audio
+	  available. It was silly to do so anyway because the channel
+	  driver doesn't know if inband audio is even available. This helps
+	  interoperability with SIP. This patch and a corresponding change
+	  in libpri work together to allow Asterisk to control the inband
+	  audio available progress indication ie on the SETUP_ACKNOWLEDGE
+	  message when dialtone is present. AST-1338 #close Reported by:
+	  Tyler Stewart Review: https://reviewboard.asterisk.org/r/3521/
+	  ........ Merged revisions 413714 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-12 22:02 +0000 [r413710]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_chanspy.c: app_chanspy: Fix a test that was failing on
+	  account of r413551 ASTERISK-23381 #close ASTERISK-23381 #comment
+	  Reported by: Robert Moss Review:
+	  https://reviewboard.asterisk.org/r/3505/
+
+2014-05-09 23:08 +0000 [r413587-413595]  Kinsey Moore <kmoore at digium.com>
+
+	* /, funcs/func_env.c: Fix 32bit build for func_env ........ Merged
+	  revisions 413592 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_fax_spandsp.c, res/res_odbc.c, main/asterisk.c,
+	  res/res_calendar.c, apps/app_voicemail.c,
+	  channels/chan_unistim.c, main/ccss.c, funcs/func_sysinfo.c,
+	  main/utils.c, res/res_musiconhold.c, channels/chan_gtalk.c,
+	  res/res_jabber.c, res/res_http_websocket.c,
+	  res/res_format_attr_h264.c, main/enum.c, main/io.c,
+	  main/channel.c, res/ael/pval.c, channels/chan_phone.c,
+	  main/manager.c, res/res_config_odbc.c, apps/app_minivm.c,
+	  channels/chan_motif.c, res/res_agi.c, main/logger.c, main/app.c,
+	  apps/app_confbridge.c, res/res_format_attr_silk.c,
+	  channels/chan_mgcp.c, apps/app_adsiprog.c,
+	  res/res_rtp_asterisk.c, main/stun.c,
+	  res/res_calendar_icalendar.c, channels/chan_sip.c,
+	  apps/app_festival.c, res/res_fax.c, main/translate.c,
+	  main/slinfactory.c, res/res_crypto.c, main/acl.c,
+	  apps/app_queue.c, apps/app_getcpeid.c, channels/sig_pri.c,
+	  res/res_srtp.c, channels/chan_jingle.c, res/res_corosync.c,
+	  res/res_stun_monitor.c, main/abstract_jb.c, main/callerid.c,
+	  main/file.c, main/config_options.c, main/adsi.c, main/event.c,
+	  pbx/pbx_dundi.c, apps/app_sms.c, channels/sip/config_parser.c,
+	  apps/app_stack.c, apps/app_verbose.c, main/dsp.c, main/xmldoc.c,
+	  main/udptl.c, main/format.c, cel/cel_pgsql.c, main/frame.c,
+	  channels/chan_local.c, main/rtp_engine.c, main/security_events.c,
+	  /, funcs/func_env.c, res/res_timing_dahdi.c,
+	  bridges/bridge_softmix.c, main/devicestate.c,
+	  cdr/cdr_adaptive_odbc.c, res/res_calendar_caldav.c,
+	  main/taskprocessor.c, res/res_xmpp.c, res/res_format_attr_h263.c,
+	  channels/chan_iax2.c, res/res_pktccops.c, main/config.c,
+	  main/loader.c, main/cli.c, res/res_format_attr_celt.c,
+	  apps/confbridge/conf_config_parser.c, funcs/func_hangupcause.c,
+	  channels/chan_dahdi.c, cel/cel_odbc.c, channels/sig_analog.c,
+	  include/asterisk/astobj.h, channels/chan_skinny.c,
+	  formats/format_pcm.c, main/features.c, apps/app_dumpchan.c,
+	  funcs/func_srv.c, channels/chan_alsa.c, main/stdtime/localtime.c,
+	  main/bridging.c, channels/sip/include/sip.h, main/sched.c,
+	  apps/app_dial.c, res/res_calendar_exchange.c, main/pbx.c,
+	  pbx/dundi-parser.c, main/aoc.c, main/cel.c,
+	  channels/iax2-parser.c, res/res_calendar_ews.c,
+	  res/res_monitor.c, main/netsock.c, main/data.c, main/audiohook.c,
+	  funcs/func_iconv.c, pbx/pbx_config.c: Allow Asterisk to compile
+	  under GCC 4.10 This resolves a large number of compiler warnings
+	  from GCC 4.10 which cause the build to fail under dev mode. The
+	  vast majority are signed/unsigned mismatches in printf-style
+	  format strings. ........ Merged revisions 413586 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-09 16:10 +0000 [r413551]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_chanspy.c: app_chanspy: Fix a bug where Barge mode could
+	  fail If the barge audiohook was attached prior to the spyee and
+	  its peer actually being bridged, the audiohook would not be
+	  applied and the connected peer would not be able to hear audio
+	  from the spy when the spy is in barge mode. (closes issue
+	  ASTERISK-23381) Reported by: Robert Moss Review:
+	  https://reviewboard.asterisk.org/r/3505/
+
+2014-05-08 00:34 +0000 [r413486]  Joshua Colp <jcolp at digium.com>
+
+	* main/manager.c, /, apps/app_queue.c: app_queue: Extend
+	  documentation for various Manager actions and events. ........
+	  Merged revisions 413485 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-07 20:29 +0000 [r413451]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_confbridge.c: app_confbridge: Fix ref leak in CLI
+	  "confbridge kick" command. Fixed ref leak in the CLI "confbridge
+	  kick" command when the channel to be kicked was not in the
+	  conference.
+
+2014-05-07 17:48 +0000 [r413397]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_config_odbc.c, /: Fix encoding of custom prepare extra
+	  data. Patches: res_config_odbc-take2.patch by John Hardin
+	  (License #6512) ........ Merged revisions 413396 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-06 17:01 +0000 [r413305]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_config_odbc.c, /: Ensure that all parts of SQL UPDATEs
+	  and DELETEs are encoded. Patches: res_config_odbc.patch by John
+	  Hardin (License #6512) ........ Merged revisions 413304 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-05-02 20:25 +0000 [r413225-413251]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_config_odbc.c, /: Prevent crashes in res_config_odbc due
+	  to uninitialized string fields. Patches: odbc-crash.patch by John
+	  Hardin (License #6512) ........ Merged revisions 413241 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_config_pgsql.c, /: Return the number of rows affected by
+	  a SQL insert, rather than an object ID. The realtime API
+	  specifies that the store callback is supposed to return the
+	  number of rows affected. res_config_pgsql was instead returning
+	  an Oid cast as an int, which during any nominal execution would
+	  be cast to 0. Returning 0 when more than 0 rows were inserted
+	  causes problems to the function's callers. To give an idea of how
+	  strange code can be, this is the necessary code change to fix a
+	  device state issue reported against chan_pjsip in Asterisk 12+.
+	  The issue was that the registrar would attempt to insert contacts
+	  into the database. Because of the 0 return from res_config_pgsql,
+	  the registrar would think that the contact was not successfully
+	  inserted, even though it actually was. As such, even though the
+	  contact was query-able and it was possible to call the endpoint,
+	  Asterisk would "think" the endpoint was unregistered, meaning it
+	  would report the device state as UNAVAILABLE instead of
+	  NOT_INUSE. The necessary fix applies to all versions of Asterisk,
+	  so even though the bug reported only applies to Asterisk 12+, the
+	  code correction is being inserted into 1.8+. Closes issue
+	  ASTERISK-23707 Reported by Mark Michelson ........ Merged
+	  revisions 413224 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-30 20:26 +0000 [r413139]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/message.c, channels/chan_sip.c, include/asterisk/message.h:
+	  chan_sip.c: Fixed off-nominal message iterator ref count and
+	  alloc fail issues. * Fixed early exit in sip_msg_send() not
+	  destroying the message iterator. * Made
+	  ast_msg_var_iterator_next() and ast_msg_var_iterator_destroy()
+	  tolerant of a NULL iter parameter in case
+	  ast_msg_var_iterator_init() fails. * Made
+	  ast_msg_var_iterator_destroy() clean up any current message data
+	  ref. * Made struct ast_msg_var_iterator,
+	  ast_msg_var_iterator_init(), ast_msg_var_iterator_next(),
+	  ast_msg_var_unref_current(), and ast_msg_var_iterator_destroy()
+	  use iter instead of i.
+
+2014-04-30 13:04 +0000 [r413123]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_http_websocket.c: Websocket: Add session locking and
+	  delay close This resolves a race condition where data could be
+	  written to a NULL FILE pointer causing a crash as a websocket
+	  connection was in the process of shutting down by adding locking
+	  to websocket session writes and by deferring session teardown
+	  until session destruction. (closes issue ASTERISK-23605) Review:
+	  https://reviewboard.asterisk.org/r/3481/ Reported by: Matt Jordan
+
+2014-04-25 17:47 +0000 [r413008]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Add support for DTLS
+	  handshake retransmissions On congested networks, it is possible
+	  for the DTLS handshake messages to get lost. This patch adds a
+	  timer to res_rtp_asterisk that will periodically check to see if
+	  the handshake has succeeded. If not, it will retransmit the DTLS
+	  handshake. Review: https://reviewboard.asterisk.org/r/3337
+	  ASTERISK-23649 #close Reported by: Nitesh Bansal patches:
+	  dtls_retransmission.patch uploaded by Nitesh Bansal (License
+	  6418)
+
+2014-04-23 17:51 +0000 [r412923]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/http.c: http: Fix spurious ERROR message in responses
+	  with no content. Backport -r411687 and fix the fix because
+	  content_length is the length of out plus the length of the file
+	  controlled by fd. When a response has an out content length of 0,
+	  fwrite would be called to write a buffer with no data in it. This
+	  resulted in the following classic error message: [Apr 3 11:49:17]
+	  ERROR[26421] http.c: fwrite() failed: Success This patch makes it
+	  so that we only attempt to write the content of out if the out
+	  string is non-zero. ........ Merged revisions 412922 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-21 17:53 +0000 [r412767-412822]  Jonathan Rose <jrose at digium.com>
+
+	* /, CHANGES: chan_sip: trust_id_outbound CHANGES message
+	  improvement (closes issue AST-1301) (closes issue ASTERISK-19465)
+	  Reported by: Krzysztof Chmielewski ........ Merged revisions
+	  412821 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, CHANGES: Typo in CHANGES ........ Merged revisions 412764 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-21 16:13 +0000 [r412748]  Kinsey Moore <kmoore at digium.com>
+
+	* main/manager.c, /, main/http.c: HTTP: Add TCP_NODELAY to accepted
+	  connections This adds the TCP_NODELAY option to accepted
+	  connections on the HTTP server built into Asterisk. This option
+	  disables the Nagle algorithm which controls queueing of outbound
+	  data and in some cases can cause delays on receipt of response by
+	  the client due to how the Nagle algorithm interacts with TCP
+	  delayed ACK. This option is already set on all non-HTTP AMI
+	  connections and this change would cover standard HTTP requests,
+	  manager HTTP connections, and ARI HTTP requests and websockets in
+	  Asterisk 12+ along with any future use of the HTTP server.
+	  Review: https://reviewboard.asterisk.org/r/3466/ ........ Merged
+	  revisions 412745 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-21 15:51 +0000 [r412746]  Jonathan Rose <jrose at digium.com>
+
+	* configs/sip.conf.sample, CHANGES, channels/sip/include/sip.h, /,
+	  channels/chan_sip.c: chan_sip: Add sendrpid trust options In
+	  r411189, some behavior was changed which made sendrpid behavior
+	  act in a more trusting manner by sending full user data for peers
+	  set with private caller presence in P-Asserted-Identity headers.
+	  Since this changed long time expected behaviors, we decided to
+	  pull that patch when that was pointed out by the community.
+	  Instead, this patch provides a trust_id_outbound setting which
+	  will expose the data per RFC-3325 if set to 'yes' and simply not
+	  send the PAI/RPID headers at all if set to 'no'. By default
+	  trust_id_outbound will be set to 'legacy' which will preserve the
+	  behavior prior to these patches. Extra special thanks to Walter
+	  Doekes for providing advice and feedback. (closes issue AST-1301)
+	  (closes issue ASTERISK-19465) Reported by: Krzysztof Chmielewski
+	  Review: https://reviewboard.asterisk.org/r/3447/ ........ Merged
+	  revisions 412744 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-21 08:29 +0000 [r412712]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix wrong dialtone. The "modulation"
+	  should not be referenced for tone+tone as it refers to the on-off
+	  characteristic - this often resulted in a single tone rather than
+	  the multitone as in the UK.
+
+2014-04-19 01:02 +0000 [r412656]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_sms.c: app_sms: Fix uninitialized values; hangup
+	  channel when REL is sent successfully This patch fixes two issues
+	  in app_sms: (1) Firstly, the 'flags' field on the stack in
+	  sms_exec() is uninitialised, causing it to use the wrong protocol
+	  in some cases. This patch correctly initializes the flags fields.
+	  (2) Secondly, when disconnect supervision is not working or
+	  inbanddisconnect=yes is set in chan_dahdi.conf, app_sms was
+	  failing to terminate the call after it sent the REL(ease) message
+	  and the peer stopped talking to it. This patch fixes the code to
+	  handle the 'bad stop bit' message more gracefully in that case,
+	  and hang up the call. Review:
+	  https://reviewboard.asterisk.org/r/1392/ ASTERISK-18331 #close
+	  Reported by: David Woodhouse patches: asterisk-fix-sms.patch
+	  uploaded by David Woodhouse (License 5754) ........ Merged
+	  revisions 412655 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-18 17:15 +0000 [r412586]  Rusty Newton <rnewton at digium.com>
+
+	* sounds/sounds.xml, sounds/Makefile: sounds: Fix Sounds Makefile
+	  and XML that didn't support new sound prompt sets In
+	  sounds/Makefile 1 Adds and moves some lines necessary for the
+	  en_GB core set. I'm just following how the other sets are defined
+	  here. 2 removes the ES extra sounds related lines as we don't
+	  have ES extra sound sets. In sounds/sounds.xml 3 Adds member
+	  definitons for EN_AU, EN_GB, IT for core sound sets, and EN_GB in
+	  extra sound sets ASTERISK-23550 #close Review:
+	  https://reviewboard.asterisk.org/r/3464/
+
+2014-04-17 20:06 +0000 [r412468]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_oss.c, main/Makefile: main/Makefile: Fix build
+	  failure on SmartOS/Illumos/SunOS This patch fixes two issues when
+	  building on SmartOS: - channels/chan_oss.c: it makes sure
+	  soundcard.h is found - main/Makefile: only use
+	  "-Wl,--version-script" when GNU LD is used as the Sun Linker
+	  doesn't support that. Similar checks are already used elswhere in
+	  the Makefile Review: https://reviewboard.asterisk.org/r/3426
+	  ASTERISK-23576 #close Reported by: Sebastian Wiedenroth patches:
+	  fix-sunos.diff uploaded by Sebastian Wiedenroth (License 6597)
+
+2014-04-15 16:23 +0000 [r412348]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_sip.c: chan_sip.c: Moved some sip_pvt unrefs after
+	  their last use. * Moved sip_pvt unref in ast_hangup() and
+	  handle_request_do() to the end of the function. The unref needs
+	  to happen after the last use of the pointer.
+
+2014-04-15 15:40 +0000 [r412329]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c, configs/sip.conf.sample: Reverting
+	  r411189 so that it can be put up for public review --- r411189 |
+	  jrose | 2014-03-26 10:50:48 -0500 (Wed, 26 Mar 2014) | 12 lines
+	  chan_sip: Send real CallerID information with
+	  P-Assserted-Identity (RFC-3325) Prior to this patch, the
+	  P-Asserted-Identity header would include anonymous caller id
+	  information which seems to go against the point of the
+	  P-Asserted-Identity header. Now the real caller ID information
+	  will be included in this header. Also, no privacy header would be
+	  included. This patch adds 'Privacy: id' to outgoing SIP messages
+	  that include the P-Asserted-Identity header. (closes issue
+	  AST-1301) --- ........ Merged revisions 412328 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-14 15:50 +0000 [r412305]  Corey Farrell <git at cfware.com>
+
+	* main/autoservice.c: autoservice: fix reference leak of logger
+	  callid. autoservice acquires a local reference to the logger
+	  callid of each channel in a loop. This local reference was not
+	  released, causing the callid of every channel in autoservice to
+	  leak. This change moves the callid unref inside the loop.
+	  ASTERISK-23616 #close Reported by: ibercom
+
+2014-04-11 21:38 +0000 [r412226]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_stack.c, /: app_stack: Add missing unlock in off-nominal
+	  path of STACK_PEEK function. ASTERISK-23620 #close Reported by:
+	  Bradley Watkins Patches: ASTERISK-23620_unlock_oldlist.patch
+	  (license #5021) patch uploaded by Bradley Watkins ........ Merged
+	  revisions 412225 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-11 02:10 +0000 [r412115]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/security_events.c,
+	  include/asterisk/astobj2.h, main/utils.c, main/astobj2.c,
+	  contrib/scripts/refcounter.py (added), main/asterisk.c,
+	  build_tools/cflags.xml: main/astobj2: Make REF_DEBUG a menuselect
+	  item; improve REF_DEBUG output This patch does the following: (1)
+	  It makes REF_DEBUG a meneselect item. Enabling REF_DEBUG now
+	  enables REF_DEBUG globally throughout Asterisk. (2) The ref debug
+	  log file is now created in the AST_LOG_DIR directory. Every run
+	  will now blow away the previous run (as large ref files sometimes
+	  caused issues). We now also no longer open/close the file on each
+	  write, instead relying on fflush to make sure data gets written
+	  to the file (in case the ao2 call being performed is about to
+	  cause a crash) (3) It goes with a comma delineated format for the
+	  ref debug file. This makes parsing much easier. This also now
+	  includes the thread ID of the thread that caused ref change. (4)
+	  A new python script instead for refcounting has been added in the
+	  contrib/scripts folder. Review:
+	  https://reviewboard.asterisk.org/r/3377/ ........ Merged
+	  revisions 412114 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-08 21:20 +0000 [r411944-411974]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/asterisk.c, /: Internal timing: Add notice that the -I and
+	  internal_timing option are no longer needed. Add notice messages
+	  during execution that the -I command line option and the
+	  astersik.conf internal_timing option are no longer needed. The
+	  internal timing functionality is now always enabled if there is a
+	  timing module loaded. NOTE: Since the command line options and
+	  the asterisk.conf config file are processed before the logging
+	  system is initialized, the messages are output to stderr. Change
+	  requested as a result of asterisk-dev list comments about the
+	  commit for ASTERISK-22846 that removed the -I and internal_timing
+	  options. Review: https://reviewboard.asterisk.org/r/3423/
+	  ........ Merged revisions 411964 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/config.c: config: Fix CB_ADD_LEN() to work as originally
+	  intended. Fix a long standing bug in CB_ADD_LEN() behaving like
+	  CB_ADD(). ASTERISK-23546 #close Reported by: Walter Doekes
+	  ........ Merged revisions 411960 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/confbridge/conf_config_parser.c: app_confbridge: Fix
+	  confbridge.conf dsp_talking_threshold option setting wrong
+	  parameter. Fixed copy pasta error. ASTERISK-23545 #close Reported
+	  by: John Knott
+
+2014-04-07 14:48 +0000 [r411808]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* configs/res_odbc.conf.sample, /, UPGRADE.txt: configs: Clean up
+	  long line and typo in res_odbc.conf.sample. ........ Merged
+	  revisions 411807 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-04 18:46 +0000 [r411716]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/options.h, main/asterisk.c, main/channel.c, /,
+	  channels/chan_sip.c, configs/asterisk.conf.sample, UPGRADE.txt:
+	  internal_timing: Remove the option and always make it enabled if
+	  a timing module is loaded. The masquerade supertest frequently
+	  fails because either the local channel chain doesn't completely
+	  optimize out or the DTMF handshake doesn't completely get
+	  accross. Local channel optimization requires frames flowing to
+	  trigger when optimization can happen. When optimization happens
+	  the media frame that triggered the optimization is dropped.
+	  Sending DTMF requires frames to flow in the other direction for
+	  timing purposes while sending nothing. If internal timing is not
+	  enabled when MOH is playing, Asterisk switches to received timing
+	  when an audio frame is received. With optimization dropping media
+	  frames and MOH not sending frames unless it receives frames,
+	  occasionaly there are no more frames being passed and the test
+	  fails. * The asterisk command line -I option and the
+	  asterisk.conf internal_timing option are removed. Asterisk now
+	  always uses internal timing when needed if any timing module is
+	  loaded. The issue ASTERISK-14861 did this quite awhile ago in
+	  v1.4 but effectively is broken if other internal timing modules
+	  besides DAHDI are used. The ast_read_generator_actions() now only
+	  does received timing if it has no choice for frame generators
+	  like MOH, silence, and playback streaming. * Cleaned up some code
+	  dealing with frame generators in ast_deactivate_generator(),
+	  generator_write_format_change(), ast_activate_generator(), and
+	  ast_channel_stop_silence_generator(). ASTERISK-22846 #close
+	  Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/3414/ ........ Merged
+	  revisions 411715 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-01 20:43 +0000 [r411633]  Corey Farrell <git at cfware.com>
+
+	* utils/extconf.c, include/asterisk/options.h, main/asterisk.c,
+	  apps/app_voicemail.c, main/channel.c: app_voicemail: fix missing
+	  symbol ASTERISK-23391 caused a regression where the symbol
+	  'defaultlanguage' was used by app_voicemail but not exported by
+	  main/asterisk. This change renames the variable to
+	  ast_defaultlanguage. The variable was already renamed in Asterisk
+	  12+. (closes issue ASTERISK-23559) Reported by: Corey Farrell
+	  Review: https://reviewboard.asterisk.org/r/3408/
+
+2014-04-01 16:49 +0000 [r411585]  Joshua Colp <jcolp at digium.com>
+
+	* apps/app_queue.c, /: app_queue: Fix a bug where realtime members
+	  would be deleted during reload causing waiting callers to get
+	  ejected. This patch causes realtime queue members to remain in
+	  queues during the reload process. Previously these members would
+	  be removed causing any waiting callers to be ejected from the
+	  queue with a reason of "EXITEMPTY". ASTERISK-23547 #close
+	  ASTERISK-23547 #comment Patch
+	  app_queue_fix_realtime_reload_1.8_trunk.patch submitted by Italo
+	  Rossi (license 6409) Review:
+	  https://reviewboard.asterisk.org/r/3404/ ........ Merged
+	  revisions 411584 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-04-23  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.9.0 Released.
+
+2014-04-21  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.9.0-rc3 Released.
+
+	* chan_sip: Add sendrpid trust options
+
+	  In r411189, some behavior was changed which made sendrpid behavior
+	  act in a more trusting manner by sending full user data for peers
+	  set with private caller presence in P-Asserted-Identity headers.
+	  Since this changed long time expected behaviors, we decided to pull
+	  that patch when that was pointed out by the community. Instead, this
+	  patch provides a trust_id_outbound setting which will expose the data
+	  per RFC-3325 if set to 'yes' and simply not send the PAI/RPID headers
+	  at all if set to 'no'. By default trust_id_outbound will be set to
+	  'legacy' which will preserve the behavior prior to these patches.
+	  Extra special thanks to Walter Doekes for providing advice and
+	  feedback.
+
+2014-04-14  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.9.0-rc2 Released.
+
+	* autoservice: fix reference leak of logger callid.
+
+	  autoservice acquires a local reference to the logger callid of each
+	  channel in a loop.  This local reference was not released, causing
+	  the callid of every channel in autoservice to leak. This change moves
+	  the callid unref inside the loop.
+
+	  ASTERISK-23616 #close
+	  Reported by: ibercom
+
+	* app_voicemail: fix missing symbol
+
+	  ASTERISK-23391 caused a regression where the symbol 'defaultlanguage'
+	  was used by app_voicemail but not exported by main/asterisk. This
+	  change renames the variable to ast_defaultlanguage. The variable was
+	  already renamed in Asterisk 12+.
+
+	  (closes issue ASTERISK-23559)
+	  Reported by: Corey Farrell
+
+2014-03-28  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.9.0-rc1 Released.
+
+2014-03-28 17:44 +0000 [r411531]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/oochannels.c,
+	  addons/ooh323c/src/ooCmdChannel.c, addons/ooh323c/src/ooq931.c,
+	  addons/ooh323c/src/ooh323.c, addons/ooh323c/src/ooGkClient.c,
+	  addons/chan_ooh323.c: process stack command even if gatekeeper
+	  client isn't register don't destroy gatekeeper client if it is
+	  not started don't destroy gatekeeper client in some sort of
+	  gatekeeper errors signal rtp create condition when call cleared
+	  before rtp structure created (closes issue ASTERISK-23460)
+	  Reported by: Dmitry Melekhov Patches: ASTERISK-23460-2.patch
+	  Tested by: Dmitry Melekhov
+
+2014-03-28 16:16 +0000 [r411463]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/manager.c, /, main/http.c, main/tcptls.c: http: response
+	  body often missing after specific request This patch works around
+	  a problem with the HTTP body being dropped from the response to a
+	  specific client and under specific circumstances: a) Client
+	  request comes from node.js user agent "Shred" via use of
+	  swagger-client library. b) Asterisk and Client are *not* on the
+	  same host or TCP/IP stack In testing this problem, it has been
+	  determined that the write of the HTTP body is lost, even if the
+	  data is written using low level write function. The only solution
+	  found is to instruct the TCP stack with the shutdown function to
+	  flush the last write and finish the transmission. See review for
+	  more details. ASTERISK-23548 #close (closes issue ASTERISK-23548)
+	  Reported by: Sam Galarneau Review:
+	  https://reviewboard.asterisk.org/r/3402/ ........ Merged
+	  revisions 411462 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-28 15:43 +0000 [r411373-411458]  Matthew Jordan <mjordan at digium.com>
+
+	* /, UPGRADE.txt: UPGRADE: Note IAX2 compatibility issue between
+	  1.4 and 1.8+ systems. ........ Merged revisions 411457 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* configs/res_odbc.conf.sample, include/asterisk/res_odbc.h,
+	  res/res_config_odbc.c, /, res/res_odbc.exports.in, UPGRADE.txt,
+	  res/res_odbc.c: res_config_odbc/res_odbc: Fix handling of
+	  non-text columns updates with empty values. This patch fixes
+	  setting nullable integer columns to NULL instead of an empty
+	  string, which fails for PostgreSQL, for example. The current code
+	  is supposed to do so, but the check is broken. The patch also
+	  allows the first column in the list to be a nullable integer.
+	  This patch also adds a compatibility setting in res_odbc.conf,
+	  allow_empty_string_in_nontext. It is enabled by default. It
+	  should be disabled for database backends (such as PostgreSQL)
+	  that require NULL instead of an empty string for Integer columns.
+	  Review: https://reviewboard.asterisk.org/r/3375 (issue
+	  ASTERISK-23459) Reported by: zvision patches:
+	  res_config_odbc.diff uploaded by zvision (License 5755) ........
+	  Merged revisions 411399 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/sip/include/sip.h, /: chan_sip: Add MESSAGE request to
+	  allowed methods The allowed methods advertised by chan_sip did
+	  not previously note the MESSAGE request. Even in Asterisk 1.8, we
+	  do accept in-dialog MESSAGE requests; we should advertise that we
+	  support MESSAGE requests. ASTERISK-23504 #close ASTERISK-23504
+	  #comment Reported by: Martin Kontsek ASTERISK-23504 #comment
+	  Patch sip.h_patch.diff uploaded by Martin Kontsek (license 6587)
+	  Review: https://reviewboard.asterisk.org/r/3396/ ........ Merged
+	  revisions 411372 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-27 19:13 +0000 [r411310-411314]  Corey Farrell <git at cfware.com>
+
+	* funcs/func_strings.c, funcs/func_math.c,
+	  funcs/func_jitterbuffer.c, res/res_xmpp.c, channels/chan_iax2.c,
+	  res/res_jabber.c, res/res_mutestream.c, funcs/func_global.c,
+	  apps/app_speech_utils.c, apps/confbridge/conf_config_parser.c,
+	  funcs/func_pitchshift.c, funcs/func_callcompletion.c,
+	  funcs/func_groupcount.c, funcs/func_volume.c, funcs/func_odbc.c,
+	  funcs/func_blacklist.c, funcs/func_channel.c,
+	  funcs/func_frame_trace.c, main/features.c, funcs/func_callerid.c,
+	  apps/app_stack.c, main/message.c, res/res_calendar.c,
+	  apps/app_jack.c, apps/app_voicemail.c, funcs/func_speex.c,
+	  funcs/func_dialplan.c, channels/chan_sip.c, /: Fix dialplan
+	  function NULL channel safety issues (closes issue ASTERISK-23391)
+	  Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/3386/ ........ Merged
+	  revisions 411313 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/format.c, include/asterisk.h, main/asterisk.c: main/formats:
+	  Fix crash in ast_format_cmp during non-clean shutdown. * Backport
+	  ast_register_cleanup from Asterisk 12. * Use ast_register_cleanup
+	  for format_attr_shutdown. ast_register_cleanup was originally
+	  commited in r390122 by dlee. (closes issue ASTERISK-23103)
+	  Reported by: JoshE
+
+2014-03-26 22:44 +0000 [r411244]  Joshua Colp <jcolp at digium.com>
+
+	* /, main/say.c: say: Fix a bug where SayNumber in Polish tries to
+	  play incorrect sound. This change fixes a bug where calling
+	  SayNumber with a number divisible by 100 using the Polish
+	  language would cause the code to attempt to play a sound file
+	  with an empty name. (closes issue ASTERISK-23509) Reported by:
+	  zvision Review: https://reviewboard.asterisk.org/r/3378/ ........
+	  Merged revisions 411243 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-26 15:57 +0000 [r411190]  Jonathan Rose <jrose at digium.com>
+
+	* configs/sip.conf.sample, /, channels/chan_sip.c: chan_sip: Send
+	  real CallerID information with P-Assserted-Identity (RFC-3325)
+	  Prior too this patch, the P-Asserted-Identity header would
+	  include anonymous caller id information which seems to go against
+	  the point of the P-Asserted-Identity header. Now the real caller
+	  ID information will be included in this header. Also, no privacy
+	  header would be included. This patch adds 'Privacy: id' to
+	  outgoing SIP messages that include the P-Asserted-Identity
+	  header. (closes issue AST-1301) ........ Merged revisions 411189
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-25 15:52 +0000 [r411089]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Fix incorrect use of timers If
+	  update_provisional_keepalive() is called while
+	  send_provisional_keepalive_full() is waiting on the PVT lock,
+	  then pvt->provisional_keepalive_sched_id will be changed to a new
+	  sched_id value by update_provisional_keepalive(), but that new
+	  sched_id then may be overwritten with -1 by
+	  send_provisional_keepalive_full(), killing the pvt's reference to
+	  a schedule and "leaking" the reference. (closes issue
+	  ASTERISK-22079) Review: https://reviewboard.asterisk.org/r/3368/
+	  Reported by: Jamuel Starkey, Matteo, Leif Madsen, Steve Davies
+	  Patches: provisional_keepalive_fix.diff uploaded by Steve Davies
+	  (license 5012) ........ Merged revisions 411088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-24 21:37 +0000 [r411022]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Always use fromdomain if set
+	  for domain, even if callerid is set to restricted. (closes issue
+	  ASTERISK-20841) Reported by: Kelly Goedert ........ Merged
+	  revisions 411021 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-20 22:46 +0000 [r410965]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_confbridge.c: app_confbridge: Fix bug - users with
+	  startmuted set don't start muted (closes issue ASTERISK-23461)
+	  Reported by: Chico Manobela Review:
+	  https://reviewboard.asterisk.org/r/3373/
+
+2014-03-18 11:50 +0000 [r410829]  Sean Bright <sean at malleable.com>
+
+	* res/res_fax_spandsp.c: res_fax_spandsp: Use g711_free() when
+	  available. Per Johann Steinwendtner on the asterisk-dev mailing
+	  list:
+	  http://lists.digium.com/pipermail/asterisk-dev/2014-March/066102.html
+	  g711_free() was introduced in spandsp 0.0.6pre4 and
+	  g711_release() became a noop. I opted not to remove the call to
+	  g711_release() since it is harmless and to call g711_free() if we
+	  have a sufficiently recent version of spandsp. (issue
+	  ASTERISK-20149) Reported by: Alexandr Gordeev
+
+2014-03-17 21:55 +0000 [r410717-410749]  Russ Meyerriecks <rmeyerreicks at digium.com>
+
+	* /, main/callerid.c: !fixup: callerid: Logic error in checksum
+	  processing Fixes syntax error in previous commit :-( ........
+	  Merged revisions 410748 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/callerid.c: callerid: Logic error in checksum processing
+	  Callerid checksum-ing was being handled incorrectly here. When
+	  the checksum is calculated to be 0x00, it will perform 0x100-0x00
+	  which results in 0x100. This value will then fail the otherwise
+	  correct callerid message. This patch changes the logic to simply
+	  add the calculated checksum to the transmitted 2's compliment
+	  checksum. Review: https://reviewboard.asterisk.org/r/3356/
+	  (closes issue ASTERISK-23488) ........ Merged revisions 410710
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-14 21:12 +0000 [r410609]  Jonathan Rose <jrose at digium.com>
+
+	* main/manager.c: manager: fix memory leak in manager_add_filter
+	  function (closes issue ASTERISK-23420) Reported by: Etienne
+	  Lessard Patches: manager_eventfilter_leak uploaded by Etienne
+	  Lessard (license 6394)
+
+2014-03-14 20:53 +0000 [r410556-410606]  Mark Michelson <mmichelson at digium.com>
+
+	* main/db.c: Remove an extra ast_cond_wait() that slipped through
+	  the patch.
+
+	* main/db.c: Prevent delayed astdb syncs. The syncing thread sleeps
+	  for a second before waiting to be told to attempt to sync again.
+	  If a signal were sent during this sleeping period, we would end
+	  up having to wait until the next sync signal occurred in order to
+	  sync up the astdb. This code rearrangement also ensures that any
+	  pending transactions will be synced prior to Asterisk shutting
+	  down. Patches: db_sync.patch by John Hardin (License #6512)
+
+2014-03-12 18:35 +0000 [r410490]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/conf_state.c,
+	  apps/confbridge/conf_state_single.c,
+	  apps/confbridge/conf_state_inactive.c,
+	  apps/confbridge/conf_state_single_marked.c: app_confbridge: Make
+	  explicitly stop MOH if a user is kicked or hangs up while MOH is
+	  playing. When MOH is playing to a user in a conference and the
+	  user is kicked or hangs up from the conference then the AMI
+	  MusicOnHoldStop events didn't happen. (Asterisk v11 AMI event:
+	  MusicOnHold, state:Stop) (closes issue ASTERISK-23311) Reported
+	  by: Benjamin Keith Ford Review:
+	  https://reviewboard.asterisk.org/r/3306/
+
+2014-03-10 17:09 +0000 [r410381]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/http.c: AST-2014-001: Stack overflow in HTTP processing
+	  of Cookie headers. Sending a HTTP request that is handled by
+	  Asterisk with a large number of Cookie headers could overflow the
+	  stack. Another vulnerability along similar lines is any HTTP
 	  request with a ridiculous number of headers in the request could
 	  exhaust system memory. (closes issue ASTERISK-23340) Reported by:
 	  Lucas Molas, researcher at Programa STIC, Fundacion; and Dr.
 	  Manuel Sadosky, Buenos Aires, Argentina ........ Merged revisions
 	  410380 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 410381 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410383 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
 
-2014-03-10 16:33 +0000 [r410369]  Scott Griepentrog <sgriepentrog at digium.com>
+2014-03-10 13:18 +0000 [r410311]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: AST-2014-002: chan_sip: Exit early on bad
+	  session timers request This change allows chan_sip to avoid
+	  creation of the channel and consumption of associated file
+	  descriptors altogether if the inbound request is going to be
+	  rejected anyway. (closes issue ASTERISK-23373) Reported by: Corey
+	  Farrell Patches: chan_sip-earlier-st-1.8.patch uploaded by Corey
+	  Farrell (license 5909) chan_sip-earlier-st-11.patch uploaded by
+	  Corey Farrell (license 5909) ........ Merged revisions 410308
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-07 22:52 +0000 [r410225]  Corey Farrell <git at cfware.com>
+
+	* /, channels/chan_sip.c: chan_sip: Fix deadlock of monlock between
+	  unload_module and do_monitor Release monlock before calling
+	  pthread_join. This ensures do_monitor cannot freeze by locking
+	  monlock during module unload. (closes issue ASTERISK-21406)
+	  Reported by: Corey Farrell Review:
+	  https://reviewboard.asterisk.org/r/3284/ ........ Merged
+	  revisions 410224 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-07 04:38 +0000 [r410106]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Allow static realtime members
+	  to be qualified during module load. When a static realtime peer
+	  with qualify=yes is loaded, Asterisk will fail to send an OPTIONS
+	  request due to the lastms being equal to 0. This results in the
+	  peer being unable to receive calls from Asterisk because the
+	  status is permanently UNKNOWN. This patch allows an OPTIONS
+	  request to be sent during module load by ignoring the lastms
+	  value on startup only. Review:
+	  https://reviewboard.asterisk.org/r/3294/ (closes issue
+	  ASTERISK-17523) Reported by: Maciej Krajewski Tested by:
+	  wushumasters patches: realtime_fix_11.7.0.txt uploaded by Trevor
+	  Peirce (license 6112) ........ Merged revisions 410105 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-06 23:15 +0000 [r410044]  Russell Bryant <russell at russellbryant.com>
+
+	* /, res/res_musiconhold.c: moh: fix a refcount error with realtime
+	  MOH I observed a crash in res_musiconhold on an Asterisk 11
+	  system using realtime MOH. Investigation of the backtrace showed
+	  a corrupt mohclass, implying that it got destroyed before the
+	  code expected it to. I went looking for reference counting errors
+	  that could have caused this crash and this patch this result. It
+	  contains 2 changes. 1) Remove a usless block of code that was
+	  impossible to reach. There was even a comment indicating that it
+	  was impossible to reach. The conditional includes
+	  "!ast_test_flag(global_flags, MOH_CACHERTCLASSES)" and it's
+	  inside of an if block with the opposite check
+	  "ast_test_flag(global_flags, MOH_CACHERTCLASSES)". There's no
+	  good reason to keep it around. 2) A similar block to #1 contained
+	  a reference counting error. It stores state->class in the local
+	  variable mohclass without increasing its reference count. The
+	  reference count on mohclass is decremented at the end of the
+	  function. This block of code probably very rarely runs, which
+	  would help explain why this system was working fine for many
+	  months before experiencing a crash. Review:
+	  https://reviewboard.asterisk.org/r/3282/ ........ Merged
+	  revisions 410043 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-06 01:58 +0000 [r409990]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_fax_spandsp.c: res_fax_spandsp: Fix crash when passing
+	  ulaw/alaw data to spandsp When acting as a T.38 fax gateway,
+	  res_fax_spandsp would at times cause a crash in libspandsp. This
+	  would occur when, during fax tone detection, a ulaw/alaw frame
+	  would be passed to modem_connect_tones_rx. That particular
+	  routine expects the data to be in slin format. This patch looks
+	  at the frame type and, if the data is ulaw/alaw, converts the
+	  format to slin before passing it to modem_connect_tones_rx.
+	  Review: https://reviewboard.asterisk.org/r/3296 (closes issue
+	  ASTERISK-20149) Reported by: Alexandr Gordeev Tested by: Michal
+	  Rybarik patches: spandsp_g711decode.diff uploaded by Michal
+	  Rybarik (license 6578)
+
+2014-03-05 20:37 +0000 [r409917]  Kinsey Moore <kmoore at digium.com>
+
+	* main/config.c, /: config: Fix inverted test The test of the
+	  result of the stat() call was inverted such that its output was
+	  only used if the call failed. This inverts the test so that the
+	  output of stat() is used correctly. This was causing full reloads
+	  on unchanged files. (closes issue ASTERISK-23383) Reported by:
+	  David Woolley ........ Merged revisions 409916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-05 18:45 +0000 [r409886]  Mark Michelson <mmichelson at digium.com>
+
+	* funcs/func_presencestate.c: Fix documentation for PRESENCE_STATE
+	  to properly illustrate how to create a presence hint. There was a
+	  missing comma. This was discovered by Dan Kaplan.
+
+2014-03-05 16:55 +0000 [r409834]  David M. Lee <dlee at digium.com>
+
+	* main/config.c, /, configure, include/asterisk/autoconfig.h.in,
+	  configure.ac: Corrected cross-platform stat nanosecond code When
+	  nanosecond time resolution was added for identifying config file
+	  changes, it didn't cover all of the myriad of ways that one might
+	  obtain nanosecond time resolution off of struct stat. Rather than
+	  complicate the #if even further figuring out one system from the
+	  next, this patch directly tests for the three struct members I
+	  know about today, and #ifdef's accordingly. Review:
+	  https://reviewboard.asterisk.org/r/3273/ ........ Merged
+	  revisions 409833 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-05 12:04 +0000 [r409778]  Sean Bright <sean at malleable.com>
+
+	* /, contrib/scripts/astgenkey, contrib/scripts/astgenkey.8: Fix
+	  references to 'keys' CLI commands in astgenkey ........ Merged
+	  revisions 409777 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-05 06:28 +0000 [r409745-409761]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, /: Correct RTP handling in chan_unistim
+	  and fix transfer process broken in previous fix: - Fixed too
+	  early RTP setup with phone, that cause no ringback tone on caller
+	  side - Handle call transfer cancel only in STATE_CALL case
+	  (related to ASTERISK-23073) (Reported by: Németh Tamás, niurkin
+	  sil)
+
+	* channels/chan_unistim.c: Add update_peer function to
+	  unistim_rtp_glue, improve other unistim_rtp_glue functions
+	  conforming to other channel drivers. Do not forget auto-detected
+	  and user-selected phone settings on 'unistim reload' ........
+	  Merged revisions 409705 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-05 04:55 +0000 [r409681-409703]  Moises Silva <moises.silva at gmail.com>
+
+	* res/res_http_websocket.c: Fix res/res_http_websocket.c build
+	  failure in 32bit due to incorrect print format for uint64_t
+
+	* res/res_http_websocket.c: Fix WebRTC over WSS not working Several
+	  fixes for the WebSockets implementation in
+	  res/res_http_websocket.c * Flush the websocket session FILE* as
+	  fwrite() may not actually guarantee sending the data to the
+	  network. If we do not flush, it seems that buffering on the SSL
+	  socket for outbound messages causes issues * Refactored
+	  ast_websocket_read to take into account that SSL file descriptors
+	  may be ready to read via fread() but poll() will not actually say
+	  so because the data was already read from the network buffers and
+	  is now in the libc buffers (closes issue ASTERISK-23099) (closes
+	  issue ASTERISK-21930) Review:
+	  https://reviewboard.asterisk.org/r/3248/
+
+2014-03-04 19:33 +0000 [r409625]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* funcs/func_audiohookinherit.c, /: func_audiohookinheritance:
+	  Check If A Channel Was Specified This patch prevents a crash when
+	  using the function audiohookinheritance without setting the
+	  channel. (closes issue ASTERISK-23104) Reported by: Joel Vandal
+	  Tested by: Joel Vandal Patches:
+	  asterisk-23104_audiohook_inherit_no_channel-11.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/3272/ ........ Merged
+	  revisions 409623 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-04 16:51 +0000 [r409567]  Kinsey Moore <kmoore at digium.com>
+
+	* main/astobj2.c, /: AO2: Add an assert for bad objects This adds
+	  an assert that will only be active if Asterisk is compiled with
+	  DO_CRASH and allows the testsuite to fail tests that would
+	  otherwise require log file parsing. ........ Merged revisions
+	  409566 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-04 16:40 +0000 [r409565]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix one way audio
+	  problems with hold/unhold when using ICE ICE sessions will now be
+	  restarted if sessions are changed to use new sets of remote
+	  candidates. (closes issue ASTERISK-22911) Reported by: Vytis
+	  Valentinavičius Review: https://reviewboard.asterisk.org/r/3275/
+
+2014-03-04 15:35 +0000 [r409524]  Kinsey Moore <kmoore at digium.com>
+
+	* main/rtp_engine.c, /: rtp_engine: Clean up after a failed remote
+	  bridge Upon failure of an INVITE transaction meant to initiate a
+	  remote native bridge, rtp_engine.c would not clean up
+	  non-reference-counted bridge instance pointers leaving a dangling
+	  pointer which was being used to perform a local native bridge
+	  after the other channel had hung up. This lead to dereferencing
+	  into freed memory and plenty of AO2 errors. This change allows
+	  the remote native bridge loop to clean up properly when the
+	  bridge fails. (closes issue ASTERISK-23310) Reported by: Jeremy
+	  Laine ........ Merged revisions 409521 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-04 14:52 +0000 [r409473]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_sip.c: Minor whitespace change to 'sip show
+	  peers' output. (closes issue ASTERISK-23406) Reported by: ibercom
+	  Tested by: ibercom Patches: asterisk-11.patch uploaded by ibercom
+	  ........ Merged revisions 409472 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-03 02:07 +0000 [r409362]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/asterisk.c: doxygen: Tweak the link back to ye olde
+	  Digium website ........ Merged revisions 409361 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-02 12:26 +0000 [r409344]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, Makefile.rules: Makefile: replace -O6 with -O3 -O6 is not a
+	  legal option of gcc. Unofficially gcc considers it to be
+	  equivalent of -O3. clang chalks on it, though. This commit sets
+	  the default optimization flag to be -O3, like gcc actually
+	  considered it. Review: https://reviewboard.asterisk.org/r/3280/
+	  ........ Merged revisions 409308 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-28 21:30 +0000 [r409255]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Add precautionary p->owner
+	  checks. * Add precautionary p->owner checks in sip_hangup(),
+	  get_refer_info(), get_also_info(), and
+	  interpret_t38_parameters(). * Simplify some tangled logic in
+	  get_refer_info(), get_also_info(), and add_rpid(). * Removed some
+	  dead code in handle_request_invite(). (closes issue
+	  ASTERISK-23323) Reported by: Walter Doekes Patches:
+	  issueA23323-more_p_owner_checks-1.8.x.patch (license #5674)
+	  uploaded by wdoekes (modified)
+	  issueA23323-more_p_owner_checks-11.x.patch (license #5674)
+	  uploaded by wdoekes (modified)
+	  issueA23323-more_p_owner_checks-12.x.patch (license #5674)
+	  uploaded by wdoekes (modified)
+	  issueA23323-more_p_owner_checks-trunk.patch (license #5674)
+	  uploaded by wdoekes (modified) ........ Merged revisions 409207
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-28 21:13 +0000 [r409208]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_queue.c: app_queue: Fix documentation generation The
+	  documentation for QueueMemberPaused was causing documentation
+	  generation to fail because the documentation for that AMI event
+	  was in the wrong location. This moves that documentation the
+	  correct location and adds a missing parameter. (closes issue
+	  SWDAT-261)
+
+2014-02-28 18:00 +0000 [r409157]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Fix crash in
+	  ast_channel_hangupcause_set(). * Fix crash in
+	  ast_channel_hangupcause_set() because p->owner not checked before
+	  calling. Regression introduced by the fix for ASTERISK-22621.
+	  (closes issue ASTERISK-23135) Reported by: OK (issue
+	  ASTERISK-23323) Reported by: Walter Doekes ........ Merged
+	  revisions 409156 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-27 19:38 +0000 [r409129-409130]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: correct build error
+	  from r409129 Accidentally placed a declaration below functional
+	  code (issue ASTERISK-23213) Reported by: Andrea Suisani Review:
+	  https://reviewboard.asterisk.org/r/3256/
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fix checklist creating
+	  problems in ICE sessions Prior to this patch, local candidate
+	  lists including SRFLX would fail to start properly when building
+	  ICE candidate check lists. This patch fixes that problem by
+	  making sure that each SRFLX candidate is associated with the
+	  proper base address so that the check list can create matches
+	  properly. This patch was written by jcolp. The issue will be left
+	  open to await testing by the issue participants. (issue
+	  ASTERISK-23213) Reported by: Andrea Suisani Review:
+	  https://reviewboard.asterisk.org/r/3256/
+
+2014-02-27 16:24 +0000 [r409083]  David M. Lee <dlee at digium.com>
+
+	* /, utils/astman.c: Fix memory stomping bug in astman. This memset
+	  complained in dev mod on my Ubuntu box. The memset is both
+	  unnecessary and dangerous. At this point, m hasn't been
+	  initialized yet, so the memset will write off to whatever address
+	  happens to be on the stack at the time. ........ Merged revisions
+	  409077 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-27 16:03 +0000 [r409053]  Corey Farrell <git at cfware.com>
+
+	* /, res/res_fax.c, configs/res_fax.conf.sample: res_fax: Warn that
+	  minrate=2400 is not valid for V.27 instead of failing load.
+	  Change minrate from 2400 to 4800 on config reload in response to
+	  changes from ASTERISK-22790 only. Any config with minrate of 2400
+	  that would fail before r405693 will still fail. Comment out many
+	  settings in res_fax.conf.sample. The defaults are set in
+	  res_fax.c, so setting the same value in sample config does
+	  nothing but make the sample config more fragile. (closes issue
+	  ASTERISK-23231) Reported by: David Brillert Review:
+	  https://reviewboard.asterisk.org/r/3261/ ........ Merged
+	  revisions 409052 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-27 12:47 +0000 [r409002]  Matthew Jordan <mjordan at digium.com>
+
+	* main/rtp_engine.c, /, include/asterisk/rtp_engine.h: rtp_engine:
+	  fix crash during remote native bridging when calling get_codecs
+	  When two RTP channels are in a remote bridge, the remote bridging
+	  loop in rtp_engine will periodically check to see if the two
+	  channels can still be bridged. One of the many things it checks
+	  is whether or not the codecs have changed on the channel. If the
+	  codec has changed, it will break out of the loop to re-determine
+	  which type of bridge is appropriate. In order to perform this
+	  check, the ast_rtp_glue virtual table's get_codec callback is
+	  called for each channel. The callback implementations assume that
+	  the channel tech private is valid when called; as such, there has
+	  always been some code in place to check whether or not the
+	  channel pvt is NULL before calling. However, this check is
+	  insufficient. The channels are unlocked during the remote
+	  bridging loop. It is possible for a channel to get masqueraded
+	  between the check for the pvt being NULL and the actual call to
+	  get_codec. When this occurs, the callback is called with a ZOMBIE
+	  channel, which now has a NULL pvt. Crash. While this has always
+	  been possible in Asterisk 1.8, it is much more likely to occur in
+	  Asterisk 11 and later versions due to the timing changes that
+	  occur when getting the codec from a channel. Note that this is
+	  much more likely to be reproduced on slow, boggy hardware running
+	  Asterisk 11 - but fairly rarely otherwise. Also Note: This crash
+	  was also caught by the various SIP blind transfer tests, in
+	  addition to the bug report Alec filed. Review:
+	  https://reviewboard.asterisk.org/r/3247/ (closes issue
+	  ASTERISK-21737) Reported by: Alec Davis Tested by: Alec Davis
+	  ........ Merged revisions 409001 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-25 17:43 +0000 [r408877]  Rusty Newton <rnewton at digium.com>
+
+	* /, configs/voicemail.conf.sample: configs/voicemail.conf.sample -
+	  Make mailcmd sample text more explicit Made the wording a bit
+	  more explicit. Didn't really change the meaning. ........ Merged
+	  revisions 408876 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-22 17:42 +0000 [r408838]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: ignore AST_CONTROL_PVT_CAUSE_CODE without
+	  any messages (closes issue ASTERISK-23336) Reported by: Alexander
+	  Semych
+
+2014-02-22 02:28 +0000 [r408786]  Corey Farrell <git at cfware.com>
+
+	* res/ael/pval.c, main/pbx.c, /, utils/extconf.c, utils/conf2ael.c:
+	  Remove extra defines of AST_PBX_MAX_STACK. * Ensure
+	  AST_PBX_MAX_STACK is only defined in extconf.h and pbx.h. * Fix
+	  incorrect function parameters in utils/extconf.c. (closes issue
+	  ASTERISK-23141) Reported by: Maxim Review:
+	  https://reviewboard.asterisk.org/r/3241/ ........ Merged
+	  revisions 408785 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-21 20:21 +0000 [r408643-408748]  Kevin Harwell <kharwell at digium.com>
+
+	* /, apps/app_forkcdr.c: app_forkcdr: ForkCDR v option does not
+	  keep CDR variables for subsequent records When the 'v' option is
+	  specified to ForkCDR application, AST_CDR_FLAG_KEEP_VARS flag is
+	  set only for the first CDR in the chain. So ForkCDR works fine
+	  with this option only once. After the second and further calls to
+	  ForkCDR, CDR variables get cleared on all CDRs besides the first
+	  one and moved to the newly forked CDR. It always sets the
+	  KEEP_VARS flag on the first CDR in the chain, instead of the most
+	  recent CDR which is used as a base to fork a new CDR. This patch
+	  sets KEEP_VARS flag on the most recent CDR on the stack (the CDR
+	  used for forking). (closes issue ASTERISK-23260) Reported by:
+	  zvision Patches: app_forkcdr.diff uploaded by zvision (license
+	  5755) ........ Merged revisions 408747 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* contrib/scripts/install_prereq: install_prereq: Missing
+	  uuid[-dev] for debian distros Added uuid and uuid-dev to install
+	  prereq script. (closes issue ASTERISK-23255) Reported by: Rusty
+	  Newton
+
+	* contrib/scripts/install_prereq, main/rtp_engine.c: rtp_engine:
+	  Dynamic payload change in rtp mapping not supported Asterisk
+	  didn't support the dynamic payload change in rtp mapping in the
+	  200 OK response. Scenario: Asterisk sends the INVITE proposing
+	  alaw and telephone-event, it proposes rtpmap:101 for
+	  telephone-event. Peer responds with 2xx, it answers with alaw and
+	  telephone-event also, but it proposes a different rtpmap number
+	  (rtpmap:103) for telephone-event. Expected Behaviour: Asterisk
+	  should honour the rtpmapping in the response and send DTMF
+	  packets using 103 as payload type for DTMF. Actual Behaviour:
+	  Asterisk sends DTMF packets using payload type 101. With this
+	  patch asterisk now supports changes that can occur in the rtp
+	  mapping in the response. (closes issue ASTERISK-23279) Reported
+	  by: NITESH BANSAL Review:
+	  https://reviewboard.asterisk.org/r/3225/ Patches:
+	  dynamic_payload_change.patch uploaded by nbansal (license 6418)
+
+	* main/rtp_engine.c, /: rtp_engine: Output mixup in
+	  ${CHANNEL(rtpqos,audio,all)} Fixed the output of
+	  CHANNEL(rtpqos,audio,all) to use txjitter instead of rxjitter.
+	  (closes issue ASTERISK-23261) Reported by: rsw686 Patches:
+	  rtpqos.patch uploaded by rsw686 (license 5887) ........ Merged
+	  revisions 408646 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c, main/channel.c: channel.c: MOH is not
+	  working for transferee after attended transfer Updated the code
+	  to check to see if MOH is playing on the transferor and if so
+	  then start it on the channel that replaces it during a
+	  masquerade. Example scenario of the problem: Alice calls Bob and
+	  then Bob begins the attended transfer process into a queue. Upon
+	  going on hold Alice hears music and so does Bob once he is in the
+	  queue. Bob then transfers Alice into the queue and then music for
+	  Alice stops even though she should be hearing it since has now
+	  replaced Bob in the queue. The problem that was occurring is that
+	  once the channel was masqueraded the app (queues, confbridge,
+	  etc...) had no way of knowing that the channel had just been
+	  swapped out thus it did not start music for the present channel.
+	  Credit to Olle Johansson for pointing me in the right direction
+	  on this issue. (closes issue ASTERISK-19499) Reported by: Timo
+	  Teräs Review: https://reviewboard.asterisk.org/r/3226/ ........
+	  Merged revisions 408642 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-21 10:40 +0000 [r408590]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/ooCalls.h: Fix type of roundTripDelay
+	  variables ........ Merged revisions 408589 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-21 00:47 +0000 [r408537]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, apps/app_chanspy.c: app_chanspy: Documentation Update To
+	  Clarify "x" Option When using the "x" option (specify a DTMF
+	  digit to exit the application), it is not obvious in the
+	  documentation that this only works when spying on a channel. If a
+	  channel being used to spy on other channels is waiting to connect
+	  to a channel or is no longer attached to a channel, the DTMF is
+	  ignored. As noted on the issue tracker, since there are
+	  workarounds available and this is a rarely used option we are
+	  opting for a documentation change here. (closes issue
+	  ASTERISK-22661) Reported by: Chris Hillman Patches:
+	  asterisk-22661-doc-clarify-chan_spy.diff uploaded by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2990/ ........ Merged
+	  revisions 408536 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-20 02:41 +0000 [r408448]  Rusty Newton <rnewton at digium.com>
+
+	* apps/app_queue.c, /: apps/app_queue - Fix incorrect Macro
+	  parameter documentation Macro is executed on the called channel,
+	  not the calling channel. (closes issue ASTERISK-23069) Reported
+	  By: Bryan Anderson ........ Merged revisions 408447 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-19 19:05 +0000 [r408388]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/config.c, /: config: Add file size and nanosecond resolution
+	  fields to the cached modified config file information. Repeatedly
+	  modifying config files and reloading too fast sometimes fails to
+	  reload the configuration because the cached modification
+	  timestamp has one second resolution. * Added file size and
+	  nanosecond resolution fields to the cached config file
+	  modification timestamp information. Now if the file size changes
+	  or the file system supports nanosecond resolution the modified
+	  file has a better chance of being detected for reload. * Added a
+	  missing unlock in an off-nominal code path. (closes issue
+	  AST-1303) Review: https://reviewboard.asterisk.org/r/3235/
+	  ........ Merged revisions 408387 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-19 11:45 +0000 [r408312-408330]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooCapability.c, /,
+	  addons/ooh323c/src/ooh245.c: process receiveAndTransmit user
+	  input remote caps instead of receive only send receiveAndTransmit
+	  user input our caps instead of receive only ........ Merged
+	  revisions 408328 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* addons/ooh323c/src/ooh323.c: Allow different socket and
+	  signalling ip on h.323 connection if gk mode is active Reported
+	  by: Gabriele Odone Patches: ASTERISK-22738-1.patch Tested by:
+	  Gabriele Odone
+
+2014-02-16 03:15 +0000 [r408193-408201]  Matthew Jordan <mjordan at digium.com>
+
+	* main/pbx.c, /: pbx: Handle a completely empty dialplan during a
+	  context merge It is highly unlikely, but - at least in Asterisk
+	  12 - theoretically possible to load Asterisk with no dialplan
+	  whatsoever. If that occurs, and some other module (that is not a
+	  pbx module) attempts to merge its contexts into the dialplan, the
+	  existing merge routine will crash. This is because it is not
+	  insane, and rightly believes that you provided some sort of
+	  dialplan, somewhere. This patch will gracefully merge the
+	  contexts in such a case. Note that this is highly unlikely to
+	  occur in 1.8/11, as features will most likely provide some
+	  dialplan via parking. However, in Asterisk 12, parking is now
+	  provided by res_parking, and hence may create its dialplan later.
+	  (closes issue ASTERISK-23297) Reported by: CJ Oster Review:
+	  https://reviewboard.asterisk.org/r/3222 ........ Merged revisions
+	  408200 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* Makefile: buildsystem: Unbreak the build (infloop) on Asterisk
+	  11+ Apparently r408084 ( https://reviewboard.asterisk.org/r/3212/
+	  ) broke the build. This patch fixes it by ignoring the .lastclean
+	  dependencies if the MENUSELECT_EMBED variable is not defined.
+	  patches: tmp.diff uploaded by wdoekes (License 5674) Review:
+	  https://reviewboard.asterisk.org/r/3228/
+
+2014-02-14 21:53 +0000 [r408137-408143]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/pbx.c, /: pbx: ast_custom_function_unregister resource leak
+	  In pbx.c ast_custom_function_unregister(), a list of escalations
+	  being removed from the list wasn't being free'd creating a leak.
+	  This patch corrects that by freeing the records. Review:
+	  https://reviewboard.asterisk.org/r/3213/ Reported by: Corey
+	  Farrell Patches: acf_escalating_leak.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 408142 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/format.c: format.c: correct possible null pointer
+	  dereference In ast_format_sdp_parse and ast_format_sdp_generate
+	  the check checks for a valid interface and function were
+	  potentially confusing, and hid an error in the test of the
+	  presence of the function that is called later. This patch clears
+	  up and corrects the test. Review:
+	  https://reviewboard.asterisk.org/r/3208/ (closes issue
+	  ASTERISK-23098) Reported by: marcelloceschia Patches:
+	  main_format.patch uploaded by marcelloceschia (license 6036)
+	  ASTERISK-23098.patch uploaded by coreyfarrell (license 5909)
+
+2014-02-14 13:27 +0000 [r408084]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* Makefile, /: buildsystem: Don't force main to depend on
+	  everything else. Directory 'main' only needs to depend on
+	  embedded modules. If no module embedding is selected, the
+	  dependency is dropped. Review:
+	  https://reviewboard.asterisk.org/r/3212/ ........ Merged
+	  revisions 408083 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-14 01:24 +0000 [r408021]  Rusty Newton <rnewton at digium.com>
+
+	* configs/agents.conf.sample, /: configs/agents.conf.sample -
+	  Remove example for non-functional "goodbye" parameter The
+	  "goodbye" parameter is not implemented in the source code, it
+	  does nothing. (closes issue SWP-6518) Reported By: Steve Pitts
+	  ........ Merged revisions 408020 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-10 16:34 +0000 [r407874]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* res/res_config_pgsql.c, /: res_config_pgsql: Fix
+	  ast_update2_realtime calls. Fix so multiple updates from a single
+	  call works (add missing ','). Remove bogus ast_free's that
+	  weren't supposed to be there. Moved a few spaces for readability.
+	  Review: https://reviewboard.asterisk.org/r/3194/ ........ Merged
+	  revisions 407873 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-10 15:28 +0000 [r407857]  Kinsey Moore <kmoore at digium.com>
+
+	* configs/confbridge.conf.sample,
+	  apps/confbridge/include/confbridge.h, UPGRADE.txt,
+	  apps/app_confbridge.c, apps/confbridge/conf_state_multi_marked.c,
+	  apps/confbridge/conf_state_empty.c,
+	  apps/confbridge/conf_config_parser.c: ConfBridge: Correct prompt
+	  playback target Currently, when the first marked user enters the
+	  conference that contains waitmarked users, a prompt is played
+	  indicating that the user is being placed into the conference.
+	  Unfortunately, this prompt is played to the marked user and not
+	  the waitmarked users which is not very helpful. This patch
+	  changes that behavior to play a prompt stating "The conference
+	  will now begin" to the entire conference after adding and
+	  unmuting the waitmarked users since the design of confbridge is
+	  not conducive to playing a prompt to a subset of users in a
+	  conference in an asynchronous manner. (closes issue PQ-1396)
+	  Review: https://reviewboard.asterisk.org/r/3155/ Reported by:
+	  Steve Pitts
+
+2014-02-09 15:52 +0000 [r407818]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* channels/chan_dahdi.c, /: chan_dahdi: handle DAHDI_EVENT_REMOVED
+	  on a pri D-Channel When a DAHDI device is removed at run-time it
+	  sends the event DAHDI_EVENT_REMOVED on each channel. This is
+	  intended to signal the userspace program to close the respective
+	  file handle, as the driver of the device will need all of them
+	  closed to properly clean-up. This event has long since been
+	  handled in chan_dahdi (chan_zap at the time). However the event
+	  that is sent on a D-Channel of a "PRI" (ISDN) span simply gets
+	  ignored. This commit adds handling for closing the file
+	  descriptor (and shutting down the span, while we're at it). It
+	  also adds a CLI command 'pri destroy span <N>' to destroy the
+	  span and its DAHDI channels. Backported from trunk/12. Review:
+	  https://reviewboard.asterisk.org/r/726/ ........ Merged revisions
+	  394552 394567 from http://svn.asterisk.org/svn/asterisk/trunk
+	  ........ Merged revisions 407817 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-07 20:46 +0000 [r407727-407765]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_iax2.c: chan_iax2: Add some more iaxs[] NULL
+	  checks to a routine already full of them. ........ Merged
+	  revisions 407764 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_iax2.c, include/asterisk/frame.h,
+	  configs/iax.conf.sample, /: chan_iax2: Block unnecessary control
+	  frames to/from the wire. Establishing an IAX2 call between
+	  Asterisk v1.4 and v1.8 (or later) results in an unexpected call
+	  disconnect. The problem happens because newer values in the enum
+	  ast_control_frame_type are not consistent between the branch
+	  versions of Asterisk. For example: 1) v1.4 calls v1.8 (or later)
+	  using IAX2 2) v1.8 answers and sends a connected line update
+	  control frame. (on v1.8 AST_CONTROL_CONNECTED_LINE = 22) 3) v1.4
+	  receives the control frame as an end-of-q (on v1.4
+	  AST_CONTROL_END_OF_Q = 22) 4) v1.4 disconnects the call once the
+	  receive queue becomes empty. Several things are done by this
+	  patch to fix the problem and attempt to prevent it from happening
+	  again in the future: * Added a warning at the definition of enum
+	  ast_control_frame_type about how to add new control frame values.
+	  * Made block sending and receiving control frames that have no
+	  reason to go over the wire. * Extended the connectedline iax.conf
+	  parameter to also include the redirecting information updates. *
+	  Updated the connectedline iax.conf parameter documentation to
+	  include a notice that the parameter must be "no" when the peer is
+	  an Asterisk v1.4 instance. (closes issue AST-1302) Review:
+	  https://reviewboard.asterisk.org/r/3174/ ........ Merged
+	  revisions 407678 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-07 13:06 +0000 [r407623]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, configs/indications.conf.sample: indications.conf: add stutter
+	  tone; end properly * If the "stutter" (voicemail indication) tone
+	  is indeed a stutter tone, and it ends with a constant tone, make
+	  sure that it is the dial tone. This was done for India (in),
+	  Mexico (mx) and the Philippines (ph). * If no "stutter" tone
+	  exists for a country, provide one. This was done for Spain (es),
+	  Malaysia (my) and Venezuela (ve). Review:
+	  https://reviewboard.asterisk.org/r/3158/ ........ Merged
+	  revisions 407622 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-05 22:59 +0000 [r407512]  Rusty Newton <rnewton at digium.com>
+
+	* /, formats/format_wav.c: formats/format_wav: enhancing log
+	  message "Not a wav file" to be clear on what is supported
+	  Modifying the log message to be more specific as to what is
+	  supported. Specifically it seems format_wav supports only PCM
+	  encoded versions with a lower-case '.wav' extension. (closes
+	  issues ASTERISK-22310) Reported by: Jim Credland Review:
+	  https://reviewboard.asterisk.org/r/3188/ ........ Merged
+	  revisions 407511 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-05 20:37 +0000 [r407457]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_local.c: chan_local: Fix reversed LocalOptimization
+	  field in LocalBridge event (closes issue ASTERISK-23232) Reported
+	  by: Leon Roy
+
+2014-02-05 20:37 +0000 [r407456]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/logger.c: Logger: Fix handling of absolute paths This
+	  fixes path handling for log files so that an extra / is not
+	  appended to the file path when the path is absolute (begins with
+	  /). This would previously result in different but functionally
+	  equivalent paths in the output of 'logger show channels'.
+	  ........ Merged revisions 407455 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-04 19:56 +0000 [r407273-407338]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/devicestate.h, /, main/devicestate.c:
+	  devicestate: Make ast_devstate_changed_literal() return value and
+	  doxygen consistent. Nothing actually cares about the value
+	  anyway. (closes issue ASTERISK-23178) Reported by: Jonathan Rose
+	  ........ Merged revisions 407337 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* configs/sip.conf.sample, main/tcptls.c, /: tcptls.c: Made TLS
+	  handle a certificate chain file. Thanks to Guillaume Martres for
+	  doing the necessary research to validate the change. (closes
+	  issue ASTERISK-17727) Reported by: LN Patches:
+	  use_certificate_chain.patch (license #5864) patch uploaded by st
+	  documente_certificate_chain.patch (license #6576) patch uploaded
+	  by Guillaume Martres ........ Merged revisions 407272 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-04 02:20 +0000 [r407210]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_clialiases.c, /: res_clialiases: Fix crash when reloading
+	  and re-aliasing an alias that is in use. The code assumed that
+	  unregistering the alias would always succeed while in practice
+	  this is not actually true. A common case is the "reload" command
+	  itself. If the cli_aliases.conf configuration file was changed
+	  and reload executed the command would fail to unregister and
+	  ultimately point to freed memory. The reload process now checks
+	  whether unregistering succeeded or not and if not the old CLI
+	  alias is retained. (closes issue ASTERISK-19773) Reported by:
+	  Joel Vandal (closes issue ASTERISK-22757) Reported by: Gareth
+	  Blades ........ Merged revisions 407205 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-02-01 00:23 +0000 [r407103]  Corey Farrell <git at cfware.com>
+
+	* apps/app_stack.c, /: app_stack: protect against missing
+	  parameters to STACK_PEEK and LOCAL_PEEK STACK_PEEK requires 2
+	  parameters and LOCAL_PEEK requires 1 parameter. This protects
+	  against situations where those parameters are blank or missing by
+	  logging an error and returning. (closes issue ASTERISK-23220)
+	  Reported by: James Sharp ........ Merged revisions 407100 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-31 23:28 +0000 [r407074]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_dial.c, /: app_dial: Allow macro/gosub pre-bridge
+	  execution to occur on priorities The parsing for the destination
+	  of the macro/gosub uses the '^' character to separate out
+	  context, extension, and priority. However, the logic for the
+	  macro/gosub execution was written such that it would only do the
+	  actual macro/gosub jump if a '^' character existed. This doesn't
+	  apply when the macro/gosub jump occurs in a priority/priority
+	  label. This patch changes the logic so that the parsing still
+	  occurs, but the jump will occur even for priorities/priority
+	  labels. (issue ASTERISK-23164) Review:
+	  https://reviewboard.asterisk.org/r/3154 ........ Merged revisions
+	  407041 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-30 20:28 +0000 [r406934]  Corey Farrell <git at cfware.com>
+
+	* main/udptl.c, res/res_rtp_asterisk.c, /: res_rtp_asterisk &
+	  udptl: fix port selection to work with SELinux restrictions
+	  ast_bind to a port reserved for another program by SELinux causes
+	  errno == EACCES. This caused random failures when binding rtp or
+	  udptl sockets. Treat EACCES as a non-fatal error, try next port.
+	  (closes issue ASTERISK-23134) Reported by: Corey Farrell ........
+	  Merged revisions 406933 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-30 17:32 +0000 [r406918]  Sean Bright <sean at malleable.com>
+
+	* main/manager.c: Make a NOTICE about an invalid channel name more
+	  useful.
+
+2014-01-29 00:39 +0000 [r406861]  Russell Bryant <russell at russellbryant.com>
+
+	* /, configs/queues.conf.sample: queues.conf.sample Fix documented
+	  default for persistentmembers Closes issue ASTERISK-22662
+	  ........ Merged revisions 406860 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-28 23:10 +0000 [r406802]  Kevin Harwell <kharwell at digium.com>
+
+	* configure, include/asterisk/autoconfig.h.in, configure.ac,
+	  cdr/cdr_radius.c, cel/cel_radius.c, /: cdr_radius, cel_radius:
+	  build agains libfreeradius-client Asterisk's RADIUS module
+	  currently build against libradiusclient-ng, but this project has
+	  been superseeded by libfreeradius-client. The API is 99%
+	  compatible except that the header name has changed, the library
+	  name has changed, and the configuration file location has
+	  changed. (closes issue ASTERISK-22980) Reported by: Jeremy Lainé
+	  Patches: freeradius-client.patch uploaded by sharky (license
+	  6561) ........ Merged revisions 406801 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-28 16:40 +0000 [r406722]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/rtp_engine.c, /: rtp_engine: improved handling of
+	  get_rtp_info failure In ast_rtp_instance_make_compatible(), after
+	  a failure of channel tech call get_rtp_info() to return
+	  peer_instance, the null pointer would be passed to ao2_ref,
+	  producing an error that looked like a refernce counting problem
+	  but is not. This patch corrects that and adds helpful LOG_ERROR
+	  messages to indicate which failure path occurred. (issue
+	  AST-1276) Review: https://reviewboard.asterisk.org/r/3156/
+	  ........ Merged revisions 406721 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-27 20:35 +0000 [r406567-406644]  Russell Bryant <russell at russellbryant.com>
+
+	* /, main/config.c: Allow nested #includes in extconfig.conf
+	  extconfig.conf was hard-coded to not allow nested includes for
+	  some reason. The code has been this way since a patch was merged
+	  for ASTERISK-3333 (revision 4889), which was a significant update
+	  to this code ("Merge config updates"). I can't figure out any
+	  good reason why this should be limited. This patch just removes
+	  the limit and uses the default nesting depth limit. Closes issue
+	  ASTERISK-17837 Review: https://reviewboard.asterisk.org/r/3159/
+	  ........ Merged revisions 406643 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/channel.c, /, main/file.c, include/asterisk/channel.h:
+	  Protect ast_filestream object when on a channel The
+	  ast_filestream object gets tacked on to a channel via
+	  chan->timingdata. It's a reference counted object, but the
+	  reference count isn't used when putting it on a channel. It's
+	  theoretically possible for another thread to interfere with the
+	  channel while it's unlocked and cause the filestream to get
+	  destroyed. Use the astobj2 reference count to make sure that as
+	  long as this code path is holding on the ast_filestream and
+	  passing it into the file.c playback code, that it knows it's
+	  valid. Bug reported by Leif Madsen. Review:
+	  https://reviewboard.asterisk.org/r/3135/ ........ Merged
+	  revisions 406566 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-26 23:01 +0000 [r406515]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/tcptls.c, /: tcptls.c: Add missing cleanup on off nominal
+	  path. ........ Merged revisions 406514 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-24 23:07 +0000 [r406400-406418]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/cel.c: CEL: Protect data structures during reload and
+	  shutdown. The CEL data structures need to be protected during a
+	  configuration reload and shutdown. Asterisk crashed during a
+	  shutdown because CEL events were still in flight and the CEL data
+	  structures were already destroyed. * Protected the appset and
+	  linkedids ao2 containers using the reload_lock. As a result
+	  appset, linkedids, and held objects don't need a lock. * Added
+	  NULL checks before use of the appset and linkedids ao2 containers
+	  in case the CEL module is already shutdown. * Fixed overloading
+	  of the linkedids held objects reference count. During shutdown
+	  any held objects would be leaked. * Fixed memory leak of
+	  linkedids held objects if the LINKEDID_END is not being tracked.
+	  The objects in the linkedids container were not removed if the
+	  LINKEDID_END event is not used. * Added access protection to the
+	  appset container during the CLI "cel show status" command. * Made
+	  CEL config reload not set defaults if the cel.conf file is
+	  invalid. (closes issue AST-1253) Reported by: Guenther Kelleter
+	  Review: https://reviewboard.asterisk.org/r/3127/ ........ Merged
+	  revisions 406417 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/manager.c, /: manager: Register atexit shutdown routine only
+	  once. * Made register atexit shutdown routine only once in
+	  __init_manager(). * Fixed some initial load failure conditions in
+	  __init_manager(). * Made reset options to defaults on reload when
+	  the reload will actually happen. * Removed unnecessary container
+	  traversals of the white/black filters during manager_free_user().
+	  * ast_free() does not need a NULL check before calling. ........
+	  Merged revisions 406359 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-24 21:14 +0000 [r406361]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_config_pgsql.c, /: res_config_pgsql: Fix a memory leak
+	  and use RAII_VAR for cleanup when practical Review:
+	  https://reviewboard.asterisk.org/r/3141/ ........ Merged
+	  revisions 406360 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-24 17:54 +0000 [r406341]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c: manager: Protect data structures during shutdown.
+	  Occasionally, the manager module would get an "INTERNAL_OBJ: bad
+	  magic number" error on a "core restart gracefully" command if an
+	  AMI connection is established. * Added ao2_global_obj protection
+	  to the sessions global container. * Fixed the order of
+	  unreferencing a session object in session_destroy(). * Removed
+	  unnecessary container traversals of the white/black filters
+	  during session_destructor(). (closes issue AST-1242) Reported by:
+	  Guenther Kelleter Review:
+	  https://reviewboard.asterisk.org/r/3144/
+
+2014-01-22 22:18 +0000 [r406245]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/pbx.c, /, utils/extconf.c: pbx.c: Pre-initialize timezone to
+	  avoid crash on destroy In ast_build_timing, initialize the
+	  timezone value to NULL in order to avoid deferencing an
+	  uninitialized value later when calling ast_destroy_timing. The
+	  timezone value could be uninitialized if ast_build_timing were to
+	  fail due to a zero length time string. (closes issue
+	  ASTERISK-22861) Reported by: Sebastian Murray-Roberts Review:
+	  https://reviewboard.asterisk.org/r/3134/ Patches:
+	  ast_build_timing-initialize-timezone.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 406241 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-22 19:31 +0000 [r406171-406217]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_confbridge.c: ConfBridge: Fix channel parameter
+	  documentation Confbridge AMI and CLI commands for mute, unmute,
+	  and setting the single video source can accept channel prefixes
+	  in lieu of a full channel name, but documentation states only
+	  that it is required and is a channel name. This corrects the
+	  documentation. (closes issue PQ-1397) Reported by: Steve Pitts
+
+	* /, channels/chan_sip.c: chan_sip: Decline image streams on
+	  unsupported transports This change allows chan_sip to decline
+	  individual image streams over unsupported transports in the SDP
+	  of the 200 response. Previously, an image stream offer with
+	  RTP/AVP as the transport would cause chan_sip to respond with a
+	  488. (closes issue ASTERISK-22988) Reported by: adomjan Original
+	  patch by: adomjan ........ Merged revisions 406170 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-21 21:05 +0000 [r406080]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* main/manager.c, /, configs/manager.conf.sample: manager: Clarify
+	  eventfilter documentation. Textual changes only. Review:
+	  https://reviewboard.asterisk.org/r/3133/ ........ Merged
+	  revisions 406079 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-21 19:59 +0000 [r406038]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_pktccops.c, channels/chan_mgcp.c, /: chan_mgcp: Enforce
+	  locking for oseq This restricts direct usage of global oseq so
+	  that all accesses are locked and threads are not racing to get
+	  oseq values that they did not claim. This also fixes a build
+	  error in res_pktccops under dev mode. (closes issue
+	  ASTERISK-23100) Reported by: adomjan Patch by: adomjan ........
+	  Merged revisions 406037 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-20 22:04 +0000 [r405927]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: chan_dahdi/PRI: Suppress CONNECTED_LINE
+	  updates when nothing in the udpate is valid. * Also simplified
+	  some subddress handling code. (closes issue ASTERISK-23008)
+	  Reported by: Michael Cargile ........ Merged revisions 405926
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-17 15:40 +0000 [r405792]  Rusty Newton <rnewton at digium.com>
+
+	* /, channels/chan_sip.c, doc/asterisk.8, main/features.c,
+	  configs/sip.conf.sample, apps/app_queue.c, apps/app_transfer.c,
+	  channels/chan_iax2.c: Documentation: doc fixes across various
+	  parts of the code for ASTERISK issues 23061,23028,23046,23027
+	  Fixes typos of "transfered" instead of "transferred" in various
+	  code. Fixes incorrect gosub param help text for app_queue. Fixes
+	  Asterisk man pages containing unquoted minus signs. Adds note
+	  about the "textsupport" option in sip.conf.sample. (issue
+	  ASTERISK-23061) (issue ASTERISK-23028) (issue ASTERISK-23046)
+	  (issue ASTERISK-23027) (closes issue ASTERISK-23061) (closes
+	  issue ASTERISK-23028) (closes issue ASTERISK-23046) (closes issue
+	  ASTERISK-23027) Reported by: Eugene, Jeremy Laine, Denis
+	  Pantsyrev Patches: transferred.patch uploaded by Jeremy Laine
+	  (license 6561) hyphen.patch uploaded by Jeremy Laine (license
+	  6561) sip.conf.sample.patch uploaded by Eugene (license 6360)
+	  ........ Merged revisions 405791 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-16 19:51 +0000 [r405693-405745]  Kevin Harwell <kharwell at digium.com>
+
+	* main/manager.c: manager: Originate doesn't abort on failed
+	  format_cap allocation action_originate responds to the remote
+	  system with an error when cap==NULL, but doesn't return (abort
+	  the originate). Patched to return. (closes issue ASTERISK-23034)
+	  Reported by: Corey Farrell Patches: ASTERISK-23034.patch uploaded
+	  by coreyfarrell (license 5909)
+
+	* configs/res_fax.conf.sample, UPGRADE.txt, /, res/res_fax.c:
+	  res_fax: check_modem_rate() returned incorrect rate for V.27
+	  According to the new standard for V.27 and V.32 they are able to
+	  transmit at a bit rate of 4,800 or 9,600. The check_mode_rate
+	  function needed to be updated to reflect this. Also, because of
+	  this change the default 'minrate' value was updated to be 4800.
+	  (closes issue ASTERISK-22790) Reported by: Paolo Compagnini
+	  Patches: res_fax.txt uploaded by looserouting (license 6548)
+	  ........ Merged revisions 405656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-15 16:35 +0000 [r405582]  Joshua Colp <jcolp at digium.com>
+
+	* /, cel/cel_manager.c: cel_manager: Don't crash if configuration
+	  file is invalid. The cel_manager module did not properly handle
+	  the case where the configuration file was invalid. The module
+	  will now output a warning message and disable itself if this
+	  occurs. Reported by: Bryan Walters ........ Merged revisions
+	  405581 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-03-03  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.8.0 Released.
+
+2014-03-01  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.8.0-rc3 Released.
+
+	* chan_sip: Fix crash in ast_channel_hangupcause_set().
+
+	  Fix crash in ast_channel_hangupcause_set() because p->owner not
+	  checked before calling.  Regression introduced by the fix for
+	  ASTERISK-22621.
+
+	  (closes issue ASTERISK-23135)
+	  Reported by: OK
+
+	  (issue ASTERISK-23323)
+	  Reported by: Walter Doekes
+
+2014-02-27  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.8.0-rc2 Released.
+
+	* res_rtp_asterisk: Fix checklist creating problems in ICE sessions
+
+	  Prior to this patch, local candidate lists including SRFLX would
+	  fail to start properly when building ICE candidate check lists. This
+	  patch fixes that problem by making sure that each SRFLX candidate is
+	  associated with the proper base address so that the check list can
+	  create matches properly. This patch was written by jcolp. Note that
+	  the issue will be left open to await testing by the issue
+	  participants.
+
+	  (issue ASTERISK-23213)
+	  Reported by: Andrea Suisani
+	  Review: https://reviewboard.asterisk.org/r/3256
+
+	  revisions 409129,409130 from
+	  https://svn.asterisk.org/svn/asterisk/branches/11
+
+2014-01-14  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.8.0-rc1 Released.
+
+2014-01-14 18:43 +0000 [r405434-405487]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: No BYE message sent after
+	  INVITE with Replaces Setting channel state DOWN is an unnecessary
+	  step that was only being done in handle_invite_replaces(). This
+	  changes that by removing the call and reducing locking. (closes
+	  issue ASTERISK-23010) Reported by: Ryan Tilton Review:
+	  https://reviewboard.asterisk.org/r/3116/ ........ Merged
+	  revisions 405486 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: chan_sip: fix Local From tag on outbound
+	  register regression In ASTERISK-12117, an improvement to insure
+	  consistant local from tags on outbound registrations resulted in
+	  an undesirable behavior - caused by leftover unexpired sip_pvt
+	  dialogs (with the previous cseq number), resulting in many
+	  uncessary REGISTER requests. Instead of significant rework of
+	  transmit_register(), this change deletes the dialogs after a 200
+	  OK response indiciating a successful registration, keeping the
+	  old dialogs from interfering with normal operation. (closes issue
+	  ASTERISK-22946) Reported by: Stephan Eisvogel Review:
+	  https://reviewboard.asterisk.org/r/3109/ ........ Merged
+	  revisions 405433 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-14 17:26 +0000 [r405431]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/asterisk.c, configs/logger.conf.sample, main/cli.c,
+	  include/asterisk/logger.h, main/pbx.c, main/manager.c,
+	  funcs/func_timeout.c, apps/app_dumpchan.c, main/logger.c,
+	  UPGRADE.txt, apps/app_verbose.c: verbosity: Fix performance of
+	  console verbose messages. The per console verbose level feature
+	  as previously implemented caused a large performance penalty. The
+	  fix required some minor incompatibilities if the new rasterisk is
+	  used to connect to an earlier version. If the new rasterisk
+	  connects to an older Asterisk version then the root console
+	  verbose level is always affected by the "core set verbose"
+	  command of the remote console even though it may appear to only
+	  affect the current console. If an older version of rasterisk
+	  connects to the new version then the "core set verbose" command
+	  will have no effect. * Fixed the verbose performance by not
+	  generating a verbose message if nothing is going to use it and
+	  then filtered any generated verbose messages before actually
+	  sending them to the remote consoles. * Split the "core set debug"
+	  and "core set verbose" CLI commands to remove the per module
+	  verbose support that cannot work with the per console verbose
+	  level. * Added a silent option to the "core set verbose" command.
+	  * Fixed "core set debug off" tab completion. * Made "core show
+	  settings" list the current console verbosity in addition to the
+	  root console verbosity. * Changed the default verbose level of
+	  the 'verbose' setting in the logger.conf [logfiles] section. The
+	  default is now to once again follow the current root console
+	  level. As a result, using the AMI Command action with "core set
+	  verbose" could again set the root console verbose level and
+	  affect the verbose level logged. (closes issue AST-1252) Reported
+	  by: Guenther Kelleter Review:
+	  https://reviewboard.asterisk.org/r/3114/
+
+2014-01-14 15:32 +0000 [r405362-405380]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Hangup transferer/transferee when
+	  transfer to Parking fails When performing a SIP transfer to a
+	  Park extension, if the Park fails, chan_sip will currently not
+	  hang up either the transferer or the transfer target. This
+	  results in the channels being orphaned with no thread to service
+	  frames, resulting in stuck channels. This patch immediately hangs
+	  up the two channels if a Park fails. (closes issue
+	  ASTERISK-22834) Reported by: rsw686 Tested by: rsw686 (closes
+	  issue ASTERISK-23047) Reported by: Tommy Thompson Tested by:
+	  Tommy Thomspon Review: https://reviewboard.asterisk.org/r/3107
+
+	* res/Makefile: res/Makefile: alias dist-clean to distclean A 'make
+	  distclean' is equivalent to 'make dist-clean' in the top most
+	  Makefile. This patch updates the res/Makefile to recognize both
+	  distclean and dist-clean. Note that this is needed for removing
+	  build.mak, which can run into problems if the source file of
+	  Asterisk or its path is changed after build.mak is generated.
+	  (issue ASTERISK-22480) Reported by: Matt Jordan
+
+2014-01-10 17:50 +0000 [r405281]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/logger.c: Logging callid: Fix some sizeof() references per
+	  coding guidelines.
+
+2014-01-09 16:49 +0000 [r405234]  Kevin Harwell <kharwell at digium.com>
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Fails to resume WebRTC
+	  call from hold In ast_rtp_ice_start if the ice session create
+	  check list failed, start check was never initiated and
+	  ice_started was never set to true. Upon re-entering the function
+	  (for instance, [un]hold) it would try to create the check list
+	  again with duplicate remote candidates. Fixed so that if the
+	  create check list fails the necessary data structures are
+	  properly re-initialized for any subsequent retries. Note, it was
+	  decided to not stop ice support (by calling ast_rtp_ice_stop) on
+	  a check list failure because it possible things might still work.
+	  However, a debug message was added to help with any future
+	  troubleshooting. (closes issue ASTERISK-22911) Reported by: Vytis
+	  Valentinavičius Patches: works_on_my_machine.patch uploaded by
+	  xytis (license 6558)
+
+2014-01-09 15:41 +0000 [r405215]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/confbridge/conf_state_multi_marked.c, apps/app_confbridge.c:
+	  app_confbridge: Fix crash caused when waitmarked/marked users
+	  leave together When waitmarked users join a ConfBridge, the
+	  conference state is transitioned from EMPTY -> INACTIVE. In this
+	  state, the users are maintined in a waiting users list. When a
+	  marked user joins, the ConfBridge conference transitions from
+	  INACTIVE -> MULTI_MARKED, and all users are put onto the active
+	  list of users. This process works correctly. When the marked user
+	  leaves, if they are the last marked user, the MULTI_MARKED state
+	  does the following: (1) It plays back a message to the bridge
+	  stating that the leader has left the conference. This requires an
+	  unlocking of the bridge. (2) It moves waitmarked users back to
+	  the waiting list (3) It transitions to the appropriate state: in
+	  this case, INACTIVE However, because it plays the prompt back to
+	  the bridge before moving the users and before finishing the state
+	  transition, this creates a race condition: with the bridge
+	  unlocked, waitmarked users who leave the conference (or are
+	  kicked from it) can cause a state transition of the bridge to
+	  another state before the conference is transitioned to the
+	  INACTIVE state. This causes the state machine to get a bit wonky,
+	  often leading to a crash when the MULTI_MARKED state attempts to
+	  conclude its processing. This patch fixes this problem: (1) It
+	  prevents kicked users from being kicked again. That's just a
+	  nicety. (2) More importantly, it fixes the race condition by only
+	  playing the prompt once the state has transitioned correctly to
+	  INACTIVE. If waitmarked users sneak out during the prompt being
+	  played, no harm no foul. Review:
+	  https://reviewboard.asterisk.org/r/3108/ (closes issue AST-1258)
+	  Reported by: Steve Pitts
+
+2014-01-09 14:12 +0000 [r405161]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* apps/app_dumpchan.c, /: "Minimun" typo. ........ Merged revisions
+	  405160 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-08 16:17 +0000 [r405081-405091]  Kinsey Moore <kmoore at digium.com>
+
+	* /, configure, configure.ac, pbx/pbx_lua.c: pbx_lua: Add support
+	  for Lua 5.2 This adds support for Lua 5.2 in pbx_lua which is
+	  available on newer operating systems. (closes issue
+	  ASTERISK-23011) Review: https://reviewboard.asterisk.org/r/3075/
+	  Reported by: George Joseph Patch by: George Joseph ........
+	  Merged revisions 405090 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* UPGRADE.txt, /: UPGRADE: Add a note about non-functionality Add a
+	  note that the "retry on 403 response to REGISTER" for chan_sip is
+	  non-functional in the versions in which it was first introduced.
+	  ........ Merged revisions 405088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: Add the missing part of r400140 When the
+	  patch to add retry-on-forbidden-response was committed, part of
+	  the patch for chan_sip was not committed which caused the feature
+	  to be entirely nonfunctional. This corrects the code in question.
+	  (closes issue ASTERISK-17138) Review:
+	  https://reviewboard.asterisk.org/r/2874 ........ Merged revisions
+	  405033 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-03 22:24 +0000 [r404888]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* main/asterisk.c, /: asterisk.c: suppress live_dangerously warning
+	  on rasterisk Even since the fixes of AST-2013-007, Asterisk
+	  prints the following warning on startup if the user decided to
+	  live dangerously: Privilege escalation protection disabled! See
+	  https://wiki.asterisk.org/wiki/x/1gKfAQ for more details. This
+	  message is intended for the logs and interactive startup. No need
+	  for it to appear on a remote console. This commit removes it from
+	  there. (closes issue ASTERISK-23084) Review:
+	  https://reviewboard.asterisk.org/r/3101/ ........ Merged
+	  revisions 404861 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-03 21:58 +0000 [r404773-404858]  Kevin Harwell <kharwell at digium.com>
+
+	* cel/cel_pgsql.c, /: cel_pgsql: module not correctly reloading
+	  Upon reload the module unconditionally "unloaded" the module
+	  (freeing memory and setting pointers to NULL) and then when
+	  attempting a "load" if the config file had not changed then
+	  nothing would be reinitialized. By moving the "unload" to occur
+	  conditionally (reload only) after an attempted configuration
+	  load, but before module "loading" alleviates the issue. The
+	  module now loads/unloads/reloads correctly. (closes issue
+	  ASTERISK-22871) Reported by: Matteo ........ Merged revisions
+	  404857 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_dahdi.c, /: chan_dahdi: dahdi show channels slices
+	  PRI channel dnid on output dahdi show channels output slices the
+	  callerid (which is dnid copied over on PRI channels). If the
+	  channel naming structures look like: 'DAHDI/i1/1408409XXXX-6'
+	  then the output slices 1408409XXXX down to 1408409XXX. This patch
+	  just opens it up to 15 chars so you can see the whole thing.
+	  (closes issue ASTERISK-22918) Reported by: outtolunc Patches:
+	  svn_chan_dahdi.c.format12_15.diff.txt uploaded by outtolunc
+	  (license 5198) ........ Merged revisions 404784 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, apps/app_meetme.c: app_meetme: compiler warning Fixed a
+	  compiler warning (errors in 'dev-mode') given by gcc version
+	  4.8.1. The one in app_meetme involved the
+	  'sizeof-pointer-memaccess' (see:
+	  http://gcc.gnu.org/gcc-4.8/porting_to.html) warning. Fixed so it
+	  would no longer issue a warning and can compile again in
+	  'dev-mode'. Review: https://reviewboard.asterisk.org/r/3098/
+	  ........ Merged revisions 404742 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2014-01-02 19:35 +0000 [r404675]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, funcs/func_strings.c: func_strings: use memmove to prevent
+	  overlapping memory on strcpy When calling REPLACE() with an empty
+	  replace-char argument, strcpy is used to overwrite the the
+	  matching <find-char>. However as the src and dest arguments to
+	  strcpy must not overlap, it causes other parts of the string to
+	  be overwritten with adjacent characters and the result is
+	  mangled. Patch replaces call to strcpy with memmove and adds a
+	  test suite case for REPLACE. (closes issue ASTERISK-22910)
+	  Reported by: Gareth Palmer Review:
+	  https://reviewboard.asterisk.org/r/3083/ Patches:
+	  func_strings.patch uploaded by Gareth Palmer (license 5169)
+	  ........ Merged revisions 404674 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-31 21:26 +0000 [r404579-404604]  Kevin Harwell <kharwell at digium.com>
+
+	* /, cel/cel_pgsql.c: cel_pgsql: deadlock on unload and
+	  core_event_dispatcher A deadlock can happen between a thread
+	  unloading or reloading the cel_pgsql module and the
+	  core_event_dispatcher taskprocessor thread. Description of what
+	  is happening: Thread 1 (for example, a netconsole thread): a
+	  "module reload cel_pgsql" is launched the thread enter the
+	  "my_unload_module" function (cel_pgsql.c) the thread acquire the
+	  write lock on psql_columns the thread enter the
+	  "ast_event_unsubscribe" function (event.c) the thread try to
+	  acquire the write lock on ast_event_subs[sub->type] Thread 2
+	  (core_event_dispatcher taskprocessor thread): the taskprocessor
+	  pop a CEL event the thread enter the "handle_event" function
+	  (event.c) the thread acquire the read lock on
+	  ast_event_subs[sub->type] the thread callback the "pgsql_log"
+	  function (cel_pgsql.c), since it's a subscriber of CEL events the
+	  thread try to acquire a read lock on psql_columns (closes issue
+	  ASTERISK-22854) Reported by: Etienne Lessard Patches:
+	  cel_pgsql_fix_deadlock_event.patch uploaded by hexanol (license
+	  6394) ........ Merged revisions 404603 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/channel.c: channels.c: core show channeltypes slicing 'core
+	  show channeltypes' type column is being sliced, resulting in
+	  incomplete type names. (closes issue ASTERISK-22919) Reported by:
+	  outtolunc Patches: svn_channel.c.format_15.diff.txt uploaded by
+	  outtolunc (license 5198)
+
+2013-12-20 21:15 +0000 [r404457]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, main/say.c: say.c: correct time for polish In
+	  ast_say_date_with_format_pl(), change ast_say_number() to use
+	  tm_sec instead of tm_mn. (closes issue ASTERISK-22856) Reported
+	  by: Robert Mordec Review:
+	  https://reviewboard.asterisk.org/r/3082/ Patches: say.c.patch
+	  uploaded by veilen (license 6555) ........ Merged revisions
+	  404456 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-19 16:57 +0000 [r404344-404351]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* res/res_fax.c: res_fax.c: crash on framehook with no dsp in fax
+	  detect In fax_detect_framehook() a null pointer reference can
+	  occur where a voice frame is processed but no dsp is attached to
+	  the fax detection structure. The code block that rejects frames
+	  that detection cannot be processed on is checking for dsp but
+	  falls through when it should instead return, as this change
+	  implements. (closes issue ASTERISK-22942) Reported by: adomjan
+	  Review: https://reviewboard.asterisk.org/r/3076/
+
+	* main/db.c: astdb: crash in sqlite3 during shutdown When Asterisk
+	  is shut down, the astdb_atexit() function releases (finalize) the
+	  previously initiated (prepared) SQL statements in sqlite3.
+	  Another thread making a subsequent request can cause a crash in
+	  sqlite3. This patch eliminates that issue by resetting the
+	  statement pointer after it is released/cleared. The sqlite3 code
+	  detects the null pointer, and aborts the operation cleanly.
+	  (closes issue AST-1265) Reported by: Alexander Hömig (closes
+	  issue ASTERISK-22350) Reported by: Birger "WIMPy" Harzenetter
+	  Review: https://reviewboard.asterisk.org/r/3078/
+
+2013-12-19 08:15 +0000 [r404318]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooGkClient.c, addons/chan_ooh323.c,
+	  addons/ooh323c/src/ooGkClient.h, addons/ooh323c/src/oochannels.c:
+	  Handle temporary failures on gk registration Introduce new
+	  'stopped' state for gk client and restart gk client on failures
+	  Remove ooh323 stack command lock as it is not need now. (closes
+	  issue ASTERISK-21960) Reported by: Dmitry Melekhov Patches:
+	  ASTERISK-21960.patch ASTERISK-21960-stacklockup-2.patch Tested
+	  by: Dmitry Melekhov
+
+2013-12-18 22:34 +0000 [r404275]  Jason Parker <jparker at digium.com>
+
+	* main/manager.c: Add AMI event for presence state. Review:
+	  https://reviewboard.asterisk.org/r/3039/
+
+2013-12-18 20:19 +0000 [r404219]  Richard Mudgett <rmudgett at digium.com>
+
+	* addons/ooh323c/src/ooTimer.c, /: ooh323c: Fix gcc 4.6.3 compiler
+	  warnings. ........ Merged revisions 404212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-18 11:59 +0000 [r404136]  Joshua Colp <jcolp at digium.com>
+
+	* /, res/res_calendar.c: res_calendar: Protect channel when adding
+	  datastore. This change adds a missing channel lock when adding a
+	  datastore to a channel. ........ Merged revisions 404135 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-18 00:28 +0000 [r404045-404087]  Rusty Newton <rnewton at digium.com>
+
+	* /, funcs/func_strings.c: func_strings: Documentation fix for
+	  QUOTE() Example output was inaccurate. (issue ASTERISK-22970)
+	  (closes issue ASTERISK-22970) Reported by: Gareth Palmer Patches:
+	  func_strings.patch uploaded by Gareth Palmer (license 5169)
+	  ........ Merged revisions 404081 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/rtp_engine.c, channels/chan_iax2.c, apps/app_chanspy.c,
+	  apps/app_mixmonitor.c, include/asterisk/test.h, main/channel.c:
+	  Several components: fixing Typos in comments and code,
+	  "avaliable" instead of "available" (issue ASTERISK-23021) (closes
+	  issue ASTERISK-23021) Reported by: Jeremy Lainé Tested by: Rusty
+	  Newton Patches: available.patch uploaded by Jeremy Lainé (license
+	  6561)
+
+2013-12-16 17:14 +0000 [r403917]  David M. Lee <dlee at digium.com>
+
+	* funcs/func_realtime.c, main/pbx.c, main/tcptls.c,
+	  funcs/func_db.c, /, README-SERIOUSLY.bestpractices.txt,
+	  configs/asterisk.conf.sample, funcs/func_shell.c,
+	  funcs/func_env.c, funcs/func_lock.c, UPGRADE.txt,
+	  include/asterisk/pbx.h, main/asterisk.c: security: Inhibit
+	  execution of privilege escalating functions This patch allows
+	  individual dialplan functions to be marked as 'dangerous', to
+	  inhibit their execution from external sources. A 'dangerous'
+	  function is one which results in a privilege escalation. For
+	  example, if one were to read the channel variable SHELL(rm -rf /)
+	  Bad Things(TM) could happen; even if the external source has only
+	  read permissions. Execution from external sources may be enabled
+	  by setting 'live_dangerously' to 'yes' in the [options] section
+	  of asterisk.conf. Although doing so is not recommended. (closes
+	  issue ASTERISK-22905) Review:
+	  http://reviewboard.digium.internal/r/432/ ........ Merged
+	  revisions 403913 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-16 15:55 +0000 [r403855-403863]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* main/pbx.c, /: pbx.c: put copy of ast_exten.data on stack to
+	  prevent memory corruption During dialplan execution in
+	  pbx_extension_helper(), the contexts global read lock prevents
+	  link list corruption, but was released with a pointer to the
+	  ast_exten and data later used in variable substitution. Instead,
+	  this patch removes pbx_substitute_variables() and locates a copy
+	  of the ast_exten data on the stack before releasing the lock,
+	  where ast_exten could get free'd by another thread performing a
+	  module reload. (issue AST-1179) Reported by: Thomas Arimont
+	  (issue AST-1246) Reported by: Alexander Hömig Review:
+	  https://reviewboard.asterisk.org/r/3055/ ........ Merged
+	  revisions 403862 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, apps/app_sms.c: app_sms: BufferOverflow when receiving odd
+	  length 16 bit message This patch prevents an infinite loop
+	  overwriting memory when a message is received into the
+	  unpacksms16() function, where the length of the message is an odd
+	  number of bytes. (closes issue ASTERISK-22590) Reported by: Jan
+	  Juergens Tested by: Jan Juergens ........ Merged revisions 403853
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-11 19:14 +0000 [r403635]  Russell Bryant <russell at russellbryant.com>
+
+	* /, channels/chan_sip.c: Reset peer outboundproxy on sip.conf
+	  reload If you set a peer's outboundproxy and then removed it from
+	  the config, this would not get picked up in a config reload. This
+	  patch fixes that by resetting it in set_peer_defaults(). Closes
+	  ASTERISK-19454 Review: https://reviewboard.asterisk.org/r/3065/
+	  ........ Merged revisions 403634 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-09 03:11 +0000 [r403450]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_fax_spandsp.c, /: res_fax_spandsp: Always init T.38
+	  session to avoid crashes during state change Prior to this patch,
+	  res_fax_spandsp was conservative with how it initialized the
+	  spandsp T.38 context. It would only initialize it if the driver
+	  thought the current state was a T.38 fax. While this works fine
+	  in nominal situations, in certain off nominal situations,
+	  res_fax_spandsp can believe that a T.38 fax will not occur when
+	  in fact one has started. In particular, this was discovered when
+	  res_fax would fall back to audio after timing out on a T.38
+	  upgrade. The SIP channel driver would continue to retry the
+	  re-INVITE and - if the remote end responded after res_fax timed
+	  out with a 200 OK - a T.38 frame would be delivered to the
+	  res_fax stack when it no longer expected it. As it turns out,
+	  there does not appear to be any downside to always initializing
+	  the T.38 context, other than the actual memory allocation. Since
+	  that avoids this off nominal situation (and others which are
+	  equally likely hard to predict), this is the safest way to avoid
+	  this problem. Much thanks to Torrey as well for providing a
+	  scenario that reproduces this issue. (closes issue
+	  ASTERISK-21242) Reported by: Ashley Winters Tested by: Torrey
+	  Searle patches: always-init-t38.patch uploaded by awinters
+	  (License 6477) A_PARTY.xml uploaded by tsearle (License 5334)
+	  ........ Merged revisions 403449 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-12-02 17:55 +0000 [r403288]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: Check and reject non-digits e164 values on
+	  peers and general sections in ooh323.conf Regenerate e164
+	  endpoint list on reload ooh323 (issue ASTERISK-22901) Reported
+	  by: Cyril CONSTANTIN Patches: ASTERISK-22901.patch
+
+2013-11-22 17:11 +0000 [r403015]  Joshua Colp <jcolp at digium.com>
+
+	* /, main/translate.c: translate: Move freeing of frame to after it
+	  is used. When translating from one format to another it is
+	  possible to inform the translation function that the source frame
+	  should be freed. This was previously done immediately but shortly
+	  afterwards the frame that was freed was accessed and used again.
+	  This change moves code around a bit so that the frame is now
+	  freed after it has been completely used. (closes issue
+	  ASTERISK-22788) Reported by: Corey Farrell Patches:
+	  translate-access-after-free-11up.patch uploaded by coreyfarrell
+	  (license 5909) translate-access-after-free-1.8.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 403014 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-11-12 15:00 +0000 [r402709]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Fix crash during caller ID
+	  read Asterisk will sometimes core dump during caller id read on
+	  analog channels due to a negative return value from the read() in
+	  my_get_callerid that slips through as a negative length argument
+	  to callerid_feed() if the errno returned by DAHDI is ELAST. This
+	  change ensures that the negative return is treated properly even
+	  when it is ELAST. (closes issue ASTERISK-22746) Reported by:
+	  Michael Walton Patches: chan_dahdi_cid_crash_fix.r401410.patch
+	  uploaded by Michael Walton (License 6502) ........ Merged
+	  revisions 402708 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-11-11 19:26 +0000 [r402686]  Mark Michelson <mmichelson at digium.com>
+
+	* apps/app_confbridge.c: Get rid of some inaccurate comments. I'm
+	  doing some unrelated work in app_confbridge and finding these
+	  "invalid pin" comments to be annoying. Get out!
+
+2013-11-11 15:35 +0000 [r402646]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_queue.c: app_queue: Honor penalty limits of 0 In the
+	  current app_queue code from 1.8 up to trunk the upper and lower
+	  penalties can be set to 0 but the value is interpreted to be
+	  disabled instead of actually setting limits. This is especially
+	  evident if min and max limits are set to 0 and members with
+	  penalties of 0 and 1 are in the queue since the member with
+	  penalty 1 will still receive calls. This patch adjusts the
+	  special disabled value to be INT_MAX instead of 0. (closes issue
+	  ASTERISK-20862) Review: https://reviewboard.asterisk.org/r/2995/
+	  Reported by: Schmooze Com ........ Merged revisions 402645 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-11-08 22:48 +0000 [r402605]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
+	  keep same local (from) tag for outgoing register requests For
+	  outbound register requests the tag on the From line was updated
+	  every 20 seconds prior to a successful registration and also once
+	  for each registration renewal. That behavior can possibly cause
+	  the registration to be denied because of the different tag, and
+	  is not aligned with the intention of RFC 3261 8.1.3.5 "...
+	  request constitutes a new transaction and SHOULD have the same
+	  value of the Call-ID, To, and From of the previous request...".
+	  This updates chan_sip to have a field to keep the local tag in
+	  the registration structure and use that tag for registration
+	  requests where the callid is also unchanged. (closes issue
+	  ASTERISK-12117) Reported by: Pawel Pierscionek Review:
+	  https://reviewboard.asterisk.org/r/2988/ ........ Merged
+	  revisions 402604 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-11-05 15:11 +0000 [r402450-402469]  Kevin Harwell <kharwell at digium.com>
+
+	* /: Recorded merge of revisions 402468 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  chan_sip: notify dialog info ignores presentation indicator in
+	  callerid The presentation indicator in a callerid (e.g. set by
+	  dialplan function Set(CALLERID(name-pres)= ...)) is not checked
+	  when SIP Dialog Info Notifies are generated during extension
+	  monitoring. Added a check to make sure the name and/or number
+	  presentations on the callee (remote identity) are set to allow.
+	  If they are restricted then "anonymous" is used instead. (closes
+	  issue AST-1175) Reported by: Thomas Arimont Review:
+	  https://reviewboard.asterisk.org/r/2976/
+
+	* channels/chan_sip.c: chan_sip: notify dialog info ignores
+	  presentation indicator in callerid The presentation indicator in
+	  a callerid (e.g. set by dialplan function
+	  Set(CALLERID(name-pres)= ...)) is not checked when SIP Dialog
+	  Info Notifies are generated during extension monitoring. Added a
+	  check to make sure the name and/or number presentations on the
+	  callee (remote identity) are set to allow. If they are restricted
+	  then "anonymous" is used instead. (closes issue AST-1175)
+	  Reported by: Thomas Arimont Review:
+	  https://reviewboard.asterisk.org/r/2976/
+
+2013-11-02 02:11 +0000 [r402407-402425]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/conf_state_inactive.c,
+	  apps/confbridge/conf_state_single_marked.c,
+	  apps/confbridge/include/confbridge.h,
+	  apps/confbridge/conf_state_multi.c, apps/app_confbridge.c,
+	  apps/confbridge/conf_state_multi_marked.c,
+	  apps/confbridge/conf_state.c,
+	  apps/confbridge/conf_state_single.c: confbridge: Separate user
+	  muting from system muting overrides. The system overrides the
+	  user muting requests when MOH is playing or a waitmarked user is
+	  waiting for a marked user to join. System muting overrides
+	  interfere with what the user may wish the muting to be when the
+	  system override ends. * User muting requests are now independent
+	  of the system muting overrides. The effective muting is now the
+	  logical or of the user request and system override. * Added a
+	  Muted column to the CLI "confbridge list <conference>" command. *
+	  Added a Muted header to the AMI ConfbridgeList action
+	  ConfbridgeList event. (closes issue AST-1102) Reported by: John
+	  Bigelow Review: https://reviewboard.asterisk.org/r/2960/
+
+	* main/config.c, configs/confbridge.conf.sample: config: Allow
+	  ConfBridge DTMF menus to have '#' as the first digit. ConfBridge
+	  allows custom DTMF menus to be created in the confbridge.conf
+	  file by assigning a DTMF key sequence to a sequence of actions as
+	  follows: DTMF-sequence = action,action... Unfortunately, the
+	  normal config file processing code interprets an initial '#'
+	  character as starting a directive such as #include. * Add the
+	  ability to escape the first non-blank character in a config line
+	  so the '#' character can be used without triggering the directive
+	  processing code. (closes issue AFS-2) (closes issue
+	  ASTERISK-22478) Reported by: Nicolas Tanski Patches:
+	  jira_asterisk_22478_v11.patch (license #5621) patch uploaded by
+	  rmudgett (modified) Review:
+	  https://reviewboard.asterisk.org/r/2969/
+
+2013-11-01 12:31 +0000 [r402345]  Kinsey Moore <kmoore at digium.com>
+
+	* include/asterisk/rtp_engine.h, res/res_rtp_asterisk.c,
+	  channels/chan_sip.c: chan_sip: Fix RTCP port for SRFLX ICE
+	  candidates This corrects one-way audio between Asterisk and
+	  Chrome/jssip as a result of Asterisk inserting the incorrect RTCP
+	  port into RTCP SRFLX ICE candidates. This also exposes an ICE
+	  component enumeration to extract further details from candidates.
+	  (closes issue ASTERISK-21383) Reported by: Shaun Clark Review:
+	  https://reviewboard.asterisk.org/r/2967/
+
+2013-10-31 15:59 +0000 [r402288]  Matthew Jordan <mjordan at digium.com>
+
+	* main/loader.c, /: core/loader: Don't call dlclose in a while loop
+	  For awhile now, we've noticed continuous integration builds
+	  hanging on CentOS 6 64-bit build agents. After resolving a number
+	  of problems with symbols, strange locks, and other shenanigans,
+	  the problem has persisted. In all cases, gdb shows the Asterisk
+	  process stuck in loader.c on one of the infinite while loops that
+	  calls dlclose repeatedly until success. The documentation of
+	  dlclose states that it returns 0 on success; any other value on
+	  error. It does not state that repeatedly calling it will
+	  eventually clear those errors. Most likely, the repeated calls to
+	  dlclose was to force a close by exhausting the references on the
+	  library; however, that will never succeed if: (a) There is some
+	  fundamental error at work in the loaded library that precludes
+	  unloading it (b) Some other loaded module is referencing a symbol
+	  in the currently loaded module This results in Asterisk sitting
+	  forever. Since we have matching pairs of dlopen/dlclose, this
+	  patch opts to only call dlclose once, and log out as an ERROR if
+	  dlclose fails to return success. If nothing else, this might help
+	  to determine why on the CentOS 6 64-bit build agent things are
+	  not closing successfully. Review:
+	  https://reviewboard.asterisk.org/r/2970 ........ Merged revisions
+	  402287 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-29 23:42 +0000 [r402225]  Rusty Newton <rnewton at digium.com>
+
+	* sounds/Makefile, /: Updates for 1.4.25 core sounds and 1.4.14
+	  extra sounds, plus new en_GB language set The new sound packages
+	  relate to issues: ASTERISK-22544, ASTERISK-22411, ASTERISK-21413,
+	  ASTERISK-20782 Modified sounds/Makefile for the new sound
+	  versions and to account for the new en_GB language set. (issue
+	  ASTERISK-22659) (closes issue ASTERISK-22659) (closes issue
+	  ASTERISK-22411) (closes issue ASTERISK-22544) ........ Merged
+	  revisions 402224 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-29 12:49 +0000 [r402151]  Matthew Jordan <mjordan at digium.com>
+
+	* main/xmldoc.c, main/channel.c, main/pbx.c, /, main/translate.c:
+	  Remove some spammy debug messages; improve clarity of others
+	  Debug messages aren't free. Even when the debug level is
+	  sufficiently low such that the messages are never evaluated,
+	  there is a cost to having to parse Asterisk logs that contain
+	  debug messages that (a) fail to convey sufficient information or
+	  (b) occur so frequently as to be next to meaningless. Based on
+	  having to stare at lots of DEBUG messages, this patch makes the
+	  following changes: * channel.c: When copying variables from a
+	  parent channel to a child channel, specify the channels involved.
+	  Do not log anything for a variable that is not inherited; the
+	  fact that it doesn't have an _ or __ already signifies that it
+	  won't be inherited. * pbx.c: Specify what function evaluation has
+	  occurred that created the result. * translate.c: Bump up the
+	  translator path messages to 10. I've never once had to use these
+	  debug messages, and for each format that is registered (on
+	  startup) and unregistered (on shutdown) the entire f^2 matrix is
+	  logged out. For short tests in the Asterisk Test Suite, this
+	  should make finding the actual test much easier. * xmldoc.c: The
+	  debug message that 'blah' is not found in the tree is expected.
+	  Often, description elements - which are not required - are not
+	  provided. This debug message adds no additional value, as it is
+	  not indicative of an error or helpful in debugging which element
+	  did not contain a 'blah' element as a child. If an element is
+	  supposed to contain a child element, then that XML tree should
+	  have failed validation in the first place. Review:
+	  https://reviewboard.asterisk.org/r/2966/ ........ Merged
+	  revisions 402150 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-28 14:50 +0000 [r402111]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c, UPGRADE.txt: chan_sip: Clarify 'Forcerport'
+	  Setting Displayed When Running "sip show peers" While looking at
+	  ASTERISK-22236, Walter Doekes pointed out that when running "sip
+	  show peers", the setting being displayed can be confusing. The
+	  display of "N" used to mean NAT (i.e. yes). The NAT setting has
+	  gone through many different changes resulting in the display of
+	  different characters to try and convey what the current setting
+	  is for 'Forcerport' (A for Auto and Forcerport is currently on, a
+	  for Auto but Forcerport is off, Y for yes, and N for no). During
+	  the initial code review to try and clarify these settings
+	  (especially since "N" no longer meant what it used to mean in
+	  prior versions of Asterisk), Mark Michelson suggested using the
+	  full space available to display the settings which helped to make
+	  the settings very clear. That was a great suggestion. Therefore,
+	  this patch does the following: * The column for 'Forcerport' now
+	  will show: Auto (Yes), Auto (No), Yes, or No. * A column for the
+	  'Comedia' setting has been added. It too will display the setting
+	  in a non-cryptic way: Auto (Yes), Auto (No), Yes, or No. *
+	  UPGRADE.txt has been updated to document this change. (closes
+	  issue ASTERISK-22728) Reported by: Walter Doekes Tested by:
+	  Michael L. Young Patches:
+	  asterisk-forcerport-display-clarification_v3.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2941
+
+2013-12-17  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.7.0 Released.
+
+2013-12-16  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.7.0-rc2 Released.
+
+	* AST-2013-006 - app_sms: BufferOverflow when receiving odd length 16
+	  bit message
+
+	  This patch prevents an infinite loop overwriting memory when a
+	  message is received into the unpacksms16() function, where the length
+	  of the message is an odd number of bytes.
+	  (closes issue ASTERISK-22590)
+
+	* AST-2013-007 - security: Inhibit execution of privilege escalating
+	  functions
+
+	  This patch allows individual dialplan functions to be marked as
+	  'dangerous', to inhibit their execution from external sources.
+
+	  A 'dangerous' function is one which results in a privilege
+	  escalation. For example, if one were to read the channel variable
+	  SHELL(rm -rf /) Bad Things(TM) could happen; even if the external
+	  source has only read permissions.
+
+	  Execution from external sources may be enabled by setting
+	  'live_dangerously' to 'yes' in the [options] section of
+	  asterisk.conf. Although doing so is not recommended.
+
+	  (closes issue ASTERISK-22905)
+
+2013-10-28  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.7.0-rc1 Released.
+
+2013-10-25 23:32 +0000 [r401960-402042]  Scott Griepentrog <sgriepentrog at digium.com>
+
+	* /, include/asterisk/rtp_engine.h, main/rtp_engine.c: rtp_engine:
+	  fix rtp payloads copy and improve argument names In function
+	  ast_rtp_instance_early _bridge_make_compatible the use of
+	  instance 0/1 as arguments doesn't clearly communicate a direction
+	  that the copying of payloads from the source channel to the
+	  destination channel will occur, making it more probable to have
+	  the arguments to ast_rtp_codecs_payloads_copy() put in the
+	  reverse order. This patch renames the arguments with _dst and
+	  _src suffixes and corrects the copy direction. (closes issue
+	  ASTERISK-21464) Reported by: Kevin Stewart Review:
+	  https://reviewboard.asterisk.org/r/2894/ ........ Merged
+	  revisions 402000 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 Test shows
+	  rtpmap:119 being copied per this change, but is not in sip invite
+
+	* include/asterisk/pbx.h, main/pbx.c, /: pbx.c: fix confused match
+	  caller id that deleted exten still in hash This fixes a bug where
+	  a zero length callerid match adjacent to a no match callerid
+	  extension entry would be deleted together, which then resulted in
+	  hashtable references to free'd memory. A third state of the
+	  matchcid value has been added to indicate match to any extension
+	  which allows enforcing comparison of matchcid on/off without
+	  errors. (closes issue AST-1235) Reported by: Guenther Kelleter
+	  Review: https://reviewboard.asterisk.org/r/2930/ ........ Merged
+	  revisions 401959 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-25 17:29 +0000 [r401896-401935]  Jonathan Rose <jrose at digium.com>
+
+	* /, utils/clicompat.c: Put clicompat-r2.patch back in We've
+	  figured out how to resolve the problems this was causing in
+	  12/trunk, so this can go back in now. (issue ASTERISK-22467)
+	  Reported by: Corey Farrell Patches: clicompat-r2.patch uploaded
+	  by coreyfarrell (license 5909) ........ Merged revisions 401914
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* utils/clicompat.c, /: revert clicompat-r2.patch from r401704
+	  Patch caused the following build errors against testsuite
+	  https://bamboo.asterisk.org/bamboo/browse/AST-ATRUNKBUILD4-244
+	  (issue ASTERISK-22467) Reported by: Corey Farrell ........ Merged
+	  revisions 401895 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-25 16:05 +0000 [r401833-401884]  Kevin Harwell <kharwell at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Allow a sip peer to accept both
+	  AVP and AVPF calls Adapts the behaviour of avpf to only impact
+	  the format of outgoing calls. For inbound calls, both AVP and
+	  AVPF calls will be accepted regardless of the value of avpf in
+	  the configuration. (closes issue ASTERISK-22005) Reported by:
+	  Torrey Searle Patches: optional_avpf_trunk.patch uploaded by
+	  tsearle (license 5334)
+
+	* main/logger.c: Logging: Logging types ignored after specifying a
+	  verbose level If one specified a verbose level within a logging
+	  facility in logger.conf then any component after it was ignored.
+	  Fixed so all values are correctly read. (closes issue
+	  ASTERISK-22456) Reported by: Kevin Harwell
+
+2013-10-24 20:33 +0000 [r401620-401830]  Jonathan Rose <jrose at digium.com>
+
+	* /, main/utils.c: utils: Fix memory leaks and missed
+	  unregistration of CLI commands on shutdown Final set of patches
+	  in a series of memory leak/cleanup patches by Corey Farrell
+	  (closes issue ASTERISK-22467) Reported by: Corey Farrell Patches:
+	  main-utils-1.8.patch uploaded by coreyfarrell (license 5909)
+	  main-utils-11.patch uploaded by coreyfarrell (license 5909)
+	  main-utils-12up.patch uploaded by coreyfarrell (license 5909)
+	  ........ Merged revisions 401829 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, tests/test_linkedlists.c: test_linkedlists: Fix memory leak
+	  (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
+	  test_linkedlists-1.8.patch uploaded by coreyfarrell (license
+	  5909) test_linkedlists-11up.patch uploaded by coreyfarrell
+	  (license 5909) ........ Merged revisions 401790 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/jitterbuf.c, /: jitterbuf: Fix memory leak on jitter buffer
+	  reset (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
+	  jitterbuf-jb_reset-leak-1.8.patch
+	  jitterbuf-jb_reset-leak-11up.patch ........ Merged revisions
+	  401786 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/astobj2.c: astobj2: Unregister debug CLI commands at exit
+	  (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
+	  astobj2-clean-debug-cli-1.8-11.patch uploaded by coreyfarrell
+	  (license 5909) astobj2-clean-debug-cli-12up.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 401781 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, apps/app_voicemail.c: app_voicemail: Memory Leaks against
+	  tests (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
+	  app_voicemail-1.8.patch uploaded by coreyfarrell (license 5909)
+	  app_voicemail-11up.patch uploaded by coreyfarrell (license 5909)
+	  ........ Merged revisions 401743 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* utils/clicompat.c, channels/chan_dahdi.c, codecs/ilbc/doCPLC.c,
+	  main/data.c, /, main/app.c, main/asterisk.c: memory leaks: Memory
+	  leak cleanup patch by Corey Farrell (second set) Also covers
+	  ast_app_parse_timelen-fail-zero-length.patch, but the patch was
+	  replaced with one of my own. (issue ASTERISK-22467) Reported by:
+	  Corey Farrell Patches: chan_dahdi-cleanup_push.patch uploaded by
+	  coreyfarrell (license 5909) clicompat-r2.patch uploaded by
+	  coreyfarrell (license 5909) codecs-ilbc-doCPLC.patch uploaded by
+	  coreyfarrell (license 5909) data-cleanup-test-registration.patch
+	  uploaded by coreyfarrell (license 5909)
+	  main-asterisk-kill-listener.patch uploaded by coreyfarrell
+	  (license 5909) ........ Merged revisions 401704 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* tests/test_dlinklists.c, funcs/func_math.c,
+	  channels/sip/reqresp_parser.c, main/test.c,
+	  main/editline/readline.c, /: memory leaks: Memory leak cleanup
+	  patch by Corey Farrell (first set) (issue ASTERSIK-22467)
+	  Reported by: Corey Farrell Patches:
+	  chan_sip-parse_contact_header_test-free-contacts.patch uploaded
+	  by coreyfarrell (license 5909) cli-filename-completion-leak.patch
+	  uploaded by coreyfarrell (license 5909) func_math.patch uploaded
+	  by corefarrell (license 5909) main-test-cleanup.patch uploaded by
+	  coreyfarrell (license 5909) test_dlinklists.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 401660 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_rtp_asterisk.c, /, main/translate.c: res_rtp_asterisk:
+	  Address jittery DTMF events in RTP streams (closes issue
+	  ASTERISK-21170) Reported by: NITESH BANSAL Patches:
+	  dtmf-timestamp.patch uploaded by NITESH BANSAL (license 6418)
+	  Review: https://reviewboard.asterisk.org/r/2938/ ........ Merged
+	  revisions 401619 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-23 16:46 +0000 [r401579]  Richard Mudgett <rmudgett at digium.com>
+
+	* cdr/cdr_adaptive_odbc.c, /: cdr_adaptive_odbc: Also apply a
+	  filter when the CDR value is empty. Extra CDR records are written
+	  if a filtered CDR value is empty because the filter is not
+	  checked. (closes issue ASTERISK-22272) Reported by: Jordi Llull
+	  Chavarria ........ Merged revisions 401577 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-23 15:22 +0000 [r401538]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_mgcp.c, /: chan_mgcp: Properly handle malformed
+	  media lines This corrects a situation in which a media line was
+	  not parsed properly and resulted in a crash. (closes issue
+	  ASTERISK-21190) Reported by: adomjan Patches:
+	  chan_mgcp.c-sscnaf_fix uploaded by adomjan (License 5448)
+	  ........ Merged revisions 401537 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-23 11:11 +0000 [r401498]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: Fix an issue where an incompatible audio
+	  format may be added to SDP. If preferred codecs included any
+	  non-audio format the code would mistakenly add the audio format,
+	  even if it was not a joint capability with the remote side.
+	  (closes issue ASTERISK-21131) Reported by: nbougues Patches:
+	  patch_unsupported_codec_1.8.patch uploaded by nbougues (license
+	  6470) ........ Merged revisions 401497 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-22 22:42 +0000 [r401446]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix crash when RTCP
+	  is not available during SSRC change In r400089, a patch was put
+	  in to correct erroneous RTCP statistic resets. Unfortunately,
+	  ast_rtp_read can be called on an RTP instance that does not have
+	  RTCP information. This patch prevents that crash by only
+	  resetting the statistics if we do actually have an RTCP instance.
+	  (issue AST-1174) (closes issue ASTERISK-22667) Reported by: John
+	  Bigelow ........ Merged revisions 401445 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-22 19:02 +0000 [r401379-401433]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_queue.c: app_queue: Fix CLI "queue remove member"
+	  queue_log entry. The queue_log entry resulting from CLI "queue
+	  remove member" when log_membername_as_agent is enabled is wrong.
+	  It always uses the interface name instead of the member name in
+	  the queue_log entry. * Get the queue member before removing it
+	  from the queue so the member name is available for the queue_log
+	  entry. (closes issue ASTERISK-21826) Reported by: Oscar Esteve
+	  Patches: fix_membername.diff (license #6505) patch uploaded by
+	  Oscar Esteve (modified to fix potential ref leak)
+
+	* channels/sig_analog.c, /: chan_dahdi: Fix unable to get index
+	  warning when transferring an analog call. Transferring an analog
+	  call using flashhooks generated an unable to get index WARNING
+	  message when the transfer is completed. * Removed unnecessary
+	  analog subchannel shell games when transferring a call using
+	  flashhooks. Thanks to Tzafrir Cohen for mentioning this in a
+	  comment on issue ASTERISK-22720. ........ Merged revisions 401378
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-21 19:46 +0000 [r401326]  Kevin Harwell <kharwell at digium.com>
+
+	* main/editline/term.c, /: Segfault in LIBEDIT_INTERNAL after
+	  tgetstr(), when libncurses5-dev isn't installed Include the
+	  appropriate declarations when not using termcap, but term+curses
+	  and [n]curses do not exist. (closes issue ASTERISK-22351)
+	  Reported by: A. Iglesias Patches:
+	  issueA22351_libedit_internal_without_ncurses_dev.patch uploaded
+	  by wdoekes (license 5674) ........ Merged revisions 401325 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-18 15:11 +0000 [r401182]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c: Remove Port Restriction When Checking For
+	  NAT When trying to determine if a peer is behind NAT, we should
+	  not be using the ports when comparing addresses. This patch
+	  removes the port from being checked and just useds the addresses
+	  now. (closes issue ASTERISK-22729) Reported by: Michael L. Young
+	  Tested by: Michael L. Young Patches:
+	  asterisk-remove-using-port-for-nat-check.diff uploaded by Michael
+	  L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2927/
+
+2013-10-18 14:43 +0000 [r401179]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* main/channel.c, /: Properly copy/remove the device state cache
+	  flag over a masquerade. In r378303 the
+	  AST_FLAG_DISABLE_DEVSTATE_CACHE flag was added that tells the
+	  devstate system to not cache states for non-real devices.
+	  However, when optimizing away channels (ast_do_masquerade), that
+	  flag wasn't copied. In my case, using Local devices as queue
+	  members created a situation where the endpoint was considered in
+	  use, but the state change of the device being available again was
+	  ignored (not cached). The endpoint channel was optimized into the
+	  (previously) Local channel, but kept the do-not-cache flag. The
+	  end result being that the queue member apparently stayed in use
+	  forever. (closes issue ASTERISK-22718) Reported by: Walter Doekes
+	  Review: https://reviewboard.asterisk.org/r/2925/ ........ Merged
+	  revisions 401178 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-17 20:32 +0000 [r401167]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c: Fix Setting A chan_sip Dialog's
+	  SIP_NAT_FORCE_RPORT Flag A condition was added in a commit to fix
+	  ASTERISK-21374, that, if the SIP_PAGE3_NAT_AUTO_RPORT flag was
+	  set, to then copy a peer's SIP_NAT_FORCE_RPORT flag to the
+	  dialog. This condition should not have been there since it
+	  assumed that if Asterisk is in an environment where NAT is
+	  involved, that the auto_* nat settings or force_rport setting
+	  would be on in the global settings. If the nat setting in the
+	  global setting is set to 'nat=no' and then turned on for peers
+	  (which is not quite the recommended way, although it is allowed)
+	  this flag is never copied to the dialog resulting in problems
+	  like, REGISTER replies going to the wrong port. This patch
+	  removes this conditional check and will now always use the peer's
+	  flag which by this point in the code the checks on whether the
+	  peer is behind NAT or not (if using auto_force_rport) have
+	  already been run. (closes issue ASTERISK-22236) Reported by:
+	  Filip Frank Tested by: Michael L. Young Patches:
+	  asterisk-2236-always-set-rport.diff uploaded by Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2919/
+
+2013-10-17 15:36 +0000 [r401120]  Kinsey Moore <kmoore at digium.com>
+
+	* /, res/res_xmpp.c, res/res_jabber.c: Reduce log level of a
+	  non-pubsub error message Drop an error log message to debug level
+	  1 since distributed device state functions correctly when
+	  receiving this message and it spams the logs. (closes issue
+	  ASTERISK-22410) Reported by: abelbeck Patches:
+	  asterisk-1.8-res_jabber-log-nonpubsub-error-to-debug.patch
+	  uploaded by abelbeck (License 5903)
+	  asterisk-11-res_xmpp-log-nonpubsub-error-to-debug.patch uploaded
+	  by abelbeck (License 5903) ........ Merged revisions 401119 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-16 11:52 +0000 [r401076]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* apps/app_queue.c, /: Don't check all realtime queues when doing
+	  "queue show some_queue". When using realtime queues, queues have
+	  to be fetched from the database every now and then to see if any
+	  info has been changed or to see if the queue has been removed.
+	  When fetching info for an individual queue, the pruning of other
+	  queues is unnecessarily costly. Review:
+	  https://reviewboard.asterisk.org/r/2907/ ........ Merged
+	  revisions 401049 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-15 19:57 +0000 [r401016]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_iax2.c: chan_iax2: Fix channel left locked in off
+	  nominal code path.
+
+2013-10-15 14:58 +0000 [r400971]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Prevent chan_sip from sending duplicate
+	  BYEs. When a 200 OK for an initial INVITE is received, we were
+	  doing the right thing by ACKing and sending an immediate BYE.
+	  However, we also were doing the wrong thing and queuing an answer
+	  frame, thus causing the call to be answered. This would cause the
+	  call to be hung up by the channel thread, thus resulting in a
+	  second BYE being sent out. In this fix, I also have set the
+	  hangupcause to be correct since the initial BYE being sent by
+	  Asterisk had an unknown hangup cause. I have changed to using
+	  "Bearer capabilty not available" since the call was hung up due
+	  to an SDP offer/answer error. (closes issue ASTERISK-22621)
+	  reported by Kinsey Moore ........ Merged revisions 400970 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-14 21:44 +0000 [r400909]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Reflect the set software
+	  gain in the CLI "dahdi show channel" output. * Remember the
+	  swgain setting from CLI "dahdi set swgain" command so the CLI
+	  "dahdi show channel" output will reflect the current setting. *
+	  Updated CLI "dahdi set hwgain" and "dahdi set swgain"
+	  documentation. (issue ASTERISK-22429) Reported by: Jaco Kroon
+	  Patches: jira_asterisk_22429_v1.8_v2.patch (license #5621) patch
+	  uploaded by rmudgett ........ Merged revisions 400907 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-14 21:42 +0000 [r400908]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Do not increment the SDP version between
+	  183 and 200 responses. Bumping the SDP version number can cause
+	  interoperability problems since receivers of the responses will
+	  expect that a 200 SDP will be identical to a previous 183 SDP.
+	  (closes issue ASTERISK-21204) reported by NITESH BANSAL Patches:
+	  dont-increment-session-version-in-2xx-after-183.patch uploaded by
+	  NITESH BANSAL (License #6418) ........ Merged revisions 400906
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-08 22:27 +0000 [r400768]  Kinsey Moore <kmoore at digium.com>
+
+	* /, configure, configure.ac: Add warning when compiling with iODBC
+	  support When running configure, libiodbc2 development headers
+	  will fulfill the requirement for ODBC development headers, but
+	  will not function properly. This adds a warning when libiodbc2
+	  development headers are detected instead of unixodbc development
+	  headers. (closes issue ASTERISK-22459) Reported by: Patrick
+	  Maille Tested by: Walter Doekes Patches:
+	  issueA22459_warn_when_using_iodbc.patch uploaded by Walter Doekes
+	  (License 5674) ........ Merged revisions 400767 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-08 20:14 +0000 [r400723-400741]  Richard Mudgett <rmudgett at digium.com>
+
+	* UPGRADE.txt, apps/app_confbridge.c,
+	  apps/confbridge/conf_config_parser.c,
+	  configs/confbridge.conf.sample,
+	  apps/confbridge/include/confbridge.h: app_confbridge: Can now set
+	  the language used for announcements to the conference. ConfBridge
+	  now has the ability to set the language of announcements to the
+	  conference. The language can be set on a bridge profile in
+	  confbridge.conf or by the dialplan function
+	  CONFBRIDGE(bridge,language)=en. (closes issue ASTERISK-19983)
+	  Reported by: Jonathan White Patches: M19983_rev2.diff (license
+	  #5138) patch uploaded by junky (modified) Tested by: rmudgett
+
+	* apps/confbridge/conf_config_parser.c: app_confbridge: Fix
+	  duplicate default_user profile. * Fixed looking in the wrong
+	  profiles container to see if the default_user profile is already
+	  created in verify_default_profiles(). The bridge profile
+	  container is never going to hold user profiles. :)
+
+2013-10-08 18:18 +0000 [r400681-400697]  Kinsey Moore <kmoore at digium.com>
+
+	* funcs/func_config.c, /: Fix func_config list entry allocation The
+	  AST_CONFIG dialplan function defined in func_config.c allocates
+	  its config file list entries using ast_malloc. List entry
+	  allocations destined for use with Asterisk's linked list API must
+	  be ast_calloc()d or otherwise initialized so that list pointers
+	  are set to NULL. These uses of ast_malloc have been replaced by
+	  ast_calloc to prevent dereferencing of uninitialized pointer
+	  values when traversing the list. (closes issue ASTERISK-22483)
+	  Reported by: Brian Scott ........ Merged revisions 400694 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_rtp_asterisk.c: Fix STUN crash when using IPv6 any
+	  address Ensure that when chan_sip binds to the IPv6 any address
+	  ([::]), IPv4 candidates are also added. (closes issue
+	  ASTERISK-21917) Reported by: Torrey Searle Patches:
+	  0023_ipv6_stun_crash.patch uploaded by Torrey Searle (License
+	  5334)
+
+2013-10-06 17:09 +0000 [r400623]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* apps/app_queue.c, /: Fix Regression With Queuelog EXITWITHKEY
+	  Only Logging Two Out Of Four Fields Commit r62462 added two extra
+	  fields for logging "the original position the caller entered the
+	  queue at, and the amount of time the caller was waiting in the
+	  queue." But when r75969 was merged from 1.4 into trunk (r75977),
+	  these two fields disappeared. Those two extra fields were not
+	  logged in 1.4 and when the patch was merged, those fields went
+	  away. Therefore, this is a regression and was caught by the
+	  reporter because he was reading the awesome "Asterisk: The
+	  Definitive Guide" book. (closes issue ASTERISK-22197) Reported
+	  by: Dalius M. Tested by: Dalius M. Patches:
+	  asterisk-22197-q-log-exitwithkey.diff uploaded by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2901/ ........ Merged
+	  revisions 400622 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-03 22:59 +0000 [r400470]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Don't ignore expires value in
+	  contact header if it lacks semicolon (closes issue
+	  ASTERISK-22574) Reported by: Filip Jenicek Patches:
+	  chan_sip_expires.patch uploaded by Filip Jenicek (license 6277)
+	  ........ Merged revisions 400469 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-03 19:22 +0000 [r400394-400421]  Kinsey Moore <kmoore at digium.com>
+
+	* main/security_events.c: Fix security events for AMI invalid
+	  password In r337595, additional security events were added for
+	  chan_sip authentication failures. The new IEs added to the
+	  existing invalid password event were defined as required IEs, but
+	  existing users of the event did not set the new IEs and could not
+	  since they didn't apply to existing uses. They are now marked as
+	  optional IEs. (closes issue ASTERISK-22578) Reported by: Matt
+	  Jordan
+
+	* res/res_rtp_multicast.c, /: Ensure res_rtp_mutlicast sets SSRC
+	  properly This fixes a bug where the SSRC field on multicast RTP
+	  can be stuck at 0 which can cause problems for endpoints trying
+	  to make sense of incoming streams. (closes issue ASTERISK-22567)
+	  Reported by: Simone Camporeale Patches:
+	  22567_res_mulitcast_ssrc.patch uploaded by Simone Camporeale
+	  (License 6536) ........ Merged revisions 400393 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-02 21:31 +0000 [r400315]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_iax2.c: Cast Integer Argument To Unsigned Char
+	  The member reg in the peercnt structure is an unsigned char and
+	  peercnt_modify() is expecting an unsigned char argument which
+	  gets assigned to peercnt->reg. This patch fixes that by casting
+	  the integer argument being passed to peercnt_modify to unsigned
+	  char. ........ Merged revisions 400314 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-02 17:36 +0000 [r400279]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* Makefile, doc/astdb2sqlite3.8 (added), doc/astdb2bdb.8 (added):
+	  man pages for astdb2bdb and astdb2sqlite3 Review:
+	  https://reviewboard.asterisk.org/r/2898/
+
+2013-09-30 15:26 +0000 [r400140]  Kinsey Moore <kmoore at digium.com>
+
+	* UPGRADE.txt, configs/sip.conf.sample, /, channels/chan_sip.c:
+	  Allow Asterisk to retry after 403 on register This adds a global
+	  option in chan_sip to allow it to continue attempting
+	  registration if a 403 is received, clearing the cached nonce and
+	  treating it as a non-fatal response. Normally, this would cause
+	  registration attempts to that endpoint to stop. (closes issue
+	  ASTERISK-17138) Review: https://reviewboard.asterisk.org/r/2874/
+	  Reported by: Rudi ........ Merged revisions 400137 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-28 22:21 +0000 [r400075-400093]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Correct erroneous
+	  lost packet information in RTCP reports RTCP's calculation of the
+	  number of lost packets in an RTP stream is based on that stream's
+	  sequence number count, the number of received packets, and how
+	  many packets we expect to receive. When the SSRC for an RTP
+	  stream changes, there can - and almost always will be - a large
+	  jump in the next packet's timestamp and sequence number. If we
+	  don't reset the number of received packets, sequence number
+	  count, and other metrics used by RTCP, the next RR/SR report will
+	  use the previous SSRC's values to calculate the lost packet count
+	  for the new SSRC - resulting in a very large number of lost
+	  packets. This patch modifies res_rtp_asterisk such that, if it
+	  detects a SSRC change, it will reset the various values used by
+	  the RTCP calculations. From the perspective of RTCP, this appears
+	  as a new media stream - which is what it is. Review:
+	  https://reviewboard.asterisk.org/r/2886/ (closes issue AST-1174)
+	  Reported by: Thomas Arimont ........ Merged revisions 400089 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, configure, configure.ac: Add check for openSUSE when detecting
+	  bfd library In ASTERISK-17842, some additional library checks
+	  were added to the configure script so that the bfd library could
+	  be found on CentOS and Fedora systems. As it turns out, openSUSE
+	  requires an additional library. This patch adds another check to
+	  the configure script for openSUSE that will add that library.
+	  Review: https://reviewboard.asterisk.org/r/2885/ (closes issue
+	  AST-1169) Reported by: Guenther Kelleter ........ Merged
+	  revisions 400073 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-27 21:35 +0000 [r400014]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/reqresp_parser.c: chan_sip:
+	  Increase some scratch buffer sizes dealing with caller id. *
+	  Eliminated an unnecessary initialization in check_user_full().
+	  (closes issue ASTERISK-22477) Reported by: Michael Shepelev
+	  ........ Merged revisions 400013 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-27 17:24 +0000 [r399962]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: chan_sip:
+	  Reject calls on 200 OKs if no SDP has been received When Asterisk
+	  receives a 200 OK in response to an invite, that peer should have
+	  sent an SDP at some point by then. If the channel has never
+	  received an SDP, media won't have been set and the remote address
+	  won't be known. Endpoints in general should not be doing this.
+	  This patch makes it so that Asterisk will simply hang up a call
+	  if it sends a 200 OK at this point. So far this odd behavior for
+	  endpoints has only been observed in tests which involved manually
+	  created SIP transactions in SIPp. (closes issue ASTERISK-22424)
+	  Reported by: Jonathan Rose Review:
+	  https://reviewboard.asterisk.org/r/2827/ ........ Merged
+	  revisions 399939 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-25 20:28 +0000 [r399834]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_ss7.c, channels/chan_dahdi.c, /: chan_dahdi: CLI
+	  "core stop gracefully" has needless delay for PRI and SS7. The
+	  PRI and SS7 link control threads are not stopped correctly when
+	  the chan_dahdi.so module is unloaded. The link control threads
+	  pri_dchannel() and ss7_linkset() are not awakened from a poll()
+	  to cancel the thread. * Added a SIGURG signal after requesting
+	  the thread cancel to break the link control thread poll()
+	  immediately. For SS7 it was slightly worse, the link poll()
+	  timeout would always be whatever was the last libss7 scheduled
+	  event time used. If no libss7 scheduled event was pending, the
+	  thread could run more often than necessary. * Set nextms to 60
+	  seconds for the ss7_linkset() poll() if there is no other libss7
+	  scheduled event. ........ Merged revisions 399818 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-25 19:27 +0000 [r399795]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix Realtime Peer Update Problem When
+	  Un-registering And Expires Header In 200ok 1st Issue When a
+	  realtime peer sends an un-REGISTER request, Asterisk un-registers
+	  the peer but the database table record still has regseconds and
+	  fullcontact for the peer. This results in calls attempting to be
+	  routed to the peer which is no longer registered. The expected
+	  behavior is to get busy/congested when attempting to call an
+	  un-registered peer through the dialplan. What was discovered is
+	  that we are clearing out the peer's registration in the database
+	  in parse_register_contact() when calling expire_register() but
+	  then upon returning from parse_register_contact(), update_peer()
+	  is run which stores back in the database table regseconds and
+	  fullcontact. 2nd Issue The reporter pointed out that the 200 ok
+	  being returned by Asterisk after un-registering a peer contains a
+	  Contact header with ;expires= and the Expires header is not set
+	  to 0. This is actually a regression. Tests were created for this
+	  second issue (ASTERISK-22548). The tests have been reviewed and a
+	  Ship It! was received on those tests. This patch does the
+	  following: * Do not ignore the Expires header value even when it
+	  is set to 0. The patch sets the pvt->expiry earlier on in the
+	  function so that it is set properly and used. * If pvt->expiry is
+	  0, do not call update_peer since that means the peer has already
+	  been un-registered and there is no need to update the database
+	  record again since nothing has changed. (closes issue
+	  ASTERISK-22428) Reported by: Ben Smithurst Tested by: Ben
+	  Smithurst, Michael L. Young Patches:
+	  asterisk-22428-rt-peer-update-and-expires-header.diff by Michael
+	  L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2869/ ........ Merged
+	  revisions 399794 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-24 20:20 +0000 [r399708]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_iax2.c: chan_iax2: Prevent some needless
+	  breaking of the native IAX2 bridge. * Clean up some twisted code
+	  in the iax2_bridge() loop. * Add AST_CONTROL_VIDUPDATE and
+	  AST_CONTROL_SRCCHANGE to a list of frames to prevent the native
+	  bridge loop from breaking. * Passing the
+	  AST_CONTROL_T38_PARAMETERS frame should also allow FAX over a
+	  native IAX2 bridge. (issue ABE-2912) Review:
+	  https://reviewboard.asterisk.org/r/2870/ ........ Merged
+	  revisions 399697 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-20 22:35 +0000 [r399564]  Kinsey Moore <kmoore at digium.com>
+
+	* main/config_options.c: Ensure global types in the config
+	  framework are initialized If a config object was allocated but
+	  one of its global objects was never encountered, then the global
+	  object's defaults were never applied. Ensure that global objects
+	  are initialized properly upon allocation instead of on
+	  configuration. Review: https://reviewboard.asterisk.org/r/2866/
+
+2013-09-20 14:23 +0000 [r399513]  Kevin Harwell <kharwell at digium.com>
+
+	* main/logger.c: Fix memory leak in logger. Fixed a memory leak
+	  discovered in the logger where a temporary string buffer was not
+	  being freed. (closes issue ASTERISK-22540) Reported by: John
+	  Hardin
+
+2013-09-19 16:45 +0000 [r399457]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Make direct media reinvites for
+	  T38 put Asterisk in the media path Prior to this patch, Asterisk
+	  would incorrectly use the previous endpoint addresses in SDP in
+	  spite of providing its own port. T38 is never meant to be done
+	  through directmedia and Asterisk should always be in the media
+	  path for these streams. (closes issue ASTERISK-17273) Reported
+	  by: Kevin Stewart (closes issue ASTERISK-18706) Reported by:
+	  Jeremy Kister Review: https://reviewboard.asterisk.org/r/2853/
+	  ........ Merged revisions 399456 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-10-21  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.6.0 Released.
+
+2013-10-18  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.6.0-rc2 Released.
+
+	* Remove Port Restriction When Checking For NAT
+
+	  When trying to determine if a peer is behind NAT, we should not be
+	  using the ports when comparing addresses.
+	  
+	  This patch removes the port from being checked and just useds the
+	  addresses now.
+
+	* Properly copy/remove the device state cache flag over a masquerade.
+
+	  In r378303 the AST_FLAG_DISABLE_DEVSTATE_CACHE flag was added that
+	  tells	the devstate system to not cache states for non-real devices.
+	  However, when optimizing away channels (ast_do_masquerade), that\
+	  flag wasn't copied.
+
+	  In my case, using Local devices as queue members created a situation
+	  where the endpoint was considered in use, but the state change of the
+	  device being available again was ignored (not cached). The endpoint
+	  channel was optimized into the (previously) Local channel, but kept
+	  the do-not-cache flag. The end result being that the queue member
+	  apparently stayed in use forever.
+
+	* Fix Setting A chan_sip Dialog's SIP_NAT_FORCE_RPORT Flag
+
+	  A condition was added in a commit to fix ASTERISK-21374, that, if the
+	  SIP_PAGE3_NAT_AUTO_RPORT flag was set, to then copy a peer's
+	  SIP_NAT_FORCE_RPORT flag to the dialog.  This condition should not
+	  have been there since	it assumed that if Asterisk is in an
+	  environment where NAT is involved, that the auto_* nat settings or
+	  force_rport setting would be on in the global settings. If the nat
+	  setting in the global setting is set to 'nat=no' and then turned on
+	  for peers (which is not quite the recommended way, although it is
+	  allowed) this flag is never copied to the dialog resulting in
+	  problems like, REGISTER replies going to the wrong port.
+
+	  This patch removes this conditional check and will now always use the
+	  peer's flag which by this point in the code the checks on whether the
+	  peer is behind NAT or not (if using auto_force_rport) have already
+	  been run.
+
+	* Fix memory leak in logger
+
+	  Fixed a memory leak discovered in the logger where a temporary string
+	  buffer was not being freed.
+
+2013-09-19  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.6.0-rc1 Released.
+
+2013-09-18 23:36 +0000 [r399442]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/udptl.c: UDPTL: Backport some fixes from v12 that should be
+	  in v11. Backported the following as applied to udptl.c: *
+	  -r398020 Fixup udpdl defaults if config file not present. *
+	  -r398533 Fixup improper use of ao2_global_obj_replace().
+
+2013-09-18 19:55 +0000 [r399403]  Kinsey Moore <kmoore at digium.com>
+
+	* main/abstract_jb.c, /: Fix jitter buffer log file creation This
+	  adjusts '/'-to-'#' replacement to replace all instances of '/'
+	  instead of just the first to ensure that the jitter buffer log
+	  file gets the correct name as per Richard Kenner's suggestion.
+	  (closes issue ASTERISK-21036) Reported by: Richard Kenner
+	  ........ Merged revisions 399402 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-18 17:22 +0000 [r399353-399373]  Matthew Jordan <mjordan at digium.com>
+
+	* /, build_tools/prep_tarball: Update prep_tarball with new
+	  documentation files on the Asterisk wiki This will now pull both
+	  a command reference for the version being prepared, as well as an
+	  Admin Guide that applies to all versions of Asterisk. (issue
+	  ASTERISK-22439) Reported by: Olle Johansson ........ Merged
+	  revisions 399351 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* bridges/bridge_softmix.c: Add a WARNING in bridge_softmix when a
+	  timing module isn't loaded If bridge_softmix fails to be created
+	  because no timing source is present in Asterisk, this will
+	  currently fail gracefully but with (most likely) a generic error
+	  message by whatever module tried to create the softmix bridge.
+	  This patch adds a more explicit warning so you can actually
+	  diagnose and fix the problem. Review:
+	  https://reviewboard.asterisk.org/r/2857/
+
+2013-09-18 01:34 +0000 [r399305]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, main/features.c: Fix Segfault When Syntax Of A Line Under
+	  [applicationmap] Is Invalid When processing the lines under the
+	  [applicationmap] context in features.conf, a segfault occurs from
+	  attempting to process a line with an invalid syntax (basically
+	  missing most of the arguments). Example: [applicationmap]
+	  automon=*6 * This patch moves the checking for empty arguments to
+	  before they are accessed. * Also, checked the "todo" comment and
+	  removed it. Some applications do not require arguments. (closes
+	  issue ASTERISK-22416) Reported by: CGI.NET Tested by: CGI.NET
+	  Patches: asterisk-22416-check-syntax-first_v2.diff by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2803 ........ Merged revisions
+	  399304 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-17 18:32 +0000 [r399222-399267]  Kevin Harwell <kharwell at digium.com>
+
+	* main/asterisk.c, main/logger.c: Remote console: more output
+	  discrepancies The remote console continued to have issues with
+	  its output. In this case CLI command output would either not show
+	  up (if verbose level = 0) or would contain verbose prefixes (if
+	  verbose level > 0) once log messages were sent to the remote
+	  console. The fix now now adds verbose prefix data to all new
+	  lines contained in a verbose log string. (closes issue
+	  ASTERISK-22450) Reported by: David Brillert (closes issue
+	  AST-1193) Reported by: Guenther Kelleter Review:
+	  https://reviewboard.asterisk.org/r/2825/
+
+	* apps/confbridge/conf_state_multi_marked.c: Confbridge: empty
+	  conference not being torn down Confbridge would not properly tear
+	  down an empty conference bridge when all users were kicked via
+	  end_marked=yes and at least one user was also set to wait_marked.
+	  This occurred because while end_marked users were being kicked
+	  and at least one was also set to wait_marked then the leave
+	  wait_marked handler would be called on that user, but there would
+	  be no waiting user (still considered active). The waiting users
+	  would decrement and now be negative. The conference would remain,
+	  but be put into an inactive state. The solution was to move from
+	  the active list to the wait list, those users with wait_marked
+	  set right before kicking. This allows both the active and wait
+	  users to decrement correctly and the confbridge to tear down
+	  properly. A crashed also occurred when trying to list the
+	  specific conference from the CLI. This happened because the
+	  conference specified was invalid. Since the conference properly
+	  tears down now there is no way to reference it thus alleviating
+	  the crash as well. (closes issue ASTERISK-21859) Reported by:
+	  Chris Gentle Review: https://reviewboard.asterisk.org/r/2848/
+
+2013-09-16 16:42 +0000 [r399159]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_iax2.c, /: chan_iax2: Fix saving the wrong expiry
+	  time in astdb. When a new IAX2 client registers, the astdb
+	  database is updated with the value of minregexpire defined in
+	  iax.conf instead of using the expiry time that is provided by the
+	  client. The provided expiry time of the client is updated after
+	  inserting the astdb entry. As a consequence, restarting or
+	  reloading asterisk creates clients whose registration may expire
+	  before they reregister. The clients are therefore unavailable
+	  after minregexpire seconds until they reregister. * Move updating
+	  of the expiry time to before inserting into the astdb. (closes
+	  issue ASTERISK-22504) Reported by: Stefan Wachtler Patches:
+	  chan_iax2.c.patch (license #6533) patch uploaded by Stefan
+	  Wachtler ........ Merged revisions 399158 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-13 20:49 +0000 [r399099]  David M. Lee <dlee at digium.com>
+
+	* main/astobj2.c, /: Don't write to /tmp/refs when REF_DEBUG is not
+	  defined. If MALLOC_DEBUG is enabled, then the debug destructor
+	  for the container is used, which would erroneously write to
+	  /tmp/refs. This patch only uses the debug destructor if ref_debug
+	  is used. (closes issue ASTERISK-22536) ........ Merged revisions
+	  399098 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-13 13:48 +0000 [r399034]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_meetme.c: Fix several crashes in MeetMeAdmin This
+	  change ensures that MeetMeAdmin commands requiring a user
+	  actually get a user and fixes another issue where an extra
+	  dereference could occur for a last-entered user being ejected if
+	  a user identifier was also provided. (closes issue
+	  ASTERISK-21907) Reported by: Alex Epshteyn Review:
+	  https://reviewboard.asterisk.org/r/2844/ ........ Merged
+	  revisions 399033 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-12 20:19 +0000 [r398986]  Jonathan Rose <jrose at digium.com>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
+	  Revert r398835 due to failing tests involving originate (issue
+	  ASTERISK-22424) Reported by: Jonathan Rose ........ Merged
+	  revisions 398977 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-12 00:02 +0000 [r398881-398885]  Rusty Newton <rnewton at digium.com>
+
+	* /, apps/app_queue.c: 'queue add member' help text correction You
+	  are adding dial strings to the queue, not channels. An aribitrary
+	  string could be used, but you are typically referencing a
+	  channel. Correcting the command help text. (issue ASTERISK-22263)
+	  (closes issue ASTERISK-22263) Reported By: Rusty Newton ........
+	  Merged revisions 398884 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* configs/chan_dahdi.conf.sample, /: Documentation fix -
+	  waitfordialtone is not boolean, it's time in milliseconds
+	  Changing text in chan_dahdi.conf sample to be accurate. (issue
+	  ASTERISK-22308) (closes issue ASTERISK-22308) Reported By:
+	  Malcolm Davenport ........ Merged revisions 398880 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-11 19:46 +0000 [r398836]  Jonathan Rose <jrose at digium.com>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
+	  Reject calls without prior SDP on 200 OK If we receive a 200 OK
+	  without SDP, we will now check to see if the remote address has
+	  been established for that channel's RTP session and if the to tag
+	  for that channel has changed from the most recent to tag in a
+	  response less than 200. If either a change has been made since
+	  the last to-tag was received or the remote address is unset, then
+	  we will drop the call. (closes issue ASTERISK-22424) Reported by:
+	  Jonathan Rose Review:
+	  https://reviewboard.asterisk.org/r/2827/diff/#index_header
+	  ........ Merged revisions 398835 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-11 18:01 +0000 [r398820]  Russell Bryant <russell at russellbryant.com>
+
+	* configs/confbridge.conf.sample: Fix typo in
+	  confbridge.conf.sample The denoise filter requires func_speex,
+	  not codec_speex. Fix this in the description of the denoise=yes
+	  option in confbridge.conf.
+
+2013-09-10 17:56 +0000 [r398758]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/event.c, res/res_musiconhold.c, main/indications.c,
+	  main/asterisk.c, main/xmldoc.c, main/cli.c, /,
+	  funcs/func_dialgroup.c, main/heap.c: Fix incorrect usages of
+	  ast_realloc(). There are several locations in the code base where
+	  this is done: buf = ast_realloc(buf, new_size); This is going to
+	  leak the original buf contents if the realloc fails. Review:
+	  https://reviewboard.asterisk.org/r/2832/ ........ Merged
+	  revisions 398757 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-10 17:48 +0000 [r398749-398753]  David M. Lee <dlee at digium.com>
+
+	* utils/check_expr.c, /: Fixed utils directory breakage from
+	  r398748, this time with extra hate. ........ Merged revisions
+	  398752 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* utils/ael_main.c, utils/conf2ael.c, utils/check_expr.c, /: Fixed
+	  utils directory breakage from r398648 ........ Merged revisions
+	  398748 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-09 23:21 +0000 [r398721]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/astmm.c: MALLOC_DEBUG: Change fence magic number to be
+	  completely different from the freed magic number. Race conditions
+	  between freeing a nul terminated string and ast_strdup()'ing it
+	  are more likely to be detected if the fence and freed magic
+	  numbers are completely different. ........ Merged revisions
+	  398703 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-09 20:02 +0000 [r398649]  David M. Lee <dlee at digium.com>
+
+	* main/lock.c, /, main/utils.c, include/asterisk/lock.h: Fix
+	  DEBUG_THREADS when lock is acquired in __constructor__ This patch
+	  fixes some long-standing bugs in debug threads that were
+	  exacerbated with recent Optional API work in Asterisk 12. With
+	  debug threads enabled, on some systems, there's a lock ordering
+	  problem between our mutex and glibc's mutex protecting its module
+	  list (Ubuntu Lucid, glibc 2.11.1 in this instance). In one
+	  thread, the module list will be locked before acquiring our
+	  mutex. In another thread, our mutex will be locked before locking
+	  the module list (which happens in the depths of calling
+	  backtrace()). This patch fixes this issue by moving backtrace()
+	  calls outside of critical sections that have the mutex acquired.
+	  The bigger change was to reentrancy tracking for
+	  ast_cond_{timed,}wait, which wrongly assumed that waiting on the
+	  mutex was equivalent to a single unlock (it actually suspends all
+	  recursive locks on the mutex). (closes issue ASTERISK-22455)
+	  Review: https://reviewboard.asterisk.org/r/2824/ ........ Merged
+	  revisions 398648 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-07 00:59 +0000 [r398510-398618]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_xmpp.c: Prevent XMPP timeout on blank responses Sometimes
+	  the Google Voice servers have a bad habit of sending out 1 byte
+	  replies to the xmpp resource. When a blank 1 byte reply is
+	  received from the socket the buffer attempts to wait (endlessly)
+	  for the rest of the reply from google which effectively blocks
+	  the socket and google voice calls will no longer come into the
+	  server. This patch allows the xmpp module to correctly detect
+	  empty packets and send out ping replies to google. It also sets a
+	  socket timeout on the default socket which prevents the xmpp
+	  socket from closing and preventing future google voice calls from
+	  coming into the server. Furthermore instead of sending an empty
+	  reply back to google we send a proper xmpp ping reply back. This
+	  also adds several more socket messages. (closes issue
+	  ASTERISK-22347) Reported by: Andrew Nagy Review:
+	  https://reviewboard.asterisk.org/r/2771 Patches: xmpp_fix_1.diff
+	  uploaded by Andrew Nagy (License #6524)
+
+	* /, res/res_xmpp.c, res/res_jabber.c: Commit the remainder of
+	  r398523 This is a missing part of the commit in revision 398523
+	  that corrects the name of a variable. (issue ASTERISK-22435)
+	  ........ Merged revisions 398576 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, res/res_xmpp.c, res/res_jabber.c: Fix Jabber/XMPP distributed
+	  MWI The mailbox and context are swapped on the receiving end for
+	  all users of Jabber and XMPP distributed MWI in Asterisk 1.8 and
+	  all more recent versions. This swaps those values to be correct
+	  when publishing to the internal event system from Jabber/XMPP
+	  distributed MWI state. (closes issue ASTERISK-22435) Reported by:
+	  abelbeck Tested by: Michael Keuter Patches:
+	  asterisk-1.8-res_jabber-aji_handle_pubsub_event.patch uploaded by
+	  abelbeck asterisk-11-res_xmpp-xmpp_pubsub_handle_event.patch
+	  uploaded by abelbeck ........ Merged revisions 398523 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_h323.c: Fix chan_h323 compilation This fixes the
+	  things in chan_h323 that were missed or ignored in the great
+	  channel opaquification and gets chan_h323 back into a compiling
+	  state. (closes issue ASTERISK-22365) Reported by: Dmitry Melekhov
+	  Patches: chan_h323.patch uploaded by Dmitry Melekhov
+
+2013-09-05 19:13 +0000 [r398302-398457]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_iax2.c, /: chan_iax2: Reduce indentation in
+	  __attempt_transmit(). * Reduce indentation in
+	  __attempt_transmit(). * Don't update the static last error time
+	  variable every time in __schedule_action() and socket_read().
+	  ........ Merged revisions 398456 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_iax2.c, /: chan_iax2: Fix stray reference to worker
+	  thread idle_list. * Fix stray reference to idle_list in
+	  cleanup_thread_list(). This may be the reason for the note in
+	  iax2_process_thread() about threads not being removed from the
+	  task lists. * Move cleanup_thread_list(&idle_list) to after the
+	  other lists are cleaned up. ........ Merged revisions 398416 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_iax2.c, /: chan_iax2: Fix bridgecallno deadlock
+	  avoidance. * Fix bridgecallno deadlock avoidance. When doing
+	  deadlock avoidance, you need to retest the status of values for
+	  each loop to see if you still need the lock for bridgecallno. *
+	  As a safety check, after acquiring the bridgecallno lock you
+	  should check if iaxs[bridgecallno] is NULL just like the current
+	  callno checks. * Move setting thread->iostate to IAX_IOSTATE_IDLE
+	  to after processing any deferred frames to ensure that the
+	  iostate is IDLE when it is placed back into the idle list.
+	  defer_full_frame() tries to ensure iax2_process_thread() wakes up
+	  to process the frame. ........ Merged revisions 398379 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/iax2-parser.c: chan_iax2: Add missing control frame
+	  names to debug frame decode output. (Part 2)
+
+	* channels/iax2-parser.c, /: chan_iax2: Add missing control frame
+	  names to debug frame decode output. ........ Merged revisions
+	  398301 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-04 21:33 +0000 [r398281-398285]  Jonathan Rose <jrose at digium.com>
+
+	* tests/test_voicemail_api.c: unit tests: test_voicemail_api leaks
+	  stringfields from snapshots (closes issue ASTERISK-22414)
+	  Reported by: Corey Farrell Patches:
+	  test_voicemail_api-leaks-11.patch uploaded by coreyfarrell
+	  (license 5909)
+
+	* apps/app_voicemail.c: app_voicemail: Fix leaking config objects
+	  when msg_id doesn't match (issues ASTERISK-22414) Reported by:
+	  Corey Farrell Patch: test_voicemail_api-leaks-11.patch uploaded
+	  by coreyfarrell (license 5909)
+
+2013-09-04 15:57 +0000 [r398236]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_misdn.c, /: chan_misdn: Fix misdn debug output
+	  printed with arbitrary verbose levels. Fix the misdn debug output
+	  to remote consoles. chan_misdn uses ast_console_puts() which
+	  doesn't know about verbose levels. Better to use ast_verbose()
+	  instead. Without this patch the misdn debug messages are appended
+	  to the verbose level which ever was set by the message sent to
+	  the console before, i.e. any undefined level. (closes issue
+	  AST-1218) Reported by: Guenther Kelleter Patches: misdnlog.patch
+	  (license #6372) patch uploaded by Guenther Kelleter ........
+	  Merged revisions 398235 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-09-03 19:45 +0000 [r398214]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooh245.c: Fix remote tcs sequence handling on
+	  empty tcs received
+
+2013-09-02 07:28 +0000 [r398168]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, cel/cel_custom.c: Be a little more verbose when loading
+	  cel_custom.conf. Review: https://reviewboard.asterisk.org/r/2805/
+	  ........ Merged revisions 398167 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-30 19:16 +0000 [r398022-398103]  Kevin Harwell <kharwell at digium.com>
+
+	* main/indications.c, main/config.c, res/res_security_log.c, /,
+	  channels/chan_sip.c, main/translate.c, main/named_acl.c: Fix
+	  various memory leaks main/config.c - cleanup cache fie includes
+	  res/res_security_log.c - unregister logger level
+	  channesl/chan_sip.c - cleanup io context and notify_types
+	  main/translator.c - cleanup at shutdown main/named_acl.c -
+	  cleanup cli commands main/indications.c -
+	  ast_get_indication_tone() unref default_tone_zone if used (closes
+	  issues ASTERISK-22378) Reported by: Corey Farrell Patches:
+	  config_shutdown.patch uploaded by coreyfarrell (license 5909)
+	  res_security_log.patch uploaded by coreyfarrell (license 5909)
+	  chan_sip-11.patch uploaded by coreyfarrell (license 5909)
+	  indications_refleak.patch uploaded by coreyfarrell (license 5909)
+	  named_acl-cli_unreg-11.patch uploaded by coreyfarrell (license
+	  5909) translate_shutdown.patch uploaded by coreyfarrell (license
+	  5909) ........ Merged revisions 398102 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_agi.c, main/manager.c, /: Memory leak fix
+	  ast_xmldoc_printable returns an allocated block that must be
+	  freed by the caller. Fixed manager.c and res_agi.c to stop
+	  leaking these results. (closes issue ASTERISK-22395) Reported by:
+	  Corey Farrell Patches: manager-leaks-11.patch uploaded by
+	  coreyfarrell (license 5909) res_agi-xmldoc-leaks.patch uploaded
+	  by coreyfarrell (license 5909) ........ Merged revisions 398060
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/features.c: Fix memory leak Fixed a features.c test that
+	  leaked a reference to a parked call. This caused chancount to
+	  never reach 0, so graceful shutdown stops. Also added an
+	  unregister test. (closes issue ASTERISK-22413) Reported by: Corey
+	  Farrell Patches: features-TEST_FRAMEWORK.patch uploaded by
+	  coreyfarrell (license 5909) ........ Merged revisions 398021 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-30 16:57 +0000 [r398019]  Richard Mudgett <rmudgett at digium.com>
+
+	* tests/test_substitution.c, /: test_substituition: Fix failed test
+	  reporting to actually report failure. You cannot put the "Testing
+	  <blah> pass/fail" on a single line before actually performing the
+	  test. Now any additional failure information is logged before the
+	  test pass/fail announcement. * Added an additional CDR(answer,u)
+	  test. ........ Merged revisions 398018 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-30 16:20 +0000 [r397948-398011]  Kevin Harwell <kharwell at digium.com>
+
+	* /, apps/app_mixmonitor.c: Fix memory leaks (closes issue
+	  ASTERISK-22368) Reported by: Corey Farrell Patches:
+	  issueA22368_mixmonitor_free_filename.patch uploaded by wdoekes
+	  (license 5674) ........ Merged revisions 398004 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/asterisk.c: Check return value on fwrite
+
+	* channels/chan_misdn.c, apps/app_dumpchan.c, main/features.c,
+	  main/logger.c, apps/app_verbose.c, main/asterisk.c: Verbose
+	  logging discrepancies Refactored cases where a combination of
+	  ast_verbose/options_verbose were present. Also in general tried
+	  to eliminate, in as many places as possible, where the
+	  options_verbose global variable was being used. Refactored the
+	  way local and remote consoles handle verbose message logging in
+	  an attempt to solve the various discrepancies that sometimes
+	  would show between the two. (closes issue AST-1193) Reported by:
+	  Guenther Kelleter Review:
+	  https://reviewboard.asterisk.org/r/2798/
+
+2013-08-27 18:03 +0000 [r397758]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: AST-2013-005: Fix crash caused by invalid
+	  SDP If the SIP channel driver processes an invalid SDP that
+	  defines media descriptions before connection information, it may
+	  attempt to reference the socket address information even though
+	  that information has not yet been set. This will cause a crash.
+	  This patch adds checks when handling the various media
+	  descriptions that ensures the media descriptions are handled only
+	  if we have connection information suitable for that media. Thanks
+	  to Walter Doekes, OSSO B.V., for reporting, testing, and
+	  providing the solution to this problem. (closes issue
+	  ASTERISK-22007) Reported by: wdoekes Tested by: wdoekes patches:
+	  issueA22007_sdp_without_c_death.patch uploaded by wdoekes
+	  (License 5674) ........ Merged revisions 397756 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 397757 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-08-27 16:40 +0000 [r397744]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_sip.c, channels/chan_motif.c, channels/chan_iax2.c,
+	  channels/sig_pri.c, channels/sig_ss7.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c: Fix uninitialized value in struct
+	  ast_control_pvt_cause_code usage.
+
+2013-08-27 15:55 +0000 [r397712]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: AST-2013-004: Fix crash when handling ACK
+	  on dialog that has no channel A remote exploitable crash
+	  vulnerability exists in the SIP channel driver if an ACK with SDP
+	  is received after the channel has been terminated. The handling
+	  code incorrectly assumed that the channel would always be
+	  present. This patch adds a check such that the SDP will only be
+	  parsed and applied if Asterisk has a channel present that is
+	  associated with the dialog. Note that the patch being applied was
+	  modified only slightly from the patch provided by Walter Doekes
+	  of OSSO B.V. (closes issue ASTERISK-21064) Reported by: Colin
+	  Cuthbertson Tested by: wdoekes, Colin Cutherbertson patches:
+	  issueA21064_fix.patch uploaded by wdoekes (License 5674) ........
+	  Merged revisions 397710 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 397711 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-08-23 21:57 +0000 [r397604]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c, UPGRADE.txt, res/Makefile: Make libuuid
+	  an optional dependency for res_rtp_asterisk instead of a
+	  requirement. Review: https://reviewboard.asterisk.org/r/2777/
+
+2013-08-23 16:07 +0000 [r397528]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/utils.c, include/asterisk/lock.h, main/astmm.c,
+	  channels/sig_pri.c, main/astobj2.c, include/asterisk/logger.h,
+	  main/lock.c, include/asterisk/utils.h, include/asterisk/astmm.h,
+	  /, main/logger.c: Fix memory corruption when trying to get "core
+	  show locks". Review https://reviewboard.asterisk.org/r/2580/
+	  tried to fix the mismatch in memory pools but had a math error
+	  determining the buffer size and didn't address other similar
+	  memory pool mismatches. * Effectively reverted the previous patch
+	  to go in the same direction as trunk for the returned memory pool
+	  of ast_bt_get_symbols(). * Fixed memory leak in
+	  ast_bt_get_symbols() when BETTER_BACKTRACES is defined. * Fixed
+	  some formatting in ast_bt_get_symbols(). * Fixed sig_pri.c
+	  freeing memory allocated by libpri when MALLOC_DEBUG is enabled.
+	  * Fixed __dump_backtrace() freeing memory from
+	  ast_bt_get_symbols() when MALLOC_DEBUG is enabled. * Moved
+	  __dump_backtrace() because of compile issues with the utils
+	  directory. (closes issue ASTERISK-22221) Reported by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/2778/ ........ Merged
+	  revisions 397525 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-22 08:22 +0000 [r397378]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* default.exports, /, main/asterisk.exports.in: Add _IO_stdin_used
+	  in version-script to fix SIGBUSes on Sparc. The
+	  --version-script,asterisk.exports linker flag (and the module
+	  exports) didn't provide _IO_stdin_used in the list of exported
+	  symbols. That causes some kind of libc compatibility mode to kick
+	  in, where stdio file structures (stdout/stderr) land somewhere
+	  else. In the case of the Sparc, they landed on misaligned memory.
+	  This became apparent first after r376428 (Reorder startup
+	  sequence) when a lot of ast_log's were replaced with fprintf's.
+	  Writing to stderr triggered a SIGBUS. (Compared to x86 and amd64
+	  architectures, the Sparc is very picky about memory alignment.)
+	  (issue ASTERISK-21763) (issue ASTERISK-21665) Reported by: Jeremy
+	  Kister Review: https://reviewboard.asterisk.org/r/2760/ ........
+	  Merged revisions 397377 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-21 23:02 +0000 [r397365]  Jonathan Rose <jrose at digium.com>
+
+	* main/udptl.c: UDPTL: Fix a regression where UDPTL won't load
+	  default settings If the file udptl.conf is unavailable at
+	  startup, UDPTL will fail to initialize and while it makes some
+	  noise, it isn't immediately obvious why consumers start to fail
+	  when using it. This patch makes UDPTL load as though an empty
+	  config was provided when udptl is unavailable at startup. (closes
+	  issue ASTERISK-22349) Reported by: Jonathan Rose Review:
+	  https://reviewboard.asterisk.org/r/2773/
+
+2013-08-21 17:07 +0000 [r397309]  David M. Lee <dlee at digium.com>
+
+	* /, main/http.c: Complete http_shutdown. This patch frees up some
+	  resources allocated in http.c. * tcp listeners stopped * tls
+	  settings freed * uri redirects freed * unregister internal http.c
+	  uri's (closes issue ASTERISK-22237) Reported by: Corey Farrell
+	  Patches: http.patch uploaded by Corey Farrell (license 5909)
+	  ........ Merged revisions 397308 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-21 15:12 +0000 [r397257]  Matthew Jordan <mjordan at digium.com>
+
+	* /, include/asterisk/frame.h: Set 14400 as the default max bit
+	  rate if T38MaxBitRate is not specified If an endpoint fails to
+	  include the T38MaxBitRate attribute during negotiation, Asterisk
+	  will negotiate a bit rate of 2400 instead of the ITU recommended
+	  bit rate of 14400. This patch fixes this by making
+	  AST_T38_RATE_14400 the 'default' value of the enum by assigning
+	  it a value of 0, such that if an endpoint fails to include the
+	  attribute, the default will be 14400. Note that Walter Doekes
+	  included the nice comment in frame.h about why we are
+	  purposefully assigning AST_T38_RATE_14400 a value of 0. (closes
+	  issue ASTERISK-22275) Reported by: Andreas Steinmetz patches:
+	  fax-fix.patch uploaded by anstein (License 6523) ........ Merged
+	  revisions 397256 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-21 14:36 +0000 [r397254]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Prevent a crash on outbound SIP MESSAGE
+	  requests. If a From header on an outbound out-of-call SIP MESSAGE
+	  were malformed, the result could crash Asterisk. In addition, if
+	  a From header on an incoming out-of-call SIP MESSAGE request were
+	  malformed, the message was happily accepted rather than being
+	  rejected up front. The incoming message path would not result in
+	  a crash, but the behavior was bad nonetheless. (closes issue
+	  ASTERISK-22185) reported by Zhang Lei
+
+2013-08-21 02:11 +0000 [r397205]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix Not Storing Current Incoming Recv
+	  Address In 1.8, r384779 introduced a regression by retrieving an
+	  old dialog and keeping the old recv address since recv was
+	  already set. This has caused a problem when a proxy is involved
+	  since responses to incoming requests from the proxy server, after
+	  an outbound call is established, are never sent to the correct
+	  recv address. In 11, r382322 introduced this regression. The fix
+	  is to revert that change and always store the recv address on
+	  incoming requests. Thank you Walter Doekes for helping to point
+	  out this error and Mark Michelson for your input/review of the
+	  fix. (closes issue ASTERISK-22071) Reported by: Alex Zarubin
+	  Tested by: Alex Zarubin, Karsten Wemheuer Patches:
+	  asterisk-22071-store-recvd-address.diff by Michael L. Young
+	  (license 5026) ........ Merged revisions 397204 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-20 17:41 +0000 [r397133-397157]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Remove REF_DEBUG definition. ........
+	  Merged revisions 397156 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c, channels/sip/dialplan_functions.c: Fix
+	  refcounting of sip_pvt in test_sip_rtpqos test and unlink it from
+	  the list of pvts. (closes issue ASTERISK-22248) reported by Corey
+	  Farrell patches: test_sip_rtpqos.patch uploaded by Corey Farrell
+	  (license #5909) ........ Merged revisions 397112 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-20 15:27 +0000 [r397034-397107]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/threadstorage.c, main/astfd.c: Unregister CLI commands on
+	  exit This patch ensures that CLI commands enabled by
+	  DEBUG_FD_LEAKS and DEBUG_THREADLOCALS are cleaned up properly on
+	  exit. (closes issue ASTERISK-22238) Reported by: Corey Farrell
+	  Tested by: Corey Farrell Patches: debug_cli_unregister.patch
+	  uploaded by Corey Farrell ........ Merged revisions 397106 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/xmldoc.c, /: Fix xmldoc memory leak This fixes a
+	  single-attribute memory leak that was occurring when the
+	  "required" attribute was not true. (closes issue ASTERISK-22249)
+	  Reported by: Corey Farrell Tested by: Corey Farrell Patches:
+	  xmldoc-free_attr_required.patch uploaded by Corey Farrell
+	  ........ Merged revisions 397064 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/cel.c, /: Protect CEL from an invalid config on reload This
+	  patch fixes CEL to properly handle an invalid config on reload.
+	  (closes issue ASTERISK-22259) Reported by: Corey Farrell Tested
+	  by: Corey Farrell Patches: cel-config.patch uploaded by Corey
+	  Farrell ........ Merged revisions 397033 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-20 11:47 +0000 [r396995]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* configs/h323.conf.sample, /, configs/sip.conf.sample: Add
+	  "autoframing" option to sip.conf.sample and h323.conf.sample. The
+	  autoframing option was added to chan_sip.c in r43243 (mogorman,
+	  2006-09-19 01:32:57), but never made its way into the sample
+	  configs. Review: https://reviewboard.asterisk.org/r/2768/
+	  ........ Merged revisions 396994 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-20 01:18 +0000 [r396944-396961]  Matthew Jordan <mjordan at digium.com>
+
+	* main/data.c, /: Fix invalid access to disposed memory in
+	  main/data unit test It is not safe to iterate over a macro'd list
+	  of ao2 objects, deref them such that the item's destructor is
+	  called, and leave them in the list. The list macro to iterate
+	  over items requires the item to be a valid allocated object in
+	  order to proceed to the next item; with MALLOC_DEBUG on the
+	  corruption of the linked list is caught in the crash. This patch
+	  fixes the invalid access to free'd memory by removing the ao2
+	  item from the list before de-refing it. Note that this is a
+	  backport of r396915 from Asterisk trunk. ........ Merged
+	  revisions 396958 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_queue.c: Let Queue wrap up time influence member
+	  availability Queue members who happen to be in multiple queues at
+	  the same time may not have any wrap up time. This problem
+	  occurred due to a code change in Asterisk 11.3.0 that unified
+	  device state tracking of Queue members in multiple Queues (which
+	  fixed some other problems, but unfortunately caused this one).
+	  This patch fixes the behavior by having the is_member_available
+	  function check the queue's wrap up time and the time of the
+	  member's last call, such that for a particular queue, the member
+	  won't be considered available if their last call is within the
+	  wrap up time. (closes issue ASTERISK-22189) Reported by: Tony
+	  Lewis Tested by: Tony Lewis
+
+	* apps/app_meetme.c: Resolve conflicts between
+	  CONFFLAG_DONT_DENOISE and CONFFLAG_INTROUSER_VMREC When r382230
+	  added an option to not denoise the MeetMe conference (if a user
+	  had a channel whose format's sample rate changed frequently, for
+	  example), the value added was the maximum allowed value for the
+	  constants that define the options for MeetMe in 1.8. Not so in 11
+	  - unfortunately, the option CONFFLAG_DONT_DENOISE conflicts with
+	  CONFFLAG_INTROUESR_VMREC. This patch fixes that, and also tweaks
+	  one of the way in which the constants was declared for
+	  consistency. Thanks to Tony Mountifield for pointing out the
+	  problem and solution. (closes issue ASTERISK-22269) Reported by:
+	  Tony Mountifield
+
+2013-08-16 22:45 +0000 [r396884]  John Bigelow <jbigelow at digium.com>
+
+	* main/features.c: Add test suite events to indicate when a feature
+	  is detected or not These are needed by the bridge test suite
+	  tests for them to be able to run against Asterisk 11. Review:
+	  https://reviewboard.asterisk.org/r/2751/
+
+2013-08-15 16:29 +0000 [r396746]  Kinsey Moore <kmoore at digium.com>
+
+	* main/asterisk.c, main/cli.c, /: Remove leading spaces from the
+	  CLI command before parsing If you've mistakenly put a space
+	  before typing in a command, the leading space will be included as
+	  part of the command, and the command parser will not find the
+	  corresponding command. This patch rectifies that situation by
+	  stripping the leading spaces on commands. Review:
+	  https://reviewboard.asterisk.org/r/2709/ Patch-by: Tilghman
+	  Lesher ........ Merged revisions 396745 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-14 19:06 +0000 [r396620-396657]  Joshua Colp <jcolp at digium.com>
+
+	* tests/test_hashtab_thrash.c, /: Tweak comment for why usleep is
+	  used. ........ Merged revisions 396656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, tests/test_hashtab_thrash.c: Tweak test_hashtab_thrash test to
+	  allow the critical threads to execute. Depending on certain
+	  conditions it was possible for the hashtab counting thread to
+	  starve other threads, preventing them from executing in the
+	  expected fashion. This change adds a sleep to allow the others to
+	  do what they need to do. While this doesn't thrash the hashtab as
+	  much as previously, it at least works. (closes issue
+	  ASTERISK-22276) Reported by: Matt Jordan ........ Merged
+	  revisions 396619 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-13 18:45 +0000 [r396580-396583]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: chan_sip: Convert 'just did sched_add
+	  waitid...' from warning to debug message. Patches:
+	  reviewboard-2377.patch uploaded by Paul Belanger Review:
+	  https://reviewboard.asterisk.org/r/2377/ ........ Merged
+	  revisions 396582 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: chan_sip: Fix IP-addr in warning when
+	  rejecting a contact ACL. Patches: reviewboard-2155.patch uploaded
+	  by Paul Belanger Review: https://reviewboard.asterisk.org/r/2155/
+	  ........ Merged revisions 396579 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-08 20:21 +0000 [r396441]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* include/asterisk/logger.h, /, main/logger.c, main/utils.c,
+	  main/astobj2.c: Consistent memory allocation by
+	  ast_bt_get_symbols. Always use ast_alloc/ast_free. This is
+	  handled differently in trunk (r391012). Review:
+	  https://reviewboard.asterisk.org/r/2580/ ........ Merged
+	  revisions 396427 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-08 07:03 +0000 [r396377]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: - Fix different issues with call
+	  transfer cancel. In case 3rd party busy or congestion call was
+	  not returned. - Fix displaying soft button 'Redial' in case of no
+	  redial number exists
+
+2013-08-06 08:37 +0000 [r396287-396310]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* funcs/func_strings.c: Check result of ast_var_assign() calls for
+	  memory allocation failure (2). Missed a spot in the previous
+	  commit.
+
+	* apps/app_stack.c, apps/app_playback.c, funcs/func_global.c,
+	  main/cdr.c, pbx/pbx_loopback.c, main/pbx.c, /,
+	  funcs/func_strings.c, pbx/pbx_dundi.c, utils/extconf.c: Check
+	  result of ast_var_assign() calls for memory allocation failure.
+	  We try to keep the system running even when all available memory
+	  is spent. Review: https://reviewboard.asterisk.org/r/2734/
+	  ........ Merged revisions 396279 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-08-05 20:19 +0000 [r396197-396248]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix Registration Failure When A Peer And
+	  TLS Are Used If a peer is used in a register line and TLS is
+	  defined as the transport, the registration fails since the
+	  transport on the dialog is never set properly resulting in UDP
+	  being used instead of TLS. This patch sets the dialog's transport
+	  based on the transport that was defined in the register line. If
+	  the register line does not specify a transport, the parsing
+	  function for the register line always defaults back to UDP.
+	  (closes issue ASTERISK-21964) Reported by: Doug Bailey Tested by:
+	  Doug Bailey Patches: asterisk-21964-set-reg-dialog-transport.diff
+	  by Michael L. Young (license 5026) ........ Merged revisions
+	  396240 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* UPGRADE.txt: Change "from" to "From". (related to issue
+	  ASTERISK-21903)
+
+	* /, UPGRADE.txt: Adding a note to UPGRADE.txt about a change made
+	  to res_agi in order to indicate when streaming an audio file
+	  fails like it is done in other parts of the code to indicate an
+	  error. Note was requested by Paul Belanger:
+	  http://lists.digium.com/pipermail/asterisk-dev/2013-July/061420.html
+	  (related to issue ASTERISK-21903) ........ Merged revisions
+	  396196 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-22 13:50 +0000 [r394890-395033]  Matthew Jordan <mjordan at digium.com>
+
+	* main/asterisk.c, /: Update copyright year to 2013 in asterisk.c;
+	  some whitespace fixes (closes issue ASTERISK-22179) Reported by:
+	  Malcolm Davenport ........ Merged revisions 395032 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* CHANGES, UPGRADE.txt: Add an upgrade note for libuuid dependency;
+	  remove note in CHANGES This patch notes that libuuid is now a
+	  dependency for res_rtp_asterisk; this was introduced in between
+	  11.4.0 and 11.5.0 to resolve a dependency for pjproject, which
+	  res_rtp_asterisk uses for ICE/STUN/TURN support. It also removes
+	  a conflicting note from CHANGES. While support for playing
+	  prompts to the first participant was added for app_queue, it was
+	  disabled by default and an option added to enable it. That was
+	  properly noted in the UPGRADE.txt file.
+
+	* /, funcs/func_channel.c: Clean up documentation This patch cleans
+	  up documentation in func_channel for the following items: *
+	  rtpsource * secure_signaling * secure_media * various OOH323
+	  parameters (closes issue ASTERISK-20969) Reported by: snuffy
+	  patches: func_chan-update.diff uploaded by snuffy (License 5024)
+	  ........ Merged revisions 394980 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, configs/indications.conf.sample: Provide proper ring tone in
+	  indications.conf for Malaysia The ring tone provided in the
+	  sample indications.conf was incorrect. This patch modifies the
+	  sample ring tone to be what it should: ring =
+	  425/400,0/200,425/400,0/2000 This brings it in line with the tone
+	  definition in DAHDI 2.7.0. (zonedata.c) (closes issue
+	  ASTERISK-21997) Reported by: Filip Jenicek patches:
+	  malaysia_ring.patch uploaded by phill (License 6277) ........
+	  Merged revisions 394940 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/http.c, /: Tolerate presence of RFC2965 Cookie2 header by
+	  ignoring it This patch modifies parsing of cookies in Asterisk's
+	  http server by doing an explicit comparison of the "Cookie"
+	  header instead of looking at the first 6 characters to determine
+	  if the header is a cookie header. This avoids parsing "Cookie2"
+	  headers and overwriting the previously parsed "Cookie" header.
+	  Note that we probably should be appending the cookies in each
+	  "Cookie" header to the parsed results; however, while clients can
+	  send multiple cookie headers they never really do. While this
+	  patch doesn't improve Asterisk's behavior in that regard, it
+	  shouldn't make it any worse either. Note that the solution in
+	  this patch was pointed out on the issue by the issue reporter,
+	  Stuart Henderson. (closes issue ASTERISK-21789) Reported by:
+	  Stuart Henderson Tested by: mjordan, Stuart Henderson ........
+	  Merged revisions 394899 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* contrib/realtime/postgresql/realtime.sql, /: Update PostgreSQL
+	  realtime scripts with schema for queue_log table This patch
+	  updates the realtime SQL scripts with an entry that will create
+	  the queue_log table. This brings the PostgreSQL scripts inline
+	  with the MySQL scripts, with respect to what tables they will
+	  create. (closes issue ASTERISK-21021) Reported by: Eugene
+	  patches: queue_log.sql uploaded by varnav (license 6360) ........
+	  Merged revisions 394896 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* configs/iax.conf.sample, /: Document connectedline parameter for
+	  chan_iax2 The connectedline parameter for a chan_iax2 peer was
+	  undocumented. This patch documents the options in the sample
+	  configuration file. (closes issue ASTERISK-21953) Reported by:
+	  Birger "WIMPy" Harzenetter ........ Merged revisions 394886 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-18 12:52 +0000 [r394641]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* res/res_agi.c, /: Properly indicate failure to open an audio
+	  stream in res_agi If there is an error streaming an audio file,
+	  the current return status makes it difficult for an AGI script to
+	  determine that there was an error with the audio file. This
+	  patches changes the result to return -1 and the function returns
+	  RESULT_FAILURE instead of RESULT_SUCCESS. From looking at other
+	  parts of res_agi, this would appear to be the proper way to
+	  handle an error. (closes issue ASTERISK-21903) Reported by: Ariel
+	  Wainer Tested by: Ariel Wainer Patches:
+	  asterisk-21903-return-stream-res_1.8.diff by Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2625/
+	  ........ Merged revisions 394640 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-14 02:34 +0000 [r394303-394345]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_queue.c: Provide error message for QUEUE_MEMBER when
+	  member is not in queue When QUEUE_MEMBER is used and the member
+	  specified is not in the queue, Asterisk provides an ERROR message
+	  that indicates that the option specified is not valid. This patch
+	  now properly displays an ERROR message that the member is not in
+	  the queue if an interface is specified. (closes issue
+	  ASTERISK-21980) Reported by: Avraam David
+
+	* /, funcs/func_strings.c: Clarify documentation for function
+	  PASSTHRU It is not apparent to the average user that the PASSTHRU
+	  function should not be passed as ${PASSTHRU(string)} but just as
+	  PASSTHRU(string) to functions which take a variable name and not
+	  its contents. This patch clarifies the behavior in the
+	  documentation and provides an example. (closes issue
+	  ASTERISK-21717) Reported by: Richard Miller patches:
+	  func_strings.diff uploaded by Richard Miller (license 5685)
+	  ........ Merged revisions 394302 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-11 21:28 +0000 [r394173]  Moises Silva <moises.silva at gmail.com>
+
+	* channels/chan_dahdi.c, /: Fix a longstanding issue with MFC-R2
+	  configuration that prevented users from mixing different variants
+	  or general MFC-R2 settings within the same E1 line. Most users do
+	  not have a problem with this since MFC-R2 lines are usually
+	  fractional E1s, or the whole E1 has the same country variant and
+	  R2 settings. In Venezuela however is common to have inbound
+	  MFC-R2 and outbound DTMF-R2 within the same E1. This fix now
+	  properly parses the chan_dahdi.conf file to generate a new openr2
+	  context every time a new channel => section is found and the
+	  configuration was changed. (closes issue ASTERISK-21117) Reported
+	  by: Rafael Angulo Related Elastix issue:
+	  http://bugs.elastix.org/view.php?id=1612 ........ Merged
+	  revisions 394106 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-10 01:49 +0000 [r393929]  Russell Bryant <russell at russellbryant.com>
+
+	* configs/sla.conf.sample, /, apps/app_meetme.c: astobj2-ify the
+	  SLA code The SLA code within app_meetme was written before
+	  asotbj2 had been merged into Asterisk. Worse, support for reloads
+	  did not exist at first and was added later as a bolt-on feature.
+	  I knew at the time that reloading was not safe at all while SLA
+	  was in use, so the reload would be queued up to execute when the
+	  system was idle. Unfortunately, this approach was still prone to
+	  errors beyond the fact that this was the only place in Asterisk
+	  where configuration was not reloaded instantly when requested.
+	  This patch converts various SLA objects to be reference counted
+	  objects using astobj2. This allows reloads to be processed while
+	  the system is in use. The code ensures that the objects will not
+	  disappear while one of the other threads is using them. However,
+	  they will be immediately removed from the global trunk and
+	  station containers so no new calls will use them if removed from
+	  configuration. Review: https://reviewboard.asterisk.org/r/2581/
+	  ........ Merged revisions 393928 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-03 23:52 +0000 [r393628-393630]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_mixmonitor.c: MixMonitor: Fix refleak in
+	  manager_stop_mixmonitor() if could not stop monitoring. ........
+	  Merged revisions 393490 from
+	  http://svn.asterisk.org/svn/asterisk/trunk
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Fix segfault reloading
+	  chan_dahdi when round robin is used. * Clear round_robin[] in
+	  dahdi_restart(). (closes issue ASTERISK-21847) Reported by: Ivo
+	  Andonov Patches: jira_asterisk_21847_v1.8.patch (license #5621)
+	  patch uploaded by rmudgett ........ Merged revisions 393627 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-02 10:14 +0000 [r393395]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix issue with inability to cancell call
+	  transfer made by on-sceen menus. Reported by: Igor Olhovskiy
+
+2013-06-25 01:07 +0000 [r392810]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_motif.c, main/http.c, main/config_options.c,
+	  main/named_acl.c, res/res_calendar.c: Fix memory/ref counting
+	  leaks in a variety of locations This patch fixes the following
+	  memory leaks: * http.c: The structure containing the addresses to
+	  bind to was not being deallocated when no longer used *
+	  named_acl.c: The global configuration information was not
+	  disposed of * config_options.c: An invalid read was occurring for
+	  certain option types. * res_calendar.c: The loaded calendars on
+	  module unload were not being properly disposed of. *
+	  chan_motif.c: The format capabilities needed to be disposed of on
+	  module unload. In addition, this now specifies the default
+	  options for the maxpayloads and maxicecandidates in such a way
+	  that it doesn't cause the invalid read in config_options.c to
+	  occur. (issue ASTERISK-21906) Reported by: John Hardin patches:
+	  http.patch uploaded by jhardin (license 6512) named_acl.patch
+	  uploaded by jhardin (license 6512) config_options.patch uploaded
+	  by jhardin (license 6512) res_calendar.patch uploaded by jhardin
+	  (license 6512) chan_motif.patch uploaded by jhardin (license
+	  6512)
+
+2013-06-14 16:21 +0000 [r391794]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_mixmonitor.c, /: app_mixmonitor: Fix crashes caused by
+	  unloading app_mixmonitor Unloading app_mixmonitor while active
+	  mixmonitors were running would cause a segfault. This patch fixes
+	  that by making it impossible to unload app_mixmonitor while
+	  mixmonitors are active. Review:
+	  https://reviewboard.asterisk.org/r/2624/ ........ Merged
+	  revisions 391778 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-06-13 18:47 +0000 [r391700]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/conf_config_parser.c,
+	  apps/confbridge/include/confbridge.h, apps/app_confbridge.c:
+	  app_confbridge: Fix memory leak on reload. The config framework
+	  options should not be registered multiple times. Instead the
+	  configuration just needs to be reprocessed by the config
+	  framework.
+
+2013-06-12 21:00 +0000 [r391560]  David M. Lee <dlee at digium.com>
+
+	* res/res_http_websocket.c: Fix segfault for certain invalid
+	  WebSocket input. The WebSocket code would allocate, on the stack,
+	  a string large enough to hold a key provided by the client, and
+	  the WEBSOCKET_GUID. If the key is NULL, this causes a segfault.
+	  If the key is too large, it could overflow the stack. This patch
+	  checks the key for NULL and checks the length of the key to avoid
+	  stack smashing nastiness. (closes issue ASTERISK-21825) Reported
+	  by: Alfred Farrugia Tested by: Alfred Farrugia, David M. Lee
+	  Patches: issueA21825_check_if_key_is_sent.patch uploaded by
+	  Walter Doekes (license 5674)
+
+2013-06-12 02:25 +0000 [r391507]  Matthew Jordan <mjordan at digium.com>
+
+	* main/loader.c, main/format.c, /: Fix memory leak while loading
+	  priority modules and adding formats This patch fixes two memory
+	  leaks: * When we load a module with the LOAD_PRIORITY flag, we
+	  remove its entry from the load order list. Unfortunately, we
+	  don't free the memory associated with entry in the list. This
+	  patch corrects that and properly frees the memory for the module
+	  in the list. * When adding a custom format (such as SILK or
+	  CELT), the routine for adding the format was leaking a reference.
+	  RAII_VAR cleans this up properly. ........ Merged revisions
+	  391489 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-06-11 10:22 +0000 [r391379]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix issue with no sound in both way in
+	  case of previous call to chan_unistim phone was canceled.
+	  (related to ASTERISK-20183)
+
+2013-06-11 08:10 +0000 [r391334]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* channels/chan_iax2.c, /: IAX2: Transfer Reject: Lock bridgecallno
+	  before touching it, refactor 1). When touching the bridgecallno,
+	  we need to lock it. 2). Remove magic number '0' and replace with
+	  TRANSFER_NONE. 3). Exit early if no bridgecallno. 4). Reduce
+	  indentation. Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2613/ ........ Merged
+	  revisions 391333 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-07-15  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.5.0 Released.
+
+2013-07-12  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.5.0-rc2 Released.
+
+	* Properly lock and safely handle a transfer failure in IAX2
+
+	  When touching the bridgecallno, we need to lock it - otherwise a
+	  race condition can occur. This patch does the proper locking
+	  of the bridgecallno before modifying its state.
+
+2013-06-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.5.0-rc1 Released.
+
+2013-06-10 14:25 +0000 [r391241]  Matthew Jordan <mjordan at digium.com>
+
+	* /, configs/queues.conf.sample, UPGRADE.txt, apps/app_queue.c: Add
+	  announce-to-first-user option for app_queue In r386792, the
+	  ability to play prompts to the first caller in a call queue was
+	  added. While this is arguably a bug fix for those who expect the
+	  first caller to continue receiving prompts while the agent is
+	  dialed, it has the side effect of preventing the first caller
+	  from hearing the agent immediately upon bridging. This may not be
+	  a problem for those who really want this option, but for those
+	  who didn't care whether or not the first caller in queue heard
+	  their position, it was an issue. This patch disables the ability
+	  for the first caller in the queue to hear prompts and adds a new
+	  option, announce-to-first-user, to queues.conf. Those who the
+	  behavior can enable it by setting this value to True. Note that
+	  if we ever implement the ability to have the prompts be stopped
+	  upon bridging, this option can be removed. (closes issue
+	  ASTERISK-21782) Reported by: Remi Quezada ........ Merged
+	  revisions 391215 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-06-10 09:32 +0000 [r391063-391148]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_iax2.c: chan_iax2: nativebridge refactor, missed
+	  unlock bridgecallno ........ Merged revisions 391143 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_iax2.c: fix bad edit after conflict resolution
+	  ........ Merged revisions 391107 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_iax2.c: IAX2: refactor nativebridge transfer
+	  remove triple checking of iaxs[fr->callno]->transferring reduce
+	  indentation. Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2602/ ........ Merged
+	  revisions 391065 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_iax2.c: IAX2: fix race condition with
+	  nativebridge transfers. 1). When touching the bridgecallno, we
+	  need to lock it. 2). stop_stuff() which calls
+	  iax2_destroy_helper() Assumes the lock on the pvt is already
+	  held, when iax2_destroy_helper() is called. Thus we need to lock
+	  the bridgecallno pvt before we call
+	  stop_stuff(iaxs[fr->callno]->bridgecallno); 3). When evaluating
+	  the state of 'callno->transferring' of the current leg, we can't
+	  change it to READY unless the bridgecallno is locked. Why, if we
+	  are interrupted by the other call leg before 'transferring =
+	  TRANSFER_RELEASED', the interrupt will find that it is READY and
+	  that the bridgecallno is also READY so Releases the legs. (closes
+	  issue ASTERISK-21409) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2594/ ........ Merged
+	  revisions 391062 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-31 10:34 +0000 [r390228-390229]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: remove unnecessary declarations (issue
+	  ASTERISK-21800)
+
+	* addons/chan_ooh323.c, /: reject call attempts when gatekeeper is
+	  configured but not registered (closes issue ASTERISK-21800)
+	  Reported by: Dmitry Melekhov Patches: ASTERISK-21800-1.patch
+	  Tested by: Dmitry Melekhov ........ Merged revisions 390181 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 390223 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-05-29 20:18 +0000 [r390047]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /: Fix segfault when dealing with chan_agent
+	  channels. Check the returned bridged pointer for NULL to avoid a
+	  crash. It looks like chan_agent is returning a NULL pointer when
+	  it probably should be returning a pointer to the channel the
+	  Agent channel is pretending to be. (closes issue ASTERISK-21793)
+	  Reported by: Rodrigo P. Telles Patches:
+	  jira_asterisk_21793_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: Rodrigo P. Telles ........ Merged revisions
+	  390044 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-28 17:43 +0000 [r389896]  Jonathan Rose <jrose at digium.com>
+
+	* /, main/slinfactory.c: Fix a memory copying bug in slinfactory
+	  which was causing mixmonitor issues. Reported by: Michael Walton
+	  Tested by: Jonathan Rose Patches:
+	  slinfactory.c.ASTERISK-21799.patch uploaded by Michael Walton
+	  (license 6502) (closes issue ASTERISK-21799) ........ Merged
+	  revisions 389895 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-24 11:49 +0000 [r389677]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/logger.c: Print all logger messages on shutdown When
+	  Asterisk shuts down and shuts down the loggin gsubsystem, any
+	  messages currently in flight will not get logged. This patch
+	  prevents the loop writing messages from breaking out prematurely,
+	  such that all of the messages are logged. (closes issue
+	  ASTERISK-21716) Reported by: Corey Farrell patches:
+	  logger-process-all-messages.patch uploaded by Corey Farrell
+	  (license 5909) ........ Merged revisions 389676 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-24 10:12 +0000 [r389661]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix several problems caused by multiple
+	  line usage with i2004 phones. Reported by: Daniel Bohling,
+	  MihaiMircea (closes issue ASTERISK-21061) (closes issue
+	  ASTERISK-21120)
+
+2013-05-20 17:43 +0000 [r389245]  Jason Parker <jparker at digium.com>
+
+	* /: Add doxygen.log to svn:ignore property. ........ Merged
+	  revisions 389244 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-15 15:57 +0000 [r388839]  kharwell <kharwell at localhost>:
+
+	* main/lock.c, /: Fix for segfault in __ast_rwlock_destroy with
+	  DEBUG_THREADS If DEBUG_THREADS is enabled __ast_rwlock_destroy
+	  causes a segfault while trying to access a possible NULL t->track
+	  object. A NULL check has been added before trying to access the
+	  memory. (closes issue ASTERISK-21724) Reported by: Corey Farrell
+	  Fixed by: Corey Farrell Patches: ast_rwlock_destroy-segv.patch
+	  uploaded by Corey Farrell (license 5909) ........ Merged
+	  revisions 388838 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-15 14:25 +0000 [r388816]  Jason Parker <jparker at digium.com>
+
+	* apps/app_voicemail.c: Fix VM snapshot handling for combined
+	  INBOX. The snapshot API contains an option that allow for
+	  combining of new and old messages within a single snapshot. New
+	  messages, however, include options beyond just 'INBOX' - it also
+	  includes the Urgent folder. A previous patch that combined INBOX
+	  and Urgent accidentally impacted snapshots that attempted to gain
+	  messages from just the Old folder. This patch fixes the snapshot
+	  gathering such that the API returns the appropriate messages for
+	  the folder selected, with and without the combine option. This
+	  should make it more clear about what's happening. Review:
+	  https://reviewboard.asterisk.org/r/2539/
+
+2013-05-15 12:39 +0000 [r388769]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_srtp.c, /, configure, include/asterisk/autoconfig.h.in,
+	  configure.ac: Use srtp_shutdown when available This allows the
+	  SRTP library to be shut down properly when the functionality is
+	  offered by libsrtp. Review:
+	  https://reviewboard.asterisk.org/r/2538/ (closes issue
+	  ASTERISK-21719) ........ Merged revisions 388768 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-14 18:55 +0000 [r388700]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h, main/astobj2.c: Make ao2 global
+	  objects not always use the debug version of the ao2_ref() calls.
+	  The debug versions of ao2_ref() should only be used if REF_DEBUG
+	  is enabled so nothing is written to /tmp/refs unexpectedly.
+	  (closes issue ASTERISK-21785) Reported by: abelbeck Patches:
+	  jira_asterisk_21785_v11.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: abelbeck
+
+2013-05-13 21:17 +0000 [r388601-388605]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* main/logger.c: Fix Missing CALL-ID When Logging Through Syslog
+	  The CALL-ID (ie [C-00000074]) is missing when logging to syslog.
+	  This was just an oversight when this feature was added. * Add
+	  CALL-IDs when using syslog (closes issue ASTERISK-21430) Reported
+	  by: Nikola Ciprich Tested by: Nikola Ciprich, Michael L. Young
+	  Patches: asterisk-21430-syslog-callid_trunk.diff by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2526/
+
+	* channels/chan_sip.c: Fix Crash Caused By One-way Audio With
+	  auto_* NAT Settings Fix The prior code committed, r385473, failed
+	  to take into consideration that not all outgoing calls will be to
+	  a peer. My fault. This patch does the following: * Check if there
+	  is a related peer involved. If there is, check and set NAT
+	  settings according to the peer's settings. * Fix a problem with
+	  realtime peers. If the global setting has auto_force_rport set
+	  and we issued a "sip reload" while a peer is still registered,
+	  the peer's flags for NAT are reset to off. When this happens, we
+	  were always setting the contact address of the peer to that of
+	  the full contact info that we had. (closes issue ASTERISK-21374)
+	  Reported by: jmls Tested by: Michael L. Young Patches:
+	  asterisk-21374-fix-crash-and-rt-peers.diff by Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2524/
+
+2013-05-13 20:35 +0000 [r388597]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_srtp.c, /: Revert r388529 for now Adding the cleanup
+	  function needs some deeper thought since it apparently doesn't
+	  exist for all variants of libsrtp. ........ Merged revisions
+	  388596 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-13 19:24 +0000 [r388578]  Jonathan Rose <jrose at digium.com>
+
+	* main/pbx.c, /: pbx: Fix lack of cleanup on macrolock and
+	  context_table (closes issue ASTERISK-21723) Reported by: Corey
+	  Farrell Patches: core-pbx-cleanup.patch uploaded by Correy
+	  Farrell (license 5909) ........ Merged revisions 388532 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-13 18:09 +0000 [r388530]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_srtp.c, /: Close libsrtp properly Ensure that libsrtp is
+	  shutdown properly when res_srtp is unloaded. (closes issue
+	  ASTERISK-21719) Reported by: Corey Farrell Patches:
+	  res_srtp-library-shutdown.patch uploaded by Corey Farrell
+	  ........ Merged revisions 388529 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-13 14:26 +0000 [r388478]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /: Fix SendText AMI action to never return
+	  non-zero. AMI actions must never return non-zero unless they
+	  intend to close the AMI connection. (Which is almost never.)
+	  (closes issue ASTERISK-21779) Reported by: Paul Goldbaum ........
+	  Merged revisions 388477 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-10 22:11 +0000 [r388424-388426]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/misdn/isdn_msg_parser.c: Allow mISDN to send PROGRESS
+	  messsage. * Made isdn_msg_parser.c build a progress message with
+	  the mandatory progress indicator IE. (The mISDNuser NT state
+	  machine rejected sending the incomplete message.) Note: The
+	  associated mISDN and mISDNuser patches respectively are viewable
+	  here: http://svnview.digium.com/svn/thirdparty?view=rev&rev=200
+	  http://svnview.digium.com/svn/thirdparty?view=rev&rev=201 (closes
+	  issue AST-1153) Reported by: Guenther Kelleter Patches:
+	  progress-chan_misdn.diff (license #6372) patch uploaded by
+	  Guenther Kelleter progress-misdn.diff (license #6372) mISDN patch
+	  uploaded by Guenther Kelleter progress-misdnuser.diff (license
+	  #6372) mISDNuser patch uploaded by Guenther Kelleter ........
+	  Merged revisions 388425 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* utils, /: Add version.c to list of ignored files in the utils
+	  directory. ........ Merged revisions 388423 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-10 20:41 +0000 [r388378]  Mark Michelson <mmichelson at digium.com>
+
+	* /, pbx/pbx_dundi.c: Fix memory leak in pbx_dundi pbx_dundi added
+	  an io context without removing it. This caused a memory leak when
+	  the module was unloaded. (closes ASTERISK-21718) Reported by
+	  Corey Farrell Patches: pbx_dundi-ast_io_remove.patch uploaded by
+	  Corey Farrell (License #5909) ........ Merged revisions 388376
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-10 11:46 +0000 [r388253]  Sean Bright <sean at malleable.com>
+
+	* channels/chan_sip.c: Fix copy/paste error in one-touch-recording
+	  implementation.
+
+2013-05-09 04:10 +0000 [r388108-388112]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* res/res_rtp_asterisk.c, /: Fix The Payload Being Set On CN
+	  Packets And Do Not Set Marker Bit When we send out a CN packet
+	  (for instance, in the case of using rtpkeepalives), we are not
+	  setting the payload code properly. Also, we are setting the
+	  marker bit when we shouldn't be according to RFC 3389, section 4.
+	  AST_RTP_CN is not defined by AST_FORMAT codes. Therefore, we
+	  should be using ast_rtp_codecs_payload_code() rather than
+	  ast_rtp_codecs_payload_lookup(). 11 and trunk already use the
+	  appropriate function. * In 1.8, use ast_rtp_codecs_payload_code()
+	  * Remove the setting of the marker bit * Fix the debug message by
+	  incrementing the seqno after the debug message is set in order to
+	  display the correct seqno that was sent out (closes issue
+	  ASTERISK-21246) Reported by: Peter Katzmann Tested by: Peter
+	  Katzmann, Michael L. Young Patches:
+	  asterisk-21246-rtp-cng-payload-error_1.8_v2.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2500/ ........ Merged
+	  revisions 388111 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_queue.c: Fix Segfault In app_queue When
+	  "persistentmembers" Is Enabled And Using Realtime When the
+	  "ignorebusy" setting was deprecated, we added some code to allow
+	  us to be compatible with older setups that are still using the
+	  "ignorebusy" setting instead of "ringinuse". We set a char
+	  *variable with the column name to use, which helps the realtime
+	  functions to use the correct column in their SQL queries. When
+	  "persistentmembers" is enabled, we are not setting this variable
+	  before the realtime functions were called to load members. This
+	  results in the variable being NULL and therefore causing a
+	  segfault when loading members during the module's process of
+	  loading. The solution was to move the code that sets that
+	  variable to be before these realtime functions are called during
+	  the loading of the module. (closes issue ASTERISK-21738) Reported
+	  by: JoshE Tested by: JoshE Patches:
+	  asterisk-21738-rt-ringinuse-field-not-set.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2499/
+
+2013-05-08 07:19 +0000 [r387880]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_sip.c: chan_sip: NOTIFYs for BLF start queuing
+	  up and fail to be sent out after retries fail RFC6665 4.2.2: ...
+	  after a failed State NOTIFY transaction remove the subscription
+	  The problem is that the State Notify requests rely on the 200OK
+	  reponse for pacing control and to not confuse the notify
+	  susbsystem. The issue is, the pendinginvite isn't cleared if a
+	  response isn't received, thus further notify's are never sent.
+	  The solution, follow RFC 6665 4.2.2's 'SHOULD' and remove the
+	  subscription after failure. (closes issue ASTERISK-21677)
+	  Reported by: Dan Martens Tested by: Dan Martens, David Brillert,
+	  alecdavis alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2475/ ........ Merged
+	  revisions 387875 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-07 18:29 +0000 [r387823]  David M. Lee <dlee at digium.com>
+
+	* res/res_config_pgsql.c, main/manager.c: Minor fixups to Doxygen
+	  comments. The \example tags marks an entire file as an example,
+	  not a code snippet.
+
+2013-05-06 15:55 +0000 [r387689]  Russell Bryant <russell at russellbryant.com>
+
+	* /, apps/app_meetme.c: Make SLA reload more paranoid. Reload
+	  support was originally not included for SLA. It was added later,
+	  but in a fairly non-traditional way. It basically sets a flag
+	  indicating that a reload is pending, and then waits for a time
+	  where it thinks everything SLA related is idle and unused, and
+	  *then* executes the reload. It does this because the reload
+	  process is destructive. It starts by throwing everything away and
+	  starting over. There are a number of problems with this approach.
+	  One of them is that the check to see if anything in use was
+	  incomplete. This patch makes it more complete and thus less
+	  likely for a crash to occur during reload processing. However,
+	  this approach still has problems so some much more significant
+	  reworking of this code will need to come in as a next step. Patch
+	  credit and testing by CoreDial, LLC. ........ Merged revisions
+	  387688 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-02 17:15 +0000 [r387422]  Matthew Jordan <mjordan at digium.com>
+
+	* utils/Makefile, /: Update utils Makefile to handle r387294 Alec's
+	  patch that added the Asterisk version to 'core show locks'
+	  angered the items in utils, as they exist somewhat outside of the
+	  Asterisk build system. Some day, this Makefile should get nuked
+	  from high orbit, but for now, include version.c in its list of
+	  stuff to pile in. ........ Merged revisions 387421 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-02 08:09 +0000 [r387295-387345]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
+	  Session-Expires: Set timer to correctly expire at (~2/3) of the
+	  interval when not the refresher RFC 4028 Section 10 if the side
+	  not performing refreshes does not receive a session refresh
+	  request before the session expiration, it SHOULD send a BYE to
+	  terminate the session, slightly before the session expiration.
+	  The minimum of 32 seconds and one third of the session interval
+	  is RECOMMENDED. Prior to this asterisk would refresh at 1/2 the
+	  Session-Expires interval, or if the remote device was the
+	  refresher, asterisk would timeout at interval end. Now, when not
+	  refresher, timeout as per RFC noted above. (closes issue
+	  ASTERISK-21742) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2488/ ........ Merged
+	  revisions 387344 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: chan_sip: Honor Session-Expires in 200OK
+	  response when it's a RE-INVITE when asterisk is the refresher.
+	  RFC 4028 Section 7.2 "UACs MUST be prepared to receive a
+	  Session-Expires header field in a response, even if none were
+	  present in the request." What changed After ASTERISK-20787,
+	  inbound calls to asterisk with no Session-Expires in the INVITE
+	  are now are offered a Session-Expires (1800 asterisk default) in
+	  the response, with asterisk as the refresher. Symptom: After 900
+	  seconds (asterisk default refresher period 1800), asterisk
+	  RE-INVITEs the device, the device may respond with a much lower
+	  Session-Expires (180 in our case) value that it is now using.
+	  Asterisk ignores this response, as it's deemed both an INBOUND
+	  CALL, and a RE-INVITE. After 180 seconds the device times out and
+	  sends BYE (hangs up), asterisk is still working with the
+	  refresher period of 1800 as it ignored the 'Session Expires: 180'
+	  in the previous 200OK response. Fix: handle_response_invite()
+	  when 200OK, remove check for outbound and reinvite. (closes issue
+	  ASTERISK-21664) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2463/ ........ Merged
+	  revisions 387312 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_dahdi.c, /: chan_dahdi: fix lower bound check with
+	  -ve integer conversion from a float Lower bound of a 16bit signed
+	  int is -32768 not -32767 (closes issue ASTERISK-21744) Reported
+	  by: alecdavis Tested by: alecdavis alecdavis (license 585)
+	  ........ Merged revisions 387297 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/utils.c: Add Asterisk Version to core show locks Assist
+	  with reporting 'core show locks' when submitting bug reports.
+	  Example below: =========================== == SVN-branch-1.8-...
+	  == Currently Held Locks =========================== (closes issue
+	  ASTERISK-21743) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) ........ Merged revisions 387294 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-01 21:17 +0000 [r387038-387216]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Clear the DTMF sending digit tracking
+	  on off nominal paths In certain situations, when the RTP engine
+	  goes to send a DTMF end digit it may be in a situation where the
+	  remote address is no longer available, or the digit that was
+	  supposed to be sent is invalid. In such cases, we need to clear
+	  the RTP counters appropriately. Otherwise, when the RTP source is
+	  set again, we'll continue to think that we're in the middle of
+	  sending a DTMF digit, which can confuse the remote party
+	  (signficantly). (closes issue ASTERISK-21522) Reported by: Corey
+	  Farrell patches: rtp_dtmf_process_end.patch uploaded by Corey
+	  Farrell (License 5909) ........ Merged revisions 387213 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_sip.c: Prevent crash in 'sip show peers' when the
+	  number of peers on a system is large When you have lots of SIP
+	  peers (according to the issue reporter, around 3500), the 'sip
+	  show peers' CLI command or AMI action can crash due to a poorly
+	  placed string duplication that occurs on the stack. This patch
+	  refactors the command to not allocate the string on the stack,
+	  and handles the formatting of a single peer in a separate
+	  function call. (closes issue ASTERISK-21466) Reported by:
+	  Guillaume Knispel patches:
+	  fix_sip_show_peers_stack_overflow_asterisk_11.3.0-v2.patch
+	  uploaded by gknispel (License 6492)
+
+	* /, main/features.c: Fix CDR not being created during an
+	  externally initiated blind transfer Way back when in the dark
+	  days of Asterisk 1.8.9, blind transferring a call in a context
+	  that included the 'h' extension would inadvertently execute the
+	  hangup code logic on the transferred channel. This was a "bad
+	  thing". The fix was to properly check for the softhangup flags on
+	  the channel and only execute the 'h' extension logic (and, in
+	  later versions, hangup handler logic) if the channel was well and
+	  truly dead (Jim). Unfortunately, CDRs are fickle. Setting the
+	  softhangup flag when we detected that the channel was leaving the
+	  bridge (but not to die) caused some crucial snippet of CDR code,
+	  lying in ambush in the middle of the bridging code, to not get
+	  executed. This had the effect of blowing away one of the CDRs
+	  that is typically created during a blind transfer. While we live
+	  and die by the adage "don't touch CDRs in release branches", this
+	  was our bad. The attached patch restores the CDR behavior, and
+	  still manages to not run the 'h' extension during a blind
+	  transfer (at least not when it's supposed to). Thanks to Steve
+	  Davies for diagnosing this and providing a fix. Review:
+	  https://reviewboard.asterisk.org/r/2476 (closes issue
+	  ASTERISK-21394) Reported by: Ishfaq Malik Tested by: Ishfaq
+	  Malik, mjordan patches: fix_missing_blindXfer_cdr2 uploaded by
+	  one47 (License 5012) ........ Merged revisions 387036 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-30 22:15 +0000 [r387030]  Jonathan Rose <jrose at digium.com>
+
+	* main/event.c: Add forgotten event types to event_names array
+
+2013-04-30 13:46 +0000 [r386930]  Sean Bright <sean at malleable.com>
+
+	* include/asterisk/utils.h, /: Use the proper lower bound when
+	  doing saturation arithmetic. 16 bit signed integers have a range
+	  of [-32768, 32768). The existing code was using the interval
+	  (-32768, 32768) instead. This patch fixes that. Review:
+	  https://reviewboard.asterisk.org/r/2479/ ........ Merged
+	  revisions 386929 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-29 23:35 +0000 [r386878]  Rusty Newton <rnewton at digium.com>
+
+	* /, sounds/Makefile: Modifying sounds/Makefile to pull down 1.4.24
+	  core sounds 1.4.24 core sounds includes a full set of Italian
+	  prompts for core sounds and a fix for the missing voicemail
+	  prompts in the Russian language. (closes issue ASTERISK-19431)
+	  (closes issue ASTERISK-19721) ........ Merged revisions 386877
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-29 08:54 +0000 [r386794]  Olle Johansson <oej at edvina.net>
+
+	* /, CHANGES, apps/app_queue.c: Play periodic prompts for first
+	  call in a call queue Review:
+	  https://reviewboard.asterisk.org/r/2263/ ........ Merged
+	  revisions 386792 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-26 21:27 +0000 [r386642-386677]  Matthew Jordan <mjordan at digium.com>
+
+	* main/config.c, /: Clean up memory leak in config file on off
+	  nominal paths when glob is allowed If a system allows for its
+	  usage, Asterisk will use glob to help parse Asterisk .conf files.
+	  The config file loading routine was leaking the memory allocated
+	  by the glob() routine when the config file was in an unmodified
+	  or invalid state. This patch properly calls globfree in those off
+	  nominal paths. (closes issue ASTERISK-21412) Reported by: Corey
+	  Farrell patches: config_glob_leak.patch uploaded by Corey Farrell
+	  (license 5909) ........ Merged revisions 386672 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, main/features.c: Clean up resources in features on exit This
+	  patch cleans up two things features: * It properly unregisters
+	  the CLI commands that features registered * It cancels and
+	  performs a pthread_join on the created parking thread. This not
+	  only properly joins a non-detached thread, but also prevents
+	  disposing of the parking lots prior to the parking thread
+	  completely exiting. (closes issue ASTERISK-21407) Reported by:
+	  Corey Farrell patches: features_shutdown-r2.patch uploaded by
+	  Corey Farrell (License 5909) ........ Merged revisions 386641
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-25 03:02 +0000 [r386484-386486]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c: Fix Displaying Symmetric RTP Global Setting
+	  * Use comedia_string() to display correctly the symmetric rtp
+	  setting when running "sip show settings"
+
+	* /, channels/chan_sip.c: Change Case On Forcerport For Consistency
+	  * Change "ForcerPort" to "Forcerport" to match everywhere else it
+	  is displayed ........ Merged revisions 386483 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-22 16:30 +0000 [r386286]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /: Fix crash when AMI redirect action redirects
+	  two channels out of a bridge. The two party bridging loops were
+	  changing the bridge peer pointers without the channel locks held.
+	  Thus when ast_channel_massquerade() tested and used the pointer
+	  there is a small window of opportunity for the pointers to become
+	  NULL even though the masquerade code has the channels locked.
+	  (closes issue ASTERISK-21356) Reported by: William luke Patches:
+	  jira_asterisk_21356_v11.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: William luke ........ Merged revisions 386256
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-19 22:25 +0000 [r386159]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_timing_pthread.c: Prevent res_timing_pthread from
+	  blocking callers There were several reports of deadlock when
+	  using res_timing_pthread. Backtraces indicated that one thread
+	  was blocked waiting for the write to the pipe to complete and
+	  this thread held the container lock for the timers. Therefore any
+	  thread that wanted to create a new timer or read an existing
+	  timer would block waiting for either the timer lock or the
+	  container lock and deadlock ensued. This patch changes the way
+	  the pipe is used to eliminate this source of deadlocks: 1) The
+	  pipe is placed in non-blocking mode so that it would never block
+	  even if the following changes someone fail... 2) Instead of
+	  writing bytes into the pipe for each "tick" that's fired the pipe
+	  now has two states--signaled and unsignaled. If signaled, the
+	  pipe is hot and any pollers of the read side filedescriptor will
+	  be woken up. If unsigned the pipe is idle. This eliminates even
+	  the chance of filling up the pipe and reduces the potential
+	  overhead of calling unnecessary writes. 3) Since we're tracking
+	  the signaled / unsignaled state, we can eliminate the exta poll
+	  system call for every firing because we know that there is data
+	  to be read. (closes issue ASTERISK-21389) Reported by: Matt
+	  Jordan Tested by: Shaun Ruffell, Matt Jordan, Tony Lewis patches:
+	  0001-res_timing_pthread-Reduce-probability-of-deadlocking.patch
+	  uploaded by sruffell (License 5417) (closes issue ASTERISK-19754)
+	  Reported by: Nikola Ciprich (closes issue ASTERISK-20577)
+	  Reported by: Kien Kennedy (closes issue ASTERISK-17436) Reported
+	  by: Henry Fernandes (closes issue ASTERISK-17467) Reported by:
+	  isrl (closes issue ASTERISK-17458) Reported by: isrl Review:
+	  https://reviewboard.asterisk.org/r/2441/ ........ Merged
+	  revisions 386109 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-19 05:18 +0000 [r386006-386051]  David M. Lee <dlee at digium.com>
+
+	* main/cli.c, /: cli.c: Properly initialize debug_modules and
+	  verbose_modules. This avoids some lock errors on the core set
+	  {debug,verbose} commands. ........ Merged revisions 386049 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/message.c: Fix lock errors on startup. In messages.c, there
+	  are several places in the code where we create a tmp_tech_holder
+	  and pass that into an ao2_find call. Unfortunately, we weren't
+	  initializing the rwlock on the tmp_tech_holder, which the hash
+	  function was locking. It's apparently harmless, but still not the
+	  best code. This patch extracts all that copy/pasted code into two
+	  functions, msg_find_by_tech and msg_find_by_tech_name, which
+	  properly initialize and destroy the rwlock on the
+	  tmp_tech_holder. Review: https://reviewboard.asterisk.org/r/2454/
+
+2013-04-16 23:27 +0000 [r385917-385938]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* res/res_xmpp.c: Distributed Device State broken at sites using
+	  res_xmpp or res_jabber where Secuity Advisory AST-2012-015 is
+	  inplace res_xmpp was not adding AST_EVENT_IE_CACHABLE to the
+	  event as each message came in, then
+	  devstate_change_collector_cb() was unable to find
+	  AST_EVENT_IE_CACHABLE in the event, so defaulted incorrectly to
+	  AST_DEVSTATE_NOT_CACHABLE. (issue ASTERISK-20175) (closes issue
+	  ASTERISK-21429) (closes issue ASTERISK-21069) (closes issue
+	  ASTERISK-21164) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2452/
+
+	* /, main/devicestate.c, res/res_jabber.c: Distributed Device State
+	  broken at sites using res_xmpp or res_jabber where Secuity
+	  Advisory AST-2012-015 is inplace res_jabber/res_xmpp were not
+	  adding AST_EVENT_IE_CACHABLE to the event as each message came
+	  in, then devstate_change_collector_cb() was unable to find
+	  AST_EVENT_IE_CACHABLE in the event, so defaulted incorrectly to
+	  AST_DEVSTATE_NOT_CACHABLE. (issue ASTERISK-20175) (closes issue
+	  ASTERISK-21429) (closes issue ASTERISK-21069) (closes issue
+	  ASTERISK-21164) Reported by: alecdavis Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2452/ ........ Merged
+	  revisions 385916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-15 17:23 +0000 [r385768]  Jason Parker <jparker at digium.com>
+
+	* Makefile, /: Don't unnecessarily rebuild things on every run of
+	  'make'. Review: https://reviewboard.asterisk.org/r/2449/ ........
+	  Merged revisions 385745 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-15 15:18 +0000 [r385689]  David M. Lee <dlee at digium.com>
+
+	* channels/sig_ss7.c, channels/sip/include/security_events.h,
+	  contrib/realtime/mysql/queue_log.sql,
+	  channels/chan_multicast_rtp.c, channels/sig_ss7.h, /,
+	  tests/test_expr.c, apps/app_saycounted.c,
+	  channels/sip/security_events.c,
+	  contrib/realtime/mysql/voicemail_messages.sql, BSDmakefile,
+	  contrib/realtime/mysql/voicemail_data.sql,
+	  build_tools/sha1sum-sh, res/res_mutestream.c,
+	  configs/res_curl.conf.sample, tests/test_func_file.c,
+	  include/asterisk/select.h, res/res_rtp_multicast.c,
+	  include/asterisk/bridging_technology.h,
+	  include/asterisk/bridging_features.h, tests/test_locale.c,
+	  doc/Makefile, tests/test_poll.c,
+	  contrib/realtime/mysql/musiconhold.sql, res/res_timing_kqueue.c:
+	  Fix the svn:keywords property on several files. Normally I think
+	  keyword expansion is silly, but the one time it would have been
+	  good, it didn't work because the property had quotes in it. This
+	  patch fixes obviously busted svn:keywords properties. ........
+	  Merged revisions 385683 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-14 03:00 +0000 [r385634-385637]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_multicast.c, /: Calculate the timestamp for outbound
+	  RTP if we don't have timing information This patch calculates the
+	  timestamp for outbound RTP when we don't have timing information.
+	  This uses the same approach in res_rtp_asterisk. Thanks to both
+	  Pietro and Tzafrir for providing patches. (closes issue
+	  ASTERISK-19883) Reported by: Giacomo Trovato Tested by: Pietro
+	  Bertera, Tzafrir Cohen patches: rtp-timestamp-1.8.patch uploaded
+	  by tzafrir (License 5035) rtp-timestamp.patch uploaded by
+	  pbertera (License 5943) ........ Merged revisions 385636 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_alsa.c: Don't attempt to create a voice frame on
+	  a read error Prior to this patch, a read error in snd_pcm_readi
+	  would still be treated as a nominal result when constructing a
+	  voice frame from the expected data. Since the value returned is
+	  negative, as opposed to the number of samples read, this could
+	  result in a crash. With this patch, we now return a null frame
+	  when a read error is detected. Note that the patch on
+	  ASTERISK-21329 was modified slightly for this commit, in that we
+	  bail immediately on detecting the read error, rather than
+	  bypassing the construction of the voice frame. (closes issue
+	  ASTERISK-21329) Reported by: Keiichiro Kawasaki patches:
+	  chan_alsa.diff uploaded by kawasaki (License 6489) ........
+	  Merged revisions 385633 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-12 22:37 +0000 [r385594]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, apps/app_queue.c: Fix Manager Segfault When app_queue Is
+	  Unloaded When app_queue is unloaded, some manager commands are
+	  not being unregistered which result in a segfault. This patch
+	  corrects this. (closes issue ASTERISK-21397) Reported by: Peter
+	  Katzmann, Corey Farrell Tested by: Corey Farrell Patches:
+	  asterisk-21397-missing-unreg-manager-cmd_1.8.diff Michael L.
+	  Young (license 5026)
+	  asterisk-21397-missing-unreg-manager-cmd_11.diff Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2444/
+	  ........ Merged revisions 385593 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-12 22:25 +0000 [r385582]  Kinsey Moore <kmoore at digium.com>
+
+	* codecs/codec_resample.c: Allow codec_resample to be unloaded
+	  Ensure that trans_size is correct to prevent uninitialized
+	  entries from preventing reload. (closes issue ASTERISK-21401)
+	  Reported by: Corey Farrell Tested by: Corey Farrell Patches:
+	  codec_resample-unload.patch uploaded by Corey Farrell
+
+2013-04-12 22:18 +0000 [r385473-385557]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* apps/app_voicemail.c, /: Fix app_voicemail Segfault And A Few
+	  Memory Leaks The original report was that app_voicemail would
+	  crash. This was caused by ast_config_load() returning
+	  CONFIG_STATUS_FILEINVALID but no checks being performed for that
+	  return status. After adding the initial patch to fix this issue,
+	  Jaco Kroon (jkroon) added some fixes to memory leaks he had
+	  discovered. During review, Walter Doekes (wdoekes) suggested
+	  adding a helper function in order to determine if we had a valid
+	  configuration or not. This patch does the following: * Creates a
+	  helper function to check if the configuration is valid * Adds
+	  calls to the new helper function where appropiate * Fixes memory
+	  leaks where the code returned without running
+	  ast_config_destroy() on the configuration that was loaded (closes
+	  issue ASTERISK-21302) Reported by: Jaco Kroon Tested by: Jaco
+	  Kroon, Michael L. Young Patches:
+	  asterisk-11.3.0-app_voicemail-ast_config-fixes.patch Jaco Kroon
+	  (license 5671) asterisk-21302-valid_cfg_and_mem_leaks_v3-1.8.diff
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2443/ ........ Merged
+	  revisions 385551 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_sip.c: Fix One-Way Audio With auto_* NAT Settings
+	  When SIP Calls Initiated By PBX When we reload Asterisk or
+	  chan_sip, the flags force_rport and comedia that are turned on
+	  and off when using the auto_force_rport and auto_comedia nat
+	  settings go back to the default setting off. These flags are
+	  turned on when needed or off when not needed at the time that a
+	  peer registers, re-registers or initiates a call. This would
+	  apply even when only the default global setting
+	  "nat=auto_force_rport" is being used, which in this case would
+	  only affect the force_rport flag. Everything is good except for
+	  the following: The nat setting is set to auto_force_rport and
+	  auto_comedia. We reload Asterisk and the peer's registration has
+	  not expired. We load in the settings for the peer which turns
+	  force_rport and comedia back to off. Since the peer has not
+	  re-registered or placed a call yet, those flags remain off. We
+	  then initiate a call to the peer from the PBX. The force_rport
+	  and comedia flags stay off. If NAT is involved, we end up with
+	  one-way audio since we never checked to see if the peer is behind
+	  NAT or not. This patch does the following: * Moves the checking
+	  of whether a peer is behind NAT into its own function * Create a
+	  function to set the peer's NAT flags if they are using the auto_*
+	  NAT settings * Adds calls in sip_request_call() to these new
+	  functions in order to setup the dialog according to the peer's
+	  settings (closes issue ASTERISK-21374) Reported by: Michael L.
+	  Young Tested by: Michael L. Young Patches:
+	  asterisk-21374-auto-nat-outgoing-fix_v2.diff Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2421/
+
+2013-04-12 08:50 +0000 [r385403-385430]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_iax2.c: IAX2 defer_full_frames fail to get sent
+	  Ensure iax2_process_thread is signalled when a deferred frame is
+	  queued to it. (issue ASTERISK-18827) Reported by: alecdavis
+	  Tested by: alecdavis alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2426/ ........ Merged
+	  revisions 385429 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_iax2.c: IAX2, prevent network thread starting
+	  before all helper threads are ready On startup, it's possible for
+	  a frame to arrive before the processing threads were ready. In
+	  iax2_process_thread() the first pass through falls into
+	  ast_cond_wait, should a frame arrive before we are at
+	  ast_cond_wait, the signal will be ignored. The result
+	  iax2_process_thread stays at ast_cond_wait forever, with deferred
+	  frames being queued. Fix: When creating initial idle
+	  iax2_process_threads, wait for init_cond to be signalled after
+	  each thread is started. (issue ASTERISK-18827) Reported by:
+	  alecdavis Tested by: alecdavis alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2427/ ........ Merged
+	  revisions 385402 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-11 19:59 +0000 [r385356]  Jason Parker <jparker at digium.com>
+
+	* res/res_rtp_asterisk.c, build_tools/menuselect-deps.in,
+	  configure, include/asterisk/autoconfig.h.in, configure.ac,
+	  makeopts.in: Add dependency on libuuid, for res_rtp_asterisk
+	  pjproject is what actually requires libuuid. (closes issue
+	  ASTERISK-21125) reported by Private Name (Ed. note: Really?
+	  Private Name? I am rolling my eyes so hard right now.)
+
+2013-04-11 16:52 +0000 [r385313]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/cli_aliases.conf.sample: Fix 'pri intense debug span'
+	  alias.
+
+2013-04-10 14:25 +0000 [r385173-385199]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_config_ldap.c: Use LDAP memory management functions
+	  instead of Asterisk's When MALLOC_DEBUG is enabled with
+	  res_config_ldap, issues (munmap_chunk: invalid pointer errors)
+	  can occur as the memory is being allocated with Asterisk's
+	  wrappers around malloc/calloc/free/strdup, as opposed to the LDAP
+	  library's wrappers. This patch uses the LDAP library's wrappers
+	  where appropriate, so that compiling with MALLOC_DEBUG doesn't
+	  cause more problems than it solves. Note that the patch listed
+	  below was modified slightly for this commit to account for some
+	  additional memory allocation/deallocations. (closes issue
+	  ASTERISK-17386) Reported by: John Covert Tested by: Andrew Latham
+	  patches: issue18789-1.8-r316873.patch uploaded by seanbright
+	  (License 5060) ........ Merged revisions 385190 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_sip.c: Fix crash in chan_sip when a core
+	  initiated op occurs at the same time as a BYE When a BYE request
+	  is processed in chan_sip, the current SIP dialog is detached from
+	  its associated Asterisk channel structure. The tech_pvt pointer
+	  in the channel object is set to NULL, and the dialog persists for
+	  an RFC mandated period of time to handle re-transmits. While this
+	  process occurs, the channel is locked (which is good).
+	  Unfortunately, operations that are initiated externally have no
+	  way of knowing that the channel they've just obtained (which is
+	  still valid) and that they are attempting to lock is about to
+	  have its tech_pvt pointer removed. By the time they obtain the
+	  channel lock and call the channel technology callback, the
+	  tech_pvt is NULL. This patch adds a few checks to some channel
+	  callbacks that make sure the tech_pvt isn't NULL before using it.
+	  Prime offenders were the DTMF digit callbacks, which would crash
+	  if AMI initiated a DTMF on the channel at the same time as a BYE
+	  was received from the UA. This patch also adds checks on
+	  sip_transfer (as AMI can also cause a callback into this
+	  function), as well as sip_indicate (as lots of things can queue
+	  an indication onto a channel). Review:
+	  https://reviewboard.asterisk.org/r/2434/ (closes issue
+	  ASTERISK-20225) Reported by: Jeff Hoppe ........ Merged revisions
+	  385170 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-08 23:36 +0000 [r385048]  Rusty Newton <rnewton at digium.com>
+
+	* /, configs/extconfig.conf.sample: Modified the list of keys for
+	  the driver backends for sake of sample clarity Added a line
+	  showing the mapping of "mysql" to res_config_mysql available in
+	  add-ons. We used "mysql" as an example driver key in the sample,
+	  but didn't show what module it mapped too. Also added a subtitle
+	  above the list of keys for driver backends. ........ Merged
+	  revisions 385047 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-05 20:34 +0000 [r384827]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c, UPGRADE.txt: Fix For Not Overriding The
+	  Default Settings In chan_sip The initial report was that the
+	  "nat" setting in the [general] section was not having any effect
+	  in overriding the default setting. Upon confirming that this was
+	  happening and looking into what was causing this, it was
+	  discovered that other default settings would not be overriden as
+	  well. This patch works similar to what occurs in build_peer(). We
+	  create a temporary ast_flags structure and using a mask, we
+	  override the default settings with whatever is set in the
+	  [general] section. In the bug report, the reporter who helped to
+	  test this patch noted that the directmedia settings were being
+	  overriden properly as well as the nat settings. This issue is
+	  also present in Asterisk 1.8 and a separate patch will be applied
+	  to it. (issue ASTERISK-21225) Reported by: Alexandre Vezina
+	  Tested by: Alexandre Vezina, Michael L. Young Patches:
+	  asterisk-21225-handle-options-default-prob_v4.diff Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2385/
+
+2013-04-03 20:18 +0000 [r384689]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_pri.h, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, /, channels/sig_pri.c:
+	  chan_dahdi: Add inband_on_proceeding compatibility option. The
+	  new inband_on_proceeding option causes Asterisk to assume inband
+	  audio may be present when a PROCEEDING message is received. Q.931
+	  Section 5.1.2 says the network cannot assume that the CPE side
+	  has attached to the B channel at this time without explicitly
+	  sending the progress indicator ie informing the CPE side to
+	  attach to the B channel for audio. However, some non-compliant
+	  ISDN switches send a PROCEEDING without the progress indicator ie
+	  indicating inband audio is available and assume that the CPE
+	  device has connected the media path for listening to ringback and
+	  other messages. ASTERISK-17834 which causes this issue was
+	  dealing with a non-compliant network switch. (closes issue
+	  ASTERISK-21151) Reported by: Gianluca Merlo Tested by: rmudgett
+	  ........ Merged revisions 384685 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-03 17:10 +0000 [r384641]  Matthew Jordan <mjordan at digium.com>
+
+	* /, funcs/func_channel.c: Update documentation for CHANNEL
+	  function Document that you can read/write the 'accountcode' and
+	  'amaflags' on a channel. ........ Merged revisions 384640 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-02 17:34 +0000 [r384545]  David M. Lee <dlee at digium.com>
+
+	* Makefile, /: Fixed spurious rebuilds of func_version.
+	  func_version.so was being rebuilt every time, because build.h was
+	  changing every build, because of the cleantest dependency that
+	  was added in r384410 to fix parallel make bugs. Now build.h will
+	  only be created if it does not exist, which was the original
+	  behavior of the Makefile. ........ Merged revisions 384544 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-04-01 14:07 +0000 [r384414]  Joshua Colp <jcolp at digium.com>
+
+	* apps/app_voicemail.c: Remove silly use of strncmp.
+
+2013-04-01 13:28 +0000 [r384411]  David M. Lee <dlee at digium.com>
+
+	* Makefile, /: Fix parallel make problems. Occasionally, make -j
+	  would fail due to missing includes, or other unusual errors. This
+	  was due to the 'cleantest' target, which was designed to force a
+	  make clean when some change in the code would cause the typical
+	  depedency checking to fail. Several targets in the main Makefile
+	  did not depend upon cleantest, hence would run in parallel to it.
+	  By adding the dependency, make -j runs happily now. Review:
+	  https://reviewboard.asterisk.org/r/2418/ ........ Merged
+	  revisions 384410 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-29 16:31 +0000 [r384326]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_voicemail.c, /: app_voicemail: Add blank argument to
+	  externnotify if no context argument At least one call to
+	  run_externnotify provides a NULL context parameter and because
+	  the snprintf statement doesn't account for a NULL context
+	  parameter, it simply writes '(null)' to the arguments string
+	  instead. This patch makes it write two quotes back to back for
+	  that argument instead in the event of a NULL context. (closes
+	  issue ASTERISK-18207) Reported by: Barry L. Kline Patches:
+	  modified from patch-20130306 uploaded by Karsten Wemheuer
+	  (License 5930) ........ Merged revisions 384325 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-05-17  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.4.0 Released.
+
+2013-05-15  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.4.0-rc3 Released.
+
+	* Fix VM snapshot handling for combined INBOX.
+
+	  The snapshot API contains an option that allow for combining of new
+	  and old messages within a single snapshot. New messages, however,
+	  include options beyond just 'INBOX' - it also includes the Urgent
+	  folder. A previous patch that combined INBOX and Urgent accidentally
+	  impacted snapshots that attempted to gain messages from just the Old
+	  folder. This patch fixes the snapshot gathering such that the API
+	  returns the appropriate messages for the folder selected, with and
+	  without the combine option.
+
+2013-05-09  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.4.0-rc2 Released.
+
+	* Fix Segfault In app_queue When "persistentmembers" Is Enabled And
+	  Using Realtime
+
+	  When the "ignorebusy" setting was deprecated, we added some code to
+	  allow us to be compatible with older setups that are still using the
+	  "ignorebusy" setting instead of "ringinuse".  We set a char *variable
+	  with the column name to use, which helps the realtime functions to
+	  use the correct column in their SQL queries.  When "persistentmembers"
+	  is enabled, we are not setting this variable before the realtime
+	  functions were called to load members.  This results in the variable
+	  being NULL and therefore causing a segfault when loading members
+	  during the module's process of loading.
+
+	  The solution was to move the code that sets that variable to be
+	  before these realtime functions are called during the loading of the
+	  module.
+
+	* Distributed Device State broken at sites using res_xmpp or res_jabber
+	  where Secuity Advisory AST-2012-015 is inplace
+
+	  res_jabber/res_xmpp were not adding AST_EVENT_IE_CACHABLE to the
+	  event as each message came in, then devstate_change_collector_cb()
+	  was unable to find AST_EVENT_IE_CACHABLE in the event, so defaulted
+	  incorrectly to AST_DEVSTATE_NOT_CACHABLE.
+
+	* Fix CDR not being created during an externally initiated blind
+	  transfer
+
+	  Way back when in the dark days of Asterisk 1.8.9, blind transferring
+	  a call in a context that included the 'h' extension would
+	  inadvertently execute the hangup code logic on the transferred
+	  channel. This was a "bad thing". The fix was to properly check for
+	  the softhangup flags on the channel and only execute the 'h'
+	  extension logic (and, in later versions, hangup handler logic) if
+	  the channel was well and truly dead (Jim).
+
+	  Unfortunately, CDRs are fickle. Setting the softhangup flag when we
+	  detected that the channel was leaving the bridge (but not to die)
+	  caused some crucial snippet of CDR code, lying in ambush in the
+	  middle of the bridging code, to not get executed. This had the
+	  effect of blowing away one of the CDRs that is typically created
+	  during a blind transfer.
+
+	  While we live and die by the adage "don't touch CDRs in release
+	  branches", this was our bad. The attached patch restores the CDR
+	  behavior, and still manages to not run the 'h' extension during a
+	  blind transfer (at least not when it's supposed to).
+
+	  Thanks to Steve Davies for diagnosing this and providing a fix.
+
+	* Prevent res_timing_pthread from blocking callers
+
+	  There were several reports of deadlock when using res_timing_pthread.
+	  Backtraces indicated that one thread was blocked waiting for the
+	  write to the pipe to complete and this thread held the container lock
+	  for the timers.  Therefore any thread that wanted to create a new
+	  timer or read an existing timer would block waiting for either the
+	  timer lock or the container lock and deadlock ensued.
+
+	  This patch changes the way the pipe is used to eliminate this source
+	  of deadlocks:
+
+	  1) The pipe is placed in non-blocking mode so that it would never
+	     block even if the following changes someone fail...
+
+	  2) Instead of writing bytes into the pipe for each "tick" that's
+	     fired the pipe now has two states--signaled and unsignaled. If
+	     signaled, the pipe is hot and any pollers of the read side
+	     filedescriptor will be woken up. If unsigned the pipe is idle.
+	     This eliminates even the chance of filling up the pipe and reduces
+	     the potential overhead of calling unnecessary writes.
+
+	  3) Since we're tracking the signaled / unsignaled state, we can
+	  eliminate the exta poll system call for every firing because we know
+	  that there is data to be read.
+
+	* Fix crash when AMI redirect action redirects two channels out of a
+	  bridge.
+
+	  The two party bridging loops were changing the bridge peer pointers
+	  without the channel locks held.  Thus when ast_channel_massquerade()
+	  tested and used the pointer there is a small window of opportunity
+	  for the pointers to become NULL even though the masquerade code has
+	  the channels locked.
+
+2013-03-28  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.4.0-rc1 Released.
+
+2013-03-27 19:51 +0000 [r384163]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c, main/format_pref.c: Address uninitialized
+	  conditional that valgrind found ........ Merged revisions 384162
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-27 18:51 +0000 [r384119]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/http.c: Fix a file descriptor leak in off nominal path
+	  While looking at the security vulnerability in ASTERISK-20967,
+	  Walter noticed a file descriptor leak and some other issues in
+	  off nominal code paths. This patch corrects them. Note that this
+	  patch is not related to the vulnerability in ASTERISK-20967, but
+	  the patch was placed on that issue. (closes issue ASTERISK-20967)
+	  Reported by: wdoekes patches:
+	  issueA20967_file_leak_and_unused_wkspace.patch uploaded by
+	  wdoekes (License 5674) ........ Merged revisions 384118 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-27 17:06 +0000 [r384049]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Fix white noise on SRTP decryption
+	  When res_rtp_asterisk.c was altered to avoid attempting to apply
+	  unprotect algorithms to non-audio RTP packets, the test used was
+	  incorrect. This caused the audio packets to not be decrypted and
+	  resulted in loud white noise on the other endpoint (or both
+	  endpoints depending on the call legs involved). The test now
+	  properly checks the version field in the RTP header to ensure
+	  that RTP and RTCP are decrypted while other types of packets are
+	  not. (closes issue ASTERISK-21323) Reported by: andrea Tested by:
+	  Kinsey Moore, andrea, John Bigelow Patches: whitenoise_fix.diff
+	  uploaded by Kinsey Moore ........ Merged revisions 384048 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-27 15:23 +0000 [r383973-384003]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/sip/include/sip.h, channels/chan_sip.c,
+	  channels/sip/security_events.c: AST-2013-003: Prevent username
+	  disclosure in SIP channel driver When authenticating a SIP
+	  request with alwaysauthreject enabled, allowguest disabled, and
+	  autocreatepeer disabled, Asterisk discloses whether a user exists
+	  for INVITE, SUBSCRIBE, and REGISTER transactions in multiple
+	  ways. The information is disclosed when: * A "407 Proxy
+	  Authentication Required" response is sent instead of a "401
+	  Unauthorized" response * The presence or absence of additional
+	  tags occurs at the end of "403 Forbidden" (such as "(Bad Auth)")
+	  * A "401 Unauthorized" response is sent instead of "403
+	  Forbidden" response after a retransmission * Retransmission are
+	  sent when a matching peer did not exist, but not when a matching
+	  peer did exist. This patch resolves these various vectors by
+	  ensuring that the responses sent in all scenarios is the same,
+	  regardless of the presence of a matching peer. This issue was
+	  reported by Walter Doekes, OSSO B.V. A substantial portion of the
+	  testing and the solution to this problem was done by Walter as
+	  well - a huge thanks to his tireless efforts in finding all the
+	  ways in which this setting didn't work, providing automated
+	  tests, and working with Kinsey on getting this fixed. (closes
+	  issue ASTERISK-21013) Reported by: wdoekes Tested by: wdoekes,
+	  kmoore patches: AST-2013-003-1.8 uploaded by kmoore, wdoekes
+	  (License 6273, 5674) AST-2013-003-10 uploaded by kmoore, wdoekes
+	  (License 6273, 5674) AST-2013-003-11 uploaded by kmoore, wdoekes
+	  (License 6273, 5674)
+
+	* main/http.c: AST-2013-002: Prevent denial of service in HTTP
+	  server AST-2012-014, fixed in January of this year, contained a
+	  fix for Asterisk's HTTP server for a remotely-triggered crash.
+	  While the fix put in place fixed the possibility for the crash to
+	  be triggered, a denial of service vector still exists with that
+	  solution if an attacker sends one or more HTTP POST requests with
+	  very large Content-Length values. This patch resolves this by
+	  capping the Content-Length at 1024 bytes. Any attempt to send an
+	  HTTP POST with Content-Length greater than this cap will not
+	  result in any memory allocation. The POST will be responded to
+	  with an HTTP 413 "Request Entity Too Large" response. This issue
+	  was reported by Christoph Hebeisen of TELUS Security Labs (closes
+	  issue ASTERISK-20967) Reported by: Christoph Hebeisen patches:
+	  AST-2013-002-1.8.diff uploaded by mmichelson (License 5049)
+	  AST-2013-002-10.diff uploaded by mmichelson (License 5049)
+	  AST-2013-002-11.diff uploaded by mmichelson (License 5049)
+
+	* res/res_format_attr_h264.c: AST-2013-001: Prevent buffer overflow
+	  through H.264 format negotiation The format attribute resource
+	  for H.264 video performs an unsafe read against a media attribute
+	  when parsing the SDP. The value passed in with the format
+	  attribute is not checked for its length when parsed into a fixed
+	  length buffer. This patch resolves the vulnerability by only
+	  reading as many characters from the SDP value as will fit into
+	  the buffer. (closes issue ASTERISK-20901) Reported by: Ulf
+	  Harnhammar patches: h264_overflow_security_patch.diff uploaded by
+	  jrose (License 6182)
+
+2013-03-26 02:28 +0000 [r383840-383878]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Resolve deadlock between SIP registration
+	  and channel based functions In r373424, several reentrancy
+	  problems in chan_sip were addressed. As a result, the SIP channel
+	  driver is now properly locking the channel driver private
+	  information in certain operations that it wasn't previously. This
+	  exposed two latent problems either in register_verify or by
+	  functions called by register_verify. This includes: * Holding the
+	  private lock while calling sip_send_mwi_to_peer. This can create
+	  a new sip_pvt via sip_alloc, which will obtain the channel
+	  container lock. This is a locking inversion, as any channel
+	  related lock must be obtained prior to obtaining the SIP channel
+	  technology private lock. Note that this issue was already fixed
+	  in Asterisk 11. * Holding the private lock while calling
+	  sip_poke_peer. In the same vein as sip_send_mwi_to_peer,
+	  sip_poke_peer can create a new SIP private, causing the same
+	  locking inversion. Note that this locking inversion typically
+	  occured when CLI commands were run while a SIP REGISTER request
+	  was being processed, as many CLI commands (such as 'sip show
+	  channels', 'core show channels', etc.) have to obtain the channel
+	  container lock. (issue ASTERISK-21068) Reported by: Nicolas
+	  Bouliane (issue ASTERISK-20550) Reported by: David Brillert
+	  (issue ASTERISK-21314) Reported by: Badalian Vyacheslav (issue
+	  ASTERISK-21296) Reported by: Gabriel Birke ........ Merged
+	  revisions 383863 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/cdr.c, /: Resolve deadlock between pending CDR and batch CDR
+	  locks r375757 attempted to resolve a race condition between
+	  multiple submissions of CDRs while in batch mode from attempting
+	  to destroy the scheduled batch submission by extending the batch
+	  CDR lock. Unfortunately, this causes a deadlock between the
+	  pending CDR lock and the batch CDR lock. This patch resolves the
+	  intent of r375757 by simply providing a new lock that protects
+	  the scheduling of the batches. The original batch CDR lock is
+	  kept to protect manipulation of the batch CDR settings, but has
+	  been placed such that it is not held when the pending lock is
+	  held. Thanks to Chase Venters for providing lock analysis on the
+	  issue. (issue ASTERISK-21162) Reported by: Chase Venters ........
+	  Merged revisions 383839 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-26 01:36 +0000 [r383836]  Russell Bryant <russell at russellbryant.com>
+
+	* /, apps/app_meetme.c: Fix multi-station answer race condition.
+	  When an SLA trunk is ringing (inbound call on the trunk) Asterisk
+	  will make outbound calls to the stations that have that trunk. If
+	  more than one station answers the call at the same time, all
+	  channels other than the first one to answer are left in a bad
+	  state. The channel gets leaked, is not connected to anything, and
+	  there's no way to get rid of it. We now properly clean up these
+	  losing channels by hanging up on them. Since they lost the race,
+	  as we process their answer, there is no ringing trunk for them to
+	  answer. ........ Merged revisions 383835 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-25 23:24 +0000 [r383798]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Set the CALLERID(dnid-num-plan) for
+	  incoming ISDN calls. The CALLEDTON channel variable is set for
+	  incoming ISDN calls to the lower 7 bits of the Q.931
+	  type-of-number/numbering-plan octet. The CALLERID(dnid-num-plan)
+	  should have the same value. (closes issue ASTERISK-21248)
+	  Reported by: rmudgett ........ Merged revisions 383796 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-25 12:36 +0000 [r383668]  Sean Bright <sean at malleable.com>
+
+	* res/res_config_curl.c, /: Properly delimit post data in
+	  res_config_curl. ........ Merged revisions 383667 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-22 20:41 +0000 [r383631]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* apps/app_mixmonitor.c: Fix StopMixMonitor Hanging Up When Unable
+	  To Stop MixMonitor On A Channel A regression was accidentally
+	  introduced when allowing an optional ID to be used when calling
+	  StopMixMonitor. When we are unable to stop MixMonitor on a
+	  channel, -1 is being returned which triggers the hangup of the
+	  channel. This patch restores the prior behavior by returning 0
+	  whether we were successful or not. It also allows the call from
+	  the manager to use the return code when the action fails. (closes
+	  issue ASTERISK-21294) Reported by: daroz Tested by: daroz
+	  Patches: asterisk-21294-stop_mixmonitor_hangingup.diff Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2404/
+
+2013-03-20 20:25 +0000 [r383457-383461]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* funcs/func_curl.c, /: Have func_curl log a warning when a curl
+	  request fails. Review: https://reviewboard.asterisk.org/r/2403/
+	  ........ Merged revisions 383460 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* funcs/func_curl.c: Minor cleanup in func_curl near hashcompat
+	  code. Review: https://reviewboard.asterisk.org/r/2402/
+
+2013-03-19 15:58 +0000 [r383341-383342]  David M. Lee <dlee at digium.com>
+
+	* codecs/Makefile: Remove codecs/speex/*.i on make clean
+
+	* codecs/Makefile, /: Removed codecs/g722/*.i on make clean
+	  ........ Merged revisions 383340 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-16 15:14 +0000 [r383266]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Fix a bug where resources were not found due to
+	  hashing on the priority itself.
+
+2013-03-15 12:51 +0000 [r383166]  Kinsey Moore <kmoore at digium.com>
+
+	* main/tcptls.c, main/manager.c, /, channels/chan_sip.c,
+	  main/http.c: tcptls: Prevent unsupported options from being set
+	  AMI, HTTP, and chan_sip all support TLS in some way, but none of
+	  them support all the options that Asterisk's TLS core is capable
+	  of interpreting. This prevents consumers of the TLS/SSL layer
+	  from setting TLS/SSL options that they do not support. This also
+	  gets tlsverifyclient closer to a working state by requesting the
+	  client certificate when tlsverifyclient is set. Currently, there
+	  is no consumer of main/tcptls.c in Asterisk that supports this
+	  feature and so it can not be properly tested. Review:
+	  https://reviewboard.asterisk.org/r/2370/ Reported-by: John
+	  Bigelow Patch-by: Kinsey Moore (closes issue AST-1093) ........
+	  Merged revisions 383165 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-15 01:34 +0000 [r383121-383125]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: When a session timer expires during a
+	  T.38 call, re-invite with correct SDP When a session timer
+	  expires during a dialog that has re-negotiated to T.38 and
+	  Asterisk is the refresher, Asterisk will send a re-INVITE with an
+	  SDP containing audio media only. This causes some hilarity with
+	  the poor fax session under weigh. This patch corrects that by
+	  sending T.38 parameters if we are in the middle of a T.38
+	  session. (closes issue ASTERISK-21232) Reported by: Nitesh Bansal
+	  patches:
+	  dont-send-audio-reinvite-for-sess-timer-in-t38-call.patch
+	  uploaded by nbansal (License 6418) ........ Merged revisions
+	  383124 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* pbx/pbx_spool.c, /: Fix processing of call files when using
+	  KQueue on OS X In certain situations, call files are not
+	  processed when using KQueue with pbx_spool. Asterisk was sending
+	  an invalid timeout value when the spool directory is empty,
+	  causing the call to kevent to error immediately. This can create
+	  a tight loop, increasing the CPU load on the system. (closes
+	  issue ASTERISK-21176) Reported by: Carlton O'Riley patches:
+	  kqueue_osx.patch uploaded by coriley (License 6473) ........
+	  Merged revisions 383120 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-14 16:57 +0000 [r383062]  Jason Parker <jparker at digium.com>
+
+	* autoconf/ast_ext_lib.m4, /: Fix whitespace in AST_EXT_LIB_CHECK
+	  macro. ........ Merged revisions 383061 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-12 21:17 +0000 [r382940-382943]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* addons/res_config_mysql.c, /: Fix Sorting Order For Parking Lots
+	  Stored In Static Realtime When retrieving the parking lots from a
+	  MySQL database table, the current order is "filename, cat_metric
+	  desc, var_metric asc, category". If there are multiple parking
+	  lots with the same cat_metric but different categories,
+	  everything is being sorted on cat_metric first resulting in
+	  errors when loading the parking lots. This patch fixes the
+	  problem by sorting on the category field first, then the
+	  cat_metric field. (closes issue ASTERISK-21035) Reported by: Alex
+	  Epshteyn Patches: asterisk-21035-orderby.diff Michael L. Young
+	  (license 5026) ........ Merged revisions 382942 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* contrib/realtime/mysql/sippeers.sql, /,
+	  contrib/realtime/postgresql/realtime.sql: Update Contributed
+	  Realtime Schema Files - IPv6 Addresses This commit updates some
+	  fields in the contributed realtime schema files to handle IPv6
+	  addresses. (closes issue ASTERISK-21173) Reported by: Torrey
+	  Searle Patches: realtime_sql.patch Torrey Searle (license 5334)
+	  asterisk-21173-update-ip-fields.diff Michael L. Young (license
+	  5026) ........ Merged revisions 382939 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-12 20:06 +0000 [r382923]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Fix a crash when res_xmpp is configured using a
+	  username without a domain. (closes issue ASTERISK-21156) Reported
+	  by: amsoft2001
+
+2013-03-12 16:23 +0000 [r382848]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c, UPGRADE.txt: Include the Username field
+	  in SIP Registry events when Status is registered In
+	  ASTERISK-17888, the AMI Registry event during SIP registrations
+	  was supposed to include the Username field. Somehow, one of the
+	  events was missed. This patch corrects that - the Username field
+	  should be included in all AMI Registry events involving SIP
+	  registrations. (issue ASTERISK-17888) (closes issue
+	  ASTERISK-21201) Reported by: Dmitriy Serov patches:
+	  chan_sip.c.diff uploaded by Dmitriy Serov (license 6479) ........
+	  Merged revisions 382847 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-12 08:53 +0000 [r382827]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix core dump on CLI usage Fix issue
+	  with 'unistim show info' CLI command when device connected not
+	  configured
+
+2013-03-08 20:16 +0000 [r382739]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Update the via header when
+	  relaying SMS MESSAGE Prior to this change, certain conditions for
+	  sending the message would result in an address of '(null)' being
+	  used in the via header of the SIP message because a NULl value of
+	  pvt->ourip was used when initially generating the via header.
+	  This is fixed by adding a call to build_via when the address is
+	  set before sending the message. (closes issue ASTERISK-21148)
+	  Reported by: Zhi Cheng Patches: 700-sip_msg_send_via_fix.patch
+	  uploaded by Zhi Cheng (license 6475)
+
+2013-03-07 17:57 +0000 [r382617]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: Let vm_mailbox_snapshot combine "Urgent"
+	  when no folder is specified r381835 fixed a bug in
+	  vm_mailbox_snapshot where combining INBOX and Old forgot that
+	  Urgent also "counts" as new messages. This fixed the problem when
+	  any of the three folders was specified and the combine option was
+	  used. It missed the case where the folder isn't specified and we
+	  build a snapshot of all folders. This patch corrects that.
+
+2013-03-07 15:08 +0000 [r382574]  Kinsey Moore <kmoore at digium.com>
+
+	* main/logger.c: Ensure that logmsgs are freed properly Messages
+	  sent while the logger thread is shutting down will now have their
+	  associated callid freed properly.
+
+2013-03-07 14:58 +0000 [r382573]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c: Add a 'secret' probation strictrtp mode
+	  to handle delayed changes in RTP source Often, Asterisk may
+	  realize that a change in the source of an RTP stream is about to
+	  occur and ask that the RTP engine reset it's lock on the current
+	  RTP source. In certain scenarios, it may take awhile for the new
+	  remote system to send RTP packets, while the old remote system
+	  may continue providing RTP during that time period. This causes
+	  Asterisk to re-lock onto the old source, thereby rejecting the
+	  new source when the old source stops sending RTP and the new
+	  source begins. This patch prevents that by having a constant
+	  secondary, 'secret' probation mode enabled when an RTP source has
+	  been chosen. RTP packets from other sources are always
+	  considered, but never chosen unless the current RTP source stops
+	  sending RTP. Review: https://reviewboard.asterisk.org/r/2364
+	  (closes issue AST-1124) Reported by: John Bigelow Tested by: John
+	  Bigelow (closes issue AST-1125) Reported by: John Bigelow Tested
+	  by: John Bigelow
+
+2013-03-06 18:28 +0000 [r382514]  Kinsey Moore <kmoore at digium.com>
+
+	* /: Recorded merge of revisions 382513 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Correct app_page documentation The 'A' and 'n' options for Page()
+	  mention that the announcement will be played simultaneously. This
+	  is not necessarily the case.
+
+2013-03-05 03:51 +0000 [r382410]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, /: Fix several unreleased mutex locks
+	  that cause problem with processing calls Reported by: Daniel
+	  Bohling Tested by: Daniel Bohling (Closes issue ASTERISK-21119)
+	  ........ Merged revisions 382409 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-04 21:12 +0000 [r382390]  Jason Parker <jparker at digium.com>
+
+	* /, main/event.c: Fix comparison of presence state in event
+	  subsystem. Several new IEs were not given types (or names),
+	  causing the comparison function to improperly succeed. This adds
+	  those. (closes issue AST-1128)
+
+2013-03-04 20:03 +0000 [r382385]  kharwell <kharwell at localhost>:
+
+	* apps/app_confbridge.c: Confbridge CLI new record file name check.
+	  This fix checks to make sure that if a confbridge record start
+	  command is issued from the CLI it will always use the file name
+	  given on the CLI even if it changes between start/stop records
+	  for a conference. Previously it had been reusing the same file
+	  between start/stops even if a new filename was given. (issue
+	  AST-1088) Reported by: John Bigelow
+
+2013-03-01 04:28 +0000 [r382322]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* contrib/realtime/mysql/sippeers.sql, channels/chan_sip.c,
+	  contrib/realtime/postgresql/realtime.sql, CHANGES: Fix / Clean Up
+	  Some Items To Handle The New auto_* NAT Options The original
+	  report had to do with a realtime peer behind NAT being pruned and
+	  the peer's private address being used instead of its external
+	  address. Upon debugging, it was discovered that this was being
+	  caused by the addition of the auto_force_rport and auto_comedia
+	  settings. This patch does the following: * Adds a missing note to
+	  the CHANGES file indicating that the default global nat setting
+	  is auto_force_rport * Constify the 'req' parameter for
+	  check_via() * Add calls to check_via() in a couple of places in
+	  order for the auto_* settings to do their job in attempting to
+	  determine if NAT is involved * Set the flags SIP_NAT_FORCE_RPORT
+	  and SIP_PAGE2_SYMMETRICRTP if the auto_* settings are in use
+	  where it was needed * Moves the copying of peer flags up in
+	  build_peer() to before they are used; this fixes the realtime
+	  prune issue * Update the contrib/realtime schemas to allow the
+	  nat column to handle the different nat setting combinations we
+	  have This patch received a review and "Ship It!" on the issue
+	  itself. (closes issue ASTERISK-20904) Reported by: JoshE Tested
+	  by: JoshE, Michael L. Young Patches:
+	  asterisk-20904-nat-auto-and-rt-peersv2.diff Michael L. Young
+	  (license 5026)
+
+2013-02-28 21:58 +0000 [r382296-382298]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: While the ICE negotiation is occurring
+	  leave strictrtp in an open state, media can and will come from
+	  different places.
+
+	* res/res_rtp_asterisk.c: Fix a bug with ICE and strictrtp where
+	  media could get dropped. If the end result of the ICE negotiation
+	  resulted in the path for media changing it was possible for the
+	  strictrtp code to discard the RTP packets. This change causes
+	  strictrtp to enter learning mode once again when the ICE
+	  negotiation has completed successfully.
+
+2013-02-28 17:16 +0000 [r382230-382234]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_iax2.c: Prevent deadlock in chan_iax2 when
+	  attempting to set caller ID A deadlock can occur in chan_iax2
+	  when it attempts to set the caller ID, as it already holds the
+	  iax2 private lock and improperly fails to obtain the channel lock
+	  before calling ast_set_callerid. By not safely obtaining the
+	  channel lock, a locking inversion can take place, causing a
+	  deadlock. This patch solves this by calling the required deadlock
+	  avoidance functions that obtain the channel lock before setting
+	  the caller ID. Thanks to Pavel for fixing my syntax errors and
+	  testing this patch out. (closes issue ASTERISK-21128) Reported
+	  by: Pavel Troller Tested by: Pavel Troller patches:
+	  ASTERISK-21128-1.8.diff uploaded by mjordan (license 6283)
+	  ASTERISK-21128-modified-1.8.diff uploaded by Pavel Troller
+	  (license 6302) ........ Merged revisions 382233 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, apps/app_meetme.c, UPGRADE.txt: Let channels joining a MeetMe
+	  conference opt out of the denoiser For some channel drivers,
+	  specifically those that have a varying rate in the number of
+	  audio samples, the audio quality for a MeetMe conference can be
+	  exceedingly poor. This is due to a unilateral application of the
+	  DENOISE function in func_speex to channels joining the
+	  conference. The denoiser function in the speex library is
+	  initialized with the number of audio samples in each sample that
+	  will be provided to it. If the number of audio samples changes,
+	  the denoiser has to be thrown away and re-initialized. While this
+	  could be worked around by removing func_speex, that doesn't help
+	  if you actually use the denoiser with other channels on the
+	  system. This patches does the following: * Checks for the
+	  presence of func_speex as opposed to codec_speex when determining
+	  if the DENOISE function is present (which is where the function
+	  is actually implemented) * Adds an option to MeetMe 'n' that
+	  causes the denoiser to not be applied to a channel when it joins.
+	  This keeps the current behavior the default, but let's users
+	  disable the denoiser if it causes problems on their system.
+	  Review: https://reviewboard.asterisk.org/r/2358 (closes issue
+	  AST-1062) Reported by: Thomas Arimont ........ Merged revisions
+	  382227 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-27 16:17 +0000 [r382151-382174]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: Relax dialog checking in
+	  get_sip_pvt_byid_locked so it works when the dialog is forked.
+	  (closes issue ASTERISK-20638) Reported by: eelcob Patches:
+	  pedantic-call-pickup-from-tag.patch uploaded by eelcob (license
+	  6442) ........ Merged revisions 382171 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* configure, include/asterisk/autoconfig.h.in: Regenerate the
+	  configure script. The one in the tree was not working for me at
+	  all.
+
+2013-02-26 19:45 +0000 [r382111]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, configure, configure.ac: Consider linux-gnuspe as linux-gnu *
+	  The powerpcspe Linux port uses linux-gnuspe as the OS string. *
+	  Our build system shouldn't really care for that, so just call it
+	  linux-gnu. * Original report: Roland Stigge ,
+	  http://bugs.debian.org/701505 Review:
+	  https://reviewboard.asterisk.org/r/2357/ ........ Merged
+	  revisions 382110 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-26 19:34 +0000 [r382108]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Correct RPID parsing for unquoted
+	  display-name. Parsing Remote-Party-ID will now succeed if
+	  display-name is of the *(token LWS) kind and not just the
+	  quoted-string kind. Review:
+	  https://reviewboard.asterisk.org/r/2341/ ........ Merged
+	  revisions 382107 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-26 19:19 +0000 [r382096]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, main/Makefile: Remove unneeded linux-gnueabi* As of r380521
+	  the configure scripts converts the value of linux-gnueabi* of
+	  OSARCH to "linux-gnu". So no point in testing for those values.
+	  ........ Merged revisions 382087 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-26 15:38 +0000 [r382066-382069]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_confbridge.c: Fix typo in r382068 Well, that was
+	  embarrassing. Removed an '-l' that somehow got in there.
+
+	* apps/app_confbridge.c: Clean up ConfBridge commands to account
+	  for wait_marked users When ConfBridge was refactored to better
+	  handle the concept of marked, wait_marked, and normal users
+	  co-existing in a conference (thereby implementing a state machine
+	  for the conference), the wait_marked users were put into their
+	  own list of conference participants, separate from the active
+	  users. This list is used for wait_marked users when they are
+	  waiting in a conference but no marked user has joined; normal
+	  users may have joined at this point however. There are several
+	  AMI/CLI commands that affect conference users that were not
+	  checking the wait_marked users list: * CLI/AMI commands that
+	  mute/unmute a participant. In this case, wait_marked users have
+	  to remain in their particular state and should not be affected -
+	  however, the commands would return "Channel not found" as opposed
+	  to the appropriate error condition. * CLI/AMI commands that kick
+	  a participant. An admin should always be able to kick a
+	  participant out of the conference. This patch fixes both sets of
+	  commands, and cleans up the CLI commands slightly by allowing
+	  them to complete a participant name (this was supposed to have
+	  been added, but the function call was commented out and wasn't
+	  implemented). Review: https://reviewboard.asterisk.org/r/2346/
+	  (closes issue AST-1114) Reported by: John Bigelow Tested by: John
+	  Bigelow
+
+	* apps/confbridge/conf_config_parser.c,
+	  configs/confbridge.conf.sample: Ensure that the default
+	  bridge/user profiles are always available ConfBridge and Page
+	  require that there always be a default bridge and user profile
+	  available. While properties of the default profiles can be
+	  overriden in the configuration file, removing them can create
+	  situations where neither application can function properly. This
+	  patch ensures that if an administrator removes the profiles from
+	  the confbridge.conf configuration file, the profiles are added
+	  upon load. Documentation clarifying this has been added to the
+	  confbridge.conf.sample file. Review:
+	  https://reviewboard.asterisk.org/r/2356/ (closes issue AST-1115)
+	  Reported by: John Bigelow Tested by: John Bigelow
+
+2013-02-25 12:50 +0000 [r381917-382022]  Matthew Jordan <mjordan at digium.com>
+
+	* addons/res_config_mysql.c, /: Clean up use of va_end/va_args in
+	  res_config_mysql There were several problems using variadic
+	  argument macros in res_config_mysql. * Improper use of va_end.
+	  Multiple calls to va_end were possible resulting in an unbalanced
+	  matching of va_start/va_end. * Calls to va_arg after a possible
+	  encounter of a SENTINEL value. This patch corrects those errors.
+	  (closes issue ASTERISK-19451) Reported by: wdoekes patches:
+	  ASTERISK-19451-1.8--2.diff uploaded by wdoekes (License 5674)
+	  ........ Merged revisions 382021 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_jingle.c, /: Set the sin_family on the bind address
+	  socket during initialization Somehow, chan_jingle has managed to
+	  operate for years without setting the sin_family on its bindaddr
+	  socket. This patch properly sets the field during initial module
+	  load to AF_INET. Note that the patch on the issue was modified
+	  slightly to change the initialization of the socket from
+	  allocation of a chan_jingle private to the module initialization,
+	  as the bindaddr object (which is static) only needs to have the
+	  address set once. (closes issue ASTERISK-19341) Reported by:
+	  andre valentin patches: 0105-chan_jingle.patch uploaded by
+	  avalentin (License 6064) ........ Merged revisions 381975 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/manager.c, /: Don't display the AMI ALL class authorization
+	  for users if they don't have it When converting AMI class
+	  authorizations to a string representation, the method always
+	  appends the ALL class authorization. This is especially important
+	  for events, as they should always communicate that class
+	  authorization - even if the event itself does not specify ALL as
+	  a class authorization for itself. (Events have always assumed
+	  that the ALL class authorization is implied when they are raised)
+	  Unfortunately, this did mean that specifying a user with
+	  restricted class authorizations would show up in the 'manager
+	  show user' CLI command as having the ALL class authorization.
+	  Rather then modifying the existing string manipulation function,
+	  this patch adds a function that will only return a string if the
+	  field being compared explicitly matches class authorization field
+	  it is being compared against. This prevents ALL from being
+	  returned unless it is actually specified for the user. (closes
+	  issue ASTERISK-20397) Reported by: Johan Wilfer ........ Merged
+	  revisions 381939 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_parkandannounce.c, /: Make ParkAndAnnounce return to
+	  priority + 1 when return context is not defined The
+	  ParkAndAnnounce application documentation for the optional
+	  return_context parameter states the following: return_context The
+	  goto-style label to jump the call back into after timeout.
+	  Default 'priority+1'. Unfortunately, the application was sending
+	  the channel back into the dialplan at 'priority', which is the
+	  ParkAndAnnounce application call. This causes an infinite loop of
+	  the channel constantly being parked, announced, timed out,
+	  parked, announced, timed out... while fun, especially for those
+	  callers you wish to drive to the end of madness, this was not the
+	  intent of the application. (closes issue ASTERISK-20113) Reported
+	  by: serginuez patches: app_parkandannounce.diff uploaded by
+	  serginuez (License 6405) ........ Merged revisions 381916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-22 19:38 +0000 [r381893]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* res/res_agi.c: Fix FastAGI To Properly Check For A Connection
+	  When IPv6 support was added to FastAGI, the intent was to have
+	  the ability to check all addresses resolved for a host since we
+	  might receive an IPv4 address and an IPv6 address. The problem
+	  with the current code, is that, since we are doing O_NONBLOCK, we
+	  get EINPROGRESS when calling ast_connect() but are ignoring this
+	  instead of handling it. We break out of the loop and continue on.
+	  When we later call ast_poll(), it succeeds but we never check if
+	  we have a connection or not on the socket level. We then attempt
+	  to send data to the host address that we think is setup and it
+	  fails. We then check the errno and see that we have "connection
+	  refused" and then return with agi failed. This patch does the
+	  following: * Handles EINPROGRESS by creating the function
+	  handle_connection() - ast_poll() was moved into this function -
+	  This function checks the results of the connection on the socket
+	  level after calling ast_poll() * Continues to the next address if
+	  the above fails to create a connection * Once all addresses
+	  resolved are tried and we still are unable to establish a
+	  connection, then we return that the FastAGI call failed (closes
+	  issue ASTERISK-21065) Reported by: Jeremy Kister Tested by:
+	  Jeremy Kister, Michael L. Young Patches:
+	  asterisk-21065_poll_correctly_v4.diff Michael L. Young (license
+	  5026) Review: https://reviewboard.asterisk.org/r/2330/
+
+2013-02-22 15:41 +0000 [r381880]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_dial.c: app_dial: Honor the 'c' flag when the calling
+	  party hangs up Apparently this feature became broken in 11,
+	  probably as a result of the Hangup Cause project. (closes issue
+	  ASTERISK-21113) Reprted by: Heiko Wundram Patches: app_dial.patch
+	  uploaded by Heiko Wundram (license 5822)
+
+2013-02-21 22:48 +0000 [r381848]  Matthew Jordan <mjordan at digium.com>
+
+	* /, configure, configure.ac: Properly detect launchd Asterisk was
+	  a little too pro-active in claiming that it found launchd. On
+	  systems without launchd - such as FreeBSD - this resulted in
+	  certain items in Asterisk that conflict with launchd to not be
+	  selectable, such as res_timing_kqueue. (closes issue
+	  ASTERISK-20749) Reported by: Oleg Baranov ........ Merged
+	  revisions 381847 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-20 19:14 +0000 [r381835]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: Let vm_mailbox_snapshot_create's combine
+	  option apply to "Urgent" as well The vm_mailbox_snapshot_create
+	  function has an option that combines the contents of INBOX and
+	  Old into a single snapshot. The intent of this is that both 'new'
+	  messages and 'deleted' messages are given in a single snapshot,
+	  as some applications prefer this view of the voicemail world.
+	  Unfortunately, the initial implementation ignored the "Urgent"
+	  folder. The "Urgent" folder is a pseudo-INBOX, in that new
+	  messages left with the 'U' flag will be placed in that folder as
+	  opposed to INBOX. Thus, the option failed the intent with which
+	  it was added. This patch makes it so that the "Urgent" folder is
+	  included in the snapshot when that option is used.
+
+2013-02-19 19:44 +0000 [r381702-381791]  kharwell <kharwell at localhost>:
+
+	* /, main/features.c: Write the correct callid to the data1 field
+	  in queue_log for transfer events. The incorrect callid was being
+	  written to the "data1" field in queue_log table for transfer
+	  events. The callid of the queue was being written instead of the
+	  transfer target's callid. This now gets the correct "transfer to"
+	  number and places that in the "data1" field of the queue_log
+	  table when a transfer event is triggered. (closes issue
+	  ASTERISK-19960) Reported by: vladimir shmagin ........ Merged
+	  revisions 381770 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* apps/app_confbridge.c: Confbridge channels staying active when
+	  all participants leave. If you started/stopped recording of a
+	  conference multiple times channels would remain active even when
+	  all participants left the conference. This was due to the fact
+	  that a reference to the confbridge was being added every time a
+	  start record command was issued, but when the recording was
+	  stopped there was no matching de-reference thus keeping the
+	  conference alive. Made sure only a single reference is added for
+	  the record thread no matter how many times recording is
+	  started/stopped. A de-reference is issued upon thread ending.
+	  Note, this issue is being fixed under AST-1088 since it relates
+	  to it and should have been corrected along with those
+	  modifications. (issue AST-1088) Reported by: John Bigelow
+
+	* apps/app_confbridge.c: Fixed Confbridge file recording deadlock
+	  and appending. A deadlock occurred after starting/stopping and
+	  then restarting a confbridge recording. Upon starting a recording
+	  a record thread is created that holds a lock until just before
+	  exiting. Stopping the recording does not stop/exit the thread or
+	  release the lock. The thread waits until recording begins again.
+	  Starting a stopped recording signals the thread to continue and
+	  start recording again. However restarting the recording also
+	  created another record thread resulting in a deadlock. The fix
+	  was to make sure the record thread was only created once. Also it
+	  was noted that filenames for the recordings were being
+	  concatenated for each start/stop. This was fixed by creating a
+	  new file for each conference session and appending the actual
+	  recorded data within the file (e.g. passing the 'a' option to
+	  MixMonitor). (issue AST-1088) Reported by: John Bigelow Review:
+	  http://reviewboard.digium.internal/r/374/
+
+2013-02-18 20:30 +0000 [r381669]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, configs/sip.conf.sample: Remove "registertrying" and add
+	  "rtp_engine" from/to sip.conf.sample The "registertrying" option
+	  was removed in r343220. The "rtp_engine" option was added in
+	  r186078 but erroneously named "engine" in the sample. Note that
+	  there is no global sip setting for a different engine. ........
+	  Merged revisions 381668 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-18 19:43 +0000 [r381655]  Jonathan Rose <jrose at digium.com>
+
+	* funcs/func_presencestate.c: PRESENCE_STATE: Provide better
+	  documentation for the 'e' option. Notes that the 'e' option
+	  actually decodes data when used as a write function such as with
+	  the SET application while it encodes data when used to read.
+	  Review: https://reviewboard.asterisk.org/r/2335/
+
+2013-02-16 16:22 +0000 [r381594-381613]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: Don't send presencestate information if the
+	  state is invalid Previously, presencestate information was sent
+	  whenever the state was not NOT_SET. When r381594 actually
+	  returned INVALID presence state in all the places it was supposed
+	  to, it caused chan_sip to start adding presence state information
+	  to NOTIFY requests that it previously would not have added.
+	  chan_sip shouldn't be adding presence state information when the
+	  provider is in an invalid state; users can't set the state to
+	  invalid and an invalid state always implies that the provider is
+	  in an error condition. (issue AST-1084)
+
+	* main/presencestate.c, funcs/func_presencestate.c, main/manager.c:
+	  Fix crash in PresenceState AMI action when specifying an invalid
+	  provider This patch fixes a crash in Asterisk that could be
+	  caused by using the PresenceState AMI action while providing an
+	  invalid provider. This patch also adds some additional warnings
+	  when a user attempts to provide the PresenceState action with
+	  invalid data, and removes some NOTICE statements that were still
+	  lurking in the code from testing. (closes issue AST-1084)
+	  Reported by: John Bigelow Tested by: John Bigelow
+
+2013-02-15 18:42 +0000 [r381566]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Fix a crash that occurred when a BYE was
+	  received on a replaced dialog. Reference counting for the channel
+	  and its tech_pvt got messed up at some point between 1.8 and 11.
+	  The result was that if a BYE for a dialog that had been replaced
+	  (via an INVITE with Replaces) was received, Asterisk would crash
+	  due to trying to access data on a channel that was no longer
+	  there. The fix I introduced is to remove code that both unrefs
+	  the sip_pvt and sets the channel's tech_pvt to NULL when an
+	  INVITE with Replaces is handled. This way when a BYE is received,
+	  the tech_pvt will be non-NULL and so the BYE can be processed and
+	  not cause a crash. (closes issue ASTERISK-20929) reported by
+	  Kristopher Lalletti patches: ASTERISK-20929.patch uploaded by
+	  Mark Michelson (License #5049)
+
+2013-02-15 17:17 +0000 [r381554]  kharwell <kharwell at localhost>:
+
+	* include/asterisk/logger.h, main/autoservice.c, main/logger.c:
+	  Stopped spamming of debug messages during attended transfer.
+	  While autoservice is running and servicing a channel the callid
+	  is being stored and removed in the thread's local storage for
+	  each iteration of the thread loop. If debug was set to a
+	  sufficient level the log file would be spammed with callid thread
+	  local storage debug messages. Added a new function that checks to
+	  see if the callid to be stored is different than what is already
+	  contained (if anything). If it is different then store/replace
+	  and log, otherwise just leave as is. Also made it so all logging
+	  of debug messages pertaining to the callid thread storage outputs
+	  only when TEST_FRAMEWORK is defined. (issue ASTERISK-21014)
+	  (closes issue ASTERISK-21014) Report by: Rusty Newton Review:
+	  https://reviewboard.asterisk.org/r/2324/
+
+2013-02-15 17:12 +0000 [r381553]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c: chan_sip: Use video and text crypto
+	  attributes to append RTP profiles to SDP Some bad copy/pasting
+	  resulted in using the audio crypto attribute for both text and
+	  video RTP. Also the audio crypto isn't set until after these, so
+	  it was really just bad all around. (closes ASTERISK-20905)
+	  Reported by: Kristopher Lalletti patches:
+	  rtp_crypto_video_text.diff uploaded by Jonathan Rose (license
+	  6182)
+
+2013-02-14 19:44 +0000 [r381467]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: End stuck DTMF if AST_SOFTHANGUP_ASYNCGOTO
+	  because it isn't a real hangup. It doesn't hurt to check
+	  AST_SOFTHANGUP_UNBRIDGE either, but it should not be set outside
+	  of a bridge. (issue ASTERISK-20492) ........ Merged revisions
+	  381466 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-14 03:48 +0000 [r381365]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_db.c: Don't throw a spurious error when using
+	  DBdeltree The function call ast_db_deltree returns the number of
+	  row deleted, or a negative number if it failed. DBdeltree was
+	  treating any non-zero return as an error, causing a spurious
+	  verbose error message to be displayed. This patch handles the
+	  return code of ast_db_deltree correctly. (closes issue
+	  ASTERISK-21070) Reported by: ianc patches: dbdeltree.diff
+	  uploaded by ianc (License #5955) ........ Merged revisions 381364
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-12 20:31 +0000 [r381306]  Mark Michelson <mmichelson at digium.com>
+
+	* main/rtp_engine.c, /: Do not allow native RTP bridging if
+	  packetization of media streams differs. The RTP engine will no
+	  longer allow for local and remote native RTP bridges if
+	  packetization of streams differs. Allowing native bridging in
+	  this scenario has been known to cause FAX failures. (closes
+	  ASTERISK-20650) Reported by: Maciej Krajewski Patches:
+	  ASTERISK-20659.patch uploaded by Mark Michelson (License #5049)
+	  Review: https://reviewboard.asterisk.org/r/2319 ........ Merged
+	  revisions 381281 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-12 20:16 +0000 [r381282]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/sip/include/sip.h, channels/chan_sip.c,
+	  channels/sip/security_events.c: Fix some more REF_DEBUG-related
+	  build errors When sip_ref_peer and sip_unref_peer were exported
+	  to be usable in channels/sip/security_events.c, modifications to
+	  those functions when building under REF_DEBUG were not taken into
+	  account. This change moves the necessary defines into sip.h to
+	  make them accessible to other parts of chan_sip that need them.
+
+2013-02-11 20:55 +0000 [r381217]  kharwell <kharwell at localhost>:
+
+	* apps/app_playback.c, /: Properly load say.conf upon reload of
+	  module app_playback. If say.conf did not exists prior to
+	  originally loading module app_playback it would not load on
+	  subsequent reloads of the module once it had been created. This
+	  occurred because upon reload of the app_playback module it would
+	  only load a new configuration if an old one had previously
+	  existed. This fix simply removed the association between checking
+	  if an old configuration existed and the loading of the new one.
+	  (closes issue ASTERISK-20800) Reported by: pgoergler ........
+	  Merged revisions 381216 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-11 15:03 +0000 [r381159]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_xmpp.c: Fix crash in res_xmpp when deleting pubsub node
+	  from CLI An error existed in res_xmpp where it would attempt to
+	  delete attributes from a node that itself was also deleted. Per
+	  the iksemel documentation, attributes added using iks_insert are
+	  copied to the parent node's stack, and will be reclaimed when
+	  that node is itself destroyed. (closes issue ASTERISK-20982)
+	  Reported by: marcelloceschia patches: delete-node-fix.diff
+	  uploaded by marcelloceschia (License 6036)
+
+2013-02-08 17:29 +0000 [r381067]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_confbridge.c: app_confbridge: Fix crash from receiving
+	  an AMI action after ConfBridge unloaded. Unloading ConfBridge
+	  caused the next AMI action received to crash Asterisk. * Add the
+	  missing unregister of AMI action ConfbridgeSetSingleVideoSrc when
+	  ConfBridge is unloaded. (closes issue ASTERISK-20994) Reported
+	  by: Jeremy Kister Patches: jira_asterisk_20994_v11.patch (license
+	  #5621) patch uploaded by rmudgett Tested by: Rusty Newton, Jeremy
+	  Kister
+
+2013-02-06 20:14 +0000 [r380974]  David M. Lee <dlee at digium.com>
+
+	* /, channels/chan_sip.c: Fixed failing test from r380696. When I
+	  added my extensive suite of session timer unit tests, apparently
+	  one of them was failing and I never noticed. If neither Min-SE
+	  nor Session-Expires is set in the header, it was responding with
+	  a Session-Expires of the global maxmimum instead of the
+	  configured max for the endpoint. (issue ASTERISK-20787) ........
+	  Merged revisions 380973 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-06 08:42 +0000 [r380926-380942]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix reload skinny with active devices.
+	  Patch ensures that d->activeline and l->activesub are moved over
+	  to the new device and line so that on callend the appropriate
+	  subs can be found to complete hangup before device resets.
+	  (closes issue ASTERISK-16610) Reported by: wedhorn Tested by:
+	  snuffy, myself Patches: skinny-reloadactive01.diff uploaded by
+	  wedhorn (license 5019)
+
+	* channels/chan_skinny.c: Reset skinny vmexten on reload. Make
+	  skinny reset vmexten '\0' on reload to ensure that it is set to
+	  '\0' if the appropriate item is removed/commented in skinny.conf.
+	  part of ASTERISK-21037 Reported by: snuffy Tested by: snuffy,
+	  myself Patches: part of immed_dial_fix.diff uploaded by snuffy
+	  (license 5024)
+
+2013-02-05 19:09 +0000 [r380854-380894]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_page.c, apps/app_confbridge.c: app_page and
+	  app_confbridge: Fix custom announcement on entering conference.
+	  The Page and ConfBridge custom announcement did not play when
+	  users entered the conference. * Fix the
+	  CONFBRIDGE(user,announcement) file not getting played. The code
+	  to do this got removed accidentally when the ConfBridge code was
+	  restructured to be more state machine like. * Fixed
+	  play_prompt_to_user() doxygen comments. * Fixed the Page A(x) and
+	  n options for the caller. The caller never played the
+	  announcement file and totally ignored the n option. The code to
+	  do this was lost when the application was converted to use
+	  ConfBridge. * Factored out setup_profile_bridge(),
+	  setup_profile_paged(), and setup_profile_caller() routines to
+	  setup ConfBridge profiles. Made each profile setup routine use
+	  the default template if one has not already been setup by
+	  dialplan. (closes issue ASTERISK-20990) Reported by: Jeremy
+	  Kister Tested by: rmudgett
+
+	* apps/confbridge/conf_state_multi_marked.c: app_confbridge: Fix
+	  error messages on exiting conference. A marked user ending a
+	  conference with only end_marked users generates error messages:
+	  ERROR[0000][C-00000000]: confbridge/conf_state.c:47
+	  conf_invalid_event_fn: Invalid event for confbridge user '' * The
+	  MULTI_MARKED state was doing too much when it was kicking out the
+	  end_marked users from the conference. The kicked out users will
+	  clean up after themselves when they exit the conference. (closes
+	  issue ASTERISK-20991) Reported by: Jeremy Kister Tested by:
+	  rmudgett
+
+	* apps/app_page.c: app_page: Fixup application XML documentation
+	  typos and inaccuracies.
+
+	* apps/confbridge/conf_config_parser.c: Because the compiler can
+	  check types with a struct copy and memcpy() cannot.
+
+	* main/dial.c, /: Separate option_types[] from the struct
+	  definition. Updated the option_types[] doxygen comment. ........
+	  Merged revisions 380853 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-02-04 19:50 +0000 [r380816]  Jason Parker <jparker at digium.com>
+
+	* res/pjproject/aconfigure, res/pjproject/build/os-auto.mak.in,
+	  Makefile, res/pjproject/aconfigure.ac, res/Makefile,
+	  res/pjproject/build/common.mak: Fix how we build pjproject. Allow
+	  parallel builds, better tolerate failures, build faster. This
+	  also stops running dependencies before top-level configure has
+	  been run. (closes issue ASTERISK-20815) Review:
+	  https://reviewboard.asterisk.org/r/2292/
+
+2013-01-31 21:42 +0000 [r380735-380736]  Jason Parker <jparker at digium.com>
+
+	* res/pjproject/pjlib/include/pj/config_site.h: Ignore warnings
+	  caused by PJ_TODO()s in pjproject.
+
+	* res/pjproject/pjlib/src/pj/ssl_sock_ossl.c,
+	  res/pjproject/pjlib/src/pj/log.c,
+	  res/pjproject/pjlib/src/pj/pool_buf.c,
+	  res/pjproject/pjsip-apps/src/samples/icedemo.c,
+	  res/pjproject/pjmedia/src/test/test.c: Fix a few compiler
+	  warnings.
+
+2013-01-31 20:10 +0000 [r380698]  David M. Lee <dlee at digium.com>
+
+	* /, channels/chan_sip.c: Process session timers, even if
+	  Session-Expires header is missing Previously, Asterisk only
+	  processed session timer information if both the 'Supported:
+	  timer' and 'Session-Expires' headers were present. However, the
+	  Session-Expires header is optional. If we were to receive a
+	  request with a Min-SE greater than our configured
+	  session-expires, we would respond with a 'Session-Expires' header
+	  that was too small. This patch cleans the situation up a bit,
+	  always processing timer information if the 'Supported: timer'
+	  header is present. (closes issue ASTERISK-20787) Reported by:
+	  Mark Michelson Review: https://reviewboard.asterisk.org/r/2299/
+	  ........ Merged revisions 380696 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-31 19:03 +0000 [r380671-380673]  Jason Parker <jparker at digium.com>
+
+	* res/pjproject/pjsip/build/Makefile,
+	  res/pjproject/pjsip-apps/build/Makefile,
+	  res/pjproject/pjmedia/build/Makefile,
+	  res/pjproject/pjlib-util/build/Makefile,
+	  res/pjproject/pjlib/build/Makefile,
+	  res/pjproject/pjnath/build/Makefile: Add support for parallel
+	  builds of pjproject. Also adds proper dependency checking, and
+	  direct .a file targets. We don't take advantage of this
+	  currently, but we will soon. (issue ASTERISK-20815)
+
+	* res/pjproject/aconfigure, res/pjproject/aconfigure.ac: Always
+	  check for libm, regardless of configure options.
+
+	* res/pjproject/aconfigure, res/pjproject/aconfigure.ac,
+	  res/pjproject/build/cc-auto.mak.in,
+	  res/pjproject/build/rules.mak: Remove a cross-compile workaround.
+	  ar and ranlib can be easily detected with autoconf.
+
+2013-01-31 00:30 +0000 [r380575-380612]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, include/asterisk/channel.h: Make CHECK_BLOCKING() debug
+	  message more useful. Change the displayed pthread value to hex
+	  format so it can be easily matched with CLI core show threads or
+	  gdb. ........ Merged revisions 380611 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Fix "dahdi show channels
+	  group" for groups greater than 31. The variable type used was not
+	  large enough to hold a group bit field. ........ Merged revisions
+	  380572 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-03-27  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.3.0-rc2 Released.
+
+	* app_confbridge: Fix error messages on exiting conference.
+	
+	  A marked user ending a conference with only end_marked users
+	  generates error messages:
+	  ERROR[0000][C-00000000]: confbridge/conf_state.c:47
+	  conf_invalid_event_fn: Invalid event for confbridge user ''
+
+	  The MULTI_MARKED state was doing too much when it was kicking out
+	  the end_marked users from the conference.  The kicked out users
+	  will clean up after themselves when they exit the conference.
+
+	* app_page and app_confbridge: Fix custom announcement on entering
+	conference.
+
+	  The Page and ConfBridge custom announcement did not play when users
+	  entered the conference.
+
+	  Fix the CONFBRIDGE(user,announcement) file not getting played. The
+	  code to do this got removed accidentally when the ConfBridge code
+	  was restructured to be more state machine like.
+
+	  Fixed play_prompt_to_user() doxygen comments.
+
+	  Fixed the Page A(x) and n options for the caller.  The caller never
+	  played the announcement file and totally ignored the n option.  The
+	  code to do this was lost when the application was converted to use
+	  ConfBridge.
+
+	  Factored out setup_profile_bridge(), setup_profile_paged(), and
+	  setup_profile_caller() routines to setup ConfBridge profiles. Made
+	  each profile setup routine use the default template if one has not
+	  already been setup by dialplan.
+
+	* app_confbridge: Fix crash from receiving an AMI action after
+	ConfBridge unloaded.
+
+	  Unloading ConfBridge caused the next AMI action received to crash
+	  Asterisk. Add the missing unregister of AMI action
+	  ConfbridgeSetSingleVideoSrc when ConfBridge is unloaded.
+
+	* Fixed Confbridge file recording deadlock and appending.
+
+	  A deadlock occurred after starting/stopping and then restarting a
+	  confbridge recording.  Upon starting a recording a record thread is
+	  created that holds a lock until just before exiting.  Stopping the
+	  recording does not stop/exit the thread or release the lock.  The
+	  thread waits until recording begins again. Starting a stopped
+	  recording signals the thread to continue and start recording
+	  again.  However restarting the recording also created another
+	  record thread resulting in a deadlock.  The fix was to make sure
+	  the record thread was only created once.
+
+	* Confbridge channels staying active when all participants leave.
+
+	  If you started/stopped recording of a conference multiple times
+	  channels would remain active even when all participants left the
+	  conference.  This was due to the fact that a reference to the
+	  confbridge was being added every time a start record command was
+	  issued, but when the recording was stopped there was no matching
+	  de-reference thus keeping the conference alive. Made sure only a
+	  single reference is added for the record thread no matter how
+	  many times recording is started/stopped.  A de-reference is
+	  issued upon thread ending.
+
+	* Let vm_mailbox_snapshot_create's combine option apply to "Urgent"
+	as well
+
+	  The vm_mailbox_snapshot_create function has an option that combines
+	  the contents of INBOX and Old into a single snapshot. The intent
+	  of this is that both 'new' messages and 'deleted' messages are given
+	  in a single snapshot, as some applications prefer this view of the
+	  voicemail world. Unfortunately, the initial implementation ignored the
+	  "Urgent" folder. The "Urgent" folder is a pseudo-INBOX, in that new
+	  messages left with the 'U' flag will be placed in that folder as
+	  opposed to INBOX. Thus, the option failed the intent with which it
+	  was added.
+
+	* Fix comparison of presence state in event subsystem.
+
+	  Several new IEs were not given types (or names), causing the
+	  comparison function to improperly succeed.  This adds those.
+
+	* Let vm_mailbox_snapshot combine "Urgent" when no folder is specified
+
+	  r381835 fixed a bug in vm_mailbox_snapshot where combining INBOX and
+	  Old forgot that Urgent also "counts" as new messages. This fixed the
+	  problem when any of the three folders was specified and the combine
+	  option was used. It missed the case where the folder isn't specified
+	  and we build a snapshot of all folders. This patch corrects that.
+
+	* Do not allow native RTP bridging if packetization of media streams
+	differs.
+
+	The RTP engine will no longer allow for local and remote native RTP
+	bridges	if packetization of streams differs. Allowing native bridging
+	in this	scenario has been known to cause FAX failures.
+
+	* Resolve deadlock between pending CDR and batch CDR locks
+
+	r375757 attempted to resolve a race condition between multiple
+	submissions of CDRs while in batch mode from attempting to destroy the
+	scheduled batch	submission by extending the batch CDR lock. Unfortunately,
+	this causes a deadlock between the pending CDR lock and the batch CDR lock.
+	This patch resolves the intent of r375757 by simply providing a new lock
+	that protects the scheduling of the batches. The original batch CDR lock
+	is kept to protect manipulation of the batch CDR settings, but has been
+	placed such that it is not held when the pending lock is held.
+
+	Thanks to Chase Venters for providing lock analysis on the issue.
+
+	* Resolve deadlock between SIP registration and channel based
+	functions
+
+	In r373424, several reentrancy problems in chan_sip were addressed. As
+	a result, the SIP channel driver is now properly locking the channel
+	driver private information in certain operations that it wasn't previously.
+	This exposed two latent problems either in register_verify or by functions
+	called by register_verify. This includes:
+	 * Holding the private lock while calling sip_send_mwi_to_peer. This
+	 can create a new sip_pvt via sip_alloc, which will obtain the channel
+	 container lock. This is a locking inversion, as any channel related lock
+	 must be obtained prior to obtaining the SIP channel technology private
+	 lock.
+	 * Holding the private lock while calling sip_poke_peer. In the same vein as
+         sip_send_mwi_to_peer, sip_poke_peer can create a new SIP private, causing
+         the same locking inversion.
+
+	Note that this locking inversion typically occured when CLI commands were run
+	while a SIP REGISTER request was being processed, as many CLI commands (such
+	as 'sip show channels', 'core show channels', etc.) have to obtain the channel
+	container lock.
+
+	* AST-2013-001: Prevent buffer overflow through H.264 format negotiation
+
+	  The format attribute resource for H.264 video performs an unsafe read
+	  against a media attribute when parsing the SDP. The value passed in with
+	  the format attribute is not checked for its length when parsed into a fixed
+	  length buffer. This patch resolves the vulnerability by only reading
+	  as many characters from the SDP value as will fit into the buffer.
+
+	* AST-2013-002: Prevent denial of service in HTTP server
+
+	AST-2012-014, fixed in January of this year, contained a fix for
+	Asterisk's HTTP server for a remotely-triggered crash. While the fix put in
+	place fixed the possibility for the crash to be triggered, a denial of
+	service vector still exists with that solution if an attacker sends one or
+	more HTTP POST requests with very large Content-Length values. This patch
+	resolves this by capping the Content-Length at 1024 bytes. Any attempt to send
+	an HTTP POST with Content-Length greater than this cap will not result in any
+	memory allocation. The POST will be responded to with an HTTP 413 "Request
+	Entity Too Large" response.
+
+	This issue was reported by Christoph Hebeisen of TELUS Security Labs
+
+	* AST-2013-003: Prevent username disclosure in SIP channel driver
+
+	When authenticating a SIP request with alwaysauthreject enabled,
+	allowguest disabled, and autocreatepeer disabled, Asterisk discloses whether
+	a user exists for INVITE, SUBSCRIBE, and REGISTER transactions in
+	multiple ways. The information is disclosed when:
+	 * A "407 Proxy Authentication Required" response is sent instead of a
+	   "401 Unauthorized" response
+	 * The presence or absence of additional tags occurs at the end of
+	   "403 Forbidden" (such as "(Bad Auth)")
+	 * A "401 Unauthorized" response is sent instead of "403 Forbidden"
+	   response after a retransmission
+	 * Retransmission are sent when a matching peer did not exist, but not
+	   when a matching peer did exist.
+	This patch resolves these various vectors by ensuring that the responses sent
+	in all scenarios is the same, regardless of the presence of a matching peer.
+
+	This issue was reported by Walter Doekes, OSSO B.V. A substantial portion of
+	the testing and the solution to this problem was done by Walter as well - a
+	huge thanks to his tireless efforts in finding all the ways in which this
+	setting didn't work, providing automated tests, and working with Kinsey on
+	getting this fixed.
+
+	* Fix white noise on SRTP decryption
+
+	When res_rtp_asterisk.c was altered to avoid attempting to apply
+	unprotect algorithms to non-audio RTP packets, the test used was
+	incorrect. This caused the audio packets to not be decrypted and
+	resulted in loud white noise on the other endpoint (or both endpoints
+	depending on the call legs involved). The test now properly checks the
+	version field in the RTP header to ensure that RTP and RTCP are
+	decrypted while other types of packets are not.
+
+2013-01-30  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.3.0-rc1 Released.
+
+2013-01-30 17:46 +0000 [r380452-380521]  Matthew Jordan <mjordan at digium.com>
+
+	* /, configure, include/asterisk/autoconfig.h.in, configure.ac:
+	  Support building Asterisk for Raspberry Pi/Raspbian with
+	  hard-float support Building Asterisk on Raspbian with hard-float
+	  support fails as it uses the string 'linux-gnueabihf' for host
+	  os, as opposed to 'linux-gnueabi'. This patch modifies the
+	  configure script for Asterisk such that it will match on any
+	  string beginning with 'linux-gnueabi', as opposed to requiring an
+	  explicit match. (closes issue ASTERISK-21006) Reported by:
+	  Christian Hesse Tested by: Christian Hesse patches:
+	  linux-gnueabihf.patch uploaded by Christian Hesse (license 6459)
+	  linux-gnueabihf-autoconf.patch uploaded by Christian Hesse
+	  (license 6459) ........ Merged revisions 380520 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_sip.c: Unregister SIP provider API if module load
+	  is declined A user in #asterisk ran into a problem where a
+	  configuration error prevented the chan_sip module from being
+	  loaded. Upon fixing their configuratione error, they could no
+	  longer load the chan_sip module. This was because the
+	  configuration checking happened after the SIP provider was
+	  registered with the Asterisk core, and subsequent attempts to
+	  load the SIP module failed as the provider was already
+	  registered. Since we want to detect any failure in registering
+	  chan_sip as early as possible (as that could be emblematic of a
+	  deeper mismatch between module and Asterisk core), this patch
+	  does not change the registration location, but does ensure that
+	  if a module load is declined, we unregister the module as the SIP
+	  api provider.
+
+	* /, channels/chan_sip.c: Perform case insensitive comparisons for
+	  T.38 attributes RFC5347 section 2.5.2 states the following: ...
+	  The attribute "T38MaxBitRate" was once incorrectly registered
+	  with IANA as "T38maxBitRate" (lower-case "m"). In accordance with
+	  T.38 examples and common implementation practice, the form
+	  "T38MaxBitRate" SHOULD be generated by implementations conforming
+	  to this package. In general, it is RECOMMENDED that
+	  implementations of this package accept lowercase, uppercase, and
+	  mixed upper/lowercase encodings of all the T.38 attributes. ...
+	  Asterisk currently does not perform case insensitive matching on
+	  the T.38 attributes. This causes the T38MaxBitRate attribute to
+	  be negotiated at 2400 baud instead of 14400 (or whatever value
+	  you actually wanted). This patch makes it so that when we compare
+	  T.38 attributes, we do so in a case insensitive fashion. Note
+	  that while the issue reporter did not directly write the patch,
+	  they contributed to it (and would have provided one themselves if
+	  the license had gone through a tad faster), and hence get
+	  attribution for it. Review:
+	  https://reviewboard.asterisk.org/r/2298/ (closes issue
+	  ASTERISK-20897) Reported by: Eric Hill Tested by: Eric Hill
+	  patches: -- uploaded by Eric Hill ........ Merged revisions
+	  380458 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* res/res_calendar_icalendar.c, /: Fix memory leak in
+	  res_calendar_icalendar The ICalendar module had a systemic memory
+	  leak on each fetch of data from the ICalendar source. The
+	  previous fetched data was not being properly disposed. This patch
+	  makes it so that before each fetch of data, we dispose of the
+	  previously fetched data. (closes issue ASTERISK-21012) Reported
+	  by: Joel Vandal Tested by: Joel Vandal ........ Merged revisions
+	  380451 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-29 17:54 +0000 [r380384]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_agent.c: chan_agent: Prevent multiple channels
+	  from logging in as the same agent. Multiple channels logging in
+	  as the same agent can result in dead channels waiting for a
+	  condition signal that will never come because another channel
+	  thread stole it. A symptom is chan_sip repeatedly generating
+	  warning messages about rescheduling autodestruction of dialogs
+	  with an agent channel owner. * Made only login_exec() (the app
+	  AgentLogin) clear the agent_pvt->chan pointer to prevent multiple
+	  channels from logging in as the same agent. agent_read(),
+	  agent_call(), and agent_set_base_channel() no longer disconnect
+	  the agent channel from the agent_pvt. This also eliminates the
+	  need to keep checking for agent_pvt->chan being NULL. * Made
+	  agent_hangup() not wake up the AgentLogin agent thread until it
+	  is done. * Made agent_request() not able to get the agent until
+	  he has logged in and any wrapup time has expired. * Made
+	  agent_request() use ast_hangup() instead of agent_hangup() to
+	  correctly dispose of a channel. * Removed
+	  agent_set_base_channel(). Nobody calls it and it is a bad thing
+	  in general. * Made only agent_devicestate() determine the current
+	  device state of an agent. Note: Agent group device states have
+	  never been supported. Review:
+	  https://reviewboard.asterisk.org/r/2260/ ........ Merged
+	  revisions 380364 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-29 17:14 +0000 [r380350]  David M. Lee <dlee at digium.com>
+
+	* channels/sip/sdp_crypto.c, /: Corrected crypto tag in SDP ANSWER
+	  for SRTP. (again) The original fix (r380043) for getting Asterisk
+	  to respond with the correct tag overlooked some corner cases, and
+	  the fact that the same code is in 1.8. This patch moves the
+	  building of the crypto line out of sdp_crypto_process(). Instead,
+	  it merely copies the accepted tag. The call to sdp_crypto_offer()
+	  will build the crypto line in all cases now, using a tag of "1"
+	  in the case of sending offers. (closes issue ASTERISK-20849)
+	  Reported by: José Luis Millán Review:
+	  https://reviewboard.asterisk.org/r/2295/ ........ Merged
+	  revisions 380347 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-29 17:05 +0000 [r380348]  Jonathan Rose <jrose at digium.com>
+
+	* main/features.c: call_parking: Make sure fallbacks are used when
+	  lacking a flat channel exten A regression was introduced which
+	  removed automatic fallback behavior from the PBX. This behavior
+	  was used by call parking (or at least documented as how the
+	  feature works) in order to select an extension when the flat
+	  channel extension wasn't available from the comebackcontext.
+	  Parking now handles the fallbacks internally in order to keep
+	  behavior matching with how it is documented. (closes issue
+	  ASTERISK-20716) Reported by: Chris Gentle Review:
+	  https://reviewboard.asterisk.org/r/2296/
+
+2013-01-29 14:45 +0000 [r380298-380331]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: Ensure that a declined media stream is
+	  terminated with a '\r\n' In r369028, chan_sip's processing of
+	  media streams in an SDP was modified to better handle multiple
+	  offered media streams. Part of that change modified how streams
+	  were declined. Previously, declined media streams were not
+	  handled in an RFC compliant manner; now, we set the port number
+	  to 0 in the media stream definition and proceed on with the next
+	  media stream. Unfortunately, the formatting of the declined media
+	  stream forgot to append a '\r\n' to the end of the media stream.
+	  This is normally added to the accepted media streams later on in
+	  the processing of the SDP. Since the declined media stream uses a
+	  different buffer than the accepted media streams (and is a
+	  malloc'd buffer as opposed to a struct ast_str), it's easier to
+	  just slap the '\r\n' on the declined media stream buffer rather
+	  than attempt to append it later on. So, that's what we do. And
+	  now some devices (and probably some providers) will be a bit
+	  happier (but probably not terribly happy, since we just rejected
+	  something they offered). Review:
+	  https://reviewboard.asterisk.org/r/2297/ (closes issue
+	  ASTERISK-20908) Reported by: Dennis DeDonatis Tested by: Dennis
+	  DeDonatis
+
+	* autoconf/ast_check_pwlib.m4, /, configure: Update configure
+	  script to be compatible with ptlib 2.10.9 With ptlib 2.10.9, the
+	  configure script fails due to grep returning multiple matches for
+	  the pattern it searches for. This patch updates the pattern
+	  matching to return only the actual version for the symbol
+	  searched for, PTLIB_VERSION. (closes issue ASTERISK-20980)
+	  Reported by: Stefan Reuter patches: ASTERISK-20980-1.patch
+	  uploaded by Stefan Reuter (license 5339) ........ Merged
+	  revisions 380297 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-28 21:08 +0000 [r380255]  Sean Bright <sean at malleable.com>
+
+	* /, channels/iax2.h, channels/chan_iax2.c: Correct the number of
+	  available call numbers in IAX2. There is currently an edge case
+	  where call number 32768 might be allocated for a call, even
+	  though the IAX2 protocol requires call numbers be only 15 bits.
+	  This resulted in some unpredictable behavior when call number
+	  32678 is chosen. This patch was mostly written by Richard Mudgett
+	  via ReviewBoard. I'm just committing it. Review:
+	  https://reviewboard.asterisk.org/r/2293/ ........ Merged
+	  revisions 380254 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-28 01:57 +0000 [r380211]  Russell Bryant <russell at russellbryant.com>
+
+	* /, main/file.c: Change cleanup ordering in filestream destructor.
+	  This patch came about due to a problem observed where wav files
+	  had an empty header. The header is supposed to be updated in
+	  wav_close(). It turns out that this was broken when the
+	  cache_record_files option from asterisk.conf was enabled. The
+	  cleanup code was moving the file to its final destination
+	  *before* running the close() method of the file destructor, so
+	  the header didn't get updated. Another problem here is that the
+	  move was being done before actually closing the FILE *. Finally,
+	  the last bug fixed here is that I noticed that wav_close() checks
+	  for stream->filename to be non-NULL. In the previous cleanup
+	  order, it's checking a pointer to freed memory. This doesn't
+	  actually cause anything to break, but it's treading on dangerous
+	  waters. Now the free() of stream->filename is happening after the
+	  format module's close() method gets called, so it's safer.
+	  Review: https://reviewboard.asterisk.org/r/2286/ ........ Merged
+	  revisions 380210 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-27 20:31 +0000 [r380193]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* apps/confbridge/conf_config_parser.c: Fix Some Configured
+	  Conference Bridge Sounds Not Being Set The "sound_only_one" sound
+	  was not being set even though it was configured. In looking into
+	  this, I found that the "join" and "leave" prompts were not being
+	  set either. (closes issue ASTERISK-20898) Reported by: Stephan
+	  Tested by: Stephan Patches:
+	  asterisk-20898-custom-sounds-ignored.diff uploaded by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2289/
+
+2013-01-24 16:39 +0000 [r380043]  David M. Lee <dlee at digium.com>
+
+	* channels/sip/sdp_crypto.c: Corrected crypto tag in SDP ANSWER for
+	  SRTP. When Asterisk responds with an SDP ANSWER for SRTP, it had
+	  the code to correctly fill in the crypto data, which was
+	  overwritten by a call to sdp_crypto_offer. Corrected the
+	  situation by changing sdp_crypto_offer to not replacing crypto
+	  data if it already exists. (closes issue ASTERISK-20849) Reported
+	  by: José Luis Millán Tested by: Iñaki Baz Castillo Patches:
+	  fix_sdp_crypto_tags.diff uploaded by Pedro Kiefer (license 6407)
+
+2013-01-24 04:01 +0000 [r380028]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_confbridge.c: Correct documentation for ConfbridgeList
+	  AMI action The documentation for ConfbridgeList states that the
+	  Conference field is optional. That's not really the case: if you
+	  fail to provide a Conference number, the command will kick back
+	  an error. (closes issue AST-1090) Reported by: John Bigelow
+
+2013-01-23 00:23 +0000 [r379964]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/astobj2.c: Attempt to be more helpful when using a bad
+	  ao2 object pointer. Put the external obj pointer in the message
+	  instead of the internal version. ........ Merged revisions 379963
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-22 22:05 +0000 [r379892-379949]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_fax_spandsp.c: res_fax_spandsp: fix t38 transmission bug
+	  caused by not returning success This patch fixes the problem, but
+	  the issue includes a test which is still being considered for the
+	  automated test suite. (issue ASTERISK-20919) Reported by: NITESH
+	  BANSAL Patches: patch_ast_fax_spandsp.patch uploaded by NITESH
+	  BANSAL (license 6418)
+
+	* /, apps/app_meetme.c, sounds/Makefile: app_meetme: Use new
+	  prompts for administrator menu The old prompts for the
+	  administrator menu were inadequate. They didn't mention that the
+	  menu had additional options through the 8 key and pressing the 8
+	  key wouldn't reveal what those options were. This patch fixes all
+	  of that while also organizing code pertaining to each individual
+	  menu type which was previously all stored in one gigantic
+	  function along with many of the basic conference functions.
+	  (closes issue AST-996) Reported by: John Bigelow Review:
+	  http://reviewboard.digium.internal/r/360/ ........ Merged
+	  revisions 379885 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-22 14:51 +0000 [r379826]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_meetme.c: Fix station ringback; trunk hangup issues
+	  in SLA This patch fixes two bugs: * If an outbound call is made
+	  from a SLA phone using SLAStation, then there is no ringtone
+	  audible to the phone that originates the call. The indication of
+	  the ringing was not being passed to the SLA station; this patch
+	  fixes that by passing through the progress indications. * If an
+	  SLA station hangs up before the called party answers, then the
+	  channel to the called party continues to ring until a timeout
+	  occurs. If the called party manages to answer, Asterisk attempts
+	  to connect the called party to a non-existant MeetMe room. This
+	  patch corrects the behavior by abandoning the call attempt if it
+	  detects that the SLA station is no longer in use while attempting
+	  to call the called party. Review:
+	  https://reviewboard.asterisk.org/r/2275/ (closes issue
+	  ASTERISK-20462) Reported by: dkerr patches:
+	  asterisk-11-bugid20440+20462.patch uploaded by dkerr (license
+	  5558) asterisk-11-bugid20462.patch uploaded by dkerr (license
+	  5558) (closes issue ASTERISK-20440) Reported by: dkerr patches:
+	  asterisk-11-bugid20440.patch uploaded by dkerr (license 5558)
+	  asterisk-11-bugid20440+20462.patch uploaded by dkerr (license
+	  5558) ........ Merged revisions 379825 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-22 00:35 +0000 [r379808]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_bridge.c, apps/app_confbridge.c: confbridge: Minor
+	  fixes playing user counts to the conference. * Generate a warning
+	  message if sound files do not exist when trying to play the user
+	  count to the conference. Use the new helper routine
+	  sound_file_exists() for consistency. * Put the new user into
+	  autoservice when playing user counts to the conference. * Check
+	  the return value of ast_bridge_impart().
+
+2013-01-21 20:40 +0000 [r379790]  Matthew Jordan <mjordan at digium.com>
+
+	* contrib/scripts/safe_asterisk, main/asterisk.c,
+	  contrib/init.d/rc.suse.asterisk,
+	  contrib/init.d/rc.mandriva.asterisk,
+	  contrib/init.d/rc.debian.asterisk, /,
+	  contrib/init.d/rc.redhat.asterisk, UPGRADE.txt,
+	  contrib/init.d/rc.gentoo.asterisk,
+	  contrib/init.d/rc.slackware.asterisk,
+	  contrib/init.d/rc.archlinux.asterisk: Update init.d scripts to
+	  handle stderr; readd splash screen for remote consoles When
+	  r376428 was commited to re-order start up sequences to be more
+	  tolerant of forking with thread primitives, a few items were
+	  changed that caused changes in behavior on some distros. This
+	  includes: * Not displaying the splash screen on a remote console.
+	  * Displaying an error message on stderr when a remote console
+	  cannot connect to a running instance of Asterisk. In the first
+	  case, the splash screen was re-added (thanks to Michael L.
+	  Young). In the second case, the various init.d scripts were
+	  modified to pipe stderr to /dev/null, as the error message is
+	  useful - if you execute a remote console or a remote console
+	  command execution and it fail, it should tell you. Note that the
+	  error message was always present, it just failed to be printed
+	  prior to r376428. Much thanks to the folks who quickly reported
+	  this problem, provided solutions, and promptly tested the various
+	  init.d scripts on a variety of distros. (closes issue
+	  ASTERISK-20945) Reported by: Warren Selby Tested by: Michael L.
+	  Young, Jamuel Starkey, kaldemar, Danny Nicholas, mjordan patches:
+	  asterisk-20945-remote-intro-msg.diff uploaded by elguero (license
+	  5026) ASTERISK-20945-1.8-mjordan.diff uploaded by mjordan
+	  (license 6283) ........ Merged revisions 379760 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 379777 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-01-21 18:33 +0000 [r379719]  Kinsey Moore <kmoore at digium.com>
+
+	* /, codecs/codec_ilbc.c: Prevent segfault for interpolated iLBC
+	  frames When iLBC is being used with a jitter buffer and the jb
+	  has to interpolate frames, it generates frames with a null
+	  pointer and a non-zero datalen. This is now handled properly.
+	  (closes issue ASTERISK-20914) Reported By: John McEleney Patches:
+	  ASTERISK-20914-1.8.diff uploaded by Matt Jordan (license 6283)
+	  ........ Merged revisions 379718 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-21 06:27 +0000 [r379677]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix device call logging issues in skinny
+	  Skinny device call logging (ie missed, place and received calls)
+	  has issues because the incorrect sequence of callstates is/can be
+	  sent to the device. This patch removes some extra callstate
+	  updates driven by forces external to skinny and ensures the
+	  needed intermediary callstate messages are sent. (closes issue
+	  ASTERISK-20964) Reported by: wedhorn Tested by: snuffy, myself
+	  Patches: ast11-skinny-calllog01.diff uploaded by wedhorn (license
+	  5019)
+
+2013-01-21 04:39 +0000 [r379643]  Andrew Latham <lathama at gmail.com>
+
+	* contrib/scripts/install_prereq: Add LDAP libraries to install
+	  script Add LDAP dev package to Debian/Ubuntu install list.
+	  Existed in Redhat already. (issue ASTERISK-20886)
+
+2013-01-21 04:07 +0000 [r379609]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_minivm.c: Fix crash in app_minivm when mime encoding
+	  string An incorrect string initializations was left in
+	  ast_str_encode_mime from the patch that converted string
+	  manipulations to use ast_str strings (r191140). The string
+	  initialization causes a crash when ast_str_set is called on the
+	  string later on in the function. (closes issue ASTERISK-18697)
+	  Reported by: Chris Boot patches:
+	  minivm-null-pointer-dereference-fix.patch uploaded by bootc
+	  (license 6309) (issue ASTERISK-20854) Reported by: Chris Warr
+	  Tested by: Chris Warr ........ Merged revisions 379608 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-20 02:53 +0000 [r379582]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix issues with skinny sessions Fixes a
+	  couple of issues with the way skinny handles sessions by ensuring
+	  sessions aren't used after being freed. Some other minor changes.
+	  Review: https://reviewboard.asterisk.org/r/2272/
+
+2013-01-19 20:49 +0000 [r379548]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, configure, include/asterisk/autoconfig.h.in,
+	  include/asterisk/compat.h, main/strcompat.c, configure.ac: Add
+	  builtin roundf() for systems lacking it. (closes issue
+	  ASTERISK-16854) Review: https://reviewboard.asterisk.org/r/2276
+	  Reported-by: Ovidiu Sas ........ Merged revisions 379547 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-19 00:17 +0000 [r379513]  Matthew Jordan <mjordan at digium.com>
+
+	* main/asterisk.c, /: Fix astcanary startup problem due to wrong
+	  pid value from before daemon call When Asterisk forks itself into
+	  the background via a call to daemon, it must re-set the pid value
+	  of the new process. Otherwise, astcanary gets the pid value of
+	  the process before the fork, which prevents it from running.
+	  Asterisk eventually starts lowering its priority, as it can no
+	  longer communicate with the proverbial canary in the coal mine.
+	  This patch ensures that the correct process identifier is used by
+	  astcanary. Note that this is getting committed to 10 as a
+	  regression fix. (closes issue ASTERISK-20947) Reported by: Jakob
+	  Hirsch Tested by: mjordan patches:
+	  asterisk-10.12.0.astcanary_ppid.diff uploaded by Jakob Hirsch
+	  (license 6113) ........ Merged revisions 379509 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 379510 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-01-18 21:46 +0000 [r379478]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_confbridge.c: Fix regression in Confbridge user count
+	  When the restructuring work got committed to Confbridge in
+	  r375470 to fix many open issues, it caused a regression in the
+	  reported count of users when conference information was requested
+	  via CLI or manager. This corrects the user count and user
+	  information displayed when listing conference information from
+	  the CLI and manager. (closes issue ASTERISK-20938) Reported By:
+	  Timo Teras Patches: confbridge-list.patch uploaded by Timo Teras
+	  (license 5409)
+
+2013-01-18 21:10 +0000 [r379475]  David M. Lee <dlee at digium.com>
+
+	* Makefile, configure, include/asterisk/autoconfig.h.in,
+	  main/Makefile, configure.ac, UPGRADE.txt, makeopts.in: Specify
+	  the -rpath linker flag when prefix != /usr. This allows Asterisk
+	  to start without having to specify the LD_LIBRARY_PATH. This can
+	  be disabled by passing --disable-rpath to configure. (closes
+	  issue ASTERISK-20407) Reported by: David M. Lee Review:
+	  https://reviewboard.asterisk.org/r/2132/
+
+2013-01-18 18:13 +0000 [r379460]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_voicemail.c: app_voicemail: Improve msg_id handling
+	  app_voicemail will no longer issue error messages when it
+	  retrieves an msg_id with a NULL value from realtime and will
+	  instead simply populate the msg_id field with a newly generated
+	  msg_id. In addition, this patch changes the way msg_ids are
+	  generated to eliminate certain causes of duplicate IDs appearing
+	  within a single system. In addition, when messages are copied,
+	  they will now receive a new msg_id. (closes issue ASTERISK-20717)
+	  Reported by: Alec Davis Review:
+	  https://reviewboard.asterisk.org/r/2220/
+
+2013-01-18 05:26 +0000 [r379393]  David M. Lee <dlee at digium.com>
+
+	* channels/sip/include/reqresp_parser.h, /, channels/chan_sip.c,
+	  channels/sip/reqresp_parser.c: Fix Record-Route parsing for large
+	  headers. Record-Route parsing copied the header into a char[256]
+	  array, which can be a problem if the header is longer than that.
+	  This patch parses the header in place, without the copy, avoiding
+	  the issue. In addition to the original patch, I added a unit test
+	  for the new get_in_brackets_const function. (closes issue
+	  ASTERISK-20837) Reported by: Corey Farrell Patches:
+	  chan_sip-build_route-optimized-rev1.patch uploaded by Corey
+	  Farrell (license 5909) (with minor changes by dlee) ........
+	  Merged revisions 379392 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-17 02:30 +0000 [r379343]  Matthew Jordan <mjordan at digium.com>
+
+	* /, addons/chan_mobile.c: Fix issue where chan_mobile fails to
+	  bind to first available port Per the bluez API, in order to bind
+	  to the first available port, the rc_channel field of the socket
+	  addressing structure used to bind the socket should be set to 0.
+	  Previously, Asterisk had set the rc_channel field set to 1,
+	  causing it to connect to whatever happens to be on port 1. We
+	  could probably not explicitly set rc_channel to 0 since we memset
+	  the struct earlier, but explicitly setting it will hopefully
+	  prevent someone from coming in and setting it to some explicit
+	  port in the future. (closes issue ASTERISK-16357) Reported by:
+	  challado Tested by: Alexander Heinz, Nikolay Ilduganov, benjamin,
+	  eliafino, David van Geyn patches: ASTERISK-16357.diff uploaded by
+	  Nikolay Ilduganov (license 6253) ........ Merged revisions 379342
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-16 22:49 +0000 [r379311]  Mark Michelson <mmichelson at digium.com>
+
+	* main/manager.c, /: Further fix misinformation in the description
+	  of manager MailboxStatus command. The description still claimed
+	  that it returned the number of messages rather than whether there
+	  were messages waiting. ........ Merged revisions 379310 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-16 21:13 +0000 [r379277]  Jason Parker <jparker at digium.com>
+
+	* contrib/scripts/install_prereq, /: Reduce number of packages
+	  install_prereq installs on Debian systems. 'search' will look for
+	  any package containing the name provided, so we need to force a
+	  more exact search. ........ Merged revisions 379276 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-16 18:08 +0000 [r379230-379232]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/logger.c: Reduce call-id logging resource usage. Since there
+	  is no need for the call-id logging ao2 object to have a lock,
+	  don't create it with one.
+
+	* channels/chan_misdn.c, /: chan_misdn: Fix compile error. (issue
+	  ASTERISK-15456) ........ Merged revisions 379226 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-16 17:45 +0000 [r379146-379228]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_xmpp.c, res/res_jabber.c, doc/appdocsxml.dtd: Let
+	  documentation reference links specify which module they're
+	  linking to Again, since res_jabber/res_xmpp have duplicate APIs,
+	  their documentation ref links have to specify which reference
+	  they're referring to. The various documentation parsers can
+	  interpret the module attribute however they want in order to
+	  construct the appropriate links.
+
+	* doc/appdocsxml.dtd: Update the dtd to actually *support* the
+	  module attribute in all elements Mea culpa.
+
+	* res/res_xmpp.c, res/res_jabber.c: Add module tags to
+	  documentation for res_jabber/res_xmpp Since res_jabber/res_xmpp
+	  provide the same APIs (app/func/manager/etc.), the XML
+	  documentation for each needs to call out which module is
+	  providing the documentation. The module attribute has been added
+	  to the various XML fragments for this purpose.
+
+	* /, addons/chan_mobile.c: Fix parsing SMSSRC for SMS messages The
+	  parser for SMS messages would incorrectly parse out the from
+	  number. The parsing would incorrectly start scanning for the from
+	  number at the same index as the first double quote ("); this
+	  would inadvertently cause it to treat the first double quote as
+	  the terminating double quote for the from number as well. The
+	  SMSSRC should now populate correctly. (closes issue
+	  ASTERISK-16822) Reported by: menschentier Tested by: Jonas Falck
+	  patches: fixSMSSRC.patch uploaded by jonax (license 6320) (closes
+	  issue ASTERISK-19153) Reported by: Panos Gkikakis patches:
+	  sms-sender-fix.diff uploaded by roeften (license 5884) ........
+	  Merged revisions 379178 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* channels/chan_misdn.c, /: Set the INVALID_EXTEN channel variable
+	  when chan_misdn forces the 'i' extension The chan_misdn channel
+	  driver will send a channel with an invalid destination to the 'i'
+	  extension itself if said extension can be reached. It forgot,
+	  however, to set the INVALID_EXTEN channel variable when it
+	  bounces the channel to this extension. Dialplan writers
+	  everywhere moaned at yet another inconsistency. This is yet
+	  another example of why duplicating logic in multiple places
+	  results in bugs that stick around in Jira for just under three
+	  years. Yes: ASTERISK-15456 was created on January 18th, 2010.
+	  Patch committed on January 15th, 2013. Ouch. (closes issue
+	  ASTERISK-15456) Reported by: Thomas Omerzu patches:
+	  chan_misdn_invalid.patch2 uploaded by Thomas Omerzu (license
+	  5927) ........ Merged revisions 379145 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-14 15:27 +0000 [r379020]  David M. Lee <dlee at digium.com>
+
+	* /, channels/chan_sip.c: Fix XML encoding of 'identity display' in
+	  NOTIFY messages, continued. When r378933 was merged into 1.8, it
+	  should have also escaped remote_display, since it will have the
+	  same XML encoding problem when the caller/callee roles are
+	  reversed. (closes issue ABE-2902) Reported by: Guenther Kelleter
+	  ........ Merged revisions 379001 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-13 21:44 +0000 [r378984]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Reset RTP timestamp; sequence number
+	  on SSRC change In r370252 for ASTERISK-18404, Asterisk's handling
+	  of RTP was modified to better account for out of order RTP
+	  packets. This was accomplished by using the RTP timestamp and
+	  sequence number to check for out of order packets. However, when
+	  a SSRC change occurs, the timestamp and sequence number will no
+	  longer have any relation to the previously received packets. The
+	  variables tracking the timestamp and sequence number therefore
+	  have to be reset. (closes issue ASTERISK-20906) Reported by:
+	  Eelco Brolman patches: dtmf_on_hold.patch uploaded by Eelco
+	  Brolman (license #6442) ........ Merged revisions 378967 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-12 06:36 +0000 [r378934]  David M. Lee <dlee at digium.com>
+
+	* include/asterisk/utils.h, /, channels/chan_sip.c,
+	  tests/test_xml_escape.c (added), main/utils.c: Fix XML encoding
+	  of 'identity display' in NOTIFY messages. XML encoding in
+	  chan_sip is accomplished by naively building the XML directly
+	  from strings. While this usually works, it fails to take into
+	  account escaping the reserved characters in XML. This patch adds
+	  an 'ast_xml_escape' function, which works similarly to
+	  'ast_uri_encode'. This is used to properly escape the
+	  local_display attribute in XML formatted NOTIFY messages. Several
+	  things to note: * The Right Thing(TM) to do would probably be to
+	  replace the ast_build_string stuff with building an ast_xml_doc.
+	  That's a much bigger change, and out of scope for the original
+	  ticket, so I refrained myself. * It is with great sadness that I
+	  wrote my own ast_xml_escape function. There's one in libxml2, but
+	  it's knee-deep in libxml2-ness, and not easily used to one-off
+	  escape a string. * I only escaped the string we know is causing
+	  problems (local_display). At least some of the other strings are
+	  URI-encoded, which should be XML safe. Rather than figuring out
+	  what's safe and escaping what's not, it would be much cleaner to
+	  simply build an ast_xml_doc for the messages and let the XML
+	  library do the XML escaping. Like I said, that's out of scope.
+	  (closes issue ABE-2902) Reported by: Guenther Kelleter Tested by:
+	  Guenther Kelleter Review:
+	  http://reviewboard.digium.internal/r/365/ ........ Merged
+	  revision 378919 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 378933 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-11 23:04 +0000 [r378917]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Retain XMPP filters across reconnections so
+	  external modules continue to function as expected. Previously if
+	  an XMPP client reconnected any filters added by an external
+	  module were lost. This issue exhibited itself with chan_motif not
+	  receiving and reacting to Jingle signaling. (closes issue
+	  ASTERISK-20916) Reported by: kuj
+
+2013-01-09 20:29 +0000 [r378734-378780]  David M. Lee <dlee at digium.com>
+
+	* main/rtp_engine.c, /: Fix end condition in
+	  ast_rtp_lookup_mime_multiple2. The erroneous end condition would
+	  never include the AST_RTP_CISCO_DTMF flag in the debug output.
+	  (closes issue ASTERISK-20772) Reported by: Xavier Hienne ........
+	  Merged revisions 378776 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* include/asterisk/strings.h: Move declaration of
+	  ast_regex_string_to_regex_pattern futher down strings.h. The
+	  prior location is before the declaration of struct ast_str, which
+	  causes compiler warnings. (closes issue ASTERISK-20852) Reported
+	  by: Pavel Troller Patches: strings.diff uploaded by Pavel Troller
+	  (license 6302)
+
+	* /, include/asterisk/causes.h: Replace errant tabs with spaces in
+	  causes.h. (closes issue ASTERISK-20826) Reported by: snuffy
+	  Patches: notabs.dif uploaded by snuffy (license 5024) ........
+	  Merged revisions 378733 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-09 00:03 +0000 [r378687-378690]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_queue.c: app_queue: Fix incorrect assertion. (issue
+	  ASTERISK-16115) ........ Merged revisions 378689 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, configs/queues.conf.sample, UPGRADE.txt, CHANGES,
+	  apps/app_queue.c: app_queue: Fix multiple calls to a queue member
+	  that is in only one queue. When ringinuse=no queue members can
+	  receive more than one call if these calls happen at nearly the
+	  same time. * Fix so a queue member does not receive more than one
+	  call from a queue. NOTE: This fix does not prevent multiple calls
+	  to a member if the member is in more than one queue. * Did some
+	  refactoring to eliminate some code redundancy. (issue
+	  ASTERISK-16115) Reported by: nik600 Patches:
+	  jira_asterisk_16115_single_q_v1.8.patch (license #5621) patch
+	  uploaded by rmudgett Modified * Revert the -r341580 and -r341599
+	  changes adding the queues.conf check_state_unknown option as it
+	  was added in an attempt to fix this problem. The fix did not need
+	  to be optional. The fix should not have tried to explicitly set
+	  the device state. Setting the device state by something other
+	  than the device introduces a race condition. I also could not see
+	  how the change would be effective other than delaying the
+	  app_queue code long enough for the device state to propagate to
+	  app_queue. ........ Merged revisions 378663 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378683 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2013-01-06 20:40 +0000 [r378622]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Rewrite skinny dialing to remove threaded
+	  simpleswitch This rewrite changes skinny dialing from the
+	  threaded simpleswitch to a scheduled timeout approach. There were
+	  some underlying issues with the threaded simple switch with
+	  occasional corruption and possible segfaults. Review:
+	  https://reviewboard.asterisk.org/r/2240/
+
+2013-01-04 23:04 +0000 [r378592]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_srtp.c, /: res_srtp: Prevent a crash from occurring due
+	  to srtp_create failures in srtp_create Under some circumstances,
+	  libsrtp's srtp_create function deallocates memory that it wasn't
+	  initially responsible for allocating. Because we weren't
+	  initially aware of this behavior, this memory was still used in
+	  spite of being unallocated during the course of the
+	  srtp_unprotect function. A while back I made a patch which would
+	  set this value to NULL, but that exposed a possible condition
+	  where we would then try to check a member of the struct which
+	  would cause a segfault. In order to address these problems,
+	  ast_srtp_unprotect will now set an error value when it ends
+	  without a valid SRTP session which will result in the caller of
+	  srtp_unprotect observing this error and hanging up the relevant
+	  channel instead of trying to keep using the invalid session
+	  address. (closes issue ASTERISK-20499) Reported by: Tootai
+	  Review:
+	  https://reviewboard.asterisk.org/r/2228/diff/#index_header
+	  ........ Merged revisions 378591 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-04 22:18 +0000 [r378582]  Kinsey Moore <kmoore at digium.com>
+
+	* res/pjproject/aconfigure, res/pjproject/aconfigure.ac,
+	  res/pjproject/build/common.mak: Fix pjproject compilation in
+	  certain circumstances On a fresh checkout of Asterisk 11, running
+	  make before ./configure could cause the pjproject subdirectory to
+	  get in an odd state that would prevent compilation. This patch by
+	  Tilghman prevents that from occurring. (closes issue
+	  ASTERISK-20681) Reported by: Dinesh Ramjuttun Tested by: danilo
+	  borges, Steve Lang patches: 20121208__ccar_solved.diff.txt
+	  uploaded by Tilghman Lesher (license 5003)
+
+2013-01-04 21:18 +0000 [r378559]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix SIP Notify Messages To Have The
+	  Proper IP Address In The FROM Field On a multihomed server when
+	  sending a NOTIFY message, we were not figuring out which network
+	  should be used to contact the peer. This patch fixes the problem
+	  by calling ast_sip_ouraddrfor() and then build_via() so that our
+	  NOTIFY message contains the correct IP address. Also, a debug
+	  message is being added to help follow the call-id changes that
+	  occur. This was helpful for confirming that the IP address was
+	  set properly since the call-id contains the IP address. It also
+	  will be helpful for troubleshooting purposes when following a
+	  call in the debug logs. (closes issue ASTERISK-20805) Reported
+	  by: Bryan Hunt Tested by: Bryan Hunt, Michael L. Young Patches:
+	  asterisk-20805-notify-ip-v2.diff uploaded by Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/2255/
+	  ........ Merged revisions 378554 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-04 21:16 +0000 [r378555]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Don't pass STUN packets through the
+	  SRTP unprotect function. (closes issue AST-1036) Reported by:
+	  jbigelow ........ Merged revisions 378553 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-03 22:12 +0000 [r378515]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, apps/app_queue.c: Fix Queue Log Reporting Every Call
+	  COMPLETECALLER With "h" Extension Present When the "h" extension
+	  is present within the context of the queue, all calls are being
+	  reported COMPLETECALLER even when the agent is hanging up the
+	  call. This patch checks to see if the agent hung-up or not
+	  instead of only relying on checking if the queue (caller) channel
+	  hung-up or not. It would appear that having the h extension in
+	  the mix, the pbx goes to the h extension, "hanging-up" the queue
+	  channel and triggering the reporting of COMPLETECALLER. (closes
+	  issue ASTERISK-20743) Reported by: call Tested by: call, Michael
+	  L. Young Patches: asterisk-20743-q-cmplt-caller.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2256/ ........ Merged
+	  revisions 378514 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-03 19:41 +0000 [r378487]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_agent.c: chan_agent: Fix wrapup time wait
+	  response. * Made agent_cont_sleep() and agent_ack_sleep() stop
+	  waiting if the wrapup time expires. agent_cont_sleep() had tried
+	  but returned the wrong value to stop waiting. * Made
+	  agent_ack_sleep() take a struct agent_pvt pointer instead of a
+	  void pointer for better type safety. ........ Merged revisions
+	  378486 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-03 18:48 +0000 [r378459]  Kinsey Moore <kmoore at digium.com>
+
+	* main/channel.c, /: Add missing test event This test event was
+	  missing from channel.c causing the dial_LS_options test to fail
+	  intermittently because of a race condition where most code paths
+	  emitted the test event but this one did not. The dial_LS_options
+	  test should stop bouncing now. ........ Merged revisions 378455
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-03 18:44 +0000 [r378428-378457]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_agent.c: chan_agent: Misc code cleanup. * Fix
+	  off-nominal path resource cleanup in agent_request(). * Create
+	  agent_pvt_destroy() to eliminate inlined versions in many places.
+	  * Pull invariant code out of loop in add_agent(). * Remove
+	  redundant module user references in login_exec(). * Remove unused
+	  struct agent_pvt logincallerid[] member. * Remove some redundant
+	  code in agent_request(). ........ Merged revisions 378456 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /, channels/chan_agent.c: chan_agent: Fix agent_indicate()
+	  locking. Avoid deadlock potential with local channels and
+	  simplify the locking. ........ Merged revisions 378427 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-03 15:38 +0000 [r378411]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Prevent exhaustion of system resources through
+	  exploitation of event cache This patch changes res_xmpp to no
+	  longer cache events under certain circumstances. (issue
+	  ASTERISK-20175) Reported by: Russell Bryant, Leif Madsen, Joshua
+	  Colp Tested by: kmoore
+
+2013-01-03 15:36 +0000 [r378376-378409]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_xmpp.c: Prevent crashes in res_xmpp when receiving large
+	  messages Similar to r378287, res_xmpp was marshaling data read
+	  from an external source onto the stack. For a sufficiently large
+	  message, this could cause a stack overflow. This patch modifies
+	  res_xmpp in a similar fashion to res_jabber by removing the stack
+	  allocation, as it was unnecessary. (issue ASTERISK-20658)
+	  Reported by: wdoekes
+
+	* main/config.c, funcs/func_realtime.c, /: Prevent crashes from
+	  occurring when reading from data sources with large values When
+	  reading configuration data from an Asterisk .conf file or when
+	  pulling data from an Asterisk RealTime backend, Asterisk was
+	  copying the data on the stack for manipulation. Unfortunately, it
+	  is possible to read configuration data or realtime data from some
+	  data source that provides a large blob of characters. This could
+	  potentially cause a crash via a stack overflow. This patch
+	  prevents large sets of data from being read from an ARA backend
+	  or from an Asterisk conf file. (issue ASTERISK-20658) Reported
+	  by: wdoekes Tested by: wdoekes, mmichelson patches: *
+	  issueA20658_dont_process_overlong_config_lines.patch uploaded by
+	  wdoekes (license 5674) * issueA20658_func_realtime_limit.patch
+	  uploaded by wdoekes (license 5674) ........ Merged revisions
+	  378375 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-02 21:17 +0000 [r378358]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /, main/features.c, include/asterisk/channel.h:
+	  Fix AMI redirect action with two channels failing to redirect
+	  both channels. The AMI redirect action can fail to redirect two
+	  channels that are bridged together. There is a race between the
+	  AMI thread redirecting the two channels and the bridge thread
+	  noticing that a channel is hungup from the redirects. * Made the
+	  bridge wait for both channels to be redirected before exiting. *
+	  Made the AMI redirect check that all required headers are present
+	  before proceeding with the redirection. * Made the AMI redirect
+	  require that any supplied ExtraChannel exist before proceeding.
+	  Previously the code fell back to a single channel redirect
+	  operation. (closes issue ASTERISK-18975) Reported by: Ben Klang
+	  (closes issue ASTERISK-19948) Reported by: Brent Dalgleish
+	  Patches: jira_asterisk_19948_v11.patch (license #5621) patch
+	  uploaded by rmudgett Tested by: rmudgett, Thomas Sevestre, Deepak
+	  Lohani, Kayode Review: https://reviewboard.asterisk.org/r/2243/
+	  ........ Merged revisions 378356 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2013-01-02 18:30 +0000 [r378337]  Kinsey Moore <kmoore at digium.com>
+
+	* /: Restore branch-1.8-merged on 11 This was accidentally deleted
+	  during a merge.
+
+2013-01-02 18:09 +0000 [r378287-378321]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_calendar.c, include/asterisk/devicestate.h,
+	  channels/chan_local.c, /, main/ccss.c, channels/chan_sip.c,
+	  apps/app_meetme.c, main/channel_internal_api.c,
+	  channels/chan_agent.c, main/devicestate.c,
+	  include/asterisk/channel.h, res/res_jabber.c, apps/app_queue.c,
+	  channels/chan_iax2.c, main/channel.c, channels/chan_dahdi.c,
+	  channels/chan_skinny.c, include/asterisk/event_defs.h,
+	  main/features.c, main/event.c, apps/app_confbridge.c,
+	  apps/confbridge/conf_state_empty.c, funcs/func_devstate.c:
+	  Prevent exhaustion of system resources through exploitation of
+	  event cache Asterisk maintains an internal cache for devices in
+	  the event subsystem. The device state cache holds the state of
+	  each device known to Asterisk, such that consumers of device
+	  state information can query for the last known state for a
+	  particular device, even if it is not part of an active call. The
+	  concept of a device in Asterisk can include entities that do not
+	  have a physical representation. One way that this occurred was
+	  when anonymous calls are allowed in Asterisk. A device was
+	  automatically created and stored in the cache for each anonymous
+	  call that occurred; this was possible in the SIP and IAX2 channel
+	  drivers and through channel drivers that utilized the
+	  res_jabber/res_xmpp resource modules (Gtalk, Jingle, and Motif).
+	  These devices are never removed from the system, allowing
+	  anonymous calls to potentially exhaust a system's resources. This
+	  patch changes the event cache subsystem and device state
+	  management to no longer cache devices that are not associated
+	  with a physical entity. (issue ASTERISK-20175) Reported by:
+	  Russell Bryant, Leif Madsen, Joshua Colp Tested by: kmoore
+	  patches: event-cachability-3.diff uploaded by jcolp (license
+	  5000) ........ Merged revisions 378303 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378320 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c, main/http.c,
+	  res/res_jabber.c: Resolve crashes due to large stack allocations
+	  when using TCP Asterisk had several places where messages
+	  received over various network transports may be copied in a
+	  single stack allocation. In the case of TCP, since multiple
+	  packets in a stream may be concatenated together, this can lead
+	  to large allocations that overflow the stack. This patch modifies
+	  those portions of Asterisk using TCP to either favor heap
+	  allocations or use an upper bound to ensure that the stack will
+	  not overflow: * For SIP, the allocation now has an upper limit *
+	  For HTTP, the allocation is now a heap allocation instead of a
+	  stack allocation * For XMPP (in res_jabber), the allocation has
+	  been eliminated since it was unnecesary. Note that the HTTP
+	  portion of this issue was independently found by Brandon Edwards
+	  of Exodus Intelligence. (issue ASTERISK-20658) Reported by:
+	  wdoekes, Brandon Edwards Tested by: mmichelson, wdoekes patches:
+	  ASTERISK-20658_res_jabber.c.patch uploaded by mmichelson (license
+	  5049) issueA20658_http_postvars_use_malloc2.patch uploaded by
+	  wdoekes (license 5674) issueA20658_limit_sip_packet_size3.patch
+	  uploaded by wdoekes (license 5674) ........ Merged revisions
+	  378269 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 378286 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-31 14:44 +0000 [r378219]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Ensure chan_sip rejects encrypted streams
+	  without crypto info This ensures that Asterisk rejects encrypted
+	  media streams (RTP/SAVP audio and video) that are missing
+	  cryptographic keys and ensures that the incoming SDP is
+	  consistent with RFC4568 as far as having a crypto attribute
+	  present for any SAVP streams. Review:
+	  https://reviewboard.asterisk.org/r/2204/ ........ Merged
+	  revisions 378217 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378218 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-20 21:44 +0000 [r378163-378165]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /: Give the causes[] a struct name. ........
+	  Merged revisions 378164 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* /: Add branch-1.8-merged property to allow direct merging from
+	  v1.8
+
+2012-12-18 17:41 +0000 [r378121]  Kinsey Moore <kmoore at digium.com>
+
+	* main/channel.c, /: Add test events for time limit-related hangups
+	  This patch adds hangup-related test events in order to support
+	  testing of time-limited bridges. This aids in testing the S() and
+	  L() bridge options. (issue SWP-4713) ........ Merged revisions
+	  378119 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 378120 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-17 23:09 +0000 [r378090-378094]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/loader.c, /: Fix potential double free when unloading a
+	  module. ........ Merged revisions 378092 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378093 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_local.c, /: Make chan_local module references tied
+	  to local_pvt lifetime. The chan_local module references were
+	  manually tied to the existence of the ;1 and ;2 channel links. *
+	  Made chan_local module references tied to the existence of the
+	  local_pvt structure as well as automatically take care of the
+	  module references. * Tweaked the wording of the local_fixup()
+	  failure warning message to make sense. Review:
+	  https://reviewboard.asterisk.org/r/2181/ ........ Merged
+	  revisions 378088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378089 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-17 20:58 +0000 [r378073]  Jason Parker <jparker at digium.com>
+
+	* main/Makefile: Make libasteriskssl.so symlink use a relative
+	  path. This was causing issues when using DESTDIR, since the path
+	  to which the link pointed is not likely to exist (and not useful
+	  to exist) on the target system. (issue ASTNOW-284)
+
+2012-12-14 21:32 +0000 [r378038]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_queue.c: app_queue: Revert bad ringinuse=no patch.
+	  With the option ringinuse=no set, the patch committed for
+	  ASTERISK-16115 causes non-SIP queue members to never be called
+	  because the device state is checked after a channel is created to
+	  determine if the member is busy. These queue members always get
+	  the "Member %s is busy, cannot dial" message. Most channel
+	  drivers other than chan_sip use the default device state
+	  handling. The default device-state state is considered in use or
+	  unknown if the channel exists or not respectively. (closes issue
+	  ASTERISK-20801) Reported by: rmudgett Patches:
+	  jira_asterisk_16115_revert_r370418_v1.8.patch (license #5621)
+	  patch uploaded by rmudgett ........ Merged revisions 378036 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 378037 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-14 01:49 +0000 [r378010]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix skinny to recognise vmexten in
+	  general section of conf Fixup the vmexten so if globally set in
+	  general section will be honored by chan_skinny. Also get rid of
+	  the 'global_' part of variable name to match regexten. (closes
+	  issue ASTERISK-20790) Reported by: snuffy Tested by: snuffy,
+	  myself Patches: skinny-vm.diff uploaded by snuffy (license 5024)
+
+2012-12-13 21:04 +0000 [r377993]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/conf_state.c, /,
+	  apps/confbridge/include/confbridge.h,
+	  include/asterisk/bridging.h, apps/app_confbridge.c,
+	  apps/confbridge/conf_state_multi_marked.c: confbridge: Fix MOH on
+	  simultaneous user entry to a new conference. When two users
+	  entered a new conference simultaneously, one of the callers hears
+	  MOH. This happened if two unmarked users entered simultaneously
+	  and also if a waitmarked and a marked user entered
+	  simultaneously. * Created a confbridge internal MOH API to
+	  eliminate the inlined MOH handling code. Note that the conference
+	  mixing bridge needs to be locked when actually starting/stopping
+	  MOH because there is a small window between the conference join
+	  unsuspend MOH and actually joining the mixing bridge. * Created
+	  the concept of suspended MOH so it can be interrupted while
+	  conference join announcements to the user and DTMF features can
+	  operate. * Suspend any MOH until the user is about to actually
+	  join the mixing bridge of the conference. This way any pre-join
+	  file playback does not need to worry about MOH. * Made post-join
+	  actions only play deferred entry announcement files. Changing the
+	  user/conference state during that time is not protected or
+	  controlled by the state machine. (closes issue ASTERISK-20606)
+	  Reported by: Eugenia Belova Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/2232/ ........ Merged
+	  revisions 377992 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-13 20:03 +0000 [r377985-377991]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Minor fixes for chan_skinny Whitespace,
+	  change SUBSTATE_ONHOOK to correct SKINNY_ONHOOK and correct len
+	  of 2 strcmp in skinny_setdebug(). (see opticron's review on
+	  https://reviewboard.asterisk.org/r/2240/)
+
+	* channels/chan_skinny.c: Fix skinny debug tab completion Review
+	  the syntax of the 'skinny debug' command to show more than just
+	  'show' for options to 'skinny debug' command. (closes issue
+	  ASTERISK-20789) Reported by: snuffy Tested by: snuffy, myself
+	  Patches: skinny-debug.diff uploaded by snuffy (license 5024)
+
+2012-12-13 13:51 +0000 [r377948]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Ensure Min-SE is included in outbound
+	  INVITEs Asterisk now includes Min-SE in outbound INVITEs when the
+	  value is not 90 (the default) and session timers are not
+	  disabled. This has the effect of Asterisk following RFC4028 more
+	  closely with regard to 422 responses and preventing situations in
+	  which Asterisk would be forced to temporarily accept a call to
+	  tear it down based on a Session-Expires below the locally
+	  configured Min-SE. (issue SWP-5051) Review:
+	  https://reviewboard.asterisk.org/r/2222/ Reported-by: Kinsey
+	  Moore Patch-by: Kinsey Moore ........ Merged revisions 377946
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 377947 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-12 22:42 +0000 [r377924]  Rusty Newton <rnewton at digium.com>
+
+	* /, sounds/Makefile: Incremented EXTRA_SOUNDS_VERSION in
+	  sounds/Makefile to 1.4.12 for new Extra Sounds releases See
+	  CHANGES-* files in English extra 1.4.12 tarballs for new sound
+	  prompts added. (closes ASTERISK-20328) Reported by: Matt Jordan
+	  (closes AST-755) Reported by: John Bigelow ........ Merged
+	  revisions 377922 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377923 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-11 23:59 +0000 [r377910]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Fix a potential deadlock in chan_sip during
+	  transfers. The issue comes from the fact that transfers may
+	  perform a redirecting update on a channel. The issue is that lock
+	  inversion between the channel and its tech_pvt occurs since the
+	  channel lock is released during the transfer process. The fix is
+	  to move when the redirecting update occurs to a place where
+	  neither the tech_pvt or the channel is locked so that the two can
+	  be locked in the proper order. (closes issue ASTERISK-20708)
+	  reported by Mark Michelson patches: ASTERISK-20708-3.patch
+	  uploaded by Mark Michelson (License #5049) Tested by: Tim
+	  Ringenbach at Asteria Solutions Group
+
+2012-12-11 22:01 +0000 [r377849-377883]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/timing.c, main/channel.c, main/data.c, main/stun.c, /,
+	  main/file.c, main/http.c, main/aoc.c, main/image.c, main/cel.c:
+	  Cleanup CLI commands on exit for several files. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  unregister-cli-multiple-all.patch (license #5909) patch uploaded
+	  by Corey Farrell ........ Merged revisions 377881 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377882 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/udptl.c, /: Cleanup udptl on exit. * Cleanup CLI commands on
+	  exit. (issue ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  udptl-shutdown-1_8-10.patch (license #5909) patch uploaded by
+	  Corey Farrell udptl-shutdown-11-trunk.patch (license #5909) patch
+	  uploaded by Corey Farrell Modified ........ Merged revisions
+	  377847 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377848 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-11 20:51 +0000 [r377843]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_clialiases.c, /: Fix crash that can occur if CLI
+	  registration fails for an aliased command. A recent memory leak
+	  fix in main/cli.c causes an ast_cli_entry's command field to be
+	  freed and NULLed if ast_cli_register() fails. res_clialiases was
+	  ignoring the return value of ast_cli_register() and was then
+	  passing the NULL command off to a a hash function. This resulted
+	  in a crash. The fix is not to ignore the erroneous return value.
+	  If ast_cli_register() fails, then we do not continue trying to
+	  process the current alias. ........ Merged revisions 377840 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377842 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-11 20:45 +0000 [r377706-377839]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/taskprocessor.c: Cleanup taskprocessor on exit. * Cleanup
+	  CLI commands on exit. (issue ASTERISK-20649) Reported by: Corey
+	  Farrell Patches: taskprocessor-cleanup-1_8-11-trunk.patch
+	  (license #5909) patch uploaded by Corey Farrell
+	  taskprocessor-cleanup-10-only.patch (license #5909) patch
+	  uploaded by Corey Farrell Modified ........ Merged revisions
+	  377837 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377838 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/pbx.c, /: Cleanup pbx on exit. * Cleanup CLI commands on
+	  exit. * Unreference hints and statecbs containers on exit. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  pbx-cleanup-1_8.patch (license #5909) patch uploaded by Corey
+	  Farrell pbx-cleanup-10.patch (license #5909) patch uploaded by
+	  Corey Farrell pbx-cleanup-11-trunk.patch (license #5909) patch
+	  uploaded by Corey Farrell Modified ........ Merged revisions
+	  377806 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377807 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/logger.c: Cleanup logger on exit. * Cleanup CLI commands,
+	  destroy verbosers and logchannels lists on exit. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  logger-cleanup-all.patch (license #5909) patch uploaded by Corey
+	  Farrell Modified ........ Merged revisions 377771 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377772 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/indications.c: Cleanup indications on exit. * Made
+	  ast_unregister_indication_country() unlink the found tone zone
+	  before selecting a new default_tone_zone to make it impossible to
+	  select the tone zone being unregistered again. * Ringcadence is
+	  no longer parsed twice in store_config_tone_zone(). * Cleanup CLI
+	  commands and destroy default_tone_zone on exit. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  indications-cleanup-all.patch (license #5909) patch uploaded by
+	  Corey Farrell Modified ........ Merged revisions 377740 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377741 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/event.c: Cleanup event on exit. * Cleanup CLI commands on
+	  exit. (issue ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  event_shutdown-10-only.patch (license #5909) patch uploaded by
+	  Corey Farrell event_shutdown-1_8-11-trunk.patch (license #5909)
+	  patch uploaded by Corey Farrell ........ Merged revisions 377708
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 377709 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/dnsmgr.c, /: Cleanup dnsmgr on exit. * Cleanup dnsmgr thread
+	  and CLI commands on exit. (issue ASTERISK-20649) Reported by:
+	  Corey Farrell Patches: dnsmgr-cleanup-1_8.patch (license #5909)
+	  patch uploaded by Corey Farrell dnsmgr-cleanup-10-11-trunk.patch
+	  (license #5909) patch uploaded by Corey Farrell Modified ........
+	  Merged revisions 377704 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377705 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-10 16:55 +0000 [r377625-377657]  Kinsey Moore <kmoore at digium.com>
+
+	* /, res/res_fax.c: Ensure ReceiveFax provides a CED tone via T.38
+	  When using res_fax_digium, the T.38 CED tone was not being
+	  provided properly which would cause some incoming faxes to fail.
+	  This was not an issue with res_fax_spandsp since it does not
+	  strictly honor the send_ced flag and sends the CED tone whenever
+	  receiving a T.38 fax. (closes issue FAX-343) Reported-by:
+	  Benjamin Tietz Patch-by: Kinsey Moore ........ Merged revisions
+	  377655 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Handle Session-Expires less than local
+	  Min-SE in 200 OK Ensure that a call is immediately torn down if a
+	  Session-Expires value received in a 200 OK is less than the local
+	  Min-SE. This also prevents Asterisk from allowing calls with
+	  Session-Expires below the RFC4028-mandated minimum (90s). (closes
+	  issue ASTERISK-20653) Review:
+	  https://reviewboard.asterisk.org/r/2237/ Patch-by: Kinsey Moore
+	  ........ Merged revisions 377623 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377624 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-10 06:49 +0000 [r377577-377593]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, /: Fix codec mismatch Fix code to send
+	  in both rx and tx open stream messages correct codecs. Found that
+	  on phase 0/1 phones wrong codecs cause to no audio in some
+	  situations. (issue ASTERISK-20183) ........ Merged revisions
+	  377591 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377592 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_unistim.c: Remove trailing whitespaces in number
+	  from incoming redial list. Reported by: Igor Olhovskiy
+
+2013-01-14  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.2.0 Released.
+
+2013-01-09  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.2.0-rc2 Released.
+
+	* Fix pjproject compilation in certain circumstances.
+
+	  On a fresh checkout of Asterisk 11, running make before ./configure
+	  could cause the pjproject subdirectory to get in an odd state that
+	  would prevent compilation. This patch by Tilghman prevents that from
+	  occurring.
+
+	  (closes issue ASTERISK-20681)
+	  Patch-by: Tilghman Lesher
+
+	* AST-2012-014: Resolve crashes due to large stack allocations when
+	  using TCP
+
+	  Asterisk had several places where messages received over various
+	  network transports may be copied in a single stack allocation. In
+	  the case of TCP, since multiple packets in a stream may be
+	  concatenated together, this can lead to large allocations that
+	  overflow the stack.
+
+	  This patch modifies those portions of Asterisk using TCP to either
+	  favor heap allocations or use an upper bound to ensure that the
+	  stack will not overflow:
+	  * For SIP, the allocation now has an upper limit
+	  * For HTTP, the allocation is now a heap allocation instead of a
+	    stack allocation
+	  * For XMPP, the allocation has been eliminated since it was
+	    unnecessary.
+
+	  This patch contains the fix for both res_jabber and res_xmpp.
+
+	* AST-2012-015: Prevent exhaustion of system resources through
+	  exploitation of event cache 
+
+	  Asterisk maintains an internal cache for devices in the event
+	  subsystem. The device state cache holds the state of each device
+	  known to Asterisk, such that consumers of device state information
+	  can query for the last known state for a particular device, even if
+	  it is not part of an active call. The concept of a device in
+	  Asterisk can include entities that do not have a physical
+	  representation. One way that this occurred was when anonymous calls
+	  are allowed in Asterisk. A device was automatically created and
+	  stored in the cache for each anonymous call that occurred; this was
+	  possible in the SIP and IAX2 channel drivers and through channel
+	  drivers that utilized the res_jabber/res_xmpp resource modules (Gtalk,
+	  Jingle, and Motif). These devices are never removed from the system,
+	  allowing anonymous call to potentially exhaust a system's resources.
+
+	  This patch changes the event cache subsystem and device state
+	  management to no longer cache devices that are not associated with a
+	  physical entity.
+
+	* Revert bad ringinuse=no patch.
+
+	  With the option ringinuse=no set, the patch committed previous for
+	  ASTERISK-16115 causes non-SIP queue members to never be called
+	  because the device state is checked after a channel is created to
+	  determine if the member is busy. These queue members always get the
+	  "Member %s is busy, cannot dial" message.
+
+	  Most channel drivers other than chan_sip use the default device
+	  state handling. The default device state is considered in use or
+	  unknown if the channel exists or not, respectively.
+
+	* Fix multiple calls to a queue member that is only in queue.
+
+	  When ringinuse=no queue members can receive more than one call if
+	  these calls happen at nearly the same time. This patch fixes it so a
+	  queu member does not receive more than one call from a queue. note
+	  that this fix does not prevent multiple calls to a member if hte
+	  member is in more than one queue (see ASTERISK-16115).
+
+2012-12-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.2.0-rc1 Released.
+
+2012-12-10 01:41 +0000 [r377505-377511]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* main/xmldoc.c, /: Improve documentation by making all of the
+	  colors used readable, no matter what the background color is.
+	  Dark blue on a black background is unreadable, as is yellow on a
+	  light background. This patch turns on the bright attribute for
+	  colors when on a dark background and turns *off* the bright
+	  attribute when the -W command line option is used (indicating a
+	  _light_ background). This ensures that text is readable in both
+	  cases. Patch by: tilghman Review:
+	  https://reviewboard.asterisk.org/r/2224 ........ Merged revisions
+	  377509 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377510 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, addons/cdr_mysql.c: Remove some dead code and additionally
+	  handle a case that wasn't handled. ........ Merged revisions
+	  377487 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377504 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-09 01:22 +0000 [r377462]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Add missing support for "who hung up" to
+	  chan_motif. (closes issue ASTERISK-20671) Reported by: Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/2208/
+
+2012-12-08 00:29 +0000 [r377401-377433]  Richard Mudgett <rmudgett at digium.com>
+
+	* contrib/realtime/mysql/sippeers.sql, /: Fix order of SIP
+	  allow/disallow in MySQL contrib script. Using the contrib
+	  sippeers.sql script to create the sippeers MySQL table would
+	  result in being unable to place calls if you set the disallow
+	  value to all. (closes issue ASTERISK-20756) Reported by: Andre
+	  Luis Patches: sippeers.patch patch uploaded by Andre Luis
+	  ........ Merged revisions 377431 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377432 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/astmm.c: MALLOC_DEBUG: Only wait if we want atexit
+	  allocation dumps. ........ Merged revisions 377398 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377399 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-07 22:02 +0000 [r377383]  Kinsey Moore <kmoore at digium.com>
+
+	* /, codecs/codec_dahdi.c: codec_dahdi: Fix output of "transcoder
+	  show" CLI command. In r306010 "Asterisk media architecture
+	  conversion - no more format bitfields", the logic for
+	  incrementing encoders and decoders when opening transcoder
+	  channels was changed without making the corresponding change when
+	  decrementing encoder / decoder channels. The result being that
+	  when a channel was destroyed, codec_dahdi couldn't properly tell
+	  if it was an encoder or decoder, and the default case is to
+	  assume it was a decoder. This could result in negative numbers
+	  for decoders in use like in: VOIP6*CLI> transcoder show 2/-2
+	  encoders/decoders of 92 channels are in use. (closes issue
+	  ASTERISK-19921) Patch-by: Shaun Ruffell ........ Merged revisions
+	  377382 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-06 23:58 +0000 [r377355]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/confbridge/conf_config_parser.c, /, apps/app_confbridge.c:
+	  confbridge: Fix some resource leaks on conference teardown. *
+	  Made destroy_conference_bridge() destroy a missed ast_mutex_t and
+	  ast_cond_t. * Made join_conference_bridge() init the
+	  ast_mutex_t's and ast_cond_t so destroy_conference_bridge() can
+	  destroy them unconditionally. * Made join_conference_bridge()
+	  abort if the new conference could not be added to the conferences
+	  container. * Made leave_conference() discard any post-join
+	  actions if join_conference_bridge() had to abort early. * Made
+	  the join_conference_bridge() diagnostic messages better describe
+	  what happened. * Renamed leave_conference_bridge() to
+	  leave_conference() and made it only take a conference user
+	  pointer. The conference pointer was redundant. * Made
+	  conf_bridge_profile_copy() use struct copy instead of memcpy(). *
+	  No need to lock the conference in start_conf_record_thread()
+	  since all of the callers already have it locked. ........ Merged
+	  revisions 377354 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-06 17:28 +0000 [r377340]  Russell Bryant <russell at russellbryant.com>
+
+	* main/named_acl.c: Add CLI tab completion to 'acl show'. The 'acl
+	  show' CLI command allows you to show the details about a specific
+	  named ACL in acl.conf. This patch adds tab completion to the
+	  command. Review: https://reviewboard.asterisk.org/r/2230/
+
+2012-12-06 14:11 +0000 [r377319]  Matthew Jordan <mjordan at digium.com>
+
+	* main/manager.c: Fix memory leak in 'manager show event' when
+	  command entered incorrectly When the CLI command 'manager show
+	  event' was run incorrectly and its usage instructions returned, a
+	  reference to the event container was leaked. This would prevent
+	  the container from being reclaimed when Asterisk exits. We now
+	  properly decrement the count on the ao2 object using the nifty
+	  RAII_VAR macro. Thanks to Russell for helping me stumble on this,
+	  and Terry for writing that ridiculously helpful macro.
+
+2012-12-05 17:08 +0000 [r377262]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_srtp.c, /: res_srtp: Fix a crash caused by srtp_dealloc
+	  on an already dealloced session When srtp_create fails, the
+	  session may be dealloced or just not alloced. At the same time
+	  though, the session pointer might not be set to NULL in this
+	  process and attempting to srtp_dealloc it again will cause a
+	  segfault. This patch checks for failure of srtp_create and sets
+	  the session pointer to NULL if it fails. (closes issue
+	  ASTERISK-20499) Reported by: tootai Review:
+	  https://reviewboard.asterisk.org/r/2228/ ........ Merged
+	  revisions 377256 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377261 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-05 16:50 +0000 [r377259]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: Fix a SIP request memory leak with TLS
+	  connections. During the TLS re-work in chan_sip some TLS specific
+	  code was moved into a separate function. This function operates
+	  on a copy of the incoming SIP request. This copy was never
+	  deinitialized causing a memory leak for each request processed.
+	  This function is now given a SIP request structure which it can
+	  use to copy the incoming request into. This reduces the amount of
+	  memory allocations done since the internal allocated components
+	  are reused between packets and also ensures the SIP request
+	  structure is deinitialized when the TLS connection is torn down.
+	  (closes issue ASTERISK-20763) Reported by: deti ........ Merged
+	  revisions 377257 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377258 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-05 02:19 +0000 [r377213-377244]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/format.c, /: Fix registering core show codecs/codec CLI
+	  commands twice. ........ Merged revisions 377241 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/confbridge/conf_config_parser.c, /: confbridge: Fix several
+	  small issues. * Made func_confbridge_helper() allow an empty
+	  value when setting options. You previously could not
+	  Set(CONFBRIDGE(user,pin)=) and clear the configured pin from the
+	  dialplan. * Made func_confbridge_helper() handle its datastore
+	  better if multiple threads attempt to set the first CONFBRIDGE
+	  option value on the channel. * Made the func_confbridge_helper()
+	  only output one diagnostic message concerning the option. * Made
+	  the bridge video_mode able to repeatedly change in the config
+	  file and CONFBRIDGE dialplan function. The video_mode option
+	  values are an enum and not independent of each other. * Made
+	  handle_cli_confbridge_show_bridge_profile() better handle the
+	  video_mode option. * Simplified datastore handling code in
+	  conf_find_user_profile() and conf_find_bridge_profile(). (closes
+	  issue ASTERISK-20655) Reported by: Birger "WIMPy" Harzenetter
+	  ........ Merged revisions 377227 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_confbridge.c: confbridge: Update online XML
+	  documentation. ........ Merged revisions 377212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-04 12:59 +0000 [r377195]  Russell Bryant <russell at russellbryant.com>
+
+	* contrib/scripts/install_prereq: Add libuuid to install_prereq for
+	  Fedora. I ran this script and my build failed. pjproject requires
+	  this.
+
+2012-12-03 22:58 +0000 [r377039-377167]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/asterisk.c, /: Cleanup ast_run_atexits() atexits list. *
+	  Convert atexits list to a mutex instead of a rd/wr lock. The lock
+	  is only write locked. * Move CLI verbose Asterisk ending message
+	  to where AMI message is output in really_quit() to avoid further
+	  surprises about using stuff already shutdown. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell ........ Merged
+	  revisions 377165 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377166 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/asterisk.c, /, include/asterisk/_private.h,
+	  main/stdtime/localtime.c: Cleanup core main on exit. * Cleanup
+	  time zones on exit. * Make exit clean/unclean report consistent
+	  for AMI and CLI in really_quit(). (issue ASTERISK-20649) Reported
+	  by: Corey Farrell Patches: core-cleanup-1_8-10.patch (license
+	  #5909) patch uploaded by Corey Farrell
+	  core-cleanup-11-trunk.patch (license #5909) patch uploaded by
+	  Corey Farrell Modified ........ Merged revisions 377135 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377136 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/config.c, /: Cleanup config cache on exit. (issue
+	  ASTERISK-20649) Reported by: Corey Farrell Patches:
+	  config-cleanup-all.patch (license #5909) patch uploaded by Corey
+	  Farrell ........ Merged revisions 377104 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377105 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/cli.c, /: Cleanup CLI resources on exit and CLI command
+	  registration errors. (issue ASTERISK-20649) Reported by: Corey
+	  Farrell Patches: cli-leaks-1_8-10.patch (license #5909) patch
+	  uploaded by Corey Farrell cli-leaks-11-trunk.patch (license
+	  #5909) patch uploaded by Corey Farrell Modified ........ Merged
+	  revisions 377073 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377074 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/cdr.c, /: Cleanup CDR resources on exit. * Simplify
+	  do_reload() return handling since it never returned anything
+	  other than 0. (issue ASTERISK-20649) Reported by: Corey Farrell
+	  Patches: cdr-cleanup-1_8.patch (license #5909) patch uploaded by
+	  Corey Farrell cdr-cleanup-10-11-trunk.patch (license #5909) patch
+	  uploaded by Corey Farrell Modified ........ Merged revisions
+	  377069 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 377070 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/ccss.c: Fix CCSS CLI commands and logger level not
+	  unregistered. (issue ASTERISK-20649) Reported by: Corey Farrell
+	  Patches: ccss-cleanup-all.patch (license #5909) patch uploaded by
+	  Corey Farrell ........ Merged revisions 377037 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 377038 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-03 14:54 +0000 [r377021]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Fix an RTP instance reference count leak
+	  in chan_motif. When setting up an RTP instance the RTCP portion
+	  of the instance keeps a reference to the instance itself. In
+	  order to release this reference and stop RTCP the stop API call
+	  must be called before destroying the instance. (closes issue
+	  ASTERISK-20751) Reported by: joshoa
+
+2012-12-01 00:46 +0000 [r376983]  Joshua Colp <jcolp at digium.com>
+
+	* configs/motif.conf.sample, channels/chan_motif.c: Tweak extension
+	  used for incoming calls received on Motif. Based on feedback from
+	  numerous individuals this patch tweaks incoming calls to first
+	  look for an extension with the name of the endpoint. If no such
+	  extension exists the call will silently fall back to the "s"
+	  extension as it previously did.
+
+2012-11-30 21:35 +0000 [r376952]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/misdn/isdn_lib.c: chan_misdn: Fix sending
+	  RELEASE_COMPLETE in response to SETUP. Fix sending a
+	  RELEASE_COMPLETE in response to a SETUP if chan_misdn does not
+	  have a B channel available to assign to the call. (closes issue
+	  ABE-2869) Reported by: Guenther Kelleter Patches:
+	  setup-reject_2.diff (license #6372) patch uploaded by Guenther
+	  Kelleter Modified ........ Merged revision 376949 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 376950 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376951 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-30 17:07 +0000 [r376921]  Sean Bright <sean at malleable.com>
+
+	* /, funcs/func_volume.c: Minor spelling fix to the VOLUME
+	  documentation. ........ Merged revisions 376919 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376920 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-30 16:36 +0000 [r376917]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix potential crashes during SIP attended
+	  transfers. The principal behind this patch is simple. During a
+	  transfer, we manipulate channels that are owned by a separate
+	  thread than the one we currently are running in, so it makes
+	  sense that we need to grab a reference to the channels so that
+	  they cannot disappear out from under us. In the wild, crashes
+	  were sometimes seen when the transferring party would hang up the
+	  call before the transfer target answered the call. The most
+	  common place to see the crash occur was when attempting to send a
+	  connected line update to the transferer channel. (closes issue
+	  ASTERISK-20226) Reported by Jared Smith Patches:
+	  ASTERISK-20226.patch uploaded by Mark Michelson (License #5049)
+	  Tested by: Jared Smith ........ Merged revisions 376901 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-29 22:59 +0000 [r376866-376870]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_local.c, /: chan_local: Fix local_pvt ref leak in
+	  local_devicestate(). Regression introduced by ASTERISK-20390 fix.
+	  (closes issue ASTERISK-20769) Reported by: rmudgett Tested by:
+	  rmudgett ........ Merged revisions 376868 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376869 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Fix compile error. (issue ASTERISK-20724)
+	  ........ Merged revisions 376864 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376865 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-29 21:57 +0000 [r376836]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Improve Code Readability And Fix Setting
+	  natdetected Flag For 1.8, 10, 11 and trunk we are are improving
+	  the code readability. For 11 and trunk, auto nat detection was
+	  added. The natdetected flag was being set to 1 when the host
+	  address in the VIA header did not specifiy a port. This patch
+	  fixes this by setting the port on the temporary sock address used
+	  to SIP_STANDARD_PORT in order for the sock address comparison to
+	  work properly. (closes issue ASTERISK-20724) Reported by: Michael
+	  L. Young Patches: asterisk-20724-set-port-v2.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2206/ ........ Merged
+	  revisions 376834 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376835 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-29 17:17 +0000 [r376822]  Pedro Kiefer <pedro at kiefer.com.br>
+
+	* channels/chan_sip.c: Fix chan_sip websocket payload handling
+	  Websocket by default doesn't return an ast_str for the payload
+	  received. When converting it to an ast_str on chan_sip the last
+	  character was being omitted, because ast_str functions expects
+	  that the given length includes the trailing 0x00. payload_len
+	  only has the actual string length without counting the trailing
+	  zero. For most cases this passed unnoticed as most of SIP
+	  messages ends with \r\n. (closes issue ASTERISK-20745) Reported
+	  by: Iñaki Baz Castillo Review:
+	  https://reviewboard.asterisk.org/r/2219/
+
+2012-11-29 00:46 +0000 [r376760-376790]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/asterisk.c, /, main/astmm.c: Add MALLOC_DEBUG atexit
+	  unreleased malloc memory summary. * Adds the following CLI
+	  commands to control MALLOC_DEBUG reporting of unreleased malloc
+	  memory when Asterisk is shut down. memory atexit list on memory
+	  atexit list off memory atexit summary byline memory atexit
+	  summary byfunc memory atexit summary byfile memory atexit summary
+	  off * Made check all remaining allocated region blocks atexit for
+	  fence violations. * Increased the allocated region hash table
+	  size by about three times. It still isn't large enough
+	  considering the number of malloced blocks Asterisk uses. * Made
+	  CLI "memory show allocations anomalies" use
+	  regions_check_all_fences(). Review:
+	  https://reviewboard.asterisk.org/r/2196/ ........ Merged
+	  revisions 376788 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376789 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/astmm.c: Enhance MALLOC_DEBUG CLI commands. * Fixed CLI
+	  "memory show allocations" misspelling of anomalies option. The
+	  command will still accept the original misspelling. *
+	  Miscellaneous tweaks to CLI "memory show allocations" command
+	  output format. * Made CLI "memory show summary" summarize by line
+	  number instead of by function if a filename is given. * Made CLI
+	  "memory show summary" sort its output by filename or
+	  function-name/line-number depending upon request. * Miscellaneous
+	  tweaks to CLI "memory show summary" command output format.
+	  ........ Merged revisions 376758 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376759 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-28 16:37 +0000 [r376727]  Jonathan Rose <jrose at digium.com>
+
+	* main/manager.c, /: manager: Make challenge work with
+	  allowmultiplelogin=no Prior to this patch, challenge would yield
+	  a multiple logins error if used without providing the username
+	  (which isn't really supposed to be an argument to challenge) if
+	  allowmultiplelogin was set to no because allowmultiplelogin finds
+	  a user with a zero length login name. This check is simply
+	  disabled for the challenge action when the username is empty by
+	  this patch. (closes issue ASTERISK-20677) Reported by: Vladimir
+	  Patches: challenge_action_nomultiplelogin.diff uploaded by
+	  Jonathan Rose (license 6182) ........ Merged revisions 376725
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 376726 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-28 00:08 +0000 [r376629-376690]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /, UPGRADE.txt: Fix extension matching with the '-'
+	  char. The '-' char is supposed to be ignored by the dialplan
+	  extension matching. Unfortunately, it's treatment is not handled
+	  consistently throughout the extension matching code. * Made the
+	  old exten matching code consistently ignore '-' chars. * Made the
+	  old exten matching code consistently handle case in the matching.
+	  * Made ignore empty character sets. * Fixed ast_extension_cmp()
+	  to return -1, 0, or 1 as documented. The only user of it in
+	  pbx_lua.c was testing for -1. It was originally returning the
+	  strcmp() value for less than which is not usually going to be -1.
+	  * Fix character set sorting if the sets have the same number of
+	  characters and start with the same character. Character set [0-9]
+	  now sorts before [02-9a] as originally intended. * Updated some
+	  extension label and priority already in use warnings to also
+	  indicate if the extension is aliased. (closes issue
+	  ASTERISK-19205) Reported by: Philippe Lindheimer, Birger "WIMPy"
+	  Harzenetter Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/2201/ ........ Merged
+	  revisions 376688 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376689 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* addons/res_config_mysql.c, /, apps/app_celgenuserevent.c,
+	  pbx/pbx_dundi.c: Remove unnecessary channel module references. *
+	  Removed call to ast_module_user_hangup_all() in
+	  res_config_mysql.c since it is effectively a noop. No channels
+	  can attach a reference to that module. * Removed call to
+	  ast_module_user_hangup_all() in app_celgenuserevent.c. The caller
+	  of unload_module() has already called it. * Removed redundant
+	  channel module references in pbx_dundi.c. The registered dialplan
+	  function callback dispatchers for the read/read2/write callbacks
+	  already reference the module before calling. * pbx_dundi: Moved
+	  unregistering CLI commands, DUNDi switch, and dialplan functions
+	  to the first thing the unload_module() does. This will reduce the
+	  chance of new channels using DUNDi services while the module is
+	  being torn down. ........ Merged revisions 376657 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376658 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, include/asterisk/linkedlists.h: Made AST_LIST_REMOVE() simpler
+	  and use better names. * Update doxygen of AST_LIST_REMOVE().
+	  ........ Merged revisions 376627 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376628 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-22 23:58 +0000 [r376588]  Matthew Jordan <mjordan at digium.com>
+
+	* main/lock.c, /, main/logger.c, include/asterisk/lock.h:
+	  Re-initialize logmsgs mutex upon logger initialization to prevent
+	  lock errors Similar to the patch that moved the fork earlier in
+	  the startup sequence to prevent mutex errors in the recursive
+	  mutex surrounding the read/write thread registration lock, this
+	  patch re-initializes the logmsgs mutex. Part of the start up
+	  sequence before forking the process into the background includes
+	  reading asterisk.conf; this has to occur prior to the call to
+	  daemon in order to read startup parameters. When reading in a
+	  conf file, log statements can be generated. Since this can't be
+	  avoided, the mutex instead is re-initialized to ensure a reset of
+	  any thread tracking information. This patch also includes some
+	  additional debugging to catch errors when locking or unlocking
+	  the recursive mutex that surrounds locks when the DEBUG_THREADS
+	  build option is enabled. DO_CRASH or THREAD_CRASH will cause an
+	  abort() if a mutex error is detected. (issue ASTERISK-19463)
+	  Reported by: mjordan Tesetd by: mjordan ........ Merged revisions
+	  376586 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 376587 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-20 21:58 +0000 [r376561]  David M. Lee <dlee at digium.com>
+
+	* res/res_http_websocket.c: Added missing newlines to websocket
+	  ast_logs. Without these newlines, log messages just continue
+	  tacking onto the same line, and do not flush immediately.
+
+2012-11-20 18:57 +0000 [r376550]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c: Add "Require:
+	  timer" to 200 OK responses when appropriate. The method by which
+	  the Require header is added to 200 responses is inspired by the
+	  method that Olle Johansson uses in his darjeeling-prack branch.
+	  (closes issue ASTERISK-20570) Reported by Matt Jordan, at the
+	  behest of Olle Johansson Review:
+	  https://reviewboard.asterisk.org/r/2172 ........ Merged revisions
+	  376521 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 376522 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-20 17:37 +0000 [r376540]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* channels/chan_sip.c: Reduce CLI spam of "Extension Changed"
+	  device state messages. Asterisk 11 follows RFC3265 that states
+	  that after every subscribe or resubscribe a notify should be
+	  sent. Thus the console if filled continuously with the following
+	  after every subscribe; == Extension Changed 8512[phones] new
+	  state IDLE for Notify User cisco1 In Asterisk 1.8 only changes
+	  would be sent. Thus only when a device state changed was anything
+	  emitted to the console. fix: Only print to console when device
+	  state isn't forced. (closes issue ASTERISK-20706) Reported by:
+	  alecdavis Tested by: alecdavis alecdavis (license 585)
+
+2012-11-19 19:54 +0000 [r376471]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c, main/security_events.c,
+	  main/indications.c: Fix most leftover non-opaque ast_str uses.
+	  Instead of calling str->str, one should use ast_str_buffer(str).
+	  Same goes for str->used as ast_str_strlen(str) and str->len as
+	  ast_str_size(str). Review:
+	  https://reviewboard.asterisk.org/r/2198 ........ Merged revisions
+	  376469 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 376470 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-18 20:22 +0000 [r376415-376441]  Matthew Jordan <mjordan at digium.com>
+
+	* main/asterisk.c, /, main/utils.c: Reorder startup sequence to
+	  prevent lockups when process is sent to background Although it is
+	  very rare and timing dependent, the potential exists for the call
+	  to 'daemon' to cause what appears to be a deadlock in Asterisk
+	  during startup. This can occur when a recursive mutex is obtained
+	  prior to the daemon call executing. Since daemon uses fork to
+	  send the process into the background, any threading primitives
+	  are unsafe to re-use after the call. Implementations of pthread
+	  recursive mutexes are highly likely to store the thread
+	  identifier of the thread that previously obtained the mutex. If
+	  the mutex was locked prior to the fork, a subsequent unlock
+	  operation will potentially fail as the thread identifier is no
+	  longer valid. Since the mutex is still locked, all subsequent
+	  attempts to grab the mutex by other threads will block. This
+	  behavior exhibited itself most often when DEBUG_THREADS was
+	  enabled, as this compile time option surrounds the mutexes in
+	  Asterisk with another recursive mutex that protects the storage
+	  of thread related information. This made it much more likely that
+	  a recursive mutex would be obtained prior to daemon and unlocked
+	  after the call. This patch does the following: a) It backports a
+	  patch from Asterisk 11 that prevents the spawning of the
+	  localtime monitoring thread. This thread is now spawned after
+	  Asterisk has fully booted. b) It re-orders the startup sequence
+	  to call daemon earlier during Asterisk startup. This limits the
+	  potential of threading primitives being accessed by
+	  initialization calls before daemon is called. c) It removes calls
+	  to ast_verbose/ast_log/etc. prior to daemon being called.
+	  Developers should send error messages directly to stderr prior to
+	  daemon, as calls to ast_log may access recursive mutexes that
+	  store thread related information. d) It reorganizes when thread
+	  local storage is created for storing lock information during the
+	  creation of threads. Prior to this patch, the read/write lock
+	  protecting the list of threads in ast_register_thread would
+	  utilize the lock in the thread local storage prior to it being
+	  initialized; this patch prevents that. On a very related note,
+	  this patch will *greatly* improve the stability of the Asterisk
+	  Test Suite. Review: https://reviewboard.asterisk.org/r/2197
+	  (closes issue ASTERISK-19463) Reported by: mjordan Tested by:
+	  mjordan ........ Merged revisions 376428 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376431 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/confbridge/conf_state.c, /: Add a test event that reports
+	  changes in ConfBridge state This patch adds a test event to
+	  ConfBridge that reports transitions between states in ConfBridge.
+	  This is used by tests in the Asterisk Test Suite that verify
+	  state changes based on the entering/leaving of conference
+	  participants. ........ Merged revisions 376414 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-16 19:59 +0000 [r376391]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_monitor.c, /: monitor: prevent attempts to move/remove
+	  recordings skipped with 'i' and 'o'. The i and o options for
+	  monitor skip the input and output sides of a recording
+	  respectively. This patch addresses a problem in those options
+	  when monitor is called without specifying a specific filename
+	  where monitor will try to move the recording that was skipped.
+	  Since this usually doesn't exist when these options are used, it
+	  would produce a warning when it does this in most cases, but it
+	  is conceivable that there are use cases where this could result
+	  in moving/removing a file unintentionally. (closes issue
+	  ASTERISK-20641) Reported by: Jonathan Rose Review:
+	  https://reviewboard.asterisk.org/r/2190/ ........ Merged
+	  revisions 376389 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376390 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-16 00:09 +0000 [r376339-376343]  David M. Lee <dlee at digium.com>
+
+	* /, utils/extconf.c: Fixed extconf.c breakage introduced in
+	  r376306. To quote wdoekes: > Note that I'm not confirming
+	  legitimacy of having that file in tree at > all. Is anyone using
+	  aelparse/conf2ael? ........ Merged revisions 376340 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376342 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* utils/Makefile, tests/test_astobj2_thrash.c (added),
+	  utils/utils.xml, /, utils/hashtest.c (removed),
+	  tests/test_hashtab_thrash.c (added), utils/hashtest2.c (removed),
+	  include/asterisk/hashtab.h: Migrate hashtest/hashtest2 to be unit
+	  tests. Both hashtest and hashtest2 are manual testing apps that
+	  thrash hash tables (hashtab and ao2 containers, respectively), by
+	  spinning up several threads that randomly insert, delete, lookup
+	  and iterate over the hash table. If the app doesn't crash, the
+	  hash table probably passes the test. Those utils are not a part
+	  of the typical Asterisk build, so they do not usually get
+	  compiled. This all makes them less that useful. This patch
+	  removes those manual test programs and replaces them with
+	  Asterisk unit test modules (test_{hashtab,astobj2}_thrash.so). It
+	  also attempts to make the tests more deterministic. * Rather than
+	  spinning up some number of threads that operate on the hash table
+	  randomly, spin up four threads that concurrenly add, remove,
+	  lookup and iterate over the hash table. * Each thread checks the
+	  state of the hash table both during and after execution, and
+	  indicates a test failure if things are not as expected. * Each
+	  thread times out after 60 seconds to prevent deadlocking the unit
+	  test run. (closes issue ASTERISK-20505) Reported by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/2189/ ........ Merged
+	  revisions 376306 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376315 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-15 23:03 +0000 [r376310]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: app_meetme: Fix channels lingering when
+	  hung up under certain conditions Channels would get stuck and
+	  MeetMe would repeatedly display an Unable to write frame to
+	  channel error in the conf_run function if hung up during certain
+	  sound prompts such as during user count announcements. This patch
+	  fixes that by reintroducing a hangup check in the meetme's main
+	  loop (also in conf_run). (closes issue ASTERISK-20486) Reported
+	  by: Michael Cargile Review:
+	  https://reviewboard.asterisk.org/r/2187/ Patches:
+	  meetme_hangup_patch_ASTERISK-20486_v3.diff uploaded by Jonathan
+	  Rose (license 6182) ........ Merged revisions 376307 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376308 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-15 02:08 +0000 [r376264]  Rusty Newton <rnewton at digium.com>
+
+	* apps/app_voicemail.c, /: Patch to play correct sound file when a
+	  voicemail's urgent status is removed We were attempting to play
+	  "vm-urgent-removed", which didn't exist. Now we play
+	  "vm-marked-nonurgent" which exists and is the correct sound file.
+	  Previous behavior was silence and a warning on the CLI. (issue
+	  ASTERISK-20280) (closes issue ASTERISK-20280) Reported by: Tomo
+	  Takebe Tested by: Rusty Newton Patches: asterisk20280.patch
+	  uploaded by Rusty Newton (license 5829) ........ Merged revisions
+	  376262 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 376263 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-14 19:53 +0000 [r376234]  Richard Mudgett <rmudgett at digium.com>
+
+	* pbx/pbx_spool.c, /: Fix call files when astspooldir is relative.
+	  Future dated call files are ignored when astspooldir is relative
+	  to the current directory. The queue_file() assumed that the qdir
+	  needed to be prepended if the given filename did not start with a
+	  '/'. If astspooldir is relative it is not going to start from the
+	  root directory obviously so it will not start with a '/'. The
+	  filename used in queue_file() ultimately results in qdir
+	  prepended multiple times. * Made queue_file() not prepend qdir if
+	  the filename contains a '/'. (closes issue ASTERISK-20593)
+	  Reported by: James Le Cuirot Patches:
+	  0004-Fix-future-call-files-from-relative-directories.patch
+	  (license #6439) patch uploaded by James Le Cuirot ........ Merged
+	  revisions 376232 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376233 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-13 18:48 +0000 [r376217]  Brent Eagles <beagles at digium.com>
+
+	* main/channel.c, /: Patch to prevent stopping the active generator
+	  when it is not the silence generator. This patch introduces an
+	  internal helper function to safely check whether the current
+	  generator is the one that is expected before deactivating it. The
+	  current externally accessible ast_channel_stop_generator()
+	  function has been modified to be implemented in terms of the new
+	  function. (closes issue ASTERISK-19918) Reported by: Eduardo Abad
+	  ........ Merged revisions 376199 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376208 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-12 20:45 +0000 [r376168]  Joshua Colp <jcolp at digium.com>
+
+	* main/pbx.c, /: Properly check if the "Context" and "Extension"
+	  headers are empty in a ShowDialPlan action. The code which
+	  handles the ShowDialPlan action wrongly assumed that a non-NULL
+	  return value from the function which retrieves headers from an
+	  action indicates that the header has a value. This is incorrect
+	  and the contents must be checked to see if they are blank.
+	  (closes issue ASTERISK-20628) Reported by: jkroon Patches:
+	  asterisk-showdialplan-incorrect-error.patch uploaded by jkroon
+	  ........ Merged revisions 376166 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376167 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-12 20:16 +0000 [r376144]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* main/pbx.c, /: Fix Dynamic Hints Variable Substition - Underscore
+	  Problem When adding a dynamic hint, if an extension contains an
+	  underscore no variable subsitution is being performed. This patch
+	  changes from checking if the extension contains an underscore to
+	  checking if the extension begins with an underscore. (closes
+	  issue ASTERISK-20639) Reported by: Steven T. Wheeler Tested by:
+	  Steven T. Wheeler, Michael L. Young Patches:
+	  asterisk-20639-dynamic-hint-underscore.diff uploaded by Michael
+	  L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2188/ ........ Merged
+	  revisions 376142 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376143 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-11 17:08 +0000 [r376130]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c, channels/chan_sip.c,
+	  configs/sip.conf.sample: Remove a fixed size limitation for
+	  producing SDP and change how ICE support is disabled by default.
+	  With ICE support enabled in chan_sip and a large number of
+	  interfaces on the system it was possible for the produced SDP to
+	  be truncated due to some fixed size buffers. These buffers have
+	  now been changed so they will dynamically grow as needed. ICE
+	  support is now also enabled by default in res_rtp_asterisk to
+	  provide a smoother experience for chan_motif users where it is
+	  required. To maintain the previous behavior in chan_sip it is no
+	  longer enabled by default there. (closes issue ASTERISK-20643)
+	  Reported by: coopvr
+
+2012-11-08 22:08 +0000 [r376089]  Mark Michelson <mmichelson at digium.com>
+
+	* /, res/res_fax.c: Fix a "set but not used" warning on newer gccs.
+	  Turns out the "helpful" setting of ms and res in this macro is
+	  completely useless after the timeout antipattern fix. If you're a
+	  new guy looking to write code, don't write a macro like this one.
+	  ........ Merged revisions 376087 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-08 21:10 +0000 [r376048-376060]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_ss7.c, /: chan_dahdi/SS7: Made reject incoming call
+	  for an in-alarm or blocked channel. If a SS7 call comes in
+	  requesting a CIC that is in-alarm, the call is accepted and
+	  connects if the extension exists in the dialplan. The call does
+	  not have any audio. * Made release the call immediately with
+	  circuit congestion cause. (closes issue ASTERISK-20204) Reported
+	  by: Tuan Le Patches: jira_asterisk_20204_v1.8.patch (license
+	  #5621) patch uploaded by rmudgett ........ Merged revisions
+	  376058 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 376059 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/asterisk.c, include/asterisk/utils.h,
+	  include/asterisk/astmm.h, /, main/utils.c, main/astmm.c: Add
+	  MALLOC_DEBUG enhancements. * Makes malloc() behave like calloc().
+	  It will return a memory block filled with 0x55. A nonzero value.
+	  * Makes free() fill the released memory block and boundary
+	  fence's with 0xdeaddead. Any pointer use after free is going to
+	  have a pointer pointing to 0xdeaddead. The 0xdeaddead pointer is
+	  usually an invalid memory address so a crash is expected. * Puts
+	  the freed memory block into a circular array so it is not reused
+	  immediately. * When the circular array rotates out a memory block
+	  to the heap it checks that the memory has not been altered from
+	  0xdeaddead. * Made the astmm_log message wording better. * Made
+	  crash if the DO_CRASH menuselect option is enabled and something
+	  is found. * Fixed a potential alignment issue on 64 bit systems.
+	  struct ast_region.data[] should now be aligned correctly for all
+	  platforms. * Extracted region_check_fences() from
+	  __ast_free_region() and handle_memory_show(). * Updated
+	  handle_memory_show() CLI usage help. Review:
+	  https://reviewboard.asterisk.org/r/2182/ ........ Merged
+	  revisions 376029 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 376030 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-07 19:03 +0000 [r376014]  Mark Michelson <mmichelson at digium.com>
+
+	* include/asterisk/time.h, apps/app_jack.c, apps/app_dial.c,
+	  main/pbx.c, main/rtp_engine.c, /, apps/app_meetme.c,
+	  res/res_fax.c, apps/app_record.c, channels/chan_agent.c,
+	  main/utils.c, include/asterisk/channel.h, apps/app_queue.c,
+	  channels/sig_pri.c, channels/chan_iax2.c, main/channel.c,
+	  channels/chan_dahdi.c, apps/app_waitforring.c,
+	  channels/sig_analog.c: Multiple revisions 375993-375994 ........
+	  r375993 | mmichelson | 2012-11-07 11:01:13 -0600 (Wed, 07 Nov
+	  2012) | 30 lines Fix misuses of timeouts throughout the code.
+	  Prior to this change, a common method for determining if a
+	  timeout was reached was to call a function such as
+	  ast_waitfor_n() and inspect the out parameter that told how many
+	  milliseconds were left, then use that as the input to
+	  ast_waitfor_n() on the next go-around. The problem with this is
+	  that in some cases, submillisecond timeouts can occur, resulting
+	  in the out parameter not decreasing any. When this happens
+	  thousands of times, the result is that the timeout takes much
+	  longer than intended to be reached. As an example, I had a
+	  situation where a 3 second timeout took multiple days to finally
+	  end since most wakeups from ast_waitfor_n() were under a
+	  millisecond. This patch seeks to fix this pattern throughout the
+	  code. Now we log the time when an operation began and find the
+	  difference in wall clock time between now and when the event
+	  started. This means that sub-millisecond timeouts now cannot play
+	  havoc when trying to determine if something has timed out. Part
+	  of this fix also includes changing the function ast_waitfor() so
+	  that it is possible for it to return less than zero when a
+	  negative timeout is given to it. This makes it actually possible
+	  to detect errors in ast_waitfor() when there is no timeout.
+	  (closes issue ASTERISK-20414) reported by David M. Lee Review:
+	  https://reviewboard.asterisk.org/r/2135/ ........ r375994 |
+	  mmichelson | 2012-11-07 11:08:44 -0600 (Wed, 07 Nov 2012) | 3
+	  lines Remove some debugging that accidentally made it in the last
+	  commit. ........ Merged revisions 375993-375994 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375995 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-06 18:59 +0000 [r375966]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/features.h, main/channel.c, /,
+	  main/channel_internal_api.c, main/features.c,
+	  include/asterisk/channel.h: Fix stuck DTMF when bridge is broken.
+	  When a bridge is broken by an AMI Redirect action or the
+	  ChannelRedirect application, an in progress DTMF digit could be
+	  stuck sending forever. * Made simulate a DTMF end event when a
+	  bridge is broken and a DTMF digit was in progress. (closes issue
+	  ASTERISK-20492) Reported by: Jeremiah Gowdy Patches:
+	  bridge_end_dtmf-v3.patch.txt (license #6358) patch uploaded by
+	  Jeremiah Gowdy Modified to jira_asterisk_20492_v1.8.patch
+	  jira_asterisk_20492_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/2169/ ........ Merged
+	  revisions 375964 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375965 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-12-10  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.1.0 Released.
+
+2012-12-06  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.1.0-rc3 Released.
+
+	* chan_local: Fix local_pvt ref leak in local_devicestate().
+
+	Regression introduced by ASTERISK-20390 fix.
+
+	(closes issue ASTERISK-20769)
+	Reported by: rmudgett
+
+2012-12-05  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.1.0-rc2 Released.
+
+	* Fix a SIP request memory leak with TLS connections.
+
+	During the TLS re-work in chan_sip some TLS specific code was moved
+	into a separate function. This function operates on a copy of the
+	incoming SIP request. This copy was never deinitialized causing a
+	memory leak for each request processed.
+
+	This function is now given a SIP request structure which it can use
+	to copy the incoming request into. This reduces the amount of memory
+	allocations done since the internal allocated components are reused
+	between packets and also ensures the SIP request structure is
+	deinitialized when the TLS connection is torn down.
+
+	(closes issue ASTERISK-20763)
+	Reported by: deti
+
+2012-11-06  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.1.0-rc1 Released.
+
+2012-11-06 12:09 +0000 [r375925]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Fix a bug where our Motif ICE candidates
+	  were not quite proper, and make us more forgiving. An issue was
+	  reported on the mailing list where calling would result in an
+	  "Incomplete ICE-UDP candidate received on session" error message.
+	  This is the result of the ICE-UDP candidate code not placing a
+	  "network" attribute within the candidates. This is now done. To
+	  increase compatibility though I have removed the requirement for
+	  the "network" attribute to exist within ICE-UDP candidates that
+	  are received since we don't actually require the value. Reported
+	  on the mailing list by Jean-Denis Girard.
+
+2012-11-05 23:09 +0000 [r375895]  Matthew Jordan <mjordan at digium.com>
+
+	* main/timing.c, main/channel.c, /, res/res_timing_pthread.c,
+	  res/res_timing_dahdi.c, res/res_timing_timerfd.c,
+	  bridges/bridge_softmix.c, funcs/func_jitterbuffer.c,
+	  include/asterisk/timing.h, res/res_musiconhold.c,
+	  channels/chan_iax2.c, res/res_fax_spandsp.c,
+	  res/res_timing_kqueue.c: Refactor ast_timer_ack to return an
+	  error and handle the error in timer users Currently, if an
+	  acknowledgement of a timer fails Asterisk will not realize that a
+	  serious error occurred and will continue attempting to use the
+	  timer's file descriptor. This can lead to situations where errors
+	  stream to the CLI/log file. This consumes significant resources,
+	  masks the actual problem that occurred (whatever caused the timer
+	  to fail in the first place), and can leave channels in odd
+	  states. This patch propagates the errors in the timing resource
+	  modules up through the timer core, and makes users of these
+	  timers handle acknowledgement failures. It also adds some
+	  defensive coding around the use of timers to prevent using bad
+	  file descriptors in off nominal code paths. Note that the patch
+	  created by the issue reporter was modified slightly for this
+	  commit and backported to 1.8, as it was originally written for
+	  Asterisk 10. Review: https://reviewboard.asterisk.org/r/2178/
+	  (issue ASTERISK-20032) Reported by: Jeremiah Gowdy patches:
+	  jgowdy-timerfd-6-22-2012.diff uploaded by Jeremiah Gowdy (license
+	  6358) ........ Merged revisions 375893 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375894 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-05 21:41 +0000 [r375864]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/loader.c, /: Add safety NULL pointer check in module user
+	  references. Made __ast_module_user_remove() check for NULL
+	  pointers. ........ Merged revision 375860 from C.3 ........
+	  Merged revisions 375862 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375863 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-05 17:59 +0000 [r375847]  Jonathan Rose <jrose at digium.com>
+
+	* /, UPGRADE.txt: chan_sip: Document a change to user-field
+	  encoding introduced with r303509 The change in question was added
+	  to improve compliance with RFC3261, but at the time of commit, it
+	  wasn't adequately documented in the UPGRADE notes. (closes issue
+	  ASTERISK-20561) Reported by: Deniz Review:
+	  https://reviewboard.asterisk.org/r/2177/ ........ Merged
+	  revisions 375846 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-04 03:09 +0000 [r375729-375802]  Matthew Jordan <mjordan at digium.com>
+
+	* main/manager.c, /: Don't attempt to purge sessions when no
+	  sessions exist Manager's tcp/tls objects have a periodic function
+	  that purge old manager sessions periodically. During shutdown,
+	  the underlying container holding those sessions can be disposed
+	  of and set to NULL before the tcp/tls periodic function is
+	  stopped. If the periodic function fires, it will attempt to
+	  iterate over a NULL container. This patch checks for whether or
+	  not the sessions container exists before attempting to purge
+	  sessions out of it. If the sessions container is NULL, we simply
+	  return. Note that this error was also caught by the Asterisk Test
+	  Suite. ........ Merged revisions 375800 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375801 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, res/res_fax.c: Only deref a reserved gateway session if we
+	  actually reserved one Its perfectly acceptable to have a gateway
+	  session unreserved when we go to first allocate one. Unreffing
+	  the reserved gateway session - when its NULL - will result in an
+	  assertion error. This problem was caught by the Asterisk Test
+	  Suite (once we had enough of the debugging flags enabled)
+	  ........ Merged revisions 375797 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/manager.c, /: Properly clean up manager resources on exit
+	  This patch does two things: 1) It properly unregisters the
+	  manager CLI commands 2) It cleans up AMI users on exit. Prior to
+	  this patch, the AMI users were not being disposed of properly,
+	  resulting in a memory leak. (closes issue ASTERISK-20646)
+	  Reported by: Corey Farrell patches: manager_shutdown.patch
+	  uploaded by Corey Farrell (license 5909) ........ Merged
+	  revisions 375793 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375794 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/db.c, /: Properly finalize prepared SQLite3 statements to
+	  prevent memory leak The AstDB uses prepared SQLite3 statements to
+	  retrieve data from the SQLite3 database. These statements should
+	  be finalized during Asterisk shutdown so that the SQLite3
+	  database can be properly closed. Failure to finalize the
+	  statements results in a memory leak and a failure when closing
+	  the database. This patch fixes those issues by ensuring that all
+	  prepared statements are properly finalized at shutdown. (closes
+	  issue ASTERISK-20647) Reported by: Corey Farrell patches:
+	  astdb-sqlite3_close.patch uploaded by Corey Farrell (license
+	  5909) ........ Merged revisions 375761 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/xmldoc.c: Fix memory leaks in XML documentation This patch
+	  fixes two memory leaks: 1) When building XML documentation items,
+	  the 'name' attribute was extracted from XML elements but not
+	  properly freed after being copied into the item being built. 2)
+	  When unloading XML documentation, the doctree container objects
+	  were not properly freed. This patch corrects these memory leaks.
+	  Note that this patch was modified slightly for this commmit, as
+	  the case where the 'name' attribute doesn't exist also wasn't
+	  handled in the item construction. This patch also checks for that
+	  attribute not existing. (closes issue ASTERISK-20648) Reported
+	  by: Corey Farrell Tested by: mjordan patches:
+	  xmldoc-memory_leak.patch uploaded by Corey Farrell (license 5909)
+
+	* main/cdr.c, /: Prevent multiple CDR batches from conflicting when
+	  scheduling the CDR write The Asterisk Test Suite caught an error
+	  condition where a scheduled CDR batch write can be deleted twice
+	  if two channels attempt to post their CDRs at the same time. The
+	  batch CDR mutex is locked while the CDRs are appended to the
+	  current batch list; however, it is unlocked prior to actually
+	  scheduling the CDR write. As such, two threads can attempt to
+	  remove the currently scheduled batch write at the same time,
+	  resulting in an assertion error. This patch extends the time that
+	  the mutex is locked to encompass actually scheduling the write.
+	  This prevents two threads from unscheduling the currently
+	  scheduled write at the same time. ........ Merged revisions
+	  375727 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 375728 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-03 03:17 +0000 [r375702]  Andrew Latham <lathama at gmail.com>
+
+	* README, include/asterisk/doxyref.h: Doxygen Updates Replace links
+	  to missing text files removed in the 1.6.x series with links to
+	  the wiki. Doxygen can handle URLs fine, don't atempt to quote
+	  them. Also update the wiki link in the Readme to get everyone on
+	  the same page. (issue ASTERISK-20259) ........ Merged revisions
+	  375698 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 375699 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-02 20:59 +0000 [r375661]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, channels/chan_misdn.c, /, main/ccss.c,
+	  main/format_pref.c: Things don't need to be that const. ........
+	  Merged revisions 375658 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375659 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-02 20:56 +0000 [r375660]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix for chan_skinny leaving RTP ports
+	  open Skinny wasn't closing RTP sockets. This patch includes
+	  ast_rtp_instance_stop before ast_rtp_instance_destroy which fixes
+	  the problem. Also add destroy for VRTP (which I believe is
+	  unused, but exists). Review:
+	  https://reviewboard.asterisk.org/r/2176/
+
+2012-11-02 18:44 +0000 [r375627]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/misdn/isdn_lib.h, /, channels/misdn/isdn_lib.c: Multiple
+	  revisions 375519-375524 ........ r375519 | rmudgett | 2012-10-30
+	  16:06:15 -0500 (Tue, 30 Oct 2012) | 11 lines chan_misdn: Timer
+	  primitives must be handled first. The frm->addr is a different
+	  "address space" than the stack/instance address of other Lx
+	  primitives. The test for B channel instance address could fail.
+	  Patches: patch01_timers.diff (license #6372) patch uploaded by
+	  Guenther Kelleter JIRA ABE-2888 ........ r375520 | rmudgett |
+	  2012-10-30 16:14:58 -0500 (Tue, 30 Oct 2012) | 10 lines
+	  chan_misdn: Free memory in error paths and other memory leaks.
+	  The one line commented with BUG is not easily fixable because
+	  there is no de-init function one can call. Patches:
+	  patch02_memory.diff (license #6372) patch uploaded by Guenther
+	  Kelleter JIRA ABE-2888 ........ r375521 | rmudgett | 2012-10-30
+	  16:38:41 -0500 (Tue, 30 Oct 2012) | 14 lines chan_misdn: ISDN NT
+	  L2 de-establish/establish * An NT-PTMP cannot de/establish L2
+	  since it doesn't know the TEIs. * On NT-PTP L2 is started when L1
+	  is finally active in handle_l1. * L2 deactivation logging
+	  cleanup. * L2 aggregate link status is unknown for NT-PTMP, show
+	  as "UNKN". * Removed unused functions and code for L2 handling.
+	  Patches: patch03_L2estab.diff (license #6372) patch uploaded by
+	  Guenther Kelleter Modified JIRA ABE-2888 ........ r375522 |
+	  rmudgett | 2012-10-30 16:56:14 -0500 (Tue, 30 Oct 2012) | 22
+	  lines chan_misdn: Fix broken upper_id/lower_id usage. Sending PH
+	  prim via lower_id layer (3 or 1) simply does not work. For TE (3)
+	  it returns an error (len=-6) which is not evaluated by
+	  handle_l1(), so the L1 layer status ends up wrong. Instead PH
+	  must be sent via L4, only then does it reach L1 without an error
+	  message. And NT PH prims only reach L1 when they are sent to
+	  layer 2 id. --> use upper_id to send PH primitives. * Check for
+	  errors in PH_(DE)ACTIVATE | CONFIRM. * Debug messages are
+	  improved. * The lower_id is now not used for anything, except:
+	  Why is lower_id layer deleted when it wasn't created? I removed
+	  this code since it looks very wrong. Patches:
+	  patch04_l1activation.diff (license #6372) patch uploaded by
+	  Guenther Kelleter JIRA ABE-2888 ........ r375523 | rmudgett |
+	  2012-10-30 17:29:15 -0500 (Tue, 30 Oct 2012) | 31 lines
+	  chan_misdn: Fix loss of B channels if L1 is down. If you make 2
+	  calls out an NT PTMP port which is not connected to any phone,
+	  the B channel associated with that call becomes unusable until
+	  Asterisk is restarted. The problem is the EVENT_SETUP is queued
+	  when L1 is not up in misdn_lib_send_event(). If L1 cannot be
+	  activated the event won't be dequeued. It gets even worse when
+	  the call is hung up. The queued EVENT_SETUP will be overwritten
+	  by an EVENT_DISCONNECT. The reserved B channel then will never be
+	  freed. If later someone connects a phone to the port, L1 will
+	  eventually activate and the queued EVENT_DISCONNECT is sent down
+	  the stack. However, it is ignored because it is the wrong call
+	  state. The real fix would be that activation and queueing for a
+	  new SETUP is done by the NT stack. But since it doesn't, the
+	  workaround must be removed because it doesn't always work. Fix:
+	  The event is no longer queued but immediately sent to the stack.
+	  If L1 cannot be activated, the L3 state machine that was started
+	  by the EVENT_SETUP will do its work, i.e. a timeout will release
+	  the B channel properly. The SETUP possibly cannot be sent the
+	  first time but is resent by T303 in case L1 could be activated.
+	  Patches: patch05_bchan-loss.diff (license #6372) patch uploaded
+	  by Guenther Kelleter Modified JIRA ABE-2888 ........ r375524 |
+	  rmudgett | 2012-10-30 18:26:05 -0500 (Tue, 30 Oct 2012) | 13
+	  lines chan_misdn: Remove some calls to exit(). Try proper cleanup
+	  when something goes wrong in misdn_lib_init(). Especially do not
+	  call exit()! * Fix memory leak because stack_destroy() does not
+	  free the stack struct. Patches: patch06_cleanup-init.diff
+	  (license #6372) patch uploaded by Guenther Kelleter Modified JIRA
+	  ABE-2888 ........ Merged revisions 375519-375524 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 375625 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375626 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-02 17:24 +0000 [r375613]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix Wrong Result In Debug Message For SDP
+	  Origin Processing While looking at some debug logs, I noticed
+	  that it was being reported that the SDP origin line was
+	  unsupported or failed. Upon looking into this on my local
+	  machine, I found that I too was getting this debug message yet
+	  everything seemed to be getting processed properly. What was
+	  discovered is, that, the variable to determine what is displayed
+	  in the debug message for the SDP line that was processed, was not
+	  being set for the origin line when the result was successful.
+	  This patch fixes this and was tested on local machine. ........
+	  Merged revisions 375594 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375601 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-11-01 14:52 +0000 [r375575]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample: chan_sip: Fix a bug
+	  causing SIP reloads to remove all entries from the registry A
+	  regression was introduced in chan_sip by changes to sip reload
+	  introduced by r349097. That patch moved peer purging from the
+	  beginning of the reload to after the general configuration was
+	  finished. This patch fixes that by undoing the repositioning of
+	  the original peer purging code and using a similar function after
+	  performing general configuration that purges only autocreated
+	  peers that were created when persist mode isn't enabled. (closes
+	  issue ASTERISK-20611) Reported by: Alisher Review:
+	  https://reviewboard.asterisk.org/r/2171/
+
+2012-10-31 18:00 +0000 [r375559]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_http_websocket.exports.in: Fix an issue with
+	  res_http_websocket where the chan_sip WebSocket handler could not
+	  be registered. On some systems the optional API support uses the
+	  GCC compiler attribute "weakref" to provide its functionality.
+	  This code changes the function names and prefixes "__" to the
+	  front. The res_http_websocket exports file did not take this into
+	  account, thereby not allowing those functions to be global and
+	  ultimately found. (closes issue ASTERISK-20631) Reported by:
+	  danjenkins
+
+2012-10-31 14:49 +0000 [r375532]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_calendar_ews.c, /: Properly extract the Body information
+	  of an EWS calendar item Unlike all other calendar modules,
+	  res_calendar_ews fails to extract the Body information for a
+	  calendar item. This is due, in part, to a quirk in the schema in
+	  the XML - not only does a CalendarItem contain a Body element,
+	  but the CalendarItem exists as a descendant of a different Body
+	  element. The neon parser was erroneously skipping all Body
+	  elements. This patch fixes that by bypassing Body elements that
+	  are not a child of CalendarItem, and parsing the Body element out
+	  if it is a child. Note that the original patch by Terry Wilson
+	  only needed slight modifications to make it properly pull the
+	  Body information out; as such, while I've linked to the patch
+	  that I uploaded for Dmitry, I've attributed the patch to Terry.
+	  (closes issue ASTERISK-19738) Reported by: Dmitry Burilov Tested
+	  by: Dmitry Burilov patches: calendar_ews_body_2012_10_29.diff
+	  uploaded by Terry Wilson (license 6283) ........ Merged revisions
+	  375528 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 375531 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-30 19:23 +0000 [r375506]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, bridges/bridge_softmix.c: Fix ConfBridge crash if no timing
+	  module loaded. (closes issue ASTERISK-19448) Reported by: feyfre
+	  Patches: smfix.patch (license #6099) patch uploaded by feyfre
+	  Modified for coding guidelines. ........ Merged revisions 375496
+	  from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-30 19:09 +0000 [r375471-375486]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_mixmonitor.c: mixmonitor: Add a test event This test
+	  event is being used to fix the mixmonitor_audiohook_inherit test.
+	  ........ Merged revisions 375484 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375485 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_confbridge.c: confbridge: Fix a bug which made
+	  conferences not record with AMI/CLI commands When confbridge was
+	  changed to handle conference status with a state machine in
+	  r374658. The function responsible for starting recording for a
+	  conference was refactored with the function actually responsible
+	  for launching the recording thread being split into a function
+	  with another name. The old function name was still used for
+	  manually started recordings through AMI or CLI. This patch fixes
+	  that by switching which function is used to start recording the
+	  conference. (closes issue ASTERISK-20601) Reported by: Vilius
+	  Patches: confbridge_mixmonitor.diff uploaded by Jonathan Rose
+	  (license 6182) ........ Merged revisions 375470 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-30 02:22 +0000 [r375469]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_queue.c: Ensure that the Queue application tracks
+	  busy members in off nominal situations There are a few code paths
+	  where the Queue application fails to count a paused or in use
+	  queue member as being 'busy'. This can cause callers to get stuck
+	  in the Queue until a paused agent unpauses themselves. (closes
+	  issue ASTERISK-20623) Reported by: Bryan Walters patches:
+	  app_queue.patch uploaded by Bryan Walters (license 5851) ........
+	  Merged revisions 375450 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375451 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-29 21:23 +0000 [r375437]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Prevent resetting of NATted realtime peer
+	  address on reload. If a "sip reload" is issued for a SIP peer,
+	  then his IP address will be cleared, thus resulting in forgetting
+	  the public IP address. Asterisk will then attempt to route SIP
+	  traffic to the private IP address. The fix here is to make "sip
+	  reload" ignore realtime peers when "host = dynamic" is spotted.
+	  Realtime peers can now only have their IP address reset if they
+	  have gone from being not dynamic to being dynamic. (closes issue
+	  ASTERISK-18203) reported by daren ferreira (closes issue
+	  ASTERISK-20572) reported by JoshE Patches: fix_nat_realtime.diff
+	  uploaded by JoshE (license #6075) ........ Merged revisions
+	  375415 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 375417 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-29 19:29 +0000 [r375363-375390]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix the Park 'r' option when a channel parks
+	  itself. When a channel uses the Park appliation to park itself
+	  with the 'r' option, the channel hears music-on-hold instead of
+	  the requested ringing. * Added a missing check for the 'r' option
+	  when a channel parks itself. (closes issue ASTERISK-19382)
+	  Reported by: James Stocks Patches by: dsessions Review:
+	  https://reviewboard.asterisk.org/r/2148/ ........ Merged
+	  revisions 375388 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375389 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c, /: chan_dahdi: Fix segfault dereferencing
+	  a NULL tech_pvt. The tech support customer was using the AMI
+	  Redirect action shortly after a call was placed. While the
+	  channel tried to do an ast_read(), the masquerade resulting from
+	  the channel redirect took place. The masquerade in the middle of
+	  the ast_read() resulted in the segfault. (closes issue AST-1025)
+	  Reported by: Trey Blancher Patches: jira_ast_1025_v1.8_v2.patch
+	  (license #5621) patch uploaded by rmudgett ........ Merged
+	  revisions 375361 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375362 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-23 16:22 +0000 [r375288-375327]  Jonathan Rose <jrose at digium.com>
+
+	* contrib/scripts/ast_tls_cert, /: ast_tls_cert script: Better
+	  response for various exit conditions to openssl (closes issue
+	  ASTERISK-20260) Reported by: Daniel O'Connor Patches:
+	  ast_tls_cert-update.diff uploaded by Daniel O'Connor (license
+	  6419) ........ Merged revisions 375325 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375326 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/app.c: core: Fix a memory leak in app.c from an early
+	  return ast_app_group_match_get_count allocates memory with the
+	  regcomp function and we previously forgot to free it when bailing
+	  out due to a regex compilation failure against category. (closes
+	  issue AST-1018) Reported by: Guenther Kelleter Patches:
+	  regcomp_memleak.diff uploaded by Guenther Kelleter (license 6372)
+	  ........ Merged revisions 375299 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375300 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, codecs/gsm/src/code.c: GSM: Fix encoding problems with GSM
+	  (closes issue ASTERISK-20457) Reported by: Richard Miller
+	  Patches: code.patch uploaded by Richard Miller (license 5685)
+	  ........ Merged revisions 375272 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375273 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-18 21:44 +0000 [r375219-375247]  Jonathan Rose <jrose at digium.com>
+
+	* UPGRADE.txt: app_queue: add upgrade notes for 375216 Adds UPGRADE
+	  notes describing behavioral changes to rrmemory strategy caused
+	  by 375216 (issue AST-989) Reported by: Thomas Arimont
+
+	* /, apps/app_queue.c: app_queue: Make ordering of
+	  rrmemory/rrordered persist over add/remove members Prior to this
+	  patch, adding, removing or reloading members to rrmemory would
+	  cause the order to become completely jumbled. Now it behaves more
+	  or less like rrordered other than the fact that it stores the
+	  members on a hash table rather than a linked list. This patch
+	  also prevents removal of members and member reloads from jumbling
+	  rrordered queues. (issue AST-989) Reported by: Thomas Arimont
+	  Review: https://reviewboard.asterisk.org/r/2164/ ........ Merged
+	  revisions 375216 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375217 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-18 20:02 +0000 [r375191]  Richard Mudgett <rmudgett at digium.com>
+
+	* Makefile, /, build_tools/make_version, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac, makeopts.in:
+	  build_tools: Allow Asterisk to report git SHAs in version string.
+	  Make git more attractive for managing work-in-progress.
+	  Especially convenient when a potential patch set needs to be
+	  tested on multiple platforms since one can use git to keep all
+	  the test environments in sync independent of a subversion server.
+	  Now the Asterisk version will show the exact git SHA5 that was
+	  used when building (still appended by "M" if there are local
+	  modifications) from a git clone of the Asterisk repository so the
+	  developer can more easily know what is actually under test. You
+	  will now get this: $ asterisk -V Asterisk GIT-1698298 Instead of
+	  this: $ asterisk -V Asterisk UNKNOWN__and_probably_unsupported
+	  This has zero impact for those not using git with the exception
+	  of an extra test in the configure script to gather git's path.
+	  This is necessary to prevent "sudo make install" from failing
+	  since git may not be in the path in make's shell environment.
+	  (closes issue ASTERISK-20483) Reported by: Shaun Ruffell Patches:
+	  0001-build_tools-Allow-Asterisk-to-report-git-SHAs-in-ver.patch
+	  (license #5417) patch uploaded by Shaun Ruffell Modified ........
+	  Merged revisions 375189 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375190 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-17 19:00 +0000 [r375148]  Kinsey Moore <kmoore at digium.com>
+
+	* main/tcptls.c, /: Ensure Asterisk fails TCP/TLS SIP calls when
+	  certificate checking fails When placing a call to a TCP/TLS SIP
+	  endpoint whose certificate is not signed by a configured CA
+	  certificate, Asterisk would issue a warning and continue to
+	  process the call as if there was not an issue with the
+	  certificate. Asterisk now properly fails the call if the
+	  certificate fails verification or if the certificate does not
+	  exist when certificate checking is enabled (the default
+	  behavior). (closes issue ASTERISK-20559) Reported by: kmoore
+	  Review: https://reviewboard.asterisk.org/r/2163/ ........ Merged
+	  revisions 375146 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375147 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-16 21:44 +0000 [r375079-375113]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Fixes to the fd-oriented SIP TCP reads.
+	  Don't crash on large user input. Allow SIP headers without space.
+	  Optimize code a bit. Review:
+	  https://reviewboard.asterisk.org/r/2162 ........ Merged revisions
+	  375111 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 375112 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Update sip_request_call SIP dial string
+	  documentation. This was missed when merging review r1859.
+	  ........ Merged revisions 375074 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375078 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-16 14:08 +0000 [r375051]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_iax2.c: Remove a log message that was left in
+	  accidentally from call-id logging development.
+
+2012-10-15 21:15 +0000 [r375027]  Mark Michelson <mmichelson at digium.com>
+
+	* apps/app_dial.c, /, main/ccss.c, include/asterisk/strings.h,
+	  channels/chan_iax2.c: Fix some potential misuses of ast_str in
+	  the code. Passing an ast_str pointer by value that then calls
+	  ast_str_set(), ast_str_set_va(), ast_str_append(), or
+	  ast_str_append_va() can result in the pointer originally passed
+	  by value being invalidated if the ast_str had to be reallocated.
+	  This fixes places in the code that do this. Only the example in
+	  ccss.c could result in pointer invalidation though since the
+	  other cases use a stack-allocated ast_str and cannot be
+	  reallocated. I've also updated the doxygen in strings.h to
+	  include notes about potential misuse of the functions mentioned
+	  previously. Review: https://reviewboard.asterisk.org/r/2161
+	  ........ Merged revisions 375025 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 375026 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-15 08:11 +0000 [r375016]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix underscreen buttons warnings apeared
+	  while transfer process
+
+2012-10-14 11:57 +0000 [r374995]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* config.guess, config.sub, /: Update config.guess and config.sub:
+	  2012-10-10 Update config.guess and config.sub to revision
+	  fb456b34ef4aa02b95dc6be69aaa66fa94a844fb from the
+	  savannah.gnu.org git repo. Adds support for e.g. aarch64 (ARM
+	  64bit). config.guess:timestamp='2012-09-25'
+	  config.sub:timestamp='2012-10-10' ........ Merged revisions
+	  374977 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 374991 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-12 21:57 +0000 [r374932]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_voicemail.c: Avoid a segfault on invalid format names If
+	  a format name was not found by ast_getformatbyname, a NULL
+	  pointer would be passed into ast_format_rate and immediately
+	  dereferenced. This ensures that a valid pointer is used since the
+	  structure is already allocated on the stack. (closes issue
+	  DPH-523) Reported-by: Steve Pitts
+
+2012-10-12 16:20 +0000 [r374914]  Mark Michelson <mmichelson at digium.com>
+
+	* main/tcptls.c, /, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  Do not use a FILE handle when doing SIP TCP reads. This is used
+	  to solve an issue where a poll on a file descriptor does not
+	  necessarily correspond to the readiness of a FILE handle to be
+	  read. This change makes it so that for TCP connections, we do a
+	  recv() on the file descriptor instead. Because TCP does not
+	  guarantee that an entire message or even just one single message
+	  will arrive during a read, a loop has been introduced to ensure
+	  that we only attempt to handle a single message at a time. The
+	  tcptls_session_instance structure has also had an overflow buffer
+	  added to it so that if more than one TCP message arrives in one
+	  go, there is a place to throw the excess. Huge thanks goes out to
+	  Walter Doekes for doing extensive review on this change and
+	  finding edge cases where code could fail. (closes issue
+	  ASTERISK-20212) reported by Phil Ciccone Review:
+	  https://reviewboard.asterisk.org/r/2123 ........ Merged revisions
+	  374905 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 374906 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-11 21:18 +0000 [r374850-374877]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Fix a bug where audio on Google Voice
+	  would not work due to ignoring candidates. Instead of ignoring
+	  parts of the message that are not known just ignore the ones we
+	  know may be present and that would cause a problem.
+
+	* res/res_rtp_asterisk.c: Remove code that should not have gotten
+	  in. (issue ASTERISK-20554)
+
+	* res/res_rtp_asterisk.c, channels/chan_motif.c: Fix an issue where
+	  outgoing calls would fail to establish audio due to ICE
+	  negotiation failures. This change removes the requirement for
+	  ufrag and pwd in the transport stanza and also makes us the
+	  controlling agent. (closes issue ASTERISK-20554) Reported by:
+	  mmichelson
+
+2012-10-11 15:44 +0000 [r374845]  Matthew Jordan <mjordan at digium.com>
+
+	* main/cdr.c, /: Fix incorrect billing duration reported when batch
+	  mode is enabled Similar to r369351, the billing duration can be
+	  skewed when batch mode is enabled. This happened much more rarely
+	  than the duration, as it only occured when the call was answered
+	  (thereby indicating an actual answer time) and immediately hung
+	  up on (indicating a billsec of 0). Since a billing time of '0'
+	  can either mean that the call immediately ended or that the CDR
+	  was improperly answered, we have to use additional information to
+	  know whether or not we can trust the CDR billsec value. Prior to
+	  this patch, we looked to see if we had a valid answer time. If we
+	  did, and billsec was zero, we used the current time to calculate
+	  what billsec value we could from the CDR being written. If batch
+	  mode is enabled, this will incorrectly report a billsec value
+	  being much greater than the actual duration of the call. Instead
+	  of relying on the presence of an answer time to know whether or
+	  not we can re-calculate the billsec for the CDR, we now also use
+	  the presence of the CDR's end time to know if we need to
+	  re-calculate or whether we can trust the billsec value that we
+	  have. This prevents erroneous jumps in the billsec value, while
+	  still making sure that in the worst case, some billing time will
+	  be calculated. (closes issue AST-1016) Reported by: Thomas
+	  Arimont Tested by: Thomas Arimont ........ Merged revisions
+	  374843 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 374844 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-11 15:31 +0000 [r374842]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c, include/asterisk/sip_api.h,
+	  channels/chan_sip.exports.in (removed), main/sip_api.c (added):
+	  Don't make chan_sip export global symbols. During testing, it was
+	  discovered that having chan_sip export global symbols was
+	  problematic. The biggest problem was that load order was
+	  affected. Trying to use realtime could be problematic since in
+	  all likelihood the necessary realtime driver(s) would not be
+	  loaded before chan_sip. In addition, it was found that it was
+	  impossible to use the Digium Phone Module for Asterisk since it
+	  must be loaded before chan_sip since it must hook into chan_sip's
+	  configuration parsing. The solution is to use a virtual table in
+	  the same manner that other modules in Asterisk do, like
+	  app_voicemail. (closes issue ASTERISK-20545) Reported by: kmoore
+
+2012-10-11 13:33 +0000 [r374833]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Consider the Google Talk content stanza
+	  name (jin:content) valid.
+
+2012-10-10 21:03 +0000 [r374804]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_queue.c: app_queue: Made pass connected line updates
+	  from the caller to ringing queue members. Party A calls Party B
+	  Party B puts Party A on hold. Party B calls a queue. Ringing
+	  queue member D sees Party B identification. Party B transfers
+	  Party A to the queue. Queue member D does not get a connected
+	  line update for Party A. Queue member D answers the call and
+	  still sees Party B information. However, if Party A later
+	  transfers the call to Party C then queue member D gets a
+	  connected line update for Party C. * Made pass connected line
+	  updates from the caller to queue members while the queue members
+	  are ringing. (closes issue AST-1017) Reported by: Thomas Arimont
+	  (closes issue ABE-2886) Reported by: Thomas Arimont Tested by:
+	  rmudgett ........ Merged revisions 374801 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 374802 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374803 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-10 13:35 +0000 [r374792]  Kinsey Moore <kmoore at digium.com>
+
+	* main/manager.c: Fix segfault regression from r370681 Due to usage
+	  of ast_hook_send_action, AMI action handling code should be able
+	  to handle a NULL mansession->session. This would cause a crash on
+	  NULL dereference if action_originate was called from
+	  ast_hook_send_action. (closes issue ASTERISK-20544)
+
+2012-10-09 22:21 +0000 [r374771]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /: Fix execution of 'i' extension due to
+	  uninitialized variable. The fix for ASTERISK-18243 added code
+	  that could potentially use dst_exten[] uninitialized. As a result
+	  the 'i' exten may not be executed when it should. (closes issue
+	  ASTERISK-20455) Reported by: Richard Miller Patches:
+	  pbx-1.8.16.0.diff (license #5685) patch uploaded by Richard
+	  Miller Made some cosmetic modifications. ........ Merged
+	  revisions 374758 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374763 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-09 21:34 +0000 [r374755-374756]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c: Improve logging for DTLS-SRTP failure
+	  situations. (closes issue ASTERISK-20487) Reported by: mjordan
+
+	* channels/chan_sip.c: Add a log message for when DTLS-SRTP is
+	  requested and the underlying engine does not support it. (closes
+	  issue ASTERISK-20487) Reported by: mjordan
+
+2012-10-08 22:30 +0000 [r374708-374729]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/chan_dahdi.conf.sample, /: dahdi.conf.sample: Add
+	  description for "buffers" setting. This contains an edited
+	  version of the patch originally created by John Bigelow. (closes
+	  issue ASTERISK-14435) Reported by: John Bigelow Patches:
+	  buffers.patch (license #5091) patch uploaded by John Bigelow
+	  0001-dahdi.conf.sample-Add-description-for-buffers-settin.patch
+	  (license #5417) patch uploaded by Shaun Ruffell Modified ........
+	  Merged revisions 374727 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374728 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* pbx/pbx_spool.c, /: Fix deletion of unopenable spool files. If
+	  scan_service() cannot open the spool file, it logs a message
+	  saying that it will delete the file and calls remove_from_queue()
+	  to do it. However, remove_from_queue() fails to delete the spool
+	  file because struct outgoing has not yet been fully initialized.
+	  * Merged allocating a new struct outgoing and init_outgoing()
+	  into new_outgoing(). Allocation is initialization. * Made
+	  apply_outgoing() not initialize the spool filename in struct
+	  outgoing. * Made apply_outgoing() call ast_trim_blanks() and
+	  ast_skip_blanks() rather than manually inlining them. * Reduced
+	  indentation levels in apply_outgoing(). * Fixed a garbled comment
+	  in remove_from_queue(). * Reworked scan_service() to simplify it.
+	  (closes issue ASTERISK-17231) Reported by: David Chappell
+	  Patches: spool_open_failure.diff (license #4997) patch uploaded
+	  by David Chappell Started with this patch. ........ Merged
+	  revisions 374686 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 * Fixed some
+	  memory leaks on off nominal paths in init_outgoing() when merging
+	  into the new_outgoing() function dealing with o->capabilities.
+	  ........ Merged revisions 374695 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-25  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.0.0 Released.
+
+2012-10-17  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.0.0-rc2 Released.
+
+	* [r374792] Fix segfault regression from r370681
+
+	  Due to usage of ast_hook_send_action, AMI action handling code should
+	  be able to handle a NULL mansession->session.  This would cause a
+	  crash	on NULL dereference if action_originate was called from
+	  ast_hook_send_action.
+
+  	  (closes issue ASTERISK-20544)
+
+	* [r374842] Don't make chan_sip export global symbols.
+
+	  During testing, it was discovered that having chan_sip export global
+	  symbols was problematic.
+
+	  The biggest problem was that load order was affected.
+	  Trying to use realtime could be problematic since in
+	  all likelihood the necessary realtime driver(s) would
+	  not be loaded before chan_sip.
+
+	  In addition, it was found that it was impossible to
+	  use the Digium Phone Module for Asterisk since it
+	  must be loaded before chan_sip since it must hook
+	  into chan_sip's configuration parsing.
+
+	  The solution is to use a virtual table in the same
+	  manner that other modules in Asterisk do, like
+	  app_voicemail.
+
+	  (closes issue ASTERISK-20545)
+	  Reported by: kmoore
+
+	* [r374850] Fix an issue where outgoing calls would fail to establish
+	  audio due to ICE negotiation failures.
+
+	  This change removes the requirement for ufrag and pwd in the transport
+	  stanza and also makes us the controlling agent.
+
+	  (closes issue ASTERISK-20554)
+	  Reported by: mmichelson
+
+	* [r374851] Remove code that should not have gotten in (r374850)
+
+	  (issue ASTERISK-20554)
+
+	* [r374877] Fix a bug where audio on Google Voice would not work due to
+	  ignoring candidates.
+
+	  Instead of ignoring parts of the message that are not known just
+	  ignore the ones we know may be present and that would cause a problem.
+
+	* [r375148] Ensure Asterisk fails TCP/TLS SIP calls when certificate
+	  checking fails
+
+	  When placing a call to a TCP/TLS SIP endpoint whose certificate is not
+	  signed by a configured CA certificate, Asterisk would issue a warning
+	  and continue to process the call as if there was not an issue with the
+	  certificate.  Asterisk now properly fails the call if the certificate
+	  fails verification or if the certificate does not exist when
+	  certificate checking is enabled (the default behavior).
+
+	  (closes issue ASTERISK-20559)
+	  Review: https://reviewboard.asterisk.org/r/2163/
+
+	* [r375051] Remove a log message that was left in accidentally from
+	  call-id logging development.
+
+2012-10-08  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 11.0.0-rc1 Released.
+
+2012-10-08 20:38 +0000 [r374632-374676]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, configs/rtp.conf.sample: Disable ICE
+	  support by default Since there are a number of legacy devices out
+	  there that fail to handle ICE candidates properly (which is a
+	  nice way of saying something much uglier), disable it by default.
+	  Support for ICE candidates can be enabled in rtp.conf using the
+	  icesupport setting.
+
+	* apps/confbridge/conf_state.c (added),
+	  apps/confbridge/conf_state_single.c (added),
+	  apps/confbridge/conf_state_inactive.c (added),
+	  apps/confbridge/conf_state_single_marked.c (added), /,
+	  apps/confbridge/include/confbridge.h,
+	  apps/confbridge/include/conf_state.h (added),
+	  apps/confbridge/conf_state_multi.c (added),
+	  apps/app_confbridge.c, apps/confbridge/conf_state_multi_marked.c
+	  (added), apps/confbridge/conf_state_empty.c (added): Resolve
+	  issues in ConfBridge regarding marked, waitmarked, and unmarked
+	  users Thank's to Neil Tallim (flan)'s tireless testing, issue
+	  reporting, and patches it became clear that app_confbridge had
+	  some complex logic in how it handled interactions between marked,
+	  waitmarked, and unmarked users. In particular, there were some
+	  areas in which the interactions between the users resulted in
+	  inconsistent behavior, and app_confbridge was missing logic in
+	  how to handle some corner cases. Some areas included: * Poor
+	  handling of mixing unmarked and waitmarked users *
+	  Inconsistencies in how MOH and muting was applied to various
+	  users * Handling of various announcements for different user
+	  profile options flan's patches seem to fix the various issues,
+	  but highlighted how hard the code could be to maintain. In an
+	  attempt to make things easier to maintain and to more fully
+	  enumerate the various cases that exist, this patch breaks up the
+	  logic into a state machine-like setup. Please note that the
+	  various state transitioned are documented on the Asterisk wiki:
+	  https://wiki.asterisk.org/wiki/display/AST/Confbridge+state+changes
+	  Review: //https://reviewboard.asterisk.org/r/2072/ Note that for
+	  the following issues, mjordan uploaded the patch, although it was
+	  written by twilson. Any contributor license discrepency is due to
+	  that. (closes issue ASTERISK-19562) Reported by: flan Tested by:
+	  flan, mjordan, jrose patches:
+	  bugASTERISK-19562_ASTERISK-19726_ASTERISK-20181.patch uploaded by
+	  twilson (license 6283) (closes issue ASTERISK-19726) Reported by:
+	  flan Tested by: flan patches:
+	  bugASTERISK-19562_ASTERISK-19726_ASTERISK-20181.patch uploaded by
+	  twilson (license 6283) (closes issue ASTERISK-20181) Reported by:
+	  Jonathan White Tested by: Jonathan White patches:
+	  bugASTERISK-19562_ASTERISK-19726_ASTERISK-20181.patch uploaded by
+	  twilson (license 6283) ........ Merged revisions 374652 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* res/pjproject/pjlib/include/pj/sock.h,
+	  res/pjproject/pjlib/src/pj/sock_symbian.cpp,
+	  res/pjproject/pjlib/src/pj/sock_bsd.c,
+	  res/pjproject/pjlib/src/pj/sock_linux_kernel.c: pjproject: Fix
+	  for Solaris builds. Do not undef s_addr. pjproject, in order to
+	  solve build problems on Windows [1], undefines s_addr in one of
+	  it's headers that is included in res_rtp_asterisk.c. On Solaris
+	  s_addr is not a structure member, but defined to map to the real
+	  strucuture member, therefore when building on Solaris it's
+	  possible to get build errors like: [CC] res_rtp_asterisk.c ->
+	  res_rtp_asterisk.o In file included from
+	  /export/home/admin/asterisk-11-svn/include/asterisk/stun.h:29,
+	  from res_rtp_asterisk.c:51:
+	  /export/home/admin/asterisk-11-svn/include/asterisk/network.h: In
+	  function `inaddrcmp':
+	  /export/home/admin/asterisk-11-svn/include/asterisk/network.h:92:
+	  error: structure has no member named `s_addr'
+	  /export/home/admin/asterisk-11-svn/include/asterisk/network.h:92:
+	  error: structure has no member named `s_addr' res_rtp_asterisk.c:
+	  In function `ast_rtp_on_ice_tx_pkt': res_rtp_asterisk.c:706:
+	  warning: dereferencing type-punned pointer will break
+	  strict-aliasing rules res_rtp_asterisk.c:710: warning:
+	  dereferencing type-punned pointer will break strict-aliasing
+	  rules res_rtp_asterisk.c: In function
+	  `rtp_add_candidates_to_ice': res_rtp_asterisk.c:1085: error:
+	  structure has no member named `s_addr' make[2]: ***
+	  [res_rtp_asterisk.o] Error 1 make[1]: *** [res] Error 2 make[1]:
+	  Leaving directory `/export/home/admin/asterisk-11-svn' gmake: ***
+	  [_cleantest_all] Error 2 Unfortunately, in order to make this
+	  work, I also had to make sure pjproject only used the typdef
+	  pj_in_addr and not the struct pj_in_addr so that when building
+	  Asterisk I could "typedef struct in_addr pj_in_addr". It's
+	  possible then that the library and users of those interfaces in
+	  Asterisk have a different idea about the type of the argument,
+	  while on the surface it looks like they are all 32 bit big endian
+	  values. [1] http://trac.pjsip.org/repos/changeset/484 (issues
+	  ASTERISK-20366) Reported by: Ben Klang Tested by: Ben Klang,
+	  mjordan patches:
+	  0001-pjproject-Fix-for-Solaris-builds.-Do-not-undef-s.patch
+	  uploaded by Shaun Ruffell (license 5417)
+
+	* main/acl.c: Trivial patch to make 'best_score' defined for all
+	  architectures. Fixes trivial build error on Solaris: acl.c: In
+	  function `get_local_address': acl.c:196: error: `best_score'
+	  undeclared (first use in this function) acl.c:196: error: (Each
+	  undeclared identifier is reported only once acl.c:196: error: for
+	  each function it appears in.) make[2]: *** [acl.o] Error 1 (issue
+	  ASTERISK-20366) Reported by: Ben Klang Tested by: Ben Klang
+	  patches:
+	  0002-main-acl.c-Trivial.-best_score-should-be-defined-for.patch
+	  by Shaun Ruffell (license 5417)
+
+2012-10-06 03:20 +0000 [r374611-374622]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_xmpp.c: Handle capability stanzas that fail to provide
+	  node or version information While XEP-0115 states that the node
+	  and ver attributes are both required, some devices fail to
+	  provide either field. Prior to this patch, failure to provide the
+	  node or ver attribute would cause a crash in res_xmpp. While
+	  failing to provide the node or ver attribute is technically
+	  invalid, since this information is not utilized by Asterisk
+	  except for reporting purposes, for interoperability reasons, we
+	  continue to process the capability stanza anyways. (closes issue
+	  ASTERISK-20495) Reported by: Martin W Tested by: Martin W
+	  patches: 20495.patch uploaded by Martin W (license #6434)
+
+	* res/res_xmpp.c, main/message.c: Update documentation for
+	  MessageSend application/command's From field for XMPP When using
+	  the channel technology agnostic application/AMI command
+	  MessageSend, the "From" field is technically optional for the SIP
+	  channel driver. However, if being sent by the XMPP resource
+	  module (either res_xmpp or res_jabber), the "From" field is
+	  necessary, and must correspond to a defined account. This patch
+	  updates the documentation for this application/AMI command to
+	  reflect this. (closes issue ASTERISK-20405) Reported by: Leif
+	  Madsen
+
+2012-10-05 20:32 +0000 [r374587]  dlee <dlee at localhost>:
+
+	* main/manager.c, /: Multiple revisions 374570,374581 ........
+	  r374570 | dlee | 2012-10-05 15:14:41 -0500 (Fri, 05 Oct 2012) |
+	  22 lines Improve AMI long line error handling In AMI's parser,
+	  when it receives a long line (> 1024 characters), it discards
+	  that line, but continues to process the message normally.
+	  Typically, this is not a problem because a) who has lines that
+	  long and b) usually a discarded line results in an invalid
+	  message. But if that line is specifying an optional field, then
+	  the message will be processed, you get a 'Response: Success', but
+	  things don't work the way you expected them to. This patch
+	  changes the behavior when a line-too-long parse error occurs. *
+	  Changes the log message to avoid way-too-long (and truncated
+	  anyways) log messages * Adds a 'parsing' status flag to Response:
+	  Success * Sets parsing = MESSAGE_LINE_TOO_LONG if, well, a line
+	  is too long * Responds with an appropriate error if parsing !=
+	  MESSAGE_OKAY (closes issue AST-961) Reported by: John Bigelow
+	  Review: https://reviewboard.asterisk.org/r/2142/ ........ r374581
+	  | dlee | 2012-10-05 15:20:28 -0500 (Fri, 05 Oct 2012) | 1 line
+	  I've committed too much. Reverting part of r374570. ........
+	  Merged revisions 374570,374581 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374586 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-05 18:34 +0000 [r374538]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/misdn/isdn_lib.h, channels/chan_misdn.c, /,
+	  channels/misdn/isdn_msg_parser.c, channels/misdn/isdn_lib.c:
+	  Merged revisions 374515-374535 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ................ r374515 | rmudgett | 2012-10-04 17:52:36 -0500
+	  (Thu, 04 Oct 2012) | 10 lines chan_misdn: Remove some deadcode *
+	  Made setup_bc() static. Patches: patch1_unused-code.diff (license
+	  #6372) patch uploaded by Guenther Kelleter Modified JIRA ABE-2882
+	  ................ r374516 | rmudgett | 2012-10-04 18:01:01 -0500
+	  (Thu, 04 Oct 2012) | 7 lines chan_misdn: Remove unused bchan
+	  states Patches: patch2_unused-states.diff (license #6372) patch
+	  uploaded by Guenther Kelleter JIRA ABE-2882 ................
+	  r374517 | rmudgett | 2012-10-04 18:17:51 -0500 (Thu, 04 Oct 2012)
+	  | 16 lines chan_misdn: Remove unnecessary null pointer checks and
+	  checks for stack->nt * cleanup_bc() is always called with valid
+	  bc (or it would've crashed before). * Value of stack->nt is known
+	  in advance at some places. * Rename handle_event() to
+	  handle_event_te(), handle_frm() to handle_frm_te(). Patches:
+	  patch3_checks.diff (license #6372) patch uploaded by Guenther
+	  Kelleter Modified JIRA ABE-2882 ................ r374518 |
+	  rmudgett | 2012-10-04 18:21:59 -0500 (Thu, 04 Oct 2012) | 7 lines
+	  chan_misdn: Fix spelling in log messages Patches:
+	  patch4_spelling.diff (license #6372) patch uploaded by Guenther
+	  Kelleter JIRA ABE-2882 ................ r374519 | rmudgett |
+	  2012-10-04 18:31:59 -0500 (Thu, 04 Oct 2012) | 15 lines
+	  chan_misdn: Don't cleanup a bc twice. In handle_frm_te() after
+	  calling misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE) bc is
+	  emptied, cleaned and set not in use, although
+	  misdn_lib_send_event() already did the same. This is bad. When
+	  it's not in use we are not allowed to touch it. * Moved log
+	  message in front of the resulting actions and fixed it to match
+	  the case. Patches: patch5_bccleanup.diff (license #6372) patch
+	  uploaded by Guenther Kelleter JIRA ABE-2882 ................
+	  r374520 | rmudgett | 2012-10-04 18:43:56 -0500 (Thu, 04 Oct 2012)
+	  | 12 lines chan_misdn: Fix memory leaks, bc, chan not cleaned up
+	  etc., really bad stuff. * Fix return codes of cb_events() for
+	  EVENT_SETUP to use caller's cleanup mechanisms. * Move
+	  cl_queue_chan() call after bearer check. Patches:
+	  patch6_leaks.diff (license #6372) patch uploaded by Guenther
+	  Kelleter JIRA ABE-2882 ................ r374521 | rmudgett |
+	  2012-10-04 18:48:38 -0500 (Thu, 04 Oct 2012) | 11 lines
+	  chan_misdn: We must initialize cause on sending a DISCONNECT. We
+	  must initialize cause on sending a DISCONNECT, so it is later
+	  correctly indicated to ast_channel in case the answer
+	  (RELEASE/RELEASE_COMPLETE) does not include one. Patches:
+	  patch7_hangupcause.diff (license #6372) patch uploaded by
+	  Guenther Kelleter JIRA ABE-2882 ................ r374522 |
+	  rmudgett | 2012-10-04 19:03:56 -0500 (Thu, 04 Oct 2012) | 7 lines
+	  chan_misdn: Remove unused code for upqueue Patches:
+	  patch8_unused-upqueue.diff (license #6372) patch uploaded by
+	  Guenther Kelleter JIRA ABE-2882 ................ r374523 |
+	  rmudgett | 2012-10-04 19:11:50 -0500 (Thu, 04 Oct 2012) | 7 lines
+	  chan_misdn: Improve debugging (port number, messages fixed, dups
+	  removed) Patches: patch9_debug.diff (license #6372) patch
+	  uploaded by Guenther Kelleter JIRA ABE-2882 ................
+	  r374533 | rmudgett | 2012-10-05 12:17:18 -0500 (Fri, 05 Oct 2012)
+	  | 8 lines chan_misdn: Better debug: we can print_bc_info even if
+	  there's no ast leg. Patches: patch10_debug-bc-2.diff (license
+	  #6372) patch uploaded by Guenther Kelleter Modified. JIRA
+	  ABE-2882 ................ r374534 | rmudgett | 2012-10-05
+	  12:34:10 -0500 (Fri, 05 Oct 2012) | 16 lines chan_misdn:
+	  setup_bc() is called too early for an incoming SETUP on TE. This
+	  prevents the B channel from being setup for HDLC mode when
+	  requested by the bearer capability and config option hdlc=yes. It
+	  violates ETS300102 Ch.5.2.3.2: "The user, in any case, must not
+	  connect to the channel until a CONNECT ACKNOWLEDGE message has
+	  been received." * Call setup_bc() on receipt of
+	  CONNECT_ACKNOWLEGDE for PTMP, and on first response to SETUP for
+	  PTP. Patches: abe-2881-2.diff (license #6372) patch uploaded by
+	  Guenther Kelleter Modified. JIRA ABE-2881 ................
+	  r374535 | rmudgett | 2012-10-05 12:41:05 -0500 (Fri, 05 Oct 2012)
+	  | 2 lines chan_misdn: Remove some more deadcode. ................
+	  ........ Merged revisions 374536 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374537 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-04 20:18 +0000 [r374477-374485]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* main/dsp.c, /, configs/dsp.conf.sample, CHANGES: dsp.c User
+	  Configurable DTMF_HITS_TO_BEGIN and DTMF_MISSES_TO_END Instead of
+	  a recompile, allow values to be adjusted in dsp.conf For binary
+	  distributions allows easy adjustment for wobbly GSM calls, and
+	  other reasons. Defaults to DTMF_HITS_TO_BEGIN=2 and
+	  DTMF_MISSES_TO_END=3 (closes issue ASTERISK-17493) Tested by:
+	  alecdavis alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2144/ ........ Merged
+	  revisions 374479 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374481 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/dsp.c, /: dsp.c fix incorrect DTMF Digit_Duration. it's
+	  always short by 'hits_to_begin*DTMF_GSIZE', or 25.5ms if
+	  hitstobegin=2 (issue ASTERISK-16003) Tested by: alecdavis
+	  alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2145/ ........ Merged
+	  revisions 374475 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374476 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-04 15:42 +0000 [r374428]  dlee <dlee at localhost>:
+
+	* main/db.c, /, res/res_agi.c: Fix DBDelTree error codes for AMI,
+	  CLI and AGI The AMI DBDelTree command will return Success/Key
+	  tree deleted successfully even if the given key does not exist.
+	  The CLI command 'database deltree' had a similar problem, but was
+	  saved because it actually responded with '0 database entries
+	  removed'. AGI had a slightly different error, where it would
+	  return success if the database was unavailable. This came from
+	  confusion about the ast_db_deltree retval, which is -1 in the
+	  event of a database error, or number of entries deleted
+	  (including 0 for deleting nothing). * Changed some poorly named
+	  res variables to num_deleted * Specified specific errors when
+	  calling ast_db_deltree (database unavailable vs. entry not found
+	  vs. success) * Fixed similar bug in AGI database deltree, where
+	  'Database unavailable' results in successful result (closes issue
+	  AST-967) Reported by: John Bigelow Review:
+	  https://reviewboard.asterisk.org/r/2138/ ........ Merged
+	  revisions 374426 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374427 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-04 04:43 +0000 [r374379-374386]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* main/dsp.c, /, configs/dsp.conf.sample, CHANGES: dsp.c User
+	  configuration of DTMF_NORMAL_TWIST and DTMF_REVERSE_TWIST values
+	  Asterisk's DTMF Specifications are based on AT&T specs, which may
+	  not be compatible in other countries. Various countries have
+	  different specifications for the maximum power level differences
+	  between the DTMF low group and high group of frequencies. Power
+	  level difference between frequencies for different
+	  Administrations/RPOAs NTT = Max. 5 dB AT&T = 4dB(reverse) to
+	  8dB(normal) Danish = Max. 6 dB Australian = Max. 10 dB Brazilian
+	  = Max. 9 dB ETSI = Max. 6 dB from ETSI ES 201 235-3 V1.3.1
+	  (2006-03) Now allow 4 variables to be individually configured in
+	  dsp.conf, with reasonable min/max of 2dB to 20dB. Default is AT&T
+	  specifications Add's the following variables to dsp.conf
+	  ;dtmf_normal_twist=6.31 ;dtmf_reverse_twist=2.51
+	  ;relax_dtmf_normal_twist=6.31 ;relax_dtmf_reverse_twist=3.98
+	  (closes issue ASTERISK-20442) Reported by: tbsky Tested by:
+	  tbsky,alecdavis alecdavis (license 585) Review
+	  https://reviewboard.asterisk.org/r/2141/ ........ Merged
+	  revisions 374384 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374385 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /: _dsp_init: bring inline with trunk preparation for clean merge
+	  of DTMF TWIST patch No functional changes, just style. alecdavis
+	  (license 585) Reported by: Alec Davis Tested by: alecdavis
+	  related https://reviewboard.asterisk.org/r/2141 ........ Merged
+	  revisions 374365 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374370 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-04 02:15 +0000 [r374196-374337]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_jabber.c: Check for presence of buddy in info/dinfo
+	  handlers The res_jabber resource module uses the ASTOBJ library
+	  for managing its ref counted objects. After calling
+	  ASTOBJ_CONTAINER_FIND to locate a buddy object, the pointer to
+	  the object has to be checked to see if the buddy existed. Prior
+	  to this patch, the buddy object was not checked for NULL; with
+	  this patch in both aji_client_info_handler and aji_dinfo_handler
+	  the pointer is checked before used and, if no buddy object was
+	  found, the handlers return an error code. This patch does not
+	  take the approach that our JID can be used to log in from another
+	  resource. If that approach is desired, an improvement could be
+	  made to this patch to create the buddy on the fly. This patch
+	  seeks only to prevent Asterisk from crashing. FYI: In Asterisk
+	  11+, you really should be using res_xmpp. It does not have this
+	  problem, as it moved to the astobj2 library. Note that multiple
+	  people have proposed patches for this issue; the patch being
+	  committed here is based on those. (closes issue ASTERISK-19532)
+	  Reported by: Karsten Wemheuer Tested by: Byron Clark patches:
+	  fix-jabber uploaded by Karsten Wemheuer (license #5930)
+	  xmpp_no_crash_with_ejabberd.patch uploaded by Byron Clark
+	  (license #6157) (closes issue ASTERISK-19557) Reported by:
+	  ulugutz ........ Merged revisions 374335 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374336 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/ccss.c: Destroy the generic_monitors container after the
+	  core_instances in ccss For each item in core_instances disposed
+	  of in the shutdown of ccss, any generic monitor instances
+	  referenced by the objects will be removed from generic_monitors
+	  during their destruction. Hilarity ensues if generic_monitors no
+	  longer exists. Thanks to the Asterisk Test Suite's generic_ccss
+	  test for complaining loudly when it ran into this. ........
+	  Merged revisions 374300 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/asterisk.c, /: Ensure Shutdown AMI event is still fired
+	  during Asterisk shutdown Richard pointed out that having the
+	  manager dispose of itself gracefully during shutdown meant that
+	  the Shutdown event will no longer get fired. This patch moves the
+	  AMI event just prior to running the atexit callbacks. ........
+	  Merged revisions 374230 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374231 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/message.c: Fix findings from check-in on r374177 Richard
+	  pointed out two problems with the check-in from r374177: * The
+	  ast_msg_shutdown function declaration doesn't match the prototype
+	  in main/message.c. * The ref/alloc function usage in astobj2 (in
+	  trunk) can use the ao2_t_* variants of the functions to allow the
+	  REF_DEBUG flag to enable/disable their debug counterparts.
+	  ........ Merged revisions 374210 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/db.c, main/asterisk.c, main/xmldoc.c, main/format.c,
+	  main/udptl.c, main/pbx.c, /, main/ccss.c,
+	  include/asterisk/astobj2.h, channels/chan_agent.c,
+	  main/taskprocessor.c, res/res_musiconhold.c, res/res_xmpp.c,
+	  main/cel.c, main/named_acl.c, main/indications.c,
+	  main/format_pref.c, main/astobj2.c, main/channel.c, main/data.c,
+	  main/manager.c, main/features.c, main/config_options.c,
+	  main/event.c, main/message.c: Fix a variety of ref counting
+	  issues This patch resolves a number of ref leaks that occur
+	  primarily on Asterisk shutdown. It adds a variety of shutdown
+	  routines to core portions of Asterisk such that they can reclaim
+	  resources allocate duringd initialization. Review:
+	  https://reviewboard.asterisk.org/r/2137 ........ Merged revisions
+	  374177 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 374178 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-01 20:26 +0000 [r374133-374150]  Sean Bright <sean at malleable.com>
+
+	* main/db.c, include/asterisk/astdb.h, /, tests/test_db.c,
+	  apps/app_queue.c: app_queue: Support persisting and loading of
+	  long member lists. Greenlight in #asterisk brought up that he was
+	  receiving an error message "Could not create persistent member
+	  string, out of space" when running app_queue in Asterisk 10.
+	  dump_queue_members() made an assumption that 8K would be enough
+	  to store the generated string, but with queues that have large
+	  member lists this is not always the case. This patch removes the
+	  limitation and uses ast_str instead of a fixed sized buffer. The
+	  complicating factor comes from the fact that ast_db_get requires
+	  a buffer and buffer size argument, which doesn't let us pull back
+	  more than what we pass in, so I introduced a new
+	  ast_db_get_allocated() which returns an ast_strdup()'d copy of
+	  the value from astdb. As an aside, I did some testing on the
+	  maximum size of data that we can store in the BDB library we
+	  distribute and was able to store a 10MB string and retrieve it
+	  with no problems, so I feel this is a safe patch. Review:
+	  https://reviewboard.asterisk.org/r/2136/ ........ Merged
+	  revisions 374108 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 374135 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/db.c, /: Use ast_copy_string instead of strncpy to guarantee
+	  a NUL terminated string. ........ Merged revisions 374132 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-10-01 16:12 +0000 [r374106]  Mark Michelson <mmichelson at digium.com>
+
+	* apps/confbridge/conf_config_parser.c: Don't destroy confbridge
+	  config when error is encountered during a reload. Not panicking
+	  means that the old config is kept. (closes issue ASTERISK-20458)
+	  Reported by: Leif Madsen Patches: ASTERISK-20458.patch uploaded
+	  by Mark Michelson(license #5049) Tested by Leif Madsen
+
+2012-09-29 03:54 +0000 [r374085]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c: Fix ref leak when adding ICE candidates to
+	  an SDP There was a missing decrement to the reference count for
+	  the current ICE candidate when local candidates are being added
+	  to an outbound SDP. This patch corrects that.
+
+2012-09-28 19:29 +0000 [r374059]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_jabber.c: res_jabber: Remove CLI command 'jabber test'
+	  The opinion of development was that it is both improper to have
+	  Matt's personal email address used in the source and that the
+	  command wouldn't be useful without it. (closes issue AST-467)
+	  Reported by: Malcolm Davenport ........ Merged revisions 374032
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 374045 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-28 13:02 +0000 [r374019]  beagles <beagles at localhost>:
+
+	* res/res_xmpp.c, main/message.c: Reset hangup flags on channels
+	  created through messages and cleanup globals in res_xmpp on
+	  unload. This patch fixes an issue where hangup flags were not
+	  being reset on a channel, affecting subsequent use of that
+	  channel. The patch also adds some additional cleanup to res_xmpp
+	  to fix an issue with reloading the module. (closes
+	  ASTERISK-20360) Reported by: Noah Engelberth Tested by: beagles
+	  Review: https://reviewboard.asterisk.org/r/2134/
+
+2012-09-28 12:16 +0000 [r373991]  Joshua Colp <jcolp at digium.com>
+
+	* /, res/res_agi.c: Update documentation to make it explicit that
+	  "stream file" will not restart musiconhold. (issue
+	  ASTERISK-17367) Reported by: oej ........ Merged revisions 373989
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 373990 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-27 22:19 +0000 [r373954]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_senddtmf.c: Fix SendDTMF crash and channel reference
+	  leak using channel name parameter. The SendDTMF channel name
+	  parameter has two issues. 1) Crashes if the channel name does not
+	  exist. 2) Leaks a channel reference if the channel is the current
+	  channel. Problem introduced by ASTERISK-15956. * Updated SendDTMF
+	  documentation. * Renamed app to senddtmf_name and tweaked the
+	  type. ........ Merged revisions 373945 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373946 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-27 17:05 +0000 [r373880-373914]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c, include/asterisk/http_websocket.h,
+	  res/res_http_websocket.c: Make res_http_websocket an optional
+	  dependency on supported platforms for chan_sip. (closes issue
+	  ASTERISK-20439) Reported by: sruffell Patches:
+	  0001-chan_sip-websocket-support-is-an-optional-API.patch uploaded
+	  by sruffell (license 5417)
+
+	* main/loader.c, /: loader: Ensure dependent modules are properly
+	  initialized. If an Asterisk module specifies a dependency in
+	  ast_module_info.nonoptreq, it is possible for Asterisk to skip
+	  calling the modules's .load function. Asterisk was loading and
+	  linking the module via load_dynamic_module() but was not adding
+	  the module to the resource_heap. Therefore the module was not
+	  initialized based on it's priority along with the other modules
+	  in the heap. Now use load_resource() instead of
+	  load_dynamic_module() for non-optional requirement. This will add
+	  the module to the resource_heap so the module can be properly
+	  initialized in the correct order. This is required if there are
+	  any module global data structures initialized in the .load()
+	  callback for the module on platforms which do not support weak
+	  references. (issue ASTERISK-20439) Reported by: sruffell Patches:
+	  0001-loader-Ensure-dependent-modules-are-properly-initial.patch
+	  uploaded by sruffell (license 5417) ........ Merged revisions
+	  373909 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373910 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_local.c, /: Fix an issue where Local channels
+	  dialed by app_queue are considered in use immediately. The
+	  chan_local channel driver returns a device state of in use even
+	  if a created Local channel has not yet been dialed. This fix
+	  changes the logic to return a state of not in use until the
+	  channel itself has been dialed. (closes issue ASTERISK-20390)
+	  Reported by: tim_ringenbach Review:
+	  https://reviewboard.asterisk.org/r/2116/ ........ Merged
+	  revisions 373878 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373879 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-26 21:16 +0000 [r373850]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Move handling of 408 response so there is
+	  no misleading warning message. (closes issue ASTERISK-20060)
+	  Reported by: Walter Doekes ........ Merged revisions 373848 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373849 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-26 18:18 +0000 [r373818]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_meetme.c: Fixed meetme tab completion and command
+	  documentation. * Removed unnecessary case sensitivity in meetme
+	  list, lock, unlock, mute, unmute, and kick commands. * Separated
+	  meetme lock/unlock, mute/unmute, and kick commands into their own
+	  registered commands to simplify tab completion and parameter
+	  checking. meetme_lock_cmd(), meetme_mute_cmd(), and
+	  meetme_kick_cmd() * Simplified meetme_show_cmd() (closes issue
+	  AST-1006) Reported by: John Bigelow Tested by: rmudgett ........
+	  Merged revisions 373815 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373816 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-26 08:29 +0000 [r373804]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* apps/app_queue.c: app_queue: 'agent available' hint, cleanup
+	  restart, and initial state Fix previously untested senarios; 1).
+	  On queue initialisation set queue_avail devstate to INUSE.
+	  Previously was unavailable, which indicated an agent was
+	  available. 2). When removing members, if there are no other
+	  members available, set queue_avail to INUSE. Previously, if a
+	  member interface had become 'unavailable', they were never going
+	  to be removed, particularly when persistant queues is enabled.
+	  3). When adding a member, check that they are available, if they
+	  are set queue_avail to NOT_INUSE. Previously on reloaded, members
+	  may have been 'unavailable'. 4). When pausing or unpausing a
+	  member, set appropriate queue availability. alecdavis (license
+	  585) Reported by: Alec Davis Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/2129/
+
+2012-09-25 23:09 +0000 [r373738-373775]  Mark Michelson <mmichelson at digium.com>
+
+	* /, main/say.c: Fix saying of date in Dutch. The Dutch say the
+	  date before the month. (closes issue ASTERISK-20353) Reported by:
+	  Teun Ouwehand ........ Merged revisions 373773 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373774 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* configs/agents.conf.sample, /, channels/chan_agent.c: Remove dead
+	  code and documentation for nonexistent feature. multiplelogin was
+	  removed from chan_agent back in 1.6.0 when AgentCallbackLogin()
+	  was removed. (closes issue AST-948) reported by Steve Pitts
+	  ........ Merged revisions 373768 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373769 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_voicemail.c, /: Fix error where improper IMAP greetings
+	  would be deleted. (closes issue ASTERISK-20435) Reported by:
+	  fhackenberger Patches: asterisk-20435-imap-del-greeting.diff
+	  uploaded by Michael L. Young (License #5026) (with suggested
+	  modification made by me) ........ Merged revisions 373735 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373737 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 20:13 +0000 [r373707]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_local.c, /: Fix T.38 support when used with
+	  chan_local in between. Users of the T.38 API can indicate
+	  AST_T38_REQUEST_PARMS on a channel to request that the channel
+	  indicate a T.38 negotiation with the parameters present on the
+	  channel. The return value of this indication is expected to be
+	  AST_T38_REQUEST_PARMS upon success but with chan_local involved
+	  this could never occur. This fix changes chan_local to always
+	  return AST_T38_REQUEST_PARMS for this situation. If the
+	  underlying channel technology on the other side does not support
+	  T.38 this would have been determined ahead of time using
+	  ast_channel_get_t38_state and an indication would not occur.
+	  (closes issue ASTERISK-20229) Reported by: wdoekes Patches:
+	  ASTERISK-20229.patch uploaded by wdoekes (license 5674) Review:
+	  https://reviewboard.asterisk.org/r/2070/ ........ Merged
+	  revisions 373705 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373706 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 19:35 +0000 [r373704]  Kinsey Moore <kmoore at digium.com>
+
+	* /: Recorded merge of revisions 373703 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Fix an
+	  issue where media would not flow for situations where the legacy
+	  STUN code is in use. The STUN packets should *not* be blocked by
+	  strict RTP. (closes issue ASTERISK-20415) Reported-by: Michele
+	  Cicciotti Patch-by: Josh Colp (trunk r369817) ........ Merged
+	  revisions 373702 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-09-25 18:52 +0000 [r373690]  Terry Wilson <twilson at digium.com>
+
+	* channels/sip/include/sip.h, /, channels/chan_sip.c,
+	  configs/sip.conf.sample: Properly handle UAC/UAS roles for SIP
+	  session timers The SIP session timer mechanism contains a
+	  mandatory 'refresher' parameter (included in the Session-Expires
+	  header) which is used in the session timer offer/answer signaling
+	  within a SIP Invite dialog. It looks like asterisk is
+	  interpreting the uac resp. uas role only as the initial role of
+	  client and server (caller is uac, callee is uas). The standard
+	  rfc 4028 however assigns the client role to the ((RE)-Invite)
+	  requester, the server role to the ((RE)-Invite) responder. This
+	  patch has Asterisk track the actual refresher as "us" or "them"
+	  as opposed to relying on just the configured "uas" or "uac"
+	  properties. (closes issue AST-922) Reported by: Thomas Airmont
+	  Review: https://reviewboard.asterisk.org/r/2118/ ........ Merged
+	  revisions 373652 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373665 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 18:24 +0000 [r373688]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_queue.c: "show" completion option for "queue"
+	  shouldn't appear twice When tab-completing CLI commands starting
+	  with "queue", "show" appeared twice in the list due to the way
+	  that Asterisk's tab completion functions and the order in which
+	  the commands were registered. The registration order has been
+	  altered to resolve this issue. (closes issue AST-940)
+	  Reported-by: Steve Pitts ........ Merged revisions 373666 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373675 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 17:21 +0000 [r373635-373650]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, codecs/ilbc/iLBC_encode.c, codecs/ilbc/iLBC_decode.c: Fix
+	  valgrind found memcpy issues in codec_ilbc. Valgrind found
+	  codec_ilbc using memcpy instead of memmove for overlapping memory
+	  blocks. (issue ASTERISK-19890) (closes issue ASTERISK-20231)
+	  Reported by: Walter Doekes Patches: ASTERISK-20231.patch (license
+	  #5674) patch uploaded by Walter Doekes ........ Merged revisions
+	  373640 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373645 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* codecs/Makefile, /: Make rebuild GSM, ilbc, or lpc10 codecs if
+	  the respective sources change. ........ Merged revisions 373618
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 373633 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 16:31 +0000 [r373632]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Set Quality of Service for
+	  video rtp instance (closes issue ASTERISK-20201) Reported by:
+	  ddkprog Patches: chan_sip.c.diff uploaded by ddkprog (license
+	  6008) ........ Merged revisions 373617 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373631 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 14:12 +0000 [r373582]  Mark Michelson <mmichelson at digium.com>
+
+	* funcs/func_presencestate.c: "He who go through turnstile sideways
+	  is going to Bangkok"
+
+2012-09-25 13:29 +0000 [r373580]  Kinsey Moore <kmoore at digium.com>
+
+	* configs/res_odbc.conf.sample, /: Fix documentation for default
+	  username in res_odbc This was previously stated to be "root", but
+	  is actually the name of the context if unspecified. (closes issue
+	  ASTERISK-20258) Reported by: Stefan x ........ Merged revisions
+	  373578 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373579 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-25 12:07 +0000 [r373552]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_multicast.c, /: Fix an issue where a caller to
+	  ast_write on a MulticastRTP channel would determine it failed
+	  when in reality it did not. When sending RTP packets via
+	  multicast the amount of data sent is stored in a variable and
+	  returned from the write function. This is incorrect as any
+	  non-zero value returned is considered a failure while a return
+	  value of 0 is success. For callers (such as ast_streamfile) that
+	  checked the return value they would have considered it a failure
+	  when in reality nothing went wrong and it was actually a success.
+	  The write function for the multicast RTP engine now returns -1 on
+	  failure and 0 on success, as it should. (closes issue
+	  ASTERISK-17254) Reported by: wybecom ........ Merged revisions
+	  373550 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373551 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-24 22:17 +0000 [r373508]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Revert change to res_rtp_asterisk
+	  committed in r373236 (1.8) The change committed in r373236
+	  attempted to account for endpoints that increased their RTP
+	  timestamp in DTMF end of event re-transmissions. This change
+	  attempted to make Asterisk continue to work with endpoints that
+	  failed to follow the RFC while maintaining the fix that allowed
+	  for out of order DTMF to be handled. Unfortunately, there is no
+	  free lunch, and this patch broke any system that sent DTMF
+	  immediately after an RTP session was established or when an SSRC
+	  is updated. As such, that patch is being reverted for the
+	  previous behavior. Endpoints that erroneously increase the RTP
+	  timestamp in DTMF end of event packets will not work properly
+	  with Asterisk. (issue ASTERISK-20424) ........ Merged revisions
+	  373504 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373505 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-24 22:12 +0000 [r373502]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Be consistent, send From: "Anonymous"
+	  <sip:anonymous at anonymous.invalid> When setting
+	  CALLERID(pres)=unavailable in the dialplan, the From header in
+	  the SIP message contains "Anonymous"
+	  <sip:Anonymous at anonymous.invalid>. For consistency, Asterisk
+	  should use a lowercase a in the userpart of the URI. * Make the
+	  From header use a lowercase A in the userpart of the anonymous
+	  URI. (closes issue ASTERISK-19838) Reported by: Antti Yrjola
+	  Patches: chan_sip_patch_ASTERISK-19838.patch (license #6383)
+	  patch uploaded by Antti Yrjola ........ Merged revisions 373500
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 373501 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-24 21:12 +0000 [r373470]  Jonathan Rose <jrose at digium.com>
+
+	* funcs/func_audiohookinherit.c, /, apps/app_mixmonitor.c:
+	  func_audiohookinherit: Document some missed sources. This patch
+	  also mentions that AUDIOHOOK_INHERIT can be used to transfer
+	  MixMonitor audiohooks. There is also wiki that addresses
+	  audiohooks and the use of AUDIOHOOK_INHERIT at the following
+	  link: https://wiki.asterisk.org/wiki/display/AST/Audiohooks
+	  (closes issue ASTERISK-18220) Reported by: Ishfaq Malik ........
+	  Merged revisions 373467 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373468 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-24 21:08 +0000 [r373469]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix potential reentrancy problems in
+	  chan_sip. Asterisk v1.8 and later was not as vulnerable to this
+	  issue. * Made find_call() lock each private as it processes the
+	  found dialogs. (Primary cause of ABE-2876) * Made the other
+	  functions that traverse the dialogs container lock each private
+	  as it examines them. * Fix race condition in sip_call() if the
+	  thread that sent the INVITE is held up long enough for a response
+	  to be processed. The p->initid for the INVITE retransmission
+	  could be added after it was canceled by the response processing.
+	  * Made __sip_destroy() clean up resource pointers after freeing.
+	  This is primarily defensive in case someone has a stale private
+	  pointer. * Removed redundant memset() in reqprep(). The call to
+	  init_req() already does the memset() and is the first reference
+	  to req in reqprep(). * Removed useless set of req.method in
+	  transmit_invite(). The calls to initreqprep() and reqprep() have
+	  to do this because they memset() the req. JIRA ABE-2876
+	  .......... Merged -r373423 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 373424 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373466 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-24 19:21 +0000 [r373413-373454]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: Fix a deadlock caused by a race condition
+	  between removing a hint and reloading the dialplan and
+	  subscribing to the removed hint. If conditions were right it was
+	  possible for both the PBX core and chan_sip to deadlock by both
+	  having a lock that the other wants. In the case of the PBX core
+	  it had the contexts lock and wanted a SIP dialog lock, while in
+	  the case of chan_sip it had the SIP dialog lock and wanted the
+	  contexts lock. This fix unlocks the SIP dialog before getting the
+	  extension state so that the other thread will not block on trying
+	  to lock it. Once the extension state is retrieved the SIP dialog
+	  is locked again and life carries on. As the SIP dialog is
+	  reference counted it is not possible for it to go away after
+	  unlocking. (closes issue ASTERISK-20437) Reported by: jhutchins
+	  ........ Merged revisions 373438 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373440 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_sip.c, res/res_format_attr_h264.c: Fix an issue
+	  with H.264 format attribute comparison and fix an issue with
+	  improper SDP being produced. The H.264 format attribute module
+	  compares two format attribute structures to determine if they are
+	  compatible or not. In some instances it was possible for this
+	  check to determine that both structures were incompatible when
+	  they actually should be considered compatible. This check has now
+	  been made even more permissive by assuming that if no attribute
+	  information is available the two structures are compatible. If
+	  both structures contain attribute information a base level
+	  comparison of the H.264 IDC value is done to see if they are
+	  compatible or not. The above issue uncovered a secondary issue in
+	  chan_sip where the SDP being produced would be incorrect if the
+	  formats were considered incompatible. This has now been fixed by
+	  checking that all information required to produce the SDP is
+	  available instead of assuming it is. (closes issue
+	  ASTERISK-20464) Reported by: Leif Madsen
+
+2012-09-24 12:33 +0000 [r373403]  beagles <beagles at localhost>:
+
+	* res/res_rtp_asterisk.c, configs/rtp.conf.sample:
+	  res_rtp_asterisk: Make TURN and STUN server configurations
+	  consistent. This patch removes the turnport configuration
+	  property and changes the turnaddr property to be a combined
+	  host[:port] configuration string. The patch also modifies the
+	  documentation in the example configuration to reflect the
+	  property changes and adds some additional text indicating how the
+	  STUN port is configured. (closes issue ASTERISK-20344) Reported
+	  by: beagles Tested by: beagles Review:
+	  https://reviewboard.asterisk.org/r/2111/
+
+2012-09-21 19:29 +0000 [r373318-373368]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/iax2-provision.c: iax2-provision: Fix improper return
+	  on failed cache retrieval (closes issue ASTERISK-20337) reported
+	  by: John Covert Patches: iax2-provision.c.patch uploaded by John
+	  Covert (license 5512) ........ Merged revisions 373342 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373343 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: app_queue: Make queue reload members and
+	  variants of that work Prior to this patch, 'queue reload members'
+	  cli command did not work at all. This also affects the manager
+	  function 'QueueReload' when supplied with the 'members: yes'
+	  field. (closes issue AST-956) Reported by: John Bigelow ........
+	  Merged revisions 373298 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373300 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-20 19:16 +0000 [r373246]  Joshua Colp <jcolp at digium.com>
+
+	* /, apps/app_meetme.c: Fix incorrect MeetME conference bridge
+	  reference count decrementing and sometimes premature destruction.
+	  When using the 'e' or 'E' option to MeetMe the configured
+	  conference bridges are loaded and examined to see if any are
+	  empty. If no conference bridges are empty the caller is prompted
+	  to enter the number of one. This operation left around a pointer
+	  to the last created conference bridge still containing
+	  participants. When the caller that was not able to find any empty
+	  conference bridge hung up this pointer was disposed of and the
+	  reference count of the conference bridge decremented. If there
+	  was only a single participant in the conference bridge it was
+	  ultimately destroyed prematurely. (closes issue AST-994) Reported
+	  by: John Bigelow ........ Merged revisions 373242 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373245 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-20 18:59 +0000 [r373235-373240]  Matthew Jordan <mjordan at digium.com>
+
+	* configs/extensions.conf.sample, CHANGES, apps/app_queue.c:
+	  app_queue: Support an 'agent available' hint Sets INUSE when no
+	  free agents, NOT_INUSE when an agent is free. modifes
+	  handle_statechange() scan members loop to scan for a free agent
+	  and updates the Queue:queuename_avial devstate. Previously exited
+	  early if the member was found in the queue. Now Exits later when
+	  both a member was found, and a free agent was found. alecdavis
+	  (license 585) Reported by: Alec Davis Tested by: alecdavis
+	  Review: https://reviewboard.asterisk.org/r/2121/ ~~~~ Support all
+	  ways a member can be available for 'agent available' hints Alec's
+	  patch in r373188 added the ability to subscribe to a hint for
+	  when Queue members are available. This patch modifies the check
+	  that determines when a Queue member is available by refactoring
+	  the availability checks in num_available_members into a shared
+	  function is_member_available. This should now handle the
+	  ringinuse option, as well as device state values other than
+	  AST_DEVICE_NOT_INUSE.
+
+	* res/res_rtp_asterisk.c, /: When processing RFC 2833 DTMF,
+	  accomodate increasing timestamps in End events While endpoints
+	  should not be changing the source timestamp between DTMF event
+	  packets, the fact is there exists those endpoints that do exactly
+	  that. To work around this, we absorb timestamps within the
+	  expected re-transmit period. Note that this period only affects
+	  End of Event packets, so it should not prevent the detection of
+	  new DTMF digits that happen to arrive right on top of each other.
+	  (closes issue ASTERISK-20424) Reported by: Vladimir Mikhelson
+	  Tested by: mjordan, Vladimir Mikhelson Review:
+	  https://reviewboard.asterisk.org/r/2124 ........ Merged revisions
+	  373236 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373237 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* configs/extensions.conf.sample, CHANGES, apps/app_queue.c: Add
+	  queue monitoring hints This patch adds support for hints on a
+	  queue. Hints can be added using the nomenclature 'Queue:name',
+	  where name is the name of the queue being monitored. This nifty
+	  feature was done by Alec Davis. Review:
+	  https://reviewboard.asterisk.org/r/1619 Reported by: Alec Davis
+	  Tested by: alecdavis patches: review1619.diff2 by alecdavis
+	  (license 585)
+
+2012-09-20 18:18 +0000 [r373229]  Joshua Colp <jcolp at digium.com>
+
+	* channels/sip/include/sip.h, res/res_rtp_asterisk.c,
+	  main/rtp_engine.c, channels/chan_sip.c, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac,
+	  configs/sip.conf.sample, include/asterisk/rtp_engine.h: Add
+	  support for DTLS-SRTP to res_rtp_asterisk and chan_sip. As
+	  mentioned on the review for this, WebRTC has moved towards
+	  choosing DTLS-SRTP as the mechanism for key exchange for SRTP.
+	  This commit adds support for this but makes it available for
+	  normal SIP clients as well. Testing has been done to ensure that
+	  this introduces no regressions with existing behavior and also
+	  that it functions as expected. Review:
+	  https://reviewboard.asterisk.org/r/2113/
+
+2012-09-20 17:15 +0000 [r373220]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/features.h, main/channel.c,
+	  apps/app_directed_pickup.c, funcs/func_channel.c,
+	  main/features.c, include/asterisk/channel.h: Named call pickup
+	  groups. Fixes, missing functionality, and improvements. *
+	  ASTERISK-20383 Missing named call pickup group features:
+	  CHANNEL(callgroup) - Need CHANNEL(namedcallgroup)
+	  CHANNEL(pickupgroup) - Need CHANNEL(namedpickupgroup) Pickup() -
+	  Needs to also select from named pickup groups. * ASTERISK-20384
+	  Using the pickupexten, the pickup channel selection could fail
+	  even though there was a call it could have picked up. In a call
+	  pickup race when there are multiple calls to pickup and two
+	  extensions try to pickup a call, it is conceivable that the loser
+	  will not pick up any call even though it could have picked up the
+	  next oldest matching call. Regression because of the named call
+	  pickup group feature. * See ASTERISK-20386 for the implementation
+	  improvements. These are the changes in channel.c and channel.h. *
+	  Fixed some locking issues in CHANNEL(). (closes issue
+	  ASTERISK-20383) Reported by: rmudgett (closes issue
+	  ASTERISK-20384) Reported by: rmudgett (closes issue
+	  ASTERISK-20386) Reported by: rmudgett Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/2112/
+
+2012-09-20 13:00 +0000 [r373211]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c: Correct handling of unknown SDP stream types
+	  When the patch to handle arbitrary SDP stream arrangements went
+	  into Asterisk, it also included an ability to transparently
+	  decline unknown stream types. The scanf calls used were not
+	  checked properly causing this part of the functionality to be
+	  broken. (closes issue ASTERISK-20203)
+
+2012-09-18 20:14 +0000 [r373133]  Sean Bright <sean at malleable.com>
+
+	* main/manager.c, /: Don't crash when passing a NULL message to
+	  __astman_get_header. Before this commit, __astman_get_header
+	  would blindly dereference the passed in 'struct message *' to
+	  traverse the header list. There are cases, however, such as
+	  '*CLI> sip qualify peer foo' where the message pointer is NULL,
+	  so we need to check for that. ........ Merged revisions 373131
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 373132 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-18 15:47 +0000 [r373119]  dlee <dlee at localhost>:
+
+	* Makefile, include/asterisk/utils.h, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac, makeopts.in: Add
+	  -fnested-functions compile flag, if needed. In order to use
+	  nested functions on some versions of GCC (e.g. GCC on OS X), the
+	  -fnested-functions flag must be passed to the compiler. This
+	  patch adds detection logic to ./configure to add the flag if
+	  necessary. It also adds a comment to utils.h as to why the nested
+	  function needs a prototype. (closes issue ASTERISK-20399)
+	  Reported by: David M. Lee Review:
+	  https://reviewboard.asterisk.org/r/2102/
+
+2012-09-15 00:27 +0000 [r373107]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_ss7.c, /: Made companding law for SS7 calls only
+	  determined by SS7 signaling type. For SS7, the companding law for
+	  a call was chosen inconsistently depending upon ss7type (ITU vs
+	  ANSI) and the DAHDI companding default (T1 vs E1). For incoming
+	  calls, the companding law was determined by ss7type. For outgoing
+	  calls, the companding law was determined by the DAHDI default.
+	  With the wrong combination you would get A-law/u-law conflicts.
+	  An A-law/u-law conflict sounds like bad static on the line. SS7
+	  ITU signaling with E1 line: ok SS7 ITU signaling with T1 line:
+	  noise SS7 ANSI signaling with E1 line: noise SS7 ANSI signaling
+	  with T1 line: ok * Fix the companding law used to be determined
+	  by the SS7 signaling type only. ........ Merged revisions 373090
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 373101 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-14 19:50 +0000 [r373079]  Matthew Jordan <mjordan at digium.com>
+
+	* main/tcptls.c, /, channels/chan_sip.c, main/libasteriskssl.c:
+	  Resolve memory leaks in TLS initialization and TLS client
+	  connections This patch resolves two sources of memory leaks when
+	  using TLS in Asterisk: 1) It removes improper initialization (and
+	  multiple re-initializations) of portions of the SSL library.
+	  Asterisk calls SSL_library_init and SSL_load_error_strings during
+	  SSL initialization; collectively this obviates the need for
+	  calling any of the following during initialization or client
+	  connection handling: * ERR_load_crypto_strings (handled by
+	  SSL_load_error_strings) * OpenSSL_add_all_algorithms (synonym for
+	  SSL_library_init) * SSLeay_add_ssl_algorithms (synonym for
+	  SSL_library_init) 2) Failure to completely clean up all memory
+	  allocated by Asterisk and by the SSL library for TLS clients.
+	  This included not freeing the SSL_CTX object in the SIP channel
+	  driver, as well as not clearing the error stack when the TLS
+	  client exited. Note that these memory leaks were found by Thomas
+	  Arimont, and this patch was essentially written by him with some
+	  minor tweaks. (closes issue AST-889) Reported by: Thomas Arimont
+	  Tested by: Thomas Arimont patches: (bugAST-889.patch) by Thomas
+	  Arimont (license 5525) Review:
+	  https://reviewboard.asterisk.org/r/2105 ........ Merged revisions
+	  373061 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 373062 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-13 20:04 +0000 [r373029-373047]  dlee <dlee at localhost>:
+
+	* main/Makefile: Fixed make clean when configured
+	  --disable-asteriskssl
+
+	* main/channel.c, /, include/asterisk/channel.h: Fix timeouts for
+	  ast_waitfordigit[_full]. ast_waitfordigit_full would simply pass
+	  its timeout to ast_waitfor_nandfds, expecting it to decrement the
+	  timeout by however many milliseconds were waited. This is a
+	  problem if it consistently waits less than 1ms. The timeout will
+	  never be decremented, and we wait... FOREVER! This patch makes
+	  ast_waitfordigit_full manage the timeout itself. It maintains the
+	  previously undocumented behavior that negative timeouts wait
+	  forever. (closes issue ASTERISK-20375) Reported by: Mark
+	  Michelson Tested by: Mark Michelson Review:
+	  https://reviewboard.asterisk.org/r/2109/ ........ Merged
+	  revisions 373024 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 373025 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-12 20:53 +0000 [r372995]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Skip any non-content information when
+	  looking for and handling content. This fixes a bug with Jitsi and
+	  conference calling. Jitsi implements XEP-0298 which places some
+	  conference-info information in the session-initiate request which
+	  chan_motif did not expect to occur.
+
+2012-09-12 18:23 +0000 [r372984]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_xmpp.c: res_xmpp: Fix a segfault caused by bodyless
+	  messages (closes issue ASTERISK-20361) Reported by: Noah
+	  Engelberth Review: https://reviewboard.asterisk.org/r/2108/
+
+2012-09-12 15:19 +0000 [r372937]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Add channel name to a warning to make
+	  debugging easier. The "autodestruct with owner in place" message
+	  is typically indicative of a channel reference leak. Printing out
+	  the name of the channel in the message may be helpful when trying
+	  to debug the issue. ........ Merged revisions 372932 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372933 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-12 14:18 +0000 [r372930]  dlee <dlee at localhost>:
+
+	* main/Makefile: Fixed r372696 when configured
+	  --disable-asteriskssl; properly install libasteriskssl.dylib on
+	  OS X. I didn't realize that libasteriskssl.c was still compiled,
+	  even when you disable asteriskssl; it simple gets statically
+	  linked into asterisk.
+
+2012-09-11 22:32 +0000 [r372917]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_local.c, /: chan_local: Switch from using a random
+	  4 digit hex identifier to unique id Changes chan_local channels
+	  to use an 8 digit hex identifier generated atomically and
+	  sequentially in order to eliminate the chance of having multiple
+	  channels with the same name during high call volume situations.
+	  (issue ASTERISK-20318) Reported by: Dan Cropp Review:
+	  https://reviewboard.asterisk.org/r/2104/ ........ Merged
+	  revisions 372902 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-11 21:15 +0000 [r372886-372888]  Mark Michelson <mmichelson at digium.com>
+
+	* main/asterisk.c, /, include/asterisk/_private.h, main/message.c:
+	  Fix inability to shutdown gracefully due to an unending channel
+	  reference. message.c makes use of a special message queue channel
+	  that exists in thread storage. This channel never goes away due
+	  to the fact that the taskprocessor used by message.c does not get
+	  shut down, meaning that it never ends the thread that stores the
+	  channel. This patch fixes the problem by shutting down the
+	  taskprocessor when Asterisk is shut down. In addition, the thread
+	  storage has a destructor that will release the channel reference
+	  when the taskprocessor is destroyed. (closes issue AST-937)
+	  Reported by Jason Parker Patches: AST-937.patch uploaded by Mark
+	  Michelson (License #5049) Tested by Jason Parker ........ Merged
+	  revisions 372885 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/features.c: Fix bad channel application data reference.
+	  When channels get bridged due to an AMI bridge action or a DTMF
+	  attended transfer, the two channels that get bridged have their
+	  application data pointing to the other channel's name. This means
+	  that if one channel is hung up but the other moves on, it means
+	  that the channel that moves on will have its application data
+	  pointing at freed memory. (issue ASTERISK-20335) Reported by:
+	  aragon ........ Merged revisions 372840 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372841 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-11 17:16 +0000 [r372864]  dlee <dlee at localhost>:
+
+	* Makefile, /: Corrects the astsbindir setting when installing the
+	  sample asterisk.conf. (closes issue ASTERISK-20406) ........
+	  Merged revisions 372863 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-10 20:59 +0000 [r372795-372806]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_iax2.c: Ensure iax2 debug output is displayed
+	  when expected When IAX2 debug was changed from iax_showframe to
+	  iax_outputframe, some instances were missed (or added afterward).
+	  This was causing debug output to not be displayed when expected.
+	  (closes issue ASTERISK-20338) Reported-by: John Covert Patch-by:
+	  John Covert ........ Merged revisions 372804 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372805 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_jingle.c, include/asterisk/doxygen/architecture.h,
+	  main/devicestate.c, channels/chan_gtalk.c, res/res_jabber.c:
+	  Deprecate chan_gtalk, chan_jingle, and res_jabber chan_gtalk,
+	  chan_jingle, and res_jabber are now deprecated in favor of using
+	  chan_motif and res_xmpp. They are a feature-equivalent
+	  replacement and are written to be more easily maintainable.
+	  (closes issue ASTERISK-20298) Review:
+	  https://reviewboard.asterisk.org/r/2082/ Reported-by: Leif Madsen
+
+2012-09-10 19:19 +0000 [r372777]  dlee <dlee at localhost>:
+
+	* res/res_rtp_asterisk.c: res_rtp_asterisk: Eliminate "type-punned
+	  pointer" build warning. Removes "res_rtp_asterisk.c:706: warning:
+	  dereferencing type-punned pointer will break strict-aliasing
+	  rules" warning from the build on 32-bit platforms. The problem is
+	  that 'size' was referenced aliased to both (pj_size_t *) and
+	  (pj_ssize_t *). Now just make a copy of size that is the right
+	  type so there isn't any pointer aliasing happening. It also adds
+	  comments and asserts regarding what looks like an inappropriate
+	  use of pj_sock_sendto, but is actually totally fine. (closes
+	  issue ASTERISK-20368) Reported by: Shaun Ruffel Tested by:
+	  Michael L. Young Patches:
+	  0001-res_rtp_asterisk-Eliminate-type-punned-pointer-build.patch
+	  uploaded by Shaun Ruffel (license 5417) slightly modified by
+	  David M. Lee.
+
+2012-09-10 18:50 +0000 [r372768]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: app_meetme: Document that 'p' option will
+	  continue in dialplan. (closes issue AST-991) Reported by John
+	  Bigelow ........ Merged revisions 372765 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372767 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-10 18:37 +0000 [r372766]  Kinsey Moore <kmoore at digium.com>
+
+	* /: Recorded merge of revisions 372764 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Warn on
+	  CLI when UDPTL init fails This adds a CLI warning when a SDP
+	  offer is rejected due to UDPTL initialization failure.
+	  Previously, there was no indication of the reason for offer
+	  rejection in this case. (closes issue ASTERISK-20357)
+	  Reported-by: Francesco Usseglio Gaudi ........ Merged revisions
+	  372763 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-09-10 17:33 +0000 [r372754]  Jonathan Rose <jrose at digium.com>
+
+	* main/channel.c, /: Masquerade: Retain parkinglot settings made by
+	  CHANNEL function. Prior to this patch, the user would have a
+	  parkinglot set on a channel that was parked and when the channel
+	  was retrieved, any attempt by that channel to park would simply
+	  use the default. This patch makes parkinglot values set in this
+	  way be retained through the masquerade. (closes issue AST-990)
+	  Reported by: Nick Huskinson Patches:
+	  masquerade_parkinglot_patch.diff Uploaded by Jonathan Rose
+	  (license 6182) ........ Merged revisions 372736 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372737 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-09 01:25 +0000 [r372711]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/sip/sdp_crypto.c, /: Only re-create an SRTP session when
+	  needed In r356604, SRTP handling was fixed to accomodate multiple
+	  crypto keys in an SDP offer and the ability to re-create an SRTP
+	  session when the crypto keys changed. In certain circumstances -
+	  most notably when a phone is put on hold after having been
+	  bridged for a significant amount of time - the act of re-creating
+	  the SRTP session causes problems for certain models of phones.
+	  The patch committed in r356604 always re-created the SRTP session
+	  regardless of whether or not the cryptographic keys changed.
+	  Since this is technically not necessary, this patch modifies the
+	  behavior to only re-create the SRTP session if Asterisk detects
+	  that the remote key has changed. This allows models of phones
+	  that do not handle the SRTP session changing to continue to work,
+	  while also providing the behavior needed for those phones that do
+	  re-negotiate cryptographic keys. (issue ASTERISK-20194) Reported
+	  by: Nicolo Mazzon Tested by: Nicolo Mazzon Review:
+	  https://reviewboard.asterisk.org/r/2099 ........ Merged revisions
+	  372709 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 372710 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-08 05:51 +0000 [r372696]  dlee <dlee at localhost>:
+
+	* /, main/Makefile: Recorded merge of revisions 372695 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Add
+	  OPENSSL_INCLUDE to the CFLAGS for ssl.c and tcptls.c. Without
+	  this flag, those files will compile with the system installed
+	  OpenSSL headers (if they exist). This is a real bummer if a
+	  different path was specified using --with-ssl= (closes issue
+	  ASTERISK-20392) ........ Merged revisions 372682 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-09-07 23:07 +0000 [r372622-372657]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/astmm.c: Fix MALLOC_DEBUG version of ast_strndup().
+	  (closes issue ASTERISK-20349) Reported by: Brent Eagles ........
+	  Merged revisions 372655 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, funcs/func_math.c: Remove annoying unconditional debug message
+	  from INC/DEC functions. (closes issue AST-1001) Reported by:
+	  Guenther Kelleter ........ Merged revisions 372628 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372629 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Fix exception path typo in app_queue.c
+	  try_calling(). (closes issue ASTERISK-20380) Reported by: Jeremy
+	  Pepper Patches: fix-local-channel-locking.patch (license #6350)
+	  patch uploaded by Jeremy Pepper ........ Merged revisions 372624
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 372625 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_voicemail.c, /: Fix VoicemailUserEntry event headers
+	  ServerEmail and MailCommand reported values. The AMI action
+	  VoicemailUsersList VoicemailUserEntry event headers ServerEmail
+	  and MailCommand did not report the global values if they were not
+	  overridden. The VoicemailUserEntry event header ServerEmail was
+	  not populated with the global value if the voicemail user did not
+	  override it. The VoicemailUserEntry event header MailCommand was
+	  never populated with a value. * Removed unused struct ast_vm_user
+	  member mailcmd[]. (closes issue AST-973) Reported by: John
+	  Bigelow Tested by: rmudgett ........ Merged revisions 372620 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372621 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-07 21:04 +0000 [r372609-372611]  dlee <dlee at localhost>:
+
+	* res/pjproject/pjlib-util/lib, res/pjproject/pjmedia/bin,
+	  res/pjproject/third_party/bin, res/pjproject/third_party/gsm/lib,
+	  res/pjproject/lib, res/pjproject/pjlib/lib,
+	  res/pjproject/third_party/gsm/bin, res/pjproject/pjnath/lib,
+	  res/pjproject/pjsip/lib, res/pjproject/pjsip-apps/lib,
+	  res/pjproject/pjsip/bin, res/pjproject/pjsip-apps/bin,
+	  res/pjproject/pjmedia/lib, res/pjproject/third_party/lib,
+	  codecs/ilbc: svn:ignore cleanup. * pjproject bin and lib
+	  directories should pretty much ignore everything * Ignore *.o in
+	  codecs/ilbc
+
+	* res/Makefile: Fix parallel make for res_asterisk_rtp. Fixes a
+	  build regression introduced in r369517 "Add support for
+	  ICE/STUN/TURN in res_rtp_asterisk and chan_sip." [1]. [1]
+	  http://svnview.digium.com/svn/asterisk?view=revision&revision=369517
+	  When compiling asterisk in parallel like: $ make -j 10 It's
+	  possible to get errors like the following:
+	  .pjlib-util-test-x86_64-unknown-linux-gnu.depend:120: *** missing
+	  separator. Stop. make[4]: *** [depend] Error 2 make[3]: *** [dep]
+	  Error 1 make[2]: ***
+	  [/home/sruffell/asterisk-working/res/pjproject/pjnath/lib/libpjnath-x86_64-unknown-linux-gnu.a]
+	  Error 2 make[3]: warning: jobserver unavailable: using -j1. Add
+	  `+' to parent make rule. This is because the build system is
+	  trying to build each of the libraries in pjproject in parallel.
+	  Now the build will build pjproject in a single job and link the
+	  results into res_asterisk_rtp. Parallel builds, on one test
+	  system, saves ~1.5 minutes from a default Asterisk build: Single
+	  job: $ git clean -fdx >/dev/null && time ( ./configure >/dev/null
+	  2>&1 && make >/dev/null 2>&1 ) real 2m34.529s user 1m41.810s sys
+	  0m15.970s Parallel make: $ git clean -fdx >/dev/null && time (
+	  ./configure >/dev/null 2>&1 && make -j10 >/dev/null 2>&1 ) real
+	  1m2.353s user 2m39.120s sys 0m18.850s (closes issue
+	  ASTERISK-20362) Reported by: Shaun Ruffel Patches:
+	  0001-res_asterisk_rtp-Fix-build-error-when-using-parallel.patch
+	  uploaded by Shaun Ruffel (License #5417)
+
+2012-09-07 02:26 +0000 [r372531-372583]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_minivm.c: Free ast_str objects when temp file fails
+	  to be created in MiniVM The previous commit (r372554) was from a
+	  patch that was written before r366880, which ensured that ast_str
+	  objects allocated in the sendmail routine were free'd in off
+	  nominal paths. This commit frees the string objects in the off
+	  nominal path introduced in r372554. (issue ASTERISK-17133)
+	  Reported by: Tzafrir Cohen ........ Merged revisions 372581 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372582 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_minivm.c: Fix file descriptor leak and pointer scope
+	  issue in MiniVM when sending mail When MiniVM sends an e-mail and
+	  it has the volgain option set, it will spawn sox in a separate
+	  process to handle the manipulation of the sound file. In doing
+	  so, it creates a temporary file. There are two problems here: 1)
+	  The file descriptor returned from mkstemp is leaked 2) The
+	  finalfilename character pointer points to a buffer that loses
+	  scope once volgain processing is finished. Note that in r316265,
+	  Russell fixed some gcc warnings by using the return value of the
+	  mkstemp call. A warning was placed in minivm that the file
+	  descriptor was going to be leaked. This patch reverts that
+	  change, as it handles the leak and 'uses' the file descriptor
+	  returned from mkstemp. (closes issue ASTERISK-17133) Reported by:
+	  Tzafrir Cohen patches: minivm_18501_demo.diff uploaded by Tzafrir
+	  Cohen (license #5035) ........ Merged revisions 372554 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372555 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_queue.c: Update QueueMemberStatus event documentation to
+	  include member status values The Status: header in a
+	  QueueMemberStatus event (and other QueueMember* events) is the
+	  numeric value of the device state corresponding to that Queue
+	  Member. As those values are not exactly obvious, listing them in
+	  the documentation is useful. Matt Riddell reported this
+	  indirectly through the wiki page. (closes issue ASTERISK-20243)
+	  Reported by: Matt Riddell
+
+2012-09-06 22:12 +0000 [r372523]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Fix loss of MOH on an ISDN channel when
+	  parking a call for the second time. Using the AMI redirect action
+	  to take an ISDN call out of a parking lot causes the MOH state to
+	  get confused. The redirect action does not take the call off of
+	  hold. When the call is subsequently parked again, the call no
+	  longer hears MOH. * Make chan_dahdi/sig_pri restart MOH on
+	  repeated AST_CONTROL_HOLD frames if it is already in a state
+	  where it is supposed to be sending MOH. The MOH may have been
+	  stopped by other means. (Such as killing the generator.) This
+	  simple fix is done rather than making the AMI redirect action
+	  post an AST_CONTROL_UNHOLD unconditionally when it redirects a
+	  channel and thus potentially breaking something with an
+	  unexpected AST_CONTROL_UNHOLD. (closes issue ABE-2873) Patches:
+	  jira_abe_2873_c.3_bier.patch (license #5621) patch uploaded by
+	  rmudgett ........ Merged revisions 372521 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  ........ Merged revisions 372522 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-06 21:42 +0000 [r372519]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_queue.c: Ensure listed queues are not offered for
+	  completion When using tab-completion for the list of queues on
+	  "queue reset stats" or "queue reload
+	  {all|members|parameters|rules}", the tab-completion listing for
+	  further queues erroneously listed queues that had already been
+	  added to the list. The tab-completion listing now only displays
+	  queues that are not already in the list. (closes issue AST-963)
+	  Reported-by: John Bigelow ........ Merged revisions 372517 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372518 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-06 18:55 +0000 [r372500]  dsessions <dsessions at localhost>:
+
+	* channels/chan_sip.c, configs/res_ldap.conf.sample: LDAP Realtime
+	  Peers Cannot Register Prior to 1.8, it was not necessary for an
+	  explicit "type" to be set for an asterisk LDAP realtime peer. Now
+	  the routine find_peer actually checks the type field during
+	  registration and fails to find the peer if it is not set. The
+	  attached patches make the realtime type equal whatever type is
+	  being searched for if the type is 0 upon return from routine
+	  build_peer. (closes issue ASTERISK-17222) Reported by: John
+	  Covert Patch by: David Vossel Tested by: Darren Sessions Review:
+	  https://reviewboard.asterisk.org/r/2095/
+
+2012-09-06 15:56 +0000 [r372473]  Jonathan Rose <jrose at digium.com>
+
+	* /, UPGRADE-1.8.txt: chan_sip: Note change in behavior to how
+	  directmediapermit/deny ACL works r366547 introduced a change to
+	  the directmedia ACL for chan_sip which modified the behavior
+	  significantly. Prior to the patch, this option would bridge peers
+	  with directmedia if a peer's IP address matched its own
+	  directmedia ACL. After that patch, the peer would check the
+	  bridged peer's ACL instead. This change has been present since
+	  1.8.14.0. That patched failed to document the change in
+	  Upgrade.txt, so this patch adds mention of that change to
+	  UPGRADE.txt (UPGRADE-1.8.txt in newer branches) (issue AST-876)
+	  ........ Merged revisions 372471 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372472 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-06 14:30 +0000 [r372446]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_queue.c: Ensure "rules" is tab-completable for "queue
+	  show" Previously, tabbing at the end of "queue show" produced a
+	  list of available queues about which information could be shown,
+	  but did not include an alternative command, "rules", to access
+	  information about queue rules. The "rules" item should now be
+	  shown in the list of tab-completable items. (closes issue
+	  AST-958) Reported-by: John Bigelow ........ Merged revisions
+	  372444 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 372445 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-06 02:50 +0000 [r372392-372419]  Matthew Jordan <mjordan at digium.com>
+
+	* /, pbx/pbx_dundi.c: Fix DUNDi message routing bug when
+	  neighboring peer is unreachable Consider a scenario where DUNDi
+	  peer PBX1 has two peers that are its neighbors, PBX2 and PBX3,
+	  and where PBX2 and PBX3 are also neighbors. If the connection is
+	  temporarily broken between PBX1 and PBX3, PBX1 should not include
+	  PBX3 in the list of peers it sends to PBX2 in a DPDISCOVER
+	  message, as it cannot send messages to PBX3. If it does, PBX2
+	  will assume that PBX3 already received the message and fail to
+	  forward the message on to PBX3 itself. This patch fixes this by
+	  only including peers in a DPDISCOVER message that are reachable
+	  by the sending node. This includes all peers with an empty
+	  address (00:00:00:00:00:00) and that are have been reached by a
+	  qualify message. This patch also prevents attempting to qualify a
+	  dynamic peer with an empty address until that peer registers.
+	  (closes issue ASTERISK-19309) Reported by: Peter Racz patches:
+	  dundi_routing.patch uploaded by Peter Racz (license 6290) The
+	  patch uploaded by Peter was modified slightly for this commit.
+	  ........ Merged revisions 372417 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372418 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_followme.c: Allow configured numbers for FollowMe to
+	  be greater than 90 characters When parsing a 'number' defined in
+	  followme.conf, FollowMe previously parsed the number in the
+	  configuration file into a buffer with a length of 90 characters.
+	  This can artificially limit some parallel dial scenarios. This
+	  patch allows for numbers of any length to be defined in the
+	  configuration file. Note that Clod Patry originally wrote a patch
+	  to fix this problem and received a Ship It! on the JIRA issue.
+	  The patch originally expanded the buffer to 256 characters.
+	  Instead, the patch being committed duplicates the string in the
+	  config file on the stack before parsing it for consumption by the
+	  application. (closes issue ASTERISK-16879) Reported by: Clod
+	  Patry Tested by: mjordan patches: followme_no_limit.diff uploaded
+	  by Clod Patry (license #5138) Slightly modified for this commit.
+	  ........ Merged revisions 372390 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372391 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 19:43 +0000 [r372373]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/dsp.c, /: Fix compile error. ........ Merged revisions
+	  372372 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 19:24 +0000 [r372365]  Kinsey Moore <kmoore at digium.com>
+
+	* main/manager.c, /: Correct documentation for ModuleLoad AMI
+	  action The documentation incorrectly listed 'rtp' as a reloadable
+	  subsystem and left out many other reloadable subsystems. It is
+	  now also documented that subsystems may only be reloaded, not
+	  loaded or unloaded. (closes issue AST-977) Reported-by: John
+	  Bigelow ........ Merged revisions 372354 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372358 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 18:46 +0000 [r372342]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* main/dsp.c, /: dsp.c: in ast_mf_detect_init incorrectly sets
+	  goertzel samples to 160, should be MF_GSIZE Related
+	  https://reviewboard.asterisk.org/r/2097/ ........ Merged
+	  revisions 372339 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372341 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 18:36 +0000 [r372340]  Kinsey Moore <kmoore at digium.com>
+
+	* main/pbx.c, /: Ensure counts generated in
+	  manager_show_dialplan_helper are correct When
+	  manager_show_dialplan_helper was written, the counter increment
+	  for the total number of contexts was placed with the extensions
+	  increment instead of in the enclosing loop. This function should
+	  now generate correct context counts. (closes issue AST-970)
+	  Reported-by: John Bigelow ........ Merged revisions 372337 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372338 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 17:35 +0000 [r372327-372328]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_rtp_asterisk.c: Fix coding guidelines issue with a recent
+	  commit.
+
+	* res/res_rtp_asterisk.c: Fix RTP/RTCP read error message
+	  confusion. The RTP/RTCP read error message can report "fail:
+	  success" when the read failure is because of an ICE failure. *
+	  Changed __rtp_recvfrom() to generate a PJ ICE message when ICE
+	  fails. * Changed RTP/RTCP read error message to indicate an
+	  unspecified error when errno is zero. (closes issue
+	  ASTERISK-20288) Reported by: Joern Krebs Patches:
+	  jira_asterisk_20288_err_msg.patch (license #5621) patch uploaded
+	  by rmudgett (modified)
+
+2012-09-05 16:04 +0000 [r372311]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_rtp_asterisk.c, main/rtp_engine.c,
+	  include/asterisk/rtp_engine.h: Re-fix sending unnegotiated
+	  payloads during a P2P RTP bridge. The previous fix still would
+	  look in the static_RTP_PT table, which is inappropriate since we
+	  specifically want to find a codec that has been negotiated.
+	  (closes issue ASTERISK-20296) reported by NITESH BANSAL Patches:
+	  codec_negotiation.patch Uploaded by NITESH BANSAL (License #6418)
+
+2012-09-05 13:47 +0000 [r372289]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c, /: Fix memory leaks in app_voicemail when
+	  using IMAP storage or realtime config This patch fixes two memory
+	  leaks: 1. When find_user is called with NULL as its first
+	  parameter, the voicemail user returned is allocated on the heap.
+	  The inboxcount2 function uses find_user in such a fashion when
+	  counting new messages, and fails to free the resulting voicemail
+	  user object. 2. When populate_defaults is called on a voicemail
+	  user, it wipes whatever flags have been set on the object by
+	  copying over the global flags object. If the VM_ALLOCED flag was
+	  ste on the voicemail user prior to doing so, that flag is
+	  removed. This leaks the voicemail user when free_user is later
+	  called. (closes issue ASTERISK-19155) Reported by: Filip Jenicek
+	  patches: asterisk.patch2 uploaded by Filip Jenicek (license 6277)
+	  Patch slightly modified for this commit. Review:
+	  https://reviewboard.asterisk.org/r/2096 ........ Merged revisions
+	  372268 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 372288 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 12:17 +0000 [r372266]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* res/res_rtp_asterisk.c: Fix breakage caused by last merge.
+	  Missing a variable for 11 and trunk.
+
+2012-09-05 07:41 +0000 [r372214-372241]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* main/dsp.c, /: dsp.c: Fix multiple issues when no-interdigit
+	  delay is present, and fast DTMF 50ms/50ms Revert DTMF hit/miss
+	  detector to original -r349249 method with some changes, remove
+	  unnecessary; 1. reseting of hits=0, when no signal, only need to
+	  set it once. 2. incrementing of hits, when the hit is the same as
+	  the current hit. 3. setting of lasthit, when it's the same as
+	  before. Change HITS_TO_BEGIN to 2, MISSES_TO_END to 3 & 3
+	  spelling mistakes (closes issue ASTERISK-19610) alecdavis
+	  (license 585) Reported by: Jean-Philippe Lord Tested by:
+	  alecdavis Review: https://reviewboard.asterisk.org/r/2085/
+	  ........ Merged revisions 372239 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372240 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/dsp.c, /: dsp.c: optimize goerztzel sample loops, in
+	  dtmf_detect, mf_detect and tone_detect use a temporary short int
+	  when repeatedly used to call goertzel_sample. alecdavis (license
+	  585) Reported by: alecdavis Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/2093/ ........ Merged
+	  revisions 372212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372213 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 04:52 +0000 [r372199]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* res/res_rtp_asterisk.c, /: Fix Incrementing Sequence Number For
+	  Retransmitted DTMF End Packets In Asterisk 1.4+, a fix was put in
+	  place to increment the sequence number for retransmitted DTMF end
+	  packets. With the introduction of the RTP engine API in 1.8, the
+	  sequence number was no longer being incremented. This patch fixes
+	  this regression as well as cleans up a few lines that were not
+	  doing anything. (closes issue ASTERISK-20295) Reported by: Nitesh
+	  Bansal Tested by: Michael L. Young Patches:
+	  01_rtp_event_seq_num.patch uploaded by Nitesh Bansal (license
+	  6418) asterisk-20295-dtmf-fix-cleanup.diff uploaded by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/2083/ ........ Merged
+	  revisions 372185 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372198 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-05 02:25 +0000 [r372175]  Matthew Jordan <mjordan at digium.com>
+
+	* cel/cel_pgsql.c, /: Fix memory leak when CEL is successfully
+	  written to PostgreSQL database PQClear is not called when the
+	  result object of a call to PQExec has a status of
+	  PGRES_COMMAND_OK. Interestingly enough, the off nominal case was
+	  handled properly, so this memory leak only occurred when CEL
+	  records were successfully written. This patch properly clears the
+	  result in the nominal code path. (closes issue ASTERISK-19991)
+	  Reported by: Etienne Lessard Tested by: Etienne Lessard patches:
+	  mem_leak_cel_pgsql.patch uploaded by Etienne Lessard (license
+	  #6394) ........ Merged revisions 372158 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372165 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-09-04 15:48 +0000 [r372135-372137]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Fix issue where SIP devices were not
+	  notified when custom devices changed to "ringing". The problem
+	  had to do with logic used when checking for what the oldest
+	  ringing channel was. The problem was that if no channel was
+	  found, then no notification would be sent. For custom device
+	  states, there is no associated channel, so no notification would
+	  get sent. This fixes the issue by still sending the notification
+	  even if no associated channel can be found for a ringing device
+	  state change. (closes issue ASTERISK-20297) Reported by Noah
+	  Engelberth
+
+	* main/config_options.c, apps/app_confbridge.c: Prevent crash from
+	  using app_page with no confbridge.conf file provided. Also
+	  prevents other potential crashes when using aco API with
+	  uninitialized aco_info structs. (closes issue ASTERISK-20305)
+	  reported by Noah Engelberth Tested by Noah Engelberth Review:
+	  https://reviewboard.asterisk.org/r/2086
+
+2012-08-31 21:14 +0000 [r372118]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_rtp_asterisk.c: Prevent local RTP bridges from sending
+	  inappropriate formats to participants. A change for Asterisk 11
+	  caused a check for failure to incorrectly check the return value.
+	  This resulted in the possibility of transmitting media that a
+	  party had not negotiated. If this media happened to be G.729,
+	  then this could potentially result in one-way audio if no G.729
+	  translators are installed. (closes issue ASTERISK-20296) reported
+	  by NITESH BANSAL
+
+2012-08-30 20:54 +0000 [r372050-372091]  Mark Michelson <mmichelson at digium.com>
+
+	* /, apps/app_queue.c: Prevent crash on shutdown due to refcount
+	  error on queues container. When app_queue is unloaded, the queues
+	  container has its refcount decremented, potentially to 0. Then
+	  the taskprocessor responsible for handling device state changes
+	  is unreferenced. If the taskprocessor happens to be just about to
+	  run its task, then it will create and destroy an iterator on the
+	  queues container. This can cause the refcount on the queues
+	  container to increase to 1 and then back to 0. Going back to 0 a
+	  second time results in double frees. This failure was seen
+	  periodically in the testsuite when Asterisk would shut down.
+	  ........ Merged revisions 372089 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 372090 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Help prevent ringing queue members from
+	  being rung when ringinuse set to no. Queue member status would
+	  not always get updated properly when the member was called, thus
+	  resulting in the member getting multiple calls. With this change,
+	  we update the member's status at the time of calling, and we also
+	  check to make sure the member is still available to take the call
+	  before placing an outbound call. (closes issue ASTERISK-16115)
+	  reported by nik600 Patches: app_queue.c-svn-r370418.patch
+	  uploaded by Italo Rossi (license #6409) ........ Merged revisions
+	  372048 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 372049 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-30 16:24 +0000 [r371963-372028]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_iax2.c: AST-2012-013: Resolve ACL rules being
+	  ignored during calls by some IAX2 peers When an IAX2 call is made
+	  using the credentials of a peer defined in a dynamic Asterisk
+	  Realtime Architecture (ARA) backend, the ACL rules for that peer
+	  are not applied to the call attempt. This allows for a remote
+	  attacker who is aware of a peer's credentials to bypass the ACL
+	  rules set for that peer. This patch ensures that the ACLs are
+	  applied for all peers, regardless of their storage mechanism.
+	  (closes issue ASTERISK-20186) Reported by: Alan Frisch Tested by:
+	  mjordan, Alan Frisch
+
+	* /: Block r372020
+
+	* main/manager.c, /, README-SERIOUSLY.bestpractices.txt:
+	  AST-2012-012: Resolve AMI User Unauthorized Shell Access through
+	  ExternalIVR The AMI Originate action can allow a remote user to
+	  specify information that can be used to execute shell commands on
+	  the system hosting Asterisk. This can result in an unwanted
+	  escalation of permissions, as the Originate action, which
+	  requires the "originate" class authorization, can be used to
+	  perform actions that would typically require the "system" class
+	  authorization. Previous attempts to prevent this permission
+	  escalation (AST-2011-006, AST-2012-004) have sought to do so by
+	  inspecting the names of applications and functions passed in with
+	  the Originate action and, if those applications/functions matched
+	  a predefined set of values, rejecting the command if the user
+	  lacked the "system" class authorization. As noted by IBM X-Force
+	  Research, the "ExternalIVR" application is not listed in the
+	  predefined set of values. The solution for this particular
+	  vulnerability is to include the "ExternalIVR" application in the
+	  set of defined applications/functions that require "system" class
+	  authorization. Unfortunately, the approach of inspecting fields
+	  in the Originate action against known applications/functions has
+	  a significant flaw. The predefined set of values can be bypassed
+	  by creative use of the Originate action or by certain dialplan
+	  configurations, which is beyond the ability of Asterisk to
+	  analyze at run-time. Attempting to work around these scenarios
+	  would result in severely restricting the applications or
+	  functions and prevent their usage for legitimate means. As such,
+	  any additional security vulnerabilities, where an
+	  application/function that would normally require the "system"
+	  class authorization can be executed by users with the "originate"
+	  class authorization, will not be addressed. Instead, the
+	  README-SERIOUSLY.bestpractices.txt file has been updated to
+	  reflect that the AMI Originate action can result in commands
+	  requiring the "system" class authorization to be executed. Proper
+	  system configuration can limit the impact of such scenarios.
+	  (closes issue ASTERISK-20132) Reported by: Zubair Ashraf of IBM
+	  X-Force Research ........ Merged revisions 371998 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371999 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* doc/CODING-GUIDELINES (added), /: Restore CODING-GUIDELINES to
+	  doc folder In r294740, the CODING-GUIDELINES was removed from the
+	  doc folder in favor of the content on the Asterisk wiki. Some
+	  folks still look in the doc folder initially for coding guideline
+	  suggestions; as such, this patch adds a CODING-GUIDELINES file
+	  back into the doc folder. The content of the file merely points
+	  to the correct page on the Asterisk wiki where the coding
+	  guidelines currently live. (closes issue ASTERISK-20279) Reported
+	  by: Andrew Latham Patches: CODING-GUIDELINES.diff uploaded by
+	  Andrew Latham (license 5985) ........ Merged revisions 371961
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371962 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-29 22:38 +0000 [r371950]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_meetme.c: Fix compile errors.
+
+2012-08-29 21:07 +0000 [r371921]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: app_meetme: Adding test events for
+	  following activity in MeetMe. ........ Merged revisions 371919
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371920 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-29 19:56 +0000 [r371862-371893]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c: Fix theoretical compile error with HAVE_EPOLL.
+	  Really shows how much epoll is used since it had not been
+	  reported yet.
+
+	* main/channel.c, /: Initialize file descriptors for dummy channels
+	  to -1. Dummy channels usually aren't read from, but functions
+	  like SHELL and CURL use autoservice on the channel. (closes issue
+	  ASTERISK-20283) Reported by: Gareth Palmer Patches:
+	  svn-371580.patch (license #5169) patch uploaded by Gareth Palmer
+	  (modified) ........ Merged revisions 371888 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371890 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_dial.c, /: Fix hangup cause passthrough regression. The
+	  v1.8 -r369258 change to fix the F and F(x) action logic
+	  introduced a regression in passing the hangup cause from the
+	  called channel to the caller channel. (closes issue
+	  ASTERISK-20287) Reported by: Konstantin Suvorov Patches:
+	  app_dial_hangupcause.patch (license #6421) patch uploaded by
+	  Konstantin Suvorov (modified) Tested by: rmudgett ........ Merged
+	  revisions 371860 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371861 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-29 17:25 +0000 [r371845]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Send 408 on retransmit timeout
+	  instead of 603 (closes issue ASTERISK-20124) Reported by: Walter
+	  Doekes ........ Merged revisions 371824 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371825 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-27 21:50 +0000 [r371784-371790]  Mark Michelson <mmichelson at digium.com>
+
+	* configs/agents.conf.sample, /: Fix misleading documentation in
+	  agents.conf.sample regarding ackcall usage. The documentation
+	  made it sound as if the DTMF acknowledgment was needed at the
+	  time the agent logs in, rather than when the agent is called.
+	  This is likely a relic from the days when there were multiple
+	  ways of logging in agents. (closes issue AST-962) reported by
+	  Steve Pitts ........ Merged revisions 371787 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371789 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/manager.c, /: Fix incorrect documentation of the
+	  MailboxStatus manager command. The "Waiting" field was
+	  misdocumented as reporting the number of messages waiting. In
+	  reality, it simply indicated the presence or absence of waiting
+	  messages. ........ Merged revisions 371782 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371783 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-27 18:14 +0000 [r371753]  dlee <dlee at localhost>:
+
+	* res/pjproject/pjlib-util/bin, res/pjproject/pjnath/build/output,
+	  res/pjproject/pjlib/bin, res/pjproject/pjlib-util/build/output,
+	  res/pjproject/pjnath/bin, res/pjproject/pjlib/build/output:
+	  svn:ignore pjproject bin & output for all platforms.
+
+2012-08-27 17:51 +0000 [r371749-371750]  Mark Michelson <mmichelson at digium.com>
+
+	* /, configs/queues.conf.sample: Fix incorrectly documented option
+	  in queues.conf sharedlastcall defaults to "no" not "yes" (closes
+	  issue AST-979) reported by Steve Pitts ........ Merged revisions
+	  371747 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 371748 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /: Re-add merge and block properties.
+
+2012-08-27 16:55 +0000 [r371720]  dlee <dlee at localhost>:
+
+	* main/lock.c, /: Fixes ast_rwlock_timed[rd|wr]lock for BSD and
+	  variants. The original implementations simply wrap pthread
+	  functions, which take absolute time as an argument. The spinlock
+	  version for systems without those functions treated the argument
+	  as a delta. This patch fixes the spinlock version to be
+	  consistent with the pthread version. (closes issue
+	  ASTERISK-20240) Reported by: Egor Gorlin Patches: lock.c.patch
+	  uploaded by Egor Gorlin (license 6416) ........ Merged revisions
+	  371718 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-08-27 14:07 +0000 [r371692]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/utils.c: Implement workaround for BETTER_BACKTRACES crash
+	  When compiling with BETTER_BACKTRACES enabled, Asterisk will
+	  sometimes crash when "core show locks" is run. This happens
+	  regularly in the testsuite since several tests run "core show
+	  locks" to help with debugging. This seems to be a fault with
+	  libraries on certain operating systems (notably CentOS 6.2/6.3)
+	  running on virtual machines and utilizing gcc 4.4.6. (closes
+	  issue ASTERISK-20090) ........ Merged revisions 371690 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371691 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-26 23:07 +0000 [r371664]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* main/dsp.c, /: mf_detect: incorrectly used DTMF_GSIZE instead of
+	  MF_GSIZE ........ Merged revisions 371662 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371663 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-22 15:54 +0000 [r371619]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Add support for call-id logging to
+	  chan_motif. Review: https://reviewboard.asterisk.org/r/2077/
+
+2012-08-21 20:54 +0000 [r371592]  Mark Michelson <mmichelson at digium.com>
+
+	* cdr/cdr_tds.c, main/xmldoc.c, apps/app_dial.c,
+	  channels/chan_dahdi.c, /, channels/chan_sip.c, funcs/func_odbc.c,
+	  main/file.c, main/utils.c, apps/app_queue.c, pbx/pbx_config.c,
+	  res/res_jabber.c, apps/app_stack.c, channels/chan_oss.c,
+	  res/res_config_sqlite.c: Fix misuses of asprintf throughout the
+	  code. This fixes three main issues * Change asprintf() uses to
+	  ast_asprintf() so that it pairs properly with ast_free() and no
+	  longer causes MALLOC_DEBUG to freak out. * When ast_asprintf()
+	  fails, set the pointer NULL if it will be referenced later. * Fix
+	  some memory leaks that were spotted while taking care of the
+	  first two points. (Closes issue ASTERISK-20135) reported by
+	  Richard Mudgett Review: https://reviewboard.asterisk.org/r/2071
+	  ........ Merged revisions 371590 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371591 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-20 20:09 +0000 [r371571]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_rtp_asterisk.c: Use thread-local storage to store
+	  pj_thread_descs. pj_thread_register() takes a parameter of type
+	  pj_thread_desc. It was assumed that pj_thread_register either
+	  used this item temporarily or made a copy of it. Unfortunately,
+	  all it does is keep a pointer to the structure in thread-local
+	  storage. This means that if our pj_thread_desc goes out of scope,
+	  then pjlib will be referencing bogus data quite often, most
+	  commonly on operations involving a pj_mutex_t. In our case, our
+	  pj_thread_desc was on the stack and went out of scope very
+	  shortly after registering our thread with pjlib. With this
+	  change, the pj_thread_desc is stored in thread-local storage so
+	  the pointer that pjlib keeps in thread-local storage will
+	  reference legitimate memory. (closes issue ASTERISK-20237)
+	  reported by Jeremy Pepper Patches: ASTERISK-20237.patch uploaded
+	  by Mark Michelson (license #5049) Tested by Jeremy Pepper
+
+2012-08-20 15:34 +0000 [r371546]  Kinsey Moore <kmoore at digium.com>
+
+	* main/udptl.c, /: Ignore recovered zero-length secondary UDPTL
+	  packets In some cases, recovering lost packets using the
+	  secondary packet recovery mechanism with UDPTL/T.38 can result in
+	  the recovery of zero-length packets. These must be ignored or the
+	  frame generated from them can cause segfaults and allocation
+	  failures. (closes issue ASTERISK-19762) (closes issue
+	  ASTERISK-19373) Reported-by: Benjamin (bulkorok) Reported-by: Rob
+	  Gagnon (rgagnon) ........ Merged revisions 371544 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371545 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-18 02:35 +0000 [r371492-371530]  Matthew Jordan <mjordan at digium.com>
+
+	* /: Recorded merge of revisions 371529 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Remove
+	  old debug code from http configuration loading (closes issue
+	  ASTERISK-20254) Reported by: Andrew Latham Patches: http.diff
+	  uploaded by Andrew Latham (license #5985)
+
+	* main/http.c: Remove old debug code from http configuration
+	  loading (closes issue ASTERISK-20254) Reported by: Andrew Latham
+	  Patches: http.diff uploaded by Andrew Latham (license #5985)
+
+	* res/res_xmpp.c: Fix typo in JabberSend that looked for '2'
+	  instead of '@' in recipient argument The summary says about all
+	  there is to say. (closes issue ASTERISK-20239) Reported by:
+	  Gregory Porras
+
+	* funcs/func_hangupcause.c: Make the name of the "HangupCauseClear"
+	  application consistent The name of the "HangupCauseClear"
+	  application is "HangupCauseClear", not "HangupcauseClear". The
+	  incorrect case of 'cause' caused the XML documentation to not
+	  register properly. As an aside, this commit message felt very
+	  awkward, but I'm not sure how else to note that "X", which has to
+	  be "X", was referred to as "x". (closes issue ASTERISK-20253)
+	  Reported by: Andrew Latham Patches: hangupcause.diff uploaded by
+	  Andrew Latham (license #5985)
+
+	* build_tools/cflags.xml, utils/utils.xml, res/res_fax.c,
+	  sounds/sounds.xml, res/res_curl.c: Update module support level on
+	  a variety of modules and compiler options Some core support
+	  modules and compiler options were no longer tagged with a module
+	  support level. This patch adds 'core' back to those options. Note
+	  that this patch modifies a few of the patches provided by Andrew
+	  Latham slightly. res_curl and res_fax are both 'core' supported
+	  modules. (closes issue ASTERISK-20215) Reported by: Andrew Latham
+	  Tested by: mjordan Patches: astcanary.diff (license #5985)
+	  uploaded by Andrew Latham cflagsxml.diff (license #5985) uploaded
+	  by Andrew Latham curl_fax.diff (license #5985) uploaded by Andrew
+	  Latham soundsxml.diff (license #5985) uploaded by Andrew Latham
+
+	* main/xmldoc.c, /: Fix memory leak in XML documentation When
+	  formatting documentation fields, the XML documentation parser
+	  calls xmldoc_get_formatted. This function allocates a string
+	  buffer at the beginning of its routine. Unfortunately, on certain
+	  code paths, it also calls xmldoc_string_cleanup, which assumes
+	  that it will create the string buffer. The previously allocated
+	  string buffer is then leaked by the xmldoc_string_cleanup
+	  routine. Now: we don't do that. (closes issue AST-932) Reported
+	  by: Alexander Homig ........ Merged revisions 371469 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371491 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-17 19:49 +0000 [r371482]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c: When a peer registers using WebSocket do not
+	  resolve the Contact provided. (closes issue ASTERISK-20238)
+	  Reported by: james.mortensen
+
+2012-08-17 15:58 +0000 [r371438]  Kinsey Moore <kmoore at digium.com>
+
+	* main/loader.c, /: Add instrumentation to subsystem reloads When
+	  Asterisk is built with TEST_FRAMEWORK defined, Asterisk will now
+	  generate TestEvent AMI events on subsystem reloads such as cdr,
+	  dnsmgr, extconfig, etc. (issue PQ-1126) ........ Merged revisions
+	  371436 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 371437 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-17 12:24 +0000 [r371426]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_format_attr_h264.c: Add some additional H.264 attributes,
+	  "max-smbps" and "max-fps", for passthrough. (closes issue
+	  ASTERISK-20206) Reported by: ddkprog Patches:
+	  res_format_attr_h264.c.diff uploaded by ddkprog (license 6008)
+
+2012-08-17 12:23 +0000 [r371425]  Russell Bryant <russell at russellbryant.com>
+
+	* res/res_rtp_asterisk.c: rtp: Ensure defaults are set without
+	  rtp.conf. While building up a new install to test chan_motif, I
+	  ran into a failure due to icesupport being disabled. This was due
+	  to me not having an rtp.conf. It was intended in the code for it
+	  to be enabled by default, but it was only applied if rtp.conf
+	  existed. This patch updates res_rtp_asterisk to be consistent in
+	  how it handles defaults. A few options didn't have their default
+	  values set globally, including icesupport. They are now set and
+	  icesupport is enabled by default, even if you do not have an
+	  rtp.conf.
+
+2012-08-16 23:02 +0000 [r371399]  Terry Wilson <twilson at digium.com>
+
+	* main/config.c, /: Handle integer over/under-flow in
+	  ast_parse_args The strtol family of functions will return
+	  *_MIN/*_MAX on overflow. To detect when an overflow has happened,
+	  errno must be set to 0 before calling the function, then checked
+	  afterward. (closes issue ASTERISK-20120) Reported by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/2073/ ........ Merged
+	  revisions 371392 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371398 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-16 22:44 +0000 [r371395]  Kinsey Moore <kmoore at digium.com>
+
+	* main/loader.c, /: Add module reload instrumentation for
+	  TEST_FRAMEWORK This adds AMI events for module reloads when
+	  Asterisk is built with TEST_FRAMEWORK enabled and corrects
+	  generation of the module load AMI event. (issue PQ-1126) ........
+	  Merged revisions 371393 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371394 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-16 19:43 +0000 [r371355-371382]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Use pvt outgoing_call variable
+	  to set Remote-Party-ID Header Previously the pvt SIP_OUTGOING
+	  flag was used instead, which will frequently flip during
+	  reinvites. (closes issue AST-897) Reported by: Thomas Arimont
+	  ........ Merged revisions 371357 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371358 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: chan_sip: Trigger reinvite if the SDP
+	  answer is included in the SIP ACK Under certain conditions, a SIP
+	  transaction involving directmedia wouldn't trigger a re-invite
+	  because the SDP answer was included in an ACK instead of in a
+	  message that we would have triggered the invite with. This patch
+	  just queues a source change control frame if the dialog is using
+	  directmedia when we find sdp for an ACK. (closes issue AST-913)
+	  Reported by: Thomas Arimont ........ Merged revisions 371337 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371338 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-15 23:28 +0000 [r371324]  Mark Michelson <mmichelson at digium.com>
+
+	* /, apps/app_queue.c: Fix bug where final queue member would not
+	  be removed from memory. If a static queue had realtime members,
+	  then there could be a potential for those realtime members not to
+	  be properly deleted from memory. If the queue's members were
+	  loaded from realtime and then all the members were deleted from
+	  the backend, then the queue would still think these members
+	  existed. The reason was that there was a short- circuit in code
+	  such that if there were no members found in the backend, then the
+	  queue would not be updated to reflect this. Note that this only
+	  affected static queues with realtime members. Realtime queues
+	  with realtime members were unaffected by this issue. (closes
+	  issue ASTERISK-19793) reported by Marcus Haas ........ Merged
+	  revisions 371306 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371313 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-15 20:40 +0000 [r371295]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* channels/chan_sip.c: Fix Segfault When Registering SIP Over
+	  WebSockets The helper function, get_address_family_filter, in
+	  chan_sip for dns resolution by address family was not recognizing
+	  the websockets transport and resulting in a null pointer being
+	  sent to functions in netsock2, in an attempt to determine if we
+	  are bound to ANY address ([::]) or not. This patch fixes this
+	  issue by handling the transport types SIP_TRANSPORT_WS and
+	  SIP_TRANSPORT_WSS which results in a sock address being set
+	  properly for use in determining the address family. (closes issue
+	  ASTERISK-20221) Reported by: Sven Beisiegel Tested by: Sven
+	  Beisiegel, James Mortensen Patches:
+	  asterisk-20221-ws-family-filter.diff uploaded by Michael L. Young
+	  (license 5026)
+
+2012-08-15 20:17 +0000 [r371258-371272]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Avoid unconditional NULLing of mwipvt on
+	  relatedpeer on SIP dialog destruction The other instance of this
+	  bug was fixed by jcolp/file in r121496. If we are destroying a
+	  dialog only set the MWI dialog pointer on the related peer to
+	  NULL if it is the dialog currently being destroyed. (closes issue
+	  ASTERISK-20119) Patch-by: Misha Vodsedalek ........ Merged
+	  revisions 371270 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371271 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sig_ss7.c, channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/chan_sip.c, channels/chan_iax2.c, channels/sig_pri.c:
+	  Add HANGUPCAUSE information to callee channels This adds
+	  HANGUPCAUSE information to called channels so that hangup
+	  handlers can, in conjunction with predial dialplan execution,
+	  access the hangupcause information when the dialed channel hangs
+	  up on a one-to-one basis instead of a many-to-one basis as with
+	  HANGUPCAUSE usage on the caller channel. Review:
+	  https://reviewboard.asterisk.org/r/2069/ (closes issue
+	  ASTERISK-20198)
+
+2012-08-13 20:28 +0000 [r371227]  Kinsey Moore <kmoore at digium.com>
+
+	* main/loader.c, /, apps/app_meetme.c: Add test instrumentation
+	  This adds test instrumentation for loading and unloading of
+	  modules and for certain actions in MeetMe to be used in the
+	  testsuite or any other consumer of AMI events. These will only be
+	  generated when Asterisk is built with TEST_FRAMEWORK enabled.
+	  (issue PQ-1131) (issue PQ-1133) ........ Merged revisions 371201
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371203 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-13 19:52 +0000 [r371200]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix problem where incorrect pointer was
+	  checked for nullity. ........ Merged revisions 371198 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371199 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-10 22:03 +0000 [r371146]  Richard Mudgett <rmudgett at digium.com>
+
+	* CHANGES: Update CHANGES for private party ID.
+
+2012-08-10 21:32 +0000 [r371143]  Mark Michelson <mmichelson at digium.com>
+
+	* /, apps/app_queue.c: Fix a couple of documentation problems in
+	  app_queue.c * The RemoveQueueMember app made mention of options
+	  that could be passed in, but no options are supported. I have
+	  removed the listing of options from the documentation. * The
+	  RQMSTATUS variable did not list "NOTDYNAMIC" as a possible value
+	  that could be set. (closes issue AST-949) reported by Steve Pitts
+	  (closes issue AST-954) reported by Steve Pitts ........ Merged
+	  revisions 371141 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371142 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-10 20:08 +0000 [r371121]  Matthew Jordan <mjordan at digium.com>
+
+	* / (added): _ _ _ _ _ _ / \ ___| |_ ___ _ __(_)___| | __ / | / | /
+	  _ \ / __| __/ _ \ '__| / __| |/ / | | | | / ___ \__ \| | __/ | |
+	  \__ \ < | | | | /_/ \_\___/\__\___|_| |_|___/_|\_\ |_| |_|
+	  Because it's one greater than 10.
+
+2012-08-10 19:54 +0000 [r371120]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, channels/chan_misdn.c, channels/chan_sip.c,
+	  main/channel_internal_api.c, main/features.c,
+	  include/asterisk/channel.h, channels/sig_pri.c,
+	  funcs/func_callerid.c, main/cli.c: Add private representation of
+	  caller, connected and redirecting party ids. This patch adds the
+	  feature "Private representation of caller, connected and
+	  redirecting party ids", as previously discussed with us (DATUS)
+	  and Digium. 1. Feature motivation Until now it is quite difficult
+	  to modify a party number or name which can only be seen by
+	  exactly one particular instantiated technology channel
+	  subscriber. One example where a modified party number or name on
+	  one channel is spread over several channels are supplementary
+	  services like call transfer or pickup. To implement these
+	  features Asterisk internally copies caller and connected ids from
+	  one channel to another. Another example are extension
+	  subscriptions. The monitoring entities (watchers) are notified of
+	  state changes and - if desired - of party numbers or names which
+	  represent the involving call parties. One major feature where a
+	  private representation of party names is essentially needed, i.e.
+	  where a party name shall be exclusively signaled to only one
+	  particular user, is a private user-specific name resolution for
+	  party numbers. A lookup in a private destination-dependent
+	  telephone book shall provide party names which cannot be seen by
+	  any other user at any time. 2. Feature Description This feature
+	  comes along with the implementation of additional private party
+	  id elements for caller id, connected id and redirecting ids
+	  inside Asterisk channels. The private party id elements can be
+	  read or set by the user using Asterisk dialplan functions. When a
+	  technology channel is initiating a call, receives an internal
+	  connected-line update event, or receives an internal redirecting
+	  update event, it merges the corresponding public id with the
+	  private id to create an effective party id. The effective party
+	  id is then used for protocol signaling. The channel technologies
+	  which initially support the private id representation with this
+	  patch are SIP (chan_sip), mISDN (chan_misdn) and PRI
+	  (chan_dahdi). Once a private name or number on a channel is set
+	  and (implicitly) made valid, it is generally used for any further
+	  protocol signaling until it is rewritten or invalidated. To
+	  simplify the invalidation of private ids all internally generated
+	  connected/redirecting update events and also all
+	  connected/redirecting update events which are generated by
+	  technology channels -- receiving regarding protocol information -
+	  automatically trigger the invalidation of private ids. If not
+	  using the private party id representation feature at all, i.e. if
+	  using only the 'regular' caller-id, connected and redirecting
+	  related functions, the current characteristic of Asterisk is not
+	  affected by the new extended functionality. 3. User interface
+	  Description To grant access to the private name and number
+	  representation from the Asterisk dialplan, the CALLERID,
+	  CONNECTEDLINE and REDIRECTING dialplan functions are extended by
+	  the following data types. The formats of these data types are
+	  equal to the corresponding regular 'non-private' already existing
+	  data types: CALLERID: priv-all priv-name priv-name-valid
+	  priv-name-charset priv-name-pres priv-num priv-num-valid
+	  priv-num-plan priv-num-pres priv-subaddr priv-subaddr-valid
+	  priv-subaddr-type priv-subaddr-odd priv-tag CONNECTEDLINE:
+	  priv-name priv-name-valid priv-name-pres priv-name-charset
+	  priv-num priv-num-valid priv-num-pres priv-num-plan priv-subaddr
+	  priv-subaddr-valid priv-subaddr-type priv-subaddr-odd priv-tag
+	  REDIRECTING: priv-orig-name priv-orig-name-valid
+	  priv-orig-name-pres priv-orig-name-charset priv-orig-num
+	  priv-orig-num-valid priv-orig-num-pres priv-orig-num-plan
+	  priv-orig-subaddr priv-orig-subaddr-valid priv-orig-subaddr-type
+	  priv-orig-subaddr-odd priv-orig-tag priv-from-name
+	  priv-from-name-valid priv-from-name-pres priv-from-name-charset
+	  priv-from-num priv-from-num-valid priv-from-num-pres
+	  priv-from-num-plan priv-from-subaddr priv-from-subaddr-valid
+	  priv-from-subaddr-type priv-from-subaddr-odd priv-from-tag
+	  priv-to-name priv-to-name-valid priv-to-name-pres
+	  priv-to-name-charset priv-to-num priv-to-num-valid
+	  priv-to-num-pres priv-to-num-plan priv-to-subaddr
+	  priv-to-subaddr-valid priv-to-subaddr-type priv-to-subaddr-odd
+	  priv-to-tag Reported by: Thomas Arimont Review:
+	  https://reviewboard.asterisk.org/r/2030/
+
+2012-08-10 17:56 +0000 [r371113]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Fix a comparison that was causing presence
+	  tests to fail. A recent change made it so that device state
+	  changes that were not actual "changes" would not get reported to
+	  subscribers. The problem was that this inadvertently blocked
+	  presence updates as well.
+
+2012-08-10 16:49 +0000 [r371059-371091]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: remove ALREADYGONE flag on ooh323 call
+	  data by ooh323_indicate (CONGESTION/BUSY) due to call hasn't gone
+	  there really. This indication arrive from asterisk core not h.323
+	  stack (closes issue ASTERISK-19308) Reported by: Dmitry Melekhov
+	  Patches: ASTERISK-19308.patch ........ Merged revisions 371089
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371090 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* addons/ooh323c/src/ooGkClient.c, /: Send re-register packets by
+	  GRQ (gatekeeper request) interval (close issue ASTERISK-20094)
+	  Patches: ASTERISK-20094-2.patch ........ Merged revisions 371060
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371061 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* addons/ooh323c/src/ooTimer.c: restore calling cb functions by
+	  timer expire this was broken in rev 369602
+
+2012-08-10 02:07 +0000 [r371052]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/features.c: Fix pickup extension channel reference error.
+	  You cannot unref a pointer and then expect to ref it again later.
+	  * Fix potential NULL pointer deref if the call pickup search
+	  fails.
+
+2012-08-09 21:35 +0000 [r371036-371043]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: Introdue 'ooh323 show gk' cli command that
+	  show status of connection to H.323 Gatekeeper (GkClient state)
+
+	* addons/ooh323c/src/ooGkClient.c, /: Fix to resend GRQ/RRQ if RRJ
+	  (registration reject) is received (close issue ASTERISK-20094)
+	  Patches: ASTERISK-20094.patch ........ Merged revisions 371011
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 371022 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-09 19:22 +0000 [r371030]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac,
+	  channels/sig_pri.c, channels/sig_ss7.c: Use better libss7
+	  detection test and move libpri compile test. ........ Merged
+	  revisions 371012 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 371013 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-09 18:28 +0000 [r371010]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/ooh323ep.c: change opening h323 logfile
+	  with append mode instead of overwrite ........ Merged revisions
+	  370988 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 370989 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-09 17:40 +0000 [r370987]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_meetme.c: Correct documentation for the MeetMe x flag
+	  The documentation for the x flag for MeetMe incorrectly described
+	  its function as closing down the conference when the last marked
+	  user left. It actually causes the users with that flag to leave
+	  the conference when the last marked user exits. The functionality
+	  of this flag is not changing. ........ Merged revisions 370985
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 370986 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-09 14:52 +0000 [r370979]  Mark Michelson <mmichelson at digium.com>
+
+	* main/pbx.c, channels/chan_sip.c, include/asterisk/pbx.h,
+	  channels/sip/include/sip.h: Extend extension state callbacks to
+	  have more information. Quote from review board: This patch
+	  extends the extension state callbacks so that monitoring channels
+	  (as chan_sip) get more information of the devices which are
+	  responsible for an extension state change. The additional
+	  information is needed by chan_sip to present names/numbers of the
+	  caller and callee in an early-state SIP notification. Users of
+	  extenstion state callback not interested in the additional
+	  information are not affected by the changes. Motivation: to
+	  present the involved party's name/number in an early-state
+	  nofification (used by the notified device as a pickup offer) one
+	  after another so that a user can see which call he will pick up
+	  in an undirected pickup. Such a pickup offer to a user shall
+	  indicate the same call (number/name-A calls number/name-B) as the
+	  call which would be picked up when an undirected pickup is
+	  executed. Users interested in additional state info must use the
+	  new functions ast_extension_state_add_extended() resp.
+	  ast_extension_state_add_destroy_extended() to register an
+	  extended state callback. When the callback is registered this
+	  way, an extra member device_state_info of struct
+	  ast_state_cb_info is passed to the callback in addition to the
+	  aggregated extension state. This container holds an object for
+	  every device of the monitored extension hint consisting of the
+	  device name, the device state and a channel reference to the
+	  channel which (presumably) caused the device state. The
+	  information is used by chan_sip for early-state notifications.
+	  When the state of a device changes and the new state contains
+	  AST_EVENT_RINGING, an early-state notification is sent to the
+	  subscribed devices with the caller/callee names/numbers of the
+	  oldest ringing channel of the monitored extension. The notified
+	  user may then invoke a direct pickup, which will pickup exactly
+	  this channel. Users of the old non-extended callbacks will only
+	  be called when the aggregated state did change (same behavior as
+	  before). Users of the extended callback will also be called when
+	  the state is unchanged but does contain AST_EVENT_RINGING. That
+	  could be the case if two channels are ringing at one device and
+	  one of them hangs up, so the aggregated state does not change.
+	  This way the monitoring channel can create a new early-state
+	  notification with the now ringing party-ids. Review:
+	  https://reviewboard.asterisk.org/r/2048 This contribution comes
+	  from Guenther Kelleter
+
+2012-08-09 14:36 +0000 [r370978]  Jonathan Rose <jrose at digium.com>
+
+	* pbx/pbx_dundi.c, CHANGES: DUNDi: Add CLI commands DUNDi show
+	  cache and DUNDi show hints (closes issue ASTERISK-18390) Reported
+	  by: Peter Racz Patches: dundi_cli_cache.patch.v2 uploaded by
+	  Peter Racz (license #6290)
+	  ASTERISK-18390_dundi_cli_cache_jrose_mods_v2.diff uploaded by
+	  Jonathan Rose (license #6182)
+
+2012-08-08 22:45 +0000 [r370955]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, apps/app_chanspy.c: Fix Not Unreferencing A Spied Channel When
+	  a channel hangs up while being spied upon and the option to exit
+	  the ChanSpy application when the spied on channel hangs up is
+	  set, ast_autochan_destroy is not being called and therefore a
+	  reference to the spied upon channel is not removed. The symptom
+	  being reported was that when using func_group in the dialplan and
+	  calling "group show channels" at the cli, the spied upon channel
+	  was still being shown while "core show channels" showed that the
+	  channel was not up. This patch calls ast_autochan_destroy when a
+	  spied upon channel hangs up and the option to exit the ChanSpy
+	  application is set, removing the reference to the channel
+	  allowing the count for the group that the spied channel was part
+	  of to be decremented. (closes issue ASTERISK-17515) Reported by:
+	  Arkadiusz Malka Tested by: Alexandr Gordeev, Michael L. Young
+	  Patches: asterisk-17515-destroy-autochan.diff uploaded by Michael
+	  L. Young (license 5026) ........ Merged revisions 370952 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370954 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-08 22:41 +0000 [r370951-370953]  Mark Michelson <mmichelson at digium.com>
+
+	* CHANGES: Move a SIP change up to the other SIP changes in the
+	  CHANGES file.
+
+	* main/channel.c, main/pbx.c, main/manager.c, pbx/pbx_spool.c,
+	  apps/app_originate.c, include/asterisk/channel.h,
+	  include/asterisk/pbx.h, CHANGES, res/res_clioriginate.c: Allow
+	  support for early media on AMI originates and call files. This is
+	  based on the work done by Olle Johansson on review board. The
+	  idea is that the channel specified in an AMI originate or call
+	  file is typically not connected to the outgoing extension until
+	  the channel has been answered. With this change, an EarlyMedia
+	  header can be specified for AMI originates and an early_media
+	  option can be specified in call files. With this option set, once
+	  early media is received on a channel, it will be connected with
+	  the outgoing extension. (closes issue ASTERISK-18644) Reported by
+	  Olle Johansson Review: https://reviewboard.asterisk.org/r/1472
+
+2012-08-08 21:22 +0000 [r370943]  Terry Wilson <twilson at digium.com>
+
+	* main/manager.c, CHANGES: Add AMI_CLIENT dialplan function
+	  Implementation of a dialplan function for checking manager
+	  accounts. Right now it only returns the number of logged in
+	  sessions for a manager account, but other attributes can be added
+	  later. Patch by: Olle Johansson Review:
+	  https://reviewboard.asterisk.org/r/421/
+
+2012-08-08 20:47 +0000 [r370927]  Joshua Colp <jcolp at digium.com>
+
+	* main/rtp_engine.c: Create the payload type if it does not exist
+	  when setting information based on the 'm' line. An rtpmap
+	  attribute is not required for defined payload numbers.
+
+2012-08-08 20:32 +0000 [r370926]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/sig_analog.h: Convert sig_analog to use a global
+	  callback table.
+
+2012-08-08 20:30 +0000 [r370925]  Kinsey Moore <kmoore at digium.com>
+
+	* main/channel.c, /: Do not define a cause that doesn't actually
+	  exist AST_CAUSE_NOTDEFINED is a placeholder for usage when there
+	  is no cause information. As such, it should not be defined and
+	  translatable as a cause. ........ Merged revisions 370923 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370924 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-08 20:17 +0000 [r370887-370902]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c, /,
+	  channels/sig_analog.h: Fix the analog dial *0 flash-hook of
+	  bridged peer feature. The flash-hook the bridged peer feature now
+	  correctly determines if the bridged peer is another chan_dahdi
+	  channel, that it is an analog channel, and that it has the
+	  correct signaling for an FXO port. It now also flash-hooks the
+	  correct channel. ........ Merged revisions 370900 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370901 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sig_pri.h, channels/chan_dahdi.c, channels/sig_pri.c:
+	  Convert sig_pri to use a global callback table.
+
+	* channels/chan_dahdi.c, channels/sig_ss7.h, channels/sig_ss7.c:
+	  Convert sig_ss7 to use a global callback table.
+
+2012-08-07 21:58 +0000 [r370881]  Damien Wedhorn <voip at facts.com.au>
+
+	* build_tools/cflags-devmode.xml, channels/chan_skinny.c: Rewrite
+	  of skinny debugging. Debugging messages and associated controls
+	  only compiled in if configured with --enable-dev-mode. Debug
+	  messages provide more detail (including thread id) and are
+	  grouped so the user/dev can limit the type of messages displayed.
+	  Functionally no real change to chan_skinny. Review:
+	  https://reviewboard.asterisk.org/r/2040/
+
+2012-08-07 19:59 +0000 [r370860]  Joshua Colp <jcolp at digium.com>
+
+	* main/rtp_engine.c, include/asterisk/rtp_engine.h: Payload and RTP
+	  code are must remain separate since in non-Asterisk format cases
+	  they differ.
+
+2012-08-07 19:26 +0000 [r370851-370859]  Kinsey Moore <kmoore at digium.com>
+
+	* /: Recorded merge of revisions 370858 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Add
+	  missing AST_CAUSE_* -> text translations ........ Merged
+	  revisions 370856 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+	* main/channel.c: Add missing AST_CAUSE_* -> text translations A
+	  few of these were missing from the list and are necessary for the
+	  Who Hung Up? functionality.
+
+2012-08-07 17:47 +0000 [r370832-370845]  Joshua Colp <jcolp at digium.com>
+
+	* main/rtp_engine.c: Fix a bug uncovered by the test suite where
+	  the RTP payload number was not getting set.
+
+	* res/res_rtp_asterisk.c, main/rtp_engine.c, channels/chan_sip.c,
+	  channels/chan_motif.c, include/asterisk/rtp_engine.h: Reduce
+	  memory consumption significantly for users of the RTP engine API
+	  by storing only the payloads present and in use instead of every
+	  possible one. Review: https://reviewboard.asterisk.org/r/2052/
+
+2012-08-07 12:46 +0000 [r370820-370831]  Matthew Jordan <mjordan at digium.com>
+
+	* main/channel.c, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, channels/chan_misdn.c,
+	  channels/chan_sip.c, main/channel_internal_api.c,
+	  channels/misdn/chan_misdn_config.h, main/features.c,
+	  configs/misdn.conf.sample, include/asterisk/channel.h,
+	  configs/sip.conf.sample, CHANGES, channels/sip/include/sip.h,
+	  channels/misdn_config.c: Add named callgroups/pickupgroups This
+	  patch adds named calledgroups/pickupgroups to Asterisk. Named
+	  groups are implemented in parallel to the existing numbered
+	  callgroup/pickupgroup implementation. However, unlike the
+	  existing implementation, which is limited to a maximum of 64
+	  defined groups, the number of defined groups allowed for named
+	  callgroups/pickupgroups is effectively unlimited. Named groups
+	  are configured with the keywords "namedcallgroup" and
+	  "namedpickupgroup". This corresponds to the numbered group
+	  definitions of "callgroup" and "pickupgroup". Note that as the
+	  implementation of named groups coexists with the existing
+	  numbered implementation, a defined named group of "4" does not
+	  equate to numbered group 4. Support for the named groups has been
+	  added to the SIP, DAHDI, and mISDN channel drivers. Review:
+	  https://reviewboard.asterisk.org/r/2043 Uploaded by: Guenther
+	  Kelleter(license #6372)
+
+	* contrib/realtime/mysql/voicemail_data.sql: Revert r370820 That
+	  change is wrong, wrong, wrong.
+
+	* contrib/realtime/mysql/voicemail_data.sql: Update the MySQL
+	  voicemail_data contrib script to reflect Asterisk 11 changes All
+	  voicemails now have a 'msg_id' included in their metadata. The
+	  ODBC message storage backend now requires this column; as such,
+	  the MySQL contrib script that creates the voicemail_data table
+	  has been updated with the appropriate column information.
+
+2012-08-06 15:18 +0000 [r370801]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Improve debug message for temporary
+	  outbound proxies. Thanks to Paul Belanger for pointing this out.
+	  ........ Merged revisions 370797 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370798 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-03 21:52 +0000 [r370773]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/config_parser.c,
+	  channels/sip/include/sip.h: Multiple revisions 370769-370771
+	  ........ r370769 | mmichelson | 2012-08-03 16:35:00 -0500 (Fri,
+	  03 Aug 2012) | 24 lines Fix error in the "IPorHost" section of a
+	  SIP dialstring. This is based on the review request posted by
+	  Walter Doekes (referenced lower in the commit message) The main
+	  fix here is to treat the IPorHost portion of the dial string as a
+	  temporary outbound proxy. This ensures requests get sent to the
+	  proper location. Due to the age of the request, some parts were
+	  no longer relevant. For instance, the request moved outbound
+	  proxy parsing code into a single method. This is done in a
+	  previous commit, so it was not necessary to do again. Also, the
+	  review request fixed some errors with regards to request routing
+	  for CANCEL and ACK requests. This has also been fixed in more
+	  recent commits. (closes issue ASTERISK-19677) reported by Walter
+	  Doekes Review https://reviewboard.asterisk.org/r/1859 ........
+	  r370770 | mmichelson | 2012-08-03 16:39:35 -0500 (Fri, 03 Aug
+	  2012) | 3 lines Remove unused variable. ........ r370771 |
+	  mmichelson | 2012-08-03 16:43:52 -0500 (Fri, 03 Aug 2012) | 5
+	  lines Seriously? Another compilation error fixed. Somebody beat
+	  me. ........ Merged revisions 370769-370771 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370772 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-08-02 15:51 +0000 [r370740]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c: Fix regression from r370636 When the
+	  chan_sip cleanup went in, a typo was included that caused some
+	  subscriptions of non-Polycom phones to be limited to the same
+	  capabilities as Polycom phones. This resolves the failures in the
+	  test suite resulting from this regression.
+
+2012-08-01 19:37 +0000 [r370726]  Mark Michelson <mmichelson at digium.com>
+
+	* main/manager.c: Fix a possible crash due to passing NULL to
+	  ast_variables_dup()
+
+2012-08-01 18:52 +0000 [r370720]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h, main/astobj2.c: Make astobj2.h not
+	  include linkedlists.h. Using astobj2 does not require
+	  linkedlists.h be included even though astob2 uses linked lists
+	  internally.
+
+2012-08-01 02:26 +0000 [r370699]  Kinsey Moore <kmoore at digium.com>
+
+	* /, utils/extconf.c: Revert alloca changes for utils These changes
+	  were a tad overzealous in the utils directory. Unfortunately,
+	  these don't compile with a "make". ........ Merged revisions
+	  370697 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 370698 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-31 22:28 +0000 [r370681-370691]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample, CHANGES,
+	  channels/sip/include/sip.h: Add headers from SIPAddHeader to
+	  outbound REFER requests. This is a patch from kkm from review
+	  board. This is useful for adding headers to REFER requests that
+	  emanate from a Transfer() dialplan application call. This also
+	  fixes some uses of the Referred-by header, removing an extra set
+	  of angle brackets. I've modified the reporter's original patch to
+	  not require any additions to the sip_refer header and to just
+	  remove the referred_by_name from sip_refer since it is no longer
+	  needed or used. (closes Issue ASTERISK-17639) reported by Kirill
+	  Katsnelson Patches: 019059-sip-refer-addheaders-trunk-353549.diff
+	  uploaded by Kirill Katsnelson (license #5845) Review:
+	  https://reviewboard.asterisk.org/r/1159
+
+	* main/manager.c, configs/manager.conf.sample, CHANGES: Add
+	  "setvar" option to manager.conf. With this option set, channel
+	  variables can be set on every manager originate. The Variable
+	  header can still be used to set additional channel variables for
+	  individual calls if desired. This work was completed by Olle
+	  Johansson on review board. I have applied the review feedback and
+	  am committing it in order to get this into trunk before Asterisk
+	  11 is branched. Review: https://reviewboard.asterisk.org/r/1412
+
+2012-07-31 21:20 +0000 [r370677]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Schedule pokes of registered SIP peers
+	  within a given timespan after SIP reload With a large number of
+	  SIP peers registered, performing a SIP reload causes a flood of
+	  SIP OPTIONS request packets. These are immediately sent out, and,
+	  as responses come back, can cause peers to be flagged as 'lagged'
+	  due to handling of the many response messages. This fix prevents
+	  this "packet storm" and schedules the pokes for a random time.
+	  That time varies between 1 ms and the peer's qualify time, or, if
+	  the qualify time is unknown, the global qualifyfreq setting. The
+	  committed patch has some very small modifications to the patch
+	  schmidts wrote for the review. (closes issue ASTERISK-19154)
+	  Reported by: Nicolo Mazzon patches: issue19154.patch license
+	  #6034 uploaded by schmidts Review:
+	  https://reviewboard.asterisk.org/r/1652 ........ Merged revisions
+	  370666 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 370672 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-31 20:33 +0000 [r370664]  Russell Bryant <russell at russellbryant.com>
+
+	* main/event.c: Move event cache updates into event processing
+	  thread. Prior to this patch, updating the device state cache was
+	  done by the thread that originated the event. It would update the
+	  cache and then queue the event up for another thread to dispatch.
+	  This thread moves the cache updating part to be in the same
+	  thread as event dispatching. I was working with someone on a
+	  heavily loaded Asterisk system and while reviewing backtraces of
+	  the system while it was having problems, I noticed that there
+	  were a lot of threads contending for the lock on the event cache.
+	  By simply moving this into a single thread, this helped
+	  performance *a lot* and alleviated some deadlock-like symptoms.
+	  Review: https://reviewboard.asterisk.org/r/2066/
+
+2012-07-31 20:21 +0000 [r370655]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/say.c, main/threadstorage.c, funcs/func_strings.c,
+	  channels/chan_iax2.c, main/config.c, channels/chan_dahdi.c,
+	  pbx/pbx_spool.c, channels/sig_analog.c, main/strcompat.c,
+	  main/features.c, pbx/pbx_ael.c, main/http.c, pbx/pbx_realtime.c,
+	  channels/chan_alsa.c, channels/sig_ss7.c, main/db.c,
+	  include/asterisk/utils.h, main/pbx.c, funcs/func_cut.c,
+	  tests/test_linkedlists.c, funcs/func_channel.c, apps/app_macro.c,
+	  apps/app_mixmonitor.c, main/asterisk.c, apps/app_voicemail.c,
+	  addons/app_mysql.c, apps/app_meetme.c, apps/app_dictate.c,
+	  main/utils.c, funcs/func_logic.c, cdr/cdr_pgsql.c,
+	  channels/chan_gtalk.c, res/res_jabber.c,
+	  res/res_http_websocket.c, res/ael/pval.c, main/channel.c,
+	  main/manager.c, apps/app_osplookup.c, res/res_agi.c,
+	  apps/app_minivm.c, main/logger.c, main/app.c,
+	  addons/chan_mobile.c, apps/app_while.c, res/res_config_pgsql.c,
+	  channels/chan_sip.c, apps/app_festival.c, pbx/pbx_lua.c,
+	  channels/sig_pri.c, apps/app_getcpeid.c, funcs/func_global.c,
+	  channels/chan_jingle.c, main/tcptls.c,
+	  apps/app_directed_pickup.c, main/file.c, main/callerid.c,
+	  apps/app_sms.c, main/astmm.c, main/event.c, pbx/pbx_dundi.c,
+	  include/asterisk/strings.h, utils/extconf.c, main/dsp.c,
+	  addons/res_config_mysql.c: Clean up and ensure proper usage of
+	  alloca() This replaces all calls to alloca() with ast_alloca()
+	  which calls gcc's __builtin_alloca() to avoid BSD semantics and
+	  removes all NULL checks on memory allocated via ast_alloca() and
+	  ast_strdupa(). (closes issue ASTERISK-20125) Review:
+	  https://reviewboard.asterisk.org/r/2032/ Patch-by: Walter Doekes
+	  (wdoekes) ........ Merged revisions 370642 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370643 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-31 19:57 +0000 [r370644]  Mark Michelson <mmichelson at digium.com>
+
+	* CHANGES, pbx/pbx_config.c: Add "dialplan remove context" and
+	  modify "dialplan add include" From corruptor's review board
+	  posting: "I've noticed that we can remove particular extension
+	  from context with dialplan remove extension command but in order
+	  to remove all extensions in the context we should delete them on
+	  by one. I've created dialplan remove context command which uses
+	  ast_context_destroy to destroy the whole context with all
+	  extensions. I've created to functions for in pbx_config.c:
+	  handle_cli_dialplan_remove_context which actually removes context
+	  and complete_dialplan_remove_context which completes input. They
+	  are based on other similar functions and pretty trivial but I can
+	  be mistaken somewhere. "I've also modified dialplan add include
+	  <context2> into <context1>. I've made it similar dialplan add
+	  extension ... command. It creates <context1> if it doesn't exist
+	  and I've also modified complete_dialplan_add_include and removed
+	  check for existance of <context2> because we can include
+	  non-existent context into another one. (I usually include empty
+	  (non-existent) contexts in advance). Should we raise warning in
+	  this case as it's raised while reading extensions.conf? "I use
+	  those functions with AMI. I think manager commands should be
+	  created in addition to those CLI commands." I've addressed the
+	  latest comments on review board and have made some other coding
+	  guidelines-related cleanup. I also have modified the CHANGES file
+	  to mention these new commands. (closes issue ASTERISK-19292)
+	  reported by Andrey Solovyev Patches: dialplan_add_include.patch
+	  uploaded by Andrey Solovyev (license #5214)
+	  dialplan_remove_context.patch uploaded by Andrey Solovyev
+	  (license #5214) Review: https://reviewboard.asterisk.org/r/2042
+
+2012-07-31 19:10 +0000 [r370636]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c, channels/sip/security_events.c,
+	  channels/sip/include/sip.h: Clean up chan_sip This clean up was
+	  broken out from https://reviewboard.asterisk.org/r/1976/ and
+	  addresses the following: - struct sip_refer converted to use the
+	  stringfields API. - sip_{refer|notify}_allocate ->
+	  sip_{notify|refer}_alloc to match other *alloc functions. -
+	  Replace get_msg_text, get_msg_text2 and get_pidf_body -> No, not
+	  get_pidf_msg_text_body3 but get_content, to match add_content. -
+	  get_body doesn't get the request body, renamed to
+	  get_content_line. - get_body_by_line doesn't get the body line,
+	  and is just a simple if test. Moved code inline and removed
+	  function. - Remove camelCase in struct sip_peer peer state
+	  variables, onHold -> onhold, inUse -> inuse, inRinging ->
+	  ringing. - Remove camelCase in struct sip_request rlPart1 ->
+	  rlpart1, rlPart2 -> rlpart2. - Rename instances of pvt->randdata
+	  to pvt->nonce because that is what it is, no need to update
+	  struct sip_pvt because _it already has a nonce field_. - Removed
+	  struct sip_pvt randdata stringfield. - Remove useless (and
+	  inconsistent) 'header' suffix on variables in
+	  handle_request_subscribe. - Use ast_strdupa on Event header in
+	  handle_request_subscribe to avoid overly complicated strncmp
+	  calls to find the event package. - Move get_destination check in
+	  handle_request_subscribe to avoid duplicate checking for packages
+	  that don't need it. - Move extension state callback management in
+	  handle_request_subscribe to avoid duplicate checking for packages
+	  that don't need it. - Remove duplicate append_date prototype. -
+	  Rename append_date -> add_date to match other add_xxx functions.
+	  - Added add_expires helper function, removed code that manually
+	  added expires header. - Remove _header suffix on
+	  add_diversion_header (no other header adding functions have
+	  this). - Don't pass req->debug to request handle_request_XXXXX
+	  handlers if req is also being passed. - Don't pass req->ignore to
+	  check_auth as req is already being passed. - Don't create a
+	  subscription in handle_request_subscribe if p->expiry == 0. -
+	  Don't walk of the back of referred_by_name when splitting string
+	  in get_refer_info - Remove duplicate check for no dialog in
+	  handle_incoming when sipmethod == SIP_REFER, handle_request_refer
+	  checks for that. Review: https://reviewboard.asterisk.org/r/1993/
+	  Patch-by: gareth
+
+2012-07-30 23:26 +0000 [r370565-370598]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/test.c: Tweak unit test warning message.
+
+	* funcs/func_presencestate.c, main/test.c: Fix some presence-state
+	  unit test typos.
+
+	* apps/app_confbridge.c: DECLINE to load confbridge if the config
+	  fails to load.
+
+	* channels/chan_misdn.c, /: Release B channel allocation on error
+	  path in chan_misdn. ........ Merged revisions 370563 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370564 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-30 14:52 +0000 [r370548]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: app_meetme: Change app_meetme support level
+	  to extended from deprecated (closes issue ASTERISK-20134)
+	  Reported by: Leif Madsen ........ Merged revisions 370547 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-30 13:45 +0000 [r370534-370541]  Russell Bryant <russell at russellbryant.com>
+
+	* tests/test_event.c: Fix ast_event_new unit test. One of my recent
+	  commits broke this test. The error was:
+	  [test_event.c:event_new_test:214]: Events expected to be
+	  identical have different size: 69 != 59 The difference in size
+	  occurred because the first event had the EID IE added to the
+	  event twice. ast_event_new() now always adds it automatically.
+	  Previously it only added it if there were no IEs specified, which
+	  was kind of weird.
+
+	* include/asterisk/event_defs.h, res/res_corosync.c, main/event.c:
+	  Add a "corosync ping" CLI command. This patch adds a new CLI
+	  command to the res_corosync module. It is primarily used as a
+	  debugging tool. It lets you fire off an event which will cause
+	  res_corosync on other nodes in the cluster to place messages into
+	  the logger if everything is working ok. It verifies that the
+	  corosync communication is working as expected. I didn't put
+	  anything in the CHANGES file for this, because this module is new
+	  in Asterisk 11. There is already a generic "res_corosync new
+	  module" entry in there so I figure that covers it just fine.
+
+	* addons/app_mysql.c, CHANGES: Allow specifying a port number for
+	  the MySQL server. This patch allows you to specify a port number
+	  for the MySQL server. It's useful if a MySQL server is running on
+	  a non-standard port. Even though this module is deprecated in
+	  favor of func_odbc, someone asked for this feature and it seems
+	  pretty harmless to add. It has been tested using a number of
+	  combinations of with/without a port number specified in the
+	  dialplan and changing the port number for mysqld.
+
+2012-07-26 15:31 +0000 [r370510-370518]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c, CHANGES: chan_sip: Add SIPpeerstatus command
+	  to AMI This patch was submitted by mnicholson a while back. It
+	  adds a new AMI action which allows users to request SIP peer
+	  status on demand similar to existing PeerStatus events and to the
+	  output you would see from CLI with sip show peer Review:
+	  https://reviewboard.asterisk.org/r/1098/
+
+	* /, res/res_agi.c: res_agi: Add message indicating need for \n
+	  character in verbose message The while loop responsible for
+	  reading AGI messages from a fastAGI service can end up looping
+	  indefinitely when an AGI script fails to indicate the end of a
+	  message with a \n character. This patch adds an indication that
+	  we are expecting a \n character to end the message to make it
+	  more clear to users that this is necessary if they are receiving
+	  this warning over and over. (issue ASTERISK-20061) Reported by:
+	  Eike Kuiper ........ Merged revisions 370494 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370495 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-25 14:27 +0000 [r370481-370488]  Kevin P. Fleming <kpfleming at digium.com>
 
-	* res/ari/resource_channels.c, main/manager.c, /: unqiueid: correct
-	  max uniqueid length test This patch adds null string test prior
-	  to checking for a max uniqueid value that was added in r410157.
-	  ........ Merged revisions 410368 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/Makefile: Repair editline builds using in-tree editline
+	  sources. The previous change to the build system for using a
+	  system-provided editline library was missing a crucial include
+	  directory for building against the copy of the library in the
+	  Asterisk source tree.
 
-2014-03-10 13:30 +0000 [r410346]  Kinsey Moore <kmoore at digium.com>
+	* main/Makefile: Use an absolute path when referring to the
+	  embedded editline directory. This patch changes the build system
+	  to refer to the embedded editline directory using an absolute
+	  path, which will resolve a problem seen on the CentOS automated
+	  build agents.
 
-	* /, channels/chan_sip.c: AST-2014-002: chan_sip: Exit early on bad
-	  session timers request This change allows chan_sip to avoid
-	  creation of the channel and consumption of associated file
-	  descriptors altogether if the inbound request is going to be
-	  rejected anyway. (closes issue ASTERISK-23373) Reported by: Corey
-	  Farrell Patches: chan_sip-earlier-st-1.8.patch uploaded by Corey
-	  Farrell (license 5909) chan_sip-earlier-st-11.patch uploaded by
-	  Corey Farrell (license 5909) ........ Merged revisions 410308
+	* build_tools/menuselect-deps.in, configure,
+	  include/asterisk/autoconfig.h.in, main/Makefile,
+	  main/editline/configure, configure.ac, main/editline/readline
+	  (removed), main/editline/readline.c, main/editline/configure.in,
+	  CHANGES, makeopts.in, main/editline/readline.h (added),
+	  main/asterisk.c, contrib/scripts/install_prereq, main/cli.c:
+	  Enable usage of system-provided NetBSD editline library if
+	  available. This patch changes the Asterisk configure script and
+	  build system to detect the presence of the NetBSD editline
+	  library (libedit) on the system. If it is found, it will be used
+	  in preference to the version included in the Asterisk source
+	  tree. (closes issue ASTERISK-18725) Reported by: Jeffrey C. Ollie
+	  Review: https://reviewboard.asterisk.org/r/1528/ Patches:
+	  0001-Allow-linking-building-against-an-external-editline.patch
+	  uploaded by jcollie (license #5373) (heavily modified by
+	  kpfleming)
+
+2012-07-25 03:51 +0000 [r370474]  Terry Wilson <twilson at digium.com>
+
+	* main/pbx.c, /: Revert a change that broke compilation 1) There is
+	  no such function as ast_ref() 2) The patch was originally
+	  credited as the one uploaded by Guenther Kelleter (license 6372)
+	  via issue AST-921, but the patch committed was not the patch
+	  referenced on the issue. 3) Guenther Kelleter's patch was
+	  actually correct. It moved the ast_free above the
+	  presencechange_cleanup label. I am not committing his change as
+	  it is not technically necesary--calling ast_free(NULL) is
+	  perfectly safe and I worry that moving the ast_free outside of
+	  the label could lead to future bugs if someone ever adds another
+	  failure conditional and expects 'goto presencechange_cleanup;' to
+	  clean up after everything.
+
+2012-07-24 21:30 +0000 [r370466]  Jonathan Rose <jrose at digium.com>
+
+	* main/pbx.c, /: Don't attempt free of NULL ptr in pbx.c
+	  handle_presencechange (closes issue AST-921) Reported by:
+	  Guenther Kelleter Patches: nullptr.patch uploaded by Guenther
+	  Kelleter (license 6372)
+
+2012-07-24 19:12 +0000 [r370453]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* tests/test_acl.c: Silence a warning message from older versions
+	  of GCC. Revision 370426 introduced the use of a nested function
+	  in tests/test_acl.c, but the lack of the 'auto' scope specifier
+	  on the function and a forward declaration resulted in compilation
+	  errors on the automated test systems.
+
+2012-07-24 17:16 +0000 [r370433]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, channels/chan_oss.c: chan_oss: fix "sample rate" error message
+	  Merged revisions 370428 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 Merged
+	  revisions 370432 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-24 16:54 +0000 [r370426-370431]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* main/frame.c, /: Rewrite a comment that didn't adequately explain
+	  the code it was documenting. ........ Merged revisions 370429
 	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 410311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410329 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-10 12:53 +0000 [r410307]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/pjsip_options.c, res/res_pjsip.c: AST-2014-003:
-	  res_pjsip: When handling 401/407 responses don't assume a request
-	  will have an endpoint. This change removes the assumption that an
-	  outgoing request will always have an endpoint and makes the
-	  authenticate_qualify option work once again. (closes issue
-	  ASTERISK-23210) Reported by: Joshua Colp ........ Merged
-	  revisions 410306 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-08 16:50 +0000 [r410288]  George Joseph <george.joseph at fairview5.com>
-
-	* res/res_pjsip/config_auth.c, /, res/res_pjsip/location.c,
-	  res/res_pjsip_outbound_registration.c,
-	  res/res_pjsip_endpoint_identifier_ip.c,
-	  include/asterisk/res_pjsip_cli.h, include/asterisk/sorcery.h,
-	  res/res_pjsip/pjsip_cli.c, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/config_transport.c, main/sorcery.c,
-	  include/asterisk/res_pjsip.h: pjsip_cli: Create pjsip show
-	  channel and contact, and general cli code cleanup. Created the
-	  'pjsip show channel' and 'pjsip show contact' commands.
-	  Refactored out the hated ast_hashtab. Replaced with
-	  ao2_container. Cleaned up function naming. Internal only, no
-	  public name changes. Cleaned up whitespace and brace formatting
-	  in cli code. Changed some NULL checking from "if"s to
-	  ast_asserts. Fixed some register/unregister ordering to reduce
-	  deadlock potential. Fixed ast_sip_location_add_contact where the
-	  'name' buffer was too short. Fixed some self-assignment issues in
-	  res_pjsip_outbound_registration. (closes issue ASTERISK-23276)
-	  Review: http://reviewboard.asterisk.org/r/3283/ ........ Merged
-	  revisions 410287 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-08 15:45 +0000 [r410275]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/ari/resource_channels.c: resource_channels: Check if a
-	  passed in ID is NULL before checking its length Calling strlen on
-	  a NULL string is explosive. This patch checks whether or not the
-	  passed in string is NULL or zero length before checking to see if
-	  the string is too long. ........ Merged revisions 410274 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 22:56 +0000 [r410227]  Corey Farrell <git at cfware.com>
+	  Merged revisions 370430 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: chan_sip: Fix deadlock of monlock between
-	  unload_module and do_monitor Release monlock before calling
-	  pthread_join. This ensures do_monitor cannot freeze by locking
-	  monlock during module unload. (closes issue ASTERISK-21406)
-	  Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3284/ ........ Merged
-	  revisions 410224 from
+	* CHANGES: Update CHANGES for list/negation ACL feature.
+
+	* tests/test_acl.c, main/acl.c: Allow permit/deny ACL lines to
+	  contain multiple items and negated entries. Rules in ACLs
+	  (specified using 'permit' and 'deny') can now contain multiple
+	  items (separated by commas), and items in the rule can be negated
+	  by prefixing them with '!'. This simplifies Asterisk Realtime
+	  configurations, since it is no longer necessray to control the
+	  order that the 'permit' and 'deny' columns are returned from
+	  queries. Review: https://reviewboard.asterisk.org/r/1592/ Initial
+	  patch contributed by Tilghman Lesher Unit tests written by Kevin
+	  P. Fleming
+
+2012-07-24 16:15 +0000 [r370419-370420]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: Build is underway so logging can go away.
+
+	* res/res_rtp_asterisk.c: Temporarily enable pj logging to console
+	  for debugging pjnath issue exposed by build slave.
+
+2012-07-24 08:53 +0000 [r370413]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Remove code, that operate with cdr in
+	  attempt_transfer(). That was removed somewhere between 1.2 and
+	  1.4 and acidentaly put back in chan_unistim. (closes issue
+	  ASTERISK-19628) Reported by: Igor Olhovskiy
+
+2012-07-23 21:27 +0000 [r370407]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* codecs/Makefile, build_tools/menuselect-deps.in, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac,
+	  codecs/codec_ilbc.c, CHANGES, makeopts.in: Enable usage of
+	  system-provided iLBC library. The WebRTC version of the iLBC
+	  codec is now package as a library and is available on some
+	  platforms. This patch allows codec_ilbc to be built against that
+	  library if it is present. Review:
+	  https://reviewboard.asterisk.org/r/1964/
+
+2012-07-23 21:15 +0000 [r370387]  Matthew Jordan <mjordan at digium.com>
+
+	* tests/test_abstract_jb.c (added), main/abstract_jb.c,
+	  funcs/func_jitterbuffer.c, include/asterisk/abstract_jb.h: Unit
+	  tests for the Jitter Buffer API; remove unnecessary resync This
+	  patch includes the following: * Unit tests for the abstract
+	  Jitter Buffer API. This includes both fixed and adaptive flavors,
+	  testing nominal creation, frame input, frame retrieval,
+	  resyncing; off nominal frame input overflow, out of order, and
+	  others. * Tweaks to the abstract_jb API to remove the unnecessary
+	  resync_threshold parameter from the create function
+	  (resync_threshold is already in the struct passed into the create
+	  function) * Ensure the fixed jitter buffer is empty before
+	  destroying it, to avoid an ASSERT * Don't "resync" the adaptive
+	  jitter buffer. The mechanism that was being used actually causes
+	  the jitter buffer to think its being overflowed by going around
+	  the jitterbuf API and attempting to 'resynch' it improperly. If a
+	  resync is needed, the jitter buffer will do it properly by
+	  itself. Note that this is only an optimization needed for trunk,
+	  as the worst that happens is the loss of three voice packets
+	  before the adaptive jitter buffer will resync anyway. Review:
+	  https://reviewboard.asterisk.org/r/2035
+
+2012-07-23 21:10 +0000 [r370386]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample, CHANGES: Add
+	  separate configuration options for subscription and registration
+	  minexpiry and maxexpiry. This offers more fine-grained control
+	  over how long subscriptions last without negatively affecting the
+	  expiration range for registrations. Uploaded by: Guenther
+	  Kelleter(license #6372) Review:
+	  https://reviewboard.asterisk.org/r/2051
+
+2012-07-23 21:10 +0000 [r370385]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, funcs/func_shell.c: Improve documentation for the SHELL()
+	  dialplan function. ........ Merged revisions 370383 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370384 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-23 21:02 +0000 [r370382]  Mark Michelson <mmichelson at digium.com>
+
+	* UPGRADE.txt: Add notes to UPGRADE.txt about addition of msg_id to
+	  VoiceMails.
+
+2012-07-23 00:15 +0000 [r370354]  Joshua Colp <jcolp at digium.com>
+
+	* UPGRADE.txt: Update UPGRADE.txt with notes about ICE support and
+	  res_xmpp.
+
+2012-07-22 23:37 +0000 [r370353]  Matthew Jordan <mjordan at digium.com>
+
+	* CHANGES: Update CHANGES for Asterisk 11 This updates the CHANGES
+	  file with things that were committed for Asterisk 11, but were
+	  not noted in that file.
+
+2012-07-22 17:03 +0000 [r370347]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c, channels/chan_sip.c,
+	  configs/sip.conf.sample, channels/sip/include/sip.h: Prevent
+	  multiple local candidates from being added with the same
+	  information and add support for disabling ICE on a per-peer
+	  basis. (closes issue ASTERISK-20088) Reported by: wimpy Review:
+	  https://reviewboard.asterisk.org/r/2044/
+
+2012-07-21 13:25 +0000 [r370341]  Terry Wilson <twilson at digium.com>
+
+	* main/config_options.c, apps/app_confbridge.c,
+	  apps/confbridge/conf_config_parser.c: Fix segfault introduced by
+	  conversion to ACO API The value "none" is specified in the config
+	  file as a valid value for the "video_mode" option. The code prior
+	  to the ACO conversion did not check for "none", but just ignored
+	  it and relied on the default zero value. The parsing with ACO is
+	  more strict, so without handling "none" specifically, parsing
+	  would fail. When parsing failed, but the module loaded anyway,
+	  the config info would never be stored, and one place in the code
+	  did not check for this case and would segfault. It was also
+	  possible that the aco_info struct's internals would be destroyed
+	  and used as well. This patch keeps the module from loading after
+	  parse failures, adds the "none" option to "video_mode", registers
+	  CLI functions only after parsing has completed, checks the config
+	  data for NULL before accessing it, and returns -1 on some
+	  allocation failures when initializing. (closes issue
+	  ASTERISK-20159) Reported by: Birger "WIMPy" Harzenetter Tested
+	  by: Birger "WIMPy" Harzenetter Patches: confbridge_fix3.txt
+	  uploaded by Terry Wilson
+
+2012-07-20 19:36 +0000 [r370335]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_iax2.c: chan_iax2: Fix a segfault introduced by
+	  call ID logging Didn't previously check that a non NULL IAX
+	  channel was stored in the array at the requested position before
+	  attempting iax_pvt_callid_get (closes issue ASTERISK-20145)
+	  Reported by: Birger "WIMPy" Harzenetter
+
+2012-07-20 19:08 +0000 [r370329]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_dial.c: Clean up ManagerEvent Dial documentation The
+	  paragraph describing the SubEvent belongs with the SubEvent
+	  parameter itself, and not with its enum values. The order of
+	  parsing was placing the description after the last enum, which
+	  isn't correct.
+
+2012-07-20 18:37 +0000 [r370328]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_misdn.c: Fix build error in chan_misdn from commit
+	  370316 chan_misdn was not updated properly to account for a
+	  change in parameters for HANGUPCAUSE functionality. It now builds
+	  properly.
+
+2012-07-20 16:25 +0000 [r370322]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_http_websocket.exports.in: Export the
+	  ast_websocket_set_nonblock function for use by other modules.
+
+2012-07-20 15:48 +0000 [r370316]  Kinsey Moore <kmoore at digium.com>
+
+	* funcs/func_hangupcause.c (added), main/channel.c,
+	  channels/chan_dahdi.c, channels/sig_analog.c, main/rtp_engine.c,
+	  channels/chan_sip.c, main/channel_internal_api.c, UPGRADE.txt,
+	  include/asterisk/channel.h, channels/chan_iax2.c,
+	  channels/sig_pri.c, include/asterisk/frame.h, channels/sig_ss7.c:
+	  Add hangupcause translation support The HANGUPCAUSE hash (trunk
+	  only) meant to replace SIP_CAUSE has now been replaced with the
+	  HANGUPCAUSE and HANGUPCAUSE_KEYS dialplan functions to better
+	  facilitate access to the AST_CAUSE translations for
+	  technology-specific cause codes. The HangupCauseClear application
+	  has also been added to remove this data from the channel. (closes
+	  issue SWP-4738) Review: https://reviewboard.asterisk.org/r/2025/
+
+2012-07-20 15:40 +0000 [r370309-370315]  Richard Mudgett <rmudgett at digium.com>
+
+	* CHANGES: Update CHANGES about adding the AccountCode header to
+	  the AMI Hangup event. (issue ASTERISK-19963)
+
+	* main/channel.c: Add the AccountCode header to the AMI Hangup
+	  event. It's harder to correlate the Newchannel and Hangup AMI
+	  events without specifying "AccountCode" in both. (closes issue
+	  ASTERISK-19963) Reported by: Oleg A. Arkhangelsky Patches:
+	  hangup_acctcode.diff (license #6397) patch uploaded by Oleg A.
+	  Arkhangelsky
+
+2012-07-19 23:21 +0000 [r370303]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/config_options.h,
+	  apps/confbridge/include/confbridge.h, main/config_options.c,
+	  apps/confbridge/conf_config_parser.c: Convert app_confbridge to
+	  use the config options framework Review:
+	  https://reviewboard.asterisk.org/r/2024/
+
+2012-07-19 22:25 +0000 [r370298]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/cel.c: Fix compiler warnings. gcc (GCC) 4.2.4 has
+	  problems casting away constness. ........ Merged revisions 370275
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 370277 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-19 22:17 +0000 [r370272-370278]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_sip.c, res/res_xmpp.c, doc/appdocsxml.dtd,
+	  main/message.c, main/xmldoc.c: Add the ability to specify
+	  technology specific documentation A number of applications/AMI
+	  commands in Asterisk have specific behavioral differences
+	  depending on the resource or channel technology those
+	  applications are executed on. For example, the MessageSend
+	  application/ command is technology agnostic, but how the channel
+	  drivers that support that functionality behave is dependant on
+	  the protocols and channel driver implementation. Prior to this
+	  patch, those details were either documented in the
+	  application/command documentation itself, or were left
+	  undocumented. This patch adds a new element to the documentation
+	  schema, <info/>. An info node is essentially a piece of
+	  technology specific reference information that can be included by
+	  any top level XML documentation node. For example, the
+	  MessageSend application can now include XMPP/SIP specific
+	  information, where that technology specific information can be
+	  defined in chan_motif/res_xmpp/ chan_sip. Likewise, that
+	  information can also be included in the MessageSend AMI command.
+	  Review: https://reviewboard.asterisk.org/r/2049
+
+	* /, main/cel.c: Fix compilation error when MALLOC_DEBUG is enabled
+	  To fix a memory leak in CEL, a channel datastore was introduced
+	  whose destruction function pointer was pointed to the ast_free
+	  macro. Without MALLOC_DEBUG enabled this compiles as fine, as
+	  ast_free is defined as free. With MALLOC_DEBUG enabled, however,
+	  ast_free takes on a definition from a different place then
+	  utils.h, and became undefined. This patch resolves this by using
+	  a reference to ast_free_ptr. When MALLOC_DEBUG is enabled, this
+	  calls ast_free; when MALLOC_DEBUG is not enabled, this is defined
+	  to be ast_free, which is defined to be free. (issue AST-916)
+	  Reported by: Thomas Arimont ........ Merged revisions 370273 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370274 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* res/res_rtp_asterisk.c, /: Handle extremely out of order RFC 2833
+	  DTMF The current implementation of RFC 2833 DTMF handling in
+	  res_rtp_asterisk will, if a packet arrives out of order, drop the
+	  packet. This is to prevent duplicate ton generation in the
+	  Asterisk core. Since the RTP layer does not buffer data itself,
+	  this is the only option the RTP layer currently has for handling
+	  packets that arrive out of order. For the most part, this doesn't
+	  matter. For a particular digit, so long as a BEGIN packet arrives
+	  before the first END packet, the digit will be produced. If
+	  subsequent BEGIN packets arrive interleaved with the ENDs, they
+	  will be dropped; likewise, if the BEGIN or END packets themselves
+	  are out of order, those packets are dropped but sufficient
+	  information is conveyed to the Asterisk core to produce the
+	  appropriate digit. For certain sequences of DTMF packets - most
+	  notably when, for a particular digit, an END packet arrives
+	  before any BEGIN packet for that digit - this is a real problem.
+	  When an END arrives before any BEGINs, the END packet is dropped
+	  - but at the same time, it causes subsequent BEGIN packets for
+	  that digit to be ignored. When the next in order END packet
+	  arrives, it too is dropped - Asterisk believes that there was no
+	  initial BEGIN. The solution this patch provides is to trust the
+	  END packet to convey the information needed for the Asterisk core
+	  to produce the DTMF digit. If we receive an END packet, and it: *
+	  Has a timestamp greater then the last timestamp received from an
+	  END packet * Does not have the same sequence number as the last
+	  received sequence number (and is thus not an END packet
+	  retransmission) Then we send the END frame up to the Asterisk
+	  core. It contains enough DTMF information for Asterisk to produce
+	  the digit. On the other hand, if we receive a BEGIN or
+	  continuation packet that occurs with a timestamp equal to or less
+	  then the last END timestamp, then we've received something out of
+	  order - but we already have received enough information to
+	  produce the digit. These packets are dropped. Much thanks goes to
+	  Olle Johansson (oej) for providing the idea for this solution.
+	  Review: https://reviewboard.asterisk.org/r/2033/ (closes issue
+	  ASTERISK-18404) Reported by: Stephane Chazelas Tested by: Matt
+	  Jordan ........ Merged revisions 370252 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 410225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410226 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 22:08 +0000 [r410212]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, include/asterisk/sorcery.h: sorcery: correct field register
-	  argument list This fixes mistakes I previously made in merging
-	  gtjoseph's changes with mine. ........ Merged revisions 410211
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 21:54 +0000 [r410208-410210]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/config_options.c: config_options: Display the see-also
-	  information for CLI config option help The config option help
-	  information has always parsed the <see-also> tags in the XML
-	  documentation. Unfortunately, it just never bothered displaying
-	  them on the CLI. With this patch, when you execute 'config show
-	  help [module] [obj] [option]', it will display what other options
-	  are useful to you. (closes issue ASTERISK-22008) Reported by:
-	  Richard Mudgett ........ Merged revisions 410209 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip.c, /: res_pjsip: Fix documentation for one touch
-	  recording see-also links The one touch recording options have
-	  several see-also links between the various configuration options.
-	  These were 'broken' by the snake casing of those options. This
-	  patch corrects the see-also links such that they reference the
-	  correct option names. ........ Merged revisions 410194 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 21:23 +0000 [r410207]  Mark Michelson <mmichelson at digium.com>
-
-	* main/sorcery.c, res/res_sorcery_realtime.c, /,
-	  include/asterisk/sorcery.h, tests/test_sorcery_realtime.c: Make
-	  res_sorcery_realtime filter unknown retrieved results. When
-	  retrieving data from a database or other realtime backend, it's
-	  quite possible to retrieve variables that Asterisk does not care
-	  about but that are legitimate to exist. Asterisk does not need to
-	  throw a hissy fit when these variables are encountered but rather
-	  just filter them out. Review:
-	  https://reviewboard.asterisk.org/r/3305 ........ Merged revisions
-	  410187 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 21:11 +0000 [r410191]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/sorcery.c, /, include/asterisk/sorcery.h,
-	  res/res_pjsip/pjsip_configuration.c: pjsip: allow and disallow
-	  show same codecs In order to prevent confusion over the allow and
-	  disallow list of codecs being the same an option for registering
-	  a field as an alias is added. The alias field will be read from
-	  the configuration file, but afterwards is not listed as a known
-	  field. With disallow set as an alias, the CLI command pjsip show
-	  endpoint # will list the allow= field, but not the disallow
-	  field. (closes issue ASTERISK-23092) Review:
-	  https://reviewboard.asterisk.org/r/3193/ ........ Merged
-	  revisions 410190 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 20:41 +0000 [r410174-410185]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/devicestate.h, main/stasis_cache.c,
-	  main/stasis_message.c, /, tests/test_devicestate.c,
-	  include/asterisk/stasis.h, main/app.c, main/devicestate.c,
-	  tests/test_stasis.c: stasis cache: Enhance to keep track of an
-	  item from different entities. A stasis cache entry now contains
-	  more than a single message/snapshot. It contains
-	  messages/snapshots for the local entity as well as any remote
-	  entities that post to the cached item. In addition callbacks can
-	  be supplied when the cache is created to compute and post the
-	  aggregate message/snapshot representing all entities stored in
-	  the cache entry. * All stasis messages now have an eid to
-	  indicate what entity posted it. * The stasis cache enhancements
-	  allow device state to cache and aggregate the device states from
-	  local and remote entities in a single operation. The cached
-	  aggregate device state is available immediately after it is
-	  posted to the stasis bus. This improves performance by
-	  eliminating a cache dump and associated ao2 container traversals
-	  to calculate the aggregate state. (closes issue ASTERISK-23204)
-	  Reported by: Mark Michelson Review:
-	  https://reviewboard.asterisk.org/r/3281/ ........ Merged
-	  revisions 410184 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* tests/test_cel.c, channels/sig_pri.c, channels/sig_ss7.c,
-	  include/asterisk/bridge.h, tests/test_cdr.c, channels/sig_pri.h,
-	  channels/chan_dahdi.c, channels/sig_ss7.h, /: uniqueid: Fix
-	  chan_dahdi, sig_pri, sig_ss7, test_cdr, and test_cel compiler
-	  errors. (issue ASTERISK-23120) ........ Merged revisions 410171
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 15:47 +0000 [r410158]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* tests/test_cdr.c, res/res_clioriginate.c, res/res_ari_bridges.c,
-	  tests/test_substitution.c, res/res_stasis_playback.c,
-	  channels/chan_multicast_rtp.c, apps/app_meetme.c, /,
-	  main/bridge_basic.c, include/asterisk/channel_internal.h,
-	  tests/test_app.c, apps/confbridge/conf_chan_record.c,
-	  main/core_unreal.c, channels/chan_gtalk.c,
-	  include/asterisk/stasis_app_playback.h,
-	  res/ari/resource_bridges.c, channels/chan_jingle.c,
-	  channels/chan_phone.c, pbx/pbx_spool.c,
-	  res/ari/resource_bridges.h, res/parking/parking_tests.c,
-	  channels/chan_motif.c, apps/app_confbridge.c,
-	  res/ari/resource_channels.c, include/asterisk/pbx.h,
-	  res/res_stasis.c, include/asterisk/bridge.h,
-	  apps/app_voicemail.c, res/ari/resource_channels.h,
-	  apps/app_dial.c, res/res_calendar_exchange.c,
-	  channels/chan_vpb.cc, apps/app_page.c, apps/app_chanisavail.c,
-	  include/asterisk/dial.h, main/core_local.c,
-	  res/parking/parking_bridge_features.c,
-	  tests/test_stasis_endpoints.c, res/parking/parking_bridge.c,
-	  channels/chan_skinny.c, include/asterisk/stasis_app_snoop.h,
-	  addons/chan_mobile.c, main/bridge_channel.c,
-	  channels/chan_pjsip.c, channels/chan_mgcp.c,
-	  channels/chan_unistim.c, main/pbx.c,
-	  res/res_calendar_icalendar.c, main/ccss.c,
-	  channels/chan_bridge_media.c, main/bridge.c,
-	  tests/test_stasis_channels.c, apps/app_bridgewait.c,
-	  apps/app_originate.c, res/res_calendar_caldav.c,
-	  include/asterisk/channel.h, res/parking/parking_applications.c,
-	  apps/app_followme.c, main/cel.c, apps/app_queue.c,
-	  res/res_ari_channels.c, res/res_calendar_ews.c,
-	  rest-api/api-docs/bridges.json, main/dial.c,
-	  channels/chan_dahdi.c, channels/chan_h323.c, tests/test_cel.c,
-	  rest-api/api-docs/channels.json,
-	  include/asterisk/bridge_internal.h,
-	  apps/confbridge/conf_chan_announce.c, res/res_calendar.c,
-	  include/asterisk/core_unreal.h, addons/chan_ooh323.c,
-	  res/stasis/control.c, channels/chan_sip.c,
-	  main/channel_internal_api.c, include/asterisk/stasis_app.h,
-	  res/res_stasis_snoop.c, channels/chan_console.c,
-	  channels/chan_iax2.c, channels/chan_oss.c, apps/app_agent_pool.c,
-	  main/channel.c, main/manager.c, channels/chan_misdn.c,
-	  tests/test_voicemail_api.c, channels/chan_alsa.c,
-	  channels/chan_nbs.c, main/message.c: uniqueid: channel linkedid,
-	  ami, ari object creation with id's Much needed was a way to
-	  assign id to objects on creation, and much change was necessary
-	  to accomplish it. Channel uniqueids and linkedids are split into
-	  separate string and creation time components without breaking
-	  linkedid propgation. This allowed the uniqueid to be specified by
-	  the user interface - and those values are now carried through to
-	  channel creation, adding the assignedids value to every function
-	  in the chain including the channel drivers. For local channels,
-	  the second channel can be specified or left to default to a ;2
-	  suffix of first. In ARI, bridge, playback, and snoop objects can
-	  also be created with a specified uniqueid. Along the way, the
-	  args order to allocating channels was fixed in chan_mgcp and
-	  chan_gtalk, and linkedid is no longer lost as masquerade occurs.
-	  (closes issue ASTERISK-23120) Review:
-	  https://reviewboard.asterisk.org/r/3191/ ........ Merged
-	  revisions 410157 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-07 05:04 +0000 [r410108]  Matthew Jordan <mjordan at digium.com>
+	  revisions 370271 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: chan_sip: Allow static realtime members
-	  to be qualified during module load. When a static realtime peer
-	  with qualify=yes is loaded, Asterisk will fail to send an OPTIONS
-	  request due to the lastms being equal to 0. This results in the
-	  peer being unable to receive calls from Asterisk because the
-	  status is permanently UNKNOWN. This patch allows an OPTIONS
-	  request to be sent during module load by ignoring the lastms
-	  value on startup only. Review:
-	  https://reviewboard.asterisk.org/r/3294/ (closes issue
-	  ASTERISK-17523) Reported by: Maciej Krajewski Tested by:
-	  wushumasters patches: realtime_fix_11.7.0.txt uploaded by Trevor
-	  Peirce (license 6112) ........ Merged revisions 410105 from
+2012-07-19 20:37 +0000 [r370246-370265]  Jonathan Rose <jrose at digium.com>
+
+	* main/named_acl.c, configs/acl.conf.sample: named_acl: Remove
+	  systemname option from acl.conf, use asterisk.conf value Review:
+	  https://reviewboard.asterisk.org/r/2057/
+
+	* main/channel_internal_api.c: CallID Logging: Remove new
+	  line/carriage return from callID change test event
+
+2012-07-19 12:14 +0000 [r370234-370240]  Joshua Colp <jcolp at digium.com>
+
+	* res/Makefile, res/pjproject/build/os-auto.mak.in: Use the
+	  bruteforce method to get debugging enabled for pjproject.
+
+	* res/Makefile: Turn on debugging for pjproject so we can get a
+	  better idea of what is causing the generic CCSS test crash.
+
+2012-07-18 19:48 +0000 [r370225]  Jonathan Rose <jrose at digium.com>
+
+	* main/channel_internal_api.c: callid logging: Issue test events
+	  when the callid is changed for a channel Review:
+	  https://reviewboard.asterisk.org/r/2054/
+
+2012-07-18 19:18 +0000 [r370187-370211]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, main/cel.c: Resolve severe memory leak in CEL logging modules.
+	  A customer reported a significant memory leak using Asterisk 1.8.
+	  They have tracked it down to
+	  ast_cel_fabricate_channel_from_event() in main/cel.c, which is
+	  called by both in-tree CEL logging modules (cel_custom.c and
+	  cel_sqlite3_custom.c) for each and every CEL event that they log.
+	  The cause was an incorrect assumption about how data attached to
+	  an ast_channel would be handled when the channel is destroyed;
+	  the data is now stored in a datastore attached to the channel,
+	  which is destroyed along with the channel at the proper time.
+	  (closes issue AST-916) Reported by: Thomas Arimont Review:
+	  https://reviewboard.asterisk.org/r/2053/ ........ Merged
+	  revisions 370205 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370206 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/channel.c, addons/app_mysql.c, main/pbx.c,
+	  funcs/func_curl.c, /, main/ccss.c, funcs/func_odbc.c,
+	  funcs/func_lock.c, apps/app_macro.c, channels/chan_iax2.c,
+	  apps/app_mixmonitor.c, apps/app_stack.c, funcs/func_global.c,
+	  res/res_odbc.c: Ensure that all ast_datastore_info structures are
+	  'const'. While addressing a bug, I came across a instance of
+	  'struct ast_datastore_info' that was not declared 'const'. Since
+	  the API already expects them to be 'const', this patch changes
+	  the declarations of all existing instances that were not already
+	  declared that way. ........ Merged revisions 370183 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 410106 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410107 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 370184 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-18 15:15 +0000 [r370171-370177]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: Fix a crash in pjnath when starting an
+	  ICE connectivity check and immediately destroying the ICE
+	  session. The initial ICE connectivity check is scheduled as a
+	  timer item that is to be executed immediately. It is possible for
+	  this timer item to start executing while the ICE session it is
+	  working on is destroyed. To reduce the chance of this any timer
+	  items that need to be immediately executed will be executed
+	  within the thread that has started the initial ICE connectivity
+	  check.
+
+	* channels/chan_sip.c, include/asterisk/rtp_engine.h: Fix a crash
+	  occurring as a result of excess stack usage. This fix involves
+	  moving the allocation of some temporary codec structures to the
+	  heap and also reduces the number of maximum payloads to something
+	  more sane for both regular and low memory builds. (closes issue
+	  ASTERISK-20140) Reported by: jonnt
+
+2012-07-18 07:17 +0000 [r370165]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, configs/unistim.conf.sample, CHANGES:
+	  Added option 'interdigit_timer' to unistim.conf to make able
+	  controll hardcoded dial timeout constant.
+
+2012-07-17 19:05 +0000 [r370152-370157]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Add pubsub unsubscription support so
+	  subscriptions do not linger for MWI and device state progatation.
+	  The pubsub code did not attempt to remove subscriptions at all.
+	  This has now changed so that if a client is being disconnected it
+	  will unsubscribe. It will also unsubscribe at connection time so
+	  if it unexpectedly disconnected duplicate subscriptions will not
+	  occur. (closes issue ASTERISK-19882) Reported by: mattvryan
+
+	* include/asterisk/xmpp.h, res/res_xmpp.c: Fix a crash as a result
+	  of propagating MWI or device state over XMPP when the client is
+	  disconnected. The MWI and device state propagation code wrongly
+	  assumes that an XMPP client connection will remain established at
+	  all times. This fix corrects that by making the lifetime of the
+	  subscription the same as the lifetime of the connection itself.
+	  As the connection is established and disconnected the
+	  subscription itself is created and destroyed. (closes issue
+	  ASTERISK-18078) Reported by: elguero
+
+2012-07-16 19:58 +0000 [r370133]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Code cleanup and bugfix in chan_sip
+	  outboundproxy parsing. The bug was clearing the global
+	  outboundproxy when a peer-specific outboundproxy was bad. The
+	  cleanup reduces duplicate code. Review:
+	  https://reviewboard.asterisk.org/r/2034/ Reviewed by: Mark
+	  Michelson ........ Merged revisions 370131 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370132 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-06 23:47 +0000 [r410092]  Richard Mudgett <rmudgett at digium.com>
+2012-07-16 19:14 +0000 [r370111-370126]  Joshua Colp <jcolp at digium.com>
 
-	* main/sorcery.c, /: sorcery.c: Fix off-nominal path ref and memory
-	  leak in ast_sorcery_objectset_json_create(). * Made exit a loop
-	  early on error in ast_sorcery_objectset_json_create(). * Removed
-	  some dead code in ast_sorcery_objectset_create2(). ........
-	  Merged revisions 410089 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res/res_xmpp.c: Fix an issue where a service discovery request
+	  could crash Asterisk. A server sending a service discovery
+	  request to us may or may not put a from attribute in the message.
+	  If the from attribute is present use it in the to attribute for
+	  the result. If the from attribute is not present do not add a to
+	  attribute. (issue ASTERISK-16203) Reported by: wubbla
 
-2014-03-06 23:43 +0000 [r410091]  Russell Bryant <russell at russellbryant.com>
+	* res/res_xmpp.c: Fix a bug where some XMPP servers would reject
+	  authentication. We need to use the user portion of the JID and
+	  not the full configured username.
 
-	* /, res/res_musiconhold.c: moh: fix a refcount error with realtime
-	  MOH I observed a crash in res_musiconhold on an Asterisk 11
-	  system using realtime MOH. Investigation of the backtrace showed
-	  a corrupt mohclass, implying that it got destroyed before the
-	  code expected it to. I went looking for reference counting errors
-	  that could have caused this crash and this patch this result. It
-	  contains 2 changes. 1) Remove a usless block of code that was
-	  impossible to reach. There was even a comment indicating that it
-	  was impossible to reach. The conditional includes
-	  "!ast_test_flag(global_flags, MOH_CACHERTCLASSES)" and it's
-	  inside of an if block with the opposite check
-	  "ast_test_flag(global_flags, MOH_CACHERTCLASSES)". There's no
-	  good reason to keep it around. 2) A similar block to #1 contained
-	  a reference counting error. It stores state->class in the local
-	  variable mohclass without increasing its reference count. The
-	  reference count on mohclass is decremented at the end of the
-	  function. This block of code probably very rarely runs, which
-	  would help explain why this system was working fine for many
-	  months before experiencing a crash. Review:
-	  https://reviewboard.asterisk.org/r/3282/ ........ Merged
-	  revisions 410043 from
+	* res/res_xmpp.c: Add missing namespace for old non-SASL based
+	  authentication.
+
+	* channels/chan_sip.c: Fix a bug exposed by the testsuite where
+	  text streams would no longer be parsed correctly.
+
+2012-07-16 14:02 +0000 [r370083]  Kinsey Moore <kmoore at digium.com>
+
+	* /, UPGRADE-10.txt, CHANGES, UPGRADE-1.8.txt: Add comments about
+	  the BUILD_NATIVE change This is a significant change and mention
+	  of it should have gone into UPGRADE.txt and CHANGES. ........
+	  Merged revisions 370081 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370082 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-16 12:58 +0000 [r370072-370073]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.c: Fix an issue where specifying the resource in the
+	  username would cause authentication to fail.
+
+	* channels/sip/sdp_crypto.c, channels/chan_sip.c,
+	  channels/sip/security_events.c,
+	  include/asterisk/http_websocket.h, configs/sip.conf.sample,
+	  CHANGES, res/res_http_websocket.c, channels/sip/include/sip.h:
+	  Add support for SIP over WebSocket. This allows SIP traffic to be
+	  exchanged over a WebSocket connection which is useful for rtcweb.
+	  Review: https://reviewboard.asterisk.org/r/2008
+
+2012-07-16 07:38 +0000 [r370066-370067]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Deactivate timer for dialing entered
+	  number on hook switch hang up. (closes issue ASTERISK-19554)
+	  Reported by: Stefano Villani
+
+	* channels/chan_unistim.c, contrib/unistimLang/fr.po (added),
+	  CHANGES: Add French translation for chan_unistim phones on-screen
+	  menus.
+
+2012-07-13 18:41 +0000 [r370055-370060]  Joshua Colp <jcolp at digium.com>
+
+	* include/asterisk/format.h, res/res_format_attr_h263.c (added),
+	  res/res_format_attr_h264.c (added): Reduce memory consumption and
+	  add the H.264 and H.263 modules I shamefully neglected to add.
+
+	* main/format.c, channels/chan_sip.c, main/translate.c,
+	  include/asterisk/format.h, res/res_format_attr_silk.c,
+	  res/res_format_attr_celt.c: Add support for parsing SDP
+	  attributes, generating SDP attributes, and passing it through.
+	  This support includes codecs such as H.263, H.264, SILK, and
+	  CELT. You are able to set up a call and have attribute
+	  information pass. This should help considerably with video calls.
+	  Review: https://reviewboard.asterisk.org/r/2005/
+
+2012-07-13 00:05 +0000 [r370048]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* contrib/scripts/live_ast: live_ast: don't set working directory
+	  contrib/scripts/live_ast currently assumes that it is being run
+	  from the top-level directory of the source tree. It creates a
+	  script that will also set the working directory. This fix avoids
+	  the need to set the working directory if the caller sets
+	  LIVE_AST_BASE_DIR instead. It relies on realpath for that. If
+	  realpath is not available, it will fall back to the original
+	  behaviour. Review: https://reviewboard.asterisk.org/r/2027/
+
+2012-07-12 21:43 +0000 [r370043]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/config_options.h,
+	  configs/config_test.conf.sample, main/config_options.c,
+	  tests/test_config.c: Handle deprecated (aliased) option names
+	  with the config options api Add a simple way to register
+	  "deprecated" option names that alias to a different "current"
+	  name. Review: https://reviewboard.asterisk.org/r/2026/
+
+2012-07-12 20:28 +0000 [r370037]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c, /: Add missing
+	  ast_hangup() calls on some analog exception paths. Make starting
+	  analog_ss_thread() or __analog_ss_thread() failure paths hangup
+	  the channel. ........ Merged revisions 370017 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370025 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-12 20:06 +0000 [r369995-370016]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Include Expires header for SIP PUBLISH
+	  requests RFC3903 requres SIP PUBLISH requests to have Expires
+	  headers, so add them. Review:
+	  https://reviewboard.asterisk.org/r/2003/ Patch-by: gareth
+	  ........ Merged revisions 370014 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 370015 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Prevent double uri_escaping in chan_sip
+	  when pedantic is enabled If pedantic mode is enabled, outbound
+	  invites will have double-escaped contacts. This avoids setting an
+	  already-escaped string into a field where it is expected to be
+	  unescaped. (closes issue ASTERISK-20023) Reported by: Walter
+	  Doekes ........ Merged revisions 369993 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369994 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-12 14:38 +0000 [r369972-369974]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, funcs/func_math.c: Correct Documentation For DEC Function The
+	  documentation for DEC in func_math.c was incorrect. Looks like a
+	  copy and paste error. (Closes issue ASTERISK-20095) Reported by:
+	  Billy Chia Tested by: Michael L. Young Patches: func_math.patch
+	  uploaded by Billy Chia (license 6381) ........ Merged revisions
+	  369970 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369971 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* funcs/func_math.c: Reverting last merge since it wasn't completed
+	  properly.
+
+	* funcs/func_math.c: Correct Documentation For DEC Function The
+	  documentation for DEC in func_math.c was incorrect. Looks like a
+	  copy and paste error. (Closes issue ASTERISK-20095) Reported by:
+	  Billy Chia Tested by: Michael L. Young Patches: func_math.patch
+	  uploaded by Billy Chia (license 6381) ........ Merged revisions
+	  369970 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-07-11 18:33 +0000 [r369959]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/acl.h, channels/chan_sip.c,
+	  include/asterisk/config.h, main/acl.c,
+	  include/asterisk/channel.h, configs/manager.conf.sample,
+	  channels/chan_iax2.c, CHANGES, main/named_acl.c (added),
+	  main/config.c, main/loader.c, configs/iax.conf.sample,
+	  main/manager.c, include/asterisk/event_defs.h,
+	  configs/extconfig.conf.sample, configs/sip.conf.sample,
+	  channels/sip/include/sip.h, main/asterisk.c,
+	  configs/acl.conf.sample (added): Named ACLs: Introduces a system
+	  for creating and sharing ACLs This patch adds Named ACL
+	  functionality to Asterisk. This allows system administrators to
+	  define an ACL and refer to it by a unique name. Configurable
+	  items can then refer to that name when specifying access control
+	  lists. It also includes updates to all core supported consumers
+	  of ACLs. That includes manager, chan_sip, and chan_iax2. This
+	  feature is based on the deluxepine-trunk by Olle E. Johansson and
+	  provides a subset of the Named ACL functionality implemented in
+	  that branch. For more information on this feature, see acl.conf
+	  and/or the Asterisk wiki. Review:
+	  https://reviewboard.asterisk.org/r/1978/
+
+2012-07-11 17:16 +0000 [r369940]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, main/ast_expr2.h, main/ast_expr2f.c, res/ael/ael_lex.c,
+	  funcs/func_realtime.c, main/ast_expr2.c: Allow the REALTIME()
+	  function to report errors back to the caller. Also, do more error
+	  checking on the arguments specified to the REALTIME() function
+	  and clarify the documentation. While I was editing the file, a
+	  few coding guidelines fixups, as well. Review:
+	  https://reviewboard.asterisk.org/r/2031/ ........ Merged
+	  revisions 369937 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369938 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-11 17:14 +0000 [r369939]  Matthew Jordan <mjordan at digium.com>
+
+	* main/features.c: Don't perform an XInclude to a document node
+	  that may not always be present Because some of the manager events
+	  are defined in the top of the source, due to the macro calls not
+	  containing all necessary information to have the documentation
+	  colocated with the call itself, several include statements were
+	  failing when built with 'make'. While this did not cause any
+	  problems in compilation or validation, it did result in a number
+	  of warnings being dumped to stderr. This patch changes those
+	  references such that they always resolve, regardless of the
+	  documentation build options.
+
+2012-07-11 16:42 +0000 [r369936]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Do not consider failure to read the
+	  configuration file in chan_motif to be a show stopper for loading
+	  Asterisk by returning decline instead of failure. (closes issue
+	  ASTERISK-20103) Reported by: Terry Wilson
+
+2012-07-11 02:06 +0000 [r369905-369910]  Matthew Jordan <mjordan at digium.com>
+
+	* main/cdr.c, main/channel.c, channels/sig_analog.c, main/logger.c,
+	  channels/sig_pri.c, main/asterisk.c, main/loader.c: Fix
+	  validation errors when producing documentation using default
+	  build script The awk script parses out the first instance of the
+	  DOCUMENTATION tag that it finds within a file. If a file did not
+	  previously have a DOCUMENTATION tag but received one due to it
+	  having an AMI event, then the XML fragment associated with the
+	  AMI event was erroneously placed in the resulting XML file.
+	  Without the python scripts, these XML fragments will not
+	  validate. This patch adds DOCUMENTATION tags at the top of those
+	  files that did not previously have them to prevent the awk script
+	  from pulling AMI event documentation.
+
+	* main/cdr.c, main/channel.c, channels/chan_dahdi.c, main/pbx.c,
+	  channels/chan_local.c, channels/sig_analog.c, main/manager.c,
+	  channels/chan_agent.c, main/features.c, main/logger.c,
+	  channels/sig_pri.c, doc/appdocsxml.dtd, main/asterisk.c,
+	  main/loader.c: Add some additional documentation for core AMI
+	  events This patch adds some basic documentation for a number of
+	  modules. This includes core source files in Asterisk (those in
+	  main), as well as chan_agent, chan_dahdi, chan_local, sig_analog,
+	  and sig_pri. The DTD has also been updated to allow referencing
+	  of AMI commands.
+
+2012-07-10 15:36 +0000 [r369900]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c: Fix failing SDP_offer_answer test Asterisk
+	  now generates image stream declinations with the same transport
+	  case that it used to before the stream declination improvements.
+	  (udptl vs UDPTL) (closes issue SWP-4736)
+
+2012-07-10 15:25 +0000 [r369873-369898]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_motif.c: Add additional description stanza names
+	  from the old Google Talk protocol which is used with Google
+	  Voice. (closes issue ASTERISK-20114) Reported by: Malcolm
+	  Davenport
+
+	* channels/chan_motif.c: Respect codec preference order when adding
+	  codecs to a media description. This change allows an endpoint in
+	  motif.conf to be configured with a preference of G.722 and
+	  fallback of ulaw. With Google this allows communication with
+	  Google Talk clients to use G.722 while when using Google Voice
+	  ulaw will be used. (closes issue ASTERISK-20114) Reported by:
+	  Malcolm Davenport
+
+2012-07-10 13:40 +0000 [r369872]  Kinsey Moore <kmoore at digium.com>
+
+	* main/pbx.c, /, apps/app_stack.c: Improve Goto and GotoIf related
+	  documentation Correct documentation on labeliftrue and
+	  labeliffalse parameters of GotoIf() and update several other
+	  locations that use the same syntax. (closes issue ASTERISK-20007)
+	  Patch-by: Leif Madsen Reported-by: WIMPy ........ Merged
+	  revisions 369869 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369871 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-10 13:34 +0000 [r369870]  Matthew Jordan <mjordan at digium.com>
+
+	* main/libasteriskssl.c: Fix initial loading problem with res_curl
+	  When the OpenSSL duplicate initialization issues were resolved in
+	  r351447, res_curl could fail to load if it checked
+	  SSL_library_init after SSL initialization completed. This is due
+	  to the SSL_library_init stub returning a value of 0 for success,
+	  as opposed to a value of 1. OpenSSL uses a value of 1 to indicate
+	  success - in fact, SSL_library_init is documented to always
+	  return 1. Interestingly, the CURL libraries actually checked the
+	  return value - the fact that nothing else that depends on OpenSSL
+	  was having problems loading probably means they don't check the
+	  return value. (closes issue AST-924) Reported by: Guenther
+	  Kelleter patches: (AST-924.patch license #6372 uploaded by
+	  Guenther Kelleter)
+
+2012-07-10 11:49 +0000 [r369837-369864]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c, channels/chan_motif.c: Add required items
+	  for Google video support. This adds legacy STUN support for RTCP
+	  sockets, adds RTCP candidates to the Google transport
+	  information, and adds required codec parameters. (closes issue
+	  ASTERISK-20106) Reported by: Malcolm Davenport
+
+	* main/stun.c: When receiving a STUN binding request send one out
+	  as the Google Talk client uses this as a method to determine if
+	  the remote party is still reachable or not. Failure to do this
+	  results in the Google Talk client ignoring RTP packets after a
+	  specific period of time. This is also done as a result of
+	  receiving a STUN binding request so that the username information
+	  can be used from the inbound request, thus not requiring it to be
+	  stored on a per candidate basis. (closes issue ASTERISK-20107)
+	  Reported by: Malcolm Davenport
+
+	* channels/chan_sip.c: Add support for exposing the received
+	  contact URI and also for setting the request URI in messages.
+	  (closes issue AST-911)
+
+	* channels/chan_motif.c: Force the clock rate of G.722 to be 16000
+	  when using the Google transports as it is 8000 elsewhere. (closes
+	  issue ASTERISK-20105) Reported by: Malcolm Davenport
+
+	* configs/motif.conf.sample: Document that multiple endpoints using
+	  the same connection is not supported. (closes issue
+	  ASTERISK-20104) Reported by: Malcolm Davenport
+
+2012-07-09 17:07 +0000 [r369820]  Jason Parker <jparker at digium.com>
+
+	* configs/sip_notify.conf.sample, /: Add Digium phones context to
+	  sip_notify sample config. This makes it so that they can be
+	  reconfigured remotely. (closes issue ASTERISK-19910) ........
+	  Merged revisions 369818 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369819 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-09 16:44 +0000 [r369811-369817]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_rtp_asterisk.c: Fix an issue where media would not flow
+	  for situations where the legacy STUN code is in use. The STUN
+	  packets should *not* be blocked by strict RTP. (closes issue
+	  ASTERISK-20102) Reported by: Malcolm Davenport
+
+	* res/res_xmpp.c: Add additional namespaces for Google Talk which
+	  are used for the gmail client. (closes issue ASTERISK-20101)
+	  Reported by: Malcolm Davenport
+
+	* channels/chan_motif.c: Fix dependency to be on res_xmpp. Long ago
+	  in a galaxy far far away it used to use res_jabber.
+
+2012-07-09 14:54 +0000 [r369794]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Fix small behavioral change
+	  accidentally introduced in r369750 When removing the warning for
+	  AST_CONTROL_FLASH from sip_indicate, I also inadvertently changed
+	  the return value, which would likely make the indication not be
+	  sent in audio. This fixes that while still removing the warning
+	  message. ........ Merged revisions 369792 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369793 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-07 17:06 +0000 [r369769]  Joshua Colp <jcolp at digium.com>
+
+	* res/res_xmpp.exports.in (added), include/asterisk/xmpp.h,
+	  channels/chan_motif.c (added), UPGRADE.txt,
+	  channels/chan_gtalk.c, res/res_xmpp.c, CHANGES, res/res_jabber.c,
+	  configs/motif.conf.sample (added): Add a new unified Jingle,
+	  Google Jingle, and Google Talk channel driver written from
+	  scratch called chan_motif. This channel driver is a replacement
+	  for both chan_gtalk and chan_jingle but adds additional features
+	  not found in either. These features include full configuration
+	  reload, video, full codec support, bidirectional cause code
+	  mapping, hold, unhold, and ringing indication. It is also
+	  compliant with the current published Jingle and Google Jingle
+	  specifications. The original Google Talk protocol is also
+	  supported for Google Voice interoperability. You may ask yourself
+	  though where the name motif comes from... and I would say to
+	  you... music! motif: a perceivable or salient recurring fragment
+	  or succession of notes Sorta like a jingle! Review:
+	  https://reviewboard.asterisk.org/r/1917/
+
+2012-07-06 22:03 +0000 [r369765]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/chan_iax2.c, channels/sig_pri.c, channels/sig_ss7.c:
+	  Remove unnecessary generation of informational cause frames It is
+	  not necessary to generate information cause code frames on every
+	  protocol event that occurs. This removes all the instances where
+	  the frame was not conveying a cause code and was instead just
+	  conveying a protocol-specific message. This also corrects the
+	  generation of the message associated with disconnects for MFC/R2
+	  to use the MFC/R2 specific text for the disconnect cause.
+
+2012-07-06 21:28 +0000 [r369764]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: chan_sip: Add case for FLASH control
+	  frames so that we don't display a warning. chan_sip channels can
+	  receive flash control frames when connected to analog phones and
+	  possibly for other reasons. There really isn't a reason to warn
+	  when these frames are received, we can safely ignore them.
+	  Patches: dahdi_sip_flash.diff uploaded by Jonathan Rose (license
+	  6182) ........ Merged revisions 369750 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369751 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-06 18:49 +0000 [r369710-369733]  Mark Michelson <mmichelson at digium.com>
+
+	* main/tcptls.c, /: Remove a superfluous and dangerous freeing of
+	  an SSL_CTX. The problem here is that multiple server sessions
+	  share a SSL_CTX. When one session ended, the SSL_CTX would be
+	  freed and set NULL, leaving the other sessions unable to
+	  function. The code being removed is superfluous because the
+	  SSL_CTX structures for servers will be properly freed when
+	  ast_ssl_teardown is called. (closes issue ASTERISK-20074)
+	  Reported by Trevor Helmsley Patches: ASTERISK-20074.diff uploaded
+	  by Mark Michelson (license #5049) Testers: Trevor Helmsley
+	  ........ Merged revisions 369731 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369732 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/bridging.c: Fix bridging thread leak. The bridge thread
+	  was exiting but was never being reaped using pthread_join(). This
+	  has been fixed now by calling pthread_join() in
+	  ast_bridge_destroy(). (closes issue ASTERISK-19834) Reported by
+	  Marcus Hunger Review: https://reviewboard.asterisk.org/r/2012
+	  ........ Merged revisions 369708 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369709 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-06 14:32 +0000 [r369703]  Joshua Colp <jcolp at digium.com>
+
+	* res/pjproject/pjnath/include/pjnath/ice_session.h,
+	  res/pjproject/pjnath/src/pjnath/ice_session.c: Import revision
+	  4196 from pjproject trunk. Fix a crash issue when starting ICE
+	  connectivity checks and immediately destroying the ICE session.
+	  This was exposed by the SIP CCSS test. Full fix for this issue
+	  will be worked on as a medium to long term roadmap item. pjroject
+	  issue viewable at https://trac.pjsip.org/repos/ticket/1548
+
+2012-07-05 21:36 +0000 [r369681]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_stun_monitor.c, CHANGES: Add 'stun show status' command
+	  This patch adds a new CLI command, 'stun show status'. This
+	  command will show a table describing all known STUN servers and
+	  statuses. (closes issue ASTERISK-18046) Reported by: Jeremy
+	  Kister Tested by: Jeremy Kister patches:
+	  (stun-show-status-v4-trunk.patch license #6232 uploaded by Jeremy
+	  Kister) Review: https://reviewboard.asterisk.org/r/2001
+
+2012-07-05 19:36 +0000 [r369677]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/pjproject/pjmedia/include/pjmedia,
+	  res/pjproject/pjsip/include/pjsip,
+	  res/pjproject/pjlib/include/pj/compat,
+	  res/pjproject/pjmedia/include/pjmedia-codec: Make res/pjproject
+	  ignore more files.
+
+2012-07-05 19:36 +0000 [r369676]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_voicemail.c: AST-2012-011: Resolve heap corruption
+	  issue with voicemail The heard and deleted arrays in the
+	  voicemail state structure were not handled properly following the
+	  memory leak fix in r354890 and a fix for an invalid free in
+	  r356797. This could result in accessing and writing into freed
+	  memory. The allocation for these arrays has been reworked to
+	  avoid the possibility of invalid frees, access of freed memory,
+	  and crashes that were occurring as a result of this. Locking
+	  around accesses and modifications of the voicemail state
+	  structure members dh_arraysize, heard, and deleted has been added
+	  to prevent simultaneous modification and access when IMAP storage
+	  is in use. If IMAP storage is not in use, this locking is not
+	  compiled in. Review: https://reviewboard.asterisk.org/r/1994/
+	  (closes issue ASTERISK-19923) Reported by: Dan Delaney Tested by:
+	  Dan Delaney, Julian Yap Patches: vm_alloc_fix.diff uploaded by
+	  kmoore (license 6273) ........ Merged revisions 369652 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369653 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-05 19:32 +0000 [r369666-369673]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/pjproject/pjsip/src/pjsip-ua,
+	  res/pjproject/pjsip-apps/src/ipjsystest/ipjsystest.xcodeproj,
+	  res/pjproject/pjnath/src/pjnath-test,
+	  res/pjproject/third_party/build/speex,
+	  res/pjproject/third_party/build/gsm/output,
+	  res/pjproject/pjmedia/include/pjmedia-codec,
+	  res/pjproject/third_party/build/baseclasses,
+	  res/pjproject/third_party/build/srtp,
+	  res/pjproject/pjsip-apps/src/samples,
+	  res/pjproject/pjlib-util/lib, res/pjproject/pjmedia/bin,
+	  res/pjproject/pjlib/include/pj++,
+	  res/pjproject/tests/pjsua/scripts-call,
+	  res/pjproject/third_party/srtp/doc,
+	  res/pjproject/pjsip-apps/src/pocketpj/output,
+	  res/pjproject/pjnath/bin,
+	  res/pjproject/third_party/srtp/crypto/replay,
+	  res/pjproject/pjsip/include/pjsip,
+	  res/pjproject/third_party/build/speex/speex,
+	  res/pjproject/build.symbian, res/pjproject/third_party/bin,
+	  res/pjproject/pjsip/src/pjsua-lib,
+	  res/pjproject/third_party/srtp/include,
+	  res/pjproject/third_party/portaudio/doc, res/pjproject/lib,
+	  res/pjproject/pjmedia/include/pjmedia-videodev,
+	  res/pjproject/pjlib/bin,
+	  res/pjproject/third_party/srtp/crypto/cipher,
+	  res/pjproject/third_party/build/speex/output,
+	  res/pjproject/pjlib-util/src/pjlib-util,
+	  res/pjproject/third_party/portaudio/test,
+	  res/pjproject/third_party/build/gsm,
+	  res/pjproject/third_party/portaudio/include,
+	  res/pjproject/pjsip-apps/src/pjsua_wince,
+	  res/pjproject/pjsip/include/pjsip-simple,
+	  res/pjproject/pjmedia/src/pjmedia-codec,
+	  res/pjproject/tests/pjsua,
+	  res/pjproject/pjsip-apps/src/pocketpj/res,
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample,
+	  res/pjproject/third_party/gsm/inc,
+	  res/pjproject/pjsip-apps/build/wince-evc4,
+	  res/pjproject/pjsip-apps/src/ipjsua/Resources-iPad,
+	  res/pjproject/third_party/portaudio/src/hostapi,
+	  res/pjproject/third_party/portaudio/build, res/pjproject/build,
+	  res/pjproject/third_party/build/resample,
+	  res/pjproject/third_party/speex/include,
+	  res/pjproject/pjsip/src/pjsip,
+	  res/pjproject/pjlib/build/wince-evc4,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group,
+	  res/pjproject/pjsip-apps/src/symbian_ua,
+	  res/pjproject/tests/pjsua/wavs,
+	  res/pjproject/third_party/portaudio/src/os/win,
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes,
+	  res/pjproject/pjmedia/include/pjmedia,
+	  res/pjproject/tests/pjsua/scripts-sendto,
+	  res/pjproject/third_party/gsm/src,
+	  res/pjproject/third_party/portaudio/build/msvc,
+	  res/pjproject/pjsip-apps/src/confbot,
+	  res/pjproject/pjnath/src/pjturn-client,
+	  res/pjproject/pjlib-util/build/output,
+	  res/pjproject/third_party/BaseClasses,
+	  res/pjproject/third_party/portaudio/src/hostapi/wasapi,
+	  res/pjproject/third_party/portaudio/src/hostapi/wdmks,
+	  res/pjproject/pjlib/src/pj/compat,
+	  res/pjproject/third_party/srtp/crypto/include,
+	  res/pjproject/third_party/speex/include/speex,
+	  res/pjproject/third_party/gsm/add-test,
+	  res/pjproject/pjsip/build,
+	  res/pjproject/pjsip-apps/src/pjsua_wince/output,
+	  res/pjproject/third_party/gsm/lib, res/pjproject/pjsip,
+	  res/pjproject/pjsip-apps/src/pjsystest,
+	  res/pjproject/third_party/portaudio/src,
+	  res/pjproject/third_party/speex/libspeex,
+	  res/pjproject/pjsip/build/wince-evc4/output,
+	  res/pjproject/pjlib-util/src/pjlib-util-test,
+	  res/pjproject/pjsip-apps/src/symsndtest,
+	  res/pjproject/third_party/srtp/tables,
+	  res/pjproject/third_party/g7221, res/pjproject/pjmedia/include,
+	  res/pjproject/pjlib/include/pj,
+	  res/pjproject/third_party/build/portaudio/output,
+	  res/pjproject/pjsip-apps/bin,
+	  res/pjproject/pjsip-apps/src/ipjsua/ipjsua.xcodeproj,
+	  res/pjproject/pjsip-apps/src/pjsua,
+	  res/pjproject/third_party/srtp/test,
+	  res/pjproject/pjsip/include/pjsip-ua,
+	  res/pjproject/third_party/resample,
+	  res/pjproject/third_party/build/ilbc,
+	  res/pjproject/pjmedia/src/pjmedia-audiodev,
+	  res/pjproject/pjsip-apps/src/ipjsua,
+	  res/pjproject/third_party/srtp/srtp,
+	  res/pjproject/third_party/build/milenage,
+	  res/pjproject/pjmedia/src/pjmedia, res/pjproject/pjlib-util,
+	  res/pjproject/third_party/portaudio/src/common,
+	  res/pjproject/third_party/portaudio/bindings/cpp,
+	  res/pjproject/pjlib-util/build/wince-evc4/output,
+	  res/pjproject/third_party/srtp/crypto/kernel,
+	  res/pjproject/tests/pjsua/scripts-pres, res/pjproject/pjnath,
+	  res/pjproject/pjsip/build/output,
+	  res/pjproject/pjsip-apps/build/output,
+	  res/pjproject/pjsip-apps/build, res/pjproject/tests/automated,
+	  res/pjproject/pjnath/build/wince-evc4/output,
+	  res/pjproject/third_party/portaudio/src/hostapi/asio,
+	  res/pjproject/pjnath/include/pjnath,
+	  res/pjproject/pjsip/src/test,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx,
+	  res/pjproject/pjsip/bin,
+	  res/pjproject/third_party/build/portaudio,
+	  res/pjproject/pjlib/build/output, res/pjproject/pjmedia/src,
+	  res/pjproject/pjlib/src/pj, res/pjproject/pjlib,
+	  res/pjproject/pjlib/build/wince-evc4/output,
+	  res/pjproject/pjmedia/src/test/vectors,
+	  res/pjproject/third_party/portaudio/src/hostapi/jack,
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722,
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio,
+	  res/pjproject/pjmedia/build/output,
+	  res/pjproject/pjlib-util/include/pjlib-util,
+	  res/pjproject/third_party/portaudio/src/hostapi/asihpi,
+	  res/pjproject/third_party/milenage, res/pjproject/pjnath/src,
+	  res/pjproject/tests/pjsua/scripts-run,
+	  res/pjproject/pjlib-util/build/wince-evc4,
+	  res/pjproject/pjmedia/lib, res/pjproject/pjmedia/src/test,
+	  res/pjproject/third_party/speex/symbian,
+	  res/pjproject/third_party/speex/win32,
+	  res/pjproject/third_party/srtp/crypto/test,
+	  res/pjproject/pjlib-util/bin,
+	  res/pjproject/third_party/portaudio/build/scons,
+	  res/pjproject/tests/cdash,
+	  res/pjproject/tests/pjsua/scripts-media-playrec,
+	  res/pjproject/third_party/build/portaudio/src,
+	  res/pjproject/pjlib/src, res/pjproject/third_party/mp3,
+	  res/pjproject/pjnath/lib, res/pjproject/third_party/build/g7221,
+	  res/pjproject/third_party/gsm/man,
+	  res/pjproject/third_party/portaudio/src/os/unix,
+	  res/pjproject/third_party/portaudio/bindings,
+	  res/pjproject/pjsip-apps/src/python,
+	  res/pjproject/pjnath/src/pjnath, res/pjproject/third_party/lib,
+	  res/pjproject/third_party/portaudio/src/os/mac_osx,
+	  res/pjproject/third_party/srtp/crypto/ae_xfm,
+	  res/pjproject/pjsip-apps/bin/samples,
+	  res/pjproject/pjnath/src/pjturn-srv,
+	  res/pjproject/third_party/portaudio/pablio,
+	  res/pjproject/pjlib/lib, res/pjproject/third_party/g7221/decode,
+	  res/pjproject/pjlib/include/pj/compat,
+	  res/pjproject/third_party/gsm,
+	  res/pjproject/third_party/build/baseclasses/output,
+	  res/pjproject/third_party/build/srtp/output,
+	  res/pjproject/third_party/srtp, res/pjproject/pjnath/build,
+	  res/pjproject/tests/pjsua/scripts-sipp, res/pjproject/pjsip-apps,
+	  res/pjproject/pjnath/build/wince-evc4,
+	  res/pjproject/third_party/srtp/crypto/rng,
+	  res/pjproject/pjsip/build/wince-evc4,
+	  res/pjproject/pjsip-apps/build/wince-evc4/output,
+	  res/pjproject/third_party/gsm/tst,
+	  res/pjproject/third_party/portaudio/src/hostapi/dsound,
+	  res/pjproject/third_party/portaudio/testcvs,
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes,
+	  res/pjproject/pjlib/build, res/pjproject/third_party/portaudio,
+	  res/pjproject/third_party/portaudio/src/hostapi/wmme,
+	  res/pjproject/pjlib-util/docs,
+	  res/pjproject/pjmedia/include/pjmedia-audiodev,
+	  res/pjproject/pjsip-apps/src/vidgui,
+	  res/pjproject/pjlib/src/pjlib-test,
+	  res/pjproject/pjsip-apps/src/py_pjsua,
+	  res/pjproject/third_party/portaudio/src/os,
+	  res/pjproject/pjsip/include,
+	  res/pjproject/pjmedia/build/wince-evc4,
+	  res/pjproject/pjmedia/src/pjmedia-videodev,
+	  res/pjproject/pjsip-apps/src, res/pjproject/third_party/speex,
+	  res/pjproject/third_party/gsm/tls,
+	  res/pjproject/third_party/g7221/common,
+	  res/pjproject/tests/pjsua/tools,
+	  res/pjproject/third_party/resample/include,
+	  res/pjproject/third_party/build/samplerate/output,
+	  res/pjproject/third_party/build/samplerate,
+	  res/pjproject/third_party/gsm/bin,
+	  res/pjproject/pjsip/src/pjsip-simple,
+	  res/pjproject/third_party/g7221/encode,
+	  res/pjproject/pjlib/src/pjlib-samples,
+	  res/pjproject/pjsip-apps/lib,
+	  res/pjproject/pjsip-apps/src/ipjsystest,
+	  res/pjproject/pjlib-util/include,
+	  res/pjproject/third_party/build/resample/output,
+	  res/pjproject/third_party/build/ilbc/output,
+	  res/pjproject/third_party/srtp/crypto,
+	  res/pjproject/pjsip-apps/src/python/samples, res/pjproject/tests,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/sis,
+	  res/pjproject/pjnath/include,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui,
+	  res/pjproject/pjmedia/build, res/pjproject/pjmedia,
+	  res/pjproject/third_party/build/milenage/output,
+	  res/pjproject/pjlib-util/build, res/pjproject/pjsip/src,
+	  res/pjproject/pjmedia/build/wince-evc4/output,
+	  res/pjproject/third_party/portaudio/src/hostapi/alsa,
+	  res/pjproject/pjsip-apps/docs,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data,
+	  res/pjproject/tests/pjsua/scripts-pesq,
+	  res/pjproject/third_party/srtp/pjlib,
+	  res/pjproject/pjlib/include, res/pjproject/pjnath/build/output,
+	  res/pjproject/third_party/srtp/crypto/hash,
+	  res/pjproject/build/vs, res/pjproject/pjlib/docs,
+	  res/pjproject/third_party/build,
+	  res/pjproject/third_party/resample/src,
+	  res/pjproject/third_party, res/pjproject/pjlib/src/pjlib++-test,
+	  res/pjproject/third_party/build/g7221/output,
+	  res/pjproject/third_party/srtp/crypto/math,
+	  res/pjproject/pjsip/lib, res/pjproject/pjsip-apps/src/pocketpj,
+	  res/pjproject/tests/pjsua/scripts-recvfrom,
+	  res/pjproject/third_party/portaudio/build/dev-cpp,
+	  res/pjproject/pjsip/include/pjsua-lib,
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src, res/pjproject,
+	  res/pjproject/third_party/portaudio/src/hostapi/oss,
+	  res/pjproject/pjlib-util/src, res/pjproject/third_party/ilbc:
+	  Make res/pjproject ignore some generated files.
+
+	* include/asterisk/utils.h: Tweak some comments and whitespace in
+	  utils.h
+
+2012-07-05 18:11 +0000 [r369644]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_mixmonitor.c: app_mixmonitor: Fix a reference leak in
+	  manager_mixmonitor function Manager_mixmonitor included an early
+	  return on failed executions of mixmonitor that would result in a
+	  leaked channel reference. (closes issue ASTERISK-19943) Reported
+	  by: Mark Murawski Patches: mixmonitor-trunk-368394.patch uploaded
+	  by Mark Murawski (license 5791)
+
+2012-07-05 17:03 +0000 [r369628]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Do not send a BYE when a provisional
+	  response arrives during a re-INVITE Commits r369557 and r369579
+	  were done to improve handling of re-INVITEs when the UA that was
+	  supposed to receive the re-INVITE fails to respond. A limitation
+	  of those patches occurred when a UA sent a provisional response
+	  to the re-INVITE. This triggered a sending of a BYE in
+	  check_pending. This patch tweaks the handling of the re-INVITE
+	  such that a BYE is not sent in response to those messages. (issue
+	  ASTERISK-19992) Reported by: Steve Davies Tested by: Steve Davies
+	  patches: (reinvite_tweak.diff license #5012 by Steve Davies)
+	  ........ Merged revisions 369626 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369627 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-05 11:42 +0000 [r369602-369620]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooCmdChannel.c,
+	  addons/ooh323c/src/ooStackCmds.c, addons/ooh323c/src/ooq931.c:
+	  Fix dev mode ooh323 warnings
+
+	* addons/chan_ooh323.c, addons/ooh323c/src/ooq931.h,
+	  addons/ooh323c/src/ooCalls.h, configs/chan_ooh323.conf.sample
+	  (removed), addons/ooh323c/src/ooh323ep.c, CHANGES,
+	  configs/ooh323.conf.sample (added),
+	  addons/ooh323c/src/ooLogChan.c, addons/ooh323c/src/ooStackCmds.c,
+	  addons/ooh323c/src/ooh323.c, addons/ooh323c/src/ooLogChan.h,
+	  addons/ooh323c/src/ooStackCmds.h, addons/ooh323c/src/ooh245.c,
+	  addons/ooh323cDriver.c, addons/ooh323c/src/ooh245.h,
+	  addons/ooh323c/src/ooCmdChannel.c, addons/ooh323c/src/ooq931.c:
+	  Added direct media support to ooh323 channel driver options are
+	  documented in config sample sample config rename to proper name -
+	  ooh323.conf To change media address ooh323 send empty TCS if
+	  there was completed TCS exchange or send facility
+	  forwardedelements with new fast start proposal if not. Then close
+	  transmit logical channels and renew TCS exchange. If new fast
+	  start proposal is received then ooh323 stack call back channel
+	  driver routine to change rtp address in the rtp instance. If
+	  empty TCS is received then close transmit logical channels and
+	  renew TCS exchange Review:
+	  https://reviewboard.asterisk.org/r/1607/
+
+	* addons/ooh323cDriver.c: fix small mistake in the previous
+
+	* addons/ooh323c/src/ooTimer.c, addons/ooh323c/src/ooCapability.c,
+	  addons/ooh323c/src/decode.c, addons/ooh323c/src/perutil.c,
+	  addons/ooh323cDriver.c, addons/ooh323c/src/ooSocket.c,
+	  addons/ooh323c/src/ooq931.c: Fix modern gcc warning Review:
+	  https://reviewboard.asterisk.org/r/1767
+
+2012-07-03 17:07 +0000 [r369559-369581]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: More improvements to re-INVITEs timing
+	  out after a provisional response There is no need to call
+	  check_pendings() on a final response to an INVITE when destroying
+	  the scheduler entry as it will be done later during normal
+	  processing. (issue ASTERISK-19992) ........ Merged revisions
+	  369579 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369580 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Better handle
+	  re-INVITEs with provisional but no final repsonses A previous
+	  attempt at fixing this issue had negative side effects related to
+	  attended transfers which this patch should resolve. Many thanks
+	  to Steve Davies for all of the good suggestions and testing.
+	  (closes issue ASTERISK-19992) Reported by: Steve Davies Tested
+	  by: Steve Davies, Terry Wilson Review:
+	  https://reviewboard.asterisk.org/r/2009/ ........ Merged
+	  revisions 369557 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369558 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-07-02 14:06 +0000 [r369517-369527]  Joshua Colp <jcolp at digium.com>
+
+	* configs/xmpp.conf.sample (added), include/asterisk/xmpp.h
+	  (added), configs/cli_aliases.conf.sample, res/res_xmpp.c (added):
+	  Add a cleaned up drop-in replacement for res_jabber called
+	  res_xmpp. This provides the same externally facing functionality
+	  but is implemented differently internally. This is currently not
+	  built by default but this will be changed once chan_jingle2
+	  (insert actual name in your head when reading this after it has
+	  been merged) is in the tree. Review:
+	  https://reviewboard.asterisk.org/r/1983/
+
+	* res/res_rtp_asterisk.c: Ensure the timer heap is protected by a
+	  lock.
+
+	* res/pjproject/pjlib/include/pj/config_site.h: Enable IPv6 support
+	  in pjproject.
+
+	* res/res_rtp_asterisk.c: Don't try to send connectivity checks on
+	  RTCP if RTCP is no longer present and don't do multiple ICE
+	  connectivity checks at once.
+
+	* res/pjproject/pjlib/src/pj/sock_qos_common.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/crc32.c (added),
+	  res/pjproject/pjsip/src/pjsip-simple/xpidf.c (added),
+	  res/pjproject/third_party/gsm/src/gsm_implode.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-cancel-no-final.xml
+	  (added), res/pjproject/build.symbian/pjmedia.mmp (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_hostapi.h
+	  (added), res/pjproject/pjlib/src/pjlib-test/fifobuf.c (added),
+	  res/pjproject/pjlib/src/pj/file_access_unistd.c (added),
+	  res/pjproject/third_party/gsm/src/toast_ulaw.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_transport_tls.h (added),
+	  res/pjproject/pjsip/include/pjsip/sip_multipart.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/errno.c (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.vcp (added),
+	  res/pjproject/third_party/speex/COPYING (added),
+	  res/pjproject/pjlib/src/pj/os_core_darwin.m (added),
+	  res/pjproject/third_party/ilbc/packing.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_internal.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_receive_crypto_tag_zero.py
+	  (added), res/pjproject/third_party/ilbc/packing.h (added),
+	  res/pjproject/pjlib/src/pj/pool_caching.c (added),
+	  res/pjproject/pjnath/include/pjnath/errno.h (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/h264_packetizer.h
+	  (added), res/pjproject/pjmedia/include/pjmedia/sdp_neg.h (added),
+	  res/pjproject/third_party/speex/libspeex/lsp_bfin.h (added),
+	  res/pjproject/third_party/portaudio/aclocal.m4 (added),
+	  res/pjproject/third_party/mp3/mp3_port.h (added),
+	  res/pjproject/third_party/BaseClasses/ctlutil.cpp (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJDlg.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py
+	  (added), res/pjproject/README-RTEMS (added),
+	  res/pjproject/third_party/build/portaudio/output (added),
+	  res/pjproject/pjsip-apps/build/Makefile (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/prack_fork.xml (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/stun.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/dns_dump.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/circbuf.h (added),
+	  res/pjproject/pjlib/build/os-darwinos.mak (added),
+	  res/pjproject/third_party/srtp/test/rtpw.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/cryptoalg.h
+	  (added), res/pjproject/third_party/portaudio/bindings/cpp
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.xml
+	  (added), res/pjproject/third_party/portaudio/configure.in
+	  (added), res/pjproject/pjmedia/include/pjmedia-codec/g722.h
+	  (added), res/pjproject/pjsip-apps/src/vidgui/pj-pkgconfig.mak
+	  (added), res/pjproject/pjmedia/include/pjmedia-codec/speex.h
+	  (added), res/pjproject/config.guess (added),
+	  res/pjproject/tests/cdash/cfg_site_sample.py (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_skeleton.c
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiSettingItemList.hrh
+	  (added), res/pjproject/third_party/srtp/test/getopt_s.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722 (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_g722.py (added),
+	  res/pjproject/pjnath/src/pjturn-client/client_main.c (added),
+	  res/pjproject/third_party/gsm/src/short_term.c (added),
+	  res/pjproject/build.symbian/libg7221codec.mmp (added),
+	  res/pjproject/pjmedia/src/pjmedia/wsola.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/hmac_sha1.h (added),
+	  res/pjproject/pjlib/include/pj++/list.hpp (added),
+	  res/pjproject/third_party/ilbc/anaFilter.c (added),
+	  res/pjproject/third_party/mp3 (added),
+	  res/pjproject/pjmedia/src/pjmedia/tonegen.c (added),
+	  res/pjproject/pjsip-apps/src/samples/stateful_proxy.c (added),
+	  res/pjproject/third_party/ilbc/anaFilter.h (added),
+	  res/pjproject/pjsip-apps/src/symsndtest/app_main.cpp (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/SettingsDlg.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-invite.xml (added),
+	  res/pjproject/third_party/g7221/encode/sam2coef.c (added),
+	  res/pjproject/pjlib/src/pj/compat/string.c (added),
+	  res/pjproject/pjlib/include/pj/compat/cc_gcce.h (added),
+	  res/pjproject/pjlib/include/pj/config_site_sample.h (added),
+	  res/pjproject/third_party/build/srtp/output (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_speex_8000.py
+	  (added), res/pjproject/tests/pjsua/scripts-sipp/uac-options.xml
+	  (added), res/pjproject/third_party/ilbc/iCBConstruct.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/153_err_sdp_unsupported_codec.py
+	  (added), res/pjproject/pjsip/build/wince-evc4 (added),
+	  res/pjproject/third_party/ilbc/iCBConstruct.h (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/py_pjsua.def (added),
+	  res/pjproject/pjnath/build/pjstun_srv_test.vcproj (added),
+	  res/pjproject/pjlib/src/pjlib-test/util.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev (added),
+	  res/pjproject/pjlib/src/pj/ctype.c (added),
+	  res/pjproject/third_party/ilbc/enhancer.c (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua (added),
+	  res/pjproject/third_party/speex/libspeex/modes_wb.c (added),
+	  res/pjproject/third_party/gsm/tst/gsm2cod.c (added),
+	  res/pjproject/third_party/ilbc/enhancer.h (added),
+	  res/pjproject/pjsip-apps/src (added),
+	  res/pjproject/build/m-arm.mak (added),
+	  res/pjproject/third_party/gsm/src/add.c (added),
+	  res/pjproject/pjsip/src/pjsip/sip_parser_wrap.cpp (added),
+	  res/pjproject/pjlib/src/pj/timer_symbian.cpp (added),
+	  res/pjproject/pjsip-apps/src/vidgui/vidwin.cpp (added),
+	  res/pjproject/pjlib/include/pj/pool_buf.h (added),
+	  res/pjproject/third_party/g7221/encode (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/wmme_dev.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/300_ice_1_0.py (added),
+	  res/pjproject/tests/pjsua/config_site.py (added),
+	  res/pjproject/pjsip-apps/src/pjsua/main.c (added),
+	  res/pjproject/pjlib/src/pj/os_timestamp_posix.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-videodev/videodev_imp.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py
+	  (added), res/pjproject/third_party/srtp/config.h_win32vc7
+	  (added), res/pjproject/tests/pjsua/scripts-pesq (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-reinv-glare.xml
+	  (added), res/pjproject/pjmedia/src/pjmedia/dummy.c (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/209c_reg_handle_423_bad_min_expires2.py
+	  (added), res/pjproject/pjlib/include/pj++/hash.hpp (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev/audiodev_imp.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_24000.py
+	  (added), res/pjproject/pjsip-apps/src/pjsua/pjsua_app.c (added),
+	  res/pjproject/pjsip-apps/src/samples/stereotest.c (added),
+	  res/pjproject/build.symbian/pjstun_client.mmp (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.cpp (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/FirstViewController.h
+	  (added), res/pjproject/pjlib-util/lib (added),
+	  res/pjproject/pjsip-apps/src/samples (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/FirstViewController.m
+	  (added), res/pjproject/tests/pjsua/scripts-call/150_srtp_1_1.py
+	  (added), res/pjproject/pjmedia/include/pjmedia/vid_stream.h
+	  (added), res/pjproject/pjsip/src/pjsip/sip_dialog.c (added),
+	  res/pjproject/pjlib/include/pj/compat/cc_armcc.h (added),
+	  res/pjproject/third_party/build/speex/speex (added),
+	  res/pjproject/third_party/bin (added),
+	  res/pjproject/pjsip/build/Makefile (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/stun_simple.h
+	  (added), res/pjproject/pjsip/src/pjsip/sip_util_proxy_wrap.cpp
+	  (added), res/pjproject/pjlib/include/pj/compat/m_m68k.h (added),
+	  res/pjproject/third_party/srtp/srtp.def (added),
+	  res/pjproject/pjlib/src/pjlib-test/rand.c (added),
+	  res/pjproject/third_party/build/gsm/config.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/avi.h (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-bad-ack.xml (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_gsm.py (added),
+	  res/pjproject/pjsip/src/pjsip-ua/sip_reg.c (added),
+	  res/pjproject/pjsip/build/wince-evc4/pjsip_ua_wince.vcp (added),
+	  res/pjproject/pjsip/include/pjsip-ua/sip_regc.h (added),
+	  res/pjproject/tests/pjsua/mod_pesq.py (added),
+	  res/pjproject/pjnath/src/pjnath/ice_session.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/scanner.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/audiodev.c (added),
+	  res/pjproject/pjsip-apps/src/confbot/confbot.py (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_0_3.py (added),
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_vid.c
+	  (added), res/pjproject/tests/pjsua/tools/cmp_wav.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_2.py
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/alsa_dev.c (added),
+	  res/pjproject/third_party/portaudio/build/msvc (added),
+	  res/pjproject/pjmedia/src/pjmedia/sound_legacy.c (added),
+	  res/pjproject/third_party/ilbc/lsf.c (added),
+	  res/pjproject/pjsip/src/test/inv_offer_answer_test.c (added),
+	  res/pjproject/pjsip-apps/src/confbot (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c
+	  (added), res/pjproject/third_party/speex/libspeex/ltp_bfin.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group/ABLD.BAT
+	  (added), res/pjproject/pjlib/src/pj/ioqueue_winnt.c (added),
+	  res/pjproject/third_party/ilbc/lsf.h (added),
+	  res/pjproject/third_party/speex/libspeex/lsp_tables_nb.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.h
+	  (added),
+	  res/pjproject/third_party/portaudio/build/scons/SConscript_common
+	  (added), res/pjproject/pjmedia/include/pjmedia/frame.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/audio_codecs.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/xml_wrap.cpp (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/PocketPJ.rc2 (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_utilities.c
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev/audiotest.h
+	  (added), res/pjproject/pjlib/src/pj/guid_win32.c (added),
+	  res/pjproject/pjlib/build/os-sunos.mak (added),
+	  res/pjproject/third_party/build/srtp/Makefile (added),
+	  res/pjproject/third_party/speex/libspeex/gain_table.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_utilities.h
+	  (added), res/pjproject/third_party/BaseClasses/wxlist.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_1.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py
+	  (added), res/pjproject/pjsip-apps/src/pjsua/gui.h (added),
+	  res/pjproject/third_party/srtp/crypto/test/auth_driver.c (added),
+	  res/pjproject/pjlib/include/pj/activesock.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/exception.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/main_rtems.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_linux_alsa.c
+	  (added), res/pjproject/pjlib-util/src/pjlib-util/symbols.c
+	  (added), res/pjproject/pjlib/include/pj/types.h (added),
+	  res/pjproject/pjnath/src/pjnath/turn_sock.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/resolver_wrap.cpp
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_linux_alsa.h
+	  (added), res/pjproject/pjlib/include/pj/compat/errno.h (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/100_simple.py (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/RootViewController.xib
+	  (added), res/pjproject/pjlib/build/wince-evc4/output (added),
+	  res/pjproject/pjlib/src/pjlib-test/echo_clt.c (added),
+	  res/pjproject/third_party/portaudio/src/os/unix/pa_unix_util.c
+	  (added), res/pjproject/pjsip/build/wince-evc4/pjsua_lib_wince.vcp
+	  (added), res/pjproject/svn_add (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c
+	  (added), res/pjproject/pjlib-util/build/wince-evc4 (added),
+	  res/pjproject/pjmedia/src/test (added),
+	  res/pjproject/third_party/srtp/crypto/test (added),
+	  res/pjproject/third_party/portaudio/src/os/unix/pa_unix_util.h
+	  (added), res/pjproject/tests/pjsua/scripts-media-playrec (added),
+	  res/pjproject/pjsip-apps/src/samples/vid_streamutil.c (added),
+	  res/pjproject/pkgconfig.py (added),
+	  res/pjproject/third_party/srtp/crypto/hash/sha1.c (added),
+	  res/pjproject/pjlib/src/pj/addr_resolv_sock.c (added),
+	  res/pjproject/pjnath/src/pjturn-srv (added),
+	  res/pjproject/pjmedia/include/pjmedia/wav_playlist.h (added),
+	  res/pjproject/pjsip/include/pjsip/sip_resolve.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/ilbc.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/format.c (added),
+	  res/pjproject/pjsip/src/pjsip/sip_dialog_wrap.cpp (added),
+	  res/pjproject/third_party/speex/include/speex/speex_buffer.h
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia/transport_adapter_sample.c
+	  (added), res/pjproject/pjsip-apps/src/vidgui/vidwin.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/main_symbian.cpp (added),
+	  res/pjproject/pjlib/docs/doxygen.css (added),
+	  res/pjproject/third_party/gsm/src/gsm_explode.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiContainer.hrh
+	  (added), res/pjproject/third_party/speex/libspeex/kiss_fftr.c
+	  (added), res/pjproject/pjlib/src/pj/addr_resolv_linux_kernel.c
+	  (added), res/pjproject/third_party/gsm/tst/lin2cod.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/l16.c (added),
+	  res/pjproject/third_party/speex/libspeex/kiss_fftr.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/SettingsDlg.h (added),
+	  res/pjproject/third_party/resample/src/stddefs.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/rtcp_xr.c (added),
+	  res/pjproject/pjsip-apps/src/vidgui/vidgui.cpp (added),
+	  res/pjproject/pjsip/src/pjsip/sip_resolve.c (added),
+	  res/pjproject/pjsip/src/test/transport_tcp_test.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/121_sdp_with_video_static_2.py
+	  (added), res/pjproject/build.symbian/libpassthroughcodec.mmp
+	  (added), res/pjproject/third_party/srtp/crypto/rng/ctr_prng.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.xml
+	  (added), res/pjproject/third_party/portaudio/fixfile.bat (added),
+	  res/pjproject/pjsip/src/test/multipart_test.c (added),
+	  res/pjproject/pjsip-apps/lib (added),
+	  res/pjproject/third_party/portaudio/pablio/pablio.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/rtp.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/stereo_port.c (added),
+	  res/pjproject/pjsip/src/test/tsx_uas_test.c (added),
+	  res/pjproject/third_party/portaudio/pablio/pablio.h (added),
+	  res/pjproject/third_party/speex/libspeex/vq_bfin.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/bidirectional.h (added),
+	  res/pjproject/third_party/BaseClasses/arithutil.cpp (added),
+	  res/pjproject/third_party/build/milenage/output (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/http_client.c (added),
+	  res/pjproject/third_party/srtp/crypto/hash/hmac.c (added),
+	  res/pjproject/third_party/speex/libspeex/quant_lsp.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-forked-200.xml
+	  (added), res/pjproject/pjmedia/src/pjmedia/mem_player.c (added),
+	  res/pjproject/third_party/speex/libspeex/quant_lsp.h (added),
+	  res/pjproject/third_party/speex/libspeex/filters_bfin.h (added),
+	  res/pjproject/pjsip-apps/src/samples/confbench.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/resample_resample.c (added),
+	  res/pjproject/third_party/build/g7221/output (added),
+	  res/pjproject/pjsip/src/test/regc_test.c (added), res/pjproject
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-videodev/videodev.h
+	  (added), res/pjproject/pjsip-apps/build/Samples-vc.mak (added),
+	  res/pjproject/pjlib/include/pj++/tree.hpp (added),
+	  res/pjproject/pjmedia/src/pjmedia/g711.c (added),
+	  res/pjproject/pjlib/include/pj/guid.h (added),
+	  res/pjproject/pjlib/include/pj/compat/cc_codew.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/echo_port.c (added),
+	  res/pjproject/pjlib/src/pj/activesock.c (added),
+	  res/pjproject/third_party/BaseClasses/msgthrd.h (added),
+	  res/pjproject/pjmedia/bin (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp/Makefile-dll
+	  (added), res/pjproject/pjmedia/src/test/main.c (added),
+	  res/pjproject/pjsip-apps/src/samples/invtester.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/avi_stream.h (added),
+	  res/pjproject/pjsip/src/test/tsx_bench.c (added),
+	  res/pjproject/third_party/speex/libspeex/testdenoise.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.c
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.h
+	  (added), res/pjproject/pjsip-apps/src/samples/recfile.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_endpoint.h (added),
+	  res/pjproject/pjmedia/include/pjmedia_videodev.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_gui.rss
+	  (added), res/pjproject/pjmedia/src/pjmedia/splitcomb.c (added),
+	  res/pjproject/third_party/ilbc/iLBC_test.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/gsm.c (added),
+	  res/pjproject/third_party/srtp/srtp7.sln (added),
+	  res/pjproject/pjlib/src/pjlib-test/string.c (added),
+	  res/pjproject/pjlib/include/pj/compat/high_precision.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/getopt.c (added),
+	  res/pjproject/pjlib/src/pjlib-samples/except.c (added),
+	  res/pjproject/pjmedia/build/pjmedia_audiodev.vcproj (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/resource.h (added),
+	  res/pjproject/third_party/speex/libspeex/bits.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/passthrough.c (added),
+	  res/pjproject/third_party/portaudio/configure (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/pjsua_app.py (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/pcap.c (added),
+	  res/pjproject/third_party/gsm/add-test (added),
+	  res/pjproject/tests/automated/symbian-vas.xml.template (added),
+	  res/pjproject/pjsip-apps/src/symsndtest (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_3_1.py (added),
+	  res/pjproject/pjlib/include/pj/ioqueue.h (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/100_defaults.py (added),
+	  res/pjproject/pjnath/build/Makefile (added),
+	  res/pjproject/pjnath/src/pjnath/errno.c (added),
+	  res/pjproject/pjlib/include/pj/list_i.h (added),
+	  channels/chan_sip.c,
+	  res/pjproject/pjmedia/include/pjmedia/vid_codec_util.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/echo_internal.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/sdp_wrap.cpp (added),
+	  res/pjproject/pjmedia/include/pjmedia/g711.h (added),
+	  res/pjproject/build/vs/pjproject-vs8-common-defaults.vsprops
+	  (added), res/pjproject/self-test.mak (added),
+	  res/pjproject/third_party/portaudio/pablio/test_rw.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-reinv-and-ack-without-sdp.xml
+	  (added), res/pjproject/pjlib-util/build/wince-evc4/output
+	  (added), res/pjproject/pjnath/src/pjnath/stun_transaction.c
+	  (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm5-common-defaults.vsprops
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/201_reg_good_ok.py
+	  (added), res/pjproject/pjsip/src/pjsip/sip_msg.c (added),
+	  res/pjproject/pjlib/src/pj/unicode_symbian.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_2_3.py (added),
+	  res/pjproject/third_party/resample/src/smallfilter.h (added),
+	  res/pjproject/tests/pjsua/scripts-call/301_ice_public_a.py
+	  (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_dither.c
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group/Icons_aif_scalable_dc.mk
+	  (added), res/pjproject/third_party/srtp/Makefile.in (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_dither.h
+	  (added), res/pjproject/pjmedia/src/pjmedia-codec/amr_sdp_match.c
+	  (added), res/pjproject/pjlib/src/pj/pool_dbg.c (added),
+	  res/pjproject/third_party/speex/libspeex/misc_bfin.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio
+	  (added), res/pjproject/pjlib/src/pj/file_io_win32.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util (added),
+	  res/pjproject/third_party/portaudio/build/msvc/portaudio.def
+	  (added), res/pjproject/third_party/speex/libspeex/smallft.c
+	  (added), res/pjproject/pjlib/include/pj/compat/string.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_1.py
+	  (added), res/pjproject/third_party/speex/libspeex/smallft.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/application.uidesign
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/320_srtp2_no_crypto.py
+	  (added), res/pjproject/pjlib/src (added),
+	  res/pjproject/pjsip/src/pjsip/sip_uri.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/410_fmtp_amrnb_offer_octet_align.py
+	  (added), res/pjproject/pjsip/include/pjsua-lib/pjsua_internal.h
+	  (added), res/pjproject/pjlib/include/pj/os.h (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/types.h (added),
+	  res/pjproject/third_party/build/samplerate/libsamplerate_static.dsp
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/string.h
+	  (added), res/pjproject/pjlib/src/pj/sock_qos_wm.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp
+	  (added), res/pjproject/build/m-sparc.mak (added),
+	  res/pjproject/pjlib/src/pjlib-test/main.c (added),
+	  res/pjproject/third_party/gsm/man/gsm_option.3 (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/205_reg_good_no_realm.py
+	  (added), res/pjproject/pjmedia/build/wince-evc4/pjmedia_test.vcp
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_l16_8000_stereo.py
+	  (added), res/pjproject/third_party/srtp/srtp/srtp.c (added),
+	  res/pjproject/third_party/srtp/crypto/Makefile.in (added),
+	  res/pjproject/pjsip/build/pjsip_core.vcproj (added),
+	  res/pjproject/pjlib/src/pj/config.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/audio_codecs.h
+	  (added), res/pjproject/pjlib/include/pj/compat/rand.h (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_win_util.c
+	  (added), res/pjproject/third_party/portaudio (added),
+	  res/pjproject/pjmedia/include/pjmedia/transport_srtp.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/TestViewController.h
+	  (added), res/pjproject/third_party/srtp/crypto/math/math.c
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_process.c
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/TestViewController.m
+	  (added), res/pjproject/tests/pjsua/scripts-pesq/200_codec_g722.py
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/h263_packetizer.c
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_process.h
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/alsa/pa_linux_alsa.c
+	  (added), res/pjproject/pjmedia/include/pjmedia-codec/ipp_codecs.h
+	  (added), res/pjproject/build.symbian/pjlib_util.mmp (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.xml
+	  (added),
+	  res/pjproject/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c
+	  (added), res/pjproject/pjlib/src/pj/sock_common.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h
+	  (added),
+	  res/pjproject/pjlib-util/build/wince-evc4/pjlib_util_wince.vcw
+	  (added), include/asterisk/rtp_engine.h,
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.xml
+	  (added), res/pjproject/pjsip/src/test/msg_test.c (added),
+	  res/pjproject/pjnath/src/pjnath/stun_msg_dump.c (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp/readme.txt
+	  (added), res/pjproject/pjmedia (added), res/pjproject/pjsip/src
+	  (added), res/pjproject/third_party/portaudio/testcvs/changeme.txt
+	  (added), res/pjproject/build/os-rtems.mak (added),
+	  res/pjproject/third_party/gsm/inc/unproto.h (added),
+	  res/pjproject/third_party/build/speex/libspeex.vcproj (added),
+	  res/pjproject/pjlib/include/pj/compat/ctype.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/xml.c (added),
+	  res/pjproject/tests/automated/README.txt (added),
+	  res/pjproject/tests/pjsua/inc_cfg.py (added),
+	  res/pjproject/pjlib/src/pj/hash.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/timer.c (added),
+	  res/pjproject/third_party/gsm/inc/toast.h (added),
+	  res/pjproject/pjnath/build/pjnath_test.vcproj (added),
+	  res/pjproject/pjsip-apps/build/get-footprint.py (added),
+	  res/pjproject/pjsip-apps/src/symsndtest/main_symbian.cpp (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/dns.c (added),
+	  res/pjproject/tests/pjsua/mod_pres.py (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/ipjsua-Info.plist (added),
+	  res/pjproject/pjnath/include/pjnath/config.h (added),
+	  res/pjproject/pjsip/include/pjsip/sip_ua_layer.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/null_dev.c (added),
+	  res/pjproject/third_party/srtp/include (added),
+	  res/pjproject/third_party/speex/libspeex/exc_20_32_table.c
+	  (added), res/pjproject/build/host-unix.mak (added),
+	  res/pjproject/pjmedia/src/pjmedia/alaw_ulaw.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/323_srtp2_receive_too_long_key.py
+	  (added), res/pjproject/third_party/g7221/encode/dct4_a.c (added),
+	  res/pjproject/pjlib/src/pj/addr_resolv_symbian.cpp (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/types.h (added),
+	  res/pjproject/pjnath/include/pjnath/ice_strans.h (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_linux_kernel.c (added),
+	  res/pjproject/third_party/g7221/encode/dct4_a.h (added),
+	  res/pjproject/third_party/speex/libspeex/vq_sse.h (added),
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
+	  (added), res/pjproject/pjlib-util/src/pjlib-util/hmac_sha1.c
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wasapi/pa_win_wasapi.cpp
+	  (added), res/pjproject/third_party/srtp/test/srtp_driver.c
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wmme/pa_win_wmme.c
+	  (added), res/pjproject/build.symbian/01.bat (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res (added),
+	  res/pjproject/third_party/srtp/crypto/VERSION (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua/main_symbian.cpp (added),
+	  res/pjproject/third_party/portaudio/src/hostapi (added),
+	  res/pjproject/pjsip/src/pjsip/sip_util_statefull.c (added),
+	  res/pjproject/tests/cdash/main.py (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/155_err_sdp_bad_syntax.py
+	  (added), res/pjproject/pjsip/src/pjsip-simple/iscomposing.c
+	  (added), res/pjproject/third_party/gsm/tst/cod2lin.c (added),
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample/config_site.h
+	  (added), res/pjproject/third_party/gsm/src (added),
+	  res/pjproject/pjmedia/src/pjmedia/codec.c (added),
+	  res/pjproject/third_party/portaudio/build/msvc/portaudio.sln
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_wmme.c
+	  (added), res/pjproject/pjlib/src/pj/sock_bsd.c (added),
+	  res/pjproject/pjlib/src/pj/lock.c (added),
+	  res/pjproject/third_party/speex/libspeex/stereo.c (added),
+	  res/pjproject/pjsip-apps/src/symsndtest/symsndtest_reg.rss
+	  (added), res/pjproject/third_party/srtp/crypto/ae_xfm/xfm.c
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_wmme.h
+	  (added), res/pjproject/pjsip-apps/src/pjsua_wince/newres.h
+	  (added), res/pjproject/pjlib-util/docs/doxygen.cfg (added),
+	  res/pjproject/build/m-powerpc.mak (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_32.py
+	  (added), res/pjproject/pjnath/src/pjturn-srv/turn.h (added),
+	  res/pjproject/pjsip/include/pjsip/sip_transaction.h (added),
+	  res/pjproject/third_party/g7221 (added),
+	  res/pjproject/pjnath/include/pjnath/nat_detect.h (added),
+	  res/pjproject/third_party/g7221/common/common.c (added),
+	  res/pjproject/pjsip/include/pjsip-simple/evsub.h (added),
+	  res/pjproject/pjlib/include/pjlib++.hpp (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/ipjsua.xcodeproj (added),
+	  res/pjproject/pjlib/src/pjlib-test/list.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiContainerView.h
+	  (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp/portaudio-static.dev
+	  (added), res/pjproject/pjlib/src/pj/os_time_bsd.c (added),
+	  res/pjproject/third_party/speex/libspeex/hexc_10_32_table.c
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/crypto_types.h
+	  (added), res/pjproject/pjnath/src/pjnath/stun_msg.c (added),
+	  res/pjproject/third_party/speex/libspeex/sb_celp.c (added),
+	  res/pjproject/third_party/srtp/crypto/include/rdb.h (added),
+	  res/pjproject/pjsip-apps/src/samples/simpleua.c (added),
+	  res/pjproject/pjsip-apps/build (added),
+	  res/pjproject/third_party/speex/libspeex/sb_celp.h (added),
+	  res/pjproject/third_party/srtp/crypto/include/aes_cbc.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/tonegen.h (added),
+	  res/pjproject/third_party/speex/libspeex/testenc_uwb.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Resources-iPad/SecondView-iPad.xib
+	  (added), res/pjproject/pjlib/src/pj/sock_symbian.cpp (added),
+	  res/pjproject/build/vs/pjproject-vs8-debug-defaults.vsprops
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiAppUi.cpp
+	  (added), res/pjproject/third_party/ilbc/FrameClassify.c (added),
+	  res/pjproject/third_party/build/speex/libspeex.vcp (added),
+	  res/pjproject/third_party/ilbc/FrameClassify.h (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/py_pjsua.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_errno.h (added),
+	  res/pjproject/third_party/gsm/src/toast_alaw.c (added),
+	  res/pjproject/third_party/resample/src/resample.h (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/py_pjsua.h (added),
+	  res/pjproject/pjsip/build/os-auto.mak.in (added),
+	  res/pjproject/third_party/portaudio/config.sub (added),
+	  res/pjproject/pjlib/src/pjlib-test/sleep.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c (added),
+	  res/pjproject/third_party/portaudio/include/pa_jack.h (added),
+	  res/pjproject/pjmedia/build/wince-evc4/pjmedia_wince.vcp (added),
+	  res/pjproject/pjlib/src/pjlib-test/atomic.c (added),
+	  res/pjproject/pjsip/include/pjsip-simple/iscomposing.h (added),
+	  res/pjproject/pjlib/src/pj/os_timestamp_linux_kernel.c (added),
+	  res/pjproject/build.symbian/pjnathU.def (added),
+	  res/pjproject/pjlib/lib (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g7221.c (added),
+	  res/pjproject/pjmedia/build/wince-evc4/pjmedia_wince.vcw (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/361_non_sip_uri.py
+	  (added), res/pjproject/pjmedia/src/pjmedia/vid_codec.c (added),
+	  res/pjproject/pjlib/include/pj/compat/m_i386.h (added),
+	  res/pjproject/third_party/gsm/src/debug.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/160_err_duplicate_replaces.py
+	  (added), res/pjproject/third_party/milenage/rijndael.c (added),
+	  res/pjproject/third_party/milenage/rijndael.h (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_22.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/220_reg_good_ims_ok.py
+	  (added), res/pjproject/build/common.mak (added),
+	  res/pjproject/pjsip-apps/build/pjsystest.vcproj (added),
+	  res/pjproject/pjsip/build/pjsip_ua.vcproj (added),
+	  res/pjproject/pjlib/src/pj/timer.c (added),
+	  res/pjproject/third_party/speex/libspeex/vbr.c (added),
+	  res/pjproject/third_party/speex/libspeex/vbr.h (added),
+	  res/pjproject/third_party/portaudio/src/os (added),
+	  res/pjproject/third_party/resample/COPYING (added),
+	  res/pjproject/pjnath/include/pjnath/turn_session.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx/qgn_menu_symbian_ua_gui.svg
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiSettingItemList.l01
+	  (added), res/pjproject/pjnath/include/pjnath/stun_msg.h (added),
+	  res/pjproject/pjsip/src/test/tsx_uac_test.c (added),
+	  res/pjproject/third_party/portaudio/Doxyfile (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_16.py
+	  (added), res/pjproject/pjsip/src/pjsip-ua/sip_inv.c (added),
+	  res/pjproject/third_party/gsm/add-test/add_test.c (added),
+	  res/pjproject/pjsip-apps/src/samples/mix.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/sock_perf.c (added),
+	  res/pjproject/third_party/build/ilbc/output (added),
+	  res/pjproject/third_party/speex/libspeex/pseudofloat.h (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/config_auto.h.in
+	  (added), res/pjproject/tests/pjsua/scripts-run/200_register.py
+	  (added), res/pjproject/pjlib-util/build (added),
+	  res/pjproject/third_party/srtp/tables/aes_tables.c (added),
+	  res/pjproject/pjsip-apps/docs (added), res/pjproject/install-sh
+	  (added), res/pjproject/third_party/srtp/test/roc_driver.c
+	  (added), res/pjproject/pjsip/src/test/transport_udp_test.c
+	  (added),
+	  res/pjproject/third_party/portaudio/include/pa_win_waveformat.h
+	  (added), res/pjproject/third_party/speex/libspeex/resample.c
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua_gui/inc (added),
+	  res/pjproject/third_party/srtp/pjlib (added),
+	  res/pjproject/third_party/portaudio/build/msvc/readme.txt
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/kernel/crypto_kernel.c
+	  (added), res/pjproject/build.symbian/null_audio.mmp (added),
+	  res/pjproject/third_party/srtp/crypto/replay/rdb.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/scanner_cis_uint.h
+	  (added), res/pjproject/pjsip/lib (added),
+	  res/pjproject/third_party/srtp/crypto/cipher/aes_icm.c (added),
+	  res/pjproject/third_party/speex/libspeex/exc_5_64_table.c
+	  (added), res/pjproject/pjlib/src/pj/os_error_win32.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/opencore_amrnb.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/301_srtp0_recv_savp.py
+	  (added), res/pjproject/pjsip/include/pjsip/sip_transport_tcp.h
+	  (added), res/pjproject/pjsip/src/pjsip/sip_transport_udp.c
+	  (added), res/pjproject/pjsip-apps/build/dummy.c (added),
+	  res/pjproject/pjlib/include/pj++/proactor.hpp (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/999_message_no_body.py
+	  (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_cpuload.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/174_timer_se_too_small.py
+	  (added), res/pjproject/pjlib/src/pj/ip_helper_symbian.cpp
+	  (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_cpuload.h
+	  (added), res/pjproject/pjlib/include/pj/compat/malloc.h (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_ringbuffer.c
+	  (added),
+	  res/pjproject/third_party/portaudio/build/scons/SConscript_opts
+	  (added), res/pjproject/pjlib/include/pj/file_access.h (added),
+	  res/pjproject/pjmedia/build/pjmedia.vcproj (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_ringbuffer.h
+	  (added), res/pjproject/pjnath/include/pjnath/ice_session.h
+	  (added), res/pjproject/pjsip-apps/src/samples/sipstateless.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/201_ice_mismatch_3.py
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/newres.h (added),
+	  res/pjproject/pjsip-apps/src/samples/playsine.c (added),
+	  res/pjproject/pjlib/include/pj/config.h (added),
+	  res/pjproject/pjlib/include/pj/compat/m_sparc.h (added),
+	  res/pjproject/third_party/BaseClasses/wxutil.cpp (added),
+	  res/pjproject/third_party/speex/AUTHORS (added),
+	  res/pjproject/third_party/ilbc/iCBSearch.c (added),
+	  res/pjproject/third_party/ilbc/iCBSearch.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/session.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_front.c (added),
+	  res/pjproject/third_party/speex/libspeex/exc_8_128_table.c
+	  (added), res/pjproject/third_party/gsm/man/toast.1 (added),
+	  res/pjproject/pjmedia/src/test/wsola_test.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/pa_dev.c (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/209b_reg_handle_423_bad_min_expires1.py
+	  (added), res/pjproject/pjsip-apps/build/wince-evc4 (added),
+	  res/pjproject/build.symbian/pjsip_uaU.def (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_unix_oss.c
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua/ua.h (added),
+	  res/pjproject/build/rules.mak (added),
+	  res/pjproject/third_party/speex/libspeex/speex_header.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto (added),
+	  res/pjproject/build.symbian/libsrtp.mmp (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/363_non_sip_uri_subscribe.py
+	  (added), res/pjproject/third_party/srtp/config.sub (added),
+	  res/pjproject/pjmedia/src/pjmedia/sdp.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_msg.h (added),
+	  res/pjproject/pjsip-apps/src/pjsystest (added),
+	  res/pjproject/pjsip (added), res/pjproject/third_party/gsm/lib
+	  (added), res/pjproject/pjmedia/src/test/jbuf_test.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/sound_port.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/ioq_perf.c (added),
+	  res/pjproject/pjsip/build/pjsua_lib.vcproj (added),
+	  res/pjproject/third_party/portaudio/build/msvc/portaudio.dsp
+	  (added), res/pjproject/pjsip/src/pjsip-simple/evsub_msg.c
+	  (added), res/pjproject/pjsip/src/pjsip-simple/mwi.c (added),
+	  res/pjproject/pjsip/src/test/transport_test.c (added),
+	  res/pjproject/build.symbian/pjsdp.mmp (added),
+	  res/pjproject/third_party/portaudio/build/msvc/portaudio.dsw
+	  (added), res/pjproject/pjsip-apps/src/python/helper.mak (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/md5.h (added),
+	  res/pjproject/pjlib-util/build/Makefile (added),
+	  res/pjproject/pjlib/include/pj/pool_alt.h (added),
+	  res/pjproject/pjnath/src/pjnath-test/ice_test.c (added),
+	  res/pjproject/third_party/gsm/tst/run (added),
+	  res/pjproject/pjsip/include/pjsip/sip_uri.h (added),
+	  res/pjproject/pjlib/src/pj (added), res/pjproject/build/cc-vc.mak
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/ipjsystest.xcodeproj/project.pbxproj
+	  (added), res/pjproject/pjnath/src/pjnath-test/stun_sock_test.c
+	  (added), res/pjproject/pjsip/include/pjsip-ua/sip_100rel.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/ipjsystest_Prefix.pch
+	  (added), res/pjproject/pjsip/include/pjsip-ua/sip_xfer.h (added),
+	  res/pjproject/build.symbian/makedef.sh (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/g7221.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asihpi (added),
+	  res/pjproject/third_party/build/portaudio/Makefile (added),
+	  res/pjproject/pjmedia/src/test/vid_dev_test.c (added),
+	  res/pjproject/pjlib/include/pj/sock_select.h (added),
+	  res/pjproject/pjlib/src/pj/pool_signature.h (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_44.py
+	  (added), res/pjproject/third_party/ilbc/helpfun.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-200-inv-without-sdp.xml
+	  (added), res/pjproject/third_party/ilbc/helpfun.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/200_ice_no_ice.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/inv_401_retry_after_100.xml
+	  (added), res/pjproject/pjsip/src/pjsip/sip_tel_uri_wrap.cpp
+	  (added), res/pjproject/pjmedia/src/pjmedia/wave.c (added),
+	  res/pjproject/third_party/portaudio/ltmain.sh (added),
+	  res/pjproject/tests/pjsua/scripts-call/300_ice_0_1.py (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/159_no_rport.py (added),
+	  res/pjproject/third_party/ilbc/iLBC_decode.c (added),
+	  res/pjproject/pjlib/include/pj/compat/os_rtems.h (added),
+	  res/pjproject/pjsip/src/test/txdata_test.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/conference.c (added),
+	  res/pjproject/third_party/srtp/srtp7.vcproj (added),
+	  res/pjproject/third_party/ilbc/iLBC_decode.h (added),
+	  res/pjproject/pjsip/src/pjsip-ua/sip_xfer.c (added),
+	  res/pjproject/pjsip-apps/src/samples/jbsim.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-ticket-1148.xml
+	  (added), res/pjproject/third_party/speex/win32/config.h (added),
+	  res/pjproject/pjsip/src/test/uri_test.c (added),
+	  res/pjproject/pjlib/include/pj/config_site.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/rtcp_xr.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/clock_thread.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/online.ico (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_1_0.py (added),
+	  res/pjproject/third_party/portaudio/testcvs (added),
+	  res/pjproject/pjmedia/include/pjmedia/config_auto.h.in (added),
+	  res/pjproject/third_party/srtp/configure (added),
+	  res/pjproject/pjsip/src/pjsip/sip_util_wrap.cpp (added),
+	  res/pjproject/pjlib/include/pj/rand.h (added),
+	  res/pjproject/third_party/srtp/crypto/include/rdbx.h (added),
+	  res/pjproject/pjproject-vs8.sln (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/avi_dev.c (added),
+	  res/pjproject/third_party/srtp/crypto/rng/rand_linux_kernel.c
+	  (added), res/pjproject/third_party/srtp/config.guess (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev (added),
+	  res/pjproject/third_party/srtp/crypto/rng/prng.c (added),
+	  res/pjproject/third_party/build/ilbc/Makefile (added),
+	  res/pjproject/pjmedia/src/pjmedia/jbuf.c (added),
+	  res/pjproject/third_party/speex/libspeex/modes.c (added),
+	  res/pjproject/third_party/speex/libspeex/modes.h (added),
+	  res/pjproject/third_party/build/samplerate/output (added),
+	  res/pjproject/pjnath/src/pjnath-test/stun.c (added),
+	  res/pjproject/third_party/build/milenage/Makefile (added),
+	  res/pjproject/third_party/build/speex/Makefile (added),
+	  res/pjproject/libpjproject.pc.in (added),
+	  res/pjproject/pjlib-util/include (added),
+	  res/pjproject/third_party/speex/libspeex/resample_sse.h (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_l16_8000.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_1.py
+	  (added), res/pjproject/third_party/BaseClasses/reftime.h (added),
+	  res/pjproject/tests/automated/msvc.xml.template (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_ringbuffer.c
+	  (added), res/pjproject/pjmedia/include/pjmedia/null_port.h
+	  (added),
+	  res/pjproject/third_party/speex/libspeex/cb_search_arm4.h
+	  (added), res/pjproject/pjlib/include/pj/math.h (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_ringbuffer.h
+	  (added), res/pjproject/pjnath/build/output (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/200_ice_success_4.py
+	  (added), res/pjproject/third_party/speex/libspeex/arch.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/wave.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/oss (added),
+	  res/pjproject/third_party/srtp/crypto/include/sha1.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/os.c (added),
+	  res/pjproject/pjlib-util/docs/doxygen.css (added),
+	  res/pjproject/third_party/speex/libspeex/ltp.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiContainer.l01
+	  (added), res/pjproject/pjlib/src/pjlib-test/pool_perf.c (added),
+	  res/pjproject/third_party/speex/libspeex/ltp.h (added),
+	  res/pjproject/tests/pjsua/mod_run.py (added),
+	  res/pjproject/tests/pjsua/scripts-call/100_simplecall.py (added),
+	  res/pjproject/build/m-alpha.mak (added),
+	  res/pjproject/pjmedia/src/pjmedia/master_port.c (added),
+	  res/pjproject/pjsip/include/pjsip (added),
+	  res/pjproject/build/os-linux-kernel.mak (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uas.py
+	  (added), res/pjproject/third_party/BaseClasses/mtype.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Resources-iPad/MainWindow-iPad.xib
+	  (added), res/pjproject/third_party/portaudio/SConstruct (added),
+	  res/pjproject/pjlib/include/pj/errno.h (added),
+	  res/pjproject/pjsip/src/test/msg_err_test.c (added),
+	  res/pjproject/c++-build.mak (added),
+	  res/pjproject/third_party/build/speex/output (added),
+	  res/pjproject/third_party/gsm/src/preprocess.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/jbuf.h (added),
+	  res/pjproject/tests/automated/symbian-aps.xml.template (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/symbian_ua_guiSettingItemList.uidesign
+	  (added), res/pjproject/third_party/portaudio/include (added),
+	  res/pjproject/third_party/build/samplerate/Static.msvc (added),
+	  res/pjproject/pjmedia/build/Makefile (added),
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample (added),
+	  res/pjproject/pjlib/src/pj/os_error_linux_kernel.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua.h
+	  (added), res/pjproject/pjmedia/src/pjmedia/transport_ice.c
+	  (added), res/pjproject/third_party/speex/libspeex/fixed_arm5e.h
+	  (added), res/pjproject/pjmedia/src/pjmedia/wav_playlist.c
+	  (added), res/pjproject/pjmedia/src/test/wince_main.c (added),
+	  res/pjproject/pjlib-util/build/output (added),
+	  res/pjproject/pjsip/include/pjsip/sip_util.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/event.h (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_win_hostapis.c
+	  (added), res/pjproject/pjmedia/src/pjmedia-videodev/sdl_dev.c
+	  (added), res/pjproject/pjsip/include/pjsip-simple/types.h
+	  (added), res/pjproject/third_party/gsm/src/table.c (added),
+	  res/pjproject/third_party/srtp/crypto/include/hmac.h (added),
+	  res/pjproject/third_party/speex/include/speex (added),
+	  res/pjproject/build/vs/pjproject-vs8-release-dynamic-defaults.vsprops
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_g711u.py
+	  (added), res/pjproject/build.symbian/symsndtest.pkg (added),
+	  res/pjproject/pjlib/src/pjlib-test/pool.c (added),
+	  res/pjproject/pjlib/src/pj/log_writer_stdout.c (added),
+	  res/pjproject/pjlib/include/pj/compat/os_palmos.h (added),
+	  res/pjproject/pjlib/include/pj/ssl_sock.h (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec.h (added),
+	  res/pjproject/third_party/build/milenage (added),
+	  res/pjproject/pjnath/src/pjnath/turn_session.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/symbian_ua_guiContainer.uidesign
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/121_sdp_with_video_static_1.py
+	  (added), res/pjproject/build.symbian/pjlib_utilU.def (added),
+	  res/pjproject/build.symbian/pjlib_test.pkg (added),
+	  res/pjproject/tests/pjsua/scripts-call/305_ice_comp_2_1.py
+	  (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm6-common-defaults.vsprops
+	  (added), res/pjproject/pjsip/src/pjsip/sip_transaction.c (added),
+	  res/pjproject/build/host-win32.mak (added),
+	  res/pjproject/third_party/gsm/inc/config.h (added),
+	  res/pjproject/third_party/srtp/test/lfsr.c (added),
+	  res/pjproject/third_party/gsm/src/gsm_print.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_dialog.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/colorbar_dev.c
+	  (added), res/pjproject/build/m-x86_64.mak (added),
+	  res/pjproject/third_party/srtp/config.hw (added),
+	  res/pjproject/pjmedia/include/pjmedia/endpoint.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/hmac_md5.c (added),
+	  res/pjproject/pjnath/src (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.xml
+	  (added), res/pjproject/pjsip-apps/src/python/_pjsua.def (added),
+	  res/pjproject/third_party/speex/win32 (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.xml
+	  (added), res/pjproject/third_party/srtp/configure.in (added),
+	  res/pjproject/pjlib/src/pj/os_timestamp_win32.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_private.h (added),
+	  res/pjproject/pjlib/include/pj/compat/m_x86_64.h (added),
+	  res/pjproject/pjmedia/build/pjmedia_codec.vcproj (added),
+	  res/pjproject/aconfigure (added),
+	  res/pjproject/pjsip/include/pjsip.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/173_timer_offer_no_refresher.py
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/ffmpeg_vid_codecs.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_l16_16000_stereo.py
+	  (added), res/pjproject/pjlib/src/pjlib-test/ssl_sock.c (added),
+	  res/pjproject/third_party/ilbc/LPCdecode.c (added),
+	  res/pjproject/pjlib/src/pj/except.c (added),
+	  res/pjproject/third_party/ilbc/LPCdecode.h (added),
+	  res/pjproject/tests/automated/testvars.template (added),
+	  res/pjproject/pjmedia/include/pjmedia/mem_port.h (added),
+	  res/pjproject/third_party/srtp/include/getopt_s.h (added),
+	  res/pjproject/third_party/gsm/tst/lin2txt.c (added),
+	  res/pjproject/third_party/g7221/common/tables.c (added),
+	  res/pjproject/pjmedia/src/test/test.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722/g722_dec.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/base64.h (added),
+	  res/pjproject/pjsip-apps/build/wince-evc4/wince_demos.vcw
+	  (added), res/pjproject/third_party/g7221/common/tables.h (added),
+	  res/pjproject/pjmedia/src/test/test.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_auth_server.c (added),
+	  res/pjproject/third_party/BaseClasses/renbase.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722/g722_dec.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/http_client.c
+	  (added), res/pjproject/pjlib/src/pj/ioqueue_epoll.c (added),
+	  res/pjproject/pjsip-apps/src/vidgui/INSTALL.TXT (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_debugprint.c
+	  (added), res/pjproject/third_party/gsm/Makefile (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_debugprint.h
+	  (added), res/pjproject/pjlib/src/pj/array.c (added),
+	  res/pjproject/pjsip/src/test/transport_loop_test.c (added),
+	  res/pjproject/pjlib/src/pj/file_io_ansi.c (added),
+	  res/pjproject/pjlib/src/pj/rbtree.c (added),
+	  res/pjproject/pjmedia/build/Jbtest.dat (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/158_err_sdp_bad_transport_type.py
+	  (added),
+	  res/pjproject/build/vs/pjproject-vs8-win32-common-defaults.vsprops
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_11.py
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/null_cipher.h
+	  (added), res/pjproject/third_party/gsm/src/gsm_decode.c (added),
+	  res/pjproject/third_party/srtp/crypto/test/cipher_driver.c
+	  (added), res/pjproject/pjsip-apps/src/samples/proxy.h (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_3_0.py (added),
+	  res/pjproject/pjmedia/include/pjmedia/master_port.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/test_wrap.cpp (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiContainer.rssi
+	  (added), res/pjproject/tests/pjsua/inc_sip.py (added),
+	  res/pjproject/third_party/g7221/common/count.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/converter.h (added),
+	  res/pjproject/pjlib/include/pj/compat/cc_mwcc.h (added),
+	  res/pjproject/pjmedia/src/test/rtp_test.c (added),
+	  res/pjproject/third_party/gsm/src/gsm_option.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_2.py
+	  (added), res/pjproject/pjsip/src/pjsua-lib/pjsua_acc.c (added),
+	  res/pjproject/third_party/build/srtp (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core.c
+	  (added), res/pjproject/pjmedia/src/pjmedia/wav_writer.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/scanner_cis_uint.c
+	  (added), res/pjproject/third_party/gsm/src/gsm_destroy.c (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_48.py
+	  (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp/portaudio-dll.dev
+	  (added), res/pjproject/tests/pjsua/scripts-call/150_srtp_2_2.py
+	  (added), res/pjproject/third_party/srtp/crypto/include/key.h
+	  (added), res/pjproject/tests/automated/run_scenario.py (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-422-then-200-bad-se.xml
+	  (added), res/pjproject/third_party/portaudio/doc (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-reinvite-port-0-bad-sdp.xml
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_dither.c
+	  (added), res/pjproject/pjlib/src/pjlib-test/hash_test.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/symbian_sound_aps.h
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_dither.h
+	  (added), res/pjproject/build.symbian/pjnath.mmp (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_0.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/412_fmtp_amrnb_offer_band_eff2.py
+	  (added), res/pjproject/third_party/srtp/crypto/replay/ut_sim.c
+	  (added), res/pjproject/third_party/speex/libspeex/cb_search.c
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/pcap.h
+	  (added), res/pjproject/pjmedia/src/pjmedia/avi_player.c (added),
+	  res/pjproject/third_party/speex/libspeex/cb_search.h (added),
+	  res/pjproject/pjsip-apps/src/python/setup-vc.py (added),
+	  res/pjproject/third_party/BaseClasses/wxlist.cpp (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/resolver.c (added),
+	  res/pjproject/pjsip/src/pjsip (added),
+	  res/pjproject/third_party/srtp/crypto/include/err.h (added),
+	  res/pjproject/tests/pjsua/scripts-call/350_prack_b.py (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group (added),
+	  res/pjproject/third_party/gsm/inc/gsm.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_endpoint_wrap.cpp (added),
+	  res/pjproject/third_party/milenage/milenage.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/http_client.h
+	  (added), res/pjproject/third_party/speex/libspeex/testenc.c
+	  (added), res/pjproject/third_party/milenage/milenage.h (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/systest.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-forked-100rel.xml
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/errno.h
+	  (added), res/pjproject/third_party/portaudio/src (added),
+	  res/pjproject/pjlib/src/pjlib-test/mutex.c (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/systest.h (added),
+	  res/pjproject/third_party/BaseClasses/refclock.h (added),
+	  res/pjproject/tests/cdash/README.TXT (added),
+	  res/pjproject/pjlib/src/pjlib-test/test.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiContainer.h
+	  (added), res/pjproject/pjmedia/src/test/mips_test.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/test.h (added),
+	  res/pjproject/third_party/srtp/srtp (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_stream.c
+	  (added), res/pjproject/pjlib-util (added),
+	  res/pjproject/third_party/srtp/crypto/replay/rdbx.c (added),
+	  res/pjproject/third_party/g7221/common/huff_def.h (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_stream.h
+	  (added), res/pjproject/tests/pjsua/scripts-pres (added),
+	  res/pjproject/pjlib/src/pjlib-test/sock.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/stream.h (added),
+	  res/pjproject/pjlib/include/pj/compat/stdfileio.h (added),
+	  res/pjproject/pjnath/build/wince-evc4/output (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asio (added),
+	  res/pjproject/pjlib/src/pj/os_timestamp_common.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/transport_udp.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/stream_common.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/main.c (added),
+	  res/pjproject/pjlib/include/pj++/lock.hpp (added),
+	  res/pjproject/third_party/speex/libspeex/fixed_arm4.h (added),
+	  res/pjproject/pjlib (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm2003-common-defaults.vsprops
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/312_srtp1_recv_savp.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/datatypes.h
+	  (added), res/pjproject/pjsip-apps/build/pjsua.vcproj (added),
+	  res/pjproject/third_party/milenage (added), res/Makefile,
+	  res/pjproject/tests/pjsua/scripts-sendto/260_multipart_err_no_sdp.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_2.py
+	  (added),
+	  res/pjproject/third_party/speex/libspeex/quant_lsp_bfin.h
+	  (added), res/pjproject/pjlib-util/bin (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/DEPRECATED.txt (added),
+	  res/pjproject/pjnath/lib (added),
+	  res/pjproject/third_party/build/g7221 (added),
+	  res/pjproject/pjlib/include/pj/ctype.h (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/h263_packetizer.h
+	  (added), res/pjproject/third_party/ilbc/gainquant.c (added),
+	  res/pjproject/pjlib/src/pj/pool_policy_kmalloc.c (added),
+	  res/pjproject/pjmedia/build/os-auto.mak.in (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/config.cfg (added),
+	  res/pjproject/third_party/ilbc/gainquant.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/plc_common.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_debugprint.c
+	  (added), res/pjproject/pjlib/include/pj/assert.h (added),
+	  res/pjproject/pjsip/include/pjsip/sip_module.h (added),
+	  res/pjproject/tests/pjsua/scripts-sipp (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_debugprint.h
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/s60_g729_bitstream.h
+	  (added), res/pjproject/third_party/srtp/crypto/rng (added),
+	  res/pjproject/pjsip-apps/build/wince-evc4/output (added),
+	  res/pjproject/pjlib/docs/footer.html (added),
+	  res/pjproject/pjlib/src/pj/os_symbian.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes (added),
+	  res/pjproject/pjmedia/include/pjmedia/rtp.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/resample.h (added),
+	  res/pjproject/pjsip-apps/src/python/samples/call.py (added),
+	  res/pjproject/third_party/speex/include/speex/speex_header.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/159_no_rport_nit.py
+	  (added), res/pjproject/tests/automated/run_continuous.py (added),
+	  res/pjproject/pjlib/src/pjlib-test/main_mod.c (added),
+	  res/pjproject/pjlib/include/pjlib.h (added),
+	  res/pjproject/third_party/srtp/test/dtls_srtp_driver.c (added),
+	  res/pjproject/pjnath/src/pjturn-srv/allocation.c (added),
+	  res/pjproject/build.symbian/symbian_audio.mmp (added),
+	  res/pjproject/pjsip/src/pjsip/sip_endpoint.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_waveformat.c
+	  (added), res/pjproject/third_party/srtp/crypto/include/prng.h
+	  (added), res/pjproject/configure (added),
+	  res/pjproject/third_party/gsm/tls (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_waveformat.h
+	  (added), res/pjproject/pjlib/src/pjlib-samples/list.c (added),
+	  res/pjproject/pjsip/src/pjsip/sip_parser.c (added),
+	  res/pjproject/third_party/srtp/crypto/include/crypto_kernel.h
+	  (added), res/pjproject/third_party/gsm/tls/bitter.c (added),
+	  res/pjproject/pjmedia/include/pjmedia.h (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_select.c (added),
+	  res/pjproject/pjsip-apps/src/samples/resampleplay.c (added),
+	  res/pjproject/third_party/srtp/crypto (added),
+	  res/pjproject/build/host-mingw.mak (added),
+	  res/pjproject/pjlib/include/pj/compat/size_t.h (added),
+	  res/pjproject/pjlib-util/build/pjlib_util.dsw (added),
+	  res/pjproject/third_party/srtp/LICENSE (added),
+	  res/pjproject/pjlib/include/pj/log.h (added),
+	  res/pjproject/pjlib/include/pj/compat/setjmp.h (added),
+	  res/pjproject/pjnath/include (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_dummy.c (added),
+	  res/pjproject/pjmedia/build (added),
+	  res/pjproject/pjsip-apps/build/py_pjsua.vcproj (added),
+	  res/pjproject/third_party/gsm/man/gsm.3 (added),
+	  res/pjproject/pjsip-apps/src/samples/pcaputil.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/errno.c (added),
+	  res/pjproject/build.symbian/libresample.mmp (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PopUpWnd.cpp (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_win_waveformat.c
+	  (added), res/pjproject/pjlib/include/pj/list.h (added),
+	  res/pjproject/third_party/ilbc (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiContainerView.cpp
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiDocument.cpp
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/ipjsystest.xcodeproj
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.rc
+	  (added), res/pjproject/pjmedia/include/pjmedia/session.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_gui_reg.rss
+	  (added), res/pjproject/pjmedia/include/pjmedia-codec/ilbc.h
+	  (added), res/pjproject/pjmedia/include/pjmedia/signatures.h
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_endianness.h
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev/audiodev.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/203_reg_good_empty_realm.py
+	  (added), res/pjproject/third_party/speex/libspeex/os_support.h
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/kernel_compat.h
+	  (added),
+	  res/pjproject/pjmedia/build/wince-evc4/pjmedia_codec_wince.vcp
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_3.py
+	  (added), res/pjproject/third_party/gsm/src/gsm_create.c (added),
+	  res/pjproject/third_party/build/ilbc/libilbccodec.vcproj (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_vid.c (added),
+	  res/pjproject/pjlib/include/pj/except.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/endpoint.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec (added),
+	  res/pjproject/pjlib/include/pj/compat/stdarg.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/TestViewController.xib
+	  (added), res/pjproject/build.symbian/symbian_ua_urel.pkg (added),
+	  res/pjproject/third_party/speex/libspeex/math_approx.h (added),
+	  res/pjproject/pjsip-apps/src/samples/tonegen.c (added),
+	  res/pjproject/build/vs/pjproject-vs8-release-defaults.vsprops
+	  (added), res/pjproject/pjlib/include/pj/rbtree.h (added),
+	  res/pjproject/pjlib/include/pj/compat/m_alpha.h (added),
+	  res/pjproject/third_party/speex/libspeex/vorbis_psy.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-timer-update.xml
+	  (added), res/pjproject/third_party/ilbc/iLBC_define.h (added),
+	  res/pjproject/third_party/speex/libspeex/vorbis_psy.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wasapi (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wdmks (added),
+	  res/pjproject/third_party/srtp/include/srtp_priv.h (added),
+	  res/pjproject/pjmedia/src/test/sdptest.c (added),
+	  res/pjproject/pjlib/include/pj++/file.hpp (added),
+	  res/pjproject/pjsip/src/test/tsx_basic_test.c (added),
+	  res/pjproject/pjnath/include/pjnath/stun_auth.h (added),
+	  res/pjproject/pjsip-apps/bin (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/ConfigViewController.h
+	  (added), res/pjproject/pjmedia/include/pjmedia-videodev/config.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/ConfigViewController.m
+	  (added), res/pjproject/pjsip-apps/src/ipjsua (added),
+	  res/pjproject/third_party/BaseClasses/combase.cpp (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/hmac_md5.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/364_non_sip_uri_subscribe.py
+	  (added), res/pjproject/third_party/portaudio/src/common (added),
+	  res/pjproject/pjlib/build/os-rtems.mak (added),
+	  res/pjproject/third_party/gsm/tls/taste.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/ioq_tcp.c (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_win_wdmks_utils.c
+	  (added), res/pjproject/third_party/gsm/tls/taste.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asio/iasiothiscallresolver.h
+	  (added), res/pjproject/third_party/BaseClasses/fourcc.h (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_win_wdmks_utils.h
+	  (added), res/pjproject/tests/automated/symbian.xml.template
+	  (added), res/pjproject/pjmedia/src/test/vectors (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/dsound/pa_win_ds.c
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_bits.h
+	  (added),
+	  res/pjproject/third_party/resample/include/resamplesubs.h
+	  (added), res/pjproject/pjsip/src/pjsip-simple/publishc.c (added),
+	  res/pjproject/third_party/srtp/crypto/include/aes.h (added),
+	  res/pjproject/third_party/srtp/undos.sh (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/scanner.h (added),
+	  res/pjproject/third_party/gsm/tls/sweet.c (added),
+	  res/pjproject/third_party/gsm/man (added),
+	  res/pjproject/build/vs/pjproject-vs8-debug-dynamic-defaults.vsprops
+	  (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_hostapi.h
+	  (added), res/pjproject/third_party/ilbc/createCB.c (added),
+	  res/pjproject/third_party/gsm/man/gsm_print.3 (added),
+	  res/pjproject/third_party/srtp/crypto/ae_xfm (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c
+	  (added), res/pjproject/third_party/ilbc/createCB.h (added),
+	  res/pjproject/third_party/gsm/ChangeLog (added),
+	  res/pjproject/pjlib/src/pj/guid.c (added),
+	  res/pjproject/pjsip-apps/src/python/Makefile (added),
+	  res/pjproject/third_party/gsm (added),
+	  res/pjproject/pjlib/include/pj/compat (added),
+	  res/pjproject/pjmedia/src/pjmedia/echo_common.c (added),
+	  res/pjproject/pjsip-apps/build/Footprint.mak (added),
+	  res/pjproject/tests/automated/iphone.xml.template (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_4.py
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_types.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/201_ice_mismatch_2.py
+	  (added), res/pjproject/third_party/build/portaudio/src/pa_trace.c
+	  (added), res/pjproject/pjsip-apps/src/samples/httpdemo.c (added),
+	  res/pjproject/pjlib/src/pj/ssl_sock_dump.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/pool_wrap.cpp (added),
+	  res/pjproject/pjnath/build/wince-evc4/pjnath_wince.vcp (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml
+	  (added), res/pjproject/third_party/gsm/tst (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g7221_sdp_match.c
+	  (added), res/pjproject/third_party/build/portaudio/src/pa_trace.h
+	  (added), res/pjproject/third_party/build/os-auto.mak.in (added),
+	  res/pjproject/third_party/speex/libspeex/speex.c (added),
+	  res/pjproject/pjnath/build/wince-evc4/pjnath_wince.vcw (added),
+	  res/pjproject/pjsip/src/pjsip/sip_ua_layer.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/string.c (added),
+	  res/pjproject/third_party/speex/libspeex/echo_diagnostic.m
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-reinvite-bad-via-branch.xml
+	  (added), res/pjproject/pjsip-apps/build/os-win32.mak (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_converters.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/321_srtp2_recv_avp.py
+	  (added), res/pjproject/tests/pjsua/tools (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_converters.h
+	  (added), res/pjproject/build/os-win32.mak (added),
+	  res/pjproject/pjlib/src/pj/compat/sigjmp.c (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_call.c (added),
+	  res/pjproject/pjsip-apps/src/samples/main_rtems.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/156_err_sdp_bad_net_type.py
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/crypto_math.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_g711a.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml
+	  (added), res/pjproject/pjmedia/include/pjmedia/echo.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_util.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_endianness.h
+	  (added), res/pjproject/third_party/srtp/update.sh (added),
+	  res/pjproject/pjsip/include/pjsip-simple/presence.h (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py
+	  (added), res/pjproject/pjlib/include/pj/addr_resolv.h (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_dump.c (added),
+	  res/pjproject/pjsip/src/pjsip-simple/evsub.c (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp/Makefile-static
+	  (added), res/pjproject/pjsip/include/pjsua-lib (added),
+	  res/pjproject/tests/pjsua/README.TXT (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/README.TXT (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_types.h (added),
+	  res/pjproject/third_party/portaudio/include/pa_mac_core.h
+	  (added), res/pjproject/pjsip/build/wince-evc4/pjsip_wince.vcw
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py
+	  (added), res/pjproject/pjlib/src/pj/log.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-mwi-0.xml (added),
+	  res/pjproject/pjsip/src/pjsip-ua (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm5-release-defaults.vsprops
+	  (added), res/pjproject/pjmedia/src/pjmedia/silencedet.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/301_srtp0_recv_avp.py
+	  (added), res/pjproject/pjmedia/include/pjmedia/vid_port.h
+	  (added), res/pjproject/third_party/gsm/inc/proto.h (added),
+	  res/pjproject/third_party/speex/libspeex/filters.c (added),
+	  res/pjproject/third_party/build/milenage/libmilenage.vcproj
+	  (added), res/pjproject/third_party/srtp/crypto/include/stat.h
+	  (added), res/pjproject/third_party/speex/libspeex/filters.h
+	  (added), res/pjproject/third_party/build/resample/libresample.vcp
+	  (added), res/pjproject/third_party/gsm/COPYRIGHT (added),
+	  res/pjproject/third_party/portaudio/include/pa_linux_alsa.h
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia/transport_adapter_sample.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_gui.loc
+	  (added), res/pjproject/third_party/srtp/include/ut_sim.h (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_im.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/output (added),
+	  res/pjproject/third_party/build/portaudio/libportaudio.vcproj
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/resolver.h
+	  (added), res/pjproject/pjmedia/include/pjmedia/config.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/udp_echo_srv_sync.c (added),
+	  res/pjproject/build.symbian/symbian_audioU.def (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/resolver_test.c
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/passthrough.h
+	  (added), res/pjproject/third_party/portaudio/test (added),
+	  res/pjproject/third_party/srtp/crypto/include/gf2_8.h (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.h (added),
+	  res/pjproject/pjmedia/src/test/vid_port_test.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/online.bmp (added),
+	  res/pjproject/third_party/gsm/inc (added),
+	  res/pjproject/pjlib/include/pj++/os.hpp (added),
+	  res/pjproject/third_party/speex/libspeex/speex_callbacks.c
+	  (added), res/pjproject/pjsip/include/pjsip-ua/sip_inv.h (added),
+	  res/pjproject/config.sub (added),
+	  res/pjproject/pjlib/src/pj/sock_linux_kernel.c (added),
+	  res/pjproject/pjlib/src/pj/sock_select_symbian.cpp (added),
+	  res/pjproject/pjsip/build/wince-evc4/pjsip_core_wince.vcp
+	  (added), res/pjproject/build.symbian/libspeexcodec.mmp (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asihpi/pa_linux_asihpi.c
+	  (added), res/pjproject/pjnath/src/pjturn-client (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/dns_server.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiContainer.cpp
+	  (added), res/pjproject/third_party/BaseClasses (added),
+	  res/pjproject/pjlib/src/pj/guid_simple.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/speex_codec.c (added),
+	  res/pjproject/third_party/BaseClasses/amvideo.cpp (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test (added),
+	  res/pjproject/pjsip/include/pjsip/sip_auth.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/types.h (added),
+	  res/pjproject/third_party/build/samplerate/README.txt (added),
+	  res/pjproject/third_party/gsm/tls/sour2.dta (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-inv-and-ack-without-sdp.xml
+	  (added), res/pjproject/pjmedia/src/pjmedia-codec/ipp_codecs.c
+	  (added), res/pjproject/third_party/g7221/common/config.h (added),
+	  res/pjproject/tests/automated (added),
+	  res/pjproject/pjlib/src/pj/pool_buf.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_0_1.py (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/qt_dev.m (added),
+	  res/pjproject/pjlib/include/pj++/scanner.hpp (added),
+	  res/pjproject/third_party/srtp/pjlib/srtp_err.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/jack (added),
+	  res/pjproject/pjlib-util/build/pjlib_util_test.vcproj (added),
+	  res/pjproject/pjsip/include/pjsip/sip_auth_parser.h (added),
+	  res/pjproject/third_party/speex/include/speex/speex_stereo.h
+	  (added), res/pjproject/third_party/build/portaudio/src (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/200_ice_success_3.py
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua/ua.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/301_timer_good_retry_after_422.py
+	  (added), res/pjproject/pjsip-apps/src/pjsystest/main_wm.c
+	  (added), res/pjproject/pjnath/src/pjnath (added),
+	  res/pjproject/third_party/portaudio/src/os/mac_osx (added),
+	  res/pjproject/third_party/build/srtp/libsrtp.vcproj (added),
+	  res/pjproject/pjsip-apps/bin/samples (added),
+	  res/pjproject/pjlib/include/pj++/sock.hpp (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py
+	  (added), res/pjproject/third_party/speex/libspeex/lsp.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_converters.c
+	  (added), res/pjproject/pjsip-apps/src/samples/stateless_proxy.c
+	  (added), res/pjproject/pjsip/include/pjsip/sip_auth_aka.h
+	  (added), res/pjproject/third_party/speex/libspeex/lsp.h (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_converters.h
+	  (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/main_win32.c
+	  (added), res/pjproject/third_party/speex/libspeex/fftwrap.c
+	  (added), res/pjproject/third_party/build/ilbc/libilbccodec.vcp
+	  (added), res/pjproject/third_party/speex/libspeex/fftwrap.h
+	  (added), res/pjproject/version.mak (added),
+	  res/pjproject/pjlib/build/pjlib_test.vcproj (added),
+	  res/pjproject/pjsip/include/pjsip-simple/mwi.h (added),
+	  res/pjproject/third_party/BaseClasses/amfilter.h (added),
+	  res/pjproject/pjnath/include/pjnath/stun_session.h (added),
+	  res/pjproject/pjsip/include/pjsip-ua/sip_timer.h (added),
+	  res/pjproject/pjmedia/src/test/codec_vectors.c (added),
+	  res/pjproject/third_party/srtp/crypto/test/stat_driver.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/ipjsua.xcodeproj/project.pbxproj
+	  (added), res/pjproject/pjlib/src/pj/os_core_linux_kernel.c
+	  (added),
+	  res/pjproject/pjmedia/build/wince-evc4/pjmedia_auddev_wince.vcp
+	  (added), res/pjproject/third_party/srtp/test/rdbx_driver.c
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_echo.h
+	  (added), res/pjproject/third_party/srtp/include/rtp.h (added),
+	  res/pjproject/pjlib/src/pj/pool_policy_malloc.c (added),
+	  res/pjproject/third_party/gsm/man/gsm_explode.3 (added),
+	  res/pjproject/pjsip/include/pjsip/sip_transport_udp.h (added),
+	  res/pjproject/pjlib/src/pj/file_access_win32.c (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.ico (added),
+	  res/pjproject/build.symbian/symsndtest.mmp (added),
+	  res/pjproject/pjmedia/build/wince-evc4/output (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py
+	  (added), res/pjproject/pjsip-apps/src/vidgui/vidgui.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/Symbian_ua_guiSettingItemListSets.cpp
+	  (added), res/pjproject/pjmedia/include/pjmedia/delaybuf.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/157_err_sdp_bad_addr_type.py
+	  (added), res/pjproject/build.symbian/pjlib_test.mmp (added),
+	  res/pjproject/pjsip/src/pjsip/sip_transport.c (added),
+	  res/pjproject/third_party/srtp/crypto/test/env.c (added),
+	  res/pjproject/third_party/speex/libspeex/scal.c (added),
+	  res/pjproject/pjlib/include/pj/pool.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/wav_port.h (added),
+	  res/pjproject/pjsip/include/pjsip-simple/errno.h (added),
+	  res/pjproject/third_party/speex/libspeex/filters_sse.h (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml
+	  (added), res/pjproject/pjsip-apps/src/samples/latency.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/400_tel_uri.py (added),
+	  res/pjproject/third_party/portaudio/pablio/test_w_saw.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_allocation.c
+	  (added), res/pjproject/pjnath/src/pjnath-test (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/400_fmtp_g7221_with_bitrate.py
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_allocation.h
+	  (added), res/pjproject/pjmedia/include/pjmedia/format.h (added),
+	  res/pjproject/third_party/gsm/inc/private.h (added),
+	  res/pjproject/third_party/srtp/crypto/replay (added),
+	  res/pjproject/third_party/speex/libspeex/stack_alloc.h (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/300_timer_good.py
+	  (added), res/pjproject/pjsip/src/pjsua-lib/pjsua_aud.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/file.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_blocking.c
+	  (added), res/pjproject/build.symbian/pjsipU.def (added),
+	  res/pjproject/pjlib/bin (added),
+	  res/pjproject/third_party/ilbc/hpInput.c (added),
+	  res/pjproject/pjsip-apps/build/python_pjsua.vcproj (added),
+	  res/pjproject/build.mak.in (added),
+	  res/pjproject/third_party/srtp/crypto/cipher (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_blocking.h
+	  (added), res/pjproject/third_party/srtp/crypto/rng/rand_source.c
+	  (added), res/pjproject/pjsip-apps/build/sample_debug.vcproj
+	  (added), res/pjproject/third_party/ilbc/hpInput.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/sdp_cmp.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/305_ice_comp_1_2.py
+	  (added), res/pjproject/pjmedia/include/pjmedia/sdp.h (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/pjsystest_wince.rc
+	  (added), res/pjproject/tests/pjsua/scripts-sipp/strict-route.xml
+	  (added), res/pjproject/pjmedia/build/os-rtems.mak (added),
+	  res/pjproject/pjsip/build/wince-evc4/test_pjsip_wince.vcp
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_callbacks.h
+	  (added), res/pjproject/pjsip-apps/src/pjsua_wince/StdAfx.cpp
+	  (added), res/pjproject/third_party/srtp/include/rtp_priv.h
+	  (added), res/pjproject/third_party/build/resample (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-early-bye.xml (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/323_srtp2_unsupported_crypto.py
+	  (added), res/pjproject/build.symbian/symbian_ua.pkg (added),
+	  res/pjproject/tests/pjsua/mod_media_playrec.py (added),
+	  res/pjproject/pjnath/build/pjnath.vcproj (added),
+	  res/pjproject/third_party/speex/libspeex/fixed_generic.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_multipart.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/200_tcp.py (added),
+	  res/pjproject/pjsip/build (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/output (added),
+	  res/pjproject/third_party/g7221/encode/encoder.c (added),
+	  res/pjproject/pjsip-apps/src/vidgui/vidgui.pro (added),
+	  res/pjproject/third_party/srtp/tables (added),
+	  res/pjproject/tests/pjsua/mod_recvfrom.py (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/171_timer_initiated_by_uas.py
+	  (added), res/pjproject/pjsip/include/pjsip-ua (added),
+	  res/pjproject/build.symbian/pjsdpU.def (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_front.c
+	  (added), res/pjproject/pjmedia/src/pjmedia/event.c (added),
+	  res/pjproject/build/m-mpc860.mak (added),
+	  res/pjproject/pjlib/src/pj/os_error_unix.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/sis/symbian_ua_gui.pkg
+	  (added), res/pjproject/pjnath/src/pjturn-srv/listener_tcp.c
+	  (added), res/pjproject/pjsip/src/pjsip/sip_transport_loop.c
+	  (added), res/pjproject/pjmedia/src/pjmedia-videodev/v4l2_dev.c
+	  (added), res/pjproject/pjsip-apps/src/samples/util.h (added),
+	  res/pjproject/third_party/speex/libspeex/ltp_sse.h (added),
+	  res/pjproject/third_party/gsm/tls/sour.c (added),
+	  res/pjproject/pjlib/build/pjlib_samples.mak (added),
+	  res/pjproject/pjlib-util/build/os-rtems.mak (added),
+	  res/pjproject/pjsip/bin (added),
+	  res/pjproject/pjlib/src/pj/os_rwmutex.c (added),
+	  res/pjproject/pjlib/src/pj/guid_uuid.c (added),
+	  res/pjproject/third_party/speex/libspeex/ltp_arm4.h (added),
+	  res/pjproject/pjlib/include/pj/sock_qos.h (added),
+	  res/pjproject/third_party/speex/libspeex/testenc_wb.c (added),
+	  res/pjproject/third_party/portaudio/pablio/pablio.def (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/362_non_sip_uri.py
+	  (added), res/pjproject/pjmedia/include/pjmedia_audiodev.h
+	  (added), res/pjproject/pjsip-apps/build/libpjproject.vcproj
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/res/action.bmp
+	  (added), res/pjproject/pjsip/include/pjsip-simple/publish.h
+	  (added), res/pjproject/pjlib/src/pj/pool_policy_new.cpp (added),
+	  res/pjproject/third_party/gsm/man/bitter.1 (added),
+	  res/pjproject/tests/cdash (added),
+	  res/pjproject/pjmedia/build/os-darwinos.mak (added),
+	  res/pjproject/build/os-linux.mak (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiSettingItemList.cpp
+	  (added), res/pjproject/pjmedia/src/pjmedia/conf_switch.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiAppUi.h
+	  (added), res/pjproject/pjlib/include/pj/timer.h (added),
+	  res/pjproject/pjlib/build/os-linux-kernel.mak (added),
+	  res/pjproject/third_party/speex/libspeex/exc_10_32_table.c
+	  (added), res/pjproject/third_party/srtp/crypto/include/alloc.h
+	  (added), res/pjproject/third_party/speex/libspeex/hexc_table.c
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_resampler.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_1.py
+	  (added), res/pjproject/pjlib/src/pj/sock_select.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/vid_port.c (added),
+	  res/pjproject/third_party/build/baseclasses/output (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/offline.ico (added),
+	  res/pjproject/pjsip-apps/src/samples/siprtp.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.vcc (added),
+	  res/pjproject/pjsip-apps (added),
+	  res/pjproject/pjmedia/include/pjmedia/sound_port.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJDlg.h (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_2_1.py (added),
+	  res/pjproject/third_party/srtp/crypto/include/integers.h (added),
+	  res/pjproject/third_party/srtp/crypto/kernel/alloc.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.vcp (added),
+	  res/pjproject/pjlib-util/docs (added),
+	  res/pjproject/third_party/srtp/crypto/include/null_auth.h
+	  (added), res/pjproject/third_party/build/speex/config.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.vcw (added),
+	  res/pjproject/third_party/portaudio/index.html (added),
+	  res/pjproject/pjmedia/build/wince-evc4 (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_util.c
+	  (added), res/pjproject/pjsip/include/pjsip/sip_transport_loop.h
+	  (added), res/pjproject/pjlib/docs/header.html (added),
+	  res/pjproject/third_party/build/samplerate (added),
+	  res/pjproject/third_party/gsm/bin (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/main.m (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_1_3.py (added),
+	  res/pjproject/pjsip-apps/src/samples/sipecho.c (added),
+	  res/pjproject/tests (added),
+	  res/pjproject/tests/pjsua/scripts-call/350_prack_a.py (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_allocation.c
+	  (added), res/pjproject/third_party/srtp/timing (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_allocation.h
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_skeleton.c
+	  (added), res/pjproject/pjlib-util/src/pjlib-util-test/xml.c
+	  (added), res/pjproject/third_party/portaudio/src/hostapi/alsa
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h
+	  (added), res/pjproject/pjlib/include (added),
+	  res/pjproject/tests/cdash/cfg_gnu.py (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/Makefile (added),
+	  res/pjproject/third_party/build (added),
+	  res/pjproject/third_party (added),
+	  res/pjproject/pjnath/include/pjnath/stun_sock.h (added),
+	  res/pjproject/third_party/srtp/crypto/math (added),
+	  res/pjproject/third_party/srtp/crypto/test/kernel_driver.c
+	  (added), res/pjproject/pjlib/include/pj/string_i.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/bidirectional.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/conference.h (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py
+	  (added), res/pjproject/pjlib-util/docs/footer.html (added),
+	  res/pjproject/third_party/README.txt (added),
+	  res/pjproject/third_party/srtp/crypto/hash/auth.c (added),
+	  res/pjproject/pjsip-apps/src/python/pjsua.py (added),
+	  res/pjproject/pjmedia/build/pjmedia_videodev.vcproj (added),
+	  res/pjproject/third_party/portaudio/missing (added),
+	  res/pjproject/third_party/srtp/crypto/cipher/aes_cbc.c (added),
+	  res/pjproject/pjsip/src/pjsip-simple/presence.c (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_l16_16000.py
+	  (added), res/pjproject/pjlib/include/pj/sock.h (added),
+	  res/pjproject/pjlib/include/pj++/pool.hpp (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_stream.c
+	  (added), res/pjproject/pjlib/include/pj++ (added),
+	  res/pjproject/pjlib/src/pj/ssl_sock_symbian.cpp (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_stream.h
+	  (added), res/pjproject/third_party/speex/libspeex/vq_arm4.h
+	  (added),
+	  res/pjproject/third_party/portaudio/src/os/unix/pa_unix_hostapis.c
+	  (added), res/pjproject/pjlib/include/pj/ip_helper.h (added),
+	  res/pjproject/tests/pjsua/inc_const.py (added),
+	  res/pjproject/third_party/speex/libspeex/gain_table_lbr.c
+	  (added), res/pjproject/tests/pjsua/scripts-pesq/201_codec_ilbc.py
+	  (added), res/pjproject/build/os-auto.mak.in (added),
+	  res/pjproject/pjsip-apps/src/3rdparty_media_sample/Makefile
+	  (added), res/pjproject/pjnath/build/pjturn_client.vcproj (added),
+	  res/pjproject/third_party/speex/libspeex/filters_arm4.h (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-timer-reinvite.xml
+	  (added), res/pjproject/pjlib/src/pjlib-test/exception_wrap.cpp
+	  (added), res/pjproject/third_party/gsm/src/rpe.c (added),
+	  res/pjproject/third_party/portaudio/build/msvc/portaudio.vcproj
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_1.py
+	  (added), res/pjproject/third_party/build/portaudio/os-linux.mak
+	  (added), res/pjproject/pjsip/include/pjsip-simple (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/amr_helper.h (added),
+	  res/pjproject/third_party/build/srtp/libsrtp.vcp (added),
+	  res/pjproject/third_party/speex/libspeex/_kiss_fft_guts.h
+	  (added), res/pjproject/pjlib-util/src/pjlib-util-test/test.c
+	  (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_process.c
+	  (added), res/pjproject/pjlib/include/pj/compat/socket.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/ios_dev.m (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/test.h (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_process.h
+	  (added), res/pjproject/tests/pjsua/wavs (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes (added),
+	  res/pjproject/third_party/build/Makefile (added),
+	  res/pjproject/pjmedia/src/pjmedia/vid_tee.c (added),
+	  res/pjproject/third_party/speex/libspeex/jitter.c (added),
+	  res/pjproject/build.symbian/null_audioU.def (added),
+	  res/pjproject/pjlib/src/pj/sock_qos_dummy.c (added),
+	  res/pjproject/pjlib/build/wince-evc4/pjlib_test_wince.vcp
+	  (added), res/pjproject/third_party/portaudio/include/pa_asio.h
+	  (added), res/pjproject/third_party/srtp/CHANGES (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/MainWindow.xib (added),
+	  res/pjproject/pjlib/src/pj/os_core_symbian.cpp (added),
+	  res/pjproject/pjlib/src/pj/os_error_symbian.cpp (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev/config.h (added),
+	  res/pjproject/pjsip-apps/src/pjsua (added),
+	  res/pjproject/pjlib/include/pj/doxygen.h (added),
+	  res/pjproject/third_party/srtp/crypto/hash/null_auth.c (added),
+	  res/pjproject/third_party/resample (added),
+	  res/pjproject/pjlib/src/pj/rand.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/resample_libsamplerate.c
+	  (added), res/pjproject/pjmedia/src/pjmedia/resample_speex.c
+	  (added), res/pjproject/third_party/portaudio/portaudio-2.0.pc.in
+	  (added), res/pjproject/COPYING (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_2.py
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp
+	  (added), res/pjproject/pjnath/src/pjnath/stun_session.c (added),
+	  res/pjproject/third_party/portaudio/src/SConscript (added),
+	  res/pjproject/pjsip/include/pjsua.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group/bld.inf
+	  (added), res/pjproject/pjsip/src/test/main_win32.c (added),
+	  res/pjproject/pjlib/include/pj/compat/os_auto.h.in (added),
+	  res/pjproject/pjsip-apps/build/output (added),
+	  res/pjproject/pjsip-apps/src/samples/footprint.c (added),
+	  res/pjproject/pjlib/src/pj/string.c (added),
+	  res/pjproject/pjnath/include/pjnath (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wdmks/readme.txt
+	  (added), res/pjproject/third_party/speex/libspeex/preprocess.c
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiApplication.cpp
+	  (added),
+	  res/pjproject/third_party/build/resample/libresample.vcproj
+	  (added), res/pjproject/third_party/gsm/tst/cod2txt.c (added),
+	  res/pjproject/pjlib/src/pj/symbols.c (added),
+	  res/pjproject/third_party/portaudio/include/pa_win_ds.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/oss/low_latency_tip.txt
+	  (added), res/pjproject/third_party/build/resample/Makefile
+	  (added), res/pjproject/pjmedia/src/test/vid_codec_test.c (added),
+	  res/pjproject/pjsip-apps/src/python/samples/simplecall.py
+	  (added), res/pjproject/pjnath/include/pjnath.h (added),
+	  res/pjproject/third_party/portaudio/build/scons (added),
+	  res/pjproject/pjmedia/src/pjmedia/delaybuf.c (added),
+	  res/pjproject/third_party/portaudio/bindings (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_speex_16000.py
+	  (added), res/pjproject/pjnath/src/pjnath-test/main_win32.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/322_srtp2_recv_savp.py
+	  (added), res/pjproject/third_party/srtp/crypto/cipher/aes.c
+	  (added), res/pjproject/svn_pset.bat (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml
+	  (added), res/pjproject/pjsip/src/pjsip/sip_auth_parser.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/jack/pa_jack.c
+	  (added), res/pjproject/pjsip/src/pjsip/sip_errno.c (added),
+	  res/pjproject/build.symbian/00.bat (added),
+	  res/pjproject/tests/cdash/starttest_sample.bat (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/sha1.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/Symbian_ua_guiSettingItemListSettings.h
+	  (added), res/pjproject/pjsip/src/pjsip/sip_auth_client.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_2.py
+	  (added), res/pjproject/pjlib/src/pj/os_time_win32.c (added),
+	  res/pjproject/build/vs/pjproject-vs8-win32-release-defaults.vsprops
+	  (added), res/pjproject/third_party/resample/src/libresample_dll.c
+	  (added), res/pjproject/third_party/g7221/decode/decoder.c
+	  (added), res/pjproject/third_party/srtp/crypto/cipher/cipher.c
+	  (added), res/pjproject/pjlib/include/pj/unicode.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx/mark_icon.bmp
+	  (added), res/pjproject/tests/pjsua/scripts-pesq/201_codec_gsm.py
+	  (added), res/pjproject/third_party/speex (added),
+	  res/pjproject/tests/pjsua/scripts-run/100_simple.py (added),
+	  res/pjproject/pjmedia/src/test/sdp_neg_test.c (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_8_22.py
+	  (added), res/pjproject/third_party/BaseClasses/combase.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/ipjsuaAppDelegate.h
+	  (added),
+	  res/pjproject/third_party/build/speex/speex/speex_config_types.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/ipjsuaAppDelegate.m
+	  (added), res/pjproject/pjsip/src/pjsip-simple (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/ffmpeg_vid_codecs.c
+	  (added), res/pjproject/build.symbian/pjsua_lib.mmp (added),
+	  res/pjproject/pjsip-apps/src/python/samples/registration.py
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/config.h
+	  (added), res/pjproject/pjsip/build/pjsip_test.vcproj (added),
+	  res/pjproject/pjnath/src/pjnath-test/main.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/base64.c (added),
+	  res/pjproject/pjsip-apps/src/samples/strerror.c (added),
+	  res/pjproject/third_party/mp3/BladeMP3EncDLL.h (added),
+	  res/pjproject/third_party/portaudio/fixdir.bat (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_common_abs.c (added),
+	  res/pjproject/third_party/srtp/crypto/kernel/key.c (added),
+	  res/pjproject/pjsip-apps/build/samples.vcproj (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_common_abs.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/stream_info.c (added),
+	  res/pjproject/third_party/BaseClasses/mtype.cpp (added),
+	  res/pjproject/third_party/BaseClasses/seekpt.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/sdl_dev_m.m (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-mwi.xml (added),
+	  res/pjproject/third_party/srtp/VERSION (added),
+	  res/pjproject/pjmedia/src/pjmedia/null_port.c (added),
+	  res/pjproject/pjlib/src/pj/ssl_sock_common.c (added),
+	  res/pjproject/third_party/portaudio/README.txt (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/152_err_sdp_no_media.py
+	  (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/coreaudio/notes.txt
+	  (added), res/pjproject/third_party/srtp/crypto/include/cipher.h
+	  (added), res/pjproject/pjmedia/src/pjmedia-codec/g722.c (added),
+	  res/pjproject/third_party/srtp/doc (added),
+	  res/pjproject/third_party/srtp/crypto/kernel/err.c (added),
+	  res/pjproject/third_party/build/gsm/libgsmcodec.vcproj (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_3_3.py (added),
+	  res/pjproject/pjsip/src/pjsua-lib (added),
+	  res/pjproject/pjnath/src/pjnath-test/server.c (added),
+	  res/pjproject/pjsip/build/os-rtems.mak (added),
+	  res/pjproject/pjmedia/src/pjmedia/resample_port.c (added),
+	  res/pjproject/pjsip-apps/src/samples/playfile.c (added),
+	  res/pjproject/pjnath/src/pjnath-test/server.h (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm6-release-defaults.vsprops
+	  (added), res/pjproject/pjmedia/src/pjmedia-audiodev/errno.c
+	  (added), res/pjproject/third_party/resample/src/resamplesubs.c
+	  (added), res/pjproject/third_party/ilbc/StateSearchW.c (added),
+	  res/pjproject/third_party/build/os-win32.mak (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_speex_8000.py
+	  (added),
+	  res/pjproject/third_party/build/portaudio/libportaudio.vcp
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_unix_hostapis.c
+	  (added), res/pjproject/third_party/ilbc/StateSearchW.h (added),
+	  res/pjproject/build/m-m68k.mak (added),
+	  res/pjproject/pjsip-apps/src/python/setup.py (added),
+	  res/pjproject/tests/automated/gnu.xml.template (added),
+	  res/pjproject/pjlib/include/pj/file_io.h (added),
+	  res/pjproject/pjsip-apps/src/samples/confsample.c (added),
+	  res/pjproject/pjsip/include/pjsip/sip_parser.h (added),
+	  res/pjproject/third_party/speex/libspeex/vq.c (added),
+	  res/pjproject/build (added),
+	  res/pjproject/third_party/speex/include (added),
+	  res/pjproject/pjnath/src/pjnath-test/turn_sock_test.c (added),
+	  res/pjproject/third_party/speex/libspeex/vq.h (added),
+	  res/pjproject/third_party/portaudio/src/os/win (added),
+	  res/pjproject/pjsip/include/pjsip/sip_auth_msg.h (added),
+	  configs/rtp.conf.sample,
+	  res/pjproject/pjsip/src/pjsip/sip_transport_tls.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/PocketPJ.ico (added),
+	  res/pjproject/Makefile (added),
+	  res/pjproject/third_party/srtp/crypto/test/rand_gen.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src/symbian_ua_guiSettingItemListView.cpp
+	  (added), res/pjproject/third_party/g7221/decode/dct4_s.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_3.py
+	  (added), res/pjproject/build.symbian/pjmedia_audiodev.mmp
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/201_ice_mismatch_1.py
+	  (added), res/pjproject/third_party/srtp/crypto/include (added),
+	  res/pjproject/third_party/g7221/decode/dct4_s.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/timestamp.c (added),
+	  res/pjproject/third_party/speex/libspeex (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/ipjsua_Prefix.pch (added),
+	  res/pjproject/pjlib/include/pj/compat/os_darwinos.h (added),
+	  res/pjproject/pjlib/src/pj/os_info_symbian.cpp (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_duplicated_crypto_tag.py
+	  (added), res/pjproject/pjlib-util/include/pjlib-util/xml.h
+	  (added), res/pjproject/third_party/srtp/test (added),
+	  res/pjproject/third_party/srtp/test/rtpw_test.sh (added),
+	  res/pjproject/third_party/speex/libspeex/exc_10_16_table.c
+	  (added), res/pjproject/third_party/BaseClasses/measure.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/plc.h (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_core.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/dns.h (added),
+	  res/pjproject/pjsip/include/pjsip-simple/xpidf.h (added),
+	  res/pjproject/pjlib/src/pj/sock_qos_symbian.cpp (added),
+	  res/pjproject/third_party/srtp/TODO (added),
+	  res/pjproject/tests/pjsua/inc_sdp.py (added),
+	  res/pjproject/pjnath/src/pjnath/stun_auth.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/ipjsystestAppDelegate.h
+	  (added), res/pjproject/pjmedia/src (added),
+	  res/pjproject/tests/pjsua/scripts-pres/200_publish.py (added),
+	  res/pjproject/pjsip/src/test/main.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/ipjsystestAppDelegate.m
+	  (added), res/pjproject/pjlib/src/pj/extra-exports.c (added),
+	  res/pjproject/tests/pjsua/scripts-run (added),
+	  res/pjproject/pjmedia/src/pjmedia/transport_loop.c (added),
+	  res/pjproject/third_party/portaudio/Makefile.in (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/errno.c (added),
+	  res/pjproject/pjlib/src/pj/os_time_unix.c (added),
+	  res/pjproject/pjlib/src/pj/types.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/g7221_sdp_match.h
+	  (added), res/pjproject/pjmedia/src/pjmedia-codec/opencore_amrnb.c
+	  (added), res/pjproject/third_party/lib (added),
+	  res/pjproject/pjsip/src/pjsip/sip_config.c (added),
+	  res/pjproject/pjsip/include/pjsua-lib/pjsua.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiSettingItemListView.h
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/ReadMe.txt
+	  (added), res/pjproject/pjmedia/include/pjmedia-codec/l16.h
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiSettingItemList.h
+	  (added), res/pjproject/third_party/BaseClasses/wxdebug.h (added),
+	  res/pjproject/third_party/g7221/decode (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_l16_16000.py
+	  (added), res/pjproject/tests/pjsua/scripts-sendto/110_tel_uri.py
+	  (added), res/pjproject/build/os-palmos.mak (added),
+	  res/pjproject/pjmedia/src/pjmedia/vid_stream.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx/list_icon.bmp
+	  (added), res/pjproject/pjlib/src/pjlib++-test/main.cpp (added),
+	  res/pjproject/pjlib/include/pj/array.h (added),
+	  res/pjproject/pjlib/src/pj/log_writer_symbian_console.cpp
+	  (added), res/pjproject/pjmedia/build/m-x86_64.mak (added),
+	  res/pjproject/pjsip-apps/src/samples/level.c (added),
+	  res/pjproject/pjnath/src/pjnath/ice_strans.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/activesock.c (added),
+	  res/pjproject/build.symbian/pjsip_simple.mmp (added),
+	  res/pjproject/pjlib/include/pj/string.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/blank.bmp (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/gui.h (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/101_defaults.py (added),
+	  res/pjproject/tests/cdash/builder.py (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/StdAfx.h (added),
+	  res/pjproject/pjlib/include/pj/pool_i.h (added),
+	  res/pjproject/build.symbian/libgsmcodec.mmp (added),
+	  res/res_rtp_asterisk.c,
+	  res/pjproject/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_2.py
+	  (added), res/pjproject/third_party/BaseClasses/amfilter.cpp
+	  (added), res/pjproject/build/m-auto.mak (added),
+	  res/pjproject/build/os-darwinos.mak (added),
+	  res/pjproject/pjmedia/include/pjmedia/echo_port.h (added),
+	  res/pjproject/third_party/BaseClasses/renbase.cpp (added),
+	  res/pjproject/third_party/g7221/common/huff_tab.c (added),
+	  res/pjproject/third_party/gsm/src/toast_lin.c (added),
+	  res/pjproject/third_party/srtp/crypto/hash (added),
+	  res/pjproject/third_party/g7221/common/huff_tab.h (added),
+	  res/pjproject/pjnath/src/pjnath/nat_detect.c (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom (added),
+	  res/pjproject/pjlib/build/pjlib.vcproj (added),
+	  res/pjproject/pjsip/build/wince-evc4/pjsip_simple_wince.vcp
+	  (added), res/pjproject/build.symbian/pjsip_ua.mmp (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/RootViewController.h
+	  (added), res/pjproject/third_party/mp3/mp3_writer.c (added),
+	  res/pjproject/third_party/ilbc/getCBvec.c (added),
+	  res/pjproject/user.mak.sample (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/StdAfx.cpp (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/Classes/RootViewController.m
+	  (added), res/pjproject/third_party/ilbc/getCBvec.h (added),
+	  res/pjproject/pjlib/include/pj++/types.hpp (added),
+	  res/pjproject/pjlib/src/pjlib-test/ioq_unreg.c (added),
+	  res/pjproject/third_party/resample/src/largefilter.h (added),
+	  res/pjproject/third_party/build/gsm/output (added),
+	  res/pjproject/pjmedia/include/pjmedia/errno.h (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec (added),
+	  res/pjproject/third_party/gsm/src/toast.c (added),
+	  res/pjproject/pjmedia/src/test/session_test.c (added),
+	  res/pjproject/pjmedia/build/pjmedia_test.vcproj (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/md5.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/clock.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/splitcomb.h (added),
+	  res/pjproject/third_party/srtp/crypto/test/aes_calc.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/gsm.h (added),
+	  res/pjproject/pjnath/bin (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/dshowclasses.cpp
+	  (added), res/pjproject/pjsip-apps/build/Samples.mak (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiSettingItemList.loc
+	  (added), res/pjproject/pjmedia/src/pjmedia/converter.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-videodev/videodev.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-videodev (added),
+	  res/pjproject/third_party/ilbc/hpOutput.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/sis/symbian_ua_gui.txt
+	  (added), res/pjproject/third_party/portaudio/pablio/README.txt
+	  (added), res/pjproject/third_party/ilbc/hpOutput.h (added),
+	  res/pjproject/third_party/gsm/tls/bitter.dta (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-template.xml (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/200_ice_success_2.py
+	  (added), res/pjproject/third_party/speex/libspeex/lpc.c (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_32.py
+	  (added), res/pjproject/third_party/build/gsm/Makefile (added),
+	  res/pjproject/build.symbian/pjmediaU.def (added),
+	  res/pjproject/third_party/speex/libspeex/lpc.h (added),
+	  res/pjproject/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
+	  (added),
+	  res/pjproject/pjsip-apps/src/ipjsystest/ipjsystest-Info.plist
+	  (added), res/pjproject/pjlib/src/pjlib-test/select.c (added),
+	  res/pjproject/pjmedia/include/pjmedia (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py
+	  (added), res/pjproject/third_party/g7221/common/typedef.h
+	  (added), res/pjproject/third_party/ilbc/iLBC_encode.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/config.h (added),
+	  res/pjproject/pjlib/src/pj/compat/string_compat.c (added),
+	  res/pjproject/pjsip-apps/build/vidgui.vcproj (added),
+	  res/pjproject/third_party/ilbc/iLBC_encode.h (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/pjsua.py (added),
+	  res/pjproject/third_party/gsm/INSTALL (added),
+	  res/pjproject/pjlib/src/pjlib-test/ioq_udp.c (added),
+	  res/pjproject/pjlib/build/os-win32.mak (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_gui.pan
+	  (added), res/pjproject/pjlib/src/pjlib-test/main_win32.c (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_ilbc.py (added),
+	  res/pjproject/pjlib/src/pj/os_time_linux_kernel.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_32000.py
+	  (added), res/pjproject/pjsip/include/pjsip/sip_tel_uri.h (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_memorybarrier.h
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/h264_packetizer.c
+	  (added), res/pjproject/pjmedia/src/pjmedia (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/invisibl.ico (added),
+	  res/pjproject/pjmedia/include/pjmedia/wsola.h (added),
+	  res/pjproject/third_party/build/portaudio/src/portaudio.h
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp
+	  (added), res/pjproject/third_party/speex/libspeex/buffer.c
+	  (added), res/pjproject/pjsip-apps/src/samples/debug.c (added),
+	  res/pjproject/third_party/srtp/crypto/include/crypto.h (added),
+	  res/pjproject/pjsip/src/test (added),
+	  res/pjproject/pjlib/src/pj/os_core_win32.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_gui.hrh
+	  (added), res/pjproject/pjmedia/src/pjmedia/types.c (added),
+	  res/pjproject/pjsip/src/pjsip/sip_tel_uri.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/252_multipart_ok_clutter.py
+	  (added), res/pjproject/third_party/gsm/src/code.c (added),
+	  main/rtp_engine.c, res/pjproject/pjsip-apps/src/samples/icedemo.c
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_cpuload.c
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/include/rand_source.h
+	  (added), res/pjproject/third_party/portaudio/include/portaudio.h
+	  (added), res/pjproject/pjmedia/lib (added),
+	  res/pjproject/pjsip-apps/src/samples/pjsip-perf.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_cpuload.h
+	  (added), res/pjproject/third_party/build/srtp/srtp_config.h
+	  (added), res/pjproject/tests/cdash/inc_test.py (added),
+	  res/pjproject/pjnath/include/pjnath/types.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wdmks/pa_win_wdmks.c
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp
+	  (added), res/pjproject/pjlib/src/pj/list.c (added),
+	  res/pjproject/pjsip-apps/src/python (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core.c
+	  (added), res/pjproject/pjsip-apps/src/confbot/config.py (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core.h
+	  (added), res/pjproject/third_party/build/os-darwinos.mak (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/151_err_sdp_video.py
+	  (added), res/pjproject/third_party/srtp/crypto/test/sha1_driver.c
+	  (added), res/pjproject/third_party/ilbc/filter.c (added),
+	  res/pjproject/third_party/speex/libspeex/testjitter.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/StdAfx.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.vcproj (added),
+	  res/pjproject/third_party/ilbc/filter.h (added),
+	  res/pjproject/third_party/speex/libspeex/cb_search_bfin.h
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_16.py
+	  (added), res/pjproject/pjsip-apps/src/ipjsua/SecondView.xib
+	  (added), res/pjproject/third_party/ilbc/StateConstructW.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.xml
+	  (added), res/pjproject/pjlib-util/src/pjlib-util/stun_simple.c
+	  (added), res/pjproject/configure-iphone (added),
+	  res/pjproject/pjlib/include/pj/fifobuf.h (added),
+	  res/pjproject/third_party/ilbc/StateConstructW.h (added),
+	  res/pjproject/pjsip/include (added),
+	  res/pjproject/third_party/gsm/src/decode.c (added),
+	  res/pjproject/build.symbian/symbian_ua.mmp (added),
+	  res/pjproject/pjsip/include/pjsip/sip_event.h (added),
+	  res/pjproject/third_party/srtp/crypto/math/gf2_8.c (added),
+	  res/pjproject/third_party/g7221/common (added),
+	  res/pjproject/third_party/gsm/MANIFEST (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiApplication.h
+	  (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_x86_plain_converters.c
+	  (added), res/pjproject/pjlib/src/pjlib-samples (added),
+	  res/pjproject/pjnath/src/pjnath-test/sess_auth.c (added),
+	  res/pjproject/build/os-sunos.mak (added),
+	  res/pjproject/third_party/portaudio/src/os/win/pa_x86_plain_converters.h
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_win_hostapis.c
+	  (added), res/pjproject/pjsip-apps/src/python/_pjsua.c (added),
+	  res/pjproject/svn_pset (added),
+	  res/pjproject/pjmedia/src/pjmedia/vid_stream_info.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/wav_player.c (added),
+	  res/pjproject/pjsip-apps/src/python/_pjsua.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/251_multipart_ok_simple.py
+	  (added), res/pjproject/third_party/gsm/tls/ginger.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_trace.c
+	  (added), res/pjproject/third_party/build/os-linux.mak (added),
+	  res/pjproject/third_party/speex/libspeex/mdf.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_trace.h
+	  (added), res/pjproject/pjsip-apps/src/samples/encdec.c (added),
+	  res/pjproject/pjmedia/README.txt (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_gui_reg.loc
+	  (added), res/pjproject/build/vs (added),
+	  res/pjproject/pjmedia/src/pjmedia/mem_capture.c (added),
+	  res/pjproject/pjsip-apps/src/py_pjsua/helper.mak (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_l16_16000_stereo.py
+	  (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp
+	  (added), res/pjproject/pjmedia/include/pjmedia/alaw_ulaw.h
+	  (added), res/pjproject/pjsip-apps/src/pjsystest/main_console.c
+	  (added), res/pjproject/pjsip/build/pjsip_simple.vcproj (added),
+	  res/pjproject/pjlib/src/pj/os_info_iphone.m (added),
+	  res/pjproject/pjmedia/src/pjmedia-audiodev/legacy_dev.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/TabBarController.h
+	  (added), res/pjproject/pjsip/include/pjsip-simple/pidf.h (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj
+	  (added), res/pjproject/pjlib-util/docs/header.html (added),
+	  res/pjproject/third_party/ilbc/constants.c (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Classes/TabBarController.m
+	  (added), res/pjproject/build.symbian (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/getopt.h (added),
+	  res/pjproject/third_party/ilbc/constants.h (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_unix_util.c
+	  (added), res/pjproject/pjmedia/include/pjmedia/transport_ice.h
+	  (added), res/pjproject/third_party/build/g7221/Makefile (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx/list_icon_mask.bmp
+	  (added), res/pjproject/pjmedia/include/pjmedia/vid_tee.h (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_unix_util.h
+	  (added), res/pjproject/pjmedia/src/pjmedia-videodev/dshow_dev.c
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/res/offline.bmp
+	  (added), res/pjproject/pjlib/src/pj/log_writer_printk.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_types.h
+	  (added), res/pjproject/pjsip/src/pjsip-simple/pidf.c (added),
+	  res/pjproject/third_party/portaudio/pablio/test_w_saw8.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/300_ice_1_1.py (added),
+	  res/pjproject/pjsip-apps/src/samples/aviplay.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/331_srtp_prefer_rtp_avp.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/400_inv_answered_with_less_media.py
+	  (added), res/pjproject/pjsip/src/pjsip/sip_auth_aka.c (added),
+	  res/pjproject/build.symbian/bld.inf (added),
+	  res/pjproject/third_party/srtp/crypto/Makefile (added),
+	  res/pjproject/third_party/speex/libspeex/kiss_fft.c (added),
+	  res/pjproject/pjlib/src/pj/compat (added),
+	  res/pjproject/third_party/speex/libspeex/kiss_fft.h (added),
+	  res/pjproject/pjnath/include/pjnath/turn_sock.h (added),
+	  res/pjproject/third_party/g7221/common/defs.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiContainer.loc
+	  (added), res/pjproject/third_party/g7221/decode/coef2sam.c
+	  (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_hostapis.c
+	  (added), res/pjproject/pjlib/include/pj/hash.h (added),
+	  res/pjproject/pjlib/include/pj/compat/assert.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/sdp_neg.c (added),
+	  res/pjproject/pjnath/src/pjturn-srv/main.c (added),
+	  res/pjproject/third_party/srtp/crypto/test/datatypes_driver.c
+	  (added), res/pjproject/pjmedia/include/pjmedia/silencedet.h
+	  (added), res/pjproject/third_party/srtp/crypto/include/aes_icm.h
+	  (added), res/pjproject/third_party/srtp/crypto/include/auth.h
+	  (added), res/pjproject/third_party/gsm/src/long_term.c (added),
+	  res/pjproject/third_party/ilbc/LPCencode.c (added),
+	  res/pjproject/pjsip/src/pjsip-ua/sip_timer.c (added),
+	  res/pjproject/third_party/gsm/add-test/add_test.dta (added),
+	  res/pjproject/third_party/ilbc/LPCencode.h (added),
+	  res/pjproject/pjlib/src/pj/ip_helper_generic.c (added),
+	  res/pjproject/tests/pjsua/scripts-call/150_srtp_1_2.py (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_44.py
+	  (added), res/pjproject/pjsip-apps/src/py_pjsua/setup.py (added),
+	  res/pjproject/third_party/build/portaudio (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/100_simplecall.py
+	  (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_guiSettingItemList.rssi
+	  (added), res/pjproject/pjlib/src/pjlib-test/pjlib_test_reg.rss
+	  (added), res/pjproject/pjlib/include/pj/compat/cc_gcc.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/vid_codec.h (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas.xml (added),
+	  res/pjproject/pjmedia/src/pjmedia/echo_suppress.c (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_8.py
+	  (added), res/pjproject/pjmedia/src/pjmedia/port.c (added),
+	  res/pjproject/pjlib/src/pj/ioqueue_symbian.cpp (added),
+	  res/pjproject/pjlib/build/cacert.pem (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/gfx/mark_icon_mask.bmp
+	  (added), res/pjproject/third_party/speex/libspeex/filterbank.c
+	  (added), res/pjproject/third_party/gsm/src/gsm_encode.c (added),
+	  res/pjproject/pjsip/src/pjsip-simple/errno.c (added),
+	  res/pjproject/third_party/speex/libspeex/filterbank.h (added),
+	  res/pjproject/third_party/gsm/src/toast_audio.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/999_asterisk_err.py
+	  (added), res/pjproject/pjsip/src/pjsip-ua/sip_100rel.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/rbtree.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/oss/pa_unix_oss.c
+	  (added), res/pjproject/pjlib/include/pj/lock.h (added),
+	  res/pjproject/pjlib/include/pj++/string.hpp (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-message-no-body.xml
+	  (added), res/pjproject/pjnath/build/wince-evc4 (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/330_srtp_prefer_rtp_savp.py
+	  (added), res/pjproject/pjlib/src/pj/sock_qos_bsd.c (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722/g722_enc.c (added),
+	  res/pjproject/third_party/speex/include/speex/speex.h (added),
+	  res/pjproject/pjsip/include/pjsip-ua/sip_replaces.h (added),
+	  res/pjproject/third_party/g7221/common/basic_op_i.h (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/PocketPJ.h (added),
+	  res/pjproject/pjmedia/src/pjmedia-codec/g722/g722_enc.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/wmme (added),
+	  res/pjproject/pjsip/include/pjsip-simple/evsub_msg.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_2.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/201_codec_g711a.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/360_non_sip_uri.py
+	  (added), res/pjproject/third_party/build/portaudio/src/pa_util.h
+	  (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/main_rtems.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py
+	  (added), res/pjproject/svn_add.bat (added),
+	  res/pjproject/build/cc-gcc.mak (added),
+	  res/pjproject/build/vs/pjproject-vs8-release-static-defaults.vsprops
+	  (added), res/pjproject/third_party/speex/libspeex/lpc_bfin.h
+	  (added), res/pjproject/pjsip-apps/src/ipjsystest (added),
+	  res/pjproject/pjlib/src/pj/compat/setjmp_i386.S (added),
+	  res/pjproject/third_party/build/resample/output (added),
+	  res/pjproject/pjsip-apps/src/python/samples (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/170_timer_required.py
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua_gui/sis (added),
+	  res/pjproject/pjsip/include/pjsip/print_util.h (added),
+	  res/pjproject/pjmedia/include/pjmedia/port.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asio/pa_asio.cpp
+	  (added), res/pjproject/third_party/ilbc/syntFilter.c (added),
+	  res/pjproject/third_party/BaseClasses/ctlutil.h (added),
+	  res/pjproject/third_party/speex/libspeex/testecho.c (added),
+	  res/pjproject/third_party/ilbc/syntFilter.h (added),
+	  res/pjproject/tests/cdash/cfg_symbian.py (added),
+	  res/pjproject/third_party/portaudio/build/dev-cpp (added),
+	  res/pjproject/pjnath/include/pjnath/stun_config.h (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/resource.h (added),
+	  res/pjproject/third_party/srtp/crypto/include/xfm.h (added),
+	  res/pjproject/pjlib/include/pj/compat/os_linux.h (added),
+	  res/pjproject/pjlib/include/pj/compat/os_linux_kernel.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_1.py
+	  (added),
+	  res/pjproject/third_party/portaudio/pablio/test_rw_echo.c
+	  (added), res/pjproject/pjmedia/src/pjmedia/echo_speex.c (added),
+	  res/pjproject/third_party/build/speex (added),
+	  res/pjproject/pjlib/src/pj/os_core_unix.c (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asio/iasiothiscallresolver.cpp
+	  (added), res/pjproject/tests/pjsua/scripts-call (added),
+	  res/pjproject/pjlib/build/os-linux.mak (added),
+	  res/pjproject/third_party/srtp/test/rtp.c (added),
+	  res/pjproject/third_party/ilbc/doCPLC.c (added),
+	  res/pjproject/pjnath/src/pjnath/stun_sock.c (added),
+	  res/pjproject/build/vs/pjproject-vs8-wm2003-release-defaults.vsprops
+	  (added), res/pjproject/pjlib/src/pj/unicode_win32.c (added),
+	  res/pjproject/third_party/ilbc/doCPLC.h (added),
+	  res/pjproject/pjlib-util/include/pjlib-util.h (added),
+	  res/pjproject/pjmedia/build/os-win32.mak (added),
+	  res/pjproject/third_party/srtp/crypto/math/datatypes.c (added),
+	  res/pjproject/build.symbian/pjlibU.def (added),
+	  res/pjproject/third_party/BaseClasses/streams.h (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/Resources-iPad (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/stun_simple_client.c
+	  (added), res/pjproject/pjsip/src/test/dns_test.c (added),
+	  res/pjproject/third_party/portaudio/LICENSE.txt (added),
+	  res/pjproject/build.symbian/pjproject.cww (added),
+	  res/pjproject/pjlib/build/wince-evc4 (added),
+	  res/pjproject/pjlib/include/pj/compat/os_symbian.h (added),
+	  res/pjproject/third_party/speex/libspeex/fixed_bfin.h (added),
+	  res/pjproject/third_party/speex/include/speex/speex_config_types.h.in
+	  (added),
+	  res/pjproject/third_party/speex/libspeex/exc_5_256_table.c
+	  (added), res/pjproject/third_party/speex/libspeex/testresample.c
+	  (added), res/pjproject/pjnath/src/pjturn-srv/listener_udp.c
+	  (added), res/pjproject/pjsip/build/wince-evc4/output (added),
+	  res/pjproject/pjsip-apps/src/samples/aectest.c (added),
+	  res/pjproject/pjlib/src/pjlib-test/thread.c (added),
+	  res/pjproject/pjlib/include/pj (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_1.py
+	  (added), res/pjproject/pjmedia/include/pjmedia/transport_udp.h
+	  (added), res/pjproject/third_party/build/ilbc (added),
+	  res/pjproject/third_party/srtp/config_in.h (added),
+	  res/pjproject/third_party/speex/libspeex/nb_celp.c (added),
+	  res/pjproject/third_party/speex/libspeex/nb_celp.h (added),
+	  res/pjproject/third_party/srtp/crypto/kernel (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/124_sdp_with_unknown_static_unknown_transport.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/310_srtp1_no_crypto.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py
+	  (added), res/pjproject/third_party/build/portaudio/os-auto.mak.in
+	  (added), res/pjproject/tests/pjsua/mod_sendto.py (added),
+	  res/pjproject/build/cc-auto.mak.in (added),
+	  res/pjproject/pjmedia/build/output (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-auth.xml (added),
+	  res/pjproject/pjlib/src/pjlib-test/errno.c (added),
+	  res/pjproject/tests/automated/gnu-ipp.xml.template (added),
+	  res/pjproject/pjmedia/include/pjmedia-audiodev/errno.h (added),
+	  res/pjproject/build.symbian/pjsip_simpleU.def (added),
+	  res/pjproject/pjsip/include/pjsip/sip_autoconf.h.in (added),
+	  res/pjproject/third_party/speex/libspeex/fixed_debug.h (added),
+	  res/pjproject/third_party/portaudio/depcomp (added),
+	  res/pjproject/pjnath/src/pjturn-srv/auth.c (added),
+	  res/pjproject/pjlib/src/pj/pool.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/sha1.h (added),
+	  res/pjproject/pjnath/src/pjturn-srv/auth.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/stream_common.c (added),
+	  res/pjproject/pjlib/include/pj/compat/m_auto.h.in (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_l16_8000.py
+	  (added), res/pjproject/pjmedia/src/pjmedia/rtcp.c (added),
+	  res/pjproject/pjlib/build/os-auto.mak.in (added),
+	  res/pjproject/tests/cdash/cfg_msvc.py (added),
+	  res/pjproject/third_party/gsm/src/lpc.c (added),
+	  res/pjproject/third_party/resample/README.resample (added),
+	  res/pjproject/pjsip-apps/src/ipjsua/MainWindow.xib (added),
+	  res/pjproject/third_party/portaudio/include/pa_win_wmme.h
+	  (added), res/pjproject/third_party/speex/symbian/config.h
+	  (added), res/pjproject/pjnath/src/pjnath-test/test.c (added),
+	  res/pjproject/pjsip-apps/src/samples/siprtp_report.c (added),
+	  res/pjproject/pjnath/src/pjnath-test/test.h (added),
+	  res/pjproject/third_party/srtp (added),
+	  res/pjproject/third_party/build/g7221/libg7221codec.vcproj
+	  (added),
+	  res/pjproject/pjlib-util/build/wince-evc4/pjlib_util_test_wince.vcp
+	  (added), res/pjproject/build/m-i386.mak (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/srv_resolver.h
+	  (added), res/pjproject/tests/pjsua/scripts-call/150_srtp_3_2.py
+	  (added), res/pjproject/pjsip/include/pjsip_simple.h (added),
+	  res/pjproject/pjmedia/src/test/audio_tool.c (added),
+	  res/pjproject/pjlib/src/pj/exception_symbian.cpp (added),
+	  res/pjproject/pjmedia/build/m-i386.mak (added),
+	  res/pjproject/third_party/BaseClasses/wxutil.h (added),
+	  res/pjproject/pjsip-apps/src/vidgui (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_media.c (added),
+	  res/pjproject/pjlib-util/build/pjlib_util.vcproj (added),
+	  res/pjproject/pjnath/include/pjnath/stun_transaction.h (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/oss/recplay.c
+	  (added), res/pjproject/third_party/resample/include (added),
+	  res/pjproject/pjmedia/include/pjmedia/transport.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/srv_resolver.c (added),
+	  res/pjproject/build.symbian/pjsua_libU.def (added),
+	  res/pjproject/pjsip/src/pjsip-simple/presence_body.c (added),
+	  res/pjproject/pjmedia/include/pjmedia/stereo.h (added),
+	  res/pjproject/tests/pjsua/scripts-call/301_ice_public_b.py
+	  (added), res/pjproject/tests/automated/configure.py (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua/symbian_ua_reg.rss
+	  (added), res/pjproject/pjsip-apps/src/pocketpj/PopUpWnd.h
+	  (added),
+	  res/pjproject/third_party/speex/libspeex/high_lsp_tables.c
+	  (added), res/pjproject/pjlib/src/pj/ssl_sock_ossl.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/313_srtp1_unsupported_crypto.py
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua_gui (added),
+	  res/pjproject/third_party/build/milenage/libmilenage.vcp (added),
+	  res/pjproject/pjmedia/include/pjmedia/transport_loop.h (added),
+	  res/pjproject/third_party/build/gsm/libgsmcodec.vcp (added),
+	  res/pjproject/third_party/speex/libspeex/window.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_2.py
+	  (added), res/pjproject/pjsip-apps/src/symbian_ua_gui/data
+	  (added), res/pjproject/pjsip/src/pjsip/sip_transport_wrap.cpp
+	  (added), res/pjproject/pjmedia/include/pjmedia-videodev/errno.h
+	  (added), res/pjproject/pjlib/src/pj/os_time_common.c (added),
+	  res/pjproject/third_party/resample/src (added),
+	  res/pjproject/pjlib/docs (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/161_err_replaces_dlg_not_found.py
+	  (added), res/pjproject/pjsip-apps/src/pocketpj (added),
+	  res/pjproject/pjsip-apps/src/samples/simple_pjsua.c (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/src (added),
+	  res/pjproject/tests/pjsua/scripts-media-playrec/100_resample_lf_11_48.py
+	  (added), res/pjproject/pjmedia/include/pjmedia/rtcp.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_invalid_crypto_tag_non_numeric.py
+	  (added), res/pjproject/tests/pjsua/scripts-pres/100_peertopeer.py
+	  (added), res/pjproject/pjmedia/src/pjmedia/vid_codec_util.c
+	  (added), res/pjproject/third_party/gsm/MACHINES (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uac-subscribe.xml (added),
+	  res/pjproject/third_party/build/baseclasses (added),
+	  res/pjproject/third_party/srtp/include/srtp.h (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uac.py
+	  (added), res/pjproject/pjmedia/src/pjmedia/stream.c (added),
+	  res/pjproject/tests/pjsua/scripts-recvfrom/209a_reg_handle_423_ok.py
+	  (added), res/pjproject/pjlib/src/pjlib-samples/log.c (added),
+	  res/pjproject/third_party/build/portaudio/src/pa_mac_core_old.c
+	  (added), res/pjproject/pjsip/src/pjsip/sip_transport_tcp.c
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/150_err_extension.py
+	  (added),
+	  res/pjproject/pjlib-util/src/pjlib-util-test/encryption.c
+	  (added), res/pjproject/lib (added),
+	  res/pjproject/pjmedia/include/pjmedia/codec.h (added),
+	  res/pjproject/pjmedia/src/pjmedia/converter_libswscale.c (added),
+	  res/pjproject/pjlib/src/pj/ip_helper_win32.c (added),
+	  res/pjproject/pjmedia/include/pjmedia-videodev/avi_dev.h (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/scanner_cis_bitwise.c
+	  (added), res/pjproject/third_party/gsm/README (added),
+	  res/pjproject/pjlib-util/src/pjlib-util (added),
+	  res/pjproject/third_party/build/gsm (added),
+	  res/pjproject/pjlib/include/pj/compat/cc_msvc.h (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince (added),
+	  res/pjproject/tests/pjsua (added),
+	  res/pjproject/pjlib/include/pj++/timer.hpp (added),
+	  res/pjproject/build.symbian/pjlib.mmp (added),
+	  res/pjproject/pjsip/src/test/test.c (added),
+	  res/pjproject/third_party/portaudio/build (added),
+	  res/pjproject/pjsip/src/test/test.h (added),
+	  res/pjproject/pjsip/include/pjsip_auth.h (added),
+	  res/pjproject/pjlib/src/pj/errno.c (added),
+	  res/pjproject/third_party/BaseClasses/wxdebug.cpp (added),
+	  res/pjproject/pjsip/include/pjsip-simple/rpid.h (added),
+	  res/pjproject/pjlib/include/pj/compat/os_sunos.h (added),
+	  res/pjproject/third_party/portaudio/install-sh (added),
+	  res/pjproject/pjlib/src/pj/os_info.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-reinv-no-media.xml
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/172_timer_supported_but_not_used.py
+	  (added),
+	  res/pjproject/third_party/build/resample/libresample_dll.vcproj
+	  (added), res/pjproject/pjmedia/include (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/asio/ASIO-README.txt
+	  (added), res/pjproject/pjsip-apps/src/python/samples/presence.py
+	  (added),
+	  res/pjproject/build/vs/pjproject-vs8-debug-static-defaults.vsprops
+	  (added), res/pjproject/pjmedia/src/pjmedia/transport_srtp.c
+	  (added),
+	  res/pjproject/pjmedia/include/pjmedia-codec/amr_sdp_match.h
+	  (added), res/pjproject/pjsip/src/pjsip-simple/rpid.c (added),
+	  res/pjproject/pjlib-util/src/pjlib-util/dns_server.c (added),
+	  res/pjproject/tests/pjsua/runall.py (added),
+	  res/pjproject/pjlib/include/pj/compat/m_armv4.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_util_proxy.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/crc32.h (added),
+	  res/pjproject/pjlib-util/build/os-auto.mak.in (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.xml
+	  (added), res/pjproject/pjlib/build/wince-evc4/pjlib_wince.vcp
+	  (added), res/pjproject/pjmedia/include/pjmedia/sound.h (added),
+	  res/pjproject/pjsip/build/output (added), res/pjproject/pjnath
+	  (added), res/pjproject/INSTALL.txt (added),
+	  res/pjproject/tests/pjsua/mod_call.py (added),
+	  res/pjproject/pjlib/build/wince-evc4/pjlib_wince.vcw (added),
+	  res/pjproject/pjsip/src/test/dlg_core_test.c (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_g711u.py
+	  (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/411_fmtp_amrnb_offer_band_eff.py
+	  (added), res/pjproject/third_party/build/resample/config.h
+	  (added), res/pjproject/pjsip-apps/src/pjsua_wince/pjsua_wince.rc
+	  (added), res/pjproject/pjlib/build/output (added),
+	  res/pjproject/pjlib/include/pj/compat/m_powerpc.h (added),
+	  res/pjproject/pjsip/src/test/msg_logger.c (added),
+	  res/pjproject/pjsip-apps/src/pjsua_wince/resource.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_auth_parser_wrap.cpp (added),
+	  res/pjproject/aconfigure.ac (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_1.py
+	  (added),
+	  res/pjproject/pjsip-apps/src/pjsystest/pjsystest_wince.rc2
+	  (added), res/pjproject/pjlib/include/pj/compat/os_win32.h
+	  (added), res/pjproject/pjmedia/include/pjmedia/doxygen.h (added),
+	  res/pjproject/pjsip/src/test/main_rtems.c (added),
+	  res/pjproject/pjlib-util/include/pjlib-util/scanner_cis_bitwise.h
+	  (added), res/pjproject/pjsip-apps/src/ipjsystest/main.m (added),
+	  res/pjproject/build.symbian/pjsip.mmp (added),
+	  res/pjproject/third_party/speex/include/speex/speex_jitter.h
+	  (added), res/pjproject/tests/pjsua/run.py (added),
+	  res/pjproject/third_party/speex/symbian (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_l16_8000_stereo.py
+	  (added), res/pjproject/pjsip-apps/src/samples/auddemo.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/300_srtp_crypto_case_insensitive.py
+	  (added), res/pjproject/third_party/g7221/common/basic_op.c
+	  (added),
+	  res/pjproject/pjnath/build/wince-evc4/pjnath_test_wince.vcp
+	  (added), res/pjproject/third_party/g7221/common/basic_op.h
+	  (added), res/pjproject/third_party/portaudio/config.guess
+	  (added), res/pjproject/third_party/portaudio/src/os/unix (added),
+	  res/pjproject/third_party/speex/libspeex/cb_search_sse.h (added),
+	  res/pjproject/tests/pjsua/tools/Makefile (added),
+	  res/pjproject/pjlib/src/pj/compat/longjmp_i386.S (added),
+	  res/pjproject/third_party/portaudio/pablio (added),
+	  res/pjproject/build.symbian/symbian_ua_udeb.pkg (added),
+	  res/pjproject/README.txt (added),
+	  res/pjproject/third_party/srtp/srtp.vcproj (added),
+	  res/pjproject/pjnath/build (added),
+	  res/pjproject/third_party/portaudio/src/hostapi/dsound (added),
+	  res/pjproject/tests/automated/prepare.xml.template (added),
+	  res/pjproject/pjsip/src/pjsua-lib/pjsua_pres.c (added),
+	  res/pjproject/tests/pjsua/scripts-sipp/uas-reinv-and-ack(same-branch)-without-sdp.xml
+	  (added), res/pjproject/pjlib/build (added),
+	  res/pjproject/third_party/build/baseclasses/libbaseclasses.vcproj
+	  (added),
+	  res/pjproject/third_party/speex/include/speex/speex_preprocess.h
+	  (added), res/pjproject/pjlib/src/pjlib-test (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/data/symbian_ua_gui.l01
+	  (added), res/pjproject/pjlib/build/privkey.pem (added),
+	  res/pjproject/pjmedia/src/pjmedia/alaw_ulaw_table.c (added),
+	  res/pjproject/configure-legacy (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/200_ice_success_1.py
+	  (added), res/pjproject/pjsip/include/pjsip/sip_transport.h
+	  (added), res/pjproject/pjnath/src/pjturn-srv/server.c (added),
+	  res/pjproject/pjmedia/build/os-linux.mak (added),
+	  res/pjproject/pjlib/include/pj/compat/os_win32_wince.h (added),
+	  res/pjproject/pjsip/src/pjsip-ua/sip_replaces.c (added),
+	  res/pjproject/third_party/portaudio/src/common/pa_util.h (added),
+	  res/pjproject/pjsip-apps/src/symbian_ua_gui/inc/symbian_ua_guiDocument.h
+	  (added), res/pjproject/pjlib/src/pj/fifobuf.c (added),
+	  res/pjproject/third_party/gsm/tls/sour1.dta (added),
+	  res/pjproject/pjsip/include/pjsip/sip_types.h (added),
+	  res/pjproject/pjlib/include/pj/compat/time.h (added),
+	  res/pjproject/pjsip/src/pjsip/sip_auth_msg.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py
+	  (added), res/pjproject/pjsip/include/pjsip_ua.h (added),
+	  res/pjproject/pjlib/build/Makefile (added),
+	  res/pjproject/third_party/srtp/README (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/311_srtp1_recv_avp.py
+	  (added), res/pjproject/pjsip-apps/src/pjsua/main_rtems.c (added),
+	  res/pjproject/pjsip-apps/src/pocketpj/res/invisibl.bmp (added),
+	  res/pjproject/pjlib/src/pjlib-test/rtems_network_config.h
+	  (added), res/pjproject/third_party/srtp/crypto/math/stat.c
+	  (added), res/pjproject/third_party/srtp/test/replay_driver.c
+	  (added), res/pjproject/pjmedia/src/pjmedia-audiodev/audiotest.c
+	  (added), res/pjproject/pjlib/src/pjlib++-test (added),
+	  res/pjproject/pjsip-apps/src/samples/streamutil.c (added),
+	  res/pjproject/pjmedia/src/pjmedia/ffmpeg_util.c (added),
+	  res/pjproject/tests/pjsua/scripts-sendto/500_pres_subscribe_with_bad_event.py
+	  (added), res/pjproject/third_party/srtp/install-sh (added),
+	  res/pjproject/tests/pjsua/scripts-pesq/200_codec_speex_16000.py
+	  (added),
+	  res/pjproject/third_party/srtp/crypto/cipher/null_cipher.c
+	  (added), res/pjproject/pjmedia/src/pjmedia/ffmpeg_util.h (added),
+	  res/pjproject/pjlib-util/src (added),
+	  res/pjproject/pjsip/include/pjsip/sip_config.h (added),
+	  res/pjproject/pjlib/docs/doxygen.cfg (added): Add support for
+	  ICE/STUN/TURN in res_rtp_asterisk and chan_sip. Review:
+	  https://reviewboard.asterisk.org/r/1891/
+
+2012-06-29 20:32 +0000 [r369512]  Mark Michelson <mmichelson at digium.com>
+
+	* main/rtp_engine.c, /: Fix apparent copy and paste error where
+	  incorrect "glue" is used. ........ Merged revisions 369511 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-29 17:02 +0000 [r369493]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, main/channel.c, main/autoservice.c, main/pbx.c,
+	  channels/chan_local.c, funcs/func_channel.c,
+	  main/channel_internal_api.c, main/features.c,
+	  configs/cdr.conf.sample, include/asterisk/channel.h,
+	  include/asterisk/pbx.h, CHANGES, apps/app_followme.c,
+	  apps/app_queue.c: Hangup handlers - Dialplan subroutines that run
+	  when the channel hangs up. Hangup handlers are an alternative to
+	  the h extension. They can be used in addition to the h extension.
+	  The idea is to attach a Gosub routine to a channel that will
+	  execute when the call hangs up. Whereas which h extension gets
+	  executed depends on the location of dialplan execution when the
+	  call hangs up, hangup handlers are attached to the call channel.
+	  You can attach multiple handlers that will execute in the order
+	  of most recently added first. (closes issue ASTERISK-19549)
+	  Reported by: Mark Murawski Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/2002/
+
+2012-06-29 16:56 +0000 [r369492]  Joshua Colp <jcolp at digium.com>
+
+	* /, channels/chan_sip.c: With some configurations a transport is
+	  not actually specified so assume UDP in these cases. ........
+	  Merged revisions 369490 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 410044 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 410090 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-06 22:39 +0000 [r410042]  George Joseph <george.joseph at fairview5.com>
-
-	* res/res_pjsip/config_auth.c, funcs/func_sorcery.c (added),
-	  res/res_pjsip/location.c, res/res_pjsip_outbound_registration.c,
-	  main/bucket.c, res/res_pjsip_endpoint_identifier_ip.c,
-	  include/asterisk/config.h, include/asterisk/sorcery.h,
-	  res/res_pjsip/pjsip_configuration.c, res/res_pjsip_acl.c,
-	  CHANGES, tests/test_sorcery.c, res/res_pjsip/config_transport.c,
-	  main/config.c, main/sorcery.c: sorcery: Create AST_SORCERY
-	  dialplan function. This patch creates the AST_SORCERY dialplan
-	  function which allows someone to retrieve any value from a
-	  sorcery-based config file. It's similar to AST_CONFIG. The
-	  creation of the function itself was fairly straightforward but it
-	  required changes to the underlying sorcery infrastructure that
-	  rippled into individual sorcery objects. The changes stemmed from
-	  inconsistencies in how sorcery created ast_variable objectsets
-	  from sorcery objects and the inconsistency in how individual
-	  objects used that feature especially when it came to parameters
-	  that can be specified multiple times like contact in aor and
-	  match in identify. You can read more here...
-	  http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html
-	  So, what this patch does, besides actually creating the
-	  AST_SORCERY function, is the following... * Creates
-	  ast_variable_list_append which is a helper to append one
-	  ast_variable list to another. * Modifies the
-	  ast_sorcery_object_field_register functions to accept the
-	  already-defined sorcery_fields_handler callback. * Modifies
-	  ast_sorcery_objectset_create to accept a parameter indicating
-	  return type preference...a single ast_variable with all values
-	  concatenated or an ast_variable list with multiple entries. Also
-	  fixed a few bugs. * Modifies individual sorcery object
-	  implementations to use the new function definition of the
-	  ast_sorcery_object_field_register functions. * Modifies
-	  location.c and res_pjsip_endpoint_identifier_ip.c to implement
-	  sorcery_fields_handler handlers so they return multiple
-	  occurrences as an ast_variable_list. * Added a whole bunch of
-	  tests to test_sorcery. (closes issue ASTERISK-22537) Review:
-	  http://reviewboard.asterisk.org/r/3254/
-
-2014-03-06 19:04 +0000 [r410029]  Jonathan Rose <jrose at digium.com>
-
-	* include/asterisk/acl.h, /, main/acl.c,
-	  res/res_pjsip/pjsip_configuration.c, UPGRADE.txt,
-	  contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
-	  (added), res/res_pjsip/config_transport.c: pjsip configuration:
-	  Make transport TOS values consistent with endpoints Transport TOS
-	  values were interpreted as DSCP values without being documented
-	  as such. Endpoint TOS values (tos_audio/tos_video) behaved
-	  normally as TOS values have historically. This patch makes the
-	  transport TOS values behave as TOS values and makes all TOS
-	  values readable as string values (e.g. AF11). In addition,
-	  alembic scripts have been updated to use the proper field types
-	  for all TOS/COS values. (issue ASTERISK-23235) Reported by:
-	  George Joseph Review: https://reviewboard.asterisk.org/r/3304/
-	  ........ Merged revisions 410028 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-06 18:20 +0000 [r410027]  Joshua Colp <jcolp at digium.com>
-
-	* res/ari/resource_channels.c, CHANGES,
-	  res/ari/ari_model_validators.c,
-	  rest-api/api-docs/recordings.json, res/ari/resource_bridges.c,
-	  res/ari/ari_model_validators.h, /,
-	  include/asterisk/stasis_app_recording.h,
-	  res/res_stasis_recording.c: res_stasis_recording: Add a
-	  "target_uri" field to recording events. This change adds a
-	  target_uri field to the live recording object. It contains the
-	  URI of what is being recorded. (closes issue ASTERISK-23258)
-	  Reported by: Ben Merrills Review:
-	  https://reviewboard.asterisk.org/r/3299/ ........ Merged
-	  revisions 410025 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-06 15:58 +0000 [r410012]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_mwi.c, /: Don't attempt to link in an aggregate MWI
-	  subscription if an endpoint does not aggregate MWI. Attempting to
-	  link a NULL object into an ao2 container had been benign
-	  previously, but since enabling DO_CRASH in the testsuite, this is
-	  now causing a crash. It's better to be right here anyway.
-	  ........ Merged revisions 410011 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-06 02:22 +0000 [r409996]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_fax_spandsp.c, /: res_fax_spandsp: Fix crash when passing
-	  ulaw/alaw data to spandsp When acting as a T.38 fax gateway,
-	  res_fax_spandsp would at times cause a crash in libspandsp. This
-	  would occur when, during fax tone detection, a ulaw/alaw frame
-	  would be passed to modem_connect_tones_rx. That particular
-	  routine expects the data to be in slin format. This patch looks
-	  at the frame type and, if the data is ulaw/alaw, converts the
-	  format to slin before passing it to modem_connect_tones_rx.
-	  Review: https://reviewboard.asterisk.org/r/3296 (closes issue
-	  ASTERISK-20149) Reported by: Alexandr Gordeev Tested by: Michal
-	  Rybarik patches: spandsp_g711decode.diff uploaded by Michal
-	  Rybarik (license 6578) ........ Merged revisions 409990 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409991 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 369491 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-06 00:33 +0000 [r409970-409977]  Richard Mudgett <rmudgett at digium.com>
+2012-06-29 16:42 +0000 [r369489]  Richard Mudgett <rmudgett at digium.com>
 
-	* apps/confbridge/conf_state_multi.c,
-	  apps/confbridge/conf_state_inactive.c, /: app_confbridge: Remove
-	  some noop code. ........ Merged revisions 409976 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/channel_internal_api.c, .cleancount: Remove obsolete struct
+	  ast_channel note. The opaquing the ast_channel struct no longer
+	  requires .cleancount to be changed when the struct is changed. *
+	  Bump .cleancount value one last time because of struct
+	  ast_channel for old times sake.
 
-	* /, res/res_musiconhold.c: res_musiconhold.c: Remove some
-	  unnecessary RAII_VAR() usage. * Made the moh_register() define
-	  use useful parameter names. ........ Merged revisions 409967 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-06-29 15:33 +0000 [r369473]  Joshua Colp <jcolp at digium.com>
 
-2014-03-05 20:41 +0000 [r409904-409919]  Kinsey Moore <kmoore at digium.com>
-
-	* main/config.c, /: config: Fix inverted test The test of the
-	  result of the stat() call was inverted such that its output was
-	  only used if the call failed. This inverts the test so that the
-	  output of stat() is used correctly. This was causing full reloads
-	  on unchanged files. (closes issue ASTERISK-23383) Reported by:
-	  David Woolley ........ Merged revisions 409916 from
+	* /, channels/chan_sip.c: Make the address family filter specific
+	  to the transport. (closes issue ASTERISK-16618) Reported by: Leif
+	  Madsen Review: https://reviewboard.asterisk.org/r/1667/ ........
+	  Merged revisions 369471 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369472 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-28 01:12 +0000 [r369449-369454]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/config_options.h,
+	  configs/config_test.conf.sample, main/config_options.c,
+	  tests/test_config.c: Add the ability to set flags via the config
+	  options api Allows the setting of flags via the config options
+	  api. For example, code like this: #define OPT1 1 << 0 #define
+	  OPT2 1 << 1 #define OPT3 1 << 2 struct thing { unsigned int
+	  flags; }; and a config like this: [blah] opt1=yes opt2=no
+	  opt3=yes Review: https://reviewboard.asterisk.org/r/2004/
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: AST-2012-010:
+	  Clean up after a reinvite that never gets a final response The
+	  basic problem is that if a re-INVITE is sent by Asterisk and it
+	  receives a provisional response, but no final response, then the
+	  dialog is never torn down. In addition to leaking memory, this
+	  also leaks file descriptors and will eventually lead to Asterisk
+	  no longer being able to process calls. This patch just keeps
+	  track of whether there is an outstanding re-INVITE, and if there
+	  is goes ahead and cleans up everything as though there was no
+	  outstanding reinvite. Review:
+	  https://reviewboard.asterisk.org/r/2009/ (closes issue
+	  ASTERISK-19992) Reported by: Steve Davies Tested by: Steve
+	  Davies, Terry Wilson ........ Merged revisions 369436 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369437 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-26 21:45 +0000 [r369414]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/logger.h, channels/chan_dahdi.c,
+	  main/autoservice.c, main/pbx.c, channels/chan_local.c,
+	  channels/sig_analog.c, main/channel_internal_api.c,
+	  channels/chan_agent.c, main/features.c, main/logger.c,
+	  channels/chan_iax2.c, channels/sig_pri.c, channels/sig_ss7.c,
+	  main/bridging.c, main/cli.c: Unique Call ID logging Phases III
+	  and IV Adds call ID logging changes to specific channel drivers
+	  that weren't handled handled in phase II of Call ID Logging. Also
+	  covers logging for threads for threads created by systems that
+	  may be involved with many different calls. Extra special thanks
+	  to Richard for rigorous review of chan_dahdi and its various
+	  signalling modules. review:
+	  https://reviewboard.asterisk.org/r/1927/ review:
+	  https://reviewboard.asterisk.org/r/1950/
+
+2012-06-26 13:23 +0000 [r369370-369392]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/adsi.c: Fix crash in unloading of res_adsi module When
+	  res_adsi is unloaded, it removes the ADSI functions that it
+	  previously installed by passing a NULL adsi_funcs pointer to
+	  ast_adsi_install_funcs. This function was not checking whether or
+	  not the adsi_funcs pointer passed in was NULL before
+	  dereferencing it to check whether or not the version of the
+	  functions matches what the core was expecting it. This patch
+	  makes it so that the version is only checked if a potentially
+	  valid adsi_funcs pointer was passed in. Passing in NULL removes
+	  the installed functions, bypassing the version check. ........
+	  Merged revisions 369390 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369391 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/manager.c: Update "manager show event" to support tab
+	  completion Thank you rmudgett for pointing out that I was missing
+	  this in the initial check-in for AMI event documentation
+	  (r369346)
+
+	* main/cdr.c, /: Fix incorrect duration reporting in CDRs created
+	  in batch mode Certain places in core/cdr.c would, if the duration
+	  value were 0, calculate the duration as being the delta between
+	  the current time and the time at which the CDR record was
+	  started. While this does not typically cause a problem in
+	  non-batch mode, this can cause an issue in batch mode where CDR
+	  records are gathered and written long after those calls have
+	  ended. In particular, this affects calls that were never
+	  answered, as those are expected to have a duration of 0. Often,
+	  this would result in CDR logs with a significant number of calls
+	  with lengthy durations, but dispositions of "BUSY". Note that
+	  this does not affect cdr_csv, as that backend does not use
+	  ast_cdr_getvar and instead directly reports the duration value.
+	  The affected core backends include cdr_apative_odbc and
+	  cdr_custom; other extended or deprecated CDR backends may
+	  potentially still directly manipulate the duration values. (issue
+	  ASTERISK-19860) Reported by: Thomas Arimont (issue AST-883)
+	  Reported by: Thomas Arimont Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1996/ ........ Merged
+	  revisions 369351 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369369 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-25 19:26 +0000 [r369367]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Re-fix how
+	  local tag is generated when sending a 481 to an INVITE. Match our
+	  local tag to whatever to-tag was sent in the initial INVITE.
+	  Because the size of the to-tag may not fit in the buffer in the
+	  sip_pvt, it has been changed to a string field. (closes issue
+	  ASTERISK-19892) reported by Walter Doekes Review:
+	  https://reviewboard.asterisk.org/r/1977 ........ Merged revisions
+	  369352 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369353 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-25 17:59 +0000 [r369346]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_dial.c, apps/app_meetme.c, configure.ac,
+	  apps/app_userevent.c, CHANGES, apps/app_queue.c, Makefile,
+	  build_tools/get_documentation.py (added), main/manager.c,
+	  configure, build_tools/post_process_documentation.py (added),
+	  include/asterisk/xmldoc.h, apps/app_confbridge.c, makeopts.in,
+	  apps/app_stack.c, apps/app_chanspy.c, doc/appdocsxml.dtd,
+	  main/xmldoc.c, apps/app_voicemail.c: Add AMI event documentation
+	  This patch adds the core changes necessary to support AMI event
+	  documentation in the source files of Asterisk, and adds
+	  documentation to those AMI events defined in the core application
+	  modules. Event documentation is built from the source by two new
+	  python scripts, located in build_tools: get_documentation.py and
+	  post_process_documentation.py. The get_documentation.py script
+	  mirrors the actions of the existing AWK get_documentation
+	  scripts, except that it will scan the entirety of a source file
+	  for Asterisk documentation. Upon encountering it, if the
+	  documentation happens to be an AMI event, it will attempt to
+	  extract information about the event directly from the manager
+	  event macro calls that raise the event. The
+	  post_process_documentation.py script combines manager event
+	  instances that are the same event but documented in multiple
+	  source files. It generates the final core-[lang].xml file. As
+	  this process can take longer to complete than a typical 'make
+	  all', it is only performed if a new make target, 'full', is
+	  chosen. Review: https://reviewboard.asterisk.org/r/1967/
+
+2012-06-25 16:07 +0000 [r369329]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix Bridge application occasionally returning
+	  to the wrong location. * Fix do_bridge_masquerade() getting the
+	  resume location from the zombie channel. The code must not touch
+	  a clone channel after it has masqueraded it. The clone channel
+	  has become a zombie and is starting to hangup. (closes issue
+	  ASTERISK-19985) Reported by: jamicque Patches:
+	  jira_asterisk_19985_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: jamicque ........ Merged revisions 369327
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 369328 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-25 15:55 +0000 [r369304-369326]  Mark Michelson <mmichelson at digium.com>
+
+	* include/asterisk/adsi.h, /, main/Makefile, res/res_adsi.c,
+	  main/adsi.c (added), res/res_adsi.exports.in (removed): Multiple
+	  revisions 369323-369324 ........ r369323 | mmichelson |
+	  2012-06-25 10:35:43 -0500 (Mon, 25 Jun 2012) | 9 lines Eliminate
+	  embedding of res_adsi.so module. The way this is done is to stop
+	  using the optional API. Instead, res_adsi.so, when loaded fills
+	  in a table of function pointers. Review:
+	  https://reviewboard.asterisk.org/r/1991 ........ r369324 |
+	  mmichelson | 2012-06-25 10:50:17 -0500 (Mon, 25 Jun 2012) | 2
+	  lines Forgot to svn add this file in my last commit. ........
+	  Merged revisions 369323-369324 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369325 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Be more consistent with the return code
+	  for requests received from invalid domain. When Asterisk receives
+	  an INVITE from an external domain when allowexternaldomains=no
+	  send a 403 instead of a 404. This is consistent with Asterisk's
+	  behavior when receiving a REGISTER in this situation. (Closes
+	  issue ASTERISK-19601) Reported by Matthew Jordan Patches:
+	  ASTERISK-19601-no401.patch uploaded by Mark Michelson (License
+	  #5049) ........ Merged revisions 369302 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369303 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-23 00:33 +0000 [r369237-369296]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/features.c: Fix F and F(x) action logic in Bridge
+	  application.
+
+	* /, main/features.c: Fix Bridge application and AMI Bridge action
+	  error handling. * Fix AMI Bridge action disconnecting the AMI
+	  link on error. * Fix AMI Bridge action and Bridge application not
+	  checking if their masquerades were successful. * Fix Bridge
+	  application running the h-exten when it should not. * Made
+	  do_bridge_masquerade() return if the masquerade was successful so
+	  the Bridge application and AMI Bridge action could deal with it
+	  correctly. * Made bridge_call_thread_launch() hangup the passed
+	  in channels if the bridge_call_thread fails to start. Those
+	  channels would have been orphaned. * Made builtin_atxfer() check
+	  the success of the transfer masquerade setup. ........ Merged
+	  revisions 369282 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409917 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409918 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* bridges/bridge_native_rtp.c, /: bridge_native_rtp: Fix crash
-	  involving masquerade It is possible for a channel to be
-	  masqueraded out of a bridge which means it may no longer have RTP
-	  glue to check upon leaving said bridge. If this situation
-	  occurred (it's possible at least during dial and call pickup)
-	  then Asterisk would crash. This change makes sure the glue is
-	  checked before use. (closes issue AST-1290) Reported by: John
-	  Bigelow ........ Merged revisions 409900 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-05 18:51 +0000 [r409889]  Richard Mudgett <rmudgett at digium.com>
-
-	* contrib/ast-db-manage/cdr/versions,
-	  contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py,
-	  /,
-	  contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py
-	  (added), contrib/ast-db-manage/cdr.ini.sample (added),
-	  contrib/ast-db-manage/cdr/env.py, contrib/ast-db-manage/cdr
-	  (added), contrib/ast-db-manage/cdr/script.py.mako: alembic: Add
-	  missing queue and CDR table creation scripts. * Added the queues
-	  and queue_members tables to the config alembic scripts. * Added
-	  the CDR table alembic creation script. The CDR table is more of
-	  an example for new setups since the actual table can be fully
-	  customized in cdr_adaptive_odbc.conf. (closes issue
-	  ASTERISK-23233) Reported by: jmls Review:
-	  https://reviewboard.asterisk.org/r/3227/ ........ Merged
-	  revisions 409885 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-05 18:47 +0000 [r409888]  Mark Michelson <mmichelson at digium.com>
-
-	* funcs/func_presencestate.c, /: Fix documentation for
-	  PRESENCE_STATE to properly illustrate how to create a presence
-	  hint. There was a missing comma. This was discovered by Dan
-	  Kaplan. ........ Merged revisions 409886 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409887 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-05 16:58 +0000 [r409836]  David M. Lee <dlee at digium.com>
+	  revisions 369283 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Explicitly check caller hangup in app Queue
+	  rather than a polluted res2 value. ........ Merged revisions
+	  369262 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369263 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_queue.c: Fix F and F(x) action logic in Queue
+	  application.
+
+	* apps/app_dial.c, /: Check if PBX was started and fix F and F(x)
+	  action logic in Dial application. ........ Merged revisions
+	  369258 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369259 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/ccss.c: Check if PBX was started for generic CCSS recall.
+	  ........ Merged revisions 369238 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369239 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/config.c, /, configure, include/asterisk/autoconfig.h.in,
-	  configure.ac: Corrected cross-platform stat nanosecond code When
-	  nanosecond time resolution was added for identifying config file
-	  changes, it didn't cover all of the myriad of ways that one might
-	  obtain nanosecond time resolution off of struct stat. Rather than
-	  complicate the #if even further figuring out one system from the
-	  next, this patch directly tests for the three struct members I
-	  know about today, and #ifdef's accordingly. Review:
-	  https://reviewboard.asterisk.org/r/3273/ ........ Merged
-	  revisions 409833 from
+	* /, channels/chan_sip.c: Change incorrect chan_sip zombie hangup
+	  debug message. They are all zombies now. ........ Merged
+	  revisions 369235 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409834 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409835 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 369236 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-05 16:26 +0000 [r409831-409832]  Moises Silva <moises.silva at gmail.com>
+2012-06-22 20:05 +0000 [r369217]  Terry Wilson <twilson at digium.com>
 
-	* res/res_http_websocket.c: Fix res/res_http_websocket.c build
-	  failure in 32bit due to incorrect print format for uint64_t
+	* /, channels/chan_sip.c: Don't crash on a guest directmedia call A
+	  sip_pvt may not have relatedpeer set if a call doesn't match up
+	  with a peer. If there is no relatedpeer, there is no direct media
+	  ACL to apply, so just return that it is allowed. (closes issue
+	  ASTERISK-20040) Reported by: Terry Wilson ........ Merged
+	  revisions 369214 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369215 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-22 19:54 +0000 [r369184-369216]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_dahdi.c: Fix wrong variable name in the R2
+	  disconnect callback
+
+	* /, channels/chan_sip.c: Don't parse media stream state for SIP
+	  video streams The sendonly/recvonly/sendrecv/inactive media
+	  stream attributes were parsed for video, but nothing was ever
+	  done with them. With this code removed, an UNSUPPORTED message is
+	  produced when these attributes are used in conjunction with a
+	  video stream which is the better behavior since they were never
+	  really supported in the first place. ........ Merged revisions
+	  369195 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 369206 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c: Add HANGUPCAUSE hash implementation for
+	  DAHDI MFC/R2 subtech This adds a minimal implementation of the
+	  "Who Hung Up?" Asterisk 11 work to chan_dahdi.c for the MFC/R2
+	  DAHDI subtech. Given the way that OpenR2 interfaces with
+	  chan_dahdi, it is much harder to expose the type of protocol
+	  information that is available in PRI, SS7, or other channel
+	  technologies.
+
+	* channels/sig_analog.c, channels/sig_pri.c: Add HANGUPCAUSE hash
+	  support for analog and PRI DAHDI subtechs This is part of the
+	  DAHDI support for the Asterisk 11 "Who Hung Up?" project and
+	  covers the implementation for the technologies implemented in
+	  sig_analog.c and sig_pri.c. Tested on a local machine to verify
+	  protocol and cause information is available. Review:
+	  https://reviewboard.asterisk.org/r/1953/ (issue SWP-4222)
+
+	* channels/sig_ss7.c: Add "Who Hung Up?" implementation for DAHDI
+	  SS7 subtechnology Testing was done on a local machine to verify
+	  that protocol and cause information was being sent properly.
+	  Review: https://reviewboard.asterisk.org/r/1955/ (issue SWP-4222)
+
+2012-06-20 21:33 +0000 [r369166-369167]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/logger.c: Don't waste time initializing the whole
+	  call_identifer_str[]. The array is either setup with a callid
+	  string or only the first element needs to be initialized.
+
+	* channels/chan_misdn.c: Fix chan_misdn compile error.
+
+2012-06-20 17:48 +0000 [r369148]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/ooq931.c, addons/ooh323c/src/ooCalls.c: fix
+	  locking issue on empty callList (issue ASTERISK-19298) Reported
+	  by: Dmitry Melekhov Patches: ASTERISK-18322-2.patch ........
+	  Merged revisions 369146 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369147 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-20 11:47 +0000 [r369142]  Sean Bright <sean at malleable.com>
+
+	* apps/app_externalivr.c: Remove declaration of eivr_connect_socket
+	  because it no longer exists.
+
+2012-06-20 11:20 +0000 [r369141]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: use right definition for channel name
+
+2012-06-20 03:18 +0000 [r369110-369126]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* main/manager.c, CHANGES: Add IPv6 Support To Manager This patch
+	  adds IPv6 support to AMI. (Closes issue ASTERISK-19965) Reported
+	  by: Michael L. Young Tested by: Michael L. Young Patches:
+	  ami_ipv6_v3.diff uploaded by Michael L. Young (license 5026)
+	  Review: https://reviewboard.asterisk.org/r/1968/
+
+	* main/netsock2.c, /, include/asterisk/netsock2.h: Fix NULL pointer
+	  segfault in ast_sockaddr_parse() While working with
+	  ast_parse_arg() to perform a validity check, a segfault occurred.
+	  The segfault occurred due to passing a NULL pointer to
+	  ast_sockaddr_parse() from ast_parse_arg(). According to the
+	  documentation in config.h, "result pointer to the result. NULL is
+	  valid here, and can be used to perform only the validity checks."
+	  This patch fixes the segfault by checking for a NULL pointer.
+	  This patch also adds documentation to netsock2.h about why it is
+	  necessary to check for a NULL pointer. (Closes issue
+	  ASTERISK-20006) Reported by: Michael L. Young Tested by: Michael
+	  L. Young Patches: asterisk-20006-netsock-null-ptr.diff uploaded
+	  by Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/1990/ ........ Merged
+	  revisions 369108 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369109 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-19 23:36 +0000 [r369092]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: check rtptimeouts in ooh323 channels as
+	  per config file (rtp voice, video, udptl except rtcp) (closes
+	  issue ASTERISK-19179) Reported by: TSAREGORODTSEV Yury Patches:
+	  19179-ooh323-ast10.patch ........ Merged revisions 369091 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-19 21:13 +0000 [r369086]  Kinsey Moore <kmoore at digium.com>
+
+	* main/channel.c, channels/chan_dahdi.c, channels/chan_misdn.c,
+	  main/rtp_engine.c, include/asterisk/channel.h,
+	  channels/chan_iax2.c: Ensure that pvt cause information does not
+	  break native bridging Channel drivers that allow native bridging
+	  need to handle AST_CONTROL_PVT_CAUSE_CODE frames and previously
+	  did not handle them properly, usually breaking out of the native
+	  bridge. This change corrects that behavior and exposes the
+	  available cause code information to the dialplan while native
+	  bridges are in place. This required exposing the HANGUPCAUSE hash
+	  setter outside of channel.c, so additional documentation has been
+	  added.
+
+2012-06-19 15:44 +0000 [r369068]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix request routing issue when
+	  outboundproxy is used. Asterisk was incorrectly setting the
+	  destination of CANCELs and ACKs for error responses to the URI of
+	  the initial INVITE. This resulted in further requests, such as
+	  INVITEs with authentication credentials, to be routed
+	  incorrectly. Instead, when these CANCEL or ACKs are to be sent,
+	  we should simply keep the destination the same as what it
+	  previously was. There is no need to alter it any. (closes issue
+	  ASTERISK-20008) Reported by Marcus Hunger Patches:
+	  ASTERISK-20008.patch uploaded by Mark Michelson (license #5049)
+	  ........ Merged revisions 369066 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369067 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* res/res_http_websocket.c, /: Fix WebRTC over WSS not working
-	  Several fixes for the WebSockets implementation in
-	  res/res_http_websocket.c * Flush the websocket session FILE* as
-	  fwrite() may not actually guarantee sending the data to the
-	  network. If we do not flush, it seems that buffering on the SSL
-	  socket for outbound messages causes issues * Refactored
-	  ast_websocket_read to take into account that SSL file descriptors
-	  may be ready to read via fread() but poll() will not actually say
-	  so because the data was already read from the network buffers and
-	  is now in the libc buffers (closes issue ASTERISK-23099) (closes
-	  issue ASTERISK-21930) Review:
-	  https://reviewboard.asterisk.org/r/3248/ ........ Merged
-	  revisions 409681 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409697 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-06-18 22:56 +0000 [r369061]  Kinsey Moore <kmoore at digium.com>
 
-2014-03-05 12:06 +0000 [r409780]  Sean Bright <sean at malleable.com>
+	* main/features.c: Fix AST_CONTROL_PVT_CAUSE_CODE handling When the
+	  IAX2 Who Hung Up? changes were added, they uncovered a bug in the
+	  way AST_CONTROL_PVT_CAUSE_CODE was handled in
+	  feature_request_and_dial(). This particular frame subtype was
+	  being treated like more terminal control frames causing the
+	  function to be exited prematurely.
 
-	* contrib/scripts/astgenkey, contrib/scripts/astgenkey.8, /: Fix
-	  references to 'keys' CLI commands in astgenkey ........ Merged
-	  revisions 409777 from
+2012-06-18 18:25 +0000 [r369057]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix monitoring calls put in a parking lot. *
+	  Fix a regression that was introduced by -r366167 which
+	  effectively disabled monitoring parked calls. (closes issue
+	  ASTERISK-20012) Reported by: sdolloff Tested by: rmudgett
+	  ........ Merged revisions 369043 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 369044 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-15 21:18 +0000 [r369034]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Various small chan_skinny fixes and
+	  cleanup Added test to skinny_register to only allow device to
+	  register against a device that is not already registered. Addback
+	  l->device test for skinny_show_lines. Fixes segfault if a line is
+	  configured but not configured to a device. Reverses part of
+	  r368680. Removed redundant l->device tests in subsubstate and
+	  dumpsub. l->device will always be valid if these routines are
+	  called. Reverses 368948 - discussed with mjordan on irc. Some
+	  indentation cleanup.
+
+2012-06-15 17:13 +0000 [r369028]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c, channels/sip/include/sip.h: Allow chan_sip
+	  to decline unwanted media streams This change replaces the static
+	  array of four representable media streams with an AST_LIST so
+	  that chan_sip can keep track of offered media streams. This
+	  allows chan_sip to deal with offers containing multiple same-type
+	  streams and many other situations without rejecting the SDP offer
+	  in its entirety, yet still generating a valid response. This also
+	  covers cases where Asterisk can not comprehend the offer if it is
+	  in the correct format. Previously, chan_sip would reject SDP
+	  offers or entirely ignore individual stream offers in an effort
+	  to be more compatible which would often result in invalid SDP
+	  responses. Review: https://reviewboard.asterisk.org/r/1988/
+
+2012-06-15 16:30 +0000 [r369027]  Jason Parker <jparker at digium.com>
+
+	* /, apps/app_voicemail.c: Fix voicemail API tests by using the
+	  correct argument order for create/destroy. ........ Merged
+	  revisions 369024 from
+	  http://svn.asterisk.org/svn/asterisk/certified/branches/1.8.11
+	  ........ Merged revisions 369026 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10-digiumphones
+
+2012-06-15 16:20 +0000 [r369013]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* main/format.c, main/udptl.c, main/netsock2.c, main/autoservice.c,
+	  main/rtp_engine.c, main/frame.c, main/security_events.c, /,
+	  main/say.c, main/threadstorage.c, channels/console_video.c,
+	  main/devicestate.c, main/astfd.c, main/taskprocessor.c,
+	  main/format_pref.c, main/astobj2.c, main/indications.c,
+	  main/config.c, main/loader.c, main/term.c,
+	  apps/confbridge/conf_config_parser.c, main/cli.c,
+	  channels/sig_analog.c, main/framehook.c, main/strcompat.c,
+	  main/plc.c, main/fskmodem_int.c, main/syslog.c,
+	  main/stdtime/localtime.c, main/bridging.c, main/db.c,
+	  channels/sig_ss7.c, main/datastore.c, main/sched.c,
+	  channels/sip/sdp_crypto.c, main/strings.c, main/pbx.c,
+	  channels/vcodecs.c, channels/sip/security_events.c,
+	  main/libasteriskssl.c, channels/iax2-provision.c,
+	  pbx/dundi-parser.c, main/aoc.c, main/cel.c, utils/astdb2bdb.c,
+	  channels/iax2-parser.c, main/chanvars.c, main/netsock.c,
+	  build_tools/find_missing_support_level (added), main/data.c,
+	  main/srv.c, channels/chan_misdn.c, main/privacy.c,
+	  main/fixedjitterbuf.c, channels/sip/dialplan_functions.c,
+	  main/test.c, main/audiohook.c, codecs/codec_dahdi.c, main/alaw.c,
+	  main/asterisk.c, main/timing.c, main/global_datastores.c,
+	  main/fskmodem_float.c, main/ccss.c,
+	  channels/sip/reqresp_parser.c, main/xml.c,
+	  channels/misdn/isdn_msg_parser.c, main/utils.c, main/autochan.c,
+	  channels/misdn/isdn_lib.c, main/enum.c, main/presencestate.c,
+	  main/fskmodem.c, channels/misdn_config.c, main/io.c,
+	  main/channel.c, main/cdr.c, res/ael/pval.c, main/ulaw.c,
+	  main/dial.c, main/format_cap.c, main/tdd.c,
+	  channels/console_gui.c, main/heap.c, channels/misdn/ie.c,
+	  main/logger.c, main/app.c, channels/console_board.c,
+	  main/image.c, main/message.c, main/dns.c, main/lock.c,
+	  main/stun.c, channels/sip/srtp.c, main/dnsmgr.c,
+	  main/slinfactory.c, main/channel_internal_api.c,
+	  main/translate.c, main/jitterbuf.c, main/acl.c,
+	  utils/astdb2sqlite3.c, channels/sip/utils.c, channels/sig_pri.c,
+	  apps/app_system.c, funcs/func_realtime.c, main/tcptls.c,
+	  main/hashtab.c, funcs/func_presencestate.c,
+	  apps/app_celgenuserevent.c, main/abstract_jb.c, main/callerid.c,
+	  main/file.c, main/config_options.c, res/snmp/agent.c,
+	  main/astmm.c, main/event.c, channels/misdn/portinfo.c,
+	  channels/sip/config_parser.c, channels/vgrabbers.c, main/dsp.c,
+	  main/xmldoc.c: Multiple revisions 369001-369002 ........ r369001
+	  | kpfleming | 2012-06-15 10:56:08 -0500 (Fri, 15 Jun 2012) | 11
+	  lines Add support-level indications to many more source files.
+	  Since we now have tools that scan through the source tree looking
+	  for files with specific support levels, we need to ensure that
+	  every file that is a component of a 'core' or 'extended' module
+	  (or the main Asterisk binary) is explicitly marked with its
+	  support level. This patch adds support-level indications to many
+	  more source files in tree, but avoids adding them to third-party
+	  libraries that are included in the tree and to source files that
+	  don't end up involved in Asterisk itself. ........ r369002 |
+	  kpfleming | 2012-06-15 10:57:14 -0500 (Fri, 15 Jun 2012) | 3
+	  lines Add a script to enable finding source files without
+	  support-levels defined. ........ Merged revisions 369001-369002
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 369005 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-15 16:17 +0000 [r369007]  Kinsey Moore <kmoore at digium.com>
+
+	* main/frame.c, channels/chan_iax2.c, include/asterisk/frame.h: Add
+	  HANGUPCAUSE hash support to IAX2 Continuing with the Who Hung Up?
+	  project for Asterisk 11, this adds support to IAX2 for the
+	  HANGUPCAUSE hash. Additionally, this breaks out some
+	  functionality in frame.c for getting information about frame
+	  types and subclasses. Review:
+	  https://reviewboard.asterisk.org/r/1941/ (issue SWP-4222)
+
+2012-06-15 15:33 +0000 [r369000]  Jason Parker <jparker at digium.com>
+
+	* /, apps/app_voicemail.exports.in: Remove some symbol exports that
+	  got missed in the removal of global symbols. (issue AST-807)
+	  (issue AST-901) (issue AST-908) ........ Merged revisions 368998
+	  from
+	  http://svn.asterisk.org/svn/asterisk/certified/branches/1.8.11
+	  ........ Merged revisions 368999 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10-digiumphones
+
+2012-06-15 00:55 +0000 [r368972-368991]  Richard Mudgett <rmudgett at digium.com>
+
+	* /: Remove remaining properties mmichelson left laying around from
+	  phones branch merge.
+
+	* apps/app_dial.c, main/channel.c, include/asterisk/app.h,
+	  main/ccss.c, main/app.c, apps/app_followme.c, apps/app_queue.c,
+	  apps/app_stack.c: Allow non-normal execution routines to be able
+	  to run on hungup channels. * Make non-normal dialplan execution
+	  routines be able to run on a hung up channel. This is preparation
+	  work for hangup handler routines. * Fixed ability to support
+	  relative non-normal dialplan execution routines. (i.e., The
+	  context and exten are optional for the specified dialplan
+	  location.) Predial routines are the only non-normal routines that
+	  it makes sense to optionally omit the context and exten. Setting
+	  a hangup handler also needs this ability. * Fix Return
+	  application being able to restore a dialplan location exactly.
+	  Channels without a PBX may not have context or exten set. * Fixes
+	  non-normal execution routines like connected line interception
+	  and predial leaving the dialplan execution stack unbalanced.
+	  Errors like missing Return statements, popping too many stack
+	  frames using StackPop, or an application returning non-zero could
+	  leave the dialplan stack unbalanced. * Fixed the AGI gosub
+	  application so it cleans up the dialplan execution stack and
+	  handles the autoloop priority increments correctly. * Eliminated
+	  the need for the gosub_virtual_context return location. Review:
+	  https://reviewboard.asterisk.org/r/1984/
+
+	* main/pbx.c: Make the Hangup application set a softhangup flag.
+	  The Hangup application used to just return -1 to cause normal
+	  dialplan execution to hangup a channel. For the non-normal
+	  execution routines like predial and connected-line interception
+	  routines, the hangup request would exit the routine early but
+	  otherwise be ignored. * Made the Hangup application not allow
+	  setting a cause code of zero. A zero cause code is not defined.
+
+	* include/asterisk/app.h: Move vm defines to group them better.
+
+2012-06-14 19:40 +0000 [r368966]  Jason Parker <jparker at digium.com>
+
+	* include/asterisk/app.h, /, tests/test_voicemail_api.c,
+	  main/app.c, include/asterisk/app_voicemail.h (removed),
+	  apps/app_voicemail.c: Multiple revisions 368963,368965 ........
+	  r368963 | qwell | 2012-06-14 13:47:03 -0500 (Thu, 14 Jun 2012) |
+	  14 lines Remove global symbol requirement from app_voicemail.
+	  This uses the existing "function installation" stuff that already
+	  existed for other functions, like getting message counts. (closes
+	  issue AST-807) (issue AST-901) (issue AST-908) Review:
+	  https://reviewboard.asterisk.org/r/1965/ ........ Merged
+	  revisions 368962 from
+	  http://svn.asterisk.org/svn/asterisk/certified/branches/1.8.11
+	  ........ r368965 | qwell | 2012-06-14 14:04:57 -0500 (Thu, 14 Jun
+	  2012) | 11 lines These functions that were moved need to be
+	  static. Also wrap test functions in a #ifdef. (issue AST-807)
+	  (issue AST-901) (issue AST-908) ........ Merged revisions 368964
+	  from
+	  http://svn.asterisk.org/svn/asterisk/certified/branches/1.8.11
+	  ........ Merged revisions 368963,368965 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10-digiumphones
+
+2012-06-14 17:34 +0000 [r368948]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_skinny.c: AST-2012-009: Fix crash in chan_skinny
+	  due to Key Pad Button Message handling AST-2012-008 (r367844)
+	  fixed a denial of service attack exploitable in the Skinny
+	  channel driver that occurred when certain messages are sent after
+	  a previously registered station sends an Off Hook message.
+	  Unresolved in that patch is an issue in the Asterisk 10 releases,
+	  wherein, if a Station Key Pad Button Message is processed after
+	  an Off Hook message, the channel driver will inappropriately
+	  dereference a NULL pointer. This patch fixes those places where
+	  the message handling or the channel callback functions would
+	  attempt to dereference the line's pointer to the device. (issue
+	  ASTERISK-19905) Reported by: Christoph Hebeisen Tested by:
+	  mjordan, Christoph Hebeisen Patches: AST-2012-009-10.diff
+	  uploaded by mjordan (license 6283) ........ Merged revisions
+	  368947 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-14 15:28 +0000 [r368929]  Mark Michelson <mmichelson at digium.com>
+
+	* /, main/Makefile: Revert Makefile change to remove embedding
+	  res_adsi.so The change has resulted in a linking error for
+	  certain versions of GCC. This is much worse than the original
+	  issue, so for now, temporarily revert the change. A more thorough
+	  change will be sought out. ........ Merged revisions 368927 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368928 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-14 13:41 +0000 [r368920-368921]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/config_options.h, main/config_options.c: Add a
+	  post_apply callback to the Config Options API This adds a
+	  callback that only fires when changes have been successfully
+	  applied via the Config Options API. Review:
+	  https://reviewboard.asterisk.org/r/1980/
+
+	* include/asterisk/config_options.h, main/config_options.c: Add
+	  filename alias support to the Config Options API This adds the
+	  ability to handle a single filename alias for a config file. This
+	  is useful if a config filename has changed, but the old filename
+	  should be supported for backwards compatibility. Review:
+	  https://reviewboard.asterisk.org/r/1981/
+
+2012-06-13 21:17 +0000 [r368900]  Mark Michelson <mmichelson at digium.com>
+
+	* /, funcs/func_volume.c: Fix a deadlock that occurs when
+	  func_volume is used on a local channel. This was discovered by
+	  trying to perform a call forward to an extension that makes use
+	  of func_volume. When the local channel is optimized away, the
+	  datastore on the local;2 channel would have its audiohook
+	  destroyed rather than detaching the audiohook from the channel
+	  and then destroying it. With this patch, func_volume's datastore
+	  destructor takes the proper route of detaching the audiohook and
+	  then destroying it. (closes issue ASTERISK-19611) reported by
+	  Volker Sauer Patches: ASTERISK-19611.patch uploaded by Mark
+	  Michelson (license #5049) ........ Merged revisions 368898 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409778 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409779 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 368899 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-13 20:28 +0000 [r368896]  Matthew Jordan <mjordan at digium.com>
+
+	* res/res_smdi.c, /, res/res_adsi.c: Mark res_smdi/res_adsi as
+	  'core' supported modules Recently, various issues surrounding
+	  weak symbols have caused problems with modules that rely on that
+	  feature to be enabled in menuselect. This includes app_voicemail
+	  and chan_dahdi, as they both rely upon res_smdi and res_adsi,
+	  which, in certain circumstances, may not be enabled by default in
+	  menuselect. Because res_smdi/res_adsi are dependencies for
+	  chan_dahdi/app_voicemail, this patch marks both as 'core'
+	  supported modules. This will allow both app_voicemail and
+	  chan_dahdi to be enabled as well, regardless of whether or not
+	  that system supports weak symbols. (issue AST-900) Reported by:
+	  Thomas Arimont (issue AST-885) Reported by: Denis Alberto
+	  Martinez ........ Merged revisions 368894 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368895 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-05 06:17 +0000 [r409747]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+2012-06-13 19:51 +0000 [r368886]  Mark Michelson <mmichelson at digium.com>
 
-	* channels/chan_unistim.c: Add update_peer function to
-	  unistim_rtp_glue, improve other unistim_rtp_glue functions
-	  conforming to other channel drivers. Do not forget auto-detected
-	  and user-selected phone settings on 'unistim reload' ........
-	  Merged revisions 409705 from
+	* /, main/Makefile: Remove forced linking of res_adsi.o In GCC 4.5+
+	  the result is that Asterisk has a phantom module loaded at
+	  startup, claiming to be res_adsi. (closes issue ASTERISK-19920)
+	  reported by Leif Madsen ........ Merged revisions 368873 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368885 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-13 14:55 +0000 [r368832-368855]  Matthew Jordan <mjordan at digium.com>
+
+	* Makefile: Replace MODULES_DIR with ASTMODDIR in Makefile's
+	  INSTALLDIRS Post Asterisk 10, the MODULES_DIR variable no longer
+	  exists, and was replaced with ASTMODDIR.
+
+	* Makefile, /: Do not install empty directories; add ASTLIBDIR
+	  r368830 modified the installation script to only create a
+	  directory if that directory does not exist. If some directory
+	  variable was empty, it would attempt to create the empty
+	  location. It also failed to create the ASTLIBDIR directory. This
+	  patch fixes it such that the correct directories are made and
+	  only created if a value specifying them actually exists. ........
+	  Merged revisions 368852 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368853 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* Makefile, /: Do not perform install on existing directories If a
+	  directory already exists, performing a 'make install' will remove
+	  the permissions associated with the current directory and replace
+	  them with the permissions of the user executing the install. This
+	  patch changes this behavior to only perform an install on the
+	  directory if the directory does not exist. Thus, if a user later
+	  changes the permissions on that directory, those permissions will
+	  be preserved in subsequent installs. Review:
+	  https://reviewboard.asterisk.org/r/1986 Review:
+	  https://reviewboard.asterisk.org/r/1864 (closes issue
+	  ASTERISK-19492) Reported by: Karl Fife Tested by: Paul Belanger,
+	  Tilghman Lesher patches: ASTERISK-19492 by pabelanger (uploaded
+	  by mjordan) ........ Merged revisions 368830 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409745 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11
+	  revisions 368831 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-12 15:46 +0000 [r368809]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Set the Caller ID "tag" on peers even if
+	  remote party information is present. On incoming calls, we were
+	  setting the cid_tag on the dialog only if there was no remote
+	  party information (Remote-Party-ID or P-Asserted-Identity)
+	  present. The Caller ID tag is an invented parameter, though, and
+	  should be set no matter the circumstance. (closes issue
+	  ASTERISK-19859) Reported by Thomas Arimont (closes issue AST-884)
+	  Reported by Trey Blancher ........ Merged revisions 368807 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368808 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-12 14:09 +0000 [r368793-368794]  Matthew Jordan <mjordan at digium.com>
+
+	* /: Update merge property information
+
+	* channels/chan_sip.c: Fix deadlock in SIP transfers that involve a
+	  REFER request In r367163, "send to voicemail" functionality was
+	  added to the SIP channel driver. This required updating the party
+	  redirecting information for the channel based on the headers
+	  provided in the REFER request. When the redirecting party
+	  information is updated on the channel, a call to
+	  ast_indicate_data occurs. Because handle_request_refer still had
+	  the sip_pvt locked, a deadlock could occur between the pbx_thread
+	  and the do_monitor thread servicing the REFER request. This patch
+	  preserves the proper locking order between the channel and the
+	  sip_pvt by ensuring that the sip_pvt is unlocked prior to
+	  updating the party redirecting information on the channel.
+	  (closes issue AST-903) Reported by: Matt Jordan patches:
+	  jira_ast_903_trunk.patch by rmudgett (license 5621)
+
+2012-06-12 04:03 +0000 [r368784]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c, UPGRADE.txt: Parse ANI2 information from SIP
+	  From header parameters ANI2 information is now parsed out of SIP
+	  From headers when present in the oli, isup-oli, and ss7-oli
+	  parameters and is available via the CALLERID(ani2) dialplan
+	  function. (closes issue ASTERISK-19912) Patch-by: Rob Gagnon
+	  Review: https://reviewboard.asterisk.org/r/1947/
+
+2012-06-11 17:34 +0000 [r368772]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, channels/chan_dahdi.c, channels/sig_analog.c, /,
+	  channels/chan_sip.c, include/asterisk/channel.h,
+	  channels/chan_iax2.c: Fix deadlock potential with
+	  ast_set_hangupsource() calls. Calling ast_set_hangupsource() with
+	  the channel lock held can result in a deadlock because the
+	  function also locks the bridged channel. (issue ASTERISK-19537)
+	  (closes issue AST-891) Reported by: Guenther Kelleter Tested by:
+	  Guenther Kelleter (closes issue ASTERISK-19801) Reported by: Alec
+	  Davis ........ Merged revisions 368759 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368760 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-11 15:23 +0000 [r368722-368751]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/sip/sdp_crypto.c, /, channels/chan_sip.c, main/say.c,
+	  res/res_fax.c, channels/sip/reqresp_parser.c, apps/app_queue.c,
+	  main/loader.c, channels/chan_dahdi.c, res/res_config_odbc.c,
+	  channels/sip/dialplan_functions.c, apps/app_directory.c,
+	  pbx/pbx_config.c, res/res_odbc.c, res/res_speech.c,
+	  apps/app_voicemail.c: Fix coverity UNUSED_VALUE findings in core
+	  support level files Most of these were just saving returned
+	  values without using them and in some cases the variable being
+	  saved to could be removed as well. (issue ASTERISK-19672)
+	  ........ Merged revisions 368738 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368739 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /: Recorded merge of revisions 368721 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Fix
+	  compilation in dev-mode Backport a compilation fix in md5.c from
+	  trunk that only showed up in dev-mode under certain compiler
+	  versions. ........ Merged revisions 368719 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+
+2012-06-08 21:08 +0000 [r368712-368714]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, main/utils.c, include/asterisk/strings.h: Fix
+	  error paths in action_hangup() for AMI Hangup action. * Check
+	  allocation function return values for failure. Crashing is bad. *
+	  Tweak ast_regex_string_to_regex_pattern() parameters for proper
+	  ast_str usage.
+
+	* main/channel.c, include/asterisk/channel.h: Tweak
+	  ast_channel_softhangup_withcause_locked() to take a typed
+	  parameter.
+
+2012-06-08 08:32 +0000 [r368688]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c: Fix MWI update so LED display correct
+	  voicemail state after phone usage. Also fixes few warnings.
+	  (closes issue #19675) Reported by: dbohling Patches: fixmwi.patch
+	  uploaded by dbohling (license 6378)
+
+2012-06-07 21:44 +0000 [r368680-368681]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Skinny cleanup (mwi_event_cb). Original
+	  was testing for d->session, setting and testing again (all
+	  nested). Removed duplicate testing and restructured function to
+	  test/return and then the main code.
+
+	* channels/chan_skinny.c: Skinny cleanup. Removed d->registered
+	  which was mirroring d->session. Changed relevant references to
+	  use d->session instead. Moved setting and unsetting of l->device
+	  from session register to device configuration. As such, l->device
+	  will always be valid unless it is has not been configured to a
+	  device. Revised various test where checking if a device is
+	  registered to use l->device->session.
+
+2012-06-07 20:39 +0000 [r368674-368675]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_queue.c: Fix app_queue debug message use of args.options
+	  after the string has been parsed.
+
+	* apps/app_queue.c: Fix inverted test in app_queue for ringinuse.
+	  Regression from -r367080 ringinuse commit. (issue ASTERISK-19536)
+
+2012-06-07 20:32 +0000 [r368673]  Terry Wilson <twilson at digium.com>
+
+	* main/udptl.c, include/asterisk/config_options.h, apps/app_skel.c,
+	  main/config_options.c, tests/test_config.c: Fix reloading an
+	  unchanged file with the Config Options API Adding multiple file
+	  support broke reloading an unchanged file. This adds an enum for
+	  return values for the aco_process_* functions and ensures that
+	  the config is not applied if res is not ACO_PROCESS_OK. Review:
+	  https://reviewboard.asterisk.org/r/1979/
+
+2012-06-07 20:00 +0000 [r368668]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* formats/format_ogg_vorbis.c: Fix a typo in format_ogg_vorbis.c:
+	  suport Review: https://reviewboard.asterisk.org/r/1970/
+
+2012-06-07 15:43 +0000 [r368663]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/config_options.h, main/config_options.c,
+	  tests/test_config.c: Add default handler documentation and
+	  standardize acl handler Added documentation describing what flags
+	  and arguments to pass to aco_option_register for default option
+	  types. Also changed the ACL handler to use the flags parameter to
+	  differentiate between "permit" and "deny" instead of adding an
+	  additional vararg parameter. Review:
+	  https://reviewboard.asterisk.org/r/1969/
+
+2012-06-06 21:34 +0000 [r368646]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c, /: Fix POTS flash
+	  hook to orignate a second call deadlock. A deadlock can occur
+	  when a POTS phone tries to flash hook to originate a second call
+	  for 3-way or transfer. If another process is scanning the
+	  channels container when the POTS line flash hooks then a deadlock
+	  will occur. * Release the channel and private locks when creating
+	  a new channel as a result of a flash hook. (closes issue
+	  ASTERISK-19842) Reported by: rmudgett Tested by: rmudgett
+	  ........ Merged revisions 368644 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368645 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-06 19:25 +0000 [r368637]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix a specific scenario where ACKs are
+	  not matched. If a dialog-starting INVITE contains a to-tag, then
+	  Asterisk will respond with a 481. In this case, the resulting
+	  incoming ACK would not be matched, so Asterisk would continue
+	  retransmitting the 481 until the transaction times out. There
+	  were two issues. Asterisk, upon creating a sip_pvt would generate
+	  a local tag. However, when the time came to transmit the 481,
+	  since there was a to-tag in the INVITE, Asterisk would place this
+	  original to-tag in the 481 response. When the ACK came in,
+	  Asterisk would attempt to match the to-tag in the ACK to the
+	  generated local tag. Unfortunately, Asterisk never actually
+	  transmitted a response with the generated local tag, so the
+	  to-tag in the ACK would not match. The other problem was that
+	  when the 481 was sent, nothing was set on the sip_pvt to indicate
+	  what CSeq is expected in the ACK. To fix the first problem, we
+	  zero out the to-tag seen in the incoming INVITE. This way,
+	  Asterisk, when time to send a response, will send its generated
+	  local tag instead. To fix the second problem, we set the
+	  sip_pvt's pendinginvite to the CSeq of the INVITE when we send a
+	  481. (closes issue ASTERISK-19892) Reported by Mark Michelson
+	  ........ Merged revisions 368625 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368629 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-06 17:22 +0000 [r368606]  Matthew Jordan <mjordan at digium.com>
+
+	* /, build_tools/make_version: Add feature modifier to versions
+	  produced from branches Certain branches, such as Certified
+	  Asterisk, may have a modifier added to them that specifies the
+	  features available in that branch. For branches, this modifier is
+	  expected to be reflected in the location of the branch in
+	  subversion. For example, a subversion of URL of
+	  /certified/branches/1.8.11 would have a feature modifier of
+	  'certified'. This is slightly different then how features are
+	  determined for tags, where the feature is part of the actual tag
+	  name, e.g., "10.5.0-digiumphones". In keeping with the
+	  nomenclature used for tags, the feature specifier for branches is
+	  translated and placed after the revision numbers. For the example
+	  given previously, this would result in a branch version of
+	  "Asterisk SVN-branch-1.8.11-cert-rXXXXXX". ........ Merged
+	  revisions 368604 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368605 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-06 16:11 +0000 [r368588]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Ensure overlapping hold flags do not
+	  conflict When changing between different modes of hold, the flags
+	  were not being cleared out properly causing a failure to change
+	  hold states. (closes issue ASTERISK-19919) Patch-by: Morten
+	  Tryfoss Reported-by: Morten Tryfoss ........ Merged revisions
+	  368586 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 368587 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-06 01:11 +0000 [r368566-368569]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix parked call performing a DTMF blind
+	  transfer after being retrieved. When a parked call was retrieved
+	  from the parking lot, it could not do a blind transfer because it
+	  caused the involved calls to be hung up unconditionally. * Made
+	  the ParkedCall application return the ast_bridge_call() return
+	  value. (closes issue ABE-2862) Reported by: Vlad Povorozniuc
+	  ........ Merged revisions 368567 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368568 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-05 01:05 +0000 [r409683]  Richard Mudgett <rmudgett at digium.com>
+	* main/features.c: Make builtin_blindtransfer() fully use
+	  ast_async_goto() abilities.
 
-	* /, include/asterisk/stasis_internal.h: stasis: Made
-	  internal_stasis_subscribe() prototype and definition match
-	  exactly. ........ Merged revisions 409682 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-06-05 16:25 +0000 [r368550]  Jonathan Rose <jrose at digium.com>
 
-2014-03-04 19:34 +0000 [r409627]  Michael L. Young <elgueromexicano at gmail.com>
+	* CHANGES: Merge 'core' and 'core changes' sections in CHANGES
+	  file.
 
-	* funcs/func_audiohookinherit.c, /: func_audiohookinheritance:
-	  Check If A Channel Was Specified This patch prevents a crash when
-	  using the function audiohookinheritance without setting the
-	  channel. (closes issue ASTERISK-23104) Reported by: Joel Vandal
-	  Tested by: Joel Vandal Patches:
-	  asterisk-23104_audiohook_inherit_no_channel-11.diff uploaded by
-	  Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/3272/ ........ Merged
-	  revisions 409623 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409625 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409626 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-06-05 15:28 +0000 [r368519-368537]  Kinsey Moore <kmoore at digium.com>
 
-2014-03-04 17:22 +0000 [r409587]  Jonathan Rose <jrose at digium.com>
+	* /: Recorded merge of revisions 368536 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Resolve
+	  some build warnings My newly upgraded compiler caught these
+	  usages of uninitialized values. They weren't actually used.
+	  ........ Merged revisions 368533 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
 
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Fix one way audio
-	  problems with hold/unhold when using ICE ICE sessions will now be
-	  restarted if sessions are changed to use new sets of remote
-	  candidates. (closes issue ASTERISK-22911) Reported by: Vytis
-	  Valentinavičius Review: https://reviewboard.asterisk.org/r/3275/
-	  ........ Merged revisions 409565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409570 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, apps/app_voicemail.c: Ensure that pages and emails are sent
+	  using RFC822-compliant date format When localization was added to
+	  app_voicemail, these headers were altered when they should have
+	  remained in en_US format for RFC compliance. This reverts the
+	  changes to those two lines. (closes issue ASTERISK-19876)
+	  ........ Merged revisions 368520 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368524 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_dial.c, channels/chan_unistim.c, channels/chan_local.c,
+	  channels/chan_sip.c, main/channel_internal_api.c,
+	  main/features.c, include/asterisk/channel.h, apps/app_queue.c:
+	  Convert AST_FLAG_ANSWERED_ELSEWHERE usage to
+	  AST_CAUSE_ANSWERED_ELSEWHERE This was essentially duplicated
+	  functionality where normal channels used
+	  AST_CAUSE_ANSWERED_ELSEWHERE while local channels and queues used
+	  AST_FLAG_ANSWERED_ELSEWHERE. This removes the flag and converts
+	  that usage into AST_CAUSE_ANSWERED_ELSEWHER usage. Review:
+	  https://reviewboard.asterisk.org/r/1944 (closes issue
+	  ASTERISK-19865) Patch-by: Birger Harzenetter
+
+2012-06-04 22:12 +0000 [r368500]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Relay proper SIP responses on calling
+	  side. Revision 351130 broke corect HANGUPCAUSE setting for the
+	  404 case in chan_sip. Other cases were also potentially broken.
+	  This patch fixes the relaying of causes to be what they used to
+	  be. (closes issue ASTERISK-19914) Reported by Pavel Troller
+	  Tested by Walter Doekes (via a reviewboard test to be committed
+	  later) Patches: chan_sip.diff uploaded by Pavel Troller (license
+	  #6302) ........ Merged revisions 368498 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368499 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-04 16:55 +0000 [r409569]  Kinsey Moore <kmoore at digium.com>
+2012-06-04 21:18 +0000 [r368472]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, main/astobj2.c: AO2: Add an assert for bad objects This adds
-	  an assert that will only be active if Asterisk is compiled with
-	  DO_CRASH and allows the testsuite to fail tests that would
-	  otherwise require log file parsing. ........ Merged revisions
-	  409566 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 409567 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409568 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, UPGRADE.txt: Document BLINDTRANSFER behavior change. (issue
+	  ASTERISK-19322) (closes issue ASTERISK-19875) Reported by: call
+	  ........ Merged revisions 368469 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368470 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-04 20:53 +0000 [r368435-368467]  Mark Michelson <mmichelson at digium.com>
+
+	* contrib/editors/asterisk.vim: Also have vim syntax-highlight
+	  type=network.
+
+	* contrib/editors/asterisk.vim: Add vim syntax highlighting for
+	  type=line, type=phone, and type=application. (closes issue
+	  ASTERISK-19800) Reported by: Billy Chia Patches:
+	  asterisk.vim.patch uploaded by Billy Chia (license #6381)
+
+	* main/channel.c, apps/app_mixmonitor.c: Remove some extra
+	  debugging I forgot to remove in the merge of Digium phone
+	  support.
+
+	* /: Remove automerge properties.
+
+	* /, contrib/realtime/mysql/voicemail_messages.sql,
+	  main/presencestate.c (added), main/config.c, main/channel.c,
+	  include/asterisk/callerid.h, include/asterisk/file.h,
+	  main/manager.c, channels/chan_skinny.c,
+	  include/asterisk/event_defs.h, include/asterisk/sip_api.h
+	  (added), tests/test_voicemail_api.c (added), main/features.c,
+	  apps/app_voicemail.exports.in, main/app.c, main/message.c,
+	  channels/sip/include/sip.h, main/pbx.c, channels/chan_sip.c,
+	  include/asterisk/presencestate.h (added),
+	  include/asterisk/config.h, include/asterisk/app_voicemail.h
+	  (added), configs/manager.conf.sample, apps/app_queue.c,
+	  include/asterisk/manager.h, include/asterisk/app.h,
+	  funcs/func_presencestate.c (added), include/asterisk/message.h,
+	  main/file.c, main/callerid.c, main/event.c,
+	  include/asterisk/pbx.h, tests/test_config.c,
+	  channels/chan_sip.exports.in (added), apps/app_mixmonitor.c,
+	  main/asterisk.c, apps/app_voicemail.c: Merge changes dealing with
+	  support for Digium phones. Presence support has been added. This
+	  is accomplished by allowing for presence hints in addition to
+	  device state hints. A dialplan function called PRESENCE_STATE has
+	  been added to allow for setting and reading presence. Presence
+	  can be transmitted to Digium phones using custom XML elements in
+	  a PIDF presence document. Voicemail has new APIs that allow for
+	  moving, removing, forwarding, and playing messages. Messages have
+	  had a new unique message ID added to them so that the APIs will
+	  work reliably. The state of a voicemail mailbox can be obtained
+	  using an API that allows one to get a snapshot of the mailbox. A
+	  voicemail Dialplan App called VoiceMailPlayMsg has been added to
+	  be able to play back a specific message. Configuration hooks have
+	  been added. Configuration hooks allow for a piece of code to be
+	  executed when a specific configuration file is loaded by a
+	  specific module. This is useful for modules that are dependent on
+	  the configuration of other modules. chan_sip now has a public
+	  method that allows for a custom SIP INFO request to be sent
+	  mid-dialog. Digium phones use this in order to display progress
+	  bars when files are played. Messaging support has been expanded a
+	  bit. The main visible difference is the addition of an AMI action
+	  MessageSend. Finally, a ParkingLots manager action has been added
+	  in order to get a list of parking lots.
+
+2012-06-04 19:46 +0000 [r368421]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /: Fix potential deadlock between masquerade and
+	  chan_local. * Restructure ast_do_masquerade() to not hold channel
+	  locks while it calls ast_indicate(). * Simplify many calls to
+	  ast_do_masquerade() since it will never return a failure now. If
+	  it does fail internally because a channel driver callback
+	  operation failed, the only thing ast_do_masquerade() can do is
+	  generate a warning message about strange things may happen and
+	  press on. * Fixed the call to ast_bridged_channel() in
+	  ast_do_masquerade(). This change fixes half of the deadlock
+	  reported in ASTERISK-19801 between masquerades and chan_iax.
+	  (closes issue ASTERISK-19537) Reported by: rmudgett Tested by:
+	  rmudgett Review: https://reviewboard.asterisk.org/r/1915/
+	  ........ Merged revisions 368405 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368407 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-02 21:13 +0000 [r368359]  Joshua Colp <jcolp at digium.com>
+
+	* include/asterisk/utils.h, res/res_http_websocket.exports.in
+	  (added), include/asterisk/http_websocket.h (added), main/utils.c,
+	  res/res_http_websocket.c (added): Add res_http_websocket module
+	  which implements the WebSocket protocol according to RFC 6455.
+	  Review: https://reviewboard.asterisk.org/r/1952/
+
+2012-06-01 23:53 +0000 [r368311]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_stack.c: Fix deadlock when Gosub used with alternate
+	  dialplan switches. Attempting to remove a channel from
+	  autoservice with the channel lock held will result in deadlock. *
+	  Restructured gosub_exec() to not call ast_parseable_goto() and
+	  ast_exists_extension() with the channel lock held. (closes issue
+	  ASTERISK-19764) Reported by: rmudgett Tested by: rmudgett
+	  ........ Merged revisions 368308 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368310 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-01 20:42 +0000 [r368268-368269]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* channels/chan_sip.c: Improve SDP offer/answer RFC compliance
+	  Asterisk should not accept SDP offers that contain unknown RTP
+	  profiles (for audio/video streams) or unknown top-level media
+	  types. When it does, it answers with an SDP that does not match
+	  the offer properly, and this will nearly always result in a
+	  broken call. This patch causes such offers to be rejected.
+	  Review: https://reviewboard.asterisk.org/r/1811/
+
+	* /, channels/chan_sip.c: Improve SDP parsing warning messages *
+	  'Unsupported media type' is only reported when that is in fact
+	  the case, not when a supported media type is included in an 'm'
+	  line that has an invalid format. * All warning messages related
+	  to parsing 'm' lines now include the 'm' line contents. * (minor
+	  bugfix) newline added to port-number-zero warning messages. *
+	  Warning messages improved to use RFC-specified terminology for
+	  various items. * Warnings for offers that include more than one
+	  port for a single media type now include the media type. Review:
+	  https://reviewboard.asterisk.org/r/1811/ ........ Merged
+	  revisions 368218 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368267 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-06-01 18:20 +0000 [r368181-368221]  Terry Wilson <twilson at digium.com>
+
+	* configs/config_test.conf.sample (added): Add missing config for
+	  config API test
+
+	* main/udptl.c, include/asterisk/utils.h,
+	  include/asterisk/astobj2.h, configure.ac,
+	  include/asterisk/config.h, main/astobj2.c, main/config.c,
+	  Makefile, include/asterisk/config_options.h (added), configure,
+	  main/asterisk.exports.in, apps/app_skel.c, main/config_options.c
+	  (added), tests/test_config.c, makeopts.in,
+	  configs/app_skel.conf.sample (added),
+	  include/asterisk/stringfields.h: Add new config-parsing framework
+	  This framework adds a way to register the various options in a
+	  config file with Asterisk and to handle loading and reloading of
+	  that config in a consistent and atomic manner. Review:
+	  https://reviewboard.asterisk.org/r/1873/
+
+2012-06-01 13:04 +0000 [r368143]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample,
+	  channels/sip/include/sip.h: Help mitigate potential reinvite
+	  glare scenarios. When Asterisk servers are set up back-to-back,
+	  and direct media is to be used betweeen endpoints, it is fairly
+	  common for the two Asterisk servers to send direct media
+	  reinvites to each other simultaneously. This results in 491s and
+	  ACKs being exchanged between the servers. While the media
+	  eventually gets set up properly, the problem is that there can be
+	  a noticeable delay for the streams to stabilize. This patch adds
+	  a new directmedia option called "outgoing". With this set, an
+	  immediate direct media reinvite will only be sent if the call
+	  direction is outgoing. For incoming dialogs, an immediate direct
+	  media reinvite will not be sent, but further "reactionary" direct
+	  media reinvites may be sent. Review:
+	  https://reviewboard.asterisk.org/r/1954
+
+2012-06-01 03:30 +0000 [r368094]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, funcs/func_channel.c: Add documentation to function CHANNEL
+	  for options echocan_mode and buffers The ability to set
+	  "echocan_mode" and "buffers" through the dialplan was added to
+	  chan_dahdi some time ago. This patch adds some documentation to
+	  func_channel. (Closes issue ASTERISK-19911) Reported by: Dale
+	  Noll Tested by: Michael L. Young Patches:
+	  asterisk-19911-branch18.diff uploaded by Michael L. Young
+	  (license 5026) Review: https://reviewboard.asterisk.org/r/1949/
+	  ........ Merged revisions 368092 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368093 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-31 18:39 +0000 [r368052]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/ael/pval.c, main/tcptls.c, main/manager.c,
+	  res/res_config_odbc.c, /, channels/chan_sip.c,
+	  channels/chan_agent.c, funcs/func_math.c, main/features.c,
+	  apps/app_queue.c, channels/chan_iax2.c, pbx/pbx_config.c:
+	  Coverity Report: Fix issues for error type REVERSE_INULL (core
+	  modules) * Fixes findings: 0-2,5,7-15,24-26,28-31 (issue
+	  ASTERISK-19648) Reported by: Matt Jordan ........ Merged
+	  revisions 368039 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 368042 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-04 14:55 +0000 [r409475]  Sean Bright <sean at malleable.com>
+2012-05-30 18:08 +0000 [r367908-367982]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, channels/chan_sip.c: Minor whitespace change to 'sip show
-	  peers' output. (closes issue ASTERISK-23406) Reported by: ibercom
-	  Tested by: ibercom Patches: asterisk-11.patch uploaded by ibercom
-	  ........ Merged revisions 409472 from
+	* /: Use the DEADLOCK_AVOIDANCE() macro instead. (issue
+	  ASTERISK-19854) ........ Merged revisions 367980 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367981 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/sig_pri.c, channels/sig_ss7.c: Fix deadlock when
+	  executing CLI "pri show channels" and "ss7 show channels"
+	  commands. * Fix sig_pri_lock_owner() to avoid deadlock properly.
+	  * Code pri_grab() better. * Fix sig_ss7_lock_owner() to avoid
+	  deadlock properly. * Code ss7_grab() better. (closes issue
+	  ASTERISK-19854) Reported by: Jaxon Patches:
+	  jira_asterisk_19854_v1.8.6.patch (license #5621) patch uploaded
+	  by rmudgett (Modified to do the same thing to sig_ss7) Tested by:
+	  Jaxon ........ Merged revisions 367976 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367978 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_meetme.c: Coverity Report: Fix issues for error type
+	  REVERSE_INULL (deprecated modules) * Fix only issue pointed out
+	  by deprecated_REVERSE_INULL.txt for app_meetme.c in find_user().
+	  * Change use of %i to %d in sscanf() in find_user(). The use of
+	  %i gives unexpected parsing because it can accept hex, octal, and
+	  decimal integer formats. * Changed other uses of %i in
+	  app_meetme() to use %d for consistency. (issue ASTERISK-19648)
+	  Reported by: Matt Jordan ........ Merged revisions 367906 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367907 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-29 18:40 +0000 [r367845]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_skinny.c: AST-2012-008: Fix remote crash
+	  vulnerability in chan_skinny When a skinny session is
+	  unregistered, the corresponding device pointer is set to NULL in
+	  the channel private data. If the client was not in the on-hook
+	  state at the time the connection was closed, the device pointer
+	  can later be dereferened if a message or channel event attempts
+	  to use a line's pointer to said device. The patches prevent this
+	  from occurring by checking the line's pointer in message handlers
+	  and channel callbacks that can fire after an unregistration
+	  attempt. (closes issue ASTERISK-19905) Reported by: Christoph
+	  Hebeisen Tested by: mjordan, Damien Wedhorn Patches:
+	  AST-2012-008-1.8.diff uploaded by mjordan (license 6283)
+	  AST-2012-008-10.diff uploaded by mjordan (licesen 6283) ........
+	  Merged revisions 367844 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-25 16:33 +0000 [r367783]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_iax2.c: AST-2012-007: Fix IAX receiving HOLD
+	  without suggested MOH class crash. * Made schedule_delivery() set
+	  the received frame f->data.ptr to NULL if the datalen is zero. *
+	  Fix queue_signalling() memcpy() size error. * Made
+	  queue_signalling() not use C++ keyword variable names. (closes
+	  issue ASTERISK-19597) Reported by: mgrobecker Patches:
+	  jira_asterisk_19597_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: rmudgett, Michael L. Young ........ Merged
+	  revisions 367781 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409473 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409474 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 367782 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-25 02:31 +0000 [r367732]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Fix pvt_sip for inbound call to use
+	  peer's allowtransfer setting The pvt_sip allowtransfer was not
+	  being set to that of the peer's setting. Therefore, the global
+	  allowtransfer setting was being used instead which would lead to
+	  calls not being transfered if the global setting was set to 'no'
+	  despite the setting on the peer being 'yes' and vice versa, calls
+	  would be allowed to transfer even if the peer's setting was 'no'
+	  but the global setting was 'yes'. (Closes issue ASTERISK-19856)
+	  Reported by: Jacek Tested by: Michael L. Young, Jacek Patches:
+	  issue-asterisk-19856-branch10-v3.diff uploaded by Michael L.
+	  Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/1923/ ........ Merged
+	  revisions 367730 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367731 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-24 23:52 +0000 [r367693]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, /, apps/app_queue.c: Fix Dial I option ignored
+	  if dial forked and one fork redirects. The Dial and Queue I
+	  option is intended to block connected line updates and
+	  redirecting updates. However, it is a feature that when a call is
+	  locally redirected, the I option is disabled if the redirected
+	  call runs as a local channel so the administrator can have an
+	  opportunity to setup new connected line information.
+	  Unfortunately, the Dial and Queue I option is disabled for *all*
+	  forked calls if one of those calls is redirected. * Make the Dial
+	  and Queue I option apply to each outgoing call leg independently.
+	  Now if one outgoing call leg is locally redirected, the other
+	  outgoing calls are not affected. * Made Dial not pass any
+	  redirecting updates when forking calls. Redirecting updates do
+	  not make sense for this scenario. * Made Queue not pass any
+	  redirecting updates when using the ringall strategy. Redirecting
+	  updates do not make sense for this scenario. * Fixed deadlock
+	  potential with chan_local when Dial and Queue send redirecting
+	  updates for a local redirect. * Converted the Queue stillgoing
+	  flag to a boolean bitfield. (closes issue ASTERISK-19511)
+	  Reported by: rmudgett Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/1920/ ........ Merged
+	  revisions 367678 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367679 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-24 18:56 +0000 [r367640]  Jonathan Rose <jrose at digium.com>
+
+	* main/rtp_engine.c, channels/chan_sip.c,
+	  include/asterisk/rtp_engine.h: chan_sip: fix problem
+	  directmediapermit/deny uses the wrong address When remotely
+	  bridging calls with directmedia, Asterisk would check the address
+	  of the peers/users holding directmedia ACLs (set via
+	  directmediapermit/directmediadeny) instead of the bridged peer.
+	  This is similar to r366547, but trunk specific and involves
+	  changes to the rtpengine instead of just chan_sip. (closes issue
+	  AST-876) review: https://reviewboard.asterisk.org/r/1924/
+
+2012-05-24 13:33 +0000 [r367563]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_confbridge.c: Fix crash in ConfBridge when user
+	  announcement is played for more than 2 users A patch introduced
+	  in r354938 made it so that ConfBridge would not attempt to play
+	  sound files if those files did not exist. Unfortunately,
+	  ConfBridge uses the same underlying function, play_sound_helper,
+	  to playback both sound files and numbers to callers. When a
+	  number is being played back, the name of the sound file is
+	  expected to be NULL. This NULL value was passed into a function
+	  that tested for the existance of a sound file and is not tolerant
+	  to NULL file names, causing a crash. This patch fixes the
+	  behavior, such that if a sound file does not exist we do not
+	  attempt to play it, but we only attempt that check if the a sound
+	  file was specified in the first place. If a sound file was not
+	  specified, we use the 'play number' logic in the helper function.
+	  (closes issue ASTERISK-19899) Reported by: Florian Gilcher Tested
+	  by: Florian Gilcher patches: asterisk-19899.diff uploaded by
+	  mjordan (license 6283) ........ Merged revisions 367562 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-24 00:36 +0000 [r367477-367520]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/iax2-parser.c: Made use IAX frame cache only for
+	  cacheable frame types.
+
+	* main/pbx.c, /: Fix WaitExten(x,m(musicclass)) string termination.
+	  The AST_CONTROL_HOLD MOH class from the WaitExten application can
+	  now be queued onto a channel, passed over local channels with the
+	  /m option, and passed over IAX channels. ........ Merged
+	  revisions 367469 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367470 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-03 19:44 +0000 [r409423]  Joshua Colp <jcolp at digium.com>
+2012-05-23 20:39 +0000 [r367419]  Jonathan Rose <jrose at digium.com>
 
-	* /, res/res_stasis_recording.c: res_stasis_recording: Fix memory
-	  leak of the absolute name. ........ Merged revisions 409422 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/pbx.c: logger: Fix a potential callid reference leak
+	  discovered in development Uncovered a nasty reference leak while
+	  I was writing some changes to chan_dahdi/sig_analog. Slapped
+	  myself around a bit after seeing that I performed the unchecked
+	  return causing this problem.
 
-2014-03-03 02:08 +0000 [r409364]  Matthew Jordan <mjordan at digium.com>
+2012-05-23 20:30 +0000 [r367418]  Mark Michelson <mmichelson at digium.com>
 
-	* main/asterisk.c, /: doxygen: Tweak the link back to ye olde
-	  Digium website ........ Merged revisions 409361 from
+	* main/tcptls.c, /: Only call SSL_CTX_free if DO_SSL is defined.
+	  Thanks to Paul Belanger for pointing out this error. ........
+	  Merged revisions 367416 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367417 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-23 13:46 +0000 [r367376]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Re-add
+	  LastMsgsSent value for SIP peers Previously, MWI logic utilized a
+	  counter called 'lastmsgssent' to know whether or not MWI NOTIFY
+	  requests had been sent to a specific peer. When MWI notifications
+	  were changed to use the internal event framework, this value was
+	  no longer needed for its original purpose. Hence, it was no
+	  longer updated with the new/old message counts for a peer. The
+	  value was previously removed for Asterisk 10; however, since it
+	  was still present in Asterisk 1.8 and still useful for reporting
+	  purposes, it was decided to re-add the value. This patch re-adds
+	  the 'LastMsgsSent' field in the response to an AMI/CLI 'sip show
+	  peer [peer]' command, and makes it so that the value of
+	  lastmsgssent is updated appropriately. The value should now
+	  display the new/old message counts for a particular peer. (closes
+	  issue ASTERISK-17866) Reported by: Steve Davies patches by:
+	  ast-17866-rb1272.patch (License #5041 by irroot) Modified
+	  slightly for this commit Review:
+	  https://reviewboard.asterisk.org/r/1939 ........ Merged revisions
+	  367362 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 367369 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-22 17:29 +0000 [r367274-367309]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c, /, include/asterisk/cel.h,
+	  main/channel_internal_api.c, include/asterisk/channel.h,
+	  main/cel.c, main/asterisk.c: Fix race condition for CEL
+	  LINKEDID_END event This patch fixes to situations that could
+	  cause the CEL LINKEDID_END event to be missed. 1) During a core
+	  stop gracefully, modules are unloaded when ast_active_channels ==
+	  0. The LINKDEDID_END event fires during the channel destructor.
+	  This means that occasionally, the cel_* module will be unloaded
+	  before the channel is destroyed. It seemed generally useful to
+	  wait until the refcount of all channels == 0 before unloading, so
+	  I added a channel counter and used it in the shutdown code. 2)
+	  During a masquerade, ast_channel_change_linkedid is called. It
+	  calls ast_cel_check_retire_linkedid which unrefs the linkedid in
+	  the linkedids container in cel.c. It didn't ref the new linkedid.
+	  Now it does. Review: https://reviewboard.asterisk.org/r/1900/
+	  ........ Merged revisions 367292 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367299 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Resolve crash in subscribing for MWI
+	  notifications ASTOBJ_UNREF sets the variable to NULL after
+	  unreffing it, so the variable should definitely not be used after
+	  that. To solve this in the two cases that affect subscribing for
+	  MWI notifications, we instead save the ref locally, and unref
+	  them in the error conditions. (closes issue ASTERISK-19827)
+	  Reported by: B. R Review:
+	  https://reviewboard.asterisk.org/r/1940/ ........ Merged
+	  revisions 367266 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367267 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-21 22:45 +0000 [r367227]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c: Made ast_queue_hangup() and
+	  ast_queue_hangup_with_cause() lock instead of trylock. It made no
+	  sense to trylock the channel and then unconditionally lock the
+	  channel right after.
+
+2012-05-21 20:35 +0000 [r367189]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_iax2.c: Make chan_iax2 reject cause code
+	  indications correctly If chan_iax2 does not reject the
+	  PVT_CAUSE_CODE frames, the cause will not be stored properly.
+
+2012-05-21 20:31 +0000 [r367163-367183]  Mark Michelson <mmichelson at digium.com>
+
+	* include/asterisk/callerid.h, channels/chan_sip.c,
+	  main/callerid.c: Revert revision 367163. This should have been
+	  committed to my team trunk-digiumphones branch instead of trunk.
+
+	* include/asterisk/callerid.h, channels/chan_sip.c,
+	  main/callerid.c: Add "send to voicemail" Digium phone
+	  functionality to Asterisk. This change accommodates two methods
+	  by which calls can be directed to a user's voicemail. * Incoming
+	  calls can be redirected to any user's voicemail. * Established
+	  calls can be blind transferred to any user's voicemail. Digium
+	  phones indicate the desire to direct a call to voicemail by using
+	  a Diversion header with a reason parameter of "send_to_vm". This
+	  patch adds the "send_to_vm" reason as a valid redirecting reason.
+	  In addition, chan_sip.c has been modified to update redirecting
+	  information on the transferred channel by reading a Diversion
+	  header on a REFER request. (closes issue AST-871) Reported by
+	  Malcolm Davenport Review: https://reviewboard.asterisk.org/r/1925
+
+2012-05-21 17:39 +0000 [r367124]  Terry Wilson <twilson at digium.com>
+
+	* include/asterisk/astobj2.h: Minor documentation change
+
+2012-05-18 19:39 +0000 [r367080]  Jonathan Rose <jrose at digium.com>
+
+	* configs/queues.conf.sample, CHANGES, apps/app_queue.c: app_queue:
+	  Per Member ringinuse option and deprecation of ignorebusy Adds a
+	  number of methods for controlling the setting of 'ringinuse'
+	  which is basically the same concept as the old ignorebusy
+	  setting, only now the per member setting always controls whether
+	  or not the member is actually ringed while in use. A CLI command
+	  and a manager action have been added to change a given queue
+	  member's ringinuse option while Asterisk is running and the an
+	  argument has been added for adding members with deliberately set
+	  ringinuse in queues.conf Some effort has been made to ensure
+	  compatability with dialplans and databases still referring to
+	  'ignorebusy'. (issue ASTERISK-19536) reported by: Philippe
+	  Lindheimer Review: https://reviewboard.asterisk.org/r/1919/
+
+2012-05-18 17:54 +0000 [r367010-367029]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_dahdi.c, /, main/say.c: Address MISSING_BREAK
+	  static analysis reports some more. This addresses core findings 4
+	  and 6. Moises Silva helped me by stating that a break could be
+	  safely added to the case where it is added in chan_dahdi.c In
+	  say.c, I have added a comment indicating that static analysis
+	  complains but that it is currently unknown if this is correct.
+	  This fixes all core findings of this type. (closes issue
+	  ASTERISK-19662) reported by Matthew Jordan ........ Merged
+	  revisions 367027 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409362 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409363 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 367028 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/tcptls.c, /, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  Fix memory leak of SSL_CTX structures in TLS core. SSL_CTX
+	  structures were allocated but never freed. This was a bigger
+	  issue for clients than servers since new SSL_CTX structures could
+	  be allocated for each connection. Servers, on the other hand,
+	  typically set up a single SSL_CTX for their lifetime. This is
+	  solved in two ways: 1. In __ssl_setup(), if a tcptls_cfg has an
+	  ssl_ctx on it, it is freed so that a new one can take its place.
+	  2. A companion to ast_ssl_setup() called ast_ssl_teardown() has
+	  been added so that servers can properly free their SSL_CTXs.
+	  (issue ASTERISK-19278) ........ Merged revisions 367002 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 367003 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-18 15:51 +0000 [r366917-366955]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_dahdi.c, /, channels/chan_sip.c, funcs/func_odbc.c,
+	  main/cli.c: Fix more memory leaks This patch adds to what was
+	  fixed in r366880. Specifically, it addresses the following: *
+	  chan_sip: dispose of an allocated frame in off nominal code paths
+	  in sip_rtp_read * func_odbc: when disposing of an allocated
+	  resultset, ensure that any rows that were appended to that
+	  resultset are also disposed of * cli: free the created return
+	  string buffer in another off nominal code path * chan_dahdi: free
+	  a frame that was allocated by the dsp layer if we choose not to
+	  process that frame (issue ASTERISK-19665) Reported by: Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/1922/ ........
+	  Merged revisions 366944 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 366948 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/netsock2.c, res/res_rtp_asterisk.c, main/pbx.c,
+	  res/res_calendar_exchange.c, res/res_calendar_icalendar.c,
+	  apps/app_page.c, /, funcs/func_dialgroup.c, channels/chan_sip.c,
+	  apps/app_record.c, res/res_calendar_caldav.c, res/res_jabber.c,
+	  apps/app_queue.c, channels/chan_iax2.c, main/enum.c,
+	  main/editline/term.c, main/config.c, res/res_srtp.c, main/cli.c,
+	  main/editline/tokenizer.c, main/data.c, channels/chan_dahdi.c,
+	  funcs/func_odbc.c, main/features.c, apps/app_minivm.c,
+	  main/editline/readline.c, channels/sip/config_parser.c,
+	  main/xmldoc.c, res/res_calendar.c, apps/app_voicemail.c: Fix a
+	  variety of memory leaks This patch addresses a number of memory
+	  leaks in a variety of modules that were found by a static
+	  analysis tool. A brief summary of the changes: * app_minivm: free
+	  ast_str objects on off nominal paths * app_page: free the
+	  ast_dial object if the requested channel technology cannot be
+	  appended to the dialing structure * app_queue: if a penalty rule
+	  failed to match any existing rule list names, the created rule
+	  would not be inserted and its memory would be leaked * app_read:
+	  dispose of the created silence detector in the presence of off
+	  nominal circumstances * app_voicemail: dispose of an allocated
+	  unique ID field for MWI event un-subscribe requests in off
+	  nominal paths; dispose of configuration objects when using the
+	  secret.conf option * chan_dahdi: dispose of the allocated frame
+	  produced by ast_dsp_process * chan_iax2: properly unref peer in
+	  CLI command "iax2 unregister" * chan_sip: dispose of the
+	  allocated frame produced by sip_rtp_read's call of
+	  ast_dsp_process; free memory in parse unit tests *
+	  func_dialgroup: properly deref ao2 object grhead in nominal path
+	  of dialgroup_read * func_odbc: free resultset in off nominal
+	  paths of odbc_read * cli: free match_list in off nominal paths of
+	  CLI match completion * config: free comment_buffer/list_buffer
+	  when configuration file load is unchanged; free the same buffers
+	  any time they were created and config files were processed *
+	  data: free XML nodes in various places * enum: free context
+	  buffer in off nominal paths * features: free ast_call_feature in
+	  off nominal paths of applicationmap config processing * netsock2:
+	  users of ast_sockaddr_resolve pass in an ast_sockaddr struct that
+	  is allocated by the method. Failures in ast_sockaddr_resolve
+	  could result in the users of the method not knowing whether or
+	  not the buffer was allocated. The method will now not allocate
+	  the ast_sockaddr struct if it will return failure. * pbx: cleanup
+	  hash table traversals in off nominal paths; free ignore pattern
+	  buffer if it already exists for the specified context * xmldoc:
+	  cleanup various nodes when we no longer need them *
+	  main/editline: various cleanup of pointers not being freed before
+	  being assigned to other memory, cleanup along off nominal paths *
+	  menuselect/mxml: cleanup of value buffer for an attribute when
+	  that attribute did not specify a value * res_calendar*: responses
+	  are allocated via the various *_request method returns and should
+	  not be allocated in the various write_event methods; ensure
+	  attendee buffer is freed if no data exists in the parsed node;
+	  ensure that calendar objects are de-ref'd appropriately *
+	  res_jabber: free buffer in off nominal path * res_musiconhold:
+	  close the DIR* object in off nominal paths * res_rtp_asterisk: if
+	  we run out of ports, close the rtp socket object and free the rtp
+	  object * res_srtp: if we fail to create the session in libsrtp,
+	  destroy the temporary ast_srtp object (issue ASTERISK-19665)
+	  Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1922 ........ Merged revisions
+	  366880 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 366881 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-18 14:27 +0000 [r366896]  Jonathan Rose <jrose at digium.com>
+
+	* channels/sip/dialplan_functions.c: chan_sip: Fix a small
+	  TEST_FRAMEWORK related error that prevents compiling Introduced
+	  with r366842, a function call made only with TEST_FRAMEWORK
+	  enabled was missing an argument since the function arguments were
+	  changed.
+
+2012-05-18 14:21 +0000 [r366843-366888]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/sip/config_parser.c: Reorder and renumber tests
+	  appropriately It appears that a patch did not apply properly when
+	  adding tests 12 and 13 and test 11 was duplicated. These tests
+	  have been reordered and renumbered such that they make sense.
+	  ........ Merged revisions 366882 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 366884 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/channel.c: Make the new SIP_CAUSE backend behave more like
+	  the original SIP_CAUSE There was a slight discrepancy in the
+	  behaviors of the old SIP_CAUSE and the new SIP_CAUSE/HANGUPCAUSE
+	  when a channel had been originated and had not yet been answered.
+	  This caused the noload_res_srtp_attempt_srtp test to fail since
+	  the SIP_CAUSE variable was never actually set. This behavior has
+	  been restored.
+
+2012-05-17 16:28 +0000 [r366842]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/logger.h, main/channel.c,
+	  channels/sip/include/dialog.h, main/pbx.c, channels/chan_sip.c,
+	  main/channel_internal_api.c, main/logger.c,
+	  include/asterisk/channel.h, CHANGES, channels/sip/include/sip.h,
+	  main/cli.c: logger: Adds additional support for call id logging
+	  and chan_sip specific stuff This patch improves the handling of
+	  call id logging significantly with regard to transfers and adding
+	  APIs to better handle specific aspects of logging. Also, changes
+	  have been made to chan_sip in order to better handle the creation
+	  of callids and to enable the monitor thread to bind itself to a
+	  particular call id when a dialog is determined to be related to a
+	  callid. It then unbinds itself before returning to normal
+	  monitoring. review: https://reviewboard.asterisk.org/r/1886/
+
+2012-05-17 13:21 +0000 [r366746]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_dahdi.c, /, res/res_calendar_ews.c: Fix checking
+	  bounds of array index after using it; improper sizeof This patch
+	  fixes two problems pointed out by a static analysis tool. * In
+	  chan_dahdi, when an event is handled the index of the sub channel
+	  is first obtained. In very off nominal cases, the method that
+	  determines the index can return a negative value. In the event
+	  handling code, whether or not the index returned is valid was
+	  being checked after that value was used to index into an array.
+	  This patch makes it so the value is checked before any indexing
+	  is done. * In res_calendar_ews, sizeof was being passed a pointer
+	  instead of the struct to determine the amount of memory to
+	  allocate. (issue ASTERISK-19651) Reported by: Matt Jordan (closes
+	  issue ASTERISK-19671) Reported by: Matt Jordan ........ Merged
+	  revisions 366740 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 366741 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-03-02 17:03 +0000 [r409350]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+2012-05-16 18:00 +0000 [r366663-366700]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, Makefile.rules: Makefile: replace -O6 with -O3 -O6 is not a
-	  legal option of gcc. Unofficially gcc considers it to be
-	  equivalent of -O3. clang chalks on it, though. This commit sets
-	  the default optimization flag to be -O3, like gcc actually
-	  considered it. Review: https://reviewboard.asterisk.org/r/3280/
-	  ........ Merged revisions 409308 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409344 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409346 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-01 20:28 +0000 [r409288]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Set options
-	  (100rel, timers) on incoming sessions. This change passes options
-	  to the UAS creation function. This in turn sets up 100rel and
-	  session timer properties on the incoming session. Reported by
-	  Julian Russell on asterisk-users mailing list. ........ Merged
-	  revisions 409287 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-03-01 00:05 +0000 [r409257-409275]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/devicestate.c: devicestate.c: Simplified some logic in
-	  _ast_device_state(). ........ Merged revisions 409274 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_cache.c, /: stasis_cache.c: Remove some unnecessary
-	  RAII_VAR() usage. ........ Merged revisions 409272 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis.c, /: stasis.c: Misc code cleanups. * Remove some
-	  unnecessary RAII_VAR() usage. * Made the struct
-	  stasis_subscription ao2 object use the ao2 lock instead of a
-	  redundant join_lock in the struct for ast_cond_wait(). * Removed
-	  locks on some ao2 objects that don't need the lock. * Made the
-	  topic pool entries container use the ao2 template functions. *
-	  Add some missing allocation failure checks. * Add missing cleanup
-	  in off nominal path of dispatch_message(). ........ Merged
-	  revisions 409270 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* include/asterisk/astobj2.h: Remove missed idx parameter to some
+	  ao2 global holder macros.
 
-	* /, channels/chan_sip.c: chan_sip: Add precautionary p->owner
-	  checks. * Add precautionary p->owner checks in sip_hangup(),
-	  get_refer_info(), get_also_info(), and
-	  interpret_t38_parameters(). * Simplify some tangled logic in
-	  get_refer_info(), get_also_info(), and add_rpid(). * Removed some
-	  dead code in handle_request_invite(). (closes issue
-	  ASTERISK-23323) Reported by: Walter Doekes Patches:
-	  issueA23323-more_p_owner_checks-1.8.x.patch (license #5674)
-	  uploaded by wdoekes (modified)
-	  issueA23323-more_p_owner_checks-11.x.patch (license #5674)
-	  uploaded by wdoekes (modified)
-	  issueA23323-more_p_owner_checks-12.x.patch (license #5674)
-	  uploaded by wdoekes (modified)
-	  issueA23323-more_p_owner_checks-trunk.patch (license #5674)
-	  uploaded by wdoekes (modified) ........ Merged revisions 409207
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 409255 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409256 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* include/asterisk/astobj2.h, tests/test_astobj2.c, main/astobj2.c:
+	  Change ao2 global array to ao2 global object holder. Review:
+	  https://reviewboard.asterisk.org/r/1921/
 
-2014-02-28 21:24 +0000 [r409237]  Kinsey Moore <kmoore at digium.com>
+2012-05-15 23:41 +0000 [r366599]  Mark Michelson <mmichelson at digium.com>
 
-	* apps/app_queue.c, /: app_queue: Fix documented AMI event name
-	  During the rewrite of AMI events to use the Stasis bus, the name
-	  of the QueueMemberPaused event was changed to QueueMemberPause.
-	  This corrects documentation to reflect that. ........ Merged
-	  revisions 409234 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/chan_sip.c: Correct misuse of ast_strip_quoted() when
+	  getting a Diversion header's reason parameter. The use here was
+	  assuming that the pointer would be updated, but the updated
+	  string is actually returned by ast_strip_quoted() instead.
+	  ........ Merged revisions 366597 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 366598 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-15 19:36 +0000 [r366462-366546]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_local.c: The predial routine must be run on the
+	  local;1 channel. When ast_call() operates on a local channel, it
+	  copies a lot of things from the local;1 channel to the local;2
+	  channel. This includes among other things, channel variables and
+	  party id information. Other reasons it was a bad idea to run
+	  predial on the local;2 channel: 1) The channel has not been
+	  completely setup. The ast_call() completes the setup. 2) The
+	  local;2 caller and connected line party information is opposite
+	  to any other channels predial runs on. (And it hasn't been setup
+	  yet.) * Partially back out -r366183 by removing the chan_local
+	  implementation of the struct ast_channel_tech.pre_call callback.
+
+	* CHANGES, apps/app_followme.c: Add predial support to FollowMe.
+	  Like the new predial feature for Dial. This adds the same b/B
+	  options to FollowMe. Review:
+	  https://reviewboard.asterisk.org/r/1910/
+
+	* channels/chan_local.c: Make chan_local use the API call instead
+	  of inlining its own version.
+
+2012-05-14 20:15 +0000 [r366413]  Mark Michelson <mmichelson at digium.com>
+
+	* /, pbx/dundi-parser.c: Fix two more coverity constant expression
+	  result findings. These correspond to findings 0 and 1 in the core
+	  findings of ASTERISK-19649. After contacting Mark Spencer, he was
+	  unsure of what the intent behind these lines of code were, so
+	  they are being axed. For Asterisk 1.8 and 10, the output of
+	  debugging DUNDi frames will not be changed, but for trunk the
+	  "Retry" portion will be omitted since it does not properly
+	  distinguish retransmissions from initial frames. (closes issue
+	  ASTERISK-19649) Reported by Matthew Jordan ........ Merged
+	  revisions 366409 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 366412 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-28 18:03 +0000 [r409159]  Richard Mudgett <rmudgett at digium.com>
+2012-05-14 19:44 +0000 [r366408]  Kinsey Moore <kmoore at digium.com>
 
-	* /, channels/chan_sip.c: chan_sip: Fix crash in
-	  ast_channel_hangupcause_set(). * Fix crash in
-	  ast_channel_hangupcause_set() because p->owner not checked before
-	  calling. Regression introduced by the fix for ASTERISK-22621.
-	  (closes issue ASTERISK-23135) Reported by: OK (issue
-	  ASTERISK-23323) Reported by: Walter Doekes ........ Merged
-	  revisions 409156 from
+	* channels/chan_unistim.c, apps/app_dial.c, main/rtp_engine.c,
+	  channels/chan_vpb.cc, channels/chan_sip.c, UPGRADE.txt,
+	  channels/chan_gtalk.c, channels/chan_console.c,
+	  channels/chan_iax2.c, apps/app_queue.c, apps/app_followme.c,
+	  channels/chan_oss.c, channels/chan_jingle.c, main/channel.c,
+	  channels/chan_phone.c, main/dial.c, channels/chan_misdn.c,
+	  channels/chan_skinny.c, funcs/func_frame_trace.c,
+	  main/features.c, channels/chan_h323.c, main/file.c,
+	  channels/chan_alsa.c, configs/sip.conf.sample,
+	  include/asterisk/frame.h, channels/chan_mgcp.c: Commit framework
+	  for HANGUPCAUSE (replacement for SIP_CAUSE) This is the starting
+	  point for the Asterisk 11: Who Hung Up work and provides a
+	  framework which will allow channel drivers to report the types of
+	  hangup cause information available in SIP_CAUSE without incurring
+	  the overhead of the MASTER_CHANNEL dialplan function. The initial
+	  implementation only includes cause generation for chan_sip and
+	  does not include cause code translation utilities. This change
+	  deprecates SIP_CAUSE and replaces its method of reporting cause
+	  codes with the new framework. This change also deprecates the
+	  'storesipcause' option in sip.conf. Review:
+	  https://reviewboard.asterisk.org/r/1822/ (Closes issue SWP-4221)
+
+2012-05-14 19:27 +0000 [r366401]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix broken reinvite glare scenario. To
+	  make a long story short, reinvite glares were broken because
+	  Asterisk would invert the To and From headers when ACKing a 491
+	  response. The reason was because the initreq of the dialog was
+	  being changed to the incoming glared reinvite instead of being
+	  set to the outgoing glared reinvite. This change has three parts
+	  * In handle_incoming, we never will reject an ACK because it has
+	  a to-tag present, even if we think the request may be out of
+	  dialog. * In handle_request_invite, we do not change the initreq
+	  when receiving a reinvite to which we will respond with a 491. *
+	  In handle_request_invite, several superflous settings up
+	  pendinginvite have been removed since this is dones automatically
+	  by transmit_response_reliable Review:
+	  https://reviewboard.asterisk.org/r/1911 ........ Merged revisions
+	  366389 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 366390 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-14 13:42 +0000 [r366351]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* configure, configure.ac, autoconf/ast_pkgconfig.m4 (added): Macro
+	  AST_PKG_CONFIG_CHECK to use chkconfig AST_PKG_CONFIG_CHECK:
+	  Similar to AST_EXT_LIB_CHECK, but simply uses pkg-config data.
+	  This simple version only uses pkg-config(1)'s tests. This commit
+	  also uses the macro to test for GTK2 and GMIME (instead of the
+	  current direct usage of pkg-config). Review:
+	  https://reviewboard.asterisk.org/r/1906/
+
+2012-05-12 00:03 +0000 [r366298]  Russell Bryant <russell at russellbryant.com>
+
+	* /, addons/format_mp3.c: format_mp3: Fix a possible crash in
+	  mp3_read(). This patch fixes a potential crash in mp3_read() by
+	  not assuming that dbuf has enough data to finish filling up the
+	  output buffer. The patch also makes sure that the dbuf state gets
+	  reset after we know we read everything out of it already. In
+	  passing, this patch includes some other cleanups of this module,
+	  including stripping trailing whitespace, formatting fixes based
+	  on coding guidelines, and removing a number of unused members
+	  from the private state struct. (closes issue ASTERISK-19761)
+	  Reported by: Chris Maciejewsk Tested by: Chris Maciejewsk
+	  ........ Merged revisions 366296 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409157 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409158 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 366297 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-27 19:54 +0000 [r409132]  Jonathan Rose <jrose at digium.com>
+2012-05-10 23:49 +0000 [r366183-366242]  Richard Mudgett <rmudgett at digium.com>
 
-	* res/res_rtp_asterisk.c, /: Multiple revisions 409129-409130
-	  ........ r409129 | jrose | 2014-02-27 13:19:02 -0600 (Thu, 27 Feb
-	  2014) | 15 lines res_rtp_asterisk: Fix checklist creating
-	  problems in ICE sessions Prior to this patch, local candidate
-	  lists including SRFLX would fail to start properly when building
-	  ICE candidate check lists. This patch fixes that problem by
-	  making sure that each SRFLX candidate is associated with the
-	  proper base address so that the check list can create matches
-	  properly. This patch was written by jcolp. The issue will be left
-	  open to await testing by the issue participants. (issue
-	  ASTERISK-23213) Reported by: Andrea Suisani Review:
-	  https://reviewboard.asterisk.org/r/3256/ ........ r409130 | jrose
-	  | 2014-02-27 13:38:10 -0600 (Thu, 27 Feb 2014) | 8 lines
-	  res_rtp_asterisk: correct build error from r409129 Accidentally
-	  placed a declaration below functional code (issue ASTERISK-23213)
-	  Reported by: Andrea Suisani Review:
-	  https://reviewboard.asterisk.org/r/3256/ ........ Merged
-	  revisions 409129-409130 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409131 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-27 16:26 +0000 [r409091]  David M. Lee <dlee at digium.com>
-
-	* utils/astman.c, /: Fix memory stomping bug in astman. This memset
-	  complained in dev mod on my Ubuntu box. The memset is both
-	  unnecessary and dangerous. At this point, m hasn't been
-	  initialized yet, so the memset will write off to whatever address
-	  happens to be on the stack at the time. ........ Merged revisions
-	  409077 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 409083 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409087 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-27 16:08 +0000 [r409055]  Corey Farrell <git at cfware.com>
-
-	* /, configs/res_fax.conf.sample: res_fax: Comment out default
-	  settings from res_fax.conf. Comment out many settings in
-	  res_fax.conf.sample. The defaults are set in res_fax.c, so
-	  setting the same value in sample config does nothing but make the
-	  sample config more fragile. (closes issue ASTERISK-23231)
-	  Reported by: David Brillert Review:
-	  https://reviewboard.asterisk.org/r/3261/ ........ Merged
-	  revisions 409052 from
+	* main/channel.c, /: * Made ast_change_name() hold the channels
+	  container lock while changing the channel name. * Eliminate
+	  redundant list not empty check in clone_variables(). ........
+	  Merged revisions 366240 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 409053 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 409054 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-27 12:29 +0000 [r409000]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_pjsip_sdp_rtp.c: res_pjsip_sdp_rtp: Apply
-	  packetization rules on inbound SDP handling The setting
-	  'use_ptime' is supposed to tell Asterisk to honour the ptime
-	  attribute in an offer, preferring it to whatever packetization
-	  preferences have been set internally. Currently, however,
-	  something rather quirky will happen: (1) The SDP answer will be
-	  constructed in create_outgoing_sdp_stream. This will use the
-	  preferences from the endpoint, such that the 200 OK response will
-	  add the packetization preferences from the endpoint, and not what
-	  was offered. (2) When the 200 response is issued,
-	  apply_negotiated_sdp_stream is called. This will call
-	  apply_packetization, which will use the ptime attribute from the
-	  offer internally. We end up telling the offerer to use the
-	  internal ptime attribute, but we end up using the offered ptime
-	  attribute. Hilarity ensues. This patch modifies the behaviour by
-	  calling apply_packetization from negotiate_incoming_sdp_stream,
-	  which is called prior to create_outgoing_sdp_stream. This causes
-	  the format preferences on the session's media object to be set to
-	  the inbound ptime value (if 'use_ptime' is enabled), such that
-	  the construction of the answer gets the right value immediately.
-	  Review: https://reviewboard.asterisk.org/r/3244/ ........ Merged
-	  revisions 408999 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-26 23:35 +0000 [r408984]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, tests/test_stasis.c: test_stasis.c: Misc cleanups. * Make the
-	  consumer ao2 object use the ao2 lock instead of a redundant lock
-	  in the struct for ast_cond_wait(). * Fixed some curly brace
-	  placements. * Fixed use of malloc(0). malloc(0) has variant
-	  behavior. It is up to the implementation to determine if it
-	  returns NULL or a valid pointer that can be later passed to
-	  free(). ........ Merged revisions 408983 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-26 19:00 +0000 [r408971]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* channels/chan_pjsip.c, /: pjsip: avoid edge case potential crash
-	  in answer() When accidentally compiling against a wrong version
-	  of pjsip headers with a different pjsip_inv_session size, the
-	  invite_tsx structure could be null in the answer() function. This
-	  led to a crash because it attempted to send the session response
-	  with an uninitialized packet pointer. This patch presets packet
-	  to null and adds a diagnostic log message to explain why the call
-	  fails. Review: https://reviewboard.asterisk.org/r/3267/ ........
-	  Merged revisions 408970 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-26 17:04 +0000 [r408958]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_ari.c, /: res_ari: Make some additional error responses
-	  consistent with the rest of the system. This change makes some
-	  error cases use ast_ari_response_error to construct their error
-	  responses instead of manually doing it. This ensures they are
-	  consistent with the other error responses. Based on the original
-	  patch as done by Paul Belanger on the associated review. Review:
-	  https://reviewboard.asterisk.org/r/2904/ ........ Merged
-	  revisions 408957 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-26 13:47 +0000 [r408942-408944]  Kinsey Moore <kmoore at digium.com>
-
-	* include/asterisk/res_pjsip_session.h, /: PJSIP: Fix some bad
-	  spacing ........ Merged revisions 408943 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_refer.c: PJSIP: Prevent crash if channel has
-	  gone away It is currently possible for an ast_sip_session to
-	  exist without an associated channel as is the case when a new
-	  invite is coming in or just after a hangup is issued on a
-	  chan_pjsip channel. Part of the attended transfer code assumed
-	  the channel would be non-NULL and used it as such causing a
-	  crash. This bug was exposed thanks to the attended transfer ARI
-	  test in the test suite. (closes issue ASTERISK-23287) Reported
-	  by: Matt Jordan ........ Merged revisions 408941 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-26 08:57 +0000 [r408932]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
-
-	* channels/chan_unistim.c: Implement functions handling keypress,
-	  display icons and text for i2004 KEM support.
-
-2014-02-25 17:51 +0000 [r408881-408883]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_exten_state.c, /,
-	  res/res_pjsip_pidf_digium_body_supplement.c (added),
-	  include/asterisk/res_pjsip_body_generator_types.h:
-	  res_pjsip_exten_state: Presence for digium phones Added presence
-	  support for digium phones. Review:
-	  https://reviewboard.asterisk.org/r/3239/ ........ Merged
-	  revisions 408882 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_send_to_voicemail.c (added),
-	  res/res_pjsip_header_funcs.c: res_pjsip_send_to_voicemail:
-	  transferring to voicemail for digium phones Added the ability for
-	  transferring directly to voicemail on digium phones. Added a new
-	  module that checks for the presence of a custom header and/or
-	  diversion header within a sip REFER. If either is found and they
-	  specify a sending to voicemail action then variables are added to
-	  the channel allowing the user access to them in the dialplan.
-	  Dialplan can then be written that branches based upon these
-	  values allowing, for instace, for a single number to be used for
-	  dialing and/or accessing voicemail directly. Also fixed a problem
-	  where the PJSIP_HEADER function was allowing non pjsip channels
-	  through (checked to make sure it has the correct channel type
-	  before proceeding). Review:
-	  https://reviewboard.asterisk.org/r/3245/ ........ Merged
-	  revisions 408880 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-25 17:44 +0000 [r408879]  Rusty Newton <rnewton at digium.com>
-
-	* configs/voicemail.conf.sample, /: configs/voicemail.conf.sample -
-	  Make mailcmd sample text more explicit Made the wording a bit
-	  more explicit. Didn't really change the meaning. ........ Merged
-	  revisions 408876 from
+	  revisions 366241 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_dial.c: Tweak app_dial predial documentation.
+
+	* apps/app_dial.c, main/channel.c, channels/chan_local.c,
+	  include/asterisk/channel.h: Run predial routine on local;2
+	  channel where you would expect. Before this patch, the predial
+	  routine executes on the ;1 channel of a local channel pair.
+	  Executing predial on the ;1 channel of a local channel pair is of
+	  limited utility. Any channel variables set by the predial routine
+	  executing on the ;1 channel will not be available when the local
+	  channel executes dialplan on the ;2 channel. * Create
+	  ast_pre_call() and an associated pre_call() technology callback
+	  to handle running the predial routine. If a channel technology
+	  does not provide the callback, the predial routine is simply run
+	  on the channel. Review: https://reviewboard.asterisk.org/r/1903/
+
+2012-05-10 20:56 +0000 [r366169]  Kinsey Moore <kmoore at digium.com>
+
+	* funcs/func_speex.c, main/pbx.c, res/res_calendar_icalendar.c, /,
+	  channels/chan_sip.c, funcs/func_lock.c, channels/chan_agent.c,
+	  channels/sip/reqresp_parser.c, main/devicestate.c,
+	  pbx/dundi-parser.c, channels/chan_iax2.c, channels/iax2-parser.c,
+	  main/config.c, res/res_monitor.c, main/channel.c, main/cdr.c,
+	  res/ael/pval.c, main/data.c, channels/chan_dahdi.c,
+	  main/tcptls.c, main/manager.c, main/features.c, main/app.c,
+	  main/event.c, pbx/pbx_dundi.c, res/res_odbc.c, main/xmldoc.c,
+	  apps/app_voicemail.c: Resolve FORWARD_NULL static analysis
+	  warnings This resolves core findings from ASTERISK-19650 numbers
+	  0-2, 6, 7, 9-11, 14-20, 22-24, 28, 30-32, 34-36, 42-56, 82-84,
+	  87, 89-90, 93-102, 104, 105, 109-111, and 115. Finding numbers
+	  26, 33, and 29 were already resolved. Those skipped were either
+	  extended/deprecated or in areas of code that shouldn't be
+	  disturbed. (Closes issue ASTERISK-19650) ........ Merged
+	  revisions 366167 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408877 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408878 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-22 23:31 +0000 [r408859]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/asterisk.c: main: Initialize dialplan providing core
-	  components prior to module pre-load It is possible to pre-load
-	  pbx_config. As a result, pbx_config - which will load and parse
-	  the dialplan - will attempt to use various dialplan components,
-	  such as device state providers and presence state providers,
-	  prior to them being initialized by the core. This would lead to a
-	  crash, as the components had not created their Stasis cache
-	  entries. This patch moves a number of core component
-	  initializations before the module pre-load. This guarantees that
-	  if someone does pre-load pbx_config - or other pbx modules - that
-	  the Stasis caches for the various core components are created.
-	  (closes issue ASTERISK-23320) Reported by: xrobau (closes issue
-	  ASTERISK-23265) Reported by: Andrew Nagy Tested by: Andrew Nagy,
-	  Rusty Newton ........ Merged revisions 408855 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-22 18:01 +0000 [r408840]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/chan_ooh323.c, /: ignore AST_CONTROL_PVT_CAUSE_CODE
-	  without any messages (closes issue ASTERISK-23336) Reported by:
-	  Alexander Semych ........ Merged revisions 408838 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408839 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-22 02:31 +0000 [r408788]  Corey Farrell <git at cfware.com>
-
-	* /, utils/extconf.c, utils/conf2ael.c, res/ael/pval.c, main/pbx.c:
-	  Remove extra defines of AST_PBX_MAX_STACK. * Ensure
-	  AST_PBX_MAX_STACK is only defined in extconf.h and pbx.h. * Fix
-	  incorrect function parameters in utils/extconf.c. (closes issue
-	  ASTERISK-23141) Reported by: Maxim Review:
-	  https://reviewboard.asterisk.org/r/3241/ ........ Merged
-	  revisions 408785 from
+	  revisions 366168 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-10 18:35 +0000 [r366126]  Jonathan Rose <jrose at digium.com>
+
+	* main/pbx.c, channels/sig_analog.c, /, channels/chan_sip.c,
+	  funcs/func_lock.c, main/features.c, main/acl.c,
+	  channels/iax2-provision.c, apps/app_queue.c,
+	  channels/chan_iax2.c, res/ael/ael.flex, funcs/func_devstate.c,
+	  main/asterisk.c, main/xmldoc.c, apps/app_voicemail.c: Coverity
+	  Report: Fix issues for error type CHECKED_RETURN for core (issue
+	  ASTERISK-19658) Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1905/ ........ Merged
+	  revisions 366094 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408786 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-21 18:37 +0000 [r408731]  Kevin Harwell <kharwell at digium.com>
-
-	* main/rtp_engine.c, /: rtp_engine: Dynamic payload change in rtp
-	  mapping not supported Asterisk didn't support the dynamic payload
-	  change in rtp mapping in the 200 OK response. Scenario: Asterisk
-	  sends the INVITE proposing alaw and telephone-event, it proposes
-	  rtpmap:101 for telephone-event. Peer responds with 2xx, it
-	  answers with alaw and telephone-event also, but it proposes a
-	  different rtpmap number (rtpmap:103) for telephone-event.
-	  Expected Behaviour: Asterisk should honour the rtpmapping in the
-	  response and send DTMF packets using 103 as payload type for
-	  DTMF. Actual Behaviour: Asterisk sends DTMF packets using payload
-	  type 101. With this patch asterisk now supports changes that can
-	  occur in the rtp mapping in the response. (closes issue
-	  ASTERISK-23279) Reported by: NITESH BANSAL Review:
-	  https://reviewboard.asterisk.org/r/3225/ Patches:
-	  dynamic_payload_change.patch uploaded by nbansal (license 6418)
-	  ........ Merged revisions 408729 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408730 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-21 18:19 +0000 [r408712-408723]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/manager.c, /: manager: Fix AMI Status action of a single
-	  channel. Fixed use of uninitialized ao2 container iterator in an
-	  off-nominal condition. Either a memory allocation error or the
-	  requested channel is an internal channel not exposed to the
-	  outside. ........ Merged revisions 408715 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/sorcery.c, res/ari/resource_endpoints.c, /,
-	  apps/app_meetme.c, res/res_fax.c, res/res_stasis_recording.c,
-	  main/stasis_channels.c, res/res_sorcery_astdb.c,
-	  include/asterisk/json.h: json: Fix off-nominal json ref counting
-	  issues. * Fixed off-nominal json ref counting issue with using
-	  the following API calls: ast_json_object_set() and
-	  ast_json_array_append(). * Fixed off-nominal error reporting in
-	  ast_ari_endpoints_list(). * Fixed some miscellaneous off-nominal
-	  json ref counting issues in report_receive_fax_status() and
-	  dial_to_json(). ........ Merged revisions 408713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/json.c, /: json: Fix json API wrapper code for json library
-	  versions earlier than 2.3.0. * Fixed json ref counting issue with
-	  json API wrapper code for ast_json_object_update_existing() and
-	  ast_json_object_update_missing() when the json library is earlier
-	  than version 2.3.0. ........ Merged revisions 408711 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-21 16:49 +0000 [r408699]  Corey Farrell <git at cfware.com>
-
-	* channels/chan_sip.c: chan_sip: prevent add_route from adding
-	  empty header. Fix regression caused by ASTERISK-22582. Empty
-	  Route headers were added when the route had a single strict hop.
-	  (closes issue ASTERISK-23306) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3236/
-
-2014-02-21 16:27 +0000 [r408645-408652]  Kevin Harwell <kharwell at digium.com>
+	  revisions 366106 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/rtp_engine.c, /: rtp_engine: Output mixup in
-	  ${CHANNEL(rtpqos,audio,all)} Fixed the output of
-	  CHANNEL(rtpqos,audio,all) to use txjitter instead of rxjitter.
-	  (closes issue ASTERISK-23261) Reported by: rsw686 Patches:
-	  rtpqos.patch uploaded by rsw686 (license 5887) ........ Merged
-	  revisions 408646 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408647 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408649 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/channel.c, /: channel.c: MOH is not working for transferee
-	  after attended transfer Updated the code to check to see if MOH
-	  is playing on the transferor and if so then start it on the
-	  channel that replaces it during a masquerade. Example scenario of
-	  the problem: Alice calls Bob and then Bob begins the attended
-	  transfer process into a queue. Upon going on hold Alice hears
-	  music and so does Bob once he is in the queue. Bob then transfers
-	  Alice into the queue and then music for Alice stops even though
-	  she should be hearing it since has now replaced Bob in the queue.
-	  The problem that was occurring is that once the channel was
-	  masqueraded the app (queues, confbridge, etc...) had no way of
-	  knowing that the channel had just been swapped out thus it did
-	  not start music for the present channel. Credit to Olle Johansson
-	  for pointing me in the right direction on this issue. (closes
-	  issue ASTERISK-19499) Reported by: Timo Teräs Review:
-	  https://reviewboard.asterisk.org/r/3226/ ........ Merged
-	  revisions 408642 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408643 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408644 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-21 10:45 +0000 [r408592]  Alexandr Anikin <may at telecom-service.ru>
+2012-05-10 16:22 +0000 [r366062]  Mark Michelson <mmichelson at digium.com>
 
-	* /, addons/ooh323c/src/ooCalls.h: Fix type of roundTripDelay
-	  variables ........ Merged revisions 408589 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408590 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408591 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/chan_sip.c: Close the proper tcptls_session when
+	  session creation fails. (issue AST-998) Reported by: Thomas
+	  Arimont Tested by: Thomas Arimont ........ Merged revisions
+	  366052 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 366053 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-21 00:50 +0000 [r408539]  Michael L. Young <elgueromexicano at gmail.com>
+2012-05-10 15:57 +0000 [r366007-366051]  Jonathan Rose <jrose at digium.com>
 
-	* /, apps/app_chanspy.c: app_chanspy: Documentation Update To
-	  Clarify "x" Option When using the "x" option (specify a DTMF
-	  digit to exit the application), it is not obvious in the
-	  documentation that this only works when spying on a channel. If a
-	  channel being used to spy on other channels is waiting to connect
-	  to a channel or is no longer attached to a channel, the DTMF is
-	  ignored. As noted on the issue tracker, since there are
-	  workarounds available and this is a rarely used option we are
-	  opting for a documentation change here. (closes issue
-	  ASTERISK-22661) Reported by: Chris Hillman Patches:
-	  asterisk-22661-doc-clarify-chan_spy.diff uploaded by Michael L.
-	  Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2990/ ........ Merged
-	  revisions 408536 from
+	* /, funcs/func_cdr.c, main/features.c, apps/app_disa.c,
+	  apps/app_chanspy.c: Coverity Report: Fix issues for error type
+	  UNINIT in Core supported modules (issue ASTERISK-19652) Reported
+	  by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1909/
+	  ........ Merged revisions 366048 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408537 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408538 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-20 21:12 +0000 [r408519-408523]  George Joseph <george.joseph at fairview5.com>
-
-	* /, res/res_pjsip/location.c,
-	  res/res_pjsip_outbound_registration.c: pjsip_cli: Add pjsip
-	  commands 'show registrations' and 'show contacts'. Added 'show
-	  registrations' and 'show contacts' to pjsip cli to make things a
-	  little more consistent. The output is exactly the same as the
-	  list command. Just needed to add entries to their respective
-	  ast_cli_entry structures. (closes issue ASTERISK-23275) Review:
-	  http://reviewboard.asterisk.org/r/3210/ ........ Merged revisions
-	  408522 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_cli.c, main/config.c: pjsip_cli: Fix
-	  memory leak in ast_sip_cli_print_sorcery_objectset. Fixed memory
-	  leaks in ast_sip_cli_print_sorcery_objectset and
-	  ast_variable_list_sort. (closes issue ASTERISK-23266) Review:
-	  http://reviewboard.asterisk.org/r/3200/ ........ Merged revisions
-	  408520 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/sorcery.h,
-	  res/res_pjsip/include/res_pjsip_private.h, res/res_pjsip.c,
-	  tests/test_sorcery.c, main/sorcery.c, /,
-	  res/res_pjsip/config_system.c: sorcery: Create sorcery instance
-	  registry. In order to retrieve an arbitrary sorcery instance from
-	  a dialplan function (or any place else) there needs to be a
-	  registry of sorcery instances. ast_sorcery_init now creates a
-	  hashtab as a registry. ast_sorcery_open now checks the hashtab
-	  for an existing sorcery instance matching the caller's module
-	  name. If it finds one, it bumps the refcount and returns it. If
-	  not, it creates a new sorcery instance, adds it to the hashtab,
-	  then returns it. ast_sorcery_retrieve_by_module_name is a new
-	  function that does a hashtab lookup by module name. It can be
-	  called by the future dialplan function. res_pjsip/config_system
-	  needed a small change to share the main res_pjsip sorcery
-	  instance. tests/test_sorcery was updated to include a test for
-	  the registry. (closes issue ASTERISK-22537) Review:
-	  http://reviewboard.asterisk.org/r/3184/ ........ Merged revisions
-	  408518 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-20 19:02 +0000 [r408503]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip.c, /: res_pjsip: Update documentation for
-	  'use_avpf' option When 'use_avpf' is set to True, inbound offers
-	  must use the AVPF/SAVPF RTP profile. However, when 'use_avpf' is
-	  set to False, Asterisk will accept both AVP/SAVP or AVPF/SAVPF
-	  RTP profiles in inbound offers. The documentation previously
-	  implied that Asterisk would reject AVPF/SAVPF if 'use_avpf' was
-	  set to False and a UA offered said profile in an INVITE request.
-	  ........ Merged revisions 408502 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-20 02:44 +0000 [r408450]  Rusty Newton <rnewton at digium.com>
-
-	* /, apps/app_queue.c: apps/app_queue - Fix incorrect Macro
-	  parameter documentation Macro is executed on the called channel,
-	  not the calling channel. (closes issue ASTERISK-23069) Reported
-	  By: Bryan Anderson ........ Merged revisions 408447 from
+	  revisions 366049 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, codecs/codec_dahdi.c: Block on frameout if the hardware has
+	  enough samples to complete a frame. Fixes some problems with
+	  skipping audio in elaborate scenarios involving multiple codecs
+	  by making codec_dahdi operate in a more synchronous fashion
+	  similar to codec_g729. This change also fixes the use of file
+	  conversion tools from Asterisk's CLI. This change may cause the
+	  thread responsible for transcoding audio to block briefly (Shaun
+	  Ruffell describes this as 'several milliseconds') while waiting
+	  for the hardware transcoder. (closes issue ASTERISK-19643)
+	  reported by: Shaun Ruffell Patches:
+	  0001-codec_dahdi-Block-on-frameout-the-hardware-has-enoug.patch
+	  uploaded by Shaun Ruffell (license 5417) ........ Merged
+	  revisions 365989 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408448 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408449 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 365990 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-09 19:26 +0000 [r366002]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* Makefile: pass BUILD_CFLGAS and BUILD_LDFLAGS to menuselect Allow
+	  menuselect to get its set of CFLAGS and LDFLAGS through the
+	  environment of Make: make BUILD_CFLAGS="whatever"
+	  BUILD_LDFLAGS="whatever" Review:
+	  https://reviewboard.asterisk.org/r/1907/
+
+2012-05-09 17:58 +0000 [r365951]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/followme.conf.sample, apps/app_followme.c: Improve
+	  FollowMe accept/decline DTMF string matching. If you hit the
+	  wrong DTMF digit trying to accept/decline a FollowMe call, you
+	  had to wait for the prompt to repeat to try again. * Make
+	  FollowMe compare the last DTMF digits received to the
+	  accept/decline matching strings.
+
+2012-05-09 16:36 +0000 [r365913]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Prevent sip_pvt refleak when an
+	  ast_channel outlasts its corresponding sip_pvt. chan_sip was
+	  coded under the assumption that a SIP dialog with an owner
+	  channel will always be destroyed after the owner channel has been
+	  hung up. However, there are situations where the SIP dialog can
+	  time out and auto destruct before the corresponding channel has
+	  hung up. A typical example of this would be if the 'h' extension
+	  in the dialplan takes a long time to complete. In such cases,
+	  __sip_autodestruct() would complain about the dialog being auto
+	  destroyed with an owner channel still in place. The problem is
+	  that even once the owner channel was hung up, the sip_pvt would
+	  still be linked in its ao2_container because nothing would ever
+	  unlink it. The fix for this is that if __sip_autodestruct() is
+	  called for a sip_pvt that still has an owner channel in place,
+	  the destruction is rescheduled for 10 seconds in the future. This
+	  will continue until the owner channel is finally hung up. (closes
+	  issue ASTERISK-19425) reported by David Cunningham Patches:
+	  ASTERISK-19425.patch uploaded by Mark Michelson (License #5049)
+	  (closes issue ASTERISK-19455) reported by Dean Vesvuio Tested by
+	  Dean Vesvuio ........ Merged revisions 365896 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365898 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-09 02:35 +0000 [r365766-365856]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/followme.conf.sample, UPGRADE.txt, apps/app_followme.c:
+	  Keep answered FollowMe calls until call accepted or last step
+	  times out.
+
+	* apps/app_followme.c: Put winning FollowMe outgoing call on hold
+	  if the caller put it on hold. The FollowMe caller call leg is
+	  usually answered and listening to MOH. The caller could put the
+	  call on hold while FollowMe is looking for a winner. The winning
+	  outgoing call is now immediately placed on hold if the caller has
+	  put the call on hold before the winning call was selected.
+
+	* apps/app_followme.c: Restructure how the FollowMe outgoing
+	  channel list is handled.
+
+	* apps/app_followme.c: Addendum to -r365766. Since it is no longer
+	  allocated.
+
+	* apps/app_followme.c: Make FollowMe findmeexec() put the list head
+	  on the stack instead of mallocing it. Why this tiny struct was
+	  malloced instead of the 28k struct in the last change is beyond
+	  me. Just doing my part to help stamp out sillyness.
+
+2012-05-08 21:46 +0000 [r365751]  Sean Bright <sean at malleable.com>
+
+	* apps/app_externalivr.c: Add interrupt ('I') command to
+	  ExternalIVR. Sending the 'I' command from an external process
+	  will cause the current playlist to be cleared, including stopping
+	  any audio file that is currently playing. This is useful when you
+	  want to interrupt audio playback only when specific DTMF is
+	  entered by the caller.
+
+2012-05-08 21:41 +0000 [r365633-365749]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_followme.c: Make FollowMe app_exec() not declare a 28k
+	  struct on the stack. Helping to stamp out stack abuse.
+
+	* apps/app_followme.c: Simplify findmeexec() parameter passing.
+
+	* /, apps/app_followme.c: * Fix FollowMe memory leak on error paths
+	  in app_exec(). * Fix FollowMe leaving recorded caller name file
+	  on error paths in app_exec(). * Use correct buffer dimension
+	  define in struct fm_args.namerecloc[]. This fixes unexpected
+	  namerecloc filename length restriction. ........ Merged revisions
+	  365692 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 365701 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_followme.c: * Fix accept/decline DTMF buffer
+	  overwrite in FollowMe. * Made use MAX_YN_STRING define to make
+	  all accept/decline DTMF buffers the same size. Just using 20
+	  isn't good enough when someone didn't get the memo. * Fix stupid
+	  use of a global variable in FollowMe. (ynlongest) * Fix bit field
+	  declarations in FollowMe. ........ Merged revisions 365631 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365632 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-08 15:57 +0000 [r365576]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Send more accurate identification
+	  information in dialog-info SIP NOTIFYs. This uses the calling
+	  channel's caller ID and connected line information to populate
+	  the remote and local identities in the dialog-info NOTIFY when an
+	  extension is ringing. There is a bit of an oddity here, and that
+	  is that we seed the remote target with the To header of the
+	  outbound call rather than the from header. This is because it was
+	  reported that seeding with the from header caused hints to be
+	  broken with certain SNOM devices. A comment has been added to the
+	  code to explain this. (closes issue ASTERISK-16735) reported by
+	  Maciej Krajewski patches: local_remote_hint2.diff uploaded by
+	  Mark Michelson (license #5049) 16735_tweak1.diff uploaded by Mark
+	  Michelson (license #5049) Tested by Niccolo Belli ........ Merged
+	  revisions 365574 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365575 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-19 19:09 +0000 [r408386-408390]  Richard Mudgett <rmudgett at digium.com>
+2012-05-07 20:08 +0000 [r365532]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, main/config.c: config: Add file size and nanosecond resolution
-	  fields to the cached modified config file information. Repeatedly
-	  modifying config files and reloading too fast sometimes fails to
-	  reload the configuration because the cached modification
-	  timestamp has one second resolution. * Added file size and
-	  nanosecond resolution fields to the cached config file
-	  modification timestamp information. Now if the file size changes
-	  or the file system supports nanosecond resolution the modified
-	  file has a better chance of being detected for reload. * Added a
-	  missing unlock in an off-nominal code path. (closes issue
-	  AST-1303) Review: https://reviewboard.asterisk.org/r/3235/
-	  ........ Merged revisions 408387 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408388 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408389 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_sorcery_astdb.c: res_sorcery_astdb.c: Fix regex
-	  handling and keep simple prefix matching performance. The sorcery
-	  astDB wizzard does not handle regex correctly if the pattern
-	  begins with an anchor character. This patch attempts to convert
-	  the anchored regex pattern to a prefix pattern supported by astDB
-	  for performance reasons. If it is not able to convert the pattern
-	  it falls back to getting all astDB members of the family and
-	  doing a normal regex pattern matching on the retrieved records.
-	  Review: https://reviewboard.asterisk.org/r/3161/ ........ Merged
-	  revisions 408385 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-19 12:04 +0000 [r408315-408332]  Alexandr Anikin <may at telecom-service.ru>
+	* main/features.c: Change comment to use local channel name
+	  designators in features.c
 
-	* addons/ooh323c/src/ooCapability.c, /,
-	  addons/ooh323c/src/ooh245.c: process receiveAndTransmit user
-	  input remote caps instead of receive only send receiveAndTransmit
-	  user input our caps instead of receive only ........ Merged
-	  revisions 408328 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408330 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408331 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-05-07 18:58 +0000 [r365480]  Matthew Jordan <mjordan at digium.com>
 
-	* addons/ooh323c/src/ooh323.c, /: Allow different socket and
-	  signalling ip on h.323 connection if gk mode is active Reported
-	  by: Gabriele Odone Patches: ASTERISK-22738-1.patch Tested by:
-	  Gabriele Odone (closes issue ASTERISK-22738) ........ Merged
-	  revisions 408312 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408314 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-18 19:19 +0000 [r408299]  Richard Mudgett <rmudgett at digium.com>
-
-	* contrib/ast-db-manage/config/env.py,
-	  contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py,
-	  contrib/ast-db-manage/config,
-	  contrib/ast-db-manage/voicemail/env.py,
-	  contrib/ast-db-manage/voicemail,
-	  contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py,
-	  contrib/ast-db-manage/config/versions,
-	  contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py,
-	  contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py,
-	  contrib/ast-db-manage/voicemail/versions, contrib/ast-db-manage,
-	  /: alembic: Add svn:ignore *.pyc to directories and
-	  svn:executable to *.py files. ........ Merged revisions 408297
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-17 15:36 +0000 [r408272]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip/location.c, UPGRADE.txt, res/res_pjsip.c,
-	  res/res_pjsip_registrar.c, include/asterisk/res_pjsip.h: Store
-	  SIP User-Agent information in contacts. When an endpoint sends a
-	  REGISTER request to Asterisk, we now will associate the
-	  User-Agent header with all contacts that were bound in that
-	  REGISTER request. ........ Merged revisions 408270 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-16 03:25 +0000 [r408199-408227]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/pbx.c: pbx: Handle a completely empty dialplan during a
-	  context merge It is highly unlikely, but - at least in Asterisk
-	  12 - theoretically possible to load Asterisk with no dialplan
-	  whatsoever. If that occurs, and some other module (that is not a
-	  pbx module) attempts to merge its contexts into the dialplan, the
-	  existing merge routine will crash. This is because it is not
-	  insane, and rightly believes that you provided some sort of
-	  dialplan, somewhere. This patch will gracefully merge the
-	  contexts in such a case. Note that this is highly unlikely to
-	  occur in 1.8/11, as features will most likely provide some
-	  dialplan via parking. However, in Asterisk 12, parking is now
-	  provided by res_parking, and hence may create its dialplan later.
-	  (closes issue ASTERISK-23297) Reported by: CJ Oster Review:
-	  https://reviewboard.asterisk.org/r/3222 ........ Merged revisions
-	  408200 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 408201 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408220 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/pbx.c, apps/app_voicemail.c: Fix channel opaquification
+	  slip-up in r365477 Those channels are opaque now...
 
-	* /, Makefile: buildsystem: Unbreak the build (infloop) on Asterisk
-	  11+ Apparently r408084 ( https://reviewboard.asterisk.org/r/3212/
-	  ) broke the build. This patch fixes it by ignoring the .lastclean
-	  dependencies if the MENUSELECT_EMBED variable is not defined.
-	  patches: tmp.diff uploaded by wdoekes (License 5674) Review:
-	  https://reviewboard.asterisk.org/r/3228/ ........ Merged
-	  revisions 408193 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408194 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-14 21:44 +0000 [r408139-408141]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/stasis_endpoints.c, /: ARI: correct upper/lower case URI
-	  discrepancies URI's are supposed to be case sensitive and all
-	  lower case. In practice some portions of URI's in ARI are case
-	  insensitive and others are not, such as TECH, which in one
-	  instance would match a lower case name and in another would not.
-	  In this patch, the ast_endpoint_lastest_snapshot() function is
-	  modified to change the TECH portion to full upper case before
-	  lookup. This resolves the discrepancy noted by the reporter.
-	  However I chose to avoid forcing the /ari prefix of the URI's to
-	  be lower case for now. Except for the two cases here, all URI's
-	  should be lower case, unless they are part of a resource name or
-	  id. Review: https://reviewboard.asterisk.org/r/3211/ Reported by:
-	  Zane Conkle (closes issue ASTERISK-23125) ........ Merged
-	  revisions 408140 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/format.c, /: format.c: correct possible null pointer
-	  dereference In ast_format_sdp_parse and ast_format_sdp_generate
-	  the check checks for a valid interface and function were
-	  potentially confusing, and hid an error in the test of the
-	  presence of the function that is called later. This patch clears
-	  up and corrects the test. Review:
-	  https://reviewboard.asterisk.org/r/3208/ (closes issue
-	  ASTERISK-23098) Reported by: marcelloceschia Patches:
-	  main_format.patch uploaded by marcelloceschia (license 6036)
-	  ASTERISK-23098.patch uploaded by coreyfarrell (license 5909)
-	  ........ Merged revisions 408137 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408138 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-05-07 18:51 +0000 [r365479]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, tests/test_config.c: Fix type punned compiler warning in
+	  test_config.c ........ Merged revisions 365476 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365478 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-07 18:42 +0000 [r365477]  Matthew Jordan <mjordan at digium.com>
+
+	* main/pbx.c, /, apps/app_voicemail.c: Support VoiceMail d() option
+	  when extension does not exist in channel's context The VoiceMail
+	  d([c]) option is documented to accept digits for a new extension
+	  in context <c>, if played during the greeting. This option works
+	  fine if the extension being redirected to has an extension with
+	  the same initial digit in the channel's current context. If that
+	  digit did not happen to exist in some extension, a dialplan match
+	  would fail and the user would not be redirected. This patch fixes
+	  it such that if the <c> option is used, the extensions are
+	  matched in that context as opposed to the caller's original
+	  context. (closes issue ASTERISK-18243) Reported by: mjordan
+	  Tested by: mjordan Review:
+	  https://reviewboard.asterisk.org/r/1892 ........ Merged revisions
+	  365474 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 365475 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-04 22:17 +0000 [r365400]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c, funcs/func_aes.c, main/features.c,
+	  apps/app_followme.c, channels/chan_iax2.c,
+	  channels/sip/config_parser.c, pbx/pbx_config.c,
+	  apps/app_chanspy.c, apps/app_stack.c, main/config.c,
+	  apps/app_voicemail.c: Fix many issues from the NULL_RETURNS
+	  Coverity report Most of the changes here are trivial NULL checks.
+	  There are a couple optimizations to remove the need to check for
+	  NULL and outboundproxy parsing in chan_sip.c was rewritten to
+	  avoid use of strtok. Additionally, a bug was found and fixed with
+	  the parsing of outboundproxy when "outboundproxy=," was set.
+	  (Closes issue ASTERISK-19654) ........ Merged revisions 365398
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 365399 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-04 17:38 +0000 [r365356]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_local.c, /: Fix local channel chains optimizing
+	  themselves out of a call. * Made chan_local.c:check_bridge()
+	  check the return value of ast_channel_masquerade(). In long
+	  chains of local channels, the masquerade occasionally fails to
+	  get setup because there is another masquerade already setup on an
+	  adjacent local channel in the chain. * Made the outgoing local
+	  channel (the ;2 channel) flush one voice or video frame per
+	  optimization attempt. * Made sure that the outgoing local channel
+	  also does not have any frames in its queue before the masquerade.
+	  * Made do the masquerade immediately to minimize the chance that
+	  the outgoing channel queue does not get any new frames added and
+	  thus unconditionally flushed. * Made block indication -1 (Stop
+	  tones) event when the local channel is going to optimize itself
+	  out. When the call is answered, a chain of local channels pass
+	  down a -1 indication for each bridge. This blizzard of -1 events
+	  really slows down the optimization process. (closes issue
+	  ASTERISK-16711) Reported by: Alec Davis Tested by: rmudgett, Alec
+	  Davis Review: https://reviewboard.asterisk.org/r/1894/ ........
+	  Merged revisions 365313 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365320 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-04 15:52 +0000 [r365300]  Mark Michelson <mmichelson at digium.com>
+
+	* res/res_rtp_asterisk.c, /: Fix core FINDING 2, FINDING 3, and
+	  FINDING 4 from Coverity's CONSTANT_EXPRESSION_RESULT report.
+	  These three all are in RTP code that attempts to print the number
+	  of sequence number cycles in an RTCP RR report. The code was
+	  masking out the upper 16 bits and then shifting the number right
+	  by 16 bits. This led to an all zero result in all cases. The fix
+	  is to do the shift without the bit masking. (issue
+	  ASTERISK-19649) ........ Merged revisions 365298 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365299 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-03 19:36 +0000 [r365248]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* tests/test_security_events.c: Update security events unit tests
+	  The security events framework API was changed in Asterisk 10 but
+	  the unit tests were not updated at the same time. This patch does
+	  the following: * Adds two more security events that were added to
+	  the API * Add challenge, received_challenge and received_hash in
+	  the inval_password security event unit test (Closes issue
+	  ASTERISK-19760) Reported by: Michael L. Young Tested by: Michael
+	  L. Young Patches: issue-asterisk-19760-trunk.diff uploaded by
+	  Michael L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/1897/
 
-2014-02-14 13:31 +0000 [r408086]  Walter Doekes <walter+asterisk at wjd.nu>
+2012-05-03 18:43 +0000 [r365213]  Sean Bright <sean at malleable.com>
 
-	* Makefile, /: buildsystem: Don't force main to depend on
-	  everything else. Directory 'main' only needs to depend on
-	  embedded modules. If no module embedding is selected, the
-	  dependency is dropped. Review:
-	  https://reviewboard.asterisk.org/r/3212/ ........ Merged
-	  revisions 408083 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 408084 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 408085 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-14 12:41 +0000 [r408070]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/chan_sip.c: chnan_sip: Set SIP_DEFER_BYE_ON_TRANSFER
-	  prior to calling bridge blind transfer This patch moves setting
-	  SIP_DEFER_BY_ON_TRANSFER prior to calling
-	  ast_bridge_transfer_blind. This prevents a BYE from being sent
-	  prior to the NOTIFY request that informs the transferor if the
-	  transfer succeeded or failed. This patch also clears said flag
-	  from the off nominal NOTIFY paths in the local_attended_transfer
-	  code, as once we've sent the NOTIFY request it is safe to send by
-	  the BYE request. This was caught by the
-	  blind-transfer-accountcode test in the Asterisk Test Suite.
-	  (closes issue ASTERISK-23290) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3214/ ........ Merged
-	  revisions 408069 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-14 08:52 +0000 [r408059]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* Makefile, build_tools/install_subst (added): install_subst:
-	  helper script for installing with path substitution A helper
-	  script to copy a source file substituting any
-	  __ASTERISK_<foo>_DIR__ with the content of $AST<foo>DIR. Review:
-	  https://reviewboard.asterisk.org/r/3202/
-
-2014-02-13 18:52 +0000 [r407990-408006]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pubsub.c, /, res/res_pjsip_mwi.c: Remove all PJSIP
-	  MWI-specific use from our MWI code. PJSIP has built-in MWI code
-	  that could be useful to some degree, but our utilization of the
-	  API actually made our code a bit more cluttered since we had to
-	  have special cases peppered throughout. With this change, we move
-	  to using the pjsip_evsub API instead, which streamlines the code
-	  by removing special cases. Review:
-	  https://reviewboard.asterisk.org/r/3205 ........ Merged revisions
-	  408005 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/location.c: Fix crash in AMI PJSIPShowEndpoint
-	  action. If an AOR has no permanent contacts, then the
-	  permanent_contacts container is never allocated. This makes the
-	  code safe in the face of NULLs. I also changed the variable that
-	  counts contacts from "num" to "total_contacts" since there are
-	  now two variables that are indicate numbers of things. ........
-	  Merged revisions 407988 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-13 15:51 +0000 [r407989]  Kinsey Moore <kmoore at digium.com>
-
-	* main/logger.c, CHANGES: Logger: Add dynamic logger channels This
-	  adds the ability to dynamically add and remove logger channels
-	  from Asterisk via the CLI. (closes issue AST-1150) Review:
-	  https://reviewboard.asterisk.org/r/3185/
-
-2014-02-12 08:25 +0000 [r407970]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /, main/config.c: realtime: Fix ast_update2_realtime() on
-	  raspberry pi. The old code depended on undefined va_arg
-	  behaviour: calling a function twice with the same va_list
-	  parameter and expecting it to continue where it left off. The
-	  changed code behaves like the manpage says it should. Also added
-	  a bunch of early returns to trap errors (e.g. OOM) instead of
-	  crashing. The problem was found by Julian Lyndon-Smith. The
-	  deviant behaviour on the raspberry PI also uncovered another bug
-	  (fixed in r407875) in the res_config_pgsql.so driver. Reported
-	  by: jmls Tested by: jmls Review:
-	  https://reviewboard.asterisk.org/r/3201/ ........ Merged
-	  revisions 407968 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-11 20:17 +0000 [r407958]  Joshua Colp <jcolp at digium.com>
-
-	* main/sched.c: scheduler: Remove hashtab usage. This is a first
-	  stab at tweaking the performance profile of the scheduler.
-	  Removing the hashtab usage removes an extra memory allocation
-	  when scheduling something and makes it so rescheduling does not
-	  incur any memory allocation at all. Review:
-	  https://reviewboard.asterisk.org/r/3199/
-
-2014-02-11 03:18 +0000 [r407940]  Matthew Jordan <mjordan at digium.com>
-
-	* res/ari/resource_channels.c, /: ari/resource_channels: Add
-	  channel variables earlier in the creation process This patch
-	  tweaks the behaviour of POST /channels with channel variables
-	  such that the variables are passed into the pbx.c routines that
-	  perform the origination. This allows the variables to be assigned
-	  to the newly created channels immediately upon their
-	  construction, as opposed to be assigned after the originate has
-	  completed. The upshot of this is that the variables are available
-	  on the channels if they execute in the dialplan, as opposed to
-	  only being available once the channels are answered. Review:
-	  https://reviewboard.asterisk.org/r/3183/ ........ Merged
-	  revisions 407937 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-10 18:28 +0000 [r407926]  Corey Farrell <git at cfware.com>
-
-	* channels/sip/include/reqresp_parser.h,
-	  channels/sip/include/route.h (added), channels/chan_sip.c,
-	  channels/sip/route.c (added), channels/sip/include/sip.h:
-	  chan_sip: Isolate code that manages struct sip_route. * Move
-	  route code to sip/route.c + sip/include/route.h * Rename
-	  functions to sip_route_* * Replace ad-hoc list code with macro's
-	  from linkedlists.h * Create sip_route_process_header() to
-	  processes Path and Record-Route headers (previously done with
-	  different code in build_route and build_path) * Add use of const
-	  where possible * Move struct uriparams, struct contact and
-	  contactliststruct from sip.h to reqresp_parser.h. sip/route.c
-	  uses reqresp_parser.h but not sip.h, this was a problem. These
-	  moved declares are not used outside of reqresp_parser. * While
-	  modifying reqprep() the lack of {} caused me trouble. I added
-	  them. * Code outside route.c treats sip_route as an opaque
-	  structure, using macro's or procedures for all access. (closes
-	  issue ASTERISK-22582) Reported by: Corey Farrell Review:
-	  https://reviewboard.asterisk.org/r/3173/
-
-2014-02-10 16:49 +0000 [r407876]  Walter Doekes <walter+asterisk at wjd.nu>
+	* CHANGES: Update documentation references in CHANGES to reflect
+	  the correct pages on the wiki. The current CHANGES file refers to
+	  doc/ in many places and those files no longer exist.
 
-	* res/res_config_pgsql.c, /: res_config_pgsql: Fix
-	  ast_update2_realtime calls. Fix so multiple updates from a single
-	  call works (add missing ','). Remove bogus ast_free's that
-	  weren't supposed to be there. Moved a few spaces for readability.
-	  Review: https://reviewboard.asterisk.org/r/3194/ ........ Merged
-	  revisions 407873 from
+2012-05-03 15:05 +0000 [r365161]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooh323.c, /,
+	  addons/ooh323c/src/h323/H323-MESSAGES.h,
+	  addons/ooh323c/src/h323/H323-MESSAGESEnc.c: Fix warning of
+	  Coverity Static analysis, change H225ProtocolIdentifier from
+	  value to pointer per functions that use this. (close issue
+	  ASTERISK-19670) Reported by: Matt Jordan Patches:
+	  ASTERISK-19670.patch (License #5415) ........ Merged revisions
+	  365159 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 365160 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-03 14:47 +0000 [r365158]  Sean Bright <sean at malleable.com>
+
+	* apps/app_externalivr.c, CHANGES: Add IPv6 support to ExternalIVR.
+	  Review: https://reviewboard.asterisk.org/r/1896/
+
+2012-05-03 14:35 +0000 [r365157]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/ooq931.c: Fix coverity static analysis
+	  warning, allocate full ie structure instead of without data
+	  buffer (close issue ASTERISK-19674) Reported by: Matt Jordan
+	  Patches: ASTERISK-19674.patch (License #5415) ........ Merged
+	  revisions 365143 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365155 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-02 17:43 +0000 [r365084]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_local.c, /, main/cel.c: Multiple revisions
+	  365006,365068 ........ r365006 | twilson | 2012-05-02 10:49:03
+	  -0500 (Wed, 02 May 2012) | 12 lines Fix a CEL LINKEDID_END race
+	  and local channel linkedids This patch has the ;2 channel inherit
+	  the linkedid of the ;1 channel and fixes the race condition by no
+	  longer scanning the channel list for "other" channels with the
+	  same linkedid. Instead, cel.c has an ao2 container of linkedid
+	  strings and uses the refcount of the string as a counter of how
+	  many channels with the linkedid exist. Not only does this
+	  eliminate the race condition, but it also allows us to look up
+	  the linkedid by the hashed key instead of traversing the entire
+	  channel list. Review: https://reviewboard.asterisk.org/r/1895/
+	  ........ r365068 | twilson | 2012-05-02 12:02:39 -0500 (Wed, 02
+	  May 2012) | 11 lines Don't leak a ref if out of memory and can't
+	  link the linkedid If the ao2_link fails, we are most likely out
+	  of memory and bad things are going to happen. Before those bad
+	  things happen, make sure to clean up the linkedid references.
+	  This patch also adds a comment explaining why linkedid can't be
+	  passed to both local channel allocations and combines two ao2_ref
+	  calls into 1. Review: https://reviewboard.asterisk.org/r/1895/
+	  ........ Merged revisions 365006,365068 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 365083 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-02 15:59 +0000 [r365011]  Jason Parker <jparker at digium.com>
+
+	* channels/chan_sip.c: Save the address on which a MESSAGE was
+	  received, so it can be used in MESSAGE() This is useful in cases
+	  where chan_sip may be listening on multiple addresses.
+
+2012-05-02 02:51 +0000 [r364966]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/audiohook.c: Only log a failure to get read/write samples
+	  from factories if it didn't happen In audiohook_read_frame_both,
+	  anytime samples are obtained from the read/write factories a
+	  debug statement is logged stating that samples were not obtained
+	  from the factories. This statement used to only occur if
+	  option_debug was turned on and no samples were obtained; in some
+	  refactoring when the option_debug statement was removed, the
+	  "else" clause was removed as well. This patch makes it so that
+	  those debug log statements only occur if the condition leading up
+	  to them actually happened. ........ Merged revisions 364965 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-01 23:23 +0000 [r364915]  Mark Michelson <mmichelson at digium.com>
+
+	* channels/chan_sip.c: Remove a function that has been marked
+	  unused since Asterisk 1.6.0. The reason I'm removing this is that
+	  Coverity reported a STRAY_SEMICOLON issue here. Since the
+	  function has been unused for so long, I just elected to remove it
+	  altogether. (closes issue ASTERISK-19660)
+
+2012-05-01 23:21 +0000 [r364910]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/astobj2.c: Fixed __ao2_ref() validating user_data twice.
+	  (closes issue ASTERISK-19755) Reported by: Gunther Kelleter
+	  Patches: ao2_ref.patch (license #6372) patch uploaded by Gunther
+	  Kelleter ........ Merged revisions 364902 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407874 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407875 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 364903 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-05-01 23:11 +0000 [r364901]  Mark Michelson <mmichelson at digium.com>
+
+	* /, funcs/func_volume.c: Fix Coverity-reported ARRAY_VS_SINGLETON
+	  error. As it turned out, this wasn't a huge deal. We were calling
+	  ast_app_parse_options() for a set of options of which none took
+	  arguments. The proper thing to do for this case is to pass NULL
+	  for the "args" parameter here. We were instead passing a
+	  seemingly-randomly chosen char * from the function. While this
+	  would never get written to, you can rest assured things would
+	  have gotten bad had new options (which took arguments) been added
+	  to func_volume. (closes issue ASTERISK-19656) ........ Merged
+	  revisions 364899 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364900 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-10 16:01 +0000 [r407859]  Kinsey Moore <kmoore at digium.com>
+2012-05-01 22:00 +0000 [r364846]  Richard Mudgett <rmudgett at digium.com>
 
-	* apps/app_confbridge.c, apps/confbridge/conf_state_multi_marked.c,
-	  apps/confbridge/conf_state_empty.c,
-	  apps/confbridge/conf_config_parser.c,
-	  configs/confbridge.conf.sample, /,
-	  apps/confbridge/include/confbridge.h, UPGRADE.txt: ConfBridge:
-	  Correct prompt playback target Currently, when the first marked
-	  user enters the conference that contains waitmarked users, a
-	  prompt is played indicating that the user is being placed into
-	  the conference. Unfortunately, this prompt is played to the
-	  marked user and not the waitmarked users which is not very
-	  helpful. This patch changes that behavior to play a prompt
-	  stating "The conference will now begin" to the entire conference
-	  after adding and unmuting the waitmarked users since the design
-	  of confbridge is not conducive to playing a prompt to a subset of
-	  users in a conference in an asynchronous manner. (closes issue
-	  PQ-1396) Review: https://reviewboard.asterisk.org/r/3155/
-	  Reported by: Steve Pitts ........ Merged revisions 407857 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407858 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-07 20:52 +0000 [r407767]  Richard Mudgett <rmudgett at digium.com>
+	* channels/chan_local.c, /: * Fix error path resouce leak in
+	  local_request(). * Restructure local_request() to reduce
+	  indentation. ........ Merged revisions 364840 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364845 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_iax2.c: chan_iax2: Add some more iaxs[] NULL
-	  checks to a routine already full of them. ........ Merged
-	  revisions 407764 from
+2012-05-01 21:49 +0000 [r364844]  Jason Parker <jparker at digium.com>
+
+	* main/manager.c, /: Prevent a potential crash when using manager
+	  hooks. Found by me while poking at DPMA-127. ........ Merged
+	  revisions 364841 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407765 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407766 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-07 20:17 +0000 [r407752]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/security_events.c: security_events: Fix assertion failure
-	  in dev-mode on optional IE parsing When formatting an optional
-	  IE, the value is, of course, optional. As such, it is entirely
-	  appropriate for ast_json_object_get to return NULL. If that
-	  occurs, we now simply skip the IE that was requested, as it was
-	  not provided by the entity that raised the event. Thanks to
-	  George Joseph (gtjoseph) for catching this and reporting it in
-	  #asterisk-dev ........ Merged revisions 407750 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-07 20:01 +0000 [r407749]  Joshua Colp <jcolp at digium.com>
-
-	* main/timing.c, res/res_timing_pthread.c, res/res_timing_dahdi.c,
-	  res/res_timing_timerfd.c, include/asterisk/timing.h,
-	  res/res_timing_kqueue.c: timing: Improve performance for most
-	  timing implementations. This change allows timing implementation
-	  data to be stored directly on the timer itself thus removing the
-	  requirement for many implementations to do a container lookup for
-	  the same information. This means that API calls into timing
-	  implementations can directly access the information they need
-	  instead of having to find it. Review:
-	  https://reviewboard.asterisk.org/r/3175/
-
-2014-02-07 19:40 +0000 [r407748]  Matthew Jordan <mjordan at digium.com>
-
-	* /, funcs/func_cdr.c: funcs/func_cdr: Handle empty time values
-	  when extracting parsed values When extracting timestamps that are
-	  parsed, time stamp values that are not set (time values of
-	  0.000000) should not actually result in a parsed string. The
-	  value should be skipped, and the result of the CDR function
-	  should be an empty string. Prior to this patch, the result was
-	  fed to the time formatting, which would result in an output of a
-	  date/time in 1969. ........ Merged revisions 407747 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-07 18:29 +0000 [r407731]  Richard Mudgett <rmudgett at digium.com>
+	  revisions 364842 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_iax2.c, include/asterisk/frame.h,
-	  configs/iax.conf.sample, /: chan_iax2: Block unnecessary control
-	  frames to/from the wire. Establishing an IAX2 call between
-	  Asterisk v1.4 and v1.8 (or later) results in an unexpected call
-	  disconnect. The problem happens because newer values in the enum
-	  ast_control_frame_type are not consistent between the branch
-	  versions of Asterisk. For example: 1) v1.4 calls v1.8 (or later)
-	  using IAX2 2) v1.8 answers and sends a connected line update
-	  control frame. (on v1.8 AST_CONTROL_CONNECTED_LINE = 22) 3) v1.4
-	  receives the control frame as an end-of-q (on v1.4
-	  AST_CONTROL_END_OF_Q = 22) 4) v1.4 disconnects the call once the
-	  receive queue becomes empty. Several things are done by this
-	  patch to fix the problem and attempt to prevent it from happening
-	  again in the future: * Added a warning at the definition of enum
-	  ast_control_frame_type about how to add new control frame values.
-	  * Made block sending and receiving control frames that have no
-	  reason to go over the wire. * Extended the connectedline iax.conf
-	  parameter to also include the redirecting information updates. *
-	  Updated the connectedline iax.conf parameter documentation to
-	  include a notice that the parameter must be "no" when the peer is
-	  an Asterisk v1.4 instance. (closes issue AST-1302) Review:
-	  https://reviewboard.asterisk.org/r/3174/ ........ Merged
-	  revisions 407678 from
+2012-05-01 19:10 +0000 [r364788]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_confbridge.c: Play conf-placeintoconf message to the
+	  correct channel Correct the code in app_confbridge to play the
+	  conf-placeintoconf message to the marked user entering the bridge
+	  instead of to the conference while the marked user hears silence.
+	  (closes issue ASTERISK-19641) Reported-by: Mark A Walters
+	  ........ Merged revisions 364786 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407727 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407729 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 364787 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-07 16:47 +0000 [r407677]  Matthew Jordan <mjordan at digium.com>
+2012-05-01 18:29 +0000 [r364785]  Jonathan Rose <jrose at digium.com>
 
-	* /, main/security_events.c: security_events: Fix error caused by
-	  DTD validation error The appdocsxml.dtd specifies that a
-	  "required" attribute in a parameter may have a value of yes, no,
-	  true, or false. On some systems, specifying "False" instead of
-	  "false" would cause a validation error. This patch fixes the
-	  casing to explicitly match the DTD. ........ Merged revisions
-	  407676 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, main/app.c: Fix bad check in voicemail functions for
+	  ast_inboxcount2_func Check looks for ast_inboxcount_func instead
+	  of ast_inboxcount2_func on ast_inboxcount2_func calls. (closes
+	  issue ASTERISK-19718) Reported by: Corey Farrell Patches:
+	  ast_app_inboxcount2-null-refcheck.patch uploaded by Corey Farrell
+	  (license 5909) ........ Merged revisions 364769 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364777 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-30 19:51 +0000 [r364708]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Revert revision 360862. Revision 360862
+	  was intended to improve identities sent in dialog-info NOTIFY
+	  requests. Some users reported that hint became broken once this
+	  was done. It's not clear exactly what part of the patch has
+	  caused this regression, but broken hints are bad. For now, this
+	  revision is being reverted so that the next releases of Asterisk
+	  do not have bad behavior in them. The original reported issue
+	  will have to be fixed differently in the next version of
+	  Asterisk. (issue ASTERISK-16735) ........ Merged revisions 364706
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 364707 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-30 17:17 +0000 [r364654]  Mark Murawki <markm at intellasoft.net>
+
+	* /, main/logger.c: Merged revisions 364635 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r364635 | markm | 2012-04-30 11:51:12 -0400 (Mon, 30 Apr 2012) |
+	  10 lines Sanatize result from bfd_find_nearest_line
+	  (BETTER_BACKTRACES) bfd_find_nearest_line can possibly set file
+	  to null resulting in a crash when strrchr(file) runs (closes
+	  issue ASTERISK-19815) Reported by Mark Murawski Tested by Mark
+	  Murawski ........ ........ Merged revisions 364650 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-30 16:59 +0000 [r364652]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323cDriver.c: Fix use freed pointer in return value
+	  from call thread (issue ASTERISK-19663) Reported by: Matt Jordan
+	  Patches: ASTERISK-19663-ooh323.patch (License #5415) ........
+	  Merged revisions 364649 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364651 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-29 19:50 +0000 [r364580]  Matthew Jordan <mjordan at digium.com>
+
+	* formats/format_ilbc.c, /, formats/format_sln.c,
+	  formats/format_vox.c, formats/format_wav.c, formats/format_pcm.c,
+	  formats/format_g723.c, formats/format_h263.c,
+	  formats/format_h264.c, formats/format_wav_gsm.c,
+	  formats/format_siren14.c, formats/format_gsm.c,
+	  formats/format_g719.c, formats/format_siren7.c,
+	  formats/format_g729.c: Fix error that caused truncate operations
+	  to fail Another very inappropriate placement of a ')' (again
+	  introduced in r362151) caused the various truncate operations to
+	  attempt to truncate the sound file at a position of '0'. (issue
+	  ASTERISK-19655) Reported by: Matt Jordan (issue ASTERISK-19810)
+	  Reported by: colbec ........ Merged revisions 364578 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364579 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-29 02:23 +0000 [r364537]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, apps/confbridge/conf_config_parser.c: Fix configuring custom
+	  sound_leader_has_left in confbridge.conf The configuration option
+	  to specify a custom sound_leader_has_left file for a conference
+	  bridge was not being parsed. This patch fixes it so that a custom
+	  sound file will now be used. (closes issue ASTERISK-19771)
+	  Reported by: Pawel Kuzak Tested by: Pawel Kuzak, Michael L. Young
+	  Patches: leaderhasleft_sound.dpatch uploaded by Pawel Kuzak
+	  (license 6380) Review: https://reviewboard.asterisk.org/r/1884/
+	  ........ Merged revisions 364536 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-28 20:24 +0000 [r364500]  Joshua Colp <jcolp at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample, CHANGES,
+	  channels/sip/include/sip.h: Add support for lightweight NAT
+	  keepalive. If enabled using the keepalive option in sip.conf a
+	  small packet will be sent at a regular interval to keep the NAT
+	  mapping open. This is lightweight as the remote side does not
+	  need to parse and handle a SIP message. (closes issue AST-783)
+	  Review: https://reviewboard.asterisk.org/r/1756/
+
+2012-04-28 01:33 +0000 [r364437-364462]  Russell Bryant <russell at russellbryant.com>
+
+	* main/md5.c: md5: supress some compiler warnings. md5.c: In
+	  function ‘MD5Final’: md5.c:154:2: error: dereferencing
+	  type-punned pointer will break strict-aliasing rules
+	  [-Werror=strict-aliasing] md5.c:155:2: error: dereferencing
+	  type-punned pointer will break strict-aliasing rules
+	  [-Werror=strict-aliasing] There is an md5 unit test and it still
+	  passes.
+
+	* configure, include/asterisk/autoconfig.h.in, res/res_corosync.c,
+	  configure.ac: res_corosync: Fix build against corosync 2.0.
+
+	* apps/app_minivm.c: app_minivm: Fix a couple compiler warnings.
+	  The warnings were about argv[0] being used uninitialized, which
+	  is correct. Just remove setting username to this value, since
+	  username is set again before it actually gets used.
+
+	* main/features.c, CHANGES: features: Add FEATURE() and
+	  FEATUREMAP() functions. Add two new dialplan functions: FEATURE()
+	  and FEATUREMAP(). FEATURE() lets you set some of the
+	  configuration options from the [general] section of features.conf
+	  on a per-channel basis. FEATUREMAP() lets you customize the key
+	  sequence used to activate built-in features, such as blindxfer,
+	  and automon. See the built-in documentation for details. Review:
+	  https://reviewboard.asterisk.org/r/1871/
+
+2012-04-28 00:31 +0000 [r364436]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, CHANGES: PreDial - Ability to run dialplan on
+	  callee and caller channels before Dial. Thanks to Mark Murawski
+	  for the initial patch and feature definition. (closes issue
+	  ASTERISK-19548) Reported by: Mark Murawski Review:
+	  https://reviewboard.asterisk.org/r/1878/ Review:
+	  https://reviewboard.asterisk.org/r/1229/
+
+2012-04-27 22:54 +0000 [r364397]  Terry Wilson <twilson at digium.com>
+
+	* /, tests/test_config.c (added), main/config.c: Multiple revisions
+	  364365,364369 ........ r364365 | twilson | 2012-04-27 17:31:01
+	  -0500 (Fri, 27 Apr 2012) | 11 lines Fix ast_parse_arg numeric
+	  type range checking and add tests ast_parse_arg wasn't checking
+	  for strto* parse errors or limiting the results by the actual
+	  range of the numeric types. This patch fixes that and adds unit
+	  tests as well. Review: https://reviewboard.asterisk.org/r/1879/
+	  ........ Merged revisions 364340 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  r364369 | twilson | 2012-04-27 17:33:10 -0500 (Fri, 27 Apr 2012)
+	  | 2 lines Add missing test_config.c ........ Merged revisions
+	  364365,364369 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-27 22:11 +0000 [r364343]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Don't attempt to make use of the
+	  dynamic_exclude_static ACL if DNS lookup fails. (closes issue
+	  ASTERISK-18321) Reported by Dan Lukes Patches:
+	  ASTERISK-18321.patch by Mark Michelson (license #5049) ........
+	  Merged revisions 364341 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364342 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-27 19:30 +0000 [r364287]  Matthew Jordan <mjordan at digium.com>
+
+	* /, include/asterisk/time.h: Prevent overflow in calculation in
+	  ast_tvdiff_ms on 32-bit machines The method ast_tvdiff_ms
+	  attempts to calculate the difference, in milliseconds, between
+	  two timeval structs, and return the difference in a 64-bit
+	  integer. Unfortunately, it assumes that the long tv_sec/tv_usec
+	  members in the timeval struct are large enough to hold the
+	  calculated values before it returns. On 64-bit machines, this
+	  might be the case, as a long may be 64-bits. On 32-bit machines,
+	  however, a long may be less (32-bits), in which case, the
+	  calculation can overflow. This overflow caused significant
+	  problems in MixMonitor, which uses the method to determine if an
+	  audio factory, which has not presented audio to an audiohook, is
+	  merely late in providing said audio or will never provide audio.
+	  In an overflow situation, the audiohook would incorrectly
+	  determine that an audio factory that will never provide audio is
+	  merely late instead. This led to situations where a MixMonitor
+	  never recorded any audio. Note that this happened most frequently
+	  when that MixMonitor was started by the ConfBridge application
+	  itself, or when the MixMonitor was attached to a Local channel.
+	  (issue ASTERISK-19497) Reported by: Ben Klang Tested by: Ben
+	  Klang Patches: 32-bit-time-overflow-10-2012-04-26.diff (license
+	  #6283) by mjordan (closes issue ASTERISK-19727) Reported by: Mark
+	  Murawski Tested by: Michael L. Young Patches:
+	  32-bit-time-overflow-2012-04-27.diff (license #6283) by mjordan)
+	  (closes issue ASTERISK-19471) Reported by: feyfre Tested by:
+	  feyfre (issue ASTERISK-19426) Reported by: Johan Wilfer Review:
+	  https://reviewboard.asterisk.org/r/1889/ ........ Merged
+	  revisions 364277 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364285 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-27 18:59 +0000 [r364260]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Allow SIP pvts involved in Replaces
+	  transfers to fall out of reference sooner Unref the SIP pvt
+	  stored in the refer structure as soon as it is no longer needed
+	  so that the pvt and associated file descriptors can be freed
+	  sooner. This change makes a reference decrement unnecessary in
+	  code that handles SIP BYE/Also transfers which should not touch
+	  the reference anyway. (Closes issue ASTERISK-19579) Reported by:
+	  Maciej Krajewski Tested by: Maciej Krajewski ........ Merged
+	  revisions 364258 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364259 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-27 14:45 +0000 [r364205]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Allow for reloading SRTP crypto keys
+	  within the same SIP dialog As a continuation of the patch in
+	  r356604, which allowed for the reloading of SRTP keys in
+	  re-INVITE transfer scenarios, this patch addresses the more
+	  common case where a new key is requested within the context of a
+	  current SIP dialog. This can occur, for example, when certain
+	  phones request a SIP hold. Previously, once a dialog was
+	  associated with an SRTP object, any subsequent attempt to process
+	  crypto keys in any SDP offer - either the current one or a new
+	  offer in a new SIP request - were ignored. This patch changes
+	  this behavior to only ignore subsequent crypto keys within the
+	  current SDP offer, but allows future SDP offers to change the
+	  keys. (issue ASTERISK-19253) Reported by: Thomas Arimont Tested
+	  by: Thomas Arimont Review:
+	  https://reviewboard.asteriskorg/r/1885/ ........ Merged revisions
+	  364203 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 364204 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-27 12:58 +0000 [r364164]  Stefan Schmidt <sst at sil.at>
+
+	* res/res_calendar_icalendar.c, /, res/res_calendar_caldav.c: fix a
+	  wrong behavior of alarm timezones in caldav and icalendar when an
+	  alarm doesnt use utc. This change uses the same timezone from the
+	  start time. ........ Merged revisions 364163 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-26 21:11 +0000 [r364082-364110]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_directed_pickup.c: Update Pickup application
+	  documentation. (With feeling this time.) ........ Merged
+	  revisions 364108 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364109 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/features.c: Fix DTMF atxfer running h exten after the
+	  wrong bridge ends. When party B does an attended transfer of
+	  party A to party C, the attending bridge between party B and C
+	  should not be running an h exten when the bridge ends. Running an
+	  h exten now sets a softhangup flag to ensure that an AGI will run
+	  in dead AGI mode. * Set the AST_FLAG_BRIDGE_HANGUP_DONT on the
+	  party B channel for the attending bridge between party B and C.
+	  (closes issue AST-870) (closes issue ASTERISK-19717) Reported by:
+	  Mario (closes issue ASTERISK-19633) Reported by: Andrey Solovyev
+	  Patches: jira_asterisk_19633_v1.8.patch (license #5621) patch
+	  uploaded by rmudgett Tested by: rmudgett, Andrey Solovyev, Mario
+	  ........ Merged revisions 364060 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 364065 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-07 13:15 +0000 [r407625]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+2012-04-26 19:33 +0000 [r364048]  Terry Wilson <twilson at digium.com>
 
-	* /, configs/indications.conf.sample: indications.conf: add stutter
-	  tone; end properly * If the "stutter" (voicemail indication) tone
-	  is indeed a stutter tone, and it ends with a constant tone, make
-	  sure that it is the dial tone. This was done for India (in),
-	  Mexico (mx) and the Philippines (ph). * If no "stutter" tone
-	  exists for a country, provide one. This was done for Spain (es),
-	  Malaysia (my) and Venezuela (ve). Review:
-	  https://reviewboard.asterisk.org/r/3158/ ........ Merged
-	  revisions 407622 from
+	* /, main/asterisk.c: Add more constness to the end_buf pointer in
+	  the netconsole issue ASTERISK-18308 Review:
+	  https://reviewboard.asterisk.org/r/1876/ ........ Merged
+	  revisions 364046 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407623 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407624 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-06 21:24 +0000 [r407602]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/security_events.c, UPGRADE.txt, CHANGES: security_events:
-	  Add AMI documentation; output optional fields This patch adds
-	  documentation for the Security Events that are emited over AMI.
-	  It also notes these events in the UPGRADE/CHANGES file. ........
-	  Merged revisions 407589 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-06 19:58 +0000 [r407588]  Rusty Newton <rnewton at digium.com>
-
-	* /, configs/pjsip.conf.sample: configs/pjsip.conf.sample:
-	  Configuration section naming in pjsip.conf.sample needs a little
-	  clarification There is a bit of nuance to how you name things in
-	  pjsip.conf. This is a documentation patch to at least clear it up
-	  a little for users. Review:
-	  https://reviewboard.asterisk.org/r/3180/ ........ Merged
-	  revisions 407587 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-06 18:11 +0000 [r407574]  Kevin Harwell <kharwell at digium.com>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py:
-	  pjsip realtime: already created enum failure for postgresql If an
-	  enum had been previously created the alembic script would attempt
-	  to re-create it and an error would be generated while running
-	  migrations for a postgresql server. The work around for this is
-	  to use the ENUM object type for postgres as opposed to the
-	  generic enum type used by sqlalchemy. Using this type in the
-	  script seems to work properly for both postgres and mysql.
-	  ........ Merged revisions 407572 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-06 17:55 +0000 [r407573]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_pjsip_logger.c,
-	  res/res_pjsip/include/res_pjsip_private.h,
-	  res/res_pjsip/pjsip_options.c, res/res_pjsip/config_transport.c,
-	  include/asterisk/res_pjsip.h, res/res_pjsip/config_global.c,
-	  res/res_pjsip/config_auth.c, /, res/res_pjsip/location.c,
-	  res/res_pjsip_outbound_registration.c,
-	  res/res_pjsip_endpoint_identifier_ip.c,
-	  include/asterisk/res_pjsip_cli.h, res/res_pjsip/pjsip_cli.c,
-	  res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/config_domain_aliases.c: res_pjsip: Updates and
-	  adds more PJSIP CLI commands. * Adds identify, transport, and
-	  registration support to the PJSIP CLI. * Creates three additional
-	  callbacks, one for an iterator, one for a comparator, and one for
-	  a container. This eliminates the link dependency from higher
-	  level modules to lower level ones. * Eliminates duplicate sorting
-	  in PJSIP CLI commands. * Cleans up PJSIP CLI output formatting. *
-	  Pushes CLI command registration down to the implementing source
-	  file. * Adds several ast_sip_destroy_sorcery functions to
-	  complement existing ast_sip_sorcery_initialize functions. The
-	  destroy functions unregister PJSIP CLI commands and PJSIP CLI
-	  formatters. Reported by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3104/ ........ Merged
-	  revisions 407568 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-05 23:04 +0000 [r407514]  Rusty Newton <rnewton at digium.com>
+	  revisions 364047 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, formats/format_wav.c: formats/format_wav: enhancing log
-	  message "Not a wav file" to be clear on what is supported
-	  Modifying the log message to be more specific as to what is
-	  supported. Specifically it seems format_wav supports only PCM
-	  encoded versions with a lower-case '.wav' extension. (closes
-	  issues ASTERISK-22310) Reported by: Jim Credland Review:
-	  https://reviewboard.asterisk.org/r/3188/ ........ Merged
-	  revisions 407511 from
+2012-04-26 13:59 +0000 [r363989]  Olle Johansson <oej at edvina.net>
+
+	* apps/app_queue.c: Code formatting fixes.
+
+2012-04-26 13:31 +0000 [r363988]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Fix reference leaks involving SIP
+	  Replaces transfers The reference held for SIP blind transfers
+	  using the Replaces header in an INVITE was never freed on success
+	  and also failed to be freed in some error conditions. This caused
+	  a file descriptor leak since the RTP structures in use at the
+	  time of the transfer were never freed. This reference leak and
+	  another relating to subscriptions in the same code path have now
+	  been corrected. (closes issue ASTERISK-19579) ........ Merged
+	  revisions 363986 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407512 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407513 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 363987 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-26 09:48 +0000 [r363936]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_sip.c: chan_sip: [general] maxforwards, not
+	  checked for a value greater than 255 The peer maxforwards is
+	  checked for both '< 1' and '> 255', but the default 'maxforwards'
+	  in the [general] section is only checked for '< 1' alecdavis
+	  (license 585) Reported by: alecdavis Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1888/ ........ Merged
+	  revisions 363934 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363935 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-05 20:56 +0000 [r407462]  Jonathan Rose <jrose at digium.com>
+2012-04-26 03:12 +0000 [r363689-363877]  Richard Mudgett <rmudgett at digium.com>
 
-	* CHANGES, /: CHANGES: Improved description of Name/Creator changes
-	  to bridge ARI, adds AMI The changes log was written with language
-	  that was a little too internal Asterisk specific, so it's been
-	  changed to be more in the frame of reference of an ARI user.
-	  Also, previously the AMI event changes were omitted from the
-	  change log as well as the ability to include a bridge name in the
-	  ARI post bridges command. ........ Merged revisions 407461 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, apps/app_directed_pickup.c: Update Pickup application
+	  documentation. (Even better) ........ Merged revisions 363875
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 363876 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-05 20:43 +0000 [r407459]  Kinsey Moore <kmoore at digium.com>
+	* apps/app_directed_pickup.c: * Put more information in
+	  pickup_exec() LOG_NOTICE. * Delay duplicating a string on the
+	  stack in pickup_exec().
 
-	* main/logger.c, /: Logger: Fix handling of absolute paths This
-	  fixes path handling for log files so that an extra / is not
-	  appended to the file path when the path is absolute (begins with
-	  /). This would previously result in different but functionally
-	  equivalent paths in the output of 'logger show channels'.
-	  ........ Merged revisions 407455 from
+	* /, apps/app_directed_pickup.c: Update Pickup application
+	  documentation. ........ Merged revisions 363788 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363789 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c, /, channels/sig_pri.c: Make
+	  DAHDISendCallreroutingFacility wait 5 seconds for a reply before
+	  disconnecting the call. Some switches may not handle the
+	  call-deflection/call-rerouting message if the call is
+	  disconnected too soon after being sent. Asteisk was not waiting
+	  for any reply before disconnecting the call. * Added a 5 second
+	  delay before disconnecting the call to wait for a potential
+	  response if the peer does not disconnect first. (closes issue
+	  ASTERISK-19708) Reported by: mehdi Shirazi Patches:
+	  jira_asterisk_19708_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: rmudgett ........ Merged revisions 363730
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 363734 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sig_pri.h, channels/chan_dahdi.c, /, channels/sig_pri.c:
+	  Clear ISDN channel resetting state if the peer continues to use
+	  it. Some ISDN switches occasionally fail to send a RESTART
+	  ACKNOWLEDGE in response to a RESTART request. * Made the second
+	  SETUP received after sending a RESTART request clear the channel
+	  resetting state as if the peer had sent the expected RESTART
+	  ACKNOWLEDGE before continuing to process the SETUP. The peer may
+	  not be sending the expected RESTART ACKNOWLEDGE. (issue
+	  ASTERISK-19608) (issue AST-844) (issue AST-815) Patches:
+	  jira_ast_815_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett (modified) ........ Merged revisions 363687 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363688 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-25 13:57 +0000 [r363480-363637]  Olle Johansson <oej at edvina.net>
+
+	* apps/app_queue.c: Add documentation Thanks Tilghman!
+
+	* apps/app_queue.c: Formatting changes only
+
+	* apps/app_followme.c, apps/app_queue.c: Use the DEFINED value for
+	  musicclass length. For some reason, features.c has it's own
+	  definition. Should propably be fixed too.
+
+	* main/channel.c, configs/asterisk.conf.sample, CHANGES,
+	  include/asterisk/options.h, main/asterisk.c: Make it possible to
+	  change the minimum DTMF duration in asterisk.conf Asterisk has a
+	  setting for the minimum allowed DTMF. If we get shorter DTMF
+	  tones, these will be changed to the minimum on the outbound call
+	  leg. (closes issue ASTERISK-19772) Review:
+	  https://reviewboard.asterisk.org/r/1882/ Reported by: oej Tested
+	  by: oej Patches by: oej Thanks to the reviewers. 1.8 branch for
+	  this patch: agave-dtmf-duration-asterisk-conf-1.8
+
+	* main/say.c: Formatting fixes Developer guidelines are important.
+
+	* main/channel.c: Formatting fixes Found a small amount of curly
+	  brackets in my hotel room here in Denmark. I hereby donate them
+	  to the Asterisk project.
+
+2012-04-25 01:26 +0000 [r363377-363430]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix recalled party B feature flags for a
+	  failed DTMF atxfer. 1) B calls A with Dial option T 2) B DTMF
+	  atxfer to C 3) B hangs up 4) C does not answer 5) B is called
+	  back 6) B answers 7) B cannot initiate transfers anymore * Add
+	  dial features datastore to recalled party B channel that is a
+	  copy of the original party B channel's dial features datastore. *
+	  Extracted add_features_datastore() from
+	  add_features_datastores(). * Renamed struct ast_dial_features
+	  features_caller and features_callee members to my_features and
+	  peer_features respectively. These better names eliminate the need
+	  for some explanatory comments. * Simplified code accessing the
+	  struct ast_dial_features datastore. (closes issue ASTERISK-19383)
+	  Reported by: lgfsantos ........ Merged revisions 363428 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407456 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-05 19:42 +0000 [r407443]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip/config_global.c, /: res_pjsip: When no global type
-	  the debug option defaults to "yes" If the global section was not
-	  specified in pjsip.conf then the configuration object does not
-	  exist in sorcery so when retrieving "debug" option it would
-	  return NULL. Then the NULL result was passed to ast_false utils
-	  function which would return false because it wasn't set to some
-	  representation of false, thus enabling sip debug logging. Made it
-	  so if the global config object does not exist then it will return
-	  a default of "no" for sip debugging. (issue ASTERISK-23038)
-	  Reported by: Rusty Newton ........ Merged revisions 407442 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-05 17:42 +0000 [r407422-407425]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES: CHANGES: Update changes log to include r403414 entry
-	  Adds note of additional 0 for operator option on app_record
-
-	* CHANGES, /: CHANGES: Update changes log to include new bridge
-	  fields added in r404042 ........ Merged revisions 407419 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-05 15:29 +0000 [r407407]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/playbacks.json, UPGRADE.txt,
-	  rest-api/api-docs/sounds.json, rest-api/resources.json, CHANGES,
-	  include/asterisk/manager.h, rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/mailboxes.json,
-	  rest-api/api-docs/asterisk.json,
-	  rest-api/api-docs/applications.json,
-	  rest-api/api-docs/channels.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/endpoints.json, rest-api/api-docs/events.json,
-	  /: ARI/AMI: Update versions; update UPGRADE/CHANGES notes for
-	  12.1.0 changes Due to backwards compatible changes made to
-	  AMI/ARI, the version needs to be bumped to 1.1.0/2.1.0,
-	  respectively. ........ Merged revisions 407402 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-04 20:15 +0000 [r407275-407340]  Richard Mudgett <rmudgett at digium.com>
+	  revisions 363429 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* include/asterisk/devicestate.h, /, main/devicestate.c:
-	  devicestate: Make ast_devstate_changed_literal() return value and
-	  doxygen consistent. Nothing actually cares about the value
-	  anyway. (closes issue ASTERISK-23178) Reported by: Jonathan Rose
-	  ........ Merged revisions 407337 from
+	* /, main/features.c: Hangup affected channel in error paths of
+	  bridge_call_thread(). ........ Merged revisions 363375 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407338 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407339 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 363376 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, res/res_pjsip/pjsip_configuration.c: res_pjsip: Fix assertion
-	  for pjsip.conf authorization list options. (closes issue
-	  ASTERISK-23168) Reported by: George Joseph Review:
-	  https://reviewboard.asterisk.org/r/3143/ ........ Merged
-	  revisions 407324 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-04-24 17:52 +0000 [r363335]  Terry Wilson <twilson at digium.com>
 
-	* configs/sip.conf.sample, main/tcptls.c, /: tcptls.c: Made TLS
-	  handle a certificate chain file. Thanks to Guillaume Martres for
-	  doing the necessary research to validate the change. (closes
-	  issue ASTERISK-17727) Reported by: LN Patches:
-	  use_certificate_chain.patch (license #5864) patch uploaded by st
-	  documente_certificate_chain.patch (license #6576) patch uploaded
-	  by Guillaume Martres ........ Merged revisions 407272 from
+	* /, main/asterisk.c: OpenBSD doesn't have rawmemchr, use strchr
+	  (closes issue ASTERISK-19758) Reported by: Barry Miller Tested
+	  by: Terry Wilson Patches: 362758-diff uploaded by Barry Miller
+	  (license 5434) ........ Merged revisions 362868 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407273 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407274 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 362869 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-02-04 16:55 +0000 [r407260]  Matthew Jordan <mjordan at digium.com>
+2012-04-23 17:05 +0000 [r363269]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, funcs/func_cdr.c: funcs/func_cdr: Fix non-epoch timestamps
-	  broken by improper char array deref Thanks to snuffy for pointing
-	  this issue out and fixing it. (closes issue ASTERISK-23250)
-	  Reported by: snuffy patches: func_cdr-fix.diff uploaded by snuffy
-	  (License 5024) ........ Merged revisions 407259 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* apps/app_dial.c, apps/app_queue.c: Make app_dial and app_queue
+	  use new macro and gosub calls. * Simplify some code in app_dial
+	  and app_queue by calling ast_app_exec_macro() and
+	  ast_app_exec_sub(). * Fix minor locking issue in app_dial for
+	  post-answer macro/gosub MACRO/GOSUB_RESULT=GOTO: handling.
 
-2014-02-04 02:22 +0000 [r407217]  Joshua Colp <jcolp at digium.com>
+2012-04-23 16:08 +0000 [r363215]  Tilghman Lesher <tilghman at meg.abyt.es>
 
-	* res/res_clialiases.c, /: res_clialiases: Fix crash when reloading
-	  and re-aliasing an alias that is in use. The code assumed that
-	  unregistering the alias would always succeed while in practice
-	  this is not actually true. A common case is the "reload" command
-	  itself. If the cli_aliases.conf configuration file was changed
-	  and reload executed the command would fail to unregister and
-	  ultimately point to freed memory. The reload process now checks
-	  whether unregistering succeeded or not and if not the old CLI
-	  alias is retained. (closes issue ASTERISK-19773) Reported by:
-	  Joel Vandal (closes issue ASTERISK-22757) Reported by: Gareth
-	  Blades ........ Merged revisions 407205 from
+	* /, main/astfd.c: On some platforms, O_RDONLY is not a flag to be
+	  checked, but merely the absence of O_RDWR and O_WRONLY. The POSIX
+	  specification does not mandate how these 3 flags must be
+	  specified, only that one of the three must be specified in every
+	  call. ........ Merged revisions 363209 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-23 14:48 +0000 [r363159]  Jonathan Rose <jrose at digium.com>
+
+	* main/manager.c, /: AST-2012-004: Fix an error that allows AMI
+	  users to run shell commands sans authorization. As detailed in
+	  the advisory, AMI users without write authorization for SYSTEM
+	  class AMI actions were able to run system commands by going
+	  through other AMI commands which did not require that
+	  authorization. Specifically, GetVar and Status allowed users to
+	  do this by setting their variable/s options to the SHELL or EVAL
+	  functions. Also, within 1.8, 10, and trunk there was a similar
+	  flaw with the Originate action that allowed users with originate
+	  permission to run MixMonitor and supply a shell command in the
+	  Data argument. That flaw is fixed in those versions of this
+	  patch. (closes issue ASTERISK-17465) Reported By: David Woolley
+	  Patches: 162_ami_readfunc_security_r2.diff uploaded by jrose
+	  (license 6182) 18_ami_readfunc_security_r2.diff uploaded by jrose
+	  (license 6182) 10_ami_readfunc_security_r2.diff uploaded by jrose
+	  (license 6182) ........ Merged revisions 363117 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.6.2 ........
+	  Merged revisions 363141 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407210 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407213 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-04 02:07 +0000 [r407198]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny - Fix deadlock when pickup of
-	  no call. Locking issues in skinny when picking up a call that
-	  doesn't exist. Cleaned up sub locking by fully removing and using
-	  the chan lock instead. Also changed ast_call_pickup to check
-	  whether chan was masq'd. (closes issue ASTERISK-23249) Reported
-	  by: wedhorn Tested by: snuffy, myself Patches:
-	  skinny-locking01.diff uploaded by wedhorn (license 5019) ........
-	  Merged revisions 407197 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-03 01:31 +0000 [r407169]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: cdrs: Check for applications to lock onto during
-	  dial begin handling This patch brings CDR processing further in
-	  line with r407085. During some dial operations, the application
-	  would not be locked to the Dial application and would instead
-	  continue to show the previously known application. In particular,
-	  this would occur when a Parked call would time out. This was due
-	  to a previous snapshot already locking the application to Park -
-	  processing this in a Dial Begin allows the Dial application to
-	  reassert its rightful place. (CDRs. Ugh.) But hooray for the
-	  Parked Call tests for catching this in the Asterisk Test Suite.
-	  ........ Merged revisions 407166 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-01 16:26 +0000 [r407154]  Joshua Colp <jcolp at digium.com>
-
-	* res/ari/ari_model_validators.h, rest-api/api-docs/events.json, /,
-	  res/stasis/app.c, res/ari/ari_model_validators.c,
-	  res/res_stasis.c, main/stasis_bridges.c: res_stasis: Enable
-	  transfers and provide events when they occur. This change enables
-	  transfers within ARI created bridges and adds events for when
-	  they occur. Unlike other events these will be received if *any*
-	  subscribed object is involved in the transfer. (closes issue
-	  ASTERISK-22984) Reported by: David M. Lee Review:
-	  https://reviewboard.asterisk.org/r/3120/ ........ Merged
-	  revisions 407153 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-02-01 00:25 +0000 [r407105]  Corey Farrell <git at cfware.com>
+	  revisions 363156 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-23 14:10 +0000 [r363105-363108]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: AST-2012-006: Fix crash in UPDATE
+	  handling when no channel owner exists If Asterisk receives a SIP
+	  UPDATE request after a call has been terminated and the channel
+	  has been destroyed but before the SIP dialog has been destroyed,
+	  a condition exists where a connected line update would be
+	  attempted on a non-existing channel. This would cause Asterisk to
+	  crash. The patch resolves this by first ensuring that the SIP
+	  dialog has an owning channel before attempting a connected line
+	  update. If an UPDATE request is received and no channel is
+	  associated with the dialog, a 481 response is sent. (closes issue
+	  ASTERISK-19770) Reported by: Thomas Arimont Tested by: Matt
+	  Jordan Patches: ASTERISK-19278-2012-04-16.diff uploaded by Matt
+	  Jordan (license 6283) ........ Merged revisions 363106 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363107 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_skinny.c: AST-2012-005: Fix remotely exploitable
+	  heap overflow in keypad button handling When handling a keypad
+	  button message event, the received digit is placed into a fixed
+	  length buffer that acts as a queue. When a new message event is
+	  received, the length of that buffer is not checked before placing
+	  the new digit on the end of the queue. The situation exists where
+	  sufficient keypad button message events would occur that would
+	  cause the buffer to be overrun. This patch explicitly checks that
+	  there is sufficient room in the buffer before appending a new
+	  digit. (closes issue ASTERISK-19592) Reported by: Russell Bryant
+	  ........ Merged revisions 363100 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.6.2 ........
+	  Merged revisions 363102 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 363103 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_stack.c, /: app_stack: protect against missing
-	  parameters to STACK_PEEK and LOCAL_PEEK STACK_PEEK requires 2
-	  parameters and LOCAL_PEEK requires 1 parameter. This protects
-	  against situations where those parameters are blank or missing by
-	  logging an error and returning. (closes issue ASTERISK-23220)
-	  Reported by: James Sharp ........ Merged revisions 407100 from
+2012-04-21 11:45 +0000 [r363045-363046]  Russell Bryant <russell at russellbryant.com>
+
+	* res/res_corosync.c: res_corosync: Recover if corosync gets
+	  restarted. If corosync gets restarted while Asterisk is running,
+	  automatically recover.
+
+	* res/res_corosync.c: res_corosync: reimplement "corosync show
+	  members" command. Reimplement the "corosync show members" CLI
+	  command using a CPG iterator instead of the cpg_membership_get
+	  API call. This will also show all CPG members, including those in
+	  groups other than 'asterisk', which may be useful at some point
+	  for debugging purposes.
+
+2012-04-21 01:46 +0000 [r362920-362999]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, /: Update app_dial M and U option GOTO return
+	  value documentation. ........ Merged revisions 362997 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 407103 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407104 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 23:40 +0000 [r407083-407085]  Matthew Jordan <mjordan at digium.com>
-
-	* apps/app_dial.c, main/cdr.c, main/pbx.c, /, main/bridge_after.c,
-	  UPGRADE.txt, main/manager_channels.c: CDRs: fix a variety of dial
-	  status problems, h/hangup handler creating CDRs This patch fixes
-	  a number of small-ish problems that were noticed when witnessing
-	  the records that the FreePBX dialplan produces: (1) Mid-call
-	  events (as well as privacy options) have the ability to change
-	  the overall state of the Dial operation after the called party
-	  answers. This means that publishing the DialEnd event when the
-	  called party is premature; we have to wait for the execution of
-	  these subroutines to complete before we can signal the overall
-	  status of the DialEnd. This patch moves that publication and adds
-	  handlers for the mid-call events. (2) The AST_FLAG_OUTGOING
-	  channel flag is cleared if an after bridge goto datastore is
-	  detected. This flag was preventing CDRs from being recorded for
-	  all outbound channels that had a 'continue' option enabled on
-	  them by the Dial application. (3) The CDR engine now locks the
-	  'Dial' application as being the CDR application if it detects
-	  that the current CDR has entered that app. This is similar to the
-	  logic that is done for Parking. In general, if we entered into
-	  Dial, then we want that CDR to record the application as such -
-	  this prevents pre-dial handlers, mid-call handlers, and other
-	  shenaniganry from changing the application value. (4) The CDR
-	  engine now checks for the AST_SOFTHANGUP_HANGUP_EXEC in more
-	  places to determine if the channel is in hangup logic or dead. In
-	  either case, we don't want to record changes in the channel. (5)
-	  The default option for "endbeforehexten" has been changed to
-	  "yes". In general, you don't want to see CDRs in the 'h' exten or
-	  in hangup logic. Since the semantics of that option changed in
-	  12, it made sense to update the default value as well. (6)
-	  Finally, because we now have the ability to synchronize on the
-	  messages published to the CDR topic, on shutdown the CDR engine
-	  will now synchronize to the messages currently in flight. This
-	  helps to ensure that all in-flight CDRs are written before
-	  shutting down. (closes issue ASTERISK-23164) Reported by: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/3154 ........
-	  Merged revisions 407084 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 362998 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* include/asterisk/app.h, main/app.c, apps/app_stack.c: Fix
+	  connected-line/redirecting interception gosubs executing more
+	  than intended. * Redo ast_app_run_sub()/ast_app_exec_sub() to use
+	  a known return point so execution will stop after the routine
+	  returns there. (s at gosub_virtual_context:1) * Create
+	  ast_app_exec_macro() and ast_app_exec_sub() to run the macro and
+	  gosub application respectively with the parameter string already
+	  created.
+
+	* main/rtp_engine.c: Move debug message in
+	  ast_rtp_instance_early_bridge_make_compatible(). Move debug
+	  message in ast_rtp_instance_early_bridge_make_compatible() to be
+	  output when what it states has actually happened.
+
+2012-04-20 16:50 +0000 [r362919]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, main/event.c: Add missing payload type to events API The
+	  Security Events Framework API was changed while adding the
+	  generation of security events in chan_sip. A payload type and
+	  name was missed from being added to struct ie_maps. (closes issue
+	  ASTERISK-19759) Reported by: Michael L. Young Patches:
+	  issue-asterisk-19759.diff uploaded by Michael L. Young (license
+	  5026) ........ Merged revisions 362918 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-20 16:23 +0000 [r362867-362888]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, channels/chan_dahdi.c, channels/chan_local.c,
+	  channels/chan_misdn.c, main/rtp_engine.c: Use
+	  ast_channel_lock_both() where it was inlined before. The
+	  CHANNEL_DEADLOCK_AVOIDANCE() feature of preserving where the
+	  channel lock was originally obtained is overkill where
+	  ast_channel_lock_both() was inlined.
+
+	* main/pbx.c: * Add more information to some messages in
+	  __ast_pbx_run(). * Simplify some dialplan priority setting code
+	  in ast_explicit_goto() because of opaquification.
+
+2012-04-20 14:50 +0000 [r362817]  Terry Wilson <twilson at digium.com>
+
+	* /, apps/app_speech_utils.c: Document Speech* apps hangup on
+	  failure and suggest TryExec The Speech API apps return -1 on
+	  failure, which will hang up the channel. This may not be
+	  desirable behavior for some, but it isn't something that can be
+	  changed without breaking people's dialplans or writing an option
+	  to all of the Speech apps that does what TryExec already does.
+	  This patch documents the hangup behavior of the apps, and
+	  suggests TryExec as the solution. (closes issue AST-813) ........
+	  Merged revisions 362815 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362816 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-20 00:57 +0000 [r362779]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, UPGRADE.txt, include/asterisk/channel.h, CHANGES,
+	  channels/sig_pri.c, funcs/func_callerid.c: Add original party id
+	  and reason support. ISDN ETSI PTP and Q.SIG (And SS7 in future)
+	  have support for reporting who was the original redirecting party
+	  of a call. * Added support for the original redirecting party and
+	  reason to the REDIRECTING function and the system core as well as
+	  to the stubbed locations in sig_pri.c. Review:
+	  https://reviewboard.asterisk.org/r/1829/
+
+2012-04-19 22:01 +0000 [r362731]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* funcs/func_version.c, /: Fix documentation for
+	  ${VERSION(ASTERISK_VERSION_NUM)}. ........ Merged revisions
+	  362729 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 362730 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-19 21:14 +0000 [r362682]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, tests/test_linkedlists.c, tests/test_poll.c: Add leading and
+	  trailing backslashes A couple of unit tests did not have have
+	  leading or trailing backslashes when setting their test category
+	  resulting in a warning message being displayed. Added the
+	  backslash where needed. ........ Merged revisions 362680 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362681 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_dial.c, /: app_dial: Allow macro/gosub pre-bridge
-	  execution to occur on priorities The parsing for the destination
-	  of the macro/gosub uses the '^' character to separate out
-	  context, extension, and priority. However, the logic for the
-	  macro/gosub execution was written such that it would only do the
-	  actual macro/gosub jump if a '^' character existed. This doesn't
-	  apply when the macro/gosub jump occurs in a priority/priority
-	  label. This patch changes the logic so that the parsing still
-	  occurs, but the jump will occur even for priorities/priority
-	  labels. (issue ASTERISK-23164) Review:
-	  https://reviewboard.asterisk.org/r/3154 ........ Merged revisions
-	  407041 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 407074 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 407082 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 23:15 +0000 [r407035-407037]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_logger.c, CHANGES, res/res_pjsip.c,
-	  include/asterisk/res_pjsip.h, res/res_pjsip/config_global.c,
-	  contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
-	  (added), /, configs/pjsip.conf.sample, UPGRADE.txt: res_pjsip:
-	  Config option to enable PJSIP logger at load time. Added a
-	  "debug" configuration option for res_pjsip that when set to "yes"
-	  enables SIP messages to be logged. It is specified under the
-	  "system" type. Also added an alembic script to add the option to
-	  realtime. (closes issue ASTERISK-23038) Reported by: Rusty Newton
-	  Review: https://reviewboard.asterisk.org/r/3148/ ........ Merged
-	  revisions 407036 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_exten_state.c, /: res_pjsip_exten_state: Exporting
-	  global symbols caused load order issues Removed the exportation
-	  of global symbols from the module as it is no longer needed and
-	  it could potentially cause load problems as on some systems it
-	  would try to load before res_pjsip_pubsub ........ Merged
-	  revisions 407034 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 23:04 +0000 [r407033]  Richard Mudgett <rmudgett at digium.com>
-
-	* CHANGES, apps/app_chanspy.c: ChanSpy: Add ability to specify
-	  channel uniqueids as well as channel names. * Made ChanSpy accept
-	  a channel uniqueid or a fully specified channel name as the
-	  chanprefix parameter if the 'u' option is specified. (closes
-	  issue AFS-42) Review: https://reviewboard.asterisk.org/r/3160/
-
-2014-01-31 22:39 +0000 [r407030-407032]  Mark Michelson <mmichelson at digium.com>
-
-	* include/asterisk/res_pjsip_presence_xml.h (added), /: Add file
-	  that apparently got missed in the merge. ........ Merged
-	  revisions 407031 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pidf_body_generator.c (added),
-	  include/asterisk/res_pjsip_exten_state.h (removed),
-	  res/res_pjsip_pubsub.exports.in, /,
-	  include/asterisk/res_pjsip_body_generator_types.h (added),
-	  res/res_pjsip_mwi.c, res/res_pjsip_xpidf_body_generator.c
-	  (added), res/res_pjsip_mwi_body_generator.c (added),
-	  res/res_pjsip_pubsub.c, res/res_pjsip_pidf.c (removed),
-	  res/res_pjsip_pidf_eyebeam_body_supplement.c (added),
-	  res/res_pjsip_exten_state.c, res/res_pjsip/presence_xml.c
-	  (added), include/asterisk/res_pjsip_pubsub.h: Decouple
-	  subscription handling from NOTIFY/PUBLISH body generation. When
-	  the PJSIP pubsub framework was created, subscription handlers
-	  were required to state what event they handled along with what
-	  body types they knew how to generate. While this serves well when
-	  implementing a base RFC, it has problems when trying to extend
-	  the body to support non-standard or proprietary body elements.
-	  The code also was NOTIFY-specific, meaning that when the time
-	  comes that we start writing code to send out PUBLISH requests
-	  with MWI or presence bodies, we would likely find ourselves
-	  duplicating code that had previously been written. This changeset
-	  introduces the concept of body generators and body supplements. A
-	  body generator is responsible for allocating a native structure
-	  for a given body type, providing the primary body content,
-	  converting the native structure to a string, and deallocating
-	  resources. A body supplement takes the primary body content (the
-	  native structure, not a string) generated by the body generator
-	  and adds nonstandard elements to the body. With these elements
-	  living in their own module, it becomes easy to extend our support
-	  for body types and to re-use resources when sending a PUBLISH
-	  request. Body generators and body supplements register themselves
-	  with the pubsub core, similar to how subscription and publish
-	  handlers had done. Now, subscription handlers do not need to know
-	  what type of body content they generate, but they still need to
-	  inform the pubsub core about what the default body type for a
-	  given event package is. The pubsub core keeps track of what body
-	  generators and body supplements have been registered. When a
-	  SUBSCRIBE arrives, the pubsub core will check that there is a
-	  subscription handler for the event in the SUBSCRIBE, then it will
-	  check that there is a body generator that can provide the content
-	  specified in the Accept header(s). Because of the nature of body
-	  generators and supplements, it means res_pjsip_exten_state and
-	  res_pjsip_mwi have been completely gutted. They no longer worry
-	  about body types, instead calling
-	  ast_sip_pubsub_generate_body_content() when they need to generate
-	  a NOTIFY body. Review: https://reviewboard.asterisk.org/r/3150
-	  ........ Merged revisions 407016 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 22:23 +0000 [r407015-407029]  Kevin Harwell <kharwell at digium.com>
-
-	* contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py,
-	  contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py,
-	  /, UPGRADE.txt: alembic: script modifications due to errors A
-	  couple of the scripts had errors that would not allow a full
-	  migration to take place. The extensions table needed to make its
-	  'id' column a primary key in order to work with mysql. The other
-	  script ...add_endpoints... was missing tables that it was trying
-	  to add columns to. Added the primary key on id for extensions and
-	  added the tables in for the missing pjsip configuration options.
-	  While it is not ideal to modify already released scripts this was
-	  a case where it had to be done due to errors in the script and
-	  lacking a better alternative. Review:
-	  https://reviewboard.asterisk.org/r/3167/ ........ Merged
-	  revisions 407019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_mwi.c: res_pjsip_mwi: Subscribe fails when
-	  missing aor name When subscribing to MWI (res_pjsip_mwi) and the
-	  sip uri did not contain a name (ex: sip:<ip address>) then the
-	  subscription would fail since it would be unable to locate an
-	  associated aor. This patch makes it so that when a subscribe
-	  comes with no aor name then it will subscribe to all aors on the
-	  located endpoint. (closes issue ASTERISK-23072) Reported by: Bob
-	  M Review: https://reviewboard.asterisk.org/r/3164/ ........
-	  Merged revisions 407014 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 15:08 +0000 [r407001]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip_nat.c, /: PJSIP: Fix address for ACK in NAT
-	  situations In NAT scenarios where a call is placed to a
-	  Grandstream phone, res_pjsip will sometimes send the ACK to a 200
-	  OK to the private address of the device behind the NAT instead of
-	  the address of the NAT device. This corrects that behavior by
-	  rewriting the address in the Contact header in the incoming 200
-	  OK and the dialog's target address if necessary (since it has
-	  already been rewritten to the incorrect private address). (closes
-	  issue ASTERISK-23106) Review:
-	  https://reviewboard.asterisk.org/r/3168/ Reported by: Matt Jordan
-	  ........ Merged revisions 407000 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-31 05:31 +0000 [r406988]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny: fix up possible double unlock
-	  of chan. Return before chan is possibly unlocked a second time
-	  when hanging up a channel in SUBSTATE_OFFHOOK. ........ Merged
-	  revisions 406987 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-30 20:36 +0000 [r406936]  Corey Farrell <git at cfware.com>
+2012-04-19 21:01 +0000 [r362679]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/udptl.c, res/res_rtp_asterisk.c, /: res_rtp_asterisk &
-	  udptl: fix port selection to work with SELinux restrictions
-	  ast_bind to a port reserved for another program by SELinux causes
-	  errno == EACCES. This caused random failures when binding rtp or
-	  udptl sockets. Treat EACCES as a non-fatal error, try next port.
-	  (closes issue ASTERISK-23134) Reported by: Corey Farrell ........
-	  Merged revisions 406933 from
+	* /, configs/queues.conf.sample: Update membermacro and membergosub
+	  documentation in queues.conf.sample. ........ Merged revisions
+	  362677 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 362678 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-19 19:05 +0000 [r362635]  Terry Wilson <twilson at digium.com>
+
+	* addons/chan_ooh323.c, apps/app_alarmreceiver.c,
+	  channels/iax2-provision.c, res/snmp/agent.c: Convert some
+	  strncpys to ast_copy_string Review:
+	  https://reviewboard.asterisk.org/r/1732/
+
+2012-04-19 16:10 +0000 [r362588]  Sean Bright <sean at malleable.com>
+
+	* /, apps/app_externalivr.c: Prevent a crash in ExternalIVR when
+	  the 'S' command is sent first. If the first command sent from an
+	  ExternalIVR client is an 'S' command, we were blindly removing
+	  the first element from the play list and deferencing it, even if
+	  it was NULL. This corrects that and also locks appropriately in
+	  one place. (issue ASTERISK-17889) Reported by: Chris Maciejewski
+	  ........ Merged revisions 362586 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362587 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-19 14:35 +0000 [r362538]  Terry Wilson <twilson at digium.com>
+
+	* /, main/asterisk.c: Handle multiple commands per connection via
+	  netconsole Asterisk would accept multiple NULL-delimited CLI
+	  commands via the netconsole socket, but would occasionally miss a
+	  command due to the command not being completely read into the
+	  buffer. This patch ensures that any partial commands get moved to
+	  the front of the read buffer, appended to, and properly sent.
+	  (closes issue ASTERISK-18308) Review:
+	  https://reviewboard.asterisk.org/r/1876/ ........ Merged
+	  revisions 362536 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406934 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406935 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 362537 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-19 02:40 +0000 [r362497]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_unistim.c, /, main/tdd.c, main/jitterbuf.c,
+	  apps/app_sms.c, main/stdtime/localtime.c, utils/extconf.c,
+	  addons/chan_mobile.c, main/format_pref.c, main/asterisk.c: Fix a
+	  variety of potential buffer overflows * chan_mobile: Fixed an
+	  overrun where the cind_state buffer (an integer array of size 16)
+	  would be overrun due to improper bounds checking. At worst, the
+	  buffer can be overrun by a total of 48 bytes (assuming 4-byte
+	  integers), which would still leave it within the allocated memory
+	  of struct hfp. This would corrupt other elements in that struct
+	  but not necessarily cause any further issues. * app_sms: The
+	  array imsg is of size 250, while the array (ud) that the data is
+	  copied into is of size 160. If the size of the inbound message is
+	  greater then 160, up to 90 bytes could be overrun in ud. This
+	  would corrupt the user data header (array udh) adjacent to ud. *
+	  chan_unistim: A number of invalid memmoves are corrected. These
+	  would move data (which may or may not be valid) into the ends of
+	  these buffers. * asterisk: ast_console_toggle_loglevel does not
+	  check that the console log level being set is less then or equal
+	  to the allowed log levels of 32. * format_pref: In
+	  ast_codec_pref_prepend, if any occurrence of the specified codec
+	  is not found, the value used to index into the array pref->order
+	  would be one greater then the maximum size of the array. *
+	  jitterbuf: If the element being placed into the jitter buffer
+	  lands in the last available slot in the jitter history buffer,
+	  the insertion sort attempts to move the last entry in the buffer
+	  into one slot past the maximum length of the buffer. Note that
+	  this occurred for both the min and max jitter history buffers. *
+	  tdd: If a read from fsk_serial returns a character that is
+	  greater then 32, an attempt to read past one of the statically
+	  defined arrays containing the values that character maps to would
+	  occur. * localtime: struct ast_time and tm are not the same size
+	  - ast_time is larger, although it contains the elements of tm
+	  within it in the same layout. Hence, when using memcpy to copy
+	  the contents of tm into ast_time, the size of tm should be used,
+	  as opposed to the size of ast_time. * extconf: this treats
+	  ast_timing's minmask array as if it had a length of 48, when it
+	  has defined the size of the array as 24. pbx.h defines minmask as
+	  having a size of 48. (issue ASTERISK-19668) Reported by: Matt
+	  Jordan ........ Merged revisions 362485 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362496 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-30 17:35 +0000 [r406920]  Sean Bright <sean at malleable.com>
+2012-04-18 17:03 +0000 [r362432]  Michael L. Young <elgueromexicano at gmail.com>
 
-	* main/manager.c, /: Make a NOTICE about an invalid channel name
-	  more useful. ........ Merged revisions 406918 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406919 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* tests/test_security_events.c: Fix building security events test
+	  The Security Events Framework API changed in trunk to support
+	  IPv6. This broke the building of the security events test which
+	  was based around IPv4. This patches fixes the build by changing
+	  the test to conform to the new changes. (related to issue
+	  ASTERISK-19447) Review: https://reviewboard.asterisk.org/r/1874/
 
-2014-01-29 00:44 +0000 [r406863]  Russell Bryant <russell at russellbryant.com>
+2012-04-18 16:41 +0000 [r362430]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, configs/queues.conf.sample: queues.conf.sample Fix documented
-	  default for persistentmembers Closes issue ASTERISK-22662
-	  ........ Merged revisions 406860 from
+	* channels/sig_pri.h, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, /, channels/sig_pri.c: Add
+	  ability to ignore layer 1 alarms for BRI PTMP lines. Several
+	  telcos bring the BRI PTMP layer 1 down when the line is idle.
+	  When layer 1 goes down, Asterisk cannot make outgoing calls.
+	  Incoming calls could fail as well because the alarm processing is
+	  handled by a different code path than the Q.931 messages. * Add
+	  the layer1_presence configuration option to ignore layer 1 alarms
+	  when the telco brings layer 1 down. This option can be configured
+	  by span while the similar DAHDI driver teignorered=1 option is
+	  system wide. This option unlike layer2_persistence does not
+	  require libpri v1.4.13 or newer. Related to JIRA AST-598 JIRA
+	  ABE-2845 ........ Merged revisions 362428 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406861 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406862 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-28 23:40 +0000 [r406789-406848]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_pubsub.c, /: res_pjsip_pubsub: potential crash on
-	  timeout What seems to be happening is if a subscription has been
-	  terminated and the subscription timeout/expires is less than the
-	  time it takes for all pending transactions (currently on the
-	  subscription) to end then the subscription timer will not have
-	  been canceled yet and sub will be null. Since the subscription
-	  has already been canceled nothing needs to be done so a null
-	  check in the asterisk code is sufficient in working around this
-	  problem. (closes issue ASTERISK-23129) Reported by: Dan Jenkins
-	  ........ Merged revisions 406847 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* cdr/cdr_radius.c, cel/cel_radius.c, /, configure,
-	  include/asterisk/autoconfig.h.in, configure.ac: cdr_radius,
-	  cel_radius: build agains libfreeradius-client Asterisk's RADIUS
-	  module currently build against libradiusclient-ng, but this
-	  project has been superseeded by libfreeradius-client. The API is
-	  99% compatible except that the header name has changed, the
-	  library name has changed, and the configuration file location has
-	  changed. (closes issue ASTERISK-22980) Reported by: Jeremy Lainé
-	  Patches: freeradius-client.patch uploaded by sharky (license
-	  6561) ........ Merged revisions 406801 from
+	  revisions 362429 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-17 21:23 +0000 [r362365-362380]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/format_pref.c: Handle case where an unknown format is
+	  used to get the preferred codec size In ast_codec_pref_getsize,
+	  if an unknown format is passed to the method, no preferred codec
+	  will be selected and a negative number will be used to index into
+	  the format list. The method now logs an unknown format as a
+	  warning, and returns an empty format list. (issue ASTERISK-19655)
+	  Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1863/ ........ Merged
+	  revisions 362377 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* res/res_rtp_asterisk.c, /, res/res_agi.c, res/res_musiconhold.c:
+	  Fix places in resources where a negative return value could
+	  impact execution This patch addresses a number of modules in
+	  resources that did not handle the negative return value from
+	  function calls adequately. This includes: * res_agi.c: if the
+	  result of the read function is a negative number, indicating some
+	  failure, the result would instead be treated as the number of
+	  bytes read. This patch now treats negative results in the same
+	  manner as an end of file condition, with the exception that it
+	  also logs the error code indicated by the return. *
+	  res_musiconhold.c: if spawn_mp3 fails to assign a file descriptor
+	  to srcfd, and instead assigns a negative value, that file
+	  descriptor could later be passed to functions that require a
+	  valid file descriptor. If spawn_mp3 fails, we now immediately
+	  retry instead of continuing in the logic. * res_rtp_asterisk.c:
+	  if no codec can be matched between two RTP instances in a peer to
+	  peer bridge, we immediately return instead of attempting to use
+	  the codec payload type as an index to determine the appropriate
+	  negotiated codec. (issue ASTERISK-19655) Reported by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/1863/ ........ Merged
+	  revisions 362362 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362364 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-17 21:10 +0000 [r362363]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_config_curl.c, res/res_config_pgsql.c,
+	  res/res_config_odbc.c, /: Make use of va_args more appropriate to
+	  form in various res_config modules plus utils. A number of
+	  va_copy operations weren't matched with a corresponding va_end in
+	  res_config_odbc. Also, there was a potential for va_end to be
+	  invoked twice on the same va_arg in utils, which would mean
+	  invoking va_end on an undefined variable... which is bad. va_end
+	  is removed from various functions in config_pgsql and config_curl
+	  since they aren't making their own copy. The invokers of those
+	  functions are responsible for calling va_end on them. (issue
+	  ASTERISK-19451) Reported by: Walter Doekes Review:
+	  https://reviewboard.asterisk.org/r/1848/ ........ Merged
+	  revisions 362354 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362357 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-17 21:08 +0000 [r362358-362361]  Matthew Jordan <mjordan at digium.com>
+
+	* main/manager.c, /, main/asterisk.c: Fix places in main where a
+	  negative return value could impact execution This patch addresses
+	  a number of modules in main that did not handle the negative
+	  return value from function calls adequately, or were not
+	  sufficiently clear that the conditions leading to improper
+	  handling of the return values could not occur. This includes: *
+	  asterisk.c: A negative return value from the read function would
+	  be used directly as an index into a buffer. We now check for
+	  success of the read function prior to using its result as an
+	  index. * manager.c: Check for failures in mkstemp and lseek when
+	  handling the temporary file created for processing data returned
+	  from a CLI command in action_command. Also check that the result
+	  of an lseek is sanitized prior to using it as the size of a
+	  memory map to allocate. (issue ASTERISK-19655) Reported by: Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/1863/ ........
+	  Merged revisions 362359 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362360 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, funcs/func_env.c: Fix places where a negative return from
+	  ftello could be used as invalid input In a variety of locations
+	  in both reading and writing a file, the result from the C library
+	  function ftello is used as input to other functions. For the
+	  parameters and functions in question, a negative value is invalid
+	  input. This patch checks the return value from the ftello
+	  function to determine if we were able to determine the current
+	  position in the file stream and, if not, fail gracefully. (issue
+	  ASTERISK-19655) Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1863/ ........ Merged
+	  revisions 362355 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362356 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-17 18:57 +0000 [r362307]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* channels/chan_unistim.c, cdr/cdr_sqlite3_custom.c,
+	  funcs/func_env.c, res/res_phoneprov.c, channels/chan_gtalk.c,
+	  cdr/cdr_pgsql.c, res/res_http_post.c, res/res_musiconhold.c,
+	  res/res_jabber.c, res/res_format_attr_celt.c,
+	  channels/chan_dahdi.c, funcs/func_groupcount.c,
+	  apps/app_osplookup.c, funcs/func_odbc.c, main/ast_expr2f.c,
+	  apps/app_minivm.c, channels/chan_alsa.c, codecs/codec_resample.c,
+	  formats/format_h264.c, res/res_format_attr_silk.c,
+	  res/res_config_ldap.c, main/ast_expr2.fl,
+	  res/res_config_sqlite3.c, channels/chan_sip.c,
+	  channels/vcodecs.c, codecs/codec_g726.c, main/data.c,
+	  res/res_corosync.c, channels/chan_h323.c, codecs/codec_dahdi.c,
+	  funcs/func_callerid.c, main/asterisk.c, res/res_odbc.c: Avoid
+	  cppcheck warnings; removing unused vars and a bit of cleanup.
+	  Patch by: junky Review: https://reviewboard.asterisk.org/r/1743/
+
+2012-04-17 18:29 +0000 [r362306]  Matthew Jordan <mjordan at digium.com>
+
+	* /, formats/format_sln.c, formats/format_vox.c,
+	  formats/format_wav.c, formats/format_pcm.c,
+	  formats/format_wav_gsm.c, formats/format_siren14.c,
+	  formats/format_gsm.c, formats/format_g719.c,
+	  formats/format_siren7.c: Fix error that caused seek format
+	  operations to set max file size to '1' or '0' A very
+	  inappropriate placement of a ')' (introduced in r362151) caused
+	  the maximum size of a file to be set as the result of a
+	  comparison operation, as opposed to the result of the ftello
+	  operation. This resulted in seeking being restricted to the
+	  beginning of the file, or 1 byte into the file. Thanks to the
+	  Asterisk Test Suite for properly freaking out about this on at
+	  least one test. (issue ASTERISK-19655) Reported by: Matt Jordan
+	  ........ Merged revisions 362304 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362305 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-17 15:00 +0000 [r362266]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* /, channels/chan_sip.c: Turn off warning message when bind
+	  address is set to any. When a bind address is set to an ANY
+	  address (udpbindport=::), a warning message is displayed stating
+	  that "Address remapping activated in sip.conf but we're using
+	  IPv6, which doesn't need it. Please remove 'localnet' and/or
+	  'externaddr' settings." But if one is running dual stack, we
+	  shouldn't be told to turn those settings off. This patch checks
+	  if the bind address is an ANY address or not. The warning message
+	  will now only be displayed if the bind address is NOT an ANY
+	  address and IPv6 is being used. Also, updated the copyright year.
+	  (closes issue ASTERISK-19456) Reported by: Michael L. Young
+	  Tested by: Michael L. Young Patches: chan_sip_ipv6_message.diff
+	  uploaded by Michael L. Young (license 5026) ........ Merged
+	  revisions 362253 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362264 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-16 21:58 +0000 [r362203-362206]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_dahdi.c, /, channels/chan_agent.c: Fix negative
+	  return handling in channel drivers In chan_agent, while handling
+	  a channel indicate, the agent channel driver must obtain a lock
+	  on both the agent channel, as well as the channel the agent
+	  channel is using. To do so, it attempts to lock the other channel
+	  first, then unlock the agent channel which is locked prior to
+	  entry into the indicate handler. If this unlock fails with a
+	  negative return value, which can occur if the object passed to
+	  agent_indicate is an invalid ao2 object or is NULL, the return
+	  value is passed directly to strerror, which can only accept
+	  positive integer values. In chan_dahdi, the return value of
+	  dahdi_get_index is used to directly index into the sub-channel
+	  array. If dahd_get_index returns a negative value, it would use
+	  that value to index into the array, which could cause an invalid
+	  memory access. If dahdi_get_index returns a negative number, we
+	  now default to SUB_REAL. (issue ASTERISK-19655) Reported by: Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/1863/ ........
+	  Merged revisions 362204 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362205 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_voicemail.c: Fix handling of negative return code
+	  when storing voicemails in ODBC storage When storing a voicemail
+	  message using an ODBC connection to a database, the voicemail
+	  message is first stored on disk. The sound file associated with
+	  the message is read into memory before being transmitted to the
+	  database. When this occurs, a failure in the C library's lseek
+	  function would cause a negative value to be passed to the mmap as
+	  the size of the memory map to create. This would almost certainly
+	  cause the creation of the memory map to fail, resulting in the
+	  message being lost. (issue ASTERISK-19655) Reported by: Matt
+	  Jordan Review: https://reviewboard.asterisk.org/r/1863 ........
+	  Merged revisions 362201 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406802 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406803 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip/include/res_pjsip_private.h, /,
-	  include/asterisk/compat.h: res_pjsip,compat: INFINITY and NAN
-	  undefined On some systems the values for INFINITY and NAN are not
-	  defined thus causing a build error on those systems. Added
-	  definitions for those if they had not previously been defined.
-	  (closes issue ASTERISK-23056) Reported by: capouch Patches:
-	  inf-nan-patch.txt uploaded by capouch (license 6564) ........
-	  Merged revisions 406788 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-28 19:19 +0000 [r406778]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_stasis_device_state.c: ARI: Make double subscribe
-	  respond with success Currently, attempting to subscribe an
-	  application to a device state that it has already subscribed to
-	  will generate a 500 error response. This will now be treated as a
-	  subscription refresh even though ARI subscriptions don't
-	  currently support lifetimes and will respond with the normal
-	  response for a successful subscription (200 OK). (closes issue
-	  ASTERISK-23143) Reported by: Matt Jordan ........ Merged
-	  revisions 406775 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-28 16:43 +0000 [r406724]  Scott Griepentrog <sgriepentrog at digium.com>
+	  revisions 362202 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-16 21:20 +0000 [r362200]  Michael L. Young <elgueromexicano at gmail.com>
+
+	* main/manager.c, main/security_events.c,
+	  channels/sip/security_events.c, CHANGES,
+	  include/asterisk/security_events_defs.h: Add IPv6 address support
+	  to security events framework. The current Security Events
+	  Framework API only supports IPv4 when it comes to generating
+	  security events. This patch does the following: * Changes the
+	  Security Events Framework API to support IPV6 and updates the
+	  components that use this API. * Eliminates an error message that
+	  was being generated since the current implementation was treating
+	  an IPv6 socket address as if it was IPv4. * Some copyright dates
+	  were updated on files touched by this patch. (closes issue
+	  ASTERISK-19447) Reported by: Michael L. Young Tested by: Michael
+	  L. Young Patches: security_events_ipv6v3.diff uploaded by Michael
+	  L. Young (license 5026) Review:
+	  https://reviewboard.asterisk.org/r/1777/
+
+2012-04-16 20:17 +0000 [r362153]  Matthew Jordan <mjordan at digium.com>
+
+	* formats/format_ilbc.c, /, formats/format_sln.c,
+	  formats/format_vox.c, formats/format_wav.c, formats/format_pcm.c,
+	  formats/format_g723.c, formats/format_h263.c,
+	  formats/format_h264.c, formats/format_wav_gsm.c,
+	  formats/format_siren14.c, formats/format_gsm.c,
+	  formats/format_g719.c, formats/format_siren7.c,
+	  formats/format_g729.c: Check for IO stream failures in various
+	  format's truncate/seek operations For the formats that support
+	  seek and/or truncate operations, many of the C library calls used
+	  to determine or set the current position indicator in the file
+	  stream were not being checked. In some situations, if an error
+	  occurred, a negative value would be returned from the library
+	  call. This could then be interpreted inappropriately as
+	  positional data. This patch checks the return values from these
+	  library calls before using them in subsequent operations. (issue
+	  ASTERISK-19655) Reported by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1863/ ........ Merged
+	  revisions 362151 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362152 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-13 16:12 +0000 [r362081-362085]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_forkcdr.c, /: Make ForkCDR e option not set end time of
+	  the newly forked CDR log Prior to this patch, ForkCDR's e option
+	  would immediately set the end time of the forked CDR to that of
+	  the CDR that is being terminated. This resulted in the new CDR's
+	  end time being roughly the same as it's beginning time (which is
+	  in turn roughly the same as the original's end time). (closes
+	  issue ASTERISK-19164) Reported by: Steve Davies Patches:
+	  cdr_fork_end.v10.patch uploaded by Steve Davies (license 5012)
+	  ........ Merged revisions 362082 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362084 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_meetme.c: Send relative path named recordings to the
+	  meetme directory instead of sounds Prior to this patch, no effort
+	  was made to parse the path name to determine a proper destination
+	  for recordings of MeetMe's r option. This fixes that. Review:
+	  https://reviewboard.asterisk.org/r/1846/ ........ Merged
+	  revisions 362079 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 362080 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-12 20:08 +0000 [r362043]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* main/srv.c: Convert SRV lookup message to debug level This helps
+	  clean up the Asterisk CLI by converting the log message from
+	  verbose to debug
+
+2012-04-12 16:29 +0000 [r361998]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/asterisk.conf.sample, UPGRADE.txt, pbx/pbx_config.c,
+	  include/asterisk/options.h, main/asterisk.c: Add option to invoke
+	  the extensions.conf stdexten using the legacy macro method.
+	  ASTERISK-18809 eliminated the legacy macro invocation of the
+	  stdexten in favor of the Gosub method without a means of
+	  backwards compatibility. (issue ASTERISK-18809) (closes issue
+	  ASTERISK-19457) Reported by: Matt Jordan Tested by: rmudgett
+	  Review: https://reviewboard.asterisk.org/r/1855/
+
+2012-04-12 16:25 +0000 [r361968-361987]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_iax2.c: Make trunkfreq take effect when set
+	  Previously, setting trunkfreq had no effect on initial load or on
+	  reload and only ever used the default value. This causes
+	  trunkfreq to be used appropriately on initial load and reload.
+	  (closes issue ASTERISK-19521) Patch-by: Jaco Kroon ........
+	  Merged revisions 361972 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361981 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* Makefile, build_tools/cflags.xml, /,
+	  build_tools/menuselect-deps.in, codecs/gsm/src/k6opt.s,
+	  configure, codecs/gsm/Makefile, configure.ac, Makefile.rules,
+	  makeopts.in, codecs/lpc10/Makefile: Simplify build system
+	  architecture optimization This change to the build system rips
+	  out any usage of PROC along with architecture-specific
+	  optimizations in favor of using -march=native where it is
+	  supported. This fixes broken builds on 64bit Intel systems and
+	  results in better optimized code on systems running GCC 4.2+.
+	  Review: https://reviewboard.asterisk.org/r/1852/ (closes issue
+	  ASTERISK-19462) ........ Merged revisions 361955 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361956 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-11 17:20 +0000 [r361909]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/queues.conf.sample, apps/app_queue.c: Change default
+	  value of 'ignorebusy' on Queue members so that behavior is more
+	  like 1.8 Prior to this patch, in order to restore that behavior,
+	  a function would have to be used on the QueueMember to make the
+	  ringinuse option do anything, which is pretty unreasonable.
+	  (closes issue ASTERISK-19536) reported by: Philippe Lindheimer
+	  Review: https://reviewboard.asterisk.org/r/1860/ ........ Merged
+	  revisions 361907 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-10 21:50 +0000 [r361856]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Prevent invalid access of free'd memory
+	  if DAHDI channel during an MWI event In the MWI processing loop,
+	  when a valid event occurs the temporary caller ID information is
+	  deallocated. If a new DAHDI channel is successfully created, the
+	  event is passed up to the analog_ss_thread without error and the
+	  loop exits. If, however, the DAHDI channel is not created, then
+	  the caller ID struct has been free'd, and the gains reset to
+	  their previous level. This will almost certainly cause an invalid
+	  access to the free'd memory, either in subsequent calls to
+	  callerid_free or calls to callerid_feed. * Rework the -r361705
+	  patch to better manage the cs and mtd allocated resources. *
+	  Fixed use of mwimonitoractive flag to be correct if the
+	  mwi_thread() fails to start. ........ Merged revisions 361854
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 361855 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/rtp_engine.c, /: rtp_engine: improved handling of
-	  get_rtp_info failure In ast_rtp_instance_make_compatible(), after
-	  a failure of channel tech call get_rtp_info() to return
-	  peer_instance, the null pointer would be passed to ao2_ref,
-	  producing an error that looked like a refernce counting problem
-	  but is not. This patch corrects that and adds helpful LOG_ERROR
-	  messages to indicate which failure path occurred. (issue
-	  AST-1276) Review: https://reviewboard.asterisk.org/r/3156/
-	  ........ Merged revisions 406721 from
+2012-04-10 19:58 +0000 [r361659-361805]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/http.c: Fix crash caused by unloading or reloading of
+	  res_http_post When unlinking itself from the registered HTTP
+	  URIs, res_http_post could inadvertently free all URIs registered
+	  with the HTTP server. This patch modifies the unregister method
+	  to only free the URI that is actually being unregistered, as
+	  opposed to all of them. ........ Merged revisions 361803 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361804 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* funcs/func_curl.c, /: Allow func_curl to exit gracefully if list
+	  allocation fails during write If the global_curl_info data
+	  structure could not be allocated, the datastore associated with
+	  the operation would be free'd, but the function would not return.
+	  This would later dereference the datastore, almost certainly
+	  causing Asterisk to crash. With this patch, if the data structure
+	  is not allocated the method will return an error code, and not
+	  attempt any further operation. ........ Merged revisions 361753
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 361754 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c, /: Prevent invalid access of free'd memory
+	  if DAHDI channel during an MWI event In the MWI processing loop,
+	  when a valid event occurs the temporary caller ID information is
+	  deallocated. If a new DAHDI channel is successfully created, the
+	  event is passed up to the analog_ss_thread without error and the
+	  loop exits. If, however, the DAHDI channel is not created, then
+	  the caller ID struct has been free'd, and the gains reset to
+	  their previous level. This will almost certainly cause an invalid
+	  access to the free'd memory, either in subsequent calls to
+	  callerid_free or calls to callerid_feed. This patch makes it so
+	  that we only free the caller ID structure if a DAHDI channel is
+	  successfully created, and we bump the gains back up if we fail to
+	  make a DAHDI channel. ........ Merged revisions 361705 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361706 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, funcs/func_global.c: Change SHARED function to use a safe
+	  traversal when modifying a variable When the SHARED function
+	  modifies a variable, it removes it from its list of variables and
+	  reinserts the new value at the head of the list of variables.
+	  Doing this inside a standard list traversal can be dangerous, as
+	  the standard list traversal does not account for the list being
+	  changed. While the code in question should not cause a use after
+	  free violation due to its breaking out of the loop after freeing
+	  the variable, it could lead to a maintenance issue if the loop
+	  was modified. This also fixes a violation reported by a static
+	  analysis tool, which also makes this code easier to maintain in
+	  the future. ........ Merged revisions 361657 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361658 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-06 22:00 +0000 [r361561-361608]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_calendar_ews.c: Fix memory leak in res_calendar_ews
+	  when event email address node is empty If the XML calendar data
+	  returned by a Microsoft Exchange Web Service specifies an XML
+	  Event E-Mail Address ("EmailAddress"), and no e-mail address is
+	  provided, a condition existed where an ast_calendar_attendee
+	  struct would be allocated but not appended to the list of
+	  attendees. Because of that, the memory associated with the
+	  attendee would never be freed. This patch frees the memory if no
+	  e-mail address is provided. ........ Merged revisions 361606 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361607 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_meetme.c: Fix memory leak when using MeetMeAdmin 'e'
+	  option with user specified A memory leak/reference counting leak
+	  occurs if the MeetMeAdmin 'e' command (eject last user that
+	  joined) is used in conjunction with a specified user. Regardless
+	  of the command being executed, if a user is specified for the
+	  command, MeetMeAdmin will look up that user. Because the 'e'
+	  option kicks the last user that joined, as opposed to the one
+	  specified, the reference to the user specified by the command
+	  would be leaked when the user variable was assigned to the last
+	  user that joined. ........ Merged revisions 361558 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361560 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-06 19:58 +0000 [r361523]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/message.c: Don't add an empty MESSAGE_DATA(key) header if
+	  it doesn't already exist. Doing Set(MESSAGE_DATA(key)=) would add
+	  an empty key header if the key header did not already exist. If
+	  it already existed it would delete it. * Made msg_set_var_full()
+	  exit early if the named variable did not already exist and the
+	  value to set is empty. ........ Merged revisions 361522 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-06 18:19 +0000 [r361476]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_unistim.c, main/pbx.c, /, channels/chan_sip.c,
+	  funcs/func_strings.c, formats/format_ogg_vorbis.c,
+	  channels/console_video.c, apps/app_ices.c, channels/chan_gtalk.c,
+	  channels/chan_iax2.c, res/res_config_sqlite.c, res/res_srtp.c,
+	  main/cdr.c, main/tcptls.c, channels/console_gui.c,
+	  funcs/func_channel.c, apps/app_sms.c, addons/chan_mobile.c,
+	  apps/app_chanspy.c, main/xmldoc.c, channels/chan_mgcp.c,
+	  res/res_config_sqlite3.c, res/res_clioriginate.c,
+	  apps/app_voicemail.c: Add missing newlines to CLI logging
+	  ........ Merged revisions 361471 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361472 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-06 16:33 +0000 [r361429]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* bridges/bridge_builtin_features.c, /, funcs/func_sysinfo.c,
+	  bridges/bridge_multiplexed.c: Multiple revisions 361403,361412
+	  ........ r361403 | pabelanger | 2012-04-06 12:24:36 -0400 (Fri,
+	  06 Apr 2012) | 2 lines Fix typo in svn:keywords ........ r361412
+	  | pabelanger | 2012-04-06 12:27:30 -0400 (Fri, 06 Apr 2012) | 2
+	  lines Fix typo in svn:keywords ........ Merged revisions
+	  361403,361412 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406722 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406723 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 361422 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-28 00:20 +0000 [r406710]  Richard Mudgett <rmudgett at digium.com>
+2012-04-06 15:50 +0000 [r361382]  Russell Bryant <russell at russellbryant.com>
 
-	* /, tests/test_cel.c, tests/test_cdr.c: test_cdr.c, test_cel.c:
-	  Correctly destroy created bridges. * Fixed the
-	  test_cel_attended_transfer_bridges_link unit test to also account
-	  for the local channel link being destroyed now that the bridges
-	  are actually destroyed. * Made CDR unit test use its own version
-	  of do_sleep() from the CEL unit tests. ........ Merged revisions
-	  406707 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, configs/rpt.conf.sample (removed),
+	  configs/usbradio.conf.sample (removed), apps/rpt_flow.pdf
+	  (removed): Remove a few more files related to chan_usbradio and
+	  app_rpt. ........ Merged revisions 361380 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361381 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-27 22:54 +0000 [r406647-406696]  Kevin Harwell <kharwell at digium.com>
+2012-04-06 14:02 +0000 [r361334]  Matthew Jordan <mjordan at digium.com>
 
-	* CHANGES: manager: ExtensionStatus event status human readable
-	  Added a note in the changes file about the new 'StatusText' field
-	  that was added to the 'ExtensionStatus' event. (issue
-	  ASTERISK-23154) Reported by: Jonathan Rose
+	* /, channels/chan_sip.c: Fix a typo in the warning messages for an
+	  ignored media stream Added a '\n' to the warning messages when we
+	  ignore a media stream due to the port number being '0'. (closes
+	  issue ASTERISK-19646) Reported by: Badalian Vyacheslav ........
+	  Merged revisions 361332 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361333 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/manager.c: manager: ExtensionStatus event status human
-	  readable When an 'ExtensionStatus' event was raised it included
-	  the status as a numerical value, but did not include a text
-	  description of the status. Added a 'StatusText' field to the
-	  event which is a string representation of the extension status.
-	  Also added this to the 'Extension State' command response.
-	  (closes issue ASTERISK-23154) Reported by: Jonathan Rose
+2012-04-06 13:32 +0000 [r361331]  Kinsey Moore <kmoore at digium.com>
 
-2014-01-27 20:38 +0000 [r406646]  Russell Bryant <russell at russellbryant.com>
+	* apps/app_dial.c, /: Remove unnecessary error message in
+	  app_dial.c The error message for failure to stop autoservice
+	  after a gosub or macro call during a dial was removed for macro
+	  while Asterisk 1.4 was still being actively developed. The
+	  corresponding gosub error message was never removed. (closes
+	  issue ASTERISK-19551) ........ Merged revisions 361329 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361330 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/config.c, /: Allow nested #includes in extconfig.conf
-	  extconfig.conf was hard-coded to not allow nested includes for
-	  some reason. The code has been this way since a patch was merged
-	  for ASTERISK-3333 (revision 4889), which was a significant update
-	  to this code ("Merge config updates"). I can't figure out any
-	  good reason why this should be limited. This patch just removes
-	  the limit and uses the default nesting depth limit. Closes issue
-	  ASTERISK-17837 Review: https://reviewboard.asterisk.org/r/3159/
-	  ........ Merged revisions 406643 from
+2012-04-05 17:22 +0000 [r361092-361279]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: Fix MusicOnHold in MeetMe so that it always
+	  uses the class if it's been defined There were a few instances of
+	  restarting music on hold in meetme that would cause Asterisk to
+	  revert to the default class of music on hold for no adequate
+	  reason. Review: https://reviewboard.asterisk.org/r/1844/ ........
+	  Merged revisions 361269 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361270 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, addons/ooh323cDriver.c: Fix some stuff involving calls to
+	  memcpy and memset The important parts of the patch were already
+	  applied through other updates. (closes issue ASTERISK-19445)
+	  Reported by: Makoto Dei Patches: memset-memcpy-length.patch
+	  uploaded by Makoto Dei (license 5027) ........ Merged revisions
+	  361210 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 361211 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, funcs/func_devstate.c: Make 'help devstate change' display
+	  properly (get rid of excess comma) (closes issue ASTERISK-19444)
+	  Reported by: Makoto Dei Patches:
+	  devstate-change-usage-truncate.patch uploaded by Makoto Dei
+	  (license 5027) ........ Merged revisions 361201 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361208 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/channel.c, pbx/pbx_loopback.c, addons/chan_ooh323.c, /,
+	  channels/chan_sip.c, main/app.c, pbx/pbx_realtime.c,
+	  apps/app_externalivr.c, channels/chan_iax2.c,
+	  res/res_fax_spandsp.c, apps/app_milliwatt.c: Replace GNU
+	  old-style field designator extensions to fix clang warnings
+	  (issue ASTERISK-19540) Reported by: Makoto Dei Patches:
+	  clang-gnu-designator.patch uploaded by Makoto Dei (license 5027)
+	  ........ Also add from the patch the portion in res_fax_spandsp
+	  that didn't apply to 1.8 Merged revisions 361142 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 (closes issue
+	  ASTERISK-19540) ........ Merged revisions 361143 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_meetme.c: Make the MeetMeAdmin N command (mute all
+	  nonadmins) not mute admins (Closes Issue ASTERISK-19335) Reported
+	  by: Johan Wilfer Review: https://reviewboard.asterisk.org/r/1843/
+	  ........ Merged revisions 361090 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361091 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-03 20:14 +0000 [r361042]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_transfer.c: Fix the display of documentation for
+	  Transfer This came up while fixing documentation generation for
+	  many other cases where the argument separator was not being
+	  displayed properly. Now that it is displayed properly, it shows
+	  up in the wrong place for Transfer since the '/' is only required
+	  if Tech is present. (related to issue ASTERISK-18168) ........
+	  Merged revisions 361040 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 361041 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-04-03 20:03 +0000 [r361038-361039]  Mark Murawki <markm at intellasoft.net>
+
+	* include/asterisk/manager.h: Fix dev-mode compiler warning about
+	  gnu_printf (related to ASTERISK-19575)
+
+	* main/channel.c, main/manager.c, main/utils.c,
+	  include/asterisk/channel.h, include/asterisk/strings.h, CHANGES,
+	  include/asterisk/manager.h: Allow the Hangup manager action to
+	  match channels by regex * Hangup now can take a regular
+	  expression as the Channel option. If you want to hangup multiple
+	  channels, use /regex/ as the Channel option. Existing behavior to
+	  hanging up a single channel is unchanged, but if you pass a
+	  regex, the manager will send you a list of channels back that
+	  were hung up. (closes issue ASTERISK-19575) Reported by: Mark
+	  Murawski Tested by: Mark Murawski
+
+2012-04-02 22:27 +0000 [r360994]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Stop sending out RTCP if RTP is inactive
+	  This change prevents Asterisk from sending RTCP receiver reports
+	  during a remote bridge since it is no longer receiving media and
+	  should not be reporting anything. (related to ASTERISK-19366)
+	  ........ Merged revisions 360987 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406644 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406645 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 360993 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-30 21:38 +0000 [r360935]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/logger.c: Fix logger deadlock on Asterisk shutdown. The
+	  logger_thread() had an exit path that failed to release the
+	  logmsgs list lock. * Make logger_thread() exit path unlock the
+	  logmsgs list lock. * Made ast_log() not queue any messages to the
+	  logmsgs list if the close_logger_thread flag is set. (issue
+	  ASTERISK-19463) Reported by: Matt Jordan ........ Merged
+	  revisions 360933 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360934 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-29 23:36 +0000 [r360872-360886]  Mark Michelson <mmichelson at digium.com>
+
+	* /, main/features.c: Fix potential race condition during call
+	  pickup. Prior to this patch, a connected line update was queued
+	  during call pickup and then an answer frame was queued. The
+	  original caller would presumably then have his connected line
+	  updated and then the call would be answered. In actuality, the
+	  answer frame was not how the call ended up being answered.
+	  Rather, an odd section in app_dial that checks if the called
+	  channel's state is up. The result is that the order of the
+	  connected line update and the answer were variable. In most
+	  cases, this wasn't actually a bad thing. However, if the 'I'
+	  option was passed to dial, the connected line update would be
+	  inhibited. The fix is to queued the connected line after the
+	  answer frame is queued. This way the race in app_dial is between
+	  two conditions resulting in an answer. This way the connected
+	  line update occurs after the answer every time. (closes issue
+	  ASTERISK-19183) Reported by: Thomas Arimont Tested by: Thomas
+	  Arimont Mark Michelson Patches: ASTERISK-19183.patch uploaded by
+	  Mark Michelson (license 5049) ........ Merged revisions 360884
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 360885 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Improve accuracy of identifying
+	  information sent in dialog-info SIP NOTIFY requests. This change
+	  makes use of connected party information in addition to caller ID
+	  in order to populate local and remote XML elements in the
+	  dialog-info NOTIFYs. (closes issue ASTERISK-16735) Reported by:
+	  Maciej Krajewski Tested by: Maciej Krajewski Patches:
+	  local_remote_hint2.diff uploaded by Mark Michelson (license 5049)
+	  ........ Merged revisions 360862 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360863 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-29 21:57 +0000 [r360827]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h, main/astobj2.c: Misc changes to make
+	  astobj2 enhancement diffs easier to follow. * Rename astobj2 API
+	  parameter funcname to func. * Rename astobj2 API iterator
+	  parameter to iter. * Update some documentation for OBJ_MULTIPLE.
+
+2012-03-29 20:01 +0000 [r360785-360787]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/logger.h, main/dial.c, main/pbx.c,
+	  include/asterisk/bridging.h, main/features.c, main/logger.c,
+	  CHANGES, apps/app_mixmonitor.c, configs/logger.conf.sample:
+	  Introducing the log message unique call identifiers feature Log
+	  messages will now display a call number that they are tied to
+	  (ordered for calls based on when they started). This feature is
+	  made to be minimally invasive without requiring changes to many
+	  of the existing log messages. These IDs won't show up for verbose
+	  messages on CLI (but they will in log files) This is currently in
+	  phase II of production, see more about this feature on the wiki
+	  --
+	  https://wiki.asterisk.org/wiki/display/AST/Unique+Call-ID+Logging
+	  Review: https://reviewboard.asterisk.org/r/1823/
+
+	* include/asterisk/logger.h, main/dial.c, main/pbx.c, /,
+	  include/asterisk/bridging.h, main/features.c, main/logger.c,
+	  CHANGES, apps/app_mixmonitor.c, configs/logger.conf.sample:
+	  undoing 360785 due to merging mistake
+
+	* include/asterisk/logger.h, main/dial.c, main/pbx.c, /,
+	  include/asterisk/bridging.h, main/features.c, main/logger.c,
+	  CHANGES, apps/app_mixmonitor.c, configs/logger.conf.sample:
+	  Introducing the log message unique call identifiers feature Log
+	  messages will now display a call number that they are tied to
+	  (ordered for calls based on when they started). This feature is
+	  made to be minimally invasive without requiring changes to many
+	  of the existing log messages. These IDs won't show up for verbose
+	  messages on CLI (but they will in log files) This is currently in
+	  phase II of production, see more about this feature on the wiki
+	  --
+	  https://wiki.asterisk.org/wiki/display/AST/Unique+Call-ID+Logging
+	  Review: https://reviewboard.asterisk.org/r/1823/
+
+2012-03-28 19:39 +0000 [r360724]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_jingle.c, addons/chan_ooh323.c,
+	  cdr/cdr_adaptive_odbc.c, addons/cdr_mysql.c,
+	  channels/chan_gtalk.c, apps/confbridge/conf_config_parser.c: Fix
+	  setting CDR variables in the hangup extension A previous CDR fix
+	  for setting CDR variables during a bridge via custom dialplan
+	  features broke setting CDR variables in the hangup extension.
+	  This patch fixes the issue. Review:
+	  https://reviewboard.asterisk.org/r/1794/ ........ Merged
+	  revisions 358978 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358989 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-27 08:17 +0000 [r406618]  Walter Doekes <walter+asterisk at wjd.nu>
+2012-03-27 18:44 +0000 [r360673]  Mark Michelson <mmichelson at digium.com>
 
-	* main/manager.c, UPGRADE.txt, configs/manager.conf.sample:
-	  manager: The eventfilter= option now takes an extended regex. In
-	  pre-trunk versions (...12) it accepts a basic regex, which is
-	  confusing because all other regexes in asterisk are of the
-	  extended kind. Review: https://reviewboard.asterisk.org/r/3147/
+	* /, channels/chan_sip.c: Make a debug message regarding
+	  subscription changes more accurate. I was getting confused during
+	  some testing why Asterisk was saying that a subscription was
+	  being added when it was clearly being removed. This fixes that
+	  confusion. ........ Merged revisions 360625 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360672 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-27 17:13 +0000 [r360626-360627]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h, tests/test_astobj2.c, main/astobj2.c:
+	  Add global ao2 array container. Global ao2 objects must always
+	  exist after initialization because there is no access control to
+	  obtain another reference to the global object. It is expected
+	  that module configuration could use these new API calls to
+	  replace an active configuration parameter object with an updated
+	  configuration parameter object. With these new API calls, the
+	  global object could be replaced, removed, or referenced without
+	  the risk of someone using a stale global object pointer. Review:
+	  https://reviewboard.asterisk.org/r/1824/
+
+	* main/astobj2.c: Attempt to be more helpful when using a bad ao2
+	  object pointer.
+
+2012-03-27 14:43 +0000 [r360576]  Jonathan Rose <jrose at digium.com>
+
+	* /, configure: Updates config with bootstrap where I changed
+	  configure.ac in r360488 (issue ASTERISK-17842) Reported by: Bryon
+	  Clark ........ Merged revisions 360574 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360575 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-27 01:25 +0000 [r406595]  Russell Bryant <russell at russellbryant.com>
+2012-03-26 21:22 +0000 [r360536]  Paul Belanger <paul.belanger at polybeacon.com>
 
-	* main/file.c, include/asterisk/channel.h, main/channel.c, /:
-	  Protect ast_filestream object when on a channel The
-	  ast_filestream object gets tacked on to a channel via
-	  chan->timingdata. It's a reference counted object, but the
-	  reference count isn't used when putting it on a channel. It's
-	  theoretically possible for another thread to interfere with the
-	  channel while it's unlocked and cause the filestream to get
-	  destroyed. Use the astobj2 reference count to make sure that as
-	  long as this code path is holding on the ast_filestream and
-	  passing it into the file.c playback code, that it knows it's
-	  valid. Bug reported by Leif Madsen. Review:
-	  https://reviewboard.asterisk.org/r/3135/ ........ Merged
-	  revisions 406566 from
+	* main/dnsmgr.c, /: Convert ast_verb() to ast_debug() and increase
+	  log level Rather then flood the CLI with verbose messages, we've
+	  changed the level to debug. This will help keep the CLI clean.
+
+2012-03-26 19:49 +0000 [r360490]  Jonathan Rose <jrose at digium.com>
+
+	* /, configure.ac: Fix BETTER_BACKTRACES library detection for
+	  Fedora/RedHat/CentOS (closes ASTERISK-17842) Reported by: Bryon
+	  Clark Patches: 20110512__issue19278.diff.txt uploaded by Tilghman
+	  Lesher (license 5003) configure_bfd_with_dl_and_iberty.patch
+	  uploaded by Bryon Clark (license 6157) ........ Merged revisions
+	  360488 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 360489 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-24 23:49 +0000 [r360359-360415]  Russell Bryant <russell at russellbryant.com>
+
+	* funcs/func_curl.c, /: func_curl: Fix leak of an ast_str in error
+	  handling code path. ........ Merged revisions 360413 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360414 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_iax2.c: chan_iax2: Use OBJ_NODATA to be a bit more
+	  explicit. This is just a minor code cleanup change. These uses of
+	  ao2_callback() would never return anything since the callbacks
+	  always returned 0. However, be more explicit that no returned
+	  results are wanted by specifying OBJ_NODATA.
+
+	* /, apps/app_page.c: app_page: Fix a memory leak on every Page().
+	  dial_list is a dynamically allocated array that is allocated at
+	  the beginning of Page() based on how many devices will be dialed.
+	  This was never being freed. ........ Merged revisions 360363 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406567 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406574 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 360364 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-26 23:04 +0000 [r406517]  Richard Mudgett <rmudgett at digium.com>
+	* /, apps/app_jack.c: app_jack: fix datastore memory leak in error
+	  handling path. ........ Merged revisions 360360 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360361 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/ast_expr2.h, res/ael/ael.tab.c, main/ast_expr2.y,
+	  main/ast_expr2f.c, res/ael/ael_lex.c, res/ael/ael.tab.h,
+	  main/ast_expr2.c: Multiple revisions 360356-360357 ........
+	  r360356 | russell | 2012-03-23 22:33:36 -0400 (Fri, 23 Mar 2012)
+	  | 6 lines expression parser: Fix (theoretical) memory leak. Fix a
+	  memory leak that is very unlikely to actually happen. If a
+	  malloc() succeeded, but the following strdup() failed, the memory
+	  from the original malloc() would be leaked. ........ r360357 |
+	  russell | 2012-03-23 22:34:39 -0400 (Fri, 23 Mar 2012) | 6 lines
+	  Rebuild parsers. This is needed to include the last fix to
+	  main/ast_expr2.y. The changes look much bigger as this
+	  regeneration of the code was done with newer versions of flex and
+	  bison. ........ Merged revisions 360356-360357 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360358 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-24 00:40 +0000 [r360264-360311]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /, channels/sig_pri.c: Make number not available
+	  presentation also set screening to network provided. Q.951
+	  indicates that when the presentation indicator is "Number not
+	  available due to interworking" for a number then the screening
+	  indicator field should be "Network provided". * Made
+	  ast_party_id_presentation() return AST_PRES_NUMBER_NOT_AVAILABLE
+	  when the presentation is "Number not available due to
+	  interworking". This fix makes Asterisk consistent and it also
+	  makes it consistent with earlier branches as far as this
+	  presentation value is concerned. * Made pri_to_ast_presentation()
+	  and ast_to_pri_presentation() conversions handle the "Number not
+	  available due to interworking" case better in sig_pri.c. This
+	  change is possible because the minimum required libpri version
+	  (v1.4.11) has the necessary defines in libpri.h. ........ Merged
+	  revisions 360309 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360310 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/tcptls.c: tcptls.c: Add missing cleanup on off nominal
-	  path. ........ Merged revisions 406514 from
+	* /, channels/chan_sip.c: Add missing initialization of
+	  update_redirecting in chan_sip.c ........ Merged revisions 360262
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 360263 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-22 21:25 +0000 [r360227]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_dial.c, include/asterisk/utils.h, main/features.c,
+	  main/utils.c, CHANGES, apps/app_queue.c: Adds F option to Bridge
+	  application Similar to dial and queue F option. (Closes issue
+	  ASTERISK-19282) Reported by: To Patches: bridge_f-v3.diff
+	  uploaded by To (license 6347) Review:
+	  https://reviewboard.asterisk.org/r/1825/
+
+2012-03-22 19:51 +0000 [r360190]  Kinsey Moore <kmoore at digium.com>
+
+	* main/udptl.c, main/stdtime/test.c, main/autoservice.c,
+	  main/rtp_engine.c, main/frame.c, main/fskmodem_float.c,
+	  main/sha1.c, main/say.c, main/ecdisa.h, main/utils.c,
+	  main/devicestate.c, main/taskprocessor.c, main/indications.c,
+	  main/enum.c, main/config.c, main/loader.c, main/term.c,
+	  main/cli.c, main/io.c, main/ulaw.c, main/channel.c, main/dial.c,
+	  main/manager.c, main/tdd.c, main/strcompat.c, main/plc.c,
+	  main/features.c, main/logger.c, main/fskmodem_int.c, main/app.c,
+	  main/stdtime/localtime.c, main/image.c, main/dns.c,
+	  main/message.c, main/md5.c, main/sched.c, main/lock.c,
+	  main/pbx.c, main/dnsmgr.c, main/slinfactory.c, main/translate.c,
+	  main/jitterbuf.c, main/cel.c, main/chanvars.c, main/netsock.c,
+	  main/srv.c, main/privacy.c, main/fixedjitterbuf.c, main/file.c,
+	  main/callerid.c, main/event.c, main/astmm.c, main/audiohook.c,
+	  main/cygload.c, main/fixedjitterbuf.h, main/asterisk.c,
+	  main/xmldoc.c, main/dsp.c, main/timing.c: Kill off red blobs in
+	  most of main/* Everything still compiled after making these
+	  changes, so I assume these whitespace-only changes didn't break
+	  anything (and shouldn't have).
+
+2012-03-21 14:55 +0000 [r360140]  Jonathan Rose <jrose at digium.com>
+
+	* /, contrib/scripts/install_prereq: Update install_prereq script
+	  to include missing GSM library for debian amd move SQLite3.
+	  (closes issue ASTERISK-19367) Reported by: Andrew Latham Patches:
+	  debian_install_prereq.diff uploaded by Andrew Latham (license
+	  5985) ........ Merged revisions 360138 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406515 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406516 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-26 14:19 +0000 [r406503]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* contrib/scripts/live_ast: live_ast: run wrapped programs with
-	  exec live_ast can be used as a wrapper script to run asterisk,
-	  gdb or valgrind. In those cases it runs them and returns the
-	  result. It is more useful to use 'exec' to avoid having another
-	  odd process in the chain. Review:
-	  https://reviewboard.asterisk.org/r/3110/
-
-2014-01-26 02:11 +0000 [r406490]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Be less strict
-	  with core requested outgoing capabilities. The core may
-	  (depending on circumstances) request a single codec on outgoing
-	  calls. Many channel drivers ignore or treat this as a suggestion
-	  while still including configured codecs. The res_pjsip_session
-	  logic treated this as an explicit request, leaving out other
-	  configured codecs. This change makes res_pjsip_session behave
-	  like other channel driver and simply adds the requested codec to
-	  the list. (closes issue ASTERISK-23082) Reported by: xrobau
-	  Review: https://reviewboard.asterisk.org/r/3140/ ........ Merged
-	  revisions 406489 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-24 23:33 +0000 [r406466]  Richard Mudgett <rmudgett at digium.com>
+	  revisions 360139 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/cel.c: CEL: Protect data structures during reload and
-	  shutdown. The CEL data structures need to be protected during a
-	  configuration reload and shutdown. Asterisk crashed during a
-	  shutdown because CEL events were still in flight and the CEL data
-	  structures were already destroyed. * Protected the cel_backends,
-	  cel_dialstatus_store, and cel_linkedids ao2 containers with a
-	  global ao2 object wrapper. * Added NULL checks before use of the
-	  cel_backends, cel_dialstatus_store, and cel_linkedids ao2
-	  containers in case the CEL module is already shutdown. * Fixed
-	  overloading of the cel_linkedids held objects reference count.
-	  During shutdown any held objects would be leaked. * Fixed memory
-	  leak of cel_linkedids held objects if the LINKEDID_END is not
-	  being tracked. The objects in the cel_linkedids container were
-	  not removed if the LINKEDID_END event is not used. * Added access
-	  protection to the cel_backends container during the CLI "cel show
-	  status" command. * Made cel_backends, cel_dialstatus_store, and
-	  cel_linkedids use the standard ao2 callback templates for the
-	  hash and cmp functions. * Eliminated unnecessary uses of
-	  RAII_VAR(). * Made ast_cel_engine_init() cleanup alocated
-	  resources on failure. (closes issue AST-1253) Reported by:
-	  Guenther Kelleter Review:
-	  https://reviewboard.asterisk.org/r/3128/ ........ Merged
-	  revisions 406417 from
+2012-03-21 14:47 +0000 [r360137]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, configure, configure.ac: Also detect gmime 2.6 Also detect
+	  gmime version 2.6 (Michael Biebl) Signed-off-by: Tzafrir Cohen
+	  (License #5035) <tzafrir.cohen at xorcom.com> ........ Merged
+	  revisions 360087 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360098 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-21 13:31 +0000 [r360089]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Ensure Asterisk sends a BYE when pending
+	  on the final response to a re-INVITE When Asterisk detects a
+	  hangup and cannot send a BYE due to a pending INVITE, it sets the
+	  pendingbye flag and waits for the final response to that INVITE.
+	  When the response is received, it transmits the BYE. If, however,
+	  that INVITE request is a pending re-INVITE, it needs to first
+	  send a CANCEL request to terminate the pending re-INVITE. In that
+	  circumstance, Asterisk was, in some scenarios, clearing the
+	  pendingbye flag after processing the CANCEL request and not
+	  checking for a pending BYE when receiving the final 487 response
+	  to the INVITE. This patch ensures that if the pendingbye flag is
+	  set, it is honored regardless of the nature of the INVITE request
+	  currently in flight. (closes issue ASTERISK-19365) Reported by:
+	  Thomas Arimont Tested by: Thomas Arimont Patches:
+	  bugASTERISK-19365_2012_03_08.patch uploaded by mjordan (license
+	  6283) Review: https://reviewboard.asterisk.org/r/1807 ........
+	  Merged revisions 360086 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-20 20:42 +0000 [r360036]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_echo.c: Prevent Echo() from relaying control, null,
+	  and modem frames Echo()'s description states that it echoes
+	  audio, video, and DTMF except for # while it actually echoes any
+	  frame that it receives other than DTMF #. This was causing frame
+	  storms in the test suite in some circumstances where Echo() was
+	  attached to both ends of a pair of local channels and control
+	  frames were being periodically generated. Echo()'s behavior and
+	  description have been modifed so that it only echoes media and
+	  non-# DTMF frames. ........ Merged revisions 360033 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 360034 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-20 18:17 +0000 [r359983]  Sean Bright <sean at malleable.com>
+
+	* /, UPGRADE.txt, channels/chan_iax2.c, include/asterisk/manager.h:
+	  chan_iax2: Correct spelling of 'Port' header in IAX2 PeerStatus
+	  AMI Events The PeerStatus event for IAX2 channels currently
+	  includes a header named Post which should have been Port. Post
+	  was removed and the AMI version has been updated to 1.3. ........
+	  Merged revisions 359982 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-20 17:31 +0000 [r359942-359981]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/data.c, main/pbx.c, main/manager.c, /, main/features.c,
+	  include/asterisk/manager.h, main/db.c: Allow AMI action callback
+	  to be reentrant. Fix AMI module reload deadlock regression from
+	  ASTERISK-18479 when it tried to fix the race between calling an
+	  AMI action callback and unregistering that action. Refixes
+	  ASTERISK-13784 broken by ASTERISK-17785 change. Locking the ao2
+	  object guaranteed that there were no active callbacks that
+	  mattered when ast_manager_unregister() was called. Unfortunately,
+	  this causes the deadlock situation. The patch stops locking the
+	  ao2 object to allow multiple threads to invoke the callback
+	  re-entrantly. There is no way to guarantee a module unload will
+	  not crash because of an active callback. The code attempts to
+	  minimize the chance with the registered flag and the maximum 5
+	  second delay before ast_manager_unregister() returns. The trunk
+	  version of the patch changes the API to fix the race condition
+	  correctly to prevent the module code from unloading from memory
+	  while an action callback is active. * Don't hold the lock while
+	  calling the AMI action callback. (closes issue ASTERISK-19487)
+	  Reported by: Philippe Lindheimer Review:
+	  https://reviewboard.asterisk.org/r/1818/ Review:
+	  https://reviewboard.asterisk.org/r/1820/ ........ Merged
+	  revisions 359979 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359980 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* res/res_mutestream.c: Convert MuteAudio documentation to XML. *
+	  Added missing error exits with cause in manager_mutestream(). *
+	  Cleaned up manager_mutestream() and func_mute_write(). * Some
+	  whitespace and comment cleanup.
+
+2012-03-16 21:00 +0000 [r359905]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_chanspy.c: Prevent chanspy from binding to zombie
+	  channels This patch addresses a bug with chanspy on local
+	  channels which roughly 50% of the time would create a situation
+	  where chanspy can latch onto a zombie channel, keeping the zombie
+	  alive forever and causing the channel doing the spying to never
+	  be able to hang up. (closes issue ASTERISK-19493) Reported by:
+	  lvl Review: https://reviewboard.asterisk.org/r/1819/ ........
+	  Merged revisions 359892 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406418 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406465 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 359898 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-24 22:34 +0000 [r406416]  Jonathan Rose <jrose at digium.com>
+2012-03-16 20:37 +0000 [r359904]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/utils.c, CHANGES: Thread Debugging: Add LWP to core show
-	  locks output This patch adds the LWP to core show locks output if
-	  it is available. Review: https://reviewboard.asterisk.org/r/3142/
+	* include/asterisk/app.h, main/app.c: Simplify some code in
+	  ast_app_run_sub(). * Remove unnnecessary const from const char *
+	  const var declaration in the ast_app_run_macro() and
+	  ast_app_run_sub() prototypes. The second const is unnecessary.
 
-2014-01-24 22:18 +0000 [r406407]  Richard Mudgett <rmudgett at digium.com>
+2012-03-16 15:38 +0000 [r359857]  Mark Michelson <mmichelson at digium.com>
 
-	* main/manager.c, /: manager: Register atexit shutdown routine only
-	  once. * Made register atexit shutdown routine only once in
-	  __init_manager(). * Fixed some initial load failure conditions in
-	  __init_manager(). * Made reset options to defaults on reload when
-	  the reload will actually happen. * Removed unnecessary container
-	  traversals of the white/black filters during manager_free_user().
-	  * ast_free() does not need a NULL check before calling. ........
-	  Merged revisions 406359 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406400 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406401 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* apps/app_dial.c, main/pbx.c, include/asterisk/pbx.h, CHANGES:
+	  Revert the pre-dial addition. The code may be just fine, but it
+	  had not received a "ship it!" on review board yet.
 
-2014-01-24 21:46 +0000 [r406399]  Jonathan Rose <jrose at digium.com>
+2012-03-16 08:27 +0000 [r359811]  Alec L Davis <sivad.a at paradise.net.nz>
 
-	* res/res_config_pgsql.c, /: res_config_pgsql: Fix a memory leak
-	  and use RAII_VAR for cleanup when practical Review:
-	  https://reviewboard.asterisk.org/r/3141/ ........ Merged
-	  revisions 406360 from
+	* /, channels/sip/include/sip.h: Missed lastinvite CSeq int to
+	  uint32_t change from Review:
+	  https://reviewboard.asterisk.org/r/1699/ ........ Merged
+	  revisions 359809 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406361 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406389 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-24 18:13 +0000 [r406343]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/manager.c, /: manager: Protect data structures during
-	  shutdown. Occasionally, the manager module would get an
-	  "INTERNAL_OBJ: bad magic number" error on a "core restart
-	  gracefully" command if an AMI connection is established. * Added
-	  ao2_global_obj protection to the sessions global container. *
-	  Fixed the order of unreferencing a session object in
-	  session_destroy(). * Removed unnecessary container traversals of
-	  the white/black filters during session_destructor(). (closes
-	  issue AST-1242) Reported by: Guenther Kelleter Review:
-	  https://reviewboard.asterisk.org/r/3144/ ........ Merged
-	  revisions 406341 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406342 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-23 23:43 +0000 [r406328]  Mark Michelson <mmichelson at digium.com>
-
-	* /: Today is not my day for writing code that compiles. ........
-	  Merged revisions 406327 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-23 22:56 +0000 [r406312]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, addons/res_config_mysql.c: res_config_mysql: Fix Setting The
-	  Column Name Incorrectly When support for a realtime sorcery
-	  module was added in revision 386731, the wrong property was
-	  accidentally used for setting the column name to be updated in
-	  the database table. This patch fixes the typo. (closes issue
-	  ASTERISK-23177) Reported by: Denis Tested by: Denis Patches:
-	  asterisk-23177-use-field-name.diff by Michael L. Young (license
-	  5026) ........ Merged revisions 406311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-23 21:18 +0000 [r406298]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pidf.c, /: Multiple revisions 406294-406295
-	  ........ r406294 | mmichelson | 2014-01-23 15:00:24 -0600 (Thu,
-	  23 Jan 2014) | 11 lines Fix presence body errors found during
-	  testing: * PIDF bodies were reporting an "open" state in many
-	  cases where it should have been reporting "closed" * XPIDF bodies
-	  had XML nodes placed incorrectly within the hierarchy. * SIP URIs
-	  in XPIDF bodies did not go through XML sanitization * XML
-	  sanitization had some errors: * Right angle bracket was being
-	  replaced with "&rt;" instead of ">" * Double quote,
-	  apostrophe, and ampersand were not being escaped. ........
-	  r406295 | mmichelson | 2014-01-23 15:09:35 -0600 (Thu, 23 Jan
-	  2014) | 11 lines Fix presence body errors found during testing: *
-	  PIDF bodies were reporting an "open" state in many cases where it
-	  should have been reporting "closed" * XPIDF bodies had XML nodes
-	  placed incorrectly within the hierarchy. * SIP URIs in XPIDF
-	  bodies did not go through XML sanitization * XML sanitization had
-	  some errors: * Right angle bracket was being replaced with "&rt;"
-	  instead of ">" * Double quote, apostrophe, and ampersand were
-	  not being escaped. ........ Merged revisions 406294-406295 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-22 22:24 +0000 [r406269]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/pbx.c, /, utils/extconf.c: pbx.c: Pre-initialize timezone to
-	  avoid crash on destroy In ast_build_timing, initialize the
-	  timezone value to NULL in order to avoid deferencing an
-	  uninitialized value later when calling ast_destroy_timing. The
-	  timezone value could be uninitialized if ast_build_timing were to
-	  fail due to a zero length time string. (closes issue
-	  ASTERISK-22861) Reported by: Sebastian Murray-Roberts Review:
-	  https://reviewboard.asterisk.org/r/3134/ Patches:
-	  ast_build_timing-initialize-timezone.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 406241 from
+	  revisions 359810 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-15 20:11 +0000 [r359772]  Mark Murawki <markm at intellasoft.net>
+
+	* main/pbx.c: Fix warning from commit r359705 (predial options for
+	  app_dial)
+
+2012-03-15 19:11 +0000 [r359708]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/utils.c: Fix remotely exploitable stack overflow in HTTP
+	  manager There exists a remotely exploitable stack buffer overflow
+	  in HTTP digest authentication handling in Asterisk. The
+	  particular method in question is only utilized by HTTP AMI. When
+	  parsing the digest information, the length of the string is not
+	  checked when it is copied into temporary buffers allocated on the
+	  stack. This patch fixes this behavior by parsing out pre-defined
+	  key/value pairs and avoiding unnecessary copies to the stack.
+	  (closes issue ASTERISK-19542) Reported by: Russell Bryant Tested
+	  by: Matt Jordan ........ Merged revisions 359706 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406245 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406264 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-22 19:36 +0000 [r406153-406224]  Kinsey Moore <kmoore at digium.com>
+	  revisions 359707 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-15 18:58 +0000 [r359705]  Mark Murawki <markm at intellasoft.net>
+
+	* apps/app_dial.c, main/pbx.c, include/asterisk/pbx.h, CHANGES: Add
+	  options PreDial options 'b' and 'B' to app_dial * Added 'b' and
+	  'B' options to Dial. These options will allow you to run
+	  last-minute dialplan on the caller and callee channels while the
+	  Dial application is executing, but before the call is started.
+	  For example you can use the 'b' option to run dialplan on the
+	  callee channel to get the name of the newly created channel right
+	  away. Review: https://reviewboard.asterisk.org/r/1229/ (closes
+	  issue: ASTERISK-19548) Reported by: Mark Murawski Tested by: Mark
+	  Murawski, Stefan Schmidt
+
+2012-03-15 18:55 +0000 [r359704]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_milliwatt.c: Fix remotely exploitable stack overrun
+	  in Milliwatt Milliwatt is vulnerable to a remotely exploitable
+	  stack overrun when using the 'o' option. This occurs due to the
+	  milliwatt_generate function not accounting for
+	  AST_FRIENDLY_OFFSET when calculating the maximum number of
+	  samples it can put in the output buffer. This patch resolves this
+	  issue by taking into account AST_FRIENDLY_OFFSET when determining
+	  the maximum number of samples allowed. Note that at no point is
+	  remote code execution possible. The data that is written into the
+	  buffer is the pre-defined Milliwatt data, and not custom data.
+	  (closes issue ASTERISK-19541) Reported by: Russell Bryant Tested
+	  by: Matt Jordan Patches: milliwatt_stack_overrun.rev1.txt by
+	  Russell Bryant (license 6283) Note that this patch was written by
+	  Russell, even though Matt uploaded it ........ Merged revisions
+	  359645 from http://svn.asterisk.org/svn/asterisk/branches/1.6.2
+	  ........ Merged revisions 359656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359694 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-15 18:34 +0000 [r359651]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* channels/chan_sip.c: Remove unused variable ‘srch’ Missed on the
+	  previous commit
+
+2012-03-15 18:32 +0000 [r359644]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, /, apps/app_queue.c: Add missing connected line
+	  macro calls to initial dial for Dial and Queue apps. The
+	  connected line interception macros do not get executed when the
+	  outgoing channel is initially created and that channel's
+	  caller-id is implicitly imported into the incoming channel's
+	  connected line data. If you are using the interception macros,
+	  you would expect that they get run for every change to a
+	  channel's connected line information outside of normal dialplan
+	  execution. Review: https://reviewboard.asterisk.org/r/1817/
+	  ........ Merged revisions 359609 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359620 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, apps/app_confbridge.c: ConfBridge: Fix channel parameter
-	  documentation Confbridge AMI and CLI commands for mute, unmute,
-	  and setting the single video source can accept channel prefixes
-	  in lieu of a full channel name, but documentation states only
-	  that it is required and is a channel name. This corrects the
-	  documentation. (closes issue PQ-1397) Reported by: Steve Pitts
-	  ........ Merged revisions 406217 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406223 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-03-15 17:36 +0000 [r359607]  Paul Belanger <paul.belanger at polybeacon.com>
 
-	* /, channels/chan_sip.c: chan_sip: Decline image streams on
-	  unsupported transports This change allows chan_sip to decline
-	  individual image streams over unsupported transports in the SDP
-	  of the 200 response. Previously, an image stream offer with
-	  RTP/AVP as the transport would cause chan_sip to respond with a
-	  488. (closes issue ASTERISK-22988) Reported by: adomjan Original
-	  patch by: adomjan ........ Merged revisions 406170 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406171 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406172 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* channels/chan_sip.c: Remove some dead code found in
+	  _sip_show_peers() Review:
+	  https://reviewboard.asterisk.org/r/1696/
 
-	* res/res_stasis_playback.c, /: res_stasis_playback: Correct error
-	  argument order Several of the playback error messages for invalid
-	  media input in res_stasis_playback.c had the media name and
-	  channel name reversed. They now correctly identify the channel
-	  name and media name. Reported by: skrusty ........ Merged
-	  revisions 406152 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-03-15 00:54 +0000 [r359456-359560]  Russell Bryant <russell at russellbryant.com>
 
-2014-01-21 21:48 +0000 [r406134]  Rusty Newton <rnewton at digium.com>
+	* /, channels/chan_iax2.c: chan_iax2: Fix use of uninitialized
+	  sockaddr_in in try_transfer(). Initialize a struct sockaddr_in in
+	  try_transfer() so that the code isn't (potentially) trying to
+	  read from it while uninitialized. ........ Merged revisions
+	  359558 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 359559 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, res/res_pjsip.c: res_pjsip: Documentation improvement for
-	  Endpoint and AOR mailbox options. Making the help text for both
-	  more explicit regarding the format of mailbox identifiers. i.e.
-	  clarifying the format for app_voicemail mailboxes vs mailboxes
-	  from external MWI sources through modules such as
-	  res_external_mwi. ........ Merged revisions 406133 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/chan_gtalk.c: chan_gtalk: Fix potential use of
+	  uninitialized variable. Avoid potential use of idroster in
+	  gtalk_alloc() before it has been initialized. ........ Merged
+	  revisions 359508 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359509 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_chanisavail.c: app_chanisavail: Fix use of
+	  uninitialized variable. Ensure that status is set before it is
+	  used by resetting it during each loop iteration. This could have
+	  resulted in incorrect results from this app. ........ Merged
+	  revisions 359486 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359491 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/udptl.c, /: udptl: Ensure fec[] in udptl_build_packet() is
+	  initialized. Scan results indicated that this array could be used
+	  uninitialized. At a quick look, it looks correct. In any case,
+	  initializing it is a Good Thing (tm). ........ Merged revisions
+	  359457 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 359458 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* include/asterisk/app.h, /: app.h: Always initialize
+	  AST_DECLARE_APP_ARGS(). This patch ensures that the struct
+	  defined by AST_DECLARE_APP_ARGS() is always fully initialized.
+	  I'm not sure if this fixes any real bugs, but it silences a bunch
+	  of warnings from coverity, and is generally a good thing to do
+	  anyway. ........ Merged revisions 359452 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359454 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-21 21:08 +0000 [r406082]  Walter Doekes <walter+asterisk at wjd.nu>
+2012-03-14 22:38 +0000 [r359455]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/manager.c, /, configs/manager.conf.sample: manager: Clarify
-	  eventfilter documentation. Textual changes only. Review:
-	  https://reviewboard.asterisk.org/r/3133/ ........ Merged
-	  revisions 406079 from
+	* main/channel.c, /, channels/chan_agent.c,
+	  include/asterisk/channel.h: Fix deadlock potential with some
+	  ast_indicate/ast_indicate_data calls. Calling
+	  ast_indicate()/ast_indicate_data() with the channel lock held can
+	  result in a deadlock with a local channel because of how local
+	  channels need to avoid deadlock. ........ Merged revisions 359451
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 359453 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-14 18:56 +0000 [r359406]  Matthew Jordan <mjordan at digium.com>
+
+	* tests/test_jitterbuf.c (added): Add tests for main/jitterbuf.c
+	  This patch adds unit tests for main/jitterbuf.c. This includes
+	  checking for the following: * Nominal insertion and retrieval of
+	  frames * Insertion and retrieval of frames where the frames are
+	  inserted out of order with respect to the previous frame *
+	  Insertion and retrieval of frames where some number of frames
+	  that would occur in the expected sequence are instead dropped *
+	  Insertion and retrieval of frames with an arrival time that does
+	  not occur at the same rate as the surrounding frames *
+	  Resynchronization of the jitter buffer when an inserted frame
+	  breaks the resynchronization threshold * Overfilling of the
+	  jitter buffer For each of the tests, both JB_TYPE_VOICE and
+	  JB_TYPE_CONTROL permutations exist. Review:
+	  https://reviewboard.asterisk.org/r/1815 (issue: ASTERISK-18964)
+	  Reported by: Kris Shaw Tested by: Kris Shaw, Matt Jordan
+
+2012-03-14 18:12 +0000 [r359360]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/channel_internal.h: Three copies of the file
+	  contents in channel_internal.h are a bit excessive.
+
+2012-03-14 17:48 +0000 [r359359]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/jitterbuf.c: Fix incorrect jitter buffer overflow due to
+	  missed resynchronizations When a change in time occurs, such that
+	  the timestamps associated with frames being placed into an
+	  adaptive jitter buffer (implemented in jitterbuf.c) are
+	  significantly different then the previously inserted frames, the
+	  jitter buffer checks to see if it needs to be resynched to the
+	  new time frame. If three consecutive packets break the threshold,
+	  the jitter buffer resynchs itself to the new timestamps. This
+	  currently only occurs when history is calculated, and hence only
+	  on JB_TYPE_VOICE frames. JB_TYPE_CONTROL frames, on the other
+	  hand, are never passed to the history calculations. Because of
+	  this, if the jump in time is greater then the maximum allowed
+	  length of the jitter buffer, the JB_TYPE_CONTROL frames are
+	  dropped and no resynchronization occurs. Alterntively, if the
+	  overfill logic is not triggered, the JB_TYPE_CONTROL frame will
+	  be placed into the buffer, but with a time reference that is not
+	  applicable. Subsequent JB_TYPE_VOICE frames will quickly trigger
+	  the overflow logic until reads from the jitter buffer reach the
+	  errant JB_TYPE_CONTROL frame. This patch allows JB_TYPE_CONTROL
+	  frames to resynch the jitter buffer. As JB_TYPE_CONTROL frames
+	  are unlikely to occur in multiples, it perform the
+	  resynchronization on any JB_TYPE_CONTROL frame that breaks the
+	  resynch threshold. Note that this only impacts chan_iax2, as
+	  other consumers of the adaptive jitter buffer use the abstract
+	  jitter buffer API, which does not use JB_TYPE_CONTROL frames.
+	  Review: https://reviewboard.asterisk.org/r/1814/ (closes issue
+	  ASTERISK-18964) Reported by: Kris Shaw Tested by: Kris Shaw, Matt
+	  Jordan Patches: jitterbuffer-2012-2-26.diff uploaded by Kris Shaw
+	  (license 5722) ........ Merged revisions 359356 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406080 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406081 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-21 20:28 +0000 [r406006-406078]  Kinsey Moore <kmoore at digium.com>
-
-	* channels/chan_mgcp.c, /: chan_mgcp: Enforce locking for oseq This
-	  restricts direct usage of global oseq so that all accesses are
-	  locked and threads are not racing to get oseq values that they
-	  did not claim. This also fixes a build error in res_pktccops
-	  under dev mode. (closes issue ASTERISK-23100) Reported by:
-	  adomjan Patch by: adomjan ........ Merged revisions 406037 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 406038 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 406049 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_outbound_registration.c, res/res_pjsip.c: PJSIP:
-	  Handle headers in a list appropriately The PJSIP header parsing
-	  function (pjsip_parse_hdr) can generate more than one header
-	  instance from a single header field. These header instances exist
-	  as a list attached to the returned header and must be handled
-	  appropriately when they are added to a message or else only the
-	  first header instance will be used. This changes the linked list
-	  functions used in outbound proxy code to merge the lists
-	  properly. ........ Merged revisions 406020 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_sounds.h, res/ari/resource_bridges.h,
-	  res/ari/resource_device_states.h, res/ari/resource_mailboxes.h,
-	  res/ari/resource_asterisk.h, rest-api/api-docs/channels.json,
-	  res/ari/resource_applications.h, res/ari/resource_channels.c,
-	  res/res_ari_playbacks.c, res/res_ari_sounds.c,
-	  rest-api-templates/asterisk_processor.py,
-	  res/ari/resource_channels.h, res/res_ari_bridges.c, /,
-	  res/res_ari_device_states.c,
-	  rest-api-templates/ari_resource.h.mustache,
-	  res/res_ari_mailboxes.c, res/res_ari_asterisk.c,
-	  res/res_ari_applications.c,
-	  rest-api-templates/res_ari_resource.c.mustache,
-	  rest-api-templates/body_parsing.mustache (added),
-	  res/res_ari_channels.c, res/ari/resource_playbacks.h,
-	  rest-api-templates/param_parsing.mustache: ARI: Support channel
-	  variables in originate This adds back in support for specifying
-	  channel variables during an originate without compromising the
-	  ability to specify query parameters in the JSON body. This was
-	  accomplished by generating the body-parsing code in a separate
-	  function instead of being integrated with the URI query parameter
-	  parsing code such that it could be called by paths with body
-	  parameters. This is transparent to the user of the API and
-	  prevents manual duplication of code or data structures. (closes
-	  issue ASTERISK-23051) Review:
-	  https://reviewboard.asterisk.org/r/3122/ Reported by: Matt Jordan
-	  ........ Merged revisions 406003 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-20 23:25 +0000 [r405985]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny: fix up handling of fragmented
-	  packets. Bad offset in reading second or more fragment of skinny
-	  packets. Fixed to offset by char (single byte) rather than size
-	  of req. ........ Merged revisions 405982 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-20 22:23 +0000 [r405947]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/sig_pri.c, /: chan_dahdi/PRI: Suppress CONNECTED_LINE
-	  updates when nothing in the udpate is valid. * Also simplified
-	  some subddress handling code. (closes issue ASTERISK-23008)
-	  Reported by: Michael Cargile ........ Merged revisions 405926
+	  revisions 359358 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-14 17:39 +0000 [r359357]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, main/channel.c, /: Fix Dial m and r options and
+	  forked calls generating warnings for voice frames. When connected
+	  line support was added, the wait_for_answer() variable single
+	  changed its meaning slightly. Unfortunately, the places where
+	  single was used did not necessarily get updated to reflect that
+	  change. Also audio/video frames were sent to all forked calls
+	  when the endpoints were never made compatible. * Don't pass
+	  audio/video media frames when the channels have not been made
+	  compatible. * Added handling of AST_CONTROL_SRCCHANGE to
+	  app_dial.c. * Fixed app_dial.c passing on AST_CONTROL_HOLD
+	  because that frame can also pass a requested MOH class. (closes
+	  issue ASTERISK-16901) Reported by: Chris Gentle (closes issue
+	  ASTERISK-17541) Reported by: clint Review:
+	  https://reviewboard.asterisk.org/r/1805/ ........ Merged
+	  revisions 359344 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359355 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-14 14:40 +0000 [r359306]  Matthew Jordan <mjordan at digium.com>
+
+	* include/asterisk/astobj2.h: Force non-inlining of
+	  ao2_iterator_destroy when TEST_FRAMEWORK is enabled In r357272,
+	  astobj2 was changed to automatically enable REF_DEBUG when the
+	  TEST_FRAMEWORK flag was enabled. Unfortunately, some compilers
+	  (gcc 4.5.1 at least) will attempt to inline ao2_iterator_destroy
+	  in handle_astobj2_test. This by itself is not a problem;
+	  unfortunately, the compiler believes that there is a code path
+	  wherein an object allocated on the stack will be free'd. As
+	  warnings are treated as errors, this prevents compilation of
+	  astobj2. This patch works around that by adding the noinline
+	  attribue to ao2_iterator_destroy, but only if the TEST_FRAMEWORK
+	  flag is enabled. Preventing inlining is only needed for the test
+	  method defined in astobj2, which is also only enabled if
+	  TEST_FRAMEWORK is enabled.
+
+2012-03-14 10:56 +0000 [r359052-359261]  Russell Bryant <russell at russellbryant.com>
+
+	* include/asterisk/logger.h, /, main/logger.c: Fix bogus
+	  reads/writes of console log levels in asterisk.c This patch
+	  updates the NUMLOGLEVELS define in logger.h to 32, to match the
+	  fact that logger.c implements 32 log levels (because of the
+	  custom log level stuff). asterisk.c uses this define to size an
+	  array of levels per remote console. This array is modified in
+	  ast_console_toggle_loglevel(), which is called by the "logger set
+	  level" CLI command. While the documentation for the CLI command
+	  doesn't make it terribly obvious, you can use this CLI command to
+	  toggle a custom log level on a remote console, as well. However,
+	  doing so led to an invalid array index in asterisk.c. This array
+	  is read from any time a log message is written to a console. So,
+	  all custom log level messages resulted in a bogus read if a
+	  remote console was connected. ........ Merged revisions 359259
 	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 405927 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405928 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-20 21:56 +0000 [r405925]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny: fix up session logging.
-	  Logging from the skinny session loop was providing some incorrect
-	  reasons for exiting the loop. Cleaned up messages and handling so
-	  correct reason displayed. ........ Merged revisions 405924 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-20 18:18 +0000 [r405910]  Jonathan Rose <jrose at digium.com>
-
-	* channels/chan_pjsip.c, /: chan_pjsip: Provide a means for
-	  tracking device state when holding/unholding Previously PJSIP did
-	  not track hold/unhold and it would always simply be 'inuse'. This
-	  patch fixes that. review:
-	  https://reviewboard.asterisk.org/r/3129/ ........ Merged
-	  revisions 405908 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-19 00:01 +0000 [r405894]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny: fix reversed device reset from
-	  CLI. Existing code would do a full device restart when "skinny
-	  reset device" was entered at the CLI and do a reset when "skinny
-	  reset device restart" entered. ........ Merged revisions 405893
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-17 22:09 +0000 [r405878]  Sean Bright <sean at malleable.com>
-
-	* /, channels/chan_sip.c: Make sure the maxptime attribute is added
-	  to the correct offers. ........ Merged revisions 405877 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-17 21:33 +0000 [r405862-405876]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/format_pref.c, main/sorcery.c, main/frame.c, /,
-	  include/asterisk/format_pref.h, res/res_pjsip_sdp_rtp.c: pjsip:
-	  fix support for allow=all This change adds improvements to
-	  support for allow=all in pjsip.conf so that it functions as
-	  intended. Previously, the allow/disallow socery configuration
-	  would set & clear codecs from the media.codecs and media.prefs
-	  list, but if all was specified the prefs list was not updated.
-	  Then a call would fail when create_outgoing_sdp_stream() created
-	  an SDP with no audio codecs. A new function
-	  ast_codec_pref_append_all() is provided to add all codecs to the
-	  prefs list - only those not already on the list. This enables the
-	  configuration to specify a codec preference, but still add all
-	  codecs, and even then remove some codecs, as shown in this
-	  example: allow = ulaw, alaw, all, !g729, !g723 Also, the display
-	  order of allow in cli output is updated to match the
-	  configuration by using prefs instead of caps when generating a
-	  human readable string. Finally, a change to
-	  create_outgoing_sdp_stream() skips a codec when it does not have
-	  a payload code instead of the call failing. (closes issue
-	  ASTERISK-23018) Reported by: xrobau Review:
-	  https://reviewboard.asterisk.org/r/3131/ ........ Merged
-	  revisions 405875 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/http.c: http: supported chunked Transfer-Encoding This
-	  change implements support for HTTP Transfer-Encoding chunked in
-	  both JSON and Form (post vars) body content. A new function
-	  ast_http_get_contents() handles both regular and chunked mode
-	  body, returning after the entire body is received. (closes issue
-	  ASTERISK-23068) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3125/ ........ Merged
-	  revisions 405861 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-17 18:55 +0000 [r405778-405844]  Rusty Newton <rnewton at digium.com>
-
-	* res/res_pjsip.c, /: Fixing some XML syntax issues with my
-	  previous commit at r405777 for ASTERISK-23071 ........ Merged
-	  revisions 405843 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Merged revisions 359260 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_externalivr.c, channels/chan_iax2.c: Fix invalid
+	  reads/writes due to incorrect sizeof(). These few places in the
+	  code used sizeof() on h_addr in struct hostent. This is
+	  sizeof(char *). The correct way to get the size of this address
+	  is to use h_length. This error would result in reads/writes of 8
+	  bytes instead of 4 on 64-bit machines. ........ Merged revisions
+	  359211 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 359212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/sched.c: Fix inaccurate sizeof() in sched.c. This code
+	  just needed sizeof(int), not sizeof(int *). ........ Merged
+	  revisions 359157 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359162 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c, doc/asterisk.8, main/features.c,
-	  configs/sip.conf.sample, apps/app_queue.c, apps/app_transfer.c,
-	  channels/chan_iax2.c: Documentation: doc fixes across various
-	  parts of the code for ASTERISK issues 23061,23028,23046,23027
-	  Fixes typos of "transfered" instead of "transferred" in various
-	  code. Fixes incorrect gosub param help text for app_queue. Fixes
-	  Asterisk man pages containing unquoted minus signs. Adds note
-	  about the "textsupport" option in sip.conf.sample. (issue
-	  ASTERISK-23061) (issue ASTERISK-23028) (issue ASTERISK-23046)
-	  (issue ASTERISK-23027) (closes issue ASTERISK-23061) (closes
-	  issue ASTERISK-23028) (closes issue ASTERISK-23046) (closes issue
-	  ASTERISK-23027) Reported by: Eugene, Jeremy Laine, Denis
-	  Pantsyrev Patches: transferred.patch uploaded by Jeremy Laine
-	  (license 6561) hyphen.patch uploaded by Jeremy Laine (license
-	  6561) sip.conf.sample.patch uploaded by Eugene (license 6360)
-	  ........ Merged revisions 405791 from
+	* /, utils/astman.c: Fix incorrect sizeof() in astman. ........
+	  Merged revisions 359116 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 405792 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405829 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip.c, /: res_pjsip: enhance documentation for
-	  mailboxes options, for both endpoints and aors Made documentation
-	  more explicit as to the use of the both options. (issue
-	  ASTERISK-23071) (closes issue ASTERISK-23071) Reported by: Matt
-	  Jordan ........ Merged revisions 405777 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-17 14:17 +0000 [r405766]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* res/res_musiconhold.c, CHANGES: Enable wide band audio in
-	  musiconhold streams. Review:
-	  https://reviewboard.asterisk.org/r/3112/
-
-2014-01-16 20:06 +0000 [r405747-405749]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip/pjsip_options.c, /: res_pjsip: AOR option
-	  qualify_frequency not respected on startup If an endpoint had
-	  previously dynamically registered a contact and the contact
-	  information was successfully stored in astdb then upon restart
-	  the qualify notifications would not be sent out if the
-	  qualify_frequency was set. This was due to the fact that only
-	  permanent contacts were being checked and scheduled for qualifies
-	  on startup. Modified the code to check and schedule all
-	  registered contacts at startup. (closes issue ASTERISK-23062)
-	  Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/3124/ ........ Merged
-	  revisions 405748 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /: manager: Originate doesn't abort on failed
-	  format_cap allocation action_originate responds to the remote
-	  system with an error when cap==NULL, but doesn't return (abort
-	  the originate). Patched to return. (closes issue ASTERISK-23034)
-	  Reported by: Corey Farrell Patches: ASTERISK-23034.patch uploaded
-	  by coreyfarrell (license 5909) ........ Merged revisions 405745
-	  from http://svn.asterisk.org/svn/asterisk/branches/11 ........
-	  Merged revisions 405746 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-16 19:33 +0000 [r405744]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip.c: PJSIP: Fix outbound OPTIONS support When path
-	  support was added and contacts were made available during request
-	  creation and transmission, the code path used by outbound qualify
-	  support was not modified correctly and was causing request
-	  creation to fail. This ensures that outbound request creation
-	  with only a contact and no dialog, endpoint, or uri can succeed
-	  which restores qualify support. Reported by: gtjoseph Reported
-	  by: kharwell ........ Merged revisions 405743 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-16 19:13 +0000 [r405644-405695]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_fax.c, configs/res_fax.conf.sample: res_fax:
-	  check_modem_rate() returned incorrect rate for V.27 According to
-	  the new standard for V.27 and V.32 they are able to transmit at a
-	  bit rate of 4,800 or 9,600. The check_mode_rate function needed
-	  to be updated to reflect this. Also, because of this change the
-	  default 'minrate' value was updated to be 4800. (closes issue
-	  ASTERISK-22790) Reported by: Paolo Compagnini Patches:
-	  res_fax.txt uploaded by looserouting (license 6548) ........
-	  Merged revisions 405656 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 405693 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405694 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_pjsip.c: chan_pjsip: initial device state on
-	  endpoints is INVALID When endpoints get loaded their device state
-	  gets set to 'INVALID' because the channel driver has not been
-	  loaded yet. Fixed by updating the device state for every endpoint
-	  upon load of the channel driver. (closes issue ASTERISK-23065)
-	  Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/3123/ ........ Merged
-	  revisions 405643 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-15 16:51 +0000 [r405586-405589]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES: Make 12 - 12.1 CHANGES log the same as in 12
-
-	* CHANGES, /: Include CHANGES info for r405553 ........ Merged
-	  revisions 405585 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-15 16:36 +0000 [r405584]  Joshua Colp <jcolp at digium.com>
+	  revisions 359117 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, cel/cel_manager.c: cel_manager: Don't crash if configuration
-	  file is invalid. The cel_manager module did not properly handle
-	  the case where the configuration file was invalid. The module
-	  will now output a warning message and disable itself if this
-	  occurs. Reported by: Bryan Walters ........ Merged revisions
-	  405581 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 405582 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405583 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-15 13:16 +0000 [r405566]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_pjsip/location.c, res/res_pjsip_outbound_registration.c,
-	  res/res_pjsip_path.c (added), res/res_pjsip_mwi.c,
-	  res/res_pjsip/pjsip_distributor.c, res/res_pjsip_diversion.c,
-	  channels/chan_pjsip.c, res/res_pjsip_registrar.c,
-	  res/res_pjsip_refer.c, include/asterisk/res_pjsip.h,
-	  include/asterisk/res_pjsip_session.h, res/res_pjsip_notify.c, /,
-	  res/res_pjsip_messaging.c, res/res_pjsip_caller_id.c,
-	  res/res_pjsip_t38.c, res/res_pjsip.c,
-	  res/res_pjsip/pjsip_options.c, res/res_pjsip_nat.c,
-	  res/res_pjsip_session.c,
-	  contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
-	  (added), res/res_pjsip_header_funcs.c: PJSIP: Add Path header
-	  support This adds Path support to chan_pjsip in res_pjsip_path.c
-	  with minimal additions in res_pjsip_registrar.c to store the path
-	  and additions in res_pjsip_outbound_registration.c to enable
-	  advertisement of path support to registrars and intervening
-	  proxies. Path information is stored on contacts and is enabled
-	  via Address of Record (AoRs) and Registration configuration
-	  sections. While adding path support, it became necessary to be
-	  able to add SIP supplements that handled messages outside of
-	  sessions, so a framework for handling these types of hooks was
-	  added in parallel to the already-existing session supplements and
-	  several senders of out-of-dialog requests were refactored as a
-	  result. (closes issue ASTERISK-21084) Review:
-	  https://reviewboard.asterisk.org/r/3050/ ........ Merged
-	  revisions 405565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-14 23:44 +0000 [r405554]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_stasis_mailbox.exports.in (added),
-	  res/ari/ari_model_validators.h, rest-api/api-docs/mailboxes.json
-	  (added), include/asterisk/stasis_app_mailbox.h (added),
-	  res/ari/resource_mailboxes.c (added), /, res/ari.make,
-	  res/res_ari_mailboxes.c (added), res/ari/resource_mailboxes.h
-	  (added), res/res_stasis_mailbox.c (added),
-	  rest-api/resources.json, res/ari/ari_model_validators.c: ARI: Add
-	  mailboxes resource for controlling and polling external MWI Adds
-	  the following AMI commands: PUT mailboxes/mailboxName modifies
-	  mailbox state and implicitly creates new mailboxes GET
-	  mailboxes/mailboxName retrieves a JSON representation of a single
-	  mailbox if it exists GET mailboxes retrieves a JSON array of all
-	  mailboxes DELETE mailbox/mailboxName deletes a mailbox Note that
-	  res_mwi_external must be loaded for these functions to actually
-	  do anything. Review: https://reviewboard.asterisk.org/r/3117/
-	  ........ Merged revisions 405553 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-14 21:46 +0000 [r405542]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/strings.c, /: string container: Remove unnecessary RAII_VAR
-	  usage and string object lock. ........ Merged revisions 405541
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-14 18:15 +0000 [r405437]  Scott Griepentrog <sgriepentrog at digium.com>
+	* /, res/res_crypto.c: Fix incorrect usage of sizeof() in
+	  res_crypto. In this case, just remove the memset(). There was a
+	  redundant memset that is done correctly just 2 lines later.
+	  ........ Merged revisions 359110 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359114 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: chan_sip: fix Local From tag on outbound
-	  register regression In ASTERISK-12117, an improvement to insure
-	  consistant local from tags on outbound registrations resulted in
-	  an undesirable behavior - caused by leftover unexpired sip_pvt
-	  dialogs (with the previous cseq number), resulting in many
-	  uncessary REGISTER requests. Instead of significant rework of
-	  transmit_register(), this change deletes the dialogs after a 200
-	  OK response indiciating a successful registration, keeping the
-	  old dialogs from interfering with normal operation. (closes issue
-	  ASTERISK-22946) Reported by: Stephan Eisvogel Review:
-	  https://reviewboard.asterisk.org/r/3109/ ........ Merged
-	  revisions 405433 from
+	* /, res/res_adsi.c: Fix broken usage of sizeof() in res_adsi.
+	  ........ Merged revisions 359088 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 405434 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405435 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 359091 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/features.c: Fix incorrect sizeof() usage in features.c.
+	  This didn't actually result in a bug anywhere, luckily. The only
+	  place where the result of these memcpys was used is in app_dial,
+	  and the only field that it read out of ast_call_feature was the
+	  first one, which is an int, so these memcpys always copied just
+	  enough to avoid a problem. ........ Merged revisions 359069 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359072 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-14 18:14 +0000 [r405436]  Richard Mudgett <rmudgett at digium.com>
+	* /, main/md5.c: Fix incorrect sizeof() on a pointer in MD5Final().
+	  ........ Merged revisions 359059 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359060 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_verbose.c, main/asterisk.c, configs/logger.conf.sample,
-	  main/cli.c, include/asterisk/logger.h, main/pbx.c,
-	  main/manager.c, /, funcs/func_timeout.c, apps/app_dumpchan.c,
-	  main/logger.c, UPGRADE.txt: verbosity: Fix performance of console
-	  verbose messages. The per console verbose level feature as
-	  previously implemented caused a large performance penalty. The
-	  fix required some minor incompatibilities if the new rasterisk is
-	  used to connect to an earlier version. If the new rasterisk
-	  connects to an older Asterisk version then the root console
-	  verbose level is always affected by the "core set verbose"
-	  command of the remote console even though it may appear to only
-	  affect the current console. If an older version of rasterisk
-	  connects to the new version then the "core set verbose" command
-	  will have no effect. * Fixed the verbose performance by not
-	  generating a verbose message if nothing is going to use it and
-	  then filtered any generated verbose messages before actually
-	  sending them to the remote consoles. * Split the "core set debug"
-	  and "core set verbose" CLI commands to remove the per module
-	  verbose support that cannot work with the per console verbose
-	  level. * Added a silent option to the "core set verbose" command.
-	  * Fixed "core set debug off" tab completion. * Made "core show
-	  settings" list the current console verbosity in addition to the
-	  root console verbosity. * Changed the default verbose level of
-	  the 'verbose' setting in the logger.conf [logfiles] section. The
-	  default is now to once again follow the current root console
-	  level. As a result, using the AMI Command action with "core set
-	  verbose" could again set the root console verbose level and
-	  affect the verbose level logged. (closes issue AST-1252) Reported
-	  by: Guenther Kelleter Review:
-	  https://reviewboard.asterisk.org/r/3114/ ........ Merged
-	  revisions 405431 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405432 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-14 16:43 +0000 [r405420]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip/pjsip_distributor.c: Fix erroneous behavior when
-	  sending auth rejection to artificial endpoint. We were not
-	  including an authentication challenge when sending a 401 response
-	  to unmatched endpoints. This was due to the conversion to use a
-	  vector for authentication section names on an endpoint. The
-	  vector for artificial endpoints was empty, resulting in the
-	  challenge being sent back containing no challenges. This is
-	  worked around by placing a bogus value in the artificial
-	  endpoint's auth vector. This value is never looked up by
-	  anything, since they instead will directly call
-	  ast_sip_get_artificial_auth().
-
-2014-01-14 03:27 +0000 [r405369]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Skinny: do not add call to missed
-	  calls list if answered elsewhere. Patch updates skinny devices
-	  with a SKINNY_CONNECTED callstate if an inbound ringing or
-	  callwaiting call is answered elsewhere. ........ Merged revisions
-	  405367 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-13 13:34 +0000 [r405339]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip/pjsip_cli.c: res_pjsip: Fix CLI tab completion
-	  issues This fixes several issues with the new res_pjsip CLI tab
-	  completion such as output of headers during tab completion and
-	  being able to tab-complete more items than the code actually
-	  handled (further items would simply be ignored). (closes issue
-	  ASTERISK-23081) Review: https://reviewboard.asterisk.org/r/3115/
-	  Reported by: xrobau ........ Merged revisions 405338 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-12 22:24 +0000 [r405326]  Joshua Colp <jcolp at digium.com>
-
-	* res/ari/resource_playbacks.c, res/ari/resource_channels.c,
-	  include/asterisk/ari.h, res/ari/resource_bridges.c,
-	  res/ari/resource_recordings.c, res/ari/resource_device_states.c,
-	  res/res_ari.c, res/ari/resource_endpoints.c, /,
-	  res/ari/resource_applications.c: res_ari: Fix various memory
-	  leaks. This change fixes a few memory leaks that were found based
-	  on a mailing list post. 1. Some JSON response messages were never
-	  freed. This was caused by the documentation stating that message
-	  references were stolen when in reality they were not. The code
-	  now follows the documentation and usage has been updated. 2. HTTP
-	  response headers were never freed. 3. The variable list for
-	  wildcards paths was never freed. (closes issue ASTERISK-23128)
-	  Reported by: Kenneth Watson (on list) Review:
-	  https://reviewboard.asterisk.org/r/3119/ ........ Merged
-	  revisions 405325 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-12 22:13 +0000 [r405313-405314]  Matthew Jordan <mjordan at digium.com>
-
-	* apps/app_forkcdr.c, /, funcs/func_cdr.c, include/asterisk/cdr.h,
-	  apps/app_cdr.c, main/cdr.c: CDRs: Synchronize dialplan
-	  applications that manipulate CDRs with the engine In
-	  https://reviewboard.asterisk.org/r/3057/, applications and
-	  functions that manipulate CDRs were made to interact over Stasis.
-	  This was done to synchronize manipulations of CDRs from the
-	  dialplan with the updates the engine itself receives over the
-	  message bus. This change rested on a faulty premise: that
-	  messages published to the CDR topic or to a topic that forwards
-	  to the CDR topic are synchronized with the messages handled by
-	  the CDR topic subscription in the CDR engine. This is not the
-	  case. There is no ordering guaranteed for two messages published
-	  to the same topic; ordering is only guaranteed if a message is
-	  published to the same subscriber. Stasis was modified in r405311
-	  to allow a publisher to synchronize on the subscriber. This patch
-	  uses that API to synchronize the CDR publishers with the CDR
-	  engine message router, which maintains the overall topic
-	  subscription. (closes issue ASTERISK-22884) Reported by: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/3099/ ........
-	  Merged revisions 405312 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis.c, main/stasis_message_router.c, /,
-	  include/asterisk/stasis.h,
-	  include/asterisk/stasis_message_router.h, tests/test_stasis.c:
-	  stasis: Add methods to allow for synchronous publishing to
-	  subscriber This patch adds an API call to Stasis that allows a
-	  publisher to publish a stasis message that will not return until
-	  a specific subscriber handles the message. Since a subscriber can
-	  have their own forwarding topic which orders messages from many
-	  topics, this allows a publisher who knows of that subscriber to
-	  synchronize to that subscriber regardless of the forwarding
-	  relationships between topics. This is of particular use for
-	  dialplan applications that need to synchronize on a particular
-	  subscriber's handling of a message. (issue ASTERISK-22884)
-	  Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3099/ ........ Merged
-	  revisions 405311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-10 20:00 +0000 [r405299]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip/security_events.c: Print "<unknown>" for
-	  artificial endpoint in PJSIP security events. Previously, this
-	  printed a UUID, which was not very clear when dealing with an
-	  artificial endpoint. Review:
-	  https://reviewboard.asterisk.org/r/3113 ........ Merged revisions
-	  405298 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-10 18:17 +0000 [r405284]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/logger.c: Logging callid: Fix some sizeof() references
-	  per coding guidelines. ........ Merged revisions 405281 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405282 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 23:52 +0000 [r405270]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_session.c: PJSIP: Add unhold on reinvite without
-	  SDP behavior Review: https://reviewboard.asterisk.org/r/3106/
-
-2014-01-09 23:50 +0000 [r405269]  Damien Wedhorn <voip at facts.com.au>
-
-	* channels/chan_dahdi.c, /: Fix chan_dahdi copile issue in
-	  dev-mode. Error "unused variable i in dahdi_create_channel_range"
-	  when compiling in dev-mode. Small restructure to
-	  dahdi_create_channel_range to move the for(x) loop and int i,x to
-	  a block within the IFDEF. ........ Merged revisions 405268 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 23:39 +0000 [r405267]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip.c, /, res/res_pjsip_messaging.c:
-	  res_pjsip_messaging: potential for field values in from/to
-	  headers to be missing Added in ability to specify display name
-	  format ("name" <sip:name at ipaddr:port>) for a given URI and made
-	  sure it was fully propagated to the outgoing message. Also made
-	  it so outoing messages in res_pjsip always send as "sip:".
-	  (closes issue ASTERISK-22924) Reported by: Anthony Messina
-	  Review: https://reviewboard.asterisk.org/r/3094/ ........ Merged
-	  revisions 405266 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 20:34 +0000 [r405254]  Kinsey Moore <kmoore at digium.com>
-
-	* main/astobj2.c, res/res_pjsip_session.c, /,
-	  include/asterisk/astobj2.h: astobj2: Correct ao2_iterator opacity
-	  violations This corrects the ao2_iterator opacity violations in
-	  res_pjsip_session.c by adding a global function to get the number
-	  of elements inside the container hidden behind the iterator.
-	  (closes issue ASTERISK-23053) Review:
-	  https://reviewboard.asterisk.org/r/3111/ Reported by: Richard
-	  Mudgett ........ Merged revisions 405253 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 16:52 +0000 [r405236]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fails to resume
-	  WebRTC call from hold In ast_rtp_ice_start if the ice session
-	  create check list failed, start check was never initiated and
-	  ice_started was never set to true. Upon re-entering the function
-	  (for instance, [un]hold) it would try to create the check list
-	  again with duplicate remote candidates. Fixed so that if the
-	  create check list fails the necessary data structures are
-	  properly re-initialized for any subsequent retries. Note, it was
-	  decided to not stop ice support (by calling ast_rtp_ice_stop) on
-	  a check list failure because it possible things might still work.
-	  However, a debug message was added to help with any future
-	  troubleshooting. (closes issue ASTERISK-22911) Reported by: Vytis
-	  Valentinavičius Patches: works_on_my_machine.patch uploaded by
-	  xytis (license 6558) ........ Merged revisions 405234 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405235 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 15:50 +0000 [r405217]  Matthew Jordan <mjordan at digium.com>
-
-	* /, apps/app_confbridge.c,
-	  apps/confbridge/conf_state_multi_marked.c: app_confbridge: Fix
-	  crash caused when waitmarked/marked users leave together When
-	  waitmarked users join a ConfBridge, the conference state is
-	  transitioned from EMPTY -> INACTIVE. In this state, the users are
-	  maintined in a waiting users list. When a marked user joins, the
-	  ConfBridge conference transitions from INACTIVE -> MULTI_MARKED,
-	  and all users are put onto the active list of users. This process
-	  works correctly. When the marked user leaves, if they are the
-	  last marked user, the MULTI_MARKED state does the following: (1)
-	  It plays back a message to the bridge stating that the leader has
-	  left the conference. This requires an unlocking of the bridge.
-	  (2) It moves waitmarked users back to the waiting list (3) It
-	  transitions to the appropriate state: in this case, INACTIVE
-	  However, because it plays the prompt back to the bridge before
-	  moving the users and before finishing the state transition, this
-	  creates a race condition: with the bridge unlocked, waitmarked
-	  users who leave the conference (or are kicked from it) can cause
-	  a state transition of the bridge to another state before the
-	  conference is transitioned to the INACTIVE state. This causes the
-	  state machine to get a bit wonky, often leading to a crash when
-	  the MULTI_MARKED state attempts to conclude its processing. This
-	  patch fixes this problem: (1) It prevents kicked users from being
-	  kicked again. That's just a nicety. (2) More importantly, it
-	  fixes the race condition by only playing the prompt once the
-	  state has transitioned correctly to INACTIVE. If waitmarked users
-	  sneak out during the prompt being played, no harm no foul.
-	  Review: https://reviewboard.asterisk.org/r/3108/ Note that the
-	  patch committed here is essentially the same as uploaded by Simon
-	  Moxon on ASTERISK-22740, with the addition of the double kick
-	  prevention. (closes issue AST-1258) Reported by: Steve Pitts
-	  (closes issue ASTERISK-22740) Reported by: Simon Moxon patches:
-	  ASTERISK-22740.diff uploaded by Simon Moxon (license 6546)
-	  ........ Merged revisions 405215 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405216 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-09 14:15 +0000 [r405163]  Walter Doekes <walter+asterisk at wjd.nu>
-
-	* /, apps/app_dumpchan.c: "Minimun" typo. ........ Merged revisions
-	  405160 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 405161 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405162 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/pbx.c, /: Don't use a buffer after it goes out of scope. 's'
+	  is set to 'workspace'. Make sure 'workspace' doesn't go out of
+	  scope while the reference to it via 's' is still used. ........
+	  Merged revisions 359056 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359057 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_usbradio.c (removed), /, channels/xpmr (removed),
+	  build_tools/menuselect-deps.in, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac, makeopts.in,
+	  apps/app_rpt.c (removed): Remove chan_usbradio and app_rpt. These
+	  modules are being maintained outside of the tree and have been
+	  for a long time now, so it doesn't make sense to keep them here.
+	  Review: https://reviewboard.asterisk.org/r/1764/ ........ Merged
+	  revisions 359050 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 359051 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-08 17:23 +0000 [r405144]  Mark Michelson <mmichelson at digium.com>
+2012-03-13 21:24 +0000 [r359011]  Terry Wilson <twilson at digium.com>
 
-	* /, res/res_pjsip/security_events.c: Use proper case for checking
-	  if digest authentication is used. ........ Merged revisions
-	  405131 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* include/asterisk/channel_internal.h (added): Add missing
+	  channel_internal.h ...again.
 
-2014-01-08 16:34 +0000 [r405129-405130]  Kinsey Moore <kmoore at digium.com>
+2012-03-13 21:18 +0000 [r358997]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, configure, configure.ac, pbx/pbx_lua.c: pbx_lua: Add support
-	  for Lua 5.2 This adds support for Lua 5.2 in pbx_lua which is
-	  available on newer operating systems. (closes issue
-	  ASTERISK-23011) Review: https://reviewboard.asterisk.org/r/3075/
-	  Reported by: George Joseph Patch by: George Joseph ........
-	  Merged revisions 405090 from
+	* channels/sig_pri.h, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, channels/sig_pri.c: Add ability
+	  for chan_dahdi ISDN to block connected line updates per span.
+	  Added new chan_dahdi.conf colp_send option parameter to block
+	  connected line updates per span. (closes issue ASTERISK-17025)
+	  Reported by: Michael Smith
+
+2012-03-13 20:43 +0000 [r358907-358993]  Terry Wilson <twilson at digium.com>
+
+	* /, main/features.c: Fix setting CDR variables in the hangup
+	  extension A previous CDR fix for setting CDR variables during a
+	  bridge via custom dialplan features broke setting CDR variables
+	  in the hangup extension. This patch fixes the issue. Review:
+	  https://reviewboard.asterisk.org/r/1794/ ........ Merged
+	  revisions 358978 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 405091 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405124 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 358989 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* include/asterisk/devicestate.h, /, channels/chan_sip.c,
+	  tests/test_devicestate.c, main/devicestate.c: Make hints for
+	  invalid SIP devices return Unavail, not idle This patch
+	  drastically simplifies the device state aggegation code. The old
+	  method was not only overly complex, but also made it impossible
+	  to return AST_DEVICE_INVALID from the aggregation code. The unit
+	  test update is as a result of fixing that bug. The SIP change
+	  stems from a bug introduced by removing a DNS lookup for
+	  hostname-based SIP channels. (closes issue ASTERISK-16702)
+	  Review: https://reviewboard.asterisk.org/r/1808/ ........ Merged
+	  revisions 358943 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358944 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: Add the missing part of r400140 When the
-	  patch to add retry-on-forbidden-response was committed, part of
-	  the patch for chan_sip was not committed which caused the feature
-	  to be entirely nonfunctional. This corrects the code in question.
-	  (closes issue ASTERISK-17138) Review:
-	  https://reviewboard.asterisk.org/r/2874 ........ Merged revisions
-	  405033 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 405081 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 405083 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-07 19:56 +0000 [r405020-405035]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_acl.c: res_pjsip_acl: Fix another case of
-	  assuming a contact will always contain a URI. ........ Merged
-	  revisions 405034 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_nat.c: res_pjsip_nat: Don't assume a Contact
-	  header will always contain a URI. If the 'rewrite_contact' option
-	  was enabled and a Contact header was received which contained a
-	  '*' a crash would occur. This change makes the res_pjsip_nat
-	  module ignore the Contact header if it contains only a '*'.
-	  (closes issue ASTERISK-23101) Reported by: Matt Jordan ........
-	  Merged revisions 405019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-06 21:55 +0000 [r404953-405007]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_voicemail.c, /: app_voicemail: Explicitly set
-	  defaultenabled=yes ........ Merged revisions 405006 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_mwi_external_ami.c (added): External MWI AMI support.
-	  The external MWI AMI interface provides a thin wrapper around the
-	  core external MWI resource. The resource adds the following AMI
-	  actions: MWIGet, MWIDelete, and MWIUpdate. (closes issue AFS-46)
-	  Review: https://reviewboard.asterisk.org/r/3061/ ........ Merged
-	  revisions 404954 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_mwi_external.c (added), configs/sorcery.conf.sample,
-	  include/asterisk/res_mwi_external.h (added),
-	  res/res_mwi_external.exports.in (added), apps/app_voicemail.c:
-	  External MWI core support. * The core external MWI resource
-	  provides for MWI message counts persistence using sorcery. With
-	  sorcery, the user is able to configure which sorcery wizzard
-	  backend to use if the default astdb is not desired. * The core
-	  external MWI resoruce provides some debugging CLI commands
-	  enabled by defining MWI_DEBUG_CLI. The debugging CLI commands
-	  are: "mwi delete all", "mwi delete like <regex>", "mwi delete
-	  mailbox <mailbox>", "mwi list all", "mwi list like <regex>", "mwi
-	  show mailbox <mailbox>", and "mwi update mailbox <mailbox> [<new>
-	  [<old>]]". (closes issue AFS-43) Review:
-	  https://reviewboard.asterisk.org/r/3061/ ........ Merged
-	  revisions 404952 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-05 16:01 +0000 [r404924-404936]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_outbound_registration.c:
-	  res_pjsip_outbound_registration: Don't assume that a registration
-	  client will always exist. ........ Merged revisions 404935 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_outbound_registration.c:
-	  res_pjsip_outbound_registration: Create registration client in pj
-	  thread. Depending on which threading was loading the outbound
-	  registration it was possible for the registration client to be
-	  allocated outside of a pj thread. This change moves the creation
-	  inside the synchronous task where it is guaranteed it will occur
-	  in a pj thread. Reported by: Rob Thomas ........ Merged revisions
-	  404923 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-04 10:52 +0000 [r404912]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+	* apps/app_voicemail.c: Fix IMAP storage compilation after
+	  opaquification changes (closes issue ASTERISK-19513)
 
-	* main/asterisk.c, /: asterisk.c: suppress live_dangerously warning
-	  on rasterisk Even since the fixes of AST-2013-007, Asterisk
-	  prints the following warning on startup if the user decided to
-	  live dangerously: Privilege escalation protection disabled! See
-	  https://wiki.asterisk.org/wiki/x/1gKfAQ for more details. This
-	  message is intended for the logs and interactive startup. No need
-	  for it to appear on a remote console. This commit removes it from
-	  there. (closes issue ASTERISK-23084) Review:
-	  https://reviewboard.asterisk.org/r/3101/ ........ Merged
-	  revisions 404861 from
+	* channels/chan_unistim.c, main/autoservice.c,
+	  channels/chan_vpb.cc, channels/chan_local.c, main/rtp_engine.c,
+	  res/res_musiconhold.c, bridges/bridge_multiplexed.c,
+	  apps/app_followme.c, main/indications.c, main/cli.c,
+	  main/channel.c, channels/chan_phone.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c, main/manager.c, main/features.c,
+	  apps/app_dumpchan.c, res/res_agi.c, main/app.c,
+	  apps/app_confbridge.c, apps/app_externalivr.c, main/bridging.c,
+	  apps/app_parkandannounce.c, apps/app_dial.c, main/pbx.c,
+	  channels/chan_sip.c, channels/chan_bridge.c,
+	  main/channel_internal_api.c, channels/chan_agent.c,
+	  apps/app_disa.c, include/asterisk/channel.h,
+	  apps/app_talkdetect.c, apps/app_queue.c, apps/app_speech_utils.c,
+	  apps/app_channelredirect.c, main/file.c, res/snmp/agent.c,
+	  apps/app_macro.c, apps/app_stack.c, apps/app_chanspy.c,
+	  apps/app_mixmonitor.c: Finalize ast_channel opaquification
+	  Review: https://reviewboard.asterisk.org/r/1786/
+
+2012-03-13 17:01 +0000 [r358858-358861]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c: Fix crash caused by opaquification change
+	  -r356042. The set_format() function was more subtle in how it
+	  modified the struct ast_channel readtrans/writetrans values. *
+	  Fixed ast_activate_generator() conversion correctly. (closes
+	  issue ASTERISK-19434) Reported by: Birger Harzenetter Tested by:
+	  rmudgett
+
+	* main/format.c: Use struct copy instead of memcpy().
+
+2012-03-13 08:06 +0000 [r358812]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* res/ael/pval.c, funcs/func_dialplan.c, /, tests/test_gosub.c,
+	  utils/ael_main.c, apps/app_stack.c, utils/conf2ael.c: Enable
+	  macros in 1.8 to find the next highest "h" extension in a
+	  context, like in 1.4. This change restores functionality that was
+	  present in 1.4, when AEL macros were implemented with the Macro
+	  dialplan application. Macros are fraught with functionality
+	  issues, because they consume a large portion of the underlying
+	  application stack. This limits the ability of AEL users to call
+	  many layers of subroutines, an issue which Gosub does not have
+	  (originally tested to 100,000 levels deep). Therefore, starting
+	  in 1.6.0, AEL macros were implemented with Gosub. However, there
+	  were some implicit behaviors of Macro, which were not replicated
+	  at the same time as with the transition to Gosub, one of which is
+	  documented in the related issue. In particular, the "h" extension
+	  is designed to execute not in the Macro context, but in the
+	  topmost calling context. Due to legacy issues with a misapplied
+	  bugfix many years ago, when a macro exited in 1.4, it looks in
+	  all calling contexts, bubbling up from the deepest level until it
+	  finds an "h" extension. Since AEL hides the complexity of the
+	  underlying dialplan logic from the AEL programmer, it's
+	  reasonable to assume that this behavior should not change in the
+	  transition from Asterisk 1.4 LTS to Asterisk 1.8 LTS, lest we
+	  break working AEL configurations in the transition to Asterisk
+	  1.8 LTS. This fix is the result, which implements a search for
+	  the "h" extension in all calling Gosub contexts. Fixes
+	  ASTERISK-19336 Patch: 20120308__ael_bugfix_for_trunk__2.diff
+	  (License #5003) by Tilghman Lesher (with slight modifications for
+	  1.8) Tested by: Johan Wilfer Review:
+	  https://reviewboard.asterisk.org/r/1776/ ........ Merged
+	  revisions 358810 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404888 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404911 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-03 22:00 +0000 [r404860]  Kevin Harwell <kharwell at digium.com>
+	  revisions 358811 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-12 17:01 +0000 [r358766]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, contrib/unistimLang/ru.po (added),
+	  contrib/unistimLang/ru.po.utf8 (added),
+	  configs/unistim.conf.sample, UPGRADE.txt, CHANGES,
+	  contrib/unistimLang/en.po (added), contrib/unistimLang (added):
+	  Massive changes in chan_unistim channel driver. Include many
+	  fixes in channel driver operation and add additional
+	  functionality: * Added ability to use multiple lines on phone, so
+	  for one device in configuration multiple lines can be defined, it
+	  allows to have multiple calls on one phone, callwaiting and
+	  switching between calls. * Added ability for translation
+	  on-screen menu to multiple languages. Tested on Russian
+	  languages. Supported encodings: ISO 8859-1, ISO 8859-2, ISO
+	  8859-4, ISO 8859-5, ISO 2022-JP. Language controlled by
+	  'language' and on-screen menu of phone * Other described in
+	  CHANGES file Testing done by issue tracker users: ibercom,
+	  scsiborg, idarwin, TeknoJuce, c0rnoTa. Tested on production
+	  system by Jonn Taylor (jonnt) using phone models: Nortel i2004,
+	  1120E and 1140E. (closes issue ASTERISK-16890) Review:
+	  https://reviewboard.asterisk.org/r/1243/
+
+2012-03-10 20:06 +0000 [r358730]  Joshua Colp <jcolp at digium.com>
+
+	* configs/confbridge.conf.sample, main/dial.c, apps/app_page.c,
+	  apps/confbridge/include/confbridge.h, apps/app_confbridge.c,
+	  include/asterisk/dial.h, CHANGES,
+	  apps/confbridge/conf_config_parser.c: Transition app_page to
+	  using app_confbridge internally for the conference bridge portion
+	  of paging. This also adds a new 'announcement' option to
+	  ConfBridge user profiles. Review:
+	  https://reviewboard.asterisk.org/r/1754/
+
+2012-03-08 17:48 +0000 [r358646-358691]  Sean Bright <sean at malleable.com>
+
+	* apps/app_dial.c, apps/app_directory.c, apps/app_queue.c: Resolve
+	  a few more cases of variable shadowing.
+
+	* channels/chan_phone.c, channels/chan_skinny.c,
+	  channels/chan_agent.c, pbx/pbx_lua.c, pbx/pbx_dundi.c,
+	  channels/chan_gtalk.c, pbx/pbx_config.c, channels/chan_oss.c,
+	  apps/confbridge/conf_config_parser.c: Eliminate a bunch of shadow
+	  warnings.
+
+	* include/asterisk/linkedlists.h: Add some underscores in a few of
+	  our llist macros to reduce name collisions.
+
+2012-03-08 16:59 +0000 [r358645]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Make transfer not ignore port information
+	  with SIP. Attempting to transfer with SIP to an address like
+	  1XXXXX at ip.ad.re.ss:5061 would fail because port would be cut from
+	  the host string and ignored. This simply keeps chan_sip from
+	  cutting off the port number during these kinds of transfers.
+	  (closes issue ASTERISK-19321) Reported by: Federico Alves Review:
+	  https://reviewboard.asterisk.org/r/1790/diff/#index_header
+	  ........ Merged revisions 358643 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358644 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-08 16:21 +0000 [r358609-358622]  Sean Bright <sean at malleable.com>
+
+	* Makefile, configure, configure.ac, makeopts.in: Add
+	  --enable-dev-mode=strict to configure. Passing -Wshadow to gcc
+	  enables shadow warnings. From the gcc manual: Warn whenever a
+	  local variable or type declaration shadows another variable,
+	  parameter, type, or class member (in C++), or whenever a built-in
+	  function is shadowed. Asterisk will not currently compile with
+	  this option set, but a number of bugs have been discovered by
+	  enabling this flag on specific files. The long-term goal is to
+	  eliminate all of the suspect code that causes this warning to be
+	  emitted.
+
+	* Makefile: Whitespace only change to the Makefile
+
+2012-03-07 21:28 +0000 [r358576]  Terry Wilson <twilson at digium.com>
+
+	* cel/cel_odbc.c, configs/cel_odbc.conf.sample: Handle numeric
+	  columns for eventtype properly in cel_odbc Patch also implements
+	  correct handling of datetime2 and datetimeoffset new datatypes in
+	  SQL Server 2008 and 2008 R2. (closes issue ASTERISK-17548)
+	  Review: https://reviewboard.asterisk.org/r/1160/ Review:
+	  https://reviewboard.asterisk.org/r/1804/
+
+2012-03-07 18:33 +0000 [r358532]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_ss7.c: Change directly setting _softhangup in
+	  sig_ss7.c to use ast_softhangup_nolock(). Update to: (issue
+	  ASTERISK-19372) ........ Merged revisions 358530 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358531 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* cel/cel_pgsql.c, /: cel_pgsql: module not correctly reloading
-	  Upon reload the module unconditionally "unloaded" the module
-	  (freeing memory and setting pointers to NULL) and then when
-	  attempting a "load" if the config file had not changed then
-	  nothing would be reinitialized. By moving the "unload" to occur
-	  conditionally (reload only) after an attempted configuration
-	  load, but before module "loading" alleviates the issue. The
-	  module now loads/unloads/reloads correctly. (closes issue
-	  ASTERISK-22871) Reported by: Matteo ........ Merged revisions
-	  404857 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 404858 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404859 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-03 21:45 +0000 [r404844-404856]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_pjsip_logger.c: res_pjsip_logger: Add the
-	  ASTERISK_FILE_VERSION macro Registering yourself with the
-	  Asterisk core is the nice thing to do, even when you're a logging
-	  module. ........ Merged revisions 404855 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_authenticator_digest.c, tests/test_utils.c:
-	  res_pjsip_authenticator_digest: Fix md5 hash buffer An md5 hash
-	  is 32 bytes long. The char buffer must be at least 33 bytes to
-	  avoid clobbering of the stack. This patch also fixes a potential
-	  clobbering in test_utils.c. Thanks to Andrew Nagy for reporting
-	  and testing this out in #asterisk-dev Reported by: Andrew Nagy
-	  Tested by: Andrew Nagy ........ Merged revisions 404843 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-03 20:02 +0000 [r404787-404832]  Kevin Harwell <kharwell at digium.com>
-
-	* main/manager.c: manager: UserEvent including action on output AMI
-	  action UserEvent event response would include the action header
-	  in its keyvalue pairs list. Adjusted the start of the header loop
-	  to skip over the action part. (closes issue ASTERISK-22899)
-	  Reported by: outtolunc Patches:
-	  svn_manager.c.skip_action.diff.txt uploaded by outtolunc (license
-	  5198)
+2012-03-07 16:16 +0000 [r358486]  Sean Bright <sean at malleable.com>
 
-	* channels/chan_dahdi.c, /: chan_dahdi: dahdi show channels slices
-	  PRI channel dnid on output dahdi show channels output slices the
-	  callerid (which is dnid copied over on PRI channels). If the
-	  channel naming structures look like: 'DAHDI/i1/1408409XXXX-6'
-	  then the output slices 1408409XXXX down to 1408409XXX. This patch
-	  just opens it up to 15 chars so you can see the whole thing.
-	  (closes issue ASTERISK-22918) Reported by: outtolunc Patches:
-	  svn_chan_dahdi.c.format12_15.diff.txt uploaded by outtolunc
-	  (license 5198) ........ Merged revisions 404784 from
+	* /, codecs/codec_dahdi.c: Return g729 and g723.1 frames with the
+	  number of samples set properly. If the wctc4xxp returns more than
+	  a single packet, we need to update the number of samples in the
+	  returned frame accordingly. Acked-by: Shaun Ruffell
+	  <sruffell at digium.com> ........ Merged revisions 358484 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404785 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404786 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 358485 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-03 18:33 +0000 [r404783]  Richard Mudgett <rmudgett at digium.com>
+2012-03-07 15:19 +0000 [r358437-358444]  Terry Wilson <twilson at digium.com>
 
-	* tests/test_stasis.c, /: test_stasis.c: Fix ref leak in normal
-	  execution path. ........ Merged revisions 404764 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, configs/cdr_adaptive_odbc.conf.sample: Set snarkiness = 0 in
+	  cdr_adaptive_odbc.conf.sample ........ Merged revisions 358438
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 358441 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* cel/cel_odbc.c, /, cdr/cdr_adaptive_odbc.c: Add detection for
+	  ODBC WCHAR fields Without detecting these types, cel_odbc blows
+	  up when the character set for the table is utf8. This also wraps
+	  cdr_adaptive_odbc's use of those types in the HAVE_ODBC_WCHAR
+	  #ifdef seen in other parts of the code. ........ Merged revisions
+	  358435 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 358436 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-06 17:47 +0000 [r358262-358379]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Fix ring cadance setup for outgoing
+	  calls on FXS ports. * Fix referencing the wrong variable in
+	  chan_dahdi.c:my_set_cadence(). Thanks to Sean Bright for
+	  compiling with -Wshadow and finding this bug. ........ Merged
+	  revisions 358377 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358378 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c, configs/chan_dahdi.conf.sample, CHANGES:
+	  Add dialtone_detect option for analog incoming calls. For analog
+	  lines, enables Asterisk to use dialtone detection per channel if
+	  an incoming call was hung up before it was answered. If dialtone
+	  is detected, the call is hung up. no: Disabled. (Default) yes:
+	  Look for dialtone for 10000 ms after answer. <number>: Look for
+	  dialtone for the specified number of ms after answer. always:
+	  Look for dialtone for the entire call. Dialtone may return if the
+	  far end hangs up first. dialtone_detect=yes dialtone_detect=5000
+	  dialtone_detect=always (closes issue ASTERISK-19316) Reported by:
+	  Jeremy Pepper Patch by: Jeremy Pepper Tested by: rmudgett,Jeremy
+	  Pepper Review: https://reviewboard.asterisk.org/r/1737/
+
+	* /, channels/sig_ss7.c: Drop SS7 call if not connected yet when
+	  INCOMPLETE/BUSY/CONGESTION. SS7 is a trunk protocol and should
+	  clear a failed call as soon as possible. * Made SS7 hangup a call
+	  immediately if it has not connected yet for
+	  INCOMPLETE/BUSY/CONGESTION causes. Otherwise, play an appropriate
+	  inband tone. (closes issue ASTERISK-19372) Reported by: Igor
+	  Nikolaev ........ Merged revisions 358278 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358284 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* include/asterisk/channel.h: Make usage of
+	  DECLARE_STRINGFIELD_SETTERS_FOR() not look so odd.
+
+	* channels/chan_dahdi.c, channels/sig_ss7.h, /, channels/sig_ss7.c:
+	  Setup DSP when SS7 call is connected or early media is available.
+	  Outgoing SS7 calls fail to detect incoming DTMF so any bridged
+	  channel that requires out-of-band DTMF will not work. * Added
+	  sig_ss7_open_media() calls at appropriate places in sig_ss7.c.
+	  The new call converts conditionaled out unconverted code and
+	  shows that the code really did something useful. * Improved some
+	  chan_dahdi DTMF debug messages to help track DTMF handling.
+	  (closes issue ASTERISK-19312) Reported by: Igor Nikolaev ........
+	  Merged revisions 358260 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358261 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-05 19:06 +0000 [r358216]  Jonathan Rose <jrose at digium.com>
+
+	* main/manager.c, /: Eliminate double close of file descriptor in
+	  manager.c The process_output function in manager.c attempted to
+	  call fclose and close immediately afterwards. Since fclose
+	  implies close, this resulted in a potential double free on file
+	  descriptors. This patch changes that behavior and also adds error
+	  checking to fclose and close depending on which was deemed
+	  necessary. Also error messages. Thanks to Rosen Iliev for
+	  pointing out the location of the problem. (closes issue
+	  ASTERISK-18453) Reported By: Jaco Kroon Review:
+	  https://reviewboard.asterisk.org/r/1793/ ........ Merged
+	  revisions 358214 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358215 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-03 18:31 +0000 [r404782]  Kevin Harwell <kharwell at digium.com>
+2012-03-05 16:44 +0000 [r358164]  Joshua Colp <jcolp at digium.com>
 
-	* /, apps/app_meetme.c: app_meetme: compiler warning Fixed a
-	  compiler warning (errors in 'dev-mode') given by gcc version
-	  4.8.1. The one in app_meetme involved the
-	  'sizeof-pointer-memaccess' (see:
-	  http://gcc.gnu.org/gcc-4.8/porting_to.html) warning. Fixed so it
-	  would no longer issue a warning and can compile again in
-	  'dev-mode'. Review: https://reviewboard.asterisk.org/r/3098/
-	  ........ Merged revisions 404742 from
+	* /, channels/chan_sip.c: Defer sending the connected line reinvite
+	  if a reinvite is already in progress. (issue ASTERISK-19355)
+	  Reported by: tomaso (closes issue AST-825) ........ Merged
+	  revisions 358162 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358163 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-05 16:00 +0000 [r358117]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Ensure Asterisk acknowledges ACKs to 4xx
+	  on Replaces errors Asterisk was not setting pendinginvite in the
+	  upper half of handle_request_invite such that the 4xx was
+	  retransmitted repeatedly even though an ack was received for
+	  every retransmission. (closes issue ASTERISK-19303) Reported by:
+	  Jon Tsiros Patches: fix-19303.patch uploaded by Jeremiah Gowdy
+	  (license 6358) ........ Merged revisions 358115 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404773 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404781 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 358116 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2014-01-03 17:27 +0000 [r404726-404738]  Joshua Colp <jcolp at digium.com>
+2012-03-05 11:20 +0000 [r358082]  Sean Bright <sean at malleable.com>
 
-	* res/res_pjsip/pjsip_configuration.c, /, res/res_pjsip/location.c:
-	  res_pjsip: Ensure more URI validation happens in pj threads.
-	  ........ Merged revisions 404737 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* configs/iax.conf.sample: Tab to spaces and text change.
 
-	* /, res/res_pjsip_outbound_registration.c:
-	  res_pjsip_outbound_registration: Ensure URI validation happens in
-	  a pjlib thread. This change moves outbound registration URI
-	  validation into the task executed within a pjlib thread. Reported
-	  by: Andrew Nagy ........ Merged revisions 404725 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-03-02 23:29 +0000 [r357999-358038]  Terry Wilson <twilson at digium.com>
 
-2014-01-02 19:38 +0000 [r404677]  Scott Griepentrog <sgriepentrog at digium.com>
+	* channels/chan_usbradio.c, /, channels/xpmr/xpmr.c: Fix
+	  unused-but-set-variable warnings All of these were pretty
+	  obviously unused. Some were unused because the code that used
+	  them was #if 0'd. In those cases, I just commented out the
+	  unused-but-set variables. ........ Merged revisions 358029 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 358033 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, funcs/func_strings.c: func_strings: use memmove to prevent
-	  overlapping memory on strcpy When calling REPLACE() with an empty
-	  replace-char argument, strcpy is used to overwrite the the
-	  matching <find-char>. However as the src and dest arguments to
-	  strcpy must not overlap, it causes other parts of the string to
-	  be overwritten with adjacent characters and the result is
-	  mangled. Patch replaces call to strcpy with memmove and adds a
-	  test suite case for REPLACE. (closes issue ASTERISK-22910)
-	  Reported by: Gareth Palmer Review:
-	  https://reviewboard.asterisk.org/r/3083/ Patches:
-	  func_strings.patch uploaded by Gareth Palmer (license 5169)
-	  ........ Merged revisions 404674 from
+	* /: Correct some set-but-unused variable warnings in the mISDN
+	  library. (from kpfleming's commit to trunk r356292) ........
+	  Merged revisions 358011 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404675 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404676 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2014-01-02 19:08 +0000 [r404664]  Kevin Harwell <kharwell at digium.com>
-
-	* channels/chan_pjsip.c, include/asterisk/res_pjsip.h, /,
-	  configs/pjsip.conf.sample, res/res_pjsip/pjsip_configuration.c,
-	  CHANGES, res/res_pjsip.c: res_pjsip: add 'set_var' support on
-	  endpoints Added a new 'set_var' option for ast_sip_endpoint(s).
-	  For each variable specified that variable gets set upon creation
-	  of a pjsip channel involving the endpoint. (closes issue
-	  ASTERISK-22868) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/3095/ ........ Merged
-	  revisions 404663 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-31 22:51 +0000 [r404620-404653]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_pjsip.c, res/res_pjsip_session.c, /: chan_pjsip:
-	  Handle hanging up before calling. Channel creation in Asterisk is
-	  broken up into two steps: requesting and calling. In some cases a
-	  channel may be requested but never called. This happens in the
-	  ChanIsAvail dialplan application for determining if something is
-	  reachable or not. The PJSIP channel driver did not take this
-	  situation into account and attempted to end a session that was
-	  never called out on. The code now checks the session state to
-	  determine if the session has been called out on and if not
-	  terminates it instead of ending it. (closes issue ASTERISK-23074)
-	  Reported by: Kilburn ........ Merged revisions 404652 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c:
-	  res_pjsip_endpoint_identifier_ip: Accept hostnames in the 'match'
-	  field. Hostnames specified in the 'match' field will be resolved
-	  and all addresses returned. Each address will be added to the
-	  endpoint identifier for the matching process. Reported by: Rob
-	  Thomas ........ Merged revisions 404613 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-31 21:39 +0000 [r404606]  Kevin Harwell <kharwell at digium.com>
-
-	* cel/cel_pgsql.c, /: cel_pgsql: deadlock on unload and
-	  core_event_dispatcher A deadlock can happen between a thread
-	  unloading or reloading the cel_pgsql module and the
-	  core_event_dispatcher taskprocessor thread. Description of what
-	  is happening: Thread 1 (for example, a netconsole thread): a
-	  "module reload cel_pgsql" is launched the thread enter the
-	  "my_unload_module" function (cel_pgsql.c) the thread acquire the
-	  write lock on psql_columns the thread enter the
-	  "ast_event_unsubscribe" function (event.c) the thread try to
-	  acquire the write lock on ast_event_subs[sub->type] Thread 2
-	  (core_event_dispatcher taskprocessor thread): the taskprocessor
-	  pop a CEL event the thread enter the "handle_event" function
-	  (event.c) the thread acquire the read lock on
-	  ast_event_subs[sub->type] the thread callback the "pgsql_log"
-	  function (cel_pgsql.c), since it's a subscriber of CEL events the
-	  thread try to acquire a read lock on psql_columns (closes issue
-	  ASTERISK-22854) Reported by: Etienne Lessard Patches:
-	  cel_pgsql_fix_deadlock_event.patch uploaded by hexanol (license
-	  6394) ........ Merged revisions 404603 from
+	  revisions 358017 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/xpmr/xpmr.c: Make chan_usbradio compile under dev
+	  mode x=++x and x=x=1? Really? ........ Merged revisions 357986
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 357987 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-02 21:06 +0000 [r357942]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/ccss.c, tests/test_event.c, main/event.c,
+	  include/asterisk/strings.h: Fix case-sensitivity for
+	  device-specific event subscriptions and CCSS This change fixes
+	  case-sensitivity for device-specific subscriptions such that the
+	  technology identifier is case-insensitive while the remainder of
+	  the device string is still case-sensitive. This should also
+	  preserve the original case of the device string as passed in to
+	  the event system. CCSS is the only feature affected as it is the
+	  only consumer of device-specific event subscriptions. The second
+	  part of this patch addresses similar case-sensitivity issues
+	  within CCSS itself that prevented it from functioning correctly
+	  after the fix to the events system. This adds a unit test to
+	  verify that the event system works as expected. (closes issue
+	  ASTERISK-19422) Review: https://reviewboard.asterisk.org/r/1780/
+	  ........ Merged revisions 357940 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357941 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-02 18:38 +0000 [r357896]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /, channels/sig_pri.c: Remove ISDN hold
+	  restriction for non-bridged calls. The check if an ISDN call is
+	  bridged before it could be placed on hold is not necessary and is
+	  overly restrictive. The check was originally done to prevent
+	  problems with call transfers in case a user tried to transfer a
+	  call connected to an application to another call connected to an
+	  application. The ISDN transfer code has not required this
+	  restriction for quite some time because ECT could transfer any
+	  two active calls to each other. * Remove ISDN hold restriction
+	  for calls connected to applications. * Made
+	  ast_waitfordigit_full() ignore AST_CONTROL_HOLD and
+	  AST_CONTROL_UNHOLD instead of generating a warning message.
+	  (closes issue ASTERISK-19388) Reported by: Birger Harzenetter
+	  Tested by: rmudgett ........ Merged revisions 357894 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404604 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404605 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-31 20:27 +0000 [r404593]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_outbound_registration.c, /:
-	  res_pjsip_outbound_registration: Add validation for 'server_uri'
-	  and 'client_uri'. When applying configuration for outbound
-	  registrations the 'server_uri' and 'client_uri' fields were not
-	  validated. The code will now confirm that they exist and that
-	  they contain parseable SIP URIs. Reported by: Andrew Nagy
-	  ........ Merged revisions 404592 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-30 23:25 +0000 [r404582]  Kevin Harwell <kharwell at digium.com>
-
-	* main/channel.c, /: channels.c: core show channeltypes slicing
-	  'core show channeltypes' type column is being sliced, resulting
-	  in incomplete type names. (closes issue ASTERISK-22919) Reported
-	  by: outtolunc Patches: svn_channel.c.format_15.diff.txt uploaded
-	  by outtolunc (license 5198) ........ Merged revisions 404579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404581 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-24 17:12 +0000 [r404567-404569]  David M. Lee <dlee at digium.com>
-
-	* UPGRADE-12.txt, /: Added note to UPGRADE.txt about the default
-	  value of live_dangerously changing ........ Merged revisions
-	  404568 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/http.c: http: Properly reject requests with
-	  Transfer-Encoding set Asterisk does not support any of the
-	  transfer encodings specified in HTTP/1.1, other than the default
-	  "identity" encoding. According to RFC 2616: A server which
-	  receives an entity-body with a transfer-coding it does not
-	  understand SHOULD return 501 (Unimplemented), and close the
-	  connection. A server MUST NOT send transfer-codings to an
-	  HTTP/1.0 client. This patch adds the 501 Unimplemented response,
-	  instead of the hard work of actually implementing other
-	  recordings. This behavior is especially problematic for Node.js
-	  clients, which use chunked encoding by default. (closes issue
-	  ASTERISK-22486) Review: https://reviewboard.asterisk.org/r/3092/
-	  ........ Merged revisions 404565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-24 02:20 +0000 [r404554]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_pubsub.c: res_pjsip_pubsub: Ensure dialog
-	  manipulation happens on proper thread. When destroying a
-	  subscription we remove the serializer from its dialog and
-	  decrease its reference count. Depending on which thread dropped
-	  the subscription reference count to 0 it was possible for this to
-	  occur in a thread where it is not possible. (closes issue
-	  ASTERISK-22952) Reported by: Matt Jordan ........ Merged
-	  revisions 404553 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-23 16:38 +0000 [r404542]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* channels/chan_dahdi.c, configs/chan_dahdi.conf.sample,
-	  UPGRADE-12.txt: chan_dahdi: enable ignore_failed_channels by
-	  default If ignore_failed_channels is set to "true" for a channel,
-	  the channel will continue to be configured even if configuring it
-	  has failed. This allows Asterisk to start before all the DAHDI
-	  initialization is done and thus not force the starting order
-	  dahdi -> asterisk. Review:
-	  https://reviewboard.asterisk.org/r/3063/
-
-2013-12-21 03:35 +0000 [r404532]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_pjsip/pjsip_cli.c: res_pjsip/pjsip_cli: fix
-	  compilation error caused by passing ast_free When wanting to pass
-	  *free as a function pointer, ast_free_ptr has to be used instead
-	  of ast_free. This allows it to be compiled with MALLOC_DEBUG
-	  enabled. ........ Merged revisions 404531 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 22:04 +0000 [r404511-404512]  David M. Lee <dlee at digium.com>
-
-	* rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, res/ari/resource_channels.h, /,
-	  rest-api/api-docs/applications.json: ari: Remove support for
-	  specifying channel vars during origination. When we added support
-	  for specifying channel variables for an origination, we didn't
-	  consider how that would interact with another feature, namely
-	  specifying request parameters in a JSON request body. The method
-	  of specifying channel variables (as a flat JSON object passed in
-	  the JSON body) interferes with parsing parameters out of the
-	  request body. Unfortunately, fixing this would be a backward
-	  incompatible change. In the interest of keeping the API sane and
-	  keeping our release schedule, we're dropping the feature for
-	  specifying channel variables in the origination request. We will
-	  bring the feature back soon, as a backward compatible addition to
-	  the API. (closes issue ASTERISK-23051) Review:
-	  https://reviewboard.asterisk.org/r/3088 ........ Merged revisions
-	  404509 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /: Remove automerge properties ........ Merged revisions 404488
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 21:32 +0000 [r404507]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/config.h, main/config.c, main/channel.c,
-	  res/res_pjsip/location.c, include/asterisk/res_pjsip_cli.h
-	  (added), res/res_pjsip/pjsip_cli.c (added),
-	  include/asterisk/sorcery.h, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/include/res_pjsip_private.h,
-	  res/res_pjsip_registrar.c, main/sorcery.c,
-	  include/asterisk/res_pjsip.h, CREDITS,
-	  res/res_pjsip/config_auth.c, /,
-	  res/res_pjsip_endpoint_identifier_ip.c: res_pjsip: Add PJSIP CLI
-	  commands Implements the following cli commands: pjsip list aors
-	  pjsip list auths pjsip list channels pjsip list contacts pjsip
-	  list endpoints pjsip show aor(s) pjsip show auth(s) pjsip show
-	  channels pjsip show endpoint(s) Also... Minor modifications made
-	  to the AMI command implementations to facilitate reuse. New
-	  function ast_variable_list_sort added to config.c and config.h to
-	  implement variable list sorting. (issue ASTERISK-22610) patches:
-	  pjsip_cli_v2.patch uploaded by george.joseph (License 6322)
-	  ........ Merged revisions 404480 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 21:18 +0000 [r404461]  Scott Griepentrog <sgriepentrog at digium.com>
+	  revisions 357895 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/say.c: say.c: correct time for polish In
-	  ast_say_date_with_format_pl(), change ast_say_number() to use
-	  tm_sec instead of tm_mn. (closes issue ASTERISK-22856) Reported
-	  by: Robert Mordec Review:
-	  https://reviewboard.asterisk.org/r/3082/ Patches: say.c.patch
-	  uploaded by veilen (license 6555) ........ Merged revisions
-	  404456 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 404457 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 20:28 +0000 [r404452]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip_refer.c: Fix issue where PJSIP blind transferer
-	  dialog may not complete as planned. When transferring to a
-	  dialplan extension that will not place any outbound calls, the
-	  only control frames that the PJSIP REFER framehook will receive
-	  are inconsequential (such as unhold or srcchange). As such, we
-	  shouldn't allow for the reception of those types of frames
-	  prevent us from signaling to the transferring party that the
-	  transfer has completed successfully once voice frames are read.
-	  Thanks to Jonathan Rose for pointing this out. ........ Merged
-	  revisions 404439 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 20:05 +0000 [r404438]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/ari/resource_applications.h,
-	  res/res_stasis_device_state.c: res_stasis_device_state: Set
-	  resource type for subscriptions to deviceState The documentation
-	  for ARI already specifies that the device state resource when
-	  used for subscribing for events is "deviceState", not
-	  "device_state". The code, however, used "device_state"; although
-	  this was inconsistent as well in doxygen comments in
-	  resource_applications. Because the actual resource being
-	  subscribed to is /deviceStates/{device}/, it makes sense for the
-	  resource type specifier to be deviceState. Note that the key
-	  value in the events is still "device_state". ........ Merged
-	  revisions 404437 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 20:00 +0000 [r404436]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/ari/resource_channels.c, tests/test_scoped_lock.c,
-	  tests/test_stasis.c, res/parking/parking_manager.c,
-	  res/ari/resource_bridges.c, res/ari/resource_endpoints.c, /,
-	  res/res_pjsip/location.c, tests/test_cel.c: ao2_iterator:
-	  Mini-audit of the ao2_iterator loops in the new code files. *
-	  Fixed several places where ao2_iterator_destroy() was not called.
-	  * Fixed several iterator loop object variable reference problems.
-	  * Fixed res_parking AMI actions returning non-zero. Only the AMI
-	  logoff action can return non-zero. Review:
-	  https://reviewboard.asterisk.org/r/3087/ ........ Merged
-	  revisions 404434 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 19:25 +0000 [r404433]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/manager.h, /: manager: bump version to 2.0.0 AMI
-	  has received substantial updates over the past year. Not only has
-	  the syntax been vastly improved and made consistent (which
-	  entails many event changes), but the underlying things that those
-	  events convey have changed substantially as well. After some
-	  conversation in #asterisk-dev, it was agreed that this is a good
-	  time to jump to 2. At the same time, since ARI will most likely
-	  use semantic versioning, we might as well use that for AMI as
-	  well. That also affords us greater meaning for the AMI version.
-	  ........ Merged revisions 404421 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 19:06 +0000 [r404420]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/sounds_index.c: Whitespace fixes. ........ Merged
-	  revisions 404419 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-20 17:22 +0000 [r404406]  Rusty Newton <rnewton at digium.com>
-
-	* /, configs/pjsip.conf.sample: Documentation: Updates for info
-	  about NAT-related settings and fixes for pjsip.conf.sample Added
-	  another NAT example to pjsip.conf.sample. We had a few mentions
-	  of NAT configuration throughout the sample, but I added another
-	  for a little bit more clarity. Additionally many pjsip options
-	  were affected by the change to snake case, so I fixed any
-	  instances of those options in pjsip.conf. I regenerated the
-	  config option list (at the bottom of the file) from a new xml
-	  config doc dump, so all the snake case changes should be
-	  reflected there, as well as any other changes to those options.
-	  (issue ASTERISK-23004) (closes issue ASTERISK-23004) Reported by:
-	  Matt Jordan Review: https://reviewboard.asterisk.org/r/3086/
-	  ........ Merged revisions 404405 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 20:48 +0000 [r404387]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/security_events.c: security_events: log events with
-	  descriptive names This patch updates the log messages to include
-	  descriptive names for event types. This is an improvement over
-	  having only cryptic type numbers. (closes issue ASTERISK-22909)
-	  Reported by: outtolunc Review:
-	  https://reviewboard.asterisk.org/r/3081/ Patches:
-	  svn_security_events.c.names.diff.txt uploaded by outtolunc
-	  (license 5198)
-
-2013-12-19 18:16 +0000 [r404376]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, CHANGES: Put notice in CHANGES as well as UPGRADE.txt.
-	  ........ Merged revisions 404375 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 18:00 +0000 [r404370-404372]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip/pjsip_outbound_auth.c, /: res_pjsip: Ignore 401/407
-	  responses for transactions and dialogs we don't know about. Under
-	  normal conditions it is unlikely we will ever receive a response
-	  for a transaction or dialog we don't know about but if any are
-	  received ignore them. ........ Merged revisions 404371 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_session.c: res_pjsip_session: Fix SDP
-	  negotiation when resending an INVITE with authentication. The
-	  process for resending an INVITE with authentication involves
-	  restarting the UAC session. We were incorrectly passing in that a
-	  new offer is being sent, causing the SDP negotiation to get into
-	  a (technically speaking) funky state. ........ Merged revisions
-	  404369 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 17:45 +0000 [r404368]  Mark Michelson <mmichelson at digium.com>
-
-	* include/asterisk/channel.h, res/res_pjsip.c, main/channel.c, /,
-	  include/asterisk/autochan.h: Fix a deadlock that occurred due to
-	  a conflict of masquerades. For the explanation, here is a
-	  copy-paste of the review board explanation: Initially, it was
-	  discovered that performing an attended transfer of a multiparty
-	  bridge with a PJSIP channel would cause a deadlock. A PBX thread
-	  started a masquerade and reached the point where it was calling
-	  the fixup() callback on the "original" channel. For chan_pjsip,
-	  this involves pushing a synchronous task to the session's
-	  serializer. The problem was that a task ahead of the fixup task
-	  was also attempting to perform a channel masquerade. However,
-	  since masquerades are designed in a way to only allow for one to
-	  occur at a time, the task ahead of the fixup could not continue
-	  until the masquerade already in progress had completed. And of
-	  course, the masquerade in progress could not complete until the
-	  task ahead of the fixup task had completed. Deadlock. The initial
-	  fix was to change the fixup task to be asynchronous. While this
-	  prevented the deadlock from occurring, it had the frightful side
-	  effect of potentially allowing for tasks in the session's
-	  serializer to operate on a zombie channel. Taking a step back
-	  from this particular deadlock, it became clear that the problem
-	  was not really this one particular issue but that masquerades
-	  themselves needed to be addressed. A PJSIP attended transfer
-	  operation calls ast_channel_move(), which attempts to both set up
-	  and execute a masquerade. The problem was that after it had set
-	  up the masquerade, the PBX thread had swooped in and tried to
-	  actually perform the masquerade. Looking at changes that had been
-	  made to Asterisk 12, it became clear that there never is any time
-	  now that anyone ever wants to set up a masquerade and allow for
-	  the channel thread to actually perform the masquerade. Everyone
-	  always is calling ast_channel_move(), performs the masquerade
-	  itself before returning. In this patch, I have removed all blocks
-	  of code from channel.c that will attempt to perform a masquerade
-	  if ast_channel_masq() returns true. Now, there is no distinction
-	  between setting up a masquerade and performing the masquerade. It
-	  is one operation. The only remaining checks for
-	  ast_channel_masq() and ast_channel_masqr() are in ast_hangup()
-	  since we do not want to interrupt a masquerade by hanging up the
-	  channel. Instead, now ast_hangup() will wait for a masquerade to
-	  complete before moving forward with its operation. The
-	  ast_channel_move() function has been modified to basically
-	  in-line the logic that used to be in ast_channel_masquerade().
-	  ast_channel_masquerade() has been killed off for real.
-	  ast_channel_move() now has a lock associated with it that is used
-	  to prevent any simultaneous moves from occurring at once. This
-	  means there is no need to make sure that ast_channel_masq() or
-	  ast_channel_masqr() are already set on a channel when
-	  ast_channel_move() is called. It also means the channel container
-	  lock is not pulling double duty by both keeping the container
-	  locked and preventing multiple masquerades from occurring
-	  simultaneously. The ast_do_masquerade() function has been renamed
-	  to do_channel_masquerade() and is now internal to channel.c. The
-	  function now takes explicit arguments of which channels are
-	  involved in the masquerade instead of a single channel. While it
-	  probably is possible to do some further refactoring of this
-	  method, I feel that I would be treading dangerously. Instead, all
-	  I did was change some comments that no longer are true after this
-	  changeset. The other more minor change introduced in this patch
-	  is to res_pjsip.c to make ast_sip_push_task_synchronous() run the
-	  task in-place if we are already a SIP servant thread. This is
-	  related to this patch because even when we isolate the channel
-	  masquerade to only running in the SIP servant thread, we would
-	  still deadlock when the fixup() callback is reached since we
-	  would essentially be waiting forever for ourselves to finish
-	  before actually running the fixup. This makes it so the fixup is
-	  run without having to push a task into a serializer at all.
-	  (closes issue ASTERISK-22936) Reported by Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/3069 ........ Merged revisions
-	  404356 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 17:13 +0000 [r404355]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/udptl.c, addons/chan_ooh323.c, /, channels/chan_sip.c,
-	  include/asterisk/udptl.h: udptl: Dead code elimination.
-	  ast_udptl_bridge was not used. Removing dead code starting with
-	  ast_udptl_bridge() eliminated the code in this change. Note: This
-	  code has actually been dead since Asterisk v1.4 when it was first
-	  put in. Review: https://reviewboard.asterisk.org/r/3079/ ........
-	  Merged revisions 404354 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 17:03 +0000 [r404353]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* /, res/res_fax.c: res_fax.c: crash on framehook with no dsp in
-	  fax detect In fax_detect_framehook() a null pointer reference can
-	  occur where a voice frame is processed but no dsp is attached to
-	  the fax detection structure. The code block that rejects frames
-	  that detection cannot be processed on is checking for dsp but
-	  falls through when it should instead return, as this change
-	  implements. (closes issue ASTERISK-22942) Reported by: adomjan
-	  Review: https://reviewboard.asterisk.org/r/3076/ ........ Merged
-	  revisions 404351 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404352 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 16:52 +0000 [r404350]  Richard Mudgett <rmudgett at digium.com>
-
-	* configs/skinny.conf.sample, res/res_xmpp.c, res/res_jabber.c,
-	  CHANGES, channels/chan_iax2.c, channels/sig_pri.c,
-	  channels/h323/chan_h323.h, configs/iax.conf.sample,
-	  channels/sig_pri.h, channels/chan_dahdi.c,
-	  include/asterisk/app.h, channels/chan_skinny.c,
-	  channels/chan_dahdi.h, channels/chan_h323.c, main/app.c,
-	  UPGRADE-12.txt, configs/sip.conf.sample,
-	  channels/sip/include/sip.h, channels/chan_mgcp.c,
-	  apps/app_voicemail.c, channels/chan_unistim.c,
-	  configs/chan_dahdi.conf.sample, /, channels/chan_sip.c,
-	  configs/voicemail.conf.sample, funcs/func_vmcount.c: Voicemail:
-	  Remove mailbox identifier format (box at context) assumptions in the
-	  system. This change is in preparation for external MWI support.
-	  Removed code from the system for normal mailbox handling that
-	  appends @default to the mailbox identifier if it does not have a
-	  context. The only exception is the legacy hasvoicemail users.conf
-	  option. The legacy option will only work for app_voicemail
-	  mailboxes. The system cannot make any assumptions about the
-	  format of the mailbox identifer used by app_voicemail. chan_sip
-	  and chan_dahdi/sig_pri had the most changes because they both
-	  tried to interpret the mailbox identifier. chan_sip just stored
-	  and compared the two components. chan_dahdi actually used the box
-	  information. The ISDN MWI support configuration options had to be
-	  reworked because chan_dahdi was parsing the box at context format to
-	  get the box number. As a result the mwi_vm_boxes chan_dahdi.conf
-	  option was added and is documented in the chan_dahdi.conf.sample
-	  file. Review: https://reviewboard.asterisk.org/r/3072/ ........
-	  Merged revisions 404348 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 16:33 +0000 [r404346]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/db.c, /: astdb: crash in sqlite3 during shutdown When
-	  Asterisk is shut down, the astdb_atexit() function releases
-	  (finalize) the previously initiated (prepared) SQL statements in
-	  sqlite3. Another thread making a subsequent request can cause a
-	  crash in sqlite3. This patch eliminates that issue by resetting
-	  the statement pointer after it is released/cleared. The sqlite3
-	  code detects the null pointer, and aborts the operation cleanly.
-	  (closes issue AST-1265) Reported by: Alexander Hömig (closes
-	  issue ASTERISK-22350) Reported by: Birger "WIMPy" Harzenetter
-	  Review: https://reviewboard.asterisk.org/r/3078/ ........ Merged
-	  revisions 404344 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404345 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 12:18 +0000 [r404333]  Joshua Colp <jcolp at digium.com>
-
-	* main/channel.c, /: channel: Add a missing ast_channel_unlock when
-	  allocating a Surrogate channel. ........ Merged revisions 404332
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 08:35 +0000 [r404321]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/ooh323c/src/oochannels.c, addons/ooh323c/src/ooGkClient.c,
-	  addons/chan_ooh323.c, /, addons/ooh323c/src/ooGkClient.h: Handle
-	  temporary failures on gk registration Introduce new 'stopped'
-	  state for gk client and restart gk client on failures Remove
-	  ooh323 stack command lock as it is not need now. (closes issue
-	  ASTERISK-21960) Reported by: Dmitry Melekhov Patches:
-	  ASTERISK-21960.patch ASTERISK-21960-stacklockup-2.patch Tested
-	  by: Dmitry Melekhov ........ Merged revisions 404318 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404320 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 02:59 +0000 [r404307]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Fixup some skinny bugs causing Fracks
-	  and ao2 cleanup issues. Moved channel locking into setsubstate so
-	  that a process can complete working on a sub before another
-	  starts changing it. The existing code was causing some Fracks
-	  with schedule deletion. Removed multiple rtp cleanup. Now only
-	  cleansup up once, fixing ao2 object cleanup issues. ........
-	  Merged revisions 404306 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 00:50 +0000 [r404295]  Matthew Jordan <mjordan at digium.com>
-
-	* include/asterisk/cdr.h, CHANGES, apps/app_cdr.c, main/cdr.c,
-	  apps/app_forkcdr.c, main/pbx.c, /, funcs/func_cdr.c,
-	  apps/app_disa.c, UPGRADE-12.txt: app_cdr,app_forkcdr,func_cdr:
-	  Synchronize with engine when manipulating state When doing the
-	  rework of the CDR engine that pushed all of the logic into cdr.c
-	  and made it respond to changes in channel state over Stasis, we
-	  knew that accessing the CDR engine from the dialplan would be
-	  "slightly" non-deterministic. Dialplan threads would be accessing
-	  CDRs while Stasis threads would be updating the state of said
-	  CDRs - whereas in the past, everything happened on the dialplan
-	  threads. Tests have shown that "slightly" is in reality "very".
-	  This patch synchronizes things by making the dialplan
-	  applications/functions that manipulate CDRs do so over Stasis.
-	  ForkCDR, NoCDR, ResetCDR, CDR, and CDR_PROP now all use Stasis to
-	  send their requests over to the CDR engine, and synchronize on
-	  the channel Stasis topic via a subscription so that they return
-	  their values/control to the dialplan at the appropriate time.
-	  While going through this, the following changes were also made: *
-	  DISA, which can reset the CDR when a user successfully
-	  authenticates, now just uses the ResetCDR app to do this. This
-	  prevents having to duplicate the same Stasis synchronization
-	  logic in that application. * Answer no longer disables CDRs. It
-	  actually didn't work anyway - calling DISABLE on the channel's
-	  CDR doesn't stop the CDR from getting the Answer time - it just
-	  kills all CDRs on that channel, which isn't what the caller would
-	  intend. (closes issue ASTERISK-22884) (closes issue
-	  ASTERISK-22886) Review: https://reviewboard.asterisk.org/r/3057/
-	  ........ Merged revisions 404294 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-19 00:32 +0000 [r404293]  Damien Wedhorn <voip at facts.com.au>
-
-	* /, channels/chan_skinny.c: Fixup skinny registration following
-	  network issues. On session registration, if device is already
-	  reporting that it is connected to a device, an innocuous packet
-	  (update time) is sent to the already connected device. If the tcp
-	  connection is down, the device will be unregistered and the new
-	  connection allowed. Without this patch, network issues can see a
-	  situation where a device can not reregister until after
-	  3*timeout. ........ Merged revisions 404292 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 23:00 +0000 [r404280]  Jason Parker <jparker at digium.com>
-
-	* main/manager.c, /: Add AMI event for presence state. Review:
-	  https://reviewboard.asterisk.org/r/3039/ ........ Merged
-	  revisions 404275 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404279 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 21:12 +0000 [r404264]  Richard Mudgett <rmudgett at digium.com>
+2012-03-02 16:57 +0000 [r357861]  Jonathan Rose <jrose at digium.com>
 
-	* addons/ooh323c/src/ooTimer.c, /: ooh323c: Fix gcc 4.6.3 compiler
-	  warnings. ........ Merged revisions 404212 from
+	* apps/app_queue.c: Adds a transfer callee on hangup option (like
+	  with Dial option F) to queues. This should (and does in my
+	  testing) act just like the Dial option of the same name. This
+	  allows a queue member to be transfered to the next priority (no
+	  args), or to a context/extension/priority similar to goto (with
+	  args context^extension^priority) when a caller hangs up on them.
+	  (closes issue ASTERISK-19283) Reported by: To Patches:
+	  queue_f-v3.diff uploaded by To (license 6347) Review:
+	  https://reviewboard.asterisk.org/r/1785/
+
+2012-03-02 16:26 +0000 [r357834]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_chanspy.c: Remove bad usage of goto in ChanSpy
+	  next_channel().
+
+2012-03-02 16:19 +0000 [r357821]  Sean Bright <sean at malleable.com>
+
+	* configs/iax.conf.sample: Beef up the IAX2 sample configuration a
+	  bit and fix some formatting issues.
+
+2012-03-02 16:03 +0000 [r357814-357815]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_chanspy.c: Fix channel reference leak in ChanSpy. *
+	  Fix next_channel() channel reference leak in ChanSpy. (closes
+	  issue ASTERISK-19461) Reported by: Irontec Patches:
+	  app_chanspy_iteartor_next_unref.patch (license #6213) patch
+	  uploaded by Irontec (issue ASTERISK-17515) ........ Merged
+	  revisions 357809 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357810 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_usbradio.c: Fix compile error from latest channel
+	  opaquification change.
+
+2012-03-02 16:00 +0000 [r357813]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: The default value for mohinterpret is
+	  the empty string, so when resetting to default values don't
+	  explicitly set the value to "default." ........ Merged revisions
+	  357811 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 357812 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-03-02 01:33 +0000 [r357774-357775]  Mark Michelson <mmichelson at digium.com>
+
+	* main/channel.c, /: Fix race condition that can cause important
+	  control frames (such as a hangup) to be missed. This takes two
+	  actions. 1. Move the reading of the alertpipe in __ast_read() to
+	  immediately before the removal of frames from the readq. This
+	  means we won't do something silly like read from the alertpipe,
+	  then ignore the fact that there's a frame to get from the readq
+	  since channel's fdno is the AST_TIMING_FD. 2. When
+	  ast_settimeout() sets the rate to 0 and the timingfunc to NULL,
+	  if the channel's fdno is the AST_TIMING_FD, then set the fdno to
+	  -1. This is because if the rate is 0 and the timingfunc is NULL,
+	  it means that the channel's timing fd is being invalidated, so
+	  any pending reads should not occur. This may actually solve more
+	  issues than the referenced one below, but it's not known at this
+	  time for sure. (closes issue ASTERISK-19223) reported by
+	  Frank-Michael Wittig Review:
+	  https://reviewboard.asterisk.org/r/1779 ........ Merged revisions
+	  357761 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 357762 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_dahdi.c: Fix compilation error due to typo during
+	  channel opaquification.
+	  s/ast_channel_fd_set/ast_channel_internal_fd_set/g
+
+2012-03-01 22:09 +0000 [r357721]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_unistim.c, apps/app_dahdibarge.c,
+	  main/autoservice.c, addons/chan_ooh323.c, channels/chan_vpb.cc,
+	  apps/app_meetme.c, channels/console_video.c,
+	  channels/chan_gtalk.c, channels/chan_iax2.c, main/cli.c,
+	  main/channel.c, channels/chan_phone.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c, channels/chan_skinny.c, main/features.c,
+	  apps/app_dumpchan.c, channels/sig_ss7.c, channels/chan_mgcp.c,
+	  main/pbx.c, channels/chan_sip.c, main/channel_internal_api.c,
+	  channels/chan_agent.c, apps/app_dahdiras.c,
+	  include/asterisk/channel.h, apps/app_queue.c, channels/sig_pri.c,
+	  channels/chan_jingle.c, channels/chan_misdn.c, apps/app_flash.c,
+	  funcs/func_channel.c, apps/app_directed_pickup.c, main/file.c,
+	  channels/chan_h323.c, res/snmp/agent.c, main/dsp.c: Opaquify
+	  ast_channel typedefs, fd arrays, and softhangup flag Review:
+	  https://reviewboard.asterisk.org/r/1784/
+
+2012-03-01 14:22 +0000 [r357673]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/acl.c: Prevent outbound SIP NOTIFY packets from
+	  displaying a port of 0 In the change from 1.6.2 to 1.8,
+	  ast_sockaddr was introduced which changed the behavior of
+	  ast_find_ourip such that port number was wiped out. This caused
+	  the port in internip (which is used for Contact and Call-ID on
+	  NOTIFYs) to be 0. This change causes ast_find_ourip to be
+	  port-preserving again. (closes issue ASTERISK-19430) ........
+	  Merged revisions 357665 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357667 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-29 20:41 +0000 [r357621]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, main/utils.c, include/asterisk/stringfields.h: Update
+	  stringfield documentation for removed second va_list in favor of
+	  va_copy. In r320946, the second va_list that was passed to
+	  ast_string_field_build_va and friends, was removed. This patch
+	  updates the documentation to reflect that. ........ Merged
+	  revisions 357620 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-29 20:31 +0000 [r357610]  Sean Bright <sean at malleable.com>
+
+	* res/res_agi.c, CHANGES: Add IPv6 support to FastAGI. Review:
+	  https://reviewboard.asterisk.org/r/1774/ Reviewed by: Simon
+	  Perreault, Mark Michelson
+
+2012-02-29 19:48 +0000 [r357577]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* apps/app_dial.c, /: Fix copying of CDR(accountcode) to local
+	  channels. In r203638, during the addition of the Channel Event
+	  Logging, in mid-2009, this got broken in trunk and ended up in
+	  asterisk 1.8 and higher. This fixes so the CDR(accountcode) from
+	  the calling channel is available to dialed channels again as well
+	  as showing up properly in the CDR's. (closes issue
+	  ASTERISK-19384) Reported by: jamicque Patches: accountcode.patch
+	  (License #6033) by jamicque Review:
+	  https://reviewboard.asterisk.org/r/1775/ Reviewed by: Richard
+	  Mudgett ........ Merged revisions 357575 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404219 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404263 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 20:48 +0000 [r404260-404262]  Kevin Harwell <kharwell at digium.com>
-
-	* channels/chan_oss.c, /: chan_oss.c: channel being locked twice
-	  and unlocked once Removed channel lock as it is now being down in
-	  ast_channel_alloc ........ Merged revisions 404261 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* pbx/pbx_realtime.c, channels/chan_alsa.c, main/stasis_channels.c,
-	  addons/chan_mobile.c, main/bridge_channel.c, tests/test_cdr.c,
-	  channels/chan_pjsip.c, res/parking/parking_manager.c,
-	  channels/chan_mgcp.c, channels/chan_unistim.c, main/pbx.c,
-	  funcs/func_timeout.c, /, apps/app_meetme.c, main/bridge.c,
-	  tests/test_stasis_channels.c, include/asterisk/channel.h,
-	  channels/chan_gtalk.c, channels/sig_pri.c, apps/app_queue.c,
-	  main/cel.c, main/stasis_bridges.c, channels/chan_jingle.c,
-	  channels/chan_phone.c, channels/chan_dahdi.c, main/dial.c,
-	  channels/sig_analog.c, include/asterisk/stasis_channels.h,
-	  res/res_agi.c, channels/chan_motif.c, tests/test_cel.c,
-	  apps/app_confbridge.c, res/res_stasis.c, res/res_pjsip_refer.c,
-	  apps/app_voicemail.c, apps/app_dial.c, channels/chan_vpb.cc,
-	  addons/chan_ooh323.c, main/pickup.c, include/asterisk/aoc.h,
-	  include/asterisk/stasis_bridges.h, apps/app_userevent.c,
-	  apps/app_disa.c, channels/chan_console.c,
-	  include/asterisk/channelstate.h, main/core_local.c,
-	  channels/chan_iax2.c, main/endpoints.c, channels/chan_oss.c,
-	  res/parking/parking_bridge_features.c, apps/app_agent_pool.c,
-	  main/channel.c, channels/chan_misdn.c, channels/chan_skinny.c:
-	  channel locking: Add locking for channel snapshot creation
-	  Original commit message by mmichelson (asterisk 12 r403311):
-	  "This adds channel locks around calls to create channel snapshots
-	  as well as other functions which operate on a channel and then
-	  end up creating a channel snapshot. Functions that expect the
-	  channel to be locked prior to being called have had their
-	  documentation updated to indicate such." The above was initially
-	  committed and then reverted at r403398. The problem was found to
-	  be in core_local.c in the publish_local_bridge_message function.
-	  The ast_unreal_lock_all function locks and adds a reference to
-	  the returned channels and while they were being unlocked they
-	  were not being unreffed when no longer needed. Fixed by unreffing
-	  the channels. Also in bridge.c a lock was obtained on
-	  "other->chan", but then an attempt was made to unlock "other" and
-	  not the previously locked channel. Fixed by unlocking
-	  "other->chan" (closes issue ASTERISK-22709) Reported by: John
-	  Bigelow ........ Merged revisions 404237 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 19:36 +0000 [r404211]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/chan_ooh323.c, configs/ooh323.conf.sample: Introduce new
-	  config option 'aniasdni'. If yes then asterisk set dialed number
-	  as own id back to the caller on incoming h.323 calls. Option can
-	  be set globally or per user section. (closes issue
-	  ASTERISK-22020) Reported by: Ross Beer
-
-2013-12-18 19:28 +0000 [r404210]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_mgcp.c, main/pbx.c, channels/chan_sip.c,
-	  apps/confbridge/conf_chan_record.c, tests/test_app.c,
-	  tests/test_stasis_channels.c, main/core_unreal.c,
-	  include/asterisk/channel.h, channels/chan_console.c,
-	  channels/chan_oss.c, channels/chan_jingle.c,
-	  channels/chan_misdn.c, channels/chan_h323.c, tests/test_cel.c,
-	  channels/chan_nbs.c, channels/chan_pjsip.c, res/res_calendar.c,
+	  revisions 357576 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-29 16:52 +0000 [r357542]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_local.c, addons/chan_ooh323.c,
+	  funcs/func_strings.c, channels/console_video.c,
+	  apps/app_alarmreceiver.c, channels/chan_iax2.c, main/cli.c,
+	  channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/chan_skinny.c, apps/app_dumpchan.c, main/features.c,
+	  apps/app_amd.c, channels/sig_ss7.c, apps/app_dial.c, main/pbx.c,
+	  include/asterisk/utils.h, funcs/func_timeout.c,
+	  apps/app_privacy.c, apps/app_fax.c, channels/chan_agent.c,
+	  apps/app_disa.c, include/asterisk/channel.h,
+	  apps/app_talkdetect.c, main/cel.c, channels/chan_misdn.c,
+	  apps/app_macro.c, apps/app_zapateller.c, apps/app_mixmonitor.c,
 	  apps/app_voicemail.c, channels/chan_unistim.c,
 	  tests/test_substitution.c, channels/chan_vpb.cc,
-	  addons/chan_ooh323.c, channels/chan_multicast_rtp.c, /,
-	  apps/app_meetme.c, res/res_stasis_snoop.c, channels/chan_gtalk.c,
-	  channels/chan_iax2.c, main/channel.c, channels/chan_dahdi.c,
-	  channels/chan_phone.c, channels/chan_skinny.c,
-	  res/parking/parking_tests.c, channels/chan_motif.c,
-	  tests/test_voicemail_api.c, channels/chan_alsa.c, main/message.c,
-	  addons/chan_mobile.c, tests/test_cdr.c: channels: Return
-	  allocated channels locked. This change makes ast_channel_alloc
-	  return allocated channels locked. By doing so no other thread can
-	  acquire, lock, and manipulate the channel before it is completely
-	  set up. (closes issue AST-1256) Review:
-	  https://reviewboard.asterisk.org/r/3067/ ........ Merged
-	  revisions 404204 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 19:10 +0000 [r404198]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/chan_ooh323.c: Implement module reload command for
-	  chan_ooh323 (close issue ASTERISK-22817) Patches:
-	  ooh323_module_reload.patch
-
-2013-12-18 12:46 +0000 [r404185]  Matthew Jordan <mjordan at digium.com>
-
-	* rest-api/api-docs/applications.json,
-	  rest-api/api-docs/playbacks.json,
-	  rest-api/api-docs/channels.json, rest-api/api-docs/sounds.json,
-	  rest-api/resources.json, rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json,
-	  rest-api/api-docs/deviceStates.json,
-	  rest-api/api-docs/endpoints.json, rest-api/api-docs/events.json,
-	  /, rest-api/api-docs/asterisk.json: ari: Bump the version of ARI
-	  to 1.0.0 (closes issue ASTERISK-23007) ........ Merged revisions
-	  404184 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-18 12:01 +0000 [r404138]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_calendar.c, /: res_calendar: Protect channel when adding
-	  datastore. This change adds a missing channel lock when adding a
-	  datastore to a channel. ........ Merged revisions 404135 from
+	  apps/app_meetme.c, main/ccss.c, apps/app_readexten.c,
+	  channels/chan_gtalk.c, main/autochan.c, apps/app_followme.c,
+	  main/cdr.c, main/channel.c, main/dial.c, channels/chan_phone.c,
+	  apps/app_osplookup.c, apps/app_setcallerid.c, main/manager.c,
+	  bridges/bridge_builtin_features.c, apps/app_minivm.c,
+	  res/res_agi.c, main/app.c, apps/app_confbridge.c, apps/app_rpt.c,
+	  main/message.c, channels/chan_mgcp.c, apps/app_parkandannounce.c,
+	  apps/app_while.c, funcs/func_dialplan.c, channels/chan_sip.c,
+	  res/res_fax.c, main/channel_internal_api.c, pbx/pbx_lua.c,
+	  channels/chan_console.c, channels/sig_pri.c, apps/app_queue.c,
+	  channels/chan_oss.c, channels/chan_jingle.c,
+	  channels/chan_usbradio.c, funcs/func_blacklist.c,
+	  main/abstract_jb.c, channels/chan_h323.c, main/file.c,
+	  res/snmp/agent.c, apps/app_sms.c, apps/app_stack.c,
+	  funcs/func_callerid.c: Opaquify ast_channel structs and lists
+	  Review: https://reviewboard.asterisk.org/r/1773/
+
+2012-02-28 22:31 +0000 [r357460-357503]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/sip.conf.sample, UPGRADE-1.8.txt: Adding transport=udp
+	  to sample sip.conf - Also changes version of Asterisk 1.8 in
+	  UPGRADE (issue ASTERISK-19352) Reported by: jamicque Patches:
+	  asterisk-19352-transport-warning-message-v1.patch uploaded by
+	  Michael L. Young (license 5026) ........ Merged revisions 357490
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 357497 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, cdr/cdr_adaptive_odbc.c: Add additional character type types
+	  to supported data types for cdr_adaptive_odbc The reporter was
+	  uable to use varchar utf8_unicode_ci with cdr_adaptive_odbc, so
+	  this patch adds those along with some other character types to
+	  the list of types cdr_adaptive_odbc will work using the varchar
+	  conditions. The problem wasn't really UTF8 characters as much as
+	  it was a failure to respond to the exact type that was
+	  declared/in use on that database. (closes issue ASTERISK-19334)
+	  Reported By: Igor Nikolaev Patches: cdr_adaptive_odbc.patch
+	  uploaded by Igor Nikolaev (license 6236) ........ Merged
+	  revisions 357455 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404136 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404137 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 357458 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-28 21:26 +0000 [r357436]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, apps/app_stack.c: Correctly reset the dialplan priority. When
+	  the stack frame is allocated, we save the address to which we
+	  should return, when the Gosub returns. However, if we just want
+	  to restore the priority, then we need to subtract 1 before
+	  setting it. Otherwise, when a Gosub goes to a nonexistent
+	  address, it will skip a priority in the dialplan. This is because
+	  when we return from an application, the PBX increments the
+	  priority for us. ........ Merged revisions 357416 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357421 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-12-18 00:36 +0000 [r404100]  Rusty Newton <rnewton at digium.com>
+2012-02-28 21:01 +0000 [r357409]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, funcs/func_strings.c: func_strings: Documentation fix for
-	  QUOTE() Example output was inaccurate. (issue ASTERISK-22970)
-	  (closes issue ASTERISK-22970) Reported by: Gareth Palmer Patches:
-	  func_strings.patch uploaded by Gareth Palmer (license 5169)
-	  ........ Merged revisions 404081 from
+	* /, channels/sig_pri.c: Use more reasonable cause code when
+	  rejecting incoming call waiting calls. (closes issue
+	  ASTERISK-19397) Reported by: Birger Harzenetter Patches:
+	  nochannel-cause.patch (license #5870) patch uploaded by Birger
+	  Harzenetter ........ Merged revisions 357407 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 404087 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 404099 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 357408 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-12-18 00:17 +0000 [r404051]  Matthew Jordan <mjordan at digium.com>
+2012-02-28 20:43 +0000 [r357406]  Jonathan Rose <jrose at digium.com>
 
-	* /, LICENSE: LICENSE: Update language to include ARI ........
-	  Merged revisions 404050 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, UPGRADE-10.txt: revision 357386 -- oops, accidentally made it
+	  10.3 to 10.4 instead of 10.2 to 10.3 (issue ASTERISK-19352)
+	  reported by: jamicque ........ Merged revisions 357405 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-12-17 23:57 +0000 [r404049]  Jonathan Rose <jrose at digium.com>
+2012-02-28 20:34 +0000 [r357404]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, tests/test_cel.c, tests/test_cdr.c: tests: fix
-	  ast_bridge_base_new calls not using the additional arguments
-	  r404042 gave ast_bridge_base_new two new arguments for setting a
-	  bridge creator and name. Unfortunately since a couple test
-	  modules aren't compiled by default, I missed the fact that this
-	  change impacted those tests and caused compilation failures
-	  against them. ........ Merged revisions 404048 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/channel.c, res/res_musiconhold.c, apps/app_queue.c: Fix
+	  REF_DEBUG compile errors.
 
-2013-12-17 23:38 +0000 [r404047]  Rusty Newton <rnewton at digium.com>
+2012-02-28 20:33 +0000 [r357358-357403]  Jonathan Rose <jrose at digium.com>
 
-	* include/asterisk/test.h, main/channel.c, main/rtp_engine.c, /,
-	  channels/chan_iax2.c, apps/app_chanspy.c, apps/app_mixmonitor.c:
-	  Several components: fixing Typos in comments and code,
-	  "avaliable" instead of "available" (issue ASTERISK-23021) (closes
-	  issue ASTERISK-23021) Reported by: Jeremy Lainé Tested by: Rusty
-	  Newton Patches: available.patch uploaded by Jeremy Lainé (license
-	  6561) ........ Merged revisions 404046 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-17 23:25 +0000 [r404043]  Jonathan Rose <jrose at digium.com>
-
-	* apps/app_bridgewait.c, res/ari/ari_model_validators.c,
-	  doc/appdocsxml.xslt, main/stasis_bridges.c,
-	  rest-api/api-docs/bridges.json, res/ari/resource_bridges.c,
-	  apps/app_agent_pool.c, res/parking/parking_bridge.c,
-	  res/ari/ari_model_validators.h, main/manager_bridges.c,
-	  res/ari/resource_bridges.h, include/asterisk/bridge_internal.h,
-	  apps/app_confbridge.c, res/res_stasis.c,
-	  include/asterisk/bridge.h, res/res_ari_bridges.c, /,
-	  main/bridge.c, main/bridge_basic.c,
-	  include/asterisk/stasis_bridges.h, include/asterisk/stasis_app.h:
-	  bridging: Give bridges a name and a known creator Bridges have
-	  two new optional properties, a creator and a name. Certain
-	  consumers of bridges will automatically provide bridges that they
-	  create with these properties. Examples include app_bridgewait,
-	  res_parking, app_confbridge, and app_agent_pool. In addition, a
-	  name may now be provided as an argument to the POST function for
-	  creating new bridges via ARI. (closes issue AFS-47) Review:
-	  https://reviewboard.asterisk.org/r/3070/ ........ Merged
-	  revisions 404042 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-17 18:35 +0000 [r404028-404030]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_sorcery_config.c, /: res_sorcery_config: Output an error
-	  message when an object can't be created. If object creation fails
-	  an error message will now be output with the id, type, and
-	  configuration file. ........ Merged revisions 404029 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/framehook.c: framehooks: Re-iterate if framehook provides
-	  different frame. Framehooks can be used in a reactive manner to
-	  execute specific logic when a frame is received with a certain
-	  type and payload. Since it is possible for framehooks to provide
-	  frames it was possible for this reactive framehook to be unaware
-	  of frames it is looking for. This change makes it so that when
-	  framehooks return a modified frame the code will now re-iterate
-	  (from the beginning) and call any previous framehooks that have
-	  not provided a modified frame themselves. Review:
-	  https://reviewboard.asterisk.org/r/3046/ ........ Merged
-	  revisions 404027 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-17 14:41 +0000 [r404008-404009]  David M. Lee <dlee at digium.com>
-
-	* /, configs/asterisk.conf.sample, main/asterisk.c: Changed the
-	  default for live_dangerously to no ........ Merged revisions
-	  404006 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/pjsip, /: Setting svn:ignore ........ Merged revisions
-	  403748 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-17 12:59 +0000 [r403994]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/ari/resource_channels.c: ari/resource_channels: When
-	  creating a channel, specify a default format (SLIN) When creating
-	  channels via ARI, the current code fails to provide any default
-	  format capabilities. For non-virtual channels this isn't really a
-	  problem - the channels typically receive their capabilities as a
-	  result of the underlying channel driver configuration. For
-	  virtual channels (such as Local channels), the lack of any format
-	  capabilities causes the Asterisk core to make some 'odd' choices
-	  with respect to the translation paths. The issue reporter had
-	  some paths that had 3 hops on each channel leg, causing multiple
-	  transcodings and some really crappy audio/performance. By
-	  specifying a baseline of SLIN, we prevent that from occurring.
-	  Note that this is what AMI does when it performs an Originate, as
-	  does res_clioriginate. Review:
-	  https://reviewboard.asterisk.org/r/3068/ (issue ASTERISK-22962)
-	  Reported by: Matt DiMeo ........ Merged revisions 403993 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-16 19:11 +0000 [r403960]  David M. Lee <dlee at digium.com>
-
-	* include/asterisk/pbx.h, main/asterisk.c, funcs/func_realtime.c,
-	  main/pbx.c, main/tcptls.c, funcs/func_db.c, /,
-	  README-SERIOUSLY.bestpractices.txt, configs/asterisk.conf.sample,
-	  funcs/func_shell.c, funcs/func_env.c, funcs/func_lock.c,
-	  UPGRADE-12.txt: security: Inhibit execution of privilege
-	  escalating functions This patch allows individual dialplan
-	  functions to be marked as 'dangerous', to inhibit their execution
-	  from external sources. A 'dangerous' function is one which
-	  results in a privilege escalation. For example, if one were to
-	  read the channel variable SHELL(rm -rf /) Bad Things(TM) could
-	  happen; even if the external source has only read permissions.
-	  Execution from external sources may be enabled by setting
-	  'live_dangerously' to 'yes' in the [options] section of
-	  asterisk.conf. Although doing so is not recommended. Also, the
-	  ABI was changed to something more reasonable, since Asterisk 12
-	  does not yet have a public release. (closes issue ASTERISK-22905)
-	  Review: http://reviewboard.digium.internal/r/432/ ........ Merged
-	  revisions 403913 from
+	* /, UPGRADE-10.txt, UPGRADE-1.8.txt: Moves UPGRADE.txt notes from
+	  r357356 to a new section specific to 1.8.12 (issue
+	  ASTERISK-19352) reported by: jamicque ........ Merged revisions
+	  357386 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 357400 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, UPGRADE-1.8.txt: Adds UPGRADE.txt notes to r357266 indicating
+	  changes to transport option (issue ASTERISK-19352) Reported by:
+	  jamicque ........ Merged revisions 357356 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 403917 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403959 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 357357 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-12-16 18:31 +0000 [r403958]  Jonathan Rose <jrose at digium.com>
+2012-02-28 19:55 +0000 [r357355]  Sean Bright <sean at malleable.com>
 
-	* /, main/bridge.c: transfers: Fix bug setting both BLINDTRANSFER
-	  and ATTENDEDTRANSFER The ast_bridge_set_transfer_variables
-	  function is supposed to wipe whichever variable isn't being set.
-	  Instead it was setting both to the new value. Oops. (issue
-	  AFS-24) ........ Merged revisions 403957 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* include/asterisk/netsock2.h: Documentation update. There is no
+	  AST_SOCKADDR_UNSPEC.
 
-2013-12-16 16:12 +0000 [r403857-403865]  Scott Griepentrog <sgriepentrog at digium.com>
+2012-02-28 19:37 +0000 [r357354]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/pbx.c, /: pbx.c: put copy of ast_exten.data on stack to
-	  prevent memory corruption During dialplan execution in
-	  pbx_extension_helper(), the contexts global read lock prevents
-	  link list corruption, but was released with a pointer to the
-	  ast_exten and data later used in variable substitution. Instead,
-	  this patch removes pbx_substitute_variables() and locates a copy
-	  of the ast_exten data on the stack before releasing the lock,
-	  where ast_exten could get free'd by another thread performing a
-	  module reload. (issue AST-1179) Reported by: Thomas Arimont
-	  (issue AST-1246) Reported by: Alexander Hömig Review:
-	  https://reviewboard.asterisk.org/r/3055/ ........ Merged
-	  revisions 403862 from
+	* /, apps/app_page.c: Remove dupliate 'i' option table entry in
+	  app_page.c. (closes issue ASTERISK-19310) Reported by: Makoto Dei
+	  Patches: app_page-duplicate-i-option.patch (license #5027) patch
+	  uploaded by Makoto Dei ........ Merged revisions 357352 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 403863 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403864 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 357353 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-28 18:52 +0000 [r357319]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/sip/security_events.c: Add a security event for the
+	  case where fake authentication challenge is sent. ........ Merged
+	  revisions 357318 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-28 18:46 +0000 [r357317]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/tcptls.c, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  Convert struct ast_tcptls_session_instance to finally use the ao2
+	  object lock.
+
+2012-02-28 18:23 +0000 [r357288]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Changes transport option in sip.conf so
+	  that using multiple instances doesn't stack. Prior to this patch,
+	  Using "transport=" multiple times would cause them to add to one
+	  another like allow/deny. This patch changes that behavior to
+	  simply use the transport option specified last. Also, if no
+	  transport option is applied now, the default will automatically
+	  be UDP. (closes ASTERISK-19352) Reported by: jamicque Patches:
+	  asterisk-19352-transport-warning-message-v1.patch uploaded by
+	  Michael L. Young (license 5026)
+	  issueA19352_no_transport_is_udp.patch uploaded by Walter Doekes
+	  (license 5674) Review:
+	  https://reviewboard.asterisk.org/r/1745/diff/#index_header
+	  ........ Merged revisions 357266 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357271 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-28 18:15 +0000 [r357272]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/format.c, main/format_cap.c, include/asterisk/astobj2.h,
+	  include/asterisk/lock.h, main/astobj2.c: Astobj2 locking
+	  enhancement. Add the ability to specify what kind of locking an
+	  ao2 object has when it is allocated. The locking could be one of:
+	  MUTEX, RWLOCK, or none. New API: ao2_t_alloc_options()
+	  ao2_alloc_options() ao2_t_container_alloc_options()
+	  ao2_container_alloc_options() ao2_rdlock() ao2_wrlock()
+	  ao2_tryrdlock() ao2_trywrlock() The OBJ_NOLOCK and
+	  AO2_ITERATOR_DONTLOCK flags have a slight meaning change. They no
+	  longer mean that the object is protected by an external
+	  mechanism. They mean the lock associated with the object has
+	  already been manually obtained by one of the ao2_lock calls. This
+	  change is necessary for RWLOCK support since they are not
+	  reentrant. Also an operation on an ao2 container may require
+	  promoting a read lock to a write lock by releasing the already
+	  held read lock to re-acquire as a write lock. Replaced API calls:
+	  ao2_t_link_nolock() ao2_link_nolock() ao2_t_unlink_nolock()
+	  ao2_unlink_nolock() with the respective ao2_t_link_flags()
+	  ao2_link_flags() ao2_t_unlink_flags() ao2_unlink_flags() API
+	  calls to be more flexible and to allow an anticipated enhancement
+	  to control linking duplicate objects into a container. The
+	  changes to format.c and format_cap.c are taking advantange of the
+	  new ao2 locking options to simplify the use of the format
+	  capabilities containers. Review:
+	  https://reviewboard.asterisk.org/r/1554/
+
+2012-02-28 14:47 +0000 [r357178-357214]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, Makefile.rules: Make COMPILE_DOUBLE magic actually work. The
+	  build system has some special magic to ensure that if Asterisk is
+	  built with --enable-dev-mode *and* DONT_OPTIMIZE, that all the
+	  source is still compiled with the optimizer enabled (even though
+	  the result will be thrown away), because the compiler is able to
+	  find a great deal of coding errors and bugs as a result of
+	  running its optimizers. Unfortunately at some point this mode got
+	  broken, and the 'throwaway' compile of the code was no longer
+	  done with the optimizer enabled. This patch corrects that
+	  problem. ........ Merged revisions 357212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 357213 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/astobj2.c: Trailing whitespace cleanup.
+
+2012-02-28 00:42 +0000 [r357096-357145]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h, tests/test_astobj2.c, main/astobj2.c:
+	  Add ability to clone ao2 containers. Occasionally there is a need
+	  to put all objects in one container also into another container.
+	  Some reasons you might need to do this: 1) You need to
+	  reconfigure a container. You would do this by creating a new
+	  container with the new configuration and ao2_container_dup the
+	  old container into it. Then replace the old container with the
+	  new. Then destroy the old container. 2) You need the contents of
+	  a container to remain stable while operating on all of the
+	  objects. You would do this by creating a cloned container of the
+	  original with ao2_container_clone. The cloned container is a
+	  snapshot of the objects at the time of the cloning. When done,
+	  just destroy the cloned container. Review:
+	  https://reviewboard.asterisk.org/r/1746/
+
+	* main/channel.c: Fix ast_channel allocation init setting priority
+	  to -1 instead of 1. * Fix opaquification conversion error.
+	  (closes issue ASTERISK-19424) Reported by: Jeremy Pepper Patches:
+	  asterisk-19424-initialize_priority_regression.diff (license
+	  #5026) patch uploaded by Michael L. Young
+
+	* main/channel.c, /: Fix callerid of Originated calls. Thanks to
+	  Matt Riddell for tracking this down. (closes issue
+	  ASTERISK-19385) Reported by: ornix ........ Merged revisions
+	  357093 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 357095 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-27 19:55 +0000 [r357051]  Jonathan Rose <jrose at digium.com>
+
+	* include/asterisk/res_odbc.h, res/res_odbc.c: Converts locking for
+	  odbc containers from ast_mutex_lock to ao2_locks.
+
+2012-02-27 17:03 +0000 [r357014]  Sean Bright <sean at malleable.com>
+
+	* channels/chan_iax2.c, main/netsock.c: Address comments from Mark
+	  Michelson
+
+2012-02-27 16:50 +0000 [r357013]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_dial.c, main/channel.c, include/asterisk/app.h,
+	  main/dial.c, main/rtp_engine.c, main/ccss.c, main/features.c,
+	  UPGRADE.txt, main/app.c, include/asterisk/channel.h,
+	  configs/ccss.conf.sample, apps/app_followme.c, apps/app_queue.c,
+	  include/asterisk/ccss.h: Deprecated macro usage for connected
+	  line, redirecting, and CCSS This commit adds GoSub alternatives
+	  to connected line, redirecting, and CCSS macro hooks so that
+	  macro can finally be deprecated. This also adds deprecation
+	  warnings for those features when used and in documentation.
+	  Review: https://reviewboard.asterisk.org/r/1760/ (closes issue
+	  SWP-4256)
+
+2012-02-27 16:31 +0000 [r357005]  Sean Bright <sean at malleable.com>
+
+	* include/asterisk/netsock.h, channels/chan_iax2.c, main/netsock.c:
+	  Convert netsock.h over to use ast_sockaddrs rather than
+	  sockaddr_in and update chan_iax2 to pass in the correct types.
+	  chan_iax2 is the only consumer for the various ast_netsock_*
+	  functions in trunk at this point, so this feels like a safe
+	  change to make.
+
+2012-02-27 16:24 +0000 [r356987]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c, configs/sip.conf.sample, CHANGES,
+	  channels/sip/include/sip.h: Adds an option to sip.conf that
+	  prevents diversion headers from being added. send_diversion=no
+	  will prevent Diversion headers from being added to SIP requests.
+	  This doesn't prevent Diversion from being added with dialplan
+	  such as with SIPAddHeader. (closes issue ASTERISK-16862) Reported
+	  by: rsw686 Review: https://reviewboard.asterisk.org/r/1769/
+
+2012-02-27 16:12 +0000 [r356966]  Sean Bright <sean at malleable.com>
+
+	* channels/chan_iax2.c: There isn't much point in saving off and
+	  restoring a value that we never use again.
+
+2012-02-27 16:08 +0000 [r356965]  Terry Wilson <twilson at digium.com>
+
+	* /, main/features.c: Copy CDR variables when set during a bridge
+	  This patch makes sure amaflags, accountcode, and userfield get
+	  copied to the bridge CDR when set during a bridge (like via a
+	  custom feature). (closes issue ASTERISK-16990) Review:
+	  https://reviewboard.asterisk.org/r/1721/ ........ Merged
+	  revisions 356963 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356964 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-27 15:35 +0000 [r356962]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_odbc.c: Remove possible segfaults from res_odbc by
+	  adding locks around usage of odbc handle (closes issue
+	  ASTERISK-19011) Reported by: Walter Doekes Patches:
+	  issueA19011_combine_read_and_write_locks_WORK_IN_PROGRESS.patch
+	  uploaded by Walter Doekes (license 5674) review:
+	  https://reviewboard.asterisk.org/r/1719/ review:
+	  https://reviewboard.asterisk.org/r/1622/ ........ Merged
+	  revisions 356917 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356961 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-27 14:57 +0000 [r356881-356916]  Sean Bright <sean at malleable.com>
+
+	* include/asterisk/netsock.h, main/netsock.c: Make
+	  ast_netsock_set_qos() delegate to ast_set_qos().
+
+	* include/asterisk/netsock.h: Correct typo in deprecation comment.
+
+	* channels/chan_unistim.c, main/udptl.c, channels/chan_skinny.c,
+	  include/asterisk/netsock.h, pbx/pbx_dundi.c,
+	  channels/chan_mgcp.c: Prefer ast_set_qos() over
+	  ast_netsock_set_qos()
+
+	* main/netsock.c: Remove trailing whitespace
+
+2012-02-26 18:25 +0000 [r356848]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooGkClient.c, addons/chan_ooh323.c: Add
+	  support change gatekeeper mode or ip per ooh323 reload command
+	  (issue ASTERISK-19298) Reported by: Dmitry Melekhov Patches:
+	  change_gk_on_reload-1.patch (License #5415)
+
+2012-02-25 17:22 +0000 [r356799]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_voicemail.c: Fix crash in app_voicemail during
+	  close_mailbox In r354890, a memory leak in app_voicemail was
+	  fixed by properly disposing of the allocated heard/deleted
+	  pointers. However, there are situations, particularly when no
+	  messages are found in a folder, where these pointers are not
+	  allocated and not NULL. In that case, an invalid free would be
+	  attempted, which could crash app_voicemail. As there are a number
+	  of code paths where this could occur, this patch uses the number
+	  of messages detected in the folder before it attempts to free the
+	  pointers. This resolves the crash detected in the Asterisk Test
+	  Suite's check_voicemail_nominal test. ........ Merged revisions
+	  356797 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 356798 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-24 23:40 +0000 [r356697-356765]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/astobj2.h: astobj2.h comment tweaks.
+
+	* include/asterisk/astobj2.h, main/astobj2.c: astobj2.h
+	  documentation updates.
+
+	* /, channels/chan_sip.c, include/asterisk/tcptls.h,
+	  channels/sip/include/sip.h: Fix worker thread resource leak in
+	  SIP TCP/TLS. The SIP TCP/TLS worker threads were created joinable
+	  but noone could join them if they died on their own. * Fix the
+	  SIP TCP/TLS worker threads to not be created joinable. *
+	  _sip_tcp_helper_thread() only needs one parameter since the pvt
+	  parameter is only passed in as NULL and never used. (closes issue
+	  ASTERISK-19203) Reported by: Steve Davies Review:
+	  https://reviewboard.asterisk.org/r/1714/ ........ Merged
+	  revisions 356677 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356690 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, apps/app_sms.c: app_sms: BufferOverflow when receiving odd
-	  length 16 bit message This patch prevents an infinite loop
-	  overwriting memory when a message is received into the
-	  unpacksms16() function, where the length of the message is an odd
-	  number of bytes. (closes issue ASTERISK-22590) Reported by: Jan
-	  Juergens Tested by: Jan Juergens ........ Merged revisions 403856
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-15 01:39 +0000 [r403824]  Matthew Jordan <mjordan at digium.com>
-
-	* channels/pjsip/dialplan_functions.c, /: pjsip/dialplan_functions:
-	  Use the right buffer length when printing URIs While
-	  entertaining, sizeof(buflen) is not the same as buflen. Doh.
-	  ........ Merged revisions 403823 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-14 17:28 +0000 [r403810-403812]  Joshua Colp <jcolp at digium.com>
-
-	* include/asterisk/res_pjsip.h, /, res/res_pjsip/location.c,
-	  res/res_pjsip/pjsip_options.c, res/res_pjsip.c: res_pjsip: Apply
-	  outbound proxy to all SIP requests. Objects which are involved in
-	  SIP request creation and sending now allow an outbound proxy to
-	  be specified. For cases where an endpoint is used the outbound
-	  proxy specified there will be applied. (closes issue
-	  ASTERISK-22673) Reported by: Antti Yrjola Review:
-	  https://reviewboard.asterisk.org/r/3022/ ........ Merged
-	  revisions 403811 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_channels.c, apps/app_queue.c,
-	  res/ari/ari_model_validators.c, apps/app_dial.c,
-	  res/ari/ari_model_validators.h, main/dial.c,
-	  include/asterisk/stasis_channels.h,
-	  rest-api/api-docs/events.json, /, res/stasis/app.c: res_stasis:
-	  Expose event for call forwarding and follow forwarded channel.
-	  This change adds an event for when an originated call is
-	  redirected to another target. This event contains the original
-	  channel and the newly created channel. If a stasis subscription
-	  exists on the original originated channel for a stasis
-	  application then a new subscription will also be created on the
-	  stasis application to the redirected channel. This allows the
-	  application to follow the call path completely. (closes issue
-	  ASTERISK-22719) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/3054/ ........ Merged
-	  revisions 403808 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 21:35 +0000 [r403797]  Jonathan Rose <jrose at digium.com>
-
-	* /, res/res_pjsip_messaging.c, main/message.c: documentation: Add
-	  PJSIP technology to messaging documentation ........ Merged
-	  revisions 403796 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 20:17 +0000 [r403784]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/test.c: test.c: Fix too sticky unit test failed status.
-	  Rerunning a failed unit test after loading any required modules
-	  should allow the test to report a pass status if it now passes.
-	  ........ Merged revisions 403782 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 20:13 +0000 [r403783]  Jonathan Rose <jrose at digium.com>
-
-	* /, main/bridge.c, main/bridge_basic.c, include/asterisk/bridge.h,
-	  res/parking/parking_bridge_features.c,
-	  res/parking/parking_manager.c: Transfers: Make Asterisk set
-	  ATTENDEDTRANSFER/BLINDTRANSFER more reliably There were still a
-	  few cases in which ATTENDEDTRANSFER and BLINDTRANSFER wouldn't be
-	  set on channels involved with blind and attended transfers. This
-	  would happen with features that were initialized by channel
-	  driver specific mechanisms in multiparty calls. This patch
-	  resolves those cases while attempted to keep the behavior for
-	  setting those variables as consistent as possible. (closes issue
-	  AFS-24) Review: https://reviewboard.asterisk.org/r/3040/ ........
-	  Merged revisions 403781 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 18:33 +0000 [r403750-403768]  Kevin Harwell <kharwell at digium.com>
-
-	* main/channel.c, /, channels/chan_sip.c,
-	  include/asterisk/channel.h, bridges/bridge_native_rtp.c,
-	  channels/chan_pjsip.c: bridge_native_rtp: Deadlock during 4-way
-	  conference creation The change contains a slightly adjusted patch
-	  that was on the issue (submitted by kmoore). A fix was made by
-	  adding in a bridge lock while calling bridge_start/stop from the
-	  framehook callback. Since the framehook callback is not called
-	  from the bridging core the bridge is not locked, but needs to be
-	  before calling bridge_start. (closes issue ASTERISK-22749)
-	  Reported by: Kinsey Moore Review:
-	  https://reviewboard.asterisk.org/r/3066/ Patches:
-	  lock_inversion.diff uploaded by kmoore (license 6273) ........
-	  Merged revisions 403767 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, res/ari/resource_channels.h, /,
-	  main/http.c: ARI: Allow specifying channel variables during a
-	  POST /channels Added the ability to specify channel variables
-	  when creating/originating a channel in ARI. The variables are
-	  sent in the body of the request and should be formatted as a
-	  single level JSON object. No nested objects allowed. For example:
-	  {"variable1": "foo", "variable2": "bar"}. (closes issue
-	  ASTERISK-22872) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3052/ ........ Merged
-	  revisions 403752 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_answer.c, rest-api/api-docs/bridges.json,
-	  res/ari/resource_bridges.c, res/res_ari_bridges.c,
-	  res/stasis/command.c, res/res_stasis_playback.c, /,
-	  res/stasis/control.c, res/stasis/command.h,
-	  include/asterisk/stasis_app.h,
-	  include/asterisk/stasis_app_impl.h, res/res_stasis_recording.c:
-	  ARI: Adding a channel to a bridge while a live recording is
-	  active blocks Added the ability to have rules that are checked
-	  when adding and/or removing channels to/from a bridge. In this
-	  case, if a channel is currently recording and someone attempts to
-	  add it to a bridge an "is recording" rule is checked, fails, and
-	  a 409 conflict is returned. Also command functions now return an
-	  integer value that can be descriptive of what kind of problems,
-	  if any, occurred before or during execution. (closes issue
-	  ASTERISK-22624) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/2947/ ........ Merged
-	  revisions 403749 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 05:00 +0000 [r403737]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/Makefile: channels/Makefile: clean pjsip directory
-	  ........ Merged revisions 403736 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-13 00:40 +0000 [r403726]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/app.h, tests/test_voicemail_api.c, main/app.c:
-	  test_voicemail_api: Add check for a registered voicemail provider
-	  before tests. It is much nicer diagnosing a test failure if
-	  app_voicemail is actually loaded.
-
-2013-12-12 19:46 +0000 [r403714]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py
-	  (added), /: realtime: Create extensions in alembic ast-db-manage
-	  contribution When the alembic scripts were written for creating
-	  Asterisk realtime databases the extensions table for dialplan
-	  wasn't included. This update creates the extensions table.
-	  (closes issue ASTERISK-22815) Reported by: Zone Conkle Review:
-	  https://reviewboard.asterisk.org/r/3064/ ........ Merged
-	  revisions 403713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-12 19:18 +0000 [r403707]  Jonathan Rose <jrose at digium.com>
-
-	* /, channels/chan_pjsip.c: chan_pjsip: Revert r403587 This patch
-	  was intended to eliminate a deadlock that occurs when masquerades
-	  occur in pjsip channels, but has some potential side effects.
-	  Mark Michelson is currently working on addressing this problem
-	  from another angle. (issue ASTERISK-22936) Reported by: Jonathan
-	  Rose ........ Merged revisions 403705 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-11 20:24 +0000 [r403687]  Kevin Harwell <kharwell at digium.com>
-
-	* include/asterisk/res_pjsip.h, res/res_pjsip/config_global.c, /,
-	  configs/pjsip.conf.sample, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip_messaging.c,
-	  res/res_pjsip/include/res_pjsip_private.h, res/res_pjsip.c:
-	  res_pjsip_messaging: send message to a default outbound endpoint
-	  In some cases messages need to be sent to a direct URI (sip:<ip
-	  address>). This patch adds in that support by using a default
-	  outbound endpoint. When sending messages, if no endpoint can be
-	  found then the default one is used. To facilitate this a new
-	  default_outbound_endpoint option was added to the globals section
-	  for pjsip.conf. Review: https://reviewboard.asterisk.org/r/2944/
-	  ........ Merged revisions 403680 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-11 19:22 +0000 [r403652]  Russell Bryant <russell at russellbryant.com>
+2012-02-24 17:43 +0000 [r356606-356652]  Matthew Jordan <mjordan at digium.com>
 
-	* /, channels/chan_sip.c: Reset peer outboundproxy on sip.conf
-	  reload If you set a peer's outboundproxy and then removed it from
-	  the config, this would not get picked up in a config reload. This
-	  patch fixes that by resetting it in set_peer_defaults(). Closes
-	  ASTERISK-19454 Review: https://reviewboard.asterisk.org/r/3065/
-	  ........ Merged revisions 403634 from
+	* /, res/res_srtp.c: Remove srtp_shutdown from res_srtp The patch
+	  for ASTERISK-19253 included properly shutting down the libsrtp
+	  library in the case of module unload. Unfortunately, not all
+	  distributions have the srtp_shutdown call. As such, this patch
+	  removes calling srtp_shutdown. ........ Merged revisions 356650
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 356651 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sip/sdp_crypto.c, include/asterisk/res_srtp.h,
+	  main/rtp_engine.c, /, include/asterisk/rtp_engine.h,
+	  res/res_srtp.c: Allow SRTP policies to be reloaded Currently,
+	  when using res_srtp, once the SRTP policy has been added to the
+	  current session the policy is locked into place. Any attempt to
+	  replace an existing policy, which would be needed if the remote
+	  endpoint negotiated a new cryptographic key, is instead rejected
+	  in res_srtp. This happens in particular in transfer scenarios,
+	  where the endpoint that Asterisk is communicating with changes
+	  but uses the same RTP session. This patch modifies res_srtp to
+	  allow remote and local policies to be reloaded in the underlying
+	  SRTP library. From the perspective of users of the SRTP API, the
+	  only change is that the adding of remote and local policies are
+	  now added in a single method call, whereas they previously were
+	  added separately. This was changed to account for the differences
+	  in handling remote and local policies in libsrtp. Review:
+	  https://reviewboard.asterisk.org/r/1741/ (closes issue
+	  ASTERISK-19253) Reported by: Thomas Arimont Tested by: Thomas
+	  Arimont Patches: srtp_renew_keys_2012_02_22.diff uploaded by Matt
+	  Jordan (license 6283) (with some small modifications for this
+	  check-in) ........ Merged revisions 356604 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 403635 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403639 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-11 19:19 +0000 [r403643]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_voicemail.c, include/asterisk/app.h,
-	  include/asterisk/doxyref.h, main/app.c: app_voicemail: Voicemail
-	  callback registration/unregistration function improvements. * The
-	  voicemail registration/unregistration functions now take a struct
-	  of callbacks instead of a lengthy parameter list of callbacks. *
-	  The voicemail registration/unregistration functions now prevent a
-	  competing module from interfering with an already registered
-	  callback supplying module.
-
-2013-12-11 13:06 +0000 [r403617-403619]  Matthew Jordan <mjordan at digium.com>
-
-	* channels/pjsip/dialplan_functions.c,
-	  include/asterisk/res_pjsip_session.h, channels/pjsip (added), /,
-	  funcs/func_channel.c, channels/pjsip/include,
-	  channels/pjsip/include/dialplan_functions.h, res/res_pjsip_t38.c,
-	  channels/pjsip/include/chan_pjsip.h, channels/Makefile,
-	  channels/chan_pjsip.c, main/xmldoc.c: func_channel, chan_pjsip:
-	  Add CHANNEL read function support for chan_pjsip This patch adds
-	  CHANNEL read support for chan_pjsip. This allows the dialplan to
-	  use the CHANNEL function on a chan_pjsip channel to obtain
-	  run-time information about the channel from the PJSIP channel
-	  driver and the PJSIP stack. This includes: * RTP information,
-	  including source/destination media addresses, whether or not the
-	  media is secure, held, and other properties. * RTCP information.
-	  This includes sets of parseable information, as well as
-	  individual statistic attriutes. * PJSIP information. This
-	  includes URIs, local/remote signalling addresses, whether or not
-	  the signalling is secure, and other properties. * The endpoint
-	  name. This can be used in conjunction with the PJSIP_ENDPOINT
-	  function to obtain more detailed endpoint information. Review:
-	  https://reviewboard.asterisk.org/r/3038/ ........ Merged
-	  revisions 403618 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* Makefile, funcs/func_pjsip_endpoint.c (added), doc/snapshots.xslt
-	  (removed), /, doc/appdocsxml.xslt (added), doc/appdocsxml.dtd,
-	  main/sorcery.c: func_pjsip_endpoint: Add PJSIP_ENDPOINT function
-	  for querying endpoint details This patch adds a new function,
-	  PJSIP_ENDPOINT, which lets the dialplan query, for any endpoint,
-	  any property configured on an endpoint. This function is a
-	  companion to the CHANNEL function, which can be used to extract
-	  the endpoint name for a channel. Review:
-	  https://reviewboard.asterisk.org/r/3035 ........ Merged revisions
-	  403616 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-10 15:15 +0000 [r403605]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_authenticator_digest.c: Fix correct authentication
-	  behavior for artificial endpoint. When switching to using a
-	  vector for authentication, I initialized the vector for the
-	  artificial endpoint to be of size 1. However, this does not
-	  result in AST_VECTOR_SIZE() returning 1 since there isn't
-	  actually anything in the vector. Rather than trifle with the
-	  vector by putting unnecessary elements in, I simply changed the
-	  callback in res_pjsip_authenticator_digest.c to explicitly report
-	  that the artificial endpoint requires authentication. Thanks to
-	  Joshua Colp for pointing this out.
-
-2013-12-09 22:59 +0000 [r403576-403588]  Jonathan Rose <jrose at digium.com>
-
-	* /, channels/chan_pjsip.c: chan_pjsip: Fix a sticking channel lock
-	  caused by channel masquerades (closes issue ASTERISK-22936)
-	  Reported by: Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/3042/ ........ Merged
-	  revisions 403587 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* CHANGES, main/dial.c, apps/app_page.c, include/asterisk/dial.h:
-	  app_page: Add predial handlers for app_page. (closes issue
-	  AFS-14) Review: https://reviewboard.asterisk.org/r/3045/
-
-2013-12-09 19:24 +0000 [r403544-403560]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_sorcery_astdb.c: Reverting regex part of -r403545 at
-	  request of file. res_sorcery_astdb.c: Fix get multiple records by
-	  regex. * Fix sorcery_astdb_retrieve_regex() pattern matching. Let
-	  the regexec() function match the stored key values instead of
-	  having astdb prefilter them. Previoiusly you could only use a
-	  simple regex pattern when the pattern began with '^'. ........
-	  Merged revisions 403559 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_sorcery_astdb.c: res_sorcery_astdb.c: Fix get multiple
-	  records by regex. * Fix sorcery_astdb_retrieve_regex() pattern
-	  matching. Let the regexec() function match the stored key values
-	  instead of having astdb prefilter them. Previoiusly you could
-	  only use a simple regex pattern when the pattern began with '^'.
-	  * Fix off nominal memory leak in sorcery_astdb_retrieve_regex().
-	  ........ Merged revisions 403545 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/sorcery.c, /: sorcery: Eliminate shadowing a varaible that
-	  caused confusion. * Eliminated shadowing of the
-	  __ast_sorcery_apply_config() name parameter causing confusion. *
-	  Fix potential crash from sorcery.conf user input in
-	  __ast_sorcery_apply_config() if the user supplied a malformed
-	  config line that is missing the sorcery object type name. *
-	  Remove redundant test in __ast_sorcery_apply_config(). !config
-	  and config == CONFIGS_STATUS_FILEMISSING are identical. ........
-	  Merged revisions 403541 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-09 18:32 +0000 [r403543]  Joshua Colp <jcolp at digium.com>
-
-	* /, main/endpoints.c: endpoints: Keep a reference to channel ids
-	  when creating snapshot. The snapshot process for endpoints uses
-	  the channel ids present on the endpoint itself. Without keeping a
-	  reference it was possible for the strings to be freed underneath
-	  any consumer of an endpoint snapshot. A reference is now held by
-	  the snapshot to the channel ids and released when the snapshot is
-	  destroyed. (issue ASTERISK-22801) Reported by: Matt Jordan
-	  ........ Merged revisions 403542 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-09 18:14 +0000 [r403528]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/sorcery.c, /: sorcery: Whitespace You would think that a new
-	  file would start off without any whitespace oddities. ........
-	  Merged revisions 403527 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-09 17:29 +0000 [r403512-403526]  Mark Michelson <mmichelson at digium.com>
-
-	* apps/app_confbridge.c, CHANGES,
-	  apps/confbridge/conf_state_multi_marked.c: Add a
-	  CONFBRIDGE_RESULT channel variable to discern why a channel left
-	  a ConfBridge. Review: https://reviewboard.asterisk.org/r/3009
-
-	* CHANGES, apps/app_mixmonitor.c: Create function for retrieving
-	  Mixmonitor instance data. For the time, this is only useful for
-	  retrieving the filename. The purpose of this function is to
-	  better facilitate multiple mixmonitors per channel. Setting a
-	  MIXMONITOR_FILENAME channel variable is not conducive to such
-	  behavior, so allowing finer grained access to individual
-	  mixmonitor properties improves the situation. The
-	  MIXMONITOR_FILENAME channel variable is still set, though, so
-	  there is no worry about backwards compatibility. Review:
-	  https://reviewboard.asterisk.org/r/3023
-
-2013-12-09 16:41 +0000 [r403511]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_nat.c, /: res_pjsip_nat: Add NAT module to session
-	  dialogs. Due to the way pjproject internally works it was
-	  possible for the NAT module to not be invoked on messages with-in
-	  a session dialog. This means that the various parts of the
-	  message would not get rewritten with the source IP address and
-	  port. This change uses a session supplement to add the NAT module
-	  to the dialog on the first incoming or outgoing INVITE. (closes
-	  issue ASTERISK-22941) Reported by: Leif Madsen ........ Merged
-	  revisions 403510 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-09 16:10 +0000 [r403499]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip/config_auth.c,
-	  res/res_pjsip_outbound_authenticator_digest.c,
-	  res/res_pjsip_authenticator_digest.c,
-	  res/res_pjsip_outbound_registration.c,
-	  res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip/pjsip_distributor.c, res/res_pjsip.c,
-	  include/asterisk/res_pjsip.h: Switch PJSIP auth to use a vector.
-	  Since Asterisk has a vector API now, places where arrays are
-	  manually resized don't really make sense any more. Since the auth
-	  work in PJSIP was freshly-written, it was easy to reform it to
-	  use a vector. Review: https://reviewboard.asterisk.org/r/3044
-
-2013-12-09 03:21 +0000 [r403436-403466]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_fax_spandsp.c: res_fax_spandsp: Always init T.38
-	  session to avoid crashes during state change Prior to this patch,
-	  res_fax_spandsp was conservative with how it initialized the
-	  spandsp T.38 context. It would only initialize it if the driver
-	  thought the current state was a T.38 fax. While this works fine
-	  in nominal situations, in certain off nominal situations,
-	  res_fax_spandsp can believe that a T.38 fax will not occur when
-	  in fact one has started. In particular, this was discovered when
-	  res_fax would fall back to audio after timing out on a T.38
-	  upgrade. The SIP channel driver would continue to retry the
-	  re-INVITE and - if the remote end responded after res_fax timed
-	  out with a 200 OK - a T.38 frame would be delivered to the
-	  res_fax stack when it no longer expected it. As it turns out,
-	  there does not appear to be any downside to always initializing
-	  the T.38 context, other than the actual memory allocation. Since
-	  that avoids this off nominal situation (and others which are
-	  equally likely hard to predict), this is the safest way to avoid
-	  this problem. Much thanks to Torrey as well for providing a
-	  scenario that reproduces this issue. (closes issue
-	  ASTERISK-21242) Reported by: Ashley Winters Tested by: Torrey
-	  Searle patches: always-init-t38.patch uploaded by awinters
-	  (License 6477) A_PARTY.xml uploaded by tsearle (License 5334)
-	  ........ Merged revisions 403449 from
+	  revisions 356605 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-24 00:32 +0000 [r356573]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_unistim.c, channels/chan_local.c,
+	  addons/chan_ooh323.c, channels/chan_multicast_rtp.c,
+	  channels/chan_vpb.cc, main/rtp_engine.c, apps/app_meetme.c,
+	  apps/app_dictate.c, apps/app_record.c, apps/app_test.c,
+	  bridges/bridge_softmix.c, channels/chan_gtalk.c, apps/app_ices.c,
+	  res/res_musiconhold.c, channels/chan_iax2.c,
+	  bridges/bridge_multiplexed.c, main/indications.c, main/cli.c,
+	  main/channel.c, channels/chan_phone.c, channels/chan_dahdi.c,
+	  channels/chan_skinny.c, res/res_agi.c, main/features.c,
+	  apps/app_mp3.c, apps/app_dumpchan.c, main/app.c, apps/app_amd.c,
+	  channels/chan_alsa.c, apps/app_confbridge.c,
+	  addons/chan_mobile.c, main/bridging.c, channels/chan_mgcp.c,
+	  apps/app_nbscat.c, main/pbx.c, channels/chan_sip.c,
+	  res/res_fax.c, apps/app_festival.c, channels/chan_bridge.c,
+	  main/channel_internal_api.c, apps/app_fax.c,
+	  apps/app_waitforsilence.c, res/res_adsi.c, channels/chan_agent.c,
+	  bridges/bridge_simple.c, include/asterisk/channel.h,
+	  channels/chan_console.c, apps/app_talkdetect.c,
+	  channels/chan_oss.c, apps/app_speech_utils.c,
+	  channels/chan_usbradio.c, channels/chan_jingle.c,
+	  channels/chan_misdn.c, funcs/func_channel.c, main/file.c,
+	  channels/chan_nbs.c, apps/app_chanspy.c, apps/app_voicemail.c,
+	  res/res_calendar.c: Opaquification for ast_format structs in
+	  struct ast_channel Review:
+	  https://reviewboard.asterisk.org/r/1770/
+
+2012-02-23 20:14 +0000 [r356523]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c, main/features.c: Fix blind transfer
+	  parking issues if the dialed extension is not recognized as a
+	  parking extension. Custom parking extensions may not be coded
+	  such that the first and only extension priority is the Park
+	  application. These custom parking extensions will not be
+	  recognized as parking extensions. When a call is blind
+	  transferred to an extension that is not recognized as a parking
+	  extension, the normal blind transfer code causes the transferred
+	  channel to start executing dialplan. Calls that get parked in
+	  this manner do not know the original channel name that parked the
+	  call so the original parker could never be called back if the
+	  parked call is not retrieved before the timeout time. The parking
+	  space is also announced to the call being parked as a side effect
+	  of not knowing the original parking channel. * Fix handling of
+	  BLINDTRANSFER channel variable for call parking. * Fixed SIP
+	  blind transfer using the wrong dialplan context variable to check
+	  for the parking extension. (closes issue ASTERISK-19322) Reported
+	  by: aragon Tested by: rmudgett, jparker Review:
+	  https://reviewboard.asterisk.org/r/1730/ JIRA AST-766 ........
+	  Merged revisions 356521 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356522 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-23 15:49 +0000 [r356477]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix ACK routing for non-2xx responses.
+	  When we send an ACK for a 2xx response to an INVITE, we are
+	  supposed to use the learned route set. However, when we receive a
+	  non-2xx final response to an INVITE, we are supposed to send the
+	  ACK to the same place we initially sent the INVITE. We had been
+	  doing this up until the changes went in that would build a route
+	  set from provisional responses. That introduced a regression
+	  where we would use the learned route set under all circumstances.
+	  With this change, we now will set the destination of our ACK
+	  based on the invitestate. If it is INV_COMPLETED then that means
+	  that we have received a non-2xx final response (INV_TERMINATED
+	  indicates a 2xx response was received). If it is INV_CANCELLED,
+	  then that means the call is being canceled, which means that we
+	  should be ACKing a 487 response. The other change introduced here
+	  is setting the invitestate to INV_CONFIRMED when we send an ACK
+	  *after* the reqprep instead of before. This way, we can tell in
+	  reqprep more easily what the invitestate is prior to sending the
+	  ACK. (closes issue ASTERISK-19389) reported by Karsten Wemheuer
+	  patches: ASTERISK-19389v2.patch uploaded by Mark Michelson
+	  (license #5049) (with some slight modifications prior to commit)
+	  ........ Merged revisions 356475 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356476 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-23 03:27 +0000 [r356429]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, apps/app_rpt.c: Multiple revisions 356290,356335,356337
+	  ........ r356290 | pabelanger | 2012-02-22 15:20:29 -0500 (Wed,
+	  22 Feb 2012) | 4 lines Fix -Werror=unused-but-set-variable
+	  compiler error (gcc 4.6.2) Review:
+	  https://reviewboard.asterisk.org/r/1763/ ........ r356335 |
+	  pabelanger | 2012-02-22 16:29:25 -0500 (Wed, 22 Feb 2012) | 2
+	  lines Add back strsep() function for previous commit ........
+	  r356337 | pabelanger | 2012-02-22 16:36:37 -0500 (Wed, 22 Feb
+	  2012) | 2 lines Missed one strsep() function ........ Merged
+	  revisions 356290,356335,356337 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356428 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-23 01:53 +0000 [r356397]  Terry Wilson <twilson at digium.com>
+
+	* tests/test_substitution.c, tests/test_utils.c: Fix some tests
+	  that didn't get opaquification changes Review:
+	  https://reviewboard.asterisk.org/r/1766/
+
+2012-02-23 00:56 +0000 [r356366]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel_internal_api.c: Revert some apparently accidental
+	  spacing changes.
+
+2012-02-22 21:22 +0000 [r356314]  Terry Wilson <twilson at digium.com>
+
+	* /, include/asterisk/calendar.h, main/loader.c,
+	  res/res_calendar.c: Track module use count for res_calendar If
+	  the res_calendar module was followed immediately by one of the
+	  calendar tech modules and "core stop gracefully" was run,
+	  Asterisk would crash. This patch adds use count tracking for
+	  res_calendar so that it is unloaded after the tech modules when
+	  shutting down gracefully. It is now not possible to unload all
+	  the of the calendar modules via "module unload res_calednar.so",
+	  but it is still possible to unload them all via "module unload -h
+	  res_calendar.so". Review:
+	  https://reviewboard.asterisk.org/r/1752/ ........ Merged
+	  revisions 356291 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 356297 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-22 21:10 +0000 [r356292]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* channels/misdn/isdn_msg_parser.c, channels/misdn/isdn_lib.c:
+	  Correct some set-but-unused variable warnings in the mISDN
+	  library.
+
+2012-02-22 17:34 +0000 [r356259]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_misdn.c: Fix chan_misdn after the lastest
+	  opaquification changes It now compiles, but there are some
+	  unrelated warnings for set but unused variables.
+
+2012-02-22 14:54 +0000 [r356216]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 356215 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r356215 | mjordan | 2012-02-22 08:53:53 -0600
+	  (Wed, 22 Feb 2012) | 32 lines Merged revisions 356214 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r356214 | mjordan | 2012-02-22 08:50:20 -0600 (Wed, 22 Feb 2012)
+	  | 27 lines Fix potential buffer overrun and memory leak when
+	  executing "sip show peers" The "sip show peers" command uses a
+	  fix sized array to sort the current peers in the peers
+	  ao2_container. The size of the array is based on the current
+	  number of peers in the container. However, once the size of the
+	  array is determined, the number of peers in the container can
+	  change, as the peers container is not locked. This could cause a
+	  buffer overrun when populating the array, if peers were added to
+	  the container after the array was created. Additionally, a memory
+	  leak of the allocated array would occur if a user caused the
+	  _show_peers method to return CLI_SHOWUSAGE. We now create a
+	  snapshot of the current peers using an ao2_callback with the
+	  OBJ_MULTIPLE flag. This size of the array is set to the number of
+	  peers that the iterator will iterate over; hence, if peers are
+	  added or removed from the peers container it will not affect the
+	  execution of the "sip show peers" command. Review:
+	  https://reviewboard.asterisk.org/r/1738/ (closes issue
+	  ASTERISK-19231) (closes issue ASTERISK-19361) Reported by: Thomas
+	  Arimont, Jamuel Starkey Tested by: Thomas Arimont, Jamuel Starkey
+	  Patches: sip_show_peers_2012_02_16.diff uploaded by mjordan
+	  (license 6283) ........ ................
+
+2012-02-22 00:35 +0000 [r356152-356183]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c, main/channel_internal_api.c,
+	  include/asterisk/channel.h: Rename
+	  ast_channel_emulate_dtmf_digit* funcs The accessors names for the
+	  "emulate_dtmf_digit" field on the ast_channel are misleading.
+	  Change them to ast_channel_dtmf_digit_to_emulate*.
+
+	* main/channel.c, main/framehook.c, res/res_monitor.c: Fix some
+	  opaquification-related compiler warnings (closes issue
+	  ASTERISK-19419) PseudoReview - seanbright on IRC
+
+2012-02-21 11:17 +0000 [r356111]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: Make 'iax2 show callnumber usage' output
+	  make sense when an IP is passed in. ........ Merged revisions
+	  356107 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 356108 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-21 04:31 +0000 [r356075]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/ccss.c: Add missing newline to ccss state change
+	  notification Move along, nothing to see here... ........ Merged
+	  revisions 356074 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-20 23:43 +0000 [r356042]  Terry Wilson <twilson at digium.com>
+
+	* main/udptl.c, apps/app_dahdibarge.c, addons/chan_ooh323.c,
+	  cdr/cdr_sqlite3_custom.c, channels/chan_local.c,
+	  main/rtp_engine.c, apps/app_playtones.c, apps/app_record.c,
+	  apps/app_sayunixtime.c, apps/app_test.c, main/devicestate.c,
+	  apps/app_alarmreceiver.c, apps/app_chanisavail.c,
+	  apps/app_ices.c, channels/chan_iax2.c,
+	  bridges/bridge_multiplexed.c, main/cli.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c, main/framehook.c, channels/chan_skinny.c,
+	  main/features.c, apps/app_dumpchan.c, pbx/pbx_realtime.c,
+	  channels/chan_alsa.c, apps/app_externalivr.c, main/bridging.c,
+	  channels/sig_ss7.c, apps/app_milliwatt.c, cdr/cdr_manager.c,
+	  apps/app_dial.c, main/pbx.c, funcs/func_timeout.c,
+	  apps/app_privacy.c, channels/chan_bridge.c, apps/app_echo.c,
+	  apps/app_softhangup.c, apps/app_fax.c, apps/app_dahdiras.c,
+	  channels/chan_agent.c, apps/app_disa.c, bridges/bridge_simple.c,
+	  include/asterisk/channel.h, apps/app_talkdetect.c,
+	  apps/app_transfer.c, main/cel.c, res/res_monitor.c,
+	  apps/app_playback.c, apps/app_speech_utils.c,
+	  channels/chan_misdn.c, apps/app_sendtext.c, funcs/func_channel.c,
+	  funcs/func_cdr.c, channels/sip/dialplan_functions.c,
+	  apps/app_macro.c, apps/app_zapateller.c, main/audiohook.c,
+	  apps/app_chanspy.c, apps/app_voicemail.c, apps/app_cdr.c,
+	  res/res_calendar.c, channels/chan_unistim.c,
+	  channels/chan_multicast_rtp.c, channels/chan_vpb.cc,
+	  apps/app_meetme.c, main/ccss.c, apps/app_dictate.c,
+	  apps/app_authenticate.c, apps/app_readexten.c,
+	  channels/chan_gtalk.c, res/res_musiconhold.c,
+	  apps/app_followme.c, main/channel.c, main/cdr.c,
+	  channels/chan_phone.c, main/dial.c, main/manager.c,
+	  apps/app_osplookup.c, bridges/bridge_builtin_features.c,
+	  res/res_agi.c, apps/app_minivm.c, main/app.c,
+	  apps/app_confbridge.c, main/image.c, apps/app_directory.c,
+	  main/message.c, apps/app_ivrdemo.c, addons/chan_mobile.c,
+	  apps/app_rpt.c, cdr/cdr_custom.c, apps/app_parkandannounce.c,
+	  channels/chan_mgcp.c, apps/app_while.c, res/res_rtp_asterisk.c,
+	  apps/app_read.c, channels/chan_sip.c, apps/app_festival.c,
+	  res/res_fax.c, cdr/cdr_syslog.c, apps/app_waitforsilence.c,
+	  main/channel_internal_api.c, res/res_adsi.c, pbx/pbx_lua.c,
+	  funcs/func_jitterbuffer.c, channels/chan_console.c,
+	  apps/app_queue.c, channels/sig_pri.c, channels/chan_oss.c,
+	  channels/chan_jingle.c, channels/chan_usbradio.c,
+	  apps/app_channelredirect.c, apps/app_forkcdr.c, apps/app_flash.c,
+	  main/abstract_jb.c, main/file.c, channels/chan_h323.c,
+	  include/asterisk/sched.h, res/snmp/agent.c, apps/app_sms.c,
+	  channels/chan_nbs.c, funcs/func_callerid.c, apps/app_verbose.c,
+	  apps/app_stack.c: ast_channel opaquification of pointers and
+	  integral types Review: https://reviewboard.asterisk.org/r/1753/
+
+2012-02-20 18:40 +0000 [r355903-355999]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: Remove spurious warning when
+	  'qualifyfreqnotok' is set successfully. (closes issue
+	  ASTERISK-17176) Reported by: John Covert Tested by: Sean Bright
+	  Patches: chan_iax2.c.qualifyfreqnotok.patch uploaded by John
+	  Covert (license 5512) ........ Merged revisions 355997 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 403450 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_config_sqlite.c: res_config_sqlite: Check for CDR
-	  unregistration failures If the CDR unregistration fails due to an
-	  inflight CDR, the res_config_sqlite module needs to bail on
-	  unloading itself. Otherwise, the config could be unloaded
-	  (including the CDR table name) while the CDR engine posts a CDR
-	  to the still registered backend, resulting in a crash. ........
-	  Merged revisions 403435 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-05 23:40 +0000 [r403414]  Jonathan Rose <jrose at digium.com>
-
-	* apps/app_record.c: app_record: Add an option that allows DTMF '0'
-	  to act as an additional terminator Using this terminator when
-	  active results in ${RECORD_STATUS} being set to 'OPERATOR'
-	  instead of 'DTMF' (closes issue AFS-7) Review:
-	  https://reviewboard.asterisk.org/r/3041/
-
-2013-12-05 22:10 +0000 [r403402-403404]  David M. Lee <dlee at digium.com>
-
-	* addons/chan_mobile.c, main/bridge_channel.c, tests/test_cdr.c,
-	  channels/chan_pjsip.c, res/parking/parking_manager.c,
-	  channels/chan_mgcp.c, channels/chan_unistim.c, main/pbx.c, /,
-	  apps/app_meetme.c, funcs/func_timeout.c, main/bridge.c,
-	  tests/test_stasis_channels.c, main/core_unreal.c,
-	  include/asterisk/channel.h, channels/chan_gtalk.c, main/cel.c,
-	  apps/app_queue.c, channels/sig_pri.c, main/stasis_bridges.c,
-	  channels/chan_jingle.c, channels/chan_phone.c,
-	  channels/chan_dahdi.c, main/dial.c, channels/sig_analog.c,
-	  include/asterisk/stasis_channels.h, res/res_agi.c,
-	  channels/chan_motif.c, channels/chan_h323.c, tests/test_cel.c,
-	  apps/app_confbridge.c, res/res_stasis.c, res/res_pjsip_refer.c,
-	  apps/app_voicemail.c, apps/app_dial.c, channels/chan_vpb.cc,
-	  addons/chan_ooh323.c, channels/chan_sip.c, main/pickup.c,
-	  include/asterisk/aoc.h, include/asterisk/stasis_bridges.h,
-	  apps/app_userevent.c, apps/app_disa.c, main/core_local.c,
-	  include/asterisk/channelstate.h, channels/chan_console.c,
-	  channels/chan_iax2.c, main/endpoints.c, channels/chan_oss.c,
-	  res/parking/parking_bridge_features.c, apps/app_agent_pool.c,
-	  main/channel.c, channels/chan_misdn.c, channels/chan_skinny.c,
-	  pbx/pbx_realtime.c, channels/chan_alsa.c, main/stasis_channels.c,
-	  channels/chan_nbs.c: Reverting r403311. It's causing ARI tests to
-	  hang. ........ Merged revisions 403398 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/stasis/control.c: ari: Fix deadlock problem with functions
-	  that use autoservice. The code for getting channel variables from
-	  ARI assumed that you needed to lock the channel in order to
-	  properly execute functions and read channel variables.
-	  Apparently, this is not the case, since any dialplan function
-	  that puts the channel into autoservice deadlocks when attempting
-	  to remove the channel from autoservice. ........ Merged revisions
-	  403342 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /: Multiple revisions 403304,403310 ........ r403304 | dlee |
-	  2013-12-02 12:34:50 -0600 (Mon, 02 Dec 2013) | 1 line Fixed the
-	  filename for the ari.conf docs ........ r403310 | file |
-	  2013-12-03 10:32:12 -0600 (Tue, 03 Dec 2013) | 5 lines Revert
-	  revision 403304: Fixed the filename for the ari.conf docs The
-	  changed value refers to the name of the module. The name of the
-	  configuration file is specified in the configFile section.
-	  ........ Merged revisions 403304,403310 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-04 21:42 +0000 [r403378]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip_registrar.c: res_pjsip_registrar: undefined
-	  function pointer symbol Used a static wrapper around the
-	  offending function to alleviate the issue. Reported by: rmudgett
-	  ........ Merged revisions 403377 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-04 20:54 +0000 [r403365]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_t38.c, /: res_pjsip_t38: Don't pass T.38 control
-	  frames through to other hooks. This crept up during gateway
-	  testing where the gateway would receive the request to negotiate
-	  and assume it came from the remote side, causing the gateway
-	  state machine to go a little, to a use a technical term, "wonky".
-	  ........ Merged revisions 403364 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-04 18:41 +0000 [r403350]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip.c: Initialize the hash value argument to
-	  pj_hash_get() to 0. Passing a non-zero value causes PJLIB to use
-	  the given input as the hash value. Passing zero causes the
-	  parameter to become an output parameter that receives the hash
-	  value that was computed based on the given key. This change
-	  essentially makes ast_sip_dict_get() properly retrieve the
-	  desired value. ........ Merged revisions 403349 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-03 18:01 +0000 [r403330]  Joshua Colp <jcolp at digium.com>
+	  revisions 355998 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, configure, include/asterisk/autoconfig.h.in, configure.ac,
-	  res/res_pjsip_session.c: res_pjsip_session: Add support for
-	  PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE flag. Newer versions of PJSIP
-	  have changed to using a flag for the
-	  PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE instead of a define. This adds
-	  a configure check to detect the presence of the flag and use it
-	  if found. ........ Merged revisions 403329 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-03 17:35 +0000 [r403327]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/sorcery.h, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip_registrar_expire.c, res/res_pjsip/pjsip_options.c,
-	  tests/test_sorcery.c, include/asterisk/bucket.h, main/sorcery.c,
-	  /, main/bucket.c: sorcery, bucket: Change observer remove calls
-	  to take const callbacks struct. * Make
-	  ast_sorcery_observer_remove() accept a const callbacks struct. *
-	  Make ast_sorcery_observer_remove() tolerant of the sorcery
-	  parameter being NULL. Now it can be called within a module unload
-	  routine if the sorcery initialization fails. * Fix
-	  ast_sorcery_observer_add() to fail if the container link fails.
-	  ........ Merged revisions 403324 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-03 17:07 +0000 [r403314]  Mark Michelson <mmichelson at digium.com>
-
-	* channels/chan_nbs.c, main/bridge_channel.c, res/res_stasis.c,
-	  channels/chan_pjsip.c, res/parking/parking_manager.c,
-	  apps/app_voicemail.c, channels/chan_unistim.c,
-	  channels/chan_vpb.cc, addons/chan_ooh323.c, /,
-	  include/asterisk/aoc.h, apps/app_meetme.c, main/bridge.c,
-	  apps/app_userevent.c, channels/chan_gtalk.c,
-	  channels/chan_iax2.c, main/endpoints.c, main/stasis_bridges.c,
-	  main/channel.c, channels/chan_phone.c, channels/chan_dahdi.c,
-	  main/dial.c, channels/sig_analog.c, channels/chan_skinny.c,
-	  res/res_agi.c, channels/chan_motif.c, pbx/pbx_realtime.c,
-	  channels/chan_alsa.c, main/stasis_channels.c,
-	  apps/app_confbridge.c, addons/chan_mobile.c, tests/test_cdr.c,
-	  res/res_pjsip_refer.c, channels/chan_mgcp.c, apps/app_dial.c,
-	  main/pbx.c, channels/chan_sip.c, main/pickup.c,
-	  funcs/func_timeout.c, tests/test_stasis_channels.c,
-	  main/core_unreal.c, include/asterisk/stasis_bridges.h,
-	  apps/app_disa.c, include/asterisk/channel.h, main/core_local.c,
-	  include/asterisk/channelstate.h, channels/chan_console.c,
-	  main/cel.c, apps/app_queue.c, channels/sig_pri.c,
-	  channels/chan_oss.c, res/parking/parking_bridge_features.c,
-	  apps/app_agent_pool.c, channels/chan_jingle.c,
-	  channels/chan_misdn.c, include/asterisk/stasis_channels.h,
-	  channels/chan_h323.c, tests/test_cel.c: Add channel locking for
-	  channel snapshot creation. This adds channel locks around calls
-	  to create channel snapshots as well as other functions which
-	  operate on a channel and then end up creating a channel snapshot.
-	  Functions that expect the channel to be locked prior to being
-	  called have had their documentation updated to indicate such.
-	  ........ Merged revisions 403311 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-03 16:39 +0000 [r403313]  Joshua Colp <jcolp at digium.com>
-
-	* main/media_index.c, /: media_index: Make media indexing tolerable
-	  of bad symlinks. Media indexing will now skip over files and
-	  directories that stat will not return information about. This can
-	  occur under normal conditions when a symbolic link points to a
-	  location that no longer exists. ........ Merged revisions 403312
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-02 18:12 +0000 [r403292]  Alexandr Anikin <may at telecom-service.ru>
-
-	* addons/chan_ooh323.c, /: Check and reject non-digits e164 values
-	  on peers and general sections in ooh323.conf Regenerate e164
-	  endpoint list on reload ooh323 (issue ASTERISK-22901) Reported
-	  by: Cyril CONSTANTIN Patches: ASTERISK-22901.patch ........
-	  Merged revisions 403288 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403290 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-12-01 21:13 +0000 [r403257-403272]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_session.c: res_pjsip_session: Apply fromuser and
-	  fromdomain to all requests as documented. ........ Merged
-	  revisions 403271 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_t38.c, /: res_pjsip_t38: Add the framehook to the
-	  channel only on first INVITE. The check for determining whether
-	  the T.38 framehook should be added to the channel or not has now
-	  been changed to guarantee adding only occurs on the first
-	  incoming or outgoing INVITE. ........ Merged revisions 403258
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip/security_events.c, res/res_pjsip/pjsip_options.c,
-	  res/res_pjsip.c, res/res_pjsip_transport_websocket.c,
-	  include/asterisk/res_pjsip.h, /, res/res_pjsip/location.c:
-	  res_pjsip_transport_websocket: Fix security events and simplify
-	  implementation. Transport type determination for security events
-	  has been simplified to use the type present on the message itself
-	  instead of searching through configured transports to find the
-	  transport used. The actual WebSocket transport has also been
-	  simplified. It now leverages the existing PJSIP transport manager
-	  for finding the active WebSocket transport for outgoing messages.
-	  This removes the need for res_pjsip_transport_websocket to store
-	  a mapping itself. (closes issue ASTERISK-22897) Reported by: Max
-	  E. Reyes Vera J. Review: https://reviewboard.asterisk.org/r/3036/
-	  ........ Merged revisions 403256 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-30 14:12 +0000 [r403241]  Joshua Colp <jcolp at digium.com>
-
-	* res/ari/ari_model_validators.h, rest-api/api-docs/events.json, /,
-	  res/ari/ari_model_validators.c: res_ari: Add Recording events to
-	  the validator. ........ Merged revisions 403240 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-28 02:12 +0000 [r403208-403224]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, /: res_pjsip_sdp_rtp: Don't produce an
-	  invalid media stream with no formats. Depending on configuration
-	  it was possible for a media stream to be created without any
-	  media formats. The produced SDP would fail internal validation
-	  and cause a crash. The code will now no longer add media streams
-	  with no formats to the SDP, allowing it to pass validation and
-	  work. (closes issue ASTERISK-22858) Reported by: Anthony Messina
-	  ........ Merged revisions 403223 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_header_funcs.c, /: res_pjsip_header_funcs: Don't
-	  add headers to re-INVITEs. When sending a re-INVITE to an
-	  endpoint it was possible for received headers to be added as well
-	  (since they are stored for retrieval using the PJSIP_HEADER
-	  dialplan function). This caused a broken (and potentially large)
-	  SIP INVITE to be produced and sent. This changes the module so it
-	  will no longer add headers to re-INVITEs. (closes issue
-	  ASTERISK-22882) Reported by: David M. Lee ........ Merged
-	  revisions 403221 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_playback.c, /: res_stasis_playback: Add 'number',
-	  'digits', and 'characters' URI scheme implementations. This
-	  change adds new URI scheme implementations for playing numbers,
-	  digits, and characters. This is done as part of the normal
-	  playback mechanism and can be used with queueing to create a
-	  combined sentence. Review:
-	  https://reviewboard.asterisk.org/r/3028/ ........ Merged
-	  revisions 403209 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_configuration.c, res/res_pjsip.c,
-	  res/res_pjsip_session.c, include/asterisk/res_pjsip.h:
-	  res_pjsip_session: Add configurable behavior for redirects. The
-	  action taken when a redirect occurs is now configurable on a
-	  per-endpoint basis. The redirect can either be treated as a
-	  redirect to a local extension, to a URI that is dialed through
-	  the Asterisk core, or to a URI that is dialed within PJSIP
-	  itself. (closes issue ASTERISK-21710) Reported by: Matt Jordan
-	  Review: https://reviewboard.asterisk.org/r/2963/ ........ Merged
-	  revisions 403207 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-27 17:32 +0000 [r403192]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/astdb.h: astdb: Tweak some doxygen comments.
-
-2013-11-27 16:12 +0000 [r403180]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/pjsip_configuration.c: res_pjsip: Fix crash when
-	  reloading certain configurations. Certain options available that
-	  specify a SIP URI perform validation on the provided URI using
-	  the PJSIP URI parser. This operation requires that the thread
-	  executing it be registered with the PJLIB library. During reloads
-	  this was done on a thread which was NOT registered with it. This
-	  fixes the problem by creating a task which reloads the
-	  configuration on a PJSIP thread. (closes issue ASTERISK-22923)
-	  Reported by: Anthony Messina ........ Merged revisions 403179
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-27 15:48 +0000 [r403177]  David M. Lee <dlee at digium.com>
-
-	* res/res_ari_channels.c, include/asterisk/ari.h,
-	  rest-api-templates/param_parsing.mustache,
-	  include/asterisk/http.h, res/res_ari_recordings.c,
-	  res/res_ari_endpoints.c, main/http.c,
-	  rest-api-templates/swagger_model.py, res/res_ari_playbacks.c,
-	  res/res_ari_sounds.c, rest-api-templates/asterisk_processor.py,
-	  res/res_ari_bridges.c, tests/test_ari.c, res/res_ari.c, /,
-	  res/res_ari_device_states.c, res/res_ari_asterisk.c,
-	  rest-api-templates/res_ari_resource.c.mustache,
-	  res/res_ari_applications.c: ari:Add application/json parameter
-	  support The patch allows ARI to parse request parameters from an
-	  incoming JSON request body, instead of requiring the request to
-	  come in as query parameters (which is just weird for POST and
-	  DELETE) or form parameters (which is okay, but a bit asymmetric
-	  given that all of our responses are JSON). For any operation that
-	  does _not_ have a parameter defined of type body (i.e.
-	  "paramType": "body" in the API declaration), if a request
-	  provides a request body with a Content type of
-	  "application/json", the provided JSON document is parsed and
-	  searched for parameters. The expected fields in the provided JSON
-	  document should match the query parameters defined for the
-	  operation. If the parameter has 'allowMultiple' set, then the
-	  field in the JSON document may optionally be an array of values.
-	  (closes issue ASTERISK-22685) Review:
-	  https://reviewboard.asterisk.org/r/2994/
-
-2013-11-27 15:31 +0000 [r403161-403174]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/pjsip_configuration.c: res_pjsip: Update
-	  handling of some options to work with new option names. Some
-	  options (such as call_group and pickup_group) share the same
-	  configuration handler and decide what logic to use based on the
-	  name of the option. These handlers were not updated to check for
-	  the new option names and were treating the options as invalid.
-	  This change simply updates the handlers with the proper names of
-	  the options. (closes issue ASTERISK-22922) Reported by: Anthony
-	  Messina ........ Merged revisions 403173 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, configure, include/asterisk/autoconfig.h.in, configure.ac: Fix
-	  a configure issue with PJSIP transaction group lock detection.
-	  The configure check did not use the provided paths for pjproject
-	  if provided when looking for transaction group lock support.
-	  ........ Merged revisions 403160 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-23 17:48 +0000 [r403133-403135]  Kevin Harwell <kharwell at digium.com>
-
-	* res/ari.make, rest-api/api-docs/applications.json,
-	  res/ari/resource_device_states.h (added),
-	  include/asterisk/stasis_app_device_state.h (added),
-	  res/ari/resource_applications.h, res/res_stasis.c,
-	  include/asterisk/devicestate.h, rest-api/api-docs/events.json,
-	  res/res_stasis_device_state.exports.in (added), res/stasis/app.c,
-	  res/res_ari_device_states.c (added), /,
-	  include/asterisk/stasis_app.h, main/devicestate.c,
-	  res/stasis/app.h, rest-api/resources.json,
-	  res/res_stasis_device_state.c (added),
-	  res/ari/ari_model_validators.c, res/ari/ari_model_validators.h,
-	  res/ari/resource_device_states.c (added),
-	  rest-api/api-docs/deviceStates.json (added),
-	  rest-api-templates/ari.make.mustache: ARI: Implement device state
-	  API Created a data model and implemented functionality for an ARI
-	  device state resource. The following operations have been added
-	  that allow a user to manipulate an ARI controlled device:
-	  Create/Change the state of an ARI controlled device PUT
-	  /deviceStates/{deviceName}&{deviceState} Retrieve all ARI
-	  controlled devices GET /deviceStates Retrieve the current state
-	  of a device GET /deviceStates/{deviceName} Destroy a device-state
-	  controlled by ARI DELETE /deviceStates/{deviceName} The ARI
-	  controlled device must begin with 'Stasis:'. An example
-	  controlled device name would be Stasis:Example. A
-	  'DeviceStateChanged' event has also been added so that an
-	  application can subscribe and receive device change events. Any
-	  device state, ARI controlled or not, can be subscribed to. While
-	  adding the event, the underlying subscription control mechanism
-	  was refactored so that all current and future resource
-	  subscriptions would be the same. Each event resource must now
-	  register itself in order to be able to properly handle
-	  [un]subscribes. (issue ASTERISK-22838) Reported by: Matt Jordan
-	  Review: https://reviewboard.asterisk.org/r/3025/ ........ Merged
-	  revisions 403134 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_registrar.c, main/sorcery.c,
-	  include/asterisk/res_pjsip.h, include/asterisk/acl.h,
-	  res/res_pjsip/config_auth.c, include/asterisk/utils.h,
-	  res/res_pjsip.exports.in, /,
-	  res/res_pjsip_endpoint_identifier_ip.c, main/acl.c, main/utils.c,
-	  res/res_pjsip.c, res/res_pjsip_exten_state.c,
-	  include/asterisk/res_pjsip_pubsub.h, res/res_pjsip/location.c,
-	  res/res_pjsip_outbound_registration.c, res/res_pjsip_mwi.c,
-	  res/res_pjsip/pjsip_configuration.c, include/asterisk/sorcery.h,
-	  include/asterisk/strings.h,
-	  res/res_pjsip/include/res_pjsip_private.h,
-	  res/res_pjsip_pubsub.c, res/res_pjsip/config_transport.c:
-	  res_pjsip: AMI commands and events. Created the following AMI
-	  commands and corresponding events for res_pjsip:
-	  PJSIPShowEndpoints - Provides a listing of all pjsip endpoints
-	  and a few select attributes on each. Events: EndpointList - for
-	  each endpoint a few attributes. EndpointlistComplete - after all
-	  endpoints have been listed. PJSIPShowEndpoint - Provides a detail
-	  list of attributes for a specified endpoint. Events:
-	  EndpointDetail - attributes on an endpoint. AorDetail - raised
-	  for each AOR on an endpoint. AuthDetail - raised for each
-	  associated inbound and outbound auth TransportDetail - transport
-	  attributes. IdentifyDetail - attributes for the identify object
-	  associated with the endpoint. EndpointDetailComplete - last event
-	  raised after all detail events. PJSIPShowRegistrationsInbound -
-	  Provides a detail listing of all inbound registrations. Events:
-	  InboundRegistrationDetail - inbound registration attributes for
-	  each registration. InboundRegistrationDetailComplete - raised
-	  after all detail records have been listed.
-	  PJSIPShowRegistrationsOutbound - Provides a detail listing of all
-	  outbound registrations. Events: OutboundRegistrationDetail -
-	  outbound registration attributes for each registration.
-	  OutboundRegistrationDetailComplete - raised after all detail
-	  records have been listed. PJSIPShowSubscriptionsInbound - A
-	  detail listing of all inbound subscriptions and their attributes.
-	  Events: SubscriptionDetail - on each subscription detailed
-	  attributes SubscriptionDetailComplete - raised after all detail
-	  records have been listed. PJSIPShowSubscriptionsOutbound - A
-	  detail listing of all outboundbound subscriptions and their
-	  attributes. Events: SubscriptionDetail - on each subscription
-	  detailed attributes SubscriptionDetailComplete - raised after all
-	  detail records have been listed. (issue ASTERISK-22609) Reported
-	  by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/
-	  ........ Merged revisions 403131 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-23 12:52 +0000 [r403118-403120]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_stasis_playback.c, rest-api/api-docs/events.json, /,
-	  res/res_stasis_recording.c, res/ari/ari_model_validators.c,
-	  rest-api/api-docs/recordings.json,
-	  res/ari/ari_model_validators.h: ari: Add events for playback and
-	  recording. While there were events defined for playback and
-	  recording these were not actually sent. This change implements
-	  the to_json handlers which produces them. (closes issue
-	  ASTERISK-22710) Reported by: Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/3026/ ........ Merged
-	  revisions 403119 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_snoop.exports.in (added), /,
-	  include/asterisk/stasis_app_snoop.h (added),
-	  rest-api/api-docs/channels.json, res/res_stasis_snoop.c (added),
-	  main/audiohook.c, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, res/ari/resource_channels.h: ari: Add
-	  Snoop operation for spying/whispering on channels. The Snoop
-	  operation can be invoked on a channel to spy or whisper on it. It
-	  returns a channel that any channel operations can then be invoked
-	  on (such as record to do monitoring). (closes issue
-	  ASTERISK-22780) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/3003/ ........ Merged
-	  revisions 403117 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-23 00:22 +0000 [r403106]  Rusty Newton <rnewton at digium.com>
-
-	* apps/app_voicemail.c: app_voicemail: when forwarding a message,
-	  play vm-msgforwarded instead of vm-msgsaved In the last release
-	  of sounds, 1.4.25 we added a vm-msgforwarded prompt for various
-	  core languages. Now we use that prompt. (issue ASTERISK-21413)
-	  (closes issue ASTERISK-21413) Reported by: netwrkr Tested by:
-	  newtonr
-
-2013-11-22 23:57 +0000 [r403095]  Kinsey Moore <kmoore at digium.com>
-
-	* tests/test_stasis.c, /, tests/test_stasis_channels.c: Make sure
-	  unit tests compile This fixes the unit tests that were broken by
-	  r403069 and several functions requiring a new parameter for
-	  sanitization of JSON messages generated from object snapshots.
-	  ........ Merged revisions 403094 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-22 22:37 +0000 [r403083]  Kevin Harwell <kharwell at digium.com>
-
-	* /,
-	  contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py,
-	  res/res_pjsip/pjsip_configuration.c: res_pjsip: convert
-	  configuration settings names to snake case some more Updated the
-	  alembic script for pjsip. Also, the dtls config parsing stuff was
-	  expecting strings with no underscores, so removed the underscores
-	  from the option name before passing it to the parser. ........
-	  Merged revisions 403082 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-22 20:10 +0000 [r403070]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_stasis.c, main/stasis_endpoints.c,
-	  res/ari/resource_endpoints.c, main/rtp_engine.c, /,
-	  res/stasis/app.c, include/asterisk/stasis_bridges.h,
-	  include/asterisk/stasis.h, include/asterisk/stasis_app.h,
-	  main/stasis_bridges.c, res/ari/resource_bridges.c, main/json.c,
-	  main/stasis_message.c, include/asterisk/stasis_channels.h,
-	  main/stasis_channels.c, res/ari/resource_channels.c,
-	  include/asterisk/stasis_endpoints.h: ARI: Don't leak
-	  implementation details This change prevents channels used as
-	  implementation details from leaking out to ARI. It does this by
-	  preventing creation of JSON blobs of channel snapshots created
-	  from those channels and sanitizing JSON blobs of bridge snapshots
-	  as they are created. This introduces a framework for excluding
-	  information from output targeted at Stasis applications on a
-	  consumer-by-consumer basis using channel sanitization callbacks
-	  which could be extended to bridges or endpoints if necessary.
-	  This prevents unhelpful error messages from being generated by
-	  ast_json_pack. This also corrects a bug where BridgeCreated
-	  events would not be created. (closes issue ASTERISK-22744)
-	  Review: https://reviewboard.asterisk.org/r/2987/ Reported by:
-	  David M. Lee ........ Merged revisions 403069 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-22 17:27 +0000 [r403051]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_acl.c, res/res_pjsip.c,
-	  res/res_pjsip/config_transport.c, res/res_pjsip/config_global.c,
-	  /, configs/pjsip.conf.sample, res/res_pjsip/config_system.c,
-	  contrib/scripts/sip_to_pjsip/sip_to_pjsip.py,
-	  res/res_pjsip/pjsip_configuration.c: res_pjsip: convert
-	  configuration settings names to snake case Renamed, where
-	  appropriate, the configuration options for chan/res_pjsip to use
-	  snake case (compound words separated by an underscore). For
-	  example, faxdetect will become fax_detect, recordofffeature will
-	  become record_off_feature, etc... Review:
-	  https://reviewboard.asterisk.org/r/3002/ ........ Merged
-	  revisions 403022 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-22 17:12 +0000 [r403017]  Joshua Colp <jcolp at digium.com>
+	* channels/chan_dahdi.c, /: This was a LOG_NOTICE, so roll it back.
+	  ........ Merged revisions 355952 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355953 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/translate.c: translate: Move freeing of frame to after it
-	  is used. When translating from one format to another it is
-	  possible to inform the translation function that the source frame
-	  should be freed. This was previously done immediately but shortly
-	  afterwards the frame that was freed was accessed and used again.
-	  This change moves code around a bit so that the frame is now
-	  freed after it has been completely used. (closes issue
-	  ASTERISK-22788) Reported by: Corey Farrell Patches:
-	  translate-access-after-free-11up.patch uploaded by coreyfarrell
-	  (license 5909) translate-access-after-free-1.8.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 403014 from
+	* channels/chan_dahdi.c, /: Change some debug messages from
+	  LOG_DEBUG to ast_debug. ........ Merged revisions 355949 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 403015 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 403016 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-22 16:43 +0000 [r403013]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_directed_pickup.c, CHANGES: PickupChan: Add ability to
-	  specify channel uniqueids as well as channel names. * Made
-	  PickupChan() search by channel uniqueids if the search could not
-	  find a channel by name. * Ensured PickupChan() never considers
-	  the picking channel for pickup. * Made PickupChan() option p use
-	  a common search by name routine. The original search was
-	  erroneously case sensitive. (issue AFS-42) Review:
-	  https://reviewboard.asterisk.org/r/3017/
-
-2013-11-21 22:38 +0000 [r402995]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES, apps/app_directory.c: app_directory: Set variable
-	  indicating reason directory exited By the time the directory
-	  application exits, a channel variable DIRECTORY_RESULT will be
-	  set for the channel that invoked it which can be used to
-	  determine the reason for exit. The changes log and the
-	  app_directory documentation contain specific details about each
-	  of the possible values for DIRECTORY_RESULT. Review:
-	  https://reviewboard.asterisk.org/r/3016/
-
-2013-11-21 22:36 +0000 [r402982-402994]  David M. Lee <dlee at digium.com>
-
-	* rest-api-templates/ari_resource.c.mustache, /,
-	  rest-api-templates/res_ari_resource.c.mustache: ari: Fix #include
-	  to match generated headers for snakeCase resource files ........
-	  Merged revisions 402993 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* rest-api-templates/make_ari_stubs.py, /: ari: Fix generators for
-	  resources with camelCase names. For the new deviceState resource,
-	  we need to properly generate device_state.[ch] files. ........
-	  Merged revisions 402981 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-21 19:22 +0000 [r402969]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_session.c, /: res_pjsip_session: Fix memory leak of
-	  direct media format capabilities The direct media format
-	  capabilities are always allocated in ast_sip_session_alloc and
-	  were not freed in the session destructor. Whoops. (This being the
-	  third whoops caught by Scott and Nitesh's valgrind work for the
-	  Asterisk Test Suite. Nifty!) ........ Merged revisions 402968
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-21 19:09 +0000 [r402945-402957]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/app.h, /: voicemail: Fixup some doxygen
-	  comments. ........ Merged revisions 402956 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/bucket.c: bucket: Fix scheme ref leak in
-	  __ast_bucket_scheme_register(). ........ Merged revisions 402944
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-21 17:53 +0000 [r402942-402943]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, /: res_pjsip_sdp_rtp: Fix use of
-	  uninitialized value in PJSIP In PJMEDIA,
-	  pjmedia_sdp_rtpmap_to_attr will attempt to use the string
-	  rtpmap.param regardless of its length value. Simply setting the
-	  length to 0 does not prevent the garbage on the stack in
-	  rtpmap.param.ptr from being formatted in a sprintf call. This
-	  patch initializes the string to NULL so that at the very least,
-	  something is provided to the function that is predictable.
-	  ........ Merged revisions 402941 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_mwi.c: res_pjsip_mwi: Fix memory leak of MWI
-	  subscriptions container This patch fixes a reference counting
-	  memory leak on the ao2_container created as part of
-	  create_mwi_subscriptions. When we create the container in this
-	  routine, the intent is to hand lifetime ownership over to the
-	  global container unsolicited_mwi. When
-	  ao2_global_obj_replace_unref is called, the reference count on
-	  mwi_subscriptions (the container) will be bumped by 1; however,
-	  the function does not decrement the reference count on
-	  mwi_subscriptions when this occurs. This will prevent the
-	  container from being fully disposed of when Asterisk exits (or on
-	  any subsequent call to this operation, such as during a reload).
-	  ........ Merged revisions 402940 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-21 15:57 +0000 [r402928-402929]  David M. Lee <dlee at digium.com>
-
-	* res/res_stasis.c, /: stasis: Fixed scoping problem with bridge
-	  tracking. ........ Merged revisions 402817 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_channels.c, res/res_ari_channels.c,
-	  res/ari/resource_channels.h, /, res/stasis/control.c,
-	  include/asterisk/stasis_app.h, rest-api/api-docs/channels.json:
-	  ari: Add silence generator controls This patch adds the ability
-	  to start a silence generator on a channel via ARI. This generator
-	  will play silence on the channel (avoiding audio timeouts on the
-	  peer) until it is stopped, or some other media operation is
-	  started (like playing media, starting music on hold, etc.).
-	  (closes issue ASTERISK-22514) Review:
-	  https://reviewboard.asterisk.org/r/3019/ ........ Merged
-	  revisions 402926 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-19 23:17 +0000 [r402892]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_caller_id.c: res_pjsip_caller_id: Don't
-	  overwrite user portion of the From header when fromuser is set.
-	  The fromuser option is used to explicitly set the user within the
-	  From header. The res_pjsip_caller_id module did not take this
-	  setting into account when determining if the From header could be
-	  modified or not. (closes issue ASTERISK-22866) Reported by:
-	  Anthony Messina ........ Merged revisions 402891 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-16 13:51 +0000 [r402865]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip/pjsip_distributor.c, /, configure,
-	  include/asterisk/autoconfig.h.in, configure.ac: res_pjsip: Add
-	  support for building against pjproject with SIP transaction group
-	  lock support. SIP transaction group lock support has been
-	  backported into our pjproject. Since the code now internally uses
-	  a group lock the code is now changed to unlock it if present.
-	  Note that the act of finding the transaction is what actually
-	  returns it locked. For further information about group locks
-	  check out the wiki page at:
-	  http://trac.pjsip.org/repos/wiki/Group_Lock (issue
-	  ASTERISK-22818) Reported by: Matt Jordan ........ Merged
-	  revisions 402864 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-15 22:38 +0000 [r402854]  Jonathan Rose <jrose at digium.com>
-
-	* apps/app_confbridge.c, CHANGES,
-	  apps/confbridge/conf_config_parser.c,
-	  configs/confbridge.conf.sample,
-	  apps/confbridge/include/confbridge.h: Confbridge: Add option to
-	  review the recording similar to announce_join_leave Review:
-	  https://reviewboard.asterisk.org/r/3008/
-
-2013-11-15 14:37 +0000 [r402839]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/cel.c: CEL: Fix crash when using CELGenUserEvent This
-	  fixes a crash when CELGenUserEvent is called from the dialplan
-	  while CEL is disabled. Currently, CEL does not create its topics
-	  and forwards if it is not enabled and external entities may
-	  depend on these topics blindly since they should always be
-	  available. This patch breaks up route creation and topic/forward
-	  creation such that the CEL topics and forwards will always exist
-	  while the router and its associated routes will be torn down and
-	  recreated as necessary. (closes issue ASTERISK-22799) Review:
-	  https://reviewboard.asterisk.org/r/3010/ Reported by: Matt Jordan
-	  ........ Merged revisions 402838 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-14 21:36 +0000 [r402820-402829]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_directed_pickup.c: Pickup: Pickup() and PickupChan()
-	  parameter parsing improvements. * Made Pickup() and PickupChan()
-	  tollerate empty pickup values. i.e., You can now have
-	  Pickup(&&exten at context). * Made PickupChan() use the standard
-	  option flag parsing code.
-
-	* apps/app_directed_pickup.c: Pickup: Ensure using PICKUPMARK never
-	  considers the picking channel.
-
-2013-11-14 20:32 +0000 [r402819]  Jonathan Rose <jrose at digium.com>
-
-	* CHANGES, main/pbx.c, apps/app_sayunixtime.c: Say: If
-	  SAY_DTMF_INTERRUPT is set to an ast_true value, jump on DTMF
-	  Similar to how background works, if a say application is called
-	  with this variable set to 'true', 'yes', 'on', etc. then using
-	  DTMF while the say action is in progress will result in the
-	  channel jumping to that extension in the dialplan. Review:
-	  https://reviewboard.asterisk.org/r/3011/
-
-2013-11-13 23:11 +0000 [r402805]  Joshua Colp <jcolp at digium.com>
-
-	* rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, res/ari/resource_channels.h, /,
-	  res/stasis/control.c, include/asterisk/stasis_app.h:
-	  res_ari_channels: Add the ability to stop locally generated
-	  ringing on a channel. Using the 'ring' operation it is possible
-	  to start locally generated ringback if the channel is answered.
-	  This change adds the ability to stop it by using DELETE. ........
-	  Merged revisions 402804 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 23:17 +0000 [r402788-402795]  Kevin Harwell <kharwell at digium.com>
-
-	* res/ari/resource_endpoints.c, /: ari endpoints: GET
-	  /ari/endpoints/{invalid-tech} should return a 404 Was returning a
-	  404 on a valid technology with an empty list of endpoints. Now
-	  checking against the channel tech to make sure the tech itself is
-	  valid and not just an empty list of endpoints. (issue
-	  ASTERISK-22803) Reported by: David M. Lee ........ Merged
-	  revisions 402793 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* rest-api/api-docs/endpoints.json, res/ari/resource_endpoints.c,
-	  /, res/res_ari_endpoints.c: ari endpoints: GET
-	  /ari/endpoints/{invalid-tech} should return a 404 Implementation
-	  listing endpoints by technology returned an empty array if no
-	  matching endpoints were found. Fixed so a "404 Not Found" will be
-	  returned instead. (closes issue ASTERISK-22803) Reported by:
-	  David M. Lee ........ Merged revisions 402787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 19:38 +0000 [r402768-402778]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/channel.c: Switch to a scoped lock to avoid missing
-	  unlocks in failure returns. ........ Merged revisions 402769 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/channel.c, /: Move a NULL check to a place that makes more
-	  sense. Two variables were being checked for NULLity immediately
-	  after being declared NULL. I moved the NULL check until after the
-	  variables are allocated. This allows for the "channelvars" option
-	  in manager.conf to work as intended again. ........ Merged
-	  revisions 402767 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 16:49 +0000 [r402758]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_messaging.c, res/res_pjsip_header_funcs.c, /:
-	  pjsip_messaging, pjsip_header_funcs: Crashes due to NULL pointer
-	  dereferences Both res_pjsip_messaging and res_pjsip_header_funcs
-	  were causing asterisk to crash because they were trying to
-	  dereference a NULL pointer. In the case of res_pjsip_messaging it
-	  was attempting to "print" a contact header that did not exist. In
-	  fact contact headers should not be part of a SIP MESSAGE, so the
-	  offending code was simply removed. In the case of
-	  res_pjsip_header_funcs a null private channel tech was being
-	  passed to the function and then later dereferenced. Added null
-	  checks (and error logging) to the read/write function handlers to
-	  guard against crashing. (closes issue ASTERISK-22821) Reported
-	  by: Anthony Messina ........ Merged revisions 402757 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 16:34 +0000 [r402756]  Kinsey Moore <kmoore at digium.com>
-
-	* /, apps/app_celgenuserevent.c: CELGenUserEvent: Fix error message
-	  from ast_json_pack This prevents NULL from being passed into an
-	  ast_json_pack call when no extra information is passed to the
-	  application which prevents an error message about NULL arguments
-	  from being generated. ........ Merged revisions 402755 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 15:27 +0000 [r402741]  David M. Lee <dlee at digium.com>
-
-	* res/ari/ari_model_validators.h, rest-api/api-docs/events.json, /:
-	  Fixed a typ. ........ Merged revisions 402738 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-12 15:03 +0000 [r402711]  Kinsey Moore <kmoore at digium.com>
+	  revisions 355950 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_dahdi.c, /: chan_dahdi: Fix crash during caller ID
-	  read Asterisk will sometimes core dump during caller id read on
-	  analog channels due to a negative return value from the read() in
-	  my_get_callerid that slips through as a negative length argument
-	  to callerid_feed() if the errno returned by DAHDI is ELAST. This
-	  change ensures that the negative return is treated properly even
-	  when it is ELAST. (closes issue ASTERISK-22746) Reported by:
-	  Michael Walton Patches: chan_dahdi_cid_crash_fix.r401410.patch
-	  uploaded by Michael Walton (License 6502) ........ Merged
-	  revisions 402708 from
+	* /, channels/chan_iax2.c: Add some boilerplate documentation for
+	  IAXVAR and IAXPEER. ........ Merged revisions 355904 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 402709 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402710 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 355905 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-11-11 20:28 +0000 [r402698]  Jonathan Rose <jrose at digium.com>
+	* /, channels/chan_iax2.c: Set the length of the ast_sockaddr, so
+	  that we can set it's port later. Without this, the call to
+	  ast_sockaddr_set_port a few lines later is a noop. ........
+	  Merged revisions 355901 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355902 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-18 08:02 +0000 [r355852]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* channels/sig_pri.h, channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/sig_ss7.h, /, channels/sig_analog.h, channels/sig_pri.c,
+	  channels/sig_ss7.c: push 'outgoing' flag from sig_XXX up to
+	  chan_dahdi 'p->outgoing' in chan_dahdi and sig_analog wern't kept
+	  in sync, particulary FXS ast_hangup didn't clear the 'outgoing'
+	  flag. sig_pri and sig_ss7 were keeping 'outgoing' flag insync.
+	  Now provides a callback for all the low level sig_XXX modules.
+	  (issue ASTERISK-19316) alecdavis (license 585) Reported by:
+	  Jeremy Pepper Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1747/ ........ Merged
+	  revisions 355850 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355851 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_confbridge.c: Confbridge: add test events for dynamic
-	  menus test Adds a couple of test events for conference menu
-	  actions so that it's easy to discern when those menu actions have
-	  been triggered. (issue ASTERISK-22760) Reported by: Matt Jordan
-	  Review: https://reviewboard.asterisk.org/r/2999/
+2012-02-17 22:03 +0000 [r355795]  Sean Bright <sean at malleable.com>
 
-2013-11-11 19:31 +0000 [r402688]  Mark Michelson <mmichelson at digium.com>
+	* configs/iax.conf.sample, /, channels/chan_iax2.c: Don't allow
+	  trunkfreq to be greater than 1000ms. ........ Merged revisions
+	  355793 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 355794 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_confbridge.c, /: Get rid of some inaccurate comments.
-	  I'm doing some unrelated work in app_confbridge and finding these
-	  "invalid pin" comments to be annoying. Get out! ........ Merged
-	  revisions 402686 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402687 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-02-17 19:56 +0000 [r355749]  Tilghman Lesher <tilghman at meg.abyt.es>
 
-2013-11-11 15:37 +0000 [r402648]  Kinsey Moore <kmoore at digium.com>
+	* main/asterisk.c: Non-verbose output should always go to the
+	  remote console, regardless of the previous level.
 
-	* /, apps/app_queue.c: app_queue: Honor penalty limits of 0 In the
-	  current app_queue code from 1.8 up to trunk the upper and lower
-	  penalties can be set to 0 but the value is interpreted to be
-	  disabled instead of actually setting limits. This is especially
-	  evident if min and max limits are set to 0 and members with
-	  penalties of 0 and 1 are in the queue since the member with
-	  penalty 1 will still receive calls. This patch adjusts the
-	  special disabled value to be INT_MAX instead of 0. (closes issue
-	  ASTERISK-20862) Review: https://reviewboard.asterisk.org/r/2995/
-	  Reported by: Schmooze Com ........ Merged revisions 402645 from
+2012-02-17 19:35 +0000 [r355748]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: Pass the correct value to
+	  ast_timer_set_rate() for IAX2 trunking. IAX2 uses the trunkfreq
+	  variable to determine how often to send trunk packets, but this
+	  value is in milliseconds while ast_timer_set_rate() expects the
+	  rate argument to be ticks per second. So we divide 1000 by
+	  trunkfreq and pass that in instead. With a default of 20ms, this
+	  change makes IAX2 send trunk packets every 20ms instead of every
+	  50ms. Tracked down by myself and Bob Wienholt. ........ Merged
+	  revisions 355746 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355747 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-17 19:22 +0000 [r355745]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Fix regressions with regards to route-set
+	  creation on early dialogs. This fixes two main issues: 1.
+	  Asterisk would send a CANCEL to the route created by the
+	  provisional response instead of using the same destination it did
+	  in the initial INVITE. 2. If a new route set arrives in a 200 OK
+	  than was in the 1XX response (perfectly possible if our outbound
+	  INVITE gets forked), then the route set in the 200 OK needs to
+	  overwrite the route set in the 1XX response. (closes issue
+	  ASTERISK-19358) Reported by: Karsten Wemheuer Tested by: Karsten
+	  Wemheuer patches: ASTERISK-19358.patch uploaded by Mark Michelson
+	  (license 5049) ASTERISK-19358.patch uploaded by Stefan Schmidt
+	  (license 6034) Review: https://reviewboard.asterisk.org/r/1749
+	  ........ Merged revisions 355732 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 402646 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402647 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 355733 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-11-08 23:07 +0000 [r402607]  Scott Griepentrog <sgriepentrog at digium.com>
+2012-02-16 22:00 +0000 [r355667]  Paul Belanger <paul.belanger at polybeacon.com>
 
-	* /, channels/chan_sip.c, channels/sip/include/sip.h: chan_sip:
-	  keep same local (from) tag for outgoing register requests For
-	  outbound register requests the tag on the From line was updated
-	  every 20 seconds prior to a successful registration and also once
-	  for each registration renewal. That behavior can possibly cause
-	  the registration to be denied because of the different tag, and
-	  is not aligned with the intention of RFC 3261 8.1.3.5 "...
-	  request constitutes a new transaction and SHOULD have the same
-	  value of the Call-ID, To, and From of the previous request...".
-	  This updates chan_sip to have a field to keep the local tag in
-	  the registration structure and use that tag for registration
-	  requests where the callid is also unchanged. (closes issue
-	  ASTERISK-12117) Reported by: Pawel Pierscionek Review:
-	  https://reviewboard.asterisk.org/r/2988/ ........ Merged
-	  revisions 402604 from
+	* apps/app_rpt.c: Fix channel opaquification for app_rpt
+
+2012-02-16 20:03 +0000 [r355624]  Sean Bright <sean at malleable.com>
+
+	* /, main/audiohook.c: Revert a change to
+	  audio_audiohook_write_list that had no affect. When I made this
+	  change initially, I was under the false impression that the
+	  audiohooks structure remained on the channel after all of the
+	  hooks had been detached. This is not the case, ast ast_read takes
+	  care of removing the audiohooks structure if the lists are empty.
+	  ........ Merged revisions 355622 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 402605 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402606 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 20:37 +0000 [r402595]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_stasis.c: res_stasis.c: Fix locking issues with the
-	  app_bridge_moh container. * Fix unlinking from the
-	  app_bridges_moh container in remove_bridge_moh() without a lock
-	  under normal circumstances. * Made check
-	  ast_bridge_set_after_callback() return value in
-	  bridge_moh_create() to handle failure. * Fixed SCOPED_AO2LOCK()
-	  locking over too much scope in stasis_app_bridge_moh_channel()
-	  and stasis_app_bridge_moh_stop(). * Fixed unusual usage of
-	  ao2_unlink_flag() in control_unlink(). * Fixed orphaned bridge
-	  from off nominal path in stasis_app_bridge_create(). * Fixed
-	  strange construct in stasis_app_unsubscribe(). From a bad merge?
-	  * Made load_module() cleanup on failure. Review:
-	  https://reviewboard.asterisk.org/r/2962/ ........ Merged
-	  revisions 402593 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 19:33 +0000 [r402585]  Jonathan Rose <jrose at digium.com>
-
-	* /, main/security_events.c, configs/manager.conf.sample, CHANGES,
-	  include/asterisk/manager.h, main/manager.c: security_events: Push
-	  out security events over AMI events Security Events will now be
-	  written to any listener of the new 'security' class Review:
-	  https://reviewboard.asterisk.org/r/2998/ ........ Merged
-	  revisions 402584 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 19:22 +0000 [r402583]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip.c, /: Clarify an ambiguous error message. ........
-	  Merged revisions 402582 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 18:53 +0000 [r402571-402572]  David M. Lee <dlee at digium.com>
-
-	* /, res/res_pjsip/config_system.c: res_pjsip: Print a helpful
-	  error message if sorcery registration fails ........ Merged
-	  revisions 402570 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_playbacks.h, /: Changes from make ari-stubs
-	  after r402560 ........ Merged revisions 402561 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 17:59 +0000 [r402562]  Kevin Harwell <kharwell at digium.com>
-
-	* rest-api/resources.json, res/ari/resource_playback.h (removed),
-	  res/res_ari_playbacks.c (added), res/ari/resource_playbacks.h
-	  (added), /, res/ari.make, rest-api/api-docs/playback.json
-	  (removed), res/ari/resource_playback.c (removed),
-	  res/res_ari_playback.c (removed),
-	  rest-api/api-docs/playbacks.json (added),
-	  res/ari/resource_playbacks.c (added): ARI playback: Rename ARI
-	  Playback to Playbacks Before playback was the only non plural
-	  resource. It has been renamed to playbacks for consistency.
-	  (closes issue ASTERISK-22737) Reported by: Paul Belanger ........
-	  Merged revisions 402560 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 17:29 +0000 [r402557]  David M. Lee <dlee at digium.com>
-
-	* res/res_ari.c, main/manager.c, /, main/http.c: ari: Add
-	  application/x-www-form-urlencoded parameter support ARI POST
-	  calls only accept parameters via the URL's query string. While
-	  this works, it's atypical for HTTP API's in general, and
-	  specifically frowned upon with RESTful API's. This patch adds
-	  parsing for application/x-www-form-urlencoded request bodies if
-	  they are sent in with the request. Any variables parsed this way
-	  are prepended to the variable list supplied by the query string.
-	  (closes issue ASTERISK-22743) Review:
-	  https://reviewboard.asterisk.org/r/2986/ ........ Merged
-	  revisions 402555 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-08 14:58 +0000 [r402546]  Kevin Harwell <kharwell at digium.com>
-
-	* apps/app_dahdiras.c, utils/extconf.c, main/asterisk.c:
-	  app_dahdiras: Use waitpid instead of wait4. Several places in the
-	  code were using wait4 while other places were using waitpid. This
-	  change makes all places use waitpid in order to make things more
-	  consistent and since the 'rusage' object passed in/out of wait4
-	  was never used. (closes issue ASTERISK-22557) Reported by:
-	  YvesGael Patches: asterisk-11.5.1-wait4.patch uploaded by hurdman
-	  (license 6537)
-
-2013-11-07 23:42 +0000 [r402538]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_authenticator_digest.c, /: PJSIP: Improve error
-	  handling in digest authenticator Previously, regardless of
-	  whether failure to authenticate was due to lacking any
-	  authentication or actually failing authentication, the Digest
-	  Authenticator would simply return that a challenge was still
-	  needed. It will continue to do that when no authentication
-	  information is in the received SIP digest, but when
-	  authentication information is present and does not pass
-	  authentication, that will be treated as an authentication error.
-	  This is to ensure that PJSIP will issue security events indicated
-	  failed auths. ........ Merged revisions 402537 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-07 21:10 +0000 [r402529]  David M. Lee <dlee at digium.com>
-
-	* res/ari/resource_applications.c, res/ari/resource_playback.c,
-	  rest-api/api-docs/channels.json, res/ari/resource_applications.h,
-	  res/ari/resource_channels.c, res/ari/resource_playback.h,
-	  rest-api/api-docs/recordings.json, res/ari/resource_recordings.c,
-	  rest-api-templates/ari_resource.c.mustache,
-	  rest-api-templates/asterisk_processor.py,
-	  res/ari/resource_channels.h, rest-api/api-docs/endpoints.json,
-	  res/ari/resource_endpoints.c, res/ari/resource_recordings.h,
-	  res/ari/resource_events.c, res/res_ari_playback.c,
-	  res/res_ari_applications.c, res/ari/resource_endpoints.h,
-	  res/ari/resource_events.h, rest-api/api-docs/sounds.json,
-	  res/ari/resource_sounds.c, res/res_ari_channels.c,
-	  rest-api/api-docs/bridges.json, res/ari/resource_bridges.c,
-	  res/ari/resource_sounds.h, res/res_ari_recordings.c,
-	  res/ari/resource_bridges.h, rest-api/api-docs/asterisk.json,
-	  res/ari/resource_asterisk.c, res/res_ari_endpoints.c,
-	  rest-api/api-docs/applications.json,
-	  rest-api/api-docs/playback.json, res/res_ari_events.c,
-	  res/ari/resource_asterisk.h, rest-api-templates/swagger_model.py,
-	  res/res_ari_sounds.c, res/res_ari_bridges.c, /,
-	  rest-api-templates/ari_resource.h.mustache,
-	  rest-api-templates/rest_handler.mustache, res/res_ari_asterisk.c,
-	  rest-api-templates/res_ari_resource.c.mustache: ari: User better
-	  nicknames for ARI operations While working on building client
-	  libraries from the Swagger API, I noticed a problem with the
-	  nicknames. channel.deleteChannel() channel.answerChannel()
-	  channel.muteChannel() Etc. We put the object name in the nickname
-	  (since we were generating C code), but it makes OO generators
-	  redundant. This patch makes the nicknames more OO friendly. This
-	  resulted in a lot of name changing within the res_ari_*.so
-	  modules, but not much else. There were a couple of other fixed I
-	  made in the process. * When reversible operations (POST /hold,
-	  POST /unhold) were made more RESTful (POST /hold, DELETE
-	  /unhold), the path for the second operation was left in the API
-	  declaration. This worked, but really the two operations should
-	  have been on the same API. * The POST /unmute operation had still
-	  not been REST-ified. Review:
-	  https://reviewboard.asterisk.org/r/2940/ ........ Merged
-	  revisions 402528 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-06 21:58 +0000 [r402518]  Kevin Harwell <kharwell at digium.com>
-
-	* /, apps/app_queue.c: app_queue: crash if first agent is "busy" If
-	  the first agent/member (via CLI "queue show") in a queue is
-	  "busy" (dnd, circuit busy, etc...) and no agents answered then
-	  app_queue would crash. This occurred because while the calling of
-	  agent(s) remained valid the channel on "busy" agent would be set
-	  to NULL and then later dereferenced upon a second "rna" function
-	  call. The original intention of the code is to have only valid
-	  "call attempt" objects (channels != NULL) checked while
-	  attempting to call agent(s). It does this by building a
-	  "call_next" list of valid "call attempt" objects. In the case of
-	  the "busy" agent subsequent builds of the valid "call attempt"
-	  list would sometimes include (the case mentioned above) an
-	  invalid "call attempt" object. The fix was to make sure the "call
-	  attempt" list was appropriately built on every iteration. A NULL
-	  sanity check was also added at the original offending spot of the
-	  crash just in case another one slipped by somehow. (closes issue
-	  ASTERISK-22644) Reported by: Marco Signorini Review:
-	  https://reviewboard.asterisk.org/r/2983/ ........ Merged
-	  revisions 402517 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-05 21:17 +0000 [r402502-402508]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/chan_sip.c: chan_sip: Use AST_AF* defined constant
-	  when calling ast_get_ip While the structure passed to ast_get_ip
-	  should be set memset to 0, thus initializing the ss_family member
-	  to 0, explicitly setting it to AST_AF_UNSPEC is more portable.
-	  ........ Merged revisions 402507 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_iax2.c, /: chan_iax2: Fix incorrect usage of
-	  ast_get_ip involving uninitialized struct This started off as a
-	  fix for the failing IAX2 acl_call test in the Asterisk Test
-	  Suite. When inspecting why that test was failing, it became clear
-	  that all attempts to bind to any local loopback address was
-	  failing: [Nov 2 15:56:28] VERBOSE[15787] chan_iax2.c: == Binding
-	  IAX2 to address 127.0.0.1:4569 [Nov 2 15:56:28] DEBUG[15787]
-	  netsock2.c: Splitting '127.0.0.1' into... [Nov 2 15:56:28]
-	  DEBUG[15787] netsock2.c: ...host '127.0.0.1' and port ''. [Nov 2
-	  15:56:28] ERROR[15787] netsock2.c: getaddrinfo("127.0.0.1",
-	  "(null)", ...): ai_family not supported [Nov 2 15:56:28]
-	  WARNING[15787] acl.c: Unable to lookup '127.0.0.1' While there's
-	  conceivably other ways for getaddrino to return EAI_FAMILY, the
-	  most common way is if AF_INET, AF_INET6, or AF_UNSPEC is not
-	  provided as the desired family. The culprit was the call to
-	  ast_get_ip, defined in acl.h. This function uses the family from
-	  the passed in addr object (which it will also populate when it
-	  returns!) when it eventually calls getaddrinfo. This patch fixes
-	  the use of ast_get_ip that were not specifying the family in
-	  chan_iax2. This prevents uninitialized use of the structure, so
-	  that the addresses resolve correctly. Review:
-	  https://reviewboard.asterisk.org/r/2991 ........ Merged revisions
-	  402505 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/acl.h, /, include/asterisk/netsock2.h: netsock2:
-	  Define AST_AF_* enum constants to their AF_* equivalents This
-	  patch explicitly defines AST_AF_* enum constants to their
-	  sys/socket.h defined equivalents. It is certainly unclear why
-	  these constants actually have to exist, given that netsock2.h
-	  includes sys/socket.h; however, since the code base is already
-	  liberally sprinkled with the usage of AST_AF_* (as well as with
-	  direct calls to AF_*), this will at least keep the semantics
-	  consistent between their usage across systems. ........ Merged
-	  revisions 402503 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_channels.c, /: stasis_channels: Don't give preference
-	  to ANI info in channel snapshots When publishing channel
-	  snapshots, we currently compute the caller ID name and number by
-	  giving preference first to ani.{name|number}, then to
-	  id.{name|number}. However, when a channel driver (such as
-	  chan_sip) updates the caller ID, it typically only updates the
-	  caller ID stored in id.{name|number}. This means that we are
-	  currently giving preference to stale information. When looking at
-	  the rest of the code base, the only other place where we appear
-	  to use this same logic is in app_amd. Everywhere else, we treat
-	  the party information in ani as being separate to the party
-	  information in id. This patch publishes only the caller ID name
-	  and number in the snapshot field for caller_name and caller_num.
-	  Note that the information in ANI is still available in
-	  caller_ani. Review: https://reviewboard.asterisk.org/r/2992/
-	  ........ Merged revisions 402501 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-04 21:02 +0000 [r402453]  Kevin Harwell <kharwell at digium.com>
-
-	* /, channels/chan_sip.c: chan_sip: notify dialog info ignores
-	  presentation indicator in callerid The presentation indicator in
-	  a callerid (e.g. set by dialplan function
-	  Set(CALLERID(name-pres)= ...)) is not checked when SIP Dialog
-	  Info Notifies are generated during extension monitoring. Added a
-	  check to make sure the name and/or number presentations on the
-	  callee (remote identity) are set to allow. If they are restricted
-	  then "anonymous" is used instead. (closes issue AST-1175)
-	  Reported by: Thomas Arimont Review:
-	  https://reviewboard.asterisk.org/r/2976/ ........ Merged
-	  revisions 402450 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402452 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-02 04:30 +0000 [r402406-402439]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/stasis.c, main/stasis_message_router.c, /,
-	  include/asterisk/vector.h: vector: Uppercase API to follow C
-	  convention. C does not support templates like C++. ........
-	  Merged revisions 402438 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/lock.h, main/stasis.c,
-	  main/stasis_message_router.c, /, include/asterisk/vector.h:
-	  vector: Update API to be more flexible. Made the vector macro API
-	  be more like linked lists. 1) Added a name parameter to
-	  ast_vector() to name the vector struct. 2) Made the API take a
-	  pointer to the vector struct instead of the struct itself. 3)
-	  Added an element cleanup macro/function parameter when removing
-	  an element from the vector for ast_vector_remove_cmp_unordered()
-	  and ast_vector_remove_elem_unordered(). 4) Added
-	  ast_vector_get_addr() in case the vector element is not a simple
-	  pointer. * Converted an inline vector usage in
-	  stasis_message_router to use the vector API. It needed the API
-	  improvements so it could be converted. * Fixed topic reference
-	  leak in router_dtor() when the stasis_message_router is
-	  destroyed. * Fixed deadlock potential in stasis_forward_all() and
-	  stasis_forward_cancel(). Locking two topics at the same time
-	  requires deadlock avoidance. * Made internal_stasis_subscribe()
-	  tolerant of a NULL topic. * Made stasis_message_router_add(),
-	  stasis_message_router_add_cache_update(),
-	  stasis_message_router_remove(), and
-	  stasis_message_router_remove_cache_update() tolerant of a NULL
-	  message_type. * Promoted a LOG_DEBUG message to LOG_ERROR as
-	  intended in dispatch_message(). Review:
-	  https://reviewboard.asterisk.org/r/2903/ ........ Merged
-	  revisions 402429 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/confbridge/conf_state_single.c,
-	  apps/confbridge/conf_state_inactive.c,
-	  apps/confbridge/conf_state_single_marked.c, /,
-	  apps/confbridge/include/confbridge.h,
-	  apps/confbridge/conf_state_multi.c, apps/app_confbridge.c,
-	  apps/confbridge/conf_state_multi_marked.c,
-	  apps/confbridge/conf_state.c: confbridge: Separate user muting
-	  from system muting overrides. The system overrides the user
-	  muting requests when MOH is playing or a waitmarked user is
-	  waiting for a marked user to join. System muting overrides
-	  interfere with what the user may wish the muting to be when the
-	  system override ends. * User muting requests are now independent
-	  of the system muting overrides. The effective muting is now the
-	  logical or of the user request and system override. * Added a
-	  Muted flag to the CLI "confbridge list <conference>" command. *
-	  Added a Muted header to the AMI ConfbridgeList action
-	  ConfbridgeList event. (closes issue AST-1102) Reported by: John
-	  Bigelow Review: https://reviewboard.asterisk.org/r/2960/ ........
-	  Merged revisions 402425 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402427 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/config.c, apps/confbridge/conf_config_parser.c,
-	  configs/confbridge.conf.sample, /: config: Allow ConfBridge DTMF
-	  menus to have '#' as the first digit. ConfBridge allows custom
-	  DTMF menus to be created in the confbridge.conf file by assigning
-	  a DTMF key sequence to a sequence of actions as follows:
-	  DTMF-sequence = action,action... Unfortunately, the normal config
-	  file processing code interprets an initial '#' character as
-	  starting a directive such as #include. * Add the ability to
-	  escape the first non-blank character in a config line so the '#'
-	  character can be used without triggering the directive processing
-	  code. (closes issue AFS-2) (closes issue ASTERISK-22478) Reported
-	  by: Nicolas Tanski Patches: jira_asterisk_22478_v11.patch
-	  (license #5621) patch uploaded by rmudgett (modified) Review:
-	  https://reviewboard.asterisk.org/r/2969/ ........ Merged
-	  revisions 402407 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402416 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/app.h, /, main/app.c: voicemail: Simplify
-	  callback pointer declarations and add doxygen. * Typedefed and
-	  added doxegen for the voicemail callback functions. * Simplified
-	  the prototypes for ast_install_vm_functions() and
-	  ast_install_vm_test_functions() to use the new function typedefs.
-	  * Simplified the voicemail callback function pointer variable
-	  declarations to use the new function typedefs. ........ Merged
-	  revisions 402398 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-01 22:48 +0000 [r402397]  Jonathan Rose <jrose at digium.com>
+	  revisions 355623 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-16 19:51 +0000 [r355576-355621]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, configure, include/asterisk/autoconfig.h.in,
+	  autoconf/ast_c_declare_check.m4 (added), configure.ac,
+	  formats/format_ogg_vorbis.c: Fix compile problem when old version
+	  of libvorbisfile v1.1.2 is used. The principle difference between
+	  libvorbisfile v1.1.2 and newer (at least v1.2.0) is the addition
+	  of the predefined callbacks OV_CALLBACKS_xxx in
+	  vorbis/vorbisfile.h used for ov_open_callbacks(). * Updated the
+	  configure script to detect if libvorbisfile.h declares
+	  OV_CALLBACKS_NOCLOSE. * Copied the declaration of
+	  OV_CALLBACKS_NOCLOSE from v1.2.0 to allow v1.1.2 to compile.
+	  (closes issue ASTERISK-19370) Reported by: Jonn Taylor ........
+	  Merged revisions 355608 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355620 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/confbridge/conf_config_parser.c,
-	  apps/confbridge/include/confbridge.h, apps/app_confbridge.c,
-	  CHANGES: app_confbridge: Make the CONFBRIDGE function be able to
-	  create dynamic menus Also adds the ability to clear all profile
-	  items and makes behavior more consistent with documentation as
-	  when choosing whether to use CONFBRIDGE datastore profiles or the
-	  application arguments to the confbridge application. (closes
-	  issue ASTERISK-22760) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2971/
-
-2013-11-01 21:51 +0000 [r402388]  Scott Griepentrog <sgriepentrog at digium.com>
-
-	* main/manager_bridges.c, /, main/bridge.c,
-	  include/asterisk/bridge.h: Manager: Add equivalent AMI actions
-	  for the bridge CLI commands. Adds the following AMI events,
-	  closely following their CLI counterparts: BridgeDestroy
-	  BridgeKick BridgeTechnologyList BridgeTechnologySuspend
-	  BridgeTechnologyUnsuspend BridgeDestroy kicks an entire bridge,
-	  where BridgeKick kicks just one channel off the bridge. When
-	  kicking a channel, specifying the bridge also (optional) insures
-	  it is not removed from the wrong bridge. The BridgeTechnology
-	  events allow viewing and changing suspension status, which
-	  affects only subsequent not active bridging. (closes
-	  ASTERISK-22356) Reported by: Richard Mudgett Review:
-	  https://reviewboard.asterisk.org/r/2973/ ........ Merged
-	  revisions 402387 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-01 16:31 +0000 [r402368]  David M. Lee <dlee at digium.com>
-
-	* /, rest-api-templates/api.wiki.mustache: ari wiki docs: add notes
-	  about allowMultiple parameters. This patch adds a note to any
-	  parameter that has 'allowMultiple' set in the Swagger
-	  documentation. (closes issue ASTERISK-22704) ........ Merged
-	  revisions 402367 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-01 14:38 +0000 [r402359]  Joshua Colp <jcolp at digium.com>
-
-	* include/asterisk/stasis_app.h, rest-api/api-docs/channels.json,
-	  res/ari/resource_channels.c, res/res_ari_channels.c,
-	  res/ari/resource_channels.h, res/res_stasis_playback.c, /,
-	  res/stasis/control.c: res_ari_channels: Add ring operation, dtmf
-	  operation, hangup reasons, and tweak early media. The ring
-	  operation sends ringing to the specified channel it is invoked
-	  on. The dtmf operation can be used to send DTMF digits to the
-	  specified channel of a specific length with a wait time in
-	  between. Finally hangup reasons allow you to specify why a
-	  channel is being hung up (busy, congestion). Early media behavior
-	  has also been tweaked slightly. When playing media to a channel
-	  it will no longer automatically answer. If it has not been
-	  answered a progress indication is sent instead. (closes issue
-	  ASTERISK-22701) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2916/ ........ Merged
-	  revisions 402358 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-01 12:40 +0000 [r402349]  Kinsey Moore <kmoore at digium.com>
-
-	* res/res_rtp_asterisk.c, /, channels/chan_sip.c,
-	  include/asterisk/rtp_engine.h: chan_sip: Fix RTCP port for SRFLX
-	  ICE candidates This corrects one-way audio between Asterisk and
-	  Chrome/jssip as a result of Asterisk inserting the incorrect RTCP
-	  port into RTCP SRFLX ICE candidates. This also exposes an ICE
-	  component enumeration to extract further details from candidates.
-	  (closes issue ASTERISK-21383) Reported by: Shaun Clark Review:
-	  https://reviewboard.asterisk.org/r/2967/ ........ Merged
-	  revisions 402345 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402348 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-11-01 12:33 +0000 [r402337-402347]  Joshua Colp <jcolp at digium.com>
-
-	* /, include/asterisk/stasis_app.h, res/ari/resource_channels.c:
-	  res_ari_channels: Fix a deadlock when originating multiple
-	  channels close to eachother. If a Stasis application is specified
-	  an implicit subscription is done on the originated channel. This
-	  was previously done with the channel lock held which is dangerous
-	  as the underlying code locks the container and iterates items.
-	  This change releases the lock on the originated channel before
-	  subscribing occurs. (closes issue ASTERISK-22768) Reported by:
-	  Matt Jordan Review: https://reviewboard.asterisk.org/r/2979/
-	  ........ Merged revisions 402346 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/stasis/control.c: res_stasis: Ensure the channel is always
-	  departed from the bridge when it leaves. This change adds a
-	  command to the command queue to explicitly depart the channel
-	  from the bridge when it is told it has left. If the channel has
-	  already been departed or has entered a different bridge this
-	  command will become a no-op. (closes issue ASTERISK-22703)
-	  Reported by: John Bigelow (closes issue ASTERISK-22634) Reported
-	  by: Kevin Harwell Review:
-	  https://reviewboard.asterisk.org/r/2965/ ........ Merged
-	  revisions 402336 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-31 22:09 +0000 [r402328]  Mark Michelson <mmichelson at digium.com>
-
-	* /, contrib/scripts/sip_to_pjsip/sip_to_pjsip.py,
-	  contrib/scripts/sip_to_res_sip (removed),
-	  contrib/scripts/sip_to_pjsip (added),
-	  contrib/scripts/sip_to_pjsip/astconfigparser.py,
-	  contrib/scripts/sip_to_pjsip/astdicts.py: Update the conversion
-	  script from sip.conf to pjsip.conf (closes issue ASTERISK-22374)
-	  Reported by Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2846 ........ Merged revisions
-	  402327 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-31 16:06 +0000 [r402286-402290]  Matthew Jordan <mjordan at digium.com>
+	* /, res/res_monitor.c: Fix AMI Monitor action without File header
+	  converting channel name into filename. * Fix potential Solaris
+	  crash if Monitor application has a urlbase and no fname_base
+	  option. ........ Merged revisions 355574 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355575 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-15 19:29 +0000 [r355450-355531]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: When IAX2 debugging is enabled, make
+	  sure to log 'apathetic' messages too. ........ Merged revisions
+	  355529 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 355530 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* build_tools/cflags.xml, channels/chan_iax2.c: Remove IAX_OLD_FIND
+	  from chan_iax2.
+
+	* /, channels/chan_iax2.c: Use TRUNK_CALL_START as originally
+	  intended. Back in r646, TRUNK_CALL_START was added and defined as
+	  0x4000. That same value was also hard-coded in one part of the
+	  IAX2 code instead of using the #define. TRUNK_CALL_START has
+	  changed over the years (for dealing with LOW_MEMORY), but the
+	  hard-coded usage was never updated to match. This patch fixes
+	  that. ........ Merged revisions 355448 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355449 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-14 20:27 +0000 [r355413]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* utils/refcounter.c, main/pbx.c, funcs/func_timeout.c,
+	  include/asterisk/autoconfig.h.in, utils/hashtest.c, UPGRADE.txt,
+	  CHANGES, main/config.c, configs/logger.conf.sample,
+	  main/loader.c, include/asterisk/logger.h, main/manager.c,
+	  main/logger.c, utils/ael_main.c, utils/hashtest2.c,
+	  codecs/codec_dahdi.c, main/stdtime/localtime.c, main/asterisk.c,
+	  addons/res_config_mysql.c: Re-commit the verbose branch. This
+	  change permits each verbose destination (consoles, logger) to
+	  have its own concept of what the verbosity level is. The big
+	  feature here is that the logger will now be able to capture a
+	  particular verbosity level without condemning each console to
+	  need to suffer that level of verbosity. Additionally, a stray
+	  'core set verbose' will no longer change what will go to the log.
+	  Review: https://reviewboard.asterisk.org/r/1599/
+
+2012-02-14 19:29 +0000 [r355321-355376]  Richard Mudgett <rmudgett at digium.com>
 
-	* main/loader.c, /: core/loader: Don't call dlclose in a while loop
-	  For awhile now, we've noticed continuous integration builds
-	  hanging on CentOS 6 64-bit build agents. After resolving a number
-	  of problems with symbols, strange locks, and other shenanigans,
-	  the problem has persisted. In all cases, gdb shows the Asterisk
-	  process stuck in loader.c on one of the infinite while loops that
-	  calls dlclose repeatedly until success. The documentation of
-	  dlclose states that it returns 0 on success; any other value on
-	  error. It does not state that repeatedly calling it will
-	  eventually clear those errors. Most likely, the repeated calls to
-	  dlclose was to force a close by exhausting the references on the
-	  library; however, that will never succeed if: (a) There is some
-	  fundamental error at work in the loaded library that precludes
-	  unloading it (b) Some other loaded module is referencing a symbol
-	  in the currently loaded module This results in Asterisk sitting
-	  forever. Since we have matching pairs of dlopen/dlclose, this
-	  patch opts to only call dlclose once, and log out as an ERROR if
-	  dlclose fails to return success. If nothing else, this might help
-	  to determine why on the CentOS 6 64-bit build agent things are
-	  not closing successfully. Review:
-	  https://reviewboard.asterisk.org/r/2970 ........ Merged revisions
-	  402287 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 402288 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402289 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/media_index.c, /: medix_index: Display errors when library
-	  calls fail Based on feedback from ipengineer in #asterisk, when
-	  the media indexer cannot access a sound file on the system (or
-	  otherwise fails) Asterisk displays a "Cannot frob file" error but
-	  fails to tell you why. This is especially problematic as the
-	  media_indexer failing will rpevent Asterisk from starting, as it
-	  is in the core. We now display the errno error messages so folks
-	  can figure out what they've done wrong. ........ Merged revisions
-	  402285 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-31 14:45 +0000 [r402277]  David M. Lee <dlee at digium.com>
-
-	* /, res/stasis/app.c: stasis: add functions embarrassingly missing
-	  from r400522 I neglected to implement two of the endpoint
-	  subscription functions when I did the work. Normally, you'll only
-	  hit that when you unsubscribe from a specific endpoint. ........
-	  Merged revisions 402276 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-30 17:54 +0000 [r402266]  Kevin Harwell <kharwell at digium.com>
-
-	* channels/chan_pjsip.c, /, res/res_pjsip_messaging.c:
-	  pjsip_messaging: Added debug for in dialog messaging (issue
-	  ASTERISK-22777) Reported by: Matt Jordan ........ Merged
-	  revisions 402265 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-29 23:43 +0000 [r402227]  Rusty Newton <rnewton at digium.com>
-
-	* /, sounds/Makefile: Updates for 1.4.25 core sounds and 1.4.14
-	  extra sounds, plus new en_GB language set The new sound packages
-	  relate to issues: ASTERISK-22544, ASTERISK-22411, ASTERISK-21413,
-	  ASTERISK-20782 Modified sounds/Makefile for the new sound
-	  versions and to account for the new en_GB language set. (issue
-	  ASTERISK-22659) (closes issue ASTERISK-22659) (closes issue
-	  ASTERISK-22411) (closes issue ASTERISK-22544) ........ Merged
-	  revisions 402224 from
+	* /, configure, include/asterisk/autoconfig.h.in, configure.ac,
+	  formats/format_ogg_vorbis.c: Fix voicemail problems when using
+	  ogg/vorbis. Ogg/vorbis was fairly useless as a voicemail file
+	  format because it did not implement the seek and tell format
+	  callbacks among other problems. Since we were already using the
+	  libvorbis and libvorbisenc libraries we can use libvorbisfile as
+	  it is also part of the vorbis library package. * Made use the
+	  libvorbisfile to handle the ogg/vorbis file stream. The
+	  format_ogg_vorbis.c is now mostly a wrapper around libvorbisfile.
+	  (closes issue ASTERISK-16926) Reported by: sque Patches:
+	  ogg_vorbis_use_libvorbisfile.patch (license #6108) patch uploaded
+	  by sque ........ Merged revisions 355365 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355375 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, cel/cel_sqlite3_custom.c: Fix lock typo that should be unlock
+	  in cel_sqlite_custom reload. (closes issue ASTERISK-19356)
+	  Reported by: Alex Villacis Lasso Patches:
+	  asterisk-1.8.9.2-cel_sqlite3_custom-fix-reload-locking-typo.patch
+	  (license #5617) patch uploaded by Alex Villacis Lasso Review:
+	  https://reviewboard.asterisk.org/r/1740/ ........ Merged
+	  revisions 355319 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 402225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402226 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 355320 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-29 12:57 +0000 [r402155]  Matthew Jordan <mjordan at digium.com>
+2012-02-14 16:28 +0000 [r355274]  Mark Michelson <mmichelson at digium.com>
 
-	* main/xmldoc.c, main/channel.c, main/pbx.c, /, main/translate.c:
-	  Remove some spammy debug messages; improve clarity of others
-	  Debug messages aren't free. Even when the debug level is
-	  sufficiently low such that the messages are never evaluated,
-	  there is a cost to having to parse Asterisk logs that contain
-	  debug messages that (a) fail to convey sufficient information or
-	  (b) occur so frequently as to be next to meaningless. Based on
-	  having to stare at lots of DEBUG messages, this patch makes the
-	  following changes: * channel.c: When copying variables from a
-	  parent channel to a child channel, specify the channels involved.
-	  Do not log anything for a variable that is not inherited; the
-	  fact that it doesn't have an _ or __ already signifies that it
-	  won't be inherited. * pbx.c: Specify what function evaluation has
-	  occurred that created the result. * translate.c: Bump up the
-	  translator path messages to 10. I've never once had to use these
-	  debug messages, and for each format that is registered (on
-	  startup) and unregistered (on shutdown) the entire f^2 matrix is
-	  logged out. For short tests in the Asterisk Test Suite, this
-	  should make finding the actual test much easier. * xmldoc.c: The
-	  debug message that 'blah' is not found in the tree is expected.
-	  Often, description elements - which are not required - are not
-	  provided. This debug message adds no additional value, as it is
-	  not indicative of an error or helpful in debugging which element
-	  did not contain a 'blah' element as a child. If an element is
-	  supposed to contain a child element, then that XML tree should
-	  have failed validation in the first place. Review:
-	  https://reviewboard.asterisk.org/r/2966/ ........ Merged
-	  revisions 402150 from
+	* /, channels/chan_sip.c: Properly invert the return of a strncmp
+	  call. This was causing identification that should have been made
+	  private to be public. (closes issue AST-814) reported by Patrick
+	  Anderson Patches: chan_sip.c.diff uploaded by Patrick Anderson
+	  (license 5430) ........ Merged revisions 355268 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355271 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-14 15:58 +0000 [r355230]  Jason Parker <jparker at digium.com>
+
+	* /, configs/cdr_sqlite3_custom.conf.sample: Don't enable sqlite3
+	  CDRs by default in sample configs. ........ Merged revisions
+	  355228 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 355229 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-14 13:35 +0000 [r355184]  Sean Bright <sean at malleable.com>
+
+	* /, channels/chan_iax2.c: Clear the high order bit from the
+	  destination call number before sending. send_apathetic_reply
+	  takes the incoming frame's source call number as the destination
+	  call number for the outgoing frame. If the incoming frame was a
+	  full frame, then the high order bit of the source call number is
+	  set and will be interpreted as a retransmit when sent back out as
+	  the destination call number. ........ Merged revisions 355182
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 355183 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-14 09:58 +0000 [r355138]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: call manager_event only if there is not
+	  null channel structure (Closes issue ASTERISK-19298) Reported by:
+	  robinfood Patches: issue19298.patch uploaded by may213 (License
+	  #5415) ........ Merged revisions 355136 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355137 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-14 00:43 +0000 [r355102]  Russell Bryant <russell at russellbryant.com>
+
+	* res/res_agi.c, CHANGES: res_agi: Add AGIEXITONHANGUP variable.
+	  This patch adds a variable AGIEXITONHANGUP for res_agi. If this
+	  variable is set to "yes" on a channel, AGI() will exit
+	  immediately once a channel hangup has been detected. This was the
+	  behavior of AGI() in Asterisk 1.4 and earlier and is still
+	  desired by some people. Review:
+	  https://reviewboard.asterisk.org/r/1734/
+
+2012-02-13 22:04 +0000 [r355055-355058]  Richard Mudgett <rmudgett at digium.com>
+
+	* pbx/pbx_spool.c, /: Fix occasional incorrectly delayed call-file
+	  execution. Since the dir timestamp is available at one second
+	  resolution, we cannot know if it was updated within the same
+	  second after we scanned it. Therefore, we will force another scan
+	  if the dir was just modified. * Changed to force another scan if
+	  the directory was just modified. (closes issue ASTERISK-19081)
+	  Reported by: Knut Bakke Review:
+	  https://reviewboard.asterisk.org/r/1688/ ........ Merged
+	  revisions 355056 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 355057 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/chan_misdn.c: Fix compile error from most recent
+	  ast_channel opaquification installment.
+
+2012-02-13 19:56 +0000 [r355011]  Joshua Colp <jcolp at digium.com>
+
+	* /, pbx/pbx_config.c: Only allow one 'dialplan reload' to execute
+	  at a time as otherwise they would share the same common local
+	  context list. (closes issue AST-758) ........ Merged revisions
+	  355009 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 355010 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-13 17:27 +0000 [r354968]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_local.c, addons/chan_ooh323.c,
+	  channels/chan_iax2.c, main/cli.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c, channels/chan_skinny.c, main/features.c,
+	  apps/app_dumpchan.c, pbx/pbx_realtime.c, channels/chan_alsa.c,
+	  apps/app_dial.c, main/pbx.c, apps/app_fax.c,
+	  channels/chan_agent.c, include/asterisk/channel.h,
+	  apps/app_talkdetect.c, main/cel.c, channels/chan_misdn.c,
+	  funcs/func_channel.c, apps/app_macro.c, apps/app_chanspy.c,
+	  res/res_calendar.c, apps/app_voicemail.c,
+	  channels/chan_unistim.c, tests/test_substitution.c,
+	  channels/chan_vpb.cc, apps/app_meetme.c, main/ccss.c,
+	  apps/app_readexten.c, channels/chan_gtalk.c, main/cdr.c,
+	  main/channel.c, main/dial.c, channels/chan_phone.c,
+	  main/manager.c, apps/app_osplookup.c,
+	  bridges/bridge_builtin_features.c, res/res_agi.c,
+	  apps/app_minivm.c, apps/app_confbridge.c, apps/app_directory.c,
+	  addons/chan_mobile.c, apps/app_rpt.c, apps/app_parkandannounce.c,
+	  channels/chan_mgcp.c, apps/app_while.c, funcs/func_dialplan.c,
+	  channels/chan_sip.c, res/res_fax.c, main/channel_internal_api.c,
+	  pbx/pbx_lua.c, channels/sig_pri.c, apps/app_queue.c,
+	  channels/chan_oss.c, channels/chan_jingle.c,
+	  apps/app_directed_pickup.c, main/file.c, channels/chan_h323.c,
+	  res/snmp/agent.c, pbx/pbx_dundi.c, channels/chan_nbs.c,
+	  apps/app_stack.c, apps/app_verbose.c: Opaquify char * and char[]
+	  in ast_channel Review: https://reviewboard.asterisk.org/r/1733/
+
+2012-02-13 17:25 +0000 [r354964]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_config_pgsql.c, /, configs/extconfig.conf.sample: Fix
+	  reconnecting to pgsql database after connection loss. There can
+	  only be one database connection in res_config_pgsql just like
+	  res_config_sqlite. If the connection is lost, the connection may
+	  not get reestablished to the same database if the res_pgsql.conf
+	  and extconfig.conf files are inconsistent. * Made only use the
+	  configured database from res_pgsql.conf. * Fixed potential buffer
+	  overwrite of last[] in config_pgsql(). (closes issue
+	  ASTERISK-16982) Reported by: german aracil boned Review:
+	  https://reviewboard.asterisk.org/r/1731/ ........ Merged
+	  revisions 354953 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354959 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-13 16:42 +0000 [r354939]  Joshua Colp <jcolp at digium.com>
+
+	* /, apps/app_confbridge.c: Don't try to play sound files that do
+	  not exist. (closes issue ASTERISK-19188) Reported by: slesru
+	  ........ Merged revisions 354938 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-10 22:44 +0000 [r354903]  Jason Parker <jparker at digium.com>
+
+	* /, apps/app_voicemail.c: Fix a voicemail memory leak with
+	  heard/deleted messages. open_mailbox() was changed quite a long
+	  time ago to allocate this memory. close_mailbox() should have
+	  been changed to be responsible for freeing it. ........ Merged
+	  revisions 354889 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354890 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-10 18:08 +0000 [r354837]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /: Fix AMI Redirect ExtraChannel not redirecting
+	  to the same exten and context. The astman_get_header() never
+	  returns NULL so the check by the code for NULL would never fail.
+	  (closes issue ASTERISK-16974) Reported by: Nuno Borges Patches:
+	  0018325.patch (license #6116) patch uploaded by Nuno Borges
+	  (modified) ........ Merged revisions 354835 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354836 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-10 14:51 +0000 [r354799]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: Fix IMAP app_voicemail compilation issue
+	  introduced in r354429 This simply fixes the compilation issue
+	  introduced in r354429 by re-adding the 'quote' variable. (closes
+	  issue ASTERISK-19337) Reported by: John Taylor
+
+2012-02-09 22:06 +0000 [r354751]  Terry Wilson <twilson at digium.com>
+
+	* /, funcs/func_cdr.c: Note that CDRs are immutable once a bridge
+	  is torn down CDRs cannot be modified after a bridge is torn down,
+	  (e.g. after Dial() returns) even though the CDR() function may be
+	  called. Since modifying the CDR code to change this behavior
+	  could very easily break all kinds of things, this patch just
+	  documents this limitation. (closes issues ASTERISK-16923) Review:
+	  https://reviewboard.asterisk.org/r/1720/ ........ Merged
+	  revisions 354749 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354750 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-09 20:52 +0000 [r354657-354704]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Fix parsing of SIP headers where compact
+	  and non-compact headers are mixed Change parsing of SIP headers
+	  so that compactness of the header no longer influences which
+	  header will be chosen. Previously, a non-compact header would be
+	  chosen instead of a preceeding compact-form header. (closes issue
+	  ASTERISK-17192) Review: https://reviewboard.asterisk.org/r/1728/
+	  ........ Merged revisions 354702 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354703 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/config.c: Make the config parser remove escaping
+	  backslashes The config parser in Asterisk does not currently
+	  remove a backslash that is used to escape a semicolon which would
+	  otherwise be interpreted as the start of a comment. The change
+	  here causes that backslash to be removed, but does not create a
+	  real escape system in the config parser. The biggest complication
+	  with a real escape system would be breaking existing configs
+	  everywhere (parsing \\ as \ and breaking on escaped non-semicolon
+	  characters) even though it would be the "right" way to do things.
+	  (closes issue ASTERISK-17121) Review:
+	  https://reviewboard.asterisk.org/r/1724/ ........ Merged
+	  revisions 354655 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-09 18:14 +0000 [r354597]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_sip.c, channels/sip/include/config_parser.h,
+	  channels/sip/utils.c (added), configs/sip.conf.sample, CHANGES,
+	  channels/sip/config_parser.c, channels/sip/include/sip.h,
+	  channels/sip/include/sip_utils.h: Add auto_force_rport and
+	  auto_comedia NAT options This patch adds the auto_force_rport and
+	  auto_comedia NAT options. It also converts the nat= setting to a
+	  list of comma-separated combinable options: no, force_rport,
+	  comedia, auto_force_rport, and auto_comedia. nat=yes remains as
+	  an undocumented option equal to "force_rport,comedia". The first
+	  instance of 'yes' or 'no' in the list stops parsing and overrides
+	  any previously set options. If an auto_* option is specified with
+	  its non-auto_ counterpart, the auto setting takes precedence.
+	  This patch builds upon the patch posted to ASTERISK-17860 by JIRA
+	  user pedro-garcia. (closes issue ASTERISK-17860) Review:
+	  https://reviewboard.asterisk.org/r/1698/
+
+2012-02-09 17:17 +0000 [r354552]  Mark Michelson <mmichelson at digium.com>
+
+	* /, res/res_fax.c: Adding reload support to res_fax.so (closes
+	  issue ASTERISK-16712) reported by Frank DiGennaro Review:
+	  https://reviewboard.asterisk.org/r/1713 ........ Merged revisions
+	  354545 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 354546 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-09 17:09 +0000 [r354544-354549]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Clean-up of minor formatting issues in
+	  r354542/3/4 rmudgett pointed out some formatting issues in the
+	  check-in for ASTERISK-19290. This cleans those up. Review:
+	  https://reviewboards.asterisk.org/r/1722/ ........ Merged
+	  revisions 354547 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354548 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Fix SIP INFO DTMF handling for
+	  non-numeric codes In ASTERISK-18924, SIP INFO DTMF handlingw as
+	  changed to account for both lowercase alphatbetic DTMF events, as
+	  well as uppercase alphabetic DTMF events. When this occurred, the
+	  comparison of the character buffer containing the event code was
+	  changed such that the buffer was first compared again '0' and '9'
+	  to determine if it was numeric. Unfortunately, since the first
+	  character in the buffer will typically be '1' in the case of
+	  non-numeric event codes (10-16), this caused those codes to be
+	  converted to a DTMF event of '1'. This patch fixes that, and
+	  cleans up handling of both application/dtmf-relay and
+	  application/dtmf content types. Review:
+	  https://reviewboard.asterisk.org/r/1722/ (closes issue
+	  ASTERISK-19290) Reported by: Ira Emus Tested by: mjordan ........
+	  Merged revisions 354542 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354543 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-09 03:09 +0000 [r354497-354498]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/chan_misdn.c: Fix some compile
+	  problems from the 'cppcheck' patch.
+
+	* /, apps/app_parkandannounce.c: Fix crash in ParkAndAnnounce.
+	  Well, thats embarrasing. I forgot to initialize the caller_id
+	  storage. (closes issue ASTERISK-19311) Reported by: tootai Tested
+	  by: rmudgett ........ Merged revisions 354495 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354496 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-09 02:28 +0000 [r354494]  Russell Bryant <russell at russellbryant.com>
+
+	* main/channel.c, /: Remove some unnecessary locking from
+	  ast_hangup(). This patch removes some unnecessary locking of the
+	  channels container in ast_hangup(). The reason this came up is
+	  that this lock can very quickly block the entire system. If any
+	  of the channel cleanup code decides to block, it causes a problem
+	  for the whole system. For example, when audiohooks get destroyed,
+	  if that blocks for a while waiting on the mixmonitor thread to
+	  exit because it's busy blocking on some I/O, it causes a problem
+	  for many other threads in the meantime. Review:
+	  https://reviewboard.asterisk.org/r/1712/ ........ Merged
+	  revisions 354492 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354493 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-08 21:29 +0000 [r354459]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* res/res_ais.c (removed), contrib/scripts/install_prereq: Revision
+	  354046 added res_corosync as a replacement for res_ais, but
+	  didn't actually remove res_ais. This commit removes it. In
+	  addition, the 'install_prereq' script has been updated to no
+	  longer install AIS dependency packages, and instead install
+	  Corosync packages instead.
+
+2012-02-08 21:28 +0000 [r354458]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_sip.c, contrib/realtime/postgresql/realtime.sql,
+	  CHANGES, channels/sip/include/sip.h: Add callbackextension
+	  matching & realtime callbackextensions This patch is based on the
+	  one by David Vossel, developer extrodinaire, at
+	  https://reviewboard.asterisk.org/r/344/. If multiple peers are
+	  defined with the same host/port, but differing
+	  callbackextensions, it chooses the peer with the matching
+	  callbackextension. Since callbackextension creates an outbound
+	  registration with the callbackextension as the Contact address,
+	  matching an incoming request by that (in addition to the
+	  host/port) makes a lot of sense. This patch also adds support for
+	  callbackextension to realtime by querying all peers with
+	  callbackextensions on reload and adding registrations for them.
+	  (closes issue ASTERISK-13456) Review:
+	  https://reviewboard.asterisk.org/r/344/ Review:
+	  https://reviewboard.asterisk.org/r/1717/
+
+2012-02-08 21:25 +0000 [r354450]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* channels/chan_dahdi.c: Restore some variables removed by the
+	  'cppcheck' patch that were actually needed.
+
+2012-02-08 20:49 +0000 [r354429]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* apps/app_dial.c, main/udptl.c, main/pbx.c, addons/chan_ooh323.c,
+	  funcs/func_env.c, funcs/func_strings.c, utils/astman.c,
+	  main/acl.c, apps/app_disa.c, apps/app_alarmreceiver.c,
+	  apps/app_queue.c, channels/chan_iax2.c,
+	  addons/ooh323c/src/memheap.c, channels/chan_usbradio.c,
+	  channels/chan_dahdi.c, apps/app_osplookup.c,
+	  channels/chan_misdn.c, channels/chan_skinny.c, funcs/func_odbc.c,
+	  main/ast_expr2f.c, apps/app_minivm.c, formats/format_h263.c,
+	  addons/chan_mobile.c, apps/app_chanspy.c, main/ast_expr2.fl,
+	  apps/app_voicemail.c: Avoid cppcheck warnings; removing unused
+	  vars and a bit of cleanup. Patch by: Clod Patry Review:
+	  https://reviewboard.asterisk.org/r/1651
+
+2012-02-08 15:28 +0000 [r354395]  Kinsey Moore <kmoore at digium.com>
+
+	* CHANGES: Add CHANGES documentation for the "pri set debug"
+	  bitmask change (related to ASTERISK-17159)
+
+2012-02-07 21:33 +0000 [r354360]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c, contrib/realtime/postgresql/realtime.sql:
+	  Fix multiple SIP realtime issues 1. Set lastms to 0 when clearing
+	  instead of "" 2. Don't set ipaddr or port to the string "(null)"
+	  when they are empty 3. Add missing required fields, set default
+	  for lastms to 0, and modify the length of the ipaddr field to 45
+	  in the Postgresql realtime.sql file. (closes issue
+	  ASTERISK-19172) Review: https://reviewboard.asterisk.org/r/1703/
+	  ........ Merged revisions 354348 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354349 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-07 18:07 +0000 [r354312-354314]  Sean Bright <sean at malleable.com>
+
+	* contrib/scripts/live_ast: Continuation of last patch - since
+	  LIVE_AST_LD_PATH_EXTRA will now never be empty, don't check for
+	  it, instead of check if LD_LIBRARY_PATH is already set and if so,
+	  append LIVE_AST_LD_PATH_EXTRA properly.
+
+	* contrib/scripts/live_ast: Include live/usr/lib in the shared
+	  library search path to that we pick up libasteriskssl.so at run
+	  time when using live_ast.
+
+	* contrib/scripts/live_ast: Whitespace only (remove trailing
+	  spaces)
+
+2012-02-07 15:29 +0000 [r354275]  Jonathan Rose <jrose at digium.com>
+
+	* /, cdr/cdr_pgsql.c: Fix column duplication bug in module reload
+	  for cdr_pgsql. Prior to this patch, attempts to reload
+	  cdr_pgsql.so would cause the column list to keep its current data
+	  and then add a second copy during the reload. This would cause
+	  attempts to log the CDR to the database to fail. This patch also
+	  cleans up some unnecessary null checks for ast_free and deals
+	  with a few potential locking problems. (closes issue
+	  ASTERISK-19216) Reported by: Jacek Konieczny Review:
+	  https://reviewboard.asterisk.org/r/1711/ ........ Merged
+	  revisions 354263 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354270 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-06 23:15 +0000 [r354174-354218]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, pbx/pbx_config.c: Improved documentation of CLI "dialplan add
+	  extension" command. * Documented dialplan add extension
+	  <exten>,<priority>,<app(<app-data>)> format. * Allow acceptance
+	  of command without the app-data value. There are many
+	  applications that do no need any parameters so it is silly to
+	  require that field for all commands. * Fixed a couple
+	  ast_malloc/ast_free mismatches with ast_add_extension2() calls.
+	  (closes issue ASTERISK-19222) Reported by: Andrey Solovyev Tested
+	  by: rmudgett ........ Merged revisions 354216 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354217 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sig_pri.h: Restore alternate SIG_PRI_DEBUG_DEFAULT
+	  meaning.
+
+2012-02-06 20:18 +0000 [r354165]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/sig_pri.h, channels/chan_dahdi.c: Allow more control
+	  over the output of pri debug This changes the debuglevel of 'pri
+	  set debug' to a bit mask allowing the user to independently
+	  select bits of output: 1 libpri internals including state machine
+	  2 Decoded Q.931 messages 4 Decoded Q.921 headers 8 raw hex dump
+	  of the full frames Additionally, this ensures that the meaning of
+	  "on" does not change and intrudces intense and hex to simplify
+	  usage. (closes issue ASTERISK-17159) Original-patch-by: wimpy
+
+2012-02-06 17:33 +0000 [r354120]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Add missing headers to AMI UnParkedCall event
+	  to uniquely identify the call. The AMI UnParkedCall event was
+	  missing the Parkinglot and Uniqueid headers that the AMI
+	  ParkedCall event contains. (closes issue ASTERISK-19240) Reported
+	  by: Michael Yara ........ Merged revisions 354116 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 354119 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-06 16:38 +0000 [r354084]  Joshua Colp <jcolp at digium.com>
+
+	* apps/app_meetme.c, UPGRADE.txt: Make the 'c' option to MeetMe
+	  work even if the 'q' option is used. (closes issue
+	  ASTERISK-17053) Reported by: justdave
+
+2012-02-05 10:58 +0000 [r354046]  Russell Bryant <russell at russellbryant.com>
+
+	* build_tools/menuselect-deps.in, configure,
+	  include/asterisk/autoconfig.h.in, res/res_corosync.c (added),
+	  configure.ac, configs/res_corosync.conf.sample (added), res/ais
+	  (removed), UPGRADE.txt, configs/ais.conf.sample (removed),
+	  CHANGES, makeopts.in: Replace res_ais with a new module,
+	  res_corosync. This patch removes res_ais and introduces a new
+	  module, res_corosync. The OpenAIS project is deprecated and is
+	  now just a wrapper around Corosync. This module provides the same
+	  functionality using the same core infrastructure, but without the
+	  use of the deprecated components. Technically res_ais could have
+	  been used with an AIS implementation other than OpenAIS, but that
+	  is the only one I know of that was ever used. Review:
+	  https://reviewboard.asterisk.org/r/1700/
+
+2012-02-03 21:33 +0000 [r354001]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_agent.c: Fixes deadlocks occuring in chan_agent
+	  due to r335976 Bad locking order was added to chan_agent to
+	  prevent segfaults from having no locking in a patch by irroot.
+	  This patch addresses the bad locking order by releasing locks
+	  before getting the right locking order to stop deadlocks from
+	  occuring when doing multiple interactions with agents. (closes
+	  issue ASTERISK-19285) Reported by: Alex Villacis Lasso Review:
+	  https://reviewboard.asterisk.org/r/1708/ ........ Merged
+	  revisions 353999 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 402151 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402154 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-29 12:51 +0000 [r402149-402153]  Kinsey Moore <kmoore at digium.com>
-
-	* rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, res/ari/resource_channels.h, /: ARI:
-	  Remove channels/{channelId}/dial This removes the
-	  /ari/channels/{channelId}/dial URI since it is redundant, overly
-	  complex, is likely to become more externally complex over time,
-	  and is too high-level compared with other ARI operations. See the
-	  following for further information:
-	  http://lists.digium.com/pipermail/asterisk-app-dev/2013-October/000002.html
-	  (closes issue ASTERISK-22784) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2968/ ........ Merged
-	  revisions 402152 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* bridges/bridge_native_rtp.c, /: bridge_native_rtp: Ensure bridge
-	  is torn down When a bridge transitions away from one tech to
-	  another, the tech going away is provided a dummy bridge with no
-	  channels in it to tear down. Currently this means that the
-	  teardown code exits prematurely and does not tear anything down.
-	  This change tears down RTP bridging for the channel provided in
-	  the leave bridge tech callback. This also reverts the majority of
-	  r400403 since it is now redundant. (closes issue ASTERISK-22628)
-	  (closes issue ASTERISK-22676) Reported by: John Bigelow Reported
-	  by: Kevin Harwell Tested by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/2905/ Patches:
-	  native_rtp_fix.diff uploaded by Kinsey Moore (License 6273)
-	  ........ Merged revisions 402148 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-29 11:15 +0000 [r402140]  Joshua Colp <jcolp at digium.com>
-
-	* /, rest-api/api-docs/playback.json, res/res_ari_playback.c:
-	  res_ari_playback: Add missing 404 error response for GET and
-	  DELETE. (closes issue ASTERISK-22722) Reported by: Richard
-	  Mudgett ........ Merged revisions 402139 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-28 22:10 +0000 [r402128-402130]  David M. Lee <dlee at digium.com>
-
-	* /, doc: Ignore full docs ........ Merged revisions 402127 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /: Put back several merge revisions that were lost in r402054
-
-	* /: Put back several merge revisions that were lost in r401962
-
-2013-10-28 15:08 +0000 [r402113-402117]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, UPGRADE-11.txt, UPGRADE-12.txt: Fix UPGRADE.txt Due To Merging
-	  From Branch 11 When merging in the patch for ASTERISK-22728, the
-	  UPGRADE.txt file was changed incorrectly. That change should have
-	  gone into ASTERISK-11.txt. This commit is to fix that. Also,
-	  another comment in the UPGRADE-11.txt was missing and this commit
-	  adds that as well. ........ Merged revisions 402115 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_sip.c, UPGRADE-12.txt: chan_sip: Clarify
-	  'Forcerport' Setting Displayed When Running "sip show peers"
-	  While looking at ASTERISK-22236, Walter Doekes pointed out that
-	  when running "sip show peers", the setting being displayed can be
-	  confusing. The display of "N" used to mean NAT (i.e. yes). The
-	  NAT setting has gone through many different changes resulting in
-	  the display of different characters to try and convey what the
-	  current setting is for 'Forcerport' (A for Auto and Forcerport is
-	  currently on, a for Auto but Forcerport is off, Y for yes, and N
-	  for no). During the initial code review to try and clarify these
-	  settings (especially since "N" no longer meant what it used to
-	  mean in prior versions of Asterisk), Mark Michelson suggested
-	  using the full space available to display the settings which
-	  helped to make the settings very clear. That was a great
-	  suggestion. Therefore, this patch does the following: * The
-	  column for 'Forcerport' now will show: Auto (Yes), Auto (No),
-	  Yes, or No. * A column for the 'Comedia' setting has been added.
-	  It too will display the setting in a non-cryptic way: Auto (Yes),
-	  Auto (No), Yes, or No. * UPGRADE.txt has been updated to document
-	  this change. (closes issue ASTERISK-22728) Reported by: Walter
-	  Doekes Tested by: Michael L. Young Patches:
-	  asterisk-forcerport-display-clarification_v3.diff uploaded by
-	  Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2941 ........ Merged revisions
-	  402111 from http://svn.asterisk.org/svn/asterisk/branches/11
-	  ........ Merged revisions 402112 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-27 23:22 +0000 [r402073-402091]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: Filter out internal channels from dial message
-	  handling Surrogate channels would pop up from time to time in
-	  dial message handling. This would cause a WARNING message to
-	  appear, indicating that the Surrogate channel had no CDR. This
-	  patch filters out those channels that have the internal
-	  implementation flag set, such that the WARNING message isn't
-	  displayed. ........ Merged revisions 402090 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* cdr/cdr_sqlite3_custom.c, /, cdr/cdr_syslog.c, cdr/cdr_sqlite.c,
-	  cdr/cdr_adaptive_odbc.c, addons/cdr_mysql.c,
-	  include/asterisk/cdr.h, cdr/cdr_pgsql.c, cdr/cdr_odbc.c,
-	  cdr/cdr_radius.c, cdr/cdr_custom.c, cdr/cdr_manager.c,
-	  cdr/cdr_tds.c, cdr/cdr_csv.c, main/cdr.c: Prevent CDR backends
-	  from unregistering while billing data is in flight This patch
-	  makes it so that CDR backends cannot be unregistered while active
-	  CDR records exist. This helps to prevent billing data from being
-	  lost during restarts and shutdowns. Review:
-	  https://reviewboard.asterisk.org/r/2880/ ........ Merged
-	  revisions 402081 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, contrib/ast-db-manage/config/env.py,
-	  contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py,
-	  contrib/ast-db-manage/voicemail/env.py: Update Alembic database
-	  scripts for external scripting and PostgreSQL, Oracle This patch
-	  does the following: 1) The env scripts have been updated to be
-	  tolerant of a NULL configuration file. This occurs when
-	  configuration is provided by an external script, such that the
-	  actual config.ini file is not used. 2) Enum types have all been
-	  given names. This is needed for PostgreSQL script generation. 3)
-	  The identifier meetme_confno_starttime_endtime is greater than 30
-	  characters, and hence invalid for Oracle databases. This has been
-	  truncated down to meetme_confno_start_end. ........ Merged
-	  revisions 400383 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-26 12:56 +0000 [r402065]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_pjsip.c, include/asterisk/res_pjsip_session.h, /:
-	  chan_pjsip: Fix a crash when direct media is enabled and an ACK
-	  is received after the channel is hung up. (closes issue
-	  ASTERISK-22731) Reported by: Kinsey Moore ........ Merged
-	  revisions 402064 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-26 00:36 +0000 [r402056]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_stasis.c, /: res_stasis.c: Made use the ao2_container
-	  callback templates. * Made res_stasis.c use the OBJ_SEARCH_XXX
-	  defines. ........ Merged revisions 402055 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-26 00:27 +0000 [r402054]  Scott Griepentrog <sgriepentrog at digium.com>
+	  revisions 354000 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-03 16:50 +0000 [r353964]  Kinsey Moore <kmoore at digium.com>
+
+	* UPGRADE.txt, cdr/cdr_adaptive_odbc.c,
+	  configs/cdr_adaptive_odbc.conf.sample: Support schema selection
+	  in cdr_adaptive_odbc Asterisk now supports using ODBC with
+	  databases where a single schema must be selected. Previously,
+	  INSERTs would fail because they did not take into account extra
+	  fields cause by having multiple schemas. This also corrects some
+	  SQL resource leaks. (closes issue ASTERISK-17106) Patch-by:
+	  Alexander Frolkin Patch-by: Tilgnman Lesher
+
+2012-02-03 16:23 +0000 [r353963]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_fax.c: Fixes a segfault occuring when performing
+	  attended transfer with FAXOPT(gateway)=yes (closes issue
+	  ASTERISK-19184) Reported by: Alexandr ........ Merged revisions
+	  353962 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-02 22:28 +0000 [r353917]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Ensure entering T.38 passthrough does not
+	  cause an infinite loop After R340970 Asterisk was still polling
+	  the RTCP file descriptor after RTCP is shut down and removed. If
+	  the descriptor happened to have data ready when the removal
+	  occured then Asterisk would go into an infinite loop trying to
+	  read data that it can never actually access. This change disables
+	  the audio RTCP file descriptor for the duration of the T.38
+	  transaction. (closes issue ASTERISK-18951) Reported-by: Kristijan
+	  Vrban ........ Merged revisions 353915 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353916 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-02 20:18 +0000 [r353872]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/sig_pri.h, channels/chan_dahdi.c, /, channels/sig_pri.c:
+	  Restore the 'w' modifier support for ISDN spans.
+	  Dial(DAHDI/g0/1234w888) This feature also causes the sending
+	  complete ie to be sent for switch types that do not automatically
+	  send the ie. (EuroISDN/ETSI) The main difference between dialing
+	  Dial(DAHDI/g0/1234w888) and Dial(DAHDI/g0/1234,,D(888)) is the
+	  sending of the sending complete ie. (closes issue ASTERISK-19176)
+	  Reported by: rmudgett Tested by: rmudgett ........ Merged
+	  revisions 353867 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353868 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-02 18:55 +0000 [r353821]  Mark Michelson <mmichelson at digium.com>
+
+	* main/manager.c, /, main/http.c, configs/manager.conf.sample,
+	  include/asterisk/manager.h, configs/http.conf.sample: Fix TLS
+	  port binding behavior as well as reload behavior: * Removes
+	  references to tlsbindport from http.conf.sample and
+	  manager.conf.sample * Properly bind to port specified in
+	  tlsbindaddr, using the default port if specified. * On a reload,
+	  properly close socket if the service has been disabled. A note
+	  has been added to UPGRADE.txt to indicate how ports must be set
+	  for TLS. (closes issue ASTERISK-16959) reported by Olaf
+	  Holthausen (closes issue ASTERISK-19201) reported by Chris
+	  Mylonas (closes issue ASTERISK-19204) reported by Chris Mylonas
+	  Review: https://reviewboard.asterisk.org/r/1709 ........ Merged
+	  revisions 353770 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353820 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-02 17:07 +0000 [r353725-353772]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Fix sip show peers port output, align
+	  columns, and fix ami port output. A previous patch I committed
+	  from ASTERISK-16930 unexpectedly changed some output for the AMI
+	  action "sippeers" which this patch changes back. Also, this
+	  aligns the output for the cli command "sip show peers" and fixes
+	  another issue that patch introduced by using
+	  ast_sockaddr_stringify calls multiple times without immediately
+	  using the pointer. I also went ahead and did a little janitorial
+	  work to clean up whitespace in _sip_show_peers. (issue
+	  ASTERISK-16930) (closes issue ASTERISK-19281) Reported by:
+	  Patrick El Youssef Patches: ASTERISK-19281.diff uploaded by
+	  Walter Doekes (license 5674) ........ Merged revisions 353769
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 353771 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Use ast_sockaddr_stringify_fmt wrappers
+	  for various functions in chan_sip There are a number of cleaner
+	  looking wrappers for ast_sockaddr_stringify_fmt available which
+	  are slightly more readable than using a direct call to
+	  ast_sockaddr_stringify_fmt. This patch switches a number of those
+	  calls in chan_sip to use those wrappers and is generally
+	  harmless. (Closes issue ASTERISK-16930) Reported by: Michael L.
+	  Young Patches: chan_sip-broken-registration-1.8.diff uploaded by
+	  Michael L. Young (license 5026) ........ Merged revisions 353720
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 353721 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-01 19:53 +0000 [r353647-353685]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_unistim.c, channels/chan_multicast_rtp.c,
+	  channels/chan_local.c, addons/chan_ooh323.c,
+	  channels/chan_vpb.cc, channels/chan_gtalk.c,
+	  channels/chan_iax2.c, main/channel.c, channels/chan_phone.c,
+	  channels/chan_dahdi.c, channels/sig_analog.c, main/manager.c,
+	  pbx/pbx_spool.c, channels/chan_skinny.c, main/features.c,
+	  channels/sig_analog.h, channels/chan_alsa.c,
+	  apps/app_confbridge.c, addons/chan_mobile.c, channels/sig_ss7.c,
+	  channels/chan_mgcp.c, main/pbx.c, channels/sig_ss7.h,
+	  channels/chan_sip.c, channels/chan_bridge.c,
+	  channels/chan_agent.c, include/asterisk/channel.h,
+	  channels/chan_console.c, channels/sig_pri.c, channels/chan_oss.c,
+	  channels/chan_usbradio.c, channels/chan_jingle.c,
+	  channels/sig_pri.h, channels/chan_misdn.c, channels/chan_h323.c,
+	  channels/chan_nbs.c, include/asterisk/pbx.h: Constify some more
+	  channel driver technology callback parameters. Review:
+	  https://reviewboard.asterisk.org/r/1707/
+
+	* cel/cel_pgsql.c, configs/cel_sqlite3_custom.conf.sample,
+	  cel/cel_odbc.c, configs/cel.conf.sample, cel/cel_manager.c,
+	  cel/cel_tds.c, configs/cel_pgsql.conf.sample,
+	  configs/cel_odbc.conf.sample, main/cel.c,
+	  configs/cel_custom.conf.sample: Remove inconsistency in CEL
+	  eventtype for user defined events. The CEL eventtype field for
+	  ODBC and PGSQL backends should be USER_DEFINED instead of the
+	  user defined event name supplied by the CELGenUserEvent
+	  application. If the field is output as a number, the user defined
+	  name does not have a value and is always output as 21 for
+	  USER_DEFINED and the userdeftype field would be required to
+	  supply the user defined name. The following CEL backends
+	  (cel_odbc, cel_pgsql, cel_custom, cel_manager, and
+	  cel_sqlite3_custom) can be independently configured to remove
+	  this inconsistency. * Allows cel_manager, cel_custom, and
+	  cel_sqlite3_custom to behave the same way. (closes issue
+	  ASTERISK-17189) Reported by: Bryant Zimmerman Review:
+	  https://reviewboard.asterisk.org/r/1669/
+
+	* main/channel.c, include/asterisk/channel.h: Fix ExtenSpy and
+	  simplify the channel search functions. When ast_channel name was
+	  opaquified, the channel search functions did not get converted
+	  correctly. As a result ExtenSpy which uses a channel iterator
+	  search by exten at context could never find anything. * Updated the
+	  doxygen documentation for the search functions in channel.h.
+	  Review: https://reviewboard.asterisk.org/r/1702/
+
+2012-02-01 15:59 +0000 [r353600]  Sean Bright <sean at malleable.com>
+
+	* /, include/asterisk/audiohook.h: Resolve an overlap in the
+	  ast_audiohook_flags values. AST_AUDIOHOOK_TRIGGER_WRITE and
+	  AST_AUDIOHOOK_WANTS_DTMF were overlapping which may have caused
+	  unintended side effects. This patch moves
+	  AST_AUDIOHOOK_TRIGGER_WRITE, and updates
+	  AST_AUDIOHOOK_TRIGGER_MODE to reflect the original intention.
+	  This will affect existing modules that use these flags, so be
+	  sure to recompile as necessary. (closes issue ASTERISK-19246)
+	  Reported by: feyfre ........ Merged revisions 353598 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353599 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/rtp_engine.c, /, include/asterisk/rtp_engine.h: rtp_engine:
-	  fix rtp payloads copy and improve argument names In function
-	  ast_rtp_instance_early _bridge_make_compatible the use of
-	  instance 0/1 as arguments doesn't clearly communicate a direction
-	  that the copying of payloads from the source channel to the
-	  destination channel will occur, making it more probable to have
-	  the arguments to ast_rtp_codecs_payloads_copy() put in the
-	  reverse order. This patch renames the arguments with _dst and
-	  _src suffixes and corrects the copy direction. (closes issue
-	  ASTERISK-21464) Reported by: Kevin Stewart Review:
-	  https://reviewboard.asterisk.org/r/2894/ ........ Merged
-	  revisions 402000 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 Test shows
-	  rtpmap:119 being copied per this change, but is not in sip invite
-	  ........ Merged revisions 402042 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 402043 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-25 23:58 +0000 [r402004-402045]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/taskprocessor.c: taskprocessor: Made use pthread_equal()
-	  to compare thread ids. * Removed another silly use of RAII_VAR().
-	  RAII_VAR() and SCOPED_LOCK() are not silver bullets that allow
-	  you to turn off your brain. ........ Merged revisions 402044 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/stasis/app.c: You'd think that new files would be free of
-	  whitespace issues. But you would be wrong. ........ Merged
-	  revisions 402003 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-25 22:01 +0000 [r401999-402002]  Jonathan Rose <jrose at digium.com>
-
-	* res/ari/resource_bridges.c, res/res_ari_bridges.c, /,
-	  rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c, rest-api/api-docs/bridges.json: ARI:
-	  channel/bridge recording errors when invalid format specified
-	  Asterisk will now issue 422 if recording is requested against
-	  channels or bridges with an unknown format (closes issue
-	  ASTERISK-22626) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/2939/ ........ Merged
-	  revisions 402001 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_recording.c, rest-api/api-docs/channels.json,
-	  res/ari/resource_channels.c, res/ari/ari_model_validators.c,
-	  res/res_ari_channels.c, rest-api/api-docs/bridges.json,
-	  rest-api/api-docs/recordings.json, res/ari/resource_bridges.c,
-	  res/ari/ari_model_validators.h, res/res_ari_bridges.c,
-	  rest-api/api-docs/events.json, /: ARI recordings: Issue HTTP
-	  failures for recording requests with file conflicts If a file
-	  already exists in the recordings directory with the same name as
-	  what we would record, issue a 422 instead of relying on the
-	  internal failure and issuing success. (closes issue
-	  ASTERISK-22623) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/2922/ ........ Merged
-	  revisions 401973 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-25 20:51 +0000 [r401962]  Scott Griepentrog <sgriepentrog at digium.com>
+2012-02-01 15:07 +0000 [r353552]  Matthew Jordan <mjordan at digium.com>
 
-	* include/asterisk/pbx.h, main/pbx.c, /: pbx.c: fix confused match
-	  caller id that deleted exten still in hash This fixes a bug where
-	  a zero length callerid match adjacent to a no match callerid
-	  extension entry would be deleted together, which then resulted in
-	  hashtable references to free'd memory. A third state of the
-	  matchcid value has been added to indicate match to any extension
-	  which allows enforcing comparison of matchcid on/off without
-	  errors. (closes issue AST-1235) Reported by: Guenther Kelleter
-	  Review: https://reviewboard.asterisk.org/r/2930/ ........ Merged
-	  revisions 401959 from
+	* /, contrib/init.d/etc_default_asterisk: Added clarification for
+	  the VERBOSITY setting to etc_default_asterisk Clarified that
+	  using the VERBOSITY setting in etc_default_asterisk is the same
+	  as using the -v command line switch, which causes Asterisk to
+	  launch in console mode. (closes issue ASTERISK-17030) Reported
+	  by: Jonas ........ Merged revisions 353550 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401960 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401961 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-25 17:41 +0000 [r401898-401939]  Jonathan Rose <jrose at digium.com>
-
-	* /, res/res_pjsip/pjsip_distributor.c,
-	  res/res_pjsip_endpoint_identifier_user.c: PJSIP: Add log messages
-	  when requests are received for non-existent endpoints (closes
-	  issue ASTERISK-22552) Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/2934/ ........ Merged
-	  revisions 401938 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* utils/clicompat.c, utils/refcounter.c, /: Put clicompat-r2.patch
-	  back in We've figured out how to resolve the problems this was
-	  causing in 12/trunk, so this can go back in now. (issue
-	  ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  clicompat-r2.patch uploaded by coreyfarrell (license 5909)
-	  ........ Merged revisions 401914 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401935 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401936 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, utils/clicompat.c: revert clicompat-r2.patch from r401704
-	  Patch caused the following build errors against testsuite
-	  https://bamboo.asterisk.org/bamboo/browse/AST-ATRUNKBUILD4-244
-	  (issue ASTERISK-22467) Reported by: Corey Farrell ........ Merged
-	  revisions 401895 from
+	  revisions 353551 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-02-01 00:08 +0000 [r353504]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_calendar.c: Allow res_calendar to be unloaded The
+	  calendaring tech modules depend on res_calendar and initially
+	  res_calendar just bumped the use count so that it couldn't be
+	  unloaded. res_calendar can potentially create many threads and
+	  I've seen issues where the Asterisk shutdown has failed where it
+	  looked like these threads could be the culprit. This patch adds
+	  unload support for res_calendar. Unloading res_calendar will also
+	  unload the dependant tech modules as well. (closes issue
+	  ASTERISK-16744) Review: https://reviewboard.asterisk.org/r/1657/
+	  ........ Merged revisions 353502 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353503 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-31 17:26 +0000 [r353466]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /, include/asterisk/channel.h: Fix memory leak in
+	  error paths for action_originate(). * Fix memory leak of vars in
+	  error paths for action_originate(). * Moved struct
+	  fast_originate_helper tech and data members to stringfields. *
+	  Simplified ActionID header handling for fast_originate(). * Added
+	  doxygen note to ast_request() and ast_call() and the associated
+	  channel callbacks that the data/addr parameters should be treated
+	  as const char *. Review: https://reviewboard.asterisk.org/r/1690/
+	  ........ Merged revisions 353454 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353463 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-30 23:58 +0000 [r353418]  Terry Wilson <twilson at digium.com>
+
+	* main/dnsmgr.c, /, channels/chan_sip.c, include/asterisk/dnsmgr.h:
+	  Re-link peers by IP when dnsmgr changes the IP Asterisk's dnsmgr
+	  currently takes a pointer to an ast_sockaddr and updates it
+	  anytime an address resolves to something different. There are a
+	  couple of issues with this. First, the ast_sockaddr is usually
+	  the address of an ast_sockaddr inside a refcounted struct and we
+	  never bump the refcount of those structs when using dnsmgr. This
+	  makes it possible that a refresh could happen after the
+	  destructor for that object is called (despite ast_dnsmgr_release
+	  being called in that destructor). Second, the module using dnsmgr
+	  cannot be aware of an address changing without polling for it in
+	  the code. If an action needs to be taken on address update (like
+	  re-linking a SIP peer in the peers_by_ip table), then polling for
+	  this change negates many of the benefits of having dnsmgr in the
+	  first place. This patch adds a function to the dnsmgr API that
+	  calls an update callback instead of blindly updating the address
+	  itself. It also moves calls to ast_dnsmgr_release outside of the
+	  destructor functions and into cleanup functions that are called
+	  when we no longer need the objects and increments the refcount of
+	  the objects using dnsmgr since those objects are stored on the
+	  ast_dnsmgr_entry struct. A helper function for returning the
+	  proper default SIP port (non-tls vs tls) is also added and used.
+	  This patch also incorporates changes from a patch posted by Timo
+	  Teräs to ASTERISK-19106 for related dnsmgr issues. (closes issue
+	  ASTERISK-19106) Review: https://reviewboard.asterisk.org/r/1691/
+	  ........ Merged revisions 353371 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401896 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401897 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 353397 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-30 22:44 +0000 [r353347-353370]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_sip.c: Merged revisions 353369 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r353369 | alecdavis | 2012-01-31 11:42:28 +1300
+	  (Tue, 31 Jan 2012) | 9 lines Merged revisions 353368 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r353368 | alecdavis | 2012-01-31 11:40:40 +1300 (Tue, 31
+	  Jan 2012) | 2 lines prevent debug messsges displaying -ve Cseq
+	  numbers. Missed in R353320 ........ ................
+
+	* channels/sip/include/dialog.h, /, channels/chan_sip.c,
+	  channels/sip/include/sip.h: Merged revisions 353321 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r353321 | alecdavis | 2012-01-31 11:16:22 +1300
+	  (Tue, 31 Jan 2012) | 25 lines Merged revisions 353320 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r353320 | alecdavis | 2012-01-31 10:57:49 +1300 (Tue, 31 Jan
+	  2012) | 18 lines RFC3261 Section 8.1.1.5. The sequence number
+	  value MUST be expressible as a 32-bit unsigned integer * fix: use
+	  %u instead of %d when dealing with CSeq numbers - to remove
+	  possibility of -ve numbers. * fix: change all uses of seqno and
+	  friends (ocseq icseq) from 'int' or 'unsigned int' to uint32_t.
+	  Summary of CSeq numbers. An initial CSeq number must be less than
+	  2^31 A CSeq number can increase in value up to 2^32-1 An
+	  incrementing CSeq number must not wrap around to 0. Tested with
+	  Asterisk 1.8.8.2 with Grandstream phones. alecdavis (license 585)
+	  Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1699/ ........
+	  ................
+
+2012-01-30 21:34 +0000 [r353262-353319]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* Makefile: Correct serious flaw in the top-level Makefile.
+
+	* include/asterisk.h, /, main/Makefile, main/libasteriskssl.c
+	  (added), configure.ac, Makefile.moddir_rules, main/ssl.c
+	  (removed), addons, CHANGES, include/asterisk/optional_api.h,
+	  Makefile, build_tools/mkpkgconfig, configure, main, makeopts.in,
+	  build_tools/make_defaults_h, main/libasteriskssl.exports.in
+	  (added): Address OpenSSL initialization issues when using
+	  third-party libraries. When Asterisk is used with various
+	  third-party libraries (CURL, PostgresSQL, many others) that have
+	  the ability themselves to use OpenSSL, it is possible for
+	  conflicts to arise in how the OpenSSL libraries are initialized
+	  and shutdown. This patch addresses these conflicts by 'wrapping'
+	  the important functions from the OpenSSL libraries in a new
+	  shared library that is part of Asterisk itself, and is loaded in
+	  such a way as to ensure that *all* calls to these functions will
+	  be dispatched through the Asterisk wrapper functions, not the
+	  native functions. This new library is optional, but enabled by
+	  default. See the CHANGES file for documentation on how to disable
+	  it. Along the way, this patch also makes a few other minor
+	  changes: * Changes MODULES_DIR to ASTMODDIR throughout the build
+	  system, in order to more closely match what is used during
+	  run-time configuration. * Corrects some errors in the configure
+	  script where AC_CHECK_TOOLS was used instead of AC_PATH_PROG. *
+	  Adds a new variable for linker flags in the build system
+	  (DYLINK), used for producing true shared libraries (as opposed to
+	  the dynamically loadable modules that the build system produces
+	  for 'regular' Asterisk modules). * Moves the Makefile bits that
+	  handle installation and uninstallation of the main Asterisk
+	  binary into main/Makefile from the top-level Makefile. * Moves a
+	  couple of useful preprocessor macros from optional_api.h to
+	  asterisk.h. Review: https://reviewboard.asterisk.org/r/1006/
+
+	* /, channels/chan_sip.c: Clarify log WARNING message when
+	  port-zero SDP 'm' lines received. Previously, if an m-line in an
+	  SDP offer or answer had a port number of zero, that line was
+	  skipped, and resulted in an 'Unsupported SDP media type...'
+	  warning message. This was misleading, as the media type was not
+	  unsupported, but was ignored because the m-line indicated that
+	  the media stream had been rejected (in an answer) or was not
+	  going to be used (in an offer). ........ Merged revisions 353260
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 353261 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-25 16:09 +0000 [r401886]  Kevin Harwell <kharwell at digium.com>
+2012-01-29 22:33 +0000 [r353224]  Damien Wedhorn <voip at facts.com.au>
 
-	* /, channels/chan_sip.c: chan_sip: Allow a sip peer to accept both
-	  AVP and AVPF calls Adapts the behaviour of avpf to only impact
-	  the format of outgoing calls. For inbound calls, both AVP and
-	  AVPF calls will be accepted regardless of the value of avpf in
-	  the configuration. (closes issue ASTERISK-22005) Reported by:
-	  Torrey Searle Patches: optional_avpf_trunk.patch uploaded by
-	  tsearle (license 5334) ........ Merged revisions 401884 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401885 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-25 13:49 +0000 [r401873]  David M. Lee <dlee at digium.com>
-
-	* tests/test_json.c, /: test_json: Fix deprecation warnings After a
-	  series of upgrades over recent weeks, I've discovered that
-	  test_json.c won't compile in dev mode any more for me. One of
-	  gcc-4.8.2, OS X Mavericks or Xcode 5 has decided to deprecate
-	  tempnam. Which, in general, is a good thing. But for test code
-	  that just needs a temporary file, it's just annoying. This patch
-	  replaces usage of tempname with mkstemp, avoiding the deprecation
-	  warning. It also removes the temporary files when the test is
-	  complete, which apparently we weren't doing before (oops).
-	  Review: https://reviewboard.asterisk.org/r/2957/ ........ Merged
-	  revisions 401872 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-24 21:06 +0000 [r401836]  Kevin Harwell <kharwell at digium.com>
-
-	* /, main/logger.c: Logging: Logging types ignored after specifying
-	  a verbose level If one specified a verbose level within a logging
-	  facility in logger.conf then any component after it was ignored.
-	  Fixed so all values are correctly read. (closes issue
-	  ASTERISK-22456) Reported by: Kevin Harwell ........ Merged
-	  revisions 401833 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401835 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-24 20:48 +0000 [r401834]  David M. Lee <dlee at digium.com>
-
-	* rest-api-templates/models.wiki.mustache,
-	  rest-api/api-docs/events.json, /,
-	  rest-api-templates/swagger_model.py,
-	  rest-api-templates/ari_model_validators.c.mustache: The Swagger
-	  1.2 specification for type extension ended up being slightly
-	  different than my proposal. Instead of putting an 'extends' field
-	  on the subtype, the base type has a 'subTypes' field, which is a
-	  list of the subTypes. Given that its a messaging model and not an
-	  object model, kinda makes sense. This patch changes the
-	  events.json api-doc, and the python translators to take the new
-	  format into account. Other changes that are in Swagger 1.2 were
-	  not adopted, since the spec is still in flux, and could change
-	  before it's finalized. A summary of changes to the Swagger-1.2
-	  spec can be found at
-	  https://github.com/wordnik/swagger-core/wiki/1.2-transition.
-	  (closes issue ASTERISK-22440) Review:
-	  https://reviewboard.asterisk.org/r/2909/ ........ Merged
-	  revisions 401701 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-24 20:34 +0000 [r401622-401832]  Jonathan Rose <jrose at digium.com>
+	* channels/chan_skinny.c: Allow softkey reject while device onhook.
+	  Fixes up softkey endcall. Previous code was a copy of onhook, now
+	  allows for endcall softkey to be used while device is still
+	  onhook.
 
-	* /, main/utils.c: utils: Fix memory leaks and missed
-	  unregistration of CLI commands on shutdown Final set of patches
-	  in a series of memory leak/cleanup patches by Corey Farrell
-	  (closes issue ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  main-utils-1.8.patch uploaded by coreyfarrell (license 5909)
-	  main-utils-11.patch uploaded by coreyfarrell (license 5909)
-	  main-utils-12up.patch uploaded by coreyfarrell (license 5909)
-	  ........ Merged revisions 401829 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401830 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401831 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-01-29 02:45 +0000 [r353177]  Russell Bryant <russell at russellbryant.com>
 
-	* /, tests/test_linkedlists.c: test_linkedlists: Fix memory leak
-	  (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  test_linkedlists-1.8.patch uploaded by coreyfarrell (license
-	  5909) test_linkedlists-11up.patch uploaded by coreyfarrell
-	  (license 5909) ........ Merged revisions 401790 from
+	* /, main/netsock.c: Find even more network interfaces. The
+	  previous change made the code look for emN and pciN in addition
+	  to what it did originally, which was search for ethN. However, it
+	  needed to be looking for pciN#N, so that's what it does now. This
+	  also moves the memset() to be before every ioctl(). ........
+	  Merged revisions 353175 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401791 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401792 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 353176 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/jitterbuf.c: jitterbuf: Fix memory leak on jitter buffer
-	  reset (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  jitterbuf-jb_reset-leak-1.8.patch
-	  jitterbuf-jb_reset-leak-11up.patch ........ Merged revisions
-	  401786 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 401787 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401788 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2012-01-28 14:52 +0000 [r353128]  Kevin P. Fleming <kpfleming at digium.com>
 
-	* main/astobj2.c, /: astobj2: Unregister debug CLI commands at exit
-	  (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  astobj2-clean-debug-cli-1.8-11.patch uploaded by coreyfarrell
-	  (license 5909) astobj2-clean-debug-cli-12up.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 401781 from
+	* main/rtp_engine.c, /: Add 'L16-256' MIME subtype alias for
+	  slin16. Asterisk has supported the 'L16' MIME subtype for 16kHz
+	  signed linear (PCM) audio for quite some time, but some endpoints
+	  refer to it as 'L16-256'. This commit adds this as an alias for
+	  the existing format. ........ Merged revisions 353126 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353127 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-28 04:31 +0000 [r353079]  Russell Bryant <russell at russellbryant.com>
+
+	* /, main/netsock.c: Update ast_set_default_eid() to find more
+	  network interfaces. As of Fedora 15, ethN is not the name of
+	  ethernet interfaces. The names are emN or pciN. Update some code
+	  that searched for interfaces named ethN to look for the new
+	  names, as well. For more information about why this change was
+	  made, see this page: http://domsch.com/blog/?p=455 ........
+	  Merged revisions 353077 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 353078 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-27 21:38 +0000 [r352996-353040]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_queue.c: Audit of ao2_iterator_init() usage for v10.
+	  Missed one. ........ Merged revisions 353039 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, tests/test_format_api.c: Audit of ao2_iterator_init() usage
+	  for v10. Fix double format_cap iterator cleanup. ........ Merged
+	  revisions 352992 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-27 19:26 +0000 [r352981]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_monitor.c: Make failed PauseMonitor and UnpauseMonitor
+	  with no valid channel not close AMI session. I also went ahead
+	  and took a little time to make sure that the manager value
+	  AMI_SUCCESS was used instead of just return 0 being thrown around
+	  everywhere since that's how we handle this stuff these days.
+	  (closes issue ASTERISK-19249) Reporter: Jamuel Starkey Patches:
+	  res_monitor.c-ASTERISK-19249.diff uploaded by Jamuel Starkey
+	  (license 5766) ........ Merged revisions 352959 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352965 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-27 18:47 +0000 [r352957]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /, channels/chan_sip.c,
+	  include/asterisk/indications.h, res/snmp/agent.c,
+	  main/taskprocessor.c, apps/app_queue.c, channels/chan_iax2.c,
+	  apps/app_chanspy.c, main/indications.c, res/res_odbc.c,
+	  res/res_srtp.c: Audit of ao2_iterator_init() usage for v1.8.
+	  Fixes numerous reference leaks and missing ao2_iterator_destroy()
+	  calls as a result. Review:
+	  https://reviewboard.asterisk.org/r/1697/ ........ Merged
+	  revisions 352955 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352956 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-27 15:57 +0000 [r352916]  Terry Wilson <twilson at digium.com>
+
+	* res/res_calendar_exchange.c, res/res_calendar_caldav.c,
+	  res/res_calendar.c: Add aresult variable for CALENDAR_WRITE This
+	  patch adds a CALENDAR_SUCCESS=1/0 variable that is set to show
+	  whether or not CALENDAR_WRITE has passed. This patch also adds
+	  some debugging for caldav PUT responses and no longer treats
+	  responses with no body as an error (as a PUT gets a 201 Created
+	  with no body). (closes issue ASTERISK-16903) Reported by: Clod
+	  Patry Tested by: Terry Wilson Patches: calendarstatus.diff
+	  uploaded by Clod Patry (License #5138), slightly modified by
+	  Terry Wilson Review: https://reviewboard.asterisk.org/r/1692/ -
+	  This line, and those below, will be ignored-- M
+	  res/res_calendar.c M res/res_calendar_exchange.c M
+	  res/res_calendar_caldav.c
+
+2012-01-27 00:11 +0000 [r352864]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Merged
+	  revisions 352863 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r352863 | alecdavis | 2012-01-27 13:08:03 +1300
+	  (Fri, 27 Jan 2012) | 19 lines Merged revisions 352862 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r352862 | alecdavis | 2012-01-27 13:05:30 +1300 (Fri, 27 Jan
+	  2012) | 12 lines rfc4235 - Section 4.1: Versions MUST be
+	  representable using a non-negative 32 bit integer. If a BLF
+	  subscription exists for long enough, using %d may print negative
+	  version numbers. Unlikely, as 2^32 at 1 update per second is ~137
+	  years, or half that before the versions number started going
+	  negative. Tested with Asterisk 1.8.8.2 with Grandstream phones.
+	  alecdavis (license 585) Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1694/ ........
+	  ................
+
+2012-01-26 20:44 +0000 [r352821]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: Fix outbound DTMF for inband mode (tell
+	  asterisk core to generate DTMF sounds). (Closes issue
+	  ASTERISK-19233) Reported by: Matt Behrens Patches:
+	  chan_ooh323.c.patch uploaded by Matt Behrens (License #6346)
+	  ........ Merged revisions 352807 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352817 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-26 19:09 +0000 [r352757]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Copy amaflags to sip_pvt from peer during
+	  create_addr_from_peer For whatever reason, we don't have a single
+	  function for copying data like this from SIP peers to the SIP
+	  pvt. This patch adds the copying of amaflags to the sip_pvt, but
+	  it would probably be worth discussing this function along with
+	  the others that essentially just copy some amount of data from a
+	  peer to a private. (Closes issue ASTERISK-19029) Reported by:
+	  Matt Lehner ........ Merged revisions 352755 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352756 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-26 06:36 +0000 [r352706]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, channels/chan_sip.c: Merged revisions 352705 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r352705 | alecdavis | 2012-01-26 19:33:11 +1300
+	  (Thu, 26 Jan 2012) | 27 lines Merged revisions 352704 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r352704 | alecdavis | 2012-01-26 19:27:07 +1300 (Thu, 26 Jan
+	  2012) | 20 lines Cleanup dialog-info+xml Notify dialog Make
+	  similar to other Notify messages. sample output: <?xml
+	  version="1.0"?> <dialog-info
+	  xmlns="urn:ietf:params:xml:ns:dialog-info" version="715"
+	  state="full" entity="sip:8523 at 192.168.x.xx"> <dialog id="8523">
+	  <state>terminated</state> </dialog> </dialog-info> Tested with
+	  Asterisk 1.8.8.2 with Grandstream phones. alecdavis (license 585)
+	  Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1693/ ........
+	  ................
+
+2012-01-25 22:25 +0000 [r352659]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, apps/app_voicemail.c: Fix -Werror=unused-but-set-variable
+	  compiler error (gcc 4.6.2) ........ Merged revisions 352643 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401783 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401784 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 352651 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-25 21:31 +0000 [r352626]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* Makefile, include/asterisk/version.h (added), main/test.c,
+	  build_tools/make_version_h (removed), include/asterisk: Remove
+	  "asterisk/version.h" in favor of "asterisk/ast_version.h". A long
+	  time ago, in a land far far away, we added
+	  "asterisk/ast_version.h", which provides the ast_get_version()
+	  and ast_get_version_num() functions. These were added so that
+	  modules that needed the version information for the Asterisk
+	  instance they were loaded in could actually get it (as opposed
+	  the version that they were compiled against). We changed
+	  everything in the tree to use the new mechanism (although later
+	  main/test.c was added using the old method). However, the old
+	  mechanism was never removed, and as a result, new code is still
+	  trying to use it. This commit removes asterisk/version.h and
+	  replaces it with a header that will generate a compile-time error
+	  if you try to use it (the error message tells you which header
+	  you should use instead). It also removes the Makefile and
+	  build_tools bits that generated the file, and it updates
+	  main/test.c to use the 'proper' method of getting the Asterisk
+	  version information. This is an API change and thus is being
+	  committed for trunk only, but it's a fairly minor one and
+	  definitely improves the situation for out-of-tree modules.
+
+2012-01-25 17:33 +0000 [r352565]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Remove some extraneous debugging from
+	  registry memleak fix ........ Merged revisions 352551 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352556 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-25 17:23 +0000 [r352538]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c, CHANGES, main/message.c,
+	  channels/sip/include/sip.h: Fixes for sending SIP MESSAGE outside
+	  of calls. * Fix authenticate MESSAGE losing custom headers added
+	  by the MESSAGE_DATA function in the authorization attempt. * Pass
+	  up better From header contents for SIP to use. Now is in the
+	  "display-name" <URI> format expected by MessageSend. (Note that
+	  this is a behavior change that could concievably affect some
+	  people.) * Block user from adding standard headers that are added
+	  automatically. (To, From,...) * Allow the user to override the
+	  Content-Type header contents sent by MessageSend. * Decrement
+	  Max-Forwards header if the user transferred it from an incoming
+	  message. * Expand SIP short header names so the dialplan and
+	  other code only has to deal with the full names. * Documents what
+	  SIP expects in the MessageSend(from) parameter. (closes issue
+	  ASTERISK-18992) Reported by: Yuri (closes issue ASTERISK-18917)
+	  Reported by: Shaun Clark Review:
+	  https://reviewboard.asterisk.org/r/1683/ ........ Merged
+	  revisions 352520 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-25 17:02 +0000 [r352519]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Clean up some SIP registry-related memory
+	  leaks 1) Be sure and free at unload the epa_backend we allocate
+	  at startup 2) Do the same sip_registry cleanup at unload we do at
+	  reload Review: https://reviewboard.asterisk.org/r/1689/ ........
+	  Merged revisions 352514 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352515 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-25 16:54 +0000 [r352517]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* main/format.c, /, main/format_cap.c, main/format_pref.c:
+	  Eliminate unnecessary rebuilds of main/format*.c. These files
+	  have no need to include "asterisk/version.h", and doing so forces
+	  them to be rebuilt each time a Subversion checkout moves between
+	  'modified' and 'unmodified' states. ........ Merged revisions
+	  352516 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-25 16:42 +0000 [r352513]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/sip.conf.sample: Redocuments sip types peer, user,
+	  friend in sip.conf.sample There was faulty information in the
+	  sample config describing user as a synonym for friend so it has
+	  been changed to better elaborate on the differences between the
+	  three entity types. (closes issue ASTERISK-15537) Reported by:
+	  yarique ........ Merged revisions 352511 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352512 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/app_voicemail.c, /: app_voicemail: Memory Leaks against
-	  tests (issue ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  app_voicemail-1.8.patch uploaded by coreyfarrell (license 5909)
-	  app_voicemail-11up.patch uploaded by coreyfarrell (license 5909)
-	  ........ Merged revisions 401743 from
+2012-01-25 01:21 +0000 [r352475]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_vpb.cc: Fix channel opaquification of stringfields
+	  for chan_vpb
+
+2012-01-24 22:28 +0000 [r352431]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Don't do a DNS lookup on an outbound
+	  REGISTER host if there is an outbound proxy configured. (closes
+	  issue ASTERISK-16550) reported by: Olle Johansson ........ Merged
+	  revisions 352424 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401744 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401745 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/app.c, main/asterisk.c, utils/clicompat.c,
-	  channels/chan_dahdi.c, codecs/ilbc/doCPLC.c, main/data.c, /:
-	  memory leaks: Memory leak cleanup patch by Corey Farrell (second
-	  set) Also covers ast_app_parse_timelen-fail-zero-length.patch,
-	  but the patch was replaced with one of my own. (issue
-	  ASTERISK-22467) Reported by: Corey Farrell Patches:
-	  chan_dahdi-cleanup_push.patch uploaded by coreyfarrell (license
-	  5909) clicompat-r2.patch uploaded by coreyfarrell (license 5909)
-	  codecs-ilbc-doCPLC.patch uploaded by coreyfarrell (license 5909)
-	  data-cleanup-test-registration.patch uploaded by coreyfarrell
-	  (license 5909) main-asterisk-kill-listener.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 401704 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401705 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401706 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, tests/test_dlinklists.c, funcs/func_math.c,
-	  channels/sip/reqresp_parser.c, main/test.c,
-	  main/editline/readline.c: memory leaks: Memory leak cleanup patch
-	  by Corey Farrell (first set) (issue ASTERSIK-22467) Reported by:
-	  Corey Farrell Patches:
-	  chan_sip-parse_contact_header_test-free-contacts.patch uploaded
-	  by coreyfarrell (license 5909) cli-filename-completion-leak.patch
-	  uploaded by coreyfarrell (license 5909) func_math.patch uploaded
-	  by corefarrell (license 5909) main-test-cleanup.patch uploaded by
-	  coreyfarrell (license 5909) test_dlinklists.patch uploaded by
-	  coreyfarrell (license 5909) ........ Merged revisions 401660 from
+	  revisions 352430 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-24 20:37 +0000 [r352377]  Jonathan Rose <jrose at digium.com>
+
+	* /, sounds/Makefile: Set core sounds version to 1.4.22. Now that
+	  we have the right license for the Russian 1.4.22 sounds as well
+	  as the sounds for the Australian English 1.4.22 sounds, we can
+	  finally set the sounds to use 1.4.22! (closes issue
+	  ASTERISK-18978) Reported by: Cameron Twomey Patches:
+	  confbridge.tar.001 uploaded by Cameron Twomey confbridge.tar.002
+	  uploaded by Cameron Twomey ........ Merged revisions 352367 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352373 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-24 20:12 +0000 [r352348]  Terry Wilson <twilson at digium.com>
+
+	* channels/chan_local.c, addons/chan_ooh323.c, main/say.c,
+	  apps/app_record.c, apps/app_sayunixtime.c, channels/chan_iax2.c,
+	  main/cli.c, channels/chan_dahdi.c, channels/sig_analog.c,
+	  channels/chan_skinny.c, main/features.c, apps/app_dumpchan.c,
+	  channels/chan_alsa.c, pbx/pbx_realtime.c, apps/app_externalivr.c,
+	  apps/app_dial.c, main/pbx.c, apps/app_page.c,
+	  channels/chan_bridge.c, apps/app_privacy.c,
+	  channels/chan_agent.c, apps/app_disa.c,
+	  include/asterisk/channel.h, main/aoc.c, apps/app_talkdetect.c,
+	  main/cel.c, res/res_monitor.c, apps/app_playback.c,
+	  apps/app_speech_utils.c, channels/chan_misdn.c,
+	  funcs/func_channel.c, apps/app_chanspy.c, apps/app_voicemail.c,
+	  channels/chan_unistim.c, channels/chan_multicast_rtp.c,
+	  apps/app_meetme.c, apps/app_dictate.c, apps/app_authenticate.c,
+	  apps/app_readexten.c, apps/app_userevent.c,
+	  res/res_musiconhold.c, channels/chan_gtalk.c,
+	  apps/app_followme.c, main/cdr.c, main/channel.c,
+	  channels/chan_phone.c, main/dial.c, main/manager.c,
+	  apps/app_minivm.c, res/res_agi.c, main/app.c,
+	  apps/app_confbridge.c, main/image.c, apps/app_directory.c,
+	  addons/chan_mobile.c, apps/app_rpt.c, channels/chan_mgcp.c,
+	  apps/app_parkandannounce.c, channels/chan_sip.c, res/res_fax.c,
+	  main/channel_internal_api.c, channels/chan_console.c,
+	  channels/sig_pri.c, apps/app_queue.c, channels/chan_oss.c,
+	  funcs/func_global.c, channels/chan_jingle.c,
+	  channels/chan_usbradio.c, channels/chan_h323.c, main/file.c,
+	  res/snmp/agent.c, channels/chan_nbs.c, apps/app_stack.c,
+	  addons/app_saycountpl.c: Opaquify channel stringfields Continue
+	  channel opaque-ification by wrapping all of the stringfields.
+	  Eventually, we will restrict what can actually set these
+	  variables, but the purpose for now is to hide the implementation
+	  and keep people from adding code that directly accesses the
+	  channel structure. Semantic changes will follow afterward.
+	  Review: https://reviewboard.asterisk.org/r/1661/
+
+2012-01-24 17:04 +0000 [r352293]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_odbc.c: Fix locking issues with channel datastores
+	  in func_odbc.c. * Fixed a potential memory leak when an existing
+	  datastore is manually destroyed by inline code instead of calling
+	  ast_datastore_free(). (closes issue ASTERISK-17948) Reported by:
+	  Archie Cobbs Review: https://reviewboard.asterisk.org/r/1687/
+	  ........ Merged revisions 352291 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401661 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401662 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 352292 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, main/translate.c, res/res_rtp_asterisk.c: res_rtp_asterisk:
-	  Address jittery DTMF events in RTP streams (closes issue
-	  ASTERISK-21170) Reported by: NITESH BANSAL Patches:
-	  dtmf-timestamp.patch uploaded by NITESH BANSAL (license 6418)
-	  Review: https://reviewboard.asterisk.org/r/2938/ ........ Merged
-	  revisions 401619 from
+2012-01-23 20:31 +0000 [r352229-352232]  Mark Michelson <mmichelson at digium.com>
+
+	* /, main/features.c: Fix grammar of comment. ........ Merged
+	  revisions 352230 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401620 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401621 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 352231 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/features.c: Fix blind transfers from failing if an 'h'
+	  extension is present. This prevents the 'h' extension from being
+	  run on the transferee channel when it is transferred via a native
+	  transfer mechanism such as SIP REFER. (closes ASTERISK-19173)
+	  Reported by: Ross Beer Tested by: Kristjan Vrban Patches:
+	  ASTERISK-19173 by Mark Michelson (license 5049) Review:
+	  https://reviewboard.asterisk.org/r/1685 ........ Merged revisions
+	  352199 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 352228 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-23 19:22 +0000 [r352166]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_fax_spandsp.c: Correctly apply FAXOPT settings (V17,
+	  V27, V29) before starting spandsp layer While the FAXOPT function
+	  could be used to set the modem capabilities, the input to that
+	  function was not being applied correctly to the spandsp layer.
+	  This patch applies the current model capabilities before starting
+	  the spandsp layer. (closes issue: ASTERISK-16409) Reported by:
+	  Kristijan Vrban Tested by: Matt Jordan, Matthew Nicholson
+	  Patches: spandsp-modems-1.8.diff uploaded by mnicholson (license
+	  5081) spandsp-modems-10.diff uploaded by mnicholson (license
+	  5081) ........ Merged revisions 352144 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352149 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-23 18:34 +0000 [r352093-352134]  Jonathan Rose <jrose at digium.com>
+
+	* configs/musiconhold.conf.sample, res/res_musiconhold.c, CHANGES:
+	  Add an announcement option to music-on-hold - plays sound when
+	  put on hold/between songs This is a feature patch which allows an
+	  'announcement' option to be specified in musiconhold.conf which
+	  should be set to the name of a sound. If a valid sound is
+	  specified for this option, then it will be played on that music
+	  on hold class whenever a channel bound to that class is put on
+	  hold as well as when Asterisk is able to detect that a song has
+	  ended before starting the next song (excludes external players).
+	  (closes ASTERISK-18977) Reported by: Timo Teräs Patches:
+	  asterisk-moh-announcement.diff uploaded by Timo Teräs (license
+	  5409)
+
+	* CHANGES, apps/app_mixmonitor.c: Adds the ability to stop specific
+	  mixmonitors by using unique IDs set at monitor launch. MixMonitor
+	  receives a new option i(channel_variable) which stores the unique
+	  id at said variable. StopMixMonitor now accepts ID as an optional
+	  argument, which if included will make StopMixMonitor specifically
+	  target the mixmonitor on that particular channel. CLI commands
+	  and AMI actions have been ammended to work with the IDs as well.
+	  In addition, monitors across a channel can now be listed be
+	  listed via CLI command "mixmonitor list <channel>" which will
+	  display all of the mixmonitors active on that channel along with
+	  the files they each have open. Created by Sergio González Martín.
+	  (closes issue ASTERISK-19096) Reported by: Sergio González Martín
+	  Review: https://reviewboard.asterisk.org/r/1643/ Review:
+	  https://reviewboard.asterisk.org/r/1682/
+
+2012-01-23 17:36 +0000 [r352092]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix sip_cfg.notifycid to be set with the
+	  defined enum values. The invalid value used when notifycid was
+	  enabled was benign. As far as the code was concerned -1 and 1 are
+	  equivalent. (closes issue ASTERISK-19232) Reported by: Eike
+	  Kuiper ........ Merged revisions 352090 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352091 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-21 00:23 +0000 [r352041]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_timeout.c, main/app.c: Fix ast_app_dtget() time
+	  unit inconsistency. Note: Noone calls ast_app_dtget() with the
+	  timeout parameter of zero so the bad code normally will never get
+	  executed. * Fix unnecessary floating point division in
+	  func_timeout.c timeout_write() when all other values are
+	  integers. (closes issue ASTERISK-16817) Reported by: Dmitry
+	  Andrianov ........ Merged revisions 352029 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352035 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-23 16:52 +0000 [r401582]  Richard Mudgett <rmudgett at digium.com>
+2012-01-21 00:11 +0000 [r352018-352019]  Mark Michelson <mmichelson at digium.com>
 
-	* /, cdr/cdr_adaptive_odbc.c: cdr_adaptive_odbc: Also apply a
-	  filter when the CDR value is empty. Extra CDR records are written
-	  if a filtered CDR value is empty because the filter is not
-	  checked. (closes issue ASTERISK-22272) Reported by: Jordi Llull
-	  Chavarria ........ Merged revisions 401577 from
+	* /, channels/chan_sip.c: Remove XXX comment that is not necessary.
+	  ........ Merged revisions 352016 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 352017 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Fix RTP reference leak. If a blind
+	  transfer were initiated using a REFER without a prior reINVITE to
+	  place the call on hold, AND if Asterisk were sending RTCP
+	  reports, then there was a reference for the RTP instance of the
+	  transferer. This fixes the issue by merging two similar but
+	  slightly conflicting sections of code into a single area. It also
+	  adds a stop_media_flows() call in the case that the transferer's
+	  UA never sends a BYE to us like it is supposed to. (issue
+	  ASTERISK-19192) Review: https://reviewboard.asterisk.org/r/1681/
+	  ........ Merged revisions 352014 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401581 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 352015 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-20 23:05 +0000 [r351977]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_sip.c: Make CLI sip show channel list the complete
+	  route set. (closes issue ASTERISK-16877) Reported by: klaus3000
+	  Patches: show-complete-routeset-patch.txt (license #5054) patch
+	  uploaded by klaus3000 (modified)
+
+2012-01-20 21:26 +0000 [r351939]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_sip.c, UPGRADE.txt: SIP session timeout AMI event
+	  Add an AMI event in the Call category that is issued when a call
+	  is terminated due to either RTP stream inactivity or SIP session
+	  timer expiration. Event description: Event: SessionTimeout
+	  Source: source Channel: channel-name Uniqueid: channel-unique-id
+	  `source` can be either RTPTimeout or SIPSessionTimer (closes
+	  issue ASTERISK-16467) Patch-by: Kirill Katsnelson
+
+2012-01-20 20:47 +0000 [r351900-351913]  Mark Michelson <mmichelson at digium.com>
+
+	* main/features.c, UPGRADE.txt, CHANGES,
+	  configs/features.conf.sample: Various parking improvements. *
+	  Adds per-parking lot options comebackcontext and comebackdialtime
+	  * Makes comebacktoorigin settable per parking lot * Sets a PARKER
+	  channel variable when comebacktoorigin is disabled (closes issue
+	  ASTERISK-16643) Reported by: Mitch Sharp (bluecrow76) Patches:
+	  asterisk-1.6.2.17.2-park-features-comebackcontext-consolidated-v3.diff
+	  by Mitch Sharp (bluecrow76) license 5231 with updates by me.
+	  Review: https://reviewboard.asterisk.org/r/1674 Review:
+	  https://reviewboard.asterisk.org/r/963 Reviewed by Richard
+	  Mudgett
+
+	* apps/app_mixmonitor.c: Prevent potential buffer overflow on AMI
+	  MixMonitor command. Don't be alarmed. This only affected trunk,
+	  and it would have required manager access to your system.
+
+2012-01-20 19:36 +0000 [r351817-351862]  Kinsey Moore <kmoore at digium.com>
+
+	* /, codecs/ilbc/iLBC_test.c: More corrections for the ilbc code
+	  These changes are in a file that is not compiled by default, and
+	  so were missed on earlier checks. ........ Merged revisions
+	  351860 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 351861 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, codecs/ilbc/LPCencode.c, codecs/ilbc/iLBC_decode.c: Restore
+	  LSF_check function calls from set/unused variable removal These
+	  functions are not noops and modify the array that is passed in.
+	  Thanks for the catch Richard. ........ Merged revisions 351818
+	  from http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, codecs/ilbc/LPCencode.c, codecs/ilbc/iLBC_decode.c: Remove
+	  more set, but unused variables in the ilbc codec GCC 4.6.3 caught
+	  these in dev mode as well. ........ Merged revisions 351816 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-20 16:00 +0000 [r351764]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Adds setting of mwi_from field to
+	  check_auth_result check_peer_ok (closes ASTERISK-19057) Reported
+	  By: Yuri Patches: 348360chan_sip.diff uploaded by Yuri (license
+	  5242) ........ Merged revisions 351759 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351762 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-23 16:48 +0000 [r401580]  John Bigelow <jbigelow at digium.com>
+2012-01-20 16:00 +0000 [r351763]  Matthew Jordan <mjordan at digium.com>
 
-	* /, main/bridge_channel.c: Add a test suite event to indicate when
-	  the atxfer 3-way feature is detected This adds a test suite event
-	  that indicates to tests when the attended transfer three-way call
-	  feature is detected. Review:
-	  https://reviewboard.asterisk.org/r/2912/ ........ Merged
-	  revisions 401578 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, codecs/ilbc/helpfun.c: Remove unused variable 'tmp' from
+	  helpfun in ilbc codec gcc version 4.6.2 caught an unused variable
+	  in the ilbc codec library. This would prevent compilation with
+	  --enable-dev-mode; variable removed. ........ Merged revisions
+	  351760 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 351761 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-23 15:23 +0000 [r401540]  Kinsey Moore <kmoore at digium.com>
+2012-01-20 13:12 +0000 [r351709]  Stefan Schmidt <sst at sil.at>
 
-	* channels/chan_mgcp.c, /: chan_mgcp: Properly handle malformed
-	  media lines This corrects a situation in which a media line was
-	  not parsed properly and resulted in a crash. (closes issue
-	  ASTERISK-21190) Reported by: adomjan Patches:
-	  chan_mgcp.c-sscnaf_fix uploaded by adomjan (License 5448)
-	  ........ Merged revisions 401537 from
+	* /, contrib/asterisk-ng-doxygen: enable doxygen build for files in
+	  the channels/sip folder like reqresp_parser.c ........ Merged
+	  revisions 351707 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401538 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401539 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-23 11:16 +0000 [r401500]  Joshua Colp <jcolp at digium.com>
-
-	* /, channels/chan_sip.c: chan_sip: Fix an issue where an
-	  incompatible audio format may be added to SDP. If preferred
-	  codecs included any non-audio format the code would mistakenly
-	  add the audio format, even if it was not a joint capability with
-	  the remote side. (closes issue ASTERISK-21131) Reported by:
-	  nbougues Patches: patch_unsupported_codec_1.8.patch uploaded by
-	  nbougues (license 6470) ........ Merged revisions 401497 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401498 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401499 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-23 02:36 +0000 [r401489]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* channels/chan_iax2.c, configs/iax.conf.sample, /: chan_iax2: Fix
-	  Binding To Multiple Addresses Again When reworking chan_iax2 for
-	  IPv6, the ability to bind to multiple addresses was removed by
-	  mistake. This patch restores this functionality and adds notes
-	  about IPv6 addresses in the sample config. (closes issue
-	  ASTERISK-22741) Reported by: Joshua Colp Tested by: Michael L.
-	  Young Patches: asterisk-22741-fix-binding-multiple-addr.diff
-	  uploaded by Michael L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2945/ ........ Merged
-	  revisions 401488 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-22 23:10 +0000 [r401450]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_rtp_asterisk.c: res_rtp_asterisk: Fix crash when RTCP
-	  is not available during SSRC change In r400089, a patch was put
-	  in to correct erroneous RTCP statistic resets. Unfortunately,
-	  ast_rtp_read can be called on an RTP instance that does not have
-	  RTCP information. This patch prevents that crash by only
-	  resetting the statistics if we do actually have an RTCP instance.
-	  (issue AST-1174) (closes issue ASTERISK-22667) Reported by: John
-	  Bigelow ........ Merged revisions 401445 from
+	  revisions 351708 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-19 23:31 +0000 [r351667]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/reqresp_parser.c: Misc minor
+	  fixes in reqresp_parser.c and chan_sip.c. * Fix corner cases in
+	  get_calleridname() parsing and ensure that the output buffer is
+	  nul terminated. * Make get_calleridname() truncate the name it
+	  parses if the given buffer is too small rather than abandoning
+	  the parse and not returning anything for the name. Adjusted
+	  get_calleridname_test() unit test to handle the truncation
+	  change. * Fix get_in_brackets_test() unit test to check the
+	  results of get_in_brackets() correctly. * Fix
+	  parse_name_andor_addr() to not return the address of a local
+	  buffer. This function is currently not used. * Fix potential NULL
+	  pointer dereference in sip_sendtext(). * No need to
+	  memset(calleridname) in check_user_full() or tmp_name in
+	  get_name_and_number() because get_calleridname() ensures that it
+	  is nul terminated. * Reply with an accurate response if
+	  get_msg_text() fails in receive_message(). This is academic in
+	  v1.8 because get_msg_text() can never fail. ........ Merged
+	  revisions 351618 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401446 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401447 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 351646 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-22 19:04 +0000 [r401421-401435]  Richard Mudgett <rmudgett at digium.com>
+2012-01-19 22:44 +0000 [r351613]  Kinsey Moore <kmoore at digium.com>
 
-	* apps/app_queue.c, /: app_queue: Fix CLI "queue remove member"
-	  queue_log entry. The queue_log entry resulting from CLI "queue
-	  remove member" when log_membername_as_agent is enabled is wrong.
-	  It always uses the interface name instead of the member name in
-	  the queue_log entry. * Get the queue member before removing it
-	  from the queue so the member name is available for the queue_log
-	  entry. (closes issue ASTERISK-21826) Reported by: Oscar Esteve
-	  Patches: fix_membername.diff (license #6505) patch uploaded by
-	  Oscar Esteve (modified to fix potential ref leak) ........ Merged
-	  revisions 401433 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401434 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/bridge_channel.c,
-	  include/asterisk/bridge_channel_internal.h, /, main/bridge.c:
-	  Bridging: Fix orphaned bridge if neither of the joining channels
-	  can join. The original issue noted that the bridge is orphaned
-	  when res_parking.so is not loaded and a call uses the dial kK
-	  flags. A similar issue happens when only one of the park flags is
-	  used. In this case you have the bridge with one or the other
-	  channel left in it. The channel and bridge will stay around until
-	  the channel hangs up. * Fixed the initial bridge channel push
-	  failure to act as if the channel were kicked out of the bridge.
-	  The bridge then decides if it needs to be dissolved. (closes
-	  issue ASTERISK-22629) Reported by: Kevin Harwell Review:
-	  https://reviewboard.asterisk.org/r/2928/ ........ Merged
-	  revisions 401424 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/parking/parking_bridge_features.c,
-	  res/parking/parking_bridge.c, /: res_parking: Give parking
-	  timeout comebacktoorigin channel DTMF features. Parking timeouts
-	  did not set any DTMF features for the channel calling the parker
-	  back. * Added code to set the parkedcalltransfers,
-	  parkedcallreparking, parkedcallhangup, and parkedcallrecording
-	  options appropriately for the channels when a parking timeout
-	  occurs. The recall channel DTMF options are set using the
-	  BRIDGE_FEATURES channel variable to allow the other timeout
-	  options to have the DTMF features available. (closes issue
-	  ASTERISK-22630) Reported by: Kevin Harwell Review:
-	  https://reviewboard.asterisk.org/r/2942/ ........ Merged
-	  revisions 401422 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_parking.c: res_parking: Update XML documention for
-	  DTMF features after parking timeout. * Updated the XML
-	  documentation to indicate that the parkedcalltransfers,
-	  parkedcallreparking, parkedcallhangup, and parkedcallrecording
-	  configuration options also apply to parking timeouts. (issue
-	  ASTERISK-22630) Reported by: Kevin Harwell Review:
-	  https://reviewboard.asterisk.org/r/2942/ ........ Merged
-	  revisions 401420 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-22 15:17 +0000 [r401411]  Joshua Colp <jcolp at digium.com>
-
-	* apps/app_dial.c: Add an 'R' option to Dial which sends ringing
-	  until early media has been received. (closes issue
-	  ASTERISK-10487) Reported by: Gaspar Zoltan Patches: 10487.patch
-	  uploaded by n8ideas (license 6075)
-
-2013-10-21 21:06 +0000 [r401365]  Mark Michelson <mmichelson at digium.com>
-
-	* /, main/bridge_channel.c: Remove a noisy debug message from
-	  bridging code. This particular debug message, during a stress
-	  test, was logged so often that it appeared that there may be a
-	  memory leak in the logger code. In actuality, there was no memory
-	  leak, but the logger thread was having a hard time keeping up
-	  with the demands of the rest of the system. Since this debug
-	  message has no value at all, the best way to fix the problem was
-	  to just remove the message. (closes issue AST-1225) reported by
-	  John Bigelow Patches: spammy_log.diff uploaded by Mark Michelson
-	  (License #5049) ........ Merged revisions 401364 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-21 19:50 +0000 [r401328]  Kevin Harwell <kharwell at digium.com>
-
-	* /, main/editline/term.c: Segfault in LIBEDIT_INTERNAL after
-	  tgetstr(), when libncurses5-dev isn't installed Include the
-	  appropriate declarations when not using termcap, but term+curses
-	  and [n]curses do not exist. (closes issue ASTERISK-22351)
-	  Reported by: A. Iglesias Patches:
-	  issueA22351_libedit_internal_without_ncurses_dev.patch uploaded
-	  by wdoekes (license 5674) ........ Merged revisions 401325 from
+	* res/res_rtp_asterisk.c, /: Correct output of RTCP jitter
+	  statistics in SR and RR reports Change the RTCP RR and SR
+	  generation code to convert Asterisk's internal jitter statistics
+	  to be represented in RTP timestamp units based on the rate of the
+	  codec in use instead of in seconds. (closes issue ASTERISK-14530)
+	  ........ Merged revisions 351611 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401326 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401327 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-21 18:59 +0000 [r401316-401317]  David M. Lee <dlee at digium.com>
-
-	* rest-api/api-docs/channels.json, /: Fixing r401281; the model
-	  name is Channel, with a capital C ........ Merged revisions
-	  401315 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_ari.c, /: Fixed malformed Access-Control-Allow-Methods
-	  header. Was causing Safari to barf on POST and DELETE. ........
-	  Merged revisions 401106 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-19 21:57 +0000 [r401292]  Kinsey Moore <kmoore at digium.com>
-
-	* /, channels/chan_iax2.c: Fix IAX2 incoming call address lookups
-	  This fixes address lookup for incoming calls without a peer
-	  definition. The address family was unset instead of being set to
-	  AST_AF_UNSPEC which was causing lookup failures on "127.0.0.1".
-	  This is one of the causes of the current failure of the app_page
-	  integration test. Review:
-	  https://reviewboard.asterisk.org/r/2933/ ........ Merged
-	  revisions 401291 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-19 14:45 +0000 [r401282]  Joshua Colp <jcolp at digium.com>
-
-	* res/ari/resource_channels.h, main/pbx.c, /,
-	  rest-api/api-docs/channels.json, res/ari/resource_channels.c,
-	  res/res_ari_channels.c: Return a channel snapshot when
-	  originating using ARI, and subscribe the Stasis application to
-	  it. This change allows a user of ARI to know what channel it has
-	  originated and also follow any progress. If a Stasis application
-	  is provided it will be automatically subscribed to the originated
-	  channel immediately. (closes issue ASTERISK-22485) Reported by:
-	  David Lee Review: https://reviewboard.asterisk.org/r/2910/
-	  ........ Merged revisions 401281 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 22:52 +0000 [r401272]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/parking/parking_controller.c: res_parking: Remove setting
-	  useless flag. ........ Merged revisions 401271 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 21:51 +0000 [r401263]  David M. Lee <dlee at digium.com>
-
-	* contrib/scripts/get_swagger_ui.sh (added), Makefile, /,
-	  static-http: This is just a quick script for dumping swagger-ui
-	  into static-http, so that it can be served by the Asterisk web
-	  server. I had to change the Makefile in order to recursively
-	  install content from the static-http directory, hence the code
-	  review instead of just putting it in. Review:
-	  https://reviewboard.asterisk.org/r/2924/ ........ Merged
-	  revisions 401261 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 18:44 +0000 [r401249]  Mark Michelson <mmichelson at digium.com>
-
-	* main/sorcery.c, main/cli.c, main/manager.c, /, main/bridge.c,
-	  main/bucket.c: Resolve some memory leaks due to incorrect for
-	  loop / ao2 ref usage. A common idiom in Asterisk is to due
-	  something like: for (ao2_obj = list_beginning; ao2_obj =
-	  next_item; ao2_ref(ao2_obj, -1)) { ...do stuff... } This is nice
-	  because it automatically takes care of the object references for
-	  you. However, there is a pitfall here. If a break statement is in
-	  the for loop, then the current reference is not cleaned up. In
-	  some cases, this is on purpose, but in others there is a leak.
-	  This commit fixes the leak cases. ........ Merged revisions
-	  401248 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 16:59 +0000 [r401233-401240]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_fax.c, include/asterisk/channel.h, apps/app_dial.c,
-	  main/channel.c: Add channel lock protection around translation
-	  path setup. Most callers of ast_channel_make_compatible() happen
-	  before the channels enter a two party bridge. With the new
-	  bridging framework, two party bridging technologies may also call
-	  ast_channel_make_compatible() when there is more than one thread
-	  involved with the two channels. * Added channel lock protection
-	  in set_format() and ast_channel_make_compatible_helper() when
-	  dealing with the channel's native formats while setting up a
-	  translation path. * Fixed best_src_fmt and best_dst_fmt usage
-	  consistency in ast_channel_make_compatible_helper(). The call to
-	  ast_translator_best_choice() got them backwards. * Updated some
-	  callers of ast_channel_make_compatible() and the function
-	  documentation. There is actually a difference between the two
-	  channels passed in. * Fixed the deadlock potential in res_fax.c
-	  dealing with ast_channel_make_compatible(). The deadlock
-	  potential was already there anyway because res_fax called
-	  ast_channel_make_compatible() with chan locked. (closes issue
-	  ASTERISK-22542) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2915/ ........ Merged
-	  revisions 401239 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, include/asterisk/bridge.h: Tweak ast_bridge_depart() doxygen.
-	  ........ Merged revisions 401232 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 16:06 +0000 [r401216-401224]  Mark Michelson <mmichelson at digium.com>
-
-	* include/asterisk/bridge.h, /: Remove the bit about requiring
-	  ast_bridge_depart() to be called before ast_bridge_destroy().
-	  ........ Merged revisions 401223 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/bridge.h, /: Clarify in ast_bridge_destroy()
-	  about how departable channels must be handled. ........ Merged
-	  revisions 401212 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-18 15:14 +0000 [r401184]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, channels/chan_sip.c: Remove Port Restriction When Checking For
-	  NAT When trying to determine if a peer is behind NAT, we should
-	  not be using the ports when comparing addresses. This patch
-	  removes the port from being checked and just useds the addresses
-	  now. (closes issue ASTERISK-22729) Reported by: Michael L. Young
-	  Tested by: Michael L. Young Patches:
-	  asterisk-remove-using-port-for-nat-check.diff uploaded by Michael
-	  L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2927/ ........ Merged
-	  revisions 401182 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401183 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 351612 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-19 21:55 +0000 [r351561]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c, include/asterisk/netsock2.h: Eliminates
+	  doubling the :port part of SIP Notify Message-Account headers.
+	  This patch prevents the domain string from getting mangled during
+	  the initreqprep step by moving the initialization to before its
+	  immediate use. It also documents this pitfall for the
+	  ast_sockaddr_stringify functions. (issue ASTERISK-19057) Reported
+	  by: Yuri Review: https://reviewboard.asterisk.org/r/1678/
+	  ........ Merged revisions 351559 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351560 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-18 14:50 +0000 [r401181]  Walter Doekes <walter+asterisk at wjd.nu>
+2012-01-19 21:13 +0000 [r351506]  Joshua Colp <jcolp at digium.com>
 
-	* main/channel.c, /: Properly copy/remove the device state cache
-	  flag over a masquerade. In r378303 the
-	  AST_FLAG_DISABLE_DEVSTATE_CACHE flag was added that tells the
-	  devstate system to not cache states for non-real devices.
-	  However, when optimizing away channels (ast_do_masquerade), that
-	  flag wasn't copied. In my case, using Local devices as queue
-	  members created a situation where the endpoint was considered in
-	  use, but the state change of the device being available again was
-	  ignored (not cached). The endpoint channel was optimized into the
-	  (previously) Local channel, but kept the do-not-cache flag. The
-	  end result being that the queue member apparently stayed in use
-	  forever. (closes issue ASTERISK-22718) Reported by: Walter Doekes
-	  Review: https://reviewboard.asterisk.org/r/2925/ ........ Merged
-	  revisions 401178 from
+	* /, channels/chan_sip.c: Prevent crash when an SDP offer is
+	  received with an encrypted video stream when support for video is
+	  disabled and res_srtp is loaded. (closes issue ASTERISK-19202)
+	  Reported by: Catalin Sanda ........ Merged revisions 351504 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351505 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-18 21:06 +0000 [r351452]  Matthew Jordan <mjordan at digium.com>
+
+	* codecs/ilbc/syntFilter.c (added), /, codecs/ilbc/iCBConstruct.h
+	  (added), codecs/ilbc/iLBC_test.c (added),
+	  codecs/ilbc/syntFilter.h (added), codecs/ilbc/StateConstructW.c
+	  (added), codecs/ilbc/packing.c (added),
+	  codecs/ilbc/StateConstructW.h (added), codecs/ilbc/packing.h
+	  (added), codecs/ilbc/getCBvec.c (added), codecs/ilbc/LPCdecode.c
+	  (added), codecs/ilbc/enhancer.c (added), codecs/ilbc/lsf.c
+	  (added), codecs/ilbc/iLBC_encode.c (added),
+	  codecs/ilbc/getCBvec.h (added), codecs/ilbc/LPCdecode.h (added),
+	  codecs/ilbc/iLBC_define.h (added), codecs/ilbc/FrameClassify.c
+	  (added), codecs/ilbc/enhancer.h (added), codecs/ilbc/lsf.h
+	  (added), codecs/ilbc/extract-cfile.awk (added),
+	  codecs/ilbc/iLBC_encode.h (added), codecs/ilbc/Makefile,
+	  codecs/ilbc/FrameClassify.h (added), codecs/ilbc/helpfun.c
+	  (added), codecs/ilbc/LICENSE_ADDENDUM (added),
+	  codecs/ilbc/doCPLC.c (added), codecs/ilbc/anaFilter.c (added),
+	  codecs/ilbc/helpfun.h (added), codecs/ilbc/createCB.c (added),
+	  codecs/ilbc/doCPLC.h (added), codecs/ilbc/anaFilter.h (added),
+	  codecs/ilbc/constants.c (added), codecs/ilbc/iLBC_decode.c
+	  (added), codecs/ilbc/createCB.h (added), codecs/ilbc/constants.h
+	  (added), codecs/ilbc/iLBC_decode.h (added),
+	  codecs/ilbc/iCBSearch.c (added), codecs/ilbc/filter.c (added),
+	  codecs/ilbc/gainquant.c (added), codecs/ilbc/hpInput.c (added),
+	  codecs/ilbc/hpOutput.c (added), codecs/ilbc/iCBSearch.h (added),
+	  codecs/ilbc/rfc3951.txt (added), codecs/ilbc/filter.h (added),
+	  codecs/ilbc/gainquant.h (added), codecs/ilbc/LPCencode.c (added),
+	  codecs/ilbc/hpInput.h (added), codecs/ilbc/PATENTS (added),
+	  codecs/ilbc/StateSearchW.c (added), codecs/ilbc/hpOutput.h
+	  (added), codecs/codec_ilbc.c, contrib/scripts/get_ilbc_source.sh,
+	  codecs/ilbc/LICENSE (added), codecs/ilbc/LPCencode.h (added),
+	  codecs/ilbc/StateSearchW.h (added), codecs/ilbc/iCBConstruct.c
+	  (added): Include iLBC source code for distribution with Asterisk
+	  This patch includes the iLBC source code for distribution with
+	  Asterisk. Clarification regarding the iLBC source code was
+	  provided by Google, and the appropriate licenses have been
+	  included in the codecs/ilbc folder. Review:
+	  https://reviewboard.asterisk.org/r/1675 Review:
+	  https://reviewboard.asterisk.org/r/1649 (closes issue:
+	  ASTERISK-18943) Reporter: Leif Madsen Tested by: Matt Jordan
+	  ........ Merged revisions 351450 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401179 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401180 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 351451 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-18 16:02 +0000 [r351409]  Stefan Schmidt <sst at sil.at>
+
+	* /, channels/chan_sip.c: The get_pai function in chan_sip.c didn't
+	  recognized a proper callerid name and number from a
+	  P-Asserted-Identity cause the header parsing logic was wrong.
+	  Changing the parsing functions to the sip header parsing APIs in
+	  reqresp_parser.h solves this problem. Review:
+	  https://reviewboard.asterisk.org/r/1673 Reviewed by: wdoekes2 and
+	  Mark Michelson ........ Merged revisions 351396 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351408 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-17 20:39 +0000 [r401169]  Michael L. Young <elgueromexicano at gmail.com>
+2012-01-17 19:45 +0000 [r351360]  Walter Doekes <walter+asterisk at wjd.nu>
 
-	* /, channels/chan_sip.c: Fix Setting A chan_sip Dialog's
-	  SIP_NAT_FORCE_RPORT Flag A condition was added in a commit to fix
-	  ASTERISK-21374, that, if the SIP_PAGE3_NAT_AUTO_RPORT flag was
-	  set, to then copy a peer's SIP_NAT_FORCE_RPORT flag to the
-	  dialog. This condition should not have been there since it
-	  assumed that if Asterisk is in an environment where NAT is
-	  involved, that the auto_* nat settings or force_rport setting
-	  would be on in the global settings. If the nat setting in the
-	  global setting is set to 'nat=no' and then turned on for peers
-	  (which is not quite the recommended way, although it is allowed)
-	  this flag is never copied to the dialog resulting in problems
-	  like, REGISTER replies going to the wrong port. This patch
-	  removes this conditional check and will now always use the peer's
-	  flag which by this point in the code the checks on whether the
-	  peer is behind NAT or not (if using auto_force_rport) have
-	  already been run. (closes issue ASTERISK-22236) Reported by:
-	  Filip Frank Tested by: Michael L. Young Patches:
-	  asterisk-2236-always-set-rport.diff uploaded by Michael L. Young
-	  (license 5026) Review: https://reviewboard.asterisk.org/r/2919/
-	  ........ Merged revisions 401167 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401168 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* Makefile: Fix support for parallel building with make (-j).
+	  Previously make -j <N> would cause a race between doing cleanup
+	  of certain files (defaults.h, menuselect, ...) and creating them
+	  anew. Add a new target that depends on cleanup only and has a
+	  submake doing the rest as command string. This way the cleanup
+	  goes first. (closes issue ASTERISK-18751) Tested by: Jeremy
+	  Kister Reviewed by: Paul Belanger Review:
+	  https://reviewboard.asterisk.org/r/1660
 
-2013-10-17 18:25 +0000 [r401159]  Jonathan Rose <jrose at digium.com>
+2012-01-17 17:23 +0000 [r351311]  Mark Michelson <mmichelson at digium.com>
 
-	* res/res_parking.c, /: res_parking: Fix bug where reloading
-	  immediately wipes new parkpos extensions (closes issue
-	  ASTERISK-22631) Reported by: Kevin Harwell ........ Merged
-	  revisions 401158 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res/res_rtp_asterisk.c, /: Eliminate odd initialization of
+	  probation variable. ........ Merged revisions 351306 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351308 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-17 17:15 +0000 [r351290]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_rtp_asterisk.c, /, configs/rtp.conf.sample, CHANGES: Adds
+	  pjmedia probation concepts to res_rtp_asterisk's learning mode.
+	  In order to better handle RTP sources with strictrtp enabled
+	  (which is now default in 10) using the learning mode to figure
+	  out new sources when they change is handled by checking for a
+	  number of consecutive (by sequence number) packets received to an
+	  rtp struct based on a new configurable value called 'probation'.
+	  Also, during learning mode instead of liberally accepting all
+	  packets received, we now reject packets until a clear source has
+	  been determined. Review: https://reviewboard.asterisk.org/r/1663/
+	  ........ Merged revisions 351287 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351289 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-17 16:56 +0000 [r351288]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/chan_sip.c: Use built-in parsing functions for
+	  Contact and Record-Route headers. If a Contact or a Record-Route
+	  header had a quoted string with an item in angle brackets, then
+	  we would mis-parse it. For instance, "Bob <1234>"
+	  <1234 at example.org> would be misparsed as having the URI "1234"
+	  The fix for this is to use parsing functions from
+	  reqresp_parser.h since they are heavily tested and are awesome.
+	  (issue ASTERISK-18990) ........ Merged revisions 351284 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351286 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-17 15:41 +0000 [r401122]  Kinsey Moore <kmoore at digium.com>
+2012-01-17 16:08 +0000 [r351235]  Matthew Jordan <mjordan at digium.com>
 
-	* /, res/res_xmpp.c, res/res_jabber.c: Reduce log level of a
-	  non-pubsub error message Drop an error log message to debug level
-	  1 since distributed device state functions correctly when
-	  receiving this message and it spams the logs. (closes issue
-	  ASTERISK-22410) Reported by: abelbeck Patches:
-	  asterisk-1.8-res_jabber-log-nonpubsub-error-to-debug.patch
-	  uploaded by abelbeck (License 5903)
-	  asterisk-11-res_xmpp-log-nonpubsub-error-to-debug.patch uploaded
-	  by abelbeck (License 5903) ........ Merged revisions 401119 from
+	* /, channels/chan_sip.c: Fix udptl issue with initial INVITE
+	  introduced by r351027 When an inital INVITE occurs that contains
+	  image media, a channel is not yet associated with the SIP dialog.
+	  The file descriptor associated with the udptl session needs to be
+	  set in initialize_udptl or in sip_new to account for this
+	  scenario. ........ Merged revisions 351233 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351234 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-17 01:48 +0000 [r351184]  Russell Bryant <russell at russellbryant.com>
+
+	* /, channels/chan_sip.c: Merged revisions 351183 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r351183 | russell | 2012-01-16 20:43:19 -0500
+	  (Mon, 16 Jan 2012) | 29 lines Merged revisions 351182 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r351182 | russell | 2012-01-16 20:37:03 -0500 (Mon, 16 Jan 2012)
+	  | 22 lines Add some missing locking in chan_sip. This patch adds
+	  some missing locking to the function
+	  send_provisional_keepalive_full(). This function is called from
+	  the scheduler, which is processed in the SIP monitor thread. The
+	  associated channel (or pbx) thread will also be using the same
+	  sip_pvt and ast_channel so locking must be used. The
+	  sip_pvt_lock_full() function is used to ensure proper locking
+	  order in a safe manner. In passing, document a suspected
+	  reference counting error in this function. The "fix" is left
+	  commented out because when the "fix" is present, crashes occur.
+	  My theory is that fixing it is exposing a reference counting
+	  error elsewhere, but I don't know where. (Or my analysis of this
+	  being a problem could have been completely wrong in the first
+	  place). Leave the comment in the code for so that someone may
+	  investigate it again in the future. Also add a bit of doxygen to
+	  transmit_provisional_response(). (closes issue ASTERISK-18979)
+	  Review: https://reviewboard.asterisk.org/r/1648 ........
+	  ................
+
+2012-01-16 21:50 +0000 [r351082-351143]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Ensure ACK retransmit & hangup on non-200
+	  response to INVITE When handling a non-2xx final response on an
+	  INVITE transaction, we have to keep the transaction around after
+	  we send an ACK in case we receive a retransmission of the
+	  response so we can re-transmit the ACK, but also tear down the
+	  ast_channel as soon as we transmit the ACK. Before this patch, we
+	  could fail at both of these things. Calling
+	  sip_alreadygone/needdestroy prevented us from keeping the
+	  transaction up and retransmitting the ACK, and queueing
+	  CONGESTION was not sufficient to cause the channel to be torn
+	  down when originating calls via the CLI, for example. This patch
+	  queues a hangup with CONGESTION instead of just queueing
+	  CONGESTION for these responses and removes the sip_alreadygone
+	  and sip_needdestroy calls from handle_response_invite on non-2xx
+	  responses. It relies on the hangup calling sip_scheddestroy. For
+	  more information, see section 17.1.1.1 of RFC 3261. (closes issue
+	  ASTERISK-17717) Review: https://reviewboard.asterisk.org/r/1672/
+	  ........ Merged revisions 351130 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351131 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c: Don't prematurely stop SIP session timer
+	  When Asterisk is the UAS (incoming call, endpoint is re-inviting)
+	  the SIP session timer expires after half the time the sip
+	  endpoint indicates in the Session-expires header in
+	  proc_session_timer(). The session timer was being stopped totally
+	  and being handled as an error case instead of running again until
+	  the second expiry. This patch treats the half-time expiry as a
+	  non-error case and continues the timer until the true expiry.
+	  (closes issue ASTERISK-18996) Reported by: Thomas Arimont Tested
+	  by: Thomas Arimont Patches: session_timer_fix.diff by Terry
+	  Wilson (License #5357) based on session_timer.patch by Thomas
+	  Arimont (License #5525) ........ Merged revisions 351080 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 351081 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-16 19:49 +0000 [r351079]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* main/ast_expr2.y, CHANGES, main/ast_expr2.c: Add ABS() absolute
+	  value function to the expression parser.
+
+2012-01-16 19:13 +0000 [r351029]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Create and initialize udptl only when
+	  dialog negotiates for image media Prior to this patch, the udptl
+	  struct was allocated and initialized when a dialog was associated
+	  with a peer that supported T.38, when a new SIP channel was
+	  allocated, or what an INVITE request was received. This resulted
+	  in any dialog associated with a peer that supported T.38 having
+	  udptl support assigned to it, including the UDP ports needed for
+	  communication. This occurred even in non-INVITE dialogs that
+	  would never send image media. This patch creates and initializes
+	  the udptl structure only when the SDP for a dialog specifies that
+	  image media is supported, or when Asterisk indicates through the
+	  appropriate control frame that a dialog is to support T.38.
+	  (closes issue ASTERISK-16698) Reported by: under Tested by:
+	  Stefan Schmidt Patches: udptl_20120113.diff uploaded by mjordan
+	  (License #6283) (closes issue ASTERISK-16794) Reported by: Elazar
+	  Broad Tested by: Stefan Schmidt review:
+	  https://reviewboard.asterisk.org/r/1668/ ........ Merged
+	  revisions 351027 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401120 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401121 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 351028 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-16 21:22 +0000 [r401108]  Richard Mudgett <rmudgett at digium.com>
+2012-01-16 17:12 +0000 [r350979]  Sean Bright <sean at malleable.com>
 
-	* /, res/ari/resource_playback.c: ARI: Fix crash when POST
-	  /playback/{id}/control does not have an operation parameter.
-	  (closes issue ASTERISK-22680) Reported by: John Bigelow ........
-	  Merged revisions 401107 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, main/db.c: Sort the output of 'database showkey' as well. You
+	  can pass wildcards (%) to the database CLI commands, so this will
+	  sort the returned list of matches. ........ Merged revisions
+	  350978 from http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-16 17:01 +0000 [r401097]  David M. Lee <dlee at digium.com>
+2012-01-16 17:07 +0000 [r350977]  Joshua Colp <jcolp at digium.com>
 
-	* rest-api/resources.json, /: Oops. Leftover /stasis reference
-	  ........ Merged revisions 401096 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/rtp_engine.c, /: Add missing code to set direct RTP setup
+	  information during dialing. ........ Merged revisions 350975 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350976 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-16 14:31 +0000 [r350939]  Sean Bright <sean at malleable.com>
+
+	* /, main/db.c: Sort the output of 'database show' by key. This
+	  more closely mimics the behavior of 'database show' before the
+	  conversion to sqlite3. ........ Merged revisions 350938 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-15 20:16 +0000 [r350887-350890]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, main/asterisk.c: Allow only one thread at a time to do
+	  asterisk cleanup/shutdown. Add locking around the
+	  really-really-quit part of the core stop/restart part. Previously
+	  more than one thread could be called to do cleanup, causing
+	  atexit handlers to be run multiple times, in turn causing
+	  segfaults. (issue ASTERISK-18883) Reviewed by: Terry Wilson
+	  Review: https://reviewboard.asterisk.org/r/1662/ Review:
+	  https://reviewboard.asterisk.org/r/1658/ ........ Merged
+	  revisions 350888 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350889 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, utils/extconf.c: Fix -Werror=unused-but-set-variable compile
+	  error in utils/extconf.c. Note that I'm not confirming legitimacy
+	  of having that file in tree at all. Is anyone using
+	  aelparse/conf2ael? (issue ASTERISK-15350) ........ Merged
+	  revisions 350885 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350886 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-14 16:43 +0000 [r350791-350839]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, configure, autoconf/ast_gcc_attribute.m4, configure.ac,
+	  autoconf/libcurl.m4: Ensure that all AC_LANG_PROGRAM calls in the
+	  configure script are properly quoted. Recent versions of autoconf
+	  (2.68 on my system) won't properly process the configure script
+	  unless every call to AC_LANG_PROGRAM is m4-quoted. Many calls in
+	  the script were, but many were not. This patch corrects the
+	  unquoted calls. ........ Merged revisions 350837 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350838 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_h323.c, addons/chan_mobile.c,
+	  res/res_pktccops.c, contrib/scripts/install_prereq: Multiple
+	  revisions 350788-350789 ........ r350788 | kpfleming | 2012-01-14
+	  09:22:33 -0600 (Sat, 14 Jan 2012) | 8 lines Ensure that two
+	  prerequisites are properly installed on Debian-style
+	  distributions. * Don't specify a specific version of libgmime;
+	  newer versions are available now and acceptable. * Install
+	  libsrtp so that res_srtp can be built. ........ r350789 |
+	  kpfleming | 2012-01-14 09:23:32 -0600 (Sat, 14 Jan 2012) | 3
+	  lines Correct some 'set-but-not-used' variable warnings. ........
+	  Merged revisions 350788-350789 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350790 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-16 14:02 +0000 [r401088]  Kinsey Moore <kmoore at digium.com>
+2012-01-13 22:17 +0000 [r350738]  Kinsey Moore <kmoore at digium.com>
 
-	* rest-api/api-docs/bridges.json, res/ari/resource_channels.h, /,
-	  res/ari/resource_bridges.h, rest-api/api-docs/channels.json:
-	  Clarify documentation for channel and bridge list This makes it
-	  clear that the ARI API calls for listing channels and bridges
-	  will list all channels or bridges in the system and not just
-	  those that are in or are controlled by a Stasis application.
-	  (closes issue ASTERISK-22635) Reported by: Kevin Harwell ........
-	  Merged revisions 401087 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, include/asterisk/autoconfig.h.in: Run bootstrap.sh for the for
+	  the ASTERISK-18929 fix configure and autoconfig.h.in were not
+	  regenerated when the fix was committed. ........ Merged revisions
+	  350736 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 350737 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-16 12:19 +0000 [r401079]  Walter Doekes <walter+asterisk at wjd.nu>
+2012-01-13 21:52 +0000 [r350735]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, apps/app_queue.c: Don't check all realtime queues when doing
-	  "queue show some_queue". When using realtime queues, queues have
-	  to be fetched from the database every now and then to see if any
-	  info has been changed or to see if the queue has been removed.
-	  When fetching info for an individual queue, the pruning of other
-	  queues is unnecessarily costly. Review:
-	  https://reviewboard.asterisk.org/r/2907/ ........ Merged
-	  revisions 401049 from
+	* /, configs/cel_pgsql.conf.sample, configs/cel_odbc.conf.sample:
+	  Correct eventtype names in cel_odbc and cel_pgsql sample files
+	  ........ Merged revisions 350733 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 401076 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401077 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-16 00:12 +0000 [r401041]  Paul Belanger <paul.belanger at polybeacon.com>
-
-	* /, rest-api/api-docs/bridges.json, res/res_ari_bridges.c: Use
-	  POST / DELETE to toggle ARI bridge moh Review:
-	  https://reviewboard.asterisk.org/r/2911/ ........ Merged
-	  revisions 401040 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-15 23:44 +0000 [r401020-401039]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/translate.c: translate.c: Some minor code tweaks. *
-	  Consistently compare format2index() return value so matrix_get()
-	  cannot get passed negative values. * Optimize
-	  ast_translator_best_choice() to defer initializing things until
-	  needed. Also cached the matrix_get() return value rather than
-	  repeatedly calling it.
-
-	* /, channels/dahdi/bridge_native_dahdi.c: bridge_native_dahdi:
-	  Return channel join failure if could not make the channels
-	  compatible. ........ Merged revisions 401030 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_iax2.c: chan_iax2: Fix channel left locked in
-	  off nominal code path. ........ Merged revisions 401016 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 401017 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-15 20:03 +0000 [r401019]  Kinsey Moore <kmoore at digium.com>
-
-	* rest-api/api-docs/bridges.json, res/res_ari_bridges.c, /: Ensure
-	  bridge record error responses validate This adds the list of
-	  expected errors to the /bridges/{bridgeId}/record ARI
-	  documentation so that outbound 4xx errors validate properly.
-	  Previously, this would result in a response validation failure.
-	  (closes issue ASTERISK-22627) Reported by: Joshua Colp ........
-	  Merged revisions 401018 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-15 15:30 +0000 [r401007]  Paul Belanger <paul.belanger at polybeacon.com>
-
-	* rest-api/api-docs/channels.json, res/res_ari_channels.c, /: Use
-	  POST / DELETE to toggle hold / moh for ARI channels This change
-	  updates how we handle toggle events, rather then create two
-	  different function names, we'll just use POST / DELETE from HTTP
-	  to handle it. Review: https://reviewboard.asterisk.org/r/2906/
-	  ........ Merged revisions 400999 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-15 15:26 +0000 [r400998]  Mark Michelson <mmichelson at digium.com>
+	  revisions 350734 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-13 21:42 +0000 [r350732]  Kinsey Moore <kmoore at digium.com>
+
+	* /, configure.ac, bootstrap.sh, main/asterisk.c: Make sure
+	  asterisk builds on OpenBSD OpenBSD defines SO_PEERCRED, but it
+	  returns a 'struct sockpeercred', not 'struct ucred', which causes
+	  compilation of main/asterisk.c to fail in read_credentials().
+	  This allows configure to check for sockpeercred and asterisk to
+	  deal with it properly. (closes issue ASTERISK-18929) Reported-by:
+	  Barry Miller Patch-by: Barry Miller ........ Merged revisions
+	  350730 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 350731 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-13 20:32 +0000 [r350681]  Mark Michelson <mmichelson at digium.com>
+
+	* /, channels/sip/config_parser.c: Set port to a default sane value
+	  if a bogus one is provided when parsing hostnames. ........
+	  Merged revisions 350679 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350680 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-13 18:52 +0000 [r350605-350644]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/features.c: Remove some dead code in ast_bridge_call(). None
+	  of the parameters to ast_bridge_call() can be NULL for the bridge
+	  to work so no need to check for it.
+
+	* configs/cel_sqlite3_custom.conf.sample, cel/cel_odbc.c,
+	  configs/cel.conf.sample, /, cel/cel_manager.c,
+	  configs/cel_pgsql.conf.sample, configs/cel_odbc.conf.sample,
+	  main/cel.c, configs/cel_custom.conf.sample: Add missing CEL
+	  logging fields to various CEL backends. Multiple revisions
+	  350555,350571 ........ r350555 | rmudgett | 2012-01-13 11:12:51
+	  -0600 (Fri, 13 Jan 2012) | 12 lines Add missing CEL logging
+	  fields to various CEL backends. * Add missing eventextra to
+	  cel_psql.c and cel_odbc.c. * Add missing PeerAccount and
+	  EventExtra to cel_manager.c. * Add missing userdeftype support
+	  for cel_custom.conf.sample and cel_sqlite3_custom.conf.sample.
+	  (closes issue ASTERISK-17190) Reported by: Bryant Zimmerman
+	  ........ r350571 | rmudgett | 2012-01-13 11:23:57 -0600 (Fri, 13
+	  Jan 2012) | 8 lines Use compatible names for event extra data for
+	  various CEL backends. * Change eventextra to extra in cel_psql.c
+	  and cel_odbc.c. * Change EventExtra to Extra in cel_manager.c.
+	  (issue ASTERISK-17190) ........ Merged revisions 350555,350571
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 350585 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-13 17:00 +0000 [r350551-350554]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_queue.c: Realtime queues failed to load queue
+	  information without queue member table Previously, realtime
+	  queues could be loaded without defining the queue member table.
+	  This allowed for queue members to be dynamic, while the realtime
+	  queue definitions could exist in some backing storage. Revision
+	  342223 broke this when it changed the return value for
+	  realtime_multientry to return NULL when no results are returned.
+	  Previously, an empty ast_config object was expected. (closes
+	  issue ASTERISK-19170) Reported by: Rene Mendoza Tested by: Rene
+	  Mendoza Patches: rt_queue_member_patch.diff uploaded by Matt
+	  Jordan (license 6283) ........ Merged revisions 350552 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350553 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, bridges/bridge_builtin_features.c, channels/chan_bridge.c,
+	  include/asterisk/bridging.h, apps/app_confbridge.c,
+	  main/bridging.c: Fix crash from bridge channel hangup race
+	  condition in ConfBridge This patch addresses two issues in
+	  ConfBridge and the channel bridge layer: 1. It fixes a race
+	  condition wherein the bridge channel could be hung up 2. It
+	  removes the deadlock avoidance from the bridging layer and makes
+	  the bridge_pvt an ao2 ref counted object Patch by David Vossel
+	  (mjordan was merely the commit monkey) (issue ASTERISK-18988)
+	  (closes issue ASTERISK-18885) Reported by: Dmitry Melekhov Tested
+	  by: Matt Jordan Patches: chan_bridge_cleanup_v.diff uploaded by
+	  David Vossel (license 5628) (closes issue ASTERISK-19100)
+	  Reported by: Matt Jordan Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1654/ ........ Merged
+	  revisions 350550 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-12 16:10 +0000 [r350503]  Jonathan Rose <jrose at digium.com>
+
+	* /, main/features.c: Adds peer to CEL report on CEL_BRIDGE_START
+	  and CEL_BRIDGE_END (closes issue ASTERISK-17940) Reporter: Nic
+	  Colledge Patches: features_18.patch uploaded by Nic Colledge
+	  (license 6245) ........ Merged revisions 350501 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350502 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-11 22:53 +0000 [r350416-350454]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/cel.c: Remove extraneous BRIDGEPEER AMI VarSet event on a
+	  CEL dummy channel. (closes issue ASTERISK-19180) Reported by:
+	  Corey Farrell Patches: asterisk_cel_noevent_varset.diff (license
+	  #5909) patch uploaded by Corey Farrell ........ Merged revisions
+	  350452 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 350453 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_dial.c, /, CHANGES, apps/app_followme.c: Make FollowMe
+	  optionally update connected line information when the accepting
+	  endpoint is bridged. Like Dial and Queue, FollowMe needs to deal
+	  with AST_CONTROL_CONNECTED_LINE information so when the parties
+	  are initially bridged, the connected line information will be
+	  correct. * Added the 'I' option just like the app_dial and
+	  app_queue 'I' option. * Made 'N' option ignored if the call is
+	  already answered. (closes issue ASTERISK-18969) Reported by:
+	  rmudgett Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/1656/ ........ Merged
+	  revisions 350364 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350415 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-11 19:19 +0000 [r350365]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c: Always treat arguments to get_by_name_cb as
+	  strings Initially, support was left in for the old style of
+	  searching, even though it wasn't actually used. In the case of
+	  name_len != 0, the OBJ_KEY flag isn't passed because we aren't
+	  matching on a full key and therefor can't use the hash function
+	  to optimize. The code left in to support the old way of searching
+	  unfortunately treated a prefix search like this as though an
+	  ast_channel struct was passed as an arg and caused a crash. This
+	  patch also adds needed parentheses around some matching
+	  conditions. (closes issue ASTERISK-19182)
+
+2012-01-10 22:10 +0000 [r350273-350313]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_lock.c: Fix absolute/relative time mismatch in LOCK
+	  function. The time passed by the LOCK function to an internal
+	  function was relative time when the function expected absolute
+	  time. * Don't use C++ keywords in get_lock(). (closes issue
+	  ASTERISK-16868) Reported by: Andrey Solovyev Patches:
+	  20101102__issue18207.diff.txt (license #5003) patch uploaded by
+	  Andrey Solovyev (modified) ........ Merged revisions 350311 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350312 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: Prevent chan_sip from sending duplicate
-	  BYEs. When a 200 OK for an initial INVITE is received, we were
-	  doing the right thing by ACKing and sending an immediate BYE.
-	  However, we also were doing the wrong thing and queuing an answer
-	  frame, thus causing the call to be answered. This would cause the
-	  call to be hung up by the channel thread, thus resulting in a
-	  second BYE being sent out. In this fix, I also have set the
-	  hangupcause to be correct since the initial BYE being sent by
-	  Asterisk had an unknown hangup cause. I have changed to using
-	  "Bearer capabilty not available" since the call was hung up due
-	  to an SDP offer/answer error. (closes issue ASTERISK-22621)
-	  reported by Kinsey Moore ........ Merged revisions 400970 from
+	* main/channel.c: Fix compiler warnings reported by gcc v4.2.4.
+
+2012-01-09 22:15 +0000 [r350223]  Terry Wilson <twilson at digium.com>
+
+	* main/udptl.c, apps/app_dahdibarge.c, addons/chan_ooh323.c,
+	  channels/chan_local.c, main/rtp_engine.c, main/say.c,
+	  apps/app_record.c, apps/app_test.c, channels/console_video.c,
+	  apps/app_alarmreceiver.c, apps/app_chanisavail.c,
+	  bridges/bridge_multiplexed.c, channels/chan_iax2.c,
+	  main/indications.c, main/cli.c, channels/chan_dahdi.c,
+	  channels/sig_analog.c, channels/chan_skinny.c, main/features.c,
+	  apps/app_dumpchan.c, pbx/pbx_realtime.c, apps/app_amd.c,
+	  channels/chan_alsa.c, apps/app_externalivr.c, main/bridging.c,
+	  apps/app_milliwatt.c, channels/sig_ss7.c, apps/app_dial.c,
+	  main/pbx.c, apps/app_page.c, apps/app_softhangup.c,
+	  apps/app_fax.c, apps/app_dahdiras.c, channels/chan_agent.c,
+	  apps/app_disa.c, include/asterisk/channel.h, main/aoc.c,
+	  apps/app_talkdetect.c, main/cel.c, res/res_mutestream.c,
+	  res/res_monitor.c, apps/app_playback.c, channels/chan_misdn.c,
+	  funcs/func_channel.c, apps/app_macro.c, apps/app_mixmonitor.c,
+	  apps/app_chanspy.c, apps/app_voicemail.c, res/res_calendar.c,
+	  channels/chan_unistim.c, channels/chan_vpb.cc, main/ccss.c,
+	  apps/app_meetme.c, apps/app_readexten.c, res/res_musiconhold.c,
+	  main/autochan.c, channels/chan_gtalk.c, apps/app_followme.c,
+	  res/res_jabber.c, main/cdr.c, main/channel.c, main/dial.c,
+	  channels/chan_phone.c, main/manager.c, funcs/func_groupcount.c,
+	  funcs/func_audiohookinherit.c, funcs/func_frame_trace.c,
+	  res/res_agi.c, apps/app_minivm.c, main/app.c,
+	  apps/app_confbridge.c, apps/app_rpt.c, addons/chan_mobile.c,
+	  apps/app_parkandannounce.c, channels/chan_mgcp.c,
+	  apps/app_jack.c, apps/app_adsiprog.c, channels/chan_sip.c,
+	  res/res_fax.c, apps/app_waitforsilence.c, funcs/func_lock.c,
+	  main/channel_internal_api.c (added), res/res_adsi.c,
+	  pbx/pbx_lua.c, channels/chan_console.c, apps/app_getcpeid.c,
+	  channels/sig_pri.c, apps/app_queue.c, channels/chan_oss.c,
+	  funcs/func_global.c, channels/chan_usbradio.c,
+	  channels/chan_jingle.c, apps/app_flash.c,
+	  apps/app_directed_pickup.c, main/abstract_jb.c, main/file.c,
+	  channels/chan_h323.c, res/snmp/agent.c, pbx/pbx_dundi.c,
+	  apps/app_sms.c, channels/chan_nbs.c, apps/app_stack.c,
+	  main/dsp.c: Replace direct access to channel name with accessor
+	  functions There are many benefits to making the ast_channel an
+	  opaque handle, from increasing maintainability to presenting ways
+	  to kill masquerades. This patch kicks things off by taking things
+	  a field at a time, renaming the field to
+	  '__do_not_use_${fieldname}' and then writing setters/getters and
+	  converting the existing code to using them. When all fields are
+	  done, we can move ast_channel to a C file from channel.h and lop
+	  off the '__do_not_use_'. This patch sets up
+	  main/channel_interal_api.c to be the only file that actually
+	  accesses the ast_channel's fields directly. The intent would be
+	  for any API functions in channel.c to use the accessor functions.
+	  No more monkeying around with channel internals. We should use
+	  our own APIs. The interesting changes in this patch are the
+	  addition of channel_internal_api.c, the moving of the AST_DATA
+	  stuff from channel.c to channel_internal_api.c (note: the
+	  AST_DATA stuff will have to be reworked to use accessor functions
+	  when ast_channel is really opaque), and some re-working of the
+	  way channel iterators/callbacks are handled so as to avoid
+	  creating fake ast_channels on the stack to pass in matching data
+	  by directly accessing fields (since "name" is a stringfield and
+	  the fake channel doesn't init the stringfields, you can't use the
+	  ast_channel_name_set() function). I went with
+	  ast_channel_name(chan) for a getter, and
+	  ast_channel_name_set(chan, name) for a setter. The majority of
+	  the grunt-work for this change was done by writing a semantic
+	  patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review:
+	  https://reviewboard.asterisk.org/r/1655/
+
+2012-01-09 21:56 +0000 [r350222]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_iax2.c: Fix joinable thread terminating without
+	  joiner memory leak in chan_iax.c. The iax2_process_thread() can
+	  exit without anyone waiting to join the thread. If noone is
+	  waiting to join the thread then a large memory leak occurs. *
+	  Made iax2_process_thread() deatach itself if nobody is waiting to
+	  join the thread. (closes issue ASTERISK-17339) Reported by:
+	  Tzafrir Cohen Patches:
+	  asterisk-1.8.4.4-chan_iax2-detach-thread-on-non-stop-exit.patch
+	  (license #5617) patch uploaded by Alex Villacis Lasso (modified)
+	  (closes issue ASTERISK-17825) Reported by: wangjin ........
+	  Merged revisions 350220 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400971 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400984 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-15 13:44 +0000 [r400959]  David M. Lee <dlee at digium.com>
-
-	* /, rest-api-templates/asterisk_processor.py: My doc correction in
-	  r400842 had a silly bug. Because I added a wiki_description to
-	  models and not their properties, the rendered wiki page had the
-	  model description instead of the property descriptions, which
-	  looks very silly indeed. (closes issue ASTERISK-22705) ........
-	  Merged revisions 400958 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-14 22:52 +0000 [r400913-400950]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_dahdi.c, configs/chan_dahdi.conf.sample,
-	  channels/chan_dahdi.h: chan_dahdi: Add config support for hwgain
-	  settings. * Add hwtxgain and hwrxgain config options to
-	  chan_dahdi.conf with documentation in chan_dahdi.conf.sample.
-	  (closes issue ASTERISK-22429) Reported by: Jaco Kroon Patches:
-	  jira_asterisk_22429_hwgain_trunk.patch (license #5621) patch
-	  uploaded by rmudgett
-
-	* channels/chan_dahdi.c, /, channels/chan_dahdi.h: chan_dahdi:
-	  Reflect the set software gain in the CLI "dahdi show channel"
-	  output. * Remember the swgain setting from CLI "dahdi set swgain"
-	  command so the CLI "dahdi show channel" output will reflect the
-	  current setting. * Updated CLI "dahdi set hwgain" and "dahdi set
-	  swgain" documentation. (issue ASTERISK-22429) Reported by: Jaco
-	  Kroon Patches: jira_asterisk_22429_v1.8_v2.patch (license #5621)
-	  patch uploaded by rmudgett ........ Merged revisions 400907 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400909 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400911 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-14 22:03 +0000 [r400912]  Mark Michelson <mmichelson at digium.com>
-
-	* /, channels/chan_sip.c: chan_sip: Do not increment the SDP
-	  version between 183 and 200 responses. Bumping the SDP version
-	  number can cause interoperability problems since receivers of the
-	  responses will expect that a 200 SDP will be identical to a
-	  previous 183 SDP. (closes issue ASTERISK-21204) reported by
-	  NITESH BANSAL Patches:
-	  dont-increment-session-version-in-2xx-after-183.patch uploaded by
-	  NITESH BANSAL (License #6418) ........ Merged revisions 400906
+	  revisions 350221 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-09 19:37 +0000 [r350181]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, main/db.c: Fix shutdown handling of sqlite3 astdb. If a
+	  db_sync was scheduled just before shutdown, the atexit code
+	  calling db_sync would have no effect, causing the astdb commit
+	  thread to stay alive. This caused the SIP/realtime_sipregs test
+	  to fail. (The fallback kill would run the atexit code again and
+	  that would wreak havoc.) This fixes that the atexit kill
+	  condition is picked up properly. (closes issue ASTERISK-18883)
+	  Reviewed by: Terry Wilson Review:
+	  https://reviewboard.asterisk.org/r/1659 ........ Merged revisions
+	  350180 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-09 18:58 +0000 [r350077-350130]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, contrib/scripts/valgrind_compare (added): Multiple revisions
+	  350127-350128 ........ r350127 | rmudgett | 2012-01-09 12:40:33
+	  -0600 (Mon, 09 Jan 2012) | 12 lines Update contrib script
+	  live_ast to invoke Asterisk with valgrind and suppression file. *
+	  Added valgrind_compare script to compare two valgrind log files
+	  for differences. (issue ASTERISK-17339) Reported by: Tzafrir
+	  Cohen Patches: valgrind_compare (license #5035) script uploaded
+	  by Tzafrir Cohen live_ast_valgrind.diff (license #5035) patch
+	  uploaded by Tzafrir Cohen live_ast_valgrind_v2.diff (license
+	  #5185) patch uploaded by Paul Belanger ........ r350128 |
+	  rmudgett | 2012-01-09 12:54:56 -0600 (Mon, 09 Jan 2012) | 11
+	  lines live_ast: valgrind: run asterisk under valgrind Adds a new
+	  sub-command, "valgrind" to live_ast. It runs asterisk under
+	  valgrind. The extra command-line parameters are passed to
+	  Asterisk as usual, and parameters to valgrind are passed through
+	  LIVE_AST_VALGRIND_ARGS in live.conf . Review:
+	  https://reviewboard.asterisk.org/r/1109/ Merged revisions 326636
+	  from http://svn.asterisk.org/svn/asterisk/branches/10 ........
+	  Merged revisions 350127-350128 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350129 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/asterisk.c: Make Asterisk -x command line parameter imply
+	  -r parameter presence. The Asterisk -x command line parameter is
+	  documented inconsistently. * Made the -x documentation and
+	  behavior consistent. * Since this is also a new year, updated the
+	  copyright notices while here. (closes issue ASTERISK-19094)
+	  Reported by: Eugene Patches:
+	  issueA19094_correct_asterisk_option_x.patch (license #5674) patch
+	  uploaded by Walter Doekes (modified) Tested by: Eugene ........
+	  Merged revisions 350075 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 350076 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-09 15:40 +0000 [r350025]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_meetme.c: Prevent SLA settings from getting wiped out
+	  on reload If SLA was reloaded without the config file being
+	  changed, current settings got wiped out before the SLA reload
+	  code decided it wasn't going to reload the file since nothing was
+	  changed. Moving the settings reset later in the reload process
+	  fixes this. (closes issue AST-744) ........ Merged revisions
+	  350023 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 350024 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-06 23:31 +0000 [r349978]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Don't leak CID in From header when
+	  presentation=unavailable When someone does
+	  Set(CALLERPRES()=unavailable) (or
+	  Set(CALLERID(pres)=unavailable)) when sendrpid=no, the From
+	  header shows "Anonymous" <anonymous at anonymous.invalid>. When
+	  sendrpid=yes/pai, the From header will still display the callerid
+	  info, even though we supply an rpid header with the anonymous
+	  info. It seems like we shouldn't leak that info in any case.
+	  Skimming http://tools.ietf.org/html/draft-ietf-sip-privacy-04
+	  seems to indicate that one shouldn't send identifying info in the
+	  From in this case. This patch anonymizes the From header as well
+	  even when sendrpid=yes/pai. (closes issue ASTERISK-16538) Review:
+	  https://reviewboard.asterisk.org/r/1649/ ........ Merged
+	  revisions 349968 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349977 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-06 21:26 +0000 [r349929]  Kinsey Moore <kmoore at digium.com>
+
+	* /, pbx/pbx_lua.c: Fix lua goto detection to prevent unexpected
+	  behavior with confbridge A bug in the pbx_lua goto detection was
+	  causing the dialplan to hangup unexpectedly after confbridge
+	  exited if it had called lua dialplan code during execution.
+	  Patch-by: Timo Teras Acked-by: Matt Nicholson (closes issue
+	  ASTERISK-18976) ........ Merged revisions 349928 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-06 16:50 +0000 [r349874]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_followme.c: Fix memory leaks in app_followme
+	  find_realtime(). (closes issue ASTERISK-19055) Reported by: Matt
+	  Jordan ........ Merged revisions 349872 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349873 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-05 23:58 +0000 [r349823]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_fax.c: Fix premature free'ing of the frame committed
+	  in r349608 Even though we set the frame to the ast_null_frame and
+	  return that, the caller of the frame hook may still need the
+	  frame. This now is a bit more careful about when it frees the
+	  frame, i.e., only under the same conditions that applied when we
+	  duplicated it in the first place. ........ Merged revisions
+	  349822 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-05 23:47 +0000 [r349782-349821]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, cel/cel_sqlite3_custom.c: Make not assume that the
+	  cel_sqlite3_custom SQL table primary key is AcctId. If a table is
+	  created by some other application and the primary key is not
+	  named "AcctId", cel/cel_sqlite3_custom.c will always try to
+	  create the table and fail because it already exists. * Change the
+	  SQL table query to not require AcctId as the primary key. (closes
+	  issue ASTERISK-18963) Reported by: socketpair Patches: fix.patch
+	  (license #6337) patch uploaded by socketpair ........ Merged
+	  revisions 349819 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349820 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* UPGRADE.txt, pbx/pbx_config.c: Make pbx_config.c use Gosub
+	  instead of Macro call for stdexten. Users created by users.conf
+	  with hasvoicemail=yes have been documented as using a Gosub to
+	  stdexten since v1.6.0. However, the code still generates dialplan
+	  to access stdexten as a Macro as documented in v1.4; which does
+	  not work with the newer extensions.conf.sample file. * Make
+	  generated dialplan access the stdexten dialplan with the
+	  documented Gosub instead of the older Macro style. (closes issue
+	  ASTERISK-18809) Reported by: Jay Allen Patches:
+	  gosub_patch-pbx_config.patch (license #6323) patch uploaded by
+	  Jay Allen (modified) Tested by: rmudgett
+
+2012-01-05 22:11 +0000 [r349733]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/file.c: Allow playback of formats that don't support
+	  seeking ast_streamfile previously did unconditional seeking on
+	  files that broke playback of formats that don't support that
+	  functionality. This patch avoids the seek that was causing the
+	  problem. This regression was introduced in r158062. (closes issue
+	  ASTERISK-18994) Patch-by: Timo Teras ........ Merged revisions
+	  349731 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 349732 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-05 22:02 +0000 [r349674-349730]  Jonathan Rose <jrose at digium.com>
+
+	* /, main/dsp.c: Fix an issue where dsp.c would interpret multiple
+	  dtmf events from a single key press. When receiving calls from a
+	  mobile phone into a DISA system on a connection with significant
+	  interference, the reporter's Asterisk system would interpret DTMF
+	  incorrectly and replicate digits received. This patch resolves
+	  that by increasing the number of frames a mismatch has to be
+	  detected before assuming the DTMF is over by 1 frame and adjusts
+	  dtmf_detect function to reset hits and misses only when an edge
+	  is detected. (closes issue ASTERISK-17493) Reported by: Alec
+	  Davis Patches: bug18904-refactor.diff.txt uploaded by Alec Davis
+	  (license 5546) Review: https://reviewboard.asterisk.org/r/1130/
+	  ........ Merged revisions 349728 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349729 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/asterisk.c: Ensures Asterisk closes when receiving
+	  terminal signals in 'no fork' mode. When catching a signal, in no
+	  fork mode the console thread is identical to the thread
+	  responsible for catching the signal and closing Asterisk, which
+	  requires it to first dispense with the console thread. Prior to
+	  this patch, if these threads were identical, upon receiving a
+	  killing signal, the thread will send an URG signal to itself,
+	  which we also catch and then promptly do nothing with. Obviously
+	  this isn't useful behavior. (closes issue ASTERISK-19127)
+	  Reported By: Bryon Clark Patches: quit_on_signals.patch uploaded
+	  by Bryon Clark (license 6157) ........ Merged revisions 349672
 	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 400908 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400910 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-14 15:54 +0000 [r400891]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip_outbound_registration.c: pjsip outbound
-	  registration: Log message says received a 408 when we didn't If
-	  the server didn't exist that we are trying to register to the log
-	  message would say that a 408 was received from that server when
-	  in reality one wasn't. Added log messages stating no response was
-	  received if the response does not exist. (closes issue
-	  ASTERISK-22554) Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/2893/ ........ Merged
-	  revisions 400890 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-14 15:01 +0000 [r400882]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_mwi.c, /: Remove duplicate module info block The
-	  module info block was repeated twice. Once is sufficient.
-	  ........ Merged revisions 400881 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-13 15:42 +0000 [r400873]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_session.c, /: Fix a race condition in
-	  res_pjsip_session with rapidly terminating the session. The
-	  INVITE session state callback wrongly assumes that a session will
-	  always exist, but when rapidly terminating the session this
-	  assumption goes out the window. As all handler code for the
-	  INVITE session state callback requires the session it will now
-	  just exit immediately if no session exists. (closes issue
-	  ASTERISK-22668) Reported by: John Bigelow ........ Merged
-	  revisions 400872 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-12 16:53 +0000 [r400864]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_pjsip_outbound_authenticator_digest.c: Fix realm
-	  comparison for outbound auth When generating the list of
-	  authentication credentials to pass to PJSIP, Asterisk was using
-	  the raw pointer of a pj_str_t which is not always
-	  NULL-terminated. This sometimes resulted in incorrect text for
-	  the realm and a failure to match the realm for authentication
-	  purposes which was causing the outbound nominal auth pjsip basic
-	  call test to bounce. This now uses the pj_str_t that contains the
-	  realm instead of generating a new one. Thanks to John Bigelow for
-	  helping to narrow this down. ........ Merged revisions 400863
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-11 17:05 +0000 [r400855]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/channel.h, /: channel.h: whitespace changes.
-	  ........ Merged revisions 400854 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-11 16:36 +0000 [r400851-400852]  David M. Lee <dlee at digium.com>
-
-	* /, res/ari/resource_bridges.h, rest-api/api-docs/playback.json,
-	  rest-api-templates/api.wiki.mustache, res/res_ari_playback.c,
-	  rest-api/api-docs/channels.json, res/ari/resource_playback.h,
-	  rest-api/api-docs/bridges.json,
-	  rest-api-templates/asterisk_processor.py,
-	  res/ari/resource_channels.h,
-	  rest-api-templates/models.wiki.mustache: Multiple revisions
-	  400508,400842-400843,400848 ........ r400508 | dlee | 2013-10-03
-	  23:54:51 -0500 (Thu, 03 Oct 2013) | 1 line Corrected response
-	  class for stopPlayback ........ r400842 | dlee | 2013-10-10
-	  14:23:24 -0500 (Thu, 10 Oct 2013) | 1 line Correct some ARI wiki
-	  rendering errors ........ r400843 | dlee | 2013-10-10 14:26:19
-	  -0500 (Thu, 10 Oct 2013) | 1 line Updated /play resource docs.
-	  The playback of http: resources isn't implemented... yet ........
-	  r400848 | dlee | 2013-10-11 11:18:46 -0500 (Fri, 11 Oct 2013) | 5
-	  lines Fix a stupid copy/paste error in ARI docs. Patches:
-	  ari-doc-patch.txt uploaded by jbigelow (license 5091) ........
-	  Merged revisions 400508,400842-400843,400848 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /: Fixed merge tracking for r400360, which was somehow lost
-
-2013-10-11 16:28 +0000 [r400850]  Richard Mudgett <rmudgett at digium.com>
-
-	* bridges/bridge_softmix.c, /: Softmix: Fix crash when switching
-	  from softmix to another bridge technology. The crash is caused by
-	  a race condition when switching between native RTP and softmix
-	  bridging technologies. In this situation, the bridging technology
-	  is switched from native RTP to softmix, and then back to native
-	  RTP fast enough that the softmix private data gets destroyed
-	  before the softmix mixing thread gets started. Thanks to Kinsey
-	  Moore for the crash analysis. * Fix race condition when starting
-	  the softmix mixing thread and switching to another bridge
-	  technology. (closes issue ASTERISK-22678) Reported by: John
-	  Bigelow Patches: jira_asterisk_22678_v12.patch (license #5621)
-	  patch uploaded by rmudgett Tested by: John Bigelow ........
-	  Merged revisions 400849 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-10 18:21 +0000 [r400825-400834]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip/location.c: Perform validation of permanent
-	  contacts on AORs in res_pjsip. ........ Merged revisions 400833
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_configuration.c, res/res_pjsip.c: Fix an
-	  assertion in res_pjsip when specifying an invalid outbound proxy.
-	  This change fixes two issues when setting an outbound proxy: 1.
-	  The outbound proxy URI was not parsed and validated during
-	  configuration. 2. If an outgoing dialog was created and the
-	  outbound proxy could not be set an assertion would occur because
-	  the usage count on the dialog was not decremented. The
-	  documentation has also been updated to specify that a full URI
-	  must be specified for the outbound proxy. (closes issue
-	  ASTERISK-22672) Reported by: Antti Yrjola ........ Merged
-	  revisions 400824 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-09 11:02 +0000 [r400772-400813]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_pjsip_header_funcs.c, /: Use 'z' as the format specifier
-	  for size_t Using 'lu' will produce a compiler warning for some
-	  versions of gcc and on some architectures. 'z' should be portable
-	  as a format specifier for size_t. ........ Merged revisions
-	  400812 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_header_funcs.c (added), /: Add PJSIP_HEADER
-	  function for manipulation of SIP headers in the PJSIP stack This
-	  patch adds support to the PJSIP stack in Asterisk for SIP header
-	  manipulation. Note that this is analagous to
-	  SIPAddHeader/SIPRemoveHeader. For PJSIP_HEADER, an incoming
-	  supplemental session callback is registered that takes the
-	  pjsip_hdrs from the incoming session and stores them in a linked
-	  list in the session datastore. Calls to PJSIP_HEADER traverse
-	  over the list and return the nth matching header where 'n' is the
-	  'number' argument to the function. When adding a header, the
-	  first call creates a datastore and linked list and adds the
-	  datastore to the session. The header is then created as a
-	  pjsip_hdr and added to the list. An outgoing supplemental session
-	  callback then traverses the list and adds the headers to the
-	  outgoing pjsip_msg. When removing a header, the list created with
-	  PJSIP_HEADER(add,...) is traversed and all matching entries are
-	  removed. (closes issue ASTERISK-22498) Reported by: George Joseph
-	  patch: res_pjsip_header_funcs_v1.patch uploaded by george.joseph
-	  (License 6322) ........ Merged revisions 400771 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-08 22:33 +0000 [r400770]  Kinsey Moore <kmoore at digium.com>
+	  Merged revisions 349673 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-04 22:23 +0000 [r349609-349634]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/confbridge/conf_config_parser.c: Fix for ConfBridge
+	  config parser unlocking channel mutex too many times When looking
+	  up a ConfBridge profile, the config parser would, if it found a
+	  channel datastore on the channel requesting the bridge profile,
+	  unlock the channel mutex twice. Since that's a little aggressive,
+	  it now only unlocks it once. (closes issue ASTERISK-19042)
+	  Reported by: Matt Jordan Tested by: Matt Jordan Patches: 19042
+	  uploaded by David Vossel (license 5628) ........ Merged revisions
+	  349619 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, res/res_fax.c: Free successfully translated frame in
+	  fax_gateway_framehook A frame that is translated via
+	  ast_translate is also duplicated via ast_frdup. This will
+	  allocate a new frame on the heap, which needs to be free'd at the
+	  appropriate time. This issue reporter used valgrind to find that
+	  this occurred in res_fax's fax_gateway_framehook; a quick search
+	  through the code showed that only place this was currently not
+	  handling the translatted frame properly. (closes issue
+	  ASTERISK-19133) Reported by: Sylvain Rochet ........ Merged
+	  revisions 349608 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-04 20:55 +0000 [r349560]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Fix segfault in chan_dahdi for
+	  CHANNEL(dahdi_span) evaluation on hangup. * Added NULL private
+	  pointer checks in the following chan_dahdi channel callbacks:
+	  dahdi_func_read(), dahdi_func_write(), dahdi_setoption(), and
+	  dahdi_queryoption(). (closes issue ASTERISK-19142) Reported by:
+	  Diego Aguirre Tested by: rmudgett ........ Merged revisions
+	  349558 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 349559 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2012-01-04 20:24 +0000 [r349506-349535]  Kinsey Moore <kmoore at digium.com>
+
+	* contrib/init.d/rc.debian.asterisk, /: Make debian init script
+	  conform to the LSB standard Previously, this init script would
+	  return 1 if Asterisk was already running. This is incorrect
+	  behavior according to the LSB standard and has been fixed by
+	  returning 0 instead. (closes issue ASTERISK-17958) Reported-by:
+	  johnc ........ Merged revisions 349529 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349532 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, contrib/scripts/autosupport.8, contrib/scripts/autosupport:
+	  Update autosupport script and man page Added information
+	  collection from the output of the utilities: top, free, uptime,
+	  ifconfig Added information collection from the output of the
+	  Asterisk command 'dahdi show status' Added option / flag '-n,
+	  --non-interactive' Updated man page to reflect new option / flag
+	  '-n, --non-interactive' Patch-by: John Bigelow (itzanger) (closes
+	  issue AST-749) ........ Merged revisions 349504 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349505 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, configure, configure.ac: Add warning when compiling with iODBC
-	  support When running configure, libiodbc2 development headers
-	  will fulfill the requirement for ODBC development headers, but
-	  will not function properly. This adds a warning when libiodbc2
-	  development headers are detected instead of unixodbc development
-	  headers. (closes issue ASTERISK-22459) Reported by: Patrick
-	  Maille Tested by: Walter Doekes Patches:
-	  issueA22459_warn_when_using_iodbc.patch uploaded by Walter Doekes
-	  (License 5674) ........ Merged revisions 400767 from
+2012-01-04 19:53 +0000 [r349452-349503]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Adds Subscription-State header to notify
+	  with call completion. per RFC3265 (Closes issue ASTERISK-17953)
+	  Reported by: George Konopacki Patches: 19400.patch uploaded by
+	  mmichelson (license 5049) ........ Merged revisions 349482 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349502 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/pbx.c, /: Fix documentation for SayNumber to reflect the
+	  fact that language is changed in CHANNEL() (closes issue
+	  ASTERISK-18962) reported by: Nir Simionovich ........ Merged
+	  revisions 349450 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349451 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-31 15:48 +0000 [r349409-349410]  Russell Bryant <russell at russellbryant.com>
+
+	* channels/chan_sip.c: Fix some minor formatting issues based on
+	  coding guidelines.
+
+	* channels/sip/include/dialog.h, channels/chan_sip.c,
+	  include/asterisk/astobj2.h, main/astobj2.c: Constify tag argument
+	  in REF_DEBUG related code.
+
+2011-12-29 15:16 +0000 [r349341]  Matthew Jordan <mjordan at digium.com>
+
+	* main/rtp_engine.c, /: Handle AST_CONTROL_UPDATE_RTP_PEER frames
+	  in local bridge loop Failing to handle
+	  AST_CONTROL_UPDATE_RTP_PEER frames in the local bridge loop
+	  causes the loop to exit prematurely. This causes a variety of
+	  negative side effects, depending on when the loop exits. This
+	  patch handles the frame by essentially swallowing the frame in
+	  the local loop, as the current channel drivers expect the RTP
+	  bridge to handle the frame, and, in the case of the local bridge
+	  loop, no additional action is necessary. (issue ASTERISK-19040)
+	  (issue ASTERISK-19128) (issue ASTERISK-17725) (issue
+	  ASTERISK-18340) (closes issue ASTERISK-19095) Reported by: Stefan
+	  Schmidt Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1640/ ........ Merged
+	  revisions 349339 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400768 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400769 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 349340 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-08 21:20 +0000 [r400759]  Richard Mudgett <rmudgett at digium.com>
+2011-12-28 21:39 +0000 [r349291]  Sean Bright <sean at malleable.com>
 
-	* apps/app_agent_pool.c, /: app_agent_pool: Fix AMI/CLI AgentLogoff
-	  soft preventing agents from logging back in. * Clear the
-	  deferred_logoff flag when an agent logs in. (closes issue
-	  ASTERISK-22669) Reported by: John Bigelow ........ Merged
-	  revisions 400754 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, main/audiohook.c: Use ast_audiohook_write_list_empty to
+	  determine if our lists are empty instead of duplicating that
+	  logic. ........ Merged revisions 349289 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349290 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-28 19:00 +0000 [r349249-349251]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* utils, /: Tell Subversion to gnore the 'astdb2bdb' binary file if
+	  it exists. ........ Merged revisions 349250 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, res/res_fax.c, include/asterisk/dsp.h,
+	  include/asterisk/res_fax.h, res/res_fax_spandsp.c, main/dsp.c:
+	  Improve T.38 gateway V.21 preamble detection. This commit removes
+	  the V.21 preamble detection code previously added to the generic
+	  DSP implementation in Asterisk, and instead enhances the res_fax
+	  module to be able to utilize V.21 preamble detection
+	  functionality made available by FAX technology modules. This
+	  commit also adds such support to res_fax_spandsp, which uses the
+	  Spandsp modem tone detection code to do the V.21 preamble
+	  detection. There should be no functional change here, other than
+	  much more reliable V.21 preamble detection (and thus T.38 gateway
+	  initiation). ........ Merged revisions 349248 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-27 20:55 +0000 [r349196]  Matthew Jordan <mjordan at digium.com>
+
+	* /, res/res_timing_pthread.c, include/asterisk/module.h,
+	  res/res_timing_dahdi.c, res/res_timing_timerfd.c,
+	  res/res_musiconhold.c: Fix timing source dependency issues with
+	  MOH Prior to this patch, res_musiconhold existed at the same
+	  module priority level as the timing sources that it depends on.
+	  This would cause a problem when music on hold was reloaded, as
+	  the timing source could be changed after res_musiconhold was
+	  processed. This patch adds a new module priority level,
+	  AST_MODPRI_TIMING, that the various timing modules are now loaded
+	  at. This now occurs before loading other resource modules, such
+	  that the timing source is guaranteed to be set prior to resolving
+	  the timing source dependencies. (closes issue ASTERISK-17474)
+	  Reporter: Luke H Tested by: Luke H, Vladimir Mikhelson, zzsurf,
+	  Wes Van Tlghem, elguero, Thomas Arimont Patches:
+	  asterisk-17474-dahdi_timing-infinite-wait-fix_v3_branch-1.8.diff
+	  uploaded by elguero (License #5026)
+	  asterisk-17474-dahdi_timing-infinite-wait-fix_v3_branch-10.diff
+	  uploaded by elguero (License #5026)
+	  asterisk-17474-dahdi_timing-infinite-wait-fix_v3.diff uploaded by
+	  elguero (License #5026) Review:
+	  https://reviewboard.asterisk.org/r/1578/ ........ Merged
+	  revisions 349194 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349195 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-08 20:52 +0000 [r400750]  Mark Michelson <mmichelson at digium.com>
+2011-12-27 17:17 +0000 [r349146]  Sean Bright <sean at malleable.com>
 
-	* /, res/res_pjsip.c, res/res_pjsip/config_transport.c: Switch from
-	  using pjsip_strerror to pj_strerror. pjsip_strerror is only aware
-	  of PJSIP-specific error codes. pj_strerror() is aware of all
-	  PJProject error codes and OS-specific error codes. This
-	  specifically fixes an oft-seen error in transport configuration
-	  code where EADDRINUSE would result in "Unknown PJSIP error
-	  120098" instead of a useful message. ........ Merged revisions
-	  400749 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, main/audiohook.c: Once an audiohook is attached to a channel,
+	  we continue to transcode all of the frames, even after all of the
+	  hooks are detached. This patch short-cicuits us out before we
+	  transcode unnecessarily. ........ Merged revisions 349144 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 349145 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-23 21:19 +0000 [r349106]  Matthew Jordan <mjordan at digium.com>
+
+	* contrib/realtime/mysql/voicemail.sql,
+	  configs/voicemail.conf.sample, CHANGES, apps/app_voicemail.c:
+	  Allow overriding of IMAP server settings on a user by user basis
+	  This patch allows the imapserver, imapport, and imapflags
+	  settings to be overridden for any voicemail user. It also
+	  documents the settings in the sample voicemail.conf file, and
+	  updates the voicemail schema to allow storage of those columns.
+	  (closes issue ASTERISK-16489) Reporter: Hubert Mickael Tested by:
+	  Matt Jordan Review: https://reviewboard.asterisk.org/r/1614/
+
+2011-12-23 20:42 +0000 [r349097-349098]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c, main/features.c, configs/sip.conf.sample,
+	  channels/sip/include/sip.h: INFO/Record request configurable to
+	  use dynamic features Adds two new options to SIP peers allowing
+	  them to specify features (dynamic or builtin) to use when sending
+	  INFO/record requests. Recordonfeature activates whatever feature
+	  is specified when recieving a record: on request while
+	  recordofffeature activates whatever feature is specified when
+	  receiving a record: off request. Both of these features can be
+	  disabled by setting the feature to an empty string. (closes issue
+	  ASTERISK-16507) Reported by: Jon Bright Review:
+	  https://reviewboard.asterisk.org/r/1634/
+
+	* channels/chan_sip.c, configs/sip.conf.sample, CHANGES,
+	  channels/sip/include/sip.h: chan_sip autocreatepeer=persist
+	  option for auto-created peers to survive reload This patch moves
+	  destruction of sip peers to immediately after the general section
+	  of sip.conf is read so that autocreatepeer setting can be read
+	  before deletion of peers. If autocreatepeer=persist at reload,
+	  then peers created by the autocreatepeer setting will be skipped
+	  when purging the current SIP peer list. (closes ASTERISK-16508)
+	  Reported by: Kirill Katsnelson Patches:
+	  017797-kkm-persist-autopeers-1.8.patch uploaded by Kirill
+	  Katsnelson (license 5845)
+
+2011-12-23 17:36 +0000 [r349046]  Sean Bright <sean at malleable.com>
+
+	* /, apps/app_chanspy.c: Merged revisions 349045 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r349045 | seanbright | 2011-12-23 12:32:33 -0500
+	  (Fri, 23 Dec 2011) | 25 lines Merged revisions 349044 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r349044 | seanbright | 2011-12-23 12:25:01 -0500 (Fri, 23 Dec
+	  2011) | 18 lines In ChanSpy, don't create audiohooks that will
+	  never be used. When ChanSpy is initialized it creates and
+	  attaches 3 audiohooks: 1) Read audio off of the channel that we
+	  are spying on 2) Write audio to the channel that we are spying on
+	  3) Write audio to the channel that is bridged to the channel that
+	  we are spying on. The first is always necessary, but the others
+	  are used only when specific options are passed to the ChanSpy
+	  application (B, d, w, and W to be specific). When those flags are
+	  not passed, neither of those audiohooks are ever sent frames, but
+	  we still try to process the hooks for each voice frame that we
+	  recieve on the channel. So in short - only create and attach
+	  audiohooks that we actually need. ........ ................
+
+2011-12-23 15:26 +0000 [r348994]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_dial.c, /: Fix missing doc tags found while fixing
+	  ASTERISK-18689 Add missing <variable></variable> tags in app_dial
+	  documentation. ........ Merged revisions 348992 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348993 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-23 02:35 +0000 [r348953]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /, channels/chan_sip.c, include/asterisk/pbx.h: Fix
+	  extension state callback references in chan_sip. Chan_sip gives a
+	  dialog reference to the extension state callback and assumes that
+	  when ast_extension_state_del() returns, the callback cannot
+	  happen anymore. Chan_sip then reduces the dialog reference count
+	  associated with the callback. Recent changes (ASTERISK-17760)
+	  have resulted in the potential for the callback to happen after
+	  ast_extension_state_del() has returned. For chan_sip, this could
+	  be very bad because the dialog pointer could have already been
+	  destroyed. * Added ast_extension_state_add_destroy() so chan_sip
+	  can account for the sip_pvt reference given to the extension
+	  state callback when the extension state callback is deleted. *
+	  Fix pbx.c awkward statecbs handling in
+	  ast_extension_state_add_destroy() and handle_statechange() now
+	  that the struct ast_state_cb has a destructor to call. * Ensure
+	  that ast_extension_state_add_destroy() will never return -1 or 0
+	  for a successful registration. * Fixed pbx.c statecbs_cmp() to
+	  compare the correct information. The passed in value to compare
+	  is a change_cb function pointer not an object pointer. * Make
+	  pbx.c ast_merge_contexts_and_delete() not perform callbacks with
+	  AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for
+	  deadlocking when those locks are held during the callback. *
+	  Removed unused lock declaration for the pbx.c store_hints list.
+	  (closes issue ASTERISK-18844) Reported by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/1635/ ........ Merged
+	  revisions 348940 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348952 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-22 22:39 +0000 [r348890]  Matthew Jordan <mjordan at digium.com>
+
+	* cel/cel_pgsql.c, /: Fix for memory leaks / cleanup in cel_pgsql
+	  There were a number of issues in cel_pgsql's pgsql_log method: *
+	  If either sql or sql2 could not be allocated, the method would
+	  return while the pgsql_lock was still locked * If the execution
+	  of the log statement succeeded, the sql and sql2 structs were
+	  never free'd * Reconnection successes were logged as ERRORs. In
+	  general, the severity of several logging statements was reduced
+	  (closes issue ASTERISK-18879) Reported by: Niolas Bouliane Tested
+	  by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1624/
+	  ........ Merged revisions 348888 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348889 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-22 21:12 +0000 [r348849]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix segfault on answer. Only
+	  update/change RTP source if RTP has already been started and
+	  connected to the subchannel.
+
+2011-12-22 20:44 +0000 [r348848]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/say.c, main/file.c, main/app.c, apps/app_confbridge.c,
+	  main/bridging.c: Add Asterisk TestSuite event hooks to support
+	  ConfBridge testing This patch adds initial testsuite event hooks
+	  so that ConfBridge tests can be executed in the Asterisk
+	  TestSuite. (issue ASTERISK-19059) ........ Merged revisions
+	  348846 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-22 20:39 +0000 [r348847]  Terry Wilson <twilson at digium.com>
+
+	* /, include/asterisk/format_pref.h: Allow packetization vaules >
+	  127 According to the RTP packetization documentation, and the
+	  maximum values listed in AST_FORMAT_LIST, we should support
+	  values > that the signed char array that ast_codec_pref makes
+	  available to store the value. All places in the code treat the
+	  framing field as though it were an int array instaead of a char
+	  array anyway, so this just fixes the type of the array. (closes
+	  issue ASTERISK-18876) Review:
+	  https://reviewboard.asterisk.org/r/1639/ ........ Merged
+	  revisions 348833 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348845 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-08 20:18 +0000 [r400728-400744]  Richard Mudgett <rmudgett at digium.com>
+2011-12-21 20:13 +0000 [r348737-348794]  Richard Mudgett <rmudgett at digium.com>
 
-	* configs/confbridge.conf.sample, /,
-	  apps/confbridge/include/confbridge.h, apps/app_confbridge.c,
-	  CHANGES, apps/confbridge/conf_config_parser.c: app_confbridge:
-	  Can now set the language used for announcements to the
-	  conference. ConfBridge now has the ability to set the language of
-	  announcements to the conference. The language can be set on a
-	  bridge profile in confbridge.conf or by the dialplan function
-	  CONFBRIDGE(bridge,language)=en. (closes issue ASTERISK-19983)
-	  Reported by: Jonathan White Patches: M19983_rev2.diff (license
-	  #5138) patch uploaded by junky (modified) Tested by: rmudgett
-	  ........ Merged revisions 400741 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400742 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, codecs/speex: Make codecs/speex ignore *.i files also.
+	  ........ Merged revisions 348793 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* apps/confbridge/conf_config_parser.c, /: app_confbridge: Fix
-	  duplicate default_user profile. * Fixed looking in the wrong
-	  profiles container to see if the default_user profile is already
-	  created in verify_default_profiles(). The bridge profile
-	  container is never going to hold user profiles. :) ........
-	  Merged revisions 400723 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400724 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, apps/confbridge: Make apps/confbridge ignore *.i files also.
+	  ........ Merged revisions 348790 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-08 18:19 +0000 [r400684-400704]  Kinsey Moore <kmoore at digium.com>
+	* /, channels/chan_iax2.c: Fix chan_iax2 to not report an RDNIS
+	  number if it is blank. Some ISDN switches complain or block the
+	  call if the RDNIS number is empty. * Made chan_iax2 not save a
+	  RDNIS number into the ast_channel if the string is blank. This is
+	  what other channel drivers do. (closes issue ASTERISK-17152)
+	  Reported by: rmudgett ........ Merged revisions 348735 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348736 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-20 20:06 +0000 [r348698]  Matthew Nicholson <mnicholson at digium.com>
+
+	* contrib/scripts/safe_asterisk: This adds support for setting
+	  several safe_asterisk parameters using environment variables and
+	  also enables a custom run directory for asterisk (instead of
+	  defaulting to /tmp). Patch by: Byron Clark (byronclark) (closes
+	  ASTERISK-17810)
+
+2011-12-19 21:43 +0000 [r348649]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, configure, configure.ac: Fix crashes on other platforms caused
+	  by interference from Darwin weak symbol support. Support weak
+	  symbols on a platform specific basis. The Mac OS X (Darwin)
+	  support must be isolated from the other platforms because it has
+	  caused other platforms to crash. Several other platforms
+	  including Linux have GCC versions that define the weak attribute.
+	  However, this attribute is only setup for use in the code by
+	  Darwin. (closes issue ASTERISK-18728) Reported by: Ben Klang
+	  Review: https://reviewboard.asterisk.org/r/1617/ ........ Merged
+	  revisions 348647 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348648 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-19 19:55 +0000 [r348606]  Leif Madsen <leif at leifmadsen.com>
+
+	* /, main/message.c: Update documentation for MESSAGE_SEND_STATUS
+	  variable. (Closes issue ASTERISK-19056) Reported by: Yuri
+	  Patches: 348360.diff uploaded by Yuri (license #5242) ........
+	  Merged revisions 348605 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-19 01:36 +0000 [r348567]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_srtp.c: Add a separate buffer for SRTCP packets The
+	  function ast_srtp_protect used a common buffer for both SRTP and
+	  SRTCP packets. Since this function can be called from multiple
+	  threads for the same SRTP session (scheduler for SRTCP and
+	  channel for SRTP) it was possible for the packets to become
+	  corrupted as the buffer was used by both threads simultaneously.
+	  This patch adds a separate buffer for SRTCP packets to avoid the
+	  problem. (closes issue ASTERISK-18889, Reported/patch by Daniel
+	  Collins) ........ Merged revisions 347995 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347996 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-18 18:29 +0000 [r348518]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, configs/sip.conf.sample: Correct two flaws in sip.conf.sample
+	  related to AST-2011-013. * The sample file listed *two* values
+	  for the 'nat' option as being the default. Only 'force_rport' is
+	  the default. * The warning about having differing 'nat' settings
+	  confusingly referred to both peers and users. ........ Merged
+	  revisions 348515 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.6.2 ........
+	  Merged revisions 348516 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348517 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-16 23:58 +0000 [r348466]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /, main/features.c: Clean-up on isle five for
+	  __ast_request_and_dial() and ast_call_forward(). * Add locking
+	  when a channel inherits variables and datastores in
+	  __ast_request_and_dial() and ast_call_forward(). Note: The
+	  involved channels are not active so there was minimal potential
+	  for problems. * Remove calls to ast_set_callerid() in
+	  __ast_request_and_dial() and ast_call_forward() because the set
+	  information is for the wrong direction. * Don't use C++ keywords
+	  for variable names in ast_call_forward(). * Run the redirecting
+	  interception macro if defined when forwarding a call in
+	  ast_call_forward(). Note: Currently will never execute because
+	  the only callers that supply a calling channel supply a hungup or
+	  zombie channel. * Make feature_request_and_dial() put the
+	  transferee into autoservice when it calls ast_call_forward() in
+	  case a redirection interception macro is run. Note: Currently
+	  will never happen because the caller channel (Party B) is always
+	  hungup at this time. * Make feature_request_and_dial() ignore the
+	  AST_CONTROL_PROCEEDING frame to silence a log message. ........
+	  Merged revisions 348464 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348465 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-16 22:00 +0000 [r348416]  Jonathan Rose <jrose at digium.com>
+
+	* configs/voicemail.conf.sample, CHANGES, apps/app_voicemail.c:
+	  Voicemail with the saycid option will now play a caller's name
+	  based on cid if available. In order to check the availability of
+	  the caller's name, app_voicemail will check for an audio file in
+	  <astspooldir>/recordings/callerids/ This change sets a precedent
+	  for where to put recordings of names. Currently the idea is that
+	  recordings here could also be used for applications like
+	  confbridge and meetme to find recorded names in this folder from
+	  callerid (when another recording isn't available) (closes issue
+	  ASTERISK-18565) Reporter: Russell Brown Patches: r uploaded by
+	  Russel Brown (license 6182)
+
+2011-12-16 21:30 +0000 [r348312-348408]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/channel.c, /: Fix cut and past error in ast_call_forward().
+	  (issue ASTERISK-18836) ........ Merged revisions 348401 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348405 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/channel.c, main/pbx.c, /, apps/app_authenticate.c,
+	  funcs/func_cdr.c, main/features.c, include/asterisk/cdr.h,
+	  apps/app_followme.c, apps/app_queue.c, res/res_monitor.c: Fix
+	  crash during CDR update. The ast_cdr_setcid() and
+	  ast_cdr_update() were shown in ASTERISK-18836 to be called by
+	  different threads for the same channel. The channel driver thread
+	  and the PBX thread running dialplan. * Add lock protection around
+	  CDR API calls that access an ast_channel pointer. (closes issue
+	  ASTERISK-18836) Reported by: gpluser Review:
+	  https://reviewboard.asterisk.org/r/1628/ ........ Merged
+	  revisions 348362 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348363 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_parkandannounce.c: Fix ParkAndAnnounce to pass the
+	  CallerID to the announcing channel. ParkAndAnnounce tried to pass
+	  the CallerID to the announcing channel but the ID was wiped out
+	  by the channel masquerade done when parking the call. * Save the
+	  CallerID before parking the channel to pass it to the announcing
+	  channel. * Fixed a minor memory leak in ParkAndAnnounce. *
+	  Updated some ParkAndAnnounce log messages. ........ Merged
+	  revisions 348310 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348311 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-14 22:36 +0000 [r348215-348266]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_originate.c: Added support for all slin formats to
+	  app_originate Previously, app_originate could not originate a
+	  call into a non-8kHz conference bridge as the formats for
+	  non-8kHz slin codecs were not applied to the created channel.
+	  This patch adds all of the formats by default, such that if a
+	  created channel has a codec that supports a higher sampling rate,
+	  a translation path can be built between it and other channels.
+	  ........ Merged revisions 348265 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Fixed Asterisk crash when function
+	  QUEUE_MEMBER receives invalid input The function QUEUE_MEMBER has
+	  two required parameters (queuename, option). It was only checking
+	  for the presence of queuename. The patch checks for the existence
+	  of the option parameter and provides better error logging when
+	  invalid values are provided for the option parameter as well.
+	  ........ Merged revisions 348211 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-14 22:05 +0000 [r348214]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Don't clear LOCALSTATIONID before sending or
+	  receiving. The user may set that variable. ASTERISK-18921
+	  ........ Merged revisions 348212 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348213 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-14 21:08 +0000 [r348161]  Jonathan Rose <jrose at digium.com>
+
+	* main/features.c, configs/features.conf.sample: Add and document
+	  PARKEDCALL variable set during timeout PARKEDCALL variable tracks
+	  which parking lot the call was last parked in. This can be used
+	  afterwards for flow control when returntoorigin is set to off. I
+	  went ahead and documented both this and the existing variable set
+	  during timeout (PARKINGSLOT) in the sample features.conf since
+	  there was no prior mention of variables being set during timeout.
+	  (closes issue ASTERISK-16239) Reported By: Clod Patry Patches:
+	  M17503.diff uploaded by Clod Patry (license 5138)
+
+2011-12-14 20:51 +0000 [r348160]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_confbridge.c: Improve error message in CONFBRIDGE_INFO
+	  Provided a more descriptive error message when a value supplied
+	  for the parameter type is not one of the acceptable values.
+	  (closes issue ASTERISK-18717) Reported by: Paul Belanger Patches:
+	  __20111103-better-confbridge_info-error-msg.txt (License #4999)
+
+2011-12-14 20:37 +0000 [r348156-348159]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/features.conf.sample: Fix accidental use of tabs
+	  instead of spaces from previous features.conf.sample change
+	  ........ Merged revisions 348157 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348158 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* funcs/func_config.c, /: Fix func_config list entry allocation The
-	  AST_CONFIG dialplan function defined in func_config.c allocates
-	  its config file list entries using ast_malloc. List entry
-	  allocations destined for use with Asterisk's linked list API must
-	  be ast_calloc()d or otherwise initialized so that list pointers
-	  are set to NULL. These uses of ast_malloc have been replaced by
-	  ast_calloc to prevent dereferencing of uninitialized pointer
-	  values when traversing the list. (closes issue ASTERISK-22483)
-	  Reported by: Brian Scott ........ Merged revisions 400694 from
+	* /, configs/features.conf.sample: Document PARKINGSLOT variable in
+	  features.conf.sample (issue ASTERISK-16239) ........ Merged
+	  revisions 348154 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348155 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-13 23:10 +0000 [r348103]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, bridges/bridge_builtin_features.c, apps/app_followme.c: Fix
+	  FollowMe CallerID on outgoing calls. The addition of the
+	  Connected Line support changed how CallerID is passed to outgoing
+	  calls. The FollowMe application was not updated to pass CallerID
+	  to the outgoing calls. * Fix FollowMe CallerID on outgoing calls.
+	  * Restructured findmeexec() to fix several memory leaks and
+	  eliminate some duplicated code. * Made check the return value of
+	  create_followme_number(). Putting a NULL into the numbers list is
+	  bad if create_followme_number() fails. * Fixed a couple uses of
+	  ast_strdupa() inside loops. * The changes to
+	  bridge_builtin_features.c fix a similar CallerID issue with the
+	  bridging API attended and blind transfers. (Not used at this
+	  time.) (closes issue ASTERISK-17557) Reported by: hamlet505a
+	  Tested by: rmudgett Review:
+	  https://reviewboard.asterisk.org/r/1612/ ........ Merged
+	  revisions 348101 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400697 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400701 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 348102 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* res/res_rtp_asterisk.c, /: Fix STUN crash when using IPv6 any
-	  address Ensure that when chan_sip binds to the IPv6 any address
-	  ([::]), IPv4 candidates are also added. (closes issue
-	  ASTERISK-21917) Reported by: Torrey Searle Patches:
-	  0023_ipv6_stun_crash.patch uploaded by Torrey Searle (License
-	  5334) ........ Merged revisions 400681 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400682 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-08 15:44 +0000 [r400683]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip/pjsip_options.c, /: Push CLI qualify into the
-	  threadpool. If you run Asterisk in the background and then
-	  connect to it through a separate console, the thread that runs
-	  CLI commands is not registered with PJLIB. Thus PJLIB does not
-	  like it when you attempt to send OPTIONS requests from that
-	  thread. So now we push the task into the threadpool, which we
-	  know to be registered with PJLIB. Thanks to Antti Yrjola for
-	  reporting this. ........ Merged revisions 400680 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-08 15:12 +0000 [r400662-400672]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, res/res_agi.c, apps/app_queue.c: Make app_queue and res_agi
-	  independent of AMI being enabled. The
-	  https://reviewboard.asterisk.org/r/2888/ review changes manager
-	  to not subscribe to stasis when it is disabled for performance
-	  reasons. When manager is disabled app_queue and res_agi decline
-	  to load and fail to clean up what they have already allocated. *
-	  Made app_queue and res_agi clean up allocated resources when they
-	  decline to load. * Made app_queue and res_agi use their own
-	  subscriptions to the stasis topics instead of borrowing manager's
-	  message router structure inappropriately. (closes issue
-	  ASTERISK-22604) Reported by: rmudgett Review:
-	  https://reviewboard.asterisk.org/r/2902/ ........ Merged
-	  revisions 400671 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, include/asterisk/stasis.h, apps/app_queue.c,
-	  include/asterisk/manager.h: Miscellaneous stand alone comment
-	  cleanups. ........ Merged revisions 400661 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-06 17:13 +0000 [r400625]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, apps/app_queue.c: app_queue: Fix Queuelog EXITWITHKEY only
-	  logging two of four fields Commit r62462 added two extra fields
-	  for logging "the original position the caller entered the queue
-	  at, and the amount of time the caller was waiting in the queue."
-	  But when r75969 was merged from 1.4 into trunk (r75977), these
-	  two fields disappeared. Those two extra fields were not logged in
-	  1.4 and when the patch was merged, those fields went away.
-	  Therefore, this is a regression and was caught by the reporter
-	  because he was reading the awesome "Asterisk: The Definitive
-	  Guide" book. (closes issue ASTERISK-22197) Reported by: Dalius M.
-	  Tested by: Dalius M. Patches:
-	  asterisk-22197-q-log-exitwithkey.diff uploaded by Michael L.
-	  Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2901/ ........ Merged
-	  revisions 400622 from
+2011-12-13 15:22 +0000 [r348061]  Stefan Schmidt <sst at sil.at>
+
+	* channels/chan_sip.c: Fix possible misshandling of an incoming SIP
+	  response as a peer poke response. Also make sure peer has even
+	  qualify enabled when handle a peer poke response. (closes issue
+	  ASTERISK-18940) Reported by: Vitaliy Tested by: Vitaliy and
+	  UnixDev Review: https://reviewboard.asterisk.org/r/1620 Reviewed
+	  by: David Vossel ........ Merged revisions 348048 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 348056 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-12 19:35 +0000 [r347997]  Matthew Jordan <mjordan at digium.com>
+
+	* include/asterisk/logger.h, utils/refcounter.c, main/logger.c,
+	  utils/hashtest.c, UPGRADE.txt, utils/ael_main.c,
+	  utils/hashtest2.c, CHANGES, main/asterisk.c, main/config.c,
+	  configs/logger.conf.sample, main/loader.c, main/cli.c: Backed out
+	  core changes from r346391 During testing, it was discovered that
+	  there were a number of side effects introduced by r346391 and
+	  subsequent check-ins related to it (r346429, r346617, and
+	  r346655). This included the /main/stdtime/ test 'hanging', as
+	  well as the remote console option failing to receive the
+	  appropriate output after a period of time. I only backed out the
+	  changes to main/ and utils/, as this was adequate to reverse the
+	  behavior experienced. (issue ASTERISK-18974)
+
+2011-12-12 17:34 +0000 [r347954]  Richard Mudgett <rmudgett at digium.com>
+
+	* configs/iax.conf.sample, configs/chan_dahdi.conf.sample, /,
+	  configs/chan_ooh323.conf.sample, configs/vpb.conf.sample,
+	  configs/extensions.lua.sample, configs/sip.conf.sample,
+	  configs/extensions.conf.sample: Update sample configs to put
+	  incoming calls into context public. * Add warning about the SIP
+	  allowguest option in context public. (closes issue
+	  ASTERISK-14122) Reported by: Alec Davis Review:
+	  https://reviewboard.asterisk.org/r/719/ ........ Merged revisions
+	  347953 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-09 21:47 +0000 [r347866-347903]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_mixmonitor.c: Adds MixMonitor and StopMixMonitor AMI
+	  commands to the manager These commands work much like the
+	  dialplan applications that would otherwise invoke them. A nice
+	  benefit of these is that they can be invoked on a call remotely
+	  and at any time during a call. They work much like the Monitor
+	  and StopMonitor ami commands. (closes issue ASTERISK-17726)
+	  Reported by: Sergio González Martín Patches:
+	  mixmonitor_actions.diff uploaded by Sergio González Martín
+	  (license 5644) Review: https://reviewboard.asterisk.org/r/1193/
+
+	* include/asterisk/file.h, apps/app_sayunixtime.c, CHANGES: Remove
+	  autojump extensions from SayUnixTime, make an option to perform
+	  automatic jumps. When a caller sends DTMF while the SayUnixTime
+	  application is saying the time, The call would jump to the next
+	  extension much like it does during Background(). This patch adds
+	  option 'j' to SayUnixTime which when used employs the old
+	  behavior. Also, this patch allows arguments to sayunixtime to not
+	  be used as empty strings in the case of something like
+	  'sayunixtime(,,,j)' or 'sayunixtime(,,pattern). (closes issue
+	  ASTERISK-16675) Reported by: jlpedrosa Patches:
+	  patch_SayUnixTime_noJump.patch uploaded by jlpedrosa (license
+	  5959) Review: https://reviewboard.asterisk.org/r/956/
+
+2011-12-09 01:33 +0000 [r347813]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /: Fix some parsing issues in
+	  add_exten_to_pattern_tree(). * Simplify compare_char() and avoid
+	  potential sign extension issue. * Fix infinite loop in
+	  add_exten_to_pattern_tree() handling of character set escape
+	  handling. * Added buffer overflow checks in
+	  add_exten_to_pattern_tree() character set collection. * Made
+	  ignore empty character sets. * Added escape character handling to
+	  end-of-range character in character sets. This has a slight
+	  change in behavior if the end-of-range character is an escape
+	  character. You must now escape it. * Fix potential sign extension
+	  issue when expanding character set ranges. * Made remove
+	  duplicated characters from character sets. The duplicate
+	  characters lower extension matching priority and prevent
+	  duplicate extension detection. * Fix escape character handling
+	  when the escape character is trying to escape the end-of-string.
+	  We could have continued processing characters after the end of
+	  the exten string. We could have added the previous character to
+	  the pattern matching tree incorrectly. (closes issue
+	  ASTERISK-18909) Reported by: Luke-Jr ........ Merged revisions
+	  347811 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 347812 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-08 21:32 +0000 [r347735]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Fix regression when using tcpenable=no
+	  and tlsenable=yes. The tlsenable settings are tucked away in
+	  main/tcptls.c, so I missed them when resolving ASTERISK-18837.
+	  This should resolve the test suite breakage of the sip tls tests.
+	  Review: https://reviewboard.asterisk.org/r/1615 Reviewed by: Matt
+	  Jordan ........ Merged revisions 347718 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347727 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-08 20:55 +0000 [r347658]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_queue.c: Fix regressed behavior of queue set penalty
+	  to work without specifying 'in <queuename>' r325483 caused a
+	  regression in Asterisk 10+ that would make Asterisk segfault when
+	  attempting to set penalty on an interface without specifying a
+	  queue in the queue set penalty CLI command. In addition, no
+	  attempt would be made whatsoever to perform the penalty setting
+	  on all the queues in the core list with either the cli command or
+	  the non-segfaulting ami equivalent. This patch fixes that and
+	  also makes an attempt to document and rename some functions
+	  required by this command to better represent what they actually
+	  do. Oh yeah, and the use of this command without specifying a
+	  specific queue actually works now. Review:
+	  https://reviewboard.asterisk.org/r/1609/ ........ Merged
+	  revisions 347656 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-08 17:55 +0000 [r347601]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Mark channel running the h exten with the
+	  soft-hangup flag. When a bridge is broken, ast_bridge_call()
+	  might execute the h exten on the calling channel. However, that
+	  channel may not have been the channel that broke the bridge by
+	  hanging up. The channel executing the h exten must be in a hung
+	  up state so things like AGI run in the correct mode. * Make sure
+	  ast_bridge_call() marks the channel it is executing the h exten
+	  on as hung up. (The AST_SOFTHANGUP_APPUNLOAD flag is used so as
+	  to match the pbx.c main dialplan execution loop when it executes
+	  the h exten.) (closes issue ASTERISK-18811) Reported by: David
+	  Hajek Patches: jira_asterisk_18811_v1.8.patch (license #5621)
+	  patch uploaded by rmudgett Tested by: David Hajek, rmudgett
+	  ........ Merged revisions 347595 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347600 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-08 16:24 +0000 [r347533]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Don't crash on INFO automon request with
+	  no channel AST-2011-014. When automon was enabled in
+	  features.conf, it was possible to crash Asterisk by sending an
+	  INFO request if no channel had been created yet. (closes issue
+	  ASTERISK-18805) ........ Merged revisions 347530 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.6.2 ........
+	  Merged revisions 347531 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347532 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-08 06:59 +0000 [r347490]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix segfault on answer. Fix a segfault if
+	  an attempt to answer a call is made between when the inbound call
+	  gives up (and the channel is removed) and when the device is
+	  notified and removes the call from the device.
+
+2011-12-07 21:42 +0000 [r347440]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /: Update AMI Getvar and Setvar documentation
+	  about supplying a channel name. (closes issue ASTERISK-18958)
+	  Reported by: Red Patches: jira_asterisk_18958_v1.8.patch (license
+	  #5621) patch uploaded by rmudgett ........ Merged revisions
+	  347438 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 347439 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-07 20:34 +0000 [r347395]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_meetme.c: Fix: Meetme recording variables from
+	  realtime DB use null entries over channel variables Meetme would
+	  attempt to substitute the realtime values of RECORDING_FILE and
+	  RECORDING_FORMAT from the meetme db entry instead of using the
+	  channel variable set for those variables in spite of those
+	  database entries being NULL or even lacking a column to represent
+	  them. (closes issue ASTERISK-18873) Reported by: Byron Clark
+	  Patches: ASTERISK-18873-1.patch uploaded by Byron Clark (license
+	  6157) ........ Merged revisions 347369 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347383 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-07 20:15 +0000 [r347345]  Terry Wilson <twilson at digium.com>
+
+	* Makefile, include/asterisk/paths.h, /,
+	  configs/asterisk.conf.sample, build_tools/make_defaults_h,
+	  main/asterisk.c, main/db.c: Add ASTSBINDIR to the list of
+	  configurable paths This patch also makes astdb2sqlite3 and
+	  astcanary use the configured directory instead of relying on
+	  $PATH. (closes issue ASTERISK-18959) Review:
+	  https://reviewboard.asterisk.org/r/1613/ ........ Merged
+	  revisions 347344 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-06 23:58 +0000 [r347294]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Make SIP INFO messages for dtmf-relay
+	  signals case insensitive. (closes issue ASTERISK-18924) Reported
+	  by: Kevin Taylor ........ Merged revisions 347292 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400623 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400624 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-05 00:59 +0000 [r400593]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, channels/iax2/include/parser.h: chan_iax2: Fix compile error.
-	  ........ Merged revisions 400588 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-04 21:41 +0000 [r400568]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* main/acl.c, include/asterisk/netsock2.h, CHANGES,
-	  channels/chan_iax2.c, channels/iax2/parser.c, main/netsock.c,
-	  main/netsock2.c, /, channels/iax2/include/parser.h: Add IPv6
-	  Support To chan_iax2 This patch adds IPv6 support to chan_iax2.
-	  Yay! (closes issue ASTERISK-22025) Patches:
-	  iax2-ipv6-v5-reviewboard.diff by Michael L. Young (license 5026)
-	  Review: https://reviewboard.asterisk.org/r/2660/ ........ Merged
-	  revisions 400567 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-04 19:32 +0000 [r400553]  David M. Lee <dlee at digium.com>
-
-	* rest-api/api-docs/applications.json (added), /: Added missing
-	  file from r400522 ........ Merged revisions 400552 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-04 19:11 +0000 [r400533-400543]  Jonathan Rose <jrose at digium.com>
-
-	* res/res_pjsip_logger.c, /: chan_pjsip: Make logger togglable
-	  without loading/unloading This patch makes the res_pjsip_logger
-	  do a few things... First, it will be built and installed by
-	  default now, so end users won't need to enable it in menuselect.
-	  Second, while it is loaded, it no longer will immediately issue
-	  log messages. Upon loading, it is in the disabled state and must
-	  be turned on with the new CLI command. The CLI command 'pjsip set
-	  logger <on/off/host> has been added and can be used to do the
-	  following: pjsip set logger on: Enables logger for all PJSIP
-	  traffic pjsip set logger off: Disables logger for all PJSIP
-	  traffic pjsip set logger host <host>: Enables logger for the
-	  specific host Review: https://reviewboard.asterisk.org/r/2900/
-	  ........ Merged revisions 400542 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /,
-	  contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py
-	  (added), configs/extconfig.conf.sample,
-	  configs/sorcery.conf.sample,
-	  contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py:
-	  chan_pjsip: Add alembic scripts for generating db tables for
-	  PJSIP Also updates sample configurations for sorcery and
-	  extconfig to demonstrate how to use databases created by that
-	  alembic script. (closes issue ASTERISK-22133) Reported by: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/2892/ ........
-	  Merged revisions 400532 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-04 16:01 +0000 [r400523]  Matthew Jordan <mjordan at digium.com>
-
-	* res/res_stasis.c, main/asterisk.c,
-	  rest-api/api-docs/endpoints.json, rest-api/api-docs/events.json,
-	  res/stasis/app.c, /,
-	  rest-api-templates/ari_model_validators.h.mustache,
-	  include/asterisk/endpoints.h, res/res_ari_applications.c (added),
-	  res/ari/resource_endpoints.h, include/asterisk/stasis_app.h,
-	  res/stasis/app.h, rest-api/resources.json,
-	  include/asterisk/_private.h, res/ari/ari_model_validators.c,
-	  main/endpoints.c, res/ari/ari_model_validators.h, main/json.c,
-	  res/res_ari_model.c, res/ari.make,
-	  res/ari/resource_applications.c (added),
-	  res/ari/resource_applications.h (added): ARI: Add subscription
-	  support This patch adds an /applications API to ARI, allowing
-	  explicit management of Stasis applications. * GET /applications -
-	  list current applications * GET /applications/{applicationName} -
-	  get details of a specific application * POST
-	  /applications/{applicationName}/subscription - explicitly
-	  subscribe to a channel, bridge or endpoint * DELETE
-	  /applications/{applicationName}/subscription - explicitly
-	  unsubscribe from a channel, bridge or endpoint Subscriptions work
-	  by a reference counting mechanism: if you subscript to an event
-	  source X number of times, you must unsubscribe X number of times
-	  to stop receiveing events for that event source. Review:
-	  https://reviewboard.asterisk.org/r/2862 (issue ASTERISK-22451)
-	  Reported by: Matt Jordan ........ Merged revisions 400522 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-04 15:49 +0000 [r400511-400521]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip.c: Enclose the To URI and update its user
-	  portion if a request user has been specified. ........ Merged
-	  revisions 400520 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_session.c, /: Replace the connection address at the
-	  SDP level if altering the SDP with the external media address.
-	  ........ Merged revisions 400510 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 23:20 +0000 [r400482]  Jonathan Rose <jrose at digium.com>
+	  revisions 347293 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-06 22:01 +0000 [r347241]  Jonathan Rose <jrose at digium.com>
+
+	* main/pbx.c, /: Documents CHANNEL(musicclass) taking priority over
+	  m([x]) in waitExten If waitExten specifies a music class to use
+	  with its music on hold option, it will use CHANNEL(musicclass)
+	  instead if that channel variable has been set on the initiating
+	  channel. This documents that behavior in the waitExten app so
+	  that this can be known without checking the documentation of the
+	  code in function local_ast_moh_start. (closes issue
+	  ASTERISK-18804) ........ Merged revisions 347239 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347240 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-06 20:23 +0000 [r347157-347192]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* UPGRADE.txt, CHANGES, apps/app_voicemail.c: Add VM_INFO()
+	  dialplan function to gather information about a mailbox.
+	  Deprecates MAILBOX_EXISTS. Provides count, email, exists,
+	  fullname, language, locale, pager, password, tz. (closes issue
+	  ASTERISK-18634) Patch by: Kris Shaw Review:
+	  https://reviewboard.asterisk.org/r/1568 Reviewed by: Walter
+	  Doekes
+
+	* /, channels/chan_sip.c: Don't allow transport=tcp when
+	  tcpenable=no. When tcpenable=no, sending to transport=tcp hosts
+	  was still allowed. Resolving the source address wasn't possible
+	  and yielded the string "(null)" in SIP messages. Fixed that and a
+	  couple of not-so-correct log messages. (closes issue
+	  ASTERISK-18837) Reported by: Andreas Topp Review:
+	  https://reviewboard.asterisk.org/r/1585 Reviewed by: Matt Jordan
+	  ........ Merged revisions 347166 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347167 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, channels/chan_sip.c: chan_sip: Don't ignore expires value in
-	  contact header if it lacks semicolon (closes issue
-	  ASTERISK-22574) Reported by: Filip Jenicek Patches:
-	  chan_sip_expires.patch uploaded by Filip Jenicek (license 6277)
-	  ........ Merged revisions 400469 from
+	* /, apps/app_voicemail.c: Add regression tests for issue
+	  ASTERISK-18838. Review: https://reviewboard.asterisk.org/r/1572
+	  Reviewed by: Matt Jordan ........ Merged revisions 347131 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400470 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400471 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 21:46 +0000 [r400461]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/channel_internal_api.c: Remove publication of a channel
-	  snapshot when the technology is set This patch removes said
-	  publication for a few reasons: (1) It is unnecessary. Association
-	  of the channel technology with a specific channel is an
-	  implementation detail that should be assumed to "just happen",
-	  and consumers of Stasis don't need to be informed about it. (2)
-	  Publication of said message can now cause crashes, as the actual
-	  creation of a channel in normal locations now stages its
-	  messages. As a result, things that create dummy channels (such as
-	  the SIP RTP QOS unit test) and associate them with a channel
-	  technology were now crashing, as the channel itself was not known
-	  by Stasis. ........ Merged revisions 400460 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 20:22 +0000 [r400452]  Mark Michelson <mmichelson at digium.com>
-
-	* bridges/bridge_native_rtp.c, /,
-	  include/asterisk/bridge_technology.h: Fix assumption in
-	  bridge_native_rtp.c regarding number of participants in a bridge.
-	  When a party leaves a bridge, there may be more participants in
-	  the bridge than expected. As such, it is important not to make
-	  assumptions regarding the list of channels in a bridge. This
-	  change makes it so that when a party leaves a native RTP bridge,
-	  we unbridge it and the party it was bridged with. Previously, the
-	  first and last channels in the list were unbridged since it was
-	  assumed that these were the two channels that had been bridged.
-	  As previously stated, a new party had been inserted into the
-	  bridge, so this logic did not work properly. (closes issue
-	  ASTERISK-22615) reported by Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2899 ........ Merged revisions
-	  400403 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 19:32 +0000 [r400443]  Joshua Colp <jcolp at digium.com>
-
-	* /, main/cdr.c: When serializing CDR variables (like for "core
-	  show channels") don't output an error if CDRs aren't enabled.
-	  ........ Merged revisions 400442 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 19:30 +0000 [r400441]  Kinsey Moore <kmoore at digium.com>
-
-	* /, main/security_events.c: Fix security events for AMI invalid
-	  password In r337595, additional security events were added for
-	  chan_sip authentication failures. The new IEs added to the
-	  existing invalid password event were defined as required IEs, but
-	  existing users of the event did not set the new IEs and could not
-	  since they didn't apply to existing uses. They are now marked as
-	  optional IEs. (closes issue ASTERISK-22578) Reported by: Matt
-	  Jordan ........ Merged revisions 400421 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400440 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 347146 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_voicemail.c: The voicemail [general] zonetag and
+	  locale variables weren't loaded until after the mailboxes were
+	  initialized. This caused the settings to be unset for those
+	  mailboxes until a reload was performed. (closes issue
+	  ASTERISK-18838) Review: https://reviewboard.asterisk.org/r/1570
+	  Reviewed by: Matt Jordan ........ Merged revisions 347111 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347124 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-06 19:09 +0000 [r347110]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/dlinkedlists.h, tests/test_linkedlists.c: Doubly
+	  linked lists unit test and update to implementation. Update the
+	  doubly linked list implementation. Now safe traversing can insert
+	  before and after the current node when traversing in either
+	  direction. Updated the linked lists unit test test_linkedlist to
+	  also test doubly linked lists. The old test_dlinkedlist requires
+	  a manual check of results and probably should be removed. Review:
+	  https://reviewboard.asterisk.org/r/1569/
+
+2011-12-06 17:34 +0000 [r347069]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Fixed crash from orphaned MWI
+	  subscriptions in chan_sip This patch resolves the issue where MWI
+	  subscriptions are orphaned by subsequent SIP SUBSCRIBE messages.
+	  When a peer is removed, either by pruning realtime SIP peers or
+	  by unloading / loading chan_sip, the MWI subscriptions that were
+	  orphaned would still be on the event engine list of valid
+	  subscriptions but have a pointer to a peer that no longer was
+	  valid. When an MWI event would occur, this would cause a seg
+	  fault. (closes issue ASTERISK-18663) Reported by: Ross Beer
+	  Tested by: Ross Beer, Matt Jordan Patches:
+	  blf_mwi_diff_12_06_11.txt uploaded by Matt Jordan (license 6283)
+	  Review: https://reviewboard.asterisk.org/r/1610/ ........ Merged
+	  revisions 347058 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347068 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-05 17:44 +0000 [r347008]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_analog.c, /,
+	  channels/sig_analog.h: Restore call progress code for analog
+	  ports. Extracting sig_analog from chan_dahdi lost call progress
+	  detection functionality. * Fix analog ports from considering a
+	  call answered immediately after dialing has completed if the
+	  callprogress option is enabled. (closes issue ASTERISK-18841)
+	  Reported by: Richard Miller Patches: chan_dahdi.diff (license
+	  #5685) patch uploaded by Richard Miller (Modified by me)
+	  sig_analog.c.diff (license #5685) patch uploaded by Richard
+	  Miller (Modified by me) sig_analog.h.diff (license #5685) patch
+	  uploaded by Richard Miller ........ Merged revisions 347006 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 347007 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-05 15:04 +0000 [r346956]  Jonathan Rose <jrose at digium.com>
+
+	* main/pbx.c, /: Resolve duplicate label used in multiple
+	  priorities for the same extension. Prior to this patch, if labels
+	  with the same name were used for different priorities in the same
+	  extension, the new label would be accepted, but it would be
+	  unusable since attempts to reach that label would just go to the
+	  first one. Now pbx.c detects this, generates a warning in logs,
+	  and culls the label before adding it to the dialplan. (closes
+	  issue ASTERISK-18807) Reported by: Kenneth Shumard Patches:
+	  pbx.c.patch uploaded by Kenneth Shumard (License 5077) ........
+	  Merged revisions 346954 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346955 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-03 19:06 +0000 [r400402]  Joshua Colp <jcolp at digium.com>
+2011-12-05 14:47 +0000 [r346953]  Kinsey Moore <kmoore at digium.com>
 
-	* res/ari/resource_channels.c, /: Fix a crash caused by muting and
-	  unmuting a channel in ARI without specifying a direction. (closes
-	  issue ASTERISK-22637) Reported by: Scott Griepentrog Patch by
-	  Matt Jordan, whose office I have taken over in the name of
-	  Canada. ........ Merged revisions 400401 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* res/res_jabber.exports.in, /: Fix chan_jingle/gtalk load
+	  regression introduced in r346087 Add missing symbol exports for
+	  ast_aji_client_destroy and ast_aji_buddy_destroy for usage
+	  outside res_jabber. Testing of these changes focused on
+	  res_jabber itself, so this problem was missed. Reported-by:
+	  Michael Spiceland ........ Merged revisions 346951 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346952 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-04 10:08 +0000 [r346901]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: For SIP REGISTER fix domain-only URIs and
+	  domain ACL bypass. The code that allowed admins to create users
+	  with domain-only uri's had stopped to work in 1.8 because of the
+	  reqresp parser rewrites. This is fixed now: if you have a
+	  [mydomain.com] sip user, you can register with useraddr
+	  sip:mydomain.com. Note that in that case -- if you're using
+	  domain ACLs (a configured domain list) -- mydomain.com must be in
+	  the allow list as well. Reviewboard r1606 shows a list of
+	  registration combinations and which SIP response codes are
+	  returned. Review: https://reviewboard.asterisk.org/r/1533/
+	  Reviewed by: Terry Wilson (closes issue ASTERISK-18389) (closes
+	  issue ASTERISK-18741) ........ Merged revisions 346899 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346900 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-02 23:30 +0000 [r346857]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Update SIP MESSAGE To parsing to
+	  correctly handle URI The previous patch (r346040) incorrectly
+	  parsed the URI in the presence of a port, e.g.,
+	  user at hostname:port would fail as the port would be double
+	  appended to the SIP message. This patch uses the parse_uri
+	  function to correctly parse the URI into its username and
+	  hostname parts, and places them in the correct fields in the
+	  sip_pvt structure. (issue ASTERISK-18903) Review:
+	  https://reviewboard.asterisk.org/r/1597/ ........ Merged
+	  revisions 346856 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-12-02 19:40 +0000 [r346777-346816]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c: implement nat option for rtp channels with
+	  ooh323
+
+	* addons/chan_ooh323.c, /, channels/chan_h323.c: Merged revisions
+	  346763 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r346763 | may | 2011-12-02 20:42:32 +0400 (Fri,
+	  02 Dec 2011) | 14 lines Merged revisions 346762 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r346762 | may | 2011-12-02 20:19:19 +0400 (Fri, 02 Dec 2011) | 7
+	  lines process null frame pointer returned by
+	  ast_rtp_instance_read correctly (closes issue ASTERISK-16697)
+	  Reported by: under Patches: segfault.diff (License #5871) patch
+	  uploaded by under ........ ................
+
+2011-12-01 21:19 +0000 [r346709]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/stun.c, /, res/res_stun_monitor.c,
+	  configs/res_stun_monitor.conf.sample, include/asterisk/stun.h:
+	  Re-resolve the STUN address if a STUN poll fails for
+	  res_stun_monitor. The STUN socket must remain open between polls
+	  or the external address seen by the STUN server is likely to
+	  change. However, if the STUN request poll fails then the STUN
+	  server address needs to be re-resolved and the STUN socket needs
+	  to be closed and reopened. * Re-resolve the STUN server address
+	  and create a new socket if the STUN request poll fails. * Fix
+	  ast_stun_request() return value consistency. * Fix
+	  ast_stun_request() to check the received packet for expected
+	  message type and transaction ID. * Fix ast_stun_request() to read
+	  packets until timeout or an associated response packet is found.
+	  The stun_purge_socket() hack is no longer required. * Reduce
+	  ast_stun_request() error messages to debug output. * No longer
+	  pass in the destination address to ast_stun_request() if the
+	  socket is already bound or connected to the destination. (closes
+	  issue ASTERISK-18327) Reported by: Wolfram Joost Tested by:
+	  rmudgett Review: https://reviewboard.asterisk.org/r/1595/
+	  ........ Merged revisions 346700 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346701 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-03 18:51 +0000 [r400399]  Richard Mudgett <rmudgett at digium.com>
+2011-12-01 20:46 +0000 [r346699]  Jonathan Rose <jrose at digium.com>
 
-	* /, main/cel.c: cel: Some whitespace cleanups ........ Merged
-	  revisions 400398 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/chan_sip.c: Change 183 Ringing in sipfrag body to 180
+	  ringing. 183 Ringing isn't even a thing. 183 is actually a
+	  session progress message. (closes issue ASTERISK-18925) Reported
+	  by: Sebastian Denz Tested by: jrose Patches:
+	  asterisk18-use_180_instead_of_183_in_sipfrag.diff by Sebastian
+	  Denz (License #6139) ........ Merged revisions 346697 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346698 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-30 23:38 +0000 [r346617-346655]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* channels/chan_unistim.c, main/tcptls.c, channels/chan_sip.c,
+	  main/config.c, main/loader.c: Remove the few places where we try
+	  to ast_verbose() without a newline.
+
+	* main/asterisk.c: Fix edge case for overflow buffer.
+
+2011-11-30 22:03 +0000 [r346525-346566]  Jonathan Rose <jrose at digium.com>
+
+	* main/tcptls.c, /, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  r346525 | jrose | 2011-11-30 15:10:38 -0600 (Wed, 30 Nov 2011) |
+	  18 lines Cleaning up chan_sip/tcptls file descriptor closing.
+	  This patch attempts to eliminate various possible instances of
+	  undefined behavior caused by invoking close/fclose in situations
+	  where fclose may have already been issued on a
+	  tcptls_session_instance and/or closing file descriptors that
+	  don't have a valid index for fd (-1). Thanks for more than a
+	  little help from wdoekes. (closes issue ASTERISK-18700) Reported
+	  by: Erik Wallin (issue ASTERISK-18345) Reported by: Stephane
+	  Cazelas (issue ASTERISK-18342) Reported by: Stephane Chazelas
+	  Review: https://reviewboard.asterisk.org/r/1576/ ........ Merged
+	  revisions 346564 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346565 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/tcptls.c, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  Reverting 346525 due to accidental patch against trunk instead of
+	  1.8
+
+	* main/tcptls.c, channels/chan_sip.c, include/asterisk/tcptls.h:
+	  Cleaning up chan_sip/tcptls file descriptor closing. This patch
+	  attempts to eliminate various possible instances of undefined
+	  behavior caused by invoking close/fclose in situations where
+	  fclose may have already been issued on a tcptls_session_instance
+	  and/or closing file descriptors that don't have a valid index for
+	  fd (-1). Thanks for more than a little help from wdoekes. (closes
+	  issue ASTERISK-18700) Reported by: Erik Wallin (issue
+	  ASTERISK-18345) Reported by: Stephane Cazelas (issue
+	  ASTERISK-18342) Reported by: Stephane Chazelas Review:
+	  https://reviewboard.asterisk.org/r/1576/
+
+2011-11-30 19:37 +0000 [r346474]  Leif Madsen <leif at leifmadsen.com>
+
+	* configs/queues.conf.sample: Update queues.conf.sample
+	  documentation. Update the documentation surrounding the use of
+	  MONITOR_EXEC to make it more clear that it can be used for both
+	  Monitor() and MixMonitor() usage. (closes issue ASTERISK-17413)
+	  Reported by: David Woolley Patches:
+	  issue18817_mixmonitor_queues_doc.diff by Michael L. Young
+	  (License #5026) ........ Merged revisions 346472 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346473 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-29 20:32 +0000 [r346391-346429]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* utils/refcounter.c, utils/hashtest.c, utils/ael_main.c,
+	  utils/hashtest2.c: Fix compilation of utilities (caught by
+	  Bamboo).
+
+	* addons/chan_ooh323.c, channels/chan_sip.c, main/say.c,
+	  res/res_fax.c, UPGRADE.txt, res/res_musiconhold.c,
+	  res/res_jabber.c, CHANGES, configs/logger.conf.sample,
+	  main/cli.c, channels/chan_usbradio.c, include/asterisk/logger.h,
+	  main/dial.c, channels/chan_skinny.c, main/logger.c,
+	  codecs/codec_dahdi.c, apps/app_rpt.c, apps/app_verbose.c,
+	  main/asterisk.c, main/bridging.c, res/res_clialiases.c,
+	  addons/res_config_mysql.c, apps/app_voicemail.c: Allow each
+	  logging destination and console to have its own notion of the
+	  verbosity level. Review: https://reviewboard.asterisk.org/r/1599
+
+2011-11-29 00:03 +0000 [r346350]  David Vossel <dvossel at digium.com>
+
+	* /, include/asterisk/message.h, main/message.c: Merged revisions
+	  346349 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r346349 | dvossel | 2011-11-28 18:00:11 -0600 (Mon, 28 Nov 2011)
+	  | 10 lines Fixes memory leak in message API. The ast_msg_get_var
+	  function did not properly decrement the ref count of the var it
+	  retrieves. The way this is implemented is a bit tricky, as we
+	  must decrement the var and then return the var's value. As long
+	  as the documentation for the function is followed, this will not
+	  result in a dangling pointer as the ast_msg structure owns its
+	  own reference to the var while it exists in the var container.
+	  ........
+
+2011-11-28 14:34 +0000 [r346294]  Stefan Schmidt <sst at sil.at>
+
+	* res/res_rtp_asterisk.c, /: Fix regression that 'rtp/rtcp set
+	  debup ip' only works when also a port was specified. (closes
+	  issue ASTERISK-18693) Reported by: Davide Dal Fra Review:
+	  https://reviewboard.asterisk.org/r/1600/ Reviewed by: Walter
+	  Doekes ........ Merged revisions 346292 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346293 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-10-03 18:32 +0000 [r400385-400397]  Kinsey Moore <kmoore at digium.com>
+2011-11-23 23:03 +0000 [r346241]  Richard Mudgett <rmudgett at digium.com>
 
-	* res/res_rtp_multicast.c, /: res_rtp_multicast: Ensure SSRC is set
-	  properly This fixes a bug where the SSRC field on multicast RTP
-	  can be stuck at 0 which can cause problems for endpoints trying
-	  to make sense of incoming streams. (closes issue ASTERISK-22567)
-	  Reported by: Simone Camporeale Patches:
-	  22567_res_mulitcast_ssrc.patch uploaded by Simone Camporeale
-	  (License 6536) ........ Merged revisions 400393 from
+	* include/asterisk/acl.h, /, channels/chan_skinny.c,
+	  channels/chan_h323.c, main/acl.c, channels/chan_iax2.c: Fix calls
+	  to ast_get_ip() not initializing the address family. ........
+	  Merged revisions 346239 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346240 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-23 20:48 +0000 [r346146-346199]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Minor cleanup in chan_sip get_msg_text()
+	  function. In r116240, get_msg_text() got an extra parameter to
+	  fix the unwanted addition of trailing newlines to SIP MESSAGE
+	  bodies. This caused all linefeeds to be trimmed, which isn't
+	  right either. This is a stop-gap; the right fix is to return the
+	  original SIP request body. Review:
+	  https://reviewboard.asterisk.org/r/1586 Reviewed by: Matt Jordan
+	  ........ Merged revisions 346147 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 346198 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, include/asterisk/strings.h: Fix ast_str_truncate signedness
+	  warning and documentation. Review:
+	  https://reviewboard.asterisk.org/r/1594 ........ Merged revisions
+	  346144 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 346145 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-23 17:16 +0000 [r346088]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_jingle.c, /, include/asterisk/jabber.h,
+	  channels/chan_gtalk.c, res/res_jabber.c: Fix res_jabber resource
+	  leaks This should fix almost all resource leaks in res_jabber
+	  that involve ASTOBJ_CONTAINER_FIND and resolves an ambiguous
+	  situation where ast_aji_get_client would sometimes bump an
+	  object's refcount and sometimes not. Review:
+	  https://reviewboard.asterisk.org/r/1553 ........ Merged revisions
+	  346086 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 346087 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-23 16:23 +0000 [r346053]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Fixed SendMessage stripping extension
+	  from To: header in SIP MESSAGE When using the MessageSend
+	  application to send a SIP MESSAGE to a non-peer, chan_sip
+	  attempted to validate the hostname or IP Address. In the process,
+	  it stripped off the extension and failed to add it back to the
+	  sip_pvt structure before transmitting. This patch adds the full
+	  URI passed in from the message core to the sip_pvt structure.
+	  (closes issue ASTERISK-18903) Reported by: Shaun Clark Tested by:
+	  Matt Jordan Review: https://reviewboard.asterisk.org/r/1597/
+	  ........ Merged revisions 346040 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-23 16:12 +0000 [r346033]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_musiconhold.c: Resume playing existing hold music for
+	  cached realtime MOH As a result of the fix for ASTERISK-18039,
+	  realtime caching MOH no longer properly resumes playing back a
+	  file between different holds in the same call. This is because
+	  scanning for new files causes the existing file array to be
+	  emptied and we were just comparing that the saved pointer to the
+	  filename matched the pointer to the filename in a particular
+	  position in the array. An easy fix is to save the filename
+	  instead of a pointer to it and then do a strcmp instead of
+	  comparing the addresses. (closes issue ASTERISK-18912) Review:
+	  https://reviewboard.asterisk.org/r/1596/ ........ Merged
+	  revisions 346030 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400394 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400395 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 346031 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, configure, include/asterisk/autoconfig.h.in, configure.ac,
-	  main/xml.c: Detect and use xsltCleanupGlobals when available This
-	  introduces usage of an additional libxslt cleanup function,
-	  xsltCleanupGlobals, when the configure script detects that it is
-	  available. Early versions of the library did not include this
-	  function. (closes issue ASTERISK-22570) Reported by: Corey
-	  Farrell Patches: xsltCleanupGlobals.patch uploaded by Corey
-	  Farrell (License 5909) ........ Merged revisions 400384 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-11-23 16:10 +0000 [r346032]  Paul Belanger <paul.belanger at polybeacon.com>
 
-2013-10-03 16:28 +0000 [r400374]  Richard Mudgett <rmudgett at digium.com>
+	* /, res/res_format_attr_silk.c, res/res_format_attr_celt.c: Added
+	  support level for new modules ........ Merged revisions 346029
+	  from http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_vpb.cc, /: chan_vpb: Make compile again. ........
-	  Merged revisions 400373 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-11-22 23:06 +0000 [r345978]  Richard Mudgett <rmudgett at digium.com>
 
-2013-10-03 14:59 +0000 [r400363-400364]  Mark Michelson <mmichelson at digium.com>
+	* main/dnsmgr.c, /, include/asterisk/dnsmgr.h: Fix dnsmgr entries
+	  to ask for the same address family each time. The dnsmgr refresh
+	  would always get the first address found regardless of the
+	  original address family requested. So if you asked for only IPv4
+	  addresses originally, you might get an IPv6 address on refresh. *
+	  Saved the original address family requested by
+	  ast_dnsmgr_lookup() to be used when the address is refreshed.
+	  ........ Merged revisions 345976 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345977 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* tests/test_cel.c, /: Get rid of uses of stasis_topic_wait()
-	  ........ Merged revisions 400362 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-11-22 20:32 +0000 [r345925]  Walter Doekes <walter+asterisk at wjd.nu>
 
-	* pbx/pbx_spool.c, main/manager.c, main/format_cap.c,
-	  channels/chan_skinny.c, res/res_agi.c, channels/chan_motif.c,
-	  channels/chan_alsa.c, apps/app_confbridge.c,
-	  addons/chan_mobile.c, channels/chan_mgcp.c,
-	  res/res_clioriginate.c, channels/chan_bridge_media.c,
-	  channels/chan_sip.c, tests/test_format_api.c,
-	  res/res_pjsip_sdp_rtp.c, bridges/bridge_simple.c,
-	  apps/app_originate.c, res/parking/parking_applications.c,
-	  main/core_local.c, channels/chan_console.c, channels/chan_oss.c,
-	  include/asterisk/format_cap.h, res/res_pjsip_session.c,
-	  res/ari/resource_bridges.c, channels/chan_jingle.c,
-	  channels/chan_misdn.c, channels/dahdi/bridge_native_dahdi.c,
-	  res/res_pjsip/pjsip_configuration.c, main/file.c,
-	  channels/chan_h323.c, channels/chan_nbs.c,
-	  bridges/bridge_native_rtp.c, tests/test_config.c,
-	  res/res_stasis.c, channels/chan_pjsip.c, channels/chan_unistim.c,
-	  channels/chan_multicast_rtp.c, addons/chan_ooh323.c,
-	  main/rtp_engine.c, /, main/ccss.c, apps/app_meetme.c,
-	  bridges/bridge_holding.c, main/bridge_basic.c,
-	  bridges/bridge_softmix.c, channels/chan_gtalk.c,
-	  channels/chan_iax2.c, main/media_index.c, main/channel.c,
-	  channels/chan_phone.c, channels/chan_dahdi.c, main/dial.c: Cache
-	  string values of formats on ast_format_cap() to save processing.
-	  Channel snapshots have string representations of the channel's
-	  native formats. Prior to this change, the format strings were
-	  re-created on ever channel snapshot creation. Since channel
-	  native formats rarely change, this was very wasteful. Now, string
-	  representations of formats may optionally be stored on the
-	  ast_format_cap for cases where string representations may be
-	  requested frequently. When formats are altered, the string cache
-	  is marked as invalid. When strings are requested, the cache
-	  validity is checked. If the cache is valid, then the cached
-	  strings are copied. If the cache is invalid, then the string
-	  cache is rebuilt and copied, and the cache is marked as being
-	  valid again. Review: https://reviewboard.asterisk.org/r/2879
-	  ........ Merged revisions 400356 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-03 14:52 +0000 [r400361]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, res/res_pjsip_t38.c, /: Fix crashes in
-	  res_pjsip_sdp_rtp and res_pjsip_t38 when a stream is rejected and
-	  external_media_address is set. The callback function for changing
-	  the media address in streams wrongly assumes that a connection
-	  line will always be present. This is false as no line is present
-	  if a stream has been rejected. (closes issue ASTERISK-22645)
-	  Reported by: Rusty Newton ........ Merged revisions 400360 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 22:22 +0000 [r400335]  Mark Michelson <mmichelson at digium.com>
-
-	* main/stasis_wait.c (removed), res/ari/resource_endpoints.c, /,
-	  include/asterisk/stasis.h, tests/test_cel.c,
-	  include/asterisk/stasis_endpoints.h, channels/chan_pjsip.c,
-	  main/stasis.c, main/stasis_endpoints.c: Multiple revisions
-	  400318-400319 ........ r400318 | mmichelson | 2013-10-02 17:08:49
-	  -0500 (Wed, 02 Oct 2013) | 12 lines Remove unnecessary waits from
-	  stasis. Since caches are updated on publisher threads, there is
-	  no need to wait for the cache updates to occur after a stasis
-	  message is published. In the case of chan_pjsip device state
-	  changes, this set of changes caused an improvement to
-	  performance. Review: https://reviewboard.asterisk.org/r/2890
-	  ........ r400319 | mmichelson | 2013-10-02 17:10:54 -0500 (Wed,
-	  02 Oct 2013) | 3 lines Remove svn:mergeinfo property. ........
-	  Merged revisions 400318-400319 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 21:33 +0000 [r400317]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* channels/chan_iax2.c, /: Cast Integer Argument To Unsigned Char
-	  The member reg in the peercnt structure is an unsigned char and
-	  peercnt_modify() is expecting an unsigned char argument which
-	  gets assigned to peercnt->reg. This patch fixes that by casting
-	  the integer argument being passed to peercnt_modify to unsigned
-	  char. ........ Merged revisions 400314 from
+	* include/asterisk/logger.h, /: Clarify why the AST_LOG_* macros
+	  exist next to the LOG_* macros. (issue ASTERISK-17973) ........
+	  Merged revisions 345923 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400315 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400316 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 21:26 +0000 [r400313]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, main/manager.c, /, main/cel.c: Only create Stasis
-	  subscriptions when enabled Subscribing to Stasis isn't free. As
-	  such, this patch makes AMI, CDR, and CEL - the "big 3" - only
-	  subscribe when enabled. Toggling their availability via a .conf
-	  file will unsubscribe/subscribe as appropriate. Review:
-	  https://reviewboard.asterisk.org/r/2888/ ........ Merged
-	  revisions 400312 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 20:31 +0000 [r400304]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/pbx.c, /: Originate: Make setting caller id on outgoing call
-	  use either name or number. Previous code was requiring both name
-	  and number to be available. Also restored a comment block on why
-	  caller id is also set on an outgoing call leg in addition to
-	  connected line from earlier versions of Asterisk. ........ Merged
-	  revisions 400303 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 19:20 +0000 [r400295]  Kinsey Moore <kmoore at digium.com>
-
-	* /, rest-api/api-docs/asterisk.json: Correct allowable values for
-	  ARI general information filter ........ Merged revisions 400291
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 19:17 +0000 [r400287]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: Fix the CDR CLI command 'cdr show active
-	  {channel}' When the switch from channel names to channel unique
-	  IDs happened, the poor CLI command got left in the dust. This
-	  fixes the command so that users can once again see how Asterisk
-	  is messing up your billing information. ........ Merged revisions
-	  400286 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 18:44 +0000 [r400285]  Joshua Colp <jcolp at digium.com>
-
-	* /, res/res_pjsip_t38.c: Fix a crash in res_pjsip_t38 caused by
-	  the wrong assumption that a session will always have a channel.
-	  When starting up or shutting down this assumption is false.
-	  ........ Merged revisions 400284 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 18:28 +0000 [r400282]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-
-	* Makefile, doc/astdb2sqlite3.8 (added), /, doc/astdb2bdb.8
-	  (added): man pages for astdb2bdb and astdb2sqlite3 Review:
-	  https://reviewboard.asterisk.org/r/2898/ ........ Merged
-	  revisions 400279 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400281 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 17:12 +0000 [r400269-400271]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_stack.c, res/stasis_recording/stored.c, main/json.c,
-	  main/stasis_cache.c, res/res_ari.c, /, main/utils.c:
-	  MALLOC_DEBUG: Fix some misuses of free() when MALLOC_DEBUG is
-	  enabled. * There were several places in ARI where an external
-	  library was mallocing memory that must always be released with
-	  free(). When MALLOC_DEBUG is enabled, free() is redirected to the
-	  MALLOC_DEBUG version. Since the external library call still uses
-	  the normal malloc(), MALLOC_DEBUG complains that the freed memory
-	  block is not registered and will not free it. These cases must
-	  use ast_std_free(). * Changed calls to asprintf() and vasprintf()
-	  to the equivalent ast_asprintf() and ast_vasprintf() versions
-	  respectively. ........ Merged revisions 400270 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/sig_ss7.c, /: sig_ss7: Fix compiler warnings. ........
-	  Merged revisions 400268 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-02 16:23 +0000 [r400246-400266]  Joshua Colp <jcolp at digium.com>
-
-	* channels/chan_alsa.c, main/stasis_channels.c, channels/sig_ss7.c,
-	  channels/chan_pjsip.c, channels/chan_mgcp.c,
-	  channels/chan_unistim.c, apps/app_dial.c, main/pbx.c, /,
-	  channels/chan_sip.c, main/bridge.c, include/asterisk/channel.h,
-	  channels/chan_gtalk.c, channels/chan_console.c,
-	  channels/sig_pri.c, channels/chan_iax2.c, channels/chan_jingle.c,
-	  main/channel.c, channels/chan_dahdi.c, main/dial.c,
-	  include/asterisk/stasis_channels.h, channels/chan_skinny.c,
-	  channels/chan_motif.c: Reduce channel snapshot creation and
-	  publishing by up to 50%. This change introduces the ability to
-	  stage channel snapshot creation and publishing by suppressing the
-	  implicit creation and publishing that some functions have. Once
-	  all operations are executed the staging is marked as done and a
-	  single snapshot is created and published. Review:
-	  https://reviewboard.asterisk.org/r/2889/ ........ Merged
-	  revisions 400265 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_session.c, /: Fix a random one way audio issue in
-	  PJSIP. Due to the asynchronous design of the PJMEDIA SDP
-	  negotiator it was possible for the SDP to be negotiated *after* a
-	  channel was created and after it was being wait on by an
-	  application. It is only after negotiation occurs that the file
-	  descriptors for RTP are placed on the channel. Since the channel
-	  was already being waited on these file descriptors were not
-	  monitored, causing incoming media to never be read. This change
-	  wakes up any application waiting on the channel so that added
-	  file descriptors end up being monitored. (closes issue AST-1227)
-	  Reported by: John Bigelow ........ Merged revisions 400256 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/stasis/control.c, include/asterisk/stasis_app.h,
-	  res/ari/resource_channels.c: Allow specifying a channel to dial
-	  an extension and context in an ARI dial operation. (issue
-	  ASTERISK-22625) Reported by: Scott Griepentrog ........ Merged
-	  revisions 400254 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip_session.c: Retrieve and store the hostname only
-	  once so multiple threads do not potentially initialize it at the
-	  same time. ........ Merged revisions 400245 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-01 21:19 +0000 [r400228-400237]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_dahdi.c, channels/sig_analog.c, /: chan_dahdi: Fix
-	  analog parking using flash-hook. Transferring an analog call
-	  using a flash-hook to parking would fail to park the call and
-	  result in an invalid ao2 object unref. * Park the correct bridged
-	  channel. ........ Merged revisions 400236 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/features_config.c, /: Features: Rearm the parking config
-	  options have moved warning for each reload. ........ Merged
-	  revisions 400227 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-10-01 15:54 +0000 [r400218]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: Filter out internal channels for bridge leave
-	  messages and parked call messages Granted, if you manage to park
-	  a Conference announcer channel, something has gone horrifically
-	  wrong. ........ Merged revisions 400217 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-30 21:40 +0000 [r400206]  Jonathan Rose <jrose at digium.com>
-
-	* configs/features.conf.sample, /, configs/res_parking.conf.sample:
-	  configuration samples: Pull all parking related stuff out of
-	  features.conf This patch also adds documentation for parking from
-	  features.conf to res_parking.conf ........ Merged revisions
-	  400205 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-30 19:58 +0000 [r400195-400197]  Matthew Jordan <mjordan at digium.com>
-
-	* /, funcs/func_cdr.c: Parse arguments passed to the CDR_PROP
-	  function correctly I can only blame this on a bad merge, because
-	  this in no way worked properly the way it was written. Mea culpa.
-	  The function should now parse its arguments correctly and
-	  function properly. (Note that the API used by the CDR_PROP
-	  function has working unit tests... this was merely bad coding of
-	  the actual registered function) (closes issue ASTERISK-22613)
-	  Reported by: Private Name ........ Merged revisions 400196 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: Remove spurious event raised when CDRs are
-	  reloaded The Reload event is now raised by the module loading
-	  core. As such, the Reload event in the CDR engine was a duplicate
-	  and not needed. ........ Merged revisions 400194 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-30 18:55 +0000 [r400186]  David M. Lee <dlee at digium.com>
-
-	* tests/test_devicestate.c, include/asterisk/sem.h (added),
-	  tests/test_taskprocessor.c, res/res_pjsip_mwi.c,
-	  res/res_pjsip/include/res_pjsip_private.h, tests/test_stasis.c,
-	  res/parking/parking_manager.c, res/res_security_log.c,
-	  channels/chan_mgcp.c, main/stasis_cache_pattern.c, main/pbx.c,
-	  include/asterisk/vector.h (added), /, main/ccss.c,
-	  apps/app_meetme.c, include/asterisk/taskprocessor.h,
-	  configs/stasis.conf.sample (removed), configure.ac,
-	  res/parking/parking_applications.c, channels/sig_pri.c,
-	  apps/app_queue.c, main/cel.c, main/stasis.c,
-	  channels/chan_dahdi.c, funcs/func_presencestate.c,
-	  main/stasis_message_router.c, configure,
-	  apps/confbridge/confbridge_manager.c, res/res_agi.c,
-	  main/manager_system.c, res/res_stasis_test.c, main/sem.c (added),
-	  main/manager_channels.c, res/res_pjsip_refer.c,
-	  main/manager_mwi.c, apps/app_voicemail.c, main/stasis_cache.c,
-	  main/stasis_wait.c, main/stasis_config.c (removed),
-	  include/asterisk/stasis_internal.h, res/stasis/app.c,
-	  channels/chan_sip.c, include/asterisk/autoconfig.h.in,
-	  main/manager_endpoints.c, main/channel_internal_api.c,
-	  include/asterisk/stasis.h, main/devicestate.c,
-	  main/taskprocessor.c, res/res_xmpp.c, main/sounds_index.c,
-	  include/asterisk/stasis_message_router.h, channels/chan_iax2.c,
-	  res/res_jabber.c, main/endpoints.c, main/astobj2.c,
-	  res/res_chan_stats.c, res/parking/parking_bridge_features.c,
-	  tests/test_stasis_endpoints.c, main/cdr.c, main/channel.c,
-	  main/manager_bridges.c, main/manager.c, channels/chan_skinny.c:
-	  Multiple revisions 399887,400138,400178,400180-400181 ........
-	  r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1
-	  line Minor performance bump by not allocate manager variable
-	  struct if we don't need it ........ r400138 | dlee | 2013-09-30
-	  10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines Stasis performance
-	  improvements This patch addresses several performance problems
-	  that were found in the initial performance testing of Asterisk
-	  12. The Stasis dispatch object was allocated as an AO2 object,
-	  even though it has a very confined lifecycle. This was replaced
-	  with a straight ast_malloc(). The Stasis message router was
-	  spending an inordinate amount of time searching hash tables. In
-	  this case, most of our routers had 6 or fewer routes in them to
-	  begin with. This was replaced with an array that's searched
-	  linearly for the route. We more heavily rely on AO2 objects in
-	  Asterisk 12, and the memset() in ao2_ref() actually became
-	  noticeable on the profile. This was #ifdef'ed to only run when
-	  AO2_DEBUG was enabled. After being misled by an erroneous comment
-	  in taskprocessor.c during profiling, the wrong comment was
-	  removed. Review: https://reviewboard.asterisk.org/r/2873/
-	  ........ r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep
-	  2013) | 24 lines Taskprocessor optimization; switch Stasis to use
-	  taskprocessors This patch optimizes taskprocessor to use a
-	  semaphore for signaling, which the OS can do a better job at
-	  managing contention and waiting that we can with a mutex and
-	  condition. The taskprocessor execution was also slightly
-	  optimized to reduce the number of locks taken. The only
-	  observable difference in the taskprocessor implementation is that
-	  when the final reference to the taskprocessor goes away, it will
-	  execute all tasks to completion instead of discarding the
-	  unexecuted tasks. For systems where unnamed semaphores are not
-	  supported, a really simple semaphore implementation is provided.
-	  (Which gives identical performance as the original taskprocessor
-	  implementation). The way we ended up implementing Stasis caused
-	  the threadpool to be a burden instead of a boost to performance.
-	  This was switched to just use taskprocessors directly for
-	  subscriptions. Review: https://reviewboard.asterisk.org/r/2881/
-	  ........ r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep
-	  2013) | 28 lines Optimize how Stasis forwards are dispatched This
-	  patch optimizes how forwards are dispatched in Stasis.
-	  Originally, forwards were dispatched as subscriptions that are
-	  invoked on the publishing thread. This did not account for the
-	  vast number of forwards we would end up having in the system, and
-	  the amount of work it would take to walk though the forward
-	  subscriptions. This patch modifies Stasis so that rather than
-	  walking the tree of forwards on every dispatch, when forwards and
-	  subscriptions are changed, the subscriber list for every topic in
-	  the tree is changed. This has a couple of benefits. First, this
-	  reduces the workload of dispatching messages. It also reduces
-	  contention when dispatching to different topics that happen to
-	  forward to the same aggregation topic (as happens with all of the
-	  channel, bridge and endpoint topics). Since forwards are no
-	  longer subscriptions, the bulk of this patch is simply changing
-	  stasis_subscription objects to stasis_forward objects (which,
-	  admittedly, I should have done in the first place.) Since this
-	  required me to yet again put in a growing array, I finally
-	  abstracted that out into a set of ast_vector macros in
-	  asterisk/vector.h. Review:
-	  https://reviewboard.asterisk.org/r/2883/ ........ r400181 | dlee
-	  | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines Remove
-	  dispatch object allocation from Stasis publishing While looking
-	  for areas for performance improvement, I realized that an unused
-	  feature in Stasis was negatively impacting performance. When a
-	  message is sent to a subscriber, a dispatch object is allocated
-	  for the dispatch, containing the topic the message was published
-	  to, the subscriber the message is being sent to, and the message
-	  itself. The topic is actually unused by any subscriber in
-	  Asterisk today. And the subscriber is associated with the
-	  taskprocessor the message is being dispatched to. First, this
-	  patch removes the unused topic parameter from Stasis subscription
-	  callbacks. Second, this patch introduces the concept of
-	  taskprocessor local data, data that may be set on a taskprocessor
-	  and provided along with the data pointer when a task is pushed
-	  using the ast_taskprocessor_push_local() call. This allows the
-	  task to have both data specific to that taskprocessor, in
-	  addition to data specific to that invocation. With those two
-	  changes, the dispatch object can be removed completely, and the
-	  message is simply refcounted and sent directly to the
-	  taskprocessor. Review: https://reviewboard.asterisk.org/r/2884/
-	  ........ Merged revisions 399887,400138,400178,400180-400181 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-30 15:57 +0000 [r400142]  Kinsey Moore <kmoore at digium.com>
-
-	* /, channels/chan_sip.c, configs/pjsip.conf.sample,
-	  res/res_pjsip_outbound_registration.c, configs/sip.conf.sample,
-	  CHANGES: chan_sip: Allow Asterisk to retry after 403 on register
-	  This adds a global option in chan_sip to allow it to continue
-	  attempting registration if a 403 is received, clearing the cached
-	  nonce and treating it as a non-fatal response. Normally, this
-	  would cause registration attempts to that endpoint to stop. This
-	  also adds a similar per-outbound-registration option to
-	  chan_pjsip which allows the retry interval to be altered for 403
-	  responses to REGISTER requests. (closes issue ASTERISK-17138)
-	  Review: https://reviewboard.asterisk.org/r/2874/ Reported by:
-	  Rudi ........ Merged revisions 400137 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400140 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400141 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-28 22:57 +0000 [r400059-400122]  Matthew Jordan <mjordan at digium.com>
-
-	* /, res/res_pjsip_notify.c, configs/pjsip_notify.conf.sample
-	  (added): res_pjsip_notify: Add documentation We forgot to add
-	  documentation for res_pjsip_notify, which would prevent it from
-	  being loaded. Whoops. This patch also updates res_pjsip_notify to
-	  use pjsip_notify.conf, which now has its own sample file in the
-	  configs directory as well. Review:
-	  https://reviewboard.asterisk.org/r/2835/ ........ Merged
-	  revisions 400121 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 345924 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-22 16:41 +0000 [r345883]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, apps/confbridge/conf_config_parser.c: Add missing
+	  sound_only_one config variable (closes issue ASTERISK-18895)
+	  Reported by: zvision Patches: conf_config_parser.diff (license
+	  #5755) patch uploaded by zvision ........ Merged revisions 345882
+	  from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-21 21:09 +0000 [r345831]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c, configs/sip.conf.sample, CHANGES: Default
+	  to nat=yes; warn when nat in general and peer differ It is
+	  possible to enumerate SIP usernames when the general and
+	  user/peer nat settings differ in whether to respond to the port a
+	  request is sent from or the port listed for responses in the Via
+	  header. In 1.4 and 1.6.2, this would mean if one setting was
+	  nat=yes or nat=route and the other was either nat=no or
+	  nat=never. In 1.8 and 10, this would mean when one was
+	  nat=force_rport and the other was nat=no. In order to address
+	  this problem, it was decided to switch the default behavior to
+	  nat=yes/force_rport as it is the most commonly used option and to
+	  strongly discourage setting nat per-peer/user when at all
+	  possible. For more discussion of the issue, please see:
+	  http://lists.digium.com/pipermail/asterisk-dev/2011-November/052191.html
+	  (closes issue ASTERISK-18862) Review:
+	  https://reviewboard.asterisk.org/r/1591/ ........ Merged
+	  revisions 345776 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.4 ........ Merged
+	  revisions 345800 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.6.2 ........
+	  Merged revisions 345828 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345830 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Correct erroneous
-	  lost packet information in RTCP reports RTCP's calculation of the
-	  number of lost packets in an RTP stream is based on that stream's
-	  sequence number count, the number of received packets, and how
-	  many packets we expect to receive. When the SSRC for an RTP
-	  stream changes, there can - and almost always will be - a large
-	  jump in the next packet's timestamp and sequence number. If we
-	  don't reset the number of received packets, sequence number
-	  count, and other metrics used by RTCP, the next RR/SR report will
-	  use the previous SSRC's values to calculate the lost packet count
-	  for the new SSRC - resulting in a very large number of lost
-	  packets. This patch modifies res_rtp_asterisk such that, if it
-	  detects a SSRC change, it will reset the various values used by
-	  the RTCP calculations. From the perspective of RTCP, this appears
-	  as a new media stream - which is what it is. Review:
-	  https://reviewboard.asterisk.org/r/2886/ (closes issue AST-1174)
-	  Reported by: Thomas Arimont ........ Merged revisions 400089 from
+2011-11-21 16:40 +0000 [r345735]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* CHANGES, main/config.c: Add #tryinclude statement This provides
+	  the same functionality as #include however an asterisk module
+	  will still load if the filename does not exist. Review:
+	  https://reviewboard.asterisk.org/r/1476/
+
+2011-11-19 15:11 +0000 [r345643-345684]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, main/db.c: Update the documentation to better clarify how the
+	  existing commands work. Review:
+	  https://reviewboard.asterisk.org/r/1593/ ........ Merged
+	  revisions 345682 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400093 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400108 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 345683 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, configure, configure.ac: Add check for openSUSE when detecting
-	  bfd library In ASTERISK-17842, some additional library checks
-	  were added to the configure script so that the bfd library could
-	  be found on CentOS and Fedora systems. As it turns out, openSUSE
-	  requires an additional library. This patch adds another check to
-	  the configure script for openSUSE that will add that library.
-	  Review: https://reviewboard.asterisk.org/r/2885/ (closes issue
-	  AST-1169) Reported by: Guenther Kelleter ........ Merged
-	  revisions 400073 from
+	* /, main/db.c: Fix a change in behavior in 'database show' from
+	  1.8. In 1.8 and previous versions, one could use any fullword
+	  portion of the key name, including the full key, to obtain the
+	  record. Until this patch, this did not work for the full key.
+	  Closes issue ASTERISK-18886 Patch: by tilghman Review: by twilson
+	  (http://pastebin.com/7rtu6bpk) on #asterisk-dev ........ Merged
+	  revisions 345640 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-17 19:47 +0000 [r345560-345601]  Matthew Jordan <mjordan at digium.com>
+
+	* contrib/realtime/mysql/sipfriends.sql (removed): Accidentally
+	  readded sipfriends.sql in r345560. This was removed in r342871
+
+	* configs/confbridge.conf.sample,
+	  apps/confbridge/include/confbridge.h, apps/app_confbridge.c,
+	  CHANGES, contrib/realtime/mysql/sipfriends.sql (added),
+	  apps/confbridge/conf_config_parser.c: Add admin toggle mute all
+	  and participant count menu options to app_confbridge This patch
+	  adds two new menu features to app_confbridge, admin_toggle_menu_
+	  participants and participant_count. The admin action will
+	  globally mute / unmute all non-admin participants on a
+	  converence, while the participant count simply exposes the
+	  existing participant count function to the conference bridge
+	  menu. This also adds configuration options to change the sound
+	  played when the conference is globally muted / unmuted, as well
+	  as the necessary config hooks to place these functions in the
+	  DTMF menus. (closes issue ASTERISK-18204) Reported by: Kevin
+	  Reeves Tested by: Matt Jordan Patches:
+	  app_confbridge.c.patch.txt, conf_config_parser.c.patch.txt,
+	  confbridge.h.patch.txt uploaded by Kevin Reeves (license 6281)
+	  Review: https://reviewboard.asterisk.org/r/1518/
+
+2011-11-17 17:31 +0000 [r345559]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Remove dead code since pri_grab() can
+	  never fail. Dead code makes programmers sick. I am sick of
+	  looking at it. ........ Merged revisions 345546 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400075 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400077 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: CDR: Improve handling of parking; resolve
-	  assertion when originating into park This patch covers two
-	  problems: 1) Currently, when a call is transferred into a parking
-	  lot from a bridge (using either the blind transfer or one touch
-	  parking mechanisms), the application fails to be set to "Park" in
-	  the resulting CDR record for the parked channel. This is due to
-	  the ParkedCall message arriving before the BridgeEnter for the
-	  channel entering the parking bridge. The ParkedCall message isn't
-	  handled as the CDR for the channel has already been finalized
-	  (due to the channel having left its two party bridge), and the
-	  BridgeEnter - which creates the new CDR - doesn't have the
-	  parking information. This patch modifies the behavior so that
-	  reception of a ParkedCall message will - if not handled by a CDR
-	  chain - cause a new CDR to be created and put into the Parking
-	  state. 2) It fixes a FRACK that occurred when a channel is
-	  originated into a parking space. The DialedPending state - which
-	  occurs for both Dialed and Originated channels - assumed that it
-	  couldn't handle the parking transitions due to it having a Party
-	  B; however, Originated channels don't have a Party B. As such,
-	  the existing CDR needs to transition into the parking state -
-	  this patch does that. Review:
-	  https://reviewboard.asterisk.org/r/2877/ (closes issue
-	  ASTERISK-22482) Reported by: Richard Mudgett ........ Merged
-	  revisions 400062 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, apps/app_queue.c: app_queue: Make manager events tolerant of
-	  Local channel shenanigans app_queue currently attempts to handle
-	  Local channel optimizations in an effort to provide accurate
-	  information in Stasis messages (and their corresponding AMI
-	  events) as well as the Queue log. Sometimes, however, things
-	  don't go as planned. Consider the following scenario: SIP/foo <->
-	  L;1 <-> L;2 <-> SIP/agent SIP/agent answers, triggering a Local
-	  channel optimization. app_queue will normally do the following: *
-	  Listen for the Local optimization events and update our agent
-	  accordingly to SIP/agent in the queue log and messages * When we
-	  get a hangup, publish the AgentComplete event based on our
-	  information (SIP/foo and SIP/agent) However, as with all things
-	  that depend on sanity from something as capricious as Local
-	  channels, things can go wrong: (1) SIP/agent immediately hangs up
-	  upon answering. This triggers a race condition between
-	  termination messages coming from SIP/agent and the ongoing Local
-	  channel optimization messages. (Note that this can also occur
-	  with SIP/foo) (2) In a race condition, Asterisk can (rarely)
-	  deliver the hangup messages prior to the Local channel
-	  optimization. In that case, the messages *may* arrive to
-	  app_queue in the following order: * Hangup SIP/Agent * Hangup
-	  SIP/foo * Optimize L;1/L;2 * Hangup L;2 * Hangup L;1 When
-	  app_queue receives the hangup of the agent or the caller, it will
-	  attempt to publish the AgentComplete event. However, it now has a
-	  problem - it thinks its agent is the ;1 side of the Local
-	  channel, as it never received the optimization event. At the same
-	  time, that channel is already gone. This results in getting NULL
-	  from the Stasis cache. What's more, we can't really wait for the
-	  optimization message, as we are currently handling the hangup of
-	  the channel that the optimization event would tell us to use.
-	  This patch modifies the behavior in app_queue such that, since we
-	  still have a lot of pertinent queue information (interface, queue
-	  name, etc.), we now raise the event with what information we
-	  know. The channels involved now may or may not be present. Users
-	  will still at least get the "AgentComplete" event, which
-	  "completes" the known Agent information. Review:
-	  https://reviewboard.asterisk.org/r/2878/ (closes issue
-	  ASTERISK-22507) Reported by: Richard Mudgett ........ Merged
-	  revisions 400060 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/manager.c, /: manager: Fix crash when appending a manager
-	  channel variable In r399887, a minor performance improvement was
-	  introduced by not allocating the manager variable struct if it
-	  wasn't used. Unfortunately, when directly accessing an
-	  ast_channel struct, manager assumed that the struct was always
-	  allocated. Since this was no longer the case, things got a bit
-	  crashy. This fixes that problem by simply bypassing appending
-	  variables if the manager channel variable struct isn't there.
-	  ........ Merged revisions 400058 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 21:58 +0000 [r400016-400021]  Richard Mudgett <rmudgett at digium.com>
-
-	* apps/app_cdr.c, res/res_parking.c, /: app_cdr and res_parking:
-	  Fix some resource leaks. * app_cdr left the ResetCDR application
-	  registered. * res_parking leaked a ref to config global. (closes
-	  issue ASTERISK-22566) Reported by: Corey Farrell Patches:
-	  ASTERISK-22566-r2.patch (license #5909) patch uploaded by Corey
-	  Farrell ........ Merged revisions 400020 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/sip/reqresp_parser.c, /, channels/chan_sip.c: chan_sip:
-	  Increase some scratch buffer sizes dealing with caller id. *
-	  Eliminated an unnecessary initialization in check_user_full().
-	  (closes issue ASTERISK-22477) Reported by: Michael Shepelev
-	  ........ Merged revisions 400013 from
+	  revisions 345558 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-16 14:56 +0000 [r345489]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_voicemail.c: Guarantee messages go into the right
+	  folders with multiple recipients Before, using the U flag in
+	  Voicemail with multiple recipients would put urgent messages in
+	  the INBOX folder for all users past the first thanks to a bug
+	  with the message copying function. This would also cause messages
+	  to fail to be sent if the INBOX directory hadn't been created for
+	  that mailbox yet. (closes issue ASTERISK-18245) Reported by: Matt
+	  Jordan (closes issue ASTERISK-18246) Reported by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/1589/ ........ Merged
+	  revisions 345487 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 400014 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 400015 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 19:18 +0000 [r400000]  Sean Bright <sean at malleable.com>
-
-	* configs/sip.conf.sample: Remove some trailing whitespace and
-	  steal revision 400000.
-
-2013-09-27 18:28 +0000 [r399991]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip.c, res/res_pjsip_session.c,
-	  include/asterisk/res_pjsip.h, res/res_pjsip.exports.in:
-	  res_pjsip: crash when using localnet and
-	  external_signaling_address options There was a collision of
-	  mod_data use on the transaction between using a nat hook and an
-	  session response callback. During state change it was assumed
-	  what was in the mod_data was nothing or the response callback.
-	  However, it was possible for it to also contain a nat hook thus
-	  resulting in a bad cast and a crash. Added the ability to store
-	  multiple data elements in mod_data via a hash table. In this
-	  instance, mod_data now stores a hash table of the two values that
-	  can be retrieved using an associated string key. (closes issue
-	  ASTERISK-22394) Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/2843/ ........ Merged
-	  revisions 399990 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 17:46 +0000 [r399978]  Jonathan Rose <jrose at digium.com>
+	  revisions 345488 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
-	  Reject calls on 200 OKs if no SDP has been received When Asterisk
-	  receives a 200 OK in response to an invite, that peer should have
-	  sent an SDP at some point by then. If the channel has never
-	  received an SDP, media won't have been set and the remote address
-	  won't be known. Endpoints in general should not be doing this.
-	  This patch makes it so that Asterisk will simply hang up a call
-	  if it sends a 200 OK at this point. So far this odd behavior for
-	  endpoints has only been observed in tests which involved manually
-	  created SIP transactions in SIPp. (closes issue ASTERISK-22424)
-	  Reported by: Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/2827/ ........ Merged
-	  revisions 399939 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399962 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399976 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 17:11 +0000 [r399938]  Richard Mudgett <rmudgett at digium.com>
-
-	* include/asterisk/astobj2.h, tests/test_astobj2.c, main/astobj2.c,
-	  /: astobj2: Remove OBJ_CONTINUE support. OBJ_CONTINUE was a
-	  strange feature that came into the world under suspicious
-	  circumstances to support an abuse of the ao2_container by
-	  chan_iax2. Since chan_iax2 no longer uses OBJ_CONTINUE, it is
-	  safe to remove it. The simplified code should help performance
-	  slightly and make understanding the code easier. Review:
-	  https://reviewboard.asterisk.org/r/2887/ ........ Merged
-	  revisions 399937 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 14:35 +0000 [r399925]  Mark Michelson <mmichelson at digium.com>
-
-	* /, bridges/bridge_native_rtp.c: Fix refleaks of ast_rtp_instance
-	  structures. These refleaks were causing bridged calls not to
-	  close their RTP ports. Thus a call would leave open 4 ports (RTP
-	  for party A, RTCP for party A, RTP for party B, and RTCP for
-	  party B). This led to an eventual depletion of available RTP
-	  ports. ........ Merged revisions 399924 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-27 14:08 +0000 [r399913]  Kinsey Moore <kmoore at digium.com>
-
-	* tests/test_cel.c, main/cel.c, /, include/asterisk/cel.h: Restore
-	  usefulness of the CEL Peer field This change makes the CEL peer
-	  field useful again for BRIDGE_ENTER and BRIDGE_EXIT events and
-	  fills the field with a comma-separated list of all channels in
-	  the bridge other than the channel that is entering or exiting the
-	  bridge. Review: https://reviewboard.asterisk.org/r/2840/ (closes
-	  issue ASTERISK-22393) ........ Merged revisions 399912 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-26 18:51 +0000 [r399898]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_registrar.c, include/asterisk/res_pjsip.h,
-	  res/res_pjsip.exports.in, /, res/res_pjsip/security_events.c:
-	  pjsip: race condition in registrar While handling a registration
-	  request a race condition could occur if/when two+ clients
-	  registered at the same time. This happened when one request
-	  obtained a copy of the current contacts for an AOR and another
-	  request did the same before the first request updated. Thus the
-	  second would update and overwrite the first (or vice-versa
-	  depending on which actually updated first). In the case of it
-	  being the same contact two "add" events would be raised. pjsip
-	  registration handling is now serialized to alleviate this issue.
-	  (closes issue AST-1213) Reported by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/2860/ ........ Merged
-	  revisions 399897 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-26 14:13 +0000 [r399875]  Rusty Newton <rnewton at digium.com>
-
-	* /, apps/app_dial.c: Adding a few words to the Dial option 'r'
-	  help text to clarify its tone argument description ........
-	  Merged revisions 399874 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-25 20:38 +0000 [r399844]  Richard Mudgett <rmudgett at digium.com>
+2011-11-15 20:11 +0000 [r345221-345433]  Richard Mudgett <rmudgett at digium.com>
 
-	* channels/sig_ss7.c, channels/chan_dahdi.c, /: chan_dahdi: CLI
-	  "core stop gracefully" has needless delay for PRI and SS7. The
-	  PRI and SS7 link control threads are not stopped correctly when
-	  the chan_dahdi.so module is unloaded. The link control threads
-	  pri_dchannel() and ss7_linkset() are not awakened from a poll()
-	  to cancel the thread. * Added a SIGURG signal after requesting
-	  the thread cancel to break the link control thread poll()
-	  immediately. For SS7 it was slightly worse, the link poll()
-	  timeout would always be whatever was the last libss7 scheduled
-	  event time used. If no libss7 scheduled event was pending, the
-	  thread could run more often than necessary. * Set nextms to 60
-	  seconds for the ss7_linkset() poll() if there is no other libss7
-	  scheduled event. ........ Merged revisions 399818 from
+	* /, res/res_agi.c: Make FastAGI HANGUP show up in AGI debug
+	  output. * Change from using send() to ast_agi_send() so the
+	  HANGUP shows up in the AGI debug output. (closes issue
+	  ASTERISK-18723) Reported by: James Van Vleet Patches:
+	  jira_asterisk_18723_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett ........ Merged revisions 345431 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399834 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399842 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-25 19:43 +0000 [r399799]  Rusty Newton <rnewton at digium.com>
-
-	* /, res/res_pjsip.c: Broke the build - Fixing XML DTD violation
-	  added in r399782, missing <para> tags inside a <note> ........
-	  Merged revisions 399798 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-25 19:29 +0000 [r399797]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, channels/chan_sip.c: chan_sip: Fix Realtime Peer Update
-	  Problem When Un-registering And Expires Header In 200ok 1st Issue
-	  When a realtime peer sends an un-REGISTER request, Asterisk
-	  un-registers the peer but the database table record still has
-	  regseconds and fullcontact for the peer. This results in calls
-	  attempting to be routed to the peer which is no longer
-	  registered. The expected behavior is to get busy/congested when
-	  attempting to call an un-registered peer through the dialplan.
-	  What was discovered is that we are clearing out the peer's
-	  registration in the database in parse_register_contact() when
-	  calling expire_register() but then upon returning from
-	  parse_register_contact(), update_peer() is run which stores back
-	  in the database table regseconds and fullcontact. 2nd Issue The
-	  reporter pointed out that the 200 ok being returned by Asterisk
-	  after un-registering a peer contains a Contact header with
-	  ;expires= and the Expires header is not set to 0. This is
-	  actually a regression. Tests were created for this second issue
-	  (ASTERISK-22548). The tests have been reviewed and a Ship It! was
-	  received on those tests. This patch does the following: * Do not
-	  ignore the Expires header value even when it is set to 0. The
-	  patch sets the pvt->expiry earlier on in the function so that it
-	  is set properly and used. * If pvt->expiry is 0, do not call
-	  update_peer since that means the peer has already been
-	  un-registered and there is no need to update the database record
-	  again since nothing has changed. (closes issue ASTERISK-22428)
-	  Reported by: Ben Smithurst Tested by: Ben Smithurst, Michael L.
-	  Young Patches:
-	  asterisk-22428-rt-peer-update-and-expires-header.diff by Michael
-	  L. Young (license 5026) Review:
-	  https://reviewboard.asterisk.org/r/2869/ ........ Merged
-	  revisions 399794 from
+	  revisions 345432 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/sig_pri.c: Fix typo in sig_pri using wrong structure
+	  name. It is fortunate that the typo does not alter generated code
+	  since the e->restart.channel and e->ring.channel members are in
+	  the same position. (closes issue ASTERISK-18868) Reported by:
+	  zvision Patches: sig_pri.c.diff (License #5755) patch uploaded by
+	  zvision ........ Merged revisions 345370 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399795 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399796 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-25 18:38 +0000 [r399782]  Rusty Newton <rnewton at digium.com>
-
-	* /, res/res_pjsip.c: Fixing documentation for the configOption
-	  "external_media_address" of both Endpoints and Transports
-	  Re-using some of Mark Michelson's text from an E-mail discussion
-	  for: * Modifying synopsis for both options * Adding description
-	  to both options * Changing name of "external_media_address" for
-	  Endpoint configuration to "media_address" in anticipation of the
-	  option name being changed. (As it is not really specific to
-	  external destinations) (issue ASTERISK-22405) (closes issue
-	  ASTERISK-22405) Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/2850/ ........ Merged
-	  revisions 399781 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-24 22:55 +0000 [r399737-399750]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/astobj2.c: astobj2: Made use OBJ_SEARCH_xxx identifiers
-	  as field enum values internally. * Made ao2_unlink to protect
-	  itself from stray OBJ_SEARCH_xxx values passed in. ........
-	  Merged revisions 399749 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/chan_iax2.c, /: chan_iax2: Prevent some needless
-	  breaking of the native IAX2 bridge. * Clean up some twisted code
-	  in the iax2_bridge() loop. * Add AST_CONTROL_VIDUPDATE and
-	  AST_CONTROL_SRCCHANGE to a list of frames to prevent the native
-	  bridge loop from breaking. * Passing the
-	  AST_CONTROL_T38_PARAMETERS frame should also allow FAX over a
-	  native IAX2 bridge. (issue ABE-2912) Review:
-	  https://reviewboard.asterisk.org/r/2870/ ........ Merged
-	  revisions 399697 from
+	  revisions 345371 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Make queue log indicate if ADDMEMBER is
+	  paused for AMI and realtime. * Add parameter to queue log
+	  ADDMEMBER to indicate if the member is paused. (closes issue
+	  ASTERISK-18645) Reported by: garlew Patches: paused.diff (License
+	  #5337) patch uploaded by garlew Tested by: rmudgett, garlew
+	  Review: https://reviewboard.asterisk.org/r/1469/ ........ Merged
+	  revisions 345285 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399708 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 For v12 and
-	  above this is really just documentation until IAX2 native
-	  bridging is restored. ........ Merged revisions 399736 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-24 19:22 +0000 [r399667-399696]  Matthew Jordan <mjordan at digium.com>
-
-	* apps/app_queue.c, /: app_queue: Don't be quite so aggressive in
-	  initializing the array We only need the first character. ........
-	  Merged revisions 399695 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_queue.c, /: app_queue: Initialize array holding
-	  MixMonitor exec options If the channel variable MONITOR_EXEC is
-	  set, app_queue will pass the specified execution parameters to
-	  the MixMonitor application when a queue is recorded. If that
-	  channel variable is not set, the buffer that holds the escaped
-	  value was not being initialized to NULL, and so would be passed
-	  to the MixMonitor application with garbage. Hilarity ensued as
-	  app_mixmonitor attempted to execute gobeldy-gook. ........ Merged
-	  revisions 399681 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/stasis_bridges.c, tests/test_cdr.c, main/cdr.c, /: Fix a
-	  performance problem CDRs There is a large performance price
-	  currently in the CDR engine. We currently perform two
-	  ao2_callback calls on a container that has an entry for every
-	  channel in the system. This is done to create matching pairs
-	  between channels in a bridge. As such, the portion of the CDR
-	  logic that this patch deals with is how we make pairings when a
-	  channel enters a mixing bridge. In general, when a channel enters
-	  such a bridge, we need to do two things: (1) Figure out if anyone
-	  in the bridge can be this channel's Party B. (2) Make pairings
-	  with every other channel in the bridge that is not already our
-	  Party B. This is a two step process. In the first step, we look
-	  through everyone in the bridge and see if they can be our Party B
-	  (single_state_process_bridge_enter). If they can - yay! We mark
-	  our CDR as having gotten a Party B. If not, we keep searching. If
-	  we don't find one, we wait until someone joins who can be our
-	  Party B. Step 2 is where we changed the logic
-	  (handle_bridge_pairings and bridge_candidate_process).
-	  Previously, we would first find candidates - those channels in
-	  the bridge with us - from the active_cdrs_by_channel container.
-	  Because a channel could be a candidate if it was Party B to an
-	  item in the container, the code implemented multiple
-	  ao2_container callbacks to get all the candidates. We also had to
-	  store them in another container with some other meta information.
-	  This was rather complex and costly, particularly if you have 300
-	  Local channels (600 channels!) going at once. Luckily, none of it
-	  is needed: when a channel enters a bridge (which is when we're
-	  figuring all this stuff out), the bridge snapshot tells us the
-	  unique IDs of everyone already in the bridge. All we need to do
-	  is: For all channels in the bridge: If the channel is us or our
-	  Party B that we got in step 1, skip it Compare us and the
-	  candidate to figure out who is Party A (based on some specific
-	  rules) If we are Party A: Make a new CDR for us, append it to our
-	  chain, and set the candidate as Party B If they are Party A: If
-	  they don't have a Party B: Make a new CDR for them, append us to
-	  their chain, and us as Party B Otherwise: Copy us over as Party B
-	  on their existing CDR. This patch does that. Because we now use
-	  channel unique IDs to find the candidates during bridging,
-	  active_cdrs_by_channel now looks up things using uniqueid instead
-	  of channel name. This makes the more complex code simpler; it
-	  does, however, have the drawback that dialplan applications and
-	  functions will be slightly slower as they have to iterate through
-	  the container looking for the CDR by name. That's a small price
-	  to pay however as the bridging code will be called a lot more
-	  often. This patch also does two other minor changes: (1) It
-	  reduces the container size of the channels in a bridge snapshot
-	  to 1. In order to be predictable for multi-party bridges, the
-	  order of the channels in the container must be stable; that is,
-	  it must always devolve to a linked list. (2) CDRs and the
-	  multi-party test was updated to show the relationship between two
-	  dialed channels. You still want to know if they talked -
-	  previously, dialed channels were always ignored, which is wrong
-	  when they have managed to get a Party B. (closes issue
-	  ASTERISK-22488) Reported by: Richard Mudgett Review:
-	  https://reviewboard.asterisk.org/r/2861/ ........ Merged
-	  revisions 399666 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-23 12:03 +0000 [r399625]  Joshua Colp <jcolp at digium.com>
-
-	* res/res_pjsip.c, res/res_pjsip_session.c, /: Fix crash in
-	  res_pjsip on load if error occurs, and prevent unloading of
-	  res_pjsip and res_pjsip_session. During load time in res_pjsip if
-	  an error occurred the operation would attempt to rollback all
-	  operations done during load. This is not permitted by PJSIP as it
-	  will assert if the operation has not been done. This fix changes
-	  the code so it will only rollback what has been initialized
-	  already. Further changes also prevent res_pjsip and
-	  res_pjsip_session from being unloaded. This is due to limitations
-	  within PJSIP itself. The library environment can only be changed
-	  to a certain extent and does not provide the ability, currently,
-	  to deinitialize certain required functionality. (closes issue
-	  ASTERISK-22474) Reported by: Corey Farrell ........ Merged
-	  revisions 399624 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-21 04:49 +0000 [r399578-399608]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/res_rtp_asterisk.c, /: res_rtp_asterisk: Fix ref leaks in
-	  ast_rtcp_read(). Moved rtcp_report RAII_VAR declaration into the
-	  loop so it is unref'ed after every loop. Moved message_blob to
-	  loop and switched it to a regular variable. The regular variable
-	  was used since message_blob is used in a very contained way.
-	  (closes issue ASTERISK-22565) Reported by: Corey Farrell Patches:
-	  rtcp_report-leak.patch (license #5909) patch uploaded by Corey
-	  Farrell Tested by: Corey Farrell ........ Merged revisions 399607
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/media_index.c: media_index: Fix
-	  process_description_file() memory leak of file_id_persist.
-	  ........ Merged revisions 399596 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/features_config.c: features_config: Fix config ref leak
-	  of parkinglots. This leak happend for just about every channel
-	  created. ........ Merged revisions 399585 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, apps/app_queue.c: app_queue: Fix json blob ref leak. The json
-	  ref from queue_member_blob_create() was never released. ........
-	  Merged revisions 399583 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/json.c, /: json: Make it obvious that ast_json_unref() is
-	  NULL safe. It looked like the safety check was done after the
-	  NULL pointer was used. ........ Merged revisions 399576 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-20 22:44 +0000 [r399566]  Kinsey Moore <kmoore at digium.com>
-
-	* main/config_options.c, /: Ensure global types in the config
-	  framework are initialized If a config object was allocated but
-	  one of its global objects was never encountered, then the global
-	  object's defaults were never applied. Ensure that global objects
-	  are initialized properly upon allocation instead of on
-	  configuration. Review: https://reviewboard.asterisk.org/r/2866/
-	  ........ Merged revisions 399564 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399565 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-20 22:06 +0000 [r399554]  Jonathan Rose <jrose at digium.com>
+	  revisions 345290 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c, configs/sip.conf.sample, UPGRADE-1.8.txt,
+	  channels/sip/include/sip.h: Restore SIP DTMF overlap dialing
+	  method. The recent fix for ASTERISK-17288 to get RFC3578 SIP
+	  overlap support working correctly removed a long standing ability
+	  to do overlap dialing using DTMF in the early media phase of a
+	  call. See ASTERISK-18702 it has a very good description of the
+	  issue. I started with Pavel Troller's chan_sip.diff patch on
+	  issue ASTERISK-18702. * Added 'dtmf' enum value to sip.conf
+	  allowoverlap config option. The new option value causes the
+	  Incomplte application to not send anything with chan_sip so the
+	  caller can supply more digits via DTMF. * Renames
+	  SIP_GET_DEST_PICKUP_EXTEN_FOUND to SIP_GET_DEST_EXTEN_MATCHMORE
+	  since that is what it really means. * Fixed get_destination()
+	  inconsistency with the pickup extension matching. * Fixed
+	  initialization of PAGE3 of global_flags in reload_config().
+	  (closes issue ASTERISK-18702) Reported by: Pavel Troller Review:
+	  https://reviewboard.asterisk.org/r/1517/ Review:
+	  https://reviewboard.asterisk.org/r/1582/ ........ Merged
+	  revisions 345273 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345275 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/dial.c, /: originate/call forwarding: Fix a crash when
-	  forwarding a call from originate (closes issue ASTERISK-22487)
-	  Reported by: David M. Lee Review:
-	  https://reviewboard.asterisk.org/r/2868/ ........ Merged
-	  revisions 399553 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* main/pbx.c, /: Fix Progress spelling error in main/pbx.c. (closes
+	  issue ASTERISK-18857) Reported by: David M Patches:
+	  mainpbx-trivial.patch (License #6326) patch uploaded by David M
+	  ........ Merged revisions 345219 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345220 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-14 19:12 +0000 [r345165]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c, /: Don't read past end of input when calling
+	  write() int blah = 1; ... write(chan->alertpipe[1], &blah,
+	  new_frames * sizeof(blah)) != (new_frames * sizeof(blah))) is
+	  only valid when new_frames == 1. Otherwise we start reading into
+	  adjacent variables declared on the stack. The read end discards
+	  what is read, so the values don't matter but it's not a good idea
+	  to read past where we want even though new_frames is almost
+	  always 1 and should never be large. This patch is basically taken
+	  out of kpfleming's eventfd branch, as he mentioned that he
+	  remembered fixing it there when I talked to him about this issue.
+	  Review: https://reviewboard.asterisk.org/r/1583/ ........ Merged
+	  revisions 345163 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345164 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-20 16:18 +0000 [r399533]  Joshua Colp <jcolp at digium.com>
+2011-11-14 19:03 +0000 [r345162]  Walter Doekes <walter+asterisk at wjd.nu>
 
-	* /, channels/chan_pjsip.c: Add a missing session supplement
-	  unregistration in chan_pjsip for ACKs. (closes issue
-	  ASTERISK-22453) Reported by: Corey Farrell Patches:
-	  chan_pjsip_session_unregister_supplement.patch uploaded by Corey
-	  Farrell (license 5909) ........ Merged revisions 399531 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/sip/include/reqresp_parser.h: Update reqresp_parser
+	  parse_uri doxygen comments. The issue mentioned in the bug report
+	  had been fixed recently by twilson. The reporter included this
+	  documentation fix. (closes issue ASTERISK-18572) Reported by:
+	  Richard Miller Patch by: Richard Miller (modified) ........
+	  Merged revisions 345160 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345161 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-14 16:21 +0000 [r345120]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_voicemail.c: Moves voicemail setup password entry to
+	  the end of the setup process. This change was made because
+	  forcegreeting and forcename settings in voicemail could be
+	  circumvented by hanging up after entering a password, because the
+	  only way voicemail currently observes whether a mailbox is new or
+	  not is by checking to see if the password is the same as the
+	  mailbox number or not. (closes issue ASTERISK-18282) Reported by:
+	  Matt Jordan Review: https://reviewboard.asterisk.org/r/1581/
+	  ........ Merged revisions 345062 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345117 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-20 14:26 +0000 [r399515]  Kevin Harwell <kharwell at digium.com>
+2011-11-14 15:11 +0000 [r345065]  Kinsey Moore <kmoore at digium.com>
 
-	* /, main/logger.c: Fix memory leak in logger. Fixed a memory leak
-	  discovered in the logger where a temporary string buffer was not
-	  being freed. (closes issue ASTERISK-22540) Reported by: John
-	  Hardin ........ Merged revisions 399513 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399514 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, channels/chan_sip.c: Ensure that a null vmexten does not cause
+	  a segfault When sip_send_mwi_to_peer was modified recently to
+	  avoid deadlocks, vmexten was not expected to be null. This change
+	  handles that situation to avoid a segfault. ........ Merged
+	  revisions 345063 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 345064 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-19 23:20 +0000 [r399503]  Richard Mudgett <rmudgett at digium.com>
+2011-11-14 01:25 +0000 [r345023]  TransNexus OSP Development <support at transnexus.com>
 
-	* /, main/optional_api.c: optional_api: Make always use the
-	  standard malloc functions even with MALLOC_DEBUG. ........ Merged
-	  revisions 399501 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* apps/app_osplookup.c: Increased max number of destinations.
 
-2013-09-19 17:01 +0000 [r399459]  Jonathan Rose <jrose at digium.com>
+2011-11-12 16:32 +0000 [r344979]  Gregory Nietsky <gregory at distrotech.co.za>
 
-	* /, channels/chan_sip.c: chan_sip: Make direct media reinvites for
-	  T38 put Asterisk in the media path Prior to this patch, Asterisk
-	  would incorrectly use the previous endpoint addresses in SDP in
-	  spite of providing its own port. T38 is never meant to be done
-	  through directmedia and Asterisk should always be in the media
-	  path for these streams. (closes issue ASTERISK-17273) Reported
-	  by: Kevin Stewart (closes issue ASTERISK-18706) Reported by:
-	  Jeremy Kister Review: https://reviewboard.asterisk.org/r/2853/
-	  ........ Merged revisions 399456 from
+	* channels/chan_misdn.c, /: mISDN Round Robin break when no channel
+	  is available Prevent channels been parsed repetitively. ........
+	  Merged revisions 344965 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344966 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-12 00:36 +0000 [r344901]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_musiconhold.c: Don't forget to rescan MOH files for
+	  cached realtime classes Realtime MOH class caching was
+	  implemented because without it, you would build a completely new
+	  MOH class and would start the music over at the beginning each
+	  time hold was pressed in a conversation. Unfortunately, this
+	  broke re-scanning for file changes for realtime MOH classes. This
+	  patch corrects that issue. (closes issue ASTERISK-18039) Review:
+	  https://reviewboard.asterisk.org/r/1579/ ........ Merged
+	  revisions 344899 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344900 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-11 22:00 +0000 [r344846]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* include/asterisk/utils.h, /, main/utils.c,
+	  include/asterisk/stringfields.h: Use __alignof__ instead of
+	  sizeof for stringfield length storage. Kevin P Fleming suggested
+	  that r343157 should use __alignof__ instead of sizeof. For most
+	  systems this won't be an issue, but better fix it now while it's
+	  still fresh. Review: https://reviewboard.asterisk.org/r/1573
+	  ........ Merged revisions 344843 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399457 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 344845 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-11 21:57 +0000 [r344844]  Matthew Jordan <mjordan at digium.com>
+
+	* /, main/file.c: Video format was treated as audio when removed
+	  from the file playback scheduler This patch fixes the format type
+	  check in ast_closestream and filestream_destructor. Previously a
+	  comparison operator was used, but since audio formats are no
+	  longer contiguous (and AST_FORMAT_AUDIO_MASK includes formats
+	  that have a value greater than the video formats), a bitwise AND
+	  operation is used instead. Duplicated code was also moved to
+	  filestream_close. (closes issue ASTERISK-18682) Reported by: Aldo
+	  Bedrij Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1580/ ........ Merged
+	  revisions 344823 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344842 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-18 20:04 +0000 [r399405]  Kinsey Moore <kmoore at digium.com>
+2011-11-11 21:37 +0000 [r344838-344840]  Walter Doekes <walter+asterisk at wjd.nu>
 
-	* /, main/abstract_jb.c: Fix jitter buffer log file creation This
-	  adjusts '/'-to-'#' replacement to replace all instances of '/'
-	  instead of just the first to ensure that the jitter buffer log
-	  file gets the correct name as per Richard Kenner's suggestion.
-	  (closes issue ASTERISK-21036) Reported by: Richard Kenner
-	  ........ Merged revisions 399402 from
+	* /, channels/sip/reqresp_parser.c: Remove unneeded if(params)
+	  checks in reqresp_parser. Nick Lewis added them in
+	  https://reviewboard.asterisk.org/r/549/diff/1-2/ for no apparent
+	  reason. There is no way that params could become NULL in that
+	  piece of code, so I removed these excess checks again. ........
+	  Merged revisions 344837 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344839 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* main/manager.c, /: Fix bad quoting of multiline mxml opaque_data
+	  that caused invalid xml. The opaque_data was added and enclosed
+	  in single quotes, assuming it would be only a single line. The
+	  rest of the lines were appended after the closing quote. (closes
+	  issue ASTERISK-18852) Reported by: peep_ on IRC Review:
+	  https://reviewboard.asterisk.org/r/1577 ........ Merged revisions
+	  344835 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 344836 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-11 20:15 +0000 [r344771]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Fix regression introduced by SDP fixups
+	  If capability is adjusted when switching to UDPTL during fax
+	  transmission, fax teardown fails. Make sure capability is only
+	  touched if RTP is active. This regression was introduced in
+	  R344385. ........ Merged revisions 344769 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344770 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-11 18:37 +0000 [r344663-344717]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Check sip.conf maxforwards parameter for
+	  range 1 <= x <= 255. JIRA AST-710 ........ Merged revisions
+	  344715 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 344716 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, main/cli.c: Make CLI "core show channel" not hold the channel
+	  lock during console output. Holding the channel lock while the
+	  CLI "core show channel" command is executing can slow down the
+	  system. It could block the system if the console output is halted
+	  or paused. * Made capture the CLI "core show channel" output into
+	  a buffer to be output after the channel is unlocked. * Removed
+	  use of C++ keyword as a variable name. out renamed to obuf. *
+	  Checked allocation of obuf for failure so will not crash. (closes
+	  issue ASTERISK-18571) Reported by: Pavel Troller Tested by:
+	  rmudgett ........ Merged revisions 344661 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399403 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399404 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 344662 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-18 17:23 +0000 [r399368-399378]  Matthew Jordan <mjordan at digium.com>
+2011-11-11 15:47 +0000 [r344610]  Jonathan Rose <jrose at digium.com>
 
-	* /, build_tools/prep_tarball: Update prep_tarball with new
-	  documentation files on the Asterisk wiki This will now pull both
-	  a command reference for the version being prepared, as well as an
-	  Admin Guide that applies to all versions of Asterisk. (issue
-	  ASTERISK-22439) Reported by: Olle Johansson ........ Merged
-	  revisions 399351 from
+	* main/pbx.c, /: Fix a segmentation fault when using an extension
+	  with CID matching and no CID. Attempting to call an extension
+	  which used Caller ID matching with a channel that has an empty
+	  caller id string would result in a segmentation fault. (closes
+	  issue ASTERISK-18392 Reported By: Ales Zelenik ........ Merged
+	  revisions 344608 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399373 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399376 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, bridges/bridge_softmix.c: Add a WARNING in bridge_softmix when
-	  a timing module isn't loaded If bridge_softmix fails to be
-	  created because no timing source is present in Asterisk, this
-	  will currently fail gracefully but with (most likely) a generic
-	  error message by whatever module tried to create the softmix
-	  bridge. This patch adds a more explicit warning so you can
-	  actually diagnose and fix the problem. Review:
-	  https://reviewboard.asterisk.org/r/2857/ ........ Merged
-	  revisions 399353 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399365 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-18 17:15 +0000 [r399352]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/config_options.c: Make config framework able to reload
-	  module configs with multiple config files. The config framework
-	  is supposed to be able to load configs that come from multiple
-	  config files. The principle example is chan_sip's sip.conf and
-	  users.conf. Unfortunately, it only does this correctly on initial
-	  load. This patch causes the module's config to be reloaded
-	  entirely if any of the config files change. (closes issue
-	  ASTERISK-22009) Reported by: Richard Mudgett Review:
-	  https://reviewboard.asterisk.org/r/2859/
-
-2013-09-18 14:56 +0000 [r399340]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_messaging.c, /: res_pjsip_messaging: Register
-	  message technology as pjsip pjsip's message technology was being
-	  registered as 'sip', which was causing it to not load due it
-	  conflicting with chan_sip's registered 'sip' technology for
-	  messaging. It now registers as 'pjsip'. However, due to this
-	  change the "to" field for outgoing pjsip messages need to be
-	  prefixed with 'pjsip:' instead of 'sip:'. Incoming messages to
-	  res_pjsip_messaging will automatically have their "to" fields
-	  altered in order to accommodate the change. Outgoing messages
-	  also handle changing it back to 'sip' before being sent so the
-	  pjsip library will properly handle it. (closes issue
-	  ASTERISK-22445) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2833/ ........ Merged
-	  revisions 399339 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-18 00:13 +0000 [r399295]  Michael L. Young <elgueromexicano at gmail.com>
-
-	* /, main/features_config.c: Fix Segfault In features-config.c When
-	  Application Has No Arguments Some applications do not require
-	  arguments. Therefore, when parsing application maps in
-	  features.conf, it is possible that app_data will be set to NULL.
-	  * This patch sets app_data to "" if it is NULL. Review:
-	  https://reviewboard.asterisk.org/r/2804 ........ Merged revisions
-	  399294 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-17 23:10 +0000 [r399284]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_sdp_rtp.c, res/res_pjsip/pjsip_configuration.c,
-	  res/res_pjsip_t38.c, include/asterisk/res_pjsip.h, /: Change the
-	  "external_media_address" PJSIP endpoint option to
-	  "media_address". The endpoint option does not apply to
-	  communication with external entities. Rather, the option is
-	  applied to all communications with the endpoint. The
-	  external_media_address transport configuration option may
-	  override the endpoint option if it turns out that we are going to
-	  be communicating with an external entity. Two things of note: 1)
-	  I have not updated the XML documentation. This is being taken
-	  care of by Rusty as part of his work on issue ASTERISK-22405 2)
-	  This commit is likely to cause testsuite failures since there are
-	  tests that use the external_media_address endpoint option, and
-	  they will need to be changed over. Well, I'm planning to get that
-	  updated ASAP after this commit. (closes issue ASTERISK-22528)
-	  reported by Rusty Newton ........ Merged revisions 399283 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-17 18:44 +0000 [r399269]  Kevin Harwell <kharwell at digium.com>
-
-	* main/logger.c, main/asterisk.c, /: Remote console: more output
-	  discrepancies The remote console continued to have issues with
-	  its output. In this case CLI command output would either not show
-	  up (if verbose level = 0) or would contain verbose prefixes (if
-	  verbose level > 0) once log messages were sent to the remote
-	  console. The fix now now adds verbose prefix data to all new
-	  lines contained in a verbose log string. (closes issue
-	  ASTERISK-22450) Reported by: David Brillert (closes issue
-	  AST-1193) Reported by: Guenther Kelleter Review:
-	  https://reviewboard.asterisk.org/r/2825/ ........ Merged
-	  revisions 399267 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399268 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-17 17:55 +0000 [r399258]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, include/asterisk/features_config.h: Fix doxygen to use correct
-	  units of features.conf options. ........ Merged revisions 399257
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-17 17:10 +0000 [r399238-399248]  Mark Michelson <mmichelson at digium.com>
-
-	* main/bridge_basic.c, main/features_config.c, /: Fix other
-	  timeouts (atxferloopdelay and atxfernoanswertimeout) to use
-	  seconds instead of milliseconds. Thanks to Richard Mudgett for
-	  pointing this out. ........ Merged revisions 399247 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/features_config.c, /, include/asterisk/features_config.h,
-	  main/bridge_basic.c: Switch transferdigittimeout to be configured
-	  as seconds instead of milliseconds. This was an unintentional
-	  consequence of the update of features.conf to use the config
-	  framework in Asterisk 12. Thanks to Marco Signorini on the
-	  Asterisk developers list for pointing out the problem. ........
-	  Merged revisions 399237 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-17 14:58 +0000 [r399226]  Kevin Harwell <kharwell at digium.com>
-
-	* apps/confbridge/conf_state_multi_marked.c, /: Confbridge: empty
-	  conference not being torn down Confbridge would not properly tear
-	  down an empty conference bridge when all users were kicked via
-	  end_marked=yes and at least one user was also set to wait_marked.
-	  This occurred because while end_marked users were being kicked
-	  and at least one was also set to wait_marked then the leave
-	  wait_marked handler would be called on that user, but there would
-	  be no waiting user (still considered active). The waiting users
-	  would decrement and now be negative. The conference would remain,
-	  but be put into an inactive state. The solution was to move from
-	  the active list to the wait list, those users with wait_marked
-	  set right before kicking. This allows both the active and wait
-	  users to decrement correctly and the confbridge to tear down
-	  properly. A crashed also occurred when trying to list the
-	  specific conference from the CLI. This happened because the
-	  conference specified was invalid. Since the conference properly
-	  tears down now there is no way to reference it thus alleviating
-	  the crash as well. (closes issue ASTERISK-21859) Reported by:
-	  Chris Gentle Review: https://reviewboard.asterisk.org/r/2848/
-	  ........ Merged revisions 399222 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399225 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-16 18:36 +0000 [r399161-399208]  Richard Mudgett <rmudgett at digium.com>
-
-	* tests/test_ari_model.c, /: Fix module load errors for
-	  test_ari_model.so. You cannot use a function pointer variable
-	  with an external function from another dynamically loaded module
-	  because data variables are always resolved even with RTLD_LAZY. *
-	  Added wrapper functions for ast_ari_validate_int() and
-	  ast_ari_validate_string() to use instead for the function pointer
-	  variable. (closes issue ASTERISK-22457) Reported by: David M. Lee
-	  ........ Merged revisions 399207 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_speech_utils.c, /, res/res_speech.exports.in:
-	  app_speech_utils: Fix unresolved symbol ast_speech_get_setting().
-	  Fixes regression introduced by -r374096. * Made
-	  res_speech.export.in export ast_* symbols instead of specific
-	  functions. * Made app_speech_utils.c declare that it is dependent
-	  upon res_speech. (issue ASTERISK-17136) Reported by: Richard
-	  Kenner ........ Merged revisions 399197 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 344609 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-10 23:21 +0000 [r344538-344560]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_macro.c: Fix app_macro.c MODULEINFO section
+	  termination. (closes issue ASTERISK-18848) Reported by: Tony
+	  Mountifield ........ Merged revisions 344557 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Fix potential deadlock calling ast_call()
+	  with channel locks held. Fixed app_queue.c:ring_entry() calling
+	  ast_call() with the channel locks held. Chan_local attempts to do
+	  deadlock avoidance in its ast_call() callback and could deadlock
+	  if a channel lock is already held. ........ Merged revisions
+	  344539 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 344540 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Make AMI event AgentCalled get
+	  CallerID/ConnectedLine info from the incoming channel. It was
+	  strange that the AgentCalled AMI event would get most of its
+	  information from the incoming channel but then get the CallerID
+	  information from the outgoing channel. Before connected line
+	  support was added, this information was always the same at this
+	  point. (closes issue ASTERISK-18152) Reported by: Thomas Farnham
+	  Tested by: rmudgett ........ Merged revisions 344536 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344537 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-10 21:56 +0000 [r344494]  David Vossel <dvossel at digium.com>
+
+	* /, main/bridging.c: Merged revisions 344493 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r344493 | dvossel | 2011-11-10 15:54:42 -0600 (Thu, 10 Nov 2011)
+	  | 12 lines Fixes issue with ConfBridge participants hanging up
+	  during DTMF feature menu usage getting stuck in conference
+	  forever. When a conference user enters the DTMF menu they are
+	  suspended from the bridge while the channel is handed off to the
+	  DTMF feature code. If a user entered this state and hungup, there
+	  existed a race condition where the channel could not exit the
+	  conference because it was waiting on a signal that would never
+	  arrive. This patch fixes that, because it would stupid for me to
+	  talk about the problem and commit a patch for something else.
+	  (closes issue ASTERISK-18829) Reported by: zvision ........
+
+2011-11-10 21:15 +0000 [r344387-344441]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_meetme.c: Fix another incorrect case with meetme's
+	  PIN logic and add documentation This fixes an issue where a user
+	  of a dynamic conference was asked for a PIN twice. This also adds
+	  documentation to assist in future modifications to the piece of
+	  code responsible for PIN checking. (closes issue AST-670)
+	  ........ Merged revisions 344439 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344440 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Fix several
+	  bugs with SDP parsing and well-formedness of responses Fix bug
+	  ASTERISK-16558 which dealt with the order of responses to
+	  incoming streams defined by SDP. Fix unreported bug where
+	  offering multiple same-type streams would cause Asterisk to reply
+	  with an incorrect SDP response missing one or more streams
+	  without a proper declination. Fix bugs related to a single
+	  non-audio stream being offered with responses requesting codecs
+	  that were not offered in the initial invite along with an
+	  additional audio stream that was not in the initial invite.
+	  Review: https://reviewboard.asterisk.org/r/1516/ ........ Merged
+	  revisions 344385 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344386 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_iax2.c, /: chan_iax2: Fix saving the wrong expiry
-	  time in astdb. When a new IAX2 client registers, the astdb
-	  database is updated with the value of minregexpire defined in
-	  iax.conf instead of using the expiry time that is provided by the
-	  client. The provided expiry time of the client is updated after
-	  inserting the astdb entry. As a consequence, restarting or
-	  reloading asterisk creates clients whose registration may expire
-	  before they reregister. The clients are therefore unavailable
-	  after minregexpire seconds until they reregister. * Move updating
-	  of the expiry time to before inserting into the astdb. (closes
-	  issue ASTERISK-22504) Reported by: Stefan Wachtler Patches:
-	  chan_iax2.c.patch (license #6533) patch uploaded by Stefan
-	  Wachtler ........ Merged revisions 399158 from
+2011-11-10 16:29 +0000 [r344335]  Matthew Nicholson <mnicholson at digium.com>
+
+	* res/res_rtp_asterisk.c, /: only attempt to do stun handling on
+	  ipv4 or ipv4 mapped to ipv6 addresses Patch by: jkonieczny
+	  (modified) ASTERISK-18490 ........ Merged revisions 344330 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399159 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399160 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-16 02:37 +0000 [r399147]  Matthew Jordan <mjordan at digium.com>
-
-	* main/cdr.c, /: Filter internal channels out of bridge enter/leave
-	  message handling Some channels exist merely as an implementation
-	  detail in Asterisk, such as ConfBridge's announcer/recorder
-	  channels. These channels should never be exposed to the outside
-	  world, or to interfaces that report on Asterisk. We already
-	  filter out such channels in snapshot processing; however, we
-	  failed to filter out bridge related messages that involved these
-	  channels. This patch filters out bridge related messages that are
-	  for such channels. This prevents a spurious WARNING message from
-	  being displayed when those channels move in and out of bridges.
-	  ........ Merged revisions 399146 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 22:19 +0000 [r399138]  Richard Mudgett <rmudgett at digium.com>
-
-	* res/parking/parking_bridge_features.c, apps/app_agent_pool.c,
-	  include/asterisk/features.h, main/channel.c,
-	  res/parking/parking_tests.c, include/asterisk/bridge_channel.h,
-	  main/features.c, tests/test_cel.c, main/bridge_channel.c,
-	  tests/test_cdr.c, apps/confbridge/conf_chan_announce.c,
-	  include/asterisk/bridge.h, res/res_pjsip_refer.c, /,
-	  channels/chan_sip.c, res/stasis/control.c, main/bridge.c,
-	  main/bridge_basic.c, main/core_unreal.c,
-	  res/parking/parking_applications.c, main/core_local.c: Restore
-	  Dial, Queue, and FollowMe 'I' option support. The Dial, Queue,
-	  and FollowMe applications need to inhibit the bridging initial
-	  connected line exchange in order to support the 'I' option. *
-	  Replaced the pass_reference flag on ast_bridge_join() with a
-	  flags parameter to pass other flags defined by enum
-	  ast_bridge_join_flags. * Replaced the independent flag on
-	  ast_bridge_impart() with a flags parameter to pass other flags
-	  defined by enum ast_bridge_impart_flags. * Since the Dial, Queue,
-	  and FollowMe applications are now the only callers of
-	  ast_bridge_call() and ast_bridge_call_with_flags(), changed the
-	  calling contract to require the initial COLP exchange to already
-	  have been done by the caller. * Made all callers of
-	  ast_bridge_impart() check the return value. It is important. As a
-	  precaution, I also made the compiler complain now if it is not
-	  checked. * Did some cleanup in parking_tests.c as a result of
-	  checking the ast_bridge_impart() return value. An independent,
-	  but associated change is: * Reduce stack usage in
-	  ast_indicate_data() and add a dropping redundant connected line
-	  verbose message. (closes issue ASTERISK-22072) Reported by:
-	  Joshua Colp Review: https://reviewboard.asterisk.org/r/2845/
-	  ........ Merged revisions 399136 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 20:55 +0000 [r399101]  David M. Lee <dlee at digium.com>
-
-	* /, main/astobj2.c: Don't write to /tmp/refs when REF_DEBUG is not
-	  defined. If MALLOC_DEBUG is enabled, then the debug destructor
-	  for the container is used, which would erroneously write to
-	  /tmp/refs. This patch only uses the debug destructor if ref_debug
-	  is used. (closes issue ASTERISK-22536) ........ Merged revisions
-	  399098 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 399099 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399100 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 14:50 +0000 [r399082-399084]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip.c, res/res_pjsip_pubsub.c, res/res_pjsip_session.c,
-	  include/asterisk/res_pjsip.h, res/res_pjsip.exports.in, /: Create
-	  more accurate Contact headers for dialogs when we are the UAS.
-	  (closes issue AST-1207) reported by John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/2842 ........ Merged revisions
-	  399083 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip/config_auth.c, /,
-	  res/res_pjsip_outbound_authenticator_digest.c,
-	  res/res_pjsip_authenticator_digest.c: Change how realms are
-	  handled for outbound authentication. With this change, if no
-	  realm is specified in an outbound auth section, then we will
-	  simply match the realm that was present in the 401/407 challenge.
-	  (closes issue ASTERISK-22471) Reported by George Joseph (closes
-	  issue ASTERISK-22386) Reported by Rusty Newton Patches:
-	  outbound_auth_realm_v4.patch uploaded by George Joseph (License
-	  #6322) ........ Merged revisions 399059 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 14:43 +0000 [r399080-399081]  David M. Lee <dlee at digium.com>
-
-	* /: Recorded merge of revisions 399035,399049 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12 These were lost
-	  in r399071
-
-	* /: Put merge tracking for r399039 back.
-
-2013-09-13 14:27 +0000 [r399071]  Rusty Newton <rnewton at digium.com>
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c: Broke the build!
-	  Forgot para tags within my description.
-	  https://bamboo.asterisk.org/bamboo/browse/AST-ATRUNKBUILD-304
-	  ........ Merged revisions 399064 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 14:22 +0000 [r399042-399051]  David M. Lee <dlee at digium.com>
-
-	* res/res_pjsip_log_forwarder.c (added), res/res_pjsip_logger.c,
-	  res/res_rtp_asterisk.c, /: res_pjsip: Forward PJSIP logging to
-	  Asterisk logging This patch uses PJSIP's pj_log_set_log_func() to
-	  forward PJSIP's log messages to Asterisk's logger. This is done
-	  in a new module: res_pjsip_log_forwarder.so. This patch sets
-	  defaultenabled on the existing res_pjsip_logger.so to no, since
-	  logging every SIP packet seems a bit odd to do by default, and is
-	  (hopefully) less necessary with regular PJSIP logging. It also
-	  removes res_rtp_asterisk's disabling of PJSIP logging. (closes
-	  issue ASTERISK-22360) Reported by: Joshua Colp Review:
-	  https://reviewboard.asterisk.org/r/2830/ ........ Merged
-	  revisions 399049 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_http_websocket.c: ARI: Fix WebSocket response when
-	  subprotocol isn't specified When I moved the ARI WebSocket from
-	  /ws to /ari/events, I added code to allow a WebSocket to connect
-	  without specifying the subprotocol if there's only one
-	  subprotocol handler registered for the WebSocket. Naively, I
-	  coded it to always respond with the subprotocol in use.
-	  Unfortunately, according to RFC 6455, if the server's response
-	  includes a subprotocol header field that "indicates the use of a
-	  subprotocol that was not present in the client's handshake [...],
-	  the client MUST _Fail the WebSocket Connection_.", emphasis
-	  theirs. This patch correctly omits the Sec-WebSocket-Protocol if
-	  one is not specified by the client. (closes issue ASTERISK-22441)
-	  Review: https://reviewboard.asterisk.org/r/2828/ ........ Merged
-	  revisions 399039 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 14:17 +0000 [r399036]  Kinsey Moore <kmoore at digium.com>
+	  revisions 344334 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-09 20:55 +0000 [r344272]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix deadlock during dialplan reload.
+	  Another deadlock between the conlock/hints and channels/channel
+	  locking orders. * Don't hold the channel and private lock in
+	  sip_new() when calling ast_exists_extension(). (closes issue
+	  ASTERISK-18740) Reported by: Byron Clark Patches:
+	  sip_exists_exten_dlock_3.diff (license #5041) patch uploaded by
+	  Gregory Hinton Nietsky ASTERISK-18740.patch (license #6157) patch
+	  uploaded by Byron Clark Tested by: Byron Clark ........ Merged
+	  revisions 344268 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344271 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-09 20:10 +0000 [r344214-344217]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c, channels/sip/reqresp_parser.c,
+	  channels/sip/include/sip.h,
+	  channels/sip/include/reqresp_parser.h: Don't treat a host:port
+	  string as a domain The domain matching code prior to 1.8 used to
+	  manually remove the port from the host:port string when
+	  determining if an incoming request matched the list of domains.
+	  When switching to the new parsing functions, the documentation
+	  implied that the "domain" was being returned by these functions,
+	  when instead it was returning the "hostport" as defined by RFC
+	  3261. This led to confusion and resulted in 1.8+ rejecting an
+	  incoming request from x.x.x.x:xxxxx when domain=x.x.x.x was set
+	  in sip.conf. This patch renames the "domain" variables in the
+	  parsing functions to "hostport" to more accurately describe what
+	  it is that they are returning and also properly truncates the
+	  resulting hostport strings when dealing with domain matching.
+	  Review: https://reviewboard.asterisk.org/r/1574/ ........ Merged
+	  revisions 344215 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344216 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, apps/app_meetme.c: Fix several crashes in MeetMeAdmin This
-	  change ensures that MeetMeAdmin commands requiring a user
-	  actually get a user and fixes another issue where an extra
-	  dereference could occur for a last-entered user being ejected if
-	  a user identifier was also provided. (closes issue
-	  ASTERISK-21907) Reported by: Alex Epshteyn Review:
-	  https://reviewboard.asterisk.org/r/2844/ ........ Merged
-	  revisions 399033 from
+	* /, tests/test_netsock2.c: Add a unit test for
+	  ast_sockaddr_split_hostport Review:
+	  https://reviewboard.asterisk.org/r/1575/ ........ Merged
+	  revisions 344157 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 399034 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 399035 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-13 13:28 +0000 [r399032]  Rusty Newton <rnewton at digium.com>
-
-	* /, res/res_pjsip_endpoint_identifier_ip.c: 'identify'
-	  configObject doesn't have a synopsis Add a straightforward
-	  synopsis and description to the identify config object in XML
-	  documentation. (issue ASTERISK-22311) (closes issue
-	  ASTERISK-22311) Reported By: Rusty Newton ........ Merged
-	  revisions 399031 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 23:42 +0000 [r399020-399022]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/bridge.c: CLI bridge: Fix "bridge destroy <id>" and
-	  "bridge kick <id> <chan>" tab completion. These two commands must
-	  deal with the live bridges container for tab completion and not
-	  the stasis cache. ........ Merged revisions 399021 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/bridge.c, /: astobj2: Register the bridges container for
-	  debug inspection. ........ Merged revisions 399019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 23:23 +0000 [r399018]  Rusty Newton <rnewton at digium.com>
-
-	* /, res/res_pjsip_acl.c: Documentation fix and improvements to XML
-	  configuration help res_pjsip_acl * One bug fix. Made the synopsis
-	  for "type" to accurate. * changing the usage of "IP-domains" to
-	  "IP addresses" * clarifying the usage for the options, by adding
-	  a relevant description for each * modified other areas of the XML
-	  help for clarity, such as the module description and a few
-	  synopsis changes here and there. See the patch. (issue
-	  ASTERISK-22458) (closes issue ASTERISK-22458) Reported By: Rusty
-	  Newton Review: https://reviewboard.asterisk.org/r/2823/ ........
-	  Merged revisions 399017 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 20:27 +0000 [r399006]  Jonathan Rose <jrose at digium.com>
+	  revisions 344175 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-09 19:08 +0000 [r344161]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooh323.c, /, addons/ooh323c/src/ooh245.c,
+	  addons/ooh323c/src/ooq931.h, addons/ooh323c/src/ootypes.h,
+	  addons/ooh323c/src/oochannels.c, addons/ooh323c/src/ooq931.c:
+	  Generate response to Status Enquiry message with Status q.931
+	  message. Some PBXes require this for call status checking (closes
+	  issue ASTERISK-18748) Reported by: Fabrizio Lazzaretti Patches:
+	  ASTERISK-18748-5.patch (License #5415) patch uploaded by may213
+	  Tested by: Fabrizio Lazzaretti ........ Merged revisions 344158
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 344159 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/sip/include/sip.h, /, channels/chan_sip.c: chan_sip:
-	  Revert r398835 due to failing tests involving originate (issue
-	  ASTERISK-22424) Reported by: Jonathan Rose ........ Merged
-	  revisions 398977 from
+2011-11-09 17:15 +0000 [r344104]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_meetme.c: Fix pin parameter behavior regression in
+	  MeetMe The last time this code was touched (by me), a subtlety
+	  was missed based on the difference between needing to check a
+	  pin's validity and the need to prompt for a pin. (closes issue
+	  ASTERISK-18488) ........ Merged revisions 344102 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398986 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398991 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 16:44 +0000 [r398939]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/core_unreal.c, /: core_local: Fix memory corruption race
-	  condition. The masquerade super test is failing on v12 with high
-	  fence violations and crashing. The fence violations are showing
-	  that party id allocated memory strings are somehow getting
-	  corrupted in the bridge_reconfigured_connected_line_update()
-	  function. The invalid string values happen to be the freed memory
-	  fill pattern. After much puzzling, I deduced that the
-	  bridge_reconfigured_connected_line_update() is copying a string
-	  out of the source channel's caller party id struct just as
-	  another thread is updating it with a new value. The copying
-	  thread is using the old string pointer being freed by the
-	  updating thread. A search of the code found the
-	  unreal_colp_redirect_indicate() routine updating the caller party
-	  id's without holding the channel lock. A latent bug in v1.8 and
-	  v11 hatched in v12 because of the bridging and connected line
-	  changes. :) (issue ASTERISK-22221) Reported by: Matt Jordan
-	  Review: https://reviewboard.asterisk.org/r/2839/ ........ Merged
-	  revisions 398938 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 15:23 +0000 [r398928]  David M. Lee <dlee at digium.com>
-
-	* res/res_pjsip.c, /: Fix symbol collision with pjsua. We shouldn't
-	  be exporting any symbols that start with pjsip_. ........ Merged
-	  revisions 398927 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-12 00:04 +0000 [r398883-398887]  Rusty Newton <rnewton at digium.com>
+	  revisions 344103 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, apps/app_queue.c: 'queue add member' help text correction You
-	  are adding dial strings to the queue, not channels. An aribitrary
-	  string could be used, but you are typically referencing a
-	  channel. Correcting the command help text. (issue ASTERISK-22263)
-	  (closes issue ASTERISK-22263) Reported By: Rusty Newton ........
-	  Merged revisions 398884 from
+2011-11-09 15:28 +0000 [r344050]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, formats/format_wav.c: don't call ltohl() twice on the same
+	  value ASTERISK-18739 Patch by: pawel (modified) ........ Merged
+	  revisions 344048 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 344049 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-08 22:14 +0000 [r344005]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Residual changes for Asterisk v10 branch
+	  from ASTERISK-18747. Residual changes for Asterisk v10 branch
+	  from ASTERISK-18747 after
+	  https://reviewboard.asterisk.org/r/1564/ commit and associated
+	  dialogs callid hash key change fix. * Make check_rtp_timeout()
+	  return CMP_MATCH if need to delete dialog from dialogs_rtpcheck.
+	  This is an optimization to avoid an unneeded lock/unlock and
+	  object search when using ao2_unlink. * Prevent crash in
+	  check_rtp_timeout() if dialog->rtp is NULL. Review:
+	  https://reviewboard.asterisk.org/r/1557/ ........ Merged
+	  revisions 344004 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-08 19:29 +0000 [r343951]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, pbx/pbx_config.c: Fix crash when dialplan remove include is
+	  called with too few arguments. "dialplan remove include x from y"
+	  crashed when the amount of arguments was less than 6. (closes
+	  issue ASTERISK-18762) Reported by: Andrey Solovyev Tested by:
+	  Andrey Solovyev ........ Merged revisions 343936 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398885 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398886 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 343944 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* configs/chan_dahdi.conf.sample, /: Documentation fix -
-	  waitfordialtone is not boolean, it's time in milliseconds
-	  Changing text in chan_dahdi.conf sample to be accurate. (issue
-	  ASTERISK-22308) (closes issue ASTERISK-22308) Reported By:
-	  Malcolm Davenport ........ Merged revisions 398880 from
+2011-11-08 18:35 +0000 [r343905]  David Vossel <dvossel at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 343900 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r343900 | dvossel | 2011-11-08 12:29:33 -0600 (Tue, 08 Nov 2011)
+	  | 11 lines Fixes regression caused by r343635 There was a missing
+	  unlock for a function return that is only present in Asterisk 10
+	  and Asterisk Trunk. (closes issue ASTERISK-18839) Reported by:
+	  Michael L. Young Patches:
+	  asterisk-18839-missing-lock-trunk-v2.diff (License #5026) patch
+	  uploaded by Michael L. Young ........
+
+2011-11-08 18:02 +0000 [r343853]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c, main/acl.c: Fixed reference to incorrect
+	  variable if unknown host configured crash. * Fixed a LOG_ERROR
+	  message referencing the config variable list v that had
+	  previously been processed and became NULL. * Added error return
+	  value set that was missing in an ast_append_ha() error return
+	  path. (closes issue ASTERISK-18743) Reported by: Michele Patches:
+	  issueA18743-fix_dynamic_exclude_static_bad_host_log.patch
+	  (license #5674) patch uploaded by Walter Doekes Tested by:
+	  Michele ........ Merged revisions 343851 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343852 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-08 13:23 +0000 [r343790]  Leif Madsen <leif at leifmadsen.com>
+
+	* /, build_tools/prep_tarball: Fix boo-boo in prep_tarball script.
+	  A hardcoded a branch number was in the prep_tarball which could
+	  not work. Changed it to the variable. ........ Merged revisions
+	  343789 from http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 22:37 +0000 [r343744]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Make "sip show settings" CLI command get
+	  RPID flags from the right global page The "Trust RPID" and "Send
+	  RPID" entries in the "sip show settings" CLI command pulled the
+	  flags from the incorrect global flags page. These are now read
+	  from sip global flags page 0. (closes issue AST-711) ........
+	  Merged revisions 343743 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 21:58 +0000 [r343693]  Leif Madsen <leif at leifmadsen.com>
+
+	* configs/dundi.conf.sample, pbx/pbx_dundi.c, CHANGES: Allow built
+	  in variables to be used with dynamic weights. You can now use the
+	  built in variables , , and within a dynamic weight. For example,
+	  this could be useful when you want to pass requested lookup
+	  number to the SHELL() function which could be used to execute a
+	  script to dynamically set the weight of the result. (Closes issue
+	  ASTERISK-13657) Reported by: Joel Vandal Tested by: Leif Madsen,
+	  Russell Bryant Patches: asterisk-1.6-dundi-varhead.patch uploaded
+	  by Joel Vandal (License #5374)
+
+2011-11-07 21:44 +0000 [r343692]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, channels/chan_sip.c: respect case changes in peer names on sip
+	  reload ASTERISK-18669 ........ Merged revisions 343690 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343691 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 21:29 +0000 [r343684]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix __sip_subscribe_mwi_do() incorectly
+	  changing dialogs hash key callid. Changing an object value used
+	  as a container key requires removing the object from the
+	  container and reinserting it. * Created change_callid_pvt() to
+	  call instead of build_callid_pvt(). The change_callid_pvt() will
+	  correctly change the dialog callid so the ao2 conainter can
+	  explicitly unlink it. ........ Merged revisions 343637 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343677 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 20:35 +0000 [r343636]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Prevent BLF subscriptions from causing
+	  deadlocks Fix a locking inversion in sip_send_mwi_to_peer that
+	  was causing deadlocks. This function now requires that both the
+	  peer and associated pvt be unlocked before it is called for cases
+	  where peer and peer->mwipvt form a circular reference. (closes
+	  issue ASTERISK-18663) Review:
+	  https://reviewboard.asterisk.org/r/1563/ ........ Merged
+	  revisions 343621 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398881 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398882 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 343635 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 19:58 +0000 [r343581]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* main/udptl.c, /, UPGRADE.txt: Correct the default udptl port
+	  range. The udptl port range was defined as 4000-4999 in the
+	  udptl.conf.sample, as 4500-4599 if you didn't have a config and
+	  4500-4999 if your config was broken. Default is now 4000-4999.
+	  (closes issue ASTERISK-16250) Reviewed by: Tilghman Lesher
+	  Review: https://reviewboard.asterisk.org/r/1565 ........ Merged
+	  revisions 343580 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 19:54 +0000 [r343579]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix deadlock if peer is destroyed while
+	  sending MWI notice. A dialog cannot be destroyed by the
+	  ao2_callback dialog_needdestroy because of a deadlock between the
+	  dialogs container lock and the RWLOCK of the events subscription
+	  list. * Create dialogs_to_destroy container to hold dialogs that
+	  will be destroyed. * Ensure that the event subscription callback
+	  will never happen with an invalid peer pointer by making the
+	  event callback removal the first thing in the peer destructor
+	  callback. NOTE: This particular deadlock will not happen with
+	  Asterisk 10, but some of the changes still apply. (closes issue
+	  ASTERISK-18747) Reported by: Gregory Hinton Nietsky Review:
+	  https://reviewboard.asterisk.org/r/1564/ ........ Merged
+	  revisions 343577 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343578 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-07 18:42 +0000 [r343534]  Matthew Nicholson <mnicholson at digium.com>
+
+	* main/format.c, /: list all of the codecs associated with a
+	  particular format id for CLI command "core show codec" AST-699
+	  ........ Merged revisions 343533 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-06 09:51 +0000 [r343492]  Olle Johansson <oej at edvina.net>
+
+	* main/tcptls.c, include/asterisk/tcptls.h: Formatting and doxygen
+	  improvements
+
+2011-11-04 19:50 +0000 [r343448]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooGkClient.c, addons/ooh323c/src/ooTimer.c,
+	  addons/ooh323c/src/dlist.c, /, addons/ooh323c/src/dlist.h,
+	  addons/ooh323c/src/printHandler.c, addons/ooh323c/src/ooq931.c:
+	  Final fix memleaks in GkClient codes, same for Timer codes.
+	  (these memleaks stop development of gk codes, now i can continue)
+	  Fix printHandler 'Unbalanced Structure' issues with locking
+	  printHandler data for single thread. ........ Merged revisions
+	  343281 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 343445 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-03 20:37 +0000 [r343394]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, res/res_config_sqlite.c: Fix sqlite config driver segfault and
+	  broken queries The sqlite realtime handler assumed you had a
+	  static config configured as well. The realtime multientry handler
+	  assumed that you weren't using dynamic realtime. (closes issue
+	  ASTERISK-18354) (closes issue ASTERISK-18355) Review:
+	  https://reviewboard.asterisk.org/r/1561 ........ Merged revisions
+	  343375 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 343393 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-03 19:57 +0000 [r343338]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_dialgroup.c: Remove invalid flag given to iterator
+	  in func_dialgroup.c ........ Merged revisions 343336 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343337 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-11 20:03 +0000 [r398838]  Jonathan Rose <jrose at digium.com>
+2011-11-03 15:40 +0000 [r343222-343278]  Terry Wilson <twilson at digium.com>
 
-	* /, channels/chan_sip.c, channels/sip/include/sip.h: chan_sip:
-	  Reject calls without prior SDP on 200 OK If we receive a 200 OK
-	  without SDP, we will now check to see if the remote address has
-	  been established for that channel's RTP session and if the to tag
-	  for that channel has changed from the most recent to tag in a
-	  response less than 200. If either a change has been made since
-	  the last to-tag was received or the remote address is unset, then
-	  we will drop the call. (closes issue ASTERISK-22424) Reported by:
-	  Jonathan Rose Review:
-	  https://reviewboard.asterisk.org/r/2827/diff/#index_header
-	  ........ Merged revisions 398835 from
+	* /, channels/sip/include/sip.h: Make room for the fax detect flags
+	  The original REGISTERTRYING flag, in addition to being impossible
+	  to check, also encroached on the space for the flag above it.
+	  This patch moves the flags that were below REGISTERTRYING back to
+	  where they were as though we had just removed the REGISTERTRYING
+	  option. ........ Merged revisions 343276 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343277 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* contrib/realtime/mysql/sippeers.sql, /, channels/chan_sip.c,
+	  channels/sip/include/sip.h: Remove registertrying option in
+	  chan_sip This option is not only useless, but has been broken
+	  since inception since the flag was never copied from the peer
+	  where it is set to the pvt where it was checked. RFC 3261
+	  specificially states that you should not send a provisional
+	  response to a non-INVITE request, and if we did fix the code so
+	  that it worked, it would cause the same kind of user enumeration
+	  vulnerability that we've discussed with the nat= setting. This
+	  patch removes registertrying option and any code that would have
+	  sent a 100 response to a register. Review:
+	  https://reviewboard.asterisk.org/r/1562/ ........ Merged
+	  revisions 343220 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343221 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-02 22:46 +0000 [r343163-343219]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c: Fix improper warning introduced by
+	  r342927 and more tweaks Changeset r342927 introduced a warning
+	  which was only supposed to be emitted when a found realtime peer
+	  had an empty (or no) name. It turned out that there were some
+	  inconsistencies left. Now found peers with an empty name are
+	  explicitly ignored like before r342927 but better. Reviewed by:
+	  Stefan Schmidts, Terry Wilson Review:
+	  https://reviewboard.asterisk.org/r/1560 ........ Merged revisions
+	  343181 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 343192 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* include/asterisk/utils.h, /, main/utils.c,
+	  include/asterisk/stringfields.h: Ensure that string field lengths
+	  are properly aligned Integers should always be aligned. For some
+	  platforms (ARM, SPARC) this is more important than for others.
+	  This changeset ensures that the string field string lengths are
+	  aligned on *all* platforms, not just on the SPARC for which there
+	  was a workaround. It also fixes that the length integer can be
+	  resized to 32 bits without problems if needed. (closes issue
+	  ASTERISK-17310) Reported by: radael, S Adrian Reviewed by:
+	  Tzafrir Cohen, Terry Wilson Tested by: S Adrian Review:
+	  https://reviewboard.asterisk.org/r/1549 ........ Merged revisions
+	  343157 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 343158 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-02 19:33 +0000 [r343049-343104]  Leif Madsen <leif at leifmadsen.com>
+
+	* apps/app_authenticate.c: Add note about how Authenticate()
+	  application with option 'd' works. (closes issue ASTERISK-17422)
+	  Reported by: Leif Madsen ........ Merged revisions 343102 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 343103 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* configs/queues.conf.sample: Update documentation for leastrecent
+	  strategy. In queues.conf.sample the leastrecent strategy was
+	  incorrectly described. Now updated to reflect how the strategy
+	  actually checks peers. (closes issue ASTERISK-17854) Reported by:
+	  Sebastian Denz Patches: queues.conf-doc_issue.patch (License
+	  #6139) ........ Merged revisions 343047 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398836 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398837 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 343048 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-02 13:46 +0000 [r342992]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, apps/app_meetme.c: Modify comments in MeetMe application
+	  documentation about DAHDI. The MeetMe application documentation
+	  has some comments about usage of DAHDI, and they were a bit
+	  outdated relative to modern DAHDI releases. This patch changes
+	  the comment to just tell the user that a functional DAHDI timing
+	  source is required, and no longer mention 'dahdi_dummy', since
+	  that module does not exist in current DAHDI releases. ........
+	  Merged revisions 342990 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342991 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-11-01 21:02 +0000 [r342871-342930]  Walter Doekes <walter+asterisk at wjd.nu>
+
+	* /, channels/chan_sip.c, configs/extconfig.conf.sample,
+	  include/asterisk/config.h, main/config.c: Several fixes to the
+	  chan_sip dynamic realtime peer/user lookup There were several
+	  problems with the dynamic realtime peer/user lookup code. The
+	  lookup logic had become rather hard to read due to lots of
+	  incremental changes to the realtime_peer function. And, during
+	  the addition of the sipregs functionality, several possibilities
+	  for memory leaks had been introduced. The insecure=port matching
+	  has always been broken for anyone using the sipregs family. And,
+	  related, the broken implementation forced those using sipregs to
+	  *still* have an ipaddr column on their sippeers table. Thanks
+	  Terry Wilson for comprehensive testing and finding and fixing
+	  unexpected behaviour from the multientry realtime call which
+	  caused the realtime_peer to have a completely unused code path.
+	  This changeset fixes the leaks, the lookup inconsistenties and
+	  that you won't need an ipaddr column on your sippeers table
+	  anymore (when you're using sipregs). Beware that when you're
+	  using sipregs, peers with insecure=port will now start matching!
+	  (closes issue ASTERISK-17792) (closes issue ASTERISK-18356)
+	  Reported by: marcelloceschia, Walter Doekes Reviewed by: Terry
+	  Wilson Review: https://reviewboard.asterisk.org/r/1395 ........
+	  Merged revisions 342927 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342929 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* contrib/realtime/mysql/sippeers.sql (added),
+	  configs/res_config_mysql.conf.sample, /,
+	  configs/extconfig.conf.sample, configs/res_ldap.conf.sample,
+	  res/res_realtime.c, UPGRADE-1.8.txt, configs/dbsep.conf.sample,
+	  main/config.c, contrib/realtime/mysql/sipfriends.sql (removed):
+	  Cleanup references to sipusers and sipfriends dynamic realtime
+	  families Somewhere between 1.4 and 1.8 the sipusers family has
+	  become completely unused. Before that, the sipfriends family had
+	  been obsoleted in favor of separate sipusers and sippeers
+	  families. Apparently, they have been merged back again into a
+	  single family which is now called "sippeers". Reviewed by:
+	  irroot, oej, pabelanger Review:
+	  https://reviewboard.asterisk.org/r/1523 ........ Merged revisions
+	  342869 from http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ........ Merged revisions 342870 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-31 17:51 +0000 [r342825]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/format.c, /, main/format_cap.c: Misc format capability
+	  fixes. * Fixed typo in format_cap.c:joint_copy_helper() using the
+	  wrong variable. * Fix potential race between checking if an
+	  interface exists and adding it to the container in
+	  format.c:ast_format_attr_reg_interface(). * Fixed double rwlock
+	  destroy in format.c:ast_format_attr_init() error exit path. *
+	  Simplified format.c:find_interface() and
+	  format.c:has_interface(). ........ Merged revisions 342824 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-31 16:10 +0000 [r342771]  Matthew Jordan <mjordan at digium.com>
+
+	* main/pbx.c, /, channels/chan_iax2.c: Fixed invalid memory access
+	  when adding extension to pattern match tree When an extension is
+	  removed from a context, its entry in the pattern match tree is
+	  not deleted. Instead, the extension is marked as deleted. When an
+	  extension is removed and re-added, if that extension is also a
+	  prefix of another extension, several log messages would report an
+	  error and did not check whether or not the extension was deleted
+	  before accessing the memory. Additionally, if the extension was
+	  already in the tree but previously deleted, and the pattern was
+	  at the end of a match, the findonly flag was not honored and the
+	  extension would be erroneously undeleted. Additionaly, it was
+	  discovered that an IAX2 peer could be unregistered via the CLI,
+	  while at the same time it could be scheduled for unregistration
+	  by Asterisk. The unregistration method now checks to see if the
+	  peer was already unregistered before continuing with an
+	  unregistration. (closes issue ASTERISK-18135) Reported by: Jaco
+	  Kroon, Henry Fernandes, Kristijan Vrban Tested by: Matt Jordan
+	  Review: https://reviewboard.asterisk.org/r/1526 ........ Merged
+	  revisions 342769 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342770 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-30 02:31 +0000 [r342716]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_calendar.c: Don't crash on empty notify channel
+	  ........ Merged revisions 342715 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-29 04:41 +0000 [r342663-342664]  Richard Mudgett <rmudgett at digium.com>
+
+	* include/asterisk/linkedlists.h: Whitespace and some better macro
+	  variable names. * Renamed AST_LIST_TRAVERSE_SAFE_BEGIN __new_prev
+	  to __list_current. * Renamed AST_LIST_MOVE_CURRENT __list_cur to
+	  __extracted.
+
+	* /, include/asterisk/linkedlists.h, tests/test_linkedlists.c: Fix
+	  AST_LIST_INSERT_BEFORE_CURRENT() updating the wrong variable.
+	  AST_LIST_INSERT_BEFORE_CURRENT() could not be used twice in an
+	  iteration or before AST_LIST_REMOVE_CURRENT() without corrupting
+	  the list. AST_LIST_INSERT_BEFORE_CURRENT() could also corrupt the
+	  list if AST_LIST_INSERT_BEFORE_CURRENT() or
+	  AST_LIST_REMOVE_CURRENT() is used on the next iteration. * Fixed
+	  cut and paste error using the wrong variable in
+	  AST_LIST_INSERT_BEFORE_CURRENT(). * Added linked list unit tests
+	  for AST_LIST_INSERT_BEFORE_CURRENT(), AST_LIST_APPEND_LIST(), and
+	  AST_LIST_INSERT_LIST_AFTER(). ........ Merged revisions 342661
+	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
+	  Merged revisions 342662 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-27 20:11 +0000 [r342606]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, main/dsp.c: tweak the v21 detector to detect an additional
+	  pattern of hits and misses ........ Merged revisions 342605 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-27 19:48 +0000 [r342557-342604]  Jonathan Rose <jrose at digium.com>
+
+	* res/res_rtp_multicast.c, /: Fix sequence number overflow over 16
+	  bits causing codec change in RTP packets. Sequence number was
+	  handled as an unsigned integer (usually 32 bits I think, more
+	  depending on the architecture) and was put into the rtp packet
+	  which is basically just a bunch of bits using an or operation.
+	  Sequence number only has 16 bits allocated to it in an RTP packet
+	  anyway, so it would add to the next field which just happened to
+	  be the codec. This makes sure the sequence number is set to be a
+	  16 bit integer regardless of architecture (hopefully) and also
+	  makes it so the incrementing of the sequence number does bitwise
+	  or at the peak of a 16 bit number so that the value will be set
+	  back to 0 when going beyond 65535 anyway. (closes issue
+	  ASTERISK-18291) Reported by: Will Schick Review:
+	  https://reviewboard.asterisk.org/r/1542/ ........ Merged
+	  revisions 342602 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342603 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, res/res_jabber.c: Cleanup reference leaks in res_jabber
+	  res_jabber.c had a number of places where astobjs would be
+	  referenced and have their reference counts bumped without having
+	  a dereference made before the object lost scope. This patch adds
+	  a number of ASTOBJ_UNREFs to resolve that. Review:
+	  https://reviewboard.asterisk.org/r/1478/ ........ Merged
+	  revisions 342545 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342546 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-11 18:03 +0000 [r398822]  Russell Bryant <russell at russellbryant.com>
+2011-10-25 22:06 +0000 [r342486-342489]  Richard Mudgett <rmudgett at digium.com>
 
-	* configs/confbridge.conf.sample, /: Fix typo in
-	  confbridge.conf.sample The denoise filter requires func_speex,
-	  not codec_speex. Fix this in the description of the denoise=yes
-	  option in confbridge.conf. ........ Merged revisions 398820 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398821 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-11 14:23 +0000 [r398808]  Kevin Harwell <kharwell at digium.com>
-
-	* res/res_pjsip_caller_id.c, channels/chan_pjsip.c, /: pjsip:
-	  reinvite for connected line updates occurs when it should not
-	  Connected line updates are now only sent out if an actual update
-	  needs to occur. This happens under the following conditions: 1.
-	  The endpoint we are sending to is trusted. 2. Either a
-	  P-Asserted-Identity or Remote Party-ID header needs to be
-	  added/sent. 3. The connected id's number and name are valid. Also
-	  added an SDP when an update is sent out. (closes issue AST-1212)
-	  Reported by: John Bigelow Review:
-	  https://reviewboard.asterisk.org/r/2831/ ........ Merged
-	  revisions 398806 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-10 18:05 +0000 [r398760]  Richard Mudgett <rmudgett at digium.com>
+	* /, main/astobj2.c: Check fopen return value for ao2 reference
+	  debug output. Reported by: wdoekes Patched by: wdoekes Review:
+	  https://reviewboard.asterisk.org/r/1539/ ........ Merged
+	  revisions 342487 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342488 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, channels/sig_pri.c: Change D-channel warning to be less
+	  confusing on non-NFAS setups. The "No D-channels available! Using
+	  Primary channel as D-channel anyway!" WARNING message has been
+	  confusing on non-NFAS setups. The message refers to things that
+	  are NFAS specific. * Changed the warning to several different
+	  warnings to be more accurate for the situation and less confusing
+	  as a result: "No D-channels up! Switching selected D-channel from
+	  X to Y.", "No D-channels up!", and "D-channel is down!". ........
+	  Merged revisions 342484 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342485 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/event.c, res/res_musiconhold.c, main/indications.c,
-	  main/asterisk.c, main/xmldoc.c, main/cli.c, /,
-	  funcs/func_dialgroup.c, main/heap.c,
-	  res/res_pjsip/pjsip_configuration.c: Fix incorrect usages of
-	  ast_realloc(). There are several locations in the code base where
-	  this is done: buf = ast_realloc(buf, new_size); This is going to
-	  leak the original buf contents if the realloc fails. Review:
-	  https://reviewboard.asterisk.org/r/2832/ ........ Merged
-	  revisions 398757 from
+2011-10-25 21:11 +0000 [r342382-342437]  Terry Wilson <twilson at digium.com>
+
+	* /, apps/app_queue.c: Use int for storing ao2_container_count
+	  instad of size_t AST-676 ........ Merged revisions 342435 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342436 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Simplify queue membercount code Despite an
+	  ominous sounding comment stating that membercount was for "logged
+	  in" members only and thus we couldn't use ao2_container_count(),
+	  I could not find a single place in the code where that seemed to
+	  be accurate. The only time we decremented membercount was when we
+	  were marking something dead or actually removing it. The only
+	  places we incremented it were either after ao2_link(), or trying
+	  to correct for having set it to 0 during a reload. In every case
+	  where we were correcting the value, it seemed that we were trying
+	  to make the count actually match what ao2_container_count() would
+	  return. The only place I could find where we made a determination
+	  about something being "logged in" or not, we didn't trust the
+	  membercount, but instead looked at devicestate, paused, etc. This
+	  patch removes membercount, replaces its use with
+	  ao2_container_count, and manually adds the results of
+	  ao2_container_count to a "membercount" field for ast_data queue
+	  query results. This patch also would fix AST-676, but as it is
+	  slightly riskier than the previously committed fix, the two
+	  commits have been made separately. Reivew:
+	  https://reviewboard.asterisk.org/r/1541/ ........ Merged
+	  revisions 342383 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342384 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_queue.c: Properly update membercount for reloaded
+	  members Since q->membercount is set to 0 before reloading, it is
+	  important to increment it again for reloaded members as well as
+	  added. (closes issue AST-676) Review:
+	  https://reviewboard.asterisk.org/r/1541/ ........ Merged
+	  revisions 342380 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398758 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398759 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 342381 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-10 17:50 +0000 [r398751-398755]  David M. Lee <dlee at digium.com>
+2011-10-25 19:09 +0000 [r342278-342330]  Kinsey Moore <kmoore at digium.com>
 
-	* utils/check_expr.c, /: Fixed utils directory breakage from
-	  r398748, this time with extra hate. ........ Merged revisions
-	  398752 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 398753 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398754 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* pbx/pbx_spool.c, /: Fix compilation on Snow Leopard/FreeBSD for
+	  pbx_spool.c One of the changes in the recent spool handling of
+	  hardlinks patch was just outside a HAVE_INOTIFY block and caused
+	  compilation to fail in some build environments. This has been
+	  corrected. ........ Merged revisions 342328 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342329 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* pbx/pbx_spool.c, /: Merged revisions 342277 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r342277 | kmoore | 2011-10-25 11:08:04 -0500
+	  (Tue, 25 Oct 2011) | 25 lines Merged revisions 342276 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r342276 | kmoore | 2011-10-25 11:06:57 -0500 (Tue, 25 Oct 2011) |
+	  18 lines Fix spool handling to allow call files to be hardlinked
+	  into place This fixes the inotify code to handle call files being
+	  hardlinked into the spool directory. The smsq utility does this,
+	  instead of rename(), to ensure that it cannot accidentally
+	  overwrite an existing spool file. A rename() might do that, but
+	  link() will definitely not. The inotify code had broken this,
+	  because it would wait for an IN_CLOSE_WRITE event on the file...
+	  which was never forthcoming, since it was never opened. Now we
+	  look for IN_OPEN events following the IN_CREATE event, and only
+	  wait for an IN_CLOSE_WRITE if the file was actually opened.
+	  Patch-by: dwmw2 (closes issue ASTERISK-18331) Review:
+	  https://reviewboard.asterisk.org/r/1391/ ........
+	  ................
+
+2011-10-25 01:29 +0000 [r342225]  Terry Wilson <twilson at digium.com>
+
+	* /, include/asterisk/config.h, main/config.c: Return NULL when no
+	  results returned for realtime_multientry It was not documented
+	  what the return value should be when no entries were returned
+	  with the multientry realtime callback. This change forces
+	  consistent behavior even if the backends return an empty
+	  ast_config. Review: https://reviewboard.asterisk.org/r/1521/
+	  ........ Merged revisions 342223 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 342224 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* utils/check_expr.c, /, utils/ael_main.c, utils/conf2ael.c: Fixed
-	  utils directory breakage from r398648 ........ Merged revisions
-	  398748 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 398749 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398750 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-24 22:37 +0000 [r342184]  Richard Mudgett <rmudgett at digium.com>
 
-2013-09-09 23:29 +0000 [r398732]  Richard Mudgett <rmudgett at digium.com>
+	* /, include/asterisk/astobj2.h: Fix ao2obj.h comment typos and add
+	  missing link/unlink nolock debug defines. ........ Merged
+	  revisions 342183 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* main/astmm.c, /: MALLOC_DEBUG: Change fence magic number to be
-	  completely different from the freed magic number. Race conditions
-	  between freeing a nul terminated string and ast_strdup()'ing it
-	  are more likely to be detected if the fence and freed magic
-	  numbers are completely different. ........ Merged revisions
-	  398703 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 398721 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398726 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-24 22:09 +0000 [r342148]  Jonathan Rose <jrose at digium.com>
 
-2013-09-09 22:00 +0000 [r398695]  Mark Michelson <mmichelson at digium.com>
+	* main/features.c: Fixes a segfault caused by referencing null
+	  frames introduced in r338623
 
-	* res/res_pjsip_endpoint_identifier_ip.c, /: Add extra debugging to
-	  res_pjsip_endpoint_identifier_ip ........ Merged revisions 398694
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-24 21:01 +0000 [r342112]  Richard Mudgett <rmudgett at digium.com>
 
-2013-09-09 20:13 +0000 [r398641-398652]  David M. Lee <dlee at digium.com>
+	* apps/app_queue.c: Fix use of OBJ_KEY in Queue application. To use
+	  the new OBJ_KEY flag, the container hash and compare callback
+	  functions must be updated to support OBJ_KEY. Otherwise, bad
+	  things happen. (issue ASTERISK-14769)
 
-	* /, main/utils.c, include/asterisk/lock.h, main/lock.c: Fix
-	  DEBUG_THREADS when lock is acquired in __constructor__ This patch
-	  fixes some long-standing bugs in debug threads that were
-	  exacerbated with recent Optional API work in Asterisk 12. With
-	  debug threads enabled, on some systems, there's a lock ordering
-	  problem between our mutex and glibc's mutex protecting its module
-	  list (Ubuntu Lucid, glibc 2.11.1 in this instance). In one
-	  thread, the module list will be locked before acquiring our
-	  mutex. In another thread, our mutex will be locked before locking
-	  the module list (which happens in the depths of calling
-	  backtrace()). This patch fixes this issue by moving backtrace()
-	  calls outside of critical sections that have the mutex acquired.
-	  The bigger change was to reentrancy tracking for
-	  ast_cond_{timed,}wait, which wrongly assumed that waiting on the
-	  mutex was equivalent to a single unlock (it actually suspends all
-	  recursive locks on the mutex). (closes issue ASTERISK-22455)
-	  Review: https://reviewboard.asterisk.org/r/2824/ ........ Merged
-	  revisions 398648 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398649 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398651 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/ari/resource_channels.h, /, rest-api/api-docs/channels.json:
-	  Multiple revisions 398638-398639 ........ r398638 | dlee |
-	  2013-09-09 14:01:54 -0500 (Mon, 09 Sep 2013) | 1 line Added note
-	  about expected behavior of originate ........ r398639 | dlee |
-	  2013-09-09 14:02:27 -0500 (Mon, 09 Sep 2013) | 1 line Added note
-	  about expected behavior of originate (the rest of the commit)
-	  ........ Merged revisions 398638-398639 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-08 23:30 +0000 [r398629]  Matthew Jordan <mjordan at digium.com>
-
-	* tests/test_cdr.c, /: Update CDR Unit tests to reflect container
-	  changes in r398579 When a channel joins a multi-party bridge, the
-	  ordering of the CDRs that is created is determined by the
-	  ordering of the channels who happen to be in that bridge. When
-	  r398579 changed the number of buckets in the container to
-	  something sensible, it changed the ordering that the CDRs was
-	  created in, causing one of the multiparty tests to fail. This
-	  fixes the test with the now expected ordering. ........ Merged
-	  revisions 398628 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-07 01:03 +0000 [r398603-398620]  Kinsey Moore <kmoore at digium.com>
-
-	* /, res/res_xmpp.c: Prevent XMPP timeout on blank responses
-	  Sometimes the Google Voice servers have a bad habit of sending
-	  out 1 byte replies to the xmpp resource. When a blank 1 byte
-	  reply is received from the socket the buffer attempts to wait
-	  (endlessly) for the rest of the reply from google which
-	  effectively blocks the socket and google voice calls will no
-	  longer come into the server. This patch allows the xmpp module to
-	  correctly detect empty packets and send out ping replies to
-	  google. It also sets a socket timeout on the default socket which
-	  prevents the xmpp socket from closing and preventing future
-	  google voice calls from coming into the server. Furthermore
-	  instead of sending an empty reply back to google we send a proper
-	  xmpp ping reply back. This also adds several more socket
-	  messages. (closes issue ASTERISK-22347) Reported by: Andrew Nagy
-	  Review: https://reviewboard.asterisk.org/r/2771 Patches:
-	  xmpp_fix_1.diff uploaded by Andrew Nagy (License #6524) ........
-	  Merged revisions 398618 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398619 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_xmpp.c, res/res_jabber.c: Multiple revisions
-	  398558,398577 ........ r398558 | kmoore | 2013-09-06 14:28:16
-	  -0500 (Fri, 06 Sep 2013) | 17 lines Fix Jabber/XMPP distributed
-	  MWI The mailbox and context are swapped on the receiving end for
-	  all users of Jabber and XMPP distributed MWI in Asterisk 1.8 and
-	  all more recent versions. This swaps those values to be correct
-	  when publishing to the internal event system from Jabber/XMPP
-	  distributed MWI state. (closes issue ASTERISK-22435) Reported by:
-	  abelbeck Tested by: Michael Keuter Patches:
-	  asterisk-1.8-res_jabber-aji_handle_pubsub_event.patch uploaded by
-	  abelbeck asterisk-11-res_xmpp-xmpp_pubsub_handle_event.patch
-	  uploaded by abelbeck ........ Merged revisions 398523 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  r398577 | kmoore | 2013-09-06 16:00:56 -0500 (Fri, 06 Sep 2013) |
-	  10 lines Commit the remainder of r398523 This is a missing part
-	  of the commit in revision 398523 that corrects the name of a
-	  variable. (issue ASTERISK-22435) ........ Merged revisions 398576
+2011-10-24 20:01 +0000 [r342063]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Outbound SIP OPTIONS messages will now
+	  include fromuser of related peer. This behavior matches up more
+	  closely with the way invite/register/etc are handled. This patch
+	  also modifies some adjacent code for code style compliance.
+	  Pretty minor. (closes issue ASTERISK-17616) Reported by: Jeremy
+	  Kister Patches: chan_sip.c-options-fromuser-fix-v1.patch uploaded
+	  by Jeremy Kister (license #6232) ........ Merged revisions 342061
 	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 398558,398577 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398580 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-06 21:17 +0000 [r398557-398583]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/cdr.c, /: cdr: Change the number of container buckets to be
-	  similar to the channels container. * Fix the temporary cdr
-	  candidate containers to use a prime number of buckets. ........
-	  Merged revisions 398579 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/core_local.c, /: core_local: Fix LocalOptimizationBegin AMI
-	  event missing Source channel snapshot. * Fix the
-	  LocalOptimizationBegin AMI event by eliminating an artificial
-	  buffer size limitation that is too small anyway. ........ Merged
-	  revisions 398572 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: cdr: Fix some ref leaks. * Added missing
-	  unregister of the cdr container in cdr_engine_shutdown(). * Fixed
-	  ref leak in off nominal path of cdr_object_alloc(). * Removed
-	  some unnecessary NULL checks in cdr_object_dtor(). ........
-	  Merged revisions 398562 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/astobj2.h, main/cel.c, main/features_config.c,
-	  apps/app_agent_pool.c, main/cdr.c, main/udptl.c, /,
-	  main/parking.c, main/stasis_config.c: astobj2: Add warn unused
-	  attribute to some functions. * Fixed resulting warnings with
-	  improper use of ao2_global_obj_replace(). * Made a couple uses of
-	  ao2_global_obj_replace_unref(x, NULL) into the equivalent and
-	  more appropriate ao2_global_obj_release() call. ........ Merged
-	  revisions 398533 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-09-06 18:53 +0000 [r398512-398522]  Kinsey Moore <kmoore at digium.com>
-
-	* main/http.c, /, res/stasis/app.c: Fix build warnings When
-	  AST_DEVMODE is not defined, ast_asserts are not compiled into the
-	  binary. In some cases, this means variables are not referenced or
-	  are set but unused which causes warnings to show up. (closes
-	  issue ASTERISK-22446) Reported by: Jason Parker (qwell) ........
-	  Merged revisions 398521 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, channels/chan_h323.c: Fix chan_h323 compilation This fixes the
-	  things in chan_h323 that were missed or ignored in the great
-	  channel opaquification and gets chan_h323 back into a compiling
-	  state. (closes issue ASTERISK-22365) Reported by: Dmitry Melekhov
-	  Patches: chan_h323.patch uploaded by Dmitry Melekhov ........
-	  Merged revisions 398510 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398511 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  Merged revisions 342062 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-05 21:48 +0000 [r398384-398499]  Richard Mudgett <rmudgett at digium.com>
+2011-10-24 07:40 +0000 [r341923-342018]  Gregory Nietsky <gregory at distrotech.co.za>
 
-	* /, main/astobj2.c: astobj2: Only define ao2_bt() once. * Make
-	  ao2_bt() not use single char variable names. * Fix ao2_bt()
-	  formatting. ........ Merged revisions 398498 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /, apps/app_queue.c: queues container needs locking when using
+	  the OBJ_NOLOCK flag ........ Merged revisions 342017 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_iax2.c, /: chan_iax2: Reduce indentation in
-	  __attempt_transmit(). * Reduce indentation in
-	  __attempt_transmit(). * Don't update the static last error time
-	  variable every time in __schedule_action() and socket_read().
-	  ........ Merged revisions 398456 from
+	* /, apps/app_queue.c: Remove some ref leaks and a return without
+	  unlock. There some resource leaks introduced in asterisk 10 make
+	  sure that locks are not held on return and we release ref's held.
+	  ........ Merged revisions 341972 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* apps/app_queue.c: Whitespace Fixups / Add Braces This janitorial
+	  patch is related to work on RB1538
+
+2011-10-22 12:03 +0000 [r341869]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/chan_ooh323.c, /: Merged revisions 341313 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r341313 | may | 2011-10-19 03:33:49 +0400 (Wed,
+	  19 Oct 2011) | 10 lines Merged revisions 341312 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r341312 | may | 2011-10-19 03:20:53 +0400 (Wed, 19 Oct 2011) | 3
+	  lines fix issue on channel numbering (calls could have same
+	  channel number on heavy loaded system) ........ ................
+
+2011-10-21 16:42 +0000 [r341808-341811]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, pbx/pbx_lua.c: only process args that exist ASTERISK-18395
+	  ........ Merged revisions 341809 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398457 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398458 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 341810 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_iax2.c, /: chan_iax2: Fix stray reference to worker
-	  thread idle_list. * Fix stray reference to idle_list in
-	  cleanup_thread_list(). This may be the reason for the note in
-	  iax2_process_thread() about threads not being removed from the
-	  task lists. * Move cleanup_thread_list(&idle_list) to after the
-	  other lists are cleaned up. ........ Merged revisions 398416 from
+	* /, pbx/pbx_lua.c: don't limit the length of app and function
+	  arguments ASTERISK-18395 ........ Merged revisions 341806 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398417 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398418 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 341807 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-21 09:16 +0000 [r341769]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* res/res_fax.c: White space fixes in res_fax
+
+2011-10-20 22:03 +0000 [r341719]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c, res/res_agi.c, include/asterisk/features.h:
+	  Fix AGI exec Park to honor the Park application parameters. The
+	  fix for ASTERISK-12715 and ASTERISK-12685 added a check for the
+	  Park application because the channel needed to be masqueraded to
+	  prevent a crash. Since the Park application now always
+	  masquerades the channel into the parking lot, the special check
+	  is no longer needed. The fix also resulted in AGI exec Park
+	  attempting to double park the call and not honor the Park
+	  application parameters. * Removed no longer necessary call to
+	  ast_masq_park_call() by AGI exec for the Park application.
+	  (Reverts -r146923) * Fix Park application to only return 0 or -1.
+	  The AGI exec Park was causing broken pipe error messages because
+	  the Park application returned 1 on successful park. (closes issue
+	  ASTERISK-18737) ........ Merged revisions 341717 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341718 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_iax2.c, /: chan_iax2: Fix bridgecallno deadlock
-	  avoidance. * Fix bridgecallno deadlock avoidance. When doing
-	  deadlock avoidance, you need to retest the status of values for
-	  each loop to see if you still need the lock for bridgecallno. *
-	  As a safety check, after acquiring the bridgecallno lock you
-	  should check if iaxs[bridgecallno] is NULL just like the current
-	  callno checks. * Move setting thread->iostate to IAX_IOSTATE_IDLE
-	  to after processing any deferred frames to ensure that the
-	  iostate is IDLE when it is placed back into the idle list.
-	  defer_full_frame() tries to ensure iax2_process_thread() wakes up
-	  to process the frame. ........ Merged revisions 398379 from
+2011-10-20 21:28 +0000 [r341666-341713]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, funcs/func_callerid.c: Fixed typo from previous commit
+	  ........ Merged revisions 341704 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398380 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398381 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 341707 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-05 14:10 +0000 [r398369]  Mark Michelson <mmichelson at digium.com>
+	* /, funcs/func_callerid.c: Updated documentation for the optional
+	  CID parameter with CALLERID ........ Merged revisions 341664 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341665 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-20 18:27 +0000 [r341583-341624]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, configs/queues.conf.sample: Merged revisions 341599 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r341599 | irroot | 2011-10-20 20:20:08 +0200 (Thu, 20
+	  Oct 2011) | 8 lines add documentation for check_state_unknown in
+	  configs/queues.conf.sample app_queue allows calls to members in a
+	  "Unknown" state to be treated as available setting
+	  check_state_unknown = yes will cause app_queue to query the
+	  channel driver to better determine the state this only applies to
+	  queues with ringinuse or ignorebusy set appropriately. ........
+
+	* /, CHANGES, apps/app_queue.c: Merged revisions 341580 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r341580 | irroot | 2011-10-20 19:13:23 +0200 (Thu, 20
+	  Oct 2011) | 15 lines Add option to check state when state is
+	  unknown r341486 reverts r325483 this is a rework of the patch.
+	  optimize to minimize load. add option check_state_unknown to
+	  control whether a member with unknown device state is checked
+	  there is a small % chance that calls will be sent to the member
+	  when they on a call. app_queue will see a device with unknown
+	  state as available and does not try verify the state without this
+	  option enabled. Review: https://reviewboard.asterisk.org/r/1535/
+	  ........
+
+2011-10-20 15:17 +0000 [r341533]  Terry Wilson <twilson at digium.com>
+
+	* /, include/asterisk/strings.h: Clean up ast_check_digits The code
+	  was originally copied from the is_int() function in the AEL code.
+	  wdoekes pointed out that the function should take a const char*
+	  and that their was an unneeded variable. This is now fixed.
+	  ........ Merged revisions 341529 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341530 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-19 21:24 +0000 [r341487]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, apps/app_queue.c: Merged revisions 341486 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r341486 | mnicholson | 2011-10-19 16:23:17 -0500 (Wed, 19 Oct
+	  2011) | 18 lines Fix a performance regression introduced in
+	  r325483. The regression was caused by a call to
+	  ast_parse_device_state() in app_queue's ring_entry() function.
+	  The ast_parse_device_state() function eventually calls
+	  ast_channel_get_full() with a channel name prefix which causes it
+	  to walk the channel list causing massive lock contention and slow
+	  downs. This patch fixes the regression by removing the call to
+	  ast_parase_device_state() which should be unnecessary. Queue
+	  member device state should be maintained by device state events.
+	  Some users have seen instances where busy agents were called when
+	  they shouldn't have, which is the reason the call to
+	  ast_parse_device_state() was added. That change appears to have
+	  resolved that issue but also causes this performance regression.
+	  There may still be issues with queue member status, and if so,
+	  alternative methods should be investigated to resolve them.
+	  AST-695 ........
+
+2011-10-19 19:02 +0000 [r341437]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, channels/chan_gtalk.c: Outgoing calls with Google Voice Google
+	  has recently make some changes (again) to their protocol. Rather
+	  then patching asterisk to flip between the two different methods,
+	  we now allow both. Lets hope this keeps Google Voice happy for a
+	  while. (closes issue ASTERISK-18714) Reported by: Iordan Iordanov
+	  Patches: chan_gtalk.patch uploaded by Iordan Iordanov (licenses
+	  6311) ........ Merged revisions 341435 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341436 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, res/res_pjsip_outbound_registration.c: Clarify server_uri and
-	  client_uri registration settings. Used some of Rusty's suggested
-	  language plus also included more SIPesque descriptions of where
-	  the URIs are actually used in an outgoing REGISTER. (closes issue
-	  ASTERISK-22390) reported by Rusty Newton ........ Merged
-	  revisions 398368 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-19 07:45 +0000 [r341381]  Terry Wilson <twilson at digium.com>
 
-2013-09-04 23:07 +0000 [r398304]  Richard Mudgett <rmudgett at digium.com>
+	* /, channels/chan_sip.c, include/asterisk/strings.h: Don't use
+	  is_int() since it doesn't link well on all platforms Just create
+	  an normal API function in strings.h that does the same thing just
+	  to be safe. ASTERISK-17146 ........ Merged revisions 341379 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341380 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/iax2/parser.c, /: chan_iax2: Add missing control frame
-	  names to debug frame decode output. ........ Merged revisions
-	  398301 from http://svn.asterisk.org/svn/asterisk/branches/1.8
-	  ........ Merged revisions 398302 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398303 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-19 07:27 +0000 [r341378]  Stefan Schmidt <sst at sil.at>
 
-2013-09-04 22:49 +0000 [r398300]  Mark Michelson <mmichelson at digium.com>
+	* /, channels/chan_sip.c: Don't sent in-dialog requests like UPDATE
+	  when Asterisk has not yet received a Contact URI from a UAS
+	  ........ Merged revisions 341366 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341377 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-18 23:45 +0000 [r341316]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Don't resolve numeric hosts or contact
+	  unresolved hosts If a SIP dial string contains a numeric hostname
+	  that is not a peer name, don't try to resolve it as it is
+	  unlikely that someone really means Dial(SIP/0.0.4.26) when
+	  Dial(SIP/1050) is called. Also, make sure that create_addr
+	  returns -1 if an address isn't resolved so that we don't attempt
+	  to send SIP requests to an address that doesn't resolve. (closes
+	  issue ASTERISK-17146, ASTERISK-17716) Review:
+	  https://reviewboard.asterisk.org/r/1532/ ........ Merged
+	  revisions 341314 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341315 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, res/res_pjsip_outbound_authenticator_digest.c: Give more
-	  detail regarding failures to create request with auth
-	  credentials. (issue ASTERISK-22386) ........ Merged revisions
-	  398299 from http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-18 21:15 +0000 [r341256]  Richard Mudgett <rmudgett at digium.com>
 
-2013-09-04 21:37 +0000 [r398284-398287]  Jonathan Rose <jrose at digium.com>
+	* channels/chan_dahdi.c, channels/sig_analog.c, /,
+	  channels/chan_sip.c, main/features.c, channels/chan_iax2.c,
+	  channels/sip/include/sip.h, channels/chan_mgcp.c,
+	  include/asterisk/features.h: More parking issues. * Fix potential
+	  deadlocks in SIP and IAX blind transfer to parking. * Fix SIP,
+	  IAX, DAHDI analog, and MGCP channel drivers to respect the
+	  parkext_exclusive option with transfers (Park(,,,,,exclusive_lot)
+	  parameter). Created ast_park_call_exten() and
+	  ast_masq_park_call_exten() to maintian API compatibility. * Made
+	  masq_park_call() handle a failed ast_channel_masquerade() setup.
+	  * Reduced excessive struct parkeduser.peername[] size. ........
+	  Merged revisions 341254 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341255 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-17 17:58 +0000 [r341198]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* /, pbx/pbx_realtime.c: Remove an unused include of md5.h Unused
+	  include of asterisk/md5.h in pbx_realtime.c . A commit needed to
+	  test the commit message. Merged-From:
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8@341074
+	  Merged-From:
+	  http://svn.asterisk.org/svn/asterisk/branches/10@341148
+
+2011-10-17 17:38 +0000 [r341191]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Initialize variables before calling
+	  parse_uri If parse_uri was called with an empty URI, some
+	  pointers would be modified and an invalid read could result. This
+	  patch avoids calling parse_uri with an empty contact uri when
+	  parsing REGISTER requests. AST-2011-012 (closes issue
+	  ASTERISK-18668) ........ Merged revisions 341189 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341190 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, tests/test_voicemail_api.c: unit tests: test_voicemail_api
-	  leaks stringfields from snapshots (closes issue ASTERISK-22414)
-	  Reported by: Corey Farrell Patches:
-	  test_voicemail_api-leaks-11.patch uploaded by coreyfarrell
-	  (license 5909) ........ Merged revisions 398285 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398286 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* apps/app_voicemail.c, /: app_voicemail: Fix leaking config
-	  objects when msg_id doesn't match (issues ASTERISK-22414)
-	  Reported by: Corey Farrell Patch:
-	  test_voicemail_api-leaks-11.patch uploaded by coreyfarrell
-	  (license 5909) ........ Merged revisions 398281 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398283 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-17 16:39 +0000 [r341126-341147]  Paul Belanger <paul.belanger at polybeacon.com>
 
-2013-09-04 16:03 +0000 [r398238]  Richard Mudgett <rmudgett at digium.com>
+	* /, tests/test_format_api.c: Set 'core' support level for
+	  test_format_api.c ........ Merged revisions 341146 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* channels/chan_misdn.c, /: chan_misdn: Fix misdn debug output
-	  printed with arbitrary verbose levels. Fix the misdn debug output
-	  to remote consoles. chan_misdn uses ast_console_puts() which
-	  doesn't know about verbose levels. Better to use ast_verbose()
-	  instead. Without this patch the misdn debug messages are appended
-	  to the verbose level which ever was set by the message sent to
-	  the console before, i.e. any undefined level. (closes issue
-	  AST-1218) Reported by: Guenther Kelleter Patches: misdnlog.patch
-	  (license #6372) patch uploaded by Guenther Kelleter ........
-	  Merged revisions 398235 from
+	* /, apps/app_voicemail.c: Multiple revisions 341108,341112
+	  ........ r341108 | pabelanger | 2011-10-17 12:22:19 -0400 (Mon,
+	  17 Oct 2011) | 2 lines Voicemail compiler flags are 'core'
+	  support ........ r341112 | pabelanger | 2011-10-17 12:23:33 -0400
+	  (Mon, 17 Oct 2011) | 2 lines Fix previous commit ........ Merged
+	  revisions 341108,341112 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398236 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398237 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 341122 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-17 16:18 +0000 [r341096]  Jason Parker <jparker at digium.com>
 
-2013-09-04 14:32 +0000 [r398227]  Kevin Harwell <kharwell at digium.com>
+	* /, CHANGES: Add information about limitations of new codec
+	  support in channel drivers. (issue ASTERISK-18680) ........
+	  Merged revisions 341094 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* /, res/res_pjsip_outbound_registration.c: Debug messages for
-	  pjsip outbound registration Added debug messages indicating that
-	  an outbound registration attempt was made and it was successful
-	  in pjsip. (closes issue ASTERISK-22388) Reported by: Rusty Newton
-	  ........ Merged revisions 398226 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-17 15:45 +0000 [r341090]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Don't try to remove peers without IPs
+	  from peers_by_ip (closes issue ASTERISK-18696) ........ Merged
+	  revisions 341088 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341089 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-14 21:37 +0000 [r341024]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, build_tools/embed_modules.xml, Makefile.moddir_rules: Change
+	  the internal name of the menuselect options that are used to
+	  control whether modules are embedded or not; using just the bare
+	  category name led to accidentally enabling these options when
+	  users used the wrong "--enable" operation on the menuselect
+	  command line. Now the internal option names are prefixed with
+	  "EMBED_", so they won't be the same as the name of the category
+	  containing the modules they control the embedding of. ........
+	  Merged revisions 341022 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 341023 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-14 21:15 +0000 [r340973]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fix simple switch to not progress a call
+	  when call already progressed. If a simple switch was started on a
+	  device and then a specific call made (such as redial or speed
+	  dial), on timeout of the simple switch the call would be
+	  attempted again. This patch only allows the simple switch to make
+	  a call if the substate is still in the collecting digits mode.
+	  Also added small debug message to dialAndAactivate sub. Tested by
+	  snuff and myself.
+
+2011-10-14 20:51 +0000 [r340972]  Kinsey Moore <kmoore at digium.com>
+
+	* res/res_rtp_asterisk.c, /, channels/chan_sip.c: Merged revisions
+	  340971 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340971 | kmoore | 2011-10-14 15:50:37 -0500
+	  (Fri, 14 Oct 2011) | 15 lines Merged revisions 340970 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r340970 | kmoore | 2011-10-14 15:49:39 -0500 (Fri, 14 Oct 2011) |
+	  8 lines Quiet RTCP Receiver Reports during fax transmission RTCP
+	  is now disabled for "inactive" RTP audio streams during SIP T.38
+	  sessions. The ability to disable RTCP streams in res_rtp_asterisk
+	  was missing, so this code was added to support the bug fix.
+	  (closes issue ASTERISK-18400) ........ ................
+
+2011-10-14 18:38 +0000 [r340932]  Jonathan Rose <jrose at digium.com>
+
+	* utils/utils.xml, /, funcs/func_jitterbuffer.c: Some additional
+	  module documentation changes for 10 for the menuselect change.
+	  (issue ASTERISK-18268) ........ Merged revisions 340931 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-14 16:45 +0000 [r340880]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c, /: Avoid unnecessary WARNING message Add
+	  AST_CONTROL_UPDATE_RTP_PEER frame to be ignored here to avoid
+	  displaying a WARNING message. (closes issue ASTERISK-18610) Patch
+	  by: Kristijan_Vrban ........ Merged revisions 340878 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340879 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-13 23:08 +0000 [r340811-340813]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Fix DTMF blind transfer continuing to execute
+	  dialplan after transfer. Party A calls Party B. Party A DTMF
+	  blind transfers Party B to Party C. Party A channel continues to
+	  execute dialplan. * Fixed the return value of
+	  builtin_blindtransfer() to return the correct value after a
+	  transfer so the dialplan will not keep executing. * Removed
+	  unnecessary connected line update that did not really do
+	  anything. * Made access to GOTO_ON_BLINDXFR thread safe in
+	  check_goto_on_transfer(). * Fixed leak of xferchan for failure
+	  cases in check_goto_on_transfer(). * Updated debug messages in
+	  builtin_blindtransfer() and check_goto_on_transfer(). (closes
+	  issue ASTERISK-18275) Reported by: rmudgett Tested by: rmudgett
+	  ........ Merged revisions 340809 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340810 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-2013-09-03 20:28 +0000 [r398217]  Alexandr Anikin <may at telecom-service.ru>
+	* /: Update 10 merged property.
 
-	* /, addons/ooh323c/src/ooh245.c: Fix remote tcs sequence handling
-	  on empty tcs received ........ Merged revisions 398214 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398215 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* /: Restore branch 10 merge properties.
 
-2013-09-03 18:09 +0000 [r398207]  Kinsey Moore <kmoore at digium.com>
+2011-10-13 08:53 +0000 [r340771]  Gregory Nietsky <gregory at distrotech.co.za>
 
-	* res/res_pjsip_dtmf_info.c, /: Prevent a crash in
-	  res_pjsip_dtmf_info.c This change makes sure that a content type
-	  header exists before checking the contents of the header against
-	  known SIP INFO DTMF content types. ........ Merged revisions
-	  398206 from http://svn.asterisk.org/svn/asterisk/branches/12
+	* /: Merged revisions 339463 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339463 | irroot | 2011-10-05 08:28:46 +0200 (Wed, 05 Oct 2011) |
+	  9 lines Only change the capabilities on the gateway when the
+	  session is been destroyed there is still a race condition that
+	  ends in a segfault. if the caps are changed the logic in
+	  res_fax_spandsp will run T30 code not gateway code to end the
+	  session. this has been experienced on a "slower" under spec
+	  system. ........
 
-2013-09-03 17:19 +0000 [r398205]  David M. Lee <dlee at digium.com>
+2011-10-13 07:05 +0000 [r340720]  Stefan Schmidt <sst at sil.at>
 
-	* Makefile, /: Fixed 'make clean' for wiki docs ........ Merged
-	  revisions 398198 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	* channels/chan_sip.c: Merged revisions 340718 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340718 | schmidts | 2011-10-13 06:59:50 +0000
+	  (Thu, 13 Oct 2011) | 9 lines Merged revisions 340717 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r340717 | schmidts | 2011-10-13 06:58:00 +0000 (Thu, 13
+	  Oct 2011) | 3 lines storing the route-set also on a 181 response
+	  not only on 180,182 or 183. ........ ................
 
-2013-09-03 14:29 +0000 [r398197]  Walter Doekes <walter+asterisk at wjd.nu>
+2011-10-13 07:02 +0000 [r340665-340719]  Terry Wilson <twilson at digium.com>
 
-	* /, cel/cel_custom.c: Be a little more verbose when loading
-	  cel_custom.conf. Review: https://reviewboard.asterisk.org/r/2805/
-	  ........ Merged revisions 398167 from
+	* /, channels/chan_sip.c: Initialize ast_sockaddr before calling
+	  ast_sockaddr_resolve Avoid possible jump based on unitialized
+	  value ........ Merged revisions 340715 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398168 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398196 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 20:58 +0000 [r398150]  David M. Lee <dlee at digium.com>
-
-	* main/asterisk.c, include/asterisk/optional_api.h, /,
-	  main/optional_api.c: Fix graceful shutdown crash. The cleanup
-	  code for optional_api needs to happen after all of the optional
-	  API users and providers have unused/unprovided. Unfortunately,
-	  regsitering the atexit() handler at the beginning of main() isn't
-	  soon enough, since module destructors run after that. ........
-	  Merged revisions 398149 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 20:37 +0000 [r398148]  Rusty Newton <rnewton at digium.com>
-
-	* /, configs/pjsip.conf.sample: New pjsip.conf.sample (issue
-	  ASTERISK-22145) (closes issue ASTERISK-22145) Reported By: Matt
-	  Jordan Review: https://reviewboard.asterisk.org/r/2811/ ........
-	  Merged revisions 398147 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 19:55 +0000 [r398124-398140]  Kevin Harwell <kharwell at digium.com>
-
-	* /, res/res_pjsip_outbound_registration.c,
-	  include/asterisk/sorcery.h, res/res_pjsip.c,
-	  res/res_pjsip/config_transport.c, main/sorcery.c: Add a
-	  reloadable option for sorcery type objects Some configuration
-	  objects currently won't place nice if reloaded. Specifically, in
-	  this case the pjsip transport objects. Now when registering an
-	  object in sorcery one may specify that the object is allowed to
-	  be reloaded or not. If the object is set to not reload then upon
-	  reloading of the configuration the objects of that type will not
-	  be reloaded. The initially loaded objects of that type however
-	  will remain. While the transport objects will not longer be
-	  reloaded it is still possible for a user to configure an endpoint
-	  to an invalid transport. A couple of log messages were added to
-	  help diagnose this problem if it occurs. (closes issue
-	  ASTERISK-22382) Reported by: Rusty Newton (closes issue
-	  ASTERISK-22384) Reported by: Rusty Newton Review:
-	  https://reviewboard.asterisk.org/r/2807/ ........ Merged
-	  revisions 398139 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/config.c, res/res_security_log.c, /, channels/chan_sip.c,
-	  main/translate.c, main/named_acl.c, main/indications.c: Fix
-	  various memory leaks main/config.c - cleanup cache fie includes
-	  res/res_security_log.c - unregister logger level
-	  channesl/chan_sip.c - cleanup io context and notify_types
-	  main/translator.c - cleanup at shutdown main/named_acl.c -
-	  cleanup cli commands main/indications.c -
-	  ast_get_indication_tone() unref default_tone_zone if used (closes
-	  issues ASTERISK-22378) Reported by: Corey Farrell Patches:
-	  config_shutdown.patch uploaded by coreyfarrell (license 5909)
-	  res_security_log.patch uploaded by coreyfarrell (license 5909)
-	  chan_sip-11.patch uploaded by coreyfarrell (license 5909)
-	  indications_refleak.patch uploaded by coreyfarrell (license 5909)
-	  named_acl-cli_unreg-trunk.patch uploaded by coreyfarrell (license
-	  5909) translate_shutdown.patch uploaded by coreyfarrell (license
-	  5909) ........ Merged revisions 398102 from
+	  revisions 340716 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, res/res_config_sqlite.c: Don't skip the query field on a
+	  realtime multi query There is no documented reason to not add the
+	  query field to the varlist returned by a realtime multi query,
+	  despite the config category being set to its value. Of course,
+	  there is no documentation that the category should be set to the
+	  value either. There is lots of no documentation when it comes to
+	  realtime. But, other engines do not skip this field so I am
+	  forcing this backend to follow the convention, because not doing
+	  so is very silly. ........ Merged revisions 340662 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398103 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398116 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 18:38 +0000 [r398101]  Matthew Jordan <mjordan at digium.com>
-
-	* /, UPGRADE-12.txt (added), UPGRADE.txt: Update UPGRADE.txt file
-	  for Asterisk 12 This simply pulls in the changes that were
-	  breaking from the CHANGES file and updates a few other areas
-	  accordingly. It also removes the 10 => 11 notes, which are
-	  traditionally removed from each major version and stored in the
-	  appropriate UPGRADE-X.txt file. ........ Merged revisions 398100
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 18:30 +0000 [r398064-398099]  Jonathan Rose <jrose at digium.com>
-
-	* main/features_config.c, /, main/config_options.c:
-	  features_config: Ignore parkinglots in features.conf instead of
-	  failing to load Parkinglots are defined in res_features.conf now,
-	  but this patch fixes features_config so that features don't fail
-	  to load when parkinglots are present in features.conf Review:
-	  https://reviewboard.asterisk.org/r/2801/ ........ Merged
-	  revisions 398068 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/features_config.c, main/udptl.c, /: features_config: Don't
-	  require features.conf to be present for Asterisk to load (closes
-	  issue ASTERISK-22426) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2806/ ........ Merged
-	  revisions 398020 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 17:59 +0000 [r398063]  Kevin Harwell <kharwell at digium.com>
-
-	* main/manager.c, /, res/res_agi.c: Memory leak fix
-	  ast_xmldoc_printable returns an allocated block that must be
-	  freed by the caller. Fixed manager.c and res_agi.c to stop
-	  leaking these results. (closes issue ASTERISK-22395) Reported by:
-	  Corey Farrell Patches: manager-leaks-12.patch uploaded by
-	  coreyfarrell (license 5909) res_agi-xmldoc-leaks.patch uploaded
-	  by coreyfarrell (license 5909) ........ Merged revisions 398060
-	  from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........
-	  Merged revisions 398061 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398062 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 17:11 +0000 [r398024-398026]  Richard Mudgett <rmudgett at digium.com>
+	  revisions 340663 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-12 21:28 +0000 [r340626]  Stefan Schmidt <sst at sil.at>
+
+	* channels/chan_sip.c: Merged revisions 340577 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340577 | schmidts | 2011-10-12 20:33:37 +0000
+	  (Mit, 12 Okt 2011) | 9 lines Merged revisions 340576 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r340576 | schmidts | 2011-10-12 20:30:37 +0000 (Mit, 12
+	  Okt 2011) | 3 lines Store route-set from provisional SIP
+	  responses so early-dialog requests can be routed properly
+	  ........ ................
+
+2011-10-12 21:02 +0000 [r340579]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 340578 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340578 | twilson | 2011-10-12 13:57:19 -0700
+	  (Wed, 12 Oct 2011) | 16 lines Merged revisions 340534 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r340534 | twilson | 2011-10-12 13:19:36 -0700 (Wed, 12 Oct 2011)
+	  | 9 lines Update SIP realtime fullcontact regardless of caching
+	  We should update the fullcontact field in the realtime table
+	  whether or not rtcachefriends is set. There is no reason to treat
+	  a non-cached realtime entity differently than a cached in this
+	  regard. (closes issue ASTERISK-18446) Reported by: wdoekes
+	  ........ ................
+
+2011-10-12 20:09 +0000 [r340472-340524]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Initialize the PRI channel alarms
+	  properly on startup. The PRI channel alarms were initialized with
+	  an inverted sense. (closes issue ASTERISK-18710) Reported by:
+	  Tzafrir Cohen ........ Merged revisions 340522 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340523 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_meetme.c: Update MeetMe p and X option documentation
+	  when interacting with the s option. ASTERISK-12175 changed the p
+	  and X options to not interfere with the s option when they are
+	  used together. It makes more sense for the s option to have
+	  priority for the DTMF '*' key since it cannot change its
+	  activation code. Otherwise, you could not use option s with the p
+	  or X options. JIRA AST-671 ........ Merged revisions 340470 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340471 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
 
-	* tests/test_substitution.c, /: test_substitution: Fix failing
-	  test. Revert the -r392190 change. The original test was correct.
-	  The CDR code was actually returning an unititialized buffer.
-	  ........ Merged revisions 398025 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+2011-10-12 16:29 +0000 [r340420]  Paul Belanger <paul.belanger at polybeacon.com>
 
-	* tests/test_substitution.c, /: test_substituition: Fix failed test
-	  reporting to actually report failure. You cannot put the "Testing
-	  <blah> pass/fail" on a single line before actually performing the
-	  test. Now any additional failure information is logged before the
-	  test pass/fail announcement. * Added an additional CDR(answer,u)
-	  test. ........ Merged revisions 398018 from
+	* /, channels/chan_sip.c: Fix verbose messages when IPv6 logic was
+	  added (closes issue ASTERISK-18612) Reported by: Tim Osman
+	  ........ Merged revisions 340418 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340419 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-11 21:06 +0000 [r340318-340367]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, channels/sig_ss7.h, /, channels/sig_ss7.c:
+	  Add protection for SS7 channel allocation and better glare
+	  handling. * Added a CLI "ss7 show channels" command that might
+	  prove useful for future debugging. * Made the incoming SS7
+	  channel event check and gripe message uniform. * Made sure that
+	  the DNID string for an incoming call is always initialized.
+	  (issue ASTERISK-17966) Reported by: Kenneth Van Velthoven
+	  Patches: jira_asterisk_17966_v1.8_glare.patch (license #5621)
+	  patch uploaded by rmudgett ........ Merged revisions 340365 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340366 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* channels/sip/include/dialog.h, /, channels/chan_sip.c: Fix some
+	  potential deadlocks pointed out by helgrind. * Fixed deadlock
+	  potential calling dialog_unlink_all() in __sip_autodestruct().
+	  Found by helgrind. * Fixed deadlock potential in
+	  handle_request_invite() after calling sip_new(). Found by
+	  helgrind. * The sip_new() function now returns with the created
+	  channel already locked. * Removed the dead code that starts a PBX
+	  in in sip_new(). No sip_new() callers caused that code to be
+	  executed and it was a bad thing to do anyway. * Removed unused
+	  parameters and return value from dialog_unlink_all(). * Made
+	  dialog_unlink_all() and __sip_autodestruct() safely obtain the
+	  owner and private channel locks without a deadlock avoidance
+	  loop. ........ Merged revisions 340284 from
 	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 398019 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398023 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  revisions 340310 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-11 19:06 +0000 [r340283]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* main/channel.c, /, main/sha1.c, include/asterisk/sha1.h: Update
+	  SHA1 code to RFC 6234 RFC 6234 is an update to RFC 3174 from
+	  which the code was originally taken. It has a slightly better
+	  code, and a better phrased license (simple 3-clause BSD). *
+	  main/sha1.c is sha1.c from RFC 6234 with formatting changes only.
+	  * include/asterisk/sha1.h merges sha.h and sha-private.h from RFC
+	  6234. * Removed unused include of asterisk/sha1.h from
+	  main/channels.c Review: https://reviewboard.asterisk.org/r/1503/
+	  Merge-From:
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8@340263
+	  Merge-From:
+	  http://svn.asterisk.org/svn/asterisk/branches/10@340280
+
+2011-10-11 18:57 +0000 [r340282]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/manager.c, /, include/asterisk/manager.h: Convert registered
+	  AMI actions to ao2 objects. * Fixed race between calling an AMI
+	  action callback and unregistering that action. Refixes
+	  ASTERISK-13784 broken by ASTERISK-17785 change. * Fixed potential
+	  memory leak if an AMI action failed to get registered because is
+	  already was registered. Part of the ao2 conversion. * Fixed AMI
+	  ListCommands action not walking the actions list with a lock
+	  held. * Fix usage of ast_strdupa() and alloca() in loops. Excess
+	  stack usage. * Fix AMI Originate action Variable header requiring
+	  a space after the header colon. Reported by Yaroslav Panych on
+	  the asterisk-dev list. * Increased the number of listed variables
+	  allowed per AMI Originate action Variable header to 64. * Fixed
+	  AMI GetConfigJSON action output format. * Fixed usage of res
+	  contents outside of scope in append_channel_vars(). * Fixed
+	  inconsistency of config file channelvars option. The values no
+	  longer accumulate with every channelvars option in the config
+	  file. Only the last value is kept to be consistent with the CLI
+	  "manager show settings" command. (closes issue ASTERISK-18479)
+	  Reported by: Jaco Kroon ........ Merged revisions 340279 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 340281 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-10-10 23:10 +0000 [r340221-340224]  Terry Wilson <twilson at digium.com>
+
+	* UPGRADE.txt, main/db.c: Return error when no rows are deleted for
+	  AMI DBDelTree (closes issue AST-654)
+
+	* /, main/db.c: Merged revisions 340222 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r340222 | twilson | 2011-10-10 15:55:39 -0700 (Mon, 10 Oct 2011)
+	  | 8 lines On astdb conversion, also warn about permissions
+	  requirements The user running Asterisk must have permission to
+	  the directory the Asterisk database resides in since SQLite 3
+	  needs to be able to create a journal file. (closes issue
+	  ASTERISK-18174) ........
+
+	* utils/Makefile, utils/utils.xml, /, UPGRADE.txt,
+	  utils/astdb2bdb.c (added): Merged revisions 340219-340220 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r340219 | twilson | 2011-10-10 15:38:06 -0700 (Mon, 10
+	  Oct 2011) | 8 lines Add astdb conversion utility for Berkeley to
+	  SQLite 3 If someone wants to backtrack from Asterisk 1.8 to 10
+	  they can use the astdb2bdb utility to convert the database back
+	  to the Berkeley format that Asterisk 1.8 uses. Review:
+	  https://reviewboard.asterisk.org/r/1502/ ........ r340220 |
+	  twilson | 2011-10-10 15:39:41 -0700 (Mon, 10 Oct 2011) | 2 lines
+	  Add a missing file for the astdb2bdb conversion utility ........
+
+2011-10-10 20:39 +0000 [r340166]  Matthew Jordan <mjordan at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 340165 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340165 | mjordan | 2011-10-10 15:30:18 -0500
+	  (Mon, 10 Oct 2011) | 20 lines Merged revisions 340164 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r340164 | mjordan | 2011-10-10 15:23:48 -0500 (Mon, 10 Oct 2011)
+	  | 13 lines Updated chan_sip to place calls on hold if SDP address
+	  in INVITE is ANY This patch fixes the case where an INVITE is
+	  received with c=0.0.0.0 or ::. In this case, the call should be
+	  placed on hold. Previously, we checked for the address being
+	  null; this patch keeps that behavior but also checks for the ANY
+	  IP addresses. Review: https://reviewboard.asterisk.org/r/1504/
+	  (closes issue ASTERISK-18086) Reported by: James Bottomley Tested
+	  by: Matt Jordan ........ ................
+
+2011-10-10 14:16 +0000 [r340110]  Matthew Nicholson <mnicholson at digium.com>
+
+	* main/pbx.c, main/manager.c, /, res/res_fax.c, apps/app_fax.c,
+	  include/asterisk/module.h, res/res_agi.c,
+	  include/asterisk/xmldoc.h, doc/appdocsxml.dtd, main/loader.c,
+	  main/xmldoc.c: Merged revisions 340109 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r340109 | mnicholson | 2011-10-10 09:15:41 -0500
+	  (Mon, 10 Oct 2011) | 18 lines Merged revisions 340108 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r340108 | mnicholson | 2011-10-10 09:14:48 -0500 (Mon, 10 Oct
+	  2011) | 11 lines Load the proper XML documentation when multiple
+	  modules document the same application. This patch adds an
+	  optional "module" attribute to the XML documentation spec that
+	  allows the documentation processor to match apps with identical
+	  names from different modules to their documentation. This patch
+	  also fixes a number of bugs with the documentation processor and
+	  should make it a little more efficient. Support for multiple
+	  languages has also been properly implemented. ASTERISK-18130
+	  Review: https://reviewboard.asterisk.org/r/1485/ ........
+	  ................
+
+2011-10-10 00:57 +0000 [r339993-340071]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Add skinny version 17 protocol support.
+	  Added some data to skinny packet structures to make compatible
+	  with v17. Added protocolversion to device, set on registration
+	  based on the version provided by device. v17 includes some
+	  increased ip space for ip6. This patch increases ip space in the
+	  packets but still only uses ip4. Some packet structures
+	  duplicated (ip4 and ip6 types). ip4 type used unless version is
+	  greater or equal to 17. Tested by snuff and myself on 7961 with
+	  recent 8.5 firmware. Also tested compatible with old 7960 and
+	  older 30VIPs.
+
+	* channels/chan_skinny.c: Increase SKINNY_MAX_PACKET and add some
+	  logging. Increase SKINNY_MAX_PACKET to 2000 bytes to handle some
+	  messages in v17 that are greater than the old 1000 bytes. Also
+	  add some useful logging regarding packet and session handling. A
+	  device (with protocol v17) was sending a packet with length
+	  greater than 1000 which resulted in the TCP session being
+	  destroyed and registration being retryed.
+
+	* /, channels/chan_skinny.c: Merged revisions 340031 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r340031 | wedhorn | 2011-10-10 09:18:27 +1100 (Mon, 10 Oct 2011)
+	  | 8 lines Return -1 to skinny_session if register rejected. If
+	  device registration is rejected, return -1 so that the session is
+	  destroyed immediately. Previously, a segfault would occur on a
+	  graceful shutdown if a register is rejected and the
+	  skinny_session has not yet timed out. ........
+
+	* /, channels/chan_skinny.c: Merged revisions 339992 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339992 | wedhorn | 2011-10-10 08:09:12 +1100 (Mon, 10 Oct 2011)
+	  | 9 lines Remove log message on traverse session list. On
+	  destroying a session, a list of sessions is traversed to find the
+	  matching session. For each session not matching, skinny
+	  erroneously logged that the session was not matched. While
+	  technically correct the message was misleading, and tended to
+	  indicate errors that were not there. ........
+
+2011-10-09 01:19 +0000 [r339832-339947]  Igor Goncharovskiy <igor.goncharovsky at gmail.com>
+
+	* channels/chan_unistim.c, /: Merged revisions 339942 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339942 | igorg | 2011-10-09 08:18:02 +0700
+	  (Вск, 09 Окт 2011) | 12 lines Merged revisions 339938 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339938 | igorg | 2011-10-09 08:16:09 +0700 (Вск, 09 Окт 2011) |
+	  6 lines Fix compilation issue, caused by missed session structure
+	  (closes issue ASTERISK-18694) Reported by: alex70 ........
+	  ................
+
+	* channels/chan_unistim.c, /: Merged revisions 339885 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339885 | igorg | 2011-10-08 22:46:27 +0700
+	  (Сбт, 08 Окт 2011) | 13 lines Merged revisions 339884 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339884 | igorg | 2011-10-08 22:45:20 +0700 (Сбт, 08 Окт 2011) |
+	  7 lines Fix segfault in Unistim channel (closes issue
+	  ASTERISK-18638) Reported by: jonnt ........ ................
+
+	* channels/chan_unistim.c, /: Merged revisions 339831 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339831 | igorg | 2011-10-08 22:01:35 +0700
+	  (Сбт, 08 Окт 2011) | 14 lines Merged revisions 339830 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339830 | igorg | 2011-10-08 21:56:35 +0700 (Сбт, 08 Окт 2011) |
+	  8 lines Fix char array cast as short array in send_client()
+	  function (for ARM platform) (closes issue ASTERISK-17314)
+	  Reported by: jjoshua ........ ................
+
+2011-10-07 19:37 +0000 [r339721-339778]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_url.c: Merged revisions 339777 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339777 | rmudgett | 2011-10-07 14:36:24 -0500
+	  (Fri, 07 Oct 2011) | 12 lines Merged revisions 339776 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339776 | rmudgett | 2011-10-07 14:34:55 -0500 (Fri, 07 Oct 2011)
+	  | 5 lines Initialize option flags for SendURL application.
+	  (closes issue ASTERISK-18574) Reported by: marcelloceschia
+	  ........ ................
+
+	* /: Recorded merge of revisions 339681 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339681 | wedhorn | 2011-10-06 15:47:08 -0500 (Thu, 06 Oct 2011)
+	  | 10 lines Fixed segfault on core stop gracefully. There was an
+	  issue that the cap and confcap pointers for each line and device
+	  were being memcpy'd so they all pointed to the same
+	  ast_format_cap. On destroying, a segfault occured on the second
+	  call to the same struct. skinny reload now works again as well.
+	  Tested by snuff (in trunk) and myself. ........
 
-2013-08-30 16:27 +0000 [r398003-398017]  Kevin Harwell <kharwell at digium.com>
+	* /, configure, include/asterisk/autoconfig.h.in, configure.ac,
+	  autoconf/ast_ext_lib.m4: Merged revisions 339720 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339720 | rmudgett | 2011-10-06 17:58:40 -0500
+	  (Thu, 06 Oct 2011) | 27 lines Merged revisions 339719 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339719 | rmudgett | 2011-10-06 17:47:50 -0500 (Thu, 06 Oct 2011)
+	  | 20 lines Fix regression in configure script for libpri
+	  capability checks. JIRA AST-598 added the PRI_L2_PERSISTENCE
+	  option to fix BRI PTMP TE layer 2 persistence issues with some
+	  telcos. ASTERISK-18535 attempted to fix the unexpected
+	  requirement that libpri *must* have that feature to work with
+	  Asterisk. The AST_EXT_LIB_SETUP_DEPENDENT lines made the PRI
+	  optional features required. Unfortunately, I thought
+	  AST_EXT_LIB_SETUP_DEPENDENT didn't do anything useful for libpri
+	  and deleted those lines for libpri. The result was the
+	  HAVE_PRI_xxx defines that control the ability to use optional
+	  libpri features were also deleted. * Created
+	  AST_EXT_LIB_SETUP_OPTIONAL configuration macro to allow optional
+	  features in a library that the source code could take advantage
+	  of if the code supports the feature. (closes issue
+	  ASTERISK-18687) Reported by: Norbert Tested by: rmudgett ........
+	  ................
+
+2011-10-06 20:18 +0000 [r339680]  Damien Wedhorn <voip at facts.com.au>
+
+	* channels/chan_skinny.c: Fixed segfault on core stop gracefully.
+	  There was an issue that the cap and confcap pointers for each
+	  line and device were being memcpy'd so they all pointed to the
+	  same ast_format_cap. On destroying, a segfault occured on the
+	  second call to the same struct. skinny reload now works again as
+	  well. Tested by snuff and myself.
+
+2011-10-06 17:54 +0000 [r339627]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/udptl.c, /, channels/chan_sip.c: Merged revisions 339626 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339626 | rmudgett | 2011-10-06 12:53:00 -0500
+	  (Thu, 06 Oct 2011) | 25 lines Merged revisions 339625 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339625 | rmudgett | 2011-10-06 12:49:38 -0500 (Thu, 06 Oct 2011)
+	  | 18 lines Fix debugging messages generated by 'udptl debug'. *
+	  Makes chan_sip set the tag to the channel name. * Fixes received
+	  debug message sequence number. * Removed tx/rx debug message type
+	  since it was hard coded to 0. * Made udptl.c logged message
+	  header consistent if possible: "UDPTL (%s): ". * Removed unused
+	  rx_expected_seq_no from struct ast_udptl. (closes issue
+	  ASTERISK-18401) Reported by: Kevin P. Fleming Patches:
+	  jira_asterisk_18401_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: Matthew Nicholson ........ ................
+
+2011-10-06 13:43 +0000 [r339587]  Leif Madsen <leif at leifmadsen.com>
+
+	* build_tools/prep_tarball: Merged revisions 339586 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339586 | lmadsen | 2011-10-06 08:43:21 -0500
+	  (Thu, 06 Oct 2011) | 16 lines Merged revisions 339566 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339566 | lmadsen | 2011-10-05 16:30:11 -0500 (Wed, 05 Oct 2011)
+	  | 8 lines Update prep_tarball script to download pre-exported
+	  documentation. I've updated the prep_tarball script to now
+	  download the pre-exported documentation from the Asterisk wiki.
+	  This will give us more control over what is being included in the
+	  tarball releases, and will make both the PDF and HTML exported
+	  documentation look much better (especially when viewing from a
+	  console). (Closes issue ASTERISK-18677) ........ ................
+
+2011-10-05 17:02 +0000 [r339510-339513]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, /: Merged revisions 339512 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339512 | rmudgett | 2011-10-05 12:01:46 -0500
+	  (Wed, 05 Oct 2011) | 9 lines Merged revisions 339511 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r339511 | rmudgett | 2011-10-05 12:01:01 -0500 (Wed, 05
+	  Oct 2011) | 1 line Fix Dial F option notes formatting. ........
+	  ................
+
+	* main/manager.c, /: Merged revisions 339508 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339508 | rmudgett | 2011-10-05 11:35:02 -0500
+	  (Wed, 05 Oct 2011) | 18 lines Merged revisions 339504,339506 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339504 | rmudgett | 2011-10-05 11:26:45 -0500 (Wed, 05 Oct 2011)
+	  | 7 lines Add missing documentation of required AMI action
+	  Challenge AuthType header. (closes issue ASTERISK-18554) Reported
+	  by: Vlad Povorozniuc Patches:
+	  __20110919-manager-challenge-docs.patch.txt (license #4999) patch
+	  uploaded by Leif Madsen ........ r339506 | rmudgett | 2011-10-05
+	  11:32:03 -0500 (Wed, 05 Oct 2011) | 1 line Fix XML error in AMI
+	  action Challenge. ........ ................
+
+2011-10-05 16:35 +0000 [r339509]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 339507 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339507 | mnicholson | 2011-10-05 11:32:59 -0500
+	  (Wed, 05 Oct 2011) | 10 lines Merged revisions 339505 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339505 | mnicholson | 2011-10-05 11:31:21 -0500 (Wed, 05 Oct
+	  2011) | 3 lines The app name in the documentation must match what
+	  we register the application as. ........ ................
+
+2011-10-05 06:50 +0000 [r339464-339465]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* res/res_fax.c, include/asterisk/res_fax.h, CHANGES: Add generic
+	  faxdetect framehook to res_fax Added func
+	  FAXOPT(faxdetect)=yes,cng,t38[,timeout]/no to enable dialplan
+	  faxdetect allowing more flexibility. as soon as a fax tone is
+	  detected the framehook is removed. there is a penalty involved in
+	  running this framehook on non G711 channels as they will be
+	  transcoded. CNG tone is suppresed using the SQUELCH flag to allow
+	  WaitForNoise to be run on the channel to detect Voice. (Closes
+	  issue ASTERISK-18569) Reported by: Myself Reviewed by: Matthew
+	  Nicholson, Kevin Fleming Review:
+	  https://reviewboard.asterisk.org/r/1116/
+
+	* /, res/res_fax.c: Merged revisions 339463 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339463 | irroot | 2011-10-05 08:28:46 +0200 (Wed, 05 Oct 2011) |
+	  9 lines Only change the capabilities on the gateway when the
+	  session is been destroyed there is still a race condition that
+	  ends in a segfault. if the caps are changed the logic in
+	  res_fax_spandsp will run T30 code not gateway code to end the
+	  session. this has been experienced on a "slower" under spec
+	  system. ........
+
+2011-10-04 22:59 +0000 [r339408]  Richard Mudgett <rmudgett at digium.com>
+
+	* Makefile, /: Merged revisions 339407 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339407 | rmudgett | 2011-10-04 17:56:25 -0500
+	  (Tue, 04 Oct 2011) | 15 lines Merged revisions 339406 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339406 | rmudgett | 2011-10-04 17:54:15 -0500 (Tue, 04 Oct 2011)
+	  | 8 lines Make always create the MOH directory
+	  (/var/lib/asterisk/moh). (closes issue ASTERISK-18409) Reported
+	  by: abelbeck Patches: asterisk-1.8-makefile-moh.patch (license
+	  #5903) patch uploaded by abelbeck Tested by: abelbeck, Michael
+	  Keuter ........ ................
+
+2011-10-04 19:51 +0000 [r339315-339354]  Jonathan Rose <jrose at digium.com>
+
+	* /, main/say.c: Merged revisions 339353 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339353 | jrose | 2011-10-04 14:44:02 -0500
+	  (Tue, 04 Oct 2011) | 18 lines Merged revisions 339352 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339352 | jrose | 2011-10-04 14:33:12 -0500 (Tue, 04 Oct 2011) |
+	  12 lines Removes improper use of sound 'and' in German language
+	  mode from application saynumber Asterisk would say 'Five hundert
+	  und sechs und zwanzig' instead of 'Five hundert sechs und
+	  zwanzig'... which is both weird sounding and wrong. This patch
+	  makes sure Asterisk will only say the 'and' word between the
+	  single digit and double digit places. (closes issue
+	  ASTERISK-18212) Reported By: Lionel Elie Mamane Patches:
+	  upstream_germand_no_and.diff (License #5402) uploaded by Lionel
+	  Elie Mamane ........ ................
+
+	* /, res/res_jabber.c: Merged revisions 339298 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339298 | jrose | 2011-10-04 09:09:50 -0500
+	  (Tue, 04 Oct 2011) | 19 lines Merged revisions 339297 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339297 | jrose | 2011-10-04 09:01:05 -0500 (Tue, 04 Oct 2011) |
+	  13 lines Reverting revision 333265 due to component connection
+	  problems it introduces. I'm going to attempt some generic
+	  res_jabber cleanup and come up with a new fix for this problem,
+	  but first it seems prudent to remove this rather broad attempt to
+	  fix it and instead approach this problem either from the same
+	  angle but looking only at canceling (or possibly rescheduling)
+	  the send when we absolutely know it will cause a segfault or, if
+	  that can't be easily accomplished, strictly from the devstate
+	  side of things. Also, I'm pretty sure a lot of the code in
+	  res_jabber isn't thread safe. (issue ASTERISK-18626) (issue
+	  ASTERISK-18078) ........ ................
+
+2011-10-04 12:27 +0000 [r339262]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/memheap.c: Merged revisions 339245 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339245 | may | 2011-10-04 15:49:49 +0400 (Tue,
+	  04 Oct 2011) | 9 lines Merged revisions 339244 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339244 | may | 2011-10-04 15:44:55 +0400 (Tue, 04 Oct 2011) | 2
+	  lines fix forget declaration in previous change ........
+	  ................
+
+2011-10-04 09:43 +0000 [r339206]  Olle Johansson <oej at edvina.net>
+
+	* main/manager.c, CHANGES: Generate error message when AMI action
+	  originate extension doesn't exist Review:
+	  https://reviewboard.asterisk.org/r/1445/ Is this a bug or a new
+	  feature? No responses on Asterisk-dev so I'm committing to trunk
+	  only.
+
+2011-10-03 20:13 +0000 [r339146-339149]  Leif Madsen <leif at leifmadsen.com>
+
+	* channels/chan_sip.c: Merged revisions 339148 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339148 | lmadsen | 2011-10-03 15:13:16 -0500
+	  (Mon, 03 Oct 2011) | 14 lines Merged revisions 339147 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339147 | lmadsen | 2011-10-03 15:12:43 -0500 (Mon, 03 Oct 2011)
+	  | 6 lines Remove duplicated Maxforwards line in AMI output.
+	  (Closes issue ASTERISK-18637) Reported by: Jacek Konieczny
+	  Patches: asterisk-sipshowpeer.patch (License #6298) uploaded by
+	  Jacek Konieczny ........ ................
+
+	* apps/app_dial.c: Merged revisions 339145 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339145 | lmadsen | 2011-10-03 14:55:15 -0500
+	  (Mon, 03 Oct 2011) | 13 lines Merged revisions 339144 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339144 | lmadsen | 2011-10-03 14:54:52 -0500 (Mon, 03 Oct 2011)
+	  | 6 lines Make documentation for Dial() options 'F' and 'F()'
+	  more clear. (Closes issue ASTERISK-18646) Reported by: Physis
+	  Heckman Tested by: Richard Mudgett ........ ................
+
+2011-10-03 19:16 +0000 [r339091]  Alexandr Anikin <may at telecom-service.ru>
+
+	* /, addons/ooh323c/src/memheap.c: Merged revisions 339089 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339089 | may | 2011-10-03 22:52:55 +0400 (Mon,
+	  03 Oct 2011) | 10 lines Merged revisions 339087 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339087 | may | 2011-10-03 22:42:49 +0400 (Mon, 03 Oct 2011) | 4
+	  lines destroy memheap mutex properly before memheap deleted (fix
+	  memory leak occured after r304950 changes with DEBUG_THREAD
+	  compile option) ........ ................
+
+2011-10-03 18:58 +0000 [r339090]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c, main/file.c: Merged revisions 339088 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r339088 | twilson | 2011-10-03 11:44:27 -0700
+	  (Mon, 03 Oct 2011) | 17 lines Merged revisions 339086 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r339086 | twilson | 2011-10-03 11:40:52 -0700 (Mon, 03 Oct 2011)
+	  | 10 lines Properly ignore AST_CONTROL_UPDATE_RTP_PEER in more
+	  places After the change in r336294, the new
+	  AST_CONTROL_UPDATE_RTP_PEER frame is sent when a re-invite
+	  happens. If we receive a re-invite from a device the
+	  waitstream_core was not aware of the new control frame and would
+	  drop the call. (closes issue ASTERISK-18610) Reported by:
+	  Kristijan_Vrban ........ ................
+
+2011-10-03 15:55 +0000 [r339021-339046]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 339045 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339045 | mnicholson | 2011-10-03 10:54:55 -0500 (Mon, 03 Oct
+	  2011) | 4 lines Ported ast_fax_caps_to_str() to 10, not sure why
+	  it wasn't already here. This function prints a list of caps
+	  instead of a hex bitfield. ........
+
+	* /, res/res_fax.c: Merged revisions 339043 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339043 | mnicholson | 2011-10-03 10:41:36 -0500 (Mon, 03 Oct
+	  2011) | 2 lines Don't clear the AST_FAX_TECH_MULTI_DOC flag right
+	  after we set it. ........
+
+	* /, res/res_fax.c: Merged revisions 339011 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r339011 | mnicholson | 2011-10-03 10:19:44 -0500 (Mon, 03 Oct
+	  2011) | 2 lines properly remove the AST_FAX_TECH_GATEWAY flag
+	  (instead of setting all of the other flags) ........
+
+2011-10-03 14:40 +0000 [r338905-338998]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, CHANGES: Merged revisions 338997 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r338997 | irroot | 2011-10-03 16:38:25 +0200 (Mon, 03 Oct 2011) |
+	  1 line Documentation noting the extension of CHANNEL() for
+	  chan_ooh323 ........
+
+	* addons/chan_ooh323.c, /, funcs/func_channel.c: Merged revisions
+	  338995 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r338995 | irroot | 2011-10-03 16:21:40 +0200 (Mon, 03 Oct 2011) |
+	  6 lines Remove the channel function OOH323() and place its
+	  options into CHANNEL() channel drivers should not have there own
+	  dialplan functions. ........
+
+	* /, res/res_fax.c: Merged revisions 338950 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r338950 | irroot | 2011-10-03 11:37:59 +0200 (Mon, 03 Oct 2011) |
+	  14 lines Fixup a race condition in res_fax.c where
+	  FAXOPT(gateway)=no will turn off the gateway but the framehook is
+	  not destroyed. this problem happens when a gateway is attempted
+	  in the dialplan and the device is not available i may want to do
+	  fax to mail in the server it will not be allowed. instead of
+	  checking only AST_FAX_TECH_GATEWAY also check gateway_id Reverts
+	  338904 Fix some white space. ........
+
+	* /, res/res_fax.c: Merged revisions 338904 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r338904 | irroot | 2011-10-02 16:17:32 +0200 (Sun, 02 Oct 2011) |
+	  8 lines Remove T38 Gateway capability when detaching framehook.
+	  SET(FAXOPT(gateway)=no) does not remove the capability when
+	  detaching the framehook. small patch to fix this problem.
+	  ........
+
+2011-10-01 01:56 +0000 [r338855]  TransNexus OSP Development <support at transnexus.com>
+
+	* configure: Update "configure" based on r338139.
+
+2011-09-30 22:08 +0000 [r338802]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 338801 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338801 | rmudgett | 2011-09-30 17:06:48 -0500
+	  (Fri, 30 Sep 2011) | 19 lines Merged revisions 338800 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r338800 | rmudgett | 2011-09-30 17:05:10 -0500 (Fri, 30 Sep 2011)
+	  | 12 lines Fix segfault in analog_ss_thread() not checking
+	  ast_read() for NULL. NOTE: The problem was reported against
+	  v1.6.2. It is unlikely to ever happen on v1.8 and above since
+	  chan_dahdi.c:analog_ss_thread() is unlikely to be used. The
+	  version in sig_analog.c has largely replaced it. (closes issue
+	  ASTERISK-18648) Reported by: Stephan Bosch Patches:
+	  jira_asterisk_18648_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: Stephan Bosch ........ ................
+
+2011-09-30 19:25 +0000 [r338755]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_sip.c: Formatting changes only --Denna och
+	  nedanstående rader kommer inte med i loggmeddelandet-- M
+	  channels/chan_sip.c
+
+2011-09-30 18:59 +0000 [r338720]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/queues.conf.sample: Merged revisions 338719 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338719 | jrose | 2011-09-30 13:55:27 -0500
+	  (Fri, 30 Sep 2011) | 9 lines Merged revisions 338718 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r338718 | jrose | 2011-09-30 13:54:30 -0500 (Fri, 30 Sep
+	  2011) | 1 line Adds documentation for QueueMemberStatus event
+	  generation ........ ................
+
+2011-09-30 16:40 +0000 [r338665]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/chan_sip.c: Fix formatting of AMI header for SIP show
+	  peer. ASTERISK-17486 exposed the problem for AMI parsers. (closes
+	  issue ASTERISK-18649) Reported by: Jacek Konieczny Patches:
+	  asterisk-sipshowpeer_response_end.patch (license #6298) patch
+	  uploaded by Jacek Konieczny ........ Merged revisions 338663 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
+	  revisions 338664 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+2011-09-30 13:21 +0000 [r338623]  Olle Johansson <oej at edvina.net>
+
+	* main/features.c: Preserve DTMF length in main/features.c Review:
+	  https://reviewboard.asterisk.org/r/1463/ A small part of much
+	  larger work with DTMF duration in Asterisk, funded by IPvision AS
+	  in Denmark. Thanks to irroot for the review!
+
+2011-09-29 21:16 +0000 [r338557]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* tests/test_security_events.c, /, tests/test_locale.c,
+	  tests/test_logger.c, tests/test_dlinklists.c,
+	  tests/test_linkedlists.c, tests/test_amihooks.c: Merged revisions
+	  338556 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338556 | pabelanger | 2011-09-29 17:14:34 -0400
+	  (Thu, 29 Sep 2011) | 9 lines Merged revisions 338555 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r338555 | pabelanger | 2011-09-29 17:12:21 -0400 (Thu,
+	  29 Sep 2011) | 2 lines Test modules should depend on the
+	  TEST_FRAMEWORK flag ........ ................
+
+2011-09-29 20:55 +0000 [r338553]  Jason Parker <jparker at digium.com>
+
+	* /, tests/test_db.c, tests/test_netsock2.c: Merged revisions
+	  338552 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338552 | qwell | 2011-09-29 15:54:55 -0500
+	  (Thu, 29 Sep 2011) | 9 lines Merged revisions 338551 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r338551 | qwell | 2011-09-29 15:54:13 -0500 (Thu, 29 Sep
+	  2011) | 1 line Test modules have a support level of core.
+	  ........ ................
+
+2011-09-29 12:22 +0000 [r338435]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Merged
+	  revisions 338417 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338417 | irroot | 2011-09-29 14:16:42 +0200
+	  (Thu, 29 Sep 2011) | 19 lines Merged revisions 338416 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r338416 | irroot | 2011-09-29 14:13:05 +0200 (Thu, 29 Sep 2011) |
+	  12 lines The rtptimeout setting is ignored on a per peer basis.
+	  Not only is the rtptimeout ignored in some cases but rtpkeepalive
+	  and rtpholdtimeout is affected. this commit also removes
+	  rtptimeout/rtpholdtimeout on text rtp. (closes issue
+	  ASTERISK-18559) Review: https://reviewboard.asterisk.org/r/1452
+	  ........ ................
+
+2011-09-29 12:03 +0000 [r338377-338415]  Olle Johansson <oej at edvina.net>
+
+	* cdr/cdr_pgsql.c, CHANGES: Add CLI command "cdr show pgsql status"
+	  based on "cdr mysql status" Review:
+	  https://reviewboard.asterisk.org/r/923/ Thanks all for the code
+	  reviews and feedback.
+
+	* res/res_agi.c: Just formatting.
+
+2011-09-28 22:38 +0000 [r338284-338324]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Merged revisions 338323 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338323 | rmudgett | 2011-09-28 17:36:57 -0500
+	  (Wed, 28 Sep 2011) | 12 lines Merged revisions 338322 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r338322 | rmudgett | 2011-09-28 17:35:52 -0500 (Wed, 28 Sep 2011)
+	  | 5 lines Make duplicate call ptr warning message more helpful. *
+	  Adds the value of the call ptr to the duplicate call ptr message
+	  to help trace why there is a duplicate call ptr. ........
+	  ................
+
+	* include/asterisk/logger.h, /: Merged revisions 338253 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338253 | rmudgett | 2011-09-28 16:22:05 -0500
+	  (Wed, 28 Sep 2011) | 14 lines Merged revisions 338235 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r338235 | rmudgett | 2011-09-28 16:17:45 -0500 (Wed, 28 Sep 2011)
+	  | 7 lines Fix inconsistency in LOG_VERBOSE/AST_LOG_VERBOSE
+	  declaration. (closes issue ASTERISK-17973) Reported by: Luke H
+	  Patches: logger_h.patch (license #6278) patch uploaded by Luke H
+	  ........ ................
+
+2011-09-28 20:55 +0000 [r338229]  Jason Parker <jparker at digium.com>
+
+	* build_tools/cflags.xml, channels/chan_usbradio.c,
+	  build_tools/cflags-devmode.xml, agi/agi.xml, utils/utils.xml, /,
+	  build_tools/embed_modules.xml, tests/test_db.c,
+	  tests/test_netsock2.c: Merged revisions 338228 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338228 | qwell | 2011-09-28 15:54:35 -0500
+	  (Wed, 28 Sep 2011) | 9 lines Merged revisions 338227 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r338227 | qwell | 2011-09-28 15:52:47 -0500 (Wed, 28 Sep
+	  2011) | 1 line Add support levels to non-module sections of
+	  menuselect (cflags, utils, etc). ........ ................
+
+2011-09-28 20:28 +0000 [r338226]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 338225 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338225 | rmudgett | 2011-09-28 15:26:39 -0500
+	  (Wed, 28 Sep 2011) | 12 lines Merged revisions 338224 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r338224 | rmudgett | 2011-09-28 15:24:41 -0500 (Wed, 28 Sep 2011)
+	  | 5 lines Fix chan_dahd compiling with gcc 4.6 when PRI and SS7
+	  not present. (closes issue ASTERISK-18357) Reported by: Matthew
+	  Nicholson ........ ................
+
+2011-09-28 17:00 +0000 [r338187-338188]  Terry Wilson <twilson at digium.com>
+
+	* CHANGES: Update CHANGES to reflect autopausebusy not being in
+	  Asterisk 10
+
+	* configs/queues.conf.sample, CHANGES, apps/app_queue.c: Add
+	  autopausebusy and autopauseunavail queue options Make it possible
+	  to autopause on a busy or unavailable response from a device.
+	  (closes issue ASTERISK-16112) Reported by: jlpedrosa Patches:
+	  autopausebusy.txt by twilson Review:
+	  https://reviewboard.asterisk.org/r/1399/
+
+2011-09-28 07:30 +0000 [r338136-338139]  TransNexus OSP Development <support at transnexus.com>
+
+	* configure.ac: Updated for checking OSP Toolkit version 4.0.0.
+
+	* apps/app_osplookup.c: Updated for OSP Toolkit 4.0.0.
+
+2011-09-27 20:15 +0000 [r338086]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, apps/app_macro.c: Merged revisions 338085 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r338085 | pabelanger | 2011-09-27 16:13:14 -0400
+	  (Tue, 27 Sep 2011) | 9 lines Merged revisions 338084 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r338084 | pabelanger | 2011-09-27 16:10:13 -0400 (Tue,
+	  27 Sep 2011) | 2 lines Upgrade app_macro to core ........
+	  ................
+
+2011-09-27 12:45 +0000 [r338042]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_sip.c: Whitespace (red blobs) fixes
+
+2011-09-26 19:40 +0000 [r337975]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, main/pbx.c, cdr/cdr_sqlite3_custom.c, /,
+	  include/asterisk/cel.h, cdr/cdr_syslog.c, tests/test_gosub.c,
+	  include/asterisk/channel.h, main/cel.c, main/manager.c,
+	  funcs/func_odbc.c, cel/cel_custom.c, apps/app_minivm.c,
+	  main/logger.c, cel/cel_sqlite3_custom.c, cdr/cdr_custom.c,
+	  cdr/cdr_manager.c, apps/app_voicemail.c: Merged revisions 337974
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500
+	  (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011)
+	  | 30 lines Fix deadlock when using dummy channels. Dummy channels
+	  created by ast_dummy_channel_alloc() should be destoyed by
+	  ast_channel_unref(). Using ast_channel_release() needlessly grabs
+	  the channel container lock and can cause a deadlock as a result.
+	  * Analyzed use of ast_dummy_channel_alloc() and made use
+	  ast_channel_unref() when done with the dummy channel. (Primary
+	  reason for the reported deadlock.) * Made
+	  app_dial.c:dial_exec_full() not call ast_call() holding any
+	  channel locks. Chan_local could not perform deadlock avoidance
+	  correctly. (Potential deadlock exposed by this issue. Secondary
+	  reason for the reported deadlock since the held lock was part of
+	  the deadlock chain.) * Fixed some uses of
+	  ast_dummy_channel_alloc() not checking the returned channel
+	  pointer for failure. * Fixed some potential chan=NULL pointer
+	  usage in func_odbc.c. Protected by testing the bogus_chan value.
+	  * Fixed needlessly clearing a 1024 char auto array when setting
+	  the first char to zero is enough in manager.c:action_getvar().
+	  (closes issue ASTERISK-18613) Reported by: Thomas Arimont
+	  Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch
+	  uploaded by rmudgett Tested by: Thomas Arimont ........
+	  ................
+
+2011-09-23 19:20 +0000 [r337855-337910]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, contrib/init.d/rc.archlinux.asterisk: Merged revisions 337902
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337902 | irroot | 2011-09-23 21:18:14 +0200
+	  (Fri, 23 Sep 2011) | 10 lines Merged revisions 337898 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337898 | irroot | 2011-09-23 21:14:30 +0200 (Fri, 23 Sep 2011) |
+	  4 lines Spelling fix ........ ................
+
+	* /, apps/app_queue.c: Merged revisions 337840 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337840 | irroot | 2011-09-23 10:39:22 +0200
+	  (Fri, 23 Sep 2011) | 17 lines Merged revisions 337839 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337839 | irroot | 2011-09-23 10:34:03 +0200 (Fri, 23 Sep 2011) |
+	  11 lines Make sure a CDR is on the stack for call in the Queue.
+	  Only let update_cdr act on the last CDR in the stack. In some
+	  circumstances [Attended transfer to queue] a CDR record is not
+	  inserted for this call where it should. (closes issue
+	  ASTERISK-18567) Review: https://reviewboard.asterisk.org/r/1266
+	  ........ ................
+
+2011-09-23 00:47 +0000 [r337776]  Russell Bryant <russell at russellbryant.com>
+
+	* /, configs/res_pktccops.conf.sample: Merged revisions 337775 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337775 | russell | 2011-09-22 19:45:35 -0500
+	  (Thu, 22 Sep 2011) | 18 lines Merged revisions 337774 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337774 | russell | 2011-09-22 19:44:19 -0500 (Thu, 22 Sep 2011)
+	  | 11 lines Comment out entries in sample res_pktccops.conf. With
+	  these options enabled, they can cause Asterisk to freak out by
+	  SYN flooding a network and eating the CPU. Obviously it would be
+	  good to fix the code so that this can't happen, but we can at
+	  least change the default configuration so it doesn't happen. This
+	  was reported downstream to the Fedora issue tracker:
+	  https://bugzilla.redhat.com/show_bug.cgi?id=658431 ........
+	  ................
+
+2011-09-22 21:42 +0000 [r337722]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Merged revisions 337721 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337721 | rmudgett | 2011-09-22 16:37:41 -0500
+	  (Thu, 22 Sep 2011) | 25 lines Merged revisions 337720 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337720 | rmudgett | 2011-09-22 16:29:46 -0500 (Thu, 22 Sep 2011)
+	  | 18 lines Made ISDN not add numbering plan prefix strings to
+	  empty numbers. When the Caller-ID is restricted, the expected
+	  behavior is for the Caller-ID to be blank. In chan_dahdi, the
+	  national prefix is placed onto the Caller-ID number even if it is
+	  restricted (empty) causing the Caller-ID to be the national
+	  prefix rather than blank. This behavior was lost when sig_pri was
+	  extracted from chan_dahdi. * Made not add prefix strings to empty
+	  connected line, calling, and ANI number strings. (closes issue
+	  ASTERISK-18577) Reported by: Kris Shaw Patches:
+	  jira_asterisk_18577_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: Kris Shaw ........ ................
+
+2011-09-22 16:35 +0000 [r337600]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c, include/asterisk/event_defs.h,
+	  main/security_events.c, channels/sip/security_events.c (added),
+	  main/event.c, CHANGES, channels/sip/include/security_events.h
+	  (added), channels/sip/include/sip.h,
+	  include/asterisk/security_events_defs.h,
+	  configs/logger.conf.sample: Merged revisions 337595,337597 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r337595 | jrose | 2011-09-22 10:35:50 -0500 (Thu, 22 Sep
+	  2011) | 12 lines Generate Security events in chan_sip using new
+	  Security Events Framework Security Events Framework was added in
+	  1.8 and support was added for AMI to generate events at that
+	  time. This patch adds support for chan_sip to generate security
+	  events. (closes issue ASTERISK-18264) Reported by: Michael L.
+	  Young Patches: security_events_chan_sip_v4.patch (license #5026)
+	  by Michael L. Young Review:
+	  https://reviewboard.asterisk.org/r/1362/ ........ r337597 | jrose
+	  | 2011-09-22 10:47:05 -0500 (Thu, 22 Sep 2011) | 10 lines Forgot
+	  to svn add new files to r337595 Part of Generating security
+	  events for chan_sip (issue ASTERISK-18264) Reported by: Michael
+	  L. Young Patches: security_events_chan_sip_v4.patch (License
+	  #5026) by Michael L. Young Reviewboard:
+	  https://reviewboard.asterisk.org/r/1362/ ........
+
+2011-09-22 11:46 +0000 [r337432-337543]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, res/res_srtp.c: Merged revisions 337542 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337542 | irroot | 2011-09-22 13:44:22 +0200
+	  (Thu, 22 Sep 2011) | 14 lines Merged revisions 337541 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337541 | irroot | 2011-09-22 13:39:49 +0200 (Thu, 22 Sep 2011) |
+	  8 lines Add warned to ast_srtp to prevent errors on each frame
+	  from libsrtp The first 9 frames are not reported as some devices
+	  dont use srtp from first frame these are suppresed. the warning
+	  is then output only once every 100 frames. ........
+	  ................
+
+	* /, channels/chan_h323.c: Merged revisions 337487 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337487 | irroot | 2011-09-22 11:26:26 +0200
+	  (Thu, 22 Sep 2011) | 16 lines Merged revisions 337486 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337486 | irroot | 2011-09-22 11:22:26 +0200 (Thu, 22 Sep 2011) |
+	  10 lines If IP address is used in chan_h323 host parameter of
+	  peer configuration. module tries to resolve IP address to IP
+	  address and fails. Simple fix to set family of socket this is a
+	  hangover from ipv6 changes. (closes issue ASTERISK-18237) (issue
+	  ASTERISK-17278) (issue ASTERISK-17500) ........ ................
+
+	* main/channel.c, /: Merged revisions 337431 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337431 | irroot | 2011-09-22 08:29:09 +0200
+	  (Thu, 22 Sep 2011) | 25 lines Merged revisions 337430 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337430 | irroot | 2011-09-22 08:18:33 +0200 (Thu, 22 Sep 2011) |
+	  19 lines Its possible to loose audio on ast_write when the
+	  channel is not transcoded correctly. in the case of DAHDI the
+	  channel is hungup. This patch tries to "fix" the problem and make
+	  the channel compatiable and warn the user of this problem. Please
+	  note there is a underlying problem with codec negotion this does
+	  not fix the problem it does try to rectify it and prevent loss of
+	  service. Review: https://reviewboard.asterisk.org/r/1442/ (closes
+	  issue ASTERISK-17541) (closes issue ASTERISK-18063) (issue
+	  ASTERISK-14384) (issue ASTERISK-17502) (issue ASTERISK-18325)
+	  (issue ASTERISK-18422) ........ ................
+
+2011-09-21 21:26 +0000 [r337343-337385]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, apps/app_voicemail.c: More silly spacing changes ..... Merged
+	  revisions 337353 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ..... Merged
+	  revisions 337380 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* /, apps/app_voicemail.c: ................ ........ Dumb little
+	  spacing fix. ........ Merged revisions 337344 from
+	  http://svn.asterisk.org/svn/asterisk/branches/1.8
+	  ................ Merged revisions 337345 from
+	  http://svn.asterisk.org/svn/asterisk/branches/10
+
+	* funcs/func_curl.c, /: ................ ........ Escape commas in
+	  keys and values, when keys and values are enumerated by commas.
+	  Review: https://reviewboard.asterisk.org/r/1433 ........ Merged
+	  revisions 337325 from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ................ Merged revisions 337342 from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+
+2011-09-21 11:21 +0000 [r337262-337283]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, configs/sip.conf.sample: Merged revisions 337263 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r337263 | irroot | 2011-09-21 13:15:48 +0200 (Wed, 21 Sep 2011) |
+	  1 line Whitespace fixup from SRTP patch ........
+
+	* /, apps/app_originate.c, CHANGES: Merged revisions 337261 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r337261 | irroot | 2011-09-21 12:42:06 +0200 (Wed, 21
+	  Sep 2011) | 10 lines Adds a timeout argument to app_originate the
+	  default is 30s this will be used if the timout supplied is
+	  invalid or no timeout is supplied. Contributed by: jacco (thank
+	  you for the work) Review:
+	  https://reviewboard.asterisk.org/r/1310/ ........
+
+2011-09-21 09:39 +0000 [r337179-337220]  Olle Johansson <oej at edvina.net>
+
+	* main/pbx.c, /, CHANGES, configs/extensions.conf.sample: Merged
+	  revisions 337219 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r337219 | oej | 2011-09-21 11:32:50 +0200 (Ons, 21 Sep 2011) | 13
+	  lines Make ast_pbx_run() not default to s at default if extension is
+	  not found Review: https://reviewboard.asterisk.org/r/1446/ This
+	  is a bug - or architecture mistake - that has been in Asterisk
+	  for a very long time. It was exposed by the AMI originate action
+	  and possibly some other applications. Most channel drivers checks
+	  if an extension exists BEFORE starting a pbx on an inbound call,
+	  so most calls will not depend on this issue. Thanks everyone
+	  involved in the review and on IRC and the mailing list for a
+	  quick review and all the feedback. (closes issue ASTERISK-18578)
+	  ........
+
+	* res/res_rtp_asterisk.c, /, configs/rtp.conf.sample, CHANGES:
+	  Merged revisions 337178 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r337178 | oej | 2011-09-21 10:51:41 +0200 (Ons, 21 Sep 2011) | 14
+	  lines Change strictrtp option to default to yes in the RTP module
+	  Suggested by Kapejod on Facebook Review:
+	  https://reviewboard.asterisk.org/r/1448/ (closes issue
+	  ASTERISK-18587) Thanks for quick feedback to kpfleming and
+	  Tilghman --Denna och nedanstående rader kommer inte med i
+	  loggmeddelandet-- M CHANGES M configs/rtp.conf.sample M
+	  res/res_rtp_asterisk.c ........
+
+2011-09-20 23:02 +0000 [r337124]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_dial.c, include/asterisk/app.h, apps/app_meetme.c,
+	  apps/app_minivm.c, main/app.c, apps/app_confbridge.c,
+	  apps/app_followme.c, apps/app_voicemail.c: Merged revisions
+	  337120 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337120 | mjordan | 2011-09-20 17:49:36 -0500
+	  (Tue, 20 Sep 2011) | 28 lines Merged revisions 337118 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337118 | mjordan | 2011-09-20 17:38:54 -0500 (Tue, 20 Sep 2011)
+	  | 21 lines Fix for incorrect voicemail duration in external
+	  notifications This patch fixes an issue where the voicemail
+	  duration was being reported with a duration significantly less
+	  than the actual sound file duration. Voicemails that contained
+	  mostly silence were reporting the duration of only the sound in
+	  the file, as opposed to the duration of the file with the
+	  silence. This patch fixes this by having two durations reported
+	  in the __ast_play_and_record family of functions - the
+	  sound_duration and the actual duration of the file. The
+	  sound_duration, which is optional, now reports the duration of
+	  the sound in the file, while the actual full duration of the file
+	  is reported in the duration parameter. This allows the voicemail
+	  applications to use the sound_duration for minimum duration
+	  checking, while reporting the full duration to external parties
+	  if the voicemail is kept. (issue ASTERISK-2234) (closes issue
+	  ASTERISK-16981) Reported by: Mary Ciuciu, Byron Clark, Brad
+	  House, Karsten Wemheuer, KevinH Tested by: Matt Jordan Review:
+	  https://reviewboard.asterisk.org/r/1443 ........ ................
+
+2011-09-20 22:54 +0000 [r337121-337123]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_strings.c: Merged revisions 337119 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r337119 | rmudgett | 2011-09-20 17:47:45 -0500 (Tue, 20 Sep 2011)
+	  | 16 lines Fix crash with STRREPLACE function. The
+	  ast_func_read() function calls the .read2 callback with the len
+	  parameter set to zero indicating no size restrictions on the
+	  supplied ast_str buffer. The value was used to dimension a local
+	  starts[] array with the array subsequently used. * Reworked the
+	  strreplace() function to perform the string replacement in a
+	  straight forward manner. Eliminated the need for the starts[]
+	  array. (closes issue ASTERISK-18545) Reported by: Federico Alves
+	  Patches: jira_asterisk_18545_v10.patch (license #5621) patch
+	  uploaded by rmudgett Tested by: rmudgett, Federico Alves ........
+
+	* /: Updated 10 merge property.
+
+	* /: Restore branch-10 merge properties.
+
+2011-09-20 22:29 +0000 [r337117]  Leif Madsen <leif at leifmadsen.com>
+
+	* /, contrib/init.d/rc.redhat.asterisk: Merged revisions 337115 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337115 | lmadsen | 2011-09-20 17:18:25 -0500 (Tue, 20 Sep 2011)
+	  | 7 lines Update RedHat Init script to work with Heartbeat. The
+	  current RedHat init script was not LSB compatible. This change
+	  will make it LSB compatible so that it can work correctly with
+	  Heartbeat. (Closes issue ASTERISK-18253) Reported by: c0rnoTa
+	  ........
+
+2011-09-20 21:05 +0000 [r337063]  Kinsey Moore <kmoore at digium.com>
+
+	* main/pbx.c, /, tests/test_pbx.c: Merged revisions 337062 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337062 | kmoore | 2011-09-20 16:05:01 -0500
+	  (Tue, 20 Sep 2011) | 18 lines Merged revisions 337061 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337061 | kmoore | 2011-09-20 16:04:11 -0500 (Tue, 20 Sep 2011) |
+	  11 lines Make CANMATCH with the new pattern match engine behave
+	  more like the old one When checking an extension for E_CANMATCH
+	  using the new extension matching algorithm, an exact match was
+	  not returned as a possible match resulting in the queue failing
+	  to allow a caller to exit on DTMF. This removes the requirement
+	  that an extension be longer than acquired digits for an
+	  E_CANMATCH operation to succeed. (closes issue ASTERISK-18044)
+	  Review: https://reviewboard.asterisk.org/r/1367/ ........
+	  ................
+
+2011-09-20 19:13 +0000 [r336988-337009]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_ss7.c: Merged revisions 337008 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r337008 | rmudgett | 2011-09-20 14:12:24 -0500
+	  (Tue, 20 Sep 2011) | 22 lines Merged revisions 337007 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r337007 | rmudgett | 2011-09-20 14:10:30 -0500 (Tue, 20 Sep 2011)
+	  | 15 lines Check if a channel was created before using the
+	  pointer in sig_ss7_new_ast_channel(). Fixes the crash in
+	  ASTERISK-17955 gdb-11918.txt backtrace. * Added some missing
+	  libss7 access lock protection. * Prevent cancelling the
+	  ss7_linkset() thread at inoportune times just like the
+	  pri_dchannel() thread. (issue ASTERISK-17955) Reported by: Ian M
+	  Sherman Patches: jira_asterisk_17955_v1.8.patch (license #5621)
+	  patch uploaded by rmudgett (attached to related ASTERISK-17966)
+	  ........ ................
+
+	* /, channels/sig_ss7.c: Merged revisions 336978 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336978 | rmudgett | 2011-09-20 13:14:40 -0500
+	  (Tue, 20 Sep 2011) | 28 lines Merged revisions 336977 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336977 | rmudgett | 2011-09-20 13:12:17 -0500 (Tue, 20 Sep 2011)
+	  | 21 lines Fix deadlock from not releasing SS7 linkset lock.
+	  sig_ss7_hangup() failed to release the SS7 linkset lock if the
+	  call had the alreadyhungup flag set. * Made unlock the SS7
+	  linkset lock in sig_ss7_hangup() if the alreadyhungup flag is
+	  set. * Made ss7_start_call() not hold any locks while creating
+	  the channel for an incoming call to prevent deadlock. * Made
+	  ss7_grab() a void function, since it could never fail, to
+	  simplify calling code. * Made obtain the channel lock to do
+	  softhangup in some places. Patches: jira_ast_668_v1.8.patch
+	  (license #5621) patch uploaded by rmudgett JIRA AST-668 ........
+	  ................
+
+2011-09-20 16:56 +0000 [r336937]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* channels/sip/sdp_crypto.c, /, channels/chan_sip.c,
+	  channels/sip/include/sdp_crypto.h, channels/sip/include/srtp.h,
+	  configs/sip.conf.sample, CHANGES, channels/sip/include/sip.h:
+	  Merged revisions 336936 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r336936 | irroot | 2011-09-20 18:51:59 +0200 (Tue, 20 Sep 2011) |
+	  14 lines Allow Setting Auth Tag Bit length Based on invite or
+	  config option Update the SIP SRTP API to allow use of 32 or 80
+	  bit taglen. Curently only 80 bit is supported. The outgoing
+	  invite will use the taglen of the incoming invite preventing
+	  one-way audio. (Closes issue ASTERISK-17895) Review:
+	  https://reviewboard.asterisk.org/r/1173/ ........
+
+2011-09-20 01:11 +0000 [r336879]  Russell Bryant <russell at russellbryant.com>
+
+	* res/res_rtp_asterisk.c, /: Merged revisions 336878 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336878 | russell | 2011-09-19 20:03:55 -0500
+	  (Mon, 19 Sep 2011) | 43 lines Merged revisions 336877 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336877 | russell | 2011-09-19 19:56:20 -0500 (Mon, 19 Sep 2011)
+	  | 36 lines Fix crashes in ast_rtcp_write(). This patch addresses
+	  crashes related to RTCP handling. The backtraces just show a
+	  crash in ast_rtcp_write() where it appears that the RTP instance
+	  is no longer valid. There is a race condition with scheduled RTCP
+	  transmissions and the destruction of the RTP instance. This patch
+	  utilizes the fact that ast_rtp_instance is a reference counted
+	  object and ensures that it will not get destroyed while a
+	  reference is still around due to scheduled RTCP transmissions.
+	  RTCP transmissions are scheduled and executed from the chan_sip
+	  scheduler context. This scheduler context is processed in the SIP
+	  monitor thread. The destruction of an RTP instance occurs when
+	  the associated sip_pvt gets destroyed (which happens when the
+	  sip_pvt reference count reaches 0). However, the SIP monitor
+	  thread is not the only thread that can cause a sip_pvt to get
+	  destroyed. The sip_hangup function, executed from a channel
+	  thread, also decrements the reference count on a sip_pvt and
+	  could cause it to get destroyed. While this is being changed
+	  anyway, the patch also removes calling ast_sched_del() from
+	  within the RTCP scheduler callback. It's not helpful. Simply
+	  returning 0 prevents the callback from being rescheduled. (closes
+	  issue ASTERISK-18570) Related issues that look like they are the
+	  same problem: (issue ASTERISK-17560) (issue ASTERISK-15406)
+	  (issue ASTERISK-15257) (issue ASTERISK-13334) (issue
+	  ASTERISK-9977) (issue ASTERISK-9716) Review:
+	  https://reviewboard.asterisk.org/r/1444/ ........
+	  ................
+
+2011-09-19 22:28 +0000 [r336837]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 336792 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336792 | twilson | 2011-09-19 17:13:34 -0500
+	  (Mon, 19 Sep 2011) | 9 lines Merged revisions 336791 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r336791 | twilson | 2011-09-19 17:07:58 -0500 (Mon, 19
+	  Sep 2011) | 2 lines Don't interfere with T.38 reinvites This is
+	  an update to the fix for ASTERISK-18340 and ASTERISK-17725
+	  ........ ................
+
+2011-09-19 21:42 +0000 [r336735-336790]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, funcs/func_strings.c: Merged revisions 336789 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r336789 | tilghman | 2011-09-19 16:41:16 -0500 (Mon, 19 Sep 2011)
+	  | 2 lines Ensure substring will not be found in the previous
+	  match. ........
 
-	* /, apps/app_mixmonitor.c: Fix memory leaks (closes issue
-	  ASTERISK-22368) Reported by: Corey Farrell Patches:
-	  issueA22368_mixmonitor_free_filename.patch uploaded by wdoekes
-	  (license 5674) ........ Merged revisions 398004 from
-	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged
-	  revisions 398011 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398016 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/asterisk.c, /: Check return value on fwrite ........ Merged
-	  revisions 398000 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 398002 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 13:40 +0000 [r397987-397990]  David M. Lee <dlee at digium.com>
-
-	* rest-api-templates/swagger_model.py, res/ari/ari_websockets.c,
-	  channels/sip/include/sip.h, main/asterisk.c, res/res_ari.c,
-	  tests/test_optional_api.c (added), /, channels/chan_sip.c,
-	  include/asterisk/autoconfig.h.in, configure.ac,
-	  rest-api-templates/res_ari_resource.c.mustache,
-	  res/ari/internal.h, res/res_http_websocket.c, CHANGES,
-	  include/asterisk/compiler.h, include/asterisk/ari.h,
-	  main/loader.c, include/asterisk/optional_api.h,
-	  build_tools/cflags.xml, configure, res/res_ari_events.c,
-	  include/asterisk/http_websocket.h, main/optional_api.c (added):
-	  optional_api: Fix linking problems between modules that export
-	  global symbols With the new work in Asterisk 12, there are some
-	  uses of the optional_api that are prone to failure. The details
-	  are rather involved, and captured on [the wiki][1]. This patch
-	  addresses the issue by removing almost all of the magic from the
-	  optional API implementation. Instead of relying on weak symbol
-	  resolution, a new optional_api.c module was added to Asterisk
-	  core. For modules providing an optional API, the pointer to the
-	  implementation function is registered with the core. For modules
-	  that use an optional API, a pointer to a stub function, along
-	  with a optional_ref function pointer are registered with the
-	  core. The optional_ref function pointers is set to the
-	  implementation function when it's provided, or the stub function
-	  when it's now. Since the implementation no longer relies on
-	  magic, it is now supported on all platforms. In the spirit of
-	  choice, an OPTIONAL_API flag was added, so we can disable the
-	  optional_api if needed (maybe it's buggy on some bizarre platform
-	  I haven't tested on) The AST_OPTIONAL_API*() macros themselves
-	  remained unchanged, so existing code could remain unchanged. But
-	  to help with debugging the optional_api, the patch limits the
-	  #include of optional API's to just the modules using the API.
-	  This also reduces resource waste maintaining optional_ref
-	  pointers that aren't used. Other changes made as a part of this
-	  patch: * The stubs for http_websocket that wrap system calls set
-	  errno to ENOSYS. * res_http_websocket now properly increments
-	  module use count. * In loader.c, the while() wrappers around
-	  dlclose() were removed. The while(!dlclose()) is actually an
-	  anti-pattern, which can lead to infinite loops if the module
-	  you're attempting to unload exports a symbol that was directly
-	  linked to. * The special handling of nonoptreq on systems without
-	  weak symbol support was removed, since we no longer rely on weak
-	  symbols for optional_api. [1]:
-	  https://wiki.asterisk.org/wiki/x/wACUAQ (closes issue
-	  ASTERISK-22296) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2797/ ........ Merged
-	  revisions 397989 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_stasis_playback.c, /,
-	  include/asterisk/stasis_app_recording.h,
-	  res/ari/resource_recordings.h, res/res_stasis_recording.c,
-	  res/Makefile, res/ari/ari_model_validators.c,
-	  rest-api/api-docs/recordings.json, res/stasis_recording (added),
-	  res/ari/resource_recordings.c, res/ari/ari_model_validators.h,
-	  res/res_ari_recordings.c: ARI: Implement /recordings/stored API's
-	  his patch implements the ARI API's for stored recordings. While
-	  the original task only specified deleting a recording, it was
-	  simple enough to implement the GET for all recordings, and for an
-	  individual recording. The recording playback operation was
-	  modified to use the same code for accessing the recording as the
-	  REST API, so that they will behave consistently. There were
-	  several problems with the api-docs that were also fixed, bringing
-	  the ARI spec in line with the implementation. There were some
-	  'wishful thinking' fields on the stored recording model (duration
-	  and timestamp) that were removed, because I ended up not
-	  implementing a metadata file to go along with the recording to
-	  store such information. The GET /recordings/live operation was
-	  removed, since it's not really that useful to get a list of all
-	  recordings that are currently going on in the system. (At least,
-	  if we did that, we'd probably want to also list all of the
-	  current playbacks. Which seems weird.) (closes issue
-	  ASTERISK-21582) Review: https://reviewboard.asterisk.org/r/2693/
-	  ........ Merged revisions 397985 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /: Multiple revisions 397975-397976 ........ r397975 | rmudgett |
-	  2013-08-29 20:00:00 -0500 (Thu, 29 Aug 2013) | 1 line pbx.c: Make
-	  ast_str_substitute_variables_full() not mask variables. ........
-	  r397976 | rmudgett | 2013-08-29 20:00:41 -0500 (Thu, 29 Aug 2013)
-	  | 1 line Revert last commit. ........ Merged revisions
-	  397975-397976 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 01:20 +0000 [r397978]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/pbx.c, /: pbx.c: Make pbx_substitute_variables_helper_full()
-	  not mask variables. ........ Merged revisions 397977 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-30 00:11 +0000 [r397962-397969]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip_pidf.c, /: Sanitize XML output for PIDF bodies.
-	  PJSIP's PIDF API does not replace angle brackets with their
-	  appropriate counterparts for XML. So we have to do it ourself. In
-	  this particular case, the problem had to do with attempting to
-	  place an unsanitized SIP URI into an XML node. Now we don't get a
-	  488 from recipients of our PIDF NOTIFYs. ........ Merged
-	  revisions 397968 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_pidf.c, /: Fix method for creating activities
-	  string in PIDF bodies. The previous method did not allocate
-	  enough space to create the entire string, but adjusted the
-	  string's slen value to be larger than the actual allocation. This
-	  resulted in garbled text in NOTIFY requests from Asterisk. This
-	  method allocates the proper amount of space first and then writes
-	  the content into the buffer. ........ Merged revisions 397960
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 22:49 +0000 [r397959]  Kevin Harwell <kharwell at digium.com>
-
-	* apps/app_dumpchan.c, main/logger.c, apps/app_verbose.c,
-	  main/asterisk.c, channels/chan_misdn.c, /: Verbose logging
-	  discrepancies Refactored cases where a combination of
-	  ast_verbose/options_verbose were present. Also in general tried
-	  to eliminate, in as many places as possible, where the
-	  options_verbose global variable was being used. Refactored the
-	  way local and remote consoles handle verbose message logging in
-	  an attempt to solve the various discrepancies that sometimes
-	  would show between the two. (closes issue AST-1193) Reported by:
-	  Guenther Kelleter Review:
-	  https://reviewboard.asterisk.org/r/2798/ ........ Merged
-	  revisions 397948 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 397958 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 22:26 +0000 [r397956-397957]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip_pubsub.c: Fix when the subscription_terminated
-	  callback is called for subscription handlers. The previous
-	  placement would result in the resubscribe() callback called
-	  instead of the subscription_terminated() callback being called
-	  when a subscription was ended via a SUBSCRIBE request. This would
-	  result in confusing PJSIP and having it throw an assertion.
-	  ........ Merged revisions 397955 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* res/res_pjsip_session.c, /: Fix a race condition where a canceled
-	  call was answered. RFC 5407 section 3.1.2 details a scenario
-	  where a UAC sends a CANCEL at the same time that a UAS sends a
-	  200 OK for the INVITE that the UAC is canceling. When this
-	  occurs, it is the role of the UAC to immediately send a BYE to
-	  terminate the call. This scenario was reproducible by have a
-	  Digium phone with two lines place a call to a second phone that
-	  forwarded the call to the second line on the original phone. The
-	  Digium phone, upon realizing that it was connecting to itself,
-	  would attempt to cancel the call. The timing of this happened to
-	  trigger the aforementioned race condition about 80% of the time.
-	  Asterisk was not doing its job of sending a BYE when receiving a
-	  200 OK on a cancelled INVITE. The result was that the ast_channel
-	  structure was destroyed but the underlying SIP session, as well
-	  as the PJSIP inv_session and dialog, were still alive. Attempting
-	  to perform an action such as a transfer, once in this state,
-	  would result in Asterisk crashing. The circumstances are now
-	  detected properly and the session is ended as recommended in RFC
-	  5407. (closes issue AST-1209) reported by John Bigelow ........
-	  Merged revisions 397945 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 21:37 +0000 [r397947]  Kevin Harwell <kharwell at digium.com>
-
-	* main/file.c, main/app.c, main/config_options.c, main/cel.c,
-	  main/asterisk.c, main/cdr.c, main/manager.c, /,
-	  main/stasis_config.c: Memory leaks fix (closes ASTERISK-22376)
-	  Reported by: John Hardin Patches: memleak.patch uploaded by
-	  jhardin (license 6512) memleak2.patch uploaded by jhardin
-	  (license 6512) ........ Merged revisions 397946 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 20:22 +0000 [r397939]  Matthew Jordan <mjordan at digium.com>
-
-	* configs/safe_asterisk.conf.sample (removed), /, CHANGES,
-	  contrib/scripts/safe_asterisk, Makefile: Revert r394939 due to
-	  (numerous) objections The patch from ASTERISK-21965 was committed
-	  perhaps a bit too hastily. Walter and Tzafrir have pointed out
-	  numerous issues with the approach and have propsed an alternative
-	  in r/2757. Since it's not a time critical issue and is not worth
-	  holding up the release of 12 for it, I've gone ahead and reverted
-	  r394939 from 12/trunk and re-opened ASTERISK-21965. ........
-	  Merged revisions 397938 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 16:21 +0000 [r397932]  David M. Lee <dlee at digium.com>
-
-	* rest-api-templates/make_ari_stubs.py, /,
-	  rest-api-templates/api.wiki.mustache,
-	  rest-api-templates/asterisk_processor.py: Account for {} in
-	  Swagger notes ........ Merged revisions 397927 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 16:05 +0000 [r397925]  Matthew Jordan <mjordan at digium.com>
-
-	* Makefile, /: Recursively search for '.c' files when making
-	  documentation with 'make full' Without this, documentation
-	  defined in sub-folders is ignored. Since having properly
-	  generated documentation is especially important in Asterisk 12 -
-	  not having it can cause a module to not load - 'make full' needs
-	  to look in all .c files. ........ Merged revisions 397924 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 15:43 +0000 [r397923]  Mark Michelson <mmichelson at digium.com>
-
-	* /, apps/app_queue.c, main/cel.c, main/stasis_bridges.c: Multiple
-	  revisions 397921-397922 ........ r397921 | mmichelson |
-	  2013-08-29 10:42:10 -0500 (Thu, 29 Aug 2013) | 6 lines Resolve
-	  assumptions that bridge snapshots would be non-NULL for transfer
-	  stasis events. Attempting to transfer an unbridged call would
-	  result in crashes in either CEL code or in the conversion to AMI
-	  messages. ........ r397922 | mmichelson | 2013-08-29 10:42:29
-	  -0500 (Thu, 29 Aug 2013) | 3 lines Remove extra debug message.
-	  ........ Merged revisions 397921-397922 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-29 12:30 +0000 [r397912]  Matthew Jordan <mjordan at digium.com>
-
-	* contrib/ast-db-manage/config,
-	  contrib/ast-db-manage/config/script.py.mako,
-	  contrib/ast-db-manage/voicemail.ini.sample,
-	  contrib/ast-db-manage/voicemail/env.py,
-	  contrib/ast-db-manage/voicemail,
-	  contrib/ast-db-manage/voicemail/script.py.mako,
-	  contrib/ast-db-manage/README.md,
-	  contrib/ast-db-manage/config/versions,
-	  contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py,
-	  contrib/ast-db-manage (added),
-	  contrib/ast-db-manage/voicemail/versions, /,
-	  contrib/ast-db-manage/config.ini.sample,
-	  contrib/ast-db-manage/config/env.py,
-	  contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py:
-	  Actually *add* the database schema management utilities In
-	  r397874, the scripts were removed... but not replaced. Thanks to
-	  Michael Young for noticing this! ........ Merged revisions 397911
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-28 23:15 +0000 [r397886-397903]  Richard Mudgett <rmudgett at digium.com>
-
-	* main/cdr.c, /, funcs/func_cdr.c, main/stdtime/localtime.c: Fix
-	  some uninitialized buffers for CDR handling valgrind found. *
-	  Made ast_strftime_locale() ensure that the output buffer is
-	  initialized. The std library strftime() returns 0 and does not
-	  touch the buffer if it has an error. However, the function can
-	  also return 0 without an error. (closes issue ASTERISK-22412)
-	  Reported by: rmudgett ........ Merged revisions 397902 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: Fixed problems with ast_cdr_serialize_variables().
-	  * Fixed return value of ast_cdr_serialize_variables() on error.
-	  It needs to return 0 indicating no CDR variables found. * Made
-	  ast_cdr_serialize_variables() check the return value of
-	  cdr_object_format_property() and assert if nonzero. A member of
-	  the cdr_readonly_vars[] was not handled. * Removed unused
-	  elements from cdr_readonly_vars[]: total_duration, total_billsec,
-	  first_start, and first_answer. ........ Merged revisions 397900
-	  from http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: Made the on/off in CLI "cdr set debug [on|off]"
-	  case insensitive. ........ Merged revisions 397898 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/cdr.c, /: Make CDR variable name chandling consistently case
-	  insensitive. ........ Merged revisions 397896 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, main/cdr.c: Make CDR code deal with channel names case
-	  insensitively. ........ Merged revisions 397894 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, funcs/func_cdr.c, main/cdr.c: Some CDR code optimization.
-	  ........ Merged revisions 397892 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, funcs/func_cdr.c: Whitespace and curly braces. ........ Merged
-	  revisions 397885 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-28 21:09 +0000 [r397877]  Mark Michelson <mmichelson at digium.com>
-
-	* /, res/res_pjsip_refer.c: Improve detection of answer on SIP
-	  blind transfer. A problem encountered during testing was that
-	  res_pjsip_refer would not ever send a NOTIFY with a 200 OK
-	  sipfrag. This is because the framehook that was supposed to send
-	  the NOTIFY would never be told that an answer had occurred. This
-	  happened for two reasons: 1) The transferee channel on which the
-	  framehook was on was already up. 2) Answers are rarely if ever
-	  written to channels. Rather, the ast_answer() or ast_raw_answer()
-	  function is used to answer channels. Thanks to a suggestion by
-	  Matt Jordan, the best way to detect that the call had been
-	  answered was to find out when the transferee channel joined a
-	  bridge. With stasis this is an easy task. So now, in addition to
-	  the framehook logic, there is a stasis subscription used to
-	  determine when the transferee has entered a bridge. Once it has
-	  entered, an appropriate NOTIFY is sent. ........ Merged revisions
-	  397876 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-28 20:55 +0000 [r397872-397875]  Matthew Jordan <mjordan at digium.com>
-
-	* contrib/realtime/mysql/queue_log.sql,
-	  contrib/realtime/mysql/voicemail.sql,
-	  contrib/realtime/mysql/sippeers.sql, /,
-	  contrib/realtime/mysql/iaxfriends.sql,
-	  contrib/realtime/mysql/meetme.sql,
-	  contrib/realtime/mysql/voicemail_messages.sql,
+	* Makefile, /, configure, include/asterisk/autoconfig.h.in,
+	  main/Makefile, codecs/gsm/Makefile, configure.ac, Makefile.rules,
+	  include/asterisk/optional_api.h: Merged revisions 336734 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336734 | tilghman | 2011-09-19 15:29:40 -0500
+	  (Mon, 19 Sep 2011) | 18 lines Merged revisions 336733 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336733 | tilghman | 2011-09-19 15:27:03 -0500 (Mon, 19 Sep 2011)
+	  | 11 lines Various changes to allow 1.8 to compile on Mac OS X
+	  Lion (10.7) * Makefile workaround for 10.6 extended to work on
+	  10.7 and later. * Now uses the 'weak' symbol for Lion systems,
+	  which no longer support 'weak_import' Closes ASTERISK-17612.
+	  Closes ASTERISK-18213. Tested by: tilghman, oej. ........
+	  ................
+
+2011-09-19 20:23 +0000 [r336732]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_echo.c, apps/app_saycounted.c, apps/app_mp3.c,
+	  apps/app_morsecode.c, res/res_musiconhold.c, apps/app_queue.c,
+	  apps/app_mixmonitor.c: Merged revisions 336717 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336717 | jrose | 2011-09-19 15:16:23 -0500
+	  (Mon, 19 Sep 2011) | 14 lines Merged revisions 336716 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336716 | jrose | 2011-09-19 15:07:36 -0500 (Mon, 19 Sep 2011) |
+	  7 lines Document applications that play audio and do not answer
+	  unanswered calls. This patch is part of an effort to document
+	  early media and its usage. If you are interested in contributing
+	  to this documentation effort, there are probably other
+	  applications worth documenting as well as an Asterisk wiki
+	  article at
+	  https://wiki.asterisk.org/wiki/display/AST/Early+Media+and+the+Progress+Application
+	  ........ ................
+
+2011-09-19 19:03 +0000 [r336660-336662]  Richard Mudgett <rmudgett at digium.com>
+
+	* apps/app_dial.c, /, UPGRADE-1.8.txt: Merged revisions 336659 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336659 | rmudgett | 2011-09-19 13:51:19 -0500
+	  (Mon, 19 Sep 2011) | 38 lines Merged revisions 336658 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336658 | rmudgett | 2011-09-19 13:46:40 -0500 (Mon, 19 Sep 2011)
+	  | 31 lines Made Dial d and H options no longer immediately
+	  auto-answer the calling leg. The Dial d and H options break DTMF
+	  attended transfer atxferdropcall option. 1) Party A calls party
+	  B. 2) Party B does a DTMF attended transfer to Party C. If the
+	  dialplan uses the Dial d or H options to call Party C then the
+	  Dial application answers the call immediately before initiating
+	  the call leg to Party C. The premature answer causes the transfer
+	  code to not invoke the atxferdropcall=no behavior for a blonde
+	  transfer since Party C has "answered". The transfer code thinks
+	  that Party B has "consulted" with Party C when Party B hangs up
+	  and completes the transfer to Party A. Party A now hears ringback
+	  until Party C actually answers. ASTERISK-13294 Dial d option.
+	  ASTERISK-11067 Dial H option to disconnect before answer. The
+	  referenced issues made Dial answer with the d and H options
+	  because many SIP and ISDN phones cannot send DTMF before the call
+	  is connected. * Made require the dialplan to control when or if
+	  the call needs to be answered to use the Dial application d and H
+	  options. (The call is no longer surprise answered when using the
+	  Dial d or H options.) Review:
+	  https://reviewboard.asterisk.org/r/1381/ JIRA AST-623 JIRA
+	  AST-666 ........ ................
+
+	* /: Update merge 10 branch merge propterty.
+
+	* /: Restore 10 branch merge properties.
+
+2011-09-19 16:22 +0000 [r336600]  Jason Parker <jparker at digium.com>
+
+	* cel/cel_odbc.c, configs/cel_odbc.conf.sample, sounds/Makefile:
+	  Remove weird mergeinfo props that make merges annoying sometimes.
+
+2011-09-19 15:48 +0000 [r336574]  Leif Madsen <leif at leifmadsen.com>
+
+	* /, contrib/scripts/get_ilbc_source.sh: Merged revisions 336572
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336572 | lmadsen | 2011-09-19 10:41:16 -0500 (Mon, 19 Sep 2011)
+	  | 7 lines Update get_ilbc_source.sh script to work again.
+	  Recently iLBC support in Asterisk has changed after the
+	  acquisition of GIPS by Google. More information about how this
+	  may affect you is available in a blog post at:
+	  http://blogs.asterisk.org/2011/09/19/ilbc-support-in-asterisk-after-googles-acquisition-of-gips/
+	  ........
+
+2011-09-19 15:36 +0000 [r336571]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Merged revisions 336570 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336570 | rmudgett | 2011-09-19 10:32:00 -0500
+	  (Mon, 19 Sep 2011) | 11 lines Merged revisions 336569 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336569 | rmudgett | 2011-09-19 10:25:34 -0500 (Mon, 19 Sep 2011)
+	  | 4 lines Rework sig_pri_hangup() to be simpler and clearer. JIRA
+	  AST-675 ........ ................
+
+2011-09-19 13:57 +0000 [r336505]  Olle Johansson <oej at edvina.net>
+
+	* /, channels/chan_sip.c: Merged revisions 336502 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336502 | oej | 2011-09-19 15:38:53 +0200 (Mån,
+	  19 Sep 2011) | 12 lines Merged revisions 336501 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336501 | oej | 2011-09-19 15:33:50 +0200 (Mån, 19 Sep 2011) | 5
+	  lines Add diversion header to a 302 redirect response if we have
+	  diversion data (closes issue ASTERISK-18143) patch by oej
+	  ........ ................
+
+2011-09-19 13:41 +0000 [r336503]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, channels/chan_h323.c: Merged revisions 336500 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336500 | irroot | 2011-09-19 15:31:50 +0200
+	  (Mon, 19 Sep 2011) | 19 lines Merged revisions 336499 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336499 | irroot | 2011-09-19 15:27:52 +0200 (Mon, 19 Sep 2011) |
+	  13 lines A long time ago in a galaxy far far away a IPv6 update
+	  was made, chan_h323 was not updated causeing all to flee to
+	  chan_ooh323. the brave Jedi [asterisk developers] pondered this
+	  miscarrige of justice and restored order to the force for the
+	  sake of closing out 2 old issues. (closes issue ASTERISK-17278)
+	  (closes issue ASTERISK-17500) Reported by: dread, sybasesql
+	  Tested by: irroot Reviewed by: IRC (russellb, kpfleming) ........
+	  ................
+
+2011-09-19 12:20 +0000 [r336382-336453]  Olle Johansson <oej at edvina.net>
+
+	* main/manager.c, /: Merged revisions 336441 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336441 | oej | 2011-09-19 14:15:06 +0200 (Mån,
+	  19 Sep 2011) | 9 lines Merged revisions 336440 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336440 | oej | 2011-09-19 14:06:48 +0200 (Mån, 19 Sep 2011) | 2
+	  lines Make sure manager_debug option is reset at reload ........
+	  ................
+
+	* /, channels/chan_sip.c: Merged revisions 336381 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336381 | oej | 2011-09-19 12:05:00 +0200 (Mån,
+	  19 Sep 2011) | 16 lines Merged revisions 336378 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336378 | oej | 2011-09-19 11:40:44 +0200 (Mån, 19 Sep 2011) | 9
+	  lines Add missing unlock at MWI message sending time (closes
+	  issue ASTERISK-18573) Patches: sip_mwi_lock.patch (license #5041)
+	  by Gregory Hinton Nietsky Thanks to irrot for the reminder, to
+	  Gregory for the patch! ........ ................
+
+2011-09-16 22:12 +0000 [r336315-336317]  Terry Wilson <twilson at digium.com>
+
+	* /, funcs/func_frame_trace.c: Merged revisions 336316 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336316 | twilson | 2011-09-16 17:11:39 -0500
+	  (Fri, 16 Sep 2011) | 9 lines Merged revisions 336314 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r336314 | twilson | 2011-09-16 17:10:56 -0500 (Fri, 16
+	  Sep 2011) | 2 lines Whitespace fix ........ ................
+
+	* /, funcs/func_frame_trace.c: Merged revisions 336313 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336313 | twilson | 2011-09-16 17:07:00 -0500
+	  (Fri, 16 Sep 2011) | 12 lines Merged revisions 336312 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336312 | twilson | 2011-09-16 17:04:25 -0500 (Fri, 16 Sep 2011)
+	  | 5 lines Add missing frame types to func_frame_trace Also casts
+	  control frames to the proper enum so that the compile will catch
+	  new additions. ........ ................
+
+2011-09-16 21:20 +0000 [r336311]  Jonathan Rose <jrose at digium.com>
+
+	* main/channel.c, main/rtp_engine.c, /, channels/chan_sip.c,
+	  include/asterisk/frame.h: Merged revisions 336307 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336307 | jrose | 2011-09-16 16:09:20 -0500
+	  (Fri, 16 Sep 2011) | 20 lines Merged revisions 336294 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336294 | jrose | 2011-09-16 14:53:40 -0500 (Fri, 16 Sep 2011) |
+	  13 lines Fix bad RTP media bridges in directmedia calls on peers
+	  separated by multiple Asterisk nodes. In a situation involving
+	  devices on separate Asterisk trunks, the remote RTP bridge would
+	  break when starting a call with directmedia. This patch queues a
+	  new type of control frame so that our RTP bridge loop can
+	  properly detect when these situations occur and check to see if
+	  peers need to be updated in order to send their media to the
+	  proper location. (Closes issue ASTERISK-18340) Reported by:
+	  Thomas Arimont (Closes issue ASTERISK-17725) Reported by: kwk
+	  Tested by: twilson, jrose ........ ................
+
+2011-09-16 19:11 +0000 [r336236]  Sean Bright <sean at malleable.com>
+
+	* /, UPGRADE-1.8.txt: Merged revisions 336235 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336235 | seanbright | 2011-09-16 15:10:39 -0400
+	  (Fri, 16 Sep 2011) | 9 lines Merged revisions 336234 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r336234 | seanbright | 2011-09-16 15:06:27 -0400 (Fri,
+	  16 Sep 2011) | 2 lines Make a note that inotify won't work with
+	  an NFS mounted spooler directory. ........ ................
+
+2011-09-16 10:16 +0000 [r336095-336168]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* channels/chan_misdn.c, /: Merged revisions 336167 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336167 | irroot | 2011-09-16 12:12:03 +0200
+	  (Fri, 16 Sep 2011) | 22 lines Merged revisions 336166 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336166 | irroot | 2011-09-16 12:09:17 +0200 (Fri, 16 Sep 2011) |
+	  16 lines The round robin routing routine in chan_misdn.c is
+	  broken. it rotates between ports but never checks the channels in
+	  the ports. i have extensivly tested it and verified it works on 1
+	  upto 4 ports. before the patch only 1 out of each port was used
+	  now all are used as expected. (closes issue ASTERISK-18413)
+	  Reported by: irroot Tested by: irroot Reviewed by: irroot Review:
+	  https://reviewboard.asterisk.org/r/1410/ ........
+	  ................
+
+	* /, apps/app_queue.c: Merged revisions 336094 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r336094 | irroot | 2011-09-15 17:54:46 +0200
+	  (Thu, 15 Sep 2011) | 26 lines Merged revisions 336093 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r336093 | irroot | 2011-09-15 17:46:21 +0200 (Thu, 15 Sep 2011) |
+	  20 lines Locking order in app_queue.c causes deadlocks. a channel
+	  lock must never be held with the queues container lock held. the
+	  deadlock occured on masquerade. the queues container lock is a
+	  relic of the past the old queue module lock. with ao2 there is no
+	  need to hold this lock when dealing with members this patch
+	  removes unneeded locks. (closes issue ASTERISK-18101) (closes
+	  issue ASTERISK-18487) Reported by: Paul Rolfe, Jason Legault
+	  Tested by: irroot, Jason Legault, Paul Rolfe Reviewed by: Matthew
+	  Nicholson Review: https://reviewboard.asterisk.org/r/1402/
+	  ........ ................
+
+2011-09-15 15:19 +0000 [r336092]  David Vossel <dvossel at digium.com>
+
+	* /, main/format_cap.c: Merged revisions 336091 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r336091 | dvossel | 2011-09-15 10:19:10 -0500 (Thu, 15 Sep 2011)
+	  | 2 lines Removes some no-op code found in format_cap.c. ........
+
+2011-09-15 12:50 +0000 [r336043]  Olle Johansson <oej at edvina.net>
+
+	* CREDITS, /, apps/app_meetme.c, CHANGES: Merged revisions 336042
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r336042 | oej | 2011-09-15 14:46:38 +0200 (Tor, 15 Sep 2011) | 12
+	  lines Meetme: Introducing a new option "k" to kill a conference
+	  if there's only a single member left. When using Meetme as a
+	  modular call bridge from third party applications, it's handy to
+	  make it behave like a normal call bridge. When the second to last
+	  person exists, the last person will be kicked out of the
+	  conference when this option is enabled. (closes issue
+	  ASTERISK-18234) Review: https://reviewboard.asterisk.org/r/1376/
+	  Patch by oej, sponsored by ClearIT, Solna, Sweden ........
+
+2011-09-15 08:40 +0000 [r335993]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, channels/chan_agent.c: Merged revisions 335991 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335991 | irroot | 2011-09-15 10:29:12 +0200
+	  (Thu, 15 Sep 2011) | 17 lines Merged revisions 335978 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335978 | irroot | 2011-09-15 10:15:22 +0200 (Thu, 15 Sep 2011) |
+	  11 lines lock the channel before calling ast_bridged_channel() to
+	  prevent a seg fault. AMI agents list called on shutdown causes a
+	  segfault, introducing proper locking will prevent this. (closes
+	  issue ASTERISK-18092) Reported by: agustina Patches:
+	  chan_agent.patch (License #5041) patch uploaded by irroot
+	  ........ ................
+
+2011-09-14 18:38 +0000 [r335853-335913]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, configure, include/asterisk/autoconfig.h.in, configure.ac:
+	  Merged revisions 335912 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335912 | rmudgett | 2011-09-14 13:31:15 -0500
+	  (Wed, 14 Sep 2011) | 20 lines Merged revisions 335911 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335911 | rmudgett | 2011-09-14 13:21:35 -0500 (Wed, 14 Sep 2011)
+	  | 13 lines Remove unnecessary libpri dependency checks in the
+	  configure script. Using the --with-pri option with the configure
+	  script generated an error about not having PRI_L2_PERSISTENCE if
+	  you did not have the absolute latest libpri SVN checkout
+	  installed. The AST_EXT_LIB_SETUP_DEPENDENT macro in the
+	  configure.ac script seems to be for libraries that are dependent
+	  upon other libraries and not necessarily for optional/added
+	  features within a library. (closes issue ASTERISK-18535) Reported
+	  by: Michael Keuter ........ ................
+
+	* channels/chan_dahdi.c, /: Merged revisions 335852 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335852 | rmudgett | 2011-09-14 11:00:37 -0500
+	  (Wed, 14 Sep 2011) | 18 lines Merged revisions 335851 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335851 | rmudgett | 2011-09-14 10:53:25 -0500 (Wed, 14 Sep 2011)
+	  | 11 lines Fixed cut-n-paste regression using the wrong variable.
+	  Fixes the missing DAHDI channels when using the newer
+	  chan_dahdi.conf sections for channel configuration. (closes issue
+	  ASTERISK-18496) Reported by: Sean Darcy Patches:
+	  jira_asterisk_18496_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: Sean Darcy, rmudgett ........
+	  ................
+
+2011-09-14 13:29 +0000 [r335792]  Matthew Nicholson <mnicholson at digium.com>
+
+	* main/manager.c, /: Merged revisions 335791 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335791 | mnicholson | 2011-09-14 08:28:50 -0500
+	  (Wed, 14 Sep 2011) | 11 lines Merged revisions 335790 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335790 | mnicholson | 2011-09-14 08:28:16 -0500 (Wed, 14 Sep
+	  2011) | 4 lines The tech and data members of
+	  fast_originate_helper are not string fields. ASTERISK-17709
+	  ........ ................
+
+2011-09-13 22:11 +0000 [r335722]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_directed_pickup.c: Merged revisions 335721 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335721 | rmudgett | 2011-09-13 17:10:44 -0500
+	  (Tue, 13 Sep 2011) | 9 lines Merged revisions 335720 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r335720 | rmudgett | 2011-09-13 17:10:15 -0500 (Tue, 13
+	  Sep 2011) | 1 line Remove obsolete todo comment about
+	  PICKUPRESULT. ........ ................
+
+2011-09-13 21:52 +0000 [r335719]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* main/dnsmgr.c: Additional updates for parsing dnsmgr.conf Review:
+	  https://reviewboard.asterisk.org/r/1432/
+
+2011-09-13 21:40 +0000 [r335718]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* main/asterisk.c: do parse defaultlanguage from asterisk.conf Do
+	  parse the option "defaultlanguage" from the [options] section of
+	  asterisk.conf, as in the sample config file. Otherwise the
+	  build-time default language (normally "en") is always the default
+	  one. Review: https://reviewboard.asterisk.org/r/1342/
+	  Signed-off-by: Tzafrir Cohen (License #5035)
+	  <tzafrir.cohen at xorcom.com> Original-Commit:
+	  http://svn.digium.com/svn/asterisk/branches/1.8@335716
+	  Original-Commit:
+	  http://svn.digium.com/svn/asterisk/branches/10@335717
+
+2011-09-13 18:56 +0000 [r335657]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, configure, configure.ac: Merged revisions 335656 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335656 | tilghman | 2011-09-13 13:55:33 -0500
+	  (Tue, 13 Sep 2011) | 11 lines Merged revisions 335655 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335655 | tilghman | 2011-09-13 13:52:38 -0500 (Tue, 13 Sep 2011)
+	  | 4 lines Move mandatory checks closer to the beginning of the
+	  file. If these are going to fail, they should fail as quickly as
+	  possible. ........ ................
+
+2011-09-13 18:49 +0000 [r335654]  Matthew Nicholson <mnicholson at digium.com>
+
+	* main/pbx.c, main/manager.c, /: Merged revisions 335653 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335653 | mnicholson | 2011-09-13 13:47:57 -0500
+	  (Tue, 13 Sep 2011) | 12 lines Merged revisions 335618 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335618 | mnicholson | 2011-09-13 13:20:52 -0500 (Tue, 13 Sep
+	  2011) | 5 lines Don't limit the size of appdata for manager
+	  originate actions. ASTERISK-17709 Patch by: tilghman (with
+	  modifications) ........ ................
+
+2011-09-13 18:11 +0000 [r335555-335603]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* UPGRADE.txt, main/dsp.c: Clean up dsp.conf parsing Review:
+	  https://reviewboard.asterisk.org/r/1434/
+
+	* UPGRADE.txt, cdr/cdr_csv.c: Clean up cdr.conf parsing for [csv]
+	  section Review: https://reviewboard.asterisk.org/r/1427/
+
+	* main/dnsmgr.c, UPGRADE.txt: Clean up dnsmgr.conf parsing Review:
+	  https://reviewboard.asterisk.org/r/1432/
+
+2011-09-13 07:35 +0000 [r335511]  Russell Bryant <russell at russellbryant.com>
+
+	* include/asterisk/event.h, /, res/ais/evt.c, main/event.c: Merged
+	  revisions 335510 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335510 | russell | 2011-09-13 02:24:34 -0500
+	  (Tue, 13 Sep 2011) | 22 lines Merged revisions 335497 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335497 | russell | 2011-09-13 02:11:36 -0500 (Tue, 13 Sep 2011)
+	  | 15 lines Fix a crash in res_ais. This patch resolves a crash
+	  observed in a load testing environment that involved the use of
+	  the res_ais module. I observed some crashes where the event
+	  delivery callback would get called, but the length parameter
+	  incidcating how much data there was to read was 0. The code
+	  assumed (with good reason I would think) that if this callback
+	  got called, there was an event available to read. However, if the
+	  rare case that there's nothing there, catch it and return instead
+	  of blowing up. More specifically, the change always ensure that
+	  the size of the received event in the cluster is always big
+	  enough to be a real ast_event. Review:
+	  https://reviewboard.asterisk.org/r/1423/ ........
+	  ................
+
+2011-09-12 15:56 +0000 [r335435]  Matthew Nicholson <mnicholson at digium.com>
+
+	* main/channel.c, /: Merged revisions 335434 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335434 | mnicholson | 2011-09-12 10:55:48 -0500
+	  (Mon, 12 Sep 2011) | 13 lines Merged revisions 335433 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335433 | mnicholson | 2011-09-12 10:54:41 -0500 (Mon, 12 Sep
+	  2011) | 6 lines Properly set caller_warning and callee_warning
+	  before we try to use them. ASTERISK-18199 Patch by: elguero
+	  Testing by: rtang ........ ................
+
+2011-09-12 14:33 +0000 [r335385]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_sip.c: Documentation updates
+
+2011-09-12 14:24 +0000 [r335354]  Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_dial.c, /: Merged revisions 335346 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335346 | kmoore | 2011-09-12 09:22:15 -0500
+	  (Mon, 12 Sep 2011) | 17 lines Merged revisions 335341 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335341 | kmoore | 2011-09-12 09:21:17 -0500 (Mon, 12 Sep 2011) |
+	  10 lines Ensure frames are not written to dialed channel if
+	  ringback is requested When a single channel was dialed and there
+	  was media to be forwarded to the calling channel, the media was
+	  written without regard for ringback causing silence to be heard
+	  in some circumstances. This regression was introduced when the
+	  meaning of "single" changed to mean only the number of channels
+	  dialed. (closes issue ASTERISK-18083) ........ ................
+
+2011-09-12 14:22 +0000 [r335324-335349]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_sip.c: Small documentation updates
+
+	* CREDITS, channels/chan_sip.c, include/asterisk/indications.h,
+	  UPGRADE.txt, configs/sip.conf.sample, channels/sip/include/sip.h:
+	  New sip.conf option for setting default tonezone for channel or
+	  individual devices Review:
+	  https://reviewboard.asterisk.org/r/1429/ (closes issue
+	  ASTERISK-18497) Thanks to russellb for peer review.
+
+	* /, channels/chan_sip.c: Merged revisions 335323 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335323 | oej | 2011-09-12 15:47:13 +0200 (Mån,
+	  12 Sep 2011) | 19 lines Merged revisions 335319 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335319 | oej | 2011-09-12 15:25:30 +0200 (Mån, 12 Sep 2011) | 12
+	  lines Lock the peer->mvipvt to avoid crashes with SIP history
+	  enabled After the launch of 1.6 event-based MWI we have two
+	  threads handling the peer->mwipvt, which cause issues with SIP
+	  history additions in combination with the max limit for number of
+	  history entries. Review: https://reviewboard.asterisk.org/r/1373/
+	  (closes issue ASTERISK-18288) Thanks to irrot for peer review.
+	  Work with this bug funded by IPvision AS ........
+	  ................
+
+2011-09-12 13:27 +0000 [r335322]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_iax2.c: Merged revisions 335321 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335321 | kmoore | 2011-09-12 08:27:04 -0500
+	  (Mon, 12 Sep 2011) | 16 lines Merged revisions 335320 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335320 | kmoore | 2011-09-12 08:25:42 -0500 (Mon, 12 Sep 2011) |
+	  9 lines Prevent IAX2 from getting IPv6 addresses via DNS IAX2
+	  does not support IPv6 and getting such addresses from DNS can
+	  cause error messages on the remote end involving bad IPv4 address
+	  casts in the presence of IPv6/IPv4 tunnels. This patch ensures
+	  that IAX2 will not encounter IPv6 addresses via DNS queries.
+	  (closes issue ASTERISK-18090) ........ ................
+
+2011-09-12 11:15 +0000 [r335261]  Stefan Schmidt <sst at sil.at>
+
+	* /, channels/chan_sip.c: Merged revisions 335260 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335260 | schmidts | 2011-09-12 11:11:45 +0000
+	  (Mon, 12 Sep 2011) | 12 lines Merged revisions 335259 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335259 | schmidts | 2011-09-12 11:09:19 +0000 (Mon, 12 Sep 2011)
+	  | 6 lines build_peer doesnt unlink a peer object from peers_by_ip
+	  container which leads to a wrong refcounter value. adding an
+	  ao2_unlink from the peers_by_ip container fix it. Review:
+	  https://reviewboard.asterisk.org/r/1428/ ........
+	  ................
+
+2011-09-12 03:10 +0000 [r335170-335212]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* UPGRADE.txt: Be more specific on which section has changed.
+
+	* main/cdr.c, UPGRADE.txt: Iterate though cdr.conf setting Review:
+	  https://reviewboard.asterisk.org/r/1426/
+
+2011-09-11 17:09 +0000 [r335129]  Terry Wilson <twilson at digium.com>
+
+	* configs/res_config_sqlite3.conf.sample (added),
+	  res/res_config_sqlite3.c (added): Add SQLite 3 realtime support
+
+2011-09-09 16:28 +0000 [r335079]  Matthew Jordan <mjordan at digium.com>
+
+	* channels/chan_unistim.c, apps/app_dial.c, main/pbx.c,
+	  addons/chan_ooh323.c, channels/chan_sip.c,
+	  channels/chan_console.c, channels/sig_pri.c, channels/chan_oss.c,
+	  main/channel.c, channels/chan_usbradio.c, main/dial.c,
+	  channels/chan_dahdi.c, channels/chan_misdn.c,
+	  channels/chan_skinny.c, funcs/func_frame_trace.c,
+	  main/features.c, channels/chan_h323.c, channels/chan_alsa.c,
+	  include/asterisk/frame.h, channels/sig_ss7.c,
+	  channels/chan_mgcp.c: Merged revisions 335078 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r335078 | mjordan | 2011-09-09 11:27:01 -0500
+	  (Fri, 09 Sep 2011) | 29 lines Merged revisions 335064 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r335064 | mjordan | 2011-09-09 11:09:09 -0500 (Fri, 09 Sep 2011)
+	  | 23 lines Updated SIP 484 handling; added Incomplete control
+	  frame When a SIP phone uses the dial application and receives a
+	  484 Address Incomplete response, if overlapped dialing is enabled
+	  for SIP, then the 484 Address Incomplete is forwarded back to the
+	  SIP phone and the HANGUPCAUSE channel variable is set to 28.
+	  Previously, the Incomplete application dialplan logic was
+	  automatically triggered; now, explicit dialplan usage of the
+	  application is required. Additionally, this patch adds a new
+	  AST_CONTOL_FRAME type called AST_CONTROL_INCOMPLETE. If a channel
+	  driver receives this control frame, it is an indication that the
+	  dialplan expects more digits back from the device. If the device
+	  supports overlap dialing it should attempt to notify the device
+	  that the dialplan is waiting for more digits; otherwise, it can
+	  handle the frame in a manner appropriate to the channel driver.
+	  (closes issue ASTERISK-17288) Reported by: Mikael Carlsson Tested
+	  by: Matthew Jordan Review:
+	  https://reviewboard.asterisk.org/r/1416/ ........
+	  ................
+
+2011-09-09 07:28 +0000 [r335015]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* funcs/func_dialplan.c, /, apps/app_readexten.c, CHANGES: Merged
+	  revisions 335014 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r335014 | irroot | 2011-09-09 09:23:53 +0200 (Fri, 09 Sep 2011) |
+	  9 lines Move code for VALID_EXTEN from app_readexten to
+	  func_dialplan Mark VALID_EXTEN deprecated. Review:
+	  https://reviewboard.asterisk.org/r/1396/ ........
+
+2011-09-08 22:30 +0000 [r334955]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/logger.c: Merged revisions 334954 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334954 | rmudgett | 2011-09-08 17:28:56 -0500
+	  (Thu, 08 Sep 2011) | 17 lines Merged revisions 334953 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334953 | rmudgett | 2011-09-08 17:27:40 -0500 (Thu, 08 Sep 2011)
+	  | 10 lines Fix crash with res_fax when MALLOC_DEBUG and "core
+	  stop gracefully" are used. Asterisk crashes if MALLOC_DEBUG is
+	  enabled when res_fax tries to unregister its logger level. * Make
+	  ast_logger_unregister_level() use ast_free() instead of free().
+	  When MALLOC_DEBUG is enabled, ast_free() does not degenerate into
+	  a call to free(). Therefore, if you allocated memory with a form
+	  of ast_malloc you must free it with ast_free. ........
+	  ................
+
+2011-09-08 13:36 +0000 [r334907]  Jonathan Rose <jrose at digium.com>
+
+	* main/cdr.c, main/pbx.c: Removes colorful verb statements
+	  erroneously commited with r332760
+
+2011-09-07 19:38 +0000 [r334845]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, channels/chan_iax2.c: Merged revisions 334844 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334844 | pabelanger | 2011-09-07 15:37:24 -0400
+	  (Wed, 07 Sep 2011) | 11 lines Merged revisions 334843 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334843 | pabelanger | 2011-09-07 15:35:52 -0400 (Wed, 07 Sep
+	  2011) | 4 lines Cleanup chan_iax2.c log messages Review:
+	  https://code.asterisk.org/code/cru/CR-AST-11 ........
+	  ................
+
+2011-09-07 19:35 +0000 [r334842]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c: Merged revisions 334841 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334841 | rmudgett | 2011-09-07 14:33:38 -0500
+	  (Wed, 07 Sep 2011) | 17 lines Merged revisions 334840 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334840 | rmudgett | 2011-09-07 14:31:44 -0500 (Wed, 07 Sep 2011)
+	  | 10 lines Fix AMI action Park crash. * Made AMI action Park not
+	  say anything to the parker channel (AMI header Channel2) since
+	  the AMI action is a third party parking the call. (This is a
+	  change in behavior that cannot be preserved without a lot of
+	  effort.) * Made not play pbx-parkingfailed if the Park 's' option
+	  is used. JIRA AST-660 ........ ................
+
+2011-09-07 15:37 +0000 [r334683-334792]  Stefan Schmidt <sst at sil.at>
+
+	* /, main/features.c: Merged revisions 334747 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334747 | schmidts | 2011-09-07 15:10:37 +0000
+	  (Wed, 07 Sep 2011) | 9 lines Merged revisions 334682 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r334682 | schmidts | 2011-09-07 13:26:50 +0000 (Wed, 07
+	  Sep 2011) | 3 lines Adding the Feature to sent a Reason Header in
+	  a SIP Cancel message by set the flag AST_FLAG_ANSWERED_ELSEWHERE
+	  before doing a masquerade in the pickup function. ........
+	  ................
+
+	* main/features.c: clean up wrong merged stuff
+
+	* /, main/features.c: Merged revisions 334682 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r334682 | schmidts | 2011-09-07 13:26:50 +0000 (Wed, 07 Sep 2011)
+	  | 3 lines Adding the Feature to sent a Reason Header in a SIP
+	  Cancel message by set the flag AST_FLAG_ANSWERED_ELSEWHERE before
+	  doing a masquerade in the pickup function. ........
+
+	* main/features.c: Adding the Feature to sent a Reason Header in a
+	  SIP Cancel message by set the flag AST_FLAG_ANSWERED_ELSEWHERE
+	  before doing a masquerade in the pickup function.
+
+2011-09-07 08:17 +0000 [r334618-334623]  Alec L Davis <sivad.a at paradise.net.nz>
+
+	* /, CHANGES, apps/app_queue.c: Merged revisions 334621 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334621 | alecdavis | 2011-09-07 20:14:50 +1200
+	  (Wed, 07 Sep 2011) | 9 lines Merged revisions 334620 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r334620 | alecdavis | 2011-09-07 20:12:49 +1200 (Wed, 07
+	  Sep 2011) | 2 lines peroid typo ........ ................
+
+	* main/logger.c: log Asterisk Version number, Build etc into each
+	  log file Allow tracking of previous versions through log file
+	  records to be tracked. Each time log file is created or opened,
+	  log Asterisk Version, Buildinfo. etc. alecdavis (license 585)
+	  Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1409/
+
+	* main/pbx.c, /: Merged revisions 334617 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334617 | alecdavis | 2011-09-07 19:45:00 +1200
+	  (Wed, 07 Sep 2011) | 17 lines Merged revisions 334616 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334616 | alecdavis | 2011-09-07 19:33:39 +1200 (Wed, 07 Sep
+	  2011) | 10 lines Prevent segfault if call arrives before Asterisk
+	  is fully booted. Prevent ast_pbx_start and ast_run_start from
+	  starting a new thread unless asterisk is fully booted. alecdavis
+	  (license 585) Tested by: alecdavis Review:
+	  https://reviewboard.asterisk.org/r/1407/ ........
+	  ................
+
+2011-09-07 00:54 +0000 [r334574]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* main/frame.c, contrib/realtime/mysql/iaxfriends.sql,
 	  contrib/realtime/postgresql/realtime.sql,
-	  contrib/realtime/mysql/voicemail_data.sql, CHANGES,
-	  contrib/realtime/mysql/musiconhold.sql: Add database schema
-	  management using Alembic This patch replaces contrib/realtime/
-	  with a new setup for managing the database schema required for
-	  database integration with Asterisk. In addition to initializing a
-	  database with the proper schema, alembic can do a database
-	  migration to assist with upgrading Asterisk in the future.
-	  Hopefully this helps make setting up and operating Asterisk with
-	  a database easier. With this the schema only needs to be
-	  maintained in one place instead of once per database. The schemas
-	  I have added here have a bit of improvement over the examples
-	  that were there before (some added consistency and added some
-	  missing indexes). Managing the schema in one place here also
-	  applies to all databases supported by SQLAlchemy. See
-	  contrib/ast-db-manage/README.md for more details. Review:
-	  https://reviewboard.asterisk.org/r/2731 patch by Russell Bryant
-	  (license 6300) ........ Merged revisions 397874 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* CHANGES, /: Update CHANGES file for Asterisk 12 This updates the
-	  Asterisk 12 CHANGES file with the things that were missed during
-	  the development cycle. Review:
-	  https://reviewboard.asterisk.org/r/2795/ ........ Merged
-	  revisions 397870 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-28 16:13 +0000 [r397857-397860]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/pbx.c: pbx.c: Make ast_str_substitute_variables_full()
-	  not mask variables. ........ Merged revisions 397859 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* main/chanvars.c: ast_free() is null tollerant.
-
-	* include/asterisk/threadstorage.h, /: Match use of ast_free() with
-	  ast_calloc() and add some curly braces. ........ Merged revisions
-	  397856 from http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-28 15:43 +0000 [r397855]  Mark Michelson <mmichelson at digium.com>
-
-	* res/res_pjsip/pjsip_distributor.c, /: Fix dialog matching in the
-	  SIP distributor. Dialog matching is performed in the distributor
-	  for the sole purpose of retrieving an associated serializer so
-	  the request may be serialized. This patch fixes two problems.
-	  First, incoming CANCEL requests that had no to-tag (which really
-	  should be *all* CANCEL requests) would not match with a dialog.
-	  An earlier bug fix to deal with early CANCEL requests would
-	  result in the CANCEL being replied to with a 481. The fix for
-	  this is to find the matching INVITE transaction and get the
-	  dialog from that transaction. Second, no SIP responses were
-	  matching dialogs. This is because we were inverting the tags that
-	  we were passing into PJSIP's dialog finding function. This logic
-	  has been corrected by setting local and remote tag variables
-	  based on whether the incoming message is a request or response.
-	  ........ Merged revisions 397854 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-27 19:19 +0000 [r397820]  David M. Lee <dlee at digium.com>
-
-	* rest-api-templates/param_parsing.mustache, res/res_ari_bridges.c,
-	  /, res/stasis/app.c, res/res_ari_events.c,
-	  res/res_ari_asterisk.c,
-	  rest-api-templates/res_ari_resource.c.mustache, res/stasis/app.h,
-	  res/res_stasis.c, main/stasis_bridges.c: ARI: WebSocket event
-	  cleanup Stasis events (which get distributed over the ARI
-	  WebSocket) are created by subscribing to the channel_all_cached
-	  and bridge_all_cached topics, filtering out events for
-	  channels/bridges currently subscribed to. There are two issues
-	  with that. First was a race condition, where messages in-flight
-	  to the master subscribe-to-all-things topic would get sent out,
-	  even though the events happened before the channel was put into
-	  Stasis. Secondly, as the number of channels and bridges grow in
-	  the system, the work spent filtering messages becomes excessive.
-	  Since r395954, individual channels and bridges have caching
-	  topics, and can be subscribed to individually. This patch takes
-	  advantage, so that channels and bridges are subscribed to on
-	  demand, instead of filtering the global topics. The one case
-	  where filtering is still required is handling BridgeMerge
-	  messages, which are published directly to the bridge_all topic.
-	  Other than the change to how subscriptions work, this patch
-	  mostly just moves code around. Most of the work generating JSON
-	  objects from messages was moved to .to_json handlers on the
-	  message types. The callback functions handling app subscriptions
-	  were moved from res_stasis (b/c they were global to the model) to
-	  stasis/app.c (b/c they are local to the app now). (closes issue
-	  ASTERISK-21969) Reported by: Matt Jordan Review:
-	  https://reviewboard.asterisk.org/r/2754/ ........ Merged
-	  revisions 397816 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-27 18:52 +0000 [r397811]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, main/astmm.c: Made MALLOC_DEBUG less CPU intensive by default.
-	  Storing a backtrace for each allocation in anticipation of a
-	  memory management problem is very CPU intensive. * Added the CLI
-	  "memory backtrace {on|off}" command to request that the backtrace
-	  be gathered only on request. The backtrace is off by default.
-	  (issue ASTERISK-22221) Reported by: Matt Jordan ........ Merged
-	  revisions 397809 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-27 18:10 +0000 [r397753-397760]  Matthew Jordan <mjordan at digium.com>
-
-	* /, channels/chan_sip.c: AST-2013-005: Fix crash caused by invalid
-	  SDP If the SIP channel driver processes an invalid SDP that
-	  defines media descriptions before connection information, it may
-	  attempt to reference the socket address information even though
-	  that information has not yet been set. This will cause a crash.
-	  This patch adds checks when handling the various media
-	  descriptions that ensures the media descriptions are handled only
-	  if we have connection information suitable for that media. Thanks
-	  to Walter Doekes, OSSO B.V., for reporting, testing, and
-	  providing the solution to this problem. (closes issue
-	  ASTERISK-22007) Reported by: wdoekes Tested by: wdoekes patches:
-	  issueA22007_sdp_without_c_death.patch uploaded by wdoekes
-	  (License 5674) ........ Merged revisions 397756 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 397757 from
-	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged
-	  revisions 397758 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 397759 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
+	  configs/sip.conf.sample, CHANGES,
+	  contrib/realtime/mysql/sipfriends.sql: Implement the '!' negation
+	  element to negate codecs directly in the allow keyword. This
+	  permits the list of codecs to be specified in one configuration
+	  line, instead of two or more, generally with the aim of either
+	  allowing all codecs with the exception of a few or disallowing
+	  most but permitting a few. Review:
+	  https://reviewboard.asterisk.org/r/1411/
+
+2011-09-06 16:15 +0000 [r334519]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, apps/app_voicemail.c: Merged revisions 334455 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334455 | irroot | 2011-09-06 15:58:56 +0200
+	  (Tue, 06 Sep 2011) | 18 lines Merged revisions 334453 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334453 | irroot | 2011-09-06 15:48:03 +0200 (Tue, 06 Sep 2011) |
+	  13 lines Make SQL query in app_voicemail.c portable LIMIT is not
+	  portable. Regression from r312212 (closes issue ASTERISK-18255)
+	  Reported by: Leif Madsen Tested by: Leif Madsen Review:
+	  https://reviewboard.asterisk.org/r/1415/ ........
+	  ................
+
+2011-09-06 16:08 +0000 [r334517]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* configs/iax.conf.sample, /, CHANGES, channels/chan_iax2.c: Merged
+	  revisions 334514 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r334514 | pabelanger | 2011-09-06 11:47:59 -0400 (Tue, 06 Sep
+	  2011) | 6 lines authdebug is now disabled by default To enable
+	  this functionaility again set authdebug = yes in iax.conf Review:
+	  https://reviewboard.asterisk.org/r/1414/ ........
+
+2011-09-06 16:04 +0000 [r334472-334515]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* /, apps/app_voicemail.c: Revert r334472 due to properties going
+	  missing
+
+	* /, apps/app_voicemail.c: Merged revisions 334455 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334455 | irroot | 2011-09-06 15:58:56 +0200
+	  (Tue, 06 Sep 2011) | 18 lines Merged revisions 334453 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334453 | irroot | 2011-09-06 15:48:03 +0200 (Tue, 06 Sep 2011) |
+	  13 lines Make SQL query in app_voicemail.c portable LIMIT is not
+	  portable. Regression from r312212 (closes issue ASTERISK-18255)
+	  Reported by: Leif Madsen Tested by: Leif Madsen Review:
+	  https://reviewboard.asterisk.org/r/1415/ ........
+	  ................
+
+2011-09-02 21:09 +0000 [r334304-334358]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, res/res_musiconhold.c: Merged revisions 334357 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334357 | rmudgett | 2011-09-02 16:08:16 -0500
+	  (Fri, 02 Sep 2011) | 26 lines Merged revisions 334355 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334355 | rmudgett | 2011-09-02 15:59:49 -0500 (Fri, 02 Sep 2011)
+	  | 19 lines MusicOnHold has extra unref which may lead to memory
+	  corruption and crash. The problem happens when a call is
+	  disconnected and you had started a MOH class that does not use
+	  the files mode. If you define REF_DEBUG and recreate the problem,
+	  it will announce itself with the following warning: Attempt to
+	  unref mohclass 0xb70722e0 (default) when only 1 ref remained, and
+	  class is still in a container! * Fixed moh_alloc() and
+	  moh_release() functions not handling the state->class reference
+	  consistently. (closes issue ASTERISK-18346) Reported by: Mark
+	  Murawski Patches: jira_asterisk_18346_v1.8.patch (license #5621)
+	  patch uploaded by rmudgett Tested by: rmudgett, Mark Murawski
+	  Review: https://reviewboard.asterisk.org/r/1404/ ........
+	  ................
+
+	* /, include/asterisk/config.h, main/config.c: Merged revisions
+	  334297 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334297 | rmudgett | 2011-09-02 12:15:08 -0500
+	  (Fri, 02 Sep 2011) | 46 lines Merged revisions 334296 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334296 | rmudgett | 2011-09-02 12:10:58 -0500 (Fri, 02 Sep 2011)
+	  | 39 lines Fix potential memory allocation failure crashes in
+	  config.c. * Added required checks to the returned memory
+	  allocation pointers to prevent crashes. * Made
+	  ast_include_rename() create a replacement ast_variable list node
+	  if the new filename is longer than the available space. Fixes
+	  potential crash and memory leak. * Factored out
+	  ast_variable_move() from ast_variable_update() so
+	  ast_include_rename() can also use it when creating a replacement
+	  ast_variable list node. * Made the filename stuffed at the end of
+	  the struct a minimum allocated size in ast_variable_new() in case
+	  ast_include_rename() changes the stored filename. * Constify
+	  struct char pointers pointing to strings stuffed at the end of
+	  the struct for: ast_variable, cache_file_mtime, and
+	  ast_config_map. * Factored out cfmtime_new() to remove inlined
+	  code and allow some struct pointers to become const. * Removed
+	  the list lock from struct cache_file_mtime that was never used. *
+	  Added doxygen comments to several structure elements and better
+	  documented what strings are stuffed at the struct end char array.
+	  * Reworked ast_config_text_file_save() and set_fn() to handle
+	  allocation failure of the include file scratch pad object
+	  tracking blank lines. * Made ast_config_text_file_save() fn[]
+	  declared with PATH_MAX to ensure it is long enough for any
+	  filename with path. Also reduced the number of container fileset
+	  buckets from a rediculus 180,000 to 1023. JIRA AST-618 Review:
+	  https://reviewboard.asterisk.org/r/1378/ ........
+	  ................
+
+2011-09-01 17:41 +0000 [r334231-334236]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* main/pbx.c, /: Merged revisions 334235 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334235 | tilghman | 2011-09-01 12:39:32 -0500
+	  (Thu, 01 Sep 2011) | 9 lines Merged revisions 334234 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r334234 | tilghman | 2011-09-01 12:38:33 -0500 (Thu, 01
+	  Sep 2011) | 2 lines Remove 1.6 compatibility documentation from
+	  1.8, as it no longer applies. ........ ................
+
+	* res/res_config_odbc.c, /: Merged revisions 334230 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334230 | tilghman | 2011-09-01 12:30:19 -0500
+	  (Thu, 01 Sep 2011) | 25 lines Merged revisions 334229 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334229 | tilghman | 2011-09-01 12:28:09 -0500 (Thu, 01 Sep 2011)
+	  | 18 lines Create a local alias for ast_odbc_clear_cache. As a
+	  function pointer, the reference has to be resolved at load time
+	  irrespective of the RTLD_LAZY flag. Creating a local alias solves
+	  this problem, because the structure is initialized with that
+	  local function pointer, while the actual function can remain
+	  lazily linked until runtime. The reason why this is important is
+	  because we lazily load function references during the module
+	  loading process, in order to obtain priority values for each
+	  module, ensuring that modules are loaded in the correct order.
+	  Previous to this change, when this module was initially loaded,
+	  the module loader would emit a symbol resolution error, because
+	  of the above requirement. Closes ASTERISK-18399 (reported by
+	  Mikael Carlsson, fix suggested by Walter Doekes, patch by me)
+	  ........ ................
+
+2011-08-31 18:54 +0000 [r334158]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 334157 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334157 | mnicholson | 2011-08-31 13:53:40 -0500
+	  (Wed, 31 Aug 2011) | 11 lines Merged revisions 334156 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334156 | mnicholson | 2011-08-31 13:50:33 -0500 (Wed, 31 Aug
+	  2011) | 4 lines Disable T.38 when we get a invite with image
+	  media port set to 0 ASTERISK-17678 ........ ................
+
+2011-08-31 18:11 +0000 [r334115]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_sip.c: Optimize chan_sip.c check_rtp_timeout()
+	  function. * Make check_rtp_timeout() remember the values returned
+	  by ast_rtp_instance_get_timeout(),
+	  ast_rtp_instance_get_hold_timeout(), and
+	  ast_rtp_instance_get_keepalive() instead of repeatedly calling
+	  them. (closes issue ASTERISK-18319) Reported by: Rob Gagnon
+	  Patches: issue-18319-trunk-r333066.diff (License #6159) patch
+	  uploaded by Rob Gagnon Review:
+	  https://reviewboard.asterisk.org/r/1377/
+
+2011-08-31 16:31 +0000 [r334067]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 334064 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r334064 | mnicholson | 2011-08-31 11:31:00 -0500 (Wed, 31 Aug
+	  2011) | 4 lines only alter the gateway_timeout when attching the
+	  gateway to a channel ASTERISK-18219 ........
+
+2011-08-31 16:02 +0000 [r334011-334014]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 334013 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334013 | rmudgett | 2011-08-31 11:00:49 -0500
+	  (Wed, 31 Aug 2011) | 30 lines Merged revisions 334012 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334012 | rmudgett | 2011-08-31 10:57:12 -0500 (Wed, 31 Aug 2011)
+	  | 23 lines No DAHDI channel available for conference, user
+	  introduction disabled. The following error will consistently
+	  occur when trying to dial into a MeetMe conference when the
+	  server does not have DAHDI hardware installed: app_meetme.c: No
+	  DAHDI channel available for conference, user introduction
+	  disabled (is chan_dahdi loaded?) While chan_dahdi is loaded
+	  correctly during compilation and install of Asterisk/Dahdi,
+	  including associated modules, etc., a chan_dahdi.conf
+	  configuration file in /etc/asterisk is not created by FreePBX if
+	  hardware does not exist, causing MeetMe to be unable to open a
+	  DAHDI pseudo channel. * Allow chan_dahdi to create a pseudo
+	  channel when there is no chan_dahdi.conf file to load. (closes
+	  issue ASTERISK-17398) Reported by: Preston Edwards Patches:
+	  jira_asterisk_17398_v1.8.patch (license #5621) patch uploaded by
+	  rmudgett Tested by: rmudgett ........ ................
+
+	* main/channel.c, /, channels/chan_agent.c: Merged revisions 334010
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334010 | rmudgett | 2011-08-31 10:23:11 -0500
+	  (Wed, 31 Aug 2011) | 50 lines Merged revisions 334009 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334009 | rmudgett | 2011-08-31 10:20:31 -0500 (Wed, 31 Aug 2011)
+	  | 43 lines Call pickup race leaves orphaned channels or crashes.
+	  Multiple users attempting to pickup a call that has been forked
+	  to multiple extensions either crashes or fails a masquerade with
+	  a "bad things may happen" message. This is the scenario that is
+	  causing all the grief: 1) Pickup target is selected 2) target is
+	  marked as being picked up in ast_do_pickup() 3) target is
+	  unlocked by ast_do_pickup() 4) app dial or queue gets a chance to
+	  hang up losing calls and calls ast_hangup() on target 5) SINCE A
+	  MASQUERADE HAS NOT BEEN SETUP YET BY ast_do_pickup() with
+	  ast_channel_masquerade(), ast_hangup() completes successfully and
+	  the channel is no longer in the channels container. 6)
+	  ast_do_pickup() then calls ast_channel_masquerade() to schedule
+	  the masquerade on the dead channel. 7) ast_do_pickup() then calls
+	  ast_do_masquerade() on the dead channel 8) bad things happen
+	  while doing the masquerade and in the process ast_do_masquerade()
+	  puts the dead channel back into the channels container 9) The
+	  "orphaned" channel is visible in the channels list if a crash
+	  does not happen. This patch does the following: * Made
+	  ast_hangup() set AST_FLAG_ZOMBIE on a successfully hung-up
+	  channel and not release the channel lock until that has happened.
+	  * Made __ast_channel_masquerade() not setup a masquerade if
+	  either channel has AST_FLAG_ZOMBIE set. * Fix chan_agent misuse
+	  of AST_FLAG_ZOMBIE since it would no longer work. (closes issue
+	  ASTERISK-18222) Reported by: Alec Davis Tested by: rmudgett, Alec
+	  Davis, irroot, Karsten Wemheuer (closes issue ASTERISK-18273)
+	  Reported by: Karsten Wemheuer Tested by: rmudgett, Alec Davis,
+	  irroot, Karsten Wemheuer Review:
+	  https://reviewboard.asterisk.org/r/1400/ ........
+	  ................
+
+2011-08-31 15:20 +0000 [r334008]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 334007 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r334007 | kmoore | 2011-08-31 10:19:30 -0500
+	  (Wed, 31 Aug 2011) | 14 lines Merged revisions 334006 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r334006 | kmoore | 2011-08-31 10:18:37 -0500 (Wed, 31 Aug 2011) |
+	  7 lines Correct an AMI protocol violation with SIPshowpeer The
+	  response of SIPshowpeer ends with "\r\n\r\n". Since other
+	  commands are ended by using \r\n this confuses any interfacing
+	  script. (closes issue ASTERISK-17486) ........ ................
+
+2011-08-30 22:16 +0000 [r333963]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooh323.c, addons/ooh323c/src/ooGkClient.c, /,
+	  addons/ooh323c/src/ooCalls.h, addons/ooh323c/src/oochannels.c,
+	  addons/ooh323c/src/ooq931.c, addons/ooh323c/src/ooCalls.c: Merged
+	  revisions 333961-333962 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333961 | may | 2011-08-31 01:21:53 +0400 (Wed,
+	  31 Aug 2011) | 11 lines Merged revisions 333947 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333947 | may | 2011-08-31 01:16:30 +0400 (Wed, 31 Aug 2011) | 5
+	  lines cleanups in ACF/ARJ GK replies processing fixed long (24
+	  sec) pause if acf/arj proccessed before ast_cond_wait called to
+	  wait this ........ ................ r333962 | may | 2011-08-31
+	  01:53:42 +0400 (Wed, 31 Aug 2011) | 3 lines security fix. really
+	  drop call if signalling addr is not same as socket addr
+	  ................
+
+2011-08-30 14:03 +0000 [r333896]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 333895 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r333895 | mnicholson | 2011-08-30 09:01:31 -0500 (Tue, 30 Aug
+	  2011) | 6 lines Replaced FAXOPT(gwtimeout) with a second
+	  parameter to FAXOPT(gateway). Patch by: irroot Review:
+	  https://reviewboard.asterisk.org/r/1385/ ASTERISK-18219 ........
+
+2011-08-29 21:43 +0000 [r333838]  Terry Wilson <twilson at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 333837 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333837 | twilson | 2011-08-29 16:41:13 -0500
+	  (Mon, 29 Aug 2011) | 22 lines Merged revisions 333836 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333836 | twilson | 2011-08-29 16:38:31 -0500 (Mon, 29 Aug 2011)
+	  | 15 lines Refresh peer address if DNS unavailable at peer
+	  creation If Asterisk starts and no DNS is available, outbound
+	  registrations will fail indefinitely. This patch copies the
+	  address from the sip_registry struct, which will be updated, to
+	  the peer->addr when necessary. If dnsmgr is enabled, the
+	  registration fails without the patch because even though the
+	  address on the registry is updated via dnsmgr, the address is
+	  just copied on the first try. Since we use ast_sockaddr_copy,
+	  dnsmgr can't update the address that is copied to the sip_pvt or
+	  peers. Closes issue ASTERISK-18000 Review:
+	  https://reviewboard.asterisk.org/r/1335/ ........
+	  ................
+
+2011-08-29 21:17 +0000 [r333789]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, include/asterisk/channel.h, addons/chan_mobile.c: Merged
+	  revisions 333786 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333786 | rmudgett | 2011-08-29 16:12:29 -0500
+	  (Mon, 29 Aug 2011) | 13 lines Merged revisions 333784-333785 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333784 | rmudgett | 2011-08-29 16:05:43 -0500 (Mon, 29 Aug 2011)
+	  | 2 lines Fix deadlock potential of
+	  chan_mobile.c:mbl_ast_hangup(). ........ r333785 | rmudgett |
+	  2011-08-29 16:06:16 -0500 (Mon, 29 Aug 2011) | 1 line Add some do
+	  not hold locks notes to channel.h ........ ................
+
+2011-08-29 18:28 +0000 [r333736]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax_spandsp.c: Merged revisions 333716 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r333716 | mnicholson | 2011-08-29 13:22:58 -0500 (Mon, 29 Aug
+	  2011) | 5 lines It is possible for the gateway to be attached
+	  when the channel is still negotiating T.38. This change handles
+	  that case. ASTERISK-18329 ........
+
+2011-08-29 17:31 +0000 [r333689]  Terry Wilson <twilson at digium.com>
+
+	* main/channel.c, /, CHANGES: Merged revisions 333681 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r333681 | twilson | 2011-08-29 12:28:59 -0500 (Mon, 29 Aug 2011)
+	  | 7 lines Use realtime text when it is negotiated This patch make
+	  use of wirte_text() realtime text instead of send_text() if T.140
+	  is in native formats. ASTERISK-17937 Review:
+	  https://reviewboard.asterisk.org/r/1356/ ........
+
+2011-08-29 17:14 +0000 [r333632]  Matthew Jordan <mjordan at digium.com>
+
+	* apps/app_voicemail.c: Merged revisions 333631 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333631 | mjordan | 2011-08-29 12:12:55 -0500
+	  (Mon, 29 Aug 2011) | 9 lines Merged revisions 333630 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r333630 | mjordan | 2011-08-29 12:11:15 -0500 (Mon, 29
+	  Aug 2011) | 1 line Fixed improperly formatted TestEvent AMI
+	  message in app_voicemail ........ ................
+
+2011-08-29 15:58 +0000 [r333571]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_jabber.c: Merged revisions 333570 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333570 | jrose | 2011-08-29 10:56:56 -0500
+	  (Mon, 29 Aug 2011) | 11 lines Merged revisions 333569 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333569 | jrose | 2011-08-29 10:55:34 -0500 (Mon, 29 Aug 2011) |
+	  4 lines Accidental use of variable client->status instead of
+	  client->state in from ASTERISK-18078 (issue ASTERISK-18078)
+	  ........ ................
+
+2011-08-28 09:57 +0000 [r333509]  Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+	* channels/chan_vpb.cc: chan_vpb: remove unused variables (gcc4.6)
+	  GCC 4.6 detects variables that get assined to, but never used
+	  later. Also removes some remmed-out lines that become invalid.
+	  (closes issue ASTERISK-18336) Signed-off-by: Tzafrir Cohen
+	  (License #5035) <tzafrir.cohen at xorcom.com>,
+
+2011-08-26 16:38 +0000 [r333428]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_jabber.c: Merged revisions 333410 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333410 | jrose | 2011-08-26 11:28:03 -0500
+	  (Fri, 26 Aug 2011) | 19 lines Merged revisions 333378 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333378 | jrose | 2011-08-26 11:19:07 -0500 (Fri, 26 Aug 2011) |
+	  13 lines [patch] Buddies are always auto-registered when
+	  processing the roster Reporter said autoregister flag was ignored
+	  for registering 'buddies' which had a subscription to us.
+	  Verified that this was the case and observed how the patch
+	  addressed this and made sure it didn't break anything. (closes
+	  issue ASTERISK-14233) Reported by: Simon Arlott Patches:
+	  asterisk-0015229.patch (license #5756) patch uploaded by Simon
+	  Arlott Tested by: Jonathan Rose ........ ................
+
+2011-08-26 16:12 +0000 [r333371]  Matthew Jordan <mjordan at digium.com>
+
+	* /, apps/app_voicemail.c: Merged revisions 333370 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333370 | mjordan | 2011-08-26 10:58:37 -0500
+	  (Fri, 26 Aug 2011) | 26 lines Merged revisions 333339 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333339 | mjordan | 2011-08-26 08:36:36 -0500 (Fri, 26 Aug 2011)
+	  | 20 lines Bug fixes for voicemail user emailsubject / emailbody.
+	  This code change fixes a few issues with the voicemail user
+	  override of emailbody and emailsubject, including escaping the
+	  strings, potential memory leaks, and not overriding the voicemail
+	  defaults. Revision 325877 fixed this for ASTERISK-16795, but did
+	  not fix it for ASTERISK-16781. A subsequent check-in prevented
+	  325877 from being applied to 10. This check-in resolves both
+	  issues, and applies the changes to 1.8, 10, and trunk. (closes
+	  issue ASTERISK-16781) Reported by: Sebastien Couture Tested by:
+	  mjordan (closes issue ASTERISK-16795) Reported by: mdeneen Tested
+	  by: mjordan Review: https://reviewboard.asterisk.org/r/1374
+	  ........ ................
+
+2011-08-25 19:13 +0000 [r333276]  Jonathan Rose <jrose at digium.com>
+
+	* /, res/res_jabber.c: Merged revisions 333266 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333266 | jrose | 2011-08-25 14:00:05 -0500
+	  (Thu, 25 Aug 2011) | 20 lines Merged revisions 333265 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333265 | jrose | 2011-08-25 13:47:42 -0500 (Thu, 25 Aug 2011) |
+	  14 lines Segfault when publishing device states via XMPP and not
+	  connected When using publishing device state with res_jabber,
+	  Asterisk will attempt to send a device state using the
+	  unconnected client using iks_send_raw and crash. This patch
+	  checks the validity of the connection before attempting to send
+	  the device state. (closes issue ASTERISK-18078) Reported by:
+	  Michael L. Young Patches:
+	  res_jabber-segfault-pubsub-not-connected2.patch (license #5026)
+	  patch uploaded by Michael L. Young Tested by: Jonathan Rose
+	  ........ ................
+
+2011-08-25 19:01 +0000 [r333159-333269]  Jason Parker <jparker at digium.com>
+
+	* Makefile, /: Merged revisions 333268 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333268 | qwell | 2011-08-25 14:01:18 -0500
+	  (Thu, 25 Aug 2011) | 9 lines Merged revisions 333267 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r333267 | qwell | 2011-08-25 14:00:55 -0500 (Thu, 25 Aug
+	  2011) | 2 lines Fix for DESTDIR spaces patch. ........
+	  ................
+
+	* Makefile, build_tools/mkpkgconfig, /, configure, configure.ac,
+	  makeopts.in, sounds/Makefile: Merged revisions 333203 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333203 | qwell | 2011-08-25 10:29:56 -0500
+	  (Thu, 25 Aug 2011) | 15 lines Merged revisions 333201 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333201 | qwell | 2011-08-25 10:27:06 -0500 (Thu, 25 Aug 2011) |
+	  8 lines Fix installation into directories containing spaces. This
+	  also vastly simplifies the logic in sounds/Makefile (Closes issue
+	  ASTERISK-18290) Reported by: Paul Belanger Review:
+	  https://reviewboard.asterisk.org/r/1379/ ........
+	  ................
+
+	* channels/chan_local.c: Fix typo from r333070
+
+2011-08-24 16:52 +0000 [r333117]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 333115 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r333115 | mnicholson | 2011-08-24 11:51:42 -0500 (Wed, 24 Aug
+	  2011) | 4 lines Changed the "timeout" option to "gwtimeout".
+	  ASTERISK-18219 ........
+
+2011-08-24 09:17 +0000 [r333070-333075]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_local.c: Formatting changes - Removing some red
+	  white space and adding some curly brackets.
+
+	* CHANGES: Add documentation for new manager event in chan_local
+	  AST-17623
+
+	* channels/chan_local.c: Add manager event for local channel
+	  semi-bridge (issue AST-17623) Review:
+	  https://reviewboard.asterisk.org/r/1154
+
+2011-08-23 18:17 +0000 [r332881-333014]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, apps/app_queue.c: Merged revisions 333011 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r333011 | rmudgett | 2011-08-23 13:15:49 -0500
+	  (Tue, 23 Aug 2011) | 19 lines Merged revisions 333010 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r333010 | rmudgett | 2011-08-23 13:14:01 -0500 (Tue, 23 Aug 2011)
+	  | 12 lines Memory Leak in app_queue The patch that was committed
+	  in the 1.6.x versions of Asterisk for ASTERISK-15862 actually
+	  fixed two issues. One was not applicable to 1.8 but the other is.
+	  queue_leak.patch fixes the portion applicable to 1.8. (closes
+	  issue ASTERISK-18265) Reported by: Fred Schroeder Patches:
+	  queue_leak.patch (license #5049) patch uploaded by mmichelson
+	  Tested by: Thomas Arimont ........ ................
+
+	* /, main/config.c: Merged revisions 332940 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332940 | rmudgett | 2011-08-22 16:23:40 -0500
+	  (Mon, 22 Aug 2011) | 14 lines Merged revisions 332939 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332939 | rmudgett | 2011-08-22 16:22:24 -0500 (Mon, 22 Aug 2011)
+	  | 7 lines Minor code optimizations. * Simplify
+	  ast_category_browse() logic for easier understanding. * Remove
+	  dead code in ast_variable_delete() and simplify some of its
+	  logic. ........ ................
+
+	* /, apps/app_queue.c: Merged revisions 332875,332878 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332875 | rmudgett | 2011-08-22 14:41:03 -0500
+	  (Mon, 22 Aug 2011) | 1 line Fix merge property. ................
+	  r332878 | rmudgett | 2011-08-22 14:46:25 -0500 (Mon, 22 Aug 2011)
+	  | 25 lines Merged revisions 332874 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332874 | rmudgett | 2011-08-22 14:32:19 -0500 (Mon, 22 Aug 2011)
+	  | 18 lines Reference leaks in app_queue. * Fixed
+	  load_realtime_queue() leaking a queue reference when it
+	  overwrites q when processing a realtime queue. (issue
+	  ASTERISK-18265) * Make join_queue() unreference the queue
+	  returned by load_realtime_queue() when it is done with the
+	  pointer. The load_realtime_queue() returns a reference to the
+	  just loaded realtime queue. * Fixed queues container reference
+	  leak in queues_data_provider_get(). * queue_unref() should not
+	  return q that was just unreferenced. * Made logic in
+	  __queues_show() and queues_data_provider_get() when calling
+	  load_realtime_queue() easier to understand. ........
+	  ................
+
+2011-08-22 19:56 +0000 [r332880]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, channels/chan_gtalk.c: Merged revisions 332877 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332877 | pabelanger | 2011-08-22 15:43:33 -0400
+	  (Mon, 22 Aug 2011) | 13 lines Merged revisions 332876 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332876 | pabelanger | 2011-08-22 15:41:24 -0400 (Mon, 22 Aug
+	  2011) | 6 lines Revert previous commit It seems google is still
+	  making changes to the protocol. (issue ASTERISK-18301) ........
+	  ................
+
+2011-08-22 19:52 +0000 [r332879]  Richard Mudgett <rmudgett at digium.com>
+
+	* /: Fix merge 10 branch merge properties.
+
+2011-08-22 19:19 +0000 [r332844]  Matthew Jordan <mjordan at digium.com>
+
+	* include/asterisk/test.h, main/manager.c, /, main/file.c,
+	  main/test.c, main/app.c, configs/manager.conf.sample,
+	  include/asterisk/manager.h, apps/app_voicemail.c: Merged
+	  revisions 332817 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332817 | mjordan | 2011-08-22 13:15:51 -0500 (Mon, 22 Aug 2011)
+	  | 4 lines Review: https://reviewboard.asterisk.org/r/1364/ This
+	  update adds a new AMI event, TestEvent, which is enabled when the
+	  TEST_FRAMEWORK compiler flag is defined. It also adds initial
+	  usage of this event to app_voicemail. The TestEvent AMI event is
+	  used extensively by the voicemail tests in the Asterisk Test
+	  Suite. ........
+
+2011-08-22 18:33 +0000 [r332762-332831]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_config_pgsql.c, res/res_config_odbc.c, /: Merged
+	  revisions 332830 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332830 | rmudgett | 2011-08-22 13:32:09 -0500
+	  (Mon, 22 Aug 2011) | 15 lines Merged revisions 332816 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332816 | rmudgett | 2011-08-22 13:14:59 -0500 (Mon, 22 Aug 2011)
+	  | 8 lines Memory leaks in realtime_multi_xxx() when database
+	  access returns error. * Fix realtime_multi_pgsql() configuration
+	  memory leak when the database access returns an error. * Fix
+	  realtime_multi_odbc() configuration category use after free when
+	  the database access returns an error. ........ ................
+
+	* /, main/config.c: Merged revisions 332761 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332761 | rmudgett | 2011-08-22 12:05:35 -0500
+	  (Mon, 22 Aug 2011) | 22 lines Merged revisions 332759 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332759 | rmudgett | 2011-08-22 12:00:03 -0500 (Mon, 22 Aug 2011)
+	  | 15 lines Memory leak reading realtime database variable list.
+	  Calling ast_load_realtime() can leak the last list node if the
+	  read list only contains empty variable value items. * Fixed list
+	  filter loop in ast_load_realtime() to delete the list node
+	  immediately instead of the next time through the loop. The next
+	  time through the loop may not happen if the node to delete is the
+	  last in the list. (issue ASTERISK-18277) (issue ASTERISK-18265)
+	  Patches: jira_asterisk_18265_v1.8_config.patch (license #5621)
+	  patch uploaded by rmudgett ........ ................
+
+2011-08-22 17:05 +0000 [r332760]  Jonathan Rose <jrose at digium.com>
+
+	* main/cdr.c, main/pbx.c, configs/cdr.conf.sample,
+	  include/asterisk/cdr.h, CHANGES: Add option for logging congested
+	  calls as CONGESTION instead of NO_ANSWER in CDR This patch adds a
+	  CDR option to cdr.conf that will allow CDR files to log calls
+	  ending with congestion in a way that is unique from other
+	  unanswered calls. (closes issue ASTERISK-14842) Reported by: Alec
+	  Davis Patches: cdr_congestion.diff.txt (License #5546) patch
+	  uploaded by Alec Davis
+
+2011-08-22 16:31 +0000 [r332757]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c, include/asterisk/res_fax.h: Merged revisions
+	  332756 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r332756 | mnicholson | 2011-08-22 11:29:45 -0500 (Mon, 22 Aug
+	  2011) | 4 lines add a way to disable and/or modify the gateway
+	  timeout ASTERISK-18219 ........
+
+2011-08-21 14:34 +0000 [r332701]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, channels/chan_gtalk.c: Merged revisions 332700 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332700 | pabelanger | 2011-08-21 10:33:23 -0400
+	  (Sun, 21 Aug 2011) | 12 lines Merged revisions 332699 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332699 | pabelanger | 2011-08-21 10:31:31 -0400 (Sun, 21 Aug
+	  2011) | 5 lines Fix outgoing calls in chan_gtalk (closes issue
+	  ASTERISK-18301) Reported by: az1324 ........ ................
+
+2011-08-19 20:00 +0000 [r332655]  Kinsey Moore <kmoore at digium.com>
+
+	* /, apps/app_confbridge.c: Merged revisions 332654 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r332654 | kmoore | 2011-08-19 14:59:34 -0500 (Fri, 19 Aug 2011) |
+	  8 lines Make CONFBRIDGE_INFO behave more nicely CONFBRIDGE_INFO
+	  doesn't behave as well in edge cases as MEETME_INFO. With this
+	  patch, CONFBRIDGE_INFO should behave in a much more reasonable
+	  manner when presented with invalid conferences and keywords.
+	  Review: https://reviewboard.asterisk.org/r/1359/ ........
+
+2011-08-19 17:24 +0000 [r332615]  Richard Mudgett <rmudgett at digium.com>
+
+	* res/res_config_ldap.c: Fix infinite loop releasing the same
+	  memory in ldap_loadentry(). * Fixed memory leak of vars in
+	  ldap_loadentry(). * Fixed potential NULL ptr dereference of vars
+	  in ldap_loadentry().
+
+2011-08-18 21:39 +0000 [r332561]  Terry Wilson <twilson at digium.com>
+
+	* main/netsock2.c, /: Merged revisions 332560 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332560 | twilson | 2011-08-18 16:34:04 -0500
+	  (Thu, 18 Aug 2011) | 12 lines Merged revisions 332559 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332559 | twilson | 2011-08-18 16:26:01 -0500 (Thu, 18 Aug 2011)
+	  | 5 lines Fix possible error on stringification of IPv4-mapped
+	  addrs The FreeBSD netsock2 test has been failing for a while. We
+	  were pasing sa->len to getnameinfo instead of sa_tmp->len.
+	  ASTERISK-18289 ........ ................
+
+2011-08-18 19:30 +0000 [r332505]  Kinsey Moore <kmoore at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 332504 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332504 | kmoore | 2011-08-18 14:29:15 -0500
+	  (Thu, 18 Aug 2011) | 15 lines Merged revisions 332503 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332503 | kmoore | 2011-08-18 14:28:00 -0500 (Thu, 18 Aug 2011) |
+	  8 lines CRC4 in "dahdi show status" gives wrong impression to T1
+	  users Change CRC4 to CRC in the output of "dahdi show status" so
+	  that it can apply in more situations without confusing users,
+	  especially since T1 lines use CRC6 instead of CRC4. (closes issue
+	  AST-471) ........ ................
+
+2011-08-18 14:49 +0000 [r332388-332448]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* build_tools/cflags.xml, build_tools/cflags-devmode.xml, /: Merged
+	  revisions 332447 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332447 | tilghman | 2011-08-18 09:48:40 -0500
+	  (Thu, 18 Aug 2011) | 9 lines Merged revisions 332446 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r332446 | tilghman | 2011-08-18 09:46:54 -0500 (Thu, 18
+	  Aug 2011) | 2 lines Move BETTER_BACKTRACES out of development
+	  mode, as it's useful when DEBUG_THREADS is enabled. ........
+	  ................
+
+	* Makefile, agi/Makefile, utils/Makefile, /, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac,
+	  Makefile.moddir_rules, makeopts.in, sounds/Makefile: Merged
+	  revisions 332369 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332369 | tilghman | 2011-08-17 14:24:59 -0500
+	  (Wed, 17 Aug 2011) | 17 lines Merged revisions 332355 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332355 | tilghman | 2011-08-17 14:21:36 -0500 (Wed, 17 Aug 2011)
+	  | 10 lines Re-add support for spaces in pathnames, including now
+	  spaces in DESTDIR. This was initially added to 1.8 prior to
+	  release, primarily to support the standard paths on Mac OS X, but
+	  was partially reverted recently in Subversion, due to the lack of
+	  support for spaces in DESTDIR. This commit restores support for
+	  the standard paths on Mac OS X, and also includes support for
+	  spaces in DESTDIR. (closes issue ASTERISK-18290) Reported by:
+	  pabelanger Review: https://reviewboard.asterisk.org/r/1326/
+	  ........ ................
+
+2011-08-17 18:31 +0000 [r332337]  Terry Wilson <twilson at digium.com>
+
+	* /, res/res_timing_timerfd.c: Merged revisions 332321 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332321 | twilson | 2011-08-17 13:09:49 -0500
+	  (Wed, 17 Aug 2011) | 17 lines Merged revisions 332320 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332320 | twilson | 2011-08-17 12:35:27 -0500 (Wed, 17 Aug 2011)
+	  | 10 lines Don't read from a disarmed or invalid timerfd Numerous
+	  isues have been reported for deadlocks that are caused by a
+	  blocking read in res_timing_timerfd on a file descriptor that
+	  will never be written to. This patch adds some checks to make
+	  sure that the timerfd is both valid and armed before calling
+	  read(). Should fix: ASTERISK-18142, ASTERISK-18166,
+	  ASTERISK-18197, AST-486, AST-495, AST-507 and possibly others.
+	  Review: https://reviewboard.asterisk.org/r/1361/ ........
+	  ................
+
+2011-08-17 16:18 +0000 [r332270]  Richard Mudgett <rmudgett at digium.com>
 
-	* /, channels/chan_sip.c: AST-2013-004: Fix crash when handling ACK
-	  on dialog that has no channel A remote exploitable crash
-	  vulnerability exists in the SIP channel driver if an ACK with SDP
-	  is received after the channel has been terminated. The handling
-	  code incorrectly assumed that the channel would always be
-	  present. This patch adds a check such that the SDP will only be
-	  parsed and applied if Asterisk has a channel present that is
-	  associated with the dialog. Note that the patch being applied was
-	  modified only slightly from the patch provided by Walter Doekes
-	  of OSSO B.V. (closes issue ASTERISK-21064) Reported by: Colin
-	  Cuthbertson Tested by: wdoekes, Colin Cutherbertson patches:
-	  issueA21064_fix.patch uploaded by wdoekes (License 5674) ........
-	  Merged revisions 397710 from
-	  http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged
-	  revisions 397711 from
-	  http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged
-	  revisions 397712 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 397713 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-27 16:51 +0000 [r397746]  Richard Mudgett <rmudgett at digium.com>
-
-	* channels/chan_iax2.c, channels/sig_pri.c, channels/sig_ss7.c,
-	  channels/chan_dahdi.c, channels/sig_analog.c, /,
-	  channels/chan_sip.c, channels/chan_motif.c: Fix uninitialized
-	  value in struct ast_control_pvt_cause_code usage. ........ Merged
-	  revisions 397744 from
-	  http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged
-	  revisions 397745 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-26 23:48 +0000 [r397691]  Matthew Jordan <mjordan at digium.com>
-
-	* /, main/bridge_channel.c: Better handle clearing the OUTGOING
-	  flag when a channel leaves a bridge When a channel with the
-	  OUTGOING flag leaves a bridge, and it will survive being pulled
-	  from the bridge (either because it will execute dialplan, go into
-	  another bridge, or live in a friendly autoloop), we have to clear
-	  the OUTGOING flag. This is the signal to the CDR engine that this
-	  channel is no longer a second class citizen, i.e., it is not
-	  "dialed". The soft hangup flags are only half the picture. If a
-	  channel is being moved from one bridge to another, the soft
-	  hangup flags aren't set; however, the state of the bridge_channel
-	  will not be hung up. Since the channel does not have one of the
-	  two hang up states, that implies that the channel is still
-	  technically alive. This patch modifies the check so that it
-	  checks both the soft hangup flags as well as the bridge_channel
-	  state. If either suggests that the channel is going to persist,
-	  we clear the OUTGOING flag. ........ Merged revisions 397690 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-26 21:32 +0000 [r397674]  David M. Lee <dlee at digium.com>
-
-	* /, main/bucket.c: Fixed bucket.c for systems where tv_usec is not
-	  an unsigned long. ........ Merged revisions 397673 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-26 16:25 +0000 [r397644-397651]  Richard Mudgett <rmudgett at digium.com>
-
-	* /, include/asterisk/bridge_channel.h, main/bridge_channel.c:
-	  bridging: Fix a livelock with local channel optimization. Use a
-	  better means of waking up the bridge channel thread. ........
-	  Merged revisions 397650 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* channels/Makefile, /: chan_dahdi: Add some missing build cleanup.
-	  ........ Merged revisions 397643 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-25 18:12 +0000 [r397622-397631]  Matthew Jordan <mjordan at digium.com>
-
-	* tests/test_bucket.c, /: Fix bucket unit tests After the review
-	  for buckets was completed (r2715), the handling of names in the
-	  bucket core was deferred to the wizards. As such, the bucket unit
-	  tests cannot expect that passing a URI with a scheme specified
-	  but no actual resource name will automatically fail. The tests
-	  have been updated to not make this check. ........ Merged
-	  revisions 397630 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* include/asterisk/config_options.h, /, main/config_options.c,
-	  tests/test_config.c: Fix the config_options_test The config
-	  options test requires the entire configuration item to be
-	  transparent from the documentation system. So we let it do that
-	  too. As an aside, please do not use this power for evil.
-	  Documentation is your friend, and you really should document your
-	  configurations. Hiding your module's configuration information
-	  from the system attempting to enforce some sanity in the universe
-	  is something only a Bond villain would contemplate. ........
-	  Merged revisions 397628 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-	* /, res/res_pjsip/pjsip_configuration.c: Add rtpengine
-	  configuration parameter The rtpengine configuration parameter was
-	  documented in the XML documentation, but it was not actually
-	  registered with the sorcery object. This adds the parameter with
-	  a default of "asterisk", such that res_rtp_asterisk is chosen as
-	  the default RTP implementation. (closes issue ASTERISK-22380)
-	  Reported by: Rusty Newton Tested by: Rusty Newton ........ Merged
-	  revisions 397621 from
-	  http://svn.asterisk.org/svn/asterisk/branches/12
-
-2013-08-23 22:40 +0000 [r397615]  Matthew Jordan <mjordan at digium.com>
-
-	* /: Set new merge properties on 12
-
-2013-08-23 22:20 +0000 [r397613]  Joshua Colp <jcolp at digium.com>
-
-	* main/bucket.c: Fix building of trunk. Note: This is why I commit
-	  on the weekend.
+	* channels/sig_pri.h, channels/chan_dahdi.c,
+	  configs/chan_dahdi.conf.sample, /, configure,
+	  include/asterisk/autoconfig.h.in, configure.ac,
+	  channels/sig_pri.c: Merged revisions 332265 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332265 | rmudgett | 2011-08-17 11:01:29 -0500
+	  (Wed, 17 Aug 2011) | 33 lines Merged revisions 332264 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332264 | rmudgett | 2011-08-17 10:51:08 -0500 (Wed, 17 Aug 2011)
+	  | 26 lines Outgoing BRI calls fail when using Asterisk 1.8 with
+	  HA8, HB8, and B410P cards. France Telecom brings layer 2 and
+	  layer 1 down on BRI lines when the line is idle. When layer 1
+	  goes down Asterisk cannot make outgoing calls and the HA8 and HB8
+	  cards also get IRQ misses. The inability to make outgoing calls
+	  is because the line is in red alarm and Asterisk will not make
+	  calls over a line it considers unavailable. The IRQ misses for
+	  the HA8 and HB8 card are because the hardware is switching clock
+	  sources from the line which just brought layer 1 down to internal
+	  timing. There is a DAHDI option for the B410P card to not tell
+	  Asterisk that layer 1 went down so Asterisk will allow outgoing
+	  calls: "modprobe wcb4xxp teignored=1". There is a similar DAHDI
+	  option for the HA8 and HB8 cards: "modprobe wctdm24xxp
+	  bri_teignored=1". Unfortunately that will not clear up the IRQ
+	  misses when the telco brings layer 1 down. * Add layer 2
+	  persistence option to customize the layer 2 behavior on BRI PTMP
+	  lines. The new option has three settings: 1) Use libpri default
+	  layer 2 setting. 2) Keep layer 2 up. Bring layer 2 back up when
+	  the peer brings it down. 3) Leave layer 2 down when the peer
+	  brings it down. Layer 2 will be brought up as needed for outgoing
+	  calls. JIRA AST-598 ........ ................
+
+2011-08-16 20:15 +0000 [r332178]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* tests/test_substitution.c, tests/test_heap.c, /,
+	  tests/test_expr.c, tests/test_ast_format_str_reduce.c,
+	  tests/test_logger.c, tests/test_gosub.c, tests/test_app.c,
+	  tests/test_dlinklists.c, tests/test_event.c, tests/test_db.c,
+	  tests/test_linkedlists.c, tests/test_sched.c,
+	  tests/test_netsock2.c, tests/test_strings.c, tests/test_pbx.c,
+	  tests/test_func_file.c, tests/test_security_events.c,
+	  tests/test_stringfields.c, tests/test_time.c, tests/test_skel.c,
+	  tests/test_acl.c, tests/test_locale.c, tests/test_utils.c,
+	  tests/test_devicestate.c, tests/test_aoc.c, tests/test_astobj2.c,
+	  tests/test_poll.c, tests/test_amihooks.c: Merged revisions 332177
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332177 | pabelanger | 2011-08-16 16:11:49 -0400
+	  (Tue, 16 Aug 2011) | 11 lines Merged revisions 332176 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332176 | pabelanger | 2011-08-16 16:10:13 -0400 (Tue, 16 Aug
+	  2011) | 4 lines Flag test modules as 'core' Review:
+	  https://reviewboard.asterisk.org/r/1369/ ........
+	  ................
+
+2011-08-16 17:53 +0000 [r332120]  Jonathan Rose <jrose at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 332119 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332119 | jrose | 2011-08-16 12:45:38 -0500
+	  (Tue, 16 Aug 2011) | 23 lines Merged revisions 332118 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332118 | jrose | 2011-08-16 12:38:19 -0500 (Tue, 16 Aug 2011) |
+	  16 lines ASTERISK-18067 ASTERISK-15479 - White Space affects
+	  mailbox value, multiple MWI subs Before, having multiple
+	  subscriptions to mailboxes on a sip peer set via the mailbox
+	  setting in sip.conf would only result in updates being sent on
+	  whichever mailbox triggered the mwi event. Now all of them get
+	  counted regardless. Also fixes a bug involving parsing of the
+	  mailbox option in sip.conf so that trailing and leading spaces
+	  before/after commas are trimmed. (closes issue ASTERISK-18067)
+	  Reported by: aragon (closes issue ASTERISK-15479) Reported by:
+	  Ben Winslow Patches:
+	  chan_sip.c-mwi_multi_mailbox_fix-1.6.2.13.diff (License #5288)
+	  patch uploaded by Ben Winslow ........ ................
+
+2011-08-16 17:23 +0000 [r332117]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/features.c, CHANGES, configs/features.conf.sample,
+	  main/asterisk.c: Merged revisions 332101 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332101 | rmudgett | 2011-08-16 12:17:28 -0500
+	  (Tue, 16 Aug 2011) | 140 lines Merged revisions 332100 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332100 | rmudgett | 2011-08-16 11:31:36 -0500 (Tue, 16 Aug 2011)
+	  | 133 lines Fix multiple parking issues. JIRA ASTERISK-17183
+	  Multi-parkinglot directs calls to wrong parkinglot. JIRA
+	  ASTERISK-17870 Cannot retrieve parked calls. JIRA ASTERISK-17430
+	  ParkedCall() with no extension should pickup first available call
+	  and does not. JIRA AST-576 Issues with parking lots * Removed
+	  searching for parking lots by extension. Parking lots can only be
+	  found by the parking lot name since parking lot access extensions
+	  and spaces are not guaranteed to be unique. * Added
+	  parking_lot_name option to the Park and ParkedCall applications.
+	  Updated documentation for Park and ParkedCall applications. * Add
+	  parkext_exclusive configuration option to make parking entry
+	  extensions specify which parking lot they access. (closes issue
+	  ASTERISK-17183) Reported by: David Cabrejos Tested by: rmudgett,
+	  David Cabrejos (closes issue ASTERISK-17870) Reported by: Remi
+	  Quezada (closes issue ASTERISK-17430) Reported by: Philippe
+	  Lindheimer JIRA ASTERISK-17452 Parking_offset not used JIRA
+	  AST-624 'next' setting for findslot does nothing * Reimplemented
+	  since findslot feature option broken by -r114655. (closes issue
+	  ASTERISK-17452) Reported by: David Woolley Tested by: rmudgett
+	  JIRA ASTERISK-15792 Dialplan continues execution after transfer
+	  to park. This happens for DTMF attended transfer, DTMF blind
+	  transfer, and DTMF one-touch-parking if the party initiating
+	  these features also initiated the call. * Fixed the return code
+	  from the affected builtin features when parking a call. (closes
+	  issue ASTERISK-15792) Reported by: Mat Murdock Tested by:
+	  rmudgett, twilson JIRA AST-607 The courtesytone is not playing to
+	  the expected call when picking up a parked call. This is mostly a
+	  documentation problem. However, the option is not reset to the
+	  default when features.conf is reloaded. * Updated
+	  features.conf.sample documentation for courtesytone and
+	  parkedplay options. * Reset the parkedplay option to default when
+	  features.conf is reloaded. JIRA AST-615 AMI Park action followed
+	  by features reload results in orphaned channels in parking lot. *
+	  Reloading features.conf will not touch parking lots that have
+	  calls still parked in them. Reload again at a later time. Misc
+	  additional fixes: * Added unit test for parking lot dialplan
+	  usage checking. * Made update connected line when a parked call
+	  is retrieved from a parking lot. * Made retrieved parked call
+	  stop ringing or MOH depending upon how the call was waiting in
+	  the parking lot. * Made CLI "features show" indicate if the
+	  parking lot is enabled for use. * Added PARKINGDYNEXTEN channel
+	  variable to allow dynamic parking lots to specify the parking lot
+	  access extension. * Made AMI ParkedCalls action ParkedCall events
+	  have a Parkinglot header. * Made AMI ParkedCalls action
+	  ParkedCallsComplete event have a Total header. * Fixed potential
+	  deadlock from AMI Park action holding channel locks while calling
+	  masq_park_call(). * Fixed several places where ast_strdupa() were
+	  used inside of loops. (Mostly fixed by refactoring the loop body
+	  into its own function.) * Fixed copy_parkinglot() copying too
+	  much from the source parking lot. Extracted the parking lot
+	  configuration settings into struct parkinglot_cfg. * Refactored
+	  courtesytone playing code to put the channel not playing the tone
+	  in autoservice. * Fix when pbx-parkingfailed is played that the
+	  other channel is put in autoservice if it exists. * Fixed
+	  parkinglot reference leak in parked_call_exec() error paths. *
+	  Fixed parkinglot_unref() use of parkinglot after it was unreffed.
+	  * Made destroy the struct ast_parkinglot parkings lock when done.
+	  * Refactored the features.conf parking lot configuration code to
+	  eliminate redundancy. * Fixed feature reload to better protect
+	  parking lots. * Fixed parking lot container reference leak in
+	  handle_parkedcalls(). * Fixed the total count in
+	  handle_parkedcalls(). Review:
+	  https://reviewboard.asterisk.org/r/1358/ ........
+	  ................
+
+2011-08-16 15:21 +0000 [r332028-332044]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, channels/sip/include/sip.h: Merged revisions 332042 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r332042 | mnicholson | 2011-08-16 10:20:48 -0500 (Tue,
+	  16 Aug 2011) | 2 lines fix a code comment AST-580 ........
+
+	* /, UPGRADE.txt, CHANGES: Merged revisions 332029 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r332029 | mnicholson | 2011-08-16 10:17:16 -0500 (Tue, 16 Aug
+	  2011) | 2 lines Moved notes about 'storesipcause' to UPGRADE.txt
+	  from CHANGES AST-580 ........
+
+	* /, channels/chan_sip.c, channels/sip/include/sip.h: Merged
+	  revisions 332027 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332027 | mnicholson | 2011-08-16 10:08:40 -0500
+	  (Tue, 16 Aug 2011) | 9 lines Merged revisions 332026 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r332026 | mnicholson | 2011-08-16 10:06:31 -0500 (Tue,
+	  16 Aug 2011) | 2 lines use DEFAULT_STORE_SIP_CAUSE to set the
+	  default value for the 'storesipcause' option AST-580 ........
+	  ................
+
+2011-08-16 14:47 +0000 [r332024]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_local.c: Formatting changes while working with
+	  DTMF...
+
+2011-08-16 14:41 +0000 [r332023]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, channels/chan_sip.c, configs/sip.conf.sample, CHANGES: Merged
+	  revisions 332022 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r332022 | mnicholson | 2011-08-16 09:40:37 -0500
+	  (Tue, 16 Aug 2011) | 16 lines In 10 and trunk this option is
+	  disabled by default. Merged revisions 332021 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r332021 | mnicholson | 2011-08-16 09:20:43 -0500 (Tue, 16 Aug
+	  2011) | 7 lines Added the 'storesipcause' option to sip.conf to
+	  allow the user to disable the setting of HASH(SIP_CAUSE,<chan
+	  name>) on the channel. Having chan_sip set HASH(SIP_CAUSE,<chan
+	  name>) on the channel carries a significant performance penalty
+	  because of the usage of the MASTER_CHANNEL() dialplan function.
+	  AST-580 ........ ................
+
+2011-08-15 17:36 +0000 [r331957]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 331956 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331956 | rmudgett | 2011-08-15 12:35:03 -0500
+	  (Mon, 15 Aug 2011) | 20 lines Merged revisions 331955 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331955 | rmudgett | 2011-08-15 12:24:08 -0500 (Mon, 15 Aug 2011)
+	  | 13 lines Fix some minor chan_dahdi config load issues. *
+	  Address chan_dahdi.conf dahdichan option todo item about needing
+	  line number. * Make ignore_failed_channels option also apply to
+	  dahdichan option. * Don't attempt to create a default pseudo
+	  channel if the chan_dahdi.conf channel/channels option is not
+	  allowed. * Add a similar check for dahdichan in normal
+	  chan_dahdi.conf sections as is done in users.conf. ........
+	  ................
+
+2011-08-15 15:24 +0000 [r331903]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* main/rtp_engine.c, /: Merged revisions 331894 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331894 | pabelanger | 2011-08-15 11:22:45 -0400
+	  (Mon, 15 Aug 2011) | 12 lines Merged revisions 331886 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331886 | pabelanger | 2011-08-15 11:21:16 -0400 (Mon, 15 Aug
+	  2011) | 5 lines Fix noisy message when briding channels (closes
+	  issue ASTERISK-18270) Reported by: Federico Alves ........
+	  ................
+
+2011-08-15 15:15 +0000 [r331869]  David Vossel <dvossel at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 331868 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331868 | dvossel | 2011-08-15 10:14:13 -0500
+	  (Mon, 15 Aug 2011) | 12 lines Merged revisions 331867 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331867 | dvossel | 2011-08-15 10:12:16 -0500 (Mon, 15 Aug 2011)
+	  | 6 lines Fixes locking inversion issues present in the handling
+	  of the sip REFER method. (closes issue ASTERISK-18082) Reported
+	  by: James Van Vleet ........ ................
+
+2011-08-15 13:27 +0000 [r331830]  Olle Johansson <oej at edvina.net>
+
+	* channels/chan_sip.c: Formatting guideline fixes
+
+2011-08-12 19:06 +0000 [r331776]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, apps/app_queue.c: Merged revisions 331775 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331775 | mnicholson | 2011-08-12 14:03:31 -0500
+	  (Fri, 12 Aug 2011) | 17 lines Merged revisions 331774 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331774 | mnicholson | 2011-08-12 14:01:27 -0500 (Fri, 12 Aug
+	  2011) | 11 lines Unlock the channel before calling update_queue.
+	  Holding the channel lock when calling update_queue which attempts
+	  to lock the queue lock can cause a deadlock. This deadlock
+	  involves the following chain: 1. hold chan lock -> wait queue
+	  lock 2. hold queue lock -> wait agent list lock 3. hold agent
+	  list lock -> wait chan list lock 4. hold chan list lock -> wait
+	  chan lock ........ ................
+
+2011-08-12 19:01 +0000 [r331773]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 331772 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331772 | rmudgett | 2011-08-12 13:59:45 -0500
+	  (Fri, 12 Aug 2011) | 15 lines Merged revisions 331771 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331771 | rmudgett | 2011-08-12 13:58:40 -0500 (Fri, 12 Aug 2011)
+	  | 8 lines Suppress warning message when using DAHDITransfer or
+	  DAHDIHangup. * The fake event should only be processed by the
+	  channel that currently owns the private and not the associated
+	  call waiting or 3-way channel. JIRA AST-620 JIRA SWP-3616
+	  ........ ................
+
+2011-08-12 18:03 +0000 [r331717]  Jonathan Rose <jrose at digium.com>
+
+	* apps/app_dial.c, /, apps/app_meetme.c: Merged revisions 331644
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331644 | jrose | 2011-08-12 11:18:57 -0500
+	  (Fri, 12 Aug 2011) | 9 lines Merged revisions 331635 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r331635 | jrose | 2011-08-12 10:49:17 -0500 (Fri, 12 Aug
+	  2011) | 1 line Fixes 32bit compilation warnings brought on by
+	  331634 in app_dial and app_meetme ........ ................
+
+2011-08-12 17:56 +0000 [r331716]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, /: Merged revisions 331715 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331715 | rmudgett | 2011-08-12 12:54:47 -0500
+	  (Fri, 12 Aug 2011) | 29 lines Merged revisions 331714 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331714 | rmudgett | 2011-08-12 12:47:57 -0500 (Fri, 12 Aug 2011)
+	  | 22 lines AMI actions DAHDIHangup and DAHDITransfer have no
+	  effect. The AMI actions DAHDIHangup and DAHDITransfer have no
+	  effect on a DAHDI channel. These two AMI actions are highly
+	  specialized to analog channels and appear to make the channel
+	  behave like a jack port for headsets. * Made the faked DAHDI
+	  event get processed before a normal media stream read in
+	  dahdi_read() instead of trying to trigger an exception read by
+	  setting the AST_FLAG_EXCEPTION flag. Apparently a change was made
+	  long ago that changed how AST_FLAG_EXCEPTION is processed in the
+	  core. Unfortunately, the faked DAHDI events no longer worked when
+	  that happened. * Updated the DAHDI AMI action documentation for
+	  the following actions: DAHDITransfer, DAHDIHangup,
+	  DAHDIDialOffhook, DAHDIDNDon, DAHDIDNDoff, DAHDIShowChannels, and
+	  DAHDIRestart. * Made use sscanf() instead of atoi() for better
+	  error checking of the DAHDIChannel header string. JIRA AST-620
+	  JIRA SWP-3616 ........ ................
+
+2011-08-12 16:32 +0000 [r331660]  Terry Wilson <twilson at digium.com>
+
+	* /, tests/test_netsock2.c: Merged revisions 331659 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331659 | twilson | 2011-08-12 11:31:21 -0500
+	  (Fri, 12 Aug 2011) | 11 lines Merged revisions 331658 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331658 | twilson | 2011-08-12 11:30:26 -0500 (Fri, 12 Aug 2011)
+	  | 4 lines Fix netsock2 multiple zero-expansion test Remove
+	  erroneous single bracket. ........ ................
+
+2011-08-12 16:22 +0000 [r331657]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/logger.c: Merged revisions 331654 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331654 | kmoore | 2011-08-12 11:21:37 -0500
+	  (Fri, 12 Aug 2011) | 19 lines Merged revisions 331649 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331649 | kmoore | 2011-08-12 11:20:25 -0500 (Fri, 12 Aug 2011) |
+	  12 lines Logger does not warn of failure to open logging channels
+	  Currently, logger only prints an error message to stderr when it
+	  fails to open a logger channel where many users will not see it
+	  because the logger lock is held. The alternative provided by this
+	  patch is to log the error to all attached consoles in the hopes
+	  that it will be easier to see. Additionally, this patch prevents
+	  the failed logger channel from being added to the list where it
+	  would silently fail on each call to the Asterisk logger. (closes
+	  issue ASTERISK-16231) Review:
+	  https://reviewboard.asterisk.org/r/1338 ........ ................
+
+2011-08-11 21:55 +0000 [r331580]  Jason Parker <jparker at digium.com>
+
+	* apps/app_dial.c, /, apps/app_meetme.c: Merged revisions 331579
+	  via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331579 | qwell | 2011-08-11 16:54:54 -0500
+	  (Thu, 11 Aug 2011) | 13 lines Merged revisions 331578 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331578 | qwell | 2011-08-11 16:46:39 -0500 (Thu, 11 Aug 2011) |
+	  6 lines Use proper values for 64-bit option flags. Also, reusing
+	  bits es no bueno, so change the value of a duplicate. (issue
+	  ASTERISK-18239) ........ ................
+
+2011-08-11 21:44 +0000 [r331577]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, funcs/func_shell.c: Merged revisions 331576 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331576 | rmudgett | 2011-08-11 16:42:21 -0500
+	  (Thu, 11 Aug 2011) | 16 lines Merged revisions 331575 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331575 | rmudgett | 2011-08-11 16:39:58 -0500 (Thu, 11 Aug 2011)
+	  | 9 lines Segfault in shell_helper in func_shell.c. The return
+	  value of popen() was not checked for failure to open. (closes
+	  issue ASTERISK-18109) JIRA SWP-3633 Reported by: Michael Myles
+	  Tested by: rmudgett ........ ................
+
+2011-08-10 22:24 +0000 [r331519]  Kinsey Moore <kmoore at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 331518 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331518 | kmoore | 2011-08-10 17:23:49 -0500
+	  (Wed, 10 Aug 2011) | 17 lines Merged revisions 331517 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331517 | kmoore | 2011-08-10 17:23:08 -0500 (Wed, 10 Aug 2011) |
+	  10 lines SIP Notify via AMI or CLI leaks SIP PVTs Any SIP notify
+	  sent via AMI or CLI leaks a SIP PVT with ref count +2. Removing
+	  the additional ref just before the invite and adding an unref
+	  following it corrects the issue as seen via REF_DEBUG. The unref
+	  existed in a distant revision and it appears as though the wrong
+	  ref operation was removed. (closes issue ASTERISK-18091) Review:
+	  https://reviewboard.asterisk.org/r/1332/ ........
+	  ................
+
+2011-08-10 20:51 +0000 [r331419-331463]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, main/logger.c: Merged revisions 331462 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331462 | rmudgett | 2011-08-10 15:41:35 -0500
+	  (Wed, 10 Aug 2011) | 37 lines Merged revisions 331461 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331461 | rmudgett | 2011-08-10 15:29:59 -0500 (Wed, 10 Aug 2011)
+	  | 30 lines Output of queue log not started until logger reloaded.
+	  ASTERISK-15863 caused a regression with queue logging. The output
+	  of the queue log is not started until the logger configuration is
+	  reloaded. * Queue log initialization is completely delayed until
+	  the first message is posted to the queue log system. Including
+	  the initial opening of the queue log file. * Fixed rotate_file()
+	  ROTATE strategy to give the file just rotated out to the
+	  configured exec function after rotate. Just like the other
+	  strategies. * Fixed logger reload to always post the queue reload
+	  entry instead of just if there is a queue log file. * Refactored
+	  some code to eliminate some redundancy and to reduce stack
+	  utilization. (closes issue ASTERISK-17036) JIRA SWP-2952 Reported
+	  by: Juan Carlos Valero Patches: jira_asterisk_17036_v1.8.patch
+	  (license #5621) patch uploaded by rmudgett Tested by: rmudgett
+	  (closes issue ASTERISK-18208) Reported by: Christian Pinedo
+	  Review: https://reviewboard.asterisk.org/r/1333/ ........
+	  ................
+
+	* /, main/features.c: Merged revisions 331420 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r331420 | rmudgett | 2011-08-10 14:07:53 -0500 (Wed, 10 Aug 2011)
+	  | 2 lines Make sure feature_request_and_dial() initializes
+	  outstate if passed in. ........
+
+	* /, main/features.c, CHANGES: Merged revisions 331418 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r331418 | rmudgett | 2011-08-10 13:25:08 -0500 (Wed, 10 Aug 2011)
+	  | 6 lines Revert -r318141. It was a band-aid that only partially
+	  fixed parking. A better fix is on reviewboard review 1358. (issue
+	  ASTERISK-17374) ........
+
+2011-08-10 15:45 +0000 [r331371]  Jonathan Rose <jrose at digium.com>
+
+	* channels/chan_sip.c, CHANGES: SIP display-name needed to be empty
+	  for Avaya IP500 In order to address a compatability issue with
+	  certain features on certain devices which rely on display name
+	  content to change behavior, initreqprep in chan_sip.c has been
+	  changed to no longer substitute cid_number into the display name
+	  when cid_name isn't present. Instead, it will send no display
+	  name in that case. (closes issue ASTERISK-16198) Reported by:
+	  Walter Doekes Review: https://reviewboard.asterisk.org/r/1341/
+
+2011-08-10 13:49 +0000 [r331317]  Kinsey Moore <kmoore at digium.com>
+
+	* main/manager.c, /: Merged revisions 331316 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331316 | kmoore | 2011-08-10 08:48:41 -0500
+	  (Wed, 10 Aug 2011) | 15 lines Merged revisions 331315 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331315 | kmoore | 2011-08-10 08:47:46 -0500 (Wed, 10 Aug 2011) |
+	  8 lines AMI action ModuleReload returns Error if Module: missing
+	  or empty An empty string was not being checked for properly
+	  causing identification of the module to be reloaded to fail and
+	  return an Error with message "No such module." (closes issue
+	  AST-616) ........ ................
+
+2011-08-09 23:17 +0000 [r331266]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /, channels/chan_sip.c, main/features.c,
+	  channels/chan_iax2.c, apps/app_parkandannounce.c: Merged
+	  revisions 331265 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331265 | rmudgett | 2011-08-09 18:12:49 -0500
+	  (Tue, 09 Aug 2011) | 22 lines Merged revisions 331248 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331248 | rmudgett | 2011-08-09 17:12:59 -0500 (Tue, 09 Aug 2011)
+	  | 15 lines Misc minor items found in code. * Add some reentrancy
+	  protection in pbx.c when creating the contexts_table hash table.
+	  * Fix inverted test in chan_sip.c conditional code. * Fix
+	  uninitialized variable and use of the wrong variable in
+	  chan_iax2.c. * Fix test of return value in app_parkandannounce.c.
+	  Explicitly testing for -1 is bad if the function does not
+	  actually return that value when it fails. * Fixup some comments
+	  and add some curly braces in features.c. ........
+	  ................
+
+2011-08-09 17:12 +0000 [r331202]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooGkClient.c, addons/chan_ooh323.c, /,
+	  addons/ooh323c/src/ooLogChan.c, addons/ooh323c/src/ooq931.c:
+	  Merged revisions 331147,331200 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331147 | may | 2011-08-09 20:16:55 +0400 (Tue,
+	  09 Aug 2011) | 11 lines Merged revisions 331146 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331146 | may | 2011-08-09 20:13:09 +0400 (Tue, 09 Aug 2011) | 4
+	  lines move ast_cond_signal for admitted call after all data
+	  filled/freed clear all log channels by pointed number not only
+	  first free allocated callToken in ooh323_answer ........
+	  ................ r331200 | may | 2011-08-09 20:36:39 +0400 (Tue,
+	  09 Aug 2011) | 9 lines Setup IP proto version for call in GK mode
+	  Added additional check for IP semantics before parse destination
+	  by ast_parse_args due to it can parse numeric as IP. (closes
+	  issue ASTERISK-18218) Reported by: slesru Patch:
+	  ASTERISK-18218.patch ................
+
+2011-08-09 17:08 +0000 [r331201]  Kinsey Moore <kmoore at digium.com>
+
+	* funcs/func_enum.c, UPGRADE.txt, main/enum.c: Allow ENUM query
+	  functions to report lookup errors The ENUM dialplan functions do
+	  not report DNS query errors properly. It is useful to
+	  differentiate between failed query (e.g. non-existent domain) vs.
+	  no data records of the appropriate type. This is required to make
+	  overlapped dialing work. (closes issue ASTERISK-13769) Review:
+	  https://reviewboard.asterisk.org/r/1355/ Patch-by: Timo Teras
+
+2011-08-09 16:02 +0000 [r331140-331144]  Jason Parker <jparker at digium.com>
+
+	* /, doc/asterisk.8: Merged revisions 331143 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331143 | qwell | 2011-08-09 10:59:54 -0500
+	  (Tue, 09 Aug 2011) | 9 lines Merged revisions 331142 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r331142 | qwell | 2011-08-09 10:58:16 -0500 (Tue, 09 Aug
+	  2011) | 1 line Regenerate asterisk man page from sgml. ........
+	  ................
+
+	* /, doc/asterisk.8, configs/asterisk.conf.sample,
+	  configs/voicemail.conf.sample, doc/asterisk.sgml: Merged
+	  revisions 331139 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331139 | qwell | 2011-08-09 10:50:07 -0500
+	  (Tue, 09 Aug 2011) | 19 lines Merged revisions 306999 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r306999 | lathama | 2011-02-08 14:22:35 -0600 (Tue, 08 Feb 2011)
+	  | 12 lines Documentation Updates Note default polling setting in
+	  voicemail.conf Add missing config to asterisk.conf Update manpage
+	  (issue #16505) Reported by: tzafrir Patches:
+	  asterisk_sgml_fixes_demo.diff uploaded by tzafrir (license 46)
+	  Tested by: lathama, tzafrir ........ ................
+
+	* doc/asterisk.8, configs/asterisk.conf.sample,
+	  configs/voicemail.conf.sample, doc/asterisk.sgml: Merged
+	  revisions 331138 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r331138 | qwell | 2011-08-09 10:47:20 -0500 (Tue, 09 Aug 2011) |
+	  1 line Revert merge of r306999, due to merge conflict. ........
+
+2011-08-08 22:59 +0000 [r331042-331098]  Terry Wilson <twilson at digium.com>
+
+	* /, UPGRADE.txt, CHANGES, include/asterisk/manager.h: Merged
+	  revisions 331097 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r331097 | twilson | 2011-08-08 17:59:01 -0500 (Mon, 08 Aug 2011)
+	  | 5 lines Bump the AMI protocol version to 1.2 As a result of
+	  converting Unlink events that were missed in the AMI 1.1 update
+	  to Bridge events, the AMI protocol version is being incremented.
+	  ........
+
+	* main/channel.c, /, CHANGES: Merged revisions 331041 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r331041 | twilson | 2011-08-08 16:12:51 -0500 (Mon, 08 Aug 2011)
+	  | 6 lines Replace AMI Unlink events with Bridge events A previous
+	  update converted some of the Link and Unlink events to Bridge
+	  events, but a couple of Unlink events were missed. This patch
+	  rectifies the situation. (closes issues ASTERISK-17455) ........
+
+2011-08-08 20:54 +0000 [r331000-331040]  Kinsey Moore <kmoore at digium.com>
+
+	* /, res/res_musiconhold.c: Merged revisions 331039 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r331039 | kmoore | 2011-08-08 15:53:30 -0500
+	  (Mon, 08 Aug 2011) | 18 lines Merged revisions 331038 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r331038 | kmoore | 2011-08-08 15:52:45 -0500 (Mon, 08 Aug 2011) |
+	  11 lines In-queue MOH stops after a periodic announcement If the
+	  seek value is past the end of file when resuming G.722 MOH, MOH
+	  will cease to function for the duration of the MOH session
+	  through all starts and stops until saved state is cleared.
+	  Adjusting the code to guarantee a single valid read (which is
+	  already assumed) fixes the bug. (closes issue ASTERISK-18077)
+	  Review: https://reviewboard.asterisk.org/r/1328/ Tested-by:
+	  Jonathan Rose <jrose at digium.com> ........ ................
+
+	* configs/queues.conf.sample, apps/app_queue.c: Log queue member
+	  name when state_interface is set for ADDMEMBER and REMOVEMEMBER
+	  events app_queue logs the events ADDMEMBER and REMOVEMEMBER with
+	  the agent field set to the interface value rather than the
+	  membername value when a member is added with a state_interface
+	  value set. However all other member related queue events are
+	  logged with the membername when a state_interface is set. This
+	  patch makes these fields optionally more consistent and correct.
+	  (closes issue ASTERISK-14769) Review:
+	  https://reviewboard.asterisk.org/r/1286 Patch-by: Jamuel Starkey
+	  Tested-by: Kinsey Moore <kmoore at digium.com>
+
+	* apps/app_queue.c: app_queue: Add StateInterface to output of
+	  "queue show" and "QueueStatus" This patch adds the
+	  state_interface of the queue member struct to the output of
+	  "queue show" (CLI command) and "QueueStatus" (AMI action) when
+	  displaying relevant queue member information. For the AMI event
+	  message the variable StateInterface has been added. (closes issue
+	  ASTERISK-18071) Review: https://reviewboard.asterisk.org/r/1300/
+	  Patch-by: Jamuel Starkey
+
+2011-08-05 15:57 +0000 [r330941]  David Vossel <dvossel at digium.com>
+
+	* /, codecs/codec_resample.c: Merged revisions 330940 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r330940 | dvossel | 2011-08-05 10:53:49 -0500 (Fri, 05 Aug 2011)
+	  | 2 lines The slin resampler is no longer dependent on an
+	  external library, but the dependency was not removed correctly.
+	  ........
+
+2011-08-05 08:47 +0000 [r330903]  Alexandr Anikin <may at telecom-service.ru>
+
+	* addons/ooh323c/src/ooGkClient.c, /,
+	  addons/ooh323c/src/ooCmdChannel.c: Merged revisions 330899 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330899 | may | 2011-08-05 11:38:28 +0400 (Fri,
+	  05 Aug 2011) | 11 lines Merged revisions 330827 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330827 | may | 2011-08-04 23:37:16 +0400 (Thu, 04 Aug 2011) | 4
+	  lines change gk client behaivour on rrq/grq failures to setup
+	  timers and next tries after timeout instead of complete failure
+	  in the ooh323 stack ........ ................
+
+2011-08-04 20:53 +0000 [r330845]  Terry Wilson <twilson at digium.com>
+
+	* /, configure, configure.ac: Merged revisions 330844 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330844 | twilson | 2011-08-04 15:51:23 -0500
+	  (Thu, 04 Aug 2011) | 11 lines Merged revisions 330843 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330843 | twilson | 2011-08-04 15:29:19 -0500 (Thu, 04 Aug 2011)
+	  | 4 lines Make libsrtp instructions more explicit when linking
+	  fails (closes issue ASTERISK-18139) ........ ................
+
+2011-08-03 15:16 +0000 [r330707-330764]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/Makefile: Merged revisions 330763 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330763 | kmoore | 2011-08-03 10:15:26 -0500
+	  (Wed, 03 Aug 2011) | 16 lines Merged revisions 330762 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330762 | kmoore | 2011-08-03 10:14:36 -0500 (Wed, 03 Aug 2011) |
+	  9 lines editing files in main/editline does not ensure rebuild of
+	  libedit.a When editing a source file in main/editline, the build
+	  system does not rebuild libedit.a and uses the already existing
+	  one instead. Adding a PHONY to CHECK_SUBDIR fixes this problem.
+	  (closes issue ASTERISK-16221) Patch-by: Walter Doekes ........
+	  ................
+
+	* channels/chan_dahdi.c, channels/sig_analog.c, /: Merged revisions
+	  330706 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330706 | kmoore | 2011-08-03 08:39:06 -0500
+	  (Wed, 03 Aug 2011) | 17 lines Merged revisions 330705 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330705 | kmoore | 2011-08-03 08:38:17 -0500 (Wed, 03 Aug 2011) |
+	  10 lines Call pickup broken for DAHDI channels when beginning
+	  with # The call pickup feature did not work on DAHDI devices for
+	  anything other than feature codes beginning with * since all
+	  feature codes in chan_dahdi were originally hard-coded to begin
+	  with *. This patch is also applied to chan_dahdi.c to fix this
+	  bug with radio modes. (closes issue AST-621) Review:
+	  https://reviewboard.asterisk.org/r/1336/ ........
+	  ................
+
+2011-08-02 20:54 +0000 [r330650]  Kevin P. Fleming <kpfleming at digium.com>
+
+	* /, res/res_jabber.c: Merged revisions 330649 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330649 | kpfleming | 2011-08-02 15:52:44 -0500
+	  (Tue, 02 Aug 2011) | 9 lines Merged revisions 330648 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r330648 | kpfleming | 2011-08-02 15:51:56 -0500 (Tue, 02
+	  Aug 2011) | 2 lines Convert an error message to actually be
+	  helpful. ........ ................
+
+2011-08-02 16:19 +0000 [r330577-330593]  David Vossel <dvossel at digium.com>
+
+	* /, channels/chan_iax2.c: Merged revisions 330586 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330586 | dvossel | 2011-08-02 11:17:59 -0500
+	  (Tue, 02 Aug 2011) | 15 lines Merged revisions 330581 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330581 | dvossel | 2011-08-02 11:15:08 -0500 (Tue, 02 Aug 2011)
+	  | 8 lines Fixes crash in chan_iax2. Fixes crash in chan_iax2
+	  resulting from an edge case in the way control frames are queued
+	  during calltoken negotiation is complete. (closes issue
+	  ASTERISK-17610) Reported by: mgrobecker ........ ................
+
+	* /, channels/chan_sip.c: Merged revisions 330579 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330579 | dvossel | 2011-08-02 11:08:57 -0500
+	  (Tue, 02 Aug 2011) | 9 lines Merged revisions 330578 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r330578 | dvossel | 2011-08-02 11:07:02 -0500 (Tue, 02
+	  Aug 2011) | 2 lines Optimization to buffer initialization fix.
+	  ........ ................
+
+	* /, channels/chan_sip.c: Merged revisions 330576 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330576 | dvossel | 2011-08-02 10:55:36 -0500
+	  (Tue, 02 Aug 2011) | 12 lines Merged revisions 330575 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330575 | dvossel | 2011-08-02 10:53:21 -0500 (Tue, 02 Aug 2011)
+	  | 5 lines Fixes uninitialized string buffer in log message.
+	  (closes issue ASTERISK-17200) Reported by: lmadsen ........
+	  ................
+
+2011-08-01 15:24 +0000 [r330435]  Kinsey Moore <kmoore at digium.com>
+
+	* /, main/say.c: Merged revisions 330434 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330434 | kmoore | 2011-08-01 10:23:29 -0500
+	  (Mon, 01 Aug 2011) | 16 lines Merged revisions 330433 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330433 | kmoore | 2011-08-01 10:22:10 -0500 (Mon, 01 Aug 2011) |
+	  9 lines Incorrect playback for Spanish in some circumstances When
+	  you say the time in spanish and it is 01:00 - 01:59 or 13:00 -
+	  13:59 you must use female pronunciation "1F". The function
+	  "say_date_with_format_es" does not take this in account. (closes
+	  ASTERISK-15016) Patch-by: Luis Jimenez ........ ................
+
+2011-07-31 00:19 +0000 [r330370-330379]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/astobj2.c: Fixed compiler warning and a couple prototype
+	  mismatches.
+
+	* main/channel.c, /: Merged revisions 330369 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330369 | rmudgett | 2011-07-30 18:57:56 -0500
+	  (Sat, 30 Jul 2011) | 11 lines Merged revisions 330368 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330368 | rmudgett | 2011-07-30 18:56:29 -0500 (Sat, 30 Jul 2011)
+	  | 4 lines Remove some redundant locking code in
+	  ast_do_masquerade(). Also updated some comments. ........
+	  ................
+
+2011-07-30 15:54 +0000 [r330313]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* main/channel.c, /: Merged revisions 330312 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330312 | irroot | 2011-07-30 17:34:41 +0200
+	  (Sat, 30 Jul 2011) | 15 lines Merged revisions 330311 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r330311 | irroot | 2011-07-30 17:25:16 +0200 (Sat, 30 Jul 2011) |
+	  9 lines prevent double masqurading channels when one is been hung
+	  up and deadlock avoidance is used. There is a race condition in
+	  ast_do_masquerade / ast_hangup (at least) Reported by me signed
+	  off by schmidts with input from David Vossel Review:
+	  https://reviewboard.asterisk.org/r/1323/ ........
+	  ................
+
+2011-07-29 19:34 +0000 [r330273]  Russell Bryant <russell at russellbryant.com>
+
+	* include/asterisk/astobj2.h, tests/test_astobj2.c,
+	  channels/chan_iax2.c, main/astobj2.c: astobj2: Avoid using
+	  temporary objects + ao2_find() with OBJ_POINTER. There is a
+	  fairly common pattern making its way through the code base where
+	  we put a temporary object on the stack so we can call ao2_find()
+	  with OBJ_POINTER. The purpose is so that it can be passed into
+	  the object hash function. However, this really seems like a hack
+	  and potentially error prone. This patch is a first stab at
+	  approach to avoid having to do that. It adds a new flag, OBJ_KEY,
+	  which can be used instead of OBJ_POINTER in these situations.
+	  Then, the hash function can know whether it was given an object
+	  or some custom data to hash. The patch also changes some uses of
+	  ao2_find() for iax2_user and iax2_peer objects to reflect how
+	  OBJ_KEY would be used. So long, and thanks for all the fish.
+	  Review: https://reviewboard.asterisk.org/r/1184/
+
+2011-07-29 17:20 +0000 [r330205-330221]  Sean Bright <sean at malleable.com>
+
+	* /, formats/format_wav.c: Merged revisions 330217 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330217 | seanbright | 2011-07-29 13:19:42 -0400
+	  (Fri, 29 Jul 2011) | 9 lines Merged revisions 330213 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r330213 | seanbright | 2011-07-29 13:18:56 -0400 (Fri,
+	  29 Jul 2011) | 2 lines Correct the check for O_RDONLY. ........
+	  ................
+
+	* /, formats/format_wav.c: Merged revisions 330204 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330204 | seanbright | 2011-07-29 12:58:40 -0400
+	  (Fri, 29 Jul 2011) | 9 lines Merged revisions 330203 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r330203 | seanbright | 2011-07-29 12:58:08 -0400 (Fri,
+	  29 Jul 2011) | 2 lines Only write to wav files that were opened
+	  to be written to. ........ ................
+
+2011-07-29 05:27 +0000 [r330163]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, apps/app_confbridge.c: Merged revisions 330162 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r330162 | pabelanger | 2011-07-29 01:25:18 -0400 (Fri, 29 Jul
+	  2011) | 4 lines Fix typo pointed out on #asterisk Thanks notten
+	  ........
+
+2011-07-28 21:46 +0000 [r330109]  Terry Wilson <twilson at digium.com>
+
+	* /, main/term.c: Merged revisions 330108 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330108 | twilson | 2011-07-28 16:44:31 -0500
+	  (Thu, 28 Jul 2011) | 9 lines Merged revisions 330107 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r330107 | twilson | 2011-07-28 16:42:41 -0500 (Thu, 28
+	  Jul 2011) | 2 lines Make console colors work for
+	  TERM=xterm-256color ........ ................
+
+2011-07-28 17:16 +0000 [r330052]  Richard Mudgett <rmudgett at digium.com>
+
+	* /, channels/sig_pri.c: Merged revisions 330051 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r330051 | rmudgett | 2011-07-28 12:10:37 -0500
+	  (Thu, 28 Jul 2011) | 29 lines Merged revisions 330050 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ................ r330050 | rmudgett | 2011-07-28 12:04:24 -0500
+	  (Thu, 28 Jul 2011) | 22 lines Merged revisions 330033 from
+	  https://origsvn.digium.com/svn/asterisk/be/branches/C.3-bier
+	  .......... r330033 | rmudgett | 2011-07-28 11:26:38 -0500 (Thu,
+	  28 Jul 2011) | 15 lines Datacalls with B410P fail. Incoming and
+	  outgoing call legs of a data call are using different formats:
+	  a-law, u-law. When the call is bridged, the media stream is run
+	  through translation to convert the media formats. The translation
+	  is bad for data calls. * Make incoming call that does not
+	  explicitly specify u-law or a-law use the DAHDI channel's default
+	  law. The outgoing call always uses the default law from the DAHDI
+	  channel. (closes issue ABE-2800) Patches:
+	  jira_abe_2800_companding.patch (license #5621) patch uploaded by
+	  rmudgett .......... ................ ................
+
+2011-07-28 15:46 +0000 [r329996]  Jason Parker <jparker at digium.com>
+
+	* /, channels/chan_sip.c: Merged revisions 329995 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329995 | qwell | 2011-07-28 10:45:49 -0500
+	  (Thu, 28 Jul 2011) | 13 lines Merged revisions 329994 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329994 | qwell | 2011-07-28 10:45:24 -0500 (Thu, 28 Jul 2011) |
+	  6 lines Fix a SIP transfer deadlock. The locking in this function
+	  is very scary. There are like 6 structs involved. (closes issue
+	  AST-470) ........ ................
+
+2011-07-28 15:30 +0000 [r329993]  Matthew Nicholson <mnicholson at digium.com>
+
+	* /, res/res_fax.c: Merged revisions 329992 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329992 | mnicholson | 2011-07-28 10:28:21 -0500
+	  (Thu, 28 Jul 2011) | 13 lines Merged revisions 329991 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329991 | mnicholson | 2011-07-28 10:26:56 -0500 (Thu, 28 Jul
+	  2011) | 6 lines check for CONFIG_STATUS_FILE_INVALID when loading
+	  the res_fax config file Patch by: tzafrir Reported by: tzafrir
+	  (closes issue ASTERISK-18161) ........ ................
+
+2011-07-28 13:04 +0000 [r329897-329953]  Sean Bright <sean at malleable.com>
+
+	* configs/confbridge.conf.sample, /: Merged revisions 329952 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r329952 | seanbright | 2011-07-28 09:03:58 -0400 (Thu,
+	  28 Jul 2011) | 4 lines The default conf-usermenu says that '8'
+	  can be used to leave the conference, so put that in the sample
+	  user menu. '5' is supposed to extend the conference, but there
+	  doesn't appear to be a concept of that in the menu actions.
+	  ........
+
+	* /, apps/app_confbridge.c: Merged revisions 329950 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r329950 | seanbright | 2011-07-28 08:43:55 -0400 (Thu, 28 Jul
+	  2011) | 1 line Correct the spelling of 'conference.' ........
+
+	* /, channels/chan_sip.c: Merged revisions 329896 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329896 | seanbright | 2011-07-28 07:35:27 -0400
+	  (Thu, 28 Jul 2011) | 9 lines Merged revisions 329895 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r329895 | seanbright | 2011-07-28 07:34:33 -0400 (Thu,
+	  28 Jul 2011) | 2 lines Make the output of Externhost in 'sip show
+	  settings' more consistent. ........ ................
+
+2011-07-27 21:22 +0000 [r329835-329856]  Jonathan Rose <jrose at digium.com>
+
+	* main/cdr.c, main/pbx.c, include/asterisk/cdr.h, CHANGES:
+	  reverting 329840 due to failing tests. Going to change this
+	  feature to be purely optional.
+
+	* main/cdr.c, main/pbx.c, include/asterisk/cdr.h, CHANGES: Adds cdr
+	  logging of calls resulting in CONGESTION Applies a patch made a
+	  long time ago by alecdavis which adds a CDR feature for logging
+	  calls that failed due to congestion. (closes issue #15907)
+	  Reported by: alecdavis Patches: cdr_congestion.diff.txt uploaded
+	  by alecdavis (license #5546) Review:
+	  https://reviewboard.asterisk.org/r/454/
+
+2011-07-27 19:19 +0000 [r329775]  Sean Bright <sean at malleable.com>
+
+	* /, Makefile.moddir_rules: Merged revisions 329771 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329771 | seanbright | 2011-07-27 15:18:47 -0400
+	  (Wed, 27 Jul 2011) | 15 lines Merged revisions 329767 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329767 | seanbright | 2011-07-27 15:17:46 -0400 (Wed, 27 Jul
+	  2011) | 8 lines Explicitly sort the module list so that the
+	  menuselect lists are sorted. (closes ASTERISK-18141) Reported by:
+	  Richard Miller Patches: sort-order.diff uploaded by seanbright
+	  (License #5060) Tested by: leifmadsen ........ ................
+
+2011-07-27 18:12 +0000 [r329711]  Jonathan Rose <jrose at digium.com>
+
+	* /, configs/indications.conf.sample: Merged revisions 329710 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329710 | jrose | 2011-07-27 13:11:07 -0500
+	  (Wed, 27 Jul 2011) | 14 lines Merged revisions 329709 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329709 | jrose | 2011-07-27 13:10:30 -0500 (Wed, 27 Jul 2011) |
+	  8 lines Fix New Zealand indications profile based on
+	  http://www.telepermit.co.nz/TNA102.pdf (closes issue
+	  ASTERISK-16263) Reported by: richardf Patches:
+	  nz-indications.patch uploaded by richardf (License #6015)
+	  ........ ................
+
+2011-07-27 15:26 +0000 [r329671]  Sean Bright <sean at malleable.com>
+
+	* /, main/loader.c: Merged revisions 329670 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r329670 | seanbright | 2011-07-27 11:25:53 -0400 (Wed, 27 Jul
+	  2011) | 2 lines Sort the module list so that 'module show' is
+	  alphabetical. ........
+
+2011-07-27 04:27 +0000 [r329615]  Tilghman Lesher <tilghman at meg.abyt.es>
+
+	* /, cdr/cdr_odbc.c: Merged revisions 329614 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329614 | tilghman | 2011-07-26 23:25:26 -0500
+	  (Tue, 26 Jul 2011) | 13 lines Merged revisions 329613 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329613 | tilghman | 2011-07-26 23:23:46 -0500 (Tue, 26 Jul 2011)
+	  | 6 lines Duration and billsec are swapped in high resolution
+	  time. Closes ASTERISK-18024 Patches:
+	  20110726__ASTERISK-18024.diff by Tilghman Lesher (License 5003)
+	  ........ ................
+
+2011-07-26 14:27 +0000 [r329530-329564]  Jonathan Rose <jrose at digium.com>
+
+	* /, apps/app_voicemail.c: Merged revisions 329538 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329538 | jrose | 2011-07-26 09:19:34 -0500
+	  (Tue, 26 Jul 2011) | 11 lines Merged revisions 329529 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329529 | jrose | 2011-07-26 09:04:55 -0500 (Tue, 26 Jul 2011) |
+	  5 lines Changes sound file for prepend "then-press-pound" to
+	  "vm-then-pound" which is the same prompt, only it turned out
+	  "then-press-pound" was part of extra sounds. Also, vm is more
+	  appropriate anyway. ........ ................
+
+	* include/asterisk/app.h, /, configs/voicemail.conf.sample,
+	  main/app.c, apps/app_voicemail.c: Merged revisions 329528 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329528 | jrose | 2011-07-26 08:52:34 -0500
+	  (Tue, 26 Jul 2011) | 24 lines Merged revisions 329527 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329527 | jrose | 2011-07-26 08:25:35 -0500 (Tue, 26 Jul 2011) |
+	  17 lines Fixes some voicemail forwarding behavior based around
+	  prepend mode. Formerly, prepend forwarding would have the user
+	  record a message with no useful prompt and an expectation for the
+	  user to push a button on the phone when finished recording. If a
+	  length of silence was detected instead, the recording would be
+	  canceled and the user would re-enter the voicemail forwarding
+	  menu. Subsequent time-outs in prepend recording would also bug
+	  out in the sense that they would write over the original message
+	  and get sent to the recipient regardless of whether they timed
+	  out or were accepted. This patch fixes this issue and adds a
+	  prompt which will be played after a timeout informing the user
+	  that they needed to press a button. Currently, the sound files
+	  that we have are somewhat inadquate for this, so after the call
+	  we simply have Allison say "Please try again. Then press pound."
+	  which actually relies on two separate sound files. Just one would
+	  be more appropriate. reporter: Vlad Povorozniuc Review:
+	  https://reviewboard.asterisk.org/r/1327/ ........
+	  ................
+
+2011-07-25 19:57 +0000 [r329473]  Paul Belanger <paul.belanger at polybeacon.com>
+
+	* /, main/enum.c: Merged revisions 329472 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329472 | pabelanger | 2011-07-25 15:55:33 -0400
+	  (Mon, 25 Jul 2011) | 9 lines Merged revisions 329471 via svnmerge
+	  from https://origsvn.digium.com/svn/asterisk/branches/1.8
+	  ........ r329471 | pabelanger | 2011-07-25 15:49:40 -0400 (Mon,
+	  25 Jul 2011) | 2 lines Decrease verbose messages to debug, to
+	  help clean up CLI. ........ ................
+
+2011-07-25 14:07 +0000 [r329391-329432]  Gregory Nietsky <gregory at distrotech.co.za>
+
+	* include/asterisk/dsp.h, main/dsp.c: dsp_process was enhanced to
+	  work with alaw and ulaw in addition to slin. noticed that some
+	  functions could be refactored here it is. Reported by: irroot
+	  Tested by: irroot, mnicholson Review:
+	  https://reviewboard.asterisk.org/r/1304/
+
+	* channels/chan_sip.c, channels/sip/include/sip.h: Remove
+	  lastmsgssent from sip it has not been working since 1.6 Clean up
+	  the return values to be consistant not currently used Add doxygen
+	  returns MWI Event is sent on Register (closes issue
+	  ASTERISK-17866) Reported by: one47 Tested by: irroot, mvanbaak
+	  Review: https://reviewboard.asterisk.org/r/1172/
+
+2011-07-22 21:15 +0000 [r329332-329335]  Richard Mudgett <rmudgett at digium.com>
+
+	* main/pbx.c, /: Merged revisions 329334 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10 ........
+	  r329334 | rmudgett | 2011-07-22 16:14:22 -0500 (Fri, 22 Jul 2011)
+	  | 1 line Make use less redundant loop construct for iterating
+	  over hints. ........
+
+	* main/pbx.c, /: Merged revisions 329331 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500
+	  (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011)
+	  | 48 lines Deadlocks dealing with dialplan hints during reload.
+	  There are two remaining different deadlocks reported dealing with
+	  dialplan hints. The deadlock in ASTERISK-17666 is caused by
+	  invalid locking order in ast_remove_hint(). The hints container
+	  must be locked before the hint object. The deadlock in
+	  ASTERISK-17760 is caused by a catch-22 situation in
+	  handle_statechange(). The deadlock is caused by not having the
+	  conlock before calling the watcher callbacks. Unfortunately,
+	  having that lock causes a different deadlock as reported in
+	  ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made
+	  handle_statechange() no longer call the watcher callbacks holding
+	  any locks that matter. * Made hint ao2 destructor do the watcher
+	  callbacks for extension deactivation to guarantee that they get
+	  called. * Fixed hint reference leak in ast_add_hint() if the
+	  callback container constructor failed. * Fixed hint reference
+	  leak in complete_core_show_hint() for every hint it found for CLI
+	  tab completion. * Adjusted locking in
+	  ast_merge_contexts_and_delete() for safety. * Added
+	  context_merge_lock to prevent ast_merge_contexts_and_delete() and
+	  handle_statechange() from interfering with each other. * Fixed
+	  ast_change_hint() not taking into account that the extension is
+	  used for the hash key. (closes issue ASTERISK-17666) Reported by:
+	  irroot Tested by: irroot JIRA SWP-3318 (closes issue
+	  ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA
+	  SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/
+	  ........ ................
+
+2011-07-21 20:26 +0000 [r329258]  Russell Bryant <russell at russellbryant.com>
+
+	* channels/chan_dahdi.c, /, main/features.c,
+	  include/asterisk/netsock2.h, CHANGES, channels/sig_pri.c,
+	  include/asterisk/rtp_engine.h: Merged revisions 329257 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ........ r329257 | russell | 2011-07-21 15:22:36 -0500 (Thu, 21
+	  Jul 2011) | 2 lines s/1.10/10.0/ ........
+
+2011-07-21 18:06 +0000 [r329146-329205]  Richard Mudgett <rmudgett at digium.com>
+
+	* channels/chan_dahdi.c, configs/chan_dahdi.conf.sample, /: Merged
+	  revisions 329204 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329204 | rmudgett | 2011-07-21 13:05:18 -0500
+	  (Thu, 21 Jul 2011) | 13 lines Merged revisions 329203 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329203 | rmudgett | 2011-07-21 13:04:09 -0500 (Thu, 21 Jul 2011)
+	  | 6 lines Document parkinglot in chan_dahdi.conf.sample. *
+	  Document existing feature in chan_dahdi.conf.sample. * Remove
+	  some dead code related to the parkinglot option. ........
+	  ................
+
+	* /, apps/app_directed_pickup.c: Merged revisions 329200 via
+	  svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329200 | rmudgett | 2011-07-21 12:32:02 -0500
+	  (Thu, 21 Jul 2011) | 24 lines Merged revisions 329199 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329199 | rmudgett | 2011-07-21 12:30:57 -0500 (Thu, 21 Jul 2011)
+	  | 17 lines Update PickupChan documentation. The PickupChan uses
+	  the ampersand as the argument separator. Was documented as:
+	  PickupChan(channel[,channel2[,...][,options]]) Fixed
+	  documentation to:
+	  PickupChan(Technology/Resource[&Technology2/Resource2[&...]][,options])
+	  This is a continuation of ASTERISK-17494 for v1.8 and later.
+	  (closes issue ASTERISK-18144) Reported by: Erik Smith Patches:
+	  pickupchan_ducumentation-v2.patch (License #6263) patch uploaded
+	  by Erik Smith Tested by: Erik Smith ........ ................
+
+	* /, main/features.c: Merged revisions 329145 via svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/10
+	  ................ r329145 | rmudgett | 2011-07-21 11:52:17 -0500
+	  (Thu, 21 Jul 2011) | 16 lines Merged revisions 329144 via
+	  svnmerge from
+	  https://origsvn.digium.com/svn/asterisk/branches/1.8 ........
+	  r329144 | rmudgett | 2011-07-21 11:46:21 -0500 (Thu, 21 Jul 2011)
+	  | 9 lines Dialplan bridge() app mutex 'current_dest_chan' freed
+	  more times than we've locked! This appears to be a leftover from
+	  when ast_channel was converted to ao2 objects. Simply removed the
+	  extraneous unlock. (closes issue ASTERISK-17772) ........
+	  ................
+
+2011-07-21 16:22 +0000 [r329106-329130]  Jason Parker <jparker at digium.com>
+
+	* UPGRADE-1.10.txt (removed), UPGRADE-10.txt (added), UPGRADE.txt:
+	  Fix UPGRADE.txt files for Asterisk 10.
+
+	* /: Remove another 2.0 property.
+
+2011-07-21 16:05 +0000 [r329105]  Russell Bryant <russell at russellbryant.com>
+
+	* /: Fix merge properties to reflect Asterisk 10 branch
 
diff --git a/LICENSE b/LICENSE
index 635c202..16230ff 100644
--- a/LICENSE
+++ b/LICENSE
@@ -27,15 +27,15 @@ would strongly encourage you to make the same exception that we do).
 Specific permission is also granted to link Asterisk with OpenSSL, OpenH323
 UniMRCP, and/or the UW IMAP Toolkit and distribute the resulting binary files.
 
-In addition, Asterisk implements several management/control protocols.
-This includes the Asterisk Manager Interface (AMI), the Asterisk Gateway
-Interface (AGI), and the Asterisk REST Interface (ARI). It is our belief
-that applications using these protocols to manage or control an Asterisk
-instance do not have to be licensed under the GPL or a compatible license,
-as we believe these protocols do not create a 'derivative work' as referred
-to in the GPL. However, should any court or other judiciary body find that
-these protocols do fall under the terms of the GPL, then we hereby grant you a
-license to use these protocols in combination with Asterisk in external
+In addition, Asterisk implements two management/control protocols: the
+Asterisk Manager Interface (AMI) and the Asterisk Gateway Interface
+(AGI). It is our belief that applications using these protocols to
+manage or control an Asterisk instance do not have to be licensed
+under the GPL or a compatible license, as we believe these protocols
+do not create a 'derivative work' as referred to in the GPL. However,
+should any court or other judiciary body find that these protocols do
+fall under the terms of the GPL, then we hereby grant you a license to
+use these protocols in combination with Asterisk in external
 applications licensed under any license you wish.
 
 The 'Asterisk' name and logos are trademarks owned by Digium, Inc.,
diff --git a/Makefile b/Makefile
index 66a8411..a470dad 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 #
 # Top level Makefile
 #
@@ -81,8 +81,6 @@ export STATIC_BUILD       # Additional cflags, set to -static
                           # should go directly to ASTLDFLAGS
 
 #--- paths to various commands
-# The makeopts include below tries to set these if they're found during
-# configure.
 export CC
 export CXX
 export AR
@@ -104,7 +102,7 @@ export PYTHON
 
 # start the primary CFLAGS and LDFLAGS with any that were provided
 # to the configure script
-_ASTCFLAGS:=$(CONFIG_CFLAGS) $(CONFIG_SIGNED_CHAR)
+_ASTCFLAGS:=$(CONFIG_CFLAGS)
 _ASTLDFLAGS:=$(CONFIG_LDFLAGS)
 
 # Some build systems, such as the one in openwrt, like to pass custom target
@@ -151,17 +149,21 @@ LINKER_SYMBOL_PREFIX=
 # Uncomment this to use the older DSP routines
 #_ASTCFLAGS+=-DOLD_DSP_ROUTINES
 
-# Default install directory for DAHDI hooks.
-DAHDI_UDEV_HOOK_DIR = /usr/share/dahdi/span_config.d
-
-# If the file .asterisk.makeopts is present in your home directory, you can
-# include all of your favorite menuselect options so that every time you download
-# a new version of Asterisk, you don't have to run menuselect to set them.
-# The file /etc/asterisk.makeopts will also be included but can be overridden
-# by the file in your home directory.
+# This Makefile previously contained a note about the ability to use .asterisk.makeopts
+# from your home directory or /etc/asterisk.makeopts to set defaults for menuselect.
+# These files have never worked in this branch of Asterisk.  The work around is to
+# manually copy the file containing defaults before running 'make menuselect':
+#
+# cp ${HOME}/.asterisk.makeopts menuselect.makeopts
+#   or
+# cp /etc/asterisk.makeopts menuselect.makeopts
+#
+# As an alternative, menuselect/menuselect can be used by a script to enable or disable
+# individual options or entire categories.  To use this feature you must first
+# compile menuselect using 'make menuselect.makeopts'.  For information about parameters
+# supported run:
+# menuselect/menuselect --help
 
-GLOBAL_MAKEOPTS=$(wildcard /etc/asterisk.makeopts)
-USER_MAKEOPTS=$(wildcard ~/.asterisk.makeopts)
 
 MOD_SUBDIR_CFLAGS="-I$(ASTTOPDIR)/include"
 OTHER_SUBDIR_CFLAGS="-I$(ASTTOPDIR)/include"
@@ -184,7 +186,7 @@ ifeq ($(findstring -Wall,$(_ASTCFLAGS) $(ASTCFLAGS)),)
   _ASTCFLAGS+=-Wall
 endif
 
-_ASTCFLAGS+=-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_NESTED_FUNCTIONS) $(DEBUG)
+_ASTCFLAGS+=-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_NESTED_FUNCTIONS) $(AST_CLANG_BLOCKS) $(DEBUG)
 ADDL_TARGETS=
 
 ifeq ($(AST_DEVMODE),yes)
@@ -225,13 +227,10 @@ ifeq ($(OSARCH),SunOS)
   _ASTCFLAGS+=-Wcast-align -DSOLARIS -I../include/solaris-compat -I/opt/ssl/include -I/usr/local/ssl/include -D_XPG4_2 -D__EXTENSIONS__
 endif
 
-ifneq ($(GREP),)
-  ASTERISKVERSION:=$(shell GREP=$(GREP) AWK=$(AWK) GIT=$(GIT) build_tools/make_version .)
-endif
-ifneq ($(AWK),)
-  ifneq ($(wildcard .version),)
-    ASTERISKVERSIONNUM:=$(shell $(AWK) -F. '{printf "%01d%02d%02d", $$1, $$2, $$3}' .version)
-  endif
+ASTERISKVERSION:=$(shell GREP=$(GREP) AWK=$(AWK) GIT=$(GIT) build_tools/make_version .)
+
+ifneq ($(wildcard .version),)
+  ASTERISKVERSIONNUM:=$(shell $(AWK) -F. '{printf "%01d%02d%02d", $$1, $$2, $$3}' .version)
 endif
 
 ifneq ($(wildcard .svn),)
@@ -253,9 +252,11 @@ MOD_SUBDIRS_EMBED_LIBS:=$(MOD_SUBDIRS:%=%-embed-libs)
 MOD_SUBDIRS_MENUSELECT_TREE:=$(MOD_SUBDIRS:%=%-menuselect-tree)
 
 ifneq ($(findstring darwin,$(OSARCH)),)
-  _ASTCFLAGS+=-D__Darwin__ -mmacosx-version-min=10.6
-  _SOLINK=-mmacosx-version-min=10.6 -Xlinker -undefined -Xlinker dynamic_lookup
-  _SOLINK+=/usr/lib/bundle1.o
+  _ASTCFLAGS+=-D__Darwin__
+  _SOLINK=-Xlinker -macosx_version_min -Xlinker 10.4 -Xlinker -undefined -Xlinker dynamic_lookup
+  ifeq ($(shell if test `/usr/bin/sw_vers -productVersion | cut -c4` -gt 5; then echo 6; else echo 0; fi),6)
+    _SOLINK+=/usr/lib/bundle1.o
+  endif
   SOLINK=-bundle $(_SOLINK)
   DYLINK=-Xlinker -dylib $(_SOLINK)
   _ASTLDFLAGS+=-L/usr/local/lib
@@ -295,6 +296,13 @@ else
 SUBMAKE:=$(MAKE) --quiet --no-print-directory
 endif
 
+# This is used when generating the doxygen documentation
+ifneq ($(DOT),:)
+  HAVEDOT=yes
+else
+  HAVEDOT=no
+endif
+
 # $(MAKE) is printed in several places, and we want it to be a
 # fixed size string. Define a variable whose name has also the
 # same size, so we can easily align text.
@@ -332,10 +340,10 @@ makeopts: configure
 	@echo "****"
 	@exit 1
 
-menuselect.makeopts: menuselect/menuselect menuselect-tree makeopts build_tools/menuselect-deps $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS)
+menuselect.makeopts: menuselect/menuselect menuselect-tree makeopts build_tools/menuselect-deps
 ifeq ($(filter %menuselect,$(MAKECMDGOALS)),)
 	menuselect/menuselect --check-deps $@
-	menuselect/menuselect --check-deps $@ $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS)
+	menuselect/menuselect --check-deps $@
 endif
 
 $(MOD_SUBDIRS_EMBED_LDSCRIPT):
@@ -422,8 +430,8 @@ _clean:
 	rm -f main/version.c
 	rm -f doc/core-en_US.xml
 	rm -f doc/full-en_US.xml
-	rm -f doc/rest-api/*.wiki
-	rm -f rest-api-templates/*.pyc
+	rm -f doxygen.log
+	rm -rf latex
 	@$(MAKE) -C menuselect clean
 	cp -f .cleancount .lastclean
 
@@ -439,22 +447,19 @@ distclean: $(SUBDIRS_DIST_CLEAN) _clean
 	rm -f include/asterisk/autoconfig.h
 	rm -f include/asterisk/buildopts.h
 	rm -rf doc/api
+	rm -f doc/asterisk-ng-doxygen
 	rm -f build_tools/menuselect-deps
 
 datafiles: _all doc/core-en_US.xml
 	CFLAGS="$(_ASTCFLAGS) $(ASTCFLAGS)" build_tools/mkpkgconfig "$(DESTDIR)$(libdir)/pkgconfig";
+# Should static HTTP be installed during make samples or even with its own target ala
+# webvoicemail?  There are portions here that *could* be customized but might also be
+# improved a lot.  I'll put it here for now.
 
-#	# Recursively install contents of the static-http directory, in case
-#	# extra content is provided there. See contrib/scripts/get_swagger_ui.sh
-	find static-http | while read x; do \
-		if test -d $$x; then \
-			$(INSTALL) -m 755 -d "$(DESTDIR)$(ASTDATADIR)/$$x"; \
-		else \
-			$(INSTALL) -m 644 $$x "$(DESTDIR)$(ASTDATADIR)/$$x" ; \
-		fi \
+	for x in static-http/*; do \
+		$(INSTALL) -m 644 $$x "$(DESTDIR)$(ASTDATADIR)/static-http" ; \
 	done
 	$(INSTALL) -m 644 doc/core-en_US.xml "$(DESTDIR)$(ASTDATADIR)/static-http";
-	$(INSTALL) -m 644 doc/appdocsxml.xslt "$(DESTDIR)$(ASTDATADIR)/static-http";
 	if [ -d doc/tex/asterisk ] ; then \
 		$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/static-http/docs" ; \
 		for n in doc/tex/asterisk/* ; do \
@@ -465,34 +470,22 @@ datafiles: _all doc/core-en_US.xml
 		$(INSTALL) -m 644 $$x "$(DESTDIR)$(ASTDATADIR)/images" ; \
 	done
 	$(MAKE) -C sounds install
-	find rest-api -name "*.json" | while read x; do \
-		$(INSTALL) -m 644 $$x "$(DESTDIR)$(ASTDATADIR)/rest-api" ; \
-	done
-
-ifneq ($(GREP),)
-  XML_core_en_US = $(foreach dir,$(MOD_SUBDIRS),$(shell $(GREP) -l "language=\"en_US\"" $(dir)/*.c $(dir)/*.cc 2>/dev/null))
-endif
 
-doc/core-en_US.xml: makeopts .lastclean $(XML_core_en_US)
+doc/core-en_US.xml: makeopts .lastclean $(foreach dir,$(MOD_SUBDIRS),$(shell $(GREP) -l "language=\"en_US\"" $(dir)/*.c $(dir)/*.cc 2>/dev/null))
 	@printf "Building Documentation For: "
 	@echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
 	@echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
-	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@
 	@echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@
 	@for x in $(MOD_SUBDIRS); do \
 		printf "$$x " ; \
-		for i in `find $$x -name '*.c'`; do \
+		for i in $$x/*.c; do \
 			$(AWK) -f build_tools/get_documentation $$i >> $@ ; \
 		done ; \
 	done
 	@echo
 	@echo "</docs>" >> $@
 
-ifneq ($(GREP),)
-  XML_full_en_US = $(foreach dir,$(MOD_SUBDIRS),$(shell $(GREP) -l "language=\"en_US\"" $(dir)/*.c $(dir)/*.cc 2>/dev/null))
-endif
-
-doc/full-en_US.xml: makeopts .lastclean $(XML_full_en_US)
+doc/full-en_US.xml: makeopts .lastclean $(foreach dir,$(MOD_SUBDIRS),$(shell $(GREP) -l "language=\"en_US\"" $(dir)/*.c $(dir)/*.cc 2>/dev/null))
 ifeq ($(PYTHON),:)
 	@echo "--------------------------------------------------------------------------"
 	@echo "---        Please install python to build full documentation           ---"
@@ -501,11 +494,10 @@ else
 	@printf "Building Documentation For: "
 	@echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
 	@echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
-	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@
 	@echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@
 	@for x in $(MOD_SUBDIRS); do \
 		printf "$$x " ; \
-		for i in `find $$x -name '*.c'`; do \
+		for i in $$x/*.c; do \
 			$(PYTHON) build_tools/get_documentation.py < $$i >> $@ ; \
 		done ; \
 	done
@@ -549,14 +541,13 @@ OLDHEADERS=$(filter-out $(NEWHEADERS) $(notdir $(DESTDIR)$(ASTHEADERDIR)),$(notd
 INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTETCDIR)" "$(ASTVARRUNDIR)" \
 	"$(ASTSPOOLDIR)" "$(ASTSPOOLDIR)/dictate" "$(ASTSPOOLDIR)/meetme" \
 	"$(ASTSPOOLDIR)/monitor" "$(ASTSPOOLDIR)/system" "$(ASTSPOOLDIR)/tmp" \
-	"$(ASTSPOOLDIR)/voicemail" "$(ASTSPOOLDIR)/recording" \
-	"$(ASTHEADERDIR)" "$(ASTHEADERDIR)/doxygen" \
+	"$(ASTSPOOLDIR)/voicemail" "$(ASTHEADERDIR)" "$(ASTHEADERDIR)/doxygen" \
 	"$(ASTLOGDIR)" "$(ASTLOGDIR)/cdr-csv" "$(ASTLOGDIR)/cdr-custom" \
 	"$(ASTLOGDIR)/cel-custom" "$(ASTDATADIR)" "$(ASTDATADIR)/documentation" \
 	"$(ASTDATADIR)/documentation/thirdparty" "$(ASTDATADIR)/firmware" \
 	"$(ASTDATADIR)/firmware/iax" "$(ASTDATADIR)/images" "$(ASTDATADIR)/keys" \
-	"$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/rest-api" "$(ASTDATADIR)/static-http" \
-	"$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)"
+	"$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/static-http" "$(ASTDATADIR)/sounds" \
+	"$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)"
 
 installdirs:
 	@for i in $(INSTALLDIRS); do \
@@ -571,8 +562,10 @@ main-bininstall:
 bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
 	$(INSTALL) -m 755 contrib/scripts/astgenkey "$(DESTDIR)$(ASTSBINDIR)/"
 	$(INSTALL) -m 755 contrib/scripts/autosupport "$(DESTDIR)$(ASTSBINDIR)/"
-	if [ ! -f /sbin/launchd ]; then \
-		./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk"; \
+	if [ ! -f "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk" -a ! -f /sbin/launchd ]; then \
+		cat contrib/scripts/safe_asterisk | sed 's|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;s|__ASTERISK_LOG_DIR__|$(ASTLOGDIR)|;' > contrib/scripts/safe.tmp ; \
+		$(INSTALL) -m 755 contrib/scripts/safe.tmp "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk" ; \
+		rm -f contrib/scripts/safe.tmp ; \
 	fi
 	$(INSTALL) -m 644 include/asterisk.h "$(DESTDIR)$(includedir)"
 	$(INSTALL) -m 644 include/asterisk/*.h "$(DESTDIR)$(ASTHEADERDIR)"
@@ -582,7 +575,6 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
 	fi
 
 	$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"
-	$(INSTALL) -m 644 doc/appdocsxml.xslt "$(DESTDIR)$(ASTDATADIR)/documentation"
 	$(INSTALL) -m 644 doc/appdocsxml.dtd "$(DESTDIR)$(ASTDATADIR)/documentation"
 	$(INSTALL) -m 644 doc/asterisk.8 "$(DESTDIR)$(ASTMANDIR)/man8"
 	$(INSTALL) -m 644 doc/astdb*.8 "$(DESTDIR)$(ASTMANDIR)/man8"
@@ -592,10 +584,6 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
 	if [ -f contrib/firmware/iax/iaxy.bin ] ; then \
 		$(INSTALL) -m 644 contrib/firmware/iax/iaxy.bin "$(DESTDIR)$(ASTDATADIR)/firmware/iax/iaxy.bin"; \
 	fi
-ifeq ($(HAVE_DAHDI),1)
-	$(INSTALL) -d $(DESTDIR)/$(DAHDI_UDEV_HOOK_DIR)
-	$(INSTALL) -m 644 contrib/scripts/dahdi_span_config_hook $(DESTDIR)$(DAHDI_UDEV_HOOK_DIR)/40-asterisk
-endif
 
 $(SUBDIRS_INSTALL):
 	+ at DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(SUBMAKE) -C $(@:-install=) install
@@ -663,7 +651,7 @@ upgrade: bininstall
 adsi:
 	@echo Installing adsi config files...
 	$(INSTALL) -d "$(DESTDIR)$(ASTETCDIR)"
-	@for x in configs/samples/*.adsi; do \
+	@for x in configs/*.adsi; do \
 		dst="$(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x`" ; \
 		if [ -f "$${dst}" ] ; then \
 			echo "Overwriting $$x" ; \
@@ -675,7 +663,7 @@ adsi:
 
 samples: adsi
 	@echo Installing other config files...
-	@for x in configs/samples/*.sample; do \
+	@for x in configs/*.sample; do \
 		dst="$(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample`" ;	\
 		if [ -f "$${dst}" ]; then \
 			if [ "$(OVERWRITE)" = "y" ]; then \
@@ -757,7 +745,8 @@ webvmail:
 	@echo " +-------------------------------------------+"
 
 progdocs:
-	# Note, Makefile conditionals must not be tabbed out. Wasted hours with that.
+# Note, Makefile conditionals must not be tabbed out. Wasted hours with that.
+	@cp doc/asterisk-ng-doxygen.in doc/asterisk-ng-doxygen
 ifeq ($(DOXYGEN),:)
 	@echo "Doxygen is not installed.  Please install and re-run the configuration script."
 else
@@ -765,20 +754,20 @@ ifeq ($(DOT),:)
 	@echo "DOT is not installed. Doxygen will not produce any diagrams. Please install and re-run the configuration script."
 else
 	# Enable DOT
-	@echo "HAVE_DOT = YES" >> contrib/asterisk-ng-doxygen
+	@echo "HAVE_DOT = YES" >> doc/asterisk-ng-doxygen
 endif
 	# Set Doxygen PROJECT_NUMBER variable
 ifneq ($(ASTERISKVERSION),UNKNOWN__and_probably_unsupported)
-	@echo "PROJECT_NUMBER = $(ASTERISKVERSION)" >> contrib/asterisk-ng-doxygen
+	@echo "PROJECT_NUMBER = $(ASTERISKVERSION)" >> doc/asterisk-ng-doxygen
 else
 	echo "Asterisk Version is unknown, not configuring Doxygen PROJECT_NUMBER."
 endif
-	# Validate Doxygen Configuration
-	@doxygen -u contrib/asterisk-ng-doxygen
+	# Validate and auto-update local copy
+	@doxygen -u doc/asterisk-ng-doxygen
 	# Run Doxygen
-	@doxygen contrib/asterisk-ng-doxygen
+	@doxygen doc/asterisk-ng-doxygen
 	# Remove configuration backup file
-	@rm -f contrib/asterisk-ng-doxygen.bak
+	@rm -f doc/asterisk-ng-doxygen.bak
 endif
 
 install-logrotate:
@@ -792,7 +781,9 @@ install-logrotate:
 config:
 	@if [ "${OSARCH}" = "linux-gnu" -o "${OSARCH}" = "kfreebsd-gnu" ]; then \
 		if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \
-			./build_tools/install_subst contrib/init.d/rc.redhat.asterisk  "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \
+			cat contrib/init.d/rc.redhat.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/rc.d/init.d/asterisk" ; \
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 			if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \
 				$(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \
 			fi ; \
@@ -800,7 +791,9 @@ config:
 				/sbin/chkconfig --add asterisk ; \
 			fi ; \
 		elif [ -f /etc/debian_version ] ; then \
-			./build_tools/install_subst contrib/init.d/rc.debian.asterisk  "$(DESTDIR)/etc/init.d/asterisk"; \
+			cat contrib/init.d/rc.debian.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/init.d/asterisk" ; \
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 			if [ ! -f "$(DESTDIR)/etc/default/asterisk" ] ; then \
 				$(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/default/asterisk" ; \
 			fi ; \
@@ -808,12 +801,16 @@ config:
 				/usr/sbin/update-rc.d asterisk defaults 50 91 ; \
 			fi ; \
 		elif [ -f /etc/gentoo-release ] ; then \
-			./build_tools/install_subst contrib/init.d/rc.gentoo.asterisk  "$(DESTDIR)/etc/init.d/asterisk"; \
+			cat contrib/init.d/rc.gentoo.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/init.d/asterisk" ; \
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 			if [ -z "$(DESTDIR)" ] ; then \
 				/sbin/rc-update add asterisk default ; \
 			fi ; \
 		elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ] ; then \
-			./build_tools/install_subst contrib/init.d/rc.mandriva.asterisk  "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \
+			cat contrib/init.d/rc.mandriva.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/rc.d/init.d/asterisk" ; \
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 			if [ ! -f /etc/sysconfig/asterisk ] ; then \
 				$(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \
 			fi ; \
@@ -821,7 +818,9 @@ config:
 				/sbin/chkconfig --add asterisk ; \
 			fi ; \
 		elif [ -f /etc/SuSE-release -o -f /etc/novell-release ] ; then \
-			./build_tools/install_subst contrib/init.d/rc.suse.asterisk  "$(DESTDIR)/etc/init.d/asterisk"; \
+			cat contrib/init.d/rc.suse.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/init.d/asterisk" ;\
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 			if [ ! -f /etc/sysconfig/asterisk ] ; then \
 				$(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \
 			fi ; \
@@ -829,13 +828,19 @@ config:
 				/sbin/chkconfig --add asterisk ; \
 			fi ; \
 		elif [ -f /etc/arch-release -o -f /etc/arch-release ] ; then \
-			./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk  "$(DESTDIR)/etc/init.d/asterisk"; \
+			cat contrib/init.d/rc.archlinux.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR)|;s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > contrib/init.d/rc.asterisk.tmp ; \
+			$(INSTALL) -m 755 contrib/init.d/rc.asterisk.tmp "$(DESTDIR)/etc/rc.d/asterisk" ; \
+			rm -f contrib/init.d/rc.asterisk.tmp ; \
 		elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \
 			if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \
-				./build_tools/install_subst contrib/init.d/org.asterisk.asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \
+				sed 's|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;' < contrib/init.d/org.asterisk.asterisk.plist > asterisk.plist ; \
+				$(INSTALL) -m 644 asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \
+				rm -f asterisk.plist; \
 			fi; \
 			if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist" ]; then \
-				./build_tools/install_subst contrib/init.d/org.asterisk.muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \
+				sed 's|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;' < contrib/init.d/org.asterisk.muted.plist > muted.plist ; \
+				$(INSTALL) -m 644 muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \
+				rm -f muted.plist; \
 			fi; \
 		elif [ -f /etc/slackware-version ]; then \
 			echo "Slackware is not currently supported, although an init script does exist for it."; \
@@ -873,9 +878,6 @@ _uninstall: $(SUBDIRS_UNINSTALL) main-binuninstall
 	rm -f "$(DESTDIR)$(ASTMANDIR)/man8/astgenkey.8"
 	rm -f "$(DESTDIR)$(ASTMANDIR)/man8/autosupport.8"
 	rm -f "$(DESTDIR)$(ASTMANDIR)/man8/safe_asterisk.8"
-ifeq ($(HAVE_DAHDI),1)
-	rm -f $(DESTDIR)$(DAHDI_UDEV_HOOK_DIR)/40-asterisk
-endif
 	$(MAKE) -C sounds uninstall
 
 uninstall: _uninstall
@@ -931,7 +933,7 @@ nmenuselect: menuselect/nmenuselect menuselect-tree menuselect.makeopts
 	- at menuselect/nmenuselect menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 # options for make in menuselect/
-MAKE_MENUSELECT=CC="$(BUILD_CC)" CXX="" LD="" AR="" RANLIB="" \
+MAKE_MENUSELECT=CC="$(BUILD_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" \
 		CFLAGS="$(BUILD_CFLAGS)" LDFLAGS="$(BUILD_LDFLAGS)" \
 		$(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
 
@@ -967,19 +969,6 @@ menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(di
 	@cat sounds/sounds.xml >> $@
 	@echo "</menu>" >> $@
 
-# We don't want to require Python or Pystache for every build, so this is its
-# own target.
-ari-stubs:
-ifeq ($(PYTHON),:)
-	@echo "--------------------------------------------------------------------------"
-	@echo "---        Please install python to build ARI stubs            ---"
-	@echo "--------------------------------------------------------------------------"
-	@false
-else
-	$(PYTHON) rest-api-templates/make_ari_stubs.py \
-		rest-api/resources.json .
-endif
-
 .PHONY: menuselect
 .PHONY: main
 .PHONY: sounds
@@ -999,7 +988,6 @@ endif
 .PHONY: installdirs
 .PHONY: validate-docs
 .PHONY: _clean
-.PHONY: ari-stubs
 .PHONY: $(SUBDIRS_INSTALL)
 .PHONY: $(SUBDIRS_DIST_CLEAN)
 .PHONY: $(SUBDIRS_CLEAN)
diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules
index 939e79f..fe4d7c1 100644
--- a/Makefile.moddir_rules
+++ b/Makefile.moddir_rules
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 #
 # Makefile rules for subdirectories containing modules
 #
@@ -118,6 +118,7 @@ clean::
 	rm -f *.so *.o *.oo *.eo *.i *.ii
 	rm -f .*.d
 	rm -f *.s *.i
+	rm -f *.gcda *.gcno
 	rm -f modules.link
 
 install:: all
diff --git a/Makefile.rules b/Makefile.rules
index 41205bc..54df636 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile rules
 #
@@ -65,6 +65,11 @@ endif
 CC_CFLAGS=$(PTHREAD_CFLAGS) $(_ASTCFLAGS) $(ASTCFLAGS)
 CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(_ASTCFLAGS) $(ASTCFLAGS))
 
+# Clang -Werror warning suppressions
+ifeq ($(C_COMPILER_FAMILY),clang)
+	CC_CFLAGS+=-Wno-unused-value -Wno-parentheses-equality
+endif
+
 ifeq ($(GNU_LD),1)
 SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(subst .so,.exports,$@),--warn-common
 ifneq ($(wildcard $(subst .so,.dynamics,$@)),)
@@ -101,10 +106,17 @@ endif
 
 %.o: %.i
 	$(ECHO_PREFIX) echo "   [CCi] $< -> $@"
+ifneq ($(AST_CLANG_BLOCKS),)
+ifeq ($(COMPILE_DOUBLE),yes)
+	$(CMD_PREFIX) $(CC) -o /dev/null -c $< $(CC_CFLAGS) $(OPTIMIZE) -Wno-unused-command-line-argument
+endif
+	$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS) $(_ASTCFLAGS_COVERAGE) -Wno-unused-command-line-argument
+else
 ifeq ($(COMPILE_DOUBLE),yes)
 	$(CMD_PREFIX) $(CC) -o /dev/null -c $< $(CC_CFLAGS) $(OPTIMIZE)
 endif
 	$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS) $(_ASTCFLAGS_COVERAGE)
+endif
 
 ifneq ($(COMPILE_DOUBLE),yes)
 %.o: %.c
diff --git a/README b/README
index ebd0712..f03d2d0 100644
--- a/README
+++ b/README
@@ -33,14 +33,10 @@ information on the project itself, please visit the Asterisk home page at:
 
            http://www.asterisk.org
 
-  The official Asterisk wiki can be found at:
-
-           https://wiki.asterisk.org
-
   In addition you'll find lots of information compiled by the Asterisk
 community on this Wiki:
 
-           http://www.voip-info.org/wiki-Asterisk
+           https://wiki.asterisk.org
 
   There is a book on Asterisk published by O'Reilly under the Creative Commons
 License. It is available in book stores as well as in a downloadable version on
diff --git a/README-SERIOUSLY.bestpractices.txt b/README-SERIOUSLY.bestpractices.txt
index 108adce..281d0d3 100644
--- a/README-SERIOUSLY.bestpractices.txt
+++ b/README-SERIOUSLY.bestpractices.txt
@@ -366,4 +366,5 @@ could result in a privilege escalation. Asterisk can inhibit the execution of
 these functions, if live_dangerously in the [options] section of asterisk.conf
 is set to no.
 
-In Asterisk 12 and later, live_dangerously defaults to no.
+For backwards compatibility, live_dangerously defaults to yes, and must be
+explicitly set to no to enable this privilege escalation protection.
diff --git a/UPGRADE-11.txt b/UPGRADE-11.txt
deleted file mode 100644
index 311edc8..0000000
--- a/UPGRADE-11.txt
+++ /dev/null
@@ -1,280 +0,0 @@
-===========================================================
-===
-=== Information for upgrading between Asterisk versions
-===
-=== These files document all the changes that MUST be taken
-=== into account when upgrading between the Asterisk
-=== versions listed below. These changes may require that
-=== you modify your configuration files, dialplan or (in
-=== some cases) source code if you have your own Asterisk
-=== modules or patches. These files also include advance
-=== notice of any functionality that has been marked as
-=== 'deprecated' and may be removed in a future release,
-=== along with the suggested replacement functionality.
-===
-=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
-=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
-=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
-=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
-=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
-===
-===========================================================
-
-From 11.6 to 11.7:
-ConfBridge
- - ConfBridge now has the ability to set the language of announcements to the
-   conference.  The language can be set on a bridge profile in confbridge.conf
-   or by the dialplan function CONFBRIDGE(bridge,language)=en.
-chan_sip - Clarify The "sip show peers" Forcerport Column And Add Comedia
- - Under the "Forcerport" column, the "N" used to mean NAT (i.e. Yes).  With
-   the additon of auto_* NAT settings, the meaning changed and there was a
-   certain combination of letters added to indicate the current setting. The
-   combination of using "Y", "N", "A" or "a", can be confusing.  Therefore, we
-   now display clearly what the current Forcerport setting is: "Yes", "No",
-   "Auto (Yes)", "Auto (No)".
- - Since we are clarifying the Forcerport column, we have added a column to
-   display the Comedia setting since this is useful information as well.  We
-   no longer have a simple "NAT" setting like other versions before 11.
-
-From 11.5 to 11.6:
-* res_agi will now properly indicate if there was an error in streaming an
-  audio file.  The result code will be -1 and the result returned from the
-  the function will be RESULT_FAILURE instead of the prior behavior of always
-  returning RESULT_SUCCESS even if there was an error.
-
-From 11.4 to 11.5:
-* The default settings for chan_sip are now overriden properly by the general
-  settings in sip.conf.  Please look over your settings upon upgrading.
-
-From 11.3 to 11.4:
-* Added the 'n' option to MeetMe to prevent application of the DENOISE function
-  to a channel joining a conference. Some channel drivers that vary the number
-  of audio samples in a voice frame will experience significant quality problems
-  if a denoiser is attached to the channel; this option gives them the ability
-  to remove the denoiser without having to unload func_speex.
-
-* The Registry AMI event for SIP registrations will now always include the
-  Username field. A previous bug fix missed an instance where it was not
-  included; that has been corrected in this release.
-
-From 11.2.0 to 11.2.1:
-* Asterisk would previously not output certain error messages when a remote
-  console attempted to connect to Asterisk and no instance of Asterisk was
-  running. This error message is displayed on stderr; as a result, some
-  initialization scripts that used remote consoles to test for the presence
-  of a running Asterisk instance started to display erroneous error messages.
-  The init.d scripts and the safe_asterisk have been updated in the contrib
-  folder to account for this.
-
-From 11.2 to 11.3:
-
-* Now by default, when Asterisk is installed in a path other than /usr, the
-  Asterisk binary will search for shared libraries in ${libdir} in addition to
-  searching system libraries. This allows Asterisk to find its shared
-  libraries without having to specify LD_LIBRARY_PATH. This can be disabled by
-  passing --disable-rpath to configure.
-
-From 10 to 11:
-
-Voicemail:
- - All voicemails now have a "msg_id" which uniquely identifies a message. For
-   users of filesystem and IMAP storage of voicemail, this should be transparent.
-   For users of ODBC, you will need to add a "msg_id" column to your voice mail
-   messages table. This should be a string capable of holding at least 32 characters.
-   All messages created in old Asterisk installations will have a msg_id added to
-   them when required. This operation should be transparent as well.
-
-Parking:
- - The comebacktoorigin setting must now be set per parking lot. The setting in
-   the general section will not be applied automatically to each parking lot.
- - The BLINDTRANSFER channel variable is deleted from a channel when it is
-   bridged to prevent subtle bugs in the parking feature.  The channel
-   variable is used by Asterisk internally for the Park application to work
-   properly.  If you were using it for your own purposes, copy it to your
-   own channel variable before the channel is bridged.
-
-res_ais:
- - Users of res_ais in versions of Asterisk prior to Asterisk 11 must change
-   to use the res_corosync module, instead.  OpenAIS is deprecated, but
-   Corosync is still actively developed and maintained.  Corosync came out of
-   the OpenAIS project.
-
-Dialplan Functions:
- - MAILBOX_EXISTS has been deprecated. Use VM_INFO with the 'exists' parameter
-   instead.
- - Macro has been deprecated in favor of GoSub.  For redirecting and connected
-   line purposes use the following variables instead of their macro equivalents:
-   REDIRECTING_SEND_SUB, REDIRECTING_SEND_SUB_ARGS,
-   CONNECTED_LINE_SEND_SUB, CONNECTED_LINE_SEND_SUB_ARGS.
- - The REDIRECTING function now supports the redirecting original party id
-   and reason.
- - The HANGUPCAUSE and HANGUPCAUSE_KEYS functions have been introduced to
-   provide a replacement for the SIP_CAUSE hash. The HangupCauseClear
-   application has also been introduced to remove this data from the channel
-   when necessary.
-
-
-func_enum:
- - ENUM query functions now return a count of -1 on lookup error to
-   differentiate between a failed query and a successful query with 0 results
-   matching the specified type.
-
-CDR:
- - cdr_adaptive_odbc now supports specifying a schema so that Asterisk can
-   connect to databases that use schemas.
-
-Configuration Files:
- - Files listed below have been updated to be more consistent with how Asterisk
-   parses configuration files.  This makes configuration files more consistent
-   with what is expected across modules.
-
-   - cdr.conf: [general] and [csv] sections
-   - dnsmgr.conf
-   - dsp.conf
-
- - The 'verbose' setting in logger.conf now takes an optional argument,
-   specifying the verbosity level for each logging destination.  The default,
-   if not otherwise specified, is a verbosity of 3.
-
-AMI:
-  - DBDelTree now correctly returns an error when 0 rows are deleted just as
-    the DBDel action does.
-  - The IAX2 PeerStatus event now sends a 'Port' header.  In Asterisk 10, this was
-    erroneously being sent as a 'Post' header.
-
-CCSS:
- - Macro is deprecated. Use cc_callback_sub instead of cc_callback_macro
-   in channel configurations.
-
-app_meetme:
-  - The 'c' option (announce user count) will now work even if the 'q' (quiet)
-    option is enabled.
-
-app_followme:
- - Answered outgoing calls no longer get cut off when the next step is started.
-   You now have until the last step times out to decide if you want to accept
-   the call or not before being disconnected.
-
-chan_gtalk:
- - chan_gtalk has been deprecated in favor of the chan_motif channel driver. It is recommended
-   that users switch to using it as it is a core supported module.
-
-chan_jingle:
- - chan_jingle has been deprecated in favor of the chan_motif channel driver. It is recommended
-   that users switch to using it as it is a core supported module.
-
-SIP
-===
- - A new option "tonezone" for setting default tonezone for the channel driver
-   or individual devices
- - A new manager event, "SessionTimeout" has been added and is triggered when
-   a call is terminated due to RTP stream inactivity or SIP session timer
-   expiration.
- - SIP_CAUSE is now deprecated.  It has been modified to use the same
-   mechanism as the HANGUPCAUSE function.  Behavior should not change, but
-   performance should be vastly improved.  The HANGUPCAUSE function should now
-   be used instead of SIP_CAUSE. Because of this, the storesipcause option in
-   sip.conf is also deprecated.
- - The sip paramater for Originating Line Information (oli, isup-oli, and
-   ss7-oli) is now parsed out of the From header and copied into the channel's
-   ANI2 information field.  This is readable from the CALLERID(ani2) dialplan
-   function.
- - ICE support has been added and is enabled by default. Some endpoints may have
-   problems with the ICE candidates within the SDP. If this is the case ICE support
-   can be disabled globally or on a per-endpoint basis using the icesupport
-   configuration option. Symptoms of this include one way media or no media flow.
-
-chan_unistim
- - Due to massive update in chan_unistim phone keys functions and on-screen 
-   information changed.
-
-users.conf:
- - A defined user with hasvoicemail=yes now finally uses a Gosub to stdexten
-   as documented in extensions.conf.sample since v1.6.0 instead of a Macro as
-   documented in v1.4.  Set the asterisk.conf stdexten=macro parameter to
-   invoke the stdexten the old way.
-
-res_jabber
- - This module has been deprecated in favor of the res_xmpp module. The res_xmpp
-   module is backwards compatible with the res_jabber configuration file, dialplan
-   functions, and AMI actions. The old CLI commands can also be made available using
-   the res_clialiases template for Asterisk 11.
-
-From 1.8 to 10:
-
-cel_pgsql:
- - This module now expects an 'extra' column in the database for data added
-   using the CELGenUserEvent() application.
-
-ConfBridge
- - ConfBridge's dialplan arguments have changed and are not
-   backwards compatible.
-
-File Interpreters
- - The format interpreter formats/format_sln16.c for the file extension
-   '.sln16' has been removed. The '.sln16' file interpreter now exists
-   in the formats/format_sln.c module along with new support for sln12,
-   sln24, sln32, sln44, sln48, sln96, and sln192 file extensions.
-
-HTTP:
- - A bindaddr must be specified in order for the HTTP server
-   to run. Previous versions would default to 0.0.0.0 if no
-   bindaddr was specified.
-
-Gtalk:
- - The default value for 'context' and 'parkinglots' in gtalk.conf has
-   been changed to 'default', previously they were empty.
-
-chan_dahdi:
- - The mohinterpret=passthrough setting is deprecated in favor of
-   moh_signaling=notify.
-
-pbx_lua:
- - Execution no longer continues after applications that do dialplan jumps
-   (such as app.goto).  Now when an application such as app.goto() is called,
-   control is returned back to the pbx engine and the current extension
-   function stops executing.
- - the autoservice now defaults to being on by default
- - autoservice_start() and autoservice_start() no longer return a value.
-
-Queue:
- - Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
- - QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
-
-Asterisk Database:
- - The internal Asterisk database has been switched from Berkeley DB 1.86 to
-   SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
-   utility in the UTILS section of menuselect. If an existing astdb is found and no
-   astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
-   convert an existing astdb to the SQLite3 version automatically at runtime. If
-   moving back from Asterisk 10 to Asterisk 1.8, the astdb2bdb utility can be used
-   to create a Berkeley DB copy of the SQLite3 astdb that Asterisk 10 uses.
-
-Manager:
- - The AMI protocol version was incremented to 1.2 as a result of changing two
-   instances of the Unlink event to Bridge events. This change was documented
-   as part of the AMI 1.1 update, but two Unlink events were inadvertently left
-   unchanged.
-
-Module Support Level
- - All modules in the addons, apps, bridge, cdr, cel, channels, codecs, 
-   formats, funcs, pbx, and res have been updated to include MODULEINFO data
-   that includes <support_level> tags with a value of core, extended, or deprecated.
-   More information is available on the Asterisk wiki at 
-   https://wiki.asterisk.org/wiki/display/AST/Asterisk+Module+Support+States
-
-   Deprecated modules are now marked to not build by default and must be explicitly
-   enabled in menuselect.
-
-chan_sip:
- - Setting of HASH(SIP_CAUSE,<slave-channel-name>) on channels is now disabled
-   by default. It can be enabled using the 'storesipcause' option. This feature
-   has a significant performance penalty.
-
-UDPTL:
- - The default UDPTL port range in udptl.conf.sample differed from the defaults
-   in the source. If you didn't have a config file, you got 4500 to 4599. Now the
-   default is 4000 to 4999.
-
-===========================================================
-===========================================================
diff --git a/UPGRADE-12.txt b/UPGRADE-12.txt
deleted file mode 100644
index 3d6c00d..0000000
--- a/UPGRADE-12.txt
+++ /dev/null
@@ -1,478 +0,0 @@
-===========================================================
-===
-=== Information for upgrading between Asterisk versions
-===
-=== These files document all the changes that MUST be taken
-=== into account when upgrading between the Asterisk
-=== versions listed below. These changes may require that
-=== you modify your configuration files, dialplan or (in
-=== some cases) source code if you have your own Asterisk
-=== modules or patches. These files also include advance
-=== notice of any functionality that has been marked as
-=== 'deprecated' and may be removed in a future release,
-=== along with the suggested replacement functionality.
-===
-=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
-=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
-=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
-=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
-=== UPGRADE-10.txt  -- Upgrade info for 1.8 to 10
-=== UPGRADE-11.txt  -- Upgrade info for 10 to 11
-===
-===========================================================
-
-There are many significant architectural changes in Asterisk 12. It is
-recommended that you not only read through this document for important
-changes that affect an upgrade, but that you also read through the CHANGES
-document in depth to better understand the new options available to you.
-
-Additional information on the architectural changes made in Asterisk can be
-found on the Asterisk wiki (https://wiki.asterisk.org)
-
-Of particular note, the following systems in Asterisk underwent significant
-changes. Documentation for the changes and a specification for their
-behavior in Asterisk 12 is also available on the Asterisk wiki.
- - AMI: Many events were changed, and the semantics of channels and bridges
-        were defined. In particular, how channels and bridges behave under
-        transfer scenarios and situations involving multiple parties has
-        changed significantly. See https://wiki.asterisk.org/wiki/x/dAFRAQ
-        for more information.
- - CDR: CDR logic was extracted from the many locations it existed in across
-        Asterisk and implemented as a consumer of Stasis message bus events.
-        As a result, consistency of records has improved significantly and the
-        behavior of CDRs in transfer scenarios has been defined in the CDR
-        specification. However, significant behavioral changes in CDRs resulted
-        from the transition. The most significant change is the addition of
-        CDR entries when a channel who is the Party A in a CDR leaves a bridge.
-        See https://wiki.asterisk.org/wiki/x/pwpRAQ for more information.
- - CEL: Much like CDRs, CEL was removed from the many locations it existed in
-        across Asterisk and implemented as a consumer of Stasis message bus
-        events. It now closely follows the Bridging API model of channels and
-        bridges, and has a much closer consistency of conveyed events as AMI.
-        For the changes in events, see https://wiki.asterisk.org/wiki/x/4ICLAQ.
-
-Build System:
- - Removed the CHANNEL_TRACE development mode build option. Certain aspects of
-   the CHANNEL_TRACE build option were incompatible with the new bridging
-   architecture.
-
- - Asterisk now depends on libjansson, libuuid and optionally (but recommended)
-   libxslt and uriparser.
-
- - The new SIP stack and channel driver uses a particular version of PJSIP.
-   Please see https://wiki.asterisk.org/wiki/x/J4GLAQ for more information on
-   configuring and installing PJSIP for use with Asterisk.
-
-AgentLogin and chan_agent:
- - Along with AgentRequest, this application has been modified to be a
-   replacement for chan_agent. The chan_agent module and the Agent channel
-   driver have been removed from Asterisk, as the concept of a channel driver
-   proxying in front of another channel driver was incompatible with the new
-   architecture (and has had numerous problems through past versions of
-   Asterisk). The act of a channel calling the AgentLogin application places the
-   channel into a pool of agents that can be requested by the AgentRequest
-   application. Note that this application, as well as all other agent related
-   functionality, is now provided by the app_agent_pool module.
-
- - This application no longer performs agent authentication. If authentication
-   is desired, the dialplan needs to perform this function using the
-   Authenticate or VMAuthenticate application or through an AGI script before
-   running AgentLogin.
-
- - The agents.conf schema has changed. Rather than specifying agents on a
-   single line in comma delineated fashion, each agent is defined in a separate
-   context. This allows agents to use the power of context templates in their
-   definition.
-
- - A number of parameters from agents.conf have been removed. This includes
-   maxloginretries, autologoffunavail, updatecdr, goodbye, group, recordformat,
-   urlprefix, and savecallsin. These options were obsoleted by the move from
-   a channel driver model to the bridging/application model provided by
-   app_agent_pool.
-
- - The AGENTUPDATECDR channel variable has also been removed, for the same
-   reason as the updatecdr option.
-
- - The endcall and enddtmf configuration options are removed.  Use the
-   dialplan function CHANNEL(dtmf-features) to set DTMF features on the agent
-   channel before calling AgentLogin.
-
-AgentMonitorOutgoing
- - This application has been removed. It was a holdover from when
-   AgentCallbackLogin was removed.
-
-Answer
- - It is no longer possible to bypass updating the CDR when answering a
-   channel. CDRs are based on the channel state and will be updated when
-   the channel is Answered.
-
-ControlPlayback
- - The channel variable CPLAYBACKSTATUS may now return the value
-   'REMOTESTOPPED' when playback is stopped by an external entity.
-
-DISA
- - This application now has a dependency on the app_cdr module. It uses this
-   module to hide the CDR created prior to execution of the DISA application.
-
-DumpChan:
- - The output of DumpChan no longer includes the DirectBridge or IndirectBridge
-   fields. Instead, if a channel is in a bridge, it includes a BridgeID field
-   containing the unique ID of the bridge that the channel happens to be in.
-
-ForkCDR:
- - Nearly every parameter in ForkCDR has been updated and changed to reflect
-   the changes in CDRs. Please see the documentation for the ForkCDR
-   application, as well as the CDR specification on the Asterisk wiki.
-
-NoCDR:
- - The NoCDR application has been deprecated. Please use the CDR_PROP function
-   to disable CDRs on a channel.
-
-ParkAndAnnounce:
- - The app_parkandannounce module has been removed. The application
-   ParkAndAnnounce is now provided by the res_parking module. See the
-   Parking changes for more information.
-
-ResetCDR:
- - The 'w' and 'a' options have been removed. Dispatching CDRs to registered
-   backends occurs on an as-needed basis in order to preserve linkedid
-   propagation and other needed behavior.
- - The 'e' option is deprecated. Please use the CDR_PROP function to enable
-   CDRs on a channel that they were previously disabled on.
- - The ResetCDR application is no longer a part of core Asterisk, and instead
-   is now delivered as part of app_cdr.
-
-Queues:
- - Queue strategy rrmemory now has a predictable order similar to strategy
-   rrordered. Members will be called in the order that they are added to the
-   queue.
-
- - Removed the queues.conf check_state_unknown option.  It is no longer
-   necessary.
-
- - It is now possible to play the Queue prompts to the first user waiting in a
-   call queue. Note that this may impact the ability for agents to talk with
-   users, as a prompt may still be playing when an agent connects to the user.
-   This ability is disabled by default but can be enabled on an individual
-   queue using the 'announce-to-first-user' option.
-
- - The configuration options eventwhencalled and eventmemberstatus have been
-   removed.  As a result, the AMI events QueueMemberStatus, AgentCalled,
-   AgentConnect, AgentComplete, AgentDump, and AgentRingNoAnswer will always be
-   sent.  The "Variable" fields will also no longer exist on the Agent* events.
-   These events can be filtered out from a connected AMI client using the
-   eventfilter setting in manager.conf.
-
- - The queue log now differentiates between blind and attended transfers. A
-   blind transfer will result in a BLINDTRANSFER message with the destination
-   context and extension. An attended transfer will result in an
-   ATTENDEDTRANSFER message. This message will indicate the method by which
-   the attended transfer was completed: "BRIDGE" for a bridge merge, "APP"
-   for running an application on a bridge or channel, or "LINK" for linking
-   two bridges together with local channels. The queue log will also now detect
-   externally initiated blind and attended transfers and record the transfer
-   status accordingly.
-
- - When performing queue pause/unpause on an interface without specifying an
-   individual queue, the PAUSEALL/UNPAUSEALL event will only be logged if at
-   least one member of any queue exists for that interface.
-
-SetAMAFlags
- - This application is deprecated in favor of CHANNEL(amaflags).
-
-VoiceMail:
- - Mailboxes defined by app_voicemail MUST be referenced by the rest of the
-   system as mailbox at context.  The rest of the system cannot add @default
-   to mailbox identifiers for app_voicemail that do not specify a context
-   any longer.  It is a mailbox identifier format that should only be
-   interpreted by app_voicemail.
-
- - The voicemail.conf configuration file now has an 'alias' configuration
-   parameter for use with the Directory application. The voicemail realtime
-   database table schema has also been updated with an 'alias' column. Systems
-   using voicemail with realtime should update their schemas accordingly.
-
-Channel Drivers:
- - When a channel driver is configured to enable jiterbuffers, they are now
-   applied unconditionally when a channel joins a bridge. If a jitterbuffer
-   is already set for that channel when it enters, such as by the JITTERBUFFER
-   function, then the existing jitterbuffer will be used and the one set by
-   the channel driver will not be applied.
-
-chan_bridge
- - chan_bridge is removed and its functionality is incorporated into ConfBridge
-   itself.
-
-chan_dahdi:
- - Analog port dialing and deferred DTMF dialing for PRI now distinguishes
-   between 'w' and 'W'.  The 'w' pauses dialing for half a second.  The 'W'
-   pauses dialing for one second.
-
- - The default for inband_on_proceeding has changed to no.
-
- - The CLI command 'dahdi destroy channel' is now 'dahdi destroy channels'.
-   A range of channels can be specified to be destroyed. Note that this command
-   should only be used if you understand the risks it entails.
-
- - The script specified by the chan_dahdi.conf mwimonitornotify option now gets
-   the exact configured mailbox name.  For app_voicemail mailboxes this is
-   mailbox at context.
-
- - Added mwi_vm_boxes that also must be configured for ISDN MWI to be enabled.
-
- - ignore_failed_channels now defaults to True: the channel will continue to
-   be configured even if configuring it has failed. This is generally a
-   better setup for systems with not more than one DAHDI device or with DAHDI
-   >= 2.8.0 .
-
-chan_local:
- - The /b option has been removed.
-
- - chan_local moved into the system core and is no longer a loadable module.
-
-chan_sip:
- - The 'callevents' parameter has been removed. Hold AMI events are now raised
-   in the core, and can be filtered out using the 'eventfilter' parameter
-   in manager.conf.
-
- - Dynamic realtime tables for SIP Users can now include a 'path' field. This
-   will store the path information for that peer when it registers. Realtime
-   tables can also use the 'supportpath' field to enable Path header support.
-
- - LDAP realtime configurations for SIP Users now have the AstAccountPathSupport
-   objectIdentifier. This maps to the supportpath option in sip.conf.
-
-Core:
- - Masquerades as an operation inside Asterisk have been effectively hidden
-   by the migration to the Bridging API. As such, many 'quirks' of Asterisk
-   no longer occur. This includes renaming of channels, "<ZOMBIE>" channels,
-   dropping of frame/audio hooks, and other internal implementation details
-   that users had to deal with. This fundamental change has large implications
-   throughout the changes documented for this version. For more information
-   about the new core architecture of Asterisk, please see the Asterisk wiki.
-
- - The following channel variables have changed behavior which is described in
-   the CHANGES file: TRANSFER_CONTEXT, BRIDGEPEER, BRIDGEPVTCALLID,
-   ATTENDED_TRANSFER_COMPLETE_SOUND, DYNAMIC_FEATURENAME, and DYNAMIC_PEERNAME.
-
-AMI (Asterisk Manager Interface):
- - Version 1.4 - The details of what happens to a channel when a masquerade
-   happens (transfers, parking, etc) have changed.
-   - The Masquerade event now includes the Uniqueid's of the clone and original
-     channels.
-   - Channels no longer swap Uniqueid's as a result of the masquerade.
-   - Instead of a shell game of renames, there's now a single rename, appending
-     <ZOMBIE> to the name of the original channel.
-
- - *Major* changes were made to both the syntax as well as the semantics of the
-   AMI protocol. In particular, AMI events have been substantially modified
-   and improved in this version of Asterisk. The major event changes are listed
-   below.
-   - NewPeerAccount has been removed. NewAccountCode is raised instead.
-   - Reload events have been consolidated and standardized.
-   - ModuleLoadReport has been removed.
-   - FaxSent is now SendFAX; FaxReceived is now ReceiveFAX. This standardizes
-     app_fax and res_fax events.
-   - MusicOnHold has been replaced with MusicOnHoldStart and MusicOnHoldStop.
-   - JabberEvent has been removed.
-   - Hold is now in the core and will now raise Hold and Unhold events.
-   - Join is now QueueCallerJoin.
-   - Leave is now QueueCallerLeave.
-   - Agentlogin/Agentlogoff is now AgentLogin/AgentLogoff, respectively.
-   - ChannelUpdate has been removed.
-   - Local channel optimization is now conveyed via LocalOptimizationBegin and
-     LocalOptimizationEnd.
-   - BridgeAction and BridgeExec have been removed.
-   - BlindTransfer and AttendedTransfer events were added.
-   - Dial is now DialBegin and DialEnd.
-   - DTMF is now DTMFBegin and DTMFEnd.
-   - Bridge has been replaced with BridgeCreate, BridgeEnter, BridgeLeave, and
-     BridgeDestroy
-   - MusicOnHold has been replaced with MusicOnHoldStart and MusicOnHoldStop
-   - AGIExec is now AGIExecStart and AGIExecEnd
-   - AsyncAGI is now AsyncAGIStart, AsyncAGIExec, and AsyncAGIEnd
-
- - The 'MCID' AMI event now publishes a channel snapshot when available and
-   its non-channel-snapshot parameters now use either the "MCallerID" or
-   'MConnectedID' prefixes with Subaddr*, Name*, and Num* suffixes instead
-   of 'CallerID' and 'ConnectedID' to avoid confusion with similarly named
-   parameters in the channel snapshot.
-
- - The 'Channel' key used in the 'AlarmClear', 'Alarm', and 'DNDState' has been
-   renamed "DAHDIChannel" since it does not convey an Asterisk channel name.
-
- - All AMI events now contain a 'SystemName' field, if available.
-
- - Local channel information in events is now prefixed with 'LocalOne' and
-   'LocalTwo'. This replaces the suffix of '1' and '2' for the two halves of
-   the Local channel. This affects the 'LocalBridge', 'LocalOptimizationBegin',
-   and 'LocalOptimizationEnd' events.
-
- - The 'RTCPSent'/'RTCPReceived' events have been significantly modified from
-   previous versions. They now report all SR/RR packets sent/received, and
-   have been restructured to better reflect the data sent in a SR/RR. In
-   particular, the event structure now supports multiple report blocks.
-
- - The deprecated use of | (pipe) as a separator in the channelvars setting in
-   manager.conf has been removed.
-
- - The SIP SIPqualifypeer action now sends a response indicating it will qualify
-   a peer once a peer has been found to qualify.  Once the qualify has been
-   completed it will now issue a SIPqualifypeerdone event.
-
- - The AMI event 'Newexten' field 'Extension' is deprecated, and may be removed
-   in a future release. Please use the common 'Exten' field instead.
-
- - The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
-   'UnParkedCall' have changed significantly in the new res_parking module.
-   - The 'Channel' and 'From' headers are gone. For the channel that was parked
-     or is coming out of parking, a 'Parkee' channel snapshot is issued and it
-     has a number of fields associated with it. The old 'Channel' header relayed
-     the same data as the new 'ParkeeChannel' header.
-   - The 'From' field was ambiguous and changed meaning depending on the event.
-     for most of these, it was the name of the channel that parked the call
-     (the 'Parker'). There is no longer a header that provides this channel name,
-     however the 'ParkerDialString' will contain a dialstring to redial the
-     device that parked the call.
-   - On UnParkedCall events, the 'From' header would instead represent the
-     channel responsible for retrieving the parkee. It receives a channel
-     snapshot labeled 'Retriever'. The 'from' field is is replaced with
-     'RetrieverChannel'.
-   - Lastly, the 'Exten' field has been replaced with 'ParkingSpace'.
-
- - The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar
-   fashion has changed the field names 'StartExten' and 'StopExten' to
-   'StartSpace' and 'StopSpace' respectively.
-
- - The AMI 'Status' response event to the AMI Status action replaces the
-   'BridgedChannel' and 'BridgedUniqueid' headers with the 'BridgeID' header to
-   indicate what bridge the channel is currently in.
-
-CDR (Call Detail Records)
- - Significant changes have been made to the behavior of CDRs. The CDR engine
-   was effectively rewritten and built on the Stasis message bus. For a full
-   definition of CDR behavior in Asterisk 12, please read the specification
-   on the Asterisk wiki (wiki.asterisk.org).
-
- - CDRs will now be created between all participants in a bridge. For each
-   pair of channels in a bridge, a CDR is created to represent the path of
-   communication between those two endpoints. This lets an end user choose who
-   to bill for what during bridge operations with multiple parties.
-
- - The duration, billsec, start, answer, and end times now reflect the times
-   associated with the current CDR for the channel, as opposed to a cumulative
-   measurement of all CDRs for that channel.
-
-CEL:
- - The Uniqueid field for a channel is now a stable identifier, and will not
-   change due to transfers, parking, etc.
-
- - CEL has undergone significant rework in Asterisk 12, and is now built on the
-   Stasis message bus. Please see the specification for CEL on the Asterisk
-   wiki at https://wiki.asterisk.org/wiki/x/4ICLAQ for more detailed
-   information. A summary of the affected events is below:
-   - BRIDGE_START, BRIDGE_END, BRIDGE_UPDATE, 3WAY_START, 3WAY_END, CONF_ENTER,
-     CONF_EXIT, CONF_START, and CONF_END events have all been removed. These
-     events have been replaced by BRIDGE_ENTER/BRIDGE_EXIT.
-   - BLINDTRANSFER/ATTENDEDTRANSFER events now report the peer as NULL and
-     additional information in the extra string field.
-
-Dialplan Functions:
-
- - Certain dialplan functions have been marked as 'dangerous', and may only be
-   executed from the dialplan. Execution from extenal sources (AMI's GetVar and
-   SetVar actions; etc.) may be inhibited by setting live_dangerously in the
-   [options] section of asterisk.conf to no. SHELL(), channel locking, and
-   direct file read/write functions are marked as dangerous. DB_DELETE() and
-   REALTIME_DESTROY() are marked as dangerous for reads, but can now safely
-   accept writes (which ignore the provided value).
- - The default value for live_dangerously was changed from yes (in Asterisk 11
-   and earlier) to no (in Asterisk 12 and greater).
-
-Dialplan:
- - All channel and global variable names are evaluated in a case-sensitive
-   manner. In previous versions of Asterisk, variables created and evaluated in
-   the dialplan were evaluated case-insensitively, but built-in variables and
-   variable evaluation done internally within Asterisk was done
-   case-sensitively.
-
- - Asterisk has always had code to ignore dash '-' characters that are not
-   part of a character set in the dialplan extensions.  The code now
-   consistently ignores these characters when matching dialplan extensions.
-
- - BRIDGE_FEATURES channel variable is now casesensitive for feature letter
-   codes. Uppercase variants apply them to the calling party while lowercase
-   variants apply them to the called party.
-
-Features:
- - The features.conf [applicationmap] <FeatureName>  ActivatedBy option is
-   no longer honored.  The feature is always activated by the channel that has
-   DYNAMIC_FEATURES defined on it when it enters the bridge. Use predial to set
-   different values of DYNAMIC_FEATURES on the channels
-
- - Executing a dynamic feature on the bridge peer in a multi-party bridge will
-   execute it on all peers of the activating channel.
-
- - There is no longer an explicit 'features reload' CLI command. Features can
-   still be reloaded using 'module reload features'.
-
- - It is no longer necessary (or possible) to define the ATXFER_NULL_TECH in
-   features.c for atxferdropcall=no to work properly. This option now just
-   works.
-
-Parking:
- - Parking has been extracted from the Asterisk core as a loadable module,
-   res_parking.
-
- - Configuration is found in res_parking.conf. It is no longer supported in
-   features.conf
-
- - The arguments for the Park, ParkedCall, and ParkAndAnnounce applications 
-   have been modified significantly. See the application documents for 
-   specific details.
-
- - Numerous changes to Parking related applications, AMI and CLI commands and
-   internal inter-workings  have been made. Please read the CHANGES file for 
-   the detailed list.
-
-Security Events Framework:
- - Security Event timestamps now use ISO 8601 formatted date/time instead of
-   the "seconds-microseconds" format that it was using previously.
-
-AGENT:
- - The password option has been disabled, as the AgentLogin application no
-   longer provides authentication.
-
-AUDIOHOOK_INHERIT:
- - Due to changes in the Asterisk core, this function is no longer needed to
-   preserve a MixMonitor on a channel during transfer operations and dialplan
-   execution. It is effectively obsolete.
-
-CDR: (function)
- - The 'amaflags' and 'accountcode' attributes for the CDR function are
-   deprecated. Use the CHANNEL function instead to access these attributes.
-
- - The 'l' option has been removed. When reading a CDR attribute, the most
-   recent record is always used. When writing a CDR attribute, all non-finalized
-   CDRs are updated.
-
- - The 'r' option has been removed, for the same reason as the 'l' option.
-
- - The 's' option has been removed, as LOCKED semantics no longer exist in the
-   CDR engine.
-
-VMCOUNT:
- - Mailboxes defined by app_voicemail MUST be referenced by the rest of the
-   system as mailbox at context.  The rest of the system cannot add @default
-   to mailbox identifiers for app_voicemail that do not specify a context
-   any longer.  It is a mailbox identifier format that should only be
-   interpreted by app_voicemail.
-
-res_rtp_asterisk:
- - ICE/STUN/TURN support in res_rtp_asterisk has been made optional. To enable
-   them, an Asterisk-specific version of PJSIP needs to be installed.
-   Tarballs are available from https://github.com/asterisk/pjproject/tags/.
-
-
-===========================================================
-===========================================================
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 0c500da..cf8a1aa 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -16,301 +16,161 @@
 === UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
 === UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
 === UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
-=== UPGRADE-10.txt  -- Upgrade info for 1.8 to 10
-=== UPGRADE-11.txt  -- Upgrade info for 10 to 11
-=== UPGRADE-12.txt  -- Upgrade info for 11 to 12
+=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
+===
 ===========================================================
 
-From 13.0.0 to 13.1.0:
-
-ARI:
- - The version of ARI has been bumped to 1.6.0 to account for backwards
-   compatible features included with this release. See CHANGES for more
-   information.
-
-AMI:
- - The version of AMI has been bumped to 2.6.0 to account for backwards
-   compatible features included with this release. See CHANGES for more
-   information.
-
-Core:
- - The core of Asterisk uses a message bus called "Stasis" to distribute
-   information to internal components. For performance reasons, the message
-   distribution was modified to make use of a thread pool instead of a
-   dedicated thread per consumer in certain cases. The initial settings for
-   the thread pool can now be configured in 'stasis.conf'.
-
-PJSIP:
- - Added the pjsip.conf system type disable_tcp_switch option.  The option
-   allows the user to disable switching from UDP to TCP transports described
-   by RFC 3261 section 18.1.1.
-
-From 12 to 13:
-General Asterisk Changes:
- - The asterisk command line -I option and the asterisk.conf internal_timing
-   option are removed and always enabled if any timing module is loaded.
+from 11.17 to 11.18
 
- - The per console verbose level feature as previously implemented caused a
-   large performance penalty.  The fix required some minor incompatibilities
-   if the new rasterisk is used to connect to an earlier version.  If the new
-   rasterisk connects to an older Asterisk version then the root console verbose
-   level is always affected by the "core set verbose" command of the remote
-   console even though it may appear to only affect the current console.  If
-   an older version of rasterisk connects to the new version then the
-   "core set verbose" command will have no effect.
-
- - The asterisk compatibility options in asterisk.conf have been removed.
-   These options enabled certain backwards compatibility features for
-   pbx_realtime, res_agi, and app_set that made their behaviour similar to
-   Asterisk 1.4. Users who used these backwards compatibility settings should
-   update their dialplans to use ',' instead of '|' as a delimiter, and should
-   use the Set dialplan application instead of the MSet dialplan application.
+Source Control:
+ - Asterisk has moved from Subversion to Git. As a result, several changes
+   were required in functionality. These are listed individually in the
+   notes below.
 
 Build System:
- - Sample config files have been moved from configs/ to a subfolder of that
-   directory, 'samples'.
-
  - The menuselect utility has been pulled into the Asterisk repository. As a
    result, the libxml2 development library is now a required dependency for
    Asterisk.
 
- - Added a new Compiler Flag, REF_DEBUG. When enabled, reference counted
-   objects will emit additional debug information to the refs log file located
-   in the standard Asterisk log file directory. This log file is useful in
-   tracking down object leaks and other reference counting issues. Prior to
-   this version, this option was only available by modifying the source code
-   directly. This change also includes a new script, refcounter.py, in the
-   contrib folder that will process the refs log file.
-
-Applications:
-
-ConfBridge:
- - The sound_place_into_conference sound used in Confbridge is now deprecated
-   and is no longer functional since it has been broken since its inception
-   and the fix involved using a different method to achieve the same goal. The
-   new method to achieve this functionality is by using sound_begin to play
-   a sound to the conference when waitmarked users are moved into the conference.
-
- - Added 'Admin' header to ConfbridgeJoin, ConfbridgeLeave, ConfbridgeMute,
-   ConfbridgeUnmute, and ConfbridgeTalking AMI events.
-
-ControlPlayback:
- - The ControlPlayback and 'control stream file' AGI command will no longer
-   implicitly answer the channel. If you do not answer the channel prior to
-   using either this application or AGI command, you must send Progress
-   first.
-
-Queue:
- - Queue rules provided in queuerules.conf can no longer be named "general".
-
-SetMusicOnHold:
- - The SetMusicOnHold dialplan application was deprecated and has been removed.
-   Users of the application should use the CHANNEL function's musicclass
-   setting instead.
-
-WaitMusicOnHold:
- - The WaitMusicOnHold dialplan application was deprecated and has been
-   removed. Users of the application should use MusicOnHold with a duration
-   parameter instead.
-
-CDR Backends:
- - The cdr_sqlite module was deprecated and has been removed. Users of this
-   module should use the cdr_sqlite3_custom module instead.
+AMI:
+ - The 'ModuleCheck' Action's Version key will now always report the
+   current version of Asterisk.
 
-Channel Drivers:
+CLI:
+ - The 'core show file version' command has been altered. In the past,
+   this command would show the SVN revision of the source files compiled
+   in Asterisk. However, when Asterisk moved to Git, the source control
+   version support was removed. As a result, the version information shown
+   by the CLI command is always the Asterisk version. This CLI command
+   will be removed in Asterisk 14.
 
 chan_dahdi:
- - SS7 support now requires libss7 v2.0 or later.
-
- - Added the inband_on_setup_ack compatibility option to chan_dahdi.conf to
-   deal with switches that don't send an inband progress indication in the
-   SETUP ACKNOWLEDGE message.
-   Default is now no.
-
-chan_gtalk
- - This module was deprecated and has been removed. Users of chan_gtalk
-   should use chan_motif.
-
-chan_h323
- - This module was deprecated and has been removed. Users of chan_h323
-   should use chan_ooh323.
-
-chan_jingle
- - This module was deprecated and has been removed. Users of chan_jingle
-   should use chan_motif.
-
-chan_pjsip:
- - Added a 'force_avp' option to chan_pjsip which will force the usage of
-   'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' as the media transport type
-   in SDP offers depending on settings, even when DTLS is used for media
-   encryption.
-
- - Added a 'media_use_received_transport' option to chan_pjsip which will
-   cause the SDP answer to use the media transport as received in the SDP
-   offer.
-
-chan_sip:
- - Made set SIPREFERREDBYHDR as inheritable for better chan_pjsip
-   interoperability.
-
- - The SIPPEER dialplan function no longer supports using a colon as a
-   delimiter for parameters. The parameters for the function should be
-   delimited using a comma.
-
- - The SIPCHANINFO dialplan function was deprecated and has been removed. Users
-   of the function should use the CHANNEL function instead.
+ - Added the force_restart_unavailable_chans compatibility option.  When
+   enabled it causes Asterisk to restart the ISDN B channel if an outgoing
+   call receives cause 44 (Requested channel not available).  The new option
+   is enabled by default in current release branches for backward
+   compatibility.
+
+cdr_odbc:
+ - Added support for post-1.8 CDR columns 'peeraccount', 'linkedid', and
+   'sequence'. Support for the new columns can be enabled via the newcdrcolumns
+   option in cdr_odbc.conf.
+
+cdr_csv:
+ - Added a new configuration option, "newcdrcolumns", which enables use of the
+   post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'.
+
+from 11.16 to 11.17
+chan_dahdi:
+ - For users using the FXO port (FXS signaling) distinctive ring detection
+   feature, you will need to adjust the dringX count values.  The count
+   values now only record ring end events instead of any DAHDI event.  A
+   ring-ring-ring pattern would exceed the pattern limits and stop
+   Caller-ID detection.
 
+from 11.15 to 11.16
+chan_dahdi:
+ - The CALLERID(ani2) value for incoming calls is now populated in featdmf
+   signaling mode.  The information was previously discarded.
+
+from 11.13.0 to 11.13.1:
+
+* Due to the POODLE vulnerability (see 
+  https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3566), the
+  default TLS method for TLS clients will no longer allow SSLv3. As
+  SSLv2 was already deprecated, it is no longer allowed by default as
+  well. TLS servers no longer allow SSLv2 or SSLv3 connections. This
+  affects the chan_sip channel driver, AMI, and the Asterisk HTTP server.
+
+* The res_jabber resource module no longer uses SSLv3 to connect to an
+  XMPP server. It will now only use TLSv1 or later methods.
+
+from 11.10.2 to 11.11.0
+ - Added a compatibility option for chan_sip, 'websocket_write_timeout'.
+   When a websocket connection exists where Asterisk writes a substantial
+   amount of data to the connected client, and the connected client is slow
+   to process the received data, the socket may be disconnected. In such
+   cases, it may be necessary to adjust this value. Default is 100 ms.
  - Added a 'force_avp' option for chan_sip. When enabled this option will
    cause the media transport in the offer or answer SDP to be 'RTP/AVP',
    'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' even if a DTLS stream has been
    configured. This option can be set to improve interoperability with WebRTC
    clients that don't use the RFC defined transport for DTLS.
-
  - The 'dtlsverify' option in chan_sip now has additional values besides
    'yes' and 'no'. If 'yes' is specified both the certificate and fingerprint
    will be verified. If 'no' is specified then neither the certificate or
    fingerprint is verified. If 'certificate' is specified then only the
    certificate is verified. If 'fingerprint' is specified then only the
    fingerprint is verified.
-
  - A 'dtlsfingerprint' option has been added to chan_sip which allows the
    hash to be specified for the DTLS fingerprint placed in SDP. Supported
    values are 'sha-1' and 'sha-256' with 'sha-256' being the default.
 
- - The 'progressinband=never' option is now more zealous in the persecution of
-   progress messages coming from Asterisk. Channels bridged with a SIP channel
-   that has 'progressinband=never' set will not be able to forward their
-   progress indications through to the SIP device. chan_sip will now turn such
-   progress indications into a 180 Ringing (if a 180 has not yet been
-   transmitted) if 'progressinband=never'.
-
-  - The codec preference order in an SDP during an offer is slightly different
-    than previous releases. Prior to Asterisk 13, the preference order of
-    codecs used to be:
-    (1) Our preferred codec
-    (2) Our configured codecs
-    (3) Any non-audio joint codecs
-
-    One of the ways the new media format architecture in Asterisk 13 improves
-    performance is by reference counting formats, such that they can be reused
-    in many places without additional allocation. To not require a large
-    amount of locking, an instance of a format is immutable by convention.
-    This works well except for formats with attributes. Since a media format
-    with an attribute is a different object than the same format without an
-    attribute, we have to carry over the formats with attributes from an
-    inbound offer so that the correct attributes are offered in an outgoing
-    INVITE request. This requires some subtle tweaks to the preference order
-    to ensure that the media format with attributes is offered to a remote
-    peer, as opposed to the same media format (but without attributes) that
-    may be stored in the peer object.
-
-    All of this means that our offer offer list will now be:
-    (1) Our preferred codec
-    (2) Any joint codecs offered by the inbound offer
-    (3) All other codecs that are not the preferred codec and not a joint
-        codec offered by the inbound offer
-
-chan_unistim:
- - The unistim.conf 'dateformat' has changed meaning of options values to conform
-   values used inside Unistim protocol
-
- - Added 'dtmf_duration' option with changing default operation to disable
-   receivied dtmf playback on unistim phone
-
-Core:
-
-Account Codes:
- - accountcode behavior changed somewhat to add functional peeraccount
-   support.  The main change is that local channels now cross accountcode
-   and peeraccount across the special bridge between the ;1 and ;2 channels
-   just like channels between normal bridges.  See the CHANGES file for
-   more information.
-
-ARI:
- - The ARI version has been changed to 1.5.0. This is to reflect backwards
-   compatible changes made since 12.0.0 was released.
-
- - Added a new ARI resource 'mailboxes' which allows the creation and
-   modification of mailboxes managed by external MWI. Modules res_mwi_external
-   and res_stasis_mailbox must be enabled to use this resource.
-
- - Added new events for externally initiated transfers. The event
-   BridgeBlindTransfer is now raised when a channel initiates a blind transfer
-   of a bridge in the ARI controlled application to the dialplan; the
-   BridgeAttendedTransfer event is raised when a channel initiates an
-   attended transfer of a bridge in the ARI controlled application to the
-   dialplan.
-
- - Channel variables may now be specified as a body parameter to the
-   POST /channels operation. The 'variables' key in the JSON is interpreted
-   as a sequence of key/value pairs that will be added to the created channel
-   as channel variables. Other parameters in the JSON body are treated as
-   query parameters of the same name.
-
- - A bug fix in bridge creation has caused a behavioural change in how
-   subscriptions are created for bridges. A bridge created through ARI, does
-   not, by itself, have a subscription created for any particular Stasis
-   application. When a channel in a Stasis application joins a bridge, an
-   implicit event subscription is created for that bridge as well. Previously,
-   when a channel left such a bridge, the subscription was leaked; this allowed
-   for later bridge events to continue to be pushed to the subscribed
-   applications. That leak has been fixed; as a result, bridge events that were
-   delivered after a channel left the bridge are no longer delivered. An
-   application must subscribe to a bridge through the applications resource if
-   it wishes to receive all events related to a bridge.
-
-AMI:
- - The AMI version has been changed to 2.5.0. This is to reflect backwards
-   compatible changes made since 12.0.0 was released.
-
- - The DialStatus field in the DialEnd event can now have additional values.
-   This includes ABORT, CONTINUE, and GOTO.
-
- - The res_mwi_external_ami module can, if loaded, provide additional AMI
-   actions and events that convey MWI state within Asterisk. This includes
-   the MWIGet, MWIUpdate, and MWIDelete actions, as well as the MWIGet and
-   MWIGetComplete events that occur in response to an MWIGet action.
-
- - AMI now contains a new class authorization, 'security'. This is used with
-   the following new events: FailedACL, InvalidAccountID, SessionLimit,
-   MemoryLimit, LoadAverageLimit, RequestNotAllowed, AuthMethodNotAllowed,
-   RequestBadFormat, SuccessfulAuth, UnexpectedAddress, ChallengeResponseFailed,
-   InvalidPassword, ChallengeSent, and InvalidTransport.
-
- - Bridge related events now have two additional fields: BridgeName and
-   BridgeCreator. BridgeName is a descriptive name for the bridge;
-   BridgeCreator is the name of the entity that created the bridge. This
-   affects the following events: ConfbridgeStart, ConfbridgeEnd,
-   ConfbridgeJoin, ConfbridgeLeave, ConfbridgeRecord, ConfbridgeStopRecord,
-   ConfbridgeMute, ConfbridgeUnmute, ConfbridgeTalking, BlindTransfer,
-   AttendedTransfer, BridgeCreate, BridgeDestroy, BridgeEnter, BridgeLeave
+ - Added the inband_on_setup_ack compatibility option to chan_dahdi.conf to
+   deal with switches that don't send an inband progress indication in the
+   SETUP ACKNOWLEDGE message.
 
+from 11.10.0 to 11.10.1
  - MixMonitor AMI actions now require users to have authorization classes.
    * MixMonitor - system
    * MixMonitorMute - call or system
    * StopMixMonitor - call or system
 
+ - Added http.conf session_inactivity timer option to close HTTP connections
+   that aren't doing anything.
+
  - Removed the undocumented manager.conf block-sockets option.  It interferes with
    TCP/TLS inactivity timeouts.
 
- - The response to the PresenceState AMI action has historically contained two
-   Message keys. The first of these is used as an informative message regarding
-   the success/failure of the action; the second contains a Presence state
-   specific message. Having two keys with the same unique name in an AMI
-   message is cumbersome for some client; hence, the Presence specific Message
-   has been deprecated. The message will now contain a PresenceMessage key
-   for the presence specific information; the Message key containing presence
-   information will be removed in the next major version of AMI.
-
- - The manager.conf 'eventfilter' now takes an "extended" regular expression
-   instead of a "basic" one.
-
-CDRs:
- - The "endbeforehexten" setting now defaults to "yes", instead of "no".
-   When set to "no", yhis setting will cause a new CDR to be generated when a
-   channel enters into hangup logic (either the 'h' extension or a hangup
-   handler subroutine). In general, this is not the preferred default: this
-   causes extra CDRs to be generated for a channel in many common dialplans.
+from 11.9 to 11.10
+ - The asterisk command line -I option and the asterisk.conf internal_timing
+   option are removed and always enabled if any timing module is loaded.
+
+ - Added a new Compiler Flag, REF_DEBUG. When enabled, reference counted
+   objects will emit additional debug information to the refs log file located
+   in the standard Asterisk log file directory. This log file is useful in
+   tracking down object leaks and other reference counting issues. Prior to
+   this version, this option was only available by modifying the source code
+   directly. This change also includes a new script, refcounter.py, in the
+   contrib folder that will process the refs log file.
+
+from 11.8 to 11.9
+- res_fax now returns the correct rates for V.27ter (4800 or 9600 bit/s).
+  Because of this the default settings would not load, so the minrate (minimum
+  transmission rate) option was changed to default to 4800 since that is the
+  minimum rate for v.27 which is included in the default modem options.
+
+- The sound_place_into_conference sound used in Confbridge is now deprecated
+  and is no longer functional since it has been broken since its inception
+  and the fix involved using a different method to achieve the same goal. The
+  new method to achieve this functionality is by using sound_begin to play
+  a sound to the conference when waitmarked users are moved into the conference.
+
+- When communicating with a peer on an Asterisk 1.4 or earlier system, the
+  chan_iax2 parameter 'connectedline' must be set to "no" in iax.conf. This
+  prevents an incompatible connected line frame from an Astersik 1.8 or later
+  system from causing a hangup in an Asterisk 1.4 or earlier system. Note that
+  this particular incompatibility has always existed between 1.4 and 1.8 and
+  later versions; this upgrade note is simply informing users of its existance.
+
+- A compatibility setting, allow_empty_string_in_nontext, has been added to
+  res_odbc.conf. When enabled (default behavior), empty column values are
+  stored as empty strings during realtime updates. Disabling this option
+  causes empty column values to be stored as NULLs for non-text columns.
+
+  Disable it for PostgreSQL backends in order to avoid errors caused by
+  updating integer columns with an empty string instead of NULL
+  (sippeers, sipregs, ..).
+
+From 11.7 to 11.8:
+- The per console verbose level feature as previously implemented caused a
+  large performance penalty.  The fix required some minor incompatibilities
+  if the new rasterisk is used to connect to an earlier version.  If the new
+  rasterisk connects to an older Asterisk version then the root console verbose
+  level is always affected by the "core set verbose" command of the remote
+  console even though it may appear to only affect the current console.  If
+  an older version of rasterisk connects to the new version then the
+  "core set verbose" command will have no effect.
 
 CLI commands:
  - "core show settings" now lists the current console verbosity in addition
@@ -320,7 +180,7 @@ CLI commands:
    logging levels since verbose logging levels were made per console.  That
    syntax is now removed and a silence option added in its place.
 
-Logging:
+Configuration Files:
  - The 'verbose' setting in logger.conf still takes an optional argument,
    specifying the verbosity level for each logging destination.  However,
    the default is now to once again follow the current root console level.
@@ -328,98 +188,309 @@ Logging:
    again set the root console verbose level and affect the verbose level
    logged.
 
+From 11.6 to 11.7:
+ConfBridge
+ - ConfBridge now has the ability to set the language of announcements to the
+   conference.  The language can be set on a bridge profile in confbridge.conf
+   or by the dialplan function CONFBRIDGE(bridge,language)=en.
+chan_sip - Clarify The "sip show peers" Forcerport Column And Add Comedia
+ - Under the "Forcerport" column, the "N" used to mean NAT (i.e. Yes).  With
+   the additon of auto_* NAT settings, the meaning changed and there was a
+   certain combination of letters added to indicate the current setting. The
+   combination of using "Y", "N", "A" or "a", can be confusing.  Therefore, we
+   now display clearly what the current Forcerport setting is: "Yes", "No",
+   "Auto (Yes)", "Auto (No)".
+ - Since we are clarifying the Forcerport column, we have added a column to
+   display the Comedia setting since this is useful information as well.  We
+   no longer have a simple "NAT" setting like other versions before 11.
+
+* Certain dialplan functions have been marked as 'dangerous', and may only be
+  executed from the dialplan. Execution from extenal sources (AMI's GetVar and
+  SetVar actions; etc.) may be inhibited by setting live_dangerously in the
+  [options] section of asterisk.conf to no. SHELL(), channel locking, and direct
+  file read/write functions are marked as dangerous. DB_DELETE() and
+  REALTIME_DESTROY() are marked as dangerous for reads, but can now safely
+  accept writes (which ignore the provided value).
+
+From 11.5 to 11.6:
+* res_agi will now properly indicate if there was an error in streaming an
+  audio file.  The result code will be -1 and the result returned from the
+  the function will be RESULT_FAILURE instead of the prior behavior of always
+  returning RESULT_SUCCESS even if there was an error.
+* The libuuid development library is now optional for res_rtp_asterisk. If the
+  library is not present when building ICE and TURN support will not be present.
+* The option "register_retry_403" has been added to chan_sip to work around
+  servers that are known to erroneously send 403 in response to valid
+  REGISTER requests and allows Asterisk to continue attepmting to connect.
+  Due to a failed merge, this option is present, but non-functional until 11.8.0.
+
+From 11.4 to 11.5:
+* The default settings for chan_sip are now overriden properly by the general
+  settings in sip.conf.  Please look over your settings upon upgrading.
+
+* It is now possible to play the Queue prompts to the first user waiting in a call queue.
+  Note that this may impact the ability for agents to talk with users, as a prompt may
+  still be playing when an agent connects to the user. This ability is disabled by
+  default but can be enabled on an individual queue using the 'announce-to-first-user'
+  option.
+
+* The libuuid development library is now required for res_rtp_asterisk. Consult
+  your distribution for the appropriate development library name.
+
+From 11.3 to 11.4:
+* Added the 'n' option to MeetMe to prevent application of the DENOISE function
+  to a channel joining a conference. Some channel drivers that vary the number
+  of audio samples in a voice frame will experience significant quality problems
+  if a denoiser is attached to the channel; this option gives them the ability
+  to remove the denoiser without having to unload func_speex.
+
+* The Registry AMI event for SIP registrations will now always include the
+  Username field. A previous bug fix missed an instance where it was not
+  included; that has been corrected in this release.
+
+From 11.2.0 to 11.2.1:
+* Asterisk would previously not output certain error messages when a remote
+  console attempted to connect to Asterisk and no instance of Asterisk was
+  running. This error message is displayed on stderr; as a result, some
+  initialization scripts that used remote consoles to test for the presence
+  of a running Asterisk instance started to display erroneous error messages.
+  The init.d scripts and the safe_asterisk have been updated in the contrib
+  folder to account for this.
+
+From 11.2 to 11.3:
+
+* Now by default, when Asterisk is installed in a path other than /usr, the
+  Asterisk binary will search for shared libraries in ${libdir} in addition to
+  searching system libraries. This allows Asterisk to find its shared
+  libraries without having to specify LD_LIBRARY_PATH. This can be disabled by
+  passing --disable-rpath to configure.
+
+From 11.1 to 11.2:
+
+* Asterisk has always had code to ignore dash '-' characters that are not
+  part of a character set in the dialplan extensions.  The code now
+  consistently ignores these characters when matching dialplan extensions.
+
+* Removed the queues.conf check_state_unknown option.  It is no longer
+  necessary.
+
+From 11.0 to 11.1:
+
+Queues:
+ - Queue strategy rrmemory now has a predictable order similar to strategy
+   rrordered. Members will be called in the order that they are added to the
+   queue.
+
+From 10 to 11:
+
+Voicemail:
+ - All voicemails now have a "msg_id" which uniquely identifies a message. For
+   users of filesystem and IMAP storage of voicemail, this should be transparent.
+   For users of ODBC, you will need to add a "msg_id" column to your voice mail
+   messages table. This should be a string capable of holding at least 32 characters.
+   All messages created in old Asterisk installations will have a msg_id added to
+   them when required. This operation should be transparent as well.
+
+Parking:
+ - The comebacktoorigin setting must now be set per parking lot. The setting in
+   the general section will not be applied automatically to each parking lot.
+ - The BLINDTRANSFER channel variable is deleted from a channel when it is
+   bridged to prevent subtle bugs in the parking feature.  The channel
+   variable is used by Asterisk internally for the Park application to work
+   properly.  If you were using it for your own purposes, copy it to your
+   own channel variable before the channel is bridged.
+
+res_ais:
+ - Users of res_ais in versions of Asterisk prior to Asterisk 11 must change
+   to use the res_corosync module, instead.  OpenAIS is deprecated, but
+   Corosync is still actively developed and maintained.  Corosync came out of
+   the OpenAIS project.
+
+Dialplan Functions:
+ - MAILBOX_EXISTS has been deprecated. Use VM_INFO with the 'exists' parameter
+   instead.
+ - Macro has been deprecated in favor of GoSub.  For redirecting and connected
+   line purposes use the following variables instead of their macro equivalents:
+   REDIRECTING_SEND_SUB, REDIRECTING_SEND_SUB_ARGS,
+   CONNECTED_LINE_SEND_SUB, CONNECTED_LINE_SEND_SUB_ARGS.
+ - The REDIRECTING function now supports the redirecting original party id
+   and reason.
+ - The HANGUPCAUSE and HANGUPCAUSE_KEYS functions have been introduced to
+   provide a replacement for the SIP_CAUSE hash. The HangupCauseClear
+   application has also been introduced to remove this data from the channel
+   when necessary.
+
+
+func_enum:
+ - ENUM query functions now return a count of -1 on lookup error to
+   differentiate between a failed query and a successful query with 0 results
+   matching the specified type.
+
+CDR:
+ - cdr_adaptive_odbc now supports specifying a schema so that Asterisk can
+   connect to databases that use schemas.
+
+Configuration Files:
+ - Files listed below have been updated to be more consistent with how Asterisk
+   parses configuration files.  This makes configuration files more consistent
+   with what is expected across modules.
+
+   - cdr.conf: [general] and [csv] sections
+   - dnsmgr.conf
+   - dsp.conf
+
+ - The 'verbose' setting in logger.conf now takes an optional argument,
+   specifying the verbosity level for each logging destination.  The default,
+   if not otherwise specified, is a verbosity of 3.
+
+AMI:
+  - DBDelTree now correctly returns an error when 0 rows are deleted just as
+    the DBDel action does.
+  - The IAX2 PeerStatus event now sends a 'Port' header.  In Asterisk 10, this was
+    erroneously being sent as a 'Post' header.
+
+CCSS:
+ - Macro is deprecated. Use cc_callback_sub instead of cc_callback_macro
+   in channel configurations.
+
+app_meetme:
+  - The 'c' option (announce user count) will now work even if the 'q' (quiet)
+    option is enabled.
+
+app_followme:
+ - Answered outgoing calls no longer get cut off when the next step is started.
+   You now have until the last step times out to decide if you want to accept
+   the call or not before being disconnected.
+
+chan_gtalk:
+ - chan_gtalk has been deprecated in favor of the chan_motif channel driver. It is recommended
+   that users switch to using it as it is a core supported module.
+
+chan_jingle:
+ - chan_jingle has been deprecated in favor of the chan_motif channel driver. It is recommended
+   that users switch to using it as it is a core supported module.
+
+SIP
+===
+ - A new option "tonezone" for setting default tonezone for the channel driver
+   or individual devices
+ - A new manager event, "SessionTimeout" has been added and is triggered when
+   a call is terminated due to RTP stream inactivity or SIP session timer
+   expiration.
+ - SIP_CAUSE is now deprecated.  It has been modified to use the same
+   mechanism as the HANGUPCAUSE function.  Behavior should not change, but
+   performance should be vastly improved.  The HANGUPCAUSE function should now
+   be used instead of SIP_CAUSE. Because of this, the storesipcause option in
+   sip.conf is also deprecated.
+ - The sip paramater for Originating Line Information (oli, isup-oli, and
+   ss7-oli) is now parsed out of the From header and copied into the channel's
+   ANI2 information field.  This is readable from the CALLERID(ani2) dialplan
+   function.
+ - ICE support has been added and is enabled by default. Some endpoints may have
+   problems with the ICE candidates within the SDP. If this is the case ICE support
+   can be disabled globally or on a per-endpoint basis using the icesupport
+   configuration option. Symptoms of this include one way media or no media flow.
+
+chan_unistim
+ - Due to massive update in chan_unistim phone keys functions and on-screen
+   information changed.
+
+users.conf:
+ - A defined user with hasvoicemail=yes now finally uses a Gosub to stdexten
+   as documented in extensions.conf.sample since v1.6.0 instead of a Macro as
+   documented in v1.4.  Set the asterisk.conf stdexten=macro parameter to
+   invoke the stdexten the old way.
+
+res_jabber
+ - This module has been deprecated in favor of the res_xmpp module. The res_xmpp
+   module is backwards compatible with the res_jabber configuration file, dialplan
+   functions, and AMI actions. The old CLI commands can also be made available using
+   the res_clialiases template for Asterisk 11.
+
+From 1.8 to 10:
+
+cel_pgsql:
+ - This module now expects an 'extra' column in the database for data added
+   using the CELGenUserEvent() application.
+
+ConfBridge
+ - ConfBridge's dialplan arguments have changed and are not
+   backwards compatible.
+
+File Interpreters
+ - The format interpreter formats/format_sln16.c for the file extension
+   '.sln16' has been removed. The '.sln16' file interpreter now exists
+   in the formats/format_sln.c module along with new support for sln12,
+   sln24, sln32, sln44, sln48, sln96, and sln192 file extensions.
+
 HTTP:
- - Added http.conf session_inactivity timer option to close HTTP connections
-   that aren't doing anything.
+ - A bindaddr must be specified in order for the HTTP server
+   to run. Previous versions would default to 0.0.0.0 if no
+   bindaddr was specified.
+
+Gtalk:
+ - The default value for 'context' and 'parkinglots' in gtalk.conf has
+   been changed to 'default', previously they were empty.
+
+chan_dahdi:
+ - The mohinterpret=passthrough setting is deprecated in favor of
+   moh_signaling=notify.
 
- - Added support for persistent HTTP connections.  To enable persistent
-   HTTP connections configure the keep alive time between HTTP requests.  The
-   keep alive time between HTTP requests is configured in http.conf with the
-   session_keep_alive parameter.
-
-Realtime Configuration:
- - WARNING: The database migration script that adds the 'extensions' table for
-   realtime had to be modified due to an error when installing for MySQL.  The
-   'extensions' table's 'id' column was changed to be a primary key.  This could
-   potentially cause a migration problem.  If so, it may be necessary to
-   manually alter the affected table/column to bring it back in line with the
-   migration scripts.
-
- - New columns have been added to realtime tables for 'support_path' on
-   ps_registrations and ps_aors and for 'path' on ps_contacts for the new
-   SIP Path support in chan_pjsip.
-
- - The following new tables have been added for pjsip realtime: 'ps_systems',
-   'ps_globals', 'ps_tranports', 'ps_registrations'.
-
- - The following columns were added to the 'ps_aors' realtime table:
-   'maximum_expiration', 'outbound_proxy', and 'support_path'.
-
- - The following columns were added to the 'ps_contacts' realtime table:
-   'outbound_proxy', 'user_agent', and 'path'.
-
- - New columns have been added to the ps_endpoints realtime table for the
-   'media_address', 'redirect_method' and 'set_var' options.  Also the
-   'mwi_fromuser' column was renamed to 'mwi_from_user'. A new column
-   'message_context' was added to let users configure how MESSAGE requests are
-   routed to the dialplan.
-
- - A new column was added to the 'ps_globals' realtime table for the 'debug'
-   option.
-
- - PJSIP endpoint columns 'tos_audio' and 'tos_video' have been changed from
-   yes/no enumerators to string values. 'cos_audio' and 'cos_video' have been
-   changed from yes/no enumerators to integer values. PJSIP transport column
-   'tos' has been changed from a yes/no enumerator to a string value. 'cos' has
-   been changed from a yes/no enumerator to an integer value.
-
- - The 'queues' and 'queue_members' realtime tables have been added to the
-   config Alembic scripts.
-
- - A new set of Alembic scripts has been added for CDR tables. This will create
-   a 'cdr' table with the default schema that Asterisk expects.
-
- - A new upgrade script has been added that adds a 'queue_rules' table for
-   app_queue. Users of app_queue can store queue rules in a database. It is
-   important to note that app_queue only looks for this table on module load or
-   module reload; for more information, see the CHANGES file.
-
-Resources:
-
-res_odbc:
-- The compatibility setting, allow_empty_string_in_nontext, has been removed.
-  Empty column values will be stored as empty strings during realtime updates.
-
-res_jabber:
- - This module was deprecated and has been removed. Users of this module should
-   use res_xmpp instead.
-
-res_http_websocket:
- - Added a compatibility option to ari.conf, sip.conf, and pjsip.conf
-   'websocket_write_timeout'. When a websocket connection exists where Asterisk
-   writes a substantial amount of data to the connected client, and the connected
-   client is slow to process the received data, the socket may be disconnected.
-   In such cases, it may be necessary to adjust this value.
-   Default is 100 ms.
-
-Scripts:
-
-safe_asterisk:
- - The safe_asterisk script was previously not installed on top of an existing
-   version. This caused bug-fixes in that script not to be deployed. If your
-   safe_asterisk script is customized, be sure to keep your changes. Custom
-   values for variables should be created in *.sh file(s) inside
-   ASTETCDIR/startup.d/. See ASTERISK-21965.
-
- - Changed a log message in safe_asterisk and the $NOTIFY mail subject. If
-   you use tools to parse either of them, update your parse functions
-   accordingly. The changed strings are:
-   - "Exited on signal $EXITSIGNAL" => "Asterisk exited on signal $EXITSIGNAL."
-   - "Asterisk Died" => "Asterisk on $MACHINE died (sig $EXITSIGNAL)"
-
-Utilities:
- - The refcounter program has been removed in favor of the refcounter.py script
-   in contrib/scripts.
+pbx_lua:
+ - Execution no longer continues after applications that do dialplan jumps
+   (such as app.goto).  Now when an application such as app.goto() is called,
+   control is returned back to the pbx engine and the current extension
+   function stops executing.
+ - the autoservice now defaults to being on by default
+ - autoservice_start() and autoservice_start() no longer return a value.
+
+Queue:
+ - Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
+ - QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
+
+Asterisk Database:
+ - The internal Asterisk database has been switched from Berkeley DB 1.86 to
+   SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
+   utility in the UTILS section of menuselect. If an existing astdb is found and no
+   astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
+   convert an existing astdb to the SQLite3 version automatically at runtime. If
+   moving back from Asterisk 10 to Asterisk 1.8, the astdb2bdb utility can be used
+   to create a Berkeley DB copy of the SQLite3 astdb that Asterisk 10 uses.
+
+Manager:
+ - The AMI protocol version was incremented to 1.2 as a result of changing two
+   instances of the Unlink event to Bridge events. This change was documented
+   as part of the AMI 1.1 update, but two Unlink events were inadvertently left
+   unchanged.
+
+Module Support Level
+ - All modules in the addons, apps, bridge, cdr, cel, channels, codecs,
+   formats, funcs, pbx, and res have been updated to include MODULEINFO data
+   that includes <support_level> tags with a value of core, extended, or deprecated.
+   More information is available on the Asterisk wiki at
+   https://wiki.asterisk.org/wiki/display/AST/Asterisk+Module+Support+States
+
+   Deprecated modules are now marked to not build by default and must be explicitly
+   enabled in menuselect.
+
+chan_sip:
+ - Setting of HASH(SIP_CAUSE,<slave-channel-name>) on channels is now disabled
+   by default. It can be enabled using the 'storesipcause' option. This feature
+   has a significant performance penalty.
+ - In order to improve compliance with RFC 3261, SIP usernames are now properly
+   escaped when encoding reserved characters. Prior to this change, the use of
+   these characters in certain SIP settings affecting usernames could cause
+   injections of these characters in their raw form into SIP headers which could
+   in turn cause all sorts of nasty behaviors. All characters that are not
+   alphanumeric or are not contained in the the following lists specified by
+   RFC 3261 section 25.1 will be escaped as %XX when encoding a SIP username:
+    * mark: "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
+    * user-unreserved: "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
+
+UDPTL:
+ - The default UDPTL port range in udptl.conf.sample differed from the defaults
+   in the source. If you didn't have a config file, you got 4500 to 4599. Now the
+   default is 4000 to 4999.
 
 ===========================================================
 ===========================================================
diff --git a/addons/.gitignore b/addons/.gitignore
new file mode 100644
index 0000000..663e668
--- /dev/null
+++ b/addons/.gitignore
@@ -0,0 +1 @@
+mp3
diff --git a/addons/Makefile b/addons/Makefile
index 96438f5..21d6b00 100644
--- a/addons/Makefile
+++ b/addons/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 #
 # Makefile for Add-on Modules
 #
@@ -27,6 +27,7 @@ H323OBJS:=ooCmdChannel.o ooLogChan.o ooUtils.o ooGkClient.o context.o \
 H323CFLAGS:=-Iooh323c/src -Iooh323c/src/h323
 
 ALL_C_MODS:=app_mysql \
+            app_saycountpl \
             cdr_mysql \
             chan_mobile \
             chan_ooh323 \
diff --git a/addons/app_mysql.c b/addons/app_mysql.c
index 298ed9d..2e9cae9 100644
--- a/addons/app_mysql.c
+++ b/addons/app_mysql.c
@@ -23,15 +23,6 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_mysql.c uses the configuration file \ref app_mysql.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page app_mysql.conf app_mysql.conf
- * \verbinclude app_mysql.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>mysqlclient</depend>
 	<defaultenabled>no</defaultenabled>
@@ -292,17 +283,16 @@ static int safe_scan_int(char **data, char *delim, int def)
 	return res;
 }
 
-static int aMYSQL_set(struct ast_channel *chan, const char *data)
+static int aMYSQL_set(struct ast_channel *chan, char *data)
 {
-	char *var, *tmp, *parse;
+	char *var, *tmp;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(set);
 		AST_APP_ARG(variable);
 		AST_APP_ARG(value);
 	);
 
-	parse = ast_strdupa(data);
-	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
+	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
 
 	if (args.argc == 3) {
 		var = ast_alloca(6 + strlen(args.variable) + 1);
@@ -318,7 +308,7 @@ static int aMYSQL_set(struct ast_channel *chan, const char *data)
 }
 
 /* MYSQL operations */
-static int aMYSQL_connect(struct ast_channel *chan, const char *data)
+static int aMYSQL_connect(struct ast_channel *chan, char *data)
 {
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(connect);
@@ -334,9 +324,8 @@ static int aMYSQL_connect(struct ast_channel *chan, const char *data)
 	const char *ctimeout;
 	unsigned int port = 0;
 	char *port_str;
-	char *parse = ast_strdupa(data);
- 
-	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
+
+	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
 
 	if (args.argc < 6) {
 		ast_log(LOG_WARNING, "MYSQL_connect is missing some arguments\n");
@@ -387,7 +376,7 @@ static int aMYSQL_connect(struct ast_channel *chan, const char *data)
 	return 0;
 }
 
-static int aMYSQL_query(struct ast_channel *chan, const char *data)
+static int aMYSQL_query(struct ast_channel *chan, char *data)
 {
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(query);
@@ -399,9 +388,8 @@ static int aMYSQL_query(struct ast_channel *chan, const char *data)
 	MYSQL_RES   *mysqlres;
 	int connid;
 	int mysql_query_res;
-	char *parse = ast_strdupa(data);
 
-	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
+	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
 
 	if (args.argc != 4 || (connid = atoi(args.connid)) == 0) {
 		ast_log(LOG_WARNING, "missing some arguments\n");
@@ -429,7 +417,7 @@ static int aMYSQL_query(struct ast_channel *chan, const char *data)
 	return -1;
 }
 
-static int aMYSQL_nextresult(struct ast_channel *chan, const char *data)
+static int aMYSQL_nextresult(struct ast_channel *chan, char *data)
 {
 	MYSQL       *mysql;
 	MYSQL_RES   *mysqlres;
@@ -439,9 +427,8 @@ static int aMYSQL_nextresult(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(connid);
 	);
 	int connid = -1;
-	char *parse = ast_strdupa(data);
 
-	AST_NONSTANDARD_APP_ARGS(args, parse, ' ');
+	AST_NONSTANDARD_APP_ARGS(args, data, ' ');
 	sscanf(args.connid, "%30d", &connid);
 
 	if (args.argc != 3 || connid <= 0) {
@@ -470,7 +457,7 @@ static int aMYSQL_nextresult(struct ast_channel *chan, const char *data)
 }
 
 
-static int aMYSQL_fetch(struct ast_channel *chan, const char *data)
+static int aMYSQL_fetch(struct ast_channel *chan, char *data)
 {
 	MYSQL_RES *mysqlres;
 	MYSQL_ROW mysqlrow;
@@ -522,14 +509,13 @@ static int aMYSQL_fetch(struct ast_channel *chan, const char *data)
 	return -1;
 }
 
-static int aMYSQL_clear(struct ast_channel *chan, const char *data)
+static int aMYSQL_clear(struct ast_channel *chan, char *data)
 {
 	MYSQL_RES *mysqlres;
 
 	int id;
-	char *parse = ast_strdupa(data);
-	strsep(&parse, " "); /* eat the first token, we already know it :P */
-	id = safe_scan_int(&parse, " \n", -1);
+	strsep(&data, " "); /* eat the first token, we already know it :P */
+	id = safe_scan_int(&data, " \n", -1);
 	if ((mysqlres = find_identifier(id, AST_MYSQL_ID_RESID)) == NULL) {
 		ast_log(LOG_WARNING, "Invalid result identifier %d passed in aMYSQL_clear\n", id);
 	} else {
@@ -540,14 +526,13 @@ static int aMYSQL_clear(struct ast_channel *chan, const char *data)
 	return 0;
 }
 
-static int aMYSQL_disconnect(struct ast_channel *chan, const char *data)
+static int aMYSQL_disconnect(struct ast_channel *chan, char *data)
 {
 	MYSQL *mysql;
 	int id;
-	char *parse = ast_strdupa(data);
-	strsep(&parse, " "); /* eat the first token, we already know it :P */
+	strsep(&data, " "); /* eat the first token, we already know it :P */
 
-	id = safe_scan_int(&parse, " \n", -1);
+	id = safe_scan_int(&data, " \n", -1);
 	if ((mysql = find_identifier(id, AST_MYSQL_ID_CONNID)) == NULL) {
 		ast_log(LOG_WARNING, "Invalid connection identifier %d passed in aMYSQL_disconnect\n", id);
 	} else {
@@ -590,19 +575,19 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
 	ast_mutex_lock(&_mysql_mutex);
 
 	if (strncasecmp("connect", data, strlen("connect")) == 0) {
-		result = aMYSQL_connect(chan, data);
+		result = aMYSQL_connect(chan, ast_strdupa(data));
 	} else if (strncasecmp("query", data, strlen("query")) == 0) {
-		result = aMYSQL_query(chan, data);
+		result = aMYSQL_query(chan, ast_strdupa(data));
 	} else if (strncasecmp("nextresult", data, strlen("nextresult")) == 0) {
-		result = aMYSQL_nextresult(chan, data);
+		result = aMYSQL_nextresult(chan, ast_strdupa(data));
 	} else if (strncasecmp("fetch", data, strlen("fetch")) == 0) {
-		result = aMYSQL_fetch(chan, data);
+		result = aMYSQL_fetch(chan, ast_strdupa(data));
 	} else if (strncasecmp("clear", data, strlen("clear")) == 0) {
-		result = aMYSQL_clear(chan, data);
+		result = aMYSQL_clear(chan, ast_strdupa(data));
 	} else if (strncasecmp("disconnect", data, strlen("disconnect")) == 0) {
-		result = aMYSQL_disconnect(chan, data);
+		result = aMYSQL_disconnect(chan, ast_strdupa(data));
 	} else if (strncasecmp("set", data, 3) == 0) {
-		result = aMYSQL_set(chan, data);
+		result = aMYSQL_set(chan, ast_strdupa(data));
 	} else {
 		ast_log(LOG_WARNING, "Unknown argument to MYSQL application : %s\n", data);
 		result = -1;
@@ -620,16 +605,6 @@ static int unload_module(void)
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	struct MYSQLidshead *headp = &_mysql_ids_head;
@@ -664,5 +639,4 @@ static int load_module(void)
 	return ast_register_application(app, MYSQL_exec, synopsis, descrip);
 }
 
-AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Simple Mysql Interface");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Mysql Interface");
diff --git a/addons/app_saycountpl.c b/addons/app_saycountpl.c
new file mode 100644
index 0000000..dce519d
--- /dev/null
+++ b/addons/app_saycountpl.c
@@ -0,0 +1,138 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2004, Andy Powell & TAAN Softworks Corp. 
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Say Polish counting words
+ * \author Andy Powell
+ */
+
+/*** MODULEINFO
+	<defaultenabled>no</defaultenabled>
+	<support_level>deprecated</support_level>
+	<replacement>say.conf</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/app.h"
+
+/*** DOCUMENTATION
+	<application name="SayCountPL" language="en_US">
+		<synopsis>
+			Say Polish counting words.
+		</synopsis>
+		<syntax>
+			<parameter name="word1" required="true" />
+			<parameter name="word2" required="true" />
+			<parameter name="word5" required="true" />
+			<parameter name="number" required="true" />
+		</syntax>
+		<description>
+			<para>Polish grammar has some funny rules for counting words. for example 1 zloty,
+			2 zlote, 5 zlotych. This application will take the words for 1, 2-4 and 5 and
+			decide based on grammar rules which one to use with the number you pass to it.</para>
+			<para>Example: SayCountPL(zloty,zlote,zlotych,122) will give: zlote</para>
+		</description>
+	</application>
+
+ ***/
+static const char app[] = "SayCountPL";
+
+static int saywords(struct ast_channel *chan, char *word1, char *word2, char *word5, int num)
+{
+	/* Put this in a separate proc because it's bound to change */
+	int d = 0;
+
+	if (num > 0) {
+		if (num % 1000 == 1) {
+			ast_streamfile(chan, word1, ast_channel_language(chan));
+			d = ast_waitstream(chan,"");
+		} else if (((num % 10) >= 2) && ((num % 10) <= 4 ) && ((num % 100) < 10 || (num % 100) > 20)) {
+			ast_streamfile(chan, word2, ast_channel_language(chan));
+			d = ast_waitstream(chan, "");
+		} else {
+			ast_streamfile(chan, word5, ast_channel_language(chan));
+			d = ast_waitstream(chan, "");
+		}
+	}
+
+	return d;
+}
+
+
+static int sayword_exec(struct ast_channel *chan, const char *data)
+{
+	int res = 0;
+	char *s;
+	int inum;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(word1);
+		AST_APP_ARG(word2);
+		AST_APP_ARG(word5);
+		AST_APP_ARG(num);
+	);
+
+	if (!data) {
+		ast_log(LOG_WARNING, "SayCountPL requires 4 arguments: word-1,word-2,word-5,number\n");
+		return -1;
+	}
+
+	s = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, s);
+
+	/* Check to see if params passed */
+	if (!args.word1 || !args.word2 || !args.word5 || !args.num) {
+		ast_log(LOG_WARNING, "SayCountPL requires 4 arguments: word-1,word-2,word-3,number\n");
+		return -1;
+	}
+
+	if (sscanf(args.num, "%30d", &inum) != 1) {
+		ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num);
+		return -1;
+	}
+
+	/* do the saying part (after a bit of maths) */
+
+	res = saywords(chan, args.word1, args.word2, args.word5, inum);
+
+	return res;
+}
+
+static int unload_module(void)
+{
+	return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+	int res;
+
+	res = ast_register_application_xml(app, sayword_exec);
+
+	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say polish counting words");
diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c
index e4ba8bf..b87d8c6 100644
--- a/addons/cdr_mysql.c
+++ b/addons/cdr_mysql.c
@@ -42,7 +42,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <mysql/mysql.h>
 #include <mysql/errmsg.h>
@@ -251,7 +251,7 @@ db_reconnect:
 					char timestr[128];
 					ast_localtime(&tv, &tm, ast_str_strlen(cdrzone) ? ast_str_buffer(cdrzone) : NULL);
 					ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
-					value = ast_strdupa(timestr);
+					ast_cdr_setvar(cdr, "calldate", timestr, 0);
 					cdrname = "calldate";
 				} else {
 					cdrname = "start";
@@ -277,11 +277,9 @@ db_reconnect:
 				 strstr(entry->type, "real") ||
 				 strstr(entry->type, "numeric") ||
 				 strstr(entry->type, "fixed"))) {
-				ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 1);
-			} else if (!strcmp(cdrname, "calldate")) {
-				/* Skip calldate - the value has already been dup'd */
+				ast_cdr_getvar(cdr, cdrname, &value, workspace, sizeof(workspace), 0, 1);
 			} else {
-				ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 0);
+				ast_cdr_getvar(cdr, cdrname, &value, workspace, sizeof(workspace), 0, 0);
 			}
 
 			if (value) {
@@ -384,11 +382,9 @@ static int my_unload_module(int reload)
 	}
 
 	dbport = 0;
-	if (reload) {
-		return ast_cdr_backend_suspend(name);
-	} else {
-		return ast_cdr_unregister(name);
-	}
+	ast_cdr_unregister(name);
+	
+	return 0;
 }
 
 static int my_load_config_string(struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
@@ -662,11 +658,7 @@ static int my_load_module(int reload)
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (!reload) {
-		res = ast_cdr_register(name, desc, mysql_log);
-	} else {
-		res = ast_cdr_backend_unsuspend(name);
-	}
+	res = ast_cdr_register(name, desc, mysql_log);
 	if (res) {
 		ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
 	} else {
@@ -698,7 +690,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MySQL CDR Backend",
-	.support_level = AST_MODULE_SUPPORT_DEPRECATED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c
index 020cd21..3feec92 100644
--- a/addons/chan_mobile.c
+++ b/addons/chan_mobile.c
@@ -25,15 +25,6 @@
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_mobile.c uses the configuration file \ref chan_mobile.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page chan_mobile.conf chan_mobile.conf
- * \verbinclude chan_mobile.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>bluetooth</depend>
 	<defaultenabled>no</defaultenabled>
@@ -42,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427611 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <pthread.h>
 #include <signal.h>
@@ -73,16 +64,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427611 $")
 #include "asterisk/app.h"
 #include "asterisk/manager.h"
 #include "asterisk/io.h"
-#include "asterisk/smoother.h"
-#include "asterisk/format_cache.h"
 
 #define MBL_CONFIG "chan_mobile.conf"
 #define MBL_CONFIG_OLD "mobile.conf"
 
 #define DEVICE_FRAME_SIZE 48
-#define DEVICE_FRAME_FORMAT ast_format_slin
+#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR
 #define CHANNEL_FRAME_SIZE 320
 
+static struct ast_format prefformat;
+
 static int discovery_interval = 60;			/* The device discovery interval, default 60 seconds. */
 static pthread_t discovery_thread = AST_PTHREADT_NULL;	/* The discovery thread */
 static sdp_session_t *sdp_session;
@@ -147,7 +138,6 @@ struct mbl_pvt {
 	int ring_sched_id;
 	struct ast_dsp *dsp;
 	struct ast_sched_context *sched;
-	int hangupcause;
 
 	/* flags */
 	unsigned int outgoing:1;	/*!< outgoing call */
@@ -173,9 +163,6 @@ static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
-static int handle_response_busy(struct mbl_pvt *pvt);
-static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
-static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
 static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
 
 /* CLI stuff */
@@ -209,9 +196,9 @@ static char *mblsendsms_desc =
 "  Message - text of the message\n";
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
+		const struct ast_channel *requestor);
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
-		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+		const struct ast_channel *requestor, const char *data, int *cause);
 static int mbl_call(struct ast_channel *ast, const char *dest, int timeout);
 static int mbl_hangup(struct ast_channel *ast);
 static int mbl_answer(struct ast_channel *ast);
@@ -345,7 +332,6 @@ struct hfp_pvt {
 	struct hfp_cind cind_map;	/*!< the cind name to index mapping for this AG */
 	int rsock;			/*!< our rfcomm socket */
 	int rport;			/*!< our rfcomm port */
-	int sent_alerting;		/*!< have we sent alerting? */
 };
 
 
@@ -440,10 +426,6 @@ typedef enum {
 	AT_CMER,
 	AT_CIND_TEST,
 	AT_CUSD,
-	AT_BUSY,
-	AT_NO_DIALTONE,
-	AT_NO_CARRIER,
-	AT_ECAM,
 } at_message_t;
 
 static int at_match_prefix(char *buf, char *prefix);
@@ -838,8 +820,9 @@ e_return:
 */
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+		const struct ast_channel *requestor)
 {
+
 	struct ast_channel *chn;
 
 	pvt->answered = 0;
@@ -854,18 +837,18 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num
 	ast_dsp_digitreset(pvt->dsp);
 
 	chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,
-			assignedids, requestor, 0,
+			requestor ? ast_channel_linkedid(requestor) : "", 0,
 			"Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
 	if (!chn) {
 		goto e_return;
 	}
 
 	ast_channel_tech_set(chn, &mbl_tech);
-	ast_channel_nativeformats_set(chn, mbl_tech.capabilities);
-	ast_channel_set_rawreadformat(chn, DEVICE_FRAME_FORMAT);
-	ast_channel_set_rawwriteformat(chn, DEVICE_FRAME_FORMAT);
-	ast_channel_set_writeformat(chn, DEVICE_FRAME_FORMAT);
-	ast_channel_set_readformat(chn, DEVICE_FRAME_FORMAT);
+	ast_format_cap_add(ast_channel_nativeformats(chn), &prefformat);
+	ast_format_copy(ast_channel_rawreadformat(chn), &prefformat);
+	ast_format_copy(ast_channel_rawwriteformat(chn), &prefformat);
+	ast_format_copy(ast_channel_writeformat(chn), &prefformat);
+	ast_format_copy(ast_channel_readformat(chn), &prefformat);
 	ast_channel_tech_pvt_set(chn, pvt);
 
 	if (state == AST_STATE_RING)
@@ -877,7 +860,6 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num
 	if (pvt->sco_socket != -1) {
 		ast_channel_set_fd(chn, 0, pvt->sco_socket);
 	}
-	ast_channel_unlock(chn);
 
 	return chn;
 
@@ -886,7 +868,7 @@ e_return:
 }
 
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
-		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+		const struct ast_channel *requestor, const char *data, int *cause)
 {
 
 	struct ast_channel *chn = NULL;
@@ -901,9 +883,9 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *
 		return NULL;
 	}
 
-	if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
+	if (!(ast_format_cap_iscompatible(cap, &prefformat))) {
+		char tmp[256];
+		ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 		*cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
 		return NULL;
 	}
@@ -945,7 +927,7 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *
 	}
 
 	ast_mutex_lock(&pvt->lock);
-	chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
+	chn = mbl_new(AST_STATE_DOWN, pvt, NULL, requestor);
 	ast_mutex_unlock(&pvt->lock);
 	if (!chn) {
 		ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
@@ -990,7 +972,6 @@ static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
 			ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
 			return -1;
 		}
-		pvt->hangupcause = 0;
 		pvt->needchup = 1;
 		msg_queue_push(pvt, AT_OK, AT_D);
 	} else {
@@ -1115,7 +1096,7 @@ static struct ast_frame *mbl_read(struct ast_channel *ast)
 
 	memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
 	pvt->fr.frametype = AST_FRAME_VOICE;
-	pvt->fr.subclass.format = DEVICE_FRAME_FORMAT;
+	ast_format_set(&pvt->fr.subclass.format, DEVICE_FRAME_FORMAT, 0);
 	pvt->fr.src = "Mobile";
 	pvt->fr.offset = AST_FRIENDLY_OFFSET;
 	pvt->fr.mallocd = 0;
@@ -1324,9 +1305,6 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
 			if (ast_channel_trylock(pvt->owner)) {
 				DEADLOCK_AVOIDANCE(&pvt->lock);
 			} else {
-				if (pvt->hangupcause != 0) {
-					ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause);
-				}
 				ast_queue_hangup(pvt->owner);
 				ast_channel_unlock(pvt->owner);
 				break;
@@ -1339,7 +1317,9 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
 
 static int mbl_ast_hangup(struct mbl_pvt *pvt)
 {
-	ast_hangup(pvt->owner);
+	if (pvt->owner) {
+		ast_hangup(pvt->owner);
+	}
 	return 0;
 }
 
@@ -1544,8 +1524,8 @@ static int rfcomm_read_and_append_char(int rsock, char **buf, size_t count, size
 }
 
 /*!
- * \brief Read until \verbatim '\r\n'. \endverbatim
- * This function consumes the \verbatim'\r\n'\endverbatim but does not add it to buf.
+ * \brief Read until '\r\n'.
+ * This function consumes the '\r\n' but does not add it to buf.
  */
 static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1572,7 +1552,7 @@ static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *i
 
 /*!
  * \brief Read the remainder of an AT SMS prompt.
- * \note the entire parsed string is \verbatim '\r\n> ' \endverbatim
+ * \note the entire parsed string is '\r\n> '
  *
  * By the time this function is executed, only a ' ' is left to read.
  */
@@ -1590,7 +1570,7 @@ e_return:
 }
 
 /*!
- * \brief Read until a \verbatim \r\nOK\r\n \endverbatim message.
+ * \brief Read until a \r\nOK\r\n message.
  */
 static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1687,7 +1667,7 @@ static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_
 
 /*!
  * \brief Read the remainder of a +CMGR message.
- * \note the entire parsed string is \verbatim '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n' \endverbatim
+ * \note the entire parsed string is '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n'
  */
 static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1706,7 +1686,7 @@ static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_coun
 
 /*!
  * \brief Read and AT result code.
- * \note the entire parsed string is \verbatim '\r\n<result code>\r\n' \endverbatim
+ * \note the entire parsed string is '\r\n<result code>\r\n'
  */
 static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1744,7 +1724,7 @@ e_return:
 
 /*!
  * \brief Read the remainder of an AT command.
- * \note the entire parsed string is \verbatim '<at command>\r' \endverbatim
+ * \note the entire parsed string is '<at command>\r'
  */
 static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1778,8 +1758,8 @@ static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_c
  * \endverbatim
  *
  * These formats correspond to AT result codes, AT commands, and the AT SMS
- * prompt respectively.  When messages are read the leading and trailing \verbatim '\r' \endverbatim
- * and \verbatim '\n' \endverbatim characters are discarded.  If the given buffer is not large enough
+ * prompt respectively.  When messages are read the leading and trailing '\r'
+ * and '\n' characters are discarded.  If the given buffer is not large enough
  * to hold the response, what does not fit in the buffer will be dropped.
  *
  * \note The rfcomm connection to the device is asynchronous, so there is no
@@ -2041,14 +2021,6 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count)
 		return AT_VGS;
 	} else if (at_match_prefix(buf, "+CUSD:")) {
 		return AT_CUSD;
-	} else if (at_match_prefix(buf, "BUSY")) {
-		return AT_BUSY;
-	} else if (at_match_prefix(buf, "NO DIALTONE")) {
-		return AT_NO_DIALTONE;
-	} else if (at_match_prefix(buf, "NO CARRIER")) {
-		return AT_NO_CARRIER;
-	} else if (at_match_prefix(buf, "*ECAV:")) {
-		return AT_ECAM;
 	} else {
 		return AT_UNKNOWN;
 	}
@@ -2093,12 +2065,6 @@ static inline const char *at_msg2str(at_message_t msg)
 		return "SMS PROMPT";
 	case AT_CMS_ERROR:
 		return "+CMS ERROR";
-	case AT_BUSY:
-		return "BUSY";
-	case AT_NO_DIALTONE:
-		return "NO DIALTONE";
-	case AT_NO_CARRIER:
-		return "NO CARRIER";
 	/* at commands */
 	case AT_A:
 		return "ATA";
@@ -2126,8 +2092,6 @@ static inline const char *at_msg2str(at_message_t msg)
 		return "AT+CIND=?";
 	case AT_CUSD:
 		return "AT+CUSD";
-	case AT_ECAM:
-		return "AT*ECAM";
 	}
 }
 
@@ -2136,40 +2100,6 @@ static inline const char *at_msg2str(at_message_t msg)
  * bluetooth handsfree profile helpers
  */
 
- /*!
- * \brief Parse a ECAV event.
- * \param hfp an hfp_pvt struct
- * \param buf the buffer to parse (null terminated)
- * \return -1 on error (parse error) or a ECAM value on success
- *
- * Example string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
- * [,exitcause][,<number>,<type>]
- *
- * Example indicating busy: *ECAV: 1,7,1
- */
-static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
-{
-	int ccid = 0;
-	int ccstatus = 0;
-	int calltype = 0;
-
-	if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
-		ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
-		return -1;
-	}
-
-	return ccstatus;
-}
-
-/*!
- * \brief Enable Sony Erricson extensions / indications.
- * \param hfp an hfp_pvt struct
- */
-static int hfp_send_ecam(struct hfp_pvt *hfp)
-{
-	return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
-}
-
 /*!
  * \brief Parse a CIEV event.
  * \param hfp an hfp_pvt struct
@@ -2202,7 +2132,7 @@ static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
  * \brief Parse a CLIP event.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * \note buf will be modified when the CID string is parsed
+ * @note buf will be modified when the CID string is parsed
  * \return NULL on error (parse error) or a pointer to the caller id
  * information in buf
  */
@@ -2248,7 +2178,7 @@ static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
  * \brief Parse a CMTI notification.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * \note buf will be modified when the CMTI message is parsed
+ * @note buf will be modified when the CMTI message is parsed
  * \return -1 on error (parse error) or the index of the new sms message
  */
 static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
@@ -2273,7 +2203,7 @@ static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
  * \param from_number a pointer to a char pointer which will store the from
  * number
  * \param text a pointer to a char pointer which will store the message text
- * \note buf will be modified when the CMGR message is parsed
+ * @note buf will be modified when the CMGR message is parsed
  * \retval -1 parse error
  * \retval 0 success
  */
@@ -2337,7 +2267,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
  * \brief Parse a CUSD answer.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * \note buf will be modified when the CUSD string is parsed
+ * @note buf will be modified when the CUSD string is parsed
  * \return NULL on error (parse error) or a pointer to the cusd message
  * information in buf
  */
@@ -3276,14 +3206,6 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
 			break;
 		case AT_CLIP:
 			ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
-			if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
-				ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
-				goto e_return;
-			}
-
-			break;
-		case AT_ECAM:
-			ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
 			if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
 				ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
 				goto e_return;
@@ -3415,21 +3337,6 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
 			ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
 			ast_debug(1, "[%s] no SMS support\n", pvt->id);
 			break;
-		case AT_ECAM:
-			ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
-
-			/* this is not a fatal error, let's continue with the initialization */
-
-			if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
-				ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
-				goto e_return;
-			}
-
-			pvt->timeout = -1;
-			pvt->hfp->initialized = 1;
-			ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
-
-			break;
 		/* end initialization stuff */
 
 		case AT_A:
@@ -3525,9 +3432,6 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
 		case HFP_CIND_CALLSETUP_NONE:
 			if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
 				if (pvt->owner) {
-					if (pvt->hfp->sent_alerting == 1) {
-						handle_response_busy(pvt);
-					}
 					if (mbl_queue_hangup(pvt)) {
 						ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
 						return -1;
@@ -3546,7 +3450,6 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
 			break;
 		case HFP_CIND_CALLSETUP_OUTGOING:
 			if (pvt->outgoing) {
-				pvt->hfp->sent_alerting = 0;
 				ast_debug(1, "[%s] outgoing call\n", pvt->id);
 			} else {
 				ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
@@ -3557,7 +3460,6 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
 			if (pvt->outgoing) {
 				ast_debug(1, "[%s] remote alerting\n", pvt->id);
 				mbl_queue_control(pvt, AST_CONTROL_RINGING);
-				pvt->hfp->sent_alerting = 1;
 			}
 			break;
 		}
@@ -3590,7 +3492,7 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
 			ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
 		}
 
-		if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL, NULL))) {
+		if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL))) {
 			ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
 			hfp_send_chup(pvt->hfp);
 			msg_queue_push(pvt, AT_OK, AT_CHUP);
@@ -3680,7 +3582,7 @@ static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
 		pvt->incoming_sms = 0;
 
 		/* XXX this channel probably does not need to be associated with this pvt */
-		if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
+		if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL))) {
 			ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
 			return -1;
 		}
@@ -3752,50 +3654,6 @@ static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
 	return 0;
 }
 
-/*!
- * \brief Handle BUSY messages.
- * \param pvt a mbl_pvt structure
- * \retval 0 success
- * \retval -1 error
- */
-static int handle_response_busy(struct mbl_pvt *pvt)
-{
-	pvt->hangupcause = AST_CAUSE_USER_BUSY;
-	pvt->needchup = 1;
-	mbl_queue_control(pvt, AST_CONTROL_BUSY);
-	return 0;
-}
-
-/*!
- * \brief Handle NO DIALTONE messages.
- * \param pvt a mbl_pvt structure
- * \param buf a null terminated buffer containing an AT message
- * \retval 0 success
- * \retval -1 error
- */
-static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
-{
-	ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
-	pvt->needchup = 1;
-	mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
-	return 0;
-}
-
-/*!
- * \brief Handle NO CARRIER messages.
- * \param pvt a mbl_pvt structure
- * \param buf a null terminated buffer containing an AT message
- * \retval 0 success
- * \retval -1 error
- */
-static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
-{
-	ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
-	pvt->needchup = 1;
-	mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
-	return 0;
-}
-
 
 static void *do_monitor_phone(void *data)
 {
@@ -3954,40 +3812,6 @@ static void *do_monitor_phone(void *data)
 			}
 			ast_mutex_unlock(&pvt->lock);
 			break;
-		case AT_BUSY:
-			ast_mutex_lock(&pvt->lock);
-			if (handle_response_busy(pvt)) {
-				ast_mutex_unlock(&pvt->lock);
-				goto e_cleanup;
-			}
-			ast_mutex_unlock(&pvt->lock);
-			break;
-		case AT_NO_DIALTONE:
-			ast_mutex_lock(&pvt->lock);
-			if (handle_response_no_dialtone(pvt, buf)) {
-				ast_mutex_unlock(&pvt->lock);
-				goto e_cleanup;
-			}
-			ast_mutex_unlock(&pvt->lock);
-			break;
-		case AT_NO_CARRIER:
-			ast_mutex_lock(&pvt->lock);
-			if (handle_response_no_carrier(pvt, buf)) {
-				ast_mutex_unlock(&pvt->lock);
-				goto e_cleanup;
-			}
-			ast_mutex_unlock(&pvt->lock);
-			break;
-		case AT_ECAM:
-			ast_mutex_lock(&pvt->lock);
-			if (hfp_parse_ecav(hfp, buf) == 7) {
-				if (handle_response_busy(pvt)) {
-					ast_mutex_unlock(&pvt->lock);
-					goto e_cleanup;
-				}
-			}
-			ast_mutex_unlock(&pvt->lock);
-			break;
 		case AT_UNKNOWN:
 			ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
 			break;
@@ -4139,7 +3963,7 @@ static void *do_monitor_headset(void *data)
 
 				pvt->incoming = 1;
 
-				if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
+				if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL))) {
 					ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
 					ast_mutex_unlock(&pvt->lock);
 					goto e_cleanup;
@@ -4696,8 +4520,7 @@ static int unload_module(void)
 	if (sdp_session)
 		sdp_close(sdp_session);
 
-	ao2_ref(mbl_tech.capabilities, -1);
-	mbl_tech.capabilities = NULL;
+	mbl_tech.capabilities = ast_format_cap_destroy(mbl_tech.capabilities);
 	return 0;
 }
 
@@ -4706,11 +4529,11 @@ static int load_module(void)
 
 	int dev_id, s;
 
-	if (!(mbl_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(mbl_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-
-	ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0);
+	ast_format_set(&prefformat, DEVICE_FRAME_FORMAT, 0);
+	ast_format_cap_add(mbl_tech.capabilities, &prefformat);
 	/* Check if we have Bluetooth, no point loading otherwise... */
 	dev_id = hci_get_route(NULL);
 	s = hci_open_dev(dev_id);
@@ -4754,7 +4577,6 @@ e_cleanup:
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c
index 6268ad0..4297abd 100644
--- a/addons/chan_ooh323.c
+++ b/addons/chan_ooh323.c
@@ -23,6 +23,7 @@
  ***/
 
 #include "chan_ooh323.h"
+#include "asterisk/paths.h"
 #include <math.h>
 
 #define FORMAT_STRING_SIZE	512
@@ -30,7 +31,7 @@
 /* Defaults */
 #define DEFAULT_CONTEXT "default"
 #define DEFAULT_H323ID "Asterisk PBX"
-#define DEFAULT_LOGFILE "/var/log/asterisk/h323_log"
+#define DEFAULT_LOGFILE "h323_log"
 #define DEFAULT_H323ACCNT "ast_h323"
 
 /* Flags */
@@ -71,7 +72,7 @@ static struct ast_jb_conf global_jbconf;
 
 /* Channel Definition */
 static struct ast_channel *ooh323_request(const char *type, struct ast_format_cap *cap,
-			const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,  const char *data, int *cause);
+			const struct ast_channel *requestor,  const char *data, int *cause);
 static int ooh323_digit_begin(struct ast_channel *ast, char digit);
 static int ooh323_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int ooh323_call(struct ast_channel *ast, const char *dest, int timeout);
@@ -92,6 +93,11 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
 static void ooh323_get_codec(struct ast_channel *chan, struct ast_format_cap *result);
 void setup_rtp_remote(ooCallData *call, const char *remoteIp, int remotePort);
 
+static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan);
+static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
+
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
+
 struct ooh323_peer *find_friend(const char *name, int port);
 
 
@@ -112,6 +118,7 @@ static struct ast_channel_tech ooh323_tech = {
 	.fixup = ooh323_fixup,
 	.send_html = 0,
 	.queryoption = ooh323_queryoption,
+	.bridge = ast_rtp_instance_bridge,		/* XXX chan unlocked ? */
 	.early_bridge = ast_rtp_instance_early_bridge,
 	.func_channel_read = function_ooh323_read,
 	.func_channel_write = function_ooh323_write,
@@ -125,6 +132,13 @@ static struct ast_rtp_glue ooh323_rtp = {
 	.get_codec = ooh323_get_codec,
 };
 
+static struct ast_udptl_protocol ooh323_udptl = {
+	.type = "H323",
+	.get_udptl_info = ooh323_get_udptl_peer,
+	.set_udptl_peer = ooh323_set_udptl_peer,
+};
+
+
 
 struct ooh323_user;
 
@@ -172,9 +186,10 @@ static struct ooh323_pvt {
 	char callee_url[AST_MAX_EXTENSION];
  
 	int port;
-	struct ast_format *readformat;   /* negotiated read format */
-	struct ast_format *writeformat;  /* negotiated write format */
+	struct ast_format readformat;   /* negotiated read format */
+	struct ast_format writeformat;  /* negotiated write format */
 	struct ast_format_cap *cap;
+	struct ast_codec_pref prefs;
 	int dtmfmode;
 	int dtmfcodec;
 	char exten[AST_MAX_EXTENSION];	/* Requested extension */
@@ -192,7 +207,6 @@ static struct ooh323_pvt {
 	char rtpmaskstr[120];
 	int rtdrcount, rtdrinterval;	/* roundtripdelayreq */
 	int faststart, h245tunneling;	/* faststart & h245 tunneling */
-	int aniasdni;			/* use dialed number as answering identification */
 	struct ooh323_pvt *next;	/* Next entity */
 } *iflist = NULL;
 
@@ -209,6 +223,7 @@ struct ooh323_user{
 	char		accountcode[20];
 	int		amaflags;
 	struct ast_format_cap *cap;
+	struct ast_codec_pref prefs;
 	int		dtmfmode;
 	int		dtmfcodec;
 	int		faxdetect;
@@ -224,7 +239,6 @@ struct ooh323_user{
 	int		directrtp;
 	int		earlydirect;
 	int		g729onlyA;
-	int		aniasdni;
 	struct ooh323_user *next;
 };
 
@@ -235,6 +249,7 @@ struct ooh323_peer{
 	unsigned    outgoinglimit;
 	unsigned    outUse;
 	struct ast_format_cap *cap;
+	struct ast_codec_pref prefs;
 	char        accountcode[20];
 	int         amaflags;
 	int         dtmfmode;
@@ -302,6 +317,7 @@ int v6mode = 0;
 static char gCallerID[AST_MAX_EXTENSION] = "";
 static struct ooAliases *gAliasList;
 static struct ast_format_cap *gCap;
+static struct ast_codec_pref gPrefs;
 static int  gDTMFMode = H323_DTMF_RFC2833;
 static int  gDTMFCodec = 101;
 static int  gFAXdetect = FAXDETECT_CNG;
@@ -328,7 +344,6 @@ OOBOOL gH323Debug = FALSE;
 static int gTRCLVL = OOTRCLVLERR;
 static int gRTDRCount = 0, gRTDRInterval = 0;
 static int gNat = FALSE;
-static int gANIasDNI = 0;
 
 static int t35countrycode = 0;
 static int t35extensions = 0;
@@ -357,50 +372,40 @@ static pthread_t monitor_thread = AST_PTHREADT_NULL;
 
 
 static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
-                                             const char *host, struct ast_format_cap *cap, 
-											 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+                                             const char *host, struct ast_format_cap *cap, const char *linkedid)
 {
-	struct ast_format_cap *caps = NULL;
 	struct ast_channel *ch = NULL;
-	struct ast_format *tmpfmt = NULL;
+	struct ast_format tmpfmt;
 	int features = 0;
 
 	if (gH323Debug) {
 		ast_verb(0, "---   ooh323_new - %s\n", host);
 	}
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-
+	ast_format_clear(&tmpfmt);
 	/* Don't hold a h323 pvt lock while we allocate a channel */
 	ast_mutex_unlock(&i->lock);
    	ast_mutex_lock(&ooh323c_cn_lock);
    	ch = ast_channel_alloc(1, state, i->callerid_num, i->callerid_name, 
-				i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags,
+				i->accountcode, i->exten, i->context, linkedid, i->amaflags,
 				"OOH323/%s-%ld", host, callnumber);
    	callnumber++;
    	ast_mutex_unlock(&ooh323c_cn_lock);
    
 	ast_mutex_lock(&i->lock);
 
-	if (ch && caps) {
+	if (ch) {
+		ast_channel_lock(ch);
 		ast_channel_tech_set(ch, &ooh323_tech);
 
-		if (cap) {
-			tmpfmt = ast_format_cap_get_format(cap, 0);
-		}
-		if (!tmpfmt) {
-			tmpfmt = ast_format_cap_get_format(i->cap, 0);
-		}
-
-		ast_format_cap_append(caps, tmpfmt, 0);
-		ast_channel_nativeformats_set(ch, caps);
-		ao2_ref(caps, -1);
+		if (cap)
+			ast_best_codec(cap, &tmpfmt);
+		if (!tmpfmt.id)
+			ast_codec_pref_index(&i->prefs, 0, &tmpfmt);
 
-		ast_channel_set_rawwriteformat(ch, tmpfmt);
-		ast_channel_set_rawreadformat(ch, tmpfmt);
-		ast_set_write_format(ch, tmpfmt);
-		ast_set_read_format(ch, tmpfmt);
-		ao2_ref(tmpfmt, -1);
+		ast_format_cap_add(ast_channel_nativeformats(ch), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(ch), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(ch), &tmpfmt);
 
 		ast_jb_configure(ch, &global_jbconf);
 
@@ -408,6 +413,8 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
 			ast_channel_rings_set(ch, 1);
 
 		ast_channel_adsicpe_set(ch, AST_ADSI_UNAVAILABLE);
+		ast_set_write_format(ch, &tmpfmt);
+		ast_set_read_format(ch, &tmpfmt);
 		ast_channel_tech_pvt_set(ch, i);
 		i->owner = ch;
 		ast_module_ref(myself);
@@ -484,13 +491,12 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
 	 	}
 
 		if (ch) {
-			ast_publish_channel_state(ch);
-
+			manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", 
+				"Channel: %s\r\nChanneltype: %s\r\n"
+				"CallRef: %u\r\n", ast_channel_name(ch), "OOH323", i->call_reference);
 		}
-	} else {
-		ao2_cleanup(caps);
+	} else
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
-	}
 
 
    	if(ch)   ast_channel_unlock(ch);
@@ -516,7 +522,7 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
 		ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n");
 		return NULL;
 	}
-	if (!(pvt->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(pvt->cap = ast_format_cap_alloc_nolock())) {
 		ast_free(pvt);
 		ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n");
 		return NULL;
@@ -550,9 +556,8 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
 	ast_copy_string(pvt->accountcode, gAccountcode, sizeof(pvt->accountcode));
 
 	pvt->amaflags = gAMAFLAGS;
-	ast_format_cap_append_from_cap(pvt->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
-
-	pvt->aniasdni = gANIasDNI;
+	ast_format_cap_copy(pvt->cap, gCap);
+	memcpy(&pvt->prefs, &gPrefs, sizeof(pvt->prefs));
 
 	ast_mutex_unlock(&pvt->lock); 
 	/* Add to interface list */
@@ -573,24 +578,24 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
 	Possible data values - peername, exten/peername, exten at ip
  */
 static struct ast_channel *ooh323_request(const char *type, struct ast_format_cap *cap,
-		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+		const struct ast_channel *requestor, const char *data, int *cause)
 
 {
-	struct ast_str *codec_buf = ast_str_alloca(64);
 	struct ast_channel *chan = NULL;
 	struct ooh323_pvt *p = NULL;
 	struct ooh323_peer *peer = NULL;
 	char *dest = NULL; 
 	char *ext = NULL;
 	char tmp[256];
+	char formats[FORMAT_STRING_SIZE];
 	int port = 0;
 
-	if (gH323Debug) {
-		ast_verb(0, "---   ooh323_request - data %s format %s\n", data, ast_format_cap_get_names(cap, &codec_buf));
-	}
+	if (gH323Debug)
+		ast_verb(0, "---   ooh323_request - data %s format %s\n", data,
+										ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
 
-	if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) {
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
+	if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
 		return NULL;
 	}
 
@@ -654,7 +659,8 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
 		if (ext)
 			ast_copy_string(p->exten, ext, sizeof(p->exten));
 
-		ast_format_cap_append_from_cap(p->cap, peer->cap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(p->cap, peer->cap);
+		memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref));
 		p->g729onlyA = peer->g729onlyA;
 		p->dtmfmode |= peer->dtmfmode;
 		p->dtmfcodec  = peer->dtmfcodec;
@@ -699,7 +705,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
 		p->t38support = gT38Support;
 		p->rtptimeout = gRTPTimeout;
 		p->nat = gNat;
-		ast_format_cap_append_from_cap(p->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(p->cap, gCap);
 		p->rtdrinterval = gRTDRInterval;
 		p->rtdrcount = gRTDRCount;
 		p->faststart = gFastStart;
@@ -707,6 +713,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
 		p->directrtp = gDirectRTP;
 		p->earlydirect = gEarlyDirect;
 
+		memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref));
 		p->username = strdup(dest);
 
 		p->host = strdup(dest);
@@ -720,7 +727,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca
 
 
 	chan = ooh323_new(p, AST_STATE_DOWN, p->username, cap,
-				 assignedids, requestor);
+				 requestor ? ast_channel_linkedid(requestor) : NULL);
 	
 	ast_mutex_unlock(&p->lock);
 
@@ -1165,6 +1172,7 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
 {
 	struct ooh323_pvt *p = ast_channel_tech_pvt(ast);
 	int res = 0;
+	char buf[256];
 
 	if (p) {
 		ast_mutex_lock(&p->lock);
@@ -1190,17 +1198,16 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
 			}
 
 
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-				if (ast_format_cap_count(ast_channel_nativeformats(ast))) {
-					struct ast_str *codec_buf = ast_str_alloca(64);
+			if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
+				if (!(ast_format_cap_is_empty(ast_channel_nativeformats(ast)))) {
 					ast_log(LOG_WARNING,
 							"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
-							ast_format_get_name(f->subclass.format),
-							ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
-							ast_format_get_name(ast_channel_readformat(ast)),
-							ast_format_get_name(ast_channel_writeformat(ast)));
+							ast_getformatname(&f->subclass.format),
+							ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+							ast_getformatname(ast_channel_readformat(ast)),
+							ast_getformatname(ast_channel_writeformat(ast)));
 
-					ast_set_write_format(ast, f->subclass.format);
+					ast_set_write_format(ast, &f->subclass.format);
 				} else {
 					/* ast_set_write_format(ast, f->subclass);
 					ast->nativeformats = f->subclass; */
@@ -1396,7 +1403,6 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
 		break;
 	case AST_CONTROL_PROCEEDING:
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 	case -1:
 		break;
 	default:
@@ -1510,10 +1516,11 @@ static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
 void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txframes)
 {
 	struct ooh323_pvt *p = NULL;
+	char formats[FORMAT_STRING_SIZE];
 
 	if (gH323Debug)
 		ast_verb(0, "---   ooh323_update_writeformat %s/%d\n", 
-				ast_format_get_name(fmt), txframes);
+				ast_getformatname(fmt), txframes);
 	
 	p = find_call(call);
 	if (!p) {
@@ -1523,17 +1530,9 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
 
 	ast_mutex_lock(&p->lock);
 
-	ao2_replace(p->writeformat, fmt);
+	ast_format_copy(&(p->writeformat), fmt);
 
 	if (p->owner) {
-		struct ast_format_cap *caps;
-
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (!caps) {
-			ast_log(LOG_ERROR, "Could not allocate capabilities structure\n");
-			return;
-		}
-
 		while (p->owner && ast_channel_trylock(p->owner)) {
 			ast_debug(1,"Failed to grab lock, trying again\n");
 			DEADLOCK_AVOIDANCE(&p->lock);
@@ -1541,16 +1540,15 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
 		if (!p->owner) {
 			ast_mutex_unlock(&p->lock);
 			ast_log(LOG_ERROR, "Channel has no owner\n");
-			ao2_ref(caps, -1);
 			return;
 		}
-		if (gH323Debug) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
-			ast_verb(0, "Writeformat before update %s/%s\n", 
-			  ast_format_get_name(ast_channel_writeformat(p->owner)),
-			  ast_format_cap_get_names(ast_channel_nativeformats(p->owner), &codec_buf));
-		}
-
+		if (gH323Debug)
+	  		ast_verb(0, "Writeformat before update %s/%s\n", 
+			  ast_getformatname(ast_channel_writeformat(p->owner)),
+			  ast_getformatname_multiple(formats, sizeof(formats), ast_channel_nativeformats(p->owner)));
+		if (txframes)
+			ast_codec_pref_setsize(&p->prefs, fmt, txframes);
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
 		if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
 			ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp),
 				 p->rtp, p->dtmfcodec, "audio", "telephone-event", 0);
@@ -1560,12 +1558,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
 				 p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0);
 		}
 
-		if (txframes) {
-			ast_format_cap_set_framing(caps, txframes);
-		}
-		ast_format_cap_append(caps, fmt, 0);
-		ast_channel_nativeformats_set(p->owner, caps);
-		ao2_ref(caps, -1);
+		ast_format_cap_set(ast_channel_nativeformats(p->owner), fmt);
 	  	ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
 	  	ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
 		ast_channel_unlock(p->owner);
@@ -1585,7 +1578,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
 
 	if (gH323Debug)
 		ast_verb(0, "---   ooh323_update_readformat %s\n", 
-				ast_format_get_name(fmt));
+				ast_getformatname(fmt));
 	
 	p = find_call(call);
 	if (!p) {
@@ -1595,17 +1588,9 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
 
 	ast_mutex_lock(&p->lock);
 
-	ao2_replace(p->readformat, fmt);
+	ast_format_copy(&(p->readformat), fmt);
 
 	if (p->owner) {
-		struct ast_format_cap *caps;
-
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (!caps) {
-			ast_log(LOG_ERROR, "Could not allocate capabilities structure\n");
-			return;
-		}
-
 		while (p->owner && ast_channel_trylock(p->owner)) {
 			ast_debug(1,"Failed to grab lock, trying again\n");
 			DEADLOCK_AVOIDANCE(&p->lock);
@@ -1613,18 +1598,14 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
 		if (!p->owner) {
 			ast_mutex_unlock(&p->lock);
 			ast_log(LOG_ERROR, "Channel has no owner\n");
-			ao2_ref(caps, -1);
 			return;
 		}
 
-		if (gH323Debug) {
-			ast_verb(0, "Readformat before update %s\n", 
-			  ast_format_get_name(ast_channel_readformat(p->owner)));
-		}
-		ast_format_cap_append(caps, fmt, 0);
-		ast_channel_nativeformats_set(p->owner, caps);
-		ao2_ref(caps, -1);
-		ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
+		if (gH323Debug)
+	  		ast_verb(0, "Readformat before update %s\n", 
+				  ast_getformatname(ast_channel_readformat(p->owner)));
+		ast_format_cap_set(ast_channel_nativeformats(p->owner), fmt);
+	  	ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
 		ast_channel_unlock(p->owner);
    	} else
 		ast_log(LOG_ERROR, "No owner found\n");
@@ -1881,8 +1862,9 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 		ast_copy_string(p->context, user->context, sizeof(p->context));
 		ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode));
 		p->amaflags = user->amaflags;
-		ast_format_cap_append_from_cap(p->cap, user->cap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(p->cap, user->cap);
 		p->g729onlyA = user->g729onlyA;
+		memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
 		p->dtmfmode |= user->dtmfmode;
 		p->dtmfcodec = user->dtmfcodec;
 		p->faxdetect = user->faxdetect;
@@ -1914,9 +1896,6 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 			p->rtdrcount = user->rtdrcount;
 			p->rtdrinterval = user->rtdrinterval;
 		}
-
-		p->aniasdni = user->aniasdni;
-
 	 	if (user->incominglimit) user->inUse++;
 		ast_mutex_unlock(&user->lock);
 	} else {
@@ -1940,19 +1919,15 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
 	 }
 	}
 
-	ooh323c_set_capability_for_call(call, p->cap, p->dtmfmode, p->dtmfcodec,
+	ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec,
 					 p->t38support, p->g729onlyA);
 /* Incoming call */
-  	c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL, NULL);
+  	c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL);
   	if(!c) {
    	ast_mutex_unlock(&p->lock);
    	ast_log(LOG_ERROR, "Could not create ast_channel\n");
          return -1;
   	}
-
-	if (p->aniasdni) {
-		ooCallSetCallerId(call, p->exten);
-	}
 	if (!configure_local_rtp(p, call)) {
 		ast_mutex_unlock(&p->lock);
 		ast_log(LOG_ERROR, "Couldn't create rtp structure\n");
@@ -2114,14 +2089,13 @@ int onNewCallCreated(ooCallData *call)
 		}
 
 		if (gH323Debug) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
-
+			char prefsBuf[256];
+			ast_codec_pref_string(&p->prefs, prefsBuf, sizeof(prefsBuf));
 			ast_verb(0, " Outgoing call %s(%s) - Codec prefs - %s\n", 
-				p->username?p->username:"NULL", call->callToken,
-				ast_format_cap_get_names(p->cap, &codec_buf));
+				p->username?p->username:"NULL", call->callToken, prefsBuf);
 		}
 
-      		ooh323c_set_capability_for_call(call, p->cap,
+      		ooh323c_set_capability_for_call(call, &p->prefs, p->cap,
                                      p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA);
 
 		configure_local_rtp(p, call);
@@ -2177,8 +2151,9 @@ int onCallEstablished(ooCallData *call)
 			}
 
 			ast_queue_control(c, AST_CONTROL_ANSWER);
-			ast_publish_channel_state(c);
-			ast_channel_unlock(p->owner);
+   			ast_channel_unlock(p->owner);
+			manager_event(EVENT_FLAG_SYSTEM,"ChannelUpdate","Channel: %s\r\nChanneltype: %s\r\n"
+				"CallRef: %u\r\n", ast_channel_name(c), "OOH323", p->call_reference);
 		}
 		ast_mutex_unlock(&p->lock);
 
@@ -2311,7 +2286,7 @@ void ooh323_delete_peer(struct ooh323_peer *peer)
       if(peer->url)      free(peer->url);
       if(peer->e164)     free(peer->e164);
 
-      ao2_cleanup(peer->cap);
+		peer->cap = ast_format_cap_destroy(peer->cap);
 		free(peer);
 	}  
 
@@ -2332,13 +2307,14 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
    	user = ast_calloc(1,sizeof(struct ooh323_user));
 	if (user) {
 		memset(user, 0, sizeof(struct ooh323_user));
-		if (!(user->cap = ast_format_cap_alloc(0))) {
+		if (!(user->cap = ast_format_cap_alloc())) {
 			ast_free(user);
 			return NULL;
 		}
 		ast_mutex_init(&user->lock);
 		ast_copy_string(user->name, name, sizeof(user->name));
-		ast_format_cap_append_from_cap(user->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(user->cap, gCap);
+		memcpy(&user->prefs, &gPrefs, sizeof(user->prefs));
 		user->rtptimeout = gRTPTimeout;
 		user->nat = gNat;
 		user->dtmfmode = gDTMFMode;
@@ -2393,15 +2369,17 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
 								sizeof(user->rtpmaskstr));
 				} else user->rtpmask = NULL;
 			} else if (!strcasecmp(v->name, "disallow")) {
-				ast_format_cap_update_by_allow_disallow(user->cap,  v->value, 0);
+				ast_parse_allow_disallow(&user->prefs, 
+					user->cap,  v->value, 0);
 			} else if (!strcasecmp(v->name, "allow")) {
 				const char* tcodecs = v->value;
 				if (!strcasecmp(v->value, "all")) {
 					tcodecs = "ulaw,alaw,g729,g723,gsm";
 				}
-				ast_format_cap_update_by_allow_disallow(user->cap,  tcodecs, 1);
+				ast_parse_allow_disallow(&user->prefs,
+					 user->cap,  tcodecs, 1);
 			} else if (!strcasecmp(v->name, "amaflags")) {
-				user->amaflags = ast_channel_string2amaflag(v->value);
+				user->amaflags = ast_cdr_amaflags2int(v->value);
          		} else if (!strcasecmp(v->name, "ip") || !strcasecmp(v->name, "host")) {
 				struct ast_sockaddr p;
 				if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
@@ -2456,8 +2434,6 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
 					user->t38support = T38_FAXGW;
 				else if (!strcasecmp(v->value, "yes"))
 					user->t38support = T38_ENABLED;
-			} else if (!strcasecmp(v->name, "aniasdni")) {
-				user->aniasdni = ast_true(v->value);
 			}
 			v = v->next;
 		}
@@ -2479,13 +2455,14 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
 	peer = ast_calloc(1, sizeof(*peer));
 	if (peer) {
 		memset(peer, 0, sizeof(struct ooh323_peer));
-		if (!(peer->cap = ast_format_cap_alloc(0))) {
+		if (!(peer->cap = ast_format_cap_alloc())) {
 			ast_free(peer);
 			return NULL;
 		}
 		ast_mutex_init(&peer->lock);
 		ast_copy_string(peer->name, name, sizeof(peer->name));
-		ast_format_cap_append_from_cap(peer->cap, gCap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(peer->cap, gCap);
+      		memcpy(&peer->prefs, &gPrefs, sizeof(peer->prefs));
 		peer->rtptimeout = gRTPTimeout;
 		peer->nat = gNat;
 		ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode));
@@ -2588,15 +2565,17 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
 								sizeof(peer->rtpmaskstr));
 				} else peer->rtpmask = NULL;
 			} else if (!strcasecmp(v->name, "disallow")) {
-				ast_format_cap_update_by_allow_disallow(peer->cap, v->value, 0);
+				ast_parse_allow_disallow(&peer->prefs, peer->cap, 
+												 v->value, 0); 
 			} else if (!strcasecmp(v->name, "allow")) {
 				const char* tcodecs = v->value;
 				if (!strcasecmp(v->value, "all")) {
 					tcodecs = "ulaw,alaw,g729,g723,gsm";
 				}
-				ast_format_cap_update_by_allow_disallow(peer->cap, tcodecs, 1);
+				ast_parse_allow_disallow(&peer->prefs, peer->cap, 
+												 tcodecs, 1);				 
 			} else if (!strcasecmp(v->name,  "amaflags")) {
-				peer->amaflags = ast_channel_string2amaflag(v->value);
+				peer->amaflags = ast_cdr_amaflags2int(v->value);
 			} else if (!strcasecmp(v->name, "roundtrip")) {
 				sscanf(v->value, "%d,%d", &peer->rtdrcount, &peer->rtdrinterval);
 			} else if (!strcasecmp(v->name, "dtmfmode")) {
@@ -2775,6 +2754,7 @@ int reload_config(int reload)
 	struct ooh323_peer *peer = NULL;
 	char *cat;
 	const char *utype;
+	struct ast_format tmpfmt;
 
 	if (gH323Debug)
 		ast_verb(0, "---   reload_config\n");
@@ -2806,12 +2786,12 @@ int reload_config(int reload)
 	}
 
 	/* Inintialize everything to default */
-	strcpy(gLogFile, DEFAULT_LOGFILE);
+	snprintf(gLogFile, sizeof(gLogFile), "%s/%s", ast_config_AST_LOG_DIR, DEFAULT_LOGFILE);
 	gPort = 1720;
 	gIP[0] = '\0';
 	strcpy(gCallerID, DEFAULT_H323ID);
-	ast_format_cap_remove_by_type(gCap, AST_MEDIA_TYPE_UNKNOWN);
-	ast_format_cap_append(gCap, ast_format_ulaw, 0);
+	ast_format_cap_set(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+	memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
 	gDTMFMode = H323_DTMF_RFC2833;
 	gDTMFCodec = 101;
 	gFAXdetect = FAXDETECT_CNG;
@@ -3008,17 +2988,17 @@ int reload_config(int reload)
 											"'lowdelay', 'throughput', 'reliability', "
 											"'mincost', or 'none'\n", v->lineno);
 		} else if (!strcasecmp(v->name, "amaflags")) {
-			gAMAFLAGS = ast_channel_string2amaflag(v->value);
+			gAMAFLAGS = ast_cdr_amaflags2int(v->value);
 		} else if (!strcasecmp(v->name, "accountcode")) {
          ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode));
 		} else if (!strcasecmp(v->name, "disallow")) {
-			ast_format_cap_update_by_allow_disallow(gCap, v->value, 0);
+			ast_parse_allow_disallow(&gPrefs, gCap, v->value, 0);
 		} else if (!strcasecmp(v->name, "allow")) {
 			const char* tcodecs = v->value;
 			if (!strcasecmp(v->value, "all")) {
 				tcodecs = "ulaw,alaw,g729,g723,gsm";
 			}
-			ast_format_cap_update_by_allow_disallow(gCap, tcodecs, 1);
+			ast_parse_allow_disallow(&gPrefs, gCap, tcodecs, 1);
 		} else if (!strcasecmp(v->name, "dtmfmode")) {
 			if (!strcasecmp(v->value, "inband"))
 				gDTMFMode = H323_DTMF_INBAND;
@@ -3073,8 +3053,6 @@ int reload_config(int reload)
 		} else if (!strcasecmp(v->name, "tracelevel")) {
 			gTRCLVL = atoi(v->value);
 			ooH323EpSetTraceLevel(gTRCLVL);
-		} else if (!strcasecmp(v->name, "aniasdni")) {
-			gANIasDNI = ast_true(v->value);
 		}
 		v = v->next;
 	}
@@ -3170,6 +3148,9 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
 					peer->h245tunneling?"yes":"no");
 		ast_cli(a->fd, "%-15s%s\n", "DirectRTP", peer->directrtp ? "yes" : "no");
 		ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", peer->earlydirect ? "yes" : "no");
+		ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
+		print_codec_to_cli(a->fd, &peer->prefs);
+		ast_cli(a->fd, ")\n");
 		ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
 		if (peer->dtmfmode & H323_DTMF_CISCO) {
 			ast_cli(a->fd, "%s\n", "cisco");
@@ -3207,7 +3188,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
 		}
 
 		ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode);
-		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_channel_amaflags2string(peer->amaflags));
+		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(peer->amaflags));
 		ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port);
 		ast_cli(a->fd, "%-15.15s%u\n", "OutgoingLimit: ", peer->outgoinglimit);
 		ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
@@ -3231,7 +3212,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
 static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ooh323_peer *prev = NULL, *peer = NULL;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+   char formats[FORMAT_STRING_SIZE];
    char ip_port[30];
 #define FORMAT  "%-15.15s  %-15.15s  %-23.23s  %-s\n"
 
@@ -3256,10 +3237,10 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru
 	while (peer) {
 		ast_mutex_lock(&peer->lock);
 		snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
-		ast_cli(a->fd, FORMAT, peer->name, 
+     ast_cli(a->fd, FORMAT, peer->name, 
 					peer->accountcode,
 					ip_port,
-					ast_format_cap_get_names(peer->cap, &codec_buf));
+                 ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,peer->cap));
 		prev = peer;
 		peer = peer->next;
 		ast_mutex_unlock(&prev->lock);
@@ -3270,6 +3251,24 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru
 	return CLI_SUCCESS;
 }
 
+/*! \brief Print codec list from preference to CLI/manager */
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
+{
+	int x;
+	struct ast_format tmpfmt;
+	for (x = 0; x < 32; x++) {
+		ast_codec_pref_index(pref, x, &tmpfmt);
+		if (!tmpfmt.id)
+			break;
+		ast_cli(fd, "%s", ast_getformatname(&tmpfmt));
+		ast_cli(fd, ":%d", pref->framing[x]);
+		if (x < 31 && ast_codec_pref_index(pref, x + 1, &tmpfmt))
+			ast_cli(fd, ",");
+	}
+	if (!x)
+		ast_cli(fd, "none");
+}
+
 static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ooh323_user *prev = NULL, *user = NULL;
@@ -3308,6 +3307,9 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
 					user->h245tunneling?"yes":"no");
 		ast_cli(a->fd, "%-15s%s\n", "DirectRTP", user->directrtp ? "yes" : "no");
 		ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", user->earlydirect ? "yes" : "no");
+		ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
+		print_codec_to_cli(a->fd, &user->prefs);
+		ast_cli(a->fd, ")\n");
 		ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
 		if (user->dtmfmode & H323_DTMF_CISCO) {
 			ast_cli(a->fd, "%s\n", "cisco");
@@ -3345,7 +3347,7 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
 		}
 
 		ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode);
-		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_channel_amaflags2string(user->amaflags));
+		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(user->amaflags));
 		ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context);
 		ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit);
 		ast_cli(a->fd, "%-15.15s%u\n", "InUse: ", user->inUse);
@@ -3370,7 +3372,7 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
 static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ooh323_user *prev = NULL, *user = NULL;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+   char formats[FORMAT_STRING_SIZE];
 #define FORMAT1  "%-15.15s  %-15.15s  %-15.15s  %-s\n"
 
 	switch (cmd) {
@@ -3397,7 +3399,7 @@ static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, stru
 		ast_mutex_lock(&user->lock);
      		ast_cli(a->fd, FORMAT1, user->name, 
 					user->accountcode, user->context,
-					ast_format_cap_get_names(user->cap, &codec_buf));
+					ast_getformatname_multiple(formats, FORMAT_STRING_SIZE, user->cap));
 		prev = user;
 		user = user->next;
 		ast_mutex_unlock(&prev->lock);
@@ -3504,7 +3506,6 @@ static char *handle_cli_ooh323_show_gk(struct ast_cli_entry *e, int cmd, struct
 static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	char value[FORMAT_STRING_SIZE];
-	struct ast_str *codec_buf = ast_str_alloca(64);
 	ooAliases *pAlias = NULL, *pAliasNext = NULL;;
 
 	switch (cmd) {
@@ -3553,7 +3554,7 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str
 	ast_cli(a->fd,  "%-20s%s\n", "H.323 LogFile:", gLogFile);
 	ast_cli(a->fd,  "%-20s%s\n", "Context:", gContext);
 	ast_cli(a->fd,  "%-20s%s\n", "Capability:",
-		ast_format_cap_get_names(gCap, &codec_buf));
+		ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCap));
 	ast_cli(a->fd, "%-20s", "DTMF Mode: ");
 	if (gDTMFMode & H323_DTMF_CISCO) {
 		ast_cli(a->fd, "%s\n", "cisco");
@@ -3597,7 +3598,7 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str
 
 	ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber);
 	ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
-	ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_channel_amaflags2string(gAMAFLAGS));
+	ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
 
 	pAlias = gAliasList;
 	if(pAlias) {
@@ -3734,6 +3735,7 @@ static int load_module(void)
 {
 	struct ooAliases * pNewAlias = NULL;
 	struct ooh323_peer *peer = NULL;
+	struct ast_format tmpfmt;
 	OOH225MsgCallbacks h225Callbacks = {0, 0, 0, 0};
 
 	OOH323CALLBACKS h323Callbacks = {
@@ -3749,16 +3751,14 @@ static int load_module(void)
 		.onModeChanged = onModeChanged,
 		.onMediaChanged = (cb_OnMediaChanged) setup_rtp_remote,
 	};
-	if (!(gCap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(gCap = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE; 
 	}
-	if (!(ooh323_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ao2_ref(gCap, -1);
-		gCap = NULL;
+	if (!(ooh323_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(gCap, ast_format_ulaw, 0);
-	ast_format_cap_append_by_type(ooh323_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_add(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add_all(ooh323_tech.capabilities);
 
 	myself = ast_module_info->self;
 
@@ -3787,23 +3787,16 @@ static int load_module(void)
 		if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile)) {
          		ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-"
                             "OOH323 Disabled\n");
-			ao2_ref(gCap, -1);
-			gCap = NULL;
-			ao2_ref(ooh323_tech.capabilities, -1);
-			ooh323_tech.capabilities = NULL;
 			return AST_MODULE_LOAD_DECLINE;
 		}
 
 		/* Make sure we can register our OOH323 channel type */
 		if (ast_channel_register(&ooh323_tech)) {
 			ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
-			ao2_ref(gCap, -1);
-			gCap = NULL;
-			ao2_ref(ooh323_tech.capabilities, -1);
-			ooh323_tech.capabilities = NULL;
 			return AST_MODULE_LOAD_DECLINE;
 		}
 		ast_rtp_glue_register(&ooh323_rtp);
+		ast_udptl_proto_register(&ooh323_udptl);
 		ast_cli_register_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
 
 		if (gIsGateway)
@@ -3882,12 +3875,8 @@ static int load_module(void)
 		ooH323EpSetH323Callbacks(h323Callbacks);
 
 		/* Add endpoint capabilities */
-		if (ooh323c_set_capability(gCap, gDTMFMode, gDTMFCodec) < 0) {
+		if (ooh323c_set_capability(&gPrefs, gCap, gDTMFMode, gDTMFCodec) < 0) {
 			ast_log(LOG_ERROR, "Capabilities failure for OOH323. OOH323 Disabled.\n");
-			ao2_ref(gCap, -1);
-			gCap = NULL;
-			ao2_ref(ooh323_tech.capabilities, -1);
-			ooh323_tech.capabilities = NULL;
 			return 1;
 		}
   
@@ -3897,10 +3886,6 @@ static int load_module(void)
                             "OOH323 DISABLED\n");
 		
 			ooH323EpDestroy();
-			ao2_ref(gCap, -1);
-			gCap = NULL;
-			ao2_ref(ooh323_tech.capabilities, -1);
-			ooh323_tech.capabilities = NULL;
 			return 1;
 		}
 
@@ -3908,10 +3893,6 @@ static int load_module(void)
 			ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. "
                             "OOH323 DISABLED\n");
 			ooH323EpDestroy();
-			ao2_ref(gCap, -1);
-			gCap = NULL;
-			ao2_ref(ooh323_tech.capabilities, -1);
-			ooh323_tech.capabilities = NULL;
 			return 1;
 		}
 		/* And start the monitor for the first time */
@@ -3924,22 +3905,6 @@ static int load_module(void)
 	return 0;
 }
 
-static int reload_module(void)
-{
-	ast_mutex_lock(&h323_reload_lock);
-	if (h323_reloading) {
-		ast_verb(0, "Previous OOH323 reload not yet done\n");
-	} else {
-		h323_reloading = 1;
-	}
-	ast_mutex_unlock(&h323_reload_lock);
-	restart_monitor();
-
-	if (gH323Debug)
-		ast_verb(0, "+++   ooh323_reload\n");
-
-	return 0;
-}
 
 static void *do_monitor(void *data)
 {
@@ -4115,6 +4080,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
 		}
 
 		if (cur->rtp) {
+			ast_rtp_instance_stop(cur->rtp);
 			ast_rtp_instance_destroy(cur->rtp);
 			cur->rtp = NULL;
 		}
@@ -4160,9 +4126,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
 
 		ast_mutex_unlock(&cur->lock);
 		ast_mutex_destroy(&cur->lock);
-		ao2_cleanup(cur->writeformat);
-		ao2_cleanup(cur->readformat);
-		ao2_cleanup(cur->cap);
+		cur->cap = ast_format_cap_destroy(cur->cap);
 		ast_free(cur);
 	}
 
@@ -4227,7 +4191,7 @@ int delete_users()
 	  			free(prev->rtpmask);
       			}
       		}
-      	ao2_cleanup(prev->cap);
+		prev->cap = ast_format_cap_destroy(prev->cap);
 		free(prev);
 		if (cur == userl.users) {
 			break;
@@ -4249,6 +4213,7 @@ static int unload_module(void)
 	/* First, take us out of the channel loop */
 	ast_cli_unregister_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
 	ast_rtp_glue_unregister(&ooh323_rtp);
+	ast_udptl_proto_unregister(&ooh323_udptl);
 	ast_channel_unregister(&ooh323_tech);
 #if 0
 	ast_unregister_atexit(&ast_ooh323c_exit);
@@ -4355,10 +4320,8 @@ static int unload_module(void)
 		ast_verb(0, "+++ ooh323  unload_module \n");
 	}
 
-	ao2_ref(gCap, -1);
-	gCap = NULL;
-	ao2_ref(ooh323_tech.capabilities, -1);
-	ooh323_tech.capabilities = NULL;
+	gCap = ast_format_cap_destroy(gCap);
+	ooh323_tech.capabilities = ast_format_cap_destroy(ooh323_tech.capabilities);
 	return 0;
 }
 
@@ -4370,11 +4333,8 @@ static void ooh323_get_codec(struct ast_channel *chan, struct ast_format_cap *re
 	}
 
 	if (p) {
-		if (ast_format_cap_count(ast_channel_nativeformats(chan))) {
-			ast_format_cap_append_from_cap(result, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_UNKNOWN);
-		} else if (ast_format_cap_count(p->cap)) {
-			ast_format_cap_append_from_cap(result, p->cap, AST_MEDIA_TYPE_UNKNOWN);
-		}
+		ast_format_cap_append(result,  ast_format_cap_is_empty(ast_channel_nativeformats(chan)) ?
+				(ast_format_cap_is_empty(p->cap) ? NULL : p->cap) : ast_channel_nativeformats(chan));
 	}
 
 	if (gH323Debug) {
@@ -4448,28 +4408,56 @@ static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, s
 	return res;
 }
 
+
+int ooh323_update_capPrefsOrderForCall
+	(ooCallData *call, struct ast_codec_pref *prefs)
+{
+	int i = 0;
+	struct ast_format tmpfmt;
+
+	ast_codec_pref_index(prefs, i, &tmpfmt);
+
+	ooResetCapPrefs(call);
+	while (tmpfmt.id) {
+		ooAppendCapToCapPrefs(call, ooh323_convertAsteriskCapToH323Cap(&tmpfmt));
+		ast_codec_pref_index(prefs, ++i, &tmpfmt);
+	}
+
+	return 0;
+}
+
+
 int ooh323_convertAsteriskCapToH323Cap(struct ast_format *format)
 {
-	if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	switch (format->id) {
+	case AST_FORMAT_ULAW:
 		return OO_G711ULAW64K;
-	} else if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ALAW:
 		return OO_G711ALAW64K;
-	} else if (ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_GSM:
 		return OO_GSMFULLRATE;
-	} else if (ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) {
+
+#ifdef AST_FORMAT_AMRNB
+	case AST_FORMAT_AMRNB:
+		return OO_AMRNB;
+#endif
+#ifdef AST_FORMAT_SPEEX
+	case AST_FORMAT_SPEEX:
 		return OO_SPEEX;
-	} else if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
+#endif
+
+	case AST_FORMAT_G729A:
 		return OO_G729A;
-	} else if (ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G726:
 		return OO_G726;
-	} else if (ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G726_AAL2:
 		return OO_G726AAL2;
-	} else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G723_1:
 		return OO_G7231;
-	} else if (ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_H263:
 		return OO_H263VIDEO;
-	} else {
-		ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_format_get_name(format));
+	default:
+		ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_getformatname(format));
 		return -1;
 	}
 }
@@ -4548,6 +4536,9 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
 	struct ast_sockaddr tmp;
 	ooMediaInfo mediaInfo;
 	int x;
+	struct ast_format tmpfmt;
+
+	ast_format_clear(&tmpfmt);
 
 	if (gH323Debug)
 		ast_verb(0, "---   configure_local_rtp\n");
@@ -4593,10 +4584,7 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
 	ast_channel_unlock(p->owner);
 
 	if (p->rtp) {
-		if (p->cap) {
-			ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp),
-				ast_format_cap_get_framing(p->cap));
-		}
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
 		if (p->nat) {
 			ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_NAT, 1);
 		}
@@ -4633,11 +4621,9 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
 	ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
 	mediaInfo.lMediaPort = lport;
 	mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort + 1;
-	for (x = 0; x < ast_format_cap_count(p->cap); x++) {
-		struct ast_format *format = ast_format_cap_get_format(p->cap, x);
-
+	for (x = 0; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) {
 		strcpy(mediaInfo.dir, "transmit");
-		mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(format);
+		mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(&tmpfmt);
 		ooAddMediaInfo(call, mediaInfo);
 		strcpy(mediaInfo.dir, "receive");
 		ooAddMediaInfo(call, mediaInfo);
@@ -4654,8 +4640,6 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
 			strcpy(mediaInfo.dir, "receive");
 			ooAddMediaInfo(call, mediaInfo);
 		}
-
-		ao2_ref(format, -1);
 	}
 
 	if (p->udptl) {
@@ -4739,7 +4723,7 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, int remotePort
 	ast_sockaddr_set_port(&tmp, remotePort);
 	ast_rtp_instance_set_remote_address(p->rtp, &tmp);
 
-	if (ast_format_cmp(p->writeformat, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) {
+	if (p->writeformat.id == AST_FORMAT_G726_AAL2) {
                 ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, 2,
 							"audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
 	}
@@ -4781,6 +4765,41 @@ void close_rtp_connection(ooCallData *call)
  udptl handling functions
  */
 
+static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan)
+{
+	struct ooh323_pvt *p;
+	struct ast_udptl *udptl = NULL;
+
+	p = ast_channel_tech_pvt(chan);
+	if (!p)
+		return NULL;
+
+	ast_mutex_lock(&p->lock);
+	if (p->udptl)
+		udptl = p->udptl;
+	ast_mutex_unlock(&p->lock);
+	return udptl;
+}
+
+static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
+{
+	struct ooh323_pvt *p;
+
+	p = ast_channel_tech_pvt(chan);
+	if (!p)
+		return -1;
+	ast_mutex_lock(&p->lock);
+
+	if (udptl) {
+		ast_udptl_get_peer(udptl, &p->udptlredirip);
+	} else
+		memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+
+	ast_mutex_unlock(&p->lock);
+	/* free(callToken); */
+	return 0;
+}
+
 void setup_udptl_connection(ooCallData *call, const char *remoteIp, 
 								  int remotePort)
 {
@@ -4956,24 +4975,15 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
 
 	if (f && p->owner && !p->faxmode && (f->frametype == AST_FRAME_VOICE)) {
 		/* We already hold the channel lock */
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(p->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_format_cap *caps;
-
-			ast_debug(1, "Oooh, voice format changed to %s\n", ast_format_get_name(f->subclass.format));
-
-			caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-			if (caps) {
-				ast_format_cap_append(caps, f->subclass.format, 0);
-				ast_channel_nativeformats_set(p->owner, caps);
-				ao2_ref(caps, -1);
-			}
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) {
+			ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
+			ast_format_cap_set(ast_channel_nativeformats(p->owner), &f->subclass.format);
 			ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
 			ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
 		}
 		if (((p->dtmfmode & H323_DTMF_INBAND) || (p->faxdetect & FAXDETECT_CNG)) && p->vad &&
-			((ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) ||
-			(ast_format_cmp(f->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) ||
-			(ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL))) {
+		    (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW ||
+		     f->subclass.format.id == AST_FORMAT_ULAW)) {
 			dfr = ast_frdup(f);
 			dfr = ast_dsp_process(p->owner, p->vad, dfr);
 		}
@@ -5187,10 +5197,4 @@ void ast_ooh323c_exit()
 }
 #endif
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Objective Systems H323 Channel",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
-			.load = load_module,
-			.unload = unload_module,
-			.reload = reload_module,
-			.load_pri = AST_MODPRI_CHANNEL_DRIVER
-			);
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Objective Systems H323 Channel");
diff --git a/addons/chan_ooh323.h b/addons/chan_ooh323.h
index 89caaff..2fb9039 100644
--- a/addons/chan_ooh323.h
+++ b/addons/chan_ooh323.h
@@ -64,8 +64,6 @@
 #include "asterisk/format.h"
 #include "asterisk/format_cap.h"
 #include "asterisk/udptl.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
 
 #include "ootypes.h"
 #include "ooUtils.h"
@@ -105,6 +103,9 @@ struct ast_frame *ooh323_rtp_read
 void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txframes);
 void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt);
 
+int ooh323_update_capPrefsOrderForCall
+   (ooCallData *call, struct ast_codec_pref *prefs);
+
 int ooh323_convertAsteriskCapToH323Cap(struct ast_format *format);
 
 int ooh323_convert_hangupcause_asteriskToH323(int cause);
diff --git a/addons/format_mp3.c b/addons/format_mp3.c
index 586f3ad..78fcc28 100644
--- a/addons/format_mp3.c
+++ b/addons/format_mp3.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "mp3/mpg123.h"
 #include "mp3/mpglib.h"
@@ -42,7 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/mod_format.h"
 #include "asterisk/logger.h"
-#include "asterisk/format_cache.h"
 
 #define MP3_BUFLEN 320
 #define MP3_SCACHE 16384
@@ -230,7 +229,10 @@ static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext)
 
 	p->offset += p->buflen;
 	delay = p->buflen / 2;
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_SLINEAR, 0);
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, p->buflen);
+	s->fr.mallocd = 0;
 	s->fr.samples = delay;
 	*whennext = delay;
 	return &s->fr;
@@ -316,7 +318,7 @@ static struct ast_format_def mp3_f = {
 
 static int load_module(void)
 {
-	mp3_f.format = ast_format_slin;
+	ast_format_set(&mp3_f.format, AST_FORMAT_SLINEAR, 0);
 	InitMP3Constants();
 	return ast_format_def_register(&mp3_f);
 }
@@ -326,5 +328,4 @@ static int unload_module(void)
 	return ast_format_def_unregister(name);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "MP3 format [Any rate but 8000hz mono is optimal]");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MP3 format [Any rate but 8000hz mono is optimal]");
diff --git a/addons/ooh323c/src/ooSocket.c b/addons/ooh323c/src/ooSocket.c
index e843f5e..ee02f52 100644
--- a/addons/ooh323c/src/ooSocket.c
+++ b/addons/ooh323c/src/ooSocket.c
@@ -15,7 +15,7 @@
  *****************************************************************************/
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369602 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/io.h"
 #include "asterisk/lock.h"
diff --git a/addons/ooh323c/src/ooh245.c b/addons/ooh323c/src/ooh245.c
index 09dd3a4..39b3994 100644
--- a/addons/ooh323c/src/ooh245.c
+++ b/addons/ooh323c/src/ooh245.c
@@ -1909,7 +1909,7 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
                                      T_H245TransportAddress_unicastAddress)
    	{
       	 OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
-                  "channel addres type is not unicast (%s, %s)\n", 
+                  "channel address type is not unicast (%s, %s)\n", 
                    call->callType, call->callToken);
       	 return OO_FAILED;
    	}
diff --git a/addons/ooh323c/src/ooq931.c b/addons/ooh323c/src/ooq931.c
index 86ecd92..cbc4afb 100644
--- a/addons/ooh323c/src/ooq931.c
+++ b/addons/ooh323c/src/ooq931.c
@@ -758,14 +758,14 @@ int ooEncodeH225Message(OOH323CallData *call, Q931Message *pq931Msg,
       i += pq931Msg->causeIE->length;
    } 
       
-   /*Add progress indicator IE 
-   if(pq931Msg->messageType == Q931AlertingMsg || pq931Msg->messageType == Q931CallProceedingMsg)
+   /* Add progress indicator IE */
+   if(pq931Msg->messageType == Q931AlertingMsg || pq931Msg->messageType == Q931ProgressMsg)
    {
       msgbuf[i++] = Q931ProgressIndicatorIE;
       msgbuf[i++] = 2; //Length is 2 octet
       msgbuf[i++] = 0x80; //PI=8
       msgbuf[i++] = 0x88;
-  }*/
+   }
 
    /*Add display ie. for all but Status message as per ASTERISK-18748 */
    if(!ooUtilsIsStrEmpty(call->ourCallerId) && (pq931Msg->messageType != Q931StatusMsg))
diff --git a/addons/ooh323c/src/printHandler.c b/addons/ooh323c/src/printHandler.c
index 3986a86..8d51137 100644
--- a/addons/ooh323c/src/printHandler.c
+++ b/addons/ooh323c/src/printHandler.c
@@ -268,7 +268,7 @@ static const char* octStrToString
       if (bufsiz > 1) buffer[1] = '\0';
       for (i = 0; i < numocts; i++) {
          if (i < bufsiz - 1) {
-            sprintf (lbuf, "%02x", (unsigned)data[i]);
+            sprintf (lbuf, "%02hhx", (unsigned char)data[i]);
             strcat (&buffer[(i*2)+1], lbuf);
          }
          else break;
diff --git a/addons/ooh323cDriver.c b/addons/ooh323cDriver.c
index bceb077..dd127a4 100644
--- a/addons/ooh323cDriver.c
+++ b/addons/ooh323cDriver.c
@@ -225,17 +225,17 @@ int ooh323c_stop_stack_thread(void)
 }
 
 int ooh323c_set_capability
-   (struct ast_format_cap *cap, int dtmf, int dtmfcodec)
+   (struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec)
 {
    int ret = 0, x;
+   struct ast_format tmpfmt;
    if (gH323Debug) {
      ast_verb(0, "\tAdding capabilities to H323 endpoint\n");
    }
 
-   for(x=0; x<ast_format_cap_count(cap); x++)
+   for(x=0; ast_codec_pref_index(prefs, x, &tmpfmt); x++)
    {
-    struct ast_format *format = ast_format_cap_get_format(cap, x);
-      if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_ULAW)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g711 ulaw capability to H323 endpoint\n");
@@ -246,7 +246,7 @@ int ooh323c_set_capability
                                      &ooh323c_stop_receive_channel, 
                                      &ooh323c_stop_transmit_channel);
       }
-      if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_ALAW)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g711 alaw capability to H323 endpoint\n");
@@ -258,7 +258,7 @@ int ooh323c_set_capability
                                      &ooh323c_stop_transmit_channel);
       }
 
-      if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G729A)
       {
          if (gH323Debug) {
 	    ast_verb(0, "\tAdding g729A capability to H323 endpoint\n");
@@ -287,7 +287,7 @@ int ooh323c_set_capability
                                      &ooh323c_stop_transmit_channel);
       }
 
-      if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G723_1)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g7231 capability to H323 endpoint\n");
@@ -300,7 +300,7 @@ int ooh323c_set_capability
 
       }
 
-      if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G726)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g726 capability to H323 endpoint\n");
@@ -313,7 +313,7 @@ int ooh323c_set_capability
 
       }
 
-      if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G726_AAL2)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g726aal2 capability to H323 endpoint\n");
@@ -326,7 +326,7 @@ int ooh323c_set_capability
 
       }
 
-      if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_H263)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding h263 capability to H323 endpoint\n");
@@ -339,7 +339,7 @@ int ooh323c_set_capability
 
       }
 
-      if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_GSM)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding gsm capability to H323 endpoint\n");
@@ -351,8 +351,24 @@ int ooh323c_set_capability
                                      &ooh323c_stop_transmit_channel);
 
       }
+      
+#ifdef AST_FORMAT_AMRNB
+      if(tmpfmt.id == AST_FORMAT_AMRNB)
+      {
+         if (gH323Debug) {
+            ast_verb(0, "\tAdding amr nb capability to H323 endpoint\n");
+	 }
+         ret = ooH323EpAddAMRNBCapability(OO_AMRNB, 4, 4, FALSE, 
+                                     OORXANDTX, &ooh323c_start_receive_channel,
+                                     &ooh323c_start_transmit_channel,
+                                     &ooh323c_stop_receive_channel, 
+                                     &ooh323c_stop_transmit_channel);
+
+      }
+#endif
 
-      if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL)
+#ifdef AST_FORMAT_SPEEX
+      if(tmpfmt.id == AST_FORMAT_SPEEX)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding speex capability to H323 endpoint\n");
@@ -364,8 +380,8 @@ int ooh323c_set_capability
                                      &ooh323c_stop_transmit_channel);
 
       }
-
-    ao2_ref(format, -1);      
+#endif
+      
    }
    
    if(dtmf & H323_DTMF_CISCO)
@@ -381,10 +397,11 @@ int ooh323c_set_capability
 }
 
 int ooh323c_set_capability_for_call
-   (ooCallData *call, struct ast_format_cap *cap, int dtmf, int dtmfcodec,
+   (ooCallData *call, struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec,
 		 int t38support, int g729onlyA)
 {
    int ret = 0, x, txframes;
+   struct ast_format tmpfmt;
    if (gH323Debug) {
      ast_verb(0, "\tAdding capabilities to call(%s, %s)\n", call->callType, 
                                                             call->callToken);
@@ -406,16 +423,15 @@ int ooh323c_set_capability_for_call
 					&ooh323c_stop_transmit_datachannel,
 					0);
 
-   for(x=0; x<ast_format_cap_count(cap); x++)
+   for(x=0; ast_codec_pref_index(prefs, x, &tmpfmt); x++)
    {
-    struct ast_format *format = ast_format_cap_get_format(cap, x);
-      if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_ULAW)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g711 ulaw capability to call(%s, %s)\n", 
                                               call->callType, call->callToken);
 	 }
-	 txframes = ast_format_cap_get_format_framing(cap, format);
+	 txframes = prefs->framing[x];
          ret= ooCallAddG711Capability(call, OO_G711ULAW64K, txframes, 
                                       txframes, OORXANDTX, 
                                       &ooh323c_start_receive_channel,
@@ -423,13 +439,13 @@ int ooh323c_set_capability_for_call
                                       &ooh323c_stop_receive_channel, 
                                       &ooh323c_stop_transmit_channel);
       }
-      if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_ALAW)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g711 alaw capability to call(%s, %s)\n",
                                             call->callType, call->callToken);
 	 }
-         txframes = ast_format_cap_get_format_framing(cap, format);
+         txframes = prefs->framing[x];
          ret= ooCallAddG711Capability(call, OO_G711ALAW64K, txframes, 
                                      txframes, OORXANDTX, 
                                      &ooh323c_start_receive_channel,
@@ -438,13 +454,13 @@ int ooh323c_set_capability_for_call
                                      &ooh323c_stop_transmit_channel);
       }
 
-      if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G726)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g726 capability to call (%s, %s)\n",
                                            call->callType, call->callToken);
 	 }
-	 txframes = ast_format_cap_get_format_framing(cap, format);
+	 txframes = prefs->framing[x];
          ret = ooCallAddG726Capability(call, OO_G726, txframes, grxframes, FALSE,
                                      OORXANDTX, &ooh323c_start_receive_channel,
                                      &ooh323c_start_transmit_channel,
@@ -453,13 +469,13 @@ int ooh323c_set_capability_for_call
 
       }
 
-      if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G726_AAL2)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g726aal2 capability to call (%s, %s)\n",
                                            call->callType, call->callToken);
 	 }
-	 txframes = ast_format_cap_get_format_framing(cap, format);
+	 txframes = prefs->framing[x];
          ret = ooCallAddG726Capability(call, OO_G726AAL2, txframes, grxframes, FALSE,
                                      OORXANDTX, &ooh323c_start_receive_channel,
                                      &ooh323c_start_transmit_channel,
@@ -468,10 +484,10 @@ int ooh323c_set_capability_for_call
 
       }
 
-      if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G729A)
       {
       
-         txframes = (ast_format_cap_get_format_framing(cap, format))/10;
+         txframes = (prefs->framing[x])/10;
          if (gH323Debug) {
             ast_verb(0, "\tAdding g729A capability to call(%s, %s)\n",
                                             call->callType, call->callToken);
@@ -504,7 +520,7 @@ int ooh323c_set_capability_for_call
 
       }
 
-      if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_G723_1)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding g7231 capability to call (%s, %s)\n",
@@ -518,7 +534,7 @@ int ooh323c_set_capability_for_call
 
       }
 
-      if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_H263)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding h263 capability to call (%s, %s)\n",
@@ -532,7 +548,7 @@ int ooh323c_set_capability_for_call
 
       }
 
-      if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL)
+      if(tmpfmt.id == AST_FORMAT_GSM)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding gsm capability to call(%s, %s)\n", 
@@ -545,7 +561,22 @@ int ooh323c_set_capability_for_call
                                      &ooh323c_stop_transmit_channel);
       }
 
-      if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL)
+#ifdef AST_FORMAT_AMRNB
+      if(tmpfmt.id == AST_FORMAT_AMRNB)
+      {
+         if (gH323Debug) {
+            ast_verb(0, "\tAdding AMR capability to call(%s, %s)\n", 
+                                             call->callType, call->callToken);
+	 }
+         ret = ooCallAddAMRNBCapability(call, OO_AMRNB, 4, 4, FALSE, 
+                                     OORXANDTX, &ooh323c_start_receive_channel,
+                                     &ooh323c_start_transmit_channel,
+                                     &ooh323c_stop_receive_channel, 
+                                     &ooh323c_stop_transmit_channel);
+      }
+#endif
+#ifdef AST_FORMAT_SPEEX
+      if(tmpfmt.id == AST_FORMAT_SPEEX)
       {
          if (gH323Debug) {
             ast_verb(0, "\tAdding Speex capability to call(%s, %s)\n", 
@@ -557,8 +588,7 @@ int ooh323c_set_capability_for_call
                                      &ooh323c_stop_receive_channel, 
                                      &ooh323c_stop_transmit_channel);
       }
-
-      ao2_ref(format, -1);
+#endif
    }
    return ret;
 }
@@ -592,9 +622,9 @@ int ooh323c_set_aliases(ooAliases * aliases)
    
 int ooh323c_start_receive_channel(ooCallData *call, ooLogicalChannel *pChannel)
 {
-   struct ast_format *tmpfmt = NULL;
-   tmpfmt = convertH323CapToAsteriskCap(pChannel->chanCap->cap);
-   if(tmpfmt) {
+   struct ast_format tmpfmt;
+   convertH323CapToAsteriskCap(pChannel->chanCap->cap, &tmpfmt);
+   if(tmpfmt.id) {
       /* ooh323_set_read_format(call, fmt); */
    }else{
      ast_log(LOG_ERROR, "Invalid capability type for receive channel %s\n",
@@ -606,17 +636,19 @@ int ooh323c_start_receive_channel(ooCallData *call, ooLogicalChannel *pChannel)
 
 int ooh323c_start_transmit_channel(ooCallData *call, ooLogicalChannel *pChannel)
 {
-   struct ast_format *tmpfmt = NULL;
-   tmpfmt = convertH323CapToAsteriskCap(pChannel->chanCap->cap);
-
-   if (tmpfmt) {
-    if ((ast_format_cmp(tmpfmt, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ||
-      (ast_format_cmp(tmpfmt, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)) {
-  	ooh323_set_write_format(call, tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes);
-    } else if (ast_format_cmp(tmpfmt, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
-	 ooh323_set_write_format(call, tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes*10);
-  } else {
-	ooh323_set_write_format(call, tmpfmt, 0);
+   struct ast_format tmpfmt;
+   convertH323CapToAsteriskCap(pChannel->chanCap->cap, &tmpfmt);
+   if(tmpfmt.id) {
+      switch (tmpfmt.id) {
+      case AST_FORMAT_ALAW:
+      case AST_FORMAT_ULAW:
+	ooh323_set_write_format(call, &tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes);
+	break;
+      case AST_FORMAT_G729A:
+	ooh323_set_write_format(call, &tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes*10);
+	break;
+      default:
+	ooh323_set_write_format(call, &tmpfmt, 0);
       }
    }else{
       ast_log(LOG_ERROR, "Invalid capability type for receive channel %s\n",
@@ -661,32 +693,41 @@ int ooh323c_stop_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChann
    return 1;
 }
 
-struct ast_format *convertH323CapToAsteriskCap(int cap)
+struct ast_format *convertH323CapToAsteriskCap(int cap, struct ast_format *result)
 {
+   ast_format_clear(result);
    switch(cap)
    {
       case OO_G711ULAW64K:
-         return ast_format_ulaw;
+         return ast_format_set(result, AST_FORMAT_ULAW, 0);
       case OO_G711ALAW64K:
-         return ast_format_alaw;
+         return ast_format_set(result, AST_FORMAT_ALAW, 0);
       case OO_GSMFULLRATE:
-         return ast_format_gsm;
+         return ast_format_set(result, AST_FORMAT_GSM, 0);
+
+#ifdef AST_FORMAT_AMRNB
+      case OO_AMRNB:
+         return ast_format_set(result, AST_FORMAT_AMRNB, 0);
+#endif
+#ifdef AST_FORMAT_SPEEX
       case OO_SPEEX:
-         return ast_format_speex;
+         return ast_format_set(result, AST_FORMAT_SPEEX, 0);
+#endif
+
       case OO_G729:
-         return ast_format_g729;
+         return ast_format_set(result, AST_FORMAT_G729A, 0);
       case OO_G729A:
-         return ast_format_g729;
+         return ast_format_set(result, AST_FORMAT_G729A, 0);
       case OO_G729B:
-         return ast_format_g729;
+         return ast_format_set(result, AST_FORMAT_G729A, 0);
       case OO_G7231:
-         return ast_format_g723;
+         return ast_format_set(result, AST_FORMAT_G723_1, 0);
       case OO_G726:
-         return ast_format_g726;
+         return ast_format_set(result, AST_FORMAT_G726, 0);
       case OO_G726AAL2:
-         return ast_format_g726_aal2;
+         return ast_format_set(result, AST_FORMAT_G726_AAL2, 0);
       case OO_H263VIDEO:
-         return ast_format_h263;
+         return ast_format_set(result, AST_FORMAT_H263, 0);
       default:
          ast_debug(1, "Cap %d is not supported by driver yet\n", cap);
          return NULL;
diff --git a/addons/ooh323cDriver.h b/addons/ooh323cDriver.h
index 9819801..af03eea 100644
--- a/addons/ooh323cDriver.h
+++ b/addons/ooh323cDriver.h
@@ -37,9 +37,9 @@ int ooh323c_stop_stack_thread(void);
 int ooh323c_start_call_thread(ooCallData *call);
 int ooh323c_stop_call_thread(ooCallData *call);
 int ooh323c_set_capability
-   (struct ast_format_cap *cap, int dtmf, int dtmfcodec);
-struct ast_format *convertH323CapToAsteriskCap(int cap);
+   (struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec);
+struct ast_format *convertH323CapToAsteriskCap(int cap, struct ast_format *format);
 int ooh323c_set_capability_for_call
-   (ooCallData *call, struct ast_format_cap *cap, int dtmf, int dtmfcodec,
+   (ooCallData *call, struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec,
 	int t38support, int g729onlyA);
 #endif
diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c
index 1c70776..4546ce9 100644
--- a/addons/res_config_mysql.c
+++ b/addons/res_config_mysql.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
@@ -316,7 +316,7 @@ static char *decode_chunk(char *chunk)
 	return orig;
 }
 
-static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
+static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
 {
 	struct mysql_conn *dbh;
 	MYSQL_RES *result;
@@ -328,8 +328,9 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	char *stringp;
 	char *chunk;
 	char *op;
-	const struct ast_variable *field = rt_fields;
+	const char *newparam, *newval;
 	struct ast_variable *var=NULL, *prev=NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 0))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: %s (check res_mysql.conf)\n", database);
@@ -343,14 +344,17 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
@@ -358,20 +362,21 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' ')) 
+	if (!strchr(newparam, ' ')) 
 		op = " ="; 
 	else 
 		op = "";
 
-	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
-	while ((field = field->next)) {
-		if (!strchr(field->name, ' ')) 
+	ESCAPE_STRING(buf, newval);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
+		if (!strchr(newparam, ' ')) 
 			op = " ="; 
 		else
 			op = "";
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(buf));
 	}
 
 	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql));
@@ -379,6 +384,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	/* Execution. */
 	if (mysql_real_query(&dbh->handle, ast_str_buffer(sql), ast_str_strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
@@ -410,13 +416,14 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
+	va_end(aq);
 	release_database(dbh);
 	mysql_free_result(result);
 
 	return var;
 }
 
-static struct ast_config *realtime_multi_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
+static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
 {
 	struct mysql_conn *dbh;
 	MYSQL_RES *result;
@@ -429,10 +436,11 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	char *stringp;
 	char *chunk;
 	char *op;
-	const struct ast_variable *field = rt_fields;
+	const char *newparam, *newval;
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 0))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -453,20 +461,23 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		ast_config_destroy(cfg);
 		release_database(dbh);
 		return NULL;
 	}
 
-	initfield = ast_strdupa(field->name);
+	initfield = ast_strdupa(newparam);
 	if ((op = strchr(initfield, ' '))) {
 		*op = '\0';
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
@@ -475,17 +486,18 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' '))
+	if (!strchr(newparam, ' '))
 		op = " =";
 	else
 		op = "";
 
-	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
-	while ((field = field->next)) {
-		if (!strchr(field->name, ' ')) op = " ="; else op = "";
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
+	ESCAPE_STRING(buf, newval);
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
+		if (!strchr(newparam, ' ')) op = " ="; else op = "";
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(buf));
 	}
 
 	if (initfield) {
@@ -497,6 +509,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	/* Execution. */
 	if (mysql_real_query(&dbh->handle, ast_str_buffer(sql), ast_str_strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		va_end(aq);
 		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
@@ -532,20 +545,22 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
+	va_end(aq);
 	release_database(dbh);
 	mysql_free_result(result);
 
 	return cfg;
 }
 
-static int update_mysql(const char *database, const char *tablename, const char *keyfield, const char *lookup, const struct ast_variable *rt_fields)
+static int update_mysql(const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct mysql_conn *dbh;
 	my_ulonglong numrows;
-	const struct ast_variable *field = rt_fields;
+	const char *newparam, *newval;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -572,16 +587,19 @@ static int update_mysql(const char *database, const char *tablename, const char
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime update requires at least 1 parameter and 1 value to update.\n");
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
 	}
 
 	/* Check that the column exists in the table */
-	if (!(column = find_column(table, field->name))) {
-		ast_log(LOG_ERROR, "MySQL RealTime: Updating column '%s', but that column does not exist within the table '%s' (first pair MUST exist)!\n", field->name, tablename);
+	if (!(column = find_column(table, newparam))) {
+		ast_log(LOG_ERROR, "MySQL RealTime: Updating column '%s', but that column does not exist within the table '%s' (first pair MUST exist)!\n", newparam, tablename);
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
@@ -589,6 +607,7 @@ static int update_mysql(const char *database, const char *tablename, const char
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
@@ -597,30 +616,34 @@ static int update_mysql(const char *database, const char *tablename, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, field->name, ast_str_buffer(buf));
+	ESCAPE_STRING(buf, newval);
+	ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, newparam, ast_str_buffer(buf));
 
 	/* If the column length isn't long enough, give a chance to lengthen it. */
 	if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-		internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
+		internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 	}
 
-	while ((field = field->next)) {
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
+
 		/* If the column is not within the table, then skip it */
-		if (!(column = find_column(table, field->name))) {
-			ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
+		if (!(column = find_column(table, newparam))) {
+			ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
 			continue;
 		}
 
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, ", `%s` = '%s'", field->name, ast_str_buffer(buf));
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&sql, 0, ", `%s` = '%s'", newparam, ast_str_buffer(buf));
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
+			internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 		}
 	}
 
+	va_end(aq);
+
 	ESCAPE_STRING(buf, lookup);
 	ast_str_append(&sql, 0, " WHERE `%s` = '%s'", keyfield, ast_str_buffer(buf));
 
@@ -649,16 +672,17 @@ static int update_mysql(const char *database, const char *tablename, const char
 	return (int)numrows;
 }
 
-static int update2_mysql(const char *database, const char *tablename, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int update2_mysql(const char *database, const char *tablename, va_list ap)
 {
 	struct mysql_conn *dbh;
 	my_ulonglong numrows;
 	int first;
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
 	struct ast_str *where = ast_str_thread_get(&sql2_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
+	va_list aq;
 
 	if (!tablename) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
@@ -693,41 +717,60 @@ static int update2_mysql(const char *database, const char *tablename, const stru
 	}
 
 	first = 1;
-	for (field = lookup_fields; field; field = field->next) {
-		if (!(column = find_column(table, field->name))) {
-			ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", field->name, tablename);
+	va_copy(aq, ap);
+	while ((newparam = va_arg(aq, const char *))) {
+		if (!(column = find_column(table, newparam))) {
+			ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
+			va_end(aq);
 			release_table(table);
 			release_database(dbh);
 			return -1;
 		}
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", field->name, ast_str_buffer(buf));
+		if (!(newval = va_arg(aq, const char *))) {
+			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
+			va_end(aq);
+			release_table(table);
+			release_database(dbh);
+			return -1;
+		}
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
 		first = 0;
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
+			internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 		}
 	}
 
 	first = 1;
-	for (field = update_fields; field; field = field->next) {
+	while ((newparam = va_arg(aq, const char *))) {
+		if (!(newval = va_arg(aq, const char *))) {
+			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
+			va_end(aq);
+			release_table(table);
+			release_database(dbh);
+			return -1;
+		}
+
 		/* If the column is not within the table, then skip it */
-		if (!(column = find_column(table, field->name))) {
-			ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
+		if (!(column = find_column(table, newparam))) {
+			ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
 			continue;
 		}
 
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", field->name, ast_str_buffer(buf));
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
 		first = 0;
 
 		/* If the column length isn't long enough, give a chance to lengthen it. */
 		if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
-			internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
+			internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 		}
 	}
 
+	va_end(aq);
+
 	release_table(table);
 
 	ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
@@ -756,14 +799,15 @@ static int update2_mysql(const char *database, const char *tablename, const stru
 	return (int)numrows;
 }
  
-static int store_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
+static int store_mysql(const char *database, const char *table, va_list ap)
 {
 	struct mysql_conn *dbh;
 	my_ulonglong insertid;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
 	struct ast_str *sql2 = ast_str_thread_get(&sql2_buf, 16);
 	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
-	const struct ast_variable *field = rt_fields;
+	const char *newparam, *newval;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -776,32 +820,39 @@ static int store_mysql(const char *database, const char *table, const struct ast
 		return -1;
 	}
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime storage requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		release_database(dbh);
 		return -1;
 	}
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		return -1;
 	}
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 		If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, field->name);
+	ESCAPE_STRING(buf, newval);
+	ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, newparam);
 	ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
 
-	internal_require(database, table, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
-
-	while ((field = field->next)) {
-		ESCAPE_STRING(buf, field->value);
+	internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 
-		if (internal_require(database, table, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
-			ast_str_append(&sql, 0, ", `%s`", field->name);
+	while ((newparam = va_arg(aq, const char *))) {
+		if ((newval = va_arg(aq, const char *))) {
+			ESCAPE_STRING(buf, newval);
+		} else {
+			ast_str_reset(buf);
+		}
+		if (internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
+			ast_str_append(&sql, 0, ", `%s`", newparam);
 			ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
 		}
 	}
+	va_end(aq);
 	ast_str_append(&sql, 0, "%s)", ast_str_buffer(sql2));
 	ast_debug(1,"MySQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql));
 
@@ -826,13 +877,14 @@ static int store_mysql(const char *database, const char *table, const struct ast
 	return (int)insertid;
 }
 
-static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *rt_fields)
+static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct mysql_conn *dbh;
 	my_ulonglong numrows;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
 	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
-	const struct ast_variable *field;
+	const char *newparam, *newval;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -846,8 +898,8 @@ static int destroy_mysql(const char *database, const char *table, const char *ke
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	/* newparam = va_arg(ap, const char *);
-	newval = va_arg(ap, const char *);*/
+	/* newparam = va_arg(aq, const char *);
+	newval = va_arg(aq, const char *);*/
 	if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime destroying requires at least 1 parameter and 1 value to search on.\n");
 		release_database(dbh);
@@ -864,10 +916,13 @@ static int destroy_mysql(const char *database, const char *table, const char *ke
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 	ESCAPE_STRING(buf, lookup);
 	ast_str_set(&sql, 0, "DELETE FROM %s WHERE `%s` = '%s'", table, keyfield, ast_str_buffer(buf));
-	for (field = rt_fields; field; field = field->next) {
-		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, " AND `%s` = '%s'", field->name, ast_str_buffer(buf));
+	va_copy(aq, ap);
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
+		ESCAPE_STRING(buf, newval);
+		ast_str_append(&sql, 0, " AND `%s` = '%s'", newparam, ast_str_buffer(buf));
 	}
+	va_end(aq);
 
 	ast_debug(1, "MySQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
 
@@ -1088,15 +1143,17 @@ static int require_mysql(const char *database, const char *tablename, va_list ap
 	struct tables *table = find_table(database, tablename);
 	char *elm;
 	int type, size, res = 0, table_altered = 0;
+	va_list aq;
 
 	if (!table) {
 		ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
 		return -1;
 	}
 
-	while ((elm = va_arg(ap, char *))) {
-		type = va_arg(ap, require_type);
-		size = va_arg(ap, int);
+	va_copy(aq, ap);
+	while ((elm = va_arg(aq, char *))) {
+		type = va_arg(aq, require_type);
+		size = va_arg(aq, int);
 		AST_LIST_TRAVERSE(&table->columns, column, list) {
 			if (strcmp(column->name, elm) == 0) {
 				/* Char can hold anything, as long as it is large enough */
@@ -1202,38 +1259,44 @@ static int require_mysql(const char *database, const char *tablename, va_list ap
 							PICK_WHICH_ALTER_ACTION(bigint)
 						}
 					}
-				} else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
-					if (table->database->requirements == RQ_WARN) {
-						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-						res = -1;
-					} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-						table_altered = 1;
-					} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-						table_altered = 1;
-					} else {
-						res = -1;
+				} else if (strncmp(column->type, "float", 5) == 0) {
+					if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
+						if (table->database->requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+							res = -1;
+						} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					}
-				} else if ((strncmp(column->type, "datetime", 8) == 0 || strncmp(column->type, "timestamp", 9) == 0) && type != RQ_DATETIME) {
-					if (table->database->requirements == RQ_WARN) {
-						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-						res = -1;
-					} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-						table_altered = 1;
-					} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-						table_altered = 1;
-					} else {
-						res = -1;
+				} else if (strncmp(column->type, "datetime", 8) == 0 || strncmp(column->type, "timestamp", 9) == 0) {
+					if (type != RQ_DATETIME) {
+						if (table->database->requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+							res = -1;
+						} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					}
-				} else if ((strncmp(column->type, "date", 4) == 0) && type != RQ_DATE) {
-					if (table->database->requirements == RQ_WARN) {
-						ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-						res = -1;
-					} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-						table_altered = 1;
-					} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-						table_altered = 1;
-					} else {
-						res = -1;
+				} else if (strncmp(column->type, "date", 4) == 0) {
+					if (type != RQ_DATE) {
+						if (table->database->requirements == RQ_WARN) {
+							ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+							res = -1;
+						} else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+							table_altered = 1;
+						} else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+							table_altered = 1;
+						} else {
+							res = -1;
+						}
 					}
 				} else { /* Other, possibly unsupported types? */
 					if (table->database->requirements == RQ_WARN) {
@@ -1317,6 +1380,7 @@ static int require_mysql(const char *database, const char *tablename, va_list ap
 			}
 		}
 	}
+	va_end(aq);
 	release_table(table);
 
 	/* If we altered the table, we must refresh the cache */
@@ -1748,7 +1812,6 @@ static char *handle_cli_realtime_mysql_status(struct ast_cli_entry *e, int cmd,
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MySQL RealTime Configuration Driver",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/agi/.gitignore b/agi/.gitignore
new file mode 100644
index 0000000..9b2a4e2
--- /dev/null
+++ b/agi/.gitignore
@@ -0,0 +1,3 @@
+eagi-sphinx-test
+eagi-test
+strcompat.c
diff --git a/agi/Makefile b/agi/Makefile
index 8a21860..fd5219f 100644
--- a/agi/Makefile
+++ b/agi/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for AGI-related stuff
 #
diff --git a/apps/Makefile b/apps/Makefile
index 1d5d2b3..598bcea 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for PBX applications
 #
@@ -28,12 +28,13 @@ all: _all
 include $(ASTTOPDIR)/Makefile.moddir_rules
 
 clean::
-	rm -f confbridge/*.o confbridge/*.i
+	rm -f confbridge/*.o confbridge/*.i confbridge/*.gcda confbridge/*.gcno
 
 $(if $(filter app_confbridge,$(EMBEDDED_MODS)),modules.link,app_confbridge.so): $(subst .c,.o,$(wildcard confbridge/*.c))
 $(subst .c,.o,$(wildcard confbridge/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,app_confbridge)
 
 ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
-  LIBS+= -lres_features.so -lres_ael_share.so -lres_monitor.so -lres_speech.so
+  LIBS+= -lres_ael_share.so -lres_monitor.so -lres_speech.so
   LIBS+= -lres_smdi.so
 endif
+
diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c
index 63c544d..3defaef 100644
--- a/apps/app_adsiprog.c
+++ b/apps/app_adsiprog.c
@@ -25,15 +25,6 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_adsiprog.c uses the configuration file \ref adsi.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page adsi.conf adsi.conf
- * \verbinclude adsi.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>res_adsi</depend>
 	<support_level>extended</support_level>
@@ -41,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <netinet/in.h>
 #include <ctype.h>
@@ -1456,7 +1447,7 @@ static void dump_message(char *type, char *vname, unsigned char *buf, int buflen
 	int x;
 	printf("%s %s: [ ", type, vname);
 	for (x = 0; x < buflen; x++)
-		printf("%02x ", buf[x]);
+		printf("%02hhx ", buf[x]);
 	printf("]\n");
 }
 #endif
@@ -1594,16 +1585,6 @@ static int unload_module(void)
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (ast_register_application_xml(app, adsi_exec))
@@ -1612,7 +1593,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk ADSI Programming Application",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.nonoptreq = "res_adsi",
diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c
deleted file mode 100644
index 0611b64..0000000
--- a/apps/app_agent_pool.c
+++ /dev/null
@@ -1,2707 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Call center agent pool.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- * \arg \ref Config_agent
- */
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427512 $")
-
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/config_options.h"
-#include "asterisk/features_config.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/causes.h"
-
-/*** DOCUMENTATION
-	<application name="AgentLogin" language="en_US">
-		<synopsis>
-			Login an agent.
-		</synopsis>
-		<syntax argsep=",">
-			<parameter name="AgentId" required="true" />
-			<parameter name="options">
-				<optionlist>
-					<option name="s">
-						<para>silent login - do not announce the login ok segment after
-						agent logged on.</para>
-					</option>
-				</optionlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Login an agent to the system.  Any agent authentication is assumed to
-			already be done by dialplan.  While logged in, the agent can receive calls
-			and will hear the sound file specified by the config option custom_beep
-			when a new call comes in for the agent.  Login failures will continue in
-			the dialplan with <variable>AGENT_STATUS</variable> set.</para>
-			<para>Before logging in, you can setup on the real agent channel the
-			CHANNEL(dtmf-features) an agent will have when talking to a caller
-			and you can setup on the channel running this application the
-			CONNECTEDLINE() information the agent will see while waiting for a
-			caller.</para>
-			<para><variable>AGENT_STATUS</variable> enumeration values:</para>
-			<enumlist>
-				<enum name = "INVALID"><para>The specified agent is invalid.</para></enum>
-				<enum name = "ALREADY_LOGGED_IN"><para>The agent is already logged in.</para></enum>
-			</enumlist>
-			<note><para>The Agents:<replaceable>AgentId</replaceable> device state is
-			available to monitor the status of the agent.</para></note>
-		</description>
-		<see-also>
-			<ref type="application">Authenticate</ref>
-			<ref type="application">Queue</ref>
-			<ref type="application">AddQueueMember</ref>
-			<ref type="application">RemoveQueueMember</ref>
-			<ref type="application">PauseQueueMember</ref>
-			<ref type="application">UnpauseQueueMember</ref>
-			<ref type="function">AGENT</ref>
-			<ref type="function">CHANNEL(dtmf-features)</ref>
-			<ref type="function">CONNECTEDLINE()</ref>
-			<ref type="filename">agents.conf</ref>
-			<ref type="filename">queues.conf</ref>
-		</see-also>
-	</application>
-	<application name="AgentRequest" language="en_US">
-		<synopsis>
-			Request an agent to connect with the channel.
-		</synopsis>
-		<syntax argsep=",">
-			<parameter name="AgentId" required="true" />
-		</syntax>
-		<description>
-			<para>Request an agent to connect with the channel.  Failure to find,
-			alert the agent, or acknowledge the call will continue in the dialplan
-			with <variable>AGENT_STATUS</variable> set.</para>
-			<para><variable>AGENT_STATUS</variable> enumeration values:</para>
-			<enumlist>
-				<enum name = "INVALID"><para>The specified agent is invalid.</para></enum>
-				<enum name = "NOT_LOGGED_IN"><para>The agent is not available.</para></enum>
-				<enum name = "BUSY"><para>The agent is on another call.</para></enum>
-				<enum name = "NOT_CONNECTED"><para>The agent did not connect with the
-				call.  The agent most likely did not acknowledge the call.</para></enum>
-				<enum name = "ERROR"><para>Alerting the agent failed.</para></enum>
-			</enumlist>
-		</description>
-		<see-also>
-			<ref type="application">AgentLogin</ref>
-		</see-also>
-	</application>
-	<function name="AGENT" language="en_US">
-		<synopsis>
-			Gets information about an Agent
-		</synopsis>
-		<syntax argsep=":">
-			<parameter name="AgentId" required="true" />
-			<parameter name="item">
-				<para>The valid items to retrieve are:</para>
-				<enumlist>
-					<enum name="status">
-						<para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
-					</enum>
-					<enum name="password">
-						<para>Deprecated.  The dialplan handles any agent authentication.</para>
-					</enum>
-					<enum name="name">
-						<para>The name of the agent</para>
-					</enum>
-					<enum name="mohclass">
-						<para>MusicOnHold class</para>
-					</enum>
-					<enum name="channel">
-						<para>The name of the active channel for the Agent (AgentLogin)</para>
-					</enum>
-					<enum name="fullchannel">
-						<para>The untruncated name of the active channel for the Agent (AgentLogin)</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description></description>
-	</function>
-	<manager name="Agents" language="en_US">
-		<synopsis>
-			Lists agents and their status.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>Will list info about all defined agents.</para>
-		</description>
-		<see-also>
-			<ref type="managerEvent">Agents</ref>
-			<ref type="managerEvent">AgentsComplete</ref>
-		</see-also>
-	</manager>
-	<managerEvent language="en_US" name="Agents">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>
-				Response event in a series to the Agents AMI action containing
-				information about a defined agent.
-			</synopsis>
-			<syntax>
-				<parameter name="Agent">
-					<para>Agent ID of the agent.</para>
-				</parameter>
-				<parameter name="Name">
-					<para>User friendly name of the agent.</para>
-				</parameter>
-				<parameter name="Status">
-					<para>Current status of the agent.</para>
-					<para>The valid values are:</para>
-					<enumlist>
-						<enum name="AGENT_LOGGEDOFF" />
-						<enum name="AGENT_IDLE" />
-						<enum name="AGENT_ONCALL" />
-					</enumlist>
-				</parameter>
-				<parameter name="TalkingToChan">
-					<para><variable>BRIDGEPEER</variable> value on agent channel.</para>
-					<para>Present if Status value is <literal>AGENT_ONCALL</literal>.</para>
-				</parameter>
-				<parameter name="CallStarted">
-					<para>Epoche time when the agent started talking with the caller.</para>
-					<para>Present if Status value is <literal>AGENT_ONCALL</literal>.</para>
-				</parameter>
-				<parameter name="LoggedInTime">
-					<para>Epoche time when the agent logged in.</para>
-					<para>Present if Status value is <literal>AGENT_IDLE</literal> or <literal>AGENT_ONCALL</literal>.</para>
-				</parameter>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			</syntax>
-			<description>
-				<para>The channel snapshot is present if the Status value is <literal>AGENT_IDLE</literal> or <literal>AGENT_ONCALL</literal>.</para>
-			</description>
-			<see-also>
-				<ref type="manager">Agents</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentsComplete">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>
-				Final response event in a series of events to the Agents AMI action.
-			</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			</syntax>
-			<see-also>
-				<ref type="manager">Agents</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="AgentLogoff" language="en_US">
-		<synopsis>
-			Sets an agent as no longer logged in.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Agent" required="true">
-				<para>Agent ID of the agent to log off.</para>
-			</parameter>
-			<parameter name="Soft">
-				<para>Set to <literal>true</literal> to not hangup existing calls.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Sets an agent as no longer logged in.</para>
-		</description>
-	</manager>
-	<configInfo name="app_agent_pool" language="en_US">
-		<synopsis>Agent pool applications</synopsis>
-		<description>
-			<note><para>Option changes take effect on agent login or after an agent
-			disconnects from a call.</para></note>
-		</description>
-		<configFile name="agents.conf">
-			<configObject name="global">
-				<synopsis>Unused, but reserved.</synopsis>
-			</configObject>
-			<configObject name="agent-id">
-				<synopsis>Configure an agent for the pool.</synopsis>
-				<description>
-					<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-				</description>
-				<configOption name="ackcall">
-					<synopsis>Enable to require the agent to acknowledge a call.</synopsis>
-					<description>
-						<para>Enable to require the agent to give a DTMF acknowledgement
-						when the agent receives a call.</para>
-						<note><para>The option is overridden by <variable>AGENTACKCALL</variable> on agent login.</para></note>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="acceptdtmf">
-					<synopsis>DTMF key sequence the agent uses to acknowledge a call.</synopsis>
-					<description>
-						<note><para>The option is overridden by <variable>AGENTACCEPTDTMF</variable> on agent login.</para></note>
-						<note><para>The option is ignored unless the ackcall option is enabled.</para></note>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="autologoff">
-					<synopsis>Time the agent has to acknowledge a call before being logged off.</synopsis>
-					<description>
-						<para>Set how many seconds a call for the agent has to wait for the
-						agent to acknowledge the call before the agent is automatically
-						logged off.  If set to zero then the call will wait forever for
-						the agent to acknowledge.</para>
-						<note><para>The option is overridden by <variable>AGENTAUTOLOGOFF</variable> on agent login.</para></note>
-						<note><para>The option is ignored unless the ackcall option is enabled.</para></note>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="wrapuptime">
-					<synopsis>Minimum time the agent has between calls.</synopsis>
-					<description>
-						<para>Set the minimum amount of time in milliseconds after
-						disconnecting a call before the agent can receive a new call.</para>
-						<note><para>The option is overridden by <variable>AGENTWRAPUPTIME</variable> on agent login.</para></note>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="musiconhold">
-					<synopsis>Music on hold class the agent listens to between calls.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="recordagentcalls">
-					<synopsis>Enable to automatically record calls the agent takes.</synopsis>
-					<description>
-						<para>Enable recording calls the agent takes automatically by
-						invoking the automixmon DTMF feature when the agent connects
-						to a caller.  See <filename>features.conf.sample</filename> for information about
-						the automixmon feature.</para>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="custom_beep">
-					<synopsis>Sound file played to alert the agent when a call is present.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-				<configOption name="fullname">
-					<synopsis>A friendly name for the agent used in log messages.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-/* ------------------------------------------------------------------- */
-
-#define AST_MAX_BUF	256
-
-/*! Maximum wait time (in ms) for the custom_beep file to play announcing the caller. */
-#define CALLER_SAFETY_TIMEOUT_TIME	(2 * 60 * 1000)
-
-/*! Number of seconds to wait for local channel optimizations to complete. */
-#define LOGIN_WAIT_TIMEOUT_TIME		5
-
-static const char app_agent_login[] = "AgentLogin";
-static const char app_agent_request[] = "AgentRequest";
-
-/*! Agent config parameters. */
-struct agent_cfg {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Identification of the agent.  (agents config container key) */
-		AST_STRING_FIELD(username);
-		/*! Name of agent for logging and querying purposes */
-		AST_STRING_FIELD(full_name);
-
-		/*!
-		 * \brief DTMF string for an agent to accept a call.
-		 *
-		 * \note The channel variable AGENTACCEPTDTMF overrides on login.
-		 */
-		AST_STRING_FIELD(dtmf_accept);
-		/*! Beep sound file to use.  Alert the agent a call is waiting. */
-		AST_STRING_FIELD(beep_sound);
-		/*! MOH class to use while agent waiting for call. */
-		AST_STRING_FIELD(moh);
-	);
-	/*!
-	 * \brief Number of seconds for agent to ack a call before being logged off.
-	 *
-	 * \note The channel variable AGENTAUTOLOGOFF overrides on login.
-	 * \note If zero then timer is disabled.
-	 */
-	unsigned int auto_logoff;
-	/*!
-	 * \brief Time after a call in ms before the agent can get a new call.
-	 *
-	 * \note The channel variable AGENTWRAPUPTIME overrides on login.
-	 */
-	unsigned int wrapup_time;
-	/*!
-	 * \brief TRUE if agent needs to ack a call to accept it.
-	 *
-	 * \note The channel variable AGENTACKCALL overrides on login.
-	 */
-	int ack_call;
-	/*! TRUE if agent calls are automatically recorded. */
-	int record_agent_calls;
-};
-
-/*!
- * \internal
- * \brief Agent config ao2 container sort function.
- * \since 12.0.0
- *
- * \param obj_left pointer to the (user-defined part) of an object.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- *
- * \retval <0 if obj_left < obj_right
- * \retval =0 if obj_left == obj_right
- * \retval >0 if obj_left > obj_right
- */
-static int agent_cfg_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct agent_cfg *cfg_left = obj_left;
-	const struct agent_cfg *cfg_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_key = cfg_right->username;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(cfg_left->username, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(cfg_left->username, right_key, strlen(right_key));
-		break;
-	}
-	return cmp;
-}
-
-static void agent_cfg_destructor(void *vdoomed)
-{
-	struct agent_cfg *doomed = vdoomed;
-
-	ast_string_field_free_memory(doomed);
-}
-
-static void *agent_cfg_alloc(const char *name)
-{
-	struct agent_cfg *cfg;
-
-	cfg = ao2_alloc_options(sizeof(*cfg), agent_cfg_destructor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!cfg || ast_string_field_init(cfg, 64)) {
-		return NULL;
-	}
-	ast_string_field_set(cfg, username, name);
-	return cfg;
-}
-
-static void *agent_cfg_find(struct ao2_container *agents, const char *username)
-{
-	return ao2_find(agents, username, OBJ_KEY);
-}
-
-/*! Agents configuration */
-struct agents_cfg {
-	/*! Master configured agents container. */
-	struct ao2_container *agents;
-};
-
-static struct aco_type agent_type = {
-	.type = ACO_ITEM,
-	.name = "agent-id",
-	.category_match = ACO_BLACKLIST,
-	.category = "^(general|agents)$",
-	.item_alloc = agent_cfg_alloc,
-	.item_find = agent_cfg_find,
-	.item_offset = offsetof(struct agents_cfg, agents),
-};
-
-static struct aco_type *agent_types[] = ACO_TYPES(&agent_type);
-
-/* The general category is reserved, but unused */
-static struct aco_type general_type = {
-	.type = ACO_GLOBAL,
-	.name = "global",
-	.category_match = ACO_WHITELIST,
-	.category = "^general$",
-};
-
-static struct aco_file agents_conf = {
-	.filename = "agents.conf",
-	.types = ACO_TYPES(&general_type, &agent_type),
-};
-
-static AO2_GLOBAL_OBJ_STATIC(cfg_handle);
-
-static void agents_cfg_destructor(void *vdoomed)
-{
-	struct agents_cfg *doomed = vdoomed;
-
-	ao2_cleanup(doomed->agents);
-	doomed->agents = NULL;
-}
-
-/*!
- * \internal
- * \brief Create struct agents_cfg object.
- * \since 12.0.0
- *
- * \note A lock is not needed for the object or any secondary
- * created cfg objects.  These objects are immutable after the
- * config is loaded and applied.
- *
- * \retval New struct agents_cfg object.
- * \retval NULL on error.
- */
-static void *agents_cfg_alloc(void)
-{
-	struct agents_cfg *cfg;
-
-	cfg = ao2_alloc_options(sizeof(*cfg), agents_cfg_destructor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!cfg) {
-		return NULL;
-	}
-	cfg->agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, agent_cfg_sort_cmp, NULL);
-	if (!cfg->agents) {
-		ao2_ref(cfg, -1);
-		cfg = NULL;
-	}
-	return cfg;
-}
-
-static void agents_post_apply_config(void);
-
-CONFIG_INFO_STANDARD(cfg_info, cfg_handle, agents_cfg_alloc,
-	.files = ACO_FILES(&agents_conf),
-	.post_apply_config = agents_post_apply_config,
-);
-
-static void destroy_config(void)
-{
-	ao2_global_obj_release(cfg_handle);
-	aco_info_destroy(&cfg_info);
-}
-
-static int load_config(void)
-{
-	if (aco_info_init(&cfg_info)) {
-		return -1;
-	}
-
-	/* Agent options */
-	aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
-	aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 1, STRFLDSET(struct agent_cfg, dtmf_accept));
-	aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
-	aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapup_time));
-	aco_option_register(&cfg_info, "musiconhold", ACO_EXACT, agent_types, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, moh));
-	aco_option_register(&cfg_info, "recordagentcalls", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, record_agent_calls));
-	aco_option_register(&cfg_info, "custom_beep", ACO_EXACT, agent_types, "beep", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, beep_sound));
-	aco_option_register(&cfg_info, "fullname", ACO_EXACT, agent_types, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, full_name));
-
-	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
-		goto error;
-	}
-
-	return 0;
-
-error:
-	destroy_config();
-	return -1;
-}
-
-enum agent_state {
-	/*! The agent is defined but an agent is not present. */
-	AGENT_STATE_LOGGED_OUT,
-	/*! Forced initial login wait to allow any local channel optimizations to happen. */
-	AGENT_STATE_PROBATION_WAIT,
-	/*! The agent is ready for a call. */
-	AGENT_STATE_READY_FOR_CALL,
-	/*! The agent has a call waiting to connect. */
-	AGENT_STATE_CALL_PRESENT,
-	/*! The agent needs to ack the call. */
-	AGENT_STATE_CALL_WAIT_ACK,
-	/*! The agent is connected with a call. */
-	AGENT_STATE_ON_CALL,
-	/*! The agent is resting between calls. */
-	AGENT_STATE_CALL_WRAPUP,
-	/*! The agent is being kicked out. */
-	AGENT_STATE_LOGGING_OUT,
-};
-
-/*! Agent config option override flags. */
-enum agent_override_flags {
-	AGENT_FLAG_ACK_CALL = (1 << 0),
-	AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
-	AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
-	AGENT_FLAG_WRAPUP_TIME = (1 << 3),
-};
-
-/*! \brief Structure representing an agent. */
-struct agent_pvt {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Identification of the agent.  (agents container key) */
-		AST_STRING_FIELD(username);
-		/*! Login override DTMF string for an agent to accept a call. */
-		AST_STRING_FIELD(override_dtmf_accept);
-	);
-	/*! Connected line information to send when reentering the holding bridge. */
-	struct ast_party_connected_line waiting_colp;
-	/*! Flags show if settings were overridden by channel vars. */
-	unsigned int flags;
-	/*! Login override number of seconds for agent to ack a call before being logged off. */
-	unsigned int override_auto_logoff;
-	/*! Login override time after a call in ms before the agent can get a new call. */
-	unsigned int override_wrapup_time;
-	/*! Login override if agent needs to ack a call to accept it. */
-	unsigned int override_ack_call:1;
-
-	/*! TRUE if the agent is requested to logoff when the current call ends. */
-	unsigned int deferred_logoff:1;
-
-	/*! Mark and sweep config update to determine if an agent is dead. */
-	unsigned int the_mark:1;
-	/*!
-	 * \brief TRUE if the agent is no longer configured and is being destroyed.
-	 *
-	 * \note Agents cannot log in if they are dead.
-	 */
-	unsigned int dead:1;
-
-	/*! Agent control state variable. */
-	enum agent_state state;
-	/*! Custom device state of agent. */
-	enum ast_device_state devstate;
-
-	/*! When agent first logged in */
-	time_t login_start;
-	/*! When agent login probation started. */
-	time_t probation_start;
-	/*! When call started */
-	time_t call_start;
-	/*! When ack timer started */
-	struct timeval ack_time;
-	/*! When last disconnected */
-	struct timeval last_disconnect;
-
-	/*! Caller is waiting in this bridge for agent to join. (Holds ref) */
-	struct ast_bridge *caller_bridge;
-	/*! Agent is logged in with this channel. (Holds ref) (NULL if not logged in.) */
-	struct ast_channel *logged;
-	/*! Active config values from config file. (Holds ref) */
-	struct agent_cfg *cfg;
-};
-
-/*! Container of defined agents. */
-static struct ao2_container *agents;
-
-/*!
- * \brief Lock the agent.
- *
- * \param agent Agent to lock
- *
- * \return Nothing
- */
-#define agent_lock(agent)	_agent_lock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
-static inline void _agent_lock(struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_lock(agent, AO2_LOCK_REQ_MUTEX, file, function, line, var);
-}
-
-/*!
- * \brief Unlock the agent.
- *
- * \param agent Agent to unlock
- *
- * \return Nothing
- */
-#define agent_unlock(agent)	_agent_unlock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
-static inline void _agent_unlock(struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_unlock(agent, file, function, line, var);
-}
-
-/*!
- * \internal
- * \brief Obtain the agent logged in channel lock if it exists.
- * \since 12.0.0
- *
- * \param agent Pointer to the LOCKED agent_pvt.
- *
- * \note Assumes the agent lock is already obtained.
- *
- * \note Defined locking order is channel lock then agent lock.
- *
- * \return Nothing
- */
-static struct ast_channel *agent_lock_logged(struct agent_pvt *agent)
-{
-	struct ast_channel *logged;
-
-	for (;;) {
-		if (!agent->logged) { /* No owner. Nothing to do. */
-			return NULL;
-		}
-
-		/* If we don't ref the logged, it could be killed when we unlock the agent. */
-		logged = ast_channel_ref(agent->logged);
-
-		/* Locking logged requires us to lock channel, then agent. */
-		agent_unlock(agent);
-		ast_channel_lock(logged);
-		agent_lock(agent);
-
-		/* Check if logged changed during agent unlock period */
-		if (logged != agent->logged) {
-			/* Channel changed. Unref and do another pass. */
-			ast_channel_unlock(logged);
-			ast_channel_unref(logged);
-		} else {
-			/* Channel stayed the same. Return it. */
-			return logged;
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Get the Agent:agent_id device state.
- * \since 12.0.0
- *
- * \param agent_id Username of the agent.
- *
- * \details
- * Search the agents container for the agent and return the
- * current state.
- *
- * \return Device state of the agent.
- */
-static enum ast_device_state agent_pvt_devstate_get(const char *agent_id)
-{
-	RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
-
-	if (agent) {
-		return agent->devstate;
-	}
-	return AST_DEVICE_INVALID;
-}
-
-/*!
- * \internal
- * \brief Request an agent device state be updated.
- * \since 12.0.0
- *
- * \param agent_id Which agent needs the device state updated.
- *
- * \return Nothing
- */
-static void agent_devstate_changed(const char *agent_id)
-{
-	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Agent:%s", agent_id);
-}
-
-static void agent_pvt_destructor(void *vdoomed)
-{
-	struct agent_pvt *doomed = vdoomed;
-
-	/* Make sure device state reflects agent destruction. */
-	if (!ast_strlen_zero(doomed->username)) {
-		ast_debug(1, "Agent %s: Destroyed.\n", doomed->username);
-		agent_devstate_changed(doomed->username);
-	}
-
-	ast_party_connected_line_free(&doomed->waiting_colp);
-	if (doomed->caller_bridge) {
-		ast_bridge_destroy(doomed->caller_bridge, 0);
-		doomed->caller_bridge = NULL;
-	}
-	if (doomed->logged) {
-		doomed->logged = ast_channel_unref(doomed->logged);
-	}
-	ao2_cleanup(doomed->cfg);
-	doomed->cfg = NULL;
-	ast_string_field_free_memory(doomed);
-}
-
-static struct agent_pvt *agent_pvt_new(struct agent_cfg *cfg)
-{
-	struct agent_pvt *agent;
-
-	agent = ao2_alloc(sizeof(*agent), agent_pvt_destructor);
-	if (!agent) {
-		return NULL;
-	}
-	if (ast_string_field_init(agent, 32)) {
-		ao2_ref(agent, -1);
-		return NULL;
-	}
-	ast_string_field_set(agent, username, cfg->username);
-	ast_party_connected_line_init(&agent->waiting_colp);
-	ao2_ref(cfg, +1);
-	agent->cfg = cfg;
-	agent->devstate = AST_DEVICE_UNAVAILABLE;
-	return agent;
-}
-
-/*!
- * \internal
- * \brief Agents ao2 container sort function.
- * \since 12.0.0
- *
- * \param obj_left pointer to the (user-defined part) of an object.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- *
- * \retval <0 if obj_left < obj_right
- * \retval =0 if obj_left == obj_right
- * \retval >0 if obj_left > obj_right
- */
-static int agent_pvt_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct agent_pvt *agent_left = obj_left;
-	const struct agent_pvt *agent_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_key = agent_right->username;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(agent_left->username, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(agent_left->username, right_key, strlen(right_key));
-		break;
-	}
-	return cmp;
-}
-
-/*!
- * \internal
- * \brief ao2_find() callback function.
- * \since 12.0.0
- *
- * Usage:
- * found = ao2_find(agents, agent, OBJ_POINTER);
- * found = ao2_find(agents, "agent-id", OBJ_KEY);
- * found = ao2_find(agents, agent->logged, 0);
- */
-static int agent_pvt_cmp(void *obj, void *arg, int flags)
-{
-	const struct agent_pvt *agent = obj;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_POINTER:
-	case OBJ_KEY:
-	case OBJ_PARTIAL_KEY:
-		cmp = CMP_MATCH;
-		break;
-	default:
-		if (agent->logged == arg) {
-			cmp = CMP_MATCH;
-		} else {
-			cmp = 0;
-		}
-		break;
-	}
-	return cmp;
-}
-
-static int agent_mark(void *obj, void *arg, int flags)
-{
-	struct agent_pvt *agent = obj;
-
-	agent_lock(agent);
-	agent->the_mark = 1;
-	agent_unlock(agent);
-	return 0;
-}
-
-static void agents_mark(void)
-{
-	ao2_callback(agents, 0, agent_mark, NULL);
-}
-
-static int agent_sweep(void *obj, void *arg, int flags)
-{
-	struct agent_pvt *agent = obj;
-	int cmp = 0;
-
-	agent_lock(agent);
-	if (agent->the_mark) {
-		agent->the_mark = 0;
-		agent->dead = 1;
-		/* Unlink dead agents immediately. */
-		cmp = CMP_MATCH;
-	}
-	agent_unlock(agent);
-	return cmp;
-}
-
-static void agents_sweep(void)
-{
-	struct ao2_iterator *iter;
-	struct agent_pvt *agent;
-	struct ast_channel *logged;
-
-	iter = ao2_callback(agents, OBJ_MULTIPLE | OBJ_UNLINK, agent_sweep, NULL);
-	if (!iter) {
-		return;
-	}
-	for (; (agent = ao2_iterator_next(iter)); ao2_ref(agent, -1)) {
-		agent_lock(agent);
-		if (agent->logged) {
-			logged = ast_channel_ref(agent->logged);
-		} else {
-			logged = NULL;
-		}
-		agent_unlock(agent);
-		if (!logged) {
-			continue;
-		}
-		ast_log(LOG_NOTICE,
-			"Forced logoff of agent %s(%s).  Agent no longer configured.\n",
-			agent->username, ast_channel_name(logged));
-		ast_softhangup(logged, AST_SOFTHANGUP_EXPLICIT);
-		ast_channel_unref(logged);
-	}
-	ao2_iterator_destroy(iter);
-}
-
-static void agents_post_apply_config(void)
-{
-	struct ao2_iterator iter;
-	struct agent_cfg *cfg;
-	RAII_VAR(struct agents_cfg *, cfgs, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
-
-	ast_assert(cfgs != NULL);
-
-	agents_mark();
-	iter = ao2_iterator_init(cfgs->agents, 0);
-	for (; (cfg = ao2_iterator_next(&iter)); ao2_ref(cfg, -1)) {
-		RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, cfg->username, OBJ_KEY), ao2_cleanup);
-
-		if (agent) {
-			agent_lock(agent);
-			agent->the_mark = 0;
-			if (!agent->logged) {
-				struct agent_cfg *cfg_old;
-
-				/* Replace the config of agents not logged in. */
-				cfg_old = agent->cfg;
-				ao2_ref(cfg, +1);
-				agent->cfg = cfg;
-				ao2_cleanup(cfg_old);
-			}
-			agent_unlock(agent);
-			continue;
-		}
-		agent = agent_pvt_new(cfg);
-		if (!agent) {
-			continue;
-		}
-		ao2_link(agents, agent);
-		ast_debug(1, "Agent %s: Created.\n", agent->username);
-		agent_devstate_changed(agent->username);
-	}
-	ao2_iterator_destroy(&iter);
-	agents_sweep();
-}
-
-static int agent_logoff_request(const char *agent_id, int soft)
-{
-	struct ast_channel *logged;
-	RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
-
-	if (!agent) {
-		return -1;
-	}
-
-	agent_lock(agent);
-	logged = agent_lock_logged(agent);
-	if (logged) {
-		if (soft) {
-			agent->deferred_logoff = 1;
-		} else {
-			ast_softhangup(logged, AST_SOFTHANGUP_EXPLICIT);
-		}
-		ast_channel_unlock(logged);
-		ast_channel_unref(logged);
-	}
-	agent_unlock(agent);
-	return 0;
-}
-
-/*! Agent holding bridge instance holder. */
-static AO2_GLOBAL_OBJ_STATIC(agent_holding);
-
-/*! Agent holding bridge deferred creation lock. */
-AST_MUTEX_DEFINE_STATIC(agent_holding_lock);
-
-/*!
- * \internal
- * \brief Callback to clear AGENT_STATUS on the caller channel.
- *
- * \param bridge_channel Which channel to operate on.
- * \param payload Data to pass to the callback. (NULL if none).
- * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
- *
- * \note The payload MUST NOT have any resources that need to be freed.
- *
- * \return Nothing
- */
-static void clear_agent_status(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
-{
-	pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", NULL);
-}
-
-/*!
- * \internal
- * \brief Connect the agent with the waiting caller.
- * \since 12.0.0
- *
- * \param bridge_channel Agent channel connecting to the caller.
- * \param agent Which agent is connecting to the caller.
- *
- * \note The agent is locked on entry and not locked on exit.
- *
- * \return Nothing
- */
-static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, struct agent_pvt *agent)
-{
-	struct ast_bridge *caller_bridge;
-	int record_agent_calls;
-	int res;
-
-	record_agent_calls = agent->cfg->record_agent_calls;
-	caller_bridge = agent->caller_bridge;
-	agent->caller_bridge = NULL;
-	agent->state = AGENT_STATE_ON_CALL;
-	time(&agent->call_start);
-	agent_unlock(agent);
-
-	if (!caller_bridge) {
-		/* Reset agent. */
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-			AST_CAUSE_NORMAL_CLEARING);
-		return;
-	}
-	res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
-		NULL, 0);
-	if (res) {
-		/* Reset agent. */
-		ast_bridge_destroy(caller_bridge, 0);
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-			AST_CAUSE_NORMAL_CLEARING);
-		return;
-	}
-	res = ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_ANSWER, NULL, 0)
-		|| ast_bridge_channel_write_callback(bridge_channel, 0, clear_agent_status, NULL, 0);
-	if (res) {
-		/* Reset agent. */
-		ast_bridge_destroy(caller_bridge, 0);
-		return;
-	}
-
-	if (record_agent_calls) {
-		struct ast_bridge_features_automixmonitor options = {
-			.start_stop = AUTO_MONITOR_START,
-			};
-
-		/*
-		 * The agent is in the new bridge so we can invoke the
-		 * mixmonitor hook to only start recording.
-		 */
-		ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, bridge_channel, &options);
-	}
-
-	ao2_t_ref(caller_bridge, -1, "Agent successfully in caller_bridge");
-}
-
-static int bridge_agent_hold_ack(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct agent_pvt *agent = hook_pvt;
-
-	agent_lock(agent);
-	switch (agent->state) {
-	case AGENT_STATE_CALL_WAIT_ACK:
-		/* Connect to caller now. */
-		ast_debug(1, "Agent %s: Acked call.\n", agent->username);
-		agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
-		return 0;
-	default:
-		break;
-	}
-	agent_unlock(agent);
-	return 0;
-}
-
-static int bridge_agent_hold_heartbeat(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct agent_pvt *agent = hook_pvt;
-	int probation_timedout = 0;
-	int ack_timedout = 0;
-	int wrapup_timedout = 0;
-	int deferred_logoff;
-	unsigned int wrapup_time;
-	unsigned int auto_logoff;
-
-	agent_lock(agent);
-	deferred_logoff = agent->deferred_logoff;
-	if (deferred_logoff) {
-		agent->state = AGENT_STATE_LOGGING_OUT;
-	}
-
-	switch (agent->state) {
-	case AGENT_STATE_PROBATION_WAIT:
-		probation_timedout =
-			LOGIN_WAIT_TIMEOUT_TIME <= (time(NULL) - agent->probation_start);
-		if (probation_timedout) {
-			/* Now ready for a caller. */
-			agent->state = AGENT_STATE_READY_FOR_CALL;
-			agent->devstate = AST_DEVICE_NOT_INUSE;
-		}
-		break;
-	case AGENT_STATE_CALL_WAIT_ACK:
-		/* Check ack call time. */
-		auto_logoff = agent->cfg->auto_logoff;
-		if (ast_test_flag(agent, AGENT_FLAG_AUTO_LOGOFF)) {
-			auto_logoff = agent->override_auto_logoff;
-		}
-		if (auto_logoff) {
-			auto_logoff *= 1000;
-			ack_timedout = ast_tvdiff_ms(ast_tvnow(), agent->ack_time) > auto_logoff;
-			if (ack_timedout) {
-				agent->state = AGENT_STATE_LOGGING_OUT;
-			}
-		}
-		break;
-	case AGENT_STATE_CALL_WRAPUP:
-		/* Check wrapup time. */
-		wrapup_time = agent->cfg->wrapup_time;
-		if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
-			wrapup_time = agent->override_wrapup_time;
-		}
-		wrapup_timedout = ast_tvdiff_ms(ast_tvnow(), agent->last_disconnect) > wrapup_time;
-		if (wrapup_timedout) {
-			agent->state = AGENT_STATE_READY_FOR_CALL;
-			agent->devstate = AST_DEVICE_NOT_INUSE;
-		}
-		break;
-	default:
-		break;
-	}
-	agent_unlock(agent);
-
-	if (deferred_logoff) {
-		ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-			AST_CAUSE_NORMAL_CLEARING);
-	} else if (probation_timedout) {
-		ast_debug(1, "Agent %s: Login complete.\n", agent->username);
-		agent_devstate_changed(agent->username);
-	} else if (ack_timedout) {
-		ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-			AST_CAUSE_NORMAL_CLEARING);
-	} else if (wrapup_timedout) {
-		ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
-		agent_devstate_changed(agent->username);
-	}
-
-	return 0;
-}
-
-static void agent_after_bridge_cb(struct ast_channel *chan, void *data);
-static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data);
-
-/*!
- * \internal
- * \brief ast_bridge agent_hold push method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to push.
- * \param swap Bridge channel to swap places with if not NULL.
- *
- * \note On entry, self is already locked.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	int res = 0;
-	unsigned int wrapup_time;
-	char dtmf[AST_FEATURE_MAX_LEN];
-	struct ast_channel *chan;
-	const char *moh_class;
-	RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
-
-	chan = bridge_channel->chan;
-
-	agent = ao2_find(agents, swap ? swap->chan : chan, 0);
-	if (!agent) {
-		/* Could not find the agent. */
-		return -1;
-	}
-
-	/* Setup agent entertainment */
-	agent_lock(agent);
-	moh_class = ast_strdupa(agent->cfg->moh);
-	agent_unlock(agent);
-	res |= ast_channel_add_bridge_role(chan, "holding_participant");
-	res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
-	res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", moh_class);
-
-	/* Add DTMF acknowledge hook. */
-	dtmf[0] = '\0';
-	agent_lock(agent);
-	if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
-		? agent->override_ack_call : agent->cfg->ack_call) {
-		const char *dtmf_accept;
-
-		dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
-			? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
-		ast_copy_string(dtmf, dtmf_accept, sizeof(dtmf));
-	}
-	agent_unlock(agent);
-	if (!ast_strlen_zero(dtmf)) {
-		ao2_ref(agent, +1);
-		if (ast_bridge_dtmf_hook(bridge_channel->features, dtmf, bridge_agent_hold_ack,
-			agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-			ao2_ref(agent, -1);
-			res = -1;
-		}
-	}
-
-	/* Add heartbeat interval hook. */
-	ao2_ref(agent, +1);
-	if (ast_bridge_interval_hook(bridge_channel->features, 0, 1000,
-		bridge_agent_hold_heartbeat, agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		ao2_ref(agent, -1);
-		res = -1;
-	}
-
-	res |= ast_bridge_base_v_table.push(self, bridge_channel, swap);
-	if (res) {
-		ast_channel_remove_bridge_role(chan, "holding_participant");
-		return -1;
-	}
-
-	if (swap) {
-		res = ast_bridge_set_after_callback(chan, agent_after_bridge_cb,
-			agent_after_bridge_cb_failed, chan);
-		if (res) {
-			ast_channel_remove_bridge_role(chan, "holding_participant");
-			return -1;
-		}
-
-		agent_lock(agent);
-		ast_channel_unref(agent->logged);
-		agent->logged = ast_channel_ref(chan);
-		agent_unlock(agent);
-
-		/*
-		 * Kick the channel out so it can come back in fully controlled.
-		 * Otherwise, the after bridge callback will linger and the
-		 * agent will have some slightly different behavior in corner
-		 * cases.
-		 */
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-			AST_CAUSE_NORMAL_CLEARING);
-		return 0;
-	}
-
-	agent_lock(agent);
-	switch (agent->state) {
-	case AGENT_STATE_LOGGED_OUT:
-		/*!
-		 * \todo XXX the login probation time should be only if it is needed.
-		 *
-		 * Need to determine if there are any local channels that can
-		 * optimize and wait until they actually do before leaving the
-		 * AGENT_STATE_PROBATION_WAIT state.  For now, the blind
-		 * timer of LOGIN_WAIT_TIMEOUT_TIME will do.
-		 */
-		/*
-		 * Start the login probation timer.
-		 *
-		 * We cannot handle an agent local channel optimization when the
-		 * agent is on a call.  The optimization may kick the agent
-		 * channel we know about out of the call without our being able
-		 * to switch to the replacement channel.  Get any agent local
-		 * channel optimization out of the way while the agent is in the
-		 * holding bridge.
-		 */
-		time(&agent->probation_start);
-		agent->state = AGENT_STATE_PROBATION_WAIT;
-		agent_unlock(agent);
-		break;
-	case AGENT_STATE_PROBATION_WAIT:
-		/* Restart the probation timer. */
-		time(&agent->probation_start);
-		agent_unlock(agent);
-		break;
-	case AGENT_STATE_READY_FOR_CALL:
-		/*
-		 * Likely someone manually kicked us out of the holding bridge
-		 * and we came right back in.
-		 */
-		agent_unlock(agent);
-		break;
-	default:
-		/* Unexpected agent state. */
-		ast_assert(0);
-		/* Fall through */
-	case AGENT_STATE_CALL_PRESENT:
-	case AGENT_STATE_CALL_WAIT_ACK:
-		agent->state = AGENT_STATE_READY_FOR_CALL;
-		agent->devstate = AST_DEVICE_NOT_INUSE;
-		agent_unlock(agent);
-		ast_debug(1, "Agent %s: Call abort recovery complete.\n", agent->username);
-		agent_devstate_changed(agent->username);
-		break;
-	case AGENT_STATE_ON_CALL:
-	case AGENT_STATE_CALL_WRAPUP:
-		wrapup_time = agent->cfg->wrapup_time;
-		if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
-			wrapup_time = agent->override_wrapup_time;
-		}
-		if (wrapup_time) {
-			agent->state = AGENT_STATE_CALL_WRAPUP;
-		} else {
-			agent->state = AGENT_STATE_READY_FOR_CALL;
-			agent->devstate = AST_DEVICE_NOT_INUSE;
-		}
-		agent_unlock(agent);
-		if (!wrapup_time) {
-			/* No wrapup time. */
-			ast_debug(1, "Agent %s: Ready for new call.\n", agent->username);
-			agent_devstate_changed(agent->username);
-		}
-		break;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief ast_bridge agent_hold pull method.
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to pull.
- *
- * \details
- * Remove any channel hooks controlled by the bridge.  Release
- * any resources held by bridge_channel->bridge_pvt and release
- * bridge_channel->bridge_pvt.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-static void bridge_agent_hold_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	ast_channel_remove_bridge_role(bridge_channel->chan, "holding_participant");
-	ast_bridge_base_v_table.pull(self, bridge_channel);
-}
-
-/*!
- * \brief The bridge is being dissolved.
- *
- * \param self Bridge to operate upon.
- *
- * \details
- * The bridge is being dissolved.  Remove any external
- * references to the bridge so it can be destroyed.
- *
- * \note On entry, self must NOT be locked.
- *
- * \return Nothing
- */
-static void bridge_agent_hold_dissolving(struct ast_bridge *self)
-{
-	ao2_global_obj_release(agent_holding);
-	ast_bridge_base_v_table.dissolving(self);
-}
-
-static struct ast_bridge_methods bridge_agent_hold_v_table;
-
-static struct ast_bridge *bridge_agent_hold_new(void)
-{
-	struct ast_bridge *bridge;
-
-	bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
-	bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-			| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED,
-		"AgentPool", NULL, NULL);
-	bridge = bridge_register(bridge);
-	return bridge;
-}
-
-static void bridge_init_agent_hold(void)
-{
-	/* Setup bridge agent_hold subclass v_table. */
-	bridge_agent_hold_v_table = ast_bridge_base_v_table;
-	bridge_agent_hold_v_table.name = "agent_hold";
-	bridge_agent_hold_v_table.dissolving = bridge_agent_hold_dissolving;
-	bridge_agent_hold_v_table.push = bridge_agent_hold_push;
-	bridge_agent_hold_v_table.pull = bridge_agent_hold_pull;
-}
-
-static int bridge_agent_hold_deferred_create(void)
-{
-	RAII_VAR(struct ast_bridge *, holding, ao2_global_obj_ref(agent_holding), ao2_cleanup);
-
-	if (!holding) {
-		ast_mutex_lock(&agent_holding_lock);
-		holding = ao2_global_obj_ref(agent_holding);
-		if (!holding) {
-			holding = bridge_agent_hold_new();
-			ao2_global_obj_replace_unref(agent_holding, holding);
-		}
-		ast_mutex_unlock(&agent_holding_lock);
-		if (!holding) {
-			ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static void send_agent_login(struct ast_channel *chan, const char *agent)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	ast_assert(agent != NULL);
-
-	blob = ast_json_pack("{s: s}",
-		"agent", agent);
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_cached_blob(chan, ast_channel_agent_login_type(), blob);
-}
-
-static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	ast_assert(agent != NULL);
-
-	blob = ast_json_pack("{s: s, s: i}",
-		"agent", agent,
-		"logintime", logintime);
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_cached_blob(chan, ast_channel_agent_logoff_type(), blob);
-}
-
-/*!
- * \internal
- * \brief Logout the agent.
- * \since 12.0.0
- *
- * \param agent Which agent logging out.
- *
- * \note On entry agent is already locked.  On exit it is no longer locked.
- *
- * \return Nothing
- */
-static void agent_logout(struct agent_pvt *agent)
-{
-	struct ast_channel *logged;
-	struct ast_bridge *caller_bridge;
-	long time_logged_in;
-
-	time_logged_in = time(NULL) - agent->login_start;
-	logged = agent->logged;
-	agent->logged = NULL;
-	caller_bridge = agent->caller_bridge;
-	agent->caller_bridge = NULL;
-	agent->state = AGENT_STATE_LOGGED_OUT;
-	agent->devstate = AST_DEVICE_UNAVAILABLE;
-	ast_clear_flag(agent, AST_FLAGS_ALL);
-	agent_unlock(agent);
-	agent_devstate_changed(agent->username);
-
-	if (caller_bridge) {
-		ast_bridge_destroy(caller_bridge, 0);
-	}
-
-	ast_channel_lock(logged);
-	send_agent_logoff(logged, agent->username, time_logged_in);
-	ast_channel_unlock(logged);
-	ast_verb(2, "Agent '%s' logged out.  Logged in for %ld seconds.\n",
-		agent->username, time_logged_in);
-	ast_channel_unref(logged);
-}
-
-/*!
- * \internal
- * \brief Agent driver loop.
- * \since 12.0.0
- *
- * \param agent Which agent.
- * \param logged The logged in channel.
- *
- * \return Nothing
- */
-static void agent_run(struct agent_pvt *agent, struct ast_channel *logged)
-{
-	struct ast_bridge_features features;
-
-	if (ast_bridge_features_init(&features)) {
-		ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
-		goto agent_run_cleanup;
-	}
-	for (;;) {
-		struct agents_cfg *cfgs;
-		struct agent_cfg *cfg_new;
-		struct agent_cfg *cfg_old;
-		struct ast_bridge *holding;
-		struct ast_bridge *caller_bridge;
-
-		ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
-
-		holding = ao2_global_obj_ref(agent_holding);
-		if (!holding) {
-			ast_debug(1, "Agent %s: Someone destroyed the agent holding bridge.\n",
-				agent->username);
-			break;
-		}
-
-		/*
-		 * When the agent channel leaves the bridging system we usually
-		 * want to put the agent back into the holding bridge for the
-		 * next caller.
-		 */
-		ast_bridge_join(holding, logged, NULL, &features, NULL,
-			AST_BRIDGE_JOIN_PASS_REFERENCE);
-		if (logged != agent->logged) {
-			/* This channel is no longer the logged in agent. */
-			break;
-		}
-
-		if (agent->dead) {
-			/* The agent is no longer configured. */
-			break;
-		}
-
-		/* Update the agent's config before rejoining the holding bridge. */
-		cfgs = ao2_global_obj_ref(cfg_handle);
-		if (!cfgs) {
-			/* There is no agent configuration.  All agents were destroyed. */
-			break;
-		}
-		cfg_new = ao2_find(cfgs->agents, agent->username, OBJ_KEY);
-		ao2_ref(cfgs, -1);
-		if (!cfg_new) {
-			/* The agent is no longer configured. */
-			break;
-		}
-		agent_lock(agent);
-		cfg_old = agent->cfg;
-		agent->cfg = cfg_new;
-
-		agent->last_disconnect = ast_tvnow();
-
-		/* Clear out any caller bridge before rejoining the holding bridge. */
-		caller_bridge = agent->caller_bridge;
-		agent->caller_bridge = NULL;
-		agent_unlock(agent);
-		ao2_ref(cfg_old, -1);
-		if (caller_bridge) {
-			ast_bridge_destroy(caller_bridge, 0);
-		}
-
-		if (agent->state == AGENT_STATE_LOGGING_OUT
-			|| agent->deferred_logoff
-			|| ast_check_hangup_locked(logged)) {
-			/* The agent was requested to logout or hungup. */
-			break;
-		}
-
-		/*
-		 * It is safe to access agent->waiting_colp without a lock.  It
-		 * is only setup on agent login and not changed.
-		 */
-		ast_channel_update_connected_line(logged, &agent->waiting_colp, NULL);
-	}
-	ast_bridge_features_cleanup(&features);
-
-agent_run_cleanup:
-	agent_lock(agent);
-	if (logged != agent->logged) {
-		/*
-		 * We are no longer the agent channel because of local channel
-		 * optimization.
-		 */
-		agent_unlock(agent);
-		ast_debug(1, "Agent %s: Channel %s is no longer the agent.\n",
-			agent->username, ast_channel_name(logged));
-		return;
-	}
-	agent_logout(agent);
-}
-
-static void agent_after_bridge_cb(struct ast_channel *chan, void *data)
-{
-	struct agent_pvt *agent;
-
-	agent = ao2_find(agents, chan, 0);
-	if (!agent) {
-		return;
-	}
-
-	ast_debug(1, "Agent %s: New agent channel %s.\n",
-		agent->username, ast_channel_name(chan));
-	agent_run(agent, chan);
-	ao2_ref(agent, -1);
-}
-
-static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
-{
-	struct ast_channel *chan = data;
-	struct agent_pvt *agent;
-
-	agent = ao2_find(agents, chan, 0);
-	if (!agent) {
-		return;
-	}
-	ast_log(LOG_WARNING, "Agent %s: Forced logout.  Lost control of %s because: %s\n",
-		agent->username, ast_channel_name(chan),
-		ast_bridge_after_cb_reason_string(reason));
-	agent_lock(agent);
-	agent_logout(agent);
-	ao2_ref(agent, -1);
-}
-
-/*!
- * \internal
- * \brief Get the lock on the agent bridge_channel and return it.
- * \since 12.0.0
- *
- * \param agent Whose bridge_channel to get.
- *
- * \retval bridge_channel on success (Reffed and locked).
- * \retval NULL on error.
- */
-static struct ast_bridge_channel *agent_bridge_channel_get_lock(struct agent_pvt *agent)
-{
-	struct ast_channel *logged;
-	struct ast_bridge_channel *bc;
-
-	for (;;) {
-		agent_lock(agent);
-		logged = agent->logged;
-		if (!logged) {
-			agent_unlock(agent);
-			return NULL;
-		}
-		ast_channel_ref(logged);
-		agent_unlock(agent);
-
-		ast_channel_lock(logged);
-		bc = ast_channel_get_bridge_channel(logged);
-		ast_channel_unlock(logged);
-		ast_channel_unref(logged);
-		if (!bc) {
-			if (agent->logged != logged) {
-				continue;
-			}
-			return NULL;
-		}
-
-		ast_bridge_channel_lock(bc);
-		if (bc->chan != logged || agent->logged != logged) {
-			ast_bridge_channel_unlock(bc);
-			ao2_ref(bc, -1);
-			continue;
-		}
-		return bc;
-	}
-}
-
-static void caller_abort_agent(struct agent_pvt *agent)
-{
-	struct ast_bridge_channel *logged;
-
-	logged = agent_bridge_channel_get_lock(agent);
-	if (!logged) {
-		struct ast_bridge *caller_bridge;
-
-		ast_debug(1, "Agent '%s' no longer logged in.\n", agent->username);
-
-		agent_lock(agent);
-		caller_bridge = agent->caller_bridge;
-		agent->caller_bridge = NULL;
-		agent_unlock(agent);
-		if (caller_bridge) {
-			ast_bridge_destroy(caller_bridge, 0);
-		}
-		return;
-	}
-
-	/* Kick the agent out of the holding bridge to reset it. */
-	ast_bridge_channel_leave_bridge_nolock(logged, BRIDGE_CHANNEL_STATE_END,
-		AST_CAUSE_NORMAL_CLEARING);
-	ast_bridge_channel_unlock(logged);
-}
-
-static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct agent_pvt *agent = hook_pvt;
-
-	if (agent->state == AGENT_STATE_CALL_PRESENT) {
-		ast_log(LOG_WARNING, "Agent '%s' process did not respond.  Safety timeout.\n",
-			agent->username);
-		pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
-
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
-		caller_abort_agent(agent);
-	}
-
-	return -1;
-}
-
-static void agent_alert(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
-{
-	const char *agent_id = payload;
-	const char *playfile;
-	const char *dtmf_accept;
-	struct agent_pvt *agent;
-	int digit;
-	char dtmf[2];
-
-	agent = ao2_find(agents, agent_id, OBJ_KEY);
-	if (!agent) {
-		ast_debug(1, "Agent '%s' does not exist.  Where did it go?\n", agent_id);
-		return;
-	}
-
-	/* Change holding bridge participant role's idle mode to silence */
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	ast_bridge_channel_clear_roles(bridge_channel);
-	ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "silence");
-	ast_bridge_channel_establish_roles(bridge_channel);
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	agent_lock(agent);
-	playfile = ast_strdupa(agent->cfg->beep_sound);
-
-	/* Determine which DTMF digits interrupt the alerting signal. */
-	if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
-		? agent->override_ack_call : agent->cfg->ack_call) {
-		dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
-			? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
-
-		/* Only the first digit of the ack will stop playback. */
-		dtmf[0] = *dtmf_accept;
-		dtmf[1] = '\0';
-		dtmf_accept = dtmf;
-	} else {
-		dtmf_accept = NULL;
-	}
-	agent_unlock(agent);
-
-	/* Alert the agent. */
-	digit = ast_stream_and_wait(bridge_channel->chan, playfile,
-		ast_strlen_zero(dtmf_accept) ? AST_DIGIT_ANY : dtmf_accept);
-	ast_stopstream(bridge_channel->chan);
-
-	agent_lock(agent);
-	switch (agent->state) {
-	case AGENT_STATE_CALL_PRESENT:
-		if (!ast_strlen_zero(dtmf_accept)) {
-			agent->state = AGENT_STATE_CALL_WAIT_ACK;
-			agent->ack_time = ast_tvnow();
-
-			if (0 < digit) {
-				/* Playback was interrupted by a digit. */
-				agent_unlock(agent);
-				ao2_ref(agent, -1);
-				ast_bridge_channel_feature_digit(bridge_channel, digit);
-				return;
-			}
-			break;
-		}
-
-		/* Connect to caller now. */
-		ast_debug(1, "Agent %s: Immediately connecting to call.\n", agent->username);
-		agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
-		ao2_ref(agent, -1);
-		return;
-	default:
-		break;
-	}
-	agent_unlock(agent);
-	ao2_ref(agent, -1);
-}
-
-static int send_alert_to_agent(struct ast_bridge_channel *bridge_channel, const char *agent_id)
-{
-	return ast_bridge_channel_queue_callback(bridge_channel,
-		AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, agent_alert, agent_id, strlen(agent_id) + 1);
-}
-
-static int send_colp_to_agent(struct ast_bridge_channel *bridge_channel, struct ast_party_connected_line *connected)
-{
-	struct ast_set_party_connected_line update = {
-		.id.name = 1,
-		.id.number = 1,
-		.id.subaddress = 1,
-	};
-	unsigned char data[1024];	/* This should be large enough */
-	size_t datalen;
-
-	datalen = ast_connected_line_build_data(data, sizeof(data), connected, &update);
-	if (datalen == (size_t) -1) {
-		return 0;
-	}
-
-	return ast_bridge_channel_queue_control_data(bridge_channel,
-		AST_CONTROL_CONNECTED_LINE, data, datalen);
-}
-
-/*!
- * \internal
- * \brief Caller joined the bridge event callback.
- *
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- *
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-static int caller_joined_bridge(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct agent_pvt *agent = hook_pvt;
-	struct ast_bridge_channel *logged;
-	int res;
-
-	logged = agent_bridge_channel_get_lock(agent);
-	if (!logged) {
-		ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
-		pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_LOGGED_IN");
-
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
-		caller_abort_agent(agent);
-		return -1;
-	}
-
-	res = send_alert_to_agent(logged, agent->username);
-	ast_bridge_channel_unlock(logged);
-	ao2_ref(logged, -1);
-	if (res) {
-		ast_verb(3, "Agent '%s': Failed to alert the agent.\n", agent->username);
-		pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
-
-		ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
-		caller_abort_agent(agent);
-		return -1;
-	}
-
-	pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_CONNECTED");
-	ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
-	return -1;
-}
-
-/*!
- * \brief Dialplan AgentRequest application to locate an agent to talk with.
- *
- * \param chan Channel wanting to talk with an agent.
- * \param data Application parameters
- *
- * \retval 0 To continue in dialplan.
- * \retval -1 To hangup.
- */
-static int agent_request_exec(struct ast_channel *chan, const char *data)
-{
-	struct ast_bridge *caller_bridge;
-	struct ast_bridge_channel *logged;
-	char *parse;
-	int res;
-	struct ast_bridge_features caller_features;
-	struct ast_party_connected_line connected;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(agent_id);
-		AST_APP_ARG(other);		/* Any remaining unused arguments */
-	);
-
-	RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
-
-	if (bridge_agent_hold_deferred_create()) {
-		return -1;
-	}
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.agent_id)) {
-		ast_log(LOG_WARNING, "AgentRequest requires an AgentId\n");
-		return -1;
-	}
-
-	/* Find the agent. */
-	agent = ao2_find(agents, args.agent_id, OBJ_KEY);
-	if (!agent) {
-		ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
-		return 0;
-	}
-
-	if (ast_bridge_features_init(&caller_features)) {
-		return -1;
-	}
-
-	/* Add safety timeout hook. */
-	ao2_ref(agent, +1);
-	if (ast_bridge_interval_hook(&caller_features, 0, CALLER_SAFETY_TIMEOUT_TIME,
-		caller_safety_timeout, agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		ao2_ref(agent, -1);
-		ast_bridge_features_cleanup(&caller_features);
-		return -1;
-	}
-
-	/* Setup the alert agent on caller joining the bridge hook. */
-	ao2_ref(agent, +1);
-	if (ast_bridge_join_hook(&caller_features, caller_joined_bridge, agent,
-		__ao2_cleanup, 0)) {
-		ao2_ref(agent, -1);
-		ast_bridge_features_cleanup(&caller_features);
-		return -1;
-	}
-
-	caller_bridge = ast_bridge_basic_new();
-	if (!caller_bridge) {
-		ast_bridge_features_cleanup(&caller_features);
-		return -1;
-	}
-
-	agent_lock(agent);
-	switch (agent->state) {
-	case AGENT_STATE_LOGGED_OUT:
-	case AGENT_STATE_LOGGING_OUT:
-		agent_unlock(agent);
-		ast_bridge_destroy(caller_bridge, 0);
-		ast_bridge_features_cleanup(&caller_features);
-		ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
-		return 0;
-	case AGENT_STATE_READY_FOR_CALL:
-		ao2_ref(caller_bridge, +1);
-		agent->caller_bridge = caller_bridge;
-		agent->state = AGENT_STATE_CALL_PRESENT;
-		agent->devstate = AST_DEVICE_INUSE;
-		break;
-	default:
-		agent_unlock(agent);
-		ast_bridge_destroy(caller_bridge, 0);
-		ast_bridge_features_cleanup(&caller_features);
-		ast_verb(3, "Agent '%s' is busy.\n", agent->username);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "BUSY");
-		return 0;
-	}
-	agent_unlock(agent);
-	agent_devstate_changed(agent->username);
-
-	/* Get COLP for agent. */
-	ast_party_connected_line_init(&connected);
-	ast_channel_lock(chan);
-	ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
-	ast_channel_unlock(chan);
-
-	logged = agent_bridge_channel_get_lock(agent);
-	if (!logged) {
-		ast_party_connected_line_free(&connected);
-		caller_abort_agent(agent);
-		ast_bridge_destroy(caller_bridge, 0);
-		ast_bridge_features_cleanup(&caller_features);
-		ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
-		return 0;
-	}
-
-	send_colp_to_agent(logged, &connected);
-	ast_bridge_channel_unlock(logged);
-	ao2_ref(logged, -1);
-	ast_party_connected_line_free(&connected);
-
-	if (ast_bridge_join(caller_bridge, chan, NULL, &caller_features, NULL,
-		AST_BRIDGE_JOIN_PASS_REFERENCE)) {
-		caller_abort_agent(agent);
-		ast_verb(3, "Agent '%s': Caller %s failed to join the bridge.\n",
-			agent->username, ast_channel_name(chan));
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ERROR");
-	}
-	ast_bridge_features_cleanup(&caller_features);
-
-	/* Determine if we need to continue in the dialplan after the bridge. */
-	ast_channel_lock(chan);
-	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
-		/*
-		 * The bridge was broken for a hangup that isn't real.
-		 * Don't run the h extension, because the channel isn't
-		 * really hung up.  This should really only happen with
-		 * AST_SOFTHANGUP_ASYNCGOTO.
-		 */
-		res = 0;
-	} else {
-		res = ast_check_hangup(chan)
-			|| ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
-			|| ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENT_STATUS"));
-	}
-	ast_channel_unlock(chan);
-
-	return res ? -1 : 0;
-}
-
-/*!
- * \internal
- * \brief Get agent config values from the login channel.
- * \since 12.0.0
- *
- * \param agent What to setup channel config values on.
- * \param chan Channel logging in as an agent.
- *
- * \return Nothing
- */
-static void agent_login_channel_config(struct agent_pvt *agent, struct ast_channel *chan)
-{
-	struct ast_flags opts = { 0 };
-	struct ast_party_connected_line connected;
-	unsigned int override_ack_call = 0;
-	unsigned int override_auto_logoff = 0;
-	unsigned int override_wrapup_time = 0;
-	const char *override_dtmf_accept = NULL;
-	const char *var;
-
-	ast_party_connected_line_init(&connected);
-
-	/* Get config values from channel. */
-	ast_channel_lock(chan);
-	ast_party_connected_line_copy(&connected, ast_channel_connected(chan));
-
-	var = pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
-	if (!ast_strlen_zero(var)) {
-		override_ack_call = ast_true(var) ? 1 : 0;
-		ast_set_flag(&opts, AGENT_FLAG_ACK_CALL);
-	}
-
-	var = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
-	if (!ast_strlen_zero(var)) {
-		override_dtmf_accept = ast_strdupa(var);
-		ast_set_flag(&opts, AGENT_FLAG_DTMF_ACCEPT);
-	}
-
-	var = pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
-	if (!ast_strlen_zero(var)) {
-		if (sscanf(var, "%u", &override_auto_logoff) == 1) {
-			ast_set_flag(&opts, AGENT_FLAG_AUTO_LOGOFF);
-		}
-	}
-
-	var = pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
-	if (!ast_strlen_zero(var)) {
-		if (sscanf(var, "%u", &override_wrapup_time) == 1) {
-			ast_set_flag(&opts, AGENT_FLAG_WRAPUP_TIME);
-		}
-	}
-	ast_channel_unlock(chan);
-
-	/* Set config values on agent. */
-	agent_lock(agent);
-	ast_party_connected_line_free(&agent->waiting_colp);
-	agent->waiting_colp = connected;
-
-	ast_string_field_set(agent, override_dtmf_accept, override_dtmf_accept);
-	ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
-	agent->override_auto_logoff = override_auto_logoff;
-	agent->override_wrapup_time = override_wrapup_time;
-	agent->override_ack_call = override_ack_call;
-	agent_unlock(agent);
-}
-
-enum AGENT_LOGIN_OPT_FLAGS {
-	OPT_SILENT = (1 << 0),
-};
-AST_APP_OPTIONS(agent_login_opts, BEGIN_OPTIONS
-	AST_APP_OPTION('s', OPT_SILENT),
-END_OPTIONS);
-
-/*!
- * \brief Dialplan AgentLogin application to log in an agent.
- *
- * \param chan Channel attempting to login as an agent.
- * \param data Application parameters
- *
- * \retval 0 To continue in dialplan.
- * \retval -1 To hangup.
- */
-static int agent_login_exec(struct ast_channel *chan, const char *data)
-{
-	char *parse;
-	struct ast_flags opts;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(agent_id);
-		AST_APP_ARG(options);
-		AST_APP_ARG(other);		/* Any remaining unused arguments */
-	);
-
-	RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
-
-	if (bridge_agent_hold_deferred_create()) {
-		return -1;
-	}
-
-	if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
-		return -1;
-	}
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.agent_id)) {
-		ast_log(LOG_WARNING, "AgentLogin requires an AgentId\n");
-		return -1;
-	}
-
-	if (ast_app_parse_options(agent_login_opts, &opts, NULL, args.options)) {
-		/* General invalid option syntax. */
-		return -1;
-	}
-
-	/* Find the agent. */
-	agent = ao2_find(agents, args.agent_id, OBJ_KEY);
-	if (!agent) {
-		ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
-		return 0;
-	}
-
-	/* Has someone already logged in as this agent already? */
-	agent_lock(agent);
-	if (agent->logged) {
-		agent_unlock(agent);
-		ast_verb(3, "Agent '%s' already logged in.\n", agent->username);
-		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ALREADY_LOGGED_IN");
-		return 0;
-	}
-	agent->logged = ast_channel_ref(chan);
-	agent->last_disconnect = ast_tvnow();
-	time(&agent->login_start);
-	agent->deferred_logoff = 0;
-	agent_unlock(agent);
-
-	agent_login_channel_config(agent, chan);
-
-	if (!ast_test_flag(&opts, OPT_SILENT)) {
-		ast_stream_and_wait(chan, "agent-loginok", AST_DIGIT_NONE);
-	}
-
-	ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username,
-		ast_format_get_name(ast_channel_readformat(chan)),
-		ast_format_get_name(ast_channel_writeformat(chan)));
-	ast_channel_lock(chan);
-	send_agent_login(chan, agent->username);
-	ast_channel_unlock(chan);
-
-	agent_run(agent, chan);
-	return -1;
-}
-
-static int agent_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	char *parse;
-	struct agent_pvt *agent;
-	struct ast_channel *logged;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(agentid);
-		AST_APP_ARG(item);
-	);
-
-	buf[0] = '\0';
-
-	parse = ast_strdupa(data ?: "");
-	AST_NONSTANDARD_APP_ARGS(args, parse, ':');
-
-	if (ast_strlen_zero(args.agentid)) {
-		ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
-		return -1;
-	}
-	if (!args.item) {
-		args.item = "status";
-	}
-
-	agent = ao2_find(agents, args.agentid, OBJ_KEY);
-	if (!agent) {
-		ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
-		return -1;
-	}
-
-	agent_lock(agent);
-	if (!strcasecmp(args.item, "status")) {
-		const char *status;
-
-		if (agent->logged) {
-			status = "LOGGEDIN";
-		} else {
-			status = "LOGGEDOUT";
-		}
-		ast_copy_string(buf, status, len);
-	} else if (!strcasecmp(args.item, "name")) {
-		ast_copy_string(buf, agent->cfg->full_name, len);
-	} else if (!strcasecmp(args.item, "mohclass")) {
-		ast_copy_string(buf, agent->cfg->moh, len);
-	} else if (!strcasecmp(args.item, "channel")) {
-		logged = agent_lock_logged(agent);
-		if (logged) {
-			char *pos;
-
-			ast_copy_string(buf, ast_channel_name(logged), len);
-			ast_channel_unlock(logged);
-			ast_channel_unref(logged);
-
-			pos = strrchr(buf, '-');
-			if (pos) {
-				*pos = '\0';
-			}
-		}
-	} else if (!strcasecmp(args.item, "fullchannel")) {
-		logged = agent_lock_logged(agent);
-		if (logged) {
-			ast_copy_string(buf, ast_channel_name(logged), len);
-			ast_channel_unlock(logged);
-			ast_channel_unref(logged);
-		}
-	}
-	agent_unlock(agent);
-	ao2_ref(agent, -1);
-
-	return 0;
-}
-
-static struct ast_custom_function agent_function = {
-	.name = "AGENT",
-	.read = agent_function_read,
-};
-
-struct agent_complete {
-	/*! Nth match to return. */
-	int state;
-	/*! Which match currently on. */
-	int which;
-};
-
-static int complete_agent_search(void *obj, void *arg, void *data, int flags)
-{
-	struct agent_complete *search = data;
-
-	if (++search->which > search->state) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_agent(const char *word, int state)
-{
-	char *ret;
-	struct agent_pvt *agent;
-	struct agent_complete search = {
-		.state = state,
-	};
-
-	agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_agent_search, (char *) word, &search);
-	if (!agent) {
-		return NULL;
-	}
-	ret = ast_strdup(agent->username);
-	ao2_ref(agent, -1);
-	return ret;
-}
-
-static int complete_agent_logoff_search(void *obj, void *arg, void *data, int flags)
-{
-	struct agent_pvt *agent = obj;
-	struct agent_complete *search = data;
-
-	if (!agent->logged) {
-		return 0;
-	}
-	if (++search->which > search->state) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_agent_logoff(const char *word, int state)
-{
-	char *ret;
-	struct agent_pvt *agent;
-	struct agent_complete search = {
-		.state = state,
-	};
-
-	agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_agent_logoff_search, (char *) word, &search);
-	if (!agent) {
-		return NULL;
-	}
-	ret = ast_strdup(agent->username);
-	ao2_ref(agent, -1);
-	return ret;
-}
-
-static void agent_show_requested(struct ast_cli_args *a, int online_only)
-{
-#define FORMAT_HDR "%-8s %-20s %-11s %-30s %s\n"
-#define FORMAT_ROW "%-8s %-20s %-11s %-30s %s\n"
-
-	struct ao2_iterator iter;
-	struct agent_pvt *agent;
-	struct ast_str *out = ast_str_alloca(512);
-	unsigned int agents_total = 0;
-	unsigned int agents_logged_in = 0;
-	unsigned int agents_talking = 0;
-
-	ast_cli(a->fd, FORMAT_HDR, "Agent-ID", "Name", "State", "Channel", "Talking with");
-	iter = ao2_iterator_init(agents, 0);
-	for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
-		struct ast_channel *logged;
-
-		++agents_total;
-
-		agent_lock(agent);
-		logged = agent_lock_logged(agent);
-		if (logged) {
-			const char *talking_with;
-
-			++agents_logged_in;
-
-			talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
-			if (!ast_strlen_zero(talking_with)) {
-				++agents_talking;
-			} else {
-				talking_with = "";
-			}
-			ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
-				ast_devstate_str(agent->devstate), ast_channel_name(logged), talking_with);
-			ast_channel_unlock(logged);
-			ast_channel_unref(logged);
-		} else {
-			ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
-				ast_devstate_str(agent->devstate), "", "");
-		}
-		agent_unlock(agent);
-
-		if (!online_only || logged) {
-			ast_cli(a->fd, "%s", ast_str_buffer(out));
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	ast_cli(a->fd, "\nDefined agents: %u, Logged in: %u, Talking: %u\n",
-		agents_total, agents_logged_in, agents_talking);
-
-#undef FORMAT_HDR
-#undef FORMAT_ROW
-}
-
-static char *agent_handle_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "agent show online";
-		e->usage =
-			"Usage: agent show online\n"
-			"       Provides summary information for logged in agents.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	agent_show_requested(a, 1);
-
-	return CLI_SUCCESS;
-}
-
-static char *agent_handle_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "agent show all";
-		e->usage =
-			"Usage: agent show all\n"
-			"       Provides summary information for all agents.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	agent_show_requested(a, 0);
-
-	return CLI_SUCCESS;
-}
-
-static char *agent_handle_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct agent_pvt *agent;
-	struct ast_channel *logged;
-	struct ast_str *out = ast_str_alloca(4096);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "agent show";
-		e->usage =
-			"Usage: agent show <agent-id>\n"
-			"       Show information about the <agent-id> agent\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_agent(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	agent = ao2_find(agents, a->argv[2], OBJ_KEY);
-	if (!agent) {
-		ast_cli(a->fd, "Agent '%s' not found\n", a->argv[2]);
-		return CLI_SUCCESS;
-	}
-
-	agent_lock(agent);
-	logged = agent_lock_logged(agent);
-	ast_str_set(&out, 0, "Id: %s\n", agent->username);
-	ast_str_append(&out, 0, "Name: %s\n", agent->cfg->full_name);
-	ast_str_append(&out, 0, "Beep: %s\n", agent->cfg->beep_sound);
-	ast_str_append(&out, 0, "MOH: %s\n", agent->cfg->moh);
-	ast_str_append(&out, 0, "RecordCalls: %s\n", AST_CLI_YESNO(agent->cfg->record_agent_calls));
-	ast_str_append(&out, 0, "State: %s\n", ast_devstate_str(agent->devstate));
-	if (logged) {
-		const char *talking_with;
-
-		ast_str_append(&out, 0, "LoggedInChannel: %s\n", ast_channel_name(logged));
-		ast_str_append(&out, 0, "LoggedInTime: %ld\n", (long) agent->login_start);
-		talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
-		if (!ast_strlen_zero(talking_with)) {
-			ast_str_append(&out, 0, "TalkingWith: %s\n", talking_with);
-			ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
-		}
-		ast_channel_unlock(logged);
-		ast_channel_unref(logged);
-	}
-	agent_unlock(agent);
-	ao2_ref(agent, -1);
-
-	ast_cli(a->fd, "%s", ast_str_buffer(out));
-
-	return CLI_SUCCESS;
-}
-
-static char *agent_handle_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "agent logoff";
-		e->usage =
-			"Usage: agent logoff <agent-id> [soft]\n"
-			"       Sets an agent as no longer logged in.\n"
-			"       If 'soft' is specified, do not hangup existing calls.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_agent_logoff(a->word, a->n);
-		} else if (a->pos == 3 && a->n == 0
-			&& (ast_strlen_zero(a->word)
-				|| !strncasecmp("soft", a->word, strlen(a->word)))) {
-			return ast_strdup("soft");
-		}
-		return NULL;
-	}
-
-	if (a->argc < 3 || 4 < a->argc) {
-		return CLI_SHOWUSAGE;
-	}
-	if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!agent_logoff_request(a->argv[2], a->argc == 4)) {
-		ast_cli(a->fd, "Logging out %s\n", a->argv[2]);
-	}
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_agents[] = {
-	AST_CLI_DEFINE(agent_handle_show_online, "Show status of online agents"),
-	AST_CLI_DEFINE(agent_handle_show_all, "Show status of all agents"),
-	AST_CLI_DEFINE(agent_handle_show_specific, "Show information about an agent"),
-	AST_CLI_DEFINE(agent_handle_logoff_cmd, "Sets an agent offline"),
-};
-
-static int action_agents(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	char id_text[AST_MAX_BUF];
-	struct ao2_iterator iter;
-	struct agent_pvt *agent;
-	struct ast_str *out = ast_str_alloca(4096);
-
-	if (!ast_strlen_zero(id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-	} else {
-		id_text[0] = '\0';
-	}
-	astman_send_ack(s, m, "Agents will follow");
-
-	iter = ao2_iterator_init(agents, 0);
-	for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
-		struct ast_channel *logged;
-
-		agent_lock(agent);
-		logged = agent_lock_logged(agent);
-
-		/*
-		 * Status Values:
-		 * AGENT_LOGGEDOFF - Agent isn't logged in
-		 * AGENT_IDLE      - Agent is logged in, and waiting for call
-		 * AGENT_ONCALL    - Agent is logged in, and on a call
-		 * AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this.
-		 */
-		ast_str_set(&out, 0, "Agent: %s\r\n", agent->username);
-		ast_str_append(&out, 0, "Name: %s\r\n", agent->cfg->full_name);
-
-		if (logged) {
-			const char *talking_to_chan;
-			struct ast_str *logged_headers;
-			RAII_VAR(struct ast_channel_snapshot *, logged_snapshot, ast_channel_snapshot_create(logged), ao2_cleanup);
-
-			if (!logged_snapshot
-				|| !(logged_headers =
-					 ast_manager_build_channel_state_string(logged_snapshot))) {
-				ast_channel_unlock(logged);
-				ast_channel_unref(logged);
-				agent_unlock(agent);
-				continue;
-			}
-
-			talking_to_chan = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
-			if (!ast_strlen_zero(talking_to_chan)) {
-				ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_ONCALL");
-				ast_str_append(&out, 0, "TalkingToChan: %s\r\n", talking_to_chan);
-				ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
-			} else {
-				ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_IDLE");
-			}
-			ast_str_append(&out, 0, "LoggedInTime: %ld\r\n", (long) agent->login_start);
-			ast_str_append(&out, 0, "%s", ast_str_buffer(logged_headers));
-			ast_channel_unlock(logged);
-			ast_channel_unref(logged);
-			ast_free(logged_headers);
-		} else {
-			ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_LOGGEDOFF");
-		}
-
-		agent_unlock(agent);
-
-		astman_append(s, "Event: Agents\r\n"
-			"%s%s\r\n",
-			ast_str_buffer(out), id_text);
-	}
-	ao2_iterator_destroy(&iter);
-
-	astman_append(s, "Event: AgentsComplete\r\n"
-		"%s"
-		"\r\n", id_text);
-	return 0;
-}
-
-static int action_agent_logoff(struct mansession *s, const struct message *m)
-{
-	const char *agent = astman_get_header(m, "Agent");
-	const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
-
-	if (ast_strlen_zero(agent)) {
-		astman_send_error(s, m, "No agent specified");
-		return 0;
-	}
-
-	if (!agent_logoff_request(agent, ast_true(soft_s))) {
-		astman_send_ack(s, m, "Agent logged out");
-	} else {
-		astman_send_error(s, m, "No such agent");
-	}
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	struct ast_bridge *holding;
-
-	/* Unregister dialplan applications */
-	ast_unregister_application(app_agent_login);
-	ast_unregister_application(app_agent_request);
-
-	/* Unregister dialplan functions */
-	ast_custom_function_unregister(&agent_function);
-
-	/* Unregister manager command */
-	ast_manager_unregister("Agents");
-	ast_manager_unregister("AgentLogoff");
-
-	/* Unregister CLI commands */
-	ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
-
-	ast_devstate_prov_del("Agent");
-
-	/* Destroy agent holding bridge. */
-	holding = ao2_global_obj_replace(agent_holding, NULL);
-	if (holding) {
-		ast_bridge_destroy(holding, 0);
-	}
-
-	destroy_config();
-	ao2_ref(agents, -1);
-	agents = NULL;
-	return 0;
-}
-
-static int load_module(void)
-{
-	int res = 0;
-
-	agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, agent_pvt_sort_cmp, agent_pvt_cmp);
-	if (!agents) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	if (load_config()) {
-		ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
-		ao2_ref(agents, -1);
-		agents = NULL;
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	/* Init agent holding bridge v_table. */
-	bridge_init_agent_hold();
-
-	/* Setup to provide Agent:agent-id device state. */
-	res |= ast_devstate_prov_add("Agent", agent_pvt_devstate_get);
-
-	/* CLI Commands */
-	res |= ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
-
-	/* Manager commands */
-	res |= ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
-	res |= ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
-
-	/* Dialplan Functions */
-	res |= ast_custom_function_register(&agent_function);
-
-	/* Dialplan applications */
-	res |= ast_register_application_xml(app_agent_login, agent_login_exec);
-	res |= ast_register_application_xml(app_agent_request, agent_request_exec);
-
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload(void)
-{
-	if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
-		/* Just keep the config we already have in place. */
-		return -1;
-	}
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Call center agent pool applications",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.reload = reload,
-	.load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
-);
diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c
index b31e76d..c6d6ec4 100644
--- a/apps/app_alarmreceiver.c
+++ b/apps/app_alarmreceiver.c
@@ -17,7 +17,6 @@
  */
 
 /*! \file
- *
  * \brief Central Station Alarm receiver for Ademco Contact ID
  * \author Steve Rodgers <hwstar at rodgers.sdcoxmail.com>
  *
@@ -30,22 +29,13 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_alarmreceiver.c uses the configuration file \ref alarmreceiver.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page alarmreceiver.conf alarmreceiver.conf
- * \verbinclude alarmreceiver.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 #include <sys/wait.h>
@@ -57,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
+#include "asterisk/ulaw.h"
 #include "asterisk/app.h"
 #include "asterisk/dsp.h"
 #include "asterisk/config.h"
@@ -64,77 +55,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/callerid.h"
 #include "asterisk/astdb.h"
 #include "asterisk/utils.h"
-#include "asterisk/indications.h"
-#include "asterisk/format_cache.h"
 
 #define ALMRCV_CONFIG "alarmreceiver.conf"
-#define UNKNOWN_FORMAT "UNKNOWN_FORMAT"
-
 #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
-/*
-	AAAA _ID_ P CCC XX ZZZ S
-
-where AAAA is the account number, _ID_ is 18 or 98, P is the pin status (alarm or restore), CCC
-is the alarm code which is pre-defined by Ademco (but you may be able to reprogram it in the panel), XX
-is the dialer group, partition or area number, ZZZ is the zone or user number and S is the checksum
-*/
-
-#define ADEMCO_EXPRESS_4_1 "ADEMCO_EXPRESS_4_1"
-/*
-	AAAA _ID_ C S
-
-where AAAA is the account number, _ID_ is 17, C is the alarm code and S is the checksum.
-*/
-
-#define ADEMCO_EXPRESS_4_2 "ADEMCO_EXPRESS_4_2"
-/*
-	AAAA _ID_ C Z S
-
-where AAAA is the account number, _ID_ is 27, C is the alarm code, Z is the zone or user number and S is the checksum.
-*/
-
-#define ADEMCO_HIGH_SPEED "ADEMCO_HIGH_SPEED"
-/*
-	AAAA _ID_ PPPP PPPP X S
-
-where AAAA is the account number, _ID_ is 55, PPPP PPPP is the status of each zone, X
-is a special digit which describes the type of information in the PPPP PPPP fields and S is checksum.
-Each P field contains one of the following values:
-        1  new alarm           3  new restore           5  normal
-        2  new opening         4  new closing           6  outstanding
-The X field contains one of the following values:
-        0  AlarmNet messages
-        1  ambush or duress
-        2  opening by user (the first P field contains the user number)
-        3  bypass (the P fields indicate which zones are bypassed)
-        4  closing by user (the first P field contain the user number)
-        5  trouble (the P fields contain which zones are in trouble)
-        6  system trouble
-        7  normal message (the P fields indicate zone status)
-        8  low battery (the P fields indicate zone status)
-        9  test (the P fields indicate zone status)
-*/
-#define ADEMCO_SUPER_FAST "ADEMCO_SUPER_FAST"
-/*
-	AAAA _ID_ PPPP PPPP X
-where AAA is the account number, _ID_ is 56
-*/
-
-#define ADEMCO_MSG_TYPE_1 "18"
-#define ADEMCO_MSG_TYPE_2 "98"
-#define ADEMCO_MSG_TYPE_3 "17"
-#define ADEMCO_MSG_TYPE_4 "27"
-#define ADEMCO_MSG_TYPE_5 "55"
-#define ADEMCO_MSG_TYPE_6 "56"
-
-#define ADEMCO_AUDIO_CALL_NEXT "606"
-
-struct {
-  char digit;
-  char weight;
-} digits_mapping[] = { {'0', 10}, {'1', 1} , {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5},
-	{'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}, {'*', 11}, {'#', 12},
-	{'A', 13}, {'B', 14}, {'C', 15} };
 
 struct event_node{
 	char data[17];
@@ -143,8 +66,6 @@ struct event_node{
 
 typedef struct event_node event_node_t;
 
-struct timeval call_start_time;
-
 static const char app[] = "AlarmReceiver";
 /*** DOCUMENTATION
 	<application name="AlarmReceiver" language="en_US">
@@ -160,19 +81,7 @@ static const char app[] = "AlarmReceiver";
 			events to the standard input of the application.
 			The configuration file also contains settings for DTMF timing, and for the loudness of the
 			acknowledgement tones.</para>
-			<note><para>Few Ademco DTMF signalling formats are detected automaticaly: Contact ID, Express 4+1,
-			Express 4+2, High Speed and Super Fast.</para></note>
-			<para>The application is affected by the following variables:</para>
-			<variablelist>
-				<variable name="ALARMRECEIVER_CALL_LIMIT">
-					<para>Maximum call time, in milliseconds.</para>
-					<para>If set, this variable causes application to exit after the specified time.</para>
-				</variable>
-				<variable name="ALARMRECEIVER_RETRIES_LIMIT">
-					<para>Maximum number of retries per call.</para>
-					<para>If set, this variable causes application to exit after the specified number of messages.</para>
-				</variable>
-			</variablelist>
+			<note><para>Only 1 signalling format is supported at this time: Ademco Contact ID.</para></note>
 		</description>
 		<see-also>
 			<ref type="filename">alarmreceiver.conf</ref>
@@ -183,10 +92,8 @@ static const char app[] = "AlarmReceiver";
 /* Config Variables */
 static int fdtimeout = 2000;
 static int sdtimeout = 200;
-static int answait = 1250;
 static int toneloudness = 4096;
 static int log_individual_events = 0;
-static int no_group_meta = 0;
 static char event_spool_dir[128] = {'\0'};
 static char event_app[128] = {'\0'};
 static char db_family[128] = {'\0'};
@@ -195,77 +102,152 @@ static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
 /* Misc variables */
 static char event_file[14] = "/event-XXXXXX";
 
-/*!
- * \brief Attempt to access a database variable and increment it
- *
- * \note Only if the user defined db-family in alarmreceiver.conf
- *
- * The alarmreceiver app will write statistics to a few variables
- * in this family if it is defined. If the new key doesn't exist in the
- * family, then create it and set its value to 1.
- *
- * \param key A database key to increment
- * \return Nothing
- */
-static void database_increment(char *key)
+/*
+* Attempt to access a database variable and increment it,
+* provided that the user defined db-family in alarmreceiver.conf
+* The alarmreceiver app will write statistics to a few variables
+* in this family if it is defined. If the new key doesn't exist in the
+* family, then create it and set its value to 1.
+*/
+static void database_increment( char *key )
 {
+	int res = 0;
 	unsigned v;
 	char value[16];
-
-	if (ast_strlen_zero(db_family)) {
-		return;	/* If not defined, don't do anything */
-	}
-
-	if (ast_db_get(db_family, key, value, sizeof(value) - 1)) {
+	
+	
+	if (ast_strlen_zero(db_family))
+		return; /* If not defined, don't do anything */
+	
+	res = ast_db_get(db_family, key, value, sizeof(value) - 1);
+	
+	if (res) {
 		ast_verb(4, "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
 		/* Guess we have to create it */
-		ast_db_put(db_family, key, "1");
+		res = ast_db_put(db_family, key, "1");
 		return;
 	}
-
+	
 	sscanf(value, "%30u", &v);
 	v++;
 
 	ast_verb(4, "AlarmReceiver: New value for %s: %u\n", key, v);
+
 	snprintf(value, sizeof(value), "%u", v);
 
-	if (ast_db_put(db_family, key, value)) {
+	res = ast_db_put(db_family, key, value);
+
+	if (res)
 		ast_verb(4, "AlarmReceiver: database_increment write error\n");
+
+	return;
+}
+
+
+/*
+* Build a MuLaw data block for a single frequency tone
+*/
+static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x)
+{
+	int     i;
+	float   val;
+
+	for (i = 0; i < len; i++) {
+		val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0);
+		data[i] = AST_LIN2MU((int)val);
 	}
 
+	/* wrap back around from 8000 */
+
+	if (*x >= 8000)
+		*x = 0;
 	return;
 }
 
-/*!
- * \brief Receive a fixed length DTMF string.
- *
- * \note Doesn't give preferential treatment to any digit,
- * \note allow different timeout values for the first and all subsequent digits
- *
- * \param chan Asterisk Channel
- * \param digit_string Digits String
- * \param buf_size The size of the Digits String buffer
- * \param expected Digits expected for this message type
- * \param received Pointer to number of digits received so far
- *
- * \retval 0 if all digits were successfully received
- * \retval 1 if a timeout occurred
- * \retval -1 if the caller hung up or on channel errors
- */
-static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int expected, int *received)
+/*
+* Send a single tone burst for a specified duration and frequency.
+* Returns 0 if successful
+*/
+static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn)
+{
+	int res = 0;
+	int i = 0;
+	int x = 0;
+	struct ast_frame *f, wf;
+	
+	struct {
+		unsigned char offset[AST_FRIENDLY_OFFSET];
+		unsigned char buf[640];
+	} tone_block;
+
+	for (;;) {
+
+		if (ast_waitfor(chan, -1) < 0) {
+			res = -1;
+			break;
+		}
+
+		f = ast_read(chan);
+		if (!f) {
+			res = -1;
+			break;
+		}
+
+		if (f->frametype == AST_FRAME_VOICE) {
+			wf.frametype = AST_FRAME_VOICE;
+			ast_format_set(&wf.subclass.format, AST_FORMAT_ULAW, 0);
+			wf.offset = AST_FRIENDLY_OFFSET;
+			wf.mallocd = 0;
+			wf.data.ptr = tone_block.buf;
+			wf.datalen = f->datalen;
+			wf.samples = wf.datalen;
+			
+			make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x);
+
+			i += wf.datalen / 8;
+			if (i > duration) {
+				ast_frfree(f);
+				break;
+			}
+			if (ast_write(chan, &wf)) {
+				ast_verb(4, "AlarmReceiver: Failed to write frame on %s\n", ast_channel_name(chan));
+				ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",ast_channel_name(chan));
+				res = -1;
+				ast_frfree(f);
+				break;
+			}
+		}
+
+		ast_frfree(f);
+	}
+	return res;
+}
+
+/*
+* Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential
+* treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent
+* digits.
+*
+* Returns 0 if all digits successfully received.
+* Returns 1 if a digit time out occurred
+* Returns -1 if the caller hung up or there was a channel error.
+*
+*/
+static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
 {
-	int rtn = 0;
+	int res = 0;
+	int i = 0;
 	int r;
 	struct ast_frame *f;
 	struct timeval lastdigittime;
 
 	lastdigittime = ast_tvnow();
-	while (*received < expected && *received < buf_size - 1) {
-		/* If timed out, leave */
-		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((*received > 0) ? sdtimeout : fdtimeout)) {
+	for (;;) {
+		/* if outa time, leave */
+		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) {
 			ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan));
-			ast_debug(1, "AlarmReceiver: DTMF timeout on chan %s\n", ast_channel_name(chan));
-			rtn = 1;
+			ast_debug(1,"AlarmReceiver: DTMF timeout on chan %s\n",ast_channel_name(chan));
+			res = 1;
 			break;
 		}
 
@@ -274,73 +256,68 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
 			continue;
 		}
 
-		if ((f = ast_read(chan)) == NULL) {
-			rtn = -1;
+		f = ast_read(chan);
+
+		if (f == NULL) {
+			res = -1;
 			break;
 		}
 
 		/* If they hung up, leave */
-		if ((f->frametype == AST_FRAME_CONTROL)
-			&& (f->subclass.integer == AST_CONTROL_HANGUP)) {
+		if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
 			if (f->data.uint32) {
 				ast_channel_hangupcause_set(chan, f->data.uint32);
 			}
 			ast_frfree(f);
-			rtn = -1;
+			res = -1;
 			break;
 		}
 
-		/* If not DTMF, just do it again */
+		/* if not DTMF, just do it again */
 		if (f->frametype != AST_FRAME_DTMF) {
 			ast_frfree(f);
 			continue;
 		}
 
-		/* Save digit */
-		digit_string[(*received)++] = f->subclass.integer;
+		digit_string[i++] = f->subclass.integer;  /* save digit */
+
 		ast_frfree(f);
 
+		/* If we have all the digits we expect, leave */
+		if(i >= length)
+			break;
+
 		lastdigittime = ast_tvnow();
 	}
 
-	/* Null terminate the end of the digit_string */
-	digit_string[*received] = '\0';
-
-	return rtn;
+	digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
+	return res;
 }
 
-/*!
- * \brief Write metadata to log file
- *
- * \param logfile Log File Pointer
- * \param signalling_type Signaling Type
- * \param chan Asterisk Channel
- * \param no_checksum Expecting messages without checksum
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan, int no_checksum)
+/*
+* Write the metadata to the log file
+*/
+static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
 {
+	int res = 0;
 	struct timeval t;
 	struct ast_tm now;
 	char *cl;
 	char *cn;
 	char workstring[80];
 	char timestamp[80];
-
+	
 	/* Extract the caller ID location */
 	ast_copy_string(workstring,
-		S_COR(ast_channel_caller(chan)->id.number.valid,
-		ast_channel_caller(chan)->id.number.str, ""), sizeof(workstring));
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
+		sizeof(workstring));
 	ast_shrink_phone_number(workstring);
 	if (ast_strlen_zero(workstring)) {
 		cl = "<unknown>";
 	} else {
 		cl = workstring;
 	}
-	cn = S_COR(ast_channel_caller(chan)->id.name.valid,
-		ast_channel_caller(chan)->id.name.str, "<unknown>");
+	cn = S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>");
 
 	/* Get the current time */
 	t = ast_tvnow();
@@ -349,369 +326,155 @@ static int write_metadata(FILE *logfile, char *signalling_type, struct ast_chann
 	/* Format the time */
 	ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
 
-	if (no_group_meta && fprintf(logfile, "PROTOCOL=%s\n"
-			"CHECKSUM=%s\n"
-			"CALLINGFROM=%s\n"
-			"CALLERNAME=%s\n"
-			"TIMESTAMP=%s\n\n",
-			signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
-		return 0;
-	} else if (fprintf(logfile, "\n\n[metadata]\n\n"
-			"PROTOCOL=%s\n"
-			"CHECKSUM=%s\n"
-			"CALLINGFROM=%s\n"
-			"CALLERNAME=%s\n"
-			"TIMESTAMP=%s\n\n"
-			"[events]\n\n",
-			signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
-		return 0;
+	res = fprintf(logfile, "\n\n[metadata]\n\n");
+	if (res >= 0) {
+		res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
+	}
+	if (res >= 0) {
+		res = fprintf(logfile, "CALLINGFROM=%s\n", cl);
+	}
+	if (res >= 0) {
+		res = fprintf(logfile, "CALLERNAME=%s\n", cn);
+	}
+	if (res >= 0) {
+		res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
+	}
+	if (res >= 0) {
+		res = fprintf(logfile, "[events]\n\n");
+	}
+	if (res < 0) {
+		ast_verb(3, "AlarmReceiver: can't write metadata\n");
+		ast_debug(1,"AlarmReceiver: can't write metadata\n");
+	} else {
+		res = 0;
 	}
 
-	ast_verb(3, "AlarmReceiver: can't write metadata\n");
-	ast_debug(1, "AlarmReceiver: can't write metadata\n");
-	return -1;
+	return res;
 }
 
-/*!
- * \brief Log a single event
- *
- * \param logfile Log File Pointer
- * \param event Event Structure
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int write_event(FILE *logfile, event_node_t *event)
+/*
+* Write a single event to the log file
+*/
+static int write_event( FILE *logfile,  event_node_t *event)
 {
-	if (fprintf(logfile, "%s%s\n", no_group_meta ? "event=" : "", event->data) < 0) {
-		return -1;
-	}
+	int res = 0;
 
-	return 0;
+	if (fprintf(logfile, "%s\n", event->data) < 0)
+		res = -1;
+
+	return res;
 }
 
-/*!
- * \brief Log events if configuration key logindividualevents is enabled or on exit
- *
- * \param chan Asterisk Channel
- * \param signalling_type Signaling Type
- * \param event Event Structure
- * \param no_checksum Expecting messages without checksum
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event, int no_checksum)
+/*
+* If we are configured to log events, do so here.
+*
+*/
+static int log_events(struct ast_channel *chan,  char *signalling_type, event_node_t *event)
 {
-	char workstring[sizeof(event_spool_dir) + sizeof(event_file)] = "";
+
+	int res = 0;
+	char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
 	int fd;
 	FILE *logfile;
 	event_node_t *elp = event;
-
+	
 	if (!ast_strlen_zero(event_spool_dir)) {
-
+		
 		/* Make a template */
 		ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
 		strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
-
+		
 		/* Make the temporary file */
 		fd = mkstemp(workstring);
-
+		
 		if (fd == -1) {
 			ast_verb(3, "AlarmReceiver: can't make temporary file\n");
-			ast_debug(1, "AlarmReceiver: can't make temporary file\n");
-			return -1;
-		}
-
-		if ((logfile = fdopen(fd, "w")) == NULL) {
-			return -1;
-		}
-
-		/* Write the file */
-		if (write_metadata(logfile, signalling_type, chan, no_checksum)) {
-			fflush(logfile);
-			fclose(logfile);
-			return -1;
-		}
-
-		while ((elp != NULL) && (write_event(logfile, elp) == 0)) {
-			elp = elp->next;
-		}
-
-		fflush(logfile);
-		fclose(logfile);
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Verify Ademco checksum
- * \since 11.0
- *
- * \param event Received DTMF String
- * \param expected Number of Digits expected
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int ademco_verify_checksum(char *event, int expected)
-{
-	int checksum = 0;
-	int i, j;
-
-	for (j = 0; j < expected; j++) {
-		for (i = 0; i < ARRAY_LEN(digits_mapping); i++) {
-			if (digits_mapping[i].digit == event[j]) {
-				break;
-			}
-		}
-
-		if (i >= ARRAY_LEN(digits_mapping)) {
-			ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
-			return -1;
+			ast_debug(1,"AlarmReceiver: can't make temporary file\n");
+			res = -1;
+		}
+
+		if (!res) {
+			logfile = fdopen(fd, "w");
+			if (logfile) {
+				/* Write the file */
+				res = write_metadata(logfile, signalling_type, chan);
+				if (!res)
+					while ((!res) && (elp != NULL)) {
+						res = write_event(logfile, elp);
+						elp = elp->next;
+					}
+				if (!res) {
+					if (fflush(logfile) == EOF)
+						res = -1;
+					if (!res) {
+						if (fclose(logfile) == EOF)
+							res = -1;
+					}
+				}
+			} else
+				res = -1;
 		}
-
-		checksum += digits_mapping[i].weight;
-	}
-
-	/* Checksum is mod(15) of the total */
-	if (!(checksum % 15)) {
-		return 0;
-	}
-
-	return -1;
-}
-
-/*!
- * \brief Send a single tone burst for a specifed duration and frequency.
- * \since 11.0
- *
- * \param chan Asterisk Channel
- * \param tone_freq Frequency of the tone to send
- * \param tone_duration Tone duration in ms
- * \param delay Delay before sending the tone
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int delay)
-{
-	if (delay && ast_safe_sleep(chan, delay)) {
-		return -1;
-	}
-
-	if (ast_playtones_start(chan, toneloudness, tone_freq, 0)) {
-		return -1;
-	}
-
-	if (ast_safe_sleep(chan, tone_duration)) {
-		return -1;
-	}
-
-	ast_playtones_stop(chan);
-	return 0;
-}
-
-/*!
- * \brief Check if the message is in known and valid Ademco format
- *
- * \param signalling_type Expected signalling type for the message
- * \param event event received
- *
- * \retval 0 The event is valid
- * \retval -1 The event is not valid
- */
-static int ademco_check_valid(char *signalling_type, char *event)
-{
-	if (!strcmp(signalling_type, UNKNOWN_FORMAT)) {
-		return 1;
-	}
-
-	if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
-		&& strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
-		&& strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
-		return -1;
-	}
-
-	if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_1) && strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
-		return -1;
-	}
-
-	if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2) && strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
-		return -1;
-	}
-
-	if (!strcmp(signalling_type, ADEMCO_HIGH_SPEED) && strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
-		return -1;
-	}
-
-	if (!strcmp(signalling_type, ADEMCO_SUPER_FAST) && strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Detect the message format of an event
- *
- * \param signalling_type Expected signalling type for the message
- * \param event event received
- * \param no_checksum Should we calculate checksum for the message
- *
- * \returns The expected digits for the detected event type
- */
-static int ademco_detect_format(char *signalling_type, char *event, int *no_checksum)
-{
-	int res = 16;
-
-	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
-		|| !strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
-		sprintf(signalling_type, "%s", ADEMCO_CONTACT_ID);
-	}
-
-	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
-		sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_1);
-		res = 8;
-	}
-
-	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
-		sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_2);
-		res = 9;
-	}
-
-	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
-		sprintf(signalling_type, "%s", ADEMCO_HIGH_SPEED);
-	}
-
-	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
-		sprintf(signalling_type, "%s", ADEMCO_SUPER_FAST);
-		*no_checksum = 1;
-		res = 15;
-	}
-
-	if (strcmp(signalling_type, UNKNOWN_FORMAT)) {
-		ast_verb(4, "AlarmMonitoring: Detected format %s.\n", signalling_type);
-		ast_debug(1, "AlarmMonitoring: Autodetected format %s.\n", signalling_type);
 	}
 
 	return res;
 }
 
-/*!
- * \brief Receive Ademco ContactID or other format Data String
- *
- * \param chan Asterisk Channel
- * \param ehead Pointer to events list
- * \param signalling_type Expected signalling type for the message
- * \param no_checksum Should we calculate checksum for the message
- *
- * \retval 0 success
- * \retval -1 failure
- */
-static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum)
+/*
+* This function implements the logic to receive the Ademco contact ID  format.
+*
+* The function will return 0 when the caller hangs up, else a -1 if there was a problem.
+*/
+static int receive_ademco_contact_id(struct ast_channel *chan, const void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
 {
+	int i, j;
 	int res = 0;
-	const char *limit;
+	int checksum;
 	char event[17];
 	event_node_t *enew, *elp;
 	int got_some_digits = 0;
 	int events_received = 0;
 	int ack_retries = 0;
-	int limit_retries = 0;
-	int expected_length = sizeof(event) - 1;
+	
+	static char digit_map[15] = "0123456789*#ABC";
+	static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
 
 	database_increment("calls-received");
 
 	/* Wait for first event */
-	ast_verb(4, "AlarmReceiver: Waiting for first event from panel...\n");
+	ast_verb(4, "AlarmReceiver: Waiting for first event from panel\n");
 
 	while (res >= 0) {
-		int digits_received = 0;
-
-		res = 0;
-
-		if (log_individual_events) {
-			sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
-			expected_length = 16;
-			*no_checksum = 0;
-		}
-
 		if (got_some_digits == 0) {
 			/* Send ACK tone sequence */
 			ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
-			res = send_tone_burst(chan, "1400", 100, 0);
+			res = send_tone_burst(chan, 1400.0, 100, tldn);
+			if (!res)
+				res = ast_safe_sleep(chan, 100);
 			if (!res) {
 				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
-				res = send_tone_burst(chan, "2300", 100, 100);
+				res = send_tone_burst(chan, 2300.0, 100, tldn);
 			}
 		}
-		if (res) {
-			return -1;
-		}
-
-		res = receive_dtmf_digits(chan, event, sizeof(event), expected_length, &digits_received);
+		if ( res >= 0)
+			res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
 		if (res < 0) {
 			if (events_received == 0) {
 				/* Hangup with no events received should be logged in the DB */
 				database_increment("no-events-received");
-				ast_verb(4, "AlarmReceiver: No events received!\n");
 			} else {
 				if (ack_retries) {
-					database_increment("ack-retries");
 					ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
+					database_increment("ack-retries");
 				}
 			}
 			ast_verb(4, "AlarmReceiver: App exiting...\n");
+			res = -1;
 			break;
 		}
 
-		if (!strcmp(signalling_type, UNKNOWN_FORMAT) && digits_received > 5) {
-			expected_length = ademco_detect_format(signalling_type, event, no_checksum);
-
-			if (res > 0) {
-				if (digits_received == expected_length) {
-					res = limit_retries = 0;
-				} else if (digits_received == expected_length - 1
-					&& (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2)
-					|| !strcmp(signalling_type, ADEMCO_EXPRESS_4_1))) {
-					/* ADEMCO EXPRESS without checksum */
-					res = limit_retries = 0;
-					expected_length--;
-					*no_checksum = 1;
-					ast_verb(4, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
-					ast_debug(1, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
-				}
-			}
-		}
-
-		ast_channel_lock(chan);
-		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_CALL_LIMIT");
-		if (!ast_strlen_zero(limit)) {
-			if (ast_tvdiff_ms(ast_tvnow(), call_start_time) > atoi(limit)) {
-				ast_channel_unlock(chan);
-				return -1;
-			}
-		}
-		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_RETRIES_LIMIT");
-		ast_channel_unlock(chan);
-		if (!ast_strlen_zero(limit)) {
-			if (limit_retries + 1 >= atoi(limit)) {
-				return -1;
-			}
-		}
-
-		if (res) {
+		if (res != 0) {
 			/* Didn't get all of the digits */
 			ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
-			limit_retries++;
-
-			if (!events_received && strcmp(signalling_type, UNKNOWN_FORMAT))
-			{
-				sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
-				expected_length = sizeof(event) - 1;
-			}
 
 			if (!got_some_digits) {
 				got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
@@ -726,7 +489,28 @@ static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead,
 		ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
 
 		/* Calculate checksum */
-		if (!(*no_checksum) && ademco_verify_checksum(event, expected_length)) {
+
+		for (j = 0, checksum = 0; j < 16; j++) {
+			for (i = 0; i < sizeof(digit_map); i++) {
+				if (digit_map[i] == event[j])
+					break;
+			}
+
+			if (i == 16)
+				break;
+
+			checksum += digit_weights[i];
+		}
+		if (i == 16) {
+			ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
+			continue; /* Bad character */
+		}
+
+		/* Checksum is mod(15) of the total */
+
+		checksum = checksum % 15;
+
+		if (checksum) {
 			database_increment("checksum-errors");
 			ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
 			ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
@@ -734,122 +518,120 @@ static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead,
 		}
 
 		/* Check the message type for correctness */
-		if (ademco_check_valid(signalling_type, event)) {
-			database_increment("format-errors");
-			ast_verb(2, "AlarmReceiver: Wrong message type\n");
-			ast_debug(1, "AlarmReceiver: Wrong message type\n");
+
+		if (strncmp(event + 4, "18", 2)) {
+			if (strncmp(event + 4, "98", 2)) {
+				database_increment("format-errors");
+				ast_verb(2, "AlarmReceiver: Wrong message type\n");
+				ast_debug(1, "AlarmReceiver: Wrong message type\n");
 			continue;
+			}
 		}
 
 		events_received++;
 
 		/* Queue the Event */
 		if (!(enew = ast_calloc(1, sizeof(*enew)))) {
-			return -1;
+			res = -1;
+			break;
 		}
 
 		enew->next = NULL;
 		ast_copy_string(enew->data, event, sizeof(enew->data));
 
-		/* Insert event onto end of list */
-		if (*ehead == NULL) {
+		/*
+		* Insert event onto end of list
+		*/
+		if (*ehead == NULL)
 			*ehead = enew;
-		} else {
-			for (elp = *ehead; elp->next != NULL; elp = elp->next) {
-				;
-			}
+		else {
+			for(elp = *ehead; elp->next != NULL; elp = elp->next)
+			;
 			elp->next = enew;
 		}
 
-		/* Let the user have the option of logging the single event before sending the kissoff tone */
-		if (log_individual_events && log_events(chan, signalling_type, enew, *no_checksum)) {
-			return -1;
-		}
+		if (res > 0)
+			res = 0;
 
-		/* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */
-		if (send_tone_burst(chan, "1400", 900, 200)) {
-			return -1;
-		}
+		/* Let the user have the option of logging the single event before sending the kissoff tone */
+		if ((res == 0) && (log_individual_events))
+			res = log_events(chan, ADEMCO_CONTACT_ID, enew);
+		/* Wait 200 msec before sending kissoff */
+		if (res == 0)
+			res = ast_safe_sleep(chan, 200);
 
-		/* If audio call follows, exit alarm receiver app */
-		if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
-			&& !strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) {
-			ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n");
-			return 0;
-		}
+		/* Send the kissoff tone */
+		if (res == 0)
+			res = send_tone_burst(chan, 1400.0, 900, tldn);
 	}
 
 	return res;
 }
 
-/*!
- * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
- *
- * \param chan Asterisk Channel
- * \param data Application data
- *
- * \retval 0 success
- * \retval -1 failure
- */
+/*
+* This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
+* This function will always return 0.
+*/
 static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
-	int no_checksum = 0;
 	event_node_t *elp, *efree;
 	char signalling_type[64] = "";
 	event_node_t *event_head = NULL;
 
-	if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
-		(ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
-		ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
-		if (ast_set_write_format(chan, ast_format_ulaw)) {
-			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
-			return -1;
-		}
+	/* Set write and read formats to ULAW */
+	ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n");
+
+	if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) {
+		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
+		return -1;
 	}
 
-	if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
-		(ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
-		ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
-		if (ast_set_read_format(chan, ast_format_ulaw)) {
-			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
-			return -1;
-		}
+	if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) {
+		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
+		return -1;
 	}
 
 	/* Set default values for this invocation of the application */
-	ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
-	call_start_time = ast_tvnow();
+	ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
 
 	/* Answer the channel if it is not already */
+	ast_verb(4, "AlarmReceiver: Answering channel\n");
 	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_verb(4, "AlarmReceiver: Answering channel\n");
-		if (ast_answer(chan)) {
+		if ((res = ast_answer(chan)))
 			return -1;
-		}
 	}
 
 	/* Wait for the connection to settle post-answer */
 	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
-	if (ast_safe_sleep(chan, answait)) {
-		return -1;
-	}
+	res = ast_safe_sleep(chan, 1250);
 
 	/* Attempt to receive the events */
-	receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);
+	if (!res) {
+		/* Determine the protocol to receive in advance */
+		/* Note: Ademco contact is the only one supported at this time */
+		/* Others may be added later */
+		if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
+			receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
+		else
+			res = -1;
+	}
 
 	/* Events queued by receiver, write them all out here if so configured */
-	if (!log_individual_events) {
-		res = log_events(chan, signalling_type, event_head, no_checksum);
-	}
+	if ((!res) && (log_individual_events == 0))
+		res = log_events(chan, signalling_type, event_head);
 
-	/* Do we exec a command line at the end? */
+	/*
+	* Do we exec a command line at the end?
+	*/
 	if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
 		ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
 		ast_safe_system(event_app);
 	}
 
-	/* Free up the data allocated in our linked list */
+	/*
+	* Free up the data allocated in our linked list
+	*/
 	for (elp = event_head; (elp != NULL);) {
 		efree = elp;
 		elp = elp->next;
@@ -859,19 +641,14 @@ static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
 	return 0;
 }
 
-/*!
- * \brief Load the configuration from the configuration file
- *
- * \param reload True on reload
- *
- * \retval 1 success
- * \retval 0 failure
- */
-static int load_config(int reload)
+/*
+* Load the configuration from the configuration file
+*/
+static int load_config(void)
 {
 	struct ast_config *cfg;
-	const char *value;
-	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	const char *p;
+	struct ast_flags config_flags = { 0 };
 
 	/* Read in the config file */
 	cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
@@ -879,124 +656,79 @@ static int load_config(int reload)
 	if (!cfg) {
 		ast_verb(4, "AlarmReceiver: No config file\n");
 		return 0;
-	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-		return 1;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n",
-			ALMRCV_CONFIG);
+		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", ALMRCV_CONFIG);
 		return 0;
-	}
-
-	if ((value = ast_variable_retrieve(cfg, "general", "eventcmd")) != NULL) {
-		ast_copy_string(event_app, value, sizeof(event_app));
-	}
-
-	if ((value = ast_variable_retrieve(cfg, "general", "loudness")) != NULL) {
-		toneloudness = atoi(value);
-		if (toneloudness < 100) {
-			toneloudness = 100;
-		} else if (toneloudness > 8192) {
-			toneloudness = 8192;
+	} else {
+		p = ast_variable_retrieve(cfg, "general", "eventcmd");
+		if (p) {
+			ast_copy_string(event_app, p, sizeof(event_app));
 		}
-	}
-
-	if ((value = ast_variable_retrieve(cfg, "general", "fdtimeout")) != NULL) {
-		fdtimeout = atoi(value);
-		if (fdtimeout < 1000) {
-			fdtimeout = 1000;
-		} else if (fdtimeout > 10000) {
-			fdtimeout = 10000;
+		p = ast_variable_retrieve(cfg, "general", "loudness");
+		if (p) {
+			toneloudness = atoi(p);
+			if(toneloudness < 100)
+				toneloudness = 100;
+			if(toneloudness > 8192)
+				toneloudness = 8192;
 		}
-	}
-
-	if ((value = ast_variable_retrieve(cfg, "general", "sdtimeout")) != NULL) {
-		sdtimeout = atoi(value);
-		if (sdtimeout < 110) {
-			sdtimeout = 110;
-		} else if (sdtimeout > 4000) {
-			sdtimeout = 4000;
+		p = ast_variable_retrieve(cfg, "general", "fdtimeout");
+		if (p) {
+			fdtimeout = atoi(p);
+			if(fdtimeout < 1000)
+				fdtimeout = 1000;
+			if(fdtimeout > 10000)
+				fdtimeout = 10000;
 		}
-	}
 
-	if ((value = ast_variable_retrieve(cfg, "general", "answait")) != NULL) {
-		answait = atoi(value);
-		if (answait < 500) {
-			answait = 500;
-		} else if (answait > 10000) {
-			answait = 10000;
+		p = ast_variable_retrieve(cfg, "general", "sdtimeout");
+		if (p) {
+			sdtimeout = atoi(p);
+			if(sdtimeout < 110)
+				sdtimeout = 110;
+			if(sdtimeout > 4000)
+				sdtimeout = 4000;
 		}
-	}
 
-	if ((value = ast_variable_retrieve(cfg, "general", "no_group_meta")) != NULL) {
-		no_group_meta = ast_true(value);
-	}
-
-	if ((value = ast_variable_retrieve(cfg, "general", "logindividualevents")) != NULL) {
-		log_individual_events = ast_true(value);
-	}
+		p = ast_variable_retrieve(cfg, "general", "logindividualevents");
+		if (p)
+			log_individual_events = ast_true(p);
 
-	if ((value = ast_variable_retrieve(cfg, "general", "eventspooldir")) != NULL) {
-		ast_copy_string(event_spool_dir, value, sizeof(event_spool_dir));
-	}
+		p = ast_variable_retrieve(cfg, "general", "eventspooldir");
+		if (p) {
+			ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
+		}
 
-	if ((value = ast_variable_retrieve(cfg, "general", "timestampformat")) != NULL) {
-		ast_copy_string(time_stamp_format, value, sizeof(time_stamp_format));
-	}
+		p = ast_variable_retrieve(cfg, "general", "timestampformat");
+		if (p) {
+			ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
+		}
 
-	if ((value = ast_variable_retrieve(cfg, "general", "db-family")) != NULL) {
-		ast_copy_string(db_family, value, sizeof(db_family));
+		p = ast_variable_retrieve(cfg, "general", "db-family");
+		if (p) {
+			ast_copy_string(db_family, p, sizeof(db_family));
+		}
+		ast_config_destroy(cfg);
 	}
-
-	ast_config_destroy(cfg);
-
 	return 1;
 }
 
-/*!
- * \brief Unregister Alarm Receiver App
- *
- * \retval 0 success
- * \retval -1 failure
- */
+/*
+* These functions are required to implement an Asterisk App.
+*/
 static int unload_module(void)
 {
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
-	if (load_config(0)) {
-		if (ast_register_application_xml(app, alarmreceiver_exec)) {
+	if (load_config()) {
+		if (ast_register_application_xml(app, alarmreceiver_exec))
 			return AST_MODULE_LOAD_FAILURE;
-		}
-		return AST_MODULE_LOAD_SUCCESS;
-	}
-
-	return AST_MODULE_LOAD_DECLINE;
-}
-
-static int reload(void)
-{
-	if (load_config(1)) {
 		return AST_MODULE_LOAD_SUCCESS;
-	}
-
-	return AST_MODULE_LOAD_DECLINE;
+	} else
+		return AST_MODULE_LOAD_DECLINE;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Alarm Receiver for Asterisk",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
-		.load = load_module,
-		.unload = unload_module,
-		.reload = reload,
-);
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");
diff --git a/apps/app_amd.c b/apps/app_amd.c
index b527aa9..a849aad 100644
--- a/apps/app_amd.c
+++ b/apps/app_amd.c
@@ -24,17 +24,6 @@
  * \brief Answering machine detection
  *
  * \author Claude Klimos (claude.klimos at aheeva.com)
- *
- * \ingroup applications
- */
-
-/*! \li \ref app_amd.c uses the configuration file \ref amd.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page amd.conf amd.conf
- * \verbinclude amd.conf.sample
  */
 
 /*** MODULEINFO
@@ -43,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
@@ -52,7 +41,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/pbx.h"
 #include "asterisk/config.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="AMD" language="en_US">
@@ -126,6 +114,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 						Voice Duration - Greeting.
 					</value>
 					<value name="MAXWORDLENGTH">
+						Word Length - max length of a single word.
+					</value>
+					<value name="MAXWORDS">
 						Word Count - maximum number of words.
 					</value>	
 				</variable>
@@ -164,7 +155,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
 	struct ast_frame *f = NULL;
 	struct ast_dsp *silenceDetector = NULL;
 	int dspsilence = 0, framelength = 0;
-	RAII_VAR(struct ast_format *, readFormat, NULL, ao2_cleanup);
+	struct ast_format readFormat;
 	int inInitialSilence = 1;
 	int inGreeting = 0;
 	int voiceDuration = 0;
@@ -203,10 +194,11 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(argMaximumWordLength);
 	);
 
+	ast_format_clear(&readFormat);
 	ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
 		S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
 		S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
-		ast_format_get_name(ast_channel_readformat(chan)));
+		ast_getformatname(ast_channel_readformat(chan)));
 
 	/* Lets parse the arguments. */
 	if (!ast_strlen_zero(parse)) {
@@ -255,8 +247,8 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
 				minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
 
 	/* Set read format to signed linear so we get signed linear frames in */
-	readFormat = ao2_bump(ast_channel_readformat(chan));
-	if (ast_set_read_format(chan, ast_format_slin) < 0 ) {
+	ast_format_copy(&readFormat, ast_channel_readformat(chan));
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0 ) {
 		ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", ast_channel_name(chan));
 		pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
 		pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
@@ -289,7 +281,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
 		if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) {
 			/* If the total time exceeds the analysis time then give up as we are not too sure */
 			if (f->frametype == AST_FRAME_VOICE) {
-				framelength = (ast_codec_samples_count(f) / DEFAULT_SAMPLES_PER_MS);
+				framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
 			} else {
 				framelength = 2 * maxWaitTimeForFrame;
 			}
@@ -412,7 +404,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
 	pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
 
 	/* Restore channel read format */
-	if (readFormat && ast_set_read_format(chan, readFormat))
+	if (readFormat.id && ast_set_read_format(chan, &readFormat))
 		ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", ast_channel_name(chan));
 
 	/* Free the DSP used to detect silence */
@@ -498,22 +490,12 @@ static int unload_module(void)
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
-	if (load_config(0) || ast_register_application_xml(app, amd_exec)) {
+	if (load_config(0))
 		return AST_MODULE_LOAD_DECLINE;
-	}
-
+	if (ast_register_application_xml(app, amd_exec))
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -525,7 +507,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_authenticate.c b/apps/app_authenticate.c
index af81d02..fbb4300 100644
--- a/apps/app_authenticate.c
+++ b/apps/app_authenticate.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 391947 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -213,9 +213,9 @@ static int auth_exec(struct ast_channel *chan, const char *data)
 						continue;
 					ast_md5_hash(md5passwd, passwd);
 					if (!strcmp(md5passwd, md5secret)) {
-						if (ast_test_flag(&flags, OPT_ACCOUNT)) {
+						if (ast_test_flag(&flags,OPT_ACCOUNT)) {
 							ast_channel_lock(chan);
-							ast_channel_accountcode_set(chan, buf);
+							ast_cdr_setaccount(chan, buf);
 							ast_channel_unlock(chan);
 						}
 						break;
@@ -224,7 +224,7 @@ static int auth_exec(struct ast_channel *chan, const char *data)
 					if (!strcmp(passwd, buf)) {
 						if (ast_test_flag(&flags, OPT_ACCOUNT)) {
 							ast_channel_lock(chan);
-							ast_channel_accountcode_set(chan, buf);
+							ast_cdr_setaccount(chan, buf);
 							ast_channel_unlock(chan);
 						}
 						break;
@@ -250,7 +250,7 @@ static int auth_exec(struct ast_channel *chan, const char *data)
 	if ((retries < 3) && !res) {
 		if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE)) {
 			ast_channel_lock(chan);
-			ast_channel_accountcode_set(chan, passwd);
+			ast_cdr_setaccount(chan, passwd);
 			ast_channel_unlock(chan);
 		}
 		if (!(res = ast_streamfile(chan, "auth-thankyou", ast_channel_language(chan))))
diff --git a/apps/app_bridgewait.c b/apps/app_bridgewait.c
deleted file mode 100644
index d40f6c8..0000000
--- a/apps/app_bridgewait.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * Author: Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Application to place the channel into a holding Bridge
- *
- * \author Jonathan Rose <jrose at digium.com>
- *
- * \ingroup applications
- */
-
-/*** MODULEINFO
-	<depend>bridge_holding</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419539 $")
-
-#include "asterisk/file.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/features.h"
-#include "asterisk/say.h"
-#include "asterisk/lock.h"
-#include "asterisk/utils.h"
-#include "asterisk/app.h"
-#include "asterisk/bridge.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/causes.h"
-
-/*** DOCUMENTATION
-	<application name="BridgeWait" language="en_US">
-		<synopsis>
-			Put a call into the holding bridge.
-		</synopsis>
-		<syntax>
-			<parameter name="name">
-				<para>Name of the holding bridge to join. This is a handle for <literal>BridgeWait</literal>
-				only and does not affect the actual bridges that are created. If not provided,
-				the reserved name <literal>default</literal> will be used.
-				</para>
-			</parameter>
-			<parameter name="role" required="false">
-				<para>Defines the channel's purpose for entering the holding bridge. Values are case sensitive.
-				</para>
-				<enumlist>
-					<enum name="participant">
-						<para>The channel will enter the holding bridge to be placed on hold
-						until it is removed from the bridge for some reason. (default)</para>
-					</enum>
-					<enum name="announcer">
-						<para>The channel will enter the holding bridge to make announcements
-						to channels that are currently in the holding bridge. While an
-						announcer is present, holding for the participants will be
-						suspended.</para>
-					</enum>
-				</enumlist>
-			</parameter>
-			<parameter name="options">
-				<optionlist>
-					<option name="m">
-						<argument name="class" required="true" />
-						<para>The specified MOH class will be used/suggested for
-						music on hold operations. This option will only be useful for
-						entertainment modes that use it (m and h).</para>
-					</option>
-					<option name="e">
-						<para>Which entertainment mechanism should be used while on hold
-						in the holding bridge. Only the first letter is read.</para>
-						<enumlist>
-							<enum name="m"><para>Play music on hold (default)</para></enum>
-							<enum name="r"><para>Ring without pause</para></enum>
-							<enum name="s"><para>Generate silent audio</para></enum>
-							<enum name="h"><para>Put the channel on hold</para></enum>
-							<enum name="n"><para>No entertainment</para></enum>
-						</enumlist>
-					</option>
-					<option name="S">
-						<argument name="duration" required="true" />
-						<para>Automatically exit the bridge and return to the PBX after
-						<emphasis>duration</emphasis> seconds.</para>
-					</option>
-				</optionlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>This application places the incoming channel into a holding bridge.
-			The channel will then wait in the holding bridge until some event occurs
-			which removes it from the holding bridge.</para>
-			<note><para>This application will answer calls which haven't already
-			been answered.</para></note>
-		</description>
-	</application>
- ***/
-
-#define APP_NAME "BridgeWait"
-#define DEFAULT_BRIDGE_NAME "default"
-
-static struct ao2_container *wait_bridge_wrappers;
-
-struct wait_bridge_wrapper {
-	struct ast_bridge *bridge;     /*!< Bridge being wrapped by this wrapper */
-	char name[0];                  /*!< Name of the holding bridge wrapper */
-};
-
-static void wait_bridge_wrapper_destructor(void *obj)
-{
-	struct wait_bridge_wrapper *wrapper = obj;
-
-	if (wrapper->bridge) {
-		ast_bridge_destroy(wrapper->bridge, 0);
-	}
-}
-
-static struct wait_bridge_wrapper *wait_bridge_wrapper_find_by_name(const char *bridge_name)
-{
-	return ao2_find(wait_bridge_wrappers, bridge_name, OBJ_KEY);
-}
-
-static int wait_bridge_hash_fn(const void *obj, const int flags)
-{
-	const struct wait_bridge_wrapper *entry;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_POINTER:
-		entry = obj;
-		return ast_str_hash(entry->name);
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int wait_bridge_sort_fn(const void *obj_left, const void *obj_right, const int flags)
-{
-	const struct wait_bridge_wrapper *left = obj_left;
-	const struct wait_bridge_wrapper *right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_POINTER:
-		right_key = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(left->name, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(left->name, right_key, strlen(right_key));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-enum bridgewait_flags {
-	MUXFLAG_MOHCLASS = (1 << 0),
-	MUXFLAG_ENTERTAINMENT = (1 << 1),
-	MUXFLAG_TIMEOUT = (1 << 2),
-};
-
-enum bridgewait_args {
-	OPT_ARG_ENTERTAINMENT,
-	OPT_ARG_MOHCLASS,
-	OPT_ARG_TIMEOUT,
-	OPT_ARG_ARRAY_SIZE, /* Always the last element of the enum */
-};
-
-AST_APP_OPTIONS(bridgewait_opts, {
-	AST_APP_OPTION_ARG('e', MUXFLAG_ENTERTAINMENT, OPT_ARG_ENTERTAINMENT),
-	AST_APP_OPTION_ARG('m', MUXFLAG_MOHCLASS, OPT_ARG_MOHCLASS),
-	AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
-});
-
-static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	ast_verb(3, "Channel %s timed out.\n", ast_channel_name(bridge_channel->chan));
-	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-		AST_CAUSE_NORMAL_CLEARING);
-	return -1;
-}
-
-static int apply_option_timeout(struct ast_bridge_features *features, char *duration_arg)
-{
-	unsigned int duration;
-
-	if (ast_strlen_zero(duration_arg)) {
-		ast_log(LOG_ERROR, "Timeout option 'S': No value provided.\n");
-		return -1;
-	}
-	if (sscanf(duration_arg, "%u", &duration) != 1 || duration == 0) {
-		ast_log(LOG_ERROR, "Timeout option 'S': Invalid value provided '%s'.\n",
-			duration_arg);
-		return -1;
-	}
-
-	duration *= 1000;
-	if (ast_bridge_interval_hook(features, 0, duration, bridgewait_timeout_callback,
-		NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		ast_log(LOG_ERROR, "Timeout option 'S': Could not create timer.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int apply_option_moh(struct ast_channel *chan, const char *class_arg)
-{
-	return ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", class_arg);
-}
-
-static int apply_option_entertainment(struct ast_channel *chan, const char *entertainment_arg)
-{
-	char entertainment = entertainment_arg[0];
-
-	switch (entertainment) {
-	case 'm':
-		return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
-	case 'r':
-		return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing");
-	case 's':
-		return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "silence");
-	case 'h':
-		return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "hold");
-	case 'n':
-		return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "none");
-	default:
-		ast_log(LOG_ERROR, "Invalid argument for BridgeWait entertainment '%s'\n", entertainment_arg);
-		return -1;
-	}
-}
-
-enum wait_bridge_roles {
-	ROLE_PARTICIPANT = 0,
-	ROLE_ANNOUNCER,
-	ROLE_INVALID,
-};
-
-static int process_options(struct ast_channel *chan, struct ast_flags *flags, char **opts, struct ast_bridge_features *features, enum wait_bridge_roles role)
-{
-	if (ast_test_flag(flags, MUXFLAG_TIMEOUT)) {
-		if (apply_option_timeout(features, opts[OPT_ARG_TIMEOUT])) {
-			return -1;
-		}
-	}
-
-	switch (role) {
-	case ROLE_PARTICIPANT:
-		if (ast_channel_add_bridge_role(chan, "holding_participant")) {
-			return -1;
-		}
-
-		if (ast_test_flag(flags, MUXFLAG_MOHCLASS)) {
-			if (apply_option_moh(chan, opts[OPT_ARG_MOHCLASS])) {
-				return -1;
-			}
-		}
-
-		if (ast_test_flag(flags, MUXFLAG_ENTERTAINMENT)) {
-			if (apply_option_entertainment(chan, opts[OPT_ARG_ENTERTAINMENT])) {
-				return -1;
-			}
-		}
-
-		break;
-	case ROLE_ANNOUNCER:
-		if (ast_channel_add_bridge_role(chan, "announcer")) {
-			return -1;
-		}
-		break;
-	case ROLE_INVALID:
-		ast_assert(0);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Allocate a new holding bridge wrapper with the given bridge name and bridge ID.
- *
- * \param bridge_name name of the bridge wrapper
- * \param bridge the bridge being wrapped
- *
- * \retval Pointer to the newly allocated holding bridge wrapper
- * \retval NULL if allocation failed. The bridge will be destroyed if this function fails.
- */
-static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char *bridge_name, struct ast_bridge *bridge)
-{
-	struct wait_bridge_wrapper *bridge_wrapper;
-
-	bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + strlen(bridge_name) + 1,
-		wait_bridge_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!bridge_wrapper) {
-		ast_bridge_destroy(bridge, 0);
-		return NULL;
-	}
-
-	strcpy(bridge_wrapper->name, bridge_name);
-	bridge_wrapper->bridge = bridge;
-
-	if (!ao2_link(wait_bridge_wrappers, bridge_wrapper)) {
-		ao2_cleanup(bridge_wrapper);
-		return NULL;
-	}
-
-	return bridge_wrapper;
-}
-
-static struct wait_bridge_wrapper *get_wait_bridge_wrapper(const char *bridge_name)
-{
-	struct wait_bridge_wrapper * wrapper;
-	struct ast_bridge *bridge = NULL;
-
-	SCOPED_AO2LOCK(lock, wait_bridge_wrappers);
-
-	if ((wrapper = wait_bridge_wrapper_find_by_name(bridge_name))) {
-		return wrapper;
-	}
-
-	/*
-	 * Holding bridges can allow local channel move/swap
-	 * optimization to the bridge.  However, we cannot allow it for
-	 * this holding bridge because the call will lose the channel
-	 * roles and dialplan location as a result.
-	 */
-	bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED, APP_NAME, bridge_name, NULL);
-
-	if (!bridge) {
-		return NULL;
-	}
-
-	/* The bridge reference is unconditionally passed. */
-	return wait_bridge_wrapper_alloc(bridge_name, bridge);
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief If we are down to the last reference of a wrapper and it's still contained within the list, remove it from the list.
- *
- * \param wrapper reference to wait bridge wrapper being checked for list culling - will be cleared on exit
- */
-static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper)
-{
-	if (!wrapper) {
-		return;
-	}
-
-	ao2_lock(wait_bridge_wrappers);
-	if (ao2_ref(wrapper, 0) == 2) {
-		/* Either we have the only real reference or else wrapper isn't in the container anyway. */
-		ao2_unlink(wait_bridge_wrappers, wrapper);
-	}
-	ao2_unlock(wait_bridge_wrappers);
-
-	ao2_cleanup(wrapper);
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Application callback for the bridgewait application
- *
- * \param chan channel running the application
- * \param data Arguments to the application
- *
- * \retval 0 Ran successfully and the call didn't hang up
- * \retval -1 Failed or the call was hung up by the time the channel exited the holding bridge
- */
-static enum wait_bridge_roles validate_role(const char *role)
-{
-	if (!strcmp(role, "participant")) {
-		return ROLE_PARTICIPANT;
-	} else if (!strcmp(role, "announcer")) {
-		return ROLE_ANNOUNCER;
-	} else {
-		return ROLE_INVALID;
-	}
-}
-
-static int bridgewait_exec(struct ast_channel *chan, const char *data)
-{
-	char *bridge_name = DEFAULT_BRIDGE_NAME;
-	struct ast_bridge_features chan_features;
-	struct ast_flags flags = { 0 };
-	char *parse;
-	enum wait_bridge_roles role = ROLE_PARTICIPANT;
-	char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
-	struct wait_bridge_wrapper *bridge_wrapper;
-	int res;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(name);
-		AST_APP_ARG(role);
-		AST_APP_ARG(options);
-		AST_APP_ARG(other);		/* Any remaining unused arguments */
-	);
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (!ast_strlen_zero(args.name)) {
-		bridge_name = args.name;
-	}
-
-	if (!ast_strlen_zero(args.role)) {
-		role = validate_role(args.role);
-		if (role == ROLE_INVALID) {
-			ast_log(LOG_ERROR, "Requested waiting bridge role '%s' is invalid.\n", args.role);
-			return -1;
-		}
-	}
-
-	if (ast_bridge_features_init(&chan_features)) {
-		ast_bridge_features_cleanup(&chan_features);
-		ast_log(LOG_ERROR, "'%s' failed to enter the waiting bridge - could not set up channel features\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-
-	if (args.options) {
-		ast_app_parse_options(bridgewait_opts, &flags, opts, args.options);
-	}
-
-	/* Answer the channel if needed */
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_answer(chan);
-	}
-
-	if (process_options(chan, &flags, opts, &chan_features, role)) {
-		ast_bridge_features_cleanup(&chan_features);
-		return -1;
-	}
-
-	bridge_wrapper = get_wait_bridge_wrapper(bridge_name);
-	if (!bridge_wrapper) {
-		ast_log(LOG_WARNING, "Failed to find or create waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
-		ast_bridge_features_cleanup(&chan_features);
-		return -1;
-	}
-
-	ast_verb(3, "%s is entering waiting bridge %s:%s\n", ast_channel_name(chan), bridge_name, bridge_wrapper->bridge->uniqueid);
-	res = ast_bridge_join(bridge_wrapper->bridge, chan, NULL, &chan_features, NULL, 0);
-	wait_wrapper_removal(bridge_wrapper);
-	ast_bridge_features_cleanup(&chan_features);
-
-	if (res) {
-		/* For the lifetime of the bridge wrapper the bridge itself will be valid, if an error occurs it is because
-		 * of extreme situations.
-		 */
-		ast_log(LOG_WARNING, "Failed to join waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
-	}
-
-	return (res || ast_check_hangup_locked(chan)) ? -1 : 0;
-}
-
-static int unload_module(void)
-{
-	ao2_cleanup(wait_bridge_wrappers);
-
-	return ast_unregister_application(APP_NAME);
-}
-
-static int load_module(void)
-{
-	wait_bridge_wrappers = ao2_container_alloc_hash(
-		AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-		37, wait_bridge_hash_fn, wait_bridge_sort_fn, NULL);
-
-	if (!wait_bridge_wrappers) {
-		return -1;
-	}
-
-	return ast_register_application_xml(APP_NAME, bridgewait_exec);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Place the channel into a holding bridge application");
diff --git a/apps/app_cdr.c b/apps/app_cdr.c
index 57b8402..3c24471 100644
--- a/apps/app_cdr.c
+++ b/apps/app_cdr.c
@@ -31,238 +31,42 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405314 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
-#include "asterisk/app.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
 
 /*** DOCUMENTATION
 	<application name="NoCDR" language="en_US">
 		<synopsis>
-			Tell Asterisk to not maintain a CDR for this channel.
+			Tell Asterisk to not maintain a CDR for the current call
 		</synopsis>
 		<syntax />
 		<description>
-			<para>This application will tell Asterisk not to maintain a CDR for
-			the current channel. This does <emphasis>NOT</emphasis> mean that
-			information is not tracked; rather, if the channel is hung up no
-			CDRs will be created for that channel.</para>
-			<para>If a subsequent call to ResetCDR occurs, all non-finalized
-			CDRs created for the channel will be enabled.</para>
-			<note><para>This application is deprecated. Please use the CDR_PROP
-			function to disable CDRs on a channel.</para></note>
+			<para>This application will tell Asterisk not to maintain a CDR for the current call.</para>
 		</description>
-		<see-also>
-			<ref type="application">ResetCDR</ref>
-			<ref type="function">CDR_PROP</ref>
-		</see-also>
-	</application>
-	<application name="ResetCDR" language="en_US">
-		<synopsis>
-			Resets the Call Data Record.
-		</synopsis>
-		<syntax>
-			<parameter name="options">
-				<optionlist>
-					<option name="v">
-						<para>Save the CDR variables during the reset.</para>
-					</option>
-					<option name="e">
-						<para>Enable the CDRs for this channel only (negate
-						effects of NoCDR).</para>
-					</option>
-				</optionlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>This application causes the Call Data Record to be reset.
-			Depending on the flags passed in, this can have several effects.
-			With no options, a reset does the following:</para>
-			<para>1. The <literal>start</literal> time is set to the current time.</para>
-			<para>2. If the channel is answered, the <literal>answer</literal> time is set to the
-			current time.</para>
-			<para>3. All variables are wiped from the CDR. Note that this step
-			can be prevented with the <literal>v</literal> option.</para>
-			<para>On the other hand, if the <literal>e</literal> option is
-			specified, the effects of the NoCDR application will be lifted. CDRs
-			will be re-enabled for this channel.</para>
-			<note><para>The <literal>e</literal> option is deprecated. Please
-			use the CDR_PROP function instead.</para></note>
-		</description>
-		<see-also>
-			<ref type="application">ForkCDR</ref>
-			<ref type="application">NoCDR</ref>
-			<ref type="function">CDR_PROP</ref>
-		</see-also>
 	</application>
  ***/
 
 static const char nocdr_app[] = "NoCDR";
-static const char resetcdr_app[] = "ResetCDR";
-
-enum reset_cdr_options {
-	OPT_DISABLE_DISPATCH = (1 << 0),
-	OPT_KEEP_VARS = (1 << 1),
-	OPT_ENABLE = (1 << 2),
-};
-
-AST_APP_OPTIONS(resetcdr_opts, {
-	AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
-	AST_APP_OPTION('e', AST_CDR_FLAG_DISABLE_ALL),
-});
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(appcdr_message_type);
-
-/*! \internal \brief Payload for the Stasis message sent to manipulate a CDR */
-struct app_cdr_message_payload {
-	/*! The name of the channel to be manipulated */
-	const char *channel_name;
-	/*! Disable the CDR for this channel */
-	int disable:1;
-	/*! Re-enable the CDR for this channel */
-	int reenable:1;
-	/*! Reset the CDR */
-	int reset:1;
-	/*! If reseting the CDR, keep the variables */
-	int keep_variables:1;
-};
-
-static void appcdr_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct app_cdr_message_payload *payload;
-
-	if (stasis_message_type(message) != appcdr_message_type()) {
-		return;
-	}
-
-	payload = stasis_message_data(message);
-	if (!payload) {
-		return;
-	}
-
-	if (payload->disable) {
-		if (ast_cdr_set_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
-			ast_log(AST_LOG_WARNING, "Failed to disable CDRs on channel %s\n",
-				payload->channel_name);
-		}
-	}
-
-	if (payload->reenable) {
-		if (ast_cdr_clear_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
-			ast_log(AST_LOG_WARNING, "Failed to enable CDRs on channel %s\n",
-				payload->channel_name);
-		}
-	}
-
-	if (payload->reset) {
-		if (ast_cdr_reset(payload->channel_name, payload->keep_variables)) {
-			ast_log(AST_LOG_WARNING, "Failed to reset CDRs on channel %s\n",
-				payload->channel_name);
-		}
-	}
-}
-
-static int publish_app_cdr_message(struct ast_channel *chan, struct app_cdr_message_payload *payload)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-
-	if (!router) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-
-	message = stasis_message_create(appcdr_message_type(), payload);
-	if (!message) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
-			payload->channel_name);
-		return -1;
-	}
-	stasis_message_router_publish_sync(router, message);
-
-	return 0;
-}
-
-static int resetcdr_exec(struct ast_channel *chan, const char *data)
-{
-	RAII_VAR(struct app_cdr_message_payload *, payload,
-		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
-	char *args;
-	struct ast_flags flags = { 0 };
-
-	if (!payload) {
-		return -1;
-	}
-
-	if (!ast_strlen_zero(data)) {
-		args = ast_strdupa(data);
-		ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
-	}
-
-	payload->channel_name = ast_channel_name(chan);
-	payload->reset = 1;
-
-	if (ast_test_flag(&flags, AST_CDR_FLAG_DISABLE_ALL)) {
-		payload->reenable = 1;
-	}
-
-	if (ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
-		payload->keep_variables = 1;
-	}
-
-	return publish_app_cdr_message(chan, payload);
-}
 
 static int nocdr_exec(struct ast_channel *chan, const char *data)
 {
-	RAII_VAR(struct app_cdr_message_payload *, payload,
-		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
-
-	if (!payload) {
-		return -1;
-	}
-
-	payload->channel_name = ast_channel_name(chan);
-	payload->disable = 1;
+	if (ast_channel_cdr(chan))
+		ast_set_flag(ast_channel_cdr(chan), AST_CDR_FLAG_POST_DISABLED);
 
-	return publish_app_cdr_message(chan, payload);
+	return 0;
 }
 
 static int unload_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-
-	if (router) {
-		stasis_message_router_remove(router, appcdr_message_type());
-	}
-	STASIS_MESSAGE_TYPE_CLEANUP(appcdr_message_type);
-	ast_unregister_application(nocdr_app);
-	ast_unregister_application(resetcdr_app);
-	return 0;
+	return ast_unregister_application(nocdr_app);
 }
 
 static int load_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-	int res = 0;
-
-	if (!router) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(appcdr_message_type);
-	res |= ast_register_application_xml(nocdr_app, nocdr_exec);
-	res |= ast_register_application_xml(resetcdr_app, resetcdr_exec);
-	res |= stasis_message_router_add(router, appcdr_message_type(),
-	                                 appcdr_callback, NULL);
-
-	if (res) {
+	if (ast_register_application_xml(nocdr_app, nocdr_exec))
 		return AST_MODULE_LOAD_FAILURE;
-	}
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/apps/app_celgenuserevent.c b/apps/app_celgenuserevent.c
index 69884fe..f5714d0 100644
--- a/apps/app_celgenuserevent.c
+++ b/apps/app_celgenuserevent.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/app.h"
@@ -62,7 +62,6 @@ static int celgenuserevent_exec(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
 	char *parse;
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(event);
 		AST_APP_ARG(extra);
@@ -75,13 +74,7 @@ static int celgenuserevent_exec(struct ast_channel *chan, const char *data)
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	blob = ast_json_pack("{s: s, s: {s: s}}",
-		"event", args.event,
-		"extra", "extra", S_OR(args.extra, ""));
-	if (!blob) {
-		return res;
-	}
-	ast_cel_publish_event(chan, AST_CEL_USER_DEFINED, blob);
+	ast_cel_report_event(chan, AST_CEL_USER_DEFINED, args.event, args.extra, NULL);
 	return res;
 }
 
@@ -102,7 +95,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generate an User-Defined CEL event",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 				.load = load_module,
 				.unload = unload_module,
 	);
diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c
index 2a4aefd..8eef4ca 100644
--- a/apps/app_chanisavail.c
+++ b/apps/app_chanisavail.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/ioctl.h>
 
@@ -171,7 +171,7 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
 			}
 			snprintf(tmp, sizeof(tmp), "%d", status);
 			ast_str_append(&tmp_availstat, 0, "%s%s", ast_str_strlen(tmp_availstat) ? "&" : "", tmp);
-			if ((inuse <= 1) && (tempchan = ast_request(tech, ast_channel_nativeformats(chan), NULL, chan, number, &status))) {
+			if ((inuse <= 1) && (tempchan = ast_request(tech, ast_channel_nativeformats(chan), chan, number, &status))) {
 					ast_str_append(&tmp_availchan, 0, "%s%s", ast_str_strlen(tmp_availchan) ? "&" : "", ast_channel_name(tempchan));
 					
 					snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
@@ -211,5 +211,4 @@ static int load_module(void)
 		AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Check channel availability");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Check channel availability");
diff --git a/apps/app_channelredirect.c b/apps/app_channelredirect.c
index 0ebae5b..8c98ed7 100644
--- a/apps/app_channelredirect.c
+++ b/apps/app_channelredirect.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389378 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -96,6 +96,10 @@ static int asyncgoto_exec(struct ast_channel *chan, const char *data)
 		return 0;
 	}
 
+	if (ast_channel_pbx(chan2)) {
+		ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+	}
+
 	res = ast_async_parseable_goto(chan2, args.label);
 
 	chan2 = ast_channel_unref(chan2);
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 972cc7b..31a1e18 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <errno.h>
@@ -55,9 +55,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 #include "asterisk/lock.h"
 #include "asterisk/options.h"
 #include "asterisk/autochan.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/json.h"
-#include "asterisk/format_cache.h"
 
 #define AST_NAME_STRLEN 256
 #define NUM_SPYGROUPS 128
@@ -146,10 +143,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 					<option name="S">
 						<para>Stop when no more channels are left to spy on.</para>
 					</option>
-					<option name="u">
-						<para>The <literal>chanprefix</literal> parameter is a channel uniqueid
-						or fully specified channel name.</para>
-					</option>
 					<option name="v">
 						<argument name="value" />
 						<para>Adjust the initial volume in the range from <literal>-4</literal> 
@@ -188,17 +181,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 			<para> - Dialing <literal>#</literal> cycles the volume level.</para>
 			<para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
 			<para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
-			to <literal>chanprefix</literal>. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
-			while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden
-			if the 'd' or 'u' options are used.</para>
+			to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing the digits '1234#' 
+			while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden if the 'd' option
+			is used</para>
 			<note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
 			single digit extension exists in the correct context ChanSpy will exit to it.
 			This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
 		</description>
 		<see-also>
 			<ref type="application">ExtenSpy</ref>
-			<ref type="managerEvent">ChanSpyStart</ref>
-			<ref type="managerEvent">ChanSpyStop</ref>
 		</see-also>
 	</application>
 	<application name="ExtenSpy" language="en_US">
@@ -335,10 +326,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 		</description>
 		<see-also>
 			<ref type="application">ChanSpy</ref>
-			<ref type="managerEvent">ChanSpyStart</ref>
-			<ref type="managerEvent">ChanSpyStop</ref>
 		</see-also>
 	</application>
+	
 	<application name="DAHDIScan" language="en_US">
 		<synopsis>
 			Scan DAHDI channels to monitor calls.
@@ -352,10 +342,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 			<para>Allows a call center manager to monitor DAHDI channels in a
 			convenient way.  Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
 		</description>
-		<see-also>
-			<ref type="managerEvent">ChanSpyStart</ref>
-			<ref type="managerEvent">ChanSpyStop</ref>
-		</see-also>
 	</application>
  ***/
 
@@ -385,7 +371,6 @@ enum {
 	OPTION_DAHDI_SCAN        = (1 << 16),	/* Scan groups in DAHDIScan mode */
 	OPTION_STOP              = (1 << 17),
 	OPTION_EXITONHANGUP      = (1 << 18),   /* Hang up when the spied-on channel hangs up. */
-	OPTION_UNIQUEID          = (1 << 19),	/* The chanprefix is a channel uniqueid or fully specified channel name. */
 };
 
 enum {
@@ -413,7 +398,6 @@ AST_APP_OPTIONS(spy_opts, {
 	AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
 	AST_APP_OPTION('s', OPTION_NOTECH),
 	AST_APP_OPTION('S', OPTION_STOP),
-	AST_APP_OPTION('u', OPTION_UNIQUEID),
 	AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
 	AST_APP_OPTION('w', OPTION_WHISPER),
 	AST_APP_OPTION('W', OPTION_PRIVATE),
@@ -452,6 +436,9 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
 {
 	struct chanspy_translation_helper *csth = data;
 	struct ast_frame *f, *cur;
+	struct ast_format format_slin;
+
+	ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0);
 
 	ast_audiohook_lock(&csth->spy_audiohook);
 	if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
@@ -462,9 +449,9 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
 
 	if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
 		/* Option 'o' was set, so don't mix channel audio */
-		f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, ast_format_slin);
+		f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
 	} else {
-		f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_slin);
+		f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin);
 	}
 
 	ast_audiohook_unlock(&csth->spy_audiohook);
@@ -498,10 +485,18 @@ static struct ast_generator spygen = {
 
 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
 {
+	int res = 0;
+	struct ast_channel *peer = NULL;
+
 	ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
 
 	ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
-	return ast_audiohook_attach(autochan->chan, audiohook);
+	res = ast_audiohook_attach(autochan->chan, audiohook);
+
+	if (!res && ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
+		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+	}
+	return res;
 }
 
 static void change_spy_mode(const char digit, struct ast_flags *flags)
@@ -518,74 +513,13 @@ static void change_spy_mode(const char digit, struct ast_flags *flags)
 	}
 }
 
-static int pack_channel_into_message(struct ast_channel *chan, const char *role,
-									 struct ast_multi_channel_blob *payload)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot,
-			ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
-			ao2_cleanup);
-
-	if (!snapshot) {
-		return -1;
-	}
-	ast_multi_channel_blob_add_channel(payload, role, snapshot);
-	return 0;
-}
-
-/*! \internal
- * \brief Publish the chanspy message over Stasis-Core
- * \param spyer The channel doing the spying
- * \param spyee Who is being spied upon
- * \start start If non-zero, the spying is starting. Otherwise, the spyer is
- * finishing
- */
-static void publish_chanspy_message(struct ast_channel *spyer,
-									struct ast_channel *spyee,
-									int start)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct stasis_message_type *type = start ? ast_channel_chanspy_start_type(): ast_channel_chanspy_stop_type();
-
-	if (!spyer) {
-		ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
-		return;
-	}
-	blob = ast_json_null();
-	if (!blob || !type) {
-		return;
-	}
-
-	payload = ast_multi_channel_blob_create(blob);
-	if (!payload) {
-		return;
-	}
-
-	if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
-		return;
-	}
-
-	if (spyee) {
-		if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
-			return;
-		}
-	}
-
-	message = stasis_message_create(type, payload);
-	if (!message) {
-		return;
-	}
-	stasis_publish(ast_channel_topic(spyer), message);
-}
-
 static int attach_barge(struct ast_autochan *spyee_autochan,
 	struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
 	const char *spyer_name, const char *name)
 {
 	int retval = 0;
 	struct ast_autochan *internal_bridge_autochan;
-	RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup);
+	struct ast_channel *bridged = ast_bridged_channel(spyee_autochan->chan);
 
 	if (!bridged) {
 		return -1;
@@ -622,22 +556,38 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
 	struct ast_silence_generator *silgen = NULL;
 	struct ast_autochan *spyee_bridge_autochan = NULL;
 	const char *spyer_name;
+	struct ast_channel *chans[] = { chan, spyee_autochan->chan };
+
+	ast_channel_lock(chan);
+	spyer_name = ast_strdupa(ast_channel_name(chan));
+	ast_channel_unlock(chan);
+
+	/* We now hold the channel lock on spyee */
 
 	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
 			ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
 		return 0;
 	}
 
-	ast_channel_lock(chan);
-	spyer_name = ast_strdupa(ast_channel_name(chan));
-	ast_channel_unlock(chan);
-
 	ast_channel_lock(spyee_autochan->chan);
 	name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
 	ast_channel_unlock(spyee_autochan->chan);
 
 	ast_verb(2, "Spying on channel %s\n", name);
-	publish_chanspy_message(chan, spyee_autochan->chan, 1);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel has started spying on another channel.</synopsis>
+			<see-also>
+				<ref type="application">ChanSpy</ref>
+				<ref type="application">ExtenSpy</ref>
+				<ref type="managerEvent">ChanSpyStop</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
+			"SpyerChannel: %s\r\n"
+			"SpyeeChannel: %s\r\n",
+			spyer_name, name);
 
 	memset(&csth, 0, sizeof(csth));
 	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
@@ -698,6 +648,9 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
 	while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
 		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
 			running = -1;
+			if (f) {
+				ast_frfree(f);
+			}
 			break;
 		}
 
@@ -820,7 +773,15 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
 	}
 
 	ast_verb(2, "Done Spying on channel %s\n", name);
-	publish_chanspy_message(chan, NULL, 0);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel has stopped spying on another channel.</synopsis>
+			<see-also>
+				<ref type="managerEvent">ChanSpyStart</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
 
 	return running;
 }
@@ -850,15 +811,6 @@ static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
 	return NULL;
 }
 
-static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
-{
-	char *mailbox_id;
-
-	mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
-	sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
-	return ast_app_sayname(chan, mailbox_id);
-}
-
 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 	int volfactor, const int fd, struct spy_dtmf_options *user_options,
 	const char *mygroup, const char *myenforced, const char *spec, const char *exten,
@@ -917,19 +869,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 
 		/* Set up the iterator we'll be using during this call */
 		if (!ast_strlen_zero(spec)) {
-			if (ast_test_flag(flags, OPTION_UNIQUEID)) {
-				struct ast_channel *unique_chan;
-
-				unique_chan = ast_channel_get_by_name(spec);
-				if (!unique_chan) {
-					res = -1;
-					goto exit;
-				}
-				iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
-				ast_channel_unref(unique_chan);
-			} else {
-				iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
-			}
+			iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
 		} else if (!ast_strlen_zero(exten)) {
 			iter = ast_channel_iterator_by_exten_new(exten, context);
 		} else {
@@ -981,7 +921,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 				break;
 			}
 
-			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_channel_is_bridged(autochan->chan)) {
+			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
 				continue;
 			}
 
@@ -1073,9 +1013,8 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 				if (ast_test_flag(flags, OPTION_NAME)) {
 					const char *local_context = S_OR(name_context, "default");
 					const char *local_mailbox = S_OR(mailbox, ptr);
-
 					if (local_mailbox) {
-						res = spy_sayname(chan, local_mailbox, local_context);
+						res = ast_app_sayname(chan, local_mailbox, local_context);
 					} else {
 						res = -1;
 					}
@@ -1093,7 +1032,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 								break;
 							}
 						} else {
-							res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
+							res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan));
 						}
 					}
 					if (ptr && (num = atoi(ptr))) {
@@ -1114,7 +1053,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 				ast_autochan_destroy(autochan);
 				iter = ast_channel_iterator_destroy(iter);
 				goto exit;
-			} else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
+			} else if (res > 1 && spec) {
 				struct ast_channel *next;
 
 				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
@@ -1167,7 +1106,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
 		.volume = '#',
 		.exit = '\0',
 	};
-	RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
+	struct ast_format oldwf;
 	int volfactor = 0;
 	int res;
 	char *mailbox = NULL;
@@ -1180,6 +1119,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
 	char *parse = ast_strdupa(data);
 
 	AST_STANDARD_APP_ARGS(args, parse);
+	ast_format_clear(&oldwf);
 
 	if (args.spec && !strcmp(args.spec, "all"))
 		args.spec = NULL;
@@ -1243,8 +1183,8 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
 		ast_clear_flag(&flags, AST_FLAGS_ALL);
 	}
 
-	oldwf = ao2_bump(ast_channel_writeformat(chan));
-	if (ast_set_write_format(chan, ast_format_slin) < 0) {
+	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
 		return -1;
 	}
@@ -1264,7 +1204,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
 	if (fd)
 		close(fd);
 
-	if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
 
 	if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
@@ -1286,7 +1226,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
 		.volume = '#',
 		.exit = '\0',
 	};
-	RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
+	struct ast_format oldwf;
 	int volfactor = 0;
 	int res;
 	char *mailbox = NULL;
@@ -1298,6 +1238,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
 	char *parse = ast_strdupa(data);
 
 	AST_STANDARD_APP_ARGS(args, parse);
+	ast_format_clear(&oldwf);
 
 	if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
 		exten = args.context;
@@ -1367,8 +1308,8 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
 		ast_clear_flag(&flags, AST_FLAGS_ALL);
 	}
 
-	oldwf = ao2_bump(ast_channel_writeformat(chan));
-	if (ast_set_write_format(chan, ast_format_slin) < 0) {
+	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
 		return -1;
 	}
@@ -1389,7 +1330,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
 	if (fd)
 		close(fd);
 
-	if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
 
 	return res;
@@ -1404,13 +1345,13 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data)
 		.volume = '\0',
 		.exit = '*',
 	};
-	struct ast_format *oldwf;
+	struct ast_format oldwf;
 	int res;
 	char *mygroup = NULL;
 
 	/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
 	ast_clear_flag(&flags, AST_FLAGS_ALL);
-
+	ast_format_clear(&oldwf);
 	if (!ast_strlen_zero(data)) {
 		mygroup = ast_strdupa(data);
 	}
@@ -1418,18 +1359,16 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data)
 	ast_set_flag(&flags, OPTION_DTMF_CYCLE);
 	ast_set_flag(&flags, OPTION_DAHDI_SCAN);
 
-	oldwf = ao2_bump(ast_channel_writeformat(chan));
-	if (ast_set_write_format(chan, ast_format_slin) < 0) {
+	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
-		ao2_cleanup(oldwf);
 		return -1;
 	}
 
 	res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
 
-	if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
 		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
-	ao2_cleanup(oldwf);
 
 	return res;
 }
diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index c13a830..cd4c814 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -28,22 +28,13 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_confbridge.c uses the configuration file \ref confbridge.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page confbridge.conf confbridge.conf
- * \verbinclude confbridge.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -58,7 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
-#include "asterisk/bridge.h"
+#include "asterisk/bridging.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"
 #include "asterisk/audiohook.h"
@@ -67,10 +58,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 #include "asterisk/paths.h"
 #include "asterisk/manager.h"
 #include "asterisk/test.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/json.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="ConfBridge" language="en_US">
@@ -101,25 +88,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 			</parameter>
 			<parameter name="menu">
 				<para>The name of the DTMF menu in confbridge.conf to be applied to
-				this channel.  When left blank, a dynamically built menu profile
-				created by the CONFBRIDGE dialplan function is searched for on
-				the channel and used. If no dynamic profile is present, the
-				'default_menu' profile found in confbridge.conf is used.</para>
+				this channel.  No menu is applied by default if this option is left
+				blank.</para>
 			</parameter>
 		</syntax>
 		<description>
 			<para>Enters the user into a specified conference bridge.  The user can
 			exit the conference by hangup or DTMF menu option.</para>
-			<para>This application sets the following channel variable upon completion:</para>
-			<variablelist>
-				<variable name="CONFBRIDGE_RESULT">
-					<value name="FAILED">The channel encountered an error and could not enter the conference.</value>
-					<value name="HANGUP">The channel exited the conference by hanging up.</value>
-					<value name="KICKED">The channel was kicked from the conference.</value>
-					<value name="ENDMARKED">The channel left the conference as a result of the last marked user leaving.</value>
-					<value name="DTMF">The channel pressed a DTMF sequence to exit the conference.</value>
-				</variable>
-			</variablelist>
 		</description>
 		<see-also>
 			<ref type="application">ConfBridge</ref>
@@ -129,27 +104,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 	</application>
 	<function name="CONFBRIDGE" language="en_US">
 		<synopsis>
-			Set a custom dynamic bridge, user, or menu profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
+			Set a custom dynamic bridge and user profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
 		</synopsis>
 		<syntax>
 			<parameter name="type" required="true">
-				<para>Type refers to which type of profile the option belongs too.  Type can be <literal>bridge</literal>, <literal>user</literal>, or
-				<literal>menu</literal>.</para>
+				<para>Type refers to which type of profile the option belongs too.  Type can be <literal>bridge</literal> or <literal>user</literal>.</para>
 			</parameter>
 			<parameter name="option" required="true">
-				<para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel, or
-				<literal>clear</literal> to remove already applied options from the channel.</para>
+				<para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel.</para>
 			</parameter>
 		</syntax>
 		<description>
 			<para>---- Example 1 ----</para>
-			<para>In this example the custom set user profile on this channel will automatically be used by the ConfBridge app.</para>
+			<para>In this example the custom set user profile on this channel will automatically be used by the ConfBridge app.</para> 
 			<para>exten => 1,1,Answer() </para>
 			<para>exten => 1,n,Set(CONFBRIDGE(user,announce_join_leave)=yes)</para>
 			<para>exten => 1,n,Set(CONFBRIDGE(user,startmuted)=yes)</para>
 			<para>exten => 1,n,ConfBridge(1) </para>
 			<para>---- Example 2 ----</para>
-			<para>This example shows how to use a predefined user or bridge profile in confbridge.conf as a template for a dynamic profile. Here we make a admin/marked user out of the default_user profile that is already defined in confbridge.conf.</para>
+			<para>This example shows how to use a predefined user or bridge profile in confbridge.conf as a template for a dynamic profile. Here we make a admin/marked user out of the default_user profile that is already defined in confbridge.conf.</para> 
 			<para>exten => 1,1,Answer() </para>
 			<para>exten => 1,n,Set(CONFBRIDGE(user,template)=default_user)</para>
 			<para>exten => 1,n,Set(CONFBRIDGE(user,admin)=yes)</para>
@@ -170,7 +143,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 			</parameter>
 		</syntax>
 		<description>
-			<para>This function returns a non-negative integer for valid conference identifiers (0 or 1 for <literal>locked</literal>) and "" for invalid conference identifiers.</para>
+			<para>This function returns a non-negative integer for valid conference identifiers (0 or 1 for <literal>locked</literal>) and "" for invalid conference identifiers.</para> 
 		</description>
 	</function>
 	<manager name="ConfbridgeList" language="en_US">
@@ -211,8 +184,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 			<parameter name="Conference" required="true" />
 			<parameter name="Channel" required="true">
 				<para>If this parameter is not a complete channel name, the first channel with this prefix will be used.</para>
-				<para>If this parameter is "all", all channels will be muted.</para>
-				<para>If this parameter is "participants", all non-admin channels will be muted.</para>
 			</parameter>
 		</syntax>
 		<description>
@@ -227,8 +198,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 			<parameter name="Conference" required="true" />
 			<parameter name="Channel" required="true">
 				<para>If this parameter is not a complete channel name, the first channel with this prefix will be used.</para>
-				<para>If this parameter is "all", all channels will be unmuted.</para>
-				<para>If this parameter is "participants", all non-admin channels will be unmuted.</para>
 			</parameter>
 		</syntax>
 		<description>
@@ -241,10 +210,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 		<syntax>
 			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
 			<parameter name="Conference" required="true" />
-			<parameter name="Channel" required="true" >
-				<para>If this parameter is "all", all channels will be kicked from the conference.</para>
-				<para>If this parameter is "participants", all non-admin channels will be kicked from the conference.</para>
-			</parameter>
+			<parameter name="Channel" required="true" />
 		</syntax>
 		<description>
 		</description>
@@ -324,22 +290,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428339 $")
 
 static const char app[] = "ConfBridge";
 
-/* Number of buckets our conference bridges container can have */
+/*! Number of buckets our conference bridges container can have */
 #define CONFERENCE_BRIDGE_BUCKETS 53
 
-enum {
-	CONF_RECORD_EXIT = 0,
-	CONF_RECORD_START,
-	CONF_RECORD_STOP,
-};
+/*! Initial recording filename space. */
+#define RECORD_FILENAME_INITIAL_SPACE	128
 
 /*! \brief Container to hold all conference bridges in progress */
-struct ao2_container *conference_bridges;
+static struct ao2_container *conference_bridges;
 
-static void leave_conference(struct confbridge_user *user);
-static int play_sound_number(struct confbridge_conference *conference, int say_number);
-static int execute_menu_entry(struct confbridge_conference *conference,
-	struct confbridge_user *user,
+static void leave_conference(struct conference_bridge_user *user);
+static int play_sound_number(struct conference_bridge *conference_bridge, int say_number);
+static int execute_menu_entry(struct conference_bridge *conference_bridge,
+	struct conference_bridge_user *conference_bridge_user,
 	struct ast_bridge_channel *bridge_channel,
 	struct conf_menu_entry *menu_entry,
 	struct conf_menu *menu);
@@ -347,48 +310,15 @@ static int execute_menu_entry(struct confbridge_conference *conference,
 /*! \brief Hashing function used for conference bridges container */
 static int conference_bridge_hash_cb(const void *obj, const int flags)
 {
-	const struct confbridge_conference *conference = obj;
-	const char *name = obj;
-	int hash;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		name = conference->name;
-		/* Fall through */
-	case OBJ_KEY:
-		hash = ast_str_case_hash(name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/* Should never happen in hash callback. */
-		ast_assert(0);
-		hash = 0;
-		break;
-	}
-	return hash;
+	const struct conference_bridge *conference_bridge = obj;
+	return ast_str_case_hash(conference_bridge->name);
 }
 
 /*! \brief Comparison function used for conference bridges container */
 static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
 {
-	const struct confbridge_conference *left = obj;
-	const struct confbridge_conference *right = arg;
-	const char *right_name = arg;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_name = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcasecmp(left->name, right_name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(left->name, right_name, strlen(right_name));
-		break;
-	}
-	return cmp ? 0 : CMP_MATCH;
+	const struct conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
+	return (!strcasecmp(conference_bridge0->name, conference_bridge1->name) ? CMP_MATCH | CMP_STOP : 0);
 }
 
 const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
@@ -445,154 +375,82 @@ const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds
 	return "";
 }
 
-static void send_conf_stasis(struct confbridge_conference *conference, struct ast_channel *chan,
-	struct stasis_message_type *type, struct ast_json *extras, int channel_topic)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
-	json_object = ast_json_pack("{s: s}",
-		"conference", conference->name);
-	if (!json_object) {
-		return;
-	}
-
-	if (extras) {
-		ast_json_object_update(json_object, extras);
-	}
-
-	ast_bridge_lock(conference->bridge);
-	msg = ast_bridge_blob_create(type,
-		conference->bridge,
-		chan,
-		json_object);
-	ast_bridge_unlock(conference->bridge);
-	if (!msg) {
-		return;
-	}
-
-	if (channel_topic) {
-		stasis_publish(ast_channel_topic(chan), msg);
-	} else {
-		stasis_publish(ast_bridge_topic(conference->bridge), msg);
-	}
-}
-
-static void send_conf_start_event(struct confbridge_conference *conference)
-{
-	send_conf_stasis(conference, NULL, confbridge_start_type(), NULL, 0);
-}
-
-static void send_conf_end_event(struct confbridge_conference *conference)
+static struct ast_frame *rec_read(struct ast_channel *ast)
 {
-	send_conf_stasis(conference, NULL, confbridge_end_type(), NULL, 0);
+	return &ast_null_frame;
 }
-
-static void send_join_event(struct confbridge_user *user, struct confbridge_conference *conference)
+static int rec_write(struct ast_channel *ast, struct ast_frame *f)
 {
-	struct ast_json *json_object;
-
-	json_object = ast_json_pack("{s: b}",
-		"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
-	);
-	if (!json_object) {
-		return;
-	}
-	send_conf_stasis(conference, user->chan, confbridge_join_type(), json_object, 0);
-	ast_json_unref(json_object);
-}
-
-static void send_leave_event(struct confbridge_user *user, struct confbridge_conference *conference)
-{
-	struct ast_json *json_object;
-
-	json_object = ast_json_pack("{s: b}",
-		"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
-	);
-	if (!json_object) {
-		return;
-	}
-	send_conf_stasis(conference, user->chan, confbridge_leave_type(), json_object, 0);
-	ast_json_unref(json_object);
-}
-
-static void send_start_record_event(struct confbridge_conference *conference)
-{
-	send_conf_stasis(conference, NULL, confbridge_start_record_type(), NULL, 0);
-}
-
-static void send_stop_record_event(struct confbridge_conference *conference)
-{
-	send_conf_stasis(conference, NULL, confbridge_stop_record_type(), NULL, 0);
-}
-
-static void send_mute_event(struct confbridge_user *user, struct confbridge_conference *conference)
-{
-	struct ast_json *json_object;
-
-	json_object = ast_json_pack("{s: b}",
-		"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
-	);
-	if (!json_object) {
-		return;
-	}
-	send_conf_stasis(conference, user->chan, confbridge_mute_type(), json_object, 1);
-	ast_json_unref(json_object);
+	return 0;
 }
-
-static void send_unmute_event(struct confbridge_user *user, struct confbridge_conference *conference)
-{
-	struct ast_json *json_object;
-
-	json_object = ast_json_pack("{s: b}",
-		"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
-	);
-	if (!json_object) {
-		return;
+static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel_tech record_tech = {
+	.type = "ConfBridgeRec",
+	.description = "Conference Bridge Recording Channel",
+	.requester = rec_request,
+	.read = rec_read,
+	.write = rec_write,
+};
+static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct ast_channel *tmp;
+	struct ast_format fmt;
+	const char *conf_name = data;
+	if (!(tmp = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", NULL, 0,
+		"ConfBridgeRecorder/conf-%s-uid-%d",
+		conf_name,
+		(int) ast_random()))) {
+		return NULL;
 	}
-	send_conf_stasis(conference, user->chan, confbridge_unmute_type(), json_object, 1);
-	ast_json_unref(json_object);
+	ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0);
+	ast_channel_tech_set(tmp, &record_tech);
+	ast_format_cap_add_all(ast_channel_nativeformats(tmp));
+	ast_format_copy(ast_channel_writeformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
+	ast_format_copy(ast_channel_readformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
+	return tmp;
 }
 
-static void set_rec_filename(struct confbridge_conference *conference, struct ast_str **filename, int is_new)
+static void set_rec_filename(struct conference_bridge *bridge, struct ast_str **filename, int is_new)
 {
-	char *rec_file = conference->b_profile.rec_file;
-	time_t now;
+	char *rec_file = bridge->b_profile.rec_file;
 	char *ext;
+	time_t now;
 
-	if (ast_str_strlen(*filename) && ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND) && !is_new) {
-		    return;
+	if (ast_str_strlen(*filename)
+		&& !is_new) {
+		return;
 	}
 
 	time(&now);
 
 	ast_str_reset(*filename);
 	if (ast_strlen_zero(rec_file)) {
-		ast_str_set(filename, 0, "confbridge-%s-%u.wav", conference->name, (unsigned int)now);
+		ast_str_set(filename, 0, "confbridge-%s-%u.wav", bridge->name,
+			(unsigned int) now);
 	} else {
 		/* insert time before file extension */
 		ext = strrchr(rec_file, '.');
 		if (ext) {
 			ast_str_set_substr(filename, 0, rec_file, ext - rec_file);
-			ast_str_append(filename, 0, "-%u%s", (unsigned int)now, ext);
+			ast_str_append(filename, 0, "-%u%s", (unsigned int) now, ext);
 		} else {
-			ast_str_set(filename, 0, "%s-%u", rec_file, (unsigned int)now);
+			ast_str_set(filename, 0, "%s-%u", rec_file, (unsigned int) now);
 		}
 	}
-
-	if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND)) {
-		ast_str_append(filename, 0, ",a");
-	}
+	ast_str_append(filename, 0, ",a");
 }
 
 static int is_new_rec_file(const char *rec_file, struct ast_str **orig_rec_file)
 {
 	if (!ast_strlen_zero(rec_file)) {
 		if (!*orig_rec_file) {
-			*orig_rec_file = ast_str_create(PATH_MAX);
+			*orig_rec_file = ast_str_create(RECORD_FILENAME_INITIAL_SPACE);
 		}
 
-		if (strcmp(ast_str_buffer(*orig_rec_file), rec_file)) {
+		if (*orig_rec_file
+			&& strcmp(ast_str_buffer(*orig_rec_file), rec_file)) {
 			ast_str_set(orig_rec_file, 0, "%s", rec_file);
 			return 1;
 		}
@@ -600,181 +458,236 @@ static int is_new_rec_file(const char *rec_file, struct ast_str **orig_rec_file)
 	return 0;
 }
 
-static void *record_thread(void *obj)
-{
-	struct confbridge_conference *conference = obj;
-	struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
-	struct ast_channel *chan;
-	struct ast_str *filename = ast_str_alloca(PATH_MAX);
-	struct ast_str *orig_rec_file = NULL;
-	struct ast_bridge_features features;
-
-	ast_mutex_lock(&conference->record_lock);
-	if (!mixmonapp) {
-		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
-		conference->record_thread = AST_PTHREADT_NULL;
-		ast_mutex_unlock(&conference->record_lock);
-		ao2_ref(conference, -1);
-		return NULL;
-	}
-	if (ast_bridge_features_init(&features)) {
-		ast_bridge_features_cleanup(&features);
-		conference->record_thread = AST_PTHREADT_NULL;
-		ast_mutex_unlock(&conference->record_lock);
-		ao2_ref(conference, -1);
-		return NULL;
-	}
-	ast_set_flag(&features.feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
-
-	/* XXX If we get an EXIT right here, START will essentially be a no-op */
-	while (conference->record_state != CONF_RECORD_EXIT) {
-		set_rec_filename(conference, &filename,
-			is_new_rec_file(conference->b_profile.rec_file, &orig_rec_file));
-		chan = ast_channel_ref(conference->record_chan);
-		ast_answer(chan);
-		pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
-		ast_bridge_join(conference->bridge, chan, NULL, &features, NULL, 0);
-
-		ast_hangup(chan); /* This will eat this thread's reference to the channel as well */
-		/* STOP has been called. Wait for either a START or an EXIT */
-		ast_cond_wait(&conference->record_cond, &conference->record_lock);
-	}
-	ast_bridge_features_cleanup(&features);
-	ast_free(orig_rec_file);
-	ast_mutex_unlock(&conference->record_lock);
-	ao2_ref(conference, -1);
-	return NULL;
-}
-
-/*! \brief Returns whether or not conference is being recorded.
- * \param conference The bridge to check for recording
+/*!
+ * \internal
+ * \brief Returns whether or not conference is being recorded.
+ *
+ * \param conference_bridge The bridge to check for recording
+ *
+ * \note Must be called with conference_bridge locked
+ *
  * \retval 1, conference is recording.
  * \retval 0, conference is NOT recording.
  */
-static int conf_is_recording(struct confbridge_conference *conference)
+static int conf_is_recording(struct conference_bridge *conference_bridge)
 {
-	return conference->record_state == CONF_RECORD_START;
+	return conference_bridge->record_chan != NULL;
 }
 
-/*! \brief Stop recording a conference bridge
+/*!
  * \internal
- * \param conference The conference bridge on which to stop the recording
+ * \brief Stop recording a conference bridge
+ *
+ * \param conference_bridge The conference bridge on which to stop the recording
+ *
+ * \note Must be called with conference_bridge locked
+ *
  * \retval -1 Failure
  * \retval 0 Success
  */
-static int conf_stop_record(struct confbridge_conference *conference)
+static int conf_stop_record(struct conference_bridge *conference_bridge)
 {
 	struct ast_channel *chan;
-	if (conference->record_thread == AST_PTHREADT_NULL || !conf_is_recording(conference)) {
-		return -1;
-	}
-	conference->record_state = CONF_RECORD_STOP;
-	chan = ast_channel_ref(conference->record_chan);
-	ast_bridge_remove(conference->bridge, chan);
-	ast_queue_frame(chan, &ast_null_frame);
-	chan = ast_channel_unref(chan);
-	ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference->b_profile.name);
-	send_stop_record_event(conference);
+	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
 
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Stops the confbridge recording thread.
- *
- * \note Must be called with the conference locked
- */
-static int conf_stop_record_thread(struct confbridge_conference *conference)
-{
-	if (conference->record_thread == AST_PTHREADT_NULL) {
+	if (!conf_is_recording(conference_bridge)) {
 		return -1;
 	}
-	conf_stop_record(conference);
 
-	ast_mutex_lock(&conference->record_lock);
-	conference->record_state = CONF_RECORD_EXIT;
-	ast_cond_signal(&conference->record_cond);
-	ast_mutex_unlock(&conference->record_lock);
+	/* Remove the recording channel from the conference bridge. */
+	chan = conference_bridge->record_chan;
+	conference_bridge->record_chan = NULL;
+	ast_queue_frame(chan, &f);
+	ast_channel_unref(chan);
 
-	pthread_join(conference->record_thread, NULL);
-	conference->record_thread = AST_PTHREADT_NULL;
-
-	/* this is the reference given to the channel during the channel alloc */
-	if (conference->record_chan) {
-		conference->record_chan = ast_channel_unref(conference->record_chan);
-	}
+	ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
 
 	return 0;
 }
 
-/*! \brief Start recording the conference
+/*!
  * \internal
- * \note The conference must be locked when calling this function
- * \param conference The conference bridge to start recording
+ * \brief Start recording the conference
+ *
+ * \param conference_bridge The conference bridge to start recording
+ *
+ * \note Must be called with conference_bridge locked
+ *
  * \retval 0 success
- * \rteval non-zero failure
+ * \retval non-zero failure
  */
-static int conf_start_record(struct confbridge_conference *conference)
+static int conf_start_record(struct conference_bridge *conference_bridge)
 {
+	struct ast_app *mixmonapp;
+	struct ast_channel *chan;
 	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
+	int cause;
 
-	if (conference->record_state != CONF_RECORD_STOP) {
+	if (conf_is_recording(conference_bridge)) {
 		return -1;
 	}
 
-	if (!pbx_findapp("MixMonitor")) {
-		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
+	mixmonapp = pbx_findapp("MixMonitor");
+	if (!mixmonapp) {
+		ast_log(LOG_WARNING, "Cannot record ConfBridge, MixMonitor app is not installed\n");
 		return -1;
 	}
 
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	cap = ast_format_cap_alloc_nolock();
 	if (!cap) {
 		return -1;
 	}
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+
+	/* Create the recording channel. */
+	chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause);
+	ast_format_cap_destroy(cap);
+	if (!chan) {
+		return -1;
+	}
 
-	ast_format_cap_append(cap, ast_format_slin, 0);
+	/* Start recording. */
+	set_rec_filename(conference_bridge, &conference_bridge->record_filename,
+		is_new_rec_file(conference_bridge->b_profile.rec_file, &conference_bridge->orig_rec_file));
+	ast_answer(chan);
+	pbx_exec(chan, mixmonapp, ast_str_buffer(conference_bridge->record_filename));
 
-	conference->record_chan = ast_request("CBRec", cap, NULL, NULL,
-		conference->name, NULL);
-	ao2_ref(cap, -1);
-	if (!conference->record_chan) {
+	/* Put the channel into the conference bridge. */
+	ast_channel_ref(chan);
+	conference_bridge->record_chan = chan;
+	if (ast_bridge_impart(conference_bridge->bridge, chan, NULL, NULL, 1)) {
+		ast_hangup(chan);
+		ast_channel_unref(chan);
+		conference_bridge->record_chan = NULL;
 		return -1;
 	}
 
-	conference->record_state = CONF_RECORD_START;
-	ast_mutex_lock(&conference->record_lock);
-	ast_cond_signal(&conference->record_cond);
-	ast_mutex_unlock(&conference->record_lock);
-	ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference->b_profile.name);
-	send_start_record_event(conference);
+	ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
 
 	return 0;
 }
 
-/*! \brief Start the recording thread on a conference bridge
- * \internal
- * \param conference The conference bridge on which to start the recording thread
- * \retval 0 success
- * \retval -1 failure
+static void send_conf_start_event(const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a conference starts.</synopsis>
+			<syntax>
+				<parameter name="Conference">
+					<para>The name of the Confbridge conference.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeEnd</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "ConfbridgeStart", "Conference: %s\r\n", conf_name);
+}
+
+static void send_conf_end_event(const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a conference ends.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeStart</ref>
+				<ref type="application">ConfBridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "ConfbridgeEnd", "Conference: %s\r\n", conf_name);
+}
+
+static void send_join_event(struct ast_channel *chan, const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel joins a Confbridge conference.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeLeave</ref>
+				<ref type="application">ConfBridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeJoin",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Conference: %s\r\n"
+		"CallerIDnum: %s\r\n"
+		"CallerIDname: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		conf_name,
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
+	);
+}
+
+static void send_leave_event(struct ast_channel *chan, const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeJoin</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeLeave",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Conference: %s\r\n"
+		"CallerIDnum: %s\r\n"
+		"CallerIDname: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		conf_name,
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
+	);
+}
+
+/* \brief Playback the given filename and monitor for any dtmf interrupts.
+ *
+ * Use this function to playback sound files to the given channel that can be
+ * interrupted by dtmf. Note, too this function can be used to playback a sound
+ * file without allowing interruptions.
+ *
+ * \retval -1 failure during playback, 0 on file was fully played, 1 on dtmf interrupt.
  */
-static int start_conf_record_thread(struct confbridge_conference *conference)
+static int play_file(struct ast_channel *channel, const char *filename, int allow_dtmf_interrupt)
 {
-	conf_start_record(conference);
+	const char *stop_digits = allow_dtmf_interrupt ? AST_DIGIT_ANY : AST_DIGIT_NONE;
+	int digit;
 
-	/*
-	 * if the thread has already been started, don't start another
-	 */
-	if (conference->record_thread != AST_PTHREADT_NULL) {
-		return 0;
+	digit = ast_stream_and_wait(channel, filename, stop_digits);
+	if (digit < 0) {
+		ast_log(LOG_WARNING, "Failed to playback file '%s' to channel\n", filename);
+		return -1;
 	}
 
-	ao2_ref(conference, +1); /* give the record thread a ref */
+	if (digit > 0) {
+		/* file playback was interrupted by a key press, re-queue it */
+		struct ast_frame frame;
 
-	if (ast_pthread_create_background(&conference->record_thread, NULL, record_thread, conference)) {
-		ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference->name);
-		ao2_ref(conference, -1); /* error so remove ref */
-		return -1;
+		memset(&frame, 0, sizeof(frame));
+		frame.frametype = AST_FRAME_DTMF_END;
+		frame.subclass.integer = digit;
+
+		ast_stopstream(channel);
+		ast_queue_frame_head(channel, &frame);
+		return 1;
 	}
 
 	return 0;
@@ -800,52 +713,50 @@ static int sound_file_exists(const char *filename)
 /*!
  * \brief Announce number of users in the conference bridge to the caller
  *
- * \param conference Conference bridge to peek at
- * \param user Optional Caller
+ * \param conference_bridge Conference bridge to peek at
+ * \param (OPTIONAL) conference_bridge_user Caller
+ * \param allow_dtmf_interrupt allow dtmf to interrupt playback
  *
  * \note if caller is NULL, the announcment will be sent to all participants in the conference.
  * \return Returns 0 on success, -1 if the user hung up
  */
-static int announce_user_count(struct confbridge_conference *conference, struct confbridge_user *user)
+static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user,
+			       int allow_dtmf_interrupt)
 {
-	const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference->b_profile.sounds);
-	const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference->b_profile.sounds);
-	const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference->b_profile.sounds);
+	const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference_bridge->b_profile.sounds);
+	const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference_bridge->b_profile.sounds);
+	const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference_bridge->b_profile.sounds);
 
-	if (conference->activeusers <= 1) {
+	if (conference_bridge->activeusers <= 1) {
 		/* Awww we are the only person in the conference bridge OR we only have waitmarked users */
 		return 0;
-	} else if (conference->activeusers == 2) {
-		if (user) {
+	} else if (conference_bridge->activeusers == 2) {
+		if (conference_bridge_user) {
 			/* Eep, there is one other person */
-			if (ast_stream_and_wait(user->chan,
-				only_one,
-				"")) {
+			if (play_file(conference_bridge_user->chan, only_one, allow_dtmf_interrupt) < 0) {
 				return -1;
 			}
 		} else {
-			play_sound_file(conference, only_one);
+			play_sound_file(conference_bridge, only_one);
 		}
 	} else {
 		/* Alas multiple others in here */
-		if (user) {
-			if (ast_stream_and_wait(user->chan,
+		if (conference_bridge_user) {
+			if (ast_stream_and_wait(conference_bridge_user->chan,
 				there_are,
 				"")) {
 				return -1;
 			}
-			if (ast_say_number(user->chan, conference->activeusers - 1, "", ast_channel_language(user->chan), NULL)) {
+			if (ast_say_number(conference_bridge_user->chan, conference_bridge->activeusers - 1, "", ast_channel_language(conference_bridge_user->chan), NULL)) {
 				return -1;
 			}
-			if (ast_stream_and_wait(user->chan,
-				other_in_party,
-				"")) {
+			if (play_file(conference_bridge_user->chan, other_in_party, allow_dtmf_interrupt) < 0) {
 				return -1;
 			}
 		} else if (sound_file_exists(there_are) && sound_file_exists(other_in_party)) {
-			play_sound_file(conference, there_are);
-			play_sound_number(conference, conference->activeusers - 1);
-			play_sound_file(conference, other_in_party);
+			play_sound_file(conference_bridge, there_are);
+			play_sound_number(conference_bridge, conference_bridge->activeusers - 1);
+			play_sound_file(conference_bridge, other_in_party);
 		}
 	}
 	return 0;
@@ -854,7 +765,7 @@ static int announce_user_count(struct confbridge_conference *conference, struct
 /*!
  * \brief Play back an audio file to a channel
  *
- * \param user User to play audio prompt to
+ * \param cbu User to play audio prompt to
  * \param filename Prompt to play
  *
  * \return Returns 0 on success, -1 if the user hung up
@@ -862,79 +773,78 @@ static int announce_user_count(struct confbridge_conference *conference, struct
  * the entire conference while the sound is played. But don't unlock the conference bridge
  * in the middle of a state transition.
  */
-static int play_prompt_to_user(struct confbridge_user *user, const char *filename)
+static int play_prompt_to_user(struct conference_bridge_user *cbu, const char *filename)
 {
-	return ast_stream_and_wait(user->chan, filename, "");
+	return ast_stream_and_wait(cbu->chan, filename, "");
 }
 
-static void handle_video_on_join(struct confbridge_conference *conference, struct ast_channel *chan, int marked)
+static void handle_video_on_join(struct conference_bridge *conference_bridge, struct ast_channel *chan, int marked)
 {
 	/* Right now, only marked users are automatically set as the single src of video.*/
 	if (!marked) {
 		return;
 	}
 
-	if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
+	if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
 		int set = 1;
-		struct confbridge_user *user = NULL;
-
-		ao2_lock(conference);
+		struct conference_bridge_user *tmp_user = NULL;
+		ao2_lock(conference_bridge);
 		/* see if anyone is already the video src */
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			if (user->chan == chan) {
+		AST_LIST_TRAVERSE(&conference_bridge->active_list, tmp_user, list) {
+			if (tmp_user->chan == chan) {
 				continue;
 			}
-			if (ast_bridge_is_video_src(conference->bridge, user->chan)) {
+			if (ast_bridge_is_video_src(conference_bridge->bridge, tmp_user->chan)) {
 				set = 0;
 				break;
 			}
 		}
-		ao2_unlock(conference);
+		ao2_unlock(conference_bridge);
 		if (set) {
-			ast_bridge_set_single_src_video_mode(conference->bridge, chan);
+			ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
 		}
-	} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
+	} else if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
 		/* we joined and are video capable, we override anyone else that may have already been the video feed */
-		ast_bridge_set_single_src_video_mode(conference->bridge, chan);
+		ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
 	}
 }
 
-static void handle_video_on_exit(struct confbridge_conference *conference, struct ast_channel *chan)
+static void handle_video_on_exit(struct conference_bridge *conference_bridge, struct ast_channel *chan)
 {
-	struct confbridge_user *user = NULL;
+	struct conference_bridge_user *tmp_user = NULL;
 
 	/* if this isn't a video source, nothing to update */
-	if (!ast_bridge_is_video_src(conference->bridge, chan)) {
+	if (!ast_bridge_is_video_src(conference_bridge->bridge, chan)) {
 		return;
 	}
 
-	ast_bridge_remove_video_src(conference->bridge, chan);
+	ast_bridge_remove_video_src(conference_bridge->bridge, chan);
 
 	/* If in follow talker mode, make sure to restore this mode on the
 	 * bridge when a source is removed.  It is possible this channel was
 	 * only set temporarily as a video source by an AMI or DTMF action. */
-	if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
-		ast_bridge_set_talker_src_video_mode(conference->bridge);
+	if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
+		ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
 	}
 
 	/* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */
-	if (!ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
-		!ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
+	if (!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
+		!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
 		return;
 	}
 
 	/* Make the next available marked user the video src.  */
-	ao2_lock(conference);
-	AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-		if (user->chan == chan) {
+	ao2_lock(conference_bridge);
+	AST_LIST_TRAVERSE(&conference_bridge->active_list, tmp_user, list) {
+		if (tmp_user->chan == chan) {
 			continue;
 		}
-		if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
-			ast_bridge_set_single_src_video_mode(conference->bridge, user->chan);
+		if (ast_test_flag(&tmp_user->u_profile, USER_OPT_MARKEDUSER)) {
+			ast_bridge_set_single_src_video_mode(conference_bridge->bridge, tmp_user->chan);
 			break;
 		}
 	}
-	ao2_unlock(conference);
+	ao2_unlock(conference_bridge);
 }
 
 /*!
@@ -946,72 +856,79 @@ static void handle_video_on_exit(struct confbridge_conference *conference, struc
  */
 static void destroy_conference_bridge(void *obj)
 {
-	struct confbridge_conference *conference = obj;
+	struct conference_bridge *conference_bridge = obj;
 
-	ast_debug(1, "Destroying conference bridge '%s'\n", conference->name);
+	ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
 
-	if (conference->playback_chan) {
-		conf_announce_channel_depart(conference->playback_chan);
-		ast_hangup(conference->playback_chan);
-		conference->playback_chan = NULL;
+	if (conference_bridge->playback_chan) {
+		struct ast_channel *underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
+		if (underlying_channel) {
+			ast_hangup(underlying_channel);
+		}
+		ast_hangup(conference_bridge->playback_chan);
+		conference_bridge->playback_chan = NULL;
 	}
 
 	/* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
-	if (conference->bridge) {
-		ast_bridge_destroy(conference->bridge, 0);
-		conference->bridge = NULL;
+	if (conference_bridge->bridge) {
+		ast_bridge_destroy(conference_bridge->bridge);
+		conference_bridge->bridge = NULL;
 	}
 
-	conf_bridge_profile_destroy(&conference->b_profile);
-	ast_cond_destroy(&conference->record_cond);
-	ast_mutex_destroy(&conference->record_lock);
-	ast_mutex_destroy(&conference->playback_lock);
+	if (conference_bridge->record_chan) {
+		ast_channel_unref(conference_bridge->record_chan);
+	}
+	ast_free(conference_bridge->orig_rec_file);
+	ast_free(conference_bridge->record_filename);
+
+	conf_bridge_profile_destroy(&conference_bridge->b_profile);
+	ast_mutex_destroy(&conference_bridge->playback_lock);
 }
 
 /*! \brief Call the proper join event handler for the user for the conference bridge's current state
  * \internal
- * \param user The conference bridge user that is joining
+ * \param cbu The conference bridge user that is joining
  * \retval 0 success
  * \retval -1 failure
  */
-static int handle_conf_user_join(struct confbridge_user *user)
+static int handle_conf_user_join(struct conference_bridge_user *cbu)
 {
 	conference_event_fn handler;
-	if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
-		handler = user->conference->state->join_marked;
-	} else if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
-		handler = user->conference->state->join_waitmarked;
+	if (ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)) {
+		handler = cbu->conference_bridge->state->join_marked;
+	} else if (ast_test_flag(&cbu->u_profile, USER_OPT_WAITMARKED)) {
+		handler = cbu->conference_bridge->state->join_waitmarked;
 	} else {
-		handler = user->conference->state->join_unmarked;
+		handler = cbu->conference_bridge->state->join_unmarked;
 	}
 
 	ast_assert(handler != NULL);
 
 	if (!handler) {
-		conf_invalid_event_fn(user);
+		conf_invalid_event_fn(cbu);
 		return -1;
 	}
 
-	handler(user);
+	handler(cbu);
 
 	return 0;
 }
 
 /*! \brief Call the proper leave event handler for the user for the conference bridge's current state
  * \internal
- * \param user The conference bridge user that is leaving
+ * \param cbu The conference bridge user that is leaving
  * \retval 0 success
  * \retval -1 failure
  */
-static int handle_conf_user_leave(struct confbridge_user *user)
+static int handle_conf_user_leave(struct conference_bridge_user *cbu)
 {
 	conference_event_fn handler;
-	if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
-		handler = user->conference->state->leave_marked;
-	} else if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
-		handler = user->conference->state->leave_waitmarked;
+	if (ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)) {
+		handler = cbu->conference_bridge->state->leave_marked;
+	} else if (ast_test_flag(&cbu->u_profile, USER_OPT_WAITMARKED)) {
+		handler = cbu->conference_bridge->state->leave_waitmarked;
 	} else {
-		handler = user->conference->state->leave_unmarked;
+		handler = cbu->conference_bridge->state->leave_unmarked;
 	}
 
 	ast_assert(handler != NULL);
@@ -1020,16 +937,16 @@ static int handle_conf_user_leave(struct confbridge_user *user)
 		/* This should never happen. If it does, though, it is bad. The user will not have been removed
 		 * from the appropriate list, so counts will be off and stuff. The conference won't be torn down, etc.
 		 * Shouldn't happen, though. */
-		conf_invalid_event_fn(user);
+		conf_invalid_event_fn(cbu);
 		return -1;
 	}
 
-	handler(user);
+	handler(cbu);
 
 	return 0;
 }
 
-void conf_update_user_mute(struct confbridge_user *user)
+void conf_update_user_mute(struct conference_bridge_user *user)
 {
 	int mute_user;
 	int mute_system;
@@ -1044,7 +961,7 @@ void conf_update_user_mute(struct confbridge_user *user)
 		 * Do not allow waitmarked users to talk to anyone unless there
 		 * is a marked user present.
 		 */
-		|| (!user->conference->markedusers
+		|| (!user->conference_bridge->markedusers
 			&& ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED));
 
 	mute_effective = mute_user || mute_system;
@@ -1062,7 +979,7 @@ void conf_update_user_mute(struct confbridge_user *user)
 		ast_channel_name(user->chan));
 }
 
-void conf_moh_stop(struct confbridge_user *user)
+void conf_moh_stop(struct conference_bridge_user *user)
 {
 	user->playing_moh = 0;
 	if (!user->suspended_moh) {
@@ -1073,23 +990,23 @@ void conf_moh_stop(struct confbridge_user *user)
 		 * call to ast_bridge_join() in confbridge_exec() from
 		 * interfering with the bridge and MOH operations here.
 		 */
-		ast_bridge_lock(user->conference->bridge);
+		ast_bridge_lock(user->conference_bridge->bridge);
 
 		/*
 		 * Temporarily suspend the user from the bridge so we have
 		 * control to stop MOH if needed.
 		 */
-		in_bridge = !ast_bridge_suspend(user->conference->bridge, user->chan);
+		in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
 		ast_moh_stop(user->chan);
 		if (in_bridge) {
-			ast_bridge_unsuspend(user->conference->bridge, user->chan);
+			ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
 		}
 
-		ast_bridge_unlock(user->conference->bridge);
+		ast_bridge_unlock(user->conference_bridge->bridge);
 	}
 }
 
-void conf_moh_start(struct confbridge_user *user)
+void conf_moh_start(struct conference_bridge_user *user)
 {
 	user->playing_moh = 1;
 	if (!user->suspended_moh) {
@@ -1100,19 +1017,19 @@ void conf_moh_start(struct confbridge_user *user)
 		 * call to ast_bridge_join() in confbridge_exec() from
 		 * interfering with the bridge and MOH operations here.
 		 */
-		ast_bridge_lock(user->conference->bridge);
+		ast_bridge_lock(user->conference_bridge->bridge);
 
 		/*
 		 * Temporarily suspend the user from the bridge so we have
 		 * control to start MOH if needed.
 		 */
-		in_bridge = !ast_bridge_suspend(user->conference->bridge, user->chan);
+		in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
 		ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
 		if (in_bridge) {
-			ast_bridge_unsuspend(user->conference->bridge, user->chan);
+			ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
 		}
 
-		ast_bridge_unlock(user->conference->bridge);
+		ast_bridge_unlock(user->conference_bridge->bridge);
 	}
 }
 
@@ -1124,13 +1041,13 @@ void conf_moh_start(struct confbridge_user *user)
  *
  * \return Nothing
  */
-static void conf_moh_unsuspend(struct confbridge_user *user)
+static void conf_moh_unsuspend(struct conference_bridge_user *user)
 {
-	ao2_lock(user->conference);
+	ao2_lock(user->conference_bridge);
 	if (--user->suspended_moh == 0 && user->playing_moh) {
 		ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
 	}
-	ao2_unlock(user->conference);
+	ao2_unlock(user->conference_bridge);
 }
 
 /*!
@@ -1141,32 +1058,32 @@ static void conf_moh_unsuspend(struct confbridge_user *user)
  *
  * \return Nothing
  */
-static void conf_moh_suspend(struct confbridge_user *user)
+static void conf_moh_suspend(struct conference_bridge_user *user)
 {
-	ao2_lock(user->conference);
+	ao2_lock(user->conference_bridge);
 	if (user->suspended_moh++ == 0 && user->playing_moh) {
 		ast_moh_stop(user->chan);
 	}
-	ao2_unlock(user->conference);
+	ao2_unlock(user->conference_bridge);
 }
 
-int conf_handle_inactive_waitmarked(struct confbridge_user *user)
+int conf_handle_inactive_waitmarked(struct conference_bridge_user *cbu)
 {
 	/* If we have not been quieted play back that they are waiting for the leader */
-	if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET) && play_prompt_to_user(user,
-			conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, user->b_profile.sounds))) {
+	if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu,
+			conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, cbu->b_profile.sounds))) {
 		/* user hungup while the sound was playing */
 		return -1;
 	}
 	return 0;
 }
 
-int conf_handle_only_unmarked(struct confbridge_user *user)
+int conf_handle_only_unmarked(struct conference_bridge_user *cbu)
 {
 	/* If audio prompts have not been quieted or this prompt quieted play it on out */
-	if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
-		if (play_prompt_to_user(user,
-			conf_get_sound(CONF_SOUND_ONLY_PERSON, user->b_profile.sounds))) {
+	if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
+		if (play_prompt_to_user(cbu,
+			conf_get_sound(CONF_SOUND_ONLY_PERSON, cbu->b_profile.sounds))) {
 			/* user hungup while the sound was playing */
 			return -1;
 		}
@@ -1174,214 +1091,219 @@ int conf_handle_only_unmarked(struct confbridge_user *user)
 	return 0;
 }
 
-int conf_add_post_join_action(struct confbridge_user *user, int (*func)(struct confbridge_user *user))
+int conf_add_post_join_action(struct conference_bridge_user *cbu, int (*func)(struct conference_bridge_user *cbu))
 {
 	struct post_join_action *action;
 	if (!(action = ast_calloc(1, sizeof(*action)))) {
 		return -1;
 	}
 	action->func = func;
-	AST_LIST_INSERT_TAIL(&user->post_join_list, action, list);
+	AST_LIST_INSERT_TAIL(&cbu->post_join_list, action, list);
 	return 0;
 }
 
 
-void conf_handle_first_join(struct confbridge_conference *conference)
+void conf_handle_first_join(struct conference_bridge *conference_bridge)
 {
-	ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference->name);
+	ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
 }
 
-void conf_handle_second_active(struct confbridge_conference *conference)
+void conf_handle_second_active(struct conference_bridge *conference_bridge)
 {
 	/* If we are the second participant we may need to stop music on hold on the first */
-	struct confbridge_user *first_user = AST_LIST_FIRST(&conference->active_list);
+	struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->active_list);
 
-	if (ast_test_flag(&first_user->u_profile, USER_OPT_MUSICONHOLD)) {
-		conf_moh_stop(first_user);
+	if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) {
+		conf_moh_stop(first_participant);
 	}
-	conf_update_user_mute(first_user);
+	conf_update_user_mute(first_participant);
 }
 
-void conf_ended(struct confbridge_conference *conference)
+void conf_ended(struct conference_bridge *conference_bridge)
 {
-	/* Called with a reference to conference */
-	ao2_unlink(conference_bridges, conference);
-	send_conf_end_event(conference);
-	conf_stop_record_thread(conference);
+	/* Called with a reference to conference_bridge */
+	ao2_unlink(conference_bridges, conference_bridge);
+	send_conf_end_event(conference_bridge->name);
+	ao2_lock(conference_bridge);
+	conf_stop_record(conference_bridge);
+	ao2_unlock(conference_bridge);
 }
 
 /*!
  * \brief Join a conference bridge
  *
- * \param conference_name The conference name
- * \param user Conference bridge user structure
+ * \param name The conference name
+ * \param conference_bridge_user Conference bridge user structure
  *
  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
  */
-static struct confbridge_conference *join_conference_bridge(const char *conference_name, struct confbridge_user *user)
+static struct conference_bridge *join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
 {
-	struct confbridge_conference *conference;
+	struct conference_bridge *conference_bridge = NULL;
 	struct post_join_action *action;
+	struct conference_bridge tmp;
 	int max_members_reached = 0;
 
+	ast_copy_string(tmp.name, name, sizeof(tmp.name));
+
 	/* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
 	ao2_lock(conference_bridges);
 
-	ast_debug(1, "Trying to find conference bridge '%s'\n", conference_name);
+	ast_debug(1, "Trying to find conference bridge '%s'\n", name);
 
 	/* Attempt to find an existing conference bridge */
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (conference && conference->b_profile.max_members) {
-		max_members_reached = conference->b_profile.max_members > conference->activeusers ? 0 : 1;
+	conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+
+	if (conference_bridge && conference_bridge->b_profile.max_members) {
+		max_members_reached = conference_bridge->b_profile.max_members > conference_bridge->activeusers ? 0 : 1;
 	}
 
 	/* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
-	if (conference && (max_members_reached || conference->locked) && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
+	if (conference_bridge && (max_members_reached || conference_bridge->locked) && !ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN)) {
 		ao2_unlock(conference_bridges);
-		ao2_ref(conference, -1);
-		ast_debug(1, "Conference '%s' is locked and caller is not an admin\n", conference_name);
-		ast_stream_and_wait(user->chan,
-				conf_get_sound(CONF_SOUND_LOCKED, user->b_profile.sounds),
+		ao2_ref(conference_bridge, -1);
+		ast_debug(1, "Conference '%s' is locked and caller is not an admin\n", name);
+		ast_stream_and_wait(conference_bridge_user->chan,
+				conf_get_sound(CONF_SOUND_LOCKED, conference_bridge_user->b_profile.sounds),
 				"");
 		return NULL;
 	}
 
 	/* If no conference bridge was found see if we can create one */
-	if (!conference) {
+	if (!conference_bridge) {
 		/* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
-		if (!(conference = ao2_alloc(sizeof(*conference), destroy_conference_bridge))) {
+		if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
 			ao2_unlock(conference_bridges);
-			ast_log(LOG_ERROR, "Conference '%s' could not be created.\n", conference_name);
+			ast_log(LOG_ERROR, "Conference '%s' could not be created.\n", name);
 			return NULL;
 		}
 
 		/* Setup lock for playback channel */
-		ast_mutex_init(&conference->playback_lock);
+		ast_mutex_init(&conference_bridge->playback_lock);
 
-		/* Setup lock for the record channel */
-		ast_mutex_init(&conference->record_lock);
-		ast_cond_init(&conference->record_cond, NULL);
+		/* Setup for the record channel */
+		conference_bridge->record_filename = ast_str_create(RECORD_FILENAME_INITIAL_SPACE);
+		if (!conference_bridge->record_filename) {
+			ao2_ref(conference_bridge, -1);
+			ao2_unlock(conference_bridges);
+			return NULL;
+		}
 
 		/* Setup conference bridge parameters */
-		conference->record_thread = AST_PTHREADT_NULL;
-		ast_copy_string(conference->name, conference_name, sizeof(conference->name));
-		conf_bridge_profile_copy(&conference->b_profile, &user->b_profile);
+		ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
+		conf_bridge_profile_copy(&conference_bridge->b_profile, &conference_bridge_user->b_profile);
 
 		/* Create an actual bridge that will do the audio mixing */
-		conference->bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
-			AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY,
-			app, conference_name, NULL);
-		if (!conference->bridge) {
-			ao2_ref(conference, -1);
-			conference = NULL;
+		if (!(conference_bridge->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX, 0))) {
+			ao2_ref(conference_bridge, -1);
+			conference_bridge = NULL;
 			ao2_unlock(conference_bridges);
-			ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", conference_name);
+			ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", name);
 			return NULL;
 		}
 
 		/* Set the internal sample rate on the bridge from the bridge profile */
-		ast_bridge_set_internal_sample_rate(conference->bridge, conference->b_profile.internal_sample_rate);
+		ast_bridge_set_internal_sample_rate(conference_bridge->bridge, conference_bridge->b_profile.internal_sample_rate);
 		/* Set the internal mixing interval on the bridge from the bridge profile */
-		ast_bridge_set_mixing_interval(conference->bridge, conference->b_profile.mix_interval);
+		ast_bridge_set_mixing_interval(conference_bridge->bridge, conference_bridge->b_profile.mix_interval);
 
-		if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
-			ast_bridge_set_talker_src_video_mode(conference->bridge);
+		if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
+			ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
 		}
 
 		/* Link it into the conference bridges container */
-		if (!ao2_link(conference_bridges, conference)) {
-			ao2_ref(conference, -1);
-			conference = NULL;
+		if (!ao2_link(conference_bridges, conference_bridge)) {
+			ao2_ref(conference_bridge, -1);
+			conference_bridge = NULL;
 			ao2_unlock(conference_bridges);
 			ast_log(LOG_ERROR,
-				"Conference '%s' could not be added to the conferences list.\n", conference_name);
+				"Conference '%s' could not be added to the conferences list.\n", name);
 			return NULL;
 		}
 
 		/* Set the initial state to EMPTY */
-		conference->state = CONF_STATE_EMPTY;
+		conference_bridge->state = CONF_STATE_EMPTY;
 
-		conference->record_state = CONF_RECORD_STOP;
-		if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) {
-			ao2_lock(conference);
-			start_conf_record_thread(conference);
-			ao2_unlock(conference);
+		if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) {
+			ao2_lock(conference_bridge);
+			conf_start_record(conference_bridge);
+			ao2_unlock(conference_bridge);
 		}
 
-		send_conf_start_event(conference);
-		ast_debug(1, "Created conference '%s' and linked to container.\n", conference_name);
+		send_conf_start_event(conference_bridge->name);
+		ast_debug(1, "Created conference '%s' and linked to container.\n", name);
 	}
 
 	ao2_unlock(conference_bridges);
 
 	/* Setup conference bridge user parameters */
-	user->conference = conference;
+	conference_bridge_user->conference_bridge = conference_bridge;
 
-	ao2_lock(conference);
+	ao2_lock(conference_bridge);
 
 	/*
 	 * Suspend any MOH until the user actually joins the bridge of
 	 * the conference.  This way any pre-join file playback does not
 	 * need to worry about MOH.
 	 */
-	user->suspended_moh = 1;
+	conference_bridge_user->suspended_moh = 1;
 
-	if (handle_conf_user_join(user)) {
+	if (handle_conf_user_join(conference_bridge_user)) {
 		/* Invalid event, nothing was done, so we don't want to process a leave. */
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(conference_bridge);
+		ao2_ref(conference_bridge, -1);
 		return NULL;
 	}
 
-	if (ast_check_hangup(user->chan)) {
-		ao2_unlock(conference);
-		leave_conference(user);
+	if (ast_check_hangup(conference_bridge_user->chan)) {
+		ao2_unlock(conference_bridge);
+		leave_conference(conference_bridge_user);
 		return NULL;
 	}
 
-	ao2_unlock(conference);
+	ao2_unlock(conference_bridge);
 
 	/* If an announcement is to be played play it */
-	if (!ast_strlen_zero(user->u_profile.announcement)) {
-		if (play_prompt_to_user(user,
-			user->u_profile.announcement)) {
-			leave_conference(user);
+	if (!ast_strlen_zero(conference_bridge_user->u_profile.announcement)) {
+		if (play_prompt_to_user(conference_bridge_user,
+			conference_bridge_user->u_profile.announcement)) {
+			leave_conference(conference_bridge_user);
 			return NULL;
 		}
 	}
 
 	/* Announce number of users if need be */
-	if (ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
-		if (announce_user_count(conference, user)) {
-			leave_conference(user);
+	if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
+		if (announce_user_count(conference_bridge, conference_bridge_user, 0)) {
+			leave_conference(conference_bridge_user);
 			return NULL;
 		}
 	}
 
-	if (ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
-		(conference->activeusers > user->u_profile.announce_user_count_all_after)) {
+	if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
+		(conference_bridge->activeusers > conference_bridge_user->u_profile.announce_user_count_all_after)) {
 		int user_count_res;
 
 		/*
 		 * We have to autoservice the new user because he has not quite
 		 * joined the conference yet.
 		 */
-		ast_autoservice_start(user->chan);
-		user_count_res = announce_user_count(conference, NULL);
-		ast_autoservice_stop(user->chan);
+		ast_autoservice_start(conference_bridge_user->chan);
+		user_count_res = announce_user_count(conference_bridge, NULL, 0);
+		ast_autoservice_stop(conference_bridge_user->chan);
 		if (user_count_res) {
-			leave_conference(user);
+			leave_conference(conference_bridge_user);
 			return NULL;
 		}
 	}
 
 	/* Handle post-join actions */
-	while ((action = AST_LIST_REMOVE_HEAD(&user->post_join_list, list))) {
-		action->func(user);
+	while ((action = AST_LIST_REMOVE_HEAD(&conference_bridge_user->post_join_list, list))) {
+		action->func(conference_bridge_user);
 		ast_free(action);
 	}
 
-	return conference;
+	return conference_bridge;
 }
 
 /*!
@@ -1389,13 +1311,13 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen
  *
  * \param user The conference user
  */
-static void leave_conference(struct confbridge_user *user)
+static void leave_conference(struct conference_bridge_user *user)
 {
 	struct post_join_action *action;
 
-	ao2_lock(user->conference);
+	ao2_lock(user->conference_bridge);
 	handle_conf_user_leave(user);
-	ao2_unlock(user->conference);
+	ao2_unlock(user->conference_bridge);
 
 	/* Discard any post-join actions */
 	while ((action = AST_LIST_REMOVE_HEAD(&user->post_join_list, list))) {
@@ -1403,122 +1325,156 @@ static void leave_conference(struct confbridge_user *user)
 	}
 
 	/* Done mucking with the conference, huzzah */
-	ao2_ref(user->conference, -1);
-	user->conference = NULL;
+	ao2_ref(user->conference_bridge, -1);
+	user->conference_bridge = NULL;
 }
 
 /*!
  * \internal
- * \brief Allocate playback channel for a conference.
+ * \brief allocates playback chan on a channel
  * \pre expects conference to be locked before calling this function
  */
-static int alloc_playback_chan(struct confbridge_conference *conference)
+static int alloc_playback_chan(struct conference_bridge *conference_bridge)
 {
+	int cause;
 	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
 
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!cap) {
+	if (conference_bridge->playback_chan) {
+		return 0;
+	}
+	if (!(cap = ast_format_cap_alloc_nolock())) {
 		return -1;
 	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
-	conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL,
-		conference->name, NULL);
-	ao2_ref(cap, -1);
-	if (!conference->playback_chan) {
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	if (!(conference_bridge->playback_chan = ast_request("Bridge", cap, NULL, "", &cause))) {
+		cap = ast_format_cap_destroy(cap);
 		return -1;
 	}
+	cap = ast_format_cap_destroy(cap);
+
+	ast_channel_internal_bridge_set(conference_bridge->playback_chan, conference_bridge->bridge);
 
 	/* To make sure playback_chan has the same language of that profile */
-	ast_channel_lock(conference->playback_chan);
-	ast_channel_language_set(conference->playback_chan, conference->b_profile.language);
-	ast_channel_unlock(conference->playback_chan);
+	ast_channel_language_set(conference_bridge->playback_chan, conference_bridge->b_profile.language);
 
-	ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n",
-		ast_channel_name(conference->playback_chan), conference->name);
+	if (ast_call(conference_bridge->playback_chan, "", 0)) {
+		ast_hangup(conference_bridge->playback_chan);
+		conference_bridge->playback_chan = NULL;
+		return -1;
+	}
+
+	ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
 	return 0;
 }
 
-static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number)
+static int play_sound_helper(struct conference_bridge *conference_bridge, const char *filename, int say_number)
 {
+	struct ast_channel *underlying_channel;
+
 	/* Do not waste resources trying to play files that do not exist */
 	if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) {
 		return 0;
 	}
 
-	ast_mutex_lock(&conference->playback_lock);
-	if (!conference->playback_chan && alloc_playback_chan(conference)) {
-		ast_mutex_unlock(&conference->playback_lock);
-		return -1;
-	}
-	if (conf_announce_channel_push(conference->playback_chan)) {
-		ast_mutex_unlock(&conference->playback_lock);
-		return -1;
+	ast_mutex_lock(&conference_bridge->playback_lock);
+	if (!(conference_bridge->playback_chan)) {
+		if (alloc_playback_chan(conference_bridge)) {
+			ast_mutex_unlock(&conference_bridge->playback_lock);
+			return -1;
+		}
+		underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
+	} else {
+		/* Channel was already available so we just need to add it back into the bridge */
+		underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
+		if (ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL, 0)) {
+			ast_mutex_unlock(&conference_bridge->playback_lock);
+			return -1;
+		}
 	}
 
 	/* The channel is all under our control, in goes the prompt */
 	if (!ast_strlen_zero(filename)) {
-		ast_stream_and_wait(conference->playback_chan, filename, "");
+		ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
 	} else if (say_number >= 0) {
-		ast_say_number(conference->playback_chan, say_number, "",
-			ast_channel_language(conference->playback_chan), NULL);
+		ast_say_number(conference_bridge->playback_chan, say_number, "", ast_channel_language(conference_bridge->playback_chan), NULL);
 	}
 
-	ast_debug(1, "Departing announcer channel '%s' from conference bridge '%s'\n",
-		ast_channel_name(conference->playback_chan), conference->name);
-	conf_announce_channel_depart(conference->playback_chan);
+	ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", ast_channel_name(underlying_channel), conference_bridge->bridge);
+	ast_bridge_depart(conference_bridge->bridge, underlying_channel);
 
-	ast_mutex_unlock(&conference->playback_lock);
+	ast_mutex_unlock(&conference_bridge->playback_lock);
 
 	return 0;
 }
 
-int play_sound_file(struct confbridge_conference *conference, const char *filename)
+int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
 {
-	return play_sound_helper(conference, filename, -1);
+	return play_sound_helper(conference_bridge, filename, -1);
 }
 
 /*!
  * \brief Play number into the conference bridge
  *
- * \param conference The conference bridge to say the number into
- * \param say_number number to say
+ * \param conference_bridge The conference bridge to say the number into
+ * \param number to say
  *
  * \retval 0 success
  * \retval -1 failure
  */
-static int play_sound_number(struct confbridge_conference *conference, int say_number)
+static int play_sound_number(struct conference_bridge *conference_bridge, int say_number)
 {
-	return play_sound_helper(conference, NULL, say_number);
+	return play_sound_helper(conference_bridge, NULL, say_number);
 }
 
-static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking)
+static void conf_handle_talker_destructor(void *pvt_data)
 {
-	const struct confbridge_user *user = hook_pvt;
-	RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
-	struct ast_json *talking_extras;
-
-	conference = ao2_find(conference_bridges, user->conference->name, OBJ_KEY);
-	if (!conference) {
-		/* Remove the hook since the conference does not exist. */
-		return -1;
-	}
-
-	talking_extras = ast_json_pack("{s: s, s: b}",
-		"talking_status", talking ? "on" : "off",
-		"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN));
-	if (!talking_extras) {
-		return 0;
-	}
-
-	send_conf_stasis(conference, bridge_channel->chan, confbridge_talking_type(), talking_extras, 0);
-	ast_json_unref(talking_extras);
-	return 0;
+	ast_free(pvt_data);
 }
 
-static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
+static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
+{
+	char *conf_name = pvt_data;
+	int talking;
+
+	switch (bridge_channel->state) {
+	case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
+		talking = 1;
+		break;
+	case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
+		talking = 0;
+		break;
+	default:
+		return; /* uhh this shouldn't happen, but bail if it does. */
+	}
+
+	/* notify AMI someone is has either started or stopped talking */
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a conference participant has started or stopped talking.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+				<parameter name="TalkingStatus">
+					<enumlist>
+						<enum name="on"/>
+						<enum name="off"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
+	      "Channel: %s\r\n"
+	      "Uniqueid: %s\r\n"
+	      "Conference: %s\r\n"
+	      "TalkingStatus: %s\r\n",
+	      ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
+}
+
+static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)
 {
 	char pin_guess[MAX_PIN+1] = { 0, };
-	const char *pin = user->u_profile.pin;
+	const char *pin = conference_bridge_user->u_profile.pin;
 	char *tmp = pin_guess;
 	int i, res;
 	unsigned int len = MAX_PIN ;
@@ -1526,14 +1482,14 @@ static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
 	/* give them three tries to get the pin right */
 	for (i = 0; i < 3; i++) {
 		if (ast_app_getdata(chan,
-			conf_get_sound(CONF_SOUND_GET_PIN, user->b_profile.sounds),
+			conf_get_sound(CONF_SOUND_GET_PIN, conference_bridge_user->b_profile.sounds),
 			tmp, len, 0) >= 0) {
 			if (!strcasecmp(pin, pin_guess)) {
 				return 0;
 			}
 		}
 		ast_streamfile(chan,
-			conf_get_sound(CONF_SOUND_INVALID_PIN, user->b_profile.sounds),
+			conf_get_sound(CONF_SOUND_INVALID_PIN, conference_bridge_user->b_profile.sounds),
 			ast_channel_language(chan));
 		res = ast_waitstream(chan, AST_DIGIT_ANY);
 		if (res > 0) {
@@ -1552,7 +1508,7 @@ static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
 	return -1;
 }
 
-static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
+static int conf_rec_name(struct conference_bridge_user *user, const char *conf_name)
 {
 	char destdir[PATH_MAX];
 	int res;
@@ -1568,26 +1524,16 @@ static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
 		 "%s/confbridge-name-%s-%s", destdir,
 		 conf_name, ast_channel_uniqueid(user->chan));
 
-	if (!(ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW))) {
-		res = ast_play_and_record(user->chan,
-			"vm-rec-name",
-			user->name_rec_location,
-			10,
-			"sln",
-			&duration,
-			NULL,
-			ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
-			0,
-			NULL);
-	} else {
-		res = ast_record_review(user->chan,
-			"vm-rec-name",
-			user->name_rec_location,
-			10,
-			"sln",
-			&duration,
-			NULL);
-	}
+	res = ast_play_and_record(user->chan,
+		"vm-rec-name",
+		user->name_rec_location,
+		10,
+		"sln",
+		&duration,
+		NULL,
+		ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
+		0,
+		NULL);
 
 	if (res == -1) {
 		user->name_rec_location[0] = '\0';
@@ -1602,11 +1548,10 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 	int res = 0, volume_adjustments[2];
 	int quiet = 0;
 	char *parse;
-	const char *b_profile_name = NULL;
-	const char *u_profile_name = NULL;
-	const char *menu_profile_name = NULL;
-	struct confbridge_conference *conference = NULL;
-	struct confbridge_user user = {
+	const char *b_profile_name = DEFAULT_BRIDGE_PROFILE;
+	const char *u_profile_name = DEFAULT_USER_PROFILE;
+	struct conference_bridge *conference_bridge = NULL;
+	struct conference_bridge_user conference_bridge_user = {
 		.chan = chan,
 		.tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
 		.tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
@@ -1616,33 +1561,26 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(conf_name);
 		AST_APP_ARG(b_profile_name);
 		AST_APP_ARG(u_profile_name);
-		AST_APP_ARG(menu_profile_name);
+		AST_APP_ARG(menu_name);
 	);
+	ast_bridge_features_init(&conference_bridge_user.features);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_answer(chan);
 	}
 
-	if (ast_bridge_features_init(&user.features)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
-		res = -1;
-		goto confbridge_cleanup;
-	}
-
 	/* We need to make a copy of the input string if we are going to modify it! */
 	parse = ast_strdupa(data);
 
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (ast_strlen_zero(args.conf_name)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
 		ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
 		res = -1;
 		goto confbridge_cleanup;
 	}
 
 	if (strlen(args.conf_name) >= MAX_CONF_NAME) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
 		ast_log(LOG_WARNING, "%s does not accept conference names longer than %d\n", app, MAX_CONF_NAME - 1);
 		res = -1;
 		goto confbridge_cleanup;
@@ -1652,10 +1590,8 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 	if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
 		b_profile_name = args.b_profile_name;
 	}
-	if (!conf_find_bridge_profile(chan, b_profile_name, &user.b_profile)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
-		ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name ?
-			b_profile_name : DEFAULT_BRIDGE_PROFILE);
+	if (!conf_find_bridge_profile(chan, b_profile_name, &conference_bridge_user.b_profile)) {
+		ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name);
 		res = -1;
 		goto confbridge_cleanup;
 	}
@@ -1664,80 +1600,73 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 	if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
 		u_profile_name = args.u_profile_name;
 	}
-	if (!conf_find_user_profile(chan, u_profile_name, &user.u_profile)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
-		ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name ?
-			u_profile_name : DEFAULT_USER_PROFILE);
+	if (!conf_find_user_profile(chan, u_profile_name, &conference_bridge_user.u_profile)) {
+		ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name);
 		res = -1;
 		goto confbridge_cleanup;
 	}
 
-	quiet = ast_test_flag(&user.u_profile, USER_OPT_QUIET);
+	quiet = ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_QUIET);
 
 	/* ask for a PIN immediately after finding user profile.  This has to be
 	 * prompted for requardless of quiet setting. */
-	if (!ast_strlen_zero(user.u_profile.pin)) {
-		if (conf_get_pin(chan, &user)) {
-			pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
+	if (!ast_strlen_zero(conference_bridge_user.u_profile.pin)) {
+		if (conf_get_pin(chan, &conference_bridge_user)) {
 			res = -1; /* invalid PIN */
 			goto confbridge_cleanup;
 		}
 	}
 
 	/* See if we need them to record a intro name */
-	if (!quiet &&
-		(ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE) ||
-		(ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW)))) {
-		conf_rec_name(&user, args.conf_name);
+	if (!quiet && ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE)) {
+		conf_rec_name(&conference_bridge_user, args.conf_name);
 	}
 
 	/* menu name */
-	if (args.argc > 3 && !ast_strlen_zero(args.menu_profile_name)) {
-		menu_profile_name = args.menu_profile_name;
-	}
-
-	if (conf_set_menu_to_user(chan, &user, menu_profile_name)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
-		ast_log(LOG_WARNING, "Conference menu profile %s does not exist\n", menu_profile_name ?
-			menu_profile_name : DEFAULT_MENU_PROFILE);
-		res = -1;
-		goto confbridge_cleanup;
+	if (args.argc > 3 && !ast_strlen_zero(args.menu_name)) {
+		ast_copy_string(conference_bridge_user.menu_name, args.menu_name, sizeof(conference_bridge_user.menu_name));
+		if (conf_set_menu_to_user(conference_bridge_user.menu_name, &conference_bridge_user)) {
+			ast_log(LOG_WARNING, "Conference menu %s does not exist and can not be applied to confbridge user.\n",
+				args.menu_name);
+			res = -1;
+			goto confbridge_cleanup;
+		}
 	}
 
 	/* Set if DTMF should pass through for this user or not */
-	if (ast_test_flag(&user.u_profile, USER_OPT_DTMF_PASS)) {
-		user.features.dtmf_passthrough = 1;
-	} else {
-		user.features.dtmf_passthrough = 0;
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DTMF_PASS)) {
+		conference_bridge_user.features.dtmf_passthrough = 1;
 	}
 
 	/* Set dsp threshold values if present */
-	if (user.u_profile.talking_threshold) {
-		user.tech_args.talking_threshold = user.u_profile.talking_threshold;
+	if (conference_bridge_user.u_profile.talking_threshold) {
+		conference_bridge_user.tech_args.talking_threshold = conference_bridge_user.u_profile.talking_threshold;
 	}
-	if (user.u_profile.silence_threshold) {
-		user.tech_args.silence_threshold = user.u_profile.silence_threshold;
+	if (conference_bridge_user.u_profile.silence_threshold) {
+		conference_bridge_user.tech_args.silence_threshold = conference_bridge_user.u_profile.silence_threshold;
 	}
 
 	/* Set a talker indicate call back if talking detection is requested */
-	if (ast_test_flag(&user.u_profile, USER_OPT_TALKER_DETECT)) {
-		if (ast_bridge_talk_detector_hook(&user.features, conf_handle_talker_cb,
-			&user, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-			pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_TALKER_DETECT)) {
+		char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
+		if (!(conf_name)) {
 			res = -1;
 			goto confbridge_cleanup;
 		}
+		ast_bridge_features_set_talk_detector(&conference_bridge_user.features,
+			conf_handle_talker_cb,
+			conf_handle_talker_destructor,
+			conf_name);
 	}
 
 	/* If the caller should be joined already muted, set the flag before we join. */
-	if (ast_test_flag(&user.u_profile, USER_OPT_STARTMUTED)) {
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
 		/* Set user level mute request. */
-		user.muted = 1;
+		conference_bridge_user.muted = 1;
 	}
 
 	/* Look for a conference bridge matching the provided name */
-	if (!(conference = join_conference_bridge(args.conf_name, &user))) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
+	if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
 		res = -1;
 		goto confbridge_cleanup;
 	}
@@ -1746,11 +1675,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 	volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
 	volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
 
-	if (ast_test_flag(&user.u_profile, USER_OPT_DROP_SILENCE)) {
-		user.tech_args.drop_silence = 1;
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
+		conference_bridge_user.tech_args.drop_silence = 1;
 	}
 
-	if (ast_test_flag(&user.u_profile, USER_OPT_JITTERBUFFER)) {
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_JITTERBUFFER)) {
 		char *func_jb;
 		if ((func_jb = ast_module_helper("", "func_jitterbuffer", 0, 0, 0, 0))) {
 			ast_free(func_jb);
@@ -1758,7 +1687,7 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 		}
 	}
 
-	if (ast_test_flag(&user.u_profile, USER_OPT_DENOISE)) {
+	if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DENOISE)) {
 		char *mod_speex;
 		/* Reduce background noise from each participant */
 		if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
@@ -1768,79 +1697,73 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 	}
 
 	/* if this user has a intro, play it before entering */
-	if (!ast_strlen_zero(user.name_rec_location)) {
+	if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
 		ast_autoservice_start(chan);
-		play_sound_file(conference, user.name_rec_location);
-		play_sound_file(conference,
-			conf_get_sound(CONF_SOUND_HAS_JOINED, user.b_profile.sounds));
+		play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
+		play_sound_file(conference_bridge,
+			conf_get_sound(CONF_SOUND_HAS_JOINED, conference_bridge_user.b_profile.sounds));
 		ast_autoservice_stop(chan);
 	}
 
 	/* Play the Join sound to both the conference and the user entering. */
 	if (!quiet) {
-		const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, user.b_profile.sounds);
+		const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds);
 
 		ast_stream_and_wait(chan, join_sound, "");
 		ast_autoservice_start(chan);
-		play_sound_file(conference, join_sound);
+		play_sound_file(conference_bridge, join_sound);
 		ast_autoservice_stop(chan);
 	}
 
 	/* See if we need to automatically set this user as a video source or not */
-	handle_video_on_join(conference, user.chan, ast_test_flag(&user.u_profile, USER_OPT_MARKEDUSER));
+	handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER));
 
-	conf_moh_unsuspend(&user);
+	conf_moh_unsuspend(&conference_bridge_user);
 
 	/* Join our conference bridge for real */
-	send_join_event(&user, conference);
-	ast_bridge_join(conference->bridge,
+	send_join_event(conference_bridge_user.chan, conference_bridge->name);
+	ast_bridge_join(conference_bridge->bridge,
 		chan,
 		NULL,
-		&user.features,
-		&user.tech_args,
-		0);
-
-	if (!user.kicked && ast_check_hangup(chan)) {
-		pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP");
-	}
-
-	send_leave_event(&user, conference);
+		&conference_bridge_user.features,
+		&conference_bridge_user.tech_args);
+	send_leave_event(conference_bridge_user.chan, conference_bridge->name);
 
 	/* if we're shutting down, don't attempt to do further processing */
 	if (ast_shutting_down()) {
-		leave_conference(&user);
-		conference = NULL;
+		leave_conference(&conference_bridge_user);
+		conference_bridge = NULL;
 		goto confbridge_cleanup;
 	}
 
 	/* If this user was a video source, we need to clean up and possibly pick a new source. */
-	handle_video_on_exit(conference, user.chan);
+	handle_video_on_exit(conference_bridge, conference_bridge_user.chan);
 
 	/* if this user has a intro, play it when leaving */
-	if (!quiet && !ast_strlen_zero(user.name_rec_location)) {
+	if (!quiet && !ast_strlen_zero(conference_bridge_user.name_rec_location)) {
 		ast_autoservice_start(chan);
-		play_sound_file(conference, user.name_rec_location);
-		play_sound_file(conference,
-			conf_get_sound(CONF_SOUND_HAS_LEFT, user.b_profile.sounds));
+		play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
+		play_sound_file(conference_bridge,
+			conf_get_sound(CONF_SOUND_HAS_LEFT, conference_bridge_user.b_profile.sounds));
 		ast_autoservice_stop(chan);
 	}
 
 	/* play the leave sound */
 	if (!quiet) {
-		const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, user.b_profile.sounds);
+		const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference_bridge_user.b_profile.sounds);
 		ast_autoservice_start(chan);
-		play_sound_file(conference, leave_sound);
+		play_sound_file(conference_bridge, leave_sound);
 		ast_autoservice_stop(chan);
 	}
 
 	/* Easy as pie, depart this channel from the conference bridge */
-	leave_conference(&user);
-	conference = NULL;
+	leave_conference(&conference_bridge_user);
+	conference_bridge = NULL;
 
 	/* If the user was kicked from the conference play back the audio prompt for it */
-	if (!quiet && user.kicked) {
+	if (!quiet && conference_bridge_user.kicked) {
 		res = ast_stream_and_wait(chan,
-			conf_get_sound(CONF_SOUND_KICKED, user.b_profile.sounds),
+			conf_get_sound(CONF_SOUND_KICKED, conference_bridge_user.b_profile.sounds),
 			"");
 	}
 
@@ -1852,78 +1775,73 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 		ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
 	}
 
-	if (!ast_strlen_zero(user.name_rec_location)) {
-		ast_filedelete(user.name_rec_location, NULL);
+	if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
+		ast_filedelete(conference_bridge_user.name_rec_location, NULL);
 	}
 
 confbridge_cleanup:
-	ast_bridge_features_cleanup(&user.features);
-	conf_bridge_profile_destroy(&user.b_profile);
+	ast_bridge_features_cleanup(&conference_bridge_user.features);
+	conf_bridge_profile_destroy(&conference_bridge_user.b_profile);
 	return res;
 }
 
-static int action_toggle_mute(struct confbridge_conference *conference,
-	struct confbridge_user *user)
+static int action_toggle_mute(struct conference_bridge *conference_bridge,
+	struct conference_bridge_user *conference_bridge_user,
+	struct ast_channel *chan)
 {
 	int mute;
 
 	/* Toggle user level mute request. */
-	mute = !user->muted;
-	user->muted = mute;
+	mute = !conference_bridge_user->muted;
+	conference_bridge_user->muted = mute;
 
-	conf_update_user_mute(user);
+	conf_update_user_mute(conference_bridge_user);
 	ast_test_suite_event_notify("CONF_MUTE",
 		"Message: participant %s %s\r\n"
 		"Conference: %s\r\n"
 		"Channel: %s",
-		ast_channel_name(user->chan),
+		ast_channel_name(chan),
 		mute ? "muted" : "unmuted",
-		user->b_profile.name,
-		ast_channel_name(user->chan));
-	if (mute) {
-		send_mute_event(user, conference);
-	} else {
-		send_unmute_event(user, conference);
-	}
+		conference_bridge_user->b_profile.name,
+		ast_channel_name(chan));
 
-	return ast_stream_and_wait(user->chan, (mute ?
-		conf_get_sound(CONF_SOUND_MUTED, user->b_profile.sounds) :
-		conf_get_sound(CONF_SOUND_UNMUTED, user->b_profile.sounds)),
-		"");
+	return play_file(chan, (mute ?
+		conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) :
+		conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)), 1) < 0;
 }
 
-static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user)
+static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 {
-	struct confbridge_user *cur_user = NULL;
+	struct conference_bridge_user *participant = NULL;
 	const char *sound_to_play;
 	int mute;
 
-	ao2_lock(conference);
+	ao2_lock(conference_bridge);
 
 	/* Toggle bridge level mute request. */
-	mute = !conference->muted;
-	conference->muted = mute;
+	mute = !conference_bridge->muted;
+	conference_bridge->muted = mute;
 
-	AST_LIST_TRAVERSE(&conference->active_list, cur_user, list) {
-		if (!ast_test_flag(&cur_user->u_profile, USER_OPT_ADMIN)) {
+	AST_LIST_TRAVERSE(&conference_bridge->active_list, participant, list) {
+		if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
 			/* Set user level to bridge level mute request. */
-			cur_user->muted = mute;
-			conf_update_user_mute(cur_user);
+			participant->muted = mute;
+			conf_update_user_mute(participant);
 		}
 	}
 
-	ao2_unlock(conference);
+	ao2_unlock(conference_bridge);
 
 	sound_to_play = conf_get_sound((mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED),
-		user->b_profile.sounds);
+		conference_bridge_user->b_profile.sounds);
 
 	/* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
-	ast_stream_and_wait(user->chan, sound_to_play, "");
+	ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, "");
 
 	/* Announce to the group that all participants are muted */
-	ast_autoservice_start(user->chan);
-	play_sound_helper(conference, sound_to_play, 0);
-	ast_autoservice_stop(user->chan);
+	ast_autoservice_start(conference_bridge_user->chan);
+	play_sound_helper(conference_bridge, sound_to_play, 0);
+	ast_autoservice_stop(conference_bridge_user->chan);
 
 	return 0;
 }
@@ -1942,8 +1860,8 @@ static int action_playback(struct ast_bridge_channel *bridge_channel, const char
 	return 0;
 }
 
-static int action_playback_and_continue(struct confbridge_conference *conference,
-	struct confbridge_user *user,
+static int action_playback_and_continue(struct conference_bridge *conference_bridge,
+	struct conference_bridge_user *conference_bridge_user,
 	struct ast_bridge_channel *bridge_channel,
 	struct conf_menu *menu,
 	const char *playback_file,
@@ -2004,8 +1922,8 @@ static int action_playback_and_continue(struct confbridge_conference *conference
 	}
 
 	if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
-		execute_menu_entry(conference,
-			user,
+		execute_menu_entry(conference_bridge,
+			conference_bridge_user,
 			bridge_channel,
 			&new_menu_entry, menu);
 		conf_menu_entry_destroy(&new_menu_entry);
@@ -2013,35 +1931,31 @@ static int action_playback_and_continue(struct confbridge_conference *conference
 	return 0;
 }
 
-static int action_kick_last(struct confbridge_conference *conference,
-	struct ast_bridge_channel *bridge_channel,
-	struct confbridge_user *user)
+static int action_kick_last(struct conference_bridge *conference_bridge,
+	struct conference_bridge_user *conference_bridge_user)
 {
-	struct confbridge_user *last_user = NULL;
-	int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
+	struct conference_bridge_user *last_participant = NULL;
+	int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
 
 	if (!isadmin) {
-		ast_stream_and_wait(bridge_channel->chan,
-			conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds),
-			"");
+		play_file(conference_bridge_user->chan,
+			conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), 1);
 		ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
-			ast_channel_name(bridge_channel->chan),
-			conference->name);
+			ast_channel_name(conference_bridge_user->chan),
+			conference_bridge->name);
 		return -1;
 	}
 
-	ao2_lock(conference);
-	if (((last_user = AST_LIST_LAST(&conference->active_list)) == user)
-		|| (ast_test_flag(&last_user->u_profile, USER_OPT_ADMIN))) {
-		ao2_unlock(conference);
-		ast_stream_and_wait(bridge_channel->chan,
-			conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds),
-			"");
-	} else if (last_user && !last_user->kicked) {
-		last_user->kicked = 1;
-		pbx_builtin_setvar_helper(last_user->chan, "CONFBRIDGE_RESULT", "KICKED");
-		ast_bridge_remove(conference->bridge, last_user->chan);
-		ao2_unlock(conference);
+	ao2_lock(conference_bridge);
+	if (((last_participant = AST_LIST_LAST(&conference_bridge->active_list)) == conference_bridge_user)
+		|| (ast_test_flag(&last_participant->u_profile, USER_OPT_ADMIN))) {
+		ao2_unlock(conference_bridge);
+		play_file(conference_bridge_user->chan,
+			conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), 1);
+	} else if (last_participant && !last_participant->kicked) {
+		last_participant->kicked = 1;
+		ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
+		ao2_unlock(conference_bridge);
 	}
 	return 0;
 }
@@ -2090,65 +2004,64 @@ static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struc
 	return res;
 }
 
-static int execute_menu_entry(struct confbridge_conference *conference,
-	struct confbridge_user *user,
+static int execute_menu_entry(struct conference_bridge *conference_bridge,
+	struct conference_bridge_user *conference_bridge_user,
 	struct ast_bridge_channel *bridge_channel,
 	struct conf_menu_entry *menu_entry,
 	struct conf_menu *menu)
 {
 	struct conf_menu_action *menu_action;
-	int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
+	int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
 	int stop_prompts = 0;
 	int res = 0;
 
 	AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
 		switch (menu_action->id) {
 		case MENU_ACTION_TOGGLE_MUTE:
-			res |= action_toggle_mute(conference, user);
+			res |= action_toggle_mute(conference_bridge,
+				conference_bridge_user,
+				bridge_channel->chan);
 			break;
 		case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
 			if (!isadmin) {
 				break;
 			}
-			action_toggle_mute_participants(conference, user);
+			action_toggle_mute_participants(conference_bridge, conference_bridge_user);
 			break;
 		case MENU_ACTION_PARTICIPANT_COUNT:
-			announce_user_count(conference, user);
+			announce_user_count(conference_bridge, conference_bridge_user, 1);
 			break;
 		case MENU_ACTION_PLAYBACK:
 			if (!stop_prompts) {
 				res |= action_playback(bridge_channel, menu_action->data.playback_file);
-				ast_test_suite_event_notify("CONF_MENU_PLAYBACK",
-					"Message: %s\r\nChannel: %s",
-					menu_action->data.playback_file, ast_channel_name(bridge_channel->chan));
 			}
 			break;
 		case MENU_ACTION_RESET_LISTENING:
-			ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
+			ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
 			break;
 		case MENU_ACTION_RESET_TALKING:
-			ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
+			ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
 			break;
 		case MENU_ACTION_INCREASE_LISTENING:
-			ast_audiohook_volume_adjust(user->chan,
+			ast_audiohook_volume_adjust(conference_bridge_user->chan,
 				AST_AUDIOHOOK_DIRECTION_WRITE, 1);
 			break;
 		case MENU_ACTION_DECREASE_LISTENING:
-			ast_audiohook_volume_adjust(user->chan,
+			ast_audiohook_volume_adjust(conference_bridge_user->chan,
 				AST_AUDIOHOOK_DIRECTION_WRITE, -1);
 			break;
 		case MENU_ACTION_INCREASE_TALKING:
-			ast_audiohook_volume_adjust(user->chan,
+			ast_audiohook_volume_adjust(conference_bridge_user->chan,
 				AST_AUDIOHOOK_DIRECTION_READ, 1);
 			break;
 		case MENU_ACTION_DECREASE_TALKING:
-			ast_audiohook_volume_adjust(user->chan,
+			ast_audiohook_volume_adjust(conference_bridge_user->chan,
 				AST_AUDIOHOOK_DIRECTION_READ, -1);
 			break;
 		case MENU_ACTION_PLAYBACK_AND_CONTINUE:
 			if (!(stop_prompts)) {
-				res |= action_playback_and_continue(conference,
-					user,
+				res |= action_playback_and_continue(conference_bridge,
+					conference_bridge_user,
 					bridge_channel,
 					menu,
 					menu_action->data.playback_file,
@@ -2163,35 +2076,29 @@ static int execute_menu_entry(struct confbridge_conference *conference,
 			if (!isadmin) {
 				break;
 			}
-			conference->locked = (!conference->locked ? 1 : 0);
-			res |= ast_stream_and_wait(bridge_channel->chan,
-				(conference->locked ?
-				conf_get_sound(CONF_SOUND_LOCKED_NOW, user->b_profile.sounds) :
-				conf_get_sound(CONF_SOUND_UNLOCKED_NOW, user->b_profile.sounds)),
-				"");
-
+			conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
+			res |= play_file(bridge_channel->chan,
+				(conference_bridge->locked ?
+				conf_get_sound(CONF_SOUND_LOCKED_NOW, conference_bridge_user->b_profile.sounds) :
+				conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)), 1) < 0;
 			break;
 		case MENU_ACTION_ADMIN_KICK_LAST:
-			res |= action_kick_last(conference, bridge_channel, user);
+			res |= action_kick_last(conference_bridge, conference_bridge_user);
 			break;
 		case MENU_ACTION_LEAVE:
-			pbx_builtin_setvar_helper(bridge_channel->chan, "CONFBRIDGE_RESULT", "DTMF");
-			ao2_lock(conference);
-			ast_bridge_remove(conference->bridge, bridge_channel->chan);
-			ast_test_suite_event_notify("CONF_MENU_LEAVE",
-				"Channel: %s",
-				ast_channel_name(bridge_channel->chan));
-			ao2_unlock(conference);
+			ao2_lock(conference_bridge);
+			ast_bridge_remove(conference_bridge->bridge, bridge_channel->chan);
+			ao2_unlock(conference_bridge);
 			break;
 		case MENU_ACTION_NOOP:
 			break;
 		case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
-			ao2_lock(conference);
-			ast_bridge_set_single_src_video_mode(conference->bridge, bridge_channel->chan);
-			ao2_unlock(conference);
+			ao2_lock(conference_bridge);
+			ast_bridge_set_single_src_video_mode(conference_bridge->bridge, bridge_channel->chan);
+			ao2_unlock(conference_bridge);
 			break;
 		case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
-			handle_video_on_exit(conference, bridge_channel->chan);
+			handle_video_on_exit(conference_bridge, bridge_channel->chan);
 			break;
 		}
 	}
@@ -2199,134 +2106,110 @@ static int execute_menu_entry(struct confbridge_conference *conference,
 }
 
 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
-	struct confbridge_user *user,
+	struct conference_bridge_user *conference_bridge_user,
 	struct conf_menu_entry *menu_entry,
 	struct conf_menu *menu)
 {
 	/* See if music on hold is playing */
-	conf_moh_suspend(user);
+	conf_moh_suspend(conference_bridge_user);
 
 	/* execute the list of actions associated with this menu entry */
-	execute_menu_entry(user->conference, user, bridge_channel, menu_entry, menu);
+	execute_menu_entry(conference_bridge_user->conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
 
 	/* See if music on hold needs to be started back up again */
-	conf_moh_unsuspend(user);
+	conf_moh_unsuspend(conference_bridge_user);
 
 	return 0;
 }
 
-static int kick_conference_participant(struct confbridge_conference *conference,
-	const char *channel)
+static int kick_conference_participant(struct conference_bridge *bridge, const char *channel)
 {
-	int res = -1;
-	int match;
-	struct confbridge_user *user = NULL;
-	int all = !strcasecmp("all", channel);
-	int participants = !strcasecmp("participants", channel);
-
-	SCOPED_AO2LOCK(bridge_lock, conference);
+	struct conference_bridge_user *participant = NULL;
 
-	AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-		if (user->kicked) {
-			continue;
-		}
-		match = !strcasecmp(channel, ast_channel_name(user->chan));
-		if (match || all
-				|| (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
-			user->kicked = 1;
-			pbx_builtin_setvar_helper(user->chan, "CONFBRIDGE_RESULT", "KICKED");
-			ast_bridge_remove(conference->bridge, user->chan);
-			res = 0;
-			if (match) {
-				return res;
-			}
+	ao2_lock(bridge);
+	AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+		if (!strcasecmp(ast_channel_name(participant->chan), channel) && !participant->kicked) {
+			participant->kicked = 1;
+			ast_bridge_remove(bridge->bridge, participant->chan);
+			ao2_unlock(bridge);
+			return 0;
 		}
 	}
-	AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
-		if (user->kicked) {
-			continue;
-		}
-		match = !strcasecmp(channel, ast_channel_name(user->chan));
-		if (match || all
-				|| (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
-			user->kicked = 1;
-			pbx_builtin_setvar_helper(user->chan, "CONFBRIDGE_RESULT", "KICKED");
-			ast_bridge_remove(conference->bridge, user->chan);
-			res = 0;
-			if (match) {
-				return res;
-			}
+	AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
+		if (!strcasecmp(ast_channel_name(participant->chan), channel) && !participant->kicked) {
+			participant->kicked = 1;
+			ast_bridge_remove(bridge->bridge, participant->chan);
+			ao2_unlock(bridge);
+			return 0;
 		}
 	}
+	ao2_unlock(bridge);
 
-	return res;
+	return -1;
 }
 
 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
 {
 	int which = 0;
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
 	char *res = NULL;
 	int wordlen = strlen(word);
-	struct ao2_iterator iter;
+	struct ao2_iterator i;
 
-	iter = ao2_iterator_init(conference_bridges, 0);
-	while ((conference = ao2_iterator_next(&iter))) {
-		if (!strncasecmp(conference->name, word, wordlen) && ++which > state) {
-			res = ast_strdup(conference->name);
-			ao2_ref(conference, -1);
+	i = ao2_iterator_init(conference_bridges, 0);
+	while ((bridge = ao2_iterator_next(&i))) {
+		if (!strncasecmp(bridge->name, word, wordlen) && ++which > state) {
+			res = ast_strdup(bridge->name);
+			ao2_ref(bridge, -1);
 			break;
 		}
-		ao2_ref(conference, -1);
+		ao2_ref(bridge, -1);
 	}
-	ao2_iterator_destroy(&iter);
+	ao2_iterator_destroy(&i);
 
 	return res;
 }
 
-static char *complete_confbridge_participant(const char *conference_name, const char *line, const char *word, int pos, int state)
+static char *complete_confbridge_participant(const char *bridge_name, const char *line, const char *word, int pos, int state)
 {
 	int which = 0;
-	RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
-	struct confbridge_user *user;
+	RAII_VAR(struct conference_bridge *, bridge, NULL, ao2_cleanup);
+	struct conference_bridge tmp;
+	struct conference_bridge_user *participant;
 	char *res = NULL;
 	int wordlen = strlen(word);
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, bridge_name, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		return NULL;
 	}
 
-	if (!strncasecmp("all", word, wordlen) && ++which > state) {
-		return ast_strdup("all");
-	}
-
-	if (!strncasecmp("participants", word, wordlen) && ++which > state) {
-		return ast_strdup("participants");
+	ao2_lock(bridge);
+	AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+		if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) {
+			res = ast_strdup(ast_channel_name(participant->chan));
+			ao2_unlock(bridge);
+			return res;
+		}
 	}
 
-	{
-		SCOPED_AO2LOCK(bridge_lock, conference);
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
-				res = ast_strdup(ast_channel_name(user->chan));
-				return res;
-			}
-		}
-		AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
-			if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
-				res = ast_strdup(ast_channel_name(user->chan));
-				return res;
-			}
+	AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
+		if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) {
+			res = ast_strdup(ast_channel_name(participant->chan));
+			ao2_unlock(bridge);
+			return res;
 		}
 	}
+	ao2_unlock(bridge);
 
 	return NULL;
 }
 
 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 	int not_found;
 
 	switch (cmd) {
@@ -2334,8 +2217,7 @@ static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct
 		e->command = "confbridge kick";
 		e->usage =
 			"Usage: confbridge kick <conference> <channel>\n"
-			"       Kicks a channel out of the conference bridge.\n"
-			"             (all to kick everyone, participants to kick non-admins).\n";
+			"       Kicks a channel out of the conference bridge.\n";
 		return NULL;
 	case CLI_GENERATE:
 		if (a->pos == 2) {
@@ -2351,82 +2233,47 @@ static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct
 		return CLI_SHOWUSAGE;
 	}
 
-	conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
 		return CLI_SUCCESS;
 	}
-	not_found = kick_conference_participant(conference, a->argv[3]);
-	ao2_ref(conference, -1);
+	not_found = kick_conference_participant(bridge, a->argv[3]);
+	ao2_ref(bridge, -1);
 	if (not_found) {
-		if (!strcasecmp("all", a->argv[3]) || !strcasecmp("participants", a->argv[3])) {
-			ast_cli(a->fd, "No participants found!\n");
-		} else {
-			ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]);
-		}
+		ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]);
 		return CLI_SUCCESS;
 	}
-	ast_cli(a->fd, "Kicked '%s' out of conference '%s'\n", a->argv[3], a->argv[2]);
+	ast_cli(a->fd, "Participant '%s' kicked out of conference '%s'\n", a->argv[3], a->argv[2]);
 	return CLI_SUCCESS;
 }
 
-static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct confbridge_user *user, int waiting)
+static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct conference_bridge_user *participant)
 {
-	char flag_str[6 + 1];/* Max flags + terminator */
-	int pos = 0;
-
-	/* Build flags column string. */
-	if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
-		flag_str[pos++] = 'A';
-	}
-	if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
-		flag_str[pos++] = 'M';
-	}
-	if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
-		flag_str[pos++] = 'W';
-	}
-	if (ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED)) {
-		flag_str[pos++] = 'E';
-	}
-	if (user->muted) {
-		flag_str[pos++] = 'm';
-	}
-	if (waiting) {
-		flag_str[pos++] = 'w';
-	}
-	flag_str[pos] = '\0';
-
-	ast_cli(a->fd, "%-30s %-6s %-16s %-16s %-16s %s\n",
-		ast_channel_name(user->chan),
-		flag_str,
-		user->u_profile.name,
-		user->b_profile.name,
-		user->menu_name,
-		S_COR(ast_channel_caller(user->chan)->id.number.valid,
-			ast_channel_caller(user->chan)->id.number.str, "<unknown>"));
+	ast_cli(a->fd, "%-30s %-16s %-16s %-16s %-16s %s\n",
+		ast_channel_name(participant->chan),
+		participant->u_profile.name,
+		participant->b_profile.name,
+		participant->menu_name,
+		S_COR(ast_channel_caller(participant->chan)->id.number.valid,
+			ast_channel_caller(participant->chan)->id.number.str, "<unknown>"),
+		AST_CLI_YESNO(participant->muted));
 }
 
 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct confbridge_conference *conference;
+	struct ao2_iterator i;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
+	struct conference_bridge_user *participant = NULL;
 
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "confbridge list";
 		e->usage =
 			"Usage: confbridge list [<name>]\n"
-			"       Lists all currently active conference bridges or a specific conference bridge.\n"
-			"\n"
-			"       When a conference bridge name is provided, flags may be shown for users. Below\n"
-			"       are the flags and what they represent.\n"
-			"\n"
-			"       Flags:\n"
-			"         A - The user is an admin\n"
-			"         M - The user is a marked user\n"
-			"         W - The user must wait for a marked user to join\n"
-			"         E - The user will be kicked after the last marked user leaves the conference\n"
-			"         m - The user is muted\n"
-			"         w - The user is waiting for a marked user to join\n";
+			"       Lists all currently active conference bridges.\n";
 		return NULL;
 	case CLI_GENERATE:
 		if (a->pos == 2) {
@@ -2436,38 +2283,35 @@ static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct
 	}
 
 	if (a->argc == 2) {
-		struct ao2_iterator iter;
-
 		ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
 		ast_cli(a->fd, "================================ ====== ====== ========\n");
-		iter = ao2_iterator_init(conference_bridges, 0);
-		while ((conference = ao2_iterator_next(&iter))) {
-			ast_cli(a->fd, "%-32s %6u %6u %s\n", conference->name, conference->activeusers + conference->waitingusers, conference->markedusers, (conference->locked ? "locked" : "unlocked"));
-			ao2_ref(conference, -1);
+		i = ao2_iterator_init(conference_bridges, 0);
+		while ((bridge = ao2_iterator_next(&i))) {
+			ast_cli(a->fd, "%-32s %6u %6u %s\n", bridge->name, bridge->activeusers + bridge->waitingusers, bridge->markedusers, (bridge->locked ? "locked" : "unlocked"));
+			ao2_ref(bridge, -1);
 		}
-		ao2_iterator_destroy(&iter);
+		ao2_iterator_destroy(&i);
 		return CLI_SUCCESS;
 	}
 
 	if (a->argc == 3) {
-		struct confbridge_user *user;
-
-		conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
-		if (!conference) {
+		ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
+		bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+		if (!bridge) {
 			ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
 			return CLI_SUCCESS;
 		}
-		ast_cli(a->fd, "Channel                        Flags  User Profile     Bridge Profile   Menu             CallerID\n");
-		ast_cli(a->fd, "============================== ====== ================ ================ ================ ================\n");
-		ao2_lock(conference);
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			handle_cli_confbridge_list_item(a, user, 0);
+		ast_cli(a->fd, "Channel                        User Profile     Bridge Profile   Menu             CallerID         Muted\n");
+		ast_cli(a->fd, "============================== ================ ================ ================ ================ =====\n");
+		ao2_lock(bridge);
+		AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+			handle_cli_confbridge_list_item(a, participant);
 		}
-		AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
-			handle_cli_confbridge_list_item(a, user, 1);
+		AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
+			handle_cli_confbridge_list_item(a, participant);
 		}
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(bridge);
+		ao2_ref(bridge, -1);
 		return CLI_SUCCESS;
 	}
 
@@ -2480,97 +2324,76 @@ static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct
  * \retval 0 success
  * \retval -1 conference not found
  */
-static int generic_lock_unlock_helper(int lock, const char *conference_name)
+static int generic_lock_unlock_helper(int lock, const char *conference)
 {
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 	int res = 0;
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		return -1;
 	}
-	ao2_lock(conference);
-	conference->locked = lock;
-	ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", conference->locked ? "locked" : "unlocked", conference->b_profile.name);
-	ao2_unlock(conference);
-	ao2_ref(conference, -1);
+	ao2_lock(bridge);
+	bridge->locked = lock;
+	ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", bridge->locked ? "locked" : "unlocked", bridge->b_profile.name);
+	ao2_unlock(bridge);
+	ao2_ref(bridge, -1);
 
 	return res;
 }
 
 /* \internal
- * \brief Mute/unmute a single user.
- */
-static void generic_mute_unmute_user(struct confbridge_conference *conference, struct confbridge_user *user, int mute)
-{
-	/* Set user level mute request. */
-	user->muted = mute ? 1 : 0;
-
-	conf_update_user_mute(user);
-	ast_test_suite_event_notify("CONF_MUTE",
-		"Message: participant %s %s\r\n"
-		"Conference: %s\r\n"
-		"Channel: %s",
-		ast_channel_name(user->chan),
-		mute ? "muted" : "unmuted",
-		conference->b_profile.name,
-		ast_channel_name(user->chan));
-	if (mute) {
-		send_mute_event(user, conference);
-	} else {
-		send_unmute_event(user, conference);
-	}
-}
-
-/* \internal
  * \brief finds a conference user by channel name and mutes/unmutes them.
  *
  * \retval 0 success
  * \retval -1 conference not found
  * \retval -2 user not found
  */
-static int generic_mute_unmute_helper(int mute, const char *conference_name,
-	const char *chan_name)
+static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
 {
-	RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
-	struct confbridge_user *user;
-	int all = !strcasecmp("all", chan_name);
-	int participants = !strcasecmp("participants", chan_name);
-	int res = -2;
-
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
+	struct conference_bridge_user *participant = NULL;
+	int res = 0;
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		return -1;
 	}
-
-	{
-		SCOPED_AO2LOCK(bridge_lock, conference);
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			int match = !strncasecmp(chan_name, ast_channel_name(user->chan),
-				strlen(chan_name));
-			if (match || all
-				|| (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
-				generic_mute_unmute_user(conference, user, mute);
-				res = 0;
-				if (match) {
-					return res;
-				}
-			}
+	ao2_lock(bridge);
+	AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+		if (!strncmp(user, ast_channel_name(participant->chan), strlen(user))) {
+			break;
 		}
-
-		AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
-			int match = !strncasecmp(chan_name, ast_channel_name(user->chan),
-				strlen(chan_name));
-			if (match || all
-				|| (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
-				generic_mute_unmute_user(conference, user, mute);
-				res = 0;
-				if (match) {
-					return res;
-				}
+	}
+	if (!participant) {
+		/* user is not in the active list so check the waiting list as well */
+		AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
+			if (!strncmp(user, ast_channel_name(participant->chan), strlen(user))) {
+				break;
 			}
 		}
 	}
+	if (participant) {
+		/* Set user level mute request. */
+		participant->muted = mute ? 1 : 0;
+
+		conf_update_user_mute(participant);
+		ast_test_suite_event_notify("CONF_MUTE",
+			"Message: participant %s %s\r\n"
+			"Conference: %s\r\n"
+			"Channel: %s",
+			ast_channel_name(participant->chan),
+			mute ? "muted" : "unmuted",
+			bridge->b_profile.name,
+			ast_channel_name(participant->chan));
+	} else {
+		res = -2;;
+	}
+	ao2_unlock(bridge);
+	ao2_ref(bridge, -1);
 
 	return res;
 }
@@ -2583,11 +2406,7 @@ static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
 		ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
 		return -1;
 	} else if (res == -2) {
-		if (!strcasecmp("all", a->argv[3]) || !strcasecmp("participants", a->argv[3])) {
-			ast_cli(a->fd, "No participants found in conference %s\n", a->argv[2]);
-		} else {
-			ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
-		}
+		ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
 		return -1;
 	}
 	ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
@@ -2602,7 +2421,6 @@ static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct
 		e->usage =
 			"Usage: confbridge mute <conference> <channel>\n"
 			"       Mute a channel in a conference.\n"
-			"              (all to mute everyone, participants to mute non-admins)\n"
 			"       If the specified channel is a prefix,\n"
 			"       the action will be taken on the first\n"
 			"       matching channel.\n";
@@ -2633,7 +2451,6 @@ static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, stru
 		e->usage =
 			"Usage: confbridge unmute <conference> <channel>\n"
 			"       Unmute a channel in a conference.\n"
-			"              (all to unmute everyone, participants to unmute non-admins)\n"
 			"       If the specified channel is a prefix,\n"
 			"       the action will be taken on the first\n"
 			"       matching channel.\n";
@@ -2712,7 +2529,8 @@ static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, stru
 static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	const char *rec_file = NULL;
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2737,38 +2555,40 @@ static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd
 		rec_file = a->argv[4];
 	}
 
-	conference = ao2_find(conference_bridges, a->argv[3], OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		ast_cli(a->fd, "Conference not found.\n");
 		return CLI_FAILURE;
 	}
-	ao2_lock(conference);
-	if (conf_is_recording(conference)) {
+	ao2_lock(bridge);
+	if (conf_is_recording(bridge)) {
 		ast_cli(a->fd, "Conference is already being recorded.\n");
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(bridge);
+		ao2_ref(bridge, -1);
 		return CLI_SUCCESS;
 	}
 	if (!ast_strlen_zero(rec_file)) {
-		ast_copy_string(conference->b_profile.rec_file, rec_file, sizeof(conference->b_profile.rec_file));
+		ast_copy_string(bridge->b_profile.rec_file, rec_file, sizeof(bridge->b_profile.rec_file));
 	}
 
-	if (start_conf_record_thread(conference)) {
+	if (conf_start_record(bridge)) {
 		ast_cli(a->fd, "Could not start recording due to internal error.\n");
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(bridge);
+		ao2_ref(bridge, -1);
 		return CLI_FAILURE;
 	}
-	ao2_unlock(conference);
+	ao2_unlock(bridge);
 
 	ast_cli(a->fd, "Recording started\n");
-	ao2_ref(conference, -1);
+	ao2_ref(bridge, -1);
 	return CLI_SUCCESS;
 }
 
 static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 	int ret;
 
 	switch (cmd) {
@@ -2788,24 +2608,25 @@ static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd,
 		return CLI_SHOWUSAGE;
 	}
 
-	conference = ao2_find(conference_bridges, a->argv[3], OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		ast_cli(a->fd, "Conference not found.\n");
 		return CLI_SUCCESS;
 	}
-	ao2_lock(conference);
-	ret = conf_stop_record(conference);
-	ao2_unlock(conference);
+	ao2_lock(bridge);
+	ret = conf_stop_record(bridge);
+	ao2_unlock(bridge);
 	ast_cli(a->fd, "Recording %sstopped.\n", ret ? "could not be " : "");
-	ao2_ref(conference, -1);
+	ao2_ref(bridge, -1);
 	return CLI_SUCCESS;
 }
 
 static struct ast_cli_entry cli_confbridge[] = {
 	AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
 	AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
-	AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute participants."),
-	AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute participants."),
+	AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
+	AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
 	AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
 	AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
 	AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
@@ -2822,7 +2643,7 @@ static struct ast_custom_function confbridge_info_function = {
 	.read = func_confbridge_info,
 };
 
-static void action_confbridgelist_item(struct mansession *s, const char *id_text, struct confbridge_conference *conference, struct confbridge_user *user, int waiting)
+static void action_confbridgelist_item(struct mansession *s, const char *id_text, struct conference_bridge *bridge, struct conference_bridge_user *participant)
 {
 	astman_append(s,
 		"Event: ConfbridgeList\r\n"
@@ -2833,40 +2654,32 @@ static void action_confbridgelist_item(struct mansession *s, const char *id_text
 		"Channel: %s\r\n"
 		"Admin: %s\r\n"
 		"MarkedUser: %s\r\n"
-		"WaitMarked: %s\r\n"
-		"EndMarked: %s\r\n"
-		"Waiting: %s\r\n"
 		"Muted: %s\r\n"
-		"AnsweredTime: %d\r\n"
 		"\r\n",
 		id_text,
-		conference->name,
-		S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
-		S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
-		ast_channel_name(user->chan),
-		ast_test_flag(&user->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
-		ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No",
-		ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED) ? "Yes" : "No",
-		ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED) ? "Yes" : "No",
-		waiting ? "Yes" : "No",
-		user->muted ? "Yes" : "No",
-		ast_channel_get_up_time(user->chan));
+		bridge->name,
+		S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(participant->chan)->id.name.valid, ast_channel_caller(participant->chan)->id.name.str, "<no name>"),
+		ast_channel_name(participant->chan),
+		ast_test_flag(&participant->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
+		ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No",
+		participant->muted ? "Yes" : "No");
 }
 
 static int action_confbridgelist(struct mansession *s, const struct message *m)
 {
 	const char *actionid = astman_get_header(m, "ActionID");
-	const char *conference_name = astman_get_header(m, "Conference");
-	struct confbridge_user *user;
-	struct confbridge_conference *conference;
-	char id_text[80];
+	const char *conference = astman_get_header(m, "Conference");
+	struct conference_bridge_user *participant = NULL;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
+	char id_text[80] = "";
 	int total = 0;
 
-	id_text[0] = '\0';
 	if (!ast_strlen_zero(actionid)) {
 		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
 	}
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -2874,25 +2687,26 @@ static int action_confbridgelist(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "No active conferences.");
 		return 0;
 	}
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
 
 	astman_send_listack(s, m, "Confbridge user list will follow", "start");
 
-	ao2_lock(conference);
-	AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+	ao2_lock(bridge);
+	AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
 		total++;
-		action_confbridgelist_item(s, id_text, conference, user, 0);
+		action_confbridgelist_item(s, id_text, bridge, participant);
 	}
-	AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
+	AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
 		total++;
-		action_confbridgelist_item(s, id_text, conference, user, 1);
+		action_confbridgelist_item(s, id_text, bridge, participant);
 	}
-	ao2_unlock(conference);
-	ao2_ref(conference, -1);
+	ao2_unlock(bridge);
+	ao2_ref(bridge, -1);
 
 	astman_append(s,
 	"Event: ConfbridgeListComplete\r\n"
@@ -2907,8 +2721,8 @@ static int action_confbridgelist(struct mansession *s, const struct message *m)
 static int action_confbridgelistrooms(struct mansession *s, const struct message *m)
 {
 	const char *actionid = astman_get_header(m, "ActionID");
-	struct confbridge_conference *conference;
-	struct ao2_iterator iter;
+	struct conference_bridge *bridge = NULL;
+	struct ao2_iterator i;
 	char id_text[512] = "";
 	int totalitems = 0;
 
@@ -2924,11 +2738,11 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message
 	astman_send_listack(s, m, "Confbridge conferences will follow", "start");
 
 	/* Traverse the conference list */
-	iter = ao2_iterator_init(conference_bridges, 0);
-	while ((conference = ao2_iterator_next(&iter))) {
+	i = ao2_iterator_init(conference_bridges, 0);
+	while ((bridge = ao2_iterator_next(&i))) {
 		totalitems++;
 
-		ao2_lock(conference);
+		ao2_lock(bridge);
 		astman_append(s,
 		"Event: ConfbridgeListRooms\r\n"
 		"%s"
@@ -2938,15 +2752,15 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message
 		"Locked: %s\r\n"
 		"\r\n",
 		id_text,
-		conference->name,
-		conference->activeusers + conference->waitingusers,
-		conference->markedusers,
-		conference->locked ? "Yes" : "No");
-		ao2_unlock(conference);
+		bridge->name,
+		bridge->activeusers + bridge->waitingusers,
+		bridge->markedusers,
+		bridge->locked ? "Yes" : "No"); 
+		ao2_unlock(bridge);
 
-		ao2_ref(conference, -1);
+		ao2_ref(bridge, -1);
 	}
-	ao2_iterator_destroy(&iter);
+	ao2_iterator_destroy(&i);
 
 	/* Send final confirmation */
 	astman_append(s,
@@ -2960,15 +2774,15 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message
 
 static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
-	const char *channel_name = astman_get_header(m, "Channel");
+	const char *conference = astman_get_header(m, "Conference");
+	const char *channel = astman_get_header(m, "Channel");
 	int res = 0;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
-	if (ast_strlen_zero(channel_name)) {
+	if (ast_strlen_zero(channel)) {
 		astman_send_error(s, m, "No channel name provided.");
 		return 0;
 	}
@@ -2977,7 +2791,7 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
 		return 0;
 	}
 
-	res = generic_mute_unmute_helper(mute, conference_name, channel_name);
+	res = generic_mute_unmute_helper(mute, conference, channel);
 
 	if (res == -1) {
 		astman_send_error(s, m, "No Conference by that name found.");
@@ -3002,10 +2816,10 @@ static int action_confbridgemute(struct mansession *s, const struct message *m)
 
 static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
+	const char *conference = astman_get_header(m, "Conference");
 	int res = 0;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -3013,7 +2827,7 @@ static int action_lock_unlock_helper(struct mansession *s, const struct message
 		astman_send_error(s, m, "No active conferences.");
 		return 0;
 	}
-	if ((res = generic_lock_unlock_helper(lock, conference_name))) {
+	if ((res = generic_lock_unlock_helper(lock, conference))) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
@@ -3031,12 +2845,13 @@ static int action_confbridgelock(struct mansession *s, const struct message *m)
 
 static int action_confbridgekick(struct mansession *s, const struct message *m)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
+	const char *conference = astman_get_header(m, "Conference");
 	const char *channel = astman_get_header(m, "Channel");
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 	int found;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -3045,17 +2860,18 @@ static int action_confbridgekick(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
 
-	found = !kick_conference_participant(conference, channel);
-	ao2_ref(conference, -1);
+	found = !kick_conference_participant(bridge, channel);
+	ao2_ref(bridge, -1);
 
 	if (found) {
-		astman_send_ack(s, m, !strcmp("all", channel) ? "All participants kicked" : "User kicked");
+		astman_send_ack(s, m, "User kicked");
 	} else {
 		astman_send_error(s, m, "No Channel by that name found in Conference.");
 	}
@@ -3064,11 +2880,12 @@ static int action_confbridgekick(struct mansession *s, const struct message *m)
 
 static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
+	const char *conference = astman_get_header(m, "Conference");
 	const char *recordfile = astman_get_header(m, "RecordFile");
-	struct confbridge_conference *conference;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -3077,42 +2894,44 @@ static int action_confbridgestartrecord(struct mansession *s, const struct messa
 		return 0;
 	}
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
 
-	ao2_lock(conference);
-	if (conf_is_recording(conference)) {
+	ao2_lock(bridge);
+	if (conf_is_recording(bridge)) {
 		astman_send_error(s, m, "Conference is already being recorded.");
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(bridge);
+		ao2_ref(bridge, -1);
 		return 0;
 	}
 
 	if (!ast_strlen_zero(recordfile)) {
-		ast_copy_string(conference->b_profile.rec_file, recordfile, sizeof(conference->b_profile.rec_file));
+		ast_copy_string(bridge->b_profile.rec_file, recordfile, sizeof(bridge->b_profile.rec_file));
 	}
 
-	if (start_conf_record_thread(conference)) {
+	if (conf_start_record(bridge)) {
 		astman_send_error(s, m, "Internal error starting conference recording.");
-		ao2_unlock(conference);
-		ao2_ref(conference, -1);
+		ao2_unlock(bridge);
+		ao2_ref(bridge, -1);
 		return 0;
 	}
-	ao2_unlock(conference);
+	ao2_unlock(bridge);
 
-	ao2_ref(conference, -1);
+	ao2_ref(bridge, -1);
 	astman_send_ack(s, m, "Conference Recording Started.");
 	return 0;
 }
 static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
-	struct confbridge_conference *conference;
+	const char *conference = astman_get_header(m, "Conference");
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -3121,34 +2940,36 @@ static int action_confbridgestoprecord(struct mansession *s, const struct messag
 		return 0;
 	}
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
 
-	ao2_lock(conference);
-	if (conf_stop_record(conference)) {
-		ao2_unlock(conference);
+	ao2_lock(bridge);
+	if (conf_stop_record(bridge)) {
+		ao2_unlock(bridge);
 		astman_send_error(s, m, "Internal error while stopping recording.");
-		ao2_ref(conference, -1);
+		ao2_ref(bridge, -1);
 		return 0;
 	}
-	ao2_unlock(conference);
+	ao2_unlock(bridge);
 
-	ao2_ref(conference, -1);
+	ao2_ref(bridge, -1);
 	astman_send_ack(s, m, "Conference Recording Stopped.");
 	return 0;
 }
 
 static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
 {
-	const char *conference_name = astman_get_header(m, "Conference");
+	const char *conference = astman_get_header(m, "Conference");
 	const char *channel = astman_get_header(m, "Channel");
-	struct confbridge_user *user;
-	struct confbridge_conference *conference;
+	struct conference_bridge_user *participant = NULL;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge tmp;
 
-	if (ast_strlen_zero(conference_name)) {
+	if (ast_strlen_zero(conference)) {
 		astman_send_error(s, m, "No Conference name provided.");
 		return 0;
 	}
@@ -3161,26 +2982,27 @@ static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct
 		return 0;
 	}
 
-	conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
-	if (!conference) {
+	ast_copy_string(tmp.name, conference, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		astman_send_error(s, m, "No Conference by that name found.");
 		return 0;
 	}
 
 	/* find channel and set as video src. */
-	ao2_lock(conference);
-	AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-		if (!strncmp(channel, ast_channel_name(user->chan), strlen(channel))) {
-			ast_bridge_set_single_src_video_mode(conference->bridge, user->chan);
+	ao2_lock(bridge);
+	AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+		if (!strncmp(channel, ast_channel_name(participant->chan), strlen(channel))) {
+			ast_bridge_set_single_src_video_mode(bridge->bridge, participant->chan);
 			break;
 		}
 	}
-	ao2_unlock(conference);
-	ao2_ref(conference, -1);
+	ao2_unlock(bridge);
+	ao2_ref(bridge, -1);
 
-	/* do not access user after conference unlock.  We are just
+	/* do not access participant after bridge unlock.  We are just
 	 * using this check to see if it was found or not */
-	if (!user) {
+	if (!participant) {
 		astman_send_error(s, m, "No channel by that name found in conference.");
 		return 0;
 	}
@@ -3190,9 +3012,10 @@ static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct
 
 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
-	char *parse;
-	struct confbridge_conference *conference;
-	struct confbridge_user *user;
+	char *parse = NULL;
+	struct conference_bridge *bridge = NULL;
+	struct conference_bridge_user *participant = NULL;
+	struct conference_bridge tmp;
 	int count = 0;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(type);
@@ -3208,180 +3031,132 @@ static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char
 	if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
 		return -1;
 	}
-	conference = ao2_find(conference_bridges, args.confno, OBJ_KEY);
-	if (!conference) {
+	if (!ao2_container_count(conference_bridges)) {
+		snprintf(buf, len, "0");
+		return 0;
+	}
+	ast_copy_string(tmp.name, args.confno, sizeof(tmp.name));
+	bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
+	if (!bridge) {
 		snprintf(buf, len, "0");
 		return 0;
 	}
 
 	/* get the correct count for the type requested */
-	ao2_lock(conference);
+	ao2_lock(bridge);
 	if (!strncasecmp(args.type, "parties", 7)) {
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+		AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
 			count++;
 		}
-		AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
+		AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
 			count++;
 		}
 	} else if (!strncasecmp(args.type, "admins", 6)) {
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
+		AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+			if (ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
 				count++;
 			}
 		}
 	} else if (!strncasecmp(args.type, "marked", 6)) {
-		AST_LIST_TRAVERSE(&conference->active_list, user, list) {
-			if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
+		AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
+			if (ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER)) {
 				count++;
 			}
 		}
 	} else if (!strncasecmp(args.type, "locked", 6)) {
-		count = conference->locked;
+		count = bridge->locked;
 	} else {
 		ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.  Should be one of: "
 			"parties, admins, marked, or locked.\n", args.type);
 	}
 	snprintf(buf, len, "%d", count);
-	ao2_unlock(conference);
-	ao2_ref(conference, -1);
+	ao2_unlock(bridge);
+	ao2_ref(bridge, -1);
 	return 0;
 }
 
-void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
+void conf_add_user_active(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
-	conference->activeusers++;
+	AST_LIST_INSERT_TAIL(&conference_bridge->active_list, cbu, list);
+	conference_bridge->activeusers++;
 }
 
-void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
+void conf_add_user_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
-	conference->activeusers++;
-	conference->markedusers++;
+	AST_LIST_INSERT_TAIL(&conference_bridge->active_list, cbu, list);
+	conference_bridge->activeusers++;
+	conference_bridge->markedusers++;
 }
 
-void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
+void conf_add_user_waiting(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	AST_LIST_INSERT_TAIL(&conference->waiting_list, user, list);
-	conference->waitingusers++;
+	AST_LIST_INSERT_TAIL(&conference_bridge->waiting_list, cbu, list);
+	conference_bridge->waitingusers++;
 }
 
-void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
+void conf_remove_user_active(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	AST_LIST_REMOVE(&conference->active_list, user, list);
-	conference->activeusers--;
+	AST_LIST_REMOVE(&conference_bridge->active_list, cbu, list);
+	conference_bridge->activeusers--;
 }
 
-void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
+void conf_remove_user_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	AST_LIST_REMOVE(&conference->active_list, user, list);
-	conference->activeusers--;
-	conference->markedusers--;
+	AST_LIST_REMOVE(&conference_bridge->active_list, cbu, list);
+	conference_bridge->activeusers--;
+	conference_bridge->markedusers--;
 }
 
-void conf_mute_only_active(struct confbridge_conference *conference)
+void conf_mute_only_active(struct conference_bridge *conference_bridge)
 {
-	struct confbridge_user *only_user = AST_LIST_FIRST(&conference->active_list);
+	struct conference_bridge_user *only_participant = AST_LIST_FIRST(&conference_bridge->active_list);
 
 	/* Turn on MOH if the single participant is set up for it */
-	if (ast_test_flag(&only_user->u_profile, USER_OPT_MUSICONHOLD)) {
-		conf_moh_start(only_user);
+	if (ast_test_flag(&only_participant->u_profile, USER_OPT_MUSICONHOLD)) {
+		conf_moh_start(only_participant);
 	}
-	conf_update_user_mute(only_user);
-}
-
-void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
-{
-	AST_LIST_REMOVE(&conference->waiting_list, user, list);
-	conference->waitingusers--;
-}
-
-/*!
- * \internal
- * \brief Unregister a ConfBridge channel technology.
- * \since 12.0.0
- *
- * \param tech What to unregister.
- *
- * \return Nothing
- */
-static void unregister_channel_tech(struct ast_channel_tech *tech)
-{
-	ast_channel_unregister(tech);
-	ao2_cleanup(tech->capabilities);
+	conf_update_user_mute(only_participant);
 }
 
-/*!
- * \internal
- * \brief Register a ConfBridge channel technology.
- * \since 12.0.0
- *
- * \param tech What to register.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int register_channel_tech(struct ast_channel_tech *tech)
+void conf_remove_user_waiting(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu)
 {
-	tech->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!tech->capabilities) {
-		return -1;
-	}
-	ast_format_cap_append_by_type(tech->capabilities, AST_MEDIA_TYPE_UNKNOWN);
-	if (ast_channel_register(tech)) {
-		ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n",
-			tech->type, tech->description);
-		return -1;
-	}
-	return 0;
+	AST_LIST_REMOVE(&conference_bridge->waiting_list, cbu, list);
+	conference_bridge->waitingusers--;
 }
 
 /*! \brief Called when module is being unloaded */
 static int unload_module(void)
 {
-	ast_unregister_application(app);
+	int res = ast_unregister_application(app);
 
 	ast_custom_function_unregister(&confbridge_function);
 	ast_custom_function_unregister(&confbridge_info_function);
 
-	ast_cli_unregister_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
-
-	ast_manager_unregister("ConfbridgeList");
-	ast_manager_unregister("ConfbridgeListRooms");
-	ast_manager_unregister("ConfbridgeMute");
-	ast_manager_unregister("ConfbridgeUnmute");
-	ast_manager_unregister("ConfbridgeKick");
-	ast_manager_unregister("ConfbridgeUnlock");
-	ast_manager_unregister("ConfbridgeLock");
-	ast_manager_unregister("ConfbridgeStartRecord");
-	ast_manager_unregister("ConfbridgeStopRecord");
-	ast_manager_unregister("ConfbridgeSetSingleVideoSrc");
-
-	/* Unsubscribe from stasis confbridge message type and clean it up. */
-	manager_confbridge_shutdown();
+	ast_cli_unregister_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
 
 	/* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
-	ao2_cleanup(conference_bridges);
-	conference_bridges = NULL;
+	ao2_ref(conference_bridges, -1);
 
 	conf_destroy_config();
 
-	unregister_channel_tech(conf_announce_get_tech());
-	unregister_channel_tech(conf_record_get_tech());
+	ast_channel_unregister(&record_tech);
+	record_tech.capabilities = ast_format_cap_destroy(record_tech.capabilities);
 
-	return 0;
+	res |= ast_manager_unregister("ConfbridgeList");
+	res |= ast_manager_unregister("ConfbridgeListRooms");
+	res |= ast_manager_unregister("ConfbridgeMute");
+	res |= ast_manager_unregister("ConfbridgeUnmute");
+	res |= ast_manager_unregister("ConfbridgeKick");
+	res |= ast_manager_unregister("ConfbridgeUnlock");
+	res |= ast_manager_unregister("ConfbridgeLock");
+	res |= ast_manager_unregister("ConfbridgeStartRecord");
+	res |= ast_manager_unregister("ConfbridgeStopRecord");
+	res |= ast_manager_unregister("ConfbridgeSetSingleVideoSrc");
+
+	return res;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief Called when module is being loaded */
 static int load_module(void)
 {
 	int res = 0;
@@ -3390,31 +3165,30 @@ static int load_module(void)
 		ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
 		return AST_MODULE_LOAD_DECLINE;
 	}
-
-	if (register_channel_tech(conf_record_get_tech())
-		|| register_channel_tech(conf_announce_get_tech())) {
-		unload_module();
+	if ((ast_custom_function_register_escalating(&confbridge_function, AST_CFE_WRITE))) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	if ((ast_custom_function_register(&confbridge_info_function))) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	if (!(record_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_format_cap_add_all(record_tech.capabilities);
+	if (ast_channel_register(&record_tech)) {
+		ast_log(LOG_ERROR, "Unable to register ConfBridge recorder.\n");
 		return AST_MODULE_LOAD_FAILURE;
 	}
-
 	/* Create a container to hold the conference bridges */
-	conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS,
-		conference_bridge_hash_cb, conference_bridge_cmp_cb);
-	if (!conference_bridges) {
-		unload_module();
+	if (!(conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS, conference_bridge_hash_cb, conference_bridge_cmp_cb))) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	if (ast_register_application_xml(app, confbridge_exec)) {
+		ao2_ref(conference_bridges, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	/* Setup manager stasis subscriptions */
-	res |= manager_confbridge_init();
-
-	res |= ast_register_application_xml(app, confbridge_exec);
-
-	res |= ast_custom_function_register_escalating(&confbridge_function, AST_CFE_WRITE);
-	res |= ast_custom_function_register(&confbridge_info_function);
-
-	res |= ast_cli_register_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
-
+	res |= ast_cli_register_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
 	res |= ast_manager_register_xml("ConfbridgeList", EVENT_FLAG_REPORTING, action_confbridgelist);
 	res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
 	res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
@@ -3426,7 +3200,6 @@ static int load_module(void)
 	res |= ast_manager_register_xml("ConfbridgeStopRecord", EVENT_FLAG_CALL, action_confbridgestoprecord);
 	res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc);
 	if (res) {
-		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -3439,7 +3212,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Conference Bridge Application",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/apps/app_controlplayback.c b/apps/app_controlplayback.c
index 09815a7..1e2e6fb 100644
--- a/apps/app_controlplayback.c
+++ b/apps/app_controlplayback.c
@@ -31,14 +31,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 379830 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/app.h"
 #include "asterisk/module.h"
-#include "asterisk/manager.h"
-#include "asterisk/utils.h"
-#include "asterisk/astobj2.h"
 
 /*** DOCUMENTATION
 	<application name="ControlPlayback" language="en_US">
@@ -85,7 +82,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 379830 $")
 					<para>Contains the status of the attempt as a text string</para>
 					<value name="SUCCESS" />
 					<value name="USERSTOPPED" />
-					<value name="REMOTESTOPPED" />
 					<value name="ERROR" />
 				</variable>
 				<variable name="CPLAYBACKOFFSET">
@@ -99,69 +95,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 379830 $")
 			</variablelist>
 		</description>
 	</application>
-	<manager name="ControlPlayback" language="en_US">
-		<synopsis>
-			Control the playback of a file being played to a channel.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Channel" required="true">
-				<para>The name of the channel that currently has a file being played back to it.</para>
-			</parameter>
-			<parameter name="Control" required="true">
-				<enumlist>
-					<enum  name="stop">
-						<para>Stop the playback operation.</para>
-					</enum>
-					<enum name="forward">
-						<para>Move the current position in the media forward. The amount
-						of time that the stream moves forward is determined by the
-						<replaceable>skipms</replaceable> value passed to the application
-						that initiated the playback.</para>
-						<note>
-							<para>The default skipms value is <literal>3000</literal> ms.</para>
-						</note>
-					</enum>
-					<enum name="reverse">
-						<para>Move the current position in the media backward. The amount
-						of time that the stream moves backward is determined by the
-						<replaceable>skipms</replaceable> value passed to the application
-						that initiated the playback.</para>
-						<note>
-							<para>The default skipms value is <literal>3000</literal> ms.</para>
-						</note>
-					</enum>
-					<enum name="pause">
-						<para>Pause/unpause the playback operation, if supported.
-						If not supported, stop the playback.</para>
-					</enum>
-					<enum name="restart">
-						<para>Restart the playback operation, if supported.
-						If not supported, stop the playback.</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Control the operation of a media file being played back to a channel.
-			Note that this AMI action does not initiate playback of media to channel, but
-			rather controls the operation of a media operation that was already initiated
-			on the channel.</para>
-			<note>
-				<para>The <literal>pause</literal> and <literal>restart</literal>
-				<replaceable>Control</replaceable> options will stop a playback
-				operation if that operation was not initiated from the
-				<replaceable>ControlPlayback</replaceable> application or the
-				<replaceable>control stream file</replaceable> AGI command.</para>
-			</note>
-		</description>
-		<see-also>
-			<ref type="application">Playback</ref>
-			<ref type="application">ControlPlayback</ref>
-			<ref type="agi">stream file</ref>
-			<ref type="agi">control stream file</ref>
-		</see-also>
-	</manager>
  ***/
 static const char app[] = "ControlPlayback";
 
@@ -268,9 +201,6 @@ static int controlplayback_exec(struct ast_channel *chan, const char *data)
 		snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
 		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
 		res = 0;
-	} else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
-		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
-		res = 0;
 	} else {
 		if (res < 0) {
 			res = 0;
@@ -285,67 +215,16 @@ static int controlplayback_exec(struct ast_channel *chan, const char *data)
 	return res;
 }
 
-static int controlplayback_manager(struct mansession *s, const struct message *m)
-{
-	const char *channel_name = astman_get_header(m, "Channel");
-	const char *control_type = astman_get_header(m, "Control");
-	struct ast_channel *chan;
-
-	if (ast_strlen_zero(channel_name)) {
-		astman_send_error(s, m, "Channel not specified");
-		return 0;
-	}
-
-	if (ast_strlen_zero(control_type)) {
-		astman_send_error(s, m, "Control not specified");
-		return 0;
-	}
-
-	chan = ast_channel_get_by_name(channel_name);
-	if (!chan) {
-		astman_send_error(s, m, "No such channel");
-		return 0;
-	}
-
-	if (!strcasecmp(control_type, "stop")) {
-		ast_queue_control(chan, AST_CONTROL_STREAM_STOP);
-	} else if (!strcasecmp(control_type, "forward")) {
-		ast_queue_control(chan, AST_CONTROL_STREAM_FORWARD);
-	} else if (!strcasecmp(control_type, "reverse")) {
-		ast_queue_control(chan, AST_CONTROL_STREAM_REVERSE);
-	} else if (!strcasecmp(control_type, "pause")) {
-		ast_queue_control(chan, AST_CONTROL_STREAM_SUSPEND);
-	} else if (!strcasecmp(control_type, "restart")) {
-		ast_queue_control(chan, AST_CONTROL_STREAM_RESTART);
-	} else {
-		astman_send_error(s, m, "Unknown control type");
-		chan = ast_channel_unref(chan);
-		return 0;
-	}
-
-	chan = ast_channel_unref(chan);
-	astman_send_ack(s, m, NULL);
-	return 0;
-}
-
 static int unload_module(void)
 {
-	int res = 0;
-
-	res |= ast_unregister_application(app);
-	res |= ast_manager_unregister("ControlPlayback");
-
+	int res;
+	res = ast_unregister_application(app);
 	return res;
 }
 
 static int load_module(void)
 {
-	int res = 0;
-
-	res |= ast_register_application_xml(app, controlplayback_exec);
-	res |= ast_manager_register_xml("ControlPlayback", EVENT_FLAG_CALL, controlplayback_manager);
-
-	return res;
+	return ast_register_application_xml(app, controlplayback_exec);
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application");
diff --git a/apps/app_dahdibarge.c b/apps/app_dahdibarge.c
new file mode 100644
index 0000000..cc05a63
--- /dev/null
+++ b/apps/app_dahdibarge.c
@@ -0,0 +1,311 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * Special thanks to comphealth.com for sponsoring this
+ * GPL application.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief DAHDI Barge support
+ *
+ * \author Mark Spencer <markster at digium.com>
+ *
+ * \note Special thanks to comphealth.com for sponsoring this
+ * GPL application.
+ * 
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+	<depend>dahdi</depend>
+	<defaultenabled>no</defaultenabled>
+	<support_level>deprecated</support_level>
+	<replacement>app_chanspy</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <dahdi/user.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/config.h"
+#include "asterisk/app.h"
+#include "asterisk/cli.h"
+#include "asterisk/say.h"
+#include "asterisk/utils.h"
+
+/*** DOCUMENTATION
+	<application name="DAHDIBarge" language="en_US">
+		<synopsis>
+			Barge in (monitor) DAHDI channel.
+		</synopsis>
+		<syntax>
+			<parameter name="channel">
+				<para>Channel to barge.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts
+			if one is not specified. Returns <literal>-1</literal> when caller user hangs
+			up and is independent of the state of the channel being monitored.
+			</para>
+		</description>
+	</application>
+ ***/
+static const char app[] = "DAHDIBarge";
+
+#define CONF_SIZE 160
+
+static int careful_write(int fd, unsigned char *data, int len)
+{
+	int res;
+	while(len) {
+		res = write(fd, data, len);
+		if (res < 1) {
+			if (errno != EAGAIN) {
+				ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
+				return -1;
+			} else
+				return 0;
+		}
+		len -= res;
+		data += res;
+	}
+	return 0;
+}
+
+static int conf_run(struct ast_channel *chan, int confno, int confflags)
+{
+	int fd;
+	struct dahdi_confinfo dahdic;
+	struct ast_frame *f;
+	struct ast_channel *c;
+	struct ast_frame fr;
+	int outfd;
+	int ms;
+	int nfds;
+	int res;
+	int flags;
+	int retrydahdi;
+	int origfd;
+	int ret = -1;
+
+	struct dahdi_bufferinfo bi;
+	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
+	char *buf = __buf + AST_FRIENDLY_OFFSET;
+
+	/* Set it into U-law mode (write) */
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
+		ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", ast_channel_name(chan));
+		goto outrun;
+	}
+
+	/* Set it into U-law mode (read) */
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
+		ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", ast_channel_name(chan));
+		goto outrun;
+	}
+	ast_indicate(chan, -1);
+	retrydahdi = strcasecmp(ast_channel_tech(chan)->type, "DAHDI");
+dahdiretry:
+	origfd = ast_channel_fd(chan, 0);
+	if (retrydahdi) {
+		fd = open("/dev/dahdi/pseudo", O_RDWR);
+		if (fd < 0) {
+			ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
+			goto outrun;
+		}
+		/* Make non-blocking */
+		flags = fcntl(fd, F_GETFL);
+		if (flags < 0) {
+			ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
+			close(fd);
+			goto outrun;
+		}
+		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
+			ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
+			close(fd);
+			goto outrun;
+		}
+		/* Setup buffering information */
+		memset(&bi, 0, sizeof(bi));
+		bi.bufsize = CONF_SIZE;
+		bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.numbufs = 4;
+		if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
+			ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
+			close(fd);
+			goto outrun;
+		}
+		nfds = 1;
+	} else {
+		/* XXX Make sure we're not running on a pseudo channel XXX */
+		fd = ast_channel_fd(chan, 0);
+		nfds = 0;
+	}
+	memset(&dahdic, 0, sizeof(dahdic));
+	/* Check to see if we're in a conference... */
+	dahdic.chan = 0;	
+	if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
+		ast_log(LOG_WARNING, "Error getting conference\n");
+		close(fd);
+		goto outrun;
+	}
+	if (dahdic.confmode) {
+		/* Whoa, already in a conference...  Retry... */
+		if (!retrydahdi) {
+			ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
+			retrydahdi = 1;
+			goto dahdiretry;
+		}
+	}
+	memset(&dahdic, 0, sizeof(dahdic));
+	/* Add us to the conference */
+	dahdic.chan = 0;	
+	dahdic.confno = confno;
+	dahdic.confmode = DAHDI_CONF_MONITORBOTH;
+
+	if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
+		ast_log(LOG_WARNING, "Error setting conference\n");
+		close(fd);
+		goto outrun;
+	}
+	ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", ast_channel_name(chan), confno);
+
+	for(;;) {
+		outfd = -1;
+		ms = -1;
+		c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
+		if (c) {
+			if (ast_channel_fd(c, 0) != origfd) {
+				if (retrydahdi) {
+					/* Kill old pseudo */
+					close(fd);
+				}
+				ast_debug(1, "Ooh, something swapped out under us, starting over\n");
+				retrydahdi = 0;
+				goto dahdiretry;
+			}
+			f = ast_read(c);
+			if (!f) 
+				break;
+			if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
+				ret = 0;
+				ast_frfree(f);
+				break;
+			} else if (fd != ast_channel_fd(chan, 0)) {
+				if (f->frametype == AST_FRAME_VOICE) {
+					if (f->subclass.format.id == AST_FORMAT_ULAW) {
+						/* Carefully write */
+						careful_write(fd, f->data.ptr, f->datalen);
+					} else
+						ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(&f->subclass.format));
+				}
+			}
+			ast_frfree(f);
+		} else if (outfd > -1) {
+			res = read(outfd, buf, CONF_SIZE);
+			if (res > 0) {
+				memset(&fr, 0, sizeof(fr));
+				fr.frametype = AST_FRAME_VOICE;
+				ast_format_set(&fr.subclass.format, AST_FORMAT_ULAW, 0);
+				fr.datalen = res;
+				fr.samples = res;
+				fr.data.ptr = buf;
+				fr.offset = AST_FRIENDLY_OFFSET;
+				if (ast_write(chan, &fr) < 0) {
+					ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
+					/* break; */
+				}
+			} else 
+				ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
+		}
+	}
+	if (fd != ast_channel_fd(chan, 0))
+		close(fd);
+	else {
+		/* Take out of conference */
+		/* Add us to the conference */
+		dahdic.chan = 0;	
+		dahdic.confno = 0;
+		dahdic.confmode = 0;
+		if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
+			ast_log(LOG_WARNING, "Error setting conference\n");
+		}
+	}
+
+outrun:
+
+	return ret;
+}
+
+static int conf_exec(struct ast_channel *chan, const char *data)
+{
+	int res = -1;
+	int retrycnt = 0;
+	int confflags = 0;
+	int confno = 0;
+	char confnostr[80] = "";
+	
+	if (!ast_strlen_zero(data)) {
+		if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
+		    (sscanf(data, "%30d", &confno) != 1)) {
+			ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
+			return 0;
+		}
+	}
+	
+	if (ast_channel_state(chan) != AST_STATE_UP)
+		ast_answer(chan);
+
+	while(!confno && (++retrycnt < 4)) {
+		/* Prompt user for conference number */
+		confnostr[0] = '\0';
+		res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0);
+		if (res <0) goto out;
+		if (sscanf(confnostr, "%30d", &confno) != 1)
+			confno = 0;
+	}
+	if (confno) {
+		/* XXX Should prompt user for pin if pin is required XXX */
+		/* Run the conference */
+		res = conf_run(chan, confno, confflags);
+	}
+out:
+	/* Do the conference */
+	return res;
+}
+
+static int unload_module(void)
+{
+	return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+	return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");
diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c
index f5890c3..3724f03 100644
--- a/apps/app_dahdiras.c
+++ b/apps/app_dahdiras.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/ioctl.h>
 #include <sys/wait.h>
@@ -150,7 +150,7 @@ static void run_ras(struct ast_channel *chan, char *args)
 		ast_log(LOG_WARNING, "Failed to spawn RAS\n");
 	} else {
 		for (;;) {
-			res = waitpid(pid, &status, WNOHANG);
+			res = wait4(pid, &status, WNOHANG, NULL);
 			if (!res) {
 				/* Check for hangup */
 				if (ast_check_hangup(chan) && !signalled) {
@@ -163,7 +163,7 @@ static void run_ras(struct ast_channel *chan, char *args)
 				continue;
 			}
 			if (res < 0) {
-				ast_log(LOG_WARNING, "waitpid returned %d: %s\n", res, strerror(errno));
+				ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno));
 			}
 			if (WIFEXITED(status)) {
 				ast_verb(3, "RAS on %s terminated with status %d\n", ast_channel_name(chan), WEXITSTATUS(status));
@@ -233,6 +233,5 @@ static int load_module(void)
 	return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");
 
diff --git a/apps/app_db.c b/apps/app_db.c
index e284867..ef8d0b3 100644
--- a/apps/app_db.c
+++ b/apps/app_db.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 381366 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/apps/app_dial.c b/apps/app_dial.c
index e59a80e..403a6e9 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2012, Digium, Inc.
+ * Copyright (C) 1999 - 2008, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -26,13 +26,14 @@
  */
 
 /*** MODULEINFO
+	<depend>chan_local</depend>
 	<support_level>core</support_level>
  ***/
 
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <sys/signal.h>
@@ -55,19 +56,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 #include "asterisk/app.h"
 #include "asterisk/causes.h"
 #include "asterisk/rtp_engine.h"
+#include "asterisk/cdr.h"
 #include "asterisk/manager.h"
 #include "asterisk/privacy.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/dsp.h"
+#include "asterisk/cel.h"
 #include "asterisk/aoc.h"
 #include "asterisk/ccss.h"
 #include "asterisk/indications.h"
 #include "asterisk/framehook.h"
-#include "asterisk/dial.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/features_config.h"
 
 /*** DOCUMENTATION
 	<application name="Dial" language="en_US">
@@ -152,12 +151,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 					<argument name="calling" />
 					<argument name="progress" />
 					<para>Send the specified DTMF strings <emphasis>after</emphasis> the called
-					party has answered, but before the call gets bridged.  The
-					<replaceable>called</replaceable> DTMF string is sent to the called party, and the
-					<replaceable>calling</replaceable> DTMF string is sent to the calling party.  Both arguments
+					party has answered, but before the call gets bridged. The 
+					<replaceable>called</replaceable> DTMF string is sent to the called party, and the 
+					<replaceable>calling</replaceable> DTMF string is sent to the calling party. Both arguments 
 					can be used alone.  If <replaceable>progress</replaceable> is specified, its DTMF is sent
-					to the called party immediately after receiving a PROGRESS message.</para>
-					<para>See SendDTMF for valid digits.</para>
+					immediately after receiving a PROGRESS message.</para>
 				</option>
 				<option name="e">
 					<para>Execute the <literal>h</literal> extension for peer after the call ends</para>
@@ -201,7 +199,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 					<argument name="exten" required="false" />
 					<argument name="priority" required="true" />
 					<para>If the call is answered, transfer the calling party to
-					the specified <replaceable>priority</replaceable> and the called party to the specified
+					the specified <replaceable>priority</replaceable> and the called party to the specified 
 					<replaceable>priority</replaceable> plus one.</para>
 					<note>
 						<para>You cannot use any additional action post answer options in conjunction with this option.</para>
@@ -290,7 +288,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 					<argument name="arg" multiple="true">
 						<para>Macro arguments</para>
 					</argument>
-					<para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel
+					<para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel 
 					before connecting to the calling channel. Arguments can be specified to the Macro
 					using <literal>^</literal> as a delimiter. The macro can set the variable
 					<variable>MACRO_RESULT</variable> to specify the following actions after the macro is
@@ -332,7 +330,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 						<para>With <replaceable>delete</replaceable> set to <literal>1</literal>, the introduction will
 						always be deleted.</para>
 					</argument>
-					<para>This option is a modifier for the call screening/privacy mode. (See the
+					<para>This option is a modifier for the call screening/privacy mode. (See the 
 					<literal>p</literal> and <literal>P</literal> options.) It specifies
 					that no introductions are to be saved in the <directory>priv-callerintros</directory>
 					directory.</para>
@@ -353,7 +351,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 					<argument name="mode">
 						<para>With <replaceable>mode</replaceable> either not specified or set to <literal>1</literal>,
 						the originator hanging up will cause the phone to ring back immediately.</para>
-						<para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator
+						<para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator 
 						flashes the trunk, it will ring their phone back.</para>
 					</argument>
 					<para>Enables <emphasis>operator services</emphasis> mode.  This option only
@@ -377,13 +375,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421235 $")
 					<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
 					party until the called channel has answered.</para>
 					<argument name="tone" required="false">
-						<para>Indicate progress to calling party. Send audio 'tone' from the indications.conf tonezone currently in use.</para>
+						<para>Indicate progress to calling party. Send audio 'tone' from indications.conf</para>
 					</argument>
 				</option>
-                                <option name="R">
-                                        <para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. 
-					Allow interruption of the ringback if early media is received on the channel.</para>
-                                </option>
 				<option name="S">
 					<argument name="x" required="true" />
 					<para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has
@@ -615,7 +609,6 @@ enum {
 #define OPT_CALLER_ANSWER    (1LLU << 40)
 #define OPT_PREDIAL_CALLEE   (1LLU << 41)
 #define OPT_PREDIAL_CALLER   (1LLU << 42)
-#define OPT_RING_WITH_EARLY_MEDIA (1LLU << 43)
 
 enum {
 	OPT_ARG_ANNOUNCE = 0,
@@ -638,7 +631,7 @@ enum {
 	OPT_ARG_PREDIAL_CALLEE,
 	OPT_ARG_PREDIAL_CALLER,
 	/* note: this entry _MUST_ be the last one in the enum */
-	OPT_ARG_ARRAY_SIZE
+	OPT_ARG_ARRAY_SIZE,
 };
 
 AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
@@ -671,7 +664,6 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
 	AST_APP_OPTION('p', OPT_SCREENING),
 	AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
 	AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
-	AST_APP_OPTION('R', OPT_RING_WITH_EARLY_MEDIA),
 	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
 	AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
 	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
@@ -757,20 +749,36 @@ struct cause_args {
 
 static void handle_cause(int cause, struct cause_args *num)
 {
+	struct ast_cdr *cdr = ast_channel_cdr(num->chan);
+
 	switch(cause) {
 	case AST_CAUSE_BUSY:
+		if (cdr)
+			ast_cdr_busy(cdr);
 		num->busy++;
 		break;
+
 	case AST_CAUSE_CONGESTION:
+		if (cdr)
+			ast_cdr_failed(cdr);
 		num->congestion++;
 		break;
+
 	case AST_CAUSE_NO_ROUTE_DESTINATION:
 	case AST_CAUSE_UNREGISTERED:
+		if (cdr)
+			ast_cdr_failed(cdr);
 		num->nochan++;
 		break;
+
 	case AST_CAUSE_NO_ANSWER:
+		if (cdr) {
+			ast_cdr_noanswer(cdr);
+		}
+		break;
 	case AST_CAUSE_NORMAL_CLEARING:
 		break;
+
 	default:
 		num->nochan++;
 		break;
@@ -809,6 +817,63 @@ static const char *get_cid_name(char *name, int namelen, struct ast_channel *cha
 	return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
 }
 
+static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
+{
+	struct ast_channel *chans[] = { src, dst };
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a dial action has started.</synopsis>
+			<syntax>
+				<parameter name="SubEvent">
+					<para>A sub event type, specifying whether the dial action has begun or ended.</para>
+					<enumlist>
+						<enum name="Begin"/>
+						<enum name="End"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "Dial", 2, chans,
+		"SubEvent: Begin\r\n"
+		"Channel: %s\r\n"
+		"Destination: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"UniqueID: %s\r\n"
+		"DestUniqueID: %s\r\n"
+		"Dialstring: %s\r\n",
+		ast_channel_name(src), ast_channel_name(dst),
+		S_COR(ast_channel_caller(src)->id.number.valid, ast_channel_caller(src)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(src)->id.name.valid, ast_channel_caller(src)->id.name.str, "<unknown>"),
+		S_COR(ast_channel_connected(src)->id.number.valid, ast_channel_connected(src)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_connected(src)->id.name.valid, ast_channel_connected(src)->id.name.str, "<unknown>"),
+		ast_channel_uniqueid(src), ast_channel_uniqueid(dst),
+		dialstring ? dialstring : "");
+}
+
+static void senddialendevent(struct ast_channel *src, const char *dialstatus)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a dial action has ended.</synopsis>
+			<syntax>
+				<parameter name="DialStatus">
+					<para>The value of the <variable>DIALSTATUS</variable> channel variable.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(src, EVENT_FLAG_CALL, "Dial",
+		"SubEvent: End\r\n"
+		"Channel: %s\r\n"
+		"UniqueID: %s\r\n"
+		"DialStatus: %s\r\n",
+		ast_channel_name(src), ast_channel_uniqueid(src), dialstatus);
+}
+
 /*!
  * helper function for wait_for_answer()
  *
@@ -864,6 +929,8 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 		ast_clear_flag64(o, OPT_IGNORE_CONNECTEDLINE);
 	}
 
+	ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(c), NULL);
+
 	/* Before processing channel, go ahead and check for forwarding */
 	ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", ast_channel_name(in), tech, stuff, ast_channel_name(c));
 	/* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
@@ -873,10 +940,10 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 		cause = AST_CAUSE_BUSY;
 	} else {
 		/* Setup parameters */
-		c = o->chan = ast_request(tech, ast_channel_nativeformats(in), NULL, in, stuff, &cause);
+		c = o->chan = ast_request(tech, ast_channel_nativeformats(in), in, stuff, &cause);
 		if (c) {
 			if (single && !caller_entertained) {
-				ast_channel_make_compatible(in, o->chan);
+				ast_channel_make_compatible(o->chan, in);
 			}
 			ast_channel_lock_both(in, o->chan);
 			ast_channel_inherit_variables(in, o->chan);
@@ -895,7 +962,6 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 				tech, stuff, cause);
 	}
 	if (!c) {
-		ast_channel_publish_dial(in, original, stuff, "BUSY");
 		ast_clear_flag64(o, DIAL_STILLGOING);
 		handle_cause(cause, num);
 		ast_hangup(original);
@@ -957,11 +1023,10 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 			ast_connected_line_copy_from_caller(ast_channel_connected(c), ast_channel_caller(in));
 		}
 
-		ast_channel_req_accountcodes(c, in, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
+		ast_channel_accountcode_set(c, ast_channel_accountcode(in));
 
 		ast_channel_appl_set(c, "AppDial");
 		ast_channel_data_set(c, "(Outgoing Line)");
-		ast_channel_publish_snapshot(c);
 
 		ast_channel_unlock(in);
 		if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
@@ -996,18 +1061,16 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 		if (ast_call(c, stuff, 0)) {
 			ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
 				tech, stuff);
-			ast_channel_publish_dial(in, original, stuff, "CONGESTION");
 			ast_clear_flag64(o, DIAL_STILLGOING);
 			ast_hangup(original);
 			ast_hangup(c);
 			c = o->chan = NULL;
 			num->nochan++;
 		} else {
-			ast_channel_publish_dial_forward(in, original, c, NULL, "CANCEL",
-				ast_channel_call_forward(original));
-
-			ast_channel_publish_dial(in, c, stuff, NULL);
-
+			ast_channel_lock_both(c, in);
+			senddialevent(in, c, stuff);
+			ast_channel_unlock(in);
+			ast_channel_unlock(c);
 			/* Hangup the original channel now, in case we needed it */
 			ast_hangup(original);
 		}
@@ -1026,17 +1089,6 @@ struct privacy_args {
 	char status[256];
 };
 
-static void publish_dial_end_event(struct ast_channel *in, struct dial_head *out_chans, struct ast_channel *exception, const char *status)
-{
-	struct chanlist *outgoing;
-	AST_LIST_TRAVERSE(out_chans, outgoing, node) {
-		if (!outgoing->chan || outgoing->chan == exception) {
-			continue;
-		}
-		ast_channel_publish_dial(in, outgoing->chan, NULL, status);
-	}
-}
-
 static struct ast_channel *wait_for_answer(struct ast_channel *in,
 	struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
 	char *opt_args[],
@@ -1058,7 +1110,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 	int caller_entertained = outgoing
 		&& ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
 	struct ast_party_connected_line connected_caller;
-	struct ast_str *featurecode = ast_str_alloca(AST_FEATURE_MAX_LEN + 1);
+	struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
 	int cc_recall_core_id;
 	int is_cc_recall;
 	int cc_frame_received = 0;
@@ -1072,14 +1124,14 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 			ast_deactivate_generator(in);
 			/* If we are calling a single channel, and not providing ringback or music, */
 			/* then, make them compatible for in-band tone purpose */
-			if (ast_channel_make_compatible(in, outgoing->chan) < 0) {
-				/* If these channels can not be made compatible,
+			if (ast_channel_make_compatible(outgoing->chan, in) < 0) {
+				/* If these channels can not be made compatible, 
 				 * there is no point in continuing.  The bridge
 				 * will just fail if it gets that far.
 				 */
 				*to = -1;
 				strcpy(pa->status, "CONGESTION");
-				ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
+				ast_cdr_failed(ast_channel_cdr(in));
 				return NULL;
 			}
 		}
@@ -1240,7 +1292,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 #ifdef HAVE_EPOLL
 				ast_poll_channel_del(in, c);
 #endif
-				ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c)));
 				ast_hangup(c);
 				c = o->chan = NULL;
 				ast_clear_flag64(o, DIAL_STILLGOING);
@@ -1281,11 +1332,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 							}
 						}
 						peer = c;
-						/* Inform everyone else that they've been canceled.
-						 * The dial end event for the peer will be sent out after
-						 * other Dial options have been handled.
-						 */
-						publish_dial_end_event(in, out_chans, peer, "CANCEL");
+						if (ast_channel_cdr(peer)) {
+							ast_channel_cdr(peer)->answer = ast_tvnow();
+							ast_channel_cdr(peer)->disposition = AST_CDR_ANSWERED;
+						}
 						ast_copy_flags64(peerflags, o,
 							OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
 							OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
@@ -1295,10 +1345,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 							DIAL_NOFORWARDHTML);
 						ast_channel_dialcontext_set(c, "");
 						ast_channel_exten_set(c, "");
-						if (CAN_EARLY_BRIDGE(peerflags, in, peer)) {
+						if (CAN_EARLY_BRIDGE(peerflags, in, peer))
 							/* Setup early bridge if appropriate */
 							ast_channel_early_bridge(in, peer);
-						}
 					}
 					/* If call has been answered, then the eventual hangup is likely to be normal hangup */
 					ast_channel_hangupcause_set(in, AST_CAUSE_NORMAL_CLEARING);
@@ -1307,7 +1356,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 				case AST_CONTROL_BUSY:
 					ast_verb(3, "%s is busy\n", ast_channel_name(c));
 					ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
-					ast_channel_publish_dial(in, c, NULL, "BUSY");
 					ast_hangup(c);
 					c = o->chan = NULL;
 					ast_clear_flag64(o, DIAL_STILLGOING);
@@ -1316,7 +1364,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 				case AST_CONTROL_CONGESTION:
 					ast_verb(3, "%s is circuit-busy\n", ast_channel_name(c));
 					ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
-					ast_channel_publish_dial(in, c, NULL, "CONGESTION");
 					ast_hangup(c);
 					c = o->chan = NULL;
 					ast_clear_flag64(o, DIAL_STILLGOING);
@@ -1523,7 +1570,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 				/* Got hung up */
 				*to = -1;
 				strcpy(pa->status, "CANCEL");
-				publish_dial_end_event(in, out_chans, NULL, pa->status);
+				ast_cdr_noanswer(ast_channel_cdr(in));
 				if (f) {
 					if (f->data.uint32) {
 						ast_channel_hangupcause_set(in, f->data.uint32);
@@ -1545,9 +1592,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 					if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
 						ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 						*to = 0;
+						ast_cdr_noanswer(ast_channel_cdr(in));
 						*result = f->subclass.integer;
 						strcpy(pa->status, "CANCEL");
-						publish_dial_end_event(in, out_chans, NULL, pa->status);
 						ast_frfree(f);
 						ast_channel_unlock(in);
 						if (is_cc_recall) {
@@ -1563,7 +1610,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 					ast_verb(3, "User requested call disconnect.\n");
 					*to = 0;
 					strcpy(pa->status, "CANCEL");
-					publish_dial_end_event(in, out_chans, NULL, pa->status);
+					ast_cdr_noanswer(ast_channel_cdr(in));
 					ast_frfree(f);
 					if (is_cc_recall) {
 						ast_cc_completed(in, "CC completed, but the caller hung up with DTMF");
@@ -1657,9 +1704,11 @@ skip_frame:;
 		}
 	}
 
-	if (!*to || ast_check_hangup(in)) {
+	if (!*to) {
 		ast_verb(3, "Nobody picked up in %d ms\n", orig);
-		publish_dial_end_event(in, out_chans, NULL, "NOANSWER");
+	}
+	if (!*to || ast_check_hangup(in)) {
+		ast_cdr_noanswer(ast_channel_cdr(in));
 	}
 
 #ifdef HAVE_EPOLL
@@ -1677,31 +1726,22 @@ skip_frame:;
 
 static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode)
 {
-	char disconnect_code[AST_FEATURE_MAX_LEN];
+	struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
+	struct ast_call_feature feature = { 0, };
 	int res;
 
 	ast_str_append(featurecode, 1, "%c", code);
 
-	res = ast_get_builtin_feature(chan, "disconnect", disconnect_code, sizeof(disconnect_code));
-	if (res) {
-		ast_str_reset(*featurecode);
-		return 0;
-	}
-
-	if (strlen(disconnect_code) > ast_str_strlen(*featurecode)) {
-		/* Could be a partial match, anyway */
-		if (strncmp(disconnect_code, ast_str_buffer(*featurecode), ast_str_strlen(*featurecode))) {
-			ast_str_reset(*featurecode);
-		}
-		return 0;
-	}
+	res = ast_feature_detect(chan, &features, ast_str_buffer(*featurecode), &feature);
 
-	if (strcmp(disconnect_code, ast_str_buffer(*featurecode))) {
+	if (res != AST_FEATURE_RETURN_STOREDIGITS) {
 		ast_str_reset(*featurecode);
-		return 0;
+	}
+	if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
+		return 1;
 	}
 
-	return 1;
+	return 0;
 }
 
 /* returns true if there is a valid privacy reply */
@@ -1737,7 +1777,7 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
 		ast_channel_musicclass_set(chan, opt_args[OPT_ARG_MUSICBACK]);
 		ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
 		ast_channel_musicclass_set(chan, original_moh);
-	} else if (ast_test_flag64(opts, OPT_RINGBACK) || ast_test_flag64(opts, OPT_RING_WITH_EARLY_MEDIA)) {
+	} else if (ast_test_flag64(opts, OPT_RINGBACK)) {
 		ast_indicate(chan, AST_CONTROL_RINGING);
 		pa->sentringing++;
 	}
@@ -1767,23 +1807,22 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
 			if (ast_test_flag64(opts, OPT_SCREENING))
 				res2 = ast_play_and_wait(peer, "screen-callee-options");
 		}
-
 		/*! \page DialPrivacy Dial Privacy scripts
-		 * \par priv-callee-options script:
-		 * \li Dial 1 if you wish this caller to reach you directly in the future,
-		 * 	and immediately connect to their incoming call.
-		 * \li Dial 2 if you wish to send this caller to voicemail now and forevermore.
-		 * \li Dial 3 to send this caller to the torture menus, now and forevermore.
-		 * \li Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
-		 * \li Dial 5 to allow this caller to come straight thru to you in the future,
-		 * 	but right now, just this once, send them to voicemail.
-		 *
-		 * \par screen-callee-options script:
-		 * \li Dial 1 if you wish to immediately connect to the incoming call
-		 * \li Dial 2 if you wish to send this caller to voicemail.
-		 * \li Dial 3 to send this caller to the torture menus.
-		 * \li Dial 4 to send this caller to a simple "go away" menu.
-		 */
+		\par priv-callee-options script:
+			"Dial 1 if you wish this caller to reach you directly in the future,
+				and immediately connect to their incoming call
+			 Dial 2 if you wish to send this caller to voicemail now and
+				forevermore.
+			 Dial 3 to send this caller to the torture menus, now and forevermore.
+			 Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
+			 Dial 5 to allow this caller to come straight thru to you in the future,
+				but right now, just this once, send them to voicemail."
+		\par screen-callee-options script:
+			"Dial 1 if you wish to immediately connect to the incoming call
+			 Dial 2 if you wish to send this caller to voicemail.
+			 Dial 3 to send this caller to the torture menus.
+			 Dial 4 to send this caller to a simple "go away" menu.
+		*/
 		if (valid_priv_reply(opts, res2))
 			break;
 		/* invalid option */
@@ -1792,7 +1831,7 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
 
 	if (ast_test_flag64(opts, OPT_MUSICBACK)) {
 		ast_moh_stop(chan);
-	} else if (ast_test_flag64(opts, OPT_RINGBACK) || ast_test_flag64(opts, OPT_RING_WITH_EARLY_MEDIA)) {
+	} else if (ast_test_flag64(opts, OPT_RINGBACK)) {
 		ast_indicate(chan, -1);
 		pa->sentringing = 0;
 	}
@@ -1896,7 +1935,7 @@ static int setup_privacy_args(struct privacy_args *pa,
 	} else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
 		ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
 	}
-
+	
 	if (pa->privdb_val == AST_PRIVACY_DENY) {
 		ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
 		ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
@@ -1960,15 +1999,22 @@ static void end_bridge_callback(void *data)
 	time_t end;
 	struct ast_channel *chan = data;
 
+	if (!ast_channel_cdr(chan)) {
+		return;
+	}
+
 	time(&end);
 
 	ast_channel_lock(chan);
-	ast_channel_stage_snapshot(chan);
-	snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
-	pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
-	snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
-	pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
-	ast_channel_stage_snapshot_done(chan);
+	if (ast_channel_cdr(chan)->answer.tv_sec) {
+		snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->answer.tv_sec);
+		pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
+	}
+
+	if (ast_channel_cdr(chan)->start.tv_sec) {
+		snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->start.tv_sec);
+		pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
+	}
 	ast_channel_unlock(chan);
 }
 
@@ -2006,40 +2052,6 @@ static int dial_handle_playtones(struct ast_channel *chan, const char *data)
 	return res;
 }
 
-/*!
- * \internal
- * \brief Setup the after bridge goto location on the peer.
- * \since 12.0.0
- *
- * \param chan Calling channel for bridge.
- * \param peer Peer channel for bridge.
- * \param opts Dialing option flags.
- * \param opt_args Dialing option argument strings.
- *
- * \return Nothing
- */
-static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags64 *opts, char *opt_args[])
-{
-	const char *context;
-	const char *extension;
-	int priority;
-
-	if (ast_test_flag64(opts, OPT_PEER_H)) {
-		ast_channel_lock(chan);
-		context = ast_strdupa(ast_channel_context(chan));
-		ast_channel_unlock(chan);
-		ast_bridge_set_after_h(peer, context);
-	} else if (ast_test_flag64(opts, OPT_CALLEE_GO_ON)) {
-		ast_channel_lock(chan);
-		context = ast_strdupa(ast_channel_context(chan));
-		extension = ast_strdupa(ast_channel_exten(chan));
-		priority = ast_channel_priority(chan);
-		ast_channel_unlock(chan);
-		ast_bridge_set_after_go_on(peer, context, extension, priority,
-			opt_args[OPT_ARG_CALLEE_GO_ON]);
-	}
-}
-
 static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast_flags64 *peerflags, int *continue_exec)
 {
 	int res = -1; /* default: error */
@@ -2103,15 +2115,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	struct ast_party_caller caller;
 
 	/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
-	ast_channel_lock(chan);
-	ast_channel_stage_snapshot(chan);
 	pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
 	pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
 	pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
 	pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
 	pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
@@ -2266,9 +2274,8 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		ast_channel_unlock(chan);
 	}
 
-	if (ast_test_flag64(&opts, OPT_RESETCDR)) {
-		ast_cdr_reset(ast_channel_name(chan), 0);
-	}
+	if (ast_test_flag64(&opts, OPT_RESETCDR) && ast_channel_cdr(chan))
+		ast_cdr_reset(ast_channel_cdr(chan), NULL);
 	if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
 		opt_args[OPT_ARG_PRIVACY] = ast_strdupa(ast_channel_exten(chan));
 
@@ -2352,8 +2359,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 				OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
 				OPT_CALLEE_PARK | OPT_CALLER_PARK |
 				OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
-				OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE |
-				OPT_RING_WITH_EARLY_MEDIA);
+				OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE);
 			ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
 		}
 
@@ -2425,7 +2431,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			AST_LIST_UNLOCK(dialed_interfaces);
 		}
 
-		tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), NULL, chan, tmp->number, &cause);
+		tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), chan, tmp->number, &cause);
 		if (!tc) {
 			/* If we can't, just go on to the next call */
 			ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
@@ -2443,33 +2449,26 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			chanlist_free(tmp);
 			continue;
 		}
-
-		ast_channel_lock(tc);
-		ast_channel_stage_snapshot(tc);
-		ast_channel_unlock(tc);
-
 		ast_channel_get_device_name(tc, device_name, sizeof(device_name));
 		if (!ignore_cc) {
 			ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name);
 		}
+		pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number);
 
 		ast_channel_lock_both(tc, chan);
-		pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number);
 
 		/* Setup outgoing SDP to match incoming one */
 		if (!AST_LIST_FIRST(&out_chans) && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
 			/* We are on the only destination. */
 			ast_rtp_instance_early_bridge_make_compatible(tc, chan);
 		}
-
+		
 		/* Inherit specially named variables from parent channel */
 		ast_channel_inherit_variables(chan, tc);
 		ast_channel_datastore_inherit(chan, tc);
 
 		ast_channel_appl_set(tc, "AppDial");
 		ast_channel_data_set(tc, "(Outgoing Line)");
-		ast_channel_publish_snapshot(tc);
-
 		memset(ast_channel_whentohangup(tc), 0, sizeof(*ast_channel_whentohangup(tc)));
 
 		/* Determine CallerID to store in outgoing channel. */
@@ -2527,7 +2526,9 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 
 		ast_channel_dialed(tc)->transit_network_select = ast_channel_dialed(chan)->transit_network_select;
 
-		ast_channel_req_accountcodes(tc, chan, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
+		if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
+			ast_channel_accountcode_set(tc, ast_channel_accountcode(chan));
+		}
 		if (ast_strlen_zero(ast_channel_musicclass(tc))) {
 			ast_channel_musicclass_set(tc, ast_channel_musicclass(chan));
 		}
@@ -2555,8 +2556,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		else
 			ast_channel_exten_set(tc, ast_channel_exten(chan));
 
-		ast_channel_stage_snapshot_done(tc);
-
 		ast_channel_unlock(tc);
 		ast_channel_unlock(chan);
 
@@ -2599,6 +2598,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		res = ast_call(tmp->chan, tmp->number, 0); /* Place the call, but don't wait on the answer */
 		ast_channel_lock(chan);
 
+		/* Save the info in cdr's that we called them */
+		if (ast_channel_cdr(chan))
+			ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(tmp->chan));
+
 		/* check the results of ast_call */
 		if (res) {
 			/* Again, keep going even if there's an error */
@@ -2616,7 +2619,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			continue;
 		}
 
-		ast_channel_publish_dial(chan, tmp->chan, tmp->number, NULL);
+		senddialevent(chan, tmp->chan, tmp->number);
 		ast_channel_unlock(chan);
 
 		ast_verb(3, "Called %s\n", tmp->interface);
@@ -2662,7 +2665,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 				ast_moh_start(chan, NULL, NULL);
 			}
 			ast_indicate(chan, AST_CONTROL_PROGRESS);
-		} else if (ast_test_flag64(outgoing, OPT_RINGBACK) || ast_test_flag64(outgoing, OPT_RING_WITH_EARLY_MEDIA)) {
+		} else if (ast_test_flag64(outgoing, OPT_RINGBACK)) {
 			if (!ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) {
 				if (dial_handle_playtones(chan, opt_args[OPT_ARG_RINGBACK])){
 					ast_indicate(chan, AST_CONTROL_RINGING);
@@ -2707,16 +2710,19 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			ast_answer(chan);
 
 		strcpy(pa.status, "ANSWER");
-		ast_channel_stage_snapshot(chan);
 		pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
 		hanguptree(&out_chans, peer, 1);
 		/* If appropriate, log that we have a destination channel and set the answer time */
+		if (ast_channel_cdr(chan)) {
+			ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
+			ast_cdr_setanswer(ast_channel_cdr(chan), ast_channel_cdr(peer)->answer);
+		}
 		if (ast_channel_name(peer))
 			pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
-
+		
 		ast_channel_lock(peer);
 		number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
 		if (ast_strlen_zero(number)) {
@@ -2725,10 +2731,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			number = ast_strdupa(number);
 		}
 		ast_channel_unlock(peer);
-		ast_channel_lock(chan);
 		pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
-		ast_channel_stage_snapshot_done(chan);
-		ast_channel_unlock(chan);
 
 		if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
 			ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
@@ -2736,7 +2739,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		}
 		if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) {
 			if (do_privacy(chan, peer, &opts, opt_args, &pa)) {
-				ast_channel_publish_dial(chan, peer, NULL, pa.status);
 				res = 0;
 				goto out;
 			}
@@ -2812,21 +2814,17 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		}
 
 		if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
-			/* chan and peer are going into the PBX; as such neither are considered
-			 * outgoing channels any longer */
-			ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
+			/* chan and peer are going into the PBX, they both
+			 * should probably get CDR records. */
+			ast_clear_flag(ast_channel_cdr(chan), AST_CDR_FLAG_DIALED);
+			ast_clear_flag(ast_channel_cdr(peer), AST_CDR_FLAG_DIALED);
 
 			ast_replace_subargument_delimiter(opt_args[OPT_ARG_GOTO]);
 			ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
 			/* peer goes to the same context and extension as chan, so just copy info from chan*/
-			ast_channel_lock(peer);
-			ast_channel_stage_snapshot(peer);
-			ast_clear_flag(ast_channel_flags(peer), AST_FLAG_OUTGOING);
 			ast_channel_context_set(peer, ast_channel_context(chan));
 			ast_channel_exten_set(peer, ast_channel_exten(chan));
 			ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
-			ast_channel_stage_snapshot_done(peer);
-			ast_channel_unlock(peer);
 			if (ast_pbx_start(peer)) {
 				ast_autoservice_chan_hangup_peer(chan, peer);
 			}
@@ -2834,7 +2832,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			if (continue_exec)
 				*continue_exec = 1;
 			res = 0;
-			ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
 			goto done;
 		}
 
@@ -2847,6 +2844,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 			ast_channel_exten_set(peer, ast_channel_exten(chan));
 			ast_channel_unlock(peer);
 			ast_channel_unlock(chan);
+
 			ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
 			res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]);
 
@@ -2887,7 +2885,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 						ast_set_flag64(peerflags, OPT_GO_ON);
 					}
 				}
-				ast_channel_publish_dial(chan, peer, NULL, macro_result);
 			} else {
 				ast_channel_unlock(peer);
 			}
@@ -2970,7 +2967,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 						ast_set_flag64(peerflags, OPT_GO_ON);
 					}
 				}
-				ast_channel_publish_dial(chan, peer, NULL, gosub_result);
 			} else {
 				ast_channel_unlock(peer);
 				ast_channel_unlock(chan);
@@ -2978,17 +2974,9 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		}
 
 		if (!res) {
-
-			/* None of the Dial options changed our status; inform
-			 * everyone that this channel answered
-			 */
-			ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
-
 			if (!ast_tvzero(calldurationlimit)) {
 				struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit);
-				ast_channel_lock(peer);
 				ast_channel_whentohangup_set(peer, &whentohangup);
-				ast_channel_unlock(peer);
 			}
 			if (!ast_strlen_zero(dtmfcalled)) {
 				ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
@@ -3001,14 +2989,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		}
 
 		if (res) { /* some error */
-			if (!ast_check_hangup(chan) && ast_check_hangup(peer)) {
-				ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
-			}
-			setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
-			if (ast_bridge_setup_after_goto(peer)
-				|| ast_pbx_start(peer)) {
-				ast_autoservice_chan_hangup_peer(chan, peer);
-			}
 			res = -1;
 		} else {
 			if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
@@ -3031,11 +3011,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 				ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
 			if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
 				ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
+			if (ast_test_flag64(peerflags, OPT_GO_ON))
+				ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
 
 			config.end_bridge_callback = end_bridge_callback;
 			config.end_bridge_callback_data = chan;
 			config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
-
+			
 			if (moh) {
 				moh = 0;
 				ast_moh_stop(chan);
@@ -3062,9 +3044,38 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 
 				ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
 			}
-			setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
 			res = ast_bridge_call(chan, peer, &config);
 		}
+
+		ast_channel_context_set(peer, ast_channel_context(chan));
+
+		if (ast_test_flag64(&opts, OPT_PEER_H)
+			&& ast_exists_extension(peer, ast_channel_context(peer), "h", 1,
+				S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
+			ast_autoservice_start(chan);
+			ast_pbx_h_exten_run(peer, ast_channel_context(peer));
+			ast_autoservice_stop(chan);
+		}
+		if (!ast_check_hangup(peer)) {
+			if (ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
+				int goto_res;
+
+				if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+					ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+					goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
+				} else { /* F() */
+					goto_res = ast_goto_if_exists(peer, ast_channel_context(chan),
+						ast_channel_exten(chan), ast_channel_priority(chan) + 1);
+				}
+				if (!goto_res && !ast_pbx_start(peer)) {
+					/* The peer is now running its own PBX. */
+					goto out;
+				}
+			}
+		} else if (!ast_check_hangup(chan)) {
+			ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
+		}
+		ast_autoservice_chan_hangup_peer(chan, peer);
 	}
 out:
 	if (moh) {
@@ -3087,6 +3098,7 @@ out:
 	ast_channel_early_bridge(chan, NULL);
 	hanguptree(&out_chans, NULL, ast_channel_hangupcause(chan)==AST_CAUSE_ANSWERED_ELSEWHERE || ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0 ); /* forward 'answered elsewhere' if we received it */
 	pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
+	senddialendevent(chan, pa.status);
 	ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
 
 	if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) {
diff --git a/apps/app_dictate.c b/apps/app_dictate.c
index be89e81..19d8a6a 100644
--- a/apps/app_dictate.c
+++ b/apps/app_dictate.c
@@ -5,7 +5,7 @@
  *
  * Anthony Minessale II <anthmct at yahoo.com>
  *
- * Donated by Sangoma Technologies <http://www.samgoma.com>
+ * Donated by Sangoma Technologies <http://www.sangoma.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
@@ -43,7 +43,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/say.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="Dictate" language="en_US">
@@ -109,7 +108,8 @@ static int dictate_exec(struct ast_channel *chan, const char *data)
 		len = 0,
 		maxlen = 0,
 		mode = 0;
-	struct ast_format *oldr;
+	struct ast_format oldr;
+	ast_format_clear(&oldr);
 
 	snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR);
 	if (!ast_strlen_zero(data)) {
@@ -126,10 +126,9 @@ static int dictate_exec(struct ast_channel *chan, const char *data)
 	if (args.argc > 1 && args.filename) {
 		filename = args.filename;
 	}
-	oldr = ao2_bump(ast_channel_readformat(chan));
-	if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) {
+	ast_format_copy(&oldr, ast_channel_readformat(chan));
+	if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) {
 		ast_log(LOG_WARNING, "Unable to set to linear mode.\n");
-		ao2_cleanup(oldr);
 		return -1;
 	}
 
@@ -175,7 +174,7 @@ static int dictate_exec(struct ast_channel *chan, const char *data)
 				ast_queue_frame(chan, &fr);
 				digit = 0;
 			}
-			if ((f->frametype == AST_FRAME_DTMF)) {
+			if (f->frametype == AST_FRAME_DTMF) {
 				int got = 1;
 				switch(mode) {
 				case DMODE_PLAY:
@@ -336,9 +335,8 @@ static int dictate_exec(struct ast_channel *chan, const char *data)
 			ast_frfree(f);
 		}
 	}
-	if (oldr) {
-		ast_set_read_format(chan, oldr);
-		ao2_ref(oldr, -1);
+	if (oldr.id) {
+		ast_set_read_format(chan, &oldr);
 	}
 	return 0;
 }
@@ -355,5 +353,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, dictate_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Virtual Dictation Machine");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine");
diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c
index a88ae0d..6fcde07 100644
--- a/apps/app_directed_pickup.c
+++ b/apps/app_directed_pickup.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -43,9 +43,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403013 $")
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
 #include "asterisk/app.h"
-#include "asterisk/pickup.h"
+#include "asterisk/features.h"
 #include "asterisk/manager.h"
 #include "asterisk/callerid.h"
+#include "asterisk/cel.h"
 
 #define PICKUPMARK "PICKUPMARK"
 
@@ -97,29 +98,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403013 $")
 			Pickup a ringing channel.
 		</synopsis>
 		<syntax >
-			<parameter name="channel" argsep="&" required="true">
-				<argument name="channel" required="true" />
-				<argument name="channel2" required="false" multiple="true" />
-				<para>List of channel names or channel uniqueids to pickup if ringing.
-					For example, a channel name could be <literal>SIP/bob</literal> or
-					<literal>SIP/bob-00000000</literal> to find
-					<literal>SIP/bob-00000000</literal>.
-				</para>
+			<parameter name="Technology/Resource" argsep="&" required="true">
+				<argument name="Technology/Resource" required="true" />
+				<argument name="Technology2/Resource2" required="false" multiple="true" />
 			</parameter>
 			<parameter name="options" required="false">
 				<optionlist>
 					<option name="p">
-						<para>Supplied channel names are prefixes.  For example,
-							<literal>SIP/bob</literal> will match
-							<literal>SIP/bob-00000000</literal> and
-							<literal>SIP/bobby-00000000</literal>.
-						</para>
+						<para>Channel name specified partial name. Used when find channel by callid.</para>
 					</option>
 				</optionlist>
 			</parameter>
 		</syntax>
 		<description>
-			<para>Pickup a specified <replaceable>channel</replaceable> if ringing.</para>
+			<para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
 		</description>
 	</application>
  ***/
@@ -128,48 +120,17 @@ static const char app[] = "Pickup";
 static const char app2[] = "PickupChan";
 
 struct pickup_by_name_args {
-	/*! Channel attempting to pickup a call. */
-	struct ast_channel *chan;
-	/*! Channel uniqueid or partial channel name to match. */
 	const char *name;
-	/*! Length of partial channel name to match. */
 	size_t len;
 };
 
-static int find_by_name(void *obj, void *arg, void *data, int flags)
+static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
 {
 	struct ast_channel *target = obj;/*!< Potential pickup target */
 	struct pickup_by_name_args *args = data;
 
-	if (args->chan == target) {
-		/* The channel attempting to pickup a call cannot pickup itself. */
-		return 0;
-	}
-
 	ast_channel_lock(target);
-	if (!strncasecmp(ast_channel_name(target), args->name, args->len)
-		&& ast_can_pickup(target)) {
-		/* Return with the channel still locked on purpose */
-		return CMP_MATCH | CMP_STOP;
-	}
-	ast_channel_unlock(target);
-
-	return 0;
-}
-
-static int find_by_uniqueid(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_channel *target = obj;/*!< Potential pickup target */
-	struct pickup_by_name_args *args = data;
-
-	if (args->chan == target) {
-		/* The channel attempting to pickup a call cannot pickup itself. */
-		return 0;
-	}
-
-	ast_channel_lock(target);
-	if (!strcasecmp(ast_channel_uniqueid(target), args->name)
-		&& ast_can_pickup(target)) {
+	if (!strncasecmp(ast_channel_name(target), args->name, args->len) && ast_can_pickup(target)) {
 		/* Return with the channel still locked on purpose */
 		return CMP_MATCH | CMP_STOP;
 	}
@@ -179,55 +140,45 @@ static int find_by_uniqueid(void *obj, void *arg, void *data, int flags)
 }
 
 /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
-static struct ast_channel *find_by_channel(struct ast_channel *chan, const char *channame)
+static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
 {
-	struct ast_channel *target;
 	char *chkchan;
 	struct pickup_by_name_args pickup_args;
 
-	pickup_args.chan = chan;
-
+	/* Check if channel name contains a '-'.
+	 * In this case the channel name will be interpreted as full channel name.
+	 */
 	if (strchr(channame, '-')) {
-		/*
-		 * Use the given channel name string as-is.  This allows a full channel
-		 * name with a typical sequence number to be used as well as still
-		 * allowing the odd partial channel name that has a '-' in it to still
-		 * work, i.e. Local/bob at en-phone.
-		 */
+		/* check full channel name */
 		pickup_args.len = strlen(channame);
 		pickup_args.name = channame;
 	} else {
-		/*
-		 * Append a '-' for the comparison so we check the channel name less
-		 * a sequence number, i.e Find SIP/bob- and not SIP/bobby.
+		/* need to append a '-' for the comparison so we check full channel name,
+		 * i.e SIP/hgc- , use a temporary variable so original stays the same for
+		 * debugging.
 		 */
 		pickup_args.len = strlen(channame) + 1;
 		chkchan = ast_alloca(pickup_args.len + 1);
-		strcpy(chkchan, channame);/* Safe */
+		strcpy(chkchan, channame);
 		strcat(chkchan, "-");
 		pickup_args.name = chkchan;
 	}
-	target = ast_channel_callback(find_by_name, NULL, &pickup_args, 0);
-	if (target) {
-		return target;
-	}
 
-	/* Now try a search for uniqueid. */
-	pickup_args.name = channame;
-	pickup_args.len = 0;
-	return ast_channel_callback(find_by_uniqueid, NULL, &pickup_args, 0);
+	return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
 }
 
-/*! \brief Attempt to pick up named channel. */
-static int pickup_by_channel(struct ast_channel *chan, const char *name)
+/*! \brief Attempt to pick up named channel, does not use context */
+static int pickup_by_channel(struct ast_channel *chan, char *pickup)
 {
 	int res = -1;
 	struct ast_channel *target;/*!< Potential pickup target */
 
-	/* The found channel is already locked. */
-	target = find_by_channel(chan, name);
+	target = my_ast_get_channel_by_name_locked(pickup);
 	if (target) {
-		res = ast_do_pickup(chan, target);
+		/* Just check that we are not picking up the SAME as target. (i.e. ourself) */
+		if (chan != target) {
+			res = ast_do_pickup(chan, target);
+		}
 		ast_channel_unlock(target);
 		target = ast_channel_unref(target);
 	}
@@ -270,15 +221,9 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
 static int find_by_mark(void *obj, void *arg, void *data, int flags)
 {
 	struct ast_channel *target = obj;/*!< Potential pickup target */
-	struct ast_channel *chan = arg;
 	const char *mark = data;
 	const char *tmp;
 
-	if (chan == target) {
-		/* The channel attempting to pickup a call cannot pickup itself. */
-		return 0;
-	}
-
 	ast_channel_lock(target);
 	tmp = pbx_builtin_getvar_helper(target, PICKUPMARK);
 	if (tmp && !strcasecmp(tmp, mark) && ast_can_pickup(target)) {
@@ -297,7 +242,7 @@ static int pickup_by_mark(struct ast_channel *chan, const char *mark)
 	int res = -1;
 
 	/* The found channel is already locked. */
-	target = ast_channel_callback(find_by_mark, chan, (char *) mark, 0);
+	target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0);
 	if (target) {
 		res = ast_do_pickup(chan, target);
 		ast_channel_unlock(target);
@@ -327,7 +272,7 @@ static int pickup_by_group(struct ast_channel *chan)
 /* application entry point for Pickup() */
 static int pickup_exec(struct ast_channel *chan, const char *data)
 {
-	char *parse;
+	char *tmp;
 	char *exten;
 	char *context;
 
@@ -336,20 +281,10 @@ static int pickup_exec(struct ast_channel *chan, const char *data)
 	}
 
 	/* Parse extension (and context if there) */
-	parse = ast_strdupa(data);
-	for (;;) {
-		if (ast_strlen_zero(parse)) {
-			break;
-		}
-		exten = strsep(&parse, "&");
-		if (ast_strlen_zero(exten)) {
-			continue;
-		}
-
-		context = strchr(exten, '@');
-		if (context) {
+	tmp = ast_strdupa(data);
+	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
+		if ((context = strchr(exten, '@')))
 			*context++ = '\0';
-		}
 		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
 			if (!pickup_by_mark(chan, exten)) {
 				/* Pickup successful.  Stop the dialplan this channel is a zombie. */
@@ -371,36 +306,32 @@ static int pickup_exec(struct ast_channel *chan, const char *data)
 	return 0;
 }
 
-/* Find channel for pick up specified by partial channel name */
-static struct ast_channel *find_by_part(struct ast_channel *chan, const char *part)
+/* Find channel for pick up specified by partial channel name */ 
+static int find_by_part(void *obj, void *arg, void *data, int flags)
 {
-	struct ast_channel *target;
-	struct pickup_by_name_args pickup_args;
-
-	pickup_args.chan = chan;
+	struct ast_channel *target = obj;/*!< Potential pickup target */
+	const char *part = data;
+	int len = strlen(part);
 
-	/* Try a partial channel name search. */
-	pickup_args.name = part;
-	pickup_args.len = strlen(part);
-	target = ast_channel_callback(find_by_name, NULL, &pickup_args, 0);
-	if (target) {
-		return target;
+	ast_channel_lock(target);
+	if (len <= strlen(ast_channel_name(target)) && !strncmp(ast_channel_name(target), part, len)
+		&& ast_can_pickup(target)) {
+		/* Return with the channel still locked on purpose */
+		return CMP_MATCH | CMP_STOP;
 	}
+	ast_channel_unlock(target);
 
-	/* Now try a search for uniqueid. */
-	pickup_args.name = part;
-	pickup_args.len = 0;
-	return ast_channel_callback(find_by_uniqueid, NULL, &pickup_args, 0);
+	return 0;
 }
 
-/* Attempt to pick up specified by partial channel name */
+/* Attempt to pick up specified by partial channel name */ 
 static int pickup_by_part(struct ast_channel *chan, const char *part)
 {
 	struct ast_channel *target;/*!< Potential pickup target */
 	int res = -1;
 
 	/* The found channel is already locked. */
-	target = find_by_part(chan, part);
+	target = ast_channel_callback(find_by_part, NULL, (char *) part, 0);
 	if (target) {
 		res = ast_do_pickup(chan, target);
 		ast_channel_unlock(target);
@@ -410,26 +341,16 @@ static int pickup_by_part(struct ast_channel *chan, const char *part)
 	return res;
 }
 
-enum OPT_PICKUPCHAN_FLAGS {
-	OPT_PICKUPCHAN_PARTIAL =   (1 << 0),	/* Channel name is a partial name. */
-};
-
-AST_APP_OPTIONS(pickupchan_opts, BEGIN_OPTIONS
-	AST_APP_OPTION('p', OPT_PICKUPCHAN_PARTIAL),
-END_OPTIONS);
-
 /* application entry point for PickupChan() */
 static int pickupchan_exec(struct ast_channel *chan, const char *data)
 {
+	int partial_pickup = 0;
 	char *pickup = NULL;
 	char *parse = ast_strdupa(data);
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(channel);
 		AST_APP_ARG(options);
-		AST_APP_ARG(other);	/* Any remining unused arguments */
 	);
-	struct ast_flags opts;
-
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (ast_strlen_zero(args.channel)) {
@@ -437,34 +358,27 @@ static int pickupchan_exec(struct ast_channel *chan, const char *data)
 		/* Pickup failed.  Keep going in the dialplan. */
 		return 0;
 	}
-	if (ast_app_parse_options(pickupchan_opts, &opts, NULL, args.options)) {
-		/*
-		 * General invalid option syntax.
-		 * Pickup failed.  Keep going in the dialplan.
-		 */
-		return 0;
+
+	if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
+		partial_pickup = 1;
 	}
 
 	/* Parse channel */
-	for (;;) {
-		if (ast_strlen_zero(args.channel)) {
-			break;
-		}
-		pickup = strsep(&args.channel, "&");
-		if (ast_strlen_zero(pickup)) {
-			continue;
-		}
-
-		if (ast_test_flag(&opts, OPT_PICKUPCHAN_PARTIAL)) {
-			if (!pickup_by_part(chan, pickup)) {
+	while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
+		if (!strncasecmp(ast_channel_name(chan), pickup, strlen(pickup))) {
+			ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
+		} else {
+			if (partial_pickup) {
+				if (!pickup_by_part(chan, pickup)) {
+					/* Pickup successful.  Stop the dialplan this channel is a zombie. */
+					return -1;
+				}
+			} else if (!pickup_by_channel(chan, pickup)) {
 				/* Pickup successful.  Stop the dialplan this channel is a zombie. */
 				return -1;
 			}
-		} else if (!pickup_by_channel(chan, pickup)) {
-			/* Pickup successful.  Stop the dialplan this channel is a zombie. */
-			return -1;
+			ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
 		}
-		ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
 	}
 
 	/* Pickup failed.  Keep going in the dialplan. */
diff --git a/apps/app_directory.c b/apps/app_directory.c
index 0db54d4..ce01bc8 100644
--- a/apps/app_directory.c
+++ b/apps/app_directory.c
@@ -26,11 +26,12 @@
  */
 
 /*** MODULEINFO
+	<depend>app_voicemail</depend>
 	<support_level>core</support_level>
  ***/
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 
@@ -86,12 +87,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
 						argument will be used for the number of characters the user should enter.</para>
 						<argument name="n" required="true" />
 					</option>
-					<option name="a">
-						<para>Allow the caller to additionally enter an alias for a user in the
-						directory.  This option must be specified in addition to the
-						<literal>f</literal>, <literal>l</literal>, or <literal>b</literal>
-						option.</para>
-					</option>
 					<option name="m">
 						<para>Instead of reading each name sequentially and asking for
 						confirmation, create a menu of up to 8 names.</para>
@@ -110,7 +105,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
 				options may be specified. <emphasis>If more than one is specified</emphasis>, then Directory will act as 
 				if <replaceable>b</replaceable> was specified.  The number
 				of characters for the user to type defaults to <literal>3</literal>.</para></note>
-
 			</parameter>
 		</syntax>
 		<description>
@@ -121,19 +115,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
 			received and the extension to jump to exists:</para>
 			<para><literal>0</literal> - Jump to the 'o' extension, if it exists.</para>
 			<para><literal>*</literal> - Jump to the 'a' extension, if it exists.</para>
-			<para>This application will set the following channel variable before completion:</para>
-			<variablelist>
-				<variable name="DIRECTORY_RESULT">
-					<para>Reason Directory application exited.</para>
-					<value name="OPERATOR">User requested operator</value>
-					<value name="ASSISTANT">User requested assistant</value>
-					<value name="TIMEOUT">User allowed DTMF wait duration to pass without sending DTMF</value>
-					<value name="HANGUP">The channel hung up before the application finished</value>
-					<value name="SELECTED">User selected a user to call from the directory</value>
-					<value name="USEREXIT">User exited with '#' during selection</value>
-					<value name="FAILED">The application failed</value>
-				</variable>
-			</variablelist>
 		</description>
 	</application>
 
@@ -154,7 +135,6 @@ enum {
 	OPT_LISTBYEITHER =    OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
 	OPT_PAUSE =           (1 << 5),
 	OPT_NOANSWER =        (1 << 6),
-	OPT_ALIAS =           (1 << 7),
 };
 
 enum {
@@ -184,7 +164,6 @@ AST_APP_OPTIONS(directory_app_options, {
 	AST_APP_OPTION('v', OPT_FROMVOICEMAIL),
 	AST_APP_OPTION('m', OPT_SELECTFROMMENU),
 	AST_APP_OPTION('n', OPT_NOANSWER),
-	AST_APP_OPTION('a', OPT_ALIAS),
 });
 
 static int compare(const char *text, const char *template)
@@ -289,24 +268,18 @@ static int play_mailbox_owner(struct ast_channel *chan, const char *context,
 	const char *ext, const char *name, struct ast_flags *flags)
 {
 	int res = 0;
-	char *mailbox_id;
-
-	mailbox_id = ast_alloca(strlen(ext) + strlen(context) + 2);
-	sprintf(mailbox_id, "%s@%s", ext, context); /* Safe */
-
-	res = ast_app_sayname(chan, mailbox_id);
-	if (res >= 0) {
+	if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
 		ast_stopstream(chan);
 		/* If Option 'e' was specified, also read the extension number with the name */
 		if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
 			ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
-			res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
+			res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan));
 		}
 	} else {
-		res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
+		res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, ast_channel_language(chan));
 		if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) {
 			ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
-			res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
+			res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan));
 		}
 	}
 
@@ -328,7 +301,6 @@ static int select_entry(struct ast_channel *chan, const char *dialcontext, const
 		return -1;
 	}
 
-	pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "SELECTED");
 	return 0;
 }
 
@@ -369,7 +341,6 @@ static int select_item_seq(struct ast_channel *chan, struct directory_item **ite
 	
 			if (res == '0') { /* operator selected */
 				goto_exten(chan, dialcontext, "o");
-				pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "OPERATOR");
 				return '0';
 			} else if (res == '1') { /* Name selected */
 				return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
@@ -378,7 +349,6 @@ static int select_item_seq(struct ast_channel *chan, struct directory_item **ite
 				break;
 			} else if (res == '#') {
 				/* Exit reading, continue in dialplan */
-				pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "USEREXIT");
 				return res;
 			}
 
@@ -444,7 +414,6 @@ static int select_item_menu(struct ast_channel *chan, struct directory_item **it
 		}
 
 		if (res && res > '0' && res < '1' + limit) {
-			pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "SELECTED");
 			return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
 		}
 
@@ -458,23 +427,17 @@ static int select_item_menu(struct ast_channel *chan, struct directory_item **it
 	return 0;
 }
 
-AST_THREADSTORAGE(commonbuf);
-
 static struct ast_config *realtime_directory(char *context)
 {
 	struct ast_config *cfg;
-	struct ast_config *rtdata = NULL;
+	struct ast_config *rtdata;
 	struct ast_category *cat;
 	struct ast_variable *var;
 	char *mailbox;
 	const char *fullname;
 	const char *hidefromdir, *searchcontexts = NULL;
+	char tmp[100];
 	struct ast_flags config_flags = { 0 };
-	struct ast_str *tmp = ast_str_thread_get(&commonbuf, 100);
-
-	if (!tmp) {
-		return NULL;
-	}
 
 	/* Load flat file config. */
 	cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
@@ -498,7 +461,7 @@ static struct ast_config *realtime_directory(char *context)
 			rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
 			context = "default";
 		}
-	} else if (!ast_strlen_zero(context)) {
+	} else {
 		rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
 	}
 
@@ -509,7 +472,6 @@ static struct ast_config *realtime_directory(char *context)
 
 	mailbox = NULL;
 	while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
-		struct ast_variable *alias;
 		const char *ctx = ast_variable_retrieve(rtdata, mailbox, "context");
 
 		fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
@@ -518,17 +480,10 @@ static struct ast_config *realtime_directory(char *context)
 			/* Skip hidden */
 			continue;
 		}
-		ast_str_set(&tmp, 0, "no-password,%s", S_OR(fullname, ""));
-		if (ast_variable_retrieve(rtdata, mailbox, "alias")) {
-			for (alias = ast_variable_browse(rtdata, mailbox); alias; alias = alias->next) {
-				if (!strcasecmp(alias->name, "alias")) {
-					ast_str_append(&tmp, 0, "|alias=%s", alias->value);
-				}
-			}
-		}
+		snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
 
 		/* Does the context exist within the config file? If not, make one */
-		if (!(cat = ast_category_get(cfg, ctx, NULL))) {
+		if (!(cat = ast_category_get(cfg, ctx))) {
 			if (!(cat = ast_category_new(ctx, "", 99999))) {
 				ast_log(LOG_WARNING, "Out of memory\n");
 				ast_config_destroy(cfg);
@@ -540,7 +495,7 @@ static struct ast_config *realtime_directory(char *context)
 			ast_category_append(cfg, cat);
 		}
 
-		if ((var = ast_variable_new(mailbox, ast_str_buffer(tmp), ""))) {
+		if ((var = ast_variable_new(mailbox, tmp, ""))) {
 			ast_variable_append(cat, var);
 		} else {
 			ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
@@ -601,26 +556,20 @@ typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
 static int search_directory_sub(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
 {
 	struct ast_variable *v;
-	struct ast_str *buf = ast_str_thread_get(&commonbuf, 100);
-	char *pos, *bufptr, *cat, *alias;
+	char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
 	struct directory_item *item;
 	int res;
 
-	if (!buf) {
-		return -1;
-	}
-
 	ast_debug(2, "Pattern: %s\n", ext);
 
 	for (v = ast_variable_browse(vmcfg, context); v; v = v->next) {
 
 		/* Ignore hidden */
-		if (strcasestr(v->value, "hidefromdir=yes")) {
+		if (strcasestr(v->value, "hidefromdir=yes"))
 			continue;
-		}
 
-		ast_str_set(&buf, 0, "%s", v->value);
-		bufptr = ast_str_buffer(buf);
+		ast_copy_string(buf, v->value, sizeof(buf));
+		bufptr = buf;
 
 		/* password,Full Name,email,pager,options */
 		strsep(&bufptr, ",");
@@ -638,23 +587,11 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s
 		if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
 			res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
 		}
-		if (!res && ast_test_flag(&flags, OPT_ALIAS) && (alias = strcasestr(bufptr, "alias="))) {
-			char *a;
-			ast_debug(1, "Found alias: %s\n", alias);
-			while ((a = strsep(&alias, "|"))) {
-				if (!strncasecmp(a, "alias=", 6)) {
-					if ((res = check_match(&item, context, a + 6, v->name, ext, 1))) {
-						break;
-					}
-				}
-			}
-		}
 
-		if (!res) {
+		if (!res)
 			continue;
-		} else if (res < 0) {
+		else if (res < 0)
 			return -1;
-		}
 
 		AST_LIST_INSERT_TAIL(alist, item, entry);
 	}
@@ -662,18 +599,15 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s
 	if (ucfg) {
 		for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
 			const char *position;
-
-			if (!strcasecmp(cat, "general")) {
+			if (!strcasecmp(cat, "general"))
 				continue;
-			}
-			if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) {
+			if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
 				continue;
-			}
 
 			/* Find all candidate extensions */
-			if (!(position = ast_variable_retrieve(ucfg, cat, "fullname"))) {
+			position = ast_variable_retrieve(ucfg, cat, "fullname");
+			if (!position)
 				continue;
-			}
 
 			res = 0;
 			if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
@@ -682,20 +616,11 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s
 			if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
 				res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
 			}
-			if (!res && ast_test_flag(&flags, OPT_ALIAS)) {
-				struct ast_variable *alias;
-				for (alias = ast_variable_browse(ucfg, cat); alias; alias = alias->next) {
-					if (!strcasecmp(v->name, "alias") && (res = check_match(&item, context, v->value, cat, ext, 1))) {
-						break;
-					}
-				}
-			}
 
-			if (!res) {
+			if (!res)
 				continue;
-			} else if (res < 0) {
+			else if (res < 0)
 				return -1;
-			}
 
 			AST_LIST_INSERT_TAIL(alist, item, entry);
 		}
@@ -764,12 +689,10 @@ static int do_directory(struct ast_channel *chan, struct ast_config *vmcfg, stru
 	char ext[10] = "";
 
 	if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
-		pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "OPERATOR");
 		return digit;
 	}
 
 	if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
-		pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "ASSISTANT");
 		return digit;
 	}
 
@@ -934,12 +857,8 @@ static int directory_exec(struct ast_channel *chan, const char *data)
 		if (!res)
 			res = ast_waitfordigit(chan, 5000);
 
-		if (res <= 0) {
-			if (res == 0) {
-				pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "TIMEOUT");
-			}
+		if (res <= 0)
 			break;
-		}
 
 		res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, digit, &flags, opts);
 		if (res)
@@ -947,22 +866,15 @@ static int directory_exec(struct ast_channel *chan, const char *data)
 
 		res = ast_waitstream(chan, AST_DIGIT_ANY);
 		ast_stopstream(chan);
-		if (res < 0) {
+
+		if (res)
 			break;
-		}
 	}
 
 	if (ucfg)
 		ast_config_destroy(ucfg);
 	ast_config_destroy(cfg);
 
-	if (ast_check_hangup(chan)) {
-		pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "HANGUP");
-	} else if (res < 0) {
-		/* If the res < 0 and we didn't hangup, an unaccounted for error must have happened. */
-		pbx_builtin_setvar_helper(chan, "DIRECTORY_RESULT", "FAILED");
-	}
-
 	return res < 0 ? -1 : 0;
 }
 
diff --git a/apps/app_disa.c b/apps/app_disa.c
index d1c4336..c43370c 100644
--- a/apps/app_disa.c
+++ b/apps/app_disa.c
@@ -27,13 +27,12 @@
  */
 
 /*** MODULEINFO
-	<use type="module">app_cdr</use>
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 404295 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 #include <sys/time.h>
@@ -363,7 +362,7 @@ static int disa_exec(struct ast_channel *chan, const char *data)
 
 	if (k == 3) {
 		int recheck = 0;
-		struct ast_app *app_reset_cdr;
+		struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };
 
 		if (!ast_exists_extension(chan, args.context, exten, 1,
 			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
@@ -382,18 +381,11 @@ static int disa_exec(struct ast_channel *chan, const char *data)
 				ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
 			}
 
-			if (!ast_strlen_zero(acctcode)) {
-				ast_channel_lock(chan);
+			if (!ast_strlen_zero(acctcode))
 				ast_channel_accountcode_set(chan, acctcode);
-				ast_channel_unlock(chan);
-			}
 
-			app_reset_cdr = pbx_findapp("ResetCDR");
-			if (app_reset_cdr) {
-				pbx_exec(chan, app_reset_cdr, special_noanswer ? "" : "e");
-			} else {
-				ast_log(AST_LOG_NOTICE, "ResetCDR application not found; CDR will not be reset\n");
-			}
+			if (special_noanswer) cdr_flags.flags = 0;
+			ast_cdr_reset(ast_channel_cdr(chan), &cdr_flags);
 			ast_explicit_goto(chan, args.context, exten, 1);
 			return 0;
 		}
diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c
index dd009e3..83ceef5 100644
--- a/apps/app_dumpchan.c
+++ b/apps/app_dumpchan.c
@@ -34,14 +34,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
 #include "asterisk/translate.h"
-#include "asterisk/bridge.h"
 
 /*** DOCUMENTATION
 	<application name="DumpChan" language="en_US">
@@ -70,27 +69,26 @@ static const char app[] = "DumpChan";
 
 static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 {
+	struct timeval now;
 	long elapsed_seconds = 0;
 	int hour = 0, min = 0, sec = 0;
-	struct ast_str *format_buf = ast_str_alloca(64);
+	char nf[256];
 	char cgrp[256];
 	char pgrp[256];
 	struct ast_str *write_transpath = ast_str_alloca(256);
 	struct ast_str *read_transpath = ast_str_alloca(256);
-	struct ast_bridge *bridge;
 
+	now = ast_tvnow();
 	memset(buf, 0, size);
 	if (!c)
 		return 0;
 
-	elapsed_seconds = ast_channel_get_duration(c);
-	hour = elapsed_seconds / 3600;
-	min = (elapsed_seconds % 3600) / 60;
-	sec = elapsed_seconds % 60;
-
-	ast_channel_lock(c);
-	bridge = ast_channel_get_bridge(c);
-	ast_channel_unlock(c);
+	if (ast_channel_cdr(c)) {
+		elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
+		hour = elapsed_seconds / 3600;
+		min = (elapsed_seconds % 3600) / 60;
+		sec = elapsed_seconds % 60;
+	}
 
 	snprintf(buf,size,
 		"Name=               %s\n"
@@ -119,7 +117,8 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 		"Framesout=          %u %s\n"
 		"TimetoHangup=       %ld\n"
 		"ElapsedTime=        %dh%dm%ds\n"
-		"BridgeID=           %s\n"
+		"DirectBridge=       %s\n"
+		"IndirectBridge=     %s\n"
 		"Context=            %s\n"
 		"Extension=          %s\n"
 		"Priority=           %d\n"
@@ -143,11 +142,11 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 		ast_state2str(ast_channel_state(c)),
 		ast_channel_state(c),
 		ast_channel_rings(c),
-		ast_format_cap_get_names(ast_channel_nativeformats(c), &format_buf),
-		ast_format_get_name(ast_channel_writeformat(c)),
-		ast_format_get_name(ast_channel_readformat(c)),
-		ast_format_get_name(ast_channel_rawwriteformat(c)),
-		ast_format_get_name(ast_channel_rawreadformat(c)),
+		ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)),
+		ast_getformatname(ast_channel_writeformat(c)),
+		ast_getformatname(ast_channel_readformat(c)),
+		ast_getformatname(ast_channel_rawwriteformat(c)),
+		ast_getformatname(ast_channel_rawreadformat(c)),
 		ast_channel_writetrans(c) ? "Yes" : "No",
 		ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
 		ast_channel_readtrans(c) ? "Yes" : "No",
@@ -159,7 +158,8 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 		hour,
 		min,
 		sec,
-		bridge ? bridge->uniqueid : "(Not bridged)",
+		ast_channel_internal_bridged_channel(c) ? ast_channel_name(ast_channel_internal_bridged_channel(c)) : "<none>",
+		ast_bridged_channel(c) ? ast_channel_name(ast_bridged_channel(c)) : "<none>",
 		ast_channel_context(c),
 		ast_channel_exten(c),
 		ast_channel_priority(c),
@@ -169,7 +169,6 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 		ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)",
 		(ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"));
 
-	ao2_cleanup(bridge);
 	return 0;
 }
 
diff --git a/apps/app_echo.c b/apps/app_echo.c
index 7b13862..df5a914 100644
--- a/apps/app_echo.c
+++ b/apps/app_echo.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/module.h"
@@ -58,6 +58,11 @@ static const char app[] = "Echo";
 static int echo_exec(struct ast_channel *chan, const char *data)
 {
 	int res = -1;
+	struct ast_format format;
+
+	ast_best_codec(ast_channel_nativeformats(chan), &format);
+	ast_set_write_format(chan, &format);
+	ast_set_read_format(chan, &format);
 
 	while (ast_waitfor(chan, -1) > -1) {
 		struct ast_frame *f = ast_read(chan);
diff --git a/apps/app_exec.c b/apps/app_exec.c
index 13d36a5..ab9a9ae 100644
--- a/apps/app_exec.c
+++ b/apps/app_exec.c
@@ -31,7 +31,7 @@
  ***/
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c
index 1affa18..765f5c9 100644
--- a/apps/app_externalivr.c
+++ b/apps/app_externalivr.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 
@@ -519,6 +519,8 @@ static int app_exec(struct ast_channel *chan, const char *data)
 			break;
 		}
 
+		ast_free(addrs);
+
 		if (i == num_addrs) {
 			ast_chan_log(LOG_ERROR, chan, "Could not connect to any host.  ExternalIVR failed.\n");
 			goto exit;
@@ -915,5 +917,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, app_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "External IVR Interface Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");
diff --git a/apps/app_fax.c b/apps/app_fax.c
index 62e1452..9d63a3c 100644
--- a/apps/app_fax.c
+++ b/apps/app_fax.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Simple fax applications
  * 
@@ -21,7 +21,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <string.h>
 #include <stdlib.h>
@@ -43,9 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/app.h"
 #include "asterisk/dsp.h"
 #include "asterisk/module.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
+#include "asterisk/manager.h"
 
 /*** DOCUMENTATION
 	<application name="SendFAX" language="en_US" module="app_fax">
@@ -204,9 +202,6 @@ static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uin
 
 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
 {
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json_filenames, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
 	const char *local_ident;
 	const char *far_ident;
 	char buf[20];
@@ -256,24 +251,32 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
 	ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
 	ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
 
-	json_filenames = ast_json_pack("[s]", s->file_name);
-	if (!json_filenames) {
-		return;
-	}
-	ast_json_ref(json_filenames);
-	json_object = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: i, s: o}",
-			"type", s->direction ? "send" : "receive",
-			"remote_station_id", far_ident,
-			"local_station_id", local_ident,
-			"fax_pages", pages_transferred,
-			"fax_resolution", stat.y_resolution,
-			"fax_bitrate", stat.bit_rate,
-			"filenames", json_filenames);
-	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(s->chan), ast_channel_fax_type(), json_object);
-	if (!message) {
-		return;
-	}
-	stasis_publish(ast_channel_topic(s->chan), message);
+	ast_manager_event(s->chan, EVENT_FLAG_CALL,
+		s->direction ? "FaxSent" : "FaxReceived",
+		"Channel: %s\r\n"
+		"Exten: %s\r\n"
+		"CallerID: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"RemoteStationID: %s\r\n"
+		"LocalStationID: %s\r\n"
+		"PagesTransferred: %d\r\n"
+		"Resolution: %d\r\n"
+		"TransferRate: %d\r\n"
+		"FileName: %s\r\n",
+		ast_channel_name(s->chan),
+		ast_channel_exten(s->chan),
+		S_COR(ast_channel_caller(s->chan)->id.number.valid, ast_channel_caller(s->chan)->id.number.str, ""),
+		S_COR(ast_channel_caller(s->chan)->id.name.valid, ast_channel_caller(s->chan)->id.name.str, ""),
+		S_COR(ast_channel_connected(s->chan)->id.number.valid, ast_channel_connected(s->chan)->id.number.str, ""),
+		S_COR(ast_channel_connected(s->chan)->id.name.valid, ast_channel_connected(s->chan)->id.name.str, ""),
+		far_ident,
+		local_ident,
+		pages_transferred,
+		stat.y_resolution,
+		stat.bit_rate,
+		s->file_name);
 }
 
 /* === Helper functions to configure fax === */
@@ -333,9 +336,9 @@ static int fax_generator_generate(struct ast_channel *chan, void *data, int len,
     
 	struct ast_frame outf = {
 		.frametype = AST_FRAME_VOICE,
-		.subclass.format = ast_format_slin,
 		.src = __FUNCTION__,
 	};
+	ast_format_set(&outf.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	if (samples > MAX_SAMPLES) {
 		ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
@@ -366,8 +369,8 @@ static struct ast_generator generator = {
 static int transmit_audio(fax_session *s)
 {
 	int res = -1;
-	struct ast_format *original_read_fmt;
-	struct ast_format *original_write_fmt = NULL;
+	struct ast_format original_read_fmt;
+	struct ast_format original_write_fmt;
 	fax_state_t fax;
 	t30_state_t *t30state;
 	struct ast_frame *inf = NULL;
@@ -387,6 +390,9 @@ static int transmit_audio(fax_session *s)
 */
 	};
 
+	ast_format_clear(&original_read_fmt);
+	ast_format_clear(&original_write_fmt);
+
 	/* if in called party mode, try to use T.38 */
 	if (s->caller_mode == FALSE) {
 		/* check if we are already in T.38 mode (unlikely), or if we can request
@@ -459,18 +465,22 @@ static int transmit_audio(fax_session *s)
         t30state = &fax.t30_state;
 #endif
 
-    original_read_fmt = ao2_bump(ast_channel_readformat(s->chan));
-	res = ast_set_read_format(s->chan, ast_format_slin);
-	if (res < 0) {
-		ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
-		goto done;
+	ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan));
+	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
+		res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+			goto done;
+		}
 	}
 
-	original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan));
-	res = ast_set_write_format(s->chan, ast_format_slin);
-	if (res < 0) {
-		ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
-		goto done;
+	ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan));
+	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
+		res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+			goto done;
+		}
 	}
 
 	/* Initialize T30 terminal */
@@ -523,13 +533,12 @@ static int transmit_audio(fax_session *s)
 			break;
 		}
 
-		ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen);
+		ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen);
 
 		/* Check the frame type. Format also must be checked because there is a chance
 		   that a frame in old format was already queued before we set channel format
 		   to slinear so it will still be received by ast_read */
-		if (inf->frametype == AST_FRAME_VOICE &&
-			(ast_format_cmp(inf->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+		if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) {
 			if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
 				/* I know fax_rx never returns errors. The check here is for good style only */
 				ast_log(LOG_WARNING, "fax_rx returned error\n");
@@ -583,16 +592,14 @@ static int transmit_audio(fax_session *s)
 	fax_release(&fax);
 
 done:
-	if (original_write_fmt) {
-		if (ast_set_write_format(s->chan, original_write_fmt) < 0)
+	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
+		if (ast_set_write_format(s->chan, &original_write_fmt) < 0)
 			ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan));
-		ao2_ref(original_write_fmt, -1);
 	}
 
-	if (original_read_fmt) {
-		if (ast_set_read_format(s->chan, original_read_fmt) < 0)
+	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
+		if (ast_set_read_format(s->chan, &original_read_fmt) < 0)
 			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan));
-		ao2_ref(original_read_fmt, -1);
 	}
 
 	return res;
@@ -996,7 +1003,6 @@ static int load_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		);
diff --git a/apps/app_festival.c b/apps/app_festival.c
index abee1c3..3f36301 100644
--- a/apps/app_festival.c
+++ b/apps/app_festival.c
@@ -27,22 +27,13 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_festival.c uses the configuration file \ref festival.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page festival.conf festival.conf
- * \verbinclude festival.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <netdb.h>
@@ -63,7 +54,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/lock.h"
 #include "asterisk/app.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define FESTIVAL_CONFIG "festival.conf"
 #define MAXLEN 180
@@ -178,7 +168,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
 	int res = 0;
 	int fds[2];
 	int needed = 0;
-	struct ast_format *owriteformat;
+	struct ast_format owriteformat;
 	struct ast_frame *f;
 	struct myframe {
 		struct ast_frame f;
@@ -188,6 +178,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
 		.f = { 0, },
 	};
 
+	ast_format_clear(&owriteformat);
 	if (pipe(fds)) {
 		ast_log(LOG_WARNING, "Unable to create pipe\n");
 		return -1;
@@ -199,19 +190,12 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
 	ast_stopstream(chan);
 	ast_indicate(chan, -1);
 	
-	owriteformat = ao2_bump(ast_channel_writeformat(chan));
-	res = ast_set_write_format(chan, ast_format_slin);
+	ast_format_copy(&owriteformat, ast_channel_writeformat(chan));
+	res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
 	if (res < 0) {
 		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
-		ao2_cleanup(owriteformat);
 		return -1;
 	}
-
-	myf.f.frametype = AST_FRAME_VOICE;
-	myf.f.subclass.format = ast_format_slin;
-	myf.f.offset = AST_FRIENDLY_OFFSET;
-	myf.f.src = __PRETTY_FUNCTION__;
-	myf.f.data.ptr = myf.frdata;
 	
 	res = send_waveform_to_fd(waveform, length, fds[1]);
 	if (res >= 0) {
@@ -247,8 +231,13 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
 				}
 				res = read(fds[0], myf.frdata, needed);
 				if (res > 0) {
+					myf.f.frametype = AST_FRAME_VOICE;
+					ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0);
 					myf.f.datalen = res;
 					myf.f.samples = res / 2;
+					myf.f.offset = AST_FRIENDLY_OFFSET;
+					myf.f.src = __PRETTY_FUNCTION__;
+					myf.f.data.ptr = myf.frdata;
 					if (ast_write(chan, &myf.f) < 0) {
 						res = -1;
 						ast_frfree(f);
@@ -271,10 +260,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
 	close(fds[0]);
 	close(fds[1]);
 
-	if (!res && owriteformat)
-		ast_set_write_format(chan, owriteformat);
-	ao2_cleanup(owriteformat);
-
+	if (!res && owriteformat.id)
+		ast_set_write_format(chan, &owriteformat);
 	return res;
 }
 
@@ -550,16 +537,6 @@ static int unload_module(void)
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	struct ast_flags config_flags = { 0 };
@@ -575,5 +552,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, festival_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Simple Festival Interface");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface");
diff --git a/apps/app_flash.c b/apps/app_flash.c
index 199878e..dbbad33 100644
--- a/apps/app_flash.c
+++ b/apps/app_flash.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 357721 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <dahdi/user.h>
 
diff --git a/apps/app_followme.c b/apps/app_followme.c
index e4c04cc..9f39c32 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * A full-featured Find-Me/Follow-Me Application
  * 
@@ -23,25 +23,19 @@
  *
  * \author BJ Weschke <bweschke at btwtech.com>
  *
+ * \arg See \ref Config_followme
+ *
  * \ingroup applications
  */
 
-/*! \li \ref app_followme.c uses the configuration file \ref followme.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page followme.conf followme.conf
- * \verbinclude followme.conf.sample
- */
-
 /*** MODULEINFO
+	<depend>chan_local</depend>
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 
@@ -63,7 +57,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/astdb.h"
 #include "asterisk/dsp.h"
 #include "asterisk/app.h"
-#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
 	<application name="FollowMe" language="en_US">
@@ -557,17 +550,6 @@ static int reload_followme(int reload)
 	return 1;
 }
 
-static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
-{
-	struct findme_user *tmpuser;
-
-	AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
-		if (tmpuser->ochan && tmpuser->ochan != exception) {
-			ast_channel_publish_dial(in, tmpuser->ochan, NULL, status);
-		}
-	}
-}
-
 static void clear_caller(struct findme_user *tmpuser)
 {
 	struct ast_channel *outbound;
@@ -578,6 +560,29 @@ static void clear_caller(struct findme_user *tmpuser)
 	}
 
 	outbound = tmpuser->ochan;
+	ast_channel_lock(outbound);
+	if (!ast_channel_cdr(outbound)) {
+		ast_channel_cdr_set(outbound, ast_cdr_alloc());
+		if (ast_channel_cdr(outbound)) {
+			ast_cdr_init(ast_channel_cdr(outbound), outbound);
+		}
+	}
+	if (ast_channel_cdr(outbound)) {
+		char tmp[256];
+
+		snprintf(tmp, sizeof(tmp), "Local/%s", tmpuser->dialarg);
+		ast_cdr_setapp(ast_channel_cdr(outbound), "FollowMe", tmp);
+		ast_cdr_update(outbound);
+		ast_cdr_start(ast_channel_cdr(outbound));
+		ast_cdr_end(ast_channel_cdr(outbound));
+		/* If the cause wasn't handled properly */
+		if (ast_cdr_disposition(ast_channel_cdr(outbound), ast_channel_hangupcause(outbound))) {
+			ast_cdr_failed(ast_channel_cdr(outbound));
+		}
+	} else {
+		ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
+	}
+	ast_channel_unlock(outbound);
 	ast_hangup(outbound);
 	tmpuser->ochan = NULL;
 }
@@ -766,7 +771,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
 						}
 						if (!tmpuser) {
 							ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
-							publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
 							ast_frfree(f);
 							return NULL;
 						}
@@ -778,8 +782,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
 							break;
 						}
 						ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
-						ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
-						publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
 						tmpuser->answered = 1;
 						/* If call has been answered, then the eventual hangup is likely to be normal hangup */ 
 						ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING);
@@ -807,7 +809,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
 						ast_verb(3, "%s is busy\n", ast_channel_name(winner));
 						if (tmpuser) {
 							/* Outbound call was busy.  Drop it. */
-							ast_channel_publish_dial(caller, winner, NULL, "BUSY");
 							clear_caller(tmpuser);
 						}
 						break;
@@ -815,7 +816,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
 						ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
 						if (tmpuser) {
 							/* Outbound call was congested.  Drop it. */
-							ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
 							clear_caller(tmpuser);
 						}
 						break;
@@ -964,7 +964,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
 					return NULL;
 				}
 				/* Outgoing channel hung up. */
-				ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
 				clear_caller(tmpuser);
 			}
 		} else {
@@ -1056,7 +1055,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
 						? "/n" : "/m");
 			}
 
-			outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller,
+			outbound = ast_request("Local", ast_channel_nativeformats(caller), caller,
 				tmpuser->dialarg, &dg);
 			if (!outbound) {
 				ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
@@ -1070,7 +1069,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
 			ast_channel_inherit_variables(caller, outbound);
 			ast_channel_datastore_inherit(caller, outbound);
 			ast_channel_language_set(outbound, ast_channel_language(caller));
-			ast_channel_req_accountcodes(outbound, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
+			ast_channel_accountcode_set(outbound, ast_channel_accountcode(caller));
 			ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
 			ast_channel_unlock(outbound);
 			ast_channel_unlock(caller);
@@ -1104,6 +1103,11 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
 				 * Destoy all new outgoing calls.
 				 */
 				while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
+					ast_channel_lock(tmpuser->ochan);
+					if (ast_channel_cdr(tmpuser->ochan)) {
+						ast_cdr_init(ast_channel_cdr(tmpuser->ochan), tmpuser->ochan);
+					}
+					ast_channel_unlock(tmpuser->ochan);
 					destroy_calling_node(tmpuser);
 				}
 
@@ -1125,11 +1129,13 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
 				AST_LIST_REMOVE_CURRENT(entry);
 
 				/* Destroy this failed new outgoing call. */
+				ast_channel_lock(tmpuser->ochan);
+				if (ast_channel_cdr(tmpuser->ochan)) {
+					ast_cdr_init(ast_channel_cdr(tmpuser->ochan), tmpuser->ochan);
+				}
+				ast_channel_unlock(tmpuser->ochan);
 				destroy_calling_node(tmpuser);
-				continue;
 			}
-
-			ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
 
@@ -1277,10 +1283,15 @@ static void end_bridge_callback(void *data)
 	time(&end);
 
 	ast_channel_lock(chan);
-	snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
-	pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
-	snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
-	pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
+	if (ast_channel_cdr(chan)->answer.tv_sec) {
+		snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->answer.tv_sec);
+		pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
+	}
+
+	if (ast_channel_cdr(chan)->start.tv_sec) {
+		snprintf(buf, sizeof(buf), "%ld", (long) end - ast_channel_cdr(chan)->start.tv_sec);
+		pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
+	}
 	ast_channel_unlock(chan);
 }
 
@@ -1424,7 +1435,7 @@ static int app_exec(struct ast_channel *chan, const char *data)
 			if (ast_waitstream(chan, "") < 0)
 				goto outrun;
 		}
-		ast_moh_start(chan, targs->mohclass, NULL);
+		ast_moh_start(chan, S_OR(targs->mohclass, NULL), NULL);
 	}
 
 	ast_channel_lock(chan);
@@ -1502,6 +1513,7 @@ static int app_exec(struct ast_channel *chan, const char *data)
 		}
 
 		res = ast_bridge_call(caller, outbound, &config);
+		ast_autoservice_chan_hangup_peer(caller, outbound);
 	}
 
 outrun:
@@ -1543,16 +1555,6 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if(!reload_followme(0))
@@ -1569,7 +1571,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c
index ad060c5..558b114 100644
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -40,52 +40,102 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/cdr.h"
 #include "asterisk/app.h"
 #include "asterisk/module.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
 
 /*** DOCUMENTATION
 	<application name="ForkCDR" language="en_US">
 		<synopsis>
-			Forks the current Call Data Record for this channel.
+			Forks the Call Data Record.
 		</synopsis>
 		<syntax>
 			<parameter name="options">
 				<optionlist>
 					<option name="a">
-						<para>If the channel is answered, set the answer time on
-						the forked CDR to the current time. If this option is
-						not used, the answer time on the forked CDR will be the
-						answer time on the original CDR. If the channel is not
-						answered, this option has no effect.</para>
-						<para>Note that this option is implicitly assumed if the
-						<literal>r</literal> option is used.</para>
+						<para>Update the answer time on the NEW CDR just after it's been inited.
+						The new CDR may have been answered already. The reset that forkcdr does
+						will erase the answer time. This will bring it back, but the answer time
+						will be a copy of the fork/start time. It will only do this if the initial
+						cdr was indeed already answered.</para>
+					</option>
+					<option name="A">
+						<para>Lock the original CDR against the answer time being updated. This
+						will allow the disposition on the original CDR to remain the same.</para>
+					</option>
+					<option name="d">
+						<para>Copy the disposition forward from the old cdr, after the init.</para>
+					</option>
+					<option name="D">
+						<para>Clear the <literal>dstchannel</literal> on the new CDR after
+						reset.</para>
 					</option>
 					<option name="e">
-						<para>End (finalize) the original CDR.</para>
+						<para>End the original CDR. Do this after all the necessary data is copied
+						from the original CDR to the new forked CDR.</para>
 					</option>
 					<option name="r">
-						<para>Reset the start and answer times on the forked CDR.
-						This will set the start and answer times (if the channel
-						is answered) to be set to the current time.</para>
-						<para>Note that this option implicitly assumes the
-						<literal>a</literal> option.</para>
+						<para>Do <emphasis>NOT</emphasis> reset the new cdr.</para>
+					</option>
+					<option name="s(name=val)">
+						<para>Set the CDR var <replaceable>name</replaceable> in the original CDR,
+						with value <replaceable>val</replaceable>.</para>
+					</option>
+					<option name="T">
+						<para>Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end
+						cdr funcs will obey this flag; normally they don't honor the LOCKED flag
+						set on the original CDR record.</para>
+						<note><para>Using this flag may cause CDR's not to have their end times
+						updated! It is suggested that if you specify this flag, you might wish
+						to use the <literal>e</literal> flag as well!.</para></note>
 					</option>
 					<option name="v">
-						<para>Do not copy CDR variables and attributes from the
-						original CDR to the forked CDR.</para>
-						<warning><para>This option has changed. Previously, the
-						variables were removed from the original CDR. This no
-						longer occurs - this option now controls whether or not
-						a forked CDR inherits the variables from the original
-						CDR.</para></warning>
+						<para>When the new CDR is forked, it gets a copy of the vars attached to
+						the current CDR. The vars attached to the original CDR are removed unless
+						this option is specified.</para>
 					</option>
 				</optionlist>
 			</parameter>
 		</syntax>
 		<description>
-			<para>Causes the Call Data Record engine to fork a new CDR starting
-			from the time the application is executed. The forked CDR will be
-			linked to the end of the CDRs associated with the channel.</para>
+			<para> Causes the Call Data Record to fork an additional cdr record starting from the time
+			of the fork call. This new cdr record will be linked to end of the list of cdr records attached
+			to the channel.	The original CDR has a LOCKED flag set, which forces most cdr operations to skip
+			it, except for the functions that set the answer and end times, which ignore the LOCKED flag. This
+			allows all the cdr records in the channel to be 'ended' together when the channel is closed.</para>
+			<para>The CDR() func (when setting CDR values) normally ignores the LOCKED flag also, but has options
+			to vary its behavior. The 'T' option (described below), can override this behavior, but beware
+			the risks.</para>
+			<para>First, this app finds the last cdr record in the list, and makes a copy of it. This new copy
+			will be the newly forked cdr record. Next, this new record is linked to the end of the cdr record list.
+			Next, The new cdr record is RESET (unless you use an option to prevent this)</para>
+			<para>This means that:</para>
+			<para>   1. All flags are unset on the cdr record</para>
+			<para>   2. the start, end, and answer times are all set to zero.</para>
+			<para>   3. the billsec and duration fields are set to zero.</para>
+			<para>   4. the start time is set to the current time.</para>
+			<para>   5. the disposition is set to NULL.</para>
+			<para>Next, unless you specified the <literal>v</literal> option, all variables will be removed from
+			the original cdr record. Thus, the <literal>v</literal> option allows any CDR variables to be replicated
+			to all new forked cdr records. Without the <literal>v</literal> option, the variables on the original
+			are effectively moved to the new forked cdr record.</para>
+			<para>Next, if the <literal>s</literal> option is set, the provided variable and value are set on the
+			original cdr record.</para>
+			<para>Next, if the <literal>a</literal> option is given, and the original cdr record has an answer time
+			set, then the new forked cdr record will have its answer time set to its start time. If the old answer
+			time were carried forward, the answer time would be earlier than the start time, giving strange
+			duration and billsec times.</para>
+			<para>If the <literal>d</literal> option was specified, the disposition is copied from
+			the original cdr record to the new forked cdr. If the <literal>D</literal> option was specified,
+			the destination channel field in the new forked CDR is erased. If the <literal>e</literal> option
+			was specified, the 'end' time for the original cdr record is set to the current time. Future hang-up or
+			ending events will not override this time stamp. If the <literal>A</literal> option is specified,
+			the original cdr record will have it ANS_LOCKED flag set, which prevent future answer events from updating
+			the original cdr record's disposition. Normally, an <literal>ANSWERED</literal> event would mark all cdr
+			records in the chain as <literal>ANSWERED</literal>. If the <literal>T</literal> option is specified,
+			the original cdr record will have its <literal>DONT_TOUCH</literal> flag set, which will force the
+			cdr_answer, cdr_end, and cdr_setvar functions to leave that cdr record alone.</para>
+			<para>And, last but not least, the original cdr record has its LOCKED flag set. Almost all internal
+			CDR functions (except for the funcs that set the end, and answer times, and set a variable) will honor
+			this flag and leave a LOCKED cdr record alone. This means that the newly created forked cdr record
+			will be affected by events transpiring within Asterisk, with the previously noted exceptions.</para>
 		</description>
 		<see-also>
 			<ref type="function">CDR</ref>
@@ -97,122 +147,140 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 
 static char *app = "ForkCDR";
 
-AST_APP_OPTIONS(forkcdr_exec_options, {
-	AST_APP_OPTION('a', AST_CDR_FLAG_SET_ANSWER),
-	AST_APP_OPTION('e', AST_CDR_FLAG_FINALIZE),
-	AST_APP_OPTION('r', AST_CDR_FLAG_RESET),
-	AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
-});
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(forkcdr_message_type);
+enum {
+	OPT_SETANS =            (1 << 0),
+	OPT_SETDISP =           (1 << 1),
+	OPT_RESETDEST =         (1 << 2),
+	OPT_ENDCDR =            (1 << 3),
+	OPT_NORESET =           (1 << 4),
+	OPT_KEEPVARS =          (1 << 5),
+	OPT_VARSET =            (1 << 6),
+	OPT_ANSLOCK =           (1 << 7),
+	OPT_DONTOUCH =          (1 << 8),
+};
 
-/*! \internal \brief Message payload for the Stasis message sent to fork the CDR */
-struct fork_cdr_message_payload {
-	/*! The name of the channel whose CDR will be forked */
-	const char *channel_name;
-	/*! Option flags that control how the CDR will be forked */
-	struct ast_flags *flags;
+enum {
+	OPT_ARG_VARSET = 0,
+	/* note: this entry _MUST_ be the last one in the enum */
+	OPT_ARG_ARRAY_SIZE,
 };
 
-static void forkcdr_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+AST_APP_OPTIONS(forkcdr_exec_options, {
+	AST_APP_OPTION('a', OPT_SETANS),
+	AST_APP_OPTION('A', OPT_ANSLOCK),
+	AST_APP_OPTION('d', OPT_SETDISP),
+	AST_APP_OPTION('D', OPT_RESETDEST),
+	AST_APP_OPTION('e', OPT_ENDCDR),
+	AST_APP_OPTION('R', OPT_NORESET),
+	AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
+	AST_APP_OPTION('T', OPT_DONTOUCH),
+	AST_APP_OPTION('v', OPT_KEEPVARS),
+});
+
+static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) 
 {
-	struct fork_cdr_message_payload *payload;
+	struct ast_cdr *cdr;
+	struct ast_cdr *newcdr;
+	struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
 
-	if (stasis_message_type(message) != forkcdr_message_type()) {
-		return;
-	}
+	cdr = ast_channel_cdr(chan);
 
-	payload = stasis_message_data(message);
-	if (!payload) {
+	while (cdr->next)
+		cdr = cdr->next;
+	
+	if (!(newcdr = ast_cdr_dup_unique(cdr)))
 		return;
+	
+	/*
+	 * End the original CDR if requested BEFORE appending the new CDR
+	 * otherwise we incorrectly end the new CDR also.
+	 */
+	if (ast_test_flag(&optflags, OPT_ENDCDR)) {
+		ast_cdr_end(cdr);
 	}
 
-	if (ast_cdr_fork(payload->channel_name, payload->flags)) {
-		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s\n",
-			payload->channel_name);
+	ast_cdr_append(cdr, newcdr);
+
+	if (!ast_test_flag(&optflags, OPT_NORESET))
+		ast_cdr_reset(newcdr, &flags);
+		
+	if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
+		ast_cdr_free_vars(cdr, 0);
+	
+	if (!ast_strlen_zero(set)) {
+		char *varname = ast_strdupa(set), *varval;
+		varval = strchr(varname,'=');
+		if (varval) {
+			*varval = 0;
+			varval++;
+			ast_cdr_setvar(cdr, varname, varval, 0);
+		}
 	}
+	
+	if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer))
+		newcdr->answer = newcdr->start;
+
+	if (ast_test_flag(&optflags, OPT_SETDISP))
+		newcdr->disposition = cdr->disposition;
+	
+	if (ast_test_flag(&optflags, OPT_RESETDEST))
+		newcdr->dstchannel[0] = 0;
+	
+	if (ast_test_flag(&optflags, OPT_ANSLOCK))
+		ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED);
+	
+	if (ast_test_flag(&optflags, OPT_DONTOUCH))
+		ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH);
+		
+	ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
 }
 
 static int forkcdr_exec(struct ast_channel *chan, const char *data)
 {
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct fork_cdr_message_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-
-	char *parse;
-	struct ast_flags flags = { 0, };
-	AST_DECLARE_APP_ARGS(args,
+	int res = 0;
+	char *argcopy = NULL;
+	struct ast_cdr *cdr;
+	struct ast_flags flags = {0};
+	char *opts[OPT_ARG_ARRAY_SIZE];
+	AST_DECLARE_APP_ARGS(arglist,
 		AST_APP_ARG(options);
 	);
 
-	parse = ast_strdupa(data);
+	if (!(cdr = ast_channel_cdr(chan))) {
+		ast_log(LOG_WARNING, "Channel does not have a CDR\n");
+		return 0;
+	}
 
-	AST_STANDARD_APP_ARGS(args, parse);
+	argcopy = ast_strdupa(data);
 
-	if (!ast_strlen_zero(args.options)) {
-		ast_app_parse_options(forkcdr_exec_options, &flags, NULL, args.options);
-	}
+	AST_STANDARD_APP_ARGS(arglist, argcopy);
 
-	if (!forkcdr_message_type()) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message type\n",
-			ast_channel_name(chan));
-		return -1;
-	}
+	opts[OPT_ARG_VARSET] = 0;
 
-	payload = ao2_alloc(sizeof(*payload), NULL);
-	if (!payload) {
-		return -1;
-	}
+	if (!ast_strlen_zero(arglist.options))
+		ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options);
 
-	if (!router) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
-			ast_channel_name(chan));
-		return -1;
+	if (!ast_strlen_zero(data)) {
+		int keepvars = ast_test_flag(&flags, OPT_KEEPVARS) ? 1 : 0;
+		while (cdr->next) {
+			cdr = cdr->next;
+		}
+		ast_set2_flag(cdr, keepvars, AST_CDR_FLAG_KEEP_VARS);
 	}
 
-	payload->channel_name = ast_channel_name(chan);
-	payload->flags = &flags;
-	message = stasis_message_create(forkcdr_message_type(), payload);
-	if (!message) {
-		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s: unable to create message\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-	stasis_message_router_publish_sync(router, message);
+	ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
 
-	return 0;
+	return res;
 }
 
 static int unload_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-
-	if (router) {
-		stasis_message_router_remove(router, forkcdr_message_type());
-	}
-	STASIS_MESSAGE_TYPE_CLEANUP(forkcdr_message_type);
-	ast_unregister_application(app);
-	return 0;
+	return ast_unregister_application(app);
 }
 
 static int load_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-	int res = 0;
-
-	if (!router) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(forkcdr_message_type);
-	res |= ast_register_application_xml(app, forkcdr_exec);
-	res |= stasis_message_router_add(router, forkcdr_message_type(),
-	                                 forkcdr_callback, NULL);
-
-	if (res) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
+	return ast_register_application_xml(app, forkcdr_exec);
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");
diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c
index 6f3029f..0fea0ed 100644
--- a/apps/app_getcpeid.c
+++ b/apps/app_getcpeid.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -87,9 +87,8 @@ static int cpeid_exec(struct ast_channel *chan, const char *idata)
 		res = ast_adsi_get_cpeid(chan, cpeid, 0);
 		if (res > 0) {
 			gotcpeid = 1;
-			ast_verb(3, "Got CPEID of '%02x:%02x:%02x:%02x' on '%s'\n",
-				(unsigned)cpeid[0], (unsigned)cpeid[1], (unsigned)cpeid[2],
-				(unsigned)cpeid[3], ast_channel_name(chan));
+			ast_verb(3, "Got CPEID of '%02hhx:%02hhx:%02hhx:%02hhx' on '%s'\n",
+				cpeid[0], cpeid[1], cpeid[2], cpeid[3], ast_channel_name(chan));
 		}
 		if (res > -1) {
 			strcpy(data[1], "Measuring CPE...");
@@ -103,9 +102,8 @@ static int cpeid_exec(struct ast_channel *chan, const char *idata)
 		}
 		if (res > -1) {
 			if (gotcpeid)
-				snprintf(data[1], 80, "CPEID: %02x:%02x:%02x:%02x",
-					(unsigned)cpeid[0], (unsigned)cpeid[1],
-					(unsigned)cpeid[2], (unsigned)cpeid[3]);
+				snprintf(data[1], 80, "CPEID: %02hhx:%02hhx:%02hhx:%02hhx",
+					cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
 			else
 				strcpy(data[1], "CPEID Unknown");
 			if (gotgeometry) 
@@ -141,7 +139,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get ADSI CPE ID",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.nonoptreq = "res_adsi",
diff --git a/apps/app_ices.c b/apps/app_ices.c
index c4d90ef..3ed5227 100644
--- a/apps/app_ices.c
+++ b/apps/app_ices.c
@@ -22,7 +22,7 @@
  *
  * \author Mark Spencer <markster at digium.com>
  * 
- * ICES - http://www.icecast.org/ices.php
+ * \extref ICES - http://www.icecast.org/ices.php
  *
  * \ingroup applications
  */
@@ -33,7 +33,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 #include <fcntl.h>
@@ -48,7 +48,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="ICES" language="en_US">
@@ -116,11 +115,12 @@ static int ices_exec(struct ast_channel *chan, const char *data)
 	int ms = -1;
 	int pid = -1;
 	int flags;
-	struct ast_format *oreadformat;
+	struct ast_format oreadformat;
 	struct ast_frame *f;
 	char filename[256]="";
 	char *c;
 
+	ast_format_clear(&oreadformat);
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
 		return -1;
@@ -145,13 +145,12 @@ static int ices_exec(struct ast_channel *chan, const char *data)
 		return -1;
 	}
 
-	oreadformat = ao2_bump(ast_channel_readformat(chan));
-	res = ast_set_read_format(chan, ast_format_slin);
+	ast_format_copy(&oreadformat, ast_channel_readformat(chan));
+	res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
 	if (res < 0) {
 		close(fds[0]);
 		close(fds[1]);
 		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
-		ao2_cleanup(oreadformat);
 		return -1;
 	}
 	if (((char *)data)[0] == '/')
@@ -198,9 +197,8 @@ static int ices_exec(struct ast_channel *chan, const char *data)
 
 	if (pid > -1)
 		kill(pid, SIGKILL);
-	if (!res && oreadformat)
-		ast_set_read_format(chan, oreadformat);
-	ao2_cleanup(oreadformat);
+	if (!res && oreadformat.id)
+		ast_set_read_format(chan, &oreadformat);
 
 	return res;
 }
@@ -215,5 +213,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, ices_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");
diff --git a/apps/app_image.c b/apps/app_image.c
index c03976a..160a285 100644
--- a/apps/app_image.c
+++ b/apps/app_image.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
@@ -106,5 +106,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, sendimage_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Image Transmission Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Image Transmission Application");
diff --git a/apps/app_ivrdemo.c b/apps/app_ivrdemo.c
index 4f0913a..099c67d 100644
--- a/apps/app_ivrdemo.c
+++ b/apps/app_ivrdemo.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -126,5 +126,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, skel_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "IVR Demo Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application");
diff --git a/apps/app_jack.c b/apps/app_jack.c
index 7f37e24..f32c59f 100644
--- a/apps/app_jack.c
+++ b/apps/app_jack.c
@@ -42,7 +42,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <limits.h>
 
@@ -58,12 +58,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/app.h"
 #include "asterisk/pbx.h"
 #include "asterisk/audiohook.h"
-#include "asterisk/format_cache.h"
 
 #define RESAMPLE_QUALITY 1
 
-/* The number of frames the ringbuffers can store. The actual size is RINGBUFFER_FRAME_CAPACITY * jack_data->frame_datalen */
-#define RINGBUFFER_FRAME_CAPACITY 100
+#define RINGBUFFER_SIZE 16384
 
 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
 #define COMMON_OPTIONS \
@@ -130,9 +128,6 @@ struct jack_data {
 	jack_port_t *output_port;
 	jack_ringbuffer_t *input_rb;
 	jack_ringbuffer_t *output_rb;
-	struct ast_format *audiohook_format;
-	unsigned int audiohook_rate;
-	unsigned int frame_datalen;
 	void *output_resampler;
 	double output_resample_factor;
 	void *input_resampler;
@@ -206,8 +201,10 @@ static int alloc_resampler(struct jack_data *jack_data, int input)
 
 	jack_srate = jack_get_sample_rate(jack_data->client);
 
-	to_srate = input ? jack_data->audiohook_rate : jack_srate;
-	from_srate = input ? jack_srate : jack_data->audiohook_rate;
+	/* XXX Hard coded 8 kHz */
+
+	to_srate = input ? 8000.0 : jack_srate;
+	from_srate = input ? jack_srate : 8000.0;
 
 	resample_factor = input ? &jack_data->input_resample_factor :
 		&jack_data->output_resample_factor;
@@ -292,7 +289,7 @@ static void handle_input(void *buf, jack_nframes_t nframes,
 
 	res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
 	if (res != write_len) {
-		ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
+		ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
 			(int) sizeof(s_buf), (int) res);
 	}
 }
@@ -395,25 +392,6 @@ static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
 	jack_status_t status = 0;
 	jack_options_t jack_options = JackNullOption;
 
-	unsigned int channel_rate;
-
-	unsigned int ringbuffer_size;
-
-	/* Deducing audiohook sample rate from channel format
-	   ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
-	*/
-	channel_rate = ast_format_get_sample_rate(ast_channel_readformat(chan));
-	jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate);
-	jack_data->audiohook_rate = ast_format_get_sample_rate(jack_data->audiohook_format);
-
-	/* Guessing frame->datalen assuming a ptime of 20ms */
-	jack_data->frame_datalen = jack_data->audiohook_rate / 50;
-
-	ringbuffer_size = jack_data->frame_datalen * RINGBUFFER_FRAME_CAPACITY;
-
-	ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
-	    ast_format_get_name(jack_data->audiohook_format), jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size);
-
 	if (!ast_strlen_zero(jack_data->client_name)) {
 		client_name = jack_data->client_name;
 	} else {
@@ -422,10 +400,10 @@ static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
 		ast_channel_unlock(chan);
 	}
 
-	if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
+	if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
 		return -1;
 
-	if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
+	if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
 		return -1;
 
 	if (jack_data->no_start_server)
@@ -595,9 +573,10 @@ static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
 
 	res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
 	if (res != (f_buf_used * sizeof(float))) {
-		ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
+		ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
 			(int) (f_buf_used * sizeof(float)), (int) res);
 	}
+
 	return 0;
 }
 
@@ -623,15 +602,15 @@ static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
 	struct ast_frame *out_frame)
 {
-	short buf[jack_data->frame_datalen];
+	short buf[160];
 	struct ast_frame f = {
 		.frametype = AST_FRAME_VOICE,
-		.subclass.format = jack_data->audiohook_format,
 		.src = "JACK",
 		.data.ptr = buf,
 		.datalen = sizeof(buf),
 		.samples = ARRAY_LEN(buf),
 	};
+	ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	for (;;) {
 		size_t res, read_len;
@@ -776,12 +755,12 @@ static int jack_exec(struct ast_channel *chan, const char *data)
 		return -1;
 	}
 
-	if (ast_set_read_format(chan, jack_data->audiohook_format)) {
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		destroy_jack_data(jack_data);
 		return -1;
 	}
 
-	if (ast_set_write_format(chan, jack_data->audiohook_format)) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		destroy_jack_data(jack_data);
 		return -1;
 	}
@@ -847,6 +826,12 @@ static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channe
 	if (frame->frametype != AST_FRAME_VOICE)
 		return 0;
 
+	if (frame->subclass.format.id != AST_FORMAT_SLINEAR) {
+		ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %s\n",
+			ast_getformatname(&frame->subclass.format));
+		return 0;
+	}
+
 	ast_channel_lock(chan);
 
 	if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
@@ -857,14 +842,6 @@ static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channe
 
 	jack_data = datastore->data;
 
-	if (ast_format_cmp(frame->subclass.format, jack_data->audiohook_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
-			ast_format_get_name(jack_data->audiohook_format),
-			ast_format_get_name(frame->subclass.format));
-		ast_channel_unlock(chan);
-		return 0;
-	}
-
 	queue_voice_frame(jack_data, frame);
 
 	handle_jack_audio(chan, jack_data, frame);
@@ -911,7 +888,7 @@ static int enable_jack_hook(struct ast_channel *chan, char *data)
 		goto return_error;
 
 	jack_data->has_audiohook = 1;
-	ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
+	ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK", 0);
 	jack_data->audiohook.manipulate_callback = jack_hook_callback;
 
 	datastore->data = jack_data;
@@ -1051,5 +1028,4 @@ static int load_module(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "JACK Interface");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");
diff --git a/apps/app_macro.c b/apps/app_macro.c
index 3ccc183..cd0833e 100644
--- a/apps/app_macro.c
+++ b/apps/app_macro.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422719 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -248,7 +248,6 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 	char *save_macro_context;
 	char *save_macro_priority;
 	char *save_macro_offset;
-	int save_in_subroutine;
 	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
 
 	if (ast_strlen_zero(data)) {
@@ -357,9 +356,6 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 
 	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
 
-	save_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
-
 	/* Setup environment for new run */
 	ast_channel_exten_set(chan, "s");
 	ast_channel_context_set(chan, fullmacro);
@@ -376,9 +372,10 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 		pbx_builtin_setvar_helper(chan, varname, cur);
 		argc++;
 	}
-	ast_channel_unlock(chan);
 	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+	ast_channel_unlock(chan);
+
 	while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
 		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
 		struct ast_context *c;
@@ -503,7 +500,10 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 
 		/* don't stop executing extensions when we're in "h" */
 		if (ast_check_hangup(chan) && !inhangup) {
-			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
+			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n",
+				ast_channel_exten(chan),
+				ast_channel_macroexten(chan),
+				ast_channel_priority(chan));
 			goto out;
 		}
 		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
@@ -517,29 +517,21 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 	snprintf(depthc, sizeof(depthc), "%d", depth);
 	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
 	ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
-	ast_set2_flag(ast_channel_flags(chan), save_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
 
   	for (x = 1; x < argc; x++) {
   		/* Restore old arguments and delete ours */
 		snprintf(varname, sizeof(varname), "ARG%d", x);
-  		if (oldargs[x]) {
-			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
-			ast_free(oldargs[x]);
-		} else {
-			pbx_builtin_setvar_helper(chan, varname, NULL);
-		}
+		pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
+		ast_free(oldargs[x]);
   	}
 
 	/* Restore macro variables */
 	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
 	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
 	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
-	if (save_macro_exten)
-		ast_free(save_macro_exten);
-	if (save_macro_context)
-		ast_free(save_macro_context);
-	if (save_macro_priority)
-		ast_free(save_macro_priority);
+	ast_free(save_macro_exten);
+	ast_free(save_macro_context);
+	ast_free(save_macro_priority);
 
 	if (setmacrocontext) {
 		ast_channel_macrocontext_set(chan, "");
@@ -547,7 +539,8 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 		ast_channel_macropriority_set(chan, 0);
 	}
 
-	if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
+	if (!strcasecmp(ast_channel_context(chan), fullmacro)
+		&& !(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)) {
 		const char *offsets;
 
   		/* If we're leaving the macro normally, restore original information */
@@ -568,8 +561,7 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
 	}
 
 	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
-	if (save_macro_offset)
-		ast_free(save_macro_offset);
+	ast_free(save_macro_offset);
 
 	/* Unlock the macro */
 	if (exclusive) {
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 0e708bf..2d8d556 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -29,15 +29,6 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_meetme.c uses configuration file \ref meetme.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page meetme.conf meetme.conf
- * \verbinclude meetme.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>dahdi</depend>
 	<defaultenabled>no</defaultenabled>
@@ -47,7 +38,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429029 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <dahdi/user.h>
 
@@ -73,11 +64,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429029 $")
 #include "asterisk/paths.h"
 #include "asterisk/data.h"
 #include "asterisk/test.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/json.h"
-#include "asterisk/format_compatibility.h"
 
 #include "enter.h"
 #include "leave.h"
@@ -558,88 +544,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429029 $")
 				MeetmeListRoomsComplete.</para>
 		</description>
 	</manager>
-	<managerEvent language="en_US" name="MeetmeJoin">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a user joins a MeetMe conference.</synopsis>
-			<syntax>
-				<parameter name="Meetme">
-					<para>The identifier for the MeetMe conference.</para>
-				</parameter>
-				<parameter name="Usernum">
-					<para>The identifier of the MeetMe user who joined.</para>
-				</parameter>
-				<channel_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MeetmeLeave</ref>
-				<ref type="application">MeetMe</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MeetmeLeave">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
-				<channel_snapshot/>
-				<parameter name="Duration">
-					<para>The length of time in seconds that the Meetme user was in the conference.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MeetmeJoin</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MeetmeEnd">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a MeetMe conference ends.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MeetmeJoin</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MeetmeTalkRequest">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a MeetMe user has started talking.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
-				<channel_snapshot/>
-				<parameter name="Duration">
-					<para>The length of time in seconds that the Meetme user has been in the conference at the time of this event.</para>
-				</parameter>
-				<parameter name="Status">
-					<enumlist>
-						<enum name="on"/>
-						<enum name="off"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MeetmeTalking">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MeetmeMute">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a MeetMe user is muted or unmuted.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #define CONFIG_FILE_NAME	"meetme.conf"
@@ -1129,271 +1033,6 @@ static const char gain_map[] = {
 	15,
 };
 
-/* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
-static struct stasis_message_router *meetme_event_message_router;
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
-
-static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message);
-
-static void meetme_stasis_cleanup(void)
-{
-	if (meetme_event_message_router) {
-		stasis_message_router_unsubscribe(meetme_event_message_router);
-		meetme_event_message_router = NULL;
-	}
-
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
-}
-
-static int meetme_stasis_init(void)
-{
-
-	STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
-	STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
-	STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
-	STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
-	STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
-	STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
-
-	meetme_event_message_router = stasis_message_router_create(
-		ast_channel_topic_all_cached());
-
-	if (!meetme_event_message_router) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_join_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_leave_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_end_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_mute_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_talking_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	if (stasis_message_router_add(meetme_event_message_router,
-			meetme_talk_request_type(),
-			meetme_stasis_cb,
-			NULL)) {
-		meetme_stasis_cleanup();
-		return -1;
-	}
-
-	return 0;
-}
-
-static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *channel_blob = stasis_message_data(message);
-	struct stasis_message_type *message_type;
-	const char *event;
-	const char *conference_num;
-	const char *status;
-	struct ast_json *json_cur;
-	RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
-	RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
-
-	if (!channel_blob) {
-		ast_assert(0);
-		return;
-	}
-
-	message_type = stasis_message_type(message);
-
-	if (!message_type) {
-		ast_assert(0);
-		return;
-	}
-
-	if (message_type == meetme_join_type()) {
-		event = "MeetmeJoin";
-	} else if (message_type == meetme_leave_type()) {
-		event = "MeetmeLeave";
-	} else if (message_type == meetme_end_type()) {
-		event = "MeetmeEnd";
-	} else if (message_type == meetme_mute_type()) {
-		event = "MeetmeMute";
-	} else if (message_type == meetme_talking_type()) {
-		event = "MeetmeTalking";
-	} else if (message_type == meetme_talk_request_type()) {
-		event = "MeetmeTalkRequest";
-	} else {
-		ast_assert(0);
-		return;
-	}
-
-	if (!event) {
-		ast_assert(0);
-		return;
-	}
-
-	conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
-	if (!conference_num) {
-		ast_assert(0);
-		return;
-	}
-
-	status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
-	if (status) {
-		ast_str_append_event_header(&extra_text, "Status", status);
-	}
-
-	if (channel_blob->snapshot) {
-		channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
-	}
-
-	if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
-		int user_number = ast_json_integer_get(json_cur);
-		RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
-		if (!user_prop_str) {
-			return;
-		}
-
-		ast_str_set(&user_prop_str, 0, "%d", user_number);
-		ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
-
-		if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
-			int duration = ast_json_integer_get(json_cur);
-			ast_str_set(&user_prop_str, 0, "%d", duration);
-			ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
-		}
-
-		json_cur = NULL;
-	}
-
-	manager_event(EVENT_FLAG_CALL, event,
-		"Meetme: %s\r\n"
-		"%s"
-		"%s",
-		conference_num,
-		channel_text ? ast_str_buffer(channel_text) : "",
-		extra_text ? ast_str_buffer(extra_text) : "");
-}
-
-/*!
- * \internal
- * \brief Build a json object from a status value for inclusion in json extras for meetme_stasis_generate_msg
- * \since 12.0.0
- *
- * \param on if true, then status is on. Otherwise status is off
- * \retval NULL on failure to allocate the JSON blob.
- * \retval pointer to the JSON blob if successful.
- */
-static struct ast_json *status_to_json(int on)
-{
-	struct ast_json *json_object = ast_json_pack("{s: s}",
-		"status", on ? "on" : "off");
-
-	return json_object;
-}
-
-/*!
- * \internal
- * \brief Generate a stasis message associated with a meetme event
- * \since 12.0.0
- *
- * \param meetme_confere The conference responsible for generating this message
- * \param chan The channel involved in the message (NULL allowed)
- * \param user The conference user involved in the message (NULL allowed)
- * \param message_type the type the stasis message being generated
- * \param extras Additional json fields desired for inclusion
- */
-static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan,
-	struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
-	json_object = ast_json_pack("{s: s}",
-		"Meetme", meetme_conference->confno);
-
-	if (!json_object) {
-		return;
-	}
-
-	if (extras) {
-		ast_json_object_update(json_object, extras);
-	}
-
-	if (user) {
-		struct timeval now = ast_tvnow();
-		long duration = (long)(now.tv_sec - user->jointime);
-		struct ast_json *json_user;
-		struct ast_json *json_user_duration;
-
-		json_user = ast_json_integer_create(user->user_no);
-		if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
-			return;
-		}
-
-		if (duration > 0) {
-			json_user_duration = ast_json_integer_create(duration);
-			if (!json_user_duration
-				|| ast_json_object_set(json_object, "duration", json_user_duration)) {
-				return;
-			}
-		}
-	}
-
-	if (chan) {
-		ast_channel_lock(chan);
-	}
-	msg = ast_channel_blob_create(chan, message_type, json_object);
-	if (chan) {
-		ast_channel_unlock(chan);
-	}
-
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_channel_topic(chan), msg);
-}
 
 static int admin_exec(struct ast_channel *chan, const char *data);
 static void *recordthread(void *args);
@@ -1601,7 +1240,6 @@ static int user_max_cmp(void *obj, void *arg, int flags)
  * \param dynamic Mark the newly created conference as dynamic
  * \param refcount How many references to mark on the conference
  * \param chan The asterisk channel
- * \param test
  *
  * \return A pointer to the conference struct, or NULL if it wasn't found and
  *         make or dynamic were not set.
@@ -1613,7 +1251,8 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
 	struct ast_conference *cnf;
 	struct dahdi_confinfo dahdic = { 0, };
 	int confno_int = 0;
-	struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
+	struct ast_format tmp_fmt;
 
 	AST_LIST_LOCK(&confs);
 
@@ -1625,7 +1264,7 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
 	if (cnf || (!make && !dynamic) || !cap_slin)
 		goto cnfout;
 
-	ast_format_cap_append(cap_slin, ast_format_slin, 0);
+	ast_format_cap_add(cap_slin, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
 	/* Make a new one */
 	if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
 		!(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
@@ -1671,10 +1310,10 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
 	cnf->dahdiconf = dahdic.confno;
 
 	/* Setup a new channel for playback of audio files */
-	cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
+	cnf->chan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL);
 	if (cnf->chan) {
-		ast_set_read_format(cnf->chan, ast_format_slin);
-		ast_set_write_format(cnf->chan, ast_format_slin);
+		ast_set_read_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
+		ast_set_write_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
 		dahdic.chan = 0;
 		dahdic.confno = cnf->dahdiconf;
 		dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
@@ -1710,7 +1349,7 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
 		conf_map[confno_int] = 1;
 	
 cnfout:
-	ao2_cleanup(cap_slin);
+	cap_slin = ast_format_cap_destroy(cap_slin);
 	if (cnf)
 		ast_atomic_fetchadd_int(&cnf->refcount, refcount);
 
@@ -2326,10 +1965,20 @@ static int conf_free(struct ast_conference *conf)
 {
 	int x;
 	struct announce_listitem *item;
-
+	
 	AST_LIST_REMOVE(&confs, conf, list);
-
-	meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a MeetMe conference ends.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">MeetmeJoin</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
 
 	if (conf->recording == MEETME_RECORD_ACTIVE) {
 		conf->recording = MEETME_RECORD_TERMINATE;
@@ -2369,8 +2018,10 @@ static int conf_free(struct ast_conference *conf)
 
 	if (conf->origframe)
 		ast_frfree(conf->origframe);
-	ast_hangup(conf->lchan);
-	ast_hangup(conf->chan);
+	if (conf->lchan)
+		ast_hangup(conf->lchan);
+	if (conf->chan)
+		ast_hangup(conf->chan);
 	if (conf->fd >= 0)
 		close(conf->fd);
 	if (conf->recordingfilename) {
@@ -2674,8 +2325,30 @@ static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
 
 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
 {
-	RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
-	meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
+				<parameter name="Status">
+					<enumlist>
+						<enum name="on"/>
+						<enum name="off"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Meetme: %s\r\n"
+		"Usernum: %d\r\n"
+		"Status: %s\r\n",
+		ast_channel_name(chan), ast_channel_uniqueid(chan),
+		conf->confno,
+		user->user_no, talking ? "on" : "off");
 }
 
 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
@@ -3092,11 +2765,11 @@ static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf,
 			}
 
 			ast_mutex_lock(&conf->recordthreadlock);
-			if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
+			if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
 				struct dahdi_confinfo dahdic;
 
-				ast_set_read_format(conf->lchan, ast_format_slin);
-				ast_set_write_format(conf->lchan, ast_format_slin);
+				ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
+				ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
 				dahdic.chan = 0;
 				dahdic.confno = conf->dahdiconf;
 				dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
@@ -3223,12 +2896,13 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 	int setusercount = 0;
 	int confsilence = 0, totalsilence = 0;
 	char *mailbox, *context;
-	struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
+	struct ast_format tmpfmt;
 
 	if (!cap_slin) {
 		goto conf_run_cleanup;
 	}
-	ast_format_cap_append(cap_slin, ast_format_slin, 0);
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 
 	if (!(user = ao2_alloc(sizeof(*user), NULL))) {
 		goto conf_run_cleanup;
@@ -3349,9 +3023,9 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 
 	ast_mutex_lock(&conf->recordthreadlock);
 	if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
-		((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
-		ast_set_read_format(conf->lchan, ast_format_slin);
-		ast_set_write_format(conf->lchan, ast_format_slin);
+		((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
+		ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
+		ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
 		dahdic.chan = 0;
 		dahdic.confno = conf->dahdiconf;
 		dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
@@ -3577,12 +3251,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 		ast_indicate(chan, -1);
 	}
 
-	if (ast_set_write_format(chan, ast_format_slin) < 0) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
 		goto outrun;
 	}
 
-	if (ast_set_read_format(chan, ast_format_slin) < 0) {
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
 		goto outrun;
 	}
@@ -3694,7 +3368,39 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 	ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
 
 	if (!sent_event) {
-		meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a user joins a MeetMe conference.</synopsis>
+				<syntax>
+					<parameter name="Meetme">
+						<para>The identifier for the MeetMe conference.</para>
+					</parameter>
+					<parameter name="Usernum">
+						<para>The identifier of the MeetMe user who joined.</para>
+					</parameter>
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">MeetmeLeave</ref>
+					<ref type="application">MeetMe</ref>
+				</see-also>
+			</managerEventInstance>
+		***/
+		ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"Meetme: %s\r\n"
+			"Usernum: %d\r\n"
+			"CallerIDnum: %s\r\n"
+			"CallerIDname: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n",
+			ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
+			user->user_no,
+			S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<unknown>"),
+			S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<unknown>")
+			);
 		sent_event = 1;
 	}
 
@@ -4043,7 +3749,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 
 			/* If I should be muted but am still talker, mute me */
 			if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
-				RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
 				dahdic.confmode ^= DAHDI_CONF_TALKER;
 				if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
 					ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
@@ -4055,34 +3760,95 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 				if (ast_test_flag64(confflags,  (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
 					set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
 				}
-				meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
+				/*** DOCUMENTATION
+				<managerEventInstance>
+					<synopsis>Raised when a MeetMe user is muted.</synopsis>
+					<syntax>
+						<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
+						<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
+						<parameter name="Status">
+							<enumlist>
+								<enum name="on"/>
+								<enum name="off"/>
+							</enumlist>
+						</parameter>
+					</syntax>
+				</managerEventInstance>
+				***/
+				ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
+					"Channel: %s\r\n"
+					"Uniqueid: %s\r\n"
+					"Meetme: %s\r\n"
+					"Usernum: %d\r\n"
+					"Status: on\r\n",
+					ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
 			}
 
 			/* If I should be un-muted but am not talker, un-mute me */
 			if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
-				RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
 				dahdic.confmode |= DAHDI_CONF_TALKER;
 				if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
 					ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
 					ret = -1;
 					break;
 				}
-				meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
+				/*** DOCUMENTATION
+				<managerEventInstance>
+					<synopsis>Raised when a MeetMe user is unmuted.</synopsis>
+				</managerEventInstance>
+				***/
+				ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
+					"Channel: %s\r\n"
+					"Uniqueid: %s\r\n"
+					"Meetme: %s\r\n"
+					"Usernum: %d\r\n"
+					"Status: off\r\n",
+					ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
 			}
-
+			
 			if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
 				(user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
-
-				RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
 				talkreq_manager = 1;
-				meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
+
+				/*** DOCUMENTATION
+				<managerEventInstance>
+					<synopsis>Raised when a MeetMe user has started talking.</synopsis>
+					<syntax>
+						<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
+						<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
+						<parameter name="Status">
+							<enumlist>
+								<enum name="on"/>
+								<enum name="off"/>
+							</enumlist>
+						</parameter>
+					</syntax>
+				</managerEventInstance>
+				***/
+				ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
+					"Channel: %s\r\n"
+					"Uniqueid: %s\r\n"
+					"Meetme: %s\r\n"
+					"Usernum: %d\r\n"
+					"Status: on\r\n",
+					ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
 			}
 
 			if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
 				!(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
-				RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
 				talkreq_manager = 0;
-				meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
+				/*** DOCUMENTATION
+				<managerEventInstance>
+					<synopsis>Raised when a MeetMe user has finished talking.</synopsis>
+				</managerEventInstance>
+				***/
+				ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
+					"Channel: %s\r\n"
+					"Uniqueid: %s\r\n"
+					"Meetme: %s\r\n"
+					"Usernum: %d\r\n"
+					"Status: off\r\n",
+					ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
 			}
 
 			/* If user have been hung up, exit the conference */
@@ -4136,7 +3902,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 					dtmfstr[1] = '\0';
 				}
 
-				if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+				if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
 					if (user->talk.actual) {
 						ast_frame_adjust_volume(f, user->talk.actual);
 					}
@@ -4294,7 +4060,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 				if (res > 0) {
 					memset(&fr, 0, sizeof(fr));
 					fr.frametype = AST_FRAME_VOICE;
-					fr.subclass.format = ast_format_slin;
+					ast_format_set(&fr.subclass.format, AST_FORMAT_SLINEAR, 0);
 					fr.datalen = res;
 					fr.samples = res / 2;
 					fr.data.ptr = buf;
@@ -4306,7 +4072,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 						 )) {
 						int idx;
 						for (idx = 0; idx < AST_FRAME_BITS; idx++) {
-							if (ast_format_compatibility_format2bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) {
+							if (ast_format_to_old_bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) {
 								break;
 							}
 						}
@@ -4324,7 +4090,11 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 									mohtempstopped = 1;
 								}
 								if (!conf->transpath[idx]) {
-									conf->transpath[idx] = ast_translator_build_path(ast_channel_rawwriteformat(chan), ast_format_slin);
+									struct ast_format src;
+									struct ast_format dst;
+									ast_format_set(&src, AST_FORMAT_SLINEAR, 0);
+									ast_format_from_old_bitfield(&dst, (1 << idx));
+									conf->transpath[idx] = ast_translator_build_path(&dst, &src);
 								}
 								if (conf->transpath[idx]) {
 									conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
@@ -4441,7 +4211,38 @@ bailoutandtrynormal:
 		now = ast_tvnow();
 
 		if (sent_event) {
-			meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
+			/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
+					<parameter name="Duration">
+						<para>The length of time in seconds that the Meetme user was in the conference.</para>
+					</parameter>
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">MeetmeJoin</ref>
+				</see-also>
+			</managerEventInstance>
+			***/
+			ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
+				"Channel: %s\r\n"
+				"Uniqueid: %s\r\n"
+				"Meetme: %s\r\n"
+				"Usernum: %d\r\n"
+				"CallerIDNum: %s\r\n"
+				"CallerIDName: %s\r\n"
+				"ConnectedLineNum: %s\r\n"
+				"ConnectedLineName: %s\r\n"
+				"Duration: %ld\r\n",
+				ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
+				user->user_no,
+				S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
+				S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<unknown>"),
+				S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
+				S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<unknown>"),
+				(long)(now.tv_sec - user->jointime));
 		}
 
 		if (setusercount) {
@@ -4486,7 +4287,7 @@ bailoutandtrynormal:
 
 
 conf_run_cleanup:
-	ao2_cleanup(cap_slin);
+	cap_slin = ast_format_cap_destroy(cap_slin);
 
 	return ret;
 }
@@ -6366,7 +6167,7 @@ static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_
 	tech_data = ast_strdupa(station->device);
 	tech = strsep(&tech_data, "/");
 
-	if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
+	if (ast_dial_append(dial, tech, tech_data) == -1) {
 		ast_dial_destroy(dial);
 		return -1;
 	}
@@ -6872,7 +6673,7 @@ static void *dial_trunk(void *data)
 
 	tech_data = ast_strdupa(trunk_ref->trunk->device);
 	tech = strsep(&tech_data, "/");
-	if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
+	if (ast_dial_append(dial, tech, tech_data) == -1) {
 		ast_mutex_lock(args->cond_lock);
 		ast_cond_signal(args->cond);
 		ast_mutex_unlock(args->cond_lock);
@@ -7546,14 +7347,13 @@ static int sla_build_trunk(struct ast_config *cfg, const char *cat)
 	ao2_unlock(trunk);
 
 	if (!ast_strlen_zero(trunk->autocontext)) {
-		struct ast_context *context;
-		context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
-		if (!context) {
+		if (!ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar)) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", trunk->autocontext);
 			return -1;
 		}
-		if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
+
+		if (ast_add_extension(trunk->autocontext, 0 /* don't replace */, "s", 1,
 			NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
 			ast_log(LOG_ERROR, "Failed to automatically create extension "
 				"for trunk '%s'!\n", trunk->name);
@@ -7722,17 +7522,16 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
 	ao2_unlock(station);
 
 	if (!ast_strlen_zero(station->autocontext)) {
-		struct ast_context *context;
 		struct sla_trunk_ref *trunk_ref;
-		context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
-		if (!context) {
+
+		if (!ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar)) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", station->autocontext);
 			return -1;
 		}
 		/* The extension for when the handset goes off-hook.
 		 * exten => station1,1,SLAStation(station1) */
-		if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
+		if (ast_add_extension(station->autocontext, 0 /* don't replace */, station->name, 1,
 			NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
 			ast_log(LOG_ERROR, "Failed to automatically create extension "
 				"for trunk '%s'!\n", station->name);
@@ -7745,7 +7544,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
 			snprintf(hint, sizeof(hint), "SLA:%s", exten);
 			/* Extension for this line button 
 			 * exten => station1_line1,1,SLAStation(station1_line1) */
-			if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
+			if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, 1,
 				NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
 				ast_log(LOG_ERROR, "Failed to automatically create extension "
 					"for trunk '%s'!\n", station->name);
@@ -7753,7 +7552,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
 			}
 			/* Hint for this line button 
 			 * exten => station1_line1,hint,SLA:station1_line1 */
-			if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
+			if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, PRIORITY_HINT,
 				NULL, NULL, hint, NULL, NULL, sla_registrar)) {
 				ast_log(LOG_ERROR, "Failed to automatically create hint "
 					"for trunk '%s'!\n", station->name);
@@ -8154,14 +7953,12 @@ AST_TEST_DEFINE(test_meetme_data_provider)
 		break;
 	}
 
-	chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "MeetMeTest");
+	chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, 0, 0, "MeetMeTest");
 	if (!chan) {
 		ast_test_status_update(test, "Channel allocation failed\n");
 		return AST_TEST_FAIL;
 	}
 
-	ast_channel_unlock(chan);
-
 	cnf = build_conf("9898", "", "1234", 1, 1, 1, chan, test);
 	if (!cnf) {
 		ast_test_status_update(test, "Build of test conference 9898 failed\n");
@@ -8222,29 +8019,15 @@ static int unload_module(void)
 	res |= ast_custom_function_unregister(&meetme_info_acf);
 	ast_unload_realtime("meetme");
 
-	meetme_stasis_cleanup();
-
 	return res;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res = 0;
 
 	res |= load_config(0);
 
-	res |= meetme_stasis_init();
-
 	ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
 	res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
 	res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
@@ -8278,7 +8061,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MeetMe conference bridge",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_milliwatt.c b/apps/app_milliwatt.c
index 2c3baf1..a4adc08 100644
--- a/apps/app_milliwatt.c
+++ b/apps/app_milliwatt.c
@@ -31,13 +31,12 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/indications.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="Milliwatt" language="en_US">
@@ -80,14 +79,13 @@ static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int
 {
 	unsigned char buf[AST_FRIENDLY_OFFSET + 640];
 	const int maxsamples = ARRAY_LEN(buf) - (AST_FRIENDLY_OFFSET / sizeof(buf[0]));
-	int i, *indexp = (int *) data, res;
+	int i, *indexp = (int *) data;
 	struct ast_frame wf = {
 		.frametype = AST_FRAME_VOICE,
 		.offset = AST_FRIENDLY_OFFSET,
 		.src = __FUNCTION__,
 	};
-
-	wf.subclass.format = ast_format_ulaw;
+	ast_format_set(&wf.subclass.format, AST_FORMAT_ULAW, 0);
 	wf.data.ptr = buf + AST_FRIENDLY_OFFSET;
 
 	/* Instead of len, use samples, because channel.c generator_force
@@ -110,10 +108,7 @@ static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int
 		*indexp &= 7;
 	}
 
-	res = ast_write(chan, &wf);
-	ast_frfree(&wf);
-
-	if (res < 0) {
+	if (ast_write(chan,&wf) < 0) {
 		ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",ast_channel_name(chan),strerror(errno));
 		return -1;
 	}
@@ -129,8 +124,8 @@ static struct ast_generator milliwattgen = {
 
 static int old_milliwatt_exec(struct ast_channel *chan)
 {
-	ast_set_write_format(chan, ast_format_ulaw);
-	ast_set_read_format(chan, ast_format_ulaw);
+	ast_set_write_format_by_id(chan, AST_FORMAT_ULAW);
+	ast_set_read_format_by_id(chan, AST_FORMAT_ULAW);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_answer(chan);
diff --git a/apps/app_minivm.c b/apps/app_minivm.c
index f50b93d..ecdf9c6 100644
--- a/apps/app_minivm.c
+++ b/apps/app_minivm.c
@@ -26,6 +26,7 @@
  * based on the Comedian Mail voicemail system (app_voicemail.c).
  * 
  * \par See also
+ * \arg \ref Config_minivm
  * \arg \ref Config_minivm_examples
  * \arg \ref App_minivm
  *
@@ -146,7 +147,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <sys/time.h>
@@ -166,15 +167,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/say.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
+#include "asterisk/manager.h"
 #include "asterisk/dsp.h"
 #include "asterisk/localtime.h"
 #include "asterisk/cli.h"
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/callerid.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/json.h"
+#include "asterisk/event.h"
 
 /*** DOCUMENTATION
 <application name="MinivmRecord" language="en_US">
@@ -496,23 +496,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 		<ref type="function">MINIVMCOUNTER</ref>
 	</see-also>
 </function>
-	<managerEvent language="en_US" name="MiniVoiceMail">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a notification is sent out by a MiniVoiceMail application</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Action">
-					<para>What action was taken. Currently, this will always be <literal>SentNotification</literal></para>
-				</parameter>
-				<parameter name="Mailbox">
-					<para>The mailbox that the notification was about, specified as <literal>mailbox</literal>@<literal>context</literal></para>
-				</parameter>
-				<parameter name="Counter">
-					<para>A message counter derived from the <literal>MVM_COUNTER</literal> channel variable.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
+
 ***/
 
 #ifndef TRUE
@@ -1366,7 +1350,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
 	prep_email_sub_vars(ast, vmu, cidnum, cidname, dur, date, counter);
 
 	/* Find email address to use */
-	/* If there's a server e-mail adress in the account, user that, othterwise template */
+	/* If there's a server e-mail address in the account, user that, othterwise template */
 	fromemail = ast_strlen_zero(vmu->serveremail) ?  template->serveremail : vmu->serveremail;
 
 	/* Find name to user for server e-mail */
@@ -1674,7 +1658,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
 			if (ast_test_flag(vmu, MVM_OPERATOR))
 				canceldtmf = "0";
-			cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
+			cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
 			if (record_gain)
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
 			if (cmd == -1) /* User has hung up, no options to give */
@@ -1778,9 +1762,6 @@ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vm
  * \brief Send message to voicemail account owner */
 static int notify_new_message(struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
 {
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
 	char *stringp;
 	struct minivm_template *etemplate;
 	char *messageformat;
@@ -1838,7 +1819,8 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
 		etemplate = message_template_find(vmu->ptemplate);
 		if (!etemplate)
 			etemplate = message_template_find("pager-default");
-		if (etemplate->locale) {
+
+		if (!ast_strlen_zero(etemplate->locale)) {
 			ast_copy_string(oldlocale, setlocale(LC_TIME, ""), sizeof(oldlocale));
 			setlocale(LC_TIME, etemplate->locale);
 		}
@@ -1846,30 +1828,11 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
 		res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter);
 	}
 
-	mwi_state = ast_mwi_create(vmu->username, vmu->domain);
-	if (!mwi_state) {
-		goto notify_cleanup;
-	}
-	mwi_state->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
-
-	json_object = ast_json_pack("{s: s, s: s}",
-			"Event", "MiniVoiceMail"
-			"Action", "SentNotification",
-			"Counter", counter);
-	if (!json_object) {
-		goto notify_cleanup;
-	}
-	message = ast_mwi_blob_create(mwi_state, ast_mwi_vm_app_type(), json_object);
-	if (!message) {
-		goto notify_cleanup;
-	}
-	stasis_publish(ast_mwi_topic(mwi_state->uniqueid), message);
+	ast_manager_event(chan, EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter);
 
-notify_cleanup:
 	run_externnotify(chan, vmu);		/* Run external notification */
-
-	if (etemplate->locale) {
-		setlocale(LC_TIME, oldlocale); /* Rest to old locale */
+	if (!ast_strlen_zero(etemplate->locale)) {
+		setlocale(LC_TIME, oldlocale);	/* Reset to old locale */
 	}
 	return res;
 }
@@ -2049,8 +2012,9 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
 
 /*!\internal
  * \brief Queue a message waiting event */
-static void queue_mwi_event(const char *channel_id, const char *mbx, const char *ctx, int urgent, int new, int old)
+static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int new, int old)
 {
+	struct ast_event *event;
 	char *mailbox, *context;
 
 	mailbox = ast_strdupa(mbx);
@@ -2059,7 +2023,16 @@ static void queue_mwi_event(const char *channel_id, const char *mbx, const char
 		context = "default";
 	}
 
-	ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
+	if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
+			AST_EVENT_IE_END))) {
+		return;
+	}
+
+	ast_event_queue_and_cache(event);
 }
 
 /*!\internal
@@ -2094,7 +2067,7 @@ static int minivm_mwi_exec(struct ast_channel *chan, const char *data)
 		ast_log(LOG_ERROR, "Need mailbox at context as argument. Sorry. Argument 0 %s\n", argv[0]);
 		return -1;
 	}
-	queue_mwi_event(ast_channel_uniqueid(chan), mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
+	queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
 
 	return res;
 }
@@ -2116,6 +2089,7 @@ static int minivm_notify_exec(struct ast_channel *chan, const char *data)
 	const char *filename;
 	const char *format;
 	const char *duration_string;
+
 	if (ast_strlen_zero(data))  {
 		ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
 		return -1;
@@ -3561,7 +3535,6 @@ static int unload_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Mini VoiceMail (A minimal Voicemail e-mail System)",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 90bfee5..89a1d8c 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -39,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_MONITOR_DIR */
 #include "asterisk/stringfields.h"
@@ -56,9 +56,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 #include "asterisk/mod_format.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/test.h"
-#include "asterisk/mixmonitor.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/beep.h"
 
 /*** DOCUMENTATION
 	<application name="MixMonitor" language="en_US">
@@ -81,14 +78,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 					</option>
 					<option name="b">
 						<para>Only save audio to the file while the channel is bridged.</para>
+						<note><para>Does not include conferences or sounds played to each bridged party</para></note>
 						<note><para>If you utilize this option inside a Local channel, you must make sure the Local
 						channel is not optimized away. To do this, be sure to call your Local channel with the
 						<literal>/n</literal> option. For example: Dial(Local/start at mycontext/n)</para></note>
 					</option>
-					<option name="B">
-						<para>Play a periodic beep while this call is being recorded.</para>
-						<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
-					</option>
 					<option name="v">
 						<para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
 						(range <literal>-4</literal> to <literal>4</literal>)</para>
@@ -109,6 +103,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 						<para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
 						Like with the basic filename argument, if an absolute path isn't given, it will create
 						the file in the configured monitoring directory.</para>
+
 					</option>
 					<option name="t">
 						<argument name="file" required="true" />
@@ -120,12 +115,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 						<argument name="chanvar" required="true" />
 						<para>Stores the MixMonitor's ID on this channel variable.</para>
 					</option>
-					<option name="p">
-						<para>Play a beep on the channel that starts the recording.</para>
-					</option>
-					<option name="P">
-						<para>Play a beep on the channel that stops the recording.</para>
-					</option>
 					<option name="m">
 						<argument name="mailbox" required="true" />
 						<para>Create a copy of the recording as a voicemail in the indicated <emphasis>mailbox</emphasis>(es)
@@ -144,7 +133,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 			<para>Records the audio on the current channel to the specified file.</para>
 			<para>This application does not automatically answer and should be preceeded by
 			an application such as Answer or Progress().</para>
-			<note><para>MixMonitor runs as an audiohook.</para></note>
+			<note><para>MixMonitor runs as an audiohook. In order to keep it running through
+			a transfer, AUDIOHOOK_INHERIT must be set for the channel which ran mixmonitor.
+			For more information, including dialplan configuration set for using
+			AUDIOHOOK_INHERIT with MixMonitor, see the function documentation for
+			AUDIOHOOK_INHERIT.</para></note>
 			<variablelist>
 				<variable name="MIXMONITOR_FILENAME">
 					<para>Will contain the filename used to record.</para>
@@ -220,11 +213,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 				would apply if invoked from the MixMonitor application. For a list of
 				available options, see the documentation for the mixmonitor application. </para>
 			</parameter>
-			<parameter name="Command">
-				<para>Will be executed when the recording is over.
-				Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.
-				All variables will be evaluated at the time MixMonitor is called.</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>This action records the audio on the current channel to the specified file.</para>
@@ -254,23 +242,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
 			action on the current channel.</para>
 		</description>
 	</manager>
-	<function name="MIXMONITOR" language="en_US">
-		<synopsis>
-			Retrieve data pertaining to specific instances of MixMonitor on a channel.
-		</synopsis>
-		<syntax>
-			<parameter name="id" required="true">
-				<para>The unique ID of the MixMonitor instance. The unique ID can be retrieved through the channel
-				variable used as an argument to the <replaceable>i</replaceable> option to MixMonitor.</para>
-			</parameter>
-			<parameter name="key" required="true">
-				<para>The piece of data to retrieve from the MixMonitor.</para>
-				<enumlist>
-					<enum name="filename" />
-				</enumlist>
-			</parameter>
-		</syntax>
-	</function>
 
  ***/
 
@@ -331,9 +302,6 @@ enum mixmonitor_flags {
 	MUXFLAG_COMBINED = (1 << 8),
 	MUXFLAG_UID = (1 << 9),
 	MUXFLAG_VMRECIPIENTS = (1 << 10),
-	MUXFLAG_BEEP = (1 << 11),
-	MUXFLAG_BEEP_START = (1 << 12),
-	MUXFLAG_BEEP_STOP = (1 << 13)
 };
 
 enum mixmonitor_args {
@@ -344,16 +312,12 @@ enum mixmonitor_args {
 	OPT_ARG_READNAME,
 	OPT_ARG_UID,
 	OPT_ARG_VMRECIPIENTS,
-	OPT_ARG_BEEP_INTERVAL,
 	OPT_ARG_ARRAY_SIZE,	/* Always last element of the enum */
 };
 
 AST_APP_OPTIONS(mixmonitor_opts, {
 	AST_APP_OPTION('a', MUXFLAG_APPEND),
 	AST_APP_OPTION('b', MUXFLAG_BRIDGED),
-	AST_APP_OPTION_ARG('B', MUXFLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
-	AST_APP_OPTION('p', MUXFLAG_BEEP_START),
-	AST_APP_OPTION('P', MUXFLAG_BEEP_STOP),
 	AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
 	AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
 	AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
@@ -379,8 +343,6 @@ struct mixmonitor_ds {
 	struct ast_audiohook *audiohook;
 
 	unsigned int samp_rate;
-	char *filename;
-	char *beep_id;
 };
 
 /*!
@@ -424,8 +386,6 @@ static void mixmonitor_ds_destroy(void *data)
 	ast_mutex_lock(&mixmonitor_ds->lock);
 	mixmonitor_ds->audiohook = NULL;
 	mixmonitor_ds->destruction_ok = 1;
-	ast_free(mixmonitor_ds->filename);
-	ast_free(mixmonitor_ds->beep_id);
 	ast_cond_signal(&mixmonitor_ds->destruction_condition);
 	ast_mutex_unlock(&mixmonitor_ds->lock);
 }
@@ -451,11 +411,18 @@ static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
 
 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
 {
-	if (!chan) {
+	struct ast_channel *peer = NULL;
+	int res = 0;
+
+	if (!chan)
 		return -1;
-	}
 
-	return ast_audiohook_attach(chan, audiohook);
+	ast_audiohook_attach(chan, audiohook);
+
+	if (!res && ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
+		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+
+	return res;
 }
 
 /*!
@@ -502,7 +469,7 @@ static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const c
 			ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
 
 			/* Add to list */
-			ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
+			ast_verb(5, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
 			AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
 		} else {
 			ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
@@ -548,6 +515,7 @@ static void mixmonitor_free(struct mixmonitor *mixmonitor)
 		if (mixmonitor->callid) {
 			ast_callid_unref(mixmonitor->callid);
 		}
+
 		ast_free(mixmonitor);
 	}
 }
@@ -616,7 +584,7 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename,
 				*errflag = 1;
 			} else {
 				struct ast_filestream *tmp = *fs;
-				mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_get_sample_rate(tmp->fmt->format));
+				mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
 			}
 		}
 	}
@@ -635,7 +603,7 @@ static void *mixmonitor_thread(void *obj)
 
 	unsigned int oflags;
 	int errflag = 0;
-	struct ast_format *format_slin;
+	struct ast_format format_slin;
 
 	/* Keep callid association before any log messages */
 	if (mixmonitor->callid) {
@@ -653,10 +621,11 @@ static void *mixmonitor_thread(void *obj)
 	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
 	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
 
-	format_slin = ast_format_cache_get_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate);
+	ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
 
 	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
 
+
 	/* The audiohook must enter and exit the loop locked */
 	ast_audiohook_lock(&mixmonitor->audiohook);
 	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
@@ -664,7 +633,7 @@ static void *mixmonitor_thread(void *obj)
 		struct ast_frame *fr_read = NULL;
 		struct ast_frame *fr_write = NULL;
 
-		if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, format_slin,
+		if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
 						&fr_read, &fr_write))) {
 			ast_audiohook_trigger_wait(&mixmonitor->audiohook);
 
@@ -678,9 +647,7 @@ static void *mixmonitor_thread(void *obj)
 		 * Unlock it, but remember to lock it before looping or exiting */
 		ast_audiohook_unlock(&mixmonitor->audiohook);
 
-		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED)
-			|| (mixmonitor->autochan->chan
-				&& ast_channel_is_bridged(mixmonitor->autochan->chan))) {
+		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
 			ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
 
 			/* Write out the frame(s) */
@@ -727,20 +694,8 @@ static void *mixmonitor_thread(void *obj)
 		ast_audiohook_lock(&mixmonitor->audiohook);
 	}
 
-	/* Test Event */
-	ast_test_suite_event_notify("MIXMONITOR_END", "Channel: %s\r\n"
-									"File: %s\r\n",
-									ast_channel_name(mixmonitor->autochan->chan),
-									mixmonitor->filename);
-
 	ast_audiohook_unlock(&mixmonitor->audiohook);
 
-	ast_channel_lock(mixmonitor->autochan->chan);
-	if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
-		ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
-	}
-	ast_channel_unlock(mixmonitor->autochan->chan);
-
 	ast_autochan_destroy(mixmonitor->autochan);
 
 	/* Datastore cleanup.  close the filestream and wait for ds destruction */
@@ -760,6 +715,7 @@ static void *mixmonitor_thread(void *obj)
 	}
 
 	ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
+	ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
 
 	if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
 		if (ast_strlen_zero(fs_ext)) {
@@ -787,7 +743,7 @@ static void *mixmonitor_thread(void *obj)
 	return NULL;
 }
 
-static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
+static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
 {
 	struct ast_datastore *datastore = NULL;
 	struct mixmonitor_ds *mixmonitor_ds;
@@ -810,18 +766,9 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
 		return -1;
 	}
 
-	ast_channel_lock(mixmonitor->autochan->chan);
-	if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
-		ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
-	}
-	ast_channel_unlock(mixmonitor->autochan->chan);
 
 	mixmonitor_ds->samp_rate = 8000;
 	mixmonitor_ds->audiohook = &mixmonitor->audiohook;
-	mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
-	if (!ast_strlen_zero(beep_id)) {
-		mixmonitor_ds->beep_id = ast_strdup(beep_id);
-	}
 	datastore->data = mixmonitor_ds;
 
 	ast_channel_lock(chan);
@@ -836,7 +783,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 				  unsigned int flags, int readvol, int writevol,
 				  const char *post_process, const char *filename_write,
 				  char *filename_read, const char *uid_channel_var,
-				  const char *recipients, const char *beep_id)
+				  const char *recipients)
 {
 	pthread_t thread;
 	struct mixmonitor *mixmonitor;
@@ -854,9 +801,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 				*p2 = '$';
 			}
 		}
-		ast_channel_lock(chan);
 		pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
-		ast_channel_unlock(chan);
 	}
 
 	/* Pre-allocate mixmonitor structure and spy */
@@ -883,19 +828,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 		return -1;
 	}
 
-	if (!ast_strlen_zero(filename)) {
-		mixmonitor->filename = ast_strdup(filename);
-	}
-
-	if (!ast_strlen_zero(filename_write)) {
-		mixmonitor->filename_write = ast_strdup(filename_write);
-	}
-
-	if (!ast_strlen_zero(filename_read)) {
-		mixmonitor->filename_read = ast_strdup(filename_read);
-	}
-
-	if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
+	if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
 		ast_autochan_destroy(mixmonitor->autochan);
 		mixmonitor_free(mixmonitor);
 		ast_free(datastore_id);
@@ -915,6 +848,18 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 		mixmonitor->post_process = ast_strdup(postprocess2);
 	}
 
+	if (!ast_strlen_zero(filename)) {
+		mixmonitor->filename = ast_strdup(filename);
+	}
+
+	if (!ast_strlen_zero(filename_write)) {
+		mixmonitor->filename_write = ast_strdup(filename_write);
+	}
+
+	if (!ast_strlen_zero(filename_read)) {
+		mixmonitor->filename_read = ast_strdup(filename_read);
+	}
+
 	if (!ast_strlen_zero(recipients)) {
 		char callerid[256];
 		struct ast_party_connected_line *connected;
@@ -995,8 +940,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 	char *filename_read = NULL;
 	char *filename_write = NULL;
 	char filename_buffer[1024] = "";
-	char *uid_channel_var = NULL;
-	char beep_id[64] = "";
+        char *uid_channel_var = NULL;
 
 	struct ast_flags flags = { 0 };
 	char *recipients = NULL;
@@ -1070,21 +1014,6 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 		if (ast_test_flag(&flags, MUXFLAG_UID)) {
 			uid_channel_var = opts[OPT_ARG_UID];
 		}
-
-		if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
-			const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
-			unsigned int interval = 15;
-
-			if (sscanf(interval_str, "%30u", &interval) != 1) {
-				ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
-						interval_str, interval);
-			}
-
-			if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
-				ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
-				return -1;
-			}
-		}
 	}
 	/* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
 
@@ -1111,8 +1040,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 			filename_write,
 			filename_read,
 			uid_channel_var,
-			recipients,
-			beep_id)) {
+			recipients)) {
 		ast_module_unref(ast_module_info->self);
 	}
 
@@ -1124,7 +1052,6 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
 	struct ast_datastore *datastore = NULL;
 	char *parse = "";
 	struct mixmonitor_ds *mixmonitor_ds;
-	const char *beep_id = NULL;
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(mixmonid);
@@ -1138,11 +1065,9 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
 
 	ast_channel_lock(chan);
 
-	datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info,
-		S_OR(args.mixmonid, NULL));
-	if (!datastore) {
+	if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
 		ast_channel_unlock(chan);
-		return -1;
+                return -1;
 	}
 	mixmonitor_ds = datastore->data;
 
@@ -1165,23 +1090,14 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
 		mixmonitor_ds->audiohook = NULL;
 	}
 
-	if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
-		beep_id = ast_strdupa(mixmonitor_ds->beep_id);
-	}
-
 	ast_mutex_unlock(&mixmonitor_ds->lock);
 
 	/* Remove the datastore so the monitor thread can exit */
 	if (!ast_channel_datastore_remove(chan, datastore)) {
 		ast_datastore_free(datastore);
 	}
-
 	ast_channel_unlock(chan);
 
-	if (!ast_strlen_zero(beep_id)) {
-		ast_beep_stop(chan, beep_id);
-	}
-
 	return 0;
 }
 
@@ -1201,11 +1117,9 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
 	case CLI_INIT:
 		e->command = "mixmonitor {start|stop|list}";
 		e->usage =
-			"Usage: mixmonitor start <chan_name> [args]\n"
-			"         The optional arguments are passed to the MixMonitor application.\n"
-			"       mixmonitor stop <chan_name> [args]\n"
-			"         The optional arguments are passed to the StopMixMonitor application.\n"
-			"       mixmonitor list <chan_name>\n";
+			"Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
+			"       The optional arguments are passed to the MixMonitor\n"
+			"       application when the 'start' command is used.\n";
 		return NULL;
 	case CLI_GENERATE:
 		return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
@@ -1221,35 +1135,35 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
 		return CLI_SUCCESS;
 	}
 
+	ast_channel_lock(chan);
+
 	if (!strcasecmp(a->argv[1], "start")) {
 		mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
+		ast_channel_unlock(chan);
 	} else if (!strcasecmp(a->argv[1], "stop")){
+		ast_channel_unlock(chan);
 		stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
 	} else if (!strcasecmp(a->argv[1], "list")) {
 		ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
 		ast_cli(a->fd, "=========================================================================\n");
-		ast_channel_lock(chan);
 		AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
 			if (datastore->info == &mixmonitor_ds_info) {
 				char *filename = "";
 				char *filename_read = "";
 				char *filename_write = "";
-
 				mixmonitor_ds = datastore->data;
-				if (mixmonitor_ds->fs) {
-					filename = mixmonitor_ds->fs->filename;
-				}
-				if (mixmonitor_ds->fs_read) {
-					filename_read = mixmonitor_ds->fs_read->filename;
-				}
-				if (mixmonitor_ds->fs_write) {
-					filename_write = mixmonitor_ds->fs_write->filename;
-				}
+				if (mixmonitor_ds->fs)
+					filename = ast_strdupa(mixmonitor_ds->fs->filename);
+				if (mixmonitor_ds->fs_read)
+					filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
+				if (mixmonitor_ds->fs_write)
+					filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
 				ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
 			}
 		}
 		ast_channel_unlock(chan);
 	} else {
+		ast_channel_unlock(chan);
 		chan = ast_channel_unref(chan);
 		return CLI_SHOWUSAGE;
 	}
@@ -1262,12 +1176,15 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
 /*! \brief  Mute / unmute  a MixMonitor channel */
 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
 {
-	struct ast_channel *c;
+	struct ast_channel *c = NULL;
+
 	const char *name = astman_get_header(m, "Channel");
 	const char *id = astman_get_header(m, "ActionID");
 	const char *state = astman_get_header(m, "State");
 	const char *direction = astman_get_header(m,"Direction");
+
 	int clearmute = 1;
+
 	enum ast_audiohook_flags flag;
 
 	if (ast_strlen_zero(direction)) {
@@ -1297,15 +1214,15 @@ static int manager_mute_mixmonitor(struct mansession *s, const struct message *m
 	}
 
 	clearmute = ast_false(state);
-
 	c = ast_channel_get_by_name(name);
+
 	if (!c) {
 		astman_send_error(s, m, "No such channel");
 		return AMI_SUCCESS;
 	}
 
 	if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
-		ast_channel_unref(c);
+		c = ast_channel_unref(c);
 		astman_send_error(s, m, "Cannot set mute flag");
 		return AMI_SUCCESS;
 	}
@@ -1318,50 +1235,33 @@ static int manager_mute_mixmonitor(struct mansession *s, const struct message *m
 
 	astman_append(s, "\r\n");
 
-	ast_channel_unref(c);
+	c = ast_channel_unref(c);
 
 	return AMI_SUCCESS;
 }
 
-static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
-{
-	char args[PATH_MAX];
-
-	if (ast_strlen_zero(options)) {
-		snprintf(args, sizeof(args), "%s", filename);
-	} else {
-		snprintf(args, sizeof(args), "%s,%s", filename, options);
-	}
-
-	return mixmonitor_exec(chan, args);
-}
-
-static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
-{
-	return stop_mixmonitor_full(chan, mixmonitor_id);
-}
-
 static int manager_mixmonitor(struct mansession *s, const struct message *m)
 {
-	struct ast_channel *c;
+	struct ast_channel *c = NULL;
+
 	const char *name = astman_get_header(m, "Channel");
 	const char *id = astman_get_header(m, "ActionID");
 	const char *file = astman_get_header(m, "File");
 	const char *options = astman_get_header(m, "Options");
-	const char *command = astman_get_header(m, "Command");
 	char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
 	struct ast_flags flags = { 0 };
 	char *uid_channel_var = NULL;
 	const char *mixmonitor_id = NULL;
-	int res;
-	char args[PATH_MAX];
 
+	int res;
+	char args[PATH_MAX] = "";
 	if (ast_strlen_zero(name)) {
 		astman_send_error(s, m, "No channel specified");
 		return AMI_SUCCESS;
 	}
 
 	c = ast_channel_get_by_name(name);
+
 	if (!c) {
 		astman_send_error(s, m, "No such channel");
 		return AMI_SUCCESS;
@@ -1371,20 +1271,19 @@ static int manager_mixmonitor(struct mansession *s, const struct message *m)
 		ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
 	}
 
-	snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
+	snprintf(args, sizeof(args), "%s,%s", file, options);
 
+	ast_channel_lock(c);
 	res = mixmonitor_exec(c, args);
 
 	if (ast_test_flag(&flags, MUXFLAG_UID)) {
 		uid_channel_var = opts[OPT_ARG_UID];
-		ast_channel_lock(c);
 		mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
-		mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
-		ast_channel_unlock(c);
 	}
+	ast_channel_unlock(c);
 
 	if (res) {
-		ast_channel_unref(c);
+		c = ast_channel_unref(c);
 		astman_send_error(s, m, "Could not start monitoring channel");
 		return AMI_SUCCESS;
 	}
@@ -1401,31 +1300,34 @@ static int manager_mixmonitor(struct mansession *s, const struct message *m)
 
 	astman_append(s, "\r\n");
 
-	ast_channel_unref(c);
+	c = ast_channel_unref(c);
 
 	return AMI_SUCCESS;
 }
 
 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
 {
-	struct ast_channel *c;
+	struct ast_channel *c = NULL;
+
 	const char *name = astman_get_header(m, "Channel");
 	const char *id = astman_get_header(m, "ActionID");
 	const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
-	int res;
 
+	int res;
 	if (ast_strlen_zero(name)) {
 		astman_send_error(s, m, "No channel specified");
 		return AMI_SUCCESS;
 	}
 
 	c = ast_channel_get_by_name(name);
+
 	if (!c) {
 		astman_send_error(s, m, "No such channel");
 		return AMI_SUCCESS;
 	}
 
 	res = stop_mixmonitor_full(c, mixmonitor_id);
+
 	if (res) {
 		ast_channel_unref(c);
 		astman_send_error(s, m, "Could not stop monitoring channel");
@@ -1440,73 +1342,15 @@ static int manager_stop_mixmonitor(struct mansession *s, const struct message *m
 
 	astman_append(s, "\r\n");
 
-	ast_channel_unref(c);
+	c = ast_channel_unref(c);
 
 	return AMI_SUCCESS;
 }
 
-static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data,
-		char *buf, size_t len)
-{
-	struct ast_datastore *datastore;
-	struct mixmonitor_ds *ds_data;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(id);
-		AST_APP_ARG(key);
-	);
-
-	AST_STANDARD_APP_ARGS(args, data);
-
-	if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
-		ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
-				"An ID and key must be provided\n", cmd);
-		return -1;
-	}
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
-	ast_channel_unlock(chan);
-
-	if (!datastore) {
-		ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
-		return -1;
-	}
-
-	ds_data = datastore->data;
-
-	if (!strcasecmp(args.key, "filename")) {
-		ast_copy_string(buf, ds_data->filename, len);
-	} else {
-		ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
-		return -1;
-	}
-	return 0;
-}
-
-static struct ast_custom_function mixmonitor_function = {
-	.name = "MIXMONITOR",
-	.read = func_mixmonitor_read,
-};
-
 static struct ast_cli_entry cli_mixmonitor[] = {
 	AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
 };
 
-static int set_mixmonitor_methods(void)
-{
-	struct ast_mixmonitor_methods mixmonitor_methods = {
-		.start = start_mixmonitor_callback,
-		.stop = stop_mixmonitor_callback,
-	};
-
-	return ast_set_mixmonitor_methods(&mixmonitor_methods);
-}
-
-static int clear_mixmonitor_methods(void)
-{
-	return ast_clear_mixmonitor_methods();
-}
-
 static int unload_module(void)
 {
 	int res;
@@ -1517,9 +1361,6 @@ static int unload_module(void)
 	res |= ast_manager_unregister("MixMonitorMute");
 	res |= ast_manager_unregister("MixMonitor");
 	res |= ast_manager_unregister("StopMixMonitor");
-	res |= ast_custom_function_unregister(&mixmonitor_function);
-	res |= clear_mixmonitor_methods();
-
 	return res;
 }
 
@@ -1533,8 +1374,6 @@ static int load_module(void)
 	res |= ast_manager_register_xml("MixMonitorMute", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_mute_mixmonitor);
 	res |= ast_manager_register_xml("MixMonitor", EVENT_FLAG_SYSTEM, manager_mixmonitor);
 	res |= ast_manager_register_xml("StopMixMonitor", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_stop_mixmonitor);
-	res |= ast_custom_function_register(&mixmonitor_function);
-	res |= set_mixmonitor_methods();
 
 	return res;
 }
diff --git a/apps/app_morsecode.c b/apps/app_morsecode.c
index 9210c54..2d7c117 100644
--- a/apps/app_morsecode.c
+++ b/apps/app_morsecode.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -186,5 +186,4 @@ static int load_module(void)
 	return ast_register_application_xml(app_morsecode, morsecode_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Morse code");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Morse code");
diff --git a/apps/app_mp3.c b/apps/app_mp3.c
index e6a0462..463a919 100644
--- a/apps/app_mp3.c
+++ b/apps/app_mp3.c
@@ -34,7 +34,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -47,7 +47,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
 #define MPG_123 "/usr/bin/mpg123"
@@ -144,7 +143,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data)
 	int fds[2];
 	int ms = -1;
 	int pid = -1;
-	RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup);
+	struct ast_format owriteformat;
 	int timeout = 2000;
 	struct timeval next;
 	struct ast_frame *f;
@@ -156,6 +155,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data)
 		.f = { 0, },
 	};
 
+	ast_format_clear(&owriteformat);
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
 		return -1;
@@ -168,21 +168,12 @@ static int mp3_exec(struct ast_channel *chan, const char *data)
 	
 	ast_stopstream(chan);
 
-	owriteformat = ao2_bump(ast_channel_writeformat(chan));
-	res = ast_set_write_format(chan, ast_format_slin);
+	ast_format_copy(&owriteformat, ast_channel_writeformat(chan));
+	res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
 	if (res < 0) {
 		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
 		return -1;
 	}
-
-	myf.f.frametype = AST_FRAME_VOICE;
-	myf.f.subclass.format = ast_format_slin;
-	myf.f.mallocd = 0;
-	myf.f.offset = AST_FRIENDLY_OFFSET;
-	myf.f.src = __PRETTY_FUNCTION__;
-	myf.f.delivery.tv_sec = 0;
-	myf.f.delivery.tv_usec = 0;
-	myf.f.data.ptr = myf.frdata;
 	
 	res = mp3play(data, fds[1]);
 	if (!strncasecmp(data, "http://", 7)) {
@@ -200,8 +191,16 @@ static int mp3_exec(struct ast_channel *chan, const char *data)
 			if (ms <= 0) {
 				res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
 				if (res > 0) {
+					myf.f.frametype = AST_FRAME_VOICE;
+					ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0);
 					myf.f.datalen = res;
 					myf.f.samples = res / 2;
+					myf.f.mallocd = 0;
+					myf.f.offset = AST_FRIENDLY_OFFSET;
+					myf.f.src = __PRETTY_FUNCTION__;
+					myf.f.delivery.tv_sec = 0;
+					myf.f.delivery.tv_usec = 0;
+					myf.f.data.ptr = myf.frdata;
 					if (ast_write(chan, &myf.f) < 0) {
 						res = -1;
 						break;
@@ -242,10 +241,8 @@ static int mp3_exec(struct ast_channel *chan, const char *data)
 	
 	if (pid > -1)
 		kill(pid, SIGKILL);
-	if (!res && owriteformat)
-		ast_set_write_format(chan, owriteformat);
-
-	ast_frfree(&myf.f);
+	if (!res && owriteformat.id)
+		ast_set_write_format(chan, &owriteformat);
 	
 	return res;
 }
@@ -260,5 +257,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, mp3_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Silly MP3 Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");
diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c
index 5eafe2e..8cf02b3 100644
--- a/apps/app_nbscat.c
+++ b/apps/app_nbscat.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <fcntl.h>
 #include <sys/time.h>
@@ -46,7 +46,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="NBScat" language="en_US">
@@ -116,7 +115,7 @@ static int NBScat_exec(struct ast_channel *chan, const char *data)
 	int fds[2];
 	int ms = -1;
 	int pid = -1;
-	struct ast_format *owriteformat;
+	struct ast_format owriteformat;
 	struct timeval next;
 	struct ast_frame *f;
 	struct myframe {
@@ -125,6 +124,7 @@ static int NBScat_exec(struct ast_channel *chan, const char *data)
 		short frdata[160];
 	} myf;
 
+	ast_format_clear(&owriteformat);
 	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
 		ast_log(LOG_WARNING, "Unable to create socketpair\n");
 		return -1;
@@ -132,22 +132,12 @@ static int NBScat_exec(struct ast_channel *chan, const char *data)
 	
 	ast_stopstream(chan);
 
-	owriteformat = ao2_bump(ast_channel_writeformat(chan));
-	res = ast_set_write_format(chan, ast_format_slin);
+	ast_format_copy(&owriteformat, ast_channel_writeformat(chan));
+	res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
 	if (res < 0) {
 		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
-		ao2_cleanup(owriteformat);
 		return -1;
 	}
-
-	myf.f.frametype = AST_FRAME_VOICE;
-	myf.f.subclass.format = ast_format_slin;
-	myf.f.mallocd = 0;
-	myf.f.offset = AST_FRIENDLY_OFFSET;
-	myf.f.src = __PRETTY_FUNCTION__;
-	myf.f.delivery.tv_sec = 0;
-	myf.f.delivery.tv_usec = 0;
-	myf.f.data.ptr = myf.frdata;
 	
 	res = NBScatplay(fds[1]);
 	/* Wait 1000 ms first */
@@ -162,8 +152,16 @@ static int NBScat_exec(struct ast_channel *chan, const char *data)
 			if (ms <= 0) {
 				res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
 				if (res > 0) {
+					myf.f.frametype = AST_FRAME_VOICE;
+					ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0);
 					myf.f.datalen = res;
 					myf.f.samples = res / 2;
+					myf.f.mallocd = 0;
+					myf.f.offset = AST_FRIENDLY_OFFSET;
+					myf.f.src = __PRETTY_FUNCTION__;
+					myf.f.delivery.tv_sec = 0;
+					myf.f.delivery.tv_usec = 0;
+					myf.f.data.ptr = myf.frdata;
 					if (ast_write(chan, &myf.f) < 0) {
 						res = -1;
 						break;
@@ -201,13 +199,11 @@ static int NBScat_exec(struct ast_channel *chan, const char *data)
 	}
 	close(fds[0]);
 	close(fds[1]);
-	ast_frfree(&myf.f);
 	
 	if (pid > -1)
 		kill(pid, SIGKILL);
-	if (!res && owriteformat)
-		ast_set_write_format(chan, owriteformat);
-	ao2_cleanup(owriteformat);
+	if (!res && owriteformat.id)
+		ast_set_write_format(chan, &owriteformat);
 
 	return res;
 }
@@ -222,5 +218,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, NBScat_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Silly NBS Stream Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application");
diff --git a/apps/app_originate.c b/apps/app_originate.c
index cced3ad..8eb8ba3 100644
--- a/apps/app_originate.c
+++ b/apps/app_originate.c
@@ -38,14 +38,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 static const char app_originate[] = "Originate";
 
@@ -113,22 +112,22 @@ static int originate_exec(struct ast_channel *chan, const char *data)
 	int outgoing_status = 0;
 	unsigned int timeout = 30;
 	static const char default_exten[] = "s";
-	struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format tmpfmt;
+	struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
 
 	ast_autoservice_start(chan);
 	if (!cap_slin) {
 		goto return_cleanup;
 	}
-
-	ast_format_cap_append(cap_slin, ast_format_slin, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin12, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin16, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin24, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin32, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin44, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin48, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin96, 0);
-	ast_format_cap_append(cap_slin, ast_format_slin192, 0);
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0));
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0));
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_ERROR, "Originate() requires arguments\n");
@@ -178,15 +177,15 @@ static int originate_exec(struct ast_channel *chan, const char *data)
 				chantech, chandata, args.arg1, exten, priority);
 
 		ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
-				timeout * 1000, args.arg1, exten, priority, &outgoing_status, 1, NULL,
-				NULL, NULL, NULL, NULL, 0, NULL);
+				timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
+				NULL, NULL, NULL, NULL, 0);
 	} else if (!strcasecmp(args.type, "app")) {
 		ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
 				chantech, chandata, args.arg1, S_OR(args.arg2, ""));
 
 		ast_pbx_outgoing_app(chantech, cap_slin, chandata,
-				timeout * 1000, args.arg1, args.arg2, &outgoing_status, 1, NULL,
-				NULL, NULL, NULL, NULL, NULL);
+				timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
+				NULL, NULL, NULL, NULL);
 	} else {
 		ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
 				args.type);
@@ -223,7 +222,7 @@ return_cleanup:
 			break;
 		}
 	}
-	ao2_cleanup(cap_slin);
+	cap_slin = ast_format_cap_destroy(cap_slin);
 	ast_autoservice_stop(chan);
 
 	return res;
diff --git a/apps/app_osplookup.c b/apps/app_osplookup.c
index abdfa12..363254b 100644
--- a/apps/app_osplookup.c
+++ b/apps/app_osplookup.c
@@ -36,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <osp/osp.h>
 #include <osp/osputils.h>
@@ -1425,7 +1425,9 @@ static int osp_uuid2str(
 	int res;
 
 	if ((uuid != NULL) && (bufsize > OSP_SIZE_UUIDSTR)) {
-		snprintf(buffer, bufsize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		snprintf(buffer, bufsize, "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-"
+					  "%02hhx%02hhx-%02hhx%02hhx-"
+					  "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
 			uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
 			uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
 		res = OSP_OK;
@@ -2281,9 +2283,9 @@ static int ospauth_exec(
 
 	headp = ast_channel_varshead(chan);
 	AST_LIST_TRAVERSE(headp, current, entries) {
-		if (!strcmp(ast_var_name(current), "OSPINPEERIP")) {
+		if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
 			source = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINTOKEN")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
 			token = ast_var_value(current);
 		}
 	}
@@ -2405,69 +2407,69 @@ static int osplookup_exec(
 
 	headp = ast_channel_varshead(chan);
 	AST_LIST_TRAVERSE(headp, current, entries) {
-		if (!strcmp(ast_var_name(current), "OSPINACTUALSRC")) {
+		if (!strcasecmp(ast_var_name(current), "OSPINACTUALSRC")) {
 			actualsrc = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINPEERIP")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
 			srcdev = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINTECH")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINTECH")) {
 			ast_copy_string(results.intech, ast_var_value(current), sizeof(results.intech));
-		} else if (!strcmp(ast_var_name(current), "OSPINHANDLE")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
 				results.inhandle = OSP_INVALID_HANDLE;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPINTIMELIMIT")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
 				results.intimelimit = OSP_DEF_TIMELIMIT;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPINNETWORKID")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
 			snetid = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINNPRN")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINNPRN")) {
 			np.rn = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINNPCIC")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINNPCIC")) {
 			np.cic = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINNPDI")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINNPDI")) {
 			if (ast_true(ast_var_value(current))) {
 				np.npdi = 1;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPINSPID")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINSPID")) {
 			np.opname[OSPC_OPNAME_SPID] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINOCN")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINOCN")) {
 			np.opname[OSPC_OPNAME_OCN] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINSPN")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINSPN")) {
 			np.opname[OSPC_OPNAME_SPN] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINALTSPN")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINALTSPN")) {
 			np.opname[OSPC_OPNAME_ALTSPN] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINMCC")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINMCC")) {
 			np.opname[OSPC_OPNAME_MCC] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINMNC")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINMNC")) {
 			np.opname[OSPC_OPNAME_MNC] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINTOHOST")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINTOHOST")) {
 			ast_copy_string(results.dest, ast_var_value(current), sizeof(results.dest));
-		} else if (!strcmp(ast_var_name(current), "OSPINRPIDUSER")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINRPIDUSER")) {
 			headers.rpiduser = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINPAIUSER")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINPAIUSER")) {
 			headers.paiuser = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINDIVUSER")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINDIVUSER")) {
 			headers.divuser = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINDIVHOST")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINDIVHOST")) {
 			headers.divhost = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINPCIUSER")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINPCIUSER")) {
 			headers.pciuser = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO1")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO1")) {
 			cinfo[0] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO2")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO2")) {
 			cinfo[1] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO3")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO3")) {
 			cinfo[2] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO4")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO4")) {
 			cinfo[3] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO5")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO5")) {
 			cinfo[4] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO6")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO6")) {
 			cinfo[5] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO7")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO7")) {
 			cinfo[6] = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "OSPINCUSTOMINFO8")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO8")) {
 			cinfo[7] = ast_var_value(current);
 		}
 	}
@@ -2669,23 +2671,23 @@ static int ospnext_exec(
 
 	headp = ast_channel_varshead(chan);
 	AST_LIST_TRAVERSE(headp, current, entries) {
-		if (!strcmp(ast_var_name(current), "OSPINHANDLE")) {
+		if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
 				results.inhandle = OSP_INVALID_HANDLE;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPOUTHANDLE")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.outhandle) != 1) {
 				results.outhandle = OSP_INVALID_HANDLE;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPINTIMELIMIT")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
 				results.intimelimit = OSP_DEF_TIMELIMIT;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
 			if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
 				callidtypes = OSP_CALLID_UNDEF;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPDESTREMAILS")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPDESTREMAILS")) {
 			if (sscanf(ast_var_value(current), "%30d", &results.numdests) != 1) {
 				results.numdests = 0;
 			}
@@ -2814,7 +2816,7 @@ static int ospfinished_exec(
 	int inhandle = OSP_INVALID_HANDLE;
 	int outhandle = OSP_INVALID_HANDLE;
 	int recorded = 0;
-	time_t start = 0, connect = 0, end = 0;
+	time_t start, connect, end;
 	unsigned int release;
 	char buffer[OSP_SIZE_INTSTR];
 	char inqos[OSP_SIZE_QOSSTR] = { 0 };
@@ -2833,25 +2835,25 @@ static int ospfinished_exec(
 
 	headp = ast_channel_varshead(chan);
 	AST_LIST_TRAVERSE(headp, current, entries) {
-		if (!strcmp(ast_var_name(current), "OSPINHANDLE")) {
+		if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
 			if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
 				inhandle = OSP_INVALID_HANDLE;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPOUTHANDLE")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
 			if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
 				outhandle = OSP_INVALID_HANDLE;
 			}
 		} else if (!recorded &&
-			(!strcmp(ast_var_name(current), "OSPAUTHSTATUS") ||
-			!strcmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
-			!strcmp(ast_var_name(current), "OSPNEXTSTATUS")))
+			(!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
+			!strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
+			!strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
 		{
-			if (strcmp(ast_var_value(current), AST_OSP_SUCCESS)) {
+			if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
 				recorded = 1;
 			}
-		} else if (!strcmp(ast_var_name(current), "OSPINAUDIOQOS")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPINAUDIOQOS")) {
 			ast_copy_string(inqos, ast_var_value(current), sizeof(inqos));
-		} else if (!strcmp(ast_var_name(current), "OSPOUTAUDIOQOS")) {
+		} else if (!strcasecmp(ast_var_name(current), "OSPOUTAUDIOQOS")) {
 			ast_copy_string(outqos, ast_var_value(current), sizeof(outqos));
 		}
 	}
@@ -2866,18 +2868,19 @@ static int ospfinished_exec(
 	}
 	ast_debug(1, "OSPFinish: cause '%d'\n", cause);
 
-	if (!ast_tvzero(ast_channel_creationtime(chan))) {
-		start = ast_channel_creationtime(chan).tv_sec;
-	}
-	if (!ast_tvzero(ast_channel_answertime(chan))) {
-		connect = ast_channel_answertime(chan).tv_sec;
-	}
-	if (connect) {
-		end = time(NULL);
+	if (ast_channel_cdr(chan)) {
+		start = ast_channel_cdr(chan)->start.tv_sec;
+		connect = ast_channel_cdr(chan)->answer.tv_sec;
+		if (connect) {
+			end = time(NULL);
+		} else {
+			end = connect;
+		}
 	} else {
-		end = connect;
+		start = 0;
+		connect = 0;
+		end = 0;
 	}
-
 	ast_debug(1, "OSPFinish: start '%ld'\n", start);
 	ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
 	ast_debug(1, "OSPFinish: end '%ld'\n", end);
@@ -3158,7 +3161,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/apps/app_page.c b/apps/app_page.c
index e31cb78..8e7d1d2 100644
--- a/apps/app_page.c
+++ b/apps/app_page.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410158 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
@@ -65,27 +65,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410158 $")
 			</parameter>
 			<parameter name="options">
 				<optionlist>
-				<option name="b" argsep="^">
-					<para>Before initiating an outgoing call, Gosub to the specified
-					location using the newly created channel.  The Gosub will be
-					executed for each destination channel.</para>
-					<argument name="context" required="false" />
-					<argument name="exten" required="false" />
-					<argument name="priority" required="true" hasparams="optional" argsep="^">
-						<argument name="arg1" multiple="true" required="true" />
-						<argument name="argN" />
-					</argument>
-				</option>
-				<option name="B" argsep="^">
-					<para>Before initiating the outgoing call(s), Gosub to the specified
-					location using the current channel.</para>
-					<argument name="context" required="false" />
-					<argument name="exten" required="false" />
-					<argument name="priority" required="true" hasparams="optional" argsep="^">
-						<argument name="arg1" multiple="true" required="true" />
-						<argument name="argN" />
-					</argument>
-				</option>
 					<option name="d">
 						<para>Full duplex audio</para>
 					</option>
@@ -139,20 +118,14 @@ enum page_opt_flags {
 	PAGE_IGNORE_FORWARDS = (1 << 4),
 	PAGE_ANNOUNCE = (1 << 5),
 	PAGE_NOCALLERANNOUNCE = (1 << 6),
-	PAGE_PREDIAL_CALLEE = (1 << 7),
-	PAGE_PREDIAL_CALLER = (1 << 8),
 };
 
 enum {
 	OPT_ARG_ANNOUNCE = 0,
-	OPT_ARG_PREDIAL_CALLEE = 1,
-	OPT_ARG_PREDIAL_CALLER = 2,
-	OPT_ARG_ARRAY_SIZE = 3,
+	OPT_ARG_ARRAY_SIZE = 1,
 };
 
 AST_APP_OPTIONS(page_opts, {
-	AST_APP_OPTION_ARG('b', PAGE_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE),
-	AST_APP_OPTION_ARG('B', PAGE_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER),
 	AST_APP_OPTION('d', PAGE_DUPLEX),
 	AST_APP_OPTION('q', PAGE_QUIET),
 	AST_APP_OPTION('r', PAGE_RECORD),
@@ -310,12 +283,6 @@ static int page_exec(struct ast_channel *chan, const char *data)
 		return -1;
 	}
 
-	if (ast_test_flag(&options.flags, PAGE_PREDIAL_CALLER)
-		&& !ast_strlen_zero(options.opts[OPT_ARG_PREDIAL_CALLER])) {
-		ast_replace_subargument_delimiter(options.opts[OPT_ARG_PREDIAL_CALLER]);
-		ast_app_exec_sub(NULL, chan, options.opts[OPT_ARG_PREDIAL_CALLER], 0);
-	}
-
 	/* Go through parsing/calling each device */
 	while ((tech = strsep(&args.devices, "&"))) {
 		int state = 0;
@@ -351,7 +318,7 @@ static int page_exec(struct ast_channel *chan, const char *data)
 		}
 
 		/* Append technology and resource */
-		if (ast_dial_append(dial, tech, resource, NULL) == -1) {
+		if (ast_dial_append(dial, tech, resource) == -1) {
 			ast_log(LOG_ERROR, "Failed to add %s to outbound dial\n", tech);
 			ast_dial_destroy(dial);
 			continue;
@@ -360,11 +327,6 @@ static int page_exec(struct ast_channel *chan, const char *data)
 		/* Set ANSWER_EXEC as global option */
 		ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, confbridgeopts);
 
-		if (ast_test_flag(&options.flags, PAGE_PREDIAL_CALLEE)
-			&& !ast_strlen_zero(options.opts[OPT_ARG_PREDIAL_CALLEE])) {
-			ast_dial_option_global_enable(dial, AST_DIAL_OPTION_PREDIAL, options.opts[OPT_ARG_PREDIAL_CALLEE]);
-		}
-
 		if (timeout) {
 			ast_dial_set_global_timeout(dial, timeout * 1000);
 		}
diff --git a/apps/app_parkandannounce.c b/apps/app_parkandannounce.c
new file mode 100644
index 0000000..6d6ccae
--- /dev/null
+++ b/apps/app_parkandannounce.c
@@ -0,0 +1,249 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * Author: Ben Miller <bgmiller at dccinc.com>
+ *    With TONS of help from Mark!
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ParkAndAnnounce application for Asterisk
+ *
+ * \author Ben Miller <bgmiller at dccinc.com>
+ * \arg With TONS of help from Mark!
+ *
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/features.h"
+#include "asterisk/say.h"
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+
+/*** DOCUMENTATION
+	<application name="ParkAndAnnounce" language="en_US">
+		<synopsis>
+			Park and Announce.
+		</synopsis>
+		<syntax>
+			<parameter name="announce_template" required="true" argsep=":">
+				<argument name="announce" required="true">
+					<para>Colon-separated list of files to announce. The word
+					<literal>PARKED</literal> will be replaced by a say_digits of the extension in which
+					the call is parked.</para>
+				</argument>
+				<argument name="announce1" multiple="true" />
+			</parameter>
+			<parameter name="timeout" required="true">
+				<para>Time in seconds before the call returns into the return
+				context.</para>
+			</parameter>
+			<parameter name="dial" required="true">
+				<para>The app_dial style resource to call to make the
+				announcement. Console/dsp calls the console.</para>
+			</parameter>
+			<parameter name="return_context">
+				<para>The goto-style label to jump the call back into after
+				timeout. Default <literal>priority+1</literal>.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Park a call into the parkinglot and announce the call to another channel.</para>
+			<para>The variable <variable>PARKEDAT</variable> will contain the parking extension
+			into which the call was placed.  Use with the Local channel to allow the dialplan to make
+			use of this information.</para>
+		</description>
+		<see-also>
+			<ref type="application">Park</ref>
+			<ref type="application">ParkedCall</ref>
+		</see-also>
+	</application>
+ ***/
+
+static char *app = "ParkAndAnnounce";
+
+static int parkandannounce_exec(struct ast_channel *chan, const char *data)
+{
+	int res = -1;
+	int lot, timeout = 0, dres;
+	char *dialtech, *tmp[100], buf[13];
+	int looptemp, i;
+	char *s;
+	struct ast_party_id caller_id;
+
+	struct ast_channel *dchan;
+	struct outgoing_helper oh = { 0, };
+	int outstate;
+	struct ast_format tmpfmt;
+	struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(template);
+		AST_APP_ARG(timeout);
+		AST_APP_ARG(dial);
+		AST_APP_ARG(return_context);
+	);
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce_template,timeout,dial,[return_context])\n");
+		res = -1;
+		goto parkcleanup;
+	}
+	if (!cap_slin) {
+		res = -1;
+		goto parkcleanup;
+	}
+	ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+
+	s = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, s);
+
+	if (args.timeout)
+		timeout = atoi(args.timeout) * 1000;
+
+	if (ast_strlen_zero(args.dial)) {
+		ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or DAHDI/g1/5551212\n");
+		res = -1;
+		goto parkcleanup;
+	}
+
+	dialtech = strsep(&args.dial, "/");
+	ast_verb(3, "Dial Tech,String: (%s,%s)\n", dialtech, args.dial);
+
+	if (!ast_strlen_zero(args.return_context)) {
+		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+		ast_parseable_goto(chan, args.return_context);
+	} else {
+		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
+	}
+
+	ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", ast_channel_context(chan), ast_channel_exten(chan),
+		ast_channel_priority(chan),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
+	if (!ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
+		ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
+	}
+
+	/* Save the CallerID because the masquerade turns chan into a ZOMBIE. */
+	ast_party_id_init(&caller_id);
+	ast_channel_lock(chan);
+	ast_party_id_copy(&caller_id, &ast_channel_caller(chan)->id);
+	ast_channel_unlock(chan);
+
+	/* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
+	before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
+
+	res = ast_masq_park_call(chan, NULL, timeout, &lot);
+	if (res) {
+		/* Parking failed. */
+		ast_party_id_free(&caller_id);
+		res = -1;
+		goto parkcleanup;
+	}
+
+	ast_verb(3, "Call parked in space: %d, timeout: %d, return-context: %s\n",
+		lot, timeout, args.return_context ? args.return_context : "");
+
+	/* Now place the call to the extension */
+
+	snprintf(buf, sizeof(buf), "%d", lot);
+	oh.parent_channel = chan;
+	oh.vars = ast_variable_new("_PARKEDAT", buf, "");
+	dchan = __ast_request_and_dial(dialtech, cap_slin, chan, args.dial, 30000,
+		&outstate,
+		S_COR(caller_id.number.valid, caller_id.number.str, NULL),
+		S_COR(caller_id.name.valid, caller_id.name.str, NULL),
+		&oh);
+	ast_variables_destroy(oh.vars);
+	ast_party_id_free(&caller_id);
+	if (dchan) {
+		if (ast_channel_state(dchan) == AST_STATE_UP) {
+			ast_verb(4, "Channel %s was answered.\n", ast_channel_name(dchan));
+		} else {
+			ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(dchan));
+			ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", ast_channel_name(dchan));
+			ast_hangup(dchan);
+			res = -1;
+			goto parkcleanup;
+		}
+	} else {
+		ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
+		res = -1;
+		goto parkcleanup;
+	}
+
+	ast_stopstream(dchan);
+
+	/* now we have the call placed and are ready to play stuff to it */
+
+	ast_verb(4, "Announce Template:%s\n", args.template);
+
+	for (looptemp = 0; looptemp < ARRAY_LEN(tmp); looptemp++) {
+		if ((tmp[looptemp] = strsep(&args.template, ":")) != NULL)
+			continue;
+		else
+			break;
+	}
+
+	for (i = 0; i < looptemp; i++) {
+		ast_verb(4, "Announce:%s\n", tmp[i]);
+		if (!strcmp(tmp[i], "PARKED")) {
+			ast_say_digits(dchan, lot, "", ast_channel_language(dchan));
+		} else {
+			dres = ast_streamfile(dchan, tmp[i], ast_channel_language(dchan));
+			if (!dres) {
+				dres = ast_waitstream(dchan, "");
+			} else {
+				ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], ast_channel_name(dchan));
+			}
+		}
+	}
+
+	ast_stopstream(dchan);  
+	ast_hangup(dchan);
+
+parkcleanup:
+	cap_slin = ast_format_cap_destroy(cap_slin);
+
+	return res;
+}
+
+static int unload_module(void)
+{
+	return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+	/* return ast_register_application(app, park_exec); */
+	return ast_register_application_xml(app, parkandannounce_exec);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");
diff --git a/apps/app_playback.c b/apps/app_playback.c
index cded2cb..0ba4456 100644
--- a/apps/app_playback.c
+++ b/apps/app_playback.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
@@ -82,14 +82,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 			<para>See Also: Background (application) -- for playing sound files that are interruptible</para>
 			<para>WaitExten (application) -- wait for digits from caller, optionally play music on hold</para>
 		</description>
-		<see-also>
-			<ref type="application">Background</ref>
-			<ref type="application">WaitExten</ref>
-			<ref type="application">ControlPlayback</ref>
-			<ref type="agi">stream file</ref>
-			<ref type="agi">control stream file</ref>
-			<ref type="manager">ControlPlayback</ref>
-		</see-also>
 	</application>
  ***/
 
@@ -485,12 +477,11 @@ static int playback_exec(struct ast_channel *chan, const char *data)
 				res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
 			else
 				res = ast_streamfile(chan, front, ast_channel_language(chan));
-			if (!res) {
-				res = ast_waitstream(chan, "");
+			if (!res) { 
+				res = ast_waitstream(chan, "");	
 				ast_stopstream(chan);
-			}
-			if (res) {
-				ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
+			} else {
+				ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char *)data);
 				res = 0;
 				mres = 1;
 			}
@@ -570,7 +561,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_playtones.c b/apps/app_playtones.c
index c2c307e..fd947dd 100644
--- a/apps/app_playtones.c
+++ b/apps/app_playtones.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356042 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
diff --git a/apps/app_privacy.c b/apps/app_privacy.c
index 190463e..0e04df6 100644
--- a/apps/app_privacy.c
+++ b/apps/app_privacy.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 357542 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
diff --git a/apps/app_queue.c b/apps/app_queue.c
index cd3b0b2..e178784 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -22,6 +22,8 @@
  *
  * \author Mark Spencer <markster at digium.com>
  *
+ * \arg Config in \ref Config_qu queues.conf
+ *
  * \par Development notes
  * \note 2004-11-25: Persistent Dynamic Members added by:
  *             NetNation Communications (www.netnation.com)
@@ -54,14 +56,6 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_queues.c uses configuration file \ref queues.conf
- * \addtogroup configuration_file
- */
-
-/*! \page queues.conf queues.conf
- * \verbinclude queues.conf.sample
- */
-
 /*** MODULEINFO
 	<use type="module">res_monitor</use>
 	<support_level>core</support_level>
@@ -69,7 +63,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <sys/signal.h>
@@ -96,23 +90,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/astdb.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/event.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/strings.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/aoc.h"
 #include "asterisk/callerid.h"
+#include "asterisk/cel.h"
 #include "asterisk/data.h"
-#include "asterisk/term.h"
-#include "asterisk/dial.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/core_local.h"
-#include "asterisk/mixmonitor.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/bridge_basic.h"
 
 /*!
  * \par Please read before modifying this file.
@@ -542,7 +528,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 			Count number of members answering a queue.
 		</synopsis>
 		<syntax>
-			<parameter name="queuename" required="true" />
+			<parameter name="queuename" required="false" />
 			<parameter name="option" required="true">
 				<enumlist>
 					<enum name="logged">
@@ -558,13 +544,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 						<para>Returns the total number of members for the specified queue.</para>
 					</enum>
 					<enum name="penalty">
-						<para>Gets or sets queue member penalty.</para>
+						<para>Gets or sets queue member penalty.  If
+						<replaceable>queuename</replaceable> is not specified
+						when setting the penalty then the penalty is set in all queues
+						the interface is a member.</para>
 					</enum>
 					<enum name="paused">
-						<para>Gets or sets queue member paused status.</para>
+						<para>Gets or sets queue member paused status.  If
+						<replaceable>queuename</replaceable> is not specified
+						when setting the paused status then the paused status is set
+						in all queues the interface is a member.</para>
 					</enum>
 					<enum name="ringinuse">
-						<para>Gets or sets queue member ringinuse.</para>
+						<para>Gets or sets queue member ringinuse.  If
+						<replaceable>queuename</replaceable> is not specified
+						when setting ringinuse then ringinuse is set
+						in all queues the interface is a member.</para>
 					</enum>
 				</enumlist>
 			</parameter>
@@ -572,10 +567,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 		</syntax>
 		<description>
 			<para>Allows access to queue counts [R] and member information [R/W].</para>
-			<para>
-				<replaceable>queuename</replaceable> is required for all operations
-				<replaceable>interface</replaceable> is required for all member operations.
-			</para>
+			<para><replaceable>queuename</replaceable> is required for all read operations.</para>
+			<para><replaceable>interface</replaceable> is required for all member operations.</para>
 		</description>
 		<see-also>
 			<ref type="application">Queue</ref>
@@ -867,6 +860,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 			<para>Change the penalty of a queue member</para>
 		</description>
 	</manager>
+
 	<manager name="QueueMemberRingInUse" language="en_US">
 		<synopsis>
 			Set the ringinuse value for a queue member.
@@ -880,6 +874,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 		<description>
 		</description>
 	</manager>
+
 	<manager name="QueueRule" language="en_US">
 		<synopsis>
 			Queue Rules.
@@ -942,275 +937,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 			<para>Reset the statistics for a queue.</para>
 		</description>
 	</manager>
-
-	<managerEvent language="en_US" name="QueueMemberStatus">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a Queue member's status has changed.</synopsis>
-			<syntax>
-				<parameter name="Queue">
-					<para>The name of the queue.</para>
-				</parameter>
-				<parameter name="MemberName">
-					<para>The name of the queue member.</para>
-				</parameter>
-				<parameter name="Interface">
-					<para>The queue member's channel technology or location.</para>
-				</parameter>
-				<parameter name="StateInterface">
-					<para>Channel technology or location from which to read device state changes.</para>
-				</parameter>
-				<parameter name="Membership">
-					<enumlist>
-						<enum name="dynamic"/>
-						<enum name="realtime"/>
-						<enum name="static"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Penalty">
-					<para>The penalty associated with the queue member.</para>
-				</parameter>
-				<parameter name="CallsTaken">
-					<para>The number of calls this queue member has serviced.</para>
-				</parameter>
-				<parameter name="LastCall">
-					<para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
-				</parameter>
-				<parameter name="Status">
-					<para>The numeric device state status of the queue member.</para>
-					<enumlist>
-						<enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
-						<enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
-						<enum name="2"><para>AST_DEVICE_INUSE</para></enum>
-						<enum name="3"><para>AST_DEVICE_BUSY</para></enum>
-						<enum name="4"><para>AST_DEVICE_INVALID</para></enum>
-						<enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
-						<enum name="6"><para>AST_DEVICE_RINGING</para></enum>
-						<enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
-						<enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
-					</enumlist>
-				</parameter>
-				<parameter name="Paused">
-					<enumlist>
-						<enum name="0"/>
-						<enum name="1"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Ringinuse">
-					<enumlist>
-						<enum name="0"/>
-						<enum name="1"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueMemberAdded">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a member is added to the queue.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">QueueMemberRemoved</ref>
-				<ref type="application">AddQueueMember</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueMemberRemoved">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a member is removed from the queue.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">QueueMemberAdded</ref>
-				<ref type="application">RemoveQueueMember</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueMemberPause">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
-				<parameter name="Reason">
-					<para>The reason a member was paused.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">PauseQueueMember</ref>
-				<ref type="application">UnPauseQueueMember</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueMemberPenalty">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a member's penalty is changed.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="function">QUEUE_MEMBER</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueMemberRinginuse">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="function">QUEUE_MEMBER</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueCallerJoin">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a caller joins a Queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<parameter name="Position">
-					<para>This channel's current position in the queue.</para>
-				</parameter>
-				<parameter name="Count">
-					<para>The total number of channels in the queue.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">QueueCallerLeave</ref>
-				<ref type="application">Queue</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueCallerLeave">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a caller leaves a Queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">QueueCallerJoin</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="QueueCallerAbandon">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a caller abandons the queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
-				<parameter name="OriginalPosition">
-					<para>The channel's original position in the queue.</para>
-				</parameter>
-				<parameter name="HoldTime">
-					<para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentCalled">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentRingNoAnswer</ref>
-				<ref type="managerEvent">AgentComplete</ref>
-				<ref type="managerEvent">AgentConnect</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentRingNoAnswer">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
-				<parameter name="RingTime">
-					<para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentCalled</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentComplete">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
-				<parameter name="TalkTime">
-					<para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
-				</parameter>
-				<parameter name="Reason">
-					<enumlist>
-						<enum name="caller"/>
-						<enum name="agent"/>
-						<enum name="transfer"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentCalled</ref>
-				<ref type="managerEvent">AgentConnect</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentDump">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentCalled</ref>
-				<ref type="managerEvent">AgentConnect</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentConnect">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentCalled</ref>
-				<ref type="managerEvent">AgentComplete</ref>
-				<ref type="managerEvent">AgentDump</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 enum {
@@ -1311,16 +1037,15 @@ static const struct autopause {
 	{ QUEUE_AUTOPAUSE_ALL,"all" },
 };
 
+
+static struct ast_taskprocessor *devicestate_tps;
+
 #define DEFAULT_RETRY		5
 #define DEFAULT_TIMEOUT		15
 #define RECHECK			1		/*!< Recheck every second to see we we're at the top yet */
 #define MAX_PERIODIC_ANNOUNCEMENTS 10           /*!< The maximum periodic announcements we can have */
-/*!
- * \brief The minimum number of seconds between position announcements.
- * \note The default value of 15 provides backwards compatibility.
- */
-#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
-
+#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15       /*!< The minimum number of seconds between position announcements \
+                                                     The default value of 15 provides backwards compatibility */
 #define MAX_QUEUE_BUCKETS 53
 
 #define	RES_OKAY	0		/*!< Action completed */
@@ -1359,11 +1084,8 @@ static int montype_default = 0;
 /*! \brief queues.conf [general] option */
 static int shared_lastcall = 1;
 
-/*! \brief queuesrules.conf [general] option */
-static int realtime_rules = 0;
-
-/*! \brief Subscription to device state change messages */
-static struct stasis_subscription *device_state_sub;
+/*! \brief Subscription to device state change events */
+static struct ast_event_sub *device_state_sub;
 
 /*! \brief queues.conf [general] option */
 static int update_cdr = 0;
@@ -1573,6 +1295,7 @@ struct call_queue {
 	/*! Sound files: Custom announce, no default */
 	struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
 	unsigned int dead:1;
+	unsigned int eventwhencalled:2;
 	unsigned int ringinuse:1;
 	unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
 	unsigned int setinterfacevar:1;
@@ -1584,6 +1307,7 @@ struct call_queue {
 	unsigned int announceholdtime:2;
 	unsigned int announceposition:3;
 	int strategy:4;
+	unsigned int maskmemberstatus:1;
 	unsigned int realtime:1;
 	unsigned int found:1;
 	unsigned int relativeperiodicannounce:1;
@@ -1643,6 +1367,8 @@ static void update_realtime_members(struct call_queue *q);
 static struct member *interface_exists(struct call_queue *q, const char *interface);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
 
+static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
 /*! \brief sets the QUEUESTATUS channel variable */
 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
@@ -1789,9 +1515,7 @@ static inline struct call_queue *_queue_ref(struct call_queue *q, const char *ta
 
 static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
 {
-	if (q) {
-		__ao2_ref_debug(q, -1, tag, file, line, filename);
-	}
+	__ao2_ref_debug(q, -1, tag, file, line, filename);
 	return NULL;
 }
 
@@ -1810,9 +1534,7 @@ static inline struct call_queue *queue_ref(struct call_queue *q)
 
 static inline struct call_queue *queue_unref(struct call_queue *q)
 {
-	if (q) {
-		ao2_ref(q, -1);
-	}
+	ao2_ref(q, -1);
 	return NULL;
 }
 #endif
@@ -1868,393 +1590,180 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st
 	new->opos = *pos;
 }
 
-static struct ast_manager_event_blob *queue_channel_to_ami(const char *type, struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	event_string = ast_manager_str_from_json_object(obj->blob, NULL);
-	if (!channel_string || !event_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AGENT, type,
-		"%s"
-		"%s",
-		ast_str_buffer(channel_string),
-		ast_str_buffer(event_string));
-}
-
-static struct ast_manager_event_blob *queue_caller_join_to_ami(struct stasis_message *message)
-{
-	return queue_channel_to_ami("QueueCallerJoin", message);
-}
-
-static struct ast_manager_event_blob *queue_caller_leave_to_ami(struct stasis_message *message)
-{
-	return queue_channel_to_ami("QueueCallerLeave", message);
-}
-
-static struct ast_manager_event_blob *queue_caller_abandon_to_ami(struct stasis_message *message)
+/*! \brief Check if members are available
+ *
+ * This function checks to see if members are available to be called. If any member
+ * is available, the function immediately returns 0. If no members are available,
+ * then -1 is returned.
+ */
+static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
 {
-	return queue_channel_to_ami("QueueCallerAbandon", message);
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,
-	.to_ami = queue_caller_join_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type,
-	.to_ami = queue_caller_leave_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type,
-	.to_ami = queue_caller_abandon_to_ami,
-	);
+	struct member *member;
+	struct ao2_iterator mem_iter;
 
-static struct ast_manager_event_blob *queue_member_to_ami(const char *type, struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
+	ao2_lock(q);
+	mem_iter = ao2_iterator_init(q->members, 0);
+	for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
+		if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
+			if (conditions & QUEUE_EMPTY_PENALTY) {
+				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
+				continue;
+			}
+		}
 
-	event_string = ast_manager_str_from_json_object(payload->json, NULL);
-	if (!event_string) {
-		return NULL;
+		switch (devstate ? ast_device_state(member->state_interface) : member->status) {
+		case AST_DEVICE_INVALID:
+			if (conditions & QUEUE_EMPTY_INVALID) {
+				ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
+				break;
+			}
+			goto default_case;
+		case AST_DEVICE_UNAVAILABLE:
+			if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
+				ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
+				break;
+			}
+			goto default_case;
+		case AST_DEVICE_INUSE:
+			if (conditions & QUEUE_EMPTY_INUSE) {
+				ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
+				break;
+			}
+			goto default_case;
+		case AST_DEVICE_RINGING:
+			if (conditions & QUEUE_EMPTY_RINGING) {
+				ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
+				break;
+			}
+			goto default_case;
+		case AST_DEVICE_UNKNOWN:
+			if (conditions & QUEUE_EMPTY_UNKNOWN) {
+				ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
+				break;
+			}
+			/* Fall-through */
+		default:
+		default_case:
+			if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
+				ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
+				break;
+			} else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
+				ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
+				break;
+			} else {
+				ao2_ref(member, -1);
+				ao2_iterator_destroy(&mem_iter);
+				ao2_unlock(q);
+				ast_debug(4, "%s is available.\n", member->membername);
+				return 0;
+			}
+			break;
+		}
 	}
+	ao2_iterator_destroy(&mem_iter);
+	ao2_unlock(q);
 
-	return ast_manager_event_blob_create(EVENT_FLAG_AGENT, type,
-		"%s",
-		ast_str_buffer(event_string));
-}
-
-static struct ast_manager_event_blob *queue_member_status_to_ami(struct stasis_message *message)
-{
-	return queue_member_to_ami("QueueMemberStatus", message);
+	if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
+		/* member state still may be RINGING due to lag in event message - check again with device state */
+		return get_member_status(q, max_penalty, min_penalty, conditions, 1);
+	}
+	return -1;
 }
 
-static struct ast_manager_event_blob *queue_member_added_to_ami(struct stasis_message *message)
-{
-	return queue_member_to_ami("QueueMemberAdded", message);
-}
+struct statechange {
+	AST_LIST_ENTRY(statechange) entry;
+	int state;
+	char dev[0];
+};
 
-static struct ast_manager_event_blob *queue_member_removed_to_ami(struct stasis_message *message)
+/*! \brief set a member's status based on device state of that member's state_interface.
+ *
+ * Lock interface list find sc, iterate through each queues queue_member list for member to
+ * update state inside queues
+*/
+static int update_status(struct call_queue *q, struct member *m, const int status)
 {
-	return queue_member_to_ami("QueueMemberRemoved", message);
-}
+	m->status = status;
 
-static struct ast_manager_event_blob *queue_member_pause_to_ami(struct stasis_message *message)
-{
-	return queue_member_to_ami("QueueMemberPause", message);
-}
+	if (q->maskmemberstatus) {
+		return 0;
+	}
 
-static struct ast_manager_event_blob *queue_member_penalty_to_ami(struct stasis_message *message)
-{
-	return queue_member_to_ami("QueueMemberPenalty", message);
-}
-
-static struct ast_manager_event_blob *queue_member_ringinuse_to_ami(struct stasis_message *message)
-{
-	return queue_member_to_ami("QueueMemberRinginuse", message);
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type,
-	.to_ami = queue_member_status_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type,
-	.to_ami = queue_member_added_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type,
-	.to_ami = queue_member_removed_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type,
-	.to_ami = queue_member_pause_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type,
-	.to_ami = queue_member_penalty_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type,
-	.to_ami = queue_member_ringinuse_to_ami,
-	);
-
-static struct ast_manager_event_blob *queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *obj = stasis_message_data(message);
-	struct ast_channel_snapshot *caller;
-	struct ast_channel_snapshot *agent;
-	RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
-
-	caller = ast_multi_channel_blob_get_channel(obj, "caller");
-	if (caller) {
-		caller_event_string = ast_manager_build_channel_state_string(caller);
-		if (!caller_event_string) {
-			ast_log(LOG_NOTICE, "No caller event string, bailing\n");
-			return NULL;
-		}
-	}
-
-	agent = ast_multi_channel_blob_get_channel(obj, "agent");
-	if (agent) {
-		agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
-		if (!agent_event_string) {
-			ast_log(LOG_NOTICE, "No agent event string, bailing\n");
-			return NULL;
-		}
-	}
-
-	event_string = ast_manager_str_from_json_object(ast_multi_channel_blob_get_json(obj), NULL);
-	if (!event_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AGENT, type,
-		"%s"
-		"%s"
-		"%s",
-		caller_event_string ? ast_str_buffer(caller_event_string) : "",
-		agent_event_string ? ast_str_buffer(agent_event_string) : "",
-		ast_str_buffer(event_string));
-}
-
-static struct ast_manager_event_blob *queue_agent_called_to_ami(struct stasis_message *message)
-{
-	return queue_multi_channel_to_ami("AgentCalled", message);
-}
-
-static struct ast_manager_event_blob *queue_agent_connect_to_ami(struct stasis_message *message)
-{
-	return queue_multi_channel_to_ami("AgentConnect", message);
-}
-
-static struct ast_manager_event_blob *queue_agent_complete_to_ami(struct stasis_message *message)
-{
-	return queue_multi_channel_to_ami("AgentComplete", message);
-}
-
-static struct ast_manager_event_blob *queue_agent_dump_to_ami(struct stasis_message *message)
-{
-	return queue_multi_channel_to_ami("AgentDump", message);
-}
-
-static struct ast_manager_event_blob *queue_agent_ringnoanswer_to_ami(struct stasis_message *message)
-{
-	return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type,
-	.to_ami = queue_agent_called_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type,
-	.to_ami = queue_agent_connect_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type,
-	.to_ami = queue_agent_complete_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_dump_type,
-	.to_ami = queue_agent_dump_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type,
-	.to_ami = queue_agent_ringnoanswer_to_ami,
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>Raised when a Queue member's status has changed.</synopsis>
+		<syntax>
+			<parameter name="Queue">
+				<para>The name of the queue.</para>
+			</parameter>
+			<parameter name="Location">
+				<para>The queue member's channel technology or location.</para>
+			</parameter>
+			<parameter name="MemberName">
+				<para>The name of the queue member.</para>
+			</parameter>
+			<parameter name="StateInterface">
+				<para>Channel technology or location from which to read device state changes.</para>
+			</parameter>
+			<parameter name="Membership">
+				<enumlist>
+					<enum name="dynamic"/>
+					<enum name="realtime"/>
+					<enum name="static"/>
+				</enumlist>
+			</parameter>
+			<parameter name="Penalty">
+				<para>The penalty associated with the queue member.</para>
+			</parameter>
+			<parameter name="CallsTaken">
+				<para>The number of calls this queue member has serviced.</para>
+			</parameter>
+			<parameter name="LastCall">
+				<para>The time this member last took call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
+			</parameter>
+			<parameter name="Status">
+				<para>The numeric device state status of the queue member.</para>
+				<enumlist>
+					<enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
+					<enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
+					<enum name="2"><para>AST_DEVICE_INUSE</para></enum>
+					<enum name="3"><para>AST_DEVICE_BUSY</para></enum>
+					<enum name="4"><para>AST_DEVICE_INVALID</para></enum>
+					<enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
+					<enum name="6"><para>AST_DEVICE_RINGING</para></enum>
+					<enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
+					<enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
+				</enumlist>
+			</parameter>
+			<parameter name="Paused">
+				<enumlist>
+					<enum name="0"/>
+					<enum name="1"/>
+				</enumlist>
+			</parameter>
+		</syntax>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
+		"Queue: %s\r\n"
+		"Location: %s\r\n"
+		"MemberName: %s\r\n"
+		"StateInterface: %s\r\n"
+		"Membership: %s\r\n"
+		"Penalty: %d\r\n"
+		"CallsTaken: %d\r\n"
+		"LastCall: %d\r\n"
+		"Status: %d\r\n"
+		"Paused: %d\r\n",
+		q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
+		m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
 	);
 
-static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic,
-		struct ast_channel_snapshot *caller_snapshot,
-		struct ast_channel_snapshot *agent_snapshot,
-		struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!type) {
-		return;
-	}
-
-	payload = ast_multi_channel_blob_create(blob);
-	if (!payload) {
-		return;
-	}
-
-	ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
-	if (agent_snapshot) {
-		ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
-	}
-
-	msg = stasis_message_create(type, payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(topic, msg);
-}
-
-static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
-		struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
-
-	ast_channel_lock(caller);
-	caller_snapshot = ast_channel_snapshot_create(caller);
-	ast_channel_unlock(caller);
-	ast_channel_lock(agent);
-	agent_snapshot = ast_channel_snapshot_create(agent);
-	ast_channel_unlock(agent);
-
-	if (!caller_snapshot || !agent_snapshot) {
-		return;
-	}
-
-	queue_publish_multi_channel_snapshot_blob(ast_channel_topic(caller), caller_snapshot,
-			agent_snapshot, type, blob);
-}
-
-/*!
- * \internal
- * \brief Publish the member blob.
- * \since 12.0.0
- *
- * \param type Stasis message type to publish.
- * \param blob The information being published.
- *
- * \note The json blob reference is passed to this function.
- *
- * \return Nothing
- */
-static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!blob || !type) {
-		return;
-	}
-
-	payload = ast_json_payload_create(blob);
-	ast_json_unref(blob);
-	if (!payload) {
-		return;
-	}
-
-	msg = stasis_message_create(type, payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_manager_get_topic(), msg);
-}
-
-static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
-{
-	return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i}",
-		"Queue", q->name,
-		"MemberName", mem->membername,
-		"Interface", mem->interface,
-		"StateInterface", mem->state_interface,
-		"Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
-		"Penalty", mem->penalty,
-		"CallsTaken", mem->calls,
-		"LastCall", (int)mem->lastcall,
-		"Status", mem->status,
-		"Paused", mem->paused,
-		"Ringinuse", mem->ringinuse);
-}
-
-/*! \brief Check if members are available
- *
- * This function checks to see if members are available to be called. If any member
- * is available, the function immediately returns 0. If no members are available,
- * then -1 is returned.
- */
-static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
-{
-	struct member *member;
-	struct ao2_iterator mem_iter;
-
-	ao2_lock(q);
-	mem_iter = ao2_iterator_init(q->members, 0);
-	for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
-		if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
-			if (conditions & QUEUE_EMPTY_PENALTY) {
-				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
-				continue;
-			}
-		}
-
-		switch (devstate ? ast_device_state(member->state_interface) : member->status) {
-		case AST_DEVICE_INVALID:
-			if (conditions & QUEUE_EMPTY_INVALID) {
-				ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
-				break;
-			}
-			goto default_case;
-		case AST_DEVICE_UNAVAILABLE:
-			if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
-				ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
-				break;
-			}
-			goto default_case;
-		case AST_DEVICE_INUSE:
-			if (conditions & QUEUE_EMPTY_INUSE) {
-				ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
-				break;
-			}
-			goto default_case;
-		case AST_DEVICE_RINGING:
-			if (conditions & QUEUE_EMPTY_RINGING) {
-				ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
-				break;
-			}
-			goto default_case;
-		case AST_DEVICE_UNKNOWN:
-			if (conditions & QUEUE_EMPTY_UNKNOWN) {
-				ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
-				break;
-			}
-			/* Fall-through */
-		default:
-		default_case:
-			if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
-				ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
-				break;
-			} else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
-				ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
-				break;
-			} else {
-				ao2_ref(member, -1);
-				ao2_iterator_destroy(&mem_iter);
-				ao2_unlock(q);
-				ast_debug(4, "%s is available.\n", member->membername);
-				return 0;
-			}
-			break;
-		}
-	}
-	ao2_iterator_destroy(&mem_iter);
-	ao2_unlock(q);
-
-	if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
-		/* member state still may be RINGING due to lag in event message - check again with device state */
-		return get_member_status(q, max_penalty, min_penalty, conditions, 1);
-	}
-	return -1;
-}
-
-/*! \brief set a member's status based on device state of that member's state_interface.
- *
- * Lock interface list find sc, iterate through each queues queue_member list for member to
- * update state inside queues
-*/
-static void update_status(struct call_queue *q, struct member *m, const int status)
-{
-	m->status = status;
-
-	queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
+	return 0;
 }
 
 /*!
- * \internal
- * \brief Determine if a queue member is available
+ * \internal \brief Determine if a queue member is available
  * \retval 1 if the member is available
  * \retval 0 if the member is not available
  */
@@ -2291,10 +1800,10 @@ static int is_member_available(struct call_queue *q, struct member *mem)
 }
 
 /*! \brief set a member's status based on device state of that member's interface*/
-static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
+static int handle_statechange(void *datap)
 {
+	struct statechange *sc = datap;
 	struct ao2_iterator miter, qiter;
-	struct ast_device_state_message *dev_state;
 	struct member *m;
 	struct call_queue *q;
 	char interface[80], *slash_pos;
@@ -2302,16 +1811,6 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 	int found_member;		/* Found this member in this queue */
 	int avail = 0;			/* Found an available member in this queue */
 
-	if (ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	dev_state = stasis_message_data(msg);
-	if (dev_state->eid) {
-		/* ignore non-aggregate states */
-		return;
-	}
-
 	qiter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
 		ao2_lock(q);
@@ -2329,9 +1828,9 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 					}
 				}
 
-				if (!strcasecmp(interface, dev_state->device)) {
+				if (!strcasecmp(interface, sc->dev)) {
 					found_member = 1;
-					update_status(q, m, dev_state->state);
+					update_status(q, m, sc->state);
 				}
 			}
 
@@ -2363,18 +1862,39 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 	ao2_iterator_destroy(&qiter);
 
 	if (found) {
-		ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
-			dev_state->device,
-			dev_state->state,
-			ast_devstate2str(dev_state->state));
+		ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
 	} else {
-		ast_debug(3, "Device '%s' changed to state '%u' (%s) but we don't care because they're not a member of any queue.\n",
-			dev_state->device,
-			dev_state->state,
-			ast_devstate2str(dev_state->state));
+		ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
 	}
 
-	return;
+	ast_free(sc);
+	return 0;
+}
+
+static void device_state_cb(const struct ast_event *event, void *unused)
+{
+	enum ast_device_state state;
+	const char *device;
+	struct statechange *sc;
+	size_t datapsize;
+
+	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+
+	if (ast_strlen_zero(device)) {
+		ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
+		return;
+	}
+	datapsize = sizeof(*sc) + strlen(device) + 1;
+	if (!(sc = ast_calloc(1, datapsize))) {
+		ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
+		return;
+	}
+	sc->state = state;
+	strcpy(sc->dev, device);
+	if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
+		ast_free(sc);
+	}
 }
 
 /*! \brief Helper function which converts from extension state to device state values */
@@ -2564,6 +2084,8 @@ static void init_queue(struct call_queue *q)
 	q->joinempty = 0;
 	q->leavewhenempty = 0;
 	q->memberdelay = 0;
+	q->maskmemberstatus = 0;
+	q->eventwhencalled = 0;
 	q->weight = 0;
 	q->timeoutrestart = 0;
 	q->periodicannouncefrequency = 0;
@@ -2733,99 +2255,6 @@ static int insert_penaltychange(const char *list_name, const char *content, cons
 	return 0;
 }
 
-/*!
- * \brief Load queue rules from realtime.
- *
- * Check rule for errors with time or fomatting, see if rule is relative to rest
- * of queue, iterate list of rules to find correct insertion point, insert and return.
- * \retval -1 on failure
- * \retval 0 on success
- * \note Call this with the rule_lists locked
-*/
-static int load_realtime_rules(void)
-{
-	struct ast_config *cfg;
-        struct rule_list *rl_iter, *new_rl;
-        struct penalty_rule *pr_iter;
-        char *rulecat = NULL;
-
-	if (!ast_check_realtime("queue_rules")) {
-		ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
-		return 0;
-	}
-	if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
-		ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
-		return 0;
-	}
-	while ((rulecat = ast_category_browse(cfg, rulecat)) && !ast_strlen_zero(rulecat)) {
-		const char *timestr, *maxstr, *minstr;
-		int penaltychangetime, rule_exists = 0, inserted = 0;
-		int max_penalty = 0, min_penalty = 0, min_relative = 0, max_relative = 0;
-		struct penalty_rule *new_penalty_rule = NULL;
-		AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
-			if (!(strcasecmp(rl_iter->name, rulecat))) {
-				rule_exists = 1;
-				new_rl = rl_iter;
-				break;
-			}
-		}
-		if (!rule_exists) {
-			if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
-				ast_config_destroy(cfg);
-				return -1;
-			}
-			ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
-			AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
-		}
-		timestr = ast_variable_retrieve(cfg, rulecat, "time");
-		if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
-			ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules,	skipping it\n",
-				(ast_strlen_zero(timestr) ? "invalid value" : timestr), rulecat);
-			continue;
-		}
-		if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
-			ast_config_destroy(cfg);
-			return -1;
-		}
-		if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
-			ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
-			max_penalty = 0;
-			max_relative = 1;
-		} else {
-			if (*maxstr == '+' || *maxstr == '-') {
-				max_relative = 1;
-			}
-		}
-		if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
-			ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
-			min_penalty = 0;
-			min_relative = 1;
-		} else {
-			if (*minstr == '+' || *minstr == '-') {
-				min_relative = 1;
-			}
-		}
-		new_penalty_rule->time = penaltychangetime;
-		new_penalty_rule->max_relative = max_relative;
-		new_penalty_rule->max_value = max_penalty;
-		new_penalty_rule->min_relative = min_relative;
-		new_penalty_rule->min_value = min_penalty;
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
-			if (new_penalty_rule->time < pr_iter->time) {
-				AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
-				inserted = 1;
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-		if (!inserted) {
-			AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
-		}
-	}
-
-	ast_config_destroy(cfg);
-	return 0;
-}
-
 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
 {
 	char *value_copy = ast_strdupa(value);
@@ -3046,6 +2475,14 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
 		parse_empty_options(val, &q->joinempty, 1);
 	} else if (!strcasecmp(param, "leavewhenempty")) {
 		parse_empty_options(val, &q->leavewhenempty, 0);
+	} else if (!strcasecmp(param, "eventmemberstatus")) {
+		q->maskmemberstatus = !ast_true(val);
+	} else if (!strcasecmp(param, "eventwhencalled")) {
+		if (!strcasecmp(val, "vars")) {
+			q->eventwhencalled = QUEUE_EVENT_VARIABLES;
+		} else {
+			q->eventwhencalled = ast_true(val) ? 1 : 0;
+		}
 	} else if (!strcasecmp(param, "reportholdtime")) {
 		q->reportholdtime = ast_true(val);
 	} else if (!strcasecmp(param, "memberdelay")) {
@@ -3072,11 +2509,6 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
 	}
 }
 
-
-#define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
-#define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
-#define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
-
 /*! \internal
  * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
  *        This adds round robin queue position data for a fresh member as well as links it.
@@ -3088,8 +2520,6 @@ static void member_add_to_queue(struct call_queue *queue, struct member *mem)
 	ao2_lock(queue->members);
 	mem->queuepos = ao2_container_count(queue->members);
 	ao2_link(queue->members, mem);
-	ast_devstate_changed(mem->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
-		AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
 	ao2_unlock(queue->members);
 }
 
@@ -3102,7 +2532,6 @@ static void member_add_to_queue(struct call_queue *queue, struct member *mem)
 static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
 {
 	ao2_lock(queue->members);
-	ast_devstate_changed(QUEUE_UNKNOWN_PAUSED_DEVSTATE, AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
 	queue_member_follower_removal(queue, mem);
 	ao2_unlink(queue->members, mem);
 	ao2_unlock(queue->members);
@@ -3169,8 +2598,6 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc
 			ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
 			if (paused_str) {
 				m->paused = paused;
-				ast_devstate_changed(m->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
-					AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
 			}
 			if (strcasecmp(state_interface, m->state_interface)) {
 				ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
@@ -3559,8 +2986,6 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
 	if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
 		*reason = QUEUE_FULL;
 	} else if (*reason == QUEUE_UNKNOWN) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
 		/* There's space for us, put us at the right position inside
 		 * the queue.
 		 * Take into account the priority of the calling user */
@@ -3603,12 +3028,40 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
 		}
 
 		res = 0;
-
-		blob = ast_json_pack("{s: s, s: i, s: i}",
-				     "Queue", q->name,
-				     "Position", qe->pos,
-				     "Count", q->count);
-		ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel joins a Queue.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<parameter name="Position">
+					<para>This channel's current position in the queue.</para>
+				</parameter>
+				<parameter name="Count">
+					<para>The total number of channels in the queue.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">Leave</ref>
+				<ref type="application">Queue</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
+			"Channel: %s\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n"
+			"Queue: %s\r\n"
+			"Position: %d\r\n"
+			"Count: %d\r\n"
+			"Uniqueid: %s\r\n",
+			ast_channel_name(qe->chan),
+			S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
+			S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
+			S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
+			S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
+			q->name, qe->pos, q->count, ast_channel_uniqueid(qe->chan));
 		ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
 	}
 	ao2_unlock(q);
@@ -3683,7 +3136,8 @@ static int valid_exit(struct queue_ent *qe, char digit)
 
 static int say_position(struct queue_ent *qe, int ringing)
 {
-	int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
+	int res = 0, announceposition = 0;
+	long avgholdmins, avgholdsecs;
 	int say_thanks = 1;
 	time_t now;
 
@@ -3757,23 +3211,23 @@ static int say_position(struct queue_ent *qe, int ringing)
 		}
 	}
 	/* Round hold time to nearest minute */
-	avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
+	avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
 
 	/* If they have specified a rounding then round the seconds as well */
 	if (qe->parent->roundingseconds) {
-		avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
+		avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
 		avgholdsecs *= qe->parent->roundingseconds;
 	} else {
 		avgholdsecs = 0;
 	}
 
-	ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
+	ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
 
 	/* If the hold time is >1 min, if it's enabled, and if it's not
 	   supposed to be only once and we have already said it, say it */
-    if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
-        ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
-        !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
+	if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
+		((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
+		!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
 		res = play_file(qe->chan, qe->parent->sound_holdtime);
 		if (res) {
 			goto playout;
@@ -3876,18 +3330,29 @@ static void leave_queue(struct queue_ent *qe)
 	prev = NULL;
 	for (current = q->head; current; current = current->next) {
 		if (current == qe) {
-			RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 			char posstr[20];
 			q->count--;
 			if (!q->count) {
 				ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
 			}
 
-			blob = ast_json_pack("{s: s, s: i, s: i}",
-					     "Queue", q->name,
-					     "Position", qe->pos,
-					     "Count", q->count);
-			ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
+			/* Take us out of the queue */
+			/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a channel leaves a Queue.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Count'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Position'])" />
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">Join</ref>
+				</see-also>
+			</managerEventInstance>
+			***/
+			ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
+				"Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
+				ast_channel_name(qe->chan), q->name,  q->count, qe->pos, ast_channel_uniqueid(qe->chan));
 			ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
 			/* Take us out of the queue */
 			if (prev) {
@@ -3899,6 +3364,7 @@ static void leave_queue(struct queue_ent *qe)
 			while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
 				ast_free(pr_iter);
 			}
+			qe->pr = NULL;
 			snprintf(posstr, sizeof(posstr), "%d", qe->pos);
 			pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
 		} else {
@@ -3945,19 +3411,8 @@ static void callattempt_free(struct callattempt *doomed)
 	ast_free(doomed);
 }
 
-static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
-{
-	struct callattempt *cur;
-
-	for (cur = outgoing; cur; cur = cur->q_next) {
-		if (cur->chan && cur->chan != exception) {
-			ast_channel_publish_dial(in, cur->chan, NULL, status);
-		}
-	}
-}
-
 /*! \brief Hang up a list of outgoing calls */
-static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
+static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 {
 	struct callattempt *oo;
 
@@ -3968,7 +3423,6 @@ static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, stru
 			if (exception || cancel_answered_elsewhere) {
 				ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
 			}
-			ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
 			ast_hangup(outgoing->chan);
 		}
 		oo = outgoing;
@@ -4061,6 +3515,46 @@ static void do_hang(struct callattempt *o)
 	o->chan = NULL;
 }
 
+/*! \brief convert "\n" to "\nVariable: " ready for manager to use */
+static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
+{
+	struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
+	const char *tmp;
+
+	if (pbx_builtin_serialize_variables(chan, &buf)) {
+		int i, j;
+
+		/* convert "\n" to "\nVariable: " */
+		strcpy(vars, "Variable: ");
+		tmp = ast_str_buffer(buf);
+
+		for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
+			vars[j] = tmp[i];
+
+			if (tmp[i + 1] == '\0') {
+				break;
+			}
+			if (tmp[i] == '\n') {
+				vars[j++] = '\r';
+				vars[j++] = '\n';
+
+				ast_copy_string(&(vars[j]), "Variable: ", len - j);
+				j += 9;
+			}
+		}
+		if (j > len - 3) {
+			j = len - 3;
+		}
+		vars[j++] = '\r';
+		vars[j++] = '\n';
+		vars[j] = '\0';
+	} else {
+		/* there are no channel variables; leave it blank */
+		*vars = '\0';
+	}
+	return vars;
+}
+
 /*!
  * \internal
  * \brief Check if the member status is available.
@@ -4188,10 +3682,12 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 	char tech[256];
 	char *location;
 	const char *macrocontext, *macroexten;
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
 	/* on entry here, we know that tmp->chan == NULL */
 	if (!can_ring_entry(qe, tmp)) {
+		if (ast_channel_cdr(qe->chan)) {
+			ast_cdr_busy(ast_channel_cdr(qe->chan));
+		}
 		tmp->stillgoing = 0;
 		++*busies;
 		return 0;
@@ -4206,7 +3702,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 	}
 
 	/* Request the peer */
-	tmp->chan = ast_request(tech, ast_channel_nativeformats(qe->chan), NULL, qe->chan, location, &status);
+	tmp->chan = ast_request(tech, ast_channel_nativeformats(qe->chan), qe->chan, location, &status);
 	if (!tmp->chan) {			/* If we can't, just go on to the next call */
 		ao2_lock(qe->parent);
 		qe->parent->rrpos++;
@@ -4215,7 +3711,9 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 
 		member_call_pending_clear(tmp->member);
 
-		publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
+		if (ast_channel_cdr(qe->chan)) {
+			ast_cdr_busy(ast_channel_cdr(qe->chan));
+		}
 		tmp->stillgoing = 0;
 		++*busies;
 		return 0;
@@ -4223,8 +3721,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 
 	ast_channel_lock_both(tmp->chan, qe->chan);
 
-	ast_channel_req_accountcodes_precious(tmp->chan, qe->chan,
-		AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
 	if (qe->cancel_answered_elsewhere) {
 		ast_channel_hangupcause_set(tmp->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
 	}
@@ -4271,6 +3767,21 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 	} else {
 		ast_channel_exten_set(tmp->chan, ast_channel_exten(qe->chan));
 	}
+	if (ast_cdr_isset_unanswered()) {
+		/* they want to see the unanswered dial attempts! */
+		/* set up the CDR fields on all the CDRs to give sensical information */
+		ast_cdr_setdestchan(ast_channel_cdr(tmp->chan), ast_channel_name(tmp->chan));
+		strcpy(ast_channel_cdr(tmp->chan)->clid, ast_channel_cdr(qe->chan)->clid);
+		strcpy(ast_channel_cdr(tmp->chan)->channel, ast_channel_cdr(qe->chan)->channel);
+		strcpy(ast_channel_cdr(tmp->chan)->src, ast_channel_cdr(qe->chan)->src);
+		strcpy(ast_channel_cdr(tmp->chan)->dst, ast_channel_exten(qe->chan));
+		strcpy(ast_channel_cdr(tmp->chan)->dcontext, ast_channel_context(qe->chan));
+		strcpy(ast_channel_cdr(tmp->chan)->lastapp, ast_channel_cdr(qe->chan)->lastapp);
+		strcpy(ast_channel_cdr(tmp->chan)->lastdata, ast_channel_cdr(qe->chan)->lastdata);
+		ast_channel_cdr(tmp->chan)->amaflags = ast_channel_cdr(qe->chan)->amaflags;
+		strcpy(ast_channel_cdr(tmp->chan)->accountcode, ast_channel_cdr(qe->chan)->accountcode);
+		strcpy(ast_channel_cdr(tmp->chan)->userfield, ast_channel_cdr(qe->chan)->userfield);
+	}
 
 	ast_channel_unlock(tmp->chan);
 	ast_channel_unlock(qe->chan);
@@ -4285,20 +3796,61 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 		return 0;
 	}
 
-	ast_channel_lock_both(tmp->chan, qe->chan);
-
-	blob = ast_json_pack("{s: s, s: s, s: s}",
-			     "Queue", qe->parent->name,
-			     "Interface", tmp->interface,
-			     "MemberName", tmp->member->membername);
-	queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
+	if (qe->parent->eventwhencalled) {
+		char vars[2048];
 
-	ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
+		ast_channel_lock_both(tmp->chan, qe->chan);
 
-	ast_channel_unlock(tmp->chan);
-	ast_channel_unlock(qe->chan);
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when an Agent is notified of a member in the queue.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<parameter name="AgentCalled">
+					<para>The agent's technology or location.</para>
+				</parameter>
+				<parameter name="AgentName">
+					<para>The name of the agent.</para>
+				</parameter>
+				<parameter name="Variable" required="no" multiple="yes">
+					<para>Optional channel variables from the ChannelCalling channel</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">AgentRingNoAnswer</ref>
+				<ref type="managerEvent">AgentComplete</ref>
+				<ref type="managerEvent">AgentConnect</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_AGENT, "AgentCalled",
+			"Queue: %s\r\n"
+			"AgentCalled: %s\r\n"
+			"AgentName: %s\r\n"
+			"ChannelCalling: %s\r\n"
+			"DestinationChannel: %s\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n"
+			"Context: %s\r\n"
+			"Extension: %s\r\n"
+			"Priority: %d\r\n"
+			"Uniqueid: %s\r\n"
+			"%s",
+			qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan),
+			S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
+			S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
+			S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
+			S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
+			ast_channel_context(qe->chan), ast_channel_exten(qe->chan), ast_channel_priority(qe->chan), ast_channel_uniqueid(qe->chan),
+			qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+
+		ast_channel_unlock(tmp->chan);
+		ast_channel_unlock(qe->chan);
 
-	ast_verb(3, "Called %s\n", tmp->interface);
+		ast_verb(3, "Called %s\n", tmp->interface);
+	}
 
 	member_call_pending_clear(tmp->member);
 	return 1;
@@ -4478,27 +4030,38 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing)
 /*! \brief Record that a caller gave up on waiting in queue */
 static void record_abandoned(struct queue_ent *qe)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
 	set_queue_variables(qe->parent, qe->chan);
 	ao2_lock(qe->parent);
-	blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
-			     "Queue", qe->parent->name,
-			     "Position", qe->pos,
-			     "OriginalPosition", qe->opos,
-			     "HoldTime", (int)(time(NULL) - qe->start));
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>Raised when an caller abandons the queue.</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Position'])" />
+			<parameter name="OriginalPosition">
+				<para>The channel's original position in the queue.</para>
+			</parameter>
+			<parameter name="HoldTime">
+				<para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
+			</parameter>
+		</syntax>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
+		"Queue: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Position: %d\r\n"
+		"OriginalPosition: %d\r\n"
+		"HoldTime: %d\r\n",
+		qe->parent->name, ast_channel_uniqueid(qe->chan), qe->pos, qe->opos, (int)(time(NULL) - qe->start));
 
 	qe->parent->callsabandoned++;
 	ao2_unlock(qe->parent);
-
-	ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
 }
 
 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
-static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
+static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int autopause)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
 	ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
 
 	/* Stop ringing, and resume MOH if specified */
@@ -4507,13 +4070,43 @@ static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, cha
 		ast_moh_start(qe->chan, qe->moh, NULL);
 	}
 
-	blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
-			     "Queue", qe->parent->name,
-			     "Interface", interface,
-			     "MemberName", membername,
-			     "RingTime", rnatime);
-	queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
-
+	if (qe->parent->eventwhencalled) {
+		char vars[2048];
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when an agent is notified of a member in the queue and fails to answer.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
+				<parameter name="Member">
+					<para>The queue member's channel technology or location.</para>
+				</parameter>
+				<parameter name="RingTime">
+					<para>The time the agent was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">AgentCalled</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
+						"Queue: %s\r\n"
+						"Uniqueid: %s\r\n"
+						"Channel: %s\r\n"
+						"Member: %s\r\n"
+						"MemberName: %s\r\n"
+						"RingTime: %d\r\n"
+						"%s",
+						qe->parent->name,
+						ast_channel_uniqueid(qe->chan),
+						ast_channel_name(qe->chan),
+						interface,
+						membername,
+						rnatime,
+						qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+	}
 	ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
 	if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) {
 		if (qe->parent->autopausedelay > 0) {
@@ -4626,8 +4219,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 						}
 						prev = o;
 					}
-				} else if (prev) {
-					prev->call_next = NULL;
 				}
 				numlines++;
 			}
@@ -4732,9 +4323,11 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 						o->block_connected_update = 0;
 					}
 
+					ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(o->chan), NULL);
+
 					ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
 					/* Setup parameters */
-					o->chan = ast_request(tech, ast_channel_nativeformats(in), NULL, in, stuff, &status);
+					o->chan = ast_request(tech, ast_channel_nativeformats(in), in, stuff, &status);
 					if (!o->chan) {
 						ast_log(LOG_NOTICE,
 							"Forwarding failed to create channel to dial '%s/%s'\n",
@@ -4763,7 +4356,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 							ast_party_connected_line_copy(&o->connected, ast_channel_connected(in));
 						}
 
-						ast_channel_req_accountcodes(o->chan, in, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
+						ast_channel_accountcode_set(o->chan, ast_channel_accountcode(in));
 
 						if (!ast_channel_redirecting(o->chan)->from.number.valid
 							|| ast_strlen_zero(ast_channel_redirecting(o->chan)->from.number.str)) {
@@ -4819,11 +4412,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 							numnochan++;
 						}
 					}
-
-					ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
-					ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL,
-						"CANCEL", ast_channel_call_forward(original));
-
 					/* Hangup the original channel now, in case we needed it */
 					ast_hangup(winner);
 					continue;
@@ -4836,8 +4424,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 							/* This is our guy if someone answered. */
 							if (!peer) {
 								ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
-								ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
-								publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
 								if (!o->block_connected_update) {
 									if (o->pending_connected_update) {
 										if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
@@ -4869,11 +4455,13 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 							break;
 						case AST_CONTROL_BUSY:
 							ast_verb(3, "%s is busy\n", ochan_name);
-							ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
+							if (ast_channel_cdr(in)) {
+								ast_cdr_busy(ast_channel_cdr(in));
+							}
+							do_hang(o);
 							endtime = (long) time(NULL);
 							endtime -= starttime;
-							rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
-							do_hang(o);
+							rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 								if (qe->parent->timeoutrestart) {
 									start_time_tv = ast_tvnow();
@@ -4888,10 +4476,12 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 							break;
 						case AST_CONTROL_CONGESTION:
 							ast_verb(3, "%s is circuit-busy\n", ochan_name);
-							ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
+							if (ast_channel_cdr(in)) {
+								ast_cdr_busy(ast_channel_cdr(in));
+							}
 							endtime = (long) time(NULL);
 							endtime -= starttime;
-							rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
+							rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail);
 							do_hang(o);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 								if (qe->parent->timeoutrestart) {
@@ -4986,8 +4576,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 					ast_frfree(f);
 				} else { /* ast_read() returned NULL */
 					endtime = (long) time(NULL) - starttime;
-					ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
-					rna(endtime * 1000, qe, o->chan, on, membername, 1);
+					rna(endtime * 1000, qe, on, membername, 1);
 					do_hang(o);
 					if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 						if (qe->parent->timeoutrestart) {
@@ -5008,7 +4597,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 			if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
 				/* Got hung up */
 				*to = -1;
-				publish_dial_end_event(in, outgoing, NULL, "CANCEL");
 				if (f) {
 					if (f->data.uint32) {
 						ast_channel_hangupcause_set(in, f->data.uint32);
@@ -5021,14 +4609,12 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 			if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
 				ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 				*to = 0;
-				publish_dial_end_event(in, outgoing, NULL, "CANCEL");
 				ast_frfree(f);
 				return NULL;
 			}
 			if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
 				ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
 				*to = 0;
-				publish_dial_end_event(in, outgoing, NULL, "CANCEL");
 				*digit = f->subclass.integer;
 				ast_frfree(f);
 				return NULL;
@@ -5083,12 +4669,8 @@ skip_frame:;
 
 	if (!*to) {
 		for (o = start; o; o = o->call_next) {
-			if (o->chan) {
-				rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
-			}
+			rna(orig, qe, o->interface, o->member->membername, 1);
 		}
-
-		publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
 	}
 
 #ifdef HAVE_EPOLL
@@ -5243,7 +4825,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
 
 			if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) {
 				*reason = QUEUE_LEAVEEMPTY;
-				ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
+				ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
 				leave_queue(qe);
 				break;
 			}
@@ -5410,688 +4992,184 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct
 	case QUEUE_STRATEGY_LEASTRECENT:
 		if (!mem->lastcall) {
 			tmp->metric = 0;
-		} else {
-			tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
-		}
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
-		break;
-	default:
-		ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
-		break;
-	}
-	return 0;
-}
-
-enum agent_complete_reason {
-	CALLER,
-	AGENT,
-	TRANSFER
-};
-
-/*! \brief Send out AMI message with member call completion status information */
-static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller,
-	struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart,
-	time_t callstart, enum agent_complete_reason rsn)
-{
-	const char *reason = NULL;	/* silence dumb compilers */
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	switch (rsn) {
-	case CALLER:
-		reason = "caller";
-		break;
-	case AGENT:
-		reason = "agent";
-		break;
-	case TRANSFER:
-		reason = "transfer";
-		break;
-	}
-
-	blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: s}",
-			     "Queue", queuename,
-			     "Interface", member->interface,
-			     "MemberName", member->membername,
-			     "HoldTime", (long)(callstart - holdstart),
-			     "TalkTime", (long)(time(NULL) - callstart),
-			     "Reason", reason);
-
-	queue_publish_multi_channel_snapshot_blob(ast_queue_topic(queuename), caller, peer,
-			queue_agent_complete_type(), blob);
-}
-
-static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct ast_channel_blob *agent_blob;
-
-	agent_blob = stasis_message_data(msg);
-
-	if (ast_channel_agent_login_type() == stasis_message_type(msg)) {
-		ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
-			ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-			"AGENTLOGIN", "%s", agent_blob->snapshot->name);
-	} else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
-		ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
-			ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-			"AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->name,
-			(long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
-	}
-}
-
-/*!
- * \brief Structure representing relevant data during a local channel optimization
- *
- * The reason we care about local channel optimizations is that we want to be able
- * to accurately report when the caller and queue member have stopped talking to
- * each other. A local channel optimization can cause it to appear that the conversation
- * has stopped immediately after it has begun. By tracking that the relevant channels
- * to monitor have changed due to a local channel optimization, we can give accurate
- * reports.
- *
- * Local channel optimizations for queues are restricted from their normal operation.
- * Bridges created by queues can only be the destination of local channel optimizations,
- * not the source. In addition, move-swap local channel optimizations are the only
- * permitted types of local channel optimization.
- *
- * This data is populated when we are told that a local channel optimization begin
- * is occurring. When we get told the optimization has ended successfully, we then
- * apply the data here into the queue_stasis_data.
- */
-struct local_optimization {
-	/*! The uniqueid of the channel that will be taking the place of the caller or member */
-	const char *source_chan_uniqueid;
-	/*! Indication of whether we think there is a local channel optimization in progress */
-	int in_progress;
-	/*! The identifier for this local channel optimization */
-	unsigned int id;
-};
-
-/*!
- * \brief User data for stasis subscriptions used for queue calls.
- *
- * app_queue subscribes to channel and bridge events for all bridged calls.
- * app_queue cares about the following events:
- *
- * \li bridge enter: To determine the unique ID of the bridge created for the call.
- * \li blind transfer: To send an appropriate agent complete event.
- * \li attended transfer: To send an appropriate agent complete event.
- * \li local optimization: To update caller and member unique IDs for the call.
- * \li hangup: To send an appropriate agent complete event.
- *
- * The stasis subscriptions last until we determine that the caller and the member
- * are no longer bridged with each other.
- */
-struct queue_stasis_data {
-	AST_DECLARE_STRING_FIELDS(
-		/*! The unique ID of the caller's channel. */
-		AST_STRING_FIELD(caller_uniqueid);
-		/*! The unique ID of the queue member's channel */
-		AST_STRING_FIELD(member_uniqueid);
-		/*! The unique ID of the bridge created by the queue */
-		AST_STRING_FIELD(bridge_uniqueid);
-	);
-	/*! The relevant queue */
-	struct call_queue *queue;
-	/*! The queue member that has answered the call */
-	struct member *member;
-	/*! The time at which the caller entered the queue. Start of the caller's hold time */
-	time_t holdstart;
-	/*! The time at which the member answered the call. */
-	time_t starttime;
-	/*! The original position of the caller when he entered the queue */
-	int caller_pos;
-	/*! Indication if the call was answered within the configured service level of the queue */
-	int callcompletedinsl;
-	/*! Indicates if the stasis subscriptions are shutting down */
-	int dying;
-	/*! The stasis message router for bridge events */
-	struct stasis_message_router *bridge_router;
-	/*! The stasis message router for channel events */
-	struct stasis_message_router *channel_router;
-	/*! Local channel optimization details for the caller */
-	struct local_optimization caller_optimize;
-	/*! Local channel optimization details for the member */
-	struct local_optimization member_optimize;
-};
-
-/*!
- * \internal
- * \brief Free memory for a queue_stasis_data
- */
-static void queue_stasis_data_destructor(void *obj)
-{
-	struct queue_stasis_data *queue_data = obj;
-
-	/* This can only happen if refcounts for this object have got severely messed up */
-	ast_assert(queue_data->bridge_router == NULL);
-	ast_assert(queue_data->channel_router == NULL);
-
-	ao2_cleanup(queue_data->member);
-	queue_unref(queue_data->queue);
-	ast_string_field_free_memory(queue_data);
-}
-
-/*!
- * \internal
- * \brief End all stasis subscriptions on a queue_stasis_data
- */
-static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
-{
-	SCOPED_AO2LOCK(lock, queue_data);
-
-	queue_data->dying = 1;
-	stasis_message_router_unsubscribe(queue_data->bridge_router);
-	queue_data->bridge_router = NULL;
-	stasis_message_router_unsubscribe(queue_data->channel_router);
-	queue_data->channel_router = NULL;
-}
-
-/*!
- * \internal
- * \brief Allocate a queue_stasis_data and initialize its data.
- */
-static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
-		struct ast_channel *peer, struct member *mem, time_t holdstart,
-		time_t starttime, int callcompletedinsl)
-{
-	struct queue_stasis_data *queue_data;
-
-	queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
-	if (!queue_data) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(queue_data, 64)) {
-		ao2_cleanup(queue_data);
-		return NULL;
-	}
-
-	ast_string_field_set(queue_data, caller_uniqueid, ast_channel_uniqueid(qe->chan));
-	ast_string_field_set(queue_data, member_uniqueid, ast_channel_uniqueid(peer));
-	queue_data->queue = queue_ref(qe->parent);
-	queue_data->starttime = starttime;
-	queue_data->holdstart = holdstart;
-	queue_data->callcompletedinsl = callcompletedinsl;
-	queue_data->caller_pos = qe->opos;
-	ao2_ref(mem, +1);
-	queue_data->member = mem;
-	return queue_data;
-}
-
-/*!
- * \internal
- * \brief Log an attended transfer in the queue log.
- *
- * Attended transfer queue log messages vary based on the method by which the
- * attended transfer was completed.
- *
- * \param queue_data Data pertaining to the particular call in the queue.
- * \param caller The channel snapshot for the caller channel in the queue.
- * \param atxfer_msg The stasis attended transfer message data.
- */
-static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_channel_snapshot *caller,
-		struct ast_attended_transfer_message *atxfer_msg)
-{
-	RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
-
-	if (!transfer_str) {
-		ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
-		return;
-	}
-
-	switch (atxfer_msg->dest_type) {
-	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
-		ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_APP:
-	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
-		ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_LINK:
-		ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->name,
-				atxfer_msg->dest.links[1]->name);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-	case AST_ATTENDED_TRANSFER_DEST_FAIL:
-		/* Threeways are headed off and should not be logged here */
-		ast_assert(0);
-		return;
-	}
-
-	ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
-			ast_str_buffer(transfer_str),
-			(long) queue_data->starttime - queue_data->holdstart,
-			(long) time(NULL) - queue_data->starttime, queue_data->caller_pos);
-}
-
-/*!
- * \internal
- * \brief Handle a stasis bridge enter event.
- *
- * We track this particular event in order to learn what bridge
- * was created for the queue call.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the bridge enter event
- */
-static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
-
-	if (queue_data->dying) {
-		return;
-	}
-
-	if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
-		return;
-	}
-
-	if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
-		ast_string_field_set(queue_data, bridge_uniqueid,
-				enter_blob->bridge->uniqueid);
-		ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
-				enter_blob->channel->name, queue_data->bridge_uniqueid);
-	}
-}
-
-/*!
- * \brief Handle a blind transfer event
- *
- * This event is important in order to be able to log the end of the
- * call to the queue log and to stasis.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the blind transfer event
- */
-static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
-	const char *exten;
-	const char *context;
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
-
-	if (queue_data->dying) {
-		return;
-	}
-
-	if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
-		return;
-	}
-
-	ao2_lock(queue_data);
-
-	if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
-			strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
-		ao2_unlock(queue_data);
-		return;
+		} else {
+			tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
+		}
+		tmp->metric += mem->penalty * 1000000 * usepenalty;
+		break;
+	default:
+		ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
+		break;
 	}
-
-	caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
-	member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
-
-	ao2_unlock(queue_data);
-
-	exten = transfer_msg->exten;
-	context = transfer_msg->context;
-
-	ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
-	ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
-			"BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
-			exten, context,
-			(long) queue_data->starttime - queue_data->holdstart,
-			(long) time(NULL) - queue_data->starttime, queue_data->caller_pos);
-
-	send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
-			queue_data->holdstart, queue_data->starttime, TRANSFER);
-	update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
-			time(NULL) - queue_data->starttime);
-	remove_stasis_subscriptions(queue_data);
+	return 0;
 }
 
-/*!
- * \brief Handle an attended transfer event
- *
- * This event is important in order to be able to log the end of the
- * call to the queue log and to stasis.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the attended transfer event.
- */
-static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
-
-	if (queue_data->dying) {
-		return;
-	}
-
-	if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
-			atxfer_msg->dest_type == AST_ATTENDED_TRANSFER_DEST_THREEWAY) {
-		return;
-	}
-
-	ao2_lock(queue_data);
-
-	if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
-		ao2_unlock(queue_data);
-		return;
-	}
-
-	if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
-					atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
-			 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
-				 atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
-		ao2_unlock(queue_data);
-		return;
-	}
-
-	caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
-	member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
-
-	ao2_unlock(queue_data);
-
-	ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
-
-	log_attended_transfer(queue_data, caller_snapshot, atxfer_msg);
-
-	send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
-			queue_data->holdstart, queue_data->starttime, TRANSFER);
-	update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
-			time(NULL) - queue_data->starttime);
-	remove_stasis_subscriptions(queue_data);
-}
+enum agent_complete_reason {
+	CALLER,
+	AGENT,
+	TRANSFER
+};
 
-/*!
- * \internal
- * \brief Callback for all stasis bridge events
- *
- * Based on the event and what bridge it is on, the task is farmed out to relevant
- * subroutines for further processing.
- */
-static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
+/*! \brief Send out AMI message with member call completion status information */
+static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
+	const struct ast_channel *peer, const struct member *member, time_t callstart,
+	char *vars, size_t vars_len, enum agent_complete_reason rsn)
 {
-	if (stasis_subscription_final_message(sub, msg)) {
-		ao2_cleanup(userdata);
-	}
-}
+	const char *reason = NULL;	/* silence dumb compilers */
 
-/*!
- * \internal
- * \brief Handler for the beginning of a local channel optimization
- *
- * This method gathers data relevant to the local channel optimization and stores
- * it to be used once the local optimization completes.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the local optimization begin event
- */
-static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
-	struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
-	struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
-	struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
-	struct local_optimization *optimization;
-	unsigned int id;
-	SCOPED_AO2LOCK(lock, queue_data);
-
-	if (queue_data->dying) {
+	if (!qe->parent->eventwhencalled) {
 		return;
 	}
 
-	if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
-		optimization = &queue_data->member_optimize;
-	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
-		optimization = &queue_data->caller_optimize;
-	} else {
-		return;
+	switch (rsn) {
+	case CALLER:
+		reason = "caller";
+		break;
+	case AGENT:
+		reason = "agent";
+		break;
+	case TRANSFER:
+		reason = "transfer";
+		break;
 	}
 
-	/* We only allow move-swap optimizations, so there had BETTER be a source */
-	ast_assert(source != NULL);
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>Raised when an agent has finished servicing a member in the queue.</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
+			<parameter name="TalkTime">
+				<para>The time the agent talked with the member in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
+			</parameter>
+			<parameter name="Reason">
+				<enumlist>
+					<enum name="caller"/>
+					<enum name="agent"/>
+					<enum name="transfer"/>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<see-also>
+			<ref type="managerEvent">AgentCalled</ref>
+			<ref type="managerEvent">AgentConnect</ref>
+		</see-also>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_AGENT, "AgentComplete",
+		"Queue: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Channel: %s\r\n"
+		"Member: %s\r\n"
+		"MemberName: %s\r\n"
+		"HoldTime: %ld\r\n"
+		"TalkTime: %ld\r\n"
+		"Reason: %s\r\n"
+		"%s",
+		queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
+		(long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
+		qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
+}
 
-	optimization->source_chan_uniqueid = ast_strdup(source->uniqueid);
-	if (!optimization->source_chan_uniqueid) {
-		ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->name);
-		return;
-	}
-	id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
+struct queue_transfer_ds {
+	struct queue_ent *qe;
+	struct member *member;
+	time_t starttime;
+	int callcompletedinsl;
+};
 
-	optimization->id = id;
-	optimization->in_progress = 1;
+static void queue_transfer_destroy(void *data)
+{
+	struct queue_transfer_ds *qtds = data;
+	ast_free(qtds);
 }
 
-/*!
- * \internal
- * \brief Handler for the end of a local channel optimization
- *
- * This method takes the data gathered during the local channel optimization begin
- * event and applies it to the queue stasis data appropriately. This generally involves
- * updating the caller or member unique ID with the channel that is taking the place of
- * the previous caller or member.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the local optimization end event
+/*! \brief a datastore used to help correctly log attended transfers of queue callers
  */
-static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
-	struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
-	struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
-	struct local_optimization *optimization;
-	int is_caller;
-	unsigned int id;
-	SCOPED_AO2LOCK(lock, queue_data);
-
-	if (queue_data->dying) {
-		return;
-	}
-
-	if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
-		optimization = &queue_data->member_optimize;
-		is_caller = 0;
-	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
-		optimization = &queue_data->caller_optimize;
-		is_caller = 1;
-	} else {
-		return;
-	}
-
-	id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
-
-	if (!optimization->in_progress) {
-		ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
-		return;
-	}
-
-	if (id != optimization->id) {
-		ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
-				id, optimization->id);
-		return;
-	}
-
-	if (is_caller) {
-		ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
-				queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
-		ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
-	} else {
-		ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
-				queue_data->member_uniqueid, optimization->source_chan_uniqueid);
-		ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
-	}
-
-	optimization->in_progress = 0;
-}
+static const struct ast_datastore_info queue_transfer_info = {
+	.type = "queue_transfer",
+	.chan_fixup = queue_transfer_fixup,
+	.destroy = queue_transfer_destroy,
+};
 
-/*!
- * \internal
- * \brief Handler for hangup stasis event
+/*! \brief Log an attended transfer when a queue caller channel is masqueraded
  *
- * This is how we determine that the caller or member has hung up and the call
- * has ended. An appropriate queue log and stasis message are raised in this
- * callback.
+ * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
+ * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
+ * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
  *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param topic The topic for this event.
- * \param msg The stasis message for the hangup event.
+ * At the end of this, we want to remove the datastore so that this fixup function is not called on any
+ * future masquerades of the caller during the current call.
  */
-static void handle_hangup(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
+static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 {
-	struct queue_stasis_data *queue_data = userdata;
-	struct ast_channel_blob *channel_blob = stasis_message_data(msg);
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
-	enum agent_complete_reason reason;
+	struct queue_transfer_ds *qtds = data;
+	struct queue_ent *qe = qtds->qe;
+	struct member *member = qtds->member;
+	time_t callstart = qtds->starttime;
+	int callcompletedinsl = qtds->callcompletedinsl;
+	struct ast_datastore *datastore;
 
-	if (queue_data->dying) {
-		return;
-	}
+	ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
+				ast_channel_exten(new_chan), ast_channel_context(new_chan), (long) (callstart - qe->start),
+				(long) (time(NULL) - callstart), qe->opos);
 
-	ao2_lock(queue_data);
+	update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
 
-	if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
-		reason = CALLER;
-	} else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
-		reason = AGENT;
+	/* No need to lock the channels because they are already locked in ast_do_masquerade */
+	if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
+		ast_channel_datastore_remove(old_chan, datastore);
+		/* Datastore is freed in try_calling() */
 	} else {
-		ao2_unlock(queue_data);
-		return;
-	}
-
-	chan = ast_channel_get_by_name(channel_blob->snapshot->name);
-	if (chan && ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME)) {
-		/* Channel that is hanging up is doing it as part of a transfer.
-		 * We'll get a transfer event later
-		 */
-		ao2_unlock(queue_data);
-		return;
+		ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
 	}
-
-	caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
-	member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
-
-	ao2_unlock(queue_data);
-
-	ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
-			channel_blob->snapshot->name);
-
-	ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
-			reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
-		(long) (queue_data->starttime - queue_data->holdstart),
-		(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
-
-	send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
-			queue_data->holdstart, queue_data->starttime, reason);
-	update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
-			time(NULL) - queue_data->starttime);
-	remove_stasis_subscriptions(queue_data);
 }
 
-/*!
- * \internal
- * \brief Callback for all stasis channel events
+/*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
+ *
+ * When a caller is atxferred, then the queue_transfer_info datastore
+ * is removed from the channel. If it's still there after the bridge is
+ * broken, then the caller was not atxferred.
  *
- * Based on the event and the channels involved, the work is farmed out into
- * subroutines for further processing.
+ * \note Only call this with chan locked
  */
-static void queue_channel_cb(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
+static int attended_transfer_occurred(struct ast_channel *chan)
 {
-	if (stasis_subscription_final_message(sub, msg)) {
-		ao2_cleanup(userdata);
-	}
+	return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
 }
 
-/*!
- * \internal
- * \brief Create stasis subscriptions for a particular call in the queue.
- *
- * These subscriptions are created once the call has been answered. The subscriptions
- * are put in place so that call progress may be tracked. Once the call can be determined
- * to have ended, then messages are logged to the queue log and stasis events are emitted.
- *
- * \param qe The queue entry representing the caller
- * \param peer The channel that has answered the call
- * \param mem The queue member that answered the call
- * \param holdstart The time at which the caller entered the queue
- * \param starttime The time at which the call was answered
- * \param callcompletedinsl Indicates if the call was answered within the configured service level of the queue.
- * \retval 0 Success
- * \retval non-zero Failure
+/*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
  */
-static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem,
-		time_t holdstart, time_t starttime, int callcompletedinsl)
+static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
 {
-	struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
-
-	if (!queue_data) {
-		return -1;
-	}
+	struct ast_datastore *ds;
+	struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
 
-	queue_data->bridge_router = stasis_message_router_create_pool(ast_bridge_topic_all());
-	if (!queue_data->bridge_router) {
-		ao2_ref(queue_data, -1);
-		return -1;
+	if (!qtds) {
+		ast_log(LOG_WARNING, "Memory allocation error!\n");
+		return NULL;
 	}
 
-	stasis_message_router_add(queue_data->bridge_router, ast_channel_entered_bridge_type(),
-			handle_bridge_enter, queue_data);
-	stasis_message_router_add(queue_data->bridge_router, ast_blind_transfer_type(),
-			handle_blind_transfer, queue_data);
-	stasis_message_router_add(queue_data->bridge_router, ast_attended_transfer_type(),
-			handle_attended_transfer, queue_data);
-	stasis_message_router_set_default(queue_data->bridge_router,
-			queue_bridge_cb, queue_data);
-
-	queue_data->channel_router = stasis_message_router_create_pool(ast_channel_topic_all());
-	if (!queue_data->channel_router) {
-		/* Unsubscribing from the bridge router will remove the only ref of queue_data,
-		 * thus beginning the destruction process
-		 */
-		stasis_message_router_unsubscribe(queue_data->bridge_router);
-		queue_data->bridge_router = NULL;
-		return -1;
+	ast_channel_lock(qe->chan);
+	if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
+		ast_channel_unlock(qe->chan);
+		ast_free(qtds);
+		ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
+		return NULL;
 	}
 
-	ao2_ref(queue_data, +1);
-	stasis_message_router_add(queue_data->channel_router, ast_local_optimization_begin_type(),
-			handle_local_optimization_begin, queue_data);
-	stasis_message_router_add(queue_data->channel_router, ast_local_optimization_end_type(),
-			handle_local_optimization_end, queue_data);
-	stasis_message_router_add(queue_data->channel_router, ast_channel_hangup_request_type(),
-			handle_hangup, queue_data);
-	stasis_message_router_set_default(queue_data->channel_router,
-			queue_channel_cb, queue_data);
-
-	return 0;
+	qtds->qe = qe;
+	/* This member is refcounted in try_calling, so no need to add it here, too */
+	qtds->member = member;
+	qtds->starttime = starttime;
+	qtds->callcompletedinsl = callcompletedinsl;
+	ds->data = qtds;
+	ast_channel_datastore_add(qe->chan, ds);
+	ast_channel_unlock(qe->chan);
+	return ds;
 }
 
 struct queue_end_bridge {
@@ -6121,113 +5199,6 @@ static void end_bridge_callback(void *data)
 
 /*!
  * \internal
- * \brief Setup the after bridge goto location on the peer.
- * \since 12.0.0
- *
- * \param chan Calling channel for bridge.
- * \param peer Peer channel for bridge.
- * \param opts Dialing option flags.
- * \param opt_args Dialing option argument strings.
- *
- * \return Nothing
- */
-static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
-{
-	const char *context;
-	const char *extension;
-	int priority;
-
-	if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
-		ast_channel_lock(chan);
-		context = ast_strdupa(ast_channel_context(chan));
-		extension = ast_strdupa(ast_channel_exten(chan));
-		priority = ast_channel_priority(chan);
-		ast_channel_unlock(chan);
-		ast_bridge_set_after_go_on(peer, context, extension, priority,
-			opt_args[OPT_ARG_CALLEE_GO_ON]);
-	}
-}
-
-static void escape_and_substitute(struct ast_channel *chan, const char *input,
-		char *output, size_t size)
-{
-	const char *m = input;
-	char escaped[size];
-	char *p;
-
-	for (p = escaped; p < escaped + size - 1; p++, m++) {
-		switch (*m) {
-		case '^':
-			if (*(m + 1) == '{') {
-				*p = '$';
-			}
-			break;
-		case ',':
-			*p++ = '\\';
-			/* Fall through */
-		default:
-			*p = *m;
-		}
-		if (*m == '\0')
-			break;
-	}
-
-	if (p == escaped + size) {
-		escaped[size - 1] = '\0';
-	}
-
-	pbx_substitute_variables_helper(chan, escaped, output, size - 1);
-}
-
-static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
-{
-	char escaped_filename[256];
-	char file_with_ext[256];
-	char mixmonargs[1512];
-	char escaped_monitor_exec[1024];
-	const char *monitor_options;
-	const char *monitor_exec;
-
-	escaped_monitor_exec[0] = '\0';
-
-	if (filename) {
-		escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
-	} else {
-		ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
-	}
-
-	ast_channel_lock(qe->chan);
-	if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
-		monitor_exec = ast_strdupa(monitor_exec);
-	}
-	if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
-		monitor_options = ast_strdupa(monitor_options);
-	} else {
-		monitor_options = "";
-	}
-	ast_channel_unlock(qe->chan);
-
-	if (monitor_exec) {
-		escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
-	}
-
-	snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
-
-	if (!ast_strlen_zero(escaped_monitor_exec)) {
-		snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
-	} else {
-		snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
-	}
-
-	ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
-
-	if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
-		ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
-	}
-}
-
-/*!
- * \internal
  * \brief A large function which calls members, updates statistics, and bridges the caller and a member
  *
  * Here is the process of this function
@@ -6256,7 +5227,7 @@ static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
  */
-static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
+static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
 {
 	struct member *cur;
 	struct callattempt *outgoing = NULL; /* the list of calls we are building */
@@ -6283,12 +5254,19 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	char *macroexec = NULL;
 	char *gosubexec = NULL;
 	const char *monitorfilename;
-	char tmpid[256];
+	const char *monitor_exec;
+	const char *monitor_options;
+	char tmpid[256], tmpid2[256];
+	char meid[1024], meid2[1024];
+	char mixmonargs[1512];
+	struct ast_app *mixmonapp = NULL;
+	char *p;
+	char vars[2048];
 	int forwardsallowed = 1;
 	int block_connected_line = 0;
 	int callcompletedinsl;
 	struct ao2_iterator memi;
-	struct ast_datastore *datastore;
+	struct ast_datastore *datastore, *transfer_ds;
 	struct queue_end_bridge *queue_end_bridge = NULL;
 
 	ast_channel_lock(qe->chan);
@@ -6297,6 +5275,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	tmpid[0] = 0;
+	meid[0] = 0;
 	time(&now);
 
 	/* If we've already exceeded our timeout, then just stop
@@ -6320,6 +5299,9 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
 		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
 	}
+	if (ast_test_flag(&opts, OPT_GO_ON)) {
+		ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
+	}
 	if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
 		nondataquality = 0;
 	}
@@ -6361,7 +5343,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	}
 
 	/* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
-		(this is mainly to support unreal/local channels)
+		(this is mainly to support chan_local)
 	*/
 	if (ast_channel_hangupcause(qe->chan) == AST_CAUSE_ANSWERED_ELSEWHERE) {
 		qe->cancel_answered_elsewhere = 1;
@@ -6539,8 +5521,26 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		if (res == -1) {
 			ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
 		}
+		if (ast_cdr_isset_unanswered()) {
+			/* channel contains the name of one of the outgoing channels
+			   in its CDR; zero out this CDR to avoid a dual-posting */
+			struct callattempt *o;
+			for (o = outgoing; o; o = o->q_next) {
+				if (!o->chan) {
+					continue;
+				}
+				if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
+					ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_POST_DISABLED);
+					break;
+				}
+			}
+		}
 	} else { /* peer is valid */
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+		/* These variables are used with the F option without arguments (callee jumps to next priority after queue) */
+		char *caller_context;
+		char *caller_extension;
+		int caller_priority;
+
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
@@ -6559,7 +5559,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		member = lpeer->member;
 		/* Increment the refcount for this member, since we're going to be using it for awhile in here. */
 		ao2_ref(member, 1);
-		hangupcalls(qe, outgoing, peer, qe->cancel_answered_elsewhere);
+		hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
 		outgoing = NULL;
 		if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
 			int res2;
@@ -6577,11 +5577,11 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 				}
 				if (!res2 && qe->parent->reportholdtime) {
 					if (!play_file(peer, qe->parent->sound_reporthold)) {
-						int holdtime, holdtimesecs;
+						long holdtime, holdtimesecs;
 
 						time(&now);
-						holdtime = abs((now - qe->start) / 60);
-						holdtimesecs = abs((now - qe->start) % 60);
+						holdtime = labs((now - qe->start) / 60);
+						holdtimesecs = labs((now - qe->start) % 60);
 						if (holdtime > 0) {
 							ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
 							if (play_file(peer, qe->parent->sound_minutes) < 0) {
@@ -6602,23 +5602,39 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 				/* Agent must have hung up */
 				ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
 				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
-
-				blob = ast_json_pack("{s: s, s: s, s: s}",
-						     "Queue", queuename,
-						     "Interface", member->interface,
-						     "MemberName", member->membername);
-				queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
-
-				ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
+				if (qe->parent->eventwhencalled)
+					/*** DOCUMENTATION
+					<managerEventInstance>
+						<synopsis>Raised when an agent hangs up on a member in the queue.</synopsis>
+						<syntax>
+							<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+							<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
+							<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+							<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
+						</syntax>
+						<see-also>
+							<ref type="managerEvent">AgentCalled</ref>
+							<ref type="managerEvent">AgentConnect</ref>
+						</see-also>
+					</managerEventInstance>
+					***/
+					manager_event(EVENT_FLAG_AGENT, "AgentDump",
+							"Queue: %s\r\n"
+							"Uniqueid: %s\r\n"
+							"Channel: %s\r\n"
+							"Member: %s\r\n"
+							"MemberName: %s\r\n"
+							"%s",
+							queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
+							qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
 				ast_autoservice_chan_hangup_peer(qe->chan, peer);
 				ao2_ref(member, -1);
 				goto out;
 			} else if (ast_check_hangup(qe->chan)) {
 				/* Caller must have hung up just before being connected */
 				ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
-				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
+				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
 				record_abandoned(qe);
-				ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
 				ast_autoservice_chan_hangup_peer(qe->chan, peer);
 				ao2_ref(member, -1);
 				return -1;
@@ -6630,14 +5646,17 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		} else {
 			ast_moh_stop(qe->chan);
 		}
-
+		/* If appropriate, log that we have a destination channel */
+		if (ast_channel_cdr(qe->chan)) {
+			ast_cdr_setdestchan(ast_channel_cdr(qe->chan), ast_channel_name(peer));
+		}
 		/* Make sure channels are compatible */
 		res = ast_channel_make_compatible(qe->chan, peer);
 		if (res < 0) {
 			ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
 			ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
 			record_abandoned(qe);
-			ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
+			ast_cdr_failed(ast_channel_cdr(qe->chan));
 			ast_autoservice_chan_hangup_peer(qe->chan, peer);
 			ao2_ref(member, -1);
 			return -1;
@@ -6664,7 +5683,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		/* use  pbx_builtin_setvar to set a load of variables with one call */
 		if (qe->parent->setqueueentryvar) {
 			snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
-				(long) time(NULL) - qe->start, qe->opos);
+				(long) (time(NULL) - qe->start), qe->opos);
 			pbx_builtin_setvar_multiple(qe->chan, interfacevar);
 			pbx_builtin_setvar_multiple(peer, interfacevar);
 		}
@@ -6675,40 +5694,131 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		set_queue_variables(qe->parent, qe->chan);
 		set_queue_variables(qe->parent, peer);
 
-		setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
 		ast_channel_lock(qe->chan);
+		/* Copy next destination data for 'F' option (no args) */
+		caller_context = ast_strdupa(ast_channel_context(qe->chan));
+		caller_extension = ast_strdupa(ast_channel_exten(qe->chan));
+		caller_priority = ast_channel_priority(qe->chan);
 		if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
 				monitorfilename = ast_strdupa(monitorfilename);
 		}
 		ast_channel_unlock(qe->chan);
 
-		/* Begin Monitoring */
-		if (qe->parent->monfmt && *qe->parent->monfmt) {
-			if (!qe->parent->montype) {
-				const char *monexec;
-				ast_debug(1, "Starting Monitor as requested.\n");
-				ast_channel_lock(qe->chan);
-				if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
-					which = qe->chan;
-					monexec = monexec ? ast_strdupa(monexec) : NULL;
-				} else {
-					which = peer;
-				}
-				ast_channel_unlock(qe->chan);
-				if (monitorfilename) {
-					ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT, NULL);
-				} else if (qe->chan) {
-					ast_monitor_start(which, qe->parent->monfmt, ast_channel_uniqueid(qe->chan), 1, X_REC_IN | X_REC_OUT, NULL);
+		/* Begin Monitoring */
+		if (*qe->parent->monfmt) {
+			if (!qe->parent->montype) {
+				const char *monexec;
+				ast_debug(1, "Starting Monitor as requested.\n");
+				ast_channel_lock(qe->chan);
+				if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
+					which = qe->chan;
+					monexec = monexec ? ast_strdupa(monexec) : NULL;
+				} else {
+					which = peer;
+				}
+				ast_channel_unlock(qe->chan);
+				if (monitorfilename) {
+					ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
+				} else if (ast_channel_cdr(qe->chan)) {
+					ast_monitor_start(which, qe->parent->monfmt, ast_channel_cdr(qe->chan)->uniqueid, 1, X_REC_IN | X_REC_OUT);
+				} else {
+					/* Last ditch effort -- no CDR, make up something */
+					snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
+					ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
+				}
+				if (!ast_strlen_zero(monexec)) {
+					ast_monitor_setjoinfiles(which, 1);
+				}
+			} else {
+				mixmonapp = pbx_findapp("MixMonitor");
+
+				if (mixmonapp) {
+					ast_debug(1, "Starting MixMonitor as requested.\n");
+					if (!monitorfilename) {
+						if (ast_channel_cdr(qe->chan)) {
+							ast_copy_string(tmpid, ast_channel_cdr(qe->chan)->uniqueid, sizeof(tmpid));
+						} else {
+							snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
+						}
+					} else {
+						const char *m = monitorfilename;
+						for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
+							switch (*m) {
+							case '^':
+								if (*(m + 1) == '{')
+									*p = '$';
+								break;
+							case ',':
+								*p++ = '\\';
+								/* Fall through */
+							default:
+								*p = *m;
+							}
+							if (*m == '\0')
+								break;
+						}
+						if (p == tmpid2 + sizeof(tmpid2))
+							tmpid2[sizeof(tmpid2) - 1] = '\0';
+
+						pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
+					}
+
+					ast_channel_lock(qe->chan);
+					if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
+							monitor_exec = ast_strdupa(monitor_exec);
+					}
+					if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
+							monitor_options = ast_strdupa(monitor_options);
+					} else {
+						monitor_options = "";
+					}
+					ast_channel_unlock(qe->chan);
+
+					if (monitor_exec) {
+						const char *m = monitor_exec;
+						for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
+							switch (*m) {
+							case '^':
+								if (*(m + 1) == '{')
+									*p = '$';
+								break;
+							case ',':
+								*p++ = '\\';
+								/* Fall through */
+							default:
+								*p = *m;
+							}
+							if (*m == '\0') {
+								break;
+							}
+						}
+						if (p == meid2 + sizeof(meid2)) {
+							meid2[sizeof(meid2) - 1] = '\0';
+						}
+
+						pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
+					}
+
+					snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
+
+					if (!ast_strlen_zero(monitor_exec)) {
+						snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
+					} else {
+						snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
+					}
+
+					ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
+					/* We purposely lock the CDR so that pbx_exec does not update the application data */
+					if (ast_channel_cdr(qe->chan)) {
+						ast_set_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
+					}
+					pbx_exec(qe->chan, mixmonapp, mixmonargs);
+					if (ast_channel_cdr(qe->chan)) {
+						ast_clear_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
+					}
 				} else {
-					/* Last ditch effort -- no channel, make up something */
-					snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
-					ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT, NULL);
-				}
-				if (!ast_strlen_zero(monexec)) {
-					ast_monitor_setjoinfiles(which, 1);
+					ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
 				}
-			} else {
-				setup_mixmonitor(qe, monitorfilename);
 			}
 		}
 		/* Drop out of the queue at this point, to prepare for next caller */
@@ -6790,17 +5900,68 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 			}
 		}
 		qe->handled++;
-		ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, ast_channel_uniqueid(peer),
+		ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
 													(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
 
-		blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i}",
-				     "Queue", queuename,
-				     "Interface", member->interface,
-				     "MemberName", member->membername,
-				     "HoldTime", (long) time(NULL) - qe->start,
-				     "RingTime", (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
-		queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
+		if (ast_channel_cdr(qe->chan)) {
+			struct ast_cdr *cdr;
+			struct ast_cdr *newcdr;
+
+			/* Only work with the last CDR in the stack*/
+			cdr = ast_channel_cdr(qe->chan);
+			while (cdr->next) {
+				cdr = cdr->next;
+			}
+
+			/* If this CDR is not related to us add new one*/
+			if ((strcasecmp(cdr->uniqueid, ast_channel_uniqueid(qe->chan))) &&
+			    (strcasecmp(cdr->linkedid, ast_channel_uniqueid(qe->chan))) &&
+			    (newcdr = ast_cdr_dup(cdr))) {
+				ast_channel_lock(qe->chan);
+				ast_cdr_init(newcdr, qe->chan);
+				ast_cdr_reset(newcdr, 0);
+				cdr = ast_cdr_append(cdr, newcdr);
+				cdr = cdr->next;
+				ast_channel_unlock(qe->chan);
+			}
 
+			if (update_cdr) {
+				ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
+			}
+		}
+
+		if (qe->parent->eventwhencalled)
+			/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an agent answers and is bridged to a member in the queue.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">AgentCalled</ref>
+					<ref type="managerEvent">AgentComplete</ref>
+					<ref type="managerEvent">AgentDump</ref>
+				</see-also>
+			</managerEventInstance>
+			***/
+			manager_event(EVENT_FLAG_AGENT, "AgentConnect",
+					"Queue: %s\r\n"
+					"Uniqueid: %s\r\n"
+					"Channel: %s\r\n"
+					"Member: %s\r\n"
+					"MemberName: %s\r\n"
+					"HoldTime: %ld\r\n"
+					"BridgedChannel: %s\r\n"
+					"RingTime: %ld\r\n"
+					"%s",
+					queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
+					(long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
+					qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
 		ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
 		ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
 
@@ -6818,15 +5979,71 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 		}
 
 		time(&callstart);
-		setup_stasis_subs(qe, peer, member, qe->start, callstart, callcompletedinsl);
-		bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
-				AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
+		transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
+		bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
+
+		/* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
+		 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
+		 * the AgentComplete manager event
+		 */
+		ast_channel_lock(qe->chan);
+		if (!attended_transfer_occurred(qe->chan)) {
+			struct ast_datastore *tds;
+
+			/* detect a blind transfer */
+			if (!(ast_channel_softhangup_internal_flag(qe->chan) | ast_channel_softhangup_internal_flag(peer)) && (strcasecmp(oldcontext, ast_channel_context(qe->chan)) || strcasecmp(oldexten, ast_channel_exten(qe->chan)))) {
+				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
+					ast_channel_exten(qe->chan), ast_channel_context(qe->chan), (long) (callstart - qe->start),
+					(long) (time(NULL) - callstart), qe->opos);
+				send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
+			} else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) {
+				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETECALLER", "%ld|%ld|%d",
+					(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
+				send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
+			} else {
+				ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
+					(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
+				send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
+			}
+			if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
+				ast_channel_datastore_remove(qe->chan, tds);
+				/* tds was added by setup_transfer_datastore() and is freed below. */
+			}
+			ast_channel_unlock(qe->chan);
+			update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
+		} else {
+			ast_channel_unlock(qe->chan);
+
+			/* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
+			send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
+		}
+
+		if (transfer_ds) {
+			ast_datastore_free(transfer_ds);
+		}
+
+		if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
+			int goto_res;
+
+			if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+				ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+				goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
+			} else { /* F() */
+				goto_res = ast_goto_if_exists(peer, caller_context, caller_extension,
+					caller_priority + 1);
+			}
+			if (goto_res || ast_pbx_start(peer)) {
+				ast_autoservice_chan_hangup_peer(qe->chan, peer);
+			}
+		} else {
+			ast_autoservice_chan_hangup_peer(qe->chan, peer);
+		}
 
 		res = bridge ? bridge : 1;
 		ao2_ref(member, -1);
 	}
 out:
-	hangupcalls(qe, outgoing, NULL, qe->cancel_answered_elsewhere);
+	hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
 
 	return res;
 }
@@ -6867,9 +6084,8 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
 
 
 /*! \brief Dump all members in a specific queue to the database
- * \code
+ *
  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
- * \endcode
  */
 static void dump_queue_members(struct call_queue *pm_queue)
 {
@@ -6946,8 +6162,25 @@ static int remove_from_queue(const char *queuename, const char *interface)
 				queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
 				return RES_NOT_DYNAMIC;
 			}
-			queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
-
+			/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a member is removed from the queue.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">QueueMemberAdded</ref>
+					<ref type="application">RemoveQueueMember</ref>
+				</see-also>
+			</managerEventInstance>
+			***/
+			manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
+				"Queue: %s\r\n"
+				"Location: %s\r\n"
+				"MemberName: %s\r\n",
+				q->name, mem->interface, mem->membername);
 			member_remove_from_queue(q, mem);
 			ao2_ref(mem, -1);
 
@@ -6995,7 +6228,42 @@ static int add_to_queue(const char *queuename, const char *interface, const char
 			new_member->ringinuse = q->ringinuse;
 			new_member->dynamic = 1;
 			member_add_to_queue(q, new_member);
-			queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
+			/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a member is added to the queue.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='StateInterface'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Membership'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Penalty'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='CallsTaken'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='LastCall'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Status'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">QueueMemberRemoved</ref>
+					<ref type="application">AddQueueMember</ref>
+				</see-also>
+			</managerEventInstance>
+			***/
+			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
+				"Queue: %s\r\n"
+				"Location: %s\r\n"
+				"MemberName: %s\r\n"
+				"StateInterface: %s\r\n"
+				"Membership: %s\r\n"
+				"Penalty: %d\r\n"
+				"CallsTaken: %d\r\n"
+				"LastCall: %d\r\n"
+				"Status: %d\r\n"
+				"Paused: %d\r\n",
+				q->name, new_member->interface, new_member->membername, state_interface,
+				"dynamic",
+				new_member->penalty, new_member->calls, (int) new_member->lastcall,
+				new_member->status, new_member->paused);
 
 			if (is_member_available(q, new_member)) {
 				ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
@@ -7022,21 +6290,99 @@ static int add_to_queue(const char *queuename, const char *interface, const char
 	return res;
 }
 
-static int publish_queue_member_pause(struct call_queue *q, struct member *member, const char *reason)
+/*!
+ * \internal
+ * \brief Set the pause status of the specific queue member.
+ *
+ * \param q Which queue the member belongs.
+ * \param mem Queue member being paused/unpaused.
+ * \param reason Why is this happening (Can be NULL/empty for no reason given.)
+ * \param paused Set to 1 if the member is being paused or 0 to unpause.
+ *
+ * \pre The q is locked on entry.
+ *
+ * \return Nothing
+ */
+static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
 {
-	struct ast_json *json_blob = queue_member_blob_create(q, member);
+	if (mem->paused == paused) {
+		ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
+			(paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
+	}
 
-	if (!json_blob) {
-		return -1;
+	if (mem->realtime) {
+		if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
+			ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
+				(paused ? "" : "un"), q->name, mem->interface);
+		}
 	}
 
-	if (!ast_strlen_zero(reason)) {
-		ast_json_object_set(json_blob, "Reason", ast_json_string_create(reason));
+	mem->paused = paused;
+
+	if (queue_persistent_members) {
+		dump_queue_members(q);
+	}
+
+	if (is_member_available(q, mem)) {
+		ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE,
+			"Queue:%s_avail", q->name);
+	} else if (!num_available_members(q)) {
+		ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
+			"Queue:%s_avail", q->name);
 	}
 
-	queue_publish_member_blob(queue_member_pause_type(), json_blob);
+	ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"),
+		"%s", S_OR(reason, ""));
 
-	return 0;
+	if (!ast_strlen_zero(reason)) {
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a member is paused/unpaused in the queue with a reason.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
+				<parameter name="Reason">
+					<para>The reason given for pausing or unpausing a queue member.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="application">PauseQueueMember</ref>
+				<ref type="application">UnPauseQueueMember</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
+			"Queue: %s\r\n"
+			"Location: %s\r\n"
+			"MemberName: %s\r\n"
+			"Paused: %d\r\n"
+			"Reason: %s\r\n",
+			q->name, mem->interface, mem->membername, paused, reason);
+	} else {
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a member is paused/unpaused in the queue without a reason.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
+			</syntax>
+			<see-also>
+				<ref type="application">PauseQueueMember</ref>
+				<ref type="application">UnPauseQueueMember</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
+			"Queue: %s\r\n"
+			"Location: %s\r\n"
+			"MemberName: %s\r\n"
+			"Paused: %d\r\n",
+			q->name, mem->interface, mem->membername, paused);
+	}
 }
 
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
@@ -7045,6 +6391,11 @@ static int set_member_paused(const char *queuename, const char *interface, const
 	struct call_queue *q;
 	struct ao2_iterator queue_iter;
 
+	/* Special event for when all queues are paused - individual events still generated */
+	/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
+	if (ast_strlen_zero(queuename))
+		ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
+
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
 		ao2_lock(q);
@@ -7052,55 +6403,17 @@ static int set_member_paused(const char *queuename, const char *interface, const
 			struct member *mem;
 
 			if ((mem = interface_exists(q, interface))) {
-				if (mem->paused == paused) {
-					ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
-				}
-
-				if (mem->realtime) {
-					if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
-						ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
-						ao2_ref(mem, -1);
-						ao2_unlock(q);
-						queue_t_unref(q, "Done with iterator");
-						continue;
-					}
-				}
-
-				mem->paused = paused;
-				ast_devstate_changed(mem->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
-					AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
-				found++;
-
-				/* Before we do the PAUSE/UNPAUSE log, if this was a PAUSEALL/UNPAUSEALL, log that here, but only on the first found entry. */
-				if (found == 1) {
-
-					/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
-					if (ast_strlen_zero(queuename)) {
-						ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
-					}
-				}
-
-				if (queue_persistent_members) {
-					dump_queue_members(q);
-				}
-
-				if (is_member_available(q, mem)) {
-					ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
-				} else if (!num_available_members(q)) {
-					ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
-				}
-
-				ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
+				++found;
 
-				publish_queue_member_pause(q, mem, reason);
+				set_queue_member_pause(q, mem, reason, paused);
 				ao2_ref(mem, -1);
 			}
-		}
 
-		if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
-			ao2_unlock(q);
-			queue_t_unref(q, "Done with iterator");
-			break;
+			if (!ast_strlen_zero(queuename)) {
+				ao2_unlock(q);
+				queue_t_unref(q, "Done with iterator");
+				break;
+			}
 		}
 
 		ao2_unlock(q);
@@ -7124,21 +6437,36 @@ static int set_member_penalty_help_members(struct call_queue *q, const char *int
 {
 	struct member *mem;
 	int foundinterface = 0;
+	char rtpenalty[80];
 
 	ao2_lock(q);
 	if ((mem = interface_exists(q, interface))) {
 		foundinterface++;
-		if (mem->realtime) {
-			char rtpenalty[80];
-
+		if (!mem->realtime) {
+			mem->penalty = penalty;
+		} else {
 			sprintf(rtpenalty, "%i", penalty);
 			update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
 		}
-
-		mem->penalty = penalty;
-
 		ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
-		queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
+		/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a member's penalty is changed.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Penalty'])" />
+			</syntax>
+			<see-also>
+				<ref type="function">QUEUE_MEMBER</ref>
+			</see-also>
+		</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
+			"Queue: %s\r\n"
+			"Location: %s\r\n"
+			"Penalty: %d\r\n",
+			q->name, mem->interface, penalty);
 		ao2_ref(mem, -1);
 	}
 	ao2_unlock(q);
@@ -7146,6 +6474,54 @@ static int set_member_penalty_help_members(struct call_queue *q, const char *int
 	return foundinterface;
 }
 
+/*!
+ * \internal
+ * \brief Set the ringinuse value of the specific queue member.
+ *
+ * \param q Which queue the member belongs.
+ * \param mem Queue member being set.
+ * \param ringinuse Set to 1 if the member is called when inuse.
+ *
+ * \pre The q is locked on entry.
+ *
+ * \return Nothing
+ */
+static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
+{
+	if (mem->realtime) {
+		update_realtime_member_field(mem, q->name, realtime_ringinuse_field,
+			ringinuse ? "1" : "0");
+	}
+
+	mem->ringinuse = ringinuse;
+
+	ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
+
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
+			<xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
+			<parameter name="Ringinuse">
+				<enumlist>
+					<enum name="0"/>
+					<enum name="1"/>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<see-also>
+			<ref type="function">QUEUE_MEMBER</ref>
+		</see-also>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_AGENT, "QueueMemberRinginuse",
+		"Queue: %s\r\n"
+		"Location: %s\r\n"
+		"Ringinuse: %d\r\n",
+		q->name, mem->interface, ringinuse);
+}
+
 static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
 {
 	struct member *mem;
@@ -7154,17 +6530,7 @@ static int set_member_ringinuse_help_members(struct call_queue *q, const char *i
 	ao2_lock(q);
 	if ((mem = interface_exists(q, interface))) {
 		foundinterface++;
-		if (mem->realtime) {
-			char rtringinuse[80];
-
-			sprintf(rtringinuse, "%i", ringinuse);
-			update_realtime_member_field(mem, q->name, realtime_ringinuse_field, rtringinuse);
-		}
-
-		mem->ringinuse = ringinuse;
-
-		ast_queue_log(q->name, "NONE", interface, "RINGINUSE", "%d", ringinuse);
-		queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
+		set_queue_member_ringinuse(q, mem, ringinuse);
 		ao2_ref(mem, -1);
 	}
 	ao2_unlock(q);
@@ -7857,7 +7223,7 @@ check_turns:
 			reason = QUEUE_TIMEOUT;
 			res = 0;
 			ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
-				qe.pos, qe.opos, (long) time(NULL) - qe.start);
+				qe.pos, qe.opos, (long) (time(NULL) - qe.start));
 			break;
 		}
 
@@ -7881,7 +7247,8 @@ check_turns:
 			record_abandoned(&qe);
 			reason = QUEUE_TIMEOUT;
 			res = 0;
-			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+				"%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
 			break;
 		}
 
@@ -7910,7 +7277,8 @@ check_turns:
 		/* exit after 'timeout' cycle if 'n' option enabled */
 		if (noption && tries >= ao2_container_count(qe.parent->members)) {
 			ast_verb(3, "Exiting on time-out cycle\n");
-			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+				"%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
 			record_abandoned(&qe);
 			reason = QUEUE_TIMEOUT;
 			res = 0;
@@ -7923,7 +7291,7 @@ check_turns:
 			record_abandoned(&qe);
 			reason = QUEUE_TIMEOUT;
 			res = 0;
-			ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
+			ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
 			break;
 		}
 
@@ -7952,7 +7320,7 @@ stop:
 				record_abandoned(&qe);
 				ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
 					"%d|%d|%ld", qe.pos, qe.opos,
-					(long) time(NULL) - qe.start);
+					(long) (time(NULL) - qe.start));
 				res = -1;
 			} else if (qcontinue) {
 				reason = QUEUE_CONTINUE;
@@ -7960,7 +7328,7 @@ stop:
 			}
 		} else if (qe.valid_digits) {
 			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
-				"%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) time(NULL) - qe.start);
+				"%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
 		}
 	}
 
@@ -8063,12 +7431,29 @@ static int queue_function_exists(struct ast_channel *chan, const char *cmd, char
 	return 0;
 }
 
+static struct member *get_interface_helper(struct call_queue *q, const char *interface)
+{
+	struct member *m;
+
+	if (ast_strlen_zero(interface)) {
+		ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
+		return NULL;
+	}
+
+	m = interface_exists(q, interface);
+	if (!m) {
+		ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
+			interface, q->name);
+	}
+	return m;
+}
+
 /*!
  * \brief Get number either busy / free / ready or total members of a specific queue
  * \brief Get or set member properties penalty / paused / ringinuse
  * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
  * \retval -1 on error
-*/
+ */
 static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
 	int count = 0;
@@ -8085,14 +7470,18 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch
 	buf[0] = '\0';
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
+		ast_log(LOG_ERROR,
+			"Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
+			cmd);
 		return -1;
 	}
 
 	AST_STANDARD_APP_ARGS(args, data);
 
-	if (args.argc < 2) {
-		ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
+	if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
+		ast_log(LOG_ERROR,
+			"Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
+			cmd);
 		return -1;
 	}
 
@@ -8131,27 +7520,29 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch
 				ao2_ref(m, -1);
 			}
 			ao2_iterator_destroy(&mem_iter);
-		} else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
+		} else if (!strcasecmp(args.option, "count")) {
 			count = ao2_container_count(q->members);
-		} else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) &&
-			   ((m = interface_exists(q, args.interface)))) {
-			count = m->penalty;
-			ao2_ref(m, -1);
-		} else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) &&
-			   ((m = interface_exists(q, args.interface)))) {
-			count = m->paused;
-			ao2_ref(m, -1);
-		} else if ( (!strcasecmp(args.option, "ignorebusy") || !strcasecmp(args.option, "ringinuse")) &&
-			   !ast_strlen_zero(args.interface) &&
-			   ((m = interface_exists(q, args.interface)))) {
-			count = m->ringinuse;
-			ao2_ref(m, -1);
-		} else if (!ast_strlen_zero(args.interface)) {
-			ast_log(LOG_ERROR, "Queue member interface %s not in queue %s\n",
-				args.interface, args.queuename);
+		} else if (!strcasecmp(args.option, "penalty")) {
+			m = get_interface_helper(q, args.interface);
+			if (m) {
+				count = m->penalty;
+				ao2_ref(m, -1);
+			}
+		} else if (!strcasecmp(args.option, "paused")) {
+			m = get_interface_helper(q, args.interface);
+			if (m) {
+				count = m->paused;
+				ao2_ref(m, -1);
+			}
+		} else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
+			|| !strcasecmp(args.option, "ringinuse"))) {
+			m = get_interface_helper(q, args.interface);
+			if (m) {
+				count = m->ringinuse;
+				ao2_ref(m, -1);
+			}
 		} else {
-			ast_log(LOG_ERROR, "Unknown option %s provided to %s, valid values are: "
-				"logged, free, ready, count, penalty, paused, ringinuse\n", args.option, cmd);
+			ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
 		}
 		ao2_unlock(q);
 		queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
@@ -8168,9 +7559,6 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch
 static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
 	int memvalue;
-	struct call_queue *q;
-	struct member *m;
-	char rtvalue[80];
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(queuename);
@@ -8179,65 +7567,48 @@ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, c
 	);
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n");
+		ast_log(LOG_ERROR,
+			"Missing required argument. %s([<queuename>],<option>,<interface>)\n",
+			cmd);
 		return -1;
 	}
 
 	AST_STANDARD_APP_ARGS(args, data);
 
-	if (args.argc < 3) {
-		ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
+	if (ast_strlen_zero(args.option)
+		|| ast_strlen_zero(args.interface)) {
+		ast_log(LOG_ERROR,
+			"Missing required argument. %s([<queuename>],<option>,<interface>)\n",
+			cmd);
 		return -1;
 	}
 
-	if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) {
-		ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n");
-		return -1;
-	}
+	/*
+	 * If queuename is empty then the option will be
+	 * set for the interface in all queues.
+	 */
 
 	memvalue = atoi(value);
 	if (!strcasecmp(args.option, "penalty")) {
-		/* if queuename = NULL then penalty will be set for interface in all the queues.*/
 		if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
-			ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
+			ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
 			return -1;
 		}
-	} else if ((q = find_load_queue_rt_friendly(args.queuename))) {
-		ao2_lock(q);
-		if ((m = interface_exists(q, args.interface))) {
-			sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1");
-			if (!strcasecmp(args.option, "paused")) {
-				if (m->realtime) {
-					update_realtime_member_field(m, q->name, args.option, rtvalue);
-				}
-				m->paused = (memvalue <= 0) ? 0 : 1;
-				ast_devstate_changed(m->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
-					AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, args.interface);
-
-			} else if ((!strcasecmp(args.option, "ignorebusy")) || (!strcasecmp(args.option, "ringinuse"))) {
-				if (m->realtime) {
-					update_realtime_member_field(m, q->name, args.option, rtvalue);
-				}
-
-				m->ringinuse = (memvalue <= 0) ? 0 : 1;
-			} else {
-				ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ringinuse/ignorebusy are valid\n");
-				ao2_ref(m, -1);
-				ao2_unlock(q);
-				ao2_ref(q, -1);
-				return -1;
-			}
-			ao2_ref(m, -1);
-		} else {
-			ao2_unlock(q);
-			ao2_ref(q, -1);
-			ast_log(LOG_ERROR, "Invalid interface for queue\n");
+	} else if (!strcasecmp(args.option, "paused")) {
+		memvalue = (memvalue <= 0) ? 0 : 1;
+		if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
+			ast_log(LOG_ERROR, "Invalid interface or queue\n");
 			return -1;
 		}
-		ao2_unlock(q);
-		ao2_ref(q, -1);
-        } else {
-		ast_log(LOG_ERROR, "Invalid queue\n");
+	} else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
+		|| !strcasecmp(args.option, "ringinuse")) {
+		memvalue = (memvalue <= 0) ? 0 : 1;
+		if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
+			ast_log(LOG_ERROR, "Invalid interface or queue\n");
+			return -1;
+		}
+	} else {
+		ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
 		return -1;
 	}
 	return 0;
@@ -8481,16 +7852,6 @@ static struct ast_custom_function queuememberpenalty_function = {
 	.write = queue_function_memberpenalty_write,
 };
 
-/*! Set the global queue rules parameters as defined in the "general" section of queuerules.conf */
-static void queue_rules_set_global_params(struct ast_config *cfg)
-{
-        const char *general_val = NULL;
-        realtime_rules = 0;
-        if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
-                realtime_rules = ast_true(general_val);
-        }
-}
-
 /*! \brief Reload the rules defined in queuerules.conf
  *
  * \param reload If 1, then only process queuerules.conf if the file
@@ -8504,7 +7865,7 @@ static int reload_queue_rules(int reload)
 	struct penalty_rule *pr_iter;
 	char *rulecat = NULL;
 	struct ast_variable *rulevar = NULL;
-	struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
 	if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
 		ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
@@ -8524,10 +7885,6 @@ static int reload_queue_rules(int reload)
 		ast_free(rl_iter);
 	}
 	while ((rulecat = ast_category_browse(cfg, rulecat))) {
-		if (!strcasecmp(rulecat, "general")) {
-			queue_rules_set_global_params(cfg);
-			continue;
-		}
 		if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
 			AST_LIST_UNLOCK(&rule_lists);
 			ast_config_destroy(cfg);
@@ -8542,15 +7899,10 @@ static int reload_queue_rules(int reload)
 					ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
 		}
 	}
+	AST_LIST_UNLOCK(&rule_lists);
 
 	ast_config_destroy(cfg);
 
-	if (realtime_rules && load_realtime_rules()) {
-		AST_LIST_UNLOCK(&rule_lists);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	AST_LIST_UNLOCK(&rule_lists);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -9087,7 +8439,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
 				ast_str_set(&out, 0, "      %s", mem->membername);
 				if (strcasecmp(mem->membername, mem->interface)) {
 					ast_str_append(&out, 0, " (%s", mem->interface);
-					if (mem->state_interface) {
+					if (!ast_strlen_zero(mem->state_interface)) {
 						ast_str_append(&out, 0, " from %s", mem->state_interface);
 					}
 					ast_str_append(&out, 0, ")");
@@ -9098,14 +8450,11 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
 
 				ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
 
-				ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s (%s%s%s)",
-					mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
-					mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
-					mem->paused ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->paused ? " (paused)" : "", ast_term_reset(),
-					ast_term_color(
-						mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ?
-							COLOR_RED : COLOR_GREEN, COLOR_BLACK),
-						ast_devstate2str(mem->status), ast_term_reset());
+				ast_str_append(&out, 0, "%s%s%s (%s)",
+					mem->dynamic ? " (dynamic)" : "",
+					mem->realtime ? " (realtime)" : "",
+					mem->paused ? " (paused)" : "",
+					ast_devstate2str(mem->status));
 				if (mem->calls) {
 					ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
 						mem->calls, (long) (time(NULL) - mem->lastcall));
@@ -10339,15 +9688,6 @@ static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cl
 	return CLI_SUCCESS;
 }
 
-static const char qpm_cmd_usage[] =
-"Usage: queue pause member <channel> in <queue> reason <reason>\n";
-
-static const char qum_cmd_usage[] =
-"Usage: queue unpause member <channel> in <queue> reason <reason>\n";
-
-static const char qsmp_cmd_usage[] =
-"Usage: queue set member penalty <channel> from <queue> <penalty>\n";
-
 static struct ast_cli_entry cli_queue[] = {
 	AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
 	AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
@@ -10382,6 +9722,7 @@ static struct ast_cli_entry cli_queue[] = {
 	MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING)	\
 	MEMBER(call_queue, sound_reporthold, AST_DATA_STRING)		\
 	MEMBER(call_queue, dead, AST_DATA_BOOLEAN)			\
+	MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN)		\
 	MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN)			\
 	MEMBER(call_queue, announce_to_first_user, AST_DATA_BOOLEAN)	\
 	MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN)		\
@@ -10391,6 +9732,7 @@ static struct ast_cli_entry cli_queue[] = {
 	MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN)			\
 	MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN)		\
 	MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER)		\
+	MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN)		\
 	MEMBER(call_queue, realtime, AST_DATA_BOOLEAN)			\
 	MEMBER(call_queue, found, AST_DATA_BOOLEAN)			\
 	MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER)	\
@@ -10629,101 +9971,70 @@ static const struct ast_data_entry queue_data_providers[] = {
 	AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
 };
 
-static struct stasis_message_router *agent_router;
-static struct stasis_forward *topic_forwarder;
-
 static int unload_module(void)
 {
-	stasis_message_router_unsubscribe_and_join(agent_router);
-	agent_router = NULL;
-
-	topic_forwarder = stasis_forward_cancel(topic_forwarder);
-
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
-
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
-
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
+	int res;
+	struct ao2_iterator q_iter;
+	struct call_queue *q = NULL;
 
 	ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
-	ast_manager_unregister("QueueStatus");
-	ast_manager_unregister("Queues");
-	ast_manager_unregister("QueueRule");
-	ast_manager_unregister("QueueSummary");
-	ast_manager_unregister("QueueAdd");
-	ast_manager_unregister("QueueRemove");
-	ast_manager_unregister("QueuePause");
-	ast_manager_unregister("QueueLog");
-	ast_manager_unregister("QueuePenalty");
-	ast_manager_unregister("QueueReload");
-	ast_manager_unregister("QueueReset");
-	ast_manager_unregister("QueueMemberRingInUse");
-	ast_unregister_application(app_aqm);
-	ast_unregister_application(app_rqm);
-	ast_unregister_application(app_pqm);
-	ast_unregister_application(app_upqm);
-	ast_unregister_application(app_ql);
-	ast_unregister_application(app);
-	ast_custom_function_unregister(&queueexists_function);
-	ast_custom_function_unregister(&queuevar_function);
-	ast_custom_function_unregister(&queuemembercount_function);
-	ast_custom_function_unregister(&queuemembercount_dep);
-	ast_custom_function_unregister(&queuememberlist_function);
-	ast_custom_function_unregister(&queuewaitingcount_function);
-	ast_custom_function_unregister(&queuememberpenalty_function);
-
-	ast_data_unregister(NULL);
-
-	device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
+	res = ast_manager_unregister("QueueStatus");
+	res |= ast_manager_unregister("Queues");
+	res |= ast_manager_unregister("QueueRule");
+	res |= ast_manager_unregister("QueueSummary");
+	res |= ast_manager_unregister("QueueAdd");
+	res |= ast_manager_unregister("QueueRemove");
+	res |= ast_manager_unregister("QueuePause");
+	res |= ast_manager_unregister("QueueLog");
+	res |= ast_manager_unregister("QueuePenalty");
+	res |= ast_manager_unregister("QueueReload");
+	res |= ast_manager_unregister("QueueReset");
+	res |= ast_manager_unregister("QueueMemberRingInUse");
+	res |= ast_unregister_application(app_aqm);
+	res |= ast_unregister_application(app_rqm);
+	res |= ast_unregister_application(app_pqm);
+	res |= ast_unregister_application(app_upqm);
+	res |= ast_unregister_application(app_ql);
+	res |= ast_unregister_application(app);
+	res |= ast_custom_function_unregister(&queueexists_function);
+	res |= ast_custom_function_unregister(&queuevar_function);
+	res |= ast_custom_function_unregister(&queuemembercount_function);
+	res |= ast_custom_function_unregister(&queuemembercount_dep);
+	res |= ast_custom_function_unregister(&queuememberlist_function);
+	res |= ast_custom_function_unregister(&queuewaitingcount_function);
+	res |= ast_custom_function_unregister(&queuememberpenalty_function);
+
+	res |= ast_data_unregister(NULL);
+
+	if (device_state_sub)
+		ast_event_unsubscribe(device_state_sub);
 
 	ast_extension_state_del(0, extension_state_cb);
 
+	q_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
+		queues_t_unlink(queues, q, "Remove queue from container due to unload");
+		queue_t_unref(q, "Done with iterator");
+	}
+	ao2_iterator_destroy(&q_iter);
+	devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
+	ao2_ref(queues, -1);
 	ast_unload_realtime("queue_members");
-	ao2_cleanup(queues);
-	queues = NULL;
-	return 0;
+	return res;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
-	int err = 0;
+	int res;
 	struct ast_flags mask = {AST_FLAGS_ALL, };
 	struct ast_config *member_config;
-	struct stasis_topic *queue_topic;
-	struct stasis_topic *manager_topic;
 
 	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
-	if (!queues) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
 
 	use_weight = 0;
 
-	if (reload_handler(0, &mask, NULL)) {
-		unload_module();
+	if (reload_handler(0, &mask, NULL))
 		return AST_MODULE_LOAD_DECLINE;
-	}
 
 	ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
 
@@ -10736,7 +10047,6 @@ static int load_module(void)
 		realtime_ringinuse_field = "ringinuse";
 	} else {
 		const char *config_val;
-
 		if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
 			ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
 			realtime_ringinuse_field = "ringinuse";
@@ -10748,102 +10058,53 @@ static int load_module(void)
 			realtime_ringinuse_field = "ringinuse";
 		}
 	}
+
 	ast_config_destroy(member_config);
 
-	if (queue_persistent_members) {
+	if (queue_persistent_members)
 		reload_queue_members();
-	}
 
 	ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
 
-	err |= ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
-	err |= ast_register_application_xml(app, queue_exec);
-	err |= ast_register_application_xml(app_aqm, aqm_exec);
-	err |= ast_register_application_xml(app_rqm, rqm_exec);
-	err |= ast_register_application_xml(app_pqm, pqm_exec);
-	err |= ast_register_application_xml(app_upqm, upqm_exec);
-	err |= ast_register_application_xml(app_ql, ql_exec);
-	err |= ast_manager_register_xml("Queues", 0, manager_queues_show);
-	err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
-	err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
-	err |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
-	err |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
-	err |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
-	err |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
-	err |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
-	err |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse);
-	err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
-	err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
-	err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
-	err |= ast_custom_function_register(&queuevar_function);
-	err |= ast_custom_function_register(&queueexists_function);
-	err |= ast_custom_function_register(&queuemembercount_function);
-	err |= ast_custom_function_register(&queuemembercount_dep);
-	err |= ast_custom_function_register(&queuememberlist_function);
-	err |= ast_custom_function_register(&queuewaitingcount_function);
-	err |= ast_custom_function_register(&queuememberpenalty_function);
-
-	/* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
-	device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL);
-	if (!device_state_sub) {
-		err = -1;
-	}
-
-	manager_topic = ast_manager_get_topic();
-	queue_topic = ast_queue_topic_all();
-	if (!manager_topic || !queue_topic) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	topic_forwarder = stasis_forward_all(queue_topic, manager_topic);
-	if (!topic_forwarder) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
+	ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
+	res = ast_register_application_xml(app, queue_exec);
+	res |= ast_register_application_xml(app_aqm, aqm_exec);
+	res |= ast_register_application_xml(app_rqm, rqm_exec);
+	res |= ast_register_application_xml(app_pqm, pqm_exec);
+	res |= ast_register_application_xml(app_upqm, upqm_exec);
+	res |= ast_register_application_xml(app_ql, ql_exec);
+	res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
+	res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
+	res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
+	res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
+	res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
+	res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
+	res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
+	res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
+	res |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse);
+	res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
+	res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
+	res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
+	res |= ast_custom_function_register(&queuevar_function);
+	res |= ast_custom_function_register(&queueexists_function);
+	res |= ast_custom_function_register(&queuemembercount_function);
+	res |= ast_custom_function_register(&queuemembercount_dep);
+	res |= ast_custom_function_register(&queuememberlist_function);
+	res |= ast_custom_function_register(&queuewaitingcount_function);
+	res |= ast_custom_function_register(&queuememberpenalty_function);
+
+	if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
+		ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
 	}
 
-	if (!ast_channel_agent_login_type()
-		|| !ast_channel_agent_logoff_type()) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	agent_router = stasis_message_router_create(ast_channel_topic_all());
-	if (!agent_router) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
+	/* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
+	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
+		res = -1;
 	}
-	err |= stasis_message_router_add(agent_router,
-		ast_channel_agent_login_type(),
-		queue_agent_cb,
-		NULL);
-	err |= stasis_message_router_add(agent_router,
-		ast_channel_agent_logoff_type(),
-		queue_agent_cb,
-		NULL);
-
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
-
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
-
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
 
 	ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
 
-	if (err) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
+	return res ? AST_MODULE_LOAD_DECLINE : 0;
 }
 
 static int reload(void)
@@ -10872,7 +10133,6 @@ static struct member *find_member_by_queuename_and_interface(const char *queuena
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_read.c b/apps/app_read.c
index 3dd6cb5..d2a1de7 100644
--- a/apps/app_read.c
+++ b/apps/app_read.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356042 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
diff --git a/apps/app_readexten.c b/apps/app_readexten.c
index 2ca9a21..deaf83f 100644
--- a/apps/app_readexten.c
+++ b/apps/app_readexten.c
@@ -30,7 +30,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 357542 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
diff --git a/apps/app_readfile.c b/apps/app_readfile.c
new file mode 100644
index 0000000..d031406
--- /dev/null
+++ b/apps/app_readfile.c
@@ -0,0 +1,134 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ReadFile application -- Reads in a File for you.
+ *
+ * \author Matt O'Gorman <mogorman at digium.com>
+ *
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+	<defaultenabled>no</defaultenabled>
+	<support_level>deprecated</support_level>
+	<replacement>func_env (FILE())</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/module.h"
+
+/*** DOCUMENTATION
+	<application name="ReadFile" language="en_US">
+		<synopsis>
+			Read the contents of a text file into a channel variable.
+		</synopsis>
+		<syntax argsep="=">
+			<parameter name="varname" required="true">
+				<para>Result stored here.</para>
+			</parameter>
+			<parameter name="fileparams" required="true">
+				<argument name="file" required="true">
+					<para>The name of the file to read.</para>
+				</argument>
+				<argument name="length" required="false">
+					<para>Maximum number of characters to capture.</para>
+					<para>If not specified defaults to max.</para>
+				</argument>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Read the contents of a text file into channel variable <replaceable>varname</replaceable></para>
+			<warning><para>ReadFile has been deprecated in favor of Set(varname=${FILE(file,0,length)})</para></warning>
+		</description>
+		<see-also>
+			<ref type="application">System</ref>
+			<ref type="application">Read</ref>
+		</see-also>
+	</application>
+ ***/
+
+static char *app_readfile = "ReadFile";
+
+static int readfile_exec(struct ast_channel *chan, const char *data)
+{
+	int res=0;
+	char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
+	int len=0;
+	static int deprecation_warning = 0;
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "ReadFile require an argument!\n");
+		return -1;
+	}
+
+	s = ast_strdupa(data);
+
+	varname = strsep(&s, "=");
+	file = strsep(&s, ",");
+	length = s;
+
+	if (deprecation_warning++ % 10 == 0)
+		ast_log(LOG_WARNING, "ReadFile has been deprecated in favor of Set(%s=${FILE(%s,0,%s)})\n", varname, file, length);
+
+	if (!varname || !file) {
+		ast_log(LOG_ERROR, "No file or variable specified!\n");
+		return -1;
+	}
+
+	if (length) {
+		if ((sscanf(length, "%30d", &len) != 1) || (len < 0)) {
+			ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length);
+			len = 0;
+		}
+	}
+
+	if ((returnvar = ast_read_textfile(file))) {
+		if (len > 0) {
+			if (len < strlen(returnvar))
+				returnvar[len]='\0';
+			else
+				ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar));
+		}
+		pbx_builtin_setvar_helper(chan, varname, returnvar);
+		ast_free(returnvar);
+	}
+
+	return res;
+}
+
+
+static int unload_module(void)
+{
+	return ast_unregister_application(app_readfile);
+}
+
+static int load_module(void)
+{
+	return ast_register_application_xml(app_readfile, readfile_exec);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable");
diff --git a/apps/app_record.c b/apps/app_record.c
index e79c607..28316f9 100644
--- a/apps/app_record.c
+++ b/apps/app_record.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428655 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
@@ -39,7 +39,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428655 $")
 #include "asterisk/app.h"
 #include "asterisk/channel.h"
 #include "asterisk/dsp.h"	/* use dsp routines for silence detection */
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="Record" language="en_US">
@@ -68,10 +67,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428655 $")
 					<option name="n">
 						<para>Do not answer, but record anyway if line not yet answered.</para>
 					</option>
-					<option name="o">
-						<para>Exit when 0 is pressed, setting the variable <variable>RECORD_STATUS</variable>
-						to <literal>OPERATOR</literal> instead of <literal>DTMF</literal></para>
-					</option>
 					<option name="q">
 						<para>quiet (do not play a beep tone).</para>
 					</option>
@@ -118,8 +113,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428655 $")
 
  ***/
 
-#define OPERATOR_KEY '0'
-
 static char *app = "Record";
 
 enum {
@@ -132,14 +125,12 @@ enum {
 	OPTION_KEEP = (1 << 6),
 	FLAG_HAS_PERCENT = (1 << 7),
 	OPTION_ANY_TERMINATE = (1 << 8),
-	OPTION_OPERATOR_EXIT = (1 << 9),
 };
 
 AST_APP_OPTIONS(app_opts,{
 	AST_APP_OPTION('a', OPTION_APPEND),
-	AST_APP_OPTION('k', OPTION_KEEP),
+	AST_APP_OPTION('k', OPTION_KEEP),	
 	AST_APP_OPTION('n', OPTION_NOANSWER),
-	AST_APP_OPTION('o', OPTION_OPERATOR_EXIT),
 	AST_APP_OPTION('q', OPTION_QUIET),
 	AST_APP_OPTION('s', OPTION_SKIP),
 	AST_APP_OPTION('t', OPTION_STAR_TERMINATE),
@@ -147,36 +138,6 @@ AST_APP_OPTIONS(app_opts,{
 	AST_APP_OPTION('x', OPTION_IGNORE_TERMINATE),
 });
 
-/*!
- * \internal
- * \brief Used to determine what action to take when DTMF is received while recording
- * \since 13.0.0
- *
- * \param chan channel being recorded
- * \param flags option flags in use by the record application
- * \param dtmf_integer the integer value of the DTMF key received
- * \param terminator key currently set to be pressed for normal termination
- *
- * \retval 0 do not exit
- * \retval -1 do exit
- */
-static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator)
-{
-	if ((dtmf_integer == OPERATOR_KEY) &&
-		(ast_test_flag(flags, OPTION_OPERATOR_EXIT))) {
-		pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "OPERATOR");
-		return -1;
-	}
-
-	if ((dtmf_integer == terminator) ||
-		(ast_test_flag(flags, OPTION_ANY_TERMINATE))) {
-		pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF");
-		return -1;
-	}
-
-	return 0;
-}
-
 static int record_exec(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
@@ -197,7 +158,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
 	int maxduration = 0;		/* max duration of recording in milliseconds */
 	int gottimeout = 0;		/* did we timeout for maxduration exceeded? */
 	int terminator = '#';
-	RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
+	struct ast_format rfmt;
 	int ioflags;
 	struct ast_silence_generator *silgen = NULL;
 	struct ast_flags flags = { 0, };
@@ -210,6 +171,8 @@ static int record_exec(struct ast_channel *chan, const char *data)
 	int ms;
 	struct timeval start;
 
+	ast_format_clear(&rfmt);
+
 	/* The next few lines of code parse out the filename and header from the input string */
 	if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
 		ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
@@ -294,9 +257,10 @@ static int record_exec(struct ast_channel *chan, const char *data)
 			}
 			count++;
 		} while (ast_fileexists(tmp, ext, ast_channel_language(chan)) > 0);
-		pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
 	} else
 		ast_copy_string(tmp, args.filename, sizeof(tmp));
+
+	pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
 	/* end of routine mentioned */
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
@@ -330,8 +294,8 @@ static int record_exec(struct ast_channel *chan, const char *data)
 	/* The end of beep code.  Now the recording starts */
 
 	if (silence > 0) {
-		rfmt = ao2_bump(ast_channel_readformat(chan));
-		res = ast_set_read_format(chan, ast_format_slin);
+		ast_format_copy(&rfmt, ast_channel_readformat(chan));
+		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
 			pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
@@ -421,11 +385,12 @@ static int record_exec(struct ast_channel *chan, const char *data)
 				ast_frfree(f);
 				break;
 			}
-		} else if (f->frametype == AST_FRAME_DTMF) {
-			if (record_dtmf_response(chan, &flags, f->subclass.integer, terminator)) {
-				ast_frfree(f);
-				break;
-			}
+		} else if ((f->frametype == AST_FRAME_DTMF) &&
+			   ((f->subclass.integer == terminator) ||
+			    (ast_test_flag(&flags, OPTION_ANY_TERMINATE)))) {
+			ast_frfree(f);
+			pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF");
+			break;
 		}
 		ast_frfree(f);
 	}
@@ -463,8 +428,8 @@ static int record_exec(struct ast_channel *chan, const char *data)
 		ast_channel_stop_silence_generator(chan, silgen);
 
 out:
-	if ((silence > 0) && rfmt) {
-		res = ast_set_read_format(chan, rfmt);
+	if ((silence > 0) && rfmt.id) {
+		res = ast_set_read_format(chan, &rfmt);
 		if (res) {
 			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
 		}
diff --git a/apps/app_saycounted.c b/apps/app_saycounted.c
index 2035e8c..377a7c4 100644
--- a/apps/app_saycounted.c
+++ b/apps/app_saycounted.c
@@ -114,7 +114,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/logger.h"
 #include "asterisk/module.h"
@@ -205,5 +205,4 @@ static int unload_module(void)
 	return res;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Decline words according to channel language");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Decline words according to channel language");
diff --git a/apps/app_sayunixtime.c b/apps/app_sayunixtime.c
index 0453d3b..7d34ed9 100644
--- a/apps/app_sayunixtime.c
+++ b/apps/app_sayunixtime.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 402819 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -59,10 +59,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 402819 $")
 			<parameter name="options" required="false">
 				 <optionlist>
 					<option name="j">
-						<para>Allow the calling user to dial digits to jump to that extension.
-						This option is automatically enabled if
-						<variable>SAY_DTMF_INTERRUPT</variable> is present on the channel and
-						set to 'true' (case insensitive)</para>
+						<para>Allow the calling user to dial digits to jump to that extension.</para>
 					</option>
 				</optionlist>
 			</parameter>
@@ -132,7 +129,6 @@ static int sayunixtime_exec(struct ast_channel *chan, const char *data)
 	const char * haltondigits = AST_DIGIT_NONE;
 	struct ast_flags64 opts = { 0, };
 	char *opt_args[OPT_ARG_ARRAY_SIZE];
-	const char *interrupt_string;
 
 	if (!data) {
 		return 0;
@@ -150,14 +146,6 @@ static int sayunixtime_exec(struct ast_channel *chan, const char *data)
 		}
 	}
 
-	/* Check if 'SAY_DTMF_INTERRUPT' is true and apply the same behavior as the j flag. */
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		haltondigits = AST_DIGIT_ANY;
-	}
-	ast_channel_unlock(chan);
-
 	ast_get_time_t(ast_strlen_zero(args.timeval) ? NULL : args.timeval, &unixtime, time(NULL), NULL);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
diff --git a/apps/app_senddtmf.c b/apps/app_senddtmf.c
index 942d61f..e1e8ee9 100644
--- a/apps/app_senddtmf.c
+++ b/apps/app_senddtmf.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374030 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
@@ -47,7 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374030 $")
 		<syntax>
 			<parameter name="digits" required="true">
 				<para>List of digits 0-9,*#,a-d,A-D to send also w for a half second pause,
-				W for a one second pause, and f or F for a flash-hook if the channel supports
+				and f or F for a flash-hook if the channel supports
 				flash-hook.</para>
 			</parameter>
 			<parameter name="timeout_ms" required="false">
@@ -79,9 +79,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374030 $")
 			<parameter name="Digit" required="true">
 				<para>The DTMF digit to play.</para>
 			</parameter>
-			<parameter name="Duration" required="false">
-				<para>The duration, in milliseconds, of the digit to be played.</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>Plays a dtmf digit on the specified channel.</para>
@@ -148,9 +145,7 @@ static int manager_play_dtmf(struct mansession *s, const struct message *m)
 {
 	const char *channel = astman_get_header(m, "Channel");
 	const char *digit = astman_get_header(m, "Digit");
-	const char *duration = astman_get_header(m, "Duration");
 	struct ast_channel *chan;
-	unsigned int duration_ms = 0;
 
 	if (!(chan = ast_channel_get_by_name(channel))) {
 		astman_send_error(s, m, "Channel not found");
@@ -162,14 +157,8 @@ static int manager_play_dtmf(struct mansession *s, const struct message *m)
 		chan = ast_channel_unref(chan);
 		return 0;
 	}
-	
-	if (!ast_strlen_zero(duration) && (sscanf(duration, "%30u", &duration_ms) != 1)) {
-		astman_send_error(s, m, "Could not convert Duration parameter");
-		chan = ast_channel_unref(chan);
-		return 0;
-	}
 
-	ast_senddigit(chan, *digit, duration_ms);
+	ast_senddigit(chan, *digit, 0);
 
 	chan = ast_channel_unref(chan);
 
diff --git a/apps/app_sendtext.c b/apps/app_sendtext.c
index 807aa33..98b7b2f 100644
--- a/apps/app_sendtext.c
+++ b/apps/app_sendtext.c
@@ -33,7 +33,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356042 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/apps/app_setcallerid.c b/apps/app_setcallerid.c
index 761f8ca..6fa3170 100644
--- a/apps/app_setcallerid.c
+++ b/apps/app_setcallerid.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -127,5 +127,4 @@ static int load_module(void)
 	return ast_register_application_xml(app2, setcallerid_pres_exec);
 }
 
-AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Set CallerID Presentation Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Presentation Application");
diff --git a/apps/app_skel.c b/apps/app_skel.c
index cfc5505..a184ea0 100644
--- a/apps/app_skel.c
+++ b/apps/app_skel.c
@@ -29,15 +29,6 @@
  * \ingroup applications
  */
 
-/*! \li \ref app_skel.c uses configuration file \ref app_skel.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page app_skel.conf app_skel.conf
- * \verbinclude app_skel.conf.sample
- */
-
 /*** MODULEINFO
 	<defaultenabled>no</defaultenabled>
 	<support_level>core</support_level>
@@ -45,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h> /* log10 */
 #include "asterisk/file.h"
@@ -86,51 +77,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 		from. It shows you the basic structure to create your own Asterisk applications.</para>
 		</description>
 	</application>
-
-	<configInfo name="app_skel" language="en_US">
-		<configFile name="app_skel.conf">
-			<configObject name="globals">
-				<synopsis>Options that apply globally to app_skel</synopsis>
-				<configOption name="games">
-					<synopsis>The number of games a single execution of SkelGuessNumber will play</synopsis>
-				</configOption>
-				<configOption name="cheat">
-					<synopsis>Should the computer cheat?</synopsis>
-					<description><para>If enabled, the computer will ignore winning guesses.</para></description>
-				</configOption>
-			</configObject>
-			<configObject name="sounds">
-				<synopsis>Prompts for SkelGuessNumber to play</synopsis>
-				<configOption name="prompt" default="please-enter-your&number&queue-less-than">
-					<synopsis>A prompt directing the user to enter a number less than the max number</synopsis>
-				</configOption>
-				<configOption name="wrong_guess" default="vm-pls-try-again">
-					<synopsis>The sound file to play when a wrong guess is made</synopsis>
-				</configOption>
-				<configOption name="right_guess" default="auth-thankyou">
-					<synopsis>The sound file to play when a correct guess is made</synopsis>
-				</configOption>
-				<configOption name="too_low">
-					<synopsis>The sound file to play when a guess is too low</synopsis>
-				</configOption>
-				<configOption name="too_high">
-					<synopsis>The sound file to play when a guess is too high</synopsis>
-				</configOption>
-				<configOption name="lose" default="vm-goodbye">
-					<synopsis>The sound file to play when a player loses</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="level">
-				<synopsis>Defined levels for the SkelGuessNumber game</synopsis>
-				<configOption name="max_number">
-					<synopsis>The maximum in the range of numbers to guess (1 is the implied minimum)</synopsis>
-				</configOption>
-				<configOption name="max_guesses">
-					<synopsis>The maximum number of guesses before a game is considered lost</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
  ***/
 
 static char *app = "SkelGuessNumber";
@@ -232,7 +178,7 @@ static void *skel_level_alloc(const char *cat);
  * internally by the Config Options code to check if an level has already been added to the
  * container that will be swapped for the live container on a successul reload.
  *
- * \param tmp_container A non-active container to search for a level
+ * \param container A non-active container to search for a level
  * \param category The category associated with the level to check for
  * \retval non-NULL The level from the container
  * \retval NULL The level does not exist in the container
@@ -242,7 +188,6 @@ static void *skel_level_find(struct ao2_container *tmp_container, const char *ca
 /*! \brief An aco_type structure to link the "general" category to the skel_global_config type */
 static struct aco_type global_option = {
 	.type = ACO_GLOBAL,
-	.name = "globals",
 	.item_offset = offsetof(struct skel_config, global),
 	.category_match = ACO_WHITELIST,
 	.category = "^general$",
@@ -253,7 +198,6 @@ struct aco_type *global_options[] = ACO_TYPES(&global_option);
 /*! \brief An aco_type structure to link the "sounds" category to the skel_global_config type */
 static struct aco_type sound_option = {
 	.type = ACO_GLOBAL,
-	.name = "sounds",
 	.item_offset = offsetof(struct skel_config, global),
 	.category_match = ACO_WHITELIST,
 	.category = "^sounds$",
@@ -264,7 +208,6 @@ struct aco_type *sound_options[] = ACO_TYPES(&sound_option);
 /*! \brief An aco_type structure to link the everything but the "general" and "sounds" categories to the skel_level type */
 static struct aco_type level_option = {
 	.type = ACO_ITEM,
-	.name = "level",
 	.category_match = ACO_BLACKLIST,
 	.category = "^(general|sounds)$",
 	.item_alloc = skel_level_alloc,
@@ -706,16 +649,6 @@ static int unload_module(void)
 	return ast_unregister_application(app);
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (aco_info_init(&cfg_info)) {
@@ -758,7 +691,6 @@ error:
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skeleton (sample) Application",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload_module,
diff --git a/apps/app_sms.c b/apps/app_sms.c
index 4c3d50a..af4c5d2 100644
--- a/apps/app_sms.c
+++ b/apps/app_sms.c
@@ -40,7 +40,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <dirent.h>
 #include <ctype.h>
@@ -56,7 +56,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/callerid.h"
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="SMS" language="en_US">
@@ -141,11 +140,11 @@ static const signed short wave[] = {
 static unsigned char wavea[80];
 typedef unsigned char output_t;
 static const output_t *wave_out = wavea;    /* outgoing samples */
-#define __OUT_FMT ast_format_alaw
+#define __OUT_FMT AST_FORMAT_ALAW;
 #else
 typedef signed short output_t;
 static const output_t *wave_out = wave;     /* outgoing samples */
-#define __OUT_FMT ast_format_slin
+#define __OUT_FMT AST_FORMAT_SLINEAR
 #endif
 
 #define OSYNC_BITS	80                      /* initial sync bits */
@@ -783,7 +782,7 @@ static void sms_log(sms_t * h, char status)
 		unsigned char n;
 
 		if (h->mr >= 0) {
-			snprintf(mrs, sizeof(mrs), "%02X", (unsigned)h->mr);
+			snprintf(mrs, sizeof(mrs), "%02hhX", (unsigned char)h->mr);
 		}
 		snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
 			isodate(time(NULL), buf, sizeof(buf)),
@@ -1016,7 +1015,7 @@ static void sms_writefile(sms_t * h)
 		unsigned int p;
 		fprintf(o, "udh#");
 		for (p = 0; p < h->udhl; p++) {
-			fprintf(o, "%02X", (unsigned)h->udh[p]);
+			fprintf(o, "%02hhX", (unsigned char)h->udh[p]);
 		}
 		fprintf(o, "\n");
 	}
@@ -1049,7 +1048,7 @@ static void sms_writefile(sms_t * h)
 			if (p == h->udl) {              /* can write in ucs-1 hex */
 				fprintf(o, "ud#");
 				for (p = 0; p < h->udl; p++) {
-					fprintf(o, "%02X", (unsigned)h->ud[p]);
+					fprintf(o, "%02hhX", (unsigned char)h->ud[p]);
 				}
 				fprintf(o, "\n");
 			} else {                        /* write in UCS-2 */
@@ -1140,7 +1139,7 @@ static unsigned char sms_handleincoming (sms_t * h)
 				return 0xFF;		  /* duh! */
 			}
 		} else {
-			ast_log(LOG_WARNING, "Unknown message type %02X\n", (unsigned)h->imsg[2]);
+			ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
 			return 0xFF;
 		}
 	} else {                                /* client */
@@ -1163,7 +1162,7 @@ static unsigned char sms_handleincoming (sms_t * h)
 				return 0xFF;                /* duh! */
 			}
 		} else {
-			ast_log(LOG_WARNING, "Unknown message type %02X\n", (unsigned)h->imsg[2]);
+			ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
 			return 0xFF;
 		}
 	}
@@ -1245,7 +1244,7 @@ static char *sms_hexdump(unsigned char buf[], int size, char *s /* destination *
 	int f;
 
 	for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
-		sprintf(p, "%02X ", (unsigned)buf[f]);
+		sprintf(p, "%02hhX ", (unsigned char)buf[f]);
 	}
 	return(s);
 }
@@ -1483,7 +1482,7 @@ static void sms_debug (int dir, sms_t *h)
 	int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
 	int q = 0;
 	while (q < n && q < 30) {
-		sprintf(p, " %02X", (unsigned)msg[q++]);
+		sprintf(p, " %02hhX", msg[q++]);
 		p += 3;
 	}
 	if (q < n) {
@@ -1600,7 +1599,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
 #define MAXSAMPLES (800)
 	output_t *buf;
 	sms_t *h = data;
-	int i, res;
+	int i;
 
 	if (samples > MAXSAMPLES) {
 		ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
@@ -1611,7 +1610,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
 	buf = ast_alloca(len);
 
 	f.frametype = AST_FRAME_VOICE;
-	f.subclass.format = __OUT_FMT;
+	ast_format_set(&f.subclass.format, __OUT_FMT, 0);
 	f.datalen = samples * sizeof(*buf);
 	f.offset = AST_FRIENDLY_OFFSET;
 	f.mallocd = 0;
@@ -1661,9 +1660,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
 			}
 		}
 	}
-	res = ast_write(chan, &f);
-	ast_frfree(&f);
-	if (res < 0) {
+	if (ast_write(chan, &f) < 0) {
 		ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
 		return -1;
 	}
@@ -2015,9 +2012,9 @@ static int sms_exec(struct ast_channel *chan, const char *data)
 		sms_messagetx(&h);
 	}
 
-	res = ast_set_write_format(chan, __OUT_FMT);
+	res = ast_set_write_format_by_id(chan, __OUT_FMT);
 	if (res >= 0) {
-		res = ast_set_read_format(chan, ast_format_slin);
+		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
 	}
 	if (res < 0) {
 		ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
@@ -2082,5 +2079,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, sms_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "SMS/PSTN handler");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");
diff --git a/apps/app_softhangup.c b/apps/app_softhangup.c
index 861ab8e..f3fc4c1 100644
--- a/apps/app_softhangup.c
+++ b/apps/app_softhangup.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356042 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/apps/app_speech_utils.c b/apps/app_speech_utils.c
index 0b412dc..4acade2 100644
--- a/apps/app_speech_utils.c
+++ b/apps/app_speech_utils.c
@@ -27,12 +27,11 @@
 
 /*** MODULEINFO
 	<support_level>core</support_level>
-	<depend>res_speech</depend>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419688 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -214,7 +213,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419688 $");
 	</function>
 	<function name="SPEECH_ENGINE" language="en_US">
 		<synopsis>
-			Get or change a speech engine specific attribute.
+			Change a speech engine specific attribute.
 		</synopsis>
 		<syntax>
 			<parameter name="name" required="true" />
@@ -437,7 +436,7 @@ static struct ast_custom_function speech_grammar_function = {
 	.write = NULL,
 };
 
-/*! \brief SPEECH_ENGINE() Dialplan Set Function */
+/*! \brief SPEECH_ENGINE() Dialplan Function */
 static int speech_engine_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
 	struct ast_speech *speech = find_speech(chan);
@@ -451,21 +450,9 @@ static int speech_engine_write(struct ast_channel *chan, const char *cmd, char *
 	return 0;
 }
 
-/*! \brief SPEECH_ENGINE() Dialplan Get Function */
-static int speech_engine_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	struct ast_speech *speech = find_speech(chan);
-
-	if (!data || !speech) {
-		return -1;
-	}
-
-	return ast_speech_get_setting(speech, data, buf, len);
-}
-
 static struct ast_custom_function speech_engine_function = {
 	.name = "SPEECH_ENGINE",
-	.read = speech_engine_read,
+	.read = NULL,
 	.write = speech_engine_write,
 };
 
@@ -705,7 +692,7 @@ static int speech_background(struct ast_channel *chan, const char *data)
 	int res = 0, done = 0, started = 0, quieted = 0, max_dtmf_len = 0;
 	struct ast_speech *speech = find_speech(chan);
 	struct ast_frame *f = NULL;
-	RAII_VAR(struct ast_format *, oldreadformat, NULL, ao2_cleanup);
+	struct ast_format oldreadformat;
 	char dtmf[AST_MAX_EXTENSION] = "";
 	struct timeval start = { 0, 0 }, current;
 	char *parse, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
@@ -720,6 +707,7 @@ static int speech_background(struct ast_channel *chan, const char *data)
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
+	ast_format_clear(&oldreadformat);
 	if (speech == NULL)
 		return -1;
 
@@ -735,10 +723,10 @@ static int speech_background(struct ast_channel *chan, const char *data)
 	}
 
 	/* Record old read format */
-	oldreadformat = ao2_bump(ast_channel_readformat(chan));
+	ast_format_copy(&oldreadformat, ast_channel_readformat(chan));
 
 	/* Change read format to be signed linear */
-	if (ast_set_read_format(chan, speech->format))
+	if (ast_set_read_format(chan, &speech->format))
 		return -1;
 
 	if (!ast_strlen_zero(args.soundfile)) {
@@ -939,7 +927,7 @@ static int speech_background(struct ast_channel *chan, const char *data)
 		speech_datastore_destroy(chan);
 	} else {
 		/* Channel is okay so restore read format */
-		ast_set_read_format(chan, oldreadformat);
+		ast_set_read_format(chan, &oldreadformat);
 	}
 
 	return 0;
@@ -1002,7 +990,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan Speech Applications",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.nonoptreq = "res_speech",
diff --git a/apps/app_stack.c b/apps/app_stack.c
index 7396d03..dd19555 100644
--- a/apps/app_stack.c
+++ b/apps/app_stack.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
  
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422719 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
@@ -40,7 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422719 $")
 #include "asterisk/manager.h"
 #include "asterisk/channel.h"
 #include "asterisk/agi.h"
-#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
 	<application name="Gosub" language="en_US">
@@ -203,32 +202,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422719 $")
 			<para>Cause the channel to execute the specified dialplan subroutine,
 			returning to the dialplan with execution of a Return().</para>
 		</description>
-		<see-also>
-			<ref type="application">GoSub</ref>
-		</see-also>
 	</agi>
-	<managerEvent language="en_US" name="VarSet">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>Raised when a variable local to the gosub stack frame is set due to a subroutine call.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Variable">
-					<para>The LOCAL variable being set.</para>
-					<note><para>The variable name will always be enclosed with
-					<literal>LOCAL()</literal></para></note>
-				</parameter>
-				<parameter name="Value">
-					<para>The new value of the variable.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">GoSub</ref>
-				<ref type="agi">gosub</ref>
-				<ref type="function">LOCAL</ref>
-				<ref type="function">LOCAL_PEEK</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 static const char app_gosub[] = "Gosub";
@@ -251,8 +225,6 @@ struct gosub_stack_frame {
 	int priority;
 	/*! TRUE if the return location marks the end of a special routine. */
 	unsigned int is_special:1;
-	/*! Whether or not we were in a subroutine when this one was created */
-	unsigned int in_subroutine:1;
 	char *context;
 	char extension[0];
 };
@@ -263,8 +235,6 @@ static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *fra
 {
 	struct ast_var_t *variables;
 	int found = 0;
-	int len;
-	RAII_VAR(char *, local_buffer, NULL, ast_free);
 
 	/* Does this variable already exist? */
 	AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
@@ -283,13 +253,20 @@ static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *fra
 		pbx_builtin_setvar_helper(chan, var, value);
 	}
 
-	len = 8 + strlen(var); /* LOCAL() + var */
-	local_buffer = ast_malloc(len);
-	if (!local_buffer) {
-		return 0;
-	}
-	sprintf(local_buffer, "LOCAL(%s)", var);
-	ast_channel_publish_varset(chan, local_buffer, value);
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>Raised when a LOCAL channel variable is set due to a subroutine call.</synopsis>
+		<see-also>
+			<ref type="application">GoSub</ref>
+		</see-also>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
+		"Channel: %s\r\n"
+		"Variable: LOCAL(%s)\r\n"
+		"Value: %s\r\n"
+		"Uniqueid: %s\r\n",
+		ast_channel_name(chan), var, value, ast_channel_uniqueid(chan));
 	return 0;
 }
 
@@ -312,7 +289,7 @@ static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_fra
 	ast_free(frame);
 }
 
-static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
+static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const char *extension, int priority, unsigned char arguments)
 {
 	struct gosub_stack_frame *new = NULL;
 	int len_extension = strlen(extension), len_context = strlen(context);
@@ -323,7 +300,6 @@ static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const
 		new->context = new->extension + len_extension + 1;
 		strcpy(new->context, context);
 		new->priority = priority;
-		new->in_subroutine = in_subroutine ? 1 : 0;
 		new->arguments = arguments;
 	}
 	return new;
@@ -419,7 +395,6 @@ static int return_exec(struct ast_channel *chan, const char *data)
 		--oldframe->priority;
 	}
 	ast_channel_priority_set(chan, oldframe->priority);
-	ast_set2_flag(ast_channel_flags(chan), oldframe->in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
 
 	gosub_release_frame(chan, oldframe);
 
@@ -528,7 +503,6 @@ static int gosub_exec(struct ast_channel *chan, const char *data)
 	char *orig_exten;
 	char *dest_context;
 	char *dest_exten;
-	int orig_in_subroutine;
 	int orig_priority;
 	int dest_priority;
 	int i;
@@ -568,7 +542,6 @@ static int gosub_exec(struct ast_channel *chan, const char *data)
 	orig_context = ast_strdupa(ast_channel_context(chan));
 	orig_exten = ast_strdupa(ast_channel_exten(chan));
 	orig_priority = ast_channel_priority(chan);
-	orig_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
 	ast_channel_unlock(chan);
 
 	if (ast_parseable_goto(chan, label)) {
@@ -636,7 +609,7 @@ static int gosub_exec(struct ast_channel *chan, const char *data)
 	}
 
 	/* Create the return address */
-	newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
+	newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc);
 	if (!newframe) {
 		goto error_exit_locked;
 	}
@@ -650,8 +623,6 @@ static int gosub_exec(struct ast_channel *chan, const char *data)
 	snprintf(argname, sizeof(argname), "%u", args2.argc);
 	frame_set_var(chan, newframe, "ARGC", argname);
 
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
-
 	/* And finally, save our return address */
 	AST_LIST_LOCK(oldlist);
 	AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
@@ -975,7 +946,6 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
 	int saved_priority;
 	int saved_hangup_flags;
 	int saved_autoloopflag;
-	int saved_in_subroutine;
 	int res;
 
 	ast_channel_lock(chan);
@@ -985,9 +955,10 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
 
 	/* Save non-hangup softhangup flags. */
 	saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
-		& AST_SOFTHANGUP_ASYNCGOTO;
+		& (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE);
 	if (saved_hangup_flags) {
-		ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
+		ast_channel_clear_softhangup(chan,
+			AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE);
 	}
 
 	/* Save autoloop flag */
@@ -999,9 +970,6 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
 	saved_exten = ast_strdupa(ast_channel_exten(chan));
 	saved_priority = ast_channel_priority(chan);
 
-	/* Save whether or not we are in a subroutine */
-	saved_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
-
 	ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
 		saved_context, saved_exten, saved_priority);
 
@@ -1039,6 +1007,10 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
 		 */
 		do {
 			/* Check for hangup. */
+			if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_UNBRIDGE) {
+				saved_hangup_flags |= AST_SOFTHANGUP_UNBRIDGE;
+				ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_UNBRIDGE);
+			}
 			if (ast_check_hangup(chan)) {
 				if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
 					ast_log(LOG_ERROR, "%s An async goto just messed up our execution location.\n",
@@ -1103,9 +1075,6 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
 	/* Restore autoloop flag */
 	ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
 
-	/* Restore subroutine flag */
-	ast_set2_flag(ast_channel_flags(chan), saved_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
-
 	/* Restore non-hangup softhangup flags. */
 	if (saved_hangup_flags) {
 		ast_softhangup_nolock(chan, saved_hangup_flags);
@@ -1121,7 +1090,6 @@ static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char
 	int res;
 	int priority;
 	int old_autoloopflag;
-	int old_in_subroutine;
 	int old_priority;
 	const char *old_context;
 	const char *old_extension;
@@ -1170,9 +1138,6 @@ static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char
 	old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
 
-	/* Save subroutine flag */
-	old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
-
 	/* Save previous location, since we're going to change it */
 	old_context = ast_strdupa(ast_channel_context(chan));
 	old_extension = ast_strdupa(ast_channel_exten(chan));
@@ -1251,7 +1216,8 @@ static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char
 		ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
 	}
 
-	ast_free(gosub_args);
+	/* Must use free because the memory was allocated by asprintf(). */
+	free(gosub_args);
 
 	ast_channel_lock(chan);
 	ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
@@ -1265,9 +1231,6 @@ static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char
 
 	/* Restore autoloop flag */
 	ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
-
-	/* Restore subroutine flag */
-	ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
 	ast_channel_unlock(chan);
 
 	return RESULT_SUCCESS;
@@ -1318,7 +1281,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_APP_DEPEND,
diff --git a/apps/app_stasis.c b/apps/app_stasis.c
deleted file mode 100644
index 377b8d9..0000000
--- a/apps/app_stasis.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis dialplan application.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend>res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_app_impl.h"
-
-/*** DOCUMENTATION
-	<application name="Stasis" language="en_US">
-		<synopsis>Invoke an external Stasis application.</synopsis>
-		<syntax>
-			<parameter name="app_name" required="true">
-				<para>Name of the application to invoke.</para>
-			</parameter>
-			<parameter name="args">
-				<para>Optional comma-delimited arguments for the
-				application invocation.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>
-				Invoke a Stasis application.
-			</para>
-		</description>
-	</application>
- ***/
-
-/*! \brief Maximum number of arguments for the Stasis dialplan application */
-#define MAX_ARGS 128
-
-/*! \brief Dialplan application name */
-static const char *stasis = "Stasis";
-
-/*! /brief Stasis dialplan application callback */
-static int app_exec(struct ast_channel *chan, const char *data)
-{
-	char *parse = NULL;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(app_name);
-		AST_APP_ARG(app_argv)[MAX_ARGS];
-	);
-
-	ast_assert(chan != NULL);
-	ast_assert(data != NULL);
-
-	/* parse the arguments */
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (args.argc < 1) {
-		ast_log(LOG_WARNING, "Stasis app_name argument missing\n");
-		return -1;
-	}
-
-	return stasis_app_exec(
-		chan, args.app_name, args.argc - 1, args.app_argv);
-}
-
-static int load_module(void)
-{
-	int r = 0;
-
-	stasis_app_ref();
-	r |= ast_register_application_xml(stasis, app_exec);
-	return r;
-}
-
-static int unload_module(void)
-{
-	int r = 0;
-	r |= ast_unregister_application(stasis);
-	stasis_app_unref();
-	return r;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Stasis dialplan application",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis",
-	);
diff --git a/apps/app_system.c b/apps/app_system.c
index f40255a..7fe453d 100644
--- a/apps/app_system.c
+++ b/apps/app_system.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c
index bb35089..5ef80c3 100644
--- a/apps/app_talkdetect.c
+++ b/apps/app_talkdetect.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -42,8 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/utils.h"
 #include "asterisk/dsp.h"
 #include "asterisk/app.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="BackgroundDetect" language="en_US">
@@ -93,7 +91,7 @@ static int background_detect_exec(struct ast_channel *chan, const char *data)
 	int analysistime = -1;
 	int continue_analysis = 1;
 	int x;
-	RAII_VAR(struct ast_format *, origrformat, NULL, ao2_cleanup);
+	struct ast_format origrformat;
 	struct ast_dsp *dsp = NULL;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(filename);
@@ -103,6 +101,7 @@ static int background_detect_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(analysistime);
 	);
 
+	ast_format_clear(&origrformat);
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
 		return -1;
@@ -132,8 +131,8 @@ static int background_detect_exec(struct ast_channel *chan, const char *data)
 			}
 		}
 
-		origrformat = ao2_bump(ast_channel_readformat(chan));
-		if ((ast_set_read_format(chan, ast_format_slin))) {
+		ast_format_copy(&origrformat, ast_channel_readformat(chan));
+		if ((ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR))) {
 			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
 			res = -1;
 			break;
@@ -188,8 +187,7 @@ static int background_detect_exec(struct ast_channel *chan, const char *data)
 						ast_frfree(fr);
 						break;
 					}
-				} else if ((fr->frametype == AST_FRAME_VOICE) &&
-				(ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) && continue_analysis) {
+				} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass.format.id == AST_FORMAT_SLINEAR) && continue_analysis) {
 					int totalsilence;
 					int ms;
 					res = ast_dsp_silence(dsp, fr, &totalsilence);
@@ -235,9 +233,9 @@ static int background_detect_exec(struct ast_channel *chan, const char *data)
 	} while (0);
 
 	if (res > -1) {
-		if (origrformat && ast_set_read_format(chan, origrformat)) {
+		if (origrformat.id && ast_set_read_format(chan, &origrformat)) {
 			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
-				ast_channel_name(chan), ast_format_get_name(origrformat));
+				ast_channel_name(chan), ast_getformatname(&origrformat));
 		}
 	}
 	if (dsp) {
@@ -256,5 +254,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, background_detect_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Playback with Talk Detection");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");
diff --git a/apps/app_test.c b/apps/app_test.c
index 8b030a8..5b7b979 100644
--- a/apps/app_test.c
+++ b/apps/app_test.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
@@ -44,7 +44,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/app.h"
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="TestServer" language="en_US">
@@ -92,12 +91,11 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who)
 	short *foo;
 	struct timeval start;
 	struct ast_frame *f;
-	struct ast_format *rformat;
+	struct ast_format rformat;
 
-	rformat = ao2_bump(ast_channel_readformat(chan));
-	if (ast_set_read_format(chan, ast_format_slin)) {
+	ast_format_copy(&rformat, ast_channel_readformat(chan));
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
-		ao2_cleanup(rformat);
 		return -1;
 	}
 	start = ast_tvnow();
@@ -113,8 +111,7 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who)
 			res = -1;
 			break;
 		}
-		if ((f->frametype == AST_FRAME_VOICE) &&
-			(ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
 			foo = (short *)f->data.ptr;
 			for (x=0;x<f->samples;x++) {
 				noise += abs(foo[x]);
@@ -124,13 +121,11 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who)
 		ast_frfree(f);
 	}
 
-	if (rformat) {
-		if (ast_set_read_format(chan, rformat)) {
+	if (rformat.id) {
+		if (ast_set_read_format(chan, &rformat)) {
 			ast_log(LOG_NOTICE, "Unable to restore original format!\n");
-			ao2_ref(rformat, -1);
 			return -1;
 		}
-		ao2_ref(rformat, -1);
 	}
 	if (res < 0)
 		return res;
@@ -498,5 +493,4 @@ static int load_module(void)
 	return res;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Interface Test Application");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Interface Test Application");
diff --git a/apps/app_transfer.c b/apps/app_transfer.c
index 9f1feba..1b81082 100644
--- a/apps/app_transfer.c
+++ b/apps/app_transfer.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405830 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
diff --git a/apps/app_url.c b/apps/app_url.c
index 7eb4e3e..00ea720 100644
--- a/apps/app_url.c
+++ b/apps/app_url.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
@@ -179,5 +179,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, sendurl_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Send URL Applications");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send URL Applications");
diff --git a/apps/app_userevent.c b/apps/app_userevent.c
index 9d3a3c7..de196f8 100644
--- a/apps/app_userevent.c
+++ b/apps/app_userevent.c
@@ -27,40 +27,33 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 414406 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 #include "asterisk/manager.h"
 #include "asterisk/app.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
 	<application name="UserEvent" language="en_US">
 		<synopsis>
-			Send an arbitrary user-defined event to parties interested in a channel (AMI users and relevant res_stasis applications).
+			Send an arbitrary event to the manager interface.
 		</synopsis>
 		<syntax>
 			<parameter name="eventname" required="true" />
 			<parameter name="body" />
 		</syntax>
 		<description>
-			<para>Sends an arbitrary event to interested parties, with an optional
+			<para>Sends an arbitrary event to the manager interface, with an optional
 			<replaceable>body</replaceable> representing additional arguments. The
 			<replaceable>body</replaceable> may be specified as
-			a <literal>,</literal> delimited list of key:value pairs.</para>
-			<para>For AMI, each additional argument will be placed on a new line in
-			the event and the format of the event will be:</para>
+			a <literal>,</literal> delimited list of headers. Each additional
+			argument will be placed on a new line in the event. The format of the
+			event will be:</para>
 			<para>    Event: UserEvent</para>
 			<para>    UserEvent: <specified event name></para>
 			<para>    [body]</para>
-			<para>If no <replaceable>body</replaceable> is specified, only Event and
-			UserEvent headers will be present.</para>
-			<para>For res_stasis applications, the event will be provided as a JSON
-			blob with additional arguments appearing as keys in the object and the
-			<replaceable>eventname</replaceable> under the
-			<literal>eventname</literal> key.</para>
+			<para>If no <replaceable>body</replaceable> is specified, only Event and UserEvent headers will be present.</para>
 		</description>
 	</application>
  ***/
@@ -75,10 +68,16 @@ static int userevent_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(eventname);
 		AST_APP_ARG(extra)[100];
 	);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+	struct ast_str *body = ast_str_create(16);
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "UserEvent requires an argument (eventname,optional event body)\n");
+		ast_free(body);
+		return -1;
+	}
+
+	if (!body) {
+		ast_log(LOG_WARNING, "Unable to allocate buffer\n");
 		return -1;
 	}
 
@@ -86,37 +85,29 @@ static int userevent_exec(struct ast_channel *chan, const char *data)
 
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	blob = ast_json_pack("{s: s}",
-			     "eventname", args.eventname);
-	if (!blob) {
-		return -1;
-	}
-
 	for (x = 0; x < args.argc - 1; x++) {
-		char *key, *value = args.extra[x];
-		struct ast_json *json_value;
-
-		key = strsep(&value, ":");
-		if (!value) {
-			/* no ':' in string? */
-			continue;
-		}
-
-		value = ast_strip(value);
-		json_value = ast_json_string_create(value);
-		if (!json_value) {
-			return -1;
-		}
-
-		/* ref stolen by ast_json_object_set */
-		if (ast_json_object_set(blob, key, json_value)) {
-			return -1;
-		}
+		ast_str_append(&body, 0, "%s\r\n", args.extra[x]);
 	}
 
-	ast_channel_lock(chan);
-	ast_multi_object_blob_single_channel_publish(chan, ast_multi_user_event_type(), blob);
-	ast_channel_unlock(chan);
+	/*** DOCUMENTATION
+	<managerEventInstance>
+		<synopsis>A user defined event raised from the dialplan.</synopsis>
+		<parameter name="UserEvent">
+			<para>The event name, as specified in the dialplan.</para>
+		</parameter>
+		<see-also>
+			<ref type="application">UserEvent</ref>
+		</see-also>
+	</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_USER, "UserEvent",
+			"UserEvent: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"%s",
+			args.eventname, ast_channel_uniqueid(chan), ast_str_buffer(body));
+
+	ast_free(body);
+
 	return 0;
 }
 
diff --git a/apps/app_verbose.c b/apps/app_verbose.c
index 9cabf41..c6fc8d1 100644
--- a/apps/app_verbose.c
+++ b/apps/app_verbose.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/app.h"
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index d073c74..d5b1dc5 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -21,34 +21,23 @@
  * \author Mark Spencer <markster at digium.com>
  * \brief Comedian Mail - Voicemail System
  *
- * unixODBC (http://www.unixodbc.org/)
- * A source distribution of University of Washington's IMAP c-client
+ * \extref unixODBC (http://www.unixodbc.org/)
+ * \extref A source distribution of University of Washington's IMAP c-client
  *         (http://www.washington.edu/imap/)
  *
  * \par See also
  * \arg \ref Config_vm
  * \note For information about voicemail IMAP storage, https://wiki.asterisk.org/wiki/display/AST/IMAP+Voicemail+Storage
  * \ingroup applications
- * \todo This module requires res_adsi to load. This needs to be optional
+ * \note This module requires res_adsi to load. This needs to be optional
  * during compilation.
  *
- * \todo This file is now almost impossible to work with, due to all \#ifdefs.
+ * \note This file is now almost impossible to work with, due to all \#ifdefs.
  *       Feels like the database code before realtime. Someone - please come up
  *       with a plan to clean this up.
  */
 
-/*! \li \ref app_voicemail.c uses configuration file \ref voicemail.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page voicemail.conf voicemail.conf
- * \verbinclude voicemail.conf.sample
- */
-
 /*** MODULEINFO
-	<defaultenabled>yes</defaultenabled>
-	<conflict>res_mwi_external</conflict>
 	<use type="module">res_adsi</use>
 	<use type="module">res_smdi</use>
 	<support_level>core</support_level>
@@ -102,7 +91,7 @@
 #endif
 #endif
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428865 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_SPOOL_DIR */
 #include <sys/time.h>
@@ -133,9 +122,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428865 $")
 #include "asterisk/strings.h"
 #include "asterisk/smdi.h"
 #include "asterisk/astobj2.h"
+#include "asterisk/event.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/test.h"
-#include "asterisk/format_cache.h"
 
 #ifdef ODBC_STORAGE
 #include "asterisk/res_odbc.h"
@@ -466,33 +455,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428865 $")
 		<description>
 		</description>
 	</manager>
-	<manager name="VoicemailRefresh" language="en_US">
-		<synopsis>
-			Tell Asterisk to poll mailboxes for a change
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Context" />
-			<parameter name="Mailbox" />
-		</syntax>
-		<description>
-			<para>Normally, MWI indicators are only sent when Asterisk itself
-			changes a mailbox.  With external programs that modify the content
-			of a mailbox from outside the application, an option exists called
-			<literal>pollmailboxes</literal> that will cause voicemail to
-			continually scan all mailboxes on a system for changes.  This can
-			cause a large amount of load on a system.  This command allows
-			external applications to signal when a particular mailbox has
-			changed, thus permitting external applications to modify mailboxes
-			and MWI to work without introducing considerable CPU load.</para>
-			<para>If <replaceable>Context</replaceable> is not specified, all
-			mailboxes on the system will be polled for changes.  If
-			<replaceable>Context</replaceable> is specified, but
-			<replaceable>Mailbox</replaceable> is omitted, then all mailboxes
-			within <replaceable>Context</replaceable> will be polled.
-			Otherwise, only a single mailbox will be polled for changes.</para>
-		</description>
-	</manager>
  ***/
 
 #ifdef IMAP_STORAGE
@@ -759,15 +721,6 @@ For vm_intro_it:
 \arg \b vm-vecchio	old
 \arg \b vm-vecchi	old plural
 
-Japanese requires the following additional soundfile:
-\arg \b jp-arimasu          there is
-\arg \b jp-arimasen         there is not
-\arg \b jp-oshitekudasai    please press
-\arg \b jp-ni               article ni
-\arg \b jp-ga               article ga
-\arg \b jp-wa               article wa
-\arg \b jp-wo               article wo
-
 Chinese (Taiwan) requires the following additional soundfile:
 \arg \b vm-tong		A class-word for call (tong1)
 \arg \b vm-ri		A class-word for day (ri4)
@@ -798,7 +751,7 @@ struct ast_vm_user {
 	char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
 	char password[80];               /*!< Secret pin code, numbers only */
 	char fullname[80];               /*!< Full name, for directory app */
-	char *email;                     /*!< E-mail address */
+	char email[80];                  /*!< E-mail address */
 	char *emailsubject;              /*!< E-mail subject */
 	char *emailbody;                 /*!< E-mail body */
 	char pager[80];                  /*!< E-mail address to pager (no attachment) */
@@ -989,8 +942,10 @@ static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
 static pthread_t poll_thread = AST_PTHREADT_NULL;
 static unsigned char poll_thread_run;
 
-/*! Subscription to MWI event subscription changes */
-static struct stasis_subscription *mwi_sub_sub;
+/*! Subscription to ... MWI event subscriptions */
+static struct ast_event_sub *mwi_sub_sub;
+/*! Subscription to ... MWI event un-subscriptions */
+static struct ast_event_sub *mwi_unsub_sub;
 
 /*!
  * \brief An MWI subscription
@@ -1004,24 +959,16 @@ struct mwi_sub {
 	int old_urgent;
 	int old_new;
 	int old_old;
-	char *uniqueid;
+	uint32_t uniqueid;
 	char mailbox[1];
 };
 
 struct mwi_sub_task {
 	const char *mailbox;
 	const char *context;
-	const char *uniqueid;
+	uint32_t uniqueid;
 };
 
-static void mwi_sub_task_dtor(struct mwi_sub_task *mwist)
-{
-	ast_free((void *) mwist->mailbox);
-	ast_free((void *) mwist->context);
-	ast_free((void *) mwist->uniqueid);
-	ast_free(mwist);
-}
-
 static struct ast_taskprocessor *mwi_subscription_tps;
 
 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
@@ -1098,6 +1045,8 @@ static void read_password_from_file(const char *secretfn, char *password, int pa
 static int write_password_to_file(const char *secretfn, const char *password);
 static const char *substitute_escapes(const char *value);
 static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu);
+static void notify_new_state(struct ast_vm_user *vmu);
+
 /*!
  * Place a message in the indicated folder
  *
@@ -1110,7 +1059,7 @@ static int message_range_and_existence_check(struct vm_state *vms, const char *m
  *
  * \note the "move" parameter is only honored for IMAP voicemail presently
  * \retval 0 Success
- * \retval other Failure
+ * \revval other Failure
  */
 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move);
 
@@ -1127,34 +1076,6 @@ static int vm_test_destroy_user(const char *context, const char *mailbox);
 static int vm_test_create_user(const char *context, const char *mailbox);
 #endif
 
-/*!
- * \internal
- * \brief Parse the given mailbox_id into mailbox and context.
- * \since 12.0.0
- *
- * \param mailbox_id The mailbox at context string to separate.
- * \param mailbox Where the mailbox part will start.
- * \param context Where the context part will start.  ("default" if not present)
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
-{
-	if (ast_strlen_zero(mailbox_id) || !mailbox || !context) {
-		return -1;
-	}
-	*context = mailbox_id;
-	*mailbox = strsep(context, "@");
-	if (ast_strlen_zero(*mailbox)) {
-		return -1;
-	}
-	if (ast_strlen_zero(*context)) {
-		*context = "default";
-	}
-	return 0;
-}
-
 struct ao2_container *inprocess_container;
 
 struct inprocess {
@@ -1273,8 +1194,6 @@ static void populate_defaults(struct ast_vm_user *vmu)
 		vmu->maxdeletedmsg = maxdeletedmsg;
 	}
 	vmu->volgain = volgain;
-	ast_free(vmu->email);
-	vmu->email = NULL;
 	ast_free(vmu->emailsubject);
 	vmu->emailsubject = NULL;
 	ast_free(vmu->emailbody);
@@ -1586,8 +1505,7 @@ static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *
 		} else if (!strcasecmp(var->name, "pager")) {
 			ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
 		} else if (!strcasecmp(var->name, "email")) {
-			ast_free(retval->email);
-			retval->email = ast_strdup(var->value);
+			ast_copy_string(retval->email, var->value, sizeof(retval->email));
 		} else if (!strcasecmp(var->name, "fullname")) {
 			ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
 		} else if (!strcasecmp(var->name, "context")) {
@@ -1724,7 +1642,6 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *contex
 		if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
 			*vmu = *cur;
 			if (!ivm) {
-				vmu->email = ast_strdup(cur->email);
 				vmu->emailbody = ast_strdup(cur->emailbody);
 				vmu->emailsubject = ast_strdup(cur->emailsubject);
 			}
@@ -1825,7 +1742,7 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
 						new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
 						sprintf(new, "%s%s", newpassword, value);
 					}
-					if (!(cat = ast_category_get(cfg, category, NULL))) {
+					if (!(cat = ast_category_get(cfg, category))) {
 						ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
 						break;
 					}
@@ -1862,7 +1779,7 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
 					}
 					new = ast_alloca(strlen(newpassword) + 1);
 					sprintf(new, "%s", newpassword);
-					if (!(cat = ast_category_get(cfg, category, NULL))) {
+					if (!(cat = ast_category_get(cfg, category))) {
 						ast_debug(4, "failed to get category!\n");
 						ast_free(var);
 						break;
@@ -2007,9 +1924,6 @@ static void free_user(struct ast_vm_user *vmu)
 {
 	if (ast_test_flag(vmu, VM_ALLOCED)) {
 
-		ast_free(vmu->email);
-		vmu->email = NULL;
-
 		ast_free(vmu->emailbody);
 		vmu->emailbody = NULL;
 
@@ -2171,6 +2085,8 @@ static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_
 	char *attachment;
 	int i;
 	BODY *body;
+	int ret = 0;
+	int curr_mbox;
 
 	/* This function is only used for retrieval of IMAP greetings
 	 * regular messages are not retrieved this way, nor are greetings
@@ -2204,6 +2120,10 @@ static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_
 	*vms_p->introfn = '\0';
 
 	ast_mutex_lock(&vms_p->lock);
+
+	/* get the current mailbox so that we can point the mailstream back to it later */
+	curr_mbox = get_folder_by_name(vms_p->curbox);
+
 	if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
 		ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
 		ast_mutex_unlock(&vms_p->lock);
@@ -2218,21 +2138,28 @@ static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_
 			attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
 		} else {
 			ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
-			ast_mutex_unlock(&vms_p->lock);
-			return -1;
+			ret = -1;
+			break;
 		}
 		filename = strsep(&attachment, ".");
 		if (!strcmp(filename, file)) {
 			ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
 			vms_p->msgArray[vms_p->curmsg] = i + 1;
 			save_body(body, vms_p, "2", attachment, 0);
-			ast_mutex_unlock(&vms_p->lock);
-			return 0;
+			ret = 0;
+			break;
 		}
 	}
-	ast_mutex_unlock(&vms_p->lock);
 
-	return -1;
+	if (curr_mbox != -1) {
+		/* restore previous mbox stream */
+		if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
+			ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
+			ret = -1;
+		}
+	}
+	ast_mutex_unlock(&vms_p->lock);
+	return ret;
 }
 
 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
@@ -2246,12 +2173,13 @@ static int imap_retrieve_file(const char *dir, const int msgnum, const char *mai
 	FILE *text_file_ptr;
 	int res = 0;
 	struct ast_vm_user *vmu;
+	int curr_mbox;
 
 	if (!(vmu = find_user(NULL, context, mailbox))) {
 		ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
 		return -1;
 	}
-	
+
 	if (msgnum < 0) {
 		if (imapgreetings) {
 			res = imap_retrieve_greeting(dir, msgnum, vmu);
@@ -2278,6 +2206,19 @@ static int imap_retrieve_file(const char *dir, const int msgnum, const char *mai
 		goto exit;
 	}
 
+	/* Ensure we have the correct mailbox open and have a valid mailstream for it */
+	curr_mbox = get_folder_by_name(vms->curbox);
+	if (curr_mbox < 0) {
+		ast_debug(3, "Mailbox folder curbox not set, defaulting to Inbox\n");
+		curr_mbox = 0;
+	}
+	init_mailstream(vms, curr_mbox);
+	if (!vms->mailstream) {
+		ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmu->mailbox);
+		res = -1;
+		goto exit;
+	}
+
 	make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
 	snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
 
@@ -2428,7 +2369,7 @@ static int __messagecount(const char *context, const char *mailbox, const char *
 	/* We have to get the user before we can open the stream! */
 	vmu = find_user(&vmus, context, mailbox);
 	if (!vmu) {
-		ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
+		ast_log(AST_LOG_WARNING, "Couldn't find mailbox %s in context %s\n", mailbox, context);
 		return -1;
 	} else {
 		/* No IMAP account available */
@@ -2444,7 +2385,6 @@ static int __messagecount(const char *context, const char *mailbox, const char *
 		free_user(vmu);
 		return -1;
 	}
-	ast_assert(msgnum < vms->msg_array_max);
 
 	/* check if someone is accessing this box right now... */
 	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
@@ -2554,22 +2494,15 @@ static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, str
 
 /*!
  * \brief Gets the number of messages that exist in a mailbox folder.
- * \param mailbox_id
+ * \param context
+ * \param mailbox
  * \param folder
  * 
  * This method is used when IMAP backend is used.
  * \return The number of messages in this mailbox folder (zero or more).
  */
-static int messagecount(const char *mailbox_id, const char *folder)
+static int messagecount(const char *context, const char *mailbox, const char *folder)
 {
-	char *context;
-	char *mailbox;
-
-	if (ast_strlen_zero(mailbox_id)
-		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
-		return 0;
-	}
-
 	if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
 		return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
 	} else {
@@ -2592,12 +2525,9 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
 	STRING str;
 	int ret; /* for better error checking */
 	char *imap_flags = NIL;
-	int msgcount;
+	int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
 	int box = NEW_FOLDER;
 
-	snprintf(mailbox, sizeof(mailbox), "%s@%s", vmu->mailbox, vmu->context);
-	msgcount = messagecount(mailbox, "INBOX") + messagecount(mailbox, "Old");
-
 	/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
 	if (msgnum < 0) {
 		if(!imapgreetings) {
@@ -2641,7 +2571,7 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
 		 * of this function, we will revert back to an empty string if tempcopy
 		 * is 1.
 		 */
-		vmu->email = ast_strdup(vmu->imapuser);
+		ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
 		tempcopy = 1;
 	}
 
@@ -2653,10 +2583,8 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
 	   command hangs. */
 	if (!(p = vm_mkftemp(tmp))) {
 		ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
-		if (tempcopy) {
-			ast_free(vmu->email);
-			vmu->email = NULL;
-		}
+		if (tempcopy)
+			*(vmu->email) = '\0';
 		return -1;
 	}
 
@@ -3332,7 +3260,7 @@ static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
 	if (taglen < 1)
 		return NULL;
 
-	if (!(start = strstr(header, tag)))
+	if (!(start = strcasestr(header, tag)))
 		return NULL;
 
 	/* Since we can be called multiple times we should clear our buffer */
@@ -3741,7 +3669,7 @@ static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
 
 /*!
  * \brief Retrieves a file from an ODBC data store.
- * \param dir the path to the file to be retreived.
+ * \param dir the path to the file to be retrieved.
  * \param msgnum the message number, such as within a mailbox folder.
  * 
  * This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end.
@@ -4967,7 +4895,7 @@ static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, con
  * \param chan
  * \param category
  * \param imap if == 1, indicates the target folder for the email notification to be sent to will be an IMAP mailstore. This causes additional mailbox headers to be set, which would facilitate searching for the email in the destination IMAP folder.
- * \param flag, msg_id
+ * \param flag
  *
  * The email body, and base 64 encoded attachement (if any) are stored to the file identified by *p. This method does not actually send the email.  That is done by invoking the configure 'mailcmd' and piping this generated file into it, or with the sendemail() function.
  */
@@ -5001,9 +4929,6 @@ static void make_email_file(FILE *p,
 	struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
 	char *greeting_attachment; 
 	char filename[256];
-	int first_line;
-	char *emailsbuf;
-	char *email;
 
 	if (!str1 || !str2) {
 		ast_free(str1);
@@ -5045,7 +4970,7 @@ static void make_email_file(FILE *p,
 			ast_str_substitute_variables(&str1, 0, ast, fromstring);
 
 			if (check_mime(ast_str_buffer(str1))) {
-				first_line = 1;
+				int first_line = 1;
 				ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
 				while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
 					*ptr = '\0';
@@ -5066,25 +4991,20 @@ static void make_email_file(FILE *p,
 		fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
 	}
 
-	emailsbuf = ast_strdupa(vmu->email);
-	fprintf(p, "To:");
-	first_line = 1;
-	while ((email = strsep(&emailsbuf, "|"))) {
-		char *next = emailsbuf;
-		if (check_mime(vmu->fullname)) {
-			char *ptr;
-			ast_str_encode_mime(&str2, 0, vmu->fullname, first_line ? strlen("To: ") : 0, strlen(email) + 3 + (next ? strlen(",") : 0));
-			while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
-				*ptr = '\0';
-				fprintf(p, " %s" ENDL, ast_str_buffer(str2));
-				/* Substring is smaller, so this will never grow */
-				ast_str_set(&str2, 0, "%s", ptr + 1);
-			}
-			fprintf(p, " %s <%s>%s" ENDL, ast_str_buffer(str2), email, next ? "," : "");
-		} else {
-			fprintf(p, " %s <%s>%s" ENDL, ast_str_quote(&str2, 0, vmu->fullname), email, next ? "," : "");
+	if (check_mime(vmu->fullname)) {
+		int first_line = 1;
+		char *ptr;
+		ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
+		while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+			*ptr = '\0';
+			fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
+			first_line = 0;
+			/* Substring is smaller, so this will never grow */
+			ast_str_set(&str2, 0, "%s", ptr + 1);
 		}
-		first_line = 0;
+		fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
+	} else {
+		fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
 	}
 
 	if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
@@ -5094,8 +5014,8 @@ static void make_email_file(FILE *p,
 			prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
 			ast_str_substitute_variables(&str1, 0, ast, e_subj);
 			if (check_mime(ast_str_buffer(str1))) {
+				int first_line = 1;
 				char *ptr;
-				first_line = 1;
 				ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
 				while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
 					*ptr = '\0';
@@ -5707,17 +5627,16 @@ static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *
 
 /*!
  * \brief Gets the number of messages that exist in a mailbox folder.
- * \param mailbox_id
+ * \param context
+ * \param mailbox
  * \param folder
  * 
  * This method is used when ODBC backend is used.
  * \return The number of messages in this mailbox folder (zero or more).
  */
-static int messagecount(const char *mailbox_id, const char *folder)
+static int messagecount(const char *context, const char *mailbox, const char *folder)
 {
 	struct odbc_obj *obj = NULL;
-	char *context;
-	char *mailbox;
 	int nummsgs = 0;
 	int res;
 	SQLHSTMT stmt = NULL;
@@ -5726,8 +5645,7 @@ static int messagecount(const char *mailbox_id, const char *folder)
 	struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
 
 	/* If no mailbox, return immediately */
-	if (ast_strlen_zero(mailbox_id)
-		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
+	if (ast_strlen_zero(mailbox)) {
 		return 0;
 	}
 
@@ -5778,16 +5696,16 @@ yuck:
  * This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
  * \return 1 if the folder has one or more messages. zero otherwise.
  */
-static int has_voicemail(const char *mailboxes, const char *folder)
+static int has_voicemail(const char *mailbox, const char *folder)
 {
-	char *parse;
-	char *mailbox;
-
-	parse = ast_strdupa(mailboxes);
-	while ((mailbox = strsep(&parse, ",&"))) {
-		if (messagecount(mailbox, folder)) {
+	char tmp[256], *tmp2 = tmp, *box, *context;
+	ast_copy_string(tmp, mailbox, sizeof(tmp));
+	while ((context = box = strsep(&tmp2, ",&"))) {
+		strsep(&context, "@");
+		if (ast_strlen_zero(context))
+			context = "default";
+		if (messagecount(context, box, folder))
 			return 1;
-		}
 	}
 	return 0;
 }
@@ -5803,7 +5721,7 @@ static int has_voicemail(const char *mailboxes, const char *folder)
  * \param recip
  * \param fmt
  * \param dir
- * \param flag, dest_folder
+ * \param flag
  *
  * This is only used by file storage based mailboxes.
  *
@@ -5875,16 +5793,8 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
 #endif
 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
 
-static int messagecount(const char *mailbox_id, const char *folder)
+static int messagecount(const char *context, const char *mailbox, const char *folder)
 {
-	char *context;
-	char *mailbox;
-
-	if (ast_strlen_zero(mailbox_id)
-		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
-		return 0;
-	}
-
 	return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
 }
 
@@ -5927,7 +5837,7 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
 
 /** 
  * \brief Determines if the given folder has messages.
- * \param mailbox The \@ delimited string for user\@context. If no context is found, uses 'default' for the context.
+ * \param mailbox The @ delimited string for user at context. If no context is found, uses 'default' for the context.
  * \param folder the folder to look in
  *
  * This function is used when the mailbox is stored in a filesystem back end.
@@ -6051,7 +5961,7 @@ static void run_externnotify(char *context, char *extension, const char *flag)
 			else if (!strncmp(mwi_msg->cause, "BLK", 3))
 				ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
 			ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
-			ao2_ref(mwi_msg, -1);
+			ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
 		} else {
 			ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
 		}
@@ -6158,12 +6068,13 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
 	if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
 		if (!ast_seekstream(recording_fs, 0, SEEK_END)) {
 			long framelength = ast_tellstream(recording_fs);
-			int sample_rate = ast_ratestream(recording_fs);
-			if (sample_rate) {
-				duration = (int) (framelength / sample_rate);
-			} else {
-				ast_log(LOG_ERROR,"Unable to determine sample rate of recording %s\n", recdata->recording_file);
-			}
+			struct ast_format result = {0,};
+			/* XXX This use of ast_getformatbyname seems incorrect here. The file extension does not necessarily correspond
+			 * to the name of the format. For instance, if "raw" were passed in, I don't think ast_getformatbyname would
+			 * find the slinear format
+			 */
+			ast_getformatbyname(recdata->recording_ext, &result);
+			duration = (int) (framelength / ast_format_rate(&result));
 		}
 		ast_closestream(recording_fs);
 	}
@@ -6373,6 +6284,7 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
 		}
 
 		STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
+		notify_new_state(recipient);
 	}
 
 	free_user(recipient);
@@ -7612,7 +7524,7 @@ static int get_folder(struct ast_channel *chan, int start)
 			if (ast_fileexists(fn, NULL, NULL)) {
 				d = vm_play_folder_name(chan, fn);
 			} else {
-				ast_verb(4, "Failed to find file %s; falling back to INBOX\n", fn);
+				ast_verb(1, "failed to find %s\n", fn);
 				d = vm_play_folder_name(chan, "vm-INBOX");
 			}
 		} else {
@@ -7634,34 +7546,6 @@ static int get_folder(struct ast_channel *chan, int start)
 	return d;
 }
 
-/* Japanese Syntax */
-static int get_folder_ja(struct ast_channel *chan, int start)
-{
-        int x;
-        int d;
-        char fn[256];
-        for (x = start; x< 5; x++) {    /* For all folders */
-                if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL))) {
-                        return d;
-		}
-		snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));     /* Folder name */
-		d = vm_play_folder_name(chan, fn);
-		if (d) {
-                        return d;
-		}
-                d = ast_waitfordigit(chan, 500);
-                if (d) {
-                        return d;
-		}
-        }
-        d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
-        if (d) {
-                return d;
-	}
-        d = ast_waitfordigit(chan, 4000);
-        return d;
-}
-
 /*!
  * \brief plays a prompt and waits for a keypress.
  * \param chan
@@ -7683,12 +7567,7 @@ static int get_folder2(struct ast_channel *chan, char *fn, int start)
 	while (((res < '0') || (res > '9')) &&
 			(res != '#') && (res >= 0) &&
 			loops < 4) {
-                /* res = get_folder(chan, 0); */
-                if (!strcasecmp(ast_channel_language(chan),"ja")) {   /* Japanese syntax */
-                      res = get_folder_ja(chan, 0);
-                } else { /* Default syntax */
-		      res = get_folder(chan, 0);
-		}
+		res = get_folder(chan, 0);
 		loops++;
 	}
 	if (loops == 4) { /* give up */
@@ -7820,7 +7699,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
 				char duration_buf[12];
 
 				*duration += prepend_duration;
-				msg_cat = ast_category_get(msg_cfg, "message", NULL);
+				msg_cat = ast_category_get(msg_cfg, "message");
 				snprintf(duration_buf, 11, "%ld", *duration);
 				if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
 					ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
@@ -7878,16 +7757,27 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
 	return cmd;
 }
 
-static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
+static void queue_mwi_event(const char *box, int urgent, int new, int old)
 {
-	char *mailbox;
-	char *context;
+	struct ast_event *event;
+	char *mailbox, *context;
 
-	if (separate_mailbox(ast_strdupa(box), &mailbox, &context)) {
+	/* Strip off @default */
+	context = mailbox = ast_strdupa(box);
+	strsep(&context, "@");
+	if (ast_strlen_zero(context))
+		context = "default";
+
+	if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
+			AST_EVENT_IE_END))) {
 		return;
 	}
 
-	ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
+	ast_event_queue_and_cache(event);
 }
 
 /*!
@@ -7977,7 +7867,32 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
 	if (ast_app_has_voicemail(ext_context, NULL)) 
 		ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
 
-	queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
+	queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
+
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a new message has been left in a voicemail mailbox.</synopsis>
+			<syntax>
+				<parameter name="Mailbox">
+					<para>The mailbox with the new message, specified as <emphasis>mailbox</emphasis>@<emphasis>context</emphasis></para>
+				</parameter>
+				<parameter name="Waiting">
+					<para>Whether or not the mailbox has access to a voicemail application.</para>
+				</parameter>
+				<parameter name="New">
+					<para>The number of new messages.</para>
+				</parameter>
+				<parameter name="Old">
+					<para>The number of old messages.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting",
+			"Mailbox: %s@%s\r\n"
+			"Waiting: %d\r\n"
+			"New: %d\r\n"
+			"Old: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
 	run_externnotify(vmu->context, vmu->mailbox, flag);
 
 #ifdef IMAP_STORAGE
@@ -8011,7 +7926,7 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
  *   - attempt to determine the context and and mailbox, and then invoke leave_message() function to record and store the message.
  *
  * When in the forward message mode (is_new_message == 0):
- *   - retreives the current message to be forwarded
+ *   - retrieves the current message to be forwarded
  *   - copies the original message to a temporary file, so updates to the envelope can be done.
  *   - determines the target mailbox and folders
  *   - copies the message into the target mailbox, using copy_message() or by generating the message into an email attachment if using imap folders.
@@ -8293,7 +8208,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
 				/* If forwarded with intro, DON'T PLAY THIS MESSAGE AGAIN! */
 				if (ast_strlen_zero(vmstmp.introfn))
 #endif
-				res = ast_play_and_wait(chan, "vm-msgforwarded");
+				res = ast_play_and_wait(chan, "vm-msgsaved");
 			}
 #ifndef IMAP_STORAGE
 			else {
@@ -8413,8 +8328,6 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
 		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q  H 'digits/kai' M ", NULL);
 	} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {     /* ITALIAN syntax */
 		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
-	} else if (!strcasecmp(ast_channel_language(chan),"ja")) {     /* Japanese syntax */
-		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "PHM q 'jp-ni' 'vm-received'", NULL);
 	} else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {     /* DUTCH syntax */
 		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
 	} else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {     /* NORWEGIAN syntax */
@@ -8889,7 +8802,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
 		} else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
 			/* Move to old folder before deleting */
 			res = save_to_folder(vmu, vms, x, 1, NULL, 0);
-			if (res == ERROR_LOCK_PATH) {
+			if (res) {
 				/* If save failed do not delete the message */
 				ast_log(AST_LOG_WARNING, "Save failed.  Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
 				vms->deleted[x] = 0;
@@ -8899,7 +8812,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
 		} else if (vms->deleted[x] && vmu->maxdeletedmsg) {
 			/* Move to deleted folder */
 			res = save_to_folder(vmu, vms, x, 10, NULL, 0);
-			if (res == ERROR_LOCK_PATH) {
+			if (res) {
 				/* If save failed do not delete the message */
 				vms->deleted[x] = 0;
 				vms->heard[x] = 0;
@@ -8980,19 +8893,6 @@ static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
 	}
 }
 
-static int vm_play_folder_name_ja(struct ast_channel *chan, char *box)
-{
-        int cmd;
-
-        if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
-                cmd = ast_play_and_wait(chan, box);
-                return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
-        } else {
-                cmd = ast_play_and_wait(chan, box);
-                return cmd;
-        }
-}
-
 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
 {
 	int cmd;
@@ -9035,8 +8935,6 @@ static int vm_play_folder_name(struct ast_channel *chan, char *box)
 		return vm_play_folder_name_gr(chan, box);
 	} else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {  /* Hebrew syntax */
 		return ast_play_and_wait(chan, box);
-        } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {  /* Japanese syntax */
-                return vm_play_folder_name_ja(chan, box);
 	} else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
 		return vm_play_folder_name_pl(chan, box);
 	} else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {  /* Ukrainian syntax */
@@ -9070,7 +8968,7 @@ static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
 		if (!res) 
 			res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
 		if (!res) {
-			if ((vms->newmessages == 1)) {
+			if (vms->newmessages == 1) {
 				res = ast_play_and_wait(chan, "vm-INBOX");
 				if (!res)
 					res = ast_play_and_wait(chan, "vm-message");
@@ -9084,7 +8982,7 @@ static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
 		res = ast_play_and_wait(chan, "vm-youhave");
 		if (!res)
 			res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
-		if ((vms->oldmessages == 1)){
+		if (vms->oldmessages == 1){
 			res = ast_play_and_wait(chan, "vm-Old");
 			if (!res)
 				res = ast_play_and_wait(chan, "vm-message");
@@ -9260,45 +9158,6 @@ static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
 	}
 	return res;
 }
-
-/* Japanese syntax */
-static int vm_intro_ja(struct ast_channel *chan,struct vm_state *vms)
-{
-      /* Introduce messages they have */
-      int res;
-      if (vms->newmessages) {
-              res = ast_play_and_wait(chan, "vm-INBOX");
-              if (!res)
-                      res = ast_play_and_wait(chan, "vm-message");
-              if (!res)
-                      res = ast_play_and_wait(chan, "jp-ga");
-              if (!res)
-                      res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
-              if (vms->oldmessages && !res)
-                      res = ast_play_and_wait(chan, "silence/1");
-
-      }
-      if (vms->oldmessages) {
-              res = ast_play_and_wait(chan, "vm-Old");
-              if (!res)
-                      res = ast_play_and_wait(chan, "vm-message");
-              if (!res)
-                      res = ast_play_and_wait(chan, "jp-ga");
-              if (!res)
-                      res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
-      }
-      if (!vms->oldmessages && !vms->newmessages) {
-              res = ast_play_and_wait(chan, "vm-messages");
-              if (!res)
-                      res = ast_play_and_wait(chan, "jp-wa");
-              if (!res)
-                      res = ast_play_and_wait(chan, "jp-arimasen");
-      }
-      else {
-              res = ast_play_and_wait(chan, "jp-arimasu");
-      }
-      return res;
-} /* Japanese */
 	
 /* Default English syntax */
 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
@@ -9315,7 +9174,7 @@ static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
 			if ((vms->oldmessages || vms->newmessages) && !res) {
 				res = ast_play_and_wait(chan, "vm-and");
 			} else if (!res) {
-				if ((vms->urgentmessages == 1))
+				if (vms->urgentmessages == 1)
 					res = ast_play_and_wait(chan, "vm-message");
 				else
 					res = ast_play_and_wait(chan, "vm-messages");
@@ -9328,7 +9187,7 @@ static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
 			if (vms->oldmessages && !res)
 				res = ast_play_and_wait(chan, "vm-and");
 			else if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-message");
 				else
 					res = ast_play_and_wait(chan, "vm-messages");
@@ -9480,7 +9339,7 @@ static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
 	}
 
 	if (vms->newmessages) {
-		if ((vms->newmessages == 1)) {
+		if (vms->newmessages == 1) {
 			res = ast_play_and_wait(chan, "digits/ett");
 			res = res ? res : ast_play_and_wait(chan, "vm-nytt");
 			res = res ? res : ast_play_and_wait(chan, "vm-message");
@@ -9524,7 +9383,7 @@ static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
 	}
 
 	if (vms->newmessages) {
-		if ((vms->newmessages == 1)) {
+		if (vms->newmessages == 1) {
 			res = ast_play_and_wait(chan, "digits/1");
 			res = res ? res : ast_play_and_wait(chan, "vm-ny");
 			res = res ? res : ast_play_and_wait(chan, "vm-message");
@@ -9559,7 +9418,7 @@ static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
 	res = ast_play_and_wait(chan, "vm-youhave");
 	if (!res) {
 		if (vms->newmessages) {
-			if ((vms->newmessages == 1))
+			if (vms->newmessages == 1)
 				res = ast_play_and_wait(chan, "digits/1F");
 			else
 				res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
@@ -9568,7 +9427,7 @@ static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
 			if (vms->oldmessages && !res)
 				res = ast_play_and_wait(chan, "vm-and");
 			else if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-message");
 				else
 					res = ast_play_and_wait(chan, "vm-messages");
@@ -9615,7 +9474,7 @@ static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
 	if (!res) {
 		if (vms->newmessages) {
 			if (!res) {
-				if ((vms->newmessages == 1)) {
+				if (vms->newmessages == 1) {
 					res = ast_play_and_wait(chan, "digits/1M");
 					if (!res)
 						res = ast_play_and_wait(chan, "vm-message");
@@ -9666,7 +9525,7 @@ static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
 	if (vms->newmessages) {
 		if (!res)
 			res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
-		if ((vms->newmessages == 1)) {
+		if (vms->newmessages == 1) {
 			if (!res)
 				res = ast_play_and_wait(chan, "vm-message");
 			if (!res)
@@ -9712,7 +9571,7 @@ static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
 			if (vms->oldmessages && !res)
 				res = ast_play_and_wait(chan, "vm-and");
 			else if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-message");
 				else
 					res = ast_play_and_wait(chan, "vm-messages");
@@ -9759,7 +9618,7 @@ static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
 			if (vms->oldmessages && !res)
 				res = ast_play_and_wait(chan, "vm-and");
 			else if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-message");
 				else
 					res = ast_play_and_wait(chan, "vm-messages");
@@ -9802,7 +9661,7 @@ static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
 		if (vms->newmessages) {
 			res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
 			if (!res) {
-				if ((vms->newmessages == 1)) {
+				if (vms->newmessages == 1) {
 					res = ast_play_and_wait(chan, "vm-message");
 					if (!res)
 						res = ast_play_and_wait(chan, "vm-INBOXs");
@@ -9868,7 +9727,7 @@ static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
 				res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
 			}
 			if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-novou");
 				if ((vms->newmessages) > 1 && (vms->newmessages < 5))
 					res = ast_play_and_wait(chan, "vm-nove");
@@ -9878,7 +9737,7 @@ static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
 			if (vms->oldmessages && !res)
 				res = ast_play_and_wait(chan, "vm-and");
 			else if (!res) {
-				if ((vms->newmessages == 1))
+				if (vms->newmessages == 1)
 					res = ast_play_and_wait(chan, "vm-zpravu");
 				if ((vms->newmessages) > 1 && (vms->newmessages < 5))
 					res = ast_play_and_wait(chan, "vm-zpravy");
@@ -9889,7 +9748,7 @@ static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
 		if (!res && vms->oldmessages) {
 			res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
 			if (!res) {
-				if ((vms->oldmessages == 1))
+				if (vms->oldmessages == 1)
 					res = ast_play_and_wait(chan, "vm-starou");
 				if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
 					res = ast_play_and_wait(chan, "vm-stare");
@@ -9897,7 +9756,7 @@ static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
 					res = ast_play_and_wait(chan, "vm-starych");
 			}
 			if (!res) {
-				if ((vms->oldmessages == 1))
+				if (vms->oldmessages == 1)
 					res = ast_play_and_wait(chan, "vm-zpravu");
 				if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
 					res = ast_play_and_wait(chan, "vm-zpravy");
@@ -10023,8 +9882,6 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm
 		return vm_intro_he(chan, vms);
 	} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {  /* ITALIAN syntax */
 		return vm_intro_it(chan, vms);
-	} else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {  /* JAPANESE syntax */
-		return vm_intro_ja(chan, vms);
 	} else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {  /* DUTCH syntax */
 		return vm_intro_nl(chan, vms);
 	} else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {  /* NORWEGIAN syntax */
@@ -10138,102 +9995,6 @@ static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu,
 	return res;
 }
 
-static int vm_instructions_ja(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms,  int skipadvanced, int in_urgent)
-{
-        int res = 0;
-        /* Play instructions and wait for new command */
-        while (!res) {
-                if (vms->starting) {
-                        if (vms->lastmsg > -1) {
-                                res = vm_play_folder_name(chan, vms->vmbox);
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "jp-wa");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "digits/1");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "jp-wo");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "silence/1");
-                        }
-                        if (!res)
-                                res = ast_play_and_wait(chan, "vm-opts");
-                } else {
-                        /* Added for additional help */
-                        if (skipadvanced) {
-                                res = vm_play_folder_name(chan, vms->vmbox);
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "jp-wa");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "digits/1");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "jp-wo");
-                                if (!res)
-                                        res = ast_play_and_wait(chan, "silence/1");
-                                res = ast_play_and_wait(chan, "vm-opts-full");
-                        }
-                        /* Logic:
-                         * If the current message is not the first OR
-                         * if we're listening to the first new message and there are
-                         * also urgent messages, then prompt for navigation to the
-                         * previous message
-                         */
-                        if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
-                                res = ast_play_and_wait(chan, "vm-prev");
-                        }
-                        if (!res && !skipadvanced)
-                                res = ast_play_and_wait(chan, "vm-advopts");
-                        if (!res)
-                                res = ast_play_and_wait(chan, "vm-repeat");
-                        /* Logic:
-                         * If we're not listening to the last message OR
-                         * we're listening to the last urgent message and there are
-                         * also new non-urgent messages, then prompt for navigation
-                         * to the next message
-                         */
-                        if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
-                                (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
-                                res = ast_play_and_wait(chan, "vm-next");
-                        }
-                        if (!res) {
-                                int curmsg_deleted;
-#ifdef IMAP_STORAGE
-                                ast_mutex_lock(&vms->lock);
-#endif
-                                curmsg_deleted = vms->deleted[vms->curmsg];
-#ifdef IMAP_STORAGE
-                                ast_mutex_unlock(&vms->lock);
-#endif
-                                if (!curmsg_deleted) {
-                                        res = ast_play_and_wait(chan, "vm-delete");
-                                } else {
-                                        res = ast_play_and_wait(chan, "vm-undelete");
-                                }
-                                if (!res) {
-                                        res = ast_play_and_wait(chan, "vm-toforward");
-                                }
-                                if (!res) {
-                                        res = ast_play_and_wait(chan, "vm-savemessage");
-                                }
-                        }
-                }
-
-		if (!res) {
-			res = ast_play_and_wait(chan, "vm-helpexit");
-		}
-		if (!res)
-			res = ast_waitfordigit(chan, 6000);
-		if (!res) {
-			vms->repeats++;
-			if (vms->repeats > 2) {
-				res = 't';
-			}
-		}
-
-	}
-
-        return res;
-}
-
 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms,  int skipadvanced, int in_urgent)
 {
 	int res = 0;
@@ -10260,9 +10021,7 @@ static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu,
 
 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
 {
-        if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* Japanese syntax */
-                return vm_instructions_ja(chan, vmu, vms, skipadvanced, in_urgent);
-        } else if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
+	if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) { /* CHINESE (Taiwan) syntax */
 		return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
 	} else {					/* Default to ENGLISH */
 		return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
@@ -10683,33 +10442,6 @@ static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms,
 	return cmd;
 }
 
-/*!
- * \brief Japanese syntax for 'You have N messages' greeting.
- * \param chan
- * \param vms
- * \param vmu
- *
- * \return zero on success, -1 on error.
- */
-static int vm_browse_messages_ja(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
-{
-        int cmd = 0;
-
-        if (vms->lastmsg > -1) {
-                cmd = play_message(chan, vmu, vms);
-        } else {
-                snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
-                cmd = ast_play_and_wait(chan, vms->fn);
-                if (!cmd)
-                        cmd = ast_play_and_wait(chan, "vm-messages");
-                if (!cmd)
-                        cmd = ast_play_and_wait(chan, "jp-wa");
-                if (!cmd)
-                        cmd = ast_play_and_wait(chan, "jp-arimasen");
-        }
-        return cmd;
-}
-
 /*! 
  * \brief Spanish syntax for 'You have N messages' greeting.
  * \param chan
@@ -10835,8 +10567,6 @@ static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, st
 		return vm_browse_messages_he(chan, vms, vmu);
 	} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {  /* ITALIAN */
 		return vm_browse_messages_it(chan, vms, vmu);
-        } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {  /* JAPANESE */
-                return vm_browse_messages_ja(chan, vms, vmu);
 	} else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {  /* PORTUGUESE */
 		return vm_browse_messages_pt(chan, vms, vmu);
 	} else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {  /* VIETNAMESE */
@@ -11256,6 +10986,7 @@ static int vm_execmain(struct ast_channel *chan, const char *data)
 	/* If ADSI is supported, setup login screen */
 	adsi_begin(chan, &useadsi);
 
+	ast_test_suite_assert(valid);
 	if (!valid) {
 		goto out;
 	}
@@ -11274,11 +11005,8 @@ static int vm_execmain(struct ast_channel *chan, const char *data)
 #endif
 
 	/* Set language from config to override channel language */
-	if (!ast_strlen_zero(vmu->language)) {
-		ast_channel_lock(chan);
+	if (!ast_strlen_zero(vmu->language))
 		ast_channel_language_set(chan, vmu->language);
-		ast_channel_unlock(chan);
-	}
 
 	/* Retrieve urgent, old and new message counts */
 	ast_debug(1, "Before open_mailbox\n");
@@ -11778,22 +11506,6 @@ static int vm_execmain(struct ast_channel *chan, const char *data)
 			break;
 		case '*': /* Help */
 			if (!vms.starting) {
-                                if (!strncasecmp(ast_channel_language(chan), "ja", 2)) {
-                                        cmd = vm_play_folder_name(chan, vms.vmbox);
-                                        if (!cmd)
-                                                cmd = ast_play_and_wait(chan, "jp-wa");
-                                        if (!cmd)
-                                                cmd = ast_play_and_wait(chan, "digits/1");
-                                        if (!cmd)
-                                                cmd = ast_play_and_wait(chan, "jp-wo");
-                                        if (!cmd)
-                                                cmd = ast_play_and_wait(chan, "silence/1");
-                                        if (!cmd)
-                                                cmd = ast_play_and_wait(chan, "vm-opts");
-                                        if (!cmd)
-                                                cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
-                                        break;
-                                }
 				cmd = ast_play_and_wait(chan, "vm-onefor");
 				if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
 					cmd = ast_play_and_wait(chan, "vm-for");
@@ -11847,10 +11559,16 @@ out:
 	if (valid) {
 		int new = 0, old = 0, urgent = 0;
 		snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a user has finished listening to their messages.</synopsis>
+			</managerEventInstance>
+		***/
+		ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
 		/* Urgent flag not passwd to externnotify here */
 		run_externnotify(vmu->context, vmu->mailbox, NULL);
 		ast_app_inboxcount2(ext_context, &urgent, &new, &old);
-		queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgent, new, old);
+		queue_mwi_event(ext_context, urgent, new, old);
 	}
 #ifdef IMAP_STORAGE
 	/* expunge message - use UID Expunge if supported on IMAP server*/
@@ -11959,7 +11677,7 @@ static int add_message_id(struct ast_config *msg_cfg, char *dir, int msg, char *
 		return -1;
 	}
 
-	cat = ast_category_get(msg_cfg, "message", NULL);
+	cat = ast_category_get(msg_cfg, "message");
 	if (!cat) {
 		ast_log(LOG_ERROR, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
 		ast_variables_destroy(var);
@@ -12048,7 +11766,7 @@ static int append_mailbox(const char *context, const char *box, const char *data
 		ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
 	}
 	if (stringp && (s = strsep(&stringp, ","))) {
-		vmu->email = ast_strdup(s);
+		ast_copy_string(vmu->email, s, sizeof(vmu->email));
 	}
 	if (stringp && (s = strsep(&stringp, ","))) {
 		ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
@@ -12069,7 +11787,7 @@ static int append_mailbox(const char *context, const char *box, const char *data
 	strcat(mailbox_full, context);
 
 	inboxcount2(mailbox_full, &urgent, &new, &old);
-	queue_mwi_event(NULL, mailbox_full, urgent, new, old);
+	queue_mwi_event(mailbox_full, urgent, new, old);
 
 	return 0;
 }
@@ -12331,9 +12049,7 @@ static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, ch
 {
 	struct ast_vm_user svm;
 	struct ast_vm_user *vmu = NULL;
-	char *parse;
-	char *mailbox;
-	char *context;
+	char *tmp, *mailbox, *context, *parse;
 	int res = 0;
 
 	AST_DECLARE_APP_ARGS(arg,
@@ -12352,13 +12068,19 @@ static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, ch
 	parse = ast_strdupa(args);
 	AST_STANDARD_APP_ARGS(arg, parse);
 
-	if (ast_strlen_zero(arg.mailbox_context)
-		|| ast_strlen_zero(arg.attribute)
-		|| separate_mailbox(ast_strdupa(arg.mailbox_context), &mailbox, &context)) {
+	if (ast_strlen_zero(arg.mailbox_context) || ast_strlen_zero(arg.attribute)) {
 		ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
 		return -1;
 	}
 
+	tmp = ast_strdupa(arg.mailbox_context);
+	mailbox = strsep(&tmp, "@");
+	context = strsep(&tmp, "");
+
+	if (ast_strlen_zero(context)) {
+		 context = "default";
+	}
+
 	vmu = find_user(&svm, context, mailbox);
 
 	if (!strncasecmp(arg.attribute, "exists", 5)) {
@@ -12376,19 +12098,16 @@ static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, ch
 		} else if (!strncasecmp(arg.attribute, "pager", 5)) {
 			ast_copy_string(buf, vmu->pager, len);
 		} else if (!strncasecmp(arg.attribute, "language", 8)) {
-			ast_copy_string(buf, S_OR(vmu->language, ast_channel_language(chan)), len);
+			const char *lang = S_OR(vmu->language, chan ?
+				ast_channel_language(chan) : ast_defaultlanguage);
+			ast_copy_string(buf, lang, len);
 		} else if (!strncasecmp(arg.attribute, "locale", 6)) {
 			ast_copy_string(buf, vmu->locale, len);
 		} else if (!strncasecmp(arg.attribute, "tz", 2)) {
 			ast_copy_string(buf, vmu->zonetag, len);
 		} else if (!strncasecmp(arg.attribute, "count", 5)) {
-			char *mailbox_id;
-
-			mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
-			sprintf(mailbox_id, "%s@%s", mailbox, context);/* Safe */
-
 			/* If mbxfolder is empty messagecount will default to INBOX */
-			res = messagecount(mailbox_id, arg.folder);
+			res = messagecount(context, mailbox, arg.folder);
 			if (res < 0) {
 				ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
 				return -1;
@@ -12807,7 +12526,7 @@ static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
 		mwi_sub->old_urgent = urgent;
 		mwi_sub->old_new = new;
 		mwi_sub->old_old = old;
-		queue_mwi_event(NULL, mwi_sub->mailbox, urgent, new, old);
+		queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
 		run_externnotify(NULL, mwi_sub->mailbox, NULL);
 	}
 }
@@ -12850,28 +12569,28 @@ static void *mb_poll_thread(void *data)
 
 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
 {
-	ast_free(mwi_sub->uniqueid);
 	ast_free(mwi_sub);
 }
 
 static int handle_unsubscribe(void *datap)
 {
 	struct mwi_sub *mwi_sub;
-	char *uniqueid = datap;
-
+	uint32_t *uniqueid = datap;
+	
 	AST_RWLIST_WRLOCK(&mwi_subs);
 	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
-		if (!strcmp(mwi_sub->uniqueid, uniqueid)) {
+		if (mwi_sub->uniqueid == *uniqueid) {
 			AST_LIST_REMOVE_CURRENT(entry);
-			/* Don't break here since a duplicate uniqueid
-			 * may have been added as a result of a cache dump. */
-			mwi_sub_destroy(mwi_sub);
+			break;
 		}
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END
 	AST_RWLIST_UNLOCK(&mwi_subs);
 
-	ast_free(uniqueid);
+	if (mwi_sub)
+		mwi_sub_destroy(mwi_sub);
+
+	ast_free(uniqueid);	
 	return 0;
 }
 
@@ -12891,7 +12610,7 @@ static int handle_subscribe(void *datap)
 	if (!(mwi_sub = ast_calloc(1, len)))
 		return -1;
 
-	mwi_sub->uniqueid = ast_strdup(p->uniqueid);
+	mwi_sub->uniqueid = p->uniqueid;
 	if (!ast_strlen_zero(p->mailbox))
 		strcpy(mwi_sub->mailbox, p->mailbox);
 
@@ -12903,88 +12622,75 @@ static int handle_subscribe(void *datap)
 	AST_RWLIST_WRLOCK(&mwi_subs);
 	AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
 	AST_RWLIST_UNLOCK(&mwi_subs);
-	mwi_sub_task_dtor(p);
+	ast_free((void *) p->mailbox);
+	ast_free((void *) p->context);
+	ast_free(p);
 	poll_subscribed_mailbox(mwi_sub);
 	return 0;
 }
 
-static void mwi_unsub_event_cb(struct stasis_subscription_change *change)
+static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
 {
-	char *uniqueid = ast_strdup(change->uniqueid);
+	uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
 
 	if (!uniqueid) {
 		ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
 		return;
 	}
 
-	if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
+	if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
 		ast_free(uniqueid);
-	}
-}
-
-static void mwi_sub_event_cb(struct stasis_subscription_change *change)
-{
-	struct mwi_sub_task *mwist;
-	char *context;
-	char *mailbox;
-
-	mwist = ast_calloc(1, (sizeof(*mwist)));
-	if (!mwist) {
 		return;
 	}
 
-	if (separate_mailbox(ast_strdupa(stasis_topic_name(change->topic)), &mailbox, &context)) {
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
+		ast_free(uniqueid);
 		return;
 	}
 
-	mwist->mailbox = ast_strdup(mailbox);
-	mwist->context = ast_strdup(context);
-	mwist->uniqueid = ast_strdup(change->uniqueid);
-
-	if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
-		mwi_sub_task_dtor(mwist);
+	u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+	*uniqueid = u;
+	if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
+		ast_free(uniqueid);
 	}
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
 {
-	struct stasis_subscription_change *change;
-	/* Only looking for subscription change notices here */
-	if (stasis_message_type(msg) != stasis_subscription_change_type()) {
+	struct mwi_sub_task *mwist;
+	
+	if (ast_event_get_type(event) != AST_EVENT_SUB)
 		return;
-	}
 
-	change = stasis_message_data(msg);
-	if (change->topic == ast_mwi_topic_all()) {
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
 		return;
-	}
 
-	if (!strcmp(change->description, "Subscribe")) {
-		mwi_sub_event_cb(change);
-	} else if (!strcmp(change->description, "Unsubscribe")) {
-		mwi_unsub_event_cb(change);
+	if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
+		ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
+		return;
+	}
+	mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
+	mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
+	mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+	
+	if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
+		ast_free(mwist);
 	}
-}
-
-static int dump_cache(void *obj, void *arg, int flags)
-{
-	struct stasis_message *msg = obj;
-	mwi_event_cb(NULL, NULL, msg);
-	return 0;
 }
 
 static void start_poll_thread(void)
 {
 	int errcode;
-	mwi_sub_sub = stasis_subscribe(ast_mwi_topic_all(), mwi_event_cb, NULL);
+	mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+		AST_EVENT_IE_END);
 
-	if (mwi_sub_sub) {
-		struct ao2_container *cached = stasis_cache_dump(ast_mwi_state_cache(), stasis_subscription_change_type());
-		if (cached) {
-			ao2_callback(cached, OBJ_MULTIPLE | OBJ_NODATA, dump_cache, NULL);
-		}
-		ao2_cleanup(cached);
-	}
+	mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+		AST_EVENT_IE_END);
+
+	if (mwi_sub_sub)
+		ast_event_report_subs(mwi_sub_sub);
 
 	poll_thread_run = 1;
 
@@ -12997,7 +12703,15 @@ static void stop_poll_thread(void)
 {
 	poll_thread_run = 0;
 
-	mwi_sub_sub = stasis_unsubscribe_and_join(mwi_sub_sub);
+	if (mwi_sub_sub) {
+		ast_event_unsubscribe(mwi_sub_sub);
+		mwi_sub_sub = NULL;
+	}
+
+	if (mwi_unsub_sub) {
+		ast_event_unsubscribe(mwi_unsub_sub);
+		mwi_unsub_sub = NULL;
+	}
 
 	ast_mutex_lock(&poll_lock);
 	ast_cond_signal(&poll_cond);
@@ -13008,42 +12722,6 @@ static void stop_poll_thread(void)
 	poll_thread = AST_PTHREADT_NULL;
 }
 
-static int manager_voicemail_refresh(struct mansession *s, const struct message *m)
-{
-	const char *context = astman_get_header(m, "Context");
-	const char *mailbox = astman_get_header(m, "Mailbox");
-	struct mwi_sub *mwi_sub;
-	const char *at;
-
-	AST_RWLIST_RDLOCK(&mwi_subs);
-	AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
-		if (!ast_strlen_zero(mwi_sub->mailbox)) {
-			if (
-				/* First case: everything matches */
-				(ast_strlen_zero(context) && ast_strlen_zero(mailbox)) ||
-				/* Second case: match the mailbox only */
-				(ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
-					(at = strchr(mwi_sub->mailbox, '@')) &&
-					strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox) == 0) ||
-				/* Third case: match the context only */
-				(!ast_strlen_zero(context) && ast_strlen_zero(mailbox) &&
-					(at = strchr(mwi_sub->mailbox, '@')) &&
-					strcmp(context, at + 1) == 0) ||
-				/* Final case: match an exact specified mailbox */
-				(!ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
-					(at = strchr(mwi_sub->mailbox, '@')) &&
-					strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox) == 0 &&
-					strcmp(context, at + 1) == 0)
-			) {
-				poll_subscribed_mailbox(mwi_sub);
-			}
-		}
-	}
-	AST_RWLIST_UNLOCK(&mwi_subs);
-	astman_send_ack(s, m, "Refresh sent");
-	return RESULT_SUCCESS;
-}
-
 /*! \brief Manager list voicemail users command */
 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
 {
@@ -13951,29 +13629,6 @@ static int sayname(struct ast_channel *chan, const char *mailbox, const char *co
 	return res;
 }
 
-/*!
- * \internal
- * \brief Play a recorded user name for the mailbox to the specified channel.
- *
- * \param chan Where to play the recorded name file.
- * \param mailbox_id The mailbox name.
- *
- * \retval 0 Name played without interruption
- * \retval dtmf ASCII value of the DTMF which interrupted playback.
- * \retval -1 Unable to locate mailbox or hangup occurred.
- */
-static int vm_sayname(struct ast_channel *chan, const char *mailbox_id)
-{
-	char *context;
-	char *mailbox;
-
-	if (ast_strlen_zero(mailbox_id)
-		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
-		return -1;
-	}
-	return sayname(chan, mailbox, context);
-}
-
 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
 	struct ast_config *pwconf;
 	struct ast_flags config_flags = { 0 };
@@ -14027,20 +13682,26 @@ static int write_password_to_file(const char *secretfn, const char *password) {
 static int vmsayname_exec(struct ast_channel *chan, const char *data)
 {
 	char *context;
-	char *mailbox;
+	char *args_copy;
 	int res;
 
-	if (ast_strlen_zero(data)
-		|| separate_mailbox(ast_strdupa(data), &mailbox, &context)) {
+	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "VMSayName requires argument mailbox at context\n");
 		return -1;
 	}
 
-	if ((res = sayname(chan, mailbox, context)) < 0) {
-		ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", mailbox, context);
+	args_copy = ast_strdupa(data);
+	if ((context = strchr(args_copy, '@'))) {
+		*context++ = '\0';
+	} else {
+		context = "default";
+	}
+
+	if ((res = sayname(chan, args_copy, context)) < 0) {
+		ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
 		res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
 		if (!res) {
-			res = ast_say_character_str(chan, mailbox, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE);
+			res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan));
 		}
 	}
 
@@ -14067,7 +13728,7 @@ AST_TEST_DEFINE(test_voicemail_vmsayname)
 
 	struct ast_channel *test_channel1 = NULL;
 	int res = -1;
-	struct ast_format_cap *capabilities;
+	struct ast_format_cap *nativeformats;
 
 	static const struct ast_channel_tech fake_tech = {
 		.write = fake_write,
@@ -14086,27 +13747,20 @@ AST_TEST_DEFINE(test_voicemail_vmsayname)
 		break;
 	}
 
-	if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL,
+	if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
         NULL, NULL, 0, 0, "TestChannel1"))) {
 		goto exit_vmsayname_test;
 	}
 
 	/* normally this is done in the channel driver */
-	capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!capabilities) {
-		goto exit_vmsayname_test;
-	}
-	ast_format_cap_append(capabilities, ast_format_gsm, 0);
-	ast_channel_nativeformats_set(test_channel1, capabilities);
-	ao2_ref(capabilities, -1);
-	ast_channel_set_writeformat(test_channel1, ast_format_gsm);
-	ast_channel_set_rawwriteformat(test_channel1, ast_format_gsm);
-	ast_channel_set_readformat(test_channel1, ast_format_gsm);
-	ast_channel_set_rawreadformat(test_channel1, ast_format_gsm);
+	ast_format_set(ast_channel_writeformat(test_channel1), AST_FORMAT_GSM, 0);
+	nativeformats = ast_channel_nativeformats(test_channel1);
+	ast_format_cap_add(nativeformats, ast_channel_writeformat(test_channel1));
+	ast_format_set(ast_channel_rawwriteformat(test_channel1), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_readformat(test_channel1), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_rawreadformat(test_channel1), AST_FORMAT_GSM, 0);
 	ast_channel_tech_set(test_channel1, &fake_tech);
 
-	ast_channel_unlock(test_channel1);
-
 	ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
 	snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT); /* not a dir, don't get confused */
 	if (!(res = vmsayname_exec(test_channel1, dir))) {
@@ -14143,7 +13797,9 @@ AST_TEST_DEFINE(test_voicemail_vmsayname)
 
 exit_vmsayname_test:
 
-	ast_hangup(test_channel1);
+	if (test_channel1) {
+		ast_hangup(test_channel1);
+	}
 
 	return res ? AST_TEST_FAIL : AST_TEST_PASS;
 }
@@ -14283,9 +13939,9 @@ AST_TEST_DEFINE(test_voicemail_msgcount)
 
 		new = old = urgent = 0;
 		for (j = 0; j < 3; j++) {
-			if (ast_app_messagecount(testspec, folders[j]) != expected_results[i][9 + j]) {
+			if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
 				ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
-					testspec, folders[j], ast_app_messagecount(testspec, folders[j]), expected_results[i][9 + j]);
+					testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
 				res = AST_TEST_FAIL;
 			}
 		}
@@ -14379,7 +14035,7 @@ AST_TEST_DEFINE(test_voicemail_notify_endl)
 	}
 
 	populate_defaults(vmu);
-	vmu->email = ast_strdup("test2 at example.net");
+	ast_copy_string(vmu->email, "test2 at example.net", sizeof(vmu->email));
 #ifdef IMAP_STORAGE
 	/* TODO When we set up the IMAP server test, we'll need to have credentials for the VMU structure added here */
 #endif
@@ -14562,7 +14218,7 @@ AST_TEST_DEFINE(test_voicemail_vm_info)
 
 	populate_defaults(vmu);
 
-	vmu->email = ast_strdup("vm-info-test at example.net");
+	ast_copy_string(vmu->email, "vm-info-test at example.net", sizeof(vmu->email));
 	ast_copy_string(vmu->fullname, "Test Framework Mailbox", sizeof(vmu->fullname));
 	ast_copy_string(vmu->pager, "vm-info-pager-test at example.net", sizeof(vmu->pager));
 	ast_copy_string(vmu->language, "en", sizeof(vmu->language));
@@ -14588,31 +14244,6 @@ AST_TEST_DEFINE(test_voicemail_vm_info)
 }
 #endif /* defined(TEST_FRAMEWORK) */
 
-static const struct ast_vm_functions vm_table = {
-	.module_version = VM_MODULE_VERSION,
-	.module_name = AST_MODULE,
-
-	.has_voicemail = has_voicemail,
-	.inboxcount = inboxcount,
-	.inboxcount2 = inboxcount2,
-	.messagecount = messagecount,
-	.copy_recording_to_vm = msg_create_from_file,
-	.index_to_foldername = vm_index_to_foldername,
-	.mailbox_snapshot_create = vm_mailbox_snapshot_create,
-	.mailbox_snapshot_destroy = vm_mailbox_snapshot_destroy,
-	.msg_move = vm_msg_move,
-	.msg_remove = vm_msg_remove,
-	.msg_forward = vm_msg_forward,
-	.msg_play = vm_msg_play,
-};
-
-static const struct ast_vm_greeter_functions vm_greeter_table = {
-	.module_version = VM_GREETER_MODULE_VERSION,
-	.module_name = AST_MODULE,
-
-	.sayname = vm_sayname,
-};
-
 static int reload(void)
 {
 	return load_config(1);
@@ -14631,7 +14262,6 @@ static int unload_module(void)
 	res |= ast_custom_function_unregister(&mailbox_exists_acf);
 	res |= ast_custom_function_unregister(&vm_info_acf);
 	res |= ast_manager_unregister("VoicemailUsersList");
-	res |= ast_manager_unregister("VoicemailRefresh");
 	res |= ast_data_unregister(NULL);
 #ifdef TEST_FRAMEWORK
 	res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
@@ -14642,8 +14272,7 @@ static int unload_module(void)
 	res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
 #endif
 	ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
-	ast_vm_unregister(vm_table.module_name);
-	ast_vm_greeter_unregister(vm_greeter_table.module_name);
+	ast_uninstall_vm_functions();
 #ifdef TEST_FRAMEWORK
 	ast_uninstall_vm_test_functions();
 #endif
@@ -14661,16 +14290,6 @@ static int unload_module(void)
 	return res;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res;
@@ -14700,7 +14319,6 @@ static int load_module(void)
 	res |= ast_custom_function_register(&mailbox_exists_acf);
 	res |= ast_custom_function_register(&vm_info_acf);
 	res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
-	res |= ast_manager_register_xml("VoicemailRefresh", EVENT_FLAG_USER, manager_voicemail_refresh);
 #ifdef TEST_FRAMEWORK
 	res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
 	res |= AST_TEST_REGISTER(test_voicemail_msgcount);
@@ -14710,15 +14328,17 @@ static int load_module(void)
 	res |= AST_TEST_REGISTER(test_voicemail_vm_info);
 #endif
 
-	res |= ast_vm_register(&vm_table);
-	res |= ast_vm_greeter_register(&vm_greeter_table);
-	if (res) {
+	if (res)
 		return res;
-	}
 
 	ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
 	ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
 
+	ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname, msg_create_from_file,
+				 vm_index_to_foldername,
+				 vm_mailbox_snapshot_create, vm_mailbox_snapshot_destroy,
+				 vm_msg_move, vm_msg_remove, vm_msg_forward, vm_msg_play);
+
 #ifdef TEST_FRAMEWORK
 	ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
 #endif
@@ -15070,7 +14690,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
 			if (ast_test_flag(vmu, VM_OPERATOR))
 				canceldtmf = "0";
-			cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
+			cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
 			if (strchr(canceldtmf, cmd)) {
 			/* need this flag here to distinguish between pressing '0' during message recording or after */
 				canceleddtmf = 1;
@@ -15176,6 +14796,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
 				} else {
 					ast_play_and_wait(chan, "vm-deleted");
 					DELETE(tempfile, -1, tempfile, vmu);
+					DISPOSE(tempfile, -1);
 					cmd = '0';
 				}
 			}
@@ -15555,7 +15176,6 @@ static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm
  * \param msg_ids An array of message identifiers
  * \param num_msgs The number of identifiers in msg_ids
  * \param msg_nums [out] The message indexes corresponding to the given
- * \param vmu
  * message IDs
  * \pre vms must have open_mailbox() called on it prior to this function.
  *
@@ -15619,7 +15239,7 @@ static void notify_new_state(struct ast_vm_user *vmu)
 	snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
 	run_externnotify(vmu->context, vmu->mailbox, NULL);
 	ast_app_inboxcount2(ext_context, &urgent, &new, &old);
-	queue_mwi_event(NULL, ext_context, urgent, new, old);
+	queue_mwi_event(ext_context, urgent, new, old);
 }
 
 static int vm_msg_forward(const char *from_mailbox,
@@ -16080,7 +15700,6 @@ play2_msg_cleanup:
  */
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/apps/app_waitforring.c b/apps/app_waitforring.c
index de4114a..fc02de3 100644
--- a/apps/app_waitforring.c
+++ b/apps/app_waitforring.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -140,5 +140,4 @@ static int load_module(void)
 	return ast_register_application_xml(app, waitforring_exec);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Waits until first ring after time");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Waits until first ring after time");
diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c
index e96be99..f792472 100644
--- a/apps/app_waitforsilence.c
+++ b/apps/app_waitforsilence.c
@@ -44,14 +44,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/dsp.h"
 #include "asterisk/module.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="WaitForSilence" language="en_US">
@@ -130,7 +129,7 @@ static char *app_noise = "WaitForNoise";
 static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) {
 	struct ast_frame *f = NULL;
 	int dsptime = 0;
-	RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
+	struct ast_format rfmt;
 	int res = 0;
 	struct ast_dsp *sildet;	 /* silence detector dsp */
  	time_t now;
@@ -139,8 +138,8 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart,
 	int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) =
 				wait_for_silence ? ast_dsp_silence : ast_dsp_noise;
 
-	rfmt = ao2_bump(ast_channel_readformat(chan));
-	if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) {
+	ast_format_copy(&rfmt, ast_channel_readformat(chan)); /* Set to linear mode */
+	if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) {
 		ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n");
 		return -1;
 	}
@@ -180,7 +179,7 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart,
 			ast_frfree(f);
 		}
 
-		ast_debug(1, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);
+		ast_verb(6, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);
 
 		if (dsptime >= timereqd) {
 			ast_verb(3, "Exiting with %dms %s >= %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);
@@ -200,8 +199,8 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart,
 	}
 
 
-	if (rfmt && ast_set_read_format(chan, rfmt)) {
-		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan));
+	if (rfmt.id && ast_set_read_format(chan, &rfmt)) {
+		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), ast_channel_name(chan));
 	}
 	ast_dsp_free(sildet);
 	return res;
@@ -274,6 +273,5 @@ static int load_module(void)
 	return res;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Wait For Silence");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Wait For Silence");
 
diff --git a/apps/app_waituntil.c b/apps/app_waituntil.c
index 49c29a0..d1f4bb1 100644
--- a/apps/app_waituntil.c
+++ b/apps/app_waituntil.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389247 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
diff --git a/apps/app_while.c b/apps/app_while.c
index 1c7e9ca..90d3d58 100644
--- a/apps/app_while.c
+++ b/apps/app_while.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370655 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
diff --git a/apps/app_zapateller.c b/apps/app_zapateller.c
index c8ca2cc..0016697 100644
--- a/apps/app_zapateller.c
+++ b/apps/app_zapateller.c
@@ -31,7 +31,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -137,5 +137,4 @@ static int load_module(void)
 	return ((ast_register_application_xml(app, zapateller_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Block Telemarketers with Special Information Tone");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Block Telemarketers with Special Information Tone");
diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c
deleted file mode 100644
index 2222624..0000000
--- a/apps/confbridge/conf_chan_announce.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief ConfBridge announcer channel driver
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410672 $")
-
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/core_unreal.h"
-#include "include/confbridge.h"
-
-/* ------------------------------------------------------------------- */
-
-/*! ConfBridge announcer channel private. */
-struct announce_pvt {
-	/*! Unreal channel driver base class values. */
-	struct ast_unreal_pvt base;
-	/*! Conference bridge associated with this announcer. */
-	struct ast_bridge *bridge;
-};
-
-static int announce_call(struct ast_channel *chan, const char *addr, int timeout)
-{
-	/* Make sure anyone calling ast_call() for this channel driver is going to fail. */
-	return -1;
-}
-
-static int announce_hangup(struct ast_channel *ast)
-{
-	struct announce_pvt *p = ast_channel_tech_pvt(ast);
-	int res;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* give the pvt a ref to fulfill calling requirements. */
-	ao2_ref(p, +1);
-	res = ast_unreal_hangup(&p->base, ast);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-static void announce_pvt_destructor(void *vdoomed)
-{
-	struct announce_pvt *doomed = vdoomed;
-
-	ao2_cleanup(doomed->bridge);
-	doomed->bridge = NULL;
-	ast_unreal_destructor(&doomed->base);
-}
-
-static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	struct ast_channel *chan;
-	const char *conf_name = data;
-	RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
-	RAII_VAR(struct announce_pvt *, pvt, NULL, ao2_cleanup);
-
-	conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
-	if (!conference) {
-		return NULL;
-	}
-	ast_assert(conference->bridge != NULL);
-
-	/* Allocate a new private structure and then Asterisk channels */
-	pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor,
-		cap);
-	if (!pvt) {
-		return NULL;
-	}
-	ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
-	ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name));
-	pvt->bridge = conference->bridge;
-	ao2_ref(pvt->bridge, +1);
-
-	chan = ast_unreal_new_channels(&pvt->base, conf_announce_get_tech(),
-		AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, NULL);
-	if (chan) {
-		ast_answer(pvt->base.owner);
-		ast_answer(pvt->base.chan);
-		if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) {
-			ast_hangup(chan);
-			chan = NULL;
-		}
-	}
-
-	return chan;
-}
-
-static struct ast_channel_tech announce_tech = {
-	.type = "CBAnn",
-	.description = "Conference Bridge Announcing Channel",
-	.requester = announce_request,
-	.call = announce_call,
-	.hangup = announce_hangup,
-
-	.send_digit_begin = ast_unreal_digit_begin,
-	.send_digit_end = ast_unreal_digit_end,
-	.read = ast_unreal_read,
-	.write = ast_unreal_write,
-	.write_video = ast_unreal_write,
-	.exception = ast_unreal_read,
-	.indicate = ast_unreal_indicate,
-	.fixup = ast_unreal_fixup,
-	.send_html = ast_unreal_sendhtml,
-	.send_text = ast_unreal_sendtext,
-	.queryoption = ast_unreal_queryoption,
-	.setoption = ast_unreal_setoption,
-	.properties = AST_CHAN_TP_INTERNAL,
-};
-
-struct ast_channel_tech *conf_announce_get_tech(void)
-{
-	return &announce_tech;
-}
-
-void conf_announce_channel_depart(struct ast_channel *chan)
-{
-	struct announce_pvt *p = ast_channel_tech_pvt(chan);
-
-	if (!p) {
-		return;
-	}
-
-	ao2_ref(p, +1);
-	ao2_lock(p);
-	if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) {
-		ao2_unlock(p);
-		ao2_ref(p, -1);
-		return;
-	}
-	ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
-	chan = p->base.chan;
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-	if (chan) {
-		ast_bridge_depart(chan);
-		ast_channel_unref(chan);
-	}
-}
-
-int conf_announce_channel_push(struct ast_channel *ast)
-{
-	struct ast_bridge_features *features;
-	struct ast_channel *chan;
-	RAII_VAR(struct announce_pvt *, p, NULL, ao2_cleanup);
-
-	{
-		SCOPED_CHANNELLOCK(lock, ast);
-
-		p = ast_channel_tech_pvt(ast);
-		if (!p) {
-			return -1;
-		}
-		ao2_ref(p, +1);
-		chan = p->base.chan;
-		if (!chan) {
-			return -1;
-		}
-		ast_channel_ref(chan);
-	}
-
-	features = ast_bridge_features_new();
-	if (!features) {
-		ast_channel_unref(chan);
-		return -1;
-	}
-	ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
-
-	/* Impart the output channel into the bridge */
-	if (ast_bridge_impart(p->bridge, chan, NULL, features,
-		AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
-		ast_bridge_features_destroy(features);
-		ast_channel_unref(chan);
-		return -1;
-	}
-	ao2_lock(p);
-	ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
-	ao2_unlock(p);
-	return 0;
-}
diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c
deleted file mode 100644
index 90c0966..0000000
--- a/apps/confbridge/conf_chan_record.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief ConfBridge recorder channel driver
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/format_cache.h"
-#include "include/confbridge.h"
-
-/* ------------------------------------------------------------------- */
-
-static int rec_call(struct ast_channel *chan, const char *addr, int timeout)
-{
-	/* Make sure anyone calling ast_call() for this channel driver is going to fail. */
-	return -1;
-}
-
-static struct ast_frame *rec_read(struct ast_channel *ast)
-{
-	return &ast_null_frame;
-}
-
-static int rec_write(struct ast_channel *ast, struct ast_frame *f)
-{
-	return 0;
-}
-
-static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	struct ast_channel *chan;
-	const char *conf_name = data;
-	RAII_VAR(struct ast_format_cap *, capabilities, NULL, ao2_cleanup);
-
-	capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!capabilities) {
-		return NULL;
-	}
-	ast_format_cap_append_by_type(capabilities, AST_MEDIA_TYPE_UNKNOWN);
-
-	chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0,
-		"CBRec/conf-%s-uid-%d",
-		conf_name, (int) ast_random());
-	if (!chan) {
-		return NULL;
-	}
-	if (ast_channel_add_bridge_role(chan, "recorder")) {
-		ast_channel_unlock(chan);
-		ast_channel_release(chan);
-		return NULL;
-	}
-
-	ast_channel_tech_set(chan, conf_record_get_tech());
-	ast_channel_nativeformats_set(chan, capabilities);
-	ast_channel_set_writeformat(chan, ast_format_slin);
-	ast_channel_set_rawwriteformat(chan, ast_format_slin);
-	ast_channel_set_readformat(chan, ast_format_slin);
-	ast_channel_set_rawreadformat(chan, ast_format_slin);
-	ast_channel_unlock(chan);
-	return chan;
-}
-
-static struct ast_channel_tech record_tech = {
-	.type = "CBRec",
-	.description = "Conference Bridge Recording Channel",
-	.requester = rec_request,
-	.call = rec_call,
-	.read = rec_read,
-	.write = rec_write,
-	.properties = AST_CHAN_TP_INTERNAL,
-};
-
-struct ast_channel_tech *conf_record_get_tech(void)
-{
-	return &record_tech;
-}
diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c
index 7b2bfbc..98838de 100644
--- a/apps/confbridge/conf_config_parser.c
+++ b/apps/confbridge/conf_config_parser.c
@@ -29,507 +29,17 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/logger.h"
 #include "asterisk/config.h"
 #include "asterisk/config_options.h"
 #include "include/confbridge.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/cli.h"
-#include "asterisk/bridge_features.h"
+#include "asterisk/bridging_features.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/pbx.h"
 
-
-/*** DOCUMENTATION
-	<configInfo name="app_confbridge" language="en_US">
-		<synopsis>Conference Bridge Application</synopsis>
-		<configFile name="confbridge.conf">
-			<configObject name="global">
-				<synopsis>Unused, but reserved.</synopsis>
-			</configObject>
-			<configObject name="user_profile">
-				<synopsis>A named profile to apply to specific callers.</synopsis>
-				<description><para>Callers in a ConfBridge have a profile associated with them
-				that determine their options. A configuration section is determined to be a
-				user_profile when the <literal>type</literal> parameter has a value
-				of <literal>user</literal>.
-				</para></description>
-				<configOption name="type">
-					<synopsis>Define this configuration category as a user profile.</synopsis>
-					<description><para>The type parameter determines how a context in the
-					configuration file is interpreted.</para>
-					<enumlist>
-						<enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
-						<enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
-						<enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
-					</enumlist>
-					</description>
-				</configOption>
-				<configOption name="admin">
-					<synopsis>Sets if the user is an admin or not</synopsis>
-				</configOption>
-				<configOption name="marked">
-					<synopsis>Sets if this is a marked user or not</synopsis>
-				</configOption>
-				<configOption name="startmuted">
-					<synopsis>Sets if all users should start out muted</synopsis>
-				</configOption>
-				<configOption name="music_on_hold_when_empty">
-					<synopsis>Play MOH when user is alone or waiting on a marked user</synopsis>
-				</configOption>
-				<configOption name="quiet">
-					<synopsis>Silence enter/leave prompts and user intros for this user</synopsis>
-				</configOption>
-				<configOption name="announce_user_count">
-					<synopsis>Sets if the number of users should be announced to the user</synopsis>
-				</configOption>
-				<configOption name="announce_user_count_all">
-					<synopsis>Announce user count to all the other users when this user joins</synopsis>
-					<description><para>Sets if the number of users should be announced to all the other users
-					in the conference when this user joins. This option can be either set to 'yes' or
-					a number. When set to a number, the announcement will only occur once the user
-					count is above the specified number.
-					</para></description>
-				</configOption>
-				<configOption name="announce_only_user">
-					<synopsis>Announce to a user when they join an empty conference</synopsis>
-				</configOption>
-				<configOption name="wait_marked">
-					<synopsis>Sets if the user must wait for a marked user to enter before joining a conference</synopsis>
-				</configOption>
-				<configOption name="end_marked">
-					<synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
-				</configOption>
-				<configOption name="talk_detection_events">
-					<synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
-				</configOption>
-				<configOption name="dtmf_passthrough">
-					<synopsis>Sets whether or not DTMF should pass through the conference</synopsis>
-				</configOption>
-				<configOption name="announce_join_leave">
-					<synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter</synopsis>
-				</configOption>
-				<configOption name="announce_join_leave_review">
-					<synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter.
-					The user will be asked to review the recording of their name before entering the conference.</synopsis>
-				</configOption>
-				<configOption name="pin">
-					<synopsis>Sets a PIN the user must enter before joining the conference</synopsis>
-				</configOption>
-				<configOption name="music_on_hold_class">
-					<synopsis>The MOH class to use for this user</synopsis>
-				</configOption>
-				<configOption name="announcement">
-					<synopsis>Sound file to play to the user when they join a conference</synopsis>
-				</configOption>
-				<configOption name="denoise">
-					<synopsis>Apply a denoise filter to the audio before mixing</synopsis>
-					<description><para>Sets whether or not a denoise filter should be applied
-					to the audio before mixing or not.  Off by default. Requires
-					<literal>codec_speex</literal> to be built and installed.  Do not confuse this option
-					with <replaceable>drop_silence</replaceable>.  Denoise is useful if there is a lot of background
-					noise for a user as it attempts to remove the noise while preserving
-					the speech.  This option does NOT remove silence from being mixed into
-					the conference and does come at the cost of a slight performance hit.
-					</para></description>
-				</configOption>
-				<configOption name="dsp_drop_silence">
-					<synopsis>Drop what Asterisk detects as silence from audio sent to the bridge</synopsis>
-					<description><para>
-					This option drops what Asterisk detects as silence from
-					entering into the bridge.  Enabling this option will drastically
-					improve performance and help remove the buildup of background
-					noise from the conference. Highly recommended for large conferences
-					due to its performance enhancements.
-					</para></description>
-				</configOption>
-				<configOption name="dsp_silence_threshold">
-					<synopsis>The number of milliseconds of detected silence necessary to trigger silence detection</synopsis>
-					<description><para>
-					The time in milliseconds of sound falling within the what
-					the dsp has established as baseline silence before a user
-					is considered be silent.  This value affects several
-					operations and should not be changed unless the impact
-					on call quality is fully understood.</para>
-					<para>What this value affects internally:</para>
-					<para>
-						1. When talk detection AMI events are enabled, this value
-						determines when the user has stopped talking after a
-						period of talking.  If this value is set too low
-						AMI events indicating the user has stopped talking
-						may get falsely sent out when the user briefly pauses
-						during mid sentence.
-					</para>
-					<para>
-						2. The <replaceable>drop_silence</replaceable> option depends on this value to
-						determine when the user's audio should begin to be
-						dropped from the conference bridge after the user
-						stops talking.  If this value is set too low the user's
-						audio stream may sound choppy to the other participants.
-						This is caused by the user transitioning constantly from
-						silence to talking during mid sentence.
-					</para>
-					<para>
-						The best way to approach this option is to set it slightly above
-						the maximum amount of ms of silence a user may generate during
-						natural speech.
-					</para>
-					<para>By default this value is 2500ms. Valid values are 1 through 2^31.</para>
-					</description>
-				</configOption>
-				<configOption name="dsp_talking_threshold">
-					<synopsis>The number of milliseconds of detected non-silence necessary to triger talk detection</synopsis>
-					<description><para>
-						The time in milliseconds of sound above what the dsp has
-						established as base line silence for a user before a user
-						is considered to be talking.  This value affects several
-						operations and should not be changed unless the impact on
-						call quality is fully understood.</para>
-						<para>
-						What this value affects internally:
-						</para>
-						<para>
-						1. Audio is only mixed out of a user's incoming audio stream
-						if talking is detected.  If this value is set too
-						loose the user will hear themselves briefly each
-						time they begin talking until the dsp has time to
-						establish that they are in fact talking.
-						</para>
-						<para>
-						2. When talk detection AMI events are enabled, this value
-						determines when talking has begun which results in
-						an AMI event to fire.  If this value is set too tight
-						AMI events may be falsely triggered by variants in
-						room noise.
-						</para>
-						<para>
-						3. The <replaceable>drop_silence</replaceable> option depends on this value to determine
-						when the user's audio should be mixed into the bridge
-						after periods of silence.  If this value is too loose
-						the beginning of a user's speech will get cut off as they
-						transition from silence to talking.
-						</para>
-						<para>By default this value is 160 ms. Valid values are 1 through 2^31</para>
-					</description>
-				</configOption>
-				<configOption name="jitterbuffer">
-					<synopsis>Place a jitter buffer on the user's audio stream before audio mixing is performed</synopsis>
-					<description><para>
-						Enabling this option places a jitterbuffer on the user's audio stream
-						before audio mixing is performed.  This is highly recommended but will
-						add a slight delay to the audio.  This option is using the <literal>JITTERBUFFER</literal>
-						dialplan function's default adaptive jitterbuffer.  For a more fine tuned
-						jitterbuffer, disable this option and use the <literal>JITTERBUFFER</literal> dialplan function
-						on the user before entering the ConfBridge application.
-					</para></description>
-				</configOption>
-				<configOption name="template">
-					<synopsis>When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="bridge_profile">
-				<synopsis>A named profile to apply to specific bridges.</synopsis>
-				<description><para>ConfBridge bridges have a profile associated with them
-				that determine their options. A configuration section is determined to be a
-				<literal>bridge_profile</literal> when the <literal>type</literal> parameter has a value
-				of <literal>bridge</literal>.
-				</para></description>
-				<configOption name="type">
-					<synopsis>Define this configuration category as a bridge profile</synopsis>
-					<description><para>The type parameter determines how a context in the
-					configuration file is interpreted.</para>
-					<enumlist>
-						<enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
-						<enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
-						<enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
-					</enumlist>
-					</description>
-				</configOption>
-				<configOption name="jitterbuffer">
-					<synopsis>Place a jitter buffer on the conference's audio stream</synopsis>
-				</configOption>
-				<configOption name="internal_sample_rate">
-					<synopsis>Set the internal native sample rate for mixing the conference</synopsis>
-					<description><para>
-						Sets the internal native sample rate the
-						conference is mixed at.  This is set to automatically
-						adjust the sample rate to the best quality by default.
-						Other values can be anything from 8000-192000.  If a
-						sample rate is set that Asterisk does not support, the
-						closest sample rate Asterisk does support to the one requested
-						will be used.
-					</para></description>
-				</configOption>
-				<configOption name="language" default="en">
-					<synopsis>The language used for announcements to the conference.</synopsis>
-					<description><para>
-						By default, announcements to a conference use English.  Which means
-						the prompts played to all users within the conference will be
-						English.  By changing the language of a bridge, this will change
-						the language of the prompts played to all users.
-					</para></description>
-				</configOption>
-				<configOption name="mixing_interval">
-					<synopsis>Sets the internal mixing interval in milliseconds for the bridge</synopsis>
-					<description><para>
-						Sets the internal mixing interval in milliseconds for the bridge.  This
-						number reflects how tight or loose the mixing will be for the conference.
-						In order to improve performance a larger mixing interval such as 40ms may
-						be chosen.  Using a larger mixing interval comes at the cost of introducing
-						larger amounts of delay into the bridge.  Valid values here are 10, 20, 40,
-						or 80.
-					</para></description>
-				</configOption>
-				<configOption name="record_conference">
-					<synopsis>Record the conference starting with the first active user's entrance and ending with the last active user's exit</synopsis>
-					<description><para>
-						Records the conference call starting when the first user
-						enters the room, and ending when the last user exits the room.
-						The default recorded filename is
-						<filename>'confbridge-${name of conference bridge}-${start time}.wav'</filename>
-						and the default format is 8khz slinear.  This file will be
-						located in the configured monitoring directory in <filename>asterisk.conf</filename>.
-					</para></description>
-				</configOption>
-				<configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
-					<synopsis>The filename of the conference recording</synopsis>
-					<description><para>
-						When <replaceable>record_conference</replaceable> is set to yes, the specific name of the
-						record file can be set using this option.  Note that since multiple
-						conferences may use the same bridge profile, this may cause issues
-						depending on the configuration.  It is recommended to only use this
-						option dynamically with the <literal>CONFBRIDGE()</literal> dialplan function. This
-						allows the record name to be specified and a unique name to be chosen.
-						By default, the record_file is stored in Asterisk's spool/monitor directory
-						with a unique filename starting with the 'confbridge' prefix.
-					</para></description>
-				</configOption>
-				<configOption name="record_file_append" default="yes">
-					<synopsis>Append record file when starting/stopping on same conference recording</synopsis>
-					<description><para>
-						When <replaceable>record_file_append</replaceable> is set to yes, stopping and starting recording on a
-						conference adds the new portion to end of current record_file. When this is
-						set to no, a new <replaceable>record_file</replaceable> is generated every time you start then stop recording
-						on a conference.
-					</para></description>
-				</configOption>
-				<configOption name="video_mode">
-					<synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis>
-					<description><para>
-						Sets how confbridge handles video distribution to the conference participants.
-						Note that participants wanting to view and be the source of a video feed
-						<emphasis>MUST</emphasis> be sharing the same video codec.  Also, using video in conjunction with
-						with the jitterbuffer currently results in the audio being slightly out of sync
-						with the video.  This is a result of the jitterbuffer only working on the audio
-						stream.  It is recommended to disable the jitterbuffer when video is used.</para>
-						<enumlist>
-							<enum name="none">
-								<para>No video sources are set by default in the conference. It is still
-								possible for a user to be set as a video source via AMI or DTMF action
-								at any time.</para>
-							</enum>
-							<enum name="follow_talker">
-								<para>The video feed will follow whoever is talking and providing video.</para>
-							</enum>
-							<enum name="last_marked">
-								<para>The last marked user to join the conference with video capabilities
-								will be the single source of video distributed to all participants.
-								If multiple marked users are capable of video, the last one to join
-								is always the source, when that user leaves it goes to the one who
-								joined before them.</para>
-							</enum>
-							<enum name="first_marked">
-								<para>The first marked user to join the conference with video capabilities
-								is the single source of video distribution among all participants. If
-								that user leaves, the marked user to join after them becomes the source.</para>
-							</enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="max_members">
-					<synopsis>Limit the maximum number of participants for a single conference</synopsis>
-					<description><para>
-						This option limits the number of participants for a single
-						conference to a specific number.  By default conferences
-						have no participant limit. After the limit is reached, the
-						conference will be locked until someone leaves.  Note however
-						that an Admin user will always be alowed to join the conference
-						regardless if this limit is reached or not.
-					</para></description>
-				</configOption>
-				<configOption name="^sound_">
-					<synopsis>Override the various conference bridge sound files</synopsis>
-					<description><para>
-						All sounds in the conference are customizable using the bridge profile options below.
-						Simply state the option followed by the filename or full path of the filename after
-						the option.  Example: <literal>sound_had_joined=conf-hasjoin</literal>  This will play the <literal>conf-hasjoin</literal>
-						sound file found in the sounds directory when announcing someone's name is joining the
-						conference.</para>
-						<enumlist>
-							<enum name="sound_join"><para>The sound played to everyone when someone enters the conference.</para></enum>
-							<enum name="sound_leave"><para>The sound played to everyone when someone leaves the conference.</para></enum>
-							<enum name="sound_has_joined"><para>The sound played before announcing someone's name has
-										joined the conference. This is used for user intros.
-										Example <literal>"_____ has joined the conference"</literal></para></enum>
-							<enum name="sound_has_left"><para>The sound played when announcing someone's name has
-										left the conference. This is used for user intros.
-										Example <literal>"_____ has left the conference"</literal></para></enum>
-							<enum name="sound_kicked"><para>The sound played to a user who has been kicked from the conference.</para></enum>
-							<enum name="sound_muted"><para>The sound played when the mute option it toggled on.</para></enum>
-							<enum name="sound_unmuted"><para>The sound played when the mute option it toggled off.</para></enum>
-							<enum name="sound_only_person"><para>The sound played when the user is the only person in the conference.</para></enum>
-							<enum name="sound_only_one"><para>The sound played to a user when there is only one other
-										person is in the conference.</para></enum>
-							<enum name="sound_there_are"><para>The sound played when announcing how many users there
-										are in a conference.</para></enum>
-							<enum name="sound_other_in_party"><para>This file is used in conjunction with <literal>sound_there_are</literal>
-										when announcing how many users there are in the conference.
-										The sounds are stringed together like this.
-										<literal>"sound_there_are" ${number of participants} "sound_other_in_party"</literal></para></enum>
-							<enum name="sound_place_into_conference"><para>The sound played when someone is placed into the conference
-										after waiting for a marked user.</para></enum>
-							<enum name="sound_wait_for_leader"><para>The sound played when a user is placed into a conference that
-										can not start until a marked user enters.</para></enum>
-							<enum name="sound_leader_has_left"><para>The sound played when the last marked user leaves the conference.</para></enum>
-							<enum name="sound_get_pin"><para>The sound played when prompting for a conference pin number.</para></enum>
-							<enum name="sound_invalid_pin"><para>The sound played when an invalid pin is entered too many times.</para></enum>
-							<enum name="sound_locked"><para>The sound played to a user trying to join a locked conference.</para></enum>
-							<enum name="sound_locked_now"><para>The sound played to an admin after toggling the conference to locked mode.</para></enum>
-							<enum name="sound_unlocked_now"><para>The sound played to an admin after toggling the conference to unlocked mode.</para></enum>
-							<enum name="sound_error_menu"><para>The sound played when an invalid menu option is entered.</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="template">
-					<synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="menu">
-				<synopsis>A conference user menu</synopsis>
-				<description>
-					<para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
-					can have a DTMF menu assigned to their profile when they enter the
-					<literal>ConfBridge</literal> application.</para>
-				</description>
-				<configOption name="type">
-					<synopsis>Define this configuration category as a menu</synopsis>
-					<description><para>The type parameter determines how a context in the
-					configuration file is interpreted.</para>
-					<enumlist>
-						<enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
-						<enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
-						<enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
-					</enumlist>
-					</description>
-				</configOption>
-				<configOption name="template">
-					<synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
-				</configOption>
-				<configOption name="^[0-9A-D*#]+$">
-					<synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
-					<description>
-					<para>The ConfBridge application also has the ability to apply custom DTMF menus to
-					each channel using the application.  Like the User and Bridge profiles a menu
-					is passed in to ConfBridge as an argument in the dialplan.</para>
-					<para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
-					<note><para>
-						To have the first DTMF digit in a sequence be the '#' character, you need to
-						escape it.  If it is not escaped then normal config file processing will
-						think it is a directive like #include.  For example: The mute setting is
-						toggled when <literal>#1</literal> is pressed.</para>
-						<para><literal>\#1=toggle_mute</literal></para>
-					</note>
-					<note><para>
-					A single DTMF sequence can have multiple actions associated with it. This is
-					accomplished by stringing the actions together and using a <literal>,</literal> as the
-					delimiter.  Example:  Both listening and talking volume is reset when <literal>5</literal> is
-					pressed.  <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
-					<enumlist>
-						<enum name="playback(filename&filename2&...)"><para>
-							<literal>playback</literal> will play back an audio file to a channel
-							and then immediately return to the conference.
-							This file can not be interupted by DTMF.
-							Multiple files can be chained together using the
-							<literal>&</literal> character.</para></enum>
-						<enum name="playback_and_continue(filename&filename2&...)"><para>
-							<literal>playback_and_continue</literal> will
-							play back a prompt while continuing to
-							collect the dtmf sequence.  This is useful
-							when using a menu prompt that describes all
-							the menu options.  Note however that any DTMF
-							during this action will terminate the prompts
-							playback.  Prompt files can be chained together
-							using the <literal>&</literal> character as a delimiter.</para></enum>
-						<enum name="toggle_mute"><para>
-							Toggle turning on and off mute.  Mute will make the user silent
-							to everyone else, but the user will still be able to listen in.
-							</para></enum>
-						<enum name="no_op"><para>
-							This action does nothing (No Operation). Its only real purpose exists for
-							being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
-						<enum name="decrease_listening_volume"><para>
-							Decreases the channel's listening volume.</para></enum>
-						<enum name="increase_listening_volume"><para>
-							Increases the channel's listening volume.</para></enum>
-						<enum name="reset_listening_volume"><para>
-							Reset channel's listening volume to default level.</para></enum>
-						<enum name="decrease_talking_volume"><para>
-							Decreases the channel's talking volume.</para></enum>
-						<enum name="increase_talking_volume"><para>
-							Increases the channel's talking volume.</para></enum>
-						<enum name="reset_talking_volume"><para>
-							Reset channel's talking volume to default level.</para></enum>
-						<enum name="dialplan_exec(context,exten,priority)"><para>
-							The <literal>dialplan_exec</literal> action allows a user
-							to escape from the conference and execute
-							commands in the dialplan.  Once the dialplan
-							exits the user will be put back into the
-							conference.  The possibilities are endless!</para></enum>
-						<enum name="leave_conference"><para>
-							This action allows a user to exit the conference and continue
-							execution in the dialplan.</para></enum>
-						<enum name="admin_kick_last"><para>
-							This action allows an Admin to kick the last participant from the
-							conference. This action will only work for admins which allows
-							a single menu to be used for both users and admins.</para></enum>
-						<enum name="admin_toggle_conference_lock"><para>
-							This action allows an Admin to toggle locking and
-							unlocking the conference.  Non admins can not use
-							this action even if it is in their menu.</para></enum>
-						<enum name="set_as_single_video_src"><para>
-							This action allows any user to set themselves as the
-							single video source distributed to all participants.
-							This will make the video feed stick to them regardless
-							of what the <literal>video_mode</literal> is set to.</para></enum>
-						<enum name="release_as_single_video_src"><para>
-							This action allows a user to release themselves as
-							the video source.  If <literal>video_mode</literal> is not set to <literal>none</literal>
-							this action will result in the conference returning to
-							whatever video mode the bridge profile is using.</para>
-							<para>Note that this action will have no effect if the user
-							is not currently the video source.  Also, the user is
-							not guaranteed by using this action that they will not
-							become the video source again.  The bridge will return
-							to whatever operation the <literal>video_mode</literal> option is set to
-							upon release of the video src.</para></enum>
-						<enum name="admin_toggle_mute_participants"><para>
-							This action allows an administrator to toggle the mute
-							state for all non-admins within a conference.  All
-							admin users are unaffected by this option.  Note that all
-							users, regardless of their admin status, are notified
-							that the conference is muted.</para></enum>
-						<enum name="participant_count"><para>
-							This action plays back the number of participants currently
-							in a conference</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
 struct confbridge_cfg {
 	struct ao2_container *bridge_profiles;
 	struct ao2_container *user_profiles;
@@ -572,7 +82,6 @@ static void *bridge_profile_find(struct ao2_container *container, const char *ca
 
 static struct aco_type bridge_type = {
 	.type = ACO_ITEM,
-	.name = "bridge_profile",
 	.category_match = ACO_BLACKLIST,
 	.category = "^general$",
 	.matchfield = "type",
@@ -609,7 +118,6 @@ static void *user_profile_find(struct ao2_container *container, const char *cate
 
 static struct aco_type user_type = {
 	.type = ACO_ITEM,
-	.name  = "user_profile",
 	.category_match = ACO_BLACKLIST,
 	.category = "^general$",
 	.matchfield = "type",
@@ -640,7 +148,6 @@ static void *menu_find(struct ao2_container *container, const char *category)
 
 static struct aco_type menu_type = {
 	.type = ACO_ITEM,
-	.name = "menu",
 	.category_match = ACO_BLACKLIST,
 	.category = "^general$",
 	.matchfield = "type",
@@ -658,7 +165,6 @@ static struct aco_type *user_types[] = ACO_TYPES(&user_type);
 /* The general category is reserved, but unused */
 static struct aco_type general_type = {
 	.type = ACO_GLOBAL,
-	.name = "global",
 	.category_match = ACO_WHITELIST,
 	.category = "^general$",
 };
@@ -680,95 +186,32 @@ CONFIG_INFO_STANDARD(cfg_info, cfg_handle, confbridge_cfg_alloc,
 /*! bridge profile container functions */
 static int bridge_cmp_cb(void *obj, void *arg, int flags)
 {
-	const struct bridge_profile *left = obj;
-	const struct bridge_profile *right = arg;
-	const char *right_name = arg;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_name = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcasecmp(left->name, right_name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(left->name, right_name, strlen(right_name));
-		break;
-	}
-	return cmp ? 0 : CMP_MATCH;
+	const struct bridge_profile *entry1 = obj, *entry2 = arg;
+	const char *name = arg;
+	return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
+		CMP_MATCH | CMP_STOP : 0;
 }
-
 static int bridge_hash_cb(const void *obj, const int flags)
 {
 	const struct bridge_profile *b_profile = obj;
 	const char *name = obj;
-	int hash;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		name = b_profile->name;
-		/* Fall through */
-	case OBJ_KEY:
-		hash = ast_str_case_hash(name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/* Should never happen in hash callback. */
-		ast_assert(0);
-		hash = 0;
-		break;
-	}
-	return hash;
+	return ast_str_case_hash(flags & OBJ_KEY ? name : b_profile->name);
 }
 
 /*! menu container functions */
 static int menu_cmp_cb(void *obj, void *arg, int flags)
 {
-	const struct conf_menu *left = obj;
-	const struct conf_menu *right = arg;
-	const char *right_name = arg;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_name = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcasecmp(left->name, right_name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(left->name, right_name, strlen(right_name));
-		break;
-	}
-	return cmp ? 0 : CMP_MATCH;
+	const struct conf_menu *entry1 = obj, *entry2 = arg;
+	const char *name = arg;
+	return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
+		CMP_MATCH | CMP_STOP : 0;
 }
-
 static int menu_hash_cb(const void *obj, const int flags)
 {
 	const struct conf_menu *menu = obj;
 	const char *name = obj;
-	int hash;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		name = menu->name;
-		/* Fall through */
-	case OBJ_KEY:
-		hash = ast_str_case_hash(name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/* Should never happen in hash callback. */
-		ast_assert(0);
-		hash = 0;
-		break;
-	}
-	return hash;
+	return ast_str_case_hash(flags & OBJ_KEY ? name : menu->name);
 }
-
 static void menu_destructor(void *obj)
 {
 	struct conf_menu *menu = obj;
@@ -783,47 +226,16 @@ static void menu_destructor(void *obj)
 /*! User profile container functions */
 static int user_cmp_cb(void *obj, void *arg, int flags)
 {
-	const struct user_profile *left = obj;
-	const struct user_profile *right = arg;
-	const char *right_name = arg;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_name = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcasecmp(left->name, right_name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(left->name, right_name, strlen(right_name));
-		break;
-	}
-	return cmp ? 0 : CMP_MATCH;
+	const struct user_profile *entry1 = obj, *entry2 = arg;
+	const char *name = arg;
+	return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
+		CMP_MATCH | CMP_STOP : 0;
 }
-
 static int user_hash_cb(const void *obj, const int flags)
 {
 	const struct user_profile *u_profile = obj;
 	const char *name = obj;
-	int hash;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		name = u_profile->name;
-		/* Fall through */
-	case OBJ_KEY:
-		hash = ast_str_case_hash(name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/* Should never happen in hash callback. */
-		ast_assert(0);
-		hash = 0;
-		break;
-	}
-	return hash;
+	return ast_str_case_hash(flags & OBJ_KEY ? name : u_profile->name);
 }
 
 /*! Bridge Profile Sounds functions */
@@ -918,35 +330,30 @@ static int set_sound(const char *sound_name, const char *sound_file, struct brid
 struct func_confbridge_data {
 	struct bridge_profile b_profile;
 	struct user_profile u_profile;
-	struct conf_menu *menu;
 	unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
 	unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
-	unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
 };
-
-static void func_confbridge_data_destructor(struct func_confbridge_data *b_data)
-{
-	conf_bridge_profile_destroy(&b_data->b_profile);
-	ao2_cleanup(b_data->menu);
-	ast_free(b_data);
-}
-
 static void func_confbridge_destroy_cb(void *data)
 {
 	struct func_confbridge_data *b_data = data;
-	func_confbridge_data_destructor(b_data);
+	conf_bridge_profile_destroy(&b_data->b_profile);
+	ast_free(b_data);
 };
-
 static const struct ast_datastore_info confbridge_datastore = {
 	.type = "confbridge",
 	.destroy = func_confbridge_destroy_cb
 };
+
 int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
 	struct ast_datastore *datastore;
 	struct func_confbridge_data *b_data;
 	char *parse;
 	struct ast_variable tmpvar = { 0, };
+	struct ast_variable template = {
+		.name = "template",
+		.file = "CONFBRIDGE"
+	};
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(type);
 		AST_APP_ARG(option);
@@ -981,18 +388,14 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
 			ast_datastore_free(datastore);
 			return 0;
 		}
-		datastore->data = b_data;
 		b_data->b_profile.sounds = bridge_profile_sounds_alloc();
 		if (!b_data->b_profile.sounds) {
 			ast_channel_unlock(chan);
 			ast_datastore_free(datastore);
+			ast_free(b_data);
 			return 0;
 		}
-		if (!(b_data->menu = menu_alloc("dialplan"))) {
-			ast_channel_unlock(chan);
-			ast_datastore_free(datastore);
-			return 0;
-		}
+		datastore->data = b_data;
 		ast_channel_datastore_add(chan, datastore);
 	} else {
 		b_data = datastore->data;
@@ -1007,46 +410,23 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
 	tmpvar.value = value;
 	tmpvar.file = "CONFBRIDGE";
 	if (!strcasecmp(args.type, "bridge")) {
-		if (!strcasecmp(args.option, "clear")) {
-			b_data->b_usable = 0;
-			conf_bridge_profile_destroy(&b_data->b_profile);
-			memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
-			if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
-				/* If this reallocation fails, the datastore has become unusable and must be destroyed. */
-				ast_channel_lock(chan);
-				ast_channel_datastore_remove(chan, datastore);
-				ast_channel_unlock(chan);
-				ast_datastore_free(datastore);
-			}
-			return 0;
-		} else if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
+		if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
+			template.value = DEFAULT_BRIDGE_PROFILE;
+			aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
+		}
+
+		if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
 			b_data->b_usable = 1;
 			return 0;
 		}
 	} else if (!strcasecmp(args.type, "user")) {
-		if (!strcasecmp(args.option, "clear")) {
-			b_data->u_usable = 0;
-			user_profile_destructor(&b_data->u_profile);
-			memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
-			return 0;
-		} else if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
-			b_data->u_usable = 1;
-			return 0;
+		if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
+			template.value = DEFAULT_USER_PROFILE;
+			aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
 		}
-	} else if (!strcasecmp(args.type, "menu")) {
-		if (!strcasecmp(args.option, "clear")) {
-			b_data->m_usable = 0;
-			ao2_cleanup(b_data->menu);
-			if (!(b_data->menu = menu_alloc("dialplan"))) {
-				/* If this reallocation fails, the datastore has become unusable and must be destroyed */
-				ast_channel_lock(chan);
-				ast_channel_datastore_remove(chan, datastore);
-				ast_channel_unlock(chan);
-				ast_datastore_free(datastore);
-			}
-			return 0;
-		} else if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
-			b_data->m_usable = 1;
+
+		if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
+			b_data->u_usable = 1;
 			return 0;
 		}
 	}
@@ -1401,9 +781,8 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in
 		u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
 		"enabled" : "disabled");
 	ast_cli(a->fd,"Announce join/leave:     %s\n",
-		u_profile.flags & (USER_OPT_ANNOUNCE_JOIN_LEAVE | USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW) ?
-		u_profile.flags & USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW ?
-		"enabled (with review)" : "enabled" : "disabled");
+		u_profile.flags & USER_OPT_ANNOUNCE_JOIN_LEAVE ?
+		"enabled" : "disabled");
 	ast_cli(a->fd,"Announce User Count all: %s\n",
 		u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNTALL ?
 		"enabled" : "disabled");
@@ -1520,10 +899,6 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
 		b_profile.flags & BRIDGE_OPT_RECORD_CONFERENCE ?
 		"yes" : "no");
 
-	ast_cli(a->fd,"Record File Append:    %s\n",
-		b_profile.flags & BRIDGE_OPT_RECORD_FILE_APPEND ?
-		"yes" : "no");
-
 	ast_cli(a->fd,"Record File:          %s\n",
 		ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
 		b_profile.rec_file);
@@ -1929,70 +1304,6 @@ static int bridge_template_handler(const struct aco_option *opt, struct ast_vari
 	return 0;
 }
 
-static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
-{
-	struct conf_menu_action *menu_action;
-	struct conf_menu_action *new_menu_action;
-
-	ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
-	AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
-
-	AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
-		if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
-			return -1;
-		}
-		memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
-		AST_LIST_NEXT(new_menu_action, action) = NULL;
-		AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
-	}
-
-	return 0;
-}
-
-static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
-{
-	/* Copy each menu item to the dst struct */
-	struct conf_menu_entry *cur;
-
-	AST_LIST_TRAVERSE(&src->entries, cur, entry) {
-		struct conf_menu_entry *cpy;
-
-		if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
-			return -1;
-		}
-
-		if (copy_menu_entry(cpy, cur)) {
-			conf_menu_entry_destroy(cpy);
-			ast_free(cpy);
-			return -1;
-		}
-		AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
-	}
-
-	return 0;
-}
-
-static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct conf_menu *dst_menu = obj;
-	struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
-	RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
-
-	if (!cfg) {
-		return 0;
-	}
-
-	if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
-		return -1;
-	}
-
-	if (conf_menu_profile_copy(dst_menu, src_menu)) {
-		return -1;
-	}
-
-	return 0;
-}
-
 static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
 	set_sound(var->name, var->value, obj);
@@ -2009,7 +1320,6 @@ static int verify_default_profiles(void)
 {
 	RAII_VAR(struct user_profile *, user_profile, NULL, ao2_cleanup);
 	RAII_VAR(struct bridge_profile *, bridge_profile, NULL, ao2_cleanup);
-	RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
 	struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
 
 	if (!cfg) {
@@ -2038,17 +1348,6 @@ static int verify_default_profiles(void)
 		ao2_link(cfg->user_profiles, user_profile);
 	}
 
-	menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
-	if (!menu_profile) {
-		menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
-		if (!menu_profile) {
-			return -1;
-		}
-		ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
-		aco_set_defaults(&menu_type, DEFAULT_MENU_PROFILE, menu_profile);
-		ao2_link(cfg->menus, menu_profile);
-	}
-
 	return 0;
 }
 
@@ -2060,6 +1359,8 @@ int conf_load_config(void)
 
 	/* User options */
 	aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
+	aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
+	aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
 	aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
 	aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
 	aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
@@ -2074,7 +1375,6 @@ int conf_load_config(void)
 	aco_option_register(&cfg_info, "talk_detection_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TALKER_DETECT);
 	aco_option_register(&cfg_info, "dtmf_passthrough", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DTMF_PASS);
 	aco_option_register(&cfg_info, "announce_join_leave", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE);
-	aco_option_register(&cfg_info, "announce_join_leave_review", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW);
 	aco_option_register(&cfg_info, "pin", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, pin));
 	aco_option_register(&cfg_info, "music_on_hold_class", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, moh_class));
 	aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
@@ -2086,16 +1386,13 @@ int conf_load_config(void)
 	/* This option should only be used with the CONFBRIDGE dialplan function */
 	aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
 
-/* XXX ASTERISK-21271 need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
 	/* Bridge options */
-	aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
 	aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
 	/* "auto" will fail to parse as a uint, but we use PARSE_DEFAULT to set the value to 0 in that case, which is the value that auto resolves to */
 	aco_option_register(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, internal_sample_rate), 0);
 	aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
 	aco_option_register(&cfg_info, "record_conference", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_CONFERENCE);
 	aco_option_register_custom(&cfg_info, "video_mode", ACO_EXACT, bridge_types, NULL, video_mode_handler, 0);
-	aco_option_register(&cfg_info, "record_file_append", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_APPEND);
 	aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
 	aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
 	aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language));
@@ -2104,8 +1401,6 @@ int conf_load_config(void)
 	aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0);
 
 	/* Menu options */
-	aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
-	aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0);
 	aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
 
 	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
@@ -2143,7 +1438,11 @@ const struct user_profile *conf_find_user_profile(struct ast_channel *chan, cons
 	struct func_confbridge_data *b_data = NULL;
 	RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
 
-	if (chan && ast_strlen_zero(user_profile_name)) {
+	if (!cfg) {
+		return NULL;
+	}
+
+	if (chan) {
 		ast_channel_lock(chan);
 		datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
 		ast_channel_unlock(chan);
@@ -2156,9 +1455,6 @@ const struct user_profile *conf_find_user_profile(struct ast_channel *chan, cons
 		}
 	}
 
-	if (!cfg) {
-		return NULL;
-	}
 	if (ast_strlen_zero(user_profile_name)) {
 		user_profile_name = DEFAULT_USER_PROFILE;
 	}
@@ -2196,7 +1492,11 @@ const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan,
 	struct func_confbridge_data *b_data = NULL;
 	RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
 
-	if (chan && ast_strlen_zero(bridge_profile_name)) {
+	if (!cfg) {
+		return NULL;
+	}
+
+	if (chan) {
 		ast_channel_lock(chan);
 		datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
 		ast_channel_unlock(chan);
@@ -2208,10 +1508,6 @@ const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan,
 			}
 		}
 	}
-
-	if (!cfg) {
-		return NULL;
-	}
 	if (ast_strlen_zero(bridge_profile_name)) {
 		bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
 	}
@@ -2227,7 +1523,7 @@ const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan,
 }
 
 struct dtmf_menu_hook_pvt {
-	struct confbridge_user *user;
+	struct conference_bridge_user *conference_bridge_user;
 	struct conf_menu_entry menu_entry;
 	struct conf_menu *menu;
 };
@@ -2237,7 +1533,7 @@ static void menu_hook_destroy(void *hook_pvt)
 	struct dtmf_menu_hook_pvt *pvt = hook_pvt;
 	struct conf_menu_action *action = NULL;
 
-	ao2_cleanup(pvt->menu);
+	ao2_ref(pvt->menu, -1);
 
 	while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
 		ast_free(action);
@@ -2245,11 +1541,28 @@ static void menu_hook_destroy(void *hook_pvt)
 	ast_free(pvt);
 }
 
-static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int menu_hook_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
 	struct dtmf_menu_hook_pvt *pvt = hook_pvt;
+	return conf_handle_dtmf(bridge_channel, pvt->conference_bridge_user, &pvt->menu_entry, pvt->menu);
+}
+
+static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
+{
+	struct conf_menu_action *menu_action = NULL;
+	struct conf_menu_action *new_menu_action = NULL;
+
+	memcpy(dst, src, sizeof(*dst));
+	AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
 
-	return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
+	AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
+		if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
+			return -1;
+		}
+		memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
+		AST_LIST_INSERT_HEAD(&dst->actions, new_menu_action, action);
+	}
+	return 0;
 }
 
 void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
@@ -2277,70 +1590,44 @@ int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu
 	return 0;
 }
 
-static int apply_menu_hooks(struct confbridge_user *user, struct conf_menu *menu)
+int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user)
 {
-	struct conf_menu_entry *menu_entry;
+	struct conf_menu *menu;
+	struct conf_menu_entry *menu_entry = NULL;
+	RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
+
+	if (!cfg) {
+		return -1;
+	}
 
-	SCOPED_AO2LOCK(menu_lock, menu);
+	if (!(menu = menu_find(cfg->menus, menu_name))) {
+		return -1;
+	}
+	ao2_lock(menu);
 	AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
 		struct dtmf_menu_hook_pvt *pvt;
-
 		if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
+			ao2_unlock(menu);
+			ao2_ref(menu, -1);
 			return -1;
 		}
-		pvt->user = user;
-		pvt->menu = ao2_bump(menu);
-
 		if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
-			menu_hook_destroy(pvt);
+			ast_free(pvt);
+			ao2_unlock(menu);
+			ao2_ref(menu, -1);
 			return -1;
 		}
+		pvt->conference_bridge_user = conference_bridge_user;
+		ao2_ref(menu, +1);
+		pvt->menu = menu;
 
-		if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
-			menu_hook_callback, pvt, menu_hook_destroy, 0)) {
-			menu_hook_destroy(pvt);
-		}
+		ast_bridge_features_hook(&conference_bridge_user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
 	}
 
-	return 0;
-}
-
-int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
-{
-	RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
-	RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
-
-	if (chan && ast_strlen_zero(menu_profile_name)) {
-		struct ast_datastore *datastore;
-		struct func_confbridge_data *b_data;
-
-		ast_channel_lock(chan);
-		datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
-		ast_channel_unlock(chan);
-		if (datastore) {
-			/* If a menu exists in the CONFBRIDGE function datastore, use it. */
-			b_data = datastore->data;
-			if (b_data->m_usable) {
-				menu = ao2_bump(b_data->menu);
-				return apply_menu_hooks(user, menu);
-			}
-		}
-	}
-
-	/* Otherwise, we need to get whatever menu profile is specified to use (or default). */
-	if (!cfg) {
-		return -1;
-	}
-
-	if (ast_strlen_zero(menu_profile_name)) {
-		menu_profile_name = DEFAULT_MENU_PROFILE;
-	}
-
-	if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
-		return -1;
-	}
+	ao2_unlock(menu);
+	ao2_ref(menu, -1);
 
-	return apply_menu_hooks(user, menu);
+	return 0;
 }
 
 void conf_destroy_config(void)
diff --git a/apps/confbridge/conf_state.c b/apps/confbridge/conf_state.c
index 305732f..0eb081f 100644
--- a/apps/confbridge/conf_state.c
+++ b/apps/confbridge/conf_state.c
@@ -42,9 +42,9 @@
 #include "include/conf_state.h"
 #include "include/confbridge.h"
 
-void conf_invalid_event_fn(struct confbridge_user *user)
+void conf_invalid_event_fn(struct conference_bridge_user *cbu)
 {
-	ast_log(LOG_ERROR, "Invalid event for confbridge user '%s'\n", user->u_profile.name);
+	ast_log(LOG_ERROR, "Invalid event for confbridge user '%s'\n", cbu->u_profile.name);
 }
 
 /*!
@@ -55,7 +55,7 @@ void conf_invalid_event_fn(struct confbridge_user *user)
  *
  * \return Nothing
  */
-static void conf_mute_moh_inactive_waitmarked(struct confbridge_user *user)
+static void conf_mute_moh_inactive_waitmarked(struct conference_bridge_user *user)
 {
 	/* Start music on hold if needed */
 	if (ast_test_flag(&user->u_profile, USER_OPT_MUSICONHOLD)) {
@@ -64,33 +64,33 @@ static void conf_mute_moh_inactive_waitmarked(struct confbridge_user *user)
 	conf_update_user_mute(user);
 }
 
-void conf_default_join_waitmarked(struct confbridge_user *user)
+void conf_default_join_waitmarked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_waiting(user->conference, user);
-	conf_mute_moh_inactive_waitmarked(user);
-	conf_add_post_join_action(user, conf_handle_inactive_waitmarked);
+	conf_add_user_waiting(cbu->conference_bridge, cbu);
+	conf_mute_moh_inactive_waitmarked(cbu);
+	conf_add_post_join_action(cbu, conf_handle_inactive_waitmarked);
 }
 
-void conf_default_leave_waitmarked(struct confbridge_user *user)
+void conf_default_leave_waitmarked(struct conference_bridge_user *cbu)
 {
-	conf_remove_user_waiting(user->conference, user);
-	if (user->playing_moh) {
-		conf_moh_stop(user);
+	conf_remove_user_waiting(cbu->conference_bridge, cbu);
+	if (cbu->playing_moh) {
+		conf_moh_stop(cbu);
 	}
 }
 
-void conf_change_state(struct confbridge_user *user, struct confbridge_state *newstate)
+void conf_change_state(struct conference_bridge_user *cbu, struct conference_state *newstate)
 {
-	ast_debug(1, "Changing conference '%s' state from %s to %s\n", user->conference->name, user->conference->state->name, newstate->name);
+	ast_debug(1, "Changing conference '%s' state from %s to %s\n", cbu->conference_bridge->name, cbu->conference_bridge->state->name, newstate->name);
 	ast_test_suite_event_notify("CONF_CHANGE_STATE", "Conference: %s\r\nOldState: %s\r\nNewState: %s\r\n",
-			user->conference->name,
-			user->conference->state->name,
+			cbu->conference_bridge->name,
+			cbu->conference_bridge->state->name,
 			newstate->name);
-	if (user->conference->state->exit) {
-		user->conference->state->exit(user);
+	if (cbu->conference_bridge->state->exit) {
+		cbu->conference_bridge->state->exit(cbu);
 	}
-	user->conference->state = newstate;
-	if (user->conference->state->entry) {
-		user->conference->state->entry(user);
+	cbu->conference_bridge->state = newstate;
+	if (cbu->conference_bridge->state->entry) {
+		cbu->conference_bridge->state->entry(cbu);
 	}
 }
diff --git a/apps/confbridge/conf_state_empty.c b/apps/confbridge/conf_state_empty.c
index 285f22a..c811986 100644
--- a/apps/confbridge/conf_state_empty.c
+++ b/apps/confbridge/conf_state_empty.c
@@ -37,12 +37,12 @@
 #include "include/confbridge.h"
 #include "include/conf_state.h"
 
-static void join_unmarked(struct confbridge_user *user);
-static void join_waitmarked(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void transition_to_empty(struct confbridge_user *user);
+static void join_unmarked(struct conference_bridge_user *cbu);
+static void join_waitmarked(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void transition_to_empty(struct conference_bridge_user *cbu);
 
-struct confbridge_state STATE_EMPTY = {
+struct conference_state STATE_EMPTY = {
 	.name = "EMPTY",
 	.join_unmarked = join_unmarked,
 	.join_waitmarked = join_waitmarked,
@@ -50,36 +50,36 @@ struct confbridge_state STATE_EMPTY = {
 	.entry = transition_to_empty,
 };
 
-struct confbridge_state *CONF_STATE_EMPTY = &STATE_EMPTY;
+struct conference_state *CONF_STATE_EMPTY = &STATE_EMPTY;
 
-static void join_unmarked(struct confbridge_user *user)
+static void join_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_handle_first_join(user->conference);
-	conf_add_post_join_action(user, conf_handle_only_unmarked);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_handle_first_join(cbu->conference_bridge);
+	conf_add_post_join_action(cbu, conf_handle_only_unmarked);
 
-	conf_change_state(user, CONF_STATE_SINGLE);
+	conf_change_state(cbu, CONF_STATE_SINGLE);
 }
 
-static void join_waitmarked(struct confbridge_user *user)
+static void join_waitmarked(struct conference_bridge_user *cbu)
 {
-	conf_default_join_waitmarked(user);
-	conf_handle_first_join(user->conference);
+	conf_default_join_waitmarked(cbu);
+	conf_handle_first_join(cbu->conference_bridge);
 
-	conf_change_state(user, CONF_STATE_INACTIVE);
+	conf_change_state(cbu, CONF_STATE_INACTIVE);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_handle_first_join(user->conference);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_handle_first_join(cbu->conference_bridge);
 
-	conf_change_state(user, CONF_STATE_SINGLE_MARKED);
+	conf_change_state(cbu, CONF_STATE_SINGLE_MARKED);
 }
 
-static void transition_to_empty(struct confbridge_user *user)
+static void transition_to_empty(struct conference_bridge_user *cbu)
 {
 	/* Set device state to "not in use" */
-	ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", user->conference->name);
-	conf_ended(user->conference);
+	ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", cbu->conference_bridge->name);
+	conf_ended(cbu->conference_bridge);
 }
diff --git a/apps/confbridge/conf_state_inactive.c b/apps/confbridge/conf_state_inactive.c
index bc41e61..b0d4ea1 100644
--- a/apps/confbridge/conf_state_inactive.c
+++ b/apps/confbridge/conf_state_inactive.c
@@ -35,39 +35,46 @@
 #include "include/confbridge.h"
 #include "include/conf_state.h"
 
-static void join_unmarked(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void leave_waitmarked(struct confbridge_user *user);
+static void join_unmarked(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void leave_waitmarked(struct conference_bridge_user *cbu);
+static void transition_to_inactive(struct conference_bridge_user *cbu);
 
-struct confbridge_state STATE_INACTIVE = {
+struct conference_state STATE_INACTIVE = {
 	.name = "INACTIVE",
 	.join_unmarked = join_unmarked,
 	.join_waitmarked = conf_default_join_waitmarked,
 	.join_marked = join_marked,
 	.leave_waitmarked = leave_waitmarked,
+	.entry = transition_to_inactive,
 };
-struct confbridge_state *CONF_STATE_INACTIVE = &STATE_INACTIVE;
+struct conference_state *CONF_STATE_INACTIVE = &STATE_INACTIVE;
 
-static void join_unmarked(struct confbridge_user *user)
+static void join_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_add_post_join_action(user, conf_handle_only_unmarked);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_add_post_join_action(cbu, conf_handle_only_unmarked);
 
-	conf_change_state(user, CONF_STATE_SINGLE);
+	conf_change_state(cbu, CONF_STATE_SINGLE);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_update_user_mute(user);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI_MARKED);
+	conf_change_state(cbu, CONF_STATE_MULTI_MARKED);
 }
 
-static void leave_waitmarked(struct confbridge_user *user)
+static void leave_waitmarked(struct conference_bridge_user *cbu)
 {
-	conf_default_leave_waitmarked(user);
-	if (user->conference->waitingusers == 0) {
-		conf_change_state(user, CONF_STATE_EMPTY);
+	conf_default_leave_waitmarked(cbu);
+	if (cbu->conference_bridge->waitingusers == 0) {
+		conf_change_state(cbu, CONF_STATE_EMPTY);
 	}
 }
+
+static void transition_to_inactive(struct conference_bridge_user *cbu)
+{
+	return;
+}
diff --git a/apps/confbridge/conf_state_multi.c b/apps/confbridge/conf_state_multi.c
index eca8899..689db8a 100644
--- a/apps/confbridge/conf_state_multi.c
+++ b/apps/confbridge/conf_state_multi.c
@@ -35,38 +35,45 @@
 #include "include/confbridge.h"
 #include "include/conf_state.h"
 
-static void join_unmarked(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void leave_unmarked(struct confbridge_user *user);
+static void join_unmarked(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void leave_unmarked(struct conference_bridge_user *cbu);
+void transition_to_multi(struct conference_bridge_user *cbu);
 
-struct confbridge_state STATE_MULTI = {
+struct conference_state STATE_MULTI = {
 	.name = "MULTI",
 	.join_unmarked = join_unmarked,
 	.join_waitmarked = conf_default_join_waitmarked,
 	.join_marked = join_marked,
 	.leave_unmarked = leave_unmarked,
 	.leave_waitmarked = conf_default_leave_waitmarked,
+	.entry = transition_to_multi,
 };
-struct confbridge_state *CONF_STATE_MULTI = &STATE_MULTI;
+struct conference_state *CONF_STATE_MULTI = &STATE_MULTI;
 
-static void join_unmarked(struct confbridge_user *user)
+static void join_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_update_user_mute(user);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_update_user_mute(cbu);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_update_user_mute(user);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI_MARKED);
+	conf_change_state(cbu, CONF_STATE_MULTI_MARKED);
 }
 
-static void leave_unmarked(struct confbridge_user *user)
+static void leave_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_remove_user_active(user->conference, user);
-	if (user->conference->activeusers == 1) {
-		conf_change_state(user, CONF_STATE_SINGLE);
+	conf_remove_user_active(cbu->conference_bridge, cbu);
+	if (cbu->conference_bridge->activeusers == 1) {
+		conf_change_state(cbu, CONF_STATE_SINGLE);
 	}
 }
+
+void transition_to_multi(struct conference_bridge_user *cbu)
+{
+	return;
+}
diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c
index 5d977f7..4f06e3a 100644
--- a/apps/confbridge/conf_state_multi_marked.c
+++ b/apps/confbridge/conf_state_multi_marked.c
@@ -38,15 +38,14 @@
 #include "include/confbridge.h"
 #include "asterisk/musiconhold.h"
 #include "include/conf_state.h"
-#include "asterisk/pbx.h"
 
-static void join_active(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void leave_active(struct confbridge_user *user);
-static void leave_marked(struct confbridge_user *user);
-static void transition_to_marked(struct confbridge_user *user);
+static void join_active(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void leave_active(struct conference_bridge_user *cbu);
+static void leave_marked(struct conference_bridge_user *cbu);
+static void transition_to_marked(struct conference_bridge_user *cbu);
 
-static struct confbridge_state STATE_MULTI_MARKED = {
+static struct conference_state STATE_MULTI_MARKED = {
 	.name = "MULTI_MARKED",
 	.join_unmarked = join_active,
 	.join_waitmarked = join_active,
@@ -56,57 +55,56 @@ static struct confbridge_state STATE_MULTI_MARKED = {
 	.leave_marked = leave_marked,
 	.entry = transition_to_marked,
 };
-struct confbridge_state *CONF_STATE_MULTI_MARKED = &STATE_MULTI_MARKED;
+struct conference_state *CONF_STATE_MULTI_MARKED = &STATE_MULTI_MARKED;
 
-static void join_active(struct confbridge_user *user)
+static void join_active(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_update_user_mute(user);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_update_user_mute(cbu);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_update_user_mute(user);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_update_user_mute(cbu);
 }
 
-static void leave_active(struct confbridge_user *user)
+static void leave_active(struct conference_bridge_user *cbu)
 {
-	conf_remove_user_active(user->conference, user);
-	if (user->conference->activeusers == 1) {
-		conf_change_state(user, CONF_STATE_SINGLE_MARKED);
+	conf_remove_user_active(cbu->conference_bridge, cbu);
+	if (cbu->conference_bridge->activeusers == 1) {
+		conf_change_state(cbu, CONF_STATE_SINGLE_MARKED);
 	}
 }
 
-static void leave_marked(struct confbridge_user *user)
+static void leave_marked(struct conference_bridge_user *cbu)
 {
-	struct confbridge_user *user_iter;
+	struct conference_bridge_user *cbu_iter;
 	int need_prompt = 0;
 
-	conf_remove_user_marked(user->conference, user);
+	conf_remove_user_marked(cbu->conference_bridge, cbu);
 
-	if (user->conference->markedusers == 0) {
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->active_list, user_iter, list) {
+	if (cbu->conference_bridge->markedusers == 0) {
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->active_list, cbu_iter, list) {
 			/* Kick ENDMARKED cbu_iters */
-			if (ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKED) && !user_iter->kicked) {
-				if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
-					&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
+			if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_ENDMARKED) && !cbu_iter->kicked) {
+				if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED)
+					&& !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) {
 					AST_LIST_REMOVE_CURRENT(list);
-					user_iter->conference->activeusers--;
-					AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
-					user_iter->conference->waitingusers++;
+					cbu_iter->conference_bridge->activeusers--;
+					AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list);
+					cbu_iter->conference_bridge->waitingusers++;
 				}
-				user_iter->kicked = 1;
-				pbx_builtin_setvar_helper(user_iter->chan, "CONFBRIDGE_RESULT", "ENDMARKED");
-				ast_bridge_remove(user_iter->conference->bridge, user_iter->chan);
-			} else if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
-				&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
+				cbu_iter->kicked = 1;
+				ast_bridge_remove(cbu_iter->conference_bridge->bridge, cbu_iter->chan);
+			} else if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED)
+				&& !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) {
 				need_prompt = 1;
 
 				AST_LIST_REMOVE_CURRENT(list);
-				user_iter->conference->activeusers--;
-				AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
-				user_iter->conference->waitingusers++;
+				cbu_iter->conference_bridge->activeusers--;
+				AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list);
+				cbu_iter->conference_bridge->waitingusers++;
 			} else {
 				/* User is neither wait_marked nor end_marked; however, they
 				 * should still hear the prompt.
@@ -117,29 +115,29 @@ static void leave_marked(struct confbridge_user *user)
 		AST_LIST_TRAVERSE_SAFE_END;
 	}
 
-	switch (user->conference->activeusers) {
+	switch (cbu->conference_bridge->activeusers) {
 	case 0:
 		/* Implies markedusers == 0 */
-		switch (user->conference->waitingusers) {
+		switch (cbu->conference_bridge->waitingusers) {
 		case 0:
-			conf_change_state(user, CONF_STATE_EMPTY);
+			conf_change_state(cbu, CONF_STATE_EMPTY);
 			break;
 		default:
-			conf_change_state(user, CONF_STATE_INACTIVE);
+			conf_change_state(cbu, CONF_STATE_INACTIVE);
 			break;
 		}
 		break;
 	case 1:
-		switch (user->conference->markedusers) {
+		switch (cbu->conference_bridge->markedusers) {
 		case 0:
-			conf_change_state(user, CONF_STATE_SINGLE);
+			conf_change_state(cbu, CONF_STATE_SINGLE);
 			break;
 		case 1:
 			/* XXX I seem to remember doing this for a reason, but right now it escapes me
 			 * how we could possibly ever have a waiting user while we have a marked user */
-			switch (user->conference->waitingusers) {
+			switch (cbu->conference_bridge->waitingusers) {
 			case 0:
-				conf_change_state(user, CONF_STATE_SINGLE_MARKED);
+				conf_change_state(cbu, CONF_STATE_SINGLE_MARKED);
 				break;
 			case 1:
 				break; /* Stay in marked */
@@ -148,9 +146,9 @@ static void leave_marked(struct confbridge_user *user)
 		}
 		break;
 	default:
-		switch (user->conference->markedusers) {
+		switch (cbu->conference_bridge->markedusers) {
 		case 0:
-			conf_change_state(user, CONF_STATE_MULTI);
+			conf_change_state(cbu, CONF_STATE_MULTI);
 			break;
 		default:
 			break; /* Stay in marked */
@@ -159,64 +157,64 @@ static void leave_marked(struct confbridge_user *user)
 
 	if (need_prompt) {
 		/* Play back the audio prompt saying the leader has left the conference */
-		if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET)) {
-			ao2_unlock(user->conference);
-			ast_autoservice_start(user->chan);
-			play_sound_file(user->conference,
-				conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->b_profile.sounds));
-			ast_autoservice_stop(user->chan);
-			ao2_lock(user->conference);
+		if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET)) {
+			ao2_unlock(cbu->conference_bridge);
+			ast_autoservice_start(cbu->chan);
+			play_sound_file(cbu->conference_bridge,
+				conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, cbu->b_profile.sounds));
+			ast_autoservice_stop(cbu->chan);
+			ao2_lock(cbu->conference_bridge);
 		}
 
-		AST_LIST_TRAVERSE(&user->conference->waiting_list, user_iter, list) {
-			if (user_iter->kicked) {
+		AST_LIST_TRAVERSE(&cbu->conference_bridge->waiting_list, cbu_iter, list) {
+			if (cbu_iter->kicked) {
 				continue;
 			}
 
-			if (ast_test_flag(&user_iter->u_profile, USER_OPT_MUSICONHOLD)) {
-				conf_moh_start(user_iter);
+			if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_MUSICONHOLD)) {
+				conf_moh_start(cbu_iter);
 			}
 
-			conf_update_user_mute(user_iter);
+			conf_update_user_mute(cbu_iter);
 		}
 	}
 }
 
-static int post_join_play_begin(struct confbridge_user *cbu)
+static int post_join_play_begin(struct conference_bridge_user *cbu)
 {
 	int res;
 
 	ast_autoservice_start(cbu->chan);
-	res = play_sound_file(cbu->conference,
+	res = play_sound_file(cbu->conference_bridge,
 		conf_get_sound(CONF_SOUND_BEGIN, cbu->b_profile.sounds));
 	ast_autoservice_stop(cbu->chan);
 	return res;
 }
 
-static void transition_to_marked(struct confbridge_user *user)
+static void transition_to_marked(struct conference_bridge_user *cbu)
 {
-	struct confbridge_user *user_iter;
+	struct conference_bridge_user *cbu_iter;
 	int waitmarked_moved = 0;
 
 	/* Move all waiting users to active, stopping MOH and unmuting if necessary */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->waiting_list, user_iter, list) {
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->waiting_list, cbu_iter, list) {
 		AST_LIST_REMOVE_CURRENT(list);
-		user->conference->waitingusers--;
-		AST_LIST_INSERT_TAIL(&user->conference->active_list, user_iter, list);
-		user->conference->activeusers++;
-		if (user_iter->playing_moh) {
-			conf_moh_stop(user_iter);
+		cbu->conference_bridge->waitingusers--;
+		AST_LIST_INSERT_TAIL(&cbu->conference_bridge->active_list, cbu_iter, list);
+		cbu->conference_bridge->activeusers++;
+		if (cbu_iter->playing_moh) {
+			conf_moh_stop(cbu_iter);
 		}
-		conf_update_user_mute(user_iter);
+		conf_update_user_mute(cbu_iter);
 		waitmarked_moved++;
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
 
 	/* Play the audio file stating that the conference is beginning */
-	if (user->conference->markedusers == 1
-		&& ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)
-		&& !ast_test_flag(&user->u_profile, USER_OPT_QUIET)
+	if (cbu->conference_bridge->markedusers == 1
+		&& ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)
+		&& !ast_test_flag(&cbu->u_profile, USER_OPT_QUIET)
 		&& waitmarked_moved) {
-		conf_add_post_join_action(user, post_join_play_begin);
+		conf_add_post_join_action(cbu, post_join_play_begin);
 	}
 }
diff --git a/apps/confbridge/conf_state_single.c b/apps/confbridge/conf_state_single.c
index b3881fa..7a1ebcd 100644
--- a/apps/confbridge/conf_state_single.c
+++ b/apps/confbridge/conf_state_single.c
@@ -35,12 +35,12 @@
 #include "include/confbridge.h"
 #include "include/conf_state.h"
 
-static void join_unmarked(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void leave_unmarked(struct confbridge_user *user);
-static void transition_to_single(struct confbridge_user *user);
+static void join_unmarked(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void leave_unmarked(struct conference_bridge_user *cbu);
+static void transition_to_single(struct conference_bridge_user *cbu);
 
-struct confbridge_state STATE_SINGLE = {
+struct conference_state STATE_SINGLE = {
 	.name = "SINGLE",
 	.join_unmarked = join_unmarked,
 	.join_waitmarked = conf_default_join_waitmarked,
@@ -49,41 +49,41 @@ struct confbridge_state STATE_SINGLE = {
 	.leave_waitmarked = conf_default_leave_waitmarked,
 	.entry = transition_to_single,
 };
-struct confbridge_state *CONF_STATE_SINGLE = &STATE_SINGLE;
+struct conference_state *CONF_STATE_SINGLE = &STATE_SINGLE;
 
-static void join_unmarked(struct confbridge_user *user)
+static void join_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_handle_second_active(user->conference);
-	conf_update_user_mute(user);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_handle_second_active(cbu->conference_bridge);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI);
+	conf_change_state(cbu, CONF_STATE_MULTI);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_handle_second_active(user->conference);
-	conf_update_user_mute(user);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_handle_second_active(cbu->conference_bridge);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI_MARKED);
+	conf_change_state(cbu, CONF_STATE_MULTI_MARKED);
 }
 
-static void leave_unmarked(struct confbridge_user *user)
+static void leave_unmarked(struct conference_bridge_user *cbu)
 {
-	conf_remove_user_active(user->conference, user);
-	if (user->playing_moh) {
-		conf_moh_stop(user);
+	conf_remove_user_active(cbu->conference_bridge, cbu);
+	if (cbu->playing_moh) {
+		conf_moh_stop(cbu);
 	}
 
-	if (user->conference->waitingusers) {
-		conf_change_state(user, CONF_STATE_INACTIVE);
+	if (cbu->conference_bridge->waitingusers) {
+		conf_change_state(cbu, CONF_STATE_INACTIVE);
 	} else {
-		conf_change_state(user, CONF_STATE_EMPTY);
+		conf_change_state(cbu, CONF_STATE_EMPTY);
 	}
 }
 
-static void transition_to_single(struct confbridge_user *user)
+static void transition_to_single(struct conference_bridge_user *cbu)
 {
-	conf_mute_only_active(user->conference);
+	conf_mute_only_active(cbu->conference_bridge);
 }
diff --git a/apps/confbridge/conf_state_single_marked.c b/apps/confbridge/conf_state_single_marked.c
index c13ef16..84bff6f 100644
--- a/apps/confbridge/conf_state_single_marked.c
+++ b/apps/confbridge/conf_state_single_marked.c
@@ -35,12 +35,12 @@
 #include "include/confbridge.h"
 #include "include/conf_state.h"
 
-static void join_active(struct confbridge_user *user);
-static void join_marked(struct confbridge_user *user);
-static void leave_marked(struct confbridge_user *user);
-static void transition_to_single_marked(struct confbridge_user *user);
+static void join_active(struct conference_bridge_user *cbu);
+static void join_marked(struct conference_bridge_user *cbu);
+static void leave_marked(struct conference_bridge_user *cbu);
+static void transition_to_single_marked(struct conference_bridge_user *cbu);
 
-struct confbridge_state STATE_SINGLE_MARKED = {
+struct conference_state STATE_SINGLE_MARKED = {
 	.name = "SINGLE_MARKED",
 	.join_unmarked = join_active,
 	.join_waitmarked = join_active,
@@ -48,37 +48,37 @@ struct confbridge_state STATE_SINGLE_MARKED = {
 	.leave_marked = leave_marked,
 	.entry = transition_to_single_marked,
 };
-struct confbridge_state *CONF_STATE_SINGLE_MARKED = &STATE_SINGLE_MARKED;
+struct conference_state *CONF_STATE_SINGLE_MARKED = &STATE_SINGLE_MARKED;
 
-static void join_active(struct confbridge_user *user)
+static void join_active(struct conference_bridge_user *cbu)
 {
-	conf_add_user_active(user->conference, user);
-	conf_handle_second_active(user->conference);
-	conf_update_user_mute(user);
+	conf_add_user_active(cbu->conference_bridge, cbu);
+	conf_handle_second_active(cbu->conference_bridge);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI_MARKED);
+	conf_change_state(cbu, CONF_STATE_MULTI_MARKED);
 }
 
-static void join_marked(struct confbridge_user *user)
+static void join_marked(struct conference_bridge_user *cbu)
 {
-	conf_add_user_marked(user->conference, user);
-	conf_handle_second_active(user->conference);
-	conf_update_user_mute(user);
+	conf_add_user_marked(cbu->conference_bridge, cbu);
+	conf_handle_second_active(cbu->conference_bridge);
+	conf_update_user_mute(cbu);
 
-	conf_change_state(user, CONF_STATE_MULTI_MARKED);
+	conf_change_state(cbu, CONF_STATE_MULTI_MARKED);
 }
 
-static void leave_marked(struct confbridge_user *user)
+static void leave_marked(struct conference_bridge_user *cbu)
 {
-	conf_remove_user_marked(user->conference, user);
-	if (user->playing_moh) {
-		conf_moh_stop(user);
+	conf_remove_user_marked(cbu->conference_bridge, cbu);
+	if (cbu->playing_moh) {
+		conf_moh_stop(cbu);
 	}
 
-	conf_change_state(user, CONF_STATE_EMPTY);
+	conf_change_state(cbu, CONF_STATE_EMPTY);
 }
 
-static void transition_to_single_marked(struct confbridge_user *user)
+static void transition_to_single_marked(struct conference_bridge_user *cbu)
 {
-	conf_mute_only_active(user->conference);
+	conf_mute_only_active(cbu->conference_bridge);
 }
diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c
deleted file mode 100644
index cc8cfa3..0000000
--- a/apps/confbridge/confbridge_manager.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Confbridge manager events for stasis messages
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422177 $")
-
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis_message_router.h"
-#include "include/confbridge.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="ConfbridgeStart">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a conference starts.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeEnd</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeEnd">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a conference ends.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeStart</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeJoin">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel joins a Confbridge conference.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="Admin">
-					<para>Identifies this user as an admin user.</para>
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeLeave</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeLeave">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="Admin">
-					<para>Identifies this user as an admin user.</para>
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeJoin</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeRecord">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a conference starts recording.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeStopRecord</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeStopRecord">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a conference that was recording stops recording.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeRecord</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeMute">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a Confbridge participant mutes.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="Admin">
-					<para>Identifies this user as an admin user.</para>
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeUnmute</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeUnmute">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a confbridge participant unmutes.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="Admin">
-					<para>Identifies this user as an admin user.</para>
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">ConfbridgeMute</ref>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ConfbridgeTalking">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a confbridge participant unmutes.</synopsis>
-			<syntax>
-				<parameter name="Conference">
-					<para>The name of the Confbridge conference.</para>
-				</parameter>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="TalkingStatus">
-					<enumlist>
-						<enum name="on"/>
-						<enum name="off"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Admin">
-					<para>Identifies this user as an admin user.</para>
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">ConfBridge</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
-static struct stasis_message_router *bridge_state_router;
-static struct stasis_message_router *channel_state_router;
-
-static void confbridge_publish_manager_event(
-	struct stasis_message *message,
-	const char *event,
-	struct ast_str *extra_text)
-{
-	struct ast_bridge_blob *blob = stasis_message_data(message);
-	const char *conference_name;
-	RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
-
-	ast_assert(blob != NULL);
-	ast_assert(event != NULL);
-
-	bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
-	if (!bridge_text) {
-		return;
-	}
-
-	conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
-	ast_assert(conference_name != NULL);
-
-	if (blob->channel) {
-		channel_text = ast_manager_build_channel_state_string(blob->channel);
-	}
-
-	manager_event(EVENT_FLAG_CALL, event,
-		"Conference: %s\r\n"
-		"%s"
-		"%s"
-		"%s",
-		conference_name,
-		ast_str_buffer(bridge_text),
-		S_COR(channel_text, ast_str_buffer(channel_text), ""),
-		S_COR(extra_text, ast_str_buffer(extra_text), ""));
-}
-
-static int get_admin_header(struct ast_str **extra_text, struct stasis_message *message)
-{
-	const struct ast_bridge_blob *blob = stasis_message_data(message);
-	const struct ast_json *admin = ast_json_object_get(blob->blob, "admin");
-	if (!admin) {
-		return -1;
-	}
-
-	return ast_str_append_event_header(extra_text, "Admin",
-		S_COR(ast_json_is_true(admin), "Yes", "No"));
-}
-
-static void confbridge_start_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	confbridge_publish_manager_event(message, "ConfbridgeStart", NULL);
-}
-
-static void confbridge_end_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	confbridge_publish_manager_event(message, "ConfbridgeEnd", NULL);
-}
-
-static void confbridge_leave_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_str *extra_text = NULL;
-
-	if (!get_admin_header(&extra_text, message)) {
-		confbridge_publish_manager_event(message, "ConfbridgeLeave", extra_text);
-	}
-	ast_free(extra_text);
-}
-
-static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_str *extra_text = NULL;
-
-	if (!get_admin_header(&extra_text, message)) {
-		confbridge_publish_manager_event(message, "ConfbridgeJoin", extra_text);
-	}
-	ast_free(extra_text);
-}
-
-static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	confbridge_publish_manager_event(message, "ConfbridgeRecord", NULL);
-}
-
-static void confbridge_stop_record_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	confbridge_publish_manager_event(message, "ConfbridgeStopRecord", NULL);
-}
-
-static void confbridge_mute_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_str *extra_text = NULL;
-
-	if (!get_admin_header(&extra_text, message)) {
-		confbridge_publish_manager_event(message, "ConfbridgeMute", extra_text);
-	}
-	ast_free(extra_text);
-}
-
-static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_str *extra_text = NULL;
-
-	if (!get_admin_header(&extra_text, message)) {
-		confbridge_publish_manager_event(message, "ConfbridgeUnmute", extra_text);
-	}
-	ast_free(extra_text);
-}
-
-static void confbridge_talking_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
-	const struct ast_bridge_blob *blob = stasis_message_data(message);
-	const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
-	if (!talking_status) {
-		return;
-	}
-
-	ast_str_append_event_header(&extra_text, "TalkingStatus", talking_status);
-	if (!extra_text) {
-		return;
-	}
-
-	if (!get_admin_header(&extra_text, message)) {
-		confbridge_publish_manager_event(message, "ConfbridgeTalking", extra_text);
-	}
-}
-
-STASIS_MESSAGE_TYPE_DEFN(confbridge_start_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_end_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_join_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_leave_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_start_record_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_stop_record_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_mute_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_unmute_type);
-STASIS_MESSAGE_TYPE_DEFN(confbridge_talking_type);
-
-void manager_confbridge_shutdown(void) {
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_end_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_join_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_leave_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_record_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_stop_record_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_mute_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_unmute_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(confbridge_talking_type);
-
-	if (bridge_state_router) {
-		stasis_message_router_unsubscribe(bridge_state_router);
-		bridge_state_router = NULL;
-	}
-
-	if (channel_state_router) {
-		stasis_message_router_unsubscribe(channel_state_router);
-		channel_state_router = NULL;
-	}
-}
-
-int manager_confbridge_init(void)
-{
-	STASIS_MESSAGE_TYPE_INIT(confbridge_start_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_end_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_join_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_leave_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_start_record_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_stop_record_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_mute_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_unmute_type);
-	STASIS_MESSAGE_TYPE_INIT(confbridge_talking_type);
-
-	bridge_state_router = stasis_message_router_create(
-		ast_bridge_topic_all_cached());
-
-	if (!bridge_state_router) {
-		return -1;
-	}
-
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_start_type(),
-			confbridge_start_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_end_type(),
-			confbridge_end_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_join_type(),
-			confbridge_join_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_leave_type(),
-			confbridge_leave_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_start_record_type(),
-			confbridge_start_record_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_stop_record_type(),
-			confbridge_stop_record_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_mute_type(),
-			confbridge_mute_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_unmute_type(),
-			confbridge_unmute_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(bridge_state_router,
-			confbridge_talking_type(),
-			confbridge_talking_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-
-	channel_state_router = stasis_message_router_create(
-		ast_channel_topic_all_cached());
-
-	if (!channel_state_router) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_start_type(),
-			confbridge_start_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_end_type(),
-			confbridge_end_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_join_type(),
-			confbridge_join_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_leave_type(),
-			confbridge_leave_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_start_record_type(),
-			confbridge_start_record_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_stop_record_type(),
-			confbridge_stop_record_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_mute_type(),
-			confbridge_mute_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_unmute_type(),
-			confbridge_unmute_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-	if (stasis_message_router_add(channel_state_router,
-			confbridge_talking_type(),
-			confbridge_talking_cb,
-			NULL)) {
-		manager_confbridge_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/apps/confbridge/include/conf_state.h b/apps/confbridge/include/conf_state.h
index b6f6f47..8a25850 100644
--- a/apps/confbridge/include/conf_state.h
+++ b/apps/confbridge/include/conf_state.h
@@ -36,16 +36,16 @@
 #ifndef _CONF_STATE_H_
 #define _CONF_STATE_H_
 
-struct confbridge_state;
-struct confbridge_conference;
-struct confbridge_user;
+struct conference_state;
+struct conference_bridge;
+struct conference_bridge_user;
 
-typedef void (*conference_event_fn)(struct confbridge_user *user);
-typedef void (*conference_entry_fn)(struct confbridge_user *user);
-typedef void (*conference_exit_fn)(struct confbridge_user *user);
+typedef void (*conference_event_fn)(struct conference_bridge_user *cbu);
+typedef void (*conference_entry_fn)(struct conference_bridge_user *cbu);
+typedef void (*conference_exit_fn)(struct conference_bridge_user *cbu);
 
 /*! \brief A conference state object to hold the various state callback functions */
-struct confbridge_state {
+struct conference_state {
 	const char *name;
 	conference_event_fn join_unmarked;    /*!< Handle an unmarked join event */
 	conference_event_fn join_waitmarked;  /*!< Handle a waitmarked join event */
@@ -58,38 +58,38 @@ struct confbridge_state {
 };
 
 /*! \brief Conference state with no active or waiting users */
-extern struct confbridge_state *CONF_STATE_EMPTY;
+extern struct conference_state *CONF_STATE_EMPTY;
 
 /*! \brief Conference state with only waiting users */
-extern struct confbridge_state *CONF_STATE_INACTIVE;
+extern struct conference_state *CONF_STATE_INACTIVE;
 
 /*! \brief Conference state with only a single unmarked active user */
-extern struct confbridge_state *CONF_STATE_SINGLE;
+extern struct conference_state *CONF_STATE_SINGLE;
 
 /*! \brief Conference state with only a single marked active user */
-extern struct confbridge_state *CONF_STATE_SINGLE_MARKED;
+extern struct conference_state *CONF_STATE_SINGLE_MARKED;
 
 /*! \brief Conference state with multiple active users, but no marked users */
-extern struct confbridge_state *CONF_STATE_MULTI;
+extern struct conference_state *CONF_STATE_MULTI;
 
 /*! \brief Conference state with multiple active users and at least one marked user */
-extern struct confbridge_state *CONF_STATE_MULTI_MARKED;
+extern struct conference_state *CONF_STATE_MULTI_MARKED;
 
 /*! \brief Execute conference state transition because of a user action
- * \param user The user that joined/left
+ * \param cbu The user that joined/left
  * \param newstate The state to transition to
  */
-void conf_change_state(struct confbridge_user *user, struct confbridge_state *newstate);
+void conf_change_state(struct conference_bridge_user *cbu, struct conference_state *newstate);
 
 /* Common event handlers shared between different states */
 
 /*! \brief Logic to execute every time a waitmarked user joins an unmarked conference */
-void conf_default_join_waitmarked(struct confbridge_user *user);
+void conf_default_join_waitmarked(struct conference_bridge_user *cbu);
 
 /*! \brief Logic to execute every time a waitmarked user leaves an unmarked conference */
-void conf_default_leave_waitmarked(struct confbridge_user *user);
+void conf_default_leave_waitmarked(struct conference_bridge_user *cbu);
 
 /*! \brief A handler for join/leave events that are invalid in a particular state */
-void conf_invalid_event_fn(struct confbridge_user *user);
+void conf_invalid_event_fn(struct conference_bridge_user *cbu);
 
 #endif
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index 4e155e6..e05b1fc 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -26,8 +26,8 @@
 #include "asterisk/logger.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_features.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_features.h"
 #include "conf_state.h"
 
 /* Maximum length of a conference bridge name */
@@ -37,7 +37,6 @@
 
 #define DEFAULT_USER_PROFILE "default_user"
 #define DEFAULT_BRIDGE_PROFILE "default_bridge"
-#define DEFAULT_MENU_PROFILE "default_menu"
 
 #define DEFAULT_TALKING_THRESHOLD 160
 #define DEFAULT_SILENCE_THRESHOLD 2500
@@ -59,7 +58,6 @@ enum user_profile_flags {
 	USER_OPT_DTMF_PASS    =  (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
 	USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
 	USER_OPT_JITTERBUFFER =  (1 << 15), /*!< Places a jitterbuffer on the user. */
-	USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW = (1 << 16), /*!< modifies ANNOUNCE_JOIN_LEAVE - user reviews the recording before continuing */
 };
 
 enum bridge_profile_flags {
@@ -67,7 +65,6 @@ enum bridge_profile_flags {
 	BRIDGE_OPT_VIDEO_SRC_LAST_MARKED = (1 << 1), /*!< Set if conference should feed video of last marked user to all participants. */
 	BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED = (1 << 2), /*!< Set if conference should feed video of first marked user to all participants. */
 	BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER = (1 << 3), /*!< Set if conference set the video feed to follow the loudest talker.  */
-	BRIDGE_OPT_RECORD_FILE_APPEND = (1 << 4), /*!< Set if the record file should be appended to between start/stops.  */
 };
 
 enum conf_menu_action_id {
@@ -206,9 +203,9 @@ struct bridge_profile {
 };
 
 /*! \brief The structure that represents a conference bridge */
-struct confbridge_conference {
+struct conference_bridge {
 	char name[MAX_CONF_NAME];                                         /*!< Name of the conference bridge */
-	struct confbridge_state *state;                                   /*!< Conference state information */
+	struct conference_state *state;                                   /*!< Conference state information */
 	struct ast_bridge *bridge;                                        /*!< Bridge structure doing the mixing */
 	struct bridge_profile b_profile;                                  /*!< The Bridge Configuration Profile */
 	unsigned int activeusers;                                         /*!< Number of active users present */
@@ -216,27 +213,23 @@ struct confbridge_conference {
 	unsigned int waitingusers;                                        /*!< Number of waiting users present */
 	unsigned int locked:1;                                            /*!< Is this conference bridge locked? */
 	unsigned int muted:1;                                             /*!< Is this conference bridge muted? */
-	unsigned int record_state:2;                                      /*!< Whether recording is started, stopped, or should exit */
 	struct ast_channel *playback_chan;                                /*!< Channel used for playback into the conference bridge */
 	struct ast_channel *record_chan;                                  /*!< Channel used for recording the conference */
-	pthread_t record_thread;                                          /*!< The thread the recording chan lives in */
+	struct ast_str *record_filename;                                  /*!< Recording filename. */
+	struct ast_str *orig_rec_file;                                    /*!< Previous b_profile.rec_file. */
 	ast_mutex_t playback_lock;                                        /*!< Lock used for playback channel */
-	ast_mutex_t record_lock;                                          /*!< Lock used for the record thread */
-	ast_cond_t record_cond;                                           /*!< Recording condition variable */
-	AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list;              /*!< List of users participating in the conference bridge */
-	AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list;             /*!< List of users waiting to join the conference bridge */
+	AST_LIST_HEAD_NOLOCK(, conference_bridge_user) active_list;       /*!< List of users participating in the conference bridge */
+	AST_LIST_HEAD_NOLOCK(, conference_bridge_user) waiting_list;      /*!< List of users waiting to join the conference bridge */
 };
 
-extern struct ao2_container *conference_bridges;
-
 struct post_join_action {
-	int (*func)(struct confbridge_user *user);
+	int (*func)(struct conference_bridge_user *);
 	AST_LIST_ENTRY(post_join_action) list;
 };
 
 /*! \brief The structure that represents a conference bridge user */
-struct confbridge_user {
-	struct confbridge_conference *conference;    /*!< Conference bridge they are participating in */
+struct conference_bridge_user {
+	struct conference_bridge *conference_bridge; /*!< Conference bridge they are participating in */
 	struct bridge_profile b_profile;             /*!< The Bridge Configuration Profile */
 	struct user_profile u_profile;               /*!< The User Configuration Profile */
 	char menu_name[64];                          /*!< The name of the DTMF menu assigned to this user */
@@ -249,7 +242,7 @@ struct confbridge_user {
 	unsigned int kicked:1;                       /*!< User has been kicked from the conference */
 	unsigned int playing_moh:1;                  /*!< MOH is currently being played to the user */
 	AST_LIST_HEAD_NOLOCK(, post_join_action) post_join_list; /*!< List of sounds to play after joining */;
-	AST_LIST_ENTRY(confbridge_user) list;        /*!< Linked list information */
+	AST_LIST_ENTRY(conference_bridge_user) list; /*!< Linked list information */
 };
 
 /*! \brief load confbridge.conf file */
@@ -265,57 +258,32 @@ void conf_destroy_config(void);
  * \brief find a user profile given a user profile's name and store
  * that profile in result structure.
  *
- * \param chan channel the user profile is requested for
- * \param user_profile_name name of the profile requested (optional)
- * \param result data contained by the user profile will be copied to this struct pointer
- *
- * \details If user_profile_name is not provided, this function will
- * check for the presence of a user profile set by the CONFBRIDGE
- * function on a channel datastore. If that doesn't exist, the
- * default_user profile is used.
- *
+ * \details This function first attempts to find any custom user
+ * profile that might exist on a channel datastore, if that doesn't
+ * exist it looks up the provided user profile name, if that doesn't
+ * exist either the default_user profile is used.
+
  * \retval user profile on success
  * \retval NULL on failure
  */
 const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result);
 
 /*!
- * \brief Find a bridge profile given a bridge profile's name and store
- * that profile in result structure.
+ * \brief Find a bridge profile
  *
- * \param chan channel the bridge profile is requested for
- * \param bridge_profile_name name of the profile requested (optional)
- * \param result data contained by the bridge profile will be copied to this struct pointer
+ * \details Any bridge profile found using this function must be
+ * destroyed using conf_bridge_profile_destroy.  This function first
+ * attempts to find any custom bridge profile that might exist on
+ * a channel datastore, if that doesn't exist it looks up the
+ * provided bridge profile name, if that doesn't exist either
+ * the default_bridge profile is used.
  *
- * \details If bridge_profile_name is not provided, this function will
- * check for the presence of a bridge profile set by the CONFBRIDGE
- * function on a channel datastore. If that doesn't exist, the
- * default_bridge profile is used.
- *
- * \retval bridge profile on success
+ * \retval Bridge profile on success
  * \retval NULL on failure
  */
 const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result);
 
 /*!
- * \brief find a menu profile given a menu profile's name and apply
- * the menu in DTMF hooks.
- *
- * \param chan channel the menu profile is requested for
- * \param user user profile the menu is being applied to
- * \param menu_profile_name name of the profile requested (optional)
- *
- * \details If menu_profile_name is not provided, this function will
- * check for the presence of a menu profile set by the CONFBRIDGE
- * function on a channel datastore. If that doesn't exist, the
- * default_menu profile is used.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name);
-
-/*!
  * \brief Destroy a bridge profile found by 'conf_find_bridge_profile'
  */
 void conf_bridge_profile_destroy(struct bridge_profile *b_profile);
@@ -327,6 +295,14 @@ void conf_bridge_profile_destroy(struct bridge_profile *b_profile);
 void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src);
 
 /*!
+ * \brief Set a DTMF menu to a conference user by menu name.
+ *
+ * \retval 0 on success, menu was found and set
+ * \retval -1 on error, menu was not found
+ */
+int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user);
+
+/*!
  * \brief Finds a menu_entry in a menu structure matched by DTMF sequence.
  *
  * \note the menu entry found must be destroyed using conf_menu_entry_destroy()
@@ -345,10 +321,10 @@ void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry);
  * \brief Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get
  * called to perform the menu action.
  *
- * \param bridge_channel Bridged channel this is involving
- * \param user the conference user to perform the action on.
- * \param menu_entry the menu entry that invoked this callback to occur.
- * \param menu an AO2 referenced pointer to the entire menu structure the menu_entry
+ * \param bridge_channel, Bridged channel this is involving
+ * \param conference_bridge_user, the conference user to perform the action on.
+ * \param menu_entry, the menu entry that invoked this callback to occur.
+ * \param menu, an AO2 referenced pointer to the entire menu structure the menu_entry
  *        derived from.
  *
  * \note The menu_entry is a deep copy of the entry found in the menu structure.  This allows
@@ -361,7 +337,7 @@ void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry);
  */
 int conf_handle_dtmf(
 	struct ast_bridge_channel *bridge_channel,
-	struct confbridge_user *user,
+	struct conference_bridge_user *conference_bridge_user,
 	struct conf_menu_entry *menu_entry,
 	struct conf_menu *menu);
 
@@ -375,18 +351,18 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
 /*!
  * \brief Play sound file into conference bridge
  *
- * \param conference The conference bridge to play sound file into
+ * \param conference_bridge The conference bridge to play sound file into
  * \param filename Sound file to play
  *
  * \retval 0 success
  * \retval -1 failure
  */
-int play_sound_file(struct confbridge_conference *conference, const char *filename);
+int play_sound_file(struct conference_bridge *conference_bridge, const char *filename);
 
 /*! \brief Callback to be called when the conference has become empty
- * \param conference The conference bridge
+ * \param conference_bridge The conference bridge
  */
-void conf_ended(struct confbridge_conference *conference);
+void conf_ended(struct conference_bridge *conference_bridge);
 
 /*!
  * \brief Update the actual mute status of the user and set it on the bridge.
@@ -395,7 +371,7 @@ void conf_ended(struct confbridge_conference *conference);
  *
  * \return Nothing
  */
-void conf_update_user_mute(struct confbridge_user *user);
+void conf_update_user_mute(struct conference_bridge_user *user);
 
 /*!
  * \brief Stop MOH for the conference user.
@@ -404,7 +380,7 @@ void conf_update_user_mute(struct confbridge_user *user);
  *
  * \return Nothing
  */
-void conf_moh_stop(struct confbridge_user *user);
+void conf_moh_stop(struct conference_bridge_user *user);
 
 /*!
  * \brief Start MOH for the conference user.
@@ -413,214 +389,81 @@ void conf_moh_stop(struct confbridge_user *user);
  *
  * \return Nothing
  */
-void conf_moh_start(struct confbridge_user *user);
+void conf_moh_start(struct conference_bridge_user *user);
 
 /*! \brief Attempt to mute/play MOH to the only user in the conference if they require it
- * \param conference A conference bridge containing a single user
+ * \param conference_bridge A conference bridge containing a single user
  */
-void conf_mute_only_active(struct confbridge_conference *conference);
+void conf_mute_only_active(struct conference_bridge *conference_bridge);
 
 /*! \brief Callback to execute any time we transition from zero to one active users
- * \param conference The conference bridge with a single active user joined
+ * \param conference_bridge The conference bridge with a single active user joined
  * \retval 0 success
  * \retval -1 failure
  */
-void conf_handle_first_join(struct confbridge_conference *conference);
+void conf_handle_first_join(struct conference_bridge *conference_bridge);
 
 /*! \brief Handle actions every time a waitmarked user joins w/o a marked user present
- * \param user The waitmarked user
+ * \param cbu The waitmarked user
  * \retval 0 success
  * \retval -1 failure
  */
-int conf_handle_inactive_waitmarked(struct confbridge_user *user);
+int conf_handle_inactive_waitmarked(struct conference_bridge_user *cbu);
 
 /*! \brief Handle actions whenever an unmarked user joins an inactive conference
  * \note These actions seem like they could apply just as well to a marked user
  * and possibly be made to happen any time transitioning to a single state.
  *
- * \param user The unmarked user
+ * \param cbu The unmarked user
  */
-int conf_handle_only_unmarked(struct confbridge_user *user);
+int conf_handle_only_unmarked(struct conference_bridge_user *cbu);
 
 /*! \brief Handle when a conference moves to having more than one active participant
- * \param conference The conference bridge with more than one active participant
+ * \param conference_bridge The conference bridge with more than one active participant
  */
-void conf_handle_second_active(struct confbridge_conference *conference);
+void conf_handle_second_active(struct conference_bridge *conference_bridge);
 
 /*! \brief Add a conference bridge user as an unmarked active user of the conference
- * \param conference The conference bridge to add the user to
- * \param user The conference bridge user to add to the conference
+ * \param conference_bridge The conference bridge to add the user to
+ * \param cbu The conference bridge user to add to the conference
  */
-void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_add_user_active(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Add a conference bridge user as a marked active user of the conference
- * \param conference The conference bridge to add the user to
- * \param user The conference bridge user to add to the conference
+ * \param conference_bridge The conference bridge to add the user to
+ * \param cbu The conference bridge user to add to the conference
  */
-void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_add_user_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Add a conference bridge user as an waiting user of the conference
- * \param conference The conference bridge to add the user to
- * \param user The conference bridge user to add to the conference
+ * \param conference_bridge The conference bridge to add the user to
+ * \param cbu The conference bridge user to add to the conference
  */
-void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_add_user_waiting(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Remove a conference bridge user from the unmarked active conference users in the conference
- * \param conference The conference bridge to remove the user from
- * \param user The conference bridge user to remove from the conference
+ * \param conference_bridge The conference bridge to remove the user from
+ * \param cbu The conference bridge user to remove from the conference
  */
-void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_remove_user_active(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Remove a conference bridge user from the marked active conference users in the conference
- * \param conference The conference bridge to remove the user from
- * \param user The conference bridge user to remove from the conference
+ * \param conference_bridge The conference bridge to remove the user from
+ * \param cbu The conference bridge user to remove from the conference
  */
-void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_remove_user_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Remove a conference bridge user from the waiting conference users in the conference
- * \param conference The conference bridge to remove the user from
- * \param user The conference bridge user to remove from the conference
+ * \param conference_bridge The conference bridge to remove the user from
+ * \param cbu The conference bridge user to remove from the conference
  */
-void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user);
+void conf_remove_user_waiting(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu);
 
 /*! \brief Queue a function to run with the given conference bridge user as an argument once the state transition is complete
- * \param user The conference bridge user to pass to the function
+ * \param cbu The conference bridge user to pass to the function
  * \param func The function to queue
  * \retval 0 success
  * \retval non-zero failure
  */
-int conf_add_post_join_action(struct confbridge_user *user, int (*func)(struct confbridge_user *user));
-
-/*!
- * \since 12.0
- * \brief get the confbridge start stasis message type
- *
- * \retval stasis message type for confbridge start messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_start_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge end stasis message type
- *
- * \retval stasis message type for confbridge end messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_end_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge join stasis message type
- *
- * \retval stasis message type for confbridge join messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_join_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge leave stasis message type
- *
- * \retval stasis message type for confbridge leave messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_leave_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge start_record stasis message type
- *
- * \retval stasis message type for confbridge start_record messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_start_record_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge stop_record stasis message type
- *
- * \retval stasis message type for confbridge stop_record messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_stop_record_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge mute stasis message type
- *
- * \retval stasis message type for confbridge mute messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_mute_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge unmute stasis message type
- *
- * \retval stasis message type for confbridge unmute messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_unmute_type(void);
-
-/*!
- * \since 12.0
- * \brief get the confbridge talking stasis message type
- *
- * \retval stasis message type for confbridge talking messages if it's available
- * \retval NULL if it isn't
- */
-struct stasis_message_type *confbridge_talking_type(void);
-
-/*!
- * \since 12.0
- * \brief register stasis message routers to handle manager events for confbridge messages
- *
- * \retval 0 success
- * \retval non-zero failure
- */
-int manager_confbridge_init(void);
-
-/*!
- * \since 12.0
- * \brief unregister stasis message routers to handle manager events for confbridge messages
- */
-void manager_confbridge_shutdown(void);
-
-/*!
- * \brief Get ConfBridge record channel technology struct.
- * \since 12.0.0
- *
- * \return ConfBridge record channel technology.
- */
-struct ast_channel_tech *conf_record_get_tech(void);
-
-/*!
- * \brief Get ConfBridge announce channel technology struct.
- * \since 12.0.0
- *
- * \return ConfBridge announce channel technology.
- */
-struct ast_channel_tech *conf_announce_get_tech(void);
-
-/*!
- * \brief Remove the announcer channel from the conference.
- * \since 12.0.0
- *
- * \param chan Either channel in the announcer channel pair.
- *
- * \return Nothing
- */
-void conf_announce_channel_depart(struct ast_channel *chan);
-
-/*!
- * \brief Push the announcer channel into the conference.
- * \since 12.0.0
- *
- * \param ast Either channel in the announcer channel pair.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int conf_announce_channel_push(struct ast_channel *ast);
+int conf_add_post_join_action(struct conference_bridge_user *cbu, int (*func)(struct conference_bridge_user *cbu));
 #endif
diff --git a/asterisk-11.20.0-summary.html b/asterisk-11.20.0-summary.html
new file mode 100644
index 0000000..7dd92d9
--- /dev/null
+++ b/asterisk-11.20.0-summary.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-11.20.0</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-11.20.0</h3><h3 align="center">Date: 2015-10-09</h3><h3 align="center"><asteriskteam at digium.com></h3><hr><h2 align="center">Table of Contents</h2><ol>
+<li><a href="#summary">Summary</a></li>
+<li><a href="#contributors">Contributors</a></li>
+<li><a href="#closed_issues">Closed Issues</a></li>
+<li><a href="#open_issues">Open Issues</a></li>
+<li><a href="#commits">Other Changes</a></li>
+<li><a href="#diffstat">Diffstat</a></li>
+</ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version a [...]
+<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
+<tr valign="top"><td width="33%">26 Kevin Harwell <kharwell at lunkwill><br/>9 Richard Mudgett <rmudgett at digium.com><br/>8 Kevin Harwell <kharwell at lunkwill.digium.internal><br/>5 Joshua Colp <jcolp at digium.com><br/>3 David M. Lee <dlee at respoke.io><br/>2 Matt Jordan <mjordan at digium.com><br/>2 Mark Michelson <mmichelson at digium.com><br/>2 Alexander Anikin <may213 at yandex.ru><br/>1 Walter Doekes <walter+asterisk at wjd.nu><br/>1 Ivan Poddubny <ivan.poddubny at gmail.com><br/>1 Elazar Broad <elazar at theb [...]
+</table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Bug</h3><h4>Category: Addons/chan_ooh323</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25227">ASTERISK-25227</a>: No audio at in-band announcements in ooh323 channel<br/>Reported by: Alexandr Dranchuk<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=198a1cab8ed070fd077361ca931898850e7b0d49">[198a1cab8e]</a> Alexander Anikin -- chan_ooh323: Add ProgressIndicator IE with inband info available</li>
+</ul><br><h4>Category: Applications/app_queue</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25215">ASTERISK-25215</a>: Differences in queue.log between Set QUEUE_MEMBER and using PauseQueueMember<br/>Reported by: Lorne Gaetz<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=43150cc58d88a79017f930edff2ae8d62bb9bb79">[43150cc58d]</a> Richard Mudgett -- app_queue.c: Fix setting QUEUE_MEMBER 'paused' and 'ringinuse'.</li>
+</ul><br><h4>Category: Applications/app_record</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25410">ASTERISK-25410</a>: app_record: RECORDED_FILE variable not being populated<br/>Reported by: Kevin Harwell<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=455a31476bfe26a0cf3fdb186cdf9f0d6f0696ee">[455a31476b]</a> Kevin Harwell -- app_record: RECORDED_FILE variable not being populated</li>
+</ul><br><h4>Category: Channels/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25427">ASTERISK-25427</a>: Callerid change does not always emit NewCallerid AMI event<br/>Reported by: Ivan Poddubny<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8d2e1ecdca3291f0f82aac392bd68deec3c914e5">[8d2e1ecdca]</a> Ivan Poddubny -- channel.c: Fix NewCallerid AMI event not been sent on Caller ID change</li>
+</ul><br><h4>Category: Channels/chan_dahdi</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25315">ASTERISK-25315</a>: DAHDI channels send shortened duration DTMF tones.<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c777c9565dbcb8527f5a9b2dbc35e81c541101f1">[c777c9565d]</a> Richard Mudgett -- chan_dahdi.c: Flush the DAHDI write buffer after starting DTMF.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f43ea74e9eb18eaead46a08ac287ee5ce0ad798a">[f43ea74e9e]</a> Richard Mudgett -- chan_dahdi.c: Lock private struct for ast_write().</li>
+</ul><br><h4>Category: Channels/chan_sip/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25346">ASTERISK-25346</a>: chan_sip: Overwriting answered elsewhere hangup cause on call pickup<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=59636e82b2140993081837b0719bf6ad0ec41c40">[59636e82b2]</a> Joshua Colp -- chan_sip: Allow call pickup to set the hangup cause.</li>
+</ul><br><h4>Category: Channels/chan_sip/Interoperability</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25396">ASTERISK-25396</a>: chan_sip: Extremely long callerid name causes invalid SIP<br/>Reported by: Walter Doekes<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2fcf45e9cfc3a68ed4b37ba8cafdf73279f5aae7">[2fcf45e9cf]</a> Walter Doekes -- chan_sip: Fix From header truncation for extremely long CALLERID(name).</li>
+</ul><br><h4>Category: Channels/chan_sip/Security Framework</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25320">ASTERISK-25320</a>: chan_sip.c: sip_report_security_event searches for wrong or non existent peer on invite<br/>Reported by: Kevin Harwell<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=430db4333e25d4d1c101ed4a3473af320abb0145">[430db4333e]</a> Kevin Harwell -- chan_sip.c: wrong peer searched in sip_report_security_event</li>
+</ul><br><h4>Category: Codecs/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25353">ASTERISK-25353</a>: [patch] Transcoding while different in Frame size = Frames lost<br/>Reported by: Alexander Traud<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c7f8c8c35db2fe1c4ce9f27c4a28649452dc5463">[c7f8c8c35d]</a> Alexander Traud -- translate: Fix transcoding while different in frame size.</li>
+</ul><br><h4>Category: Core/BuildSystem</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25265">ASTERISK-25265</a>: [patch]DTLS Failure when calling WebRTC-peer on Firefox 39 - add ECDH support and fallback to prime256v1<br/>Reported by: Stefan Engström<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c7a1dca4baec5c2edec16470b377761066021650">[c7a1dca4ba]</a> Joshua Colp -- res_rtp_asterisk: Don't leak temporary key when enabling PFS.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2d2e7419054cb4b837fa9113f0f309e19fc690ee">[2d2e741905]</a> Mark Duncan -- res/res_rtp_asterisk: Add ECDH support</li>
+</ul><br><h4>Category: Core/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25449">ASTERISK-25449</a>: main/sched: Regression introduced by 5c713fdf18f causes erroneous duplicate RTCP messages; other potential scheduling issues in chan_sip/chan_skinny<br/>Reported by: Matt Jordan<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=984ff78ec7c568b3c4cee5f7e389ed908dfcada2">[984ff78ec7]</a> Matt Jordan -- res/res_rtp_asterisk: Fix assignment after ao2 decrement</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=33c945f471e92046d50cb35482f4d94e5ed86e86">[33c945f471]</a> Matt Jordan -- Fix improper usage of scheduler exposed by 5c713fdf18f</li>
+</ul><br><h4>Category: Core/Logging</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25407">ASTERISK-25407</a>: Asterisk fails to log to multiple syslog destinations<br/>Reported by: Elazar Broad<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=29694eb2aaa45c366fe28777722b0307f3742f95">[29694eb2aa]</a> Elazar Broad -- core/logging: Fix logging to more than one syslog channel</li>
+</ul><br><h4>Category: Core/PBX</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25394">ASTERISK-25394</a>: pbx: Incorrect device and presence state when changing hint details<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=51013b052d242717fce8b30bfba083721981b769">[51013b052d]</a> Joshua Colp -- pbx: Update device and presence state when changing a hint extension.</li>
+</ul><br><h4>Category: Resources/res_http_websocket</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25312">ASTERISK-25312</a>: res_http_websocket: Terminate connection on fatal cases<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b9bd3c1435cb1e7b09851de2c7dcc5882bc2f9f4">[b9bd3c1435]</a> Joshua Colp -- res_http_websocket: Forcefully terminate on write errors.</li>
+</ul><br><h4>Category: Resources/res_rtp_asterisk</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25438">ASTERISK-25438</a>: res_rtp_asterisk: ICE role message even when ICE is not enabled<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=72d3a65706a10f29d590d05a586ae0009d7b1807">[72d3a65706]</a> Joshua Colp -- res_rtp_asterisk: Move "Set role" warning to be debug.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25265">ASTERISK-25265</a>: [patch]DTLS Failure when calling WebRTC-peer on Firefox 39 - add ECDH support and fallback to prime256v1<br/>Reported by: Stefan Engström<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c7a1dca4baec5c2edec16470b377761066021650">[c7a1dca4ba]</a> Joshua Colp -- res_rtp_asterisk: Don't leak temporary key when enabling PFS.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2d2e7419054cb4b837fa9113f0f309e19fc690ee">[2d2e741905]</a> Mark Duncan -- res/res_rtp_asterisk: Add ECDH support</li>
+</ul><br><h3>Improvement</h3><h4>Category: Core/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25310">ASTERISK-25310</a>: [patch]on FreeBSD also pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED<br/>Reported by: Guido Falsi<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ffa26a0c2e88ab294e6f0407faa71cc053a4e511">[ffa26a0c2e]</a> Guido Falsi -- Core/General: Add #ifdef needed on FreeBSD.</li>
+</ul><br><hr><a name="open_issues"><h2 align="center">Open Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all open issues from the issue tracker that were referenced by changes that went into this release.</p><h3>Bug</h3><h4>Category: Addons/chan_ooh323</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25299">ASTERISK-25299</a>: RTP port leaks with incoming OOH323 calls<br/>Reported by: Alexandr Dranchuk<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=07b25a2312efecdfc4aeccaf8742782e714ff358">[07b25a2312]</a> Alexander Anikin -- chan_ooh323: call ast_rtp_instance_stop on ooh323_destroy</li>
+</ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
+<tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cf32d3dd190da24c6db0e90a3111a8ada3903ca4">cf32d3dd19</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=aa049e16e5ce68b6affb8b6ffe3118c157dfe274">aa049e16e5</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=625fc1fc2cc3d3af3acf48ed9679d4c885427b12">625fc1fc2c</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5f8c0fb6c92b2ce0e3d963458c88ac4a1f3fdad3">5f8c0fb6c9</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5638b89f37d182a0972526ab767225b2983e843d">5638b89f37</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5ab7cac6e2ecf11f6930b7f0da64bd496280c75f">5ab7cac6e2</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5130fa4854fb96b32bb7d6fef5cd8321ab4acf3d">5130fa4854</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=779180b1f495040707f91b8f3abfee9136fa66e4">779180b1f4</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4980a406a1c4f6f147917fcec8ef445d918fc1cb">4980a406a1</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ad4e9103687872c0022c3be8bc9bae07fe8eb317">ad4e910368</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1b7a210bb849bd8904f1d08f00effb2f24dfb9e9">1b7a210bb8</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=edd82562ba527cf1d2ee271e76f43a75a8f5d9fc">edd82562ba</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=495a482281fc5ffd3fcc8081863042f689f64cd5">495a482281</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=74b5c009bc79a281d6b3ec9330afd8744bdd6682">74b5c009bc</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7f4408940e7bf96d4d5f7b81c74d6982b60021ff">7f4408940e</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=38d8bb41e4f93d3b7c1fbc84ee379e6cfe58c6aa">38d8bb41e4</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=25a701c39822e140aca4d9bf030adf710040b7d7">25a701c398</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1fb284225e9e77ba7f1b29b766b003431f18f475">1fb284225e</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=96430103568e298023df2529c01de4e97d436d58">9643010356</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ac23a5511dc3989e75665974c8de62be6dc1bdf7">ac23a5511d</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5036db7bad82a24874377a70d8a9132a6e24229a">5036db7bad</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ab3078d6643f9610f4b050e8f57687918d6a384b">ab3078d664</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=502b4c978671a9b38c9b8d1bc5ae1e235e65b9fd">502b4c9786</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8aae2a474513d7eddb432e04f73e10614c9280bb">8aae2a4745</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0-rc3</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a42c71a4a48d968e0fc931f9c90a25a48c2c0dec">a42c71a4a4</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0-rc3</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=01c9b5457cad9b7ff89da9f78b277e1a96f784ec">01c9b5457c</a></td><td>Kevin Harwell</td><td>Release summaries: Remove previous versions</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7d711312895f62c50beb43ef278b98e959a6cb43">7d71131289</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0-rc3</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=19fea938160d84a3328627c26a84e2927cbc37b7">19fea93816</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0-rc3</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e93726aec2cf7330c96843679bb6984469cfe5af">e93726aec2</a></td><td>Kevin Harwell</td><td>ChangeLog: Updated for 11.20.0-rc1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e4ef76777f084eba6474df18a80e516d86310216">e4ef76777f</a></td><td>Kevin Harwell</td><td>Release summaries: Add summaries for 11.20.0-rc1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=db337a8a50633167fced3c197372e1234a6ce67a">db337a8a50</a></td><td>Kevin Harwell</td><td>.version: Update for 11.20.0-rc1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1db02c4e569935b233215ba10d81499e18880abc">1db02c4e56</a></td><td>Kevin Harwell</td><td>.lastclean: Update for 11.20.0-rc1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3cf0f293101cb8f044b3b1b57e3ecaaaf47365bf">3cf0f29310</a></td><td>Mark Michelson</td><td>scheduler: Use queue for allocating sched IDs.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=819760baece744384b7bba992738b002d50236e6">819760baec</a></td><td>David M. Lee</td><td>res_rtp_asterisk: Add more ICE debugging</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=94b764c8f3e771c100154303c38949beaed9ea42">94b764c8f3</a></td><td>David M. Lee</td><td>Fix when remote candidates exceed PJ_ICE_MAX_CAND</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6a364807f4b9016d0ccda9d67f1accacee7cbca5">6a364807f4</a></td><td>Richard Mudgett</td><td>app_queue.c: Extract some functions for simpler code.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a56da797d96bb797825b8c5029f597e1472050cc">a56da797d9</a></td><td>Richard Mudgett</td><td>app_queue.c: Fix error checking in QUEUE_MEMBER() read.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=06b464ab1b7c42e3c1b5b05463d5bc73c112dd76">06b464ab1b</a></td><td>David M. Lee</td><td>Replace htobe64 with htonll</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5311d18101b9a1a20cb9b86a7102a1c7a0b1df28">5311d18101</a></td><td>Richard Mudgett</td><td>chan_sip.c: Move NULL check to where it will do some good.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=75185c5d8f40e1bba48e15b566e4974967b261f6">75185c5d8f</a></td><td>Richard Mudgett</td><td>rtp_engine.c: Fix off nominal ref leak and some minor tweaks.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1b51b5efb619eb29c67ed5be0f4ab6d0793760d5">1b51b5efb6</a></td><td>Richard Mudgett</td><td>rtp_engine.c: Tweak glue->update_peer() parameter nil value.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f5cd1fa0df0b8ed9aa7736419f2b066c909bcadb">f5cd1fa0df</a></td><td>Richard Mudgett</td><td>chan_sip.c: Tweak glue->update_peer() parameter nil value.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f2089dce3dd972c147328cf8e7df5c756ee272b0">f2089dce3d</a></td><td>Mark Michelson</td><td>res_http_websocket: Properly encode 64 bit payload</td></tr>
+</table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>asterisk-11.19.0-summary.html            |  139 ------
+asterisk-11.19.0-summary.txt             |  445 ----------------------
+b/.version                               |    2
+b/ChangeLog                              |  627 ++++++++++++++++++++++++++++++-
+b/addons/chan_ooh323.c                   |    1
+b/addons/ooh323c/src/ooq931.c            |    6
+b/apps/app_queue.c                       |  432 +++++++++++----------
+b/apps/app_record.c                      |    3
+b/channels/chan_dahdi.c                  |   59 ++
+b/channels/chan_sip.c                    |   81 ++--
+b/channels/chan_skinny.c                 |   18
+b/channels/sip/include/security_events.h |    3
+b/channels/sip/security_events.c         |    5
+b/codecs/codec_gsm.c                     |   29 -
+b/codecs/codec_ilbc.c                    |   28 -
+b/codecs/codec_lpc10.c                   |   41 +-
+b/codecs/codec_speex.c                   |   61 +--
+b/configure                              |   63 +++
+b/configure.ac                           |    6
+b/contrib/scripts/install_prereq         |    2
+b/include/asterisk/autoconfig.h.in       |    3
+b/main/channel.c                         |   25 -
+b/main/logger.c                          |    7
+b/main/pbx.c                             |  129 ++++++
+b/main/rtp_engine.c                      |   20
+b/main/sched.c                           |  171 ++++++--
+b/main/translate.c                       |   53 +-
+b/main/utils.c                           |    4
+b/res/res_http_websocket.c               |   36 +
+b/res/res_rtp_asterisk.c                 |   44 +-
+30 files changed, 1552 insertions(+), 991 deletions(-)</pre><br></html>
\ No newline at end of file
diff --git a/asterisk-11.20.0-summary.txt b/asterisk-11.20.0-summary.txt
new file mode 100644
index 0000000..6ecc1f1
--- /dev/null
+++ b/asterisk-11.20.0-summary.txt
@@ -0,0 +1,399 @@
+                                Release Summary
+
+                                asterisk-11.20.0
+
+                                Date: 2015-10-09
+
+                           <asteriskteam at digium.com>
+
+     ----------------------------------------------------------------------
+
+                               Table of Contents
+
+    1. Summary
+    2. Contributors
+    3. Closed Issues
+    4. Open Issues
+    5. Other Changes
+    6. Diffstat
+
+     ----------------------------------------------------------------------
+
+                                    Summary
+
+                                 [Back to Top]
+
+   This release is a point release of an existing major version. The changes
+   included were made to address problems that have been identified in this
+   release series, or are minor, backwards compatible new features or
+   improvements. Users should be able to safely upgrade to this version if
+   this release series is already in use. Users considering upgrading from a
+   previous version are strongly encouraged to review the UPGRADE.txt
+   document as well as the CHANGES document for information about upgrading
+   to this release series.
+
+   The data in this summary reflects changes that have been made since the
+   previous release, asterisk-11.19.0.
+
+     ----------------------------------------------------------------------
+
+                                  Contributors
+
+                                 [Back to Top]
+
+   This table lists the people who have submitted code, those that have
+   tested patches, as well as those that reported issues on the issue tracker
+   that were resolved in this release. For coders, the number is how many of
+   their patches (of any size) were committed into this release. For testers,
+   the number is the number of times their name was listed as assisting with
+   testing a patch. Finally, for reporters, the number is the number of
+   issues that they reported that were affected by commits that went into
+   this release.
+
+   Coders                   Testers                  Reporters                
+   26 Kevin Harwell         1 Elazar Broad           4 Joshua Colp            
+   9 Richard Mudgett                                 2 Stefan EngstrAP:m      
+   8 Kevin Harwell                                   2 Matt Jordan            
+   5 Joshua Colp                                     2 Richard Mudgett        
+   3 David M. Lee                                    2 John Hardin            
+   2 Matt Jordan                                     2 Alexandr Dranchuk      
+   2 Mark Michelson                                  2 Kevin Harwell          
+   2 Alexander Anikin                                1 Guido Falsi            
+   1 Walter Doekes                                   1 Walter Doekes          
+   1 Ivan Poddubny                                   1 Kevin Harwell          
+   1 Elazar Broad                                    1 Ivan Poddubny          
+   1 Mark Duncan                                     1 Ivan Poddubny          
+   1 Scott Griepentrog                               1 Elazar Broad           
+   1 Guido Falsi                                     1 Lorne Gaetz            
+   1 Alexander Traud                                 1 Scott Griepentrog      
+                                                     1 Elazar Broad           
+                                                     1 Guido Falsi            
+                                                     1 Lorne Gaetz            
+                                                     1 Alexandr Dranchuk      
+                                                     1 Alexander Traud        
+
+     ----------------------------------------------------------------------
+
+                                 Closed Issues
+
+                                 [Back to Top]
+
+   This is a list of all issues from the issue tracker that were closed by
+   changes that went into this release.
+
+  Bug
+
+    Category: Addons/chan_ooh323
+
+   ASTERISK-25227: No audio at in-band announcements in ooh323 channel
+   Reported by: Alexandr Dranchuk
+     * [198a1cab8e] Alexander Anikin -- chan_ooh323: Add ProgressIndicator IE
+       with inband info available
+
+    Category: Applications/app_queue
+
+   ASTERISK-25215: Differences in queue.log between Set QUEUE_MEMBER and
+   using PauseQueueMember
+   Reported by: Lorne Gaetz
+     * [43150cc58d] Richard Mudgett -- app_queue.c: Fix setting QUEUE_MEMBER
+       'paused' and 'ringinuse'.
+
+    Category: Applications/app_record
+
+   ASTERISK-25410: app_record: RECORDED_FILE variable not being populated
+   Reported by: Kevin Harwell
+     * [455a31476b] Kevin Harwell -- app_record: RECORDED_FILE variable not
+       being populated
+
+    Category: Channels/General
+
+   ASTERISK-25427: Callerid change does not always emit NewCallerid AMI event
+   Reported by: Ivan Poddubny
+     * [8d2e1ecdca] Ivan Poddubny -- channel.c: Fix NewCallerid AMI event not
+       been sent on Caller ID change
+
+    Category: Channels/chan_dahdi
+
+   ASTERISK-25315: DAHDI channels send shortened duration DTMF tones.
+   Reported by: Richard Mudgett
+     * [c777c9565d] Richard Mudgett -- chan_dahdi.c: Flush the DAHDI write
+       buffer after starting DTMF.
+     * [f43ea74e9e] Richard Mudgett -- chan_dahdi.c: Lock private struct for
+       ast_write().
+
+    Category: Channels/chan_sip/General
+
+   ASTERISK-25346: chan_sip: Overwriting answered elsewhere hangup cause on
+   call pickup
+   Reported by: Joshua Colp
+     * [59636e82b2] Joshua Colp -- chan_sip: Allow call pickup to set the
+       hangup cause.
+
+    Category: Channels/chan_sip/Interoperability
+
+   ASTERISK-25396: chan_sip: Extremely long callerid name causes invalid SIP
+   Reported by: Walter Doekes
+     * [2fcf45e9cf] Walter Doekes -- chan_sip: Fix From header truncation for
+       extremely long CALLERID(name).
+
+    Category: Channels/chan_sip/Security Framework
+
+   ASTERISK-25320: chan_sip.c: sip_report_security_event searches for wrong
+   or non existent peer on invite
+   Reported by: Kevin Harwell
+     * [430db4333e] Kevin Harwell -- chan_sip.c: wrong peer searched in
+       sip_report_security_event
+
+    Category: Codecs/General
+
+   ASTERISK-25353: [patch] Transcoding while different in Frame size = Frames
+   lost
+   Reported by: Alexander Traud
+     * [c7f8c8c35d] Alexander Traud -- translate: Fix transcoding while
+       different in frame size.
+
+    Category: Core/BuildSystem
+
+   ASTERISK-25265: [patch]DTLS Failure when calling WebRTC-peer on Firefox 39
+   - add ECDH support and fallback to prime256v1
+   Reported by: Stefan EngstrAP:m
+     * [c7a1dca4ba] Joshua Colp -- res_rtp_asterisk: Don't leak temporary key
+       when enabling PFS.
+     * [2d2e741905] Mark Duncan -- res/res_rtp_asterisk: Add ECDH support
+
+    Category: Core/General
+
+   ASTERISK-25449: main/sched: Regression introduced by 5c713fdf18f causes
+   erroneous duplicate RTCP messages; other potential scheduling issues in
+   chan_sip/chan_skinny
+   Reported by: Matt Jordan
+     * [984ff78ec7] Matt Jordan -- res/res_rtp_asterisk: Fix assignment after
+       ao2 decrement
+     * [33c945f471] Matt Jordan -- Fix improper usage of scheduler exposed by
+       5c713fdf18f
+
+    Category: Core/Logging
+
+   ASTERISK-25407: Asterisk fails to log to multiple syslog destinations
+   Reported by: Elazar Broad
+     * [29694eb2aa] Elazar Broad -- core/logging: Fix logging to more than
+       one syslog channel
+
+    Category: Core/PBX
+
+   ASTERISK-25394: pbx: Incorrect device and presence state when changing
+   hint details
+   Reported by: Joshua Colp
+     * [51013b052d] Joshua Colp -- pbx: Update device and presence state when
+       changing a hint extension.
+
+    Category: Resources/res_http_websocket
+
+   ASTERISK-25312: res_http_websocket: Terminate connection on fatal cases
+   Reported by: Joshua Colp
+     * [b9bd3c1435] Joshua Colp -- res_http_websocket: Forcefully terminate
+       on write errors.
+
+    Category: Resources/res_rtp_asterisk
+
+   ASTERISK-25438: res_rtp_asterisk: ICE role message even when ICE is not
+   enabled
+   Reported by: Joshua Colp
+     * [72d3a65706] Joshua Colp -- res_rtp_asterisk: Move "Set role" warning
+       to be debug.
+   ASTERISK-25265: [patch]DTLS Failure when calling WebRTC-peer on Firefox 39
+   - add ECDH support and fallback to prime256v1
+   Reported by: Stefan EngstrAP:m
+     * [c7a1dca4ba] Joshua Colp -- res_rtp_asterisk: Don't leak temporary key
+       when enabling PFS.
+     * [2d2e741905] Mark Duncan -- res/res_rtp_asterisk: Add ECDH support
+
+  Improvement
+
+    Category: Core/General
+
+   ASTERISK-25310: [patch]on FreeBSD also pthread_attr_init() defaults to
+   PTHREAD_EXPLICIT_SCHED
+   Reported by: Guido Falsi
+     * [ffa26a0c2e] Guido Falsi -- Core/General: Add #ifdef needed on
+       FreeBSD.
+
+     ----------------------------------------------------------------------
+
+                                  Open Issues
+
+                                 [Back to Top]
+
+   This is a list of all open issues from the issue tracker that were
+   referenced by changes that went into this release.
+
+  Bug
+
+    Category: Addons/chan_ooh323
+
+   ASTERISK-25299: RTP port leaks with incoming OOH323 calls
+   Reported by: Alexandr Dranchuk
+     * [07b25a2312] Alexander Anikin -- chan_ooh323: call
+       ast_rtp_instance_stop on ooh323_destroy
+
+     ----------------------------------------------------------------------
+
+                      Commits Not Associated with an Issue
+
+                                 [Back to Top]
+
+   This is a list of all changes that went into this release that did not
+   reference a JIRA issue.
+
+   +------------------------------------------------------------------------+
+   | Revision   | Author          | Summary                                 |
+   |------------+-----------------+-----------------------------------------|
+   | cf32d3dd19 | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | aa049e16e5 | Kevin Harwell   | .version: Update for 11.20.0            |
+   |------------+-----------------+-----------------------------------------|
+   | 625fc1fc2c | Kevin Harwell   | .lastclean: Update for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 5f8c0fb6c9 | Kevin Harwell   | ChangeLog: Updated for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 5638b89f37 | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0                                 |
+   |------------+-----------------+-----------------------------------------|
+   | 5ab7cac6e2 | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | 5130fa4854 | Kevin Harwell   | .version: Update for 11.20.0            |
+   |------------+-----------------+-----------------------------------------|
+   | 779180b1f4 | Kevin Harwell   | .lastclean: Update for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 4980a406a1 | Kevin Harwell   | ChangeLog: Updated for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | ad4e910368 | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0                                 |
+   |------------+-----------------+-----------------------------------------|
+   | 1b7a210bb8 | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | edd82562ba | Kevin Harwell   | .version: Update for 11.20.0            |
+   |------------+-----------------+-----------------------------------------|
+   | 495a482281 | Kevin Harwell   | .lastclean: Update for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 74b5c009bc | Kevin Harwell   | ChangeLog: Updated for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 7f4408940e | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0                                 |
+   |------------+-----------------+-----------------------------------------|
+   | 38d8bb41e4 | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | 25a701c398 | Kevin Harwell   | .version: Update for 11.20.0            |
+   |------------+-----------------+-----------------------------------------|
+   | 1fb284225e | Kevin Harwell   | .lastclean: Update for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 9643010356 | Kevin Harwell   | ChangeLog: Updated for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | ac23a5511d | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0                                 |
+   |------------+-----------------+-----------------------------------------|
+   | 5036db7bad | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | ab3078d664 | Kevin Harwell   | .version: Update for 11.20.0            |
+   |------------+-----------------+-----------------------------------------|
+   | 502b4c9786 | Kevin Harwell   | .lastclean: Update for 11.20.0          |
+   |------------+-----------------+-----------------------------------------|
+   | 8aae2a4745 | Kevin Harwell   | ChangeLog: Updated for 11.20.0-rc3      |
+   |------------+-----------------+-----------------------------------------|
+   | a42c71a4a4 | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0-rc3                             |
+   |------------+-----------------+-----------------------------------------|
+   | 01c9b5457c | Kevin Harwell   | Release summaries: Remove previous      |
+   |            |                 | versions                                |
+   |------------+-----------------+-----------------------------------------|
+   | 7d71131289 | Kevin Harwell   | .version: Update for 11.20.0-rc3        |
+   |------------+-----------------+-----------------------------------------|
+   | 19fea93816 | Kevin Harwell   | .lastclean: Update for 11.20.0-rc3      |
+   |------------+-----------------+-----------------------------------------|
+   | e93726aec2 | Kevin Harwell   | ChangeLog: Updated for 11.20.0-rc1      |
+   |------------+-----------------+-----------------------------------------|
+   | e4ef76777f | Kevin Harwell   | Release summaries: Add summaries for    |
+   |            |                 | 11.20.0-rc1                             |
+   |------------+-----------------+-----------------------------------------|
+   | db337a8a50 | Kevin Harwell   | .version: Update for 11.20.0-rc1        |
+   |------------+-----------------+-----------------------------------------|
+   | 1db02c4e56 | Kevin Harwell   | .lastclean: Update for 11.20.0-rc1      |
+   |------------+-----------------+-----------------------------------------|
+   | 3cf0f29310 | Mark Michelson  | scheduler: Use queue for allocating     |
+   |            |                 | sched IDs.                              |
+   |------------+-----------------+-----------------------------------------|
+   | 819760baec | David M. Lee    | res_rtp_asterisk: Add more ICE          |
+   |            |                 | debugging                               |
+   |------------+-----------------+-----------------------------------------|
+   | 94b764c8f3 | David M. Lee    | Fix when remote candidates exceed       |
+   |            |                 | PJ_ICE_MAX_CAND                         |
+   |------------+-----------------+-----------------------------------------|
+   | 6a364807f4 | Richard Mudgett | app_queue.c: Extract some functions for |
+   |            |                 | simpler code.                           |
+   |------------+-----------------+-----------------------------------------|
+   | a56da797d9 | Richard Mudgett | app_queue.c: Fix error checking in      |
+   |            |                 | QUEUE_MEMBER() read.                    |
+   |------------+-----------------+-----------------------------------------|
+   | 06b464ab1b | David M. Lee    | Replace htobe64 with htonll             |
+   |------------+-----------------+-----------------------------------------|
+   | 5311d18101 | Richard Mudgett | chan_sip.c: Move NULL check to where it |
+   |            |                 | will do some good.                      |
+   |------------+-----------------+-----------------------------------------|
+   | 75185c5d8f | Richard Mudgett | rtp_engine.c: Fix off nominal ref leak  |
+   |            |                 | and some minor tweaks.                  |
+   |------------+-----------------+-----------------------------------------|
+   | 1b51b5efb6 | Richard Mudgett | rtp_engine.c: Tweak glue->update_peer() |
+   |            |                 | parameter nil value.                    |
+   |------------+-----------------+-----------------------------------------|
+   | f5cd1fa0df | Richard Mudgett | chan_sip.c: Tweak glue->update_peer()   |
+   |            |                 | parameter nil value.                    |
+   |------------+-----------------+-----------------------------------------|
+   | f2089dce3d | Mark Michelson  | res_http_websocket: Properly encode 64  |
+   |            |                 | bit payload                             |
+   +------------------------------------------------------------------------+
+
+     ----------------------------------------------------------------------
+
+                                Diffstat Results
+
+                                 [Back to Top]
+
+   This is a summary of the changes to the source code that went into this
+   release that was generated using the diffstat utility.
+
+ asterisk-11.19.0-summary.html            |  139 ------
+ asterisk-11.19.0-summary.txt             |  445 ----------------------
+ b/.version                               |    2
+ b/ChangeLog                              |  627 ++++++++++++++++++++++++++++++-
+ b/addons/chan_ooh323.c                   |    1
+ b/addons/ooh323c/src/ooq931.c            |    6
+ b/apps/app_queue.c                       |  432 +++++++++++----------
+ b/apps/app_record.c                      |    3
+ b/channels/chan_dahdi.c                  |   59 ++
+ b/channels/chan_sip.c                    |   81 ++--
+ b/channels/chan_skinny.c                 |   18
+ b/channels/sip/include/security_events.h |    3
+ b/channels/sip/security_events.c         |    5
+ b/codecs/codec_gsm.c                     |   29 -
+ b/codecs/codec_ilbc.c                    |   28 -
+ b/codecs/codec_lpc10.c                   |   41 +-
+ b/codecs/codec_speex.c                   |   61 +--
+ b/configure                              |   63 +++
+ b/configure.ac                           |    6
+ b/contrib/scripts/install_prereq         |    2
+ b/include/asterisk/autoconfig.h.in       |    3
+ b/main/channel.c                         |   25 -
+ b/main/logger.c                          |    7
+ b/main/pbx.c                             |  129 ++++++
+ b/main/rtp_engine.c                      |   20
+ b/main/sched.c                           |  171 ++++++--
+ b/main/translate.c                       |   53 +-
+ b/main/utils.c                           |    4
+ b/res/res_http_websocket.c               |   36 +
+ b/res/res_rtp_asterisk.c                 |   44 +-
+ 30 files changed, 1552 insertions(+), 991 deletions(-)
diff --git a/asterisk-13.1.1-summary.html b/asterisk-13.1.1-summary.html
deleted file mode 100644
index e1f0e59..0000000
--- a/asterisk-13.1.1-summary.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Release Summary - asterisk-13.1.1</title></head>
-<body>
-<h1 align="center"><a name="top">Release Summary</a></h1>
-<h3 align="center">asterisk-13.1.1</h3>
-<h3 align="center">Date: 2015-01-28</h3>
-<h3 align="center"><asteriskteam at digium.com></h3>
-<hr/>
-<h2 align="center">Table of Contents</h2>
-<ol>
-   <li><a href="#summary">Summary</a></li>
-   <li><a href="#contributors">Contributors</a></li>
-   <li><a href="#commits">Other Changes</a></li>
-   <li><a href="#diffstat">Diffstat</a></li>
-</ol>
-<hr/>
-<a name="summary"><h2 align="center">Summary</h2></a>
-<center><a href="#top">[Back to Top]</a></center><br/><p>This release has been made to address one or more security vulnerabilities that have been identified.  A security advisory document has been published for each vulnerability that includes additional information.  Users of versions of Asterisk that are affected are strongly encouraged to review the advisories and determine what action they should take to protect their systems from these issues.</p>
-<p>Security Advisories: <a href="http://downloads.asterisk.org/pub/security/AST-2015-001.html">AST-2015-001</a>, <a href="http://downloads.asterisk.org/pub/security/AST-2015-002.html">AST-2015-002</a></p>
-<p>The data in this summary reflects changes that have been made since the previous release, asterisk-13.1.0.</p>
-<hr/>
-<a name="contributors"><h2 align="center">Contributors</h2></a>
-<center><a href="#top">[Back to Top]</a></center><br/><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release.  For coders, the number is how many of their patches (of any size) were committed into this release.  For testers, the number is the number of times their name was listed as assisting with testing a patch.  Finally, for reporters, the number is the number [...]
-<table width="100%" border="0">
-<tr>
-<td width="33%"><h3>Coders</h3></td>
-<td width="33%"><h3>Testers</h3></td>
-<td width="33%"><h3>Reporters</h3></td>
-</tr>
-<tr valign="top">
-<td>
-3 bebuild<br/>
-</td>
-<td>
-</td>
-<td>
-</td>
-</tr>
-</table>
-<hr/>
-<a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a>
-<center><a href="#top">[Back to Top]</a></center><br/><p>This is a list of all changes that went into this release that did not directly close an issue from the issue tracker.  The commits may have been marked as being related to an issue.  If that is the case, the issue numbers are listed here, as well.</p>
-<table width="100%" border="1">
-<tr><td><b>Revision</b></td><td><b>Author</b></td><td><b>Summary</b></td><td><b>Issues Referenced</b></td></tr><tr><td><a href="http://svn.digium.com/view/asterisk/tags/13.1.1?view=revision&revision=431290">431290</a></td><td>bebuild</td><td>Create 13.1.1 tag</td>
-<td></td></tr><tr><td><a href="http://svn.digium.com/view/asterisk/tags/13.1.1?view=revision&revision=431296">431296</a></td><td>bebuild</td><td>Update .version; remove old summaries</td>
-<td></td></tr><tr><td><a href="http://svn.digium.com/view/asterisk/tags/13.1.1?view=revision&revision=431327">431327</a></td><td>bebuild</td><td>Merge r431301, 431303 for 13.1.1</td>
-<td></td></tr></table>
-<hr/>
-<a name="diffstat"><h2 align="center">Diffstat Results</h2></a>
-<center><a href="#top">[Back to Top]</a></center><br/><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p>
-<pre>
-.version                     |    2
-ChangeLog                    |   35 +
-asterisk-13.1.0-summary.html |  747 ---------------------------------
-asterisk-13.1.0-summary.txt  |  947 -------------------------------------------
-funcs/func_curl.c            |   83 +++
-res/res_pjsip_sdp_rtp.c      |    1
-res/res_pjsip_session.c      |   60 ++
-res/res_pjsip_t38.c          |    1
-8 files changed, 173 insertions(+), 1703 deletions(-)
-</pre><br/>
-<hr/>
-</body>
-</html>
diff --git a/asterisk-13.1.1-summary.txt b/asterisk-13.1.1-summary.txt
deleted file mode 100644
index f48a6f5..0000000
--- a/asterisk-13.1.1-summary.txt
+++ /dev/null
@@ -1,96 +0,0 @@
-                                Release Summary
-
-                                asterisk-13.1.1
-
-                                Date: 2015-01-28
-
-                           <asteriskteam at digium.com>
-
-     ----------------------------------------------------------------------
-
-                               Table of Contents
-
-    1. Summary
-    2. Contributors
-    3. Other Changes
-    4. Diffstat
-
-     ----------------------------------------------------------------------
-
-                                    Summary
-
-                                 [Back to Top]
-
-   This release has been made to address one or more security vulnerabilities
-   that have been identified. A security advisory document has been published
-   for each vulnerability that includes additional information. Users of
-   versions of Asterisk that are affected are strongly encouraged to review
-   the advisories and determine what action they should take to protect their
-   systems from these issues.
-
-   Security Advisories: AST-2015-001, AST-2015-002
-
-   The data in this summary reflects changes that have been made since the
-   previous release, asterisk-13.1.0.
-
-     ----------------------------------------------------------------------
-
-                                  Contributors
-
-                                 [Back to Top]
-
-   This table lists the people who have submitted code, those that have
-   tested patches, as well as those that reported issues on the issue tracker
-   that were resolved in this release. For coders, the number is how many of
-   their patches (of any size) were committed into this release. For testers,
-   the number is the number of times their name was listed as assisting with
-   testing a patch. Finally, for reporters, the number is the number of
-   issues that they reported that were closed by commits that went into this
-   release.
-
-     Coders                   Testers                  Reporters              
-   3 bebuild                
-
-     ----------------------------------------------------------------------
-
-                      Commits Not Associated with an Issue
-
-                                 [Back to Top]
-
-   This is a list of all changes that went into this release that did not
-   directly close an issue from the issue tracker. The commits may have been
-   marked as being related to an issue. If that is the case, the issue
-   numbers are listed here, as well.
-
-   +------------------------------------------------------------------------+
-   | Revision | Author  | Summary                       | Issues Referenced |
-   |----------+---------+-------------------------------+-------------------|
-   | 431290   | bebuild | Create 13.1.1 tag             |                   |
-   |----------+---------+-------------------------------+-------------------|
-   | 431296   | bebuild | Update .version; remove old   |                   |
-   |          |         | summaries                     |                   |
-   |----------+---------+-------------------------------+-------------------|
-   | 431327   | bebuild | Merge r431301, 431303 for     |                   |
-   |          |         | 13.1.1                        |                   |
-   +------------------------------------------------------------------------+
-
-     ----------------------------------------------------------------------
-
-                                Diffstat Results
-
-                                 [Back to Top]
-
-   This is a summary of the changes to the source code that went into this
-   release that was generated using the diffstat utility.
-
- .version                     |    2
- ChangeLog                    |   35 +
- asterisk-13.1.0-summary.html |  747 ---------------------------------
- asterisk-13.1.0-summary.txt  |  947 -------------------------------------------
- funcs/func_curl.c            |   83 +++
- res/res_pjsip_sdp_rtp.c      |    1
- res/res_pjsip_session.c      |   60 ++
- res/res_pjsip_t38.c          |    1
- 8 files changed, 173 insertions(+), 1703 deletions(-)
-
-     ----------------------------------------------------------------------
diff --git a/autoconf/ast_check_raii.m4 b/autoconf/ast_check_raii.m4
new file mode 100644
index 0000000..e39a43d
--- /dev/null
+++ b/autoconf/ast_check_raii.m4
@@ -0,0 +1,56 @@
+dnl check RAII requirements
+dnl
+dnl gcc / llvm-gcc: -fnested-functions
+dnl clang : -fblocks / -fblocks and -lBlocksRuntime"
+AC_DEFUN([AST_CHECK_RAII], [
+	AC_MSG_CHECKING([for RAII support])
+	AST_C_COMPILER_FAMILY=""
+	AC_LINK_IFELSE(
+		[AC_LANG_PROGRAM([], [
+			int main() {
+				#if defined(__clang__)
+				choke
+				#endif
+				return 0;
+			}
+			])
+		],[
+			dnl Nested functions required for RAII implementation
+			AC_MSG_CHECKING(for gcc -fnested-functions)
+			AC_COMPILE_IFELSE(
+				dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
+				[
+					AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])
+				],[
+					AST_NESTED_FUNCTIONS=""
+					AC_MSG_RESULT(no)
+				],[
+					AST_NESTED_FUNCTIONS="-fnested-functions"
+					AC_MSG_RESULT(yes)
+				]
+			)
+			AC_SUBST(AST_NESTED_FUNCTIONS)
+			AST_C_COMPILER_FAMILY="gcc"
+		],[
+			AC_MSG_CHECKING(for clang -fblocks)
+			if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS=""
+				AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+				AC_MSG_RESULT(yes)
+			elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+				AST_CLANG_BLOCKS="-fblocks"
+				AC_MSG_RESULT(yes)
+			else
+				AC_MSG_ERROR([BlocksRuntime is required for clang, please install libblocksruntime])
+			fi
+			AC_SUBST(AST_CLANG_BLOCKS_LIBS)
+			AC_SUBST(AST_CLANG_BLOCKS)
+			AST_C_COMPILER_FAMILY="clang"
+		]
+	)
+	if test -z "${AST_C_COMPILER_FAMILY}"; then
+		AC_MSG_ERROR([Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev])
+	fi
+	AC_SUBST(AST_C_COMPILER_FAMILY)
+])
diff --git a/autoconf/ast_check_strsep_array_bounds.m4 b/autoconf/ast_check_strsep_array_bounds.m4
new file mode 100644
index 0000000..47a41e5
--- /dev/null
+++ b/autoconf/ast_check_strsep_array_bounds.m4
@@ -0,0 +1,81 @@
+dnl macro AST_CHECK_STRSEP_ARRAY_BOUNDS0
+dnl
+dnl The optimized strcmp and strsep macro's in
+dnl /usr/include/xxx-linux-gnu/bits/string2.h produce a warning (-Warray-bounds)
+dnl when compiled with clang (+ -O1), when the delimiter parameter is
+dnl passed in as a char *, instead of the expected char[]
+dnl
+dnl Instead of replacing all occurrences of strsep and strcmp, looking like:
+dnl xxx_name = strsep(&rest, ",");
+dnl
+dnl with:
+dnl char delimiters[] = ",";
+dnl xxx_name = strsep(&rest, delimiters);
+dnl
+dnl to get around this warning, without having to suppress the warning completely.
+dnl This macro detects the warning and force these 'optimizations' to be
+dnl switched off (Clang already has a set of builtin optimizers which should result
+dnl in good performance for these type of functions).
+dnl
+dnl When the issue is detected it will add a define to autoconfig.h which will prevent
+dnl bits/string2.h from replacing the standard implementation of strsep/strcmp with it's
+dnl macro optimized version. bits/string.h checks these defines before inserting it's
+dnl replacements.
+dnl
+dnl When bits/string2.h get's fixed in the future, this macro should be able to
+dnl detect the new behaviour, and when no warning is generated, it will use the optimize
+dnl version from bits/string2.h
+dnl
+dnl
+dnl See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h'
+dnl
+dnl llvm-comment: Normally, this array-bounds warning are suppressed for macros, so that
+dnl unused paths like the one that accesses __s1[3] are not warned about.  But if you
+dnl preprocess manually, and feed the result to another instance of clang, it will warn
+dnl about all the possible forks of this particular if statement.
+dnl
+dnl Instead of switching of this optimization, another solution would be to run the pre-
+dnl processing step with -frewrite-includes, which should preserve enough information
+dnl so that clang should still be able to suppress the diagnostic at the compile step
+dnl later on.
+dnl
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=11536"
+dnl
+AC_DEFUN([AST_CHECK_STRSEP_ARRAY_BOUNDS], [
+	AC_MSG_CHECKING([for clang strsep/strcmp optimization])
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+	AC_COMPILE_IFELSE(
+		[
+		    	AC_LANG_SOURCE([
+				#include <stdio.h>
+				#include <string.h>
+
+				/* fails with clang and -O1 */
+				void test_strsep_strcmp (void) {
+					char *haystackstr = "test1,test2";
+					char *outstr;
+					if (!strcmp(haystackstr, ",")) {
+						printf("fail\n");
+					}
+					if ((outstr = strsep(&haystackstr, ","))) {
+						printf("fail:%s\n", outstr);
+					}
+				}
+				int main(int argc, char *argv[]) {
+					test_strsep_strcmp();
+					return 0;
+				}
+			])
+		],[
+			AC_MSG_RESULT(no)
+		],[
+			dnl setting this define in autoconfig.h will prevent bits/string2.h from replacing the standard implementation of strsep/strcmp
+			AC_DEFINE([_HAVE_STRING_ARCH_strcmp], 1, [Prevent clang array-bounds warning by not using strcmp from bits/string2.h])
+			AC_DEFINE([_HAVE_STRING_ARCH_strsep], 1, [Prevent clang array-bounds warning by not using strsep from bits/string2.h])
+			AC_MSG_RESULT([prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h])
+		]
+	)
+	CFLAGS="$save_CFLAGS"
+])
diff --git a/autoconf/ast_ext_tool_check.m4 b/autoconf/ast_ext_tool_check.m4
index 758720d..da256c7 100644
--- a/autoconf/ast_ext_tool_check.m4
+++ b/autoconf/ast_ext_tool_check.m4
@@ -5,7 +5,6 @@
 # AST_EXT_TOOL_CHECK([package], [tool name], [--cflags], [--libs], [includes], [expression])
 AC_DEFUN([AST_EXT_TOOL_CHECK],
 [
-	AC_REQUIRE([AST_PROG_SED])dnl
 	if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
 		PBX_$1=0
 		AC_PATH_TOOL(CONFIG_$1, $2, No, [${$1_DIR}/bin:$PATH])
diff --git a/autoconf/ast_gcc_attribute.m4 b/autoconf/ast_gcc_attribute.m4
index bceaa28..4ade814 100644
--- a/autoconf/ast_gcc_attribute.m4
+++ b/autoconf/ast_gcc_attribute.m4
@@ -20,7 +20,7 @@ AC_COMPILE_IFELSE(
 )
 else
 AC_COMPILE_IFELSE(
-	[AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) {return (void *) 0;}],
+	[AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) ;],
 			[])],
 	AC_MSG_RESULT(yes)
 	m4_ifval([$4],$4=1)
diff --git a/bridges/Makefile b/bridges/Makefile
index d887ae1..90ed6c2 100644
--- a/bridges/Makefile
+++ b/bridges/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for bridging modules
 #
diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c
index b5a6316..823ef1c 100644
--- a/bridges/bridge_builtin_features.c
+++ b/bridges/bridge_builtin_features.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426552 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -41,475 +41,228 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426552 $")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
 #include "asterisk/frame.h"
 #include "asterisk/file.h"
 #include "asterisk/app.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/parking.h"
-#include "asterisk/features_config.h"
-#include "asterisk/monitor.h"
-#include "asterisk/mixmonitor.h"
-#include "asterisk/audiohook.h"
-#include "asterisk/causes.h"
-
-enum set_touch_variables_res {
-	SET_TOUCH_SUCCESS,
-	SET_TOUCH_UNSET,
-	SET_TOUCH_ALLOC_FAILURE,
-};
-
-static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
-{
-	const char *c_touch;
-
-	if (*res == SET_TOUCH_ALLOC_FAILURE) {
-		return;
-	}
-	c_touch = pbx_builtin_getvar_helper(chan, var_name);
-	if (!ast_strlen_zero(c_touch)) {
-		*touch = ast_strdup(c_touch);
-		if (!*touch) {
-			*res = SET_TOUCH_ALLOC_FAILURE;
-		} else {
-			*res = SET_TOUCH_SUCCESS;
-		}
-	}
-}
 
-static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
+/*! \brief Helper function that presents dialtone and grabs extension */
+static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
 {
-	enum set_touch_variables_res res = SET_TOUCH_UNSET;
-	const char *var_format;
-	const char *var_monitor;
-	const char *var_prefix;
+	int res;
 
-	SCOPED_CHANNELLOCK(lock, chan);
+	/* Play the simple "transfer" prompt out and wait */
+	res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
+	ast_stopstream(chan);
 
-	if (is_mixmonitor) {
-		var_format = "TOUCH_MIXMONITOR_FORMAT";
-		var_monitor = "TOUCH_MIXMONITOR";
-		var_prefix = "TOUCH_MIXMONITOR_PREFIX";
-	} else {
-		var_format = "TOUCH_MONITOR_FORMAT";
-		var_monitor = "TOUCH_MONITOR";
-		var_prefix = "TOUCH_MONITOR_PREFIX";
+	/* If the person hit a DTMF digit while the above played back stick it into the buffer */
+	if (res) {
+		exten[0] = (char)res;
 	}
-	set_touch_variable(&res, chan, var_format, touch_format);
-	set_touch_variable(&res, chan, var_monitor, touch_monitor);
-	set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
 
-	return res;
-}
+	/* Drop to dialtone so they can enter the extension they want to transfer to */
+	res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
 
-static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
-{
-	ast_verb(4, "AutoMonitor used to stop recording call.\n");
-
-	ast_channel_lock(peer_chan);
-	if (ast_channel_monitor(peer_chan)) {
-		if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
-			ast_verb(4, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
-			if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
-				ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-			}
-			ast_channel_unlock(peer_chan);
-			return;
-		}
-	} else {
-		/* Something else removed the Monitor before we got to it. */
-		ast_channel_unlock(peer_chan);
-		return;
-	}
-
-	ast_channel_unlock(peer_chan);
-
-	if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-	}
-
-	if (!ast_strlen_zero(stop_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
-	}
+	return res;
 }
 
-static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
+/*! \brief Helper function that creates an outgoing channel and returns it immediately */
+static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *exten, const char *context)
 {
-	char *touch_filename;
-	size_t len;
-	int x;
-	enum set_touch_variables_res set_touch_res;
-
-	RAII_VAR(char *, touch_format, NULL, ast_free);
-	RAII_VAR(char *, touch_monitor, NULL, ast_free);
-	RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
-
-	set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
-		&touch_monitor, &touch_monitor_prefix);
-	switch (set_touch_res) {
-	case SET_TOUCH_SUCCESS:
-		break;
-	case SET_TOUCH_UNSET:
-		set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
-			&touch_monitor_prefix);
-		if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
-			return;
-		}
-		break;
-	case SET_TOUCH_ALLOC_FAILURE:
-		return;
-	}
-
-	if (!ast_strlen_zero(touch_monitor)) {
-		len = strlen(touch_monitor) + 50;
-		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s",
-			S_OR(touch_monitor_prefix, "auto"),
-			(long) time(NULL),
-			touch_monitor);
-	} else {
-		char *caller_chan_id;
-		char *peer_chan_id;
-
-		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
-			ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
-		peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
-			ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
-		len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
-		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s-%s",
-			S_OR(touch_monitor_prefix, "auto"),
-			(long) time(NULL),
-			caller_chan_id,
-			peer_chan_id);
-	}
-
-	for (x = 0; x < strlen(touch_filename); x++) {
-		if (touch_filename[x] == '/') {
-			touch_filename[x] = '-';
-		}
-	}
+	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
+	struct ast_channel *chan;
+	int cause;
 
-	ast_verb(4, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
+	/* Fill the variable with the extension and context we want to call */
+	snprintf(destination, sizeof(destination), "%s@%s", exten, context);
 
-	if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, NULL)) {
-		ast_verb(4, "AutoMonitor feature was tried by '%s' but monitor failed to start.\n",
-			ast_channel_name(bridge_channel->chan));
-		return;
+	/* Now we request that chan_local prepare to call the destination */
+	if (!(chan = ast_request("Local", ast_channel_nativeformats(caller), caller, destination, &cause))) {
+		return NULL;
 	}
 
-	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+	/* Before we actually dial out let's inherit appropriate information. */
+	ast_channel_lock_both(caller, chan);
+	ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(caller));
+	ast_channel_inherit_variables(caller, chan);
+	ast_channel_datastore_inherit(caller, chan);
+	ast_channel_unlock(chan);
+	ast_channel_unlock(caller);
+
+	/* Since the above worked fine now we actually call it and return the channel */
+	if (ast_call(chan, destination, 0)) {
+		ast_hangup(chan);
+		return NULL;
 	}
 
-	if (!ast_strlen_zero(start_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
-	}
-
-	pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
+	return chan;
 }
 
-static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+/*! \brief Internal built in feature for blind transfers */
+static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-	const char *start_message;
-	const char *stop_message;
-	struct ast_bridge_features_automonitor *options = hook_pvt;
-	enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
-	int is_monitoring;
-
-	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
-
-	ast_channel_lock(bridge_channel->chan);
-	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
-	ast_channel_unlock(bridge_channel->chan);
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	if (!peer_chan) {
-		ast_verb(4, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
-			ast_channel_name(bridge_channel->chan));
-		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
+	char exten[AST_MAX_EXTENSION] = "";
+	struct ast_channel *chan = NULL;
+	struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
+	const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : ast_channel_context(bridge_channel->chan));
+
+	/* Grab the extension to transfer to */
+	if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+		ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
 		return 0;
 	}
 
-	ast_channel_lock(bridge_channel->chan);
-	start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
-		"TOUCH_MONITOR_MESSAGE_START");
-	start_message = ast_strdupa(S_OR(start_message, ""));
-	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
-		"TOUCH_MONITOR_MESSAGE_STOP");
-	stop_message = ast_strdupa(S_OR(stop_message, ""));
-	ast_channel_unlock(bridge_channel->chan);
-
-	is_monitoring = ast_channel_monitor(peer_chan) != NULL;
-	switch (start_stop) {
-	case AUTO_MONITOR_TOGGLE:
-		if (is_monitoring) {
-			stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
-		} else {
-			start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
-		}
+	/* Get a channel that is the destination we wish to call */
+	if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
 		return 0;
-	case AUTO_MONITOR_START:
-		if (!is_monitoring) {
-			start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
-			return 0;
-		}
-		ast_verb(4, "AutoMonitor already recording call.\n");
-		break;
-	case AUTO_MONITOR_STOP:
-		if (is_monitoring) {
-			stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
-			return 0;
-		}
-		ast_verb(4, "AutoMonitor already stopped on call.\n");
-		break;
 	}
 
-	/*
-	 * Fake start/stop to invoker so will think it did something but
-	 * was already in that mode.
-	 */
-	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-	}
-	if (is_monitoring) {
-		if (!ast_strlen_zero(start_message)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
-		}
-	} else {
-		if (!ast_strlen_zero(stop_message)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
-		}
-	}
+	/* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
+	ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL, 1);
+
 	return 0;
 }
 
-static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
+/*! \brief Attended transfer feature to turn it into a threeway call */
+static int attended_threeway_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-	ast_verb(4, "AutoMixMonitor used to stop recording call.\n");
-
-	if (ast_stop_mixmonitor(peer_chan, NULL)) {
-		ast_verb(4, "Failed to stop AutoMixMonitor for %s.\n", ast_channel_name(bridge_channel->chan));
-		if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
-		return;
-	}
-
-	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-	}
-
-	if (!ast_strlen_zero(stop_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
-	}
+	/* This is sort of abusing the depart state but in this instance it is only going to be handled in the below function so it is okay */
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
+	return 0;
 }
 
-static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
+/*! \brief Attended transfer abort feature */
+static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-	char *touch_filename;
-	size_t len;
-	int x;
-	enum set_touch_variables_res set_touch_res;
-
-	RAII_VAR(char *, touch_format, NULL, ast_free);
-	RAII_VAR(char *, touch_monitor, NULL, ast_free);
-	RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
-
-	set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
-		&touch_monitor, &touch_monitor_prefix);
-	switch (set_touch_res) {
-	case SET_TOUCH_SUCCESS:
-		break;
-	case SET_TOUCH_UNSET:
-		set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
-			&touch_monitor_prefix);
-		if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
-			return;
-		}
-		break;
-	case SET_TOUCH_ALLOC_FAILURE:
-		return;
-	}
+	struct ast_bridge_channel *called_bridge_channel = NULL;
 
-	if (!ast_strlen_zero(touch_monitor)) {
-		len = strlen(touch_monitor) + 50;
-		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s.%s",
-			S_OR(touch_monitor_prefix, "auto"),
-			(long) time(NULL),
-			touch_monitor,
-			S_OR(touch_format, "wav"));
-	} else {
-		char *caller_chan_id;
-		char *peer_chan_id;
-
-		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
-			ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
-		peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
-			ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
-		len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
-		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
-			S_OR(touch_monitor_prefix, "auto"),
-			(long) time(NULL),
-			caller_chan_id,
-			peer_chan_id,
-			S_OR(touch_format, "wav"));
-	}
+	/* It is possible (albeit unlikely) that the bridge channels list may change, so we have to ensure we do all of our magic while locked */
+	ao2_lock(bridge);
 
-	for (x = 0; x < strlen(touch_filename); x++) {
-		if (touch_filename[x] == '/') {
-			touch_filename[x] = '-';
-		}
+	if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
+		called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
+	} else {
+		called_bridge_channel = AST_LIST_LAST(&bridge->channels);
 	}
 
-	ast_verb(4, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
-
-	if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
-		ast_verb(4, "AutoMixMonitor feature was tried by '%s' but MixMonitor failed to start.\n",
-			ast_channel_name(bridge_channel->chan));
-
-		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
-		return;
+	/* Now we basically eject the other channel from the bridge. This will cause their thread to hang them up, and our own code to consider the transfer failed. */
+	if (called_bridge_channel) {
+		ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
 	}
 
-	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
-	}
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
 
-	if (!ast_strlen_zero(start_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
-	}
+	ao2_unlock(bridge);
 
-	pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+	return 0;
 }
 
-static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+/*! \brief Internal built in feature for attended transfers */
+static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-	static const char *mixmonitor_spy_type = "MixMonitor";
-	const char *stop_message;
-	const char *start_message;
-	struct ast_bridge_features_automixmonitor *options = hook_pvt;
-	enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
-	int is_monitoring;
-
-	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
-
-	ast_channel_lock(bridge_channel->chan);
-	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
-	ast_channel_unlock(bridge_channel->chan);
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	if (!peer_chan) {
-		ast_verb(4, "Cannot start AutoMixMonitor for %s - cannot determine peer in bridge.\n",
-			ast_channel_name(bridge_channel->chan));
-		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
+	char exten[AST_MAX_EXTENSION] = "";
+	struct ast_channel *chan = NULL;
+	struct ast_bridge *attended_bridge = NULL;
+	struct ast_bridge_features caller_features, called_features;
+	enum ast_bridge_channel_state attended_bridge_result;
+	struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
+	const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : ast_channel_context(bridge_channel->chan));
+
+	/* Grab the extension to transfer to */
+	if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+		ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
 		return 0;
 	}
 
-	ast_channel_lock(bridge_channel->chan);
-	start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
-		"TOUCH_MIXMONITOR_MESSAGE_START");
-	start_message = ast_strdupa(S_OR(start_message, ""));
-	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
-		"TOUCH_MIXMONITOR_MESSAGE_STOP");
-	stop_message = ast_strdupa(S_OR(stop_message, ""));
-	ast_channel_unlock(bridge_channel->chan);
-
-	is_monitoring =
-		0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
-	switch (start_stop) {
-	case AUTO_MONITOR_TOGGLE:
-		if (is_monitoring) {
-			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
-		} else {
-			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
-		}
+	/* Get a channel that is the destination we wish to call */
+	if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
 		return 0;
-	case AUTO_MONITOR_START:
-		if (!is_monitoring) {
-			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
-			return 0;
-		}
-		ast_verb(4, "AutoMixMonitor already recording call.\n");
-		break;
-	case AUTO_MONITOR_STOP:
-		if (is_monitoring) {
-			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
-			return 0;
-		}
-		ast_verb(4, "AutoMixMonitor already stopped on call.\n");
-		break;
 	}
 
-	/*
-	 * Fake start/stop to invoker so will think it did something but
-	 * was already in that mode.
-	 */
-	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+	/* Create a bridge to use to talk to the person we are calling */
+	if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
+		ast_hangup(chan);
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+		return 0;
 	}
-	if (is_monitoring) {
-		if (!ast_strlen_zero(start_message)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
+
+	/* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
+	ast_bridge_features_init(&called_features);
+	ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);
+
+	/* This is how this is going down, we are imparting the channel we called above into this bridge first */
+	ast_bridge_impart(attended_bridge, chan, NULL, &called_features, 1);
+
+	/* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
+	ast_bridge_features_init(&caller_features);
+	ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
+				   (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
+	ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
+				 attended_threeway_transfer, NULL, NULL);
+	ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
+				 attended_abort_transfer, NULL, NULL);
+
+	/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
+	attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL);
+
+	/* Since the above returned the caller features structure is of no more use */
+	ast_bridge_features_cleanup(&caller_features);
+
+	/* Drop the channel we are transferring to out of the above bridge since it has ended */
+	if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
+		/* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
+		if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
+			/* We want to impart them upon the bridge and just have us return to it as normal */
+			ast_bridge_impart(bridge, chan, NULL, NULL, 1);
+		} else {
+			ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL, 1);
 		}
 	} else {
-		if (!ast_strlen_zero(stop_message)) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
-		}
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
 	}
+
+	/* Now that all channels are out of it we can destroy the bridge and the called features structure */
+	ast_bridge_features_cleanup(&called_features);
+	ast_bridge_destroy(attended_bridge);
+
 	return 0;
 }
 
 /*! \brief Internal built in feature for hangup */
-static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-	/*
-	 * This is very simple, we simply change the state on the
-	 * bridge_channel to force the channel out of the bridge and the
-	 * core takes care of the rest.
-	 */
-	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-		AST_CAUSE_NORMAL_CLEARING);
+	/* This is very simple, we basically change the state on the bridge channel to end and the core takes care of the rest */
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
 	return 0;
 }
 
 static int unload_module(void)
 {
+	ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
+	ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER);
+	ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_BLINDTRANSFER);
+
 	return 0;
 }
 
 static int load_module(void)
 {
+	ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
+	ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
 	ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
-	ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
-	ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
 
-	/* Bump up our reference count so we can't be unloaded */
-	ast_module_ref(ast_module_info->self);
+	/* This module cannot be unloaded until shutdown */
+	ast_module_shutdown_ref(ast_module_info->self);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
diff --git a/bridges/bridge_builtin_interval_features.c b/bridges/bridge_builtin_interval_features.c
deleted file mode 100644
index 39a12de..0000000
--- a/bridges/bridge_builtin_interval_features.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Built in bridging interval features
- *
- * \author Jonathan Rose <jrose at digium.com>
- *
- * \ingroup bridges
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397577 $")
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/file.h"
-#include "asterisk/app.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/test.h"
-#include "asterisk/say.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/causes.h"
-
-static int bridge_features_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-
-	if (!ast_strlen_zero(limits->duration_sound)) {
-		ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE);
-	}
-
-	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
-		AST_CAUSE_NORMAL_CLEARING);
-
-	ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s",
-		ast_channel_name(bridge_channel->chan));
-	return -1;
-}
-
-static void limits_interval_playback(struct ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, const char *file)
-{
-	if (!strcasecmp(file, "timeleft")) {
-		unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, ast_tvnow()) / 1000;
-		unsigned int min;
-		unsigned int sec;
-
-		if (remaining <= 0) {
-			return;
-		}
-
-		if ((remaining / 60) > 1) {
-			min = remaining / 60;
-			sec = remaining % 60;
-		} else {
-			min = 0;
-			sec = remaining;
-		}
-
-		ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE);
-		if (min) {
-			ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE,
-				ast_channel_language(bridge_channel->chan), NULL);
-			ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE);
-		}
-		if (sec) {
-			ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE,
-				ast_channel_language(bridge_channel->chan), NULL);
-			ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE);
-		}
-	} else {
-		ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE);
-	}
-
-	/*
-	 * It may be necessary to resume music on hold after we finish
-	 * playing the announcment.
-	 */
-	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
-		const char *latest_musicclass;
-
-		ast_channel_lock(bridge_channel->chan);
-		latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan));
-		ast_channel_unlock(bridge_channel->chan);
-		ast_moh_start(bridge_channel->chan, latest_musicclass, NULL);
-	}
-}
-
-static int bridge_features_connect_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-
-	limits_interval_playback(bridge_channel, limits, limits->connect_sound);
-	return -1;
-}
-
-static int bridge_features_warning_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-
-	limits_interval_playback(bridge_channel, limits, limits->warning_sound);
-	return limits->frequency ?: -1;
-}
-
-static void bridge_features_limits_copy(struct ast_bridge_features_limits *dst, struct ast_bridge_features_limits *src)
-{
-	ast_string_fields_copy(dst, src);
-	dst->quitting_time = src->quitting_time;
-	dst->duration = src->duration;
-	dst->warning = src->warning;
-	dst->frequency = src->frequency;
-}
-
-static void bridge_features_limits_dtor(void *vdoomed)
-{
-	struct ast_bridge_features_limits *doomed = vdoomed;
-
-	ast_bridge_features_limits_destroy(doomed);
-	ast_module_unref(ast_module_info->self);
-}
-
-static int bridge_builtin_set_limits(struct ast_bridge_features *features,
-	struct ast_bridge_features_limits *limits,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	RAII_VAR(struct ast_bridge_features_limits *, feature_limits, NULL, ao2_cleanup);
-
-	if (!limits->duration) {
-		return -1;
-	}
-
-	/* Create limits hook_pvt data. */
-	ast_module_ref(ast_module_info->self);
-	feature_limits = ao2_alloc_options(sizeof(*feature_limits),
-		bridge_features_limits_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!feature_limits) {
-		ast_module_unref(ast_module_info->self);
-		return -1;
-	}
-	if (ast_bridge_features_limits_construct(feature_limits)) {
-		return -1;
-	}
-	bridge_features_limits_copy(feature_limits, limits);
-	feature_limits->quitting_time = ast_tvadd(ast_tvnow(),
-		ast_samp2tv(feature_limits->duration, 1000));
-
-	/* Install limit hooks. */
-	ao2_ref(feature_limits, +1);
-	if (ast_bridge_interval_hook(features, AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA,
-		feature_limits->duration,
-		bridge_features_duration_callback, feature_limits, __ao2_cleanup, remove_flags)) {
-		ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");
-		ao2_ref(feature_limits, -1);
-		return -1;
-	}
-	if (!ast_strlen_zero(feature_limits->connect_sound)) {
-		ao2_ref(feature_limits, +1);
-		if (ast_bridge_interval_hook(features, AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA, 1,
-			bridge_features_connect_callback, feature_limits, __ao2_cleanup, remove_flags)) {
-			ast_log(LOG_WARNING, "Failed to schedule connect sound to the bridge channel.\n");
-			ao2_ref(feature_limits, -1);
-		}
-	}
-	if (feature_limits->warning && feature_limits->warning < feature_limits->duration) {
-		ao2_ref(feature_limits, +1);
-		if (ast_bridge_interval_hook(features, AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA,
-			feature_limits->duration - feature_limits->warning,
-			bridge_features_warning_callback, feature_limits, __ao2_cleanup, remove_flags)) {
-			ast_log(LOG_WARNING, "Failed to schedule warning sound playback to the bridge channel.\n");
-			ao2_ref(feature_limits, -1);
-		}
-	}
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_bridge_interval_unregister(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS);
-	return 0;
-}
-
-static int load_module(void)
-{
-	return ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS,
-		bridge_builtin_set_limits);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging interval features");
diff --git a/bridges/bridge_holding.c b/bridges/bridge_holding.c
deleted file mode 100644
index 2253a95..0000000
--- a/bridges/bridge_holding.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Bridging technology for storing channels in a bridge for
- *        the purpose of holding, parking, queues, and other such
- *        states where a channel may need to be in a bridge but not
- *        actually communicating with anything.
- *
- * \author Jonathan Rose <jrose at digium.com>
- *
- * \ingroup bridges
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
-#include "asterisk/frame.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/format_cache.h"
-
-enum holding_roles {
-	HOLDING_ROLE_PARTICIPANT,
-	HOLDING_ROLE_ANNOUNCER,
-};
-
-enum idle_modes {
-	IDLE_MODE_NONE,
-	IDLE_MODE_MOH,
-	IDLE_MODE_RINGING,
-	IDLE_MODE_SILENCE,
-	IDLE_MODE_HOLD,
-};
-
-/*! \brief Structure which contains per-channel role information */
-struct holding_channel {
-	struct ast_silence_generator *silence_generator;
-	enum holding_roles role;
-	enum idle_modes idle_mode;
-	/*! TRUE if the entertainment is started. */
-	unsigned int entertainment_active:1;
-};
-
-typedef void (*deferred_cb)(struct ast_bridge_channel *bridge_channel);
-
-struct deferred_data {
-	/*! Deferred holding technology callback */
-	deferred_cb callback;
-};
-
-static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size);
-
-/*!
- * \internal
- * \brief Defer an action to a bridge_channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to operate on.
- * \param callback action to defer.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
-{
-	struct deferred_data data = { .callback = callback };
-	int res;
-
-	res = ast_bridge_channel_queue_callback(bridge_channel, 0, deferred_action,
-		&data, sizeof(data));
-	if (res) {
-		ast_log(LOG_WARNING, "Bridge %s: Could not defer action on %s.\n",
-			bridge_channel->bridge->uniqueid, ast_channel_name(bridge_channel->chan));
-	}
-	return res;
-}
-
-/*!
- * \internal
- * \brief Setup participant idle mode from channel.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to setup idle mode.
- *
- * \return Nothing
- */
-static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
-{
-	const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-
-	ast_assert(hc != NULL);
-
-	if (ast_strlen_zero(idle_mode)) {
-		hc->idle_mode = IDLE_MODE_MOH;
-	} else if (!strcmp(idle_mode, "musiconhold")) {
-		hc->idle_mode = IDLE_MODE_MOH;
-	} else if (!strcmp(idle_mode, "ringing")) {
-		hc->idle_mode = IDLE_MODE_RINGING;
-	} else if (!strcmp(idle_mode, "none")) {
-		hc->idle_mode = IDLE_MODE_NONE;
-	} else if (!strcmp(idle_mode, "silence")) {
-		hc->idle_mode = IDLE_MODE_SILENCE;
-	} else if (!strcmp(idle_mode, "hold")) {
-		hc->idle_mode = IDLE_MODE_HOLD;
-	} else {
-		/* Invalid idle mode requested. */
-		ast_debug(1, "channel %s idle mode '%s' doesn't match any defined idle mode\n",
-			ast_channel_name(bridge_channel->chan), idle_mode);
-		ast_assert(0);
-	}
-}
-
-static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
-{
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-
-	ast_assert(hc != NULL);
-
-	if (!hc->entertainment_active) {
-		/* Already stopped */
-		return;
-	}
-	hc->entertainment_active = 0;
-
-	switch (hc->idle_mode) {
-	case IDLE_MODE_MOH:
-		ast_moh_stop(bridge_channel->chan);
-		break;
-	case IDLE_MODE_RINGING:
-		ast_indicate(bridge_channel->chan, -1);
-		break;
-	case IDLE_MODE_NONE:
-		break;
-	case IDLE_MODE_SILENCE:
-		if (hc->silence_generator) {
-			ast_channel_stop_silence_generator(bridge_channel->chan, hc->silence_generator);
-			hc->silence_generator = NULL;
-		}
-		break;
-	case IDLE_MODE_HOLD:
-		ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
-		break;
-	}
-}
-
-static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_channel *chan;
-
-	chan = bridge_channel->chan;
-	participant_entertainment_stop(bridge_channel);
-	if (ast_set_write_format(chan, ast_format_slin)) {
-		ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
-	}
-}
-
-/* This should only be called on verified holding_participants. */
-static void participant_entertainment_start(struct ast_bridge_channel *bridge_channel)
-{
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-	const char *moh_class;
-	size_t moh_length;
-
-	ast_assert(hc != NULL);
-
-	if (hc->entertainment_active) {
-		/* Already started */
-		return;
-	}
-	hc->entertainment_active = 1;
-
-	participant_idle_mode_setup(bridge_channel);
-	switch(hc->idle_mode) {
-	case IDLE_MODE_MOH:
-		moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
-		ast_moh_start(bridge_channel->chan, moh_class, NULL);
-		break;
-	case IDLE_MODE_RINGING:
-		ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
-		break;
-	case IDLE_MODE_NONE:
-		break;
-	case IDLE_MODE_SILENCE:
-		hc->silence_generator = ast_channel_start_silence_generator(bridge_channel->chan);
-		break;
-	case IDLE_MODE_HOLD:
-		moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
-		moh_length = moh_class ? strlen(moh_class + 1) : 0;
-		ast_indicate_data(bridge_channel->chan, AST_CONTROL_HOLD, moh_class, moh_length);
-		break;
-	}
-}
-
-static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
-{
-	struct ast_channel *us = bridge_channel->chan;
-
-	/* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
-	if (!announcer_channel) {
-		defer_action(bridge_channel, participant_entertainment_start);
-		return;
-	}
-
-	/* We need to get compatible with the announcer. */
-	if (ast_set_write_format(us, ast_format_slin)) {
-		ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
-	}
-}
-
-static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge_channel *other_channel;
-	struct ast_bridge_channel *announcer_channel;
-	struct holding_channel *hc;
-	struct ast_channel *us = bridge_channel->chan; /* The joining channel */
-
-	ast_assert(bridge_channel->tech_pvt == NULL);
-
-	if (!(hc = ast_calloc(1, sizeof(*hc)))) {
-		return -1;
-	}
-
-	bridge_channel->tech_pvt = hc;
-
-	/* The bridge pvt holds the announcer channel if we have one. */
-	announcer_channel = bridge->tech_pvt;
-
-	if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
-		if (announcer_channel) {
-			/* Another announcer already exists. */
-			bridge_channel->tech_pvt = NULL;
-			ast_free(hc);
-			ast_log(LOG_WARNING, "Bridge %s: Channel %s tried to be an announcer.  Bridge already has one.\n",
-				bridge->uniqueid, ast_channel_name(bridge_channel->chan));
-			return -1;
-		}
-
-		bridge->tech_pvt = bridge_channel;
-		hc->role = HOLDING_ROLE_ANNOUNCER;
-
-		/* The announcer should always be made compatible with signed linear */
-		if (ast_set_read_format(us, ast_format_slin)) {
-			ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
-		}
-
-		/* Make everyone listen to the announcer. */
-		AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
-			/* Skip the reaction if we are the channel in question */
-			if (bridge_channel == other_channel) {
-				continue;
-			}
-			defer_action(other_channel, participant_reaction_announcer_join);
-		}
-
-		return 0;
-	}
-
-	hc->role = HOLDING_ROLE_PARTICIPANT;
-	handle_participant_join(bridge_channel, announcer_channel);
-	return 0;
-}
-
-static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
-{
-	ast_bridge_channel_restore_formats(bridge_channel);
-	participant_entertainment_start(bridge_channel);
-}
-
-static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge_channel *other_channel;
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-
-	if (!hc) {
-		return;
-	}
-
-	switch (hc->role) {
-	case HOLDING_ROLE_ANNOUNCER:
-		/* The announcer is leaving */
-		bridge->tech_pvt = NULL;
-
-		/* Reset the other channels back to moh/ringing. */
-		AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
-			defer_action(other_channel, participant_reaction_announcer_leave);
-		}
-		break;
-	default:
-		/* Nothing needs to react to its departure. */
-		participant_entertainment_stop(bridge_channel);
-		break;
-	}
-	bridge_channel->tech_pvt = NULL;
-	ast_free(hc);
-}
-
-static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	struct holding_channel *hc = bridge_channel ? bridge_channel->tech_pvt : NULL;
-
-	/* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
-	if (!hc) {
-		/* "Accept" the frame and discard it. */
-		return 0;
-	}
-
-	switch (hc->role) {
-	case HOLDING_ROLE_ANNOUNCER:
-		/* Write the frame to all other channels if any. */
-		ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
-		break;
-	default:
-		/* "Accept" the frame and discard it. */
-		break;
-	}
-
-	return 0;
-}
-
-static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-
-	if (!hc) {
-		return;
-	}
-
-	switch (hc->role) {
-	case HOLDING_ROLE_PARTICIPANT:
-		participant_entertainment_stop(bridge_channel);
-		break;
-	default:
-		break;
-	}
-}
-
-static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct holding_channel *hc = bridge_channel->tech_pvt;
-	struct ast_bridge_channel *announcer_channel = bridge->tech_pvt;
-
-	if (!hc) {
-		return;
-	}
-
-	switch (hc->role) {
-	case HOLDING_ROLE_PARTICIPANT:
-		if (announcer_channel) {
-			/* There is an announcer channel in the bridge. */
-			break;
-		}
-		/* We need to restart the entertainment. */
-		participant_entertainment_start(bridge_channel);
-		break;
-	default:
-		break;
-	}
-}
-
-static struct ast_bridge_technology holding_bridge = {
-	.name = "holding_bridge",
-	.capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
-	.preference = AST_BRIDGE_PREFERENCE_BASE_HOLDING,
-	.write = holding_bridge_write,
-	.join = holding_bridge_join,
-	.leave = holding_bridge_leave,
-	.suspend = holding_bridge_suspend,
-	.unsuspend = holding_bridge_unsuspend,
-};
-
-/*!
- * \internal
- * \brief Deferred action to start/stop participant entertainment.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to operate on.
- * \param payload Data to pass to the callback. (NULL if none).
- * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
- *
- * \return Nothing
- */
-static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
-{
-	const struct deferred_data *data = payload;
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	if (bridge_channel->bridge->technology != &holding_bridge
-		|| !bridge_channel->tech_pvt) {
-		/* Not valid anymore. */
-		ast_bridge_unlock(bridge_channel->bridge);
-		return;
-	}
-	data->callback(bridge_channel);
-	ast_bridge_unlock(bridge_channel->bridge);
-}
-
-static int unload_module(void)
-{
-	ao2_cleanup(holding_bridge.format_capabilities);
-	holding_bridge.format_capabilities = NULL;
-	return ast_bridge_technology_unregister(&holding_bridge);
-}
-
-static int load_module(void)
-{
-	if (!(holding_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO);
-	ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO);
-	ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT);
-
-	return ast_bridge_technology_register(&holding_bridge);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Holding bridge module");
-
diff --git a/bridges/bridge_multiplexed.c b/bridges/bridge_multiplexed.c
new file mode 100644
index 0000000..cd30266
--- /dev/null
+++ b/bridges/bridge_multiplexed.c
@@ -0,0 +1,432 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Two channel bridging module which groups bridges into batches of threads
+ *
+ * \author Joshua Colp <jcolp at digium.com>
+ *
+ * \ingroup bridges
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
+#include "asterisk/frame.h"
+#include "asterisk/astobj2.h"
+
+/*! \brief Number of buckets our multiplexed thread container can have */
+#define MULTIPLEXED_BUCKETS 53
+
+/*! \brief Number of channels we handle in a single thread */
+#define MULTIPLEXED_MAX_CHANNELS 8
+
+/*! \brief Structure which represents a single thread handling multiple 2 channel bridges */
+struct multiplexed_thread {
+	/*! Thread itself */
+	pthread_t thread;
+	/*! Pipe used to wake up the multiplexed thread */
+	int pipe[2];
+	/*! Channels in this thread */
+	struct ast_channel *chans[MULTIPLEXED_MAX_CHANNELS];
+	/*! Number of channels in this thread */
+	unsigned int count;
+	/*! Bit used to indicate that the thread is waiting on channels */
+	unsigned int waiting:1;
+	/*! Number of channels actually being serviced by this thread */
+	unsigned int service_count;
+};
+
+/*! \brief Container of all operating multiplexed threads */
+static struct ao2_container *multiplexed_threads;
+
+/*! \brief Callback function for finding a free multiplexed thread */
+static int find_multiplexed_thread(void *obj, void *arg, int flags)
+{
+	struct multiplexed_thread *multiplexed_thread = obj;
+	return (multiplexed_thread->count <= (MULTIPLEXED_MAX_CHANNELS - 2)) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Destroy callback for a multiplexed thread structure */
+static void destroy_multiplexed_thread(void *obj)
+{
+	struct multiplexed_thread *multiplexed_thread = obj;
+
+	if (multiplexed_thread->pipe[0] > -1) {
+		close(multiplexed_thread->pipe[0]);
+	}
+	if (multiplexed_thread->pipe[1] > -1) {
+		close(multiplexed_thread->pipe[1]);
+	}
+
+	return;
+}
+
+/*! \brief Create function which finds/reserves/references a multiplexed thread structure */
+static int multiplexed_bridge_create(struct ast_bridge *bridge)
+{
+	struct multiplexed_thread *multiplexed_thread;
+
+	ao2_lock(multiplexed_threads);
+
+	/* Try to find an existing thread to handle our additional channels */
+	if (!(multiplexed_thread = ao2_callback(multiplexed_threads, 0, find_multiplexed_thread, NULL))) {
+		int flags;
+
+		/* If we failed we will have to create a new one from scratch */
+		if (!(multiplexed_thread = ao2_alloc(sizeof(*multiplexed_thread), destroy_multiplexed_thread))) {
+			ast_debug(1, "Failed to find or create a new multiplexed thread for bridge '%p'\n", bridge);
+			ao2_unlock(multiplexed_threads);
+			return -1;
+		}
+
+		multiplexed_thread->pipe[0] = multiplexed_thread->pipe[1] = -1;
+		/* Setup a pipe so we can poke the thread itself when needed */
+		if (pipe(multiplexed_thread->pipe)) {
+			ast_debug(1, "Failed to create a pipe for poking a multiplexed thread for bridge '%p'\n", bridge);
+			ao2_ref(multiplexed_thread, -1);
+			ao2_unlock(multiplexed_threads);
+			return -1;
+		}
+
+		/* Setup each pipe for non-blocking operation */
+		flags = fcntl(multiplexed_thread->pipe[0], F_GETFL);
+		if (fcntl(multiplexed_thread->pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
+			ast_log(LOG_WARNING, "Failed to setup first nudge pipe for non-blocking operation on %p (%d: %s)\n", bridge, errno, strerror(errno));
+			ao2_ref(multiplexed_thread, -1);
+			ao2_unlock(multiplexed_threads);
+			return -1;
+		}
+		flags = fcntl(multiplexed_thread->pipe[1], F_GETFL);
+		if (fcntl(multiplexed_thread->pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
+			ast_log(LOG_WARNING, "Failed to setup second nudge pipe for non-blocking operation on %p (%d: %s)\n", bridge, errno, strerror(errno));
+			ao2_ref(multiplexed_thread, -1);
+			ao2_unlock(multiplexed_threads);
+			return -1;
+		}
+
+		/* Set up default parameters */
+		multiplexed_thread->thread = AST_PTHREADT_NULL;
+
+		/* Finally link us into the container so others may find us */
+		ao2_link(multiplexed_threads, multiplexed_thread);
+		ast_debug(1, "Created multiplexed thread '%p' for bridge '%p'\n", multiplexed_thread, bridge);
+	} else {
+		ast_debug(1, "Found multiplexed thread '%p' for bridge '%p'\n", multiplexed_thread, bridge);
+	}
+
+	/* Bump the count of the thread structure up by two since the channels for this bridge will be joining shortly */
+	multiplexed_thread->count += 2;
+
+	ao2_unlock(multiplexed_threads);
+
+	bridge->bridge_pvt = multiplexed_thread;
+
+	return 0;
+}
+
+/*! \brief Internal function which nudges the thread */
+static void multiplexed_nudge(struct multiplexed_thread *multiplexed_thread)
+{
+	int nudge = 0;
+
+	if (multiplexed_thread->thread == AST_PTHREADT_NULL) {
+		return;
+	}
+
+	if (write(multiplexed_thread->pipe[1], &nudge, sizeof(nudge)) != sizeof(nudge)) {
+		ast_log(LOG_ERROR, "We couldn't poke multiplexed thread '%p'... something is VERY wrong\n", multiplexed_thread);
+	}
+
+	while (multiplexed_thread->waiting) {
+		sched_yield();
+	}
+
+	return;
+}
+
+/*! \brief Destroy function which unreserves/unreferences/removes a multiplexed thread structure */
+static int multiplexed_bridge_destroy(struct ast_bridge *bridge)
+{
+	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;
+
+	ao2_lock(multiplexed_threads);
+
+	multiplexed_thread->count -= 2;
+
+	if (!multiplexed_thread->count) {
+		ast_debug(1, "Unlinking multiplexed thread '%p' since nobody is using it anymore\n", multiplexed_thread);
+		ao2_unlink(multiplexed_threads, multiplexed_thread);
+	}
+
+	multiplexed_nudge(multiplexed_thread);
+
+	ao2_unlock(multiplexed_threads);
+
+	ao2_ref(multiplexed_thread, -1);
+
+	return 0;
+}
+
+/*! \brief Thread function that executes for multiplexed threads */
+static void *multiplexed_thread_function(void *data)
+{
+	struct multiplexed_thread *multiplexed_thread = data;
+	int fds = multiplexed_thread->pipe[0];
+
+	ao2_lock(multiplexed_thread);
+
+	ast_debug(1, "Starting actual thread for multiplexed thread '%p'\n", multiplexed_thread);
+
+	while (multiplexed_thread->thread != AST_PTHREADT_STOP) {
+		struct ast_channel *winner = NULL, *first = multiplexed_thread->chans[0];
+		int to = -1, outfd = -1;
+
+		/* Move channels around so not just the first one gets priority */
+		memmove(multiplexed_thread->chans, multiplexed_thread->chans + 1, sizeof(struct ast_channel *) * (multiplexed_thread->service_count - 1));
+		multiplexed_thread->chans[multiplexed_thread->service_count - 1] = first;
+
+		multiplexed_thread->waiting = 1;
+		ao2_unlock(multiplexed_thread);
+		winner = ast_waitfor_nandfds(multiplexed_thread->chans, multiplexed_thread->service_count, &fds, 1, NULL, &outfd, &to);
+		multiplexed_thread->waiting = 0;
+		ao2_lock(multiplexed_thread);
+		if (multiplexed_thread->thread == AST_PTHREADT_STOP) {
+			break;
+		}
+
+		if (outfd > -1) {
+			int nudge;
+
+			if (read(multiplexed_thread->pipe[0], &nudge, sizeof(nudge)) < 0) {
+				if (errno != EINTR && errno != EAGAIN) {
+					ast_log(LOG_WARNING, "read() failed for pipe on multiplexed thread '%p': %s\n", multiplexed_thread, strerror(errno));
+				}
+			}
+		}
+		if (winner && ast_channel_internal_bridge(winner)) {
+			struct ast_bridge *bridge = ast_channel_internal_bridge(winner);
+			int stop = 0;
+			ao2_unlock(multiplexed_thread);
+			while ((bridge = ast_channel_internal_bridge(winner)) && ao2_trylock(bridge)) {
+				sched_yield();
+				if (multiplexed_thread->thread == AST_PTHREADT_STOP) {
+					stop = 1;
+					break;
+				}
+			}
+			if (!stop && bridge) {
+				ast_bridge_handle_trip(bridge, NULL, winner, -1);
+				ao2_unlock(bridge);
+			}
+			ao2_lock(multiplexed_thread);
+		}
+	}
+
+	multiplexed_thread->thread = AST_PTHREADT_NULL;
+
+	ast_debug(1, "Stopping actual thread for multiplexed thread '%p'\n", multiplexed_thread);
+
+	ao2_unlock(multiplexed_thread);
+	ao2_ref(multiplexed_thread, -1);
+
+	return NULL;
+}
+
+/*! \brief Helper function which adds or removes a channel and nudges the thread */
+static void multiplexed_add_or_remove(struct multiplexed_thread *multiplexed_thread, struct ast_channel *chan, int add)
+{
+	int i, removed = 0;
+	pthread_t thread = AST_PTHREADT_NULL;
+
+	ao2_lock(multiplexed_thread);
+
+	multiplexed_nudge(multiplexed_thread);
+
+	for (i = 0; i < MULTIPLEXED_MAX_CHANNELS; i++) {
+		if (multiplexed_thread->chans[i] == chan) {
+			if (!add) {
+				multiplexed_thread->chans[i] = NULL;
+				multiplexed_thread->service_count--;
+				removed = 1;
+			}
+			break;
+		} else if (!multiplexed_thread->chans[i] && add) {
+			multiplexed_thread->chans[i] = chan;
+			multiplexed_thread->service_count++;
+			break;
+		}
+	}
+
+	if (multiplexed_thread->service_count && multiplexed_thread->thread == AST_PTHREADT_NULL) {
+		ao2_ref(multiplexed_thread, +1);
+		if (ast_pthread_create(&multiplexed_thread->thread, NULL, multiplexed_thread_function, multiplexed_thread)) {
+			ao2_ref(multiplexed_thread, -1);
+			ast_debug(1, "Failed to create an actual thread for multiplexed thread '%p', trying next time\n", multiplexed_thread);
+		}
+	} else if (!multiplexed_thread->service_count && multiplexed_thread->thread != AST_PTHREADT_NULL) {
+		thread = multiplexed_thread->thread;
+		multiplexed_thread->thread = AST_PTHREADT_STOP;
+	} else if (!add && removed) {
+		memmove(multiplexed_thread->chans + i, multiplexed_thread->chans + i + 1, sizeof(struct ast_channel *) * (MULTIPLEXED_MAX_CHANNELS - (i + 1)));
+	}
+
+	ao2_unlock(multiplexed_thread);
+
+	if (thread != AST_PTHREADT_NULL) {
+		pthread_join(thread, NULL);
+	}
+
+	return;
+}
+
+/*! \brief Join function which actually adds the channel into the array to be monitored */
+static int multiplexed_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan, *c1 = AST_LIST_LAST(&bridge->channels)->chan;
+	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;
+
+	ast_debug(1, "Adding channel '%s' to multiplexed thread '%p' for monitoring\n", ast_channel_name(bridge_channel->chan), multiplexed_thread);
+
+	multiplexed_add_or_remove(multiplexed_thread, bridge_channel->chan, 1);
+
+	/* If the second channel has not yet joined do not make things compatible */
+	if (c0 == c1) {
+		return 0;
+	}
+
+	if ((ast_format_cmp(ast_channel_writeformat(c0), ast_channel_readformat(c1)) == AST_FORMAT_CMP_EQUAL) &&
+		(ast_format_cmp(ast_channel_readformat(c0), ast_channel_writeformat(c1)) == AST_FORMAT_CMP_EQUAL) &&
+		(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) {
+		return 0;
+	}
+
+	return ast_channel_make_compatible(c0, c1);
+}
+
+/*! \brief Leave function which actually removes the channel from the array */
+static int multiplexed_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;
+
+	ast_debug(1, "Removing channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), multiplexed_thread);
+
+	multiplexed_add_or_remove(multiplexed_thread, bridge_channel->chan, 0);
+
+	return 0;
+}
+
+/*! \brief Suspend function which means control of the channel is going elsewhere */
+static void multiplexed_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;
+
+	ast_debug(1, "Suspending channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), multiplexed_thread);
+
+	multiplexed_add_or_remove(multiplexed_thread, bridge_channel->chan, 0);
+
+	return;
+}
+
+/*! \brief Unsuspend function which means control of the channel is coming back to us */
+static void multiplexed_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;
+
+	ast_debug(1, "Unsuspending channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), multiplexed_thread);
+
+	multiplexed_add_or_remove(multiplexed_thread, bridge_channel->chan, 1);
+
+	return;
+}
+
+/*! \brief Write function for writing frames into the bridge */
+static enum ast_bridge_write_result multiplexed_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+{
+	struct ast_bridge_channel *other;
+
+	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+		return AST_BRIDGE_WRITE_FAILED;
+	}
+
+	if (!(other = (AST_LIST_FIRST(&bridge->channels) == bridge_channel ? AST_LIST_LAST(&bridge->channels) : AST_LIST_FIRST(&bridge->channels)))) {
+		return AST_BRIDGE_WRITE_FAILED;
+	}
+
+	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		ast_write(other->chan, frame);
+	}
+
+	return AST_BRIDGE_WRITE_SUCCESS;
+}
+
+static struct ast_bridge_technology multiplexed_bridge = {
+	.name = "multiplexed_bridge",
+	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
+	.preference = AST_BRIDGE_PREFERENCE_HIGH,
+	.create = multiplexed_bridge_create,
+	.destroy = multiplexed_bridge_destroy,
+	.join = multiplexed_bridge_join,
+	.leave = multiplexed_bridge_leave,
+	.suspend = multiplexed_bridge_suspend,
+	.unsuspend = multiplexed_bridge_unsuspend,
+	.write = multiplexed_bridge_write,
+};
+
+static int unload_module(void)
+{
+	int res = ast_bridge_technology_unregister(&multiplexed_bridge);
+
+	ao2_ref(multiplexed_threads, -1);
+	multiplexed_bridge.format_capabilities = ast_format_cap_destroy(multiplexed_bridge.format_capabilities);
+
+	return res;
+}
+
+static int load_module(void)
+{
+	if (!(multiplexed_threads = ao2_container_alloc(MULTIPLEXED_BUCKETS, NULL, NULL))) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	if (!(multiplexed_bridge.format_capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
+	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
+	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
+	return ast_bridge_technology_register(&multiplexed_bridge);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Multiplexed two channel bridging module");
diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c
deleted file mode 100644
index 6d47985..0000000
--- a/bridges/bridge_native_rtp.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Native RTP bridging technology module
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- * \ingroup bridges
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427583 $")
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
-#include "asterisk/frame.h"
-#include "asterisk/rtp_engine.h"
-
-/*! \brief Internal structure which contains information about bridged RTP channels */
-struct native_rtp_bridge_data {
-	/*! \brief Framehook used to intercept certain control frames */
-	int id;
-};
-
-/*! \brief Internal helper function which gets all RTP information (glue and instances) relating to the given channels */
-static enum ast_rtp_glue_result native_rtp_bridge_get(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_glue **glue0,
-	struct ast_rtp_glue **glue1, struct ast_rtp_instance **instance0, struct ast_rtp_instance **instance1,
-	struct ast_rtp_instance **vinstance0, struct ast_rtp_instance **vinstance1)
-{
-	enum ast_rtp_glue_result audio_glue0_res;
-	enum ast_rtp_glue_result video_glue0_res;
-	enum ast_rtp_glue_result audio_glue1_res;
-	enum ast_rtp_glue_result video_glue1_res;
-
-	if (!(*glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) ||
-		!(*glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) {
-		return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	audio_glue0_res = (*glue0)->get_rtp_info(c0, instance0);
-	video_glue0_res = (*glue0)->get_vrtp_info ? (*glue0)->get_vrtp_info(c0, vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
-
-	audio_glue1_res = (*glue1)->get_rtp_info(c1, instance1);
-	video_glue1_res = (*glue1)->get_vrtp_info ? (*glue1)->get_vrtp_info(c1, vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
-
-	/* Apply any limitations on direct media bridging that may be present */
-	if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
-		if ((*glue0)->allow_rtp_remote && !((*glue0)->allow_rtp_remote(c0, *instance1))) {
-			/* If the allow_rtp_remote indicates that remote isn't allowed, revert to local bridge */
-			audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
-		} else if ((*glue1)->allow_rtp_remote && !((*glue1)->allow_rtp_remote(c1, *instance0))) {
-			audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
-		}
-	}
-	if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
-		if ((*glue0)->allow_vrtp_remote && !((*glue0)->allow_vrtp_remote(c0, *instance1))) {
-			/* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */
-			video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
-		} else if ((*glue1)->allow_vrtp_remote && !((*glue1)->allow_vrtp_remote(c1, *instance0))) {
-			video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
-		}
-	}
-
-	/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
-	if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID
-		&& (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE
-			|| video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
-		audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
-	}
-	if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID
-		&& (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE
-			|| video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
-		audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	/* The order of preference is: forbid, local, and remote. */
-	if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID ||
-		audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
-		/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
-		return AST_RTP_GLUE_RESULT_FORBID;
-	} else if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL ||
-		audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) {
-		return AST_RTP_GLUE_RESULT_LOCAL;
-	} else {
-		return AST_RTP_GLUE_RESULT_REMOTE;
-	}
-}
-
-/*!
- * \internal
- * \brief Start native RTP bridging of two channels
- *
- * \param bridge The bridge that had native RTP bridging happening on it
- * \param target If remote RTP bridging, the channel that is unheld.
- *
- * \note Bridge must be locked when calling this function.
- */
-static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channel *target)
-{
-	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
-	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
-	enum ast_rtp_glue_result native_type;
-	struct ast_rtp_glue *glue0, *glue1;
-	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, tinstance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, tinstance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-
-	if (bc0 == bc1) {
-		return;
-	}
-
-	ast_channel_lock_both(bc0->chan, bc1->chan);
-	native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
-
-	switch (native_type) {
-	case AST_RTP_GLUE_RESULT_LOCAL:
-		if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
-			ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, instance1);
-		}
-		if (ast_rtp_instance_get_engine(instance1)->local_bridge) {
-			ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, instance0);
-		}
-		ast_rtp_instance_set_bridged(instance0, instance1);
-		ast_rtp_instance_set_bridged(instance1, instance0);
-		ast_debug(2, "Locally RTP bridged '%s' and '%s' in stack\n",
-			ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));
-		break;
-
-	case AST_RTP_GLUE_RESULT_REMOTE:
-		if (glue0->get_codec) {
-			glue0->get_codec(bc0->chan, cap0);
-		}
-		if (glue1->get_codec) {
-			glue1->get_codec(bc1->chan, cap1);
-		}
-
-		/* If we have a target, it's the channel that received the UNHOLD or UPDATE_RTP_PEER frame and was told to resume */
-		if (!target) {
-			glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0);
-			glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0);
-			ast_debug(2, "Remotely bridged '%s' and '%s' - media will flow directly between them\n",
-				ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));
-		} else {
-			/*
-			 * If a target was provided, it is the recipient of an unhold or an update and needs to have
-			 * its media redirected to fit the current remote bridging needs. The other channel is either
-			 * already set up to handle the new media path or will have its own set of updates independent
-			 * of this pass.
-			 */
-			if (bc0->chan == target) {
-				glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0);
-			} else {
-				glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0);
-			}
-		}
-		break;
-	case AST_RTP_GLUE_RESULT_FORBID:
-		break;
-	}
-
-	ast_channel_unlock(bc0->chan);
-	ast_channel_unlock(bc1->chan);
-}
-
-static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target)
-{
-	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
-	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
-	enum ast_rtp_glue_result native_type;
-	struct ast_rtp_glue *glue0, *glue1 = NULL;
-	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
-
-	if (bc0 == bc1) {
-		return;
-	}
-
-	ast_channel_lock_both(bc0->chan, bc1->chan);
-	native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
-
-	switch (native_type) {
-	case AST_RTP_GLUE_RESULT_LOCAL:
-		if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
-			ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, NULL);
-		}
-		if (instance1 && ast_rtp_instance_get_engine(instance1)->local_bridge) {
-			ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, NULL);
-		}
-		ast_rtp_instance_set_bridged(instance0, NULL);
-		if (instance1) {
-			ast_rtp_instance_set_bridged(instance1, NULL);
-		}
-		break;
-	case AST_RTP_GLUE_RESULT_REMOTE:
-		if (target) {
-			/*
-			 * If a target was provided, it is being put on hold and should expect to
-			 * receive media from Asterisk instead of what it was previously connected to.
-			 */
-			if (bc0->chan == target) {
-				glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0);
-			} else {
-				glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0);
-			}
-		}
-		break;
-	case AST_RTP_GLUE_RESULT_FORBID:
-		break;
-	}
-
-	if (!target && native_type != AST_RTP_GLUE_RESULT_FORBID) {
-		glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0);
-		glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0);
-	}
-
-	ast_debug(2, "Discontinued RTP bridging of '%s' and '%s' - media will flow through Asterisk core\n",
-		ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));
-
-	ast_channel_unlock(bc0->chan);
-	ast_channel_unlock(bc1->chan);
-}
-
-/*! \brief Frame hook that is called to intercept hold/unhold */
-static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
-{
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
-
-	if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
-		return f;
-	}
-
-	bridge = ast_channel_get_bridge(chan);
-
-	if (bridge) {
-		/* native_rtp_bridge_start/stop are not being called from bridging
-		   core so we need to lock the bridge prior to calling these functions
-		   Unfortunately that means unlocking the channel, but as it
-		   should not be modified this should be okay...hopefully */
-		ast_channel_unlock(chan);
-		ast_bridge_lock(bridge);
-		if (f->subclass.integer == AST_CONTROL_HOLD) {
-			native_rtp_bridge_stop(bridge, chan);
-		} else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
-			native_rtp_bridge_start(bridge, chan);
-		}
-		ast_bridge_unlock(bridge);
-		ast_channel_lock(chan);
-
-	}
-
-	return f;
-}
-
-/*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */
-static int native_rtp_framehook_consume(void *data, enum ast_frame_type type)
-{
-	return (type == AST_FRAME_CONTROL ? 1 : 0);
-}
-
-/*! \brief Internal helper function which checks whether the channels are compatible with our native bridging */
-static int native_rtp_bridge_capable(struct ast_channel *chan)
-{
-	return !ast_channel_has_hook_requiring_audio(chan);
-}
-
-static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
-	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
-	enum ast_rtp_glue_result native_type;
-	struct ast_rtp_glue *glue0, *glue1;
-	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-	int read_ptime0, read_ptime1, write_ptime0, write_ptime1;
-
-	/* We require two channels before even considering native bridging */
-	if (bridge->num_channels != 2) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
-			bridge->uniqueid);
-		return 0;
-	}
-
-	if (!native_rtp_bridge_capable(bc0->chan)) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
-			bridge->uniqueid, ast_channel_name(bc0->chan));
-		return 0;
-	}
-
-	if (!native_rtp_bridge_capable(bc1->chan)) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
-			bridge->uniqueid, ast_channel_name(bc1->chan));
-		return 0;
-	}
-
-	if ((native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1))
-		== AST_RTP_GLUE_RESULT_FORBID) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
-			bridge->uniqueid);
-		return 0;
-	}
-
-	if (ao2_container_count(bc0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
-			bridge->uniqueid, ast_channel_name(bc0->chan));
-		return 0;
-	}
-
-	if (ao2_container_count(bc1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) {
-		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
-			bridge->uniqueid, ast_channel_name(bc1->chan));
-		return 0;
-	}
-
-	if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge !=
-		ast_rtp_instance_get_engine(instance1)->local_bridge) ||
-		(ast_rtp_instance_get_engine(instance0)->dtmf_compatible &&
-			!ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, instance0, bc1->chan, instance1)))) {
-		ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
-			bridge->uniqueid);
-		return 0;
-	}
-
-	/* Make sure that codecs match */
-	if (glue0->get_codec) {
-		glue0->get_codec(bc0->chan, cap0);
-	}
-	if (glue1->get_codec) {
-		glue1->get_codec(bc1->chan, cap1);
-	}
-	if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) {
-		struct ast_str *codec_buf0 = ast_str_alloca(64);
-		struct ast_str *codec_buf1 = ast_str_alloca(64);
-		ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
-			ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1));
-		return 0;
-	}
-
-	read_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawreadformat(bc0->chan));
-	read_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawreadformat(bc1->chan));
-	write_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawwriteformat(bc0->chan));
-	write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(bc1->chan));
-
-	if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
-		ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
-				read_ptime0, write_ptime1, read_ptime1, write_ptime0);
-		return 0;
-	}
-
-	return 1;
-}
-
-/*! \brief Helper function which adds frame hook to bridge channel */
-static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel)
-{
-	struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL);
-	static struct ast_framehook_interface hook = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = native_rtp_framehook,
-		.consume_cb = native_rtp_framehook_consume,
-		.disable_inheritance = 1,
-	};
-
-	if (!data) {
-		return -1;
-	}
-
-	ast_channel_lock(bridge_channel->chan);
-	data->id = ast_framehook_attach(bridge_channel->chan, &hook);
-	ast_channel_unlock(bridge_channel->chan);
-	if (data->id < 0) {
-		ao2_cleanup(data);
-		return -1;
-	}
-
-	bridge_channel->tech_pvt = data;
-
-	return 0;
-}
-
-/*! \brief Helper function which removes frame hook from bridge channel */
-static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel)
-{
-	RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup);
-
-	if (!data) {
-		return;
-	}
-
-	ast_channel_lock(bridge_channel->chan);
-	ast_framehook_detach(bridge_channel->chan, data->id);
-	ast_channel_unlock(bridge_channel->chan);
-	bridge_channel->tech_pvt = NULL;
-}
-
-static int native_rtp_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	native_rtp_bridge_framehook_detach(bridge_channel);
-	if (native_rtp_bridge_framehook_attach(bridge_channel)) {
-		return -1;
-	}
-
-	native_rtp_bridge_start(bridge, NULL);
-	return 0;
-}
-
-static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	native_rtp_bridge_join(bridge, bridge_channel);
-}
-
-static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	native_rtp_bridge_framehook_detach(bridge_channel);
-	native_rtp_bridge_stop(bridge, NULL);
-}
-
-static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
-}
-
-static struct ast_bridge_technology native_rtp_bridge = {
-	.name = "native_rtp",
-	.capabilities = AST_BRIDGE_CAPABILITY_NATIVE,
-	.preference = AST_BRIDGE_PREFERENCE_BASE_NATIVE,
-	.join = native_rtp_bridge_join,
-	.unsuspend = native_rtp_bridge_unsuspend,
-	.leave = native_rtp_bridge_leave,
-	.suspend = native_rtp_bridge_leave,
-	.write = native_rtp_bridge_write,
-	.compatible = native_rtp_bridge_compatible,
-};
-
-static int unload_module(void)
-{
-	ao2_t_ref(native_rtp_bridge.format_capabilities, -1, "Dispose of capabilities in module unload");
-	return ast_bridge_technology_unregister(&native_rtp_bridge);
-}
-
-static int load_module(void)
-{
-	if (!(native_rtp_bridge.format_capabilities = ast_format_cap_alloc(0))) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO);
-	ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO);
-	ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT);
-
-	return ast_bridge_technology_register(&native_rtp_bridge);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Native RTP bridging module");
diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c
index 7665547..69e4114 100644
--- a/bridges/bridge_simple.c
+++ b/bridges/bridge_simple.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -41,54 +41,74 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
 #include "asterisk/frame.h"
 
 static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-	struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan;
-	struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan;
-
-	/*
-	 * If this is the first channel we can't make it compatible...
-	 * unless we make it compatible with itself.  O.o
-	 */
-	if (c0 == c1) {
+	struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan, *c1 = AST_LIST_LAST(&bridge->channels)->chan;
+
+	/* If this is the first channel we can't make it compatible... unless we make it compatible with itself O.o */
+	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+		return 0;
+	}
+
+	/* See if we need to make these compatible */
+	if ((ast_format_cmp(ast_channel_writeformat(c0), ast_channel_readformat(c1)) == AST_FORMAT_CMP_EQUAL) &&
+		(ast_format_cmp(ast_channel_readformat(c0), ast_channel_writeformat(c1)) == AST_FORMAT_CMP_EQUAL) &&
+		(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) {
 		return 0;
 	}
 
+	/* BOOM! We do. */
 	return ast_channel_make_compatible(c0, c1);
 }
 
-static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+static enum ast_bridge_write_result simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
+	struct ast_bridge_channel *other = NULL;
+
+	/* If this is the only channel in this bridge then immediately exit */
+	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+		return AST_BRIDGE_WRITE_FAILED;
+	}
+
+	/* Find the channel we actually want to write to */
+	if (!(other = (AST_LIST_FIRST(&bridge->channels) == bridge_channel ? AST_LIST_LAST(&bridge->channels) : AST_LIST_FIRST(&bridge->channels)))) {
+		return AST_BRIDGE_WRITE_FAILED;
+	}
+
+	/* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		ast_write(other->chan, frame);
+	}
+
+	return AST_BRIDGE_WRITE_SUCCESS;
 }
 
 static struct ast_bridge_technology simple_bridge = {
 	.name = "simple_bridge",
-	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
-	.preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX,
+	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_THREAD,
+	.preference = AST_BRIDGE_PREFERENCE_MEDIUM,
 	.join = simple_bridge_join,
 	.write = simple_bridge_write,
 };
 
 static int unload_module(void)
 {
-	ao2_cleanup(simple_bridge.format_capabilities);
-	simple_bridge.format_capabilities = NULL;
+	ast_format_cap_destroy(simple_bridge.format_capabilities);
 	return ast_bridge_technology_unregister(&simple_bridge);
 }
 
 static int load_module(void)
 {
-	if (!(simple_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(simple_bridge.format_capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO);
-	ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO);
-	ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT);
+	ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
+	ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
+	ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
 
 	return ast_bridge_technology_register(&simple_bridge);
 }
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index 8fca093..0d14c15 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423423 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -45,8 +45,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423423 $")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
 #include "asterisk/frame.h"
 #include "asterisk/options.h"
 #include "asterisk/logger.h"
@@ -100,15 +100,13 @@ struct softmix_channel {
 	struct ast_frame read_frame;
 	/*! DSP for detecting silence */
 	struct ast_dsp *dsp;
-	/*!
-	 * \brief TRUE if a channel is talking.
-	 *
-	 * \note This affects how the channel's audio is mixed back to
-	 * it.
-	 */
-	unsigned int talking:1;
-	/*! TRUE if the channel provided audio for this mixing interval */
-	unsigned int have_audio:1;
+	/*! Bit used to indicate if a channel is talking or not. This affects how
+	 * the channel's audio is mixed back to it. */
+	int talking:1;
+	/*! Bit used to indicate that the channel provided audio for this mixing interval */
+	int have_audio:1;
+	/*! Bit used to indicate that a frame is available to be written out to the channel */
+	int have_frame:1;
 	/*! Buffer containing final mixed audio from all sources */
 	short final_buf[MAX_DATALEN];
 	/*! Buffer containing only the audio from the channel */
@@ -119,58 +117,42 @@ struct softmix_channel {
 
 struct softmix_bridge_data {
 	struct ast_timer *timer;
-	/*!
-	 * \brief Bridge pointer passed to the softmix mixing thread.
-	 *
-	 * \note Does not need a reference because the bridge will
-	 * always exist while the mixing thread exists even if the
-	 * bridge is no longer actively using the softmix technology.
-	 */
-	struct ast_bridge *bridge;
-	/*! Lock for signaling the mixing thread. */
-	ast_mutex_t lock;
-	/*! Condition, used if we need to wake up the mixing thread. */
-	ast_cond_t cond;
-	/*! Thread handling the mixing */
-	pthread_t thread;
 	unsigned int internal_rate;
 	unsigned int internal_mixing_interval;
-	/*! TRUE if the mixing thread should stop */
-	unsigned int stop:1;
 };
 
 struct softmix_stats {
-	/*! Each index represents a sample rate used above the internal rate. */
-	unsigned int sample_rates[16];
-	/*! Each index represents the number of channels using the same index in the sample_rates array.  */
-	unsigned int num_channels[16];
-	/*! the number of channels above the internal sample rate */
-	unsigned int num_above_internal_rate;
-	/*! the number of channels at the internal sample rate */
-	unsigned int num_at_internal_rate;
-	/*! the absolute highest sample rate supported by any channel in the bridge */
-	unsigned int highest_supported_rate;
-	/*! Is the sample rate locked by the bridge, if so what is that rate.*/
-	unsigned int locked_rate;
+		/*! Each index represents a sample rate used above the internal rate. */
+		unsigned int sample_rates[16];
+		/*! Each index represents the number of channels using the same index in the sample_rates array.  */
+		unsigned int num_channels[16];
+		/*! the number of channels above the internal sample rate */
+		unsigned int num_above_internal_rate;
+		/*! the number of channels at the internal sample rate */
+		unsigned int num_at_internal_rate;
+		/*! the absolute highest sample rate supported by any channel in the bridge */
+		unsigned int highest_supported_rate;
+		/*! Is the sample rate locked by the bridge, if so what is that rate.*/
+		unsigned int locked_rate;
 };
 
 struct softmix_mixing_array {
-	unsigned int max_num_entries;
-	unsigned int used_entries;
+	int max_num_entries;
+	int used_entries;
 	int16_t **buffers;
 };
 
 struct softmix_translate_helper_entry {
 	int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt
 	                              and re-init if it was usable. */
-	struct ast_format *dst_format; /*!< The destination format for this helper */
+	struct ast_format dst_format; /*!< The destination format for this helper */
 	struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */
 	struct ast_frame *out_frame; /*!< The output frame from the last translation */
 	AST_LIST_ENTRY(softmix_translate_helper_entry) entry;
 };
 
 struct softmix_translate_helper {
-	struct ast_format *slin_src; /*!< the source format expected for all the translators */
+	struct ast_format slin_src; /*!< the source format expected for all the translators */
 	AST_LIST_HEAD_NOLOCK(, softmix_translate_helper_entry) entries;
 };
 
@@ -180,14 +162,15 @@ static struct softmix_translate_helper_entry *softmix_translate_helper_entry_all
 	if (!(entry = ast_calloc(1, sizeof(*entry)))) {
 		return NULL;
 	}
-	entry->dst_format = ao2_bump(dst);
+	ast_format_copy(&entry->dst_format, dst);
+	/* initialize this to one so that the first time through the cleanup code after
+	   allocation it won't be removed from the entry list */
+	entry->num_times_requested = 1;
 	return entry;
 }
 
 static void *softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry)
 {
-	ao2_cleanup(entry->dst_format);
-
 	if (entry->trans_pvt) {
 		ast_translator_free_path(entry->trans_pvt);
 	}
@@ -201,7 +184,7 @@ static void *softmix_translate_helper_free_entry(struct softmix_translate_helper
 static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
 {
 	memset(trans_helper, 0, sizeof(*trans_helper));
-	trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate);
+	ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
 }
 
 static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper)
@@ -217,11 +200,11 @@ static void softmix_translate_helper_change_rate(struct softmix_translate_helper
 {
 	struct softmix_translate_helper_entry *entry;
 
-	trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate);
+	ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) {
 		if (entry->trans_pvt) {
 			ast_translator_free_path(entry->trans_pvt);
-			if (!(entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src))) {
+			if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) {
 				AST_LIST_REMOVE_CURRENT(entry);
 				entry = softmix_translate_helper_free_entry(entry);
 			}
@@ -233,7 +216,7 @@ static void softmix_translate_helper_change_rate(struct softmix_translate_helper
 /*!
  * \internal
  * \brief Get the next available audio on the softmix channel's read stream
- * and determine if it should be mixed out or not on the write stream.
+ * and determine if it should be mixed out or not on the write stream. 
  *
  * \retval pointer to buffer containing the exact number of samples requested on success.
  * \retval NULL if no samples are present
@@ -270,25 +253,38 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h
 		for (i = 0; i < sc->write_frame.samples; i++) {
 			ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
 		}
+		/* check to see if any entries exist for the format. if not we'll want
+		   to remove it during cleanup */
+		AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
+			if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
+				++entry->num_times_requested;
+				break;
+			}
+		}
 		/* do not do any special write translate optimization if we had to make
 		 * a special mix for them to remove their own audio. */
 		return;
 	}
 
+	/* Attempt to optimize channels using the same translation path/codec. Build a list of entries
+	   of translation paths and track the number of references for each type. Each one of the same
+	   type should be able to use the same out_frame. Since the optimization is only necessary for
+	   multiple channels (>=2) using the same codec make sure resources are allocated only when
+	   needed and released when not (see also softmix_translate_helper_cleanup */
 	AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
-		if (ast_format_cmp(entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
+		if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
 			entry->num_times_requested++;
 		} else {
 			continue;
 		}
 		if (!entry->trans_pvt && (entry->num_times_requested > 1)) {
-			entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src);
+			entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src);
 		}
 		if (entry->trans_pvt && !entry->out_frame) {
 			entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0);
 		}
 		if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) {
-			ao2_replace(sc->write_frame.subclass.format, entry->out_frame->subclass.format);
+			ast_format_copy(&sc->write_frame.subclass.format, &entry->out_frame->subclass.format);
 			memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
 			sc->write_frame.datalen = entry->out_frame->datalen;
 			sc->write_frame.samples = entry->out_frame->samples;
@@ -304,58 +300,108 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h
 
 static void softmix_translate_helper_cleanup(struct softmix_translate_helper *trans_helper)
 {
-	struct softmix_translate_helper_entry *entry;
+	struct softmix_translate_helper_entry *entry = NULL;
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) {
+		/* if it hasn't been requested then remove it */
+		if (!entry->num_times_requested) {
+			AST_LIST_REMOVE_CURRENT(entry);
+			softmix_translate_helper_free_entry(entry);
+			continue;
+		}
 
-	AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
 		if (entry->out_frame) {
 			ast_frfree(entry->out_frame);
 			entry->out_frame = NULL;
 		}
+
+		/* nothing is optimized for a single path reference, so there is
+		   no reason to continue to hold onto the codec */
+		if (entry->num_times_requested == 1 && entry->trans_pvt) {
+			ast_translator_free_path(entry->trans_pvt);
+			entry->trans_pvt = NULL;
+		}
+
+		/* for each iteration (a mixing run) in the bridge softmix thread the number
+		   of references to a given entry is recalculated, so reset the number of
+		   times requested */
 		entry->num_times_requested = 0;
 	}
+	AST_LIST_TRAVERSE_SAFE_END;
+}
+
+static void softmix_bridge_data_destroy(void *obj)
+{
+	struct softmix_bridge_data *softmix_data = obj;
+
+	if (softmix_data->timer) {
+		ast_timer_close(softmix_data->timer);
+		softmix_data->timer = NULL;
+	}
+}
+
+/*! \brief Function called when a bridge is created */
+static int softmix_bridge_create(struct ast_bridge *bridge)
+{
+	struct softmix_bridge_data *softmix_data;
+
+	if (!(softmix_data = ao2_alloc(sizeof(*softmix_data), softmix_bridge_data_destroy))) {
+		return -1;
+	}
+	if (!(softmix_data->timer = ast_timer_open())) {
+		ast_log(AST_LOG_WARNING, "Failed to open timer for softmix bridge\n");
+		ao2_ref(softmix_data, -1);
+		return -1;
+	}
+
+	/* start at 8khz, let it grow from there */
+	softmix_data->internal_rate = 8000;
+	softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
+
+	bridge->bridge_pvt = softmix_data;
+	return 0;
+}
+
+/*! \brief Function called when a bridge is destroyed */
+static int softmix_bridge_destroy(struct ast_bridge *bridge)
+{
+	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
+	if (!bridge->bridge_pvt) {
+		return -1;
+	}
+	ao2_ref(softmix_data, -1);
+	bridge->bridge_pvt = NULL;
+	return 0;
 }
 
 static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset)
 {
-	struct softmix_channel *sc = bridge_channel->tech_pvt;
-	unsigned int channel_read_rate = ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan));
+	struct softmix_channel *sc = bridge_channel->bridge_pvt;
+	unsigned int channel_read_rate = ast_format_rate(ast_channel_rawreadformat(bridge_channel->chan));
 
 	ast_mutex_lock(&sc->lock);
 	if (reset) {
 		ast_slinfactory_destroy(&sc->factory);
 		ast_dsp_free(sc->dsp);
 	}
-
-	/* Setup write frame parameters */
+	/* Setup read/write frame parameters */
 	sc->write_frame.frametype = AST_FRAME_VOICE;
-	/*
-	 * NOTE: The write_frame format holds a reference because translation
-	 * could be needed and the format changed to the translated format
-	 * for the channel.  The translated format may not be a
-	 * static cached format.
-	 */
-	ao2_replace(sc->write_frame.subclass.format, ast_format_cache_get_slin_by_rate(rate));
+	ast_format_set(&sc->write_frame.subclass.format, ast_format_slin_by_rate(rate), 0);
 	sc->write_frame.data.ptr = sc->final_buf;
 	sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval);
 	sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval);
 
-	/* Setup read frame parameters */
 	sc->read_frame.frametype = AST_FRAME_VOICE;
-	/*
-	 * NOTE: The read_frame format does not hold a reference because it
-	 * will always be a signed linear format.
-	 */
-	sc->read_frame.subclass.format = ast_format_cache_get_slin_by_rate(channel_read_rate);
+	ast_format_set(&sc->read_frame.subclass.format, ast_format_slin_by_rate(channel_read_rate), 0);
 	sc->read_frame.data.ptr = sc->our_buf;
 	sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval);
 	sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval);
 
 	/* Setup smoother */
-	ast_slinfactory_init_with_format(&sc->factory, sc->write_frame.subclass.format);
+	ast_slinfactory_init_with_format(&sc->factory, &sc->write_frame.subclass.format);
 
 	/* set new read and write formats on channel. */
-	ast_set_read_format(bridge_channel->chan, sc->read_frame.subclass.format);
-	ast_set_write_format(bridge_channel->chan, sc->write_frame.subclass.format);
+	ast_set_read_format(bridge_channel->chan, &sc->read_frame.subclass.format);
+	ast_set_write_format(bridge_channel->chan, &sc->write_frame.subclass.format);
 
 	/* set up new DSP.  This is on the read side only right before the read frame enters the smoother.  */
 	sc->dsp = ast_dsp_new_with_rate(channel_read_rate);
@@ -369,90 +415,39 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch
 	ast_mutex_unlock(&sc->lock);
 }
 
-/*!
- * \internal
- * \brief Poke the mixing thread in case it is waiting for an active channel.
- * \since 12.0.0
- *
- * \param softmix_data Bridge mixing data.
- *
- * \return Nothing
- */
-static void softmix_poke_thread(struct softmix_bridge_data *softmix_data)
-{
-	ast_mutex_lock(&softmix_data->lock);
-	ast_cond_signal(&softmix_data->cond);
-	ast_mutex_unlock(&softmix_data->lock);
-}
-
-/*! \brief Function called when a channel is unsuspended from the bridge */
-static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	if (bridge->tech_pvt) {
-		softmix_poke_thread(bridge->tech_pvt);
-	}
-}
-
-/*!
- * \internal
- * \brief Indicate a source change to the channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel source is changing.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int softmix_src_change(struct ast_bridge_channel *bridge_channel)
-{
-	return ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_SRCCHANGE, NULL, 0);
-}
-
 /*! \brief Function called when a channel is joined into the bridge */
 static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-	struct softmix_channel *sc;
-	struct softmix_bridge_data *softmix_data;
-
-	softmix_data = bridge->tech_pvt;
-	if (!softmix_data) {
-		return -1;
-	}
+	struct softmix_channel *sc = NULL;
+	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
 
 	/* Create a new softmix_channel structure and allocate various things on it */
 	if (!(sc = ast_calloc(1, sizeof(*sc)))) {
 		return -1;
 	}
 
-	softmix_src_change(bridge_channel);
-
 	/* Can't forget the lock */
 	ast_mutex_init(&sc->lock);
 
 	/* Can't forget to record our pvt structure within the bridged channel structure */
-	bridge_channel->tech_pvt = sc;
+	bridge_channel->bridge_pvt = sc;
 
 	set_softmix_bridge_data(softmix_data->internal_rate,
-		softmix_data->internal_mixing_interval
-			? softmix_data->internal_mixing_interval
-			: DEFAULT_SOFTMIX_INTERVAL,
+		softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL,
 		bridge_channel, 0);
 
-	softmix_poke_thread(softmix_data);
 	return 0;
 }
 
 /*! \brief Function called when a channel leaves the bridge */
-static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+static int softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-	struct softmix_channel *sc = bridge_channel->tech_pvt;
+	struct softmix_channel *sc = bridge_channel->bridge_pvt;
 
-	if (!sc) {
-		return;
+	if (!(bridge_channel->bridge_pvt)) {
+		return 0;
 	}
-	bridge_channel->tech_pvt = NULL;
-
-	softmix_src_change(bridge_channel);
+	bridge_channel->bridge_pvt = NULL;
 
 	/* Drop mutex lock */
 	ast_mutex_destroy(&sc->lock);
@@ -460,107 +455,116 @@ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_ch
 	/* Drop the factory */
 	ast_slinfactory_destroy(&sc->factory);
 
-	/* Drop any formats on the frames */
-	ao2_cleanup(sc->write_frame.subclass.format);
-
 	/* Drop the DSP */
 	ast_dsp_free(sc->dsp);
 
 	/* Eep! drop ourselves */
 	ast_free(sc);
+
+	return 0;
 }
 
-static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct ast_frame *frame)
+/*!
+ * \internal
+ * \brief If the bridging core passes DTMF to us, then they want it to be distributed out to all memebers. Do that here.
+ */
+static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	struct ast_bridge_channel *cur;
+	struct ast_bridge_channel *tmp;
+	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
+		if (tmp == bridge_channel) {
+			continue;
+		}
+		ast_write(tmp->chan, frame);
+	}
+}
 
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		if (cur->suspended) {
+static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct ast_frame *frame)
+{
+	struct ast_bridge_channel *tmp;
+	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
+		if (tmp->suspended) {
 			continue;
 		}
-		if (ast_bridge_is_video_src(bridge, cur->chan) == 1) {
-			ast_bridge_channel_queue_frame(cur, frame);
+		if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) {
+			ast_write(tmp->chan, frame);
 			break;
 		}
 	}
 }
 
-/*!
- * \internal
- * \brief Determine what to do with a video frame.
- * \since 12.0.0
- *
- * \param bridge Which bridge is getting the frame
- * \param bridge_channel Which channel is writing the frame.
- * \param frame What is being written.
- *
- * \return Nothing
- */
-static void softmix_bridge_write_video(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+static void softmix_pass_video_all(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame, int echo)
 {
-	struct softmix_channel *sc;
-	int video_src_priority;
-
-	/* Determine if the video frame should be distributed or not */
-	switch (bridge->softmix.video_mode.mode) {
-	case AST_BRIDGE_VIDEO_MODE_NONE:
-		break;
-	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
-		video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan);
-		if (video_src_priority == 1) {
-			/* Pass to me and everyone else. */
-			ast_bridge_queue_everyone_else(bridge, NULL, frame);
+	struct ast_bridge_channel *tmp;
+	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
+		if (tmp->suspended) {
+			continue;
 		}
-		break;
-	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
-		sc = bridge_channel->tech_pvt;
-		ast_mutex_lock(&sc->lock);
-		ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan,
-			sc->video_talker.energy_average,
-			frame->subclass.frame_ending);
-		ast_mutex_unlock(&sc->lock);
-		video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan);
-		if (video_src_priority == 1) {
-			int num_src = ast_bridge_number_video_src(bridge);
-			int echo = num_src > 1 ? 0 : 1;
-
-			ast_bridge_queue_everyone_else(bridge, echo ? NULL : bridge_channel, frame);
-		} else if (video_src_priority == 2) {
-			softmix_pass_video_top_priority(bridge, frame);
+		if ((tmp->chan == bridge_channel->chan) && !echo) {
+			continue;
 		}
-		break;
+		ast_write(tmp->chan, frame);
 	}
 }
 
-/*!
- * \internal
- * \brief Determine what to do with a voice frame.
- * \since 12.0.0
- *
- * \param bridge Which bridge is getting the frame
- * \param bridge_channel Which channel is writing the frame.
- * \param frame What is being written.
- *
- * \return Nothing
- */
-static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+/*! \brief Function called when a channel writes a frame into the bridge */
+static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	struct softmix_channel *sc = bridge_channel->tech_pvt;
-	struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
+	struct softmix_channel *sc = bridge_channel->bridge_pvt;
+	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
 	int totalsilence = 0;
 	int cur_energy = 0;
 	int silence_threshold = bridge_channel->tech_args.silence_threshold ?
 		bridge_channel->tech_args.silence_threshold :
 		DEFAULT_SOFTMIX_SILENCE_THRESHOLD;
 	char update_talking = -1;  /* if this is set to 0 or 1, tell the bridge that the channel has started or stopped talking. */
+	int res = AST_BRIDGE_WRITE_SUCCESS;
+
+	/* Only accept audio frames, all others are unsupported */
+	if (frame->frametype == AST_FRAME_DTMF_END || frame->frametype == AST_FRAME_DTMF_BEGIN) {
+		softmix_pass_dtmf(bridge, bridge_channel, frame);
+		goto bridge_write_cleanup;
+	} else if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO) {
+		res = AST_BRIDGE_WRITE_UNSUPPORTED;
+		goto bridge_write_cleanup;
+	} else if (frame->datalen == 0) {
+		goto bridge_write_cleanup;
+	}
+
+	/* Determine if this video frame should be distributed or not */
+	if (frame->frametype == AST_FRAME_VIDEO) {
+		int num_src = ast_bridge_number_video_src(bridge);
+		int video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan);
+
+		switch (bridge->video_mode.mode) {
+		case AST_BRIDGE_VIDEO_MODE_NONE:
+			break;
+		case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+			if (video_src_priority == 1) {
+				softmix_pass_video_all(bridge, bridge_channel, frame, 1);
+			}
+			break;
+		case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+			ast_mutex_lock(&sc->lock);
+			ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan, sc->video_talker.energy_average, ast_format_get_video_mark(&frame->subclass.format));
+			ast_mutex_unlock(&sc->lock);
+			if (video_src_priority == 1) {
+				int echo = num_src > 1 ? 0 : 1;
+				softmix_pass_video_all(bridge, bridge_channel, frame, echo);
+			} else if (video_src_priority == 2) {
+				softmix_pass_video_top_priority(bridge, frame);
+			}
+			break;
+		}
+		goto bridge_write_cleanup;
+	}
 
-	/* Write the frame into the conference */
+	/* If we made it here, we are going to write the frame into the conference */
 	ast_mutex_lock(&sc->lock);
 	ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy);
 
-	if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) {
+	if (bridge->video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) {
 		int cur_slot = sc->video_talker.energy_history_cur_slot;
-
 		sc->video_talker.energy_accum -= sc->video_talker.energy_history[cur_slot];
 		sc->video_talker.energy_accum += cur_energy;
 		sc->video_talker.energy_history[cur_slot] = cur_energy;
@@ -592,101 +596,55 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri
 
 	/* If a frame was provided add it to the smoother, unless drop silence is enabled and this frame
 	 * is not determined to be talking. */
-	if (!(bridge_channel->tech_args.drop_silence && !sc->talking)) {
+	if (!(bridge_channel->tech_args.drop_silence && !sc->talking) &&
+		(frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format))) {
 		ast_slinfactory_feed(&sc->factory, frame);
 	}
 
+	/* If a frame is ready to be written out, do so */
+	if (sc->have_frame) {
+		ast_write(bridge_channel->chan, &sc->write_frame);
+		sc->have_frame = 0;
+	}
+
 	/* Alllll done */
 	ast_mutex_unlock(&sc->lock);
 
 	if (update_talking != -1) {
-		ast_bridge_channel_notify_talking(bridge_channel, update_talking);
+		ast_bridge_notify_talking(bridge, bridge_channel, update_talking);
 	}
-}
 
-/*!
- * \internal
- * \brief Determine what to do with a control frame.
- * \since 12.0.0
- *
- * \param bridge Which bridge is getting the frame
- * \param bridge_channel Which channel is writing the frame.
- * \param frame What is being written.
- *
- * \retval 0 Frame accepted into the bridge.
- * \retval -1 Frame needs to be deferred.
- */
-static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	/*
-	 * XXX Softmix needs to use channel roles to determine what to
-	 * do with control frames.
-	 */
-	return 0;
+	return res;
+
+bridge_write_cleanup:
+	/* Even though the frame is not being written into the conference because it is not audio,
+	 * we should use this opportunity to check to see if a frame is ready to be written out from
+	 * the conference to the channel. */
+	ast_mutex_lock(&sc->lock);
+	if (sc->have_frame) {
+		ast_write(bridge_channel->chan, &sc->write_frame);
+		sc->have_frame = 0;
+	}
+	ast_mutex_unlock(&sc->lock);
+
+	return res;
 }
 
-/*!
- * \internal
- * \brief Determine what to do with a frame written into the bridge.
- * \since 12.0.0
- *
- * \param bridge Which bridge is getting the frame
- * \param bridge_channel Which channel is writing the frame.
- * \param frame What is being written.
- *
- * \retval 0 Frame accepted into the bridge.
- * \retval -1 Frame needs to be deferred.
- *
- * \note On entry, bridge is already locked.
- */
-static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+/*! \brief Function called when the channel's thread is poked */
+static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-	int res = 0;
+	struct softmix_channel *sc = bridge_channel->bridge_pvt;
 
-	if (!bridge->tech_pvt || (bridge_channel && !bridge_channel->tech_pvt)) {
-		/* "Accept" the frame and discard it. */
-		return 0;
-	}
+	ast_mutex_lock(&sc->lock);
 
-	/*
-	 * XXX Softmix needs to use channel roles to determine who gets
-	 * what frame.  Possible roles: announcer, recorder, agent,
-	 * supervisor.
-	 */
-	switch (frame->frametype) {
-	case AST_FRAME_NULL:
-		/* "Accept" the frame and discard it. */
-		break;
-	case AST_FRAME_DTMF_BEGIN:
-	case AST_FRAME_DTMF_END:
-		res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
-		break;
-	case AST_FRAME_VOICE:
-		if (bridge_channel) {
-			softmix_bridge_write_voice(bridge, bridge_channel, frame);
-		}
-		break;
-	case AST_FRAME_VIDEO:
-		if (bridge_channel) {
-			softmix_bridge_write_video(bridge, bridge_channel, frame);
-		}
-		break;
-	case AST_FRAME_CONTROL:
-		res = softmix_bridge_write_control(bridge, bridge_channel, frame);
-		break;
-	case AST_FRAME_BRIDGE_ACTION:
-		res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
-		break;
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
-		ast_log(LOG_ERROR, "Synchronous bridge action written to a softmix bridge.\n");
-		ast_assert(0);
-	default:
-		ast_debug(3, "Frame type %u unsupported\n", frame->frametype);
-		/* "Accept" the frame and discard it. */
-		break;
+	if (sc->have_frame) {
+		ast_write(bridge_channel->chan, &sc->write_frame);
+		sc->have_frame = 0;
 	}
 
-	return res;
+	ast_mutex_unlock(&sc->lock);
+
+	return 0;
 }
 
 static void gather_softmix_stats(struct softmix_stats *stats,
@@ -696,8 +654,8 @@ static void gather_softmix_stats(struct softmix_stats *stats,
 	int channel_native_rate;
 	int i;
 	/* Gather stats about channel sample rates. */
-	channel_native_rate = MAX(ast_format_get_sample_rate(ast_channel_rawwriteformat(bridge_channel->chan)),
-		ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan)));
+	channel_native_rate = MAX(ast_format_rate(ast_channel_rawwriteformat(bridge_channel->chan)),
+		ast_format_rate(ast_channel_rawreadformat(bridge_channel->chan)));
 
 	if (channel_native_rate > stats->highest_supported_rate) {
 		stats->highest_supported_rate = channel_native_rate;
@@ -723,8 +681,8 @@ static void gather_softmix_stats(struct softmix_stats *stats,
  * \brief Analyse mixing statistics and change bridges internal rate
  * if necessary.
  *
- * \retval 0, no changes to internal rate
- * \retval 1, internal rate was changed, update all the channels on the next mixing iteration.
+ * \retval 0, no changes to internal rate 
+ * \ratval 1, internal rate was changed, update all the channels on the next mixing iteration.
  */
 static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data)
 {
@@ -740,8 +698,7 @@ static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct so
 		 * from the current rate we are using. */
 		if (softmix_data->internal_rate != stats->locked_rate) {
 			softmix_data->internal_rate = stats->locked_rate;
-			ast_debug(1, "Bridge is locked in at sample rate %u\n",
-				softmix_data->internal_rate);
+			ast_debug(1, " Bridge is locked in at sample rate %u\n", softmix_data->internal_rate);
 			return 1;
 		}
 	} else if (stats->num_above_internal_rate >= 2) {
@@ -780,15 +737,13 @@ static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct so
 			}
 		}
 
-		ast_debug(1, "Bridge changed from %u To %u\n",
-			softmix_data->internal_rate, best_rate);
+		ast_debug(1, " Bridge changed from %u To %u\n", softmix_data->internal_rate, best_rate);
 		softmix_data->internal_rate = best_rate;
 		return 1;
 	} else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) {
 		/* In this case, the highest supported rate is actually lower than the internal rate */
 		softmix_data->internal_rate = stats->highest_supported_rate;
-		ast_debug(1, "Bridge changed from %u to %u\n",
-			softmix_data->internal_rate, stats->highest_supported_rate);
+		ast_debug(1, " Bridge changed from %u to %u\n", softmix_data->internal_rate, stats->highest_supported_rate);
 		return 1;
 	}
 	return 0;
@@ -799,7 +754,7 @@ static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array,
 	memset(mixing_array, 0, sizeof(*mixing_array));
 	mixing_array->max_num_entries = starting_num_entries;
 	if (!(mixing_array->buffers = ast_calloc(mixing_array->max_num_entries, sizeof(int16_t *)))) {
-		ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure.\n");
+		ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
 		return -1;
 	}
 	return 0;
@@ -816,52 +771,48 @@ static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array,
 	/* give it some room to grow since memory is cheap but allocations can be expensive */
 	mixing_array->max_num_entries = num_entries;
 	if (!(tmp = ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries * sizeof(int16_t *))))) {
-		ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure.\n");
+		ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure. \n");
 		return -1;
 	}
 	mixing_array->buffers = tmp;
 	return 0;
 }
 
-/*!
- * \brief Mixing loop.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int softmix_mixing_loop(struct ast_bridge *bridge)
+/*! \brief Function which acts as the mixing thread */
+static int softmix_bridge_thread(struct ast_bridge *bridge)
 {
 	struct softmix_stats stats = { { 0 }, };
 	struct softmix_mixing_array mixing_array;
-	struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
+	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
 	struct ast_timer *timer;
 	struct softmix_translate_helper trans_helper;
-	int16_t buf[MAX_DATALEN];
+	int16_t buf[MAX_DATALEN] = { 0, };
 	unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
 	int timingfd;
 	int update_all_rates = 0; /* set this when the internal sample rate has changed */
-	unsigned int idx;
-	unsigned int x;
+	int i, x;
 	int res = -1;
 
+	if (!(softmix_data = bridge->bridge_pvt)) {
+		goto softmix_cleanup;
+	}
+
+	ao2_ref(softmix_data, 1);
 	timer = softmix_data->timer;
 	timingfd = ast_timer_fd(timer);
 	softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
 	ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
 
 	/* Give the mixing array room to grow, memory is cheap but allocations are expensive. */
-	if (softmix_mixing_array_init(&mixing_array, bridge->num_channels + 10)) {
+	if (softmix_mixing_array_init(&mixing_array, bridge->num + 10)) {
+		ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
 		goto softmix_cleanup;
 	}
 
-	/*
-	 * XXX Softmix needs to use channel roles to determine who gets
-	 * what audio mixed.
-	 */
-	while (!softmix_data->stop && bridge->num_active) {
-		struct ast_bridge_channel *bridge_channel;
+	while (!bridge->stop && !bridge->refresh && bridge->array_num) {
+		struct ast_bridge_channel *bridge_channel = NULL;
 		int timeout = -1;
-		struct ast_format *cur_slin = ast_format_cache_get_slin_by_rate(softmix_data->internal_rate);
+		enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate);
 		unsigned int softmix_samples = SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
 		unsigned int softmix_datalen = SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
 
@@ -870,15 +821,12 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 			 * all the memcpys used during this process depend on this assumption.  Rather
 			 * than checking this over and over again through out the code, this single
 			 * verification is done on each iteration. */
-			ast_log(LOG_WARNING,
-				"Bridge %s: Conference mixing error, requested mixing length greater than mixing buffer.\n",
-				bridge->uniqueid);
+			ast_log(LOG_WARNING, "Conference mixing error, requested mixing length greater than mixing buffer.\n");
 			goto softmix_cleanup;
 		}
 
 		/* Grow the mixing array buffer as participants are added. */
-		if (mixing_array.max_num_entries < bridge->num_channels
-			&& softmix_mixing_array_grow(&mixing_array, bridge->num_channels + 5)) {
+		if (mixing_array.max_num_entries < bridge->num && softmix_mixing_array_grow(&mixing_array, bridge->num + 5)) {
 			goto softmix_cleanup;
 		}
 
@@ -889,7 +837,7 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 		/* These variables help determine if a rate change is required */
 		if (!stat_iteration_counter) {
 			memset(&stats, 0, sizeof(stats));
-			stats.locked_rate = bridge->softmix.internal_sample_rate;
+			stats.locked_rate = bridge->internal_sample_rate;
 		}
 
 		/* If the sample rate has changed, update the translator helper */
@@ -899,7 +847,7 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 
 		/* Go through pulling audio from each factory that has it available */
 		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			struct softmix_channel *sc = bridge_channel->tech_pvt;
+			struct softmix_channel *sc = bridge_channel->bridge_pvt;
 
 			/* Update the sample rate to match the bridge's native sample rate if necessary. */
 			if (update_all_rates) {
@@ -926,15 +874,15 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 
 		/* mix it like crazy */
 		memset(buf, 0, softmix_datalen);
-		for (idx = 0; idx < mixing_array.used_entries; ++idx) {
-			for (x = 0; x < softmix_samples; ++x) {
-				ast_slinear_saturated_add(buf + x, mixing_array.buffers[idx] + x);
+		for (i = 0; i < mixing_array.used_entries; i++) {
+			for (x = 0; x < softmix_samples; x++) {
+				ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x);
 			}
 		}
 
 		/* Next step go through removing the channel's own audio and creating a good frame... */
 		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			struct softmix_channel *sc = bridge_channel->tech_pvt;
+			struct softmix_channel *sc = bridge_channel->bridge_pvt;
 
 			if (bridge_channel->suspended) {
 				continue;
@@ -943,8 +891,9 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 			ast_mutex_lock(&sc->lock);
 
 			/* Make SLINEAR write frame from local buffer */
-			ao2_t_replace(sc->write_frame.subclass.format, cur_slin,
-				"Replace softmix channel slin format");
+			if (sc->write_frame.subclass.format.id != cur_slin_id) {
+				ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
+			}
 			sc->write_frame.datalen = softmix_datalen;
 			sc->write_frame.samples = softmix_samples;
 			memcpy(sc->final_buf, buf, softmix_datalen);
@@ -952,10 +901,13 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 			/* process the softmix channel's new write audio */
 			softmix_process_write_audio(&trans_helper, ast_channel_rawwriteformat(bridge_channel->chan), sc);
 
+			/* The frame is now ready for use... */
+			sc->have_frame = 1;
+
 			ast_mutex_unlock(&sc->lock);
 
-			/* A frame is now ready for the channel. */
-			ast_bridge_channel_queue_frame(bridge_channel, &sc->write_frame);
+			/* Poke bridged channel thread just in case */
+			pthread_kill(bridge_channel->thread, SIGURG);
 		}
 
 		update_all_rates = 0;
@@ -965,23 +917,21 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 		}
 		stat_iteration_counter--;
 
-		ast_bridge_unlock(bridge);
+		ao2_unlock(bridge);
 		/* cleanup any translation frame data from the previous mixing iteration. */
 		softmix_translate_helper_cleanup(&trans_helper);
 		/* Wait for the timing source to tell us to wake up and get things done */
 		ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
 		if (ast_timer_ack(timer, 1) < 0) {
-			ast_log(LOG_ERROR, "Bridge %s: Failed to acknowledge timer in softmix.\n",
-				bridge->uniqueid);
-			ast_bridge_lock(bridge);
+			ast_log(LOG_ERROR, "Failed to acknowledge timer in softmix bridge\n");
+			ao2_lock(bridge);
 			goto softmix_cleanup;
 		}
-		ast_bridge_lock(bridge);
+		ao2_lock(bridge);
 
 		/* make sure to detect mixing interval changes if they occur. */
-		if (bridge->softmix.internal_mixing_interval
-			&& (bridge->softmix.internal_mixing_interval != softmix_data->internal_mixing_interval)) {
-			softmix_data->internal_mixing_interval = bridge->softmix.internal_mixing_interval;
+		if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) {
+			softmix_data->internal_mixing_interval = bridge->internal_mixing_interval;
 			ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
 			update_all_rates = 1; /* if the interval changes, the rates must be adjusted as well just to be notified new interval.*/
 		}
@@ -992,184 +942,38 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
 softmix_cleanup:
 	softmix_translate_helper_destroy(&trans_helper);
 	softmix_mixing_array_destroy(&mixing_array);
-	return res;
-}
-
-/*!
- * \internal
- * \brief Mixing thread.
- * \since 12.0.0
- *
- * \note The thread does not have its own reference to the
- * bridge.  The lifetime of the thread is tied to the lifetime
- * of the mixing technology association with the bridge.
- */
-static void *softmix_mixing_thread(void *data)
-{
-	struct softmix_bridge_data *softmix_data = data;
-	struct ast_bridge *bridge = softmix_data->bridge;
-
-	ast_bridge_lock(bridge);
-	if (bridge->callid) {
-		ast_callid_threadassoc_add(bridge->callid);
-	}
-
-	ast_debug(1, "Bridge %s: starting mixing thread\n", bridge->uniqueid);
-
-	while (!softmix_data->stop) {
-		if (!bridge->num_active) {
-			/* Wait for something to happen to the bridge. */
-			ast_bridge_unlock(bridge);
-			ast_mutex_lock(&softmix_data->lock);
-			if (!softmix_data->stop) {
-				ast_cond_wait(&softmix_data->cond, &softmix_data->lock);
-			}
-			ast_mutex_unlock(&softmix_data->lock);
-			ast_bridge_lock(bridge);
-			continue;
-		}
-
-		if (softmix_mixing_loop(bridge)) {
-			/*
-			 * A mixing error occurred.  Sleep and try again later so we
-			 * won't flood the logs.
-			 */
-			ast_bridge_unlock(bridge);
-			sleep(1);
-			ast_bridge_lock(bridge);
-		}
-	}
-
-	ast_bridge_unlock(bridge);
-
-	ast_debug(1, "Bridge %s: stopping mixing thread\n", bridge->uniqueid);
-
-	return NULL;
-}
-
-static void softmix_bridge_data_destroy(struct softmix_bridge_data *softmix_data)
-{
-	if (softmix_data->timer) {
-		ast_timer_close(softmix_data->timer);
-		softmix_data->timer = NULL;
+	if (softmix_data) {
+		ao2_ref(softmix_data, -1);
 	}
-	ast_mutex_destroy(&softmix_data->lock);
-	ast_cond_destroy(&softmix_data->cond);
-	ast_free(softmix_data);
-}
-
-/*! \brief Function called when a bridge is created */
-static int softmix_bridge_create(struct ast_bridge *bridge)
-{
-	struct softmix_bridge_data *softmix_data;
-
-	softmix_data = ast_calloc(1, sizeof(*softmix_data));
-	if (!softmix_data) {
-		return -1;
-	}
-	softmix_data->bridge = bridge;
-	ast_mutex_init(&softmix_data->lock);
-	ast_cond_init(&softmix_data->cond, NULL);
-	softmix_data->timer = ast_timer_open();
-	if (!softmix_data->timer) {
-		ast_log(AST_LOG_WARNING, "Failed to open timer for softmix bridge\n");
-		softmix_bridge_data_destroy(softmix_data);
-		return -1;
-	}
-	/* start at 8khz, let it grow from there */
-	softmix_data->internal_rate = 8000;
-	softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
-
-	bridge->tech_pvt = softmix_data;
-
-	/* Start the mixing thread. */
-	if (ast_pthread_create(&softmix_data->thread, NULL, softmix_mixing_thread,
-		softmix_data)) {
-		softmix_data->thread = AST_PTHREADT_NULL;
-		softmix_bridge_data_destroy(softmix_data);
-		bridge->tech_pvt = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Request the softmix mixing thread stop.
- * \since 12.0.0
- *
- * \param bridge Which bridge is being stopped.
- *
- * \return Nothing
- */
-static void softmix_bridge_stop(struct ast_bridge *bridge)
-{
-	struct softmix_bridge_data *softmix_data;
-
-	softmix_data = bridge->tech_pvt;
-	if (!softmix_data) {
-		return;
-	}
-
-	ast_mutex_lock(&softmix_data->lock);
-	softmix_data->stop = 1;
-	ast_mutex_unlock(&softmix_data->lock);
-}
-
-/*! \brief Function called when a bridge is destroyed */
-static void softmix_bridge_destroy(struct ast_bridge *bridge)
-{
-	struct softmix_bridge_data *softmix_data;
-	pthread_t thread;
-
-	softmix_data = bridge->tech_pvt;
-	if (!softmix_data) {
-		return;
-	}
-
-	/* Stop the mixing thread. */
-	ast_mutex_lock(&softmix_data->lock);
-	softmix_data->stop = 1;
-	ast_cond_signal(&softmix_data->cond);
-	thread = softmix_data->thread;
-	softmix_data->thread = AST_PTHREADT_NULL;
-	ast_mutex_unlock(&softmix_data->lock);
-	if (thread != AST_PTHREADT_NULL) {
-		ast_debug(1, "Bridge %s: Waiting for mixing thread to die.\n", bridge->uniqueid);
-		pthread_join(thread, NULL);
-	}
-
-	softmix_bridge_data_destroy(softmix_data);
-	bridge->tech_pvt = NULL;
+	return res;
 }
 
 static struct ast_bridge_technology softmix_bridge = {
 	.name = "softmix",
-	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX,
-	.preference = AST_BRIDGE_PREFERENCE_BASE_MULTIMIX,
+	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_THREAD | AST_BRIDGE_CAPABILITY_MULTITHREADED | AST_BRIDGE_CAPABILITY_OPTIMIZE | AST_BRIDGE_CAPABILITY_VIDEO,
+	.preference = AST_BRIDGE_PREFERENCE_LOW,
 	.create = softmix_bridge_create,
-	.stop = softmix_bridge_stop,
 	.destroy = softmix_bridge_destroy,
 	.join = softmix_bridge_join,
 	.leave = softmix_bridge_leave,
-	.unsuspend = softmix_bridge_unsuspend,
 	.write = softmix_bridge_write,
+	.thread = softmix_bridge_thread,
+	.poke = softmix_bridge_poke,
 };
 
 static int unload_module(void)
 {
-	ao2_cleanup(softmix_bridge.format_capabilities);
-	softmix_bridge.format_capabilities = NULL;
+	ast_format_cap_destroy(softmix_bridge.format_capabilities);
 	return ast_bridge_technology_unregister(&softmix_bridge);
 }
 
 static int load_module(void)
 {
-	if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	struct ast_format tmp;
+	if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(softmix_bridge.format_capabilities, ast_format_slin, 0);
+	ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0));
 	return ast_bridge_technology_register(&softmix_bridge);
 }
 
diff --git a/build_tools/.gitignore b/build_tools/.gitignore
new file mode 100644
index 0000000..c60a0df
--- /dev/null
+++ b/build_tools/.gitignore
@@ -0,0 +1 @@
+menuselect-deps
diff --git a/build_tools/cflags-devmode.xml b/build_tools/cflags-devmode.xml
index 0ed9f67..cfcc26c 100644
--- a/build_tools/cflags-devmode.xml
+++ b/build_tools/cflags-devmode.xml
@@ -24,6 +24,9 @@
 		<member name="THREAD_CRASH" displayname="Crash on mutex errors">
 			<support_level>extended</support_level>
 		</member>
+		<member name="CHANNEL_TRACE" displayname="Enable CHANNEL(trace) function">
+			<support_level>extended</support_level>
+		</member>
 		<member name="TEST_FRAMEWORK" displayname="Enable Test Framework API">
 			<support_level>extended</support_level>
 		</member>
diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml
index 082e8e6..95af0ac 100644
--- a/build_tools/cflags.xml
+++ b/build_tools/cflags.xml
@@ -1,4 +1,4 @@
-<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
+	<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
 		<member name="DONT_OPTIMIZE" displayname="Disable Optimizations by the Compiler">
 			<support_level>core</support_level>
 		</member>
@@ -8,9 +8,6 @@
 		<member name="REF_DEBUG" displayname="Enable reference count debugging">
 			<support_level>extended</support_level>
 		</member>
-		<member name="AO2_DEBUG" displayname="Enable internal Astobj2 debugging">
-			<support_level>extended</support_level>
-		</member>
 		<member name="STATIC_BUILD" displayname="Build static binaries">
 			<support_level>extended</support_level>
 		</member>
@@ -30,19 +27,6 @@
 		<member name="LOW_MEMORY" displayname="Optimize for Low Memory Usage">
 			<support_level>extended</support_level>
 		</member>
-		<member name="DISABLE_INLINE" displayname="Disable the inline API">
-			<!-- Added to work around GCC bug
-			     See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47816
-			  -->
-			<support_level>extended</support_level>
-		</member>
-		<member name="OPTIONAL_API" displayname="Enable the optional API">
-			<!-- Added to manually disable the optional API, since
-			     it's now supported on all systems.
-			  -->
-			<defaultenabled>yes</defaultenabled>
-			<support_level>extended</support_level>
-		</member>
 		<member name="BETTER_BACKTRACES" displayname="Use libbfd (GPL) to generate better inline backtraces">
 			<depend>BFD</depend>
 			<depend>DLADDR</depend>
diff --git a/build_tools/install_subst b/build_tools/install_subst
deleted file mode 100755
index 5b5407a..0000000
--- a/build_tools/install_subst
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-
-# install_subst: install a script while doing path substitution
-
-# install_subst [-d] source destination
-#
-# -d: file is data (rather than script)
-
-install_args=
-if [ "$1" = '-d' ]; then
-	install_args="-m 644"
-	shift
-fi
-
-set -e
-
-tmp=`mktemp install_subst_XXXXXX`
-
-cleanup_tmp() {
-	rm -f "$tmp"
-}
-
-# Delete it on exit
-trap cleanup_tmp 0
-
-src="$1"
-dst="$2"
-sed <"$src" \
-	-e "s|__ASTERISK_DATA_DIR__|$ASTDATADIR|g" \
-	-e "s|__ASTERISK_DB_DIR__|$ASTDBDIR|g" \
-	-e "s|__ASTERISK_ETC_DIR__|$ASTETCDIR|g" \
-	-e "s|__ASTERISK_HEADER_DIR__|$ASTHEADERDIR|g" \
-	-e "s|__ASTERISK_LIB_DIR__|$ASTLIBDIR|g" \
-	-e "s|__ASTERISK_LOG_DIR__|$ASTLOGDIR|g" \
-	-e "s|__ASTERISK_MOD_DIR__|$ASTMODDIR|g" \
-	-e "s|__ASTERISK_MAN_DIR__|$ASTMANDIR|g" \
-	-e "s|__ASTERISK_SBIN_DIR__|$ASTSBINDIR|g" \
-	-e "s|__ASTERISK_SPOOL_DIR__|$ASTSPOOLDIR|g" \
-	-e "s|__ASTERISK_VARLIB_DIR__|$ASTVARLIBDIR|g" \
-	-e "s|__ASTERISK_VARRUN_DIR__|$ASTVARRUNDIR|g" \
-	> "$tmp"
-
-install $install_args "$tmp" "$dst"
diff --git a/build_tools/make_buildopts_h b/build_tools/make_buildopts_h
index 55d08ba..3f7843b 100755
--- a/build_tools/make_buildopts_h
+++ b/build_tools/make_buildopts_h
@@ -1,8 +1,5 @@
 #!/bin/sh
 
-GREP=${GREP:-grep}
-MD5=${MD5:-md5sum}
-
 cat << END
 /*
  * buildopts.h 
@@ -10,27 +7,37 @@ cat << END
  */
 
 END
+
+if ${GREP} "AST_DEVMODE" makeopts | ${GREP} -q "yes"
+then
+	echo "#define AST_DEVMODE 1"
+	BUILDOPTS="AST_DEVMODE"
+fi
+
 TMP=`${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
 for x in ${TMP}; do
 	echo "#define ${x} 1"
+	if test "${x}" = "DONT_OPTIMIZE" \
+			-o "${x}" = "BETTER_BACKTRACES" \
+			-o "${x}" = "LOTS_OF_SPANS" \
+			-o "${x}" = "BUILD_NATIVE" \
+			-o "${x}" = "AO2_DEBUG" \
+			-o "${x}" = "REBUILD_PARSERS" \
+			-o "${x}" = "RADIO_RELAX" \
+			-o "${x}" = "DEBUG_SCHEDULER" \
+			-o "${x}" = "DETECT_DEADLOCKS" \
+			-o "${x}" = "DUMP_SCHEDULER" ; then
+		# These aren't ABI affecting options, keep them out of AST_BUILDOPTS
+		continue
+	fi
 	if test "x${BUILDOPTS}" != "x" ; then
 		BUILDOPTS="${BUILDOPTS}, ${x}"
 	else
 		BUILDOPTS="${x}"
 	fi
 done
-TMP=`${GREP} -e "^MENUSELECT_BUILD_DEPS" menuselect.makeopts | sed 's/MENUSELECT_BUILD_DEPS\=//g'`
-for x in ${TMP}; do
-	x2=`echo ${x} | tr a-z A-Z`
-	echo "#define AST_MODULE_${x2} 1"
-done
-if ${GREP} "AST_DEVMODE" makeopts | ${GREP} -q "yes"
-then
-	echo "#define AST_DEVMODE 1"
-	TMP="${TMP} AST_DEVMODE"
-fi
 
-BUILDSUM=`echo ${TMP} | ${MD5} | cut -c1-32`
+BUILDSUM=`echo ${BUILDOPTS} | ${MD5} | cut -c1-32`
 
 echo "#define AST_BUILDOPT_SUM \"${BUILDSUM}\""
 echo "#define AST_BUILDOPTS \"${BUILDOPTS}\""
diff --git a/build_tools/make_linker_version_script b/build_tools/make_linker_version_script
index 5d6bd42..871ff47 100755
--- a/build_tools/make_linker_version_script
+++ b/build_tools/make_linker_version_script
@@ -1,6 +1,5 @@
 #!/bin/sh
 
-AWK=${AWK:-awk}
-
 test -f ${1}.exports.in && ${AWK} "{sub(\"LINKER_SYMBOL_PREFIX\", \"${2}\"); print;}" ${1}.exports.in > ${1}.exports && exit 0
 test -f ${1}.exports.in || rm -f ${1}.exports && cp ${3}/default.exports ${1}.exports && exit 0
+
diff --git a/build_tools/make_version b/build_tools/make_version
index d11c096..4174844 100755
--- a/build_tools/make_version
+++ b/build_tools/make_version
@@ -1,8 +1,6 @@
 #!/bin/sh
 
-AWK=${AWK:-awk}
-GIT=${GIT:-git}
-GREP=${GREP:-grep}
+MAINLINE_BRANCH=11
 
 if [ -f ${1}/.version ]; then
     cat ${1}/.version
@@ -96,20 +94,20 @@ elif [ -d ${1}/.git ]; then
     # If the first log commit messages indicates that this is checked into
     # subversion, we'll just use the SVN- form of the revision.
     MODIFIED=""
-    SVN_REV=`${GIT} log --pretty=full -1 | ${GREP} -F "git-svn-id:" | sed -e "s/.*\@\([^\s]*\)\s.*/\1/g"`
+    SVN_REV=`${GIT} log --pretty=full -1 | grep -F "git-svn-id:" | sed -e "s/.*\@\([^\s]*\)\s.*/\1/g"`
     if [ -z "$SVN_REV" ]; then
-        VERSION=GIT-`${GIT} describe --long --always --tags --dirty=M 2> /dev/null`
+        VERSION=`${GIT} describe --long --always --tags --dirty=M 2> /dev/null`
         if [ $? -ne 0 ]; then
             if [ "`${GIT} ls-files -m | wc -l`" != "0" ]; then
                 MODIFIED="M"
             fi
             # Some older versions of git do not support all the above
             # options.
-            VERSION=GIT-`${GIT} rev-parse --short --verify HEAD`${MODIFIED}
+            VERSION=`${GIT} rev-parse --short --verify HEAD`${MODIFIED}
         fi
-        echo ${VERSION}
+        echo GIT-${MAINLINE_BRANCH}-${VERSION}
     else
-        PARTS=`LANG=C ${GIT} log --pretty=full | ${GREP} -F "git-svn-id:" | head -1 | ${AWK} '{print $2;}' | sed -e s:^.*/svn/$2/:: | sed -e 's:/: :g' | sed -e 's/@.*$//g'`
+        PARTS=`LANG=C ${GIT} log --pretty=full | grep -F "git-svn-id:" | head -1 | awk '{print $2;}' | sed -e s:^.*/svn/$2/:: | sed -e 's:/: :g' | sed -e 's/@.*$//g'`
         BRANCH=0
         TEAM=0
         TAG=0
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index a77530b..2b5efc4 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -15,6 +15,7 @@ GNU_LD=@GNU_LD@
 GSM=@PBX_GSM@
 ILBC=@PBX_ILBC@
 GTK2=@PBX_GTK2@
+H323=@PBX_H323@
 HOARD=@PBX_HOARD@
 ICAL=@PBX_ICAL@
 ICONV=@PBX_ICONV@
@@ -24,8 +25,6 @@ IODBC=@PBX_IODBC@
 ISDNNET=@PBX_ISDNNET@
 IXJUSER=@PBX_IXJUSER@
 JACK=@PBX_JACK@
-JANSSON=@PBX_JANSSON@
-URIPARSER=@PBX_URIPARSER@
 KQUEUE=@PBX_KQUEUE@
 LDAP=@PBX_LDAP@
 LIBEDIT=@PBX_LIBEDIT@
@@ -41,11 +40,9 @@ NEON=@PBX_NEON@
 NEON29=@PBX_NEON29@
 OGG=@PBX_OGG@
 OPENH323=@PBX_OPENH323@
-OPUS=@PBX_OPUS@
 OSPTK=@PBX_OSPTK@
 OSS=@PBX_OSS@
 PGSQL=@PBX_PGSQL@
-PJPROJECT=@PBX_PJPROJECT@
 POPT=@PBX_POPT@
 PORTAUDIO=@PBX_PORTAUDIO@
 PRI=@PBX_PRI@
@@ -66,6 +63,7 @@ SUPPSERV=@PBX_SUPPSERV@
 SYSLOG=@PBX_SYSLOG@
 TONEZONE=@PBX_TONEZONE@
 UNIXODBC=@PBX_UNIXODBC@
+UUID=@PBX_UUID@
 VORBIS=@PBX_VORBIS@
 VPB=@PBX_VPB@
 WINARCH=@PBX_WINARCH@
diff --git a/build_tools/mkpkgconfig b/build_tools/mkpkgconfig
index fd7d906..a677bcf 100755
--- a/build_tools/mkpkgconfig
+++ b/build_tools/mkpkgconfig
@@ -1,6 +1,5 @@
 #!/bin/sh
 PPATH="$1"
-GREP=${GREP:-grep}
 ## Make sure we were called from Makefile
 
 if [ "x$ASTERISKVERSIONNUM" = "x" ]; then
@@ -22,13 +21,12 @@ else
 fi
 
 ## Clean out CFLAGS for the spec file.
-
-LOCAL_CFLAGS=`echo $CFLAGS | ${EXTREGEX} 's/\s*-pipe\s*//g' | ${EXTREGEX} 's/-[Wmp]\S*\s*//g' | \
-  ${EXTREGEX} 's/-I(include|\.\.\/include) //g' | \
+LOCAL_CFLAGS=`echo $CFLAGS | ${EXTREGEX} 's/-pipe\s*//g' | ${EXTREGEX} 's/-[Wmp]\S*\s*//g' | \
+  ${EXTREGEX} 's/\s+-I(include|\.\.\/include)\s+/ /g' | \
   ${EXTREGEX} 's/-DINSTALL_PREFIX=\S* //g' | \
   ${EXTREGEX} 's/-DASTERISK_VERSION=\S* //g' | \
-  ${EXTREGEX} 's/-DAST(ETCDIR|LIBDIR|VARLIBDIR|VARRUNDIR|SPOOLDIR|LOGDIR|CONFPATH|MODDIR|AGIDIR)=\S* //g'`
-
+  ${EXTREGEX} 's/-DAST(ETCDIR|LIBDIR|VARLIBDIR|VARRUNDIR|SPOOLDIR|LOGDIR|CONFPATH|MODDIR|AGIDIR)=\S* //g' | \
+  ${EXTREGEX} 's/^\s|\s$//g'`
 
 cat <<EOF > "$PPATH/asterisk.pc"
 install_prefix=$INSTALL_PREFIX
diff --git a/build_tools/post_process_documentation.py b/build_tools/post_process_documentation.py
index 5fa1c5b..b2d9e5e 100644
--- a/build_tools/post_process_documentation.py
+++ b/build_tools/post_process_documentation.py
@@ -22,9 +22,9 @@ def merge_parameter_information(managerEvent):
 
     def __swap_parameter_documentation(one, two):
         # See who has the better documentation and use it
-        if (one.hasChildNodes() and not two.hasChildNodes()):
+        if (one.hasChildNodes()):
             two.parentNode.replaceChild(one.cloneNode(True), two)
-        elif (two.hasChildNodes() and not one.hasChildNodes()):
+        elif (two.hasChildNodes()):
             one.parentNode.replaceChild(two.cloneNode(True), one)
 
     def __merge_parameter(param, other_instances):
@@ -59,10 +59,7 @@ def collapse_event_pair(managerEventOne, managerEventTwo):
 def collapse_manager_events(rootNode, managerEvents):
     events = {}
     for managerEvent in managerEvents:
-        if (managerEvent.parentNode.nodeName == 'list-elements'
-            or managerEvent.parentNode.nodeName == 'responses'):
-            continue
-        managerEvent.parentNode.removeChild(managerEvent)
+        rootNode.removeChild(managerEvent)
         attr = managerEvent.getAttribute('name')
         if attr in events:
             # match, collapse the two managerEvents
diff --git a/cdr/Makefile b/cdr/Makefile
index 865bb3f..8ea490a 100644
--- a/cdr/Makefile
+++ b/cdr/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 #
 # Makefile for CDR backends
 #
diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c
index f159b90..36a6c7c 100644
--- a/cdr/cdr_adaptive_odbc.c
+++ b/cdr/cdr_adaptive_odbc.c
@@ -24,15 +24,6 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_adaptive_odbc.c uses the configuration file \ref cdr_adaptive_odbc.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_adaptive_odbc.conf cdr_adaptive_odbc.conf
- * \verbinclude cdr_adaptive_odbc.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>res_odbc</depend>
 	<support_level>core</support_level>
@@ -40,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <time.h>
@@ -196,7 +187,7 @@ static int load_config(void)
 					ast_trim_blanks(cdrvar);
 				}
 
-				ast_verb(3, "Found filter %s'%s' for CDR variable %s in %s@%s\n", negate ? "!" : "", var->value, cdrvar, tableptr->table, tableptr->connection);
+				ast_verb(3, "Found filter %s'%s' for cdr variable %s in %s@%s\n", negate ? "!" : "", var->value, cdrvar, tableptr->table, tableptr->connection);
 
 				entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(cdrvar) + 1 + strlen(var->value) + 1);
 				if (!entry) {
@@ -281,7 +272,7 @@ static int load_config(void)
 			if (entry->octetlen == 0)
 				entry->octetlen = entry->size;
 
-			ast_verb(4, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
+			ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
 			/* Insert column info into column list */
 			AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
 			res = 0;
@@ -433,7 +424,7 @@ static int odbc_log(struct ast_cdr *cdr)
 				ast_strftime(colbuf, sizeof(colbuf), "%Y-%m-%d %H:%M:%S", &tm);
 				colptr = colbuf;
 			} else {
-				ast_cdr_format_var(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), datefield ? 0 : 1);
+				ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0, datefield ? 0 : 1);
 			}
 
 			if (colptr) {
@@ -472,9 +463,9 @@ static int odbc_log(struct ast_cdr *cdr)
 					 * form (but only when we're dealing with a character-based field).
 					 */
 					if (strcasecmp(entry->name, "disposition") == 0) {
-						ast_cdr_format_var(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0);
+						ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
 					} else if (strcasecmp(entry->name, "amaflags") == 0) {
-						ast_cdr_format_var(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0);
+						ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
 					}
 
 					/* Truncate too-long fields */
@@ -723,7 +714,7 @@ static int odbc_log(struct ast_cdr *cdr)
 			} else if (entry->filtervalue
 				&& ((!entry->negatefiltervalue && entry->filtervalue[0] != '\0')
 					|| (entry->negatefiltervalue && entry->filtervalue[0] == '\0'))) {
-				ast_log(AST_LOG_WARNING, "CDR column '%s' was not set and does not match filter of"
+				ast_verb(4, "CDR column '%s' was not set and does not match filter of"
 					" %s'%s'.  Cancelling this CDR.\n",
 					entry->cdrname, entry->negatefiltervalue ? "!" : "",
 					entry->filtervalue);
@@ -737,7 +728,7 @@ static int odbc_log(struct ast_cdr *cdr)
 		ast_str_append(&sql2, 0, ")");
 		ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
 
-		ast_debug(3, "Executing [%s]\n", ast_str_buffer(sql));
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
 
 		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
 		if (stmt) {
@@ -767,10 +758,7 @@ early_release:
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
 		ast_cdr_register(name, ast_module_info->description, odbc_log);
 		ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
@@ -809,7 +797,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Adaptive ODBC CDR backend",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index 7aa6aa7..df7a5fe 100644
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -28,17 +28,13 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_csv.c uses the configuration file \ref cdr.conf
- * \addtogroup configuration_file Configuration Files
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_LOG_DIR */
 #include "asterisk/config.h"
@@ -58,6 +54,7 @@ static int accountlogs = 1;
 static int loguniqueid = 0;
 static int loguserfield = 0;
 static int loaded = 0;
+static int newcdrcolumns = 0;
 static const char config[] = "cdr.conf";
 
 /* #define CSV_LOGUNIQUEID 1 */
@@ -113,6 +110,7 @@ static int load_config(int reload)
 	usegmtime = 0;
 	loguniqueid = 0;
 	loguserfield = 0;
+	newcdrcolumns = 0;
 
 	if (!(v = ast_variable_browse(cfg, "csv"))) {
 		ast_config_destroy(cfg);
@@ -129,7 +127,10 @@ static int load_config(int reload)
 			loguniqueid = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "loguserfield")) {
 			loguserfield = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "newcdrcolumns")) {
+			newcdrcolumns = ast_true(v->value);
 		}
+
 	}
 	ast_config_destroy(cfg);
 	return 1;
@@ -234,13 +235,18 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
 	/* Disposition */
 	append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
 	/* AMA Flags */
-	append_string(buf, ast_channel_amaflags2string(cdr->amaflags), bufsize);
+	append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize);
 	/* Unique ID */
 	if (loguniqueid)
 		append_string(buf, cdr->uniqueid, bufsize);
 	/* append the user field */
 	if(loguserfield)
 		append_string(buf, cdr->userfield,bufsize);
+	if (newcdrcolumns) {
+		append_string(buf, cdr->peeraccount, bufsize);
+		append_string(buf, cdr->linkedid, bufsize);
+		append_int(buf, cdr->sequence, bufsize);
+	}
 	/* If we hit the end of our buffer, log an error */
 	if (strlen(buf) < bufsize - 5) {
 		/* Trim off trailing comma */
@@ -285,6 +291,9 @@ static int csv_log(struct ast_cdr *cdr)
 	char buf[1024];
 	char csvmaster[PATH_MAX];
 	snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
+#if 0
+	printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode);
+#endif
 	if (build_csv_record(buf, sizeof(buf), cdr)) {
 		ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
 		return 0;
@@ -315,10 +324,7 @@ static int csv_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	loaded = 0;
 	return 0;
 }
@@ -353,7 +359,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Comma Separated Values CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c
index 7a35a00..b56b7be 100644
--- a/cdr/cdr_custom.c
+++ b/cdr/cdr_custom.c
@@ -30,22 +30,13 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_custom.c uses the configuration file \ref cdr_custom.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_custom.conf cdr_custom.conf
- * \verbinclude cdr_custom.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 
@@ -67,20 +58,20 @@ AST_THREADSTORAGE(custom_buf);
 
 static const char name[] = "cdr-custom";
 
-struct cdr_custom_config {
+struct cdr_config {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(filename);
 		AST_STRING_FIELD(format);
 		);
 	ast_mutex_t lock;
-	AST_RWLIST_ENTRY(cdr_custom_config) list;
+	AST_RWLIST_ENTRY(cdr_config) list;
 };
 
-static AST_RWLIST_HEAD_STATIC(sinks, cdr_custom_config);
+static AST_RWLIST_HEAD_STATIC(sinks, cdr_config);
 
 static void free_config(void)
 {
-	struct cdr_custom_config *sink;
+	struct cdr_config *sink;
 	while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
 		ast_mutex_destroy(&sink->lock);
 		ast_free(sink);
@@ -103,7 +94,7 @@ static int load_config(void)
 	var = ast_variable_browse(cfg, "mappings");
 	while (var) {
 		if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) {
-			struct cdr_custom_config *sink = ast_calloc_with_stringfields(1, struct cdr_custom_config, 1024);
+			struct cdr_config *sink = ast_calloc_with_stringfields(1, struct cdr_config, 1024);
 
 			if (!sink) {
 				ast_log(LOG_ERROR, "Unable to allocate memory for configuration settings.\n");
@@ -130,7 +121,7 @@ static int custom_log(struct ast_cdr *cdr)
 {
 	struct ast_channel *dummy;
 	struct ast_str *str;
-	struct cdr_custom_config *config;
+	struct cdr_config *config;
 
 	/* Batching saves memory management here.  Otherwise, it's the same as doing an allocation and free each time. */
 	if (!(str = ast_str_thread_get(&custom_buf, 16))) {
@@ -184,9 +175,7 @@ static int custom_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
+	ast_cdr_unregister(name);
 
 	if (AST_RWLIST_WRLOCK(&sinks)) {
 		ast_cdr_register(name, ast_module_info->description, custom_log);
@@ -226,7 +215,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable Comma Separated Values CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c
index 2e30b2e..0d9f46d 100644
--- a/cdr/cdr_manager.c
+++ b/cdr/cdr_manager.c
@@ -25,22 +25,13 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_manager.c uses the configuration file \ref cdr_manager.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_manager.conf cdr_manager.conf
- * \verbinclude cdr_manager.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 
@@ -86,9 +77,8 @@ static int load_config(int reload)
 	if (!cfg) {
 		/* Standard configuration */
 		ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
-		if (enablecdr) {
-			ast_cdr_backend_suspend(name);
-		}
+		if (enablecdr)
+			ast_cdr_unregister(name);
 		enablecdr = 0;
 		return -1;
 	}
@@ -136,11 +126,10 @@ static int load_config(int reload)
 
 	ast_config_destroy(cfg);
 
-	if (!newenablecdr) {
-		ast_cdr_backend_suspend(name);
-	} else if (newenablecdr) {
-		ast_cdr_backend_unsuspend(name);
-	}
+	if (enablecdr && !newenablecdr)
+		ast_cdr_unregister(name);
+	else if (!enablecdr && newenablecdr)
+		ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
 	enablecdr = newenablecdr;
 
 	return 0;
@@ -205,17 +194,14 @@ static int manager_log(struct ast_cdr *cdr)
 	    cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
 	    cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
 	    cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
-	    ast_channel_amaflags2string(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);
+	    ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);
 
 	return 0;
 }
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	if (customfields)
 		ast_free(customfields);
 
@@ -224,12 +210,7 @@ static int unload_module(void)
 
 static int load_module(void)
 {
-	if (ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
 	if (load_config(0)) {
-		ast_cdr_unregister(name);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -242,7 +223,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Manager Interface CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index dbd53a2..207807f 100644
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -28,15 +28,6 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_odbc.c uses the configuration file \ref cdr_odbc.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_odbc.conf cdr_odbc.conf
- * \verbinclude cdr_odbc.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>res_odbc</depend>
 	<support_level>extended</support_level>
@@ -44,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/config.h"
 #include "asterisk/channel.h"
@@ -64,6 +55,7 @@ enum {
 	CONFIG_DISPOSITIONSTRING = 1 << 2,
 	CONFIG_HRTIME =            1 << 3,
 	CONFIG_REGISTERED =        1 << 4,
+	CONFIG_NEWCDRCOLUMNS =     1 << 5,
 };
 
 static struct ast_flags config = { 0 };
@@ -72,29 +64,35 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
 {
 	struct ast_cdr *cdr = data;
 	SQLRETURN ODBC_res;
-	char sqlcmd[2048] = "", timestr[128];
+	char sqlcmd[2048] = "", timestr[128], new_columns[120] = "", new_values[7] = "";
 	struct ast_tm tm;
 	SQLHSTMT stmt;
+	int i = 0;
 
 	ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
 	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
 
+	if (ast_test_flag(&config, CONFIG_NEWCDRCOLUMNS)) {
+		snprintf(new_columns, sizeof(new_columns), "%s", ",peeraccount,linkedid,sequence");
+		snprintf(new_values, sizeof(new_values), "%s", ",?,?,?");
+	}
+
 	if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
 		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
 		"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
-		"lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
-		"VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
+		"lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield%s) "
+		"VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,? %s)", table, new_columns, timestr, new_values);
 	} else {
 		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
 		"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
-		"duration,billsec,disposition,amaflags,accountcode) "
-		"VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
+		"duration,billsec,disposition,amaflags,accountcode%s) "
+		"VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?%s)", table, new_columns, timestr, new_values);
 	}
 
 	ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
 
 	if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
+		ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		return NULL;
 	}
@@ -124,25 +122,30 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
 		SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL);
 	}
 
-	if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING)) {
-		char *disposition;
-		disposition = ast_strdupa(ast_cdr_disp2str(cdr->disposition));
-		SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(disposition) + 1, 0, disposition, 0, NULL);
-	} else {
+	if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING))
+		SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL);
+	else
 		SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL);
-	}
 	SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
 	SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
 
+	i = 14;
 	if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
 		SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
 		SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
+		i = 16;
+	}
+
+	if (ast_test_flag(&config, CONFIG_NEWCDRCOLUMNS)) {
+		SQLBindParameter(stmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->peeraccount), 0, cdr->peeraccount, 0, NULL);
+		SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->linkedid), 0, cdr->linkedid, 0, NULL);
+		SQLBindParameter(stmt, i + 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sequence, 0, NULL);
 	}
 
 	ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
 
 	if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "cdr_odbc: Error in ExecDirect: %d, query is: %s\n", ODBC_res, sqlcmd);
+		ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res);
 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 		return NULL;
 	}
@@ -252,6 +255,9 @@ static int odbc_load_module(int reload)
 			break;
 		}
 
+		ast_verb(3, "cdr_odbc: dsn is %s\n", dsn);
+		ast_verb(3, "cdr_odbc: table is %s\n", table);
+
 		if (!ast_test_flag(&config, CONFIG_REGISTERED)) {
 			res = ast_cdr_register(name, ast_module_info->description, odbc_log);
 			if (res) {
@@ -260,13 +266,18 @@ static int odbc_load_module(int reload)
 				ast_set_flag(&config, CONFIG_REGISTERED);
 			}
 		}
+		if (((tmp = ast_variable_retrieve(cfg, "global", "newcdrcolumns"))) && ast_true(tmp)) {
+			ast_set_flag(&config, CONFIG_NEWCDRCOLUMNS);
+			ast_debug(1, "cdr_odbc: Add new cdr fields\n");
+		} else {
+			ast_clear_flag(&config, CONFIG_NEWCDRCOLUMNS);
+			ast_debug(1, "cdr_odbc: Not add new cdr fields\n");
+		}
 	} while (0);
 
 	if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
-		ast_cdr_backend_suspend(name);
+		ast_cdr_unregister(name);
 		ast_clear_flag(&config, CONFIG_REGISTERED);
-	} else {
-		ast_cdr_backend_unsuspend(name);
 	}
 
 	if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
@@ -282,14 +293,14 @@ static int load_module(void)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
+	ast_cdr_unregister(name);
 
 	if (dsn) {
+		ast_verb(11, "cdr_odbc: free dsn\n");
 		ast_free(dsn);
 	}
 	if (table) {
+		ast_verb(11, "cdr_odbc: free table\n");
 		ast_free(table);
 	}
 
@@ -302,7 +313,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ODBC CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c
index c6ffd4d..845493f 100644
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -25,23 +25,14 @@
  * \brief PostgreSQL CDR logger
  *
  * \author Matthew D. Hardeman <mhardemn at papersoft.com>
- * PostgreSQL http://www.postgresql.org/
+ * \extref PostgreSQL http://www.postgresql.org/
  *
  * See also
  * \arg \ref Config_cdr
- * PostgreSQL http://www.postgresql.org/
+ * \extref PostgreSQL http://www.postgresql.org/
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_pgsql.c uses the configuration file \ref cdr_pgsql.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_pgsql.conf cdr_pgsql.conf
- * \verbinclude cdr_pgsql.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>pgsql</depend>
 	<support_level>extended</support_level>
@@ -49,7 +40,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libpq-fe.h>
 
@@ -63,17 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 
 static const char name[] = "pgsql";
 static const char config[] = "cdr_pgsql.conf";
-
-static char *pghostname;
-static char *pgdbname;
-static char *pgdbuser;
-static char *pgpassword;
-static char *pgappname;
-static char *pgdbport;
-static char *table;
-static char *encoding;
-static char *tz;
-
+static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL, *encoding = NULL, *tz = NULL;
 static int connected = 0;
 static int maxsize = 512, maxsize2 = 512;
 static time_t connect_time = 0;
@@ -143,7 +124,7 @@ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct as
 		return NULL;
 	}
 
-	if (a->argc != 3)
+	if (a->argc != e->args)
 		return CLI_SHOWUSAGE;
 
 	if (connected) {
@@ -184,34 +165,6 @@ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct as
 	return CLI_SUCCESS;
 }
 
-static void pgsql_reconnect(void)
-{
-	struct ast_str *conn_info = ast_str_create(128);
-	if (!conn_info) {
-		ast_log(LOG_ERROR, "Failed to allocate memory for connection string.\n");
-		return;
-	}
-
-	if (conn) {
-		PQfinish(conn);
-		conn = NULL;
-	}
-
-	ast_str_set(&conn_info, 0, "host=%s port=%s dbname=%s user=%s",
-		pghostname, pgdbport, pgdbname, pgdbuser);
-
-	if (!ast_strlen_zero(pgappname)) {
-		ast_str_append(&conn_info, 0, " application_name=%s", pgappname);
-	}
-
-	if (!ast_strlen_zero(pgpassword)) {
-		ast_str_append(&conn_info, 0, " password=%s", pgpassword);
-	}
-
-	conn = PQconnectdb(ast_str_buffer(conn_info));
-	ast_free(conn_info);
-}
-
 static int pgsql_log(struct ast_cdr *cdr)
 {
 	struct ast_tm tm;
@@ -221,8 +174,7 @@ static int pgsql_log(struct ast_cdr *cdr)
 	ast_mutex_lock(&pgsql_lock);
 
 	if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
-		pgsql_reconnect();
-
+		conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
 		if (PQstatus(conn) != CONNECTION_BAD) {
 			connected = 1;
 			connect_time = time(NULL);
@@ -261,9 +213,9 @@ static int pgsql_log(struct ast_cdr *cdr)
 		AST_RWLIST_RDLOCK(&psql_columns);
 		AST_RWLIST_TRAVERSE(&psql_columns, cur, list) {
 			/* For fields not set, simply skip them */
-			ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
+			ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
 			if (strcmp(cur->name, "calldate") == 0 && !value) {
-				ast_cdr_format_var(cdr, "start", &value, buf, sizeof(buf), 0);
+				ast_cdr_getvar(cdr, "start", &value, buf, sizeof(buf), 0, 0);
 			}
 			if (!value) {
 				if (cur->notnull && !cur->hasdefault) {
@@ -325,7 +277,7 @@ static int pgsql_log(struct ast_cdr *cdr)
 			} else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
 				if (cur->type[0] == 'i') {
 					/* Get integer, no need to escape anything */
-					ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
+					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
 					LENGTHEN_BUF2(13);
 					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
 				} else if (strncmp(cur->type, "float", 5) == 0) {
@@ -341,18 +293,18 @@ static int pgsql_log(struct ast_cdr *cdr)
 			} else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
 					/* Integer, no need to escape anything */
-					ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 1);
+					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1);
 					LENGTHEN_BUF2(13);
 					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
 				} else {
 					/* Although this is a char field, there are no special characters in the values for these fields */
-					ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
+					ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
 					LENGTHEN_BUF2(31);
 					ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value);
 				}
 			} else {
 				/* Arbitrary field, could be anything */
-				ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
+				ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
 				if (strncmp(cur->type, "int", 3) == 0) {
 					long long whatever;
 					if (value && sscanf(value, "%30lld", &whatever) == 1) {
@@ -387,8 +339,9 @@ static int pgsql_log(struct ast_cdr *cdr)
 		LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
 		AST_RWLIST_UNLOCK(&psql_columns);
 		ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
 
-		ast_debug(3, "Inserting a CDR record: [%s]\n", ast_str_buffer(sql));
+		ast_debug(2, "inserting a CDR record.\n");
 
 		/* Test to be sure we're still connected... */
 		/* If we're connected, and connection is working, good. */
@@ -474,21 +427,15 @@ static void empty_columns(void)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
 
-	if (conn) {
-		PQfinish(conn);
-		conn = NULL;
-	}
+	PQfinish(conn);
+
 	ast_free(pghostname);
 	ast_free(pgdbname);
 	ast_free(pgdbuser);
 	ast_free(pgpassword);
-	ast_free(pgappname);
 	ast_free(pgdbport);
 	ast_free(table);
 	ast_free(encoding);
@@ -561,18 +508,6 @@ static int config_module(int reload)
 		return -1;
 	}
 
-	if (!(tmp = ast_variable_retrieve(cfg, "global", "appname"))) {
-		tmp = "";
-	}
-
-	ast_free(pgappname);
-	if (!(pgappname = ast_strdup(tmp))) {
-		ast_config_destroy(cfg);
-		ast_mutex_unlock(&pgsql_lock);
-		return -1;
-	}
-
-
 	if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) {
 		ast_log(LOG_WARNING, "PostgreSQL database password not specified.  Assuming blank\n");
 		tmp = "";
@@ -644,14 +579,12 @@ static int config_module(int reload)
 		ast_debug(1, "got user of %s\n", pgdbuser);
 		ast_debug(1, "got dbname of %s\n", pgdbname);
 		ast_debug(1, "got password of %s\n", pgpassword);
-		ast_debug(1, "got application name of %s\n", pgappname);
 		ast_debug(1, "got sql table name of %s\n", table);
 		ast_debug(1, "got encoding of %s\n", encoding);
 		ast_debug(1, "got timezone of %s\n", tz);
 	}
 
-	pgsql_reconnect();
-
+	conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
 	if (PQstatus(conn) != CONNECTION_BAD) {
 		char sqlcmd[768];
 		char *fname, *ftype, *flen, *fnotnull, *fdef;
@@ -670,42 +603,20 @@ static int config_module(int reload)
 		version = PQserverVersion(conn);
 
 		if (version >= 70300) {
-			char *schemaname, *tablename;
+			char *schemaname, *tablename, *tmp_schemaname, *tmp_tablename;
 			if (strchr(table, '.')) {
-				schemaname = ast_strdupa(table);
-				tablename = strchr(schemaname, '.');
-				*tablename++ = '\0';
+				tmp_schemaname = ast_strdupa(table);
+				tmp_tablename = strchr(tmp_schemaname, '.');
+				*tmp_tablename++ = '\0';
 			} else {
-				schemaname = "";
-				tablename = table;
+				tmp_schemaname = "";
+				tmp_tablename = table;
 			}
+			tablename = ast_alloca(strlen(tmp_tablename) * 2 + 1);
+			PQescapeStringConn(conn, tablename, tmp_tablename, strlen(tmp_tablename), NULL);
 
-			/* Escape special characters in schemaname */
-			if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
-				char *tmp = schemaname, *ptr;
-
-				ptr = schemaname = ast_alloca(strlen(tmp) * 2 + 1);
-				for (; *tmp; tmp++) {
-					if (strchr("\\'", *tmp)) {
-						*ptr++ = *tmp;
-					}
-					*ptr++ = *tmp;
-				}
-				*ptr = '\0';
-			}
-			/* Escape special characters in tablename */
-			if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
-				char *tmp = tablename, *ptr;
-
-				ptr = tablename = ast_alloca(strlen(tmp) * 2 + 1);
-				for (; *tmp; tmp++) {
-					if (strchr("\\'", *tmp)) {
-						*ptr++ = *tmp;
-					}
-					*ptr++ = *tmp;
-				}
-				*ptr = '\0';
-			}
+			schemaname = ast_alloca(strlen(tmp_schemaname) * 2 + 1);
+			PQescapeStringConn(conn, schemaname, tmp_schemaname, strlen(tmp_schemaname), NULL);
 
 			snprintf(sqlcmd, sizeof(sqlcmd), "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND c.relname = '%s' AND n.nspname = %s%s%s) INNER JOIN pg_catalog.pg_attribute a ON (NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a [...]
 				tablename,
@@ -746,7 +657,7 @@ static int config_module(int reload)
 				/* For varchar columns, the maximum length is encoded in a different field */
 				flen = PQgetvalue(result, i, 5);
 			}
-
+			ast_verb(4, "Found column '%s' of type '%s'\n", fname, ftype);
 			cur = ast_calloc(1, sizeof(*cur) + strlen(fname) + strlen(ftype) + 2);
 			if (cur) {
 				sscanf(flen, "%30d", &cur->len);
@@ -775,8 +686,6 @@ static int config_module(int reload)
 		ast_log(LOG_ERROR, "Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
 		ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
 		connected = 0;
-		PQfinish(conn);
-		conn = NULL;
 	}
 
 	ast_config_destroy(cfg);
@@ -801,7 +710,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PostgreSQL CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c
index 1cb5541..fc28860 100644
--- a/cdr/cdr_radius.c
+++ b/cdr/cdr_radius.c
@@ -21,17 +21,12 @@
  * \brief RADIUS CDR Support
  *
  * \author Philippe Sultan
- * The Radius Client Library
- * 	http://developer.berlios.de/projects/radiusclient-ng/
+ * \extref The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
  *
  * \arg See also \ref AstCDR
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_radius.c uses the configuration file \ref cdr.conf
- * \addtogroup configuration_file Configuration Files
- */
-
 /*** MODULEINFO
 	<depend>radius</depend>
 	<support_level>extended</support_level>
@@ -39,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef FREERADIUS_CLIENT
 #include <freeradius-client.h>
@@ -178,12 +173,12 @@ static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
 		return -1;
 
 	/* Disposition */
-	tmp = ast_strdupa(ast_cdr_disp2str(cdr->disposition));
+	tmp = ast_cdr_disp2str(cdr->disposition);
 	if (!rc_avpair_add(rh, tosend, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
 		return -1;
 
 	/* AMA Flags */
-	tmp = ast_strdupa(ast_channel_amaflags2string(cdr->amaflags));
+	tmp = ast_cdr_flags2str(cdr->amaflags);
 	if (!rc_avpair_add(rh, tosend, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
 		return -1;
 
@@ -200,8 +195,7 @@ static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
 	}
 
 	/* Setting Acct-Session-Id & User-Name attributes for proper generation
-	 * of Acct-Unique-Session-Id on server side 
-	 */
+	   of Acct-Unique-Session-Id on server side */
 	/* Channel */
 	if (!rc_avpair_add(rh, tosend, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
 		return -1;
@@ -238,10 +232,7 @@ return_cleanup:
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	if (rh) {
 		rc_destroy(rh);
 		rh = NULL;
@@ -301,7 +292,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CDR_DRIVER,
diff --git a/cdr/cdr_sqlite.c b/cdr/cdr_sqlite.c
index 1b28b6c..47d1a51 100644
--- a/cdr/cdr_sqlite.c
+++ b/cdr/cdr_sqlite.c
@@ -22,7 +22,7 @@
  * \brief Store CDR records in a SQLite database.
  *
  * \author Holger Schurig <hs4233 at mail.mn-solutions.de>
- * SQLite http://www.sqlite.org/
+ * \extref SQLite http://www.sqlite.org/
  *
  * See also
  * \arg \ref Config_cdr
@@ -43,7 +43,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sqlite.h>
 
@@ -191,10 +191,7 @@ static int sqlite_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
+	ast_cdr_unregister(name);
 	if (db) {
 		sqlite_close(db);
 	}
@@ -246,7 +243,6 @@ err:
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite CDR Backend",
-	.support_level = AST_MODULE_SUPPORT_DEPRECATED,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CDR_DRIVER,
diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c
index 152afc2..ba318d4 100644
--- a/cdr/cdr_sqlite3_custom.c
+++ b/cdr/cdr_sqlite3_custom.c
@@ -39,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sqlite3.h>
 
@@ -197,7 +197,7 @@ static int load_config(int reload)
 		return -1;
 	}
 
-	ast_verb(4, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
+	ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
 
 	ast_config_destroy(cfg);
 
@@ -279,9 +279,7 @@ static int write_cdr(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
+	ast_cdr_unregister(name);
 
 	free_config(0);
 
@@ -347,7 +345,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite3 Custom CDR Module",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cdr/cdr_syslog.c b/cdr/cdr_syslog.c
index 6997d17..e593812 100644
--- a/cdr/cdr_syslog.c
+++ b/cdr/cdr_syslog.c
@@ -27,15 +27,6 @@
  * \ingroup cdr_drivers
  */
 
-/*! \li \ref cdr_syslog.c uses the configuration file \ref cdr_syslog.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr_syslog.conf cdr_syslog.conf
- * \verbinclude cdr_syslog.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>syslog</depend>
 	<support_level>core</support_level>
@@ -43,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
@@ -60,7 +51,7 @@ AST_THREADSTORAGE(syslog_buf);
 
 static const char name[] = "cdr-syslog";
 
-struct cdr_syslog_config {
+struct cdr_config {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(ident);
 		AST_STRING_FIELD(format);
@@ -68,14 +59,14 @@ struct cdr_syslog_config {
 	int facility;
 	int priority;
 	ast_mutex_t lock;
-	AST_LIST_ENTRY(cdr_syslog_config) list;
+	AST_LIST_ENTRY(cdr_config) list;
 };
 
-static AST_RWLIST_HEAD_STATIC(sinks, cdr_syslog_config);
+static AST_RWLIST_HEAD_STATIC(sinks, cdr_config);
 
 static void free_config(void)
 {
-	struct cdr_syslog_config *sink;
+	struct cdr_config *sink;
 	while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
 		ast_mutex_destroy(&sink->lock);
 		ast_free(sink);
@@ -86,7 +77,7 @@ static int syslog_log(struct ast_cdr *cdr)
 {
 	struct ast_channel *dummy;
 	struct ast_str *str;
-	struct cdr_syslog_config *sink;
+	struct cdr_config *sink;
 
 	/* Batching saves memory management here.  Otherwise, it's the same as doing an
 	   allocation and free each time. */
@@ -174,7 +165,7 @@ static int load_config(int reload)
 	}
 
 	while ((catg = ast_category_browse(cfg, catg))) {
-		struct cdr_syslog_config *sink;
+		struct cdr_config *sink;
 
 		if (!strcasecmp(catg, "general")) {
 			continue;
@@ -186,7 +177,7 @@ static int load_config(int reload)
 			continue;
 		}
 
-		sink = ast_calloc_with_stringfields(1, struct cdr_syslog_config, 1024);
+		sink = ast_calloc_with_stringfields(1, struct cdr_config, 1024);
 
 		if (!sink) {
 			ast_log(AST_LOG_ERROR,
@@ -235,9 +226,7 @@ static int load_config(int reload)
 
 static int unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
+	ast_cdr_unregister(name);
 
 	if (AST_RWLIST_WRLOCK(&sinks)) {
 		ast_cdr_register(name, ast_module_info->description, syslog_log);
@@ -286,7 +275,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable syslog CDR Backend",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c
index b71a15e..dd75dbb 100644
--- a/cdr/cdr_tds.c
+++ b/cdr/cdr_tds.c
@@ -64,7 +64,7 @@ CREATE TABLE [dbo].[cdr] (
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/config.h"
 #include "asterisk/channel.h"
@@ -176,7 +176,7 @@ retry:
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, hrduration,
-					 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
+					 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid,
 					 userfield
 			);
 		} else {
@@ -196,7 +196,7 @@ retry:
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
-					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
+					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid,
 					 userfield
 			);
 		}
@@ -226,7 +226,7 @@ retry:
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, hrduration,
-					 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
+					 hrbillsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid
 			);
 		} else {
 			erc = dbfcmd(settings->dbproc,
@@ -245,7 +245,7 @@ retry:
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
-					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
+					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid
 			);
 		}
 	}
@@ -443,10 +443,6 @@ failed:
 
 static int tds_unload_module(void)
 {
-	if (ast_cdr_unregister(name)) {
-		return -1;
-	}
-
 	if (settings) {
 		ast_mutex_lock(&tds_lock);
 		mssql_disconnect();
@@ -456,6 +452,8 @@ static int tds_unload_module(void)
 		ast_free(settings);
 	}
 
+	ast_cdr_unregister(name);
+
 	dbexit();
 
 	return 0;
@@ -632,7 +630,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "FreeTDS CDR Backend",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/cel/Makefile b/cel/Makefile
index 8e0a022..5ac6d89 100644
--- a/cel/Makefile
+++ b/cel/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for CEL backends
 #
diff --git a/cel/cel_custom.c b/cel/cel_custom.c
index 9fc2e7f..d6055cd 100644
--- a/cel/cel_custom.c
+++ b/cel/cel_custom.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"
 #include "asterisk/channel.h"
@@ -64,7 +64,7 @@ struct cel_config {
 	AST_RWLIST_ENTRY(cel_config) list;
 };
 
-#define CUSTOM_BACKEND_NAME "CEL Custom CSV Logging"
+static struct ast_event_sub *event_sub = NULL;
 
 static AST_RWLIST_HEAD_STATIC(sinks, cel_config);
 
@@ -124,7 +124,7 @@ static int load_config(void)
 	return res;
 }
 
-static void custom_log(struct ast_event *event)
+static void custom_log(const struct ast_event *event, void *userdata)
 {
 	struct ast_channel *dummy;
 	struct ast_str *str;
@@ -175,15 +175,19 @@ static void custom_log(struct ast_event *event)
 
 static int unload_module(void)
 {
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 
 	if (AST_RWLIST_WRLOCK(&sinks)) {
+		event_sub = ast_event_subscribe(AST_EVENT_CEL, custom_log, "CEL Custom CSV Logging",
+			NULL, AST_EVENT_IE_END);
 		ast_log(LOG_ERROR, "Unable to lock sink list.  Unload failed.\n");
 		return -1;
 	}
 
 	free_config();
 	AST_RWLIST_UNLOCK(&sinks);
-	ast_cel_backend_unregister(CUSTOM_BACKEND_NAME);
 	return 0;
 }
 
@@ -197,9 +201,8 @@ static enum ast_module_load_result load_module(void)
 	load_config();
 	AST_RWLIST_UNLOCK(&sinks);
 
-	if (ast_cel_backend_register(CUSTOM_BACKEND_NAME, custom_log)) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, custom_log, "CEL Custom CSV Logging",
+		NULL, AST_EVENT_IE_END);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -217,7 +220,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable Comma Separated Values CEL Backend",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cel/cel_manager.c b/cel/cel_manager.c
index b3b5f0f..ba28971 100644
--- a/cel/cel_manager.c
+++ b/cel/cel_manager.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/cel.h"
@@ -57,12 +57,12 @@ static int enablecel;
 /*! \brief show_user_def is off by default */
 #define CEL_SHOW_USERDEF_DEFAULT	0
 
-#define MANAGER_BACKEND_NAME "Manager Event Logging"
-
 /*! TRUE if we should set the EventName header to USER_DEFINED on user events. */
 static unsigned char cel_show_user_def;
 
-static void manager_log(struct ast_event *event)
+static struct ast_event_sub *event_sub;
+
+static void manager_log(const struct ast_event *event, void *userdata)
 {
 	struct ast_tm timeresult;
 	char start_time[80] = "";
@@ -129,7 +129,7 @@ static void manager_log(struct ast_event *event)
 		record.application_name,
 		record.application_data,
 		start_time,
-		ast_channel_amaflags2string(record.amaflag),
+		ast_cel_get_ama_flag_name(record.amaflag),
 		record.unique_id,
 		record.linked_id,
 		record.user_field,
@@ -185,9 +185,12 @@ static int load_config(int reload)
 
 	cel_show_user_def = new_cel_show_user_def;
 	if (enablecel && !newenablecel) {
-		ast_cel_backend_unregister(MANAGER_BACKEND_NAME);
+		if (event_sub) {
+			event_sub = ast_event_unsubscribe(event_sub);
+		}
 	} else if (!enablecel && newenablecel) {
-		if (ast_cel_backend_register(MANAGER_BACKEND_NAME, manager_log)) {
+		event_sub = ast_event_subscribe(AST_EVENT_CEL, manager_log, "Manager Event Logging", NULL, AST_EVENT_IE_END);
+		if (!event_sub) {
 			ast_log(LOG_ERROR, "Unable to register Asterisk Call Manager CEL handling\n");
 		}
 	}
@@ -198,7 +201,9 @@ static int load_config(int reload)
 
 static int unload_module(void)
 {
-	ast_cel_backend_unregister(MANAGER_BACKEND_NAME);
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 	return 0;
 }
 
@@ -217,7 +222,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Manager Interface CEL Backend",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c
index 62e198e..f416401 100644
--- a/cel/cel_odbc.c
+++ b/cel/cel_odbc.c
@@ -22,7 +22,7 @@
  *
  * \brief ODBC CEL backend
  *
- * \author Tilghman Lesher \verbatim <tlesher AT digium DOT com> \endverbatim
+ * \author Tilghman Lesher <tlesher AT digium DOT com>
  * \ingroup cel_drivers
  */
 
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427954 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <time.h>
@@ -51,8 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427954 $")
 #include "asterisk/module.h"
 
 #define	CONFIG	"cel_odbc.conf"
-
-#define ODBC_BACKEND_NAME "ODBC CEL backend"
+static struct ast_event_sub *event_sub = NULL;
 
 /*! \brief show_user_def is off by default */
 #define CEL_SHOW_USERDEF_DEFAULT	0
@@ -368,7 +367,7 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
 				}																\
 			} while (0)
 
-static void odbc_log(struct ast_event *event)
+static void odbc_log(const struct ast_event *event, void *userdata)
 {
 	struct tables *tableptr;
 	struct columns *entry;
@@ -762,7 +761,8 @@ static void odbc_log(struct ast_event *event)
 		ast_str_append(&sql2, 0, ")");
 		ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
 
-		ast_debug(3, "Executing SQL statement: [%s]\n", ast_str_buffer(sql));
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
+
 		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
 		if (stmt) {
 			SQLRowCount(stmt, &rows);
@@ -790,12 +790,18 @@ early_release:
 
 static int unload_module(void)
 {
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+		event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
+		if (!event_sub) {
+			ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
+		}
 		ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
 		return -1;
 	}
 
-	ast_cel_backend_unregister(ODBC_BACKEND_NAME);
 	free_config();
 	AST_RWLIST_UNLOCK(&odbc_tables);
 	AST_RWLIST_HEAD_DESTROY(&odbc_tables);
@@ -809,13 +815,13 @@ static int load_module(void)
 
 	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
 		ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
-		return AST_MODULE_LOAD_FAILURE;
+		return 0;
 	}
 	load_config();
 	AST_RWLIST_UNLOCK(&odbc_tables);
-	if (ast_cel_backend_register(ODBC_BACKEND_NAME, odbc_log)) {
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
+	if (!event_sub) {
 		ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
-		return AST_MODULE_LOAD_FAILURE;
 	}
 	return AST_MODULE_LOAD_SUCCESS;
 }
@@ -824,7 +830,7 @@ static int reload(void)
 {
 	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
 		ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
-		return AST_MODULE_LOAD_FAILURE;
+		return -1;
 	}
 
 	free_config();
@@ -833,8 +839,7 @@ static int reload(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, ODBC_BACKEND_NAME,
-	.support_level = AST_MODULE_SUPPORT_CORE,
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ODBC CEL backend",
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c
index c61024e..6cd93e5 100644
--- a/cel/cel_pgsql.c
+++ b/cel/cel_pgsql.c
@@ -4,8 +4,8 @@
  * Copyright (C) 2008
  *
  * Steve Murphy - adapted to CEL, from:
- * Matthew D. Hardeman <mhardemn at papersoft.com>
- * Adapted from the MySQL CDR logger originally by James Sharp
+ * Matthew D. Hardeman <mhardemn at papersoft.com> 
+ * Adapted from the MySQL CDR logger originally by James Sharp 
  *
  * Modified April, 2007; Dec, 2008
  * Steve Murphy <murf at digium.com>
@@ -26,14 +26,14 @@
 
 /*! \file
  *
- * \brief PostgreSQL CEL logger
- *
+ * \brief PostgreSQL CEL logger 
+ * 
  * \author Steve Murphy <murf at digium.com>
- * PostgreSQL http://www.postgresql.org/
+ * \extref PostgreSQL http://www.postgresql.org/
  *
  * See also
  * \arg \ref Config_cel
- * PostgreSQL http://www.postgresql.org/
+ * \extref PostgreSQL http://www.postgresql.org/
  * \ingroup cel_drivers
  */
 
@@ -44,7 +44,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libpq-fe.h>
 
@@ -58,18 +58,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 
 #define DATE_FORMAT "%Y-%m-%d %T.%6q"
 
-#define PGSQL_BACKEND_NAME "CEL PGSQL backend"
-
 static char *config = "cel_pgsql.conf";
-
-static char *pghostname;
-static char *pgdbname;
-static char *pgdbuser;
-static char *pgpassword;
-static char *pgappname;
-static char *pgdbport;
-static char *table;
-
+static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL;
 static int connected = 0;
 static int maxsize = 512, maxsize2 = 512;
 
@@ -83,6 +73,7 @@ AST_MUTEX_DEFINE_STATIC(pgsql_lock);
 
 static PGconn	*conn = NULL;
 static PGresult	*result = NULL;
+static struct ast_event_sub *event_sub = NULL;
 
 struct columns {
 	char *name;
@@ -100,7 +91,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
 		/* Lengthen buffer, if necessary */ \
 		if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \
 			if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) { \
-				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n"); \
+				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CEL '%s:%s' failed.\n", pghostname, table); \
 				ast_free(sql); \
 				ast_free(sql2); \
 				AST_RWLIST_UNLOCK(&psql_columns); \
@@ -113,7 +104,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
 	do { \
 		if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \
 			if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
-				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n"); \
+				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CEL '%s:%s' failed.\n", pghostname, table); \
 				ast_free(sql); \
 				ast_free(sql2); \
 				AST_RWLIST_UNLOCK(&psql_columns); \
@@ -122,36 +113,7 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
 		} \
 	} while (0)
 
-static void pgsql_reconnect(void)
-{
-	struct ast_str *conn_info = ast_str_create(128);
-	if (!conn_info) {
-		ast_log(LOG_ERROR, "Failed to allocate memory for connection string.\n");
-		return;
-	}
-
-	if (conn) {
-		PQfinish(conn);
-		conn = NULL;
-	}
-
-	ast_str_set(&conn_info, 0, "host=%s port=%s dbname=%s user=%s",
-		pghostname, pgdbport, pgdbname, pgdbuser);
-
-	if (!ast_strlen_zero(pgappname)) {
-		ast_str_append(&conn_info, 0, " application_name=%s", pgappname);
-	}
-
-	if (!ast_strlen_zero(pgpassword)) {
-		ast_str_append(&conn_info, 0, " password=%s", pgpassword);
-	}
-
-	conn = PQconnectdb(ast_str_buffer(conn_info));
-	ast_free(conn_info);
-}
-
-
-static void pgsql_log(struct ast_event *event)
+static void pgsql_log(const struct ast_event *event, void *userdata)
 {
 	struct ast_tm tm;
 	char timestr[128];
@@ -170,7 +132,7 @@ static void pgsql_log(struct ast_event *event)
 	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
 
 	if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) {
-		pgsql_reconnect();
+		conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
 		if (PQstatus(conn) != CONNECTION_BAD) {
 			connected = 1;
 		} else {
@@ -325,8 +287,9 @@ static void pgsql_log(struct ast_event *event)
 		AST_RWLIST_UNLOCK(&psql_columns);
 		LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
 		ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
 
-		ast_debug(3, "Inserting a CEL record: [%s].\n", ast_str_buffer(sql));
+		ast_debug(2, "inserting a CEL record.\n");
 		/* Test to be sure we're still connected... */
 		/* If we're connected, and connection is working, good. */
 		/* Otherwise, attempt reconnect.  If it fails... sorry... */
@@ -383,7 +346,10 @@ static int my_unload_module(void)
 {
 	struct columns *current;
 
-	ast_cel_backend_unregister(PGSQL_BACKEND_NAME);
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
+
 	AST_RWLIST_WRLOCK(&psql_columns);
 	if (conn) {
 		PQfinish(conn);
@@ -405,10 +371,6 @@ static int my_unload_module(void)
 		ast_free(pgpassword);
 		pgpassword = NULL;
 	}
-	if (pgappname) {
-		ast_free(pgappname);
-		pgappname = NULL;
-	}
 	if (pgdbport) {
 		ast_free(pgdbport);
 		pgdbport = NULL;
@@ -481,17 +443,6 @@ static int process_my_load_module(struct ast_config *cfg)
 		ast_log(LOG_WARNING,"PostgreSQL Ran out of memory copying password info\n");
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	if (!(tmp = ast_variable_retrieve(cfg, "global", "appname"))) {
-		tmp = "";
-	}
-	if (pgappname) {
-		ast_free(pgappname);
-	}
-	if (!(pgappname = ast_strdup(tmp))) {
-		ast_log(LOG_WARNING,"PostgreSQL Ran out of memory copying appname info\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
 	if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) {
 		ast_log(LOG_WARNING,"PostgreSQL database port not specified.  Using default 5432.\n");
 		tmp = "5432";
@@ -530,7 +481,7 @@ static int process_my_load_module(struct ast_config *cfg)
 			cel_show_user_def ? "Yes" : "No");
 	}
 
-	pgsql_reconnect();
+	conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
 	if (PQstatus(conn) != CONNECTION_BAD) {
 		char sqlcmd[512];
 		char *fname, *ftype, *flen, *fnotnull, *fdef;
@@ -592,8 +543,6 @@ static int process_my_load_module(struct ast_config *cfg)
 		ast_log(LOG_ERROR, "cel_pgsql: Unable to connect to database server %s.  CALLS WILL NOT BE LOGGED!!\n", pghostname);
 		ast_log(LOG_ERROR, "cel_pgsql: Reason: %s\n", pgerror);
 		connected = 0;
-		PQfinish(conn);
-		conn = NULL;
 	}
 	return AST_MODULE_LOAD_SUCCESS;
 }
@@ -617,7 +566,9 @@ static int my_load_module(int reload)
 	process_my_load_module(cfg);
 	ast_config_destroy(cfg);
 
-	if (ast_cel_backend_register(PGSQL_BACKEND_NAME, pgsql_log)) {
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, pgsql_log, "CEL PGSQL backend", NULL, AST_EVENT_IE_END);
+
+	if (!event_sub) {
 		ast_log(LOG_WARNING, "Unable to subscribe to CEL events for pgsql\n");
 		return AST_MODULE_LOAD_DECLINE;
 	}
@@ -636,7 +587,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PostgreSQL CEL Backend",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cel/cel_radius.c b/cel/cel_radius.c
index b1dc167..f69b973 100644
--- a/cel/cel_radius.c
+++ b/cel/cel_radius.c
@@ -20,7 +20,7 @@
  *
  * \brief RADIUS CEL Support
  * \author Philippe Sultan
- * The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
+ * \extref The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
  *
  * \arg See also \ref AstCEL
  * \ingroup cel_drivers
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Rev: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
 
 #ifdef FREERADIUS_CLIENT
 #include <freeradius-client.h>
@@ -92,8 +92,7 @@ static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
 
 static rc_handle *rh = NULL;
-
-#define RADIUS_BACKEND_NAME "CEL Radius Logging"
+static struct ast_event_sub *event_sub = NULL;
 
 #define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, &y, strlen(y), VENDOR_CODE))
 
@@ -159,7 +158,7 @@ static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *r
 		return -1;
 	}
 	/* AMA Flags */
-	amaflags = ast_strdupa(ast_channel_amaflags2string(record->amaflag));
+	amaflags = ast_strdupa(ast_cel_get_ama_flag_name(record->amaflag));
 	if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) {
 		return -1;
 	}
@@ -183,7 +182,7 @@ static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *r
 	return 0;
 }
 
-static void radius_log(struct ast_event *event)
+static void radius_log(const struct ast_event *event, void *userdata)
 {
 	int result = ERROR_RC;
 	VALUE_PAIR *send = NULL;
@@ -213,7 +212,9 @@ return_cleanup:
 
 static int unload_module(void)
 {
-	ast_cel_backend_unregister(RADIUS_BACKEND_NAME);
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 	if (rh) {
 		rc_destroy(rh);
 		rh = NULL;
@@ -263,7 +264,8 @@ static int load_module(void)
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	if (ast_cel_backend_register(RADIUS_BACKEND_NAME, radius_log)) {
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, radius_log, "CEL Radius Logging", NULL, AST_EVENT_IE_END);
+	if (!event_sub) {
 		rc_destroy(rh);
 		rh = NULL;
 		return AST_MODULE_LOAD_DECLINE;
@@ -273,7 +275,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CEL Backend",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CDR_DRIVER,
diff --git a/cel/cel_sqlite3_custom.c b/cel/cel_sqlite3_custom.c
index b27a94f..2da6983 100644
--- a/cel/cel_sqlite3_custom.c
+++ b/cel/cel_sqlite3_custom.c
@@ -41,7 +41,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sqlite3.h>
 
@@ -57,20 +57,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/options.h"
 #include "asterisk/stringfields.h"
 
-#define SQLITE_BACKEND_NAME "CEL sqlite3 custom backend"
-
 AST_MUTEX_DEFINE_STATIC(lock);
 
 static const char config_file[] = "cel_sqlite3_custom.conf";
 
-static const char name[] = "cel_sqlite3_custom";
 static sqlite3 *db = NULL;
 
 static char table[80];
-/*!
- * \bug Handling of this var is crash prone on reloads
- */
+/*! XXX \bug Handling of this var is crash prone on reloads */
 static char *columns;
+static struct ast_event_sub *event_sub = NULL;
 
 struct values {
 	char *expression;
@@ -230,7 +226,7 @@ static void free_config(void)
 	}
 }
 
-static void write_cel(struct ast_event *event)
+static void write_cel(const struct ast_event *event, void *userdata)
 {
 	char *error = NULL;
 	char *sql = NULL;
@@ -283,7 +279,9 @@ static void write_cel(struct ast_event *event)
 
 static int unload_module(void)
 {
-	ast_cel_backend_unregister(SQLITE_BACKEND_NAME);
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 
 	free_config();
 
@@ -327,7 +325,8 @@ static int load_module(void)
 		}
 	}
 
-	if (ast_cel_backend_register(SQLITE_BACKEND_NAME, write_cel)) {
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, write_cel, "CEL sqlite3 custom backend", NULL, AST_EVENT_IE_END);
+	if (!event_sub) {
 		ast_log(LOG_ERROR, "Unable to register custom SQLite3 CEL handling\n");
 		free_config();
 		return AST_MODULE_LOAD_DECLINE;
@@ -348,7 +347,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite3 Custom CEL Module",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/cel/cel_tds.c b/cel/cel_tds.c
index 786a85e..df2b573 100644
--- a/cel/cel_tds.c
+++ b/cel/cel_tds.c
@@ -61,7 +61,7 @@ CREATE TABLE [dbo].[cel] (
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 #include <math.h>
@@ -81,10 +81,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 
 #define DATE_FORMAT "%Y/%m/%d %T"
 
-#define TDS_BACKEND_NAME "CEL TDS logging backend"
-
 static char *config = "cel_tds.conf";
 
+static struct ast_event_sub *event_sub = NULL;
+
 struct cel_tds_config {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(connection);
@@ -112,7 +112,7 @@ static int execute_and_consume(DBPROCESS *dbproc, const char *fmt, ...)
 static int mssql_connect(void);
 static int mssql_disconnect(void);
 
-static void tds_log(struct ast_event *event)
+static void tds_log(const struct ast_event *event, void *userdata)
 {
 	char start[80];
 	char *accountcode_ai, *clidnum_ai, *exten_ai, *context_ai, *clid_ai, *channel_ai, *app_ai, *appdata_ai, *uniqueid_ai, *linkedid_ai, *cidani_ai, *cidrdnis_ai, *ciddnid_ai, *peer_ai, *userfield_ai;
@@ -206,7 +206,7 @@ retry:
 		ciddnid_ai, exten_ai, context_ai, channel_ai, app_ai, appdata_ai, start,
 		(record.event_type == AST_CEL_USER_DEFINED)
 			? record.user_defined_name : record.event_name,
-					ast_channel_amaflags2string(record.amaflag), uniqueid_ai, linkedid_ai,
+		ast_cel_get_ama_flag_name(record.amaflag), uniqueid_ai, linkedid_ai,
 		userfield_ai, peer_ai);
 
 	if (erc == FAIL) {
@@ -397,7 +397,9 @@ failed:
 
 static int tds_unload_module(void)
 {
-	ast_cel_backend_unregister(TDS_BACKEND_NAME);
+	if (event_sub) {
+		event_sub = ast_event_unsubscribe(event_sub);
+	}
 
 	if (settings) {
 		ast_mutex_lock(&tds_lock);
@@ -559,7 +561,8 @@ static int load_module(void)
 	}
 
 	/* Register MSSQL CEL handler */
-	if (ast_cel_backend_register(TDS_BACKEND_NAME, tds_log)) {
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, tds_log, "CEL TDS logging backend", NULL, AST_EVENT_IE_END);
+	if (!event_sub) {
 		ast_log(LOG_ERROR, "Unable to register MSSQL CEL handling\n");
 		ast_string_field_free_memory(settings);
 		ast_free(settings);
@@ -577,7 +580,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "FreeTDS CEL Backend",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/channels/Makefile b/channels/Makefile
index b24478a..eeed686 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -1,6 +1,6 @@
 #
-# Asterisk -- An open source telephony toolkit.
-#
+# Asterisk -- A telephony toolkit for Linux.
+# 
 # Makefile for channel drivers
 #
 # Copyright (C) 1999-2006, Digium, Inc.
@@ -15,39 +15,80 @@ MODULE_PREFIX=chan
 MENUSELECT_CATEGORY=CHANNELS
 MENUSELECT_DESCRIPTION=Channel Drivers
 
+ifeq ($(OSARCH),OpenBSD)
+  PTLIB=-lpt
+  H323LIB=-lh323
+endif
+
+ifeq ($(OSARCH),linux-gnu)
+  PTLIB=-lpt_linux_x86_r
+  H323LIB=-lh323_linux_x86_r
+  CHANH323LIB=-ldl
+endif
+
+ifeq ($(OSARCH),FreeBSD)
+  PTLIB=-lpt_FreeBSD_x86_r
+  H323LIB=-lh323_FreeBSD_x86_r
+  CHANH323LIB=-pthread
+endif
+
+ifeq ($(OSARCH),NetBSD)
+  PTLIB=-lpt_NetBSD_x86_r
+  H323LIB=-lh323_NetBSD_x86_r
+endif
+
+ifeq ($(wildcard h323/libchanh323.a),)
+  MODULE_EXCLUDE += chan_h323
+endif
+
+ifndef OPENH323DIR
+  OPENH323DIR=$(HOME)/openh323
+endif
+
+ifndef PWLIBDIR
+  PWLIBDIR=$(HOME)/pwlib
+endif
+
 all: _all
 
 include $(ASTTOPDIR)/Makefile.moddir_rules
 
 ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
-  LIBS+= -lres_monitor.so -lres_features.so
+  LIBS+= -lres_monitor.so
+endif
+
+ifneq ($(wildcard h323/Makefile.ast),)
+include h323/Makefile.ast
 endif
 
 clean::
 	$(MAKE) -C misdn clean
-	rm -f dahdi/*.o dahdi/*.i
-	rm -f sip/*.o sip/*.i
-	rm -f iax2/*.o iax2/*.i
-	rm -f pjsip/*.o pjsip/*.i
+	rm -f sip/*.o sip/*.i sip/*.gcda sip/*.gcno
+	rm -f h323/libchanh323.a h323/Makefile.ast h323/*.o h323/*.dep h323/*.gcda h323/*.gcno
 
-$(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): $(subst .c,.o,$(wildcard iax2/*.c))
-$(subst .c,.o,$(wildcard iax2/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_iax2)
+dist-clean::
+	rm -f h323/Makefile
 
+$(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): iax2-parser.o iax2-provision.o
+iax2-parser.o iax2-provision.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_iax2)
 $(if $(filter chan_sip,$(EMBEDDED_MODS)),modules.link,chan_sip.so): $(subst .c,.o,$(wildcard sip/*.c))
 $(subst .c,.o,$(wildcard sip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_sip)
-
-$(if $(filter chan_pjsip,$(EMBEDDED_MODS)),modules.link,chan_pjsip.so): $(subst .c,.o,$(wildcard pjsip/*.c))
-$(subst .c,.o,$(wildcard pjsip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_pjsip)
-
-# Additional objects to combine with chan_dahdi.so
-CHAN_DAHDI_OBJS= \
-	$(subst .c,.o,$(wildcard dahdi/*.c))	\
-	sig_analog.o	\
-	sig_pri.o	\
-	sig_ss7.o	\
-
-$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): $(CHAN_DAHDI_OBJS)
-$(CHAN_DAHDI_OBJS): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_dahdi)
+$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): sig_analog.o sig_pri.o sig_ss7.o
+sig_analog.o sig_pri.o sig_ss7.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_dahdi)
+
+ifneq ($(filter chan_h323,$(EMBEDDED_MODS)),)
+modules.link: h323/libchanh323.a
+else
+ifeq ($(OSARCH),linux-gnu)
+chan_h323.so: chan_h323.o h323/libchanh323.a
+	$(ECHO_PREFIX) echo "   [LD] $^ -> $@"
+	$(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(SOLINK) -o $@ $< h323/libchanh323.a $(H323LDLIBS)
+else
+chan_h323.so: chan_h323.o h323/libchanh323.a
+	$(ECHO_PREFIX) echo "   [LD] $^ -> $@"
+	$(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
+endif
+endif
 
 chan_misdn.o: _ASTCFLAGS+=-Imisdn
 
@@ -66,3 +107,8 @@ chan_usbradio.o: ./xpmr/xpmr.c ./xpmr/xpmr.h ./xpmr/xpmr_coef.h
 chan_usbradio.so: LIBS+=-lusb -lasound
 chan_usbradio.so: _ASTCFLAGS+=-DNDEBUG
 
+h323/Makefile.ast:
+	$(CMD_PREFIX) $(MAKE) -C h323 Makefile.ast
+
+h323/libchanh323.a: h323/Makefile.ast
+	$(CMD_PREFIX) $(MAKE) -C h323 libchanh323.a
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
new file mode 100644
index 0000000..b9047fe
--- /dev/null
+++ b/channels/chan_agent.c
@@ -0,0 +1,2593 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2012, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+
+/*! \file
+ * 
+ * \brief Implementation of Agents (proxy channel)
+ *
+ * \author Mark Spencer <markster at digium.com>
+ *
+ * This file is the implementation of Agents modules.
+ * It is a dynamic module that is loaded by Asterisk. 
+ * \par See also
+ * \arg \ref Config_agent
+ *
+ * \ingroup channel_drivers
+ */
+/*** MODULEINFO
+        <depend>chan_local</depend>
+        <depend>res_monitor</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/signal.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/manager.h"
+#include "asterisk/features.h"
+#include "asterisk/utils.h"
+#include "asterisk/causes.h"
+#include "asterisk/astdb.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/monitor.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/event.h"
+#include "asterisk/data.h"
+
+/*** DOCUMENTATION
+	<application name="AgentLogin" language="en_US">
+		<synopsis>
+			Call agent login.
+		</synopsis>
+		<syntax>
+			<parameter name="AgentNo" />
+			<parameter name="options">
+				<optionlist>
+					<option name="s">
+						<para>silent login - do not announce the login ok segment after
+						agent logged on/off</para>
+					</option>
+				</optionlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Asks the agent to login to the system. Always returns <literal>-1</literal>.
+			While logged in, the agent can receive calls and will hear a <literal>beep</literal>
+			when a new call comes in. The agent can dump the call by pressing the star key.</para>
+		</description>
+		<see-also>
+			<ref type="application">Queue</ref>
+			<ref type="application">AddQueueMember</ref>
+			<ref type="application">RemoveQueueMember</ref>
+			<ref type="application">PauseQueueMember</ref>
+			<ref type="application">UnpauseQueueMember</ref>
+			<ref type="function">AGENT</ref>
+			<ref type="filename">agents.conf</ref>
+			<ref type="filename">queues.conf</ref>
+		</see-also>
+	</application>
+	<application name="AgentMonitorOutgoing" language="en_US">
+		<synopsis>
+			Record agent's outgoing call.
+		</synopsis>
+		<syntax>
+			<parameter name="options">
+				<optionlist>
+					<option name="d">
+						<para>make the app return <literal>-1</literal> if there is an error condition.</para>
+					</option>
+					<option name="c">
+						<para>change the CDR so that the source of the call is
+						<literal>Agent/agent_id</literal></para>
+					</option>
+					<option name="n">
+						<para>don't generate the warnings when there is no callerid or the
+						agentid is not known. It's handy if you want to have one context
+						for agent and non-agent calls.</para>
+					</option>
+				</optionlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Tries to figure out the id of the agent who is placing outgoing call based on
+			comparison of the callerid of the current interface and the global variable
+			placed by the AgentCallbackLogin application. That's why it should be used only
+			with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent
+			instead of Monitor application. That has to be configured in the
+			<filename>agents.conf</filename> file.</para>
+			<para>Normally the app returns <literal>0</literal> unless the options are passed.</para>
+		</description>
+		<see-also>
+			<ref type="filename">agents.conf</ref>
+		</see-also>
+	</application>
+	<function name="AGENT" language="en_US">
+		<synopsis>
+			Gets information about an Agent
+		</synopsis>
+		<syntax argsep=":">
+			<parameter name="agentid" required="true" />
+			<parameter name="item">
+				<para>The valid items to retrieve are:</para>
+				<enumlist>
+					<enum name="status">
+						<para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
+					</enum>
+					<enum name="password">
+						<para>The password of the agent</para>
+					</enum>
+					<enum name="name">
+						<para>The name of the agent</para>
+					</enum>
+					<enum name="mohclass">
+						<para>MusicOnHold class</para>
+					</enum>
+					<enum name="channel">
+						<para>The name of the active channel for the Agent (AgentLogin)</para>
+					</enum>
+					<enum name="fullchannel">
+						<para>The untruncated name of the active channel for the Agent (AgentLogin)</para>
+					</enum>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<description></description>
+	</function>
+	<manager name="Agents" language="en_US">
+		<synopsis>
+			Lists agents and their status.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+		</syntax>
+		<description>
+			<para>Will list info about all possible agents.</para>
+		</description>
+	</manager>
+	<manager name="AgentLogoff" language="en_US">
+		<synopsis>
+			Sets an agent as no longer logged in.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Agent" required="true">
+				<para>Agent ID of the agent to log off.</para>
+			</parameter>
+			<parameter name="Soft">
+				<para>Set to <literal>true</literal> to not hangup existing calls.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Sets an agent as no longer logged in.</para>
+		</description>
+	</manager>
+ ***/
+
+static const char tdesc[] = "Call Agent Proxy Channel";
+static const char config[] = "agents.conf";
+
+static const char app[] = "AgentLogin";
+static const char app3[] = "AgentMonitorOutgoing";
+
+static char moh[80] = "default";
+
+#define AST_MAX_AGENT	80                          /*!< Agent ID or Password max length */
+#define AST_MAX_BUF	256
+#define AST_MAX_FILENAME_LEN	256
+
+static const char pa_family[] = "Agents";          /*!< Persistent Agents astdb family */
+#define PA_MAX_LEN 2048                             /*!< The maximum length of each persistent member agent database entry */
+
+#define DEFAULT_ACCEPTDTMF '#'
+#define DEFAULT_ENDDTMF '*'
+
+static ast_group_t group;
+static int autologoff;
+static int wrapuptime;
+static int ackcall;
+static int endcall;
+static int autologoffunavail = 0;
+static char acceptdtmf = DEFAULT_ACCEPTDTMF;
+static char enddtmf = DEFAULT_ENDDTMF;
+
+static int maxlogintries = 3;
+static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
+
+static int recordagentcalls = 0;
+static char recordformat[AST_MAX_BUF] = "";
+static char recordformatext[AST_MAX_BUF] = "";
+static char urlprefix[AST_MAX_BUF] = "";
+static char savecallsin[AST_MAX_BUF] = "";
+static int updatecdr = 0;
+static char beep[AST_MAX_BUF] = "beep";
+
+#define GETAGENTBYCALLERID	"AGENTBYCALLERID"
+
+enum {
+	AGENT_FLAG_ACKCALL = (1 << 0),
+	AGENT_FLAG_AUTOLOGOFF = (1 << 1),
+	AGENT_FLAG_WRAPUPTIME = (1 << 2),
+	AGENT_FLAG_ACCEPTDTMF = (1 << 3),
+	AGENT_FLAG_ENDDTMF = (1 << 4),
+};
+
+/*! \brief Structure representing an agent.  */
+struct agent_pvt {
+	ast_mutex_t lock;              /*!< Channel private lock */
+	int dead;                      /*!< Poised for destruction? */
+	int pending;                   /*!< Not a real agent -- just pending a match */
+	int abouttograb;               /*!< About to grab */
+	int autologoff;                /*!< Auto timeout time */
+	int ackcall;                   /*!< ackcall */
+	int deferlogoff;               /*!< Defer logoff to hangup */
+	char acceptdtmf;
+	char enddtmf;
+	time_t loginstart;             /*!< When agent first logged in (0 when logged off) */
+	time_t start;                  /*!< When call started */
+	struct timeval lastdisc;       /*!< When last disconnected */
+	int wrapuptime;                /*!< Wrapup time in ms */
+	ast_group_t group;             /*!< Group memberships */
+	int acknowledged;              /*!< Acknowledged */
+	char moh[80];                  /*!< Which music on hold */
+	char agent[AST_MAX_AGENT];     /*!< Agent ID */
+	char password[AST_MAX_AGENT];  /*!< Password for Agent login */
+	char name[AST_MAX_AGENT];
+	int app_lock_flag;
+	ast_cond_t app_complete_cond;
+	ast_cond_t login_wait_cond;
+	int app_sleep_cond;            /*!< Non-zero if the login app should sleep. */
+	struct ast_channel *owner;     /*!< Agent */
+	struct ast_channel *chan;      /*!< Channel we use */
+	unsigned int flags;            /*!< Flags show if settings were applied with channel vars */
+	AST_LIST_ENTRY(agent_pvt) list;/*!< Next Agent in the linked list. */
+};
+
+#define DATA_EXPORT_AGENT(MEMBER)				\
+	MEMBER(agent_pvt, autologoff, AST_DATA_INTEGER)		\
+	MEMBER(agent_pvt, ackcall, AST_DATA_BOOLEAN)		\
+	MEMBER(agent_pvt, deferlogoff, AST_DATA_BOOLEAN)	\
+	MEMBER(agent_pvt, wrapuptime, AST_DATA_MILLISECONDS)	\
+	MEMBER(agent_pvt, acknowledged, AST_DATA_BOOLEAN)	\
+	MEMBER(agent_pvt, name, AST_DATA_STRING)		\
+	MEMBER(agent_pvt, password, AST_DATA_PASSWORD)		\
+	MEMBER(agent_pvt, acceptdtmf, AST_DATA_CHARACTER)
+
+AST_DATA_STRUCTURE(agent_pvt, DATA_EXPORT_AGENT);
+
+static AST_LIST_HEAD_STATIC(agents, agent_pvt);	/*!< Holds the list of agents (loaded form agents.conf). */
+
+#define CHECK_FORMATS(ast, p) do { \
+	if (p->chan) {\
+		if (!(ast_format_cap_identical(ast_channel_nativeformats(ast), ast_channel_nativeformats(p->chan)))) { \
+			char tmp1[256], tmp2[256]; \
+			ast_debug(1, "Native formats changing from '%s' to '%s'\n", ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(ast)), ast_getformatname_multiple(tmp2, sizeof(tmp2), ast_channel_nativeformats(p->chan))); \
+			/* Native formats changed, reset things */ \
+			ast_format_cap_copy(ast_channel_nativeformats(ast), ast_channel_nativeformats(p->chan)); \
+			ast_debug(1, "Resetting read to '%s' and write to '%s'\n", ast_getformatname(ast_channel_readformat(ast)), ast_getformatname(ast_channel_writeformat(ast)));\
+			ast_set_read_format(ast, ast_channel_readformat(ast)); \
+			ast_set_write_format(ast, ast_channel_writeformat(ast)); \
+		} \
+		if ((ast_format_cmp(ast_channel_readformat(p->chan), ast_channel_rawreadformat(ast)) != AST_FORMAT_CMP_EQUAL) && !ast_channel_generator(p->chan))  \
+			ast_set_read_format(p->chan, ast_channel_rawreadformat(ast)); \
+		if ((ast_format_cmp(ast_channel_writeformat(p->chan), ast_channel_rawwriteformat(ast)) != AST_FORMAT_CMP_EQUAL) && !ast_channel_generator(p->chan)) \
+			ast_set_write_format(p->chan, ast_channel_rawwriteformat(ast)); \
+	} \
+} while(0)
+
+/*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
+   properly for a timingfd XXX This might need more work if agents were logged in as agents or other
+   totally impractical combinations XXX */
+
+#define CLEANUP(ast, p) do { \
+	int x; \
+	if (p->chan) { \
+		for (x = 0; x < AST_MAX_FDS; x++) { \
+			if (x != AST_TIMING_FD) { \
+				ast_channel_set_fd(ast, x, ast_channel_fd(p->chan, x)); \
+			} \
+		} \
+		ast_channel_set_fd(ast, AST_AGENT_FD, ast_channel_fd(p->chan, AST_TIMING_FD)); \
+	} \
+} while(0)
+
+/*--- Forward declarations */
+static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int agent_devicestate(const char *data);
+static int agent_digit_begin(struct ast_channel *ast, char digit);
+static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int agent_call(struct ast_channel *ast, const char *dest, int timeout);
+static int agent_hangup(struct ast_channel *ast);
+static int agent_answer(struct ast_channel *ast);
+static struct ast_frame *agent_read(struct ast_channel *ast);
+static int agent_write(struct ast_channel *ast, struct ast_frame *f);
+static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
+static int agent_sendtext(struct ast_channel *ast, const char *text);
+static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
+static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state);
+static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
+static int agent_logoff(const char *agent, int soft);
+
+/*! \brief Channel interface description for PBX integration */
+static struct ast_channel_tech agent_tech = {
+	.type = "Agent",
+	.description = tdesc,
+	.requester = agent_request,
+	.devicestate = agent_devicestate,
+	.send_digit_begin = agent_digit_begin,
+	.send_digit_end = agent_digit_end,
+	.call = agent_call,
+	.hangup = agent_hangup,
+	.answer = agent_answer,
+	.read = agent_read,
+	.write = agent_write,
+	.write_video = agent_write,
+	.send_html = agent_sendhtml,
+	.send_text = agent_sendtext,
+	.exception = agent_read,
+	.indicate = agent_indicate,
+	.fixup = agent_fixup,
+	.bridged_channel = agent_bridgedchannel,
+	.get_base_channel = agent_get_base_channel,
+};
+
+/*!
+ * \brief Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt
+ * must enter this function locked and will be returned locked, but this function will
+ * unlock the pvt for a short time, so it can't be used while expecting the pvt to remain
+ * static. If function returns a non NULL channel, it will need to be unlocked and
+ * unrefed once it is no longer needed.
+ *
+ * \param pvt Pointer to the LOCKED agent_pvt for which the owner is needed
+ * \ret locked channel which owns the pvt at the time of completion. NULL if not available.
+ */
+static struct ast_channel *agent_lock_owner(struct agent_pvt *pvt)
+{
+	struct ast_channel *owner;
+
+	for (;;) {
+		if (!pvt->owner) { /* No owner. Nothing to do. */
+			return NULL;
+		}
+
+		/* If we don't ref the owner, it could be killed when we unlock the pvt. */
+		owner = ast_channel_ref(pvt->owner);
+
+		/* Locking order requires us to lock channel, then pvt. */
+		ast_mutex_unlock(&pvt->lock);
+		ast_channel_lock(owner);
+		ast_mutex_lock(&pvt->lock);
+
+		/* Check if owner changed during pvt unlock period */
+		if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
+			ast_channel_unlock(owner);
+			owner = ast_channel_unref(owner);
+		} else { /* Channel stayed the same. Return it. */
+			return owner;
+		}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Destroy an agent pvt struct.
+ *
+ * \param doomed Agent pvt to destroy.
+ *
+ * \return Nothing
+ */
+static void agent_pvt_destroy(struct agent_pvt *doomed)
+{
+	ast_mutex_destroy(&doomed->lock);
+	ast_cond_destroy(&doomed->app_complete_cond);
+	ast_cond_destroy(&doomed->login_wait_cond);
+	ast_free(doomed);
+}
+
+/*!
+ * Adds an agent to the global list of agents.
+ *
+ * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
+ * \param pending If it is pending or not.
+ * @return The just created agent.
+ * \sa agent_pvt, agents.
+ */
+static struct agent_pvt *add_agent(const char *agent, int pending)
+{
+	char *parse;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(agt);
+		AST_APP_ARG(password);
+		AST_APP_ARG(name);
+	);
+	char *password = NULL;
+	char *name = NULL;
+	char *agt = NULL;
+	struct agent_pvt *p;
+
+	parse = ast_strdupa(agent);
+
+	/* Extract username (agt), password and name from agent (args). */
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if(args.argc == 0) {
+		ast_log(LOG_WARNING, "A blank agent line!\n");
+		return NULL;
+	}
+
+	if(ast_strlen_zero(args.agt) ) {
+		ast_log(LOG_WARNING, "An agent line with no agentid!\n");
+		return NULL;
+	} else
+		agt = args.agt;
+
+	if(!ast_strlen_zero(args.password)) {
+		password = args.password;
+		while (*password && *password < 33) password++;
+	}
+	if(!ast_strlen_zero(args.name)) {
+		name = args.name;
+		while (*name && *name < 33) name++;
+	}
+
+	if (!pending) {
+		/* Are we searching for the agent here ? To see if it exists already ? */
+		AST_LIST_TRAVERSE(&agents, p, list) {
+			if (!strcmp(p->agent, agt)) {
+				break;
+			}
+		}
+	} else {
+		p = NULL;
+	}
+	if (!p) {
+		// Build the agent.
+		if (!(p = ast_calloc(1, sizeof(*p))))
+			return NULL;
+		ast_copy_string(p->agent, agt, sizeof(p->agent));
+		ast_mutex_init(&p->lock);
+		ast_cond_init(&p->app_complete_cond, NULL);
+		ast_cond_init(&p->login_wait_cond, NULL);
+		p->app_lock_flag = 0;
+		p->app_sleep_cond = 1;
+		p->group = group;
+		p->pending = pending;
+		AST_LIST_INSERT_TAIL(&agents, p, list);
+	}
+	
+	ast_copy_string(p->password, password ? password : "", sizeof(p->password));
+	ast_copy_string(p->name, name ? name : "", sizeof(p->name));
+	ast_copy_string(p->moh, moh, sizeof(p->moh));
+	if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
+		p->ackcall = ackcall;
+	}
+	if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
+		p->autologoff = autologoff;
+	}
+	if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
+		p->acceptdtmf = acceptdtmf;
+	}
+	if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
+		p->enddtmf = enddtmf;
+	}
+
+	/* If someone reduces the wrapuptime and reloads, we want it
+	 * to change the wrapuptime immediately on all calls */
+	if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
+		struct timeval now = ast_tvnow();
+		/* XXX check what is this exactly */
+
+		/* We won't be pedantic and check the tv_usec val */
+		if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
+			p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
+			p->lastdisc.tv_usec = now.tv_usec;
+		}
+	}
+	p->wrapuptime = wrapuptime;
+
+	if (pending)
+		p->dead = 1;
+	else
+		p->dead = 0;
+	return p;
+}
+
+/*!
+ * Deletes an agent after doing some clean up.
+ * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
+ *
+ * \warning XXX This function seems to be very unsafe.
+ * Potential for double free and use after free among other
+ * problems.
+ *
+ * \param p Agent to be deleted.
+ * \returns Always 0.
+ */
+static int agent_cleanup(struct agent_pvt *p)
+{
+	struct ast_channel *chan;
+
+	ast_mutex_lock(&p->lock);
+	chan = p->owner;
+	p->owner = NULL;
+	/* Release ownership of the agent to other threads (presumably running the login app). */
+	p->app_sleep_cond = 1;
+	p->app_lock_flag = 0;
+	ast_cond_signal(&p->app_complete_cond);
+	if (chan) {
+		ast_channel_tech_pvt_set(chan, NULL);
+		chan = ast_channel_release(chan);
+	}
+	if (p->dead) {
+		ast_mutex_unlock(&p->lock);
+		agent_pvt_destroy(p);
+	} else {
+		ast_mutex_unlock(&p->lock);
+	}
+	return 0;
+}
+
+static int agent_answer(struct ast_channel *ast)
+{
+	ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
+	return -1;
+}
+
+static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
+{
+	char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
+	char filename[AST_MAX_BUF];
+	int res = -1;
+	if (!p)
+		return -1;
+	if (!ast_channel_monitor(ast)) {
+		snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast_channel_uniqueid(ast));
+		/* substitute . for - */
+		if ((pointer = strchr(filename, '.')))
+			*pointer = '-';
+		snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
+		ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
+		ast_monitor_setjoinfiles(ast, 1);
+		snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
+#if 0
+		ast_verbose("name is %s, link is %s\n",tmp, tmp2);
+#endif
+		if (!ast_channel_cdr(ast))
+			ast_channel_cdr_set(ast, ast_cdr_alloc());
+		ast_cdr_setuserfield(ast, tmp2);
+		res = 0;
+	} else
+		ast_log(LOG_ERROR, "Recording already started on that call.\n");
+	return res;
+}
+
+static int agent_start_monitoring(struct ast_channel *ast, int needlock)
+{
+	return __agent_start_monitoring(ast, ast_channel_tech_pvt(ast), needlock);
+}
+
+static struct ast_frame *agent_read(struct ast_channel *ast)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	struct ast_frame *f = NULL;
+	static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
+	int cur_time = time(NULL);
+	struct ast_channel *owner;
+
+	ast_mutex_lock(&p->lock);
+	owner = agent_lock_owner(p);
+
+	CHECK_FORMATS(ast, p);
+	if (!p->start) {
+		p->start = cur_time;
+	}
+	if (p->chan) {
+		ast_copy_flags(ast_channel_flags(p->chan), ast_channel_flags(ast), AST_FLAG_EXCEPTION);
+		ast_channel_fdno_set(p->chan, (ast_channel_fdno(ast) == AST_AGENT_FD) ? AST_TIMING_FD : ast_channel_fdno(ast));
+		f = ast_read(p->chan);
+		ast_channel_fdno_set(ast, -1);
+	} else
+		f = &ast_null_frame;
+	if (f) {
+		/* if acknowledgement is not required, and the channel is up, we may have missed
+			an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
+		if (!p->ackcall && !p->acknowledged && p->chan && (ast_channel_state(p->chan) == AST_STATE_UP)) {
+			p->acknowledged = 1;
+		}
+
+		if (!p->acknowledged) {
+			int howlong = cur_time - p->start;
+			if (p->autologoff && (howlong >= p->autologoff)) {
+				ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
+				if (owner || p->chan) {
+					if (owner) {
+						ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+						ast_channel_unlock(owner);
+						owner = ast_channel_unref(owner);
+					}
+
+					while (p->chan && ast_channel_trylock(p->chan)) {
+						DEADLOCK_AVOIDANCE(&p->lock);
+					}
+					if (p->chan) {
+						ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
+						ast_channel_unlock(p->chan);
+					}
+				}
+			}
+		}
+		switch (f->frametype) {
+		case AST_FRAME_CONTROL:
+			if (f->subclass.integer == AST_CONTROL_ANSWER) {
+				if (p->ackcall) {
+					ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", ast_channel_name(p->chan), p->acceptdtmf);
+					/* Don't pass answer along */
+					ast_frfree(f);
+					f = &ast_null_frame;
+				} else {
+					p->acknowledged = 1;
+					/* Use the builtin answer frame for the 
+					   recording start check below. */
+					ast_frfree(f);
+					f = &answer_frame;
+				}
+			}
+			break;
+		case AST_FRAME_DTMF_BEGIN:
+			/*ignore DTMF begin's as it can cause issues with queue announce files*/
+			if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){
+				ast_frfree(f);
+				f = &ast_null_frame;
+			}
+			break;
+		case AST_FRAME_DTMF_END:
+			if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) {
+				if (p->chan) {
+					ast_verb(3, "%s acknowledged\n", ast_channel_name(p->chan));
+				}
+				p->acknowledged = 1;
+				ast_frfree(f);
+				f = &answer_frame;
+			} else if (f->subclass.integer == p->enddtmf && endcall) {
+				/* terminates call */
+				ast_frfree(f);
+				f = NULL;
+			}
+			break;
+		case AST_FRAME_VOICE:
+		case AST_FRAME_VIDEO:
+			/* don't pass voice or video until the call is acknowledged */
+			if (!p->acknowledged) {
+				ast_frfree(f);
+				f = &ast_null_frame;
+			}
+		default:
+			/* pass everything else on through */
+			break;
+		}
+	}
+
+	if (owner) {
+		ast_channel_unlock(owner);
+		owner = ast_channel_unref(owner);
+	}
+
+	CLEANUP(ast,p);
+	if (p->chan && !ast_channel_internal_bridged_channel(p->chan)) {
+		if (strcasecmp(ast_channel_tech(p->chan)->type, "Local")) {
+			ast_channel_internal_bridged_channel_set(p->chan, ast);
+			ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", ast_channel_name(p->chan), ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
+		}
+	}
+	ast_mutex_unlock(&p->lock);
+	if (recordagentcalls && f == &answer_frame)
+		agent_start_monitoring(ast,0);
+	return f;
+}
+
+static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	ast_mutex_lock(&p->lock);
+	if (p->chan) 
+		res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
+	ast_mutex_unlock(&p->lock);
+	return res;
+}
+
+static int agent_sendtext(struct ast_channel *ast, const char *text)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	ast_mutex_lock(&p->lock);
+	if (p->chan) 
+		res = ast_sendtext(p->chan, text);
+	ast_mutex_unlock(&p->lock);
+	return res;
+}
+
+static int agent_write(struct ast_channel *ast, struct ast_frame *f)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	CHECK_FORMATS(ast, p);
+	ast_mutex_lock(&p->lock);
+	if (!p->chan) 
+		res = 0;
+	else {
+		if ((f->frametype != AST_FRAME_VOICE) ||
+		    (f->frametype != AST_FRAME_VIDEO) ||
+		    (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(p->chan)) != AST_FORMAT_CMP_NOT_EQUAL)) {
+			res = ast_write(p->chan, f);
+		} else {
+			ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
+				f->frametype == AST_FRAME_VOICE ? "audio" : "video",
+				ast_channel_name(ast), ast_channel_name(p->chan));
+			res = 0;
+		}
+	}
+	CLEANUP(ast, p);
+	ast_mutex_unlock(&p->lock);
+	return res;
+}
+
+static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(newchan);
+	ast_mutex_lock(&p->lock);
+	if (p->owner != oldchan) {
+		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
+		ast_mutex_unlock(&p->lock);
+		return -1;
+	}
+	p->owner = newchan;
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+
+	ast_mutex_lock(&p->lock);
+	if (p->chan && !ast_check_hangup(p->chan)) {
+		ast_channel_unlock(ast);
+		ast_channel_lock(p->chan);
+		res = ast_channel_tech(p->chan)->indicate
+			? ast_channel_tech(p->chan)->indicate(p->chan, condition, data, datalen)
+			: -1;
+		ast_channel_unlock(p->chan);
+		ast_mutex_unlock(&p->lock);
+		ast_channel_lock(ast);
+	} else {
+		ast_mutex_unlock(&p->lock);
+		res = 0;
+	}
+	return res;
+}
+
+static int agent_digit_begin(struct ast_channel *ast, char digit)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	ast_mutex_lock(&p->lock);
+	if (p->chan) {
+		ast_senddigit_begin(p->chan, digit);
+	}
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	ast_mutex_lock(&p->lock);
+	if (p->chan) {
+		ast_senddigit_end(p->chan, digit, duration);
+	}
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int agent_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	int res;
+	int newstate=0;
+
+	ast_mutex_lock(&p->lock);
+	p->acknowledged = 0;
+
+	if (p->pending) {
+		ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
+		ast_mutex_unlock(&p->lock);
+		ast_setstate(ast, AST_STATE_DIALING);
+		return 0;
+	}
+
+	ast_assert(p->chan != NULL);
+	ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, ast_channel_name(p->chan));
+	ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(p->chan));
+
+	ast_mutex_unlock(&p->lock);
+
+	res = ast_streamfile(p->chan, beep, ast_channel_language(p->chan));
+	ast_debug(3, "Played beep, result '%d'\n", res);
+	if (!res) {
+		res = ast_waitstream(p->chan, "");
+		ast_debug(3, "Waited for stream, result '%d'\n", res);
+	}
+	
+	ast_mutex_lock(&p->lock);
+
+	if (!res) {
+		struct ast_format tmpfmt;
+		res = ast_set_read_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
+		ast_debug(3, "Set read format, result '%d'\n", res);
+		if (res)
+			ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
+	}
+
+	if (!res) {
+		struct ast_format tmpfmt;
+		res = ast_set_write_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
+		ast_debug(3, "Set write format, result '%d'\n", res);
+		if (res)
+			ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
+	}
+	if(!res) {
+		/* Call is immediately up, or might need ack */
+		if (p->ackcall) {
+			newstate = AST_STATE_RINGING;
+		} else {
+			newstate = AST_STATE_UP;
+			if (recordagentcalls)
+				agent_start_monitoring(ast, 0);
+			p->acknowledged = 1;
+		}
+	}
+	CLEANUP(ast, p);
+	ast_mutex_unlock(&p->lock);
+	if (newstate)
+		ast_setstate(ast, newstate);
+	return res ? -1 : 0;
+}
+
+/*! \brief return the channel or base channel if one exists.  This function assumes the channel it is called on is already locked */
+struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
+{
+	struct agent_pvt *p;
+	struct ast_channel *base = chan;
+
+	/* chan is locked by the calling function */
+	if (!chan || !ast_channel_tech_pvt(chan)) {
+		ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)ast_channel_tech_pvt(chan):(long)NULL);
+		return NULL;
+	}
+	p = ast_channel_tech_pvt(chan);
+	if (p->chan) 
+		base = p->chan;
+	return base;
+}
+
+static int agent_hangup(struct ast_channel *ast)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(ast);
+	struct ast_channel *indicate_chan = NULL;
+	char *tmp_moh; /* moh buffer for indicating after unlocking p */
+
+	if (p->pending) {
+		AST_LIST_LOCK(&agents);
+		AST_LIST_REMOVE(&agents, p, list);
+		AST_LIST_UNLOCK(&agents);
+	}
+
+	ast_mutex_lock(&p->lock);
+	p->owner = NULL;
+	ast_channel_tech_pvt_set(ast, NULL);
+	p->acknowledged = 0;
+
+	/* if they really are hung up then set start to 0 so the test
+	 * later if we're called on an already downed channel
+	 * doesn't cause an agent to be logged out like when
+	 * agent_request() is followed immediately by agent_hangup()
+	 * as in apps/app_chanisavail.c:chanavail_exec()
+	 */
+
+	ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast_channel_state(ast)));
+	p->start = 0;
+	if (p->chan) {
+		ast_channel_internal_bridged_channel_set(p->chan, NULL);
+		/* If they're dead, go ahead and hang up on the agent now */
+		if (p->dead) {
+			ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
+		} else if (p->loginstart) {
+			indicate_chan = ast_channel_ref(p->chan);
+			tmp_moh = ast_strdupa(p->moh);
+		}
+	}
+	ast_mutex_unlock(&p->lock);
+
+	if (indicate_chan) {
+		ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
+			S_OR(tmp_moh, NULL),
+			!ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
+		indicate_chan = ast_channel_unref(indicate_chan);
+	}
+
+	ast_mutex_lock(&p->lock);
+	if (p->abouttograb) {
+		/* Let the "about to grab" thread know this isn't valid anymore, and let it
+		   kill it later */
+		p->abouttograb = 0;
+	} else if (p->dead) {
+		ast_mutex_unlock(&p->lock);
+		agent_pvt_destroy(p);
+		return 0;
+	} else {
+		/* Store last disconnect time */
+		p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
+	}
+
+	/* Release ownership of the agent to other threads (presumably running the login app). */
+	p->app_sleep_cond = 1;
+	p->app_lock_flag = 0;
+	ast_cond_signal(&p->app_complete_cond);
+
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int agent_cont_sleep(void *data)
+{
+	struct agent_pvt *p;
+	int res;
+
+	p = (struct agent_pvt *) data;
+
+	ast_mutex_lock(&p->lock);
+	res = p->app_sleep_cond;
+	if (res && p->lastdisc.tv_sec) {
+		if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
+			res = 0;
+		}
+	}
+	ast_mutex_unlock(&p->lock);
+
+	if (!res) {
+		ast_debug(5, "agent_cont_sleep() returning %d\n", res);
+	}
+
+	return res;
+}
+
+static int agent_ack_sleep(struct agent_pvt *p)
+{
+	int digit;
+	int to = 1000;
+	struct ast_frame *f;
+	struct timeval start = ast_tvnow();
+	int ms;
+
+	/* Wait a second and look for something */
+	while ((ms = ast_remaining_ms(start, to))) {
+		ms = ast_waitfor(p->chan, ms);
+		if (ms < 0) {
+			return -1;
+		}
+		if (ms == 0) {
+			return 0;
+		}
+		f = ast_read(p->chan);
+		if (!f) {
+			return -1;
+		}
+		if (f->frametype == AST_FRAME_DTMF) {
+			digit = f->subclass.integer;
+		} else {
+			digit = 0;
+		}
+		ast_frfree(f);
+		ast_mutex_lock(&p->lock);
+		if (!p->app_sleep_cond) {
+			ast_mutex_unlock(&p->lock);
+			return 0;
+		}
+		if (digit == p->acceptdtmf) {
+			ast_mutex_unlock(&p->lock);
+			return 1;
+		}
+		if (p->lastdisc.tv_sec) {
+			if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
+				ast_mutex_unlock(&p->lock);
+				return 0;
+			}
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	return 0;
+}
+
+static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
+{
+	struct agent_pvt *p = ast_channel_tech_pvt(bridge);
+	struct ast_channel *ret = NULL;
+
+	if (p) {
+		if (chan == p->chan)
+			ret = ast_channel_internal_bridged_channel(bridge);
+		else if (chan == ast_channel_internal_bridged_channel(bridge))
+			ret = p->chan;
+	}
+
+	ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", ast_channel_name(chan), ast_channel_name(bridge), ret ? ast_channel_name(ret) : "<none>");
+	return ret;
+}
+
+/*! \brief Create new agent channel */
+static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
+{
+	struct ast_channel *tmp;
+#if 0
+	if (!p->chan) {
+		ast_log(LOG_WARNING, "No channel? :(\n");
+		return NULL;
+	}
+#endif	
+	if (p->pending)
+		tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
+	else
+		tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/%s", p->agent);
+	if (!tmp) {
+		ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
+		return NULL;
+	}
+
+	if (callid) {
+		ast_channel_callid_set(tmp, callid);
+	}
+
+	ast_channel_tech_set(tmp, &agent_tech);
+	if (p->chan) {
+		ast_format_cap_copy(ast_channel_nativeformats(tmp), ast_channel_nativeformats(p->chan));
+		ast_format_copy(ast_channel_writeformat(tmp), ast_channel_writeformat(p->chan));
+		ast_format_copy(ast_channel_rawwriteformat(tmp), ast_channel_writeformat(p->chan));
+		ast_format_copy(ast_channel_readformat(tmp), ast_channel_readformat(p->chan));
+		ast_format_copy(ast_channel_rawreadformat(tmp), ast_channel_readformat(p->chan));
+		ast_channel_language_set(tmp, ast_channel_language(p->chan));
+		ast_channel_context_set(tmp, ast_channel_context(p->chan));
+		ast_channel_exten_set(tmp, ast_channel_exten(p->chan));
+		/* XXX Is this really all we copy form the originating channel?? */
+	} else {
+		ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
+		ast_format_set(ast_channel_rawwriteformat(tmp), AST_FORMAT_SLINEAR, 0);
+		ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
+		ast_format_set(ast_channel_rawreadformat(tmp), AST_FORMAT_SLINEAR, 0);
+		ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
+	}
+	/* Safe, agentlock already held */
+	ast_channel_tech_pvt_set(tmp, p);
+	p->owner = tmp;
+	ast_channel_priority_set(tmp, 1);
+	return tmp;
+}
+
+
+/*!
+ * Read configuration data. The file named agents.conf.
+ *
+ * \returns Always 0, or so it seems.
+ */
+static int read_agent_config(int reload)
+{
+	struct ast_config *cfg;
+	struct ast_config *ucfg;
+	struct ast_variable *v;
+	struct agent_pvt *p;
+	const char *catname;
+	const char *hasagent;
+	int genhasagent;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+	group = 0;
+	autologoff = 0;
+	wrapuptime = 0;
+	ackcall = 0;
+	endcall = 1;
+	cfg = ast_config_load(config, config_flags);
+	if (!cfg) {
+		ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
+		return 0;
+	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+		return -1;
+	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
+		return 0;
+	}
+	if ((ucfg = ast_config_load("users.conf", config_flags))) {
+		if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
+			ucfg = NULL;
+		} else if (ucfg == CONFIG_STATUS_FILEINVALID) {
+			ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
+			return 0;
+		}
+	}
+
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		p->dead = 1;
+	}
+	strcpy(moh, "default");
+	/* set the default recording values */
+	recordagentcalls = 0;
+	strcpy(recordformat, "wav");
+	strcpy(recordformatext, "wav");
+	urlprefix[0] = '\0';
+	savecallsin[0] = '\0';
+
+	/* Read in the [agents] section */
+	v = ast_variable_browse(cfg, "agents");
+	while(v) {
+		/* Create the interface list */
+		if (!strcasecmp(v->name, "agent")) {
+			add_agent(v->value, 0);
+		} else if (!strcasecmp(v->name, "group")) {
+			group = ast_get_group(v->value);
+		} else if (!strcasecmp(v->name, "autologoff")) {
+			autologoff = atoi(v->value);
+			if (autologoff < 0)
+				autologoff = 0;
+		} else if (!strcasecmp(v->name, "ackcall")) {
+			if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
+				ackcall = 1;
+			}
+		} else if (!strcasecmp(v->name, "endcall")) {
+			endcall = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "acceptdtmf")) {
+			acceptdtmf = *(v->value);
+			ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
+		} else if (!strcasecmp(v->name, "enddtmf")) {
+			enddtmf = *(v->value);
+		} else if (!strcasecmp(v->name, "wrapuptime")) {
+			wrapuptime = atoi(v->value);
+			if (wrapuptime < 0)
+				wrapuptime = 0;
+		} else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
+			maxlogintries = atoi(v->value);
+			if (maxlogintries < 0)
+				maxlogintries = 0;
+		} else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
+			strcpy(agentgoodbye,v->value);
+		} else if (!strcasecmp(v->name, "musiconhold")) {
+			ast_copy_string(moh, v->value, sizeof(moh));
+		} else if (!strcasecmp(v->name, "updatecdr")) {
+			if (ast_true(v->value))
+				updatecdr = 1;
+			else
+				updatecdr = 0;
+		} else if (!strcasecmp(v->name, "autologoffunavail")) {
+			if (ast_true(v->value))
+				autologoffunavail = 1;
+			else
+				autologoffunavail = 0;
+		} else if (!strcasecmp(v->name, "recordagentcalls")) {
+			recordagentcalls = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "recordformat")) {
+			ast_copy_string(recordformat, v->value, sizeof(recordformat));
+			if (!strcasecmp(v->value, "wav49"))
+				strcpy(recordformatext, "WAV");
+			else
+				ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
+		} else if (!strcasecmp(v->name, "urlprefix")) {
+			ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
+			if (urlprefix[strlen(urlprefix) - 1] != '/')
+				strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
+		} else if (!strcasecmp(v->name, "savecallsin")) {
+			if (v->value[0] == '/')
+				ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
+			else
+				snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
+			if (savecallsin[strlen(savecallsin) - 1] != '/')
+				strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
+		} else if (!strcasecmp(v->name, "custom_beep")) {
+			ast_copy_string(beep, v->value, sizeof(beep));
+		}
+		v = v->next;
+	}
+	if (ucfg) {
+		genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
+		catname = ast_category_browse(ucfg, NULL);
+		while(catname) {
+			if (strcasecmp(catname, "general")) {
+				hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
+				if (ast_true(hasagent) || (!hasagent && genhasagent)) {
+					char tmp[256];
+					const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
+					const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
+					if (!fullname)
+						fullname = "";
+					if (!secret)
+						secret = "";
+					snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
+					add_agent(tmp, 0);
+				}
+			}
+			catname = ast_category_browse(ucfg, catname);
+		}
+		ast_config_destroy(ucfg);
+	}
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
+		if (p->dead) {
+			AST_LIST_REMOVE_CURRENT(list);
+			/* Destroy if  appropriate */
+			if (!p->owner) {
+				if (!p->chan) {
+					agent_pvt_destroy(p);
+				} else {
+					/* Cause them to hang up */
+					ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
+				}
+			}
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&agents);
+	ast_config_destroy(cfg);
+	return 1;
+}
+
+static int check_availability(struct agent_pvt *newlyavailable, int needlock)
+{
+	struct ast_channel *chan=NULL, *parent=NULL;
+	struct agent_pvt *p;
+	int res;
+
+	ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
+	if (needlock)
+		AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		if (p == newlyavailable) {
+			continue;
+		}
+		ast_mutex_lock(&p->lock);
+		if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
+			ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
+			/* We found a pending call, time to merge */
+			chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL, NULL);
+			parent = p->owner;
+			p->abouttograb = 1;
+			ast_mutex_unlock(&p->lock);
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	if (needlock)
+		AST_LIST_UNLOCK(&agents);
+	if (parent && chan)  {
+		if (newlyavailable->ackcall) {
+			/* Don't do beep here */
+			res = 0;
+		} else {
+			ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
+			res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
+			ast_debug(3, "Played beep, result '%d'\n", res);
+			if (!res) {
+				res = ast_waitstream(newlyavailable->chan, "");
+				ast_debug(1, "Waited for stream, result '%d'\n", res);
+			}
+		}
+		if (!res) {
+			/* Note -- parent may have disappeared */
+			if (p->abouttograb) {
+				newlyavailable->acknowledged = 1;
+				/* Safe -- agent lock already held */
+				ast_setstate(parent, AST_STATE_UP);
+				ast_setstate(chan, AST_STATE_UP);
+				ast_channel_context_set(parent, ast_channel_context(chan));
+				ast_channel_masquerade(parent, chan);
+				ast_hangup(chan);
+				p->abouttograb = 0;
+			} else {
+				ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
+				agent_cleanup(newlyavailable);
+			}
+		} else {
+			ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
+			agent_cleanup(newlyavailable);
+		}
+	}
+	return 0;
+}
+
+static int check_beep(struct agent_pvt *newlyavailable, int needlock)
+{
+	struct agent_pvt *p;
+	int res=0;
+
+	ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
+	if (needlock)
+		AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		if (p == newlyavailable) {
+			continue;
+		}
+		ast_mutex_lock(&p->lock);
+		if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
+			ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
+			ast_mutex_unlock(&p->lock);
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	if (needlock)
+		AST_LIST_UNLOCK(&agents);
+	if (p) {
+		ast_mutex_unlock(&newlyavailable->lock);
+		ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
+		res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
+		ast_debug(1, "Played beep, result '%d'\n", res);
+		if (!res) {
+			res = ast_waitstream(newlyavailable->chan, "");
+			ast_debug(1, "Waited for stream, result '%d'\n", res);
+		}
+		ast_mutex_lock(&newlyavailable->lock);
+	}
+	return res;
+}
+
+/*! \brief Part of the Asterisk PBX interface */
+static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel* requestor, const char *data, int *cause)
+{
+	struct agent_pvt *p;
+	struct ast_channel *chan = NULL;
+	const char *s;
+	ast_group_t groupmatch;
+	int groupoff;
+	int waitforagent=0;
+	int hasagent = 0;
+	struct timeval now;
+	struct ast_callid *callid = ast_read_threadstorage_callid();
+
+	s = data;
+	if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
+		groupmatch = (1 << groupoff);
+	} else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
+		groupmatch = (1 << groupoff);
+		waitforagent = 1;
+	} else 
+		groupmatch = 0;
+
+	/* Check actual logged in agents first */
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		ast_mutex_lock(&p->lock);
+		if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
+			if (p->chan) {
+				hasagent++;
+			}
+			now = ast_tvnow();
+			if (p->loginstart
+				&& (!p->lastdisc.tv_sec || ast_tvdiff_ms(now, p->lastdisc) > 0)) {
+				p->lastdisc = ast_tv(0, 0);
+				/* Agent must be registered, but not have any active call, and not be in a waiting state */
+				if (!p->owner && p->chan) {
+					/* Fixed agent */
+					chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
+				}
+				if (chan) {
+					ast_mutex_unlock(&p->lock);
+					break;
+				}
+			}
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+
+	if (!chan && waitforagent) {
+		/* No agent available -- but we're requesting to wait for one.
+		   Allocate a place holder */
+		if (hasagent) {
+			ast_debug(1, "Creating place holder for '%s'\n", s);
+			p = add_agent(data, 1);
+			if (p) {
+				p->group = groupmatch;
+				chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
+				if (!chan) {
+					AST_LIST_REMOVE(&agents, p, list);
+					agent_pvt_destroy(p);
+				}
+			}
+		} else {
+			ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
+		}
+	}
+	*cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
+	AST_LIST_UNLOCK(&agents);
+
+	if (callid) {
+		callid = ast_callid_unref(callid);
+	}
+
+	if (chan) {
+		ast_mutex_lock(&p->lock);
+		if (p->pending) {
+			ast_mutex_unlock(&p->lock);
+			return chan;
+		}
+
+		if (!p->chan) {
+			ast_debug(1, "Agent disconnected before we could connect the call\n");
+			ast_mutex_unlock(&p->lock);
+			ast_hangup(chan);
+			*cause = AST_CAUSE_UNREGISTERED;
+			return NULL;
+		}
+
+		/* we need to take control of the channel from the login app
+		 * thread */
+		p->app_sleep_cond = 0;
+		p->app_lock_flag = 1;
+		ast_queue_frame(p->chan, &ast_null_frame);
+		ast_cond_wait(&p->login_wait_cond, &p->lock);
+
+		if (!p->chan) {
+			ast_debug(1, "Agent disconnected while we were connecting the call\n");
+			ast_mutex_unlock(&p->lock);
+			ast_hangup(chan);
+			*cause = AST_CAUSE_UNREGISTERED;
+			return NULL;
+		}
+
+		ast_indicate(p->chan, AST_CONTROL_UNHOLD);
+		ast_mutex_unlock(&p->lock);
+	}
+
+	return chan;
+}
+
+static force_inline int powerof(unsigned int d)
+{
+	int x = ffs(d);
+
+	if (x)
+		return x - 1;
+
+	return 0;
+}
+
+/*!
+ * Lists agents and their status to the Manager API.
+ * It is registered on load_module() and it gets called by the manager backend.
+ * This function locks both the pvt and the channel that owns it for a while, but
+ * does not keep these locks.
+ * \param s
+ * \param m
+ * \returns 
+ * \sa action_agent_logoff(), load_module().
+ */
+static int action_agents(struct mansession *s, const struct message *m)
+{
+	const char *id = astman_get_header(m,"ActionID");
+	char idText[256] = "";
+	struct agent_pvt *p;
+	char *username = NULL;
+	char *loginChan = NULL;
+	char *talkingto = NULL;
+	char *talkingtoChan = NULL;
+	char *status = NULL;
+	struct ast_channel *bridge;
+
+	if (!ast_strlen_zero(id))
+		snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
+	astman_send_ack(s, m, "Agents will follow");
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner;
+		ast_mutex_lock(&p->lock);
+		owner = agent_lock_owner(p);
+
+		/* Status Values:
+		   AGENT_LOGGEDOFF - Agent isn't logged in
+		   AGENT_IDLE      - Agent is logged in, and waiting for call
+		   AGENT_ONCALL    - Agent is logged in, and on a call
+		   AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
+
+		username = S_OR(p->name, "None");
+
+		/* Set a default status. It 'should' get changed. */
+		status = "AGENT_UNKNOWN";
+
+		if (p->chan) {
+			loginChan = ast_strdupa(ast_channel_name(p->chan));
+			if (owner && ast_channel_internal_bridged_channel(owner)) {
+				talkingto = S_COR(ast_channel_caller(p->chan)->id.number.valid,
+					ast_channel_caller(p->chan)->id.number.str, "n/a");
+				if ((bridge = ast_bridged_channel(owner))) {
+					talkingtoChan = ast_strdupa(ast_channel_name(bridge));
+				} else {
+					talkingtoChan = "n/a";
+				}
+				status = "AGENT_ONCALL";
+			} else {
+				talkingto = "n/a";
+				talkingtoChan = "n/a";
+				status = "AGENT_IDLE";
+			}
+		} else {
+			loginChan = "n/a";
+			talkingto = "n/a";
+			talkingtoChan = "n/a";
+			status = "AGENT_LOGGEDOFF";
+		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			owner = ast_channel_unref(owner);
+		}
+
+		astman_append(s, "Event: Agents\r\n"
+			"Agent: %s\r\n"
+			"Name: %s\r\n"
+			"Status: %s\r\n"
+			"LoggedInChan: %s\r\n"
+			"LoggedInTime: %d\r\n"
+			"TalkingTo: %s\r\n"
+			"TalkingToChan: %s\r\n"
+			"%s"
+			"\r\n",
+			p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
+		ast_mutex_unlock(&p->lock);
+	}
+	AST_LIST_UNLOCK(&agents);
+	astman_append(s, "Event: AgentsComplete\r\n"
+		"%s"
+		"\r\n",idText);
+	return 0;
+}
+
+static int agent_logoff(const char *agent, int soft)
+{
+	struct agent_pvt *p;
+	int ret = -1; /* Return -1 if no agent if found */
+
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		if (!strcasecmp(p->agent, agent)) {
+			ret = 0;
+			if (p->owner || p->chan) {
+				if (!soft) {
+					struct ast_channel *owner;
+					ast_mutex_lock(&p->lock);
+					owner = agent_lock_owner(p);
+
+					if (owner) {
+						ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+						ast_channel_unlock(owner);
+						owner = ast_channel_unref(owner);
+					}
+
+					while (p->chan && ast_channel_trylock(p->chan)) {
+						DEADLOCK_AVOIDANCE(&p->lock);
+					}
+					if (p->chan) {
+						ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
+						ast_channel_unlock(p->chan);
+					}
+
+					ast_mutex_unlock(&p->lock);
+				} else
+					p->deferlogoff = 1;
+			}
+			break;
+		}
+	}
+	AST_LIST_UNLOCK(&agents);
+
+	return ret;
+}
+
+static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int ret;
+	const char *agent;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "agent logoff";
+		e->usage =
+			"Usage: agent logoff <channel> [soft]\n"
+			"       Sets an agent as no longer logged in.\n"
+			"       If 'soft' is specified, do not hangup existing calls.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
+	}
+
+	if (a->argc < 3 || a->argc > 4)
+		return CLI_SHOWUSAGE;
+	if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
+		return CLI_SHOWUSAGE;
+
+	agent = a->argv[2] + 6;
+	ret = agent_logoff(agent, a->argc == 4);
+	if (ret == 0)
+		ast_cli(a->fd, "Logging out %s\n", agent);
+
+	return CLI_SUCCESS;
+}
+
+/*!
+ * Sets an agent as no longer logged in in the Manager API.
+ * It is registered on load_module() and it gets called by the manager backend.
+ * \param s
+ * \param m
+ * \returns 
+ * \sa action_agents(), load_module().
+ */
+static int action_agent_logoff(struct mansession *s, const struct message *m)
+{
+	const char *agent = astman_get_header(m, "Agent");
+	const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
+	int soft;
+	int ret; /* return value of agent_logoff */
+
+	if (ast_strlen_zero(agent)) {
+		astman_send_error(s, m, "No agent specified");
+		return 0;
+	}
+
+	soft = ast_true(soft_s) ? 1 : 0;
+	ret = agent_logoff(agent, soft);
+	if (ret == 0)
+		astman_send_ack(s, m, "Agent logged out");
+	else
+		astman_send_error(s, m, "No such agent");
+
+	return 0;
+}
+
+static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
+{
+	char *ret = NULL;
+
+	if (pos == 2) {
+		struct agent_pvt *p;
+		char name[AST_MAX_AGENT];
+		int which = 0, len = strlen(word);
+
+		AST_LIST_LOCK(&agents);
+		AST_LIST_TRAVERSE(&agents, p, list) {
+			snprintf(name, sizeof(name), "Agent/%s", p->agent);
+			if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
+				ret = ast_strdup(name);
+				break;
+			}
+		}
+		AST_LIST_UNLOCK(&agents);
+	} else if (pos == 3 && state == 0) 
+		return ast_strdup("soft");
+	
+	return ret;
+}
+
+/*!
+ * Show agents in cli.
+ */
+static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct agent_pvt *p;
+	char username[AST_MAX_BUF];
+	char location[AST_MAX_BUF] = "";
+	char talkingto[AST_MAX_BUF] = "";
+	char music[AST_MAX_BUF];
+	int count_agents = 0;		/*!< Number of agents configured */
+	int online_agents = 0;		/*!< Number of online agents */
+	int offline_agents = 0;		/*!< Number of offline agents */
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "agent show";
+		e->usage =
+			"Usage: agent show\n"
+			"       Provides summary information on agents.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 2)
+		return CLI_SHOWUSAGE;
+
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner;
+		ast_mutex_lock(&p->lock);
+		owner = agent_lock_owner(p);
+		if (p->pending) {
+			if (p->group)
+				ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
+			else
+				ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
+		} else {
+			if (!ast_strlen_zero(p->name))
+				snprintf(username, sizeof(username), "(%s) ", p->name);
+			else
+				username[0] = '\0';
+			if (p->chan) {
+				snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
+				if (owner && ast_bridged_channel(owner)) {
+					snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
+				} else {
+					strcpy(talkingto, " is idle");
+				}
+				online_agents++;
+			} else {
+				strcpy(location, "not logged in");
+				talkingto[0] = '\0';
+				offline_agents++;
+			}
+			if (!ast_strlen_zero(p->moh))
+				snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
+			ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
+				username, location, talkingto, music);
+			count_agents++;
+		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			owner = ast_channel_unref(owner);
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	AST_LIST_UNLOCK(&agents);
+	if ( !count_agents ) 
+		ast_cli(a->fd, "No Agents are configured in %s\n",config);
+	else 
+		ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
+	ast_cli(a->fd, "\n");
+	                
+	return CLI_SUCCESS;
+}
+
+
+static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct agent_pvt *p;
+	char username[AST_MAX_BUF];
+	char location[AST_MAX_BUF] = "";
+	char talkingto[AST_MAX_BUF] = "";
+	char music[AST_MAX_BUF];
+	int count_agents = 0;           /* Number of agents configured */
+	int online_agents = 0;          /* Number of online agents */
+	int agent_status = 0;           /* 0 means offline, 1 means online */
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "agent show online";
+		e->usage =
+			"Usage: agent show online\n"
+			"       Provides a list of all online agents.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner;
+
+		agent_status = 0;       /* reset it to offline */
+		ast_mutex_lock(&p->lock);
+		owner = agent_lock_owner(p);
+
+		if (!ast_strlen_zero(p->name))
+			snprintf(username, sizeof(username), "(%s) ", p->name);
+		else
+			username[0] = '\0';
+		if (p->chan) {
+			snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
+			if (p->owner && ast_bridged_channel(p->owner)) {
+				snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
+			} else {
+				strcpy(talkingto, " is idle");
+			}
+			agent_status = 1;
+			online_agents++;
+		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			owner = ast_channel_unref(owner);
+		}
+
+		if (!ast_strlen_zero(p->moh))
+			snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
+		if (agent_status)
+			ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
+		count_agents++;
+		ast_mutex_unlock(&p->lock);
+	}
+	AST_LIST_UNLOCK(&agents);
+	if (!count_agents) 
+		ast_cli(a->fd, "No Agents are configured in %s\n", config);
+	else
+		ast_cli(a->fd, "%d agents online\n", online_agents);
+	ast_cli(a->fd, "\n");
+	return CLI_SUCCESS;
+}
+
+static const char agent_logoff_usage[] =
+"Usage: agent logoff <channel> [soft]\n"
+"       Sets an agent as no longer logged in.\n"
+"       If 'soft' is specified, do not hangup existing calls.\n";
+
+static struct ast_cli_entry cli_agents[] = {
+	AST_CLI_DEFINE(agents_show, "Show status of agents"),
+	AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
+	AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
+};
+
+/*!
+ * Called by the AgentLogin application (from the dial plan).
+ * 
+ * \brief Log in agent application.
+ *
+ * \param chan
+ * \param data
+ * \returns
+ * \sa agentmonitoroutgoing_exec(), load_module().
+ */
+static int login_exec(struct ast_channel *chan, const char *data)
+{
+	int res=0;
+	int tries = 0;
+	int max_login_tries = maxlogintries;
+	struct agent_pvt *p;
+	char user[AST_MAX_AGENT];
+	char pass[AST_MAX_AGENT];
+	char xpass[AST_MAX_AGENT];
+	char *errmsg;
+	char *parse;
+	AST_DECLARE_APP_ARGS(args,
+			     AST_APP_ARG(agent_id);
+			     AST_APP_ARG(options);
+			     AST_APP_ARG(extension);
+		);
+	const char *tmpoptions = NULL;
+	int play_announcement = 1;
+	char agent_goodbye[AST_MAX_FILENAME_LEN];
+	int update_cdr = updatecdr;
+
+	user[0] = '\0';
+	xpass[0] = '\0';
+
+	parse = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
+
+	ast_channel_lock(chan);
+	/* Set Channel Specific Login Overrides */
+	if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
+		max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
+		if (max_login_tries < 0)
+			max_login_tries = 0;
+		tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
+		ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,ast_channel_name(chan));
+	}
+	if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
+		if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
+			update_cdr = 1;
+		else
+			update_cdr = 0;
+		tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
+		ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan));
+	}
+	if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
+		strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
+		tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
+		ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan));
+	}
+	ast_channel_unlock(chan);
+	/* End Channel Specific Login Overrides */
+	
+	if (!ast_strlen_zero(args.options)) {
+		if (strchr(args.options, 's')) {
+			play_announcement = 0;
+		}
+	}
+
+	if (ast_channel_state(chan) != AST_STATE_UP)
+		res = ast_answer(chan);
+	if (!res) {
+		if (!ast_strlen_zero(args.agent_id))
+			ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
+		else
+			res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
+	}
+	while (!res && (max_login_tries==0 || tries < max_login_tries)) {
+		tries++;
+		/* Check for password */
+		AST_LIST_LOCK(&agents);
+		AST_LIST_TRAVERSE(&agents, p, list) {
+			if (!strcmp(p->agent, user) && !p->pending)
+				ast_copy_string(xpass, p->password, sizeof(xpass));
+		}
+		AST_LIST_UNLOCK(&agents);
+		if (!res) {
+			if (!ast_strlen_zero(xpass))
+				res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
+			else
+				pass[0] = '\0';
+		}
+		errmsg = "agent-incorrect";
+
+#if 0
+		ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
+#endif		
+
+		/* Check again for accuracy */
+		AST_LIST_LOCK(&agents);
+		AST_LIST_TRAVERSE(&agents, p, list) {
+			int unlock_channel = 1;
+
+			ast_channel_lock(chan);
+			ast_mutex_lock(&p->lock);
+			if (!strcmp(p->agent, user) &&
+			    !strcmp(p->password, pass) && !p->pending) {
+
+				/* Set Channel Specific Agent Overrides */
+				if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
+					if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
+						p->ackcall = 1;
+					} else {
+						p->ackcall = 0;
+					}
+					tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
+					ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
+					ast_set_flag(p, AGENT_FLAG_ACKCALL);
+				} else {
+					p->ackcall = ackcall;
+				}
+				if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
+					p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
+					if (p->autologoff < 0)
+						p->autologoff = 0;
+					tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
+					ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
+					ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
+				} else {
+					p->autologoff = autologoff;
+				}
+				if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
+					p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
+					if (p->wrapuptime < 0)
+						p->wrapuptime = 0;
+					tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
+					ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
+					ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
+				} else {
+					p->wrapuptime = wrapuptime;
+				}
+				tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
+				if (!ast_strlen_zero(tmpoptions)) {
+					p->acceptdtmf = *tmpoptions;
+					ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
+					ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
+				}
+				tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
+				if (!ast_strlen_zero(tmpoptions)) {
+					p->enddtmf = *tmpoptions;
+					ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
+					ast_set_flag(p, AGENT_FLAG_ENDDTMF);
+				}
+				ast_channel_unlock(chan);
+				unlock_channel = 0;
+				/* End Channel Specific Agent Overrides */
+
+				if (!p->chan) {
+					/* Ensure nobody else can be this agent until we're done. */
+					p->chan = chan;
+
+					p->acknowledged = 0;
+
+					if (!res) {
+						struct ast_format tmpfmt;
+						res = ast_set_read_format_from_cap(chan, ast_channel_nativeformats(chan));
+						if (res) {
+							ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
+						}
+					}
+					if (!res) {
+						struct ast_format tmpfmt;
+						res = ast_set_write_format_from_cap(chan, ast_channel_nativeformats(chan));
+						if (res) {
+							ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
+						}
+					}
+					if (!res && play_announcement == 1) {
+						ast_mutex_unlock(&p->lock);
+						AST_LIST_UNLOCK(&agents);
+						res = ast_streamfile(chan, "agent-loginok", ast_channel_language(chan));
+						if (!res) {
+							ast_waitstream(chan, "");
+						}
+						AST_LIST_LOCK(&agents);
+						ast_mutex_lock(&p->lock);
+					}
+
+					if (!res) {
+						long logintime;
+						char agent[AST_MAX_AGENT];
+
+						snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
+
+						/* Login this channel and wait for it to go away */
+						ast_indicate_data(chan, AST_CONTROL_HOLD, 
+							S_OR(p->moh, NULL), 
+							!ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
+
+						/* Must be done after starting HOLD. */
+						p->lastdisc = ast_tvnow();
+						time(&p->loginstart);
+
+						/*** DOCUMENTATION
+							<managerEventInstance>
+								<synopsis>Raised when an Agent has logged in.</synopsis>
+								<syntax>
+									<parameter name="Agent">
+										<para>The name of the agent.</para>
+									</parameter>
+								</syntax>
+								<see-also>
+									<ref type="application">AgentLogin</ref>
+									<ref type="managerEvent">Agentlogoff</ref>
+								</see-also>
+							</managerEventInstance>
+						***/
+						manager_event(EVENT_FLAG_AGENT, "Agentlogin",
+							      "Agent: %s\r\n"
+							      "Channel: %s\r\n"
+							      "Uniqueid: %s\r\n",
+							      p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan));
+						if (update_cdr && ast_channel_cdr(chan))
+							snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "%s", agent);
+						ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan));
+						ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
+								    ast_getformatname(ast_channel_readformat(chan)), ast_getformatname(ast_channel_writeformat(chan)));
+
+						ast_mutex_unlock(&p->lock);
+						AST_LIST_UNLOCK(&agents);
+
+						while (res >= 0) {
+							ast_mutex_lock(&p->lock);
+							if (p->deferlogoff) {
+								p->deferlogoff = 0;
+								ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
+								ast_mutex_unlock(&p->lock);
+								break;
+							}
+							ast_mutex_unlock(&p->lock);
+
+							AST_LIST_LOCK(&agents);
+							ast_mutex_lock(&p->lock);
+							if (p->lastdisc.tv_sec) {
+								if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
+									ast_debug(1, "Wrapup time for %s expired!\n", agent);
+									p->lastdisc = ast_tv(0, 0);
+									ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "%s", agent);
+									if (p->ackcall) {
+										check_beep(p, 0);
+									} else {
+										check_availability(p, 0);
+									}
+								}
+							}
+							ast_mutex_unlock(&p->lock);
+							AST_LIST_UNLOCK(&agents);
+
+							/* Synchronize channel ownership between call to agent and itself. */
+							ast_mutex_lock(&p->lock);
+							if (p->app_lock_flag) {
+								ast_cond_signal(&p->login_wait_cond);
+								ast_cond_wait(&p->app_complete_cond, &p->lock);
+								if (ast_check_hangup(chan)) {
+									/* Agent hungup */
+									ast_mutex_unlock(&p->lock);
+									break;
+								}
+							}
+							ast_mutex_unlock(&p->lock);
+
+							if (p->ackcall) {
+								res = agent_ack_sleep(p);
+								if (res == 1) {
+									AST_LIST_LOCK(&agents);
+									ast_mutex_lock(&p->lock);
+									check_availability(p, 0);
+									ast_mutex_unlock(&p->lock);
+									AST_LIST_UNLOCK(&agents);
+								}
+							} else {
+								res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
+							}
+						}
+						ast_mutex_lock(&p->lock);
+
+						/* Logoff this channel */
+						p->chan = NULL;
+						logintime = time(NULL) - p->loginstart;
+						p->loginstart = 0;
+
+						/* Synchronize channel ownership between call to agent and itself. */
+						if (p->app_lock_flag) {
+							ast_cond_signal(&p->login_wait_cond);
+							ast_cond_wait(&p->app_complete_cond, &p->lock);
+						}
+
+						if (p->owner) {
+							ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
+						}
+
+						p->acknowledged = 0;
+						ast_mutex_unlock(&p->lock);
+
+						ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "%s", agent);
+						/*** DOCUMENTATION
+							<managerEventInstance>
+								<synopsis>Raised when an Agent has logged off.</synopsis>
+								<syntax>
+									<xi:include xpointer="xpointer(/docs/managerEvent[@name='Agentlogin']/managerEventInstance/syntax/parameter[@name='Agent'])" />
+								</syntax>
+								<see-also>
+									<ref type="managerEvent">Agentlogin</ref>
+								</see-also>
+							</managerEventInstance>
+						***/
+						manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
+							      "Agent: %s\r\n"
+							      "Logintime: %ld\r\n"
+							      "Uniqueid: %s\r\n",
+							      p->agent, logintime, ast_channel_uniqueid(chan));
+						ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
+						ast_verb(2, "Agent '%s' logged out\n", p->agent);
+
+						/* If there is no owner, go ahead and kill it now */
+						if (p->dead && !p->owner) {
+							agent_pvt_destroy(p);
+						}
+						AST_LIST_LOCK(&agents);
+					} else {
+						/* Agent hung up before could be logged in. */
+						p->chan = NULL;
+
+						ast_mutex_unlock(&p->lock);
+					}
+					res = -1;
+				} else {
+					ast_mutex_unlock(&p->lock);
+					errmsg = "agent-alreadyon";
+				}
+				break;
+			}
+			ast_mutex_unlock(&p->lock);
+			if (unlock_channel) {
+				ast_channel_unlock(chan);
+			}
+		}
+		AST_LIST_UNLOCK(&agents);
+
+		if (!res && (max_login_tries==0 || tries < max_login_tries))
+			res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
+	}
+		
+	if (!res)
+		res = ast_safe_sleep(chan, 500);
+
+ 	return -1;
+}
+
+/*!
+ *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
+ *
+ * \param chan
+ * \param data
+ * \returns
+ * \sa login_exec(), load_module().
+ */
+static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
+{
+	int exitifnoagentid = 0;
+	int nowarnings = 0;
+	int changeoutgoing = 0;
+	int res = 0;
+	char agent[AST_MAX_AGENT];
+
+	if (data) {
+		if (strchr(data, 'd'))
+			exitifnoagentid = 1;
+		if (strchr(data, 'n'))
+			nowarnings = 1;
+		if (strchr(data, 'c'))
+			changeoutgoing = 1;
+	}
+	if (ast_channel_caller(chan)->id.number.valid
+		&& !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
+		const char *tmp;
+		char agentvar[AST_MAX_BUF];
+		snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
+			ast_channel_caller(chan)->id.number.str);
+		if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
+			struct agent_pvt *p;
+			ast_copy_string(agent, tmp, sizeof(agent));
+			AST_LIST_LOCK(&agents);
+			AST_LIST_TRAVERSE(&agents, p, list) {
+				if (!strcasecmp(p->agent, tmp)) {
+					if (changeoutgoing) snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
+					__agent_start_monitoring(chan, p, 1);
+					break;
+				}
+			}
+			AST_LIST_UNLOCK(&agents);
+			
+		} else {
+			res = -1;
+			if (!nowarnings)
+				ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar);
+		}
+	} else {
+		res = -1;
+		if (!nowarnings)
+			ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n");
+	}
+	if (res) {
+		if (exitifnoagentid)
+			return res;
+	}
+	return 0;
+}
+
+/*! \brief Part of PBX channel interface */
+static int agent_devicestate(const char *data)
+{
+	struct agent_pvt *p;
+	const char *device = data;
+	int res = AST_DEVICE_INVALID;
+
+	if (device[0] == '@' || device[0] == ':') {
+		/* Device state of groups not supported. */
+		return AST_DEVICE_INVALID;
+	}
+
+	/* Want device state of a specific agent. */
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		ast_mutex_lock(&p->lock);
+		if (!p->pending && !strcmp(device, p->agent)) {
+			if (p->owner) {
+				res = AST_DEVICE_BUSY;
+			} else if (p->chan) {
+				if (p->lastdisc.tv_sec || p->deferlogoff) {
+					/* Agent is in wrapup time so unavailable for another call. */
+					res = AST_DEVICE_INUSE;
+				} else {
+					res = AST_DEVICE_NOT_INUSE;
+				}
+			} else {
+				res = AST_DEVICE_UNAVAILABLE;
+			}
+			ast_mutex_unlock(&p->lock);
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	AST_LIST_UNLOCK(&agents);
+	return res;
+}
+
+/*!
+ * \note This function expects the agent list to be locked
+ */
+static struct agent_pvt *find_agent(char *agentid)
+{
+	struct agent_pvt *cur;
+
+	AST_LIST_TRAVERSE(&agents, cur, list) {
+		if (!strcmp(cur->agent, agentid))
+			break;	
+	}
+
+	return cur;	
+}
+
+static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	char *parse;    
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(agentid);
+		AST_APP_ARG(item);
+	);
+	char *tmp;
+	struct agent_pvt *agent;
+
+	buf[0] = '\0';
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+
+	AST_NONSTANDARD_APP_ARGS(args, parse, ':');
+	if (!args.item)
+		args.item = "status";
+
+	AST_LIST_LOCK(&agents);
+
+	if (!(agent = find_agent(args.agentid))) {
+		AST_LIST_UNLOCK(&agents);
+		ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
+		return -1;
+	}
+
+	if (!strcasecmp(args.item, "status")) {
+		char *status = "LOGGEDOUT";
+		if (agent->chan) {
+			status = "LOGGEDIN";
+		}
+		ast_copy_string(buf, status, len);
+	} else if (!strcasecmp(args.item, "password")) 
+		ast_copy_string(buf, agent->password, len);
+	else if (!strcasecmp(args.item, "name"))
+		ast_copy_string(buf, agent->name, len);
+	else if (!strcasecmp(args.item, "mohclass"))
+		ast_copy_string(buf, agent->moh, len);
+	else if (!strcasecmp(args.item, "channel")) {
+		if (agent->chan) {
+			ast_channel_lock(agent->chan);
+			ast_copy_string(buf, ast_channel_name(agent->chan), len);
+			ast_channel_unlock(agent->chan);
+			tmp = strrchr(buf, '-');
+			if (tmp)
+				*tmp = '\0';
+		} 
+	} else if (!strcasecmp(args.item, "fullchannel")) {
+		if (agent->chan) {
+			ast_channel_lock(agent->chan);
+			ast_copy_string(buf, ast_channel_name(agent->chan), len);
+			ast_channel_unlock(agent->chan);
+		} 
+	} else if (!strcasecmp(args.item, "exten")) {
+		buf[0] = '\0';
+	}
+
+	AST_LIST_UNLOCK(&agents);
+
+	return 0;
+}
+
+static struct ast_custom_function agent_function = {
+	.name = "AGENT",
+	.read = function_agent,
+};
+
+/*!
+ * \internal
+ * \brief Callback used to generate the agents tree.
+ * \param[in] search The search pattern tree.
+ * \retval NULL on error.
+ * \retval non-NULL The generated tree.
+ */
+static int agents_data_provider_get(const struct ast_data_search *search,
+	struct ast_data *data_root)
+{
+	struct agent_pvt *p;
+	struct ast_data *data_agent, *data_channel, *data_talkingto;
+
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		struct ast_channel *owner;
+
+		data_agent = ast_data_add_node(data_root, "agent");
+		if (!data_agent) {
+			continue;
+		}
+
+		ast_mutex_lock(&p->lock);
+		owner = agent_lock_owner(p);
+
+		if (!(p->pending)) {
+			ast_data_add_str(data_agent, "id", p->agent);
+			ast_data_add_structure(agent_pvt, data_agent, p);
+
+			ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
+			if (p->chan) {
+				data_channel = ast_data_add_node(data_agent, "loggedon");
+				if (!data_channel) {
+					ast_mutex_unlock(&p->lock);
+					ast_data_remove_node(data_root, data_agent);
+					if (owner) {
+						ast_channel_unlock(owner);
+						owner = ast_channel_unref(owner);
+					}
+					continue;
+				}
+				ast_channel_data_add_structure(data_channel, p->chan, 0);
+				if (owner && ast_bridged_channel(owner)) {
+					data_talkingto = ast_data_add_node(data_agent, "talkingto");
+					if (!data_talkingto) {
+						ast_mutex_unlock(&p->lock);
+						ast_data_remove_node(data_root, data_agent);
+						if (owner) {
+							ast_channel_unlock(owner);
+							owner = ast_channel_unref(owner);
+						}
+						continue;
+					}
+					ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
+				}
+			} else {
+				ast_data_add_node(data_agent, "talkingto");
+				ast_data_add_node(data_agent, "loggedon");
+			}
+			ast_data_add_str(data_agent, "musiconhold", p->moh);
+		}
+
+		if (owner) {
+			ast_channel_unlock(owner);
+			owner = ast_channel_unref(owner);
+		}
+
+		ast_mutex_unlock(&p->lock);
+
+		/* if this agent doesn't match remove the added agent. */
+		if (!ast_data_search_match(search, data_agent)) {
+			ast_data_remove_node(data_root, data_agent);
+		}
+	}
+	AST_LIST_UNLOCK(&agents);
+
+	return 0;
+}
+
+static const struct ast_data_handler agents_data_provider = {
+	.version = AST_DATA_HANDLER_VERSION,
+	.get = agents_data_provider_get
+};
+
+static const struct ast_data_entry agents_data_providers[] = {
+	AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
+};
+
+/*!
+ * \brief Initialize the Agents module.
+ * This function is being called by Asterisk when loading the module. 
+ * Among other things it registers applications, cli commands and reads the cofiguration file.
+ *
+ * \returns int Always 0.
+ */
+static int load_module(void)
+{
+	if (!(agent_tech.capabilities = ast_format_cap_alloc())) {
+		ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_format_cap_add_all(agent_tech.capabilities);
+	/* Make sure we can register our agent channel type */
+	if (ast_channel_register(&agent_tech)) {
+		agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
+		ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	/* Read in the config */
+	if (!read_agent_config(0)) {
+		agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	/* Dialplan applications */
+	ast_register_application_xml(app, login_exec);
+	ast_register_application_xml(app3, agentmonitoroutgoing_exec);
+
+	/* data tree */
+	ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
+
+	/* Manager commands */
+	ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
+	ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
+
+	/* CLI Commands */
+	ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
+
+	/* Dialplan Functions */
+	ast_custom_function_register(&agent_function);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void)
+{
+	return read_agent_config(1);
+}
+
+static int unload_module(void)
+{
+	struct agent_pvt *p;
+	/* First, take us out of the channel loop */
+	ast_channel_unregister(&agent_tech);
+	/* Unregister dialplan functions */
+	ast_custom_function_unregister(&agent_function);	
+	/* Unregister CLI commands */
+	ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
+	/* Unregister dialplan applications */
+	ast_unregister_application(app);
+	ast_unregister_application(app3);
+	/* Unregister manager command */
+	ast_manager_unregister("Agents");
+	ast_manager_unregister("AgentLogoff");
+	/* Unregister the data tree */
+	ast_data_unregister(NULL);
+	/* Unregister channel */
+	AST_LIST_LOCK(&agents);
+	/* Hangup all interfaces if they have an owner */
+	while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
+		if (p->owner)
+			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+		ast_free(p);
+	}
+	AST_LIST_UNLOCK(&agents);
+
+	agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+		.nonoptreq = "res_monitor,chan_local",
+	       );
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index acb5e19..f6bffcc 100644
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -21,17 +21,12 @@
  *
  * \author Matthew Fredrickson <creslin at digium.com>
  *
+ * \par See also
+ * \arg Config_alsa
+ *
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_alsa.c uses the configuration file \ref alsa.conf
- * \addtogroup configuration_file
- */
-
-/*! \page alsa.conf alsa.conf
- * \verbinclude alsa.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>alsa</depend>
 	<support_level>extended</support_level>
@@ -39,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <fcntl.h>
 #include <sys/ioctl.h>
@@ -62,8 +57,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/abstract_jb.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/poll-compat.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
 
 /*! Global jitterbuffer configuration - by default, jb is disabled
  *  \note Values shown here match the defaults shown in alsa.conf.sample */
@@ -142,7 +135,7 @@ static int autoanswer = 1;
 static int mute = 0;
 static int noaudiocapture = 0;
 
-static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
 static int alsa_text(struct ast_channel *c, const char *text);
 static int alsa_hangup(struct ast_channel *c);
@@ -512,7 +505,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan)
 		}
 
 		f.frametype = AST_FRAME_VOICE;
-		f.subclass.format = ast_format_slin;
+		ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
 		f.samples = FRAME_SIZE;
 		f.datalen = FRAME_SIZE * 2;
 		f.data.ptr = buf;
@@ -575,20 +568,18 @@ static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, s
 	return res;
 }
 
-static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const char *linkedid)
 {
 	struct ast_channel *tmp = NULL;
 
-	if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, assignedids, requestor, 0, "ALSA/%s", indevname)))
+	if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, linkedid, 0, "ALSA/%s", indevname)))
 		return NULL;
 
-	ast_channel_stage_snapshot(tmp);
-
 	ast_channel_tech_set(tmp, &alsa_tech);
 	ast_channel_set_fd(tmp, 0, readdev);
-	ast_channel_set_readformat(tmp, ast_format_slin);
-	ast_channel_set_writeformat(tmp, ast_format_slin);
-	ast_channel_nativeformats_set(tmp, alsa_tech.capabilities);
+	ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
+	ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
+	ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
 
 	ast_channel_tech_pvt_set(tmp, p);
 	if (!ast_strlen_zero(p->context))
@@ -600,10 +591,6 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const st
 	p->owner = tmp;
 	ast_module_ref(ast_module_info->self);
 	ast_jb_configure(tmp, &global_jbconf);
-
-	ast_channel_stage_snapshot_done(tmp);
-	ast_channel_unlock(tmp);
-
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(tmp)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
@@ -615,13 +602,16 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const st
 	return tmp;
 }
 
-static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
+	struct ast_format tmpfmt;
+	char buf[256];
 	struct ast_channel *tmp = NULL;
 
-	if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
+	ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);
+
+	if (!(ast_format_cap_iscompatible(cap, &tmpfmt))) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
 		return NULL;
 	}
 
@@ -630,7 +620,7 @@ static struct ast_channel *alsa_request(const char *type, struct ast_format_cap
 	if (alsa.owner) {
 		ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
 		*cause = AST_CAUSE_BUSY;
-	} else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN, assignedids, requestor))) {
+	} else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL))) {
 		ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
 	}
 
@@ -879,7 +869,7 @@ static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 			ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
 			ast_copy_string(alsa.context, myc, sizeof(alsa.context));
 			hookstate = 1;
-			alsa_new(&alsa, AST_STATE_RINGING, NULL, NULL);
+			alsa_new(&alsa, AST_STATE_RINGING, NULL);
 		} else
 			ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
 	}
@@ -942,26 +932,17 @@ static struct ast_cli_entry cli_alsa[] = {
 	AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
 };
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
 	struct ast_flags config_flags = { 0 };
+	struct ast_format tmpfmt;
 
-	if (!(alsa_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(alsa_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(alsa_tech.capabilities, ast_format_slin, 0);
+	ast_format_cap_add(alsa_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
@@ -1039,14 +1020,11 @@ static int unload_module(void)
 	if (alsa.owner)
 		return -1;
 
-	ao2_cleanup(alsa_tech.capabilities);
-	alsa_tech.capabilities = NULL;
-
+	alsa_tech.capabilities = ast_format_cap_destroy(alsa_tech.capabilities);
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
diff --git a/channels/chan_bridge.c b/channels/chan_bridge.c
new file mode 100644
index 0000000..8eac76a
--- /dev/null
+++ b/channels/chan_bridge.c
@@ -0,0 +1,235 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2008, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Joshua Colp <jcolp at digium.com>
+ *
+ * \brief Bridge Interaction Channel
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <fcntl.h>
+#include <sys/signal.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/bridging.h"
+#include "asterisk/astobj2.h"
+
+static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int bridge_call(struct ast_channel *ast, const char *dest, int timeout);
+static int bridge_hangup(struct ast_channel *ast);
+static struct ast_frame *bridge_read(struct ast_channel *ast);
+static int bridge_write(struct ast_channel *ast, struct ast_frame *f);
+static struct ast_channel *bridge_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
+
+static struct ast_channel_tech bridge_tech = {
+	.type = "Bridge",
+	.description = "Bridge Interaction Channel",
+	.requester = bridge_request,
+	.call = bridge_call,
+	.hangup = bridge_hangup,
+	.read = bridge_read,
+	.write = bridge_write,
+	.write_video = bridge_write,
+	.exception = bridge_read,
+	.bridged_channel = bridge_bridgedchannel,
+};
+
+struct bridge_pvt {
+	struct ast_channel *input;  /*!< Input channel - talking to source */
+	struct ast_channel *output; /*!< Output channel - talking to bridge */
+};
+
+/*! \brief Called when the user of this channel wants to get the actual channel in the bridge */
+static struct ast_channel *bridge_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
+{
+	struct bridge_pvt *p = ast_channel_tech_pvt(chan);
+	return (chan == p->input) ? p->output : bridge;
+}
+
+/*! \brief Called when a frame should be read from the channel */
+static struct ast_frame  *bridge_read(struct ast_channel *ast)
+{
+	return &ast_null_frame;
+}
+
+/*! \brief Called when a frame should be written out to a channel */
+static int bridge_write(struct ast_channel *ast, struct ast_frame *f)
+{
+	struct bridge_pvt *p = ast_channel_tech_pvt(ast);
+	struct ast_channel *other = NULL;
+
+	ao2_lock(p);
+	/* only write frames to output. */
+	if (p->input == ast) {
+		other = p->output;
+		if (other) {
+			ast_channel_ref(other);
+		}
+	}
+	ao2_unlock(p);
+
+	if (other) {
+		ast_channel_unlock(ast);
+		ast_queue_frame(other, f);
+		ast_channel_lock(ast);
+		other = ast_channel_unref(other);
+	}
+
+	return 0;
+}
+
+/*! \brief Called when the channel should actually be dialed */
+static int bridge_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct bridge_pvt *p = ast_channel_tech_pvt(ast);
+
+	/* If no bridge has been provided on the input channel, bail out */
+	if (!ast_channel_internal_bridge(ast)) {
+		return -1;
+	}
+
+	/* Impart the output channel upon the given bridge of the input channel */
+	return ast_bridge_impart(ast_channel_internal_bridge(p->input), p->output, NULL, NULL, 0)
+		? -1 : 0;
+}
+
+/*! \brief Called when a channel should be hung up */
+static int bridge_hangup(struct ast_channel *ast)
+{
+	struct bridge_pvt *p = ast_channel_tech_pvt(ast);
+
+	if (!p) {
+		return 0;
+	}
+
+	ao2_lock(p);
+	if (p->input == ast) {
+		p->input = NULL;
+	} else if (p->output == ast) {
+		p->output = NULL;
+	}
+	ao2_unlock(p);
+
+	ast_channel_tech_pvt_set(ast, NULL);
+	ao2_ref(p, -1);
+
+	return 0;
+}
+
+/*! \brief Called when we want to place a call somewhere, but not actually call it... yet */
+static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct bridge_pvt *p = NULL;
+	struct ast_format slin;
+
+	/* Try to allocate memory for our very minimal pvt structure */
+	if (!(p = ao2_alloc(sizeof(*p), NULL))) {
+		return NULL;
+	}
+
+	/* Try to grab two Asterisk channels to use as input and output channels */
+	if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? ast_channel_linkedid(requestor) : NULL, 0, "Bridge/%p-input", p))) {
+		ao2_ref(p, -1);
+		return NULL;
+	}
+	if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? ast_channel_linkedid(requestor) : NULL, 0, "Bridge/%p-output", p))) {
+		p->input = ast_channel_release(p->input);
+		ao2_ref(p, -1);
+		return NULL;
+	}
+
+	/* Setup parameters on both new channels */
+	ast_channel_tech_set(p->input, &bridge_tech);
+	ast_channel_tech_set(p->output, &bridge_tech);
+
+	ao2_ref(p, 2);
+	ast_channel_tech_pvt_set(p->input, p);
+	ast_channel_tech_pvt_set(p->output, p);
+
+	ast_format_set(&slin, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_cap_add(ast_channel_nativeformats(p->input), &slin);
+	ast_format_cap_add(ast_channel_nativeformats(p->output), &slin);
+	ast_format_copy(ast_channel_readformat(p->input), &slin);
+	ast_format_copy(ast_channel_readformat(p->output), &slin);
+	ast_format_copy(ast_channel_rawreadformat(p->input), &slin);
+	ast_format_copy(ast_channel_rawreadformat(p->output), &slin);
+	ast_format_copy(ast_channel_writeformat(p->input), &slin);
+	ast_format_copy(ast_channel_writeformat(p->output), &slin);
+	ast_format_copy(ast_channel_rawwriteformat(p->input), &slin);
+	ast_format_copy(ast_channel_rawwriteformat(p->output), &slin);
+
+	ast_answer(p->output);
+	ast_answer(p->input);
+
+	/* remove the reference from the alloc. The channels now own the pvt. */
+	ao2_ref(p, -1);
+	return p->input;
+}
+
+/*! \brief Load module into PBX, register channel */
+static int load_module(void)
+{
+	if (!(bridge_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
+	ast_format_cap_add_all(bridge_tech.capabilities);
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&bridge_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class 'Bridge'\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+/*! \brief Unload the bridge interaction channel from Asterisk */
+static int unload_module(void)
+{
+	ast_channel_unregister(&bridge_tech);
+	bridge_tech.capabilities = ast_format_cap_destroy(bridge_tech.capabilities);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bridge Interaction Channel",
+	.load = load_module,
+	.unload = unload_module,
+	.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+);
diff --git a/channels/chan_bridge_media.c b/channels/chan_bridge_media.c
deleted file mode 100644
index 13d096e..0000000
--- a/channels/chan_bridge_media.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Bridge Media Channels driver
- *
- * \author Jonathan Rose <jrose at digium.com>
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * \brief Bridge Media Channels
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/module.h"
-
-static int media_call(struct ast_channel *chan, const char *addr, int timeout)
-{
-	/* ast_call() will fail unconditionally against channels provided by this driver */
-	return -1;
-}
-
-static int media_hangup(struct ast_channel *ast)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* Give the pvt a ref to fulfill calling requirements. */
-	ao2_ref(p, +1);
-	res = ast_unreal_hangup(p, ast);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
-
-static struct ast_channel *record_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
-
-static struct ast_channel_tech announce_tech = {
-	.type = "Announcer",
-	.description = "Bridge Media Announcing Channel Driver",
-	.requester = announce_request,
-	.call = media_call,
-	.hangup = media_hangup,
-
-	.send_digit_begin = ast_unreal_digit_begin,
-	.send_digit_end = ast_unreal_digit_end,
-	.read = ast_unreal_read,
-	.write = ast_unreal_write,
-	.write_video = ast_unreal_write,
-	.exception = ast_unreal_read,
-	.indicate = ast_unreal_indicate,
-	.fixup = ast_unreal_fixup,
-	.send_html = ast_unreal_sendhtml,
-	.send_text = ast_unreal_sendtext,
-	.queryoption = ast_unreal_queryoption,
-	.setoption = ast_unreal_setoption,
-	.properties = AST_CHAN_TP_INTERNAL,
-};
-
-static struct ast_channel_tech record_tech = {
-	.type = "Recorder",
-	.description = "Bridge Media Recording Channel Driver",
-	.requester = record_request,
-	.call = media_call,
-	.hangup = media_hangup,
-
-	.send_digit_begin = ast_unreal_digit_begin,
-	.send_digit_end = ast_unreal_digit_end,
-	.read = ast_unreal_read,
-	.write = ast_unreal_write,
-	.write_video = ast_unreal_write,
-	.exception = ast_unreal_read,
-	.indicate = ast_unreal_indicate,
-	.fixup = ast_unreal_fixup,
-	.send_html = ast_unreal_sendhtml,
-	.send_text = ast_unreal_sendtext,
-	.queryoption = ast_unreal_queryoption,
-	.setoption = ast_unreal_setoption,
-	.properties = AST_CHAN_TP_INTERNAL,
-};
-
-static struct ast_channel *media_request_helper(struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids,
-	const struct ast_channel *requestor, const char *data, struct ast_channel_tech *tech, const char *role)
-{
-	struct ast_channel *chan;
-
-	RAII_VAR(struct ast_callid *, callid, NULL, ast_callid_cleanup);
-	RAII_VAR(struct ast_unreal_pvt *, pvt, NULL, ao2_cleanup);
-
-	if (!(pvt = ast_unreal_alloc(sizeof(*pvt), ast_unreal_destructor, cap))) {
-		return NULL;
-	}
-
-	ast_copy_string(pvt->name, data, sizeof(pvt->name));
-
-	ast_set_flag(pvt, AST_UNREAL_NO_OPTIMIZATION);
-
-	callid = ast_read_threadstorage_callid();
-
-	chan = ast_unreal_new_channels(pvt, tech,
-		AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, callid);
-	if (!chan) {
-		return NULL;
-	}
-
-	ast_answer(pvt->owner);
-	ast_answer(pvt->chan);
-
-	if (ast_channel_add_bridge_role(pvt->chan, role)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	return chan;
-}
-
-static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	return media_request_helper(cap, assignedids, requestor, data, &announce_tech, "announcer");
-}
-
-static struct ast_channel *record_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	return media_request_helper(cap, assignedids, requestor, data, &record_tech, "recorder");
-}
-
-static void cleanup_capabilities(void)
-{
-	if (announce_tech.capabilities) {
-		ao2_ref(announce_tech.capabilities, -1);
-		announce_tech.capabilities = NULL;
-	}
-
-	if (record_tech.capabilities) {
-		ao2_ref(record_tech.capabilities, -1);
-		record_tech.capabilities = NULL;
-	}
-}
-
-static int unload_module(void)
-{
-	ast_channel_unregister(&announce_tech);
-	ast_channel_unregister(&record_tech);
-	cleanup_capabilities();
-	return 0;
-}
-
-static int load_module(void)
-{
-	announce_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!announce_tech.capabilities) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	record_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!record_tech.capabilities) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_format_cap_append_by_type(announce_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
-	ast_format_cap_append_by_type(record_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
-
-	if (ast_channel_register(&announce_tech)) {
-		ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n",
-			announce_tech.type, announce_tech.description);
-		cleanup_capabilities();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_channel_register(&record_tech)) {
-		ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n",
-			record_tech.type, record_tech.description);
-		cleanup_capabilities();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bridge Media Channel Driver",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-    .load = load_module,
-    .unload = unload_module,
-);
diff --git a/channels/chan_console.c b/channels/chan_console.c
index 84c30f9..0d3c12b 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -29,7 +29,7 @@
  * 
  * \ingroup channel_drivers
  *
- * Portaudio http://www.portaudio.com/
+ * \extref Portaudio http://www.portaudio.com/
  *
  * To install portaudio v19 from svn, check it out using the following command:
  *  - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel
@@ -47,14 +47,6 @@
  * - console_video support
  */
 
-/*! \li \ref chan_console.c uses the configuration file \ref console.conf
- * \addtogroup configuration_file
- */
-
-/*! \page console.conf console.conf
- * \verbinclude console.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>portaudio</depend>
 	<support_level>extended</support_level>
@@ -62,7 +54,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427557 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/signal.h>  /* SIGURG */
 
@@ -76,8 +68,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427557 $")
 #include "asterisk/musiconhold.h"
 #include "asterisk/callerid.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
 
 /*! 
  * \brief The sample rate to request from PortAudio 
@@ -196,7 +186,7 @@ static struct ast_jb_conf global_jbconf;
 
 /*! Channel Technology Callbacks @{ */
 static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+	const struct ast_channel *requestor, const char *data, int *cause);
 static int console_digit_begin(struct ast_channel *c, char digit);
 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int console_text(struct ast_channel *c, const char *text);
@@ -271,12 +261,12 @@ static void *stream_monitor(void *data)
 	PaError res;
 	struct ast_frame f = {
 		.frametype = AST_FRAME_VOICE,
-		.subclass.format = ast_format_slin16,
 		.src = "console_stream_monitor",
 		.data.ptr = buf,
 		.datalen = sizeof(buf),
 		.samples = sizeof(buf) / sizeof(int16_t),
 	};
+	ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR16, 0);
 
 	for (;;) {
 		pthread_testcancel();
@@ -420,30 +410,19 @@ static int stop_stream(struct console_pvt *pvt)
 /*!
  * \note Called with the pvt struct locked
  */
-static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const char *linkedid)
 {
-	struct ast_format_cap *caps;
 	struct ast_channel *chan;
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return NULL;
-	}
-
 	if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, 
-		ext, ctx, assignedids, requestor, 0, "Console/%s", pvt->name))) {
-		ao2_ref(caps, -1);
+		ext, ctx, linkedid, 0, "Console/%s", pvt->name))) {
 		return NULL;
 	}
 
-	ast_channel_stage_snapshot(chan);
-
 	ast_channel_tech_set(chan, &console_tech);
-	ast_channel_set_readformat(chan, ast_format_slin16);
-	ast_channel_set_writeformat(chan, ast_format_slin16);
-	ast_format_cap_append(caps, ast_format_slin16, 0);
-	ast_channel_nativeformats_set(chan, caps);
-	ao2_ref(caps, -1);
+	ast_format_set(ast_channel_readformat(chan), AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(ast_channel_writeformat(chan), AST_FORMAT_SLINEAR16, 0);
+	ast_format_cap_add(ast_channel_nativeformats(chan), ast_channel_readformat(chan));
 	ast_channel_tech_pvt_set(chan, ref_pvt(pvt));
 
 	pvt->owner = chan;
@@ -453,9 +432,6 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext,
 
 	ast_jb_configure(chan, &global_jbconf);
 
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
-
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(chan)) {
 			ast_channel_hangupcause_set(chan, AST_CAUSE_SWITCH_CONGESTION);
@@ -468,20 +444,19 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext,
 	return chan;
 }
 
-static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	struct ast_channel *chan = NULL;
 	struct console_pvt *pvt;
+	char buf[512];
 
 	if (!(pvt = find_pvt(data))) {
 		ast_log(LOG_ERROR, "Console device '%s' not found\n", data);
 		return NULL;
 	}
 
-	if (!(ast_format_cap_iscompatible(cap, console_tech.capabilities))) {
-		struct ast_str *cap_buf = ast_str_alloca(64);
-		ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n",
-			ast_format_cap_get_names(cap, &cap_buf));
+	if (!(ast_format_cap_has_joint(cap, console_tech.capabilities))) {
+		ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
 		goto return_unref;
 	}
 
@@ -492,7 +467,7 @@ static struct ast_channel *console_request(const char *type, struct ast_format_c
 	}
 
 	console_pvt_lock(pvt);
-	chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, assignedids, requestor);
+	chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
 	console_pvt_unlock(pvt);
 
 	if (!chan)
@@ -862,7 +837,7 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
 		console_pvt_lock(pvt);
 		pvt->hookstate = 1;
-		console_new(pvt, mye, myc, AST_STATE_RINGING, NULL, NULL);
+		console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
 		console_pvt_unlock(pvt);
 	} else
 		ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
@@ -1494,8 +1469,7 @@ static void stop_streams(void)
 
 static int unload_module(void)
 {
-	ao2_ref(console_tech.capabilities, -1);
-	console_tech.capabilities = NULL;
+	console_tech.capabilities = ast_format_cap_destroy(console_tech.capabilities);
 	ast_channel_unregister(&console_tech);
 	ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
 
@@ -1511,24 +1485,15 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
+	struct ast_format tmpfmt;
 	PaError res;
 
-	if (!(console_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(console_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(console_tech.capabilities, ast_format_slin16, 0);
+	ast_format_cap_add(console_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0));
 
 	init_pvt(&globals, NULL);
 
@@ -1565,8 +1530,6 @@ return_error:
 	if (pvts)
 		ao2_ref(pvts, -1);
 	pvts = NULL;
-	ao2_ref(console_tech.capabilities, -1);
-	console_tech.capabilities = NULL;
 	pvt_destructor(&globals);
 
 	return AST_MODULE_LOAD_DECLINE;
@@ -1578,7 +1541,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 74387a5..2dbeeaa 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -29,19 +29,14 @@
  * You need to install libraries before you attempt to compile
  * and install the DAHDI channel.
  *
+ * \par See also
+ * \arg \ref Config_dahdi
+ *
  * \ingroup channel_drivers
  *
  * \todo Deprecate the "musiconhold" configuration option post 1.4
  */
 
-/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
- * \addtogroup configuration_file
- */
-
-/*! \page chan_dahdi.conf chan_dahdi.conf
- * \verbinclude chan_dahdi.conf.sample
- */
-
 /*** MODULEINFO
 	<use type="module">res_smdi</use>
 	<depend>dahdi</depend>
@@ -54,7 +49,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #if defined(__NetBSD__) || defined(__FreeBSD__)
 #include <pthread.h>
@@ -62,9 +57,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #else
 #include <sys/signal.h>
 #endif
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <math.h>
+#include <ctype.h>
 
+#include <dahdi/user.h>
+#include <dahdi/tonezone.h>
 #include "sig_analog.h"
 /* Analog signaling is currently still present in chan_dahdi for use with
  * radio. Sig_analog does not currently handle any radio operations. If
@@ -81,17 +80,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 
 #if defined(HAVE_SS7)
 #include "sig_ss7.h"
-#if !defined(LIBSS7_ABI_COMPATIBILITY)
-#error "Upgrade your libss7"
-#elif LIBSS7_ABI_COMPATIBILITY != 2
+#if defined(LIBSS7_ABI_COMPATIBILITY)
 #error "Your installed libss7 is not compatible"
 #endif
 #endif	/* defined(HAVE_SS7) */
 
-#if defined(HAVE_OPENR2)
+#ifdef HAVE_OPENR2
 /* put this here until sig_mfcr2 comes along */
 #define SIG_MFCR2_MAX_CHANNELS	672		/*!< No more than a DS3 per trunk group */
-#endif	/* defined(HAVE_OPENR2) */
+#include <openr2.h>
+#endif
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
@@ -104,7 +102,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/callerid.h"
 #include "asterisk/adsi.h"
 #include "asterisk/cli.h"
-#include "asterisk/pickup.h"
+#include "asterisk/cdr.h"
+#include "asterisk/cel.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"
@@ -120,17 +119,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/stringfields.h"
 #include "asterisk/abstract_jb.h"
 #include "asterisk/smdi.h"
+#include "asterisk/astobj.h"
+#include "asterisk/event.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/paths.h"
 #include "asterisk/ccss.h"
 #include "asterisk/data.h"
-#include "asterisk/features_config.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/parking.h"
-#include "asterisk/format_cache.h"
-#include "chan_dahdi.h"
-#include "dahdi/bridge_native_dahdi.h"
 
 /*** DOCUMENTATION
 	<application name="DAHDISendKeypadFacility" language="en_US">
@@ -296,130 +290,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 			<para>Similar to the CLI command "pri show spans".</para>
 		</description>
 	</manager>
-	<manager name="PRIDebugSet" language="en_US">
-		<synopsis>
-			Set PRI debug levels for a span
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Span" required="true">
-				<para>Which span to affect.</para>
-			</parameter>
-			<parameter name="Level" required="true">
-				<para>What debug level to set. May be a numerical value or a text value from the list below</para>
-				<enumlist>
-					<enum name="off" />
-					<enum name="on" />
-					<enum name="hex" />
-					<enum name="intense" />
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Equivalent to the CLI command "pri set debug <level> span <span>".</para>
-		</description>
-	</manager>
-	<manager name="PRIDebugFileSet" language="en_US">
-		<synopsis>
-			Set the file used for PRI debug message output
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="File" required="true">
-				<para>Path of file to write debug output.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Equivalent to the CLI command "pri set debug file <output-file>"</para>
-		</description>
-	</manager>
-	<manager name="PRIDebugFileUnset" language="en_US">
-		<synopsis>
-			Disables file output for PRI debug messages
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-	</manager>
-	<managerEvent language="en_US" name="AlarmClear">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
-			<syntax>
-				<parameter name="DAHDIChannel">
-					<para>The DAHDI channel on which the alarm was cleared.</para>
-					<note><para>This is not an Asterisk channel identifier.</para></note>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SpanAlarmClear">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
-			<syntax>
-				<parameter name="Span">
-					<para>The span on which the alarm was cleared.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="DNDState">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
-			<syntax>
-				<parameter name="DAHDIChannel">
-					<para>The DAHDI channel on which DND status changed.</para>
-					<note><para>This is not an Asterisk channel identifier.</para></note>
-				</parameter>
-				<parameter name="Status">
-					<enumlist>
-						<enum name="enabled"/>
-						<enum name="disabled"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Alarm">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
-			<syntax>
-				<parameter name="DAHDIChannel">
-					<para>The channel on which the alarm occurred.</para>
-					<note><para>This is not an Asterisk channel identifier.</para></note>
-				</parameter>
-				<parameter name="Alarm">
-					<para>A textual description of the alarm that occurred.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SpanAlarm">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
-			<syntax>
-				<parameter name="Span">
-					<para>The span on which the alarm occurred.</para>
-				</parameter>
-				<parameter name="Alarm">
-					<para>A textual description of the alarm that occurred.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="DAHDIChannel">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="DAHDISpan">
-					<para>The DAHDI span associated with this channel.</para>
-				</parameter>
-				<parameter name="DAHDIChannel">
-					<para>The DAHDI channel associated with this channel.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -461,13 +331,13 @@ static struct ast_jb_conf global_jbconf;
 /*! \brief Typically, how many rings before we should send Caller*ID */
 #define DEFAULT_CIDRINGS 1
 
-#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
+#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
 
 
 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
 #define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
 
-static const char tdesc[] = "DAHDI Telephony"
+static const char tdesc[] = "DAHDI Telephony Driver"
 #if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
 	" w/"
 	#if defined(HAVE_PRI)
@@ -490,6 +360,33 @@ static const char tdesc[] = "DAHDI Telephony"
 
 static const char config[] = "chan_dahdi.conf";
 
+#define SIG_EM		DAHDI_SIG_EM
+#define SIG_EMWINK 	(0x0100000 | DAHDI_SIG_EM)
+#define SIG_FEATD	(0x0200000 | DAHDI_SIG_EM)
+#define	SIG_FEATDMF	(0x0400000 | DAHDI_SIG_EM)
+#define	SIG_FEATB	(0x0800000 | DAHDI_SIG_EM)
+#define	SIG_E911	(0x1000000 | DAHDI_SIG_EM)
+#define	SIG_FEATDMF_TA	(0x2000000 | DAHDI_SIG_EM)
+#define	SIG_FGC_CAMA	(0x4000000 | DAHDI_SIG_EM)
+#define	SIG_FGC_CAMAMF	(0x8000000 | DAHDI_SIG_EM)
+#define SIG_FXSLS	DAHDI_SIG_FXSLS
+#define SIG_FXSGS	DAHDI_SIG_FXSGS
+#define SIG_FXSKS	DAHDI_SIG_FXSKS
+#define SIG_FXOLS	DAHDI_SIG_FXOLS
+#define SIG_FXOGS	DAHDI_SIG_FXOGS
+#define SIG_FXOKS	DAHDI_SIG_FXOKS
+#define SIG_PRI		DAHDI_SIG_CLEAR
+#define SIG_BRI		(0x2000000 | DAHDI_SIG_CLEAR)
+#define SIG_BRI_PTMP	(0X4000000 | DAHDI_SIG_CLEAR)
+#define SIG_SS7		(0x1000000 | DAHDI_SIG_CLEAR)
+#define SIG_MFCR2 	DAHDI_SIG_CAS
+#define	SIG_SF		DAHDI_SIG_SF
+#define SIG_SFWINK 	(0x0100000 | DAHDI_SIG_SF)
+#define SIG_SF_FEATD	(0x0200000 | DAHDI_SIG_SF)
+#define	SIG_SF_FEATDMF	(0x0400000 | DAHDI_SIG_SF)
+#define	SIG_SF_FEATB	(0x0800000 | DAHDI_SIG_SF)
+#define SIG_EM_E1	DAHDI_SIG_EM_E1
+
 #ifdef LOTS_OF_SPANS
 #define NUM_SPANS	DAHDI_MAX_SPANS
 #else
@@ -507,8 +404,6 @@ static const char config[] = "chan_dahdi.conf";
 static int num_cadence = 4;
 static int user_has_defined_cadences = 0;
 
-static int has_pseudo;
-
 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
 	{ { 125, 125, 2000, 4000 } },			/*!< Quick chirp followed by normal ring */
 	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
@@ -556,7 +451,7 @@ static int mwilevel = 512;
 static int dtmfcid_level = 256;
 
 #define REPORT_CHANNEL_ALARMS 1
-#define REPORT_SPAN_ALARMS    2
+#define REPORT_SPAN_ALARMS    2 
 static int report_alarms = REPORT_CHANNEL_ALARMS;
 
 #ifdef HAVE_PRI
@@ -598,9 +493,11 @@ static int num_restart_pending = 0;
 
 static int restart_monitor(void);
 
+static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* This module does not handle MWI in an event-based manner.  However, it
 	 * subscribes to MWI for each mailbox that is configured so that the core
@@ -643,6 +540,8 @@ static inline int dahdi_wait_event(int fd)
 #define DEFAULT_RINGT 					((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
 #define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
 
+struct dahdi_pvt;
+
 /*!
  * \brief Configured ring timeout base.
  * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
@@ -658,7 +557,6 @@ struct dahdi_ss7 {
 static struct dahdi_ss7 linksets[NUM_SPANS];
 
 static int cur_ss7type = -1;
-static int cur_slc = -1;
 static int cur_linkset = -1;
 static int cur_pointcode = -1;
 static int cur_cicbeginswith = -1;
@@ -739,16 +637,644 @@ static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
 struct dahdi_pri;
 #endif
 
+#define SUB_REAL	0			/*!< Active call */
+#define SUB_CALLWAIT	1			/*!< Call-Waiting call on hold */
+#define SUB_THREEWAY	2			/*!< Three-way call */
+
 /* Polarity states */
 #define POLARITY_IDLE   0
 #define POLARITY_REV    1
 
-const char * const subnames[] = {
+
+struct distRingData {
+	int ring[3];
+	int range;
+};
+struct ringContextData {
+	char contextData[AST_MAX_CONTEXT];
+};
+struct dahdi_distRings {
+	struct distRingData ringnum[3];
+	struct ringContextData ringContext[3];
+};
+
+static const char * const subnames[] = {
 	"Real",
 	"Callwait",
 	"Threeway"
 };
 
+struct dahdi_subchannel {
+	int dfd;
+	struct ast_channel *owner;
+	int chan;
+	short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
+	struct ast_frame f;		/*!< One frame for each channel.  How did this ever work before? */
+	unsigned int needringing:1;
+	unsigned int needbusy:1;
+	unsigned int needcongestion:1;
+	unsigned int needanswer:1;
+	unsigned int needflash:1;
+	unsigned int needhold:1;
+	unsigned int needunhold:1;
+	unsigned int linear:1;
+	unsigned int inthreeway:1;
+	struct dahdi_confinfo curconf;
+};
+
+#define CONF_USER_REAL		(1 << 0)
+#define CONF_USER_THIRDCALL	(1 << 1)
+
+#define MAX_SLAVES	4
+
+/* States for sending MWI message
+ * First three states are required for send Ring Pulse Alert Signal
+ */
+typedef enum {
+	MWI_SEND_NULL = 0,
+	MWI_SEND_SA,
+	MWI_SEND_SA_WAIT,
+	MWI_SEND_PAUSE,
+	MWI_SEND_SPILL,
+	MWI_SEND_CLEANUP,
+	MWI_SEND_DONE,
+} mwisend_states;
+
+struct mwisend_info {
+	struct	timeval	pause;
+	mwisend_states 	mwisend_current;
+};
+
+/*! Specify the lists dahdi_pvt can be put in. */
+enum DAHDI_IFLIST {
+	DAHDI_IFLIST_NONE,	/*!< The dahdi_pvt is not in any list. */
+	DAHDI_IFLIST_MAIN,	/*!< The dahdi_pvt is in the main interface list */
+#if defined(HAVE_PRI)
+	DAHDI_IFLIST_NO_B_CHAN,	/*!< The dahdi_pvt is in a no B channel interface list */
+#endif	/* defined(HAVE_PRI) */
+};
+
+struct dahdi_pvt {
+	ast_mutex_t lock;					/*!< Channel private lock. */
+	struct callerid_state *cs;
+	struct ast_channel *owner;			/*!< Our current active owner (if applicable) */
+							/*!< Up to three channels can be associated with this call */
+
+	struct dahdi_subchannel sub_unused;		/*!< Just a safety precaution */
+	struct dahdi_subchannel subs[3];			/*!< Sub-channels */
+	struct dahdi_confinfo saveconf;			/*!< Saved conference info */
+
+	struct dahdi_pvt *slaves[MAX_SLAVES];		/*!< Slave to us (follows our conferencing) */
+	struct dahdi_pvt *master;				/*!< Master to us (we follow their conferencing) */
+	int inconference;				/*!< If our real should be in the conference */
+
+	int bufsize;                /*!< Size of the buffers */
+	int buf_no;					/*!< Number of buffers */
+	int buf_policy;				/*!< Buffer policy */
+	int faxbuf_no;              /*!< Number of Fax buffers */
+	int faxbuf_policy;          /*!< Fax buffer policy */
+	int sig;					/*!< Signalling style */
+	/*!
+	 * \brief Nonzero if the signaling type is sent over a radio.
+	 * \note Set to a couple of nonzero values but it is only tested like a boolean.
+	 */
+	int radio;
+	int outsigmod;					/*!< Outbound Signalling style (modifier) */
+	int oprmode;					/*!< "Operator Services" mode */
+	struct dahdi_pvt *oprpeer;				/*!< "Operator Services" peer tech_pvt ptr */
+	/*! \brief Amount of gain to increase during caller id */
+	float cid_rxgain;
+	/*! \brief Software Rx gain set by chan_dahdi.conf */
+	float rxgain;
+	/*! \brief Software Tx gain set by chan_dahdi.conf */
+	float txgain;
+
+	float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */
+	float rxdrc;
+	
+	int tonezone;					/*!< tone zone for this chan, or -1 for default */
+	enum DAHDI_IFLIST which_iflist;	/*!< Which interface list is this structure listed? */
+	struct dahdi_pvt *next;				/*!< Next channel in list */
+	struct dahdi_pvt *prev;				/*!< Prev channel in list */
+
+	/* flags */
+
+	/*!
+	 * \brief TRUE if ADSI (Analog Display Services Interface) available
+	 * \note Set from the "adsi" value read in from chan_dahdi.conf
+	 */
+	unsigned int adsi:1;
+	/*!
+	 * \brief TRUE if we can use a polarity reversal to mark when an outgoing
+	 * call is answered by the remote party.
+	 * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
+	 */
+	unsigned int answeronpolarityswitch:1;
+	/*!
+	 * \brief TRUE if busy detection is enabled.
+	 * (Listens for the beep-beep busy pattern.)
+	 * \note Set from the "busydetect" value read in from chan_dahdi.conf
+	 */
+	unsigned int busydetect:1;
+	/*!
+	 * \brief TRUE if call return is enabled.
+	 * (*69, if your dialplan doesn't catch this first)
+	 * \note Set from the "callreturn" value read in from chan_dahdi.conf
+	 */
+	unsigned int callreturn:1;
+	/*!
+	 * \brief TRUE if busy extensions will hear the call-waiting tone
+	 * and can use hook-flash to switch between callers.
+	 * \note Can be disabled by dialing *70.
+	 * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
+	 */
+	unsigned int callwaiting:1;
+	/*!
+	 * \brief TRUE if send caller ID for Call Waiting
+	 * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
+	 */
+	unsigned int callwaitingcallerid:1;
+	/*!
+	 * \brief TRUE if support for call forwarding enabled.
+	 * Dial *72 to enable call forwarding.
+	 * Dial *73 to disable call forwarding.
+	 * \note Set from the "cancallforward" value read in from chan_dahdi.conf
+	 */
+	unsigned int cancallforward:1;
+	/*!
+	 * \brief TRUE if support for call parking is enabled.
+	 * \note Set from the "canpark" value read in from chan_dahdi.conf
+	 */
+	unsigned int canpark:1;
+	/*! \brief TRUE if to wait for a DTMF digit to confirm answer */
+	unsigned int confirmanswer:1;
+	/*!
+	 * \brief TRUE if the channel is to be destroyed on hangup.
+	 * (Used by pseudo channels.)
+	 */
+	unsigned int destroy:1;
+	unsigned int didtdd:1;				/*!< flag to say its done it once */
+	/*! \brief TRUE if analog type line dialed no digits in Dial() */
+	unsigned int dialednone:1;
+	/*!
+	 * \brief TRUE if in the process of dialing digits or sending something.
+	 * \note This is used as a receive squelch for ISDN until connected.
+	 */
+	unsigned int dialing:1;
+	/*! \brief TRUE if the transfer capability of the call is digital. */
+	unsigned int digital:1;
+	/*! \brief TRUE if Do-Not-Disturb is enabled, present only for non sig_analog */
+	unsigned int dnd:1;
+	/*! \brief XXX BOOLEAN Purpose??? */
+	unsigned int echobreak:1;
+	/*!
+	 * \brief TRUE if echo cancellation enabled when bridged.
+	 * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
+	 * \note Disabled if the echo canceller is not setup.
+	 */
+	unsigned int echocanbridged:1;
+	/*! \brief TRUE if echo cancellation is turned on. */
+	unsigned int echocanon:1;
+	/*! \brief TRUE if a fax tone has already been handled. */
+	unsigned int faxhandled:1;
+	/*! TRUE if dynamic faxbuffers are configured for use, default is OFF */
+	unsigned int usefaxbuffers:1;
+	/*! TRUE while buffer configuration override is in use */
+	unsigned int bufferoverrideinuse:1;
+	/*! \brief TRUE if over a radio and dahdi_read() has been called. */
+	unsigned int firstradio:1;
+	/*!
+	 * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
+	 * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
+	 */
+	unsigned int hanguponpolarityswitch:1;
+	/*! \brief TRUE if DTMF detection needs to be done by hardware. */
+	unsigned int hardwaredtmf:1;
+	/*!
+	 * \brief TRUE if the outgoing caller ID is blocked/hidden.
+	 * \note Caller ID can be disabled by dialing *67.
+	 * \note Caller ID can be enabled by dialing *82.
+	 * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
+	 */
+	unsigned int hidecallerid:1;
+	/*!
+	 * \brief TRUE if hide just the name not the number for legacy PBX use.
+	 * \note Only applies to PRI channels.
+	 * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
+	 */
+	unsigned int hidecalleridname:1;
+	/*! \brief TRUE if DTMF detection is disabled. */
+	unsigned int ignoredtmf:1;
+	/*!
+	 * \brief TRUE if the channel should be answered immediately
+	 * without attempting to gather any digits.
+	 * \note Set from the "immediate" value read in from chan_dahdi.conf
+	 */
+	unsigned int immediate:1;
+	/*! \brief TRUE if in an alarm condition. */
+	unsigned int inalarm:1;
+	/*! \brief TRUE if TDD in MATE mode */
+	unsigned int mate:1;
+	/*! \brief TRUE if we originated the call leg. */
+	unsigned int outgoing:1;
+	/* unsigned int overlapdial:1; 			unused and potentially confusing */
+	/*!
+	 * \brief TRUE if busy extensions will hear the call-waiting tone
+	 * and can use hook-flash to switch between callers.
+	 * \note Set from the "callwaiting" value read in from chan_dahdi.conf
+	 */
+	unsigned int permcallwaiting:1;
+	/*!
+	 * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
+	 * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
+	 */
+	unsigned int permhidecallerid:1;
+	/*!
+	 * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
+	 * \note Set from the "priindication" value read in from chan_dahdi.conf
+	 */
+	unsigned int priindication_oob:1;
+	/*!
+	 * \brief TRUE if PRI B channels are always exclusively selected.
+	 * \note Set from the "priexclusive" value read in from chan_dahdi.conf
+	 */
+	unsigned int priexclusive:1;
+	/*!
+	 * \brief TRUE if we will pulse dial.
+	 * \note Set from the "pulsedial" value read in from chan_dahdi.conf
+	 */
+	unsigned int pulse:1;
+	/*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
+	unsigned int pulsedial:1;
+	unsigned int restartpending:1;		/*!< flag to ensure counted only once for restart */
+	/*!
+	 * \brief TRUE if caller ID is restricted.
+	 * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
+	 * \note Set from the "restrictcid" value read in from chan_dahdi.conf
+	 */
+	unsigned int restrictcid:1;
+	/*!
+	 * \brief TRUE if three way calling is enabled
+	 * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
+	 */
+	unsigned int threewaycalling:1;
+	/*!
+	 * \brief TRUE if call transfer is enabled
+	 * \note For FXS ports (either direct analog or over T1/E1):
+	 *   Support flash-hook call transfer
+	 * \note For digital ports using ISDN PRI protocols:
+	 *   Support switch-side transfer (called 2BCT, RLT or other names)
+	 * \note Set from the "transfer" value read in from chan_dahdi.conf
+	 */
+	unsigned int transfer:1;
+	/*!
+	 * \brief TRUE if caller ID is used on this channel.
+	 * \note PRI and SS7 spans will save caller ID from the networking peer.
+	 * \note FXS ports will generate the caller ID spill.
+	 * \note FXO ports will listen for the caller ID spill.
+	 * \note Set from the "usecallerid" value read in from chan_dahdi.conf
+	 */
+	unsigned int use_callerid:1;
+	/*!
+	 * \brief TRUE if we will use the calling presentation setting
+	 * from the Asterisk channel for outgoing calls.
+	 * \note Only applies to PRI and SS7 channels.
+	 * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
+	 */
+	unsigned int use_callingpres:1;
+	/*!
+	 * \brief TRUE if distinctive rings are to be detected.
+	 * \note For FXO lines
+	 * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
+	 */
+	unsigned int usedistinctiveringdetection:1;
+	/*!
+	 * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
+	 * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
+	 */
+	unsigned int dahditrcallerid:1;
+	/*!
+	 * \brief TRUE if allowed to flash-transfer to busy channels.
+	 * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
+	 */
+	unsigned int transfertobusy:1;
+	/*!
+	 * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
+	 * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
+	 */
+	unsigned int mwimonitor_neon:1;
+	/*!
+	 * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
+	 * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
+	 */
+	unsigned int mwimonitor_fsk:1;
+	/*!
+	 * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
+	 * \note RPAS - Ring Pulse Alert Signal
+	 * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
+	 */
+	unsigned int mwimonitor_rpas:1;
+	/*! \brief TRUE if an MWI monitor thread is currently active */
+	unsigned int mwimonitoractive:1;
+	/*! \brief TRUE if a MWI message sending thread is active */
+	unsigned int mwisendactive:1;
+	/*!
+	 * \brief TRUE if channel is out of reset and ready
+	 * \note Set but not used.
+	 */
+	unsigned int inservice:1;
+	/*!
+	 * \brief TRUE if the channel is locally blocked.
+	 * \note Applies to SS7 and MFCR2 channels.
+	 */
+	unsigned int locallyblocked:1;
+	/*!
+	 * \brief TRUE if the channel is remotely blocked.
+	 * \note Applies to SS7 and MFCR2 channels.
+	 */
+	unsigned int remotelyblocked:1;
+	/*!
+	 * \brief TRUE if the channel alarms will be managed also as Span ones
+	 * \note Applies to all channels
+	 */
+	unsigned int manages_span_alarms:1;
+
+#if defined(HAVE_PRI)
+	struct sig_pri_span *pri;
+	int logicalspan;
+#endif
+	/*!
+	 * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
+	 * \note Set from the "usesmdi" value read in from chan_dahdi.conf
+	 */
+	unsigned int use_smdi:1;
+	struct mwisend_info mwisend_data;
+	/*! \brief The SMDI interface to get SMDI messages from. */
+	struct ast_smdi_interface *smdi_iface;
+
+	/*! \brief Distinctive Ring data */
+	struct dahdi_distRings drings;
+
+	/*!
+	 * \brief The configured context for incoming calls.
+	 * \note The "context" string read in from chan_dahdi.conf
+	 */
+	char context[AST_MAX_CONTEXT];
+	/*! 
+	 * \brief A description for the channel configuration
+	 * \note The "description" string read in from chan_dahdi.conf
+	 */
+	char description[32];
+	/*!
+	 * \brief Default distinctive ring context.
+	 */
+	char defcontext[AST_MAX_CONTEXT];
+	/*! \brief Extension to use in the dialplan. */
+	char exten[AST_MAX_EXTENSION];
+	/*!
+	 * \brief Language configured for calls.
+	 * \note The "language" string read in from chan_dahdi.conf
+	 */
+	char language[MAX_LANGUAGE];
+	/*!
+	 * \brief The configured music-on-hold class to use for calls.
+	 * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
+	 */
+	char mohinterpret[MAX_MUSICCLASS];
+	/*!
+	 * \brief Suggested music-on-hold class for peer channel to use for calls.
+	 * \note The "mohsuggest" string read in from chan_dahdi.conf
+	 */
+	char mohsuggest[MAX_MUSICCLASS];
+	char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
+	/*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
+	char cid_ani[AST_MAX_EXTENSION];
+#endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) */
+	/*! \brief Automatic Number Identification code from PRI */
+	int cid_ani2;
+	/*! \brief Caller ID number from an incoming call. */
+	char cid_num[AST_MAX_EXTENSION];
+	/*!
+	 * \brief Caller ID tag from incoming call
+	 * \note the "cid_tag" string read in from chan_dahdi.conf
+	 */
+	char cid_tag[AST_MAX_EXTENSION];
+	/*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
+	int cid_ton;
+	/*! \brief Caller ID name from an incoming call. */
+	char cid_name[AST_MAX_EXTENSION];
+	/*! \brief Caller ID subaddress from an incoming call. */
+	char cid_subaddr[AST_MAX_EXTENSION];
+	char *origcid_num;				/*!< malloced original callerid */
+	char *origcid_name;				/*!< malloced original callerid */
+	/*! \brief Call waiting number. */
+	char callwait_num[AST_MAX_EXTENSION];
+	/*! \brief Call waiting name. */
+	char callwait_name[AST_MAX_EXTENSION];
+	/*! \brief Redirecting Directory Number Information Service (RDNIS) number */
+	char rdnis[AST_MAX_EXTENSION];
+	/*! \brief Dialed Number Identifier */
+	char dnid[AST_MAX_EXTENSION];
+	/*!
+	 * \brief Bitmapped groups this belongs to.
+	 * \note The "group" bitmapped group string read in from chan_dahdi.conf
+	 */
+	ast_group_t group;
+	/*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
+	int law_default;
+	/*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
+	int law;
+	int confno;					/*!< Our conference */
+	int confusers;					/*!< Who is using our conference */
+	int propconfno;					/*!< Propagated conference number */
+	/*!
+	 * \brief Bitmapped call groups this belongs to.
+	 * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
+	 */
+	ast_group_t callgroup;
+	/*!
+	 * \brief Bitmapped pickup groups this belongs to.
+	 * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
+	 */
+	ast_group_t pickupgroup;
+	/*!
+	 * \brief Named call groups this belongs to.
+	 * \note The "namedcallgroup" string read in from chan_dahdi.conf
+	 */
+	struct ast_namedgroups *named_callgroups;
+	/*!
+	 * \brief Named pickup groups this belongs to.
+	 * \note The "namedpickupgroup" string read in from chan_dahdi.conf
+	 */
+	struct ast_namedgroups *named_pickupgroups;
+	/*!
+	 * \brief Channel variable list with associated values to set when a channel is created.
+	 * \note The "setvar" strings read in from chan_dahdi.conf
+	 */
+	struct ast_variable *vars;
+	int channel;					/*!< Channel Number */
+	int span;					/*!< Span number */
+	time_t guardtime;				/*!< Must wait this much time before using for new call */
+	int cid_signalling;				/*!< CID signalling type bell202 or v23 */
+	int cid_start;					/*!< CID start indicator, polarity or ring or DTMF without warning event */
+	int dtmfcid_holdoff_state;		/*!< State indicator that allows for line to settle before checking for dtmf energy */
+	struct timeval	dtmfcid_delay;  /*!< Time value used for allow line to settle */
+	int callingpres;				/*!< The value of calling presentation that we're going to use when placing a PRI call */
+	int callwaitingrepeat;				/*!< How many samples to wait before repeating call waiting */
+	int cidcwexpire;				/*!< When to stop waiting for CID/CW CAS response (In samples) */
+	int cid_suppress_expire;		/*!< How many samples to suppress after a CID spill. */
+	/*! \brief Analog caller ID waveform sample buffer */
+	unsigned char *cidspill;
+	/*! \brief Position in the cidspill buffer to send out next. */
+	int cidpos;
+	/*! \brief Length of the cidspill buffer containing samples. */
+	int cidlen;
+	/*! \brief Ring timeout timer?? */
+	int ringt;
+	/*!
+	 * \brief Ring timeout base.
+	 * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
+	 */
+	int ringt_base;
+	/*!
+	 * \brief Number of most significant digits/characters to strip from the dialed number.
+	 * \note Feature is deprecated.  Use dialplan logic.
+	 * \note The characters are stripped before the PRI TON/NPI prefix
+	 * characters are processed.
+	 */
+	int stripmsd;
+	/*!
+	 * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
+	 * \note
+	 * After CAS is sent, the call waiting caller id will be sent if the phone
+	 * gives a positive reply.
+	 */
+	int callwaitcas;
+	/*! \brief Number of call waiting rings. */
+	int callwaitrings;
+	/*! \brief Echo cancel parameters. */
+	struct {
+		struct dahdi_echocanparams head;
+		struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
+	} echocancel;
+	/*!
+	 * \brief Echo training time. 0 = disabled
+	 * \note Set from the "echotraining" value read in from chan_dahdi.conf
+	 */
+	int echotraining;
+	/*! \brief Filled with 'w'.  XXX Purpose?? */
+	char echorest[20];
+	/*!
+	 * \brief Number of times to see "busy" tone before hanging up.
+	 * \note Set from the "busycount" value read in from chan_dahdi.conf
+	 */
+	int busycount;
+	/*!
+	 * \brief Busy cadence pattern description.
+	 * \note Set from the "busypattern" value read from chan_dahdi.conf
+	 */
+	struct ast_dsp_busy_pattern busy_cadence;
+	/*!
+	 * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
+	 * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
+	 */
+	int callprogress;
+	/*!
+	 * \brief Number of milliseconds to wait for dialtone.
+	 * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf
+	 */
+	int waitfordialtone;
+	/*!
+	 * \brief Number of frames to watch for dialtone in incoming calls
+	 * \note Set from the "dialtone_detect" value read in from chan_dahdi.conf
+	 */
+	int dialtone_detect;
+	int dialtone_scanning_time_elapsed;	/*!< Amount of audio scanned for dialtone, in frames */
+	struct timeval waitingfordt;			/*!< Time we started waiting for dialtone */
+	struct timeval flashtime;			/*!< Last flash-hook time */
+	/*! \brief Opaque DSP configuration structure. */
+	struct ast_dsp *dsp;
+	/*! \brief DAHDI dial operation command struct for ioctl() call. */
+	struct dahdi_dialoperation dop;
+	int whichwink;					/*!< SIG_FEATDMF_TA Which wink are we on? */
+	/*! \brief Second part of SIG_FEATDMF_TA wink operation. */
+	char finaldial[64];
+	char accountcode[AST_MAX_ACCOUNT_CODE];		/*!< Account code */
+	int amaflags;					/*!< AMA Flags */
+	struct tdd_state *tdd;				/*!< TDD flag */
+	/*! \brief Accumulated call forwarding number. */
+	char call_forward[AST_MAX_EXTENSION];
+	/*!
+	 * \brief Voice mailbox location.
+	 * \note Set from the "mailbox" string read in from chan_dahdi.conf
+	 */
+	char mailbox[AST_MAX_EXTENSION];
+	/*! \brief Opaque event subscription parameters for message waiting indication support. */
+	struct ast_event_sub *mwi_event_sub;
+	/*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
+	char dialdest[256];
+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
+	struct dahdi_vmwi_info mwisend_setting;				/*!< Which VMWI methods to use */
+	unsigned int mwisend_fsk: 1;		/*! Variable for enabling FSK MWI handling in chan_dahdi */
+	unsigned int mwisend_rpas:1;		/*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
+#endif
+	int distinctivering;				/*!< Which distinctivering to use */
+	int dtmfrelax;					/*!< whether to run in relaxed DTMF mode */
+	/*! \brief Holding place for event injected from outside normal operation. */
+	int fake_event;
+	/*!
+	 * \brief Minimal time period (ms) between the answer polarity
+	 * switch and hangup polarity switch.
+	 */
+	int polarityonanswerdelay;
+	/*! \brief Start delay time if polarityonanswerdelay is nonzero. */
+	struct timeval polaritydelaytv;
+	/*!
+	 * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
+	 * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
+	 */
+	int sendcalleridafter;
+	/*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
+	int polarity;
+	/*! \brief DSP feature flags: DSP_FEATURE_xxx */
+	int dsp_features;
+#if defined(HAVE_SS7)
+	/*! \brief SS7 control parameters */
+	struct sig_ss7_linkset *ss7;
+#endif	/* defined(HAVE_SS7) */
+#ifdef HAVE_OPENR2
+	struct dahdi_mfcr2 *mfcr2;
+	openr2_chan_t *r2chan;
+	openr2_calling_party_category_t mfcr2_recvd_category;
+	openr2_calling_party_category_t mfcr2_category;
+	int mfcr2_dnis_index;
+	int mfcr2_ani_index;
+	int mfcr2call:1;
+	int mfcr2_answer_pending:1;
+	int mfcr2_charge_calls:1;
+	int mfcr2_allow_collect_calls:1;
+	int mfcr2_forced_release:1;
+	int mfcr2_dnis_matched:1;
+	int mfcr2_call_accepted:1;
+	int mfcr2_accept_on_offer:1;
+	int mfcr2_progress_sent:1;
+#endif
+	/*! \brief DTMF digit in progress.  0 when no digit in progress. */
+	char begindigit;
+	/*! \brief TRUE if confrence is muted. */
+	int muting;
+	void *sig_pvt;
+	struct ast_cc_config_params *cc_params;
+	/* DAHDI channel names may differ greatly from the
+	 * string that was provided to an app such as Dial. We
+	 * need to save the original string passed to dahdi_request
+	 * for call completion purposes. This way, we can replicate
+	 * the original dialed string later.
+	 */
+	char dialstring[AST_CHANNEL_NAME];
+};
+
 #define DATA_EXPORT_DAHDI_PVT(MEMBER)					\
 	MEMBER(dahdi_pvt, cid_rxgain, AST_DATA_DOUBLE)			\
 	MEMBER(dahdi_pvt, rxgain, AST_DATA_DOUBLE)			\
@@ -806,8 +1332,8 @@ const char * const subnames[] = {
 	MEMBER(dahdi_pvt, mwimonitoractive, AST_DATA_BOOLEAN)			\
 	MEMBER(dahdi_pvt, mwisendactive, AST_DATA_BOOLEAN)			\
 	MEMBER(dahdi_pvt, inservice, AST_DATA_BOOLEAN)				\
-	MEMBER(dahdi_pvt, locallyblocked, AST_DATA_UNSIGNED_INTEGER)		\
-	MEMBER(dahdi_pvt, remotelyblocked, AST_DATA_UNSIGNED_INTEGER)		\
+	MEMBER(dahdi_pvt, locallyblocked, AST_DATA_BOOLEAN)			\
+	MEMBER(dahdi_pvt, remotelyblocked, AST_DATA_BOOLEAN)			\
 	MEMBER(dahdi_pvt, manages_span_alarms, AST_DATA_BOOLEAN)		\
 	MEMBER(dahdi_pvt, use_smdi, AST_DATA_BOOLEAN)				\
 	MEMBER(dahdi_pvt, context, AST_DATA_STRING)				\
@@ -825,14 +1351,6 @@ static struct dahdi_pvt *iflist = NULL;	/*!< Main interface list start */
 static struct dahdi_pvt *ifend = NULL;	/*!< Main interface list end */
 
 #if defined(HAVE_PRI)
-struct doomed_pri {
-	struct sig_pri_span *pri;
-	AST_LIST_ENTRY(doomed_pri) list;
-};
-static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
-
-static void pri_destroy_span(struct sig_pri_span *pri);
-
 static struct dahdi_parms_pseudo {
 	int buf_no;					/*!< Number of buffers */
 	int buf_policy;				/*!< Buffer policy */
@@ -874,18 +1392,6 @@ struct dahdi_chan_conf {
 	 * \note Set from the "smdiport" string read in from chan_dahdi.conf
 	 */
 	char smdi_port[SMDI_MAX_FILENAME_LEN];
-
-	/*!
-	 * \brief Don't create channels below this number
-	 * \note by default is 0 (no limit)
-	 */
-	int wanted_channels_start;
-
-	/*!
-	 * \brief Don't create channels above this number (infinity by default)
-	 * \note by default is 0 (special value that means "no limit").
-	 */
-	int wanted_channels_end;
 };
 
 /*! returns a new dahdi_chan_conf with default values (by-value) */
@@ -903,6 +1409,8 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 			.localdialplan = PRI_NATIONAL_ISDN + 1,
 			.nodetype = PRI_CPE,
 			.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
+			.inband_on_setup_ack = 1,
+			.inband_on_proceeding = 1,
 
 #if defined(HAVE_PRI_CCSS)
 			.cc_ptmp_recall_mode = 1,/* specificRecall */
@@ -919,6 +1427,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 			.privateprefix = "",
 			.unknownprefix = "",
 			.colp_send = SIG_PRI_COLP_UPDATE,
+			.force_restart_unavailable_chans = 1,
 			.resetinterval = -1,
 		},
 #endif
@@ -929,8 +1438,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 			.internationalprefix = "",
 			.nationalprefix = "",
 			.subscriberprefix = "",
-			.unknownprefix = "",
-			.networkroutedprefix = ""
+			.unknownprefix = ""
 		},
 #endif	/* defined(HAVE_SS7) */
 #ifdef HAVE_OPENR2
@@ -1018,7 +1526,6 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 			.debouncetime = -1
 		},
 		.is_sig_auto = 1,
-		.ignore_failed_channels = 1,
 		.smdi_port = "/dev/ttyS0",
 	};
 
@@ -1026,9 +1533,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 }
 
 
-static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	const char *data, int *cause);
+static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int dahdi_digit_begin(struct ast_channel *ast, char digit);
 static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
@@ -1059,6 +1564,7 @@ static struct ast_channel_tech dahdi_tech = {
 	.answer = dahdi_answer,
 	.read = dahdi_read,
 	.write = dahdi_write,
+	.bridge = dahdi_bridge,
 	.exception = dahdi_exception,
 	.indicate = dahdi_indicate,
 	.fixup = dahdi_fixup,
@@ -1072,6 +1578,77 @@ static struct ast_channel_tech dahdi_tech = {
 
 #define GET_CHANNEL(p) ((p)->channel)
 
+#define SIG_PRI_LIB_HANDLE_CASES	\
+	SIG_PRI:						\
+	case SIG_BRI:					\
+	case SIG_BRI_PTMP
+
+/*!
+ * \internal
+ * \brief Determine if sig_pri handles the signaling.
+ * \since 1.8
+ *
+ * \param signaling Signaling to determine if is for sig_pri.
+ *
+ * \return TRUE if the signaling is for sig_pri.
+ */
+static inline int dahdi_sig_pri_lib_handles(int signaling)
+{
+	int handles;
+
+	switch (signaling) {
+	case SIG_PRI_LIB_HANDLE_CASES:
+		handles = 1;
+		break;
+	default:
+		handles = 0;
+		break;
+	}
+
+	return handles;
+}
+
+static int analog_lib_handles(int signalling, int radio, int oprmode)
+{
+	switch (signalling) {
+	case SIG_FXOLS:
+	case SIG_FXOGS:
+	case SIG_FXOKS:
+	case SIG_FXSLS:
+	case SIG_FXSGS:
+	case SIG_FXSKS:
+	case SIG_EMWINK:
+	case SIG_EM:
+	case SIG_EM_E1:
+	case SIG_FEATD:
+	case SIG_FEATDMF:
+	case SIG_E911:
+	case SIG_FGC_CAMA:
+	case SIG_FGC_CAMAMF:
+	case SIG_FEATB:
+	case SIG_SFWINK:
+	case SIG_SF:
+	case SIG_SF_FEATD:
+	case SIG_SF_FEATDMF:
+	case SIG_FEATDMF_TA:
+	case SIG_SF_FEATB:
+		break;
+	default:
+		/* The rest of the function should cover the remainder of signalling types */
+		return 0;
+	}
+
+	if (radio) {
+		return 0;
+	}
+
+	if (oprmode) {
+		return 0;
+	}
+
+	return 1;
+}
+
 static enum analog_sigtype dahdisig_to_analogsig(int sig)
 {
 	switch (sig) {
@@ -1165,123 +1742,6 @@ static int analogsub_to_dahdisub(enum analog_sub analogsub)
 	return index;
 }
 
-/*!
- * \internal
- * \brief release all members on the doomed pris list
- * \since 13.0
- *
- * Called priodically by the monitor threads to release spans marked for
- * removal.
- */
-static void release_doomed_pris(void)
-{
-#ifdef HAVE_PRI
-	struct doomed_pri *entry;
-
-	AST_LIST_LOCK(&doomed_pris);
-	while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
-		/* The span destruction must be done with this lock not held */
-		AST_LIST_UNLOCK(&doomed_pris);
-		ast_debug(4, "Destroying span %d from doomed queue.\n",
-				entry->pri->span);
-		pri_destroy_span(entry->pri);
-		ast_free(entry);
-		AST_LIST_LOCK(&doomed_pris);
-	}
-	AST_LIST_UNLOCK(&doomed_pris);
-#endif
-}
-
-#ifdef HAVE_PRI
-/*!
- * \brief Queue a span for destruction
- * \since 13.0
- *
- * \param pri the span to destroy
- *
- * Add a span to the list of spans to be destroyed later on
- * by the monitor thread. Allows destroying a span while holding its
- * lock.
- */
-static void pri_queue_for_destruction(struct sig_pri_span *pri)
-{
-	struct doomed_pri *entry;
-
-	AST_LIST_LOCK(&doomed_pris);
-	AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
-		if (entry->pri == pri) {
-			AST_LIST_UNLOCK(&doomed_pris);
-			return;
-		}
-	}
-	entry = ast_calloc(sizeof(struct doomed_pri), 1);
-	if (!entry) {
-		/* Nothing useful to do here. Panic? */
-		ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
-		AST_LIST_UNLOCK(&doomed_pris);
-		return;
-	}
-	entry->pri = pri;
-	ast_debug(4, "Queue span %d for destruction.\n", pri->span);
-	AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
-	AST_LIST_UNLOCK(&doomed_pris);
-}
-#endif
-
-/*!
- * \internal
- * \brief Send a dial string to DAHDI.
- * \since 12.0.0
- *
- * \param pvt DAHDI private pointer
- * \param operation DAHDI dial operation to do to string
- * \param dial_str Dial string to send
- *
- * \retval 0 on success.
- * \retval non-zero on error.
- */
-static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
-{
-	int res;
-	int offset;
-	const char *pos;
-	struct dahdi_dialoperation zo = {
-		.op = operation,
-	};
-
-	/* Convert the W's to ww. */
-	pos = dial_str;
-	for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
-		if (!*pos) {
-			break;
-		}
-		if (*pos == 'W') {
-			/* Convert 'W' to "ww" */
-			++pos;
-			if (offset >= sizeof(zo.dialstr) - 3) {
-				/* No room to expand */
-				break;
-			}
-			zo.dialstr[offset] = 'w';
-			++offset;
-			zo.dialstr[offset] = 'w';
-			continue;
-		}
-		zo.dialstr[offset] = *pos++;
-	}
-	/* The zo initialization has already terminated the dialstr. */
-
-	ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
-		pvt->channel, dial_str, zo.dialstr);
-	res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
-	if (res) {
-		ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
-			pvt->channel, dial_str, strerror(errno));
-	}
-
-	return res;
-}
-
 static enum analog_event dahdievent_to_analogevent(int event);
 static int bump_gains(struct dahdi_pvt *p);
 static int dahdi_setlinear(int dfd, int linear);
@@ -1301,13 +1761,21 @@ static int my_start_cid_detect(void *pvt, int cid_signalling)
 	return 0;
 }
 
+static int restore_gains(struct dahdi_pvt *p);
+
 static int my_stop_cid_detect(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
 	int index = SUB_REAL;
-	if (p->cs)
+
+	if (p->cs) {
 		callerid_free(p->cs);
+	}
+
+	/* Restore linear mode after Caller*ID processing */
 	dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
+	restore_gains(p);
+
 	return 0;
 }
 
@@ -1321,6 +1789,7 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 	int res;
 	unsigned char buf[256];
 	int flags;
+	struct ast_format tmpfmt;
 
 	poller.fd = p->subs[SUB_REAL].dfd;
 	poller.events = POLLPRI | POLLIN;
@@ -1353,9 +1822,9 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 		}
 
 		if (p->cid_signalling == CID_SIG_V23_JP) {
-			res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
+			res = callerid_feed_jp(p->cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		} else {
-			res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+			res = callerid_feed(p->cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		}
 		if (res < 0) {
 			/*
@@ -1383,7 +1852,6 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
 }
 
 static const char *event2str(int event);
-static int restore_gains(struct dahdi_pvt *p);
 
 static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
 {
@@ -1396,7 +1864,7 @@ static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int
 	int i;
 	int res;
 	int checkaftercid = 0;
-
+	const char *matched_context;
 	struct dahdi_pvt *p = pvt;
 	struct analog_pvt *analog_p = p->sig_pvt;
 
@@ -1406,46 +1874,44 @@ static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int
 		checkaftercid = 1;
 	}
 
-	/* We must have a ring by now, so, if configured, lets try to listen for
-	 * distinctive ringing */
+	/* We must have a ring by now so lets try to listen for distinctive ringing */
 	if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
 		/* Clear the current ring data array so we don't have old data in it. */
 		for (receivedRingT = 0; receivedRingT < RING_PATTERNS; receivedRingT++)
 			ringdata[receivedRingT] = 0;
 		receivedRingT = 0;
-		if (checkaftercid && distinctiveringaftercid)
+
+		if (checkaftercid && distinctiveringaftercid) {
 			ast_verb(3, "Detecting post-CID distinctive ring\n");
-		/* Check to see if context is what it should be, if not set to be. */
-		else if (strcmp(p->context,p->defcontext) != 0) {
-			ast_copy_string(p->context, p->defcontext, sizeof(p->context));
-			ast_channel_context_set(chan, p->defcontext);
 		}
 
 		for (;;) {
 			i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-			if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
+			res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i);
+			if (res) {
 				ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
 				ast_hangup(chan);
 				return 1;
 			}
 			if (i & DAHDI_IOMUX_SIGEVENT) {
 				res = dahdi_get_event(p->subs[idx].dfd);
+				ast_debug(3, "Got event %d (%s)...\n", res, event2str(res));
 				if (res == DAHDI_EVENT_NOALARM) {
 					p->inalarm = 0;
 					analog_p->inalarm = 0;
-				}
-				ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
-				res = 0;
-				/* Let us detect distinctive ring */
+				} else if (res == DAHDI_EVENT_RINGOFFHOOK) {
+					/* Let us detect distinctive ring */
+					ringdata[receivedRingT] = analog_p->ringt;
 
-				ringdata[receivedRingT] = analog_p->ringt;
-
-				if (analog_p->ringt < analog_p->ringt_base/2)
-					break;
-				/* Increment the ringT counter so we can match it against
-				   values in chan_dahdi.conf for distinctive ring */
-				if (++receivedRingT == RING_PATTERNS)
-					break;
+					if (analog_p->ringt < analog_p->ringt_base / 2) {
+						break;
+					}
+					/* Increment the ringT counter so we can match it against
+					   values in chan_dahdi.conf for distinctive ring */
+					if (++receivedRingT == RING_PATTERNS) {
+						break;
+					}
+				}
 			} else if (i & DAHDI_IOMUX_READ) {
 				res = read(p->subs[idx].dfd, buf, sizeof(buf));
 				if (res < 0) {
@@ -1458,51 +1924,55 @@ static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int
 				}
 				if (analog_p->ringt > 0) {
 					if (!(--analog_p->ringt)) {
-						res = -1;
 						break;
 					}
 				}
 			}
 		}
 	}
-	if ((checkaftercid && usedistinctiveringdetection) || !checkaftercid) {
-		/* this only shows up if you have n of the dring patterns filled in */
-		ast_verb(3, "Detected ring pattern: %d,%d,%d\n",ringdata[0],ringdata[1],ringdata[2]);
-		for (counter = 0; counter < 3; counter++) {
-		/* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
-			distMatches = 0;
-			/* this only shows up if you have n of the dring patterns filled in */
-			ast_verb(3, "Checking %d,%d,%d\n",
-					p->drings.ringnum[counter].ring[0],
-					p->drings.ringnum[counter].ring[1],
-					p->drings.ringnum[counter].ring[2]);
-			for (counter1 = 0; counter1 < 3; counter1++) {
-				ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
-				if (p->drings.ringnum[counter].ring[counter1] == -1) {
-					ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
-					ringdata[counter1]);
-					distMatches++;
-				} else if (ringdata[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
-										ringdata[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
-					ast_verb(3, "Ring pattern matched in range: %d to %d\n",
-					(p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
-					(p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
-					distMatches++;
-				}
-			}
 
-			if (distMatches == 3) {
-				/* The ring matches, set the context to whatever is for distinctive ring.. */
-				ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
-				ast_channel_context_set(chan, S_OR(p->drings.ringContext[counter].contextData, p->defcontext));
-				ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
+	/* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
+	ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
+	matched_context = p->defcontext;
+	for (counter = 0; counter < 3; counter++) {
+		int range = p->drings.ringnum[counter].range;
+
+		distMatches = 0;
+		ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
+			p->drings.ringnum[counter].ring[0],
+			p->drings.ringnum[counter].ring[1],
+			p->drings.ringnum[counter].ring[2],
+			range);
+		for (counter1 = 0; counter1 < 3; counter1++) {
+			int ring = p->drings.ringnum[counter].ring[counter1];
+
+			if (ring == -1) {
+				ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
+					ringdata[counter1]);
+				distMatches++;
+			} else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
+				ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
+					ringdata[counter1], ring - range, ring + range);
+				distMatches++;
+			} else {
+				/* The current dring pattern cannot match. */
 				break;
 			}
 		}
+
+		if (distMatches == 3) {
+			/* The ring matches, set the context to whatever is for distinctive ring.. */
+			matched_context = S_OR(p->drings.ringContext[counter].contextData, p->defcontext);
+			ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context);
+			break;
+		}
+	}
+
+	/* Set selected distinctive ring context if not already set. */
+	if (strcmp(p->context, matched_context) != 0) {
+		ast_copy_string(p->context, matched_context, sizeof(p->context));
+		ast_channel_context_set(chan, matched_context);
 	}
-	/* Restore linear mode (if appropriate) for Caller*ID processing */
-	dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
-	restore_gains(p);
 
 	return 0;
 }
@@ -1524,7 +1994,7 @@ static int restore_conference(struct dahdi_pvt *p);
 static int my_callwait(void *pvt)
 {
 	struct dahdi_pvt *p = pvt;
-
+	struct ast_format tmpfmt;
 	p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
 	if (p->cidspill) {
 		ast_log(LOG_WARNING, "Spill already exists?!?\n");
@@ -1541,11 +2011,11 @@ static int my_callwait(void *pvt)
 	/* Silence */
 	memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
 	if (!p->callwaitrings && p->callwaitingcallerid) {
-		ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
+		ast_gen_cas(p->cidspill, 1, 2400 + 680, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		p->callwaitcas = 1;
 		p->cidlen = 2400 + 680 + READ_SIZE * 4;
 	} else {
-		ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
+		ast_gen_cas(p->cidspill, 1, 2400, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		p->callwaitcas = 0;
 		p->cidlen = 2400 + READ_SIZE * 4;
 	}
@@ -1558,6 +2028,7 @@ static int my_callwait(void *pvt)
 static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
 {
 	struct dahdi_pvt *p = pvt;
+	struct ast_format tmpfmt;
 
 	ast_debug(2, "Starting cid spill\n");
 
@@ -1571,7 +2042,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
 			p->cidlen = ast_callerid_generate(p->cidspill,
 				caller->id.name.str,
 				caller->id.number.str,
-				AST_LAW(p));
+				ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		} else {
 			ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n",
 				caller->id.name.str, caller->id.number.str);
@@ -1580,7 +2051,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
 			p->cidlen = ast_callerid_callwaiting_generate(p->cidspill,
 				caller->id.name.str,
 				caller->id.number.str,
-				AST_LAW(p));
+				ast_format_set(&tmpfmt, AST_LAW(p), 0));
 			p->cidlen += READ_SIZE * 4;
 		}
 		p->cidpos = 0;
@@ -1747,52 +2218,6 @@ static void my_deadlock_avoidance_private(void *pvt)
 	DEADLOCK_AVOIDANCE(&p->lock);
 }
 
-static struct ast_manager_event_blob *dahdichannel_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	struct ast_json *span, *channel;
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	span = ast_json_object_get(obj->blob, "span");
-	channel = ast_json_object_get(obj->blob, "channel");
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
-		"%s"
-		"DAHDISpan: %u\r\n"
-		"DAHDIChannel: %s\r\n",
-		ast_str_buffer(channel_string),
-		(unsigned int)ast_json_integer_get(span),
-		ast_json_string_get(channel));
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,
-	.to_ami = dahdichannel_to_ami,
-	);
-
-/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
-static void publish_dahdichannel(struct ast_channel *chan, int span, const char *dahdi_channel)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	ast_assert(dahdi_channel != NULL);
-
-	blob = ast_json_pack("{s: i, s: s}",
-		"span", span,
-		"channel", dahdi_channel);
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, dahdichannel_type(), blob);
-	ast_channel_unlock(chan);
-}
-
 /*!
  * \internal
  * \brief Post an AMI DAHDI channel association event.
@@ -1817,7 +2242,20 @@ static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *cha
 		/* Real channel */
 		snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
 	}
-	publish_dahdichannel(chan, p->span, ch_name);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "DAHDIChannel",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"DAHDISpan: %d\r\n"
+		"DAHDIChannel: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		p->span,
+		ch_name);
 }
 
 #ifdef HAVE_PRI
@@ -1840,14 +2278,14 @@ static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
 #endif
 
 /* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
-* 	returns the last value of the linear setting
-*/
+* 	returns the last value of the linear setting 
+*/ 
 static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
 {
 	struct dahdi_pvt *p = pvt;
 	int oldval;
 	int idx = analogsub_to_dahdisub(sub);
-
+	
 	dahdi_setlinear(p->subs[idx].dfd, linear_mode);
 	oldval = p->subs[idx].linear;
 	p->subs[idx].linear = linear_mode ? 1 : 0;
@@ -1875,12 +2313,12 @@ static void my_get_and_handle_alarms(void *pvt)
 
 static void *my_get_sigpvt_bridged_channel(struct ast_channel *chan)
 {
-	RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup);
+	struct ast_channel *bridged = ast_bridged_channel(chan);
 
 	if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
 		struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
 
-		if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 			return p->sig_pvt;
 		}
 	}
@@ -2223,9 +2661,9 @@ static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel
  *
  * \param callid_created value returned from ast_callid_threadstorage_auto()
  */
-static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid, int callid_created);
+static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linked, struct ast_callid *callid, int callid_created);
 
-static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid);
+static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid);
 
 static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
 {
@@ -2234,7 +2672,7 @@ static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int s
 	struct dahdi_pvt *p = pvt;
 	int dsub = analogsub_to_dahdisub(sub);
 
-	return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, NULL, requestor, callid, callid_created);
+	return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
@@ -2249,9 +2687,7 @@ static int dahdi_setlaw(int dfd, int law)
 #endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) */
 
 #if defined(HAVE_PRI)
-static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
-	enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
-	const struct ast_channel *requestor)
+static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state, enum sig_pri_law law, char *exten, const struct ast_channel *requestor)
 {
 	struct dahdi_pvt *p = pvt;
 	int audio;
@@ -2294,7 +2730,7 @@ static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
 			break;
 	}
 
-	return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
+	return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 #endif	/* defined(HAVE_PRI) */
 
@@ -2366,13 +2802,19 @@ static void my_pri_ss7_open_media(void *p)
  */
 static void my_pri_dial_digits(void *p, const char *dial_string)
 {
-	char dial_str[DAHDI_MAX_DTMF_BUF];
+	struct dahdi_dialoperation zo = {
+		.op = DAHDI_DIAL_OP_APPEND,
+	};
 	struct dahdi_pvt *pvt = p;
 	int res;
 
-	snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
-	res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
-	if (!res) {
+	snprintf(zo.dialstr, sizeof(zo.dialstr), "T%s", dial_string);
+	ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", pvt->channel, zo.dialstr);
+	res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
+	if (res) {
+		ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
+			pvt->channel, dial_string, strerror(errno));
+	} else {
 		pvt->dialing = 1;
 	}
 }
@@ -2562,14 +3004,17 @@ static int my_is_off_hook(void *pvt)
 	return par.rxisoffhook;
 }
 
+static void dahdi_enable_ec(struct dahdi_pvt *p);
+static void dahdi_disable_ec(struct dahdi_pvt *p);
+
 static int my_set_echocanceller(void *pvt, int enable)
 {
 	struct dahdi_pvt *p = pvt;
 
 	if (enable)
-		dahdi_ec_enable(p);
+		dahdi_enable_ec(p);
 	else
-		dahdi_ec_disable(p);
+		dahdi_disable_ec(p);
 
 	return 0;
 }
@@ -2660,7 +3105,10 @@ static int my_start(void *pvt)
 
 static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
 {
+	int index = analogsub_to_dahdisub(sub);
+	int res;
 	struct dahdi_pvt *p = pvt;
+	struct dahdi_dialoperation ddop;
 
 	if (dop->op != ANALOG_DIAL_OP_REPLACE) {
 		ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
@@ -2673,7 +3121,17 @@ static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoper
 		return -1;
 	}
 
-	return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
+	ddop.op = DAHDI_DIAL_OP_REPLACE;
+	ast_copy_string(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
+
+	ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", p->channel, ddop.dialstr);
+
+	res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
+	if (res == -1) {
+		ast_debug(1, "DAHDI_DIAL ioctl failed on %s: %s\n", ast_channel_name(p->owner), strerror(errno));
+	}
+
+	return res;
 }
 
 static void dahdi_train_ec(struct dahdi_pvt *p);
@@ -2768,6 +3226,8 @@ static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
+static int pri_destroy_dchan(struct sig_pri_span *pri);
+
 static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 {
 	int x;
@@ -2783,7 +3243,7 @@ static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 		}
 		/* Fall through */
 	default:
-		ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
+		ast_log(LOG_NOTICE, "PRI got event: %s (%d) on D-channel of span %d\n",
 			event2str(x), x, pri->span);
 		break;
 	}
@@ -2796,7 +3256,7 @@ static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 		pri_event_noalarm(pri, index, 0);
 		break;
 	case DAHDI_EVENT_REMOVED:
-		pri_queue_for_destruction(pri);
+		pri_destroy_dchan(pri);
 		break;
 	default:
 		break;
@@ -3079,7 +3539,6 @@ struct sig_pri_callback sig_pri_callbacks =
 	.dial_digits = my_pri_dial_digits,
 	.open_media = my_pri_ss7_open_media,
 	.ami_channel_event = my_ami_channel_event,
-	.destroy_later = pri_queue_for_destruction,
 };
 #endif	/* defined(HAVE_PRI) */
 
@@ -3139,34 +3598,6 @@ static void my_ss7_set_loopback(void *pvt, int enable)
 #if defined(HAVE_SS7)
 /*!
  * \internal
- * \brief Find the linkset to which SS7 belongs.
- * \since 11.0
- *
- * \param ss7 structure to match on.
- *
- * \retval linkset if found.
- * \retval NULL if not found.
- */
-static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
-{
-	int idx;
-
-	if (!ss7) {
-		return NULL;
-	}
-
-	for (idx = 0; idx < NUM_SPANS; ++idx) {
-		if (linksets[idx].ss7.ss7 == ss7) {
-			return &linksets[idx].ss7;
-		}
-	}
-	return NULL;
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
-/*!
- * \internal
  * \brief Create a new asterisk channel structure for SS7.
  * \since 1.8
  *
@@ -3179,7 +3610,7 @@ static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
  * \retval ast_channel on success.
  * \retval NULL on error.
  */
-static struct ast_channel *my_new_ss7_ast_channel(void *pvt, int state, enum sig_ss7_law law, char *exten, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *my_new_ss7_ast_channel(void *pvt, int state, enum sig_ss7_law law, char *exten, const struct ast_channel *requestor)
 {
 	struct dahdi_pvt *p = pvt;
 	int audio;
@@ -3212,7 +3643,7 @@ static struct ast_channel *my_new_ss7_ast_channel(void *pvt, int state, enum sig
 		newlaw = DAHDI_LAW_MULAW;
 		break;
 	}
-	return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
+	return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 #endif	/* defined(HAVE_SS7) */
 
@@ -3273,16 +3704,15 @@ struct sig_ss7_callback sig_ss7_callbacks =
 	.set_callerid = my_set_callerid,
 	.set_dnid = my_set_dnid,
 	.open_media = my_pri_ss7_open_media,
-	.find_linkset = my_ss7_find_linkset,
 };
 #endif	/* defined(HAVE_SS7) */
 
 /*!
  * \brief Send MWI state change
  *
- * \param mailbox This is the mailbox associated with the FXO line that the
+ * \arg mailbox_full This is the mailbox associated with the FXO line that the
  *      MWI state has changed on.
- * \param thereornot This argument should simply be set to 1 or 0, to indicate
+ * \arg thereornot This argument should simply be set to 1 or 0, to indicate
  *      whether there are messages waiting or not.
  *
  *  \return nothing
@@ -3295,16 +3725,30 @@ struct sig_ss7_callback sig_ss7_callbacks =
  * 2) It runs the script specified by the mwimonitornotify option to allow
  *    some custom handling of the state change.
  */
-static void notify_message(char *mailbox, int thereornot)
+static void notify_message(char *mailbox_full, int thereornot)
 {
 	char s[sizeof(mwimonitornotify) + 80];
-
-	if (ast_strlen_zero(mailbox)) {
+	struct ast_event *event;
+	char *mailbox, *context;
+
+	/* Strip off @default */
+	context = mailbox = ast_strdupa(mailbox_full);
+	strsep(&context, "@");
+	if (ast_strlen_zero(context))
+		context = "default";
+
+	if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+			AST_EVENT_IE_END))) {
 		return;
 	}
 
-	ast_publish_mwi_state(mailbox, NULL, thereornot, thereornot);
-	if (!ast_strlen_zero(mwimonitornotify)) {
+	ast_event_queue_and_cache(event);
+
+	if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
 		snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
 		ast_safe_system(s);
 	}
@@ -3418,7 +3862,8 @@ struct analog_callback analog_callbacks =
 /*! Round robin search locations. */
 static struct dahdi_pvt *round_robin[32];
 
-int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
+#define dahdi_get_index(ast, p, nullok)	_dahdi_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
+static int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
 {
 	int res;
 	if (p->subs[SUB_REAL].owner == ast)
@@ -3493,37 +3938,6 @@ static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
 	}
 }
 
-static void publish_channel_alarm_clear(int channel)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
-	if (!dahdi_chan) {
-		return;
-	}
-
-	ast_str_set(&dahdi_chan, 0, "%d", channel);
-	ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
-	body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
-}
-
-static void publish_span_alarm_clear(int span)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-
-	ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
-	body = ast_json_pack("{s: i}", "Span", span);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
-}
-
 static void handle_clear_alarms(struct dahdi_pvt *p)
 {
 #if defined(HAVE_PRI)
@@ -3533,10 +3947,22 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
 #endif	/* defined(HAVE_PRI) */
 
 	if (report_alarms & REPORT_CHANNEL_ALARMS) {
-		publish_channel_alarm_clear(p->channel);
+		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
 	}
 	if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
-		publish_span_alarm_clear(p->span);
+		ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", p->span);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_SYSTEM, "SpanAlarmClear", "Span: %d\r\n", p->span);
 	}
 }
 
@@ -3703,7 +4129,7 @@ static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, con
 	}
 	if (!p->mfcr2_accept_on_offer) {
 		/* The user wants us to start the PBX thread right away without accepting the call first */
-		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
+		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, callid);
 		if (c) {
 			/* Done here, don't disable reading now since we still need to generate MF tones to accept
 			   the call or reject it and detect the tone off condition of the other end, all of this
@@ -3733,6 +4159,7 @@ static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
 	ast_mutex_unlock(&p->lock);
 }
 
+static void dahdi_enable_ec(struct dahdi_pvt *p);
 static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
 {
 	struct dahdi_pvt *p = NULL;
@@ -3740,7 +4167,7 @@ static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t
 	struct ast_callid *callid = NULL;
 	int callid_created = ast_callid_threadstorage_auto(&callid);
 	p = openr2_chan_get_client_data(r2chan);
-	dahdi_ec_enable(p);
+	dahdi_enable_ec(p);
 	p->mfcr2_call_accepted = 1;
 	/* if it's an incoming call ... */
 	if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
@@ -3757,7 +4184,7 @@ static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t
 			}
 			goto dahdi_r2_on_call_accepted_cleanup;
 		}
-		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
+		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, callid);
 		if (c) {
 			/* chan_dahdi will take care of reading from now on in the PBX thread, tell the
 			   library to forget about it */
@@ -4197,7 +4624,7 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
 {
 	struct dahdi_pvt *pvt;
 	int idx;
-	int dtmf = -1;
+	int dtmf;
 	int res;
 
 	pvt = ast_channel_tech_pvt(chan);
@@ -4220,21 +4647,39 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
 		break;
 	}
 #endif
-	if ((dtmf = digit_to_dtmfindex(digit)) == -1)
+	dtmf = digit_to_dtmfindex(digit);
+	if (dtmf == -1) {
+		/* Not a valid DTMF digit */
 		goto out;
+	}
 
 	if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
-		char dial_str[] = { 'T', digit, '\0' };
+		struct dahdi_dialoperation zo = {
+			.op = DAHDI_DIAL_OP_APPEND,
+		};
 
-		res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
-		if (!res) {
+		zo.dialstr[0] = 'T';
+		zo.dialstr[1] = digit;
+		zo.dialstr[2] = '\0';
+		if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
+			ast_log(LOG_WARNING, "Channel %s couldn't dial digit %c: %s\n",
+				ast_channel_name(chan), digit, strerror(errno));
+		else
 			pvt->dialing = 1;
-		}
 	} else {
-		ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
-			ast_channel_name(chan), digit);
 		pvt->dialing = 1;
 		pvt->begindigit = digit;
+
+		/* Flush the write buffer in DAHDI to start sending the digit immediately. */
+		dtmf = DAHDI_FLUSH_WRITE;
+		res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
+		if (res) {
+			ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
+				pvt->channel, strerror(errno));
+		}
+
+		ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
+			ast_channel_name(chan), digit);
 	}
 
 out:
@@ -4527,7 +4972,7 @@ static int reset_conf(struct dahdi_pvt *p)
 	return 0;
 }
 
-void dahdi_conf_update(struct dahdi_pvt *p)
+static int update_conf(struct dahdi_pvt *p)
 {
 	int needconf = 0;
 	int x;
@@ -4580,9 +5025,10 @@ void dahdi_conf_update(struct dahdi_pvt *p)
 		p->confno = -1;
 	}
 	ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
+	return 0;
 }
 
-void dahdi_ec_enable(struct dahdi_pvt *p)
+static void dahdi_enable_ec(struct dahdi_pvt *p)
 {
 	int res;
 	if (!p)
@@ -4654,7 +5100,7 @@ static void dahdi_train_ec(struct dahdi_pvt *p)
 	}
 }
 
-void dahdi_ec_disable(struct dahdi_pvt *p)
+static void dahdi_disable_ec(struct dahdi_pvt *p)
 {
 	int res;
 
@@ -4672,22 +5118,13 @@ void dahdi_ec_disable(struct dahdi_pvt *p)
 	p->echocanon = 0;
 }
 
-static int set_hwgain(int fd, float gain, int tx_direction)
-{
-	struct dahdi_hwgain hwgain;
-
-	hwgain.newgain = gain * 10.0;
-	hwgain.tx = tx_direction;
-	return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
-}
-
 /* perform a dynamic range compression transform on the given sample */
 static int drc_sample(int sample, float drc)
 {
 	float neg;
 	float shallow, steep;
 	float max = SHRT_MAX;
-
+	
 	neg = (sample < 0 ? -1 : 1);
 	steep = drc*sample;
 	shallow = neg*(max-max/drc)+(float)sample/drc;
@@ -4963,12 +5400,14 @@ static int restore_conference(struct dahdi_pvt *p)
 
 static int send_cwcidspill(struct dahdi_pvt *p)
 {
+	struct ast_format tmpfmt;
+
 	p->callwaitcas = 0;
 	p->cidcwexpire = 0;
 	p->cid_suppress_expire = 0;
 	if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
 		return -1;
-	p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
+	p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 	/* Make sure we account for the end */
 	p->cidlen += READ_SIZE * 4;
 	p->cidpos = 0;
@@ -4980,15 +5419,24 @@ static int send_cwcidspill(struct dahdi_pvt *p)
 static int has_voicemail(struct dahdi_pvt *p)
 {
 	int new_msgs;
-	RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
-
-	mwi_message = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
-	if (mwi_message) {
-		struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
-		new_msgs = mwi_state->new_msgs;
-	} else {
+	struct ast_event *event;
+	char *mailbox, *context;
+
+	mailbox = context = ast_strdupa(p->mailbox);
+	strsep(&context, "@");
+	if (ast_strlen_zero(context))
+		context = "default";
+
+	event = ast_event_get_cached(AST_EVENT_MWI,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+		AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+		AST_EVENT_IE_END);
+
+	if (event) {
+		new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+		ast_event_destroy(event);
+	} else
 		new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
-	}
 
 	return new_msgs;
 }
@@ -5034,7 +5482,7 @@ static int send_callerid(struct dahdi_pvt *p)
 static int dahdi_callwait(struct ast_channel *ast)
 {
 	struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
-
+	struct ast_format tmpfmt;
 	p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
 	if (p->cidspill) {
 		ast_log(LOG_WARNING, "Spill already exists?!?\n");
@@ -5051,11 +5499,11 @@ static int dahdi_callwait(struct ast_channel *ast)
 	/* Silence */
 	memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
 	if (!p->callwaitrings && p->callwaitingcallerid) {
-		ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
+		ast_gen_cas(p->cidspill, 1, 2400 + 680, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		p->callwaitcas = 1;
 		p->cidlen = 2400 + 680 + READ_SIZE * 4;
 	} else {
-		ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
+		ast_gen_cas(p->cidspill, 1, 2400, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 		p->callwaitcas = 0;
 		p->cidlen = 2400 + READ_SIZE * 4;
 	}
@@ -5133,7 +5581,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 		set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
 	} else {
 		set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
-	}
+	}	
 
 #ifdef HAVE_PRI
 	if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -5153,7 +5601,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 #endif	/* defined(HAVE_SS7) */
 
 	/* If this is analog signalling we can exit here */
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		p->callwaitrings = 0;
 		res = analog_call(p->sig_pvt, ast, rdest, timeout);
 		ast_mutex_unlock(&p->lock);
@@ -5504,7 +5952,7 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 	}
 
 	if (p->sig_pvt) {
-		if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
+		if (analog_lib_handles(p->sig, 0, 0)) {
 			analog_delete(p->sig_pvt);
 		}
 		switch (p->sig) {
@@ -5523,12 +5971,10 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 		}
 	}
 	ast_free(p->cidspill);
-	if (p->use_smdi) {
-		ao2_cleanup(p->smdi_iface);
-	}
-	if (p->mwi_event_sub) {
-		p->mwi_event_sub = stasis_unsubscribe(p->mwi_event_sub);
-	}
+	if (p->use_smdi)
+		ast_smdi_interface_unref(p->smdi_iface);
+	if (p->mwi_event_sub)
+		ast_event_unsubscribe(p->mwi_event_sub);
 	if (p->vars) {
 		ast_variables_destroy(p->vars);
 	}
@@ -5541,9 +5987,8 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 
 	ast_mutex_destroy(&p->lock);
 	dahdi_close_sub(p, SUB_REAL);
-	if (p->owner) {
+	if (p->owner)
 		ast_channel_tech_pvt_set(p->owner, NULL);
-	}
 	ast_free(p);
 }
 
@@ -5907,7 +6352,7 @@ static int dahdi_hangup(struct ast_channel *ast)
 
 	ast_mutex_lock(&p->lock);
 	p->exten[0] = '\0';
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		dahdi_confmute(p, 0);
 		restore_gains(p);
 		p->ignoredtmf = 0;
@@ -5965,14 +6410,14 @@ static int dahdi_hangup(struct ast_channel *ast)
 		sig_pri_hangup(p->sig_pvt, ast);
 
 		tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-		dahdi_ec_disable(p);
+		dahdi_disable_ec(p);
 
 		x = 0;
 		ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
 		p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
 		p->rdnis[0] = '\0';
-		dahdi_conf_update(p);
+		update_conf(p);
 		reset_conf(p);
 
 		/* Restore data mode */
@@ -6027,13 +6472,13 @@ static int dahdi_hangup(struct ast_channel *ast)
 		sig_ss7_hangup(p->sig_pvt, ast);
 
 		tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-		dahdi_ec_disable(p);
+		dahdi_disable_ec(p);
 
 		x = 0;
 		ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
 		p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
-		dahdi_conf_update(p);
+		update_conf(p);
 		reset_conf(p);
 
 		/* Restore data mode */
@@ -6114,7 +6559,8 @@ static int dahdi_hangup(struct ast_channel *ast)
 				p->owner = p->subs[SUB_REAL].owner;
 				if (ast_channel_state(p->owner) != AST_STATE_UP)
 					p->subs[SUB_REAL].needanswer = 1;
-				ast_queue_unhold(p->subs[SUB_REAL].owner);
+				if (ast_bridged_channel(p->subs[SUB_REAL].owner))
+					ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
 			} else if (p->subs[SUB_THREEWAY].dfd > -1) {
 				swap_subs(p, SUB_THREEWAY, SUB_REAL);
 				unalloc_sub(p, SUB_THREEWAY);
@@ -6135,8 +6581,10 @@ static int dahdi_hangup(struct ast_channel *ast)
 			if (p->subs[SUB_CALLWAIT].inthreeway) {
 				/* This is actually part of a three way, placed on hold.  Place the third part
 				   on music on hold now */
-				if (p->subs[SUB_THREEWAY].owner) {
-					ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
+				if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+					ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
 				p->subs[SUB_THREEWAY].inthreeway = 0;
 				/* Make it the call wait now */
@@ -6148,8 +6596,10 @@ static int dahdi_hangup(struct ast_channel *ast)
 			if (p->subs[SUB_CALLWAIT].inthreeway) {
 				/* The other party of the three way call is currently in a call-wait state.
 				   Start music on hold for them, and take the main guy out of the third call */
-				if (p->subs[SUB_CALLWAIT].owner) {
-					ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
+				if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
+					ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
 				p->subs[SUB_CALLWAIT].inthreeway = 0;
 			}
@@ -6254,7 +6704,7 @@ static int dahdi_hangup(struct ast_channel *ast)
 			break;
 		}
 		if (p->sig)
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 		x = 0;
 		ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
 		ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
@@ -6265,7 +6715,7 @@ static int dahdi_hangup(struct ast_channel *ast)
 		p->waitingfordt.tv_sec = 0;
 		p->dialing = 0;
 		p->rdnis[0] = '\0';
-		dahdi_conf_update(p);
+		update_conf(p);
 		reset_conf(p);
 		/* Restore data mode */
 		switch (p->sig) {
@@ -6323,7 +6773,7 @@ static int dahdi_answer(struct ast_channel *ast)
 		return 0;
 	}
 
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		res = analog_answer(p->sig_pvt, ast);
 		ast_mutex_unlock(&p->lock);
 		return res;
@@ -6371,7 +6821,7 @@ static int dahdi_answer(struct ast_channel *ast)
 	return res;
 }
 
-void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
+static void disable_dtmf_detect(struct dahdi_pvt *p)
 {
 	int val = 0;
 
@@ -6385,7 +6835,7 @@ void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
 	}
 }
 
-void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
+static void enable_dtmf_detect(struct dahdi_pvt *p)
 {
 	int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
 
@@ -6510,7 +6960,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
 		}
 		ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
 			(*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
-		dahdi_ec_disable(p);
+		dahdi_disable_ec(p);
 		/* otherwise, turn it on */
 		if (!p->didtdd) { /* if havent done it yet */
 			unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
@@ -6592,7 +7042,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
 		if (!*cp) {
 			ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
 			x = 0;
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 		} else {
 			ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
 			x = 1;
@@ -6627,19 +7077,19 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
 		cp = (char *) data;
 		if (*cp) {
 			ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
-			dahdi_ec_enable(p);
+			dahdi_enable_ec(p);
 		} else {
 			ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 		}
 		break;
 	case AST_OPTION_DIGIT_DETECT:
 		cp = (char *) data;
 		ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
 		if (*cp) {
-			dahdi_dtmf_detect_enable(p);
+			enable_dtmf_detect(p);
 		} else {
-			dahdi_dtmf_detect_disable(p);
+			disable_dtmf_detect(p);
 		}
 		break;
 	case AST_OPTION_FAX_DETECT:
@@ -6834,11 +7284,11 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 	} else if (!strcasecmp(data, "echocan_mode")) {
 		if (!strcasecmp(value, "on")) {
 			ast_mutex_lock(&p->lock);
-			dahdi_ec_enable(p);
+			dahdi_enable_ec(p);
 			ast_mutex_unlock(&p->lock);
 		} else if (!strcasecmp(value, "off")) {
 			ast_mutex_lock(&p->lock);
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 			ast_mutex_unlock(&p->lock);
 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
 		} else if (!strcasecmp(value, "fax")) {
@@ -6846,7 +7296,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
 			ast_mutex_lock(&p->lock);
 			if (!p->echocanon) {
-				dahdi_ec_enable(p);
+				dahdi_enable_ec(p);
 			}
 			if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
 				ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -6857,7 +7307,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
 			ast_mutex_lock(&p->lock);
 			if (!p->echocanon) {
-				dahdi_ec_enable(p);
+				dahdi_enable_ec(p);
 			}
 			if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
 				ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -6875,7 +7325,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 	return res;
 }
 
-void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
+static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
 {
 	/* Unlink a specific slave or all slaves/masters from a given master */
 	int x;
@@ -6923,7 +7373,7 @@ void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master
 		}
 		master->master = NULL;
 	}
-	dahdi_conf_update(master);
+	update_conf(master);
 	if (needlock) {
 		if (slave)
 			ast_mutex_unlock(&slave->lock);
@@ -6931,8 +7381,7 @@ void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master
 	}
 }
 
-void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
-{
+static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
 	int x;
 	if (!slave || !master) {
 		ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
@@ -6955,6 +7404,373 @@ void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
 	ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
+static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
+{
+	struct ast_channel *who;
+	struct dahdi_pvt *p0, *p1, *op0, *op1;
+	struct dahdi_pvt *master = NULL, *slave = NULL;
+	struct ast_frame *f;
+	int inconf = 0;
+	int nothingok = 1;
+	int ofd0, ofd1;
+	int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
+	int os0 = -1, os1 = -1;
+	int priority = 0;
+	struct ast_channel *oc0, *oc1;
+	enum ast_bridge_result res;
+	struct timeval start = ast_tvnow();
+#ifdef PRI_2BCT
+	int triedtopribridge = 0;
+	q931_call *q931c0;
+	q931_call *q931c1;
+#endif
+
+	/* For now, don't attempt to native bridge if either channel needs DTMF detection.
+	   There is code below to handle it properly until DTMF is actually seen,
+	   but due to currently unresolved issues it's ignored...
+	*/
+
+	if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
+		return AST_BRIDGE_FAILED_NOWARN;
+
+	ast_channel_lock_both(c0, c1);
+
+	p0 = ast_channel_tech_pvt(c0);
+	p1 = ast_channel_tech_pvt(c1);
+	/* cant do pseudo-channels here */
+	if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+
+	oi0 = dahdi_get_index(c0, p0, 0);
+	oi1 = dahdi_get_index(c1, p1, 0);
+	if ((oi0 < 0) || (oi1 < 0)) {
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED;
+	}
+
+	op0 = p0 = ast_channel_tech_pvt(c0);
+	op1 = p1 = ast_channel_tech_pvt(c1);
+	ofd0 = ast_channel_fd(c0, 0);
+	ofd1 = ast_channel_fd(c1, 0);
+	oc0 = p0->owner;
+	oc1 = p1->owner;
+
+	if (ast_mutex_trylock(&p0->lock)) {
+		/* Don't block, due to potential for deadlock */
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
+		return AST_BRIDGE_RETRY;
+	}
+	if (ast_mutex_trylock(&p1->lock)) {
+		/* Don't block, due to potential for deadlock */
+		ast_mutex_unlock(&p0->lock);
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
+		return AST_BRIDGE_RETRY;
+	}
+
+	if ((p0->callwaiting && p0->callwaitingcallerid)
+		|| (p1->callwaiting && p1->callwaitingcallerid)) {
+		/*
+		 * Call Waiting Caller ID requires DTMF detection to know if it
+		 * can send the CID spill.
+		 *
+		 * For now, don't attempt to native bridge if either channel
+		 * needs DTMF detection.  There is code below to handle it
+		 * properly until DTMF is actually seen, but due to currently
+		 * unresolved issues it's ignored...
+		 */
+		ast_mutex_unlock(&p0->lock);
+		ast_mutex_unlock(&p1->lock);
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+
+#if defined(HAVE_PRI)
+	if ((dahdi_sig_pri_lib_handles(p0->sig)
+			&& ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
+		|| (dahdi_sig_pri_lib_handles(p1->sig)
+			&& ((struct sig_pri_chan *) p1->sig_pvt)->no_b_channel)) {
+		/*
+		 * PRI nobch channels (hold and call waiting) are equivalent to
+		 * pseudo channels and cannot be done here.
+		 */
+		ast_mutex_unlock(&p0->lock);
+		ast_mutex_unlock(&p1->lock);
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+#endif	/* defined(HAVE_PRI) */
+
+	if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
+		if (p0->owner && p1->owner) {
+			/* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
+			if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
+				master = p0;
+				slave = p1;
+				inconf = 1;
+			} else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
+				master = p1;
+				slave = p0;
+				inconf = 1;
+			} else {
+				ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
+				ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
+					p0->channel,
+					oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
+					p0->subs[SUB_REAL].inthreeway, p0->channel,
+					oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
+					p1->subs[SUB_REAL].inthreeway);
+			}
+			nothingok = 0;
+		}
+	} else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
+		if (p1->subs[SUB_THREEWAY].inthreeway) {
+			master = p1;
+			slave = p0;
+			nothingok = 0;
+		}
+	} else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
+		if (p0->subs[SUB_THREEWAY].inthreeway) {
+			master = p0;
+			slave = p1;
+			nothingok = 0;
+		}
+	} else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
+		/* We have a real and a call wait.  If we're in a three way call, put us in it, otherwise,
+		   don't put us in anything */
+		if (p1->subs[SUB_CALLWAIT].inthreeway) {
+			master = p1;
+			slave = p0;
+			nothingok = 0;
+		}
+	} else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
+		/* Same as previous */
+		if (p0->subs[SUB_CALLWAIT].inthreeway) {
+			master = p0;
+			slave = p1;
+			nothingok = 0;
+		}
+	}
+	ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
+		master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
+	if (master && slave) {
+		/* Stop any tones, or play ringtone as appropriate.  If they're bridged
+		   in an active threeway call with a channel that is ringing, we should
+		   indicate ringing. */
+		if ((oi1 == SUB_THREEWAY) &&
+			p1->subs[SUB_THREEWAY].inthreeway &&
+			p1->subs[SUB_REAL].owner &&
+			p1->subs[SUB_REAL].inthreeway &&
+			(ast_channel_state(p1->subs[SUB_REAL].owner) == AST_STATE_RINGING)) {
+			ast_debug(1,
+				"Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
+				p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
+			tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
+			os1 = ast_channel_state(p1->subs[SUB_REAL].owner);
+		} else {
+			ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
+				p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
+			tone_zone_play_tone(p0->subs[oi0].dfd, -1);
+		}
+		if ((oi0 == SUB_THREEWAY) &&
+			p0->subs[SUB_THREEWAY].inthreeway &&
+			p0->subs[SUB_REAL].owner &&
+			p0->subs[SUB_REAL].inthreeway &&
+			(ast_channel_state(p0->subs[SUB_REAL].owner) == AST_STATE_RINGING)) {
+			ast_debug(1,
+				"Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
+				p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
+			tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
+			os0 = ast_channel_state(p0->subs[SUB_REAL].owner);
+		} else {
+			ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
+				p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
+			tone_zone_play_tone(p1->subs[oi1].dfd, -1);
+		}
+		if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
+			if (!p0->echocanbridged || !p1->echocanbridged) {
+				/* Disable echo cancellation if appropriate */
+				dahdi_disable_ec(p0);
+				dahdi_disable_ec(p1);
+			}
+		}
+		dahdi_link(slave, master);
+		master->inconference = inconf;
+	} else if (!nothingok)
+		ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
+
+	update_conf(p0);
+	update_conf(p1);
+	t0 = p0->subs[SUB_REAL].inthreeway;
+	t1 = p1->subs[SUB_REAL].inthreeway;
+
+	ast_mutex_unlock(&p0->lock);
+	ast_mutex_unlock(&p1->lock);
+
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
+
+	/* Native bridge failed */
+	if ((!master || !slave) && !nothingok) {
+		dahdi_enable_ec(p0);
+		dahdi_enable_ec(p1);
+		return AST_BRIDGE_FAILED;
+	}
+
+	ast_verb(3, "Native bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
+
+	if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
+		disable_dtmf_detect(op0);
+
+	if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
+		disable_dtmf_detect(op1);
+
+	for (;;) {
+		struct ast_channel *c0_priority[2] = {c0, c1};
+		struct ast_channel *c1_priority[2] = {c1, c0};
+		int ms;
+
+		/* Here's our main loop...  Start by locking things, looking for private parts,
+		   and then balking if anything is wrong */
+
+		ast_channel_lock_both(c0, c1);
+
+		p0 = ast_channel_tech_pvt(c0);
+		p1 = ast_channel_tech_pvt(c1);
+
+		if (op0 == p0)
+			i0 = dahdi_get_index(c0, p0, 1);
+		if (op1 == p1)
+			i1 = dahdi_get_index(c1, p1, 1);
+
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		ms = ast_remaining_ms(start, timeoutms);
+		if (!ms ||
+			(op0 != p0) ||
+			(op1 != p1) ||
+			(ofd0 != ast_channel_fd(c0, 0)) ||
+			(ofd1 != ast_channel_fd(c1, 0)) ||
+			(p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != ast_channel_state(p0->subs[SUB_REAL].owner))) ||
+			(p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != ast_channel_state(p1->subs[SUB_REAL].owner))) ||
+			(oc0 != p0->owner) ||
+			(oc1 != p1->owner) ||
+			(t0 != p0->subs[SUB_REAL].inthreeway) ||
+			(t1 != p1->subs[SUB_REAL].inthreeway) ||
+			(oi0 != i0) ||
+			(oi1 != i1)) {
+			ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
+				op0->channel, oi0, op1->channel, oi1);
+			res = AST_BRIDGE_RETRY;
+			goto return_from_bridge;
+		}
+
+#ifdef PRI_2BCT
+		if (!triedtopribridge) {
+			triedtopribridge = 1;
+			if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
+				ast_mutex_lock(&p0->pri->lock);
+				switch (p0->sig) {
+				case SIG_PRI_LIB_HANDLE_CASES:
+					q931c0 = ((struct sig_pri_chan *) (p0->sig_pvt))->call;
+					break;
+				default:
+					q931c0 = NULL;
+					break;
+				}
+				switch (p1->sig) {
+				case SIG_PRI_LIB_HANDLE_CASES:
+					q931c1 = ((struct sig_pri_chan *) (p1->sig_pvt))->call;
+					break;
+				default:
+					q931c1 = NULL;
+					break;
+				}
+				if (q931c0 && q931c1) {
+					pri_channel_bridge(q931c0, q931c1);
+				}
+				ast_mutex_unlock(&p0->pri->lock);
+			}
+		}
+#endif
+
+		who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &ms);
+		if (!who) {
+			ast_debug(1, "Ooh, empty read...\n");
+			continue;
+		}
+		f = ast_read(who);
+		switch (f ? f->frametype : AST_FRAME_CONTROL) {
+		case AST_FRAME_CONTROL:
+			if (f && f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+				ast_channel_hangupcause_hash_set((who == c0) ? c1 : c0, f->data.ptr, f->datalen);
+				break;
+			}
+			*fo = f;
+			*rc = who;
+			res = AST_BRIDGE_COMPLETE;
+			goto return_from_bridge;
+		case AST_FRAME_DTMF_END:
+			if ((who == c0) && p0->pulsedial) {
+				ast_write(c1, f);
+			} else if ((who == c1) && p1->pulsedial) {
+				ast_write(c0, f);
+			} else {
+				*fo = f;
+				*rc = who;
+				res = AST_BRIDGE_COMPLETE;
+				goto return_from_bridge;
+			}
+			break;
+		case AST_FRAME_TEXT:
+			if (who == c0) {
+				ast_write(c1, f);
+			} else {
+				ast_write(c0, f);
+			}
+			break;
+		case AST_FRAME_VOICE:
+			/* Native bridge handles voice frames in hardware. */
+		case AST_FRAME_NULL:
+			break;
+		default:
+			ast_debug(1, "Chan '%s' is discarding frame of frametype:%u\n",
+				ast_channel_name(who), f->frametype);
+			break;
+		}
+		ast_frfree(f);
+
+		/* Swap who gets priority */
+		priority = !priority;
+	}
+
+return_from_bridge:
+	if (op0 == p0)
+		dahdi_enable_ec(p0);
+
+	if (op1 == p1)
+		dahdi_enable_ec(p1);
+
+	if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
+		enable_dtmf_detect(op0);
+
+	if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
+		enable_dtmf_detect(op1);
+
+	dahdi_unlink(slave, master, 1);
+
+	return res;
+}
+
 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
 	struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
@@ -6969,12 +7785,12 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 	for (x = 0; x < 3; x++) {
 		if (p->subs[x].owner == oldchan) {
 			if (!x) {
-				dahdi_master_slave_unlink(NULL, p, 0);
+				dahdi_unlink(NULL, p, 0);
 			}
 			p->subs[x].owner = newchan;
 		}
 	}
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		analog_fixup(oldchan, newchan, p->sig_pvt);
 #if defined(HAVE_PRI)
 	} else if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -6985,7 +7801,7 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 		sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
 #endif	/* defined(HAVE_SS7) */
 	}
-	dahdi_conf_update(p);
+	update_conf(p);
 
 	ast_mutex_unlock(&p->lock);
 
@@ -7027,49 +7843,56 @@ static int dahdi_ring_phone(struct dahdi_pvt *p)
 
 static void *analog_ss_thread(void *data);
 
-/*!
- * \internal
- * \brief Attempt to transfer 3-way call.
- *
- * \param p DAHDI private structure.
- *
- * \note On entry these locks are held: real-call, private, 3-way call.
- * \note On exit these locks are held: real-call, private.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
 static int attempt_transfer(struct dahdi_pvt *p)
 {
-	struct ast_channel *owner_real;
-	struct ast_channel *owner_3way;
-	enum ast_transfer_result xfer_res;
-	int res = 0;
-
-	owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
-	owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
-
-	ast_verb(3, "TRANSFERRING %s to %s\n",
-		ast_channel_name(owner_3way), ast_channel_name(owner_real));
-
-	ast_channel_unlock(owner_real);
-	ast_channel_unlock(owner_3way);
-	ast_mutex_unlock(&p->lock);
-
-	xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
-	if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		ast_softhangup(owner_3way, AST_SOFTHANGUP_DEV);
-		res = -1;
+	/* In order to transfer, we need at least one of the channels to
+	   actually be in a call bridge.  We can't conference two applications
+	   together (but then, why would we want to?) */
+	if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
+		/* The three-way person we're about to transfer to could still be in MOH, so
+		   stop if now if appropriate */
+		if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
+			ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
+		if (ast_channel_state(p->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
+			ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
+		}
+		if (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_RING) {
+			tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
+		}
+		 if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+					ast_channel_name(ast_bridged_channel(p->subs[SUB_REAL].owner)), ast_channel_name(p->subs[SUB_THREEWAY].owner));
+			return -1;
+		}
+		/* Orphan the channel after releasing the lock */
+		ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+		unalloc_sub(p, SUB_THREEWAY);
+	} else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+		ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+		if (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_RINGING) {
+			ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
+		}
+		if (ast_channel_state(p->subs[SUB_REAL].owner) == AST_STATE_RING) {
+			tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+		}
+		if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+					ast_channel_name(ast_bridged_channel(p->subs[SUB_THREEWAY].owner)), ast_channel_name(p->subs[SUB_REAL].owner));
+			return -1;
+		}
+		/* Three-way is now the REAL */
+		swap_subs(p, SUB_THREEWAY, SUB_REAL);
+		ast_channel_unlock(p->subs[SUB_REAL].owner);
+		unalloc_sub(p, SUB_THREEWAY);
+		/* Tell the caller not to hangup */
+		return 1;
+	} else {
+		ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+			ast_channel_name(p->subs[SUB_REAL].owner), ast_channel_name(p->subs[SUB_THREEWAY].owner));
+		ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
+		return -1;
 	}
-
-	/* Must leave with these locked. */
-	ast_channel_lock(owner_real);
-	ast_mutex_lock(&p->lock);
-
-	ast_channel_unref(owner_real);
-	ast_channel_unref(owner_3way);
-
-	return res;
+	return 0;
 }
 
 static int check_for_conference(struct dahdi_pvt *p)
@@ -7223,39 +8046,6 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
 	}
 }
 
-static void publish_span_alarm(int span, const char *alarm_txt)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-
-	body = ast_json_pack("{s: i, s: s}",
-		"Span", span,
-		"Alarm", alarm_txt);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
-}
-
-static void publish_channel_alarm(int channel, const char *alarm_txt)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
-	if (!dahdi_chan) {
-		return;
-	}
-
-	ast_str_set(&dahdi_chan, 0, "%d", channel);
-	body = ast_json_pack("{s: s, s: s}",
-		"DAHDIChannel", ast_str_buffer(dahdi_chan),
-		"Alarm", alarm_txt);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM, body);
-}
-
 static void handle_alarms(struct dahdi_pvt *p, int alms)
 {
 	const char *alarm_str;
@@ -7269,12 +8059,28 @@ static void handle_alarms(struct dahdi_pvt *p, int alms)
 	alarm_str = alarm2str(alms);
 	if (report_alarms & REPORT_CHANNEL_ALARMS) {
 		ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
-		publish_channel_alarm(p->channel, alarm_str);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_SYSTEM, "Alarm",
+					  "Alarm: %s\r\n"
+					  "Channel: %d\r\n",
+					  alarm_str, p->channel);
 	}
 
 	if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
 		ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
-		publish_span_alarm(p->span, alarm_str);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_SYSTEM, "SpanAlarm",
+					  "Alarm: %s\r\n"
+					  "Span: %d\r\n",
+					  alarm_str, p->span);
 	}
 }
 
@@ -7428,12 +8234,12 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 			return NULL;
 		}
 		if (!x) { /* if not still dialing in driver */
-			dahdi_ec_enable(p);
+			dahdi_enable_ec(p);
 			if (p->echobreak) {
 				dahdi_train_ec(p);
 				ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
 				p->dop.op = DAHDI_DIAL_OP_REPLACE;
-				res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
+				res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
 				p->echobreak = 0;
 			} else {
 				p->dialing = 0;
@@ -7596,13 +8402,17 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 								p->owner = NULL;
 								/* Ring the phone */
 								dahdi_ring_phone(p);
-							} else if (!attempt_transfer(p)) {
-								/*
-								 * Transfer successful.  Don't actually hang up at this point.
-								 * Let our channel legs of the calls die off as the transfer
-								 * percolates through the core.
-								 */
-								break;
+							} else {
+								if ((res = attempt_transfer(p)) < 0) {
+									ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
+									if (p->subs[SUB_THREEWAY].owner)
+										ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+								} else if (res) {
+									/* Don't actually hang up at this point */
+									if (p->subs[SUB_THREEWAY].owner)
+										ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+									break;
+								}
 							}
 						} else {
 							ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
@@ -7623,7 +8433,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 			}
 			/* Fall through */
 		default:
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 			return NULL;
 		}
 		break;
@@ -7664,11 +8474,14 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 				p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
 			} else
 				p->echobreak = 0;
-			if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
+			if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
+				int saveerr = errno;
+
 				x = DAHDI_ONHOOK;
 				ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
+				ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
 				return NULL;
-			}
+				}
 			p->dialing = 1;
 			return &p->subs[idx].f;
 		}
@@ -7678,7 +8491,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 		case SIG_FXOKS:
 			switch (ast_channel_state(ast)) {
 			case AST_STATE_RINGING:
-				dahdi_ec_enable(p);
+				dahdi_enable_ec(p);
 				dahdi_train_ec(p);
 				p->subs[idx].f.frametype = AST_FRAME_CONTROL;
 				p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
@@ -7700,8 +8513,9 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 					p->subs[idx].f.subclass.integer = 0;
 				} else if (!ast_strlen_zero(p->dop.dialstr)) {
 					/* nick at dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
-					res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
-					if (res) {
+					res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+					if (res < 0) {
+						ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 						p->dop.dialstr[0] = '\0';
 						return NULL;
 					} else {
@@ -7726,7 +8540,8 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 				/* Make sure it stops ringing */
 				dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
 				/* Okay -- probably call waiting*/
-				ast_queue_unhold(p->owner);
+				if (ast_bridged_channel(p->owner))
+					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 				p->subs[idx].needunhold = 1;
 				break;
 			case AST_STATE_RESERVED:
@@ -7880,11 +8695,17 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 				p->cidcwexpire = 0;
 				p->cid_suppress_expire = 0;
 				/* Start music on hold if appropriate */
-				if (!p->subs[SUB_CALLWAIT].inthreeway) {
-					ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
+				if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
+					ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
 				p->subs[SUB_CALLWAIT].needhold = 1;
-				ast_queue_hold(p->subs[SUB_REAL].owner, p->mohsuggest);
+				if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
+					ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+				}
 				p->subs[SUB_REAL].needunhold = 1;
 			} else if (!p->subs[SUB_THREEWAY].owner) {
 				if (!p->threewaycalling) {
@@ -7932,7 +8753,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 					 */
 					ast_mutex_unlock(&p->lock);
 					ast_channel_unlock(ast);
-					chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, NULL, callid);
+					chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, callid);
 					ast_channel_lock(ast);
 					ast_mutex_lock(&p->lock);
 					if (p->dahditrcallerid) {
@@ -7946,7 +8767,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 					/* Swap things around between the three-way and real call */
 					swap_subs(p, SUB_THREEWAY, SUB_REAL);
 					/* Disable echo canceller for better dialing */
-					dahdi_ec_disable(p);
+					dahdi_disable_ec(p);
 					res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
 					if (res)
 						ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
@@ -7956,13 +8777,17 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 					} else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
 						ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
 						res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
-						dahdi_ec_enable(p);
+						dahdi_enable_ec(p);
 						ast_hangup(chan);
 					} else {
 						ast_verb(3, "Started three way call on channel %d\n", p->channel);
 
-						/* Start music on hold */
-						ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
+						/* Start music on hold if appropriate */
+						if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+							ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+								S_OR(p->mohsuggest, NULL),
+								!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+						}
 						p->subs[SUB_THREEWAY].needhold = 1;
 					}
 					ast_callid_threadstorage_auto_clean(callid, callid_created);
@@ -7999,9 +8824,8 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 							swap_subs(p, SUB_THREEWAY, SUB_REAL);
 							otherindex = SUB_REAL;
 						}
-						if (p->subs[otherindex].owner) {
-							ast_queue_unhold(p->subs[otherindex].owner);
-						}
+						if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
+							ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
 						p->subs[otherindex].needunhold = 1;
 						p->owner = p->subs[SUB_REAL].owner;
 					} else {
@@ -8009,16 +8833,15 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 						swap_subs(p, SUB_THREEWAY, SUB_REAL);
 						ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
 						p->owner = p->subs[SUB_REAL].owner;
-						if (p->subs[SUB_REAL].owner) {
-							ast_queue_unhold(p->subs[SUB_REAL].owner);
-						}
+						if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
+							ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
 						p->subs[SUB_REAL].needunhold = 1;
-						dahdi_ec_enable(p);
+						dahdi_enable_ec(p);
 					}
 				}
 			}
 winkflashdone:
-			dahdi_conf_update(p);
+			update_conf(p);
 			break;
 		case SIG_EM:
 		case SIG_EM_E1:
@@ -8063,8 +8886,9 @@ winkflashdone:
 		case SIG_EMWINK:
 			/* FGD MF and EMWINK *Must* wait for wink */
 			if (!ast_strlen_zero(p->dop.dialstr)) {
-				res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
-				if (res) {
+				res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+				if (res < 0) {
+					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 					p->dop.dialstr[0] = '\0';
 					return NULL;
 				} else
@@ -8092,8 +8916,9 @@ winkflashdone:
 		case SIG_SFWINK:
 		case SIG_SF_FEATD:
 			if (!ast_strlen_zero(p->dop.dialstr)) {
-				res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
-				if (res) {
+				res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+				if (res < 0) {
+					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 					p->dop.dialstr[0] = '\0';
 					return NULL;
 				} else
@@ -8204,14 +9029,13 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
 			(res != DAHDI_EVENT_HOOKCOMPLETE)) {
 			ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
 			p->owner = p->subs[SUB_REAL].owner;
-			if (p->owner) {
-				ast_queue_unhold(p->owner);
-			}
+			if (p->owner && ast_bridged_channel(p->owner))
+				ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 			p->subs[SUB_REAL].needunhold = 1;
 		}
 		switch (res) {
 		case DAHDI_EVENT_ONHOOK:
-			dahdi_ec_disable(p);
+			dahdi_disable_ec(p);
 			if (p->owner) {
 				ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
 				dahdi_ring_phone(p);
@@ -8220,10 +9044,10 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
 				p->cid_suppress_expire = 0;
 			} else
 				ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-			dahdi_conf_update(p);
+			update_conf(p);
 			break;
 		case DAHDI_EVENT_RINGOFFHOOK:
-			dahdi_ec_enable(p);
+			dahdi_enable_ec(p);
 			dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
 			if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
 				p->subs[SUB_REAL].needanswer = 1;
@@ -8250,11 +9074,12 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
 				p->callwaitingrepeat = 0;
 				p->cidcwexpire = 0;
 				p->cid_suppress_expire = 0;
-				ast_queue_unhold(p->owner);
+				if (ast_bridged_channel(p->owner))
+					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 				p->subs[SUB_REAL].needunhold = 1;
 			} else
 				ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-			dahdi_conf_update(p);
+			update_conf(p);
 			break;
 		default:
 			ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
@@ -8292,7 +9117,7 @@ static struct ast_frame *dahdi_exception(struct ast_channel *ast)
 	struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
 	struct ast_frame *f;
 	ast_mutex_lock(&p->lock);
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 		struct analog_pvt *analog_p = p->sig_pvt;
 		f = analog_exception(analog_p, ast);
 	} else {
@@ -8398,7 +9223,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 			/* if the call is already accepted and we already delivered AST_CONTROL_RINGING
 			 * now enqueue a progress frame to bridge the media up */
 			if (p->mfcr2_call_accepted &&
-				!p->mfcr2_progress_sent &&
+				!p->mfcr2_progress_sent && 
 				ast_channel_state(ast) == AST_STATE_RINGING) {
 				ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
 				ast_queue_frame(p->owner, &fr);
@@ -8489,7 +9314,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 	 * if this channel owns the private.
 	 */
 	if (p->fake_event && p->owner == ast) {
-		if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 			struct analog_pvt *analog_p = p->sig_pvt;
 
 			f = analog_exception(analog_p, ast);
@@ -8500,20 +9325,25 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 		return f;
 	}
 
-	if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) {
 		if (!p->subs[idx].linear) {
 			p->subs[idx].linear = 1;
 			res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
 			if (res)
 				ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
 		}
-	} else {
+	} else if ((ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) ||
+		(ast_channel_rawreadformat(ast)->id == AST_FORMAT_ALAW)) {
 		if (p->subs[idx].linear) {
 			p->subs[idx].linear = 0;
 			res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
 			if (res)
 				ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
 		}
+	} else {
+		ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast_channel_rawreadformat(ast)));
+		ast_mutex_unlock(&p->lock);
+		return NULL;
 	}
 	readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
 	CHECK_BLOCKING(ast);
@@ -8528,7 +9358,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 				ast_mutex_unlock(&p->lock);
 				return &p->subs[idx].f;
 			} else if (errno == ELAST) {
-				if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+				if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 					struct analog_pvt *analog_p = p->sig_pvt;
 					f = analog_exception(analog_p, ast);
 				} else {
@@ -8542,7 +9372,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 	}
 	if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
 		ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-		if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 			struct analog_pvt *analog_p = p->sig_pvt;
 			f = analog_exception(analog_p, ast);
 		} else {
@@ -8603,7 +9433,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 	}
 
 	p->subs[idx].f.frametype = AST_FRAME_VOICE;
-	p->subs[idx].f.subclass.format = ast_channel_rawreadformat(ast);
+	ast_format_copy(&p->subs[idx].f.subclass.format, ast_channel_rawreadformat(ast));
 	p->subs[idx].f.samples = READ_SIZE;
 	p->subs[idx].f.mallocd = 0;
 	p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
@@ -8695,8 +9525,9 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 						ast_dsp_set_features(p->dsp, p->dsp_features);
 						ast_debug(1, "Got 10 samples of dialtone!\n");
 						if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
-							res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
-							if (res) {
+							res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+							if (res < 0) {
+								ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel);
 								p->dop.dialstr[0] = '\0';
 								ast_mutex_unlock(&p->lock);
 								ast_frfree(f);
@@ -8720,7 +9551,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 		switch (f->frametype) {
 		case AST_FRAME_DTMF_BEGIN:
 		case AST_FRAME_DTMF_END:
-			if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+			if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 				analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
 			} else {
 				dahdi_handle_dtmf(ast, idx, &f);
@@ -8771,39 +9602,61 @@ static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int
 
 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 {
-	struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
+	struct dahdi_pvt *p;
 	int res;
 	int idx;
+
+	/* Write a frame of (presumably voice) data */
+	if (frame->frametype != AST_FRAME_VOICE) {
+		if (frame->frametype != AST_FRAME_IMAGE) {
+			ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n",
+				frame->frametype);
+		}
+		return 0;
+	}
+	if ((frame->subclass.format.id != AST_FORMAT_SLINEAR) &&
+		(frame->subclass.format.id != AST_FORMAT_ULAW) &&
+		(frame->subclass.format.id != AST_FORMAT_ALAW)) {
+		ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
+			ast_getformatname(&frame->subclass.format));
+		return -1;
+	}
+
+	/* Return if it's not valid data */
+	if (!frame->data.ptr || !frame->datalen) {
+		return 0;
+	}
+
+	p = ast_channel_tech_pvt(ast);
+	ast_mutex_lock(&p->lock);
+
 	idx = dahdi_get_index(ast, p, 0);
 	if (idx < 0) {
+		ast_mutex_unlock(&p->lock);
 		ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast_channel_name(ast));
 		return -1;
 	}
 
-	/* Write a frame of (presumably voice) data */
-	if (frame->frametype != AST_FRAME_VOICE) {
-		if (frame->frametype != AST_FRAME_IMAGE)
-			ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n", frame->frametype);
-		return 0;
-	}
 	if (p->dialing) {
-		ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",ast_channel_name(ast));
+		ast_mutex_unlock(&p->lock);
+		ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
+			ast_channel_name(ast));
 		return 0;
 	}
 	if (!p->owner) {
-		ast_debug(5, "Dropping frame since there is no active owner on %s...\n",ast_channel_name(ast));
+		ast_mutex_unlock(&p->lock);
+		ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
+			ast_channel_name(ast));
 		return 0;
 	}
 	if (p->cidspill) {
+		ast_mutex_unlock(&p->lock);
 		ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
 			ast_channel_name(ast));
 		return 0;
 	}
-	/* Return if it's not valid data */
-	if (!frame->data.ptr || !frame->datalen)
-		return 0;
 
-	if (ast_format_cmp(frame->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	if (frame->subclass.format.id == AST_FORMAT_SLINEAR) {
 		if (!p->subs[idx].linear) {
 			p->subs[idx].linear = 1;
 			res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
@@ -8811,8 +9664,7 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 				ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
 		}
 		res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
-	} else if (ast_format_cmp(frame->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL
-		|| ast_format_cmp(frame->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	} else {
 		/* x-law already */
 		if (p->subs[idx].linear) {
 			p->subs[idx].linear = 0;
@@ -8820,12 +9672,9 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 			if (res)
 				ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
 		}
-		res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
-	} else {
-		ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
-			ast_format_get_name(frame->subclass.format));
-		return -1;
+		res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
 	}
+	ast_mutex_unlock(&p->lock);
 	if (res < 0) {
 		ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
 		return -1;
@@ -9002,20 +9851,19 @@ static struct ast_str *create_channel_name(struct dahdi_pvt *i)
 	return chan_name;
 }
 
-static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid, int callid_created)
+static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid, int callid_created)
 {
-	struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
+	struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, linkedid, callid);
 
 	ast_callid_threadstorage_auto_clean(callid, callid_created);
 
 	return new_channel;
 }
 
-static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid)
+static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid)
 {
 	struct ast_channel *tmp;
-	struct ast_format_cap *caps;
-	struct ast_format *deflaw;
+	struct ast_format deflaw;
 	int x;
 	int features;
 	struct ast_str *chan_name;
@@ -9028,6 +9876,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 		return NULL;
 	}
 
+	ast_format_clear(&deflaw);
 #if defined(HAVE_PRI)
 	/*
 	 * The dnid has been stuffed with the called-number[:subaddress]
@@ -9041,21 +9890,12 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 		return NULL;
 	}
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_free(chan_name);
-		return NULL;
-	}
-
-	tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name));
+	tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name));
 	ast_free(chan_name);
 	if (!tmp) {
-		ao2_ref(caps, -1);
 		return NULL;
 	}
 
-	ast_channel_stage_snapshot(tmp);
-
 	if (callid) {
 		ast_channel_callid_set(tmp, callid);
 	}
@@ -9070,9 +9910,9 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 	if (law) {
 		i->law = law;
 		if (law == DAHDI_LAW_ALAW) {
-			deflaw = ast_format_alaw;
+			ast_format_set(&deflaw, AST_FORMAT_ALAW, 0);
 		} else {
-			deflaw = ast_format_ulaw;
+			ast_format_set(&deflaw, AST_FORMAT_ULAW, 0);
 		}
 	} else {
 		switch (i->sig) {
@@ -9086,20 +9926,18 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 			break;
 		}
 		if (i->law_default == DAHDI_LAW_ALAW) {
-			deflaw = ast_format_alaw;
+			ast_format_set(&deflaw, AST_FORMAT_ALAW, 0);
 		} else {
-			deflaw = ast_format_ulaw;
+			ast_format_set(&deflaw, AST_FORMAT_ULAW, 0);
 		}
 	}
 	ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
-	ast_format_cap_append(caps, deflaw, 0);
-	ast_channel_nativeformats_set(tmp, caps);
-	ao2_ref(caps, -1);
+	ast_format_cap_add(ast_channel_nativeformats(tmp), &deflaw);
 	/* Start out assuming ulaw since it's smaller :) */
-	ast_channel_set_rawreadformat(tmp, deflaw);
-	ast_channel_set_readformat(tmp, deflaw);
-	ast_channel_set_rawwriteformat(tmp, deflaw);
-	ast_channel_set_writeformat(tmp, deflaw);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &deflaw);
+	ast_format_copy(ast_channel_readformat(tmp), &deflaw);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &deflaw);
+	ast_format_copy(ast_channel_writeformat(tmp), &deflaw);
 	i->subs[idx].linear = 0;
 	dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
 	features = 0;
@@ -9178,7 +10016,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 		ast_channel_amaflags_set(tmp, i->amaflags);
 	i->subs[idx].owner = tmp;
 	ast_channel_context_set(tmp, i->context);
-	if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+	if (!analog_lib_handles(i->sig, i->radio, i->oprmode)) {
 		ast_channel_call_forward_set(tmp, i->call_forward);
 	}
 	/* If we've been told "no ADSI" then enforce it */
@@ -9235,10 +10073,6 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 	for (v = i->vars ; v ; v = v->next)
 		pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
-	ast_channel_stage_snapshot_done(tmp);
-
-	ast_channel_unlock(tmp);
-
 	ast_module_ref(ast_module_info->self);
 
 	dahdi_ami_channel_event(i, tmp);
@@ -9295,26 +10129,6 @@ static int dahdi_wink(struct dahdi_pvt *p, int idx)
 	return 0;
 }
 
-static void publish_dnd_state(int channel, const char *status)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
-	if (!dahdichan) {
-		return;
-	}
-
-	ast_str_set(&dahdichan, 0, "%d", channel);
-
-	body = ast_json_pack("{s: s, s: s}",
-		"DAHDIChannel", ast_str_buffer(dahdichan),
-		"Status", status);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
-}
-
 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
  * \param flag on 1 to enable, 0 to disable, -1 return dnd value
@@ -9326,7 +10140,7 @@ static void publish_dnd_state(int channel, const char *status)
  */
 static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
 {
-	if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
+	if (analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
 		return analog_dnd(dahdichan->sig_pvt, flag);
 	}
 
@@ -9339,19 +10153,36 @@ static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
 	ast_verb(3, "%s DND on channel %d\n",
 			flag? "Enabled" : "Disabled",
 			dahdichan->channel);
-	publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
+			<syntax>
+				<parameter name="Status">
+					<enumlist>
+						<enum name="enabled"/>
+						<enum name="disabled"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_SYSTEM, "DNDState",
+			"Channel: DAHDI/%d\r\n"
+			"Status: %s\r\n", dahdichan->channel,
+			flag? "enabled" : "disabled");
+
 	return 0;
 }
 
-static int canmatch_featurecode(const char *pickupexten, const char *exten)
+static int canmatch_featurecode(const char *exten)
 {
 	int extlen = strlen(exten);
-
+	const char *pickup_ext;
 	if (!extlen) {
 		return 1;
 	}
-
-	if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
+	pickup_ext = ast_pickup_ext();
+	if (extlen < strlen(pickup_ext) && !strncmp(pickup_ext, exten, extlen)) {
 		return 1;
 	}
 	/* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
@@ -9396,8 +10227,7 @@ static void *analog_ss_thread(void *data)
 	int len = 0;
 	int res;
 	int idx;
-	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-	const char *pickupexten;
+	struct ast_format tmpfmt;
 
 	ast_mutex_lock(&ss_thread_lock);
 	ss_thread_count++;
@@ -9417,17 +10247,6 @@ static void *analog_ss_thread(void *data)
 		ast_hangup(chan);
 		goto quit;
 	}
-
-	ast_channel_lock(chan);
-	pickup_cfg = ast_get_chan_features_pickup_config(chan);
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-		pickupexten = "";
-	} else {
-		pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-	}
-	ast_channel_unlock(chan);
-
 	if (p->dsp)
 		ast_dsp_digitreset(p->dsp);
 	switch (p->sig) {
@@ -9662,7 +10481,7 @@ static void *analog_ss_thread(void *data)
 				goto quit;
 			}
 		}
-		dahdi_ec_enable(p);
+		dahdi_enable_ec(p);
 		if (NEED_MFDETECT(p)) {
 			if (p->dsp) {
 				if (!p->hardwaredtmf)
@@ -9710,8 +10529,6 @@ static void *analog_ss_thread(void *data)
 		if (p->subs[SUB_THREEWAY].owner)
 			timeout = 999999;
 		while (len < AST_MAX_EXTENSION-1) {
-			int is_exten_parking = 0;
-
 			/* Read digit unless it's supposed to be immediate, in which case the
 			   only answer is 's' */
 			if (p->immediate)
@@ -9729,15 +10546,11 @@ static void *analog_ss_thread(void *data)
 				exten[len++]=res;
 				exten[len] = '\0';
 			}
-			if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
+			if (!ast_ignore_pattern(ast_channel_context(chan), exten))
 				tone_zone_play_tone(p->subs[idx].dfd, -1);
-			} else {
+			else
 				tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
-			}
-			if (ast_parking_provider_registered()) {
-				is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
-			}
-			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
+			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
 				if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
 					if (getforward) {
 						/* Record this as the forwarding extension */
@@ -9755,7 +10568,6 @@ static void *analog_ss_thread(void *data)
 						getforward = 0;
 					} else {
 						res = tone_zone_play_tone(p->subs[idx].dfd, -1);
-						ast_channel_lock(chan);
 						ast_channel_exten_set(chan, exten);
 						if (!ast_strlen_zero(p->cid_num)) {
 							if (!p->hidecallerid)
@@ -9768,8 +10580,7 @@ static void *analog_ss_thread(void *data)
 								ast_set_callerid(chan, NULL, p->cid_name, NULL);
 						}
 						ast_setstate(chan, AST_STATE_RING);
-						ast_channel_unlock(chan);
-						dahdi_ec_enable(p);
+						dahdi_enable_ec(p);
 						res = ast_pbx_run(chan);
 						if (res) {
 							ast_log(LOG_WARNING, "PBX exited non-zero\n");
@@ -9802,7 +10613,7 @@ static void *analog_ss_thread(void *data)
 				memset(exten, 0, sizeof(exten));
 				timeout = firstdigittimeout;
 
-			} else if (!strcmp(exten, pickupexten)) {
+			} else if (!strcmp(exten,ast_pickup_ext())) {
 				/* Scan all channels and see if there are any
 				 * ringing channels that have call groups
 				 * that equal this channels pickup group
@@ -9816,7 +10627,7 @@ static void *analog_ss_thread(void *data)
 						swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
 						unalloc_sub(p, SUB_THREEWAY);
 					}
-					dahdi_ec_enable(p);
+					dahdi_enable_ec(p);
 					if (ast_pickup_call(chan)) {
 						ast_debug(1, "No call pickup possible...\n");
 						res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
@@ -9875,35 +10686,14 @@ static void *analog_ss_thread(void *data)
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if ((p->transfer || p->canpark) && is_exten_parking
-				&& p->subs[SUB_THREEWAY].owner) {
-				struct ast_bridge_channel *bridge_channel;
-
-				/*
-				 * This is a three way call, the main call being a real channel,
-				 * and we're parking the first call.
-				 */
-				ast_channel_lock(p->subs[SUB_THREEWAY].owner);
-				bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
-				ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
-				if (bridge_channel) {
-					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
-						/*
-						 * Swap things around between the three-way and real call so we
-						 * can hear where the channel got parked.
-						 */
-						ast_mutex_lock(&p->lock);
-						p->owner = p->subs[SUB_THREEWAY].owner;
-						swap_subs(p, SUB_THREEWAY, SUB_REAL);
-						ast_mutex_unlock(&p->lock);
-
-						ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
-						ast_hangup(chan);
-						ao2_ref(bridge_channel, -1);
-						goto quit;
-					}
-					ao2_ref(bridge_channel, -1);
-				}
+			} else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
+						p->subs[SUB_THREEWAY].owner &&
+						ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+				/* This is a three way call, the main call being a real channel,
+					and we're parking the first call. */
+				ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner),
+					chan, exten, ast_channel_context(chan), 0, NULL);
+				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
 				break;
 			} else if (p->hidecallerid && !strcmp(exten, "*82")) {
 				ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
@@ -9922,15 +10712,12 @@ static void *analog_ss_thread(void *data)
 				struct ast_channel *nbridge =
 					p->subs[SUB_THREEWAY].owner;
 				struct dahdi_pvt *pbridge = NULL;
-				RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
-
 				/* set up the private struct of the bridged one, if any */
-				if (nbridge && bridged) {
-					pbridge = ast_channel_tech_pvt(bridged);
-				}
+				if (nbridge && ast_bridged_channel(nbridge))
+					pbridge = ast_channel_tech_pvt(ast_bridged_channel(nbridge));
 				if (nbridge && pbridge &&
 					(ast_channel_tech(nbridge) == &dahdi_tech) &&
-					(ast_channel_tech(bridged) == &dahdi_tech) &&
+					(ast_channel_tech(ast_bridged_channel(nbridge)) == &dahdi_tech) &&
 					ISTRUNK(pbridge)) {
 					int func = DAHDI_FLASH;
 					/* Clear out the dial buffer */
@@ -9943,7 +10730,8 @@ static void *analog_ss_thread(void *data)
 					swap_subs(p, SUB_REAL, SUB_THREEWAY);
 					unalloc_sub(p, SUB_THREEWAY);
 					p->owner = p->subs[SUB_REAL].owner;
-					ast_queue_unhold(p->subs[SUB_REAL].owner);
+					if (ast_bridged_channel(p->subs[SUB_REAL].owner))
+						ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
 					ast_hangup(chan);
 					goto quit;
 				} else {
@@ -9958,7 +10746,7 @@ static void *analog_ss_thread(void *data)
 				}
 			} else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
 				S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
-				&& !canmatch_featurecode(pickupexten, exten)) {
+				&& !canmatch_featurecode(exten)) {
 				ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
 					S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
 					ast_channel_context(chan));
@@ -10112,9 +10900,9 @@ static void *analog_ss_thread(void *data)
 							samples += res;
 
 							if (p->cid_signalling == CID_SIG_V23_JP) {
-								res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
+								res = callerid_feed_jp(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 							} else {
-								res = callerid_feed(cs, buf, res, AST_LAW(p));
+								res = callerid_feed(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 							}
 							if (res < 0) {
 								/*
@@ -10397,7 +11185,7 @@ static void *analog_ss_thread(void *data)
 								}
 							}
 							samples += res;
-							res = callerid_feed(cs, buf, res, AST_LAW(p));
+							res = callerid_feed(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0));
 							if (res < 0) {
 								/*
 								 * The previous diagnostic message output likely
@@ -10524,17 +11312,16 @@ static void *analog_ss_thread(void *data)
 			ast_shrink_phone_number(number);
 		ast_set_callerid(chan, number, name, number);
 
-		ao2_cleanup(smdi_msg);
+		if (smdi_msg)
+			ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
 
 		if (cs)
 			callerid_free(cs);
 
 		my_handle_notify_message(chan, p, flags, -1);
 
-		ast_channel_lock(chan);
 		ast_setstate(chan, AST_STATE_RING);
 		ast_channel_rings_set(chan, 1);
-		ast_channel_unlock(chan);
 		p->ringt = p->ringt_base;
 		res = ast_pbx_run(chan);
 		if (res) {
@@ -10566,7 +11353,7 @@ struct mwi_thread_data {
 	size_t len;
 };
 
-static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
+static int calc_energy(const unsigned char *buf, int len, enum ast_format_id law)
 {
 	int x;
 	int sum = 0;
@@ -10575,7 +11362,7 @@ static int calc_energy(const unsigned char *buf, int len, struct ast_format *law
 		return 0;
 
 	for (x = 0; x < len; x++)
-		sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
+		sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
 
 	return sum / len;
 }
@@ -10591,12 +11378,13 @@ static void *mwi_thread(void *data)
 	int i, res;
 	unsigned int spill_done = 0;
 	int spill_result = -1;
+	struct ast_format tmpfmt;
 
 	if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
 		goto quit_no_clean;
 	}
 
-	callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
+	callerid_feed(cs, mtd->buf, mtd->len, ast_format_set(&tmpfmt, AST_LAW(mtd->pvt), 0));
 
 	bump_gains(mtd->pvt);
 
@@ -10624,7 +11412,7 @@ static void *mwi_thread(void *data)
 			case DAHDI_EVENT_BITSCHANGED:
 				break;
 			case DAHDI_EVENT_NOALARM:
-				if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+				if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
 					struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
 					analog_p->inalarm = 0;
@@ -10633,7 +11421,7 @@ static void *mwi_thread(void *data)
 				handle_clear_alarms(mtd->pvt);
 				break;
 			case DAHDI_EVENT_ALARM:
-				if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+				if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
 					struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
 					analog_p->inalarm = 1;
@@ -10650,10 +11438,10 @@ static void *mwi_thread(void *data)
 				restore_gains(mtd->pvt);
 				mtd->pvt->ringt = mtd->pvt->ringt_base;
 
-				if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
+				if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, callid))) {
 					int result;
 
-					if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+					if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
 						result = analog_ss_thread_start(mtd->pvt->sig_pvt, chan);
 					} else {
 						result = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
@@ -10682,7 +11470,7 @@ static void *mwi_thread(void *data)
 			}
 			samples += res;
 			if (!spill_done) {
-				if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
+				if ((spill_result = callerid_feed(cs, mtd->buf, res, ast_format_set(&tmpfmt, AST_LAW(mtd->pvt), 0))) < 0) {
 					/*
 					 * The previous diagnostic message output likely
 					 * explains why it failed.
@@ -10740,6 +11528,7 @@ quit_no_clean:
 static int mwi_send_init(struct dahdi_pvt * pvt)
 {
 	int x;
+	struct ast_format tmpfmt;
 
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 	/* Determine how this spill is to be sent */
@@ -10781,8 +11570,8 @@ static int mwi_send_init(struct dahdi_pvt * pvt)
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 	if (pvt->mwisend_fsk) {
 #endif
-		pvt->cidlen = ast_callerid_vmwi_generate(pvt->cidspill, has_voicemail(pvt),
-			CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
+		pvt->cidlen = ast_callerid_vmwi_generate(pvt->cidspill, has_voicemail(pvt), CID_MWI_TYPE_MDMF_FULL,
+							 ast_format_set(&tmpfmt, AST_LAW(pvt), 0), pvt->cid_name, pvt->cid_num, 0);
 		pvt->cidpos = 0;
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 	}
@@ -10831,10 +11620,9 @@ static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
 			break;
 		case MWI_SEND_SPILL:
 			/* We read some number of bytes.  Write an equal amount of data */
-			if (0 < num_read) {
-				if (num_read > pvt->cidlen - pvt->cidpos) {
+			if(0 < num_read) {
+				if (num_read > pvt->cidlen - pvt->cidpos)
 					num_read = pvt->cidlen - pvt->cidpos;
-				}
 				res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
 				if (res > 0) {
 					pvt->cidpos += res;
@@ -10885,7 +11673,7 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
 	if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
 		switch (event) {
 		case DAHDI_EVENT_RINGEROFF:
-			if (pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) {
+			if(pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) {
 				handled = 1;
 
 				if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
@@ -10921,123 +11709,29 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
 	return handled;
 }
 
-/* destroy a range DAHDI channels, identified by their number */
-static void dahdi_destroy_channel_range(int start, int end)
+/* destroy a DAHDI channel, identified by its number */
+static int dahdi_destroy_channel_bynum(int channel)
 {
 	struct dahdi_pvt *cur;
-	struct dahdi_pvt *next;
-	int destroyed_first = 0;
-	int destroyed_last = 0;
 
 	ast_mutex_lock(&iflock);
-	ast_debug(1, "range: %d-%d\n", start, end);
-	for (cur = iflist; cur; cur = next) {
-		next = cur->next;
-		if (cur->channel >= start && cur->channel <= end) {
+	for (cur = iflist; cur; cur = cur->next) {
+		if (cur->channel == channel) {
 			int x = DAHDI_FLASH;
 
-			if (cur->channel > destroyed_last) {
-				destroyed_last = cur->channel;
-			}
-			if (destroyed_first < 1 || cur->channel < destroyed_first) {
-				destroyed_first = cur->channel;
-			}
-			ast_debug(3, "Destroying %d\n", cur->channel);
 			/* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
 			ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
 
 			destroy_channel(cur, 1);
+			ast_mutex_unlock(&iflock);
 			ast_module_unref(ast_module_info->self);
+			return RESULT_SUCCESS;
 		}
 	}
 	ast_mutex_unlock(&iflock);
-	if (destroyed_first > start || destroyed_last < end) {
-		ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
-			start, end, destroyed_first, destroyed_last);
-	}
-}
-
-static int setup_dahdi(int reload);
-static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
-
-/*!
- * \internal
- * \brief create a range of new DAHDI channels
- *
- * \param start first channel in the range
- * \param end last channel in the range
- *
- * \retval RESULT_SUCCESS on success.
- * \retval RESULT_FAILURE on error.
- */
-static int dahdi_create_channel_range(int start, int end)
-{
-	struct dahdi_pvt *cur;
-	struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
-	struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
-	struct dahdi_chan_conf conf = dahdi_chan_conf_default();
-	int ret = RESULT_FAILURE; /* be pessimistic */
-
-	ast_debug(1, "channel range caps: %d - %d\n", start, end);
-	ast_mutex_lock(&iflock);
-	for (cur = iflist; cur; cur = cur->next) {
-		if (cur->channel >= start && cur->channel <= end) {
-			ast_log(LOG_ERROR,
-				"channel range %d-%d is occupied\n",
-				start, end);
-			goto out;
-		}
-	}
-#ifdef HAVE_PRI
-	{
-		int i, x;
-		for (x = 0; x < NUM_SPANS; x++) {
-			struct dahdi_pri *pri = pris + x;
-
-			if (!pris[x].pri.pvts[0]) {
-				break;
-			}
-			for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
-				int channo = pri->dchannels[i];
-
-				if (!channo) {
-					break;
-				}
-				if (!pri->pri.fds[i]) {
-					break;
-				}
-				if (channo >= start && channo <= end) {
-					ast_log(LOG_ERROR,
-							"channel range %d-%d is occupied by span %d\n",
-							start, end, x + 1);
-					goto out;
-				}
-			}
-		}
-	}
-#endif
-	if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
-		!conf.chan.cc_params) {
-		goto out;
-	}
-	default_conf.wanted_channels_start = start;
-	base_conf.wanted_channels_start = start;
-	conf.wanted_channels_start = start;
-	default_conf.wanted_channels_end = end;
-	base_conf.wanted_channels_end = end;
-	conf.wanted_channels_end = end;
-	if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
-		ret = RESULT_SUCCESS;
-	}
-out:
-	ast_cc_config_params_destroy(default_conf.chan.cc_params);
-	ast_cc_config_params_destroy(base_conf.chan.cc_params);
-	ast_cc_config_params_destroy(conf.chan.cc_params);
-	ast_mutex_unlock(&iflock);
-	return ret;
+	return RESULT_FAILURE;
 }
 
-
 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 {
 	int res;
@@ -11074,10 +11768,10 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 			restore_conference(i);
 
 			if (i->immediate) {
-				dahdi_ec_enable(i);
+				dahdi_enable_ec(i);
 				/* The channel is immediately up.  Start right away */
 				res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
-				chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
+				chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, callid);
 				if (!chan) {
 					ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
 					res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
@@ -11086,7 +11780,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 				}
 			} else {
 				/* Check for callerid, digits, etc */
-				chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
+				chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, callid);
 				if (chan) {
 					if (has_voicemail(i))
 						res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
@@ -11130,9 +11824,9 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 			/* Check for callerid, digits, etc */
 			callid_created = ast_callid_threadstorage_auto(&callid);
 			if (i->cid_start == CID_START_POLARITY_IN) {
-				chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
+				chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
 			} else {
-				chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
+				chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, callid);
 			}
 
 			if (!chan) {
@@ -11223,7 +11917,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 		case SIG_FXSGS:
 		case SIG_FXSKS:
 		case SIG_FXOKS:
-			dahdi_ec_disable(i);
+			dahdi_disable_ec(i);
 			/* Diddle the battery for the zhone */
 #ifdef ZHONE_HACK
 			dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
@@ -11234,7 +11928,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 			break;
 		case SIG_SS7:
 		case SIG_PRI_LIB_HANDLE_CASES:
-			dahdi_ec_disable(i);
+			dahdi_disable_ec(i);
 			res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
 			break;
 		default:
@@ -11260,7 +11954,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 				ast_verb(2, "Starting post polarity "
 					"CID detection on channel %d\n",
 					i->channel);
-				chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
+				chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
 				if (!chan) {
 					ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
 				} else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
@@ -11348,7 +12042,7 @@ static void *do_monitor(void *data)
 		for (i = iflist; i; i = i->next) {
 			ast_mutex_lock(&i->lock);
 			if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
-				if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+				if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
 					struct analog_pvt *p = i->sig_pvt;
 
 					if (!p) {
@@ -11359,7 +12053,7 @@ static void *do_monitor(void *data)
 						pfds[count].events = POLLPRI;
 						pfds[count].revents = 0;
 						/* Message waiting or r2 channels also get watched for reading */
-						if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
+						if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk || 
 							(i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
 							pfds[count].events |= POLLIN;
 						}
@@ -11409,7 +12103,11 @@ static void *do_monitor(void *data)
 		doomed = NULL;
 		for (i = iflist;; i = i->next) {
 			if (doomed) {
-				dahdi_destroy_channel_range(doomed->channel, doomed->channel);
+				int res;
+				res = dahdi_destroy_channel_bynum(doomed->channel);
+				if (res != RESULT_SUCCESS) {
+					ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
+				}
 				doomed = NULL;
 			}
 			if (!i) {
@@ -11458,7 +12156,7 @@ static void *do_monitor(void *data)
 						ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
 						/* Don't hold iflock while handling init events */
 						ast_mutex_unlock(&iflock);
-						if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
+						if (analog_lib_handles(i->sig, i->radio, i->oprmode))
 							doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
 						else
 							doomed = handle_init_event(i, res);
@@ -11508,7 +12206,7 @@ static void *do_monitor(void *data)
 							int energy;
 							struct timeval now;
 							/* State machine dtmfcid_holdoff_state allows for the line to settle
-							 * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again
+							 * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again 
 							*/
 							if (1 == i->dtmfcid_holdoff_state) {
 								gettimeofday(&i->dtmfcid_delay, NULL);
@@ -11524,14 +12222,14 @@ static void *do_monitor(void *data)
 									pthread_t threadid;
 									struct ast_channel *chan;
 									ast_mutex_unlock(&iflock);
-									if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+									if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
 										/* just in case this event changes or somehow destroys a channel, set doomed here too */
-										doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);
+										doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);  
 										i->dtmfcid_holdoff_state = 1;
 									} else {
 										struct ast_callid *callid = NULL;
 										int callid_created = ast_callid_threadstorage_auto(&callid);
-										chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
+										chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
 										if (!chan) {
 											ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
 										} else {
@@ -11569,7 +12267,7 @@ static void *do_monitor(void *data)
 					/* Don't hold iflock while handling init events */
 					ast_mutex_unlock(&iflock);
 					if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
-						if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
+						if (analog_lib_handles(i->sig, i->radio, i->oprmode))
 							doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
 						else
 							doomed = handle_init_event(i, res);
@@ -11579,7 +12277,6 @@ static void *do_monitor(void *data)
 			}
 		}
 		ast_mutex_unlock(&iflock);
-		release_doomed_pris();
 	}
 	/* Never reached */
 	pthread_cleanup_pop(1);
@@ -11789,9 +12486,9 @@ static struct dahdi_mfcr2 *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
 	struct dahdi_mfcr2 *new_r2link = NULL;
 	struct dahdi_mfcr2 **new_r2links = NULL;
 
-	/* Only create a new R2 link if
+	/* Only create a new R2 link if 
 	   1. This is the first link requested
-	   2. Configuration changed
+	   2. Configuration changed 
 	   3. We got more channels than supported per link */
 	if (!r2links_count ||
 	    memcmp(&conf->mfcr2, &r2links[r2links_count - 1]->conf, sizeof(conf->mfcr2)) ||
@@ -12040,7 +12737,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 			tmp->sig = chan_sig;
 			tmp->outsigmod = conf->chan.outsigmod;
 
-			if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
+			if (analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
 				analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
 				if (!analog_p) {
 					destroy_dahdi_pvt(tmp);
@@ -12091,7 +12788,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
 				ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
 				ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
-				ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
 
 				ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
 				ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
@@ -12312,9 +13008,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 						ast_copy_string(pris[span].pri.mwi_mailboxes,
 							conf->pri.pri.mwi_mailboxes,
 							sizeof(pris[span].pri.mwi_mailboxes));
-						ast_copy_string(pris[span].pri.mwi_vm_boxes,
-							conf->pri.pri.mwi_vm_boxes,
-							sizeof(pris[span].pri.mwi_vm_boxes));
 						ast_copy_string(pris[span].pri.mwi_vm_numbers,
 							conf->pri.pri.mwi_vm_numbers,
 							sizeof(pris[span].pri.mwi_vm_numbers));
@@ -12335,6 +13028,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #if defined(HAVE_PRI_MCID)
 						pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
 #endif	/* defined(HAVE_PRI_MCID) */
+						pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
 #if defined(HAVE_PRI_DATETIME_SEND)
 						pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
 #endif	/* defined(HAVE_PRI_DATETIME_SEND) */
@@ -12559,7 +13253,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
 		ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
 		tmp->cid_ton = 0;
-		if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
+		if (analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
 			ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
 			ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
 		} else {
@@ -12577,12 +13271,16 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		tmp->cid_subaddr[0] = '\0';
 		ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
 		if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
-			struct stasis_topic *mailbox_specific_topic;
-
-			mailbox_specific_topic = ast_mwi_topic(tmp->mailbox);
-			if (mailbox_specific_topic) {
-				tmp->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
-			}
+			char *mailbox, *context;
+			mailbox = context = ast_strdupa(tmp->mailbox);
+			strsep(&context, "@");
+			if (ast_strlen_zero(context))
+				context = "default";
+			tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "Dahdi MWI subscription", NULL,
+				AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+				AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+				AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+				AST_EVENT_IE_END);
 		}
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
 		tmp->mwisend_setting = conf->chan.mwisend_setting;
@@ -12599,17 +13297,13 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
 		if (conf->chan.vars) {
 			struct ast_variable *v, *tmpvar;
-			for (v = conf->chan.vars ; v ; v = v->next) {
-				if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
-					tmpvar->next = tmp->vars;
-					tmp->vars = tmpvar;
-				}
-			}
+	                for (v = conf->chan.vars ; v ; v = v->next) {
+        	                if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
+                	                tmpvar->next = tmp->vars;
+                        	        tmp->vars = tmpvar;
+                        	}
+                	}
 		}
-		tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
-		tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
-		tmp->hwrxgain = conf->chan.hwrxgain;
-		tmp->hwtxgain = conf->chan.hwtxgain;
 		tmp->cid_rxgain = conf->chan.cid_rxgain;
 		tmp->rxgain = conf->chan.rxgain;
 		tmp->txgain = conf->chan.txgain;
@@ -12617,16 +13311,10 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		tmp->rxdrc = conf->chan.rxdrc;
 		tmp->tonezone = conf->chan.tonezone;
 		if (tmp->subs[SUB_REAL].dfd > -1) {
-			if (tmp->hwrxgain_enabled) {
-				tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
-			}
-			if (tmp->hwtxgain_enabled) {
-				tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
-			}
 			set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
 			if (tmp->dsp)
 				ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
-			dahdi_conf_update(tmp);
+			update_conf(tmp);
 			if (!here) {
 				switch (chan_sig) {
 				case SIG_PRI_LIB_HANDLE_CASES:
@@ -12713,9 +13401,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #if defined(HAVE_SS7)
 			case SIG_SS7:
 				tmp->inservice = 0;
-				if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
-					tmp->remotelyblocked |= SS7_BLOCKED_HARDWARE;
-				}
 				break;
 #endif	/* defined(HAVE_SS7) */
 			default:
@@ -12750,7 +13435,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		case SIG_SS7:
 			if (ss7_chan) {
 				ss7_chan->inalarm = tmp->inalarm;
-				ss7_chan->inservice = tmp->inservice;
 
 				ss7_chan->stripmsd = tmp->stripmsd;
 				ss7_chan->hidecallerid = tmp->hidecallerid;
@@ -12786,6 +13470,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				analog_p->transfer = conf->chan.transfer;
 				analog_p->transfertobusy = conf->chan.transfertobusy;
 				analog_p->use_callerid = tmp->use_callerid;
+				analog_p->usedistinctiveringdetection = tmp->usedistinctiveringdetection;
 				analog_p->use_smdi = tmp->use_smdi;
 				analog_p->smdi_iface = tmp->smdi_iface;
 				analog_p->outsigmod = ANALOG_SIG_NONE;
@@ -12890,7 +13575,7 @@ static int available(struct dahdi_pvt **pvt, int is_specific_channel)
 	if (p->inalarm)
 		return 0;
 
-	if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
+	if (analog_lib_handles(p->sig, p->radio, p->oprmode))
 		return analog_available(p->sig_pvt);
 
 	switch (p->sig) {
@@ -13316,9 +14001,7 @@ static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi
 	return p;
 }
 
-static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	const char *data, int *cause)
+static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	int callwait = 0;
 	struct dahdi_pvt *p;
@@ -13398,7 +14081,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
 			}
 
 			p->outgoing = 1;
-			if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+			if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
 				tmp = analog_request(p->sig_pvt, &callwait, requestor);
 #ifdef HAVE_PRI
 			} else if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -13412,14 +14095,14 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
 
 				sig_pri_extract_called_num_subaddr(p->sig_pvt, data, p->dnid,
 					sizeof(p->dnid));
-				tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
+				tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, requestor, transcapdigital);
 #endif
 #if defined(HAVE_SS7)
 			} else if (p->sig == SIG_SS7) {
-				tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
+				tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, requestor, transcapdigital);
 #endif	/* defined(HAVE_SS7) */
 			} else {
-				tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
+				tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, requestor ? ast_channel_linkedid(requestor) : "", callid);
 			}
 			if (!tmp) {
 				p->outgoing = 0;
@@ -13869,21 +14552,10 @@ static int prepare_pri(struct dahdi_pri *pri)
 	for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
 		if (!pri->dchannels[i])
 			break;
-		if (pri->pri.fds[i] >= 0) {
-			/* A partial range addition. Not a complete setup. */
-			break;
-		}
 		pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
-		if ((pri->pri.fds[i] < 0)) {
-			ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
-				pri->pri.fds[i], strerror(errno));
-			return -1;
-		}
 		x = pri->dchannels[i];
-		res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
-		if (res) {
-			dahdi_close_pri_fd(pri, i);
-			ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
+		if ((pri->pri.fds[i] < 0) || (ioctl(pri->pri.fds[i],DAHDI_SPECIFY,&x) == -1)) {
+			ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
 			return -1;
 		}
 		memset(&p, 0, sizeof(p));
@@ -13992,55 +14664,6 @@ static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
-static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
-{
-	const char *output_file = astman_get_header(m, "File");
-	int myfd;
-
-	if (ast_strlen_zero(output_file)) {
-		astman_send_error(s, m, "Action must define a 'File'");
-	}
-
-	myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
-	if (myfd < 0) {
-		astman_send_error(s, m, "Unable to open requested file for writing");
-		return 0;
-	}
-
-	ast_mutex_lock(&pridebugfdlock);
-
-	if (pridebugfd >= 0) {
-		close(pridebugfd);
-	}
-
-	pridebugfd = myfd;
-	ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
-	ast_mutex_unlock(&pridebugfdlock);
-	astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
-
-	return 0;
-}
-#endif	/* defined(HAVE_PRI) */
-
-#if defined(HAVE_PRI)
-static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
-{
-	ast_mutex_lock(&pridebugfdlock);
-
-	if (pridebugfd >= 0) {
-		close(pridebugfd);
-	}
-
-	pridebugfd = -1;
-
-	ast_mutex_unlock(&pridebugfdlock);
-
-	astman_send_ack(s, m, "PRI Debug output to file disabled");
-	return 0;
-}
-#endif	/* defined(HAVE_PRI) */
-
-#if defined(HAVE_PRI)
 static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int span;
@@ -14119,95 +14742,6 @@ static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
-static int action_pri_debug_set(struct mansession *s, const struct message *m)
-{
-	const char *level = astman_get_header(m, "Level");
-	const char *span = astman_get_header(m, "Span");
-	int level_val;
-	int span_val;
-	int x;
-	int debugmask = 0;
-
-	if (ast_strlen_zero(level)) {
-		astman_send_error(s, m, "'Level' was not specified");
-		return 0;
-	}
-
-	if (ast_strlen_zero(span)) {
-		astman_send_error(s, m, "'Span' was not specified");
-		return 0;
-	}
-
-	if (!strcasecmp(level, "on")) {
-		level_val = 3;
-	} else if (!strcasecmp(level, "off")) {
-		level_val = 0;
-	} else if (!strcasecmp(level, "intense")) {
-		level_val = 15;
-	} else if (!strcasecmp(level, "hex")) {
-		level_val = 8;
-	} else {
-		if (sscanf(level, "%30d", &level_val) != 1) {
-			astman_send_error(s, m, "Invalid value for 'Level'");
-			return 0;
-		}
-	}
-
-	if (sscanf(span, "%30d", &span_val) != 1) {
-		astman_send_error(s, m, "Invalid value for 'Span'");
-	}
-
-	if ((span_val < 1) || (span_val > NUM_SPANS)) {
-		const char *id = astman_get_header(m, "ActionID");
-		char id_text[256] = "";
-
-		if (!ast_strlen_zero(id)) {
-			snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-		}
-
-		astman_append(s, "Response: Error\r\n"
-			"%s" /* id_text */
-			"Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
-			"\r\n",
-			id_text,
-			span, NUM_SPANS);
-
-		return 0;
-	}
-
-	if (!pris[span_val-1].pri.pri) {
-		astman_send_error(s, m, "No PRI running on requested span");
-		return 0;
-	}
-
-	if (level_val & 1) {
-		debugmask |= SIG_PRI_DEBUG_NORMAL;
-	}
-	if (level_val & 2) {
-		debugmask |= PRI_DEBUG_Q931_DUMP;
-	}
-	if (level_val & 4) {
-		debugmask |= PRI_DEBUG_Q921_DUMP;
-	}
-	if (level_val & 8) {
-		debugmask |= PRI_DEBUG_Q921_RAW;
-	}
-
-	/* Set debug level in libpri */
-	for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
-		if (pris[span_val - 1].pri.dchans[x]) {
-			pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
-		}
-	}
-
-	pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
-	astman_send_ack(s, m, "Debug level set for requested span");
-
-	return 0;
-}
-#endif	/* defined(HAVE_PRI) */
-
-#if defined(HAVE_PRI)
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
 static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
 {
@@ -14422,63 +14956,40 @@ static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_
  *
  * \param pri the pri span
  *
+ * \return TRUE if the span was valid and we attempted destroying.
+ *
  * Shuts down a span and destroys its D-Channel. Further destruction
  * of the B-channels using dahdi_destroy_channel() would probably be required
  * for the B-Channels.
  */
-static void pri_destroy_span(struct sig_pri_span *pri)
+static int pri_destroy_dchan(struct sig_pri_span *pri)
 {
 	int i;
-	int res;
-	int cancel_code;
 	struct dahdi_pri* dahdi_pri;
-	pthread_t master = pri->master;
-
-	if (!master || (master == AST_PTHREADT_NULL)) {
-		return;
-	}
-	ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
-	for (i = 0; i < pri->numchans; i++) {
-		int channel;
-		struct sig_pri_chan *pvt = pri->pvts[i];
-
-		if (!pvt) {
-			continue;
-		}
-		channel = pvt->channel;
-		ast_debug(2, "About to destroy B-channel %d.\n", channel);
-		dahdi_destroy_channel_range(channel, channel);
-	}
 
-	cancel_code = pthread_cancel(master);
-	pthread_kill(master, SIGURG);
-	ast_debug(4,
-		"Waiting to join thread of span %d "
-		"with pid=%p cancel_code=%d\n",
-		pri->span, (void *)master, cancel_code);
-	res = pthread_join(master, NULL);
-	if (res != 0) {
-		ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
+	if (!pri->master || (pri->master == AST_PTHREADT_NULL)) {
+		return 0;
 	}
-	pri->master = AST_PTHREADT_NULL;
+	pthread_cancel(pri->master);
+	pthread_join(pri->master, NULL);
 
 	/* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
 	dahdi_pri = container_of(pri, struct dahdi_pri, pri);
 	for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
 		ast_debug(4, "closing pri_fd %d\n", i);
 		dahdi_close_pri_fd(dahdi_pri, i);
-		dahdi_pri->dchannels[i] = 0;
 	}
-	sig_pri_init_pri(pri);
+	pri->pri = NULL;
 	ast_debug(1, "PRI span %d destroyed\n", pri->span);
+	return 1;
 }
 
 static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
 		struct ast_cli_args *a)
 {
 	int span;
+	int i;
 	int res;
-	struct sig_pri_span *pri;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -14502,13 +15013,25 @@ static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
 			a->argv[3], 1, NUM_SPANS);
 		return CLI_SUCCESS;
 	}
-	pri = &pris[span - 1].pri;
-	if (!pri->pri) {
+	if (!pris[span - 1].pri.pri) {
 		ast_cli(a->fd, "No PRI running on span %d\n", span);
 		return CLI_SUCCESS;
 	}
 
-	pri_destroy_span(pri);
+	for (i = 0; i < pris[span - 1].pri.numchans; i++) {
+		int channel;
+		struct sig_pri_chan *pvt = pris[span - 1].pri.pvts[i];
+
+		if (!pvt) {
+			continue;
+		}
+		channel = pvt->channel;
+		ast_debug(2, "About to destroy B-channel %d.\n", channel);
+		dahdi_destroy_channel_bynum(channel);
+	}
+	ast_debug(2, "About to destroy D-channel of span %d.\n", span);
+	pri_destroy_dchan(&pris[span - 1].pri);
+
 	return CLI_SUCCESS;
 }
 
@@ -14960,97 +15483,26 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
 
 #endif /* HAVE_OPENR2 */
 
-static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int start;
-	int end;
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "dahdi destroy channels";
-		e->usage =
-			"Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
-			"	DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-	if ((a->argc < 4) || a->argc > 5) {
-		return CLI_SHOWUSAGE;
-	}
-	start = atoi(a->argv[3]);
-	if (start < 1) {
-		ast_cli(a->fd, "Invalid starting channel number %s.\n",
-				a->argv[4]);
-		return CLI_FAILURE;
-	}
-	if (a->argc == 5) {
-		end = atoi(a->argv[4]);
-		if (end < 1) {
-			ast_cli(a->fd, "Invalid ending channel number %s.\n",
-					a->argv[4]);
-			return CLI_FAILURE;
-		}
-	} else {
-		end = start;
-	}
-
-	if (end < start) {
-		ast_cli(a->fd,
-			"range end (%d) is smaller than range start (%d)\n",
-			end, start);
-		return CLI_FAILURE;
-	}
-	dahdi_destroy_channel_range(start, end);
-	return CLI_SUCCESS;
-}
-
-static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	int start;
-	int end;
+	int channel;
 	int ret;
-
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "dahdi create channels";
-		e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
-			   "       dahdi create channels new           - add channels not yet created\n"
-			   "For ISDN  and SS7 the range should include complete spans.\n";
+		e->command = "dahdi destroy channel";
+		e->usage =
+			"Usage: dahdi destroy channel <chan num>\n"
+			"	DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
-	if ((a->argc < 4) || a->argc > 5) {
+	if (a->argc != 4)
 		return CLI_SHOWUSAGE;
-	}
-	if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
-		ret = dahdi_create_channel_range(0, 0);
-		return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
-	}
-	start = atoi(a->argv[3]);
-	if (start <= 0) {
-		ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
-				a->argv[3]);
-		return CLI_FAILURE;
-	}
-	if (a->argc == 5) {
-		end = atoi(a->argv[4]);
-		if (end <= 0) {
-			ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
-					a->argv[4]);
-			return CLI_FAILURE;
-		}
-	} else {
-		end = start;
-	}
-	if (end < start) {
-		ast_cli(a->fd,
-			"range end (%d) is smaller than range start (%d)\n",
-			end, start);
-		return CLI_FAILURE;
-	}
-	ret = dahdi_create_channel_range(start, end);
-	return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
+
+	channel = atoi(a->argv[3]);
+	ret = dahdi_destroy_channel_bynum(channel);
+	return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
 }
 
 static void dahdi_softhangup_all(void)
@@ -15081,6 +15533,7 @@ retry:
 	ast_mutex_unlock(&iflock);
 }
 
+static int setup_dahdi(int reload);
 static int dahdi_restart(void)
 {
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
@@ -15181,9 +15634,6 @@ static int dahdi_restart(void)
 	}
 	ss7_set_error(dahdi_ss7_error);
 	ss7_set_message(dahdi_ss7_message);
-	ss7_set_hangup(sig_ss7_cb_hangup);
-	ss7_set_notinservice(sig_ss7_cb_notinservice);
-	ss7_set_call_null(sig_ss7_cb_call_null);
 #endif	/* defined(HAVE_SS7) */
 
 	if (setup_dahdi(2) != 0) {
@@ -15236,8 +15686,9 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
 	ast_group_t targetnum = 0;
 	int filtertype = 0;
 	struct dahdi_pvt *tmp = NULL;
-	char tmps[20];
-	char blockstr[20];
+	char tmps[20] = "";
+	char statestr[20] = "";
+	char blockstr[20] = "";
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -15253,9 +15704,8 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
 
 	/* syntax: dahdi show channels [ group <group> | context <context> ] */
 
-	if (!((a->argc == 3) || (a->argc == 5))) {
+	if (!((a->argc == 3) || (a->argc == 5)))
 		return CLI_SHOWUSAGE;
-	}
 
 	if (a->argc == 5) {
 		if (!strcasecmp(a->argv[3], "group")) {
@@ -15270,7 +15720,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
 		}
 	}
 
-	ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Description");
+	ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State", "Description");
 	ast_mutex_lock(&iflock);
 	for (tmp = iflist; tmp; tmp = tmp->next) {
 		if (filtertype) {
@@ -15291,15 +15741,24 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
 		}
 		if (tmp->channel > 0) {
 			snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
-		} else {
+		} else
 			ast_copy_string(tmps, "pseudo", sizeof(tmps));
-		}
 
-		blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
-		blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
+		if (tmp->locallyblocked)
+			blockstr[0] = 'L';
+		else
+			blockstr[0] = ' ';
+
+		if (tmp->remotelyblocked)
+			blockstr[1] = 'R';
+		else
+			blockstr[1] = ' ';
+
 		blockstr[2] = '\0';
 
-		ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No", tmp->description);
+		snprintf(statestr, sizeof(statestr), "%s", "In Service");
+
+		ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr, tmp->description);
 	}
 	ast_mutex_unlock(&iflock);
 	return CLI_SUCCESS;
@@ -15314,8 +15773,6 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
 	struct dahdi_confinfo ci;
 	struct dahdi_params ps;
 	int x;
-	char hwrxgain[15];
-	char hwtxgain[15];
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -15389,18 +15846,7 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
 			ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
 			ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
 			ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
-			if (tmp->hwrxgain_enabled) {
-				snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
-			} else {
-				ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
-			}
-			if (tmp->hwtxgain_enabled) {
-				snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
-			} else {
-				ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
-			}
-			ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
-			ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
+			ast_cli(a->fd, "Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
 			ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
 			ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
 			ast_cli(a->fd, "Echo Cancellation:\n");
@@ -15666,8 +16112,9 @@ static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli
 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int channel;
-	float gain;
+	int gain;
 	int tx;
+	struct dahdi_hwgain hwgain;
 	struct dahdi_pvt *tmp = NULL;
 
 	switch (cmd) {
@@ -15675,8 +16122,7 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		e->command = "dahdi set hwgain {rx|tx}";
 		e->usage =
 			"Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
-			"   Sets the hardware gain on a given channel and overrides the\n"
-			"   value provided at module loadtime.  Changes take effect\n"
+			"   Sets the hardware gain on a given channel.  Changes take effect\n"
 			"   immediately whether the channel is in use or not.\n"
 			"\n"
 			"   <rx|tx> which direction do you want to change (relative to our module)\n"
@@ -15684,6 +16130,7 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 			"   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
 			"\n"
 			"   Please note:\n"
+			"   * This is currently the only way to set hwgain by the channel driver.\n"
 			"   * hwgain is only supportable by hardware with analog ports because\n"
 			"     hwgain works on the analog side of an analog-digital conversion.\n";
 		return NULL;
@@ -15702,7 +16149,7 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		return CLI_SHOWUSAGE;
 
 	channel = atoi(a->argv[4]);
-	gain = atof(a->argv[5]);
+	gain = atof(a->argv[5])*10.0;
 
 	ast_mutex_lock(&iflock);
 
@@ -15714,21 +16161,15 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		if (tmp->subs[SUB_REAL].dfd == -1)
 			break;
 
-		if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
+		hwgain.newgain = gain;
+		hwgain.tx = tx;
+		if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
 			ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
 			ast_mutex_unlock(&iflock);
 			return CLI_FAILURE;
 		}
-		ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
-			tx ? "tx" : "rx", gain, channel);
-
-		if (tx) {
-			tmp->hwtxgain_enabled = 1;
-			tmp->hwtxgain = gain;
-		} else {
-			tmp->hwrxgain_enabled = 1;
-			tmp->hwrxgain = gain;
-		}
+		ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
+			tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
 		break;
 	}
 
@@ -15800,7 +16241,7 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 			return CLI_FAILURE;
 		}
 
-		ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
+		ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
 			tx ? "tx" : "rx", gain, channel);
 
 		if (tx) {
@@ -15881,8 +16322,7 @@ static struct ast_cli_entry dahdi_cli[] = {
 	AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
 	AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
 	AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
-	AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
-	AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
+	AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
 	AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
 	AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
 	AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
@@ -15997,7 +16437,7 @@ static int action_transfer(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "No such channel");
 		return 0;
 	}
-	if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
+	if (!analog_lib_handles(p->sig, 0, 0)) {
 		astman_send_error(s, m, "Channel signaling is not analog");
 		return 0;
 	}
@@ -16020,7 +16460,7 @@ static int action_transferhangup(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "No such channel");
 		return 0;
 	}
-	if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
+	if (!analog_lib_handles(p->sig, 0, 0)) {
 		astman_send_error(s, m, "Channel signaling is not analog");
 		return 0;
 	}
@@ -16307,7 +16747,7 @@ static int linkset_addsigchan(int sigchan)
 		(params.sigtype == DAHDI_SIG_MTP2)
 			? SS7_TRANSPORT_DAHDIMTP2
 			: SS7_TRANSPORT_DAHDIDCHAN,
-		si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
+		si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode);
 	if (res) {
 		dahdi_close_ss7_fd(link, curfd);
 		return -1;
@@ -16333,11 +16773,8 @@ static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	case CLI_GENERATE:
 		return NULL;
 	}
-
-	if (a->argc < 6) {
+	if (a->argc < 6)
 		return CLI_SHOWUSAGE;
-	}
-
 	span = atoi(a->argv[5]);
 	if ((span < 1) || (span > NUM_SPANS)) {
 		ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
@@ -16362,35 +16799,24 @@ static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 #endif	/* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int linkset, cic;
-	int blocked, i;
-	int do_block = 0;
-	unsigned int dpc;
-
+	int blocked = -1, i;
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "ss7 {block|unblock} cic";
+		e->command = "ss7 block cic";
 		e->usage =
-			"Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
-			"       Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
+			"Usage: ss7 block cic <linkset> <CIC>\n"
+			"       Sends a remote blocking request for the given CIC on the specified linkset\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
-
-	if (a->argc == 6) {
+	if (a->argc == 5)
 		linkset = atoi(a->argv[3]);
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!strcasecmp(a->argv[1], "block")) {
-		do_block = 1;
-	} else if (strcasecmp(a->argv[1], "unblock")) {
+	else
 		return CLI_SHOWUSAGE;
-	}
 
 	if ((linkset < 1) || (linkset > NUM_SPANS)) {
 		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
@@ -16402,480 +16828,184 @@ static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct as
 		return CLI_SUCCESS;
 	}
 
-	cic = atoi(a->argv[5]);
+	cic = atoi(a->argv[4]);
+
 	if (cic < 1) {
 		ast_cli(a->fd, "Invalid CIC specified!\n");
 		return CLI_SUCCESS;
 	}
 
-	dpc = atoi(a->argv[4]);
-	if (dpc < 1) {
-		ast_cli(a->fd, "Invalid DPC specified!\n");
-		return CLI_SUCCESS;
-	}
-
 	for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
-		if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
+		if (linksets[linkset-1].ss7.pvts[i]->cic == cic) {
 			blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
-			if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
-				if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
-					ast_cli(a->fd, "Unable to allocate new ss7call\n");
-				} else {
-					ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
-				}
-			} else if (!do_block && blocked) {
-				ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
-			} else {
-				ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
-			}
-			return CLI_SUCCESS;
-		}
-	}
-
-	ast_cli(a->fd, "Invalid CIC specified!\n");
-	return CLI_SUCCESS;
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
-static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int linkset, i;
-	enum {
-		DO_BLOCK,
-		DO_UNBLOCK,
-		DO_RESET,
-	} do_what;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ss7 {reset|block|unblock} linkset";
-		e->usage =
-			"Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
-			"       Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc == 4) {
-		linkset = atoi(a->argv[3]);
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!strcasecmp(a->argv[1], "block")) {
-		do_what = DO_BLOCK;
-	} else if (!strcasecmp(a->argv[1], "unblock")) {
-		do_what = DO_UNBLOCK;
-	} else if (!strcasecmp(a->argv[1], "reset")) {
-		do_what = DO_RESET;
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset - 1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-
-	for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
-		/* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
-		if (linksets[linkset - 1].ss7.pvts[i]) {
-			switch (do_what) {
-			case DO_BLOCK:
-			case DO_UNBLOCK:
-				if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
-					ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
-						(do_what == DO_BLOCK) ? "blocking" : "unblocking",
-						linksets[linkset - 1].ss7.pvts[i]->cic);
-				}
-				break;
-			case DO_RESET:
-				if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
-					linksets[linkset - 1].ss7.pvts[i]->cic,
-					linksets[linkset - 1].ss7.pvts[i]->dpc)) {
-					ast_cli(a->fd, "Sent reset request on CIC %d\n",
-						linksets[linkset - 1].ss7.pvts[i]->cic);
-				}
-				break;
+			if (!blocked) {
+				ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+				isup_blo(linksets[linkset-1].ss7.ss7, cic, linksets[linkset-1].ss7.pvts[i]->dpc);
+				ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
 			}
 		}
 	}
 
-	return CLI_SUCCESS;
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
-static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int linkset, cic, range, chanpos;
-	int i, dpc, orient = 0;
-	int do_block = 0;
-	unsigned char state[255];
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ss7 {block|unblock} group";
-		e->usage =
-			"Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
-			"       Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc == 7 || a->argc == 8) {
-		linkset = atoi(a->argv[3]);
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!strcasecmp(a->argv[1], "block")) {
-		do_block = 1;
-	} else if (strcasecmp(a->argv[1], "unblock")) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (a->argc == 8) {
-		if (!strcasecmp(a->argv[7], "H")) {
-			orient = 1;
-		} else {
-			return CLI_SHOWUSAGE;
-		}
-	}
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset-1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-
-	cic = atoi(a->argv[5]);
-	if (cic < 1) {
+	if (blocked < 0) {
 		ast_cli(a->fd, "Invalid CIC specified!\n");
 		return CLI_SUCCESS;
 	}
 
-	range = atoi(a->argv[6]);
-	/* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
-	if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
-		ast_cli(a->fd, "Invalid range specified!\n");
-		return CLI_SUCCESS;
-	}
-
-	dpc = atoi(a->argv[4]);
-	if (dpc < 1) {
-		ast_cli(a->fd, "Invalid DPC specified!\n");
-		return CLI_SUCCESS;
-	}
-
-	ast_mutex_lock(&linksets[linkset-1].ss7.lock);
-	if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
-		ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
-		ast_cli(a->fd, "Invalid CIC/RANGE\n");
-		return CLI_SHOWUSAGE;
-	}
-
-	memset(state, 0, sizeof(state));
-	for (i = 0; i <= range; ++i) {
-		state[i] = 1;
-	}
-
-	/* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
-	chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
-	if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
-		ast_cli(a->fd, "Unable allocate new ss7call\n");
-	} else {
-		ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
-			orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
-	}
-
-	ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+	if (!blocked)
+		ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
+	else
+		ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
 
 	/* Break poll on the linkset so it sends our messages */
-	if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
-		pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
-	}
-	return CLI_SUCCESS;
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
-static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int linkset, cic, range;
-	unsigned int dpc;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ss7 reset group";
-		e->usage =
-			"Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
-			"       Send a GRS for the given CIC range on the specified linkset\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc == 7) {
-		linkset = atoi(a->argv[3]);
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset-1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-
-	cic = atoi(a->argv[5]);
-
-	if (cic < 1) {
-		ast_cli(a->fd, "Invalid CIC specified!\n");
-		return CLI_SUCCESS;
-	}
+	pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
 
-	range = atoi(a->argv[6]);
-	if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
-		ast_cli(a->fd, "Invalid range specified!\n");
-		return CLI_SUCCESS;
-	}
-
-	dpc = atoi(a->argv[4]);
-	if (dpc < 1) {
-		ast_cli(a->fd, "Invalid DPC specified!\n");
-		return CLI_SUCCESS;
-	}
-
-	ast_mutex_lock(&linksets[linkset-1].ss7.lock);
-	if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
-		ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
-		ast_cli(a->fd, "Invalid CIC/RANGE\n");
-		return CLI_SHOWUSAGE;
-	}
-
-	if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
-		ast_cli(a->fd, "Unable to allocate new ss7call\n");
-	} else {
-		ast_cli(a->fd, "GRS sent ... \n");
-	}
-
-	ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
-
-	/* Break poll on the linkset so it sends our messages */
-	if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
-		pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
-	}
 	return CLI_SUCCESS;
 }
 #endif	/* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int linkset;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ss7 show calls";
-		e->usage =
-			"Usage: ss7 show calls <linkset>\n"
-			"       Show SS7 calls on the specified linkset\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc == 4) {
-		linkset = atoi(a->argv[3]);
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset-1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-
-	ast_mutex_lock(&linksets[linkset-1].ss7.lock);
-	isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
-	ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
-static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int linkset, cic, res;
-	unsigned int dpc;
-
+	int i;
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "ss7 reset cic";
+		e->command = "ss7 block linkset";
 		e->usage =
-			"Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
-			"       Send a RSC for the given CIC on the specified linkset\n";
+			"Usage: ss7 block linkset <linkset number>\n"
+			"       Sends a remote blocking request for all CICs on the given linkset\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
-
-	if (a->argc == 6) {
+	if (a->argc == 4)
 		linkset = atoi(a->argv[3]);
-	} else {
+	else
 		return CLI_SHOWUSAGE;
-	}
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset-1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-
-	cic = atoi(a->argv[5]);
 
-	if (cic < 1) {
-		ast_cli(a->fd, "Invalid CIC specified!\n");
+	if ((linkset < 1) || (linkset > NUM_SPANS)) {
+		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
 		return CLI_SUCCESS;
 	}
 
-	dpc = atoi(a->argv[4]);
-	if (dpc < 1) {
-		ast_cli(a->fd, "Invalid DPC specified!\n");
+	if (!linksets[linkset-1].ss7.ss7) {
+		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
 		return CLI_SUCCESS;
 	}
 
-	res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
+	for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
+		ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].ss7.pvts[i]->cic);
+		ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+		isup_blo(linksets[linkset-1].ss7.ss7, linksets[linkset-1].ss7.pvts[i]->cic, linksets[linkset-1].ss7.pvts[i]->dpc);
+		ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+	}
 
-	ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
+	/* Break poll on the linkset so it sends our messages */
+	pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
 
 	return CLI_SUCCESS;
 }
 #endif	/* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	int linkset;
-	unsigned int slc;
-	unsigned int arg = 0;
-	const char *res;
-
+	int linkset, cic;
+	int i, blocked = -1;
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "ss7 mtp3";
+		e->command = "ss7 unblock cic";
 		e->usage =
-			"Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
-			"       Send a NET MNG message\n"
-			"       WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
+			"Usage: ss7 unblock cic <linkset> <CIC>\n"
+			"       Sends a remote unblocking request for the given CIC on the specified linkset\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
 
-	if (a->argc < 5) {
+	if (a->argc == 5)
+		linkset = atoi(a->argv[3]);
+	else
 		return CLI_SHOWUSAGE;
-	}
 
-	linkset = atoi(a->argv[2]);
 	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
+		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
 		return CLI_SUCCESS;
 	}
+
 	if (!linksets[linkset-1].ss7.ss7) {
 		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
 		return CLI_SUCCESS;
 	}
 
-	slc = atoi(a->argv[3]);
+	cic = atoi(a->argv[4]);
 
-	if (a->argc == 6) {
-		arg = atoi(a->argv[5]);
+	if (cic < 1) {
+		ast_cli(a->fd, "Invalid CIC specified!\n");
+		return CLI_SUCCESS;
 	}
 
-	ast_mutex_lock(&linksets[linkset-1].ss7.lock);
-	res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
-	ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
-
-	/* Break poll on the linkset so it sends our messages */
-	if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
-		pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
+	for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
+		if (linksets[linkset-1].ss7.pvts[i]->cic == cic) {
+			blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
+			if (blocked) {
+				ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+				isup_ubl(linksets[linkset-1].ss7.ss7, cic, linksets[linkset-1].ss7.pvts[i]->dpc);
+				ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+			}
+		}
 	}
 
-	ast_cli(a->fd, "%s", res);
+	if (blocked > 0)
+		ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
+
+	/* Break poll on the linkset so it sends our messages */
+	pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
 
 	return CLI_SUCCESS;
 }
 #endif	/* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int linkset;
-	unsigned int slc = 0;
-
+	int i;
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "ss7 restart mtp3";
+		e->command = "ss7 unblock linkset";
 		e->usage =
-			"Usage: ss7 restart mtp3 <linkset> <slc>\n"
-			"       Restart link\n";
+			"Usage: ss7 unblock linkset <linkset number>\n"
+			"       Sends a remote unblocking request for all CICs on the specified linkset\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
 
-	if (a->argc < 5) {
+	if (a->argc == 4)
+		linkset = atoi(a->argv[3]);
+	else
 		return CLI_SHOWUSAGE;
-	}
 
-	linkset = atoi(a->argv[3]);
 	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
+		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
 		return CLI_SUCCESS;
 	}
+
 	if (!linksets[linkset-1].ss7.ss7) {
 		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
 		return CLI_SUCCESS;
 	}
 
-	slc = atoi(a->argv[4]);
-
-	ast_mutex_lock(&linksets[linkset-1].ss7.lock);
-	mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
-	ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+	for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
+		ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].ss7.pvts[i]->cic);
+		ast_mutex_lock(&linksets[linkset-1].ss7.lock);
+		isup_ubl(linksets[linkset-1].ss7.ss7, linksets[linkset-1].ss7.pvts[i]->cic, linksets[linkset-1].ss7.pvts[i]->dpc);
+		ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
+	}
 
 	/* Break poll on the linkset so it sends our messages */
-	if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
-		pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
-	}
+	pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
 
 	return CLI_SUCCESS;
 }
@@ -16897,10 +17027,8 @@ static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct as
 		return NULL;
 	}
 
-	if (a->argc < 4) {
+	if (a->argc < 4)
 		return CLI_SHOWUSAGE;
-	}
-
 	linkset = atoi(a->argv[3]);
 	if ((linkset < 1) || (linkset > NUM_SPANS)) {
 		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
@@ -16912,16 +17040,7 @@ static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct as
 		return CLI_SUCCESS;
 	}
 
-	ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
 	ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
-	ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
-	ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
-	ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
-	ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
-	ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
-	ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
-	ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
-	ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
 
 	return CLI_SUCCESS;
 }
@@ -16943,9 +17062,8 @@ static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct a
 		return NULL;
 	}
 
-	if (a->argc != 3) {
+	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
-	}
 
 	sig_ss7_cli_show_channels_header(a->fd);
 	for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
@@ -16958,110 +17076,6 @@ static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct a
 #endif	/* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-#define FORMAT "%5s %5s %6s %12s   %-12s\n"
-#define FORMAT2 "%5i %5i %6i %12s   %-12s\n"
-	int i, linkset, dpc = 0;
-	struct sig_ss7_linkset *ss7;
-	char *state;
-	char blocking[12];
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ss7 show cics";
-		e->usage =
-			"Usage: ss7 show cics <linkset> [dpc]\n"
-			"       Shows the cics of an SS7 linkset.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc < 4 || a->argc > 5) {
-		return CLI_SHOWUSAGE;
-	}
-
-	linkset = atoi(a->argv[3]);
-
-	if ((linkset < 1) || (linkset > NUM_SPANS)) {
-		ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
-		return CLI_SUCCESS;
-	}
-
-	if (!linksets[linkset-1].ss7.ss7) {
-		ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
-		return CLI_SUCCESS;
-	}
-	ss7 = &linksets[linkset-1].ss7;
-
-	if (a->argc == 5) {
-		dpc = atoi(a->argv[4]);
-		if (dpc < 1) {
-			ast_cli(a->fd, "Invalid DPC specified!\n");
-			return CLI_SUCCESS;
-		}
-	}
-
-	ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
-
-	for (i = 0; i < ss7->numchans; i++) {
-		if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
-			struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
-
-			if (ss7->pvts[i]->owner) {
-				state = "Used";
-			} else if (ss7->pvts[i]->ss7call) {
-				state = "Pending";
-			} else if (!p->inservice) {
-				state = "NotInServ";
-			} else {
-				state = "Idle";
-			}
-
-			if (p->locallyblocked) {
-				strcpy(blocking, "L:");
-				if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
-					strcat(blocking, "M");
-				} else {
-					strcat(blocking, " ");
-				}
-
-				if (p->locallyblocked & SS7_BLOCKED_HARDWARE) {
-					strcat(blocking, "H");
-				} else {
-					strcat(blocking, " ");
-				}
-			} else {
-				strcpy(blocking, "    ");
-			}
-
-			if (p->remotelyblocked) {
-				strcat(blocking, " R:");
-				if (p->remotelyblocked & SS7_BLOCKED_MAINTENANCE) {
-					strcat(blocking, "M");
-				} else {
-					strcat(blocking, " ");
-				}
-
-				if (p->remotelyblocked & SS7_BLOCKED_HARDWARE) {
-					strcat(blocking, "H");
-				} else {
-					strcat(blocking, " ");
-				}
-			}
-
-			ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
-		}
-	}
-
-	return CLI_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-#endif	/* defined(HAVE_SS7) */
-
-#if defined(HAVE_SS7)
 static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	switch (cmd) {
@@ -17084,17 +17098,12 @@ static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli
 #if defined(HAVE_SS7)
 static struct ast_cli_entry dahdi_ss7_cli[] = {
 	AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
-	AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
-	AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
-	AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
-	AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
-	AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
-	AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
-	AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
+	AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
+	AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
+	AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
+	AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
 	AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
 	AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
-	AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
-	AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
 	AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
 };
 #endif	/* defined(HAVE_SS7) */
@@ -17248,9 +17257,6 @@ static int __unload_module(void)
 	ast_manager_unregister("DAHDIRestart");
 #if defined(HAVE_PRI)
 	ast_manager_unregister("PRIShowSpans");
-	ast_manager_unregister("PRIDebugSet");
-	ast_manager_unregister("PRIDebugFileSet");
-	ast_manager_unregister("PRIDebugFileUnset");
 #endif	/* defined(HAVE_PRI) */
 	ast_data_unregister(NULL);
 	ast_channel_unregister(&dahdi_tech);
@@ -17299,19 +17305,11 @@ static int __unload_module(void)
 		for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
 			dahdi_close_ss7_fd(&(linksets[i]), j);
 		}
-		if (linksets[i].ss7.ss7) {
-			ss7_destroy(linksets[i].ss7.ss7);
-			linksets[i].ss7.ss7 = NULL;
-		}
 	}
 #endif	/* defined(HAVE_SS7) */
 	ast_cond_destroy(&ss_thread_complete);
 
-	dahdi_native_unload();
-
-	ao2_cleanup(dahdi_tech.capabilities);
-	dahdi_tech.capabilities = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
+	dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities);
 	return 0;
 }
 
@@ -17354,7 +17352,7 @@ static char *parse_spanchan(char *chanstr, char **subdir)
 	return p;
 }
 
-static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
+static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno, int *found_pseudo)
 {
 	char *c, *chan;
 	char *subdir;
@@ -17377,6 +17375,8 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
 			finish = start;
 		} else if (!strcasecmp(chan, "pseudo")) {
 			finish = start = CHAN_PSEUDO;
+			if (found_pseudo)
+				*found_pseudo = 1;
 		} else {
 			ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
 			return -1;
@@ -17406,12 +17406,6 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
 					}
 				}
 			}
-			if (conf->wanted_channels_start &&
-				(real_channel < conf->wanted_channels_start ||
-				 real_channel > conf->wanted_channels_end)
-			   ) {
-				continue;
-			}
 			tmp = mkintf(real_channel, conf, reload);
 
 			if (tmp) {
@@ -17421,9 +17415,6 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
 						(reload == 1) ? "reconfigure" : "register", value);
 				return -1;
 			}
-			if (real_channel == CHAN_PSEUDO) {
-				has_pseudo = 1;
-			}
 		}
 	}
 
@@ -17579,13 +17570,13 @@ static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_patte
 
 	for (; ;) {
 		/* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
-		if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
+		if(!sscanf(v->value, "%30d", &norval) && count_pattern == 0) { 
 			ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
 			break;
 		}
 
-		busy_cadence->pattern[count_pattern] = norval;
-
+		busy_cadence->pattern[count_pattern] = norval; 
+		
 		count_pattern++;
 		if (count_pattern == 4) {
 			break;
@@ -17599,17 +17590,18 @@ static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_patte
 	}
 	busy_cadence->length = count_pattern;
 
-	if (count_pattern % 2 != 0) {
+	if (count_pattern % 2 != 0) { 
 		/* The pattern length must be divisible by two */
 		ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
 	}
-
+	
 }
 
 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
 {
 	struct dahdi_pvt *tmp;
 	int y;
+	int found_pseudo = 0;
 	struct ast_variable *dahdichan = NULL;
 
 	for (; v; v = v->next) {
@@ -17622,7 +17614,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
 				continue;
 			}
-			if (build_channels(confp, v->value, reload, v->lineno)) {
+			if (build_channels(confp, v->value, reload, v->lineno, &found_pseudo)) {
 				if (confp->ignore_failed_channels) {
 					ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
 					continue;
@@ -17709,16 +17701,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
 		} else if (!strcasecmp(v->name, "hasvoicemail")) {
 			if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
-				/*
-				 * hasvoicemail is a users.conf legacy voicemail enable method.
-				 * hasvoicemail is only going to work for app_voicemail mailboxes.
-				 */
-				if (strchr(cat, '@')) {
-					ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
-				} else {
-					snprintf(confp->chan.mailbox, sizeof(confp->chan.mailbox),
-						"%s at default", cat);
-				}
+				ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
 			}
 		} else if (!strcasecmp(v->name, "adsi")) {
 			confp->chan.adsi = ast_true(v->value);
@@ -17852,24 +17835,6 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			if (ast_true(v->value)) {
 				confp->chan.mwimonitor_fsk = 1;
 			}
-		} else if (!strcasecmp(v->name, "hwrxgain")) {
-			confp->chan.hwrxgain_enabled = 0;
-			if (strcasecmp(v->value, "disabled")) {
-				if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
-					confp->chan.hwrxgain_enabled = 1;
-				} else {
-					ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
-				}
-			}
-		} else if (!strcasecmp(v->name, "hwtxgain")) {
-			confp->chan.hwtxgain_enabled = 0;
-			if (strcasecmp(v->value, "disabled")) {
-				if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
-					confp->chan.hwtxgain_enabled = 1;
-				} else {
-					ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
-				}
-			}
 		} else if (!strcasecmp(v->name, "cid_rxgain")) {
 			if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
 				ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
@@ -17916,7 +17881,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 		} else if (!strcasecmp(v->name, "accountcode")) {
 			ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
 		} else if (!strcasecmp(v->name, "amaflags")) {
-			y = ast_channel_string2amaflag(v->value);
+			y = ast_cdr_amaflags2int(v->value);
 			if (y < 0)
 				ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
 			else
@@ -17943,23 +17908,23 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 #else
 			/* Default is fsk, to turn it off you must specify nofsk */
 			memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
-			if (strcasestr(v->value, "nofsk")) {		/* NoFSK */
+			if (strcasestr(v->value, "nofsk")) { 		/* NoFSK */
 				confp->chan.mwisend_fsk = 0;
 			} else {					/* Default FSK */
 				confp->chan.mwisend_fsk = 1;
 			}
-			if (strcasestr(v->value, "rpas")) {		/* Ring Pulse Alert Signal, normally followed by FSK */
+			if (strcasestr(v->value, "rpas")) { 		/* Ring Pulse Alert Signal, normally followed by FSK */
 				confp->chan.mwisend_rpas = 1;
 			} else {
 				confp->chan.mwisend_rpas = 0;
 			}
-			if (strcasestr(v->value, "lrev")) {		/* Line Reversal */
+			if (strcasestr(v->value, "lrev")) { 		/* Line Reversal */
 				confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
 			}
-			if (strcasestr(v->value, "hvdc")) {		/* HV 90VDC */
+			if (strcasestr(v->value, "hvdc")) { 		/* HV 90VDC */
 				confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
 			}
-			if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) {	/* 90V DC pulses */
+			if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ){ 	/* 90V DC pulses */
 				confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
 			}
 #endif
@@ -18252,6 +18217,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				else
 					ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
 						v->value, v->lineno);
+			} else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
+				confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
 			} else if (!strcasecmp(v->name, "minunused")) {
 				confp->pri.pri.minunused = atoi(v->value);
 			} else if (!strcasecmp(v->name, "minidle")) {
@@ -18287,7 +18254,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
 			} else if (!strcasecmp(v->name, "service_message_support")) {
 				/* assuming switchtype for this channel group has been configured already */
-				if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
+				if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS 
 					|| confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
 					|| confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
 					confp->pri.pri.enable_service_message_support = 1;
@@ -18406,9 +18373,6 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			} else if (!strcasecmp(v->name, "mwi_mailboxes")) {
 				ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
 					sizeof(confp->pri.pri.mwi_mailboxes));
-			} else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
-				ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
-					sizeof(confp->pri.pri.mwi_vm_boxes));
 			} else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
 				ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
 					sizeof(confp->pri.pri.mwi_vm_numbers));
@@ -18469,11 +18433,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 					cur_ss7type = SS7_ITU;
 				} else if (!strcasecmp(v->value, "ansi")) {
 					cur_ss7type = SS7_ANSI;
-				} else {
+				} else
 					ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
-				}
-			} else if (!strcasecmp(v->name, "slc")) {
-				cur_slc = atoi(v->value);
 			} else if (!strcasecmp(v->name, "linkset")) {
 				cur_linkset = atoi(v->value);
 			} else if (!strcasecmp(v->name, "pointcode")) {
@@ -18485,17 +18446,16 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			} else if (!strcasecmp(v->name, "cicbeginswith")) {
 				cur_cicbeginswith = atoi(v->value);
 			} else if (!strcasecmp(v->name, "networkindicator")) {
-				if (!strcasecmp(v->value, "national")) {
+				if (!strcasecmp(v->value, "national"))
 					cur_networkindicator = SS7_NI_NAT;
-				} else if (!strcasecmp(v->value, "national_spare")) {
+				else if (!strcasecmp(v->value, "national_spare"))
 					cur_networkindicator = SS7_NI_NAT_SPARE;
-				} else if (!strcasecmp(v->value, "international")) {
+				else if (!strcasecmp(v->value, "international"))
 					cur_networkindicator = SS7_NI_INT;
-				} else if (!strcasecmp(v->value, "international_spare")) {
+				else if (!strcasecmp(v->value, "international_spare"))
 					cur_networkindicator = SS7_NI_INT_SPARE;
-				} else {
+				else
 					cur_networkindicator = -1;
-				}
 			} else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
 				ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
 			} else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
@@ -18504,8 +18464,6 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
 			} else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
 				ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
-			} else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
-				ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
 			} else if (!strcasecmp(v->name, "ss7_called_nai")) {
 				if (!strcasecmp(v->value, "national")) {
 					confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
@@ -18538,9 +18496,9 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				int sigchan, res;
 				sigchan = atoi(v->value);
 				res = linkset_addsigchan(sigchan);
-				if (res < 0) {
+				if (res < 0)
 					return -1;
-				}
+
 			} else if (!strcasecmp(v->name, "ss7_explicitacm")) {
 				struct dahdi_ss7 *link;
 				link = ss7_resolve_linkset(cur_linkset);
@@ -18548,148 +18506,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
 					return -1;
 				}
-				if (ast_true(v->value)) {
+				if (ast_true(v->value))
 					link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
-				} else {
-					link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
-				}
-			} else if (!strcasecmp(v->name, "ss7_autoacm")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (ast_true(v->value)) {
-					link->ss7.flags |= LINKSET_FLAG_AUTOACM;
-				} else {
-					link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
-				}
-			} else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (ast_true(v->value)) {
-					link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
-				} else {
-					link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
-				}
-			} else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (ast_true(v->value)) {
-					link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
-				} else {
-					link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
-				}
-			} else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (ast_true(v->value)) {
-					link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
-				} else {
-					link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
-				}
-			} else if (!strncasecmp(v->name, "isup_timer.", 11)) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
-				} else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
-					ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
-				}
-			} else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
-				} else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
-					ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
-				}
-			} else if (!strcasecmp(v->name, "inr_if_no_calling")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
-				} else if (ast_true(v->value)) {
-					ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
-				} else {
-					ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
-				}
-			} else if (!strcasecmp(v->name, "non_isdn_access")) {
-				struct dahdi_ss7 *link;
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
-				} else if (ast_true(v->value)) {
-					ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
-				} else {
-					ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
-				}
-			} else if (!strcasecmp(v->name, "sls_shift")) {
-				struct dahdi_ss7 *link;
-				int sls_shift = atoi(v->value);
-
-				if (sls_shift < 0 || sls_shift > 7) {
-					ast_log(LOG_ERROR, "Invalid sls_shift value.  Must be between 0 and 7\n");
-					return -1;
-				}
-
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
-				} else {
-					ss7_set_sls_shift(link->ss7.ss7, sls_shift);
-				}
-			} else if (!strcasecmp(v->name, "cause_location")) {
-				struct dahdi_ss7 *link;
-				int cause_location = atoi(v->value);
-
-				if (cause_location < 0 || cause_location > 15) {
-					ast_log(LOG_ERROR, "Invalid cause_location value.  Must be between 0 and 15\n");
-					return -1;
-				}
-				link = ss7_resolve_linkset(cur_linkset);
-				if (!link) {
-					ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
-					return -1;
-				}
-				if (!link->ss7.ss7) {
-					ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
-				} else {
-					ss7_set_cause_location(link->ss7.ss7, cause_location);
-				}
 #endif	/* defined(HAVE_SS7) */
 #ifdef HAVE_OPENR2
 			} else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
@@ -18752,12 +18570,12 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
 			} else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
 				confp->mfcr2.max_ani = atoi(v->value);
-				if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
+				if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION){
 					confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
 				}
 			} else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
 				confp->mfcr2.max_dnis = atoi(v->value);
-				if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
+				if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION){
 					confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
 				}
 			} else if (!strcasecmp(v->name, "mfcr2_category")) {
@@ -18925,15 +18743,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
 	}
 
-	/* Since confp has already filled invidual dahdi_pvt objects with channels at this point, clear the variables in confp's pvt. */
-	if (confp->chan.vars) {
-		ast_variables_destroy(confp->chan.vars);
-		confp->chan.vars = NULL;
-	}
-
 	if (dahdichan) {
 		/* Process the deferred dahdichan value. */
-		if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
+		if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno,
+			&found_pseudo)) {
 			if (confp->ignore_failed_channels) {
 				ast_log(LOG_WARNING,
 					"Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
@@ -18944,11 +18757,20 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 		}
 	}
 
+	/*
+	 * Since confp has already filled individual dahdi_pvt objects with channels
+	 * at this point, clear the variables in confp's pvt.
+	 */
+	if (confp->chan.vars) {
+		ast_variables_destroy(confp->chan.vars);
+		confp->chan.vars = NULL;
+	}
+
 	/* mark the first channels of each DAHDI span to watch for their span alarms */
 	for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
 		if (!tmp->destroy && tmp->span != y) {
 			tmp->manages_span_alarms = 1;
-			y = tmp->span;
+			y = tmp->span; 
 		} else {
 			tmp->manages_span_alarms = 0;
 		}
@@ -18956,7 +18778,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 
 	/*< \todo why check for the pseudo in the per-channel section.
 	 * Any actual use for manual setup of the pseudo channel? */
-	if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
+	if (!found_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
 		/* use the default configuration for a channel, so
 		   that any settings from real configured channels
 		   don't "leak" into the pseudo channel config
@@ -18970,7 +18792,6 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 		}
 		if (tmp) {
 			ast_verb(3, "Automatically generated pseudo channel\n");
-			has_pseudo = 1;
 		} else {
 			ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
 		}
@@ -19250,8 +19071,7 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
 	if (reload != 1) {
 		int x;
 		for (x = 0; x < NUM_SPANS; x++) {
-			if (pris[x].pri.pvts[0] &&
-					pris[x].pri.master == AST_PTHREADT_NULL) {
+			if (pris[x].pri.pvts[0]) {
 				prepare_pri(pris + x);
 				if (sig_pri_start_pri(&pris[x].pri)) {
 					ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
@@ -19479,38 +19299,20 @@ static const struct ast_data_entry dahdi_data_providers[] = {
 	AST_DATA_ENTRY("asterisk/channel/dahdi/version", &dahdi_version_data_provider)
 };
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res;
+	struct ast_format tmpfmt;
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
 	int y;
 #endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) */
 
-	if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (!(dahdi_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	ast_format_cap_append(dahdi_tech.capabilities, ast_format_slin, 0);
-	ast_format_cap_append(dahdi_tech.capabilities, ast_format_ulaw, 0);
-	ast_format_cap_append(dahdi_tech.capabilities, ast_format_alaw, 0);
-
-	if (dahdi_native_load(ast_module_info->self, &dahdi_tech)) {
-		ao2_ref(dahdi_tech.capabilities, -1);
+	if (!(dahdi_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
+	ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
 
 #ifdef HAVE_PRI
 	memset(pris, 0, sizeof(pris));
@@ -19548,16 +19350,11 @@ static int load_module(void)
 	}
 	ss7_set_error(dahdi_ss7_error);
 	ss7_set_message(dahdi_ss7_message);
-	ss7_set_hangup(sig_ss7_cb_hangup);
-	ss7_set_notinservice(sig_ss7_cb_notinservice);
-	ss7_set_call_null(sig_ss7_cb_call_null);
 #endif	/* defined(HAVE_SS7) */
 	res = setup_dahdi(0);
 	/* Make sure we can register our DAHDI channel type */
-	if (res) {
-		__unload_module();
+	if (res)
 		return AST_MODULE_LOAD_DECLINE;
-	}
 	if (ast_channel_register(&dahdi_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
 		__unload_module();
@@ -19587,9 +19384,6 @@ static int load_module(void)
 	ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart);
 #if defined(HAVE_PRI)
 	ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
-	ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
-	ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
-	ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
 #endif	/* defined(HAVE_PRI) */
 
 	ast_cond_init(&ss_thread_complete, NULL);
@@ -19650,9 +19444,10 @@ static int dahdi_sendtext(struct ast_channel *c, const char *text)
 		return -1;
 	mybuf = buf;
 	if (p->mate) {
+		struct ast_format tmp;
 		/* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
-		struct ast_format *codec = AST_LAW(p);
-
+		struct ast_format *codec = &tmp;
+		ast_format_set(codec, AST_LAW(p), 0);
 		for (x = 0; x < HEADER_MS; x++) {	/* 50 ms of Mark */
 			PUT_CLID_MARKMS;
 		}
@@ -19735,10 +19530,9 @@ static int reload(void)
  */
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, tdesc,
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
 	.load_pri = AST_MODPRI_CHANNEL_DRIVER,
-	.nonoptreq = "res_smdi",
+		.nonoptreq = "res_smdi",
 	);
diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h
deleted file mode 100644
index e4a689a..0000000
--- a/channels/chan_dahdi.h
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief DAHDI internal API definitions.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_CHAN_DAHDI_H
-#define _ASTERISK_CHAN_DAHDI_H
-
-#if defined(HAVE_OPENR2)
-#include <openr2.h>
-#endif	/* defined(HAVE_OPENR2) */
-
-#include <dahdi/user.h>
-#include <dahdi/tonezone.h>
-
-#include "asterisk/channel.h"
-#include "asterisk/dsp.h"
-#include "asterisk/app.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/* ------------------------------------------------------------------- */
-
-#if defined(HAVE_PRI)
-struct sig_pri_span;
-#endif	/* defined(HAVE_PRI) */
-#if defined(HAVE_SS7)
-struct sig_ss7_linkset;
-#endif	/* defined(HAVE_SS7) */
-
-#define SUB_REAL		0			/*!< Active call */
-#define SUB_CALLWAIT	1			/*!< Call-Waiting call on hold */
-#define SUB_THREEWAY	2			/*!< Three-way call */
-
-
-struct distRingData {
-	int ring[3];
-	int range;
-};
-struct ringContextData {
-	char contextData[AST_MAX_CONTEXT];
-};
-struct dahdi_distRings {
-	struct distRingData ringnum[3];
-	struct ringContextData ringContext[3];
-};
-
-
-extern const char * const subnames[];
-
-struct dahdi_subchannel {
-	int dfd;
-	struct ast_channel *owner;
-	int chan;
-	short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
-	struct ast_frame f;		/*!< One frame for each channel.  How did this ever work before? */
-	unsigned int needringing:1;
-	unsigned int needbusy:1;
-	unsigned int needcongestion:1;
-	unsigned int needanswer:1;
-	unsigned int needflash:1;
-	unsigned int needhold:1;
-	unsigned int needunhold:1;
-	unsigned int linear:1;
-	unsigned int inthreeway:1;
-	struct dahdi_confinfo curconf;
-};
-
-#define MAX_SLAVES	4
-
-/* States for sending MWI message
- * First three states are required for send Ring Pulse Alert Signal
- */
-typedef enum {
-	MWI_SEND_NULL = 0,
-	MWI_SEND_SA,
-	MWI_SEND_SA_WAIT,
-	MWI_SEND_PAUSE,
-	MWI_SEND_SPILL,
-	MWI_SEND_CLEANUP,
-	MWI_SEND_DONE,
-} mwisend_states;
-
-struct mwisend_info {
-	struct timeval pause;
-	mwisend_states mwisend_current;
-};
-
-/*! Specify the lists dahdi_pvt can be put in. */
-enum DAHDI_IFLIST {
-	DAHDI_IFLIST_NONE,	/*!< The dahdi_pvt is not in any list. */
-	DAHDI_IFLIST_MAIN,	/*!< The dahdi_pvt is in the main interface list */
-#if defined(HAVE_PRI)
-	DAHDI_IFLIST_NO_B_CHAN,	/*!< The dahdi_pvt is in a no B channel interface list */
-#endif	/* defined(HAVE_PRI) */
-};
-
-struct dahdi_pvt {
-	ast_mutex_t lock;					/*!< Channel private lock. */
-	struct callerid_state *cs;
-	struct ast_channel *owner;			/*!< Our current active owner (if applicable) */
-							/*!< Up to three channels can be associated with this call */
-
-	struct dahdi_subchannel sub_unused;		/*!< Just a safety precaution */
-	struct dahdi_subchannel subs[3];			/*!< Sub-channels */
-	struct dahdi_confinfo saveconf;			/*!< Saved conference info */
-
-	struct dahdi_pvt *slaves[MAX_SLAVES];		/*!< Slave to us (follows our conferencing) */
-	struct dahdi_pvt *master;				/*!< Master to us (we follow their conferencing) */
-	int inconference;				/*!< If our real should be in the conference */
-
-	int bufsize;                /*!< Size of the buffers */
-	int buf_no;					/*!< Number of buffers */
-	int buf_policy;				/*!< Buffer policy */
-	int faxbuf_no;              /*!< Number of Fax buffers */
-	int faxbuf_policy;          /*!< Fax buffer policy */
-	int sig;					/*!< Signalling style */
-	/*!
-	 * \brief Nonzero if the signaling type is sent over a radio.
-	 * \note Set to a couple of nonzero values but it is only tested like a boolean.
-	 */
-	int radio;
-	int outsigmod;					/*!< Outbound Signalling style (modifier) */
-	int oprmode;					/*!< "Operator Services" mode */
-	struct dahdi_pvt *oprpeer;				/*!< "Operator Services" peer tech_pvt ptr */
-	/*! \brief Hardware Rx gain set by chan_dahdi.conf */
-	float hwrxgain;
-	/*! \brief Hardware Tx gain set by chan_dahdi.conf */
-	float hwtxgain;
-	/*! \brief Amount of gain to increase during caller id */
-	float cid_rxgain;
-	/*! \brief Software Rx gain set by chan_dahdi.conf */
-	float rxgain;
-	/*! \brief Software Tx gain set by chan_dahdi.conf */
-	float txgain;
-
-	float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */
-	float rxdrc;
-
-	int tonezone;					/*!< tone zone for this chan, or -1 for default */
-	enum DAHDI_IFLIST which_iflist;	/*!< Which interface list is this structure listed? */
-	struct dahdi_pvt *next;				/*!< Next channel in list */
-	struct dahdi_pvt *prev;				/*!< Prev channel in list */
-
-	/* flags */
-
-	/*!
-	 * \brief TRUE if ADSI (Analog Display Services Interface) available
-	 * \note Set from the "adsi" value read in from chan_dahdi.conf
-	 */
-	unsigned int adsi:1;
-	/*!
-	 * \brief TRUE if we can use a polarity reversal to mark when an outgoing
-	 * call is answered by the remote party.
-	 * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
-	 */
-	unsigned int answeronpolarityswitch:1;
-	/*!
-	 * \brief TRUE if busy detection is enabled.
-	 * (Listens for the beep-beep busy pattern.)
-	 * \note Set from the "busydetect" value read in from chan_dahdi.conf
-	 */
-	unsigned int busydetect:1;
-	/*!
-	 * \brief TRUE if call return is enabled.
-	 * (*69, if your dialplan doesn't catch this first)
-	 * \note Set from the "callreturn" value read in from chan_dahdi.conf
-	 */
-	unsigned int callreturn:1;
-	/*!
-	 * \brief TRUE if busy extensions will hear the call-waiting tone
-	 * and can use hook-flash to switch between callers.
-	 * \note Can be disabled by dialing *70.
-	 * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
-	 */
-	unsigned int callwaiting:1;
-	/*!
-	 * \brief TRUE if send caller ID for Call Waiting
-	 * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
-	 */
-	unsigned int callwaitingcallerid:1;
-	/*!
-	 * \brief TRUE if support for call forwarding enabled.
-	 * Dial *72 to enable call forwarding.
-	 * Dial *73 to disable call forwarding.
-	 * \note Set from the "cancallforward" value read in from chan_dahdi.conf
-	 */
-	unsigned int cancallforward:1;
-	/*!
-	 * \brief TRUE if support for call parking is enabled.
-	 * \note Set from the "canpark" value read in from chan_dahdi.conf
-	 */
-	unsigned int canpark:1;
-	/*! \brief TRUE if to wait for a DTMF digit to confirm answer */
-	unsigned int confirmanswer:1;
-	/*!
-	 * \brief TRUE if the channel is to be destroyed on hangup.
-	 * (Used by pseudo channels.)
-	 */
-	unsigned int destroy:1;
-	unsigned int didtdd:1;				/*!< flag to say its done it once */
-	/*! \brief TRUE if analog type line dialed no digits in Dial() */
-	unsigned int dialednone:1;
-	/*!
-	 * \brief TRUE if in the process of dialing digits or sending something.
-	 * \note This is used as a receive squelch for ISDN until connected.
-	 */
-	unsigned int dialing:1;
-	/*! \brief TRUE if the transfer capability of the call is digital. */
-	unsigned int digital:1;
-	/*! \brief TRUE if Do-Not-Disturb is enabled, present only for non sig_analog */
-	unsigned int dnd:1;
-	/*! \brief XXX BOOLEAN Purpose??? */
-	unsigned int echobreak:1;
-	/*!
-	 * \brief TRUE if echo cancellation enabled when bridged.
-	 * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
-	 * \note Disabled if the echo canceller is not setup.
-	 */
-	unsigned int echocanbridged:1;
-	/*! \brief TRUE if echo cancellation is turned on. */
-	unsigned int echocanon:1;
-	/*! \brief TRUE if a fax tone has already been handled. */
-	unsigned int faxhandled:1;
-	/*! TRUE if dynamic faxbuffers are configured for use, default is OFF */
-	unsigned int usefaxbuffers:1;
-	/*! TRUE while buffer configuration override is in use */
-	unsigned int bufferoverrideinuse:1;
-	/*! \brief TRUE if over a radio and dahdi_read() has been called. */
-	unsigned int firstradio:1;
-	/*!
-	 * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
-	 * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
-	 */
-	unsigned int hanguponpolarityswitch:1;
-	/*! \brief TRUE if DTMF detection needs to be done by hardware. */
-	unsigned int hardwaredtmf:1;
-	/*!
-	 * \brief TRUE if the outgoing caller ID is blocked/hidden.
-	 * \note Caller ID can be disabled by dialing *67.
-	 * \note Caller ID can be enabled by dialing *82.
-	 * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
-	 */
-	unsigned int hidecallerid:1;
-	/*!
-	 * \brief TRUE if hide just the name not the number for legacy PBX use.
-	 * \note Only applies to PRI channels.
-	 * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
-	 */
-	unsigned int hidecalleridname:1;
-	/*! \brief TRUE if DTMF detection is disabled. */
-	unsigned int ignoredtmf:1;
-	/*!
-	 * \brief TRUE if the channel should be answered immediately
-	 * without attempting to gather any digits.
-	 * \note Set from the "immediate" value read in from chan_dahdi.conf
-	 */
-	unsigned int immediate:1;
-	/*! \brief TRUE if in an alarm condition. */
-	unsigned int inalarm:1;
-	/*! \brief TRUE if TDD in MATE mode */
-	unsigned int mate:1;
-	/*! \brief TRUE if we originated the call leg. */
-	unsigned int outgoing:1;
-	/*!
-	 * \brief TRUE if busy extensions will hear the call-waiting tone
-	 * and can use hook-flash to switch between callers.
-	 * \note Set from the "callwaiting" value read in from chan_dahdi.conf
-	 */
-	unsigned int permcallwaiting:1;
-	/*!
-	 * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
-	 * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
-	 */
-	unsigned int permhidecallerid:1;
-	/*!
-	 * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
-	 * \note Set from the "priindication" value read in from chan_dahdi.conf
-	 */
-	unsigned int priindication_oob:1;
-	/*!
-	 * \brief TRUE if PRI B channels are always exclusively selected.
-	 * \note Set from the "priexclusive" value read in from chan_dahdi.conf
-	 */
-	unsigned int priexclusive:1;
-	/*!
-	 * \brief TRUE if we will pulse dial.
-	 * \note Set from the "pulsedial" value read in from chan_dahdi.conf
-	 */
-	unsigned int pulse:1;
-	/*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
-	unsigned int pulsedial:1;
-	unsigned int restartpending:1;		/*!< flag to ensure counted only once for restart */
-	/*!
-	 * \brief TRUE if caller ID is restricted.
-	 * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
-	 * \note Set from the "restrictcid" value read in from chan_dahdi.conf
-	 */
-	unsigned int restrictcid:1;
-	/*!
-	 * \brief TRUE if three way calling is enabled
-	 * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
-	 */
-	unsigned int threewaycalling:1;
-	/*!
-	 * \brief TRUE if call transfer is enabled
-	 * \note For FXS ports (either direct analog or over T1/E1):
-	 *   Support flash-hook call transfer
-	 * \note For digital ports using ISDN PRI protocols:
-	 *   Support switch-side transfer (called 2BCT, RLT or other names)
-	 * \note Set from the "transfer" value read in from chan_dahdi.conf
-	 */
-	unsigned int transfer:1;
-	/*!
-	 * \brief TRUE if caller ID is used on this channel.
-	 * \note PRI and SS7 spans will save caller ID from the networking peer.
-	 * \note FXS ports will generate the caller ID spill.
-	 * \note FXO ports will listen for the caller ID spill.
-	 * \note Set from the "usecallerid" value read in from chan_dahdi.conf
-	 */
-	unsigned int use_callerid:1;
-	/*!
-	 * \brief TRUE if we will use the calling presentation setting
-	 * from the Asterisk channel for outgoing calls.
-	 * \note Only applies to PRI and SS7 channels.
-	 * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
-	 */
-	unsigned int use_callingpres:1;
-	/*!
-	 * \brief TRUE if distinctive rings are to be detected.
-	 * \note For FXO lines
-	 * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
-	 */
-	unsigned int usedistinctiveringdetection:1;
-	/*!
-	 * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
-	 * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
-	 */
-	unsigned int dahditrcallerid:1;
-	/*!
-	 * \brief TRUE if allowed to flash-transfer to busy channels.
-	 * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
-	 */
-	unsigned int transfertobusy:1;
-	/*!
-	 * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
-	 * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
-	 */
-	unsigned int mwimonitor_neon:1;
-	/*!
-	 * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
-	 * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
-	 */
-	unsigned int mwimonitor_fsk:1;
-	/*!
-	 * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
-	 * \note RPAS - Ring Pulse Alert Signal
-	 * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
-	 */
-	unsigned int mwimonitor_rpas:1;
-	/*! \brief TRUE if an MWI monitor thread is currently active */
-	unsigned int mwimonitoractive:1;
-	/*! \brief TRUE if a MWI message sending thread is active */
-	unsigned int mwisendactive:1;
-	/*!
-	 * \brief TRUE if channel is out of reset and ready
-	 * \note Used by SS7.  Otherwise set but not used.
-	 */
-	unsigned int inservice:1;
-	/*!
-	 * \brief Bitmask for the channel being locally blocked.
-	 * \note Applies to SS7 and MFCR2 channels.
-	 * \note For MFCR2 only the first bit is used - TRUE if blocked
-	 * \note For SS7 two bits are used
-	 * \note Bit 0 - TRUE if maintenance blocked
-	 * \note Bit 1 - TRUE if hardware blocked
-	 */
-	unsigned int locallyblocked:2;
-	/*!
-	 * \brief Bitmask for the channel being remotely blocked. 1 maintenance, 2 blocked in hardware.
-	 * \note Applies to SS7 and MFCR2 channels.
-	 * \note For MFCR2 only the first bit is used - TRUE if blocked
-	 * \note For SS7 two bits are used
-	 * \note Bit 0 - TRUE if maintenance blocked
-	 * \note Bit 1 - TRUE if hardware blocked
-	 */
-	unsigned int remotelyblocked:2;
-	/*!
-	 * \brief TRUE if the channel alarms will be managed also as Span ones
-	 * \note Applies to all channels
-	 */
-	unsigned int manages_span_alarms:1;
-	/*! \brief TRUE if hardware Rx gain set by Asterisk */
-	unsigned int hwrxgain_enabled;
-	/*! \brief TRUE if hardware Tx gain set by Asterisk */
-	unsigned int hwtxgain_enabled;
-
-#if defined(HAVE_PRI)
-	struct sig_pri_span *pri;
-	int logicalspan;
-#endif	/* defined(HAVE_PRI) */
-	/*!
-	 * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
-	 * \note Set from the "usesmdi" value read in from chan_dahdi.conf
-	 */
-	unsigned int use_smdi:1;
-	struct mwisend_info mwisend_data;
-	/*! \brief The SMDI interface to get SMDI messages from. */
-	struct ast_smdi_interface *smdi_iface;
-
-	/*! \brief Distinctive Ring data */
-	struct dahdi_distRings drings;
-
-	/*!
-	 * \brief The configured context for incoming calls.
-	 * \note The "context" string read in from chan_dahdi.conf
-	 */
-	char context[AST_MAX_CONTEXT];
-	/*!
-	 * \brief A description for the channel configuration
-	 * \note The "description" string read in from chan_dahdi.conf
-	 */
-	char description[32];
-	/*!
-	 * \brief Saved context string.
-	 */
-	char defcontext[AST_MAX_CONTEXT];
-	/*! \brief Extension to use in the dialplan. */
-	char exten[AST_MAX_EXTENSION];
-	/*!
-	 * \brief Language configured for calls.
-	 * \note The "language" string read in from chan_dahdi.conf
-	 */
-	char language[MAX_LANGUAGE];
-	/*!
-	 * \brief The configured music-on-hold class to use for calls.
-	 * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
-	 */
-	char mohinterpret[MAX_MUSICCLASS];
-	/*!
-	 * \brief Suggested music-on-hold class for peer channel to use for calls.
-	 * \note The "mohsuggest" string read in from chan_dahdi.conf
-	 */
-	char mohsuggest[MAX_MUSICCLASS];
-	char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
-#if defined(HAVE_PRI) || defined(HAVE_SS7)
-	/*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
-	char cid_ani[AST_MAX_EXTENSION];
-#endif	/* defined(HAVE_PRI) || defined(HAVE_SS7) */
-	/*! \brief Automatic Number Identification code from PRI */
-	int cid_ani2;
-	/*! \brief Caller ID number from an incoming call. */
-	char cid_num[AST_MAX_EXTENSION];
-	/*!
-	 * \brief Caller ID tag from incoming call
-	 * \note the "cid_tag" string read in from chan_dahdi.conf
-	 */
-	char cid_tag[AST_MAX_EXTENSION];
-	/*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
-	int cid_ton;
-	/*! \brief Caller ID name from an incoming call. */
-	char cid_name[AST_MAX_EXTENSION];
-	/*! \brief Caller ID subaddress from an incoming call. */
-	char cid_subaddr[AST_MAX_EXTENSION];
-	char *origcid_num;				/*!< malloced original callerid */
-	char *origcid_name;				/*!< malloced original callerid */
-	/*! \brief Call waiting number. */
-	char callwait_num[AST_MAX_EXTENSION];
-	/*! \brief Call waiting name. */
-	char callwait_name[AST_MAX_EXTENSION];
-	/*! \brief Redirecting Directory Number Information Service (RDNIS) number */
-	char rdnis[AST_MAX_EXTENSION];
-	/*! \brief Dialed Number Identifier */
-	char dnid[AST_MAX_EXTENSION];
-	/*!
-	 * \brief Bitmapped groups this belongs to.
-	 * \note The "group" bitmapped group string read in from chan_dahdi.conf
-	 */
-	ast_group_t group;
-	/*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
-	int law_default;
-	/*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
-	int law;
-	int confno;					/*!< Our conference */
-	int confusers;					/*!< Who is using our conference */
-	int propconfno;					/*!< Propagated conference number */
-	/*!
-	 * \brief Bitmapped call groups this belongs to.
-	 * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
-	 */
-	ast_group_t callgroup;
-	/*!
-	 * \brief Bitmapped pickup groups this belongs to.
-	 * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
-	 */
-	ast_group_t pickupgroup;
-	/*!
-	 * \brief Named call groups this belongs to.
-	 * \note The "namedcallgroup" string read in from chan_dahdi.conf
-	 */
-	struct ast_namedgroups *named_callgroups;
-	/*!
-	 * \brief Named pickup groups this belongs to.
-	 * \note The "namedpickupgroup" string read in from chan_dahdi.conf
-	 */
-	struct ast_namedgroups *named_pickupgroups;
-	/*!
-	 * \brief Channel variable list with associated values to set when a channel is created.
-	 * \note The "setvar" strings read in from chan_dahdi.conf
-	 */
-	struct ast_variable *vars;
-	int channel;					/*!< Channel Number */
-	int span;					/*!< Span number */
-	time_t guardtime;				/*!< Must wait this much time before using for new call */
-	int cid_signalling;				/*!< CID signalling type bell202 or v23 */
-	int cid_start;					/*!< CID start indicator, polarity or ring or DTMF without warning event */
-	int dtmfcid_holdoff_state;		/*!< State indicator that allows for line to settle before checking for dtmf energy */
-	struct timeval	dtmfcid_delay;  /*!< Time value used for allow line to settle */
-	int callingpres;				/*!< The value of calling presentation that we're going to use when placing a PRI call */
-	int callwaitingrepeat;				/*!< How many samples to wait before repeating call waiting */
-	int cidcwexpire;				/*!< When to stop waiting for CID/CW CAS response (In samples) */
-	int cid_suppress_expire;		/*!< How many samples to suppress after a CID spill. */
-	/*! \brief Analog caller ID waveform sample buffer */
-	unsigned char *cidspill;
-	/*! \brief Position in the cidspill buffer to send out next. */
-	int cidpos;
-	/*! \brief Length of the cidspill buffer containing samples. */
-	int cidlen;
-	/*! \brief Ring timeout timer?? */
-	int ringt;
-	/*!
-	 * \brief Ring timeout base.
-	 * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
-	 */
-	int ringt_base;
-	/*!
-	 * \brief Number of most significant digits/characters to strip from the dialed number.
-	 * \note Feature is deprecated.  Use dialplan logic.
-	 * \note The characters are stripped before the PRI TON/NPI prefix
-	 * characters are processed.
-	 */
-	int stripmsd;
-	/*!
-	 * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
-	 * \note
-	 * After CAS is sent, the call waiting caller id will be sent if the phone
-	 * gives a positive reply.
-	 */
-	int callwaitcas;
-	/*! \brief Number of call waiting rings. */
-	int callwaitrings;
-	/*! \brief Echo cancel parameters. */
-	struct {
-		struct dahdi_echocanparams head;
-		struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
-	} echocancel;
-	/*!
-	 * \brief Echo training time. 0 = disabled
-	 * \note Set from the "echotraining" value read in from chan_dahdi.conf
-	 */
-	int echotraining;
-	/*! \brief Filled with 'w'.  XXX Purpose?? */
-	char echorest[20];
-	/*!
-	 * \brief Number of times to see "busy" tone before hanging up.
-	 * \note Set from the "busycount" value read in from chan_dahdi.conf
-	 */
-	int busycount;
-	/*!
-	 * \brief Busy cadence pattern description.
-	 * \note Set from the "busypattern" value read from chan_dahdi.conf
-	 */
-	struct ast_dsp_busy_pattern busy_cadence;
-	/*!
-	 * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
-	 * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
-	 */
-	int callprogress;
-	/*!
-	 * \brief Number of milliseconds to wait for dialtone.
-	 * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf
-	 */
-	int waitfordialtone;
-	/*!
-	 * \brief Number of frames to watch for dialtone in incoming calls
-	 * \note Set from the "dialtone_detect" value read in from chan_dahdi.conf
-	 */
-	int dialtone_detect;
-	int dialtone_scanning_time_elapsed;	/*!< Amount of audio scanned for dialtone, in frames */
-	struct timeval waitingfordt;			/*!< Time we started waiting for dialtone */
-	struct timeval flashtime;			/*!< Last flash-hook time */
-	/*! \brief Opaque DSP configuration structure. */
-	struct ast_dsp *dsp;
-	/*! \brief DAHDI dial operation command struct for ioctl() call. */
-	struct dahdi_dialoperation dop;
-	int whichwink;					/*!< SIG_FEATDMF_TA Which wink are we on? */
-	/*! \brief Second part of SIG_FEATDMF_TA wink operation. */
-	char finaldial[64];
-	char accountcode[AST_MAX_ACCOUNT_CODE];		/*!< Account code */
-	int amaflags;					/*!< AMA Flags */
-	struct tdd_state *tdd;				/*!< TDD flag */
-	/*! \brief Accumulated call forwarding number. */
-	char call_forward[AST_MAX_EXTENSION];
-	/*!
-	 * \brief Voice mailbox location.
-	 * \note Set from the "mailbox" string read in from chan_dahdi.conf
-	 */
-	char mailbox[AST_MAX_MAILBOX_UNIQUEID];
-	/*! \brief Opaque event subscription parameters for message waiting indication support. */
-	struct stasis_subscription *mwi_event_sub;
-	/*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
-	char dialdest[256];
-#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
-	struct dahdi_vmwi_info mwisend_setting;				/*!< Which VMWI methods to use */
-	unsigned int mwisend_fsk: 1;		/*! Variable for enabling FSK MWI handling in chan_dahdi */
-	unsigned int mwisend_rpas:1;		/*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
-#endif
-	int distinctivering;				/*!< Which distinctivering to use */
-	int dtmfrelax;					/*!< whether to run in relaxed DTMF mode */
-	/*! \brief Holding place for event injected from outside normal operation. */
-	int fake_event;
-	/*!
-	 * \brief Minimal time period (ms) between the answer polarity
-	 * switch and hangup polarity switch.
-	 */
-	int polarityonanswerdelay;
-	/*! \brief Start delay time if polarityonanswerdelay is nonzero. */
-	struct timeval polaritydelaytv;
-	/*!
-	 * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
-	 * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
-	 */
-	int sendcalleridafter;
-	/*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
-	int polarity;
-	/*! \brief DSP feature flags: DSP_FEATURE_xxx */
-	int dsp_features;
-#if defined(HAVE_SS7)
-	/*! \brief SS7 control parameters */
-	struct sig_ss7_linkset *ss7;
-#endif	/* defined(HAVE_SS7) */
-#if defined(HAVE_OPENR2)
-	struct dahdi_mfcr2 *mfcr2;
-	openr2_chan_t *r2chan;
-	openr2_calling_party_category_t mfcr2_recvd_category;
-	openr2_calling_party_category_t mfcr2_category;
-	int mfcr2_dnis_index;
-	int mfcr2_ani_index;
-	int mfcr2call:1;
-	int mfcr2_answer_pending:1;
-	int mfcr2_charge_calls:1;
-	int mfcr2_allow_collect_calls:1;
-	int mfcr2_forced_release:1;
-	int mfcr2_dnis_matched:1;
-	int mfcr2_call_accepted:1;
-	int mfcr2_accept_on_offer:1;
-	int mfcr2_progress_sent:1;
-#endif	/* defined(HAVE_OPENR2) */
-	/*! \brief DTMF digit in progress.  0 when no digit in progress. */
-	char begindigit;
-	/*! \brief TRUE if confrence is muted. */
-	int muting;
-	void *sig_pvt;
-	struct ast_cc_config_params *cc_params;
-	/* DAHDI channel names may differ greatly from the
-	 * string that was provided to an app such as Dial. We
-	 * need to save the original string passed to dahdi_request
-	 * for call completion purposes. This way, we can replicate
-	 * the original dialed string later.
-	 */
-	char dialstring[AST_CHANNEL_NAME];
-};
-
-
-/* Analog signaling */
-#define SIG_EM          DAHDI_SIG_EM
-#define SIG_EMWINK      (0x0100000 | DAHDI_SIG_EM)
-#define SIG_FEATD       (0x0200000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF     (0x0400000 | DAHDI_SIG_EM)
-#define SIG_FEATB       (0x0800000 | DAHDI_SIG_EM)
-#define SIG_E911        (0x1000000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF_TA  (0x2000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMA    (0x4000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMAMF  (0x8000000 | DAHDI_SIG_EM)
-#define SIG_FXSLS       DAHDI_SIG_FXSLS
-#define SIG_FXSGS       DAHDI_SIG_FXSGS
-#define SIG_FXSKS       DAHDI_SIG_FXSKS
-#define SIG_FXOLS       DAHDI_SIG_FXOLS
-#define SIG_FXOGS       DAHDI_SIG_FXOGS
-#define SIG_FXOKS       DAHDI_SIG_FXOKS
-#define SIG_SF          DAHDI_SIG_SF
-#define SIG_SFWINK      (0x0100000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATD    (0x0200000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATDMF  (0x0400000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATB    (0x0800000 | DAHDI_SIG_SF)
-#define SIG_EM_E1       DAHDI_SIG_EM_E1
-
-/* PRI signaling */
-#define SIG_PRI         DAHDI_SIG_CLEAR
-#define SIG_BRI         (0x2000000 | DAHDI_SIG_CLEAR)
-#define SIG_BRI_PTMP    (0X4000000 | DAHDI_SIG_CLEAR)
-
-/* SS7 signaling */
-#define SIG_SS7         (0x1000000 | DAHDI_SIG_CLEAR)
-
-/* MFC/R2 signaling */
-#define SIG_MFCR2       DAHDI_SIG_CAS
-
-
-#define SIG_PRI_LIB_HANDLE_CASES	\
-	SIG_PRI:						\
-	case SIG_BRI:					\
-	case SIG_BRI_PTMP
-
-/*!
- * \internal
- * \brief Determine if sig_pri handles the signaling.
- * \since 1.8
- *
- * \param signaling Signaling to determine if is for sig_pri.
- *
- * \return TRUE if the signaling is for sig_pri.
- */
-static inline int dahdi_sig_pri_lib_handles(int signaling)
-{
-	int handles;
-
-	switch (signaling) {
-	case SIG_PRI_LIB_HANDLE_CASES:
-		handles = 1;
-		break;
-	default:
-		handles = 0;
-		break;
-	}
-
-	return handles;
-}
-
-static inline int dahdi_analog_lib_handles(int signalling, int radio, int oprmode)
-{
-	switch (signalling) {
-	case SIG_FXOLS:
-	case SIG_FXOGS:
-	case SIG_FXOKS:
-	case SIG_FXSLS:
-	case SIG_FXSGS:
-	case SIG_FXSKS:
-	case SIG_EMWINK:
-	case SIG_EM:
-	case SIG_EM_E1:
-	case SIG_FEATD:
-	case SIG_FEATDMF:
-	case SIG_E911:
-	case SIG_FGC_CAMA:
-	case SIG_FGC_CAMAMF:
-	case SIG_FEATB:
-	case SIG_SFWINK:
-	case SIG_SF:
-	case SIG_SF_FEATD:
-	case SIG_SF_FEATDMF:
-	case SIG_FEATDMF_TA:
-	case SIG_SF_FEATB:
-		break;
-	default:
-		/* The rest of the function should cover the remainder of signalling types */
-		return 0;
-	}
-
-	if (radio) {
-		return 0;
-	}
-
-	if (oprmode) {
-		return 0;
-	}
-
-	return 1;
-}
-
-#define dahdi_get_index(ast, p, nullok)	_dahdi_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
-int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line);
-
-void dahdi_dtmf_detect_disable(struct dahdi_pvt *p);
-void dahdi_dtmf_detect_enable(struct dahdi_pvt *p);
-
-void dahdi_ec_enable(struct dahdi_pvt *p);
-void dahdi_ec_disable(struct dahdi_pvt *p);
-
-void dahdi_conf_update(struct dahdi_pvt *p);
-void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master);
-void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock);
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_CHAN_DAHDI_H */
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
new file mode 100644
index 0000000..83dca94
--- /dev/null
+++ b/channels/chan_gtalk.c
@@ -0,0 +1,2415 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ * Philippe Sultan <philippe.sultan at gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Matt O'Gorman <mogorman at digium.com>
+ * \author Philippe Sultan <philippe.sultan at gmail.com>
+ *
+ * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec
+ *
+ * \ingroup channel_drivers
+ *
+ * ********** General TODO:s
+ * \todo Support config reloading.
+ * \todo Fix native bridging.
+ */
+
+/*** MODULEINFO
+        <defaultenabled>no</defaultenabled>
+	<depend>iksemel</depend>
+	<depend>res_jabber</depend>
+	<use type="external">openssl</use>
+	<support_level>deprecated</support_level>
+	<replacement>chan_motif</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/signal.h>
+#include <iksemel.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/stun.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/manager.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/utils.h"
+#include "asterisk/causes.h"
+#include "asterisk/astobj.h"
+#include "asterisk/abstract_jb.h"
+#include "asterisk/jabber.h"
+#include "asterisk/jingle.h"
+#include "asterisk/features.h"
+
+#define GOOGLE_CONFIG		"gtalk.conf"
+
+/*! Global jitterbuffer configuration - by default, jb is disabled */
+static struct ast_jb_conf default_jbconf =
+{
+	.flags = 0,
+	.max_size = -1,
+	.resync_threshold = -1,
+	.impl = "",
+	.target_extra = -1,
+};
+static struct ast_jb_conf global_jbconf;
+
+enum gtalk_protocol {
+	AJI_PROTOCOL_UDP = 1,
+	AJI_PROTOCOL_SSLTCP = 2,
+};
+
+enum gtalk_connect_type {
+	AJI_CONNECT_STUN = 1,
+	AJI_CONNECT_LOCAL = 2,
+	AJI_CONNECT_RELAY = 3,
+};
+
+struct gtalk_pvt {
+	ast_mutex_t lock;                /*!< Channel private lock */
+	time_t laststun;
+	struct gtalk *parent;	         /*!< Parent client */
+	char sid[100];
+	char us[AJI_MAX_JIDLEN];
+	char them[AJI_MAX_JIDLEN];
+	char ring[10];                   /*!< Message ID of ring */
+	iksrule *ringrule;               /*!< Rule for matching RING request */
+	int initiator;                   /*!< If we're the initiator */
+	int alreadygone;
+	struct ast_codec_pref prefs;
+	struct gtalk_candidate *theircandidates;
+	struct gtalk_candidate *ourcandidates;
+	char cid_num[80];                /*!< Caller ID num */
+	char cid_name[80];               /*!< Caller ID name */
+	char exten[80];                  /*!< Called extension */
+	struct ast_channel *owner;       /*!< Master Channel */
+	struct ast_rtp_instance *rtp;             /*!< RTP audio session */
+	struct ast_rtp_instance *vrtp;            /*!< RTP video session */
+	struct ast_format_cap *cap;
+	struct ast_format_cap *jointcap;             /*!< Supported capability at both ends (codecs ) */
+	struct ast_format_cap *peercap;
+	struct gtalk_pvt *next;	/* Next entity */
+};
+
+struct gtalk_candidate {
+	char name[100];
+	enum gtalk_protocol protocol;
+	double preference;
+	char username[100];
+	char password[100];
+	enum gtalk_connect_type type;
+	char network[6];
+	int generation;
+	char ip[16];
+	int port;
+	int receipt;
+	struct gtalk_candidate *next;
+};
+
+struct gtalk {
+	ASTOBJ_COMPONENTS(struct gtalk);
+	struct aji_client *connection;
+	struct aji_buddy *buddy;
+	struct gtalk_pvt *p;
+	struct ast_codec_pref prefs;
+	int amaflags;			/*!< AMA Flags */
+	char user[AJI_MAX_JIDLEN];
+	char context[AST_MAX_CONTEXT];
+	char parkinglot[AST_MAX_CONTEXT];	/*!<  Parkinglot */
+	char accountcode[AST_MAX_ACCOUNT_CODE];	/*!< Account code */
+	struct ast_format_cap *cap;
+	ast_group_t callgroup;	/*!< Call group */
+	ast_group_t pickupgroup;	/*!< Pickup group */
+	int callingpres;		/*!< Calling presentation */
+	int allowguest;
+	char language[MAX_LANGUAGE];	/*!<  Default language for prompts */
+	char musicclass[MAX_MUSICCLASS];	/*!<  Music on Hold class */
+};
+
+struct gtalk_container {
+	ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
+};
+
+static const char desc[]		= "Gtalk Channel";
+static const char DEFAULT_CONTEXT[]	= "default";
+static const int DEFAULT_ALLOWGUEST	= 1;
+
+static struct ast_format_cap *global_capability;
+
+AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pvt's) */
+
+/* Forward declarations */
+static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+/*static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);*/
+static int gtalk_sendtext(struct ast_channel *ast, const char *text);
+static int gtalk_digit_begin(struct ast_channel *ast, char digit);
+static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout);
+static int gtalk_hangup(struct ast_channel *ast);
+static int gtalk_answer(struct ast_channel *ast);
+static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);
+static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);
+static int gtalk_newcall(struct gtalk *client, ikspak *pak);
+static struct ast_frame *gtalk_read(struct ast_channel *ast);
+static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
+static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
+static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
+static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p);
+/* static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); */
+static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static int gtalk_update_externip(void);
+static int gtalk_parser(void *data, ikspak *pak);
+static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to);
+
+/*! \brief PBX interface structure for channel registration */
+static struct ast_channel_tech gtalk_tech = {
+	.type = "Gtalk",
+	.description = "Gtalk Channel Driver",
+	.requester = gtalk_request,
+	.send_text = gtalk_sendtext,
+	.send_digit_begin = gtalk_digit_begin,
+	.send_digit_end = gtalk_digit_end,
+	/* XXX TODO native bridging is causing odd problems with DTMF pass-through with
+	 * the gtalk servers. Enable native bridging once the source of this problem has
+	 * been identified.
+	.bridge = ast_rtp_instance_bridge, */
+	.call = gtalk_call,
+	.hangup = gtalk_hangup,
+	.answer = gtalk_answer,
+	.read = gtalk_read,
+	.write = gtalk_write,
+	.exception = gtalk_read,
+	.indicate = gtalk_indicate,
+	.fixup = gtalk_fixup,
+	.send_html = gtalk_sendhtml,
+	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
+};
+
+static struct sockaddr_in bindaddr = { 0, };	/*!< The address we bind to */
+
+static struct ast_sched_context *sched;	/*!< The scheduling context */
+static struct io_context *io;	/*!< The IO context */
+static struct in_addr __ourip;
+
+static struct ast_cli_entry gtalk_cli[] = {
+/*	AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"), XXX TODO reloads are not possible yet. */
+	AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
+	AST_CLI_DEFINE(gtalk_show_settings, "Show GoogleTalk global settings"),
+};
+
+static char externip[16];
+static char global_context[AST_MAX_CONTEXT];
+static char global_parkinglot[AST_MAX_CONTEXT];
+static int global_allowguest;
+static struct sockaddr_in stunaddr; /*!< the stun server we get the externip from */
+static int global_stunaddr;
+
+static struct gtalk_container gtalk_list;
+
+static void gtalk_member_destroy(struct gtalk *obj)
+{
+	obj->cap = ast_format_cap_destroy(obj->cap);
+	if (obj->connection) {
+		ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
+	}
+	if (obj->buddy) {
+		ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
+	}
+	ast_free(obj);
+}
+
+/* XXX This could be a source of reference leaks given that the CONTAINER_FIND
+ * macros bump the refcount while the traversal does not. */
+static struct gtalk *find_gtalk(char *name, char *connection)
+{
+	struct gtalk *gtalk = NULL;
+	char *domain = NULL , *s = NULL;
+
+	if (strchr(connection, '@')) {
+		s = ast_strdupa(connection);
+		domain = strsep(&s, "@");
+		ast_verbose("OOOOH domain = %s\n", domain);
+	}
+	gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
+	if (!gtalk && strchr(name, '@'))
+		gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
+
+	if (!gtalk) {
+		/* guest call */
+		ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			if (!strcasecmp(iterator->name, "guest")) {
+				gtalk = iterator;
+			}
+			ASTOBJ_UNLOCK(iterator);
+
+			if (gtalk)
+				break;
+		});
+
+	}
+	return gtalk;
+}
+
+
+static int add_codec_to_answer(const struct gtalk_pvt *p, struct ast_format *codec, iks *dcodecs)
+{
+	int res = 0;
+	const char *format = ast_getformatname(codec);
+
+	if (!strcasecmp("ulaw", format)) {
+		iks *payload_eg711u, *payload_pcmu;
+		payload_pcmu = iks_new("payload-type");
+		payload_eg711u = iks_new("payload-type");
+
+		if(!payload_eg711u || !payload_pcmu) {
+			iks_delete(payload_pcmu);
+			iks_delete(payload_eg711u);
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_pcmu, "id", "0");
+		iks_insert_attrib(payload_pcmu, "name", "PCMU");
+		iks_insert_attrib(payload_pcmu, "clockrate","8000");
+		iks_insert_attrib(payload_pcmu, "bitrate","64000");
+		iks_insert_attrib(payload_eg711u, "id", "100");
+		iks_insert_attrib(payload_eg711u, "name", "EG711U");
+		iks_insert_attrib(payload_eg711u, "clockrate","8000");
+		iks_insert_attrib(payload_eg711u, "bitrate","64000");
+		iks_insert_node(dcodecs, payload_pcmu);
+		iks_insert_node(dcodecs, payload_eg711u);
+		res ++;
+	}
+	if (!strcasecmp("alaw", format)) {
+		iks *payload_eg711a, *payload_pcma;
+		payload_pcma = iks_new("payload-type");
+		payload_eg711a = iks_new("payload-type");
+		if(!payload_eg711a || !payload_pcma) {
+			iks_delete(payload_eg711a);
+			iks_delete(payload_pcma);
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_pcma, "id", "8");
+		iks_insert_attrib(payload_pcma, "name", "PCMA");
+		iks_insert_attrib(payload_pcma, "clockrate","8000");
+		iks_insert_attrib(payload_pcma, "bitrate","64000");
+		payload_eg711a = iks_new("payload-type");
+		iks_insert_attrib(payload_eg711a, "id", "101");
+		iks_insert_attrib(payload_eg711a, "name", "EG711A");
+		iks_insert_attrib(payload_eg711a, "clockrate","8000");
+		iks_insert_attrib(payload_eg711a, "bitrate","64000");
+		iks_insert_node(dcodecs, payload_pcma);
+		iks_insert_node(dcodecs, payload_eg711a);
+		res ++;
+	}
+	if (!strcasecmp("ilbc", format)) {
+		iks *payload_ilbc = iks_new("payload-type");
+		if(!payload_ilbc) {
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_ilbc, "id", "97");
+		iks_insert_attrib(payload_ilbc, "name", "iLBC");
+		iks_insert_attrib(payload_ilbc, "clockrate","8000");
+		iks_insert_attrib(payload_ilbc, "bitrate","13300");
+		iks_insert_node(dcodecs, payload_ilbc);
+		res ++;
+	}
+	if (!strcasecmp("g723", format)) {
+		iks *payload_g723 = iks_new("payload-type");
+		if(!payload_g723) {
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_g723, "id", "4");
+		iks_insert_attrib(payload_g723, "name", "G723");
+		iks_insert_attrib(payload_g723, "clockrate","8000");
+		iks_insert_attrib(payload_g723, "bitrate","6300");
+		iks_insert_node(dcodecs, payload_g723);
+		res ++;
+	}
+	if (!strcasecmp("speex", format)) {
+		iks *payload_speex = iks_new("payload-type");
+		if(!payload_speex) {
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_speex, "id", "110");
+		iks_insert_attrib(payload_speex, "name", "speex");
+		iks_insert_attrib(payload_speex, "clockrate","8000");
+		iks_insert_attrib(payload_speex, "bitrate","11000");
+		iks_insert_node(dcodecs, payload_speex);
+		res++;
+	}
+	if (!strcasecmp("gsm", format)) {
+		iks *payload_gsm = iks_new("payload-type");
+		if(!payload_gsm) {
+			ast_log(LOG_WARNING,"Failed to allocate iks node\n");
+			return -1;
+		}
+		iks_insert_attrib(payload_gsm, "id", "103");
+		iks_insert_attrib(payload_gsm, "name", "gsm");
+		iks_insert_node(dcodecs, payload_gsm);
+		res++;
+	}
+
+	return res;
+}
+
+static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
+{
+	struct gtalk *client = p->parent;
+	iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
+	int x;
+	struct ast_format_cap *alreadysent;
+	int codecs_num = 0;
+	char *lowerto = NULL;
+	struct ast_format tmpfmt;
+
+	iq = iks_new("iq");
+	gtalk = iks_new("session");
+	dcodecs = iks_new("description");
+	transport = iks_new("transport");
+	payload_telephone = iks_new("payload-type");
+	if (!(iq && gtalk && dcodecs && transport && payload_telephone)) {
+		iks_delete(iq);
+		iks_delete(gtalk);
+		iks_delete(dcodecs);
+		iks_delete(transport);
+		iks_delete(payload_telephone);
+
+		ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
+		return 0;
+	}
+	iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
+	iks_insert_attrib(dcodecs, "xml:lang", "en");
+
+	if (!(alreadysent = ast_format_cap_alloc_nolock())) {
+		return 0;
+	}
+	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+		if (!(ast_codec_pref_index(&client->prefs, x, &tmpfmt))) {
+			break;
+		}
+		if (!(ast_format_cap_iscompatible(client->cap, &tmpfmt))) {
+			continue;
+		}
+		if (ast_format_cap_iscompatible(alreadysent, &tmpfmt)) {
+			continue;
+		}
+		codecs_num = add_codec_to_answer(p, &tmpfmt, dcodecs);
+		ast_format_cap_add(alreadysent, &tmpfmt);
+	}
+	alreadysent = ast_format_cap_destroy(alreadysent);
+
+	if (codecs_num) {
+		/* only propose DTMF within an audio session */
+		iks_insert_attrib(payload_telephone, "id", "101");
+		iks_insert_attrib(payload_telephone, "name", "telephone-event");
+		iks_insert_attrib(payload_telephone, "clockrate", "8000");
+	}
+	iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
+
+	iks_insert_attrib(iq, "type", "set");
+	iks_insert_attrib(iq, "to", to);
+	iks_insert_attrib(iq, "from", from);
+	iks_insert_attrib(iq, "id", client->connection->mid);
+	ast_aji_increment_mid(client->connection->mid);
+
+	iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
+	iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
+	/* put the initiator attribute to lower case if we receive the call
+	 * otherwise GoogleTalk won't establish the session */
+	if (!initiator) {
+	        char c;
+	        char *t = lowerto = ast_strdupa(to);
+		while (((c = *t) != '/') && (*t++ = tolower(c)));
+	}
+	iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
+	iks_insert_attrib(gtalk, "id", sid);
+	iks_insert_node(iq, gtalk);
+	iks_insert_node(gtalk, dcodecs);
+	iks_insert_node(dcodecs, payload_telephone);
+
+	ast_aji_send(client->connection, iq);
+
+	iks_delete(payload_telephone);
+	iks_delete(transport);
+	iks_delete(dcodecs);
+	iks_delete(gtalk);
+	iks_delete(iq);
+	return 1;
+}
+
+static int gtalk_ringing_ack(void *data, ikspak *pak)
+{
+	struct gtalk_pvt *p = data;
+	struct ast_channel *owner;
+
+	ast_mutex_lock(&p->lock);
+
+	if (p->ringrule) {
+		iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
+	}
+	p->ringrule = NULL;
+
+	/* this may be a redirect */
+	if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
+		char *name = NULL;
+		char *redirect = NULL;
+		iks *traversenodes = NULL;
+		traversenodes = pak->query;
+		while (traversenodes) {
+			if (!(name = iks_name(traversenodes))) {
+				break;
+			}
+			if (!strcasecmp(name, "error") &&
+				((redirect = iks_find_cdata(traversenodes, "redirect")) ||
+				  (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
+				(redirect = strstr(redirect, "xmpp:"))) {
+				redirect += 5;
+				ast_debug(1, "redirect %s\n", redirect);
+				ast_copy_string(p->them, redirect, sizeof(p->them));
+
+				gtalk_invite(p, p->them, p->us, p->sid, 1);
+				break;
+			}
+			traversenodes = iks_next_tag(traversenodes);
+		}
+	}
+	gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
+	owner = p->owner;
+	ast_mutex_unlock(&p->lock);
+
+	if (owner) {
+		ast_queue_control(owner, AST_CONTROL_RINGING);
+	}
+
+	return IKS_FILTER_EAT;
+}
+
+static int gtalk_answer(struct ast_channel *ast)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
+	int res = 0;
+
+	ast_debug(1, "Answer!\n");
+	ast_mutex_lock(&p->lock);
+	gtalk_invite(p, p->them, p->us,p->sid, 0);
+	manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
+		ast_channel_name(ast), "GTALK", p->sid);
+	ast_mutex_unlock(&p->lock);
+	return res;
+}
+
+static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
+	enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+	if (!p)
+		return res;
+
+	ast_mutex_lock(&p->lock);
+	if (p->rtp){
+		ao2_ref(p->rtp, +1);
+		*instance = p->rtp;
+		res = AST_RTP_GLUE_RESULT_LOCAL;
+	}
+	ast_mutex_unlock(&p->lock);
+
+	return res;
+}
+
+static void gtalk_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
+	ast_mutex_lock(&p->lock);
+	ast_format_cap_copy(result, p->peercap);
+	ast_mutex_unlock(&p->lock);
+}
+
+static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *cap, int nat_active)
+{
+	struct gtalk_pvt *p;
+
+	p = ast_channel_tech_pvt(chan);
+	if (!p)
+		return -1;
+	ast_mutex_lock(&p->lock);
+
+/*	if (rtp)
+		ast_rtp_get_peer(rtp, &p->redirip);
+	else
+		memset(&p->redirip, 0, sizeof(p->redirip));
+	p->redircodecs = codecs; */
+
+	/* Reset lastrtprx timer */
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static struct ast_rtp_glue gtalk_rtp_glue = {
+	.type = "Gtalk",
+	.get_rtp_info = gtalk_get_rtp_peer,
+	.get_codec = gtalk_get_codec,
+	.update_peer = gtalk_set_rtp_peer,
+};
+
+static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
+{
+	iks *response = NULL, *error = NULL, *reason = NULL;
+	int res = -1;
+
+	response = iks_new("iq");
+	if (response) {
+		iks_insert_attrib(response, "type", "result");
+		iks_insert_attrib(response, "from", from);
+		iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
+		iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
+		if (reasonstr) {
+			error = iks_new("error");
+			if (error) {
+				iks_insert_attrib(error, "type", "cancel");
+				reason = iks_new(reasonstr);
+				if (reason)
+					iks_insert_node(error, reason);
+				iks_insert_node(response, error);
+			}
+		}
+		ast_aji_send(client->connection, response);
+		res = 0;
+	}
+
+	iks_delete(reason);
+	iks_delete(error);
+	iks_delete(response);
+
+	return res;
+}
+
+static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *tmp = NULL;
+	char *from;
+	iks *codec;
+	char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
+	int peernoncodeccapability;
+
+	ast_debug(1, "The client is %s\n", client->name);
+
+	/* Make sure our new call does exist */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
+			break;
+		} else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
+			break;
+		}
+	}
+
+	if (!tmp) {
+		ast_log(LOG_WARNING, "Could not find session in iq\n");
+		return -1;
+	}
+
+	/* codec points to the first <payload-type/> tag */
+	codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
+	while (codec) {
+		char *codec_id = iks_find_attrib(codec, "id");
+		char *codec_name = iks_find_attrib(codec, "name");
+		if (!codec_id || !codec_name) {
+			codec = iks_next_tag(codec);
+			continue;
+		}
+
+		ast_rtp_codecs_payloads_set_m_type(
+			ast_rtp_instance_get_codecs(tmp->rtp),
+			tmp->rtp,
+			atoi(codec_id));
+		ast_rtp_codecs_payloads_set_rtpmap_type(
+			ast_rtp_instance_get_codecs(tmp->rtp),
+			tmp->rtp,
+			atoi(codec_id),
+			"audio",
+			codec_name,
+			0);
+		codec = iks_next_tag(codec);
+	}
+
+	/* Now gather all of the codecs that we are asked for */
+	ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), tmp->peercap, &peernoncodeccapability);
+
+	/* at this point, we received an answer from the remote Gtalk client,
+	   which allows us to compare capabilities */
+	ast_format_cap_joint_copy(tmp->cap, tmp->peercap, tmp->jointcap);
+	if (ast_format_cap_is_empty(tmp->jointcap)) {
+		ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->cap),
+			ast_getformatname_multiple(s2, BUFSIZ, tmp->peercap),
+			ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcap));
+		/* close session if capabilities don't match */
+		ast_queue_hangup(tmp->owner);
+
+		return -1;
+
+	}
+
+	from = iks_find_attrib(pak->x, "to");
+	if (!from) {
+		from = client->connection->jid->full;
+	}
+
+	if (tmp->owner) {
+		ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
+	}
+	gtalk_update_stun(tmp->parent, tmp);
+	gtalk_response(client, from, pak, NULL, NULL);
+	return 1;
+}
+
+static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *tmp;
+	char *from;
+
+	ast_debug(1, "The client is %s\n", client->name);
+	/* find corresponding call */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
+			break;
+		}
+	}
+
+	from = iks_find_attrib(pak->x, "to");
+	if (!from) {
+		from = client->connection->jid->full;
+	}
+
+	if (tmp) {
+		gtalk_update_stun(tmp->parent, tmp);
+	} else {
+		ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
+	}
+
+	/* answer 'iq' packet to let the remote peer know that we're alive */
+	gtalk_response(client, from, pak, NULL, NULL);
+	return 1;
+}
+
+static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *tmp;
+	iks *dtmfnode = NULL, *dtmfchild = NULL;
+	char *dtmf;
+	char *from;
+	/* Make sure our new call doesn't exist yet */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
+			break;
+	}
+	from = iks_find_attrib(pak->x, "to");
+	if (!from) {
+		from = client->connection->jid->full;
+	}
+
+	if (tmp) {
+		if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
+			gtalk_response(client, from, pak,
+					"feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
+					"unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
+			return -1;
+		}
+		if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
+			if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
+				if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
+					struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
+				} else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
+					struct ast_frame f = {AST_FRAME_DTMF_END, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
+				} else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
+					struct ast_frame f = {AST_FRAME_DTMF, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
+				}
+			}
+		} else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
+			if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
+				if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
+					if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
+						struct ast_frame f = {AST_FRAME_DTMF_END, };
+						f.subclass.integer = dtmf[0];
+						ast_queue_frame(tmp->owner, &f);
+						ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
+					} else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
+						struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
+						f.subclass.integer = dtmf[0];
+						ast_queue_frame(tmp->owner, &f);
+						ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
+					}
+				}
+			}
+		}
+		gtalk_response(client, from, pak, NULL, NULL);
+		return 1;
+	} else {
+		ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
+	}
+
+	gtalk_response(client, from, pak, NULL, NULL);
+	return 1;
+}
+
+static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *tmp;
+	char *from;
+
+	ast_debug(1, "The client is %s\n", client->name);
+	/* Make sure our new call doesn't exist yet */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
+			(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
+			break;
+		}
+	}
+	from = iks_find_attrib(pak->x, "to");
+	if (!from) {
+		from = client->connection->jid->full;
+	}
+
+	if (tmp) {
+		tmp->alreadygone = 1;
+		if (tmp->owner) {
+			ast_queue_hangup(tmp->owner);
+		}
+	} else {
+		ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
+	}
+	gtalk_response(client, from, pak, NULL, NULL);
+	return 1;
+}
+
+static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
+{
+	struct ast_sockaddr root;
+	struct ast_sockaddr bindaddr_tmp;
+	struct ast_sockaddr *addrs;
+
+	/* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
+		ast_sockaddr_copy(ourip, &bindaddr_tmp);
+		return 0;
+	}
+
+	/* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
+	 * If you can't resolve google.com from your network, then this module is useless for you anyway. */
+	if (ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET) > 0) {
+		ast_sockaddr_copy(&root, &addrs[0]);
+		ast_free(addrs);
+		if (!ast_ouraddrfor(&root, ourip)) {
+			return 0;
+		}
+	}
+
+	/* As a last resort, use this function to find our local address. */
+	return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
+}
+
+static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
+{
+	struct gtalk_candidate *tmp;
+	struct aji_client *c = client->connection;
+	struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
+	struct sockaddr_in sin = { 0, };
+	struct ast_sockaddr sin_tmp;
+	struct ast_sockaddr us;
+	iks *iq, *gtalk, *candidate, *transport;
+	char user[17], pass[17], preference[5], port[7];
+	char *lowerfrom = NULL;
+
+	iq = iks_new("iq");
+	gtalk = iks_new("session");
+	candidate = iks_new("candidate");
+	transport = iks_new("transport");
+	if (!iq || !gtalk || !candidate || !transport) {
+		ast_log(LOG_ERROR, "Memory allocation error\n");
+		goto safeout;
+	}
+	ours1 = ast_calloc(1, sizeof(*ours1));
+	ours2 = ast_calloc(1, sizeof(*ours2));
+	if (!ours1 || !ours2)
+		goto safeout;
+
+	iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
+	iks_insert_node(iq, gtalk);
+	iks_insert_node(gtalk,candidate);
+	iks_insert_node(gtalk,transport);
+
+	for (; p; p = p->next) {
+		if (!strcasecmp(p->sid, sid))
+			break;
+	}
+
+	if (!p) {
+		ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
+		goto safeout;
+	}
+
+	ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
+	ast_sockaddr_to_sin(&sin_tmp, &sin);
+
+	gtalk_get_local_ip(&us);
+
+	if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
+		ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.\n");
+	}
+
+	/* Setup our gtalk candidates */
+	ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
+	ours1->port = ntohs(sin.sin_port);
+	ours1->preference = 1;
+	snprintf(user, sizeof(user), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
+	snprintf(pass, sizeof(pass), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
+	ast_copy_string(ours1->username, user, sizeof(ours1->username));
+	ast_copy_string(ours1->password, pass, sizeof(ours1->password));
+	ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
+			sizeof(ours1->ip));
+	ours1->protocol = AJI_PROTOCOL_UDP;
+	ours1->type = AJI_CONNECT_LOCAL;
+	ours1->generation = 0;
+	p->ourcandidates = ours1;
+
+	/* XXX this is a blocking action.  We send a STUN request to the server
+	 * and wait for the response.  If blocking here is a problem the STUN requests/responses
+	 * for the externip may need to be done differently. */
+	gtalk_update_externip();
+	if (!ast_strlen_zero(externip)) {
+		ast_copy_string(ours2->username, user, sizeof(ours2->username));
+		ast_copy_string(ours2->password, pass, sizeof(ours2->password));
+		ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
+		ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
+		ours2->port = ntohs(sin.sin_port);
+		ours2->preference = 0.9;
+		ours2->protocol = AJI_PROTOCOL_UDP;
+		ours2->type = AJI_CONNECT_STUN;
+		ours2->generation = 0;
+		ours1->next = ours2;
+		ours2 = NULL;
+	}
+	ours1 = NULL;
+
+	for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
+		snprintf(port, sizeof(port), "%d", tmp->port);
+		snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
+		iks_insert_attrib(iq, "from", to);
+		iks_insert_attrib(iq, "to", from);
+		iks_insert_attrib(iq, "type", "set");
+		iks_insert_attrib(iq, "id", c->mid);
+		ast_aji_increment_mid(c->mid);
+		iks_insert_attrib(gtalk, "type", "candidates");
+		iks_insert_attrib(gtalk, "id", sid);
+		/* put the initiator attribute to lower case if we receive the call
+		 * otherwise GoogleTalk won't establish the session */
+		if (!p->initiator) {
+			char cur;
+			char *t = lowerfrom = ast_strdupa(from);
+			while (((cur = *t) != '/') && (*t++ = tolower(cur)));
+		}
+		iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
+		iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
+		iks_insert_attrib(candidate, "name", tmp->name);
+		iks_insert_attrib(candidate, "address", tmp->ip);
+		iks_insert_attrib(candidate, "port", port);
+		iks_insert_attrib(candidate, "username", tmp->username);
+		iks_insert_attrib(candidate, "password", tmp->password);
+		iks_insert_attrib(candidate, "preference", preference);
+		if (tmp->protocol == AJI_PROTOCOL_UDP)
+			iks_insert_attrib(candidate, "protocol", "udp");
+		if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
+			iks_insert_attrib(candidate, "protocol", "ssltcp");
+		if (tmp->type == AJI_CONNECT_STUN)
+			iks_insert_attrib(candidate, "type", "stun");
+		if (tmp->type == AJI_CONNECT_LOCAL)
+			iks_insert_attrib(candidate, "type", "local");
+		if (tmp->type == AJI_CONNECT_RELAY)
+			iks_insert_attrib(candidate, "type", "relay");
+		iks_insert_attrib(candidate, "network", "0");
+		iks_insert_attrib(candidate, "generation", "0");
+		ast_aji_send(c, iq);
+	}
+	p->laststun = 0;
+
+safeout:
+	if (ours1)
+		ast_free(ours1);
+	if (ours2)
+		ast_free(ours2);
+	iks_delete(iq);
+	iks_delete(gtalk);
+	iks_delete(candidate);
+	iks_delete(transport);
+
+	return 1;
+}
+
+static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
+{
+	struct gtalk_pvt *tmp = NULL;
+	struct aji_resource *resources = NULL;
+	struct aji_buddy *buddy = NULL;
+	char idroster[200] = "";
+	char *data, *exten = NULL;
+	struct ast_sockaddr bindaddr_tmp;
+
+	ast_debug(1, "The client is %s for alloc\n", client->name);
+	if (!sid && !strchr(them, '/')) {	/* I started call! */
+		if (!strcasecmp(client->name, "guest")) {
+			buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
+			if (buddy) {
+				resources = buddy->resources;
+			}
+		} else if (client->buddy) {
+			resources = client->buddy->resources;
+		}
+
+		while (resources) {
+			if (resources->cap->jingle) {
+				break;
+			}
+			resources = resources->next;
+		}
+		if (resources) {
+			snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
+		} else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
+			snprintf(idroster, sizeof(idroster), "%s", them);
+		} else {
+			ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
+			if (buddy) {
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			}
+			return NULL;
+		}
+		if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+		}
+	}
+	if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+		return NULL;
+	}
+	tmp->cap = ast_format_cap_alloc_nolock();
+	tmp->jointcap = ast_format_cap_alloc_nolock();
+	tmp->peercap = ast_format_cap_alloc_nolock();
+	if (!tmp->jointcap || !tmp->peercap || !tmp->cap) {
+		tmp->cap = ast_format_cap_destroy(tmp->cap);
+		tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
+		tmp->peercap = ast_format_cap_destroy(tmp->peercap);
+		ast_free(tmp);
+		return NULL;
+	}
+
+	memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
+
+	if (sid) {
+		ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
+		ast_copy_string(tmp->them, them, sizeof(tmp->them));
+		ast_copy_string(tmp->us, us, sizeof(tmp->us));
+	} else {
+		snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
+		ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
+		ast_copy_string(tmp->us, us, sizeof(tmp->us));
+		tmp->initiator = 1;
+	}
+	/* clear codecs */
+	bindaddr.sin_family = AF_INET;
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
+	  ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
+	  ast_free(tmp);
+	  return NULL;
+	}
+	ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
+	ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
+	ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
+	ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
+	ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
+
+	/* add user configured codec capabilites */
+	if (!(ast_format_cap_is_empty(client->cap))) {
+		ast_format_cap_copy(tmp->cap, client->cap);
+	} else if (!(ast_format_cap_is_empty(global_capability))) {
+		ast_format_cap_copy(tmp->cap, global_capability);
+	}
+
+	tmp->parent = client;
+	if (!tmp->rtp) {
+		ast_log(LOG_WARNING, "Out of RTP sessions?\n");
+		ast_free(tmp);
+		return NULL;
+	}
+
+	/* Set CALLERID(name) to the full JID of the remote peer */
+	ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
+
+	if(strchr(tmp->us, '/')) {
+		data = ast_strdupa(tmp->us);
+		exten = strsep(&data, "/");
+	} else {
+		exten = tmp->us;
+	}
+	ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
+	ast_mutex_init(&tmp->lock);
+	ast_mutex_lock(&gtalklock);
+	tmp->next = client->p;
+	client->p = tmp;
+	ast_mutex_unlock(&gtalklock);
+	return tmp;
+}
+
+/*! \brief Start new gtalk channel */
+static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
+{
+	struct ast_channel *tmp;
+	const char *n2;
+	struct ast_format_cap *what; /* used as SHALLOW COPY DO NOT DESTROY */
+	struct ast_format tmpfmt;
+
+	if (title)
+		n2 = title;
+	else
+		n2 = i->us;
+	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid,
+		client->accountcode, i->exten, client->context, client->amaflags,
+		"Gtalk/%s-%04lx", n2, (long unsigned)(ast_random() & 0xffff));
+	if (!tmp) {
+		ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
+		return NULL;
+	}
+	ast_channel_tech_set(tmp, &gtalk_tech);
+
+	/* Select our native format based on codec preference until we receive
+	   something from another device to the contrary. */
+	if (!(ast_format_cap_is_empty(i->jointcap))) {
+		what = i->jointcap;
+	} else if (i->cap) {
+		what = i->cap;
+	} else {
+		what = global_capability;
+	}
+
+	/* Set Frame packetization */
+	if (i->rtp) {
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
+	}
+
+	ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
+	ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
+
+	ast_format_cap_iter_start(i->jointcap);
+	while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
+		if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
+			ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
+		}
+	}
+	ast_format_cap_iter_end(i->jointcap);
+
+	if (i->rtp) {
+		ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
+		ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
+	}
+	if (i->vrtp) {
+		ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
+		ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
+	}
+	if (state == AST_STATE_RING)
+		ast_channel_rings_set(tmp, 1);
+	ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
+
+	ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+	ast_channel_tech_pvt_set(tmp, i);
+
+	ast_channel_callgroup_set(tmp, client->callgroup);
+	ast_channel_pickupgroup_set(tmp, client->pickupgroup);
+	ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
+	ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
+	if (!ast_strlen_zero(client->accountcode))
+		ast_channel_accountcode_set(tmp, client->accountcode);
+	if (client->amaflags)
+		ast_channel_amaflags_set(tmp, client->amaflags);
+	if (!ast_strlen_zero(client->language))
+		ast_channel_language_set(tmp, client->language);
+	if (!ast_strlen_zero(client->musicclass))
+		ast_channel_musicclass_set(tmp, client->musicclass);
+	if (!ast_strlen_zero(client->parkinglot))
+		ast_channel_parkinglot_set(tmp, client->parkinglot);
+	i->owner = tmp;
+	ast_module_ref(ast_module_info->self);
+	ast_channel_context_set(tmp, client->context);
+	ast_channel_exten_set(tmp, i->exten);
+
+	if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
+		ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
+	}
+	ast_channel_priority_set(tmp, 1);
+	if (i->rtp)
+		ast_jb_configure(tmp, &global_jbconf);
+	if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
+		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+		ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
+		ast_hangup(tmp);
+		tmp = NULL;
+	} else {
+		manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+			"Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
+			i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
+	}
+	return tmp;
+}
+
+static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
+{
+	iks *request, *session = NULL;
+	int res = -1;
+	char *lowerthem = NULL;
+
+	request = iks_new("iq");
+	if (request) {
+		iks_insert_attrib(request, "type", "set");
+		iks_insert_attrib(request, "from", p->us);
+		iks_insert_attrib(request, "to", p->them);
+		iks_insert_attrib(request, "id", client->connection->mid);
+		ast_aji_increment_mid(client->connection->mid);
+		session = iks_new("session");
+		if (session) {
+			iks_insert_attrib(session, "type", action);
+			iks_insert_attrib(session, "id", p->sid);
+			/* put the initiator attribute to lower case if we receive the call
+			 * otherwise GoogleTalk won't establish the session */
+			if (!p->initiator) {
+			        char c;
+				char *t = lowerthem = ast_strdupa(p->them);
+				while (((c = *t) != '/') && (*t++ = tolower(c)));
+			}
+			iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
+			iks_insert_attrib(session, "xmlns", GOOGLE_NS);
+			iks_insert_node(request, session);
+			ast_aji_send(client->connection, request);
+			res = 0;
+		}
+	}
+
+	iks_delete(session);
+	iks_delete(request);
+
+	return res;
+}
+
+static void gtalk_free_candidates(struct gtalk_candidate *candidate)
+{
+	struct gtalk_candidate *last;
+	while (candidate) {
+		last = candidate;
+		candidate = candidate->next;
+		ast_free(last);
+	}
+}
+
+static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
+{
+	struct gtalk_pvt *cur, *prev = NULL;
+	cur = client->p;
+	while (cur) {
+		if (cur == p) {
+			if (prev)
+				prev->next = p->next;
+			else
+				client->p = p->next;
+			break;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+	if (p->ringrule)
+		iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
+	if (p->owner)
+		ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
+	if (p->rtp)
+		ast_rtp_instance_destroy(p->rtp);
+	if (p->vrtp)
+		ast_rtp_instance_destroy(p->vrtp);
+	gtalk_free_candidates(p->theircandidates);
+	p->cap = ast_format_cap_destroy(p->cap);
+	p->jointcap = ast_format_cap_destroy(p->jointcap);
+	p->peercap = ast_format_cap_destroy(p->peercap);
+	ast_free(p);
+}
+
+
+static int gtalk_newcall(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *p, *tmp = client->p;
+	struct ast_channel *chan;
+	int res;
+	iks *codec;
+	char *from = NULL;
+	char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
+	int peernoncodeccapability;
+	char *sid;
+
+	/* Make sure our new call doesn't exist yet */
+	from = iks_find_attrib(pak->x,"to");
+	if (!from) {
+		from = client->connection->jid->full;
+	}
+
+	while (tmp) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
+			(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
+			ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
+			gtalk_response(client, from, pak, "out-of-order", NULL);
+			return -1;
+		}
+		tmp = tmp->next;
+	}
+
+	if (!strcasecmp(client->name, "guest")){
+		/* the guest account is not tied to any configured XMPP client,
+		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
+		client->connection = ast_aji_get_client(from);
+		if (!client->connection) {
+			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
+			return -1;
+		}
+	}
+
+	if (!(sid = iks_find_attrib(pak->query, "id"))) {
+		ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
+		return -1;
+	}
+
+	p = gtalk_alloc(client, from, pak->from->full, sid);
+	if (!p) {
+		ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
+		return -1;
+	}
+
+	chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
+	if (!chan) {
+		gtalk_free_pvt(client, p);
+		return -1;
+	}
+
+	ast_mutex_lock(&p->lock);
+	ast_copy_string(p->them, pak->from->full, sizeof(p->them));
+	ast_copy_string(p->sid, sid, sizeof(p->sid));
+
+	/* codec points to the first <payload-type/> tag */
+	codec = iks_first_tag(iks_first_tag(pak->query));
+
+	while (codec) {
+		char *codec_id = iks_find_attrib(codec, "id");
+		char *codec_name = iks_find_attrib(codec, "name");
+		if (!codec_id || !codec_name) {
+			codec = iks_next_tag(codec);
+			continue;
+		}
+		if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
+			ast_rtp_codecs_payloads_set_m_type(
+				ast_rtp_instance_get_codecs(p->vrtp),
+				p->vrtp,
+				atoi(codec_id));
+			ast_rtp_codecs_payloads_set_rtpmap_type(
+				ast_rtp_instance_get_codecs(p->vrtp),
+				p->vrtp,
+				atoi(codec_id),
+				"video",
+				codec_name,
+				0);
+		} else {
+			ast_rtp_codecs_payloads_set_m_type(
+				ast_rtp_instance_get_codecs(p->rtp),
+				p->rtp,
+				atoi(codec_id));
+			ast_rtp_codecs_payloads_set_rtpmap_type(
+				ast_rtp_instance_get_codecs(p->rtp),
+				p->rtp,
+				atoi(codec_id),
+				"audio",
+				codec_name,
+				0);
+		}
+		codec = iks_next_tag(codec);
+	}
+
+	/* Now gather all of the codecs that we are asked for */
+	ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), p->peercap, &peernoncodeccapability);
+	ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap);
+	ast_mutex_unlock(&p->lock);
+
+	ast_setstate(chan, AST_STATE_RING);
+	if (ast_format_cap_is_empty(p->jointcap)) {
+		ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap),
+			ast_getformatname_multiple(s2, BUFSIZ, p->peercap),
+			ast_getformatname_multiple(s3, BUFSIZ, p->jointcap));
+		/* close session if capabilities don't match */
+		gtalk_action(client, p, "reject");
+		p->alreadygone = 1;
+		gtalk_hangup(chan);
+		ast_channel_release(chan);
+		return -1;
+	}
+
+	res = ast_pbx_start(chan);
+
+	switch (res) {
+	case AST_PBX_FAILED:
+		ast_log(LOG_WARNING, "Failed to start PBX :(\n");
+		gtalk_response(client, from, pak, "service-unavailable", NULL);
+		break;
+	case AST_PBX_CALL_LIMIT:
+		ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
+		gtalk_response(client, from, pak, "service-unavailable", NULL);
+		break;
+	case AST_PBX_SUCCESS:
+		gtalk_response(client, from, pak, NULL, NULL);
+		gtalk_create_candidates(client, p, p->sid, p->them, p->us);
+		/* nothing to do */
+		break;
+	}
+
+	return 1;
+}
+
+static int gtalk_update_externip(void)
+{
+	int sock;
+	char *newaddr;
+	struct sockaddr_in answer = { 0, };
+	struct sockaddr_in *dst;
+	struct ast_sockaddr tmp_dst;
+
+	if (!stunaddr.sin_addr.s_addr) {
+		return -1;
+	}
+	dst = &stunaddr;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
+		return -1;
+	}
+
+	ast_sockaddr_from_sin(&tmp_dst, dst);
+	if (ast_connect(sock, &tmp_dst) != 0) {
+		ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
+		close(sock);
+		return -1;
+	}
+
+	if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
+		close(sock);
+		return -1;
+	}
+
+	newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
+	memcpy(externip, newaddr, sizeof(externip));
+
+	close(sock);
+	return 0;
+
+}
+
+static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
+{
+	struct gtalk_candidate *tmp;
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct sockaddr_in sin = { 0, };
+	struct sockaddr_in aux = { 0, };
+	struct ast_sockaddr sin_tmp;
+	struct ast_sockaddr aux_tmp;
+
+	if (time(NULL) == p->laststun)
+		return 0;
+
+	tmp = p->theircandidates;
+	p->laststun = time(NULL);
+	while (tmp) {
+		char username[256];
+
+		/* Find the IP address of the host */
+		if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
+			ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
+			tmp = tmp->next;
+			continue;
+		}
+		sin.sin_family = AF_INET;
+		memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+		sin.sin_port = htons(tmp->port);
+		snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
+
+		/* Find out the result of the STUN */
+		ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
+		ast_sockaddr_to_sin(&aux_tmp, &aux);
+
+		/* If the STUN result is different from the IP of the hostname,
+		 * lock on the stun IP of the hostname advertised by the
+		 * remote client */
+		if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
+			ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
+		} else {
+			ast_sockaddr_from_sin(&sin_tmp, &sin);
+			ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
+		}
+		if (aux.sin_addr.s_addr) {
+			ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
+			ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
+		}
+
+		tmp = tmp->next;
+	}
+	return 1;
+}
+
+static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
+{
+	struct gtalk_pvt *p = NULL, *tmp = NULL;
+	struct aji_client *c = client->connection;
+	struct gtalk_candidate *newcandidate = NULL;
+	iks *traversenodes = NULL, *receipt = NULL;
+	char *from;
+
+	from = iks_find_attrib(pak->x,"to");
+	if (!from) {
+		from = c->jid->full;
+	}
+
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
+			(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
+			p = tmp;
+			break;
+		}
+	}
+
+	if (!p) {
+		return -1;
+	}
+	traversenodes = pak->query;
+	while(traversenodes) {
+		if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
+			traversenodes = iks_first_tag(traversenodes);
+			continue;
+		}
+		if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
+			traversenodes = iks_child(traversenodes);
+			continue;
+		}
+		if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
+			newcandidate = ast_calloc(1, sizeof(*newcandidate));
+			if (!newcandidate)
+				return 0;
+			ast_copy_string(newcandidate->name,
+				S_OR(iks_find_attrib(traversenodes, "name"), ""),
+				sizeof(newcandidate->name));
+			ast_copy_string(newcandidate->ip,
+				S_OR(iks_find_attrib(traversenodes, "address"), ""),
+				sizeof(newcandidate->ip));
+			newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
+			ast_copy_string(newcandidate->username,
+				S_OR(iks_find_attrib(traversenodes, "username"), ""),
+				sizeof(newcandidate->username));
+			ast_copy_string(newcandidate->password,
+				S_OR(iks_find_attrib(traversenodes, "password"), ""),
+				sizeof(newcandidate->password));
+			newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
+			if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
+				newcandidate->protocol = AJI_PROTOCOL_UDP;
+			if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
+				newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
+
+			if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
+				newcandidate->type = AJI_CONNECT_STUN;
+			if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
+				newcandidate->type = AJI_CONNECT_LOCAL;
+			if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
+				newcandidate->type = AJI_CONNECT_RELAY;
+			ast_copy_string(newcandidate->network,
+				S_OR(iks_find_attrib(traversenodes, "network"), ""),
+				sizeof(newcandidate->network));
+			newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
+			newcandidate->next = NULL;
+
+			newcandidate->next = p->theircandidates;
+			p->theircandidates = newcandidate;
+			p->laststun = 0;
+			gtalk_update_stun(p->parent, p);
+			newcandidate = NULL;
+		}
+		traversenodes = iks_next_tag(traversenodes);
+	}
+
+	receipt = iks_new("iq");
+	iks_insert_attrib(receipt, "type", "result");
+	iks_insert_attrib(receipt, "from", from);
+	iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
+	iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
+	ast_aji_send(c, receipt);
+
+	iks_delete(receipt);
+
+	return 1;
+}
+
+static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
+{
+	struct ast_frame *f;
+
+	if (!p->rtp) {
+		return &ast_null_frame;
+	}
+	f = ast_rtp_instance_read(p->rtp, 0);
+	gtalk_update_stun(p->parent, p);
+	if (p->owner) {
+		/* We already hold the channel lock */
+		if (f->frametype == AST_FRAME_VOICE) {
+			if (!ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) {
+				ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+				ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
+				ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
+				ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
+				ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
+			}
+			/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
+				f = ast_dsp_process(p->owner, p->vad, f);
+				if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
+					ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
+	        } */
+		}
+	}
+	return f;
+}
+
+static struct ast_frame *gtalk_read(struct ast_channel *ast)
+{
+	struct ast_frame *fr;
+	struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
+
+	ast_mutex_lock(&p->lock);
+	fr = gtalk_rtp_read(ast, p);
+	ast_mutex_unlock(&p->lock);
+	return fr;
+}
+
+/*! \brief Send frame to media channel (rtp) */
+static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
+	int res = 0;
+	char buf[256];
+
+	switch (frame->frametype) {
+	case AST_FRAME_VOICE:
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+			ast_log(LOG_WARNING,
+					"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
+					ast_getformatname(&frame->subclass.format),
+					ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+					ast_getformatname(ast_channel_readformat(ast)),
+					ast_getformatname(ast_channel_writeformat(ast)));
+			return 0;
+		}
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			if (p->rtp) {
+				res = ast_rtp_instance_write(p->rtp, frame);
+			}
+			ast_mutex_unlock(&p->lock);
+		}
+		break;
+	case AST_FRAME_VIDEO:
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			if (p->vrtp) {
+				res = ast_rtp_instance_write(p->vrtp, frame);
+			}
+			ast_mutex_unlock(&p->lock);
+		}
+		break;
+	case AST_FRAME_IMAGE:
+		return 0;
+		break;
+	default:
+		ast_log(LOG_WARNING, "Can't send %u type frames with Gtalk write\n",
+				frame->frametype);
+		return 0;
+	}
+
+	return res;
+}
+
+static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(newchan);
+	ast_mutex_lock(&p->lock);
+
+	if ((p->owner != oldchan)) {
+		ast_mutex_unlock(&p->lock);
+		return -1;
+	}
+	if (p->owner == oldchan)
+		p->owner = newchan;
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+	int res = 0;
+
+	switch (condition) {
+	case AST_CONTROL_HOLD:
+		ast_moh_start(ast, data, NULL);
+		break;
+	case AST_CONTROL_UNHOLD:
+		ast_moh_stop(ast);
+		break;
+	default:
+		ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
+		/* fallthrough */
+	case AST_CONTROL_PVT_CAUSE_CODE:
+		res = -1;
+	}
+
+	return res;
+}
+
+static int gtalk_sendtext(struct ast_channel *chan, const char *text)
+{
+	int res = 0;
+	struct aji_client *client = NULL;
+	struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
+
+	if (!p->parent) {
+		ast_log(LOG_ERROR, "Parent channel not found\n");
+		return -1;
+	}
+	if (!p->parent->connection) {
+		ast_log(LOG_ERROR, "XMPP client not found\n");
+		return -1;
+	}
+	client = p->parent->connection;
+	res = ast_aji_send_chat(client, p->them, text);
+	return res;
+}
+
+static int gtalk_digit_begin(struct ast_channel *chan, char digit)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
+	int res = 0;
+
+	ast_mutex_lock(&p->lock);
+	if (p->rtp) {
+		ast_rtp_instance_dtmf_begin(p->rtp, digit);
+	} else {
+		res = -1;
+	}
+	ast_mutex_unlock(&p->lock);
+
+	return res;
+}
+
+static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
+	int res = 0;
+
+	ast_mutex_lock(&p->lock);
+	if (p->rtp) {
+		ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
+	} else {
+		res = -1;
+	}
+	ast_mutex_unlock(&p->lock);
+
+	return res;
+}
+
+/* This function is of not in use at the moment, but I am choosing to leave this
+ * within the code base as a reference to how DTMF is possible through
+ * jingle signaling.  However, google currently does DTMF through the RTP. */
+#if 0
+static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct gtalk_pvt *p = ast->tech_pvt;
+	struct gtalk *client = p->parent;
+	iks *iq, *gtalk, *dtmf;
+	char buffer[2] = {digit, '\0'};
+	char *lowerthem = NULL;
+	iq = iks_new("iq");
+	gtalk = iks_new("gtalk");
+	dtmf = iks_new("dtmf");
+	if(!iq || !gtalk || !dtmf) {
+		iks_delete(iq);
+		iks_delete(gtalk);
+		iks_delete(dtmf);
+		ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
+		return -1;
+	}
+
+	iks_insert_attrib(iq, "type", "set");
+	iks_insert_attrib(iq, "to", p->them);
+	iks_insert_attrib(iq, "from", p->us);
+	iks_insert_attrib(iq, "id", client->connection->mid);
+	ast_aji_increment_mid(client->connection->mid);
+	iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
+	iks_insert_attrib(gtalk, "action", "session-info");
+	// put the initiator attribute to lower case if we receive the call
+	// otherwise GoogleTalk won't establish the session
+	if (!p->initiator) {
+	        char c;
+	        char *t = lowerthem = ast_strdupa(p->them);
+	        while (((c = *t) != '/') && (*t++ = tolower(c)));
+	}
+	iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
+	iks_insert_attrib(gtalk, "sid", p->sid);
+	iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
+	iks_insert_attrib(dtmf, "code", buffer);
+	iks_insert_node(iq, gtalk);
+	iks_insert_node(gtalk, dtmf);
+
+	ast_mutex_lock(&p->lock);
+	if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
+		iks_insert_attrib(dtmf, "action", "button-down");
+	} else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
+		iks_insert_attrib(dtmf, "action", "button-up");
+	}
+	ast_aji_send(client->connection, iq);
+
+	iks_delete(iq);
+	iks_delete(gtalk);
+	iks_delete(dtmf);
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+#endif
+
+static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
+{
+	ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
+
+	return -1;
+}
+
+/*!\brief Initiate new call, part of PBX interface
+ * dest is the dial string */
+static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
+
+	if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
+		ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
+		return -1;
+	}
+
+	ast_setstate(ast, AST_STATE_RING);
+	if (!p->ringrule) {
+		ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
+		p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
+							IKS_RULE_ID, p->ring, IKS_RULE_DONE);
+	} else {
+		ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
+	}
+
+	gtalk_invite(p, p->them, p->us, p->sid, 1);
+
+	return 0;
+}
+
+/*! \brief Hangup a call through the gtalk proxy channel */
+static int gtalk_hangup(struct ast_channel *ast)
+{
+	struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
+	struct gtalk *client;
+
+	ast_mutex_lock(&p->lock);
+	client = p->parent;
+	p->owner = NULL;
+	ast_channel_tech_pvt_set(ast, NULL);
+	if (!p->alreadygone) {
+		gtalk_action(client, p, "terminate");
+	}
+	ast_mutex_unlock(&p->lock);
+
+	gtalk_free_pvt(client, p);
+	ast_module_unref(ast_module_info->self);
+
+	return 0;
+}
+
+/*!\brief Part of PBX interface */
+static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct gtalk_pvt *p = NULL;
+	struct gtalk *client = NULL;
+	char *sender = NULL, *to = NULL, *s = NULL;
+	struct ast_channel *chan = NULL;
+
+	if (data) {
+		s = ast_strdupa(data);
+		sender = strsep(&s, "/");
+		if (sender && (sender[0] != '\0')) {
+			to = strsep(&s, "/");
+		}
+		if (!to) {
+			ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", data);
+			return NULL;
+		}
+		if (!to) {
+			ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
+			return NULL;
+		}
+	}
+
+	client = find_gtalk(to, sender);
+	if (!client) {
+		ast_log(LOG_WARNING, "Could not find recipient.\n");
+		return NULL;
+	}
+	if (!strcasecmp(client->name, "guest")){
+		/* the guest account is not tied to any configured XMPP client,
+		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
+		client->connection = ast_aji_get_client(sender);
+		if (!client->connection) {
+			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
+			ASTOBJ_UNREF(client, gtalk_member_destroy);
+			return NULL;
+		}
+	}
+
+	ASTOBJ_WRLOCK(client);
+	p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
+	if (p) {
+		chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
+	}
+	ASTOBJ_UNLOCK(client);
+	return chan;
+}
+
+/*! \brief CLI command "gtalk show channels" */
+static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
+	struct gtalk_pvt *p;
+	struct ast_channel *chan;
+	int numchans = 0;
+	char them[AJI_MAX_JIDLEN];
+	char *jid = NULL;
+	char *resource = NULL;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "gtalk show channels";
+		e->usage =
+			"Usage: gtalk show channels\n"
+			"       Shows current state of the Gtalk channels.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	ast_mutex_lock(&gtalklock);
+	ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
+	ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
+		ASTOBJ_WRLOCK(iterator);
+		p = iterator->p;
+		while(p) {
+			chan = p->owner;
+			ast_copy_string(them, p->them, sizeof(them));
+			jid = them;
+			resource = strchr(them, '/');
+			if (!resource)
+				resource = "None";
+			else {
+				*resource = '\0';
+				resource ++;
+			}
+			if (chan)
+				ast_cli(a->fd, FORMAT,
+					ast_channel_name(chan),
+					jid,
+					resource,
+					ast_getformatname(ast_channel_readformat(chan)),
+					ast_getformatname(ast_channel_writeformat(chan))
+					);
+			else
+				ast_log(LOG_WARNING, "No available channel\n");
+			numchans ++;
+			p = p->next;
+		}
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+	ast_mutex_unlock(&gtalklock);
+
+	ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
+	return CLI_SUCCESS;
+#undef FORMAT
+}
+
+/*! \brief List global settings for the GoogleTalk channel */
+static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	char codec_buf[BUFSIZ];
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "gtalk show settings";
+		e->usage =
+			"Usage: gtalk show settings\n"
+			"       Provides detailed list of the configuration on the GoogleTalk channel.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+#define FORMAT "  %-25.20s  %-15.30s\n"
+
+	ast_cli(a->fd, "\nGlobal Settings:\n");
+	ast_cli(a->fd, "----------------\n");
+	ast_cli(a->fd, FORMAT, "UDP Bindaddress:", ast_inet_ntoa(bindaddr.sin_addr));
+	ast_cli(a->fd, FORMAT, "Stun Address:", global_stunaddr != 0 ? ast_inet_ntoa(stunaddr.sin_addr) : "Disabled");
+	ast_cli(a->fd, FORMAT, "External IP:", S_OR(externip, "Disabled"));
+	ast_cli(a->fd, FORMAT, "Context:", global_context);
+	ast_cli(a->fd, FORMAT, "Codecs:", ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, global_capability));
+	ast_cli(a->fd, FORMAT, "Parking Lot:", global_parkinglot);
+	ast_cli(a->fd, FORMAT, "Allow Guest:", AST_CLI_YESNO(global_allowguest));
+	ast_cli(a->fd, "\n----\n");
+
+	return CLI_SUCCESS;
+#undef FORMAT
+}
+
+/*! \brief CLI command "gtalk reload"
+ *  \todo XXX TODO make this work. */
+#if 0
+static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "gtalk reload";
+		e->usage =
+			"Usage: gtalk reload\n"
+			"       Reload gtalk channel driver.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_verbose("IT DOES WORK!\n");
+	return CLI_SUCCESS;
+}
+#endif
+
+static int gtalk_parser(void *data, ikspak *pak)
+{
+	struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
+	int res;
+	iks *tmp;
+
+	if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
+		ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
+		pak->query = tmp;
+	}
+
+	if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
+		ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
+	}
+
+	if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
+		ast_log(LOG_NOTICE, "No attribute \"type\" found.  Ignoring message.\n");
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
+		/* New call */
+		gtalk_newcall(client, pak);
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
+		ast_debug(3, "About to add candidate!\n");
+		res = gtalk_add_candidate(client, pak);
+		if (!res) {
+			ast_log(LOG_WARNING, "Could not add any candidate\n");
+		} else {
+			ast_debug(3, "Candidate Added!\n");
+		}
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
+		gtalk_is_answered(client, pak);
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
+		gtalk_is_accepted(client, pak);
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
+		gtalk_handle_dtmf(client, pak);
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
+		gtalk_hangup_farend(client, pak);
+	} else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
+		gtalk_hangup_farend(client, pak);
+	}
+	ASTOBJ_UNREF(client, gtalk_member_destroy);
+	return IKS_FILTER_EAT;
+}
+
+static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
+								struct ast_codec_pref prefs, char *context,
+								struct gtalk *member)
+{
+	struct aji_client *client;
+
+	if (!member)
+		ast_log(LOG_WARNING, "Out of memory.\n");
+
+	ast_copy_string(member->name, label, sizeof(member->name));
+	ast_copy_string(member->user, label, sizeof(member->user));
+	ast_copy_string(member->context, context, sizeof(member->context));
+	member->allowguest = allowguest;
+	member->prefs = prefs;
+	while (var) {
+		if (!strcasecmp(var->name, "username"))
+			ast_copy_string(member->user, var->value, sizeof(member->user));
+		else if (!strcasecmp(var->name, "disallow"))
+			ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
+		else if (!strcasecmp(var->name, "allow"))
+			ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
+		else if (!strcasecmp(var->name, "context"))
+			ast_copy_string(member->context, var->value, sizeof(member->context));
+		else if (!strcasecmp(var->name, "parkinglot"))
+			ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
+		else if (!strcasecmp(var->name, "connection")) {
+			if ((client = ast_aji_get_client(var->value))) {
+				member->connection = client;
+				iks_filter_add_rule(client->f, gtalk_parser, member,
+						    IKS_RULE_TYPE, IKS_PAK_IQ,
+						    IKS_RULE_FROM_PARTIAL, member->user,
+						    IKS_RULE_NS, GOOGLE_NS,
+						    IKS_RULE_DONE);
+			} else {
+				ast_log(LOG_ERROR, "connection referenced not found!\n");
+				return 0;
+			}
+		}
+		var = var->next;
+	}
+	if (member->connection && member->user)
+		member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
+	else {
+		ast_log(LOG_ERROR, "No Connection or Username!\n");
+	}
+	return 1;
+}
+
+static int gtalk_load_config(void)
+{
+	char *cat = NULL;
+	struct ast_config *cfg = NULL;
+	struct ast_variable *var;
+	struct gtalk *member;
+	struct ast_codec_pref prefs;
+	struct aji_client_container *clients;
+	struct gtalk_candidate *global_candidates = NULL;
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct ast_flags config_flags = { 0 };
+
+	cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
+	if (!cfg) {
+		return 0;
+	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", GOOGLE_CONFIG);
+		return 0;
+	}
+
+	/* Copy the default jb config over global_jbconf */
+	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+
+	/* set defaults */
+	memset(&prefs, 0, sizeof(prefs));
+	memset(&stunaddr, 0, sizeof(stunaddr));
+	global_stunaddr = 0;
+	global_allowguest = DEFAULT_ALLOWGUEST;
+	ast_copy_string(global_context, DEFAULT_CONTEXT, sizeof(global_context));
+	ast_copy_string(global_parkinglot, DEFAULT_PARKINGLOT, sizeof(global_parkinglot));
+
+	cat = ast_category_browse(cfg, NULL);
+	for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+		/* handle jb conf */
+		if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) {
+			continue;
+		}
+
+		if (!strcasecmp(var->name, "allowguest")) {
+			global_allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
+		} else if (!strcasecmp(var->name, "disallow")) {
+			ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
+		} else if (!strcasecmp(var->name, "allow")) {
+			ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
+		} else if (!strcasecmp(var->name, "context")) {
+			ast_copy_string(global_context, var->value, sizeof(global_context));
+		} else if (!strcasecmp(var->name, "externip")) {
+			ast_copy_string(externip, var->value, sizeof(externip));
+		} else if (!strcasecmp(var->name, "parkinglot")) {
+			ast_copy_string(global_parkinglot, var->value, sizeof(global_parkinglot));
+		} else if (!strcasecmp(var->name, "bindaddr")) {
+			if (!(hp = ast_gethostbyname(var->value, &ahp))) {
+				ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
+			} else {
+				memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
+			}
+		} else if (!strcasecmp(var->name, "stunaddr")) {
+			stunaddr.sin_port = htons(STANDARD_STUN_PORT);
+			global_stunaddr = 1;
+			if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
+				ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
+			}
+		}
+	}
+	while (cat) {
+		if (strcasecmp(cat, "general")) {
+			var = ast_variable_browse(cfg, cat);
+			member = ast_calloc(1, sizeof(*member));
+			ASTOBJ_INIT(member);
+			ASTOBJ_WRLOCK(member);
+			member->cap = ast_format_cap_alloc_nolock();
+			if (!strcasecmp(cat, "guest")) {
+				ast_copy_string(member->name, "guest", sizeof(member->name));
+				ast_copy_string(member->user, "guest", sizeof(member->user));
+				ast_copy_string(member->context, global_context, sizeof(member->context));
+				ast_copy_string(member->parkinglot, global_parkinglot, sizeof(member->parkinglot));
+				member->allowguest = global_allowguest;
+				member->prefs = prefs;
+				while (var) {
+					if (!strcasecmp(var->name, "disallow")) {
+						ast_parse_allow_disallow(&member->prefs, member->cap,
+												 var->value, 0);
+					} else if (!strcasecmp(var->name, "allow")) {
+						ast_parse_allow_disallow(&member->prefs, member->cap,
+												 var->value, 1);
+					} else if (!strcasecmp(var->name, "context")) {
+						ast_copy_string(member->context, var->value,
+										sizeof(member->context));
+					} else if (!strcasecmp(var->name, "parkinglot")) {
+						ast_copy_string(member->parkinglot, var->value,
+										sizeof(member->parkinglot));
+					}
+					var = var->next;
+				}
+				ASTOBJ_UNLOCK(member);
+				clients = ast_aji_get_clients();
+				if (clients) {
+					ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
+						ASTOBJ_WRLOCK(iterator);
+						ASTOBJ_WRLOCK(member);
+						if (member->connection) {
+							ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
+						}
+						member->connection = NULL;
+						iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
+						iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
+						iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
+						ASTOBJ_UNLOCK(member);
+						ASTOBJ_UNLOCK(iterator);
+					});
+					ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
+					ASTOBJ_UNREF(member, gtalk_member_destroy);
+				} else {
+					ASTOBJ_UNLOCK(member);
+					ASTOBJ_UNREF(member, gtalk_member_destroy);
+				}
+			} else {
+				ASTOBJ_UNLOCK(member);
+				if (gtalk_create_member(cat, var, global_allowguest, prefs, global_context, member)) {
+					ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
+				}
+				ASTOBJ_UNREF(member, gtalk_member_destroy);
+			}
+		}
+		cat = ast_category_browse(cfg, cat);
+	}
+
+	ast_config_destroy(cfg);
+	gtalk_update_externip();
+	gtalk_free_candidates(global_candidates);
+	return 1;
+}
+
+/*! \brief Load module into PBX, register channel */
+static int load_module(void)
+{
+	struct ast_sockaddr bindaddr_tmp;
+	struct ast_sockaddr ourip_tmp;
+	char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
+	struct ast_format tmpfmt;
+
+	if (!(gtalk_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	if (!(global_capability = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	ast_format_cap_add_all_by_type(gtalk_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
+
+	free(jabber_loaded);
+	if (!jabber_loaded) {
+		/* If embedded, check for a different module name */
+		jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
+		free(jabber_loaded);
+		if (!jabber_loaded) {
+			ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
+			return AST_MODULE_LOAD_DECLINE;
+		}
+	}
+
+	ASTOBJ_CONTAINER_INIT(&gtalk_list);
+	if (!gtalk_load_config()) {
+		ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
+		return 0;
+	}
+
+	sched = ast_sched_context_create();
+	if (!sched) {
+		ast_log(LOG_WARNING, "Unable to create schedule context\n");
+	}
+
+	io = io_context_create();
+	if (!io) {
+		ast_log(LOG_WARNING, "Unable to create I/O context\n");
+	}
+
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	if (gtalk_get_local_ip(&ourip_tmp)) {
+		ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
+		return 0;
+	}
+	__ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
+
+	ast_rtp_glue_register(&gtalk_rtp_glue);
+	ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
+
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&gtalk_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
+		return -1;
+	}
+	return 0;
+}
+
+/*! \brief Reload module
+ *  \todo XXX TODO make this work. */
+#if 0
+static int reload(void)
+{
+	return 0;
+}
+#endif
+/*! \brief Unload the gtalk channel from Asterisk */
+static int unload_module(void)
+{
+	struct gtalk_pvt *privates = NULL;
+	ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
+	/* First, take us out of the channel loop */
+	ast_channel_unregister(&gtalk_tech);
+	ast_rtp_glue_unregister(&gtalk_rtp_glue);
+
+	if (!ast_mutex_lock(&gtalklock)) {
+		/* Hangup all interfaces if they have an owner */
+		ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
+			ASTOBJ_WRLOCK(iterator);
+			privates = iterator->p;
+			while(privates) {
+				if (privates->owner)
+					ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
+				privates = privates->next;
+			}
+			iterator->p = NULL;
+			ASTOBJ_UNLOCK(iterator);
+		});
+		ast_mutex_unlock(&gtalklock);
+	} else {
+		ast_log(LOG_WARNING, "Unable to lock the monitor\n");
+		return -1;
+	}
+	ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
+	global_capability = ast_format_cap_destroy(global_capability);
+	gtalk_tech.capabilities = ast_format_cap_destroy(gtalk_tech.capabilities);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver",
+		.load = load_module,
+		.unload = unload_module,
+		/* .reload = reload, */
+		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+		);
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
new file mode 100644
index 0000000..b333f5a
--- /dev/null
+++ b/channels/chan_h323.c
@@ -0,0 +1,3505 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ *			By Jeremy McNamara
+ *                      For The NuFone Network
+ *
+ * chan_h323 has been derived from code created by
+ *               Michael Manousos and Mark Spencer
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief This file is part of the chan_h323 driver for Asterisk
+ *
+ * \author Jeremy McNamara
+ *
+ * \par See also
+ * \arg Config_h323
+ * \extref OpenH323 http://www.voxgratia.org/
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+	<depend>openh323</depend>
+	<defaultenabled>no</defaultenabled>
+	<support_level>deprecated</support_level>
+	<replacement>chan_ooh323</replacement>
+ ***/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/pbx.h"
+#include "asterisk/utils.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/cli.h"
+#include "asterisk/dsp.h"
+#include "asterisk/causes.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/abstract_jb.h"
+#include "asterisk/astobj.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef open
+#undef close
+#include "h323/chan_h323.h"
+
+receive_digit_cb on_receive_digit;
+on_rtp_cb on_external_rtp_create;
+start_rtp_cb on_start_rtp_channel;
+setup_incoming_cb on_incoming_call;
+setup_outbound_cb on_outgoing_call;
+chan_ringing_cb	on_chan_ringing;
+con_established_cb on_connection_established;
+clear_con_cb on_connection_cleared;
+answer_call_cb on_answer_call;
+progress_cb on_progress;
+rfc2833_cb on_set_rfc2833_payload;
+hangup_cb on_hangup;
+setcapabilities_cb on_setcapabilities;
+setpeercapabilities_cb on_setpeercapabilities;
+onhold_cb on_hold;
+
+int h323debug; /*!< global debug flag */
+
+/*! \brief Global jitterbuffer configuration - by default, jb is disabled
+ *  \note Values shown here match the defaults shown in h323.conf.sample */
+static struct ast_jb_conf default_jbconf =
+{
+	.flags = 0,
+	.max_size = 200,
+	.resync_threshold = 1000,
+	.impl = "fixed",
+	.target_extra = 40,
+};
+static struct ast_jb_conf global_jbconf;
+
+/** Variables required by Asterisk */
+static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";
+static const char config[] = "h323.conf";
+static char default_context[AST_MAX_CONTEXT] = "default";
+static struct sockaddr_in bindaddr;
+
+#define GLOBAL_CAPABILITY (ast_format_id_to_old_bitfield(AST_FORMAT_G723_1) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_GSM) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_G729A) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) | \
+	ast_format_id_to_old_bitfield(AST_FORMAT_H261)) \
+
+/** H.323 configuration values */
+static int h323_signalling_port = 1720;
+static char gatekeeper[100];
+static int gatekeeper_disable = 1;
+static int gatekeeper_discover = 0;
+static int gkroute = 0;
+/* Find user by alias (h.323 id) is default, alternative is the incoming call's source IP address*/
+static int userbyalias = 1;
+static int acceptAnonymous = 1;
+static unsigned int tos = 0;
+static unsigned int cos = 0;
+static char secret[50];
+static unsigned int unique = 0;
+
+static call_options_t global_options;
+
+/*! \brief Private structure of a OpenH323 channel */
+static struct oh323_pvt {
+	ast_mutex_t lock;			/*!< Channel private lock */
+	call_options_t options;			/*!<!< Options to be used during call setup */
+	int alreadygone;			/*!< Whether or not we've already been destroyed by our peer */
+	int needdestroy;			/*!< if we need to be destroyed */
+	call_details_t cd;			/*!< Call details */
+	struct ast_channel *owner;		/*!< Who owns us */
+	struct sockaddr_in sa;			/*!< Our peer */
+	struct sockaddr_in redirip;		/*!< Where our RTP should be going if not to us */
+	int nonCodecCapability;			/*!< non-audio capability */
+	int outgoing;				/*!< Outgoing or incoming call? */
+	char exten[AST_MAX_EXTENSION];		/*!< Requested extension */
+	char context[AST_MAX_CONTEXT];		/*!< Context where to start */
+	char accountcode[256];			/*!< Account code */
+	char rdnis[80];				/*!< Referring DNIS, if available */
+	int amaflags;				/*!< AMA Flags */
+	struct ast_rtp_instance *rtp;		/*!< RTP Session */
+	struct ast_dsp *vad;			/*!< Used for in-band DTMF detection */
+	int nativeformats;			/*!< Codec formats supported by a channel */
+	int needhangup;				/*!< Send hangup when Asterisk is ready */
+	int hangupcause;			/*!< Hangup cause from OpenH323 layer */
+	int newstate;				/*!< Pending state change */
+	int newcontrol;				/*!< Pending control to send */
+	int newdigit;				/*!< Pending DTMF digit to send */
+	int newduration;			/*!< Pending DTMF digit duration to send */
+	h323_format pref_codec;				/*!< Preferred codec */
+	h323_format peercapability;			/*!< Capabilities learned from peer */
+	h323_format jointcapability;			/*!< Common capabilities for local and remote side */
+	struct ast_codec_pref peer_prefs;	/*!< Preferenced list of codecs which remote side supports */
+	int dtmf_pt[2];				/*!< Payload code used for RFC2833/CISCO messages */
+	int curDTMF;				/*!< DTMF tone being generated to Asterisk side */
+	int DTMFsched;				/*!< Scheduler descriptor for DTMF */
+	int update_rtp_info;			/*!< Configuration of fd's array is pending */
+	int recvonly;				/*!< Peer isn't wish to receive our voice stream */
+	int txDtmfDigit;			/*!< DTMF digit being to send to H.323 side */
+	int noInbandDtmf;			/*!< Inband DTMF processing by DSP isn't available */
+	int connection_established;		/*!< Call got CONNECT message */
+	int got_progress;			/*!< Call got PROGRESS message, pass inband audio */
+	struct oh323_pvt *next;			/*!< Next channel in list */
+} *iflist = NULL;
+
+/*! \brief H323 User list */
+static struct h323_user_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_user);
+} userl;
+
+/*! \brief H323 peer list */
+static struct h323_peer_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_peer);
+} peerl;
+
+/*! \brief H323 alias list */
+static struct h323_alias_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_alias);
+} aliasl;
+
+/* Asterisk RTP stuff */
+static struct ast_sched_context *sched;
+static struct io_context *io;
+
+AST_MUTEX_DEFINE_STATIC(iflock);	/*!< Protect the interface list (oh323_pvt) */
+
+/*! \brief  Protect the H.323 monitoring thread, so only one process can kill or start it, and not
+   when it's doing something critical. */
+AST_MUTEX_DEFINE_STATIC(monlock);
+
+/*! \brief Protect the H.323 capabilities list, to avoid more than one channel to set the capabilities simultaneaously in the h323 stack. */
+AST_MUTEX_DEFINE_STATIC(caplock);
+
+/*! \brief Protect the reload process */
+AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
+static int h323_reloading = 0;
+
+/*! \brief This is the thread for the monitor which checks for input on the channels
+   which are not currently in use. */
+static pthread_t monitor_thread = AST_PTHREADT_NULL;
+static int restart_monitor(void);
+static int h323_do_reload(void);
+
+static void delete_users(void);
+static void delete_aliases(void);
+static void prune_peers(void);
+
+static struct ast_channel *oh323_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
+static int oh323_digit_begin(struct ast_channel *c, char digit);
+static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration);
+static int oh323_call(struct ast_channel *c, const char *dest, int timeout);
+static int oh323_hangup(struct ast_channel *c);
+static int oh323_answer(struct ast_channel *c);
+static struct ast_frame *oh323_read(struct ast_channel *c);
+static int oh323_write(struct ast_channel *c, struct ast_frame *frame);
+static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
+static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+
+static struct ast_channel_tech oh323_tech = {
+	.type = "H323",
+	.description = tdesc,
+	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
+	.requester = oh323_request,
+	.send_digit_begin = oh323_digit_begin,
+	.send_digit_end = oh323_digit_end,
+	.call = oh323_call,
+	.hangup = oh323_hangup,
+	.answer = oh323_answer,
+	.read = oh323_read,
+	.write = oh323_write,
+	.indicate = oh323_indicate,
+	.fixup = oh323_fixup,
+	.bridge = ast_rtp_instance_bridge,
+};
+
+static const char* redirectingreason2str(int redirectingreason)
+{
+	switch (redirectingreason) {
+	case 0:
+		return "UNKNOWN";
+	case 1:
+		return "BUSY";
+	case 2:
+		return "NO_REPLY";
+	case 0xF:
+		return "UNCONDITIONAL";
+	default:
+		return "NOREDIRECT";
+	}
+}
+
+static void oh323_destroy_alias(struct oh323_alias *alias)
+{
+	if (h323debug)
+		ast_debug(1, "Destroying alias '%s'\n", alias->name);
+	ast_free(alias);
+}
+
+static void oh323_destroy_user(struct oh323_user *user)
+{
+	if (h323debug)
+		ast_debug(1, "Destroying user '%s'\n", user->name);
+	ast_free_ha(user->ha);
+	ast_free(user);
+}
+
+static void oh323_destroy_peer(struct oh323_peer *peer)
+{
+	if (h323debug)
+		ast_debug(1, "Destroying peer '%s'\n", peer->name);
+	ast_free_ha(peer->ha);
+	ast_free(peer);
+}
+
+static int oh323_simulate_dtmf_end(const void *data)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *)data;
+
+	if (pvt) {
+		ast_mutex_lock(&pvt->lock);
+		/* Don't hold pvt lock while trying to lock the channel */
+		while (pvt->owner && ast_channel_trylock(pvt->owner)) {
+			DEADLOCK_AVOIDANCE(&pvt->lock);
+		}
+
+		if (pvt->owner) {
+			struct ast_frame f = {
+				.frametype = AST_FRAME_DTMF_END,
+				.subclass.integer = pvt->curDTMF,
+				.samples = 0,
+				.src = "SIMULATE_DTMF_END",
+			};
+			ast_queue_frame(pvt->owner, &f);
+			ast_channel_unlock(pvt->owner);
+		}
+
+		pvt->DTMFsched = -1;
+		ast_mutex_unlock(&pvt->lock);
+	}
+
+	return 0;
+}
+
+/*! \brief Channel and private structures should be already locked */
+static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
+{
+	h323_format chan_nativeformats_bits = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c));
+	if (chan_nativeformats_bits != pvt->nativeformats) {
+		if (h323debug)
+			ast_debug(1, "Preparing %s for new native format\n", ast_channel_name(c));
+		ast_format_cap_from_old_bitfield(ast_channel_nativeformats(c), pvt->nativeformats);
+		ast_set_read_format(c, ast_channel_readformat(c));
+		ast_set_write_format(c, ast_channel_writeformat(c));
+	}
+	if (pvt->needhangup) {
+		if (h323debug)
+			ast_debug(1, "Process pending hangup for %s\n", ast_channel_name(c));
+		ast_channel_softhangup_internal_flag_add(c, AST_SOFTHANGUP_DEV);
+		ast_channel_hangupcause_set(c, pvt->hangupcause);
+		ast_queue_hangup_with_cause(c, pvt->hangupcause);
+		pvt->needhangup = 0;
+		pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1;
+	}
+	if (pvt->newstate >= 0) {
+		ast_setstate(c, pvt->newstate);
+		pvt->newstate = -1;
+	}
+	if (pvt->newcontrol >= 0) {
+		ast_queue_control(c, pvt->newcontrol);
+		pvt->newcontrol = -1;
+	}
+	if (pvt->newdigit >= 0) {
+		struct ast_frame f = {
+			.frametype = AST_FRAME_DTMF_END,
+			.subclass.integer = pvt->newdigit,
+			.samples = pvt->newduration * 8,
+			.len = pvt->newduration,
+			.src = "UPDATE_INFO",
+		};
+		if (pvt->newdigit == ' ') {		/* signalUpdate message */
+			f.subclass.integer = pvt->curDTMF;
+			if (pvt->DTMFsched >= 0) {
+				AST_SCHED_DEL(sched, pvt->DTMFsched);
+			}
+		} else {						/* Regular input or signal message */
+			if (pvt->newduration) {		/* This is a signal, signalUpdate follows */
+				f.frametype = AST_FRAME_DTMF_BEGIN;
+				AST_SCHED_DEL(sched, pvt->DTMFsched);
+				pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt);
+				if (h323debug)
+					ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched);
+			}
+			pvt->curDTMF = pvt->newdigit;
+		}
+		ast_queue_frame(c, &f);
+		pvt->newdigit = -1;
+	}
+	if (pvt->update_rtp_info > 0) {
+		if (pvt->rtp) {
+			ast_jb_configure(c, &global_jbconf);
+			ast_channel_set_fd(c, 0, ast_rtp_instance_fd(pvt->rtp, 0));
+			ast_channel_set_fd(c, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+			ast_queue_frame(pvt->owner, &ast_null_frame);	/* Tell Asterisk to apply changes */
+		}
+		pvt->update_rtp_info = -1;
+	}
+}
+
+/*! \brief Only channel structure should be locked */
+static void oh323_update_info(struct ast_channel *c)
+{
+	struct oh323_pvt *pvt = ast_channel_tech_pvt(c);
+
+	if (pvt) {
+		ast_mutex_lock(&pvt->lock);
+		__oh323_update_info(c, pvt);
+		ast_mutex_unlock(&pvt->lock);
+	}
+}
+
+static void cleanup_call_details(call_details_t *cd)
+{
+	if (cd->call_token) {
+		ast_free(cd->call_token);
+		cd->call_token = NULL;
+	}
+	if (cd->call_source_aliases) {
+		ast_free(cd->call_source_aliases);
+		cd->call_source_aliases = NULL;
+	}
+	if (cd->call_dest_alias) {
+		ast_free(cd->call_dest_alias);
+		cd->call_dest_alias = NULL;
+	}
+	if (cd->call_source_name) {
+		ast_free(cd->call_source_name);
+		cd->call_source_name = NULL;
+	}
+	if (cd->call_source_e164) {
+		ast_free(cd->call_source_e164);
+		cd->call_source_e164 = NULL;
+	}
+	if (cd->call_dest_e164) {
+		ast_free(cd->call_dest_e164);
+		cd->call_dest_e164 = NULL;
+	}
+	if (cd->sourceIp) {
+		ast_free(cd->sourceIp);
+		cd->sourceIp = NULL;
+	}
+	if (cd->redirect_number) {
+		ast_free(cd->redirect_number);
+		cd->redirect_number = NULL;
+	}
+}
+
+static void __oh323_destroy(struct oh323_pvt *pvt)
+{
+	struct oh323_pvt *cur, *prev = NULL;
+
+	AST_SCHED_DEL(sched, pvt->DTMFsched);
+
+	if (pvt->rtp) {
+		ast_rtp_instance_destroy(pvt->rtp);
+	}
+
+	/* Free dsp used for in-band DTMF detection */
+	if (pvt->vad) {
+		ast_dsp_free(pvt->vad);
+	}
+	cleanup_call_details(&pvt->cd);
+
+	/* Unlink us from the owner if we have one */
+	if (pvt->owner) {
+		ast_channel_lock(pvt->owner);
+		if (h323debug)
+			ast_debug(1, "Detaching from %s\n", ast_channel_name(pvt->owner));
+		ast_channel_tech_pvt_set(pvt->owner, NULL);
+		ast_channel_unlock(pvt->owner);
+	}
+	cur = iflist;
+	while(cur) {
+		if (cur == pvt) {
+			if (prev)
+				prev->next = cur->next;
+			else
+				iflist = cur->next;
+			break;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+	if (!cur) {
+		ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
+	} else {
+		ast_mutex_unlock(&pvt->lock);
+		ast_mutex_destroy(&pvt->lock);
+		ast_free(pvt);
+	}
+}
+
+static void oh323_destroy(struct oh323_pvt *pvt)
+{
+	if (h323debug) {
+		ast_debug(1, "Destroying channel %s\n", (pvt->owner ? ast_channel_name(pvt->owner) : "<unknown>"));
+	}
+	ast_mutex_lock(&iflock);
+	ast_mutex_lock(&pvt->lock);
+	__oh323_destroy(pvt);
+	ast_mutex_unlock(&iflock);
+}
+
+static int oh323_digit_begin(struct ast_channel *c, char digit)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	char *token;
+
+	if (!pvt) {
+		ast_log(LOG_ERROR, "No private structure?! This is bad\n");
+		return -1;
+	}
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->rtp &&
+		(((pvt->options.dtmfmode & H323_DTMF_RFC2833) && pvt->dtmf_pt[0])
+		 /*|| ((pvt->options.dtmfmode & H323_DTMF_CISCO) && pvt->dtmf_pt[1]))*/)) {
+		/* out-of-band DTMF */
+		if (h323debug) {
+			ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, ast_channel_name(c));
+		}
+		ast_rtp_instance_dtmf_begin(pvt->rtp, digit);
+		ast_mutex_unlock(&pvt->lock);
+	} else if (pvt->txDtmfDigit != digit) {
+		/* in-band DTMF */
+		if (h323debug) {
+			ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, ast_channel_name(c));
+		}
+		pvt->txDtmfDigit = digit;
+		token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL;
+		ast_mutex_unlock(&pvt->lock);
+		h323_send_tone(token, digit);
+		if (token) {
+			ast_free(token);
+		}
+	} else
+		ast_mutex_unlock(&pvt->lock);
+	oh323_update_info(c);
+	return 0;
+}
+
+/*! \brief
+ * Send (play) the specified digit to the channel.
+ *
+ */
+static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	char *token;
+
+	if (!pvt) {
+		ast_log(LOG_ERROR, "No private structure?! This is bad\n");
+		return -1;
+	}
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && ((pvt->dtmf_pt[0] > 0) || (pvt->dtmf_pt[0] > 0))) {
+		/* out-of-band DTMF */
+		if (h323debug) {
+			ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, ast_channel_name(c), duration);
+		}
+		ast_rtp_instance_dtmf_end(pvt->rtp, digit);
+		ast_mutex_unlock(&pvt->lock);
+	} else {
+		/* in-band DTMF */
+		if (h323debug) {
+			ast_log(LOG_DTMF, "End sending inband digit %c on %s, duration %d\n", digit, ast_channel_name(c), duration);
+		}
+		pvt->txDtmfDigit = ' ';
+		token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL;
+		ast_mutex_unlock(&pvt->lock);
+		h323_send_tone(token, ' ');
+		if (token) {
+			ast_free(token);
+		}
+	}
+	oh323_update_info(c);
+	return 0;
+}
+
+/*! \brief
+ * Make a call over the specified channel to the specified
+ * destination.
+ * Returns -1 on error, 0 on success.
+ */
+static int oh323_call(struct ast_channel *c, const char *dest, int timeout)
+{
+	int res = 0;
+	struct oh323_pvt *pvt = (struct oh323_pvt *)ast_channel_tech_pvt(c);
+	const char *addr;
+	char called_addr[1024];
+
+	if (h323debug) {
+		ast_debug(1, "Calling to %s on %s\n", dest, ast_channel_name(c));
+	}
+	if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) {
+		ast_log(LOG_WARNING, "Line is already in use (%s)\n", ast_channel_name(c));
+		return -1;
+	}
+	ast_mutex_lock(&pvt->lock);
+	if (!gatekeeper_disable) {
+		if (ast_strlen_zero(pvt->exten)) {
+			ast_copy_string(called_addr, dest, sizeof(called_addr));
+		} else {
+			snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest);
+		}
+	} else {
+		res = htons(pvt->sa.sin_port);
+		addr = ast_inet_ntoa(pvt->sa.sin_addr);
+		if (ast_strlen_zero(pvt->exten)) {
+			snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res);
+		} else {
+			snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, res);
+		}
+	}
+	/* make sure null terminated */
+	called_addr[sizeof(called_addr) - 1] = '\0';
+
+	if (ast_channel_connected(c)->id.number.valid && ast_channel_connected(c)->id.number.str) {
+		ast_copy_string(pvt->options.cid_num, ast_channel_connected(c)->id.number.str, sizeof(pvt->options.cid_num));
+	}
+
+	if (ast_channel_connected(c)->id.name.valid && ast_channel_connected(c)->id.name.str) {
+		ast_copy_string(pvt->options.cid_name, ast_channel_connected(c)->id.name.str, sizeof(pvt->options.cid_name));
+	}
+
+	if (ast_channel_redirecting(c)->from.number.valid && ast_channel_redirecting(c)->from.number.str) {
+		ast_copy_string(pvt->options.cid_rdnis, ast_channel_redirecting(c)->from.number.str, sizeof(pvt->options.cid_rdnis));
+	}
+
+	pvt->options.presentation = ast_party_id_presentation(&ast_channel_connected(c)->id);
+	pvt->options.type_of_number = ast_channel_connected(c)->id.number.plan;
+
+	if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) {
+		if (!strcasecmp(addr, "UNKNOWN"))
+			pvt->options.redirect_reason = 0;
+		else if (!strcasecmp(addr, "BUSY"))
+			pvt->options.redirect_reason = 1;
+		else if (!strcasecmp(addr, "NO_REPLY"))
+			pvt->options.redirect_reason = 2;
+		else if (!strcasecmp(addr, "UNCONDITIONAL"))
+			pvt->options.redirect_reason = 15;
+		else
+			pvt->options.redirect_reason = -1;
+	} else
+		pvt->options.redirect_reason = -1;
+
+	pvt->options.transfer_capability = ast_channel_transfercapability(c);
+
+	/* indicate that this is an outgoing call */
+	pvt->outgoing = 1;
+
+	ast_verb(3, "Requested transfer capability: 0x%02hx - %s\n", ast_channel_transfercapability(c), ast_transfercapability2str(ast_channel_transfercapability(c)));
+	if (h323debug)
+		ast_debug(1, "Placing outgoing call to %s, %d/%d\n", called_addr, pvt->options.dtmfcodec[0], pvt->options.dtmfcodec[1]);
+	ast_mutex_unlock(&pvt->lock);
+	res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
+	if (res) {
+		ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", ast_channel_name(c));
+		return -1;
+	}
+	oh323_update_info(c);
+	return 0;
+}
+
+static int oh323_answer(struct ast_channel *c)
+{
+	int res;
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	char *token;
+
+	if (h323debug)
+		ast_debug(1, "Answering on %s\n", ast_channel_name(c));
+
+	ast_mutex_lock(&pvt->lock);
+	token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL;
+	ast_mutex_unlock(&pvt->lock);
+	res = h323_answering_call(token, 0);
+	if (token)
+		ast_free(token);
+
+	oh323_update_info(c);
+	if (ast_channel_state(c) != AST_STATE_UP) {
+		ast_setstate(c, AST_STATE_UP);
+	}
+	return res;
+}
+
+static int oh323_hangup(struct ast_channel *c)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	int q931cause = AST_CAUSE_NORMAL_CLEARING;
+	char *call_token;
+
+
+	if (h323debug)
+		ast_debug(1, "Hanging up and scheduling destroy of call %s\n", ast_channel_name(c));
+
+	if (!ast_channel_tech_pvt(c)) {
+		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
+		return 0;
+	}
+	ast_mutex_lock(&pvt->lock);
+	/* Determine how to disconnect */
+	if (pvt->owner != c) {
+		ast_log(LOG_WARNING, "Huh?  We aren't the owner?\n");
+		ast_mutex_unlock(&pvt->lock);
+		return 0;
+	}
+
+	pvt->owner = NULL;
+	ast_channel_tech_pvt_set(c, NULL);
+
+	if (ast_channel_hangupcause(c)) {
+		q931cause = ast_channel_hangupcause(c);
+	} else {
+		const char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS");
+		if (cause) {
+			if (!strcmp(cause, "CONGESTION")) {
+				q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+			} else if (!strcmp(cause, "BUSY")) {
+				q931cause = AST_CAUSE_USER_BUSY;
+			} else if (!strcmp(cause, "CHANISUNVAIL")) {
+				q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
+			} else if (!strcmp(cause, "NOANSWER")) {
+				q931cause = AST_CAUSE_NO_ANSWER;
+			} else if (!strcmp(cause, "CANCEL")) {
+				q931cause = AST_CAUSE_CALL_REJECTED;
+			}
+		}
+	}
+
+	/* Start the process if it's not already started */
+	if (!pvt->alreadygone && !pvt->hangupcause) {
+		call_token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL;
+		if (call_token) {
+			/* Release lock to eliminate deadlock */
+			ast_mutex_unlock(&pvt->lock);
+			if (h323_clear_call(call_token, q931cause)) {
+				ast_log(LOG_WARNING, "ClearCall failed.\n");
+			}
+			ast_free(call_token);
+			ast_mutex_lock(&pvt->lock);
+		}
+	}
+	pvt->needdestroy = 1;
+	ast_mutex_unlock(&pvt->lock);
+
+	/* Update usage counter */
+	ast_module_unref(ast_module_info->self);
+
+	return 0;
+}
+
+/*! \brief Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
+static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
+{
+	struct ast_frame *f;
+
+	/* Only apply it for the first packet, we just need the correct ip/port */
+	if (pvt->options.nat) {
+		ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat);
+		pvt->options.nat = 0;
+	}
+
+	f = ast_rtp_instance_read(pvt->rtp, 0);
+	/* Don't send RFC2833 if we're not supposed to */
+	if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO))) {
+		return &ast_null_frame;
+	}
+	if (f && pvt->owner) {
+		/* We already hold the channel lock */
+		if (f->frametype == AST_FRAME_VOICE) {
+			if (!ast_format_cap_iscompatible(ast_channel_nativeformats(pvt->owner), &f->subclass.format)) {
+				/* Try to avoid deadlock */
+				if (ast_channel_trylock(pvt->owner)) {
+					ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
+					return &ast_null_frame;
+				}
+				if (h323debug)
+					ast_debug(1, "Oooh, format changed to '%s'\n", ast_getformatname(&f->subclass.format));
+				ast_format_cap_set(ast_channel_nativeformats(pvt->owner), &f->subclass.format);
+
+				pvt->nativeformats = ast_format_to_old_bitfield(&f->subclass.format);
+
+				ast_set_read_format(pvt->owner, ast_channel_readformat(pvt->owner));
+				ast_set_write_format(pvt->owner, ast_channel_writeformat(pvt->owner));
+				ast_channel_unlock(pvt->owner);
+			}
+			/* Do in-band DTMF detection */
+			if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
+				if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) {
+					if (!ast_channel_trylock(pvt->owner)) {
+						f = ast_dsp_process(pvt->owner, pvt->vad, f);
+						ast_channel_unlock(pvt->owner);
+					}
+					else
+						ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
+				} else if (pvt->nativeformats && !pvt->noInbandDtmf) {
+					ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&f->subclass.format));
+					pvt->noInbandDtmf = 1;
+				}
+				if (f &&(f->frametype == AST_FRAME_DTMF)) {
+					if (h323debug)
+						ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass.integer);
+				}
+			}
+		}
+	}
+	return f;
+}
+
+static struct ast_frame *oh323_read(struct ast_channel *c)
+{
+	struct ast_frame *fr;
+	struct oh323_pvt *pvt = (struct oh323_pvt *)ast_channel_tech_pvt(c);
+	ast_mutex_lock(&pvt->lock);
+	__oh323_update_info(c, pvt);
+	switch(ast_channel_fdno(c)) {
+	case 0:
+		fr = oh323_rtp_read(pvt);
+		break;
+	case 1:
+		if (pvt->rtp)
+			fr = ast_rtp_instance_read(pvt->rtp, 1);
+		else
+			fr = &ast_null_frame;
+		break;
+	default:
+		ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", ast_channel_fdno(c), ast_channel_name(c));
+		fr = &ast_null_frame;
+		break;
+	}
+	ast_mutex_unlock(&pvt->lock);
+	return fr;
+}
+
+static int oh323_write(struct ast_channel *c, struct ast_frame *frame)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	int res = 0;
+	if (frame->frametype != AST_FRAME_VOICE) {
+		if (frame->frametype == AST_FRAME_IMAGE) {
+			return 0;
+		} else {
+			ast_log(LOG_WARNING, "Can't send %d type frames with H323 write\n", frame->frametype);
+			return 0;
+		}
+	} else {
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(c), &frame->subclass.format))) {
+			char tmp[256];
+			ast_log(LOG_WARNING, "Asked to transmit frame type '%s', while native formats is '%s' (read/write = %s/%s)\n",
+				ast_getformatname(&frame->subclass.format),
+				ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(c)),
+				ast_getformatname(ast_channel_readformat(c)),
+				ast_getformatname(ast_channel_writeformat(c)));
+			return 0;
+		}
+	}
+	if (pvt) {
+		ast_mutex_lock(&pvt->lock);
+		if (pvt->rtp && !pvt->recvonly)
+			res = ast_rtp_instance_write(pvt->rtp, frame);
+		__oh323_update_info(c, pvt);
+		ast_mutex_unlock(&pvt->lock);
+	}
+	return res;
+}
+
+static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen)
+{
+
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c);
+	char *token = (char *)NULL;
+	int res = -1;
+	int got_progress;
+
+	ast_mutex_lock(&pvt->lock);
+	token = (pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL);
+	got_progress = pvt->got_progress;
+	if (condition == AST_CONTROL_PROGRESS)
+		pvt->got_progress = 1;
+	else if ((condition == AST_CONTROL_BUSY) || (condition == AST_CONTROL_CONGESTION))
+		pvt->alreadygone = 1;
+	ast_mutex_unlock(&pvt->lock);
+
+	if (h323debug)
+		ast_debug(1, "OH323: Indicating %d on %s (%s)\n", condition, token, ast_channel_name(c));
+
+	switch(condition) {
+	case AST_CONTROL_RINGING:
+		if (ast_channel_state(c) == AST_STATE_RING || ast_channel_state(c) == AST_STATE_RINGING) {
+			h323_send_alerting(token);
+			res = (got_progress ? 0 : -1);	/* Do not simulate any audio tones if we got PROGRESS message */
+		}
+		break;
+	case AST_CONTROL_PROGRESS:
+		if (ast_channel_state(c) != AST_STATE_UP) {
+			/* Do not send PROGRESS message more than once */
+			if (!got_progress)
+				h323_send_progress(token);
+			res = 0;
+		}
+		break;
+	case AST_CONTROL_BUSY:
+		if (ast_channel_state(c) != AST_STATE_UP) {
+			h323_answering_call(token, 1);
+			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
+			res = 0;
+		}
+		break;
+	case AST_CONTROL_INCOMPLETE:
+		/* While h323 does support overlapped dialing, this channel driver does not
+		 * at this time.  Treat a response of Incomplete as if it were congestion.
+		 */
+	case AST_CONTROL_CONGESTION:
+		if (ast_channel_state(c) != AST_STATE_UP) {
+			h323_answering_call(token, 1);
+			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
+			res = 0;
+		}
+		break;
+	case AST_CONTROL_HOLD:
+		h323_hold_call(token, 1);
+		/* We should start MOH only if remote party isn't provide audio for us */
+		ast_moh_start(c, data, NULL);
+		res = 0;
+		break;
+	case AST_CONTROL_UNHOLD:
+		h323_hold_call(token, 0);
+		ast_moh_stop(c);
+		res = 0;
+		break;
+	case AST_CONTROL_SRCUPDATE:
+		ast_rtp_instance_update_source(pvt->rtp);
+		res = 0;
+		break;
+	case AST_CONTROL_SRCCHANGE:
+		ast_rtp_instance_change_source(pvt->rtp);
+		res = 0;
+		break;
+	case AST_CONTROL_PROCEEDING:
+	case AST_CONTROL_PVT_CAUSE_CODE:
+	case -1:
+		break;
+	default:
+		ast_log(LOG_WARNING, "OH323: Don't know how to indicate condition %d on %s\n", condition, token);
+		break;
+	}
+
+	if (h323debug)
+		ast_debug(1, "OH323: Indicated %d on %s, res=%d\n", condition, token, res);
+	if (token)
+		ast_free(token);
+	oh323_update_info(c);
+
+	return res;
+}
+
+static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(newchan);
+
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->owner != oldchan) {
+		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, pvt->owner);
+		return -1;
+	}
+	pvt->owner = newchan;
+	ast_mutex_unlock(&pvt->lock);
+	return 0;
+}
+
+static int __oh323_rtp_create(struct oh323_pvt *pvt)
+{
+	struct ast_sockaddr our_addr;
+
+	if (pvt->rtp)
+		return 0;
+
+	{
+		struct ast_sockaddr tmp;
+
+		ast_sockaddr_from_sin(&tmp, &bindaddr);
+		if (ast_find_ourip(&our_addr, &tmp, AF_INET)) {
+			ast_mutex_unlock(&pvt->lock);
+			ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n");
+			return -1;
+		}
+	}
+	our_addr.ss.ss_family = AF_INET;
+	pvt->rtp = ast_rtp_instance_new("asterisk", sched, &our_addr, NULL);
+	if (!pvt->rtp) {
+		ast_mutex_unlock(&pvt->lock);
+		ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
+		return -1;
+	}
+	if (h323debug)
+		ast_debug(1, "Created RTP channel\n");
+
+	ast_rtp_instance_set_qos(pvt->rtp, tos, cos, "H323 RTP");
+
+	if (h323debug)
+		ast_debug(1, "Setting NAT on RTP to %d\n", pvt->options.nat);
+	ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat);
+
+	if (pvt->dtmf_pt[0] > 0)
+		ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[0], "audio", "telephone-event", 0);
+	if (pvt->dtmf_pt[1] > 0)
+		ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[1], "audio", "cisco-telephone-event", 0);
+
+	if (pvt->peercapability)
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs);
+
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		ast_jb_configure(pvt->owner, &global_jbconf);
+		ast_channel_set_fd(pvt->owner, 0, ast_rtp_instance_fd(pvt->rtp, 0));
+		ast_channel_set_fd(pvt->owner, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+		ast_queue_frame(pvt->owner, &ast_null_frame);	/* Tell Asterisk to apply changes */
+		ast_channel_unlock(pvt->owner);
+	} else
+		pvt->update_rtp_info = 1;
+
+	return 0;
+}
+
+/*! \brief Private structure should be locked on a call */
+static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const char *host, const char *linkedid)
+{
+	struct ast_channel *ch;
+	char *cid_num, *cid_name;
+	h323_format fmt;
+	struct ast_format tmpfmt;
+
+	if (!ast_strlen_zero(pvt->options.cid_num))
+		cid_num = pvt->options.cid_num;
+	else
+		cid_num = pvt->cd.call_source_e164;
+
+	if (!ast_strlen_zero(pvt->options.cid_name))
+		cid_name = pvt->options.cid_name;
+	else
+		cid_name = pvt->cd.call_source_name;
+	
+	/* Don't hold a oh323_pvt lock while we allocate a chanel */
+	ast_mutex_unlock(&pvt->lock);
+	ch = ast_channel_alloc(1, state, cid_num, cid_name, pvt->accountcode, pvt->exten, pvt->context, linkedid, pvt->amaflags, "H323/%s", host);
+	/* Update usage counter */
+	ast_module_ref(ast_module_info->self);
+	ast_mutex_lock(&pvt->lock);
+	if (ch) {
+		ast_channel_tech_set(ch, &oh323_tech);
+		if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability))
+			fmt = global_options.capability;
+
+		ast_format_cap_from_old_bitfield(ast_channel_nativeformats(ch), fmt);
+		ast_codec_choose(&pvt->options.prefs, ast_channel_nativeformats(ch), 1, &tmpfmt)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/;
+
+		ast_format_cap_set(ast_channel_nativeformats(ch), &tmpfmt);
+
+		pvt->nativeformats = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(ch));
+		ast_best_codec(ast_channel_nativeformats(ch), &tmpfmt);
+		ast_format_copy(ast_channel_writeformat(ch), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(ch), &tmpfmt);
+		ast_format_copy(ast_channel_readformat(ch), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(ch), &tmpfmt);
+		if (!pvt->rtp)
+			__oh323_rtp_create(pvt);
+#if 0
+		ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(pvt->rtp, 0));
+		ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+#endif
+#ifdef VIDEO_SUPPORT
+		if (pvt->vrtp) {
+			ast_channel_set_fd(ch, 2, ast_rtp_instance_fd(pvt->vrtp, 0));
+			ast_channel_set_fd(ch, 3, ast_rtp_instance_fd(pvt->vrtp, 1));
+		}
+#endif
+#ifdef T38_SUPPORT
+		if (pvt->udptl) {
+			ast_channel_set_fd(ch, 4, ast_udptl_fd(pvt->udptl));
+		}
+#endif
+		if (state == AST_STATE_RING) {
+			ast_channel_rings_set(ch, 1);
+		}
+		/* Allocate dsp for in-band DTMF support */
+		if (pvt->options.dtmfmode & H323_DTMF_INBAND) {
+			pvt->vad = ast_dsp_new();
+			ast_dsp_set_features(pvt->vad, DSP_FEATURE_DIGIT_DETECT);
+		}
+		/* Register channel functions. */
+		ast_channel_tech_pvt_set(ch, pvt);
+		/* Set the owner of this channel */
+		pvt->owner = ch;
+
+		ast_channel_context_set(ch, pvt->context);
+		ast_channel_exten_set(ch, pvt->exten);
+		ast_channel_priority_set(ch, 1);
+		if (!ast_strlen_zero(pvt->accountcode)) {
+			ast_channel_accountcode_set(ch, pvt->accountcode);
+		}
+		if (pvt->amaflags) {
+			ast_channel_amaflags_set(ch, pvt->amaflags);
+		}
+
+		/* Don't use ast_set_callerid() here because it will
+		 * generate a needless NewCallerID event */
+		if (!ast_strlen_zero(cid_num)) {
+			ast_channel_caller(ch)->ani.number.valid = 1;
+			ast_channel_caller(ch)->ani.number.str = ast_strdup(cid_num);
+		}
+
+		if (pvt->cd.redirect_reason >= 0) {
+			ast_channel_redirecting(ch)->from.number.valid = 1;
+			ast_channel_redirecting(ch)->from.number.str = ast_strdup(pvt->cd.redirect_number);
+			pbx_builtin_setvar_helper(ch, "PRIREDIRECTREASON", redirectingreason2str(pvt->cd.redirect_reason));
+		}
+		ast_channel_caller(ch)->id.name.presentation = pvt->cd.presentation;
+		ast_channel_caller(ch)->id.number.presentation = pvt->cd.presentation;
+		ast_channel_caller(ch)->id.number.plan = pvt->cd.type_of_number;
+
+		if (!ast_strlen_zero(pvt->exten) && strcmp(pvt->exten, "s")) {
+			ast_channel_dialed(ch)->number.str = ast_strdup(pvt->exten);
+		}
+		if (pvt->cd.transfer_capability >= 0)
+			ast_channel_transfercapability_set(ch, pvt->cd.transfer_capability);
+		if (state != AST_STATE_DOWN) {
+			if (ast_pbx_start(ch)) {
+				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(ch));
+				ast_hangup(ch);
+				ch = NULL;
+			}
+		}
+	} else {
+		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+	}
+	return ch;
+}
+
+static struct oh323_pvt *oh323_alloc(int callid)
+{
+	struct oh323_pvt *pvt;
+
+	pvt = ast_calloc(1, sizeof(*pvt));
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Couldn't allocate private structure. This is bad\n");
+		return NULL;
+	}
+	pvt->cd.redirect_reason = -1;
+	pvt->cd.transfer_capability = -1;
+	/* Ensure the call token is allocated for outgoing call */
+	if (!callid) {
+		if ((pvt->cd).call_token == NULL) {
+			(pvt->cd).call_token = ast_calloc(1, 128);
+		}
+		if (!pvt->cd.call_token) {
+			ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
+			ast_rtp_instance_destroy(pvt->rtp);
+			ast_free(pvt);
+			return NULL;
+		}
+		memset((char *)(pvt->cd).call_token, 0, 128);
+		pvt->cd.call_reference = callid;
+	}
+	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
+	if (pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO)) {
+		pvt->nonCodecCapability |= AST_RTP_DTMF;
+	} else {
+		pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+	}
+	ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
+	pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->update_rtp_info = pvt->DTMFsched = -1;
+	ast_mutex_init(&pvt->lock);
+	/* Add to interface list */
+	ast_mutex_lock(&iflock);
+	pvt->next = iflist;
+	iflist = pvt;
+	ast_mutex_unlock(&iflock);
+	return pvt;
+}
+
+static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+
+	ast_mutex_lock(&iflock);
+	pvt = iflist;
+	while(pvt) {
+		if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
+			/* Found the call */
+			if ((token != NULL) && (pvt->cd.call_token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
+				ast_mutex_lock(&pvt->lock);
+				ast_mutex_unlock(&iflock);
+				return pvt;
+			} else if (token == NULL) {
+				ast_log(LOG_WARNING, "Call Token is NULL\n");
+				ast_mutex_lock(&pvt->lock);
+				ast_mutex_unlock(&iflock);
+				return pvt;
+			}
+		}
+		pvt = pvt->next;
+	}
+	ast_mutex_unlock(&iflock);
+	return NULL;
+}
+
+static int update_state(struct oh323_pvt *pvt, int state, int signal)
+{
+	if (!pvt)
+		return 0;
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		if (state >= 0)
+			ast_setstate(pvt->owner, state);
+		if (signal >= 0)
+			ast_queue_control(pvt->owner, signal);
+		ast_channel_unlock(pvt->owner);
+		return 1;
+	}
+	else {
+		if (state >= 0)
+			pvt->newstate = state;
+		if (signal >= 0)
+			pvt->newcontrol = signal;
+		return 0;
+	}
+}
+
+static struct oh323_alias *build_alias(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+	struct oh323_alias *alias;
+	int found = 0;
+
+	alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&aliasl, name, name, 0, 0, strcasecmp);
+
+	if (alias)
+		found++;
+	else {
+		if (!(alias = ast_calloc(1, sizeof(*alias))))
+			return NULL;
+		ASTOBJ_INIT(alias);
+	}
+	if (!found && name)
+		ast_copy_string(alias->name, name, sizeof(alias->name));
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!strcasecmp(v->name, "e164")) {
+			ast_copy_string(alias->e164, v->value, sizeof(alias->e164));
+		} else if (!strcasecmp(v->name, "prefix")) {
+			ast_copy_string(alias->prefix, v->value, sizeof(alias->prefix));
+		} else if (!strcasecmp(v->name, "context")) {
+			ast_copy_string(alias->context, v->value, sizeof(alias->context));
+		} else if (!strcasecmp(v->name, "secret")) {
+			ast_copy_string(alias->secret, v->value, sizeof(alias->secret));
+		} else {
+			if (strcasecmp(v->value, "h323")) {
+				ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->name);
+			}
+		}
+	}
+	ASTOBJ_UNMARK(alias);
+	return alias;
+}
+
+static struct oh323_alias *realtime_alias(const char *alias)
+{
+	struct ast_variable *var, *tmp;
+	struct oh323_alias *a;
+
+	var = ast_load_realtime("h323", "name", alias, SENTINEL);
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		if (!strcasecmp(tmp->name, "type") &&
+		!(!strcasecmp(tmp->value, "alias") || !strcasecmp(tmp->value, "h323"))) {
+			ast_variables_destroy(var);
+			return NULL;
+		}
+	}
+
+	a = build_alias(alias, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return a;
+}
+
+static int h323_parse_allow_disallow(struct ast_codec_pref *pref, h323_format *formats, const char *list, int allowing)
+{
+	int res;
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	if (!cap) {
+		return 1;
+	}
+
+	ast_format_cap_from_old_bitfield(cap, *formats);
+	res = ast_parse_allow_disallow(pref, cap, list, allowing);
+	*formats = ast_format_cap_to_old_bitfield(cap);
+	cap = ast_format_cap_destroy(cap);
+	return res;
+
+}
+
+static int update_common_options(struct ast_variable *v, struct call_options *options)
+{
+	int tmp = 0;
+	char *val, *opt;
+
+	if (!strcasecmp(v->name, "allow")) {
+		h323_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1);
+	} else if (!strcasecmp(v->name, "autoframing")) {
+		options->autoframing = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "disallow")) {
+		h323_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0);
+	} else if (!strcasecmp(v->name, "dtmfmode")) {
+		val = ast_strdupa(v->value);
+		if ((opt = strchr(val, ':')) != (char *)NULL) {
+			*opt++ = '\0';
+			tmp = atoi(opt);
+		}
+		if (!strcasecmp(v->value, "inband")) {
+			options->dtmfmode |= H323_DTMF_INBAND;
+		} else if (!strcasecmp(val, "rfc2833")) {
+			options->dtmfmode |= H323_DTMF_RFC2833;
+			if (!opt) {
+				options->dtmfcodec[0] = H323_DTMF_RFC2833_PT;
+			} else if ((tmp >= 96) && (tmp < 128)) {
+				options->dtmfcodec[0] = tmp;
+			} else {
+				options->dtmfcodec[0] = H323_DTMF_RFC2833_PT;
+				ast_log(LOG_WARNING, "Unknown rfc2833 payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[0]);
+			}
+		} else if (!strcasecmp(val, "cisco")) {
+			options->dtmfmode |= H323_DTMF_CISCO;
+			if (!opt) {
+				options->dtmfcodec[1] = H323_DTMF_CISCO_PT;
+			} else if ((tmp >= 96) && (tmp < 128)) {
+				options->dtmfcodec[1] = tmp;
+			} else {
+				options->dtmfcodec[1] = H323_DTMF_CISCO_PT;
+				ast_log(LOG_WARNING, "Unknown Cisco DTMF payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[1]);
+			}
+		} else if (!strcasecmp(v->value, "h245-signal")) {
+			options->dtmfmode |= H323_DTMF_SIGNAL;
+		} else {
+			ast_log(LOG_WARNING, "Unknown dtmf mode '%s' at line %d\n", v->value, v->lineno);
+		}
+	} else if (!strcasecmp(v->name, "dtmfcodec")) {
+		ast_log(LOG_NOTICE, "Option %s at line %d is deprecated. Use dtmfmode=rfc2833[:<payload>] instead.\n", v->name, v->lineno);
+		tmp = atoi(v->value);
+		if (tmp < 96)
+			ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno);
+		else
+			options->dtmfcodec[0] = tmp;
+	} else if (!strcasecmp(v->name, "bridge")) {
+		options->bridge = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "nat")) {
+		options->nat = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "fastStart")) {
+		options->fastStart = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "h245Tunneling")) {
+		options->h245Tunneling = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "silenceSuppression")) {
+		options->silenceSuppression = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "progress_setup")) {
+		tmp = atoi(v->value);
+		if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+			tmp = 0;
+		}
+		options->progress_setup = tmp;
+	} else if (!strcasecmp(v->name, "progress_alert")) {
+		tmp = atoi(v->value);
+		if ((tmp != 0) && (tmp != 1) && (tmp != 8)) {
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+			tmp = 0;
+		}
+		options->progress_alert = tmp;
+	} else if (!strcasecmp(v->name, "progress_audio")) {
+		options->progress_audio = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "callerid")) {
+		ast_callerid_split(v->value, options->cid_name, sizeof(options->cid_name), options->cid_num, sizeof(options->cid_num));
+	} else if (!strcasecmp(v->name, "fullname")) {
+		ast_copy_string(options->cid_name, v->value, sizeof(options->cid_name));
+	} else if (!strcasecmp(v->name, "cid_number")) {
+		ast_copy_string(options->cid_num, v->value, sizeof(options->cid_num));
+	} else if (!strcasecmp(v->name, "tunneling")) {
+		if (!strcasecmp(v->value, "none"))
+			options->tunnelOptions = 0;
+		else if (!strcasecmp(v->value, "cisco"))
+			options->tunnelOptions |= H323_TUNNEL_CISCO;
+		else if (!strcasecmp(v->value, "qsig"))
+			options->tunnelOptions |= H323_TUNNEL_QSIG;
+		else
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
+	} else if (!strcasecmp(v->name, "hold")) {
+		if (!strcasecmp(v->value, "none"))
+			options->holdHandling = ~0;
+		else if (!strcasecmp(v->value, "notify"))
+			options->holdHandling |= H323_HOLD_NOTIFY;
+		else if (!strcasecmp(v->value, "q931only"))
+			options->holdHandling |= H323_HOLD_NOTIFY | H323_HOLD_Q931ONLY;
+		else if (!strcasecmp(v->value, "h450"))
+			options->holdHandling |= H323_HOLD_H450;
+		else
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
+	} else
+		return 1;
+
+	return 0;
+}
+
+static struct oh323_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+	struct oh323_user *user;
+	struct ast_ha *oldha;
+	int found = 0;
+	int format;
+
+	user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&userl, name, name, 0, 0, strcmp);
+
+	if (user)
+		found++;
+	else {
+		if (!(user = ast_calloc(1, sizeof(*user))))
+			return NULL;
+		ASTOBJ_INIT(user);
+	}
+	oldha = user->ha;
+	user->ha = (struct ast_ha *)NULL;
+	memcpy(&user->options, &global_options, sizeof(user->options));
+	user->options.dtmfmode = 0;
+	user->options.holdHandling = 0;
+	/* Set default context */
+	ast_copy_string(user->context, default_context, sizeof(user->context));
+	if (!found) {
+		ast_copy_string(user->name, name, sizeof(user->name));
+	}
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+	if (user->chanvars) {
+		ast_variables_destroy(user->chanvars);
+		user->chanvars = NULL;
+	}
+#endif
+
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!update_common_options(v, &user->options))
+			continue;
+		if (!strcasecmp(v->name, "context")) {
+			ast_copy_string(user->context, v->value, sizeof(user->context));
+		} else if (!strcasecmp(v->name, "secret")) {
+			ast_copy_string(user->secret, v->value, sizeof(user->secret));
+		} else if (!strcasecmp(v->name, "accountcode")) {
+			ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
+		} else if (!strcasecmp(v->name, "host")) {
+			if (!strcasecmp(v->value, "dynamic")) {
+				ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
+				ASTOBJ_UNREF(user, oh323_destroy_user);
+				return NULL;
+			} else {
+				struct ast_sockaddr tmp;
+
+				tmp.ss.ss_family = AF_INET;
+				if (ast_get_ip(&tmp, v->value)) {
+					ASTOBJ_UNREF(user, oh323_destroy_user);
+					return NULL;
+				}
+				ast_sockaddr_to_sin(&tmp, &user->addr);
+			}
+			/* Let us know we need to use ip authentication */
+			user->host = 1;
+		} else if (!strcasecmp(v->name, "amaflags")) {
+			format = ast_cdr_amaflags2int(v->value);
+			if (format < 0) {
+				ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
+			} else {
+				user->amaflags = format;
+			}
+		} else if (!strcasecmp(v->name, "permit") ||
+					!strcasecmp(v->name, "deny")) {
+			int ha_error = 0;
+
+			user->ha = ast_append_ha(v->name, v->value, user->ha, &ha_error);
+			if (ha_error)
+				ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+		}
+	}
+	if (!user->options.dtmfmode)
+		user->options.dtmfmode = global_options.dtmfmode;
+	if (user->options.holdHandling == ~0)
+		user->options.holdHandling = 0;
+	else if (!user->options.holdHandling)
+		user->options.holdHandling = global_options.holdHandling;
+	ASTOBJ_UNMARK(user);
+	ast_free_ha(oldha);
+	return user;
+}
+
+static struct oh323_user *realtime_user(const call_details_t *cd)
+{
+	struct ast_variable *var, *tmp;
+	struct oh323_user *user;
+	const char *username;
+
+	if (userbyalias)
+		var = ast_load_realtime("h323", "name", username = cd->call_source_aliases, SENTINEL);
+	else {
+		username = (char *)NULL;
+		var = ast_load_realtime("h323", "host", cd->sourceIp, SENTINEL);
+	}
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		if (!strcasecmp(tmp->name, "type") &&
+		!(!strcasecmp(tmp->value, "user") || !strcasecmp(tmp->value, "friend"))) {
+			ast_variables_destroy(var);
+			return NULL;
+		} else if (!username && !strcasecmp(tmp->name, "name"))
+			username = tmp->value;
+	}
+
+	if (!username) {
+		ast_log(LOG_WARNING, "Cannot determine user name for IP address %s\n", cd->sourceIp);
+		ast_variables_destroy(var);
+		return NULL;
+	}
+
+	user = build_user(username, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return user;
+}
+
+static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+	struct oh323_peer *peer;
+	struct ast_ha *oldha;
+	int found = 0;
+
+	peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
+
+	if (peer)
+		found++;
+	else {
+		if (!(peer = ast_calloc(1, sizeof(*peer))))
+			return NULL;
+		ASTOBJ_INIT(peer);
+	}
+	oldha = peer->ha;
+	peer->ha = NULL;
+	memcpy(&peer->options, &global_options, sizeof(peer->options));
+	peer->options.dtmfmode = 0;
+	peer->options.holdHandling = 0;
+	peer->addr.sin_port = htons(h323_signalling_port);
+	peer->addr.sin_family = AF_INET;
+	if (!found && name)
+		ast_copy_string(peer->name, name, sizeof(peer->name));
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+	if (peer->chanvars) {
+		ast_variables_destroy(peer->chanvars);
+		peer->chanvars = NULL;
+	}
+#endif
+	/* Default settings for mailbox */
+	peer->mailbox[0] = '\0';
+
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!update_common_options(v, &peer->options))
+			continue;
+		if (!strcasecmp(v->name, "host")) {
+			if (!strcasecmp(v->value, "dynamic")) {
+				ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
+				ASTOBJ_UNREF(peer, oh323_destroy_peer);
+				return NULL;
+			}
+			{
+				struct ast_sockaddr tmp;
+
+				tmp.ss.ss_family = AF_INET;
+				if (ast_get_ip(&tmp, v->value)) {
+					ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
+					ASTOBJ_UNREF(peer, oh323_destroy_peer);
+					return NULL;
+				}
+				ast_sockaddr_to_sin(&tmp, &peer->addr);
+			}
+		} else if (!strcasecmp(v->name, "port")) {
+			peer->addr.sin_port = htons(atoi(v->value));
+		} else if (!strcasecmp(v->name, "permit") ||
+					!strcasecmp(v->name, "deny")) {
+			int ha_error = 0;
+
+			peer->ha = ast_append_ha(v->name, v->value, peer->ha, &ha_error);
+			if (ha_error)
+				ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+		} else if (!strcasecmp(v->name, "mailbox")) {
+			ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
+		} else if (!strcasecmp(v->name, "hasvoicemail")) {
+			if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
+				ast_copy_string(peer->mailbox, name, sizeof(peer->mailbox));
+			}
+		}
+	}
+	if (!peer->options.dtmfmode)
+		peer->options.dtmfmode = global_options.dtmfmode;
+	if (peer->options.holdHandling == ~0)
+		peer->options.holdHandling = 0;
+	else if (!peer->options.holdHandling)
+		peer->options.holdHandling = global_options.holdHandling;
+	ASTOBJ_UNMARK(peer);
+	ast_free_ha(oldha);
+	return peer;
+}
+
+static struct oh323_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
+{
+	struct oh323_peer *peer;
+	struct ast_variable *var;
+	struct ast_variable *tmp;
+	const char *addr = NULL;
+
+	/* First check on peer name */
+	if (peername)
+		var = ast_load_realtime("h323", "name", peername, SENTINEL);
+	else if (sin) /* Then check on IP address for dynamic peers */
+		var = ast_load_realtime("h323", "host", addr = ast_inet_ntoa(sin->sin_addr), SENTINEL);
+	else
+		return NULL;
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		/* If this is type=user, then skip this object. */
+		if (!strcasecmp(tmp->name, "type") &&
+				!(!strcasecmp(tmp->value, "peer") || !strcasecmp(tmp->value, "friend"))) {
+			ast_variables_destroy(var);
+			return NULL;
+		} else if (!peername && !strcasecmp(tmp->name, "name")) {
+			peername = tmp->value;
+		}
+	}
+
+	if (!peername) {	/* Did not find peer in realtime */
+		ast_log(LOG_WARNING, "Cannot determine peer name for IP address %s\n", addr);
+		ast_variables_destroy(var);
+		return NULL;
+	}
+
+	/* Peer found in realtime, now build it in memory */
+	peer = build_peer(peername, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return peer;
+}
+
+static int oh323_addrcmp_str(struct in_addr inaddr, char *addr)
+{
+	return strcmp(ast_inet_ntoa(inaddr), addr);
+}
+
+static struct oh323_user *find_user(const call_details_t *cd, int realtime)
+{
+	struct oh323_user *u;
+
+	if (userbyalias)
+		u = ASTOBJ_CONTAINER_FIND(&userl, cd->call_source_aliases);
+	else
+		u = ASTOBJ_CONTAINER_FIND_FULL(&userl, cd->sourceIp, addr.sin_addr, 0, 0, oh323_addrcmp_str);
+
+	if (!u && realtime)
+		u = realtime_user(cd);
+
+	if (!u && h323debug)
+		ast_debug(1, "Could not find user by name %s or address %s\n", cd->call_source_aliases, cd->sourceIp);
+
+	return u;
+}
+
+static int oh323_addrcmp(struct sockaddr_in addr, struct sockaddr_in *sin)
+{
+	int res;
+
+	if (!sin)
+		res = -1;
+	else
+		res = inaddrcmp(&addr , sin);
+
+	return res;
+}
+
+static struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
+{
+	struct oh323_peer *p;
+
+	if (peer)
+		p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
+	else
+		p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, addr, 0, 0, oh323_addrcmp);
+
+	if (!p && realtime)
+		p = realtime_peer(peer, sin);
+
+	if (!p && h323debug)
+		ast_debug(1, "Could not find peer by name %s or address %s\n", (peer ? peer : "<NONE>"), (sin ? ast_inet_ntoa(sin->sin_addr) : "<NONE>"));
+
+	return p;
+}
+
+static int create_addr(struct oh323_pvt *pvt, char *opeer)
+{
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct oh323_peer *p;
+	int portno;
+	int found = 0;
+	char *port;
+	char *hostn;
+	char peer[256] = "";
+
+	ast_copy_string(peer, opeer, sizeof(peer));
+	port = strchr(peer, ':');
+	if (port) {
+		*port = '\0';
+		port++;
+	}
+	pvt->sa.sin_family = AF_INET;
+	p = find_peer(peer, NULL, 1);
+	if (p) {
+		found++;
+		memcpy(&pvt->options, &p->options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
+		if (pvt->options.dtmfmode) {
+			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+				pvt->nonCodecCapability |= AST_RTP_DTMF;
+			} else {
+				pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+			}
+		}
+		if (p->addr.sin_addr.s_addr) {
+			pvt->sa.sin_addr = p->addr.sin_addr;
+			pvt->sa.sin_port = p->addr.sin_port;
+		}
+		ASTOBJ_UNREF(p, oh323_destroy_peer);
+	}
+	if (!p && !found) {
+		hostn = peer;
+		if (port) {
+			portno = atoi(port);
+		} else {
+			portno = h323_signalling_port;
+		}
+		hp = ast_gethostbyname(hostn, &ahp);
+		if (hp) {
+			memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
+			pvt->sa.sin_port = htons(portno);
+			/* Look peer by address */
+			p = find_peer(NULL, &pvt->sa, 1);
+			memcpy(&pvt->options, (p ? &p->options : &global_options), sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
+			if (p) {
+				ASTOBJ_UNREF(p, oh323_destroy_peer);
+			}
+			if (pvt->options.dtmfmode) {
+				if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+					pvt->nonCodecCapability |= AST_RTP_DTMF;
+				} else {
+					pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+				}
+			}
+			return 0;
+		} else {
+			ast_log(LOG_WARNING, "No such host: %s\n", peer);
+			return -1;
+		}
+	} else if (!found) {
+		return -1;
+	} else {
+		return 0;
+	}
+}
+static struct ast_channel *oh323_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause)
+{
+	struct oh323_pvt *pvt;
+	struct ast_channel *tmpc = NULL;
+	char *ext, *host;
+	char *h323id = NULL;
+	char tmp[256], tmp1[256];
+
+	if (h323debug)
+		ast_debug(1, "type=%s, format=%s, data=%s.\n", type, ast_getformatname_multiple(tmp, sizeof(tmp), cap), dest);
+
+	pvt = oh323_alloc(0);
+	if (!pvt) {
+		ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", dest);
+		return NULL;
+	}
+	if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
+		oh323_destroy(pvt);
+		if (cause)
+			*cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
+		return NULL;
+	}
+	ast_copy_string(tmp, dest, sizeof(tmp));
+	host = strchr(tmp, '@');
+	if (host) {
+		*host = '\0';
+		host++;
+		ext = tmp;
+	} else {
+		ext = strrchr(tmp, '/');
+		if (ext)
+			*ext++ = '\0';
+		host = tmp;
+	}
+	strtok_r(host, "/", &(h323id));
+	if (!ast_strlen_zero(h323id)) {
+		h323_set_id(h323id);
+	}
+	if (ext) {
+		ast_copy_string(pvt->exten, ext, sizeof(pvt->exten));
+	}
+	if (h323debug)
+		ast_debug(1, "Extension: %s Host: %s\n", pvt->exten, host);
+
+	if (gatekeeper_disable) {
+		if (create_addr(pvt, host)) {
+			oh323_destroy(pvt);
+			if (cause)
+				*cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
+			return NULL;
+		}
+	}
+	else {
+		memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
+		if (pvt->options.dtmfmode) {
+			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+				pvt->nonCodecCapability |= AST_RTP_DTMF;
+			} else {
+				pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+			}
+		}
+	}
+
+	ast_mutex_lock(&caplock);
+	/* Generate unique channel identifier */
+	snprintf(tmp1, sizeof(tmp1)-1, "%s-%u", host, ++unique);
+	tmp1[sizeof(tmp1)-1] = '\0';
+	ast_mutex_unlock(&caplock);
+
+	ast_mutex_lock(&pvt->lock);
+	tmpc = __oh323_new(pvt, AST_STATE_DOWN, tmp1, requestor ? ast_channel_linkedid(requestor) : NULL);
+	ast_mutex_unlock(&pvt->lock);
+	if (!tmpc) {
+		oh323_destroy(pvt);
+		if (cause)
+			*cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
+	}
+	ast_update_use_count();
+	restart_monitor();
+	return tmpc;
+}
+
+/*! \brief Find a call by alias */
+static struct oh323_alias *find_alias(const char *source_aliases, int realtime)
+{
+	struct oh323_alias *a;
+
+	a = ASTOBJ_CONTAINER_FIND(&aliasl, source_aliases);
+
+	if (!a && realtime)
+		a = realtime_alias(source_aliases);
+
+	return a;
+}
+
+/*! \brief
+  * Callback for sending digits from H.323 up to asterisk
+  *
+  */
+static int receive_digit(unsigned call_reference, char digit, const char *token, int duration)
+{
+	struct oh323_pvt *pvt;
+	int res;
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token);
+		return -1;
+	}
+	if (h323debug)
+		ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token);
+
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		if (digit == '!')
+			res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
+		else {
+			struct ast_frame f = {
+				.frametype = AST_FRAME_DTMF_END,
+				.subclass.integer = digit,
+				.samples = duration * 8,
+				.len = duration,
+				.src = "SEND_DIGIT",
+			};
+			if (digit == ' ') {		/* signalUpdate message */
+				f.subclass.integer = pvt->curDTMF;
+				AST_SCHED_DEL(sched, pvt->DTMFsched);
+			} else {				/* Regular input or signal message */
+				if (pvt->DTMFsched >= 0) {
+					/* We still don't send DTMF END from previous event, send it now */
+					AST_SCHED_DEL(sched, pvt->DTMFsched);
+					f.subclass.integer = pvt->curDTMF;
+					f.samples = f.len = 0;
+					ast_queue_frame(pvt->owner, &f);
+					/* Restore values */
+					f.subclass.integer = digit;
+					f.samples = duration * 8;
+					f.len = duration;
+				}
+				if (duration) {		/* This is a signal, signalUpdate follows */
+					f.frametype = AST_FRAME_DTMF_BEGIN;
+					pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt);
+					if (h323debug)
+						ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched);
+				}
+				pvt->curDTMF = digit;
+			}
+			res = ast_queue_frame(pvt->owner, &f);
+		}
+		ast_channel_unlock(pvt->owner);
+	} else {
+		if (digit == '!')
+			pvt->newcontrol = AST_CONTROL_FLASH;
+		else {
+			pvt->newduration = duration;
+			pvt->newdigit = digit;
+		}
+		res = 0;
+	}
+	ast_mutex_unlock(&pvt->lock);
+	return res;
+}
+
+/*! \brief
+  * Callback function used to inform the H.323 stack of the local rtp ip/port details
+  *
+  * \return Returns the local RTP information
+  */
+static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
+{
+	struct oh323_pvt *pvt;
+	struct sockaddr_in us;
+	struct rtp_info *info;
+
+	info = ast_calloc(1, sizeof(*info));
+	if (!info) {
+		ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
+		return NULL;
+	}
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_free(info);
+		ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
+		return NULL;
+	}
+	if (!pvt->rtp)
+		__oh323_rtp_create(pvt);
+	if (!pvt->rtp) {
+		ast_mutex_unlock(&pvt->lock);
+		ast_free(info);
+		ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference);
+		return NULL;
+	}
+	/* figure out our local RTP port and tell the H.323 stack about it */
+	{
+		struct ast_sockaddr tmp;
+
+		ast_rtp_instance_get_local_address(pvt->rtp, &tmp);
+		ast_sockaddr_to_sin(&tmp, &us);
+	}
+	ast_mutex_unlock(&pvt->lock);
+
+	ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr));
+	info->port = ntohs(us.sin_port);
+	if (h323debug)
+		ast_debug(1, "Sending RTP 'US' %s:%d\n", info->addr, info->port);
+	return info;
+}
+
+/*! \brief
+  * Call-back function passing remote ip/port information from H.323 to asterisk
+  *
+  * Returns nothing
+  */
+static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
+{
+	struct oh323_pvt *pvt;
+	struct sockaddr_in them;
+	int nativeformats_changed;
+	enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE;
+
+	if (h323debug)
+		ast_debug(1, "Setting up RTP connection for %s\n", token);
+
+	/* Find the call or allocate a private structure if call not found */
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: rtp\n");
+		return;
+	}
+	if (pvt->alreadygone) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
+
+	if (!pvt->rtp)
+		__oh323_rtp_create(pvt);
+
+	if ((pt == 2) && (pvt->jointcapability & AST_FORMAT_G726_AAL2)) {
+		ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pt, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
+	}
+
+	them.sin_family = AF_INET;
+	/* only works for IPv4 */
+	them.sin_addr.s_addr = inet_addr(remoteIp);
+	them.sin_port = htons(remotePort);
+
+	if (them.sin_addr.s_addr) {
+		{
+			struct ast_sockaddr tmp;
+
+			ast_sockaddr_from_sin(&tmp, &them);
+			ast_rtp_instance_set_remote_address(pvt->rtp, &tmp);
+		}
+		if (pvt->recvonly) {
+			pvt->recvonly = 0;
+			rtp_change = NEED_UNHOLD;
+		}
+	} else {
+		ast_rtp_instance_stop(pvt->rtp);
+		if (!pvt->recvonly) {
+			pvt->recvonly = 1;
+			rtp_change = NEED_HOLD;
+		}
+	}
+
+	/* Change native format to reflect information taken from OLC/OLCAck */
+	nativeformats_changed = 0;
+	if (pt != 128 && pvt->rtp) {	/* Payload type is invalid, so try to use previously decided */
+		struct ast_rtp_payload_type rtptype = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(pvt->rtp), pt);
+		if (rtptype.asterisk_format) {
+			if (pvt->nativeformats != ast_format_to_old_bitfield(&rtptype.format)) {
+				pvt->nativeformats = ast_format_to_old_bitfield(&rtptype.format);
+				nativeformats_changed = 1;
+			}
+		}
+	} else if (h323debug)
+		ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n");
+
+	/* Don't try to lock the channel if nothing changed */
+	if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) {
+		if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+			struct ast_format_cap *pvt_native = ast_format_cap_alloc_nolock();
+			ast_format_cap_from_old_bitfield(pvt_native, pvt->nativeformats);
+
+			/* Re-build translation path only if native format(s) has been changed */
+			if (!(ast_format_cap_identical(ast_channel_nativeformats(pvt->owner), pvt_native))) {
+				if (h323debug) {
+					char tmp[256], tmp2[256];
+					ast_debug(1, "Native format changed to '%s' from '%s', read format is %s, write format is %s\n",
+						ast_getformatname_multiple(tmp, sizeof(tmp), pvt_native),
+						ast_getformatname_multiple(tmp2, sizeof(tmp2), ast_channel_nativeformats(pvt->owner)),
+						ast_getformatname(ast_channel_readformat(pvt->owner)),
+						ast_getformatname(ast_channel_readformat(pvt->owner)));
+				}
+				ast_format_cap_copy(ast_channel_nativeformats(pvt->owner), pvt_native);
+				ast_set_read_format(pvt->owner, ast_channel_readformat(pvt->owner));
+				ast_set_write_format(pvt->owner, ast_channel_writeformat(pvt->owner));
+			}
+			if (pvt->options.progress_audio)
+				ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
+			switch (rtp_change) {
+			case NEED_HOLD:
+				ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+				break;
+			case NEED_UNHOLD:
+				ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+				break;
+			default:
+				break;
+			}
+			ast_channel_unlock(pvt->owner);
+			pvt_native = ast_format_cap_destroy(pvt_native);
+		}
+		else {
+			if (pvt->options.progress_audio)
+				pvt->newcontrol = AST_CONTROL_PROGRESS;
+			else if (rtp_change == NEED_HOLD)
+				pvt->newcontrol = AST_CONTROL_HOLD;
+			else if (rtp_change == NEED_UNHOLD)
+				pvt->newcontrol = AST_CONTROL_UNHOLD;
+			if (h323debug)
+				ast_debug(1, "RTP connection preparation for %s is pending...\n", token);
+		}
+	}
+	ast_mutex_unlock(&pvt->lock);
+
+	if (h323debug)
+		ast_debug(1, "RTP connection prepared for %s\n", token);
+
+	return;
+}
+
+/*! \brief
+  *	Call-back function to signal asterisk that the channel has been answered
+  * Returns nothing
+  */
+static void connection_made(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Call %s answered\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: connection\n");
+		return;
+	}
+
+	/* Inform asterisk about remote party connected only on outgoing calls */
+	if (!pvt->outgoing) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
+	/* Do not send ANSWER message more than once */
+	if (!pvt->connection_established) {
+		pvt->connection_established = 1;
+		update_state(pvt, -1, AST_CONTROL_ANSWER);
+	}
+	ast_mutex_unlock(&pvt->lock);
+	return;
+}
+
+static int progress(unsigned call_reference, const char *token, int inband)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Private structure not found in progress.\n");
+		return -1;
+	}
+	if (!pvt->owner) {
+		ast_mutex_unlock(&pvt->lock);
+		ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
+		return -1;
+	}
+	update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
+	ast_mutex_unlock(&pvt->lock);
+
+	return 0;
+}
+
+/*! \brief
+ *  Call-back function for incoming calls
+ *
+ *  Returns 1 on success
+ */
+static call_options_t *setup_incoming_call(call_details_t *cd)
+{
+	struct oh323_pvt *pvt;
+	struct oh323_user *user = NULL;
+	struct oh323_alias *alias = NULL;
+
+	if (h323debug)
+		ast_debug(1, "Setting up incoming call for %s\n", cd->call_token);
+
+	/* allocate the call*/
+	pvt = oh323_alloc(cd->call_reference);
+
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
+		cleanup_call_details(cd);
+		return NULL;
+	}
+
+	/* Populate the call details in the private structure */
+	memcpy(&pvt->cd, cd, sizeof(pvt->cd));
+	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
+
+	if (h323debug) {
+		ast_verb(3, "Setting up Call\n");
+		ast_verb(3, " \tCall token:  [%s]\n", pvt->cd.call_token);
+		ast_verb(3, " \tCalling party name:  [%s]\n", pvt->cd.call_source_name);
+		ast_verb(3, " \tCalling party number:  [%s]\n", pvt->cd.call_source_e164);
+		ast_verb(3, " \tCalled party name:  [%s]\n", pvt->cd.call_dest_alias);
+		ast_verb(3, " \tCalled party number:  [%s]\n", pvt->cd.call_dest_e164);
+		if (pvt->cd.redirect_reason >= 0)
+			ast_verb(3, " \tRedirecting party number:  [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason);
+		ast_verb(3, " \tCalling party IP:  [%s]\n", pvt->cd.sourceIp);
+	}
+
+	/* Decide if we are allowing Gatekeeper routed calls*/
+	if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) {
+		if (!ast_strlen_zero(cd->call_dest_e164)) {
+			ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
+			ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
+		} else {
+			alias = find_alias(cd->call_dest_alias, 1);
+			if (!alias) {
+				ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias);
+				oh323_destroy(pvt);
+				return NULL;
+			}
+			ast_copy_string(pvt->exten, alias->name, sizeof(pvt->exten));
+			ast_copy_string(pvt->context, alias->context, sizeof(pvt->context));
+		}
+	} else {
+		/* Either this call is not from the Gatekeeper
+		   or we are not allowing gk routed calls */
+		user = find_user(cd, 1);
+		if (!user) {
+			if (!acceptAnonymous) {
+				ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+				oh323_destroy(pvt);
+				return NULL;
+			}
+			if (ast_strlen_zero(default_context)) {
+				ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+				oh323_destroy(pvt);
+				return NULL;
+			}
+			ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
+			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
+				ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
+			} else {
+				ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten));
+			}
+			if (h323debug)
+				ast_debug(1, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten);
+		} else {
+			if (user->host) {
+				if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) {
+					if (ast_strlen_zero(user->context)) {
+						if (ast_strlen_zero(default_context)) {
+							ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp);
+							oh323_destroy(pvt);
+							ASTOBJ_UNREF(user, oh323_destroy_user);
+							return NULL;
+						}
+						ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
+					} else {
+						ast_copy_string(pvt->context, user->context, sizeof(pvt->context));
+					}
+					pvt->exten[0] = 'i';
+					pvt->exten[1] = '\0';
+					ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp);
+					oh323_destroy(pvt);
+					ASTOBJ_UNREF(user, oh323_destroy_user);
+					return NULL;	/* XXX: Hmmm... Why to setup context if we drop connection immediately??? */
+				}
+			}
+			ast_copy_string(pvt->context, user->context, sizeof(pvt->context));
+			memcpy(&pvt->options, &user->options, sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
+			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
+				ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
+			} else {
+				ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten));
+			}
+			if (!ast_strlen_zero(user->accountcode)) {
+				ast_copy_string(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode));
+			}
+			if (user->amaflags) {
+				pvt->amaflags = user->amaflags;
+			}
+			ASTOBJ_UNREF(user, oh323_destroy_user);
+		}
+	}
+	return &pvt->options;
+}
+
+/*! \brief
+ * Call-back function to start PBX when OpenH323 ready to serve incoming call
+ *
+ * Returns 1 on success
+ */
+static int answer_call(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+	struct ast_channel *c = NULL;
+	enum {ext_original, ext_s, ext_i, ext_notexists} try_exten;
+	char tmp_exten[sizeof(pvt->exten)];
+
+	if (h323debug)
+		ast_debug(1, "Preparing Asterisk to answer for %s\n", token);
+
+	/* Find the call or allocate a private structure if call not found */
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: answer_call\n");
+		return 0;
+	}
+	/* Check if requested extension at context pair exists in the dialplan */
+	ast_copy_string(tmp_exten, pvt->exten, sizeof(tmp_exten));
+
+	/* Try to find best extension in specified context */
+	if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) {
+		if (tmp_exten[0] == 's')
+			try_exten = ext_s;
+		else if (tmp_exten[0] == 'i')
+			try_exten = ext_i;
+		else
+			try_exten = ext_original;
+	} else
+		try_exten = ext_original;
+	do {
+		if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL))
+			break;
+		switch (try_exten) {
+		case ext_original:
+			tmp_exten[0] = 's';
+			tmp_exten[1] = '\0';
+			try_exten = ext_s;
+			break;
+		case ext_s:
+			tmp_exten[0] = 'i';
+			try_exten = ext_i;
+			break;
+		case ext_i:
+			try_exten = ext_notexists;
+			break;
+		default:
+			break;
+		}
+	} while (try_exten != ext_notexists);
+
+	/* Drop the call if we don't have <exten>, s and i extensions */
+	if (try_exten == ext_notexists) {
+		ast_log(LOG_NOTICE, "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s]\n", pvt->exten, pvt->context);
+		ast_mutex_unlock(&pvt->lock);
+		h323_clear_call(token, AST_CAUSE_UNALLOCATED);
+		return 0;
+	} else if ((try_exten != ext_original) && (strcmp(pvt->exten, tmp_exten) != 0)) {
+		if (h323debug)
+			ast_debug(1, "Going to extension %s@%s because %s@%s isn't exists\n", tmp_exten, pvt->context, pvt->exten, pvt->context);
+		ast_copy_string(pvt->exten, tmp_exten, sizeof(pvt->exten));
+	}
+
+	/* allocate a channel and tell asterisk about it */
+	c = __oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token, NULL);
+
+	/* And release when done */
+	ast_mutex_unlock(&pvt->lock);
+	if (!c) {
+		ast_log(LOG_ERROR, "Couldn't create channel. This is bad\n");
+		return 0;
+	}
+	return 1;
+}
+
+/*! \brief
+ * Call-back function to establish an outgoing H.323 call
+ *
+ * Returns 1 on success
+ */
+static int setup_outgoing_call(call_details_t *cd)
+{
+	/* Use argument here or free it immediately */
+	cleanup_call_details(cd);
+
+	return 1;
+}
+
+/*! \brief
+  *  Call-back function to signal asterisk that the channel is ringing
+  *  Returns nothing
+  */
+static void chan_ringing(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Ringing on %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: ringing\n");
+		return;
+	}
+	if (!pvt->owner) {
+		ast_mutex_unlock(&pvt->lock);
+		ast_log(LOG_ERROR, "Channel has no owner\n");
+		return;
+	}
+	update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING);
+	ast_mutex_unlock(&pvt->lock);
+	return;
+}
+
+/*! \brief
+  * Call-back function to cleanup communication
+  * Returns nothing,
+  */
+static void cleanup_connection(unsigned call_reference, const char *call_token)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Cleaning connection to %s\n", call_token);
+
+	while (1) {
+		pvt = find_call_locked(call_reference, call_token);
+		if (!pvt) {
+			if (h323debug)
+				ast_debug(1, "No connection for %s\n", call_token);
+			return;
+		}
+		if (!pvt->owner || !ast_channel_trylock(pvt->owner))
+			break;
+#if 1
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", call_token);
+#ifdef DEBUG_THREADS
+		/* XXX to be completed
+		 * If we want to print more info on who is holding the lock,
+		 * implement the relevant code in lock.h and use the routines
+		 * supplied there.
+		 */
+#endif
+#endif
+		ast_mutex_unlock(&pvt->lock);
+		usleep(1);
+	}
+	if (pvt->rtp) {
+		/* Immediately stop RTP */
+		ast_rtp_instance_destroy(pvt->rtp);
+		pvt->rtp = NULL;
+	}
+	/* Free dsp used for in-band DTMF detection */
+	if (pvt->vad) {
+		ast_dsp_free(pvt->vad);
+		pvt->vad = NULL;
+	}
+	cleanup_call_details(&pvt->cd);
+	pvt->alreadygone = 1;
+	/* Send hangup */
+	if (pvt->owner) {
+		ast_channel_softhangup_internal_flag_add(pvt->owner, AST_SOFTHANGUP_DEV);
+		ast_queue_hangup(pvt->owner);
+		ast_channel_unlock(pvt->owner);
+	}
+	ast_mutex_unlock(&pvt->lock);
+	if (h323debug)
+		ast_debug(1, "Connection to %s cleaned\n", call_token);
+	return;
+}
+
+static void hangup_connection(unsigned int call_reference, const char *token, int cause)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Hanging up connection to %s with cause %d\n", token, cause);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		if (h323debug)
+			ast_debug(1, "Connection to %s already cleared\n", token);
+		return;
+	}
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		ast_channel_softhangup_internal_flag_add(pvt->owner, AST_SOFTHANGUP_DEV);
+		ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause = cause);
+		ast_queue_hangup_with_cause(pvt->owner, cause);
+		ast_channel_unlock(pvt->owner);
+	}
+	else {
+		pvt->needhangup = 1;
+		pvt->hangupcause = cause;
+		if (h323debug)
+			ast_debug(1, "Hangup for %s is pending\n", token);
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
+static void set_dtmf_payload(unsigned call_reference, const char *token, int payload, int is_cisco)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Setting %s DTMF payload to %d on %s\n", (is_cisco ? "Cisco" : "RFC2833"), payload, token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt) {
+		return;
+	}
+	if (pvt->rtp) {
+		ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, payload, "audio", (is_cisco ? "cisco-telephone-event" : "telephone-event"), 0);
+	}
+	pvt->dtmf_pt[is_cisco ? 1 : 0] = payload;
+	ast_mutex_unlock(&pvt->lock);
+	if (h323debug)
+		ast_debug(1, "DTMF payload on %s set to %d\n", token, payload);
+}
+
+static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities, struct ast_codec_pref *prefs)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Got remote capabilities from connection %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	pvt->peercapability = capabilities;
+	pvt->jointcapability = pvt->options.capability & capabilities;
+	if (prefs) {
+		memcpy(&pvt->peer_prefs, prefs, sizeof(pvt->peer_prefs));
+		if (h323debug) {
+			int i;
+			for (i = 0; i < 32; ++i) {
+				if (!prefs->order[i])
+					break;
+				ast_debug(1, "prefs[%d]=%s:%d\n", i, (prefs->order[i] ? ast_getformatname(&prefs->formats[i]) : "<none>"), prefs->framing[i]);
+			}
+		}
+		if (pvt->rtp) {
+			if (pvt->options.autoframing) {
+				ast_debug(2, "Autoframing option set, using peer's packetization settings\n");
+				ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs);
+			} else {
+				ast_debug(2, "Autoframing option not set, ignoring peer's packetization settings\n");
+				ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->options.prefs);
+			}
+		}
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
+static void set_local_capabilities(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+	int capability, dtmfmode, pref_codec;
+	struct ast_codec_pref prefs;
+
+	if (h323debug)
+		ast_debug(1, "Setting capabilities for connection %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability;
+	dtmfmode = pvt->options.dtmfmode;
+	prefs = pvt->options.prefs;
+	pref_codec = pvt->pref_codec;
+	ast_mutex_unlock(&pvt->lock);
+	h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec);
+
+	if (h323debug) {
+		int i;
+		for (i = 0; i < 32; i++) {
+			if (!prefs.order[i])
+				break;
+			ast_debug(1, "local prefs[%d]=%s:%d\n", i, (prefs.order[i] ? ast_getformatname(&prefs.formats[i]) : "<none>"), prefs.framing[i]);
+		}
+		ast_debug(1, "Capabilities for connection %s is set\n", token);
+	}
+}
+
+static void remote_hold(unsigned call_reference, const char *token, int is_hold)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_debug(1, "Setting %shold status for connection %s\n", (is_hold ? "" : "un"), token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		if (is_hold)
+			ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+		else
+			ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+		ast_channel_unlock(pvt->owner);
+	}
+	else {
+		if (is_hold)
+			pvt->newcontrol = AST_CONTROL_HOLD;
+		else
+			pvt->newcontrol = AST_CONTROL_UNHOLD;
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
+static void *do_monitor(void *data)
+{
+	int res;
+	int reloading;
+	struct oh323_pvt *oh323 = NULL;
+
+	for(;;) {
+		/* Check for a reload request */
+		ast_mutex_lock(&h323_reload_lock);
+		reloading = h323_reloading;
+		h323_reloading = 0;
+		ast_mutex_unlock(&h323_reload_lock);
+		if (reloading) {
+			ast_verb(1, "Reloading H.323\n");
+			h323_do_reload();
+		}
+		/* Check for interfaces needing to be killed */
+		if (!ast_mutex_trylock(&iflock)) {
+#if 1
+			do {
+				for (oh323 = iflist; oh323; oh323 = oh323->next) {
+					if (!ast_mutex_trylock(&oh323->lock)) {
+						if (oh323->needdestroy) {
+							__oh323_destroy(oh323);
+							break;
+						}
+						ast_mutex_unlock(&oh323->lock);
+					}
+				}
+			} while (/*oh323*/ 0);
+#else
+restartsearch:
+			oh323 = iflist;
+			while(oh323) {
+				if (!ast_mutex_trylock(&oh323->lock)) {
+					if (oh323->needdestroy) {
+						__oh323_destroy(oh323);
+						goto restartsearch;
+					}
+					ast_mutex_unlock(&oh323->lock);
+					oh323 = oh323->next;
+				}
+			}
+#endif
+			ast_mutex_unlock(&iflock);
+		} else
+			oh323 = (struct oh323_pvt *)1;	/* Force fast loop */
+		pthread_testcancel();
+		/* Wait for sched or io */
+		res = ast_sched_wait(sched);
+		if ((res < 0) || (res > 1000)) {
+			res = 1000;
+		}
+		/* Do not wait if some channel(s) is destroyed, probably, more available too */
+		if (oh323)
+			res = 1;
+		res = ast_io_wait(io, res);
+		pthread_testcancel();
+		ast_mutex_lock(&monlock);
+		if (res >= 0) {
+			ast_sched_runq(sched);
+		}
+		ast_mutex_unlock(&monlock);
+	}
+	/* Never reached */
+	return NULL;
+}
+
+static int restart_monitor(void)
+{
+	/* If we're supposed to be stopped -- stay stopped */
+	if (ast_mutex_lock(&monlock)) {
+		ast_log(LOG_WARNING, "Unable to lock monitor\n");
+		return -1;
+	}
+	if (monitor_thread == AST_PTHREADT_STOP) {
+		ast_mutex_unlock(&monlock);
+		return 0;
+	}
+	if (monitor_thread == pthread_self()) {
+		ast_mutex_unlock(&monlock);
+		ast_log(LOG_WARNING, "Cannot kill myself\n");
+		return -1;
+	}
+	if (monitor_thread && (monitor_thread != AST_PTHREADT_NULL)) {
+		/* Wake up the thread */
+		pthread_kill(monitor_thread, SIGURG);
+	} else {
+		/* Start a new monitor */
+		if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
+			monitor_thread = AST_PTHREADT_NULL;
+			ast_mutex_unlock(&monlock);
+			ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
+			return -1;
+		}
+	}
+	ast_mutex_unlock(&monlock);
+	return 0;
+}
+
+static char *handle_cli_h323_set_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 set trace [on|off]";
+		e->usage =
+			"Usage: h323 set trace (on|off|<trace level>)\n"
+			"       Enable/Disable H.323 stack tracing for debugging purposes\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != e->args)
+		return CLI_SHOWUSAGE;
+	if (!strcasecmp(a->argv[3], "off")) {
+		h323_debug(0, 0);
+		ast_cli(a->fd, "H.323 Trace Disabled\n");
+	} else if (!strcasecmp(a->argv[3], "on")) {
+		h323_debug(1, 1);
+		ast_cli(a->fd, "H.323 Trace Enabled\n");
+	} else {
+		int tracelevel = atoi(a->argv[3]);
+		h323_debug(1, tracelevel);
+		ast_cli(a->fd, "H.323 Trace Enabled (Trace Level: %d)\n", tracelevel);
+	}
+	return CLI_SUCCESS;
+}
+
+static char *handle_cli_h323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 set debug [on|off]";
+		e->usage =
+			"Usage: h323 set debug [on|off]\n"
+			"       Enable/Disable H.323 debugging output\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != e->args)
+		return CLI_SHOWUSAGE;
+	if (strcasecmp(a->argv[3], "on") && strcasecmp(a->argv[3], "off"))
+		return CLI_SHOWUSAGE;
+
+	h323debug = (strcasecmp(a->argv[3], "on")) ? 0 : 1;
+	ast_cli(a->fd, "H.323 Debugging %s\n", h323debug ? "Enabled" : "Disabled");
+	return CLI_SUCCESS;
+}
+
+static char *handle_cli_h323_cycle_gk(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 cycle gk";
+		e->usage =
+			"Usage: h323 cycle gk\n"
+			"       Manually re-register with the Gatekeper (Currently Disabled)\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	h323_gk_urq();
+
+	/* Possibly register with a GK */
+	if (!gatekeeper_disable) {
+		if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
+			ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
+		}
+	}
+	return CLI_SUCCESS;
+}
+
+static char *handle_cli_h323_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 hangup";
+		e->usage =
+			"Usage: h323 hangup <token>\n"
+			"       Manually try to hang up the call identified by <token>\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+	if (h323_soft_hangup(a->argv[2])) {
+		ast_verb(3, "Hangup succeeded on %s\n", a->argv[2]);
+	} else {
+		ast_verb(3, "Hangup failed for %s\n", a->argv[2]);
+	}
+	return CLI_SUCCESS;
+}
+
+static char *handle_cli_h323_show_tokens(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 show tokens";
+		e->usage =
+			"Usage: h323 show tokens\n"
+			"       Print out all active call tokens\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	h323_show_tokens();
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_cli_h323_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 show version";
+		e->usage =
+			"Usage: h323 show version\n"
+			"		Show the version of the H.323 library in use\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	h323_show_version();
+	
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_h323[] = {
+	AST_CLI_DEFINE(handle_cli_h323_set_trace,    "Enable/Disable H.323 Stack Tracing"),
+	AST_CLI_DEFINE(handle_cli_h323_set_debug,    "Enable/Disable H.323 Debugging"),
+	AST_CLI_DEFINE(handle_cli_h323_cycle_gk,     "Manually re-register with the Gatekeper"),
+	AST_CLI_DEFINE(handle_cli_h323_hangup,       "Manually try to hang up a call"),
+	AST_CLI_DEFINE(handle_cli_h323_show_tokens,  "Show all active call tokens"),
+	AST_CLI_DEFINE(handle_cli_h323_show_version, "Show the version of the H.323 library in use"),
+};
+
+static void delete_users(void)
+{
+	int pruned = 0;
+
+	/* Delete all users */
+	ASTOBJ_CONTAINER_WRLOCK(&userl);
+	ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		++pruned;
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	if (pruned) {
+		ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, oh323_destroy_user);
+	}
+	ASTOBJ_CONTAINER_UNLOCK(&userl);
+
+	ASTOBJ_CONTAINER_WRLOCK(&peerl);
+	ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	ASTOBJ_CONTAINER_UNLOCK(&peerl);
+}
+
+static void delete_aliases(void)
+{
+	int pruned = 0;
+
+	/* Delete all aliases */
+	ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+	ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		++pruned;
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	if (pruned) {
+		ASTOBJ_CONTAINER_PRUNE_MARKED(&aliasl, oh323_destroy_alias);
+	}
+	ASTOBJ_CONTAINER_UNLOCK(&aliasl);
+}
+
+static void prune_peers(void)
+{
+	/* Prune peers who still are supposed to be deleted */
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, oh323_destroy_peer);
+}
+
+static int reload_config(int is_reload)
+{
+	struct ast_config *cfg, *ucfg;
+	struct ast_variable *v;
+	struct oh323_peer *peer = NULL;
+	struct oh323_user *user = NULL;
+	struct oh323_alias *alias = NULL;
+	struct ast_hostent ahp; struct hostent *hp;
+	char *cat;
+	const char *utype;
+	int is_user, is_peer, is_alias;
+	char _gatekeeper[100];
+	int gk_discover, gk_disable, gk_changed;
+	struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+	cfg = ast_config_load(config, config_flags);
+
+	/* We *must* have a config file otherwise stop immediately */
+	if (!cfg) {
+		ast_log(LOG_NOTICE, "Unable to load config %s, H.323 disabled\n", config);
+		return 1;
+	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+		ucfg = ast_config_load("users.conf", config_flags);
+		if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
+			return 0;
+		} else if (ucfg == CONFIG_STATUS_FILEINVALID) {
+			ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
+			return 0;
+		}
+		ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+		if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) {
+			ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
+			ast_config_destroy(ucfg);
+			return 0;
+		}
+	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
+		return 0;
+	} else {
+		ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+		if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
+			ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
+			ast_config_destroy(cfg);
+			return 0;
+		}
+	}
+
+	if (is_reload) {
+		delete_users();
+		delete_aliases();
+		prune_peers();
+	}
+
+	/* fire up the H.323 Endpoint */
+	if (!h323_end_point_exist()) {
+		h323_end_point_create();
+	}
+	ast_copy_string(_gatekeeper, gatekeeper, sizeof(_gatekeeper));
+	gk_discover = gatekeeper_discover;
+	gk_disable = gatekeeper_disable;
+	memset(&bindaddr, 0, sizeof(bindaddr));
+	memset(&global_options, 0, sizeof(global_options));
+	global_options.fastStart = 1;
+	global_options.h245Tunneling = 1;
+	global_options.dtmfcodec[0] = H323_DTMF_RFC2833_PT;
+	global_options.dtmfcodec[1] = H323_DTMF_CISCO_PT;
+	global_options.dtmfmode = 0;
+	global_options.holdHandling = 0;
+	global_options.capability = GLOBAL_CAPABILITY;
+	global_options.bridge = 1;		/* Do native bridging by default */
+	global_options.autoframing = 0;
+	strcpy(default_context, "default");
+	h323_signalling_port = 1720;
+	gatekeeper_disable = 1;
+	gatekeeper_discover = 0;
+	gkroute = 0;
+	userbyalias = 1;
+	acceptAnonymous = 1;
+	tos = 0;
+	cos = 0;
+
+	/* Copy the default jb config over global_jbconf */
+	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+
+	if (ucfg) {
+		struct ast_variable *gen;
+		int genhas_h323;
+		const char *has_h323;
+
+		genhas_h323 = ast_true(ast_variable_retrieve(ucfg, "general", "hash323"));
+		gen = ast_variable_browse(ucfg, "general");
+		for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) {
+			if (strcasecmp(cat, "general")) {
+				has_h323 = ast_variable_retrieve(ucfg, cat, "hash323");
+				if (ast_true(has_h323) || (!has_h323 && genhas_h323)) {
+					user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
+					if (user) {
+						ASTOBJ_CONTAINER_LINK(&userl, user);
+						ASTOBJ_UNREF(user, oh323_destroy_user);
+					}
+					peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
+					if (peer) {
+						ASTOBJ_CONTAINER_LINK(&peerl, peer);
+						ASTOBJ_UNREF(peer, oh323_destroy_peer);
+					}
+				}
+			}
+		}
+		ast_config_destroy(ucfg);
+	}
+
+	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+		/* handle jb conf */
+		if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
+			continue;
+		/* Create the interface list */
+		if (!strcasecmp(v->name, "port")) {
+			h323_signalling_port = (int)strtol(v->value, NULL, 10);
+		} else if (!strcasecmp(v->name, "bindaddr")) {
+			if (!(hp = ast_gethostbyname(v->value, &ahp))) {
+				ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
+			} else {
+				memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
+			}
+		} else if (!strcasecmp(v->name, "tos")) {	/* Needs to be removed in next release */
+			ast_log(LOG_WARNING, "The \"tos\" setting is deprecated in this version of Asterisk. Please change to \"tos_audio\".\n");
+			if (ast_str2tos(v->value, &tos)) {
+				ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);			
+			}
+		} else if (!strcasecmp(v->name, "tos_audio")) {
+			if (ast_str2tos(v->value, &tos)) {
+				ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);			
+			}
+		} else if (!strcasecmp(v->name, "cos")) {
+			ast_log(LOG_WARNING, "The \"cos\" setting is deprecated in this version of Asterisk. Please change to \"cos_audio\".\n");
+			if (ast_str2cos(v->value, &cos)) {
+				ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);			
+			}
+		} else if (!strcasecmp(v->name, "cos_audio")) {
+			if (ast_str2cos(v->value, &cos)) {
+				ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);			
+			}
+		} else if (!strcasecmp(v->name, "gatekeeper")) {
+			if (!strcasecmp(v->value, "DISABLE")) {
+				gatekeeper_disable = 1;
+			} else if (!strcasecmp(v->value, "DISCOVER")) {
+				gatekeeper_disable = 0;
+				gatekeeper_discover = 1;
+			} else {
+				gatekeeper_disable = 0;
+				ast_copy_string(gatekeeper, v->value, sizeof(gatekeeper));
+			}
+		} else if (!strcasecmp(v->name, "secret")) {
+			ast_copy_string(secret, v->value, sizeof(secret));
+		} else if (!strcasecmp(v->name, "AllowGKRouted")) {
+			gkroute = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "context")) {
+			ast_copy_string(default_context, v->value, sizeof(default_context));
+			ast_verb(2, "Setting default context to %s\n", default_context);
+		} else if (!strcasecmp(v->name, "UserByAlias")) {
+			userbyalias = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "AcceptAnonymous")) {
+			acceptAnonymous = ast_true(v->value);
+		} else if (!update_common_options(v, &global_options)) {
+			/* dummy */
+		}
+	}
+	if (!global_options.dtmfmode)
+		global_options.dtmfmode = H323_DTMF_RFC2833;
+	if (global_options.holdHandling == ~0)
+		global_options.holdHandling = 0;
+	else if (!global_options.holdHandling)
+		global_options.holdHandling = H323_HOLD_H450;
+
+	for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
+		if (strcasecmp(cat, "general")) {
+			utype = ast_variable_retrieve(cfg, cat, "type");
+			if (utype) {
+				is_user = is_peer = is_alias = 0;
+				if (!strcasecmp(utype, "user"))
+					is_user = 1;
+				else if (!strcasecmp(utype, "peer"))
+					is_peer = 1;
+				else if (!strcasecmp(utype, "friend"))
+					is_user = is_peer = 1;
+				else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias"))
+					is_alias = 1;
+				else {
+					ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
+					continue;
+				}
+				if (is_user) {
+					user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
+					if (user) {
+						ASTOBJ_CONTAINER_LINK(&userl, user);
+						ASTOBJ_UNREF(user, oh323_destroy_user);
+					}
+				}
+				if (is_peer) {
+					peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
+					if (peer) {
+						ASTOBJ_CONTAINER_LINK(&peerl, peer);
+						ASTOBJ_UNREF(peer, oh323_destroy_peer);
+					}
+				}
+				if (is_alias) {
+					alias = build_alias(cat, ast_variable_browse(cfg, cat), NULL, 0);
+					if (alias) {
+						ASTOBJ_CONTAINER_LINK(&aliasl, alias);
+						ASTOBJ_UNREF(alias, oh323_destroy_alias);
+					}
+				}
+			} else {
+				ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
+			}
+		}
+	}
+	ast_config_destroy(cfg);
+
+	/* Register our H.323 aliases if any*/
+	ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+	ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		if (h323_set_alias(iterator)) {
+			ast_log(LOG_ERROR, "Alias %s rejected by endpoint\n", alias->name);
+			ASTOBJ_UNLOCK(iterator);
+			continue;
+		}
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	ASTOBJ_CONTAINER_UNLOCK(&aliasl);
+
+	/* Don't touch GK if nothing changed because URQ will drop all existing calls */
+	gk_changed = 0;
+	if (gatekeeper_disable != gk_disable)
+		gk_changed = is_reload;
+	else if(!gatekeeper_disable && (gatekeeper_discover != gk_discover))
+		gk_changed = is_reload;
+	else if(!gatekeeper_disable && (strncmp(_gatekeeper, gatekeeper, sizeof(_gatekeeper)) != 0))
+		gk_changed = is_reload;
+	if (gk_changed) {
+		if(!gk_disable)
+			h323_gk_urq();
+		if (!gatekeeper_disable) {
+			if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
+				ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
+				gatekeeper_disable = 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int h323_reload(void)
+{
+	ast_mutex_lock(&h323_reload_lock);
+	if (h323_reloading) {
+		ast_verbose("Previous H.323 reload not yet done\n");
+	} else {
+		h323_reloading = 1;
+	}
+	ast_mutex_unlock(&h323_reload_lock);
+	restart_monitor();
+	return 0;
+}
+
+static char *handle_cli_h323_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "h323 reload";
+		e->usage =
+			"Usage: h323 reload\n"
+			"       Reloads H.323 configuration from h323.conf\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 2)
+		return CLI_SHOWUSAGE;
+
+	h323_reload();
+
+	return CLI_SUCCESS;
+}
+
+static int h323_do_reload(void)
+{
+	reload_config(1);
+	return 0;
+}
+
+static int reload(void)
+{
+	if (!sched || !io) {
+		ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n");
+		return 0;
+	}
+	return h323_reload();
+}
+
+static struct ast_cli_entry cli_h323_reload =
+	AST_CLI_DEFINE(handle_cli_h323_reload, "Reload H.323 configuration");
+
+static enum ast_rtp_glue_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+{
+	struct oh323_pvt *pvt;
+	enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
+
+	if (!(pvt = (struct oh323_pvt *)ast_channel_tech_pvt(chan)))
+		return AST_RTP_GLUE_RESULT_FORBID;
+
+	ast_mutex_lock(&pvt->lock);
+	*instance = pvt->rtp ? ao2_ref(pvt->rtp, +1), pvt->rtp : NULL;
+#if 0
+	if (pvt->options.bridge) {
+		res = AST_RTP_GLUE_RESULT_REMOTE;
+	}
+#endif
+	ast_mutex_unlock(&pvt->lock);
+
+	return res;
+}
+
+#if 0
+static char *convertcap(struct ast_format *format)
+{
+	switch (format->id) {
+	case AST_FORMAT_G723_1:
+		return "G.723";
+	case AST_FORMAT_GSM:
+		return "GSM";
+	case AST_FORMAT_ULAW:
+		return "ULAW";
+	case AST_FORMAT_ALAW:
+		return "ALAW";
+	case AST_FORMAT_G722:
+		return "G.722";
+	case AST_FORMAT_ADPCM:
+		return "G.728";
+	case AST_FORMAT_G729A:
+		return "G.729";
+	case AST_FORMAT_SPEEX:
+		return "SPEEX";
+	case AST_FORMAT_ILBC:
+		return "ILBC";
+	default:
+		ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_getformatname(format));
+		return NULL;
+	}
+}
+#endif
+
+static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active)
+{
+	/* XXX Deal with Video */
+	struct oh323_pvt *pvt;
+	struct sockaddr_in them = { 0, };
+	struct sockaddr_in us = { 0, };
+#if 0	/* Native bridge still isn't ready */
+	char *mode;
+#endif
+
+	if (!rtp) {
+		return 0;
+	}
+
+#if 0	/* Native bridge still isn't ready */
+	mode = convertcap(&chan->writeformat);
+#endif
+
+	pvt = (struct oh323_pvt *) ast_channel_tech_pvt(chan);
+	if (!pvt) {
+		ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
+		return -1;
+	}
+	{
+		struct ast_sockaddr tmp;
+
+		ast_rtp_instance_get_remote_address(rtp, &tmp);
+		ast_sockaddr_to_sin(&tmp, &them);
+		ast_rtp_instance_get_local_address(rtp, &tmp);
+		ast_sockaddr_to_sin(&tmp, &us);
+	}
+#if 0	/* Native bridge still isn't ready */
+	h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode);
+#endif
+	return 0;
+}
+
+static struct ast_rtp_glue oh323_rtp_glue = {
+	.type = "H323",
+	.get_rtp_info = oh323_get_rtp_peer,
+	.update_peer = oh323_set_rtp_peer,
+};
+
+static enum ast_module_load_result load_module(void)
+{
+	int res;
+
+	if (!(oh323_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_format_cap_add_all_by_type(oh323_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
+
+	h323debug = 0;
+	sched = ast_sched_context_create();
+	if (!sched) {
+		ast_log(LOG_WARNING, "Unable to create schedule context\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	io = io_context_create();
+	if (!io) {
+		ast_log(LOG_WARNING, "Unable to create I/O context\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_cli_register(&cli_h323_reload);
+	ASTOBJ_CONTAINER_INIT(&userl);
+	ASTOBJ_CONTAINER_INIT(&peerl);
+	ASTOBJ_CONTAINER_INIT(&aliasl);
+	res = reload_config(0);
+	if (res) {
+		/* No config entry */
+		ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n");
+		ast_cli_unregister(&cli_h323_reload);
+		io_context_destroy(io);
+		io = NULL;
+		ast_sched_context_destroy(sched);
+		sched = NULL;
+		ASTOBJ_CONTAINER_DESTROY(&userl);
+		ASTOBJ_CONTAINER_DESTROY(&peerl);
+		ASTOBJ_CONTAINER_DESTROY(&aliasl);
+		return AST_MODULE_LOAD_DECLINE;
+	} else {
+		/* Make sure we can register our channel type */
+		if (ast_channel_register(&oh323_tech)) {
+			ast_log(LOG_ERROR, "Unable to register channel class 'H323'\n");
+			ast_cli_unregister(&cli_h323_reload);
+			h323_end_process();
+			io_context_destroy(io);
+			ast_sched_context_destroy(sched);
+
+			ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+			ASTOBJ_CONTAINER_DESTROY(&userl);
+			ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+			ASTOBJ_CONTAINER_DESTROY(&peerl);
+			ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+			ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+			return AST_MODULE_LOAD_FAILURE;
+		}
+		ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+
+		ast_rtp_glue_register(&oh323_rtp_glue);
+
+		/* Register our callback functions */
+		h323_callback_register(setup_incoming_call,
+						setup_outgoing_call,
+						external_rtp_create,
+						setup_rtp_connection,
+						cleanup_connection,
+						chan_ringing,
+						connection_made,
+						receive_digit,
+						answer_call,
+						progress,
+						set_dtmf_payload,
+						hangup_connection,
+						set_local_capabilities,
+						set_peer_capabilities,
+						remote_hold);
+		/* start the h.323 listener */
+		if (h323_start_listener(h323_signalling_port, bindaddr)) {
+			ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
+			ast_rtp_glue_unregister(&oh323_rtp_glue);
+			ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+			ast_cli_unregister(&cli_h323_reload);
+			h323_end_process();
+			io_context_destroy(io);
+			ast_sched_context_destroy(sched);
+
+			ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+			ASTOBJ_CONTAINER_DESTROY(&userl);
+			ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+			ASTOBJ_CONTAINER_DESTROY(&peerl);
+			ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+			ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+			return AST_MODULE_LOAD_DECLINE;
+		}
+		/* Possibly register with a GK */
+		if (!gatekeeper_disable) {
+			if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
+				ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
+				gatekeeper_disable = 1;
+				res = AST_MODULE_LOAD_SUCCESS;
+			}
+		}
+		/* And start the monitor for the first time */
+		restart_monitor();
+	}
+	return res;
+}
+
+static int unload_module(void)
+{
+	struct oh323_pvt *p, *pl;
+
+	/* unregister commands */
+	ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+	ast_cli_unregister(&cli_h323_reload);
+
+	ast_channel_unregister(&oh323_tech);
+	ast_rtp_glue_unregister(&oh323_rtp_glue);
+
+	if (!ast_mutex_lock(&iflock)) {
+		/* hangup all interfaces if they have an owner */
+		p = iflist;
+		while(p) {
+			if (p->owner) {
+				ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+			}
+			p = p->next;
+		}
+		iflist = NULL;
+		ast_mutex_unlock(&iflock);
+	} else {
+		ast_log(LOG_WARNING, "Unable to lock the interface list\n");
+		return -1;
+	}
+	if (!ast_mutex_lock(&monlock)) {
+		if ((monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
+			if (monitor_thread != pthread_self()) {
+				pthread_cancel(monitor_thread);
+			}
+			pthread_kill(monitor_thread, SIGURG);
+			pthread_join(monitor_thread, NULL);
+		}
+		monitor_thread = AST_PTHREADT_STOP;
+		ast_mutex_unlock(&monlock);
+	} else {
+		ast_log(LOG_WARNING, "Unable to lock the monitor\n");
+		return -1;
+	}
+	if (!ast_mutex_lock(&iflock)) {
+		/* destroy all the interfaces and free their memory */
+		p = iflist;
+		while(p) {
+			pl = p;
+			p = p->next;
+			/* free associated memory */
+			ast_mutex_destroy(&pl->lock);
+			ast_free(pl);
+		}
+		iflist = NULL;
+		ast_mutex_unlock(&iflock);
+	} else {
+		ast_log(LOG_WARNING, "Unable to lock the interface list\n");
+		return -1;
+	}
+	if (!gatekeeper_disable)
+		h323_gk_urq();
+	h323_end_process();
+	if (io)
+		io_context_destroy(io);
+	if (sched)
+		ast_sched_context_destroy(sched);
+
+	ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+	ASTOBJ_CONTAINER_DESTROY(&userl);
+	ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+	ASTOBJ_CONTAINER_DESTROY(&peerl);
+	ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+	ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+	oh323_tech.capabilities = ast_format_cap_destroy(oh323_tech.capabilities);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "The NuFone Network's OpenH323 Channel Driver",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+);
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index aa76b75..f6708c6 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -27,30 +27,10 @@
  * \arg \ref Config_iax
  *
  * \ingroup channel_drivers
- *
+ * 
  * \todo Implement musicclass settings for IAX2 devices
  */
 
-/*! \li \ref chan_iax2.c uses the configuration file \ref iax.conf
- * \addtogroup configuration_file
- */
-
-/*! \page iax.conf iax.conf
- * \verbinclude iax.conf.sample
- */
-
-/*!
- * \todo XXX The IAX2 channel driver needs its native bridge
- * code converted to the new bridge technology scheme.
- *
- * \note The chan_dahdi native bridge code can be used as an
- * example.  It also appears that chan_iax2 also has a native
- * transfer check like chan_dahdi to eliminate tromboned calls.
- *
- * \note The existing native bridge code is marked with the
- * IAX2_NATIVE_BRIDGING conditional.
- */
-
 /*** MODULEINFO
 	<use type="external">crypto</use>
 	<support_level>core</support_level>
@@ -58,7 +38,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/mman.h>
 #include <dirent.h>
@@ -76,10 +56,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include <sys/stat.h>
 #include <regex.h>
 
-#include "asterisk/paths.h"
+#include "asterisk/paths.h"	/* need ast_config_AST_DATA_DIR for firmware */
 
 #include "asterisk/lock.h"
-#include "asterisk/frame.h"
+#include "asterisk/frame.h" 
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
@@ -89,6 +69,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/cli.h"
 #include "asterisk/translate.h"
 #include "asterisk/md5.h"
+#include "asterisk/cdr.h"
 #include "asterisk/crypto.h"
 #include "asterisk/acl.h"
 #include "asterisk/manager.h"
@@ -105,28 +86,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/netsock.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/event.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/timing.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/test.h"
 #include "asterisk/data.h"
-#include "asterisk/security_events.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_system.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_compatibility.h"
-#include "asterisk/format_cap.h"
-
-#include "iax2/include/iax2.h"
-#include "iax2/include/firmware.h"
-#include "iax2/include/parser.h"
-#include "iax2/include/provision.h"
-#include "iax2/include/codec_pref.h"
-#include "iax2/include/format_compatibility.h"
+#include "asterisk/netsock2.h"
 
+#include "iax2.h"
+#include "iax2-parser.h"
+#include "iax2-provision.h"
 #include "jitterbuf.h"
 
 /*** DOCUMENTATION
@@ -285,7 +255,7 @@ static int nochecksums = 0;
 /* Sample over last 100 units to determine historic jitter */
 #define GAMMA (0.01)
 
-static struct iax2_codec_pref prefs_global;
+static struct ast_codec_pref prefs;
 
 static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";
 
@@ -304,9 +274,9 @@ static char default_parkinglot[AST_MAX_CONTEXT];
 static char language[MAX_LANGUAGE] = "";
 static char regcontext[AST_MAX_CONTEXT] = "";
 
-static struct stasis_subscription *network_change_sub; /*!< subscription id for network change events */
-static struct stasis_subscription *acl_change_sub; /*!< subscription id for ACL change events */
-static int network_change_sched_id = -1;
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static struct ast_event_sub *acl_change_event_subscription; /*!< subscription id for ACL change events */
+static int network_change_event_sched_id = -1;
 
 static int maxauthreq = 3;
 static int max_retries = 4;
@@ -353,22 +323,22 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 #define IAX_CAPABILITY_FULLBANDWIDTH	0xFFFF
 /* T1, maybe ISDN */
 #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
-                     ~AST_FORMAT_SLIN &      \
-                     ~AST_FORMAT_SLIN16 &    \
-                     ~AST_FORMAT_SIREN7 &       \
-                     ~AST_FORMAT_SIREN14 &      \
-                     ~AST_FORMAT_G719 &         \
-                     ~AST_FORMAT_ULAW &         \
-                     ~AST_FORMAT_ALAW &         \
-                     ~AST_FORMAT_G722)
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR) &      \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR16) &    \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN7) &       \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN14) &      \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G719) &         \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) &         \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) &         \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G722))
 /* A modem */
 #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
-                     ~AST_FORMAT_G726 &         \
-                     ~AST_FORMAT_G726_AAL2 &    \
-                     ~AST_FORMAT_ADPCM)
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726) &         \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) &    \
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ADPCM))
 
 #define IAX_CAPABILITY_LOWFREE      (IAX_CAPABILITY_LOWBANDWIDTH & \
-                     ~AST_FORMAT_G723)
+                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G723_1))
 
 
 #define DEFAULT_MAXMS		2000		/* Must be faster than 2 seconds by default */
@@ -387,7 +357,7 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 			break; \
 		\
 		for (idx = 0; idx < 16; idx++) \
-			sprintf(digest + (idx << 1), "%2.2x", (unsigned) key[idx]); \
+			sprintf(digest + (idx << 1), "%02hhx", (unsigned char) key[idx]); \
 		\
 		ast_log(LOG_NOTICE, msg " IAX_COMMAND_RTKEY to rotate key to '%s'\n", digest); \
 	} while(0)
@@ -509,7 +479,7 @@ struct iax2_user {
 	iax2_format capability;
 	int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */
 	int curauthreq; /*!< Current number of outstanding AUTHREQs */
-	struct iax2_codec_pref prefs;
+	struct ast_codec_pref prefs;
 	struct ast_acl_list *acl;
 	struct iax2_context *contexts;
 	struct ast_variable *vars;
@@ -538,23 +508,23 @@ struct iax2_peer {
 		AST_STRING_FIELD(zonetag);		/*!< Time Zone */
 		AST_STRING_FIELD(parkinglot);   /*!< Default parkinglot for device */
 	);
-	struct iax2_codec_pref prefs;
+	struct ast_codec_pref prefs;
 	struct ast_dnsmgr_entry *dnsmgr;		/*!< DNS refresh manager */
 	struct ast_sockaddr addr;
 	int formats;
 	int sockfd;					/*!< Socket to use for transmission */
-	struct ast_sockaddr mask;
+	struct in_addr mask;
 	int adsi;
 	uint64_t flags;
 
 	/* Dynamic Registration fields */
-	struct ast_sockaddr defaddr;			/*!< Default address if there is one */
+	struct sockaddr_in defaddr;			/*!< Default address if there is one */
 	int authmethods;				/*!< Authentication methods (IAX_AUTH_*) */
 	int encmethods;					/*!< Encryption methods (IAX_ENCRYPT_*) */
 
 	int expire;					/*!< Schedule entry for expiry */
 	int expiry;					/*!< How soon to expire */
-	iax2_format capability;				/*!< Capability */
+	iax2_format capability;        /*!< Capability */
 
 	/* Qualification */
 	int callno;					/*!< Call number of POKE request */
@@ -566,14 +536,12 @@ struct iax2_peer {
 	int pokefreqnotok;				/*!< How often to check when the host has been determined to be down */
 	int historicms;					/*!< How long recent average responses took */
 	int smoothing;					/*!< Sample over how many units to determine historic ms */
-	uint16_t maxcallno;				/*!< Max call number limit for this peer.  Set on registration */
+	uint16_t maxcallno;					/*!< Max call number limit for this peer.  Set on registration */
 
-	struct stasis_subscription *mwi_event_sub;	/*!< This subscription lets pollmailboxes know which mailboxes need to be polled */
+	struct ast_event_sub *mwi_event_sub;
 
 	struct ast_acl_list *acl;
-	enum calltoken_peer_enum calltoken_required;	/*!< Is calltoken validation required or not, can be YES, NO, or AUTO */
-
-	struct ast_endpoint *endpoint; /*!< Endpoint structure for this peer */
+	enum calltoken_peer_enum calltoken_required;        /*!< Is calltoken validation required or not, can be YES, NO, or AUTO */
 };
 
 #define IAX2_TRUNK_PREFACE (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
@@ -581,7 +549,7 @@ struct iax2_peer {
 struct iax2_trunk_peer {
 	ast_mutex_t lock;
 	int sockfd;
-	struct ast_sockaddr addr;
+	struct sockaddr_in addr;
 	struct timeval txtrunktime;		/*!< Transmit trunktime */
 	struct timeval rxtrunktime;		/*!< Receive trunktime */
 	struct timeval lasttxtime;		/*!< Last transmitted trunktime */
@@ -599,6 +567,15 @@ struct iax2_trunk_peer {
 
 static AST_LIST_HEAD_STATIC(tpeers, iax2_trunk_peer);
 
+struct iax_firmware {
+	AST_LIST_ENTRY(iax_firmware) list;
+	int fd;
+	int mmaplen;
+	int dead;
+	struct ast_iax2_firmware_header *fwh;
+	unsigned char *buf;
+};
+
 enum iax_reg_state {
 	REG_STATE_UNREGISTERED = 0,
 	REG_STATE_REGSENT,
@@ -632,7 +609,7 @@ struct iax2_registry {
 	enum iax_reg_state regstate;
 	int messages;				/*!< Message count, low 8 bits = new, high 8 bits = old */
 	int callno;				/*!< Associated call number if applicable */
-	struct ast_sockaddr us;			/*!< Who the server thinks we are */
+	struct sockaddr_in us;			/*!< Who the server thinks we are */
 	struct ast_dnsmgr_entry *dnsmgr;	/*!< DNS refresh manager */
 	AST_LIST_ENTRY(iax2_registry) entry;
 	int port;
@@ -676,10 +653,6 @@ struct iax_rr {
 
 struct iax2_pvt_ref;
 
-/* We use the high order bit as the validated flag, and the lower 15 as the
- * actual call number */
-typedef uint16_t callno_entry;
-
 struct chan_iax2_pvt {
 	/*! Socket to send/receive on for this call */
 	int sockfd;
@@ -714,15 +687,15 @@ struct chan_iax2_pvt {
 	/*! Max time for initial response */
 	int maxtime;
 	/*! Peer Address */
-	struct ast_sockaddr addr;
+	struct sockaddr_in addr;
 	/*! Actual used codec preferences */
-	struct iax2_codec_pref prefs;
+	struct ast_codec_pref prefs;
 	/*! Requested codec preferences */
-	struct iax2_codec_pref rprefs;
+	struct ast_codec_pref rprefs;
 	/*! Our call number */
 	unsigned short callno;
 	/*! Our callno_entry entry */
-	callno_entry callno_entry;
+	struct callno_entry *callno_entry;
 	/*! Peer callno */
 	unsigned short peercallno;
 	/*! Negotiated format, this is only used to remember what format was
@@ -812,7 +785,7 @@ struct chan_iax2_pvt {
 	ast_aes_decrypt_key mydcx;
 	/*! Decryption AES-128 Key used to decrypt peer frames */
 	ast_aes_decrypt_key dcx;
-	/*! scheduler id associated with iax_key_rotate
+	/*! scheduler id associated with iax_key_rotate 
 	 * for encrypted calls*/
 	int keyrotateid;
 	/*! 32 bytes of semi-random data */
@@ -830,7 +803,7 @@ struct chan_iax2_pvt {
 	/*! Transfer identifier */
 	int transferid;
 	/*! Who we are IAX transferring to */
-	struct ast_sockaddr transfer;
+	struct sockaddr_in transfer;
 	/*! What's the new call number for the transfer */
 	unsigned short transfercallno;
 	/*! Transfer encrypt AES-128 Key */
@@ -878,31 +851,13 @@ struct signaling_queue_entry {
 	AST_LIST_ENTRY(signaling_queue_entry) next;
 };
 
-enum callno_type {
-	CALLNO_TYPE_NORMAL,
-	CALLNO_TYPE_TRUNK,
-};
-
-#define PTR_TO_CALLNO_ENTRY(a) ((uint16_t)(unsigned long)(a))
-#define CALLNO_ENTRY_TO_PTR(a) ((void *)(unsigned long)(a))
-
-#define CALLNO_ENTRY_SET_VALIDATED(a) ((a) |= 0x8000)
-#define CALLNO_ENTRY_IS_VALIDATED(a)  ((a) & 0x8000)
-#define CALLNO_ENTRY_GET_CALLNO(a)    ((a) & 0x7FFF)
-
-struct call_number_pool {
-	size_t capacity;
-	size_t available;
-	callno_entry numbers[IAX_MAX_CALLS / 2 + 1];
-};
-
-AST_MUTEX_DEFINE_STATIC(callno_pool_lock);
-
 /*! table of available call numbers */
-static struct call_number_pool callno_pool;
+static struct ao2_container *callno_pool;
 
 /*! table of available trunk call numbers */
-static struct call_number_pool callno_pool_trunk;
+static struct ao2_container *callno_pool_trunk;
+
+static const unsigned int CALLNO_POOL_BUCKETS = 2699;
 
 /*!
  * \brief a list of frames that may need to be retransmitted
@@ -962,7 +917,7 @@ static uint16_t total_nonval_callno_used = 0;
  *  consumed by a single ip address */
 struct peercnt {
 	/*! ip address consuming call numbers */
-	struct ast_sockaddr addr;
+	unsigned long addr;
 	/*! Number of call numbers currently used by this ip address */
 	uint16_t cur;
 	/*! Max call numbers allowed for this ip address */
@@ -982,6 +937,15 @@ struct addr_range {
 	unsigned char delme;
 };
 
+struct callno_entry {
+	/*! callno used for this entry */
+	uint16_t callno;
+	/*! was this callno calltoken validated or not */
+	unsigned char validated;
+};
+
+static AST_LIST_HEAD_STATIC(firmwares, iax_firmware);
+
 enum {
 	/*! Extension exists */
 	CACHE_FLAG_EXISTS      = (1 << 0),
@@ -1016,8 +980,8 @@ struct iax2_dpcache {
 static AST_LIST_HEAD_STATIC(dpcache, iax2_dpcache);
 
 static void reg_source_db(struct iax2_peer *p);
-static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr);
-static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr);
+static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
+static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin);
 
 static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
 static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, uint64_t flags);
@@ -1051,12 +1015,12 @@ struct iax2_thread {
 #endif
 #ifdef DEBUG_SCHED_MULTITHREAD
 	char curfunc[80];
-#endif
+#endif	
 	int actions;
 	pthread_t threadid;
 	int threadnum;
-	struct ast_sockaddr ioaddr;
-	unsigned char readbuf[4096];
+	struct sockaddr_in iosin;
+	unsigned char readbuf[4096]; 
 	unsigned char *buf;
 	ssize_t buf_len;
 	size_t buf_size;
@@ -1072,7 +1036,7 @@ struct iax2_thread {
 	  frames for that callno to other threads */
 	struct {
 		unsigned short callno;
-		struct ast_sockaddr addr;
+		struct sockaddr_in sin;
 		unsigned char type;
 		unsigned char csub;
 	} ffinfo;
@@ -1156,8 +1120,8 @@ static ast_mutex_t iaxsl[ARRAY_LEN(iaxs)];
 
 /*!
  *  * \brief Another container of iax2_pvt structures
- *
- *  Active IAX2 pvt stucts used during transfering a call are stored here.
+ *  
+ *  Active IAX2 pvt stucts used during transfering a call are stored here.  
  */
 static struct ao2_container *iax_transfercallno_pvts;
 
@@ -1166,21 +1130,20 @@ static struct ao2_container *iax_transfercallno_pvts;
 #define TRUNK_CALL_START	(IAX_MAX_CALLS / 2)
 
 /* Debug routines... */
-static struct ast_sockaddr debugaddr;
+static struct sockaddr_in debugaddr;
 
-static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
+static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
 {
 	if (iaxdebug ||
-	    (addr && !ast_sockaddr_isnull(&debugaddr) &&
-		(!ast_sockaddr_port(&debugaddr) ||
-		  ast_sockaddr_port(&debugaddr) == ast_sockaddr_port(addr)) &&
-		  !ast_sockaddr_cmp_addr(&debugaddr, addr))) {
-
+	    (sin && debugaddr.sin_addr.s_addr && 
+	     (!ntohs(debugaddr.sin_port) ||
+	      debugaddr.sin_port == sin->sin_port) &&
+	     debugaddr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
 		if (iaxdebug) {
-			iax_showframe(f, fhi, rx, addr, datalen);
+			iax_showframe(f, fhi, rx, sin, datalen);
 		} else {
 			iaxdebug = 1;
-			iax_showframe(f, fhi, rx, addr, datalen);
+			iax_showframe(f, fhi, rx, sin, datalen);
 			iaxdebug = 0;
 		}
 	}
@@ -1233,6 +1196,7 @@ static void __attribute__((format(printf, 1, 2))) jb_debug_output(const char *fm
 	ast_verbose("%s", buf);
 }
 
+static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 static int expire_registry(const void *data);
 static int iax2_answer(struct ast_channel *c);
 static int iax2_call(struct ast_channel *c, const char *dest, int timeout);
@@ -1244,7 +1208,7 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
 static int iax2_hangup(struct ast_channel *c);
 static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest, const char *template, int force);
+static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force);
 static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
 static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
 static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
@@ -1261,7 +1225,7 @@ static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, c
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
-static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
@@ -1276,11 +1240,11 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 static int encrypt_frame(ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh, unsigned char *poo, int *datalen);
 static void build_ecx_key(const unsigned char *digest, struct chan_iax2_pvt *pvt);
 static void build_rand_pad(unsigned char *buf, ssize_t len);
-static int get_unused_callno(enum callno_type type, int validated, callno_entry *entry);
+static struct callno_entry *get_unused_callno(int trunk, int validated);
 static int replace_callno(const void *obj);
-static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry);
-static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
+static void sched_delay_remove(struct sockaddr_in *sin, struct callno_entry *callno_entry);
+static void network_change_event_cb(const struct ast_event *, void *);
+static void acl_change_event_cb(const struct ast_event *, void *);
 
 static struct ast_channel_tech iax2_tech = {
 	.type = "IAX2",
@@ -1302,6 +1266,7 @@ static struct ast_channel_tech iax2_tech = {
 	.indicate = iax2_indicate,
 	.setoption = iax2_setoption,
 	.queryoption = iax2_queryoption,
+	.bridge = iax2_bridge,
 	.transfer = iax2_transfer,
 	.fixup = iax2_fixup,
 	.func_channel_read = acf_channel_read,
@@ -1421,61 +1386,52 @@ static int iax2_is_control_frame_allowed(int subtype)
 		/* Only meaningful across a bridge on this machine for direct-media exchange. */
 	case AST_CONTROL_PVT_CAUSE_CODE:
 		/* Intended only for the sending machine's local channel structure. */
-	case AST_CONTROL_MASQUERADE_NOTIFY:
-		/* Intended only for masquerades when calling ast_indicate_data(). */
-	case AST_CONTROL_STREAM_STOP:
-	case AST_CONTROL_STREAM_SUSPEND:
-	case AST_CONTROL_STREAM_RESTART:
-	case AST_CONTROL_STREAM_REVERSE:
-	case AST_CONTROL_STREAM_FORWARD:
-		/* None of these playback stream control frames should go across the link. */
-	case AST_CONTROL_RECORD_CANCEL:
-	case AST_CONTROL_RECORD_STOP:
-	case AST_CONTROL_RECORD_SUSPEND:
-	case AST_CONTROL_RECORD_MUTE:
-		/* None of these media recording control frames should go across the link. */
 		break;
 	}
 	return is_allowed;
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* The MWI subscriptions exist just so the core knows we care about those
 	 * mailboxes.  However, we just grab the events out of the cache when it
 	 * is time to send MWI, since it is only sent with a REGACK. */
 }
 
-static void network_change_stasis_subscribe(void)
+static void network_change_event_subscribe(void)
 {
-	if (!network_change_sub) {
-		network_change_sub = stasis_subscribe(ast_system_topic(),
-			network_change_stasis_cb, NULL);
+	if (!network_change_event_subscription) {
+		network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+			network_change_event_cb, "IAX2 Network Change", NULL, AST_EVENT_IE_END);
 	}
 }
 
-static void network_change_stasis_unsubscribe(void)
+static void network_change_event_unsubscribe(void)
 {
-	network_change_sub = stasis_unsubscribe_and_join(network_change_sub);
+	if (network_change_event_subscription) {
+		network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+	}
 }
 
-static void acl_change_stasis_subscribe(void)
+static void acl_change_event_subscribe(void)
 {
-	if (!acl_change_sub) {
-		acl_change_sub = stasis_subscribe(ast_security_topic(),
-			acl_change_stasis_cb, NULL);
+	if (!acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_subscribe(AST_EVENT_ACL_CHANGE,
+			acl_change_event_cb, "IAX2 ACL Change", NULL, AST_EVENT_IE_END);
 	}
 }
 
-static void acl_change_stasis_unsubscribe(void)
+static void acl_change_event_unsubscribe(void)
 {
-	acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
+	if (acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_unsubscribe(acl_change_event_subscription);
+	}
 }
 
-static int network_change_sched_cb(const void *data)
+static int network_change_event_sched_cb(const void *data)
 {
 	struct iax2_registry *reg;
-	network_change_sched_id = -1;
+	network_change_event_sched_id = -1;
 	AST_LIST_LOCK(&registrations);
 	AST_LIST_TRAVERSE(&registrations, reg, entry) {
 		iax2_do_register(reg);
@@ -1485,31 +1441,32 @@ static int network_change_sched_cb(const void *data)
 	return 0;
 }
 
-static void network_change_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
 {
-	/* This callback is only concerned with network change messages from the system topic. */
-	if (stasis_message_type(message) != ast_network_change_type()) {
-		return;
+	ast_debug(1, "IAX, got a network change event, renewing all IAX registrations.\n");
+	if (network_change_event_sched_id == -1) {
+		network_change_event_sched_id = iax2_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
 	}
 
-	ast_verb(1, "IAX, got a network change message, renewing all IAX registrations.\n");
-	if (network_change_sched_id == -1) {
-		network_change_sched_id = iax2_sched_add(sched, 1000, network_change_sched_cb, NULL);
-	}
 }
 
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static void acl_change_event_cb(const struct ast_event *event, void *userdata)
 {
-	if (stasis_message_type(message) != ast_named_acl_change_type()) {
-		return;
-	}
-
 	ast_log(LOG_NOTICE, "Reloading chan_iax2 in response to ACL change event.\n");
 	reload_config(1);
 }
 
+
+/*! \brief Send manager event at call setup to link between Asterisk channel name
+	and IAX2 call identifiers */
+static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
+{
+	manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+		"Channel: %s\r\nChanneltype: IAX2\r\nIAX2-callno-local: %d\r\nIAX2-callno-remote: %d\r\nIAX2-peer: %s\r\n",
+		pvt->owner ? ast_channel_name(pvt->owner) : "",
+		pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
+}
+
 static const struct ast_datastore_info iax2_variable_datastore_info = {
 	.type = "IAX2_VARIABLE",
 	.duplicate = iax2_dup_variable_datastore,
@@ -1819,114 +1776,73 @@ static iax2_format uncompress_subclass(unsigned char csub)
 		return csub;
 }
 
-static struct ast_format *codec_choose_from_prefs(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
+static iax2_format iax2_codec_choose(struct ast_codec_pref *pref, iax2_format formats, int find_best)
 {
-	int x;
-	struct ast_format *found_format = NULL;
-
-	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
-		struct ast_format *pref_format;
-		uint64_t pref_bitfield;
-
-		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
-		if (!pref_bitfield) {
-			break;
-		}
-
-		pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
-		if (!pref_format) {
-			/* The bitfield is not associated with any format. */
-			continue;
-		}
-		found_format = ast_format_cap_get_compatible_format(cap, pref_format);
-		if (found_format) {
-			break;
-		}
-	}
-
-	if (found_format && (ast_format_get_type(found_format) == AST_MEDIA_TYPE_AUDIO)) {
-		return found_format;
+	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
+	iax2_format format = 0;
+	if ((cap = ast_format_cap_alloc_nolock())) {
+		ast_format_clear(&tmpfmt);
+		ast_format_cap_from_old_bitfield(cap, formats);
+		ast_codec_choose(pref, cap, find_best, &tmpfmt);
+		format = ast_format_to_old_bitfield(&tmpfmt);
+		cap = ast_format_cap_destroy(cap);
 	}
 
-	ast_debug(4, "Could not find preferred codec - Returning zero codec.\n");
-	ao2_cleanup(found_format);
-	return NULL;
+	return format;
 }
 
-static iax2_format iax2_codec_choose(struct iax2_codec_pref *pref, iax2_format formats)
+static iax2_format iax2_best_codec(iax2_format formats)
 {
-	struct ast_format_cap *cap;
-	struct ast_format *tmpfmt;
-	iax2_format format = 0;
-
-	if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		iax2_format_compatibility_bitfield2cap(formats, cap);
-		tmpfmt = codec_choose_from_prefs(pref, cap);
-		if (!tmpfmt) {
-			ao2_ref(cap, -1);
-			return 0;
-		}
-
-		format = ast_format_compatibility_format2bitfield(tmpfmt);
-		ao2_ref(tmpfmt, -1);
-		ao2_ref(cap, -1);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	struct ast_format tmpfmt;
+	if (!cap) {
+		return 0;
 	}
 
-	return format;
+	ast_format_clear(&tmpfmt);
+	ast_format_cap_from_old_bitfield(cap, formats);
+	ast_best_codec(cap, &tmpfmt);
+	cap = ast_format_cap_destroy(cap);
+	return ast_format_to_old_bitfield(&tmpfmt);
 }
 
 const char *iax2_getformatname(iax2_format format)
 {
-	struct ast_format *tmpfmt;
-
-	tmpfmt = ast_format_compatibility_bitfield2format(format);
-	if (!tmpfmt) {
+	struct ast_format tmpfmt;
+	if (!(ast_format_from_old_bitfield(&tmpfmt, format))) {
 		return "Unknown";
 	}
 
-	return ast_format_get_name(tmpfmt);
+	return ast_getformatname(&tmpfmt);
 }
 
-static const char *iax2_getformatname_multiple(iax2_format format, struct ast_str **codec_buf)
+static char *iax2_getformatname_multiple(char *codec_buf, size_t len, iax2_format format)
 {
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
 
 	if (!cap) {
 		return "(Nothing)";
 	}
-	iax2_format_compatibility_bitfield2cap(format, cap);
-	ast_format_cap_get_names(cap, codec_buf);
-	ao2_ref(cap, -1);
+	ast_format_cap_from_old_bitfield(cap, format);
+	ast_getformatname_multiple(codec_buf, len, cap);
+	cap = ast_format_cap_destroy(cap);
 
-	return ast_str_buffer(*codec_buf);
+	return codec_buf;
 }
 
-static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
+static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
 {
-	int res, i;
-	struct ast_format_cap *cap;
-
-	/* We want to add the formats to the cap in the preferred order */
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
-		ao2_cleanup(cap);
+	int res;
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	if (!cap) {
 		return 1;
 	}
 
-	res = ast_format_cap_update_by_allow_disallow(cap, list, allowing);
-
-	/* Adjust formats bitfield and pref list to match. */
-	*formats = iax2_format_compatibility_cap2bitfield(cap);
-	iax2_codec_pref_remove_missing(pref, *formats);
-
-	for (i = 0; i < ast_format_cap_count(cap); i++) {
-		struct ast_format *fmt = ast_format_cap_get_format(cap, i);
-
-		iax2_codec_pref_append(pref, fmt, ast_format_cap_get_format_framing(cap, fmt));
-		ao2_ref(fmt, -1);
-	}
-
-	ao2_ref(cap, -1);
+	ast_format_cap_from_old_bitfield(cap, *formats);
+	res = ast_parse_allow_disallow(pref, cap, list, allowing);
+	*formats = ast_format_cap_to_old_bitfield(cap);
+	cap = ast_format_cap_destroy(cap);
 
 	return res;
 }
@@ -1934,13 +1850,13 @@ static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *
 static int iax2_data_add_codecs(struct ast_data *root, const char *node_name, iax2_format formats)
 {
 	int res;
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
 	if (!cap) {
 		return -1;
 	}
-	iax2_format_compatibility_bitfield2cap(formats, cap);
+	ast_format_cap_from_old_bitfield(cap, formats);
 	res = ast_data_add_codecs(root, node_name, cap);
-	ao2_ref(cap, -1);
+	cap = ast_format_cap_destroy(cap);
 	return res;
 }
 
@@ -1994,16 +1910,16 @@ static int user_cmp_cb(void *obj, void *arg, int flags)
  * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call it with a pvt lock held.
  */
-static struct iax2_peer *find_peer(const char *name, int realtime)
+static struct iax2_peer *find_peer(const char *name, int realtime) 
 {
 	struct iax2_peer *peer = NULL;
 
 	peer = ao2_find(peers, name, OBJ_KEY);
 
 	/* Now go for realtime if applicable */
-	if (!peer && realtime) {
+	if(!peer && realtime)
 		peer = realtime_peer(name, NULL);
-	}
+
 	return peer;
 }
 
@@ -2023,11 +1939,6 @@ static struct iax2_user *find_user(const char *name)
 {
 	return ao2_find(users, name, OBJ_KEY);
 }
-static inline struct iax2_user *user_ref(struct iax2_user *user)
-{
-	ao2_ref(user, +1);
-	return user;
-}
 
 static inline struct iax2_user *user_unref(struct iax2_user *user)
 {
@@ -2035,7 +1946,7 @@ static inline struct iax2_user *user_unref(struct iax2_user *user)
 	return NULL;
 }
 
-static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
+static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 {
 	struct iax2_peer *peer = NULL;
 	int res = 0;
@@ -2043,8 +1954,12 @@ static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
 
 	i = ao2_iterator_init(peers, 0);
 	while ((peer = ao2_iterator_next(&i))) {
+		struct sockaddr_in peer_addr;
+
+		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-		if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
+		if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
+		    (peer_addr.sin_port == sin.sin_port)) {
 			ast_copy_string(host, peer->name, len);
 			peer_unref(peer);
 			res = 1;
@@ -2055,7 +1970,7 @@ static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
 	ao2_iterator_destroy(&i);
 
 	if (!peer) {
-		peer = realtime_peer(NULL, &addr);
+		peer = realtime_peer(NULL, &sin);
 		if (peer) {
 			ast_copy_string(host, peer->name, len);
 			peer_unref(peer);
@@ -2171,7 +2086,7 @@ static void pvt_destructor(void *obj)
 	iax2_destroy_helper(pvt);
 
 	sched_delay_remove(&pvt->addr, pvt->callno_entry);
-	pvt->callno_entry = 0;
+	pvt->callno_entry = NULL;
 
 	/* Already gone */
 	ast_set_flag64(pvt, IAX_ALREADYGONE);
@@ -2212,7 +2127,7 @@ static void pvt_destructor(void *obj)
 
 }
 
-static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host)
+static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
 {
 	struct chan_iax2_pvt *tmp;
 	jb_conf jbconf;
@@ -2226,8 +2141,8 @@ static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host
 		tmp = NULL;
 		return NULL;
 	}
-
-	tmp->prefs = prefs_global;
+		
+	tmp->prefs = prefs;
 	tmp->pingid = -1;
 	tmp->lagid = -1;
 	tmp->autoid = -1;
@@ -2283,9 +2198,10 @@ enum {
 	NEW_ALLOW_CALLTOKEN_VALIDATED = 3,
 };
 
-static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
+static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
 {
-	if (!ast_sockaddr_cmp(&cur->addr, addr)) {
+	if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->addr.sin_port == sin->sin_port)) {
 		/* This is the main host */
 		if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
 			 (check_dcallno ? dcallno == cur->callno : 1) ) {
@@ -2293,7 +2209,8 @@ static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned shor
 			return 1;
 		}
 	}
-	if (!ast_sockaddr_cmp(&cur->transfer, addr) && cur->transferring) {
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+	    (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
 		/* We're transferring */
 		if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
 			return 1;
@@ -2305,7 +2222,7 @@ static int make_trunk(unsigned short callno, int locked)
 {
 	int x;
 	int res= 0;
-	callno_entry entry;
+	struct callno_entry *callno_entry;
 	if (iaxs[callno]->oseqno) {
 		ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");
 		return -1;
@@ -2315,15 +2232,12 @@ static int make_trunk(unsigned short callno, int locked)
 		return -1;
 	}
 
-	if (get_unused_callno(
-			CALLNO_TYPE_TRUNK,
-			CALLNO_ENTRY_IS_VALIDATED(iaxs[callno]->callno_entry),
-			&entry)) {
+	if (!(callno_entry = get_unused_callno(1, iaxs[callno]->callno_entry->validated))) {
 		ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
 		return -1;
 	}
 
-	x = CALLNO_ENTRY_GET_CALLNO(entry);
+	x = callno_entry->callno;
 	ast_mutex_lock(&iaxsl[x]);
 
 	/*!
@@ -2339,20 +2253,15 @@ static int make_trunk(unsigned short callno, int locked)
 	/* since we copied over the pvt from a different callno, make sure the old entry is replaced
 	 * before assigning the new one */
 	if (iaxs[x]->callno_entry) {
-		iax2_sched_add(
-			sched,
-			MIN_REUSE_TIME * 1000,
-			replace_callno,
-			CALLNO_ENTRY_TO_PTR(iaxs[x]->callno_entry));
-
+		iax2_sched_add(sched, MIN_REUSE_TIME * 1000, replace_callno, iaxs[x]->callno_entry);
 	}
-	iaxs[x]->callno_entry = entry;
+	iaxs[x]->callno_entry = callno_entry;
 
 	iaxs[callno] = NULL;
 	/* Update the two timers that should have been started */
-	iaxs[x]->pingid = iax2_sched_add(sched,
+	iaxs[x]->pingid = iax2_sched_add(sched, 
 		ping_time * 1000, send_ping, (void *)(long)x);
-	iaxs[x]->lagid = iax2_sched_add(sched,
+	iaxs[x]->lagid = iax2_sched_add(sched, 
 		lagrq_time * 1000, send_lagrq, (void *)(long)x);
 
 	if (locked)
@@ -2416,7 +2325,9 @@ static int addr_range_delme_cb(void *obj, void *arg, int flags)
 static int addr_range_hash_cb(const void *obj, const int flags)
 {
 	const struct addr_range *lim = obj;
-	return abs(ast_sockaddr_hash(&lim->ha.addr));
+	struct sockaddr_in sin;
+	ast_sockaddr_to_sin(&lim->ha.addr, &sin);
+	return abs((int) sin.sin_addr.s_addr);
 }
 
 static int addr_range_cmp_cb(void *obj, void *arg, int flags)
@@ -2430,39 +2341,37 @@ static int addr_range_cmp_cb(void *obj, void *arg, int flags)
 static int peercnt_hash_cb(const void *obj, const int flags)
 {
 	const struct peercnt *peercnt = obj;
-
-	if (ast_sockaddr_isnull(&peercnt->addr)) {
-		return 0;
-	}
-	return ast_sockaddr_hash(&peercnt->addr);
+	return abs((int) peercnt->addr);
 }
 
 static int peercnt_cmp_cb(void *obj, void *arg, int flags)
 {
 	struct peercnt *peercnt1 = obj, *peercnt2 = arg;
-	return !ast_sockaddr_cmp_addr(&peercnt1->addr, &peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
+	return (peercnt1->addr == peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static int addr_range_match_address_cb(void *obj, void *arg, int flags)
 {
 	struct addr_range *addr_range = obj;
-	struct ast_sockaddr *addr = arg;
-	struct ast_sockaddr tmp_addr;
+	struct sockaddr_in *sin = arg;
+	struct sockaddr_in ha_netmask_sin;
+	struct sockaddr_in ha_addr_sin;
 
-	ast_sockaddr_apply_netmask(addr, &addr_range->ha.netmask, &tmp_addr);
+	ast_sockaddr_to_sin(&addr_range->ha.netmask, &ha_netmask_sin);
+	ast_sockaddr_to_sin(&addr_range->ha.addr, &ha_addr_sin);
 
-	if (!ast_sockaddr_cmp_addr(&tmp_addr, &addr_range->ha.addr)) {
+	if ((sin->sin_addr.s_addr & ha_netmask_sin.sin_addr.s_addr) == ha_addr_sin.sin_addr.s_addr) {
 		return CMP_MATCH | CMP_STOP;
 	}
 	return 0;
 }
 
-/*!
+/*! 
  * \internal
  *
- * \brief compares addr to calltoken_ignores table to determine if validation is required.
+ * \brief compares sin to calltoken_ignores table to determine if validation is required.
  */
-static int calltoken_required(struct ast_sockaddr *addr, const char *name, int subclass)
+static int calltoken_required(struct sockaddr_in *sin, const char *name, int subclass)
 {
 	struct addr_range *addr_range;
 	struct iax2_peer *peer = NULL;
@@ -2479,7 +2388,7 @@ static int calltoken_required(struct ast_sockaddr *addr, const char *name, int s
 	 */
 
 	/* ----- Case 1 ----- */
-	if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, addr))) {
+	if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, sin))) {
 		ao2_ref(addr_range, -1);
 		optional = 1;
 	}
@@ -2487,11 +2396,11 @@ static int calltoken_required(struct ast_sockaddr *addr, const char *name, int s
 	/* ----- Case 2 ----- */
 	if ((subclass == IAX_COMMAND_NEW) && (user = find_user(find))) {
 		calltoken_required = user->calltoken_required;
-	} else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, addr))) {
+	} else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, sin))) {
 		calltoken_required = user->calltoken_required;
 	} else if ((subclass != IAX_COMMAND_NEW) && (peer = find_peer(find, 0))) {
 		calltoken_required = peer->calltoken_required;
-	} else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, addr))) {
+	} else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, sin))) {
 		calltoken_required = peer->calltoken_required;
 	}
 
@@ -2502,7 +2411,7 @@ static int calltoken_required(struct ast_sockaddr *addr, const char *name, int s
 		user_unref(user);
 	}
 
-	ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %u \n", ast_sockaddr_stringify_addr(addr), name, optional, calltoken_required);
+	ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %u\n", ast_inet_ntoa(sin->sin_addr), name, optional, calltoken_required);
 	if (((calltoken_required == CALLTOKEN_NO) || (calltoken_required == CALLTOKEN_AUTO)) ||
 		(optional && (calltoken_required == CALLTOKEN_DEFAULT))) {
 		res = 0;
@@ -2511,12 +2420,12 @@ static int calltoken_required(struct ast_sockaddr *addr, const char *name, int s
 	return res;
 }
 
-/*!
+/*! 
  * \internal
  *
  * \brief set peercnt callno limit.
  *
- * \details
+ * \details 
  * First looks in custom definitions. If not found, global limit
  * is used.  Entries marked as reg already have
  * a custom limit set by a registration and are not modified.
@@ -2525,24 +2434,25 @@ static void set_peercnt_limit(struct peercnt *peercnt)
 {
 	uint16_t limit = global_maxcallno;
 	struct addr_range *addr_range;
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin = {
+		.sin_addr.s_addr = peercnt->addr,
+	};
 
-	ast_sockaddr_copy(&addr, &peercnt->addr);
 
 	if (peercnt->reg && peercnt->limit) {
 		return; /* this peercnt has a custom limit set by a registration */
 	}
 
-	if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &addr))) {
+	if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &sin))) {
 		limit = addr_range->limit;
-		ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_sockaddr_stringify(&addr));
+		ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_inet_ntoa(sin.sin_addr));
 		ao2_ref(addr_range, -1);
 	}
 
 	peercnt->limit = limit;
 }
 
-/*!
+/*! 
  * \internal
  * \brief sets limits for all peercnts in table. done on reload to reflect changes in conf.
  */
@@ -2556,9 +2466,9 @@ static int set_peercnt_limit_all_cb(void *obj, void *arg, int flags)
 	return 0;
 }
 
-/*!
+/*! 
  * \internal
- * \brief returns match if delme is set.
+ * \brief returns match if delme is set. 
  */
 static int prune_addr_range_cb(void *obj, void *arg, int flags)
 {
@@ -2567,7 +2477,7 @@ static int prune_addr_range_cb(void *obj, void *arg, int flags)
 	return addr_range->delme ? CMP_MATCH : 0;
 }
 
-/*!
+/*! 
  * \internal
  * \brief modifies peercnt entry in peercnts table. Used to set custom limit or mark a registered ip
  */
@@ -2575,9 +2485,14 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
 {
 	/* this function turns off and on custom callno limits set by peer registration */
 	struct peercnt *peercnt;
-	struct peercnt tmp;
+	struct peercnt tmp = {
+		.addr = 0,
+	};
+	struct sockaddr_in sin;
 
-	ast_sockaddr_copy(&tmp.addr, sockaddr);
+	ast_sockaddr_to_sin(sockaddr, &sin);
+
+	tmp.addr = sin.sin_addr.s_addr;
 
 	if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
 		peercnt->reg = reg;
@@ -2586,12 +2501,12 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
 		} else {
 			set_peercnt_limit(peercnt);
 		}
-		ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_sockaddr_stringify_addr(sockaddr), peercnt->limit, peercnt->reg);
+		ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_inet_ntoa(sin.sin_addr), peercnt->limit, peercnt->reg);
 		ao2_ref(peercnt, -1); /* decrement ref from find */
 	}
 }
 
-/*!
+/*! 
  * \internal
  * \brief adds an ip to the peercnts table, increments connection count if it already exists
  *
@@ -2599,13 +2514,14 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
  * the current count is incremented.  If not found a new peercnt is allocated
  * and linked into the peercnts table with a call number count of 1.
  */
-static int peercnt_add(struct ast_sockaddr *addr)
+static int peercnt_add(struct sockaddr_in *sin)
 {
 	struct peercnt *peercnt;
+	unsigned long addr = sin->sin_addr.s_addr;
 	int res = 0;
-	struct peercnt tmp;
-
-	ast_sockaddr_copy(&tmp.addr, addr);
+	struct peercnt tmp = {
+		.addr = addr,
+	};
 
 	/* Reasoning for peercnts container lock:  Two identical ip addresses
 	 * could be added by different threads at the "same time". Without the container
@@ -2619,7 +2535,7 @@ static int peercnt_add(struct ast_sockaddr *addr)
 	} else if ((peercnt = ao2_alloc(sizeof(*peercnt), NULL))) {
 		ao2_lock(peercnt);
 		/* create and set defaults */
-		ast_sockaddr_copy(&peercnt->addr, addr);
+		peercnt->addr = addr;
 		set_peercnt_limit(peercnt);
 		/* guarantees it does not go away after unlocking table
 		 * ao2_find automatically adds this */
@@ -2632,9 +2548,9 @@ static int peercnt_add(struct ast_sockaddr *addr)
 	/* check to see if the address has hit its callno limit.  If not increment cur. */
 	if (peercnt->limit > peercnt->cur) {
 		peercnt->cur++;
-		ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(addr));
+		ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin->sin_addr));
 	} else { /* max num call numbers for this peer has been reached! */
-		ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_sockaddr_stringify_addr(addr));
+		ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_inet_ntoa(sin->sin_addr));
 		res = -1;
 	}
 
@@ -2646,15 +2562,15 @@ static int peercnt_add(struct ast_sockaddr *addr)
 	return res;
 }
 
-/*!
+/*! 
  * \internal
  * \brief decrements a peercnts table entry
  */
 static void peercnt_remove(struct peercnt *peercnt)
 {
-	struct ast_sockaddr addr;
-
-	ast_sockaddr_copy(&addr, &peercnt->addr);
+	struct sockaddr_in sin = {
+		.sin_addr.s_addr = peercnt->addr,
+	};
 
 	/*
 	 * Container locked here since peercnt may be unlinked from
@@ -2664,7 +2580,7 @@ static void peercnt_remove(struct peercnt *peercnt)
 	 */
 	ao2_lock(peercnts);
 	peercnt->cur--;
-	ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(&addr));
+	ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr));
 	/* if this was the last connection from the peer remove it from table */
 	if (peercnt->cur == 0) {
 		ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */
@@ -2672,7 +2588,7 @@ static void peercnt_remove(struct peercnt *peercnt)
 	ao2_unlock(peercnts);
 }
 
-/*!
+/*! 
  * \internal
  * \brief called by scheduler to decrement object
  */
@@ -2686,16 +2602,16 @@ static int peercnt_remove_cb(const void *obj)
 	return 0;
 }
 
-/*!
+/*! 
  * \internal
  * \brief decrements peercnts connection count, finds by addr
  */
-static int peercnt_remove_by_addr(struct ast_sockaddr *addr)
+static int peercnt_remove_by_addr(struct sockaddr_in *sin)
 {
 	struct peercnt *peercnt;
-	struct peercnt tmp;
-
-	ast_sockaddr_copy(&tmp.addr, addr);
+	struct peercnt tmp = {
+		.addr = sin->sin_addr.s_addr,
+	};
 
 	if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
 		peercnt_remove(peercnt);
@@ -2704,7 +2620,7 @@ static int peercnt_remove_by_addr(struct ast_sockaddr *addr)
 	return 0;
 }
 
-/*!
+/*! 
  * \internal
  * \brief Create callno_limit entry based on configuration
  */
@@ -2759,7 +2675,7 @@ static void build_callno_limits(struct ast_variable *v)
 	}
 }
 
-/*!
+/*! 
  * \internal
  * \brief Create calltoken_ignores entry based on configuration
  */
@@ -2808,7 +2724,7 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 {
 	struct ao2_iterator i;
 	struct peercnt *peercnt;
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	int found = 0;
 
 	switch (cmd) {
@@ -2825,43 +2741,39 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 			return CLI_SHOWUSAGE;
 
 		if (a->argc == 4) {
-			ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+			ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
 		}
 
 		i = ao2_iterator_init(peercnts, 0);
 		while ((peercnt = ao2_iterator_next(&i))) {
-			ast_sockaddr_copy(&addr, &peercnt->addr);
-
+			sin.sin_addr.s_addr = peercnt->addr;
 			if (a->argc == 5) {
-				if (!strcasecmp(a->argv[4], ast_sockaddr_stringify(&addr))) {
-					ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
-					ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
+				if (!strcasecmp(a->argv[4], ast_inet_ntoa(sin.sin_addr))) {
+					ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+					ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
 					ao2_ref(peercnt, -1);
 					found = 1;
 					break;
 				}
 			} else {
-				ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
+				ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
 			}
 			ao2_ref(peercnt, -1);
 		}
 		ao2_iterator_destroy(&i);
 
 		if (a->argc == 4) {
-			size_t pool_avail = callno_pool.available;
-			size_t trunk_pool_avail = callno_pool_trunk.available;
-
 			ast_cli(a->fd, "\nNon-CallToken Validation Callno Limit: %d\n"
 			                 "Non-CallToken Validated Callno Used:   %d\n",
 				global_maxcallno_nonval,
 				total_nonval_callno_used);
 
-			ast_cli(a->fd,   "Total Available Callno:                %zu\n"
-			                 "Regular Callno Available:              %zu\n"
-			                 "Trunk Callno Available:                %zu\n",
-				pool_avail + trunk_pool_avail,
-				pool_avail,
-				trunk_pool_avail);
+			ast_cli(a->fd,   "Total Available Callno:                %d\n"
+			                 "Regular Callno Available:              %d\n"
+			                 "Trunk Callno Available:                %d\n",
+				ao2_container_count(callno_pool) + ao2_container_count(callno_pool_trunk),
+				ao2_container_count(callno_pool),
+				ao2_container_count(callno_pool_trunk));
 		} else if (a->argc == 5 && !found) {
 			ast_cli(a->fd, "No call number table entries for %s found\n", a->argv[4] );
 		}
@@ -2873,143 +2785,103 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 	}
 }
 
-static int get_unused_callno(enum callno_type type, int validated, callno_entry *entry)
+static struct callno_entry *get_unused_callno(int trunk, int validated)
 {
-	struct call_number_pool *pool = NULL;
-	callno_entry swap;
-	size_t choice;
-
-	switch (type) {
-	case CALLNO_TYPE_NORMAL:
-		pool = &callno_pool;
-		break;
-	case CALLNO_TYPE_TRUNK:
-		pool = &callno_pool_trunk;
-		break;
-	default:
-		ast_assert(0);
-		break;
+	struct callno_entry *callno_entry = NULL;
+	if ((!ao2_container_count(callno_pool) && !trunk) || (!ao2_container_count(callno_pool_trunk) && trunk)) {
+		ast_log(LOG_WARNING, "Out of CallNumbers\n");
+		/* Minor optimization for the extreme case. */
+		return NULL;
 	}
 
-	/* If we fail, make sure this has a defined value */
-	*entry = 0;
+	/* the callno_pool container is locked here primarily to ensure thread
+	 * safety of the total_nonval_callno_used check and increment */
+	ao2_lock(callno_pool);
 
-	/* We lock here primarily to ensure thread safety of the
-	 * total_nonval_callno_used check and increment */
-	ast_mutex_lock(&callno_pool_lock);
-
-	/* Bail out if we don't have any available call numbers */
-	if (!pool->available) {
-		ast_log(LOG_WARNING, "Out of call numbers\n");
-		ast_mutex_unlock(&callno_pool_lock);
-		return 1;
-	}
-
-	/* Only a certain number of non-validated call numbers should be allocated.
-	 * If there ever is an attack, this separates the calltoken validating users
-	 * from the non-calltoken validating users. */
-	if (!validated && total_nonval_callno_used >= global_maxcallno_nonval) {
-		ast_log(LOG_WARNING,
-			"NON-CallToken callnumber limit is reached. Current: %d Max: %d\n",
-			total_nonval_callno_used,
-			global_maxcallno_nonval);
-		ast_mutex_unlock(&callno_pool_lock);
-		return 1;
+	/* only a certain number of nonvalidated call numbers should be allocated.
+	 * If there ever is an attack, this separates the calltoken validating
+	 * users from the non calltoken validating users. */
+	if (!validated && (total_nonval_callno_used >= global_maxcallno_nonval)) {
+		ast_log(LOG_WARNING, "NON-CallToken callnumber limit is reached. Current:%d Max:%d\n", total_nonval_callno_used, global_maxcallno_nonval);
+		ao2_unlock(callno_pool);
+		return NULL;
 	}
 
-	/* We use a modified Fisher-Yates-Durstenfeld Shuffle to maintain a list of
-	 * available call numbers.  The array of call numbers begins as an ordered
-	 * list from 1 -> n, and we keep a running tally of how many remain unclaimed
-	 * - let's call that x.  When a call number is needed we pick a random index
-	 * into the array between 0 and x and use that as our call number.  In a
-	 * typical FYD shuffle, we would swap the value that we are extracting with
-	 * the number at x, but in our case we swap and don't touch the value at x
-	 * because it is effectively invisible.  We rely on the rest of the IAX2 core
-	 * to return the number to us at some point.  Finally, we decrement x by 1
-	 * which establishes our new unused range.
-	 *
-	 * When numbers are returned to the pool, we put them just past x and bump x
-	 * by 1 so that this number is now available for re-use. */
-
-	choice = ast_random() % pool->available;
-
-	*entry = pool->numbers[choice];
-	swap = pool->numbers[pool->available - 1];
+	/* unlink the object from the container, taking over ownership
+	 * of the reference the container had to the object */
+	callno_entry = ao2_find((trunk ? callno_pool_trunk : callno_pool), NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE);
 
-	pool->numbers[choice] = swap;
-	pool->available--;
-
-	if (validated) {
-		CALLNO_ENTRY_SET_VALIDATED(*entry);
-	} else {
-		total_nonval_callno_used++;
+	if (callno_entry) {
+		callno_entry->validated = validated;
+		if (!validated) {
+			total_nonval_callno_used++;
+		}
 	}
 
-	ast_mutex_unlock(&callno_pool_lock);
-
-	return 0;
+	ao2_unlock(callno_pool);
+	return callno_entry;
 }
 
 static int replace_callno(const void *obj)
 {
-	callno_entry entry = PTR_TO_CALLNO_ENTRY(obj);
-	struct call_number_pool *pool;
+	struct callno_entry *callno_entry = (struct callno_entry *) obj;
 
-	/* We lock here primarily to ensure thread safety of the
-	 * total_nonval_callno_used check and decrement */
-	ast_mutex_lock(&callno_pool_lock);
+	/* the callno_pool container is locked here primarily to ensure thread
+	 * safety of the total_nonval_callno_used check and decrement */
+	ao2_lock(callno_pool);
 
-	if (!CALLNO_ENTRY_IS_VALIDATED(entry)) {
-		if (total_nonval_callno_used) {
-			total_nonval_callno_used--;
-		} else {
-			ast_log(LOG_ERROR,
-				"Attempted to decrement total non calltoken validated "
-				"callnumbers below zero.  Callno is: %d\n",
-				CALLNO_ENTRY_GET_CALLNO(entry));
-		}
+	if (!callno_entry->validated && (total_nonval_callno_used != 0)) {
+		total_nonval_callno_used--;
+	} else if (!callno_entry->validated && (total_nonval_callno_used == 0)) {
+		ast_log(LOG_ERROR, "Attempted to decrement total non calltoken validated callnumbers below zero... Callno is:%d \n", callno_entry->callno);
 	}
 
-	if (CALLNO_ENTRY_GET_CALLNO(entry) < TRUNK_CALL_START) {
-		pool = &callno_pool;
+	if (callno_entry->callno < TRUNK_CALL_START) {
+		ao2_link(callno_pool, callno_entry);
 	} else {
-		pool = &callno_pool_trunk;
+		ao2_link(callno_pool_trunk, callno_entry);
 	}
+	ao2_ref(callno_entry, -1); /* only container ref remains */
 
-	ast_assert(pool->capacity > pool->available);
-
-	/* This clears the validated flag */
-	entry = CALLNO_ENTRY_GET_CALLNO(entry);
-
-	pool->numbers[pool->available] = entry;
-	pool->available++;
-
-	ast_mutex_unlock(&callno_pool_lock);
-
+	ao2_unlock(callno_pool);
 	return 0;
 }
 
+static int callno_hash(const void *obj, const int flags)
+{
+	return abs(ast_random());
+}
+
 static int create_callno_pools(void)
 {
 	uint16_t i;
 
-	callno_pool.available = callno_pool_trunk.available = 0;
-
-	/* We start at 2.  0 and 1 are reserved. */
-	for (i = 2; i < TRUNK_CALL_START; i++) {
-		callno_pool.numbers[callno_pool.available] = i;
-		callno_pool.available++;
+	if (!(callno_pool = ao2_container_alloc(CALLNO_POOL_BUCKETS, callno_hash, NULL))) {
+		return -1;
 	}
 
-	for (i = TRUNK_CALL_START; i < IAX_MAX_CALLS; i++) {
-		callno_pool_trunk.numbers[callno_pool_trunk.available] = i;
-		callno_pool_trunk.available++;
+	if (!(callno_pool_trunk = ao2_container_alloc(CALLNO_POOL_BUCKETS, callno_hash, NULL))) {
+		return -1;
 	}
 
-	callno_pool.capacity = callno_pool.available;
-	callno_pool_trunk.capacity = callno_pool_trunk.available;
+	/* start at 2, 0 and 1 are reserved */
+	for (i = 2; i < IAX_MAX_CALLS; i++) {
+		struct callno_entry *callno_entry;
 
-	ast_assert(callno_pool.capacity && callno_pool_trunk.capacity);
+		if (!(callno_entry = ao2_alloc(sizeof(*callno_entry), NULL))) {
+			return -1;
+		}
+
+		callno_entry->callno = i;
+
+		if (i < TRUNK_CALL_START) {
+			ao2_link(callno_pool, callno_entry);
+		} else {
+			ao2_link(callno_pool_trunk, callno_entry);
+		}
+
+		ao2_ref(callno_entry, -1);
+	}
 
 	return 0;
 }
@@ -3022,33 +2894,29 @@ static int create_callno_pools(void)
  * available again, and the address from the previous connection must be decremented
  * from the peercnts table.  This function schedules these operations to take place.
  */
-static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry)
+static void sched_delay_remove(struct sockaddr_in *sin, struct callno_entry *callno_entry)
 {
 	int i;
 	struct peercnt *peercnt;
-	struct peercnt tmp;
-
-	ast_sockaddr_copy(&tmp.addr, addr);
+	struct peercnt tmp = {
+		.addr = sin->sin_addr.s_addr,
+	};
 
 	if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
 		/* refcount is incremented with ao2_find.  keep that ref for the scheduler */
-		ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_sockaddr_stringify_addr(addr), MIN_REUSE_TIME);
+		ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_inet_ntoa(sin->sin_addr), MIN_REUSE_TIME);
 		i = iax2_sched_add(sched, MIN_REUSE_TIME * 1000, peercnt_remove_cb, peercnt);
 		if (i == -1) {
 			ao2_ref(peercnt, -1);
 		}
 	}
 
-	iax2_sched_add(
-		sched,
-		MIN_REUSE_TIME * 1000,
-		replace_callno,
-		CALLNO_ENTRY_TO_PTR(entry));
+	iax2_sched_add(sched, MIN_REUSE_TIME * 1000, replace_callno, callno_entry);
 }
 
-/*!
+/*! 
  * \internal
- * \brief returns whether or not a frame is capable of starting a new IAX2 dialog.
+ * \brief returns whether or not a frame is capable of starting a new IAX2 dialog. 
  *
  * \note For this implementation, inbound pokes should _NOT_ be capable of allocating
  * a new callno.
@@ -3076,7 +2944,7 @@ static inline int attribute_pure iax2_allow_new(int frametype, int subclass, int
 /*
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
-static int __find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int return_locked, int check_dcallno)
+static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
 {
 	int res = 0;
 	int x;
@@ -3096,8 +2964,8 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 				.frames_received = check_dcallno,
 			};
 
-			ast_sockaddr_copy(&tmp_pvt.addr, addr);
-			/* this works for finding normal call numbers not involving transfering */
+			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
+			/* this works for finding normal call numbers not involving transfering */ 
 			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
 				if (return_locked) {
 					ast_mutex_lock(&iaxsl[pvt->callno]);
@@ -3109,7 +2977,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 			}
 			/* this searches for transfer call numbers that might not get caught otherwise */
 			memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
-			ast_sockaddr_copy(&tmp_pvt.transfer, addr);
+			memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.transfer));
 			if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
 				if (return_locked) {
 					ast_mutex_lock(&iaxsl[pvt->callno]);
@@ -3125,7 +2993,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 		if (dcallno) {
 			ast_mutex_lock(&iaxsl[dcallno]);
 		}
-		if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(addr, callno, dcallno, iaxs[dcallno], check_dcallno)) {
+		if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {
 			iaxs[dcallno]->peercallno = callno;
 			res = dcallno;
 			store_by_peercallno(iaxs[dcallno]);
@@ -3139,40 +3007,41 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 		}
 	}
 	if (!res && (new >= NEW_ALLOW)) {
-		callno_entry entry;
-
+		struct callno_entry *callno_entry;
 		/* It may seem odd that we look through the peer list for a name for
 		 * this *incoming* call.  Well, it is weird.  However, users don't
 		 * have an IP address/port number that we can match against.  So,
 		 * this is just checking for a peer that has that IP/port and
 		 * assuming that we have a user of the same name.  This isn't always
 		 * correct, but it will be changed if needed after authentication. */
-		if (!iax2_getpeername(*addr, host, sizeof(host)))
-			snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(addr));
+		if (!iax2_getpeername(*sin, host, sizeof(host)))
+			snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 
-		if (peercnt_add(addr)) {
+		if (peercnt_add(sin)) {
 			/* This address has hit its callnumber limit.  When the limit
 			 * is reached, the connection is not added to the peercnts table.*/
 			return 0;
 		}
 
-		if (get_unused_callno(CALLNO_TYPE_NORMAL, validated, &entry)) {
+		if (!(callno_entry = get_unused_callno(0, validated))) {
 			/* since we ran out of space, remove the peercnt
 			 * entry we added earlier */
-			peercnt_remove_by_addr(addr);
+			peercnt_remove_by_addr(sin);
 			ast_log(LOG_WARNING, "No more space\n");
 			return 0;
 		}
-		x = CALLNO_ENTRY_GET_CALLNO(entry);
+		x = callno_entry->callno;
 		ast_mutex_lock(&iaxsl[x]);
 
-		iaxs[x] = new_iax(addr, host);
+		iaxs[x] = new_iax(sin, host);
 		if (iaxs[x]) {
 			if (iaxdebug)
 				ast_debug(1, "Creating new call structure %d\n", x);
-			iaxs[x]->callno_entry = entry;
+			iaxs[x]->callno_entry = callno_entry;
 			iaxs[x]->sockfd = sockfd;
-			ast_sockaddr_copy(&iaxs[x]->addr, addr);
+			iaxs[x]->addr.sin_port = sin->sin_port;
+			iaxs[x]->addr.sin_family = sin->sin_family;
+			iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
 			iaxs[x]->peercallno = callno;
 			iaxs[x]->callno = x;
 			iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
@@ -3192,7 +3061,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 		} else {
 			ast_log(LOG_WARNING, "Out of resources\n");
 			ast_mutex_unlock(&iaxsl[x]);
-			replace_callno(CALLNO_ENTRY_TO_PTR(entry));
+			replace_callno(callno_entry);
 			return 0;
 		}
 		if (!return_locked)
@@ -3202,13 +3071,13 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
 	return res;
 }
 
-static int find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
-	return __find_callno(callno, dcallno, addr, new, sockfd, 0, full_frame);
+static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) { 
+	return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
 }
 
-static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
+static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
 
-	return __find_callno(callno, dcallno, addr, new, sockfd, 1, full_frame);
+	return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
 }
 
 /*!
@@ -3232,9 +3101,9 @@ static int iax2_queue_frame(int callno, struct ast_frame *f)
 }
 
 /*!
- * \brief Queue a hold frame on the ast_channel owner
+ * \brief Queue a hangup frame on the ast_channel owner
  *
- * This function queues a hold frame on the owner of the IAX2 pvt struct that
+ * This function queues a hangup frame on the owner of the IAX2 pvt struct that
  * is active for the given call number.
  *
  * \pre Assumes lock for callno is already held.
@@ -3244,20 +3113,20 @@ static int iax2_queue_frame(int callno, struct ast_frame *f)
  * This function may unlock and lock the mutex associated with this callno,
  * meaning that another thread may grab it and destroy the call.
  */
-static int iax2_queue_hold(int callno, const char *musicclass)
+static int iax2_queue_hangup(int callno)
 {
 	iax2_lock_owner(callno);
 	if (iaxs[callno] && iaxs[callno]->owner) {
-		ast_queue_hold(iaxs[callno]->owner, musicclass);
+		ast_queue_hangup(iaxs[callno]->owner);
 		ast_channel_unlock(iaxs[callno]->owner);
 	}
 	return 0;
 }
 
 /*!
- * \brief Queue an unhold frame on the ast_channel owner
+ * \brief Queue a control frame on the ast_channel owner
  *
- * This function queues an unhold frame on the owner of the IAX2 pvt struct that
+ * This function queues a control frame on the owner of the IAX2 pvt struct that
  * is active for the given call number.
  *
  * \pre Assumes lock for callno is already held.
@@ -3267,45 +3136,270 @@ static int iax2_queue_hold(int callno, const char *musicclass)
  * This function may unlock and lock the mutex associated with this callno,
  * meaning that another thread may grab it and destroy the call.
  */
-static int iax2_queue_unhold(int callno)
+static int iax2_queue_control_data(int callno, 
+	enum ast_control_frame_type control, const void *data, size_t datalen)
 {
 	iax2_lock_owner(callno);
 	if (iaxs[callno] && iaxs[callno]->owner) {
-		ast_queue_unhold(iaxs[callno]->owner);
+		ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
 		ast_channel_unlock(iaxs[callno]->owner);
 	}
 	return 0;
 }
+static void destroy_firmware(struct iax_firmware *cur)
+{
+	/* Close firmware */
+	if (cur->fwh) {
+		munmap((void*)cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
+	}
+	close(cur->fd);
+	ast_free(cur);
+}
 
-/*!
- * \brief Queue a hangup frame on the ast_channel owner
- *
- * This function queues a hangup frame on the owner of the IAX2 pvt struct that
- * is active for the given call number.
- *
- * \pre Assumes lock for callno is already held.
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- * This function may unlock and lock the mutex associated with this callno,
- * meaning that another thread may grab it and destroy the call.
- */
-static int iax2_queue_hangup(int callno)
+static int try_firmware(char *s)
 {
-	iax2_lock_owner(callno);
-	if (iaxs[callno] && iaxs[callno]->owner) {
-		ast_queue_hangup(iaxs[callno]->owner);
-		ast_channel_unlock(iaxs[callno]->owner);
+	struct stat stbuf;
+	struct iax_firmware *cur = NULL;
+	int ifd, fd, res, len, chunk;
+	struct ast_iax2_firmware_header *fwh, fwh2;
+	struct MD5Context md5;
+	unsigned char sum[16], buf[1024];
+	char *s2, *last;
+
+	s2 = ast_alloca(strlen(s) + 100);
+
+	last = strrchr(s, '/');
+	if (last)
+		last++;
+	else
+		last = s;
+
+	snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, ast_random());
+
+	if (stat(s, &stbuf) < 0) {
+		ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));
+		return -1;
+	}
+
+	/* Make sure it's not a directory */
+	if (S_ISDIR(stbuf.st_mode))
+		return -1;
+	ifd = open(s, O_RDONLY);
+	if (ifd < 0) {
+		ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));
+		return -1;
+	}
+	fd = open(s2, O_RDWR | O_CREAT | O_EXCL, AST_FILE_MODE);
+	if (fd < 0) {
+		ast_log(LOG_WARNING, "Cannot open '%s' for writing: %s\n", s2, strerror(errno));
+		close(ifd);
+		return -1;
+	}
+	/* Unlink our newly created file */
+	unlink(s2);
+	
+	/* Now copy the firmware into it */
+	len = stbuf.st_size;
+	while(len) {
+		chunk = len;
+		if (chunk > sizeof(buf))
+			chunk = sizeof(buf);
+		res = read(ifd, buf, chunk);
+		if (res != chunk) {
+			ast_log(LOG_WARNING, "Only read %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
+			close(ifd);
+			close(fd);
+			return -1;
+		}
+		res = write(fd, buf, chunk);
+		if (res != chunk) {
+			ast_log(LOG_WARNING, "Only write %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
+			close(ifd);
+			close(fd);
+			return -1;
+		}
+		len -= chunk;
+	}
+	close(ifd);
+	/* Return to the beginning */
+	lseek(fd, 0, SEEK_SET);
+	if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {
+		ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);
+		close(fd);
+		return -1;
+	}
+	if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {
+		ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);
+		close(fd);
+		return -1;
+	}
+	if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {
+		ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);
+		close(fd);
+		return -1;
 	}
+	if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {
+		ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
+		close(fd);
+		return -1;
+	}
+	fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 
+	if (fwh == MAP_FAILED) {
+		ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	MD5Init(&md5);
+	MD5Update(&md5, fwh->data, ntohl(fwh->datalen));
+	MD5Final(sum, &md5);
+	if (memcmp(sum, fwh->chksum, sizeof(sum))) {
+		ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);
+		munmap((void*)fwh, stbuf.st_size);
+		close(fd);
+		return -1;
+	}
+
+	AST_LIST_TRAVERSE(&firmwares, cur, list) {
+		if (!strcmp((char *)cur->fwh->devname, (char *)fwh->devname)) {
+			/* Found a candidate */
+			if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
+				/* The version we have on loaded is older, load this one instead */
+				break;
+			/* This version is no newer than what we have.  Don't worry about it.
+			   We'll consider it a proper load anyhow though */
+			munmap((void*)fwh, stbuf.st_size);
+			close(fd);
+			return 0;
+		}
+	}
+	
+	if (!cur && ((cur = ast_calloc(1, sizeof(*cur))))) {
+		cur->fd = -1;
+		AST_LIST_INSERT_TAIL(&firmwares, cur, list);
+	}
+	
+	if (cur) {
+		if (cur->fwh)
+			munmap((void*)cur->fwh, cur->mmaplen);
+		if (cur->fd > -1)
+			close(cur->fd);
+		cur->fwh = fwh;
+		cur->fd = fd;
+		cur->mmaplen = stbuf.st_size;
+		cur->dead = 0;
+	}
+	
 	return 0;
 }
 
+static int iax_check_version(char *dev)
+{
+	int res = 0;
+	struct iax_firmware *cur = NULL;
+
+	if (ast_strlen_zero(dev))
+		return 0;
+
+	AST_LIST_LOCK(&firmwares);
+	AST_LIST_TRAVERSE(&firmwares, cur, list) {
+		if (!strcmp(dev, (char *)cur->fwh->devname)) {
+			res = ntohs(cur->fwh->version);
+			break;
+		}
+	}
+	AST_LIST_UNLOCK(&firmwares);
+
+	return res;
+}
+
+static int iax_firmware_append(struct iax_ie_data *ied, const unsigned char *dev, unsigned int desc)
+{
+	int res = -1;
+	unsigned int bs = desc & 0xff;
+	unsigned int start = (desc >> 8) & 0xffffff;
+	unsigned int bytes;
+	struct iax_firmware *cur;
+
+	if (ast_strlen_zero((char *)dev) || !bs)
+		return -1;
+
+	start *= bs;
+	
+	AST_LIST_LOCK(&firmwares);
+	AST_LIST_TRAVERSE(&firmwares, cur, list) {
+		if (strcmp((char *)dev, (char *)cur->fwh->devname))
+			continue;
+		iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
+		if (start < ntohl(cur->fwh->datalen)) {
+			bytes = ntohl(cur->fwh->datalen) - start;
+			if (bytes > bs)
+				bytes = bs;
+			iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);
+		} else {
+			bytes = 0;
+			iax_ie_append(ied, IAX_IE_FWBLOCKDATA);
+		}
+		if (bytes == bs)
+			res = 0;
+		else
+			res = 1;
+		break;
+	}
+	AST_LIST_UNLOCK(&firmwares);
+
+	return res;
+}
+
+
+static void reload_firmware(int unload)
+{
+	struct iax_firmware *cur = NULL;
+	DIR *fwd;
+	struct dirent *de;
+	char dir[256], fn[256];
+
+	AST_LIST_LOCK(&firmwares);
+
+	/* Mark all as dead */
+	AST_LIST_TRAVERSE(&firmwares, cur, list)
+		cur->dead = 1;
+
+	/* Now that we have marked them dead... load new ones */
+	if (!unload) {
+		snprintf(dir, sizeof(dir), "%s/firmware/iax", ast_config_AST_DATA_DIR);
+		fwd = opendir(dir);
+		if (fwd) {
+			while((de = readdir(fwd))) {
+				if (de->d_name[0] != '.') {
+					snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);
+					if (!try_firmware(fn)) {
+						ast_verb(2, "Loaded firmware '%s'\n", de->d_name);
+					}
+				}
+			}
+			closedir(fwd);
+		} else 
+			ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno));
+	}
+
+	/* Clean up leftovers */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&firmwares, cur, list) {
+		if (!cur->dead)
+			continue;
+		AST_LIST_REMOVE_CURRENT(list);
+		destroy_firmware(cur);
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	AST_LIST_UNLOCK(&firmwares);
+}
+
 /*!
  * \note This function assumes that iaxsl[callno] is locked when called.
  *
  * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
  * was valid before calling it, it may no longer be valid after calling it.
- * This function calls iax2_queue_frame(), which may unlock and lock the mutex
+ * This function calls iax2_queue_frame(), which may unlock and lock the mutex 
  * associated with this callno, meaning that another thread may grab it and destroy the call.
  */
 static int __do_deliver(void *data)
@@ -3345,7 +3439,7 @@ static int handle_error(void)
 	else {
 		if (m.msg_controllen) {
 			sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);
-			if (sin)
+			if (sin) 
 				ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(sin->sin_addr));
 			else
 				ast_log(LOG_WARNING, "No address detected??\n");
@@ -3357,11 +3451,11 @@ static int handle_error(void)
 	return 0;
 }
 
-static int transmit_trunk(struct iax_frame *f, struct ast_sockaddr *addr, int sockfd)
+static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd)
 {
 	int res;
-	res = ast_sendto(sockfd, f->data, f->datalen, 0, addr);
-
+	res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,
+					sizeof(*sin));
 	if (res < 0) {
 		ast_debug(1, "Received error: %s\n", strerror(errno));
 		handle_error();
@@ -3380,15 +3474,15 @@ static int send_packet(struct iax_frame *f)
 	    return -1;
 
 	/* Called with iaxsl held */
-	if (iaxdebug) {
-		ast_debug(3, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
-	}
+	if (iaxdebug)
+		ast_debug(3, "Sending %u on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
+
 	if (f->transfer) {
 		iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
-		res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->transfer);
+		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer, sizeof(iaxs[callno]->transfer));
 	} else {
 		iax_outputframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
-		res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->addr);
+		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr, sizeof(iaxs[callno]->addr));
 	}
 	if (res < 0) {
 		if (iaxdebug)
@@ -3525,7 +3619,7 @@ static void __attempt_transmit(const void *data)
 	int callno = f->callno;
 
 	/* Make sure this call is still active */
-	if (callno)
+	if (callno) 
 		ast_mutex_lock(&iaxsl[callno]);
 	if (callno && iaxs[callno]) {
 		if (f->retries < 0) {
@@ -3541,7 +3635,7 @@ static void __attempt_transmit(const void *data)
 			} else {
 				if (iaxs[callno]->owner) {
 					ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %u, subclass = %d, ts=%u, seqno=%d)\n",
-						ast_sockaddr_stringify_addr(&iaxs[f->callno]->addr),
+						ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),
 						ast_channel_name(iaxs[f->callno]->owner),
 						f->af.frametype,
 						f->af.subclass.integer,
@@ -3603,7 +3697,7 @@ static int attempt_transmit(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__attempt_transmit, data))
-#endif
+#endif		
 		__attempt_transmit(data);
 	return 0;
 }
@@ -3775,7 +3869,7 @@ static int peer_status(struct iax2_peer *peer, char *status, int statuslen)
 		} else {
 			ast_copy_string(status, "UNKNOWN", statuslen);
 		}
-	} else {
+	} else { 
 		ast_copy_string(status, "Unmonitored", statuslen);
 		res = -1;
 	}
@@ -3788,9 +3882,9 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
 	char status[30];
 	char cbuf[256];
 	struct iax2_peer *peer;
-	struct ast_str *codec_buf = ast_str_alloca(256);
+	char codec_buf[512];
 	struct ast_str *encmethods = ast_str_alloca(256);
-	int load_realtime = 0;
+	int x = 0, load_realtime = 0;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -3812,13 +3906,9 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
 
 	peer = find_peer(a->argv[3], load_realtime);
 	if (peer) {
-		char *str_addr, *str_defaddr;
-		char *str_port, *str_defport;
+		struct sockaddr_in peer_addr;
 
-		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
-		str_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
-		str_defaddr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->defaddr));
-		str_defport = ast_strdupa(ast_sockaddr_stringify_port(&peer->defaddr));
+		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
 		encmethods_to_str(peer->encmethods, &encmethods);
 		ast_cli(a->fd, "\n\n");
@@ -3836,18 +3926,30 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
 		ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
 		ast_cli(a->fd, "  Expire       : %d\n", peer->expire);
 		ast_cli(a->fd, "  ACL          : %s\n", (ast_acl_list_is_empty(peer->acl) ? "No" : "Yes"));
-		ast_cli(a->fd, "  Addr->IP     : %s Port %s\n",  str_addr ? str_addr : "(Unspecified)", str_port);
-		ast_cli(a->fd, "  Defaddr->IP  : %s Port %s\n", str_defaddr, str_defport);
+		ast_cli(a->fd, "  Addr->IP     : %s Port %d\n",  peer_addr.sin_addr.s_addr ? ast_inet_ntoa(peer_addr.sin_addr) : "(Unspecified)", ntohs(peer_addr.sin_port));
+		ast_cli(a->fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
 		ast_cli(a->fd, "  Username     : %s\n", peer->username);
-		ast_cli(a->fd, "  Codecs       : %s\n", iax2_getformatname_multiple(peer->capability, &codec_buf));
-
-		if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) < 0) {
-			strcpy(cbuf, "Error"); /* Safe */
+		ast_cli(a->fd, "  Codecs       : ");
+		iax2_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
+		ast_cli(a->fd, "%s\n", codec_buf);
+
+		ast_cli(a->fd, "  Codec Order  : (");
+		for(x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+			struct ast_format tmpfmt;
+			if(!(ast_codec_pref_index(&peer->prefs, x, &tmpfmt)))
+				break;
+			ast_cli(a->fd, "%s", ast_getformatname(&tmpfmt));
+			if(x < 31 && ast_codec_pref_index(&peer->prefs, x+1, &tmpfmt))
+				ast_cli(a->fd, "|");
 		}
-		ast_cli(a->fd, "  Codec Order  : %s\n", cbuf);
 
-		peer_status(peer, status, sizeof(status));
-		ast_cli(a->fd, "  Status       : %s\n", status);
+		if (!x)
+			ast_cli(a->fd, "none");
+		ast_cli(a->fd, ")\n");
+
+		ast_cli(a->fd, "  Status       : ");
+		peer_status(peer, status, sizeof(status));	
+		ast_cli(a->fd, "%s\n",status);
 		ast_cli(a->fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
 		ast_cli(a->fd, "\n");
 		peer_unref(peer);
@@ -3949,23 +4051,23 @@ static char *handle_cli_iax2_set_mtu(struct ast_cli_entry *e, int cmd, struct as
 	}
 
 	if (a->argc != 4)
-		return CLI_SHOWUSAGE;
+		return CLI_SHOWUSAGE; 
 	if (strncasecmp(a->argv[3], "default", strlen(a->argv[3])) == 0)
 		mtuv = MAX_TRUNK_MTU;
 	else
 		mtuv = atoi(a->argv[3]);
 
 	if (mtuv == 0) {
-		ast_cli(a->fd, "Trunk MTU control disabled (mtu was %d)\n", global_max_trunk_mtu);
-		global_max_trunk_mtu = 0;
-		return CLI_SUCCESS;
+		ast_cli(a->fd, "Trunk MTU control disabled (mtu was %d)\n", global_max_trunk_mtu); 
+		global_max_trunk_mtu = 0; 
+		return CLI_SUCCESS; 
 	}
 	if (mtuv < 172 || mtuv > 4000) {
-		ast_cli(a->fd, "Trunk MTU must be between 172 and 4000\n");
-		return CLI_SHOWUSAGE;
+		ast_cli(a->fd, "Trunk MTU must be between 172 and 4000\n"); 
+		return CLI_SHOWUSAGE; 
 	}
-	ast_cli(a->fd, "Trunk MTU changed from %d to %d\n", global_max_trunk_mtu, mtuv);
-	global_max_trunk_mtu = mtuv;
+	ast_cli(a->fd, "Trunk MTU changed from %d to %d\n", global_max_trunk_mtu, mtuv); 
+	global_max_trunk_mtu = mtuv; 
 	return CLI_SUCCESS;
 }
 
@@ -4103,7 +4205,7 @@ static void __get_from_jb(const void *p)
 	long ms;
 	long next;
 	struct timeval now = ast_tvnow();
-
+	
 	/* Make sure we have a valid private structure before going on */
 	ast_mutex_lock(&iaxsl[callno]);
 	pvt = iaxs[callno];
@@ -4114,18 +4216,18 @@ static void __get_from_jb(const void *p)
 	}
 
 	pvt->jbid = -1;
-
+	
 	/* round up a millisecond since ast_sched_runq does; */
 	/* prevents us from spinning while waiting for our now */
 	/* to catch up with runq's now */
 	now.tv_usec += 1000;
-
+	
 	ms = ast_tvdiff_ms(now, pvt->rxcore);
-
+	
 	if(ms >= (next = jb_next(pvt->jb))) {
-		struct ast_format *voicefmt;
-		voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
-		ret = jb_get(pvt->jb, &frame, ms, voicefmt ? ast_format_get_default_ms(voicefmt) : 20);
+		struct ast_format voicefmt;
+		ast_format_from_old_bitfield(&voicefmt, pvt->voiceformat);
+		ret = jb_get(pvt->jb, &frame, ms, ast_codec_interp_len(&voicefmt));
 		switch(ret) {
 		case JB_OK:
 			fr = frame.data;
@@ -4136,15 +4238,15 @@ static void __get_from_jb(const void *p)
 		case JB_INTERP:
 		{
 			struct ast_frame af = { 0, };
-
+			
 			/* create an interpolation frame */
 			af.frametype = AST_FRAME_VOICE;
-			af.subclass.format = voicefmt;
-			af.samples  = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000);
+			ast_format_copy(&af.subclass.format, &voicefmt);
+			af.samples  = frame.ms * (ast_format_rate(&voicefmt) / 1000);
 			af.src  = "IAX2 JB interpolation";
 			af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
 			af.offset = AST_FRIENDLY_OFFSET;
-
+			
 			/* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
 			 * which we'd need to malloc, and then it would free it.  That seems like a drag */
 			if (!ast_test_flag64(iaxs[callno], IAX_ALREADYGONE)) {
@@ -4175,7 +4277,7 @@ static int get_from_jb(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__get_from_jb, data))
-#endif
+#endif		
 		__get_from_jb(data);
 	return 0;
 }
@@ -4192,7 +4294,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 	int ret;
 	int needfree = 0;
 	struct ast_channel *owner = NULL;
-	RAII_VAR(struct ast_channel *, bridge, NULL, ast_channel_cleanup);
+	struct ast_channel *bridge = NULL;
 
 	/*
 	 * Clear fr->af.data if there is no data in the buffer.  Things
@@ -4221,7 +4323,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 
 	if(fr->af.frametype == AST_FRAME_VOICE) {
 		type = JB_TYPE_VOICE;
-		len = ast_codec_samples_count(&fr->af) / (ast_format_get_sample_rate(fr->af.subclass.format) / 1000);
+		len = ast_codec_get_samples(&fr->af) / (ast_format_rate(&fr->af.subclass.format) / 1000);
 	} else if(fr->af.frametype == AST_FRAME_CNG) {
 		type = JB_TYPE_SILENCE;
 	}
@@ -4239,9 +4341,8 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 		iax2_frame_free(fr);
 		return -1;
 	}
-	if ((owner = iaxs[fr->callno]->owner)) {
-		bridge = ast_channel_bridge_peer(owner);
-	}
+	if ((owner = iaxs[fr->callno]->owner))
+		bridge = ast_bridged_channel(owner);
 
 	/* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
 	 * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
@@ -4337,7 +4438,7 @@ static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int durati
 
 static int iax2_sendtext(struct ast_channel *c, const char *text)
 {
-
+	
 	return send_command_locked(PTR_TO_CALLNO(ast_channel_tech_pvt(c)), AST_FRAME_TEXT,
 		0, 0, (unsigned char *)text, strlen(text) + 1, -1);
 }
@@ -4368,25 +4469,22 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
  * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this with a pvt lock held.
  */
-static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr)
+static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
 {
 	struct ast_variable *var = NULL;
 	struct ast_variable *tmp;
 	struct iax2_peer *peer=NULL;
 	time_t regseconds = 0, nowtime;
 	int dynamic=0;
-	char *str_addr, *str_port;
-
-	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
-	str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
 	if (peername) {
 		var = ast_load_realtime("iaxpeers", "name", peername, "host", "dynamic", SENTINEL);
-		if (!var && !ast_sockaddr_isnull(addr)) {
-			var = ast_load_realtime("iaxpeers", "name", peername, "host", str_addr, SENTINEL);
-		}
-	} else if (!ast_sockaddr_isnull(addr)) {
-		var = ast_load_realtime("iaxpeers", "ipaddr", str_addr, "port", str_port, SENTINEL);
+		if (!var && sin)
+			var = ast_load_realtime("iaxpeers", "name", peername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
+	} else if (sin) {
+		char porta[25];
+		sprintf(porta, "%d", ntohs(sin->sin_port));
+		var = ast_load_realtime("iaxpeers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
 		if (var) {
 			/* We'll need the peer name in order to build the structure! */
 			for (tmp = var; tmp; tmp = tmp->next) {
@@ -4403,13 +4501,12 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
 		 * is because we only have the IP address and the host field might be
 		 * set as a name (and the reverse PTR might not match).
 		 */
-		if (var && !ast_sockaddr_isnull(addr)) {
+		if (var && sin) {
 			for (tmp = var; tmp; tmp = tmp->next) {
 				if (!strcasecmp(tmp->name, "host")) {
-					struct ast_sockaddr *hostaddr;
-
-					if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
-						|| ast_sockaddr_cmp_addr(hostaddr, addr)) {
+					struct ast_hostent ahp;
+					struct hostent *hp;
+					if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
 						/* No match */
 						ast_variables_destroy(var);
 						var = NULL;
@@ -4441,19 +4538,11 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
 		} else if (!strcasecmp(tmp->name, "regseconds")) {
 			ast_get_time_t(tmp->value, &regseconds, 0, NULL);
 		} else if (!strcasecmp(tmp->name, "ipaddr")) {
-			int setport = ast_sockaddr_port(&peer->addr);
-			if (ast_parse_arg(tmp->value, PARSE_ADDR | PARSE_PORT_FORBID, NULL)) {
+			if (!ast_sockaddr_parse(&peer->addr, tmp->value, PARSE_PORT_IGNORE)) {
 				ast_log(LOG_WARNING, "Failed to parse sockaddr '%s' for ipaddr of realtime peer '%s'\n", tmp->value, tmp->name);
-			} else {
-				ast_sockaddr_parse(&peer->addr, tmp->value, 0);
 			}
-			ast_sockaddr_set_port(&peer->addr, setport);
 		} else if (!strcasecmp(tmp->name, "port")) {
-			int bindport;
-			if (ast_parse_arg(tmp->value, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
-				bindport = IAX_DEFAULT_PORTNO;
-			}
-			ast_sockaddr_set_port(&peer->addr, bindport);
+			ast_sockaddr_set_port(&peer->addr, atoi(tmp->value));
 		} else if (!strcasecmp(tmp->name, "host")) {
 			if (!strcasecmp(tmp->value, "dynamic"))
 				dynamic = 1;
@@ -4462,6 +4551,9 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
 
 	ast_variables_destroy(var);
 
+	if (!peer)
+		return NULL;
+
 	if (ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS)) {
 		ast_copy_flags64(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
 		if (ast_test_flag64(peer, IAX_RTAUTOCLEAR)) {
@@ -4499,23 +4591,21 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
 	return peer;
 }
 
-static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr)
+static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin)
 {
 	struct ast_variable *var;
 	struct ast_variable *tmp;
 	struct iax2_user *user=NULL;
-	char *str_addr, *str_port;
-
-	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
-	str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
 	var = ast_load_realtime("iaxusers", "name", username, "host", "dynamic", SENTINEL);
 	if (!var)
-		var = ast_load_realtime("iaxusers", "name", username, "host", str_addr, SENTINEL);
-	if (!var && !ast_sockaddr_isnull(addr)) {
-		var = ast_load_realtime("iaxusers", "name", username, "ipaddr", str_addr, "port", str_port, SENTINEL);
+		var = ast_load_realtime("iaxusers", "name", username, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
+	if (!var && sin) {
+		char porta[6];
+		snprintf(porta, sizeof(porta), "%d", ntohs(sin->sin_port));
+		var = ast_load_realtime("iaxusers", "name", username, "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
 		if (!var)
-			var = ast_load_realtime("iaxusers", "ipaddr", str_addr, "port", str_port, SENTINEL);
+			var = ast_load_realtime("iaxusers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
 	}
 	if (!var) { /* Last ditch effort */
 		var = ast_load_realtime("iaxusers", "name", username, SENTINEL);
@@ -4528,10 +4618,9 @@ static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr
 		if (var) {
 			for (tmp = var; tmp; tmp = tmp->next) {
 				if (!strcasecmp(tmp->name, "host")) {
-					struct ast_sockaddr *hostaddr;
-
-					if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
-						|| ast_sockaddr_cmp_addr(hostaddr, addr)) {
+					struct ast_hostent ahp;
+					struct hostent *hp;
+					if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
 						/* No match */
 						ast_variables_destroy(var);
 						var = NULL;
@@ -4551,7 +4640,7 @@ static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr
 			if (strcasecmp(tmp->value, "friend") &&
 			    strcasecmp(tmp->value, "user")) {
 				return NULL;
-			}
+			} 
 		}
 		tmp = tmp->next;
 	}
@@ -4575,10 +4664,10 @@ static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr
 
 static void realtime_update_peer(const char *peername, struct ast_sockaddr *sockaddr, time_t regtime)
 {
+	char port[10];
 	char regseconds[20];
 	const char *sysname = ast_config_AST_SYSTEM_NAME;
 	char *syslabel = NULL;
-	char *port;
 
 	if (ast_strlen_zero(sysname))	/* No system name, disable this */
 		sysname = NULL;
@@ -4586,17 +4675,15 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *sock
 		syslabel = "regserver";
 
 	snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
-	port = ast_strdupa(ast_sockaddr_stringify_port(sockaddr));
-	ast_update_realtime("iaxpeers", "name", peername,
-		"ipaddr", ast_sockaddr_isnull(sockaddr) ? "" : ast_sockaddr_stringify_addr(sockaddr),
-		"port", ast_sockaddr_isnull(sockaddr) ? "" : port,
+	snprintf(port, sizeof(port), "%d", ast_sockaddr_port(sockaddr));
+	ast_update_realtime("iaxpeers", "name", peername, 
+		"ipaddr", ast_sockaddr_stringify_addr(sockaddr), "port", port, 
 		"regseconds", regseconds, syslabel, sysname, SENTINEL); /* note syslable can be NULL */
 }
 
 struct create_addr_info {
 	iax2_format capability;
 	uint64_t flags;
-	struct iax2_codec_pref prefs;
 	int maxtime;
 	int encmethods;
 	int found;
@@ -4606,6 +4693,7 @@ struct create_addr_info {
 	char secret[80];
 	char outkey[80];
 	char timezone[80];
+	char prefs[32];
 	char cid_num[80];
 	char cid_name[80];
 	char context[AST_MAX_CONTEXT];
@@ -4614,55 +4702,52 @@ struct create_addr_info {
 	char mohsuggest[MAX_MUSICCLASS];
 };
 
-static int create_addr(const char *peername, struct ast_channel *c, struct ast_sockaddr *addr, struct create_addr_info *cai)
+static int create_addr(const char *peername, struct ast_channel *c, struct sockaddr_in *sin, struct create_addr_info *cai)
 {
 	struct iax2_peer *peer;
 	int res = -1;
+	struct ast_codec_pref ourprefs;
+	struct sockaddr_in peer_addr;
 
 	ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
 	cai->sockfd = defaultsockfd;
 	cai->maxtime = 0;
+	sin->sin_family = AF_INET;
 
 	if (!(peer = find_peer(peername, 1))) {
-		struct ast_sockaddr peer_addr;
+		struct ast_sockaddr sin_tmp;
 
-		peer_addr.ss.ss_family = AST_AF_UNSPEC;
 		cai->found = 0;
-		if (ast_get_ip_or_srv(&peer_addr, peername, srvlookup ? "_iax._udp" : NULL)) {
+		sin_tmp.ss.ss_family = AF_INET;
+		if (ast_get_ip_or_srv(&sin_tmp, peername, srvlookup ? "_iax._udp" : NULL)) {
 			ast_log(LOG_WARNING, "No such host: %s\n", peername);
 			return -1;
 		}
-
-		if (!ast_sockaddr_port(&peer_addr)) {
-			ast_sockaddr_set_port(&peer_addr, IAX_DEFAULT_PORTNO);
+		ast_sockaddr_to_sin(&sin_tmp, sin);
+		if (sin->sin_port == 0) {
+			sin->sin_port = htons(IAX_DEFAULT_PORTNO);
 		}
-
-		ast_sockaddr_copy(addr, &peer_addr);
-		/*
-		 * Use The global iax prefs for unknown peer/user.
-		 * However, move the calling channel's native codec to
-		 * the top of the preference list.
-		 */
-		cai->prefs = prefs_global;
+		/* use global iax prefs for unknown peer/user */
+		/* But move the calling channel's native codec to the top of the preference list */
+		memcpy(&ourprefs, &prefs, sizeof(ourprefs));
 		if (c) {
-			int i;
-
-			for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
-				struct ast_format *format = ast_format_cap_get_format(
-					ast_channel_nativeformats(c), i);
-				iax2_codec_pref_prepend(&cai->prefs, format,
-					ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format),
-					1);
-				ao2_ref(format, -1);
+			struct ast_format tmpfmt;
+			ast_format_cap_iter_start(ast_channel_nativeformats(c));
+			while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
+				ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
 			}
+			ast_format_cap_iter_end(ast_channel_nativeformats(c));
 		}
+		ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
 		return 0;
 	}
 
 	cai->found = 1;
 
+	ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+
 	/* if the peer has no address (current or default), return failure */
-	if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) {
+	if (!(peer_addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr)) {
 		goto return_unref;
 	}
 
@@ -4676,20 +4761,18 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s
 	cai->encmethods = peer->encmethods;
 	cai->sockfd = peer->sockfd;
 	cai->adsi = peer->adsi;
-	cai->prefs = peer->prefs;
+	memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
 	/* Move the calling channel's native codec to the top of the preference list */
 	if (c) {
-		int i;
-
-		for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
-			struct ast_format *tmpfmt = ast_format_cap_get_format(
-				ast_channel_nativeformats(c), i);
-			iax2_codec_pref_prepend(&cai->prefs, tmpfmt,
-				ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt),
-				1);
-			ao2_ref(tmpfmt, -1);
+		struct ast_format tmpfmt;
+		ast_format_cap_iter_start(ast_channel_nativeformats(c));
+		while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
+			ast_debug(1, "prepending %s to prefs\n", ast_getformatname(&tmpfmt));
+			ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
 		}
+		ast_format_cap_iter_end(ast_channel_nativeformats(c));
 	}
+	ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
 	ast_copy_string(cai->context, peer->context, sizeof(cai->context));
 	ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
 	ast_copy_string(cai->username, peer->username, sizeof(cai->username));
@@ -4715,10 +4798,12 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s
 		}
 	}
 
-	if (!ast_sockaddr_isnull(&peer->addr)) {
-		ast_sockaddr_copy(addr, &peer->addr);
+	if (peer_addr.sin_addr.s_addr) {
+		sin->sin_addr = peer_addr.sin_addr;
+		sin->sin_port = peer_addr.sin_port;
 	} else {
-		ast_sockaddr_copy(addr, &peer->defaddr);
+		sin->sin_addr = peer->defaddr.sin_addr;
+		sin->sin_port = peer->defaddr.sin_port;
 	}
 
 	res = 0;
@@ -4746,7 +4831,7 @@ static int auto_congest(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__auto_congest, data))
-#endif
+#endif		
 		__auto_congest(data);
 	return 0;
 }
@@ -4778,7 +4863,7 @@ struct parsed_dial_string {
 };
 
 static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
-		struct ast_sockaddr *addr, int command, int ts, unsigned char seqno,
+		struct sockaddr_in *sin, int command, int ts, unsigned char seqno,
 		int sockfd, struct iax_ie_data *ied)
 {
 	struct {
@@ -4800,9 +4885,9 @@ static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
 	data.f.type = AST_FRAME_IAX;
 	data.f.csub = compress_subclass(command);
 
-	iax_outputframe(NULL, &data.f, 0, addr, size - sizeof(struct ast_iax2_full_hdr));
+	iax_outputframe(NULL, &data.f, 0, sin, size - sizeof(struct ast_iax2_full_hdr));
 
-	return ast_sendto(sockfd, &data, size, 0, addr);
+	return sendto(sockfd, &data, size, 0, (struct sockaddr *)sin, sizeof(*sin));
 }
 
 static void add_empty_calltoken_ie(struct chan_iax2_pvt *pvt, struct iax_ie_data *ied)
@@ -4834,16 +4919,16 @@ static void resend_with_token(int callno, struct iax_frame *f, const char *newto
 		return;  /* this should not be possible if called from socket_process() */
 	}
 
-	/*
+	/* 
 	 * Check to make sure last frame sent is valid for call token resend
-	 * 1. Frame should _NOT_ be encrypted since it starts the IAX dialog
+	 * 1. Frame should _NOT_ be encrypted since it starts the IAX dialog 
 	 * 2. Frame should _NOT_ already have a destination callno
 	 * 3. Frame must be a valid iax_frame subclass capable of starting dialog
 	 * 4. Pvt must have a calltoken_ie_len which represents the number of
 	 *    bytes at the end of the frame used for the previous calltoken ie.
 	 * 5. Pvt's calltoken_ie_len must be _LESS_ than the total IE length
 	 * 6. Total length of f->data must be _LESS_ than size of our data struct
-	 *    because f->data must be able to fit within data.
+	 *    because f->data must be able to fit within data. 
 	 */
 	if (f->encmethods || f->dcallno || !iax2_allow_new(frametype, subclass, 0)
 		|| !pvt->calltoken_ie_len || (pvt->calltoken_ie_len > ie_data_pos) ||
@@ -4924,9 +5009,9 @@ static void requirecalltoken_mark_auto(const char *name, int subclass)
  * \internal
  *
  * \brief handles calltoken logic for a received iax_frame.
- *
+ * 
  * \note frametype must be AST_FRAME_IAX.
- *
+ * 
  * \note
  * Three different cases are possible here.
  * Case 1. An empty calltoken is provided. This means the client supports
@@ -4938,9 +5023,9 @@ static void requirecalltoken_mark_auto(const char *name, int subclass)
  *         to decide how this should be handled (reject or permit without calltoken)
  */
 static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
-		struct ast_sockaddr *addr, int fd)
+		struct sockaddr_in *sin, int fd)
 {
-#define CALLTOKEN_HASH_FORMAT "%s%u%d"  /* address + port + ts + randomcalldata */
+#define CALLTOKEN_HASH_FORMAT "%s%d%u%d"  /* address + port + ts + randomcalldata */
 #define CALLTOKEN_IE_FORMAT   "%u?%s"     /* time + ? + (40 char hash) */
 	struct ast_str *buf = ast_str_alloca(256);
 	time_t t = time(NULL);
@@ -4955,12 +5040,12 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 		};
 
 		/* create the hash with their address data and our timestamp */
-		ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) t, randomcalltokendata);
+		ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) t, randomcalltokendata);
 		ast_sha1_hash(hash, ast_str_buffer(buf));
 
 		ast_str_set(&buf, 0, CALLTOKEN_IE_FORMAT, (unsigned int) t, hash);
 		iax_ie_append_str(&ied, IAX_IE_CALLTOKEN, ast_str_buffer(buf));
-		send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
+		send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
 
 		return 1;
 
@@ -4985,27 +5070,27 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 		}
 
 		/* create a hash with their address and the _TOKEN'S_ timestamp */
-		ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) rec_time, randomcalltokendata);
+		ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) rec_time, randomcalltokendata);
 		ast_sha1_hash(hash, ast_str_buffer(buf));
 
 		/* compare hashes and then check timestamp delay */
 		if (strcmp(hash, rec_hash)) {
-			ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_sockaddr_stringify(addr));
+			ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_inet_ntoa(sin->sin_addr));
 			goto reject; /* received hash does not match ours, reject */
 		} else if ((t < rec_time) || ((t - rec_time) >= MAX_CALLTOKEN_DELAY)) {
-			ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_sockaddr_stringify(addr));
+			ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_inet_ntoa(sin->sin_addr));
 			goto reject; /* too much delay, reject */
 		}
 
-		/* at this point the call token is valid, returning 0
+		/* at this point the call token is valid, returning 0 
 		 * will allow socket_process to continue as usual */
 		requirecalltoken_mark_auto(ies->username, subclass);
 		return 0;
 
 	/* ----- Case 3 ----- */
 	} else { /* calltokens are not supported for this client, how do we respond? */
-		if (calltoken_required(addr, ies->username, subclass)) {
-			ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_sockaddr_stringify(addr), S_OR(ies->username, "guest"));
+		if (calltoken_required(sin, ies->username, subclass)) {
+			ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_inet_ntoa(sin->sin_addr), S_OR(ies->username, "guest"));
 			goto reject;
 		}
 		return 0; /* calltoken is not required for this addr, so permit it. */
@@ -5014,9 +5099,9 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 reject:
 	/* received frame has failed calltoken inspection, send apathetic reject messages */
 	if (subclass == IAX_COMMAND_REGREQ || subclass == IAX_COMMAND_REGREL) {
-		send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+		send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 	} else {
-		send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+		send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 	}
 
 	return 1;
@@ -5038,7 +5123,7 @@ reject:
  * password field will be set to NULL.
  *
  * \note The dial string format is:
- *       [username[:password]@]peer[:port][/exten[@context]][/options]
+ *       [username[:password]@]peer[:port][/exten[@@context]][/options]
  */
 static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 {
@@ -5071,10 +5156,9 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 	pds->peer = strsep(&data, ":");
 	pds->port = data;
 
-	/*
-	 * Check for a key name wrapped in [] in the password position.
-	 * If found, move it to the key field instead.
-	 */
+	/* check for a key name wrapped in [] in the secret position, if found,
+	   move it to the key field instead
+	*/
 	if (pds->password && (pds->password[0] == '[')) {
 		pds->key = ast_strip_quoted(pds->password, "[", "]");
 		pds->password = NULL;
@@ -5083,7 +5167,7 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 
 static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 {
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	char *l=NULL, *n=NULL, *tmpstr;
 	struct iax_ie_data ied;
 	char *defaultrdest = "s";
@@ -5097,7 +5181,6 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	unsigned char osp_block_index;
 	unsigned int osp_block_length;
 	unsigned char osp_buffer[256];
-	char encoded_prefs[32];
 	iax2_format iax2_tmpfmt;
 
 	if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) {
@@ -5119,7 +5202,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	if (!pds.exten) {
 		pds.exten = defaultrdest;
 	}
-	if (create_addr(pds.peer, c, &addr, &cai)) {
+	if (create_addr(pds.peer, c, &sin, &cai)) {
 		ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer);
 		return -1;
 	}
@@ -5144,17 +5227,13 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	/* Keep track of the context for outgoing calls too */
 	ast_channel_context_set(c, cai.context);
 
-	if (pds.port) {
-		int bindport;
-		if (ast_parse_arg(pds.port, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
-			ast_sockaddr_set_port(&addr, bindport);
-		}
-	}
+	if (pds.port)
+		sin.sin_port = htons(atoi(pds.port));
 
 	l = ast_channel_connected(c)->id.number.valid ? ast_channel_connected(c)->id.number.str : NULL;
 	n = ast_channel_connected(c)->id.name.valid ? ast_channel_connected(c)->id.name.str : NULL;
 
-	/* Now build request */
+	/* Now build request */	
 	memset(&ied, 0, sizeof(ied));
 
 	/* On new call, first IE MUST be IAX version of caller */
@@ -5166,8 +5245,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	}
 
 	/* WARNING: this breaks down at 190 bits! */
-	iax2_codec_pref_convert(&cai.prefs, encoded_prefs, sizeof(encoded_prefs), 1);
-	iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, encoded_prefs);
+	iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);
 
 	if (l) {
 		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
@@ -5221,7 +5299,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	iaxs[callno]->encmethods = cai.encmethods;
 
 	iaxs[callno]->adsi = cai.adsi;
-
+	
 	ast_string_field_set(iaxs[callno], mohinterpret, cai.mohinterpret);
 	ast_string_field_set(iaxs[callno], mohsuggest, cai.mohsuggest);
 
@@ -5230,7 +5308,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 	if (pds.password)
 		ast_string_field_set(iaxs[callno], secret, pds.password);
 
-	iax2_tmpfmt = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(c));
+	iax2_tmpfmt = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c));
 	iax_ie_append_int(&ied, IAX_IE_FORMAT, (int) iax2_tmpfmt);
 	iax_ie_append_versioned_uint64(&ied, IAX_IE_FORMAT2, 0, iax2_tmpfmt);
 
@@ -5261,7 +5339,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 				osp_block_index++;
 				osp_token_ptr += osp_block_length;
 				osp_token_length -= osp_block_length;
-			}
+			} 
 		} else
 			ast_log(LOG_WARNING, "OSP token is too long\n");
 	} else if (iaxdebug)
@@ -5454,7 +5532,7 @@ static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *
 	}
 }
 
-static struct ast_frame *iax2_read(struct ast_channel *c)
+static struct ast_frame *iax2_read(struct ast_channel *c) 
 {
 	ast_debug(1, "I should never be called!\n");
 	return &ast_null_frame;
@@ -5492,7 +5570,6 @@ static int iax2_key_rotate(const void *vpvt)
 	return res;
 }
 
-#if defined(IAX2_NATIVE_BRIDGING)
 static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, int mediaonly)
 {
 	int res;
@@ -5527,9 +5604,7 @@ static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, i
 	iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
 	return 0;
 }
-#endif	/* defined(IAX2_NATIVE_BRIDGING) */
 
-#if defined(IAX2_NATIVE_BRIDGING)
 static void lock_both(unsigned short callno0, unsigned short callno1)
 {
 	ast_mutex_lock(&iaxsl[callno0]);
@@ -5537,17 +5612,13 @@ static void lock_both(unsigned short callno0, unsigned short callno1)
 		DEADLOCK_AVOIDANCE(&iaxsl[callno0]);
 	}
 }
-#endif	/* defined(IAX2_NATIVE_BRIDGING) */
 
-#if defined(IAX2_NATIVE_BRIDGING)
 static void unlock_both(unsigned short callno0, unsigned short callno1)
 {
 	ast_mutex_unlock(&iaxsl[callno1]);
 	ast_mutex_unlock(&iaxsl[callno0]);
 }
-#endif	/* defined(IAX2_NATIVE_BRIDGING) */
 
-#if defined(IAX2_NATIVE_BRIDGING)
 static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
 	struct ast_channel *cs[3];
@@ -5600,13 +5671,11 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
 			return AST_BRIDGE_FAILED_NOWARN;
 		}
 		if (!(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) {
-			struct ast_str *c0_buf = ast_str_alloca(64);
-			struct ast_str *c1_buf = ast_str_alloca(64);
-
-			ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n",
-				ast_format_cap_get_names(ast_channel_nativeformats(c0), &c0_buf),
-				ast_format_cap_get_names(ast_channel_nativeformats(c1), &c1_buf));
-
+			char buf0[256];
+			char buf1[256];
+			ast_getformatname_multiple(buf0, sizeof(buf0), ast_channel_nativeformats(c0));
+			ast_getformatname_multiple(buf1, sizeof(buf1), ast_channel_nativeformats(c1));
+			ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", buf0, buf1);
 			/* Remove from native mode */
 			lock_both(callno0, callno1);
 			if (iaxs[callno0])
@@ -5669,7 +5738,7 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
 			break;
 		}
 		other = (who == c0) ? c1 : c0;  /* the 'other' channel */
-		if (f->frametype == AST_FRAME_CONTROL) {
+		if (f->frametype == AST_FRAME_CONTROL && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
 			switch (f->subclass.integer) {
 			case AST_CONTROL_VIDUPDATE:
 			case AST_CONTROL_SRCUPDATE:
@@ -5723,12 +5792,15 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
 	unlock_both(callno0, callno1);
 	return res;
 }
-#endif	/* defined(IAX2_NATIVE_BRIDGING) */
 
 static int iax2_answer(struct ast_channel *c)
 {
 	unsigned short callno = PTR_TO_CALLNO(ast_channel_tech_pvt(c));
 	ast_debug(1, "Answering IAX2 call\n");
+	ast_mutex_lock(&iaxsl[callno]);
+	if (iaxs[callno])
+		iax2_ami_channelupdate(iaxs[callno]);
+	ast_mutex_unlock(&iaxsl[callno]);
 	return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
 }
 
@@ -5772,7 +5844,6 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data,
 		}
 		break;
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 		res = -1;
 		goto done;
 	}
@@ -5805,7 +5876,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
 	return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
 }
 
-static int iax2_getpeertrunk(struct ast_sockaddr addr)
+static int iax2_getpeertrunk(struct sockaddr_in sin)
 {
 	struct iax2_peer *peer;
 	int res = 0;
@@ -5813,8 +5884,12 @@ static int iax2_getpeertrunk(struct ast_sockaddr addr)
 
 	i = ao2_iterator_init(peers, 0);
 	while ((peer = ao2_iterator_next(&i))) {
+		struct sockaddr_in peer_addr;
+
+		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-		if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
+		if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
+		    (peer_addr.sin_port == sin.sin_port)) {
 			res = ast_test_flag64(peer, IAX_TRUNK);
 			peer_unref(peer);
 			break;
@@ -5827,102 +5902,50 @@ static int iax2_getpeertrunk(struct ast_sockaddr addr)
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability,
-	struct iax2_codec_pref *prefs, const struct ast_assigned_ids *assignedids,
-	const struct ast_channel *requestor, unsigned int cachable)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid, unsigned int cachable)
 {
-	struct ast_channel *tmp = NULL;
+	struct ast_channel *tmp;
 	struct chan_iax2_pvt *i;
-	struct iax2_peer *peer;
 	struct ast_variable *v = NULL;
-	struct ast_format_cap *native;
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 	struct ast_callid *callid;
-	char *peer_name = NULL;
 
 	if (!(i = iaxs[callno])) {
 		ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno);
 		return NULL;
 	}
 
-	if (!capability) {
-		ast_log(LOG_WARNING, "No formats specified for call to: IAX2/%s-%d\n",
-			i->host, i->callno);
-		return NULL;
-	}
-	native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!native) {
-		return NULL;
-	}
-	if (iax2_codec_pref_best_bitfield2cap(capability, prefs, native)
-		|| !ast_format_cap_count(native)) {
-		ast_log(LOG_WARNING, "No requested formats available for call to: IAX2/%s-%d\n",
-			i->host, i->callno);
-		ao2_ref(native, -1);
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(i->peer)) {
-		peer_name = ast_strdupa(i->peer);
-	} else if (!ast_strlen_zero(i->host)) {
-		peer_name = ast_strdupa(i->host);
-	}
-
-	/* Don't hold call lock while making a channel or looking up a peer */
+	/* Don't hold call lock */
 	ast_mutex_unlock(&iaxsl[callno]);
-
-	if (!ast_strlen_zero(peer_name)) {
-		peer = find_peer(peer_name, 1);
-		if (peer && peer->endpoint) {
-			tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name,
-				i->accountcode, i->exten, i->context, assignedids, requestor,
-				i->amaflags, peer->endpoint, "IAX2/%s-%d", i->host, i->callno);
-		}
-		ao2_cleanup(peer);
-	}
-
-	if (!tmp) {
-		tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode,
-			i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d",
-			i->host, i->callno);
-	}
-
+	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
 	ast_mutex_lock(&iaxsl[callno]);
 	if (i != iaxs[callno]) {
 		if (tmp) {
 			/* unlock and relock iaxsl[callno] to preserve locking order */
 			ast_mutex_unlock(&iaxsl[callno]);
-			ast_channel_unlock(tmp);
 			tmp = ast_channel_release(tmp);
 			ast_mutex_lock(&iaxsl[callno]);
 		}
-		ao2_ref(native, -1);
 		return NULL;
 	}
+	iax2_ami_channelupdate(i);
 	if (!tmp) {
-		ao2_ref(native, -1);
 		return NULL;
 	}
 
-	ast_channel_stage_snapshot(tmp);
-
 	if ((callid = iaxs[callno]->callid)) {
 		ast_channel_callid_set(tmp, callid);
 	}
 
 	ast_channel_tech_set(tmp, &iax2_tech);
-
 	/* We can support any format by default, until we get restricted */
-	ast_channel_nativeformats_set(tmp, native);
-	tmpfmt = ast_format_cap_get_format(native, 0);
-
-	ast_channel_set_readformat(tmp, tmpfmt);
-	ast_channel_set_rawreadformat(tmp, tmpfmt);
-	ast_channel_set_writeformat(tmp, tmpfmt);
-	ast_channel_set_rawwriteformat(tmp, tmpfmt);
+	ast_format_cap_from_old_bitfield(ast_channel_nativeformats(tmp), capability);
+	ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
 
-	ao2_ref(tmpfmt, -1);
-	ao2_ref(native, -1);
+	ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
 
 	ast_channel_tech_pvt_set(tmp, CALLNO_TO_PTR(i->callno));
 
@@ -6007,16 +6030,11 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
 		}
 	}
 
-	ast_channel_stage_snapshot_done(tmp);
-	ast_channel_unlock(tmp);
-
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(tmp)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
-			/* unlock and relock iaxsl[callno] to preserve locking order */
-			ast_mutex_unlock(&iaxsl[callno]);
 			ast_hangup(tmp);
-			ast_mutex_lock(&iaxsl[callno]);
+			i->owner = NULL;
 			return NULL;
 		}
 	}
@@ -6039,14 +6057,14 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
 	}
 	/* Update last transmit time now */
 	tpeer->lasttxtime = *now;
-
+	
 	/* Calculate ms offset */
 	ms = ast_tvdiff_ms(*now, tpeer->txtrunktime);
 	/* Predict from last value */
 	pred = tpeer->lastsent + sampms;
-	if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
+	if (labs(ms - pred) < MAX_TIMESTAMP_SKEW)
 		ms = pred;
-
+	
 	/* We never send the same timestamp twice, so fudge a little if we must */
 	if (ms == tpeer->lastsent)
 		ms = tpeer->lastsent + 1;
@@ -6075,7 +6093,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 	int voice = 0;
 	int genuine = 0;
 	int adjust;
-	int rate = 0;
+	int rate = ast_format_rate(&f->subclass.format) / 1000;
 	struct timeval *delivery = NULL;
 
 
@@ -6087,7 +6105,6 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 	*/
 	if (f->frametype == AST_FRAME_VOICE) {
 		voice = 1;
-		rate = ast_format_get_sample_rate(f->subclass.format) / 1000;
 		delivery = &f->delivery;
 	} else if (f->frametype == AST_FRAME_IAX) {
 		genuine = 1;
@@ -6117,13 +6134,14 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 			ms = 0;
 		if (voice) {
 			/* On a voice frame, use predicted values if appropriate */
-			if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
+			adjust = (ms - p->nextpred);
+			if (p->notsilenttx && abs(adjust) <= MAX_TIMESTAMP_SKEW) {
 				/* Adjust our txcore, keeping voice and non-voice synchronized */
 				/* AN EXPLANATION:
 				   When we send voice, we usually send "calculated" timestamps worked out
 			 	   on the basis of the number of samples sent. When we send other frames,
 				   we usually send timestamps worked out from the real clock.
-				   The problem is that they can tend to drift out of step because the
+				   The problem is that they can tend to drift out of step because the 
 			    	   source channel's clock and our clock may not be exactly at the same rate.
 				   We fix this by continuously "tweaking" p->offset.  p->offset is "time zero"
 				   for this call.  Moving it adjusts timestamps for non-voice frames.
@@ -6134,9 +6152,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 				   The use of a moving average avoids offset moving too radically.
 				   Generally, "adjust" roams back and forth around 0, with offset hardly
 				   changing at all.  But if a consistent different starts to develop it
-				   will be eliminated over the course of 10 frames (200-300msecs)
+				   will be eliminated over the course of 10 frames (200-300msecs) 
 				*/
-				adjust = (ms - p->nextpred);
 				if (adjust < 0)
 					p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
 				else if (adjust > 0)
@@ -6158,9 +6175,9 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 				* silent periods are multiples of
 				* frame size too) */
 
-				if (iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
+				if (iaxdebug && abs(adjust) > MAX_TIMESTAMP_SKEW )
 					ast_debug(1, "predicted timestamp skew (%d) > max (%d), using real ts instead.\n",
-						abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);
+						abs(adjust), MAX_TIMESTAMP_SKEW);
 
 				if (f->samples >= rate) /* check to make sure we don't core dump */
 				{
@@ -6186,20 +6203,20 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 		} else {
 			/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
 			   it's a genuine frame */
+			adjust = (ms - p->lastsent);
 			if (genuine) {
 				/* genuine (IAX LAGRQ etc) must keep their clock-based stamps */
 				if (ms <= p->lastsent)
 					ms = p->lastsent + 3;
-			} else if (abs(ms - p->lastsent) <= MAX_TIMESTAMP_SKEW) {
+			} else if (abs(adjust) <= MAX_TIMESTAMP_SKEW) {
 				/* non-genuine frames (!?) (DTMF, CONTROL) should be pulled into the predicted stream stamps */
 				ms = p->lastsent + 3;
 			}
 		}
 	}
 	p->lastsent = ms;
-	if (voice) {
+	if (voice)
 		p->nextpred = p->nextpred + f->samples / rate;
-	}
 	return ms;
 }
 
@@ -6243,15 +6260,15 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
 	return ms;
 }
 
-static struct iax2_trunk_peer *find_tpeer(struct ast_sockaddr *addr, int fd)
+static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
 {
 	struct iax2_trunk_peer *tpeer = NULL;
-
+	
 	/* Finds and locks trunk peer */
 	AST_LIST_LOCK(&tpeers);
 
 	AST_LIST_TRAVERSE(&tpeers, tpeer, list) {
-		if (!ast_sockaddr_cmp(&tpeer->addr, addr)) {
+		if (!inaddrcmp(&tpeer->addr, sin)) {
 			ast_mutex_lock(&tpeer->lock);
 			break;
 		}
@@ -6261,15 +6278,14 @@ static struct iax2_trunk_peer *find_tpeer(struct ast_sockaddr *addr, int fd)
 		if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
 			ast_mutex_init(&tpeer->lock);
 			tpeer->lastsent = 9999;
-			ast_sockaddr_copy(&tpeer->addr, addr);
+			memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
 			tpeer->trunkact = ast_tvnow();
 			ast_mutex_lock(&tpeer->lock);
 			tpeer->sockfd = fd;
-
 #ifdef SO_NO_CHECK
 			setsockopt(tpeer->sockfd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
 #endif
-			ast_debug(1, "Created trunk peer for '%s'\n", ast_sockaddr_stringify(&tpeer->addr));
+			ast_debug(1, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
 			AST_LIST_INSERT_TAIL(&tpeers, tpeer, list);
 		}
 	}
@@ -6291,7 +6307,6 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 	f = &fr->af;
 	tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
 	if (tpeer) {
-
 		if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
 			/* Need to reallocate space */
 			if (tpeer->trunkdataalloc < trunkmaxsize) {
@@ -6302,9 +6317,9 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 
 				tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
 				tpeer->trunkdata = tmp;
-				ast_debug(1, "Expanded trunk '%s' to %u bytes\n", ast_sockaddr_stringify(&tpeer->addr), tpeer->trunkdataalloc);
+				ast_debug(1, "Expanded trunk '%s:%d' to %u bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), tpeer->trunkdataalloc);
 			} else {
-				ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s\n", ast_sockaddr_stringify(&tpeer->addr));
+				ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s:%d\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
 				ast_mutex_unlock(&tpeer->lock);
 				return -1;
 			}
@@ -6335,14 +6350,14 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 		tpeer->calls++;
 
 		/* track the largest mtu we actually have sent */
-		if (tpeer->trunkdatalen + f->datalen + 4 > trunk_maxmtu)
-			trunk_maxmtu = tpeer->trunkdatalen + f->datalen + 4 ;
+		if (tpeer->trunkdatalen + f->datalen + 4 > trunk_maxmtu) 
+			trunk_maxmtu = tpeer->trunkdatalen + f->datalen + 4 ; 
 
 		/* if we have enough for a full MTU, ship it now without waiting */
 		if (global_max_trunk_mtu > 0 && tpeer->trunkdatalen + f->datalen + 4 >= global_max_trunk_mtu) {
 			now = ast_tvnow();
-			send_trunk(tpeer, &now);
-			trunk_untimed ++;
+			send_trunk(tpeer, &now); 
+			trunk_untimed ++; 
 		}
 
 		ast_mutex_unlock(&tpeer->lock);
@@ -6387,7 +6402,7 @@ static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len
 		ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
 	for (x=0;x<len;x++)
 		dst[x] = src[x] ^ 0xff;
-#else
+#else	
 	unsigned char lastblock[16] = { 0 };
 	int x;
 	while(len > 0) {
@@ -6418,7 +6433,7 @@ static void memcpy_encrypt(unsigned char *dst, const unsigned char *src, int len
 		for (x=0;x<16;x++)
 			curblock[x] ^= src[x];
 		ast_aes_encrypt(curblock, dst, ecx);
-		memcpy(curblock, dst, sizeof(curblock));
+		memcpy(curblock, dst, sizeof(curblock)); 
 		dst += 16;
 		src += 16;
 		len -= 16;
@@ -6442,7 +6457,7 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 
 		padding = 16 + (workspace[15] & 0x0f);
 		if (iaxdebug)
-			ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, (unsigned)workspace[15]);
+			ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02hhx)\n", *datalen, padding, workspace[15]);
 		if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
 			return -1;
 
@@ -6450,9 +6465,9 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 		memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
 		f->frametype = fh->type;
 		if (f->frametype == AST_FRAME_VIDEO) {
-			f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1));
+			ast_format_from_old_bitfield(&f->subclass.format, (uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1)));
 		} else if (f->frametype == AST_FRAME_VOICE) {
-			f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
+			ast_format_from_old_bitfield(&f->subclass.format, uncompress_subclass(fh->csub));
 		} else {
 			f->subclass.integer = uncompress_subclass(fh->csub);
 		}
@@ -6489,7 +6504,7 @@ static int encrypt_frame(ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh,
 		workspace[15] &= 0xf0;
 		workspace[15] |= (padding & 0xf);
 		if (iaxdebug)
-			ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, (unsigned)workspace[15]);
+			ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02hhx)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
 		*datalen += padding;
 		memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
 		if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
@@ -6520,7 +6535,7 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
 		struct MD5Context md5;
 		unsigned char digest[16];
 		char *tmppw, *stringp;
-
+		
 		tmppw = ast_strdupa(iaxs[callno]->secret);
 		stringp = tmppw;
 		while ((tmppw = strsep(&stringp, ";"))) {
@@ -6535,7 +6550,7 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
 				break;
 			}
 		}
-	} else
+	} else 
 		res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
 	return res;
 }
@@ -6564,7 +6579,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		ast_log(LOG_WARNING, "No private structure for packet?\n");
 		return -1;
 	}
-
+	
 	lastsent = pvt->lastsent;
 
 	/* Calculate actual timestamp */
@@ -6576,7 +6591,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 	if(f->frametype == AST_FRAME_VOICE && f->datalen == 0)
 		return 0;
 #if 0
-	ast_log(LOG_NOTICE,
+	ast_log(LOG_NOTICE, 
 		"f->frametype %c= AST_FRAME_VOICE, %sencrypted, %srotation scheduled...\n",
 		*("=!" + (f->frametype == AST_FRAME_VOICE)),
 		IAX_CALLENCRYPTED(pvt) ? "" : "not ",
@@ -6587,14 +6602,13 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		iax2_key_rotate(pvt);
 	}
 
-	if ((ast_test_flag64(pvt, IAX_TRUNK) ||
+	if ((ast_test_flag64(pvt, IAX_TRUNK) || 
 			(((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) ||
 			((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L))))
 		/* High two bytes are the same on timestamp, or sending on a trunk */ &&
-	    (f->frametype == AST_FRAME_VOICE)
+	    (f->frametype == AST_FRAME_VOICE) 
 		/* is a voice frame */ &&
-		(ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svoiceformat)) ==
-			AST_FORMAT_CMP_EQUAL)
+		(f->subclass.format.id == ast_format_id_from_old_bitfield(pvt->svoiceformat))
 		/* is the same type */ ) {
 			/* Force immediate rather than delayed transmission */
 			now = 1;
@@ -6608,8 +6622,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		 * Otherwise send a mini video frame
 		 */
 		if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) &&
-		(ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svideoformat)) ==
-			AST_FORMAT_CMP_EQUAL)
+		    ((f->subclass.format.id) == ast_format_id_from_old_bitfield(pvt->svideoformat))
 		   ) {
 			now = 1;
 			sendmini = 1;
@@ -6664,11 +6677,11 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		fh->type = fr->af.frametype & 0xFF;
 
 		if (fr->af.frametype == AST_FRAME_VIDEO) {
-			iax2_format tmpfmt = ast_format_compatibility_format2bitfield(fr->af.subclass.format);
-			tmpfmt |= fr->af.subclass.frame_ending ? 0x1LL : 0;
+			iax2_format tmpfmt = ast_format_to_old_bitfield(&fr->af.subclass.format);
+			tmpfmt |= ast_format_get_video_mark(&fr->af.subclass.format) ? 0x1LL : 0;
 			fh->csub = compress_subclass(tmpfmt | ((tmpfmt & 0x1LL) << 6));
 		} else if (fr->af.frametype == AST_FRAME_VOICE) {
-			fh->csub = compress_subclass(ast_format_compatibility_format2bitfield(fr->af.subclass.format));
+			fh->csub = compress_subclass(ast_format_to_old_bitfield(&fr->af.subclass.format));
 		} else {
 			fh->csub = compress_subclass(fr->af.subclass.integer);
 		}
@@ -6691,9 +6704,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		if ((f->frametype == AST_FRAME_IAX) && (f->subclass.integer == IAX_COMMAND_ACK))
 			fr->retries = -1;
 		else if (f->frametype == AST_FRAME_VOICE)
-			pvt->svoiceformat = ast_format_compatibility_format2bitfield(f->subclass.format);
+			pvt->svoiceformat = ast_format_to_old_bitfield(&f->subclass.format);
 		else if (f->frametype == AST_FRAME_VIDEO)
-			pvt->svideoformat = ast_format_compatibility_format2bitfield(f->subclass.format);
+			pvt->svideoformat = ast_format_to_old_bitfield(&f->subclass.format);
 		if (ast_test_flag64(pvt, IAX_ENCRYPTED)) {
 			if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) {
 				if (fr->transfer)
@@ -6724,7 +6737,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 			vh = (struct ast_iax2_video_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_video_hdr));
 			vh->zeros = 0;
 			vh->callno = htons(0x8000 | fr->callno);
-			vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass.frame_ending ? 0x8000 : 0));
+			vh->ts = htons((fr->ts & 0x7FFF) | (ast_format_get_video_mark(&fr->af.subclass.format) ? 0x8000 : 0));
 			fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
 			fr->data = vh;
 			fr->retries = -1;
@@ -6813,7 +6826,7 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
 		else
 			pstr = ast_test_flag64(user, IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
 
-		ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods,
+		ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods, 
 			user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
 			ast_acl_list_is_empty(user->acl) ? "No" : "Yes", pstr);
 	}
@@ -6827,190 +6840,50 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
 #undef FORMAT2
 }
 
-struct show_peers_context {
-	regex_t regexbuf;
-	int havepattern;
-	char idtext[256];
-	int registeredonly;
-	int peerlist;
-	int total_peers;
-	int online_peers;
-	int offline_peers;
-	int unmonitored_peers;
-};
-
-#define PEERS_FORMAT2 "%-15.15s  %-40.40s %s   %-40.40s  %-9s %s  %-11s %-32.32s\n"
-#define PEERS_FORMAT "%-15.15s  %-40.40s %s  %-40.40s  %-6s%s %s  %-11s %-32.32s\n"
-
-static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers_context *cont, struct iax2_peer *peer)
-{
-	char name[256] = "";
-	char status[20];
-	int retstatus;
-	struct ast_str *encmethods = ast_str_alloca(256);
-
-	char *tmp_host, *tmp_mask, *tmp_port;
-
-	tmp_host = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
-	tmp_mask = ast_strdupa(ast_sockaddr_stringify_addr(&peer->mask));
-	tmp_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
-
-	if (!ast_strlen_zero(peer->username)) {
-		snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
-	} else {
-		ast_copy_string(name, peer->name, sizeof(name));
-	}
-
-	encmethods_to_str(peer->encmethods, &encmethods);
-	retstatus = peer_status(peer, status, sizeof(status));
-	if (retstatus > 0) {
-		cont->online_peers++;
-	} else if (!retstatus) {
-		cont->offline_peers++;
-	} else {
-		cont->unmonitored_peers++;
-	}
-
-	if (s) {
-
-		if (cont->peerlist) { /* IAXpeerlist */
-
-			astman_append(s,
-				"Event: PeerEntry\r\n%s"
-				"Channeltype: IAX\r\n",
-				cont->idtext);
-
-			if (!ast_strlen_zero(peer->username)) {
-
-				astman_append(s,
-					"ObjectName: %s\r\n"
-					"ObjectUsername: %s\r\n",
-					peer->name,
-					peer->username);
-
-			} else {
-
-				astman_append(s,
-					"ObjectName: %s\r\n",
-					name);
-			}
-
-		} else { /* IAXpeers */
-
-			astman_append(s,
-				"Event: PeerEntry\r\n%s"
-				"Channeltype: IAX2\r\n"
-				"ObjectName: %s\r\n",
-				cont->idtext,
-				name);
-		}
-
-		astman_append(s,
-			"ChanObjectType: peer\r\n"
-			"IPaddress: %s\r\n",
-			tmp_host);
-
-		if (cont->peerlist) { /* IAXpeerlist */
-
-			astman_append(s,
-				"Mask: %s\r\n"
-				"Port: %s\r\n",
-				tmp_mask,
-				tmp_port);
-
-		} else { /* IAXpeers */
-
-			astman_append(s,
-				"IPport: %s\r\n",
-				tmp_port);
-
-		}
-
-		astman_append(s,
-			"Dynamic: %s\r\n"
-			"Trunk: %s\r\n"
-			"Encryption: %s\r\n"
-			"Status: %s\r\n",
-			ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
-			ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
-			peer->encmethods ? ast_str_buffer(encmethods) : "no",
-			status);
-
-		if (cont->peerlist) { /* IAXpeerlist */
-
-			astman_append(s, "\r\n");
-
-		} else { /* IAXpeers */
-
-			astman_append(s,
-				"Description: %s\r\n\r\n",
-				peer->description);
-
-		}
-
-	} else {
-		ast_cli(fd, PEERS_FORMAT,
-			name,
-			tmp_host,
-			ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
-			tmp_mask,
-			tmp_port,
-			ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
-			peer->encmethods ? "(E)" : "   ",
-			status,
-			peer->description);
-	}
-
-	cont->total_peers++;
-
-}
-
 static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int argc, const char * const argv[])
 {
-	struct show_peers_context cont = {
-		.havepattern = 0,
-		.idtext = "",
-		.registeredonly = 0,
-
-		.peerlist = 0,
-
-		.total_peers = 0,
-		.online_peers = 0,
-		.offline_peers = 0,
-		.unmonitored_peers = 0,
-	};
-
+	regex_t regexbuf;
+	int havepattern = 0;
+	int total_peers = 0;
+	int online_peers = 0;
+	int offline_peers = 0;
+	int unmonitored_peers = 0;
 	struct ao2_iterator i;
 
-	struct iax2_peer *peer = NULL;
+#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-11s %-32.32s\n"
+#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-11s %-32.32s\n"
 
+	struct iax2_peer *peer = NULL;
+	char name[256];
+	struct ast_str *encmethods = ast_str_alloca(256);
+	int registeredonly=0;
+	char idtext[256] = "";
 	switch (argc) {
 	case 6:
 		if (!strcasecmp(argv[3], "registered"))
-			cont.registeredonly = 1;
+			registeredonly = 1;
 		else
 			return RESULT_SHOWUSAGE;
 		if (!strcasecmp(argv[4], "like")) {
-			if (regcomp(&cont.regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
+			if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
 				return RESULT_SHOWUSAGE;
-			cont.havepattern = 1;
+			havepattern = 1;
 		} else
 			return RESULT_SHOWUSAGE;
 		break;
 	case 5:
 		if (!strcasecmp(argv[3], "like")) {
-			if (regcomp(&cont.regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
+			if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
 				return RESULT_SHOWUSAGE;
-			cont.havepattern = 1;
+			havepattern = 1;
 		} else
 			return RESULT_SHOWUSAGE;
 		break;
 	case 4:
-		if (!strcasecmp(argv[3], "registered")) {
-			cont.registeredonly = 1;
-		} else {
+ 		if (!strcasecmp(argv[3], "registered"))
+			registeredonly = 1;
+		else
 			return RESULT_SHOWUSAGE;
-		}
 		break;
 	case 3:
 		break;
@@ -7019,43 +6892,92 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
 	}
 
 
-	if (!s) {
-		ast_cli(fd, PEERS_FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
-	}
+	if (!s)
+		ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
 
 	i = ao2_iterator_init(peers, 0);
 	for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
+		char nm[20];
+		char status[20];
+		int retstatus;
+		struct sockaddr_in peer_addr;
 
-		if (cont.registeredonly && ast_sockaddr_isnull(&peer->addr)) {
+		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+
+		if (registeredonly && !peer_addr.sin_addr.s_addr) {
 			continue;
 		}
-		if (cont.havepattern && regexec(&cont.regexbuf, peer->name, 0, NULL, 0)) {
+		if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
 			continue;
 		}
 
-		_iax2_show_peers_one(fd, s, &cont, peer);
+		if (!ast_strlen_zero(peer->username))
+			snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
+		else
+			ast_copy_string(name, peer->name, sizeof(name));
+
+		encmethods_to_str(peer->encmethods, &encmethods);
+		retstatus = peer_status(peer, status, sizeof(status));
+		if (retstatus > 0)
+			online_peers++;
+		else if (!retstatus)
+			offline_peers++;
+		else
+			unmonitored_peers++;
+
+		ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
 
+		if (s) {
+			astman_append(s,
+				"Event: PeerEntry\r\n%s"
+				"Channeltype: IAX2\r\n"
+				"ObjectName: %s\r\n"
+				"ChanObjectType: peer\r\n"
+				"IPaddress: %s\r\n"
+				"IPport: %d\r\n"
+				"Dynamic: %s\r\n"
+				"Trunk: %s\r\n"
+				"Encryption: %s\r\n"
+				"Status: %s\r\n"
+				"Description: %s\r\n\r\n",
+				idtext,
+				name,
+				ast_sockaddr_stringify_addr(&peer->addr),
+				ast_sockaddr_port(&peer->addr),
+				ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
+				ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
+				peer->encmethods ? ast_str_buffer(encmethods) : "no",
+				status,
+				peer->description);
+		} else {
+			ast_cli(fd, FORMAT, name,
+				ast_sockaddr_stringify_addr(&peer->addr),
+				ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
+				nm,
+				ast_sockaddr_port(&peer->addr),
+				ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
+				peer->encmethods ? "(E)" : "   ",
+				status,
+				peer->description);
+		}
+		total_peers++;
 	}
 	ao2_iterator_destroy(&i);
 
-	if (!s) {
+	if (!s)
 		ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]\n",
-			cont.total_peers, cont.online_peers, cont.offline_peers, cont.unmonitored_peers);
-	}
+			total_peers, online_peers, offline_peers, unmonitored_peers);
 
-	if (cont.havepattern) {
-		regfree(&cont.regexbuf);
-	}
+	if (havepattern)
+		regfree(&regexbuf);
 
-	if (total) {
-		*total = cont.total_peers;
-	}
+	if (total)
+		*total = total_peers;
 
 	return RESULT_SUCCESS;
-
+#undef FORMAT
+#undef FORMAT2
 }
-#undef PEERS_FORMAT2
-#undef PEERS_FORMAT
 
 static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -7076,17 +6998,17 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
 	}
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
-
+		
 	ast_cli(a->fd, "IAX2 Thread Information\n");
 	time(&t);
 	ast_cli(a->fd, "Idle Threads:\n");
 	AST_LIST_LOCK(&idle_list);
 	AST_LIST_TRAVERSE(&idle_list, thread, list) {
 #ifdef DEBUG_SCHED_MULTITHREAD
-		ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n",
+		ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n", 
 			thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-		ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n",
+		ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n", 
 			thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
 		threadcount++;
@@ -7100,10 +7022,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
 		else
 			type = 'P';
 #ifdef DEBUG_SCHED_MULTITHREAD
-		ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d, func='%s'\n",
+		ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d, func='%s'\n", 
 			type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-		ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d\n",
+		ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d\n", 
 			type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
 		threadcount++;
@@ -7178,7 +7100,7 @@ static char *complete_iax2_unregister(const char *line, const char *word, int po
 	if (pos == 2) {
 		struct ao2_iterator i = ao2_iterator_init(peers, 0);
 		while ((p = ao2_iterator_next(&i))) {
-			if (!strncasecmp(p->name, word, wordlen) &&
+			if (!strncasecmp(p->name, word, wordlen) && 
 				++which > state && p->expire > 0) {
 				res = ast_strdup(p->name);
 				peer_unref(p);
@@ -7224,21 +7146,10 @@ static int manager_iax2_show_netstats(struct mansession *s, const struct message
 	return RESULT_SUCCESS;
 }
 
-static int firmware_show_callback(struct ast_iax2_firmware_header *header,
-	void *user_data)
-{
-	int *fd = user_data;
-
-	ast_cli(*fd, "%-15.15s  %-15d %-15d\n",
-		header->devname,
-		ntohs(header->version),
-		(int) ntohl(header->datalen));
-
-	return 0;
-}
-
 static char *handle_cli_iax2_show_firmware(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
+	struct iax_firmware *cur = NULL;
+
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "iax2 show firmware";
@@ -7254,11 +7165,14 @@ static char *handle_cli_iax2_show_firmware(struct ast_cli_entry *e, int cmd, str
 		return CLI_SHOWUSAGE;
 
 	ast_cli(a->fd, "%-15.15s  %-15.15s %-15.15s\n", "Device", "Version", "Size");
-
-	iax_firmware_traverse(
-		a->argc == 3 ? NULL : a->argv[3],
-		firmware_show_callback,
-		(void *) &a->fd);
+	AST_LIST_LOCK(&firmwares);
+	AST_LIST_TRAVERSE(&firmwares, cur, list) {
+		if ((a->argc == 3) || (!strcasecmp(a->argv[3], (char *) cur->fwh->devname)))  {
+			ast_cli(a->fd, "%-15.15s  %-15d %-15d\n", cur->fwh->devname, 
+				ntohs(cur->fwh->version), (int)ntohl(cur->fwh->datalen));
+		}
+	}
+	AST_LIST_UNLOCK(&firmwares);
 
 	return CLI_SUCCESS;
 }
@@ -7290,48 +7204,45 @@ static int manager_iax2_show_peers(struct mansession *s, const struct message *m
 /*! \brief callback to display iax peers in manager format */
 static int manager_iax2_show_peer_list(struct mansession *s, const struct message *m)
 {
-	struct show_peers_context cont = {
-		.havepattern = 0,
-		.idtext = "",
-		.registeredonly = 0,
-
-		.peerlist = 1,
-
-		.total_peers = 0,
-		.online_peers = 0,
-		.offline_peers = 0,
-		.unmonitored_peers = 0,
-	};
-
 	struct iax2_peer *peer = NULL;
-	struct ao2_iterator i;
-
+	int peer_count = 0;
+	char nm[20];
+	char status[20];
 	const char *id = astman_get_header(m,"ActionID");
+	char idtext[256] = "";
+	struct ast_str *encmethods = ast_str_alloca(256);
+	struct ao2_iterator i;
 
-	if (!ast_strlen_zero(id)) {
-		snprintf(cont.idtext, sizeof(cont.idtext), "ActionID: %s\r\n", id);
-	}
+	if (!ast_strlen_zero(id))
+		snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
 
-	astman_append(s,
-		"Response: Success\r\n"
-		"%sMessage: IAX Peer status list will follow\r\n\r\n",
-		cont.idtext);
+	astman_append(s, "Response: Success\r\n%sMessage: IAX Peer status list will follow\r\n\r\n", idtext);
 
 
 	i = ao2_iterator_init(peers, 0);
 	for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-
-		_iax2_show_peers_one(-1, s, &cont, peer);
-
+		encmethods_to_str(peer->encmethods, &encmethods);
+		astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
+		if (!ast_strlen_zero(peer->username)) {
+			astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username);
+		} else {
+			astman_append(s, "ObjectName: %s\r\n", peer->name);
+		}
+		astman_append(s, "ChanObjectType: peer\r\n");
+		astman_append(s, "IPaddress: %s\r\n", ast_sockaddr_stringify_addr(&peer->addr));
+		ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
+		astman_append(s, "Mask: %s\r\n", nm);
+		astman_append(s, "Port: %d\r\n", ast_sockaddr_port(&peer->addr));
+		astman_append(s, "Dynamic: %s\r\n", ast_test_flag64(peer, IAX_DYNAMIC) ? "Yes" : "No");
+		astman_append(s, "Trunk: %s\r\n", ast_test_flag64(peer, IAX_TRUNK) ? "Yes" : "No");
+		astman_append(s, "Encryption: %s\r\n", peer->encmethods ? ast_str_buffer(encmethods) : "No");
+		peer_status(peer, status, sizeof(status));
+		astman_append(s, "Status: %s\r\n\r\n", status);
+		peer_count++;
 	}
 	ao2_iterator_destroy(&i);
 
-	astman_append(s,
-		"Event: PeerlistComplete\r\n"
-		"%sListItems: %d\r\n\r\n",
-		cont.idtext,
-		cont.total_peers);
-
+	astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
 	return RESULT_SUCCESS;
 }
 
@@ -7360,9 +7271,8 @@ static char *regstate2str(int regstate)
 
 static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8.8s  %s\n"
-#define FORMAT  "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8d  %s\n"
-
+#define FORMAT2 "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8.8s  %s\n"
+#define FORMAT  "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8d  %s\n"
 	struct iax2_registry *reg = NULL;
 	char host[80];
 	char perceived[80];
@@ -7384,12 +7294,13 @@ static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, str
 	AST_LIST_LOCK(&registrations);
 	AST_LIST_TRAVERSE(&registrations, reg, entry) {
 		snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
-
-		snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
-
-		ast_cli(a->fd, FORMAT, host,
-				(reg->dnsmgr) ? "Y" : "N",
-				reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
+		if (reg->us.sin_addr.s_addr) 
+			snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
+		else
+			ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
+		ast_cli(a->fd, FORMAT, host, 
+					(reg->dnsmgr) ? "Y" : "N", 
+					reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
 		counter++;
 	}
 	AST_LIST_UNLOCK(&registrations);
@@ -7416,9 +7327,13 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
 	AST_LIST_LOCK(&registrations);
 	AST_LIST_TRAVERSE(&registrations, reg, entry) {
 		snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
-
-		snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
-
+		
+		if (reg->us.sin_addr.s_addr) {
+			snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
+		} else {
+			ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
+		}
+		
 		astman_append(s,
 			"Event: RegistryEntry\r\n"
 			"%s"
@@ -7428,7 +7343,7 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
 			"Perceived: %s\r\n"
 			"Refresh: %d\r\n"
 			"State: %s\r\n"
-			"\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived,
+			"\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived, 
 			reg->refresh, regstate2str(reg->regstate));
 
 		total++;
@@ -7441,15 +7356,15 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
 		"ListItems: %d\r\n"
 		"%s"
 		"\r\n", total, idtext);
-
+	
 	return 0;
 }
 
 static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-20.20s  %-40.40s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
-#define FORMAT  "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
-#define FORMATB "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
+#define FORMAT2 "%-20.20s  %-15.15s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
+#define FORMAT  "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
+#define FORMATB "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
 	int x;
 	int numchans = 0;
 	char first_message[10] = { 0, };
@@ -7488,7 +7403,7 @@ static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, str
 			lag = iaxs[x]->remote_rr.delay;
 			ast_cli(a->fd, FORMAT,
 				iaxs[x]->owner ? ast_channel_name(iaxs[x]->owner) : "(None)",
-				ast_sockaddr_stringify_addr(&iaxs[x]->addr),
+				ast_inet_ntoa(iaxs[x]->addr.sin_addr),
 				S_OR(iaxs[x]->username, "(None)"),
 				iaxs[x]->callno, iaxs[x]->peercallno,
 				iaxs[x]->oseqno, iaxs[x]->iseqno,
@@ -7638,6 +7553,8 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
 
 	if (!strcasecmp(a->argv[3], "peer")) {
 		struct iax2_peer *peer;
+		struct sockaddr_in peer_addr;
+
 
 		if (a->argc != e->args + 1)
 			return CLI_SHOWUSAGE;
@@ -7649,9 +7566,13 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
 			return CLI_FAILURE;
 		}
 
-		ast_sockaddr_copy(&debugaddr, &peer->addr);
+		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-		ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_port(&debugaddr));
+		debugaddr.sin_addr = peer_addr.sin_addr;
+		debugaddr.sin_port = peer_addr.sin_port;
+
+		ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%d\n",
+			ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));
 
 		ao2_ref(peer, -1);
 	} else if (!strncasecmp(a->argv[3], "on", 2)) {
@@ -7706,7 +7627,7 @@ static char *handle_cli_iax2_set_debug_jb(struct ast_cli_entry *e, int cmd, stru
 
 	if (a->argc != e->args)
 		return CLI_SHOWUSAGE;
-
+	
 	if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
 		jb_setoutput(jb_error_output, jb_warning_output, jb_debug_output);
 		ast_cli(a->fd, "IAX2 Jitterbuffer Debugging Enabled\n");
@@ -7787,7 +7708,7 @@ static int send_command_locked(unsigned short callno, char type, int command, un
 
 /*!
  * \note Since this function calls iax2_predestroy() -> iax2_queue_hangup(),
- *       the pvt struct for the given call number may disappear during its
+ *       the pvt struct for the given call number may disappear during its 
  *       execution.
  */
 static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
@@ -7821,7 +7742,7 @@ static int apply_context(struct iax2_context *con, const char *context)
 }
 
 
-static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
+static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
 {
 	/* Start pessimistic */
 	int res = -1;
@@ -7831,13 +7752,14 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 	int gotcapability = 0;
 	struct ast_variable *v = NULL, *tmpvar = NULL;
 	struct ao2_iterator i;
+	struct ast_sockaddr addr;
 
 	if (!iaxs[callno])
 		return res;
 	if (ies->called_number)
 		ast_string_field_set(iaxs[callno], exten, ies->called_number);
 	if (ies->calling_number) {
-		if (ast_test_flag64(&globalflags, IAX_SHRINKCALLERID)) {
+		if (ast_test_flag64(&globalflags, IAX_SHRINKCALLERID)) { 
 			ast_shrink_phone_number(ies->calling_number);
 		}
 		ast_string_field_set(iaxs[callno], cid_num, ies->calling_number);
@@ -7869,32 +7791,30 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 	if (ies->capability) {
 		gotcapability = 1;
 		iaxs[callno]->peercapability = ies->capability;
-	}
+	} 
 	if (ies->version)
 		version = ies->version;
 
 	/* Use provided preferences until told otherwise for actual preferences */
 	if (ies->codec_prefs) {
-		iax2_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
-	} else {
-		memset(&iaxs[callno]->rprefs, 0, sizeof(iaxs[callno]->rprefs));
+		ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
+		ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
 	}
-	iaxs[callno]->prefs = iaxs[callno]->rprefs;
 
-	if (!gotcapability) {
+	if (!gotcapability) 
 		iaxs[callno]->peercapability = iaxs[callno]->peerformat;
-	}
 	if (version > IAX_PROTO_VERSION) {
-		ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n",
-				ast_sockaddr_stringify_addr(addr), version);
+		ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n", 
+			ast_inet_ntoa(sin->sin_addr), version);
 		return res;
 	}
 	/* Search the userlist for a compatible entry, and fill in the rest */
+	ast_sockaddr_from_sin(&addr, sin);
 	i = ao2_iterator_init(users, 0);
 	while ((user = ao2_iterator_next(&i))) {
 		if ((ast_strlen_zero(iaxs[callno]->username) ||				/* No username specified */
 			!strcmp(iaxs[callno]->username, user->name))	/* Or this username specified */
-			&& (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)	/* Access is permitted from this IP */
+			&& (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)	/* Access is permitted from this IP */
 			&& (ast_strlen_zero(iaxs[callno]->context) ||			/* No context specified */
 			     apply_context(user->contexts, iaxs[callno]->context))) {			/* Context is permitted */
 			if (!ast_strlen_zero(iaxs[callno]->username)) {
@@ -7951,8 +7871,8 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 	ao2_iterator_destroy(&i);
 	user = best;
 	if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
-		user = realtime_user(iaxs[callno]->username, addr);
-		if (user && (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_DENY		/* Access is denied from this IP */
+		user = realtime_user(iaxs[callno]->username, sin);
+		if (user && (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_DENY		/* Access is denied from this IP */
 			|| (!ast_strlen_zero(iaxs[callno]->context) &&					/* No context specified */
 				!apply_context(user->contexts, iaxs[callno]->context)))) {	/* Context is permitted */
 			user = user_unref(user);
@@ -7963,7 +7883,7 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 		/* copy vars */
 		for (v = user->vars ; v ; v = v->next) {
 			if((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
-				tmpvar->next = iaxs[callno]->vars;
+				tmpvar->next = iaxs[callno]->vars; 
 				iaxs[callno]->vars = tmpvar;
 			}
 		}
@@ -8014,7 +7934,7 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 			iaxs[callno]->amaflags = user->amaflags;
 		if (!ast_strlen_zero(user->language))
 			ast_string_field_set(iaxs[callno], language, user->language);
-		ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+		ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);	
 		/* Keep this check last */
 		if (!ast_strlen_zero(user->dbsecret)) {
 			char *family, *key=NULL;
@@ -8046,11 +7966,11 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 			res = 0;
 		}
 	}
-	ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*addr), IAX_TRUNK);
+	ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
 	return res;
 }
 
-static int raw_hangup(struct ast_sockaddr *addr, unsigned short src, unsigned short dst, int sockfd)
+static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd)
 {
 	struct ast_iax2_full_hdr fh;
 	fh.scallno = htons(src | IAX_FLAG_FULL);
@@ -8060,10 +7980,10 @@ static int raw_hangup(struct ast_sockaddr *addr, unsigned short src, unsigned sh
 	fh.iseqno = 0;
 	fh.type = AST_FRAME_IAX;
 	fh.csub = compress_subclass(IAX_COMMAND_INVAL);
-	iax_outputframe(NULL, &fh, 0, addr, 0);
-
-	ast_debug(1, "Raw Hangup %s, src=%d, dst=%d\n", ast_sockaddr_stringify(addr), src, dst);
-	return ast_sendto(sockfd, &fh, sizeof(fh), 0, addr);
+	iax_outputframe(NULL, &fh, 0, sin, 0);
+	ast_debug(1, "Raw Hangup %s:%d, src=%d, dst=%d\n",
+		ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), src, dst);
+	return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
 }
 
 static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc)
@@ -8144,14 +8064,13 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 	char md5secret[256] = "";
 	char secret[256] = "";
 	char rsasecret[256] = "";
-	int res = -1;
+	int res = -1; 
 	int x;
 	struct iax2_user *user;
 
 	if (p->authrej) {
 		return res;
 	}
-
 	user = ao2_find(users, p->username, OBJ_KEY);
 	if (user) {
 		if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
@@ -8161,7 +8080,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 		ast_string_field_set(p, host, user->name);
 		user = user_unref(user);
 	}
-	if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) {
+	if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) { 
 		ast_log(LOG_NOTICE, "Call Terminated, Incoming call is unencrypted while force encrypt is enabled.\n");
 		return res;
 	}
@@ -8176,13 +8095,10 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 	if ((p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(rsasecret) && !ast_strlen_zero(p->inkeys)) {
 		struct ast_key *key;
 		char *keyn;
-		char *tmpkey;
+		char tmpkey[256];
 		char *stringp=NULL;
-		if (!(tmpkey = ast_strdup(p->inkeys))) {
-			ast_log(LOG_ERROR, "Unable to create a temporary string for parsing stored 'inkeys'\n");
-			return res;
-		}
-		stringp = tmpkey;
+		ast_copy_string(tmpkey, p->inkeys, sizeof(tmpkey));
+		stringp=tmpkey;
 		keyn = strsep(&stringp, ":");
 		while(keyn) {
 			key = ast_key_get(keyn, AST_KEY_PUBLIC);
@@ -8193,11 +8109,11 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 				ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
 			keyn = strsep(&stringp, ":");
 		}
-		ast_free(tmpkey);
 	} else if (p->authmethods & IAX_AUTH_MD5) {
 		struct MD5Context md5;
 		unsigned char digest[16];
 		char *tmppw, *stringp;
+		
 		tmppw = ast_strdupa(p->secret);
 		stringp = tmppw;
 		while((tmppw = strsep(&stringp, ";"))) {
@@ -8207,7 +8123,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 			MD5Final(digest, &md5);
 			/* If they support md5, authenticate with it.  */
 			for (x=0;x<16;x++)
-				sprintf(requeststr + (x << 1), "%2.2x", (unsigned)digest[x]); /* safe */
+				sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
 			if (!strcasecmp(requeststr, md5secret)) {
 				res = 0;
 				break;
@@ -8221,7 +8137,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 }
 
 /*! \brief Verify inbound registration */
-static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
+static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
 {
 	char requeststr[256] = "";
 	char peer[256] = "";
@@ -8234,6 +8150,7 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 	int x;
 	int expire = 0;
 	int res = -1;
+	struct ast_sockaddr addr;
 
 	ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
 	/* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
@@ -8249,7 +8166,7 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 		expire = ies->refresh;
 
 	if (ast_strlen_zero(peer)) {
-		ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_sockaddr_stringify_addr(addr));
+		ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(sin->sin_addr));
 		return -1;
 	}
 
@@ -8266,7 +8183,7 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 			 * 1. A challenge already exists indicating a AUTHREQ was already sent out.
 			 * 2. A plaintext secret is present in ie as result of a previous AUTHREQ requesting it.
 			 * 3. A plaintext secret is present in the ie and the last_authmethod used by a peer happened
-			 *    to be plaintext, indicating it is an authmethod used by other peers on the system.
+			 *    to be plaintext, indicating it is an authmethod used by other peers on the system. 
 			 *
 			 * If none of these cases exist, res will be returned as 0 without authentication indicating
 			 * an AUTHREQ needs to be sent out. */
@@ -8278,19 +8195,20 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 			}
 		}
 		if (authdebug && !p)
-			ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
+			ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
 		goto return_unref;
 	}
 
 	if (!ast_test_flag64(p, IAX_DYNAMIC)) {
 		if (authdebug)
-			ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
+			ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
 		goto return_unref;
 	}
 
-	if (!ast_apply_acl(p->acl, addr, "IAX2 Peer ACL: ")) {
+	ast_sockaddr_from_sin(&addr, sin);
+	if (!ast_apply_acl(p->acl, &addr, "IAX2 Peer ACL: ")) {
 		if (authdebug)
-			ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
+			ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
 		goto return_unref;
 	}
 	ast_string_field_set(iaxs[callno], secret, p->secret);
@@ -8298,13 +8216,10 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 	/* Check secret against what we have on file */
 	if (!ast_strlen_zero(rsasecret) && (p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(iaxs[callno]->challenge)) {
 		if (!ast_strlen_zero(p->inkeys)) {
-			char *tmpkey;
+			char tmpkeys[256];
 			char *stringp=NULL;
-			if (!(tmpkey = ast_strdup(p->inkeys))) {
-				ast_log(LOG_ERROR, "Unable to create a temporary string for parsing stored 'inkeys'\n");
-				goto return_unref;
-			}
-			stringp = tmpkey;
+			ast_copy_string(tmpkeys, p->inkeys, sizeof(tmpkeys));
+			stringp=tmpkeys;
 			keyn = strsep(&stringp, ":");
 			while(keyn) {
 				key = ast_key_get(keyn, AST_KEY_PUBLIC);
@@ -8315,7 +8230,6 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 					ast_log(LOG_WARNING, "requested inkey '%s' does not exist\n", keyn);
 				keyn = strsep(&stringp, ":");
 			}
-			ast_free(tmpkey);
 			if (!keyn) {
 				if (authdebug)
 					ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
@@ -8339,7 +8253,7 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 			MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
 			MD5Final(digest, &md5);
 			for (x=0;x<16;x++)
-				sprintf(requeststr + (x << 1), "%2.2x", (unsigned)digest[x]); /* safe */
+				sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
 			if (!strcasecmp(requeststr, md5secret))
 				break;
 		}
@@ -8347,14 +8261,14 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
 			ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
 		} else {
 			if (authdebug)
-				ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_sockaddr_stringify_addr(addr), p->name, requeststr, md5secret);
+				ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
 			goto return_unref;
 		}
 	} else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
 		/* They've provided a plain text password and we support that */
 		if (strcmp(secret, p->secret)) {
 			if (authdebug)
-				ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
+				ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
 			goto return_unref;
 		} else
 			ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
@@ -8383,17 +8297,16 @@ return_unref:
 	return res;
 }
 
-static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct ast_sockaddr *addr, struct chan_iax2_pvt *pvt)
+static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, struct chan_iax2_pvt *pvt)
 {
 	int res = -1;
 	int x;
 	if (!ast_strlen_zero(keyn)) {
 		if (!(authmethods & IAX_AUTH_RSA)) {
-			if (ast_strlen_zero(secret)) {
-				ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_sockaddr_stringify_addr(addr));
-			}
+			if (ast_strlen_zero(secret)) 
+				ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(sin->sin_addr));
 		} else if (ast_strlen_zero(challenge)) {
-			ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_sockaddr_stringify_addr(addr));
+			ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(sin->sin_addr));
 		} else {
 			char sig[256];
 			struct ast_key *key;
@@ -8410,7 +8323,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
 				}
 			}
 		}
-	}
+	} 
 	/* Fall back */
 	if (res && !ast_strlen_zero(secret)) {
 		if ((authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(challenge)) {
@@ -8423,7 +8336,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
 			MD5Final(digest, &md5);
 			/* If they support md5, authenticate with it.  */
 			for (x=0;x<16;x++)
-				sprintf(digres + (x << 1),  "%2.2x", (unsigned)digest[x]); /* safe */
+				sprintf(digres + (x << 1),  "%02hhx", digest[x]); /* safe */
 			if (pvt) {
 				build_encryption_keys(digest, pvt);
 			}
@@ -8433,7 +8346,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
 			iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
 			res = 0;
 		} else
-			ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_sockaddr_stringify_addr(addr), authmethods);
+			ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_inet_ntoa(sin->sin_addr), authmethods);
 	}
 	return res;
 }
@@ -8442,7 +8355,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
  * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this function with a pvt lock held.
  */
-static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr, struct iax_ies *ies, const char *override, const char *okey)
+static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
 {
 	struct iax2_peer *peer = NULL;
 	/* Start pessimistic */
@@ -8452,7 +8365,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr
 	uint16_t callno = p->callno;
 
 	memset(&ied, 0, sizeof(ied));
-
+	
 	if (ies->username)
 		ast_string_field_set(p, username, ies->username);
 	if (ies->challenge)
@@ -8467,27 +8380,22 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr
 	/* Check for override RSA authentication first */
 	if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
 		/* Normal password authentication */
-		res = authenticate(p->challenge, override, okey, authmethods, &ied, addr, p);
+		res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, p);
 	} else {
 		struct ao2_iterator i = ao2_iterator_init(peers, 0);
 		while ((peer = ao2_iterator_next(&i))) {
-			struct ast_sockaddr peer_addr;
-			struct ast_sockaddr tmp_sockaddr1;
-			struct ast_sockaddr tmp_sockaddr2;
-
-			ast_sockaddr_copy(&peer_addr, &peer->addr);
+			struct sockaddr_in peer_addr;
 
-			ast_sockaddr_apply_netmask(addr, &peer->mask, &tmp_sockaddr1);
-			ast_sockaddr_apply_netmask(&peer_addr, &peer->mask, &tmp_sockaddr2);
+			ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-			if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name))
-				/* No peer specified at our end, or this is the peer */
+			if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name)) 
+			    /* No peer specified at our end, or this is the peer */
 			    && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
 			    /* No username specified in peer rule, or this is the right username */
-			    && (ast_sockaddr_isnull(&peer_addr) || !(ast_sockaddr_cmp_addr(&tmp_sockaddr1, &tmp_sockaddr2)))
+			    && (!peer_addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer_addr.sin_addr.s_addr & peer->mask.s_addr)))
 			    /* No specified host, or this is our host */
 				) {
-				res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, addr, p);
+				res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, p);
 				if (!res) {
 					peer_unref(peer);
 					break;
@@ -8497,7 +8405,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr
 		}
 		ao2_iterator_destroy(&i);
 		if (!peer) {
-			/* We checked our list and didn't find one.  It's unlikely, but possible,
+			/* We checked our list and didn't find one.  It's unlikely, but possible, 
 			   that we're trying to authenticate *to* a realtime peer */
 			const char *peer_name = ast_strdupa(p->peer);
 			ast_mutex_unlock(&iaxsl[callno]);
@@ -8507,7 +8415,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr
 					peer_unref(peer);
 					return -1;
 				}
-				res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, addr, p);
+				res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, p);
 				peer_unref(peer);
 			}
 			if (!peer) {
@@ -8589,7 +8497,7 @@ static int iax2_do_register_s(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__iax2_do_register_s, data))
-#endif
+#endif		
 		__iax2_do_register_s(data);
 	return 0;
 }
@@ -8597,22 +8505,23 @@ static int iax2_do_register_s(const void *data)
 static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
 	int newcall = 0;
+	char newip[256];
 	struct iax_ie_data ied;
-	struct ast_sockaddr new;
+	struct sockaddr_in new = { 0, };
 
 	memset(&ied, 0, sizeof(ied));
-	if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
-		ast_sockaddr_copy(&new, &ies->apparent_addr);
-	}
-	if (ies->callno) {
+	if (ies->apparent_addr)
+		memmove(&new, ies->apparent_addr, sizeof(new));
+	if (ies->callno)
 		newcall = ies->callno;
-	}
-	if (!newcall || ast_sockaddr_isnull(&new)) {
+	if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
 		ast_log(LOG_WARNING, "Invalid transfer request\n");
 		return -1;
 	}
 	pvt->transfercallno = newcall;
-	ast_sockaddr_copy(&pvt->transfer, &new);
+	memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
+	inet_aton(newip, &pvt->transfer.sin_addr);
+	pvt->transfer.sin_family = AF_INET;
 	pvt->transferid = ies->transferid;
 	/* only store by transfercallno if this is a new transfer,
 	 * just in case we get a duplicate TXREQ */
@@ -8621,9 +8530,8 @@ static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 	}
 	pvt->transferring = TRANSFER_BEGIN;
 
-	if (ies->transferid) {
+	if (ies->transferid)
 		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
-	}
 	send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
 	return 0;
 }
@@ -8633,10 +8541,10 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 	char exten[256] = "";
 	int status = CACHE_FLAG_UNKNOWN, expiry = iaxdefaultdpcache, x, matchmore = 0;
 	struct iax2_dpcache *dp = NULL;
-
+	
 	if (ies->called_number)
 		ast_copy_string(exten, ies->called_number, sizeof(exten));
-
+	
 	if (ies->dpstatus & IAX_DPSTATUS_EXISTS)
 		status = CACHE_FLAG_EXISTS;
 	else if (ies->dpstatus & IAX_DPSTATUS_CANEXIST)
@@ -8648,7 +8556,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 		expiry = ies->refresh;
 	if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
 		matchmore = CACHE_FLAG_MATCHMORE;
-
+	
 	AST_LIST_LOCK(&dpcache);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, peer_list) {
 		if (strcmp(dp->exten, exten))
@@ -8736,13 +8644,8 @@ static int complete_transfer(int callno, struct iax_ies *ies)
 	return 0;
 }
 
-static void iax2_publish_registry(const char *username, const char *domain, const char *status, const char *cause)
-{
-	ast_system_publish_registry("IAX2", username, domain, status, cause);
-}
-
 /*! \brief Acknowledgment received for OUR registration */
-static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int callno)
+static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int callno)
 {
 	struct iax2_registry *reg;
 	/* Start pessimistic */
@@ -8750,12 +8653,14 @@ static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int
 	char msgstatus[60];
 	int refresh = 60;
 	char ourip[256] = "<Unspecified>";
-	struct ast_sockaddr oldus;
-	struct ast_sockaddr us;
+	struct sockaddr_in oldus;
+	struct sockaddr_in us;
 	int oldmsgs;
+	struct sockaddr_in reg_addr;
 
-	if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
-		ast_sockaddr_copy(&us, &ies->apparent_addr);
+	memset(&us, 0, sizeof(us));
+	if (ies->apparent_addr) {
+		memmove(&us, ies->apparent_addr, sizeof(us));
 	}
 	if (ies->username) {
 		ast_copy_string(peer, ies->username, sizeof(peer));
@@ -8771,13 +8676,14 @@ static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int
 		ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
 		return -1;
 	}
-	ast_sockaddr_copy(&oldus, &reg->us);
+	memcpy(&oldus, &reg->us, sizeof(oldus));
 	oldmsgs = reg->messages;
-	if (ast_sockaddr_cmp(&reg->addr, addr)) {
-		ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_sockaddr_stringify(addr));
+	ast_sockaddr_to_sin(&reg->addr, &reg_addr);
+	if (inaddrcmp(&reg_addr, sin)) {
+		ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(sin->sin_addr));
 		return -1;
 	}
-	ast_sockaddr_copy(&reg->us, &us);
+	memcpy(&reg->us, &us, sizeof(reg->us));
 	if (ies->msgcount >= 0) {
 		reg->messages = ies->msgcount & 0xffff;		/* only low 16 bits are used in the transmission of the IE */
 	}
@@ -8787,8 +8693,7 @@ static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int
 	reg->refresh = refresh;
 	reg->expire = iax2_sched_replace(reg->expire, sched,
 		(5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
-	if (ast_sockaddr_cmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
-
+	if (inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
 		if (reg->messages > 255) {
 			snprintf(msgstatus, sizeof(msgstatus), " with %d new and %d old messages waiting", reg->messages & 0xff, reg->messages >> 8);
 		} else if (reg->messages > 1) {
@@ -8798,11 +8703,9 @@ static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int
 		} else {
 			ast_copy_string(msgstatus, " with no messages waiting", sizeof(msgstatus));
 		}
-
-		snprintf(ourip, sizeof(ourip), "%s", ast_sockaddr_stringify(&reg->us));
-
-		ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_sockaddr_stringify(addr), ourip, msgstatus);
-		iax2_publish_registry(reg->username, ast_sockaddr_stringify(addr), "Registered", NULL);
+		snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
+		ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(sin->sin_addr), ourip, msgstatus);
+		manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", ast_inet_ntoa(sin->sin_addr));
 	}
 	reg->regstate = REG_STATE_REGISTERED;
 	return 0;
@@ -8817,7 +8720,7 @@ static int iax2_append_register(const char *hostname, const char *username,
 		return -1;
 	}
 
-	reg->addr.ss.ss_family = AST_AF_UNSPEC;
+	reg->addr.ss.ss_family = AF_INET;
 	if (ast_dnsmgr_lookup(hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) {
 		ast_free(reg);
 		return -1;
@@ -8856,7 +8759,7 @@ static int iax2_register(const char *value, int lineno)
 	char *username, *hostname, *secret;
 	char *porta;
 	char *stringp=NULL;
-
+	
 	if (!value)
 		return -1;
 
@@ -8876,7 +8779,7 @@ static int iax2_register(const char *value, int lineno)
 	stringp = hostname;
 	hostname = strsep(&stringp, ":");
 	porta = strsep(&stringp, ":");
-
+	
 	if (porta && !atoi(porta)) {
 		ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
 		return -1;
@@ -8927,7 +8830,6 @@ static void unlink_peer(struct iax2_peer *peer)
 static void __expire_registry(const void *data)
 {
 	struct iax2_peer *peer = (struct iax2_peer *) data;
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
 	if (!peer)
 		return;
@@ -8941,15 +8843,11 @@ static void __expire_registry(const void *data)
 	ast_debug(1, "Expiring registration for peer '%s'\n", peer->name);
 	if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
 		realtime_update_peer(peer->name, &peer->addr, 0);
-	ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_OFFLINE);
-	blob = ast_json_pack("{s: s, s: s}",
-		"peer_status", "Unregistered",
-		"cause", "Expired");
-	ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
+	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
 	/* modify entry in peercnts table as _not_ registered */
 	peercnt_modify((unsigned char) 0, 0, &peer->addr);
 	/* Reset the address */
-	ast_sockaddr_setnull(&peer->addr);
+	memset(&peer->addr, 0, sizeof(peer->addr));
 	/* Reset expiry value */
 	peer->expiry = min_reg_expire;
 	if (!ast_test_flag64(peer, IAX_TEMPONLY))
@@ -8969,7 +8867,7 @@ static int expire_registry(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__expire_registry, data))
-#endif
+#endif		
 		__expire_registry(data);
 	return 0;
 }
@@ -9028,9 +8926,8 @@ static void reg_source_db(struct iax2_peer *p)
  * \note Since this function calls send_command_final(), the pvt struct for
  *       the given call number may disappear while executing this function.
  */
-static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype, int fd, unsigned short refresh)
+static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
 {
-
 	/* Called from IAX thread only, with proper iaxsl lock */
 	struct iax_ie_data ied = {
 		.pos = 0,
@@ -9038,10 +8935,12 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 	struct iax2_peer *p;
 	int msgcount;
 	char data[80];
-	uint16_t version;
+	int version;
 	const char *peer_name;
 	int res = -1;
-	char *str_addr;
+	struct ast_sockaddr sockaddr;
+
+	ast_sockaddr_from_sin(&sockaddr, sin);
 
 	peer_name = ast_strdupa(iaxs[callno]->peer);
 
@@ -9057,12 +8956,12 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 		goto return_unref;
 
 	if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
-		if (!ast_sockaddr_isnull(addr)) {
+		if (sin->sin_addr.s_addr) {
 			time_t nowtime;
 			time(&nowtime);
-			realtime_update_peer(peer_name, addr, nowtime);
+			realtime_update_peer(peer_name, &sockaddr, nowtime);
 		} else {
-			realtime_update_peer(peer_name, addr, 0);
+			realtime_update_peer(peer_name, &sockaddr, 0);
 		}
 	}
 
@@ -9082,9 +8981,7 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 		p->expiry = refresh;
 	}
 
-	if (ast_sockaddr_cmp(&p->addr, addr)) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
+	if (ast_sockaddr_cmp(&p->addr, &sockaddr)) {
 		if (iax2_regfunk) {
 			iax2_regfunk(p->name, 1);
 		}
@@ -9093,39 +8990,24 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 		peercnt_modify((unsigned char) 0, 0, &p->addr);
 
 		/* Stash the IP address from which they registered */
-		ast_sockaddr_copy(&p->addr, addr);
+		ast_sockaddr_from_sin(&p->addr, sin);
 
-		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
-
-		snprintf(data, sizeof(data), "%s:%d", ast_sockaddr_stringify(addr), p->expiry);
-
-		if (!ast_test_flag64(p, IAX_TEMPONLY) && !ast_sockaddr_isnull(addr)) {
+		snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
+		if (!ast_test_flag64(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
 			ast_db_put("IAX/Registry", p->name, data);
-			ast_verb(3, "Registered IAX2 '%s' (%s) at %s\n",
-						p->name,
-					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED",
-					    ast_sockaddr_stringify(addr));
-			ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_ONLINE);
-			blob = ast_json_pack("{s: s, s: s, s: i}",
-				"peer_status", "Registered",
-				"address", str_addr,
-				"port", ast_sockaddr_port(addr));
+			ast_verb(3, "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
+					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\nPort: %d\r\n", p->name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 			register_peer_exten(p, 1);
 			ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 		} else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
-			ast_verb(3, "Unregistered IAX2 '%s' (%s)\n",
-						p->name,
+			ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
 					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
-			ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_OFFLINE);
-			blob = ast_json_pack("{s: s}",
-				"peer_status", "Unregistered");
+			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
 			register_peer_exten(p, 0);
 			ast_db_del("IAX/Registry", p->name);
 			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 		}
-
-		ast_endpoint_blob_publish(p->endpoint, ast_endpoint_state_type(), blob);
-
 		/* Update the host */
 		/* Verify that the host is really there */
 		iax2_poke_peer(p, callno);
@@ -9152,29 +9034,38 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 		}
 	}
 
-	if (p->expiry && !ast_sockaddr_isnull(addr)) {
+	if (p->expiry && sin->sin_addr.s_addr) {
 		p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
 		if (p->expire == -1)
 			peer_unref(p);
 	}
 	iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
 	iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
-	if (!ast_sockaddr_isnull(addr)) {
-		struct ast_sockaddr peer_addr;
+	if (sin->sin_addr.s_addr) {
+		struct sockaddr_in peer_addr;
 
-		ast_sockaddr_copy(&peer_addr, &p->addr);
+		ast_sockaddr_to_sin(&p->addr, &peer_addr);
 
 		iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
 		iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &peer_addr);
 		if (!ast_strlen_zero(p->mailbox)) {
+			struct ast_event *event;
 			int new, old;
-			RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-			msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
-			if (msg) {
-				struct ast_mwi_state *mwi_state = stasis_message_data(msg);
-				new = mwi_state->new_msgs;
-				old = mwi_state->old_msgs;
+			char *mailbox, *context;
+
+			context = mailbox = ast_strdupa(p->mailbox);
+			strsep(&context, "@");
+			if (ast_strlen_zero(context))
+				context = "default";
+
+			event = ast_event_get_cached(AST_EVENT_MWI,
+				AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+				AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+				AST_EVENT_IE_END);
+			if (event) {
+				new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+				old = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
+				ast_event_destroy(event);
 			} else { /* Fall back on checking the mailbox directly */
 				ast_app_inboxcount(p->mailbox, &new, &old);
 			}
@@ -9194,9 +9085,9 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
 			iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
 		}
 	}
-	if (iax_firmware_get_version(devtype, &version)) {
+	version = iax_check_version(devtype);
+	if (version) 
 		iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-	}
 
 	res = 0;
 
@@ -9254,7 +9145,7 @@ return_unref:
 	return iaxs[callno] ? send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1) : -1;
 }
 
-static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockaddr *addr)
+static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
 {
 	struct iax2_registry *reg;
 	/* Start pessimistic */
@@ -9272,9 +9163,12 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockad
 	memset(&ied, 0, sizeof(ied));
 	reg = iaxs[callno]->reg;
 	if (reg) {
+		struct sockaddr_in reg_addr;
 
-		if (ast_sockaddr_cmp(&reg->addr, addr)) {
-			ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_sockaddr_stringify(addr));
+		ast_sockaddr_to_sin(&reg->addr, &reg_addr);
+
+		if (inaddrcmp(&reg_addr, sin)) {
+			ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(sin->sin_addr));
 			return -1;
 		}
 		if (ast_strlen_zero(reg->secret)) {
@@ -9288,9 +9182,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockad
 			char tmpkey[256];
 			ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
 			tmpkey[strlen(tmpkey) - 1] = '\0';
-			res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, addr, NULL);
+			res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL);
 		} else
-			res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, addr, NULL);
+			res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL);
 		if (!res) {
 			reg->regstate = REG_STATE_AUTHSENT;
 			add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
@@ -9298,7 +9192,7 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockad
 		} else
 			return -1;
 		ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
-	} else
+	} else	
 		ast_log(LOG_NOTICE, "Can't reregister without a reg\n");
 	return -1;
 }
@@ -9337,7 +9231,7 @@ static int auth_reject(const void *data)
 	ast_mutex_unlock(&iaxsl[callno]);
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__auth_reject, data))
-#endif
+#endif		
 		__auth_reject(data);
 	return 0;
 }
@@ -9349,7 +9243,7 @@ static int auth_fail(int callno, int failcode)
 	if (iaxs[callno]) {
 		iaxs[callno]->authfail = failcode;
 		if (delayreject) {
-			iaxs[callno]->authid = iax2_sched_replace(iaxs[callno]->authid,
+			iaxs[callno]->authid = iax2_sched_replace(iaxs[callno]->authid, 
 				sched, 1000, auth_reject, (void *)(long)callno);
 		} else
 			auth_reject((void *)(long)callno);
@@ -9382,7 +9276,7 @@ static int auto_hangup(const void *data)
 	ast_mutex_unlock(&iaxsl[callno]);
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__auto_hangup, data))
-#endif
+#endif		
 		__auto_hangup(data);
 	return 0;
 }
@@ -9391,7 +9285,7 @@ static void iax2_dprequest(struct iax2_dpcache *dp, int callno)
 {
 	struct iax_ie_data ied;
 	/* Auto-hangup with 30 seconds of inactivity */
-	iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid,
+	iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
 		sched, 30000, auto_hangup, (void *)(long)callno);
 	memset(&ied, 0, sizeof(ied));
 	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, dp->exten);
@@ -9430,7 +9324,7 @@ static int iax2_poke_peer_s(const void *data)
 	peer->pokeexpire = -1;
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__iax2_poke_peer_s, data))
-#endif
+#endif		
 		__iax2_poke_peer_s(data);
 	return 0;
 }
@@ -9442,7 +9336,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
 	struct ast_iax2_meta_hdr *meta;
 	struct ast_iax2_meta_trunk_hdr *mth;
 	int calls = 0;
-
+	
 	/* Point to frame */
 	fr = (struct iax_frame *)tpeer->trunkdata;
 	/* Point to meta data */
@@ -9481,7 +9375,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
 static inline int iax2_trunk_expired(struct iax2_trunk_peer *tpeer, struct timeval *now)
 {
 	/* Drop when trunk is about 5 seconds idle */
-	if (now->tv_sec > tpeer->trunkact.tv_sec + 5)
+	if (now->tv_sec > tpeer->trunkact.tv_sec + 5) 
 		return 1;
 	return 0;
 }
@@ -9492,9 +9386,8 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 	struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
 	struct timeval now = ast_tvnow();
 
-	if (iaxtrunkdebug) {
+	if (iaxtrunkdebug)
 		ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
-	}
 
 	if (timer) {
 		if (ast_timer_ack(timer, 1) < 0) {
@@ -9519,14 +9412,8 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 		} else {
 			res = send_trunk(tpeer, &now);
 			trunk_timed++;
-			if (iaxtrunkdebug) {
-				ast_verbose(" - Trunk peer (%s) has %d call chunk%s in transit, %u bytes backloged and has hit a high water mark of %u bytes\n",
-							ast_sockaddr_stringify(&tpeer->addr),
-							res,
-							(res != 1) ? "s" : "",
-							tpeer->trunkdatalen,
-							tpeer->trunkdataalloc);
-			}
+			if (iaxtrunkdebug)
+				ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %u bytes backloged and has hit a high water mark of %u bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
 		}
 		totalcalls += res;
 		res = 0;
@@ -9537,9 +9424,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 
 	if (drop) {
 		ast_mutex_lock(&drop->lock);
-		/*  Once we have this lock, we're sure nobody else is using it or could use it once we release it,
-			because by the time they could get tpeerlock, we've already grabbed it */
-		ast_debug(1, "Dropping unused iax2 trunk peer '%s'\n", ast_sockaddr_stringify(&drop->addr));
+		/* Once we have this lock, we're sure nobody else is using it or could use it once we release it, 
+		   because by the time they could get tpeerlock, we've already grabbed it */
+		ast_debug(1, "Dropping unused iax2 trunk peer '%s:%d'\n", ast_inet_ntoa(drop->addr.sin_addr), ntohs(drop->addr.sin_port));
 		if (drop->trunkdata) {
 			ast_free(drop->trunkdata);
 			drop->trunkdata = NULL;
@@ -9549,9 +9436,8 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 		ast_free(drop);
 	}
 
-	if (iaxtrunkdebug) {
+	if (iaxtrunkdebug)
 		ast_verbose("Ending trunk processing with %d peers and %d call chunks processed\n", processed, totalcalls);
-	}
 	iaxtrunkdebug = 0;
 
 	return 1;
@@ -9573,7 +9459,7 @@ static void dp_lookup(int callno, const char *context, const char *callednum, co
 	memset(&ied1, 0, sizeof(ied1));
 	mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
 	/* Must be started */
-	if (ast_exists_extension(NULL, context, callednum, 1, callerid)) {
+	if (ast_parking_ext_valid(callednum, NULL, context) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_EXISTS;
 	} else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_CANEXIST;
@@ -9611,7 +9497,7 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
 {
 	pthread_t newthread;
 	struct dpreq_data *dpr;
-
+	
 	if (!(dpr = ast_calloc(1, sizeof(*dpr))))
 		return;
 
@@ -9625,7 +9511,131 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
 	}
 }
 
-static int check_provisioning(struct ast_sockaddr *addr, int sockfd, char *si, unsigned int ver)
+struct iax_dual {
+	struct ast_channel *chan1;
+	struct ast_channel *chan2;
+	char *park_exten;
+	char *park_context;
+};
+
+static void *iax_park_thread(void *stuff)
+{
+	struct iax_dual *d;
+	int res;
+	int ext = 0;
+
+	d = stuff;
+
+	ast_debug(4, "IAX Park: Transferer channel %s, Transferee %s\n",
+		ast_channel_name(d->chan2), ast_channel_name(d->chan1));
+
+	res = ast_park_call_exten(d->chan1, d->chan2, d->park_exten, d->park_context, 0, &ext);
+	if (res) {
+		/* Parking failed. */
+		ast_hangup(d->chan1);
+	} else {
+		ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
+	}
+	ast_hangup(d->chan2);
+
+	ast_free(d->park_exten);
+	ast_free(d->park_context);
+	ast_free(d);
+	return NULL;
+}
+
+/*! DO NOT hold any locks while calling iax_park */
+static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *park_exten, const char *park_context)
+{
+	struct iax_dual *d;
+	struct ast_channel *chan1m, *chan2m;/* Chan2m: The transferer, chan1m: The transferee */
+	pthread_t th;
+
+	chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(chan2), ast_channel_exten(chan1), ast_channel_context(chan1), ast_channel_linkedid(chan1), ast_channel_amaflags(chan1), "Parking/%s", ast_channel_name(chan1));
+	chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(chan2), ast_channel_exten(chan2), ast_channel_context(chan2), ast_channel_linkedid(chan2), ast_channel_amaflags(chan2), "IAXPeer/%s", ast_channel_name(chan2));
+	d = ast_calloc(1, sizeof(*d));
+	if (!chan1m || !chan2m || !d) {
+		if (chan1m) {
+			ast_hangup(chan1m);
+		}
+		if (chan2m) {
+			ast_hangup(chan2m);
+		}
+		ast_free(d);
+		return -1;
+	}
+	d->park_exten = ast_strdup(park_exten);
+	d->park_context = ast_strdup(park_context);
+	if (!d->park_exten || !d->park_context) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(chan1m), ast_channel_readformat(chan1));
+	ast_format_copy(ast_channel_writeformat(chan1m), ast_channel_writeformat(chan1));
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(chan1m, chan1)) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_channel_context_set(chan1m, ast_channel_context(chan1));
+	ast_channel_exten_set(chan1m, ast_channel_exten(chan1));
+	ast_channel_priority_set(chan1m, ast_channel_priority(chan1));
+
+	ast_do_masquerade(chan1m);
+
+	/* We make a clone of the peer channel too, so we can play
+	   back the announcement */
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(chan2m), ast_channel_readformat(chan2));
+	ast_format_copy(ast_channel_writeformat(chan2m), ast_channel_writeformat(chan2));
+	ast_channel_parkinglot_set(chan2m, ast_channel_parkinglot(chan2));
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(chan2m, chan2)) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_channel_context_set(chan2m, ast_channel_context(chan2));
+	ast_channel_exten_set(chan2m, ast_channel_exten(chan2));
+	ast_channel_priority_set(chan2m, ast_channel_priority(chan2));
+
+	ast_do_masquerade(chan2m);
+
+	d->chan1 = chan1m;	/* Transferee */
+	d->chan2 = chan2m;	/* Transferer */
+	if (ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d) < 0) {
+		/* Could not start thread */
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+	return 0;
+}
+
+static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
 {
 	unsigned int ourver;
 	char rsi[80];
@@ -9634,7 +9644,7 @@ static int check_provisioning(struct ast_sockaddr *addr, int sockfd, char *si, u
 		return 0;
 	ast_debug(1, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
 	if (ourver != ver)
-		iax2_provision(addr, sockfd, NULL, rsi, 1);
+		iax2_provision(sin, sockfd, NULL, rsi, 1);
 	return 0;
 }
 
@@ -9654,7 +9664,7 @@ static void construct_rr(struct chan_iax2_pvt *pvt, struct iax_ie_data *iep)
 	iax_ie_append_int(iep,IAX_IE_RR_OOO, stats.frames_ooo);
 }
 
-static void save_rr(struct iax_frame *fr, struct iax_ies *ies)
+static void save_rr(struct iax_frame *fr, struct iax_ies *ies) 
 {
 	iaxs[fr->callno]->remote_rr.jitter = ies->rr_jitter;
 	iaxs[fr->callno]->remote_rr.losspct = ies->rr_loss >> 24;
@@ -9665,7 +9675,7 @@ static void save_rr(struct iax_frame *fr, struct iax_ies *ies)
 	iaxs[fr->callno]->remote_rr.ooo = ies->rr_ooo;
 }
 
-static void save_osptoken(struct iax_frame *fr, struct iax_ies *ies)
+static void save_osptoken(struct iax_frame *fr, struct iax_ies *ies) 
 {
 	int i;
 	unsigned int length, offset = 0;
@@ -9729,6 +9739,23 @@ static void log_jitterstats(unsigned short callno)
 			iaxs[callno]->remote_rr.dropped,
 			iaxs[callno]->remote_rr.ooo,
 			iaxs[callno]->remote_rr.packets);
+		manager_event(EVENT_FLAG_REPORTING, "JitterBufStats", "Owner: %s\r\nPing: %u\r\nLocalJitter: %d\r\nLocalJBDelay: %d\r\nLocalTotalLost: %d\r\nLocalLossPercent: %d\r\nLocalDropped: %d\r\nLocalooo: %d\r\nLocalReceived: %d\r\nRemoteJitter: %d\r\nRemoteJBDelay: %d\r\nRemoteTotalLost: %d\r\nRemoteLossPercent: %d\r\nRemoteDropped: %d\r\nRemoteooo: %d\r\nRemoteReceived: %d\r\n",
+			ast_channel_name(iaxs[callno]->owner),
+			iaxs[callno]->pingtime,
+			localjitter,
+			localdelay,
+			locallost,
+			locallosspct,
+			localdropped,
+			localooo,
+			localpackets,
+			iaxs[callno]->remote_rr.jitter,
+			iaxs[callno]->remote_rr.delay,
+			iaxs[callno]->remote_rr.losscnt,
+			iaxs[callno]->remote_rr.losspct/1000,
+			iaxs[callno]->remote_rr.dropped,
+			iaxs[callno]->remote_rr.ooo,
+			iaxs[callno]->remote_rr.packets);
 	}
 	ast_mutex_unlock(&iaxsl[callno]);
 }
@@ -9750,7 +9777,7 @@ static void handle_deferred_full_frames(struct iax2_thread *thread)
 		thread->buf = pkt_buf->buf;
 		thread->buf_len = pkt_buf->len;
 		thread->buf_size = pkt_buf->len + 1;
-
+		
 		socket_process(thread);
 
 		thread->buf = NULL;
@@ -9802,6 +9829,7 @@ static void defer_full_frame(struct iax2_thread *from_here, struct iax2_thread *
 static int socket_read(int *id, int fd, short events, void *cbdata)
 {
 	struct iax2_thread *thread;
+	socklen_t len;
 	time_t t;
 	static time_t last_errtime = 0;
 	struct ast_iax2_full_hdr *fh;
@@ -9816,8 +9844,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 		return 1;
 	}
 
+	len = sizeof(thread->iosin);
 	thread->iofd = fd;
-	thread->buf_len = ast_recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, &thread->ioaddr);
+	thread->buf_len = recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, (struct sockaddr *) &thread->iosin, &len);
 	thread->buf_size = sizeof(thread->readbuf);
 	thread->buf = thread->readbuf;
 	if (thread->buf_len < 0) {
@@ -9833,7 +9862,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 		signal_condition(&thread->lock, &thread->cond);
 		return 1;
 	}
-
+	
 	/* Determine if this frame is a full frame; if so, and any thread is currently
 	   processing a full frame for the same callno from this peer, then drop this
 	   frame (and the peer will retransmit it) */
@@ -9841,11 +9870,11 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 	if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
 		struct iax2_thread *cur = NULL;
 		uint16_t callno = ntohs(fh->scallno) & ~IAX_FLAG_FULL;
-
+		
 		AST_LIST_LOCK(&active_list);
 		AST_LIST_TRAVERSE(&active_list, cur, list) {
 			if ((cur->ffinfo.callno == callno) &&
-			    !ast_sockaddr_cmp_addr(&cur->ffinfo.addr, &thread->ioaddr))
+			    !inaddrcmp(&cur->ffinfo.sin, &thread->iosin))
 				break;
 		}
 		if (cur) {
@@ -9859,14 +9888,14 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 		} else {
 			/* this thread is going to process this frame, so mark it */
 			thread->ffinfo.callno = callno;
-			ast_sockaddr_copy(&thread->ffinfo.addr, &thread->ioaddr);
+			memcpy(&thread->ffinfo.sin, &thread->iosin, sizeof(thread->ffinfo.sin));
 			thread->ffinfo.type = fh->type;
 			thread->ffinfo.csub = fh->csub;
 			AST_LIST_INSERT_HEAD(&active_list, thread, list);
 		}
 		AST_LIST_UNLOCK(&active_list);
 	}
-
+	
 	/* Mark as ready and send on its way */
 	thread->iostate = IAX_IOSTATE_READY;
 #ifdef DEBUG_SCHED_MULTITHREAD
@@ -9877,7 +9906,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 	return 1;
 }
 
-static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct ast_sockaddr *addr, int sockfd,
+static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd,
 	struct iax_frame *fr)
 {
 	unsigned char metatype;
@@ -9891,8 +9920,8 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 	struct ast_frame f = { 0, };
 
 	if (packet_len < sizeof(*meta)) {
-		ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a meta frame but is too short\n",
-				ast_sockaddr_stringify(addr));
+		ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", 
+			ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 		return 1;
 	}
 
@@ -9909,10 +9938,10 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 	metatype = meta->cmddata;
 	packet_len -= (sizeof(*meta) + sizeof(*mth));
 	ptr = mth->data;
-	tpeer = find_tpeer(addr, sockfd);
+	tpeer = find_tpeer(sin, sockfd);
 	if (!tpeer) {
-		ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s': No matching peer\n",
-				ast_sockaddr_stringify(addr));
+		ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", 
+			ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 		return 1;
 	}
 	tpeer->trunkact = ast_tvnow();
@@ -9939,13 +9968,13 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 			callno = ntohs(mte->callno);
 			trunked_ts = 0;
 		} else {
-			ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s': dropping\n", ast_sockaddr_stringify(addr));
+			ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 			break;
 		}
 		/* Stop if we don't have enough data */
 		if (len > packet_len)
 			break;
-		fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, addr, NEW_PREVENT, sockfd, 0);
+		fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd, 0);
 		if (!fr->callno)
 			continue;
 
@@ -9960,7 +9989,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 			ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
 			iax2_vnak(fr->callno);
 		} else {
-			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
+			ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat);
 			f.datalen = len;
 			if (f.datalen >= 0) {
 				if (f.datalen)
@@ -9979,8 +10008,8 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 					f.src = "IAX2";
 					f.mallocd = 0;
 					f.offset = 0;
-					if (f.datalen && (f.frametype == AST_FRAME_VOICE))
-						f.samples = ast_codec_samples_count(&f);
+					if (f.datalen && (f.frametype == AST_FRAME_VOICE)) 
+						f.samples = ast_codec_get_samples(&f);
 					else
 						f.samples = 0;
 					fr->outoforder = 0;
@@ -10111,7 +10140,7 @@ static void set_hangup_source_and_cause(int callno, unsigned char causecode)
 
 static int socket_process_helper(struct iax2_thread *thread)
 {
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	int res;
 	int updatehistory=1;
 	int new = NEW_PREVENT;
@@ -10137,7 +10166,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 	struct iax_frame *duped_fr;
 	char host_pref_buf[128];
 	char caller_pref_buf[128];
-	struct iax2_codec_pref pref;
+	struct ast_codec_pref pref;
 	char *using_prefs = "mine";
 
 	/* allocate an iax_frame with 4096 bytes of data buffer */
@@ -10148,7 +10177,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 	/* Copy frequently used parameters to the stack */
 	res = thread->buf_len;
 	fd = thread->iofd;
-	ast_sockaddr_copy(&addr, &thread->ioaddr);
+	memcpy(&sin, &thread->iosin, sizeof(sin));
 
 	if (res < sizeof(*mh)) {
 		ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
@@ -10156,25 +10185,23 @@ static int socket_process_helper(struct iax2_thread *thread)
 	}
 	if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
 		if (res < sizeof(*vh)) {
-			ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a video frame but is too short\n",
-					ast_sockaddr_stringify(&addr));
+			ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a video frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 			return 1;
 		}
 
 		/* This is a video frame, get call number */
-		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &addr, new, fd, 0);
+		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
 		minivid = 1;
 	} else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
-		return socket_process_meta(res, meta, &addr, fd, fr);
+		return socket_process_meta(res, meta, &sin, fd, fr);
 
 #ifdef DEBUG_SUPPORT
 	if (res >= sizeof(*fh))
-		iax_outputframe(NULL, fh, 1, &addr, res - sizeof(*fh));
+		iax_outputframe(NULL, fh, 1, &sin, res - sizeof(*fh));
 #endif
 	if (ntohs(mh->callno) & IAX_FLAG_FULL) {
 		if (res < sizeof(*fh)) {
-			ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a full frame but is too short\n",
-				ast_sockaddr_stringify(&addr));
+			ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 			return 1;
 		}
 
@@ -10183,10 +10210,10 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 
 		/* check to make sure this full frame isn't encrypted before we attempt
-		 * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
+ 		 * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
 		 * callno is not found here, that just means one hasn't been allocated for
 		 * this connection yet. */
-		if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, NEW_PREVENT, fd, 1))) {
+		if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, NEW_PREVENT, fd, 1))) {
 			ast_mutex_lock(&iaxsl[fr->callno]);
 			if (iaxs[fr->callno] && ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED)) {
 				if (decrypt_frame(fr->callno, fh, &f, &res)) {
@@ -10202,12 +10229,12 @@ static int socket_process_helper(struct iax2_thread *thread)
 		/* Retrieve the type and subclass */
 		f.frametype = fh->type;
 		if (f.frametype == AST_FRAME_VIDEO) {
-			f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40));
+			ast_format_from_old_bitfield(&f.subclass.format, (uncompress_subclass(fh->csub & ~0x40)));
 			if ((fh->csub >> 6) & 0x1) {
-				f.subclass.frame_ending = 1;
+				ast_format_set_video_mark(&f.subclass.format);
 			}
 		} else if (f.frametype == AST_FRAME_VOICE) {
-			f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
+			ast_format_from_old_bitfield(&f.subclass.format, uncompress_subclass(fh->csub));
 		} else {
 			f.subclass.integer = uncompress_subclass(fh->csub);
 		}
@@ -10215,7 +10242,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 		/* Deal with POKE/PONG without allocating a callno */
 		if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_POKE) {
 			/* Reply back with a PONG, but don't care about the result. */
-			send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+			send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 			return 1;
 		} else if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_ACK && dcallno == 1) {
 			/* Ignore */
@@ -10226,7 +10253,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 		if (f.datalen) {
 			if (f.frametype == AST_FRAME_IAX) {
 				if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
-					ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_sockaddr_stringify(&addr));
+					ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
 					ast_variables_destroy(ies.vars);
 					return 1;
 				}
@@ -10246,7 +10273,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 		if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) {
 			/* only set NEW_ALLOW if calltoken checks out */
-			if (handle_call_token(fh, &ies, &addr, fd)) {
+			if (handle_call_token(fh, &ies, &sin, fd)) {
 				ast_variables_destroy(ies.vars);
 				return 1;
 			}
@@ -10276,18 +10303,18 @@ static int socket_process_helper(struct iax2_thread *thread)
 		 * end to know the destination call number before call setup can complete.
 		 *
 		 * Discussed in the following thread:
-		 *    http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html
+		 *    http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html 
 		 */
 
 		if ((ntohs(mh->callno) & IAX_FLAG_FULL) && ((f.frametype == AST_FRAME_IAX) && (f.subclass.integer == IAX_COMMAND_ACK))) {
 			check_dcallno = 1;
 		}
 
-		if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, new, fd, check_dcallno))) {
+		if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno))) {
 			if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_NEW) {
-				send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+				send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 			} else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) {
-				send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+				send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 			}
 			ast_variables_destroy(ies.vars);
 			return 1;
@@ -10314,12 +10341,11 @@ static int socket_process_helper(struct iax2_thread *thread)
 				 (f.subclass.integer != IAX_COMMAND_TXACC) &&
 				 (f.subclass.integer != IAX_COMMAND_FWDOWNL))||
 			    (f.frametype != AST_FRAME_IAX))
-				raw_hangup(&addr, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
+				raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
 				fd);
 		}
-		if (fr->callno > 0){
+		if (fr->callno > 0) 
 			ast_mutex_unlock(&iaxsl[fr->callno]);
-		}
 		ast_variables_destroy(ies.vars);
 		return 1;
 	}
@@ -10335,7 +10361,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 #ifdef DEBUG_SUPPORT
 	if (decrypted) {
-		iax_outputframe(NULL, fh, 3, &addr, res - sizeof(*fh));
+		iax_outputframe(NULL, fh, 3, &sin, res - sizeof(*fh));
 	}
 #endif
 
@@ -10387,7 +10413,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 	/* count this frame */
 	iaxs[fr->callno]->frames_received++;
 
-	if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) && !minivid &&
+	if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
 		f.subclass.integer != IAX_COMMAND_TXCNT &&		/* for attended transfer */
 		f.subclass.integer != IAX_COMMAND_TXACC) {		/* for attended transfer */
 		unsigned short new_peercallno;
@@ -10482,9 +10508,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 				thread->buf[res - 1] = '\0';
 		}
 
-		/* Handle implicit ACKing unless this is an INVAL, and only if this is
+		/* Handle implicit ACKing unless this is an INVAL, and only if this is 
 		   from the real peer, not the transfer peer */
-		if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
+		if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
 		    ((f.subclass.integer != IAX_COMMAND_INVAL) ||
 		     (f.frametype != AST_FRAME_IAX))) {
 			unsigned char x;
@@ -10532,7 +10558,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 				ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
 			}
 		}
-		if (ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
+		if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
 			((f.frametype != AST_FRAME_IAX) ||
 			 ((f.subclass.integer != IAX_COMMAND_TXACC) &&
 			  (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
@@ -10550,9 +10576,8 @@ static int socket_process_helper(struct iax2_thread *thread)
 		    (f.frametype == AST_FRAME_IAX)) {
 			if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
 				ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-				if (!ast_iax2_new(fr->callno, AST_STATE_RING,
-					iaxs[fr->callno]->chosenformat, &iaxs[fr->callno]->rprefs, NULL, NULL,
-					ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
+				if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL,
+						  ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
 					ast_variables_destroy(ies.vars);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 					return 1;
@@ -10632,21 +10657,22 @@ static int socket_process_helper(struct iax2_thread *thread)
 		}
 
 		if (f.frametype == AST_FRAME_VOICE) {
-			if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->voiceformat) {
-					iaxs[fr->callno]->voiceformat = ast_format_compatibility_format2bitfield(f.subclass.format);
-					ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_format_get_name(f.subclass.format));
+			if (ast_format_to_old_bitfield(&f.subclass.format) != iaxs[fr->callno]->voiceformat) {
+					iaxs[fr->callno]->voiceformat = ast_format_to_old_bitfield(&f.subclass.format);
+					ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(&f.subclass.format));
 					if (iaxs[fr->callno]->owner) {
 						iax2_lock_owner(fr->callno);
 						if (iaxs[fr->callno]) {
 							if (iaxs[fr->callno]->owner) {
-								struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-								if (native) {
-									ast_format_cap_append(native, f.subclass.format, 0);
-									ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
-									if (ast_channel_readformat(iaxs[fr->callno]->owner)) {
+								struct ast_format_cap *orignative = ast_format_cap_dup(ast_channel_nativeformats(iaxs[fr->callno]->owner));
+								struct ast_format_cap *native = ast_channel_nativeformats(iaxs[fr->callno]->owner);
+								if (orignative) {
+									ast_format_cap_set(native, &f.subclass.format);
+									if (ast_channel_readformat(iaxs[fr->callno]->owner)->id) {
 										ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
 									}
-									ao2_ref(native, -1);
+									ast_format_cap_copy(native, orignative);
+									orignative = ast_format_cap_destroy(orignative);
 								}
 								ast_channel_unlock(iaxs[fr->callno]->owner);
 							}
@@ -10665,9 +10691,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 			}
 		}
 		if (f.frametype == AST_FRAME_VIDEO) {
-			if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->videoformat) {
-				ast_debug(1, "Ooh, video format changed to %s\n", ast_format_get_name(f.subclass.format));
-				iaxs[fr->callno]->videoformat = ast_format_compatibility_format2bitfield(f.subclass.format);
+			if (f.subclass.format.id != ast_format_id_from_old_bitfield(iaxs[fr->callno]->videoformat)) {
+				ast_debug(1, "Ooh, video format changed to %s\n", ast_getformatname(&f.subclass.format));
+				iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format);
 			}
 		}
 		if (f.frametype == AST_FRAME_IAX) {
@@ -10695,21 +10721,33 @@ static int socket_process_helper(struct iax2_thread *thread)
 				break;
 			case IAX_COMMAND_QUELCH:
 				if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+				        /* Generate Manager Hold event, if necessary*/
+					if (iaxs[fr->callno]->owner) {
+						ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
+							"Status: On\r\n"
+							"Channel: %s\r\n"
+							"Uniqueid: %s\r\n",
+							ast_channel_name(iaxs[fr->callno]->owner),
+							ast_channel_uniqueid(iaxs[fr->callno]->owner));
+					}
+
 					ast_set_flag64(iaxs[fr->callno], IAX_QUELCH);
 					if (ies.musiconhold) {
-						const char *moh_suggest;
-
 						iax2_lock_owner(fr->callno);
 						if (!iaxs[fr->callno] || !iaxs[fr->callno]->owner) {
 							break;
 						}
-
-						/*
-						 * We already hold the owner lock so we do not
-						 * need to check iaxs[fr->callno] after it returns.
-						 */
-						moh_suggest = iaxs[fr->callno]->mohsuggest;
-						iax2_queue_hold(fr->callno, moh_suggest);
+						if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
+							const char *moh_suggest = iaxs[fr->callno]->mohsuggest;
+
+							/*
+							 * We already hold the owner lock so we do not
+							 * need to check iaxs[fr->callno] after it returns.
+							 */
+							iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD, 
+								S_OR(moh_suggest, NULL),
+								!ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0);
+						}
 						ast_channel_unlock(iaxs[fr->callno]->owner);
 					}
 				}
@@ -10720,17 +10758,27 @@ static int socket_process_helper(struct iax2_thread *thread)
 					if (!iaxs[fr->callno]) {
 						break;
 					}
+					/* Generate Manager Unhold event, if necessary */
+					if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) {
+						ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
+							"Status: Off\r\n"
+							"Channel: %s\r\n"
+							"Uniqueid: %s\r\n",
+							ast_channel_name(iaxs[fr->callno]->owner),
+							ast_channel_uniqueid(iaxs[fr->callno]->owner));
+					}
 
 					ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH);
 					if (!iaxs[fr->callno]->owner) {
 						break;
 					}
-
-					/*
-					 * We already hold the owner lock so we do not
-					 * need to check iaxs[fr->callno] after it returns.
-					 */
-					iax2_queue_unhold(fr->callno);
+					if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
+						/*
+						 * We already hold the owner lock so we do not
+						 * need to check iaxs[fr->callno] after it returns.
+						 */
+						iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
+					}
 					ast_channel_unlock(iaxs[fr->callno]->owner);
 				}
 				break;
@@ -10753,9 +10801,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 				/* Ignore if it's already up */
 				if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD))
 					break;
-				if (ies.provverpres && ies.serviceident && !(ast_sockaddr_isnull(&addr))) {
+				if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
 					ast_mutex_unlock(&iaxsl[fr->callno]);
-					check_provisioning(&addr, fd, ies.serviceident, ies.provver);
+					check_provisioning(&sin, fd, ies.serviceident, ies.provver);
 					ast_mutex_lock(&iaxsl[fr->callno]);
 					if (!iaxs[fr->callno]) {
 						break;
@@ -10770,13 +10818,11 @@ static int socket_process_helper(struct iax2_thread *thread)
 				/* For security, always ack immediately */
 				if (delayreject)
 					send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
-				if (check_access(fr->callno, &addr, &ies)) {
+				if (check_access(fr->callno, &sin, &ies)) {
 					/* They're not allowed on */
 					auth_fail(fr->callno, IAX_COMMAND_REJECT);
-					if (authdebug) {
-						ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n",
-								ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
-					}
+					if (authdebug)
+						ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
 					break;
 				}
 				if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag64(iaxs[fr->callno], IAX_FORCE_ENCRYPT)) {
@@ -10812,10 +10858,8 @@ static int socket_process_helper(struct iax2_thread *thread)
 						if (!iaxs[fr->callno]) {
 							break;
 						}
-						if (authdebug) {
-							ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
-									ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
-						}
+						if (authdebug)
+							ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
 					} else {
 						/* Select an appropriate format */
 
@@ -10830,12 +10874,12 @@ static int socket_process_helper(struct iax2_thread *thread)
 							strcpy(caller_pref_buf, "disabled");
 							strcpy(host_pref_buf, "disabled");
 						} else {
-							struct ast_format *tmpfmt;
+							struct ast_format tmpfmt;
 							using_prefs = "mine";
 							/* If the information elements are in here... use them */
 							if (ies.codec_prefs)
-								iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-							if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+								ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+							if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
 								/* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
 								if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 									pref = iaxs[fr->callno]->rprefs;
@@ -10846,9 +10890,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 							} else
 								pref = iaxs[fr->callno]->prefs;
 
-							format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability);
-							iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
-							iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+							format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
+							ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+							ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
 						}
 						if (!format) {
 							if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
@@ -10862,21 +10906,18 @@ static int socket_process_helper(struct iax2_thread *thread)
 									break;
 								}
 								if (authdebug) {
-									struct ast_str *peer_buf = ast_str_alloca(64);
-									struct ast_str *cap_buf = ast_str_alloca(64);
-									struct ast_str *peer_form_buf = ast_str_alloca(64);
-
+									char tmp[256], tmp2[256], tmp3[256];
 									if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+											ast_inet_ntoa(sin.sin_addr),
+											iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
+											iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
 									} else {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+											ast_inet_ntoa(sin.sin_addr),
+											iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
+											iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
+											iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
 									}
 								}
 							} else {
@@ -10888,13 +10929,13 @@ static int socket_process_helper(struct iax2_thread *thread)
 									if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
 										using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
 										memset(&pref, 0, sizeof(pref));
-										format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+										format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 										strcpy(caller_pref_buf,"disabled");
 										strcpy(host_pref_buf,"disabled");
 									} else {
-										struct ast_format *tmpfmt;
+										struct ast_format tmpfmt;
 										using_prefs = "mine";
-										if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+										if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
 											/* Do the opposite of what we tried above. */
 											if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 												pref = iaxs[fr->callno]->prefs;
@@ -10902,31 +10943,28 @@ static int socket_process_helper(struct iax2_thread *thread)
 												pref = iaxs[fr->callno]->rprefs;
 												using_prefs = "caller";
 											}
-											format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+											format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
 										} else /* if no codec_prefs IE do it the old way */
-											format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+											format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 									}
 								}
 
 								if (!format) {
-									struct ast_str *peer_buf = ast_str_alloca(64);
-									struct ast_str *cap_buf = ast_str_alloca(64);
-									struct ast_str *peer_form_buf = ast_str_alloca(64);
-
+									char tmp[256], tmp2[256], tmp3[256];
 									memset(&ied0, 0, sizeof(ied0));
 									iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
 									iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
-									ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
+									ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
 									send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 									if (!iaxs[fr->callno]) {
 										break;
 									}
 									if (authdebug) {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+											ast_inet_ntoa(sin.sin_addr),
+											iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
+											iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
+											iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
 									}
 									ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
 									break;
@@ -10947,15 +10985,15 @@ static int socket_process_helper(struct iax2_thread *thread)
 												"%sactual format = %s,\n"
 												"%shost prefs = %s,\n"
 												"%spriority = %s\n",
-												ast_sockaddr_stringify(&addr),
+												ast_inet_ntoa(sin.sin_addr), 
 												VERBOSE_PREFIX_4,
-												iax2_getformatname(iaxs[fr->callno]->peerformat),
+												iax2_getformatname(iaxs[fr->callno]->peerformat), 
 												VERBOSE_PREFIX_4,
 												caller_pref_buf,
 												VERBOSE_PREFIX_4,
-												iax2_getformatname(format),
+												iax2_getformatname(format), 
 												VERBOSE_PREFIX_4,
-												host_pref_buf,
+												host_pref_buf, 
 												VERBOSE_PREFIX_4,
 												using_prefs);
 
@@ -10967,7 +11005,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 							} else {
 								ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
 								/* If this is a TBD call, we're ready but now what...  */
-								ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_sockaddr_stringify(&addr));
+								ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
 							}
 						}
 					}
@@ -11020,7 +11058,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 				if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) {
 					if (iaxs[fr->callno]->owner && authdebug)
 						ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
-							ast_sockaddr_stringify(&addr),
+							ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
 							ies.cause ? ies.cause : "<Unknown>");
 					ast_debug(1, "Immediately destroying %d, having received reject\n",
 						fr->callno);
@@ -11034,28 +11072,56 @@ static int socket_process_helper(struct iax2_thread *thread)
 				break;
 			case IAX_COMMAND_TRANSFER:
 			{
+				struct ast_channel *bridged_chan;
+				struct ast_channel *owner;
+
 				iax2_lock_owner(fr->callno);
 				if (!iaxs[fr->callno]) {
 					/* Initiating call went away before we could transfer. */
 					break;
 				}
-				if (iaxs[fr->callno]->owner) {
-					struct ast_channel *owner = iaxs[fr->callno]->owner;
-					char *context = ast_strdupa(iaxs[fr->callno]->context);
+				owner = iaxs[fr->callno]->owner;
+				bridged_chan = owner ? ast_bridged_channel(owner) : NULL;
+				if (bridged_chan && ies.called_number) {
+					const char *context;
+
+					context = ast_strdupa(iaxs[fr->callno]->context);
 
 					ast_channel_ref(owner);
+					ast_channel_ref(bridged_chan);
 					ast_channel_unlock(owner);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 
-					if (ast_bridge_transfer_blind(1, owner, ies.called_number,
-								context, NULL, NULL) != AST_BRIDGE_TRANSFER_SUCCESS) {
-						ast_log(LOG_WARNING, "Blind transfer of '%s' to '%s@%s' failed\n",
-							ast_channel_name(owner), ies.called_number,
-							context);
-					}
+					/* Set BLINDTRANSFER channel variables */
+					pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", ast_channel_name(bridged_chan));
+					pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", ast_channel_name(owner));
 
+					/* DO NOT hold any locks while calling ast_parking_ext_valid() */
+					if (ast_parking_ext_valid(ies.called_number, owner, context)) {
+						ast_debug(1, "Parking call '%s'\n", ast_channel_name(bridged_chan));
+						if (iax_park(bridged_chan, owner, ies.called_number, context)) {
+							ast_log(LOG_WARNING, "Failed to park call '%s'\n",
+								ast_channel_name(bridged_chan));
+						}
+					} else {
+						if (ast_async_goto(bridged_chan, context, ies.called_number, 1)) {
+							ast_log(LOG_WARNING,
+								"Async goto of '%s' to '%s@%s' failed\n",
+								ast_channel_name(bridged_chan), ies.called_number, context);
+						} else {
+							ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
+								ast_channel_name(bridged_chan), ies.called_number, context);
+						}
+					}
 					ast_channel_unref(owner);
+					ast_channel_unref(bridged_chan);
+
 					ast_mutex_lock(&iaxsl[fr->callno]);
+				} else {
+					ast_debug(1, "Async goto not applicable on call %d\n", fr->callno);
+					if (owner) {
+						ast_channel_unlock(owner);
+					}
 				}
 
 				break;
@@ -11074,12 +11140,11 @@ static int socket_process_helper(struct iax2_thread *thread)
 					iaxs[fr->callno]->peerformat = ies.format;
 				} else {
 					if (iaxs[fr->callno]->owner)
-						iaxs[fr->callno]->peerformat = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
+						iaxs[fr->callno]->peerformat = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
 					else
 						iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
 				}
-				ast_verb(3, "Call accepted by %s (format %s)\n", ast_sockaddr_stringify(&addr),
-						iax2_getformatname(iaxs[fr->callno]->peerformat));
+				ast_verb(3, "Call accepted by %s (format %s)\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iax2_getformatname(iaxs[fr->callno]->peerformat));
 				if (!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability)) {
 					memset(&ied0, 0, sizeof(ied0));
 					iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
@@ -11089,38 +11154,28 @@ static int socket_process_helper(struct iax2_thread *thread)
 						break;
 					}
 					if (authdebug) {
-						struct ast_str *peer_buf = ast_str_alloca(64);
-						struct ast_str *cap_buf = ast_str_alloca(64);
-
+						char tmp1[256], tmp2[256];
 						ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n",
-							ast_sockaddr_stringify(&addr),
-							iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_buf),
-							iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+							ast_inet_ntoa(sin.sin_addr),
+							iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
+							iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
 					}
 				} else {
-					struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-
 					ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
 					iax2_lock_owner(fr->callno);
-					if (iaxs[fr->callno] && iaxs[fr->callno]->owner && native) {
-						struct ast_str *cap_buf = ast_str_alloca(64);
-
+					if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
+						char tmp[256];
 						/* Switch us to use a compatible format */
-						iax2_codec_pref_best_bitfield2cap(
-							iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
-							native);
-						ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
-						ast_verb(3, "Format for call is %s\n", ast_format_cap_get_names(ast_channel_nativeformats(iaxs[fr->callno]->owner), &cap_buf));
+						ast_format_cap_from_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner), iaxs[fr->callno]->peerformat);
+						ast_verb(3, "Format for call is %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(iaxs[fr->callno]->owner)));
 
 						/* Setup read/write formats properly. */
-						if (ast_channel_writeformat(iaxs[fr->callno]->owner))
+						if (ast_channel_writeformat(iaxs[fr->callno]->owner)->id)
 							ast_set_write_format(iaxs[fr->callno]->owner, ast_channel_writeformat(iaxs[fr->callno]->owner));
-						if (ast_channel_readformat(iaxs[fr->callno]->owner))
+						if (ast_channel_readformat(iaxs[fr->callno]->owner)->id)
 							ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
 						ast_channel_unlock(iaxs[fr->callno]->owner);
 					}
-
-					ao2_cleanup(native);
 				}
 				if (iaxs[fr->callno]) {
 					AST_LIST_LOCK(&dpcache);
@@ -11152,34 +11207,26 @@ static int socket_process_helper(struct iax2_thread *thread)
 				log_jitterstats(fr->callno);
 
 				if (iaxs[fr->callno]->peerpoke) {
-					RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 					peer = iaxs[fr->callno]->peerpoke;
 					if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) {
 						if (iaxs[fr->callno]->pingtime <= peer->maxms) {
 							ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %u\n", peer->name, iaxs[fr->callno]->pingtime);
-							ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
-							blob = ast_json_pack("{s: s, s: i}",
-								"peer_status", "Reachable",
-								"time", iaxs[fr->callno]->pingtime);
+							manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %u\r\n", peer->name, iaxs[fr->callno]->pingtime); 
 							ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
 						}
 					} else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
 						if (iaxs[fr->callno]->pingtime > peer->maxms) {
 							ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%u ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
-							ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
-							blob = ast_json_pack("{s: s, s: i}",
-								"peer_status", "Lagged",
-								"time", iaxs[fr->callno]->pingtime);
+							manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %u\r\n", peer->name, iaxs[fr->callno]->pingtime); 
 							ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
 						}
 					}
-					ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
 					peer->lastms = iaxs[fr->callno]->pingtime;
 					if (peer->smoothing && (peer->lastms > -1))
 						peer->historicms = (iaxs[fr->callno]->pingtime + peer->historicms) / 2;
 					else if (peer->smoothing && peer->lastms < 0)
 						peer->historicms = (0 + peer->historicms) / 2;
-					else
+					else					
 						peer->historicms = iaxs[fr->callno]->pingtime;
 
 					/* Remove scheduled iax2_poke_noanswer */
@@ -11223,7 +11270,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 					iaxs[fr->callno]->lag = ts - fr->ts;
 					if (iaxdebug)
 						ast_debug(1, "Peer %s lag measured as %dms\n",
-							ast_sockaddr_stringify(&addr), iaxs[fr->callno]->lag);
+							ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->lag);
 				}
 				break;
 			case IAX_COMMAND_AUTHREQ:
@@ -11235,9 +11282,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 					struct ast_frame hangup_fr = { .frametype = AST_FRAME_CONTROL,
 								.subclass.integer = AST_CONTROL_HANGUP,
 					};
-					ast_log(LOG_WARNING,
-						"I don't know how to authenticate %s to %s\n",
-						ies.username ? ies.username : "<unknown>", ast_sockaddr_stringify(&addr));
+					ast_log(LOG_WARNING, 
+						"I don't know how to authenticate %s to %s\n", 
+						ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
 					iax2_queue_frame(fr->callno, &hangup_fr);
 				}
 				break;
@@ -11252,8 +11299,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 				}
 				if (authenticate_verify(iaxs[fr->callno], &ies)) {
 					if (authdebug)
-						ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_sockaddr_stringify(&addr),
-								iaxs[fr->callno]->username);
+						ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->username);
 					memset(&ied0, 0, sizeof(ied0));
 					auth_fail(fr->callno, IAX_COMMAND_REJECT);
 					break;
@@ -11265,10 +11311,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 					exists = 0;
 				if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
 					if (authdebug)
-						ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
-								ast_sockaddr_stringify(&addr),
-								iaxs[fr->callno]->exten,
-								iaxs[fr->callno]->context);
+						ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
 					memset(&ied0, 0, sizeof(ied0));
 					iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
 					iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
@@ -11289,11 +11332,11 @@ static int socket_process_helper(struct iax2_thread *thread)
 						strcpy(caller_pref_buf, "disabled");
 						strcpy(host_pref_buf, "disabled");
 					} else {
-						struct ast_format *tmpfmt;
+						struct ast_format tmpfmt;
 						using_prefs = "mine";
 						if (ies.codec_prefs)
-							iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-						if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+							ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+						if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
 							if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 								pref = iaxs[fr->callno]->rprefs;
 								using_prefs = "caller";
@@ -11302,34 +11345,30 @@ static int socket_process_helper(struct iax2_thread *thread)
 							}
 						} else /* if no codec_prefs IE do it the old way */
 							pref = iaxs[fr->callno]->prefs;
-						format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability);
-						iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
-						iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+						format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
+						ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+						ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
 					}
 					if (!format) {
-						struct ast_str *cap_buf = ast_str_alloca(64);
-						struct ast_str *peer_buf = ast_str_alloca(64);
-						struct ast_str *peer_form_buf = ast_str_alloca(64);
-
+						char tmp1[256], tmp2[256], tmp3[256];
 						if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
 							ast_debug(1, "We don't do requested format %s, falling back to peer capability '%s'\n",
 								iax2_getformatname(iaxs[fr->callno]->peerformat),
-								iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf));
+								iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability));
 							format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
 						}
 						if (!format) {
 							if (authdebug) {
 								if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
-									ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-										iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-										iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+									ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", ast_inet_ntoa(sin.sin_addr),
+										iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
+										iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
 								} else {
 									ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-										ast_sockaddr_stringify(&addr),
-										iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-										iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
-										iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+										ast_inet_ntoa(sin.sin_addr),
+										iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
+										iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
+										iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
 								}
 							}
 							memset(&ied0, 0, sizeof(ied0));
@@ -11348,15 +11387,14 @@ static int socket_process_helper(struct iax2_thread *thread)
 								if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
 									using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
 									memset(&pref, 0, sizeof(pref));
-									format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)
-										? iaxs[fr->callno]->peerformat
-										: iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+									format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
+										iaxs[fr->callno]->peerformat : iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 									strcpy(caller_pref_buf,"disabled");
 									strcpy(host_pref_buf,"disabled");
 								} else {
-									struct ast_format *tmpfmt;
+									struct ast_format tmpfmt;
 									using_prefs = "mine";
-									if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+									if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
 										/* Do the opposite of what we tried above. */
 										if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 											pref = iaxs[fr->callno]->prefs;
@@ -11364,30 +11402,27 @@ static int socket_process_helper(struct iax2_thread *thread)
 											pref = iaxs[fr->callno]->rprefs;
 											using_prefs = "caller";
 										}
-										format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+										format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
 									} else /* if no codec_prefs IE do it the old way */
-										format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+										format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);	
 								}
 							}
 							if (!format) {
-								struct ast_str *cap_buf = ast_str_alloca(64);
-								struct ast_str *peer_buf = ast_str_alloca(64);
-								struct ast_str *peer_form_buf = ast_str_alloca(64);
-
+								char tmp1[256], tmp2[256], tmp3[256];
 								ast_log(LOG_ERROR, "No best format in %s???\n",
-									iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
+									iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
 								if (authdebug) {
 									if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+											ast_inet_ntoa(sin.sin_addr),
+											iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
+											iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
 									} else {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-											ast_sockaddr_stringify(&addr),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
-											iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
+											ast_inet_ntoa(sin.sin_addr),
+											iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
+											iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
+											iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
 									}
 								}
 								memset(&ied0, 0, sizeof(ied0));
@@ -11413,8 +11448,8 @@ static int socket_process_helper(struct iax2_thread *thread)
 											"%srequested prefs = %s,\n"
 											"%sactual format = %s,\n"
 											"%shost prefs = %s,\n"
-											"%spriority = %s\n",
-											ast_sockaddr_stringify(&addr),
+											"%spriority = %s\n", 
+											ast_inet_ntoa(sin.sin_addr), 
 											VERBOSE_PREFIX_4,
 											iax2_getformatname(iaxs[fr->callno]->peerformat),
 											VERBOSE_PREFIX_4,
@@ -11427,11 +11462,9 @@ static int socket_process_helper(struct iax2_thread *thread)
 											using_prefs);
 
 							ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-							c = ast_iax2_new(fr->callno, AST_STATE_RING, format,
-								&iaxs[fr->callno]->rprefs, NULL, NULL, 1);
-							if (!c) {
+							if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, 1)))
 								iax2_destroy(fr->callno);
-							} else if (ies.vars) {
+							else if (ies.vars) {
 								struct ast_datastore *variablestore;
 								struct ast_variable *var, *prev = NULL;
 								AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -11469,7 +11502,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 						} else {
 							ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
 							/* If this is a TBD call, we're ready but now what...  */
-							ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_sockaddr_stringify(&addr));
+							ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
 							if (ast_test_flag64(iaxs[fr->callno], IAX_IMMEDIATE)) {
 								goto immediatedial;
 							}
@@ -11484,10 +11517,7 @@ immediatedial:
 					ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s");
 					if (!ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num)) {
 						if (authdebug)
-							ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n",
-									ast_sockaddr_stringify(&addr),
-									iaxs[fr->callno]->exten,
-									iaxs[fr->callno]->context);
+							ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
 						memset(&ied0, 0, sizeof(ied0));
 						iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
 						iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
@@ -11496,19 +11526,16 @@ immediatedial:
 							break;
 						}
 					} else {
-						struct ast_str *cap_buf = ast_str_alloca(64);
+						char tmp[256];
 						ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
 						ast_verb(3, "Accepting DIAL from %s, formats = %s\n",
-								ast_sockaddr_stringify(&addr),
-								iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &cap_buf));
+							ast_inet_ntoa(sin.sin_addr),
+							iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
 						ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
 						send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
-						c = ast_iax2_new(fr->callno, AST_STATE_RING,
-							iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
-							NULL, NULL, 1);
-						if (!c) {
+						if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1)))
 							iax2_destroy(fr->callno);
-						} else if (ies.vars) {
+						else if (ies.vars) {
 							struct ast_datastore *variablestore;
 							struct ast_variable *var, *prev = NULL;
 							AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -11562,7 +11589,7 @@ immediatedial:
 				/* For security, always ack immediately */
 				if (delayreject)
 					send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
-				if (register_verify(fr->callno, &addr, &ies)) {
+				if (register_verify(fr->callno, &sin, &ies)) {
 					if (!iaxs[fr->callno]) {
 						break;
 					}
@@ -11577,17 +11604,18 @@ immediatedial:
 						ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) {
 
 					if (f.subclass.integer == IAX_COMMAND_REGREL) {
-						ast_sockaddr_setnull(&addr);
+						memset(&sin, 0, sizeof(sin));
+						sin.sin_family = AF_INET;
 					}
-					if (update_registry(&addr, fr->callno, ies.devicetype, fd, ies.refresh)) {
+					if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh)) {
 						ast_log(LOG_WARNING, "Registry error\n");
 					}
 					if (!iaxs[fr->callno]) {
 						break;
 					}
-					if (ies.provverpres && ies.serviceident && !(ast_sockaddr_isnull(&addr))) {
+					if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
 						ast_mutex_unlock(&iaxsl[fr->callno]);
-						check_provisioning(&addr, fd, ies.serviceident, ies.provver);
+						check_provisioning(&sin, fd, ies.serviceident, ies.provver);
 						ast_mutex_lock(&iaxsl[fr->callno]);
 					}
 					break;
@@ -11595,9 +11623,8 @@ immediatedial:
 				registry_authrequest(fr->callno);
 				break;
 			case IAX_COMMAND_REGACK:
-				if (iax2_ack_registry(&ies, &addr, fr->callno)) {
+				if (iax2_ack_registry(&ies, &sin, fr->callno)) 
 					ast_log(LOG_WARNING, "Registration failure\n");
-				}
 				/* Send ack immediately, before we destroy */
 				send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
 				iax2_destroy(fr->callno);
@@ -11605,11 +11632,9 @@ immediatedial:
 			case IAX_COMMAND_REGREJ:
 				if (iaxs[fr->callno]->reg) {
 					if (authdebug) {
-						ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n",
-								iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>",
-								ast_sockaddr_stringify(&addr));
+						ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>", ast_inet_ntoa(sin.sin_addr));
+						manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nUsername: %s\r\nStatus: Rejected\r\nCause: %s\r\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>");
 					}
-					iax2_publish_registry(iaxs[fr->callno]->reg->username, ast_sockaddr_stringify(&addr), "Rejected", S_OR(ies.cause, "<unknown>"));
 					iaxs[fr->callno]->reg->regstate = REG_STATE_REJECTED;
 				}
 				/* Send ack immediately, before we destroy */
@@ -11618,7 +11643,7 @@ immediatedial:
 				break;
 			case IAX_COMMAND_REGAUTH:
 				/* Authentication request */
-				if (registry_rerequest(&ies, fr->callno, &addr)) {
+				if (registry_rerequest(&ies, fr->callno, &sin)) {
 					memset(&ied0, 0, sizeof(ied0));
 					iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
 					iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
@@ -11734,7 +11759,7 @@ immediatedial:
 				send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
 				complete_transfer(fr->callno, &ies);
 				stop_stuff(fr->callno);	/* for attended transfer to work with libiax */
-				break;
+				break;	
 			case IAX_COMMAND_TXMEDIA:
 				if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
 					AST_LIST_TRAVERSE(&frame_queue[fr->callno], cur, list) {
@@ -11749,7 +11774,7 @@ immediatedial:
 				break;
 			case IAX_COMMAND_RTKEY:
 				if (!IAX_CALLENCRYPTED(iaxs[fr->callno])) {
-					ast_log(LOG_WARNING,
+					ast_log(LOG_WARNING, 
 						"we've been told to rotate our encryption key, "
 						"but this isn't an encrypted call. bad things will happen.\n"
 					);
@@ -11773,7 +11798,7 @@ immediatedial:
 					break;
 				}
 				memset(&ied0, 0, sizeof(ied0));
-				res = iax_firmware_append(&ied0, ies.devicetype, ies.fwdesc);
+				res = iax_firmware_append(&ied0, (unsigned char *)ies.devicetype, ies.fwdesc);
 				if (res < 0)
 					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 				else if (res > 0)
@@ -11823,9 +11848,9 @@ immediatedial:
 		f.frametype = AST_FRAME_VIDEO;
 		if (iaxs[fr->callno]->videoformat > 0) {
 			if (ntohs(vh->ts) & 0x8000LL) {
-				f.subclass.frame_ending = 1;
+				ast_format_set_video_mark(&f.subclass.format);
 			}
-			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->videoformat);
+			ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->videoformat);
 		} else {
 			ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
 			iax2_vnak(fr->callno);
@@ -11848,7 +11873,7 @@ immediatedial:
 		/* A mini frame */
 		f.frametype = AST_FRAME_VOICE;
 		if (iaxs[fr->callno]->voiceformat > 0)
-			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
+			ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat);
 		else {
 			ast_debug(1, "Received mini frame before first full voice frame\n");
 			iax2_vnak(fr->callno);
@@ -11956,9 +11981,9 @@ immediatedial:
 	f.offset = 0;
 	f.len = 0;
 	if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
-		f.samples = ast_codec_samples_count(&f);
+		f.samples = ast_codec_get_samples(&f);
 		/* We need to byteswap incoming slinear samples from network byte order */
-		if (ast_format_cmp(f.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)
+		if (f.subclass.format.id == AST_FORMAT_SLINEAR)
 			ast_frame_byteswap_be(&f);
 	} else
 		f.samples = 0;
@@ -11972,7 +11997,7 @@ immediatedial:
 		if (iaxdebug && iaxs[fr->callno]) {
 			ast_debug(1, "Received out of order packet... (type=%u, subclass %d, ts = %u, last = %u)\n", f.frametype, f.subclass.integer, fr->ts, iaxs[fr->callno]->last);
 		}
-		fr->outoforder = -1;
+		fr->outoforder = 1;
 	}
 	fr->cacheable = ((f.frametype == AST_FRAME_VOICE) || (f.frametype == AST_FRAME_VIDEO));
 	if (iaxs[fr->callno]) {
@@ -12073,7 +12098,7 @@ static void *iax2_process_thread(void *data)
 				AST_LIST_UNLOCK(&dynamic_list);
 				if (t) {
 					/* This dynamic thread timed out waiting for a task and was
-					 * not acquired immediately after the timeout,
+					 * not acquired immediately after the timeout, 
 					 * so it's time to go away. */
 					ast_mutex_unlock(&thread->lock);
 					break;
@@ -12117,7 +12142,7 @@ static void *iax2_process_thread(void *data)
 			thread->iostate = IAX_IOSTATE_PROCESSING;
 #ifdef SCHED_MULTITHREADED
 			thread->schedfunc(thread->scheddata);
-#endif
+#endif		
 			break;
 		default:
 			break;
@@ -12172,7 +12197,7 @@ static int iax2_do_register(struct iax2_registry *reg)
 		ast_debug(1, "Sending registration request for '%s'\n", reg->username);
 
 	if (reg->dnsmgr &&
-	    ((reg->regstate == REG_STATE_TIMEOUT) || ast_sockaddr_isnull(&reg->addr))) {
+	    ((reg->regstate == REG_STATE_TIMEOUT) || !ast_sockaddr_ipv4(&reg->addr))) {
 		/* Maybe the IP has changed, force DNS refresh */
 		ast_dnsmgr_refresh(reg->dnsmgr);
 	}
@@ -12188,7 +12213,7 @@ static int iax2_do_register(struct iax2_registry *reg)
 		ast_mutex_unlock(&iaxsl[callno]);
 		reg->callno = 0;
 	}
-	if (ast_sockaddr_isnull(&reg->addr)) {
+	if (!ast_sockaddr_ipv4(&reg->addr)) {
 		if (iaxdebug)
 			ast_debug(1, "Unable to send registration request for '%s' without IP address\n", reg->username);
 		/* Setup the next registration attempt */
@@ -12201,10 +12226,13 @@ static int iax2_do_register(struct iax2_registry *reg)
 	}
 
 	if (!reg->callno) {
+		struct sockaddr_in reg_addr;
 
 		ast_debug(3, "Allocate call number\n");
 
-		reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
+		ast_sockaddr_to_sin(&reg->addr, &reg_addr);
+
+		reg->callno = find_callno_locked(0, 0, &reg_addr, NEW_FORCE, defaultsockfd, 0);
 		if (reg->callno < 1) {
 			ast_log(LOG_WARNING, "Unable to create call for registration\n");
 			return -1;
@@ -12226,14 +12254,14 @@ static int iax2_do_register(struct iax2_registry *reg)
 	return 0;
 }
 
-static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest, const char *template, int force)
+static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force)
 {
 	/* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
 	   is found for template */
 	struct iax_ie_data provdata;
 	struct iax_ie_data ied;
 	unsigned int sig;
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	int callno;
 	struct create_addr_info cai;
 
@@ -12247,22 +12275,22 @@ static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest
 	}
 
 	if (end) {
-		ast_sockaddr_copy(&addr, end);
+		memcpy(&sin, end, sizeof(sin));
 		cai.sockfd = sockfd;
-	} else if (create_addr(dest, NULL, &addr, &cai))
+	} else if (create_addr(dest, NULL, &sin, &cai))
 		return -1;
 
 	/* Build the rest of the message */
 	memset(&ied, 0, sizeof(ied));
 	iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);
 
-	callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
 	if (!callno)
 		return -1;
 
 	if (iaxs[callno]) {
 		/* Schedule autodestruct in case they don't ever give us anything back */
-		iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid,
+		iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
 			sched, 15000, auto_hangup, (void *)(long)callno);
 		ast_set_flag64(iaxs[callno], IAX_PROVISION);
 		/* Got a call number now, so go ahead and send the provisioning information */
@@ -12295,14 +12323,14 @@ static int iax2_prov_app(struct ast_channel *chan, const char *data)
 	if (ast_channel_tech(chan) != &iax2_tech) {
 		ast_log(LOG_NOTICE, "Can't provision a non-IAX device!\n");
 		return -1;
-	}
-	if (!callno || !iaxs[callno] || ast_sockaddr_isnull(&iaxs[callno]->addr)) {
+	} 
+	if (!callno || !iaxs[callno] || !iaxs[callno]->addr.sin_addr.s_addr) {
 		ast_log(LOG_NOTICE, "Can't provision something with no IP?\n");
 		return -1;
 	}
 	res = iax2_provision(&iaxs[callno]->addr, iaxs[callno]->sockfd, NULL, sdata, force);
 	ast_verb(3, "Provisioned IAXY at '%s' with '%s'= %d\n",
-		ast_sockaddr_stringify(&iaxs[callno]->addr),
+		ast_inet_ntoa(iaxs[callno]->addr.sin_addr),
 		sdata, res);
 	return res;
 }
@@ -12315,7 +12343,7 @@ static char *handle_cli_iax2_provision(struct ast_cli_entry *e, int cmd, struct
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "iax2 provision";
-		e->usage =
+		e->usage = 
 			"Usage: iax2 provision <host> <template> [forced]\n"
 			"       Provisions the given peer or IP address using a template\n"
 			"       matching either 'template' or '*' if the template is not\n"
@@ -12352,14 +12380,8 @@ static void __iax2_poke_noanswer(const void *data)
 	int callno;
 
 	if (peer->lastms > -1) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
 		ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
-		ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_OFFLINE);
-		blob = ast_json_pack("{s: s, s: i}",
-			"peer_status", "Unreachable",
-			"time", peer->lastms);
-		ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
+		manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
 		ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
 	}
 	if ((callno = peer->callno) > 0) {
@@ -12381,7 +12403,7 @@ static int iax2_poke_noanswer(const void *data)
 	peer->pokeexpire = -1;
 #ifdef SCHED_MULTITHREADED
 	if (schedule_action(__iax2_poke_noanswer, data))
-#endif
+#endif		
 		__iax2_poke_noanswer(data);
 	peer_unref(peer);
 	return 0;
@@ -12399,8 +12421,10 @@ static int iax2_poke_peer_cb(void *obj, void *arg, int flags)
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 {
 	int callno;
+	int poke_timeout;
+	struct sockaddr_in peer_addr;
 
-	if (!peer->maxms || (ast_sockaddr_isnull(&peer->addr) && !peer->dnsmgr)) {
+	if (!peer->maxms || (!ast_sockaddr_ipv4(&peer->addr) && !peer->dnsmgr)) {
 		/* IF we have no IP without dnsmgr, or this isn't to be monitored, return
 		  immediately after clearing things out */
 		peer->lastms = 0;
@@ -12410,6 +12434,8 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 		return 0;
 	}
 
+	ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+
 	/* The peer could change the callno inside iax2_destroy, since we do deadlock avoidance */
 	if ((callno = peer->callno) > 0) {
 		ast_log(LOG_NOTICE, "Still have a callno...\n");
@@ -12419,18 +12445,14 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 	}
 	if (heldcall)
 		ast_mutex_unlock(&iaxsl[heldcall]);
-	callno = peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
+	callno = peer->callno = find_callno(0, 0, &peer_addr, NEW_FORCE, peer->sockfd, 0);
 	if (heldcall)
 		ast_mutex_lock(&iaxsl[heldcall]);
-	if (peer->callno < 1) {
+	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
 		return -1;
 	}
 
-	/* Speed up retransmission times for this qualify call */
-	iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
-	iaxs[peer->callno]->peerpoke = peer;
-
 	if (peer->pokeexpire > -1) {
 		if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
 			peer->pokeexpire = -1;
@@ -12438,12 +12460,24 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 		}
 	}
 
+	if (peer->lastms < 0){
+		/* If the host is already unreachable then use time less than the unreachable
+		 * interval. 5/6 is arbitrary multiplier to get value less than
+		 * peer->pokefreqnotok. Value less than peer->pokefreqnotok is used to expire
+		 * current POKE before starting new POKE (which is scheduled after
+		 * peer->pokefreqnotok). */
+		poke_timeout = peer->pokefreqnotok * 5  / 6;
+	} else {
+		/* If the host is reachable, use timeout large enough to allow for multiple
+		 * POKE retries. Limit this value to less than peer->pokefreqok. 5/6 is arbitrary
+		 * multiplier to get value less than peer->pokefreqok. Value less than
+		 * peer->pokefreqok is used to expire current POKE before starting new POKE
+		 * (which is scheduled after peer->pokefreqok). */
+		poke_timeout = MIN(MAX_RETRY_TIME * 2 + peer->maxms, peer->pokefreqok * 5  / 6);
+	}
+
 	/* Queue up a new task to handle no reply */
-	/* If the host is already unreachable then use the unreachable interval instead */
-	if (peer->lastms < 0)
-		peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer_ref(peer));
-	else
-		peer->pokeexpire = iax2_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer_ref(peer));
+	peer->pokeexpire = iax2_sched_add(sched, poke_timeout, iax2_poke_noanswer, peer_ref(peer));
 
 	if (peer->pokeexpire == -1)
 		peer_unref(peer);
@@ -12455,6 +12489,11 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 			.buf = { 0 },
 			.pos = 0,
 		};
+
+		/* Speed up retransmission times for this qualify call */
+		iaxs[callno]->pingtime = peer->maxms / 8;
+		iaxs[callno]->peerpoke = peer;
+
 		add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
 		send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, ied.buf, ied.pos, -1);
 	}
@@ -12473,11 +12512,11 @@ static void free_context(struct iax2_context *con)
 	}
 }
 
-static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	int callno;
 	int res;
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	struct ast_channel *c;
 	struct parsed_dial_string pds;
 	struct create_addr_info cai;
@@ -12500,18 +12539,15 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
 	ast_copy_flags64(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
 
 	/* Populate our address from the given */
-	if (create_addr(pds.peer, NULL, &addr, &cai)) {
+	if (create_addr(pds.peer, NULL, &sin, &cai)) {
 		*cause = AST_CAUSE_UNREGISTERED;
 		return NULL;
 	}
 
-	if (pds.port) {
-		int bindport;
-		ast_parse_arg(pds.port, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535);
-		ast_sockaddr_set_port(&addr, bindport);
-	}
+	if (pds.port)
+		sin.sin_port = htons(atoi(pds.port));
 
-	callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
 	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to create call\n");
 		*cause = AST_CAUSE_CONGESTION;
@@ -12534,55 +12570,36 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
 		ast_string_field_set(iaxs[callno], host, pds.peer);
 	}
 
-	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, &cai.prefs, assignedids,
-		requestor, cai.found);
+	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? ast_channel_linkedid(requestor) : NULL, cai.found);
 
 	ast_mutex_unlock(&iaxsl[callno]);
 
 	if (c) {
 		struct ast_format_cap *joint;
-		struct ast_format *format;
 		if (callid) {
-			ast_channel_lock(c);
 			ast_channel_callid_set(c, callid);
-			ast_channel_unlock(c);
-		}
-
-		joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (!joint) {
-			ast_hangup(c);
-			return NULL;
 		}
 
-		ast_format_cap_get_compatible(ast_channel_nativeformats(c), cap, joint);
-
-		/* If there is no joint format find one through translation */
-		if (!ast_format_cap_count(joint)) {
-			struct ast_format *best_fmt_cap = NULL;
-			struct ast_format *best_fmt_native = NULL;
+		/* Choose a format we can live with */
+		if ((joint = ast_format_cap_joint(ast_channel_nativeformats(c), cap))) {
+			ast_format_cap_copy(ast_channel_nativeformats(c), joint);
+			joint = ast_format_cap_destroy(joint);
+		} else {
+			struct ast_format best_fmt_cap;
+			struct ast_format best_fmt_native;
 			res = ast_translator_best_choice(cap, ast_channel_nativeformats(c), &best_fmt_cap, &best_fmt_native);
 			if (res < 0) {
-				struct ast_str *native_cap_buf = ast_str_alloca(64);
-				struct ast_str *cap_buf = ast_str_alloca(64);
-
+				char tmp[256];
+				char tmp2[256];
 				ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n",
-					ast_format_cap_get_names(ast_channel_nativeformats(c), &native_cap_buf),
-					ast_format_cap_get_names(cap, &cap_buf),
-					ast_channel_name(c));
+					ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(c)), ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_channel_name(c));
 				ast_hangup(c);
 				return NULL;
 			}
-			ast_format_cap_append(joint, best_fmt_native, 0);
-			ao2_ref(best_fmt_cap, -1);
-			ao2_ref(best_fmt_native, -1);
+			ast_format_cap_set(ast_channel_nativeformats(c), &best_fmt_native);
 		}
-		ast_channel_nativeformats_set(c, joint);
-		format = ast_format_cap_get_format(ast_channel_nativeformats(c), 0);
-		ast_channel_set_readformat(c, format);
-		ast_channel_set_writeformat(c, format);
-
-		ao2_ref(joint, -1);
-		ao2_ref(format, -1);
+		ast_best_codec(ast_channel_nativeformats(c), ast_channel_readformat(c));
+		ast_format_copy(ast_channel_writeformat(c), ast_channel_readformat(c));
 	}
 
 	if (callid) {
@@ -12663,7 +12680,7 @@ static struct iax2_context *build_context(const char *context)
 
 	if ((con = ast_calloc(1, sizeof(*con))))
 		ast_copy_string(con->context, context, sizeof(con->context));
-
+	
 	return con;
 }
 
@@ -12725,7 +12742,8 @@ static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
 			port = IAX_DEFAULT_PORTNO;
 	}
 
-	addr.ss.ss_family = AST_AF_UNSPEC;
+	addr.ss.ss_family = AF_INET;
+
 	if (!ast_get_ip(&addr, host)) {
 		struct ast_netsock *sock;
 
@@ -12794,11 +12812,10 @@ static void peer_destructor(void *obj)
 	if (peer->dnsmgr)
 		ast_dnsmgr_release(peer->dnsmgr);
 
-	peer->mwi_event_sub = stasis_unsubscribe(peer->mwi_event_sub);
+	if (peer->mwi_event_sub)
+		ast_event_unsubscribe(peer->mwi_event_sub);
 
 	ast_string_field_free_memory(peer);
-
-	ast_endpoint_shutdown(peer->endpoint);
 }
 
 /*! \brief Create peer structure based on configuration */
@@ -12828,11 +12845,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 		peer->expire = -1;
 		peer->pokeexpire = -1;
 		peer->sockfd = defaultsockfd;
+		peer->addr.ss.ss_family = AF_INET;
+		peer->addr.len = sizeof(struct sockaddr_in);
 		if (ast_string_field_init(peer, 32))
 			peer = peer_unref(peer);
-		if (!(peer->endpoint = ast_endpoint_create("IAX2", name))) {
-			peer = peer_unref(peer);
-		}
 	}
 
 	if (peer) {
@@ -12840,14 +12856,13 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 			ast_copy_flags64(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
 			peer->encmethods = iax2_encryption;
 			peer->adsi = adsi;
-			ast_string_field_set(peer, secret, "");
+			ast_string_field_set(peer,secret,"");
 			if (!found) {
 				ast_string_field_set(peer, name, name);
-				ast_sockaddr_parse(&peer->addr, "0.0.0.0", 0);
 				ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
 				peer->expiry = min_reg_expire;
 			}
-			peer->prefs = prefs_global;
+			peer->prefs = prefs;
 			peer->capability = iax2_capability;
 			peer->smoothing = 0;
 			peer->pokefreqok = DEFAULT_FREQ_OK;
@@ -12875,15 +12890,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 				ast_string_field_set(peer, mailbox, v->value);
 			} else if (!strcasecmp(v->name, "hasvoicemail")) {
 				if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
-					/*
-					 * hasvoicemail is a users.conf legacy voicemail enable method.
-					 * hasvoicemail is only going to work for app_voicemail mailboxes.
-					 */
-					if (strchr(name, '@')) {
-						ast_string_field_set(peer, mailbox, name);
-					} else {
-						ast_string_field_build(peer, mailbox, "%s at default", name);
-					}
+					ast_string_field_set(peer, mailbox, name);
 				}
 			} else if (!strcasecmp(v->name, "mohinterpret")) {
 				ast_string_field_set(peer, mohinterpret, v->value);
@@ -12894,7 +12901,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 			} else if (!strcasecmp(v->name, "description")) {
 				ast_string_field_set(peer, description, v->value);
 			} else if (!strcasecmp(v->name, "trunk")) {
-				ast_set2_flag64(peer, ast_true(v->value), IAX_TRUNK);
+				ast_set2_flag64(peer, ast_true(v->value), IAX_TRUNK);	
 				if (ast_test_flag64(peer, IAX_TRUNK) && !timer) {
 					ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name);
 					ast_clear_flag64(peer, IAX_TRUNK);
@@ -12931,9 +12938,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 					/* They'll register with us */
 					ast_set_flag64(peer, IAX_DYNAMIC);
 					if (!found) {
-						int peer_port = ast_sockaddr_port(&peer->addr);
-						if (peer_port) {
-							ast_sockaddr_set_port(&peer->defaddr, peer_port);
+						/* Initialize stuff iff we're not found, otherwise
+						   we keep going with what we had */
+						if (ast_sockaddr_port(&peer->addr)) {
+							peer->defaddr.sin_port = htons(ast_sockaddr_port(&peer->addr));
 						}
 						ast_sockaddr_setnull(&peer->addr);
 					}
@@ -12941,22 +12949,23 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 					/* Non-dynamic.  Make sure we become that way if we're not */
 					AST_SCHED_DEL(sched, peer->expire);
 					ast_clear_flag64(peer, IAX_DYNAMIC);
-					peer->addr.ss.ss_family = AST_AF_UNSPEC;
-					if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) {
+					if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL))
 						return peer_unref(peer);
-					}
 					if (!ast_sockaddr_port(&peer->addr)) {
 						ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
 					}
 				}
+				if (!maskfound)
+					inet_aton("255.255.255.255", &peer->mask);
 			} else if (!strcasecmp(v->name, "defaultip")) {
 				struct ast_sockaddr peer_defaddr_tmp;
-				peer_defaddr_tmp.ss.ss_family = AF_UNSPEC;
+
+				peer_defaddr_tmp.ss.ss_family = AF_INET;
 				if (ast_get_ip(&peer_defaddr_tmp, v->value)) {
 					return peer_unref(peer);
 				}
-				ast_sockaddr_set_port(&peer_defaddr_tmp, ast_sockaddr_port(&peer->defaddr));
-				ast_sockaddr_copy(&peer->defaddr, &peer_defaddr_tmp);
+				ast_sockaddr_to_sin(&peer_defaddr_tmp,
+						    &peer->defaddr);
 			} else if (!strcasecmp(v->name, "sourceaddress")) {
 				peer_set_srcaddr(peer, v->value);
 			} else if (!strcasecmp(v->name, "permit") ||
@@ -12965,7 +12974,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 				ast_append_acl(v->name, v->value, &peer->acl, NULL, &subscribe_acl_change);
 			} else if (!strcasecmp(v->name, "mask")) {
 				maskfound++;
-				ast_sockaddr_parse(&peer->mask, v->value, 0);
+				inet_aton(v->value, &peer->mask);
 			} else if (!strcasecmp(v->name, "context")) {
 				ast_string_field_set(peer, context, v->value);
 			} else if (!strcasecmp(v->name, "regexten")) {
@@ -12973,14 +12982,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 			} else if (!strcasecmp(v->name, "peercontext")) {
 				ast_string_field_set(peer, peercontext, v->value);
 			} else if (!strcasecmp(v->name, "port")) {
-				int bindport;
-				if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
-					bindport = IAX_DEFAULT_PORTNO;
-				}
 				if (ast_test_flag64(peer, IAX_DYNAMIC)) {
-					ast_sockaddr_set_port(&peer->defaddr, bindport);
+					peer->defaddr.sin_port = htons(atoi(v->value));
 				} else {
-					ast_sockaddr_set_port(&peer->addr, bindport);
+					ast_sockaddr_set_port(&peer->addr, atoi(v->value));
 				}
 			} else if (!strcasecmp(v->name, "username")) {
 				ast_string_field_set(peer, username, v->value);
@@ -13077,31 +13082,23 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 		ast_clear_flag64(peer, IAX_DELME);
 	}
 
-	if (!maskfound && !ast_sockaddr_isnull(&peer->addr)) {
-		if (ast_sockaddr_is_ipv4_mapped(&peer->addr)) {
-			ast_sockaddr_parse(&peer->mask, "::ffff:ffff:ffff", 0);
-		} else if (ast_sockaddr_is_ipv6(&peer->addr)) {
-			ast_sockaddr_parse(&peer->mask, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0);
-		} else {
-			ast_sockaddr_parse(&peer->mask, "255.255.255.255", 0);
-		}
-	}
-
-	if (oldacl) {
+	if (oldacl)
 		ast_free_acl_list(oldacl);
-	}
 
 	if (!ast_strlen_zero(peer->mailbox)) {
-		struct stasis_topic *mailbox_specific_topic;
-
-		mailbox_specific_topic = ast_mwi_topic(peer->mailbox);
-		if (mailbox_specific_topic) {
-			peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
-		}
+		char *mailbox, *context;
+		context = mailbox = ast_strdupa(peer->mailbox);
+		strsep(&context, "@");
+		if (ast_strlen_zero(context))
+			context = "default";
+		peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "IAX MWI subscription", NULL,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+			AST_EVENT_IE_END);
 	}
 
 	if (subscribe_acl_change) {
-		acl_change_stasis_subscribe();
+		acl_change_event_subscribe();
 	}
 
 	return peer;
@@ -13153,7 +13150,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
  	} else {
 		user = ao2_alloc(sizeof(*user), user_destructor);
 	}
-
+	
 	if (user) {
 		if (firstpass) {
 			ast_string_field_free_memory(user);
@@ -13164,7 +13161,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
 			}
 			user->maxauthreq = maxauthreq;
 			user->curauthreq = oldcurauthreq;
-			user->prefs = prefs_global;
+			user->prefs = prefs;
 			user->capability = iax2_capability;
 			user->encmethods = iax2_encryption;
 			user->adsi = adsi;
@@ -13203,7 +13200,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
 					*varval = '\0';
 					varval++;
 					if((tmpvar = ast_variable_new(varname, varval, ""))) {
-						tmpvar->next = user->vars;
+						tmpvar->next = user->vars; 
 						user->vars = tmpvar;
 					}
 				}
@@ -13212,7 +13209,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
 			} else if (!strcasecmp(v->name, "disallow")) {
 				iax2_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
 			} else if (!strcasecmp(v->name, "trunk")) {
-				ast_set2_flag64(user, ast_true(v->value), IAX_TRUNK);
+				ast_set2_flag64(user, ast_true(v->value), IAX_TRUNK);	
 				if (ast_test_flag64(user, IAX_TRUNK) && !timer) {
 					ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name);
 					ast_clear_flag64(user, IAX_TRUNK);
@@ -13306,7 +13303,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
 			} else if (!strcasecmp(v->name, "language")) {
 				ast_string_field_set(user, language, v->value);
 			} else if (!strcasecmp(v->name, "amaflags")) {
-				format = ast_channel_string2amaflag(v->value);
+				format = ast_cdr_amaflags2int(v->value);
 				if (format < 0) {
 					ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
 				} else {
@@ -13373,7 +13370,7 @@ cleanup:
 	}
 
 	if (subscribe_acl_change) {
-		acl_change_stasis_subscribe();
+		acl_change_event_subscribe();
 	}
 
 	return user;
@@ -13477,7 +13474,7 @@ static void set_config_destroy(void)
 static int set_config(const char *config_file, int reload, int forced)
 {
 	struct ast_config *cfg, *ucfg;
-	iax2_format capability;
+	iax2_format capability = iax2_capability;
 	struct ast_variable *v;
 	char *cat;
 	const char *utype;
@@ -13491,8 +13488,9 @@ static int set_config(const char *config_file, int reload, int forced)
 	struct iax2_peer *peer;
 	struct ast_netsock *ns;
 	struct ast_flags config_flags = { (reload && !forced) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	struct ast_sockaddr bindaddr;
-	struct iax2_codec_pref prefs_new;
+#if 0
+	static unsigned short int last_port=0;
+#endif
 
 	cfg = ast_config_load(config_file, config_flags);
 
@@ -13531,10 +13529,8 @@ static int set_config(const char *config_file, int reload, int forced)
 		set_config_destroy();
 	}
 
-	ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
-
-	/* Setup new codec prefs */
-	capability = iax2_codec_pref_from_bitfield(&prefs_new, IAX_CAPABILITY_FULLBANDWIDTH);
+	/* Reset global codec prefs */
+	memset(&prefs, 0 , sizeof(struct ast_codec_pref));
 
 	/* Reset Global Flags */
 	memset(&globalflags, 0, sizeof(globalflags));
@@ -13572,16 +13568,13 @@ static int set_config(const char *config_file, int reload, int forced)
 			ast_log(LOG_WARNING, "Invalid cos value, refer to QoS documentation\n");
 	}
 	while(v) {
-		if (!strcasecmp(v->name, "bindport")) {
-			if (reload) {
+		if (!strcasecmp(v->name, "bindport")){ 
+			if (reload)
 				ast_log(LOG_NOTICE, "Ignoring bindport on reload\n");
-			}
-			else if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE, &portno, 1024, 65535)) {
-				portno = IAX_DEFAULT_PORTNO;
-			}
-		} else if (!strcasecmp(v->name, "pingtime")){
+			else
+				portno = atoi(v->value);
+		} else if (!strcasecmp(v->name, "pingtime")) 
 			ping_time = atoi(v->value);
-		}
 		else if (!strcasecmp(v->name, "iaxthreadcount")) {
 			if (reload) {
 				if (atoi(v->value) != iaxthreadcount)
@@ -13622,46 +13615,34 @@ static int set_config(const char *config_file, int reload, int forced)
 				ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
 #endif
 		}
-		else if (!strcasecmp(v->name, "maxjitterbuffer"))
+		else if (!strcasecmp(v->name, "maxjitterbuffer")) 
 			maxjitterbuffer = atoi(v->value);
-		else if (!strcasecmp(v->name, "resyncthreshold"))
+		else if (!strcasecmp(v->name, "resyncthreshold")) 
 			resyncthreshold = atoi(v->value);
-		else if (!strcasecmp(v->name, "maxjitterinterps"))
+		else if (!strcasecmp(v->name, "maxjitterinterps")) 
 			maxjitterinterps = atoi(v->value);
 		else if (!strcasecmp(v->name, "jittertargetextra"))
 			jittertargetextra = atoi(v->value);
-		else if (!strcasecmp(v->name, "lagrqtime"))
+		else if (!strcasecmp(v->name, "lagrqtime")) 
 			lagrq_time = atoi(v->value);
-		else if (!strcasecmp(v->name, "maxregexpire"))
+		else if (!strcasecmp(v->name, "maxregexpire")) 
 			max_reg_expire = atoi(v->value);
-		else if (!strcasecmp(v->name, "minregexpire"))
+		else if (!strcasecmp(v->name, "minregexpire")) 
 			min_reg_expire = atoi(v->value);
 		else if (!strcasecmp(v->name, "bindaddr")) {
 			if (reload) {
 				ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
 			} else {
-
-				if (!ast_parse_arg(v->value, PARSE_ADDR, NULL)) {
-
-					ast_sockaddr_parse(&bindaddr, v->value, 0);
-
-					if (!ast_sockaddr_port(&bindaddr)) {
-						ast_sockaddr_set_port(&bindaddr, portno);
-					}
-
-					if (!(ns = ast_netsock_bindaddr(netsock, io, &bindaddr, qos.tos, qos.cos, socket_read, NULL))) {
-						ast_log(LOG_WARNING, "Unable to apply binding to '%s' at line %d\n", v->value, v->lineno);
-					} else {
-						ast_verb(2, "Binding IAX2 to address %s\n", ast_sockaddr_stringify(&bindaddr));
-
-						if (defaultsockfd < 0) {
-							defaultsockfd = ast_netsock_sockfd(ns);
-						}
-						ast_netsock_unref(ns);
-					}
-
+				if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, qos.tos, qos.cos, socket_read, NULL))) {
+					ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno);
 				} else {
-					ast_log(LOG_WARNING, "Invalid address '%s' specified, at line %d\n", v->value, v->lineno);
+						if (strchr(v->value, ':'))
+						ast_verb(2, "Binding IAX2 to '%s'\n", v->value);
+						else
+						ast_verb(2, "Binding IAX2 to '%s:%d'\n", v->value, portno);
+					if (defaultsockfd < 0) 
+						defaultsockfd = ast_netsock_sockfd(ns);
+					ast_netsock_unref(ns);
 				}
 			}
 		} else if (!strcasecmp(v->name, "authdebug")) {
@@ -13759,21 +13740,17 @@ static int set_config(const char *config_file, int reload, int forced)
 			}
 		} else if (!strcasecmp(v->name, "bandwidth")) {
 			if (!strcasecmp(v->value, "low")) {
-				capability = iax2_codec_pref_from_bitfield(&prefs_new,
-					IAX_CAPABILITY_LOWBANDWIDTH);
+				capability = IAX_CAPABILITY_LOWBANDWIDTH;
 			} else if (!strcasecmp(v->value, "medium")) {
-				capability = iax2_codec_pref_from_bitfield(&prefs_new,
-					IAX_CAPABILITY_MEDBANDWIDTH);
+				capability = IAX_CAPABILITY_MEDBANDWIDTH;
 			} else if (!strcasecmp(v->value, "high")) {
-				capability = iax2_codec_pref_from_bitfield(&prefs_new,
-					IAX_CAPABILITY_FULLBANDWIDTH);
-			} else {
+				capability = IAX_CAPABILITY_FULLBANDWIDTH;
+			} else
 				ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
-			}
 		} else if (!strcasecmp(v->name, "allow")) {
-			iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 1);
+			iax2_parse_allow_disallow(&prefs, &capability, v->value, 1);
 		} else if (!strcasecmp(v->name, "disallow")) {
-			iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 0);
+			iax2_parse_allow_disallow(&prefs, &capability, v->value, 0);
 		} else if (!strcasecmp(v->name, "register")) {
 			iax2_register(v->value, v->lineno);
 		} else if (!strcasecmp(v->name, "iaxcompat")) {
@@ -13797,7 +13774,7 @@ static int set_config(const char *config_file, int reload, int forced)
 		} else if (!strcasecmp(v->name, "mohsuggest")) {
 			ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
 		} else if (!strcasecmp(v->name, "amaflags")) {
-			format = ast_channel_string2amaflag(v->value);
+			format = ast_cdr_amaflags2int(v->value);
 			if (format < 0) {
 				ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
 			} else {
@@ -13859,19 +13836,16 @@ static int set_config(const char *config_file, int reload, int forced)
 	}
 
 	if (subscribe_network_change) {
-		network_change_stasis_subscribe();
+		network_change_event_subscribe();
 	} else {
-		network_change_stasis_unsubscribe();
+		network_change_event_unsubscribe();
 	}
 
 	if (defaultsockfd < 0) {
-
-		ast_sockaddr_set_port(&bindaddr, portno);
-
-		if (!(ns = ast_netsock_bindaddr(netsock, io, &bindaddr, qos.tos, qos.cos, socket_read, NULL))) {
+		if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, qos.tos, qos.cos, socket_read, NULL))) {
 			ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
 		} else {
-			ast_verb(2, "Binding IAX2 to default address %s\n", ast_sockaddr_stringify(&bindaddr));
+			ast_verb(2, "Binding IAX2 to default address 0.0.0.0:%d\n", portno);
 			defaultsockfd = ast_netsock_sockfd(ns);
 			ast_netsock_unref(ns);
 		}
@@ -13891,15 +13865,14 @@ static int set_config(const char *config_file, int reload, int forced)
 			min_reg_expire, max_reg_expire, max_reg_expire);
 		min_reg_expire = max_reg_expire;
 	}
-	prefs_global = prefs_new;
 	iax2_capability = capability;
-
+	
 	if (ucfg) {
 		struct ast_variable *gen;
 		int genhasiax;
 		int genregisteriax;
 		const char *hasiax, *registeriax;
-
+		
 		genhasiax = ast_true(ast_variable_retrieve(ucfg, "general", "hasiax"));
 		genregisteriax = ast_true(ast_variable_retrieve(ucfg, "general", "registeriax"));
 		gen = ast_variable_browse(ucfg, "general");
@@ -13917,9 +13890,8 @@ static int set_config(const char *config_file, int reload, int forced)
 					}
 					peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
 					if (peer) {
-						if (ast_test_flag64(peer, IAX_DYNAMIC)) {
+						if (ast_test_flag64(peer, IAX_DYNAMIC))
 							reg_source_db(peer);
-						}
 						ao2_link(peers, peer);
 						peer = peer_unref(peer);
 					}
@@ -13948,7 +13920,7 @@ static int set_config(const char *config_file, int reload, int forced)
 		}
 		ast_config_destroy(ucfg);
 	}
-
+	
 	cat = ast_category_browse(cfg, NULL);
 	while(cat) {
 		if (strcasecmp(cat, "general")) {
@@ -14006,7 +13978,7 @@ static int reload_config(int forced_reload)
 		ao2_callback(callno_limits, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, prune_addr_range_cb, NULL);
 		ao2_callback(calltoken_ignores, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, prune_addr_range_cb, NULL);
 		ao2_callback(peercnts, OBJ_NODATA, set_peercnt_limit_all_cb, NULL);
-		trunk_timed = trunk_untimed = 0;
+		trunk_timed = trunk_untimed = 0; 
 		trunk_nmaxmtu = trunk_maxmtu = 0;
 		memset(&debugaddr, '\0', sizeof(debugaddr));
 
@@ -14018,8 +13990,8 @@ static int reload_config(int forced_reload)
 		/* Qualify hosts, too */
 		poke_all_peers();
 	}
-
-	iax_firmware_reload();
+	
+	reload_firmware(0);
 	iax_provision_reload(1);
 	ast_unload_realtime("iaxpeers");
 
@@ -14051,7 +14023,7 @@ static int reload(void)
 
 static int cache_get_callno_locked(const char *data)
 {
-	struct ast_sockaddr addr;
+	struct sockaddr_in sin;
 	int x;
 	int callno;
 	struct iax_ie_data ied;
@@ -14084,13 +14056,13 @@ static int cache_get_callno_locked(const char *data)
 	}
 
 	/* Populate our address from the given */
-	if (create_addr(pds.peer, NULL, &addr, &cai))
+	if (create_addr(pds.peer, NULL, &sin, &cai))
 		return -1;
 
 	ast_debug(1, "peer: %s, username: %s, password: %s, context: %s\n",
 		pds.peer, pds.username, pds.password, pds.context);
 
-	callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
 	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to create call\n");
 		return -1;
@@ -14251,7 +14223,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
 		if (!old && chan)
 			ast_channel_undefer_dtmf(chan);
 	}
-	return dp;
+	return dp;	
 }
 
 /*! \brief Part of the IAX2 switch interface */
@@ -14339,7 +14311,7 @@ static int iax2_exec(struct ast_channel *chan, const char *context, const char *
 		const char *dialstatus = pbx_builtin_getvar_helper(chan, "DIALSTATUS");
 		if (dialstatus) {
 			dial = pbx_findapp(dialstatus);
-			if (dial)
+			if (dial) 
 				pbx_exec(chan, dial, "");
 		}
 		return -1;
@@ -14388,8 +14360,8 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
 		if (!chan || ast_channel_tech(chan) != &iax2_tech) {
 			return -1;
 		}
-		callno = PTR_TO_CALLNO(ast_channel_tech_pvt(chan));
-		ast_copy_string(buf, !ast_sockaddr_isnull(&iaxs[callno]->addr) ? ast_sockaddr_stringify_addr(&iaxs[callno]->addr) : "", len);
+		callno = PTR_TO_CALLNO(ast_channel_tech_pvt(chan));	
+		ast_copy_string(buf, iaxs[callno]->addr.sin_addr.s_addr ? ast_inet_ntoa(iaxs[callno]->addr.sin_addr) : "", len);
 		return 0;
 	}
 
@@ -14404,7 +14376,7 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
 	if (!strcasecmp(colname, "ip")) {
 		ast_copy_string(buf, ast_sockaddr_stringify_addr(&peer->addr), len);
 	} else  if (!strcasecmp(colname, "status")) {
-		peer_status(peer, buf, len);
+		peer_status(peer, buf, len); 
 	} else  if (!strcasecmp(colname, "mailbox")) {
 		ast_copy_string(buf, peer->mailbox, len);
 	} else  if (!strcasecmp(colname, "context")) {
@@ -14418,13 +14390,10 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
 	} else  if (!strcasecmp(colname, "callerid_num")) {
 		ast_copy_string(buf, peer->cid_num, len);
 	} else  if (!strcasecmp(colname, "codecs")) {
-		struct ast_str *codec_buf = ast_str_alloca(256);
-
-		iax2_getformatname_multiple(peer->capability, &codec_buf);
-		ast_copy_string(buf, ast_str_buffer(codec_buf), len);
+		iax2_getformatname_multiple(buf, len -1, peer->capability);
 	} else  if (!strncasecmp(colname, "codec[", 6)) {
 		char *codecnum, *ptr;
-		struct ast_format *tmpfmt;
+		struct ast_format tmpfmt;
 
 		/* skip over "codec" to the '[' */
 		codecnum = colname + 5;
@@ -14433,8 +14402,8 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
 		if ((ptr = strchr(codecnum, ']'))) {
 			*ptr = '\0';
 		}
-		if((iax2_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) {
-			ast_copy_string(buf, ast_format_get_name(tmpfmt), len);
+		if((ast_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) {
+			ast_copy_string(buf, ast_getformatname(&tmpfmt), len);
 		} else {
 			buf[0] = '\0';
 		}
@@ -14473,7 +14442,7 @@ static int acf_channel_read(struct ast_channel *chan, const char *funcname, char
 	if (!strcasecmp(args, "osptoken")) {
 		ast_copy_string(buf, pvt->osptoken, buflen);
 	} else if (!strcasecmp(args, "peerip")) {
-		ast_copy_string(buf, !ast_sockaddr_isnull(&pvt->addr) ? ast_sockaddr_stringify_addr(&pvt->addr) : "", buflen);
+		ast_copy_string(buf, pvt->addr.sin_addr.s_addr ? ast_inet_ntoa(pvt->addr.sin_addr) : "", buflen);
 	} else if (!strcasecmp(args, "peername")) {
 		ast_copy_string(buf, pvt->username, buflen);
 	} else if (!strcasecmp(args, "secure_signaling") || !strcasecmp(args, "secure_media")) {
@@ -14510,11 +14479,10 @@ static int iax2_devicestate(const char *data)
 		return res;
 
 	res = AST_DEVICE_UNAVAILABLE;
+	ast_debug(3, "Found peer. What's device state of %s? addr=%u, defaddr=%u maxms=%d, lastms=%d\n",
+		pds.peer, ast_sockaddr_ipv4(&p->addr), p->defaddr.sin_addr.s_addr, p->maxms, p->lastms);
 
-	ast_debug(3, "Found peer. What's device state of %s? addr=%s, defaddr=%s maxms=%d, lastms=%d\n",
-		pds.peer, ast_sockaddr_stringify(&p->addr), ast_sockaddr_stringify(&p->defaddr), p->maxms, p->lastms);
-
-	if (((!ast_sockaddr_isnull(&p->addr)) || (!ast_sockaddr_isnull(&p->defaddr))) &&
+	if ((ast_sockaddr_ipv4(&p->addr) || p->defaddr.sin_addr.s_addr) &&
 	    (!p->maxms || ((p->lastms > -1) && (p->historicms <= p->maxms)))) {
 		/* Peer is registered, or have default IP address
 		   and a valid registration */
@@ -14538,6 +14506,110 @@ static struct ast_switch iax2_switch =
 	.matchmore   = iax2_matchmore,
 };
 
+/*
+	{ { "iax2", "show", "cache", NULL },
+	iax2_show_cache, "Display IAX cached dialplan",
+	show_cache_usage },
+
+	{ { "iax2", "show", "channels", NULL },
+	iax2_show_channels, "List active IAX channels",
+	show_channels_usage },
+
+	{ { "iax2", "show", "firmware", NULL },
+	iax2_show_firmware, "List available IAX firmwares",
+	show_firmware_usage },
+
+	{ { "iax2", "show", "netstats", NULL },
+	iax2_show_netstats, "List active IAX channel netstats",
+	show_netstats_usage },
+
+	{ { "iax2", "show", "peers", NULL },
+	iax2_show_peers, "List defined IAX peers",
+	show_peers_usage },
+
+	{ { "iax2", "show", "registry", NULL },
+	iax2_show_registry, "Display IAX registration status",
+	show_reg_usage },
+
+	{ { "iax2", "show", "stats", NULL },
+	iax2_show_stats, "Display IAX statistics",
+	show_stats_usage },
+
+	{ { "iax2", "show", "threads", NULL },
+	iax2_show_threads, "Display IAX helper thread info",
+	show_threads_usage },
+
+	{ { "iax2", "unregister", NULL },
+	iax2_unregister, "Unregister (force expiration) an IAX2 peer from the registry",
+	unregister_usage, complete_iax2_unregister },
+
+	{ { "iax2", "set", "mtu", NULL },
+	iax2_set_mtu, "Set the IAX systemwide trunking MTU",
+	set_mtu_usage, NULL, NULL },
+
+	{ { "iax2", "show", "users", NULL },
+	iax2_show_users, "List defined IAX users",
+	show_users_usage },
+
+	{ { "iax2", "prune", "realtime", NULL },
+	iax2_prune_realtime, "Prune a cached realtime lookup",
+	prune_realtime_usage, complete_iax2_show_peer },
+
+	{ { "iax2", "reload", NULL },
+	iax2_reload, "Reload IAX configuration",
+	iax2_reload_usage },
+
+	{ { "iax2", "show", "peer", NULL },
+	iax2_show_peer, "Show details on specific IAX peer",
+	show_peer_usage, complete_iax2_show_peer },
+
+	{ { "iax2", "set", "debug", NULL },
+	iax2_do_debug, "Enable IAX debugging",
+	debug_usage },
+
+	{ { "iax2", "set", "debug", "trunk", NULL },
+	iax2_do_trunk_debug, "Enable IAX trunk debugging",
+	debug_trunk_usage },
+
+	{ { "iax2", "set", "debug", "jb", NULL },
+	iax2_do_jb_debug, "Enable IAX jitterbuffer debugging",
+	debug_jb_usage },
+
+	{ { "iax2", "set", "debug", "off", NULL },
+	iax2_no_debug, "Disable IAX debugging",
+	no_debug_usage },
+
+	{ { "iax2", "set", "debug", "trunk", "off", NULL },
+	iax2_no_trunk_debug, "Disable IAX trunk debugging",
+	no_debug_trunk_usage },
+
+	{ { "iax2", "set", "debug", "jb", "off", NULL },
+	iax2_no_jb_debug, "Disable IAX jitterbuffer debugging",
+	no_debug_jb_usage },
+
+	{ { "iax2", "test", "losspct", NULL },
+	iax2_test_losspct, "Set IAX2 incoming frame loss percentage",
+	iax2_test_losspct_usage },
+
+	{ { "iax2", "provision", NULL },
+	iax2_prov_cmd, "Provision an IAX device",
+	show_prov_usage, iax2_prov_complete_template_3rd },
+
+#ifdef IAXTESTS
+	{ { "iax2", "test", "late", NULL },
+	iax2_test_late, "Test the receipt of a late frame",
+	iax2_test_late_usage },
+
+	{ { "iax2", "test", "resync", NULL },
+	iax2_test_resync, "Test a resync in received timestamps",
+	iax2_test_resync_usage },
+
+	{ { "iax2", "test", "jitter", NULL },
+	iax2_test_jitter, "Simulates jitter for testing",
+	iax2_test_jitter_usage },
+#endif
+*/
+
 static struct ast_cli_entry cli_iax2[] = {
 	AST_CLI_DEFINE(handle_cli_iax2_provision,           "Provision an IAX device"),
 	AST_CLI_DEFINE(handle_cli_iax2_prune_realtime,      "Prune a cached realtime lookup"),
@@ -14711,11 +14783,10 @@ static void cleanup_thread_list(void *head)
 
 static int __unload_module(void)
 {
-	struct ast_context *con;
 	int x;
 
-	network_change_stasis_unsubscribe();
-	acl_change_stasis_unsubscribe();
+	network_change_event_unsubscribe();
+	acl_change_event_unsubscribe();
 
 	ast_manager_unregister("IAXpeers");
 	ast_manager_unregister("IAXpeerlist");
@@ -14765,7 +14836,7 @@ static int __unload_module(void)
 	ast_channel_unregister(&iax2_tech);
 	delete_users();
 	iax_provision_unload();
-	iax_firmware_unload();
+	reload_firmware(1);
 
 	for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
 		ast_mutex_destroy(&iaxsl[x]);
@@ -14775,7 +14846,6 @@ static int __unload_module(void)
 	ao2_ref(users, -1);
 	ao2_ref(iax_peercallno_pvts, -1);
 	ao2_ref(iax_transfercallno_pvts, -1);
-	ao2_ref(peercnts, -1);
 	ao2_ref(callno_limits, -1);
 	ao2_ref(calltoken_ignores, -1);
 	if (timer) {
@@ -14783,16 +14853,19 @@ static int __unload_module(void)
 		timer = NULL;
 	}
 	transmit_processor = ast_taskprocessor_unreference(transmit_processor);
+
+	ast_sched_clean_by_callback(sched, peercnt_remove_cb, peercnt_remove_cb);
+	ast_sched_clean_by_callback(sched, replace_callno, replace_callno);
 	ast_sched_context_destroy(sched);
 	sched = NULL;
+	ao2_ref(peercnts, -1);
+	ao2_ref(callno_pool, -1);
+	ao2_ref(callno_pool_trunk, -1);
 
-	con = ast_context_find(regcontext);
-	if (con)
-		ast_context_destroy(con, "IAX2");
+	ast_context_destroy_by_name(regcontext, "IAX2");
 	ast_unload_realtime("iaxpeers");
 
-	ao2_ref(iax2_tech.capabilities, -1);
-	iax2_tech.capabilities = NULL;
+	iax2_tech.capabilities = ast_format_cap_destroy(iax2_tech.capabilities);
 	return 0;
 }
 
@@ -14827,7 +14900,7 @@ static int pvt_cmp_cb(void *obj, void *arg, int flags)
 	/* The frames_received field is used to hold whether we're matching
 	 * against a full frame or not ... */
 
-	return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt,
+	return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt, 
 		pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
 }
 
@@ -14852,7 +14925,7 @@ static int transfercallno_pvt_cmp_cb(void *obj, void *arg, int flags)
 static int load_objects(void)
 {
 	peers = users = iax_peercallno_pvts = iax_transfercallno_pvts = NULL;
-	peercnts = callno_limits = calltoken_ignores = NULL;
+	peercnts = callno_limits = calltoken_ignores = callno_pool = callno_pool_trunk = NULL;
 
 	if (!(peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb))) {
 		goto container_fail;
@@ -14898,6 +14971,12 @@ container_fail:
 	if (calltoken_ignores) {
 		ao2_ref(calltoken_ignores, -1);
 	}
+	if (callno_pool) {
+		ao2_ref(callno_pool, -1);
+	}
+	if (callno_pool_trunk) {
+		ao2_ref(callno_pool_trunk, -1);
+	}
 	return AST_MODULE_LOAD_FAILURE;
 }
 
@@ -14957,7 +15036,7 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 
 		ast_data_add_str(data_peer, "host", ast_sockaddr_stringify_host(&peer->addr));
 
-		ast_data_add_str(data_peer, "mask", ast_sockaddr_stringify_addr(&peer->mask));
+		ast_data_add_str(data_peer, "mask", ast_inet_ntoa(peer->mask));
 
 		ast_data_add_int(data_peer, "port", ast_sockaddr_port(&peer->addr));
 
@@ -15001,14 +15080,9 @@ static int users_data_provider_get(const struct ast_data_search *search,
 	struct ast_data *data_user, *data_authmethods, *data_enum_node;
 	struct iax2_user *user;
 	struct ao2_iterator i;
-	struct ast_str *auth;
+	char auth[90];
 	char *pstr = "";
 
-	if (!(auth = ast_str_create(90))) {
-		ast_log(LOG_ERROR, "Unable to create temporary string for storing 'secret'\n");
-		return 0;
-	}
-
 	i = ao2_iterator_init(users, 0);
 	for (; (user = ao2_iterator_next(&i)); user_unref(user)) {
 		data_user = ast_data_add_node(data_root, "user");
@@ -15021,13 +15095,13 @@ static int users_data_provider_get(const struct ast_data_search *search,
 		iax2_data_add_codecs(data_user, "codecs", user->capability);
 
 		if (!ast_strlen_zero(user->secret)) {
-			ast_str_set(&auth, 0, "%s", user->secret);
+			ast_copy_string(auth, user->secret, sizeof(auth));
 		} else if (!ast_strlen_zero(user->inkeys)) {
-			ast_str_set(&auth, 0, "Key: %s", user->inkeys);
+			snprintf(auth, sizeof(auth), "Key: %s", user->inkeys);
 		} else {
-			ast_str_set(&auth, 0, "no secret");
+			ast_copy_string(auth, "no secret", sizeof(auth));
 		}
-		ast_data_add_password(data_user, "secret", ast_str_buffer(auth));
+		ast_data_add_password(data_user, "secret", auth);
 
 		ast_data_add_str(data_user, "context", user->contexts ? user->contexts->context : DEFAULT_CONTEXT);
 
@@ -15048,7 +15122,7 @@ static int users_data_provider_get(const struct ast_data_search *search,
 			continue;
 		}
 		ast_data_add_int(data_enum_node, "value", user->amaflags);
-		ast_data_add_str(data_enum_node, "text", ast_channel_amaflags2string(user->amaflags));
+		ast_data_add_str(data_enum_node, "text", ast_cdr_flags2str(user->amaflags));
 
 		ast_data_add_bool(data_user, "access-control", ast_acl_list_is_empty(user->acl) ? 0 : 1);
 
@@ -15067,7 +15141,6 @@ static int users_data_provider_get(const struct ast_data_search *search,
 	}
 	ao2_iterator_destroy(&i);
 
-	ast_free(auth);
 	return 0;
 }
 
@@ -15086,26 +15159,17 @@ static const struct ast_data_entry iax2_data_providers[] = {
 	AST_DATA_ENTRY("asterisk/channel/iax2/users", &users_data_provider),
 };
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief Load IAX2 module, load configuraiton ---*/
 static int load_module(void)
 {
 	static const char config[] = "iax.conf";
 	int x = 0;
 	struct iax2_registry *reg = NULL;
 
-	if (!(iax2_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(iax2_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_format_cap_append_by_type(iax2_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_add_all(iax2_tech.capabilities);
 
 	if (load_objects()) {
 		return AST_MODULE_LOAD_FAILURE;
@@ -15143,7 +15207,7 @@ static int load_module(void)
 		return AST_MODULE_LOAD_FAILURE;
 	}
 	ast_netsock_init(netsock);
-
+	
 	outsock = ast_netsock_list_alloc();
 	if (!outsock) {
 		ast_log(LOG_ERROR, "Could not allocate outsock list.\n");
@@ -15159,7 +15223,7 @@ static int load_module(void)
 	iax_set_output(iax_debug_output);
 	iax_set_error(iax_error_output);
 	jb_setoutput(jb_error_output, jb_warning_output, NULL);
-
+	
 	if ((timer = ast_timer_open())) {
 		ast_timer_set_rate(timer, 1000 / trunkfreq);
 	}
@@ -15212,24 +15276,23 @@ static int load_module(void)
 	AST_LIST_LOCK(&registrations);
 	AST_LIST_TRAVERSE(&registrations, reg, entry)
 		iax2_do_register(reg);
-	AST_LIST_UNLOCK(&registrations);
-
+	AST_LIST_UNLOCK(&registrations);	
+	
 	ao2_callback(peers, 0, peer_set_sock_cb, NULL);
 	ao2_callback(peers, 0, iax2_poke_peer_cb, NULL);
 
 
-	iax_firmware_reload();
+	reload_firmware(0);
 	iax_provision_reload(0);
 
 	ast_realtime_require_field("iaxpeers", "name", RQ_CHAR, 10, "ipaddr", RQ_CHAR, 15, "port", RQ_UINTEGER2, 5, "regseconds", RQ_UINTEGER2, 6, SENTINEL);
 
-	network_change_stasis_subscribe();
+	network_change_event_subscribe();
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Inter Asterisk eXchange (Ver 2)",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
new file mode 100644
index 0000000..8a2ce47
--- /dev/null
+++ b/channels/chan_jingle.c
@@ -0,0 +1,2051 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Matt O'Gorman <mogorman at digium.com>
+ *
+ * \brief Jingle Channel Driver
+ *
+ * \extref Iksemel http://iksemel.jabberstudio.org/
+ * 
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+	<depend>iksemel</depend>
+	<depend>res_jabber</depend>
+	<use type="external">openssl</use>
+	<defaultenabled>no</defaultenabled>
+	<support_level>deprecated</support_level>
+	<replacement>chan_motif</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/signal.h>
+#include <iksemel.h>
+#include <pthread.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/manager.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/utils.h"
+#include "asterisk/causes.h"
+#include "asterisk/astobj.h"
+#include "asterisk/abstract_jb.h"
+#include "asterisk/jabber.h"
+#include "asterisk/jingle.h"
+
+#define JINGLE_CONFIG "jingle.conf"
+
+/*! Global jitterbuffer configuration - by default, jb is disabled */
+static struct ast_jb_conf default_jbconf =
+{
+	.flags = 0,
+	.max_size = -1,
+	.resync_threshold = -1,
+	.impl = "",
+	.target_extra = -1,
+};
+static struct ast_jb_conf global_jbconf;
+
+enum jingle_protocol {
+	AJI_PROTOCOL_UDP,
+	AJI_PROTOCOL_SSLTCP,
+};
+
+enum jingle_connect_type {
+	AJI_CONNECT_HOST,
+	AJI_CONNECT_PRFLX,
+	AJI_CONNECT_RELAY,
+	AJI_CONNECT_SRFLX,
+};
+
+struct jingle_pvt {
+	ast_mutex_t lock;                /*!< Channel private lock */
+	time_t laststun;
+	struct jingle *parent;	         /*!< Parent client */
+	char sid[100];
+	char them[AJI_MAX_JIDLEN];
+	char ring[10];                   /*!< Message ID of ring */
+	iksrule *ringrule;               /*!< Rule for matching RING request */
+	int initiator;                   /*!< If we're the initiator */
+	int alreadygone;
+	struct ast_codec_pref prefs;
+	struct jingle_candidate *theircandidates;
+	struct jingle_candidate *ourcandidates;
+	char cid_num[80];                /*!< Caller ID num */
+	char cid_name[80];               /*!< Caller ID name */
+	char exten[80];                  /*!< Called extension */
+	struct ast_channel *owner;       /*!< Master Channel */
+	char audio_content_name[100];    /*!< name attribute of content tag */
+	struct ast_rtp_instance *rtp;             /*!< RTP audio session */
+	char video_content_name[100];    /*!< name attribute of content tag */
+	struct ast_rtp_instance *vrtp;            /*!< RTP video session */
+	struct ast_format_cap *cap;
+	struct ast_format_cap *jointcap;             /*!< Supported capability at both ends (codecs ) */
+	struct ast_format_cap *peercap;
+	struct jingle_pvt *next;	/* Next entity */
+};
+
+struct jingle_candidate {
+	unsigned int component;          /*!< ex. : 1 for RTP, 2 for RTCP */
+	unsigned int foundation;         /*!< Function of IP, protocol, type */
+	unsigned int generation;
+	char ip[16];
+	unsigned int network;
+	unsigned int port;
+	unsigned int priority;
+	enum jingle_protocol protocol;
+	char password[100];
+	enum jingle_connect_type type;
+	char ufrag[100];
+	unsigned int preference;
+	struct jingle_candidate *next;
+};
+
+struct jingle {
+	ASTOBJ_COMPONENTS(struct jingle);
+	struct aji_client *connection;
+	struct aji_buddy *buddy;
+	struct jingle_pvt *p;
+	struct ast_codec_pref prefs;
+	int amaflags;			/*!< AMA Flags */
+	char user[100];
+	char context[100];
+	char accountcode[AST_MAX_ACCOUNT_CODE];	/*!< Account code */
+	struct ast_format_cap *cap;
+	ast_group_t callgroup;	/*!< Call group */
+	ast_group_t pickupgroup;	/*!< Pickup group */
+	int callingpres;		/*!< Calling presentation */
+	int allowguest;
+	char language[MAX_LANGUAGE];	/*!<  Default language for prompts */
+	char musicclass[MAX_MUSICCLASS];	/*!<  Music on Hold class */
+	char parkinglot[AST_MAX_CONTEXT];   /*!< Parkinglot */
+};
+
+struct jingle_container {
+	ASTOBJ_CONTAINER_COMPONENTS(struct jingle);
+};
+
+static const char desc[] = "Jingle Channel";
+static const char channel_type[] = "Jingle";
+
+static struct ast_format_cap *global_capability;
+
+AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_pvt's) */
+
+/* Forward declarations */
+static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int jingle_sendtext(struct ast_channel *ast, const char *text);
+static int jingle_digit_begin(struct ast_channel *ast, char digit);
+static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
+static int jingle_hangup(struct ast_channel *ast);
+static int jingle_answer(struct ast_channel *ast);
+static int jingle_newcall(struct jingle *client, ikspak *pak);
+static struct ast_frame *jingle_read(struct ast_channel *ast);
+static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
+static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
+static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid);
+static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+
+/*! \brief PBX interface structure for channel registration */
+static struct ast_channel_tech jingle_tech = {
+	.type = "Jingle",
+	.description = "Jingle Channel Driver",
+	.requester = jingle_request,
+	.send_text = jingle_sendtext,
+	.send_digit_begin = jingle_digit_begin,
+	.send_digit_end = jingle_digit_end,
+	.bridge = ast_rtp_instance_bridge,
+	.call = jingle_call,
+	.hangup = jingle_hangup,
+	.answer = jingle_answer,
+	.read = jingle_read,
+	.write = jingle_write,
+	.exception = jingle_read,
+	.indicate = jingle_indicate,
+	.fixup = jingle_fixup,
+	.send_html = jingle_sendhtml,
+	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
+};
+
+static struct sockaddr_in bindaddr = { 0, };	/*!< The address we bind to */
+
+static struct ast_sched_context *sched;	/*!< The scheduling context */
+static struct io_context *io;	/*!< The IO context */
+static struct in_addr __ourip;
+
+static struct ast_cli_entry jingle_cli[] = {
+	AST_CLI_DEFINE(jingle_do_reload, "Reload Jingle configuration"),
+	AST_CLI_DEFINE(jingle_show_channels, "Show Jingle channels"),
+};
+
+
+static char externip[16];
+
+static struct jingle_container jingle_list;
+
+static void jingle_member_destroy(struct jingle *obj)
+{
+	obj->cap = ast_format_cap_destroy(obj->cap);
+	if (obj->connection) {
+		ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
+	}
+	if (obj->buddy) {
+		ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
+	}
+	ast_free(obj);
+}
+
+/* XXX This could be a source of reference leaks given that the CONTAINER_FIND
+ * macros bump the refcount while the traversal does not. */
+static struct jingle *find_jingle(char *name, char *connection)
+{
+	struct jingle *jingle = NULL;
+
+	jingle = ASTOBJ_CONTAINER_FIND(&jingle_list, name);
+	if (!jingle && strchr(name, '@'))
+		jingle = ASTOBJ_CONTAINER_FIND_FULL(&jingle_list, name, user,,, strcasecmp);
+
+	if (!jingle) {				
+		/* guest call */
+		ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			if (!strcasecmp(iterator->name, "guest")) {
+				jingle = iterator;
+			}
+			ASTOBJ_UNLOCK(iterator);
+
+			if (jingle)
+				break;
+		});
+
+	}
+	return jingle;
+}
+
+
+static void add_codec_to_answer(const struct jingle_pvt *p, struct ast_format *codec, iks *dcodecs)
+{
+	const char *format = ast_getformatname(codec);
+
+	if (!strcasecmp("ulaw", format)) {
+		iks *payload_eg711u, *payload_pcmu;
+		payload_pcmu = iks_new("payload-type");
+		iks_insert_attrib(payload_pcmu, "id", "0");
+		iks_insert_attrib(payload_pcmu, "name", "PCMU");
+		payload_eg711u = iks_new("payload-type");
+		iks_insert_attrib(payload_eg711u, "id", "100");
+		iks_insert_attrib(payload_eg711u, "name", "EG711U");
+		iks_insert_node(dcodecs, payload_pcmu);
+		iks_insert_node(dcodecs, payload_eg711u);
+	}
+	if (!strcasecmp("alaw", format)) {
+		iks *payload_eg711a;
+		iks *payload_pcma = iks_new("payload-type");
+		iks_insert_attrib(payload_pcma, "id", "8");
+		iks_insert_attrib(payload_pcma, "name", "PCMA");
+		payload_eg711a = iks_new("payload-type");
+		iks_insert_attrib(payload_eg711a, "id", "101");
+		iks_insert_attrib(payload_eg711a, "name", "EG711A");
+		iks_insert_node(dcodecs, payload_pcma);
+		iks_insert_node(dcodecs, payload_eg711a);
+	}
+	if (!strcasecmp("ilbc", format)) {
+		iks *payload_ilbc = iks_new("payload-type");
+		iks_insert_attrib(payload_ilbc, "id", "97");
+		iks_insert_attrib(payload_ilbc, "name", "iLBC");
+		iks_insert_node(dcodecs, payload_ilbc);
+	}
+	if (!strcasecmp("g723", format)) {
+		iks *payload_g723 = iks_new("payload-type");
+		iks_insert_attrib(payload_g723, "id", "4");
+		iks_insert_attrib(payload_g723, "name", "G723");
+		iks_insert_node(dcodecs, payload_g723);
+	}
+}
+
+static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p)
+{
+	struct jingle_pvt *tmp = client->p;
+	struct aji_client *c = client->connection;
+	iks *iq, *jingle, *dcodecs, *payload_red, *payload_audio, *payload_cn;
+	int x;
+	struct ast_format pref_codec;
+	struct ast_format_cap *alreadysent = ast_format_cap_alloc_nolock();
+
+	if (p->initiator || !alreadysent)
+		return 1;
+
+	iq = iks_new("iq");
+	jingle = iks_new(JINGLE_NODE);
+	dcodecs = iks_new("description");
+	if (iq && jingle && dcodecs) {
+		iks_insert_attrib(dcodecs, "xmlns", JINGLE_AUDIO_RTP_NS);
+
+		for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+			if (!(ast_codec_pref_index(&client->prefs, x, &pref_codec)))
+				break;
+			if (!(ast_format_cap_iscompatible(client->cap, &pref_codec)))
+				continue;
+			if ((ast_format_cap_iscompatible(alreadysent, &pref_codec)))
+				continue;
+			add_codec_to_answer(p, &pref_codec, dcodecs);
+			ast_format_cap_add(alreadysent, &pref_codec);
+		}
+		payload_red = iks_new("payload-type");
+		iks_insert_attrib(payload_red, "id", "117");
+		iks_insert_attrib(payload_red, "name", "red");
+		payload_audio = iks_new("payload-type");
+		iks_insert_attrib(payload_audio, "id", "106");
+		iks_insert_attrib(payload_audio, "name", "audio/telephone-event");
+		payload_cn = iks_new("payload-type");
+		iks_insert_attrib(payload_cn, "id", "13");
+		iks_insert_attrib(payload_cn, "name", "CN");
+
+
+		iks_insert_attrib(iq, "type", "set");
+		iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user);
+		iks_insert_attrib(iq, "id", client->connection->mid);
+		ast_aji_increment_mid(client->connection->mid);
+
+		iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+		iks_insert_attrib(jingle, "action", JINGLE_ACCEPT);
+		iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
+		iks_insert_attrib(jingle, JINGLE_SID, tmp->sid);
+		iks_insert_node(iq, jingle);
+		iks_insert_node(jingle, dcodecs);
+		iks_insert_node(dcodecs, payload_red);
+		iks_insert_node(dcodecs, payload_audio);
+		iks_insert_node(dcodecs, payload_cn);
+
+		ast_aji_send(c, iq);
+
+		iks_delete(payload_red);
+		iks_delete(payload_audio);
+		iks_delete(payload_cn);
+		iks_delete(dcodecs);
+		iks_delete(jingle);
+		iks_delete(iq);
+	}
+	alreadysent = ast_format_cap_destroy(alreadysent);
+	return 1;
+}
+
+static int jingle_ringing_ack(void *data, ikspak *pak)
+{
+	struct jingle_pvt *p = data;
+
+	if (p->ringrule)
+		iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
+	p->ringrule = NULL;
+	if (p->owner)
+		ast_queue_control(p->owner, AST_CONTROL_RINGING);
+	return IKS_FILTER_EAT;
+}
+
+static int jingle_answer(struct ast_channel *ast)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+	struct jingle *client = p->parent;
+	int res = 0;
+
+	ast_debug(1, "Answer!\n");
+	ast_mutex_lock(&p->lock);
+	jingle_accept_call(client, p);
+	ast_mutex_unlock(&p->lock);
+	return res;
+}
+
+static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(chan);
+	enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+	if (!p)
+		return res;
+
+	ast_mutex_lock(&p->lock);
+	if (p->rtp) {
+		ao2_ref(p->rtp, +1);
+		*instance = p->rtp;
+		res = AST_RTP_GLUE_RESULT_LOCAL;
+	}
+	ast_mutex_unlock(&p->lock);
+
+	return res;
+}
+
+static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(chan);
+	ast_mutex_lock(&p->lock);
+	ast_format_cap_copy(result, p->peercap);
+	ast_mutex_unlock(&p->lock);
+}
+
+static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
+{
+	struct jingle_pvt *p;
+
+	p = ast_channel_tech_pvt(chan);
+	if (!p)
+		return -1;
+	ast_mutex_lock(&p->lock);
+
+/*	if (rtp)
+		ast_rtp_get_peer(rtp, &p->redirip);
+	else
+		memset(&p->redirip, 0, sizeof(p->redirip));
+	p->redircodecs = codecs; */
+
+	/* Reset lastrtprx timer */
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static struct ast_rtp_glue jingle_rtp_glue = {
+	.type = "Jingle",
+	.get_rtp_info = jingle_get_rtp_peer,
+	.get_codec = jingle_get_codec,
+	.update_peer = jingle_set_rtp_peer,
+};
+
+static int jingle_response(struct jingle *client, ikspak *pak, const char *reasonstr, const char *reasonstr2)
+{
+	iks *response = NULL, *error = NULL, *reason = NULL;
+	int res = -1;
+
+	response = iks_new("iq");
+	if (response) {
+		iks_insert_attrib(response, "type", "result");
+		iks_insert_attrib(response, "from", client->connection->jid->full);
+		iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
+		iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
+		if (reasonstr) {
+			error = iks_new("error");
+			if (error) {
+				iks_insert_attrib(error, "type", "cancel");
+				reason = iks_new(reasonstr);
+				if (reason)
+					iks_insert_node(error, reason);
+				iks_insert_node(response, error);
+			}
+		}
+		ast_aji_send(client->connection, response);
+		res = 0;
+	}
+	
+	iks_delete(reason);
+	iks_delete(error);
+	iks_delete(response);
+
+	return res;
+}
+
+static int jingle_is_answered(struct jingle *client, ikspak *pak)
+{
+	struct jingle_pvt *tmp;
+
+	ast_debug(1, "The client is %s\n", client->name);
+	/* Make sure our new call doesn't exist yet */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
+			break;
+	}
+
+	if (tmp) {
+		if (tmp->owner)
+			ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
+	} else
+		ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
+	jingle_response(client, pak, NULL, NULL);
+	return 1;
+}
+
+static int jingle_handle_dtmf(struct jingle *client, ikspak *pak)
+{
+	struct jingle_pvt *tmp;
+	iks *dtmfnode = NULL, *dtmfchild = NULL;
+	char *dtmf;
+	/* Make sure our new call doesn't exist yet */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
+			break;
+	}
+
+	if (tmp) {
+		if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
+			jingle_response(client,pak,
+					"feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
+					"unsupported-dtmf-method xmlns='http://www.xmpp.org/extensions/xep-0181.html#ns-errors'");
+			return -1;
+		}
+		if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
+			if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
+				if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
+					struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
+				} else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
+					struct ast_frame f = {AST_FRAME_DTMF_END, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
+				} else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
+					struct ast_frame f = {AST_FRAME_DTMF, };
+					f.subclass.integer = dtmf[0];
+					ast_queue_frame(tmp->owner, &f);
+					ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
+				}
+			}
+		} else if ((dtmfnode = iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "session-info"))) {
+			if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
+				if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
+					if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
+						struct ast_frame f = {AST_FRAME_DTMF_END, };
+						f.subclass.integer = dtmf[0];
+						ast_queue_frame(tmp->owner, &f);
+						ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
+					} else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
+						struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
+						f.subclass.integer = dtmf[0];
+						ast_queue_frame(tmp->owner, &f);
+						ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
+					}
+				}
+			}
+		}
+		jingle_response(client, pak, NULL, NULL);
+		return 1;
+	} else
+		ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
+
+	jingle_response(client, pak, NULL, NULL);
+	return 1;
+}
+
+
+static int jingle_hangup_farend(struct jingle *client, ikspak *pak)
+{
+	struct jingle_pvt *tmp;
+
+	ast_debug(1, "The client is %s\n", client->name);
+	/* Make sure our new call doesn't exist yet */
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
+			break;
+	}
+
+	if (tmp) {
+		tmp->alreadygone = 1;
+		if (tmp->owner)
+			ast_queue_hangup(tmp->owner);
+	} else
+		ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
+	jingle_response(client, pak, NULL, NULL);
+	return 1;
+}
+
+static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, char *sid, char *from)
+{
+	struct jingle_candidate *tmp;
+	struct aji_client *c = client->connection;
+	struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
+	struct sockaddr_in sin = { 0, };
+	struct ast_sockaddr sin_tmp;
+	struct ast_sockaddr us_tmp;
+	struct ast_sockaddr bindaddr_tmp;
+	struct in_addr us;
+	struct in_addr externaddr;
+	iks *iq, *jingle, *content, *transport, *candidate;
+	char component[16], foundation[16], generation[16], network[16], pass[16], port[7], priority[16], user[16];
+
+
+	iq = iks_new("iq");
+	jingle = iks_new(JINGLE_NODE);
+	content = iks_new("content");
+	transport = iks_new("transport");
+	candidate = iks_new("candidate");
+	if (!iq || !jingle || !content || !transport || !candidate) {
+		ast_log(LOG_ERROR, "Memory allocation error\n");
+		goto safeout;
+	}
+	ours1 = ast_calloc(1, sizeof(*ours1));
+	ours2 = ast_calloc(1, sizeof(*ours2));
+	if (!ours1 || !ours2)
+		goto safeout;
+
+	iks_insert_node(iq, jingle);
+	iks_insert_node(jingle, content);
+	iks_insert_node(content, transport);
+	iks_insert_node(transport, candidate);
+
+	for (; p; p = p->next) {
+		if (!strcasecmp(p->sid, sid))
+			break;
+	}
+
+	if (!p) {
+		ast_log(LOG_NOTICE, "No matching jingle session - SID %s!\n", sid);
+		goto safeout;
+	}
+
+	ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
+	ast_sockaddr_to_sin(&sin_tmp, &sin);
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	ast_find_ourip(&us_tmp, &bindaddr_tmp, AF_INET);
+	us.s_addr = htonl(ast_sockaddr_ipv4(&us_tmp));
+
+	/* Setup our first jingle candidate */
+	ours1->component = 1;
+	ours1->foundation = (unsigned int)bindaddr.sin_addr.s_addr | AJI_CONNECT_HOST | AJI_PROTOCOL_UDP;
+	ours1->generation = 0;
+	ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
+	ours1->network = 0;
+	ours1->port = ntohs(sin.sin_port);
+	ours1->priority = 1678246398;
+	ours1->protocol = AJI_PROTOCOL_UDP;
+	snprintf(pass, sizeof(pass), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
+	ast_copy_string(ours1->password, pass, sizeof(ours1->password));
+	ours1->type = AJI_CONNECT_HOST;
+	snprintf(user, sizeof(user), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
+	ast_copy_string(ours1->ufrag, user, sizeof(ours1->ufrag));
+	p->ourcandidates = ours1;
+
+	if (!ast_strlen_zero(externip)) {
+		/* XXX We should really stun for this one not just go with externip XXX */
+		if (inet_aton(externip, &externaddr))
+			ast_log(LOG_WARNING, "Invalid extern IP : %s\n", externip);
+
+		ours2->component = 1;
+		ours2->foundation = (unsigned int)externaddr.s_addr | AJI_CONNECT_PRFLX | AJI_PROTOCOL_UDP;
+		ours2->generation = 0;
+		ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
+		ours2->network = 0;
+		ours2->port = ntohs(sin.sin_port);
+		ours2->priority = 1678246397;
+		ours2->protocol = AJI_PROTOCOL_UDP;
+		snprintf(pass, sizeof(pass), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
+		ast_copy_string(ours2->password, pass, sizeof(ours2->password));
+		ours2->type = AJI_CONNECT_PRFLX;
+
+		snprintf(user, sizeof(user), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
+		ast_copy_string(ours2->ufrag, user, sizeof(ours2->ufrag));
+		ours1->next = ours2;
+		ours2 = NULL;
+	}
+	ours1 = NULL;
+
+	for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
+		snprintf(component, sizeof(component), "%u", tmp->component);
+		snprintf(foundation, sizeof(foundation), "%u", tmp->foundation);
+		snprintf(generation, sizeof(generation), "%u", tmp->generation);
+		snprintf(network, sizeof(network), "%u", tmp->network);
+		snprintf(port, sizeof(port), "%u", tmp->port);
+		snprintf(priority, sizeof(priority), "%u", tmp->priority);
+
+		iks_insert_attrib(iq, "from", c->jid->full);
+		iks_insert_attrib(iq, "to", from);
+		iks_insert_attrib(iq, "type", "set");
+		iks_insert_attrib(iq, "id", c->mid);
+		ast_aji_increment_mid(c->mid);
+		iks_insert_attrib(jingle, "action", JINGLE_NEGOTIATE);
+		iks_insert_attrib(jingle, JINGLE_SID, sid);
+		iks_insert_attrib(jingle, "initiator", (p->initiator) ? c->jid->full : from);
+		iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+		iks_insert_attrib(content, "creator", p->initiator ? "initiator" : "responder");
+		iks_insert_attrib(content, "name", "asterisk-audio-content");
+		iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
+		iks_insert_attrib(candidate, "component", component);
+		iks_insert_attrib(candidate, "foundation", foundation);
+		iks_insert_attrib(candidate, "generation", generation);
+		iks_insert_attrib(candidate, "ip", tmp->ip);
+		iks_insert_attrib(candidate, "network", network);
+		iks_insert_attrib(candidate, "port", port);
+		iks_insert_attrib(candidate, "priority", priority);
+		switch (tmp->protocol) {
+		case AJI_PROTOCOL_UDP:
+			iks_insert_attrib(candidate, "protocol", "udp");
+			break;
+		case AJI_PROTOCOL_SSLTCP:
+			iks_insert_attrib(candidate, "protocol", "ssltcp");
+			break;
+		}
+		iks_insert_attrib(candidate, "pwd", tmp->password);
+		switch (tmp->type) {
+		case AJI_CONNECT_HOST:
+			iks_insert_attrib(candidate, "type", "host");
+			break;
+		case AJI_CONNECT_PRFLX:
+			iks_insert_attrib(candidate, "type", "prflx");
+			break;
+		case AJI_CONNECT_RELAY:
+			iks_insert_attrib(candidate, "type", "relay");
+			break;
+		case AJI_CONNECT_SRFLX:
+			iks_insert_attrib(candidate, "type", "srflx");
+			break;
+		}
+		iks_insert_attrib(candidate, "ufrag", tmp->ufrag);
+
+		ast_aji_send(c, iq);
+	}
+	p->laststun = 0;
+
+safeout:
+	if (ours1)
+		ast_free(ours1);
+	if (ours2)
+		ast_free(ours2);
+	iks_delete(iq);
+	iks_delete(jingle);
+	iks_delete(content);
+	iks_delete(transport);
+	iks_delete(candidate);
+
+	return 1;
+}
+
+static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid)
+{
+	struct jingle_pvt *tmp = NULL;
+	struct aji_resource *resources = NULL;
+	struct aji_buddy *buddy = NULL;
+	char idroster[200];
+	struct ast_sockaddr bindaddr_tmp;
+
+	ast_debug(1, "The client is %s for alloc\n", client->name);
+	if (!sid && !strchr(from, '/')) {	/* I started call! */
+		if (!strcasecmp(client->name, "guest")) {
+			buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, from);
+			if (buddy) {
+				resources = buddy->resources;
+			}
+		} else if (client->buddy)
+			resources = client->buddy->resources;
+		while (resources) {
+			if (resources->cap->jingle) {
+				break;
+			}
+			resources = resources->next;
+		}
+		if (resources)
+			snprintf(idroster, sizeof(idroster), "%s/%s", from, resources->resource);
+		else {
+			ast_log(LOG_ERROR, "no jingle capable clients to talk to.\n");
+			if (buddy) {
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			}
+			return NULL;
+		}
+		if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+		}
+	}
+	if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+		return NULL;
+	}
+
+	tmp->cap = ast_format_cap_alloc_nolock();
+	tmp->jointcap = ast_format_cap_alloc_nolock();
+	tmp->peercap = ast_format_cap_alloc_nolock();
+	if (!tmp->cap || !tmp->jointcap || !tmp->peercap) {
+		tmp->cap = ast_format_cap_destroy(tmp->cap);
+		tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
+		tmp->peercap = ast_format_cap_destroy(tmp->peercap);
+		ast_free(tmp);
+		return NULL;
+	}
+	memcpy(&tmp->prefs, &client->prefs, sizeof(tmp->prefs));
+
+	if (sid) {
+		ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
+		ast_copy_string(tmp->them, from, sizeof(tmp->them));
+	} else {
+		snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
+		ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
+		tmp->initiator = 1;
+	}
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
+	tmp->parent = client;
+	if (!tmp->rtp) {
+		ast_log(LOG_WARNING, "Out of RTP sessions?\n");
+		ast_free(tmp);
+		return NULL;
+	}
+	ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
+	ast_mutex_init(&tmp->lock);
+	ast_mutex_lock(&jinglelock);
+	tmp->next = client->p;
+	client->p = tmp;
+	ast_mutex_unlock(&jinglelock);
+	return tmp;
+}
+
+/*! \brief Start new jingle channel */
+static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const char *linkedid)
+{
+	struct ast_channel *tmp;
+	struct ast_format_cap *what;  /* SHALLOW COPY DO NOT DESTROY */
+	struct ast_format tmpfmt;
+	const char *str;
+
+	if (title)
+		str = title;
+	else
+		str = i->them;
+	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", "", "", linkedid, 0, "Jingle/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff));
+	if (!tmp) {
+		ast_log(LOG_WARNING, "Unable to allocate Jingle channel structure!\n");
+		return NULL;
+	}
+	ast_channel_tech_set(tmp, &jingle_tech);
+
+	/* Select our native format based on codec preference until we receive
+	   something from another device to the contrary. */
+	if (!ast_format_cap_is_empty(i->jointcap))
+		what = i->jointcap;
+	else if (!(ast_format_cap_is_empty(i->cap)))
+		what = i->cap;
+	else
+		what = global_capability;
+
+	/* Set Frame packetization */
+	if (i->rtp)
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
+
+	ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
+	ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
+
+	ast_format_cap_iter_start(i->jointcap);
+	while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
+		if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
+			ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
+		}
+	}
+	ast_format_cap_iter_end(i->jointcap);
+
+	if (i->rtp) {
+		ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
+		ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
+	}
+	if (i->vrtp) {
+		ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
+		ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
+	}
+	if (state == AST_STATE_RING)
+		ast_channel_rings_set(tmp, 1);
+	ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
+
+
+	ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+	ast_channel_tech_pvt_set(tmp, i);
+
+	ast_channel_callgroup_set(tmp, client->callgroup);
+	ast_channel_pickupgroup_set(tmp, client->pickupgroup);
+	ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
+	ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
+	if (!ast_strlen_zero(client->accountcode))
+		ast_channel_accountcode_set(tmp, client->accountcode);
+	if (client->amaflags)
+		ast_channel_amaflags_set(tmp, client->amaflags);
+	if (!ast_strlen_zero(client->language))
+		ast_channel_language_set(tmp, client->language);
+	if (!ast_strlen_zero(client->musicclass))
+		ast_channel_musicclass_set(tmp, client->musicclass);
+	i->owner = tmp;
+	ast_channel_context_set(tmp, client->context);
+	ast_channel_exten_set(tmp, i->exten);
+	/* Don't use ast_set_callerid() here because it will
+	 * generate an unnecessary NewCallerID event  */
+	if (!ast_strlen_zero(i->cid_num)) {
+		ast_channel_caller(tmp)->ani.number.valid = 1;
+		ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
+	}
+	if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
+		ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
+	}
+	ast_channel_priority_set(tmp, 1);
+	if (i->rtp)
+		ast_jb_configure(tmp, &global_jbconf);
+	if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
+		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+		ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
+		ast_hangup(tmp);
+		tmp = NULL;
+	}
+
+	return tmp;
+}
+
+static int jingle_action(struct jingle *client, struct jingle_pvt *p, const char *action)
+{
+	iks *iq, *jingle = NULL;
+	int res = -1;
+
+	iq = iks_new("iq");
+	jingle = iks_new("jingle");
+	
+	if (iq) {
+		iks_insert_attrib(iq, "type", "set");
+		iks_insert_attrib(iq, "from", client->connection->jid->full);
+		iks_insert_attrib(iq, "to", p->them);
+		iks_insert_attrib(iq, "id", client->connection->mid);
+		ast_aji_increment_mid(client->connection->mid);
+		if (jingle) {
+			iks_insert_attrib(jingle, "action", action);
+			iks_insert_attrib(jingle, JINGLE_SID, p->sid);
+			iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
+			iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+
+			iks_insert_node(iq, jingle);
+
+			ast_aji_send(client->connection, iq);
+			res = 0;
+		}
+	}
+	
+	iks_delete(jingle);
+	iks_delete(iq);
+	
+	return res;
+}
+
+static void jingle_free_candidates(struct jingle_candidate *candidate)
+{
+	struct jingle_candidate *last;
+	while (candidate) {
+		last = candidate;
+		candidate = candidate->next;
+		ast_free(last);
+	}
+}
+
+static void jingle_free_pvt(struct jingle *client, struct jingle_pvt *p)
+{
+	struct jingle_pvt *cur, *prev = NULL;
+	cur = client->p;
+	while (cur) {
+		if (cur == p) {
+			if (prev)
+				prev->next = p->next;
+			else
+				client->p = p->next;
+			break;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+	if (p->ringrule)
+		iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
+	if (p->owner)
+		ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
+	if (p->rtp)
+		ast_rtp_instance_destroy(p->rtp);
+	if (p->vrtp)
+		ast_rtp_instance_destroy(p->vrtp);
+	jingle_free_candidates(p->theircandidates);
+	p->cap = ast_format_cap_destroy(p->cap);
+	p->jointcap = ast_format_cap_destroy(p->jointcap);
+	p->peercap = ast_format_cap_destroy(p->peercap);
+
+	ast_free(p);
+}
+
+
+static int jingle_newcall(struct jingle *client, ikspak *pak)
+{
+	struct jingle_pvt *p, *tmp = client->p;
+	struct ast_channel *chan;
+	int res;
+	iks *codec, *content, *description;
+	char *from = NULL;
+
+	/* Make sure our new call doesn't exist yet */
+	from = iks_find_attrib(pak->x,"to");
+	if(!from)
+		from = client->connection->jid->full;
+
+	while (tmp) {
+		if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
+			ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
+			jingle_response(client, pak, "out-of-order", NULL);
+			return -1;
+		}
+		tmp = tmp->next;
+	}
+
+	if (!strcasecmp(client->name, "guest")){
+		/* the guest account is not tied to any configured XMPP client,
+		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
+		client->connection = ast_aji_get_client(from);
+		if (!client->connection) {
+			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
+			return -1;
+		}
+	}
+
+	p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID));
+	if (!p) {
+		ast_log(LOG_WARNING, "Unable to allocate jingle structure!\n");
+		return -1;
+	}
+	chan = jingle_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
+	if (!chan) {
+		jingle_free_pvt(client, p);
+		return -1;
+	}
+	ast_mutex_lock(&p->lock);
+	ast_copy_string(p->them, pak->from->full, sizeof(p->them));
+	if (iks_find_attrib(pak->query, JINGLE_SID)) {
+		ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID),
+				sizeof(p->sid));
+	}
+	
+	/* content points to the first <content/> tag */	
+	content = iks_child(iks_child(pak->x));
+	while (content) {
+		description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_AUDIO_RTP_NS);
+		if (description) {
+			/* audio content found */
+			codec = iks_child(iks_child(content));
+		        ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name));
+
+			while (codec) {
+				ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
+				ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+				codec = iks_next(codec);
+			}
+		}
+		
+		description = NULL;
+		codec = NULL;
+
+		description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_VIDEO_RTP_NS);
+		if (description) {
+			/* video content found */
+			codec = iks_child(iks_child(content));
+		        ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name));
+
+			while (codec) {
+				ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
+				ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+				codec = iks_next(codec);
+			}
+		}
+		
+		content = iks_next(content);
+	}
+
+	ast_mutex_unlock(&p->lock);
+	ast_setstate(chan, AST_STATE_RING);
+	res = ast_pbx_start(chan);
+	
+	switch (res) {
+	case AST_PBX_FAILED:
+		ast_log(LOG_WARNING, "Failed to start PBX :(\n");
+		jingle_response(client, pak, "service-unavailable", NULL);
+		break;
+	case AST_PBX_CALL_LIMIT:
+		ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
+		jingle_response(client, pak, "service-unavailable", NULL);
+		break;
+	case AST_PBX_SUCCESS:
+		jingle_response(client, pak, NULL, NULL);
+		jingle_create_candidates(client, p,
+					 iks_find_attrib(pak->query, JINGLE_SID),
+					 iks_find_attrib(pak->x, "from"));
+		/* nothing to do */
+		break;
+	}
+
+	return 1;
+}
+
+static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p)
+{
+	struct jingle_candidate *tmp;
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct sockaddr_in sin;
+	struct ast_sockaddr sin_tmp;
+
+	if (time(NULL) == p->laststun)
+		return 0;
+
+	tmp = p->theircandidates;
+	p->laststun = time(NULL);
+	while (tmp) {
+		char username[256];
+		hp = ast_gethostbyname(tmp->ip, &ahp);
+		sin.sin_family = AF_INET;
+		memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+		sin.sin_port = htons(tmp->port);
+		snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag);
+
+		ast_sockaddr_from_sin(&sin_tmp, &sin);
+		ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
+		tmp = tmp->next;
+	}
+	return 1;
+}
+
+static int jingle_add_candidate(struct jingle *client, ikspak *pak)
+{
+	struct jingle_pvt *p = NULL, *tmp = NULL;
+	struct aji_client *c = client->connection;
+	struct jingle_candidate *newcandidate = NULL;
+	iks *traversenodes = NULL, *receipt = NULL;
+
+	for (tmp = client->p; tmp; tmp = tmp->next) {
+		if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
+			p = tmp;
+			break;
+		}
+	}
+
+	if (!p)
+		return -1;
+
+	traversenodes = pak->query;
+	while(traversenodes) {
+		if(!strcasecmp(iks_name(traversenodes), "jingle")) {
+			traversenodes = iks_child(traversenodes);
+			continue;
+		}
+		if(!strcasecmp(iks_name(traversenodes), "content")) {
+			traversenodes = iks_child(traversenodes);
+			continue;
+		}
+		if(!strcasecmp(iks_name(traversenodes), "transport")) {
+			traversenodes = iks_child(traversenodes);
+			continue;
+		}
+
+		if(!strcasecmp(iks_name(traversenodes), "candidate")) {
+			newcandidate = ast_calloc(1, sizeof(*newcandidate));
+			if (!newcandidate)
+				return 0;
+			ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "ip"), sizeof(newcandidate->ip));
+			newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
+			ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "pwd"), sizeof(newcandidate->password));
+			if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
+				newcandidate->protocol = AJI_PROTOCOL_UDP;
+			else if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
+				newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
+			
+			if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "host"))
+				newcandidate->type = AJI_CONNECT_HOST;
+			else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "prflx"))
+				newcandidate->type = AJI_CONNECT_PRFLX;
+			else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
+				newcandidate->type = AJI_CONNECT_RELAY;
+			else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "srflx"))
+				newcandidate->type = AJI_CONNECT_SRFLX;
+
+			newcandidate->network = atoi(iks_find_attrib(traversenodes, "network"));
+			newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
+			newcandidate->next = NULL;
+		
+			newcandidate->next = p->theircandidates;
+			p->theircandidates = newcandidate;
+			p->laststun = 0;
+			jingle_update_stun(p->parent, p);
+			newcandidate = NULL;
+		}
+		traversenodes = iks_next(traversenodes);
+	}
+	
+	receipt = iks_new("iq");
+	iks_insert_attrib(receipt, "type", "result");
+	iks_insert_attrib(receipt, "from", c->jid->full);
+	iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
+	iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
+	ast_aji_send(c, receipt);
+
+	iks_delete(receipt);
+
+	return 1;
+}
+
+static struct ast_frame *jingle_rtp_read(struct ast_channel *ast, struct jingle_pvt *p)
+{
+	struct ast_frame *f;
+
+	if (!p->rtp)
+		return &ast_null_frame;
+	f = ast_rtp_instance_read(p->rtp, 0);
+	jingle_update_stun(p->parent, p);
+	if (p->owner) {
+		/* We already hold the channel lock */
+		if (f->frametype == AST_FRAME_VOICE) {
+			if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) {
+				ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+				ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
+				ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
+				ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
+				ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
+			}
+/*			if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
+				f = ast_dsp_process(p->owner, p->vad, f);
+				if (f && (f->frametype == AST_FRAME_DTMF))
+					ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.codec);
+		        } */
+		}
+	}
+	return f;
+}
+
+static struct ast_frame *jingle_read(struct ast_channel *ast)
+{
+	struct ast_frame *fr;
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+
+	ast_mutex_lock(&p->lock);
+	fr = jingle_rtp_read(ast, p);
+	ast_mutex_unlock(&p->lock);
+	return fr;
+}
+
+/*! \brief Send frame to media channel (rtp) */
+static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+	int res = 0;
+	char buf[256];
+
+	switch (frame->frametype) {
+	case AST_FRAME_VOICE:
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+			ast_log(LOG_WARNING,
+					"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
+					ast_getformatname(&frame->subclass.format),
+					ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+					ast_getformatname(ast_channel_readformat(ast)),
+					ast_getformatname(ast_channel_writeformat(ast)));
+			return 0;
+		}
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			if (p->rtp) {
+				res = ast_rtp_instance_write(p->rtp, frame);
+			}
+			ast_mutex_unlock(&p->lock);
+		}
+		break;
+	case AST_FRAME_VIDEO:
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			if (p->vrtp) {
+				res = ast_rtp_instance_write(p->vrtp, frame);
+			}
+			ast_mutex_unlock(&p->lock);
+		}
+		break;
+	case AST_FRAME_IMAGE:
+		return 0;
+		break;
+	default:
+		ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
+				frame->frametype);
+		return 0;
+	}
+
+	return res;
+}
+
+static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(newchan);
+	ast_mutex_lock(&p->lock);
+
+	if ((p->owner != oldchan)) {
+		ast_mutex_unlock(&p->lock);
+		return -1;
+	}
+	if (p->owner == oldchan)
+		p->owner = newchan;
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+	int res = 0;
+
+	switch (condition) {
+	case AST_CONTROL_HOLD:
+		ast_moh_start(ast, data, NULL);
+		break;
+	case AST_CONTROL_UNHOLD:
+		ast_moh_stop(ast);
+		break;
+	default:
+		ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
+		/* fallthrough */
+	case AST_CONTROL_PVT_CAUSE_CODE:
+		res = -1;
+	}
+
+	return res;
+}
+
+static int jingle_sendtext(struct ast_channel *chan, const char *text)
+{
+	int res = 0;
+	struct aji_client *client = NULL;
+	struct jingle_pvt *p = ast_channel_tech_pvt(chan);
+
+
+	if (!p->parent) {
+		ast_log(LOG_ERROR, "Parent channel not found\n");
+		return -1;
+	}
+	if (!p->parent->connection) {
+		ast_log(LOG_ERROR, "XMPP client not found\n");
+		return -1;
+	}
+	client = p->parent->connection;
+	res = ast_aji_send_chat(client, p->them, text);
+	return res;
+}
+
+static int jingle_digit(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+	struct jingle *client = p->parent;
+	iks *iq, *jingle, *dtmf;
+	char buffer[2] = {digit, '\0'};
+	iq = iks_new("iq");
+	jingle = iks_new("jingle");
+	dtmf = iks_new("dtmf");
+	if(!iq || !jingle || !dtmf) {
+		iks_delete(iq);
+		iks_delete(jingle);
+		iks_delete(dtmf);
+		ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
+		return -1;
+	}
+
+	iks_insert_attrib(iq, "type", "set");
+	iks_insert_attrib(iq, "to", p->them);
+	iks_insert_attrib(iq, "from", client->connection->jid->full);
+	iks_insert_attrib(iq, "id", client->connection->mid);
+	ast_aji_increment_mid(client->connection->mid);
+	iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+	iks_insert_attrib(jingle, "action", "session-info");
+	iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
+	iks_insert_attrib(jingle, "sid", p->sid);
+	iks_insert_attrib(dtmf, "xmlns", JINGLE_DTMF_NS);
+	iks_insert_attrib(dtmf, "code", buffer);
+	iks_insert_node(iq, jingle);
+	iks_insert_node(jingle, dtmf);
+
+	ast_mutex_lock(&p->lock);
+	if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
+		iks_insert_attrib(dtmf, "action", "button-down");
+	} else if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_END || duration != 0) {
+		iks_insert_attrib(dtmf, "action", "button-up");
+	}
+	ast_aji_send(client->connection, iq);
+
+	iks_delete(iq);
+	iks_delete(jingle);
+	iks_delete(dtmf);
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+
+static int jingle_digit_begin(struct ast_channel *chan, char digit)
+{
+	return jingle_digit(chan, digit, 0);
+}
+
+static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	return jingle_digit(ast, digit, duration);
+}
+
+static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
+{
+	ast_log(LOG_NOTICE, "XXX Implement jingle sendhtml XXX\n");
+
+	return -1;
+}
+static int jingle_transmit_invite(struct jingle_pvt *p)
+{
+	struct jingle *aux = NULL;
+	struct aji_client *client = NULL;
+	iks *iq, *jingle, *content, *description, *transport;
+	iks *payload_eg711u, *payload_pcmu;
+
+	aux = p->parent;
+	client = aux->connection;
+	iq = iks_new("iq");
+	jingle = iks_new(JINGLE_NODE);
+	content = iks_new("content");
+	description = iks_new("description");
+	transport = iks_new("transport");
+	payload_pcmu = iks_new("payload-type");
+	payload_eg711u = iks_new("payload-type");
+
+	ast_copy_string(p->audio_content_name, "asterisk-audio-content", sizeof(p->audio_content_name));
+
+	iks_insert_attrib(iq, "type", "set");
+	iks_insert_attrib(iq, "to", p->them);
+	iks_insert_attrib(iq, "from", client->jid->full);
+	iks_insert_attrib(iq, "id", client->mid);
+	ast_aji_increment_mid(client->mid);
+	iks_insert_attrib(jingle, "action", JINGLE_INITIATE);
+	iks_insert_attrib(jingle, JINGLE_SID, p->sid);
+	iks_insert_attrib(jingle, "initiator", client->jid->full);
+	iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
+
+	/* For now, we only send one audio based content */
+	iks_insert_attrib(content, "creator", "initiator");
+	iks_insert_attrib(content, "name", p->audio_content_name);
+	iks_insert_attrib(content, "profile", "RTP/AVP");
+	iks_insert_attrib(description, "xmlns", JINGLE_AUDIO_RTP_NS);
+	iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
+	iks_insert_attrib(payload_pcmu, "id", "0");
+	iks_insert_attrib(payload_pcmu, "name", "PCMU");
+	iks_insert_attrib(payload_eg711u, "id", "100");
+	iks_insert_attrib(payload_eg711u, "name", "EG711U");
+	iks_insert_node(description, payload_pcmu);
+	iks_insert_node(description, payload_eg711u);
+	iks_insert_node(content, description);
+	iks_insert_node(content, transport);
+	iks_insert_node(jingle, content);
+	iks_insert_node(iq, jingle);
+
+	ast_aji_send(client, iq);
+
+	iks_delete(iq);
+	iks_delete(jingle);
+	iks_delete(content);
+	iks_delete(description);
+	iks_delete(transport);
+	iks_delete(payload_eg711u);
+	iks_delete(payload_pcmu);
+	return 0;
+}
+
+/* Not in use right now.
+static int jingle_auto_congest(void *nothing)
+{
+	struct jingle_pvt *p = nothing;
+
+	ast_mutex_lock(&p->lock);
+	if (p->owner) {
+		if (!ast_channel_trylock(p->owner)) {
+			ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
+			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+			ast_channel_unlock(p->owner);
+		}
+	}
+	ast_mutex_unlock(&p->lock);
+	return 0;
+}
+*/
+
+/*! \brief Initiate new call, part of PBX interface 
+ * 	dest is the dial string */
+static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+
+	if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
+		ast_log(LOG_WARNING, "jingle_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
+		return -1;
+	}
+
+	ast_setstate(ast, AST_STATE_RING);
+	ast_format_cap_copy(p->jointcap, p->cap);
+	if (!p->ringrule) {
+		ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
+		p->ringrule = iks_filter_add_rule(p->parent->connection->f, jingle_ringing_ack, p,
+							IKS_RULE_ID, p->ring, IKS_RULE_DONE);
+	} else
+		ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
+
+	jingle_transmit_invite(p);
+	jingle_create_candidates(p->parent, p, p->sid, p->them);
+
+	return 0;
+}
+
+/*! \brief Hangup a call through the jingle proxy channel */
+static int jingle_hangup(struct ast_channel *ast)
+{
+	struct jingle_pvt *p = ast_channel_tech_pvt(ast);
+	struct jingle *client;
+
+	ast_mutex_lock(&p->lock);
+	client = p->parent;
+	p->owner = NULL;
+	ast_channel_tech_pvt_set(ast, NULL);
+	if (!p->alreadygone)
+		jingle_action(client, p, JINGLE_TERMINATE);
+	ast_mutex_unlock(&p->lock);
+
+	jingle_free_pvt(client, p);
+
+	return 0;
+}
+
+/*! \brief Part of PBX interface */
+static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct jingle_pvt *p = NULL;
+	struct jingle *client = NULL;
+	char *sender = NULL, *to = NULL, *s = NULL;
+	struct ast_channel *chan = NULL;
+
+	if (data) {
+		s = ast_strdupa(data);
+		sender = strsep(&s, "/");
+		if (sender && (sender[0] != '\0'))
+			to = strsep(&s, "/");
+		if (!to) {
+			ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", data);
+			return NULL;
+		}
+		if (!to) {
+			ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", (char*) data);
+			return NULL;
+		}
+	}
+
+	client = find_jingle(to, sender);
+	if (!client) {
+		ast_log(LOG_WARNING, "Could not find recipient.\n");
+		return NULL;
+	}
+	if (!strcasecmp(client->name, "guest")){
+		/* the guest account is not tied to any configured XMPP client,
+		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
+		client->connection = ast_aji_get_client(sender);
+		if (!client->connection) {
+			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
+			return NULL;
+		}
+	}
+       
+	ASTOBJ_WRLOCK(client);
+	p = jingle_alloc(client, to, NULL);
+	if (p)
+		chan = jingle_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
+	ASTOBJ_UNLOCK(client);
+
+	return chan;
+}
+
+/*! \brief CLI command "jingle show channels" */
+static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
+	struct jingle_pvt *p;
+	struct ast_channel *chan;
+	int numchans = 0;
+	char them[AJI_MAX_JIDLEN];
+	char *jid = NULL;
+	char *resource = NULL;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jingle show channels";
+		e->usage =
+			"Usage: jingle show channels\n"
+			"       Shows current state of the Jingle channels.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	ast_mutex_lock(&jinglelock);
+	ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
+	ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
+		ASTOBJ_WRLOCK(iterator);
+		p = iterator->p;
+		while(p) {
+			chan = p->owner;
+			ast_copy_string(them, p->them, sizeof(them));
+			jid = them;
+			resource = strchr(them, '/');
+			if (!resource)
+				resource = "None";
+			else {
+				*resource = '\0';
+				resource ++;
+			}
+			if (chan)
+				ast_cli(a->fd, FORMAT, 
+					ast_channel_name(chan),
+					jid,
+					resource,
+					ast_getformatname(ast_channel_readformat(chan)),
+					ast_getformatname(ast_channel_writeformat(chan))
+					);
+			else 
+				ast_log(LOG_WARNING, "No available channel\n");
+			numchans ++;
+			p = p->next;
+		}
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+	ast_mutex_unlock(&jinglelock);
+
+	ast_cli(a->fd, "%d active jingle channel%s\n", numchans, (numchans != 1) ? "s" : "");
+	return CLI_SUCCESS;
+#undef FORMAT
+}
+
+/*! \brief CLI command "jingle reload" */
+static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jingle reload";
+		e->usage =
+			"Usage: jingle reload\n"
+			"       Reload jingle channel driver.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}	
+	
+	return CLI_SUCCESS;
+}
+
+static int jingle_parser(void *data, ikspak *pak)
+{
+	struct jingle *client = ASTOBJ_REF((struct jingle *) data);
+	ast_log(LOG_NOTICE, "Filter matched\n");
+
+	if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INITIATE)) {
+		/* New call */
+		jingle_newcall(client, pak);
+	} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_NEGOTIATE)) {
+		ast_debug(3, "About to add candidate!\n");
+		jingle_add_candidate(client, pak);
+		ast_debug(3, "Candidate Added!\n");
+	} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_ACCEPT)) {
+		jingle_is_answered(client, pak);
+	} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INFO)) {
+		jingle_handle_dtmf(client, pak);
+	} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_TERMINATE)) {
+		jingle_hangup_farend(client, pak);
+	} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "reject")) {
+		jingle_hangup_farend(client, pak);
+	}
+	ASTOBJ_UNREF(client, jingle_member_destroy);
+	return IKS_FILTER_EAT;
+}
+/* Not using this anymore probably take out soon 
+static struct jingle_candidate *jingle_create_candidate(char *args)
+{
+	char *name, *type, *preference, *protocol;
+	struct jingle_candidate *res;
+	res = ast_calloc(1, sizeof(*res));
+	if (args)
+		name = args;
+	if ((args = strchr(args, ','))) {
+		*args = '\0';
+		args++;
+		preference = args;
+	}
+	if ((args = strchr(args, ','))) {
+		*args = '\0';
+		args++;
+		protocol = args;
+	}
+	if ((args = strchr(args, ','))) {
+		*args = '\0';
+		args++;
+		type = args;
+	}
+	if (name)
+		ast_copy_string(res->name, name, sizeof(res->name));
+	if (preference) {
+		res->preference = atof(preference);
+	}
+	if (protocol) {
+		if (!strcasecmp("udp", protocol))
+			res->protocol = AJI_PROTOCOL_UDP;
+		if (!strcasecmp("ssltcp", protocol))
+			res->protocol = AJI_PROTOCOL_SSLTCP;
+	}
+	if (type) {
+		if (!strcasecmp("host", type))
+			res->type = AJI_CONNECT_HOST;
+		if (!strcasecmp("prflx", type))
+			res->type = AJI_CONNECT_PRFLX;
+		if (!strcasecmp("relay", type))
+			res->type = AJI_CONNECT_RELAY;
+		if (!strcasecmp("srflx", type))
+			res->type = AJI_CONNECT_SRFLX;
+	}
+
+	return res;
+}
+*/
+
+static int jingle_create_member(char *label, struct ast_variable *var, int allowguest,
+								struct ast_codec_pref prefs, char *context,
+								struct jingle *member)
+{
+	struct aji_client *client;
+
+	if (!member)
+		ast_log(LOG_WARNING, "Out of memory.\n");
+
+	ast_copy_string(member->name, label, sizeof(member->name));
+	ast_copy_string(member->user, label, sizeof(member->user));
+	ast_copy_string(member->context, context, sizeof(member->context));
+	member->allowguest = allowguest;
+	member->prefs = prefs;
+	while (var) {
+#if 0
+		struct jingle_candidate *candidate = NULL;
+#endif
+		if (!strcasecmp(var->name, "username"))
+			ast_copy_string(member->user, var->value, sizeof(member->user));
+		else if (!strcasecmp(var->name, "disallow"))
+			ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
+		else if (!strcasecmp(var->name, "allow"))
+			ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
+		else if (!strcasecmp(var->name, "context"))
+			ast_copy_string(member->context, var->value, sizeof(member->context));
+#if 0
+		else if (!strcasecmp(var->name, "candidate")) {
+			candidate = jingle_create_candidate(var->value);
+			if (candidate) {
+				candidate->next = member->ourcandidates;
+				member->ourcandidates = candidate;
+			}
+		}
+#endif
+		else if (!strcasecmp(var->name, "connection")) {
+			if ((client = ast_aji_get_client(var->value))) {
+				member->connection = client;
+				iks_filter_add_rule(client->f, jingle_parser, member,
+						    IKS_RULE_TYPE, IKS_PAK_IQ,
+						    IKS_RULE_FROM_PARTIAL, member->user,
+						    IKS_RULE_NS, JINGLE_NS,
+						    IKS_RULE_DONE);
+			} else {
+				ast_log(LOG_ERROR, "connection referenced not found!\n");
+				return 0;
+			}
+		}
+		var = var->next;
+	}
+	if (member->connection && member->user)
+		member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
+	else {
+		ast_log(LOG_ERROR, "No Connection or Username!\n");
+	}
+	return 1;
+}
+
+static int jingle_load_config(void)
+{
+	char *cat = NULL;
+	struct ast_config *cfg = NULL;
+	char context[100];
+	int allowguest = 1;
+	struct ast_variable *var;
+	struct jingle *member;
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct ast_codec_pref prefs;
+	struct aji_client_container *clients;
+	struct jingle_candidate *global_candidates = NULL;
+	struct ast_flags config_flags = { 0 };
+
+	cfg = ast_config_load(JINGLE_CONFIG, config_flags);
+	if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
+		return 0;
+	}
+
+	/* Copy the default jb config over global_jbconf */
+	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
+
+	cat = ast_category_browse(cfg, NULL);
+	for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+		/* handle jb conf */
+		if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
+			continue;
+
+		if (!strcasecmp(var->name, "allowguest"))
+			allowguest =
+				(ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
+		else if (!strcasecmp(var->name, "disallow"))
+			ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
+		else if (!strcasecmp(var->name, "allow"))
+			ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
+		else if (!strcasecmp(var->name, "context"))
+			ast_copy_string(context, var->value, sizeof(context));
+		else if (!strcasecmp(var->name, "externip"))
+			ast_copy_string(externip, var->value, sizeof(externip));
+		else if (!strcasecmp(var->name, "bindaddr")) {
+			if (!(hp = ast_gethostbyname(var->value, &ahp))) {
+				ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
+			} else {
+				memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
+			}
+		}
+/*  Idea to allow for custom candidates  */
+/*
+		else if (!strcasecmp(var->name, "candidate")) {
+			candidate = jingle_create_candidate(var->value);
+			if (candidate) {
+				candidate->next = global_candidates;
+				global_candidates = candidate;
+			}
+		}
+*/
+	}
+	while (cat) {
+		if (strcasecmp(cat, "general")) {
+			var = ast_variable_browse(cfg, cat);
+			member = ast_calloc(1, sizeof(*member));
+			ASTOBJ_INIT(member);
+			ASTOBJ_WRLOCK(member);
+			member->cap = ast_format_cap_alloc_nolock();
+			if (!strcasecmp(cat, "guest")) {
+				ast_copy_string(member->name, "guest", sizeof(member->name));
+				ast_copy_string(member->user, "guest", sizeof(member->user));
+				ast_copy_string(member->context, context, sizeof(member->context));
+				member->allowguest = allowguest;
+				member->prefs = prefs;
+				while (var) {
+					if (!strcasecmp(var->name, "disallow"))
+						ast_parse_allow_disallow(&member->prefs, member->cap,
+												 var->value, 0);
+					else if (!strcasecmp(var->name, "allow"))
+						ast_parse_allow_disallow(&member->prefs, member->cap,
+												 var->value, 1);
+					else if (!strcasecmp(var->name, "context"))
+						ast_copy_string(member->context, var->value,
+										sizeof(member->context));
+					else if (!strcasecmp(var->name, "parkinglot"))
+						ast_copy_string(member->parkinglot, var->value,
+										sizeof(member->parkinglot));
+/*  Idea to allow for custom candidates  */
+/*
+					else if (!strcasecmp(var->name, "candidate")) {
+						candidate = jingle_create_candidate(var->value);
+						if (candidate) {
+							candidate->next = member->ourcandidates;
+							member->ourcandidates = candidate;
+						}
+					}
+*/
+					var = var->next;
+				}
+				ASTOBJ_UNLOCK(member);
+				clients = ast_aji_get_clients();
+				if (clients) {
+					ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
+						ASTOBJ_WRLOCK(iterator);
+						ASTOBJ_WRLOCK(member);
+						if (member->connection) {
+							ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
+						}
+						member->connection = NULL;
+						iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS,	JINGLE_NS, IKS_RULE_DONE);
+						iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS,	JINGLE_DTMF_NS, IKS_RULE_DONE);
+						ASTOBJ_UNLOCK(member);
+						ASTOBJ_UNLOCK(iterator);
+					});
+					ASTOBJ_CONTAINER_LINK(&jingle_list, member);
+				} else {
+					ASTOBJ_UNLOCK(member);
+					ASTOBJ_UNREF(member, jingle_member_destroy);
+				}
+			} else {
+				ASTOBJ_UNLOCK(member);
+				if (jingle_create_member(cat, var, allowguest, prefs, context, member))
+					ASTOBJ_CONTAINER_LINK(&jingle_list, member);
+				ASTOBJ_UNREF(member, jingle_member_destroy);
+			}
+		}
+		cat = ast_category_browse(cfg, cat);
+	}
+	ast_config_destroy(cfg);
+	jingle_free_candidates(global_candidates);
+	return 1;
+}
+
+/*! \brief Load module into PBX, register channel */
+static int load_module(void)
+{
+	struct ast_sockaddr ourip_tmp;
+	struct ast_sockaddr bindaddr_tmp;
+	struct ast_format tmpfmt;
+
+	char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
+
+	if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
+	if (!(global_capability = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
+
+	free(jabber_loaded);
+	if (!jabber_loaded) {
+		/* Dependency module has a different name, if embedded */
+		jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
+		free(jabber_loaded);
+		if (!jabber_loaded) {
+			ast_log(LOG_ERROR, "chan_jingle.so depends upon res_jabber.so\n");
+			return AST_MODULE_LOAD_DECLINE;
+		}
+	}
+
+	ASTOBJ_CONTAINER_INIT(&jingle_list);
+	if (!jingle_load_config()) {
+		ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", JINGLE_CONFIG);
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	sched = ast_sched_context_create();
+	if (!sched) {
+		ast_log(LOG_WARNING, "Unable to create schedule context\n");
+	}
+
+	io = io_context_create();
+	if (!io) {
+		ast_log(LOG_WARNING, "Unable to create I/O context\n");
+	}
+
+	bindaddr.sin_family = AF_INET;
+	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+	if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp, AF_INET)) {
+		ast_log(LOG_WARNING, "Unable to get own IP address, Jingle disabled\n");
+		return 0;
+	}
+	__ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
+
+	ast_rtp_glue_register(&jingle_rtp_glue);
+	ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&jingle_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
+		return -1;
+	}
+	return 0;
+}
+
+/*! \brief Reload module */
+static int reload(void)
+{
+	return 0;
+}
+
+/*! \brief Unload the jingle channel from Asterisk */
+static int unload_module(void)
+{
+	struct jingle_pvt *privates = NULL;
+	ast_cli_unregister_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
+	/* First, take us out of the channel loop */
+	ast_channel_unregister(&jingle_tech);
+	ast_rtp_glue_unregister(&jingle_rtp_glue);
+
+	if (!ast_mutex_lock(&jinglelock)) {
+		/* Hangup all interfaces if they have an owner */
+		ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
+			ASTOBJ_WRLOCK(iterator);
+			privates = iterator->p;
+			while(privates) {
+				if (privates->owner)
+					ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
+				privates = privates->next;
+			}
+			iterator->p = NULL;
+			ASTOBJ_UNLOCK(iterator);
+		});
+		ast_mutex_unlock(&jinglelock);
+	} else {
+		ast_log(LOG_WARNING, "Unable to lock the monitor\n");
+		return -1;
+	}
+	ASTOBJ_CONTAINER_DESTROYALL(&jingle_list, jingle_member_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&jingle_list);
+
+	global_capability = ast_format_cap_destroy(global_capability);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Jingle Channel Driver",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+	       );
diff --git a/channels/chan_local.c b/channels/chan_local.c
new file mode 100644
index 0000000..562c181
--- /dev/null
+++ b/channels/chan_local.c
@@ -0,0 +1,1491 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Mark Spencer <markster at digium.com>
+ *
+ * \brief Local Proxy Channel
+ * 
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <fcntl.h>
+#include <sys/signal.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/causes.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/manager.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/astobj2.h"
+
+/*** DOCUMENTATION
+	<manager name="LocalOptimizeAway" language="en_US">
+		<synopsis>
+			Optimize away a local channel when possible.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Channel" required="true">
+				<para>The channel name to optimize away.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>A local channel created with "/n" will not automatically optimize away.
+			Calling this command on the local channel will clear that flag and allow
+			it to optimize away if it's bridged or when it becomes bridged.</para>
+		</description>
+	</manager>
+ ***/
+
+static const char tdesc[] = "Local Proxy Channel Driver";
+
+#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
+
+/* right now we are treating the locals astobj2 container as a
+ * list.  If there is ever a reason to make this more efficient
+ * increasing the bucket size would help. */
+static const int BUCKET_SIZE = 1;
+
+static struct ao2_container *locals;
+
+static unsigned int name_sequence = 0;
+
+static struct ast_jb_conf g_jb_conf = {
+	.flags = 0,
+	.max_size = -1,
+	.resync_threshold = -1,
+	.impl = "",
+	.target_extra = -1,
+};
+
+static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int local_digit_begin(struct ast_channel *ast, char digit);
+static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int local_call(struct ast_channel *ast, const char *dest, int timeout);
+static int local_hangup(struct ast_channel *ast);
+static int local_answer(struct ast_channel *ast);
+static struct ast_frame *local_read(struct ast_channel *ast);
+static int local_write(struct ast_channel *ast, struct ast_frame *f);
+static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
+static int local_sendtext(struct ast_channel *ast, const char *text);
+static int local_devicestate(const char *data);
+static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
+static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
+static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
+
+/* PBX interface structure for channel registration */
+static struct ast_channel_tech local_tech = {
+	.type = "Local",
+	.description = tdesc,
+	.requester = local_request,
+	.send_digit_begin = local_digit_begin,
+	.send_digit_end = local_digit_end,
+	.call = local_call,
+	.hangup = local_hangup,
+	.answer = local_answer,
+	.read = local_read,
+	.write = local_write,
+	.write_video = local_write,
+	.exception = local_read,
+	.indicate = local_indicate,
+	.fixup = local_fixup,
+	.send_html = local_sendhtml,
+	.send_text = local_sendtext,
+	.devicestate = local_devicestate,
+	.bridged_channel = local_bridgedchannel,
+	.queryoption = local_queryoption,
+	.setoption = local_setoption,
+};
+
+/*! \brief the local pvt structure for all channels
+
+	The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
+
+	ast_chan owner -> local_pvt -> ast_chan chan -> yet-another-pvt-depending-on-channel-type
+
+*/
+struct local_pvt {
+	unsigned int flags;             /*!< Private flags */
+	char context[AST_MAX_CONTEXT];  /*!< Context to call */
+	char exten[AST_MAX_EXTENSION];  /*!< Extension to call */
+	struct ast_format_cap *reqcap;  /*!< Requested format capabilities */
+	struct ast_jb_conf jb_conf;     /*!< jitterbuffer configuration for this local channel */
+	struct ast_channel *owner;      /*!< Master Channel - Bridging happens here */
+	struct ast_channel *chan;       /*!< Outbound channel - PBX is run here */
+};
+
+#define LOCAL_ALREADY_MASQED  (1 << 0) /*!< Already masqueraded */
+#define LOCAL_LAUNCHED_PBX    (1 << 1) /*!< PBX was launched */
+#define LOCAL_NO_OPTIMIZATION (1 << 2) /*!< Do not optimize using masquerading */
+#define LOCAL_BRIDGE          (1 << 3) /*!< Report back the "true" channel as being bridged to */
+#define LOCAL_MOH_PASSTHRU    (1 << 4) /*!< Pass through music on hold start/stop frames */
+
+/* 
+ * \brief Send a pvt in with no locks held and get all locks
+ *
+ * \note NO locks should be held prior to calling this function
+ * \note The pvt must have a ref held before calling this function
+ * \note if outchan or outowner is set != NULL after calling this function
+ *       those channels are locked and reffed.
+ * \note Batman.
+ */
+static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
+{
+	struct ast_channel *chan = NULL;
+	struct ast_channel *owner = NULL;
+
+	for (;;) {
+		ao2_lock(p);
+		if (p->chan) {
+			chan = p->chan;
+			ast_channel_ref(chan);
+		}
+		if (p->owner) {
+			owner = p->owner;
+			ast_channel_ref(owner);
+		}
+		ao2_unlock(p);
+
+		/* if we don't have both channels, then this is very easy */
+		if (!owner || !chan) {
+			if (owner) {
+				ast_channel_lock(owner);
+			} else if(chan) {
+				ast_channel_lock(chan);
+			}
+			ao2_lock(p);
+		} else {
+			/* lock both channels first, then get the pvt lock */
+			ast_channel_lock_both(chan, owner);
+			ao2_lock(p);
+		}
+
+		/* Now that we have all the locks, validate that nothing changed */
+		if (p->owner != owner || p->chan != chan) {
+			if (owner) {
+				ast_channel_unlock(owner);
+				owner = ast_channel_unref(owner);
+			}
+			if (chan) {
+				ast_channel_unlock(chan);
+				chan = ast_channel_unref(chan);
+			}
+			ao2_unlock(p);
+			continue;
+		}
+
+		break;
+	}
+	*outowner = p->owner;
+	*outchan = p->chan;
+}
+
+/* Called with ast locked */
+static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
+{
+	int res = 0;
+	struct local_pvt *p = NULL;
+	struct ast_channel *otherchan = NULL;
+	ast_chan_write_info_t *write_info;
+
+	if (option != AST_OPTION_CHANNEL_WRITE) {
+		return -1;
+	}
+
+	write_info = data;
+
+	if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
+		ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
+		return -1;
+	}
+
+	if (!strcmp(write_info->function, "CHANNEL")
+		&& !strncasecmp(write_info->data, "hangup_handler_", 15)) {
+		/* Block CHANNEL(hangup_handler_xxx) writes to the other local channel. */
+		return 0;
+	}
+
+	/* get the tech pvt */
+	if (!(p = ast_channel_tech_pvt(ast))) {
+		return -1;
+	}
+	ao2_ref(p, 1);
+	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
+
+	/* get the channel we are supposed to write to */
+	ao2_lock(p);
+	otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
+	if (!otherchan || otherchan == write_info->chan) {
+		res = -1;
+		otherchan = NULL;
+		ao2_unlock(p);
+		goto setoption_cleanup;
+	}
+	ast_channel_ref(otherchan);
+
+	/* clear the pvt lock before grabbing the channel */
+	ao2_unlock(p);
+
+	ast_channel_lock(otherchan);
+	res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
+	ast_channel_unlock(otherchan);
+
+setoption_cleanup:
+	if (p) {
+		ao2_ref(p, -1);
+	}
+	if (otherchan) {
+		ast_channel_unref(otherchan);
+	}
+	ast_channel_lock(ast); /* Lock back before we leave */
+	return res;
+}
+
+/*! \brief Adds devicestate to local channels */
+static int local_devicestate(const char *data)
+{
+	char *exten = ast_strdupa(data);
+	char *context = NULL, *opts = NULL;
+	int res;
+	struct local_pvt *lp;
+	struct ao2_iterator it;
+
+	if (!(context = strchr(exten, '@'))) {
+		ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
+		return AST_DEVICE_INVALID;
+	}
+
+	*context++ = '\0';
+
+	/* Strip options if they exist */
+	if ((opts = strchr(context, '/')))
+		*opts = '\0';
+
+	ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
+
+	res = ast_exists_extension(NULL, context, exten, 1, NULL);
+	if (!res)
+		return AST_DEVICE_INVALID;
+
+	res = AST_DEVICE_NOT_INUSE;
+
+	it = ao2_iterator_init(locals, 0);
+	for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
+		int is_inuse;
+
+		ao2_lock(lp);
+		is_inuse = !strcmp(exten, lp->exten)
+			&& !strcmp(context, lp->context)
+			&& lp->owner
+			&& ast_test_flag(lp, LOCAL_LAUNCHED_PBX);
+		ao2_unlock(lp);
+		if (is_inuse) {
+			res = AST_DEVICE_INUSE;
+			ao2_ref(lp, -1);
+			break;
+		}
+	}
+	ao2_iterator_destroy(&it);
+
+	return res;
+}
+
+/*! \brief Return the bridged channel of a Local channel */
+static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(bridge);
+	struct ast_channel *bridged = bridge;
+
+	if (!p) {
+		ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
+			ast_channel_name(chan), ast_channel_name(bridge));
+		return NULL;
+	}
+
+	ao2_lock(p);
+
+	if (ast_test_flag(p, LOCAL_BRIDGE)) {
+		/* Find the opposite channel */
+		bridged = (bridge == p->owner ? p->chan : p->owner);
+
+		/* Now see if the opposite channel is bridged to anything */
+		if (!bridged) {
+			bridged = bridge;
+		} else if (ast_channel_internal_bridged_channel(bridged)) {
+			bridged = ast_channel_internal_bridged_channel(bridged);
+		}
+	}
+
+	ao2_unlock(p);
+
+	return bridged;
+}
+
+/* Called with ast locked */
+static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
+{
+	struct local_pvt *p;
+	struct ast_channel *bridged = NULL;
+	struct ast_channel *tmp = NULL;
+	int res = 0;
+
+	if (option != AST_OPTION_T38_STATE) {
+		/* AST_OPTION_T38_STATE is the only supported option at this time */
+		return -1;
+	}
+
+	/* for some reason the channel is not locked in channel.c when this function is called */
+	if (!(p = ast_channel_tech_pvt(ast))) {
+		return -1;
+	}
+
+	ao2_lock(p);
+	if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
+		ao2_unlock(p);
+		return -1;
+	}
+	ast_channel_ref(tmp);
+	ao2_unlock(p);
+	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
+
+	ast_channel_lock(tmp);
+	if (!(bridged = ast_bridged_channel(tmp))) {
+		res = -1;
+		ast_channel_unlock(tmp);
+		goto query_cleanup;
+	}
+	ast_channel_ref(bridged);
+	ast_channel_unlock(tmp);
+
+query_cleanup:
+	if (bridged) {
+		res = ast_channel_queryoption(bridged, option, data, datalen, 0);
+		bridged = ast_channel_unref(bridged);
+	}
+	if (tmp) {
+		tmp = ast_channel_unref(tmp);
+	}
+	ast_channel_lock(ast); /* Lock back before we leave */
+
+	return res;
+}
+
+/*! \brief queue a frame on a to either the p->owner or p->chan
+ *
+ * \note the local_pvt MUST have it's ref count bumped before entering this function and
+ * decremented after this function is called.  This is a side effect of the deadlock
+ * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
+ * local_pvt, it is impossible to guarantee it will not be destroyed by another thread
+ * during deadlock avoidance.
+ */
+static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
+	struct ast_channel *us, int us_locked)
+{
+	struct ast_channel *other = NULL;
+
+	/* Recalculate outbound channel */
+	other = isoutbound ? p->owner : p->chan;
+
+	if (!other) {
+		return 0;
+	}
+
+	/* do not queue media frames if a generator is on both local channels */
+	if (us
+		&& (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
+		&& ast_channel_generator(us)
+		&& ast_channel_generator(other)) {
+		return 0;
+	}
+
+	/* grab a ref on the channel before unlocking the pvt,
+	 * other can not go away from us now regardless of locking */
+	ast_channel_ref(other);
+	if (us && us_locked) {
+		ast_channel_unlock(us);
+	}
+	ao2_unlock(p);
+
+	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
+		ast_setstate(other, AST_STATE_RINGING);
+	}
+	ast_queue_frame(other, f);
+
+	other = ast_channel_unref(other);
+	if (us && us_locked) {
+		ast_channel_lock(us);
+	}
+	ao2_lock(p);
+
+	return 0;
+}
+
+static int local_answer(struct ast_channel *ast)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int isoutbound;
+	int res = -1;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_lock(p);
+	ao2_ref(p, 1);
+	isoutbound = IS_OUTBOUND(ast, p);
+	if (isoutbound) {
+		/* Pass along answer since somebody answered us */
+		struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
+		res = local_queue_frame(p, isoutbound, &answer, ast, 1);
+	} else {
+		ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
+	}
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+	return res;
+}
+
+/*!
+ * \internal
+ * \note This function assumes that we're only called from the "outbound" local channel side
+ *
+ * \note it is assummed p is locked and reffed before entering this function
+ */
+static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
+{
+	struct ast_channel *owner;
+	struct ast_channel *chan;
+	struct ast_channel *bridged_chan;
+	struct ast_frame *f;
+
+	/* Do a few conditional checks early on just to see if this optimization is possible */
+	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
+		|| !p->chan || !p->owner) {
+		return;
+	}
+
+	/* Safely get the channel bridged to p->chan */
+	chan = ast_channel_ref(p->chan);
+
+	ao2_unlock(p); /* don't call bridged channel with the pvt locked */
+	bridged_chan = ast_bridged_channel(chan);
+	ao2_lock(p);
+
+	chan = ast_channel_unref(chan);
+
+	/* since we had to unlock p to get the bridged chan, validate our
+	 * data once again and verify the bridged channel is what we expect
+	 * it to be in order to perform this optimization */
+	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
+		|| !p->chan || !p->owner
+		|| (ast_channel_internal_bridged_channel(p->chan) != bridged_chan)) {
+		return;
+	}
+
+	/* only do the masquerade if we are being called on the outbound channel,
+	   if it has been bridged to another channel and if there are no pending
+	   frames on the owner channel (because they would be transferred to the
+	   outbound channel during the masquerade)
+	*/
+	if (!ast_channel_internal_bridged_channel(p->chan) /* Not ast_bridged_channel!  Only go one step! */
+		|| !AST_LIST_EMPTY(ast_channel_readq(p->owner))
+		|| ast != p->chan /* Sanity check (should always be false) */) {
+		return;
+	}
+
+	/* Masquerade bridged channel into owner */
+	/* Lock everything we need, one by one, and give up if
+	   we can't get everything.  Remember, we'll get another
+	   chance in just a little bit */
+	if (ast_channel_trylock(ast_channel_internal_bridged_channel(p->chan))) {
+		return;
+	}
+	if (ast_check_hangup(ast_channel_internal_bridged_channel(p->chan))
+		|| ast_channel_trylock(p->owner)) {
+		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
+		return;
+	}
+
+	/*
+	 * At this point we have 4 locks:
+	 * p, p->chan (same as ast), p->chan->_bridge, p->owner
+	 *
+	 * Flush a voice or video frame on the outbound channel to make
+	 * the queue empty faster so we can get optimized out.
+	 */
+	f = AST_LIST_FIRST(ast_channel_readq(p->chan));
+	if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+		AST_LIST_REMOVE_HEAD(ast_channel_readq(p->chan), frame_list);
+		ast_frfree(f);
+		f = AST_LIST_FIRST(ast_channel_readq(p->chan));
+	}
+
+	if (f
+		|| ast_check_hangup(p->owner)
+		|| ast_channel_masquerade(p->owner, ast_channel_internal_bridged_channel(p->chan))) {
+		ast_channel_unlock(p->owner);
+		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
+		return;
+	}
+
+	/* Masquerade got setup. */
+	ast_debug(4, "Masquerading %s <- %s\n",
+		ast_channel_name(p->owner),
+		ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
+	if (ast_channel_monitor(p->owner)
+		&& !ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan))) {
+		struct ast_channel_monitor *tmp;
+
+		/* If a local channel is being monitored, we don't want a masquerade
+		 * to cause the monitor to go away. Since the masquerade swaps the monitors,
+		 * pre-swapping the monitors before the masquerade will ensure that the monitor
+		 * ends up where it is expected.
+		 */
+		tmp = ast_channel_monitor(p->owner);
+		ast_channel_monitor_set(p->owner, ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan)));
+		ast_channel_monitor_set(ast_channel_internal_bridged_channel(p->chan), tmp);
+	}
+	if (ast_channel_audiohooks(p->chan)) {
+		struct ast_audiohook_list *audiohooks_swapper;
+
+		audiohooks_swapper = ast_channel_audiohooks(p->chan);
+		ast_channel_audiohooks_set(p->chan, ast_channel_audiohooks(p->owner));
+		ast_channel_audiohooks_set(p->owner, audiohooks_swapper);
+	}
+
+	/* If any Caller ID was set, preserve it after masquerade like above. We must check
+	 * to see if Caller ID was set because otherwise we'll mistakingly copy info not
+	 * set from the dialplan and will overwrite the real channel Caller ID. The reason
+	 * for this whole preswapping action is because the Caller ID is set on the channel
+	 * thread (which is the to be masqueraded away local channel) before both local
+	 * channels are optimized away.
+	 */
+	if (ast_channel_caller(p->owner)->id.name.valid || ast_channel_caller(p->owner)->id.number.valid
+		|| ast_channel_caller(p->owner)->id.subaddress.valid || ast_channel_caller(p->owner)->ani.name.valid
+		|| ast_channel_caller(p->owner)->ani.number.valid || ast_channel_caller(p->owner)->ani.subaddress.valid) {
+		SWAP(*ast_channel_caller(p->owner), *ast_channel_caller(ast_channel_internal_bridged_channel(p->chan)));
+	}
+	if (ast_channel_redirecting(p->owner)->from.name.valid || ast_channel_redirecting(p->owner)->from.number.valid
+		|| ast_channel_redirecting(p->owner)->from.subaddress.valid || ast_channel_redirecting(p->owner)->to.name.valid
+		|| ast_channel_redirecting(p->owner)->to.number.valid || ast_channel_redirecting(p->owner)->to.subaddress.valid) {
+		SWAP(*ast_channel_redirecting(p->owner), *ast_channel_redirecting(ast_channel_internal_bridged_channel(p->chan)));
+	}
+	if (ast_channel_dialed(p->owner)->number.str || ast_channel_dialed(p->owner)->subaddress.valid) {
+		SWAP(*ast_channel_dialed(p->owner), *ast_channel_dialed(ast_channel_internal_bridged_channel(p->chan)));
+	}
+	ast_app_group_update(p->chan, p->owner);
+	ast_set_flag(p, LOCAL_ALREADY_MASQED);
+
+	ast_channel_unlock(p->owner);
+	ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
+
+	/* Do the masquerade now. */
+	owner = ast_channel_ref(p->owner);
+	ao2_unlock(p);
+	ast_channel_unlock(ast);
+	ast_do_masquerade(owner);
+	ast_channel_unref(owner);
+	ast_channel_lock(ast);
+	ao2_lock(p);
+}
+
+static struct ast_frame  *local_read(struct ast_channel *ast)
+{
+	return &ast_null_frame;
+}
+
+static int local_write(struct ast_channel *ast, struct ast_frame *f)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* Just queue for delivery to the other side */
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_lock(p);
+	isoutbound = IS_OUTBOUND(ast, p);
+
+	if (isoutbound
+		&& (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+		check_bridge(ast, p);
+	}
+
+	if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
+		res = local_queue_frame(p, isoutbound, f, ast, 1);
+	} else {
+		ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n",
+			ast_channel_name(ast));
+		res = 0;
+	}
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+
+	return res;
+}
+
+static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(newchan);
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_lock(p);
+
+	if ((p->owner != oldchan) && (p->chan != oldchan)) {
+		ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
+		ao2_unlock(p);
+		return -1;
+	}
+	if (p->owner == oldchan) {
+		p->owner = newchan;
+	} else {
+		p->chan = newchan;
+	}
+
+	/* Do not let a masquerade cause a Local channel to be bridged to itself! */
+	if (!ast_check_hangup(newchan) && ((p->owner && ast_channel_internal_bridged_channel(p->owner) == p->chan) || (p->chan && ast_channel_internal_bridged_channel(p->chan) == p->owner))) {
+		ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
+		ao2_unlock(p);
+		ast_queue_hangup(newchan);
+		return -1;
+	}
+
+	ao2_unlock(p);
+	return 0;
+}
+
+static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = 0;
+	struct ast_frame f = { AST_FRAME_CONTROL, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+
+	/* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
+	if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
+		ast_moh_start(ast, data, NULL);
+	} else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
+		ast_moh_stop(ast);
+	} else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
+		struct ast_channel *this_channel;
+		struct ast_channel *the_other_channel;
+		/* A connected line update frame may only contain a partial amount of data, such
+		 * as just a source, or just a ton, and not the full amount of information. However,
+		 * the collected information is all stored in the outgoing channel's connectedline
+		 * structure, so when receiving a connected line update on an outgoing local channel,
+		 * we need to transmit the collected connected line information instead of whatever
+		 * happens to be in this control frame. The same applies for redirecting information, which
+		 * is why it is handled here as well.*/
+		ao2_lock(p);
+		isoutbound = IS_OUTBOUND(ast, p);
+		if (isoutbound) {
+			this_channel = p->chan;
+			the_other_channel = p->owner;
+		} else {
+			this_channel = p->owner;
+			the_other_channel = p->chan;
+		}
+		if (the_other_channel) {
+			unsigned char frame_data[1024];
+			if (condition == AST_CONTROL_CONNECTED_LINE) {
+				if (isoutbound) {
+					ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel), ast_channel_connected(this_channel));
+				}
+				f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), ast_channel_connected(this_channel), NULL);
+			} else {
+				f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), ast_channel_redirecting(this_channel), NULL);
+			}
+			f.subclass.integer = condition;
+			f.data.ptr = frame_data;
+			res = local_queue_frame(p, isoutbound, &f, ast, 1);
+		}
+		ao2_unlock(p);
+	} else if (condition == AST_CONTROL_RINGING && ast_channel_state(ast) != AST_STATE_RING) {
+		/* Don't queue ringing frames if the channel is not in a "ring" state. Otherwise,
+		 * the real channel on the other end will likely start a playtones generator. It is
+		 * possible that this playtones generator will never be stopped under certain
+		 * circumstances.
+		 */
+		res = -1;
+	} else {
+		/* Queue up a frame representing the indication as a control frame */
+		ao2_lock(p);
+		/*
+		 * Block -1 stop tones events if we are to be optimized out.  We
+		 * don't need a flurry of these events on an unreal channel chain
+		 * when initially connected to slow the optimization process.
+		 */
+		if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
+			isoutbound = IS_OUTBOUND(ast, p);
+			f.subclass.integer = condition;
+			f.data.ptr = (void *) data;
+			f.datalen = datalen;
+			res = local_queue_frame(p, isoutbound, &f, ast, 1);
+
+			if (!res && (condition == AST_CONTROL_T38_PARAMETERS) &&
+			    (datalen == sizeof(struct ast_control_t38_parameters))) {
+				const struct ast_control_t38_parameters *parameters = data;
+				
+				if (parameters->request_response == AST_T38_REQUEST_PARMS) {
+					res = AST_T38_REQUEST_PARMS;
+				}
+			}
+		} else {
+			ast_debug(4, "Blocked indication %d\n", condition);
+		}
+		ao2_unlock(p);
+	}
+
+	ao2_ref(p, -1);
+	return res;
+}
+
+static int local_digit_begin(struct ast_channel *ast, char digit)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_lock(p);
+	isoutbound = IS_OUTBOUND(ast, p);
+	f.subclass.integer = digit;
+	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+
+	return res;
+}
+
+static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	struct ast_frame f = { AST_FRAME_DTMF_END, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_lock(p);
+	isoutbound = IS_OUTBOUND(ast, p);
+	f.subclass.integer = digit;
+	f.len = duration;
+	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+
+	return res;
+}
+
+static int local_sendtext(struct ast_channel *ast, const char *text)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	struct ast_frame f = { AST_FRAME_TEXT, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_lock(p);
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	isoutbound = IS_OUTBOUND(ast, p);
+	f.data.ptr = (char *) text;
+	f.datalen = strlen(text) + 1;
+	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+	return res;
+}
+
+static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res = -1;
+	struct ast_frame f = { AST_FRAME_HTML, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_lock(p);
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	isoutbound = IS_OUTBOUND(ast, p);
+	f.subclass.integer = subclass;
+	f.data.ptr = (char *)data;
+	f.datalen = datalen;
+	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+
+	return res;
+}
+
+/*! \brief Initiate new call, part of PBX interface
+ *         dest is the dial string */
+static int local_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int pvt_locked = 0;
+
+	struct ast_channel *owner = NULL;
+	struct ast_channel *chan = NULL;
+	int res;
+	struct ast_var_t *varptr;
+	struct ast_var_t *clone_var;
+	char *reduced_dest = ast_strdupa(dest);
+	char *slash;
+	const char *exten;
+	const char *context;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* since we are letting go of channel locks that were locked coming into
+	 * this function, then we need to give the tech pvt a ref */
+	ao2_ref(p, 1);
+	ast_channel_unlock(ast);
+
+	awesome_locking(p, &chan, &owner);
+	pvt_locked = 1;
+
+	if (owner != ast) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	if (!owner || !chan) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
+	 * call, so it's done here instead.
+	 *
+	 * All these failure points just return -1. The individual strings will
+	 * be cleared when we destroy the channel.
+	 */
+	ast_party_redirecting_copy(ast_channel_redirecting(chan), ast_channel_redirecting(owner));
+
+	ast_party_dialed_copy(ast_channel_dialed(chan), ast_channel_dialed(owner));
+
+	ast_connected_line_copy_to_caller(ast_channel_caller(chan), ast_channel_connected(owner));
+	ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(owner));
+
+	ast_channel_language_set(chan, ast_channel_language(owner));
+	ast_channel_accountcode_set(chan, ast_channel_accountcode(owner));
+	ast_channel_musicclass_set(chan, ast_channel_musicclass(owner));
+	ast_cdr_update(chan);
+
+	ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
+
+	/* Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's set on the queue/dial call request in the dialplan */
+	if (ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) {
+		ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
+	}
+
+	/* copy the channel variables from the incoming channel to the outgoing channel */
+	/* Note that due to certain assumptions, they MUST be in the same order */
+	AST_LIST_TRAVERSE(ast_channel_varshead(owner), varptr, entries) {
+		clone_var = ast_var_assign(varptr->name, varptr->value);
+		if (clone_var) {
+			AST_LIST_INSERT_TAIL(ast_channel_varshead(chan), clone_var, entries);
+		}
+	}
+	ast_channel_datastore_inherit(owner, chan);
+	/* If the local channel has /n or /b on the end of it,
+	 * we need to lop that off for our argument to setting
+	 * up the CC_INTERFACES variable
+	 */
+	if ((slash = strrchr(reduced_dest, '/'))) {
+		*slash = '\0';
+	}
+	ast_set_cc_interfaces_chanvar(chan, reduced_dest);
+
+	exten = ast_strdupa(ast_channel_exten(chan));
+	context = ast_strdupa(ast_channel_context(chan));
+
+	ao2_unlock(p);
+	pvt_locked = 0;
+
+	ast_channel_unlock(chan);
+
+	if (!ast_exists_extension(chan, context, exten, 1,
+		S_COR(ast_channel_caller(owner)->id.number.valid, ast_channel_caller(owner)->id.number.str, NULL))) {
+		ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
+		res = -1;
+		chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
+		goto return_cleanup;
+	}
+
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
+			<syntax>
+				<parameter name="Channel1">
+					<para>The name of the Local Channel half that bridges to another channel.</para>
+				</parameter>
+				<parameter name="Channel2">
+					<para>The name of the Local Channel half that executes the dialplan.</para>
+				</parameter>
+				<parameter name="Context">
+					<para>The context in the dialplan that Channel2 starts in.</para>
+				</parameter>
+				<parameter name="Exten">
+					<para>The extension in the dialplan that Channel2 starts in.</para>
+				</parameter>
+				<parameter name="LocalOptimization">
+					<enumlist>
+						<enum name="Yes"/>
+						<enum name="No"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "LocalBridge",
+		      "Channel1: %s\r\n"
+		      "Channel2: %s\r\n"
+		      "Uniqueid1: %s\r\n"
+		      "Uniqueid2: %s\r\n"
+		      "Context: %s\r\n"
+		      "Exten: %s\r\n"
+		      "LocalOptimization: %s\r\n",
+			ast_channel_name(p->owner), ast_channel_name(p->chan), ast_channel_uniqueid(p->owner), ast_channel_uniqueid(p->chan),
+			p->context, p->exten,
+			ast_test_flag(p, LOCAL_NO_OPTIMIZATION) ? "No" : "Yes");
+
+
+	/* Start switch on sub channel */
+	if (!(res = ast_pbx_start(chan))) {
+		ao2_lock(p);
+		ast_set_flag(p, LOCAL_LAUNCHED_PBX);
+		ao2_unlock(p);
+	}
+	chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
+
+return_cleanup:
+	if (p) {
+		if (pvt_locked) {
+			ao2_unlock(p);
+		}
+		ao2_ref(p, -1);
+	}
+	if (chan) {
+		ast_channel_unlock(chan);
+		chan = ast_channel_unref(chan);
+	}
+
+	/* owner is supposed to be == to ast,  if it
+	 * is, don't unlock it because ast must exit locked */
+	if (owner) {
+		if (owner != ast) {
+			ast_channel_unlock(owner);
+			ast_channel_lock(ast);
+		}
+		owner = ast_channel_unref(owner);
+	} else {
+		/* we have to exit with ast locked */
+		ast_channel_lock(ast);
+	}
+
+	return res;
+}
+
+/*! \brief Hangup a call through the local proxy channel */
+static int local_hangup(struct ast_channel *ast)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int isoutbound;
+	int hangup_chan = 0;
+	int res = 0;
+	struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast_channel_hangupcause(ast) };
+	struct ast_channel *owner = NULL;
+	struct ast_channel *chan = NULL;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* give the pvt a ref since we are unlocking the channel. */
+	ao2_ref(p, 1);
+
+	/* the pvt isn't going anywhere, we gave it a ref */
+	ast_channel_unlock(ast);
+
+	/* lock everything */
+	awesome_locking(p, &chan, &owner);
+
+	if (ast != chan && ast != owner) {
+		res = -1;
+		goto local_hangup_cleanup;
+	}
+
+	isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
+
+	if (p->chan && ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) {
+		ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
+		ast_debug(2, "This local call has AST_CAUSE_ANSWERED_ELSEWHERE set.\n");
+	}
+
+	if (isoutbound) {
+		const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
+
+		if (status && p->owner) {
+			ast_channel_hangupcause_set(p->owner, ast_channel_hangupcause(p->chan));
+			pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
+		}
+
+		ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
+		p->chan = NULL;
+	} else {
+		if (p->chan) {
+			ast_queue_hangup(p->chan);
+		}
+		p->owner = NULL;
+	}
+
+	ast_channel_tech_pvt_set(ast, NULL); /* this is one of our locked channels, doesn't matter which */
+
+	if (!p->owner && !p->chan) {
+		ao2_unlock(p);
+
+		/* Remove from list */
+		ao2_unlink(locals, p);
+		ao2_ref(p, -1);
+		p = NULL;
+		res = 0;
+		goto local_hangup_cleanup;
+	}
+	if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
+		/* Need to actually hangup since there is no PBX */
+		hangup_chan = 1;
+	} else {
+		local_queue_frame(p, isoutbound, &f, NULL, 0);
+	}
+
+local_hangup_cleanup:
+	if (p) {
+		ao2_unlock(p);
+		ao2_ref(p, -1);
+	}
+	if (owner) {
+		ast_channel_unlock(owner);
+		owner = ast_channel_unref(owner);
+	}
+	if (chan) {
+		ast_channel_unlock(chan);
+		if (hangup_chan) {
+			ast_hangup(chan);
+		}
+		chan = ast_channel_unref(chan);
+	}
+
+	/* leave with the same stupid channel locked that came in */
+	ast_channel_lock(ast);
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief struct local_pvt destructor.
+ *
+ * \param vdoomed Void local_pvt to destroy.
+ *
+ * \return Nothing
+ */
+static void local_pvt_destructor(void *vdoomed)
+{
+	struct local_pvt *doomed = vdoomed;
+
+	doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
+
+	ast_module_unref(ast_module_info->self);
+}
+
+/*! \brief Create a call structure */
+static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
+{
+	struct local_pvt *tmp = NULL;
+	char *c = NULL, *opts = NULL;
+
+	if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) {
+		return NULL;
+	}
+	if (!(tmp->reqcap = ast_format_cap_dup(cap))) {
+		ao2_ref(tmp, -1);
+		return NULL;
+	}
+
+	ast_module_ref(ast_module_info->self);
+
+	/* Initialize private structure information */
+	ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
+
+	memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
+
+	/* Look for options */
+	if ((opts = strchr(tmp->exten, '/'))) {
+		*opts++ = '\0';
+		if (strchr(opts, 'n'))
+			ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
+		if (strchr(opts, 'j')) {
+			if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
+				ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
+			else {
+				ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
+					"to use the 'j' option to enable the jitterbuffer\n");
+			}
+		}
+		if (strchr(opts, 'b')) {
+			ast_set_flag(tmp, LOCAL_BRIDGE);
+		}
+		if (strchr(opts, 'm')) {
+			ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
+		}
+	}
+
+	/* Look for a context */
+	if ((c = strchr(tmp->exten, '@')))
+		*c++ = '\0';
+
+	ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
+#if 0
+	/* We can't do this check here, because we don't know the CallerID yet, and
+	 * the CallerID could potentially affect what step is actually taken (or
+	 * even if that step exists). */
+	if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
+		ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
+		tmp = local_pvt_destroy(tmp);
+	} else {
+#endif
+		/* Add to list */
+		ao2_link(locals, tmp);
+#if 0
+	}
+#endif
+	return tmp; /* this is returned with a ref */
+}
+
+/*! \brief Start new local channel */
+static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
+{
+	struct ast_channel *tmp = NULL, *tmp2 = NULL;
+	struct ast_format fmt;
+	int generated_seqno = ast_atomic_fetchadd_int((int *)&name_sequence, +1);
+	const char *t;
+	int ama;
+
+	/* Allocate two new Asterisk channels */
+	/* safe accountcode */
+	if (p->owner && ast_channel_accountcode(p->owner))
+		t = ast_channel_accountcode(p->owner);
+	else
+		t = "";
+
+	if (p->owner)
+		ama = ast_channel_amaflags(p->owner);
+	else
+		ama = 0;
+
+	/* Make sure that the ;2 channel gets the same linkedid as ;1. You can't pass linkedid to both
+	 * allocations since if linkedid isn't set, then each channel will generate its own linkedid. */
+	if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%08x;1", p->exten, p->context, (unsigned)generated_seqno))
+		|| !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ast_channel_linkedid(tmp), ama, "Local/%s@%s-%08x;2", p->exten, p->context, (unsigned)generated_seqno))) {
+		if (tmp) {
+			tmp = ast_channel_release(tmp);
+		}
+		ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
+		return NULL;
+	}
+
+	if (callid) {
+		ast_channel_callid_set(tmp, callid);
+		ast_channel_callid_set(tmp2, callid);
+	}
+
+	ast_channel_tech_set(tmp, &local_tech);
+	ast_channel_tech_set(tmp2, &local_tech);
+
+	ast_format_cap_copy(ast_channel_nativeformats(tmp), p->reqcap);
+	ast_format_cap_copy(ast_channel_nativeformats(tmp2), p->reqcap);
+
+	/* Determine our read/write format and set it on each channel */
+	ast_best_codec(p->reqcap, &fmt);
+	ast_format_copy(ast_channel_writeformat(tmp), &fmt);
+	ast_format_copy(ast_channel_writeformat(tmp2), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp2), &fmt);
+	ast_format_copy(ast_channel_readformat(tmp), &fmt);
+	ast_format_copy(ast_channel_readformat(tmp2), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp2), &fmt);
+
+	ast_channel_tech_pvt_set(tmp, p);
+	ast_channel_tech_pvt_set(tmp2, p);
+
+	ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+	ast_set_flag(ast_channel_flags(tmp2), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+
+	p->owner = tmp;
+	p->chan = tmp2;
+
+	ast_channel_context_set(tmp, p->context);
+	ast_channel_context_set(tmp2, p->context);
+	ast_channel_exten_set(tmp2, p->exten);
+	ast_channel_priority_set(tmp, 1);
+	ast_channel_priority_set(tmp2, 1);
+
+	ast_jb_configure(tmp, &p->jb_conf);
+
+	return tmp;
+}
+
+/*! \brief Part of PBX interface */
+static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct local_pvt *p;
+	struct ast_channel *chan;
+	struct ast_callid *callid = ast_read_threadstorage_callid();
+
+	/* Allocate a new private structure and then Asterisk channel */
+	p = local_alloc(data, cap);
+	if (!p) {
+		chan = NULL;
+		goto local_request_end;
+	}
+	chan = local_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
+	if (!chan) {
+		ao2_unlink(locals, p);
+	} else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
+		ao2_unlink(locals, p);
+		p->owner = ast_channel_release(p->owner);
+		p->chan = ast_channel_release(p->chan);
+		chan = NULL;
+	}
+	ao2_ref(p, -1); /* kill the ref from the alloc */
+
+local_request_end:
+
+	if (callid) {
+		ast_callid_unref(callid);
+	}
+
+	return chan;
+}
+
+/*! \brief CLI command "local show channels" */
+static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct local_pvt *p = NULL;
+	struct ao2_iterator it;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "local show channels";
+		e->usage =
+			"Usage: local show channels\n"
+			"       Provides summary information on active local proxy channels.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ao2_container_count(locals) == 0) {
+		ast_cli(a->fd, "No local channels in use\n");
+		return RESULT_SUCCESS;
+	}
+
+	it = ao2_iterator_init(locals, 0);
+	while ((p = ao2_iterator_next(&it))) {
+		ao2_lock(p);
+		ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? ast_channel_name(p->owner) : "<unowned>", p->exten, p->context);
+		ao2_unlock(p);
+		ao2_ref(p, -1);
+	}
+	ao2_iterator_destroy(&it);
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_local[] = {
+	AST_CLI_DEFINE(locals_show, "List status of local channels"),
+};
+
+static int manager_optimize_away(struct mansession *s, const struct message *m)
+{
+	const char *channel;
+	struct local_pvt *p, *tmp = NULL;
+	struct ast_channel *c;
+	int found = 0;
+	struct ao2_iterator it;
+
+	channel = astman_get_header(m, "Channel");
+
+	if (ast_strlen_zero(channel)) {
+		astman_send_error(s, m, "'Channel' not specified.");
+		return 0;
+	}
+
+	c = ast_channel_get_by_name(channel);
+	if (!c) {
+		astman_send_error(s, m, "Channel does not exist.");
+		return 0;
+	}
+
+	p = ast_channel_tech_pvt(c);
+	ast_channel_unref(c);
+	c = NULL;
+
+	it = ao2_iterator_init(locals, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		if (tmp == p) {
+			ao2_lock(tmp);
+			found = 1;
+			ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
+			ao2_unlock(tmp);
+			ao2_ref(tmp, -1);
+			break;
+		}
+		ao2_ref(tmp, -1);
+	}
+	ao2_iterator_destroy(&it);
+
+	if (found) {
+		astman_send_ack(s, m, "Queued channel to be optimized away");
+	} else {
+		astman_send_error(s, m, "Unable to find channel");
+	}
+
+	return 0;
+}
+
+
+static int locals_cmp_cb(void *obj, void *arg, int flags)
+{
+	return (obj == arg) ? CMP_MATCH : 0;
+}
+
+/*! \brief Load module into PBX, register channel */
+static int load_module(void)
+{
+	if (!(local_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_format_cap_add_all(local_tech.capabilities);
+
+	if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
+		ast_format_cap_destroy(local_tech.capabilities);
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&local_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
+		ao2_ref(locals, -1);
+		ast_format_cap_destroy(local_tech.capabilities);
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
+	ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+/*! \brief Unload the local proxy channel from Asterisk */
+static int unload_module(void)
+{
+	struct local_pvt *p = NULL;
+	struct ao2_iterator it;
+
+	/* First, take us out of the channel loop */
+	ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
+	ast_manager_unregister("LocalOptimizeAway");
+	ast_channel_unregister(&local_tech);
+
+	it = ao2_iterator_init(locals, 0);
+	while ((p = ao2_iterator_next(&it))) {
+		if (p->owner) {
+			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+		}
+		ao2_ref(p, -1);
+	}
+	ao2_iterator_destroy(&it);
+	ao2_ref(locals, -1);
+
+	ast_format_cap_destroy(local_tech.capabilities);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
+		.load = load_module,
+		.unload = unload_module,
+		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+	);
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 546256e..7154f43 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -22,17 +22,13 @@
  *
  * \author Mark Spencer <markster at digium.com>
  *
+ * \par See also
+ * \arg \ref Config_mgcp
+ * \arg \ref res_pktccops
+ *
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_mgcp.c uses the configuration file \ref mgcp.conf
- * \addtogroup configuration_file
- */
-
-/*! \page mgcp.conf mgcp.conf
- * \verbinclude mgcp.conf.sample
- */
-
 /*** MODULEINFO
         <use type="module">res_pktccops</use>
 	<support_level>extended</support_level>
@@ -40,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <sys/ioctl.h>
@@ -59,7 +55,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/channel.h"
 #include "asterisk/config.h"
 #include "asterisk/module.h"
-#include "asterisk/pickup.h"
 #include "asterisk/pbx.h"
 #include "asterisk/sched.h"
 #include "asterisk/io.h"
@@ -68,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/callerid.h"
 #include "asterisk/cli.h"
 #include "asterisk/say.h"
+#include "asterisk/cdr.h"
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
 #include "asterisk/app.h"
@@ -79,14 +75,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/devicestate.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/abstract_jb.h"
+#include "asterisk/event.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/pktccops.h"
-#include "asterisk/stasis.h"
-#include "asterisk/bridge.h"
-#include "asterisk/features_config.h"
-#include "asterisk/parking.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
 
 /*
  * Define to work around buggy dlink MGCP phone firmware which
@@ -203,7 +194,7 @@ static int directmedia = DIRECTMEDIA;
 
 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
 
-static char mailbox[AST_MAX_MAILBOX_UNIQUEID];
+static char mailbox[AST_MAX_EXTENSION];
 
 static int amaflags = 0;
 
@@ -348,7 +339,7 @@ struct mgcp_endpoint {
 	char curtone[80];			/*!< Current tone */
 	char mailbox[AST_MAX_EXTENSION];
 	char parkinglot[AST_MAX_CONTEXT];   /*!< Parkinglot */
-	struct stasis_subscription *mwi_event_sub;
+	struct ast_event_sub *mwi_event_sub;
 	ast_group_t callgroup;
 	ast_group_t pickupgroup;
 	int callwaiting;
@@ -435,7 +426,6 @@ static int mgcpsock  = -1;
 
 static struct sockaddr_in bindaddr;
 
-static void mgcp_set_owner(struct mgcp_subchannel *sub, struct ast_channel *chan);
 static struct ast_frame  *mgcp_read(struct ast_channel *ast);
 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
@@ -452,7 +442,7 @@ static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
 static char *mgcp_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static int reload_config(int reload);
 
-static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause);
+static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
 static int mgcp_call(struct ast_channel *ast, const char *dest, int timeout);
 static int mgcp_hangup(struct ast_channel *ast);
 static int mgcp_answer(struct ast_channel *ast);
@@ -486,10 +476,11 @@ static struct ast_channel_tech mgcp_tech = {
 	.fixup = mgcp_fixup,
 	.send_digit_begin = mgcp_senddigit_begin,
 	.send_digit_end = mgcp_senddigit_end,
+	.bridge = ast_rtp_instance_bridge,
 	.func_channel_read = acf_channel_read,
 };
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* This module does not handle MWI in an event-based manner.  However, it
 	 * subscribes to MWI for each mailbox that is configured so that the core
@@ -500,15 +491,24 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
 static int has_voicemail(struct mgcp_endpoint *p)
 {
 	int new_msgs;
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
-	if (msg) {
-		struct ast_mwi_state *mwi_state = stasis_message_data(msg);
-		new_msgs = mwi_state->new_msgs;
-	} else {
+	struct ast_event *event;
+	char *mbox, *cntx;
+
+	cntx = mbox = ast_strdupa(p->mailbox);
+	strsep(&cntx, "@");
+	if (ast_strlen_zero(cntx))
+		cntx = "default";
+
+	event = ast_event_get_cached(AST_EVENT_MWI,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
+		AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
+		AST_EVENT_IE_END);
+
+	if (event) {
+		new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+		ast_event_destroy(event);
+	} else
 		new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
-	}
 
 	return new_msgs;
 }
@@ -522,7 +522,7 @@ static int unalloc_sub(struct mgcp_subchannel *sub)
 	}
 	ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
 
-	mgcp_set_owner(sub, NULL);
+	sub->owner = NULL;
 	if (!ast_strlen_zero(sub->cxident)) {
 		transmit_connection_del(sub);
 	}
@@ -839,11 +839,20 @@ static int mgcp_call(struct ast_channel *ast, const char *dest, int timeout)
 	struct mgcp_endpoint *p;
 	struct mgcp_subchannel *sub;
 	char tone[50] = "";
-	const char *distinctive_ring = pbx_builtin_getvar_helper(ast, "ALERT_INFO");
+	const char *distinctive_ring = NULL;
+	struct varshead *headp;
+	struct ast_var_t *current;
 
 	ast_debug(3, "MGCP mgcp_call(%s)\n", ast_channel_name(ast));
 	sub = ast_channel_tech_pvt(ast);
 	p = sub->parent;
+	headp = ast_channel_varshead(ast);
+	AST_LIST_TRAVERSE(headp,current,entries) {
+		/* Check whether there is an ALERT_INFO variable */
+		if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
+			distinctive_ring = ast_var_value(current);
+		}
+	}
 
 	ast_mutex_lock(&sub->lock);
 	switch (p->hookstate) {
@@ -913,6 +922,7 @@ static int mgcp_hangup(struct ast_channel *ast)
 {
 	struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
 	struct mgcp_endpoint *p = sub->parent;
+	struct ast_channel *bridged;
 
 	ast_debug(1, "mgcp_hangup(%s)\n", ast_channel_name(ast));
 	if (!ast_channel_tech_pvt(ast)) {
@@ -938,7 +948,7 @@ static int mgcp_hangup(struct ast_channel *ast)
 		}
 	}
 
-	mgcp_set_owner(sub, NULL);
+	sub->owner = NULL;
 
 	/* for deleting gate */
 	if (p->pktcgatealloc && sub->gate) {
@@ -959,11 +969,10 @@ static int mgcp_hangup(struct ast_channel *ast)
 	}
 	sub->cxident[0] = '\0';
 	if ((sub == p->sub) && sub->next->owner) {
-		RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(sub->next->owner), ast_channel_cleanup);
-
 		if (p->hookstate == MGCP_OFFHOOK) {
-			if (sub->next->owner && bridged) {
+			if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
 				/* ncs fix! */
+				bridged = ast_bridged_channel(sub->next->owner);
 				transmit_notify_request_with_callerid(p->sub, (p->ncs ? "L/wt1" : "L/wt"),
 					S_COR(ast_channel_caller(bridged)->id.number.valid, ast_channel_caller(bridged)->id.number.str, ""),
 					S_COR(ast_channel_caller(bridged)->id.name.valid, ast_channel_caller(bridged)->id.name.str, ""));
@@ -973,7 +982,8 @@ static int mgcp_hangup(struct ast_channel *ast)
 			p->sub = sub->next;
 			p->sub->cxmode = MGCP_CX_RECVONLY;
 			transmit_modify_request(p->sub);
-			if (sub->next->owner && bridged) {
+			if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
+				bridged = ast_bridged_channel(sub->next->owner);
 				transmit_notify_request_with_callerid(p->sub, "L/rg",
 					S_COR(ast_channel_caller(bridged)->id.number.valid, ast_channel_caller(bridged)->id.number.str, ""),
 					S_COR(ast_channel_caller(bridged)->id.name.valid, ast_channel_caller(bridged)->id.name.str, ""));
@@ -1135,7 +1145,7 @@ static char *handle_mgcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_
 		e->command = "mgcp set debug {on|off}";
 		e->usage =
 			"Usage: mgcp set debug {on|off}\n"
-			"       Enables/Disables dumping of MGCP packets for debugging purposes\n";
+			"       Enables/Disables dumping of MGCP packets for debugging purposes\n";	
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
@@ -1200,20 +1210,9 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
 	if (sub->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-				struct ast_format_cap *caps;
-
-				ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format));
-
-				caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-				if (caps) {
-					ast_format_cap_append(caps, f->subclass.format, 0);
-					ast_channel_nativeformats_set(sub->owner, caps);
-					ao2_ref(caps, -1);
-				} else {
-					return &ast_null_frame;
-				}
-
+			if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format)) {
+				ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+				ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format);
 				ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
 				ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
 			}
@@ -1229,13 +1228,6 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
 	return f;
 }
 
-static void mgcp_set_owner(struct mgcp_subchannel *sub, struct ast_channel *chan)
-{
-	sub->owner = chan;
-	if (sub->rtp) {
-		ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(chan) : "");
-	}
-}
 
 static struct ast_frame *mgcp_read(struct ast_channel *ast)
 {
@@ -1251,6 +1243,7 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 	struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
 	int res = 0;
+	char buf[256];
 
 	if (frame->frametype != AST_FRAME_VOICE) {
 		if (frame->frametype == AST_FRAME_IMAGE)
@@ -1260,14 +1253,12 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
 			return 0;
 		}
 	} else {
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *cap_buf = ast_str_alloca(64);
-
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
-				ast_format_get_name(frame->subclass.format),
-				ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
-				ast_format_get_name(ast_channel_readformat(ast)),
-				ast_format_get_name(ast_channel_writeformat(ast)));
+				ast_getformatname(&frame->subclass.format),
+				ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+				ast_getformatname(ast_channel_readformat(ast)),
+				ast_getformatname(ast_channel_writeformat(ast)));
 			/* return -1; */
 		}
 	}
@@ -1300,7 +1291,7 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
 		return -1;
 	}
-	mgcp_set_owner(sub, newchan);
+	sub->owner = newchan;
 	ast_mutex_unlock(&sub->lock);
 	return 0;
 }
@@ -1455,7 +1446,7 @@ static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, siz
 	ast_mutex_lock(&sub->lock);
 	switch(ind) {
 	case AST_CONTROL_RINGING:
-#ifdef DLINK_BUGGY_FIRMWARE
+#ifdef DLINK_BUGGY_FIRMWARE	
 		transmit_notify_request(sub, "rt");
 #else
 		if (!sub->sdpsent) { /* will hide the inband progress!!! */
@@ -1501,105 +1492,87 @@ static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, siz
 	return res;
 }
 
-static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, const char *linkedid)
 {
-	struct ast_format_cap *caps = NULL;
 	struct ast_channel *tmp;
 	struct ast_variable *v = NULL;
 	struct mgcp_endpoint *i = sub->parent;
-	struct ast_format *tmpfmt;
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_log(LOG_ERROR, "Format capabilities could not be created\n");
-		return NULL;
-	}
-	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
-	if (!tmp) {
-		ast_log(LOG_WARNING, "Channel could not be created\n");
-		ao2_ref(caps, -1);
-		return NULL;
-	}
-
-	ast_channel_stage_snapshot(tmp);
-	ast_channel_tech_set(tmp, &mgcp_tech);
-	if (ast_format_cap_count(i->cap)) {
-		ast_format_cap_append_from_cap(caps, i->cap, AST_MEDIA_TYPE_UNKNOWN);
-	} else {
-		ast_format_cap_append_from_cap(caps, global_capability, AST_MEDIA_TYPE_UNKNOWN);
-	}
-	ast_channel_nativeformats_set(tmp, caps);
-	ao2_ref(caps, -1);
-	if (sub->rtp) {
-		ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
-	}
-	if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
-		i->dsp = ast_dsp_new();
-		ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
-		/* this is to prevent clipping of dtmf tones during dsp processing */
-		ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
-	} else {
-		i->dsp = NULL;
-	}
-	if (state == AST_STATE_RING) {
-		ast_channel_rings_set(tmp, 1);
-	}
-
-	tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
-	ast_channel_set_writeformat(tmp, tmpfmt);
-	ast_channel_set_rawwriteformat(tmp, tmpfmt);
-	ast_channel_set_readformat(tmp, tmpfmt);
-	ast_channel_set_rawreadformat(tmp, tmpfmt);
-	ao2_ref(tmpfmt, -1);
-	ast_channel_tech_pvt_set(tmp, sub);
-	if (!ast_strlen_zero(i->language))
-		ast_channel_language_set(tmp, i->language);
-	if (!ast_strlen_zero(i->accountcode))
-		ast_channel_accountcode_set(tmp, i->accountcode);
-	if (i->amaflags)
-		ast_channel_amaflags_set(tmp, i->amaflags);
-	mgcp_set_owner(sub, tmp);
-	ast_module_ref(ast_module_info->self);
-	ast_channel_callgroup_set(tmp, i->callgroup);
-	ast_channel_pickupgroup_set(tmp, i->pickupgroup);
-	ast_channel_call_forward_set(tmp, i->call_forward);
-	ast_channel_context_set(tmp, i->context);
-	ast_channel_exten_set(tmp, i->exten);
-	/* Don't use ast_set_callerid() here because it will
-	 * generate a needless NewCallerID event */
-	if (!ast_strlen_zero(i->cid_num)) {
-		ast_channel_caller(tmp)->ani.number.valid = 1;
-		ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
-	}
-
-	if (!i->adsi) {
-		ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
-	}
-	ast_channel_priority_set(tmp, 1);
-
-	/* Set channel variables for this call from configuration */
-	for (v = i->chanvars ; v ; v = v->next) {
-		char valuebuf[1024];
-		pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
-	}
+	struct ast_format tmpfmt;
+
+	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
+	if (tmp) {
+		ast_channel_tech_set(tmp, &mgcp_tech);
+		ast_format_cap_copy(ast_channel_nativeformats(tmp), i->cap);
+		if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
+			ast_format_cap_copy(ast_channel_nativeformats(tmp), global_capability);
+		}
+		if (sub->rtp) {
+			ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
+		}
+		if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
+			i->dsp = ast_dsp_new();
+			ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
+			/* this is to prevent clipping of dtmf tones during dsp processing */
+			ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
+		} else {
+			i->dsp = NULL;
+		}
+		if (state == AST_STATE_RING)
+			ast_channel_rings_set(tmp, 1);
+
+		ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+		ast_channel_tech_pvt_set(tmp, sub);
+		if (!ast_strlen_zero(i->language))
+			ast_channel_language_set(tmp, i->language);
+		if (!ast_strlen_zero(i->accountcode))
+			ast_channel_accountcode_set(tmp, i->accountcode);
+		if (i->amaflags)
+			ast_channel_amaflags_set(tmp, i->amaflags);
+		sub->owner = tmp;
+		ast_module_ref(ast_module_info->self);
+		ast_channel_callgroup_set(tmp, i->callgroup);
+		ast_channel_pickupgroup_set(tmp, i->pickupgroup);
+		ast_channel_call_forward_set(tmp, i->call_forward);
+		ast_channel_context_set(tmp, i->context);
+		ast_channel_exten_set(tmp, i->exten);
+
+		/* Don't use ast_set_callerid() here because it will
+		 * generate a needless NewCallerID event */
+		if (!ast_strlen_zero(i->cid_num)) {
+			ast_channel_caller(tmp)->ani.number.valid = 1;
+			ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
+		}
 
-	if (sub->rtp) {
-		ast_jb_configure(tmp, &global_jbconf);
-	}
+		if (!i->adsi) {
+			ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
+		}
+		ast_channel_priority_set(tmp, 1);
 
-	ast_channel_stage_snapshot_done(tmp);
-	ast_channel_unlock(tmp);
+		/* Set channel variables for this call from configuration */
+		for (v = i->chanvars ; v ; v = v->next) {
+			char valuebuf[1024];
+			pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
+		}
 
-	if (state != AST_STATE_DOWN) {
-		if (ast_pbx_start(tmp)) {
-			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
-			ast_hangup(tmp);
-			tmp = NULL;
+		if (sub->rtp) {
+			ast_jb_configure(tmp, &global_jbconf);
+		}
+		if (state != AST_STATE_DOWN) {
+			if (ast_pbx_start(tmp)) {
+				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+				ast_hangup(tmp);
+				tmp = NULL;
+			}
 		}
+		ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
+				ast_channel_name(tmp), ast_state2str(state));
+	} else {
+		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
 	}
-	ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
-			ast_channel_name(tmp), ast_state2str(state));
-
 	return tmp;
 }
 
@@ -1994,9 +1967,7 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
 	int codec, codec_count=0;
 	int iterator;
 	struct mgcp_endpoint *p = sub->parent;
-	struct ast_str *global_buf = ast_str_alloca(64);
-	struct ast_str *peer_buf = ast_str_alloca(64);
-	struct ast_str *pvt_buf = ast_str_alloca(64);
+	char tmp1[256], tmp2[256], tmp3[256];
 
 	/* Get codec and RTP info from SDP */
 	m = get_sdp(req, "m");
@@ -2053,20 +2024,20 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
 	}
 
 	/* Now gather all of the codecs that were asked for: */
-	if (!(peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(peercap = ast_format_cap_alloc_nolock())) {
 		return -1;
 	}
 	ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), peercap, &peerNonCodecCapability);
-	ast_format_cap_get_compatible(global_capability, peercap, p->cap);
+	ast_format_cap_joint_copy(global_capability, peercap, p->cap);
 	ast_debug(1, "Capabilities: us - %s, them - %s, combined - %s\n",
-		ast_format_cap_get_names(global_capability, &global_buf),
-		ast_format_cap_get_names(peercap, &peer_buf),
-		ast_format_cap_get_names(p->cap, &pvt_buf));
-	ao2_ref(peercap, -1);
+		ast_getformatname_multiple(tmp1, sizeof(tmp1), global_capability),
+		ast_getformatname_multiple(tmp2, sizeof(tmp2), peercap),
+		ast_getformatname_multiple(tmp3, sizeof(tmp3), p->cap));
+	peercap = ast_format_cap_destroy(peercap);
 
 	ast_debug(1, "Non-codec capabilities: us - %d, them - %d, combined - %d\n",
 		nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
-	if (!ast_format_cap_count(p->cap)) {
+	if (ast_format_cap_is_empty(p->cap)) {
 		ast_log(LOG_WARNING, "No compatible codecs!\n");
 		return -1;
 	}
@@ -2224,6 +2195,7 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc
 	char m[256] = "";
 	char a[1024] = "";
 	int x;
+	struct ast_format tmpfmt;
 	struct sockaddr_in dest = { 0, };
 	struct ast_sockaddr dest_tmp;
 	struct mgcp_endpoint *p = sub->parent;
@@ -2258,25 +2230,24 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc
 	ast_copy_string(t, "t=0 0\r\n", sizeof(t));
 	snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
 
-	for (x = 0; x < ast_format_cap_count(p->cap); x++) {
-		struct ast_format *format = ast_format_cap_get_format(p->cap, x);
-
-		if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) {
-			ao2_ref(format, -1);
+	ast_format_cap_iter_start(p->cap);
+	while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
+		if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
+			/* Audio is now discontiguous */
 			continue;
 		}
-
-		ast_debug(1, "Answering with capability %s\n", ast_format_get_name(format));
-		codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, format, 0);
-		if (codec > -1) {
-			snprintf(costr, sizeof(costr), " %d", codec);
-			strncat(m, costr, sizeof(m) - strlen(m) - 1);
-			snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
-			strncat(a, costr, sizeof(a) - strlen(a) - 1);
+		if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
+			ast_debug(1, "Answering with capability %s\n", ast_getformatname(&tmpfmt));
+			codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, &tmpfmt, 0);
+			if (codec > -1) {
+				snprintf(costr, sizeof(costr), " %d", codec);
+				strncat(m, costr, sizeof(m) - strlen(m) - 1);
+				snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
+				strncat(a, costr, sizeof(a) - strlen(a) - 1);
+			}
 		}
-
-		ao2_ref(format, -1);
 	}
+	ast_format_cap_iter_end(p->cap);
 
 	for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
 		if (p->nonCodecCapability & x) {
@@ -2315,7 +2286,7 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_
 	char local[256];
 	char tmp[80];
 	struct mgcp_endpoint *p = sub->parent;
-	int i;
+	struct ast_format tmpfmt;
 	struct ast_sockaddr sub_tmpdest_tmp;
 	unsigned int oseq;
 
@@ -2327,20 +2298,18 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_
 		return 0;
 	}
 	ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));
-
-	for (i = 0; i < ast_format_cap_count(p->cap); i++) {
-		struct ast_format *format = ast_format_cap_get_format(p->cap, i);
-
-		if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) {
-			ao2_ref(format, -1);
+	ast_format_cap_iter_start(p->cap);
+	while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
+		if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
+			/* Audio is now discontiguous */
 			continue;
 		}
-
-		snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
-		strncat(local, tmp, sizeof(local) - strlen(local) - 1);
-
-		ao2_ref(format, -1);
+		if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
+			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
+			strncat(local, tmp, sizeof(local) - strlen(local) - 1);
+		}
 	}
+	ast_format_cap_iter_end(p->cap);
 
 	if (sub->gate) {
 		if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) {
@@ -2376,7 +2345,7 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
 	struct mgcp_request resp;
 	char local[256];
 	char tmp[80];
-	int i;
+	struct ast_format tmpfmt;
 	struct mgcp_endpoint *p = sub->parent;
 	unsigned int oseq;
 
@@ -2385,19 +2354,18 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
 
 	ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));
 
-	for (i = 0; i < ast_format_cap_count(p->cap); i++) {
-		struct ast_format *format = ast_format_cap_get_format(p->cap, i);
-
-		if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) {
-			ao2_ref(format, -1);
+	ast_format_cap_iter_start(p->cap);
+	while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
+		if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
+			/* Audio is now discontiguous */
 			continue;
 		}
-
-		snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
-		strncat(local, tmp, sizeof(local) - strlen(local) - 1);
-
-		ao2_ref(format, -1);
+		if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
+			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
+			strncat(local, tmp, sizeof(local) - strlen(local) - 1);
+		}
 	}
+	ast_format_cap_iter_end(p->cap);
 
 	if (sub->gate) {
 		if(sub->gate->state == GATE_ALLOCATED) {
@@ -2473,23 +2441,22 @@ static int mgcp_alloc_pktcgate(struct mgcp_subchannel *sub)
 static int transmit_connect(struct mgcp_subchannel *sub)
 {
 	struct mgcp_request resp;
-	int x;
 	char local[256];
 	char tmp[80];
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 	struct mgcp_endpoint *p = sub->parent;
 	unsigned int oseq;
 
 	ast_copy_string(local, "p:20, s:off, e:on", sizeof(local));
 
-	for (x = 0; x < ast_format_cap_count(p->cap); x++) {
-		tmpfmt = ast_format_cap_get_format(p->cap, x);
-
-		snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, tmpfmt, 0, 0));
-		strncat(local, tmp, sizeof(local) - strlen(local) - 1);
-
-		ao2_ref(tmpfmt, -1);
+	ast_format_cap_iter_start(p->cap);
+	while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
+		if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
+			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
+			strncat(local, tmp, sizeof(local) - strlen(local) - 1);
+		}
 	}
+	ast_format_cap_iter_end(p->cap);
 
 	ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
 		    p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
@@ -2584,7 +2551,7 @@ static int transmit_modify_request(struct mgcp_subchannel *sub)
 {
 	struct mgcp_request resp;
 	struct mgcp_endpoint *p = sub->parent;
-	int i;
+	struct ast_format tmpfmt;
 	int fc = 1;
 	char local[256];
 	char tmp[80];
@@ -2599,22 +2566,18 @@ static int transmit_modify_request(struct mgcp_subchannel *sub)
 		p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
 
 	ast_copy_string(local, "", sizeof(local));
-	for (i = 0; i < ast_format_cap_count(p->cap); i++) {
-		struct ast_format *format = ast_format_cap_get_format(p->cap, i);
-
+	ast_format_cap_iter_start(p->cap);
+	while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
 		if (p->ncs && !fc) {
-			ast_format_cap_remove_by_type(p->cap, AST_MEDIA_TYPE_UNKNOWN);
-			ast_format_cap_append(p->cap, format, 0); /* sb5120e bug */
-			ao2_ref(format, -1);
+			ast_format_cap_set(p->cap, &tmpfmt); /* sb5120e bug */
 			break;
 		} else {
 			fc = 0;
-			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
+			snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
 		}
 		strncat(local, tmp, sizeof(local) - strlen(local) - 1);
-
-		ao2_ref(format, -1);
 	}
+	ast_format_cap_iter_end(p->cap);
 
 	if (!sub->sdpsent) {
 		if (sub->gate) {
@@ -3019,21 +2982,9 @@ static void *mgcp_ss(void *data)
 	int res= 0;
 	int getforward = 0;
 	int loop_pause = 100;
-	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-	const char *pickupexten;
 
 	len = strlen(p->dtmf_buf);
 
-	ast_channel_lock(chan);
-	pickup_cfg = ast_get_chan_features_pickup_config(chan);
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-		pickupexten = "";
-	} else {
-		pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-	}
-	ast_channel_unlock(chan);
-
 	while (len < AST_MAX_EXTENSION - 1) {
 		ast_debug(1, "Dtmf buffer '%s' for '%s@%s'\n", p->dtmf_buf, p->name, p->parent->name);
 		res = 1;  /* Assume that we will get a digit */
@@ -3081,7 +3032,6 @@ static void *mgcp_ss(void *data)
 				} else {
 					/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
 					ast_indicate(chan, -1);
-					ast_channel_lock(chan);
 					ast_channel_exten_set(chan, p->dtmf_buf);
 					ast_channel_dialed(chan)->number.str = ast_strdup(p->dtmf_buf);
 					memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
@@ -3090,7 +3040,7 @@ static void *mgcp_ss(void *data)
 						p->hidecallerid ? "" : p->cid_name,
 						ast_channel_caller(chan)->ani.number.valid ? NULL : p->cid_num);
 					ast_setstate(chan, AST_STATE_RING);
-					ast_channel_unlock(chan);
+					/*dahdi_enable_ec(p);*/
 					if (p->dtmfmode & MGCP_DTMF_HYBRID) {
 						p->dtmfmode |= MGCP_DTMF_INBAND;
 						ast_indicate(chan, -1);
@@ -3126,7 +3076,7 @@ static void *mgcp_ss(void *data)
 			len = 0;
 			memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
 			timeout = firstdigittimeout;
-		} else if (!strcmp(p->dtmf_buf, pickupexten)) {
+		} else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
 			/* Scan all channels and see if any there
 			 * ringing channqels with that have call groups
 			 * that equal this channels pickup group
@@ -3190,17 +3140,13 @@ static void *mgcp_ss(void *data)
 			getforward = 0;
 			memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
 			len = 0;
-		} else if (ast_parking_provider_registered() && ast_parking_is_exten_park(ast_channel_context(chan), p->dtmf_buf) &&
-			sub->next->owner) {
-			RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+		} else if (ast_parking_ext_valid(p->dtmf_buf, chan, ast_channel_context(chan)) &&
+			sub->next->owner && ast_bridged_channel(sub->next->owner)) {
 			/* This is a three way call, the main call being a real channel,
-				and we're parking the first call. */
-			ast_channel_lock(chan);
-			bridge_channel = ast_channel_get_bridge_channel(chan);
-			ast_channel_unlock(chan);
-			if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf, NULL, NULL)) {
-				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
-			}
+			   and we're parking the first call. */
+			ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan,
+				p->dtmf_buf, ast_channel_context(chan), 0, NULL);
+			ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
 			break;
 		} else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
 			ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
@@ -3278,55 +3224,57 @@ static void *mgcp_ss(void *data)
 	return NULL;
 }
 
-/*! \brief Complete an attended transfer
- *
- * \param p The endpoint performing the attended transfer
- * \param sub The sub-channel completing the attended transfer
- *
- * \note p->sub is the currently active sub-channel (the channel the phone is using)
- * \note p->sub->next is the sub-channel not in use, potentially on hold
- *
- * \retval 0 when channel should be hung up
- * \retval 1 when channel should not be hung up
- */
-static int attempt_transfer(struct mgcp_endpoint *p, struct mgcp_subchannel *sub)
+static int attempt_transfer(struct mgcp_endpoint *p)
 {
-	enum ast_transfer_result res;
-
-	/* Ensure that the other channel goes off hold and that it is indicating properly */
-	ast_queue_unhold(sub->next->owner);
-	if (ast_channel_state(sub->owner) == AST_STATE_RINGING) {
-		ast_queue_control(sub->next->owner, AST_CONTROL_RINGING);
-	}
-
-	ast_mutex_unlock(&p->sub->next->lock);
-	ast_mutex_unlock(&p->sub->lock);
-	res = ast_bridge_transfer_attended(sub->owner, sub->next->owner);
-
-	/* Subs are only freed when the endpoint itself is destroyed, so they will continue to exist
-	 * after ast_bridge_transfer_attended returns making this safe without reference counting
-	 */
-	ast_mutex_lock(&p->sub->lock);
-	ast_mutex_lock(&p->sub->next->lock);
-
-	if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		/* If transferring fails hang up the other channel if present and us */
-		if (sub->next->owner) {
-			ast_channel_softhangup_internal_flag_add(sub->next->owner, AST_SOFTHANGUP_DEV);
-			mgcp_queue_hangup(sub->next);
+	/* *************************
+	 * I hope this works.
+	 * Copied out of chan_zap
+	 * Cross your fingers
+	 * *************************/
+
+	/* In order to transfer, we need at least one of the channels to
+	   actually be in a call bridge.  We can't conference two applications
+	   together (but then, why would we want to?) */
+	if (ast_bridged_channel(p->sub->owner)) {
+		/* The three-way person we're about to transfer to could still be in MOH, so
+		   stop if now if appropriate */
+		if (ast_bridged_channel(p->sub->next->owner))
+			ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
+		if (ast_channel_state(p->sub->owner) == AST_STATE_RINGING) {
+			ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
 		}
-		sub->next->alreadygone = 1;
-		return 0;
-	}
-
-	unalloc_sub(sub->next);
-
-	/* If the active sub is NOT the one completing the transfer change it to be, and hang up the other sub */
-	if (p->sub != sub) {
-		p->sub = sub;
+		if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+				ast_channel_name(ast_bridged_channel(p->sub->owner)), ast_channel_name(p->sub->next->owner));
+			return -1;
+		}
+		/* Orphan the channel */
+		unalloc_sub(p->sub->next);
+	} else if (ast_bridged_channel(p->sub->next->owner)) {
+		if (ast_channel_state(p->sub->owner) == AST_STATE_RINGING) {
+			ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
+		}
+		ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
+		if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+				ast_channel_name(ast_bridged_channel(p->sub->next->owner)), ast_channel_name(p->sub->owner));
+			return -1;
+		}
+		/*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
+		ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
+		p->sub = p->sub->next;
+		unalloc_sub(p->sub->next);
+		/* Tell the caller not to hangup */
 		return 1;
+	} else {
+		ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+			ast_channel_name(p->sub->owner), ast_channel_name(p->sub->next->owner));
+		ast_channel_softhangup_internal_flag_add(p->sub->next->owner, AST_SOFTHANGUP_DEV);
+		if (p->sub->next->owner) {
+			p->sub->next->alreadygone = 1;
+			mgcp_queue_hangup(p->sub->next);
+		}
 	}
-
 	return 0;
 }
 
@@ -3340,7 +3288,8 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
 	if (sub->outgoing) {
 		/* Answered */
 		if (sub->owner) {
-			ast_queue_unhold(sub->owner);
+			if (ast_bridged_channel(sub->owner))
+				ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
 			sub->cxmode = MGCP_CX_SENDRECV;
 			if (!sub->rtp) {
 				start_rtp(sub);
@@ -3367,7 +3316,7 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
 #else
 				transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
 #endif
-				c = mgcp_new(sub, AST_STATE_RING, NULL, NULL);
+				c = mgcp_new(sub, AST_STATE_RING, NULL);
 				if (!c) {
 					ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
 					transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
@@ -3379,7 +3328,7 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
 				} else {
 					transmit_notify_request(sub, "L/dl");
 				}
-				c = mgcp_new(sub, AST_STATE_DOWN, NULL, NULL);
+				c = mgcp_new(sub, AST_STATE_DOWN, NULL);
 				if (c) {
 					if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
 						ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
@@ -3396,7 +3345,8 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
 				ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
 				ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
 			}
-			ast_queue_unhold(sub->owner);
+			if (ast_bridged_channel(sub->owner))
+				ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
 			sub->cxmode = MGCP_CX_SENDRECV;
 			if (!sub->rtp) {
 				start_rtp(sub);
@@ -3513,20 +3463,20 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
 					sub->cxmode = MGCP_CX_MUTE;
 					ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
 					transmit_modify_request(sub);
-					if (sub->owner) {
-						ast_queue_hold(sub->owner, NULL);
-					}
+					if (sub->owner && ast_bridged_channel(sub->owner))
+						ast_queue_control(sub->owner, AST_CONTROL_HOLD);
 					sub->next->cxmode = MGCP_CX_RECVONLY;
 					handle_hd_hf(sub->next, ev);
 				} else if (sub->owner && sub->next->owner) {
 					/* We've got two active calls lets decide whether or not to conference or just flip flop */
 					if ((!sub->outgoing) && (!sub->next->outgoing)) {
-						/* We made both calls lets conference */
+						/* We made both calls lets conferenct */
 						ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
 								sub->id, sub->next->id, p->name, p->parent->name);
 						sub->cxmode = MGCP_CX_CONF;
 						sub->next->cxmode = MGCP_CX_CONF;
-						ast_queue_unhold(sub->next->owner);
+						if (ast_bridged_channel(sub->next->owner))
+							ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
 						transmit_modify_request(sub);
 						transmit_modify_request(sub->next);
 					} else {
@@ -3538,9 +3488,11 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
 						sub->cxmode = MGCP_CX_MUTE;
 						ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
 						transmit_modify_request(sub);
+						if (ast_bridged_channel(sub->owner))
+							ast_queue_control(sub->owner, AST_CONTROL_HOLD);
 
-						ast_queue_hold(sub->owner, NULL);
-						ast_queue_hold(sub->next->owner, NULL);
+						if (ast_bridged_channel(sub->next->owner))
+							ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
 
 						handle_hd_hf(sub->next, ev);
 					}
@@ -3555,7 +3507,8 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
 						/* XXX - What do we do now? */
 						return -1;
 					}
-					ast_queue_unhold(p->sub->owner);
+					if (ast_bridged_channel(p->sub->owner))
+						ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
 					p->sub->cxmode = MGCP_CX_SENDRECV;
 					transmit_modify_request(p->sub);
 				}
@@ -3576,8 +3529,13 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
 				/* We're allowed to transfer, we have two avtive calls and */
 				/* we made at least one of the calls.  Let's try and transfer */
 				ast_mutex_lock(&p->sub->next->lock);
-				res = attempt_transfer(p, sub);
-				if (res) {
+				res = attempt_transfer(p);
+				if (res < 0) {
+					if (p->sub->next->owner) {
+						sub->next->alreadygone = 1;
+						mgcp_queue_hangup(sub->next);
+					}
+				} else if (res) {
 					ast_log(LOG_WARNING, "Transfer attempt failed\n");
 					ast_mutex_unlock(&p->sub->next->lock);
 					return -1;
@@ -3973,16 +3931,14 @@ static int restart_monitor(void)
 	return 0;
 }
 
-static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause)
+static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause)
 {
 	struct mgcp_subchannel *sub;
 	struct ast_channel *tmpc = NULL;
 	char tmp[256];
 
-	if (!(ast_format_cap_iscompatible(cap, global_capability))) {
-		struct ast_str *cap_buf = ast_str_alloca(64);
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
-			ast_format_cap_get_names(cap, &cap_buf));
+	if (!(ast_format_cap_has_joint(cap, global_capability))) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 		/*return NULL;*/
 	}
 	ast_copy_string(tmp, dest, sizeof(tmp));
@@ -4014,7 +3970,7 @@ static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap
 		ast_mutex_unlock(&sub->lock);
 		return NULL;
 	}
-	tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN, assignedids, requestor);
+	tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
 	ast_mutex_unlock(&sub->lock);
 	if (!tmpc)
 		ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
@@ -4140,7 +4096,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 		} else if (!strcasecmp(v->name, "accountcode")) {
 			ast_copy_string(accountcode, v->value, sizeof(accountcode));
 		} else if (!strcasecmp(v->name, "amaflags")) {
-			y = ast_channel_string2amaflag(v->value);
+			y = ast_cdr_amaflags2int(v->value);
 			if (y < 0) {
 				ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
 			} else {
@@ -4173,15 +4129,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 			ast_copy_string(mailbox, v->value, sizeof(mailbox));
 		} else if (!strcasecmp(v->name, "hasvoicemail")) {
 			if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
-				/*
-				 * hasvoicemail is a users.conf legacy voicemail enable method.
-				 * hasvoicemail is only going to work for app_voicemail mailboxes.
-				 */
-				if (strchr(gw->name, '@')) {
-					ast_copy_string(mailbox, gw->name, sizeof(mailbox));
-				} else {
-					snprintf(mailbox, sizeof(mailbox), "%s at default", gw->name);
-				}
+				ast_copy_string(mailbox, gw->name, sizeof(mailbox));
 			}
 		} else if (!strcasecmp(v->name, "adsi")) {
 			adsi = ast_true(v->value);
@@ -4218,7 +4166,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 					ast_mutex_init(&e->lock);
 					ast_mutex_init(&e->rqnt_queue_lock);
 					ast_mutex_init(&e->cmd_queue_lock);
-					e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+					e->cap = ast_format_cap_alloc_nolock();
 					ast_copy_string(e->name, v->value, sizeof(e->name));
 					e->needaudit = 1;
 				}
@@ -4233,17 +4181,22 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 				ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
 				ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
 				if (!ast_strlen_zero(e->mailbox)) {
-					struct stasis_topic *mailbox_specific_topic;
-
-					mailbox_specific_topic = ast_mwi_topic(e->mailbox);
-					if (mailbox_specific_topic) {
-						e->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
+					char *mbox, *cntx;
+					cntx = mbox = ast_strdupa(e->mailbox);
+					strsep(&cntx, "@");
+					if (ast_strlen_zero(cntx)) {
+						cntx = "default";
 					}
+					e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "MGCP MWI subscription", NULL,
+						AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
+						AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
+						AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+						AST_EVENT_IE_END);
 				}
 				snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", (unsigned long)ast_random());
 				e->msgstate = -1;
 				e->amaflags = amaflags;
-				ast_format_cap_append_from_cap(e->cap, global_capability, AST_MEDIA_TYPE_UNKNOWN);
+				ast_format_cap_copy(e->cap, global_capability);
 				e->parent = gw;
 				e->ncs = ncs;
 				e->dtmfmode = dtmfmode;
@@ -4325,7 +4278,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 					ast_mutex_init(&e->lock);
 					ast_mutex_init(&e->rqnt_queue_lock);
 					ast_mutex_init(&e->cmd_queue_lock);
-					e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+					e->cap = ast_format_cap_alloc_nolock();
 					ast_copy_string(e->name, v->value, sizeof(e->name));
 					e->needaudit = 1;
 				}
@@ -4347,7 +4300,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 					e->parent = gw;
 				}
 				e->amaflags = amaflags;
-				ast_format_cap_append_from_cap(e->cap, global_capability, AST_MEDIA_TYPE_UNKNOWN);
+				ast_format_cap_copy(e->cap, global_capability);
 				e->dtmfmode = dtmfmode;
 				e->ncs = ncs;
 				e->pktcgatealloc = pktcgatealloc;
@@ -4503,8 +4456,7 @@ static void mgcp_get_codec(struct ast_channel *chan, struct ast_format_cap *resu
 {
 	struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan);
 	struct mgcp_endpoint *p = sub->parent;
-
-	ast_format_cap_append_from_cap(result, p->cap, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(result, p->cap);
 }
 
 static struct ast_rtp_glue mgcp_rtp_glue = {
@@ -4578,9 +4530,8 @@ static void destroy_endpoint(struct mgcp_endpoint *e)
 		ast_free(s);
 	}
 
-	if (e->mwi_event_sub) {
-		e->mwi_event_sub = stasis_unsubscribe(e->mwi_event_sub);
-	}
+	if (e->mwi_event_sub)
+		ast_event_unsubscribe(e->mwi_event_sub);
 
 	if (e->chanvars) {
 		ast_variables_destroy(e->chanvars);
@@ -4590,7 +4541,7 @@ static void destroy_endpoint(struct mgcp_endpoint *e)
 	ast_mutex_destroy(&e->lock);
 	ast_mutex_destroy(&e->rqnt_queue_lock);
 	ast_mutex_destroy(&e->cmd_queue_lock);
-	ao2_ref(e->cap, -1);
+	e->cap = ast_format_cap_destroy(e->cap);
 	ast_free(e);
 }
 
@@ -4688,8 +4639,9 @@ static int reload_config(int reload)
 	char *cat;
 	struct ast_hostent ahp;
 	struct hostent *hp;
+	struct ast_format format;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
+	
 	if (gethostname(ourhost, sizeof(ourhost)-1)) {
 		ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
 		return 0;
@@ -4727,9 +4679,19 @@ static int reload_config(int reload)
 				memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
 			}
 		} else if (!strcasecmp(v->name, "allow")) {
-			ast_format_cap_update_by_allow_disallow(global_capability, v->value, 1);
+			ast_getformatbyname(v->value, &format);
+			if (!format.id) {
+				ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
+			} else {
+				ast_format_cap_add(global_capability, &format);
+			}
 		} else if (!strcasecmp(v->name, "disallow")) {
-			ast_format_cap_update_by_allow_disallow(global_capability, v->value, 0);
+			ast_getformatbyname(v->value, &format);
+			if (!format.id) {
+				ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
+			} else {
+				ast_format_cap_remove(global_capability, &format);
+			}
 		} else if (!strcasecmp(v->name, "tos")) {
 			if (ast_str2tos(v->value, &qos.tos)) {
 			    ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
@@ -4842,56 +4804,39 @@ static int reload_config(int reload)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief  load_module: PBX load module - initialization ---*/
 static int load_module(void)
 {
-	if (!(global_capability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	struct ast_format tmpfmt;
+
+	if (!(global_capability = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	if (!(mgcp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ao2_ref(global_capability, -1);
+	if (!(mgcp_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_format_cap_append(global_capability, ast_format_ulaw, 0);
-	ast_format_cap_append(mgcp_tech.capabilities, ast_format_ulaw, 0);
-	ast_format_cap_append(mgcp_tech.capabilities, ast_format_alaw, 0);
+	ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
 	if (!(sched = ast_sched_context_create())) {
 		ast_log(LOG_WARNING, "Unable to create schedule context\n");
-		ao2_ref(global_capability, -1);
-		ao2_ref(mgcp_tech.capabilities, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
 	if (!(io = io_context_create())) {
 		ast_log(LOG_WARNING, "Unable to create I/O context\n");
 		ast_sched_context_destroy(sched);
-		ao2_ref(global_capability, -1);
-		ao2_ref(mgcp_tech.capabilities, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (reload_config(0)) {
-		ao2_ref(global_capability, -1);
-		ao2_ref(mgcp_tech.capabilities, -1);
+	if (reload_config(0))
 		return AST_MODULE_LOAD_DECLINE;
-	}
 
 	/* Make sure we can register our mgcp channel type */
 	if (ast_channel_register(&mgcp_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
 		io_context_destroy(io);
 		ast_sched_context_destroy(sched);
-		ao2_ref(global_capability, -1);
-		ao2_ref(mgcp_tech.capabilities, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -4999,21 +4944,20 @@ static int unload_module(void)
 		return -1;
 	}
 
-	close(mgcpsock);
+	if (mgcpsock > -1) {
+		close(mgcpsock);
+	}
 	ast_rtp_glue_unregister(&mgcp_rtp_glue);
 	ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
 	ast_sched_context_destroy(sched);
 
-	ao2_ref(global_capability, -1);
-	global_capability = NULL;
-	ao2_ref(mgcp_tech.capabilities, -1);
-	mgcp_tech.capabilities = NULL;
+	global_capability = ast_format_cap_destroy(global_capability);
+	mgcp_tech.capabilities = ast_format_cap_destroy(mgcp_tech.capabilities);
 
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Media Gateway Control Protocol (MGCP)",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 95ca173..6cab76b 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -24,19 +24,11 @@
  *
  * \author Christian Richter <crich at beronet.com>
  *
- * MISDN http://www.misdn.org/
+ * \extref MISDN http://www.misdn.org/
  *
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_misdn.c uses the configuration file \ref misdn.conf
- * \addtogroup configuration_file
- */
-
-/*! \page misdn.conf misdn.conf
- * \verbinclude misdn.conf.sample
- */
-
 /*!
  * \note
  * To use the CCBS/CCNR supplementary service feature and other
@@ -57,21 +49,6 @@
 /* Define to enable cli commands to generate canned CCBS messages. */
 // #define CCBS_TEST_MESSAGES	1
 
-/*
- * XXX The mISDN channel driver needs its native bridge code
- * converted to the new bridge technology scheme.  The
- * chan_dahdi native bridge code can be used as an example.  It
- * is unlikely that this will ever get done.  Support for this
- * channel driver is dwindling because the supported version of
- * mISDN does not support newer kernels.
- *
- * Without native bridge support, the following config file
- * parameters have no effect: bridging.
- *
- * The existing native bridge code is marked with the
- * mISDN_NATIVE_BRIDGING conditional.
- */
-
 /*** MODULEINFO
 	<depend>isdnnet</depend>
 	<depend>misdn</depend>
@@ -81,7 +58,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <pthread.h>
 #include <sys/socket.h>
@@ -117,10 +94,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
 #include "asterisk/causes.h"
 #include "asterisk/format.h"
 #include "asterisk/format_cap.h"
-#include "asterisk/features_config.h"
-#include "asterisk/bridge.h"
-#include "asterisk/pickup.h"
-#include "asterisk/format_cache.h"
 
 #include "chan_misdn_config.h"
 #include "isdn_lib.h"
@@ -676,7 +649,7 @@ static int *misdn_ports;
 static void chan_misdn_log(int level, int port, char *tmpl, ...)
 	__attribute__((format(printf, 3, 4)));
 
-static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int port, int c);
+static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const char *linkedid, int port, int c);
 static void send_digit_to_chan(struct chan_list *cl, char digit);
 
 static int pbx_start_chan(struct chan_list *ch);
@@ -692,6 +665,9 @@ static const char misdn_type[] = "mISDN";
 
 static int tracing = 0;
 
+/*! \brief Only alaw and mulaw is allowed for now */
+static struct ast_format prefformat; /*  AST_FORMAT_SLINEAR ;  AST_FORMAT_ULAW | */
+
 static int *misdn_debug;
 static int *misdn_debug_only;
 static int max_ports;
@@ -763,7 +739,6 @@ static int misdn_chan_is_valid(struct chan_list *ch)
 	return 0;
 }
 
-#if defined(mISDN_NATIVE_BRIDGING)
 /*! Returns a reference to the found chan_list. */
 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
 {
@@ -781,7 +756,6 @@ static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
 
 	return NULL;
 }
-#endif	/* defined(mISDN_NATIVE_BRIDGING) */
 
 /*! Returns a reference to the found chan_list. */
 static struct chan_list *get_chan_by_ast_name(const char *name)
@@ -3458,7 +3432,6 @@ static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type
 
 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
 {
-	RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
 	char buf[128];
 
 	if (!bc->AOCD_need_export || !ast) {
@@ -3466,48 +3439,46 @@ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misd
 	}
 
 	if (originator == ORG_AST) {
-		chan = ast_channel_bridge_peer(ast);
-		if (!chan) {
+		ast = ast_bridged_channel(ast);
+		if (!ast) {
 			return;
 		}
-	} else {
-		chan = ast_channel_ref(ast);
 	}
 
 	switch (bc->AOCDtype) {
 	case Fac_AOCDCurrency:
-		pbx_builtin_setvar_helper(chan, "AOCD_Type", "currency");
+		pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
 		if (bc->AOCD.currency.chargeNotAvailable) {
-			pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
+			pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
 		} else {
-			pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
+			pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
 			if (bc->AOCD.currency.freeOfCharge) {
-				pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
+				pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
 			} else {
-				pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
+				pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
 				if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
-					pbx_builtin_setvar_helper(chan, "AOCD_Amount", buf);
+					pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
 					if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
-						pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
+						pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
 					}
 				}
 			}
 		}
 		break;
 	case Fac_AOCDChargingUnit:
-		pbx_builtin_setvar_helper(chan, "AOCD_Type", "charging_unit");
+		pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
 		if (bc->AOCD.chargingUnit.chargeNotAvailable) {
-			pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
+			pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
 		} else {
-			pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
+			pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
 			if (bc->AOCD.chargingUnit.freeOfCharge) {
-				pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
+				pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
 			} else {
-				pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
+				pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
 				if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
-					pbx_builtin_setvar_helper(chan, "AOCD_RecordedUnits", buf);
+					pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
 					if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
-						pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
+						pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
 					}
 				}
 			}
@@ -5952,9 +5923,7 @@ static int read_config(struct chan_list *ch)
 	chan_misdn_log(1, port, "read_config: Getting Config\n");
 
 	misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
-	ast_channel_lock(ast);
 	ast_channel_language_set(ast, lang);
-	ast_channel_unlock(ast);
 
 	misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
 
@@ -6000,9 +5969,7 @@ static int read_config(struct chan_list *ch)
 
 	misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
 
-	ast_channel_lock(ast);
 	ast_channel_context_set(ast, ch->context);
-	ast_channel_unlock(ast);
 
 #ifdef MISDN_1_2
 	update_pipeline_config(bc);
@@ -6019,10 +5986,8 @@ static int read_config(struct chan_list *ch)
 	misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
 	misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
 	chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
-	ast_channel_lock(ast);
 	ast_channel_pickupgroup_set(ast, pg);
 	ast_channel_callgroup_set(ast, cg);
-	ast_channel_unlock(ast);
 
 	misdn_cfg_get(port, MISDN_CFG_NAMEDPICKUPGROUP, &npg, sizeof(npg));
 	misdn_cfg_get(port, MISDN_CFG_NAMEDCALLGROUP, &ncg, sizeof(ncg));
@@ -6035,10 +6000,8 @@ static int read_config(struct chan_list *ch)
 		ast_free(tmp_str);
 	}
 
-	ast_channel_lock(ast);
 	ast_channel_named_pickupgroups_set(ast, npg);
 	ast_channel_named_callgroups_set(ast, ncg);
-	ast_channel_unlock(ast);
 
 	if (ch->originator == ORG_AST) {
 		char callerid[BUFFERSIZE + 1];
@@ -6092,9 +6055,7 @@ static int read_config(struct chan_list *ch)
 		/* Add configured prefix to dialed.number */
 		misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
 
-		ast_channel_lock(ast);
 		ast_channel_exten_set(ast, bc->dialed.number);
-		ast_channel_unlock(ast);
 
 		misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
 		ast_mutex_init(&ch->overlap_tv_lock);
@@ -6421,7 +6382,7 @@ static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct as
 		bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
 	}
 
-	bc->redirecting.reason = ast_to_misdn_reason(ast_channel_redirecting(ast)->reason.code);
+	bc->redirecting.reason = ast_to_misdn_reason(ast_channel_redirecting(ast)->reason);
 	bc->redirecting.count = ast_channel_redirecting(ast)->count;
 }
 
@@ -6465,7 +6426,7 @@ static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct
 		| misdn_to_ast_screen(redirect->to.screening);
 	redirecting.to.tag = tag;
 
-	redirecting.reason.code = misdn_to_ast_reason(redirect->reason);
+	redirecting.reason = misdn_to_ast_reason(redirect->reason);
 	redirecting.count = redirect->count;
 
 	ast_channel_set_redirecting(ast, &redirecting, &update_redirecting);
@@ -7108,7 +7069,6 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
 		chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
 		/* fallthrough */
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 		return -1;
 	}
 
@@ -7435,7 +7395,7 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
 	}
 
 	tmp->frame.frametype = AST_FRAME_VOICE;
-	tmp->frame.subclass.format = ast_format_alaw;
+	ast_format_set(&tmp->frame.subclass.format, AST_FORMAT_ALAW, 0);
 	tmp->frame.datalen = len;
 	tmp->frame.samples = len;
 	tmp->frame.mallocd = 0;
@@ -7500,14 +7460,13 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
 	}
 
 
-	if (!frame->subclass.format) {
+	if (!frame->subclass.format.id) {
 		chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
 		return 0;
 	}
 
-	if (ast_format_cmp(frame->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL) {
-		chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n",
-			ast_format_get_name(frame->subclass.format));
+	if (ast_format_cmp(&frame->subclass.format, &prefformat) == AST_FORMAT_CMP_NOT_EQUAL) {
+		chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", ast_getformatname(&frame->subclass.format));
 		return 0;
 	}
 
@@ -7541,7 +7500,7 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
 		ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
 
 		for (i = 0; i < max; i++) {
-			ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]);
+			ast_debug(1, "%02hhx ", ((unsigned char *) frame->data.ptr)[i]);
 		}
 	}
 #endif
@@ -7584,7 +7543,6 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
 	return 0;
 }
 
-#if defined(mISDN_NATIVE_BRIDGING)
 static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
 	struct ast_channel *c1, int flags,
 	struct ast_frame **fo,
@@ -7598,20 +7556,14 @@ static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
 	int p1_b, p2_b;
 	int bridging;
 
-	misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
-	if (!bridging) {
-		/* Native mISDN bridging globally disabled. */
-		return AST_BRIDGE_FAILED_NOWARN;
-	}
-
 	ch1 = get_chan_by_ast(c0);
 	if (!ch1) {
-		return AST_BRIDGE_FAILED;
+		return -1;
 	}
 	ch2 = get_chan_by_ast(c1);
 	if (!ch2) {
 		chan_list_unref(ch1, "Failed to find ch2");
-		return AST_BRIDGE_FAILED;
+		return -1;
 	}
 
 	carr[0] = c0;
@@ -7619,16 +7571,20 @@ static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
 
 	misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
 	misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));
-	if (!p1_b || !p2_b) {
+
+	if (! p1_b || ! p2_b) {
 		ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
 		chan_list_unref(ch1, "Bridge fallback ch1");
 		chan_list_unref(ch2, "Bridge fallback ch2");
-		return AST_BRIDGE_FAILED_NOWARN;
+		return AST_BRIDGE_FAILED;
 	}
 
-	/* make a mISDN_dsp conference */
-	chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
-	misdn_lib_bridge(ch1->bc, ch2->bc);
+	misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
+	if (bridging) {
+		/* trying to make a mISDN_dsp conference */
+		chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
+		misdn_lib_bridge(ch1->bc, ch2->bc);
+	}
 
 	ast_verb(3, "Native bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
 
@@ -7701,7 +7657,6 @@ static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
 	chan_list_unref(ch2, "Bridge complete ch2");
 	return AST_BRIDGE_COMPLETE;
 }
-#endif	/* defined(mISDN_NATIVE_BRIDGING) */
 
 /** AST INDICATIONS END **/
 
@@ -7853,7 +7808,7 @@ static struct chan_list *chan_list_init(int orig)
 	return cl;
 }
 
-static struct ast_channel *misdn_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *misdn_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	struct ast_channel *ast;
 	char group[BUFFERSIZE + 1] = "";
@@ -8087,7 +8042,7 @@ static struct ast_channel *misdn_request(const char *type, struct ast_format_cap
 	}
 	cl->bc = newbc;
 
-	ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, cap, assignedids, requestor, port, channel);
+	ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, cap, requestor ? ast_channel_linkedid(requestor) : NULL, port, channel);
 	if (!ast) {
 		chan_list_unref(cl, "Failed to create a new channel");
 		misdn_lib_release(newbc);
@@ -8135,6 +8090,24 @@ static struct ast_channel_tech misdn_tech = {
 	.send_digit_begin = misdn_digit_begin,
 	.send_digit_end = misdn_digit_end,
 	.call = misdn_call,
+	.bridge = misdn_bridge,
+	.hangup = misdn_hangup,
+	.answer = misdn_answer,
+	.read = misdn_read,
+	.write = misdn_write,
+	.indicate = misdn_indication,
+	.fixup = misdn_fixup,
+	.send_text = misdn_send_text,
+	.properties = 0,
+};
+
+static struct ast_channel_tech misdn_tech_wo_bridge = {
+	.type = misdn_type,
+	.description = "Channel driver for mISDN Support (Bri/Pri)",
+	.requester = misdn_request,
+	.send_digit_begin = misdn_digit_begin,
+	.send_digit_end = misdn_digit_end,
+	.call = misdn_call,
 	.hangup = misdn_hangup,
 	.answer = misdn_answer,
 	.read = misdn_read,
@@ -8172,20 +8145,15 @@ static void update_name(struct ast_channel *tmp, int port, int c)
 	}
 }
 
-static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int port, int c)
+static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const char *linkedid, int port, int c)
 {
-	struct ast_format_cap *native;
 	struct ast_channel *tmp;
 	char *cid_name = NULL;
 	char *cid_num = NULL;
 	int chan_offset = 0;
 	int tmp_port = misdn_cfg_get_next_port(0);
-	struct ast_format *tmpfmt;
-
-	native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!native) {
-		return NULL;
-	}
+	int bridging;
+	struct ast_format tmpfmt;
 
 	for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
 		if (tmp_port == port) {
@@ -8201,26 +8169,24 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char
 		ast_callerid_parse(callerid, &cid_name, &cid_num);
 	}
 
-	tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", assignedids, requestor, 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
+	tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", linkedid, 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
 	if (tmp) {
 		chan_misdn_log(2, port, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
 
-		tmpfmt = ast_format_cap_get_format(cap, 0);
-		ast_format_cap_append(native, ast_format_alaw, 0);
-		ast_channel_nativeformats_set(tmp, native);
-		ast_channel_set_writeformat(tmp, tmpfmt);
-		ast_channel_set_rawwriteformat(tmp, tmpfmt);
-		ast_channel_set_readformat(tmp, tmpfmt);
-		ast_channel_set_rawreadformat(tmp, tmpfmt);
-
-		ao2_ref(tmpfmt, -1);
+		ast_best_codec(cap, &tmpfmt);
+		ast_format_cap_add(ast_channel_nativeformats(tmp), &prefformat);
+		ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
 
 		/* Link the channel and private together */
 		chan_list_ref(chlist, "Give a reference to ast_channel");
 		MISDN_ASTERISK_TECH_PVT_SET(tmp, chlist);
 		chlist->ast = tmp;
 
-		ast_channel_tech_set(tmp, &misdn_tech);
+		misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
+		ast_channel_tech_set(tmp, bridging ? &misdn_tech : &misdn_tech_wo_bridge);
 
 		ast_channel_priority_set(tmp, 1);
 
@@ -8245,14 +8211,10 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char
 		ast_channel_rings_set(tmp, (state == AST_STATE_RING) ? 1 : 0);
 
 		ast_jb_configure(tmp, misdn_get_global_jbconf());
-
-		ast_channel_unlock(tmp);
 	} else {
 		chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
 	}
 
-	ao2_ref(native, -1);
-
 	return tmp;
 }
 
@@ -8620,9 +8582,10 @@ static void release_chan_early(struct chan_list *ch)
 static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
 {
 	int retval;
-	enum ast_transfer_result xfer_res;
-	struct ast_channel *to_target;
-	struct ast_channel *to_transferee;
+	struct ast_channel *target;
+	struct ast_channel *transferee;
+	struct ast_party_connected_line target_colp;
+	struct ast_party_connected_line transferee_colp;
 
 	switch (active_ch->state) {
 	case MISDN_PROCEEDING:
@@ -8635,24 +8598,59 @@ static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list
 	}
 
 	ast_channel_lock_both(held_ch->ast, active_ch->ast);
-	to_target = active_ch->ast;
-	to_transferee = held_ch->ast;
-	chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
-		ast_channel_name(to_transferee), ast_channel_name(to_target));
-	held_ch->hold.state = MISDN_HOLD_TRANSFER;
-	ast_channel_ref(to_target);
-	ast_channel_ref(to_transferee);
-	ast_channel_unlock(to_target);
-	ast_channel_unlock(to_transferee);
 
-	retval = 0;
-	xfer_res = ast_bridge_transfer_attended(to_transferee, to_target);
-	if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		retval = -1;
+	transferee = ast_bridged_channel(held_ch->ast);
+	if (!transferee) {
+		/*
+		 * Could not transfer.  Held channel is not bridged anymore.
+		 * Held party probably got tired of waiting and hung up.
+		 */
+		ast_channel_unlock(held_ch->ast);
+		ast_channel_unlock(active_ch->ast);
+		return -1;
 	}
 
-	ast_channel_unref(to_target);
-	ast_channel_unref(to_transferee);
+	target = active_ch->ast;
+	chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
+		ast_channel_name(held_ch->ast), ast_channel_name(target));
+
+	ast_party_connected_line_init(&target_colp);
+	ast_party_connected_line_copy(&target_colp, ast_channel_connected(target));
+
+	/* Reset any earlier private connected id representation */
+	ast_party_id_reset(&target_colp.priv);
+
+	ast_party_connected_line_init(&transferee_colp);
+	ast_party_connected_line_copy(&transferee_colp, ast_channel_connected(held_ch->ast));
+
+	/* Reset any earlier private connected id representation*/
+	ast_party_id_reset(&transferee_colp.priv);
+
+	held_ch->hold.state = MISDN_HOLD_TRANSFER;
+
+	/*
+	 * Before starting a masquerade, all channel and pvt locks must
+	 * be unlocked.  Any recursive channel locks held before
+	 * ast_channel_transfer_masquerade() invalidates deadlock
+	 * avoidance.  Since we are unlocking both the pvt and its owner
+	 * channel it is possible for "target" and "transferee" to be
+	 * destroyed by their pbx threads.  To prevent this we must give
+	 * "target" and "transferee" a reference before any unlocking
+	 * takes place.
+	 */
+	ao2_ref(target, +1);
+	ao2_ref(transferee, +1);
+	ast_channel_unlock(held_ch->ast);
+	ast_channel_unlock(active_ch->ast);
+
+	/* Setup transfer masquerade. */
+	retval = ast_channel_transfer_masquerade(target, &target_colp, 0,
+		transferee, &transferee_colp, 1);
+
+	ast_party_connected_line_free(&target_colp);
+	ast_party_connected_line_free(&transferee_colp);
+	ao2_ref(target, -1);
+	ao2_ref(transferee, -1);
 	return retval;
 }
 
@@ -8972,8 +8970,6 @@ static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *no
 	ast_free(ast_channel_dialed(chan)->number.str);
 	ast_channel_dialed(chan)->number.str = ast_strdup(notify->exten);
 
-	ast_channel_unlock(chan);
-
 	if (ast_pbx_start(chan)) {
 		ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", ast_channel_name(chan));
 		ast_channel_release(chan);
@@ -9450,11 +9446,11 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
 		break;
 #endif	/* We don't handle this yet */
 	case Fac_SubaddressTransfer:
-		/* We do not have anything to do for this message since we do not handle subaddreses. */
+		/* We do not have anything to do for this message since we do not handle subaddresses. */
 		break;
 	case Fac_RequestSubaddress:
 		/*
-		 * We do not have anything to do for this message since we do not handle subaddreses.
+		 * We do not have anything to do for this message since we do not handle subaddresses.
 		 * However, we do care about some other ie's that should be present.
 		 */
 		if (bc->redirecting.to_changed) {
@@ -10066,9 +10062,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		}
 
 		if (ch->state == MISDN_WAITING4DIGS) {
-			RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-			const char *pickupexten;
-
 			/*  Ok, incomplete Setup, waiting till extension exists */
 			if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
 				chan_misdn_log(1, bc->port, " --> using keypad as info\n");
@@ -10078,18 +10071,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 			strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
 			ast_channel_exten_set(ch->ast, bc->dialed.number);
 
-			ast_channel_lock(ch->ast);
-			pickup_cfg = ast_get_chan_features_pickup_config(ch->ast);
-			if (!pickup_cfg) {
-				ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-				pickupexten = "";
-			} else {
-				pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-			}
-			ast_channel_unlock(ch->ast);
-
 			/* Check for Pickup Request first */
-			if (!strcmp(ast_channel_exten(ch->ast), pickupexten)) {
+			if (!strcmp(ast_channel_exten(ch->ast), ast_pickup_ext())) {
 				if (ast_pickup_call(ch->ast)) {
 					hangup_chan(ch, bc);
 				} else {
@@ -10163,6 +10146,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 				if (digits) {
 					strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
 					ast_channel_exten_set(ch->ast, bc->dialed.number);
+					ast_cdr_update(ch->ast);
 				}
 
 				ast_queue_frame(ch->ast, &fr);
@@ -10176,8 +10160,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		int ai;
 		int im;
 		int append_msn = 0;
-		RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-		const char *pickupexten;
 
 		if (ch) {
 			switch (ch->state) {
@@ -10218,13 +10200,14 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		ch->addr = bc->addr;
 
 		{
-			struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+			struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+			struct ast_format tmpfmt;
 			if (!(cap)) {
 				return RESPONSE_ERR;
 			}
-			ast_format_cap_append(cap, ast_format_alaw, 0);
-			chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, cap, NULL, NULL, bc->port, bc->channel);
-			ao2_ref(cap, -1);
+			ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+			chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, cap, NULL, bc->port, bc->channel);
+			cap = ast_format_cap_destroy(cap);
 		}
 		if (!chan) {
 			chan_list_unref(ch, "Failed to create a new channel");
@@ -10232,16 +10215,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 			return RESPONSE_RELEASE_SETUP;
 		}
 
-		ast_channel_lock(chan);
-		pickup_cfg = ast_get_chan_features_pickup_config(chan);
-		if (!pickup_cfg) {
-			ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-			pickupexten = "";
-		} else {
-			pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-		}
-		ast_channel_unlock(chan);
-
 		if ((exceed = add_in_calls(bc->port))) {
 			char tmp[16];
 			snprintf(tmp, sizeof(tmp), "%d", exceed);
@@ -10252,10 +10225,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 
 		export_ch(chan, bc, ch);
 
-		ast_channel_lock(ch->ast);
 		ast_channel_rings_set(ch->ast, 1);
 		ast_setstate(ch->ast, AST_STATE_RINGING);
-		ast_channel_unlock(ch->ast);
 
 		/* Update asterisk channel caller information */
 		chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
@@ -10335,7 +10306,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		}
 
 		/* Check for Pickup Request first */
-		if (!strcmp(ast_channel_exten(chan), pickupexten)) {
+		if (!strcmp(ast_channel_exten(chan), ast_pickup_ext())) {
 			if (!ch->noautorespond_on_setup) {
 				/* Sending SETUP_ACK */
 				misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
@@ -10554,9 +10525,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		}
 
 		ast_queue_control(ch->ast, AST_CONTROL_RINGING);
-		ast_channel_lock(ch->ast);
 		ast_setstate(ch->ast, AST_STATE_RINGING);
-		ast_channel_unlock(ch->ast);
 
 		cb_log(7, bc->port, " --> Set State Ringing\n");
 
@@ -10859,7 +10828,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 			/* In Data Modes we queue frames */
 			memset(&frame, 0, sizeof(frame));
 			frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */
-			frame.subclass.format = ast_format_alaw;
+			ast_format_set(&frame.subclass.format, AST_FORMAT_ALAW, 0);
 			frame.datalen = bc->bframe_len;
 			frame.samples = bc->bframe_len;
 			frame.mallocd = 0;
@@ -10965,7 +10934,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 		ch->hold.port = 0;
 		ch->hold.channel = 0;
 
-		ast_queue_unhold(ch->ast);
+		ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
 
 		if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
 			chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
@@ -10975,7 +10944,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 	case EVENT_HOLD:
 	{
 		int hold_allowed;
-		RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
+		struct ast_channel *bridged;
 
 		misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
 		if (!hold_allowed) {
@@ -10984,7 +10953,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 			break;
 		}
 
-		bridged = ast_channel_bridge_peer(ch->ast);
+		bridged = ast_bridged_channel(ch->ast);
 		if (bridged) {
 			chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", ast_channel_tech(bridged)->type);
 			ch->l3id = bc->l3_id;
@@ -10995,7 +10964,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 			ch->hold.port = bc->port;
 			ch->hold.channel = bc->channel;
 
-			ast_queue_hold(ch->ast, NULL);
+			ast_queue_control(ch->ast, AST_CONTROL_HOLD);
 
 			misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
 		} else {
@@ -11297,22 +11266,12 @@ static int unload_module(void)
 #if defined(AST_MISDN_ENHANCEMENTS)
 	misdn_cc_destroy();
 #endif	/* defined(AST_MISDN_ENHANCEMENTS) */
-	ao2_cleanup(misdn_tech.capabilities);
-	misdn_tech.capabilities = NULL;
+	misdn_tech.capabilities = ast_format_cap_destroy(misdn_tech.capabilities);
+	misdn_tech_wo_bridge.capabilities = ast_format_cap_destroy(misdn_tech_wo_bridge.capabilities);
 
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int i, port;
@@ -11327,10 +11286,15 @@ static int load_module(void)
 	};
 
 
-	if (!(misdn_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(misdn_tech.capabilities = ast_format_cap_alloc())) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	if (!(misdn_tech_wo_bridge.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(misdn_tech.capabilities, ast_format_alaw, 0);
+	ast_format_set(&prefformat, AST_FORMAT_ALAW, 0);
+	ast_format_cap_add(misdn_tech.capabilities, &prefformat);
+	ast_format_cap_add(misdn_tech_wo_bridge.capabilities, &prefformat);
 
 	max_ports = misdn_lib_maxports_get();
 
@@ -12831,7 +12795,6 @@ static void chan_misdn_log(int level, int port, char *tmpl, ...)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Channel driver for mISDN Support (BRI/PRI)",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/channels/chan_motif.c b/channels/chan_motif.c
index 11f0bb8..313c66c 100644
--- a/channels/chan_motif.c
+++ b/channels/chan_motif.c
@@ -22,19 +22,11 @@
  *
  * \brief Motif Jingle Channel Driver
  *
- * Iksemel http://iksemel.jabberstudio.org/
+ * \extref Iksemel http://iksemel.jabberstudio.org/
  *
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_motif.c uses the configuration file \ref motif.conf
- * \addtogroup configuration_file
- */
-
-/*! \page motif.conf motif.conf
- * \verbinclude motif.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>iksemel</depend>
 	<depend>res_xmpp</depend>
@@ -44,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427982 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <fcntl.h>
@@ -73,150 +65,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427982 $")
 #include "asterisk/stringfields.h"
 #include "asterisk/utils.h"
 #include "asterisk/causes.h"
+#include "asterisk/astobj.h"
 #include "asterisk/abstract_jb.h"
 #include "asterisk/xmpp.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
-
-/*** DOCUMENTATION
-	<configInfo name="chan_motif" language="en_US">
-		<synopsis>Jingle Channel Driver</synopsis>
-		<description>
-			<para><emphasis>Transports</emphasis></para>
-			<para>There are three different transports and protocol derivatives
-			supported by <literal>chan_motif</literal>. They are in order of
-			preference: Jingle using ICE-UDP, Google Jingle, and Google-V1.</para>
-			<para>Jingle as defined in XEP-0166 supports the widest range of
-			features. It is referred to as <literal>ice-udp</literal>. This is
-			the specification that Jingle clients implement.</para>
-			<para>Google Jingle follows the Jingle specification for signaling
-			but uses a custom transport for media. It is supported by the
-			Google Talk Plug-in in Gmail and by some other Jingle clients. It
-			is referred to as <literal>google</literal> in this file.</para>
-			<para>Google-V1 is the original Google Talk signaling protocol
-			which uses an initial preliminary version of Jingle. It also uses
-			the same custom transport as Google Jingle for media. It is
-			supported by Google Voice, some other Jingle clients, and the
-			Windows Google Talk client. It is referred to as <literal>google-v1</literal>
-			in this file.</para>
-			<para>Incoming sessions will automatically switch to the correct
-			transport once it has been determined.</para>
-			<para>Outgoing sessions are capable of determining if the target
-			is capable of Jingle or a Google transport if the target is in the
-			roster. Unfortunately it is not possible to differentiate between
-			a Google Jingle or Google-V1 capable resource until a session
-			initiate attempt occurs. If a resource is determined to use a
-			Google transport it will initially use Google Jingle but will fall
-			back to Google-V1 if required.</para>
-			<para>If an outgoing session attempt fails due to failure to
-			support the given transport <literal>chan_motif</literal> will
-			fall back in preference order listed previously until all
-			transports have been exhausted.</para>
-			<para><emphasis>Dialing and Resource Selection Strategy</emphasis></para>
-			<para>Placing a call through an endpoint can be accomplished using the
-			following dial string:</para>
-			<para><literal>Motif/[endpoint name]/[target]</literal></para>
-			<para>When placing an outgoing call through an endpoint the requested
-			target is searched for in the roster list. If present the first Jingle
-			or Google Jingle capable resource is specifically targeted. Since the
-			capabilities of the resource are known the outgoing session initiation
-			will disregard the configured transport and use the determined one.</para>
-			<para>If the target is not found in the roster the target will be used
-			as-is and a session will be initiated using the transport specified
-			in this configuration file. If no transport has been specified the
-			endpoint defaults to <literal>ice-udp</literal>.</para>
-			<para><emphasis>Video Support</emphasis></para>
-			<para>Support for video does not need to be explicitly enabled.
-			Configuring any video codec on your endpoint will automatically enable
-			it.</para>
-			<para><emphasis>DTMF</emphasis></para>
-			<para>The only supported method for DTMF is RFC2833. This is always
-			enabled on audio streams and negotiated if possible.</para>
-			<para><emphasis>Incoming Calls</emphasis></para>
-			<para>Incoming calls will first look for the extension matching the
-			name of the endpoint in the configured context. If no such extension
-			exists the call will automatically fall back to the <literal>s</literal> extension.</para>
-			<para><emphasis>CallerID</emphasis></para>
-			<para>The incoming caller id number is populated with the username of
-			the caller and the name is populated with the full identity of the
-			caller. If you would like to perform authentication or filtering
-			of incoming calls it is recommended that you use these fields to do so.</para>
-			<para>Outgoing caller id can <emphasis>not</emphasis> be set.</para>
-			<warning>
-				<para>Multiple endpoints using the
-				same connection is <emphasis>NOT</emphasis> supported. Doing so
-				may result in broken calls.</para>
-			</warning>
-		</description>
-		<configFile name="motif.conf">
-			<configObject name="endpoint">
-				<synopsis>The configuration for an endpoint.</synopsis>
-				<configOption name="context">
-					<synopsis>Default dialplan context that incoming sessions will be routed to</synopsis>
-				</configOption>
-				<configOption name="callgroup">
-					<synopsis>A callgroup to assign to this endpoint.</synopsis>
-				</configOption>
-				<configOption name="pickupgroup">
-					<synopsis>A pickup group to assign to this endpoint.</synopsis>
-				</configOption>
-				<configOption name="language">
-					<synopsis>The default language for this endpoint.</synopsis>
-				</configOption>
-				<configOption name="musicclass">
-					<synopsis>Default music on hold class for this endpoint.</synopsis>
-				</configOption>
-				<configOption name="parkinglot">
-					<synopsis>Default parking lot for this endpoint.</synopsis>
-				</configOption>
-				<configOption name="accountcode">
-					<synopsis>Accout code for CDR purposes</synopsis>
-				</configOption>
-				<configOption name="allow">
-					<synopsis>Codecs to allow</synopsis>
-				</configOption>
-				<configOption name="disallow">
-					<synopsis>Codecs to disallow</synopsis>
-				</configOption>
-				<configOption name="connection">
-					<synopsis>Connection to accept traffic on and on which to send traffic out</synopsis>
-				</configOption>
-				<configOption name="transport">
-					<synopsis>The transport to use for the endpoint.</synopsis>
-					<description>
-						<para>The default outbound transport for this endpoint. Inbound
-						messages are inferred. Allowed transports are <literal>ice-udp</literal>,
-						<literal>google</literal>, or <literal>google-v1</literal>. Note
-						that <literal>chan_motif</literal> will fall back to transport
-						preference order if the transport value chosen here fails.</para>
-						<enumlist>
-							<enum name="ice-udp">
-								<para>The Jingle protocol, as defined in XEP 0166.</para>
-							</enum>
-							<enum name="google">
-								<para>The Google Jingle protocol, which follows the Jingle
-								specification for signaling but uses a custom transport for
-								media.</para>
-							</enum>
-							<enum name="google-v1">
-								<para>Google-V1 is the original Google Talk signaling
-								protocol which uses an initial preliminary version of Jingle.
-								It also uses the same custom transport as <literal>google</literal> for media.</para>
-							</enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="maxicecandidates">
-					<synopsis>Maximum number of ICE candidates to offer</synopsis>
-				</configOption>
-				<configOption name="maxpayloads">
-					<synopsis>Maximum number of pyaloads to offer</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
 
 /*! \brief Default maximum number of ICE candidates we will offer */
 #define DEFAULT_MAX_ICE_CANDIDATES "10"
@@ -287,6 +138,7 @@ struct jingle_endpoint {
 	iksrule *rule;                          /*!< Active matching rule */
 	unsigned int maxicecandidates;          /*!< Maximum number of ICE candidates we will offer */
 	unsigned int maxpayloads;               /*!< Maximum number of payloads we will offer */
+	struct ast_codec_pref prefs;            /*!< Codec preferences */
 	struct ast_format_cap *cap;             /*!< Formats to use */
 	ast_group_t callgroup;                  /*!< Call group */
 	ast_group_t pickupgroup;                /*!< Pickup group */
@@ -309,6 +161,7 @@ struct jingle_session {
 	char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
 	char remote[XMPP_MAX_JIDLEN];         /*!< Identifier of the remote party */
 	iksrule *rule;                        /*!< Session matching rule */
+	struct ast_codec_pref prefs;          /*!< Codec preferences */
 	struct ast_channel *owner;            /*!< Master Channel */
 	struct ast_rtp_instance *rtp;         /*!< RTP audio session */
 	struct ast_rtp_instance *vrtp;        /*!< RTP video session */
@@ -332,7 +185,7 @@ static AO2_GLOBAL_OBJ_STATIC(globals);
 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
 
 /* \brief Asterisk core interaction functions */
-static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int jingle_sendtext(struct ast_channel *ast, const char *text);
 static int jingle_digit_begin(struct ast_channel *ast, char digit);
 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
@@ -360,6 +213,7 @@ static struct ast_channel_tech jingle_tech = {
 	.send_text = jingle_sendtext,
 	.send_digit_begin = jingle_digit_begin,
 	.send_digit_end = jingle_digit_end,
+	.bridge = ast_rtp_instance_bridge,
 	.call = jingle_call,
 	.hangup = jingle_hangup,
 	.answer = jingle_answer,
@@ -453,7 +307,8 @@ static void jingle_endpoint_destructor(void *obj)
 		ast_xmpp_client_unref(endpoint->connection);
 	}
 
-	ao2_cleanup(endpoint->cap);
+	ast_format_cap_destroy(endpoint->cap);
+
 	ao2_ref(endpoint->state, -1);
 
 	ast_string_field_free_memory(endpoint);
@@ -517,7 +372,7 @@ static void *jingle_endpoint_alloc(const char *cat)
 
 	ast_string_field_set(endpoint, name, cat);
 
-	endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	endpoint->cap = ast_format_cap_alloc_nolock();
 	endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
 
 	return endpoint;
@@ -543,7 +398,6 @@ static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
 
 static struct aco_type endpoint_option = {
 	.type = ACO_ITEM,
-	.name = "endpoint",
 	.category_match = ACO_BLACKLIST,
 	.category = "^general$",
 	.item_alloc = jingle_endpoint_alloc,
@@ -581,9 +435,9 @@ static void jingle_session_destructor(void *obj)
 		ast_rtp_instance_destroy(session->vrtp);
 	}
 
-	ao2_cleanup(session->cap);
-	ao2_cleanup(session->jointcap);
-	ao2_cleanup(session->peercap);
+	ast_format_cap_destroy(session->cap);
+	ast_format_cap_destroy(session->jointcap);
+	ast_format_cap_destroy(session->peercap);
 
 	if (session->callid) {
 		ast_callid_unref(session->callid);
@@ -655,18 +509,6 @@ static struct ast_rtp_glue jingle_rtp_glue = {
 	.update_peer = jingle_set_rtp_peer,
 };
 
-/*! \brief Set the channel owner on the \ref jingle_session object and related objects */
-static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
-{
-	session->owner = chan;
-	if (session->rtp) {
-		ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
-	}
-	if (session->vrtp) {
-		ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
-	}
-}
-
 /*! \brief Internal helper function which enables video support on a sesson if possible */
 static void jingle_enable_video(struct jingle_session *session)
 {
@@ -679,7 +521,7 @@ static void jingle_enable_video(struct jingle_session *session)
 	}
 
 	/* If there are no configured video codecs do not turn video support on, it just won't work */
-	if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) {
+	if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
 		return;
 	}
 
@@ -690,11 +532,11 @@ static void jingle_enable_video(struct jingle_session *session)
 	}
 
 	ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
-	ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
+
 	ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
 	ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
-	ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp),
-		ast_format_cap_get_framing(session->cap));
+	ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
+
 	if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
 		ice->stop(session->vrtp);
 	}
@@ -739,15 +581,15 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con
 	session->connection = endpoint->connection;
 	session->transport = endpoint->transport;
 
-	if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
-	    !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
-	    !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
+	if (!(session->cap = ast_format_cap_alloc_nolock()) ||
+	    !(session->jointcap = ast_format_cap_alloc_nolock()) ||
+	    !(session->peercap = ast_format_cap_alloc_nolock()) ||
 	    !session->callid) {
 		ao2_ref(session, -1);
 		return NULL;
 	}
 
-	ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(session->cap, endpoint->cap);
 
 	/* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
 	 * that we want IPv4 */
@@ -761,6 +603,8 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con
 	ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
 	ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
 
+	memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
+
 	session->maxicecandidates = endpoint->maxicecandidates;
 	session->maxpayloads = endpoint->maxpayloads;
 
@@ -768,46 +612,35 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con
 }
 
 /*! \brief Function called to create a new Jingle Asterisk channel */
-static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
+static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const char *linkedid, const char *cid_name)
 {
 	struct ast_channel *chan;
 	const char *str = S_OR(title, session->remote);
-	struct ast_format_cap *caps;
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 
-	if (!ast_format_cap_count(session->cap)) {
+	if (ast_format_cap_is_empty(session->cap)) {
 		return NULL;
 	}
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
+	if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
 		return NULL;
 	}
 
-	if (!(chan = ast_channel_alloc_with_endpoint(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, endpoint->connection->endpoint, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
-		ao2_ref(caps, -1);
-		return NULL;
-	}
-
-	ast_channel_stage_snapshot(chan);
-
 	ast_channel_tech_set(chan, &jingle_tech);
 	ast_channel_tech_pvt_set(chan, session);
-	jingle_set_owner(session, chan);
+	session->owner = chan;
 
 	ast_channel_callid_set(chan, session->callid);
 
-	ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN);
-	ast_channel_nativeformats_set(chan, caps);
-	ao2_ref(caps, -1);
+	ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
+	ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
 
 	if (session->rtp) {
 		struct ast_rtp_engine_ice *ice;
 
 		ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
 		ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
-		ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp),
-			ast_format_cap_get_framing(session->cap));
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
 
 		if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
 		     (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
@@ -823,12 +656,11 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j
 
 	ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
 
-	tmpfmt = ast_format_cap_get_format(session->cap, 0);
-	ast_channel_set_writeformat(chan, tmpfmt);
-	ast_channel_set_rawwriteformat(chan, tmpfmt);
-	ast_channel_set_readformat(chan, tmpfmt);
-	ast_channel_set_rawreadformat(chan, tmpfmt);
-	ao2_ref(tmpfmt, -1);
+	ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
+	ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
+	ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
+	ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
+	ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
 
 	ao2_lock(endpoint);
 
@@ -857,9 +689,6 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j
 
 	ao2_unlock(endpoint);
 
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
-
 	return chan;
 }
 
@@ -1306,24 +1135,30 @@ static void jingle_send_transport_info(struct jingle_session *session, const cha
 }
 
 /*! \brief Internal helper function which adds payloads to a description */
-static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_media_type type)
+static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type)
 {
+	struct ast_format format;
 	int x = 0, i = 0, res = 0;
 
-	for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) {
-		struct ast_format *format = ast_format_cap_get_format(session->jointcap, x);
+	for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
 		int rtp_code;
 		iks *payload;
 		char tmp[32];
 
-		if (ast_format_get_type(format) != type) {
-			ao2_ref(format, -1);
+		if (!ast_codec_pref_index(&session->prefs, x, &format)) {
+			break;
+		}
+
+		if (AST_FORMAT_GET_TYPE(format.id) != type) {
+			continue;
+		}
+
+		if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
 			continue;
 		}
 
-		if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) ||
+		if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
 		    (!(payload = iks_new("payload-type")))) {
-			ao2_ref(format, -1);
 			return -1;
 		}
 
@@ -1333,18 +1168,17 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st
 
 		snprintf(tmp, sizeof(tmp), "%d", rtp_code);
 		iks_insert_attrib(payload, "id", tmp);
-		iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
+		iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
 		iks_insert_attrib(payload, "channels", "1");
 
-		if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) &&
-			((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
+		if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
 			iks_insert_attrib(payload, "clockrate", "16000");
 		} else {
-			snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0));
+			snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, &format, 0));
 			iks_insert_attrib(payload, "clockrate", tmp);
 		}
 
-		if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
+		if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
 			iks *parameter;
 
 			/* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
@@ -1367,11 +1201,9 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st
 
 		iks_insert_node(description, payload);
 		payloads[i++] = payload;
-
-		ao2_ref(format, -1);
 	}
 	/* If this is for audio and there is room for RFC2833 add it in */
-	if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) {
+	if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
 		iks *payload;
 
 		if ((payload = iks_new("payload-type"))) {
@@ -1393,7 +1225,7 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st
 
 /*! \brief Helper function which adds content to a description */
 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
-			      const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads)
+			      const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
 {
 	int res = 0;
 
@@ -1403,9 +1235,9 @@ static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *
 		iks_insert_node(jingle, content);
 
 		iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
-		if (type == AST_MEDIA_TYPE_AUDIO) {
+		if (type == AST_FORMAT_TYPE_AUDIO) {
 			iks_insert_attrib(description, "media", "audio");
-		} else if (type == AST_MEDIA_TYPE_VIDEO) {
+		} else if (type == AST_FORMAT_TYPE_VIDEO) {
 			iks_insert_attrib(description, "media", "video");
 		} else {
 			return -1;
@@ -1472,7 +1304,7 @@ static void jingle_send_session_action(struct jingle_session *session, const cha
 	if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
 	    (audio_transport = iks_new("transport"))) {
 		res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
-					 AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads);
+					 AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
 	} else {
 		ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
 		res = -1;
@@ -1482,7 +1314,7 @@ static void jingle_send_session_action(struct jingle_session *session, const cha
 		if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
 		    (video_transport = iks_new("transport"))) {
 			res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
-						 AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads);
+						 AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
 		} else {
 			ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
 			res = -1;
@@ -1671,24 +1503,17 @@ static struct ast_frame *jingle_read(struct ast_channel *ast)
 	}
 
 	if (frame && frame->frametype == AST_FRAME_VOICE &&
-	    ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+	    !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
+		if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
 			ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
-				  ast_format_get_name(frame->subclass.format), ast_channel_name(ast));
+				  ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
 			ast_frfree(frame);
 			frame = &ast_null_frame;
 		} else {
-			struct ast_format_cap *caps;
-
 			ast_debug(1, "Oooh, format changed to %s\n",
-				  ast_format_get_name(frame->subclass.format));
-
-			caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-			if (caps) {
-				ast_format_cap_append(caps, frame->subclass.format, 0);
-				ast_channel_nativeformats_set(ast, caps);
-				ao2_ref(caps, -1);
-			}
+				  ast_getformatname(&frame->subclass.format));
+			ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
+			ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
 			ast_set_read_format(ast, ast_channel_readformat(ast));
 			ast_set_write_format(ast, ast_channel_writeformat(ast));
 		}
@@ -1702,18 +1527,17 @@ static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 	struct jingle_session *session = ast_channel_tech_pvt(ast);
 	int res = 0;
+	char buf[256];
 
 	switch (frame->frametype) {
 	case AST_FRAME_VOICE:
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
-
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
 			ast_log(LOG_WARNING,
 				"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
-				ast_format_get_name(frame->subclass.format),
-				ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
-				ast_format_get_name(ast_channel_readformat(ast)),
-				ast_format_get_name(ast_channel_writeformat(ast)));
+				ast_getformatname(&frame->subclass.format),
+				ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+				ast_getformatname(ast_channel_readformat(ast)),
+				ast_getformatname(ast_channel_writeformat(ast)));
 			return 0;
 		}
 		if (session && session->rtp) {
@@ -1741,7 +1565,7 @@ static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
 
 	ao2_lock(session);
 
-	jingle_set_owner(session, newchan);
+	session->owner = newchan;
 
 	ao2_unlock(session);
 
@@ -1805,7 +1629,6 @@ static int jingle_indicate(struct ast_channel *ast, int condition, const void *d
 	case AST_CONTROL_CONNECTED_LINE:
 		break;
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 	case -1:
 		res = -1;
 		break;
@@ -1857,7 +1680,7 @@ static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
 	ast_setstate(ast, AST_STATE_RING);
 
 	/* Since we have no idea of the remote capabilities use ours for now */
-	ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(session->jointcap, session->cap);
 
 	/* We set up a hook so we can know when our session-initiate message was accepted or rejected */
 	session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
@@ -1892,7 +1715,7 @@ static int jingle_hangup(struct ast_channel *ast)
 	}
 
 	ast_channel_tech_pvt_set(ast, NULL);
-	jingle_set_owner(session, NULL);
+	session->owner = NULL;
 
 	ao2_unlink(session->state->sessions, session);
 	ao2_ref(session->state, -1);
@@ -1904,7 +1727,7 @@ static int jingle_hangup(struct ast_channel *ast)
 }
 
 /*! \brief Function called by core to create a new outgoing Jingle session */
-static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
 	RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
@@ -1920,7 +1743,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca
 		);
 
 	/* We require at a minimum one audio format to be requested */
-	if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) {
+	if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
 		ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
 		*cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
 		return NULL;
@@ -2005,7 +1828,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca
 		/* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
 	}
 
-	if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
+	if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
 		ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
 		ao2_ref(session, -1);
@@ -2013,7 +1836,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca
 	}
 
 	/* If video was requested try to enable it on the session */
-	if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) {
+	if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
 		jingle_enable_video(session);
 	}
 
@@ -2055,8 +1878,8 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
 			ast_string_field_set(session, audio_name, name);
 		}
 		*rtp = session->rtp;
-		ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO);
-		ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO);
+		ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
+		ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
 	} else if (!strcasecmp(media, "video")) {
 		if (!ast_strlen_zero(name)) {
 			ast_string_field_set(session, video_name, name);
@@ -2072,8 +1895,8 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
 			return -1;
 		}
 
-		ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO);
-		ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO);
+		ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
+		ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
 	} else {
 		/* Unknown media type */
 		jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
@@ -2094,6 +1917,8 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
 		int rtp_id, rtp_clockrate;
 
 		if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
+			ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
+
 			if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
 				ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
 			} else {
@@ -2103,9 +1928,9 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
 	}
 
 	ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
-	ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
+	ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
 
-	if (!ast_format_cap_count(session->jointcap)) {
+	if (ast_format_cap_is_empty(session->jointcap)) {
 		/* We have no compatible codecs, so terminate the session appropriately */
 		jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 		ast_rtp_codecs_payloads_destroy(&codecs);
@@ -2365,20 +2190,12 @@ static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
 	}
 
 	if ((chan = jingle_session_lock_full(session))) {
-		struct ast_format_cap *caps;
-		struct ast_format *fmt;
-
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (caps) {
-			ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
-			ast_channel_nativeformats_set(chan, caps);
-			ao2_ref(caps, -1);
-		}
+		struct ast_format fmt;
 
-		fmt = ast_format_cap_get_format(session->jointcap, 0);
-		ast_set_read_format(chan, fmt);
-		ast_set_write_format(chan, fmt);
-		ao2_ref(fmt, -1);
+		ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
+		ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
+		ast_set_read_format(chan, &fmt);
+		ast_set_write_format(chan, &fmt);
 
 		ast_channel_unlock(chan);
 		ast_channel_unref(chan);
@@ -2423,7 +2240,7 @@ static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, str
 	}
 
 	/* Create a new Asterisk channel using the above local session */
-	if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
+	if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
 		ao2_ref(session, -1);
 		jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
 		return;
@@ -2431,9 +2248,7 @@ static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, str
 
 	ao2_link(endpoint->state->sessions, session);
 
-	ast_channel_lock(chan);
 	ast_setstate(chan, AST_STATE_RING);
-	ast_channel_unlock(chan);
 	res = ast_pbx_start(chan);
 
 	switch (res) {
@@ -2519,9 +2334,9 @@ static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct
 			ast_setstate(chan, AST_STATE_RINGING);
 		}
 	} else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
-		ast_queue_hold(chan, NULL);
+		ast_queue_control(chan, AST_CONTROL_HOLD);
 	} else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
-		ast_queue_unhold(chan);
+		ast_queue_control(chan, AST_CONTROL_UNHOLD);
 	}
 
 	ast_channel_unlock(chan);
@@ -2716,19 +2531,10 @@ static int custom_transport_handler(const struct aco_option *opt, struct ast_var
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief Load module into PBX, register channel */
 static int load_module(void)
 {
-	if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -2744,8 +2550,8 @@ static int load_module(void)
 	aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
 	aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
 	aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
-	aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
-	aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
+	aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
+	aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
 	aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
 	aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
 	aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
@@ -2753,12 +2559,12 @@ static int load_module(void)
 	aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
 			    FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
 
-	ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
+	ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
 
 	if (aco_process_config(&cfg_info, 0)) {
-		ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
+		ast_log(LOG_ERROR, "Unable to read config file motif.conf. Not loading module.\n");
 		aco_info_destroy(&cfg_info);
-		ao2_cleanup(jingle_tech.capabilities);
+		ast_format_cap_destroy(jingle_tech.capabilities);
 		jingle_tech.capabilities = NULL;
 		return AST_MODULE_LOAD_DECLINE;
 	}
@@ -2792,7 +2598,7 @@ end:
 	aco_info_destroy(&cfg_info);
 	ao2_global_obj_release(globals);
 
-	ao2_cleanup(jingle_tech.capabilities);
+	ast_format_cap_destroy(jingle_tech.capabilities);
 	jingle_tech.capabilities = NULL;
 
 	return AST_MODULE_LOAD_FAILURE;
@@ -2801,18 +2607,14 @@ end:
 /*! \brief Reload module */
 static int reload(void)
 {
-	if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
-		return -1;
-	}
-
-	return 0;
+	return aco_process_config(&cfg_info, 1);
 }
 
 /*! \brief Unload the jingle channel from Asterisk */
 static int unload_module(void)
 {
 	ast_channel_unregister(&jingle_tech);
-	ao2_cleanup(jingle_tech.capabilities);
+	ast_format_cap_destroy(jingle_tech.capabilities);
 	jingle_tech.capabilities = NULL;
 	ast_rtp_glue_unregister(&jingle_rtp_glue);
 	ast_sched_context_destroy(sched);
@@ -2823,7 +2625,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c
index de44bf1..dfa0680 100644
--- a/channels/chan_multicast_rtp.c
+++ b/channels/chan_multicast_rtp.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <fcntl.h>
 #include <sys/signal.h>
@@ -56,7 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 static const char tdesc[] = "Multicast RTP Paging Channel Driver";
 
 /* Forward declarations */
-static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int multicast_rtp_call(struct ast_channel *ast, const char *dest, int timeout);
 static int multicast_rtp_hangup(struct ast_channel *ast);
 static struct ast_frame *multicast_rtp_read(struct ast_channel *ast);
@@ -110,17 +110,15 @@ static int multicast_rtp_hangup(struct ast_channel *ast)
 }
 
 /*! \brief Function called when we should prepare to call the destination */
-static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control;
 	struct ast_rtp_instance *instance;
 	struct ast_sockaddr control_address;
 	struct ast_sockaddr destination_address;
 	struct ast_channel *chan;
-	struct ast_format_cap *caps = NULL;
-	struct ast_format *fmt = NULL;
-
-	fmt = ast_format_cap_get_format(cap, 0);
+	struct ast_format fmt;
+	ast_best_codec(cap, &fmt);
 
 	ast_sockaddr_setnull(&control_address);
 
@@ -147,43 +145,30 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo
 		goto failure;
 	}
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		goto failure;
-	}
-
 	if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) {
 		goto failure;
 	}
 
-	if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "MulticastRTP/%p", instance))) {
+	if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", requestor ? ast_channel_linkedid(requestor) : "", 0, "MulticastRTP/%p", instance))) {
 		ast_rtp_instance_destroy(instance);
 		goto failure;
 	}
-	ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan));
+
 	ast_rtp_instance_set_remote_address(instance, &destination_address);
 
 	ast_channel_tech_set(chan, &multicast_rtp_tech);
 
-	ast_format_cap_append(caps, fmt, 0);
-	ast_channel_nativeformats_set(chan, caps);
-	ast_channel_set_writeformat(chan, fmt);
-	ast_channel_set_rawwriteformat(chan, fmt);
-	ast_channel_set_readformat(chan, fmt);
-	ast_channel_set_rawreadformat(chan, fmt);
+	ast_format_cap_add(ast_channel_nativeformats(chan), &fmt);
+	ast_format_copy(ast_channel_writeformat(chan), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
+	ast_format_copy(ast_channel_readformat(chan), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
 
 	ast_channel_tech_pvt_set(chan, instance);
 
-	ast_channel_unlock(chan);
-
-	ao2_ref(fmt, -1);
-	ao2_ref(caps, -1);
-
 	return chan;
 
 failure:
-	ao2_cleanup(fmt);
-	ao2_cleanup(caps);
 	*cause = AST_CAUSE_FAILURE;
 	return NULL;
 }
@@ -191,14 +176,12 @@ failure:
 /*! \brief Function called when our module is loaded */
 static int load_module(void)
 {
-	if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append_by_type(multicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_add_all(multicast_rtp_tech.capabilities);
 	if (ast_channel_register(&multicast_rtp_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel class 'MulticastRTP'\n");
-		ao2_ref(multicast_rtp_tech.capabilities, -1);
-		multicast_rtp_tech.capabilities = NULL;
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -209,14 +192,12 @@ static int load_module(void)
 static int unload_module(void)
 {
 	ast_channel_unregister(&multicast_rtp_tech);
-	ao2_ref(multicast_rtp_tech.capabilities, -1);
-	multicast_rtp_tech.capabilities = NULL;
+	multicast_rtp_tech.capabilities = ast_format_cap_destroy(multicast_rtp_tech.capabilities);
 
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Paging Channel",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DRIVER,
diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c
index e49a8a9..e638487 100644
--- a/channels/chan_nbs.c
+++ b/channels/chan_nbs.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <sys/time.h>
@@ -47,10 +47,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
-#include "asterisk/format_cache.h"
 
 static const char tdesc[] = "Network Broadcast Sound Driver";
 
+/* Only linear is allowed */
+static struct ast_format prefformat;
+
 static char context[AST_MAX_EXTENSION] = "default";
 static const char type[] = "NBS";
 
@@ -61,10 +63,11 @@ struct nbs_pvt {
 	struct ast_channel *owner;		/* Channel we belong to, possibly NULL */
 	char app[16];					/* Our app */
 	char stream[80];				/* Our stream */
+	struct ast_frame fr;			/* "null" frame */
 	struct ast_module_user *u;		/*! for holding a reference to this module */
 };
 
-static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout);
 static int nbs_hangup(struct ast_channel *ast);
 static struct ast_frame *nbs_xread(struct ast_channel *ast);
@@ -175,14 +178,37 @@ static int nbs_hangup(struct ast_channel *ast)
 
 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
 {
+	struct nbs_pvt *p = ast_channel_tech_pvt(ast);
+	
+
+	/* Some nice norms */
+	p->fr.datalen = 0;
+	p->fr.samples = 0;
+	p->fr.data.ptr =  NULL;
+	p->fr.src = type;
+	p->fr.offset = 0;
+	p->fr.mallocd=0;
+	p->fr.delivery.tv_sec = 0;
+	p->fr.delivery.tv_usec = 0;
+
 	ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast));
 
-	return &ast_null_frame;
+	return &p->fr;
 }
 
 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
 {
 	struct nbs_pvt *p = ast_channel_tech_pvt(ast);
+	/* Write a frame of (presumably voice) data */
+	if (frame->frametype != AST_FRAME_VOICE) {
+		if (frame->frametype != AST_FRAME_IMAGE)
+			ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
+		return 0;
+	}
+	if (frame->subclass.format.id != (AST_FORMAT_SLINEAR)) {
+		ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format));
+		return 0;
+	}
 	if (ast_channel_state(ast) != AST_STATE_UP) {
 		/* Don't try tos end audio on-hook */
 		return 0;
@@ -192,19 +218,19 @@ static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
 	return 0;
 }
 
-static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *linkedid)
 {
 	struct ast_channel *tmp;
-	tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, assignedids, requestor, 0, "NBS/%s", i->stream);
+	tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, linkedid, 0, "NBS/%s", i->stream);
 	if (tmp) {
 		ast_channel_tech_set(tmp, &nbs_tech);
 		ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
 
-		ast_channel_nativeformats_set(tmp, nbs_tech.capabilities);
-		ast_channel_set_rawreadformat(tmp, ast_format_slin);
-		ast_channel_set_rawwriteformat(tmp, ast_format_slin);
-		ast_channel_set_writeformat(tmp, ast_format_slin);
-		ast_channel_set_readformat(tmp, ast_format_slin);
+		ast_format_cap_add(ast_channel_nativeformats(tmp), &prefformat);
+		ast_format_copy(ast_channel_rawreadformat(tmp), &prefformat);
+		ast_format_copy(ast_channel_rawwriteformat(tmp), &prefformat);
+		ast_format_copy(ast_channel_writeformat(tmp), &prefformat);
+		ast_format_copy(ast_channel_readformat(tmp), &prefformat);
 		if (state == AST_STATE_RING)
 			ast_channel_rings_set(tmp, 1);
 		ast_channel_tech_pvt_set(tmp, i);
@@ -213,7 +239,6 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct as
 		ast_channel_language_set(tmp, "");
 		i->owner = tmp;
 		i->u = ast_module_user_add(tmp);
-		ast_channel_unlock(tmp);
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
@@ -226,21 +251,19 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct as
 }
 
 
-static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	struct nbs_pvt *p;
 	struct ast_channel *tmp = NULL;
 
-	if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_str *cap_buf = ast_str_alloca(64);
-
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
-			ast_format_cap_get_names(cap, &cap_buf));
+	if (!(ast_format_cap_iscompatible(cap, &prefformat))) {
+		char tmp[256];
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 		return NULL;
 	}
 	p = nbs_alloc(data);
 	if (p) {
-		tmp = nbs_new(p, AST_STATE_DOWN, assignedids, requestor);
+		tmp = nbs_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
 		if (!tmp)
 			nbs_destroy(p);
 	}
@@ -251,17 +274,17 @@ static int unload_module(void)
 {
 	/* First, take us out of the channel loop */
 	ast_channel_unregister(&nbs_tech);
-	ao2_ref(nbs_tech.capabilities, -1);
-	nbs_tech.capabilities = NULL;
+	nbs_tech.capabilities = ast_format_cap_destroy(nbs_tech.capabilities);
 	return 0;
 }
 
 static int load_module(void)
 {
-	if (!(nbs_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	ast_format_set(&prefformat, AST_FORMAT_SLINEAR, 0);
+	if (!(nbs_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_format_cap_append(nbs_tech.capabilities, ast_format_slin, 0);
+	ast_format_cap_add(nbs_tech.capabilities, &prefformat);
 	/* Make sure we can register our channel type */
 	if (ast_channel_register(&nbs_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
@@ -270,5 +293,4 @@ static int load_module(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 84a45ad..f98dc4e 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -27,17 +27,12 @@
  * \author Mark Spencer <markster at digium.com>
  * \author Luigi Rizzo
  *
+ * \par See also
+ * \arg \ref Config_oss
+ *
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_oss.c uses the configuration file \ref oss.conf
- * \addtogroup configuration_file
- */
-
-/*! \page oss.conf oss.conf
- * \verbinclude oss.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>oss</depend>
 	<support_level>extended</support_level>
@@ -45,7 +40,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>		/* isalnum() used here */
 #include <math.h>
@@ -68,8 +63,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/causes.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
-#include "asterisk/bridge.h"
-#include "asterisk/format_cache.h"
 
 #include "console_video.h"
 
@@ -335,7 +328,7 @@ static struct chan_oss_pvt oss_default = {
 
 static int setformat(struct chan_oss_pvt *o, int mode);
 
-static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
+static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor,
 									   const char *data, int *cause);
 static int oss_digit_begin(struct ast_channel *c, char digit);
 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
@@ -727,7 +720,7 @@ static struct ast_frame *oss_read(struct ast_channel *c)
 		return f;
 	/* ok we can build and deliver the frame to the caller */
 	f->frametype = AST_FRAME_VOICE;
-	f->subclass.format = ao2_bump(ast_format_slin);
+	ast_format_set(&f->subclass.format, AST_FORMAT_SLINEAR, 0);
 	f->samples = FRAME_SIZE;
 	f->datalen = FRAME_SIZE * 2;
 	f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
@@ -793,11 +786,11 @@ static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_
 /*!
  * \brief allocate a new channel.
  */
-static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
 {
 	struct ast_channel *c;
 
-	c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, assignedids, requestor, 0, "Console/%s", o->device + 5);
+	c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5);
 	if (c == NULL)
 		return NULL;
 	ast_channel_tech_set(c, &oss_tech);
@@ -805,9 +798,9 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
 		setformat(o, O_RDWR);
 	ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
 
-	ast_channel_set_readformat(c, ast_format_slin);
-	ast_channel_set_writeformat(c, ast_format_slin);
-	ast_channel_nativeformats_set(c, oss_tech.capabilities);
+	ast_format_set(ast_channel_readformat(c), AST_FORMAT_SLINEAR, 0);
+	ast_format_set(ast_channel_writeformat(c), AST_FORMAT_SLINEAR, 0);
+	ast_format_cap_add(ast_channel_nativeformats(c), ast_channel_readformat(c));
 
 	/* if the console makes the call, add video to the offer */
 	/* if (state == AST_STATE_RINGING) TODO XXX CONSOLE VIDEO IS DISABLED UNTIL IT GETS A MAINTAINER
@@ -830,7 +823,6 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
 	o->owner = c;
 	ast_module_ref(ast_module_info->self);
 	ast_jb_configure(c, &global_jbconf);
-	ast_channel_unlock(c);
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(c)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c));
@@ -843,7 +835,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
 	return c;
 }
 
-static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	struct ast_channel *c;
 	struct chan_oss_pvt *o;
@@ -852,6 +844,8 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap *
 		AST_APP_ARG(flags);
 	);
 	char *parse = ast_strdupa(data);
+	char buf[256];
+	struct ast_format tmpfmt;
 
 	AST_NONSTANDARD_APP_ARGS(args, parse, '/');
 	o = find_desc(args.name);
@@ -862,9 +856,8 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap *
 		/* XXX we could default to 'dsp' perhaps ? */
 		return NULL;
 	}
-	if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_format_cap_get_names(cap, &codec_buf));
+	if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)))) {
+		ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
 		return NULL;
 	}
 	if (o->owner) {
@@ -872,7 +865,7 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap *
 		*cause = AST_CAUSE_BUSY;
 		return NULL;
 	}
-	c = oss_new(o, NULL, NULL, AST_STATE_DOWN, assignedids, requestor);
+	c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
 	if (c == NULL) {
 		ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
 		return NULL;
@@ -1131,7 +1124,7 @@ static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		myc = o->ctx;
 	if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
 		o->hookstate = 1;
-		oss_new(o, mye, myc, AST_STATE_RINGING, NULL, NULL);
+		oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
 	} else
 		ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
 	if (s)
@@ -1175,6 +1168,7 @@ static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct chan_oss_pvt *o = find_desc(oss_active);
+	struct ast_channel *b = NULL;
 	char *tmp, *ext, *ctx;
 
 	switch (cmd) {
@@ -1193,19 +1187,24 @@ static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		return CLI_SHOWUSAGE;
 	if (o == NULL)
 		return CLI_FAILURE;
-	if (o->owner == NULL || !ast_channel_is_bridged(o->owner)) {
+	if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
 		ast_cli(a->fd, "There is no call to transfer\n");
 		return CLI_SUCCESS;
 	}
 
 	tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
-	if (ctx == NULL) {			/* supply default context if needed */
+	if (ctx == NULL)			/* supply default context if needed */
 		ctx = ast_strdupa(ast_channel_context(o->owner));
+	if (!ast_exists_extension(b, ctx, ext, 1,
+		S_COR(ast_channel_caller(b)->id.number.valid, ast_channel_caller(b)->id.number.str, NULL))) {
+		ast_cli(a->fd, "No such extension exists\n");
+	} else {
+		ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", ast_channel_name(b), ext, ctx);
+		if (ast_async_goto(b, ctx, ext, 1))
+			ast_cli(a->fd, "Failed to transfer :(\n");
 	}
-	if (ast_bridge_transfer_blind(1, o->owner, ext, ctx, NULL, NULL) != AST_BRIDGE_TRANSFER_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to transfer call from channel %s\n", ast_channel_name(o->owner));
-	}
-	ast_free(tmp);
+	if (tmp)
+		ast_free(tmp);
 	return CLI_SUCCESS;
 }
 
@@ -1437,21 +1436,12 @@ error:
 #endif
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	struct ast_config *cfg = NULL;
 	char *ctg = NULL;
 	struct ast_flags config_flags = { 0 };
+	struct ast_format tmpfmt;
 
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
@@ -1478,10 +1468,10 @@ static int load_module(void)
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (!(oss_tech.capabilities = ast_format_cap_alloc(0))) {
+	if (!(oss_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_format_cap_append(oss_tech.capabilities, ast_format_slin, 0);
+	ast_format_cap_add(oss_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 
 	/* TODO XXX CONSOLE VIDEO IS DISABLE UNTIL IT HAS A MAINTAINER
 	 * add console_video_formats to oss_tech.capabilities once this occurs. */
@@ -1516,11 +1506,8 @@ static int unload_module(void)
 		ast_free(o);
 		o = next;
 	}
-	ao2_cleanup(oss_tech.capabilities);
-	oss_tech.capabilities = NULL;
-
+	oss_tech.capabilities = ast_format_cap_destroy(oss_tech.capabilities);
 	return 0;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "OSS Console Channel Driver");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index 390e250..3d5c7d2 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -25,14 +25,6 @@
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_phone.c uses the configuration file \ref phone.conf
- * \addtogroup configuration_file
- */
-
-/*! \page phone.conf phone.conf
- * \verbinclude phone.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>ixjuser</depend>
 	<support_level>extended</support_level>
@@ -40,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426570 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <sys/socket.h>
@@ -67,8 +59,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426570 $")
 #include "asterisk/causes.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/musiconhold.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_compatibility.h"
 
 #include "chan_phone.h"
 
@@ -136,8 +126,8 @@ static struct phone_pvt {
 	int fd;							/* Raw file descriptor for this device */
 	struct ast_channel *owner;		/* Channel we belong to, possibly NULL */
 	int mode;						/* Is this in the  */
-	struct ast_format *lastformat;            /* Last output format */
-	struct ast_format *lastinput;             /* Last input format */
+	struct ast_format lastformat;            /* Last output format */
+	struct ast_format lastinput;             /* Last input format */
 	int ministate;					/* Miniature state, for dialtone mode */
 	char dev[256];					/* Device name */
 	struct phone_pvt *next;			/* Next channel in list */
@@ -161,7 +151,7 @@ static struct phone_pvt {
 static char cid_num[AST_MAX_EXTENSION];
 static char cid_name[AST_MAX_EXTENSION];
 
-static struct ast_channel *phone_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *phone_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int phone_digit_begin(struct ast_channel *ast, char digit);
 static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int phone_call(struct ast_channel *ast, const char *dest, int timeout);
@@ -220,8 +210,7 @@ static int phone_indicate(struct ast_channel *chan, int condition, const void *d
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
 		usleep(320000);
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
-		ao2_cleanup(p->lastformat);
-		p->lastformat = NULL;
+		ast_format_clear(&p->lastformat);
 		res = 0;
 		break;
 	case AST_CONTROL_HOLD:
@@ -285,8 +274,7 @@ static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int dur
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
 		usleep(320000);
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
-		ao2_cleanup(p->lastformat);
-		p->lastformat = NULL;
+		ast_format_clear(&p->lastformat);
 		return 0;
 	default:
 		ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
@@ -294,8 +282,7 @@ static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int dur
 	}
 	ast_debug(1, "Dialed %d\n", outdigit);
 	ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
-	ao2_cleanup(p->lastformat);
-	p->lastformat = NULL;
+	ast_format_clear(&p->lastformat);
 	return 0;
 }
 
@@ -386,10 +373,8 @@ static int phone_hangup(struct ast_channel *ast)
 		ioctl(p->fd, PHONE_BUSY);
 		p->cpt = 1;
 	}
-	ao2_cleanup(p->lastformat);
-	p->lastformat = NULL;
-	ao2_cleanup(p->lastinput);
-	p->lastinput = NULL;
+	ast_format_clear(&p->lastformat);
+	ast_format_clear(&p->lastinput);
 	p->ministate = 0;
 	p->obuflen = 0;
 	p->dialtone = 0;
@@ -409,38 +394,38 @@ static int phone_setup(struct ast_channel *ast)
 	p = ast_channel_tech_pvt(ast);
 	ioctl(p->fd, PHONE_CPT_STOP);
 	/* Nothing to answering really, just start recording */
-	if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
+	if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G729A) {
 		/* Prefer g729 */
 		ioctl(p->fd, PHONE_REC_STOP);
-		if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_g729) != AST_FORMAT_CMP_EQUAL)) {
-			ao2_replace(p->lastinput, ast_format_g729);
+		if (p->lastinput.id != AST_FORMAT_G729A) {
+			ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0);
 			if (ioctl(p->fd, PHONE_REC_CODEC, G729)) {
 				ast_log(LOG_WARNING, "Failed to set codec to g729\n");
 				return -1;
 			}
 		}
-	} else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
+        } else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G723_1) {
 		ioctl(p->fd, PHONE_REC_STOP);
-		if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_g723) != AST_FORMAT_CMP_EQUAL)) {
-			ao2_replace(p->lastinput, ast_format_g723);
+		if (p->lastinput.id != AST_FORMAT_G723_1) {
+			ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0);
 			if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
 				ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
 				return -1;
 			}
 		}
-	} else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	} else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) {
 		ioctl(p->fd, PHONE_REC_STOP);
-		if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_slin) != AST_FORMAT_CMP_EQUAL)) {
-			ao2_replace(p->lastinput, ast_format_slin);
+		if (p->lastinput.id != AST_FORMAT_SLINEAR) {
+			ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0);
 			if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
 				ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
 				return -1;
 			}
 		}
-	} else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	} else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) {
 		ioctl(p->fd, PHONE_REC_STOP);
-		if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) {
-			ao2_replace(p->lastinput, ast_format_ulaw);
+		if (p->lastinput.id != AST_FORMAT_ULAW) {
+			ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0);
 			if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
 				ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
 				return -1;
@@ -448,16 +433,16 @@ static int phone_setup(struct ast_channel *ast)
 		}
 	} else if (p->mode == MODE_FXS) {
 		ioctl(p->fd, PHONE_REC_STOP);
-		if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_channel_rawreadformat(ast)) == AST_FORMAT_CMP_NOT_EQUAL)) {
-			ao2_replace(p->lastinput, ast_channel_rawreadformat(ast));
+		if (ast_format_cmp(&p->lastinput, ast_channel_rawreadformat(ast)) == AST_FORMAT_CMP_NOT_EQUAL) {
+			ast_format_copy(&p->lastinput, ast_channel_rawreadformat(ast));
 			if (ioctl(p->fd, PHONE_REC_CODEC, ast_channel_rawreadformat(ast))) {
 				ast_log(LOG_WARNING, "Failed to set codec to %s\n", 
-					ast_format_get_name(ast_channel_rawreadformat(ast)));
+					ast_getformatname(ast_channel_rawreadformat(ast)));
 				return -1;
 			}
 		}
 	} else {
-		ast_log(LOG_WARNING, "Can't do format %s\n", ast_format_get_name(ast_channel_rawreadformat(ast)));
+		ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast_channel_rawreadformat(ast)));
 		return -1;
 	}
 	if (ioctl(p->fd, PHONE_REC_START)) {
@@ -608,13 +593,13 @@ static struct ast_frame  *phone_read(struct ast_channel *ast)
 	}
 	p->fr.samples = 240;
 	p->fr.datalen = res;
-	p->fr.frametype = ast_format_get_type(p->lastinput) == AST_MEDIA_TYPE_AUDIO ?
-		AST_FRAME_VOICE : ast_format_get_type(p->lastinput) == AST_MEDIA_TYPE_IMAGE ?
+	p->fr.frametype = AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_AUDIO ?
+		AST_FRAME_VOICE : AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_IMAGE ?
 		AST_FRAME_IMAGE : AST_FRAME_VIDEO;
-	p->fr.subclass.format = p->lastinput;
+	ast_format_copy(&p->fr.subclass.format, &p->lastinput);
 	p->fr.offset = AST_FRIENDLY_OFFSET;
 	/* Byteswap from little-endian to native-endian */
-	if (ast_format_cmp(p->fr.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)
+	if (p->fr.subclass.format.id == AST_FORMAT_SLINEAR)
 		ast_frame_byteswap_le(&p->fr);
 	return &p->fr;
 }
@@ -676,6 +661,14 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 			ast_log(LOG_WARNING, "Don't know what to do with  frame type '%u'\n", frame->frametype);
 		return 0;
 	}
+	if (!(frame->subclass.format.id == AST_FORMAT_G723_1 ||
+		frame->subclass.format.id == AST_FORMAT_SLINEAR ||
+		frame->subclass.format.id == AST_FORMAT_ULAW ||
+		frame->subclass.format.id == AST_FORMAT_G729A) &&
+	    p->mode != MODE_FXS) {
+		ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format));
+		return -1;
+	}
 #if 0
 	/* If we're not in up mode, go into up mode now */
 	if (ast->_state != AST_STATE_UP) {
@@ -688,8 +681,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 		return 0;
 	}
 #endif	
-	if (ast_format_cmp(frame->subclass.format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
-		if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_g729) != AST_FORMAT_CMP_EQUAL)) {
+	if (frame->subclass.format.id == AST_FORMAT_G729A) {
+		if (p->lastformat.id != AST_FORMAT_G729A) {
 			ioctl(p->fd, PHONE_PLAY_STOP);
 			ioctl(p->fd, PHONE_REC_STOP);
 			if (ioctl(p->fd, PHONE_PLAY_CODEC, G729)) {
@@ -700,8 +693,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 				ast_log(LOG_WARNING, "Unable to set G729 mode\n");
 				return -1;
 			}
-			ao2_replace(p->lastformat, ast_format_g729);
-			ao2_replace(p->lastinput, ast_format_g729);
+			ast_format_set(&p->lastformat, AST_FORMAT_G729A, 0);
+			ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0);
 			/* Reset output buffer */
 			p->obuflen = 0;
 			codecset = 1;
@@ -711,8 +704,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 			return -1;
 		}
 		maxfr = 80;
-    } else if (ast_format_cmp(frame->subclass.format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
-		if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_g723) != AST_FORMAT_CMP_EQUAL)) {
+        } else if (frame->subclass.format.id == AST_FORMAT_G723_1) {
+		if (p->lastformat.id != AST_FORMAT_G723_1) {
 			ioctl(p->fd, PHONE_PLAY_STOP);
 			ioctl(p->fd, PHONE_REC_STOP);
 			if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
@@ -723,8 +716,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 				ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
 				return -1;
 			}
-			ao2_replace(p->lastformat, ast_format_g723);
-			ao2_replace(p->lastinput, ast_format_g723);
+			ast_format_set(&p->lastformat, AST_FORMAT_G723_1, 0);
+			ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0);
 			/* Reset output buffer */
 			p->obuflen = 0;
 			codecset = 1;
@@ -734,8 +727,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 			return -1;
 		}
 		maxfr = 24;
-	} else if (ast_format_cmp(frame->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
-		if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_slin) != AST_FORMAT_CMP_EQUAL)) {
+	} else if (frame->subclass.format.id == AST_FORMAT_SLINEAR) {
+		if (p->lastformat.id != AST_FORMAT_SLINEAR) {
 			ioctl(p->fd, PHONE_PLAY_STOP);
 			ioctl(p->fd, PHONE_REC_STOP);
 			if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
@@ -746,15 +739,15 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 				ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
 				return -1;
 			}
-			ao2_replace(p->lastformat, ast_format_slin);
-			ao2_replace(p->lastinput, ast_format_slin);
+			ast_format_set(&p->lastformat, AST_FORMAT_SLINEAR, 0);
+			ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0);
 			codecset = 1;
 			/* Reset output buffer */
 			p->obuflen = 0;
 		}
 		maxfr = 480;
-	} else if (ast_format_cmp(frame->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
-		if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) {
+	} else if (frame->subclass.format.id == AST_FORMAT_ULAW) {
+		if (p->lastformat.id != AST_FORMAT_ULAW) {
 			ioctl(p->fd, PHONE_PLAY_STOP);
 			ioctl(p->fd, PHONE_REC_STOP);
 			if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
@@ -765,29 +758,29 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 				ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
 				return -1;
 			}
-			ao2_replace(p->lastformat, ast_format_ulaw);
-			ao2_replace(p->lastinput, ast_format_ulaw);
+			ast_format_set(&p->lastformat, AST_FORMAT_ULAW, 0);
+			ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0);
 			codecset = 1;
 			/* Reset output buffer */
 			p->obuflen = 0;
 		}
 		maxfr = 240;
 	} else {
-		if (!p->lastformat || (ast_format_cmp(p->lastformat, frame->subclass.format) != AST_FORMAT_CMP_EQUAL)) {
+		if (ast_format_cmp(&p->lastformat, &frame->subclass.format) != AST_FORMAT_CMP_EQUAL) {
 			ioctl(p->fd, PHONE_PLAY_STOP);
 			ioctl(p->fd, PHONE_REC_STOP);
-			if (ioctl(p->fd, PHONE_PLAY_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) {
+			if (ioctl(p->fd, PHONE_PLAY_CODEC, (int) frame->subclass.format.id)) {
 				ast_log(LOG_WARNING, "Unable to set %s mode\n",
-					ast_format_get_name(frame->subclass.format));
+					ast_getformatname(&frame->subclass.format));
 				return -1;
 			}
-			if (ioctl(p->fd, PHONE_REC_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) {
+			if (ioctl(p->fd, PHONE_REC_CODEC, (int) frame->subclass.format.id)) {
 				ast_log(LOG_WARNING, "Unable to set %s mode\n",
-					ast_format_get_name(frame->subclass.format));
+					ast_getformatname(&frame->subclass.format));
 				return -1;
 			}
-			ao2_replace(p->lastformat, frame->subclass.format);
-			ao2_replace(p->lastinput, frame->subclass.format);
+			ast_format_copy(&p->lastformat, &frame->subclass.format);
+			ast_format_copy(&p->lastinput, &frame->subclass.format);
 			codecset = 1;
 			/* Reset output buffer */
 			p->obuflen = 0;
@@ -827,7 +820,7 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 		} else {
 			int swap = 0;
 #if __BYTE_ORDER == __BIG_ENDIAN
-			if (ast_format_cmp(frame->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)
+			if (frame->subclass.format.id == AST_FORMAT_SLINEAR)
 				swap = 1; /* Swap big-endian samples to little-endian as we copy */
 #endif
 			res = phone_write_buf(p, pos, expected, maxfr, swap);
@@ -854,36 +847,31 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
 	return 0;
 }
 
-static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, const char *linkedid)
 {
-	struct ast_format_cap *caps = NULL;
 	struct ast_channel *tmp;
 	struct phone_codec_data queried_codec;
-	struct ast_format *tmpfmt;
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, assignedids, requestor, 0, "Phone/%s", i->dev + 5);
-	if (tmp && caps) {
-		ast_channel_lock(tmp);
+	struct ast_format tmpfmt;
+	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, linkedid, 0, "Phone/%s", i->dev + 5);
+	if (tmp) {
 		ast_channel_tech_set(tmp, cur_tech);
 		ast_channel_set_fd(tmp, 0, i->fd);
 		/* XXX Switching formats silently causes kernel panics XXX */
 		if (i->mode == MODE_FXS &&
 		    ioctl(i->fd, PHONE_QUERY_CODEC, &queried_codec) == 0) {
 			if (queried_codec.type == LINEAR16) {
-				ast_format_cap_append(caps, ast_format_slin, 0);
+				ast_format_cap_add(ast_channel_nativeformats(tmp), ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+				ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+				ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
 			} else {
-				ast_format_cap_remove(prefcap, ast_format_slin);
-				ast_format_cap_append_from_cap(caps, prefcap, AST_MEDIA_TYPE_UNKNOWN);
+				ast_format_cap_remove(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 			}
 		} else {
-			ast_format_cap_append_from_cap(caps, prefcap, AST_MEDIA_TYPE_UNKNOWN);
+			ast_format_cap_copy(ast_channel_nativeformats(tmp), prefcap);
+			ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+			ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+			ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
 		}
-		tmpfmt = ast_format_cap_get_format(caps, 0);
-		ast_channel_nativeformats_set(tmp, caps);
-		ao2_ref(caps, -1);
-		ast_channel_set_rawreadformat(tmp, tmpfmt);
-		ast_channel_set_rawwriteformat(tmp, tmpfmt);
-		ao2_ref(tmpfmt, -1);
 		/* no need to call ast_setstate: the channel_alloc already did its job */
 		if (state == AST_STATE_RING)
 			ast_channel_rings_set(tmp, 1);
@@ -905,7 +893,6 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx,
 
 		i->owner = tmp;
 		ast_module_ref(ast_module_info->self);
-		ast_channel_unlock(tmp);
 		if (state != AST_STATE_DOWN) {
 			if (state == AST_STATE_RING) {
 				ioctl(ast_channel_fd(tmp, 0), PHONE_RINGBACK);
@@ -916,10 +903,8 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx,
 				ast_hangup(tmp);
 			}
 		}
-	} else {
-		ao2_cleanup(caps);
+	} else
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
-	}
 	return tmp;
 }
 
@@ -959,14 +944,14 @@ static void phone_check_exception(struct phone_pvt *i)
 			     !phonee.bits.dtmf_ready) &&
 			    ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
 				/* It's a valid extension in its context, get moving! */
-				phone_new(i, AST_STATE_RING, i->context, NULL, NULL);
+				phone_new(i, AST_STATE_RING, i->context, NULL);
 				/* No need to restart monitor, we are the monitor */
 			} else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
 				/* There is nothing in the specified extension that can match anymore.
 				   Try the default */
 				if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
 					/* Check the default, too... */
-					phone_new(i, AST_STATE_RING, "default", NULL, NULL);
+					phone_new(i, AST_STATE_RING, "default", NULL);
 					/* XXX This should probably be justified better XXX */
 				}  else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
 					/* It's not a valid extension, give a busy signal */
@@ -984,7 +969,7 @@ static void phone_check_exception(struct phone_pvt *i)
 		offhook = ioctl(i->fd, PHONE_HOOKSTATE);
 		if (offhook) {
 			if (i->mode == MODE_IMMEDIATE) {
-				phone_new(i, AST_STATE_RING, i->context, NULL, NULL);
+				phone_new(i, AST_STATE_RING, i->context, NULL);
 			} else if (i->mode == MODE_DIALTONE) {
 				ast_module_ref(ast_module_info->self);
 				/* Reset the extension */
@@ -994,8 +979,7 @@ static void phone_check_exception(struct phone_pvt *i)
 				ioctl(i->fd, PHONE_PLAY_STOP);
 				ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
 				ioctl(i->fd, PHONE_PLAY_START);
-				ao2_cleanup(i->lastformat);
-				i->lastformat = NULL;
+				ast_format_clear(&i->lastformat);
 			} else if (i->mode == MODE_SIGMA) {
 				ast_module_ref(ast_module_info->self);
 				/* Reset the extension */
@@ -1016,13 +1000,12 @@ static void phone_check_exception(struct phone_pvt *i)
 			ioctl(i->fd, PHONE_PLAY_STOP);
 			ioctl(i->fd, PHONE_REC_STOP);
 			i->dialtone = 0;
-			ao2_cleanup(i->lastformat);
-			i->lastformat = NULL;
+			ast_format_clear(&i->lastformat);
 		}
 	}
 	if (phonee.bits.pstn_ring) {
 		ast_verbose("Unit is ringing\n");
-		phone_new(i, AST_STATE_RING, i->context, NULL, NULL);
+		phone_new(i, AST_STATE_RING, i->context, NULL);
 	}
 	if (phonee.bits.caller_id)
 		ast_verbose("We have caller ID\n");
@@ -1229,10 +1212,8 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai
 		flags = fcntl(tmp->fd, F_GETFL);
 		fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
 		tmp->owner = NULL;
-		ao2_cleanup(tmp->lastformat);
-		tmp->lastformat = NULL;
-		ao2_cleanup(tmp->lastinput);
-		tmp->lastinput = NULL;
+		ast_format_clear(&tmp->lastformat);
+		ast_format_clear(&tmp->lastinput);
 		tmp->ministate = 0;
 		memset(tmp->ext, 0, sizeof(tmp->ext));
 		ast_copy_string(tmp->language, language, sizeof(tmp->language));
@@ -1252,7 +1233,7 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai
 	return tmp;
 }
 
-static struct ast_channel *phone_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *phone_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
 	struct phone_pvt *p;
 	struct ast_channel *tmp = NULL;
@@ -1265,12 +1246,12 @@ static struct ast_channel *phone_request(const char *type, struct ast_format_cap
 	}
 	p = iflist;
 	while(p) {
-		if (p->mode == MODE_FXS || (ast_format_cap_iscompatible(cap, phone_tech.capabilities))) {
+		if (p->mode == MODE_FXS || (ast_format_cap_has_joint(cap, phone_tech.capabilities))) {
 			size_t length = strlen(p->dev + 5);
     		if (strncmp(name, p->dev + 5, length) == 0 &&
     		    !isalnum(name[length])) {
     		    if (!p->owner) {
-                     tmp = phone_new(p, AST_STATE_DOWN, p->context, assignedids, requestor);
+                     tmp = phone_new(p, AST_STATE_DOWN, p->context, requestor ? ast_channel_linkedid(requestor) : NULL);
                      break;
                 } else
                      *cause = AST_CAUSE_BUSY;
@@ -1281,10 +1262,9 @@ static struct ast_channel *phone_request(const char *type, struct ast_format_cap
 	ast_mutex_unlock(&iflock);
 	restart_monitor();
 	if (tmp == NULL) {
-		if (!(ast_format_cap_iscompatible(cap, phone_tech.capabilities))) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
-			ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
-				ast_format_cap_get_names(cap, &codec_buf));
+		if (!(ast_format_cap_has_joint(cap, phone_tech.capabilities))) {
+			char buf[256];
+			ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
 			return NULL;
 		}
 	}
@@ -1367,10 +1347,9 @@ static int __unload_module(void)
 		return -1;
 	}
 
-	ao2_ref(phone_tech.capabilities, -1);
-	ao2_ref(phone_tech_fxs.capabilities, -1);
-	ao2_ref(prefcap, -1);
-
+	phone_tech.capabilities = ast_format_cap_destroy(phone_tech.capabilities);
+	phone_tech_fxs.capabilities = ast_format_cap_destroy(phone_tech_fxs.capabilities);
+	prefcap = ast_format_cap_destroy(prefcap);
 	return 0;
 }
 
@@ -1387,21 +1366,21 @@ static int load_module(void)
 	int mode = MODE_IMMEDIATE;
 	int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
 	struct ast_flags config_flags = { 0 };
+	struct ast_format tmpfmt;
 
-	if (!(phone_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(phone_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
+	ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0));
+	ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0));
 
-	ast_format_cap_append(phone_tech.capabilities, ast_format_g723, 0);
-	ast_format_cap_append(phone_tech.capabilities, ast_format_slin, 0);
-	ast_format_cap_append(phone_tech.capabilities, ast_format_ulaw, 0);
-	ast_format_cap_append(phone_tech.capabilities, ast_format_g729, 0);
-
-	if (!(prefcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(prefcap = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append_from_cap(prefcap, phone_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
-	if (!(phone_tech_fxs.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	ast_format_cap_copy(prefcap, phone_tech.capabilities);
+	if (!(phone_tech_fxs.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -1451,7 +1430,7 @@ static int load_module(void)
 				mode = MODE_IMMEDIATE;
 			else if (!strncasecmp(v->value, "fxs", 3)) {
 				mode = MODE_FXS;
-				ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_AUDIO); /* All non-voice */
+				ast_format_cap_remove_bytype(prefcap, AST_FORMAT_TYPE_AUDIO); /* All non-voice */
 			}
 			else if (!strncasecmp(v->value, "fx", 2))
 				mode = MODE_FXO;
@@ -1461,21 +1440,18 @@ static int load_module(void)
 			ast_copy_string(context, v->value, sizeof(context));
 		} else if (!strcasecmp(v->name, "format")) {
 			if (!strcasecmp(v->value, "g729")) {
-				ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append(prefcap, ast_format_g729, 0);
+				ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0));
 			} else if (!strcasecmp(v->value, "g723.1")) {
-				ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append(prefcap, ast_format_g723, 0);
+				ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0));
 			} else if (!strcasecmp(v->value, "slinear")) {
+				ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);
 				if (mode == MODE_FXS) {
-					ast_format_cap_append(prefcap, ast_format_slin, 0);
+					ast_format_cap_add(prefcap, &tmpfmt);
 				} else {
-					ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN);
-					ast_format_cap_append(prefcap, ast_format_slin, 0);
+					ast_format_cap_set(prefcap, &tmpfmt);
 				}
 			} else if (!strcasecmp(v->value, "ulaw")) {
-				ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append(prefcap, ast_format_ulaw, 0);
+				ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
 			} else
 				ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
 		} else if (!strcasecmp(v->name, "echocancel")) {
@@ -1499,7 +1475,7 @@ static int load_module(void)
 	ast_mutex_unlock(&iflock);
 
 	if (mode == MODE_FXS) {
-		ast_format_cap_append_from_cap(phone_tech_fxs.capabilities, prefcap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(phone_tech_fxs.capabilities, prefcap);
 		cur_tech = &phone_tech_fxs;
 	} else
 		cur_tech = (struct ast_channel_tech *) &phone_tech;
@@ -1518,5 +1494,4 @@ static int load_module(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Linux Telephony API Support");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Linux Telephony API Support");
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
deleted file mode 100644
index 4c03e1a..0000000
--- a/channels/chan_pjsip.c
+++ /dev/null
@@ -1,2332 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- * \brief PSJIP SIP Channel Driver
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjlib.h>
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428302 $")
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/rtp_engine.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/causes.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/dsp.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/indications.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/translate.h"
-#include "asterisk/threadstorage.h"
-#include "asterisk/features_config.h"
-#include "asterisk/pickup.h"
-#include "asterisk/test.h"
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-
-#include "pjsip/include/chan_pjsip.h"
-#include "pjsip/include/dialplan_functions.h"
-
-AST_THREADSTORAGE(uniqueid_threadbuf);
-#define UNIQUEID_BUFSIZE 256
-
-static const char desc[] = "PJSIP Channel";
-static const char channel_type[] = "PJSIP";
-
-static unsigned int chan_idx;
-
-static void chan_pjsip_pvt_dtor(void *obj)
-{
-	struct chan_pjsip_pvt *pvt = obj;
-	int i;
-
-	for (i = 0; i < SIP_MEDIA_SIZE; ++i) {
-		ao2_cleanup(pvt->media[i]);
-		pvt->media[i] = NULL;
-	}
-}
-
-/* \brief Asterisk core interaction functions */
-static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
-static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text);
-static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit);
-static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeout);
-static int chan_pjsip_hangup(struct ast_channel *ast);
-static int chan_pjsip_answer(struct ast_channel *ast);
-static struct ast_frame *chan_pjsip_read(struct ast_channel *ast);
-static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *f);
-static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int chan_pjsip_transfer(struct ast_channel *ast, const char *target);
-static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int chan_pjsip_devicestate(const char *data);
-static int chan_pjsip_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
-static const char *chan_pjsip_get_uniqueid(struct ast_channel *ast);
-
-/*! \brief PBX interface structure for channel registration */
-struct ast_channel_tech chan_pjsip_tech = {
-	.type = channel_type,
-	.description = "PJSIP Channel Driver",
-	.requester = chan_pjsip_request,
-	.send_text = chan_pjsip_sendtext,
-	.send_digit_begin = chan_pjsip_digit_begin,
-	.send_digit_end = chan_pjsip_digit_end,
-	.call = chan_pjsip_call,
-	.hangup = chan_pjsip_hangup,
-	.answer = chan_pjsip_answer,
-	.read = chan_pjsip_read,
-	.write = chan_pjsip_write,
-	.write_video = chan_pjsip_write,
-	.exception = chan_pjsip_read,
-	.indicate = chan_pjsip_indicate,
-	.transfer = chan_pjsip_transfer,
-	.fixup = chan_pjsip_fixup,
-	.devicestate = chan_pjsip_devicestate,
-	.queryoption = chan_pjsip_queryoption,
-	.func_channel_read = pjsip_acf_channel_read,
-	.get_pvt_uniqueid = chan_pjsip_get_uniqueid,
-	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
-};
-
-/*! \brief SIP session interaction functions */
-static void chan_pjsip_session_begin(struct ast_sip_session *session);
-static void chan_pjsip_session_end(struct ast_sip_session *session);
-static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
-static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
-
-/*! \brief SIP session supplement structure */
-static struct ast_sip_session_supplement chan_pjsip_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
-	.session_begin = chan_pjsip_session_begin,
-	.session_end = chan_pjsip_session_end,
-	.incoming_request = chan_pjsip_incoming_request,
-	.incoming_response = chan_pjsip_incoming_response,
-	/* It is important that this supplement runs after media has been negotiated */
-	.response_priority = AST_SIP_SESSION_AFTER_MEDIA,
-};
-
-static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
-
-static struct ast_sip_session_supplement chan_pjsip_ack_supplement = {
-	.method = "ACK",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
-	.incoming_request = chan_pjsip_incoming_ack,
-};
-
-/*! \brief Function called by RTP engine to get local audio RTP peer */
-static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_endpoint *endpoint;
-
-	if (!pvt || !channel->session || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
-		return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	endpoint = channel->session->endpoint;
-
-	*instance = pvt->media[SIP_MEDIA_AUDIO]->rtp;
-	ao2_ref(*instance, +1);
-
-	ast_assert(endpoint != NULL);
-	if (endpoint->media.rtp.encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
-		return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	if (endpoint->media.direct_media.enabled) {
-		return AST_RTP_GLUE_RESULT_REMOTE;
-	}
-
-	return AST_RTP_GLUE_RESULT_LOCAL;
-}
-
-/*! \brief Function called by RTP engine to get local video RTP peer */
-static enum ast_rtp_glue_result chan_pjsip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_endpoint *endpoint;
-
-	if (!pvt || !channel->session || !pvt->media[SIP_MEDIA_VIDEO]->rtp) {
-		return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	endpoint = channel->session->endpoint;
-
-	*instance = pvt->media[SIP_MEDIA_VIDEO]->rtp;
-	ao2_ref(*instance, +1);
-
-	ast_assert(endpoint != NULL);
-	if (endpoint->media.rtp.encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
-		return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-	return AST_RTP_GLUE_RESULT_LOCAL;
-}
-
-/*! \brief Function called by RTP engine to get peer capabilities */
-static void chan_pjsip_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-
-	ast_format_cap_append_from_cap(result, channel->session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN);
-}
-
-static int send_direct_media_request(void *data)
-{
-	RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
-
-	return ast_sip_session_refresh(session, NULL, NULL, NULL,
-			session->endpoint->media.direct_media.method, 1);
-}
-
-/*! \brief Destructor function for \ref transport_info_data */
-static void transport_info_destroy(void *obj)
-{
-	struct transport_info_data *data = obj;
-	ast_free(data);
-}
-
-/*! \brief Datastore used to store local/remote addresses for the
- * INVITE request that created the PJSIP channel */
-static struct ast_datastore_info transport_info = {
-	.type = "chan_pjsip_transport_info",
-	.destroy = transport_info_destroy,
-};
-
-static struct ast_datastore_info direct_media_mitigation_info = { };
-
-static int direct_media_mitigate_glare(struct ast_sip_session *session)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-
-	if (session->endpoint->media.direct_media.glare_mitigation ==
-			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
-		return 0;
-	}
-
-	datastore = ast_sip_session_get_datastore(session, "direct_media_glare_mitigation");
-	if (!datastore) {
-		return 0;
-	}
-
-	/* Removing the datastore ensures we won't try to mitigate glare on subsequent reinvites */
-	ast_sip_session_remove_datastore(session, "direct_media_glare_mitigation");
-
-	if ((session->endpoint->media.direct_media.glare_mitigation ==
-			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING &&
-			session->inv_session->role == PJSIP_ROLE_UAC) ||
-			(session->endpoint->media.direct_media.glare_mitigation ==
-			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING &&
-			session->inv_session->role == PJSIP_ROLE_UAS)) {
-		return 1;
-	}
-
-	return 0;
-}
-
-static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp,
-		struct ast_sip_session_media *media, int rtcp_fd)
-{
-	int changed = 0;
-
-	if (rtp) {
-		changed = ast_rtp_instance_get_and_cmp_remote_address(rtp, &media->direct_media_addr);
-		if (media->rtp) {
-			ast_channel_set_fd(chan, rtcp_fd, -1);
-			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 0);
-		}
-	} else if (!ast_sockaddr_isnull(&media->direct_media_addr)){
-		ast_sockaddr_setnull(&media->direct_media_addr);
-		changed = 1;
-		if (media->rtp) {
-			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1);
-			ast_channel_set_fd(chan, rtcp_fd, ast_rtp_instance_fd(media->rtp, 1));
-		}
-	}
-
-	return changed;
-}
-
-/*! \brief Function called by RTP engine to change where the remote party should send media */
-static int chan_pjsip_set_rtp_peer(struct ast_channel *chan,
-		struct ast_rtp_instance *rtp,
-		struct ast_rtp_instance *vrtp,
-		struct ast_rtp_instance *tpeer,
-		const struct ast_format_cap *cap,
-		int nat_active)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session *session = channel->session;
-	int changed = 0;
-
-	/* Don't try to do any direct media shenanigans on early bridges */
-	if ((rtp || vrtp || tpeer) && !ast_channel_is_bridged(chan)) {
-		ast_debug(4, "Disregarding setting RTP on %s: channel is not bridged\n", ast_channel_name(chan));
-		return 0;
-	}
-
-	if (nat_active && session->endpoint->media.direct_media.disable_on_nat) {
-		ast_debug(4, "Disregarding setting RTP on %s: NAT is active\n", ast_channel_name(chan));
-		return 0;
-	}
-
-	if (pvt->media[SIP_MEDIA_AUDIO]) {
-		changed |= check_for_rtp_changes(chan, rtp, pvt->media[SIP_MEDIA_AUDIO], 1);
-	}
-	if (pvt->media[SIP_MEDIA_VIDEO]) {
-		changed |= check_for_rtp_changes(chan, vrtp, pvt->media[SIP_MEDIA_VIDEO], 3);
-	}
-
-	if (direct_media_mitigate_glare(session)) {
-		ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(chan));
-		return 0;
-	}
-
-	if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) {
-		ast_format_cap_remove_by_type(session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(session->direct_media_cap, cap, AST_MEDIA_TYPE_UNKNOWN);
-		changed = 1;
-	}
-
-	if (changed) {
-		ao2_ref(session, +1);
-
-		ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(chan));
-		if (ast_sip_push_task(session->serializer, send_direct_media_request, session)) {
-			ao2_cleanup(session);
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Local glue for interacting with the RTP engine core */
-static struct ast_rtp_glue chan_pjsip_rtp_glue = {
-	.type = "PJSIP",
-	.get_rtp_info = chan_pjsip_get_rtp_peer,
-	.get_vrtp_info = chan_pjsip_get_vrtp_peer,
-	.get_codec = chan_pjsip_get_codec,
-	.update_peer = chan_pjsip_set_rtp_peer,
-};
-
-static void set_channel_on_rtp_instance(struct chan_pjsip_pvt *pvt, const char *channel_id)
-{
-	if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
-		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, channel_id);
-	}
-	if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
-		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, channel_id);
-	}
-}
-
-/*! \brief Function called to create a new PJSIP Asterisk channel */
-static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
-{
-	struct ast_channel *chan;
-	struct ast_format_cap *caps;
-	RAII_VAR(struct chan_pjsip_pvt *, pvt, NULL, ao2_cleanup);
-	struct ast_sip_channel_pvt *channel;
-	struct ast_variable *var;
-
-	if (!(pvt = ao2_alloc(sizeof(*pvt), chan_pjsip_pvt_dtor))) {
-		return NULL;
-	}
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return NULL;
-	}
-
-	chan = ast_channel_alloc_with_endpoint(1, state,
-		S_COR(session->id.number.valid, session->id.number.str, ""),
-		S_COR(session->id.name.valid, session->id.name.str, ""),
-		session->endpoint->accountcode, "", "", assignedids, requestor, 0,
-		session->endpoint->persistent, "PJSIP/%s-%08x",
-		ast_sorcery_object_get_id(session->endpoint),
-		(unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1));
-	if (!chan) {
-		ao2_ref(caps, -1);
-		return NULL;
-	}
-
-	ast_channel_tech_set(chan, &chan_pjsip_tech);
-
-	if (!(channel = ast_sip_channel_pvt_alloc(pvt, session))) {
-		ao2_ref(caps, -1);
-		ast_channel_unlock(chan);
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	ast_channel_stage_snapshot(chan);
-
-	ast_channel_tech_pvt_set(chan, channel);
-
-	if (!ast_format_cap_count(session->req_caps) ||
-		!ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) {
-		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN);
-	} else {
-		ast_format_cap_append_from_cap(caps, session->req_caps, AST_MEDIA_TYPE_UNKNOWN);
-	}
-
-	ast_channel_nativeformats_set(chan, caps);
-
-	if (!ast_format_cap_empty(caps)) {
-		/*
-		 * XXX Probably should pick the first audio codec instead
-		 * of simply the first codec.  The first codec may be video.
-		 */
-		struct ast_format *fmt = ast_format_cap_get_format(caps, 0);
-
-		ast_channel_set_writeformat(chan, fmt);
-		ast_channel_set_rawwriteformat(chan, fmt);
-		ast_channel_set_readformat(chan, fmt);
-		ast_channel_set_rawreadformat(chan, fmt);
-		ao2_ref(fmt, -1);
-	}
-
-	ao2_ref(caps, -1);
-
-	if (state == AST_STATE_RING) {
-		ast_channel_rings_set(chan, 1);
-	}
-
-	ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
-
-	ast_party_id_copy(&ast_channel_caller(chan)->id, &session->id);
-	ast_party_id_copy(&ast_channel_caller(chan)->ani, &session->id);
-
-	ast_channel_context_set(chan, session->endpoint->context);
-	ast_channel_exten_set(chan, S_OR(exten, "s"));
-	ast_channel_priority_set(chan, 1);
-
-	ast_channel_callgroup_set(chan, session->endpoint->pickup.callgroup);
-	ast_channel_pickupgroup_set(chan, session->endpoint->pickup.pickupgroup);
-
-	ast_channel_named_callgroups_set(chan, session->endpoint->pickup.named_callgroups);
-	ast_channel_named_pickupgroups_set(chan, session->endpoint->pickup.named_pickupgroups);
-
-	if (!ast_strlen_zero(session->endpoint->language)) {
-		ast_channel_language_set(chan, session->endpoint->language);
-	}
-
-	if (!ast_strlen_zero(session->endpoint->zone)) {
-		struct ast_tone_zone *zone = ast_get_indication_zone(session->endpoint->zone);
-		if (!zone) {
-			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", session->endpoint->zone);
-		}
-		ast_channel_zone_set(chan, zone);
-	}
-
-	for (var = session->endpoint->channel_vars; var; var = var->next) {
-		char buf[512];
-		pbx_builtin_setvar_helper(chan, var->name, ast_get_encoded_str(
-						  var->value, buf, sizeof(buf)));
-	}
-
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
-
-	/* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media
-	 * during a call such as if multiple same-type stream support is introduced,
-	 * these will need to be recaptured as well */
-	pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
-	pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
-	set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(chan));
-
-	return chan;
-}
-
-static int answer(void *data)
-{
-	pj_status_t status = PJ_SUCCESS;
-	pjsip_tx_data *packet = NULL;
-	struct ast_sip_session *session = data;
-
-	if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
-		ao2_ref(session, -1);
-		return 0;
-	}
-
-	pjsip_dlg_inc_lock(session->inv_session->dlg);
-	if (session->inv_session->invite_tsx) {
-		status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet);
-	} else {
-		ast_log(LOG_ERROR,"Cannot answer '%s' because there is no associated SIP transaction\n",
-			ast_channel_name(session->channel));
-	}
-	pjsip_dlg_dec_lock(session->inv_session->dlg);
-
-	if (status == PJ_SUCCESS && packet) {
-		ast_sip_session_send_response(session, packet);
-	}
-
-	ao2_ref(session, -1);
-
-	return (status == PJ_SUCCESS) ? 0 : -1;
-}
-
-/*! \brief Function called by core when we should answer a PJSIP session */
-static int chan_pjsip_answer(struct ast_channel *ast)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-
-	if (ast_channel_state(ast) == AST_STATE_UP) {
-		return 0;
-	}
-
-	ast_setstate(ast, AST_STATE_UP);
-
-	ao2_ref(channel->session, +1);
-	if (ast_sip_push_task(channel->session->serializer, answer, channel->session)) {
-		ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n");
-		ao2_cleanup(channel->session);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Internal helper function called when CNG tone is detected */
-static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *session, struct ast_frame *f)
-{
-	const char *target_context;
-	int exists;
-
-	/* If we only needed this DSP for fax detection purposes we can just drop it now */
-	if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
-		ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT);
-	} else {
-		ast_dsp_free(session->dsp);
-		session->dsp = NULL;
-	}
-
-	/* If already executing in the fax extension don't do anything */
-	if (!strcmp(ast_channel_exten(session->channel), "fax")) {
-		return f;
-	}
-
-	target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel));
-
-	/* We need to unlock the channel here because ast_exists_extension has the
-	 * potential to start and stop an autoservice on the channel. Such action
-	 * is prone to deadlock if the channel is locked.
-	 */
-	ast_channel_unlock(session->channel);
-	exists = ast_exists_extension(session->channel, target_context, "fax", 1,
-		S_COR(ast_channel_caller(session->channel)->id.number.valid,
-			ast_channel_caller(session->channel)->id.number.str, NULL));
-	ast_channel_lock(session->channel);
-
-	if (exists) {
-		ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n",
-			ast_channel_name(session->channel));
-		pbx_builtin_setvar_helper(session->channel, "FAXEXTEN", ast_channel_exten(session->channel));
-		if (ast_async_goto(session->channel, target_context, "fax", 1)) {
-			ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n",
-				ast_channel_name(session->channel), target_context);
-		}
-		ast_frfree(f);
-		f = &ast_null_frame;
-	} else {
-		ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n",
-			ast_channel_name(session->channel), target_context);
-	}
-
-	return f;
-}
-
-/*! \brief Function called by core to read any waiting frames */
-static struct ast_frame *chan_pjsip_read(struct ast_channel *ast)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_frame *f;
-	struct ast_sip_session_media *media = NULL;
-	int rtcp = 0;
-	int fdno = ast_channel_fdno(ast);
-
-	switch (fdno) {
-	case 0:
-		media = pvt->media[SIP_MEDIA_AUDIO];
-		break;
-	case 1:
-		media = pvt->media[SIP_MEDIA_AUDIO];
-		rtcp = 1;
-		break;
-	case 2:
-		media = pvt->media[SIP_MEDIA_VIDEO];
-		break;
-	case 3:
-		media = pvt->media[SIP_MEDIA_VIDEO];
-		rtcp = 1;
-		break;
-	}
-
-	if (!media || !media->rtp) {
-		return &ast_null_frame;
-	}
-
-	if (!(f = ast_rtp_instance_read(media->rtp, rtcp))) {
-		return f;
-	}
-
-	if (f->frametype != AST_FRAME_VOICE) {
-		return f;
-	}
-
-	if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_format_cap *caps;
-
-		ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format));
-
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (caps) {
-			ast_format_cap_append(caps, f->subclass.format, 0);
-			ast_channel_nativeformats_set(ast, caps);
-			ao2_ref(caps, -1);
-		}
-
-		ast_set_read_format(ast, ast_channel_readformat(ast));
-		ast_set_write_format(ast, ast_channel_writeformat(ast));
-	}
-
-	if (channel->session->dsp) {
-		f = ast_dsp_process(ast, channel->session->dsp, f);
-
-		if (f && (f->frametype == AST_FRAME_DTMF)) {
-			if (f->subclass.integer == 'f') {
-				ast_debug(3, "Fax CNG detected on %s\n", ast_channel_name(ast));
-				f = chan_pjsip_cng_tone_detected(channel->session, f);
-			} else {
-				ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer,
-					ast_channel_name(ast));
-			}
-		}
-	}
-
-	return f;
-}
-
-/*! \brief Function called by core to write frames */
-static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session_media *media;
-	int res = 0;
-
-	switch (frame->frametype) {
-	case AST_FRAME_VOICE:
-		media = pvt->media[SIP_MEDIA_AUDIO];
-
-		if (!media) {
-			return 0;
-		}
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *cap_buf = ast_str_alloca(128);
-			struct ast_str *write_transpath = ast_str_alloca(256);
-			struct ast_str *read_transpath = ast_str_alloca(256);
-
-			ast_log(LOG_WARNING,
-				"Channel %s asked to send %s frame when native formats are %s (rd:%s->%s;%s wr:%s->%s;%s)\n",
-				ast_channel_name(ast),
-				ast_format_get_name(frame->subclass.format),
-				ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
-				ast_format_get_name(ast_channel_rawreadformat(ast)),
-				ast_format_get_name(ast_channel_readformat(ast)),
-				ast_translate_path_to_str(ast_channel_readtrans(ast), &read_transpath),
-				ast_format_get_name(ast_channel_writeformat(ast)),
-				ast_format_get_name(ast_channel_rawwriteformat(ast)),
-				ast_translate_path_to_str(ast_channel_writetrans(ast), &write_transpath));
-			return 0;
-		}
-		if (media->rtp) {
-			res = ast_rtp_instance_write(media->rtp, frame);
-		}
-		break;
-	case AST_FRAME_VIDEO:
-		if ((media = pvt->media[SIP_MEDIA_VIDEO]) && media->rtp) {
-			res = ast_rtp_instance_write(media->rtp, frame);
-		}
-		break;
-	case AST_FRAME_MODEM:
-		break;
-	default:
-		ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype);
-		break;
-	}
-
-	return res;
-}
-
-/*! \brief Function called by core to change the underlying owner channel */
-static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(newchan);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-
-	if (channel->session->channel != oldchan) {
-		return -1;
-	}
-
-	/*
-	 * The masquerade has suspended the channel's session
-	 * serializer so we can safely change it outside of
-	 * the serializer thread.
-	 */
-	channel->session->channel = newchan;
-
-	set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(newchan));
-
-	return 0;
-}
-
-/*! AO2 hash function for on hold UIDs */
-static int uid_hold_hash_fn(const void *obj, const int flags)
-{
-	const char *key = obj;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		break;
-	case OBJ_SEARCH_OBJECT:
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! AO2 sort function for on hold UIDs */
-static int uid_hold_sort_fn(const void *obj_left, const void *obj_right, const int flags)
-{
-	const char *left = obj_left;
-	const char *right = obj_right;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left, right);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left, right, strlen(right));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-static struct ao2_container *pjsip_uids_onhold;
-
-/*!
- * \brief Add a channel ID to the list of PJSIP channels on hold
- *
- * \param chan_uid - Unique ID of the channel being put into the hold list
- *
- * \retval 0 Channel has been added to or was already in the hold list
- * \retval -1 Failed to add channel to the hold list
- */
-static int chan_pjsip_add_hold(const char *chan_uid)
-{
-	RAII_VAR(char *, hold_uid, NULL, ao2_cleanup);
-
-	hold_uid = ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY);
-	if (hold_uid) {
-		/* Device is already on hold. Nothing to do. */
-		return 0;
-	}
-
-	/* Device wasn't in hold list already. Create a new one. */
-	hold_uid = ao2_alloc_options(strlen(chan_uid) + 1, NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!hold_uid) {
-		return -1;
-	}
-
-	ast_copy_string(hold_uid, chan_uid, strlen(chan_uid) + 1);
-
-	if (ao2_link(pjsip_uids_onhold, hold_uid) == 0) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Remove a channel ID from the list of PJSIP channels on hold
- *
- * \param chan_uid - Unique ID of the channel being taken out of the hold list
- */
-static void chan_pjsip_remove_hold(const char *chan_uid)
-{
-	ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-}
-
-/*!
- * \brief Determine whether a channel ID is in the list of PJSIP channels on hold
- *
- * \param chan_uid - Channel being checked
- *
- * \retval 0 The channel is not in the hold list
- * \retval 1 The channel is in the hold list
- */
-static int chan_pjsip_get_hold(const char *chan_uid)
-{
-	RAII_VAR(char *, hold_uid, NULL, ao2_cleanup);
-
-	hold_uid = ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY);
-	if (!hold_uid) {
-		return 0;
-	}
-
-	return 1;
-}
-
-/*! \brief Function called to get the device state of an endpoint */
-static int chan_pjsip_devicestate(const char *data)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", data), ao2_cleanup);
-	enum ast_device_state state = AST_DEVICE_UNKNOWN;
-	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	struct ast_devstate_aggregate aggregate;
-	int num, inuse = 0;
-
-	if (!endpoint) {
-		return AST_DEVICE_INVALID;
-	}
-
-	endpoint_snapshot = ast_endpoint_latest_snapshot(ast_endpoint_get_tech(endpoint->persistent),
-		ast_endpoint_get_resource(endpoint->persistent));
-
-	if (!endpoint_snapshot) {
-		return AST_DEVICE_INVALID;
-	}
-
-	if (endpoint_snapshot->state == AST_ENDPOINT_OFFLINE) {
-		state = AST_DEVICE_UNAVAILABLE;
-	} else if (endpoint_snapshot->state == AST_ENDPOINT_ONLINE) {
-		state = AST_DEVICE_NOT_INUSE;
-	}
-
-	if (!endpoint_snapshot->num_channels || !(cache = ast_channel_cache())) {
-		return state;
-	}
-
-	ast_devstate_aggregate_init(&aggregate);
-
-	ao2_ref(cache, +1);
-
-	for (num = 0; num < endpoint_snapshot->num_channels; num++) {
-		RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-		struct ast_channel_snapshot *snapshot;
-
-		msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
-			endpoint_snapshot->channel_ids[num]);
-
-		if (!msg) {
-			continue;
-		}
-
-		snapshot = stasis_message_data(msg);
-
-		if (chan_pjsip_get_hold(snapshot->uniqueid)) {
-			ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);
-		} else {
-			ast_devstate_aggregate_add(&aggregate, ast_state_chan2dev(snapshot->state));
-		}
-
-		if ((snapshot->state == AST_STATE_UP) || (snapshot->state == AST_STATE_RING) ||
-			(snapshot->state == AST_STATE_BUSY)) {
-			inuse++;
-		}
-	}
-
-	if (endpoint->devicestate_busy_at && (inuse == endpoint->devicestate_busy_at)) {
-		state = AST_DEVICE_BUSY;
-	} else if (ast_devstate_aggregate_result(&aggregate) != AST_DEVICE_INVALID) {
-		state = ast_devstate_aggregate_result(&aggregate);
-	}
-
-	return state;
-}
-
-/*! \brief Function called to query options on a channel */
-static int chan_pjsip_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct ast_sip_session *session = channel->session;
-	int res = -1;
-	enum ast_sip_session_t38state state = T38_STATE_UNAVAILABLE;
-
-	switch (option) {
-	case AST_OPTION_T38_STATE:
-		if (session->endpoint->media.t38.enabled) {
-			switch (session->t38state) {
-			case T38_LOCAL_REINVITE:
-			case T38_PEER_REINVITE:
-				state = T38_STATE_NEGOTIATING;
-				break;
-			case T38_ENABLED:
-				state = T38_STATE_NEGOTIATED;
-				break;
-			case T38_REJECTED:
-				state = T38_STATE_REJECTED;
-				break;
-			default:
-				state = T38_STATE_UNKNOWN;
-				break;
-			}
-		}
-
-		*((enum ast_t38_state *) data) = state;
-		res = 0;
-
-		break;
-	default:
-		break;
-	}
-
-	return res;
-}
-
-static const char *chan_pjsip_get_uniqueid(struct ast_channel *ast)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	char *uniqueid = ast_threadstorage_get(&uniqueid_threadbuf, UNIQUEID_BUFSIZE);
-
-	if (!uniqueid) {
-		return "";
-	}
-
-	ast_copy_pj_str(uniqueid, &channel->session->inv_session->dlg->call_id->id, UNIQUEID_BUFSIZE);
-
-	return uniqueid;
-}
-
-struct indicate_data {
-	struct ast_sip_session *session;
-	int condition;
-	int response_code;
-	void *frame_data;
-	size_t datalen;
-};
-
-static void indicate_data_destroy(void *obj)
-{
-	struct indicate_data *ind_data = obj;
-
-	ast_free(ind_data->frame_data);
-	ao2_ref(ind_data->session, -1);
-}
-
-static struct indicate_data *indicate_data_alloc(struct ast_sip_session *session,
-		int condition, int response_code, const void *frame_data, size_t datalen)
-{
-	struct indicate_data *ind_data = ao2_alloc(sizeof(*ind_data), indicate_data_destroy);
-
-	if (!ind_data) {
-		return NULL;
-	}
-
-	ind_data->frame_data = ast_malloc(datalen);
-	if (!ind_data->frame_data) {
-		ao2_ref(ind_data, -1);
-		return NULL;
-	}
-
-	memcpy(ind_data->frame_data, frame_data, datalen);
-	ind_data->datalen = datalen;
-	ind_data->condition = condition;
-	ind_data->response_code = response_code;
-	ao2_ref(session, +1);
-	ind_data->session = session;
-
-	return ind_data;
-}
-
-static int indicate(void *data)
-{
-	pjsip_tx_data *packet = NULL;
-	struct indicate_data *ind_data = data;
-	struct ast_sip_session *session = ind_data->session;
-	int response_code = ind_data->response_code;
-
-	if ((session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
-		(pjsip_inv_answer(session->inv_session, response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
-		ast_sip_session_send_response(session, packet);
-	}
-
-	ao2_ref(ind_data, -1);
-
-	return 0;
-}
-
-/*! \brief Send SIP INFO with video update request */
-static int transmit_info_with_vidupdate(void *data)
-{
-	const char * xml =
-		"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
-		" <media_control>\r\n"
-		"  <vc_primitive>\r\n"
-		"   <to_encoder>\r\n"
-		"    <picture_fast_update/>\r\n"
-		"   </to_encoder>\r\n"
-		"  </vc_primitive>\r\n"
-		" </media_control>\r\n";
-
-	const struct ast_sip_body body = {
-		.type = "application",
-		.subtype = "media_control+xml",
-		.body_text = xml
-	};
-
-	RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
-	struct pjsip_tx_data *tdata;
-
-	if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
-		ast_log(LOG_ERROR, "Could not create text video update INFO request\n");
-		return -1;
-	}
-	if (ast_sip_add_body(tdata, &body)) {
-		ast_log(LOG_ERROR, "Could not add body to text video update INFO request\n");
-		return -1;
-	}
-	ast_sip_session_send_request(session, tdata);
-
-	return 0;
-}
-
-/*! \brief Update connected line information */
-static int update_connected_line_information(void *data)
-{
-	RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
-
-	if ((ast_channel_state(session->channel) != AST_STATE_UP) && (session->inv_session->role == PJSIP_UAS_ROLE)) {
-		int response_code = 0;
-
-		if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
-			return 0;
-		}
-
-		if (ast_channel_state(session->channel) == AST_STATE_RING) {
-			response_code = !session->endpoint->inband_progress ? 180 : 183;
-		} else if (ast_channel_state(session->channel) == AST_STATE_RINGING) {
-			response_code = 183;
-		}
-
-		if (response_code) {
-			struct pjsip_tx_data *packet = NULL;
-
-			if (pjsip_inv_answer(session->inv_session, response_code, NULL, NULL, &packet) == PJ_SUCCESS) {
-				ast_sip_session_send_response(session, packet);
-			}
-		}
-	} else {
-		enum ast_sip_session_refresh_method method = session->endpoint->id.refresh_method;
-		int generate_new_sdp;
-		struct ast_party_id connected_id;
-
-		if (session->inv_session->invite_tsx && (session->inv_session->options & PJSIP_INV_SUPPORT_UPDATE)) {
-			method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
-		}
-
-		/* Only the INVITE method actually needs SDP, UPDATE can do without */
-		generate_new_sdp = (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE);
-
-		/*
-		 * We can get away with a shallow copy here because we are
-		 * not looking at strings.
-		 */
-		ast_channel_lock(session->channel);
-		connected_id = ast_channel_connected_effective_id(session->channel);
-		ast_channel_unlock(session->channel);
-
-		if ((session->endpoint->id.send_pai || session->endpoint->id.send_rpid) &&
-		    (session->endpoint->id.trust_outbound ||
-		     ((connected_id.name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
-		      (connected_id.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED))) {
-			ast_sip_session_refresh(session, NULL, NULL, NULL, method, generate_new_sdp);
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Function called by core to ask the channel to indicate some sort of condition */
-static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session_media *media;
-	int response_code = 0;
-	int res = 0;
-	char *device_buf;
-	size_t device_buf_size;
-
-	switch (condition) {
-	case AST_CONTROL_RINGING:
-		if (ast_channel_state(ast) == AST_STATE_RING) {
-			if (channel->session->endpoint->inband_progress) {
-				response_code = 183;
-				res = -1;
-			} else {
-				response_code = 180;
-			}
-		} else {
-			res = -1;
-		}
-		ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_sorcery_object_get_id(channel->session->endpoint));
-		break;
-	case AST_CONTROL_BUSY:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 486;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_CONGESTION:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 503;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_INCOMPLETE:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 484;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_PROCEEDING:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 100;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_PROGRESS:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 183;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_VIDUPDATE:
-		media = pvt->media[SIP_MEDIA_VIDEO];
-		if (media && media->rtp) {
-			/* FIXME: Only use this for VP8. Additional work would have to be done to
-			 * fully support other video codecs */
-
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) {
-				/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
-				 * RTP engine would provide a way to externally write/schedule RTCP
-				 * packets */
-				struct ast_frame fr;
-				fr.frametype = AST_FRAME_CONTROL;
-				fr.subclass.integer = AST_CONTROL_VIDUPDATE;
-				res = ast_rtp_instance_write(media->rtp, &fr);
-			} else {
-				ao2_ref(channel->session, +1);
-
-				if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
-					ao2_cleanup(channel->session);
-				}
-			}
-			ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Success");
-		} else {
-			ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Failure");
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_CONNECTED_LINE:
-		ao2_ref(channel->session, +1);
-		if (ast_sip_push_task(channel->session->serializer, update_connected_line_information, channel->session)) {
-			ao2_cleanup(channel->session);
-		}
-		break;
-	case AST_CONTROL_UPDATE_RTP_PEER:
-		break;
-	case AST_CONTROL_PVT_CAUSE_CODE:
-		res = -1;
-		break;
-	case AST_CONTROL_MASQUERADE_NOTIFY:
-		ast_assert(datalen == sizeof(int));
-		if (*(int *) data) {
-			/*
-			 * Masquerade is beginning:
-			 * Wait for session serializer to get suspended.
-			 */
-			ast_channel_unlock(ast);
-			ast_sip_session_suspend(channel->session);
-			ast_channel_lock(ast);
-		} else {
-			/*
-			 * Masquerade is complete:
-			 * Unsuspend the session serializer.
-			 */
-			ast_sip_session_unsuspend(channel->session);
-		}
-		break;
-	case AST_CONTROL_HOLD:
-		chan_pjsip_add_hold(ast_channel_uniqueid(ast));
-		device_buf_size = strlen(ast_channel_name(ast)) + 1;
-		device_buf = alloca(device_buf_size);
-		ast_channel_get_device_name(ast, device_buf, device_buf_size);
-		ast_devstate_changed_literal(AST_DEVICE_ONHOLD, 1, device_buf);
-		ast_moh_start(ast, data, NULL);
-		break;
-	case AST_CONTROL_UNHOLD:
-		chan_pjsip_remove_hold(ast_channel_uniqueid(ast));
-		device_buf_size = strlen(ast_channel_name(ast)) + 1;
-		device_buf = alloca(device_buf_size);
-		ast_channel_get_device_name(ast, device_buf, device_buf_size);
-		ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, 1, device_buf);
-		ast_moh_stop(ast);
-		break;
-	case AST_CONTROL_SRCUPDATE:
-		break;
-	case AST_CONTROL_SRCCHANGE:
-		break;
-	case AST_CONTROL_REDIRECTING:
-		if (ast_channel_state(ast) != AST_STATE_UP) {
-			response_code = 181;
-		} else {
-			res = -1;
-		}
-		break;
-	case AST_CONTROL_T38_PARAMETERS:
-		res = 0;
-
-		if (channel->session->t38state == T38_PEER_REINVITE) {
-			const struct ast_control_t38_parameters *parameters = data;
-
-			if (parameters->request_response == AST_T38_REQUEST_PARMS) {
-				res = AST_T38_REQUEST_PARMS;
-			}
-		}
-
-		break;
-	case -1:
-		res = -1;
-		break;
-	default:
-		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
-		res = -1;
-		break;
-	}
-
-	if (response_code) {
-		struct indicate_data *ind_data = indicate_data_alloc(channel->session, condition, response_code, data, datalen);
-		if (!ind_data || ast_sip_push_task(channel->session->serializer, indicate, ind_data)) {
-			ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
-					response_code, ast_sorcery_object_get_id(channel->session->endpoint));
-			ao2_cleanup(ind_data);
-			res = -1;
-		}
-	}
-
-	return res;
-}
-
-struct transfer_data {
-	struct ast_sip_session *session;
-	char *target;
-};
-
-static void transfer_data_destroy(void *obj)
-{
-	struct transfer_data *trnf_data = obj;
-
-	ast_free(trnf_data->target);
-	ao2_cleanup(trnf_data->session);
-}
-
-static struct transfer_data *transfer_data_alloc(struct ast_sip_session *session, const char *target)
-{
-	struct transfer_data *trnf_data = ao2_alloc(sizeof(*trnf_data), transfer_data_destroy);
-
-	if (!trnf_data) {
-		return NULL;
-	}
-
-	if (!(trnf_data->target = ast_strdup(target))) {
-		ao2_ref(trnf_data, -1);
-		return NULL;
-	}
-
-	ao2_ref(session, +1);
-	trnf_data->session = session;
-
-	return trnf_data;
-}
-
-static void transfer_redirect(struct ast_sip_session *session, const char *target)
-{
-	pjsip_tx_data *packet;
-	enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
-	pjsip_contact_hdr *contact;
-	pj_str_t tmp;
-
-	if (pjsip_inv_end_session(session->inv_session, 302, NULL, &packet) != PJ_SUCCESS) {
-		message = AST_TRANSFER_FAILED;
-		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-
-		return;
-	}
-
-	if (!(contact = pjsip_msg_find_hdr(packet->msg, PJSIP_H_CONTACT, NULL))) {
-		contact = pjsip_contact_hdr_create(packet->pool);
-	}
-
-	pj_strdup2_with_null(packet->pool, &tmp, target);
-	if (!(contact->uri = pjsip_parse_uri(packet->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR))) {
-		message = AST_TRANSFER_FAILED;
-		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-		pjsip_tx_data_dec_ref(packet);
-
-		return;
-	}
-	pjsip_msg_add_hdr(packet->msg, (pjsip_hdr *) contact);
-
-	ast_sip_session_send_response(session, packet);
-	ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-}
-
-static void transfer_refer(struct ast_sip_session *session, const char *target)
-{
-	pjsip_evsub *sub;
-	enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
-	pj_str_t tmp;
-	pjsip_tx_data *packet;
-
-	if (pjsip_xfer_create_uac(session->inv_session->dlg, NULL, &sub) != PJ_SUCCESS) {
-		message = AST_TRANSFER_FAILED;
-		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-
-		return;
-	}
-
-	if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
-		message = AST_TRANSFER_FAILED;
-		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-		pjsip_evsub_terminate(sub, PJ_FALSE);
-
-		return;
-	}
-
-	pjsip_xfer_send_request(sub, packet);
-	ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
-}
-
-static int transfer(void *data)
-{
-	struct transfer_data *trnf_data = data;
-
-	if (ast_channel_state(trnf_data->session->channel) == AST_STATE_RING) {
-		transfer_redirect(trnf_data->session, trnf_data->target);
-	} else {
-		transfer_refer(trnf_data->session, trnf_data->target);
-	}
-
-	ao2_ref(trnf_data, -1);
-	return 0;
-}
-
-/*! \brief Function called by core for Asterisk initiated transfer */
-static int chan_pjsip_transfer(struct ast_channel *chan, const char *target)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct transfer_data *trnf_data = transfer_data_alloc(channel->session, target);
-
-	if (!trnf_data) {
-		return -1;
-	}
-
-	if (ast_sip_push_task(channel->session->serializer, transfer, trnf_data)) {
-		ast_log(LOG_WARNING, "Error requesting transfer\n");
-		ao2_cleanup(trnf_data);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Function called by core to start a DTMF digit */
-static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
-	int res = 0;
-
-	switch (channel->session->endpoint->dtmf) {
-	case AST_SIP_DTMF_RFC_4733:
-		if (!media || !media->rtp) {
-			return -1;
-		}
-
-		ast_rtp_instance_dtmf_begin(media->rtp, digit);
-	case AST_SIP_DTMF_NONE:
-		break;
-	case AST_SIP_DTMF_INBAND:
-		res = -1;
-		break;
-	default:
-		break;
-	}
-
-	return res;
-}
-
-struct info_dtmf_data {
-	struct ast_sip_session *session;
-	char digit;
-	unsigned int duration;
-};
-
-static void info_dtmf_data_destroy(void *obj)
-{
-	struct info_dtmf_data *dtmf_data = obj;
-	ao2_ref(dtmf_data->session, -1);
-}
-
-static struct info_dtmf_data *info_dtmf_data_alloc(struct ast_sip_session *session, char digit, unsigned int duration)
-{
-	struct info_dtmf_data *dtmf_data = ao2_alloc(sizeof(*dtmf_data), info_dtmf_data_destroy);
-	if (!dtmf_data) {
-		return NULL;
-	}
-	ao2_ref(session, +1);
-	dtmf_data->session = session;
-	dtmf_data->digit = digit;
-	dtmf_data->duration = duration;
-	return dtmf_data;
-}
-
-static int transmit_info_dtmf(void *data)
-{
-	RAII_VAR(struct info_dtmf_data *, dtmf_data, data, ao2_cleanup);
-
-	struct ast_sip_session *session = dtmf_data->session;
-	struct pjsip_tx_data *tdata;
-
-	RAII_VAR(struct ast_str *, body_text, NULL, ast_free_ptr);
-
-	struct ast_sip_body body = {
-		.type = "application",
-		.subtype = "dtmf-relay",
-	};
-
-	if (!(body_text = ast_str_create(32))) {
-		ast_log(LOG_ERROR, "Could not allocate buffer for INFO DTMF.\n");
-		return -1;
-	}
-	ast_str_set(&body_text, 0, "Signal=%c\r\nDuration=%u\r\n", dtmf_data->digit, dtmf_data->duration);
-
-	body.body_text = ast_str_buffer(body_text);
-
-	if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
-		ast_log(LOG_ERROR, "Could not create DTMF INFO request\n");
-		return -1;
-	}
-	if (ast_sip_add_body(tdata, &body)) {
-		ast_log(LOG_ERROR, "Could not add body to DTMF INFO request\n");
-		pjsip_tx_data_dec_ref(tdata);
-		return -1;
-	}
-	ast_sip_session_send_request(session, tdata);
-
-	return 0;
-}
-
-/*! \brief Function called by core to stop a DTMF digit */
-static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
-	int res = 0;
-
-	switch (channel->session->endpoint->dtmf) {
-	case AST_SIP_DTMF_INFO:
-	{
-		struct info_dtmf_data *dtmf_data = info_dtmf_data_alloc(channel->session, digit, duration);
-
-		if (!dtmf_data) {
-			return -1;
-		}
-
-		if (ast_sip_push_task(channel->session->serializer, transmit_info_dtmf, dtmf_data)) {
-			ast_log(LOG_WARNING, "Error sending DTMF via INFO.\n");
-			ao2_cleanup(dtmf_data);
-			return -1;
-		}
-		break;
-	}
-	case AST_SIP_DTMF_RFC_4733:
-		if (!media || !media->rtp) {
-			return -1;
-		}
-
-		ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
-	case AST_SIP_DTMF_NONE:
-		break;
-	case AST_SIP_DTMF_INBAND:
-		res = -1;
-		break;
-	}
-
-	return res;
-}
-
-static void update_initial_connected_line(struct ast_sip_session *session)
-{
-	struct ast_party_connected_line connected;
-
-	/*
-	 * Use the channel CALLERID() as the initial connected line data.
-	 * The core or a predial handler may have supplied missing values
-	 * from the session->endpoint->id.self about who we are calling.
-	 */
-	ast_channel_lock(session->channel);
-	ast_party_id_copy(&session->id, &ast_channel_caller(session->channel)->id);
-	ast_channel_unlock(session->channel);
-
-	/* Supply initial connected line information if available. */
-	if (!session->id.number.valid && !session->id.name.valid) {
-		return;
-	}
-
-	ast_party_connected_line_init(&connected);
-	connected.id = session->id;
-	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-
-	ast_channel_queue_connected_line_update(session->channel, &connected, NULL);
-}
-
-static int call(void *data)
-{
-	struct ast_sip_channel_pvt *channel = data;
-	struct ast_sip_session *session = channel->session;
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	pjsip_tx_data *tdata;
-
-	int res = ast_sip_session_create_invite(session, &tdata);
-
-	if (res) {
-		ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
-		ast_queue_hangup(session->channel);
-	} else {
-		set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(session->channel));
-		update_initial_connected_line(session);
-		ast_sip_session_send_request(session, tdata);
-	}
-	ao2_ref(channel, -1);
-	return res;
-}
-
-/*! \brief Function called by core to actually start calling a remote party */
-static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeout)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-
-	ao2_ref(channel, +1);
-	if (ast_sip_push_task(channel->session->serializer, call, channel)) {
-		ast_log(LOG_WARNING, "Error attempting to place outbound call to '%s'\n", dest);
-		ao2_cleanup(channel);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Internal function which translates from Asterisk cause codes to SIP response codes */
-static int hangup_cause2sip(int cause)
-{
-	switch (cause) {
-	case AST_CAUSE_UNALLOCATED:             /* 1 */
-	case AST_CAUSE_NO_ROUTE_DESTINATION:    /* 3 IAX2: Can't find extension in context */
-	case AST_CAUSE_NO_ROUTE_TRANSIT_NET:    /* 2 */
-		return 404;
-	case AST_CAUSE_CONGESTION:              /* 34 */
-	case AST_CAUSE_SWITCH_CONGESTION:       /* 42 */
-		return 503;
-	case AST_CAUSE_NO_USER_RESPONSE:        /* 18 */
-		return 408;
-	case AST_CAUSE_NO_ANSWER:               /* 19 */
-	case AST_CAUSE_UNREGISTERED:        /* 20 */
-		return 480;
-	case AST_CAUSE_CALL_REJECTED:           /* 21 */
-		return 403;
-	case AST_CAUSE_NUMBER_CHANGED:          /* 22 */
-		return 410;
-	case AST_CAUSE_NORMAL_UNSPECIFIED:      /* 31 */
-		return 480;
-	case AST_CAUSE_INVALID_NUMBER_FORMAT:
-		return 484;
-	case AST_CAUSE_USER_BUSY:
-		return 486;
-	case AST_CAUSE_FAILURE:
-		return 500;
-	case AST_CAUSE_FACILITY_REJECTED:       /* 29 */
-		return 501;
-	case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
-		return 503;
-	case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
-		return 502;
-	case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL:       /* Can't find codec to connect to host */
-		return 488;
-	case AST_CAUSE_INTERWORKING:    /* Unspecified Interworking issues */
-		return 500;
-	case AST_CAUSE_NOTDEFINED:
-	default:
-		ast_debug(1, "AST hangup cause %d (no match found in PJSIP)\n", cause);
-		return 0;
-	}
-
-	/* Never reached */
-	return 0;
-}
-
-struct hangup_data {
-	int cause;
-	struct ast_channel *chan;
-};
-
-static void hangup_data_destroy(void *obj)
-{
-	struct hangup_data *h_data = obj;
-
-	h_data->chan = ast_channel_unref(h_data->chan);
-}
-
-static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan)
-{
-	struct hangup_data *h_data = ao2_alloc(sizeof(*h_data), hangup_data_destroy);
-
-	if (!h_data) {
-		return NULL;
-	}
-
-	h_data->cause = cause;
-	h_data->chan = ast_channel_ref(chan);
-
-	return h_data;
-}
-
-/*! \brief Clear a channel from a session along with its PVT */
-static void clear_session_and_channel(struct ast_sip_session *session, struct ast_channel *ast, struct chan_pjsip_pvt *pvt)
-{
-	session->channel = NULL;
-	set_channel_on_rtp_instance(pvt, "");
-	ast_channel_tech_pvt_set(ast, NULL);
-}
-
-static int hangup(void *data)
-{
-	struct hangup_data *h_data = data;
-	struct ast_channel *ast = h_data->chan;
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	struct ast_sip_session *session = channel->session;
-	int cause = h_data->cause;
-
-	if (!session->defer_terminate) {
-		pj_status_t status;
-		pjsip_tx_data *packet = NULL;
-
-		if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
-			pjsip_inv_terminate(session->inv_session, cause ? cause : 603, PJ_TRUE);
-		} else if (((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS)
-			&& packet) {
-			if (packet->msg->type == PJSIP_RESPONSE_MSG) {
-				ast_sip_session_send_response(session, packet);
-			} else {
-				ast_sip_session_send_request(session, packet);
-			}
-		}
-	}
-
-	clear_session_and_channel(session, ast, pvt);
-	ao2_cleanup(channel);
-	ao2_cleanup(h_data);
-
-	return 0;
-}
-
-/*! \brief Function called by core to hang up a PJSIP session */
-static int chan_pjsip_hangup(struct ast_channel *ast)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct chan_pjsip_pvt *pvt = channel->pvt;
-	int cause = hangup_cause2sip(ast_channel_hangupcause(channel->session->channel));
-	struct hangup_data *h_data = hangup_data_alloc(cause, ast);
-
-	if (!h_data) {
-		goto failure;
-	}
-
-	if (ast_sip_push_task(channel->session->serializer, hangup, h_data)) {
-		ast_log(LOG_WARNING, "Unable to push hangup task to the threadpool. Expect bad things\n");
-		goto failure;
-	}
-
-	return 0;
-
-failure:
-	/* Go ahead and do our cleanup of the session and channel even if we're not going
-	 * to be able to send our SIP request/response
-	 */
-	clear_session_and_channel(channel->session, ast, pvt);
-	ao2_cleanup(channel);
-	ao2_cleanup(h_data);
-
-	return -1;
-}
-
-struct request_data {
-	struct ast_sip_session *session;
-	struct ast_format_cap *caps;
-	const char *dest;
-	int cause;
-};
-
-static int request(void *obj)
-{
-	struct request_data *req_data = obj;
-	struct ast_sip_session *session = NULL;
-	char *tmp = ast_strdupa(req_data->dest), *endpoint_name = NULL, *request_user = NULL;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(endpoint);
-		AST_APP_ARG(aor);
-	);
-
-	if (ast_strlen_zero(tmp)) {
-		ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty destination\n");
-		req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
-		return -1;
-	}
-
-	AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
-
-	/* If a request user has been specified extract it from the endpoint name portion */
-	if ((endpoint_name = strchr(args.endpoint, '@'))) {
-		request_user = args.endpoint;
-		*endpoint_name++ = '\0';
-	} else {
-		endpoint_name = args.endpoint;
-	}
-
-	if (ast_strlen_zero(endpoint_name)) {
-		ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n");
-		req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
-	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
-		ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name);
-		req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
-		return -1;
-	}
-
-	if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->caps))) {
-		ast_log(LOG_ERROR, "Failed to create outgoing session to endpoint '%s'\n", endpoint_name);
-		req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
-		return -1;
-	}
-
-	req_data->session = session;
-
-	return 0;
-}
-
-/*! \brief Function called by core to create a new outgoing PJSIP session */
-static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	struct request_data req_data;
-	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-
-	req_data.caps = cap;
-	req_data.dest = data;
-
-	if (ast_sip_push_task_synchronous(NULL, request, &req_data)) {
-		*cause = req_data.cause;
-		return NULL;
-	}
-
-	session = req_data.session;
-
-	if (!(session->channel = chan_pjsip_new(session, AST_STATE_DOWN, NULL, NULL, assignedids, requestor, NULL))) {
-		/* Session needs to be terminated prematurely */
-		return NULL;
-	}
-
-	return session->channel;
-}
-
-struct sendtext_data {
-	struct ast_sip_session *session;
-	char text[0];
-};
-
-static void sendtext_data_destroy(void *obj)
-{
-	struct sendtext_data *data = obj;
-	ao2_ref(data->session, -1);
-}
-
-static struct sendtext_data* sendtext_data_create(struct ast_sip_session *session, const char *text)
-{
-	int size = strlen(text) + 1;
-	struct sendtext_data *data = ao2_alloc(sizeof(*data)+size, sendtext_data_destroy);
-
-	if (!data) {
-		return NULL;
-	}
-
-	data->session = session;
-	ao2_ref(data->session, +1);
-	ast_copy_string(data->text, text, size);
-	return data;
-}
-
-static int sendtext(void *obj)
-{
-	RAII_VAR(struct sendtext_data *, data, obj, ao2_cleanup);
-	pjsip_tx_data *tdata;
-
-	const struct ast_sip_body body = {
-		.type = "text",
-		.subtype = "plain",
-		.body_text = data->text
-	};
-
-	/* NOT ast_strlen_zero, because a zero-length message is specifically
-	 * allowed by RFC 3428 (See section 10, Examples) */
-	if (!data->text) {
-		return 0;
-	}
-
-	ast_debug(3, "Sending in dialog SIP message\n");
-
-	ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
-	ast_sip_add_body(tdata, &body);
-	ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
-
-	return 0;
-}
-
-/*! \brief Function called by core to send text on PJSIP session */
-static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
-	struct sendtext_data *data = sendtext_data_create(channel->session, text);
-
-	if (!data || ast_sip_push_task(channel->session->serializer, sendtext, data)) {
-		ao2_ref(data, -1);
-		return -1;
-	}
-	return 0;
-}
-
-/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
-static int hangup_sip2cause(int cause)
-{
-	/* Possible values taken from causes.h */
-
-	switch(cause) {
-	case 401:       /* Unauthorized */
-		return AST_CAUSE_CALL_REJECTED;
-	case 403:       /* Not found */
-		return AST_CAUSE_CALL_REJECTED;
-	case 404:       /* Not found */
-		return AST_CAUSE_UNALLOCATED;
-	case 405:       /* Method not allowed */
-		return AST_CAUSE_INTERWORKING;
-	case 407:       /* Proxy authentication required */
-		return AST_CAUSE_CALL_REJECTED;
-	case 408:       /* No reaction */
-		return AST_CAUSE_NO_USER_RESPONSE;
-	case 409:       /* Conflict */
-		return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
-	case 410:       /* Gone */
-		return AST_CAUSE_NUMBER_CHANGED;
-	case 411:       /* Length required */
-		return AST_CAUSE_INTERWORKING;
-	case 413:       /* Request entity too large */
-		return AST_CAUSE_INTERWORKING;
-	case 414:       /* Request URI too large */
-		return AST_CAUSE_INTERWORKING;
-	case 415:       /* Unsupported media type */
-		return AST_CAUSE_INTERWORKING;
-	case 420:       /* Bad extension */
-		return AST_CAUSE_NO_ROUTE_DESTINATION;
-	case 480:       /* No answer */
-		return AST_CAUSE_NO_ANSWER;
-	case 481:       /* No answer */
-		return AST_CAUSE_INTERWORKING;
-	case 482:       /* Loop detected */
-		return AST_CAUSE_INTERWORKING;
-	case 483:       /* Too many hops */
-		return AST_CAUSE_NO_ANSWER;
-	case 484:       /* Address incomplete */
-		return AST_CAUSE_INVALID_NUMBER_FORMAT;
-	case 485:       /* Ambiguous */
-		return AST_CAUSE_UNALLOCATED;
-	case 486:       /* Busy everywhere */
-		return AST_CAUSE_BUSY;
-	case 487:       /* Request terminated */
-		return AST_CAUSE_INTERWORKING;
-	case 488:       /* No codecs approved */
-		return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
-	case 491:       /* Request pending */
-		return AST_CAUSE_INTERWORKING;
-	case 493:       /* Undecipherable */
-		return AST_CAUSE_INTERWORKING;
-	case 500:       /* Server internal failure */
-		return AST_CAUSE_FAILURE;
-	case 501:       /* Call rejected */
-		return AST_CAUSE_FACILITY_REJECTED;
-	case 502:
-		return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
-	case 503:       /* Service unavailable */
-		return AST_CAUSE_CONGESTION;
-	case 504:       /* Gateway timeout */
-		return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
-	case 505:       /* SIP version not supported */
-		return AST_CAUSE_INTERWORKING;
-	case 600:       /* Busy everywhere */
-		return AST_CAUSE_USER_BUSY;
-	case 603:       /* Decline */
-		return AST_CAUSE_CALL_REJECTED;
-	case 604:       /* Does not exist anywhere */
-		return AST_CAUSE_UNALLOCATED;
-	case 606:       /* Not acceptable */
-		return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
-	default:
-		if (cause < 500 && cause >= 400) {
-			/* 4xx class error that is unknown - someting wrong with our request */
-			return AST_CAUSE_INTERWORKING;
-		} else if (cause < 600 && cause >= 500) {
-			/* 5xx class error - problem in the remote end */
-			return AST_CAUSE_CONGESTION;
-		} else if (cause < 700 && cause >= 600) {
-			/* 6xx - global errors in the 4xx class */
-			return AST_CAUSE_INTERWORKING;
-		}
-		return AST_CAUSE_NORMAL;
-	}
-	/* Never reached */
-	return 0;
-}
-
-static void chan_pjsip_session_begin(struct ast_sip_session *session)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-
-	if (session->endpoint->media.direct_media.glare_mitigation ==
-			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
-		return;
-	}
-
-	datastore = ast_sip_session_alloc_datastore(&direct_media_mitigation_info,
-			"direct_media_glare_mitigation");
-
-	if (!datastore) {
-		return;
-	}
-
-	ast_sip_session_add_datastore(session, datastore);
-}
-
-/*! \brief Function called when the session ends */
-static void chan_pjsip_session_end(struct ast_sip_session *session)
-{
-	if (!session->channel) {
-		return;
-	}
-
-	chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));
-
-	ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
-	if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
-		int cause = hangup_sip2cause(session->inv_session->cause);
-
-		ast_queue_hangup_with_cause(session->channel, cause);
-	} else {
-		ast_queue_hangup(session->channel);
-	}
-}
-
-/*! \brief Function called when a request is received on the session */
-static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	struct transport_info_data *transport_data;
-	pjsip_tx_data *packet = NULL;
-
-	if (session->channel) {
-		return 0;
-	}
-
-	datastore = ast_sip_session_alloc_datastore(&transport_info, "transport_info");
-	if (!datastore) {
-		return -1;
-	}
-
-	transport_data = ast_calloc(1, sizeof(*transport_data));
-	if (!transport_data) {
-		return -1;
-	}
-	pj_sockaddr_cp(&transport_data->local_addr, &rdata->tp_info.transport->local_addr);
-	pj_sockaddr_cp(&transport_data->remote_addr, &rdata->pkt_info.src_addr);
-	datastore->data = transport_data;
-	ast_sip_session_add_datastore(session, datastore);
-
-	if (!(session->channel = chan_pjsip_new(session, AST_STATE_RING, session->exten, NULL, NULL, NULL, NULL))) {
-		if (pjsip_inv_end_session(session->inv_session, 503, NULL, &packet) == PJ_SUCCESS) {
-			ast_sip_session_send_response(session, packet);
-		}
-
-		ast_log(LOG_ERROR, "Failed to allocate new PJSIP channel on incoming SIP INVITE\n");
-		return -1;
-	}
-	/* channel gets created on incoming request, but we wait to call start
-           so other supplements have a chance to run */
-	return 0;
-}
-
-static int call_pickup_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	struct ast_features_pickup_config *pickup_cfg = ast_get_chan_features_pickup_config(session->channel);
-	struct ast_channel *chan;
-
-	/* We don't care about reinvites */
-	if (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED) {
-		return 0;
-	}
-
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension.\n");
-		return 0;
-	}
-
-	if (strcmp(session->exten, pickup_cfg->pickupexten)) {
-		ao2_ref(pickup_cfg, -1);
-		return 0;
-	}
-	ao2_ref(pickup_cfg, -1);
-
-	/* We can't directly use session->channel because the pickup operation will cause a masquerade to occur,
-	 * changing the channel pointer in session to a different channel. To ensure we work on the right channel
-	 * we store a pointer locally before we begin and keep a reference so it remains valid no matter what.
-	 */
-	chan = ast_channel_ref(session->channel);
-	if (ast_pickup_call(chan)) {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_CALL_REJECTED);
-	} else {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL_CLEARING);
-	}
-	/* A hangup always occurs because the pickup operation will have either failed resulting in the call
-	 * needing to be hung up OR the pickup operation was a success and the channel we now have is actually
-	 * the channel that was replaced, which should be hung up since it is literally in limbo not connected
-	 * to anything at all.
-	 */
-	ast_hangup(chan);
-	ast_channel_unref(chan);
-
-	return 1;
-}
-
-static struct ast_sip_session_supplement call_pickup_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST - 1,
-	.incoming_request = call_pickup_incoming_request,
-};
-
-static int pbx_start_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	int res;
-
-	/* We don't care about reinvites */
-	if (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED) {
-		return 0;
-	}
-
-	res = ast_pbx_start(session->channel);
-
-	switch (res) {
-	case AST_PBX_FAILED:
-		ast_log(LOG_WARNING, "Failed to start PBX ;(\n");
-		ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
-		ast_hangup(session->channel);
-		break;
-	case AST_PBX_CALL_LIMIT:
-		ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
-		ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
-		ast_hangup(session->channel);
-		break;
-	case AST_PBX_SUCCESS:
-	default:
-		break;
-	}
-
-	ast_debug(3, "Started PBX on new PJSIP channel %s\n", ast_channel_name(session->channel));
-
-	return (res == AST_PBX_SUCCESS) ? 0 : -1;
-}
-
-static struct ast_sip_session_supplement pbx_start_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST,
-	.incoming_request = pbx_start_incoming_request,
-};
-
-/*! \brief Function called when a response is received on the session */
-static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	struct pjsip_status_line status = rdata->msg_info.msg->line.status;
-	struct ast_control_pvt_cause_code *cause_code;
-	int data_size = sizeof(*cause_code);
-
-	if (!session->channel) {
-		return;
-	}
-
-	switch (status.code) {
-	case 180:
-		ast_queue_control(session->channel, AST_CONTROL_RINGING);
-		ast_channel_lock(session->channel);
-		if (ast_channel_state(session->channel) != AST_STATE_UP) {
-			ast_setstate(session->channel, AST_STATE_RINGING);
-		}
-		ast_channel_unlock(session->channel);
-		break;
-	case 183:
-		ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
-		break;
-	case 200:
-		ast_queue_control(session->channel, AST_CONTROL_ANSWER);
-		break;
-	default:
-		break;
-	}
-
-	/* Build and send the tech-specific cause information */
-	/* size of the string making up the cause code is "SIP " number + " " + reason length */
-	data_size += 4 + 4 + pj_strlen(&status.reason);
-	cause_code = ast_alloca(data_size);
-	memset(cause_code, 0, data_size);
-
-	ast_copy_string(cause_code->chan_name, ast_channel_name(session->channel), AST_CHANNEL_NAME);
-
-	snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code,
-		(int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
-
-	cause_code->ast_cause = hangup_sip2cause(status.code);
-	ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
-	ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size);
-}
-
-static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
-		if (session->endpoint->media.direct_media.enabled && session->channel) {
-			ast_queue_control(session->channel, AST_CONTROL_SRCCHANGE);
-		}
-	}
-	return 0;
-}
-
-static int update_devstate(void *obj, void *arg, int flags)
-{
-	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE,
-			     "PJSIP/%s", ast_sorcery_object_get_id(obj));
-	return 0;
-}
-
-static struct ast_custom_function chan_pjsip_dial_contacts_function = {
-	.name = "PJSIP_DIAL_CONTACTS",
-	.read = pjsip_acf_dial_contacts_read,
-};
-
-static struct ast_custom_function media_offer_function = {
-	.name = "PJSIP_MEDIA_OFFER",
-	.read = pjsip_acf_media_offer_read,
-	.write = pjsip_acf_media_offer_write
-};
-
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
-static int load_module(void)
-{
-	struct ao2_container *endpoints;
-
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (!(chan_pjsip_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_format_cap_append_by_type(chan_pjsip_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
-
-	ast_rtp_glue_register(&chan_pjsip_rtp_glue);
-
-	if (ast_channel_register(&chan_pjsip_tech)) {
-		ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
-		goto end;
-	}
-
-	if (ast_custom_function_register(&chan_pjsip_dial_contacts_function)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP_DIAL_CONTACTS dialplan function\n");
-		goto end;
-	}
-
-	if (ast_custom_function_register(&media_offer_function)) {
-		ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
-		goto end;
-	}
-
-	if (ast_sip_session_register_supplement(&chan_pjsip_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP supplement\n");
-		goto end;
-	}
-
-	if (!(pjsip_uids_onhold = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,
-			AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, 37, uid_hold_hash_fn,
-			uid_hold_sort_fn, NULL))) {
-		ast_log(LOG_ERROR, "Unable to create held channels container\n");
-		goto end;
-	}
-
-	if (ast_sip_session_register_supplement(&call_pickup_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP call pickup supplement\n");
-		ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
-		goto end;
-	}
-
-	if (ast_sip_session_register_supplement(&pbx_start_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP pbx start supplement\n");
-		ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
-		ast_sip_session_unregister_supplement(&call_pickup_supplement);
-		goto end;
-	}
-
-	if (ast_sip_session_register_supplement(&chan_pjsip_ack_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP ACK supplement\n");
-		ast_sip_session_unregister_supplement(&pbx_start_supplement);
-		ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
-		ast_sip_session_unregister_supplement(&call_pickup_supplement);
-		goto end;
-	}
-
-	/* since endpoints are loaded before the channel driver their device
-	   states get set to 'invalid', so they need to be updated */
-	if ((endpoints = ast_sip_get_endpoints())) {
-		ao2_callback(endpoints, OBJ_NODATA, update_devstate, NULL);
-		ao2_ref(endpoints, -1);
-	}
-
-	return 0;
-
-end:
-	ao2_cleanup(pjsip_uids_onhold);
-	pjsip_uids_onhold = NULL;
-	ast_custom_function_unregister(&media_offer_function);
-	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
-	ast_channel_unregister(&chan_pjsip_tech);
-	ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
-
-	return AST_MODULE_LOAD_FAILURE;
-}
-
-/*! \brief Unload the PJSIP channel from Asterisk */
-static int unload_module(void)
-{
-	ao2_cleanup(pjsip_uids_onhold);
-	pjsip_uids_onhold = NULL;
-
-	ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
-	ast_sip_session_unregister_supplement(&pbx_start_supplement);
-	ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
-	ast_sip_session_unregister_supplement(&call_pickup_supplement);
-
-	ast_custom_function_unregister(&media_offer_function);
-	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
-
-	ast_channel_unregister(&chan_pjsip_tech);
-	ao2_ref(chan_pjsip_tech.capabilities, -1);
-	ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Channel Driver",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
-	       );
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 2022402..b149c99 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -40,7 +40,7 @@
  * \todo Transaction support
  *
  * ******** Wishlist: Improvements
- * - Support of SIP domains for devices, so that we match on username\@domain in the From: header
+ * - Support of SIP domains for devices, so that we match on username at domain in the From: header
  * - Connect registrations with a specific device on the incoming call. It's not done
  *   automatically in Asterisk
  *
@@ -92,18 +92,6 @@
  * the sip_hangup() function
  */
 
-/*! \li \ref chan_sip.c uses configuration files \ref sip.conf and \ref sip_notify.conf
- * \addtogroup configuration_file
- */
-
-/*! \page sip.conf sip.conf
- * \verbinclude sip.conf.sample
- */
-
-/*! \page sip_notify.conf sip_notify.conf
- * \verbinclude sip_notify.conf.sample
- */
-
 /*!
  * \page sip_tcp_tls SIP TCP and TLS support
  *
@@ -111,7 +99,7 @@
  * \todo Fix TCP/TLS handling in dialplan, SRV records, transfers and much more
  * \todo Save TCP/TLS sessions in registry
  *	If someone registers a SIPS uri, this forces us to set up a TLS connection back.
- * \todo Add TCP/TLS information to function SIPPEER and CHANNEL function
+ * \todo Add TCP/TLS information to function SIPPEER and SIPCHANINFO
  * \todo If tcpenable=yes, we must open a TCP socket on the same address as the IP for UDP.
  * 	The tcpbindaddr config option should only be used to open ADDITIONAL ports
  * 	So we should propably go back to
@@ -176,7 +164,8 @@
 /*** MODULEINFO
 	<use type="module">res_crypto</use>
 	<use type="module">res_http_websocket</use>
-	<support_level>extended</support_level>
+	<depend>chan_local</depend>
+	<support_level>core</support_level>
  ***/
 
 /*!  \page sip_session_timers SIP Session Timers in Asterisk Chan_sip
@@ -221,7 +210,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 #include <sys/signal.h>
@@ -244,8 +233,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 #include "asterisk/cli.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/dsp.h"
-#include "asterisk/pickup.h"
-#include "asterisk/parking.h"
+#include "asterisk/features.h"
 #include "asterisk/srv.h"
 #include "asterisk/astdb.h"
 #include "asterisk/causes.h"
@@ -261,6 +249,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 #include "asterisk/threadstorage.h"
 #include "asterisk/translate.h"
 #include "asterisk/ast_version.h"
+#include "asterisk/event.h"
+#include "asterisk/cel.h"
 #include "asterisk/data.h"
 #include "asterisk/aoc.h"
 #include "asterisk/message.h"
@@ -269,23 +259,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 #include "sip/include/config_parser.h"
 #include "sip/include/reqresp_parser.h"
 #include "sip/include/sip_utils.h"
-#include "asterisk/sdp_srtp.h"
+#include "sip/include/srtp.h"
+#include "sip/include/sdp_crypto.h"
 #include "asterisk/ccss.h"
 #include "asterisk/xml.h"
 #include "sip/include/dialog.h"
 #include "sip/include/dialplan_functions.h"
 #include "sip/include/security_events.h"
-#include "sip/include/route.h"
 #include "asterisk/sip_api.h"
-#include "asterisk/app.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_system.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/features_config.h"
-#include "asterisk/http_websocket.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="SIPDtmfMode" language="en_US">
@@ -375,7 +356,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 			<para>Since there are several headers (such as Via) which can occur multiple
 			times, SIP_HEADER takes an optional second argument to specify which header with
 			that name to retrieve. Headers start at offset <literal>1</literal>.</para>
-			<para>Please observe that contents of the SDP (an attachment to the
+			<para>Please observe that contents of the SDP (an attachment to the 
 			SIP request) can't be accessed with this function.</para>
 		</description>
 	</function>
@@ -464,6 +445,40 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 		</syntax>
 		<description></description>
 	</function>
+	<function name="SIPCHANINFO" language="en_US">
+		<synopsis>
+			Gets the specified SIP parameter from the current channel.
+		</synopsis>
+		<syntax>
+			<parameter name="item" required="true">
+				<enumlist>
+					<enum name="peerip">
+						<para>The IP address of the peer.</para>
+					</enum>
+					<enum name="recvip">
+						<para>The source IP address of the peer.</para>
+					</enum>
+					<enum name="from">
+						<para>The SIP URI from the <literal>From:</literal> header.</para>
+					</enum>
+					<enum name="uri">
+						<para>The SIP URI from the <literal>Contact:</literal> header.</para>
+					</enum>
+					<enum name="useragent">
+						<para>The Useragent header used by the peer.</para>
+					</enum>
+					<enum name="peername">
+						<para>The name of the peer.</para>
+					</enum>
+					<enum name="t38passthrough">
+						<para><literal>1</literal> if T38 is offered or enabled in this channel,
+						otherwise <literal>0</literal>.</para>
+					</enum>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<description></description>
+	</function>
 	<function name="CHECKSIPDOMAIN" language="en_US">
 		<synopsis>
 			Checks if domain is a local domain.
@@ -518,9 +533,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 		<description>
 			<para>Qualify a SIP peer.</para>
 		</description>
-		<see-also>
-			<ref type="managerEvent">SIPQualifyPeerDone</ref>
-		</see-also>
 	</manager>
 	<manager name="SIPshowregistry" language="en_US">
 		<synopsis>
@@ -577,37 +589,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 		<para>Specifying a prefix of <literal>sip:</literal> will send the
 		message as a SIP MESSAGE request.</para>
 	</info>
-	<managerEvent language="en_US" name="SIPQualifyPeerDone">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when SIPQualifyPeer has finished qualifying the specified peer.</synopsis>
-			<syntax>
-				<parameter name="Peer">
-					<para>The name of the peer.</para>
-				</parameter>
-				<parameter name="ActionID">
-					<para>This is only included if an ActionID Header was sent with the action request, in which case it will be that ActionID.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">SIPqualifypeer</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SessionTimeout">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a SIP session times out.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Source">
-					<para>The source of the session timeout.</para>
-					<enumlist>
-						<enum name="RTPTimeout" />
-						<enum name="SIPSessionTimer" />
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 static int min_expiry = DEFAULT_MIN_EXPIRY;        /*!< Minimum accepted registration time */
@@ -733,6 +714,7 @@ static const struct sip_reasons {
 	Default setttings are used as a channel setting and as a default when
 	configuring devices
 */
+/*@{*/
 static char default_language[MAX_LANGUAGE];      /*!< Default language setting for new channels */
 static char default_callerid[AST_MAX_EXTENSION]; /*!< Default caller ID for sip messages */
 static char default_mwi_from[80];                /*!< Default caller ID for MWI updates */
@@ -748,9 +730,11 @@ static char default_mohsuggest[MAX_MUSICCLASS];    /*!< Global setting for moh c
 static char default_parkinglot[AST_MAX_CONTEXT];   /*!< Parkinglot */
 static char default_engine[256];                   /*!< Default RTP engine */
 static int default_maxcallbitrate;                 /*!< Maximum bitrate for call */
+static struct ast_codec_pref default_prefs;        /*!< Default codec prefs */
 static char default_zone[MAX_TONEZONE_COUNTRY];        /*!< Default tone zone for channels created from the SIP driver */
-static unsigned int default_transports;            /*!< Default Transports (enum ast_transport) that are acceptable */
-static unsigned int default_primary_transport;     /*!< Default primary Transport (enum ast_transport) for outbound connections to devices */
+static unsigned int default_transports;            /*!< Default Transports (enum sip_transport) that are acceptable */
+static unsigned int default_primary_transport;     /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */
+/*@}*/
 
 static struct sip_settings sip_cfg;		/*!< SIP configuration data.
 					\note in the future we could have multiple of these (per domain, per device group etc) */
@@ -818,21 +802,20 @@ static unsigned char global_refer_addheaders; /*!< Add extra headers to outgoing
 static int can_parse_xml;
 
 /*! \name Object counters @{
- *
- * \bug These counters are not handled in a thread-safe way ast_atomic_fetchadd_int()
- * should be used to modify these values.
- */
+ *  \bug These counters are not handled in a thread-safe way ast_atomic_fetchadd_int()
+ *  should be used to modify these values. */
 static int speerobjs = 0;     /*!< Static peers */
 static int rpeerobjs = 0;     /*!< Realtime peers */
 static int apeerobjs = 0;     /*!< Autocreated peer objects */
-/*! @} */
+static int regobjs = 0;       /*!< Registry objects */
+/* }@ */
 
 static struct ast_flags global_flags[3] = {{0}};  /*!< global SIP_ flags */
 static unsigned int global_t38_maxdatagram;                /*!< global T.38 FaxMaxDatagram override */
 
-static struct stasis_subscription *network_change_sub; /*!< subscription id for network change events */
-static struct stasis_subscription *acl_change_sub; /*!< subscription id for named ACL system change events */
-static int network_change_sched_id = -1;
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static struct ast_event_sub *acl_change_event_subscription; /*!< subscription id for named ACL system change events */
+static int network_change_event_sched_id = -1;
 
 static char used_context[AST_MAX_CONTEXT];        /*!< name of automatically created context for unloading */
 
@@ -884,11 +867,9 @@ static const struct _map_x_s referstatusstrings[] = {
 #ifdef LOW_MEMORY
 static const int HASH_PEER_SIZE = 17;
 static const int HASH_DIALOG_SIZE = 17;
-static const int HASH_REGISTRY_SIZE = 17;
 #else
 static const int HASH_PEER_SIZE = 563;	/*!< Size of peer hash table, prime number preferred! */
 static const int HASH_DIALOG_SIZE = 563;
-static const int HASH_REGISTRY_SIZE = 563;
 #endif
 
 static const struct {
@@ -901,6 +882,17 @@ static const struct {
 	[AST_CC_CCNL] = { AST_CC_CCNL, "NL" },
 };
 
+static enum ast_cc_service_type service_string_to_service_type(const char * const service_string)
+{
+	enum ast_cc_service_type service;
+	for (service = AST_CC_CCBS; service <= AST_CC_CCNL; ++service) {
+		if (!strcasecmp(service_string, sip_cc_service_map[service].service_string)) {
+			return service;
+		}
+	}
+	return AST_CC_NONE;
+}
+
 static const struct {
 	enum sip_cc_notify_state state;
 	const char *state_string;
@@ -911,6 +903,80 @@ static const struct {
 
 AST_LIST_HEAD_STATIC(epa_static_data_list, epa_backend);
 
+static int sip_epa_register(const struct epa_static_data *static_data)
+{
+	struct epa_backend *backend = ast_calloc(1, sizeof(*backend));
+
+	if (!backend) {
+		return -1;
+	}
+
+	backend->static_data = static_data;
+
+	AST_LIST_LOCK(&epa_static_data_list);
+	AST_LIST_INSERT_TAIL(&epa_static_data_list, backend, next);
+	AST_LIST_UNLOCK(&epa_static_data_list);
+	return 0;
+}
+
+static void sip_epa_unregister_all(void)
+{
+	struct epa_backend *backend;
+
+	AST_LIST_LOCK(&epa_static_data_list);
+	while ((backend = AST_LIST_REMOVE_HEAD(&epa_static_data_list, next))) {
+		ast_free(backend);
+	}
+	AST_LIST_UNLOCK(&epa_static_data_list);
+}
+
+static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct sip_request *req, struct sip_epa_entry *epa_entry);
+
+static void cc_epa_destructor(void *data)
+{
+	struct sip_epa_entry *epa_entry = data;
+	struct cc_epa_entry *cc_entry = epa_entry->instance_data;
+	ast_free(cc_entry);
+}
+
+static const struct epa_static_data cc_epa_static_data  = {
+	.event = CALL_COMPLETION,
+	.name = "call-completion",
+	.handle_error = cc_handle_publish_error,
+	.destructor = cc_epa_destructor,
+};
+
+static const struct epa_static_data *find_static_data(const char * const event_package)
+{
+	const struct epa_backend *backend = NULL;
+
+	AST_LIST_LOCK(&epa_static_data_list);
+	AST_LIST_TRAVERSE(&epa_static_data_list, backend, next) {
+		if (!strcmp(backend->static_data->name, event_package)) {
+			break;
+		}
+	}
+	AST_LIST_UNLOCK(&epa_static_data_list);
+	return backend ? backend->static_data : NULL;
+}
+
+static struct sip_epa_entry *create_epa_entry (const char * const event_package, const char * const destination)
+{
+	struct sip_epa_entry *epa_entry;
+	const struct epa_static_data *static_data;
+
+	if (!(static_data = find_static_data(event_package))) {
+		return NULL;
+	}
+
+	if (!(epa_entry = ao2_t_alloc(sizeof(*epa_entry), static_data->destructor, "Allocate new EPA entry"))) {
+		return NULL;
+	}
+
+	epa_entry->static_data = static_data;
+	ast_copy_string(epa_entry->destination, destination, sizeof(epa_entry->destination));
+	return epa_entry;
+}
 
 /*!
  * Used to create new entity IDs by ESCs.
@@ -950,6 +1016,118 @@ static struct event_state_compositor {
 #endif
 };
 
+static const int ESC_MAX_BUCKETS = 37;
+
+static void esc_entry_destructor(void *obj)
+{
+	struct sip_esc_entry *esc_entry = obj;
+	if (esc_entry->sched_id > -1) {
+		AST_SCHED_DEL(sched, esc_entry->sched_id);
+	}
+}
+
+static int esc_hash_fn(const void *obj, const int flags)
+{
+	const struct sip_esc_entry *entry = obj;
+	return ast_str_hash(entry->entity_tag);
+}
+
+static int esc_cmp_fn(void *obj, void *arg, int flags)
+{
+	struct sip_esc_entry *entry1 = obj;
+	struct sip_esc_entry *entry2 = arg;
+
+	return (!strcmp(entry1->entity_tag, entry2->entity_tag)) ? (CMP_MATCH | CMP_STOP) : 0;
+}
+
+static struct event_state_compositor *get_esc(const char * const event_package) {
+	int i;
+	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+		if (!strcasecmp(event_package, event_state_compositors[i].name)) {
+			return &event_state_compositors[i];
+		}
+	}
+	return NULL;
+}
+
+static struct sip_esc_entry *get_esc_entry(const char * entity_tag, struct event_state_compositor *esc) {
+	struct sip_esc_entry *entry;
+	struct sip_esc_entry finder;
+
+	ast_copy_string(finder.entity_tag, entity_tag, sizeof(finder.entity_tag));
+
+	entry = ao2_find(esc->compositor, &finder, OBJ_POINTER);
+
+	return entry;
+}
+
+static int publish_expire(const void *data)
+{
+	struct sip_esc_entry *esc_entry = (struct sip_esc_entry *) data;
+	struct event_state_compositor *esc = get_esc(esc_entry->event);
+
+	ast_assert(esc != NULL);
+
+	ao2_unlink(esc->compositor, esc_entry);
+	ao2_ref(esc_entry, -1);
+	return 0;
+}
+
+static void create_new_sip_etag(struct sip_esc_entry *esc_entry, int is_linked)
+{
+	int new_etag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
+	struct event_state_compositor *esc = get_esc(esc_entry->event);
+
+	ast_assert(esc != NULL);
+	if (is_linked) {
+		ao2_unlink(esc->compositor, esc_entry);
+	}
+	snprintf(esc_entry->entity_tag, sizeof(esc_entry->entity_tag), "%d", new_etag);
+	ao2_link(esc->compositor, esc_entry);
+}
+
+static struct sip_esc_entry *create_esc_entry(struct event_state_compositor *esc, struct sip_request *req, const int expires)
+{
+	struct sip_esc_entry *esc_entry;
+	int expires_ms;
+
+	if (!(esc_entry = ao2_alloc(sizeof(*esc_entry), esc_entry_destructor))) {
+		return NULL;
+	}
+
+	esc_entry->event = esc->name;
+
+	expires_ms = expires * 1000;
+	/* Bump refcount for scheduler */
+	ao2_ref(esc_entry, +1);
+	esc_entry->sched_id = ast_sched_add(sched, expires_ms, publish_expire, esc_entry);
+
+	/* Note: This links the esc_entry into the ESC properly */
+	create_new_sip_etag(esc_entry, 0);
+
+	return esc_entry;
+}
+
+static int initialize_escs(void)
+{
+	int i, res = 0;
+	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+		if (!((event_state_compositors[i].compositor) =
+					ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
+			res = -1;
+		}
+	}
+	return res;
+}
+
+static void destroy_escs(void)
+{
+	int i;
+	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+		ao2_ref(event_state_compositors[i].compositor, -1);
+	}
+}
+
 struct state_notify_data {
 	int state;
 	struct ao2_container *device_state_info;
@@ -958,9 +1136,6 @@ struct state_notify_data {
 	const char *presence_message;
 };
 
-
-static const int ESC_MAX_BUCKETS = 37;
-
 /*!
  * \details
  * Here we implement the container for dialogs which are in the
@@ -1004,11 +1179,15 @@ static struct sip_peer *bogus_peer;
 #define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string"
 
 /*! \brief  The register list: Other SIP proxies we register with and receive calls from */
-static struct ao2_container *registry_list;
+static struct ast_register_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
+	int recheck;
+} regl;
 
 /*! \brief  The MWI subscription list */
-static struct ao2_container *subscription_mwi_list;
-
+static struct ast_subscription_mwi_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct sip_subscription_mwi);
+} submwil;
 static int temp_pvt_init(void *);
 static void temp_pvt_cleanup(void *);
 
@@ -1026,11 +1205,6 @@ static struct sip_auth_container *authl = NULL;
 /*! \brief Global authentication container protection while adjusting the references. */
 AST_MUTEX_DEFINE_STATIC(authl_lock);
 
-static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(session_timeout_type,
-	.to_ami = session_timeout_to_ami,
-	);
-
 /* --- Sockets and networking --------------*/
 
 /*! \brief Main socket for UDP SIP communication.
@@ -1106,8 +1280,6 @@ static struct ast_config *notify_types = NULL;    /*!< The list of manual NOTIFY
 		(head) = (element)->next;	\
 	} while (0)
 
-struct ao2_container *sip_monitor_instances;
-
 struct show_peers_context;
 
 /*---------------------------- Forward declarations of functions in chan_sip.c */
@@ -1115,7 +1287,7 @@ struct show_peers_context;
 	in coming releases. */
 
 /*--- PBX interface functions */
-static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause);
+static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
 static int sip_devicestate(const char *data);
 static int sip_sendtext(struct ast_channel *ast, const char *text);
 static int sip_call(struct ast_channel *ast, const char *dest, int timeout);
@@ -1134,7 +1306,7 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
 static const char *sip_get_callid(struct ast_channel *chan);
 
 static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr);
-static int sip_standard_port(enum ast_transport type, int port);
+static int sip_standard_port(enum sip_transport type, int port);
 static int sip_prepare_socket(struct sip_pvt *p);
 static int get_address_family_filter(unsigned int transport);
 
@@ -1178,17 +1350,19 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only);
 
 /* Misc dialog routines */
 static int __sip_autodestruct(const void *data);
+static void *registry_unref(struct sip_registry *reg, char *tag);
 static int update_call_counter(struct sip_pvt *fup, int event);
 static int auto_congest(const void *arg);
 static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method);
+static void free_old_route(struct sip_route *route);
+static void list_route(struct sip_route *route);
 static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
-static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, const char *pathbuf);
 static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
 					      struct sip_request *req, const char *uri);
-static int get_sip_pvt_from_replaces(const char *callid, const char *totag, const char *fromtag,
-		struct sip_pvt **out_pvt, struct ast_channel **out_chan);
+static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
 static void check_pendings(struct sip_pvt *p);
-static void sip_set_owner(struct sip_pvt *p, struct ast_channel *chan);
+static void *sip_park_thread(void *stuff);
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, uint32_t seqno, const char *park_exten, const char *park_context);
 
 static void *sip_pickup_thread(void *stuff);
 static int sip_pickup(struct ast_channel *chan);
@@ -1216,7 +1390,7 @@ static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **
 static void start_ice(struct ast_rtp_instance *instance, int offer);
 static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
 			     struct ast_str **m_buf, struct ast_str **a_buf,
-			     int debug, int *min_packet_size, int *max_packet_size);
+			     int debug, int *min_packet_size);
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
 				struct ast_str **m_buf, struct ast_str **a_buf,
 				int debug);
@@ -1259,6 +1433,8 @@ static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt);
 static int sip_refer_alloc(struct sip_pvt *p);
 static void sip_refer_destroy(struct sip_pvt *p);
 static int sip_notify_alloc(struct sip_pvt *p);
+static void ast_quiet_chan(struct ast_channel *chan);
+static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
 static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
 static void set_peer_nat(const struct sip_pvt *p, struct sip_peer *peer);
 static void check_for_nat(const struct ast_sockaddr *them, struct sip_pvt *p);
@@ -1270,9 +1446,9 @@ static int sip_poke_noanswer(const void *data);
 static int sip_poke_peer(struct sip_peer *peer, int force);
 static void sip_poke_all_peers(void);
 static void sip_peer_hold(struct sip_pvt *p, int hold);
-static void mwi_event_cb(void *, struct stasis_subscription *, struct stasis_message *);
-static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
+static void mwi_event_cb(const struct ast_event *, void *);
+static void network_change_event_cb(const struct ast_event *, void *);
+static void acl_change_event_cb(const struct ast_event *event, void *userdata);
 static void sip_keepalive_all_peers(void);
 
 /*--- Applications, functions, CLI and manager command helpers */
@@ -1292,6 +1468,7 @@ static int str2dtmfmode(const char *str) attribute_unused;
 static const char *insecure2str(int mode) attribute_const;
 static const char *allowoverlap2str(int mode) attribute_const;
 static void cleanup_stale_contexts(char *new, char *old);
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
 static const char *domain_mode_to_text(const enum domain_mode mode);
 static char *sip_show_domains(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
@@ -1357,7 +1534,7 @@ static void set_socket_transport(struct sip_socket *socket, int transport);
 static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags);
 
 /* Realtime device support */
-static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path);
+static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
 static void update_peer(struct sip_peer *p, int expire);
 static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
 static const char *get_name_from_variable(const struct ast_variable *var);
@@ -1366,7 +1543,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
 
 /*--- Internal UA client handling (outbound registrations) */
 static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us, struct sip_pvt *p);
-static void sip_registry_destroy(void *reg);
+static void sip_registry_destroy(struct sip_registry *reg);
 static int sip_register(const char *value, int lineno);
 static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
 static int sip_reregister(const void *data);
@@ -1398,7 +1575,7 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
 static int set_address_from_contact(struct sip_pvt *pvt);
 static void check_via(struct sip_pvt *p, const struct sip_request *req);
 static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason, char **reason_str);
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
 static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
 static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout);
 static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
@@ -1439,14 +1616,14 @@ static int add_text(struct sip_request *req, struct sip_pvt *p);
 static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
 static int add_rpid(struct sip_request *req, struct sip_pvt *p);
 static int add_vidupdate(struct sip_request *req);
-static void add_route(struct sip_request *req, struct sip_route *route, int skip);
+static void add_route(struct sip_request *req, struct sip_route *route);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
-static void set_destination(struct sip_pvt *p, const char *uri);
+static void set_destination(struct sip_pvt *p, char *uri);
 static void add_date(struct sip_request *req);
 static void add_expires(struct sip_request *req, int expires);
-static void build_contact(struct sip_pvt *p);
+static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming);
 
 /*------Request handling functions */
 static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock);
@@ -1460,10 +1637,9 @@ static int handle_request_message(struct sip_pvt *p, struct sip_request *req, st
 static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, const char *e);
 static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
 static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req,
-		int *nounlock, struct sip_pvt *replaces_pvt, struct ast_channel *replaces_chan);
+static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, int *nounlock);
 static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, const char *e);
-static int local_attended_transfer(struct sip_pvt *transferer, struct ast_channel *transferer_chan, uint32_t seqno, int *nounlock);
+static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, uint32_t seqno, int *nounlock);
 
 /*------Response handling functions */
 static void handle_response_publish(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
@@ -1475,10 +1651,13 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
 
 /*------ SRTP Support -------- */
-static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a);
+static int setup_srtp(struct sip_srtp **srtp);
+static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a);
 
 /*------ T38 Support --------- */
 static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
+static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
+static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
 static void change_t38_state(struct sip_pvt *p, int state);
 
 /*------ Session-Timers functions --------- */
@@ -1487,7 +1666,7 @@ static int  proc_session_timer(const void *vp);
 static void stop_session_timer(struct sip_pvt *p);
 static void start_session_timer(struct sip_pvt *p);
 static void restart_session_timer(struct sip_pvt *p);
-static const char *strefresherparam2str(enum st_refresher r);
+static const char *strefresherparam2str(enum st_refresher_param r);
 static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref);
 static int parse_minse(const char *p_hdrval, int *const p_interval);
 static int st_get_se(struct sip_pvt *, int max);
@@ -1500,7 +1679,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 
 /*!--- SIP MWI Subscription support */
 static int sip_subscribe_mwi(const char *value, int lineno);
-static void sip_subscribe_mwi_destroy(void *data);
+static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi);
 static void sip_send_all_mwi_subscriptions(void);
 static int sip_subscribe_mwi_do(const void *data);
 static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi);
@@ -1525,6 +1704,7 @@ struct ast_channel_tech sip_tech = {
 	.fixup = sip_fixup,			/* called with chan locked */
 	.send_digit_begin = sip_senddigit_begin,	/* called with chan unlocked */
 	.send_digit_end = sip_senddigit_end,
+	.bridge = ast_rtp_instance_bridge,			/* XXX chan unlocked ? */
 	.early_bridge = ast_rtp_instance_early_bridge,
 	.send_text = sip_sendtext,		/* called with chan locked */
 	.func_channel_read = sip_acf_channel_read,
@@ -1563,208 +1743,6 @@ static struct ast_cc_agent_callbacks sip_cc_agent_callbacks = {
 	.destructor = sip_cc_agent_destructor,
 };
 
-/* -------- End of declarations of structures, constants and forward declarations of functions
-   Below starts actual code
-   ------------------------
-*/
-
-static int sip_epa_register(const struct epa_static_data *static_data)
-{
-	struct epa_backend *backend = ast_calloc(1, sizeof(*backend));
-
-	if (!backend) {
-		return -1;
-	}
-
-	backend->static_data = static_data;
-
-	AST_LIST_LOCK(&epa_static_data_list);
-	AST_LIST_INSERT_TAIL(&epa_static_data_list, backend, next);
-	AST_LIST_UNLOCK(&epa_static_data_list);
-	return 0;
-}
-
-static void sip_epa_unregister_all(void)
-{
-	struct epa_backend *backend;
-
-	AST_LIST_LOCK(&epa_static_data_list);
-	while ((backend = AST_LIST_REMOVE_HEAD(&epa_static_data_list, next))) {
-		ast_free(backend);
-	}
-	AST_LIST_UNLOCK(&epa_static_data_list);
-}
-
-static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct sip_request *req, struct sip_epa_entry *epa_entry);
-
-static void cc_epa_destructor(void *data)
-{
-	struct sip_epa_entry *epa_entry = data;
-	struct cc_epa_entry *cc_entry = epa_entry->instance_data;
-	ast_free(cc_entry);
-}
-
-static const struct epa_static_data cc_epa_static_data  = {
-	.event = CALL_COMPLETION,
-	.name = "call-completion",
-	.handle_error = cc_handle_publish_error,
-	.destructor = cc_epa_destructor,
-};
-
-static const struct epa_static_data *find_static_data(const char * const event_package)
-{
-	const struct epa_backend *backend = NULL;
-
-	AST_LIST_LOCK(&epa_static_data_list);
-	AST_LIST_TRAVERSE(&epa_static_data_list, backend, next) {
-		if (!strcmp(backend->static_data->name, event_package)) {
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&epa_static_data_list);
-	return backend ? backend->static_data : NULL;
-}
-
-static struct sip_epa_entry *create_epa_entry (const char * const event_package, const char * const destination)
-{
-	struct sip_epa_entry *epa_entry;
-	const struct epa_static_data *static_data;
-
-	if (!(static_data = find_static_data(event_package))) {
-		return NULL;
-	}
-
-	if (!(epa_entry = ao2_t_alloc(sizeof(*epa_entry), static_data->destructor, "Allocate new EPA entry"))) {
-		return NULL;
-	}
-
-	epa_entry->static_data = static_data;
-	ast_copy_string(epa_entry->destination, destination, sizeof(epa_entry->destination));
-	return epa_entry;
-}
-static enum ast_cc_service_type service_string_to_service_type(const char * const service_string)
-{
-	enum ast_cc_service_type service;
-	for (service = AST_CC_CCBS; service <= AST_CC_CCNL; ++service) {
-		if (!strcasecmp(service_string, sip_cc_service_map[service].service_string)) {
-			return service;
-		}
-	}
-	return AST_CC_NONE;
-}
-
-/* Even state compositors code */
-static void esc_entry_destructor(void *obj)
-{
-	struct sip_esc_entry *esc_entry = obj;
-	if (esc_entry->sched_id > -1) {
-		AST_SCHED_DEL(sched, esc_entry->sched_id);
-	}
-}
-
-static int esc_hash_fn(const void *obj, const int flags)
-{
-	const struct sip_esc_entry *entry = obj;
-	return ast_str_hash(entry->entity_tag);
-}
-
-static int esc_cmp_fn(void *obj, void *arg, int flags)
-{
-	struct sip_esc_entry *entry1 = obj;
-	struct sip_esc_entry *entry2 = arg;
-
-	return (!strcmp(entry1->entity_tag, entry2->entity_tag)) ? (CMP_MATCH | CMP_STOP) : 0;
-}
-
-static struct event_state_compositor *get_esc(const char * const event_package) {
-	int i;
-	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
-		if (!strcasecmp(event_package, event_state_compositors[i].name)) {
-			return &event_state_compositors[i];
-		}
-	}
-	return NULL;
-}
-
-static struct sip_esc_entry *get_esc_entry(const char * entity_tag, struct event_state_compositor *esc) {
-	struct sip_esc_entry *entry;
-	struct sip_esc_entry finder;
-
-	ast_copy_string(finder.entity_tag, entity_tag, sizeof(finder.entity_tag));
-
-	entry = ao2_find(esc->compositor, &finder, OBJ_POINTER);
-
-	return entry;
-}
-
-static int publish_expire(const void *data)
-{
-	struct sip_esc_entry *esc_entry = (struct sip_esc_entry *) data;
-	struct event_state_compositor *esc = get_esc(esc_entry->event);
-
-	ast_assert(esc != NULL);
-
-	ao2_unlink(esc->compositor, esc_entry);
-	ao2_ref(esc_entry, -1);
-	return 0;
-}
-
-static void create_new_sip_etag(struct sip_esc_entry *esc_entry, int is_linked)
-{
-	int new_etag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
-	struct event_state_compositor *esc = get_esc(esc_entry->event);
-
-	ast_assert(esc != NULL);
-	if (is_linked) {
-		ao2_unlink(esc->compositor, esc_entry);
-	}
-	snprintf(esc_entry->entity_tag, sizeof(esc_entry->entity_tag), "%d", new_etag);
-	ao2_link(esc->compositor, esc_entry);
-}
-
-static struct sip_esc_entry *create_esc_entry(struct event_state_compositor *esc, struct sip_request *req, const int expires)
-{
-	struct sip_esc_entry *esc_entry;
-	int expires_ms;
-
-	if (!(esc_entry = ao2_alloc(sizeof(*esc_entry), esc_entry_destructor))) {
-		return NULL;
-	}
-
-	esc_entry->event = esc->name;
-
-	expires_ms = expires * 1000;
-	/* Bump refcount for scheduler */
-	ao2_ref(esc_entry, +1);
-	esc_entry->sched_id = ast_sched_add(sched, expires_ms, publish_expire, esc_entry);
-
-	/* Note: This links the esc_entry into the ESC properly */
-	create_new_sip_etag(esc_entry, 0);
-
-	return esc_entry;
-}
-
-static int initialize_escs(void)
-{
-	int i, res = 0;
-	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
-		if (!((event_state_compositors[i].compositor) =
-					ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
-			res = -1;
-		}
-	}
-	return res;
-}
-
-static void destroy_escs(void)
-{
-	int i;
-	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
-		ao2_cleanup(event_state_compositors[i].compositor);
-	}
-}
-
-
 static int find_by_notify_uri_helper(void *obj, void *arg, int flags)
 {
 	struct ast_cc_agent *agent = obj;
@@ -1947,6 +1925,7 @@ static void sip_cc_agent_destructor(struct ast_cc_agent *agent)
 	ast_free(agent_pvt);
 }
 
+struct ao2_container *sip_monitor_instances;
 
 static int sip_monitor_instance_hash_fn(const void *obj, const int flags)
 {
@@ -2400,35 +2379,8 @@ static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text)
 	return ast;
 }
 
-static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason, int *table_lookup)
+static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
 {
-	int code = reason->code;
-
-	/* If there's a specific string set, then we just
-	 * use it.
-	 */
-	if (!ast_strlen_zero(reason->str)) {
-		/* If we care about whether this can be found in
-		 * the table, then we need to check about that.
-		 */
-		if (table_lookup) {
-			/* If the string is literally "unknown" then don't bother with the lookup
-			 * because it can lead to a false negative.
-			 */
-			if (!strcasecmp(reason->str, "unknown") ||
-					sip_reason_str_to_code(reason->str) != AST_REDIRECTING_REASON_UNKNOWN) {
-				*table_lookup = TRUE;
-			} else {
-				*table_lookup = FALSE;
-			}
-		}
-		return reason->str;
-	}
-
-	if (table_lookup) {
-		*table_lookup = TRUE;
-	}
-
 	if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) {
 		return sip_reason_table[code].text;
 	}
@@ -2453,7 +2405,7 @@ static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *r
 			sip_get_transport(tmpl->socket.type), peer->name, get_transport_list(peer->transports) \
 			); \
 		ret = 1; \
-	} else if (peer->socket.type & AST_TRANSPORT_TLS) { \
+	} else if (peer->socket.type & SIP_TRANSPORT_TLS) { \
 		ast_log(LOG_WARNING, \
 			"peer '%s' HAS NOT USED (OR SWITCHED TO) TLS in favor of '%s' (but this was allowed in sip.conf)!\n", \
 			peer->name, sip_get_transport(tmpl->socket.type) \
@@ -2546,7 +2498,7 @@ static struct sip_threadinfo *sip_threadinfo_create(struct ast_tcptls_session_in
 	}
 	ao2_t_ref(tcptls_session, +1, "tcptls_session ref for sip_threadinfo object");
 	th->tcptls_session = tcptls_session;
-	th->type = transport ? transport : (tcptls_session->ssl ? AST_TRANSPORT_TLS: AST_TRANSPORT_TCP);
+	th->type = transport ? transport : (tcptls_session->ssl ? SIP_TRANSPORT_TLS: SIP_TRANSPORT_TCP);
 	ao2_t_link(threadt, th, "Adding new tcptls helper thread");
 	ao2_t_ref(th, -1, "Decrementing threadinfo ref from alloc, only table ref remains");
 	return th;
@@ -2659,7 +2611,7 @@ static void sip_websocket_callback(struct ast_websocket *session, struct ast_var
 			}
 
 			req.socket.fd = ast_websocket_fd(session);
-			set_socket_transport(&req.socket, ast_websocket_is_secure(session) ? AST_TRANSPORT_WSS : AST_TRANSPORT_WS);
+			set_socket_transport(&req.socket, ast_websocket_is_secure(session) ? SIP_TRANSPORT_WSS : SIP_TRANSPORT_WS);
 			req.socket.ws_session = session;
 
 			handle_request_do(&req, ast_websocket_remote_address(session));
@@ -2964,7 +2916,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
 			goto cleanup;
 		}
 
-		if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) {
+		if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP))) {
 			goto cleanup;
 		}
 		ao2_t_ref(me, +1, "Adding threadinfo ref for tcp_helper_thread");
@@ -3050,7 +3002,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
 			}
 		}
 
-		/*
+		/* 
 		 * handle the socket event, check for both reads from the socket fd or TCP overflow buffer,
 		 * and writes from alert_pipe fd.
 		 */
@@ -3071,10 +3023,10 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
 			memset(buf, 0, sizeof(buf));
 
 			if (tcptls_session->ssl) {
-				set_socket_transport(&req.socket, AST_TRANSPORT_TLS);
+				set_socket_transport(&req.socket, SIP_TRANSPORT_TLS);
 				req.socket.port = htons(ourport_tls);
 			} else {
-				set_socket_transport(&req.socket, AST_TRANSPORT_TCP);
+				set_socket_transport(&req.socket, SIP_TRANSPORT_TCP);
 				req.socket.port = htons(ourport_tcp);
 			}
 			req.socket.fd = tcptls_session->fd;
@@ -3234,7 +3186,7 @@ static void unlink_peers_from_tables(peer_unlink_flag_t flag)
 	ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
 		match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers");
 	ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
-		match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers_by_ip");
+		match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers");
 }
 
 /* \brief Unlink all marked peers from ao2 containers */
@@ -3299,7 +3251,7 @@ void dialog_unlink_all(struct sip_pvt *dialog)
 		ast_channel_tech_pvt_set(owner, dialog_unref(ast_channel_tech_pvt(owner), "resetting channel dialog ptr in unlink_all"));
 		ast_channel_unlock(owner);
 		ast_channel_unref(owner);
-		sip_set_owner(dialog, NULL);
+		dialog->owner = NULL;
 	}
 	sip_pvt_unlock(dialog);
 
@@ -3307,7 +3259,7 @@ void dialog_unlink_all(struct sip_pvt *dialog)
 		if (dialog->registry->call == dialog) {
 			dialog->registry->call = dialog_unref(dialog->registry->call, "nulling out the registry's call dialog field in unlink_all");
 		}
-		ao2_t_replace(dialog->registry, NULL, "delete dialog->registry");
+		dialog->registry = registry_unref(dialog->registry, "delete dialog->registry");
 	}
 	if (dialog->stateid != -1) {
 		ast_extension_state_del(dialog->stateid, cb_extensionstate);
@@ -3336,6 +3288,10 @@ void dialog_unlink_all(struct sip_pvt *dialog)
 
 	AST_SCHED_DEL_UNREF(sched, dialog->initid, dialog_unref(dialog, "when you delete the initid sched, you should dec the refcount for the stored dialog ptr"));
 
+	if (dialog->reinviteid > -1) {
+		AST_SCHED_DEL_UNREF(sched, dialog->reinviteid, dialog_unref(dialog, "clear ref for reinvite_timeout"));
+	}
+
 	if (dialog->autokillid > -1) {
 		AST_SCHED_DEL_UNREF(sched, dialog->autokillid, dialog_unref(dialog, "when you delete the autokillid sched, you should dec the refcount for the stored dialog ptr"));
 	}
@@ -3357,6 +3313,27 @@ void dialog_unlink_all(struct sip_pvt *dialog)
 	dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time");
 }
 
+void *registry_unref(struct sip_registry *reg, char *tag)
+{
+	ast_debug(3, "SIP Registry %s: refcount now %u\n", reg->hostname, reg->refcount - 1);
+	ASTOBJ_UNREF(reg, sip_registry_destroy);
+	return NULL;
+}
+
+/*! \brief Add object reference to SIP registry */
+static struct sip_registry *registry_addref(struct sip_registry *reg, char *tag)
+{
+	ast_debug(3, "SIP Registry %s: refcount now %u\n", reg->hostname, reg->refcount + 1);
+	return ASTOBJ_REF(reg);	/* Add pointer to registry in packet */
+}
+
+/*! \brief Interface structure with callbacks used to connect to UDPTL module*/
+static struct ast_udptl_protocol sip_udptl = {
+	.type = "SIP",
+	.get_udptl_info = sip_get_udptl_peer,
+	.set_udptl_peer = sip_set_udptl_peer,
+};
+
 static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
 	__attribute__((format(printf, 2, 3)));
 
@@ -3412,7 +3389,7 @@ static int proxy_update(struct sip_proxy *proxy)
 	if (!ast_sockaddr_parse(&proxy->ip, proxy->name, 0)) {
 		/* Ok, not an IP address, then let's check if it's a domain or host */
 		/* XXX Todo - if we have proxy port, don't do SRV */
-		proxy->ip.ss.ss_family = get_address_family_filter(AST_TRANSPORT_UDP); /* Filter address family */
+		proxy->ip.ss.ss_family = get_address_family_filter(SIP_TRANSPORT_UDP); /* Filter address family */
 		if (ast_get_ip_or_srv(&proxy->ip, proxy->name, sip_cfg.srvlookup ? "_sip._udp" : NULL) < 0) {
 				ast_log(LOG_WARNING, "Unable to locate host '%s'\n", proxy->name);
 				return FALSE;
@@ -3535,7 +3512,7 @@ static int method_match(enum sipmethod id, const char *name)
 static int find_sip_method(const char *msg)
 {
 	int i, res = 0;
-
+	
 	if (ast_strlen_zero(msg)) {
 		return 0;
 	}
@@ -3605,19 +3582,19 @@ static int get_transport_str2enum(const char *transport)
 	}
 
 	if (!strcasecmp(transport, "udp")) {
-		res |= AST_TRANSPORT_UDP;
+		res |= SIP_TRANSPORT_UDP;
 	}
 	if (!strcasecmp(transport, "tcp")) {
-		res |= AST_TRANSPORT_TCP;
+		res |= SIP_TRANSPORT_TCP;
 	}
 	if (!strcasecmp(transport, "tls")) {
-		res |= AST_TRANSPORT_TLS;
+		res |= SIP_TRANSPORT_TLS;
 	}
 	if (!strcasecmp(transport, "ws")) {
-		res |= AST_TRANSPORT_WS;
+		res |= SIP_TRANSPORT_WS;
 	}
 	if (!strcasecmp(transport, "wss")) {
-		res |= AST_TRANSPORT_WSS;
+		res |= SIP_TRANSPORT_WSS;
 	}
 
 	return res;
@@ -3638,19 +3615,19 @@ static inline const char *get_transport_list(unsigned int transports)
 
 	memset(buf, 0, SIP_TRANSPORT_STR_BUFSIZE);
 
-	if (transports & AST_TRANSPORT_UDP) {
+	if (transports & SIP_TRANSPORT_UDP) {
 		strncat(buf, "UDP,", SIP_TRANSPORT_STR_BUFSIZE - strlen(buf));
 	}
-	if (transports & AST_TRANSPORT_TCP) {
+	if (transports & SIP_TRANSPORT_TCP) {
 		strncat(buf, "TCP,", SIP_TRANSPORT_STR_BUFSIZE - strlen(buf));
 	}
-	if (transports & AST_TRANSPORT_TLS) {
+	if (transports & SIP_TRANSPORT_TLS) {
 		strncat(buf, "TLS,", SIP_TRANSPORT_STR_BUFSIZE - strlen(buf));
 	}
-	if (transports & AST_TRANSPORT_WS) {
+	if (transports & SIP_TRANSPORT_WS) {
 		strncat(buf, "WS,", SIP_TRANSPORT_STR_BUFSIZE - strlen(buf));
 	}
-	if (transports & AST_TRANSPORT_WSS) {
+	if (transports & SIP_TRANSPORT_WSS) {
 		strncat(buf, "WSS,", SIP_TRANSPORT_STR_BUFSIZE - strlen(buf));
 	}
 
@@ -3663,17 +3640,17 @@ static inline const char *get_transport_list(unsigned int transports)
 }
 
 /*! \brief Return transport as string */
-const char *sip_get_transport(enum ast_transport t)
+const char *sip_get_transport(enum sip_transport t)
 {
 	switch (t) {
-	case AST_TRANSPORT_UDP:
+	case SIP_TRANSPORT_UDP:
 		return "UDP";
-	case AST_TRANSPORT_TCP:
+	case SIP_TRANSPORT_TCP:
 		return "TCP";
-	case AST_TRANSPORT_TLS:
+	case SIP_TRANSPORT_TLS:
 		return "TLS";
-	case AST_TRANSPORT_WS:
-	case AST_TRANSPORT_WSS:
+	case SIP_TRANSPORT_WS:
+	case SIP_TRANSPORT_WSS:
 		return "WS";
 	}
 
@@ -3681,17 +3658,17 @@ const char *sip_get_transport(enum ast_transport t)
 }
 
 /*! \brief Return protocol string for srv dns query */
-static inline const char *get_srv_protocol(enum ast_transport t)
+static inline const char *get_srv_protocol(enum sip_transport t)
 {
 	switch (t) {
-	case AST_TRANSPORT_UDP:
+	case SIP_TRANSPORT_UDP:
 		return "udp";
-	case AST_TRANSPORT_WS:
+	case SIP_TRANSPORT_WS:
 		return "ws";
-	case AST_TRANSPORT_TLS:
-	case AST_TRANSPORT_TCP:
+	case SIP_TRANSPORT_TLS:
+	case SIP_TRANSPORT_TCP:
 		return "tcp";
-	case AST_TRANSPORT_WSS:
+	case SIP_TRANSPORT_WSS:
 		return "wss";
 	}
 
@@ -3699,15 +3676,15 @@ static inline const char *get_srv_protocol(enum ast_transport t)
 }
 
 /*! \brief Return service string for srv dns query */
-static inline const char *get_srv_service(enum ast_transport t)
+static inline const char *get_srv_service(enum sip_transport t)
 {
 	switch (t) {
-	case AST_TRANSPORT_TCP:
-	case AST_TRANSPORT_UDP:
-	case AST_TRANSPORT_WS:
+	case SIP_TRANSPORT_TCP:
+	case SIP_TRANSPORT_UDP:
+	case SIP_TRANSPORT_WS:
 		return "sip";
-	case AST_TRANSPORT_TLS:
-	case AST_TRANSPORT_WSS:
+	case SIP_TRANSPORT_TLS:
+	case SIP_TRANSPORT_WSS:
 		return "sips";
 	}
 	return "sip";
@@ -3750,7 +3727,7 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data)
 		return XMIT_ERROR;
 	}
 
-	if (p->socket.type == AST_TRANSPORT_UDP) {
+	if (p->socket.type == SIP_TRANSPORT_UDP) {
 		res = ast_sendto(p->socket.fd, ast_str_buffer(data), ast_str_strlen(data), 0, dst);
 	} else if (p->socket.tcptls_session) {
 		res = sip_tcptls_write(p->socket.tcptls_session, ast_str_buffer(data), ast_str_strlen(data));
@@ -3824,7 +3801,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 	ast_ouraddrfor(them, us);
 	ast_sockaddr_copy(&theirs, them);
 
-	if (ast_sockaddr_is_ipv6(&theirs)) {
+	if (ast_sockaddr_is_ipv6(&theirs) && !ast_sockaddr_is_ipv4_mapped(&theirs)) {
 		if (localaddr && !ast_sockaddr_isnull(&externaddr) && !ast_sockaddr_is_any(&bindaddr)) {
 			ast_log(LOG_WARNING, "Address remapping activated in sip.conf "
 				"but we're using IPv6, which doesn't need it. Please "
@@ -3848,17 +3825,17 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 		if (!ast_sockaddr_isnull(&externaddr)) {
 			ast_sockaddr_copy(us, &externaddr);
 			switch (p->socket.type) {
-			case AST_TRANSPORT_TCP:
+			case SIP_TRANSPORT_TCP:
 				if (!externtcpport && ast_sockaddr_port(&externaddr)) {
 					/* for consistency, default to the externaddr port */
 					externtcpport = ast_sockaddr_port(&externaddr);
 				}
 				ast_sockaddr_set_port(us, externtcpport);
 				break;
-			case AST_TRANSPORT_TLS:
+			case SIP_TRANSPORT_TLS:
 				ast_sockaddr_set_port(us, externtlsport);
 				break;
-			case AST_TRANSPORT_UDP:
+			case SIP_TRANSPORT_UDP:
 				if (!ast_sockaddr_port(&externaddr)) {
 					ast_sockaddr_set_port(us, ast_sockaddr_port(&bindaddr));
 				}
@@ -3872,7 +3849,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 	} else {
 		/* no remapping, but we bind to a specific address, so use it. */
 		switch (p->socket.type) {
-		case AST_TRANSPORT_TCP:
+		case SIP_TRANSPORT_TCP:
 			if (!ast_sockaddr_is_any(&sip_tcp_desc.local_address)) {
 				ast_sockaddr_copy(us,
 						  &sip_tcp_desc.local_address);
@@ -3881,7 +3858,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 						      ast_sockaddr_port(&sip_tcp_desc.local_address));
 			}
 			break;
-		case AST_TRANSPORT_TLS:
+		case SIP_TRANSPORT_TLS:
 			if (!ast_sockaddr_is_any(&sip_tls_desc.local_address)) {
 				ast_sockaddr_copy(us,
 						  &sip_tls_desc.local_address);
@@ -3890,7 +3867,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 						      ast_sockaddr_port(&sip_tls_desc.local_address));
 			}
 			break;
-		case AST_TRANSPORT_UDP:
+		case SIP_TRANSPORT_UDP:
 			/* fall through on purpose */
 		default:
 			if (!ast_sockaddr_is_any(&bindaddr)) {
@@ -3901,7 +3878,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
 			}
 		}
 	}
-	ast_debug(3, "Setting AST_TRANSPORT_%s with address %s\n", sip_get_transport(p->socket.type), ast_sockaddr_stringify(us));
+	ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s\n", sip_get_transport(p->socket.type), ast_sockaddr_stringify(us));
 }
 
 /*! \brief Append to SIP dialog history with arg list  */
@@ -4164,7 +4141,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in
 	/* If the transport is something reliable (TCP or TLS) then don't really send this reliably */
 	/* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */
 	/*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */
-	if (!(p->socket.type & AST_TRANSPORT_UDP)) {
+	if (!(p->socket.type & SIP_TRANSPORT_UDP)) {
 		xmitres = __sip_xmit(p, data);	/* Send packet */
 		if (xmitres == XMIT_ERROR) {	/* Serious network trouble, no need to try again */
 			append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)");
@@ -4356,7 +4333,7 @@ void sip_scheddestroy(struct sip_pvt *p, int ms)
 	}
 	p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, dialog_ref(p, "setting ref as passing into ast_sched_add for __sip_autodestruct"));
 
-	if (p->stimer && p->stimer->st_active == TRUE && p->stimer->st_schedid > 0) {
+	if (p->stimer && p->stimer->st_active == TRUE && p->stimer->st_schedid > -1) {
 		stop_session_timer(p);
 	}
 }
@@ -4737,12 +4714,17 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
 	switch (option) {
 	case AST_OPTION_FORMAT_READ:
 		if (p->rtp) {
-			res = ast_rtp_instance_set_read_format(p->rtp, *(struct ast_format **) data);
+			res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data);
 		}
 		break;
 	case AST_OPTION_FORMAT_WRITE:
 		if (p->rtp) {
-			res = ast_rtp_instance_set_write_format(p->rtp, *(struct ast_format **) data);
+			res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data);
+		}
+		break;
+	case AST_OPTION_MAKE_COMPATIBLE:
+		if (p->rtp) {
+			res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
 		}
 		break;
 	case AST_OPTION_DIGIT_DETECT:
@@ -4945,7 +4927,7 @@ static int sip_sendtext(struct ast_channel *ast, const char *text)
 	that name and store that in the "regserver" field in the sippeers
 	table to facilitate multi-server setups.
 */
-static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path)
+static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms)
 {
 	char port[10];
 	char ipaddr[INET6_ADDRSTRLEN];
@@ -4968,11 +4950,10 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
 	ast_copy_string(ipaddr, ast_sockaddr_isnull(addr) ? "" : ast_sockaddr_stringify_addr(addr), sizeof(ipaddr));
 	ast_copy_string(port, ast_sockaddr_port(addr) ? ast_sockaddr_stringify_port(addr) : "", sizeof(port));
 
-	if (ast_strlen_zero(sysname)) {	/* No system name, disable this */
+	if (ast_strlen_zero(sysname))	/* No system name, disable this */
 		sysname = NULL;
-	} else if (sip_cfg.rtsave_sysname) {
+	else if (sip_cfg.rtsave_sysname)
 		syslabel = "regserver";
-	}
 
 	/* XXX IMPORTANT: Anytime you add a new parameter to be updated, you
          *  must also add it to contrib/scripts/asterisk.ldap-schema,
@@ -4980,38 +4961,18 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
          *  and to configs/res_ldap.conf.sample as described in
          *  bugs 15156 and 15895
          */
-
-	/* This is ugly, we need something better ;-) */
-	if (sip_cfg.rtsave_path) {
-		if (fc) {
-			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-				"port", port, "regseconds", regseconds,
-				deprecated_username ? "username" : "defaultuser", defaultuser,
-				"useragent", useragent, "lastms", str_lastms,
-				"path", path,			/* Path data can be NULL */
-				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
-		} else {
-			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-				"port", port, "regseconds", regseconds,
-				"useragent", useragent, "lastms", str_lastms,
-				deprecated_username ? "username" : "defaultuser", defaultuser,
-				"path", path,			/* Path data can be NULL */
-				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
-		}
+	if (fc) {
+		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+			"port", port, "regseconds", regseconds,
+			deprecated_username ? "username" : "defaultuser", defaultuser,
+			"useragent", useragent, "lastms", str_lastms,
+			fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
 	} else {
-		if (fc) {
-			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-				"port", port, "regseconds", regseconds,
-				deprecated_username ? "username" : "defaultuser", defaultuser,
-				"useragent", useragent, "lastms", str_lastms,
-				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
-		} else {
-			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-				"port", port, "regseconds", regseconds,
-				"useragent", useragent, "lastms", str_lastms,
-				deprecated_username ? "username" : "defaultuser", defaultuser,
-				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
-		}
+		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+			"port", port, "regseconds", regseconds,
+			"useragent", useragent, "lastms", str_lastms,
+			deprecated_username ? "username" : "defaultuser", defaultuser,
+			syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
 	}
 }
 
@@ -5055,9 +5016,8 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
 /*! Destroy mailbox subscriptions */
 static void destroy_mailbox(struct sip_mailbox *mailbox)
 {
-	if (mailbox->event_sub) {
-		mailbox->event_sub = stasis_unsubscribe(mailbox->event_sub);
-	}
+	if (mailbox->event_sub)
+		ast_event_unsubscribe(mailbox->event_sub);
 	ast_free(mailbox);
 }
 
@@ -5107,7 +5067,6 @@ static void sip_destroy_peer(struct sip_peer *peer)
 		ast_variables_destroy(peer->chanvars);
 		peer->chanvars = NULL;
 	}
-	sip_route_clear(&peer->path);
 
 	register_peer_exten(peer, FALSE);
 	ast_free_acl_list(peer->acl);
@@ -5139,26 +5098,18 @@ static void sip_destroy_peer(struct sip_peer *peer)
 
 	ast_string_field_free_memory(peer);
 
-	ao2_cleanup(peer->caps);
+	peer->caps = ast_format_cap_destroy(peer->caps);
 
 	ast_rtp_dtls_cfg_free(&peer->dtls_cfg);
-
-	ast_endpoint_shutdown(peer->endpoint);
-	peer->endpoint = NULL;
 }
 
 /*! \brief Update peer data in database (if used) */
 static void update_peer(struct sip_peer *p, int expire)
 {
 	int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
-	if (sip_cfg.peer_rtupdate && (p->is_realtime || rtcachefriends)) {
-		struct ast_str *r = sip_route_list(&p->path, 0, 0);
-		if (r) {
-			realtime_update_peer(p->name, &p->addr, p->username,
-				p->fullcontact, p->useragent, expire, p->deprecated_username,
-				p->lastms, ast_str_buffer(r));
-			ast_free(r);
-		}
+	if (sip_cfg.peer_rtupdate &&
+	    (p->is_realtime || rtcachefriends)) {
+		realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms);
 	}
 }
 
@@ -5300,7 +5251,7 @@ static int realtime_peer_by_name(const char *const *name, struct ast_sockaddr *a
 					if (ast_sockaddr_resolve(&addrs,
 								 tmp->value,
 								 PARSE_PORT_FORBID,
-								 get_address_family_filter(AST_TRANSPORT_UDP)) <= 0 ||
+								 get_address_family_filter(SIP_TRANSPORT_UDP)) <= 0 ||
 								 ast_sockaddr_cmp(&addrs[0], addr)) {
 						/* No match */
 						ast_variables_destroy(*var);
@@ -5447,7 +5398,7 @@ static int register_realtime_peers_with_callbackextens(void)
  * Checks the "sipregs" realtime family from extconfig.conf if it's configured.
  * This returns a pointer to a peer and because we use build_peer, we can rest
  * assured that the refcount is bumped.
- *
+ * 
  * \note This is never called with both newpeername and addr at the same time.
  * If you do, be prepared to get a peer with a different name than newpeername.
  */
@@ -5606,7 +5557,7 @@ static struct sip_peer *sip_find_peer_full(const char *peer, struct ast_sockaddr
 
 /*!
  * \brief Locate device by name or ip address
- * \param peer, addr, realtime, devstate_only, transport
+ * \param peer, sin, realtime, devstate_only, transport
  * \param which_objects Define which objects should be matched when doing a lookup
  *        by name.  Valid options are FINDUSERS, FINDPEERS, or FINDALLDEVICES.
  *        Note that this option is not used at all when doing a lookup by IP.
@@ -5738,7 +5689,7 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket
 }
 
 /*! \brief Initialize DTLS-SRTP support on an RTP instance */
-static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp)
+static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct sip_srtp **srtp)
 {
 	struct ast_rtp_engine_dtls *dtls;
 
@@ -5763,7 +5714,7 @@ static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_
 		return -1;
 	}
 
-	if (!(*srtp = ast_sdp_srtp_alloc())) {
+	if (!(*srtp = sip_srtp_alloc())) {
 		ast_log(LOG_ERROR, "Failed to create required SRTP structure on RTP instance '%p'\n",
 			rtp);
 		return -1;
@@ -5798,7 +5749,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
 	}
 
 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) ||
-			(ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_MEDIA_TYPE_VIDEO)))) {
+			(ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_FORMAT_TYPE_VIDEO)))) {
 		if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) {
 			return -1;
 		}
@@ -5853,8 +5804,6 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
 	return 0;
 }
 
-static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp);
-
 /*! \brief Create address structure from peer reference.
  *	This function copies data from peer to the dialog, so we don't have to look up the peer
  *	again from memory or database during the life time of the dialog.
@@ -5884,11 +5833,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 	ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
 	ast_copy_flags(&dialog->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
-	/* Take the peer's caps */
-	if (peer->caps) {
-		ast_format_cap_remove_by_type(dialog->caps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(dialog->caps, peer->caps, AST_MEDIA_TYPE_UNKNOWN);
-	}
+	ast_format_cap_copy(dialog->caps, peer->caps);
+	dialog->prefs = peer->prefs;
 	dialog->amaflags = peer->amaflags;
 
 	ast_string_field_set(dialog, engine, peer->engine);
@@ -5898,12 +5844,6 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 	dialog->rtptimeout = peer->rtptimeout;
 	dialog->rtpholdtimeout = peer->rtpholdtimeout;
 	dialog->rtpkeepalive = peer->rtpkeepalive;
-	sip_route_copy(&dialog->route, &peer->path);
-	if (!sip_route_empty(&dialog->route)) {
-		/* Parse SIP URI of first route-set hop and use it as target address */
-		__set_address_from_contact(sip_route_first_uri(&dialog->route), &dialog->sa, dialog->socket.type == AST_TRANSPORT_TLS ? 1 : 0);
-	}
-
 	if (dialog_initialize_rtp(dialog)) {
 		return -1;
 	}
@@ -5912,8 +5852,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 		ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
 		ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 		/* Set Frame packetization */
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs);
 		dialog->autoframing = peer->autoframing;
-		ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(dialog->rtp), ast_format_cap_get_framing(dialog->caps));
 	}
 
 	/* XXX TODO: get fields directly from peer only as they are needed using dialog->relatedpeer */
@@ -5986,58 +5926,50 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 			}
 		}
 	}
-	if (!ast_strlen_zero(peer->fromuser)) {
+	if (!ast_strlen_zero(peer->fromuser))
 		ast_string_field_set(dialog, fromuser, peer->fromuser);
-	}
-	if (!ast_strlen_zero(peer->language)) {
+	if (!ast_strlen_zero(peer->language))
 		ast_string_field_set(dialog, language, peer->language);
-	}
 	/* Set timer T1 to RTT for this peer (if known by qualify=) */
 	/* Minimum is settable or default to 100 ms */
 	/* If there is a maxms and lastms from a qualify use that over a manual T1
 	   value. Otherwise, use the peer's T1 value. */
-	if (peer->maxms && peer->lastms) {
+	if (peer->maxms && peer->lastms)
 		dialog->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
-	} else {
+	else
 		dialog->timer_t1 = peer->timer_t1;
-	}
 
 	/* Set timer B to control transaction timeouts, the peer setting is the default and overrides
 	   the known timer */
-	if (peer->timer_b) {
+	if (peer->timer_b)
 		dialog->timer_b = peer->timer_b;
-	} else {
+	else
 		dialog->timer_b = 64 * dialog->timer_t1;
-	}
 
 	if ((ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
-	    (ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+	    (ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
 		dialog->noncodeccapability |= AST_RTP_DTMF;
-	} else {
+	else
 		dialog->noncodeccapability &= ~AST_RTP_DTMF;
-	}
 
 	dialog->directmediaacl = ast_duplicate_acl_list(peer->directmediaacl);
 
-	if (peer->call_limit) {
+	if (peer->call_limit)
 		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
-	}
-	if (!dialog->portinuri) {
+	if (!dialog->portinuri)
 		dialog->portinuri = peer->portinuri;
-	}
 	dialog->chanvars = copy_vars(peer->chanvars);
-	if (peer->fromdomainport) {
+	if (peer->fromdomainport)
 		dialog->fromdomainport = peer->fromdomainport;
-	}
 	dialog->callingpres = peer->callingpres;
 
 	return 0;
 }
 
 /*! \brief The default sip port for the given transport */
-static inline int default_sip_port(enum ast_transport type)
+static inline int default_sip_port(enum sip_transport type)
 {
-	return type == AST_TRANSPORT_TLS ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
+	return type == SIP_TRANSPORT_TLS ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
 }
 
 /*! \brief create address structure from device name
@@ -6113,7 +6045,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
 		 * an A record lookup should be used instead of SRV.
 		 */
 		if (!hostport.port && sip_cfg.srvlookup) {
-			snprintf(service, sizeof(service), "_%s._%s.%s",
+			snprintf(service, sizeof(service), "_%s._%s.%s", 
 				 get_srv_service(dialog->socket.type),
 				 get_srv_protocol(dialog->socket.type), peername);
 			if ((srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno,
@@ -6122,7 +6054,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
 			}
 		}
 
-		if (ast_sockaddr_resolve_first_transport(&dialog->sa, hostn, 0, dialog->socket.type ? dialog->socket.type : AST_TRANSPORT_UDP)) {
+		if (ast_sockaddr_resolve_first_transport(&dialog->sa, hostn, 0, dialog->socket.type ? dialog->socket.type : SIP_TRANSPORT_UDP)) {
 			ast_log(LOG_WARNING, "No such host: %s\n", peername);
 			return -1;
 		}
@@ -6133,7 +6065,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
 	}
 
 	if (!dialog->socket.type)
-		set_socket_transport(&dialog->socket, AST_TRANSPORT_UDP);
+		set_socket_transport(&dialog->socket, SIP_TRANSPORT_UDP);
 	if (!dialog->socket.port) {
 		dialog->socket.port = htons(ast_sockaddr_port(&bindaddr));
 	}
@@ -6201,28 +6133,28 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 	}
 
 	/* Check whether there is vxml_url, distinctive ring variables */
-	headp = ast_channel_varshead(ast);
+	headp=ast_channel_varshead(ast);
 	AST_LIST_TRAVERSE(headp, current, entries) {
 		/* Check whether there is a VXML_URL variable */
-		if (!p->options->vxml_url && !strcmp(ast_var_name(current), "VXML_URL")) {
+		if (!p->options->vxml_url && !strcasecmp(ast_var_name(current), "VXML_URL")) {
 			p->options->vxml_url = ast_var_value(current);
-		} else if (!p->options->uri_options && !strcmp(ast_var_name(current), "SIP_URI_OPTIONS")) {
+		} else if (!p->options->uri_options && !strcasecmp(ast_var_name(current), "SIP_URI_OPTIONS")) {
 			p->options->uri_options = ast_var_value(current);
-		} else if (!p->options->addsipheaders && !strncmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
+		} else if (!p->options->addsipheaders && !strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
 			/* Check whether there is a variable with a name starting with SIPADDHEADER */
 			p->options->addsipheaders = 1;
-		} else if (!strcmp(ast_var_name(current), "SIPFROMDOMAIN")) {
+		} else if (!strcasecmp(ast_var_name(current), "SIPFROMDOMAIN")) {
 			ast_string_field_set(p, fromdomain, ast_var_value(current));
-		} else if (!strcmp(ast_var_name(current), "SIPTRANSFER")) {
+		} else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER")) {
 			/* This is a transferred call */
 			p->options->transfer = 1;
-		} else if (!strcmp(ast_var_name(current), "SIPTRANSFER_REFERER")) {
+		} else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REFERER")) {
 			/* This is the referrer */
 			referer = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
+		} else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
 			/* We're replacing a call. */
 			p->options->replaces = ast_var_value(current);
-		} else if (!strcmp(ast_var_name(current), "SIP_MAX_FORWARDS")) {
+		} else if (!strcasecmp(ast_var_name(current), "SIP_MAX_FORWARDS")) {
 			if (sscanf(ast_var_value(current), "%30d", &(p->maxforwards)) != 1) {
 				ast_log(LOG_WARNING, "The SIP_MAX_FORWARDS channel variable is not a valid integer.\n");
 			}
@@ -6230,7 +6162,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 	}
 
 	/* Check to see if we should try to force encryption */
-	if (p->req_secure_signaling && p->socket.type != AST_TRANSPORT_TLS) {
+	if (p->req_secure_signaling && p->socket.type != SIP_TRANSPORT_TLS) {
 	   ast_log(LOG_WARNING, "Encrypted signaling is required\n");
 	   ast_channel_hangupcause_set(ast, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 	   return -1;
@@ -6242,17 +6174,17 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 			ast_clear_flag(&p->flags[0], SIP_REINVITE);
 		}
 
-		if (p->rtp && !p->srtp && !(p->srtp = ast_sdp_srtp_alloc())) {
+		if (p->rtp && !p->srtp && setup_srtp(&p->srtp) < 0) {
 			ast_log(LOG_WARNING, "SRTP audio setup failed\n");
 			return -1;
 		}
 
-		if (p->vrtp && !p->vsrtp && !(p->vsrtp = ast_sdp_srtp_alloc())) {
+		if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp) < 0) {
 			ast_log(LOG_WARNING, "SRTP video setup failed\n");
 			return -1;
 		}
 
-		if (p->trtp && !p->tsrtp && !(p->tsrtp = ast_sdp_srtp_alloc())) {
+		if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) {
 			ast_log(LOG_WARNING, "SRTP text setup failed\n");
 			return -1;
 		}
@@ -6267,7 +6199,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 	ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38);
 
 	if (p->options->transfer) {
-		char buf[SIPBUFSIZE / 2];
+		char buf[SIPBUFSIZE/2];
 
 		if (referer) {
 			if (sipdebug)
@@ -6290,7 +6222,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 	p->jointnoncodeccapability = p->noncodeccapability;
 
 	/* If there are no audio formats left to offer, punt */
-	if (!(ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_AUDIO))) {
+	if (!(ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO))) {
 		ast_log(LOG_WARNING, "No audio format found to offer. Cancelling call to %s\n", p->username);
 		res = -1;
 	} else {
@@ -6345,16 +6277,15 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
 
 /*! \brief Destroy registry object
 	Objects created with the register= statement in static configuration */
-static void sip_registry_destroy(void *obj)
+static void sip_registry_destroy(struct sip_registry *reg)
 {
-	struct sip_registry *reg = obj;
 	/* Really delete */
 	ast_debug(3, "Destroying registry entry for %s@%s\n", reg->username, reg->hostname);
 
 	if (reg->call) {
 		/* Clear registry before destroying to ensure
 		   we don't get reentered trying to grab the registry lock */
-		ao2_t_replace(reg->call->registry, NULL, "destroy reg->call->registry");
+		reg->call->registry = registry_unref(reg->call->registry, "destroy reg->call->registry");
 		ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
 		dialog_unlink_all(reg->call);
 		reg->call = dialog_unref(reg->call, "unref reg->call");
@@ -6364,12 +6295,13 @@ static void sip_registry_destroy(void *obj)
 	AST_SCHED_DEL(sched, reg->timeout);
 
 	ast_string_field_free_memory(reg);
+	ast_atomic_fetchadd_int(&regobjs, -1);
+	ast_free(reg);
 }
 
 /*! \brief Destroy MWI subscription object */
-static void sip_subscribe_mwi_destroy(void *data)
+static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi)
 {
-	struct sip_subscription_mwi *mwi = data;
 	if (mwi->call) {
 		mwi->call->mwi = NULL;
 		mwi->call = dialog_unref(mwi->call, "sip_subscription_mwi destruction");
@@ -6377,6 +6309,7 @@ static void sip_subscribe_mwi_destroy(void *data)
 
 	AST_SCHED_DEL(sched, mwi->resub);
 	ast_string_field_free_memory(mwi);
+	ast_free(mwi);
 }
 
 /*! \brief Destroy SDP media offer list */
@@ -6429,16 +6362,16 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 		p->relatedpeer->mwipvt = dialog_unref(p->relatedpeer->mwipvt, "delete ->relatedpeer->mwipvt");
 	if (p->relatedpeer && p->relatedpeer->call == p)
 		p->relatedpeer->call = dialog_unref(p->relatedpeer->call, "unset the relatedpeer->call field in tandem with relatedpeer field itself");
-
+	
 	if (p->relatedpeer)
 		p->relatedpeer = sip_unref_peer(p->relatedpeer,"unsetting a dialog relatedpeer field in sip_destroy");
-
+	
 	if (p->registry) {
 		if (p->registry->call == p)
 			p->registry->call = dialog_unref(p->registry->call, "nulling out the registry's call dialog field in unlink_all");
-		ao2_t_replace(p->registry, NULL, "delete p->registry");
+		p->registry = registry_unref(p->registry, "delete p->registry");
 	}
-
+	
 	if (p->mwi) {
 		p->mwi->call = NULL;
 		p->mwi = NULL;
@@ -6482,7 +6415,10 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 		p->udptl = NULL;
 	}
 	sip_refer_destroy(p);
-	sip_route_clear(&p->route);
+	if (p->route) {
+		free_old_route(p->route);
+		p->route = NULL;
+	}
 	deinit_req(&p->initreq);
 
 	/* Clear history */
@@ -6510,17 +6446,17 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 	destroy_msg_headers(p);
 
 	if (p->srtp) {
-		ast_sdp_srtp_destroy(p->srtp);
+		sip_srtp_destroy(p->srtp);
 		p->srtp = NULL;
 	}
 
 	if (p->vsrtp) {
-		ast_sdp_srtp_destroy(p->vsrtp);
+		sip_srtp_destroy(p->vsrtp);
 		p->vsrtp = NULL;
 	}
 
 	if (p->tsrtp) {
-		ast_sdp_srtp_destroy(p->tsrtp);
+		sip_srtp_destroy(p->tsrtp);
 		p->tsrtp = NULL;
 	}
 
@@ -6554,11 +6490,11 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 	p->named_callgroups = ast_unref_namedgroups(p->named_callgroups);
 	p->named_pickupgroups = ast_unref_namedgroups(p->named_pickupgroups);
 
-	ao2_cleanup(p->caps);
-	ao2_cleanup(p->jointcaps);
-	ao2_cleanup(p->peercaps);
-	ao2_cleanup(p->redircaps);
-	ao2_cleanup(p->prefcaps);
+	p->caps = ast_format_cap_destroy(p->caps);
+	p->jointcaps = ast_format_cap_destroy(p->jointcaps);
+	p->peercaps = ast_format_cap_destroy(p->peercaps);
+	p->redircaps = ast_format_cap_destroy(p->redircaps);
+	p->prefcaps = ast_format_cap_destroy(p->prefcaps);
 
 	ast_rtp_dtls_cfg_free(&p->dtls_cfg);
 
@@ -6969,7 +6905,7 @@ static int sip_hangup(struct ast_channel *ast)
 		if (p->owner) {
 			sip_pvt_lock(p);
 			oldowner = p->owner;
-			sip_set_owner(p, NULL); /* Owner will be gone after we return, so take it away */
+			p->owner = NULL;  /* Owner will be gone after we return, so take it away */
 			sip_pvt_unlock(p);
 			ast_channel_tech_pvt_set(oldowner, dialog_unref(ast_channel_tech_pvt(oldowner), "unref oldowner->tech_pvt"));
 		}
@@ -7006,7 +6942,7 @@ static int sip_hangup(struct ast_channel *ast)
 	/* Disconnect */
 	disable_dsp_detect(p);
 
-	sip_set_owner(p, NULL);
+	p->owner = NULL;
 	ast_channel_tech_pvt_set(ast, NULL);
 
 	ast_module_unref(ast_module_info->self);
@@ -7061,29 +6997,37 @@ static int sip_hangup(struct ast_channel *ast)
 			}
 
 			if (!p->pendinginvite) {
-				char *quality;
-				char quality_buf[AST_MAX_USER_FIELD];
+				struct ast_channel *bridge = ast_bridged_channel(oldowner);
+				char quality_buf[AST_MAX_USER_FIELD], *quality;
+
+				/* We need to get the lock on bridge because ast_rtp_instance_set_stats_vars will attempt
+				 * to lock the bridge. This may get hairy...
+				 */
+				while (bridge && ast_channel_trylock(bridge)) {
+					sip_pvt_unlock(p);
+					do {
+						CHANNEL_DEADLOCK_AVOIDANCE(oldowner);
+					} while (sip_pvt_trylock(p));
+					bridge = ast_bridged_channel(oldowner);
+				}
 
 				if (p->rtp) {
-					struct ast_rtp_instance *p_rtp;
+					ast_rtp_instance_set_stats_vars(oldowner, p->rtp);
+				}
 
-					p_rtp = p->rtp;
-					ao2_ref(p_rtp, +1);
-					ast_channel_unlock(oldowner);
-					sip_pvt_unlock(p);
-					ast_rtp_instance_set_stats_vars(oldowner, p_rtp);
-					ao2_ref(p_rtp, -1);
-					ast_channel_lock(oldowner);
-					sip_pvt_lock(p);
+				if (bridge) {
+					struct sip_pvt *q = ast_channel_tech_pvt(bridge);
+
+					if (IS_SIP_TECH(ast_channel_tech(bridge)) && q && q->rtp) {
+						ast_rtp_instance_set_stats_vars(bridge, q->rtp);
+					}
+					ast_channel_unlock(bridge);
 				}
 
 				/*
 				 * The channel variables are set below just to get the AMI
 				 * VarSet event because the channel is being hungup.
 				 */
-				if (p->rtp || p->vrtp || p->trtp) {
-					ast_channel_stage_snapshot(oldowner);
-				}
 				if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
 					if (p->do_history) {
 						append_history(p, "RTCPaudio", "Quality:%s", quality);
@@ -7102,20 +7046,17 @@ static int sip_hangup(struct ast_channel *ast)
 					}
 					pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", quality);
 				}
-				if (p->rtp || p->vrtp || p->trtp) {
-					ast_channel_stage_snapshot_done(oldowner);
-				}
 
 				/* Send a hangup */
-				if (ast_channel_state(oldowner) == AST_STATE_UP) {
+				if (ast_channel_state(oldowner) == AST_STATE_UP || p->invitereplaces) {
 					transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 				}
 
 			} else {
 				/* Note we will need a BYE when this all settles out
 				   but we can't send one while we have "INVITE" outstanding. */
-				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
-				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
+				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
+				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
 				AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr"));
 				if (sip_cancel_destroy(p)) {
 					ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
@@ -7138,69 +7079,35 @@ static int sip_hangup(struct ast_channel *ast)
 	return 0;
 }
 
-/*! \brief Try setting the codecs suggested by the SIP_CODEC channel variable */
+/*! \brief Try setting codec suggested by the SIP_CODEC channel variable */
 static void try_suggested_sip_codec(struct sip_pvt *p)
 {
-	const char *codec_list;
-	char *codec_list_copy;
-	struct ast_format_cap *original_jointcaps;
-	char *codec;
-	int first_codec = 1;
+	struct ast_format fmt;
+	const char *codec;
 
-	char *strtok_ptr;
+	ast_format_clear(&fmt);
 
 	if (p->outgoing_call) {
-		codec_list = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_OUTBOUND");
-	} else if (!(codec_list = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_INBOUND"))) {
-		codec_list = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
-	}
-
-	if (ast_strlen_zero(codec_list)) {
-		return;
+		codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_OUTBOUND");
+	} else if (!(codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_INBOUND"))) {
+		codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
 	}
 
-	codec_list_copy = ast_strdupa(codec_list);
-
-	original_jointcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!original_jointcaps) {
+	if (!codec) 
 		return;
-	}
-	ast_format_cap_append_from_cap(original_jointcaps, p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-
-	for (codec = strtok_r(codec_list_copy, ",", &strtok_ptr); codec; codec = strtok_r(NULL, ",", &strtok_ptr)) {
-		struct ast_format *fmt;
-
-		codec = ast_strip(codec);
-
-		fmt = ast_format_cache_get(codec);
-		if (!fmt) {
-			ast_log(AST_LOG_NOTICE, "Ignoring ${SIP_CODEC*} variable because of unrecognized/not configured codec %s (check allow/disallow in sip.conf)\n", codec);
-			continue;
-		}
-		if (ast_format_cap_iscompatible_format(original_jointcaps, fmt) != AST_FORMAT_CMP_NOT_EQUAL) {
-			if (first_codec) {
-				ast_verb(4, "Set codec to '%s' for this call because of ${SIP_CODEC*} variable\n", codec);
-				ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append(p->jointcaps, fmt, 0);
-				ast_format_cap_remove_by_type(p->caps, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append(p->caps, fmt, 0);
-				first_codec = 0;
-			} else {
-				ast_verb(4, "Add codec to '%s' for this call because of ${SIP_CODEC*} variable\n", codec);
-				/* Add the format to the capabilities structure */
-				ast_format_cap_append(p->jointcaps, fmt, 0);
-				ast_format_cap_append(p->caps, fmt, 0);
-			}
-		} else {
-			ast_log(AST_LOG_NOTICE, "Ignoring ${SIP_CODEC*} variable because it is not shared by both ends: %s\n", codec);
-		}
 
-		ao2_ref(fmt, -1);
-	}
-	ao2_ref(original_jointcaps, -1);
+	ast_getformatbyname(codec, &fmt);
+	if (fmt.id) {
+		ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC} variable\n", codec);
+		if (ast_format_cap_iscompatible(p->jointcaps, &fmt)) {
+			ast_format_cap_set(p->jointcaps, &fmt);
+			ast_format_cap_set(p->caps, &fmt);
+		} else
+			ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
+	} else
+		ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
 	return;
- }
-
+}
 
 /*! \brief  sip_answer: Answer SIP call , send 200 OK on Invite
  * Part of PBX interface */
@@ -7246,13 +7153,13 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 
 	switch (frame->frametype) {
 	case AST_FRAME_VOICE:
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+			char s1[512];
 			ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s read/write = %s/%s\n",
-				ast_format_get_name(frame->subclass.format),
-				ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
-				ast_format_get_name(ast_channel_readformat(ast)),
-				ast_format_get_name(ast_channel_writeformat(ast)));
+				ast_getformatname(&frame->subclass.format),
+				ast_getformatname_multiple(s1, sizeof(s1), ast_channel_nativeformats(ast)),
+				ast_getformatname(ast_channel_readformat(ast)),
+				ast_getformatname(ast_channel_writeformat(ast)));
 			return 0;
 		}
 		if (p) {
@@ -7273,11 +7180,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 						ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 					}
 				}
-				if (p->invitestate > INV_EARLY_MEDIA || (p->invitestate == INV_EARLY_MEDIA &&
-									 ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT))) {
-					p->lastrtptx = time(NULL);
-					res = ast_rtp_instance_write(p->rtp, frame);
-				}
+				p->lastrtptx = time(NULL);
+				res = ast_rtp_instance_write(p->rtp, frame);
 			}
 			sip_pvt_unlock(p);
 		}
@@ -7294,11 +7198,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 					transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
 					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 				}
-				if (p->invitestate > INV_EARLY_MEDIA || (p->invitestate == INV_EARLY_MEDIA &&
-									 ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT))) {
-					p->lastrtptx = time(NULL);
-					res = ast_rtp_instance_write(p->vrtp, frame);
-				}
+				p->lastrtptx = time(NULL);
+				res = ast_rtp_instance_write(p->vrtp, frame);
 			}
 			sip_pvt_unlock(p);
 		}
@@ -7318,11 +7219,8 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 						transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
 						ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 					}
-					if (p->invitestate > INV_EARLY_MEDIA || (p->invitestate == INV_EARLY_MEDIA &&
-										 ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT))) {
-						p->lastrtptx = time(NULL);
-						res = ast_rtp_instance_write(p->trtp, frame);
-					}
+					p->lastrtptx = time(NULL);
+					res = ast_rtp_instance_write(p->trtp, frame);
 				}
 			}
 			sip_pvt_unlock(p);
@@ -7381,14 +7279,14 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 	if (p->owner != oldchan)
 		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
 	else {
-		sip_set_owner(p, newchan);
+		p->owner = newchan;
 		/* Re-invite RTP back to Asterisk. Needed if channel is masqueraded out of a native
 		   RTP bridge (i.e., RTP not going through Asterisk): RTP bridge code might not be
 		   able to do this if the masquerade happens before the bridge breaks (e.g., AMI
 		   redirect of both channels). Note that a channel can not be masqueraded *into*
 		   a native bridge. So there is no danger that this breaks a native bridge that
 		   should stay up. */
-		sip_set_rtp_peer(newchan, NULL, NULL, 0, 0, 0);
+		sip_set_rtp_peer(newchan, NULL, NULL, NULL, NULL, 0);
 		ret = 0;
 	}
 	ast_debug(3, "SIP Fixup: New owner for dialogue %s: %s (Old parent: %s)\n", p->callid, ast_channel_name(p->owner), ast_channel_name(oldchan));
@@ -7566,10 +7464,7 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_
 	return res;
 }
 
-/*!
- * \internal
- * \brief Create and initialize UDPTL for the specified dialog
- *
+/*! \internal \brief Create and initialize UDPTL for the specified dialog
  * \param p SIP private structure to create UDPTL object for
  * \pre p is locked
  * \pre p->owner is locked
@@ -7681,7 +7576,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 		if (ast_channel_state(ast) == AST_STATE_RING) {
 			p->invitestate = INV_EARLY_MEDIA;
 			if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
-			    (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {
+			    (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {				
 				/* Send 180 ringing if out-of-band seems reasonable */
 				transmit_provisional_response(p, "180 Ringing", &p->initreq, 0);
 				ast_set_flag(&p->flags[0], SIP_RINGING);
@@ -7750,14 +7645,8 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
 		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 			p->invitestate = INV_EARLY_MEDIA;
-			/* SIP_PROG_INBAND_NEVER means sending 180 ringing in place of a 183 */
-			if (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_NEVER) {
-				transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
-				ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
-			} else if (ast_channel_state(ast) == AST_STATE_RING && !ast_test_flag(&p->flags[0], SIP_RINGING)) {
-				transmit_provisional_response(p, "180 Ringing", &p->initreq, 0);
-				ast_set_flag(&p->flags[0], SIP_RINGING);
-			}
+			transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
+			ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 			break;
 		}
 		res = -1;
@@ -7772,22 +7661,10 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 		break;
 	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
 		if (p->vrtp && !p->novideo) {
-			/* FIXME: Only use this for VP8. Additional work would have to be done to
-			 * fully support other video codecs */
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) {
-				/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
-				 * RTP engine would provide a way to externally write/schedule RTCP
-				 * packets */
-				struct ast_frame fr;
-				fr.frametype = AST_FRAME_CONTROL;
-				fr.subclass.integer = AST_CONTROL_VIDUPDATE;
-				res = ast_rtp_instance_write(p->vrtp, &fr);
-			} else {
-				transmit_info_with_vidupdate(p);
-			}
-		} else {
+			transmit_info_with_vidupdate(p);
+			/* ast_rtcp_send_h261fur(p->vrtp); */
+		} else
 			res = -1;
-		}
 		break;
 	case AST_CONTROL_T38_PARAMETERS:
 		res = -1;
@@ -7853,7 +7730,6 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 		res = -1;
 		break;
 	case AST_CONTROL_PVT_CAUSE_CODE: /* these should be handled by the code in channel.c */
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 	case -1:
 		res = -1;
 		break;
@@ -7877,55 +7753,42 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
  *
  * \return New ast_channel locked.
  */
-static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid)
+static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const char *linkedid, struct ast_callid *callid)
 {
-	struct ast_format_cap *caps;
 	struct ast_channel *tmp;
 	struct ast_variable *v = NULL;
-	struct ast_format *fmt;
+	struct ast_format fmt;
 	struct ast_format_cap *what = NULL; /* SHALLOW COPY DO NOT DESTROY! */
-	struct ast_str *codec_buf = ast_str_alloca(64);
 	int needvideo = 0;
 	int needtext = 0;
+	char buf[SIPBUFSIZE];
 	char *exten;
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return NULL;
-	}
-
 	{
 		const char *my_name;	/* pick a good name */
-
+	
 		if (title) {
 			my_name = title;
 		} else {
 			my_name = ast_strdupa(i->fromdomain);
 		}
 
-		/* Don't hold a sip pvt lock while we allocate a channel */
 		sip_pvt_unlock(i);
-
-		if (i->relatedpeer && i->relatedpeer->endpoint) {
-			tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, i->relatedpeer->endpoint, "SIP/%s-%08x", my_name, (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
-		} else {
-			tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "SIP/%s-%08x", my_name, (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
-		}
+		/* Don't hold a sip pvt lock while we allocate a channel */
+		tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "SIP/%s-%08x", my_name, (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
 	}
 	if (!tmp) {
 		ast_log(LOG_WARNING, "Unable to allocate AST channel structure for SIP channel\n");
-		ao2_ref(caps, -1);
 		sip_pvt_lock(i);
 		return NULL;
 	}
 
-	ast_channel_stage_snapshot(tmp);
-
 	/* If we sent in a callid, bind it to the channel. */
 	if (callid) {
 		ast_channel_callid_set(tmp, callid);
 	}
 
+	ast_channel_lock(tmp);
 	sip_pvt_lock(i);
 	ast_channel_cc_params_init(tmp, i->cc_params);
 	ast_channel_caller(tmp)->id.tag = ast_strdup(i->cid_tag);
@@ -7934,40 +7797,27 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 
 	/* Select our native format based on codec preference until we receive
 	   something from another device to the contrary. */
-	if (ast_format_cap_count(i->jointcaps)) {	/* The joint capabilities of us and peer */
+	if (!(ast_format_cap_is_empty(i->jointcaps))) {	/* The joint capabilities of us and peer */
 		what = i->jointcaps;
-	} else if (ast_format_cap_count(i->caps)) {		/* Our configured capability for this peer */
+	} else if (!(ast_format_cap_is_empty(i->caps))) {		/* Our configured capability for this peer */
 		what = i->caps;
 	} else {
 		what = sip_cfg.caps;
 	}
 
 	/* Set the native formats */
-	ast_format_cap_append_from_cap(caps, what, AST_MEDIA_TYPE_UNKNOWN);
-	/* Use only the preferred audio format, which is stored at the '0' index */
-	fmt = ast_format_cap_get_best_by_type(what, AST_MEDIA_TYPE_AUDIO); /* get the best audio format */
-	if (fmt) {
-		ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); /* remove only the other audio formats */
-		ast_format_cap_append(caps, fmt, 0); /* add our best choice back */
-	} else {
-		/* If we don't have an audio format, try to get something */
-		fmt = ast_format_cap_get_format(caps, 0);
-		if (!fmt) {
-			ast_log(LOG_WARNING, "No compatible formats could be found for %s\n", ast_channel_name(tmp));
-			ao2_ref(caps, -1);
-			tmp = ast_channel_unref(tmp);
-			return NULL;
-		}
-	}
-	ast_channel_nativeformats_set(tmp, caps);
-	ao2_ref(caps, -1);
+	ast_format_cap_copy(ast_channel_nativeformats(tmp), what);
+	/* choose and use only the best audio format for our native formats */
+	ast_codec_choose(&i->prefs, ast_channel_nativeformats(tmp), 1, &fmt); /* get the best audio format */
+	ast_format_cap_remove_bytype(ast_channel_nativeformats(tmp), AST_FORMAT_TYPE_AUDIO); /* remove only the other audio formats */
+	ast_format_cap_add(ast_channel_nativeformats(tmp), &fmt); /* add our best choice back */
 
-	ast_debug(3, "*** Our native formats are %s \n", ast_format_cap_get_names(ast_channel_nativeformats(tmp), &codec_buf));
-	ast_debug(3, "*** Joint capabilities are %s \n", ast_format_cap_get_names(i->jointcaps, &codec_buf));
-	ast_debug(3, "*** Our capabilities are %s \n", ast_format_cap_get_names(i->caps, &codec_buf));
-	ast_debug(3, "*** AST_CODEC_CHOOSE formats are %s \n", ast_format_get_name(fmt));
-	if (ast_format_cap_count(i->prefcaps)) {
-		ast_debug(3, "*** Our preferred formats from the incoming channel are %s \n", ast_format_cap_get_names(i->prefcaps, &codec_buf));
+	ast_debug(3, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, ast_channel_nativeformats(tmp)));
+	ast_debug(3, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->jointcaps));
+	ast_debug(3, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->caps));
+	ast_debug(3, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname(&fmt));
+	if (!ast_format_cap_is_empty(i->prefcaps)) {
+		ast_debug(3, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->prefcaps));
 	}
 
 	/* If we have a prefcodec setting, we have an inbound channel that set a
@@ -7977,17 +7827,17 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	if (i->vrtp) {
 		if (ast_test_flag(&i->flags[1], SIP_PAGE2_VIDEOSUPPORT))
 			needvideo = 1;
-		else if (ast_format_cap_count(i->prefcaps))
-			needvideo = ast_format_cap_has_type(i->prefcaps, AST_MEDIA_TYPE_VIDEO);	/* Outbound call */
+		else if (!ast_format_cap_is_empty(i->prefcaps))
+			needvideo = ast_format_cap_has_type(i->prefcaps, AST_FORMAT_TYPE_VIDEO);	/* Outbound call */
 		else
-			needvideo = ast_format_cap_has_type(i->jointcaps, AST_MEDIA_TYPE_VIDEO);	/* Inbound call */
+			needvideo = ast_format_cap_has_type(i->jointcaps, AST_FORMAT_TYPE_VIDEO);	/* Inbound call */
 	}
 
 	if (i->trtp) {
-		if (ast_format_cap_count(i->prefcaps))
-			needtext = ast_format_cap_has_type(i->prefcaps, AST_MEDIA_TYPE_TEXT);	/* Outbound call */
+		if (!ast_format_cap_is_empty(i->prefcaps))
+			needtext = ast_format_cap_has_type(i->prefcaps, AST_FORMAT_TYPE_TEXT);	/* Outbound call */
 		else
-			needtext = ast_format_cap_has_type(i->jointcaps, AST_MEDIA_TYPE_TEXT);	/* Inbound call */
+			needtext = ast_format_cap_has_type(i->jointcaps, AST_FORMAT_TYPE_TEXT);	/* Inbound call */
 	}
 
 	if (needvideo) {
@@ -8015,8 +7865,8 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	if (i->rtp) {
 		ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
 		ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
-		ast_rtp_instance_set_write_format(i->rtp, fmt);
-		ast_rtp_instance_set_read_format(i->rtp, fmt);
+		ast_rtp_instance_set_write_format(i->rtp, &fmt);
+		ast_rtp_instance_set_read_format(i->rtp, &fmt);
 	}
 	if (needvideo && i->vrtp) {
 		ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
@@ -8034,13 +7884,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	}
 	ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
 
-	ast_channel_set_writeformat(tmp, fmt);
-	ast_channel_set_rawwriteformat(tmp, fmt);
-
-	ast_channel_set_readformat(tmp, fmt);
-	ast_channel_set_rawreadformat(tmp, fmt);
+	ast_format_copy(ast_channel_writeformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
 
-	ao2_ref(fmt, -1);
+	ast_format_copy(ast_channel_readformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
 
 	ast_channel_tech_pvt_set(tmp, dialog_ref(i, "sip_new: set chan->tech_pvt to i"));
 
@@ -8068,10 +7916,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 		struct ast_tone_zone *zone;
 		if (!(zone = ast_get_indication_zone(i->zone))) {
 			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", i->zone);
-		}
+		} 
 		ast_channel_zone_set(tmp, zone);
 	}
-	sip_set_owner(i, tmp);
+	i->owner = tmp;
 	ast_module_ref(ast_module_info->self);
 	ast_channel_context_set(tmp, i->context);
 	/*Since it is valid to have extensions in the dialplan that have unescaped characters in them
@@ -8110,9 +7958,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	if (!ast_strlen_zero(i->domain)) {
 		pbx_builtin_setvar_helper(tmp, "SIPDOMAIN", i->domain);
 	}
-	if (!ast_strlen_zero(i->tel_phone_context)) {
-		pbx_builtin_setvar_helper(tmp, "SIPURIPHONECONTEXT", i->tel_phone_context);
-	}
 	if (!ast_strlen_zero(i->callid)) {
 		pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
 	}
@@ -8133,7 +7978,12 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 		append_history(i, "NewChan", "Channel %s - from %s", ast_channel_name(tmp), i->callid);
 	}
 
-	ast_channel_stage_snapshot_done(tmp);
+	/* Inform manager user about new channel and their SIP call ID */
+	if (sip_cfg.callevents) {
+		manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+			"Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n",
+			ast_channel_name(tmp), ast_channel_uniqueid(tmp), "SIP", i->callid, i->fullcontact);
+	}
 
 	return tmp;
 }
@@ -8335,7 +8185,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 {
 	/* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
 	struct ast_frame *f;
-
+	
 	if (!p->rtp) {
 		/* We have no RTP allocated for this channel */
 		return &ast_null_frame;
@@ -8369,7 +8219,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 				}
 				ast_str_append(&out, 0, " -> ");
 				for (i = 0; i < f->datalen; i++) {
-					ast_str_append(&out, 0, "%02X ", (unsigned)arr[i]);
+					ast_str_append(&out, 0, "%02hhX ", arr[i]);
 				}
 				ast_verb(0, "%s\n", ast_str_buffer(out));
 				ast_free(out);
@@ -8395,26 +8245,17 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 		return f;
 	}
 
-	if (f && ast_format_cap_iscompatible_format(ast_channel_nativeformats(p->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_format_cap *caps;
-
-		if (ast_format_cap_iscompatible_format(p->jointcaps, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+	if (f && !ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) {
+		if (!ast_format_cap_iscompatible(p->jointcaps, &f->subclass.format)) {
 			ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
-				ast_format_get_name(f->subclass.format), ast_channel_name(p->owner));
+				ast_getformatname(&f->subclass.format), ast_channel_name(p->owner));
 			ast_frfree(f);
 			return &ast_null_frame;
 		}
 		ast_debug(1, "Oooh, format changed to %s\n",
-			ast_format_get_name(f->subclass.format));
-
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (caps) {
-			ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(p->owner), AST_MEDIA_TYPE_UNKNOWN);
-			ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO);
-			ast_format_cap_append(caps, f->subclass.format, 0);
-			ast_channel_nativeformats_set(p->owner, caps);
-			ao2_ref(caps, -1);
-		}
+			ast_getformatname(&f->subclass.format));
+		ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
+		ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
 		ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
 		ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
 	}
@@ -8510,7 +8351,7 @@ static char *generate_random_string(char *buf, size_t size)
 static char *generate_uri(struct sip_pvt *pvt, char *buf, size_t size)
 {
 	struct ast_str *uri = ast_str_alloca(size);
-	ast_str_set(&uri, 0, "%s", pvt->socket.type == AST_TRANSPORT_TLS ? "sips:" : "sip:");
+	ast_str_set(&uri, 0, "%s", pvt->socket.type == SIP_TRANSPORT_TLS ? "sips:" : "sip:");
 	/* Here would be a great place to generate a UUID, but for now we'll
 	 * use the handy random string generation function we already have
 	 */
@@ -8666,18 +8507,18 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 		sip_pvt_callid_set(p, logger_callid);
 	}
 
-	p->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	p->jointcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	p->peercaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	p->redircaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	p->prefcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	p->caps = ast_format_cap_alloc_nolock();
+	p->jointcaps = ast_format_cap_alloc_nolock();
+	p->peercaps = ast_format_cap_alloc_nolock();
+	p->redircaps = ast_format_cap_alloc_nolock();
+	p->prefcaps = ast_format_cap_alloc_nolock();
 
-	if (!p->caps|| !p->jointcaps || !p->peercaps || !p->redircaps || !p->prefcaps) {
-		ao2_cleanup(p->caps);
-		ao2_cleanup(p->jointcaps);
-		ao2_cleanup(p->peercaps);
-		ao2_cleanup(p->redircaps);
-		ao2_cleanup(p->prefcaps);
+	if (!p->caps|| !p->jointcaps || !p->peercaps || !p->redircaps) {
+		p->caps = ast_format_cap_destroy(p->caps);
+		p->jointcaps = ast_format_cap_destroy(p->jointcaps);
+		p->peercaps = ast_format_cap_destroy(p->peercaps);
+		p->redircaps = ast_format_cap_destroy(p->redircaps);
+		p->prefcaps = ast_format_cap_destroy(p->prefcaps);
 		ao2_t_ref(p, -1, "Yuck, couldn't allocate format capabilities. Get rid o' p");
 		return NULL;
 	}
@@ -8710,7 +8551,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 		/* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
 		set_socket_transport(&p->socket, req->socket.type);
 	} else {
-		set_socket_transport(&p->socket, AST_TRANSPORT_UDP);
+		set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
 	}
 
 	p->socket.fd = -1;
@@ -8727,6 +8568,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 	p->sessionversion_remote = -1;
 	p->session_modify = TRUE;
 	p->stimer = NULL;
+	p->prefs = default_prefs;		/* Set default codecs for this call */
 	ast_copy_string(p->zone, default_zone, sizeof(p->zone));
 	p->maxforwards = sip_cfg.default_max_forwards;
 
@@ -8749,10 +8591,11 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 
 	p->do_history = recordhistory;
 
-	p->branch = ast_random();
+	p->branch = ast_random();	
 	make_our_tag(p);
 	p->ocseq = INITIAL_CSEQ;
 	p->allowed_methods = UINT_MAX;
+	p->invitereplaces = 0;
 
 	if (sip_methods[intended_method].need_rtp) {
 		p->maxcallbitrate = default_maxcallbitrate;
@@ -8778,7 +8621,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 	/* Assign default music on hold class */
 	ast_string_field_set(p, mohinterpret, default_mohinterpret);
 	ast_string_field_set(p, mohsuggest, default_mohsuggest);
-	ast_format_cap_append_from_cap(p->caps, sip_cfg.caps, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(p->caps, sip_cfg.caps);
 	p->allowtransfer = sip_cfg.allowtransfer;
 	if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
 	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
@@ -8808,7 +8651,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
  * This function will update the destination of the response according to the
  * Via header in the request and RFC 3261 section 18.2.2. We do not have a
  * transport layer so we ignore certain values like the 'received' param (we
- * set the destination address to the addres the request came from in the
+ * set the destination address to the address the request came from in the
  * respprep() function).
  *
  * \retval -1 error
@@ -8949,14 +8792,14 @@ static enum match_req_res match_req_to_dialog(struct sip_pvt *sip_pvt_ptr, struc
 
 	/*
 	 * Compare incoming request against initial transaction.
-	 *
+	 * 
 	 * This is a best effort attempt at distinguishing forked requests from
 	 * our initial transaction.  If all the elements are NOT in place to evaluate
 	 * this, this block is ignored and the dialog match is made regardless.
 	 * Once the totag is established after the dialog is confirmed, this is not necessary.
 	 *
 	 * CRITERIA required for initial transaction matching.
-	 *
+	 * 
 	 * 1. Is a Request
 	 * 2. Callid and theirtag match (this is done in the dialog matching block)
 	 * 3. totag is NOT present
@@ -9152,21 +8995,6 @@ static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt)
 	return pvt->owner;
 }
 
-/*! \brief Set the owning channel on the \ref sip_pvt object */
-static void sip_set_owner(struct sip_pvt *p, struct ast_channel *chan)
-{
-	p->owner = chan;
-	if (p->rtp) {
-		ast_rtp_instance_set_channel_id(p->rtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
-	}
-	if (p->vrtp) {
-		ast_rtp_instance_set_channel_id(p->vrtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
-	}
-	if (p->trtp) {
-		ast_rtp_instance_set_channel_id(p->trtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
-	}
-}
-
 /*! \brief find or create a dialog structure for an incoming SIP message.
  * Connect incoming SIP message to current dialog or create new dialog structure
  * Returns a reference to the sip_pvt object, remember to give it back once done.
@@ -9224,7 +9052,8 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
 		}
 	}
 
-	if (!sip_cfg.pedanticsipchecking) {
+	/* match on callid only for REGISTERs */
+	if (!sip_cfg.pedanticsipchecking || req->method == SIP_REGISTER) {
 		struct sip_pvt tmp_dialog = {
 			.callid = callid,
 		};
@@ -9283,6 +9112,15 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
 
 			switch (found) {
 			case SIP_REQ_MATCH:
+				sip_pvt_lock(sip_pvt_ptr);
+				if (args.method != SIP_RESPONSE && args.authentication_present
+						&& strcmp(args.fromtag, sip_pvt_ptr->theirtag)) {
+					/* If we have a request that uses athentication and the fromtag is
+					 * different from that in the original call dialog, update the
+					 * fromtag in the saved call dialog */
+					ast_string_field_set(sip_pvt_ptr, theirtag, args.fromtag);
+				}
+				sip_pvt_unlock(sip_pvt_ptr);
 				ao2_iterator_destroy(iterator);
 				dialog_unref(fork_pvt, "unref fork_pvt");
 				free_via(via);
@@ -9373,27 +9211,18 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
 /*! \brief create sip_registry object from register=> line in sip.conf and link into reg container */
 static int sip_register(const char *value, int lineno)
 {
-	struct sip_registry *reg;
-
-	reg = ao2_t_find(registry_list, value, OBJ_SEARCH_KEY, "check for existing registry");
-	if (reg) {
-		ao2_t_ref(reg, -1, "throw away found registry");
-		return 0;
-	}
+	struct sip_registry *reg, *tmp;
 
-	if (!(reg = ao2_t_alloc(sizeof(*reg), sip_registry_destroy, "allocate a registry struct"))) {
+	if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
 		ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
 		return -1;
 	}
 
-	if (ast_string_field_init(reg, 256)) {
-		ao2_t_ref(reg, -1, "failed to string_field_init, drop reg");
-		return -1;
-	}
+	ASTOBJ_INIT(reg);
 
-	ast_string_field_set(reg, configvalue, value);
+	ast_copy_string(reg->name, value, sizeof(reg->name));
 	if (sip_parse_register_line(reg, default_expiry, value, lineno)) {
-		ao2_t_ref(reg, -1, "failure to parse, unref the reg pointer");
+		registry_unref(reg, "failure to parse, unref the reg pointer");
 		return -1;
 	}
 
@@ -9402,8 +9231,16 @@ static int sip_register(const char *value, int lineno)
 		reg->refresh = reg->expiry = reg->configured_expiry = default_expiry;
 	}
 
-	ao2_t_link(registry_list, reg, "link reg to registry_list");
-	ao2_t_ref(reg, -1, "unref the reg pointer");
+	/* Add the new registry entry to the list, but only if it isn't already there */
+	if ((tmp = ASTOBJ_CONTAINER_FIND(&regl, reg->name))) {
+		registry_unref(tmp, "throw away found registry");
+	} else {
+		ast_atomic_fetchadd_int(&regobjs, 1);
+		ASTOBJ_CONTAINER_LINK(&regl, reg);
+	}
+
+	/* release the reference given by ASTOBJ_INIT. The container has another reference */
+	registry_unref(reg, "unref the reg pointer");
 
 	return 0;
 }
@@ -9413,7 +9250,7 @@ static int sip_subscribe_mwi(const char *value, int lineno)
 {
 	struct sip_subscription_mwi *mwi;
 	int portnum = 0;
-	enum ast_transport transport = AST_TRANSPORT_UDP;
+	enum sip_transport transport = SIP_TRANSPORT_UDP;
 	char buf[256] = "";
 	char *username = NULL, *hostname = NULL, *secret = NULL, *authuser = NULL, *porta = NULL, *mailbox = NULL;
 
@@ -9455,15 +9292,11 @@ static int sip_subscribe_mwi(const char *value, int lineno)
 		}
 	}
 
-	if (!(mwi = ao2_t_alloc(sizeof(*mwi), sip_subscribe_mwi_destroy, "allocate an mwi struct"))) {
-		return -1;
-	}
-
-	if (ast_string_field_init(mwi, 256)) {
-		ao2_t_ref(mwi, -1, "failed to string_field_init, drop mwi");
+	if (!(mwi = ast_calloc_with_stringfields(1, struct sip_subscription_mwi, 256))) {
 		return -1;
 	}
 
+	ASTOBJ_INIT(mwi);
 	ast_string_field_set(mwi, username, username);
 	if (secret) {
 		ast_string_field_set(mwi, secret, secret);
@@ -9477,8 +9310,8 @@ static int sip_subscribe_mwi(const char *value, int lineno)
 	mwi->portno = portnum;
 	mwi->transport = transport;
 
-	ao2_t_link(subscription_mwi_list, mwi, "link new mwi object");
-	ao2_t_ref(mwi, -1, "unref to match ao2_t_alloc");
+	ASTOBJ_CONTAINER_LINK(&submwil, mwi);
+	ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy);
 
 	return 0;
 }
@@ -9571,7 +9404,7 @@ static unsigned int parse_allowed_methods(struct sip_request *req)
 static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req)
 {
 	pvt->allowed_methods = parse_allowed_methods(req);
-
+	
 	if (ast_test_flag(&pvt->flags[1], SIP_PAGE2_RPID_UPDATE)) {
 		mark_method_allowed(&pvt->allowed_methods, SIP_UPDATE);
 	}
@@ -9635,7 +9468,8 @@ static int parse_request(struct sip_request *req)
 {
 	char *c = ast_str_buffer(req->data);
 	ptrdiff_t *dst = req->header;
-	int i = 0, lim = SIP_MAX_HEADERS - 1;
+	int i = 0;
+	unsigned int lim = SIP_MAX_HEADERS - 1;
 	unsigned int skipping_headers = 0;
 	ptrdiff_t current_header_offset = 0;
 	char *previous_header = "";
@@ -9807,7 +9641,7 @@ static int find_sdp(struct sip_request *req)
 		}
 		if (!strcasecmp(line, "Content-Type: application/sdp"))
 			found_application_sdp = TRUE;
-
+		
 		if (ast_strlen_zero(line)) {
 			if (found_application_sdp && !found_end_of_headers){
 				req->sdp_start = x;
@@ -9825,9 +9659,16 @@ static int find_sdp(struct sip_request *req)
 /*! \brief Change hold state for a call */
 static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, int holdstate, int sendonly)
 {
-	if (sip_cfg.notifyhold && (!holdstate || !ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD))) {
+	if (sip_cfg.notifyhold && (!holdstate || !ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD)))
 		sip_peer_hold(dialog, holdstate);
-	}
+	if (sip_cfg.callevents)
+		manager_event(EVENT_FLAG_CALL, "Hold",
+			      "Status: %s\r\n"
+			      "Channel: %s\r\n"
+			      "Uniqueid: %s\r\n",
+			      holdstate ? "On" : "Off",
+			      ast_channel_name(dialog->owner),
+			      ast_channel_uniqueid(dialog->owner));
 	append_history(dialog, holdstate ? "Hold" : "Unhold", "%s", ast_str_buffer(req->data));
 	if (!holdstate) {	/* Put off remote hold */
 		ast_clear_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD);	/* Clear both flags */
@@ -9847,6 +9688,64 @@ static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, i
 	return;
 }
 
+
+static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct ast_sockaddr *addr)
+{
+	const char *m;
+	const char *c;
+	int miterator = req->sdp_start;
+	int citerator = req->sdp_start;
+	unsigned int x = 0;
+	unsigned int numberofports;
+	int len;
+	int af;
+	char proto[4], host[258] = ""; /*Initialize to empty so we will know if we have any input */
+
+	c = get_sdp_iterate(&citerator, req, "c");
+	if (sscanf(c, "IN %3s %256s", proto, host) != 2) {
+			ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
+			/* Continue since there may be a valid host in a c= line specific to the audio stream */
+	}
+	/* We only want the m and c lines for audio */
+	for (m = get_sdp_iterate(&miterator, req, "m"); !ast_strlen_zero(m); m = get_sdp_iterate(&miterator, req, "m")) {
+		if ((media == SDP_AUDIO && ((sscanf(m, "audio %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+		    (sscanf(m, "audio %30u RTP/AVP %n", &x, &len) == 1 && len > 0))) ||
+			(media == SDP_VIDEO && ((sscanf(m, "video %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+		    (sscanf(m, "video %30u RTP/AVP %n", &x, &len) == 1 && len > 0)))) {
+			/* See if there's a c= line for this media stream.
+			 * XXX There is no guarantee that we'll be grabbing the c= line for this
+			 * particular media stream here. However, this is the same logic used in process_sdp.
+			 */
+			c = get_sdp_iterate(&citerator, req, "c");
+			if (!ast_strlen_zero(c)) {
+				sscanf(c, "IN %3s %256s", proto, host);
+			}
+			break;
+		}
+	}
+
+	if (!strcmp("IP4", proto)) {
+		af = AF_INET;
+	} else if (!strcmp("IP6", proto)) {
+		af = AF_INET6;
+	} else {
+		ast_log(LOG_WARNING, "Unknown protocol '%s'.\n", proto);
+		return -1;
+	}
+
+	if (ast_strlen_zero(host) || x == 0) {
+		ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
+		return -1;
+	}
+
+	if (ast_sockaddr_resolve_first_af(addr, host, 0, af)) {
+		ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*! \internal
  * \brief Returns whether or not the address is null or ANY / unspecified (0.0.0.0 or ::)
  * \retval TRUE if the address is null or any
@@ -9908,17 +9807,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	int udptlportno = -1;			/*!< UDPTL image destination port number */
 
 	/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */
-	struct ast_format_cap *peercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	struct ast_format_cap *vpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	struct ast_format_cap *tpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *peercapability = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *vpeercapability = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *tpeercapability = ast_format_cap_alloc_nolock();
 
 	int peernoncodeccapability = 0, vpeernoncodeccapability = 0, tpeernoncodeccapability = 0;
 
-	struct ast_rtp_codecs newaudiortp = AST_RTP_CODECS_NULL_INIT;
-	struct ast_rtp_codecs newvideortp = AST_RTP_CODECS_NULL_INIT;
-	struct ast_rtp_codecs newtextrtp = AST_RTP_CODECS_NULL_INIT;
-	struct ast_format_cap *newjointcapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); /* Negotiated capability */
-	struct ast_format_cap *newpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_rtp_codecs newaudiortp = { 0, }, newvideortp = { 0, }, newtextrtp = { 0, };
+	struct ast_format_cap *newjointcapability = ast_format_cap_alloc_nolock(); /* Negotiated capability */
+	struct ast_format_cap *newpeercapability = ast_format_cap_alloc_nolock();
 	int newnoncodeccapability;
 
 	const char *codecs;
@@ -9938,8 +9835,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	int debug = sip_debug_test_pvt(p);
 
 	/* START UNKNOWN */
-	struct ast_str *codec_buf = ast_str_alloca(64);
-	struct ast_format *tmp_fmt;
+	char buf[SIPBUFSIZE];
+	struct ast_format tmp_fmt;
 	/* END UNKNOWN */
 
 	/* Initial check */
@@ -10021,19 +9918,19 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 			if (process_sdp_a_dtls(value, p, p->rtp)) {
 				processed = TRUE;
 				if (p->srtp) {
-					ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+					ast_set_flag(p->srtp, SRTP_CRYPTO_OFFER_OK);
 				}
 			}
 			if (process_sdp_a_dtls(value, p, p->vrtp)) {
 				processed = TRUE;
 				if (p->vsrtp) {
-					ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+					ast_set_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK);
 				}
 			}
 			if (process_sdp_a_dtls(value, p, p->trtp)) {
 				processed = TRUE;
 				if (p->tsrtp) {
-					ast_set_flag(p->tsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+					ast_set_flag(p->tsrtp, SRTP_CRYPTO_OFFER_OK);
 				}
 			}
 
@@ -10089,7 +9986,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				sprintf(offer->decline_m_line, "m=audio 0 %s %s\r\n", protocol, codecs);
 
 				if (x == 0) {
-					ast_debug(1, "Ignoring audio media offer because port number is zero\n");
+					ast_log(LOG_WARNING, "Ignoring audio media offer because port number is zero\n");
 					continue;
 				}
 
@@ -10127,9 +10024,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
 					secure_audio = 1;
 
-					processed_crypto = 1;
 					if (p->srtp) {
-						ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+						ast_set_flag(p->srtp, SRTP_CRYPTO_OFFER_OK);
 					}
 				} else if (!strcmp(protocol, "RTP/SAVP") || !strcmp(protocol, "RTP/SAVPF")) {
 					secure_audio = 1;
@@ -10199,7 +10095,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				sprintf(offer->decline_m_line, "m=video 0 %s %s\r\n", protocol, codecs);
 
 				if (x == 0) {
-					ast_debug(1, "Ignoring video stream offer because port number is zero\n");
+					ast_log(LOG_WARNING, "Ignoring video stream offer because port number is zero\n");
 					continue;
 				}
 
@@ -10222,9 +10118,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
 					secure_video = 1;
 
-					processed_crypto = 1;
-					if (p->vsrtp || (p->vsrtp = ast_sdp_srtp_alloc())) {
-						ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+					if (p->vsrtp || (p->vsrtp = sip_srtp_alloc())) {
+						ast_set_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK);
 					}
 				} else if (!strcmp(protocol, "RTP/SAVP") || !strcmp(protocol, "RTP/SAVPF")) {
 					secure_video = 1;
@@ -10278,7 +10173,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				sprintf(offer->decline_m_line, "m=text 0 %s %s\r\n", protocol, codecs);
 
 				if (x == 0) {
-					ast_debug(1, "Ignoring text stream offer because port number is zero\n");
+					ast_log(LOG_WARNING, "Ignoring text stream offer because port number is zero\n");
 					continue;
 				}
 
@@ -10341,7 +10236,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				strcpy(offer->decline_m_line, "m=image 0 udptl t38\r\n");
 
 				if (x == 0) {
-					ast_debug(1, "Ignoring image stream offer because port number is zero\n");
+					ast_log(LOG_WARNING, "Ignoring image stream offer because port number is zero\n");
 					continue;
 				}
 
@@ -10445,7 +10340,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 						processed_crypto = TRUE;
 						processed = TRUE;
 						if (p->srtp) {
-							ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+							ast_set_flag(p->srtp, SRTP_CRYPTO_OFFER_OK);
 						}
 					} else if (process_sdp_a_sendonly(value, &sendonly)) {
 						processed = TRUE;
@@ -10464,7 +10359,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 						processed_crypto = TRUE;
 						processed = TRUE;
 						if (p->vsrtp) {
-							ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+							ast_set_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK);
 						}
 					} else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
 						processed_crypto = TRUE;
@@ -10502,11 +10397,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		if (audio && secure_audio && !processed_crypto) {
 			ast_log(LOG_WARNING, "Rejecting secure audio stream without encryption details: %s\n", m);
 			res = -1;
-			goto process_sdp_cleanup;
+			goto process_sdp_cleanup_b;
 		} else if (video && secure_video && !processed_crypto) {
 			ast_log(LOG_WARNING, "Rejecting secure video stream without encryption details: %s\n", m);
 			res = -1;
-			goto process_sdp_cleanup;
+			goto process_sdp_cleanup_b;
 		}
 	}
 
@@ -10526,31 +10421,37 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		goto process_sdp_cleanup;
 	}
 
-	if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK)))) {
+	if (p->srtp && p->udptl && udptlportno != -1) {
+		ast_debug(1, "Terminating SRTP due to T.38 UDPTL\n");
+		sip_srtp_destroy(p->srtp);
+		p->srtp = NULL;
+        }
+
+	if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
 		ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
 		res = -1;
 		goto process_sdp_cleanup;
 	}
 
 	if (!secure_audio && p->srtp) {
-		ast_log(LOG_WARNING, "We are requesting SRTP for audio, but they responded without it!\n");
+		ast_log(LOG_WARNING, "Failed to receive SDP offer/answer with required SRTP crypto attributes for audio\n");
 		res = -1;
 		goto process_sdp_cleanup;
 	}
 
-	if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK)))) {
+	if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) {
 		ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n");
 		res = -1;
 		goto process_sdp_cleanup;
 	}
 
 	if (!p->novideo && !secure_video && p->vsrtp) {
-		ast_log(LOG_WARNING, "We are requesting SRTP for video, but they responded without it!\n");
+		ast_log(LOG_WARNING, "Failed to receive SDP offer/answer with required SRTP crypto attributes for video\n");
 		res = -1;
 		goto process_sdp_cleanup;
 	}
 
-	if (!(secure_audio || secure_video) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) {
+	if (!(secure_audio || secure_video || (p->udptl && udptlportno != -1)) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) {
 		ast_log(LOG_WARNING, "Matched device setup to use SRTP, but request was not!\n");
 		res = -1;
 		goto process_sdp_cleanup;
@@ -10565,12 +10466,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	ast_rtp_codecs_payload_formats(&newvideortp, vpeercapability, &vpeernoncodeccapability);
 	ast_rtp_codecs_payload_formats(&newtextrtp, tpeercapability, &tpeernoncodeccapability);
 
-	ast_format_cap_append_from_cap(newpeercapability, peercapability, AST_MEDIA_TYPE_AUDIO);
-	ast_format_cap_append_from_cap(newpeercapability, vpeercapability, AST_MEDIA_TYPE_VIDEO);
-	ast_format_cap_append_from_cap(newpeercapability, tpeercapability, AST_MEDIA_TYPE_TEXT);
+	ast_format_cap_append(newpeercapability, peercapability);
+	ast_format_cap_append(newpeercapability, vpeercapability);
+	ast_format_cap_append(newpeercapability, tpeercapability);
 
-	ast_format_cap_get_compatible(p->caps, newpeercapability, newjointcapability);
-	if (!ast_format_cap_count(newjointcapability) && udptlportno == -1) {
+	ast_format_cap_joint_copy(p->caps, newpeercapability, newjointcapability);
+	if (ast_format_cap_is_empty(newjointcapability) && udptlportno == -1) {
 		ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
 		/* Do NOT Change current setting */
 		res = -1;
@@ -10581,18 +10482,14 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 
 	if (debug) {
 		/* shame on whoever coded this.... */
-		struct ast_str *cap_buf = ast_str_alloca(64);
-		struct ast_str *peer_buf = ast_str_alloca(64);
-		struct ast_str *vpeer_buf = ast_str_alloca(64);
-		struct ast_str *tpeer_buf = ast_str_alloca(64);
-		struct ast_str *joint_buf = ast_str_alloca(64);
+		char s1[SIPBUFSIZE], s2[SIPBUFSIZE], s3[SIPBUFSIZE], s4[SIPBUFSIZE], s5[SIPBUFSIZE];
 
 		ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n",
-			    ast_format_cap_get_names(p->caps, &cap_buf),
-			    ast_format_cap_get_names(peercapability, &peer_buf),
-			    ast_format_cap_get_names(vpeercapability, &vpeer_buf),
-			    ast_format_cap_get_names(tpeercapability, &tpeer_buf),
-			    ast_format_cap_get_names(newjointcapability, &joint_buf));
+			    ast_getformatname_multiple(s1, SIPBUFSIZE, p->caps),
+			    ast_getformatname_multiple(s2, SIPBUFSIZE, peercapability),
+			    ast_getformatname_multiple(s3, SIPBUFSIZE, vpeercapability),
+			    ast_getformatname_multiple(s4, SIPBUFSIZE, tpeercapability),
+			    ast_getformatname_multiple(s5, SIPBUFSIZE, newjointcapability));
 	}
 	if (debug) {
 		struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
@@ -10608,21 +10505,14 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	if (portno != -1 || vportno != -1 || tportno != -1) {
 		/* We are now ready to change the sip session and RTP structures with the offered codecs, since
 		   they are acceptable */
-		ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(p->jointcaps, newjointcapability, AST_MEDIA_TYPE_UNKNOWN); /* Our joint codec profile for this call */
-		ast_format_cap_remove_by_type(p->peercaps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(p->peercaps, newpeercapability, AST_MEDIA_TYPE_UNKNOWN); /* The other side's capability in latest offer */
+		ast_format_cap_copy(p->jointcaps, newjointcapability);                /* Our joint codec profile for this call */
+		ast_format_cap_copy(p->peercaps, newpeercapability);                  /* The other side's capability in latest offer */
 		p->jointnoncodeccapability = newnoncodeccapability;     /* DTMF capabilities */
 
 		/* respond with single most preferred joint codec, limiting the other side's choice */
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) {
-			unsigned int framing;
-
-			tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0);
-			framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt);
-			ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-			ast_format_cap_append(p->jointcaps, tmp_fmt, framing);
-			ao2_ref(tmp_fmt, -1);
+			ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt);
+			ast_format_cap_set(p->jointcaps, &tmp_fmt);
 		}
 	}
 
@@ -10702,7 +10592,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				ast_verbose("Peer T.140 RTP is at port %s\n",
 					    ast_sockaddr_stringify(tsa));
 			}
-			if (ast_format_cap_iscompatible_format(p->jointcaps, ast_format_t140_red) != AST_FORMAT_CMP_NOT_EQUAL) {
+			if (ast_format_cap_iscompatible(p->jointcaps, ast_format_set(&tmp_fmt, AST_FORMAT_T140RED, 0))) {
 				p->red = 1;
 				ast_rtp_red_init(p->trtp, 300, red_data_pt, 2);
 			} else {
@@ -10728,7 +10618,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 			ast_sockaddr_set_port(isa, udptlportno);
 			ast_udptl_set_peer(p->udptl, isa);
 			if (debug)
-				ast_debug(1, "Peer T.38 UDPTL is at port %s\n", ast_sockaddr_stringify(isa));
+				ast_debug(1,"Peer T.38 UDPTL is at port %s\n", ast_sockaddr_stringify(isa));
 
 			/* verify the far max ifp can be calculated. this requires far max datagram to be set. */
 			if (!ast_udptl_get_far_max_datagram(p->udptl)) {
@@ -10779,7 +10669,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	}
 
 	/* Ok, we're going with this offer */
-	ast_debug(2, "We're settling with these formats: %s\n", ast_format_cap_get_names(p->jointcaps, &codec_buf));
+	ast_debug(2, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, p->jointcaps));
 
 	if (!p->owner) { /* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */
 		res = 0;
@@ -10787,46 +10677,33 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	}
 
 	ast_debug(4, "We have an owner, now see if we need to change this call\n");
-	if (ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_AUDIO)) {
-		struct ast_format_cap *caps;
-		unsigned int framing;
-
+	if (ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO)) {
 		if (debug) {
-			struct ast_str *cap_buf = ast_str_alloca(64);
-			struct ast_str *joint_buf = ast_str_alloca(64);
-
+			char s1[SIPBUFSIZE], s2[SIPBUFSIZE];
 			ast_debug(1, "Setting native formats after processing SDP. peer joint formats %s, old nativeformats %s\n",
-				ast_format_cap_get_names(p->jointcaps, &joint_buf),
-				ast_format_cap_get_names(ast_channel_nativeformats(p->owner), &cap_buf));
+				ast_getformatname_multiple(s1, SIPBUFSIZE, p->jointcaps),
+				ast_getformatname_multiple(s2, SIPBUFSIZE, ast_channel_nativeformats(p->owner)));
 		}
 
-		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (caps) {
-			tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0);
-			framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt);
-			ast_format_cap_append(caps, tmp_fmt, framing);
-			ast_format_cap_append_from_cap(caps, vpeercapability, AST_MEDIA_TYPE_VIDEO);
-			ast_format_cap_append_from_cap(caps, tpeercapability, AST_MEDIA_TYPE_TEXT);
-			ast_channel_nativeformats_set(p->owner, caps);
-			ao2_ref(caps, -1);
-			ao2_ref(tmp_fmt, -1);
-		}
+		ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt);
+
+		ast_format_cap_set(ast_channel_nativeformats(p->owner), &tmp_fmt);
+		ast_format_cap_joint_append(p->caps, vpeercapability, ast_channel_nativeformats(p->owner));
+		ast_format_cap_joint_append(p->caps, tpeercapability, ast_channel_nativeformats(p->owner));
 
 		ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
 		ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
 	}
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && (!ast_sockaddr_isnull(sa) || !ast_sockaddr_isnull(vsa) || !ast_sockaddr_isnull(tsa) || !ast_sockaddr_isnull(isa)) && (!sendonly || sendonly == -1)) {
-		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL)) {
-			ast_queue_unhold(p->owner);
-		}
+		ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 		/* Activate a re-invite */
 		ast_queue_frame(p->owner, &ast_null_frame);
 		change_hold_state(p, req, FALSE, sendonly);
 	} else if ((sockaddr_is_null_or_any(sa) && sockaddr_is_null_or_any(vsa) && sockaddr_is_null_or_any(tsa) && sockaddr_is_null_or_any(isa)) || (sendonly && sendonly != -1)) {
-		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL)) {
-			ast_queue_hold(p->owner, p->mohsuggest);
-		}
+		ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
+				       S_OR(p->mohsuggest, NULL),
+				       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 		if (sendonly)
 			ast_rtp_instance_stop(p->rtp);
 		/* RTCP needs to go ahead, even if we're on hold!!! */
@@ -10839,14 +10716,16 @@ process_sdp_cleanup:
 	if (res) {
 		offered_media_list_destroy(p);
 	}
+
+process_sdp_cleanup_b:
 	ast_rtp_codecs_payloads_destroy(&newtextrtp);
 	ast_rtp_codecs_payloads_destroy(&newvideortp);
 	ast_rtp_codecs_payloads_destroy(&newaudiortp);
-	ao2_cleanup(peercapability);
-	ao2_cleanup(vpeercapability);
-	ao2_cleanup(tpeercapability);
-	ao2_cleanup(newjointcapability);
-	ao2_cleanup(newpeercapability);
+	ast_format_cap_destroy(peercapability);
+	ast_format_cap_destroy(vpeercapability);
+	ast_format_cap_destroy(tpeercapability);
+	ast_format_cap_destroy(newjointcapability);
+	ast_format_cap_destroy(newpeercapability);
 	return res;
 }
 
@@ -11103,10 +10982,17 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
 				ast_debug(1, "Can't read framing from SDP: %s\n", a);
 			}
 		}
-
 		if (framing && p->autoframing) {
-			ast_debug(1, "Setting framing to %ld\n", framing);
-			ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), framing);
+			struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
+			int codec_n;
+			for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) {
+				struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
+				if (!format.asterisk_format)	/* non-codec or not found */
+					continue;
+				ast_debug(1, "Setting framing for %s to %ld\n", ast_getformatname(&format.format), framing);
+				ast_codec_pref_setsize(pref, &format.format, framing);
+			}
+			ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
 		}
 		found = TRUE;
 	} else if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
@@ -11133,19 +11019,15 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
 
 		if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) {
 			unsigned int bit_rate;
-			struct ast_format *format_parsed;
 
-			format_parsed = ast_format_parse_sdp_fmtp(format, fmtp_string);
-			if (format_parsed) {
-				ast_rtp_codecs_payload_replace_format(newaudiortp, codec, format_parsed);
-				ao2_replace(format, format_parsed);
-				ao2_ref(format_parsed, -1);
+			if (!ast_format_sdp_parse(format, fmtp_string)) {
 				found = TRUE;
 			} else {
 				ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
 			}
 
-			if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) {
+			switch ((int) format->id) {
+			case AST_FORMAT_SIREN7:
 				if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
 					if (bit_rate != 32000) {
 						ast_log(LOG_WARNING, "Got Siren7 offer at %u bps, but only 32000 bps supported; ignoring.\n", bit_rate);
@@ -11154,7 +11036,8 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
 						found = TRUE;
 					}
 				}
-			} else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) {
+				break;
+			case AST_FORMAT_SIREN14:
 				if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
 					if (bit_rate != 48000) {
 						ast_log(LOG_WARNING, "Got Siren14 offer at %u bps, but only 48000 bps supported; ignoring.\n", bit_rate);
@@ -11163,7 +11046,8 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
 						found = TRUE;
 					}
 				}
-			} else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) {
+				break;
+			case AST_FORMAT_G719:
 				if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
 					if (bit_rate != 64000) {
 						ast_log(LOG_WARNING, "Got G.719 offer at %u bps, but only 64000 bps supported; ignoring.\n", bit_rate);
@@ -11172,8 +11056,8 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
 						found = TRUE;
 					}
 				}
+				break;
 			}
-			ao2_ref(format, -1);
 		}
 	}
 
@@ -11193,8 +11077,7 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_
 		/* We have a rtpmap to handle */
 		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
 			/* Note: should really look at the '#chans' params too */
-			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)
-					|| !strncasecmp(mimeSubtype, "VP8", 3)) {
+			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
 				if (!(ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate))) {
 					if (debug)
 						ast_verbose("Found video description format %s for ID %u\n", mimeSubtype, codec);
@@ -11215,19 +11098,11 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_
 		struct ast_format *format;
 
 		if ((format = ast_rtp_codecs_get_payload_format(newvideortp, codec))) {
-			struct ast_format *format_parsed;
-
-			format_parsed = ast_format_parse_sdp_fmtp(format, fmtp_string);
-
-			if (format_parsed) {
-				ast_rtp_codecs_payload_replace_format(newvideortp, codec, format_parsed);
-				ao2_replace(format, format_parsed);
-				ao2_ref(format_parsed, -1);
+			if (!ast_format_sdp_parse(format, fmtp_string)) {
 				found = TRUE;
 			} else {
 				ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec);
 			}
-			ao2_ref(format, -1);
 		}
 	}
 
@@ -11337,13 +11212,13 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
 	} else if ((sscanf(attrib, "t38faxmaxdatagram:%30u", &x) == 1) || (sscanf(attrib, "t38maxdatagram:%30u", &x) == 1)) {
 		/* override the supplied value if the configuration requests it */
 		if (((signed int) p->t38_maxdatagram >= 0) && ((unsigned int) p->t38_maxdatagram > x)) {
-			ast_debug(1, "Overriding T38FaxMaxDatagram '%u' with '%d'\n", x, p->t38_maxdatagram);
+			ast_debug(1, "Overriding T38FaxMaxDatagram '%u' with '%u'\n", x, p->t38_maxdatagram);
 			x = p->t38_maxdatagram;
 		}
 		ast_debug(3, "FaxMaxDatagram: %u\n", x);
 		ast_udptl_set_far_max_datagram(p->udptl, x);
 		found = TRUE;
-	} else if ((strncmp(attrib, "t38faxfillbitremoval", sizeof("t38faxfillbitremoval") - 1) == 0)) {
+	} else if ((strncmp(attrib, "t38faxfillbitremoval", 20) == 0)) {
 		if (sscanf(attrib, "t38faxfillbitremoval:%30u", &x) == 1) {
 			ast_debug(3, "FillBitRemoval: %u\n", x);
 			if (x == 1) {
@@ -11354,7 +11229,7 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
 			p->t38.their_parms.fill_bit_removal = TRUE;
 		}
 		found = TRUE;
-	} else if ((strncmp(attrib, "t38faxtranscodingmmr", sizeof("t38faxtranscodingmmr") - 1) == 0)) {
+	} else if ((strncmp(attrib, "t38faxtranscodingmmr", 20) == 0)) {
 		if (sscanf(attrib, "t38faxtranscodingmmr:%30u", &x) == 1) {
 			ast_debug(3, "Transcoding MMR: %u\n", x);
 			if (x == 1) {
@@ -11365,7 +11240,7 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
 			p->t38.their_parms.transcoding_mmr = TRUE;
 		}
 		found = TRUE;
-	} else if ((strncmp(attrib, "t38faxtranscodingjbig", sizeof("t38faxtranscodingjbig") - 1) == 0)) {
+	} else if ((strncmp(attrib, "t38faxtranscodingjbig", 21) == 0)) {
 		if (sscanf(attrib, "t38faxtranscodingjbig:%30u", &x) == 1) {
 			ast_debug(3, "Transcoding JBIG: %u\n", x);
 			if (x == 1) {
@@ -11403,14 +11278,12 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
  *  is supported for this dialog. */
 static int add_supported(struct sip_pvt *pvt, struct sip_request *req)
 {
-	char supported_value[SIPBUFSIZE];
 	int res;
-
-	sprintf(supported_value, "replaces%s%s",
-		(st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) ? ", timer" : "",
-		ast_test_flag(&pvt->flags[0], SIP_USEPATH) ? ", path" : "");
-	res = add_header(req, "Supported", supported_value);
-
+	if (st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) {
+		res = add_header(req, "Supported", "replaces, timer");
+	} else {
+		res = add_header(req, "Supported", "replaces");
+	}
 	return res;
 }
 
@@ -11436,12 +11309,12 @@ static int add_header(struct sip_request *req, const char *var, const char *valu
 
 	req->headers++;
 
-	return 0;
+	return 0;	
 }
 
-/*!
+/*! 
  * \pre dialog is assumed to be locked while calling this function
- * \brief Add 'Max-Forwards' header to SIP message
+ * \brief Add 'Max-Forwards' header to SIP message 
  */
 static int add_max_forwards(struct sip_pvt *dialog, struct sip_request *req)
 {
@@ -11584,35 +11457,45 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
 }
 
 /*! \brief Add route header into request per learned route */
-static void add_route(struct sip_request *req, struct sip_route *route, int skip)
+static void add_route(struct sip_request *req, struct sip_route *route)
 {
-	struct ast_str *r;
+	char r[SIPBUFSIZE*2], *p;
+	int n, rem = sizeof(r);
 
-	if (sip_route_empty(route)) {
+	if (!route)
 		return;
-	}
 
-	if ((r = sip_route_list(route, 0, skip))) {
-		if (ast_str_strlen(r)) {
-			add_header(req, "Route", ast_str_buffer(r));
+	p = r;
+	for (;route ; route = route->next) {
+		n = strlen(route->hop);
+		if (rem < n+3) /* we need room for ",<route>" */
+			break;
+		if (p != r) {	/* add a separator after fist route */
+			*p++ = ',';
+			--rem;
 		}
-		ast_free(r);
+		*p++ = '<';
+		ast_copy_string(p, route->hop, rem); /* cannot fail */
+		p += n;
+		*p++ = '>';
+		rem -= (n+2);
 	}
+	*p = '\0';
+	add_header(req, "Route", r);
 }
 
 /*! \brief Set destination from SIP URI
  *
  * Parse uri to h (host) and port - uri is already just the part inside the <>
- * general form we are expecting is \verbatim sip[s]:username[:password][;parameter]@host[:port][;...] \endverbatim
+ * general form we are expecting is sip[s]:username[:password][;parameter]@host[:port][;...]
  * If there's a port given, turn NAPTR/SRV off. NAPTR might indicate SIPS preference even
  * for SIP: uri's
  *
  * If there's a sips: uri scheme, TLS will be required.
  */
-static void set_destination(struct sip_pvt *p, const char *uri)
+static void set_destination(struct sip_pvt *p, char *uri)
 {
-	char *trans, *maddr, hostname[256];
-	const char *h;
+	char *trans, *h, *maddr, hostname[256];
 	int hn;
 	int debug=sip_debug_test_pvt(p);
 	int tls_on = FALSE;
@@ -11875,9 +11758,6 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
 			snprintf(contact, sizeof(contact), "%s%s%s;expires=%d", brackets ? "" : "<", contact_uri, brackets ? "" : ">", p->expiry);
 			add_header(resp, "Contact", contact);	/* Not when we unregister */
 		}
-		if (p->method == SIP_REGISTER && ast_test_flag(&p->flags[0], SIP_USEPATH)) {
-			copy_header(resp, req, "Path");
-		}
 	} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) {
 		add_header(resp, "Contact", p->our_contact);
 	}
@@ -11935,59 +11815,50 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, ui
 	}
 
 	/* Check for strict or loose router */
-	if (sip_route_is_strict(&p->route)) {
+	if (p->route && !ast_strlen_zero(p->route->hop) && strstr(p->route->hop, ";lr") == NULL) {
 		is_strict = TRUE;
 		if (sipdebug)
 			ast_debug(1, "Strict routing enforced for session %s\n", p->callid);
 	}
 
-	if (sipmethod == SIP_CANCEL) {
+	if (sipmethod == SIP_CANCEL)
 		c = REQ_OFFSET_TO_STR(&p->initreq, rlpart2);	/* Use original URI */
-	} else if (sipmethod == SIP_ACK) {
+	else if (sipmethod == SIP_ACK) {
 		/* Use URI from Contact: in 200 OK (if INVITE)
 		(we only have the contacturi on INVITEs) */
-		if (!ast_strlen_zero(p->okcontacturi)) {
-			c = is_strict ? sip_route_first_uri(&p->route) : p->okcontacturi;
-		} else {
+		if (!ast_strlen_zero(p->okcontacturi))
+			c = is_strict ? p->route->hop : p->okcontacturi;
+		else
 			c = REQ_OFFSET_TO_STR(&p->initreq, rlpart2);
-		}
-	} else if (!ast_strlen_zero(p->okcontacturi)) {
-		/* Use for BYE or REINVITE */
-		c = is_strict ? sip_route_first_uri(&p->route) : p->okcontacturi;
-	} else if (!ast_strlen_zero(p->uri)) {
+	} else if (!ast_strlen_zero(p->okcontacturi))
+		c = is_strict ? p->route->hop : p->okcontacturi; /* Use for BYE or REINVITE */
+	else if (!ast_strlen_zero(p->uri))
 		c = p->uri;
-	} else {
+	else {
 		char *n;
 		/* We have no URI, use To: or From:  header as URI (depending on direction) */
 		ast_copy_string(stripped, sip_get_header(orig, is_outbound ? "To" : "From"),
 				sizeof(stripped));
 		n = get_in_brackets(stripped);
 		c = remove_uri_parameters(n);
-	}
+	}	
 	init_req(req, sipmethod, c);
 
 	snprintf(tmp, sizeof(tmp), "%u %s", seqno, sip_methods[sipmethod].text);
 
 	add_header(req, "Via", p->via);
 	/*
-	 * Use the learned route set unless this is a CANCEL on an ACK for a non-2xx
+	 * Use the learned route set unless this is a CANCEL or an ACK for a non-2xx
 	 * final response. For a CANCEL or ACK, we have to send to the same destination
 	 * as the original INVITE.
+	 * Send UPDATE to the same destination as CANCEL, if call is not in final state.
 	 */
-	if (!sip_route_empty(&p->route) &&
+	if (p->route &&
 			!(sipmethod == SIP_CANCEL ||
-				(sipmethod == SIP_ACK && (p->invitestate == INV_COMPLETED || p->invitestate == INV_CANCELLED)))) {
-		if (p->socket.type != AST_TRANSPORT_UDP && p->socket.tcptls_session) {
-			/* For TCP/TLS sockets that are connected we won't need
-			 * to do any hostname/IP lookups */
-		} else if (ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT)) {
-			/* For NATed traffic, we ignore the contact/route and
-			 * simply send to the received-from address. No need
-			 * for lookups. */
-		} else {
-			set_destination(p, sip_route_first_uri(&p->route));
-		}
-		add_route(req, &p->route, is_strict ? 1 : 0);
+				(sipmethod == SIP_ACK && (p->invitestate == INV_COMPLETED || p->invitestate == INV_CANCELLED)) ||
+				(sipmethod == SIP_UPDATE && (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA)))) {
+		set_destination(p, p->route->hop);
+		add_route(req, is_strict ? p->route->next : p->route);
 	}
 	add_max_forwards(p, req);
 
@@ -12395,7 +12266,7 @@ static void get_realm(struct sip_pvt *p, const struct sip_request *req)
 			}
 		}
 	}
-
+	
 	/* Use default realm from config file */
 	ast_string_field_set(p, realm, sip_cfg.realm);
 }
@@ -12786,15 +12657,21 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
 	struct ast_str **m_buf,
 	struct ast_str **a_buf,
 	int debug,
-	int *min_packet_size,
-	int *max_packet_size)
+	int *min_packet_size)
 {
 	int rtp_code;
+	struct ast_format_list fmt;
 	const char *mime;
-	unsigned int rate, framing;
+	unsigned int rate;
+	struct ast_codec_pref *pref;
+
+	if (!p->rtp) {
+		/* I don't see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
+		return;
+	}
 
 	if (debug)
-		ast_verbose("Adding codec %s to SDP\n", ast_format_get_name(format));
+		ast_verbose("Adding codec %u (%s) to SDP\n", format->id, ast_getformatname(format));
 
 	if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->rtp), 1, format, 0)) == -1) ||
 	    !(mime = ast_rtp_lookup_mime_subtype2(1, format, 0, ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0)) ||
@@ -12802,55 +12679,47 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
 		return;
 	}
 
-	ast_str_append(m_buf, 0, " %d", rtp_code);
-	/* Opus mandates 2 channels in rtpmap */
-	if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) {
-		ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate);
-	} else {
-		ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate);
-	}
+	pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
+	fmt = ast_codec_pref_getsize(pref, format);
 
-	ast_format_generate_sdp_fmtp(format, rtp_code, a_buf);
+	ast_str_append(m_buf, 0, " %d", rtp_code);
+	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate);
 
-	framing = ast_format_cap_get_format_framing(p->caps, format);
+	ast_format_sdp_generate(format, rtp_code, a_buf);
 
-	if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
+	switch ((int) format->id) {
+	case AST_FORMAT_G729A:
 		/* Indicate that we don't support VAD (G.729 annex B) */
 		ast_str_append(a_buf, 0, "a=fmtp:%d annexb=no\r\n", rtp_code);
-	} else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
+		break;
+	case AST_FORMAT_G723_1:
 		/* Indicate that we don't support VAD (G.723.1 annex A) */
 		ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code);
-	} else if (ast_format_cmp(format, ast_format_ilbc) == AST_FORMAT_CMP_EQUAL) {
+		break;
+	case AST_FORMAT_ILBC:
 		/* Add information about us using only 20/30 ms packetization */
-		ast_str_append(a_buf, 0, "a=fmtp:%d mode=%u\r\n", rtp_code, framing);
-	} else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) {
+		ast_str_append(a_buf, 0, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms);
+		break;
+	case AST_FORMAT_SIREN7:
 		/* Indicate that we only expect 32Kbps */
 		ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code);
-	} else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) {
+		break;
+	case AST_FORMAT_SIREN14:
 		/* Indicate that we only expect 48Kbps */
 		ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code);
-	} else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) {
+		break;
+	case AST_FORMAT_G719:
 		/* Indicate that we only expect 64Kbps */
 		ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code);
+		break;
 	}
 
-	if (max_packet_size && ast_format_get_maximum_ms(format) &&
-		(ast_format_get_maximum_ms(format) < *max_packet_size)) {
-		*max_packet_size = ast_format_get_maximum_ms(format);
-	}
-
-	if (framing && (framing < *min_packet_size)) {
-		*min_packet_size = framing;
-	}
+	if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
+		*min_packet_size = fmt.cur_ms;
 
 	/* Our first codec packetization processed cannot be zero */
-	if ((*min_packet_size) == 0 && framing) {
-		*min_packet_size = framing;
-	}
-
-	if ((*max_packet_size) == 0 && ast_format_get_maximum_ms(format)) {
-		*max_packet_size = ast_format_get_maximum_ms(format);
-	}
+	if ((*min_packet_size)==0 && fmt.cur_ms)
+		*min_packet_size = fmt.cur_ms;
 }
 
 /*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
@@ -12867,7 +12736,7 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format
 		return;
 
 	if (debug)
-		ast_verbose("Adding video codec %s to SDP\n", ast_format_get_name(format));
+		ast_verbose("Adding video codec %u (%s) to SDP\n", format->id, ast_getformatname(format));
 
 	if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->vrtp), 1, format, 0)) == -1) ||
 	    !(subtype = ast_rtp_lookup_mime_subtype2(1, format, 0, 0)) ||
@@ -12877,12 +12746,8 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format
 
 	ast_str_append(m_buf, 0, " %d", rtp_code);
 	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, subtype, rate);
-	/* VP8: add RTCP FIR support */
-	if (ast_format_cmp(format, ast_format_vp8) == AST_FORMAT_CMP_EQUAL) {
-		ast_str_append(a_buf, 0, "a=rtcp-fb:* ccm fir\r\n");
-	}
 
-	ast_format_generate_sdp_fmtp(format, rtp_code, a_buf);
+	ast_format_sdp_generate(format, rtp_code, a_buf);
 }
 
 /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
@@ -12896,7 +12761,7 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format
 		return;
 
 	if (debug)
-		ast_verbose("Adding text codec %s to SDP\n", ast_format_get_name(format));
+		ast_verbose("Adding text codec %u (%s) to SDP\n", format->id, ast_getformatname(format));
 
 	if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, format, 0)) == -1)
 		return;
@@ -12907,8 +12772,9 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format
 		       ast_rtp_lookup_sample_rate2(1, format, 0));
 	/* Add fmtp code here */
 
-	if (ast_format_cmp(format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
-		int t140code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, ast_format_t140, 0);
+	if (format->id == AST_FORMAT_T140RED) {
+		struct ast_format tmp_fmt;
+		int t140code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, ast_format_set(&tmp_fmt, AST_FORMAT_T140, 0), 0);
 		ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code,
 			 t140code,
 			 t140code,
@@ -13055,24 +12921,56 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
 	}
 }
 
-static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
+static void get_crypto_attrib(struct sip_pvt *p, struct sip_srtp *srtp, const char **a_crypto)
 {
-	char *a_crypto;
-	const char *orig_crypto;
+	int taglen = 80;
 
-	if (!srtp || dtls_enabled) {
-		return NULL;
-	}
+	/* Set encryption properties */
+	if (srtp) {
+		if (!srtp->crypto) {
+			srtp->crypto = sdp_crypto_setup();
+		}
 
-	orig_crypto = ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32);
-	if (ast_strlen_zero(orig_crypto)) {
-		return NULL;
+		if (p->dtls_cfg.enabled) {
+			/* If DTLS-SRTP is enabled the key details will be pulled from TLS */
+			return;
+		}
+
+		/* set the key length based on INVITE or settings */
+		if (ast_test_flag(srtp, SRTP_CRYPTO_TAG_80)) {
+			taglen = 80;
+		} else if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32) ||
+		    ast_test_flag(srtp, SRTP_CRYPTO_TAG_32)) {
+			taglen = 32;
+		}
+
+		if (srtp->crypto && (sdp_crypto_offer(srtp->crypto, taglen) >= 0)) {
+			*a_crypto = sdp_crypto_attrib(srtp->crypto);
+		}
+
+		if (!*a_crypto) {
+			ast_log(LOG_WARNING, "No SRTP key management enabled\n");
+		}
 	}
+}
 
-	if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) {
-		return NULL;
+static char *get_sdp_rtp_profile(const struct sip_pvt *p, unsigned int secure, struct ast_rtp_instance *instance)
+{
+	struct ast_rtp_engine_dtls *dtls;
+
+	if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) {
+		if (ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)) {
+			return ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF) ? "RTP/SAVPF" : "RTP/SAVP";
+		} else {
+			return ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF) ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
+		}
+	} else {
+		if (ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)) {
+			return secure ? "RTP/SAVPF" : "RTP/AVPF";
+		} else {
+			return secure ? "RTP/SAVP" : "RTP/AVP";
+		}
 	}
-	return a_crypto;
 }
 
 /*! \brief Add Session Description Protocol message
@@ -13083,8 +12981,8 @@ static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int
 */
 static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38)
 {
-	struct ast_format_cap *alreadysent = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	struct ast_format_cap *tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *alreadysent = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *tmpcap = ast_format_cap_alloc_nolock();
 	int res = AST_SUCCESS;
 	int doing_directmedia = FALSE;
 	struct ast_sockaddr addr = { {0,} };
@@ -13113,22 +13011,22 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	struct ast_str *a_video = ast_str_create(256); /* Attributes for video */
 	struct ast_str *a_text = ast_str_create(256);  /* Attributes for text */
 	struct ast_str *a_modem = ast_str_alloca(1024); /* Attributes for modem */
-	RAII_VAR(char *, a_crypto, NULL, ast_free);
-	RAII_VAR(char *, v_a_crypto, NULL, ast_free);
-	RAII_VAR(char *, t_a_crypto, NULL, ast_free);
+	const char *a_crypto = NULL;
+	const char *v_a_crypto = NULL;
+	const char *t_a_crypto = NULL;
 
 	int x;
-	struct ast_format *tmp_fmt;
+	struct ast_format tmp_fmt;
 	int needaudio = FALSE;
 	int needvideo = FALSE;
 	int needtext = FALSE;
 	int debug = sip_debug_test_pvt(p);
 	int min_audio_packet_size = 0;
-	int max_audio_packet_size = 0;
 	int min_video_packet_size = 0;
 	int min_text_packet_size = 0;
 
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	char codecbuf[SIPBUFSIZE];
+	char buf[SIPBUFSIZE];
 
 	/* Set the SDP session name */
 	snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
@@ -13156,24 +13054,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	}
 
 	if (add_audio) {
-		doing_directmedia = (!ast_sockaddr_isnull(&p->redirip) && (ast_format_cap_count(p->redircaps))) ? TRUE : FALSE;
-
-		if (doing_directmedia) {
-			ast_format_cap_get_compatible(p->jointcaps, p->redircaps, tmpcap);
-			ast_debug(1, "** Our native-bridge filtered capablity: %s\n", ast_format_cap_get_names(tmpcap, &codec_buf));
-		} else {
-			ast_format_cap_append_from_cap(tmpcap, p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-		}
-
-		/* Check if we need audio */
-		if (ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_AUDIO)
-			|| ast_format_cap_has_type(p->caps, AST_MEDIA_TYPE_AUDIO)) {
-			needaudio = TRUE;
-		}
-
+		doing_directmedia = (!ast_sockaddr_isnull(&p->redirip) && !(ast_format_cap_is_empty(p->redircaps))) ? TRUE : FALSE;
 		/* Check if we need video in this call */
-		if ((ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) && !p->novideo) {
-			if (doing_directmedia && !ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) {
+		if ((ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_VIDEO)) && !p->novideo) {
+			ast_format_cap_joint_copy(p->jointcaps, p->redircaps, tmpcap);
+			if (doing_directmedia && !ast_format_cap_has_type(tmpcap, AST_FORMAT_TYPE_VIDEO)) {
 				ast_debug(2, "This call needs video offers, but caller probably did not offer it!\n");
 			} else if (p->vrtp) {
 				needvideo = TRUE;
@@ -13182,9 +13067,8 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 				ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
 			}
 		}
-
 		/* Check if we need text in this call */
-		if ((ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_TEXT)) && !p->notext) {
+		if ((ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_TEXT)) && !p->notext) {
 			if (sipdebug_text)
 				ast_verbose("We think we can do text\n");
 			if (p->trtp) {
@@ -13197,12 +13081,6 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 				ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
 			}
 		}
-
-		/* XXX note, Video and Text are negated - 'true' means 'no' */
-		ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n",
-			  ast_format_cap_get_names(tmpcap, &codec_buf),
-			  p->novideo ? "True" : "False", p->notext ? "True" : "False");
-		ast_debug(1, "** Our prefcodec: %s \n", ast_format_cap_get_names(p->prefcaps, &codec_buf));
 	}
 
 	get_our_media_address(p, needvideo, needtext, &addr, &vaddr, &taddr, &dest, &vdest, &tdest);
@@ -13230,6 +13108,22 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 			hold = "a=sendrecv\r\n";
 		}
 
+		ast_format_cap_copy(tmpcap, p->jointcaps);
+
+		/* XXX note, Video and Text are negated - 'true' means 'no' */
+		ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), tmpcap),
+			  p->novideo ? "True" : "False", p->notext ? "True" : "False");
+		ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcaps));
+
+		if (doing_directmedia) {
+			ast_format_cap_joint_copy(p->jointcaps, p->redircaps, tmpcap);
+			ast_debug(1, "** Our native-bridge filtered capablity: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), tmpcap));
+		}
+
+		/* Check if we need audio */
+		if (ast_format_cap_has_type(tmpcap, AST_FORMAT_TYPE_AUDIO))
+			needaudio = TRUE;
+
 		if (debug) {
 			ast_verbose("Audio is at %s\n", ast_sockaddr_stringify_port(&addr));
 		}
@@ -13237,12 +13131,9 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		/* Ok, we need video. Let's add what we need for video and set codecs.
 		   Video is handled differently than audio since we can not transcode. */
 		if (needvideo) {
-			v_a_crypto = crypto_get_attrib(p->vsrtp, p->dtls_cfg.enabled,
-				ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
+			get_crypto_attrib(p, p->vsrtp, &v_a_crypto);
 			ast_str_append(&m_video, 0, "m=video %d %s", ast_sockaddr_port(&vdest),
-				ast_sdp_get_rtp_profile(v_a_crypto ? 1 : 0, p->vrtp,
-					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
-					ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
+				       get_sdp_rtp_profile(p, v_a_crypto ? 1 : 0, p->vrtp));
 
 			/* Build max bitrate string */
 			if (p->maxcallbitrate)
@@ -13265,12 +13156,9 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		if (needtext) {
 			if (sipdebug_text)
 				ast_verbose("Lets set up the text sdp\n");
-			t_a_crypto = crypto_get_attrib(p->tsrtp, p->dtls_cfg.enabled,
-				ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
+			get_crypto_attrib(p, p->tsrtp, &t_a_crypto);
 			ast_str_append(&m_text, 0, "m=text %d %s", ast_sockaddr_port(&tdest),
-				ast_sdp_get_rtp_profile(t_a_crypto ? 1 : 0, p->trtp,
-					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
-					ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
+				       get_sdp_rtp_profile(p, t_a_crypto ? 1 : 0, p->trtp));
 			if (debug) {  /* XXX should I use tdest below ? */
 				ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr));
 			}
@@ -13289,80 +13177,69 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		/* We break with the "recommendation" and send our IP, in order that our
 		   peer doesn't have to ast_gethostbyname() us */
 
-		a_crypto = crypto_get_attrib(p->srtp, p->dtls_cfg.enabled,
-			ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
+		get_crypto_attrib(p, p->srtp, &a_crypto);
 		ast_str_append(&m_audio, 0, "m=audio %d %s", ast_sockaddr_port(&dest),
-			ast_sdp_get_rtp_profile(a_crypto ? 1 : 0, p->rtp,
-				ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
-				ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
+			       get_sdp_rtp_profile(p, a_crypto ? 1 : 0, p->rtp));
 
 		/* Now, start adding audio codecs. These are added in this order:
 		   - First what was requested by the calling channel
-		   - Then our mutually shared capabilities, determined previous in tmpcap
 		   - Then preferences in order from sip.conf device config for this peer/user
+		   - Then other codecs in capabilities, including video
 		*/
 
-
-		/* Unless otherwise configured, the prefcaps is added before the peer's
-		 * configured codecs.
-		 */
-		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_IGNORE_PREFCAPS)) {
-			for (x = 0; x < ast_format_cap_count(p->prefcaps); x++) {
-				tmp_fmt = ast_format_cap_get_format(p->prefcaps, x);
-
-				if ((ast_format_get_type(tmp_fmt) != AST_MEDIA_TYPE_AUDIO) ||
-					(ast_format_cap_iscompatible_format(tmpcap, tmp_fmt) == AST_FORMAT_CMP_NOT_EQUAL)) {
-					ao2_ref(tmp_fmt, -1);
-					continue;
-				}
-
-				add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
-				ast_format_cap_append(alreadysent, tmp_fmt, 0);
-				ao2_ref(tmp_fmt, -1);
+		/* Prefer the audio codec we were requested to use, first, no matter what
+		   Note that p->prefcodec can include video codecs, so ignore them
+		*/
+		ast_format_cap_iter_start(p->prefcaps);
+		while (!(ast_format_cap_iter_next(p->prefcaps, &tmp_fmt))) {
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO ||
+				!ast_format_cap_iscompatible(tmpcap, &tmp_fmt)) {
+				continue;
 			}
+			add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			ast_format_cap_add(alreadysent, &tmp_fmt);
 		}
+		ast_format_cap_iter_end(p->prefcaps);
 
-		/* Now send any other common codecs */
-		for (x = 0; x < ast_format_cap_count(tmpcap); x++) {
-			tmp_fmt = ast_format_cap_get_format(tmpcap, x);
+		/* Start by sending our preferred audio/video codecs */
+		for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+			struct ast_format pref;
 
-			if (ast_format_cap_iscompatible_format(alreadysent, tmp_fmt) != AST_FORMAT_CMP_NOT_EQUAL) {
-				ao2_ref(tmp_fmt, -1);
+			if (!(ast_codec_pref_index(&p->prefs, x, &pref)))
+				break;
+
+			if (!ast_format_cap_get_compatible_format(tmpcap, &pref, &tmp_fmt))
+				continue;
+
+			if (ast_format_cap_iscompatible(alreadysent, &tmp_fmt))
 				continue;
-			}
 
-			if (ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_AUDIO) {
-				add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
-			} else if (needvideo && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_VIDEO) {
-				add_vcodec_to_sdp(p, tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
-			} else if (needtext && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_TEXT) {
-				add_tcodec_to_sdp(p, tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size);
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) {
+				add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			} else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) {
+				add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
+			} else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) {
+				add_tcodec_to_sdp(p, &tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size);
 			}
 
-			ast_format_cap_append(alreadysent, tmp_fmt, 0);
-			ao2_ref(tmp_fmt, -1);
+			ast_format_cap_add(alreadysent, &tmp_fmt);
 		}
 
-		/* Finally our remaining audio/video codecs */
-		for (x = 0; x < ast_format_cap_count(p->caps); x++) {
-			tmp_fmt = ast_format_cap_get_format(p->caps, x);
-
-			if (ast_format_cap_iscompatible_format(alreadysent, tmp_fmt) != AST_FORMAT_CMP_NOT_EQUAL) {
-				ao2_ref(tmp_fmt, -1);
+		/* Now send any other common audio and video codecs, and non-codec formats: */
+		ast_format_cap_iter_start(tmpcap);
+		while (!(ast_format_cap_iter_next(tmpcap, &tmp_fmt))) {
+			if (ast_format_cap_iscompatible(alreadysent, &tmp_fmt))
 				continue;
-			}
 
-			if (ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_AUDIO) {
-				add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
-			} else if (needvideo && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_VIDEO) {
-				add_vcodec_to_sdp(p, tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
-			} else if (needtext && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_TEXT) {
-				add_tcodec_to_sdp(p, tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size);
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) {
+				add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			} else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) {
+				add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
+			} else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) {
+				add_tcodec_to_sdp(p, &tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size);
 			}
-
-			ast_format_cap_append(alreadysent, tmp_fmt, 0);
-			ao2_ref(tmp_fmt, -1);
 		}
+		ast_format_cap_iter_end(tmpcap);
 
 		/* Now add DTMF RFC2833 telephony-event as a codec */
 		for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
@@ -13378,23 +13255,16 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 			ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
 		}
 
-		if (min_audio_packet_size) {
+		if (min_audio_packet_size)
 			ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
-		}
 
 		/* XXX don't think you can have ptime for video */
-		if (min_video_packet_size) {
+		if (min_video_packet_size)
 			ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
-		}
 
 		/* XXX don't think you can have ptime for text */
-		if (min_text_packet_size) {
+		if (min_text_packet_size)
 			ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
-		}
-
-		if (max_audio_packet_size) {
-			ast_str_append(&a_audio, 0, "a=maxptime:%d\r\n", max_audio_packet_size);
-		}
 
 		if (!doing_directmedia) {
 			if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
@@ -13574,15 +13444,14 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 	ao2_t_link(dialogs_rtpcheck, p, "link pvt into dialogs_rtpcheck container");
 	ao2_unlock(dialogs_rtpcheck);
 
-	ast_debug(3, "Done building SDP. Settling with this capability: %s\n",
-		ast_format_cap_get_names(tmpcap, &codec_buf));
+	ast_debug(3, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, tmpcap));
 
 add_sdp_cleanup:
 	ast_free(a_text);
 	ast_free(a_video);
 	ast_free(a_audio);
-	ao2_cleanup(alreadysent);
-	ao2_cleanup(tmpcap);
+	alreadysent = ast_format_cap_destroy(alreadysent);
+	tmpcap = ast_format_cap_destroy(tmpcap);
 
 	return res;
 }
@@ -13690,7 +13559,7 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
 	if (p->rtp) {
 		if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 			ast_debug(1, "Setting framing from config on incoming call\n");
-			ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(p->caps));
+			ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
 		}
 		ast_rtp_instance_activate(p->rtp);
 		try_suggested_sip_codec(p);
@@ -13755,7 +13624,7 @@ static int determine_firstline_parts(struct sip_request *req)
 	INVITE that opened the SIP dialogue
 	We reinvite so that the audio stream (RTP) go directly between
 	the SIP UAs. SIP Signalling stays with * in the path.
-
+	
 	If t38version is TRUE, we send T38 SDP for re-invite from audio/video to
 	T38 UDPTL transmission on the channel
 
@@ -13766,7 +13635,7 @@ static int determine_firstline_parts(struct sip_request *req)
 static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int oldsdp)
 {
 	struct sip_request req;
-
+	
 	reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ?  SIP_UPDATE : SIP_INVITE, 0, 1);
 
 	add_header(&req, "Allow", ALLOWED_METHODS);
@@ -13829,22 +13698,110 @@ static void extract_uri(struct sip_pvt *p, struct sip_request *req)
 	if (!ast_strlen_zero(c)) {
 		ast_string_field_set(p, uri, c);
 	}
+}
+
+/*!
+ * \brief Determine if, as a UAS, we need to use a SIPS Contact.
+ *
+ * This uses the rules defined in RFC 3261 section 12.1.1 to
+ * determine if a SIPS URI should be used as the Contact header
+ * when responding to incoming SIP requests.
+ *
+ * \param req The incoming SIP request
+ * \retval 0 SIPS is not required
+ * \retval 1 SIPS is required
+ */
+static int uas_sips_contact(struct sip_request *req)
+{
+	const char *record_route = sip_get_header(req, "Record-Route");
+
+	if (!strncmp(REQ_OFFSET_TO_STR(req, rlpart2), "sips:", 5)) {
+		return 1;
+	}
 
+	if (record_route) {
+		char *record_route_uri = get_in_brackets(ast_strdupa(record_route));
+
+		if (!strncmp(record_route_uri, "sips:", 5)) {
+			return 1;
+		}
+	} else {
+		const char *contact = sip_get_header(req, "Contact");
+		char *contact_uri = get_in_brackets(ast_strdupa(contact));
+
+		if (!strncmp(contact_uri, "sips:", 5)) {
+			return 1;
+		}
+	}
+
+	return 0;
 }
 
-/*! \brief Build contact header - the contact header we send out */
-static void build_contact(struct sip_pvt *p)
+/*!
+ * \brief Determine if, as a UAC, we need to use a SIPS Contact.
+ *
+ * This uses the rules defined in RFC 3621 section 8.1.1.8 to
+ * determine if a SIPS URI should be used as the Contact header
+ * on our outgoing request.
+ *
+ * \param req The outgoing SIP request
+ * \retval 0 SIPS is not required
+ * \retval 1 SIPS is required
+ */
+static int uac_sips_contact(struct sip_request *req)
+{
+	const char *route = sip_get_header(req, "Route");
+
+	if (!strncmp(REQ_OFFSET_TO_STR(req, rlpart2), "sips:", 5)) {
+		return 1;
+	}
+
+	if (route) {
+		char *route_uri = get_in_brackets(ast_strdupa(route));
+
+		if (!strncmp(route_uri, "sips:", 5)) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Build contact header
+ *
+ * This is the Contact header that we send out in SIP requests and responses
+ * involving this sip_pvt.
+ *
+ * The incoming parameter is used to tell if we are building the request parameter
+ * is an incoming SIP request that we are building the Contact header in response to,
+ * or if the req parameter is an outbound SIP request that we will later be adding
+ * the Contact header to.
+ *
+ * \param p The sip_pvt where the built Contact will be saved.
+ * \param req The request that triggered the creation of a Contact header.
+ * \param incoming Indicates if the Contact header is being created for a response to an incoming request
+ */
+static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming)
 {
 	char tmp[SIPBUFSIZE];
 	char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
+	int use_sips;
 
-	if (p->socket.type == AST_TRANSPORT_UDP) {
-		ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user,
-			ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip));
+	if (incoming) {
+		use_sips = uas_sips_contact(req);
 	} else {
-		ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", user,
-			ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip),
-			sip_get_transport(p->socket.type));
+		use_sips = uac_sips_contact(req);
+	}
+
+	if (p->socket.type == SIP_TRANSPORT_UDP) {
+		ast_string_field_build(p, our_contact, "<%s:%s%s%s>", use_sips ? "sips" : "sip",
+			user, ast_strlen_zero(user) ? "" : "@",
+			ast_sockaddr_stringify_remote(&p->ourip));
+	} else {
+		ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
+			use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
+			ast_sockaddr_stringify_remote(&p->ourip), sip_get_transport(p->socket.type));
 	}
 }
 
@@ -13864,6 +13821,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 	int cid_has_name = 1;
 	int cid_has_num = 1;
 	struct ast_party_id connected_id;
+	int ret;
 
 	if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
 	 	const char *s = p->username;	/* being a string field, cannot be NULL */
@@ -13948,26 +13906,41 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 
 	ast_copy_string(tmp_l, l, sizeof(tmp_l));
 	if (sip_cfg.pedanticsipchecking) {
-		ast_escape_quoted(n, tmp_n, sizeof(tmp_n));
-		n = tmp_n;
 		ast_uri_encode(l, tmp_l, sizeof(tmp_l), ast_uri_sip_user);
 	}
 
 	ourport = (p->fromdomainport && (p->fromdomainport != STANDARD_SIP_PORT)) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
 
-	/* If a caller id name was specified, add a display name. */
-	if (cid_has_name || !cid_has_num) {
-		snprintf(from, sizeof(from), "\"%s\" ", n);
+	if (!sip_standard_port(p->socket.type, ourport)) {
+		ret = snprintf(from, sizeof(from), "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag);
 	} else {
-		from[0] = '\0';
+		ret = snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag);
+	}
+	if (ret < 0 || ret >= sizeof(from)) { /* a return value of size or more means that the output was truncated */
+		/* We don't have an escape path from here... */
+		ast_log(LOG_ERROR, "The From header was truncated in call '%s'. This call setup will fail.\n", p->callid);
 	}
 
-	if (!sip_standard_port(p->socket.type, ourport)) {
-		size_t offset = strlen(from);
-		snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag);
-	} else {
-		size_t offset = strlen(from);
-		snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag);
+	/* If a caller id name was specified, prefix a display name, if there is enough room. */
+	if (cid_has_name || !cid_has_num) {
+		size_t written = strlen(from);
+		ssize_t left = sizeof(from) - written - 4; /* '"" \0' */
+		if (left > 0) {
+			size_t name_len;
+			if (sip_cfg.pedanticsipchecking) {
+				ast_escape_quoted(n, tmp_n, MIN(left + 1, sizeof(tmp_n)));
+				n = tmp_n;
+			}
+			name_len = strlen(n);
+			if (left < name_len) {
+				name_len = left;
+			}
+			memmove(from + name_len + 3, from, written + 1);
+			from[0] = '"';
+			memcpy(from + 1, n, name_len);
+			from[name_len + 1] = '"';
+			from[name_len + 2] = ' ';
+		}
 	}
 
 	if (!ast_strlen_zero(explicit_uri)) {
@@ -13999,7 +13972,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 	/* If custom URI options have been provided, append them */
 	if (p->options && !ast_strlen_zero(p->options->uri_options))
 		ast_str_append(&invite, 0, ";%s", p->options->uri_options);
-
+	
  	/* This is the request URI, which is the next hop of the call
  		which may or may not be the destination of the call
  	*/
@@ -14009,21 +13982,25 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
  		/*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */
  		if (!strchr(p->todnid, '@')) {
  			/* We have no domain in the dnid */
- 			snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+			ret = snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
  		} else {
- 			snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+			ret = snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
  		}
  	} else {
  		if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) {
  			/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
-			snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag);
+			ret = snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag);
  		} else if (p->options && p->options->vxml_url) {
  			/* If there is a VXML URL append it to the SIP URL */
- 			snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
+			ret = snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
  		} else {
- 			snprintf(to, sizeof(to), "<%s>", p->uri);
+			ret = snprintf(to, sizeof(to), "<%s>", p->uri);
 		}
  	}
+	if (ret < 0 || ret >= sizeof(to)) { /* a return value of size or more means that the output was truncated */
+		/* We don't have an escape path from here... */
+		ast_log(LOG_ERROR, "The To header was truncated in call '%s'. This call setup will fail.\n", p->callid);
+	}
 
 	init_req(req, sipmethod, p->uri);
 	/* now tmp_n is available so reuse it to build the CSeq */
@@ -14035,12 +14012,12 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 	 * NOTIFY messages will use this function for preparing the request and should
 	 * have Route headers present.
 	 */
-	add_route(req, &p->route, 0);
+	add_route(req, p->route);
 
 	add_header(req, "From", from);
 	add_header(req, "To", to);
 	ast_string_field_set(p, exten, l);
-	build_contact(p);
+	build_contact(p, req, 0);
 	add_header(req, "Contact", p->our_contact);
 	add_header(req, "Call-ID", p->callid);
 	add_header(req, "CSeq", tmp_n);
@@ -14061,9 +14038,7 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
 {
 	struct ast_party_id diverting_from;
 	const char *reason;
-	int found_in_table;
 	char header_text[256];
-	char encoded_number[SIPBUFSIZE/2];
 
 	/* We skip this entirely if the configuration doesn't allow diversion headers */
 	if (!sip_cfg.send_diversion) {
@@ -14080,37 +14055,20 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
 		return;
 	}
 
-	if (sip_cfg.pedanticsipchecking) {
-		ast_uri_encode(diverting_from.number.str, encoded_number, sizeof(encoded_number), ast_uri_sip_user);
-	} else {
-		ast_copy_string(encoded_number, diverting_from.number.str, sizeof(encoded_number));
-	}
-
-	reason = sip_reason_code_to_str(&ast_channel_redirecting(pvt->owner)->reason, &found_in_table);
+	reason = sip_reason_code_to_str(ast_channel_redirecting(pvt->owner)->reason);
 
 	/* We at least have a number to place in the Diversion header, which is enough */
 	if (!diverting_from.name.valid
 		|| ast_strlen_zero(diverting_from.name.str)) {
-		snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s%s%s",
-				encoded_number,
-				ast_sockaddr_stringify_host_remote(&pvt->ourip),
-				found_in_table ? "" : "\"",
-				reason,
-				found_in_table ? "" : "\"");
+		snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_from.number.str,
+				ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
 	} else {
-		char escaped_name[SIPBUFSIZE/2];
-		if (sip_cfg.pedanticsipchecking) {
-			ast_escape_quoted(diverting_from.name.str, escaped_name, sizeof(escaped_name));
-		} else {
-			ast_copy_string(escaped_name, diverting_from.name.str, sizeof(escaped_name));
-		}
-		snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s%s%s",
-				escaped_name,
-				encoded_number,
-				ast_sockaddr_stringify_host_remote(&pvt->ourip),
-				found_in_table ? "" : "\"",
-				reason,
-				found_in_table ? "" : "\"");
+		char diverting_name_buf[128];
+
+		ast_escape_quoted(diverting_from.name.str, diverting_name_buf, sizeof(diverting_name_buf));
+		snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s",
+				diverting_name_buf, diverting_from.number.str,
+				ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
 	}
 
 	add_header(req, "Diversion", header_text);
@@ -14151,7 +14109,7 @@ static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_ty
 	return 0;
 }
 
-/*!
+/*! 
  * \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it
  * \param p sip_pvt structure
  * \param sipmethod
@@ -14217,7 +14175,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
 		}
 
 		p->stimer->st_active = TRUE;
-		if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {
+		if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {	
 			snprintf(i2astr, sizeof(i2astr), "%d", p->stimer->st_interval);
 			add_header(&req, "Session-Expires", i2astr);
 		}
@@ -14233,7 +14191,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
 				  || (p->refer && global_refer_addheaders))) {
 		struct ast_channel *chan = p->owner; /* The owner channel */
 		struct varshead *headp;
-
+	
 		ast_channel_lock(chan);
 
 		headp = ast_channel_varshead(chan);
@@ -14244,7 +14202,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
 			const struct ast_var_t *current;
 			AST_LIST_TRAVERSE(headp, current, entries) {
 				/* SIPADDHEADER: Add SIP header to outgoing call */
-				if (!strncmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
+				if (!strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
 					char *content, *end;
 					const char *header = ast_var_value(current);
 					char *headdup = ast_strdupa(header);
@@ -14325,15 +14283,15 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
 static int sip_subscribe_mwi_do(const void *data)
 {
 	struct sip_subscription_mwi *mwi = (struct sip_subscription_mwi*)data;
-
+	
 	if (!mwi) {
 		return -1;
 	}
-
+	
 	mwi->resub = -1;
 	__sip_subscribe_mwi_do(mwi);
-	ao2_t_ref(mwi, -1, "unref mwi to balance ast_sched_add");
-
+	ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy);
+	
 	return 0;
 }
 
@@ -14409,13 +14367,14 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 	/* If we have no DNS manager let's do a lookup */
 	if (!mwi->dnsmgr) {
 		char transport[MAXHOSTNAMELEN];
+		struct sip_subscription_mwi *saved;
 		snprintf(transport, sizeof(transport), "_%s._%s", get_srv_service(mwi->transport), get_srv_protocol(mwi->transport));
 
 		mwi->us.ss.ss_family = get_address_family_filter(mwi->transport); /* Filter address family */
-		ao2_t_ref(mwi, +1, "dnsmgr reference to mwi");
-		ast_dnsmgr_lookup_cb(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_mwi, mwi);
+		saved = ASTOBJ_REF(mwi);
+		ast_dnsmgr_lookup_cb(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_mwi, saved);
 		if (!mwi->dnsmgr) {
-			ao2_t_ref(mwi, -1, "dnsmgr disabled, remove reference");
+			ASTOBJ_UNREF(saved, sip_subscribe_mwi_destroy); /* dnsmgr disabled, remove reference */
 		}
 	}
 
@@ -14424,7 +14383,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 		transmit_invite(mwi->call, SIP_SUBSCRIBE, 0, 0, NULL);
 		return 0;
 	}
-
+	
 	/* Create a dialog that we will use for the subscription */
 	if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL, NULL))) {
 		return -1;
@@ -14435,7 +14394,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 	if (!ast_sockaddr_port(&mwi->us) && mwi->portno) {
 		ast_sockaddr_set_port(&mwi->us, mwi->portno);
 	}
-
+	
 	/* Setup the destination of our subscription */
 	if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0)) {
 		dialog_unlink_all(mwi->call);
@@ -14444,14 +14403,14 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 	}
 
 	mwi->call->expiry = mwi_expiry;
-
+	
 	if (!mwi->dnsmgr && mwi->portno) {
 		ast_sockaddr_set_port(&mwi->call->sa, mwi->portno);
 		ast_sockaddr_set_port(&mwi->call->recv, mwi->portno);
 	} else {
 		mwi->portno = ast_sockaddr_port(&mwi->call->sa);
 	}
-
+	
 	/* Set various other information */
 	if (!ast_strlen_zero(mwi->authuser)) {
 		ast_string_field_set(mwi->call, peername, mwi->authuser);
@@ -14469,16 +14428,15 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 	set_socket_transport(&mwi->call->socket, mwi->transport);
 	mwi->call->socket.port = htons(mwi->portno);
 	ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call);
-	build_contact(mwi->call);
 	build_via(mwi->call);
 
 	/* Change the dialog callid. */
 	change_callid_pvt(mwi->call, NULL);
 
 	ast_set_flag(&mwi->call->flags[0], SIP_OUTGOING);
-
+	
 	/* Associate the call with us */
-	mwi->call->mwi = ao2_t_bump(mwi, "Reference mwi from it's call");
+	mwi->call->mwi = ASTOBJ_REF(mwi);
 
 	mwi->call->subscribed = MWI_NOTIFICATION;
 
@@ -14488,10 +14446,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Find the channel that is causing the RINGING update, ref'd
- */
+/*! \internal \brief Find the channel that is causing the RINGING update, ref'd */
 static struct ast_channel *find_ringing_channel(struct ao2_container *device_state_info, struct sip_pvt *p)
 {
 	struct ao2_iterator citer;
@@ -14932,13 +14887,13 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs,
 	domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip));
 
 	if (!sip_standard_port(p->socket.type, ourport)) {
-		if (p->socket.type == AST_TRANSPORT_UDP) {
+		if (p->socket.type == SIP_TRANSPORT_UDP) {
 			ast_str_append(&out, 0, "Message-Account: sip:%s@%s:%d\r\n", exten, domain, ourport);
 		} else {
 			ast_str_append(&out, 0, "Message-Account: sip:%s@%s:%d;transport=%s\r\n", exten, domain, ourport, sip_get_transport(p->socket.type));
 		}
 	} else {
-		if (p->socket.type == AST_TRANSPORT_UDP) {
+		if (p->socket.type == SIP_TRANSPORT_UDP) {
 			ast_str_append(&out, 0, "Message-Account: sip:%s@%s\r\n", exten, domain);
 		} else {
 			ast_str_append(&out, 0, "Message-Account: sip:%s@%s;transport=%s\r\n", exten, domain, sip_get_transport(p->socket.type));
@@ -14971,7 +14926,7 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
 {
 	struct sip_request req;
 	char tmp[SIPBUFSIZE/2];
-
+	
 	reqprep(&req, p, SIP_NOTIFY, 0, 1);
 	snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
 	add_header(&req, "Event", tmp);
@@ -15097,7 +15052,7 @@ static void update_connectedline(struct sip_pvt *p, const void *data, size_t dat
 			ast_set_flag(&p->flags[0], SIP_OUTGOING);
 			p->invitestate = INV_CALLING;
 			send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-		} else if ((is_method_allowed(&p->allowed_methods, SIP_UPDATE)) && (!ast_strlen_zero(p->okcontacturi))) {
+		} else if ((is_method_allowed(&p->allowed_methods, SIP_UPDATE)) && (!ast_strlen_zero(p->okcontacturi))) { 
 			reqprep(&req, p, SIP_UPDATE, 0, 1);
 			add_rpid(&req, p);
 			add_header(&req, "X-Asterisk-rpid-update", "Yes");
@@ -15148,11 +15103,6 @@ static const char *regstate2str(enum sipregistrystate regstate)
 	return map_x_s(regstatestrings, regstate, "Unknown");
 }
 
-static void sip_publish_registry(const char *username, const char *domain, const char *status)
-{
-	ast_system_publish_registry("SIP", username, domain, status, NULL);
-}
-
 /*! \brief Update registration with SIP Proxy.
  * Called from the scheduler when the previous registration expires,
  * so we don't have to cancel the pending event.
@@ -15181,12 +15131,12 @@ static int sip_reregister(const void *data)
 	r->expire = -1;
 	r->expiry = r->configured_expiry;
 	__sip_do_register(r);
-	ao2_t_ref(r, -1, "unref the re-register scheduled event");
+	registry_unref(r, "unref the re-register scheduled event");
 	return 0;
 }
 
-/*! \brief Register with SIP proxy
-	\return see \ref __sip_xmit
+/*! \brief Register with SIP proxy 
+	\return see \ref __sip_xmit 
 */
 static int __sip_do_register(struct sip_registry *r)
 {
@@ -15235,7 +15185,9 @@ static int sip_reg_timeout(const void *data)
 
 		/* decouple the two objects */
 		/* p->registry == r, so r has 2 refs, and the unref won't take the object away */
-		ao2_t_replace(p->registry, NULL, "p->registry unreffed");
+		if (p->registry) {
+			p->registry = registry_unref(p->registry, "p->registry unreffed");
+		}
 		r->call = dialog_unref(r->call, "unrefing r->call");
 	}
 	/* If we have a limit, stop registration and give up */
@@ -15251,8 +15203,8 @@ static int sip_reg_timeout(const void *data)
 		transmit_register(r, SIP_REGISTER, NULL, NULL);
 		ast_log(LOG_NOTICE, "   -- Registration for '%s@%s' timed out, trying again (Attempt #%d)\n", r->username, r->hostname, r->regattempts);
 	}
-	sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
-	ao2_t_ref(r, -1, "unreffing registry_unref r");
+	manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
+	registry_unref(r, "unreffing registry_unref r");
 	return 0;
 }
 
@@ -15303,11 +15255,11 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 		 * or peer NULL. Since we're only concerned with its existence, we're not going to
 		 * bother getting a ref to the proxy*/
 		if (!obproxy_get(r->call, peer)) {
-			ao2_t_ref(r, +1, "add reg ref for dnsmgr");
+			registry_addref(r, "add reg ref for dnsmgr");
 			ast_dnsmgr_lookup_cb(peer ? peer->tohost : r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_registry, r);
 			if (!r->dnsmgr) {
 				/*dnsmgr refresh disabled, no reference added! */
-				ao2_t_ref(r, -1, "remove reg ref, dnsmgr disabled");
+				registry_unref(r, "remove reg ref, dnsmgr disabled");
 			}
 		}
 		if (peer) {
@@ -15371,12 +15323,12 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 			p = dialog_unref(p, "unref dialog after unlink_all");
 			if (r->timeout > -1) {
 				AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r,
-										ao2_t_ref(_data, -1, "del for REPLACE of registry ptr"),
-										ao2_t_ref(r, -1, "object ptr dec when SCHED_REPLACE add failed"),
-										ao2_t_ref(r, +1, "add for REPLACE registry ptr"));
+										registry_unref(_data, "del for REPLACE of registry ptr"),
+										registry_unref(r, "object ptr dec when SCHED_REPLACE add failed"),
+										registry_addref(r,"add for REPLACE registry ptr"));
 				ast_log(LOG_WARNING, "Still have a registration timeout for %s@%s (create_addr() error), %d\n", r->username, r->hostname, r->timeout);
 			} else {
-				r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, ao2_t_bump(r, "add for REPLACE registry ptr"));
+				r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, registry_addref(r, "add for REPLACE registry ptr"));
 				ast_log(LOG_WARNING, "Probably a DNS error for registration to %s@%s, trying REGISTER again (after %d seconds)\n", r->username, r->hostname, global_reg_timeout);
 			}
 			r->regattempts++;
@@ -15400,7 +15352,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 
 		ast_set_flag(&p->flags[0], SIP_OUTGOING);	/* Registration is outgoing call */
 		r->call = dialog_ref(p, "copying dialog into registry r->call");		/* Save pointer to SIP dialog */
-		p->registry = ao2_t_bump(r, "transmit_register: addref to p->registry in transmit_register");	/* Add pointer to registry in packet */
+		p->registry = registry_addref(r, "transmit_register: addref to p->registry in transmit_register");	/* Add pointer to registry in packet */
 		if (!ast_strlen_zero(r->secret)) {	/* Secret (password) */
 			ast_string_field_set(p, peersecret, r->secret);
 		}
@@ -15426,7 +15378,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 
 		/* Set transport and port so the correct contact is built */
 		set_socket_transport(&p->socket, r->transport);
-		if (r->transport == AST_TRANSPORT_TLS || r->transport == AST_TRANSPORT_TCP) {
+		if (r->transport == SIP_TRANSPORT_TLS || r->transport == SIP_TRANSPORT_TCP) {
 			p->socket.port =
 			    htons(ast_sockaddr_port(&sip_tcp_desc.local_address));
 		}
@@ -15437,7 +15389,6 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 		  internal network so we can register through nat
 		 */
 		ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
-		build_contact(p);
 	}
 
 	/* set up a timeout */
@@ -15446,9 +15397,9 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 			ast_log(LOG_WARNING, "Still have a registration timeout, #%d - deleting it\n", r->timeout);
 		}
 		AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r,
-								ao2_t_ref(_data, -1, "reg ptr unrefed from del in SCHED_REPLACE"),
-								ao2_t_ref(r, -1, "reg ptr unrefed from add failure in SCHED_REPLACE"),
-								ao2_t_ref(r, +1, "reg ptr reffed from add in SCHED_REPLACE"));
+								registry_unref(_data,"reg ptr unrefed from del in SCHED_REPLACE"),
+								registry_unref(r,"reg ptr unrefed from add failure in SCHED_REPLACE"),
+								registry_addref(r,"reg ptr reffed from add in SCHED_REPLACE"));
 		ast_debug(1, "Scheduled a registration timeout for %s id  #%d \n", r->hostname, r->timeout);
 	}
 
@@ -15484,7 +15435,6 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 	add_header(&req, "To", to);
 	add_header(&req, "Call-ID", p->callid);
 	add_header(&req, "CSeq", tmp);
-	add_supported(p, &req);
 	if (!ast_strlen_zero(global_useragent))
 		add_header(&req, "User-Agent", global_useragent);
 
@@ -15517,6 +15467,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 	}
 
 	add_expires(&req, r->expiry);
+	build_contact(p, &req, 0);
 	add_header(&req, "Contact", p->our_contact);
 
 	initialize_initreq(p, &req);
@@ -15565,6 +15516,9 @@ static int sip_refer_alloc(struct sip_pvt *p)
 static void sip_refer_destroy(struct sip_pvt *p)
 {
 	if (p->refer) {
+		if (p->refer->refer_call) {
+			p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
+		}
 		ast_string_field_free_memory(p->refer);
 		ast_free(p->refer);
 		p->refer = NULL;
@@ -15697,7 +15651,7 @@ static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *dec
 static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration)
 {
 	struct sip_request req;
-
+	
 	reqprep(&req, p, SIP_INFO, 0, 1);
 	add_digit(&req, digit, duration, (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_SHORTINFO));
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
@@ -15707,7 +15661,7 @@ static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigne
 static int transmit_info_with_vidupdate(struct sip_pvt *p)
 {
 	struct sip_request req;
-
+	
 	reqprep(&req, p, SIP_INFO, 0, 1);
 	add_vidupdate(&req);
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
@@ -15719,7 +15673,7 @@ static int transmit_info_with_vidupdate(struct sip_pvt *p)
 static int transmit_request(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch)
 {
 	struct sip_request resp;
-
+	
 	reqprep(&resp, p, sipmethod, seqno, newbranch);
 	if (sipmethod == SIP_CANCEL && p->answered_elsewhere) {
 		add_header(&resp, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
@@ -15751,7 +15705,7 @@ void sip_auth_headers(enum sip_auth_type code, char **header, char **respheader)
 static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch)
 {
 	struct sip_request resp;
-
+	
 	reqprep(&resp, p, sipmethod, seqno, newbranch);
 	if (!ast_strlen_zero(p->realm)) {
 		char digest[1024];
@@ -15793,7 +15747,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t
 		break;
 	}
 
-	return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
+	return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);	
 }
 
 /*! \brief Remove registration data from realtime database or AST/DB when registration expires */
@@ -15804,10 +15758,9 @@ static void destroy_association(struct sip_peer *peer)
 
 	if (!sip_cfg.ignore_regexpire) {
 		if (peer->rt_fromcontact && sip_cfg.peer_rtupdate) {
-			ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL);
+			ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "0", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL);
 		} else {
 			ast_db_del("SIP/Registry", peer->name);
-			ast_db_del("SIP/RegistryPath", peer->name);
 			ast_db_del("SIP/PeerMethods", peer->name);
 		}
 	}
@@ -15852,14 +15805,7 @@ static int expire_register(const void *data)
 		peer->socket.ws_session = NULL;
 	}
 
-	if (peer->endpoint) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-		ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_OFFLINE);
-		blob = ast_json_pack("{s: s, s: s}",
-			"peer_status", "Unregistered",
-			"cause", "Expired");
-		ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-	}
+	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
 	register_peer_exten(peer, FALSE);	/* Remove regexten */
 	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
 
@@ -15915,11 +15861,21 @@ static int sip_poke_peer_s(const void *data)
 	return 0;
 }
 
+static int sip_poke_peer_now(const void *data)
+{
+	struct sip_peer *peer = (struct sip_peer *) data;
+
+	peer->pokeexpire = -1;
+	sip_poke_peer(peer, 0);
+	sip_unref_peer(peer, "removing poke peer ref");
+
+	return 0;
+}
+
 /*! \brief Get registration details from Asterisk DB */
 static void reg_source_db(struct sip_peer *peer)
 {
 	char data[256];
-	char path[SIPBUFSIZE * 2];
 	struct ast_sockaddr sa;
 	int expire;
 	char full_addr[128];
@@ -15978,9 +15934,6 @@ static void reg_source_db(struct sip_peer *peer)
 			sip_unref_peer(peer, "remove registration ref"),
 			sip_ref_peer(peer, "add registration ref"));
 	register_peer_exten(peer, TRUE);
-	if (!ast_db_get("SIP/RegistryPath", peer->name, path, sizeof(path))) {
-		build_path(NULL, peer, NULL, path);
-	}
 }
 
 /*! \brief Save contact header for 200 OK on INVITE */
@@ -16001,7 +15954,7 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
 
 	/* We should return false for URI:s we can't handle,
 		like tel:, mailto:,ldap: etc */
-	return TRUE;
+	return TRUE;		
 }
 
 /*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
@@ -16032,7 +15985,7 @@ static int __set_address_from_contact(const char *fullcontact, struct ast_sockad
 	ast_copy_string(contact_buf, fullcontact, sizeof(contact_buf));
 	contact = contact_buf;
 
-	/*
+	/* 
 	 * We have only the part in <brackets> here so we just need to parse a SIP URI.
 	 *
 	 * Note: The outbound proxy could be using UDP between the proxy and Asterisk.
@@ -16068,7 +16021,7 @@ static int __set_address_from_contact(const char *fullcontact, struct ast_sockad
 	if (!ast_sockaddr_port(addr)) {
 		ast_sockaddr_set_port(addr,
 				      (get_transport_str2enum(transport) ==
-				       AST_TRANSPORT_TLS ||
+				       SIP_TRANSPORT_TLS ||
 				       !strncasecmp(fullcontact, "sips", 4)) ?
 				      STANDARD_TLS_PORT : STANDARD_SIP_PORT);
 	}
@@ -16087,7 +16040,7 @@ static int set_address_from_contact(struct sip_pvt *pvt)
 		return 0;
 	}
 
-	return __set_address_from_contact(pvt->fullcontact, &pvt->sa, pvt->socket.type == AST_TRANSPORT_TLS ? 1 : 0);
+	return __set_address_from_contact(pvt->fullcontact, &pvt->sa, pvt->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);
 }
 
 /*! \brief Parse contact header and save registration (peer registration) */
@@ -16206,7 +16159,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
 		ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
 	}
 
-	if ((transport_type != AST_TRANSPORT_WS) && (transport_type != AST_TRANSPORT_WSS) &&
+	if ((transport_type != SIP_TRANSPORT_WS) && (transport_type != SIP_TRANSPORT_WSS) &&
 	    (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT))) {
 		/* use the data provided in the Contact header for call routing */
 		ast_debug(1, "Store REGISTER's Contact header for call routing.\n");
@@ -16277,32 +16230,12 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
 			sip_unref_peer(peer, "remote registration ref");
 		}
 	}
-	if (!build_path(pvt, peer, req, NULL)) {
-		/* Tell the dialog to use the Path header in the response */
-		ast_set2_flag(&pvt->flags[0], 1, SIP_USEPATH);
-	}
 	snprintf(data, sizeof(data), "%s:%d:%s:%s", ast_sockaddr_stringify(&peer->addr),
 		 expire, peer->username, peer->fullcontact);
 	/* We might not immediately be able to reconnect via TCP, but try caching it anyhow */
-	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate) {
-		if (!sip_route_empty(&peer->path)) {
-			struct ast_str *r = sip_route_list(&peer->path, 0, 0);
-			if (r) {
-				ast_db_put("SIP/RegistryPath", peer->name, ast_str_buffer(r));
-				ast_free(r);
-			}
-		}
+	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate)
 		ast_db_put("SIP/Registry", peer->name, data);
-	}
-
-	if (peer->endpoint) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-		ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
-		blob = ast_json_pack("{s: s, s: s}",
-			"peer_status", "Registered",
-			"address", ast_sockaddr_stringify(&peer->addr));
-		ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-	}
+	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name,  ast_sockaddr_stringify(&peer->addr));
 
 	/* Is this a new IP address for us? */
 	if (ast_sockaddr_cmp(&peer->addr, &oldsin)) {
@@ -16323,26 +16256,48 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
 	return PARSE_REGISTER_UPDATE;
 }
 
-/*! \brief Build route list from Record-Route header
- *
- * \param p
- * \param req
- * \param backwards
- * \param resp the SIP response code or 0 for a request
- *
- */
+/*! \brief Remove route from route list */
+static void free_old_route(struct sip_route *route)
+{
+	struct sip_route *next;
+
+	while (route) {
+		next = route->next;
+		ast_free(route);
+		route = next;
+	}
+}
+
+/*! \brief List all routes - mostly for debugging */
+static void list_route(struct sip_route *route)
+{
+	if (!route) {
+		ast_verbose("list_route: no route\n");
+	} else {
+		for (;route; route = route->next)
+			ast_verbose("list_route: hop: <%s>\n", route->hop);
+	}
+}
+
+/*! \brief Build route list from Record-Route header 
+    \param resp the SIP response code or 0 for a request */
 static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp)
 {
+	struct sip_route *thishop, *head, *tail;
 	int start = 0;
-	const char *header;
+	int len;
+	const char *rr, *c;
 
 	/* Once a persistent route is set, don't fool with it */
-	if (!sip_route_empty(&p->route) && p->route_persistent) {
-		ast_debug(1, "build_route: Retaining previous route: <%s>\n", sip_route_first_uri(&p->route));
+	if (p->route && p->route_persistent) {
+		ast_debug(1, "build_route: Retaining previous route: <%s>\n", p->route->hop);
 		return;
 	}
 
-	sip_route_clear(&p->route);
+	if (p->route) {
+		free_old_route(p->route);
+		p->route = NULL;
+	}
 
 	/* We only want to create the route set the first time this is called except
 	   it is called from a provisional response.*/
@@ -16355,76 +16310,96 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
 	 * in reverse order. However, we do need to maintain a correct
 	 * tail pointer because the contact is always at the end.
 	 */
+	head = NULL;
+	tail = head;
 	/* 1st we pass through all the hops in any Record-Route headers */
 	for (;;) {
-		header = __get_header(req, "Record-Route", &start);
-		if (*header == '\0') {
+		/* Each Record-Route header */
+		int len = 0;
+		const char *uri;
+		rr = __get_header(req, "Record-Route", &start);
+		if (*rr == '\0') {
 			break;
 		}
-		sip_route_process_header(&p->route, header, backwards);
+		while (!get_in_brackets_const(rr, &uri, &len)) {
+			len++;
+			rr = strchr(rr, ',');
+			if(rr >= uri && rr < (uri + len)) {
+				/* comma inside brackets*/
+				const char *next_br = strchr(rr, '<');
+				if (next_br && next_br < (uri + len)) {
+					rr++;
+					continue;
+				}
+				continue;
+			}
+			if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
+				ast_copy_string(thishop->hop, uri, len);
+				ast_debug(2, "build_route: Record-Route hop: <%s>\n", thishop->hop);
+				/* Link in */
+				if (backwards) {
+					/* Link in at head so they end up in reverse order */
+					thishop->next = head;
+					head = thishop;
+					/* If this was the first then it'll be the tail */
+					if (!tail) {
+						tail = thishop;
+					}
+				} else {
+					thishop->next = NULL;
+					/* Link in at the end */
+					if (tail) {
+						tail->next = thishop;
+					} else {
+						head = thishop;
+					}
+					tail = thishop;
+				}
+			}
+			rr = strchr(uri + len, ',');
+			if (rr == NULL) {
+				/* No more field-values, we're done with this header */
+				break;
+			}
+			/* Advance past comma */
+			rr++;
+		}
 	}
 
-	/* Only append the contact if we are dealing with a strict router or have no route */
-	if (sip_route_empty(&p->route) || sip_route_is_strict(&p->route)) {
+	/* Only append the contact if we are dealing with a strict router */
+	if (!head || (!ast_strlen_zero(head->hop) && strstr(head->hop, ";lr") == NULL) ) {
 		/* 2nd append the Contact: if there is one */
 		/* Can be multiple Contact headers, comma separated values - we just take the first */
-		int len;
-		header = sip_get_header(req, "Contact");
-		if (strchr(header, '<')) {
-			get_in_brackets_const(header, &header, &len);
-		} else {
-			len = strlen(header);
-		}
-		if (header && len) {
-			sip_route_add(&p->route, header, len, 0);
-		}
-	}
-
-	/* For debugging dump what we ended up with */
-	if (sip_debug_test_pvt(p)) {
-		sip_route_dump(&p->route);
-	}
-}
-
-/*! \brief Build route list from Path header
- *  RFC 3327 requires that the Path header contains SIP URIs with lr paramter.
- *  Thus, we do not care about strict routing SIP routers
- */
-static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, const char *pathbuf)
-{
-	sip_route_clear(&peer->path);
-
-	if (!ast_test_flag(&peer->flags[0], SIP_USEPATH)) {
-		ast_debug(2, "build_path: do not use Path headers\n");
-		return -1;
-	}
-	ast_debug(2, "build_path: try to build pre-loaded route-set by parsing Path headers\n");
-
-	if (req) {
-		int start = 0;
-		const char *header;
-		for (;;) {
-			header = __get_header(req, "Path", &start);
-			if (*header == '\0') {
-				break;
+		char *contact = ast_strdupa(sip_get_header(req, "Contact"));
+		if (!ast_strlen_zero(contact)) {
+			ast_debug(2, "build_route: Contact hop: %s\n", contact);
+			/* Look for <: delimited address */
+			c = get_in_brackets(contact);
+			len = strlen(c) + 1;
+			if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
+				/* ast_calloc is not needed because all fields are initialized in this block */
+				ast_copy_string(thishop->hop, c, len);
+				thishop->next = NULL;
+				/* Goes at the end */
+				if (tail) {
+					tail->next = thishop;
+				} else {
+					head = thishop;
+				}
 			}
-			sip_route_process_header(&peer->path, header, 0);
 		}
-	} else if (pathbuf) {
-		sip_route_process_header(&peer->path, pathbuf, 0);
 	}
 
-	/* Caches result for any dialog->route copied from peer->path */
-	sip_route_is_strict(&peer->path);
+	/* Store as new route */
+	p->route = head;
 
 	/* For debugging dump what we ended up with */
-	if (p && sip_debug_test_pvt(p)) {
-		sip_route_dump(&peer->path);
+	if (sip_debug_test_pvt(p)) {
+		list_route(p->route);
 	}
-	return 0;
 }
 
-/*! \brief builds the sip_pvt's nonce field which is used for the authentication
+/*! \brief builds the sip_pvt's nonce field which is used for the authentication 
  *  challenge.  When forceupdate is not set, the nonce is only updated if
  *  the current one is stale.  In this case, a stalenonce is one which
  *  has already received a response, if a nonce has not received a response
@@ -16658,70 +16633,57 @@ static void sip_peer_hold(struct sip_pvt *p, int hold)
 }
 
 /*! \brief Receive MWI events that we have subscribed to */
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
-	char *peer_name = userdata;
-	struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0);
+	struct sip_peer *peer = userdata;
 
-	if (stasis_subscription_final_message(sub, msg)) {
-		if (peer) {
-			/* configuration reloaded */
-			return;
-		}
-		ast_free(peer_name);
-		return;
-	}
-	if (peer && ast_mwi_state_type() == stasis_message_type(msg)) {
-		sip_send_mwi_to_peer(peer, 0);
-	}
-	ao2_cleanup(peer);
+	sip_send_mwi_to_peer(peer, 0);
 }
 
-static void network_change_stasis_subscribe(void)
+static void network_change_event_subscribe(void)
 {
-	if (!network_change_sub) {
-		network_change_sub = stasis_subscribe(ast_system_topic(),
-			network_change_stasis_cb, NULL);
+	if (!network_change_event_subscription) {
+		network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+			network_change_event_cb, "SIP Network Change", NULL, AST_EVENT_IE_END);
 	}
 }
 
-static void network_change_stasis_unsubscribe(void)
+static void network_change_event_unsubscribe(void)
 {
-	network_change_sub = stasis_unsubscribe_and_join(network_change_sub);
+	if (network_change_event_subscription) {
+		network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+	}
 }
 
-static void acl_change_stasis_subscribe(void)
+static void acl_change_event_subscribe(void)
 {
-	if (!acl_change_sub) {
-		acl_change_sub = stasis_subscribe(ast_security_topic(),
-			acl_change_stasis_cb, NULL);
+	if (!acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_subscribe(AST_EVENT_ACL_CHANGE,
+		acl_change_event_cb, "Manager must react to Named ACL changes", NULL, AST_EVENT_IE_END);
 	}
 
 }
 
-static void acl_change_event_stasis_unsubscribe(void)
+static void acl_change_event_unsubscribe(void)
 {
-	acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
+	if (acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_unsubscribe(acl_change_event_subscription);
+	}
 }
 
-static int network_change_sched_cb(const void *data)
+static int network_change_event_sched_cb(const void *data)
 {
-	network_change_sched_id = -1;
+	network_change_event_sched_id = -1;
 	sip_send_all_registers();
 	sip_send_all_mwi_subscriptions();
 	return 0;
 }
 
-static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
 {
-	/* This callback is only concerned with network change messages from the system topic. */
-	if (stasis_message_type(message) != ast_network_change_type()) {
-		return;
-	}
-
-	ast_verb(1, "SIP, got a network change message, renewing all SIP registrations.\n");
-	if (network_change_sched_id == -1) {
-		network_change_sched_id = ast_sched_add(sched, 1000, network_change_sched_cb, NULL);
+	ast_debug(1, "SIP, got a network change event, renewing all SIP registrations.\n");
+	if (network_change_event_sched_id == -1) {
+		network_change_event_sched_id = ast_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
 	}
 }
 
@@ -16962,9 +16924,7 @@ static void extract_host_from_hostport(char **hostport)
 	ast_sockaddr_split_hostport(*hostport, hostport, &dont_care, PARSE_PORT_IGNORE);
 }
 
-/*!
- * \internal
- * \brief Helper function to update a peer's lastmsgssent value
+/*! \internal \brief Helper function to update a peer's lastmsgssent value
  */
 static void update_peer_lastmsgssent(struct sip_peer *peer, int value, int locked)
 {
@@ -16978,16 +16938,13 @@ static void update_peer_lastmsgssent(struct sip_peer *peer, int value, int locke
 }
 
 
-/*!
- * \brief Verify registration of user
- *
- * \details
- * - Registration is done in several steps, first a REGISTER without auth
- *   to get a challenge (nonce) then a second one with auth
- * - Registration requests are only matched with peers that are marked as "dynamic"
+/*! \brief Verify registration of user
+	- Registration is done in several steps, first a REGISTER without auth
+	  to get a challenge (nonce) then a second one with auth
+	- Registration requests are only matched with peers that are marked as "dynamic"
  */
 static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
-	struct sip_request *req, const char *uri)
+					      struct sip_request *req, const char *uri)
 {
 	enum check_auth_result res = AUTH_NOT_FOUND;
 	struct sip_peer *peer;
@@ -17046,7 +17003,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 	}
 
 	ast_string_field_set(p, exten, name);
-	build_contact(p);
+	build_contact(p, req, 1);
 	if (req->ignore) {
 		/* Expires is a special case, where we only want to load the peer if this isn't a deregistration attempt */
 		const char *expires = sip_get_header(req, "Expires");
@@ -17172,14 +17129,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 				ast_string_field_set(p, fullcontact, peer->fullcontact);
 				/* Say OK and ask subsystem to retransmit msg counter */
 				transmit_response_with_date(p, "200 OK", req);
-				if (peer->endpoint) {
-					RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-					ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
-					blob = ast_json_pack("{s: s, s: s}",
-						"peer_status", "Registered",
-						"address", ast_sockaddr_stringify(addr));
-					ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-				}
+				manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(addr));
 				send_mwi = 1;
 				res = 0;
 				break;
@@ -17198,8 +17148,6 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 		ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
 	}
 	if (res < 0) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
 		switch (res) {
 		case AUTH_SECRET_FAILED:
 			/* Wrong password in authentication. Go away, don't try again until you fixed it */
@@ -17207,12 +17155,14 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 			if (global_authfailureevents) {
 				const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 				const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
-
-				blob = ast_json_pack("{s: s, s: s, s: s, s: s}",
-					"peer_status", "Rejected",
-					"cause", "AUTH_SECRET_FAILED",
-					"address", peer_addr,
-					"port", peer_port);
+				manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
+					      "ChannelType: SIP\r\n"
+					      "Peer: SIP/%s\r\n"
+					      "PeerStatus: Rejected\r\n"
+					      "Cause: AUTH_SECRET_FAILED\r\n"
+					      "Address: %s\r\n"
+					      "Port: %s\r\n",
+					      name, peer_addr, peer_port);
 			}
 			break;
 		case AUTH_USERNAME_MISMATCH:
@@ -17228,12 +17178,16 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 				if (global_authfailureevents) {
 					const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 					const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
-
-					blob = ast_json_pack("{s: s, s: s, s: s, s: s}",
-						"peer_status", "Rejected",
-						"cause", res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND",
-						"address", peer_addr,
-						"port", peer_port);
+					manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
+						      "ChannelType: SIP\r\n"
+						      "Peer: SIP/%s\r\n"
+						      "PeerStatus: Rejected\r\n"
+						      "Cause: %s\r\n"
+						      "Address: %s\r\n"
+						      "Port: %s\r\n",
+						      name,
+						      res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND",
+						      peer_addr, peer_port);
 				}
 			} else {
 				/* URI not found */
@@ -17242,24 +17196,30 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 					if (global_authfailureevents) {
 						const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 						const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
-
-						blob = ast_json_pack("{s: s, s: s, s: s, s: s}",
-							"peer_status", "Rejected",
-							"cause", "AUTH_PEER_NOT_DYNAMIC",
-							"address", peer_addr,
-							"port", peer_port);
+						manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
+							"ChannelType: SIP\r\n"
+							"Peer: SIP/%s\r\n"
+							"PeerStatus: Rejected\r\n"
+							"Cause: AUTH_PEER_NOT_DYNAMIC\r\n"
+							"Address: %s\r\n"
+							"Port: %s\r\n",
+							name, peer_addr, peer_port);
 					}
 				} else {
 					transmit_response(p, "404 Not found", &p->initreq);
 					if (global_authfailureevents) {
 						const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 						const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
-
-						blob = ast_json_pack("{s: s, s: s, s: s, s: s}",
-							"peer_status", "Rejected",
-							"cause", (res == AUTH_USERNAME_MISMATCH) ? "AUTH_USERNAME_MISMATCH" : "URI_NOT_FOUND",
-							"address", peer_addr,
-							"port", peer_port);
+						manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
+							"ChannelType: SIP\r\n"
+							"Peer: SIP/%s\r\n"
+							"PeerStatus: Rejected\r\n"
+							"Cause: %s\r\n"
+							"Address: %s\r\n"
+							"Port: %s\r\n",
+							name,
+							(res == AUTH_USERNAME_MISMATCH) ? "AUTH_USERNAME_MISMATCH" : "URI_NOT_FOUND",
+							peer_addr, peer_port);
 					}
 				}
 			}
@@ -17268,10 +17228,6 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 		default:
 			break;
 		}
-
-		if (peer && peer->endpoint) {
-			ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-		}
 	}
 	if (peer) {
 		sip_unref_peer(peer, "register_verify: sip_unref_peer: tossing stack peer pointer at end of func");
@@ -17358,7 +17314,7 @@ static int get_pai(struct sip_pvt *p, struct sip_request *req)
 	if (!cid_name) {
 		no_name = 1;
 		cid_name = (char *)emptyname;
-	}
+	}	
 	/* Only return true if the supplied caller id is different */
 	if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres) {
 		do_update = 0;
@@ -17506,19 +17462,8 @@ static int get_rpid(struct sip_pvt *p, struct sip_request *oreq)
 	return 1;
 }
 
-/*! \brief Get referring dnis
- *
- * \param p dialog information
- * \param oreq The request to retrieve RDNIS from
- * \param[out] name The name of the party redirecting the call.
- * \param[out] number The number of the party redirecting the call.
- * \param[out] reason_code The numerical code corresponding to the reason for the redirection.
- * \param[out] reason_str A string describing the reason for redirection. Will never be zero-length
- *
- * \retval -1 Could not retrieve RDNIS information
- * \retval 0 RDNIS successfully retrieved
- */
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason_code, char **reason_str)
+/*! \brief Get referring dnis */
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason)
 {
 	char tmp[256], *exten, *rexten, *rdomain, *rname = NULL;
 	char *params, *reason_param = NULL;
@@ -17575,9 +17520,9 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
 	if (p->owner)
 		pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain);
 
-	if (sip_debug_test_pvt(p)) {
+	if (sip_debug_test_pvt(p))
 		ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, S_OR(reason_param, ""));
-	}
+
 	/*ast_string_field_set(p, rdnis, rexten);*/
 
 	if (*tmp == '\"') {
@@ -17597,14 +17542,8 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
 		*name = ast_strdup(rname);
 	}
 
-	if (!ast_strlen_zero(reason_param)) {
-		if (reason_code) {
-			*reason_code = sip_reason_str_to_code(reason_param);
-		}
-
-		if (reason_str) {
-			*reason_str = ast_strdup(reason_param);
-		}
+	if (reason && !ast_strlen_zero(reason_param)) {
+		*reason = sip_reason_str_to_code(reason_param);
 	}
 
 	return 0;
@@ -17631,16 +17570,6 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 	char *from = NULL;
 	struct sip_request *req;
 	char *decoded_uri;
-	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, ast_get_chan_features_pickup_config(p->owner), ao2_cleanup);
-	const char *pickupexten;
-
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-		pickupexten = "";
-	} else {
-		/* Don't need to duplicate since channel is locked for the duration of this function */
-		pickupexten = pickup_cfg->pickupexten;
-	}
 
 	req = oreq;
 	if (!req) {
@@ -17654,7 +17583,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 
 	uri = ast_strdupa(get_in_brackets(tmp));
 
-	if (parse_uri_legacy_check(uri, "sip:,sips:,tel:", &uri, &unused_password, &domain, NULL)) {
+	if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &unused_password, &domain, NULL)) {
 		ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
 		return SIP_GET_DEST_INVALID_URI;
 	}
@@ -17664,12 +17593,6 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 
 	extract_host_from_hostport(&domain);
 
-	if (strncasecmp(get_in_brackets(tmp), "tel:", 4)) {
-		ast_string_field_set(p, domain, domain);
-	} else {
-		ast_string_field_set(p, tel_phone_context, domain);
-	}
-
 	if (ast_strlen_zero(uri)) {
 		/*
 		 * Either there really was no extension found or the request
@@ -17679,6 +17602,8 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 		uri = "s";
 	}
 
+	ast_string_field_set(p, domain, domain);
+
 	/* Now find the From: caller ID and name */
 	/* XXX Why is this done in get_destination? Isn't it already done?
 	   Needs to be checked
@@ -17686,7 +17611,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 	tmpf = ast_strdup(sip_get_header(req, "From"));
 	if (!ast_strlen_zero(tmpf)) {
 		from = get_in_brackets(tmpf);
-		if (parse_uri_legacy_check(from, "sip:,sips:,tel:", &from, NULL, &domain, NULL)) {
+		if (parse_uri_legacy_check(from, "sip:,sips:", &from, NULL, &domain, NULL)) {
 			ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from);
 			return SIP_GET_DEST_INVALID_URI;
 		}
@@ -17755,7 +17680,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 			return SIP_GET_DEST_EXTEN_FOUND;
 		}
 		if (ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))
-			|| !strcmp(decoded_uri, pickupexten)) {
+			|| !strcmp(decoded_uri, ast_pickup_ext())) {
 			if (!oreq) {
 				ast_string_field_set(p, exten, decoded_uri);
 			}
@@ -17783,7 +17708,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 	if (ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP)
 		&& (ast_canmatch_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from))
 			|| ast_canmatch_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))
-			|| !strncmp(decoded_uri, pickupexten, strlen(decoded_uri)))) {
+			|| !strncmp(decoded_uri, ast_pickup_ext(), strlen(decoded_uri)))) {
 		/* Overlap dialing is enabled and we need more digits to match an extension. */
 		return SIP_GET_DEST_EXTEN_MATCHMORE;
 	}
@@ -17791,25 +17716,10 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
 	return SIP_GET_DEST_EXTEN_NOT_FOUND;
 }
 
-/*! \brief Find a companion dialog based on Replaces information
- *
- * This information may come from a Refer-To header in a REFER or from
- * a Replaces header in an INVITE.
- *
- * This function will find the appropriate sip_pvt and increment the refcount
- * of both the sip_pvt and its owner channel. These two references are returned
- * in the out parameters
- *
- * \param callid Callid to search for
- * \param totag to-tag parameter from Replaces
- * \param fromtag from-tag parameter from Replaces
- * \param[out] out_pvt The found sip_pvt.
- * \param[out] out_chan The found sip_pvt's owner channel.
- * \retval 0 Success
- * \retval non-zero Failure
- */
-static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
-		const char *fromtag, struct sip_pvt **out_pvt, struct ast_channel **out_chan)
+/*! \brief Lock dialog lock and find matching pvt lock
+	\return a reference, remember to release it when done
+*/
+static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag)
 {
 	struct sip_pvt *sip_pvt_ptr;
 	struct sip_pvt tmp_dialog = {
@@ -17825,20 +17735,22 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
 	sip_pvt_ptr = ao2_t_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find of dialog in dialogs table");
 	if (sip_pvt_ptr) {
 		/* Go ahead and lock it (and its owner) before returning */
-		SCOPED_LOCK(lock, sip_pvt_ptr, sip_pvt_lock, sip_pvt_unlock);
+		sip_pvt_lock(sip_pvt_ptr);
 		if (sip_cfg.pedanticsipchecking) {
 			unsigned char frommismatch = 0, tomismatch = 0;
 
 			if (ast_strlen_zero(fromtag)) {
+				sip_pvt_unlock(sip_pvt_ptr);
 				ast_debug(4, "Matched %s call for callid=%s - no from tag specified, pedantic check fails\n",
 					  sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid);
-				return -1;
+				return NULL;
 			}
 
 			if (ast_strlen_zero(totag)) {
+				sip_pvt_unlock(sip_pvt_ptr);
 				ast_debug(4, "Matched %s call for callid=%s - no to tag specified, pedantic check fails\n",
 					  sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid);
-				return -1;
+				return NULL;
 			}
 			/* RFC 3891
 			 * > 3.  User Agent Server Behavior: Receiving a Replaces Header
@@ -17857,10 +17769,11 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
 			frommismatch = !!strcmp(fromtag, sip_pvt_ptr->theirtag);
 			tomismatch = !!strcmp(totag, sip_pvt_ptr->tag);
 
-			/* Don't check from if the dialog is not established, due to multi forking the from
-			 * can change when the call is not answered yet.
-			 */
+                        /* Don't check from if the dialog is not established, due to multi forking the from
+                         * can change when the call is not answered yet.
+                         */
 			if ((frommismatch && ast_test_flag(&sip_pvt_ptr->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) || tomismatch) {
+				sip_pvt_unlock(sip_pvt_ptr);
 				if (frommismatch) {
 					ast_debug(4, "Matched %s call for callid=%s - pedantic from tag check fails; their tag is %s our tag is %s\n",
 						  sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid,
@@ -17871,7 +17784,7 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
 						  sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid,
 						  totag, sip_pvt_ptr->tag);
 				}
-				return -1;
+				return NULL;
 			}
 		}
 
@@ -17880,13 +17793,15 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
 					  sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING",
 					  sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
 
-		*out_pvt = sip_pvt_ptr;
-		if (out_chan) {
-			*out_chan = sip_pvt_ptr->owner ? ast_channel_ref(sip_pvt_ptr->owner) : NULL;
+		/* deadlock avoidance... */
+		while (sip_pvt_ptr->owner && ast_channel_trylock(sip_pvt_ptr->owner)) {
+			sip_pvt_unlock(sip_pvt_ptr);
+			usleep(1);
+			sip_pvt_lock(sip_pvt_ptr);
 		}
 	}
-
-	return 0;
+	
+	return sip_pvt_ptr;
 }
 
 /*! \brief Call transfer support (the REFER method)
@@ -17937,31 +17852,10 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi
 
 	/* Give useful transfer information to the dialplan */
 	if (transferer->owner) {
-		RAII_VAR(struct ast_channel *, peer, NULL, ast_channel_cleanup);
-		RAII_VAR(struct ast_channel *, owner_relock, NULL, ast_channel_cleanup);
-		RAII_VAR(struct ast_channel *, owner_ref, NULL, ast_channel_cleanup);
-
-		/* Grab a reference to transferer->owner to prevent it from going away */
-		owner_ref = ast_channel_ref(transferer->owner);
-
-		/* Established locking order here is bridge, channel, pvt
-		 * and the bridge will be locked during ast_channel_bridge_peer */
-		ast_channel_unlock(owner_ref);
-		sip_pvt_unlock(transferer);
-
-		peer = ast_channel_bridge_peer(owner_ref);
+		struct ast_channel *peer = ast_bridged_channel(transferer->owner);
 		if (peer) {
-			pbx_builtin_setvar_helper(peer, "SIPREFERRINGCONTEXT",
-				S_OR(transferer->context, NULL));
-			pbx_builtin_setvar_helper(peer, "__SIPREFERREDBYHDR",
-				S_OR(p_referred_by, NULL));
-			ast_channel_unlock(peer);
-		}
-
-		owner_relock = sip_pvt_lock_full(transferer);
-		if (!owner_relock) {
-			ast_debug(3, "Unable to reacquire owner channel lock, channel is gone\n");
-			return -5;
+			pbx_builtin_setvar_helper(peer, "SIPREFERRINGCONTEXT", transferer->context);
+			pbx_builtin_setvar_helper(peer, "SIPREFERREDBYHDR", p_referred_by);
 		}
 	}
 
@@ -17999,7 +17893,7 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi
 			to = strcasestr(ptr, "to-tag=");
 			from = strcasestr(ptr, "from-tag=");
 		}
-
+		
 		/* Grab the to header */
 		if (to) {
 			ptr = to + 7;
@@ -18103,7 +17997,7 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi
 	/* Either an existing extension or the parking extension */
 	if (refer->attendedtransfer || ast_exists_extension(NULL, transfer_context, refer_to, 1, NULL)) {
 		if (sip_debug_test_pvt(transferer)) {
-			ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, S_OR(referred_by_uri, "Unknown"));
+			ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, referred_by_uri);
 		}
 		/* We are ready to transfer to the extension */
 		return 0;
@@ -18335,7 +18229,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 		if (!peer) {
 			char *uri_tmp, *callback = NULL, *dummy;
 			uri_tmp = ast_strdupa(uri2);
-			parse_uri(uri_tmp, "sip:,sips:,tel:", &callback, &dummy, &dummy, &dummy);
+			parse_uri(uri_tmp, "sip:,sips:", &callback, &dummy, &dummy, &dummy);
 			if (!ast_strlen_zero(callback) && (peer = sip_find_peer_by_ip_and_exten(&p->recv, callback, p->socket.type))) {
 				; /* found, fall through */
 			} else {
@@ -18386,9 +18280,10 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 			peer->name, of, ast_sockaddr_stringify(&p->recv));
 	}
 
+	/* XXX what about p->prefs = peer->prefs; ? */
 	/* Set Frame packetization */
 	if (p->rtp) {
-		ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(peer->caps));
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
 		p->autoframing = peer->autoframing;
 	}
 
@@ -18505,22 +18400,20 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 		p->named_callgroups = ast_ref_namedgroups(peer->named_callgroups);
 		ast_unref_namedgroups(p->named_pickupgroups);
 		p->named_pickupgroups = ast_ref_namedgroups(peer->named_pickupgroups);
-		ast_format_cap_remove_by_type(p->caps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(p->caps, peer->caps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(p->jointcaps, peer->caps, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(p->caps, peer->caps);
+		ast_format_cap_copy(p->jointcaps, peer->caps);
+		p->prefs = peer->prefs;
 		ast_copy_string(p->zone, peer->zone, sizeof(p->zone));
  		if (peer->maxforwards > 0) {
 			p->maxforwards = peer->maxforwards;
 		}
-		if (ast_format_cap_count(p->peercaps)) {
-			struct ast_format_cap *joint;
-
-			joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-			if (joint) {
-				ast_format_cap_get_compatible(p->jointcaps, p->peercaps, joint);
-				ao2_ref(p->jointcaps, -1);
-				p->jointcaps = joint;
+		if (!(ast_format_cap_is_empty(p->peercaps))) {
+			struct ast_format_cap *tmp = ast_format_cap_joint(p->jointcaps, p->peercaps);
+			struct ast_format_cap *tmp2;
+			if (tmp) {
+				tmp2 = p->jointcaps;
+				p->jointcaps = tmp;
+				ast_format_cap_destroy(tmp2);
 			}
 		}
 		p->maxcallbitrate = peer->maxcallbitrate;
@@ -18535,7 +18428,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 		p->rtpkeepalive = peer->rtpkeepalive;
 		if (!dialog_initialize_rtp(p)) {
 			if (p->rtp) {
-				ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(peer->caps));
+				ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
 				p->autoframing = peer->autoframing;
 			}
 		} else {
@@ -18580,20 +18473,18 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
 
 	if (ast_strlen_zero(p->exten)) {
 		char *t = uri2;
-		if (!strncasecmp(t, "sip:", 4)) {
-			t += 4;
-		} else if (!strncasecmp(t, "sips:", 5)) {
+		if (!strncasecmp(t, "sip:", 4))
+			t+= 4;
+		else if (!strncasecmp(t, "sips:", 5))
 			t += 5;
-		} else if (!strncasecmp(t, "tel:", 4)) {	/* TEL URI INVITE */
-			t += 4;
-		}
 		ast_string_field_set(p, exten, t);
 		t = strchr(p->exten, '@');
 		if (t)
 			*t = '\0';
 
-		if (ast_strlen_zero(p->our_contact))
-			build_contact(p);
+		if (ast_strlen_zero(p->our_contact)) {
+			build_contact(p, req, 1);
+		}
 	}
 
 	of = get_in_brackets(of);
@@ -18601,7 +18492,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
 	/* save the URI part of the From header */
 	ast_string_field_set(p, from, of);
 
-	if (parse_uri_legacy_check(of, "sip:,sips:,tel:", &name, &unused_password, &domain, NULL)) {
+	if (parse_uri_legacy_check(of, "sip:,sips:", &name, &unused_password, &domain, NULL)) {
 		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
 	}
 
@@ -18684,7 +18575,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
 }
 
 /*! \brief  Find user
-	If we get a match, this will add a reference pointer to the user object, that needs to be unreferenced
+	If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced
 */
 static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct ast_sockaddr *addr)
 {
@@ -18735,7 +18626,6 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
 	char *to;
 	char from_name[50];
 	char stripped[SIPBUFSIZE];
-	enum sip_get_dest_result dest_result;
 
 	if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */
 		transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
@@ -18845,8 +18735,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
 		ast_string_field_set(p, context, sip_cfg.messagecontext);
 	}
 
-	dest_result = get_destination(p, NULL, NULL);
-	switch (dest_result) {
+	switch (get_destination(p, NULL, NULL)) {
 	case SIP_GET_DEST_REFUSED:
 		/* Okay to send 403 since this is after auth processing */
 		transmit_response(p, "403 Forbidden", req);
@@ -18856,9 +18745,12 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
 		transmit_response(p, "416 Unsupported URI Scheme", req);
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 		return;
-	default:
-		/* We may have something other than dialplan who wants
-		 * the message, so defer further error handling for now */
+	case SIP_GET_DEST_EXTEN_NOT_FOUND:
+	case SIP_GET_DEST_EXTEN_MATCHMORE:
+		transmit_response(p, "404 Not Found", req);
+		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+		return;
+	case SIP_GET_DEST_EXTEN_FOUND:
 		break;
 	}
 
@@ -18889,9 +18781,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
 	res |= ast_msg_set_context(msg, "%s", p->context);
 
 	res |= ast_msg_set_var(msg, "SIP_RECVADDR", ast_sockaddr_stringify(&p->recv));
-	res |= ast_msg_set_tech(msg, "%s", "SIP");
 	if (!ast_strlen_zero(p->peername)) {
-		res |= ast_msg_set_endpoint(msg, "%s", p->peername);
 		res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername);
 	}
 
@@ -18904,32 +18794,12 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
 	if (res) {
 		ast_msg_destroy(msg);
 		transmit_response(p, "500 Internal Server Error", req);
-		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		return;
-	}
-
-	if (ast_msg_has_destination(msg)) {
+	} else {
 		ast_msg_queue(msg);
 		transmit_response(p, "202 Accepted", req);
-		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		return;
 	}
 
-	/* Find a specific error cause to send */
-	switch (dest_result) {
-	case SIP_GET_DEST_EXTEN_NOT_FOUND:
-	case SIP_GET_DEST_EXTEN_MATCHMORE:
-		transmit_response(p, "404 Not Found", req);
-		break;
-	case SIP_GET_DEST_EXTEN_FOUND:
-	default:
-		/* We should have sent the message already! */
-		ast_assert(0);
-		transmit_response(p, "500 Internal Server Error", req);
-		break;
-	}
 	sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-	ast_msg_destroy(msg);
 }
 
 /*! \brief  CLI Command to show calls within limits set by call_limit */
@@ -18942,7 +18812,7 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	int showall = FALSE;
 	struct ao2_iterator i;
 	struct sip_peer *peer;
-
+	
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "sip show inuse";
@@ -18960,7 +18830,7 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
 	if (a->argc == 4 && !strcmp(a->argv[3], "all"))
 		showall = TRUE;
-
+	
 	ast_cli(a->fd, FORMAT, "* Peer name", "In use", "Limit");
 
 	i = ao2_iterator_init(peers, 0);
@@ -19032,12 +18902,12 @@ static const struct _map_x_s strefreshers[] = {
         { -1,                           NULL   },
 };
 
-static const char *strefresherparam2str(enum st_refresher r)
+static const char *strefresherparam2str(enum st_refresher_param r)
 {
 	return map_x_s(strefresher_params, r, "Unknown");
 }
 
-static enum st_refresher str2strefresherparam(const char *s)
+static enum st_refresher_param str2strefresherparam(const char *s)
 {
 	return map_s_x(strefresher_params, s, -1);
 }
@@ -19200,18 +19070,14 @@ static int manager_show_registry(struct mansession *s, const struct message *m)
 	const char *id = astman_get_header(m, "ActionID");
 	char idtext[256] = "";
 	int total = 0;
-	struct ao2_iterator iter;
-	struct sip_registry *iterator;
 
 	if (!ast_strlen_zero(id))
 		snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
 
 	astman_send_listack(s, m, "Registrations will follow", "start");
 
-	iter = ao2_iterator_init(registry_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "manager_show_registry iter"))) {
-		ao2_lock(iterator);
-
+	ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
 		astman_append(s,
 			"Event: RegistryEntry\r\n"
 			"%s"
@@ -19233,12 +19099,9 @@ static int manager_show_registry(struct mansession *s, const struct message *m)
 			iterator->refresh,
 			regstate2str(iterator->regstate),
 			(long) iterator->regtime.tv_sec);
-
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "manager_show_registry iter");
+		ASTOBJ_UNLOCK(iterator);
 		total++;
-	}
-	ao2_iterator_destroy(&iter);
+	} while(0));
 
 	astman_append(s,
 		"Event: RegistrationsComplete\r\n"
@@ -19246,7 +19109,7 @@ static int manager_show_registry(struct mansession *s, const struct message *m)
 		"ListItems: %d\r\n"
 		"%s"
 		"\r\n", total, idtext);
-
+	
 	return 0;
 }
 
@@ -19534,7 +19397,7 @@ static int peer_dump_func(void *userobj, void *arg, int flags)
 	struct sip_peer *peer = userobj;
 	int refc = ao2_t_ref(userobj, 0, "");
 	struct ast_cli_args *a = (struct ast_cli_args *) arg;
-
+	
 	ast_cli(a->fd, "name: %s\ntype: peer\nobjflags: %d\nrefcount: %d\n\n",
 		peer->name, 0, refc);
 	return 0;
@@ -19545,7 +19408,7 @@ static int dialog_dump_func(void *userobj, void *arg, int flags)
 	struct sip_pvt *pvt = userobj;
 	int refc = ao2_t_ref(userobj, 0, "");
 	struct ast_cli_args *a = (struct ast_cli_args *) arg;
-
+	
 	ast_cli(a->fd, "name: %s\ntype: dialog\nobjflags: %d\nrefcount: %d\n\n",
 		pvt->callid, 0, refc);
 	return 0;
@@ -19555,9 +19418,8 @@ static int dialog_dump_func(void *userobj, void *arg, int flags)
 /*! \brief List all allocated SIP Objects (realtime or static) */
 static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct sip_registry *reg;
-	struct ao2_iterator iter;
-
+	char tmp[256];
+	
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "sip show objects";
@@ -19567,25 +19429,16 @@ static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
-	}
+	}	
 
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
 	ast_cli(a->fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs);
 	ao2_t_callback(peers, OBJ_NODATA, peer_dump_func, a, "initiate ao2_callback to dump peers");
-	ast_cli(a->fd, "-= Peer objects by IP =-\n\n");
+	ast_cli(a->fd, "-= Peer objects by IP =-\n\n"); 
 	ao2_t_callback(peers_by_ip, OBJ_NODATA, peer_dump_func, a, "initiate ao2_callback to dump peers_by_ip");
-
-	iter = ao2_iterator_init(registry_list, 0);
-	ast_cli(a->fd, "-= Registry objects: %d =-\n\n", ao2_container_count(registry_list));
-	while ((reg = ao2_t_iterator_next(&iter, "sip_show_objects iter"))) {
-		ao2_lock(reg);
-		ast_cli(a->fd, "name: %s\n", reg->configvalue);
-		ao2_unlock(reg);
-		ao2_t_ref(reg, -1, "sip_show_objects iter");
-	}
-	ao2_iterator_destroy(&iter);
-
+	ast_cli(a->fd, "-= Registry objects: %d =-\n\n", regobjs);
+	ASTOBJ_CONTAINER_DUMP(a->fd, tmp, sizeof(tmp), &regl);
 	ast_cli(a->fd, "-= Dialog objects:\n\n");
 	ao2_t_callback(dialogs, OBJ_NODATA, dialog_dump_func, a, "initiate ao2_callback to dump dialogs");
 	return CLI_SUCCESS;
@@ -19676,21 +19529,20 @@ static void cleanup_stale_contexts(char *new, char *old)
 	char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
 
 	while ((oldcontext = strsep(&old, "&"))) {
-		stalecontext = '\0';
+		stalecontext = NULL;
 		ast_copy_string(newlist, new, sizeof(newlist));
 		stringp = newlist;
 		while ((newcontext = strsep(&stringp, "&"))) {
 			if (!strcmp(newcontext, oldcontext)) {
 				/* This is not the context you're looking for */
-				stalecontext = '\0';
+				stalecontext = NULL;
 				break;
 			} else if (strcmp(newcontext, oldcontext)) {
 				stalecontext = oldcontext;
 			}
-
+			
 		}
-		if (stalecontext)
-			ast_context_destroy(ast_context_find(stalecontext), "SIP");
+		ast_context_destroy_by_name(stalecontext, "SIP");
 	}
 }
 
@@ -19785,7 +19637,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
 	struct ao2_iterator i;
 	static const char * const choices[] = { "all", "like", NULL };
 	char *cmplt;
-
+	
 	if (cmd == CLI_INIT) {
 		e->command = "sip prune realtime [peer|all]";
 		e->usage =
@@ -19859,7 +19711,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
 	if (multi) {
 		if (prunepeer) {
 			int pruned = 0;
-
+			
 			i = ao2_iterator_init(peers, 0);
 			while ((pi = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
 				ao2_lock(pi);
@@ -19912,6 +19764,25 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
 	return CLI_SUCCESS;
 }
 
+/*! \brief Print codec list from preference to CLI/manager */
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
+{
+	int x;
+	struct ast_format codec;
+
+	for(x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+		if (!(ast_codec_pref_index(pref, x, &codec))) {
+			break;
+		}
+		ast_cli(fd, "%s", ast_getformatname(&codec));
+		ast_cli(fd, ":%d", pref->framing[x]);
+		if (x < 31 && ast_codec_pref_index(pref, x + 1, &codec))
+			ast_cli(fd, ",");
+	}
+	if (!x)
+		ast_cli(fd, "none");
+}
+
 /*! \brief Print domain mode to cli */
 static const char *domain_mode_to_text(const enum domain_mode mode)
 {
@@ -20082,21 +19953,6 @@ static int manager_sip_peer_status(struct mansession *s, const struct message *m
 	return 0;
 }
 
-static void publish_qualify_peer_done(const char *id, const char *peer)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-
-	if (ast_strlen_zero(id)) {
-		body = ast_json_pack("{s: s}", "Peer", peer);
-	} else {
-		body = ast_json_pack("{s: s, s: s}", "Peer", peer, "ActionID", id);
-	}
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("SIPQualifyPeerDone", EVENT_FLAG_CALL, body);
-}
 
 /*! \brief Send qualify message to peer from cli or manager. Mostly for debugging. */
 static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
@@ -20109,23 +19965,13 @@ static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const str
 
 	load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
 	if ((peer = sip_find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0))) {
-		const char *id = astman_get_header(m,"ActionID");
-
-		if (type != 0) {
-			astman_send_ack(s, m, "SIP peer found - will qualify");
-		}
-
 		sip_poke_peer(peer, 1);
-
-		publish_qualify_peer_done(id, argv[3]);
-
 		sip_unref_peer(peer, "qualify: done with peer");
 	} else if (type == 0) {
 		ast_cli(fd, "Peer '%s' not found\n", argv[3]);
 	} else {
 		astman_send_error(s, m, "Peer not found");
 	}
-
 	return CLI_SUCCESS;
 }
 
@@ -20146,6 +19992,7 @@ static int manager_sip_qualify_peer(struct mansession *s, const struct message *
 	a[3] = peer;
 
 	_sip_qualify_peer(1, -1, s, m, 4, a);
+	astman_append(s, "\r\n\r\n" );
 	return 0;
 }
 
@@ -20172,8 +20019,10 @@ static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer
 	struct sip_mailbox *mailbox;
 
 	AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
-		ast_str_append(mailbox_str, 0, "%s%s",
-			mailbox->id,
+		ast_str_append(mailbox_str, 0, "%s%s%s%s",
+			mailbox->mailbox,
+			ast_strlen_zero(mailbox->context) ? "" : "@",
+			S_OR(mailbox->context, ""),
 			AST_LIST_NEXT(mailbox, entry) ? "," : "");
 	}
 }
@@ -20196,9 +20045,11 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 	char status[30] = "";
 	char cbuf[256];
 	struct sip_peer *peer;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	char codec_buf[512];
+	struct ast_codec_pref *pref;
 	struct ast_variable *v;
 	int x = 0, load_realtime;
+	struct ast_format codec;
 	int realtimepeers;
 
 	realtimepeers = ast_check_realtime("sippeers");
@@ -20224,7 +20075,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 	}
 	if (peer && type==0 ) { /* Normal listing */
 		struct ast_str *mailbox_str = ast_str_alloca(512);
-		struct ast_str *path;
 		struct sip_auth_container *credentials;
 
 		ao2_lock(peer);
@@ -20265,7 +20115,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		ast_cli(fd, "  Tonezone     : %s\n", peer->zone[0] != '\0' ? peer->zone : "<Not set>");
 		if (!ast_strlen_zero(peer->accountcode))
 			ast_cli(fd, "  Accountcode  : %s\n", peer->accountcode);
-		ast_cli(fd, "  AMA flags    : %s\n", ast_channel_amaflags2string(peer->amaflags));
+		ast_cli(fd, "  AMA flags    : %s\n", ast_cdr_flags2str(peer->amaflags));
 		ast_cli(fd, "  Transfer mode: %s\n", transfermode2str(peer->allowtransfer));
 		ast_cli(fd, "  CallingPres  : %s\n", ast_describe_caller_presentation(peer->callingpres));
 		if (!ast_strlen_zero(peer->fromuser))
@@ -20309,11 +20159,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		ast_cli(fd, "  Ign SDP ver  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION)));
 		ast_cli(fd, "  Trust RPID   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID)));
 		ast_cli(fd, "  Send RPID    : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID)));
-		ast_cli(fd, "  Path support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEPATH)));
-		if ((path = sip_route_list(&peer->path, 1, 0))) {
-			ast_cli(fd, "  Path         : %s\n", ast_str_buffer(path));
-			ast_free(path);
-		}
 		ast_cli(fd, "  TrustIDOutbnd: %s\n", trust_id_outbound2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_TRUST_ID_OUTBOUND)));
 		ast_cli(fd, "  Subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
 		ast_cli(fd, "  Overlap dial : %s\n", allowoverlap2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP)));
@@ -20347,7 +20192,12 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 			ast_cli(fd, "(none)");
 
 		ast_cli(fd, "\n");
-		ast_cli(fd, "  Codecs       : %s\n", ast_format_cap_get_names(peer->caps, &codec_buf));
+		ast_cli(fd, "  Codecs       : ");
+		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->caps);
+		ast_cli(fd, "%s\n", codec_buf);
+		ast_cli(fd, "  Codec Order  : (");
+		print_codec_to_cli(fd, &peer->prefs);
+		ast_cli(fd, ")\n");
 
 		ast_cli(fd, "  Auto-Framing : %s\n", AST_CLI_YESNO(peer->autoframing));
 		ast_cli(fd, "  Status       : ");
@@ -20383,14 +20233,11 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		astman_append(s, "RemoteSecretExist: %s\r\n", ast_strlen_zero(peer->remotesecret)?"N":"Y");
 		astman_append(s, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y");
 		astman_append(s, "Context: %s\r\n", peer->context);
-		if (!ast_strlen_zero(peer->subscribecontext)) {
-			astman_append(s, "SubscribeContext: %s\r\n", peer->subscribecontext);
-		}
 		astman_append(s, "Language: %s\r\n", peer->language);
 		astman_append(s, "ToneZone: %s\r\n", peer->zone[0] != '\0' ? peer->zone : "<Not set>");
 		if (!ast_strlen_zero(peer->accountcode))
 			astman_append(s, "Accountcode: %s\r\n", peer->accountcode);
-		astman_append(s, "AMAflags: %s\r\n", ast_channel_amaflags2string(peer->amaflags));
+		astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(peer->amaflags));
 		astman_append(s, "CID-CallingPres: %s\r\n", ast_describe_caller_presentation(peer->callingpres));
 		if (!ast_strlen_zero(peer->fromuser))
 			astman_append(s, "SIP-FromUser: %s\r\n", peer->fromuser);
@@ -20450,7 +20297,21 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		astman_append(s, "Default-Username: %s\r\n", peer->username);
 		if (!ast_strlen_zero(sip_cfg.regcontext))
 			astman_append(s, "RegExtension: %s\r\n", peer->regexten);
-		astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(peer->caps, &codec_buf));
+		astman_append(s, "Codecs: ");
+		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->caps);
+		astman_append(s, "%s\r\n", codec_buf);
+		astman_append(s, "CodecOrder: ");
+		pref = &peer->prefs;
+		for(x = 0; x < AST_CODEC_PREF_SIZE ; x++) {
+			if (!(ast_codec_pref_index(pref, x, &codec))) {
+				break;
+			}
+			astman_append(s, "%s", ast_getformatname(&codec));
+			if ((x < (AST_CODEC_PREF_SIZE - 1)) && ast_codec_pref_index(pref, x+1, &codec))
+				astman_append(s, ",");
+		}
+
+		astman_append(s, "\r\n");
 		astman_append(s, "Status: ");
 		peer_status(peer, status, sizeof(status));
 		astman_append(s, "%s\r\n", status);
@@ -20551,7 +20412,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		ast_cli(a->fd, "  Language     : %s\n", user->language);
 		if (!ast_strlen_zero(user->accountcode))
 			ast_cli(a->fd, "  Accountcode  : %s\n", user->accountcode);
-		ast_cli(a->fd, "  AMA flags    : %s\n", ast_channel_amaflags2string(user->amaflags));
+		ast_cli(a->fd, "  AMA flags    : %s\n", ast_cdr_flags2str(user->amaflags));
 		ast_cli(a->fd, "  Tonezone     : %s\n", user->zone[0] != '\0' ? user->zone : "<Not set>");
 		ast_cli(a->fd, "  Transfer mode: %s\n", transfermode2str(user->allowtransfer));
 		ast_cli(a->fd, "  MaxCallBR    : %d kbps\n", user->maxcallbitrate);
@@ -20573,6 +20434,10 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
  		ast_cli(a->fd, "  Sess-Min-SE  : %d secs\n", user->stimer.st_min_se);
 		ast_cli(a->fd, "  RTP Engine   : %s\n", user->engine);
 
+		ast_cli(a->fd, "  Codec Order  : (");
+		print_codec_to_cli(a->fd, &user->prefs);
+		ast_cli(a->fd, ")\n");
+
 		ast_cli(a->fd, "  Auto-Framing:  %s \n", AST_CLI_YESNO(user->autoframing));
 		if (user->chanvars) {
  			ast_cli(a->fd, "  Variables    :\n");
@@ -20596,25 +20461,34 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_str *cbuf;
-	struct ast_cb_names cbnames = {9, { "retrans_pkt",
-                                        "__sip_autodestruct",
-                                        "expire_register",
-                                        "auto_congest",
-                                        "sip_reg_timeout",
-                                        "sip_poke_peer_s",
-                                        "sip_poke_noanswer",
-                                        "sip_reregister",
-                                        "sip_reinvite_retry"},
-								   { retrans_pkt,
-                                     __sip_autodestruct,
-                                     expire_register,
-                                     auto_congest,
-                                     sip_reg_timeout,
-                                     sip_poke_peer_s,
-                                     sip_poke_noanswer,
-                                     sip_reregister,
-                                     sip_reinvite_retry}};
-
+	struct ast_cb_names cbnames = {
+		10,
+		{
+			"retrans_pkt",
+			"__sip_autodestruct",
+			"expire_register",
+			"auto_congest",
+			"sip_reg_timeout",
+			"sip_poke_peer_s",
+			"sip_poke_peer_now",
+			"sip_poke_noanswer",
+			"sip_reregister",
+			"sip_reinvite_retry"
+		},
+		{
+			retrans_pkt,
+			__sip_autodestruct,
+			expire_register,
+			auto_congest,
+			sip_reg_timeout,
+			sip_poke_peer_s,
+			sip_poke_peer_now,
+			sip_poke_noanswer,
+			sip_reregister,
+			sip_reinvite_retry
+		}
+	};
+	
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "sip show sched";
@@ -20645,8 +20519,6 @@ static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	char tmpdat[256];
 	struct ast_tm tm;
 	int counter = 0;
-	struct ao2_iterator iter;
-	struct sip_registry *iterator;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -20662,11 +20534,9 @@ static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
 	ast_cli(a->fd, FORMAT2, "Host", "dnsmgr", "Username", "Refresh", "State", "Reg.Time");
-
-	iter = ao2_iterator_init(registry_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "sip_show_registry iter"))) {
-		ao2_lock(iterator);
-
+	
+	ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
 		snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT);
 		snprintf(user, sizeof(user), "%s", iterator->username);
 		if (!ast_strlen_zero(iterator->regdomain)) {
@@ -20681,13 +20551,9 @@ static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		} else
 			tmpdat[0] = '\0';
 		ast_cli(a->fd, FORMAT, host, (iterator->dnsmgr) ? "Y" : "N", user, iterator->refresh, regstate2str(iterator->regstate), tmpdat);
-
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "sip_show_registry iter");
+		ASTOBJ_UNLOCK(iterator);
 		counter++;
-	}
-	ao2_iterator_destroy(&iter);
-
+	} while(0));
 	ast_cli(a->fd, "%d SIP registrations.\n", counter);
 	return CLI_SUCCESS;
 #undef FORMAT
@@ -20713,10 +20579,10 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	case CLI_GENERATE:
 		return complete_sip_unregister(a->line, a->word, a->pos, a->n);
 	}
-
+	
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
-
+	
 	if ((peer = sip_find_peer(a->argv[2], NULL, load_realtime, FINDPEERS, TRUE, 0))) {
 		if (peer->expire > 0) {
 			AST_SCHED_DEL_UNREF(sched, peer->expire,
@@ -20730,7 +20596,7 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	} else {
 		ast_cli(a->fd, "Peer unknown: \'%s\'. Not unregistered.\n", a->argv[2]);
 	}
-
+	
 	return CLI_SUCCESS;
 }
 
@@ -20742,6 +20608,8 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags)
 	struct sip_pvt *cur = __cur;
 	struct ast_rtp_instance_stats stats;
 	char durbuf[10];
+	int duration;
+	int durh, durm, durs;
 	struct ast_channel *c;
 	struct __show_chan_arg *arg = __arg;
 	int fd = arg->fd;
@@ -20772,8 +20640,12 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags)
 		return 0;
 	}
 
-	if (c) {
-		ast_format_duration_hh_mm_ss(ast_channel_get_duration(c), durbuf, sizeof(durbuf));
+	if (c && ast_channel_cdr(c) && !ast_tvzero(ast_channel_cdr(c)->start)) {
+		duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_cdr(c)->start) / 1000);
+		durh = duration / 3600;
+		durm = (duration % 3600) / 60;
+		durs = duration % 60;
+		snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
 	} else {
 		durbuf[0] = '\0';
 	}
@@ -20833,7 +20705,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 {
 	int realtimepeers;
 	int realtimeregs;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	char codec_buf[SIPBUFSIZE];
 	const char *msg;	/* temporary msg pointer */
 	struct sip_auth_container *credentials;
 
@@ -20887,7 +20759,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	ast_cli(a->fd, "  Allow promisc. redir:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
 	ast_cli(a->fd, "  Enable call counters:   %s\n", AST_CLI_YESNO(global_callcounter));
 	ast_cli(a->fd, "  SIP domain support:     %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
-	ast_cli(a->fd, "  Path support :          %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USEPATH)));
 	ast_cli(a->fd, "  Realm. auth:            %s\n", AST_CLI_YESNO(credentials != NULL));
 	if (credentials) {
 		struct sip_auth *auth;
@@ -20925,6 +20796,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		ast_cli(a->fd, "  From: Domain:           %s\n", default_fromdomain);
 	}
 	ast_cli(a->fd, "  Record SIP history:     %s\n", AST_CLI_ONOFF(recordhistory));
+	ast_cli(a->fd, "  Call Events:            %s\n", AST_CLI_ONOFF(sip_cfg.callevents));
 	ast_cli(a->fd, "  Auth. Failure Events:   %s\n", AST_CLI_ONOFF(global_authfailureevents));
 
 	ast_cli(a->fd, "  T.38 support:           %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT)));
@@ -20986,7 +20858,12 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	}
 	ast_cli(a->fd, "\nGlobal Signalling Settings:\n");
 	ast_cli(a->fd, "---------------------------\n");
-	ast_cli(a->fd, "  Codecs:                 %s\n", ast_format_cap_get_names(sip_cfg.caps, &codec_buf));
+	ast_cli(a->fd, "  Codecs:                 ");
+	ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, sip_cfg.caps);
+	ast_cli(a->fd, "%s\n", codec_buf);
+	ast_cli(a->fd, "  Codec Order:            ");
+	print_codec_to_cli(a->fd, &default_prefs);
+	ast_cli(a->fd, "\n");
 	ast_cli(a->fd, "  Relax DTMF:             %s\n", AST_CLI_YESNO(global_relaxdtmf));
 	ast_cli(a->fd, "  RFC2833 Compensation:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_RFC2833_COMPENSATE)));
 	ast_cli(a->fd, "  Symmetric RTP:          %s\n", comedia_string(global_flags));
@@ -21046,7 +20923,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	ast_cli(a->fd, "  MOH Suggest:            %s\n", default_mohsuggest);
 	ast_cli(a->fd, "  Voice Mail Extension:   %s\n", default_vmexten);
 
-
+	
 	if (realtimepeers || realtimeregs) {
 		ast_cli(a->fd, "\nRealtime SIP Settings:\n");
 		ast_cli(a->fd, "----------------------\n");
@@ -21056,7 +20933,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		ast_cli(a->fd, "  Update:                 %s\n", AST_CLI_YESNO(sip_cfg.peer_rtupdate));
 		ast_cli(a->fd, "  Ignore Reg. Expire:     %s\n", AST_CLI_YESNO(sip_cfg.ignore_regexpire));
 		ast_cli(a->fd, "  Save sys. name:         %s\n", AST_CLI_YESNO(sip_cfg.rtsave_sysname));
-		ast_cli(a->fd, "  Save path header:       %s\n", AST_CLI_YESNO(sip_cfg.rtsave_path));
 		ast_cli(a->fd, "  Auto Clear:             %d (%s)\n", sip_cfg.rtautoclear, ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR) ? "Enabled" : "Disabled");
 	}
 	ast_cli(a->fd, "\n----\n");
@@ -21067,9 +20943,7 @@ static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 {
 #define FORMAT  "%-30.30s  %-12.12s  %-10.10s  %-10.10s\n"
 	char host[80];
-	struct ao2_iterator iter;
-	struct sip_subscription_mwi *iterator;
-
+	
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "sip show mwi";
@@ -21080,18 +20954,15 @@ static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 	case CLI_GENERATE:
 		return NULL;
 	}
-
+	
 	ast_cli(a->fd, FORMAT, "Host", "Username", "Mailbox", "Subscribed");
-
-	iter = ao2_iterator_init(subscription_mwi_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "sip_show_mwi iter"))) {
-		ao2_lock(iterator);
+	
+	ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+		ASTOBJ_RDLOCK(iterator);
 		snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT);
 		ast_cli(a->fd, FORMAT, host, iterator->username, iterator->mailbox, AST_CLI_YESNO(iterator->subscribed));
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "sip_show_mwi iter");
-	}
-	ao2_iterator_destroy(&iter);
+		ASTOBJ_UNLOCK(iterator);
+	} while(0));
 
 	return CLI_SUCCESS;
 #undef FORMAT
@@ -21150,12 +21021,12 @@ static int show_channels_cb(void *__cur, void *__arg, int flags)
 	if (cur->subscribed == NONE && !arg->subscriptions) {
 		/* set if SIP transfer in progress */
 		const char *referstatus = cur->refer ? referstatus2str(cur->refer->status) : "";
-		struct ast_str *codec_buf = ast_str_alloca(64);
-
+		char formatbuf[SIPBUFSIZE/2];
+		
 		ast_cli(arg->fd, FORMAT, ast_sockaddr_stringify_addr(dst),
 				S_OR(cur->username, S_OR(cur->cid_num, "(None)")),
 				cur->callid,
-				cur->owner ? ast_format_cap_get_names(ast_channel_nativeformats(cur->owner), &codec_buf) : "(nothing)",
+				cur->owner ? ast_getformatname_multiple(formatbuf, sizeof(formatbuf), ast_channel_nativeformats(cur->owner)) : "(nothing)",
 				AST_CLI_YESNO(ast_test_flag(&cur->flags[1], SIP_PAGE2_CALL_ONHOLD)),
 				cur->needdestroy ? "(d)" : "",
 				cur->lastmsg ,
@@ -21215,7 +21086,7 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_
 
 	/* iterate on the container and invoke the callback on each item */
 	ao2_t_callback(dialogs, OBJ_NODATA, show_channels_cb, &arg, "callback to show channels");
-
+	
 	/* print summary information */
 	ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans,
 		(arg.subscriptions ? "subscription" : "dialog"),
@@ -21292,7 +21163,7 @@ static char *complete_sip_registered_peer(const char *word, int state, int flags
        int which = 0;
        struct ao2_iterator i;
        struct sip_peer *peer;
-
+       
        i = ao2_iterator_init(peers, 0);
        while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
 	       if (!strncasecmp(word, peer->name, wordlen) &&
@@ -21351,7 +21222,7 @@ static char *complete_sip_notify(const char *line, const char *word, int pos, in
 
 		if (!notify_types)
 			return NULL;
-
+		
 		while ( (cat = ast_category_browse(notify_types, cat)) ) {
 			if (!strncasecmp(word, cat, wordlen) && ++which > state) {
 				c = ast_strdup(cat);
@@ -21367,6 +21238,24 @@ static char *complete_sip_notify(const char *line, const char *word, int pos, in
 	return NULL;
 }
 
+static const char *transport2str(enum sip_transport transport)
+{
+	switch (transport) {
+	case SIP_TRANSPORT_TLS:
+		return "TLS";
+	case SIP_TRANSPORT_UDP:
+		return "UDP";
+	case SIP_TRANSPORT_TCP:
+		return "TCP";
+	case SIP_TRANSPORT_WS:
+		return "WS";
+	case SIP_TRANSPORT_WSS:
+		return "WSS";
+	}
+
+	return "Undefined";
+}
+
 /*! \brief Show details of one active dialog */
 static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -21389,15 +21278,13 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	if (a->argc != 4)
 		return CLI_SHOWUSAGE;
 	len = strlen(a->argv[3]);
-
+	
 	i = ao2_iterator_init(dialogs, 0);
 	while ((cur = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
 		sip_pvt_lock(cur);
 
 		if (!strncasecmp(cur->callid, a->argv[3], len)) {
-			struct ast_str *strbuf;
-			struct ast_str *codec_buf = ast_str_alloca(64);
-
+			char formatbuf[SIPBUFSIZE/2];
 			ast_cli(a->fd, "\n");
 			if (cur->subscribed != NONE) {
 				ast_cli(a->fd, "  * Subscription (type: %s)\n", subscription_type2str(cur->subscribed));
@@ -21407,11 +21294,11 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 			ast_cli(a->fd, "  Curr. trans. direction:  %s\n", ast_test_flag(&cur->flags[0], SIP_OUTGOING) ? "Outgoing" : "Incoming");
 			ast_cli(a->fd, "  Call-ID:                %s\n", cur->callid);
 			ast_cli(a->fd, "  Owner channel ID:       %s\n", cur->owner ? ast_channel_name(cur->owner) : "<none>");
-			ast_cli(a->fd, "  Our Codec Capability:   %s\n", ast_format_cap_get_names(cur->caps, &codec_buf));
+			ast_cli(a->fd, "  Our Codec Capability:   %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->caps));
 			ast_cli(a->fd, "  Non-Codec Capability (DTMF):   %d\n", cur->noncodeccapability);
-			ast_cli(a->fd, "  Their Codec Capability:   %s\n", ast_format_cap_get_names(cur->peercaps, &codec_buf));
-			ast_cli(a->fd, "  Joint Codec Capability:   %s\n", ast_format_cap_get_names(cur->jointcaps, &codec_buf));
-			ast_cli(a->fd, "  Format:                 %s\n", cur->owner ? ast_format_cap_get_names(ast_channel_nativeformats(cur->owner), &codec_buf) : "(nothing)" );
+			ast_cli(a->fd, "  Their Codec Capability:   %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->peercaps));
+			ast_cli(a->fd, "  Joint Codec Capability:   %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->jointcaps));
+			ast_cli(a->fd, "  Format:                 %s\n", cur->owner ? ast_getformatname_multiple(formatbuf, sizeof(formatbuf), ast_channel_nativeformats(cur->owner)) : "(nothing)" );
 			ast_cli(a->fd, "  T.38 support            %s\n", AST_CLI_YESNO(cur->udptl != NULL));
 			ast_cli(a->fd, "  Video support           %s\n", AST_CLI_YESNO(cur->vrtp != NULL));
 			ast_cli(a->fd, "  MaxCallBR:              %d kbps\n", cur->maxcallbitrate);
@@ -21446,9 +21333,18 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 			ast_cli(a->fd, "  Need Destroy:           %s\n", AST_CLI_YESNO(cur->needdestroy));
 			ast_cli(a->fd, "  Last Message:           %s\n", cur->lastmsg);
 			ast_cli(a->fd, "  Promiscuous Redir:      %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[0], SIP_PROMISCREDIR)));
-			if ((strbuf = sip_route_list(&cur->route, 1, 0))) {
-				ast_cli(a->fd, "  Route:                  %s\n", ast_str_buffer(strbuf));
-				ast_free(strbuf);
+			ast_cli(a->fd, "  Route:                  ");
+			if (cur->route) {
+				struct sip_route *route;
+				int first = 1;
+
+				for (route = cur->route; route; route = route->next) {
+					ast_cli(a->fd, "%s<%s>", first ? "" : ", ", route->hop);
+					first = 0;
+				}
+				ast_cli(a->fd, "\n");
+			} else {
+				ast_cli(a->fd, "N/A\n");
 			}
 			ast_cli(a->fd, "  DTMF Mode:              %s\n", dtmfmode2str(ast_test_flag(&cur->flags[0], SIP_DTMF)));
 			ast_cli(a->fd, "  SIP Options:            ");
@@ -21474,13 +21370,13 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
  					ast_cli(a->fd, "  S-Timer Peer Sts:       %s\n", cur->stimer->st_active_peer_ua ? "Active" : "Inactive");
  					ast_cli(a->fd, "  S-Timer Cached Min-SE:  %d\n", cur->stimer->st_cached_min_se);
  					ast_cli(a->fd, "  S-Timer Cached SE:      %d\n", cur->stimer->st_cached_max_se);
- 					ast_cli(a->fd, "  S-Timer Cached Ref:     %s\n", strefresherparam2str(cur->stimer->st_cached_ref));
+ 					ast_cli(a->fd, "  S-Timer Cached Ref:     %s\n", strefresher2str(cur->stimer->st_cached_ref));
  					ast_cli(a->fd, "  S-Timer Cached Mode:    %s\n", stmode2str(cur->stimer->st_cached_mode));
  				}
 			}
 
 			/* add transport and media types */
-			ast_cli(a->fd, "  Transport:              %s\n", ast_transport2str(cur->socket.type));
+			ast_cli(a->fd, "  Transport:              %s\n", transport2str(cur->socket.type));
 			ast_cli(a->fd, "  Media:                  %s\n", cur->srtp ? "SRTP" : cur->rtp ? "RTP" : "None");
 
 			ast_cli(a->fd, "\n\n");
@@ -21703,8 +21599,11 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
 	} else if (!ast_strlen_zero(c = sip_get_header(req, "X-ClientCode"))) {
 		/* Client code (from SNOM phone) */
 		if (ast_test_flag(&p->flags[0], SIP_USECLIENTCODE)) {
-			if (p->owner) {
-				ast_cdr_setuserfield(ast_channel_name(p->owner), c);
+			if (p->owner && ast_channel_cdr(p->owner)) {
+				ast_cdr_setuserfield(p->owner, c);
+			}
+			if (p->owner && ast_bridged_channel(p->owner) && ast_channel_cdr(ast_bridged_channel(p->owner))) {
+				ast_cdr_setuserfield(ast_bridged_channel(p->owner), c);
 			}
 			transmit_response(p, "200 OK", req);
 		} else {
@@ -21716,8 +21615,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
 		 * on phone calls.
 		 */
 
-		char feat[AST_FEATURE_MAX_LEN];
-		int feat_res = -1;
+		struct ast_call_feature *feat = NULL;
 		int j;
 		struct ast_frame f = { AST_FRAME_DTMF, };
 		int suppress_warning = 0; /* Supress warning if the feature is blank */
@@ -21729,40 +21627,43 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
 		}
 
 		/* first, get the feature string, if it exists */
+		ast_rdlock_call_features();
 		if (p->relatedpeer) {
 			if (!strcasecmp(c, "on")) {
 				if (ast_strlen_zero(p->relatedpeer->record_on_feature)) {
 					suppress_warning = 1;
 				} else {
-					feat_res = ast_get_feature(p->owner, p->relatedpeer->record_on_feature, feat, sizeof(feat));
+					feat = ast_find_call_feature(p->relatedpeer->record_on_feature);
 				}
 			} else if (!strcasecmp(c, "off")) {
 				if (ast_strlen_zero(p->relatedpeer->record_off_feature)) {
 					suppress_warning = 1;
 				} else {
-					feat_res = ast_get_feature(p->owner, p->relatedpeer->record_off_feature, feat, sizeof(feat));
+					feat = ast_find_call_feature(p->relatedpeer->record_off_feature);
 				}
 			} else {
 				ast_log(LOG_ERROR, "Received INFO requesting to record with invalid value: %s\n", c);
 			}
 		}
-		if (feat_res || ast_strlen_zero(feat)) {
+		if (!feat || ast_strlen_zero(feat->exten)) {
 			if (!suppress_warning) {
 				ast_log(LOG_WARNING, "Recording requested, but no One Touch Monitor registered. (See features.conf)\n");
 			}
 			/* 403 means that we don't support this feature, so don't request it again */
 			transmit_response(p, "403 Forbidden", req);
+			ast_unlock_call_features();
 			return;
 		}
 		/* Send the feature code to the PBX as DTMF, just like the handset had sent it */
 		f.len = 100;
-		for (j = 0; j < strlen(feat); j++) {
-			f.subclass.integer = feat[j];
+		for (j=0; j < strlen(feat->exten); j++) {
+			f.subclass.integer = feat->exten[j];
 			ast_queue_frame(p->owner, &f);
 			if (sipdebug) {
 				ast_verbose("* DTMF-relay event faked: %c\n", f.subclass.integer);
 			}
 		}
+		ast_unlock_call_features();
 
 		ast_debug(1, "Got a Request to Record the channel, state %s\n", c);
 		transmit_response(p, "200 OK", req);
@@ -21846,7 +21747,7 @@ static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 			ast_cli(a->fd, "SIP Debugging Disabled\n");
 			return CLI_SUCCESS;
 		}
-	} else if (a->argc == e->args + 1) { /* ip/peer */
+	} else if (a->argc == e->args +1) {/* ip/peer */
 		if (!strcasecmp(what, "ip"))
 			return sip_do_debug_ip(a->fd, a->argv[e->args]);
 		else if (!strcasecmp(what, "peer"))
@@ -22116,11 +22017,11 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
 	struct sip_auth_container *credentials;
 
 	if (!ast_strlen_zero(p->domain))
-		snprintf(uri, sizeof(uri), "%s:%s", p->socket.type == AST_TRANSPORT_TLS ? "sips" : "sip", p->domain);
+		snprintf(uri, sizeof(uri), "%s:%s", p->socket.type == SIP_TRANSPORT_TLS ? "sips" : "sip", p->domain);
 	else if (!ast_strlen_zero(p->uri))
 		ast_copy_string(uri, p->uri, sizeof(uri));
 	else
-		snprintf(uri, sizeof(uri), "%s:%s@%s", p->socket.type == AST_TRANSPORT_TLS ? "sips" : "sip", p->username, ast_sockaddr_stringify_host_remote(&p->sa));
+		snprintf(uri, sizeof(uri), "%s:%s@%s", p->socket.type == SIP_TRANSPORT_TLS ? "sips" : "sip", p->username, ast_sockaddr_stringify_host_remote(&p->sa));
 
 	snprintf(cnonce, sizeof(cnonce), "%08lx", (unsigned long)ast_random());
 
@@ -22156,7 +22057,7 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
 	} else {
 		/* No authentication, use peer or register= config */
 		username = p->authname;
- 		secret = p->relatedpeer
+ 		secret = p->relatedpeer 
 			&& !ast_strlen_zero(p->relatedpeer->remotesecret)
 				? p->relatedpeer->remotesecret : p->peersecret;
 		md5secret = p->peermd5secret;
@@ -22203,7 +22104,7 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d
 	}
 	return 0;
 }
-
+	
 /*! \brief Read SIP header (dialplan function) */
 static int func_header_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
 {
@@ -22293,11 +22194,15 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
 	struct sip_peer *peer;
 	char *colname;
 
-	if ((colname = strchr(data, ','))) {
+	if ((colname = strchr(data, ':'))) {	/*! \todo Will be deprecated after 1.4 */
+		static int deprecation_warning = 0;
 		*colname++ = '\0';
-	} else {
+		if (deprecation_warning++ % 10 == 0)
+			ast_log(LOG_WARNING, "SIPPEER(): usage of ':' to separate arguments is deprecated.  Please use ',' instead.\n");
+	} else if ((colname = strchr(data, ',')))
+		*colname++ = '\0';
+	else
 		colname = "ip";
-	}
 
 	if (!(peer = sip_find_peer(data, NULL, TRUE, FINDPEERS, FALSE, 0)))
 		return -1;
@@ -22355,9 +22260,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
 	} else  if (!strcasecmp(colname, "callerid_num")) {
 		ast_copy_string(buf, peer->cid_num, len);
 	} else  if (!strcasecmp(colname, "codecs")) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_format_cap_get_names(peer->caps, &codec_buf);
-		ast_copy_string(buf, ast_str_buffer(codec_buf), len);
+		ast_getformatname_multiple(buf, len -1, peer->caps);
 	} else if (!strcasecmp(colname, "encryption")) {
 		snprintf(buf, len, "%u", ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP));
 	} else  if (!strncasecmp(colname, "chanvar[", 8)) {
@@ -22372,14 +22275,12 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
 		}
 	} else  if (!strncasecmp(colname, "codec[", 6)) {
 		char *codecnum;
-		struct ast_format *codec;
+		struct ast_format codec;
 
 		codecnum = colname + 6;	/* move past the '[' */
 		codecnum = strsep(&codecnum, "]"); /* trim trailing ']' if any */
-		codec = ast_format_cap_get_format(peer->caps, atoi(codecnum));
-		if (codec) {
-			ast_copy_string(buf, ast_format_get_name(codec), len);
-			ao2_ref(codec, -1);
+		if((ast_codec_pref_index(&peer->prefs, atoi(codecnum), &codec))) {
+			ast_copy_string(buf, ast_getformatname(&codec), len);
 		} else {
 			buf[0] = '\0';
 		}
@@ -22398,6 +22299,77 @@ static struct ast_custom_function sippeer_function = {
 	.read = function_sippeer,
 };
 
+/*! \brief ${SIPCHANINFO()} Dialplan function - reads sip channel data */
+static int function_sipchaninfo_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	struct sip_pvt *p;
+	static int deprecated = 0;
+
+	*buf = 0;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	if (!data) {
+		ast_log(LOG_WARNING, "This function requires a parameter name.\n");
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (!IS_SIP_TECH(ast_channel_tech(chan))) {
+		ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (deprecated++ % 20 == 0) {
+		/* Deprecated in 1.6.1 */
+		ast_log(LOG_WARNING, "SIPCHANINFO() is deprecated.  Please transition to using CHANNEL().\n");
+	}
+
+	p = ast_channel_tech_pvt(chan);
+
+	/* If there is no private structure, this channel is no longer alive */
+	if (!p) {
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (!strcasecmp(data, "peerip")) {
+		ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->sa), len);
+	} else  if (!strcasecmp(data, "recvip")) {
+		ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->recv), len);
+	} else  if (!strcasecmp(data, "from")) {
+		ast_copy_string(buf, p->from, len);
+	} else  if (!strcasecmp(data, "uri")) {
+		ast_copy_string(buf, p->uri, len);
+	} else  if (!strcasecmp(data, "useragent")) {
+		ast_copy_string(buf, p->useragent, len);
+	} else  if (!strcasecmp(data, "peername")) {
+		ast_copy_string(buf, p->peername, len);
+	} else if (!strcasecmp(data, "t38passthrough")) {
+		if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
+			ast_copy_string(buf, "0", len);
+		} else { /* T38 is offered or enabled in this call */
+			ast_copy_string(buf, "1", len);
+		}
+	} else {
+		ast_channel_unlock(chan);
+		return -1;
+	}
+	ast_channel_unlock(chan);
+
+	return 0;
+}
+
+/*! \brief Structure to declare a dialplan function: SIPCHANINFO */
+static struct ast_custom_function sipchaninfo_function = {
+	.name = "SIPCHANINFO",
+	.read = function_sipchaninfo_read,
+};
+
 /*! \brief update redirecting information for a channel based on headers
  *
  */
@@ -22409,12 +22381,11 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
 	char *redirecting_from_number = NULL;
 	char *redirecting_to_name = NULL;
 	char *redirecting_to_number = NULL;
-	char *reason_str = NULL;
 	int reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
 	int is_response = req->method == SIP_RESPONSE;
 	int res = 0;
 
-	res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason, &reason_str);
+	res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason);
 	if (res == -1) {
 		if (is_response) {
 			get_name_and_number(sip_get_header(req, "TO"), &redirecting_from_name, &redirecting_from_number);
@@ -22467,12 +22438,7 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
 		ast_free(redirecting->to.name.str);
 		redirecting->to.name.str = redirecting_to_name;
 	}
-	redirecting->reason.code = reason;
-	if (reason_str) {
-		ast_debug(3, "Got redirecting reason %s\n", reason_str);
-		ast_free(redirecting->reason.str);
-		redirecting->reason.str = reason_str;
-	}
+	redirecting->reason = reason;
 }
 
 /*! \brief Parse 302 Moved temporalily response
@@ -22488,7 +22454,7 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
 	char *contact_number = NULL;
 	char *separator, *trans;
 	char *domain;
-	enum ast_transport transport = AST_TRANSPORT_UDP;
+	enum sip_transport transport = SIP_TRANSPORT_UDP;
 
 	ast_copy_string(contact, sip_get_header(req, "Contact"), sizeof(contact));
 	if ((separator = strchr(contact, ',')))
@@ -22502,14 +22468,14 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
 			*separator = '\0';
 
 		if (!strncasecmp(trans, "tcp", 3))
-			transport = AST_TRANSPORT_TCP;
+			transport = SIP_TRANSPORT_TCP;
 		else if (!strncasecmp(trans, "tls", 3))
-			transport = AST_TRANSPORT_TLS;
+			transport = SIP_TRANSPORT_TLS;
 		else {
 			if (strncasecmp(trans, "udp", 3))
 				ast_debug(1, "received contact with an invalid transport, '%s'\n", contact_number);
 			/* This will assume UDP for all unknown transports */
-			transport = AST_TRANSPORT_UDP;
+			transport = SIP_TRANSPORT_UDP;
 		}
 	}
 	contact_number = remove_uri_parameters(contact_number);
@@ -22591,7 +22557,7 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
 	}
 }
 
-/*! \brief Check pending actions on SIP call
+/*! \brief Check pending actions on SIP call 
  *
  * \note both sip_pvt and sip_pvt's owner channel (if present)
  *  must be locked for this function.
@@ -22629,7 +22595,7 @@ static void check_pendings(struct sip_pvt *p)
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 	} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
 		/* if we can't REINVITE, hold it for later */
-		if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA || p->waitid > 0) {
+		if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA || p->waitid > -1) {
 			ast_debug(2, "NOT Sending pending reinvite (yet) on '%s'\n", p->callid);
 		} else {
 			ast_debug(2, "Sending pending reinvite on '%s'\n", p->callid);
@@ -22864,7 +22830,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
  	if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA )) {
  		p->invitestate = INV_COMPLETED;
 	}
-
+ 	
 	if ((resp >= 200 && reinvite)) {
 		p->ongoing_reinvite = 0;
 		if (p->reinviteid > -1) {
@@ -22943,8 +22909,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 			if (!req->ignore && p->owner) {
 				/* Queue a progress frame only if we have SDP in 180 or 182 */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
-				/* We have not sent progress, but we have been sent progress so enable early media */
-				ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 			}
 			ast_rtp_instance_activate(p->rtp);
 		}
@@ -23028,8 +22992,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 			if (!req->ignore && p->owner) {
 				/* Queue a progress frame */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
-				/* We have not sent progress, but we have been sent progress so enable early media */
-				ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 			}
 			ast_rtp_instance_activate(p->rtp);
 		} else {
@@ -23123,8 +23085,8 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 			if(set_address_from_contact(p)) {
 				/* Bad contact - we don't know how to reach this device */
 				/* We need to ACK, but then send a bye */
-				if (sip_route_empty(&p->route) && !req->ignore) {
-					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+				if (!p->route && !req->ignore) {
+					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 				}
 			}
 
@@ -23133,6 +23095,11 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 		if (!req->ignore && p->owner) {
 			if (!reinvite && !res) {
 				ast_queue_control(p->owner, AST_CONTROL_ANSWER);
+				if (sip_cfg.callevents) {
+					manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+						"Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
+						ast_channel_name(p->owner), "SIP", ast_channel_uniqueid(p->owner), p->callid, p->fullcontact, p->peername);
+				}
 			} else {	/* RE-invite */
 				if (p->t38.state == T38_DISABLED || p->t38.state == T38_REJECTED) {
 					ast_queue_control(p->owner, AST_CONTROL_UPDATE_RTP_PEER);
@@ -23145,7 +23112,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 				  by sending CANCEL */
 			/* First send ACK, then send bye */
 			if (!req->ignore) {
-				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 			}
 		}
 
@@ -23158,7 +23125,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 				int tmp_st_interval = 0;
 				rtn = parse_session_expires(p_hdrval, &tmp_st_interval, &st_ref_param);
 				if (rtn != 0) {
-					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
+					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 				} else if (tmp_st_interval < st_get_se(p, FALSE)) {
 					ast_log(LOG_WARNING, "Got Session-Expires less than local Min-SE in 200 OK, tearing down call\n");
 					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
@@ -23261,28 +23228,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
 		}
 		break;
 
-	case 480: /* Temporarily unavailable. */
-		/* RFC 3261 encourages setting the reason phrase to something indicative
-		 * of why the endpoint is not available. We will make this readable via the
-		 * redirecting reason.
-		 */
-		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-		append_history(p, "TempUnavailable", "Endpoint is temporarily unavailable.");
-		if (p->owner && !req->ignore) {
-			struct ast_party_redirecting redirecting;
-			struct ast_set_party_redirecting update_redirecting;
-			ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(p->owner));
-			memset(&update_redirecting, 0, sizeof(update_redirecting));
-
-			redirecting.reason.code = sip_reason_str_to_code(rest);
-			redirecting.reason.str = ast_strdup(rest);
-
-			ast_channel_queue_redirecting_update(p->owner, &redirecting, &update_redirecting);
-			ast_party_redirecting_free(&redirecting);
-
-			ast_queue_control(p->owner, AST_CONTROL_BUSY);
-		}
-		break;
 	case 487: /* Cancelled transaction */
 		/* We have sent CANCEL on an outbound INVITE
 			This transaction is already scheduled to be killed by sip_hangup().
@@ -23449,8 +23394,8 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
 			p->options = NULL;
 		}
 		p->mwi->subscribed = 1;
-		if ((p->mwi->resub = ast_sched_add(sched, mwi_expiry * 1000, sip_subscribe_mwi_do, ao2_t_bump(p->mwi, "mwi ast_sched_add"))) < 0) {
-			ao2_t_ref(p->mwi, -1, "mwi ast_sched_add < 0");
+		if ((p->mwi->resub = ast_sched_add(sched, mwi_expiry * 1000, sip_subscribe_mwi_do, ASTOBJ_REF(p->mwi))) < 0) {
+			ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 		}
 		break;
 	case 401:
@@ -23459,7 +23404,7 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
 		if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_SUBSCRIBE, 0)) {
 			ast_log(LOG_NOTICE, "Failed to authenticate on SUBSCRIBE to '%s'\n", sip_get_header(&p->initreq, "From"));
 			p->mwi->call = NULL;
-			ao2_t_ref(p->mwi, -1, "failed to authenticate SUBSCRIBE");
+			ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 			pvt_set_needdestroy(p, "failed to authenticate SUBSCRIBE");
 		}
 		break;
@@ -23467,20 +23412,20 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
 		transmit_response_with_date(p, "200 OK", req);
 		ast_log(LOG_WARNING, "Authentication failed while trying to subscribe for MWI.\n");
 		p->mwi->call = NULL;
-		ao2_t_ref(p->mwi, -1, "received 403 response");
+		ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 		pvt_set_needdestroy(p, "received 403 response");
 		sip_alreadygone(p);
 		break;
 	case 404:
 		ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side said that a mailbox may not have been configured.\n");
 		p->mwi->call = NULL;
-		ao2_t_ref(p->mwi, -1, "received 404 response");
+		ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 		pvt_set_needdestroy(p, "received 404 response");
 		break;
 	case 481:
 		ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side said that our dialog did not exist.\n");
 		p->mwi->call = NULL;
-		ao2_t_ref(p->mwi, -1, "received 481 response");
+		ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 		pvt_set_needdestroy(p, "received 481 response");
 		break;
 
@@ -23491,7 +23436,7 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
 	case 501:
 		ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side may have suffered a heart attack.\n");
 		p->mwi->call = NULL;
-		ao2_t_ref(p->mwi, -1, "received 500/501 response");
+		ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy);
 		pvt_set_needdestroy(p, "received serious error (500/501/493/414/400) response");
 		break;
 	}
@@ -23537,7 +23482,7 @@ static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest,
 			pvt_set_needdestroy(p, "failed to authenticate REFER");
 		}
 		break;
-
+	
 	case 405:   /* Method not allowed */
 		/* Return to the current call onhold */
 		/* Status flag needed to be reset */
@@ -23581,11 +23526,11 @@ static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest,
 		break;
 	default:
 		/* We should treat unrecognized 9xx as 900.  400 is actually
-		   specified as a possible response, but any 4-6xx is
+		   specified as a possible response, but any 4-6xx is 
 		   theoretically possible. */
 
 		if (resp < 299) { /* 1xx cases don't get here */
-			ast_log(LOG_WARNING, "SIP transfer to %s had unxpected 2xx response (%d), confusion is possible. \n", p->refer->refer_to, resp);
+			ast_log(LOG_WARNING, "SIP transfer to %s had unexpected 2xx response (%d), confusion is possible. \n", p->refer->refer_to, resp);
 		} else {
 			ast_log(LOG_WARNING, "SIP transfer to %s with response (%d). \n", p->refer->refer_to, resp);
 		}
@@ -23604,8 +23549,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 {
 	int expires, expires_ms;
 	struct sip_registry *r;
-	r = p->registry;
-
+	r=p->registry;
+	
 	switch (resp) {
 	case 401:	/* Unauthorized */
 		if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
@@ -23622,9 +23567,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 			break;
 		}
 		ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
-		AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 403"));
+		AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 403"));
 		r->regstate = REG_STATE_NOAUTH;
-		sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
 		pvt_set_needdestroy(p, "received 403 response");
 		break;
 	case 404:	/* Not found */
@@ -23633,8 +23577,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 		if (r->call)
 			r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 404");
 		r->regstate = REG_STATE_REJECTED;
-		sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
-		AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 404"));
+		AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 404"));
 		break;
 	case 407:	/* Proxy auth */
 		if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
@@ -23653,7 +23596,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 	case 423:	/* Interval too brief */
 		r->expiry = atoi(sip_get_header(req, "Min-Expires"));
 		ast_log(LOG_WARNING, "Got 423 Interval too brief for service %s@%s, minimum is %d seconds\n", p->registry->username, p->registry->hostname, r->expiry);
-		AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 423"));
+		AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 423"));
 		if (r->call) {
 			r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 423");
 			pvt_set_needdestroy(p, "received 423 response");
@@ -23666,7 +23609,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 			r->regstate = REG_STATE_UNREGISTERED;
 			transmit_register(r, SIP_REGISTER, NULL, NULL);
 		}
-		sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
+		manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
 		break;
 	case 400:	/* Bad request */
 	case 414:	/* Request URI too long */
@@ -23677,8 +23620,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 		if (r->call)
 			r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 4xx");
 		r->regstate = REG_STATE_REJECTED;
-		sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
-		AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 479"));
+		AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 479"));
 		break;
 	case 200:	/* 200 OK */
 		if (!r) {
@@ -23689,16 +23631,16 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 
 		r->regstate = REG_STATE_REGISTERED;
 		r->regtime = ast_tvnow();		/* Reset time of last successful registration */
-		sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate));
+		manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
 		r->regattempts = 0;
 		ast_debug(1, "Registration successful\n");
 		if (r->timeout > -1) {
 			ast_debug(1, "Cancelling timeout %d\n", r->timeout);
 		}
-		AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 200"));
+		AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 200"));
 		if (r->call)
 			r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 200");
-		ao2_t_replace(p->registry, NULL, "unref registry entry p->registry");
+		p->registry = registry_unref(p->registry, "unref registry entry p->registry");
 
 		/* destroy dialog now to avoid interference with next register */
 		pvt_set_needdestroy(p, "Registration successfull");
@@ -23731,13 +23673,13 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 					expires = 0;
 				}
 			}
-
+			
 		}
 		if (!expires)
 			expires=atoi(sip_get_header(req, "expires"));
 		if (!expires)
 			expires=default_expiry;
-
+		
 		expires_ms = expires * 1000;
 		if (expires <= EXPIRY_GUARD_LIMIT)
 			expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT), EXPIRY_GUARD_MIN);
@@ -23745,14 +23687,14 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
 			expires_ms -= EXPIRY_GUARD_SECS * 1000;
 		if (sipdebug)
 			ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d s)\n", r->hostname, expires, expires_ms/1000);
-
+		
 		r->refresh= (int) expires_ms / 1000;
-
+		
 		/* Schedule re-registration before we expire */
 		AST_SCHED_REPLACE_UNREF(r->expire, sched, expires_ms, sip_reregister, r,
-								ao2_t_ref(_data, -1, "unref in REPLACE del fail"),
-								ao2_t_ref(r, -1, "unref in REPLACE add fail"),
-								ao2_t_ref(r, +1, "The Addition side of REPLACE"));
+								registry_unref(_data,"unref in REPLACE del fail"),
+								registry_unref(r,"unref in REPLACE add fail"),
+								registry_addref(r,"The Addition side of REPLACE"));
 	}
 	return 1;
 }
@@ -23792,7 +23734,6 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
 	if (statechanged) {
 		const char *s = is_reachable ? "Reachable" : "Lagged";
 		char str_lastms[20];
-
 		snprintf(str_lastms, sizeof(str_lastms), "%d", pingtime);
 
 		ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
@@ -23801,18 +23742,11 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
 		if (sip_cfg.peer_rtupdate) {
 			ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL);
 		}
-		if (peer->endpoint) {
-			RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-			ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
-			blob = ast_json_pack("{s: s, s: i}",
-				"peer_status", s,
-				"time", pingtime);
-			ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-		}
-
-		if (is_reachable && sip_cfg.regextenonqualify) {
+		manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
+			"ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: %s\r\nTime: %d\r\n",
+			peer->name, s, pingtime);
+		if (is_reachable && sip_cfg.regextenonqualify)
 			register_peer_exten(peer, TRUE);
-		}
 	}
 
 	pvt_set_needdestroy(p, "got OPTIONS response");
@@ -24004,7 +23938,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 			ast_channel_hangupcause_set(owner, hangup_sip2cause(resp));
 	}
 
-	if (p->socket.type == AST_TRANSPORT_UDP) {
+	if (p->socket.type == SIP_TRANSPORT_UDP) {
 		int ack_res = FALSE;
 
 		/* Acknowledge whatever it is destined for */
@@ -24187,16 +24121,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 				handle_response_invite(p, resp, rest, req, seqno);
 			}
 			break;
-		case 480:
-			if (sipmethod == SIP_INVITE) {
-				handle_response_invite(p, resp, rest, req, seqno);
-			} else if (sipmethod == SIP_SUBSCRIBE) {
-				handle_response_subscribe(p, resp, rest, req, seqno);
-			} else if (owner) {
-				/* No specific handler. Default to congestion */
-				ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-			}
-			break;
+
 		case 481: /* Call leg does not exist */
 			if (sipmethod == SIP_INVITE) {
 				handle_response_invite(p, resp, rest, req, seqno);
@@ -24253,7 +24178,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 				/* Fatal response */
 				if ((resp != 487))
 					ast_verb(3, "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_sockaddr_stringify(&p->sa));
-
+	
 				if (sipmethod == SIP_INVITE)
 					stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 
@@ -24285,6 +24210,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 					}
 					break;
 				case 482: /* Loop Detected */
+				case 480: /* Temporarily Unavailable */
 				case 404: /* Not Found */
 				case 410: /* Gone */
 				case 400: /* Bad Request */
@@ -24313,7 +24239,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 					}
 					break;
 				default:
-					/* Send hangup */
+					/* Send hangup */	
 					if (owner && sipmethod != SIP_BYE)
 						ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp));
 					break;
@@ -24339,7 +24265,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 			} else
 				ast_log(LOG_NOTICE, "Don't know how to handle a %d %s response from %s\n", resp, rest, p->owner ? ast_channel_name(p->owner) : ast_sockaddr_stringify(&p->sa));
 		}
-	} else {
+	} else {	
 		/* Responses to OUTGOING SIP requests on INCOMING calls
 		   get handled here. As well as out-of-call message responses */
 		if (req->debug)
@@ -24424,6 +24350,167 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
 	}
 }
 
+
+/*! \brief Park SIP call support function
+	Starts in a new thread, then parks the call
+	XXX Should we add a wait period after streaming audio and before hangup?? Sometimes the
+		audio can't be heard before hangup
+*/
+static void *sip_park_thread(void *stuff)
+{
+	struct ast_channel *transferee, *transferer;	/* Chan1: The transferee, Chan2: The transferer */
+	struct sip_pvt *transferer_pvt;
+	struct sip_dual *d;
+	int ext;
+	int res;
+
+	d = stuff;
+	transferee = d->chan1;
+	transferer = d->chan2;
+	transferer_pvt = ast_channel_tech_pvt(transferer);
+
+	ast_debug(4, "SIP Park: Transferer channel %s, Transferee %s\n", ast_channel_name(transferer), ast_channel_name(transferee));
+
+	res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext);
+
+	sip_pvt_lock(transferer_pvt);
+#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
+	if (res) {
+		destroy_msg_headers(transferer_pvt);
+		ast_string_field_set(transferer_pvt, msg_body, "Unable to park call.");
+		transmit_message(transferer_pvt, 0, 0);
+	} else {
+		/* Then tell the transferer what happened */
+		destroy_msg_headers(transferer_pvt);
+		sprintf(buf, "Call parked on extension '%d'.", ext);
+		ast_string_field_set(transferer_pvt, msg_body, buf);
+		transmit_message(transferer_pvt, 0, 0);
+	}
+#endif
+
+	/* Any way back to the current call??? */
+	/* Transmit response to the REFER request */
+	ast_set_flag(&transferer_pvt->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
+	if (!res)	{
+		/* Transfer succeeded */
+		append_history(transferer_pvt, "SIPpark", "Parked call on %d", ext);
+		transmit_notify_with_sipfrag(transferer_pvt, d->seqno, "200 OK", TRUE);
+		sip_pvt_unlock(transferer_pvt);
+		ast_channel_hangupcause_set(transferer, AST_CAUSE_NORMAL_CLEARING);
+		ast_debug(1, "SIP Call parked on extension '%d'\n", ext);
+	} else {
+		transmit_notify_with_sipfrag(transferer_pvt, d->seqno, "503 Service Unavailable", TRUE);
+		append_history(transferer_pvt, "SIPpark", "Parking failed\n");
+		sip_pvt_unlock(transferer_pvt);
+		ast_log(AST_LOG_NOTICE, "SIP Call parked failed for %s\n", ast_channel_name(transferee));
+		ast_hangup(transferee);
+	}
+	ast_hangup(transferer);
+
+	deinit_req(&d->req);
+	ast_free(d->park_exten);
+	ast_free(d->park_context);
+	ast_free(d);
+	return NULL;
+}
+
+/*! DO NOT hold any locks while calling sip_park */
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, uint32_t seqno, const char *park_exten, const char *park_context)
+{
+	struct sip_dual *d;
+	struct ast_channel *transferee, *transferer;
+	pthread_t th;
+
+	transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(chan1), ast_channel_exten(chan1), ast_channel_context(chan1), ast_channel_linkedid(chan1), ast_channel_amaflags(chan1), "Parking/%s", ast_channel_name(chan1));
+	transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(chan2), ast_channel_exten(chan2), ast_channel_context(chan2), ast_channel_linkedid(chan2), ast_channel_amaflags(chan2), "SIPPeer/%s", ast_channel_name(chan2));
+	d = ast_calloc(1, sizeof(*d));
+	if (!transferee || !transferer || !d) {
+		if (transferee) {
+			ast_hangup(transferee);
+		}
+		if (transferer) {
+			ast_hangup(transferer);
+		}
+		ast_free(d);
+		return -1;
+	}
+	d->park_exten = ast_strdup(park_exten);
+	d->park_context = ast_strdup(park_context);
+	if (!d->park_exten || !d->park_context) {
+		ast_hangup(transferee);
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(transferee), ast_channel_readformat(chan1));
+	ast_format_copy(ast_channel_writeformat(transferee), ast_channel_writeformat(chan1));
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(transferee, chan1)) {
+		ast_hangup(transferee);
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_channel_context_set(transferee, ast_channel_context(chan1));
+	ast_channel_exten_set(transferee, ast_channel_exten(chan1));
+	ast_channel_priority_set(transferee, ast_channel_priority(chan1));
+
+	ast_do_masquerade(transferee);
+
+	/* We make a clone of the peer channel too, so we can play
+	   back the announcement */
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(transferer), ast_channel_readformat(chan2));
+	ast_format_copy(ast_channel_writeformat(transferer), ast_channel_writeformat(chan2));
+	ast_channel_parkinglot_set(transferer, ast_channel_parkinglot(chan2));
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(transferer, chan2)) {
+		ast_hangup(transferee);
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_channel_context_set(transferer, ast_channel_context(chan2));
+	ast_channel_exten_set(transferer, ast_channel_exten(chan2));
+	ast_channel_priority_set(transferer, ast_channel_priority(chan2));
+
+	ast_do_masquerade(transferer);
+
+	/* Save original request for followup */
+	copy_request(&d->req, req);
+	d->chan1 = transferee;	/* Transferee */
+	d->chan2 = transferer;	/* Transferer */
+	d->seqno = seqno;
+	if (ast_pthread_create_detached_background(&th, NULL, sip_park_thread, d) < 0) {
+		/* Could not start thread */
+		ast_hangup(transferer);
+		ast_hangup(transferee);
+		deinit_req(&d->req);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);	/* We don't need it anymore. If thread is created, d will be free'd
+				   by sip_park_thread() */
+		return -1;
+	}
+	return 0;
+}
+
+
 /*! \brief SIP pickup support function
  *	Starts in a new thread, then pickup the call
  */
@@ -24432,10 +24519,9 @@ static void *sip_pickup_thread(void *stuff)
 	struct ast_channel *chan;
 	chan = stuff;
 
+	ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL_CLEARING);
 	if (ast_pickup_call(chan)) {
 		ast_channel_hangupcause_set(chan, AST_CAUSE_CALL_REJECTED);
-	} else {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL_CLEARING);
 	}
 	ast_hangup(chan);
 	ast_channel_unref(chan);
@@ -24461,6 +24547,92 @@ static int sip_pickup(struct ast_channel *chan)
 	return 0;
 }
 
+
+/*! \brief Turn off generator data
+	XXX Does this function belong in the SIP channel?
+*/
+static void ast_quiet_chan(struct ast_channel *chan)
+{
+	if (chan && ast_channel_state(chan) == AST_STATE_UP) {
+		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
+			ast_moh_stop(chan);
+		else if (ast_channel_generatordata(chan))
+			ast_deactivate_generator(chan);
+	}
+}
+
+/*! \brief Attempt transfer of SIP call
+	This fix for attended transfers on a local PBX */
+static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target)
+{
+	int res = 0;
+	struct ast_channel *peera = NULL,
+		*peerb = NULL,
+		*peerc = NULL,
+		*peerd = NULL;
+
+
+	/* We will try to connect the transferee with the target and hangup
+	   all channels to the transferer */
+	ast_debug(4, "Sip transfer:--------------------\n");
+	if (transferer->chan1)
+		ast_debug(4, "-- Transferer to PBX channel: %s State %s\n", ast_channel_name(transferer->chan1), ast_state2str(ast_channel_state(transferer->chan1)));
+	else
+		ast_debug(4, "-- No transferer first channel - odd??? \n");
+	if (target->chan1)
+		ast_debug(4, "-- Transferer to PBX second channel (target): %s State %s\n", ast_channel_name(target->chan1), ast_state2str(ast_channel_state(target->chan1)));
+	else
+		ast_debug(4, "-- No target first channel ---\n");
+	if (transferer->chan2)
+		ast_debug(4, "-- Bridged call to transferee: %s State %s\n", ast_channel_name(transferer->chan2), ast_state2str(ast_channel_state(transferer->chan2)));
+	else
+		ast_debug(4, "-- No bridged call to transferee\n");
+	if (target->chan2)
+		ast_debug(4, "-- Bridged call to transfer target: %s State %s\n", target->chan2 ? ast_channel_name(target->chan2) : "<none>", target->chan2 ? ast_state2str(ast_channel_state(target->chan2)) : "(none)");
+	else
+		ast_debug(4, "-- No target second channel ---\n");
+	ast_debug(4, "-- END Sip transfer:--------------------\n");
+	if (transferer->chan2) { /* We have a bridge on the transferer's channel */
+		peera = transferer->chan1;	/* Transferer - PBX -> transferee channel * the one we hangup */
+		peerb = target->chan1;		/* Transferer - PBX -> target channel - This will get lost in masq */
+		peerc = transferer->chan2;	/* Asterisk to Transferee */
+		peerd = target->chan2;		/* Asterisk to Target */
+		ast_debug(3, "SIP transfer: Four channels to handle\n");
+	} else if (target->chan2) {	/* Transferer has no bridge (IVR), but transferee */
+		peera = target->chan1;		/* Transferer to PBX -> target channel */
+		peerb = transferer->chan1;	/* Transferer to IVR*/
+		peerc = target->chan2;		/* Asterisk to Target */
+		peerd = transferer->chan2;	/* Nothing */
+		ast_debug(3, "SIP transfer: Three channels to handle\n");
+	}
+
+	if (peera && peerb && peerc && (peerb != peerc)) {
+		ast_quiet_chan(peera);		/* Stop generators */
+		/* no need to quiet peerb since it should be hungup after the
+		   transfer and the masquerade needs to be able to see if MOH is
+		   playing on it */
+		ast_quiet_chan(peerc);
+		if (peerd)
+			ast_quiet_chan(peerd);
+
+		ast_debug(4, "SIP transfer: trying to masquerade %s into %s\n", ast_channel_name(peerc), ast_channel_name(peerb));
+		if (ast_channel_masquerade(peerb, peerc)) {
+			ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", ast_channel_name(peerb), ast_channel_name(peerc));
+			res = -1;
+		} else
+			ast_debug(4, "SIP transfer: Succeeded to masquerade channels.\n");
+		return res;
+	} else {
+		ast_log(LOG_NOTICE, "SIP Transfer attempted with no appropriate bridged calls to transfer\n");
+		if (transferer->chan1)
+			ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV);
+		if (target->chan1)
+			ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV);
+		return -1;
+	}
+	return 0;
+}
+
 /*! \brief Get tag from packet
  *
  * \return Returns the pointer to the provided tag buffer,
@@ -24595,7 +24767,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
 		A minimal, but complete, implementation can respond with a single
 		NOTIFY containing either the body:
 			SIP/2.0 100 Trying
-
+		
 		if the subscription is pending, the body:
 			SIP/2.0 200 OK
 		if the reference was successful, the body:
@@ -24606,7 +24778,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
 		if the REFER request was accepted before approval to follow the
 		reference could be obtained and that approval was subsequently denied
 		(see Section 2.4.7).
-
+		
 		If there are several REFERs in the same dialog, we need to
 		match the ID of the event header...
 		*/
@@ -24683,9 +24855,16 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
 		if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(c)) {
 			char *old = strsep(&c, " ");
 			char *new = strsep(&old, "/");
+			struct ast_event *event;
 
-			ast_publish_mwi_state(mailbox, "SIP_Remote", atoi(new), atoi(old));
-
+			if ((event = ast_event_new(AST_EVENT_MWI,
+						   AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+						   AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "SIP_Remote",
+						   AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(new),
+						   AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(old),
+						   AST_EVENT_IE_END))) {
+				ast_event_queue_and_cache(event);
+			}
 			transmit_response(p, "200 OK", req);
 		} else {
 			transmit_response(p, "489 Bad event", req);
@@ -24743,7 +24922,7 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st
 
 	/* must go through authentication before getting here */
 	gotdest = get_destination(p, req, NULL);
-	build_contact(p);
+	build_contact(p, req, 1);
 
 	if (ast_strlen_zero(p->context))
 		ast_string_field_set(p, context, sip_cfg.default_context);
@@ -24776,71 +24955,148 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st
 }
 
 /*! \brief Handle the transfer part of INVITE with a replaces: header,
- *
- * This is used for call-pickup and for attended transfers initiated on
- * remote endpoints (i.e. a REFER received on a remote server).
- *
- * \note p and p->owner are locked upon entering this function. If the
- * call pickup or attended transfer is successful, then p->owner will
- * be unlocked upon exiting this function. This is communicated to the
- * caller through the nounlock parameter.
- *
- * \param p The sip_pvt where the INVITE with Replaces was received
- * \param req The incoming INVITE
- * \param[out] nounlock Indicator if p->owner should remained locked. On successful transfer, this will be set true.
- * \param replaces_pvt sip_pvt referenced by Replaces header
- * \param replaces_chan replaces_pvt's owner channel
- * \retval 0 Success
- * \retval non-zero Failure
+    meaning a target pickup or an attended transfer.
+    Used only once.
+	XXX 'ignore' is unused.
+
+	\note this function is called by handle_request_invite(). Four locks
+	held at the beginning of this function, p, p->owner, p->refer->refer_call and
+	p->refere->refer_call->owner.  only p's lock should remain at the end of this
+	function.  p's lock as well as the channel p->owner's lock are held by
+	handle_request_do(), we unlock p->owner before the masq.  By setting nounlock
+	we are indicating to handle_request_do() that we have already unlocked the owner.
  */
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req,
-		int *nounlock, struct sip_pvt *replaces_pvt, struct ast_channel *replaces_chan)
+static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, int *nounlock)
 {
-	struct ast_channel *c;
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+	int earlyreplace = 0;
+	int oneleggedreplace = 0;		/* Call with no bridge, propably IVR or voice message */
+	struct ast_channel *c = p->owner;	/* Our incoming call */
+	struct ast_channel *replacecall = p->refer->refer_call->owner;	/* The channel we're about to take over */
+	struct ast_channel *targetcall;		/* The bridge to the take-over target */
 
-	if (req->ignore) {
-		return 0;
+	p->refer->refer_call->invitereplaces = 1;
+
+	/* Check if we're in ring state */
+	if (ast_channel_state(replacecall) == AST_STATE_RING)
+		earlyreplace = 1;
+
+	/* Check if we have a bridge */
+	if (!(targetcall = ast_bridged_channel(replacecall))) {
+		/* We have no bridge */
+		if (!earlyreplace) {
+			ast_debug(2, "	Attended transfer attempted to replace call with no bridge (maybe ringing). Channel %s!\n", ast_channel_name(replacecall));
+			oneleggedreplace = 1;
+		}
 	}
+	if (targetcall && ast_channel_state(targetcall) == AST_STATE_RINGING)
+		ast_debug(4, "SIP transfer: Target channel is in ringing state\n");
 
-	if (!p->owner) {
+	if (targetcall)
+		ast_debug(4, "SIP transfer: Invite Replace incoming channel should bridge to channel %s while hanging up channel %s\n", ast_channel_name(targetcall), ast_channel_name(replacecall));
+	else
+		ast_debug(4, "SIP transfer: Invite Replace incoming channel should replace and hang up channel %s (one call leg)\n", ast_channel_name(replacecall));
+
+	if (req->ignore) {
+		ast_log(LOG_NOTICE, "Ignoring this INVITE with replaces in a stupid way.\n");
+		/* We should answer something here. If we are here, the
+			call we are replacing exists, so an accepted
+			can't harm */
+		transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
+		/* Do something more clever here */
+		if (c) {
+			*nounlock = 1;
+			ast_channel_unlock(c);
+		}
+		ast_channel_unlock(replacecall);
+		sip_pvt_unlock(p->refer->refer_call);
+		return 1;
+	}
+	if (!c) {
 		/* What to do if no channel ??? */
 		ast_log(LOG_ERROR, "Unable to create new channel.  Invite/replace failed.\n");
 		transmit_response_reliable(p, "503 Service Unavailable", req);
 		append_history(p, "Xfer", "INVITE/Replace Failed. No new channel.");
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+		ast_channel_unlock(replacecall);
+		sip_pvt_unlock(p->refer->refer_call);
 		return 1;
 	}
 	append_history(p, "Xfer", "INVITE/Replace received");
-
-	c = ast_channel_ref(p->owner);
+	/* We have three channels to play with
+		channel c: New incoming call
+		targetcall: Call from PBX to target
+		p->refer->refer_call: SIP pvt dialog from transferer to pbx.
+		replacecall: The owner of the previous
+		We need to masq C into refer_call to connect to
+		targetcall;
+		If we are talking to internal audio stream, target call is null.
+	*/
 
 	/* Fake call progress */
 	transmit_response(p, "100 Trying", req);
 	ast_setstate(c, AST_STATE_RING);
 
-	ast_debug(4, "Invite/Replaces: preparing to replace %s with %s\n", ast_channel_name(replaces_chan), ast_channel_name(c));
+	/* Masquerade the new call into the referred call to connect to target call
+	   Targetcall is not touched by the masq */
 
-	*nounlock = 1;
-	ast_channel_unlock(c);
-	sip_pvt_unlock(p);
+	/* Answer the incoming call and set channel to UP state */
+	transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE);
 
-	ast_raw_answer(c);
+	/* Is this a call pickup? */
+	if (earlyreplace || oneleggedreplace) {
+		/* Report pickup event, in this order: PICKUP, CHAN_UP, ANSWER */
+		ast_cel_report_event(replacecall, AST_CEL_PICKUP, NULL, NULL, c);
+		ast_setstate(c, AST_STATE_UP);
+		ast_cel_report_event(c, AST_CEL_ANSWER, NULL, NULL, NULL);
+	} else {
+		ast_setstate(c, AST_STATE_UP);
+	}
 
-	ast_channel_lock(replaces_chan);
-	bridge = ast_channel_get_bridge(replaces_chan);
-	ast_channel_unlock(replaces_chan);
+	/* Stop music on hold and other generators */
+	ast_quiet_chan(replacecall);
+	ast_quiet_chan(targetcall);
+	ast_debug(4, "Invite/Replaces: preparing to masquerade %s into %s\n", ast_channel_name(c), ast_channel_name(replacecall));
 
-	if (bridge) {
-		if (ast_bridge_impart(bridge, c, replaces_chan, NULL,
-			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-			ast_hangup(c);
-		}
-	} else {
-		ast_channel_move(replaces_chan, c);
-		ast_hangup(c);
+	/* Make sure that the masq does not free our PVT for the old call */
+	if (! earlyreplace && ! oneleggedreplace )
+		ast_set_flag(&p->refer->refer_call->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Delay hangup */
+
+	/* Prepare the masquerade - if this does not happen, we will be gone */
+	if(ast_channel_masquerade(replacecall, c))
+		ast_log(LOG_ERROR, "Failed to masquerade C into Replacecall\n");
+	else
+		ast_debug(4, "Invite/Replaces: Going to masquerade %s into %s\n", ast_channel_name(c), ast_channel_name(replacecall));
+
+	/* C should now be in place of replacecall. all channel locks and pvt locks should be removed
+	 * before issuing the masq.  Since we are unlocking both the pvt (p) and its owner channel (c)
+	 * it is possible for channel c to be destroyed on us.  To prevent this, we must give c a reference
+	 * before any unlocking takes place and remove it only once we are completely done with it */
+	ast_channel_ref(c);
+	ast_channel_unlock(replacecall);
+	ast_channel_unlock(c);
+	sip_pvt_unlock(p->refer->refer_call);
+	sip_pvt_unlock(p);
+	if (ast_do_masquerade(replacecall)) {
+		ast_log(LOG_WARNING, "Failed to perform masquerade with INVITE replaces\n");
 	}
+	if (earlyreplace || oneleggedreplace ) {
+		ast_channel_lock(c);
+		ast_channel_hangupcause_set(c, AST_CAUSE_SWITCH_CONGESTION);
+		ast_channel_unlock(c);
+	}
+
+	/* Clear SIP_DEFER_BYE_ON_TRANSFER after the masq to avoid delay hanging up replaced channel */
 	sip_pvt_lock(p);
+	ast_clear_flag(&p->refer->refer_call->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
+	sip_pvt_unlock(p);
+
+	/* c and c's tech pvt must be unlocked at this point for ast_hangup */
+	ast_hangup(c);
+	/* this indicates to handle_request_do that the owner channel has already been unlocked */
+	*nounlock = 1;
+	/* lock PVT structure again after hangup */
+	sip_pvt_lock(p);
+	ast_channel_unref(c);
 	return 0;
 }
 
@@ -24888,6 +25144,39 @@ static int sip_t38_abort(const void *data)
 	return 0;
 }
 
+/*! \brief Checks state of the p->refer->refer_call state: can it be picked up?
+ *
+ * It will terminate the call if it cannot be picked up; e.g. because it
+ * was gone, or because it wasn't in a ringing state.
+ *
+ * \return 1 if terminated, 0 if ok
+ */
+static int terminate_on_invalid_replaces_state(struct sip_pvt *p, struct sip_request *req, const char *replace_id)
+{
+	if (p->refer->refer_call == p) {
+		ast_log(LOG_NOTICE, "INVITE with replaces into its own call id (%s == %s)!\n", replace_id, p->callid);
+		transmit_response_reliable(p, "400 Bad request", req);	/* The best way to not not accept the transfer */
+
+	} else if (!p->refer->refer_call->owner) {
+		/* Oops, someting wrong anyway, no owner, no call */
+		ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
+		/* Check for better return code */
+		transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replace)", req);
+
+	} else if (ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RINGING &&
+			ast_channel_state(p->refer->refer_call->owner) != AST_STATE_RING &&
+			ast_channel_state(p->refer->refer_call->owner) != AST_STATE_UP) {
+		ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
+		transmit_response_reliable(p, "603 Declined (Replaces)", req);
+
+	} else {
+		/* Ok */
+		return 0;
+	}
+	/* Terminated */
+	return 1;
+}
+
 /*!
  * \brief bare-bones support for SIP UPDATE
  *
@@ -25089,6 +25378,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 	int gotdest;
 	const char *p_replaces;
 	char *replace_id = NULL;
+	int magic_call_id = 0;
+	int refer_locked = 0;
 	const char *required;
 	unsigned int required_profile = 0;
 	struct ast_channel *c = NULL;		/* New channel */
@@ -25105,8 +25396,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 	} pickup = {
 			.exten = "",
 	};
-	RAII_VAR(struct sip_pvt *, replaces_pvt, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, replaces_chan, NULL, ao2_cleanup);
 
 	/* Find out what they support */
 	if (!p->sipoptions) {
@@ -25212,6 +25501,21 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 		} else {
 			/* We already have a pending invite. Sorry. You are on hold. */
 			p->glareinvite = seqno;
+			if (p->rtp && find_sdp(req)) {
+				struct ast_sockaddr addr;
+				if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &addr)) {
+					ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
+				} else {
+					ast_rtp_instance_set_alt_remote_address(p->rtp, &addr);
+				}
+				if (p->vrtp) {
+					if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &addr)) {
+						ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
+					} else {
+						ast_rtp_instance_set_alt_remote_address(p->vrtp, &addr);
+					}
+				}
+			}
 			transmit_response_reliable(p, "491 Request Pending", req);
 			check_via(p, req);
 			ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
@@ -25290,60 +25594,57 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 		   First we cheat a little and look for a magic call-id from phones that support
 		   dialog-info+xml so we can do technology independent pickup... */
 		if (strncmp(replace_id, "pickup-", 7) == 0) {
-			RAII_VAR(struct sip_pvt *, subscription, NULL, ao2_cleanup);
-			RAII_VAR(struct ast_channel *, subscription_chan, NULL, ao2_cleanup);
-
+			struct sip_pvt *subscription = NULL;
 			replace_id += 7; /* Worst case we are looking at \0 */
 
-			if (get_sip_pvt_from_replaces(replace_id, totag, fromtag, &subscription, &subscription_chan)) {
+			if ((subscription = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
 				ast_log(LOG_NOTICE, "Unable to find subscription with call-id: %s\n", replace_id);
 				transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
 				error = 1;
 			} else {
-				SCOPED_LOCK(lock, subscription, sip_pvt_lock, sip_pvt_unlock);
 				ast_log(LOG_NOTICE, "Trying to pick up %s@%s\n", subscription->exten, subscription->context);
 				ast_copy_string(pickup.exten, subscription->exten, sizeof(pickup.exten));
 				ast_copy_string(pickup.context, subscription->context, sizeof(pickup.context));
+				sip_pvt_unlock(subscription);
+				if (subscription->owner) {
+					ast_channel_unlock(subscription->owner);
+				}
+				subscription = dialog_unref(subscription, "unref dialog subscription");
+				magic_call_id = !ast_strlen_zero(pickup.exten);
 			}
 		}
 
-		if (!error && ast_strlen_zero(pickup.exten) && get_sip_pvt_from_replaces(replace_id,
-					totag, fromtag, &replaces_pvt, &replaces_chan)) {
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
-			transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
-			error = 1;
-		}
-
-		/* The matched call is the call from the transferer to Asterisk .
-			We want to bridge the bridged part of the call to the
-			incoming invite, thus taking over the refered call */
-
-		if (replaces_pvt == p) {
-			ast_log(LOG_NOTICE, "INVITE with replaces into it's own call id (%s == %s)!\n", replace_id, p->callid);
-			transmit_response_reliable(p, "400 Bad request", req);	/* The best way to not not accept the transfer */
-			error = 1;
-		}
-
-		if (!error && ast_strlen_zero(pickup.exten) && !replaces_chan) {
-			/* Oops, someting wrong anyway, no owner, no call */
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
-			/* Check for better return code */
-			transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replace)", req);
-			error = 1;
-		}
-
-		if (!error && ast_strlen_zero(pickup.exten) &&
-				ast_channel_state(replaces_chan) != AST_STATE_RINGING &&
-				ast_channel_state(replaces_chan) != AST_STATE_RING &&
-				ast_channel_state(replaces_chan) != AST_STATE_UP) {
-			ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
-			transmit_response_reliable(p, "603 Declined (Replaces)", req);
-			error = 1;
+		if (!error) {
+			if (magic_call_id) {
+				;
+			/* This locks both refer_call pvt and refer_call pvt's owner!!!*/
+			} else if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag))) {
+				/* The matched call is the call from the transferer to Asterisk .
+					We want to bridge the bridged part of the call to the
+					incoming invite, thus taking over the refered call */
+				refer_locked = 1;
+				if (terminate_on_invalid_replaces_state(p, req, replace_id)) {
+					error = 1;
+				}
+			} else {
+				ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
+				transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
+				error = 1;
+			}
 		}
 
 		if (error) {	/* Give up this dialog */
 			append_history(p, "Xfer", "INVITE/Replace Failed.");
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+			sip_pvt_unlock(p);
+			if (p->refer->refer_call) {
+				sip_pvt_unlock(p->refer->refer_call);
+				if (p->refer->refer_call->owner) {
+					ast_channel_unlock(p->refer->refer_call->owner);
+				}
+				p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
+			}
+			refer_locked = 0;
 			p->invitestate = INV_COMPLETED;
 			res = INV_REQ_ERROR;
 			check_via(p, req);
@@ -25418,14 +25719,13 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 				}
 				ast_queue_control(p->owner, AST_CONTROL_SRCUPDATE);
 			} else {
-				ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-				ast_format_cap_append_from_cap(p->jointcaps, p->caps, AST_MEDIA_TYPE_UNKNOWN);
+				ast_format_cap_copy(p->jointcaps, p->caps);
 				ast_debug(1, "Hm....  No sdp for the moment\n");
 				/* Some devices signal they want to be put off hold by sending a re-invite
 				   *without* an SDP, which is supposed to mean "Go back to your state"
 				   and since they put os on remote hold, we go back to off hold */
 				if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
-					ast_queue_unhold(p->owner);
+					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 					/* Activate a re-invite */
 					ast_queue_frame(p->owner, &ast_null_frame);
 					change_hold_state(p, req, FALSE, 0);
@@ -25484,8 +25784,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 				goto request_invite_cleanup;
 			}
 		} else {	/* No SDP in invite, call control session */
-			ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN);
-			ast_format_cap_append_from_cap(p->jointcaps, p->caps, AST_MEDIA_TYPE_UNKNOWN);
+			ast_format_cap_copy(p->jointcaps, p->caps);
 			ast_debug(2, "No SDP in Invite, third party call control\n");
 		}
 
@@ -25509,8 +25808,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 			goto request_invite_cleanup;
 		}
 		gotdest = get_destination(p, NULL, &cc_recall_core_id);	/* Get destination right away */
-		extract_uri(p, req);			/* Get the Contact URI */
-		build_contact(p);			/* Build our contact header */
+		extract_uri(p, req);        /* Get the Contact URI */
+		build_contact(p, req, 1);   /* Build our contact header */
 
 		if (p->rtp) {
 			ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
@@ -25573,10 +25872,51 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 				goto request_invite_cleanup;
 			}
 
+			/* We cannot call sip_new with any channel locks
+			 * held. Unlock the referred channel if locked. */
+			if (refer_locked) {
+				sip_pvt_unlock(p->refer->refer_call);
+				if (p->refer->refer_call->owner) {
+					ast_channel_unlock(p->refer->refer_call->owner);
+				}
+			}
+
 			/* First invitation - create the channel.  Allocation
 			 * failures are handled below. */
+			c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL, p->logger_callid);
+
+			/* Reacquire the lock on the referred call. */
+			if (refer_locked) {
+				/* Reuse deadlock avoid pattern found in
+				 * get_sip_pvt_byid_locked. */
+				sip_pvt_lock(p->refer->refer_call);
+				while (p->refer->refer_call->owner && ast_channel_trylock(p->refer->refer_call->owner)) {
+					sip_pvt_unlock(p->refer->refer_call);
+					usleep(1);
+					sip_pvt_lock(p->refer->refer_call);
+				}
 
-			c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL, NULL, p->logger_callid);
+				/* And now, check once more that the call is still
+				 * still available. Yuck. Bail out if it isn't. */
+				if (terminate_on_invalid_replaces_state(p, req, replace_id)) {
+					/* Free the referred call: it's not ours anymore. */
+					sip_pvt_unlock(p->refer->refer_call);
+					if (p->refer->refer_call->owner) {
+						ast_channel_unlock(p->refer->refer_call->owner);
+					}
+					p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
+					refer_locked = 0;
+					/* Kill the channel we just created. */
+					sip_pvt_unlock(p);
+					ast_hangup(c);
+					sip_pvt_lock(p); /* pvt is expected to remain locked on return, so re-lock it */
+					/* Mark the call as failed. */
+					sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+					p->invitestate = INV_COMPLETED;
+					res = INV_REQ_ERROR;
+					goto request_invite_cleanup;
+				}
+			}
 
 			if (cc_recall_core_id != -1) {
 				ast_setup_cc_recall_datastore(c, cc_recall_core_id);
@@ -25636,7 +25976,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 		p->lastinvite = seqno;
 
 	if (c && replace_id) {	/* Attended transfer or call pickup - we're the target */
-		if (!ast_strlen_zero(pickup.exten)) {
+		if (magic_call_id) {
 			append_history(p, "Xfer", "INVITE/Replace received");
 
 			/* Let the caller know we're giving it a shot */
@@ -25665,7 +26005,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 			/* Go and take over the target call */
 			if (sipdebug)
 				ast_debug(4, "Sending this call to the invite/replaces handler %s\n", p->callid);
-			res = handle_invite_replaces(p, req, nounlock, replaces_pvt, replaces_chan);
+			res = handle_invite_replaces(p, req, addr, seqno, nounlock);
+			refer_locked = 0;
 			goto request_invite_cleanup;
 		}
 	}
@@ -25673,15 +26014,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 
 	if (c) {	/* We have a call  -either a new call or an old one (RE-INVITE) */
 		enum ast_channel_state c_state = ast_channel_state(c);
-		RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, ast_get_chan_features_pickup_config(c), ao2_cleanup);
-		const char *pickupexten;
-
-		if (!pickup_cfg) {
-			ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-			pickupexten = "";
-		} else {
-			pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-		}
 
 		if (c_state != AST_STATE_UP && reinvite &&
 			(p->invitestate == INV_TERMINATED || p->invitestate == INV_CONFIRMED)) {
@@ -25703,18 +26035,20 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 			transmit_provisional_response(p, "100 Trying", req, 0);
 			p->invitestate = INV_PROCEEDING;
 			ast_setstate(c, AST_STATE_RING);
-			if (strcmp(p->exten, pickupexten)) {	/* Call to extension -start pbx on this call */
+			if (strcmp(p->exten, ast_pickup_ext())) {	/* Call to extension -start pbx on this call */
 				enum ast_pbx_result result;
 
 				result = ast_pbx_start(c);
 
 				switch(result) {
 				case AST_PBX_FAILED:
+					sip_alreadygone(p);
 					ast_log(LOG_WARNING, "Failed to start PBX :(\n");
 					p->invitestate = INV_COMPLETED;
 					transmit_response_reliable(p, "503 Unavailable", req);
 					break;
 				case AST_PBX_CALL_LIMIT:
+					sip_alreadygone(p);
 					ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
 					p->invitestate = INV_COMPLETED;
 					transmit_response_reliable(p, "480 Temporarily Unavailable", req);
@@ -25778,7 +26112,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 				transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)));
 			} else if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
 				/* If this is not a re-invite or something to ignore - it's critical */
-				if (p->srtp && !ast_test_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK)) {
+				if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
 					ast_log(LOG_WARNING, "Target does not support required crypto\n");
 					transmit_response_reliable(p, "488 Not Acceptable Here (crypto)", req);
 				} else {
@@ -25799,7 +26133,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 		if (!req->ignore && p && (p->autokillid == -1)) {
 			const char *msg;
 
-			if ((!ast_format_cap_count(p->jointcaps)))
+			if ((ast_format_cap_is_empty(p->jointcaps)))
 				msg = "488 Not Acceptable Here (codec error)";
 			else {
 				ast_log(LOG_NOTICE, "Unable to create/find SIP channel for this INVITE\n");
@@ -25813,6 +26147,13 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
 
 request_invite_cleanup:
 
+	if (refer_locked) {
+		sip_pvt_unlock(p->refer->refer_call);
+		if (p->refer->refer_call->owner) {
+			ast_channel_unlock(p->refer->refer_call->owner);
+		}
+		p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
+	}
 	if (authpeer) {
 		authpeer = sip_unref_peer(authpeer, "sip_unref_peer, from handle_request_invite authpeer");
 	}
@@ -25868,7 +26209,7 @@ static void parse_oli(struct sip_request *req, struct ast_channel *chan)
 /*! \brief  Find all call legs and bridge transferee with target
  *	called from handle_request_refer
  *
- *	\note this function assumes two locks to begin with, sip_pvt transferer and current.chan1 (the pvt's owner)...
+ *	\note this function assumes two locks to begin with, sip_pvt transferer and current.chan1 (the pvt's owner)... 
  *	2 additional locks are held at the beginning of the function, targetcall_pvt, and targetcall_pvt's owner
  *	channel (which is stored in target.chan1).  These 2 locks _MUST_ be let go by the end of the function.  Do
  *	not be confused into thinking a pvt's owner is the same thing as the channels locked at the beginning of
@@ -25878,17 +26219,20 @@ static void parse_oli(struct sip_request *req, struct ast_channel *chan)
  *	If this function is successful, only the transferer pvt lock will remain on return.  Setting nounlock indicates
  *	to handle_request_do() that the pvt's owner it locked does not require an unlock.
  */
-static int local_attended_transfer(struct sip_pvt *transferer, struct ast_channel *transferer_chan, uint32_t seqno, int *nounlock)
+static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, uint32_t seqno, int *nounlock)
 {
-	RAII_VAR(struct sip_pvt *, targetcall_pvt, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, targetcall_chan, NULL, ao2_cleanup);
-	enum ast_transfer_result transfer_res;
+	struct sip_dual target;		/* Chan 1: Call from tranferer to Asterisk */
+					/* Chan 2: Call from Asterisk to target */
+	int res = 0;
+	struct sip_pvt *targetcall_pvt;
+	struct ast_party_connected_line connected_to_transferee;
+	struct ast_party_connected_line connected_to_target;
+	char transferer_linkedid[32];
+	struct ast_channel *chans[2];
 
 	/* Check if the call ID of the replaces header does exist locally */
-	if (get_sip_pvt_from_replaces(transferer->refer->replaces_callid,
-				transferer->refer->replaces_callid_totag,
-				transferer->refer->replaces_callid_fromtag,
-				&targetcall_pvt, &targetcall_chan)) {
+	if (!(targetcall_pvt = get_sip_pvt_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag,
+		transferer->refer->replaces_callid_fromtag))) {
 		if (transferer->refer->localtransfer) {
 			/* We did not find the refered call. Sorry, can't accept then */
 			/* Let's fake a response from someone else in order
@@ -25904,98 +26248,177 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct ast_channe
 		return 0;
 	}
 
-	if (!targetcall_chan) {	/* No active channel */
+	/* Ok, we can accept this transfer */
+	append_history(transferer, "Xfer", "Refer accepted");
+	if (!targetcall_pvt->owner) {	/* No active channel */
 		ast_debug(4, "SIP attended transfer: Error: No owner of target call\n");
 		/* Cancel transfer */
 		transmit_notify_with_sipfrag(transferer, seqno, "503 Service Unavailable", TRUE);
 		append_history(transferer, "Xfer", "Refer failed");
 		ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
 		transferer->refer->status = REFER_FAILED;
+		sip_pvt_unlock(targetcall_pvt);
+		if (targetcall_pvt)
+			ao2_t_ref(targetcall_pvt, -1, "Drop targetcall_pvt pointer");
 		return -1;
 	}
 
-	ast_set_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Delay hangup */
+	/* We have a channel, find the bridge */
+	target.chan1 = ast_channel_ref(targetcall_pvt->owner);				/* Transferer to Asterisk */
+	target.chan2 = ast_bridged_channel(targetcall_pvt->owner);	/* Asterisk to target */
+	if (target.chan2) {
+		ast_channel_ref(target.chan2);
+	}
 
-	sip_pvt_unlock(transferer);
-	ast_channel_unlock(transferer_chan);
-	*nounlock = 1;
+	if (!target.chan2 || !(ast_channel_state(target.chan2) == AST_STATE_UP || ast_channel_state(target.chan2) == AST_STATE_RINGING) ) {
+		/* Wrong state of new channel */
+		if (target.chan2)
+			ast_debug(4, "SIP attended transfer: Error: Wrong state of target call: %s\n", ast_state2str(ast_channel_state(target.chan2)));
+		else if (ast_channel_state(target.chan1) != AST_STATE_RING)
+			ast_debug(4, "SIP attended transfer: Error: No target channel\n");
+		else
+			ast_debug(4, "SIP attended transfer: Attempting transfer in ringing state\n");
+	}
 
-	transfer_res = ast_bridge_transfer_attended(transferer_chan, targetcall_chan);
+	/* Transfer */
+	if (sipdebug) {
+		if (current->chan2)	/* We have two bridges */
+			ast_debug(4, "SIP attended transfer: trying to bridge %s and %s\n", ast_channel_name(target.chan1), ast_channel_name(current->chan2));
+		else			/* One bridge, propably transfer of IVR/voicemail etc */
+			ast_debug(4, "SIP attended transfer: trying to make %s take over (masq) %s\n", ast_channel_name(target.chan1), ast_channel_name(current->chan1));
+	}
 
-	sip_pvt_lock(transferer);
+	ast_set_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Delay hangup */
 
-	switch (transfer_res) {
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		transferer->refer->status = REFER_200OK;
+	ast_copy_string(transferer_linkedid, ast_channel_linkedid(transferer->owner), sizeof(transferer_linkedid));
+
+	/* Perform the transfer */
+	chans[0] = transferer->owner;
+	chans[1] = target.chan1;
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans,
+		"TransferMethod: SIP\r\n"
+		"TransferType: Attended\r\n"
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"SIP-Callid: %s\r\n"
+		"TargetChannel: %s\r\n"
+		"TargetUniqueid: %s\r\n",
+		ast_channel_name(transferer->owner),
+		ast_channel_uniqueid(transferer->owner),
+		transferer->callid,
+		ast_channel_name(target.chan1),
+		ast_channel_uniqueid(target.chan1));
+	ast_party_connected_line_init(&connected_to_transferee);
+	ast_party_connected_line_init(&connected_to_target);
+	/* No need to lock current->chan1 here since it was locked in sipsock_read */
+	ast_party_connected_line_copy(&connected_to_transferee, ast_channel_connected(current->chan1));
+	/* No need to lock target.chan1 here since it was locked in get_sip_pvt_byid_locked */
+	ast_party_connected_line_copy(&connected_to_target, ast_channel_connected(target.chan1));
+	/* Reset any earlier private connected id representation */
+	ast_party_id_reset(&connected_to_transferee.priv);
+	ast_party_id_reset(&connected_to_target.priv);
+	connected_to_target.source = connected_to_transferee.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+	res = attempt_transfer(current, &target);
+	if (res) {
+		/* Failed transfer */
+		transmit_notify_with_sipfrag(transferer, seqno, "486 Busy Here", TRUE);
+		append_history(transferer, "Xfer", "Refer failed");
+		ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
+		/* if transfer failed, go ahead and unlock targetcall_pvt and it's owner channel */
+		sip_pvt_unlock(targetcall_pvt);
+		ast_channel_unlock(target.chan1);
+	} else {
+		/* Transfer succeeded! */
+		const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND");
+
+		/* target.chan1 was locked in get_sip_pvt_byid_locked, do not unlock target.chan1 before this */
+		ast_cel_report_event(target.chan1, AST_CEL_ATTENDEDTRANSFER, NULL, transferer_linkedid, target.chan2);
+
+		/* Tell transferer that we're done. */
 		transmit_notify_with_sipfrag(transferer, seqno, "200 OK", TRUE);
 		append_history(transferer, "Xfer", "Refer succeeded");
-		return 1;
-	case AST_BRIDGE_TRANSFER_FAIL:
-		transferer->refer->status = REFER_FAILED;
-		transmit_notify_with_sipfrag(transferer, seqno, "500 Internal Server Error", TRUE);
-		append_history(transferer, "Xfer", "Refer failed (internal error)");
-		ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		return -1;
-	case AST_BRIDGE_TRANSFER_INVALID:
-		transferer->refer->status = REFER_FAILED;
-		transmit_notify_with_sipfrag(transferer, seqno, "503 Service Unavailable", TRUE);
-		append_history(transferer, "Xfer", "Refer failed (invalid bridge state)");
-		ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		return -1;
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-		transferer->refer->status = REFER_FAILED;
-		transmit_notify_with_sipfrag(transferer, seqno, "403 Forbidden", TRUE);
-		append_history(transferer, "Xfer", "Refer failed (operation not permitted)");
-		ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		return -1;
-	default:
-		break;
-	}
+		transferer->refer->status = REFER_200OK;
+		if (target.chan2 && !ast_strlen_zero(xfersound) && ast_streamfile(target.chan2, xfersound, ast_channel_language(target.chan2)) >= 0) {
+			ast_waitstream(target.chan2, "");
+		}
 
-	return 1;
-}
+		/* By forcing the masquerade, we know that target.chan1 and target.chan2 are bridged. We then
+		 * can queue connected line updates where they need to go.
+		 *
+		 * before a masquerade, all channel and pvt locks must be unlocked.  Any recursive
+		 * channel locks held before this function invalidates channel container locking order.
+		 * Since we are unlocking both the pvt (transferer) and its owner channel (current.chan1)
+		 * it is possible for current.chan1 to be destroyed in the pbx thread.  To prevent this
+		 * we must give c a reference before any unlocking takes place.
+		 */
 
-/*!
- * Data to set on a channel that runs dialplan
- * at the completion of a blind transfer
- */
-struct blind_transfer_cb_data {
-	/*! Contents of the REFER's Referred-by header */
-	const char *referred_by;
-	/*! Domain of the URI in the REFER's Refer-To header */
-	const char *domain;
-	/*! Contents of what to place in a Replaces header of an INVITE */
-	const char *replaces;
-	/*! Redirecting information to set on the channel */
-	struct ast_party_redirecting redirecting;
-	/*! Parts of the redirecting structure that are to be updated */
-	struct ast_set_party_redirecting update_redirecting;
-};
+		ast_channel_ref(current->chan1);
+		ast_channel_unlock(current->chan1); /* current.chan1 is p->owner before the masq, it was locked by socket_read()*/
+		ast_channel_unlock(target.chan1);
+		*nounlock = 1;  /* we just unlocked the dialog's channel and have no plans of locking it again. */
+		sip_pvt_unlock(targetcall_pvt);
+		sip_pvt_unlock(transferer);
 
-/*!
- * \internal
- * \brief Callback called on new outbound channel during blind transfer
- *
- * We use this opportunity to populate the channel with data from the REFER
- * so that, if necessary, we can include proper information on any new INVITE
- * we may send out.
- *
- * \param chan The new outbound channel
- * \param user_data A blind_transfer_cb_data struct
- * \param transfer_type Unused
- */
-static void blind_transfer_cb(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
-		enum ast_transfer_type transfer_type)
-{
-	struct blind_transfer_cb_data *cb_data = user_data_wrapper->data;
+		ast_do_masquerade(target.chan1);
+
+		if (target.chan2) {
+			ast_indicate(target.chan2, AST_CONTROL_UNHOLD);
+		}
+
+		if (current->chan2 && ast_channel_state(current->chan2) == AST_STATE_RING) {
+			ast_indicate(target.chan1, AST_CONTROL_RINGING);
+		}
 
-	pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
-	pbx_builtin_setvar_helper(chan, "SIPTRANSFER_REFERER", cb_data->referred_by);
-	pbx_builtin_setvar_helper(chan, "SIPTRANSFER_REPLACES", cb_data->replaces);
-	pbx_builtin_setvar_helper(chan, "SIPDOMAIN", cb_data->domain);
-	ast_channel_update_redirecting(chan, &cb_data->redirecting, &cb_data->update_redirecting);
+		if (target.chan2) {
+			ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee, NULL);
+			ast_channel_queue_connected_line_update(target.chan2, &connected_to_target, NULL);
+		} else {
+			/* Since target.chan1 isn't actually connected to another channel, there is no way for us
+			 * to queue a frame so that its connected line status will be updated.
+			 *
+			 * Instead, we use the somewhat hackish approach of using a special control frame type that
+			 * instructs ast_read to perform a specific action. In this case, the frame we queue tells
+			 * ast_read to call the connected line interception macro configured for target.chan1.
+			 */
+			struct ast_control_read_action_payload *frame_payload;
+			int payload_size;
+			int frame_size;
+			unsigned char connected_line_data[1024];
+			payload_size = ast_connected_line_build_data(connected_line_data,
+				sizeof(connected_line_data), &connected_to_target, NULL);
+			frame_size = payload_size + sizeof(*frame_payload);
+			if (payload_size != -1) {
+				frame_payload = ast_alloca(frame_size);
+				frame_payload->payload_size = payload_size;
+				memcpy(frame_payload->payload, connected_line_data, payload_size);
+				frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
+				ast_queue_control_data(target.chan1, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
+			}
+			/* In addition to queueing the read action frame so that target.chan1's connected line info
+			 * will be updated, we also are going to queue a plain old connected line update on target.chan1. This
+			 * way, either Dial or Queue can apply this connected line update to the outgoing ringing channel.
+			 */
+			ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee, NULL);
+
+		}
+		sip_pvt_lock(transferer); /* the transferer pvt is expected to remain locked on return */
+
+		ast_channel_unref(current->chan1);
+	}
+
+	/* at this point if the transfer is successful only the transferer pvt should be locked. */
+	ast_party_connected_line_free(&connected_to_target);
+	ast_party_connected_line_free(&connected_to_transferee);
+	ast_channel_unref(target.chan1);
+	if (target.chan2) {
+		ast_channel_unref(target.chan2);
+	}
+	if (targetcall_pvt)
+		ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
+	return 1;
 }
 
+
 /*! \brief Handle incoming REFER request */
 /*! \page SIP_REFER SIP transfer Support (REFER)
 
@@ -26055,19 +26478,28 @@ static void blind_transfer_cb(struct ast_channel *chan, struct transfer_channel_
 	inform the target about the transferor
 
 	"Any REFER request has to be appropriately authenticated.".
-
+	
 	We can't destroy dialogs, since we want the call to continue.
-
+	
 	*/
 static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint32_t seqno, int *nounlock)
 {
+	/*!
+	 * Chan1: Call between asterisk and transferer
+	 * Chan2: Call between asterisk and transferee
+	 */
+	struct sip_dual current = { 0, };
+	struct ast_channel *chans[2] = { 0, };
 	char *refer_to = NULL;
+	char *refer_to_domain = NULL;
 	char *refer_to_context = NULL;
+	char *referred_by = NULL;
+	char *callid = NULL;
+	int localtransfer = 0;
+	int attendedtransfer = 0;
 	int res = 0;
-	struct blind_transfer_cb_data cb_data;
-	enum ast_transfer_result transfer_res;
-	RAII_VAR(struct ast_channel *, transferer, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_str *, replaces_str, NULL, ast_free_ptr);
+	struct ast_party_redirecting redirecting;
+	struct ast_set_party_redirecting update_redirecting;
 
 	if (req->debug) {
 		ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n",
@@ -26085,7 +26517,8 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 			sip_alreadygone(p);
 			pvt_set_needdestroy(p, "outside of dialog");
 		}
-		return 0;
+		res = 0;
+		goto handle_refer_cleanup;
 	}
 
 	/* Check if transfer is allowed from this device */
@@ -26094,21 +26527,24 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 		transmit_response(p, "603 Declined (policy)", req);
 		append_history(p, "Xfer", "Refer failed. Allowtransfer == closed.");
 		/* Do not destroy SIP session */
-		return 0;
+		res = 0;
+		goto handle_refer_cleanup;
 	}
 
 	if (!req->ignore && ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
 		/* Already have a pending REFER */
 		transmit_response(p, "491 Request pending", req);
 		append_history(p, "Xfer", "Refer failed. Request pending.");
-		return 0;
+		res = 0;
+		goto handle_refer_cleanup;
 	}
 
 	/* Allocate memory for call transfer data */
 	if (!sip_refer_alloc(p)) {
 		transmit_response(p, "500 Internal Server Error", req);
 		append_history(p, "Xfer", "Refer failed. Memory allocation error.");
-		return -3;
+		res = -3;
+		goto handle_refer_cleanup;
 	}
 
 	res = get_refer_info(p, req);	/* Extract headers */
@@ -26142,9 +26578,9 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 			}
 			break;
 		}
-		return 0;
+		res = 0;
+		goto handle_refer_cleanup;
 	}
-
 	if (ast_strlen_zero(p->context)) {
 		ast_string_field_set(p, context, sip_cfg.default_context);
 	}
@@ -26165,16 +26601,70 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 	/* Is this a repeat of a current request? Ignore it */
 	/* Don't know what else to do right now. */
 	if (req->ignore) {
-		return 0;
-	}
+		goto handle_refer_cleanup;
+	}
+
+	/* If this is a blind transfer, we have the following
+	channels to work with:
+	- chan1, chan2: The current call between transferer and transferee (2 channels)
+	- target_channel: A new call from the transferee to the target (1 channel)
+	We need to stay tuned to what happens in order to be able
+	to bring back the call to the transferer */
+
+	/* If this is a attended transfer, we should have all call legs within reach:
+	- chan1, chan2: The call between the transferer and transferee (2 channels)
+	- target_channel, targetcall_pvt: The call between the transferer and the target (2 channels)
+	We want to bridge chan2 with targetcall_pvt!
+	
+	The replaces call id in the refer message points
+	to the call leg between Asterisk and the transferer.
+	So we need to connect the target and the transferee channel
+	and hangup the two other channels silently
+	
+	If the target is non-local, the call ID could be on a remote
+	machine and we need to send an INVITE with replaces to the
+	target. We basically handle this as a blind transfer
+	and let the sip_call function catch that we need replaces
+	header in the INVITE.
+	*/
 
 	/* Get the transferer's channel */
-	transferer = ast_channel_ref(p->owner);
+	chans[0] = current.chan1 = p->owner;
+
+	/* Find the other part of the bridge (2) - transferee */
+	chans[1] = current.chan2 = ast_bridged_channel(current.chan1);
+
+	ast_channel_ref(current.chan1);
+	if (current.chan2) {
+		ast_channel_ref(current.chan2);
+	}
 
 	if (sipdebug) {
-		ast_debug(3, "SIP %s transfer: Transferer channel %s\n",
+		ast_debug(3, "SIP %s transfer: Transferer channel %s, transferee channel %s\n",
 			p->refer->attendedtransfer ? "attended" : "blind",
-			ast_channel_name(transferer));
+			ast_channel_name(current.chan1),
+			current.chan2 ? ast_channel_name(current.chan2) : "<none>");
+	}
+
+	if (!current.chan2 && !p->refer->attendedtransfer) {
+		/* No bridged channel, propably IVR or echo or similar... */
+		/* Guess we should masquerade or something here */
+		/* Until we figure it out, refuse transfer of such calls */
+		if (sipdebug) {
+			ast_debug(3, "Refused SIP transfer on non-bridged channel.\n");
+		}
+		p->refer->status = REFER_FAILED;
+		append_history(p, "Xfer", "Refer failed. Non-bridged channel.");
+		transmit_response(p, "603 Declined", req);
+		res = -1;
+		goto handle_refer_cleanup;
+	}
+
+	if (current.chan2) {
+		if (sipdebug) {
+			ast_debug(4, "Got SIP transfer, applying to bridged peer '%s'\n", ast_channel_name(current.chan2));
+		}
+		ast_queue_control(current.chan1, AST_CONTROL_UNHOLD);
 	}
 
 	ast_set_flag(&p->flags[0], SIP_GOTREFER);
@@ -26185,9 +26675,8 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 	/* Attended transfer: Find all call legs and bridge transferee with target*/
 	if (p->refer->attendedtransfer) {
 		/* both p and p->owner _MUST_ be locked while calling local_attended_transfer */
-		if ((res = local_attended_transfer(p, transferer, seqno, nounlock))) {
-			ast_clear_flag(&p->flags[0], SIP_GOTREFER);
-			return res;
+		if ((res = local_attended_transfer(p, &current, req, seqno, nounlock))) {
+			goto handle_refer_cleanup; /* We're done with the transfer */
 		}
 		/* Fall through for remote transfers that we did not find locally */
 		if (sipdebug) {
@@ -26198,77 +26687,210 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
 
 	/* Copy data we can not safely access after letting the pvt lock go. */
 	refer_to = ast_strdupa(p->refer->refer_to);
+	refer_to_domain = ast_strdupa(p->refer->refer_to_domain);
 	refer_to_context = ast_strdupa(p->refer->refer_to_context);
+	referred_by = ast_strdupa(p->refer->referred_by);
+	callid = ast_strdupa(p->callid);
+	localtransfer = p->refer->localtransfer;
+	attendedtransfer = p->refer->attendedtransfer;
+
+	if (!*nounlock) {
+		ast_channel_unlock(p->owner);
+		*nounlock = 1;
+	}
+	sip_pvt_unlock(p);
 
-	ast_party_redirecting_init(&cb_data.redirecting);
-	memset(&cb_data.update_redirecting, 0, sizeof(cb_data.update_redirecting));
-	change_redirecting_information(p, req, &cb_data.redirecting, &cb_data.update_redirecting, 0);
+	/* Parking a call.  DO NOT hold any locks while calling ast_parking_ext_valid() */
+	if (localtransfer && ast_parking_ext_valid(refer_to, current.chan1, refer_to_context)) {
+		sip_pvt_lock(p);
+		ast_clear_flag(&p->flags[0], SIP_GOTREFER);
+		p->refer->status = REFER_200OK;
+		append_history(p, "Xfer", "REFER to call parking.");
+		sip_pvt_unlock(p);
 
-	cb_data.domain = ast_strdupa(p->refer->refer_to_domain);
-	cb_data.referred_by = ast_strdupa(p->refer->referred_by);
+		ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans,
+			"TransferMethod: SIP\r\n"
+			"TransferType: Blind\r\n"
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"SIP-Callid: %s\r\n"
+			"TargetChannel: %s\r\n"
+			"TargetUniqueid: %s\r\n"
+			"TransferExten: %s\r\n"
+			"Transfer2Parking: Yes\r\n",
+			ast_channel_name(current.chan1),
+			ast_channel_uniqueid(current.chan1),
+			callid,
+			ast_channel_name(current.chan2),
+			ast_channel_uniqueid(current.chan2),
+			refer_to);
 
-	if (!ast_strlen_zero(p->refer->replaces_callid)) {
-		replaces_str = ast_str_create(128);
-		if (!replaces_str) {
-			ast_log(LOG_NOTICE, "Unable to create Replaces string for remote attended transfer. Transfer failed\n");
-			ast_clear_flag(&p->flags[0], SIP_GOTREFER);
-			ast_party_redirecting_free(&cb_data.redirecting);
-			return -1;
+		if (sipdebug) {
+			ast_debug(4, "SIP transfer to parking: trying to park %s. Parked by %s\n", ast_channel_name(current.chan2), ast_channel_name(current.chan1));
 		}
-		ast_str_append(&replaces_str, 0, "%s%s%s%s%s", p->refer->replaces_callid,
-				!ast_strlen_zero(p->refer->replaces_callid_totag) ? ";to-tag=" : "",
-				S_OR(p->refer->replaces_callid_totag, ""),
-				!ast_strlen_zero(p->refer->replaces_callid_fromtag) ? ";from-tag=" : "",
-				S_OR(p->refer->replaces_callid_fromtag, ""));
-		cb_data.replaces = ast_str_buffer(replaces_str);
-	} else {
-		cb_data.replaces = NULL;
+
+		/* DO NOT hold any locks while calling sip_park */
+		if (sip_park(current.chan2, current.chan1, req, seqno, refer_to, refer_to_context)) {
+			sip_pvt_lock(p);
+			transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE);
+		} else {
+			sip_pvt_lock(p);
+		}
+		goto handle_refer_cleanup;
 	}
 
-	if (!*nounlock) {
+	/* Blind transfers and remote attended xfers.
+	 * Locks should not be held while calling pbx_builtin_setvar_helper. This function
+	 * locks the channel being passed into it.*/
+	if (current.chan1 && current.chan2) {
+		ast_debug(3, "chan1->name: %s\n", ast_channel_name(current.chan1));
+		pbx_builtin_setvar_helper(current.chan1, "BLINDTRANSFER", ast_channel_name(current.chan2));
+	}
+
+	if (current.chan2) {
+		pbx_builtin_setvar_helper(current.chan2, "BLINDTRANSFER", ast_channel_name(current.chan1));
+		pbx_builtin_setvar_helper(current.chan2, "SIPDOMAIN", refer_to_domain);
+		pbx_builtin_setvar_helper(current.chan2, "SIPTRANSFER", "yes");
+		/* One for the new channel */
+		pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER", "yes");
+		/* Attended transfer to remote host, prepare headers for the INVITE */
+		if (!ast_strlen_zero(referred_by)) {
+			pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REFERER", referred_by);
+		}
+
+		/* When a call is transferred to voicemail from a Digium phone, there may be
+		 * a Diversion header present in the REFER with an appropriate reason parameter
+		 * set. We need to update the redirecting information appropriately.
+		 */
+		ast_channel_lock(p->owner);
+		sip_pvt_lock(p);
+		ast_party_redirecting_init(&redirecting);
+		memset(&update_redirecting, 0, sizeof(update_redirecting));
+		change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE);
+
+		/* Do not hold the pvt lock during a call that causes an indicate or an async_goto.
+		 * Those functions lock channels which will invalidate locking order if the pvt lock
+		 * is held.*/
+		sip_pvt_unlock(p);
 		ast_channel_unlock(p->owner);
-		*nounlock = 1;
+		ast_channel_update_redirecting(current.chan2, &redirecting, &update_redirecting);
+		ast_party_redirecting_free(&redirecting);
 	}
 
-	ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-	sip_pvt_unlock(p);
-	transfer_res = ast_bridge_transfer_blind(1, transferer, refer_to, refer_to_context, blind_transfer_cb, &cb_data);
 	sip_pvt_lock(p);
+	/* Generate a Replaces string to be used in the INVITE during attended transfer */
+	if (!ast_strlen_zero(p->refer->replaces_callid)) {
+		char tempheader[SIPBUFSIZE];
+		snprintf(tempheader, sizeof(tempheader), "%s%s%s%s%s", p->refer->replaces_callid,
+			p->refer->replaces_callid_totag ? ";to-tag=" : "",
+			p->refer->replaces_callid_totag,
+			p->refer->replaces_callid_fromtag ? ";from-tag=" : "",
+			p->refer->replaces_callid_fromtag);
+
+		if (current.chan2) {
+			sip_pvt_unlock(p);
+			pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REPLACES", tempheader);
+			sip_pvt_lock(p);
+		}
+	}
 
-	switch (transfer_res) {
-	case AST_BRIDGE_TRANSFER_INVALID:
-		res = -1;
+	/* Connect the call */
+
+	/* FAKE ringing if not attended transfer */
+	if (!p->refer->attendedtransfer) {
+		transmit_notify_with_sipfrag(p, seqno, "180 Ringing", FALSE);
+	}
+
+	/* For blind transfer, this will lead to a new call */
+	/* For attended transfer to remote host, this will lead to
+	   a new SIP call with a replaces header, if the dial plan allows it
+	*/
+	if (!current.chan2) {
+		/* We have no bridge, so we're talking with Asterisk somehow */
+		/* We need to masquerade this call */
+		/* What to do to fix this situation:
+		   * Set up the new call in a new channel
+		   * Let the new channel masq into this channel
+		   Please add that code here :-)
+		*/
 		p->refer->status = REFER_FAILED;
 		transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable (can't handle one-legged xfers)", TRUE);
+		ast_clear_flag(&p->flags[0], SIP_GOTREFER);	
 		append_history(p, "Xfer", "Refer failed (only bridged calls).");
-		ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		break;
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
 		res = -1;
+		goto handle_refer_cleanup;
+	}
+	ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Delay hangup */
+
+	sip_pvt_unlock(p);
+
+	/* For blind transfers, move the call to the new extensions. For attended transfers on multiple
+	 * servers - generate an INVITE with Replaces. Either way, let the dial plan decided
+	 * indicate before masquerade so the indication actually makes it to the real channel
+	 * when using local channels with MOH passthru */
+	ast_indicate(current.chan2, AST_CONTROL_UNHOLD);
+	res = ast_async_goto(current.chan2, refer_to_context, refer_to, 1);
+
+	if (!res) {
+		ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans,
+			"TransferMethod: SIP\r\n"
+			"TransferType: Blind\r\n"
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"SIP-Callid: %s\r\n"
+			"TargetChannel: %s\r\n"
+			"TargetUniqueid: %s\r\n"
+			"TransferExten: %s\r\n"
+			"TransferContext: %s\r\n",
+			ast_channel_name(current.chan1),
+			ast_channel_uniqueid(current.chan1),
+			callid,
+			ast_channel_name(current.chan2),
+			ast_channel_uniqueid(current.chan2),
+			refer_to,
+			refer_to_context);
+		/* Success  - we have a new channel */
+		ast_debug(3, "%s transfer succeeded. Telling transferer.\n", attendedtransfer? "Attended" : "Blind");
+
+		/* XXX - what to we put in CEL 'extra' for attended transfers to external systems? NULL for now */
+		ast_channel_lock(current.chan1);
+		ast_cel_report_event(current.chan1, p->refer->attendedtransfer? AST_CEL_ATTENDEDTRANSFER : AST_CEL_BLINDTRANSFER, NULL, p->refer->attendedtransfer ? NULL : p->refer->refer_to, current.chan2);
+		ast_channel_unlock(current.chan1);
+
+		sip_pvt_lock(p);
+		transmit_notify_with_sipfrag(p, seqno, "200 Ok", TRUE);
+		if (p->refer->localtransfer) {
+			p->refer->status = REFER_200OK;
+		}
+		if (p->owner) {
+			ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
+		}
+		append_history(p, "Xfer", "Refer succeeded.");
+		ast_clear_flag(&p->flags[0], SIP_GOTREFER);
+		/* Do not hangup call, the other side do that when we say 200 OK */
+		/* We could possibly implement a timer here, auto congestion */
+		res = 0;
+	} else {
+		sip_pvt_lock(p);
+		ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Don't delay hangup */
+		ast_debug(3, "%s transfer failed. Resuming original call.\n", p->refer->attendedtransfer? "Attended" : "Blind");
+		append_history(p, "Xfer", "Refer failed.");
+		/* Failure of some kind */
 		p->refer->status = REFER_FAILED;
-		transmit_notify_with_sipfrag(p, seqno, "403 Forbidden", TRUE);
-		append_history(p, "Xfer", "Refer failed (bridge does not permit transfers)");
-		ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		break;
-	case AST_BRIDGE_TRANSFER_FAIL:
+		transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable", TRUE);
+		ast_clear_flag(&p->flags[0], SIP_GOTREFER);
 		res = -1;
-		p->refer->status = REFER_FAILED;
-		transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE);
-		append_history(p, "Xfer", "Refer failed (internal error)");
-		ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
-		break;
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		res = 0;
-		p->refer->status = REFER_200OK;
-		transmit_notify_with_sipfrag(p, seqno, "200 OK", TRUE);
-		append_history(p, "Xfer", "Refer succeeded.");
-		break;
-	default:
-		break;
 	}
 
-	ast_clear_flag(&p->flags[0], SIP_GOTREFER);
-	ast_party_redirecting_free(&cb_data.redirecting);
+handle_refer_cleanup:
+	if (current.chan1) {
+		ast_channel_unref(current.chan1);
+	}
+	if (current.chan2) {
+		ast_channel_unref(current.chan2);
+	}
+
+	/* Make sure we exit with the pvt locked */
 	return res;
 }
 
@@ -26345,9 +26967,8 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 {
 	struct ast_channel *c=NULL;
 	int res;
+	struct ast_channel *bridged_to;
 	const char *required;
-	RAII_VAR(struct ast_channel *, peer_channel, NULL, ast_channel_cleanup);
-	char quality_buf[AST_MAX_USER_FIELD], *quality;
 
 	/* If we have an INCOMING invite that we haven't answered, terminate that transaction */
 	if (p->pendinginvite && !ast_test_flag(&p->flags[0], SIP_OUTGOING) && !req->ignore) {
@@ -26364,115 +26985,71 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 	check_via(p, req);
 	sip_alreadygone(p);
 
-	if (p->owner) {
-		RAII_VAR(struct ast_channel *, owner_relock, NULL, ast_channel_cleanup);
-		RAII_VAR(struct ast_channel *, owner_ref, NULL, ast_channel_cleanup);
-
-		/* Grab a reference to p->owner to prevent it from going away */
-		owner_ref = ast_channel_ref(p->owner);
-
-		/* Established locking order here is bridge, channel, pvt
-		 * and the bridge will be locked during ast_channel_bridge_peer */
-		ast_channel_unlock(owner_ref);
-		sip_pvt_unlock(p);
-
-		peer_channel = ast_channel_bridge_peer(owner_ref);
-
-		owner_relock = sip_pvt_lock_full(p);
-		if (!owner_relock) {
-			ast_debug(3, "Unable to reacquire owner channel lock, channel is gone\n");
-			return 0;
-		}
-	}
-
 	/* Get RTCP quality before end of call */
-	if (p->rtp) {
-		if (p->do_history) {
-			if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
-				append_history(p, "RTCPaudio", "Quality:%s", quality);
-			}
-			if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
-				append_history(p, "RTCPaudioJitter", "Quality:%s", quality);
-			}
-			if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
-				append_history(p, "RTCPaudioLoss", "Quality:%s", quality);
-			}
-			if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
-				append_history(p, "RTCPaudioRTT", "Quality:%s", quality);
-			}
-		}
+	if (p->do_history || p->owner) {
+		char quality_buf[AST_MAX_USER_FIELD], *quality;
+		struct ast_channel *bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
 
-		if (p->owner) {
-			RAII_VAR(struct ast_channel *, owner_relock, NULL, ast_channel_cleanup);
-			RAII_VAR(struct ast_channel *, owner_ref, NULL, ast_channel_cleanup);
-			struct ast_rtp_instance *p_rtp;
-
-			/* Grab a reference to p->owner to prevent it from going away */
-			owner_ref = ast_channel_ref(p->owner);
+		/* We need to get the lock on bridge because ast_rtp_instance_set_stats_vars will attempt
+		 * to lock the bridge. This may get hairy...
+		 */
+		while (bridge && ast_channel_trylock(bridge)) {
+			ast_channel_unlock(p->owner);
+			do {
+				/* Can't use DEADLOCK_AVOIDANCE since p is an ao2 object */
+				sip_pvt_unlock(p);
+				usleep(1);
+				sip_pvt_lock(p);
+			} while (p->owner && ast_channel_trylock(p->owner));
+			bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
+		}
 
-			p_rtp = p->rtp;
-			ao2_ref(p_rtp, +1);
 
-			/* Established locking order here is bridge, channel, pvt
-			 * and the bridge and channel will be locked during
-			 * ast_rtp_instance_set_stats_vars */
-			ast_channel_unlock(owner_ref);
-			sip_pvt_unlock(p);
+		if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
+			if (p->do_history) {
+				append_history(p, "RTCPaudio", "Quality:%s", quality);
 
-			ast_rtp_instance_set_stats_vars(owner_ref, p_rtp);
-			ao2_ref(p_rtp, -1);
-
-			if (peer_channel) {
-				ast_channel_lock(peer_channel);
-				if (IS_SIP_TECH(ast_channel_tech(peer_channel))) {
-					struct sip_pvt *peer_pvt;
-
-					peer_pvt = ast_channel_tech_pvt(peer_channel);
-					if (peer_pvt) {
-						ao2_ref(peer_pvt, +1);
-						sip_pvt_lock(peer_pvt);
-						if (peer_pvt->rtp) {
-							struct ast_rtp_instance *peer_rtp;
-
-							peer_rtp = peer_pvt->rtp;
-							ao2_ref(peer_rtp, +1);
-							ast_channel_unlock(peer_channel);
-							sip_pvt_unlock(peer_pvt);
-							ast_rtp_instance_set_stats_vars(peer_channel, peer_rtp);
-							ao2_ref(peer_rtp, -1);
-							ast_channel_lock(peer_channel);
-							sip_pvt_lock(peer_pvt);
-						}
-						sip_pvt_unlock(peer_pvt);
-						ao2_ref(peer_pvt, -1);
-					}
+				if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
+					append_history(p, "RTCPaudioJitter", "Quality:%s", quality);
+				}
+				if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
+					append_history(p, "RTCPaudioLoss", "Quality:%s", quality);
+				}
+				if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
+					append_history(p, "RTCPaudioRTT", "Quality:%s", quality);
 				}
-				ast_channel_unlock(peer_channel);
 			}
 
-			owner_relock = sip_pvt_lock_full(p);
-			if (!owner_relock) {
-				ast_debug(3, "Unable to reacquire owner channel lock, channel is gone\n");
-				return 0;
+			if (p->owner) {
+				ast_rtp_instance_set_stats_vars(p->owner, p->rtp);
 			}
-		}
-	}
 
-	if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
-		if (p->do_history) {
-			append_history(p, "RTCPvideo", "Quality:%s", quality);
 		}
-		if (p->owner) {
-			pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", quality);
+
+		if (bridge) {
+			struct sip_pvt *q = ast_channel_tech_pvt(bridge);
+
+			if (IS_SIP_TECH(ast_channel_tech(bridge)) && q && q->rtp) {
+				ast_rtp_instance_set_stats_vars(bridge, q->rtp);
+			}
+			ast_channel_unlock(bridge);
 		}
-	}
 
-	if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
-		if (p->do_history) {
-			append_history(p, "RTCPtext", "Quality:%s", quality);
+		if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
+			if (p->do_history) {
+				append_history(p, "RTCPvideo", "Quality:%s", quality);
+			}
+			if (p->owner) {
+				pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", quality);
+			}
 		}
-		if (p->owner) {
-			pbx_builtin_setvar_helper(p->owner, "RTPTEXTQOS", quality);
+		if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
+			if (p->do_history) {
+				append_history(p, "RTCPtext", "Quality:%s", quality);
+			}
+			if (p->owner) {
+				pbx_builtin_setvar_helper(p->owner, "RTPTEXTQOS", quality);
+			}
 		}
 	}
 
@@ -26490,27 +27067,15 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 		if (!res) {
 			c = p->owner;
 			if (c) {
-				if (peer_channel) {
-					RAII_VAR(struct ast_channel *, owner_relock, NULL, ast_channel_cleanup);
-					char *local_context = ast_strdupa(p->context);
-					char *local_refer_to = ast_strdupa(p->refer->refer_to);
-
-					/* Grab a reference to p->owner to prevent it from going away */
-					ast_channel_ref(c);
-
+				bridged_to = ast_bridged_channel(c);
+				if (bridged_to) {
 					/* Don't actually hangup here... */
-					ast_queue_unhold(c);
-					ast_channel_unlock(c);  /* async_goto can do a masquerade, no locks can be held during a masq */
+					ast_queue_control(c, AST_CONTROL_UNHOLD);
 					sip_pvt_unlock(p);
-
-					ast_async_goto(peer_channel, local_context, local_refer_to, 1);
-
-					owner_relock = sip_pvt_lock_full(p);
-					ast_channel_cleanup(c);
-					if (!owner_relock) {
-						ast_debug(3, "Unable to reacquire owner channel lock, channel is gone\n");
-						return 0;
-					}
+					ast_channel_unlock(c);  /* async_goto can do a masquerade, no locks can be held during a masq */
+					ast_async_goto(bridged_to, p->context, p->refer->refer_to, 1);
+					ast_channel_lock(c);
+					sip_pvt_lock(p);
 				} else {
 					ast_queue_hangup(p->owner);
 				}
@@ -27226,10 +27791,7 @@ static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, st
 	return handler_result;
 }
 
-/*!
- * \internal
- * \brief Subscribe to MWI events for the specified peer
- *
+/*! \internal \brief Subscribe to MWI events for the specified peer
  * \note The peer cannot be locked during this method.  sip_send_mwi_peer will
  * attempt to lock the peer after the event subscription lock is held; if the peer is locked during
  * this method then we will attempt to lock the event subscription lock but after the peer, creating
@@ -27240,17 +27802,14 @@ static void add_peer_mwi_subs(struct sip_peer *peer)
 	struct sip_mailbox *mailbox;
 
 	AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
-		struct stasis_topic *mailbox_specific_topic;
-		mailbox->event_sub = stasis_unsubscribe(mailbox->event_sub);
-
-		mailbox_specific_topic = ast_mwi_topic(mailbox->id);
-		if (mailbox_specific_topic) {
-			char *peer_name = ast_strdup(peer->name);
-			if (!peer_name) {
-				return;
-			}
-			mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer_name);
+		if (mailbox->event_sub) {
+			ast_event_unsubscribe(mailbox->event_sub);
 		}
+
+		mailbox->event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "SIP mbox event", peer,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox->mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, S_OR(mailbox->context, "default"),
+			AST_EVENT_IE_END);
 	}
 }
 
@@ -27418,7 +27977,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
 
 	/* Get full contact header - this needs to be used as a request URI in NOTIFY's */
 	parse_ok_contact(p, req);
-	build_contact(p);
+	build_contact(p, req, 1);
 
 	/* Initialize tag for new subscriptions */
 	if (ast_strlen_zero(p->tag)) {
@@ -27525,12 +28084,11 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
 		accept = __get_header(req, "Accept", &start);
 		while (!found_supported && !ast_strlen_zero(accept)) {
 			found_supported = strcmp(accept, "application/simple-message-summary") ? 0 : 1;
-			if (!found_supported) {
-				ast_debug(3, "Received SIP mailbox subscription for unknown format: %s\n", accept);
+			if (!found_supported && (option_debug > 2)) {
+				ast_debug(1, "Received SIP mailbox subscription for unknown format: %s\n", accept);
 			}
 			accept = __get_header(req, "Accept", &start);
 		}
-		/* If !start, there is no Accept header at all */
 		if (start && !found_supported) {
 			/* Format requested that we do not support */
 			transmit_response(p, "406 Not Acceptable", req);
@@ -28009,7 +28567,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
 		res = handle_request_invite(p, req, addr, seqno, recount, e, nounlock);
 
 		if (res < 9) {
-			sip_report_security_event(p, req, res);
+			sip_report_security_event(NULL, &p->recv, p, req, res);
 		}
 
 		switch (res) {
@@ -28048,7 +28606,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
 		break;
 	case SIP_REGISTER:
 		res = handle_request_register(p, req, addr, e);
-		sip_report_security_event(p, req, res);
+		sip_report_security_event(p->exten, NULL, p, req, res);
 		break;
 	case SIP_INFO:
 		if (req->debug)
@@ -28142,7 +28700,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
 	}
 
 	req.socket.fd = sipsock;
-	set_socket_transport(&req.socket, AST_TRANSPORT_UDP);
+	set_socket_transport(&req.socket, SIP_TRANSPORT_UDP);
 	req.socket.tcptls_session	= NULL;
 	req.socket.port = htons(ast_sockaddr_port(&bindaddr));
 
@@ -28247,9 +28805,9 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
  * \param port Port we are checking to see if it's the standard port.
  * \note port is expected in host byte order
  */
-static int sip_standard_port(enum ast_transport type, int port)
+static int sip_standard_port(enum sip_transport type, int port)
 {
-	if (type & AST_TRANSPORT_TLS)
+	if (type & SIP_TRANSPORT_TLS)
 		return port == STANDARD_TLS_PORT;
 	else
 		return port == STANDARD_SIP_PORT;
@@ -28294,11 +28852,11 @@ int get_address_family_filter(unsigned int transport)
 {
 	const struct ast_sockaddr *addr = NULL;
 
-	if ((transport == AST_TRANSPORT_UDP) || !transport) {
+	if ((transport == SIP_TRANSPORT_UDP) || !transport) {
 		addr = &bindaddr;
-	} else if (transport == AST_TRANSPORT_TCP || transport == AST_TRANSPORT_WS) {
+	} else if (transport == SIP_TRANSPORT_TCP || transport == SIP_TRANSPORT_WS) {
 		addr = &sip_tcp_desc.local_address;
-	} else if (transport == AST_TRANSPORT_TLS || transport == AST_TRANSPORT_WSS) {
+	} else if (transport == SIP_TRANSPORT_TLS || transport == SIP_TRANSPORT_WSS) {
 		addr = &sip_tls_desc.local_address;
 	}
 
@@ -28321,15 +28879,15 @@ static int sip_prepare_socket(struct sip_pvt *p)
 	pthread_t launched;
 
 	/* check to see if a socket is already active */
-	if ((s->fd != -1) && (s->type == AST_TRANSPORT_UDP)) {
+	if ((s->fd != -1) && (s->type == SIP_TRANSPORT_UDP)) {
 		return s->fd;
 	}
-	if ((s->type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) &&
+	if ((s->type & (SIP_TRANSPORT_TCP | SIP_TRANSPORT_TLS)) &&
 			(s->tcptls_session) &&
 			(s->tcptls_session->fd != -1)) {
 		return s->tcptls_session->fd;
 	}
-	if ((s->type & (AST_TRANSPORT_WS | AST_TRANSPORT_WSS))) {
+	if ((s->type & (SIP_TRANSPORT_WS | SIP_TRANSPORT_WSS))) {
 		return s->ws_session ? ast_websocket_fd(s->ws_session) : -1;
 	}
 
@@ -28340,7 +28898,7 @@ static int sip_prepare_socket(struct sip_pvt *p)
 		s->type = p->outboundproxy->transport;
 	}
 
-	if (s->type == AST_TRANSPORT_UDP) {
+	if (s->type == SIP_TRANSPORT_UDP) {
 		s->fd = sipsock;
 		return s->fd;
 	}
@@ -28378,7 +28936,7 @@ static int sip_prepare_socket(struct sip_pvt *p)
 	ca->accept_fd = -1;
 	ast_sockaddr_copy(&ca->remote_address,sip_real_dst(p));
 	/* if type is TLS, we need to create a tls cfg for this session arg */
-	if (s->type == AST_TRANSPORT_TLS) {
+	if (s->type == SIP_TRANSPORT_TLS) {
 		if (!(ca->tls_cfg = ast_calloc(1, sizeof(*ca->tls_cfg)))) {
 			goto create_tcptls_session_fail;
 		}
@@ -28453,17 +29011,16 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old)
 
 	in_cache = 0;
 	AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
-		RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-		struct ast_mwi_state *mwi_state;
-
-		msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), mailbox->id);
-		if (!msg) {
+		struct ast_event *event;
+		event = ast_event_get_cached(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox->mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, S_OR(mailbox->context, "default"),
+			AST_EVENT_IE_END);
+		if (!event)
 			continue;
-		}
-
-		mwi_state = stasis_message_data(msg);
-		*new += mwi_state->new_msgs;
-		*old += mwi_state->old_msgs;
+		*new += ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+		*old += ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
+		ast_event_destroy(event);
 		in_cache = 1;
 	}
 
@@ -28579,39 +29136,6 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only)
 	return 0;
 }
 
-static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	const char *source = ast_json_string_get(ast_json_object_get(obj->blob, "source"));
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "SessionTimeout",
-		"%s"
-		"Source: %s\r\n",
-		ast_str_buffer(channel_string), source);
-}
-
-/*! \brief Sends a session timeout channel blob used to produce SessionTimeout AMI messages */
-static void send_session_timeout(struct ast_channel *chan, const char *source)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	ast_assert(chan != NULL);
-	ast_assert(source != NULL);
-
-	blob = ast_json_pack("{s: s}", "source", source);
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_blob(chan, session_timeout_type(), blob);
-}
-
 /*!
  * \brief helper function for the monitoring thread -- seems to be called with the assumption that the dialog is locked
  *
@@ -28687,8 +29211,8 @@ static int check_rtp_timeout(struct sip_pvt *dialog, time_t t)
 				}
 				ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
 					ast_channel_name(dialog->owner), (long) (t - dialog->lastrtprx));
-				send_session_timeout(dialog->owner, "RTPTimeout");
-
+				manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: RTPTimeout\r\n"
+						"Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(dialog->owner), ast_channel_uniqueid(dialog->owner));
 				/* Issue a softhangup */
 				ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
 				ast_channel_unlock(dialog->owner);
@@ -28806,7 +29330,7 @@ static int restart_monitor(void)
 		ast_log(LOG_WARNING, "Cannot kill myself\n");
 		return -1;
 	}
-	if (monitor_thread != AST_PTHREADT_NULL) {
+	if (monitor_thread != AST_PTHREADT_NULL && monitor_thread != AST_PTHREADT_STOP) {
 		/* Wake up the thread */
 		pthread_kill(monitor_thread, SIGURG);
 	} else {
@@ -28821,13 +29345,8 @@ static int restart_monitor(void)
 	return 0;
 }
 
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static void acl_change_event_cb(const struct ast_event *event, void *userdata)
 {
-	if (stasis_message_type(message) != ast_named_acl_change_type()) {
-		return;
-	}
-
 	ast_log(LOG_NOTICE, "Reloading chan_sip in response to ACL change event.\n");
 
 	ast_mutex_lock(&sip_reload_lock);
@@ -28952,7 +29471,8 @@ static int proc_session_timer(const void *vp)
 			sip_pvt_lock(p);
 		}
 
-		send_session_timeout(p->owner, "SIPSessionTimer");
+		manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: SIPSessionTimer\r\n"
+				"Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(p->owner), ast_channel_uniqueid(p->owner));
 		ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
 		ast_channel_unlock(p->owner);
 		sip_pvt_unlock(p);
@@ -29100,11 +29620,11 @@ int st_get_se(struct sip_pvt *p, int max)
 		}
 		p->stimer->st_cached_max_se = global_max_se;
 		return (p->stimer->st_cached_max_se);
-	}
+	} 
 	/* Find Min SE timer */
 	if (p->stimer->st_cached_min_se) {
 		return p->stimer->st_cached_min_se;
-	}
+	} 
 	if (p->relatedpeer) {
 		p->stimer->st_cached_min_se = p->relatedpeer->stimer.st_min_se;
 		return (p->stimer->st_cached_min_se);
@@ -29130,16 +29650,16 @@ enum st_refresher st_get_refresher(struct sip_pvt *p)
 		p->stimer->st_cached_ref = (p->relatedpeer->stimer.st_ref == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
 		return p->stimer->st_cached_ref;
 	}
-
+	
 	p->stimer->st_cached_ref = (global_st_refresher == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
 	return p->stimer->st_cached_ref;
 }
 
 
 /*!
- * \brief Get the session-timer mode
- * \param p pointer to the SIP dialog
- * \param no_cached Set this to true in order to force a peername lookup on
+ * \brief Get the session-timer mode 
+ * \param p pointer to the SIP dialog 
+ * \param no_cached, set this to true in order to force a peername lookup on
  *        the session timer mode.
 */
 enum st_mode st_get_mode(struct sip_pvt *p, int no_cached)
@@ -29178,13 +29698,13 @@ static int sip_send_keepalive(const void *data)
 	}
 
 	/* Send the packet out using the proper method for this peer */
-	if ((peer->socket.fd != -1) && (peer->socket.type == AST_TRANSPORT_UDP)) {
+	if ((peer->socket.fd != -1) && (peer->socket.type == SIP_TRANSPORT_UDP)) {
 		res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr);
-	} else if ((peer->socket.type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) &&
+	} else if ((peer->socket.type & (SIP_TRANSPORT_TCP | SIP_TRANSPORT_TLS)) &&
 		   (peer->socket.tcptls_session) &&
 		   (peer->socket.tcptls_session->fd != -1)) {
 		res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive));
-	} else if (peer->socket.type == AST_TRANSPORT_UDP) {
+	} else if (peer->socket.type == SIP_TRANSPORT_UDP) {
 		res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr);
 	}
 
@@ -29222,21 +29742,11 @@ static int sip_poke_noanswer(const void *data)
 	peer->pokeexpire = -1;
 
 	if (peer->lastms > -1) {
-
 		ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE!  Last qualify: %d\n", peer->name, peer->lastms);
 		if (sip_cfg.peer_rtupdate) {
 			ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", "-1", SENTINEL);
 		}
-
-		if (peer->endpoint) {
-			RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-			ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_OFFLINE);
-			blob = ast_json_pack("{s: s, s: s}",
-				"peer_status", "Unreachable",
-				"time", "-1");
-			ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
-		}
-
+		manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1);
 		if (sip_cfg.regextenonqualify) {
 			register_peer_exten(peer, FALSE);
 		}
@@ -29279,13 +29789,13 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
 {
 	struct sip_pvt *p;
 	int xmitres = 0;
-
+	
 	if ((!peer->maxms && !force) || ast_sockaddr_isnull(&peer->addr)) {
 		/* IF we have no IP, or this isn't to be monitored, return
 		  immediately after clearing things out */
 		AST_SCHED_DEL_UNREF(sched, peer->pokeexpire,
 				sip_unref_peer(peer, "removing poke peer ref"));
-
+		
 		peer->lastms = 0;
 		if (peer->call) {
 			peer->call = dialog_unref(peer->call, "unref dialog peer->call");
@@ -29311,11 +29821,6 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
-	sip_route_copy(&p->route, &peer->path);
-	if (!sip_route_empty(&p->route)) {
-		/* Parse SIP URI of first route-set hop and use it as target address */
-		__set_address_from_contact(sip_route_first_uri(&p->route), &p->sa, p->socket.type == AST_TRANSPORT_TLS ? 1 : 0);
-	}
 
 	/* Get the outbound proxy information */
 	ref_proxy(p, obproxy_get(p, peer));
@@ -29344,7 +29849,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
 
 	AST_SCHED_DEL_UNREF(sched, peer->pokeexpire,
 			sip_unref_peer(peer, "removing poke peer ref"));
-
+	
 	if (p->relatedpeer)
 		p->relatedpeer = sip_unref_peer(p->relatedpeer,"unsetting the relatedpeer field in the dialog, before it is set to something else.");
 	p->relatedpeer = sip_ref_peer(peer, "setting the relatedpeer field in the dialog");
@@ -29388,7 +29893,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
 		- not registered			AST_DEVICE_UNAVAILABLE
 		- registered				AST_DEVICE_NOT_INUSE
 		- fixed IP (!dynamic)			AST_DEVICE_NOT_INUSE
-
+	
 	Peers that does not have a known call and can't be reached by OPTIONS
 		- unreachable				AST_DEVICE_UNAVAILABLE
 
@@ -29484,14 +29989,13 @@ static int sip_devicestate(const char *data)
  *	To: header.
  * \endverbatim
  */
-static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause)
+static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause)
 {
 	struct sip_pvt *p;
 	struct ast_channel *tmpc = NULL;
 	char *ext = NULL, *host;
 	char tmp[256];
-	struct ast_str *codec_buf = ast_str_alloca(64);
-	struct ast_str *cap_buf = ast_str_alloca(64);
+	char tmp2[256];
 	char *dnid;
 	char *secret = NULL;
 	char *md5secret = NULL;
@@ -29499,7 +30003,7 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
 	char *trans = NULL;
 	char dialstring[256];
 	char *remote_address;
-	enum ast_transport transport = 0;
+	enum sip_transport transport = 0;
 	struct ast_callid *callid;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(peerorhost);
@@ -29514,14 +30018,14 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
 	 * configured from sip.conf, and sip_tech.capabilities, which is
 	 * hardwired to all audio formats.
 	 */
-	if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) {
+	if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) {
 		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n",
-			ast_format_cap_get_names(cap, &codec_buf),
-			ast_format_cap_get_names(sip_cfg.caps, &cap_buf));
+		ast_getformatname_multiple(tmp, sizeof(tmp), cap),
+		ast_getformatname_multiple(tmp2, sizeof(tmp2), sip_cfg.caps));
 		*cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;	/* Can't find codec to connect to host */
 		return NULL;
 	}
-	ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_format_cap_get_names(cap, &codec_buf));
+	ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 
 	if (ast_strlen_zero(dest)) {
 		ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
@@ -29591,16 +30095,16 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
 	if (trans) {
 		*trans++ = '\0';
 		if (!strcasecmp(trans, "tcp"))
-			transport = AST_TRANSPORT_TCP;
+			transport = SIP_TRANSPORT_TCP;
 		else if (!strcasecmp(trans, "tls"))
-			transport = AST_TRANSPORT_TLS;
+			transport = SIP_TRANSPORT_TLS;
 		else {
 			if (strcasecmp(trans, "udp"))
 				ast_log(LOG_WARNING, "'%s' is not a valid transport option to Dial() for SIP calls, using udp by default.\n", trans);
-			transport = AST_TRANSPORT_UDP;
+			transport = SIP_TRANSPORT_UDP;
 		}
 	} else { /* use default */
-		transport = AST_TRANSPORT_UDP;
+		transport = SIP_TRANSPORT_UDP;
 	}
 
 	if (!host) {
@@ -29673,7 +30177,7 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
 
 	/* We have an extension to call, don't use the full contact here */
 	/* This to enable dialing registered peers with extension dialling,
-	   like SIP/peername/extension
+	   like SIP/peername/extension 	
 	   SIP/peername will still use the full contact
 	 */
 	if (ext) {
@@ -29691,16 +30195,20 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
 #if 0
 	printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
 #endif
-	ast_format_cap_append_from_cap(p->prefcaps, cap, AST_MEDIA_TYPE_UNKNOWN);
-	ast_format_cap_get_compatible(cap, p->caps, p->jointcaps);
+	ast_format_cap_append(p->prefcaps, cap);
+	ast_format_cap_joint_copy(cap, p->caps, p->jointcaps);
 
 	sip_pvt_lock(p);
 
-	tmpc = sip_new(p, AST_STATE_DOWN, host, assignedids, requestor, callid);	/* Place the call */
+	tmpc = sip_new(p, AST_STATE_DOWN, host, requestor ? ast_channel_linkedid(requestor) : NULL, callid);	/* Place the call */
 	if (callid) {
 		callid = ast_callid_unref(callid);
 	}
 
+	if (sip_cfg.callevents)
+		manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+			"Channel: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
+			p->owner ? ast_channel_name(p->owner) : "", "SIP", p->callid, p->fullcontact, p->peername);
 	sip_pvt_unlock(p);
 	if (!tmpc) {
 		dialog_unlink_all(p);
@@ -29793,9 +30301,6 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
 	if (!strcasecmp(v->name, "trustrpid")) {
 		ast_set_flag(&mask[0], SIP_TRUSTRPID);
 		ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
-	} else if (!strcasecmp(v->name, "supportpath")) {
-		ast_set_flag(&mask[0], SIP_USEPATH);
-		ast_set2_flag(&flags[0], ast_true(v->value), SIP_USEPATH);
 	} else if (!strcasecmp(v->name, "sendrpid")) {
 		ast_set_flag(&mask[0], SIP_SENDRPID);
 		if (!strcasecmp(v->value, "pai")) {
@@ -29877,7 +30382,7 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
 	} else if (!strcasecmp(v->name, "insecure")) {
 		ast_set_flag(&mask[0], SIP_INSECURE);
 		ast_clear_flag(&flags[0], SIP_INSECURE);
-		set_insecure_flags(&flags[0], v->value, v->lineno);
+		set_insecure_flags(&flags[0], v->value, v->lineno);	
 	} else if (!strcasecmp(v->name, "progressinband")) {
 		ast_set_flag(&mask[0], SIP_PROG_INBAND);
 		ast_clear_flag(&flags[0], SIP_PROG_INBAND);
@@ -30131,7 +30636,7 @@ static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
 {
 	struct ast_variable *tmpvar = NULL;
 	char *varname = ast_strdupa(buf), *varval = NULL;
-
+	
 	if ((varval = strchr(varname, '='))) {
 		*varval++ = '\0';
 		if ((tmpvar = ast_variable_new(varname, varval, ""))) {
@@ -30152,7 +30657,7 @@ static void set_peer_defaults(struct sip_peer *peer)
 		peer->expire = -1;
 		peer->pokeexpire = -1;
 		peer->keepalivesend = -1;
-		set_socket_transport(&peer->socket, AST_TRANSPORT_UDP);
+		set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP);
 	}
 	peer->type = SIP_TYPE_PEER;
 	ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
@@ -30169,7 +30674,7 @@ static void set_peer_defaults(struct sip_peer *peer)
 	ast_string_field_set(peer, engine, default_engine);
 	ast_sockaddr_setnull(&peer->addr);
 	ast_sockaddr_setnull(&peer->defaddr);
-	ast_format_cap_append_from_cap(peer->caps, sip_cfg.caps, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(peer->caps, sip_cfg.caps);
 	peer->maxcallbitrate = default_maxcallbitrate;
 	peer->rtptimeout = global_rtptimeout;
 	peer->rtpholdtimeout = global_rtpholdtimeout;
@@ -30195,6 +30700,7 @@ static void set_peer_defaults(struct sip_peer *peer)
 	peer->pickupgroup = 0;
 	peer->maxms = default_qualify;
 	peer->keepalive = default_keepalive;
+	peer->prefs = default_prefs;
 	ast_string_field_set(peer, zone, default_zone);
 	peer->stimer.st_mode_oper = global_st_mode;	/* Session-Timers */
 	peer->stimer.st_ref = global_st_refresher;
@@ -30224,13 +30730,13 @@ static struct sip_peer *temp_peer(const char *name)
 		ao2_t_ref(peer, -1, "failed to string_field_init, drop peer");
 		return NULL;
 	}
-
+	
 	if (!(peer->cc_params = ast_cc_config_params_init())) {
 		ao2_t_ref(peer, -1, "failed to allocate cc_params for peer");
 		return NULL;
 	}
 
-	if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(peer->caps = ast_format_cap_alloc_nolock())) {
 		ao2_t_ref(peer, -1, "failed to allocate format capabilities, drop peer");
 		return NULL;
 	}
@@ -30242,6 +30748,7 @@ static struct sip_peer *temp_peer(const char *name)
 
 	peer->selfdestruct = TRUE;
 	peer->host_dynamic = TRUE;
+	peer->prefs = default_prefs;
 	reg_source_db(peer);
 
 	return peer;
@@ -30250,24 +30757,24 @@ static struct sip_peer *temp_peer(const char *name)
 /*! \todo document this function */
 static void add_peer_mailboxes(struct sip_peer *peer, const char *value)
 {
-	char *next;
-	char *mbox;
+	char *next, *mbox, *context;
 
 	next = ast_strdupa(value);
 
-	while ((mbox = strsep(&next, ","))) {
+	while ((mbox = context = strsep(&next, ","))) {
 		struct sip_mailbox *mailbox;
 		int duplicate = 0;
-
 		/* remove leading/trailing whitespace from mailbox string */
 		mbox = ast_strip(mbox);
+		strsep(&context, "@");
+
 		if (ast_strlen_zero(mbox)) {
 			continue;
 		}
 
 		/* Check whether the mailbox is already in the list */
 		AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
-			if (!strcmp(mailbox->id, mbox)) {
+			if (!strcmp(mailbox->mailbox, mbox) && !strcmp(S_OR(mailbox->context, ""), S_OR(context, ""))) {
 				duplicate = 1;
 				break;
 			}
@@ -30276,11 +30783,15 @@ static void add_peer_mailboxes(struct sip_peer *peer, const char *value)
 			continue;
 		}
 
-		mailbox = ast_calloc(1, sizeof(*mailbox) + strlen(mbox));
-		if (!mailbox) {
+		if (!(mailbox = ast_calloc(1, sizeof(*mailbox) + strlen(mbox) + strlen(S_OR(context, ""))))) {
 			continue;
 		}
-		strcpy(mailbox->id, mbox); /* SAFE */
+
+		if (!ast_strlen_zero(context)) {
+			mailbox->context = mailbox->mailbox + strlen(mbox) + 1;
+			strcpy(mailbox->context, context); /* SAFE */
+		}
+		strcpy(mailbox->mailbox, mbox); /* SAFE */
 
 		AST_LIST_INSERT_TAIL(&peer->mailboxes, mailbox, entry);
 	}
@@ -30331,10 +30842,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 		if (!(peer = ao2_t_alloc(sizeof(*peer), sip_destroy_peer_fn, "allocate a peer struct"))) {
 			return NULL;
 		}
-		if (!(peer->endpoint = ast_endpoint_create("SIP", name))) {
-			return NULL;
-		}
-		if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+		if (!(peer->caps = ast_format_cap_alloc_nolock())) {
 			ao2_t_ref(peer, -1, "failed to allocate format capabilities, drop peer");
 			return NULL;
 		}
@@ -30418,15 +30926,15 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 					trans = ast_skip_blanks(trans);
 
 					if (!strncasecmp(trans, "udp", 3)) {
-						peer->transports |= AST_TRANSPORT_UDP;
+						peer->transports |= SIP_TRANSPORT_UDP;
 					} else if (!strncasecmp(trans, "wss", 3)) {
-						peer->transports |= AST_TRANSPORT_WSS;
+						peer->transports |= SIP_TRANSPORT_WSS;
 					} else if (!strncasecmp(trans, "ws", 2)) {
-						peer->transports |= AST_TRANSPORT_WS;
+						peer->transports |= SIP_TRANSPORT_WS;
 					} else if (sip_cfg.tcp_enabled && !strncasecmp(trans, "tcp", 3)) {
-						peer->transports |= AST_TRANSPORT_TCP;
+						peer->transports |= SIP_TRANSPORT_TCP;
 					} else if (default_tls_cfg.enabled && !strncasecmp(trans, "tls", 3)) {
-						peer->transports |= AST_TRANSPORT_TLS;
+						peer->transports |= SIP_TRANSPORT_TLS;
 					} else if (!strncasecmp(trans, "tcp", 3) || !strncasecmp(trans, "tls", 3)) {
 						ast_log(LOG_WARNING, "'%.3s' is not a valid transport type when %.3senable=no. If no other is specified, the defaults from general will be used.\n", trans, trans);
 					} else {
@@ -30533,7 +31041,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 					srvlookup = v->value;
 				}
 			} else if (!strcasecmp(v->name, "defaultip")) {
-				peer->defaddr.ss.ss_family = AST_AF_UNSPEC;
 				if (!ast_strlen_zero(v->value) && ast_get_ip(&peer->defaddr, v->value)) {
 					sip_unref_peer(peer, "sip_unref_peer: from build_peer defaultip");
 					return NULL;
@@ -30575,7 +31082,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 				if (peer->callingpres == -1) {
 					peer->callingpres = atoi(v->value);
 				}
-			} else if (!strcasecmp(v->name, "username") || !strcmp(v->name, "defaultuser")) {	/* "username" is deprecated */
+			} else if (!strcasecmp(v->name, "username") || !strcasecmp(v->name, "defaultuser")) {	/* "username" is deprecated */
 				ast_string_field_set(peer, username, v->value);
 				if (!strcasecmp(v->name, "username")) {
 					if (deprecation_warning) {
@@ -30599,7 +31106,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 			} else if (!strcasecmp(v->name, "callbackextension")) {
 				ast_string_field_set(peer, callback, v->value);
 			} else if (!strcasecmp(v->name, "amaflags")) {
-				format = ast_channel_string2amaflag(v->value);
+				format = ast_cdr_amaflags2int(v->value);
 				if (format < 0) {
 					ast_log(LOG_WARNING, "Invalid AMA Flags for peer: %s at line %d\n", v->value, v->lineno);
 				} else {
@@ -30627,18 +31134,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 				/* People expect that if 'hasvoicemail' is set, that the mailbox will
 				 * be also set, even if not explicitly specified. */
 				if (ast_true(v->value) && AST_LIST_EMPTY(&peer->mailboxes)) {
-					/*
-					 * hasvoicemail is a users.conf legacy voicemail enable method.
-					 * hasvoicemail is only going to work for app_voicemail mailboxes.
-					 */
-					if (strchr(name, '@')) {
-						add_peer_mailboxes(peer, name);
-					} else {
-						char mailbox[AST_MAX_MAILBOX_UNIQUEID];
-
-						snprintf(mailbox, sizeof(mailbox), "%s at default", name);
-						add_peer_mailboxes(peer, mailbox);
-					}
+					add_peer_mailboxes(peer, name);
 				}
 			} else if (!strcasecmp(v->name, "subscribemwi")) {
 				ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_SUBSCRIBEMWIONLY);
@@ -30655,12 +31151,12 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 			} else if (!strcasecmp(v->name, "namedpickupgroup")) {
 				peer->named_pickupgroups = ast_get_namedgroups(v->value);
 			} else if (!strcasecmp(v->name, "allow")) {
-				int error = ast_format_cap_update_by_allow_disallow(peer->caps, v->value, TRUE);
+				int error = ast_parse_allow_disallow(&peer->prefs, peer->caps, v->value, TRUE);
 				if (error) {
 					ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
 				}
 			} else if (!strcasecmp(v->name, "disallow")) {
-				int error =  ast_format_cap_update_by_allow_disallow(peer->caps, v->value, FALSE);
+				int error =  ast_parse_allow_disallow(&peer->prefs, peer->caps, v->value, FALSE);
 				if (error) {
 					ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
 				}
@@ -30761,10 +31257,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_USE_AVPF);
 			} else if (!strcasecmp(v->name, "icesupport")) {
 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_ICE_SUPPORT);
-			} else if (!strcasecmp(v->name, "ignore_requested_pref")) {
-				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_IGNORE_PREFCAPS);
-			} else if (!strcasecmp(v->name, "discard_remote_hold_retrieval")) {
-				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL);
 			} else if (!strcasecmp(v->name, "force_avp")) {
 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_FORCE_AVP);
 			} else {
@@ -30957,16 +31449,16 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 
 	if (ast_sockaddr_port(&peer->addr) == 0) {
 		ast_sockaddr_set_port(&peer->addr,
-				      (peer->socket.type & AST_TRANSPORT_TLS) ?
+				      (peer->socket.type & SIP_TRANSPORT_TLS) ?
 				      STANDARD_TLS_PORT : STANDARD_SIP_PORT);
 	}
 	if (ast_sockaddr_port(&peer->defaddr) == 0) {
 		ast_sockaddr_set_port(&peer->defaddr,
-				      (peer->socket.type & AST_TRANSPORT_TLS) ?
+				      (peer->socket.type & SIP_TRANSPORT_TLS) ?
 				      STANDARD_TLS_PORT : STANDARD_SIP_PORT);
 	}
 	if (!peer->socket.port) {
-		peer->socket.port = htons(((peer->socket.type & AST_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT));
+		peer->socket.port = htons(((peer->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT));
 	}
 
 	if (realtime) {
@@ -30986,7 +31478,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 
 		/* Startup regular pokes */
 		if (!devstate_only && enablepoke) {
-			sip_poke_peer(peer, 0);
+			/*
+			 * We cannot poke the peer now in this thread without
+			 * a lock inversion so pass it off to the scheduler
+			 * thread.
+			 */
+			AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched,
+				0, /* Poke the peer ASAP */
+				sip_poke_peer_now, peer,
+				sip_unref_peer(_data, "removing poke peer ref"),
+				sip_unref_peer(peer, "removing poke peer ref"),
+				sip_ref_peer(peer, "adding poke peer ref"));
 		}
 	}
 
@@ -31023,7 +31525,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 
 	/* If an ACL change subscription is needed and doesn't exist, we need one. */
 	if (acl_change_subscription_needed) {
-		acl_change_stasis_subscribe();
+		acl_change_event_subscribe();
 	}
 
 	return peer;
@@ -31049,15 +31551,18 @@ static int peer_markall_autopeers_func(void *device, void *arg, int flags)
 
 /*!
  * \internal
- * \brief If no default formats are set in config, these are used
+ * \brief If no default formats are set in config, these are used 
  */
 static void sip_set_default_format_capabilities(struct ast_format_cap *cap)
 {
-	ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
-	ast_format_cap_append(cap, ast_format_ulaw, 0);
-	ast_format_cap_append(cap, ast_format_alaw, 0);
-	ast_format_cap_append(cap, ast_format_gsm, 0);
-	ast_format_cap_append(cap, ast_format_h263, 0);
+	struct ast_format tmp_fmt;
+
+	ast_format_cap_remove_all(cap);
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_TESTLAW, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ALAW, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_H263, 0));
 }
 
 static void display_nat_warning(const char *cat, int reason, struct ast_flags *flags) {
@@ -31074,36 +31579,29 @@ static void display_nat_warning(const char *cat, int reason, struct ast_flags *f
 
 static void cleanup_all_regs(void)
 {
-	struct ao2_iterator iter;
-	struct sip_registry *iterator;
-	/* First, destroy all outstanding registry calls */
-	/* This is needed, since otherwise active registry entries will not be destroyed */
-	iter = ao2_iterator_init(registry_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "cleanup_all_regs iter"))) {
-		ao2_lock(iterator);
-
-		if (iterator->call) {
-			ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
-			/* This will also remove references to the registry */
-			dialog_unlink_all(iterator->call);
-			iterator->call = dialog_unref(iterator->call, "remove iterator->call from registry traversal");
-		}
-		if (iterator->expire > -1) {
-			AST_SCHED_DEL_UNREF(sched, iterator->expire, ao2_t_ref(iterator, -1, "reg ptr unref from reload config"));
-		}
-		if (iterator->timeout > -1) {
-			AST_SCHED_DEL_UNREF(sched, iterator->timeout, ao2_t_ref(iterator, -1, "reg ptr unref from reload config"));
-		}
-		if (iterator->dnsmgr) {
-			ast_dnsmgr_release(iterator->dnsmgr);
-			iterator->dnsmgr = NULL;
-			ao2_t_ref(iterator, -1, "reg ptr unref from dnsmgr");
-		}
-
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "cleanup_all_regs iter");
-	}
-	ao2_iterator_destroy(&iter);
+		/* First, destroy all outstanding registry calls */
+		/* This is needed, since otherwise active registry entries will not be destroyed */
+		ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {  /* regl is locked */
+				ASTOBJ_WRLOCK(iterator); /* now regl is locked, and the object is also locked */
+				if (iterator->call) {
+					ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
+					/* This will also remove references to the registry */
+					dialog_unlink_all(iterator->call);
+					iterator->call = dialog_unref(iterator->call, "remove iterator->call from registry traversal");
+				}
+				if (iterator->expire > -1) {
+					AST_SCHED_DEL_UNREF(sched, iterator->expire, registry_unref(iterator, "reg ptr unref from reload config"));
+				}
+				if (iterator->timeout > -1) {
+					AST_SCHED_DEL_UNREF(sched, iterator->timeout, registry_unref(iterator, "reg ptr unref from reload config"));
+				}
+				if (iterator->dnsmgr) {
+					ast_dnsmgr_release(iterator->dnsmgr);
+					iterator->dnsmgr = NULL;
+					registry_unref(iterator, "reg ptr unref from dnsmgr");
+				}
+				ASTOBJ_UNLOCK(iterator);
+		} while(0));
 }
 
 /*! \brief Re-read SIP.conf config file
@@ -31187,8 +31685,10 @@ static int reload_config(enum channelreloadreason reason)
 		}
 		ast_mutex_unlock(&authl_lock);
 
-		/* Then, actually destroy users and registry */
 		cleanup_all_regs();
+
+		/* Then, actually destroy users and registry */
+		ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
 		ast_debug(4, "--------------- Done destroying registry list\n");
 		ao2_t_callback(peers, OBJ_NODATA, peer_markall_func, NULL, "callback to mark all peers");
 	}
@@ -31227,10 +31727,11 @@ static int reload_config(enum channelreloadreason reason)
 	memset(&localaddr, 0, sizeof(localaddr));
 	memset(&externaddr, 0, sizeof(externaddr));
 	memset(&media_address, 0, sizeof(media_address));
+	memset(&default_prefs, 0 , sizeof(default_prefs));
 	memset(&sip_cfg.outboundproxy, 0, sizeof(struct sip_proxy));
 	sip_cfg.outboundproxy.force = FALSE;		/*!< Don't force proxy usage, use route: headers */
-	default_transports = AST_TRANSPORT_UDP;
-	default_primary_transport = AST_TRANSPORT_UDP;
+	default_transports = SIP_TRANSPORT_UDP;
+	default_primary_transport = SIP_TRANSPORT_UDP;
 	ourport_tcp = STANDARD_SIP_PORT;
 	ourport_tls = STANDARD_TLS_PORT;
 	externtcpport = STANDARD_SIP_PORT;
@@ -31337,6 +31838,7 @@ static int reload_config(enum channelreloadreason reason)
 
 	/* Misc settings for the channel */
 	global_relaxdtmf = FALSE;
+	sip_cfg.callevents = DEFAULT_CALLEVENTS;
 	global_authfailureevents = FALSE;
 	global_t1 = DEFAULT_TIMER_T1;
 	global_timer_b = 64 * DEFAULT_TIMER_T1;
@@ -31417,8 +31919,6 @@ static int reload_config(enum channelreloadreason reason)
 			ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);
 		} else if (!strcasecmp(v->name, "rtsavesysname")) {
 			sip_cfg.rtsave_sysname = ast_true(v->value);
-		} else if (!strcasecmp(v->name, "rtsavepath")) {
-			sip_cfg.rtsave_path = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "rtupdate")) {
 			sip_cfg.peer_rtupdate = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "ignoreregexpire")) {
@@ -31446,15 +31946,15 @@ static int reload_config(enum channelreloadreason reason)
 				trans = ast_skip_blanks(trans);
 
 				if (!strncasecmp(trans, "udp", 3)) {
-					default_transports |= AST_TRANSPORT_UDP;
+					default_transports |= SIP_TRANSPORT_UDP;
 				} else if (!strncasecmp(trans, "tcp", 3)) {
-					default_transports |= AST_TRANSPORT_TCP;
+					default_transports |= SIP_TRANSPORT_TCP;
 				} else if (!strncasecmp(trans, "tls", 3)) {
-					default_transports |= AST_TRANSPORT_TLS;
+					default_transports |= SIP_TRANSPORT_TLS;
 				} else if (!strncasecmp(trans, "wss", 3)) {
-					default_transports |= AST_TRANSPORT_WSS;
+					default_transports |= SIP_TRANSPORT_WSS;
 				} else if (!strncasecmp(trans, "ws", 2)) {
-					default_transports |= AST_TRANSPORT_WS;
+					default_transports |= SIP_TRANSPORT_WS;
 				} else {
 					ast_log(LOG_NOTICE, "'%s' is not a valid transport type. if no other is specified, udp will be used.\n", trans);
 				}
@@ -31718,12 +32218,12 @@ static int reload_config(enum channelreloadreason reason)
 				ast_log(LOG_WARNING, "Invalid externtlsport value, must be a positive integer between 1 and 65535 at line %d\n", v->lineno);
 			}
 		} else if (!strcasecmp(v->name, "allow")) {
-			int error =  ast_format_cap_update_by_allow_disallow(sip_cfg.caps, v->value, TRUE);
+			int error =  ast_parse_allow_disallow(&default_prefs, sip_cfg.caps, v->value, TRUE);
 			if (error) {
 				ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
 			}
 		} else if (!strcasecmp(v->name, "disallow")) {
-			int error =  ast_format_cap_update_by_allow_disallow(sip_cfg.caps, v->value, FALSE);
+			int error =  ast_parse_allow_disallow(&default_prefs, sip_cfg.caps, v->value, FALSE);
 			if (error) {
 				ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
 			}
@@ -31819,6 +32319,8 @@ static int reload_config(enum channelreloadreason reason)
 				ast_log(LOG_WARNING, "Invalid qualifyfreq number '%s' at line %d of %s\n", v->value, v->lineno, config);
 				global_qualifyfreq = DEFAULT_QUALIFYFREQ;
 			}
+		} else if (!strcasecmp(v->name, "callevents")) {
+			sip_cfg.callevents = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "authfailureevents")) {
 			global_authfailureevents = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "maxcallbitrate")) {
@@ -31904,8 +32406,6 @@ static int reload_config(enum channelreloadreason reason)
 			ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 		} else if (!strcasecmp(v->name, "icesupport")) {
 			ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_ICE_SUPPORT);
-		} else if (!strcasecmp(v->name, "discard_remote_hold_retrieval")) {
-			ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL);
 		} else if (!strcasecmp(v->name, "parkinglot")) {
 			ast_copy_string(default_parkinglot, v->value, sizeof(default_parkinglot));
 		} else if (!strcasecmp(v->name, "refer_addheaders")) {
@@ -31937,9 +32437,9 @@ static int reload_config(enum channelreloadreason reason)
 	}
 
 	if (subscribe_network_change) {
-		network_change_stasis_subscribe();
+		network_change_event_subscribe();
 	} else {
-		network_change_stasis_unsubscribe();
+		network_change_event_unsubscribe();
 	}
 
 	if (global_t1 < global_t1min) {
@@ -31965,22 +32465,22 @@ static int reload_config(enum channelreloadreason reason)
 		sip_cfg.allow_external_domains = 1;
 	}
 	/* If not or badly configured, set default transports */
-	if (!sip_cfg.tcp_enabled && (default_transports & AST_TRANSPORT_TCP)) {
+	if (!sip_cfg.tcp_enabled && (default_transports & SIP_TRANSPORT_TCP)) {
 		ast_log(LOG_WARNING, "Cannot use 'tcp' transport with tcpenable=no. Removing from available transports.\n");
-		default_primary_transport &= ~AST_TRANSPORT_TCP;
-		default_transports &= ~AST_TRANSPORT_TCP;
+		default_primary_transport &= ~SIP_TRANSPORT_TCP;
+		default_transports &= ~SIP_TRANSPORT_TCP;
 	}
-	if (!default_tls_cfg.enabled && (default_transports & AST_TRANSPORT_TLS)) {
+	if (!default_tls_cfg.enabled && (default_transports & SIP_TRANSPORT_TLS)) {
 		ast_log(LOG_WARNING, "Cannot use 'tls' transport with tlsenable=no. Removing from available transports.\n");
-		default_primary_transport &= ~AST_TRANSPORT_TLS;
-		default_transports &= ~AST_TRANSPORT_TLS;
+		default_primary_transport &= ~SIP_TRANSPORT_TLS;
+		default_transports &= ~SIP_TRANSPORT_TLS;
 	}
 	if (!default_transports) {
 		ast_log(LOG_WARNING, "No valid transports available, falling back to 'udp'.\n");
-		default_transports = default_primary_transport = AST_TRANSPORT_UDP;
+		default_transports = default_primary_transport = SIP_TRANSPORT_UDP;
 	} else if (!default_primary_transport) {
 		ast_log(LOG_WARNING, "No valid default transport. Selecting 'udp' as default.\n");
-		default_primary_transport = AST_TRANSPORT_UDP;
+		default_primary_transport = SIP_TRANSPORT_UDP;
 	}
 
 	/* Build list of authentication to various SIP realms, i.e. service providers */
@@ -32095,7 +32595,7 @@ static int reload_config(enum channelreloadreason reason)
 		struct ast_variable *gen;
 		int genhassip, genregistersip;
 		const char *hassip, *registersip;
-
+		
 		genhassip = ast_true(ast_variable_retrieve(ucfg, "general", "hassip"));
 		genregistersip = ast_true(ast_variable_retrieve(ucfg, "general", "registersip"));
 		gen = ast_variable_browse(ucfg, "general");
@@ -32113,7 +32613,7 @@ static int reload_config(enum channelreloadreason reason)
 						if ((peer->type & SIP_TYPE_PEER) && !ast_sockaddr_isnull(&peer->addr)) {
 							ao2_t_link(peers_by_ip, peer, "link peer into peers_by_ip table");
 						}
-
+						
 						sip_unref_peer(peer, "sip_unref_peer: from reload_config");
 						peer_count++;
 					}
@@ -32240,7 +32740,7 @@ static int reload_config(enum channelreloadreason reason)
 		if (!ast_strlen_zero(externhost)) {
 			add_sip_domain(externhost, SIP_DOMAIN_AUTO, NULL);
 		}
-
+		
 		/* Our host name */
 		if (!gethostname(temp, sizeof(temp))) {
 			add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
@@ -32261,67 +32761,165 @@ static int reload_config(enum channelreloadreason reason)
 		notify_types = NULL;
 	}
 
+	/* Done, tell the manager */
+	manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count);
 	run_end = time(0);
 	ast_debug(4, "SIP reload_config done...Runtime= %d sec\n", (int)(run_end-run_start));
 
 	/* If an ACL change subscription is needed and doesn't exist, we need one. */
 	if (acl_change_subscription_needed) {
-		acl_change_stasis_subscribe();
+		acl_change_event_subscribe();
 	}
 
 	return 0;
 }
 
-static int sip_allow_anyrtp_remote(struct ast_channel *chan1, struct ast_rtp_instance *instance, const char *rtptype)
+static int apply_directmedia_acl(struct sip_pvt *p, struct ast_acl_list *directmediaacl, const char *op)
+{
+	struct ast_sockaddr us = { { 0, }, }, them = { { 0, }, };
+	int res = AST_SENSE_ALLOW;
+
+	ast_rtp_instance_get_remote_address(p->rtp, &them);
+	ast_rtp_instance_get_local_address(p->rtp, &us);
+
+	if ((res = ast_apply_acl(directmediaacl, &them, "SIP Direct Media ACL: ")) == AST_SENSE_DENY) {
+		const char *us_addr = ast_strdupa(ast_sockaddr_stringify(&us));
+		const char *them_addr = ast_strdupa(ast_sockaddr_stringify(&them));
+
+		ast_debug(3, "Reinvite %s to %s denied by directmedia ACL on %s\n",
+			op, them_addr, us_addr);
+	}
+
+	return res;
+}
+
+static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan)
 {
 	struct sip_pvt *p;
-	struct ast_acl_list *acl = NULL;
-	int res = 1;
+	struct ast_udptl *udptl = NULL;
+	
+	p = ast_channel_tech_pvt(chan);
+	if (!p) {
+		return NULL;
+	}
 
-	if (!(p = ast_channel_tech_pvt(chan1))) {
-		return 0;
+	sip_pvt_lock(p);
+	if (p->udptl && ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
+		udptl = p->udptl;
 	}
+	sip_pvt_unlock(p);
+	return udptl;
+}
 
+static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
+{
+	struct sip_pvt *p;
+
+	/* Lock the channel and the private safely. */
+	ast_channel_lock(chan);
+	p = ast_channel_tech_pvt(chan);
+	if (!p) {
+		ast_channel_unlock(chan);
+		return -1;
+	}
 	sip_pvt_lock(p);
-	if (p->relatedpeer && p->relatedpeer->directmediaacl) {
-		acl = ast_duplicate_acl_list(p->relatedpeer->directmediaacl);
+	if (p->owner != chan) {
+		/* I suppose it could be argued that if this happens it is a bug. */
+		ast_debug(1, "The private is not owned by channel %s anymore.\n", ast_channel_name(chan));
+		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
+		return 0;
 	}
+
+	if (udptl) {
+		ast_udptl_get_peer(udptl, &p->udptlredirip);
+	} else {
+		memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+	}
+	if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
+		if (!p->pendinginvite) {
+			ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s\n",
+					p->callid, ast_sockaddr_stringify(udptl ? &p->udptlredirip : &p->ourip));
+			transmit_reinvite_with_sdp(p, TRUE, FALSE);
+		} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+			ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s\n",
+					p->callid, ast_sockaddr_stringify(udptl ? &p->udptlredirip : &p->ourip));
+			ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+		}
+	}
+	/* Reset lastrtprx timer */
+	p->lastrtprx = p->lastrtptx = time(NULL);
 	sip_pvt_unlock(p);
+	ast_channel_unlock(chan);
+	return 0;
+}
 
-	if (!acl) {
-		return res;
+static int sip_allow_anyrtp_remote(struct ast_channel *chan1, struct ast_channel *chan2, char *rtptype)
+{
+	struct sip_pvt *p1 = NULL, *p2 = NULL;
+	struct ast_acl_list *p2_directmediaacl = NULL; /* opposed directmediaha for comparing against first channel host address */
+	struct ast_acl_list *p1_directmediaacl = NULL; /* opposed directmediaha for comparing against second channel host address */
+	int res = 1;
+
+	if (!(p1 = ast_channel_tech_pvt(chan1))) {
+		return 0;
 	}
 
-	if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
-		struct ast_sockaddr us = { { 0, }, }, them = { { 0, }, };
+	if (!(p2 = ast_channel_tech_pvt(chan2))) {
+		return 0;
+	}
 
-		ast_rtp_instance_get_remote_address(instance, &them);
-		ast_rtp_instance_get_local_address(instance, &us);
+	sip_pvt_lock(p2);
+	if (p2->relatedpeer && p2->relatedpeer->directmediaacl) {
+		p2_directmediaacl = ast_duplicate_acl_list(p2->relatedpeer->directmediaacl);
+	}
+	sip_pvt_unlock(p2);
 
-		if (ast_apply_acl(acl, &them, "SIP Direct Media ACL: ") == AST_SENSE_DENY) {
-			const char *us_addr = ast_strdupa(ast_sockaddr_stringify(&us));
-			const char *them_addr = ast_strdupa(ast_sockaddr_stringify(&them));
+	sip_pvt_lock(p1);
+	if (p1->relatedpeer && p1->relatedpeer->directmediaacl) {
+		p1_directmediaacl = ast_duplicate_acl_list(p1->relatedpeer->directmediaacl);
+	}
 
-			ast_debug(3, "Reinvite %s to %s denied by directmedia ACL on %s\n",
-				  rtptype, them_addr, us_addr);
+	if (p2_directmediaacl && ast_test_flag(&p1->flags[0], SIP_DIRECT_MEDIA)) {
+		if (!apply_directmedia_acl(p1, p2_directmediaacl, rtptype)) {
+			res = 0;
+		}
+	}
+	sip_pvt_unlock(p1);
+
+	if (res == 0) {
+		goto allow_anyrtp_remote_end;
+	}
 
+	sip_pvt_lock(p2);
+	if (p1_directmediaacl && ast_test_flag(&p2->flags[0], SIP_DIRECT_MEDIA)) {
+		if (!apply_directmedia_acl(p2, p1_directmediaacl, rtptype)) {
 			res = 0;
 		}
 	}
+	sip_pvt_unlock(p2);
 
-	ast_free_acl_list(acl);
+allow_anyrtp_remote_end:
+
+	if (p2_directmediaacl) {
+		p2_directmediaacl = ast_free_acl_list(p2_directmediaacl);
+	}
+
+	if (p1_directmediaacl) {
+		p1_directmediaacl = ast_free_acl_list(p1_directmediaacl);
+	}
 
 	return res;
 }
 
-static int sip_allow_rtp_remote(struct ast_channel *chan1, struct ast_rtp_instance *instance)
+static int sip_allow_rtp_remote(struct ast_channel *chan1, struct ast_channel *chan2)
 {
-	return sip_allow_anyrtp_remote(chan1, instance, "audio");
+	return sip_allow_anyrtp_remote(chan1, chan2, "audio");
 }
 
-static int sip_allow_vrtp_remote(struct ast_channel *chan1, struct ast_rtp_instance *instance)
+static int sip_allow_vrtp_remote(struct ast_channel *chan1, struct ast_channel *chan2)
 {
-	return sip_allow_anyrtp_remote(chan1, instance, "video");
+	return sip_allow_anyrtp_remote(chan1, chan2, "video");
 }
 
 static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
@@ -32350,19 +32948,6 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc
 		res = AST_RTP_GLUE_RESULT_FORBID;
 	}
 
-	if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
-		switch (p->t38.state) {
-		case T38_LOCAL_REINVITE:
-		case T38_PEER_REINVITE:
-		case T38_ENABLED:
-			res = AST_RTP_GLUE_RESULT_LOCAL;
-			break;
-		case T38_REJECTED:
-		default:
-			break;
-		}
-	}
-
 	if (p->srtp) {
 		res = AST_RTP_GLUE_RESULT_FORBID;
 	}
@@ -32431,8 +33016,11 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 	struct sip_pvt *p;
 	int changed = 0;
 
+	/* Lock the channel and the private safely. */
+	ast_channel_lock(chan);
 	p = ast_channel_tech_pvt(chan);
 	if (!p) {
+		ast_channel_unlock(chan);
 		return -1;
 	}
 	sip_pvt_lock(p);
@@ -32440,20 +33028,23 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 		/* I suppose it could be argued that if this happens it is a bug. */
 		ast_debug(1, "The private is not owned by channel %s anymore.\n", ast_channel_name(chan));
 		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
 		return 0;
 	}
 
 	/* Disable early RTP bridge  */
 	if ((instance || vinstance || tinstance) &&
-		!ast_channel_is_bridged(chan) &&
+		!ast_bridged_channel(chan) &&
 		!sip_cfg.directrtpsetup) {
 		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
 		return 0;
 	}
 
 	if (p->alreadygone) {
 		/* If we're destroyed, don't bother */
 		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
 		return 0;
 	}
 
@@ -32462,6 +33053,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 	*/
 	if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
 		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
 		return 0;
 	}
 
@@ -32515,9 +33107,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 		memset(&p->tredirip, 0, sizeof(p->tredirip));
 		changed = 1;
 	}
-	if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(cap, p->redircaps)) {
-		ast_format_cap_remove_by_type(p->redircaps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(p->redircaps, cap, AST_MEDIA_TYPE_UNKNOWN);
+	if (cap && !ast_format_cap_is_empty(cap) && !ast_format_cap_identical(p->redircaps, cap)) {
+		ast_format_cap_copy(p->redircaps, cap);
 		changed = 1;
 	}
 
@@ -32528,6 +33119,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 		 */
 		ast_clear_flag(&p->flags[2], SIP_PAGE3_DIRECT_MEDIA_OUTGOING);
 		sip_pvt_unlock(p);
+		ast_channel_unlock(chan);
 		return 0;
 	}
 
@@ -32548,14 +33140,14 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
 	/* Reset lastrtprx timer */
 	p->lastrtprx = p->lastrtptx = time(NULL);
 	sip_pvt_unlock(p);
+	ast_channel_unlock(chan);
 	return 0;
 }
 
 static void sip_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
 {
 	struct sip_pvt *p = ast_channel_tech_pvt(chan);
-
-	ast_format_cap_append_from_cap(result, !ast_format_cap_count(p->peercaps) ? p->caps : p->peercaps, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_append(result, ast_format_cap_is_empty(p->peercaps) ? p->caps : p->peercaps);
 }
 
 static struct ast_rtp_glue sip_rtp_glue = {
@@ -32638,7 +33230,7 @@ static int sip_addheader(struct ast_channel *chan, const char *data)
 	char varbuf[30];
 	const char *inbuf = data;
 	char *subbuf;
-
+	
 	if (ast_strlen_zero(inbuf)) {
 		ast_log(LOG_WARNING, "This application requires the argument: Header\n");
 		return 0;
@@ -32685,7 +33277,7 @@ static int sip_removeheader(struct ast_channel *chan, const char *data)
 
 	headp=ast_channel_varshead(chan);
 	AST_LIST_TRAVERSE_SAFE_BEGIN (headp, newvariable, entries) {
-		if (strncmp(ast_var_name(newvariable), "SIPADDHEADER", strlen("SIPADDHEADER")) == 0) {
+		if (strncasecmp(ast_var_name(newvariable), "SIPADDHEADER", strlen("SIPADDHEADER")) == 0) {
 			if (removeall || (!strncasecmp(ast_var_value(newvariable),inbuf,strlen(inbuf)))) {
 				if (sipdebug) {
 					ast_debug(1,"removing SIP Header \"%s\" as %s\n",
@@ -32855,53 +33447,57 @@ static void sip_send_all_registers(void)
 {
 	int ms;
 	int regspacing;
-	struct ao2_iterator iter;
-	struct sip_registry *iterator;
-
-	if (!ao2_container_count(registry_list)) {
+	if (!regobjs) {
 		return;
 	}
-	regspacing = default_expiry * 1000 / ao2_container_count(registry_list);
+	regspacing = default_expiry * 1000/regobjs;
 	if (regspacing > 100) {
 		regspacing = 100;
 	}
 	ms = regspacing;
-
-	iter = ao2_iterator_init(registry_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "sip_send_all_registers iter"))) {
-		ao2_lock(iterator);
+	ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
+		ASTOBJ_WRLOCK(iterator);
 		ms += regspacing;
 		AST_SCHED_REPLACE_UNREF(iterator->expire, sched, ms, sip_reregister, iterator,
-								ao2_t_ref(_data, -1, "REPLACE sched del decs the refcount"),
-								ao2_t_ref(iterator, -1, "REPLACE sched add failure decs the refcount"),
-								ao2_t_ref(iterator, +1, "REPLACE sched add incs the refcount"));
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "sip_send_all_registers iter");
-	}
-	ao2_iterator_destroy(&iter);
+								registry_unref(_data, "REPLACE sched del decs the refcount"),
+								registry_unref(iterator, "REPLACE sched add failure decs the refcount"),
+								registry_addref(iterator, "REPLACE sched add incs the refcount"));
+		ASTOBJ_UNLOCK(iterator);
+	} while (0)
+	);
 }
 
 /*! \brief Send all MWI subscriptions */
 static void sip_send_all_mwi_subscriptions(void)
 {
-	struct ao2_iterator iter;
-	struct sip_subscription_mwi *iterator;
-
-	iter = ao2_iterator_init(subscription_mwi_list, 0);
-	while ((iterator = ao2_t_iterator_next(&iter, "sip_send_all_mwi_subscriptions iter"))) {
-		ao2_lock(iterator);
+	ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+		struct sip_subscription_mwi *saved;
+		ASTOBJ_WRLOCK(iterator);
 		AST_SCHED_DEL(sched, iterator->resub);
-		ao2_t_ref(iterator, +1, "mwi added to schedule");
-		if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, iterator)) < 0) {
-			ao2_t_ref(iterator, -1, "mwi failed to schedule");
+		saved = ASTOBJ_REF(iterator);
+		if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, saved)) < 0) {
+			ASTOBJ_UNREF(saved, sip_subscribe_mwi_destroy);
 		}
-		ao2_unlock(iterator);
-		ao2_t_ref(iterator, -1, "sip_send_all_mwi_subscriptions iter");
+		ASTOBJ_UNLOCK(iterator);
+	} while (0));
+}
+
+/* SRTP */
+static int setup_srtp(struct sip_srtp **srtp)
+{
+	if (!ast_rtp_engine_srtp_is_registered()) {
+		ast_log(LOG_ERROR, "No SRTP module loaded, can't setup SRTP session.\n");
+		return -1;
 	}
-	ao2_iterator_destroy(&iter);
+
+	if (!(*srtp = sip_srtp_alloc())) { /* Allocate SRTP data structure */
+		return -1;
+	}
+
+	return 0;
 }
 
-static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a)
+static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a)
 {
 	struct ast_rtp_engine_dtls *dtls;
 
@@ -32914,28 +33510,27 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc
 	if (strncasecmp(a, "crypto:", 7)) {
 		return FALSE;
 	}
-	/* skip "crypto:" */
-	a += strlen("crypto:");
-
 	if (!*srtp) {
 		if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 			ast_log(LOG_WARNING, "Ignoring unexpected crypto attribute in SDP answer\n");
 			return FALSE;
 		}
 
-		if (!(*srtp = ast_sdp_srtp_alloc())) {
+		if (setup_srtp(srtp) < 0) {
 			return FALSE;
 		}
 	}
 
-	if (!(*srtp)->crypto && !((*srtp)->crypto = ast_sdp_crypto_alloc())) {
+	if (!(*srtp)->crypto && !((*srtp)->crypto = sdp_crypto_setup())) {
 		return FALSE;
 	}
 
-	if (ast_sdp_crypto_process(rtp, *srtp, a) < 0) {
+	if (sdp_crypto_process((*srtp)->crypto, a, rtp, *srtp) < 0) {
 		return FALSE;
 	}
 
+	ast_set_flag(*srtp, SRTP_CRYPTO_OFFER_OK);
+
 	if ((dtls = ast_rtp_instance_get_dtls(rtp))) {
 		dtls->stop(rtp);
 		p->dtls_cfg.enabled = 0;
@@ -33030,7 +33625,7 @@ static int reload(void)
 
 /*! \brief  Return the first entry from ast_sockaddr_resolve filtered by address family
  *
- * \warning Using this function probably means you have a faulty design.
+ * \warn Using this function probably means you have a faulty design.
  */
 static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
 				      const char* name, int flag, int family)
@@ -33054,17 +33649,17 @@ static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
 
 /*! \brief  Return the first entry from ast_sockaddr_resolve filtered by family of binddaddr
  *
- * \warning Using this function probably means you have a faulty design.
+ * \warn Using this function probably means you have a faulty design.
  */
 static int ast_sockaddr_resolve_first(struct ast_sockaddr *addr,
 				      const char* name, int flag)
 {
-	return ast_sockaddr_resolve_first_af(addr, name, flag, get_address_family_filter(AST_TRANSPORT_UDP));
+	return ast_sockaddr_resolve_first_af(addr, name, flag, get_address_family_filter(SIP_TRANSPORT_UDP));
 }
 
 /*! \brief  Return the first entry from ast_sockaddr_resolve filtered by family of binddaddr
  *
- * \warning Using this function probably means you have a faulty design.
+ * \warn Using this function probably means you have a faulty design.
  */
 static int ast_sockaddr_resolve_first_transport(struct ast_sockaddr *addr,
 						const char* name, int flag, unsigned int transport)
@@ -33151,7 +33746,7 @@ static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags)
 	}
 
 	/* We matched the IP, check to see if we need to match by port as well. */
-	if ((peer->transports & peer2->transports) & (AST_TRANSPORT_TLS | AST_TRANSPORT_TCP)) {
+	if ((peer->transports & peer2->transports) & (SIP_TRANSPORT_TLS | SIP_TRANSPORT_TCP)) {
 		/* peer matching on port is not possible with TCP/TLS */
 		return CMP_MATCH | CMP_STOP;
 	} else if (ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
@@ -33215,53 +33810,6 @@ static int dialog_cmp_cb(void *obj, void *arg, int flags)
 	return !strcasecmp(pvt->callid, pvt2->callid) ? CMP_MATCH | CMP_STOP : 0;
 }
 
-
-static int registry_hash_cb(const void *obj, const int flags)
-{
-	const struct sip_registry *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->configvalue;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int registry_cmp_cb(void *obj, void *arg, int flags)
-{
-	const struct sip_registry *object_left = obj;
-	const struct sip_registry *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->configvalue;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->configvalue, right_key);
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-
 /*! \brief SIP Cli commands definition */
 static struct ast_cli_entry cli_sip[] = {
 	AST_CLI_DEFINE(sip_show_channels, "List active SIP channels or subscriptions"),
@@ -33308,8 +33856,6 @@ static void sip_unregister_tests(void)
 #ifdef TEST_FRAMEWORK
 AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 {
-	struct ao2_iterator iter;
-	struct sip_subscription_mwi *iterator;
 	int found = 0;
 	enum ast_test_result_state res = AST_TEST_PASS;
 	const char *mwi1 = "1234 at mysipprovider.com/1234";
@@ -33336,10 +33882,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 	} else {
 		found = 0;
 		res = AST_TEST_FAIL;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "test_sip_mwi_subscribe_parse mwi1"))) {
-			ao2_lock(iterator);
+		ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+			ASTOBJ_WRLOCK(iterator);
 			if (
 				!strcmp(iterator->hostname, "mysipprovider.com") &&
 				!strcmp(iterator->username, "1234") &&
@@ -33350,10 +33894,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 				found = 1;
 				res = AST_TEST_PASS;
 			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "test_sip_mwi_subscribe_parse mwi1");
-		}
-		ao2_iterator_destroy(&iter);
+			ASTOBJ_UNLOCK(iterator);
+		} while(0));
 		if (!found) {
 			ast_test_status_update(test, "sip_subscribe_mwi test 1 failed\n");
 		}
@@ -33364,10 +33906,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 	} else {
 		found = 0;
 		res = AST_TEST_FAIL;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "test_sip_mwi_subscribe_parse mwi2"))) {
-			ao2_lock(iterator);
+		ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+			ASTOBJ_WRLOCK(iterator);
 			if (
 				!strcmp(iterator->hostname, "mysipprovider.com") &&
 				!strcmp(iterator->username, "1234") &&
@@ -33378,10 +33918,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 				found = 1;
 				res = AST_TEST_PASS;
 			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "test_sip_mwi_subscribe_parse mwi2");
-		}
-		ao2_iterator_destroy(&iter);
+			ASTOBJ_UNLOCK(iterator);
+		} while(0));
 		if (!found) {
 			ast_test_status_update(test, "sip_subscribe_mwi test 2 failed\n");
 		}
@@ -33392,10 +33930,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 	} else {
 		found = 0;
 		res = AST_TEST_FAIL;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "test_sip_mwi_subscribe_parse mwi3"))) {
-			ao2_lock(iterator);
+		ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+			ASTOBJ_WRLOCK(iterator);
 			if (
 				!strcmp(iterator->hostname, "mysipprovider.com") &&
 				!strcmp(iterator->username, "1234") &&
@@ -33406,10 +33942,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 				found = 1;
 				res = AST_TEST_PASS;
 			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "test_sip_mwi_subscribe_parse mwi3");
-		}
-		ao2_iterator_destroy(&iter);
+			ASTOBJ_UNLOCK(iterator);
+		} while(0));
 		if (!found) {
 			ast_test_status_update(test, "sip_subscribe_mwi test 3 failed\n");
 		}
@@ -33420,10 +33954,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 	} else {
 		found = 0;
 		res = AST_TEST_FAIL;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "test_sip_mwi_subscribe_parse mwi4"))) {
-			ao2_lock(iterator);
+		ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+			ASTOBJ_WRLOCK(iterator);
 			if (
 				!strcmp(iterator->hostname, "mysipprovider.com") &&
 				!strcmp(iterator->username, "1234") &&
@@ -33434,10 +33966,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 				found = 1;
 				res = AST_TEST_PASS;
 			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "test_sip_mwi_subscribe_parse mwi4");
-		}
-		ao2_iterator_destroy(&iter);
+			ASTOBJ_UNLOCK(iterator);
+		} while(0));
 		if (!found) {
 			ast_test_status_update(test, "sip_subscribe_mwi test 4 failed\n");
 		}
@@ -33448,10 +33978,8 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 	} else {
 		found = 0;
 		res = AST_TEST_FAIL;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "test_sip_mwi_subscribe_parse mwi4"))) {
-			ao2_lock(iterator);
+		ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+			ASTOBJ_WRLOCK(iterator);
 			if (
 				!strcmp(iterator->hostname, "mysipprovider.com") &&
 				!strcmp(iterator->username, "1234") &&
@@ -33462,15 +33990,13 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse)
 				found = 1;
 				res = AST_TEST_PASS;
 			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "test_sip_mwi_subscribe_parse mwi4");
-		}
-		ao2_iterator_destroy(&iter);
+			ASTOBJ_UNLOCK(iterator);
+		} while(0));
 		if (!found) {
 			ast_test_status_update(test, "sip_subscribe_mwi test 5 failed\n");
 		}
 	}
-
+	
 	if (sip_subscribe_mwi(mwi6, 1)) {
 		res = AST_TEST_PASS;
 	} else {
@@ -34185,7 +34711,8 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 			if (!data_peer_mailbox) {
 				continue;
 			}
-			ast_data_add_str(data_peer_mailbox, "id", mailbox->id);
+			ast_data_add_str(data_peer_mailbox, "mailbox", mailbox->mailbox);
+			ast_data_add_str(data_peer_mailbox, "context", mailbox->context);
 		}
 
 		/* amaflags */
@@ -34196,7 +34723,7 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 			continue;
 		}
 		ast_data_add_int(enum_node, "value", peer->amaflags);
-		ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(peer->amaflags));
+		ast_data_add_str(enum_node, "text", ast_cdr_flags2str(peer->amaflags));
 
 		/* sip options */
 		data_sip_options = ast_data_add_node(data_peer, "sipoptions");
@@ -34249,34 +34776,16 @@ static const struct ast_sip_api_tech chan_sip_api_provider = {
 	.sipinfo_send = sipinfo_send,
 };
 
-static int unload_module(void);
-
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief PBX load module - initialization */
 static int load_module(void)
 {
 	ast_verbose("SIP channel loading...\n");
 
-	if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (!(sip_tech.capabilities = ast_format_cap_alloc(0))) {
-		unload_module();
+	if (!(sip_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
 	if (ast_sip_api_provider_register(&chan_sip_api_provider)) {
-		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -34291,29 +34800,24 @@ static int load_module(void)
 	if (!peers || !peers_by_ip || !dialogs || !dialogs_needdestroy || !dialogs_rtpcheck
 		|| !threadt) {
 		ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n");
-		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (!(sip_cfg.caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		unload_module();
+	if (!(sip_cfg.caps = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
-	ast_format_cap_append_by_type(sip_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
+	ast_format_cap_add_all_by_type(sip_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
 
-	registry_list = ao2_t_container_alloc(HASH_REGISTRY_SIZE, registry_hash_cb, registry_cmp_cb, "allocate registry_list");
-	subscription_mwi_list = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, NULL, NULL, "allocate subscription_mwi_list");
+	ASTOBJ_CONTAINER_INIT(&regl); /* Registry object list -- not searched for anything */
+	ASTOBJ_CONTAINER_INIT(&submwil); /* MWI subscription object list */
 
 	if (!(sched = ast_sched_context_create())) {
 		ast_log(LOG_ERROR, "Unable to create scheduler context\n");
-		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
 	if (!(io = io_context_create())) {
 		ast_log(LOG_ERROR, "Unable to create I/O context\n");
-		unload_module();
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -34321,14 +34825,15 @@ static int load_module(void)
 
 	can_parse_xml = sip_is_xml_parsable();
 	if (reload_config(sip_reloadreason)) {	/* Load the configuration from sip.conf */
-		unload_module();
+		ast_sip_api_provider_unregister();
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
 	/* Initialize bogus peer. Can be done first after reload_config() */
 	if (!(bogus_peer = temp_peer("(bogus_peer)"))) {
 		ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n");
-		unload_module();
+		io_context_destroy(io);
+		ast_sched_context_destroy(sched);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 	/* Make sure the auth will always fail. */
@@ -34343,14 +34848,16 @@ static int load_module(void)
 	memset((void *) &sip_tech_info.send_digit_begin, 0, sizeof(sip_tech_info.send_digit_begin));
 
 	if (ast_msg_tech_register(&sip_msg_tech)) {
-		unload_module();
+		/* LOAD_FAILURE stops Asterisk, so cleanup is a moot point. */
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
 	/* Make sure we can register our sip channel type */
 	if (ast_channel_register(&sip_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n");
-		unload_module();
+		ao2_t_ref(bogus_peer, -1, "unref the bogus_peer");
+		io_context_destroy(io);
+		ast_sched_context_destroy(sched);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -34367,6 +34874,9 @@ static int load_module(void)
 	/* Register all CLI functions for SIP */
 	ast_cli_register_multiple(cli_sip, ARRAY_LEN(cli_sip));
 
+	/* Tell the UDPTL subdriver that we're here */
+	ast_udptl_proto_register(&sip_udptl);
+
 	/* Tell the RTP engine about our RTP glue */
 	ast_rtp_glue_register(&sip_rtp_glue);
 
@@ -34381,6 +34891,7 @@ static int load_module(void)
 	/* Register dialplan functions */
 	ast_custom_function_register(&sip_header_function);
 	ast_custom_function_register(&sippeer_function);
+	ast_custom_function_register(&sipchaninfo_function);
 	ast_custom_function_register(&checksipdomain_function);
 
 	/* Register manager commands */
@@ -34397,13 +34908,13 @@ static int load_module(void)
 	initialize_escs();
 
 	if (sip_epa_register(&cc_epa_static_data)) {
-		unload_module();
+		ast_sip_api_provider_unregister();
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
 	if (sip_reqresp_parser_init() == -1) {
 		ast_log(LOG_ERROR, "Unable to initialize the SIP request and response parser\n");
-		unload_module();
+		ast_sip_api_provider_unregister();
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -34412,16 +34923,16 @@ static int load_module(void)
 		 * in incoming PUBLISH requests
 		 */
 		if (ast_cc_agent_register(&sip_cc_agent_callbacks)) {
-			unload_module();
+			ast_sip_api_provider_unregister();
 			return AST_MODULE_LOAD_DECLINE;
 		}
 	}
 	if (ast_cc_monitor_register(&sip_cc_monitor_callbacks)) {
-		unload_module();
+		ast_sip_api_provider_unregister();
 		return AST_MODULE_LOAD_DECLINE;
 	}
 	if (!(sip_monitor_instances = ao2_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn))) {
-		unload_module();
+		ast_sip_api_provider_unregister();
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -34442,7 +34953,7 @@ static int load_module(void)
 
 
 	sip_register_tests();
-	network_change_stasis_subscribe();
+	network_change_event_subscribe();
 
 	ast_websocket_add_protocol("sip", sip_websocket_callback);
 
@@ -34454,7 +34965,6 @@ static int unload_module(void)
 {
 	struct sip_pvt *p;
 	struct sip_threadinfo *th;
-	struct ast_context *con;
 	struct ao2_iterator i;
 	int wait_count;
 
@@ -34462,17 +34972,18 @@ static int unload_module(void)
 
 	ast_websocket_remove_protocol("sip", sip_websocket_callback);
 
-	network_change_stasis_unsubscribe();
-	acl_change_event_stasis_unsubscribe();
+	network_change_event_unsubscribe();
+	acl_change_event_unsubscribe();
 
 	ast_sched_dump(sched);
-
+	
 	/* First, take us out of the channel type list */
 	ast_channel_unregister(&sip_tech);
 
 	ast_msg_tech_unregister(&sip_msg_tech);
 
 	/* Unregister dial plan functions */
+	ast_custom_function_unregister(&sipchaninfo_function);
 	ast_custom_function_unregister(&sippeer_function);
 	ast_custom_function_unregister(&sip_header_function);
 	ast_custom_function_unregister(&checksipdomain_function);
@@ -34495,6 +35006,9 @@ static int unload_module(void)
 	/* Unregister CLI commands */
 	ast_cli_unregister_multiple(cli_sip, ARRAY_LEN(cli_sip));
 
+	/* Disconnect from UDPTL */
+	ast_udptl_proto_unregister(&sip_udptl);
+
 	/* Disconnect from RTP engine */
 	ast_rtp_glue_unregister(&sip_rtp_glue);
 
@@ -34505,7 +35019,7 @@ static int unload_module(void)
 	ast_manager_unregister("SIPshowregistry");
 	ast_manager_unregister("SIPnotify");
 	ast_manager_unregister("SIPpeerstatus");
-
+	
 	/* Kill TCP/TLS server threads */
 	if (sip_tcp_desc.master) {
 		ast_tcptls_server_stop(&sip_tcp_desc);
@@ -34562,7 +35076,7 @@ static int unload_module(void)
 
 	ast_mutex_lock(&authl_lock);
 	if (authl) {
-		ao2_t_cleanup(authl, "Removing global authentication");
+		ao2_t_ref(authl, -1, "Removing global authentication");
 		authl = NULL;
 	}
 	ast_mutex_unlock(&authl_lock);
@@ -34577,26 +35091,20 @@ static int unload_module(void)
 	ast_free(default_tls_cfg.capath);
 
 	cleanup_all_regs();
-	ao2_cleanup(registry_list);
+	ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&regl);
 
-	{
-		struct ao2_iterator iter;
-		struct sip_subscription_mwi *iterator;
-
-		iter = ao2_iterator_init(subscription_mwi_list, 0);
-		while ((iterator = ao2_t_iterator_next(&iter, "unload_module iter"))) {
-			ao2_lock(iterator);
-			if (iterator->dnsmgr) {
-				ast_dnsmgr_release(iterator->dnsmgr);
-				iterator->dnsmgr = NULL;
-				ao2_t_ref(iterator, -1, "dnsmgr release");
-			}
-			ao2_unlock(iterator);
-			ao2_t_ref(iterator, -1, "unload_module iter");
+	ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+		ASTOBJ_WRLOCK(iterator);
+		if (iterator->dnsmgr) {
+			ast_dnsmgr_release(iterator->dnsmgr);
+			iterator->dnsmgr = NULL;
+			ASTOBJ_UNREF(iterator, sip_subscribe_mwi_destroy);
 		}
-		ao2_iterator_destroy(&iter);
-	}
-	ao2_cleanup(subscription_mwi_list);
+		ASTOBJ_UNLOCK(iterator);
+	} while(0));
+	ASTOBJ_CONTAINER_DESTROYALL(&submwil, sip_subscribe_mwi_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&submwil);
 
 	/*
 	 * Wait awhile for the TCP/TLS thread container to become empty.
@@ -34613,15 +35121,15 @@ static int unload_module(void)
 		ast_debug(2, "TCP/TLS thread container did not become empty :(\n");
 	}
 
-	ao2_t_cleanup(bogus_peer, "unref the bogus_peer");
+	ao2_t_ref(bogus_peer, -1, "unref the bogus_peer");
 
-	ao2_t_cleanup(peers, "unref the peers table");
-	ao2_t_cleanup(peers_by_ip, "unref the peers_by_ip table");
-	ao2_t_cleanup(dialogs, "unref the dialogs table");
-	ao2_t_cleanup(dialogs_needdestroy, "unref dialogs_needdestroy");
-	ao2_t_cleanup(dialogs_rtpcheck, "unref dialogs_rtpcheck");
-	ao2_t_cleanup(threadt, "unref the thread table");
-	ao2_t_cleanup(sip_monitor_instances, "unref the sip_monitor_instances table");
+	ao2_t_ref(peers, -1, "unref the peers table");
+	ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table");
+	ao2_t_ref(dialogs, -1, "unref the dialogs table");
+	ao2_t_ref(dialogs_needdestroy, -1, "unref dialogs_needdestroy");
+	ao2_t_ref(dialogs_rtpcheck, -1, "unref dialogs_rtpcheck");
+	ao2_t_ref(threadt, -1, "unref the thread table");
+	ao2_t_ref(sip_monitor_instances, -1, "unref the sip_monitor_instances table");
 
 	clear_sip_domains();
 	sip_cfg.contact_acl = ast_free_acl_list(sip_cfg.contact_acl);
@@ -34632,10 +35140,7 @@ static int unload_module(void)
 	close(sipsock);
 	io_context_destroy(io);
 	ast_sched_context_destroy(sched);
-	con = ast_context_find(used_context);
-	if (con) {
-		ast_context_destroy(con, "SIP");
-	}
+	ast_context_destroy_by_name(used_context, "SIP");
 	ast_unload_realtime("sipregs");
 	ast_unload_realtime("sippeers");
 	ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
@@ -34649,21 +35154,16 @@ static int unload_module(void)
 		notify_types = NULL;
 	}
 
-	ao2_cleanup(sip_tech.capabilities);
-	sip_tech.capabilities = NULL;
-	ao2_cleanup(sip_cfg.caps);
-	sip_cfg.caps = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type);
+	ast_format_cap_destroy(sip_tech.capabilities);
+	sip_cfg.caps = ast_format_cap_destroy(sip_cfg.caps);
 
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Session Initiation Protocol (SIP)",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
 		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
-		.nonoptreq = "res_crypto,res_http_websocket",
+		.nonoptreq = "res_crypto,chan_local,res_http_websocket",
 	       );
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 8317b89..9462eb6 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -25,21 +25,13 @@
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_skinny.c uses the configuration file \ref skinny.conf
- * \addtogroup configuration_file
- */
-
-/*! \page skinny.conf skinny.conf
- * \verbinclude skinny.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -67,9 +59,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/cli.h"
 #include "asterisk/manager.h"
 #include "asterisk/say.h"
+#include "asterisk/cdr.h"
 #include "asterisk/astdb.h"
-#include "asterisk/causes.h"
-#include "asterisk/pickup.h"
+#include "asterisk/features.h"
 #include "asterisk/app.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/utils.h"
@@ -78,13 +70,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/abstract_jb.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/devicestate.h"
+#include "asterisk/event.h"
 #include "asterisk/indications.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/bridge.h"
-#include "asterisk/parking.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<manager name="SKINNYdevices" language="en_US">
@@ -147,6 +135,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #ifdef AST_DEVMODE
 static int skinnydebug = 0;
 char dbgcli_buf[256];
+char dbgreg_buf[256];
+char dbgsub_buf[256];
 #define DEBUG_GENERAL	(1 << 1)
 #define DEBUG_SUB	(1 << 2)
 #define DEBUG_PACKET	(1 << 3)
@@ -155,7 +145,6 @@ char dbgcli_buf[256];
 #define DEBUG_TEMPLATE	(1 << 6)
 #define DEBUG_THREAD	(1 << 7)
 #define DEBUG_HINT	(1 << 8)
-#define DEBUG_KEEPALIVE (1 << 9)
 #define SKINNY_DEBUG(type, verb_level, text, ...)						\
 	do{											\
 		if (skinnydebug & (type)) {							\
@@ -173,11 +162,11 @@ static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
 static const char config[] = "skinny.conf";
 
 static struct ast_format_cap *default_cap;
+static struct ast_codec_pref default_prefs;
 
 enum skinny_codecs {
 	SKINNY_CODEC_ALAW = 2,
 	SKINNY_CODEC_ULAW = 4,
-	SKINNY_CODEC_G722 = 6,
 	SKINNY_CODEC_G723_1 = 9,
 	SKINNY_CODEC_G729A = 12,
 	SKINNY_CODEC_G726_32 = 82, /* XXX Which packing order does this translate to? */
@@ -204,7 +193,6 @@ static int keep_alive = 120;
 static int auth_timeout = DEFAULT_AUTH_TIMEOUT;
 static int auth_limit = DEFAULT_AUTH_LIMIT;
 static int unauth_sessions = 0;
-static char immed_dialchar;
 static char vmexten[AST_MAX_EXTENSION];      /* Voicemail pilot number */
 static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */
 static char regcontext[AST_MAX_CONTEXT];     /* Context for auto-extension */
@@ -404,11 +392,6 @@ struct soft_key_event_message {
 #define HEADSET_STATUS_MESSAGE 0x002B
 #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
 
-#define SERVICEURL_STATREQ_MESSAGE 0x0033
-struct serviceurl_statreq_message {
-	uint32_t instance;
-};
-
 #define REGISTER_ACK_MESSAGE 0x0081
 struct register_ack_message {
 	uint32_t keepAlive;
@@ -583,7 +566,6 @@ struct button_definition_template {
 #define STIMULUS_LINE 0x09
 #define STIMULUS_VOICEMAIL 0x0F
 #define STIMULUS_AUTOANSWER 0x11
-#define STIMULUS_SERVICEURL 0x14
 #define STIMULUS_DND 0x3F
 #define STIMULUS_CONFERENCE 0x7D
 #define STIMULUS_CALLPARK 0x7E
@@ -602,7 +584,6 @@ struct button_definition_template {
 #define BT_LINE STIMULUS_LINE
 #define BT_VOICEMAIL STIMULUS_VOICEMAIL
 #define BT_AUTOANSWER STIMULUS_AUTOANSWER
-#define BT_SERVICEURL STIMULUS_SERVICEURL
 #define BT_DND STIMULUS_DND
 #define BT_CONFERENCE STIMULUS_CONFERENCE
 #define BT_CALLPARK STIMULUS_CALLPARK
@@ -706,7 +687,6 @@ struct bksp_req_message {
 #define KEYDEF_UNKNOWN 10
 #define KEYDEF_SLAHOLD 11
 #define KEYDEF_SLACONNECTEDNOTACTIVE 12
-#define KEYDEF_RINGOUTWITHTRANS 13
 
 #define SOFTKEY_NONE 0x00
 #define SOFTKEY_REDIAL 0x01
@@ -729,188 +709,164 @@ struct bksp_req_message {
 #define SOFTKEY_GPICKUP 0x12
 #define SOFTKEY_DND 0x13
 #define SOFTKEY_IDIVERT 0x14
-#define SOFTKEY_FORCEDIAL 0x15
-
-#define KEYMASK_ALL            0xFFFFFFFF
-#define KEYMASK_NONE           (1 << 0)
-#define KEYMASK_REDIAL         (1 << 1)
-#define KEYMASK_NEWCALL        (1 << 2)
-#define KEYMASK_HOLD           (1 << 3)
-#define KEYMASK_TRNSFER        (1 << 4)
-#define KEYMASK_CFWDALL        (1 << 5)
-#define KEYMASK_CFWDBUSY       (1 << 6)
-#define KEYMASK_CFWDNOANSWER   (1 << 7)
-#define KEYMASK_BKSPC          (1 << 8)
-#define KEYMASK_ENDCALL        (1 << 9)
-#define KEYMASK_RESUME         (1 << 10)
-#define KEYMASK_ANSWER         (1 << 11)
-#define KEYMASK_INFO           (1 << 12)
-#define KEYMASK_CONFRN         (1 << 13)
-#define KEYMASK_PARK           (1 << 14)
-#define KEYMASK_JOIN           (1 << 15)
-#define KEYMASK_MEETME         (1 << 16)
-#define KEYMASK_PICKUP         (1 << 17)
-#define KEYMASK_GPICKUP        (1 << 18)
-#define KEYMASK_DND            (1 << 29)
-#define KEYMASK_IDIVERT        (1 << 20)
-#define KEYMASK_FORCEDIAL      (1 << 21)
-
-/* Localized message "codes" (in octal)
-   Below is en_US (taken from a 7970) */
-
-/*                            "\200\000"        ??? */
-#define OCTAL_REDIAL          "\200\001"     /* Redial */
-#define OCTAL_NEWCALL         "\200\002"     /* New Call */
-#define OCTAL_HOLD            "\200\003"     /* Hold */
-#define OCTAL_TRANSFER        "\200\004"     /* Transfer */
-#define OCTAL_CFWDALL         "\200\005"     /* CFwdALL */
-#define OCTAL_CFWDBUSY        "\200\006"     /* CFwdBusy */
-#define OCTAL_CFWDNOAN        "\200\007"     /* CFwdNoAnswer */
-#define OCTAL_BKSPC           "\200\010"     /* << */
-#define OCTAL_ENDCALL         "\200\011"     /* EndCall */
-#define OCTAL_RESUME          "\200\012"     /* Resume */
-#define OCTAL_ANSWER          "\200\013"     /* Answer */
-#define OCTAL_INFO            "\200\014"     /* Info */
-#define OCTAL_CONFRN          "\200\015"     /* Confrn */
-#define OCTAL_PARK            "\200\016"     /* Park */
-#define OCTAL_JOIN            "\200\017"     /* Join */
-#define OCTAL_MEETME          "\200\020"     /* MeetMe */
-#define OCTAL_PICKUP          "\200\021"     /* PickUp */
-#define OCTAL_GPICKUP         "\200\022"     /* GPickUp */
-#define OCTAL_CUROPTS         "\200\023"     /* Your current options */
-#define OCTAL_OFFHOOK         "\200\024"     /* Off Hook */
-#define OCTAL_ONHOOK          "\200\025"     /* On Hook */
-#define OCTAL_RINGOUT         "\200\026"     /* Ring out */
-#define OCTAL_FROM            "\200\027"     /* From */
-#define OCTAL_CONNECTED       "\200\030"     /* Connected */
-#define OCTAL_BUSY            "\200\031"     /* Busy */
-#define OCTAL_LINEINUSE       "\200\032"     /* Line In Use */
-#define OCTAL_CALLWAITING     "\200\033"     /* Call Waiting */
-#define OCTAL_CALLXFER        "\200\034"     /* Call Transfer */
-#define OCTAL_CALLPARK        "\200\035"     /* Call Park */
-#define OCTAL_CALLPROCEED     "\200\036"     /* Call Proceed */
-#define OCTAL_INUSEREMOTE     "\200\037"     /* In Use Remote */
-#define OCTAL_ENTRNUM         "\200\040"     /* Enter number */
-#define OCTAL_PARKAT          "\200\041"     /* Call park At */
-#define OCTAL_PRIMONLY        "\200\042"     /* Primary Only */
-#define OCTAL_TMPFAIL         "\200\043"     /* Temp Fail */
-#define OCTAL_HAVEVMAIL       "\200\044"     /* You Have VoiceMail */
-#define OCTAL_FWDEDTO         "\200\045"     /* Forwarded to */
-#define OCTAL_CANTCOMPCNF     "\200\046"     /* Can Not Complete Conference */
-#define OCTAL_NOCONFBRDG      "\200\047"     /* No Conference Bridge */
-#define OCTAL_NOPRIMARYCTL    "\200\050"     /* Can Not Hold Primary Control */
-#define OCTAL_INVALCONFPART   "\200\051"     /* Invalid Conference Participant */
-#define OCTAL_INCONFALREADY   "\200\052"     /* In Conference Already */
-#define OCTAL_NOPARTINFO      "\200\053"     /* No Participant Info */
-#define OCTAL_MAXPARTEXCEED   "\200\054"     /* Exceed Maximum Parties */
-#define OCTAL_KEYNOTACTIVE    "\200\055"     /* Key Is Not Active */
-#define OCTAL_ERRNOLIC        "\200\056"     /* Error No License */
-#define OCTAL_ERRDBCFG        "\200\057"     /* Error DBConfig */
-#define OCTAL_ERRDB           "\200\060"     /* Error Database */
-#define OCTAL_ERRPASSLMT      "\200\061"     /* Error Pass Limit */
-#define OCTAL_ERRUNK          "\200\062"     /* Error Unknown */
-#define OCTAL_ERRMISMATCH     "\200\063"     /* Error Mismatch */
-#define OCTAL_CONFERENCE      "\200\064"     /* Conference */
-#define OCTAL_PARKNO          "\200\065"     /* Park Number */
-#define OCTAL_PRIVATE         "\200\066"     /* Private */
-#define OCTAL_INSUFBANDW      "\200\067"     /* Not Enough Bandwidth */
-#define OCTAL_UNKNUM          "\200\070"     /* Unknown Number */
-#define OCTAL_RMLSTC          "\200\071"     /* RmLstC */
-#define OCTAL_VOICEMAIL       "\200\072"     /* Voicemail */
-#define OCTAL_IMMDIV          "\200\073"     /* ImmDiv */
-#define OCTAL_INTRCPT         "\200\074"     /* Intrcpt */
-#define OCTAL_SETWTCH         "\200\075"     /* SetWtch */
-#define OCTAL_TRNSFVM         "\200\076"     /* TrnsfVM */
-#define OCTAL_DND             "\200\077"     /* DND */
-#define OCTAL_DIVALL          "\200\100"     /* DivAll */
-#define OCTAL_CALLBACK        "\200\101"     /* CallBack */
-#define OCTAL_NETCNGREROUT    "\200\102"     /* Network congestion,rerouting */
-#define OCTAL_BARGE           "\200\103"     /* Barge */
-#define OCTAL_BARGEFAIL       "\200\104"     /* Failed to setup Barge */
-#define OCTAL_BARGEEXIST      "\200\105"     /* Another Barge exists */
-#define OCTAL_INCOMPATDEV     "\200\106"     /* Incompatible device type */
-#define OCTAL_PARKNONUM       "\200\107"     /* No Park Number Available */
-#define OCTAL_PARKREVERSION   "\200\110"     /* CallPark Reversion */
-#define OCTAL_SRVNOTACTIVE    "\200\111"     /* Service is not Active */
-#define OCTAL_HITRAFFIC       "\200\112"     /* High Traffic Try Again Later */
-#define OCTAL_QRT             "\200\113"     /* QRT */
-#define OCTAL_MCID            "\200\114"     /* MCID */
-#define OCTAL_DIRTRFR         "\200\115"     /* DirTrfr */
-#define OCTAL_SELECT          "\200\116"     /* Select */
-#define OCTAL_CONFLIST        "\200\117"     /* ConfList */
-#define OCTAL_IDIVERT         "\200\120"     /* iDivert */
-#define OCTAL_CBARGE          "\200\121"     /* cBarge */
-#define OCTAL_CANTCOMPLXFER   "\200\122"     /* Can Not Complete Transfer */
-#define OCTAL_CANTJOINCALLS   "\200\123"     /* Can Not Join Calls */
-#define OCTAL_MCIDSUCCESS     "\200\124"     /* Mcid Successful */
-#define OCTAL_NUMNOTCFG       "\200\125"     /* Number Not Configured */
-#define OCTAL_SECERROR        "\200\126"     /* Security Error */
-#define OCTAL_VIDBANDWNA      "\200\127"     /* Video Bandwidth Unavailable */
-#define OCTAL_VIDMODE         "\200\130"     /* VidMode */
-#define OCTAL_CALLDURTIMEOUT  "\200\131"     /* Max Call Duration Timeout */
-#define OCTAL_HOLDDURTIMEOUT  "\200\132"     /* Max Hold Duration Timeout */
-#define OCTAL_OPICKUP         "\200\133"     /* OPickUp */
-/*                            "\200\134"        ??? */
-/*                            "\200\135"        ??? */
-/*                            "\200\136"        ??? */
-/*                            "\200\137"        ??? */
-/*                            "\200\140"        ??? */
-#define OCTAL_EXTXFERRESTRICT "\200\141"     /* External Transfer Restricted */
-/*                            "\200\142"        ??? */
-/*                            "\200\143"        ??? */
-/*                            "\200\144"        ??? */
-#define OCTAL_MACADD          "\200\145"     /* Mac Address */
-#define OCTAL_HOST            "\200\146"     /* Host Name */
-#define OCTAL_DOMAIN          "\200\147"     /* Domain Name */
-#define OCTAL_IPADD           "\200\150"     /* IP Address */
-#define OCTAL_SUBMASK         "\200\151"     /* Subnet Mask */
-#define OCTAL_TFTP1           "\200\152"     /* TFTP Server 1 */
-#define OCTAL_ROUTER1         "\200\153"     /* Default Router 1 */
-#define OCTAL_ROUTER2         "\200\154"     /* Default Router 2 */
-#define OCTAL_ROUTER3         "\200\155"     /* Default Router 3 */
-#define OCTAL_ROUTER4         "\200\156"     /* Default Router 4 */
-#define OCTAL_ROUTER5         "\200\157"     /* Default Router 5 */
-#define OCTAL_DNS1            "\200\160"     /* DNS Server 1 */
-#define OCTAL_DNS2            "\200\161"     /* DNS Server 2 */
-#define OCTAL_DNS3            "\200\162"     /* DNS Server 3 */
-#define OCTAL_DNS4            "\200\163"     /* DNS Server 4 */
-#define OCTAL_DNS5            "\200\164"     /* DNS Server 5 */
-#define OCTAL_VLANOPID        "\200\165"     /* Operational VLAN Id */
-#define OCTAL_VLANADID        "\200\166"     /* Admin. VLAN Id */
-#define OCTAL_CM1             "\200\167"     /* CallManager 1 */
-#define OCTAL_CM2             "\200\170"     /* CallManager 2 */
-#define OCTAL_CM3             "\200\171"     /* CallManager 3 */
-#define OCTAL_CM4             "\200\172"     /* CallManager 4 */
-#define OCTAL_CM5             "\200\173"     /* CallManager 5 */
-#define OCTAL_URLINFO         "\200\174"     /* Information URL */
-#define OCTAL_URLDIRS         "\200\175"     /* Directories URL */
-#define OCTAL_URLMSGS         "\200\176"     /* Messages URL */
-#define OCTAL_URLSRVS         "\200\177"     /* Services URL */
 
 static struct soft_key_template_definition soft_key_template_default[] = {
-	{ OCTAL_REDIAL, SOFTKEY_REDIAL },
-	{ OCTAL_NEWCALL, SOFTKEY_NEWCALL },
-	{ OCTAL_HOLD, SOFTKEY_HOLD },
-	{ OCTAL_TRANSFER, SOFTKEY_TRNSFER },
-	{ OCTAL_CFWDALL, SOFTKEY_CFWDALL },
-	{ OCTAL_CFWDBUSY, SOFTKEY_CFWDBUSY },
-	{ OCTAL_CFWDNOAN, SOFTKEY_CFWDNOANSWER },
-	{ OCTAL_BKSPC, SOFTKEY_BKSPC },
-	{ OCTAL_ENDCALL, SOFTKEY_ENDCALL },
-	{ OCTAL_RESUME, SOFTKEY_RESUME },
-	{ OCTAL_ANSWER, SOFTKEY_ANSWER },
-	{ OCTAL_INFO, SOFTKEY_INFO },
-	{ OCTAL_CONFRN, SOFTKEY_CONFRN },
-	{ OCTAL_PARK, SOFTKEY_PARK },
-	{ OCTAL_JOIN, SOFTKEY_JOIN },
-	{ OCTAL_MEETME, SOFTKEY_MEETME },
-	{ OCTAL_PICKUP, SOFTKEY_PICKUP },
-	{ OCTAL_GPICKUP, SOFTKEY_GPICKUP },
-	{ OCTAL_DND, SOFTKEY_DND },
-	{ OCTAL_IDIVERT, SOFTKEY_IDIVERT },
-	{ "Dial", SOFTKEY_FORCEDIAL},
+	{ "\200\001", SOFTKEY_REDIAL },
+	{ "\200\002", SOFTKEY_NEWCALL },
+	{ "\200\003", SOFTKEY_HOLD },
+	{ "\200\004", SOFTKEY_TRNSFER },
+	{ "\200\005", SOFTKEY_CFWDALL },
+	{ "\200\006", SOFTKEY_CFWDBUSY },
+	{ "\200\007", SOFTKEY_CFWDNOANSWER },
+	{ "\200\010", SOFTKEY_BKSPC },
+	{ "\200\011", SOFTKEY_ENDCALL },
+	{ "\200\012", SOFTKEY_RESUME },
+	{ "\200\013", SOFTKEY_ANSWER },
+	{ "\200\014", SOFTKEY_INFO },
+	{ "\200\015", SOFTKEY_CONFRN },
+	{ "\200\016", SOFTKEY_PARK },
+	{ "\200\017", SOFTKEY_JOIN },
+	{ "\200\020", SOFTKEY_MEETME },
+	{ "\200\021", SOFTKEY_PICKUP },
+	{ "\200\022", SOFTKEY_GPICKUP },
+	{ "\200\077", SOFTKEY_DND },
+	{ "\200\120", SOFTKEY_IDIVERT },
 };
 
+/* Localized message "codes" (in octal)
+   Below is en_US (taken from a 7970)
+
+   \200\xxx
+       \000: ???
+       \001: Redial
+       \002: New Call
+       \003: Hold
+       \004: Transfer
+       \005: CFwdALL
+       \006: CFwdBusy
+       \007: CFwdNoAnswer
+       \010: <<
+       \011: EndCall
+       \012: Resume
+       \013: Answer
+       \014: Info
+       \015: Confrn
+       \016: Park
+       \017: Join
+       \020: MeetMe
+       \021: PickUp
+       \022: GPickUp
+       \023: Your current options
+       \024: Off Hook
+       \025: On Hook
+       \026: Ring out
+       \027: From
+       \030: Connected
+       \031: Busy
+       \032: Line In Use
+       \033: Call Waiting
+       \034: Call Transfer
+       \035: Call Park
+       \036: Call Proceed
+       \037: In Use Remote
+       \040: Enter number
+       \041: Call park At
+       \042: Primary Only
+       \043: Temp Fail
+       \044: You Have VoiceMail
+       \045: Forwarded to
+       \046: Can Not Complete Conference
+       \047: No Conference Bridge
+       \050: Can Not Hold Primary Control
+       \051: Invalid Conference Participant
+       \052: In Conference Already
+       \053: No Participant Info
+       \054: Exceed Maximum Parties
+       \055: Key Is Not Active
+       \056: Error No License
+       \057: Error DBConfig
+       \060: Error Database
+       \061: Error Pass Limit
+       \062: Error Unknown
+       \063: Error Mismatch
+       \064: Conference
+       \065: Park Number
+       \066: Private
+       \067: Not Enough Bandwidth
+       \070: Unknown Number
+       \071: RmLstC
+       \072: Voicemail
+       \073: ImmDiv
+       \074: Intrcpt
+       \075: SetWtch
+       \076: TrnsfVM
+       \077: DND
+       \100: DivAll
+       \101: CallBack
+       \102: Network congestion,rerouting
+       \103: Barge
+       \104: Failed to setup Barge
+       \105: Another Barge exists
+       \106: Incompatible device type
+       \107: No Park Number Available
+       \110: CallPark Reversion
+       \111: Service is not Active
+       \112: High Traffic Try Again Later
+       \113: QRT
+       \114: MCID
+       \115: DirTrfr
+       \116: Select
+       \117: ConfList
+       \120: iDivert
+       \121: cBarge
+       \122: Can Not Complete Transfer
+       \123: Can Not Join Calls
+       \124: Mcid Successful
+       \125: Number Not Configured
+       \126: Security Error
+       \127: Video Bandwidth Unavailable
+       \130: VidMode
+       \131: Max Call Duration Timeout
+       \132: Max Hold Duration Timeout
+       \133: OPickUp
+       \134: ???
+       \135: ???
+       \136: ???
+       \137: ???
+       \140: ???
+       \141: External Transfer Restricted
+       \142: ???
+       \143: ???
+       \144: ???
+       \145: Mac Address
+       \146: Host Name
+       \147: Domain Name
+       \150: IP Address
+       \151: Subnet Mask
+       \152: TFTP Server 1
+       \153: Default Router 1
+       \154: Default Router 2
+       \155: Default Router 3
+       \156: Default Router 4
+       \157: Default Router 5
+       \160: DNS Server 1
+       \161: DNS Server 2
+       \162: DNS Server 3
+       \163: DNS Server 4
+       \164: DNS Server 5
+       \165: Operational VLAN Id
+       \166: Admin. VLAN Id
+       \167: CallManager 1
+       \170: CallManager 2
+       \171: CallManager 3
+       \172: CallManager 4
+       \173: CallManager 5
+       \174: Information URL
+       \175: Directories URL
+       \176: Messages URL
+       \177: Services URL
+ */
+
 struct soft_key_definitions {
 	const uint8_t mode;
 	const uint8_t *defaults;
@@ -922,10 +878,9 @@ static const uint8_t soft_key_default_onhook[] = {
 	SOFTKEY_NEWCALL,
 	SOFTKEY_CFWDALL,
 	SOFTKEY_CFWDBUSY,
-	SOFTKEY_CFWDNOANSWER,
 	SOFTKEY_DND,
-	SOFTKEY_GPICKUP,
-	/*SOFTKEY_CONFRN,*/
+	/*SOFTKEY_GPICKUP,
+	SOFTKEY_CONFRN,*/
 };
 
 static const uint8_t soft_key_default_connected[] = {
@@ -935,7 +890,6 @@ static const uint8_t soft_key_default_connected[] = {
 	SOFTKEY_PARK,
 	SOFTKEY_CFWDALL,
 	SOFTKEY_CFWDBUSY,
-	SOFTKEY_CFWDNOANSWER,
 };
 
 static const uint8_t soft_key_default_onhold[] = {
@@ -954,11 +908,9 @@ static const uint8_t soft_key_default_ringin[] = {
 static const uint8_t soft_key_default_offhook[] = {
 	SOFTKEY_REDIAL,
 	SOFTKEY_ENDCALL,
-	SOFTKEY_TRNSFER,
 	SOFTKEY_CFWDALL,
 	SOFTKEY_CFWDBUSY,
-	SOFTKEY_CFWDNOANSWER,
-	SOFTKEY_GPICKUP,
+	/*SOFTKEY_GPICKUP,*/
 };
 
 static const uint8_t soft_key_default_connwithtrans[] = {
@@ -968,14 +920,11 @@ static const uint8_t soft_key_default_connwithtrans[] = {
 	SOFTKEY_PARK,
 	SOFTKEY_CFWDALL,
 	SOFTKEY_CFWDBUSY,
-	SOFTKEY_CFWDNOANSWER,
 };
 
 static const uint8_t soft_key_default_dadfd[] = {
 	SOFTKEY_BKSPC,
 	SOFTKEY_ENDCALL,
-	SOFTKEY_TRNSFER,
-	SOFTKEY_FORCEDIAL,
 };
 
 static const uint8_t soft_key_default_connwithconf[] = {
@@ -987,12 +936,6 @@ static const uint8_t soft_key_default_ringout[] = {
 	SOFTKEY_ENDCALL,
 };
 
-static const uint8_t soft_key_default_ringoutwithtransfer[] = {
-	SOFTKEY_NONE,
-	SOFTKEY_ENDCALL,
-	SOFTKEY_TRNSFER,
-};
-
 static const uint8_t soft_key_default_offhookwithfeat[] = {
 	SOFTKEY_REDIAL,
 	SOFTKEY_ENDCALL,
@@ -1025,7 +968,6 @@ static const struct soft_key_definitions soft_key_default_definitions[] = {
 	{KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
 	{KEYDEF_CONNWITHCONF, soft_key_default_connwithconf, sizeof(soft_key_default_connwithconf) / sizeof(uint8_t)},
 	{KEYDEF_RINGOUT, soft_key_default_ringout, sizeof(soft_key_default_ringout) / sizeof(uint8_t)},
-	{KEYDEF_RINGOUTWITHTRANS, soft_key_default_ringoutwithtransfer, sizeof(soft_key_default_ringoutwithtransfer) / sizeof(uint8_t)},
 	{KEYDEF_OFFHOOKWITHFEAT, soft_key_default_offhookwithfeat, sizeof(soft_key_default_offhookwithfeat) / sizeof(uint8_t)},
 	{KEYDEF_UNKNOWN, soft_key_default_unknown, sizeof(soft_key_default_unknown) / sizeof(uint8_t)},
 	{KEYDEF_SLAHOLD, soft_key_default_SLAhold, sizeof(soft_key_default_SLAhold) / sizeof(uint8_t)},
@@ -1103,57 +1045,6 @@ struct dialed_number_message {
 	uint32_t callReference;
 };
 
-#define MAX_SERVICEURL 256
-#define SERVICEURL_STAT_MESSAGE 0x012F
-struct serviceurl_stat_message {
-	uint32_t instance;
-	char url[MAX_SERVICEURL];
-	char displayName[40];
-};
-
-#define MAXCALLINFOSTR 256
-#define MAXDISPLAYNOTIFYSTR 32
-
-#define DISPLAY_PRINOTIFY_MESSAGE 0x0120
-struct display_prinotify_message {
-	uint32_t timeout;
-	uint32_t priority;
-	char text[MAXDISPLAYNOTIFYSTR];
-};
-
-#define CLEAR_PRINOTIFY_MESSAGE 0x0121
-struct clear_prinotify_message {
-	uint32_t priority;
-};
-
-#define CALL_INFO_MESSAGE_VARIABLE 0x014A
-struct call_info_message_variable {
-	uint32_t instance;
-	uint32_t callreference;
-	uint32_t calldirection;
-	uint32_t unknown1;
-	uint32_t unknown2;
-	uint32_t unknown3;
-	uint32_t unknown4;
-	uint32_t unknown5;
-	char calldetails[MAXCALLINFOSTR];
-};
-
-#define DISPLAY_PRINOTIFY_MESSAGE_VARIABLE 0x0144
-struct display_prinotify_message_variable {
-	uint32_t timeout;
-	uint32_t priority;
-	char text[MAXDISPLAYNOTIFYSTR];
-};
-
-#define DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE 0x0145
-struct display_prompt_status_message_variable {
-	uint32_t unknown;
-	uint32_t lineInstance;
-	uint32_t callReference;
-	char promptMessage[MAXCALLINFOSTR];
-};
-
 union skinny_data {
 	struct alarm_message alarm;
 	struct speed_dial_stat_req_message speeddialreq;
@@ -1202,19 +1093,13 @@ union skinny_data {
 	struct enbloc_call_message enbloccallmessage;
 	struct forward_stat_message forwardstat;
 	struct bksp_req_message bkspmessage;
-	struct call_info_message_variable callinfomessagevariable;
-	struct display_prompt_status_message_variable displaypromptstatusvar;
-	struct serviceurl_stat_message serviceurlmessage;
-	struct clear_prinotify_message clearprinotify;
-	struct display_prinotify_message displayprinotify;
-	struct display_prinotify_message_variable displayprinotifyvar;
 };
 
 /* packet composition */
 struct skinny_req {
-	uint32_t len;
-	uint32_t res;
-	uint32_t e;
+	int len;
+	int res;
+	int e;
 	union skinny_data data;
 };
 
@@ -1377,11 +1262,8 @@ static int matchdigittimeout = 3000;
 #define SUBSTATE_PROGRESS 12
 #define SUBSTATE_DIALING 101
 
-#define DIALTYPE_NORMAL      1<<0
-#define DIALTYPE_CFWD        1<<1
-#define DIALTYPE_XFER        1<<2
-
 struct skinny_subchannel {
+	ast_mutex_t lock;
 	struct ast_channel *owner;
 	struct ast_rtp_instance *rtp;
 	struct ast_rtp_instance *vrtp;
@@ -1401,11 +1283,6 @@ struct skinny_subchannel {
 	int aa_beep;
 	int aa_mute;
 	int dialer_sched;
-	int cfwd_sched;
-	int dialType;
-	int getforward;
-	char *origtonum;
-	char *origtoname;
 
 	AST_LIST_ENTRY(skinny_subchannel) list;
 	struct skinny_subchannel *related;
@@ -1420,14 +1297,14 @@ struct skinny_subchannel {
 	char exten[AST_MAX_EXTENSION];			\
 	char context[AST_MAX_CONTEXT];			\
 	char language[MAX_LANGUAGE];			\
-	char cid_num[AST_MAX_EXTENSION];		\
-	char cid_name[AST_MAX_EXTENSION];		\
-	char lastcallerid[AST_MAX_EXTENSION];		\
+	char cid_num[AST_MAX_EXTENSION]; 		\
+	char cid_name[AST_MAX_EXTENSION]; 		\
+	char lastcallerid[AST_MAX_EXTENSION]; 		\
 	int cfwdtype;					\
 	char call_forward_all[AST_MAX_EXTENSION];	\
 	char call_forward_busy[AST_MAX_EXTENSION];	\
 	char call_forward_noanswer[AST_MAX_EXTENSION];	\
-	char mailbox[AST_MAX_MAILBOX_UNIQUEID];		\
+	char mailbox[AST_MAX_EXTENSION];		\
 	char vmexten[AST_MAX_EXTENSION];		\
 	char regexten[AST_MAX_EXTENSION];		\
 	char regcontext[AST_MAX_CONTEXT];		\
@@ -1439,19 +1316,19 @@ struct skinny_subchannel {
 	char dialoutcontext[AST_MAX_CONTEXT];		\
 	ast_group_t callgroup;				\
 	ast_group_t pickupgroup;			\
-	struct ast_namedgroups *named_callgroups;	\
-	struct ast_namedgroups *named_pickupgroups;	\
 	int callwaiting;				\
 	int transfer;					\
 	int threewaycalling;				\
 	int mwiblink;					\
 	int cancallforward;				\
-	int callfwdtimeout;				\
+	int getforward;					\
 	int dnd;					\
 	int hidecallerid;				\
 	int amaflags;					\
 	int instance;					\
 	int group;					\
+	struct ast_codec_pref confprefs;		\
+	struct ast_codec_pref prefs;			\
 	int nonCodecCapability;				\
 	int immediate;					\
 	int nat;					\
@@ -1462,7 +1339,7 @@ struct skinny_line {
 	SKINNY_LINE_OPTIONS
 	ast_mutex_t lock;
 	struct skinny_container *container;
-	struct stasis_subscription *mwi_event_sub; /* Event based MWI */
+	struct ast_event_sub *mwi_event_sub; /* Event based MWI */
 	struct skinny_subchannel *activesub;
 	AST_LIST_HEAD(, skinny_subchannel) sub;
 	AST_LIST_HEAD(, skinny_subline) sublines;
@@ -1478,16 +1355,16 @@ struct skinny_line {
 static struct skinny_line_options{
 	SKINNY_LINE_OPTIONS
 } default_line_struct = {
-	.callwaiting = 1,
+ 	.callwaiting = 1,
 	.transfer = 1,
-	.mwiblink = 0,
-	.dnd = 0,
-	.hidecallerid = 0,
+ 	.mwiblink = 0,
+ 	.dnd = 0,
+ 	.hidecallerid = 0,
 	.amaflags = 0,
-	.instance = 0,
-	.directmedia = 0,
-	.nat = 0,
-	.callfwdtimeout = 20000,
+ 	.instance = 0,
+ 	.directmedia = 0,
+ 	.nat = 0,
+	.getforward = 0,
 	.prune = 0,
 };
 static struct skinny_line_options *default_line = &default_line_struct;
@@ -1529,14 +1406,6 @@ struct skinny_speeddial {
 	struct skinny_device *parent;
 };
 
-struct skinny_serviceurl {
-	int instance;
-	char url[MAX_SERVICEURL];
-	char displayName[40];
-	AST_LIST_ENTRY(skinny_serviceurl) list;
-	struct skinny_device *device;
-};
-
 #define SKINNY_DEVICECONTAINER 1
 #define SKINNY_LINECONTAINER 2
 #define SKINNY_SUBLINECONTAINER 3
@@ -1564,6 +1433,7 @@ struct skinny_addon {
 	int hookstate;					\
 	int lastlineinstance;					\
 	int lastcallreference;					\
+	struct ast_codec_pref confprefs;			\
 	int earlyrtp;						\
 	int transfer;						\
 	int callwaiting;					\
@@ -1583,10 +1453,8 @@ struct skinny_device {
 	struct skinny_line *activeline;
 	struct ast_format_cap *cap;
 	struct ast_format_cap *confcap;
-	struct ast_endpoint *endpoint;
 	AST_LIST_HEAD(, skinny_line) lines;
 	AST_LIST_HEAD(, skinny_speeddial) speeddials;
-	AST_LIST_HEAD(, skinny_serviceurl) serviceurls;
 	AST_LIST_HEAD(, skinny_addon) addons;
 	AST_LIST_ENTRY(skinny_device) list;
 };
@@ -1595,34 +1463,30 @@ static struct skinny_device_options {
 	SKINNY_DEVICE_OPTIONS
 } default_device_struct = {
 	.transfer = 1,
-	.earlyrtp = 1,
-	.callwaiting = 1,
-	.mwiblink = 0,
-	.dnd = 0,
+ 	.earlyrtp = 1,
+ 	.callwaiting = 1,
+ 	.mwiblink = 0,
+ 	.dnd = 0,
 	.prune = 0,
 	.hookstate = SKINNY_ONHOOK,
 };
 static struct skinny_device_options *default_device = &default_device_struct;
-
+	
 static AST_LIST_HEAD_STATIC(devices, skinny_device);
 
 struct skinnysession {
 	pthread_t t;
 	ast_mutex_t lock;
-	struct timeval start;
+	time_t start;
 	struct sockaddr_in sin;
 	int fd;
+	char inbuf[SKINNY_MAX_PACKET];
 	char outbuf[SKINNY_MAX_PACKET];
 	struct skinny_device *device;
 	AST_LIST_ENTRY(skinnysession) list;
-	int lockstate; /* Only for use in the skinny_session thread */
-	int auth_timeout_sched;
-	int keepalive_timeout_sched;
-	struct timeval last_keepalive;
-	int keepalive_count;
 };
 
-static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause);
+static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
 static AST_LIST_HEAD_STATIC(sessions, skinnysession);
 
 static int skinny_devicestate(const char *data);
@@ -1635,18 +1499,14 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg);
+static void mwi_event_cb(const struct ast_event *event, void *userdata);
 static int skinny_dialer_cb(const void *data);
 static int skinny_reload(void);
 
-static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan);
 static void setsubstate(struct skinny_subchannel *sub, int state);
 static void dumpsub(struct skinny_subchannel *sub, int forcehangup);
 static void activatesub(struct skinny_subchannel *sub, int state);
 static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION]);
-static int skinny_nokeepalive_cb(const void *data);
-
-static void transmit_definetimedate(struct skinny_device *d);
 
 static struct ast_channel_tech skinny_tech = {
 	.type = "Skinny",
@@ -1663,9 +1523,11 @@ static struct ast_channel_tech skinny_tech = {
 	.fixup = skinny_fixup,
 	.send_digit_begin = skinny_senddigit_begin,
 	.send_digit_end = skinny_senddigit_end,
+	.bridge = ast_rtp_instance_bridge, 
 };
 
 static int skinny_extensionstate_cb(char *context, char *id, struct ast_state_cb_info *info, void *data);
+static int skinny_transfer(struct skinny_subchannel *sub);
 
 static struct skinny_line *skinny_line_alloc(void)
 {
@@ -1674,11 +1536,11 @@ static struct skinny_line *skinny_line_alloc(void)
 		return NULL;
 	}
 
-	l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	l->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	l->cap = ast_format_cap_alloc_nolock();
+	l->confcap = ast_format_cap_alloc_nolock();
 	if (!l->cap || !l->confcap) {
-		ao2_cleanup(l->cap);
-		ao2_cleanup(l->confcap);
+		l->cap = ast_format_cap_destroy(l->cap);
+		l->confcap = ast_format_cap_destroy(l->confcap);
 		ast_free(l);
 		return NULL;
 	}
@@ -1686,40 +1548,33 @@ static struct skinny_line *skinny_line_alloc(void)
 }
 static struct skinny_line *skinny_line_destroy(struct skinny_line *l)
 {
-	ao2_ref(l->cap, -1);
-	ao2_ref(l->confcap, -1);
-	l->named_callgroups = ast_unref_namedgroups(l->named_callgroups);
-	l->named_pickupgroups = ast_unref_namedgroups(l->named_pickupgroups);
+	l->cap = ast_format_cap_destroy(l->cap);
+	l->confcap = ast_format_cap_destroy(l->confcap);
 	ast_free(l->container);
 	ast_free(l);
 	return NULL;
 }
-static struct skinny_device *skinny_device_alloc(const char *dname)
+static struct skinny_device *skinny_device_alloc(void)
 {
 	struct skinny_device *d;
 	if (!(d = ast_calloc(1, sizeof(*d)))) {
 		return NULL;
 	}
 
-	d->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	d->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	d->endpoint = ast_endpoint_create("Skinny", dname);
-	if (!d->cap || !d->confcap || !d->endpoint) {
-		ao2_cleanup(d->cap);
-		ao2_cleanup(d->confcap);
+	d->cap = ast_format_cap_alloc_nolock();
+	d->confcap = ast_format_cap_alloc_nolock();
+	if (!d->cap || !d->confcap) {
+		d->cap = ast_format_cap_destroy(d->cap);
+		d->confcap = ast_format_cap_destroy(d->confcap);
 		ast_free(d);
 		return NULL;
 	}
-
-	ast_copy_string(d->name, dname, sizeof(d->name));
-
 	return d;
 }
 static struct skinny_device *skinny_device_destroy(struct skinny_device *d)
 {
-	ao2_ref(d->cap, -1);
-	ao2_ref(d->confcap, -1);
-	ast_endpoint_shutdown(d->endpoint);
+	d->cap = ast_format_cap_destroy(d->cap);
+	d->confcap = ast_format_cap_destroy(d->confcap);
 	ast_free(d);
 	return NULL;
 }
@@ -1745,7 +1600,7 @@ static void *get_button_template(struct skinnysession *s, struct button_definiti
 				(btn++)->buttonDefinition = BT_NONE;
 			for (i = 0; i < 13; i++)
 				(btn++)->buttonDefinition = BT_SPEEDDIAL;
-
+			
 			break;
 		case SKINNY_DEVICE_12SPPLUS:
 		case SKINNY_DEVICE_12SP:
@@ -1972,7 +1827,7 @@ static struct skinny_subline *find_subline_by_callid(struct skinny_device *d, in
 {
 	struct skinny_subline *subline;
 	struct skinny_line *l;
-
+	
 	AST_LIST_TRAVERSE(&d->lines, l, list){
 		AST_LIST_TRAVERSE(&l->sublines, subline, list){
 			if (subline->callid == callid) {
@@ -2001,20 +1856,6 @@ static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
 	return list;
 }
 
-static void skinny_locksub(struct skinny_subchannel *sub)
-{
-	if (sub && sub->owner) {
-		ast_channel_lock(sub->owner);
-	}
-}
-
-static void skinny_unlocksub(struct skinny_subchannel *sub)
-{
-	if (sub && sub->owner) {
-		ast_channel_unlock(sub->owner);
-	}
-}
-
 static int skinny_sched_del(int sched_id, struct skinny_subchannel *sub)
 {
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Deleting SCHED %d\n",
@@ -2098,49 +1939,47 @@ static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device
 	return sd;
 }
 
-static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec)
+static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec, struct ast_format *result)
 {
 	switch (skinnycodec) {
 	case SKINNY_CODEC_ALAW:
-		return ast_format_alaw;
+		return ast_format_set(result, AST_FORMAT_ALAW, 0);
 	case SKINNY_CODEC_ULAW:
-		return ast_format_ulaw;
-	case SKINNY_CODEC_G722:
-		return ast_format_g722;
+		return ast_format_set(result, AST_FORMAT_ULAW, 0);
 	case SKINNY_CODEC_G723_1:
-		return ast_format_g723;
+		return ast_format_set(result, AST_FORMAT_G723_1, 0);
 	case SKINNY_CODEC_G729A:
-		return ast_format_g729;
+		return ast_format_set(result, AST_FORMAT_G729A, 0);
 	case SKINNY_CODEC_G726_32:
-		return ast_format_g726; /* XXX Is this right? */
+		return ast_format_set(result, AST_FORMAT_G726_AAL2, 0); /* XXX Is this right? */
 	case SKINNY_CODEC_H261:
-		return ast_format_h261;
+		return ast_format_set(result, AST_FORMAT_H261, 0);
 	case SKINNY_CODEC_H263:
-		return ast_format_h263;
+		return ast_format_set(result, AST_FORMAT_H263 ,0);
 	default:
-		return ast_format_none;
+		ast_format_clear(result);
+		return result;
 	}
 }
 
 static int codec_ast2skinny(const struct ast_format *astcodec)
 {
-	if (ast_format_cmp(astcodec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	switch (astcodec->id) {
+	case AST_FORMAT_ALAW:
 		return SKINNY_CODEC_ALAW;
-	} else if (ast_format_cmp(astcodec, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ULAW:
 		return SKINNY_CODEC_ULAW;
-	} else if (ast_format_cmp(astcodec, ast_format_g722) == AST_FORMAT_CMP_EQUAL) {
-		return SKINNY_CODEC_G722;
-	} else if (ast_format_cmp(astcodec, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G723_1:
 		return SKINNY_CODEC_G723_1;
-	} else if (ast_format_cmp(astcodec, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G729A:
 		return SKINNY_CODEC_G729A;
-	} else if (ast_format_cmp(astcodec, ast_format_g726) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_G726_AAL2: /* XXX Is this right? */
 		return SKINNY_CODEC_G726_32;
-	} else if (ast_format_cmp(astcodec, ast_format_h261) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_H261:
 		return SKINNY_CODEC_H261;
-	} else if (ast_format_cmp(astcodec, ast_format_h263) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_H263:
 		return SKINNY_CODEC_H263;
-	} else {
+	default:
 		return 0;
 	}
 }
@@ -2185,21 +2024,20 @@ static void cleanup_stale_contexts(char *new, char *old)
 	char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
 
 	while ((oldcontext = strsep(&old, "&"))) {
-		stalecontext = '\0';
+		stalecontext = NULL;
 		ast_copy_string(newlist, new, sizeof(newlist));
 		stringp = newlist;
 		while ((newcontext = strsep(&stringp, "&"))) {
 			if (strcmp(newcontext, oldcontext) == 0) {
 				/* This is not the context you're looking for */
-				stalecontext = '\0';
+				stalecontext = NULL;
 				break;
 			} else if (strcmp(newcontext, oldcontext)) {
 				stalecontext = oldcontext;
 			}
-
+			
 		}
-		if (stalecontext)
-			ast_context_destroy(ast_context_find(stalecontext), "Skinny");
+		ast_context_destroy_by_name(stalecontext, "Skinny");
 	}
 }
 
@@ -2261,27 +2099,13 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
 	struct sockaddr_in sin;
 	socklen_t slen;
 	int instance;
-	int res = -1;
-
-	if (s->auth_timeout_sched && ast_sched_del(sched, s->auth_timeout_sched)) {
-		return 0;
-	}
-	s->auth_timeout_sched = 0;
 
 	AST_LIST_LOCK(&devices);
 	AST_LIST_TRAVERSE(&devices, d, list){
 		struct ast_sockaddr addr;
 		ast_sockaddr_from_sin(&addr, &s->sin);
-		if (!strcasecmp(req->data.reg.name, d->id)
+		if (!d->session && !strcasecmp(req->data.reg.name, d->id)
 				&& ast_apply_ha(d->ha, &addr)) {
-			RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-			if (d->session) {
-				ast_log(LOG_WARNING, "Device already registered.\n");
-				transmit_definetimedate(d);
-				res = 0;
-				break;
-			}
 			s->device = d;
 			d->type = letohl(req->data.reg.type);
 			d->protocolversion = letohl(req->data.reg.protocolVersion);
@@ -2305,34 +2129,64 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
 				instance++;
 			}
 			AST_LIST_TRAVERSE(&d->lines, l, list) {
-				ast_format_cap_get_compatible(l->confcap, d->cap, l->cap);
-				/* l->capability = d->capability; */
+				ast_format_cap_joint_copy(l->confcap, d->cap, l->cap);
+				l->prefs = l->confprefs;
+				if (!l->prefs.order[0]) {
+					l->prefs = d->confprefs;
+				}
+				/* l->capability = d->capability;
+				l->prefs = d->prefs; */
 				l->instance = instance;
 				l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
-				set_callforwards(l, NULL, SKINNY_CFWD_ALL|SKINNY_CFWD_BUSY|SKINNY_CFWD_NOANSWER);
+				set_callforwards(l, NULL, 0);
+				manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Registered\r\n", l->name, d->name);
 				register_exten(l);
 				/* initialize MWI on line and device */
-				mwi_event_cb(l, NULL, NULL);
+				mwi_event_cb(0, l);
 				AST_LIST_TRAVERSE(&l->sublines, subline, list) {
 					ast_extension_state_add(subline->context, subline->exten, skinny_extensionstate_cb, subline->container);
 				}
 				ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 				--instance;
 			}
-			ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_ONLINE);
-			blob = ast_json_pack("{s: s}", "peer_status", "Registered");
-			ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
-			res = 1;
 			break;
 		}
 	}
 	AST_LIST_UNLOCK(&devices);
-	return res;
+	if (!d) {
+		return 0;
+	}
+	return 1;
 }
 
-static void end_session(struct skinnysession *s)
+static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
 {
-	pthread_cancel(s->t);
+	struct skinny_device *d;
+	struct skinny_line *l;
+	struct skinny_speeddial *sd;
+
+	d = s->device;
+
+	if (d) {
+		d->session = NULL;
+
+		AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
+			if (sd->stateid > -1)
+				ast_extension_state_del(sd->stateid, NULL);
+		}
+		AST_LIST_TRAVERSE(&d->lines, l, list) {
+			if (l->device == d) {
+				ast_format_cap_remove_all(l->cap);
+				ast_parse_allow_disallow(&l->prefs, l->cap, "all", 0);
+				l->instance = 0;
+				manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
+				unregister_exten(l);
+				ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
+			}
+		}
+	}
+
+	return -1; /* main loop will destroy the session */
 }
 
 #ifdef AST_DEVMODE
@@ -2374,6 +2228,7 @@ static char *callstate2str(int ind)
 static int transmit_response_bysession(struct skinnysession *s, struct skinny_req *req)
 {
 	int res = 0;
+	unsigned long len;
 
 	if (!s) {
 		ast_log(LOG_WARNING, "Asked to transmit to a non-existent session!\n");
@@ -2382,8 +2237,14 @@ static int transmit_response_bysession(struct skinnysession *s, struct skinny_re
 
 	ast_mutex_lock(&s->lock);
 
-	if ((letohl(req->len) > SKINNY_MAX_PACKET) || (letohl(req->len) < 0)) {
-		ast_log(LOG_WARNING, "transmit_response: the length of the request (%u) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET);
+	/* Don't optimize out assigning letohl() to len. It is necessary to guarantee that
+	 * the comparison will always catch invalid values.
+         * letohl() may or may not return a signed value depending upon which definition
+	 * is used.
+	 */
+	len = letohl(req->len);
+	if (SKINNY_MAX_PACKET < len) {
+		ast_log(LOG_WARNING, "transmit_response: the length of the request (%d) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET);
 		ast_mutex_unlock(&s->lock);
 		return -1;
 	}
@@ -2395,10 +2256,10 @@ static int transmit_response_bysession(struct skinnysession *s, struct skinny_re
 	res = write(s->fd, s->outbuf, letohl(req->len)+8);
 
 	if (res != letohl(req->len)+8) {
-		ast_log(LOG_WARNING, "Transmit: write only sent %d out of %u bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
+		ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
 		if (res == -1) {
 			ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
-			end_session(s);
+			skinny_unregister(NULL, s);
 		}
 
 	}
@@ -2455,8 +2316,7 @@ static void transmit_microphone_mode(struct skinny_device *d, int mode)
 }
 
 //static void transmit_callinfo(struct skinny_subchannel *sub)
-static void transmit_callinfo(struct skinny_device *d, int instance, int callid,
-	char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
+static void transmit_callinfo(struct skinny_device *d, int instance, int callid, char *fromname, char *fromnum, char *toname, char *tonum, int calldirection)
 {
 	struct skinny_req *req;
 
@@ -2467,82 +2327,12 @@ static void transmit_callinfo(struct skinny_device *d, int instance, int callid,
 	ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
 	ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
 	ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
-	if (origtoname) {
-		ast_copy_string(req->data.callinfo.originalCalledPartyName, origtoname, sizeof(req->data.callinfo.originalCalledPartyName));
-	}
-	if (origtonum) {
-		ast_copy_string(req->data.callinfo.originalCalledParty, origtonum, sizeof(req->data.callinfo.originalCalledParty));
-	}
-
 	req->data.callinfo.instance = htolel(instance);
 	req->data.callinfo.reference = htolel(callid);
 	req->data.callinfo.type = htolel(calldirection);
 
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_INFO_MESSAGE to %s, to %s(%s) from %s(%s), origto %s(%s) (dir=%d) on %s(%d)\n",
-		d->name, toname, tonum, fromname, fromnum, origtoname, origtonum, calldirection, d->name, instance);
-	transmit_response(d, req);
-}
-
-static void transmit_callinfo_variable(struct skinny_device *d, int instance, int callreference,
-	char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
-{
-	struct skinny_req *req;
-	char *strptr;
-	char *thestrings[13];
-	int i;
-	int callinfostrleft = MAXCALLINFOSTR;
-
-	if (!(req = req_alloc(sizeof(struct call_info_message_variable), CALL_INFO_MESSAGE_VARIABLE)))
-		return;
-
-	req->data.callinfomessagevariable.instance = htolel(instance);
-	req->data.callinfomessagevariable.callreference = htolel(callreference);
-	req->data.callinfomessagevariable.calldirection = htolel(calldirection);
-
-	req->data.callinfomessagevariable.unknown1 = htolel(0x00);
-	req->data.callinfomessagevariable.unknown2 = htolel(0x00);
-	req->data.callinfomessagevariable.unknown3 = htolel(0x00);
-	req->data.callinfomessagevariable.unknown4 = htolel(0x00);
-	req->data.callinfomessagevariable.unknown5 = htolel(0x00);
-
-	thestrings[0] = fromnum;
-	thestrings[1] = "";                     /* Appears to be origfrom */
-	if (calldirection == SKINNY_OUTGOING) {
-		thestrings[2] = tonum;
-		thestrings[3] = origtonum;
-	} else {
-		thestrings[2] = "";
-		thestrings[3] = "";
-	}
-	thestrings[4] = "";
-	thestrings[5] = "";
-	thestrings[6] = "";
-	thestrings[7] = "";
-
-	thestrings[8] = "";
-	thestrings[9] = fromname;
-	thestrings[10] = toname;
-	thestrings[11] = origtoname;
-	thestrings[12] = "";
-
-	strptr = req->data.callinfomessagevariable.calldetails;
-
-	for(i = 0; i < 13; i++) {
-		if (thestrings[i]) {
-			ast_copy_string(strptr, thestrings[i], callinfostrleft);
-			strptr += strlen(thestrings[i]) + 1;
-			callinfostrleft -= strlen(thestrings[i]) + 1;
-		} else {
-			ast_copy_string(strptr, "", callinfostrleft);
-			strptr++;
-			callinfostrleft--;
-		}
-	}
-
-	req->len = req->len - (callinfostrleft & ~0x3);
-
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_INFO_MESSAGE_VARIABLE to %s, to %s(%s) from %s(%s), origto %s(%s) (dir=%d) on %s(%d)\n",
-		d->name, toname, tonum, fromname, fromnum, origtoname, origtonum, calldirection, d->name, instance);
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_INFO_MESSAGE to %s, to %s(%s) from %s(%s) (dir=%d) on %s(%d)\n",
+		d->name, toname, tonum, fromname, fromnum, calldirection, d->name, instance);
 	transmit_response(d, req);
 }
 
@@ -2551,7 +2341,6 @@ static void send_callinfo(struct skinny_subchannel *sub)
 	struct ast_channel *ast;
 	struct skinny_device *d;
 	struct skinny_line *l;
-	struct ast_party_id connected_id;
 	char *fromname;
 	char *fromnum;
 	char *toname;
@@ -2560,37 +2349,26 @@ static void send_callinfo(struct skinny_subchannel *sub)
 	if (!sub || !sub->owner || !sub->line || !sub->line->device) {
 		return;
 	}
-
+	
 	ast = sub->owner;
 	l = sub->line;
 	d = l->device;
-	connected_id = ast_channel_connected_effective_id(ast);
-
+	
 	if (sub->calldirection == SKINNY_INCOMING) {
-		if ((ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-			fromname = S_COR(connected_id.name.valid, connected_id.name.str, "");
-			fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "");
-		} else {
-			fromname = "";
-			fromnum = "";
-		}
+		fromname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
+		fromnum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, "");
 		toname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
 		tonum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
 	} else if (sub->calldirection == SKINNY_OUTGOING) {
 		fromname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
 		fromnum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
-		toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
+		toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, l->lastnumberdialed);
 		tonum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, l->lastnumberdialed);
 	} else {
 		ast_verb(1, "Error sending Callinfo to %s(%d) - No call direction in sub\n", d->name, l->instance);
 		return;
 	}
-
-	if (d->protocolversion < 17) {
-		transmit_callinfo(d, l->instance, sub->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
-	} else {
-		transmit_callinfo_variable(d, l->instance, sub->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
-	}
+	transmit_callinfo(d, l->instance, sub->callid, fromname, fromnum, toname, tonum, sub->calldirection);
 }
 
 static void push_callinfo(struct skinny_subline *subline, struct skinny_subchannel *sub)
@@ -2598,7 +2376,6 @@ static void push_callinfo(struct skinny_subline *subline, struct skinny_subchann
 	struct ast_channel *ast;
 	struct skinny_device *d;
 	struct skinny_line *l;
-	struct ast_party_id connected_id;
 	char *fromname;
 	char *fromnum;
 	char *toname;
@@ -2607,64 +2384,49 @@ static void push_callinfo(struct skinny_subline *subline, struct skinny_subchann
 	if (!sub || !sub->owner || !sub->line || !sub->line->device) {
 		return;
 	}
-
+	
 	ast = sub->owner;
 	l = sub->line;
 	d = l->device;
-	connected_id = ast_channel_connected_effective_id(ast);
-
+	
 	if (sub->calldirection == SKINNY_INCOMING) {
-		if((ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-			fromname = S_COR(connected_id.name.valid, connected_id.name.str, "");
-			fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "");
-		} else {
-			fromname = "";
-			fromnum = "";
-		}
+		fromname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
+		fromnum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, "");
 		toname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
 		tonum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
 	} else if (sub->calldirection == SKINNY_OUTGOING) {
 		fromname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
 		fromnum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
-		toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
+		toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, l->lastnumberdialed);
 		tonum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, l->lastnumberdialed);
 	} else {
 		ast_verb(1, "Error sending Callinfo to %s(%d) - No call direction in sub\n", d->name, l->instance);
 		return;
 	}
-
-	if (d->protocolversion < 17) {
-		transmit_callinfo(subline->line->device, subline->line->instance, subline->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
-	} else {
-		transmit_callinfo_variable(subline->line->device, subline->line->instance, subline->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
-	}
+	transmit_callinfo(subline->line->device, subline->line->instance, subline->callid, fromname, fromnum, toname, tonum, sub->calldirection);
 }
 
 static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *sub)
 {
 	struct skinny_req *req;
 	struct skinny_line *l = sub->line;
-	struct ast_format *tmpfmt;
-	unsigned int framing;
+	struct ast_format_list fmt;
+	struct ast_format tmpfmt;
 
 	if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE)))
 		return;
-
-	tmpfmt = ast_format_cap_get_format(l->cap, 0);
-	framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
+	ast_best_codec(l->cap, &tmpfmt);
+	fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt);
 
 	req->data.openreceivechannel.conferenceId = htolel(sub->callid);
 	req->data.openreceivechannel.partyId = htolel(sub->callid);
-	req->data.openreceivechannel.packets = htolel(framing);
-	req->data.openreceivechannel.capability = htolel(codec_ast2skinny(tmpfmt));
+	req->data.openreceivechannel.packets = htolel(fmt.cur_ms);
+	req->data.openreceivechannel.capability = htolel(codec_ast2skinny(&fmt.format));
 	req->data.openreceivechannel.echo = htolel(0);
 	req->data.openreceivechannel.bitrate = htolel(0);
 
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting OPEN_RECEIVE_CHANNEL_MESSAGE to %s, confid %u, partyid %u, ms %u, fmt %d, echo %d, brate %d\n",
-		d->name, sub->callid, sub->callid, framing, codec_ast2skinny(tmpfmt), 0, 0);
-
-	ao2_ref(tmpfmt, -1);
-
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting OPEN_RECEIVE_CHANNEL_MESSAGE to %s, confid %u, partyid %u, ms %d, fmt %d, echo %d, brate %d\n",
+		d->name, sub->callid, sub->callid, fmt.cur_ms, codec_ast2skinny(&fmt.format), 0, 0);
 	transmit_response(d, req);
 }
 
@@ -2695,44 +2457,20 @@ static void transmit_stop_tone(struct skinny_device *d, int instance, int refere
 	transmit_response(d, req);
 }
 
-static int keyset_translatebitmask(int keyset, int intmask)
-{
-	int extmask = 0;
-	int x, y;
-	const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
-
-	for(x = 0; x < ARRAY_LEN(soft_key_default_definitions); x++) {
-		if (softkeymode[x].mode == keyset) {
-			const uint8_t *defaults = softkeymode[x].defaults;
-
-			for (y = 0; y < softkeymode[x].count; y++) {
-				if (intmask & (1 << (defaults[y]))) {
-					extmask |= (1 << ((y)));
-				}
-			}
-			break;
-		}
-	}
-
-	return extmask;
-}
-
-static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey, int mask)
+static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey)
 {
 	struct skinny_req *req;
-	int newmask;
 
 	if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
 		return;
 
-	newmask = keyset_translatebitmask(softkey, mask);
 	req->data.selectsoftkey.instance = htolel(instance);
 	req->data.selectsoftkey.reference = htolel(callid);
 	req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
-	req->data.selectsoftkey.validKeyMask = htolel(newmask);
+	req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF);
 
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SELECT_SOFT_KEYS_MESSAGE to %s, inst %d, callid %d, softkey %d, mask 0x%08x\n",
-		d->name, instance, callid, softkey, (unsigned)newmask);
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SELECT_SOFT_KEYS_MESSAGE to %s, inst %d, callid %d, softkey %d, mask 0xFFFFFFFF\n",
+		d->name, instance, callid, softkey);
 	transmit_response(d, req);
 }
 
@@ -2824,146 +2562,22 @@ static void transmit_displaynotify(struct skinny_device *d, const char *text, in
 	transmit_response(d, req);
 }
 
-static void transmit_clearprinotify(struct skinny_device *d, int priority)
-{
-	struct skinny_req *req;
-
-	if (!(req = req_alloc(sizeof(struct clear_prinotify_message), CLEAR_PRINOTIFY_MESSAGE)))
-		return;
-
-	req->data.clearprinotify.priority = htolel(priority);
-
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CLEAR_PRINOTIFY_MESSAGE to %s, priority %d\n", d->name, priority);
-	transmit_response(d, req);
-}
-
-static void _transmit_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
-{
-	struct skinny_req *req;
-
-	if (!(req = req_alloc(sizeof(struct display_prinotify_message), DISPLAY_PRINOTIFY_MESSAGE)))
-		return;
-
-	req->data.displayprinotify.timeout = htolel(timeout);
-	req->data.displayprinotify.priority = htolel(priority);
-
-	if ((char)*text == '\200') {
-		int octalstrlen = strlen(text);
-		ast_copy_string(req->data.displayprinotify.text, text, sizeof(req->data.displayprinotify.text));
-		ast_copy_string(req->data.displayprinotify.text+octalstrlen, extratext, sizeof(req->data.displayprinotify.text)-octalstrlen);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE to %s, '\\%03o\\%03o', '%s', timeout=%d, priority=%d\n",
-			d->name, (unsigned)*text, (unsigned)*(text+1), extratext, timeout, priority);
-	} else {
-		ast_copy_string(req->data.displayprinotify.text, text, sizeof(req->data.displayprinotify.text));
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE to %s, '%s', timeout=%d, priority=%d\n",
-			d->name, text, timeout, priority);
-	}
-
-	transmit_response(d, req);
-}
-
-static void _transmit_displayprinotifyvar(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
-{
-	struct skinny_req *req;
-	int packetlen;
-
-	if (!(req = req_alloc(sizeof(struct display_prinotify_message_variable), DISPLAY_PRINOTIFY_MESSAGE_VARIABLE)))
-		return;
-
-	req->data.displayprinotifyvar.timeout = htolel(timeout);
-	req->data.displayprinotifyvar.priority = htolel(priority);
-
-	if ((char)*text == '\200') {
-		int octalstrlen = strlen(text);
-		ast_copy_string(req->data.displayprinotifyvar.text, text, sizeof(req->data.displayprinotifyvar.text));
-		ast_copy_string(req->data.displayprinotifyvar.text+octalstrlen, extratext, sizeof(req->data.displayprinotifyvar.text)-octalstrlen);
-		packetlen = req->len - MAXDISPLAYNOTIFYSTR + strlen(text) + strlen(extratext);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE_VARIABLE to %s, '\\%03o\\%03o', '%s', timeout=%d, priority=%d\n",
-			d->name, (unsigned)*text, (unsigned)*(text+1), extratext, timeout, priority);
-	} else {
-		ast_copy_string(req->data.displayprinotifyvar.text, text, sizeof(req->data.displayprinotifyvar.text));
-		packetlen = req->len - MAXDISPLAYNOTIFYSTR + strlen(text);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE_VARIABLE to %s, '%s', timeout=%d, priority=%d\n",
-			d->name, text, timeout, priority);
-	}
-
-	req->len = (packetlen & ~0x3) + 4;
-
-	transmit_response(d, req);
-}
-
-static void send_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
-{
-	if (d->protocolversion < 17) {
-		_transmit_displayprinotify(d, text, extratext, timeout, priority);
-	} else {
-		_transmit_displayprinotifyvar(d, text, extratext, timeout, priority);
-	}
-}
-
-static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
+static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, int t, int instance, int callid)
 {
 	struct skinny_req *req;
 
 	if (!(req = req_alloc(sizeof(struct display_prompt_status_message), DISPLAY_PROMPT_STATUS_MESSAGE)))
 		return;
 
+	ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
 	req->data.displaypromptstatus.messageTimeout = htolel(t);
 	req->data.displaypromptstatus.lineInstance = htolel(instance);
 	req->data.displaypromptstatus.callReference = htolel(callid);
 
-	if ((char)*text == '\200') {
-		int octalstrlen = strlen(text);
-		ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatusvar.promptMessage));
-		ast_copy_string(req->data.displaypromptstatus.promptMessage+octalstrlen, extratext, sizeof(req->data.displaypromptstatus.promptMessage)-octalstrlen);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE to %s, '\\%03o\\%03o', '%s'\n",
-			d->name, (unsigned)*text, (unsigned)*(text+1), extratext);
-	} else {
-		ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE to %s, '%s'\n",
-			d->name, text);
-	}
-	transmit_response(d, req);
-}
-
-static void transmit_displaypromptstatusvar(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
-{
-	struct skinny_req *req;
-	int packetlen;
-
-	if (!(req = req_alloc(sizeof(struct display_prompt_status_message_variable), DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE)))
-		return;
-
-	req->data.displaypromptstatusvar.lineInstance = htolel(instance);
-	req->data.displaypromptstatusvar.callReference = htolel(callid);
-
-	if ((char)*text == '\200') {
-		int octalstrlen = strlen(text);
-		ast_copy_string(req->data.displaypromptstatusvar.promptMessage, text, sizeof(req->data.displaypromptstatusvar.promptMessage));
-		ast_copy_string(req->data.displaypromptstatusvar.promptMessage+octalstrlen, extratext, sizeof(req->data.displaypromptstatusvar.promptMessage)-octalstrlen);
-		packetlen = req->len - MAXCALLINFOSTR + strlen(text) + strlen(extratext);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE to %s, '\\%03o\\%03o', '%s'\n",
-			d->name, (unsigned)*text, (unsigned)*(text+1), extratext);
-	} else {
-		ast_copy_string(req->data.displaypromptstatusvar.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
-		packetlen = req->len - MAXCALLINFOSTR + strlen(text);
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE to %s, '%s'\n",
-			d->name, text);
-	}
-	req->len = (packetlen & ~0x3) + 4;
-
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE to %s, text %s\n", d->name, text);
 	transmit_response(d, req);
 }
 
-static void send_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
-{
-	if (d->protocolversion < 17) {
-		transmit_displaypromptstatus(d, text, extratext, t, instance, callid);
-	} else {
-		transmit_displaypromptstatusvar(d, text, extratext, t, instance, callid);
-	}
-}
-
 static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
 {
 	struct skinny_req *req;
@@ -3025,8 +2639,7 @@ static void transmit_stopmediatransmission(struct skinny_device *d, struct skinn
 	transmit_response(d, req);
 }
 
-static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest,
-	struct ast_format *format, unsigned int framing)
+static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt)
 {
 	struct skinny_req *req;
 
@@ -3037,8 +2650,8 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin
 		req->data.startmedia_ip4.passThruPartyId = htolel(sub->callid);
 		req->data.startmedia_ip4.remoteIp = dest.sin_addr.s_addr;
 		req->data.startmedia_ip4.remotePort = htolel(ntohs(dest.sin_port));
-		req->data.startmedia_ip4.packetSize = htolel(framing);
-		req->data.startmedia_ip4.payloadType = htolel(codec_ast2skinny(format));
+		req->data.startmedia_ip4.packetSize = htolel(fmt.cur_ms);
+		req->data.startmedia_ip4.payloadType = htolel(codec_ast2skinny(&fmt.format));
 		req->data.startmedia_ip4.qualifier.precedence = htolel(127);
 		req->data.startmedia_ip4.qualifier.vad = htolel(0);
 		req->data.startmedia_ip4.qualifier.packets = htolel(0);
@@ -3050,16 +2663,16 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin
 		req->data.startmedia_ip6.passThruPartyId = htolel(sub->callid);
 		memcpy(req->data.startmedia_ip6.remoteIp, &dest.sin_addr.s_addr, sizeof(dest.sin_addr.s_addr));
 		req->data.startmedia_ip6.remotePort = htolel(ntohs(dest.sin_port));
-		req->data.startmedia_ip6.packetSize = htolel(framing);
-		req->data.startmedia_ip6.payloadType = htolel(codec_ast2skinny(format));
+		req->data.startmedia_ip6.packetSize = htolel(fmt.cur_ms);
+		req->data.startmedia_ip6.payloadType = htolel(codec_ast2skinny(&fmt.format));
 		req->data.startmedia_ip6.qualifier.precedence = htolel(127);
 		req->data.startmedia_ip6.qualifier.vad = htolel(0);
 		req->data.startmedia_ip6.qualifier.packets = htolel(0);
 		req->data.startmedia_ip6.qualifier.bitRate = htolel(0);
 	}
 
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting START_MEDIA_TRANSMISSION_MESSAGE to %s, callid %u, passthrupartyid %u, ip %s:%d, ms %u, fmt %d, prec 127\n",
-		d->name, sub->callid, sub->callid, ast_inet_ntoa(dest.sin_addr), dest.sin_port, framing, codec_ast2skinny(format));
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting START_MEDIA_TRANSMISSION_MESSAGE to %s, callid %u, passthrupartyid %u, ip %s:%d, ms %d, fmt %d, prec 127\n",
+		d->name, sub->callid, sub->callid, ast_inet_ntoa(dest.sin_addr), dest.sin_port, fmt.cur_ms, codec_ast2skinny(&fmt.format));
 	transmit_response(d, req);
 }
 
@@ -3240,7 +2853,6 @@ static void transmit_softkeysetres(struct skinny_device *d)
 	int i;
 	int x;
 	int y;
-	int keydefcount;
 	const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
 
 	if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
@@ -3248,11 +2860,10 @@ static void transmit_softkeysetres(struct skinny_device *d)
 
 	SKINNY_DEBUG(DEBUG_TEMPLATE, 3, "Creating Softkey Template\n");
 
-	keydefcount = ARRAY_LEN(soft_key_default_definitions);
 	req->data.softkeysets.softKeySetOffset = htolel(0);
-	req->data.softkeysets.softKeySetCount = htolel(keydefcount);
-	req->data.softkeysets.totalSoftKeySetCount = htolel(keydefcount);
-	for (x = 0; x < keydefcount; x++) {
+	req->data.softkeysets.softKeySetCount = htolel(13);
+	req->data.softkeysets.totalSoftKeySetCount = htolel(13);
+	for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
 		const uint8_t *defaults = softkeymode->defaults;
 		/* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
 		   This will have to do for now. */
@@ -3277,7 +2888,6 @@ static void transmit_softkeysetres(struct skinny_device *d)
 static void transmit_softkeytemplateres(struct skinny_device *d)
 {
 	struct skinny_req *req;
-
 	if (!(req = req_alloc(sizeof(struct soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE)))
 		return;
 
@@ -3296,10 +2906,10 @@ static void transmit_softkeytemplateres(struct skinny_device *d)
 static void transmit_reset(struct skinny_device *d, int fullrestart)
 {
 	struct skinny_req *req;
-
+  
 	if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
 		return;
-
+  
 	if (fullrestart)
 		req->data.reset.resetType = 2;
 	else
@@ -3310,20 +2920,15 @@ static void transmit_reset(struct skinny_device *d, int fullrestart)
 	transmit_response(d, req);
 }
 
-static void transmit_keepaliveack(struct skinnysession *s)
+static void transmit_keepaliveack(struct skinny_device *d)
 {
 	struct skinny_req *req;
 
 	if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
 		return;
 
-#ifdef AST_DEVMODE
-	{
-	struct skinny_device *d = s->device;
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting KEEP_ALIVE_ACK_MESSAGE to %s\n", (d ? d->name : "unregistered"));
-	}
-#endif
-	transmit_response_bysession(s, req);
+	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting KEEP_ALIVE_ACK_MESSAGE to %s\n", d->name);
+	transmit_response(d, req);
 }
 
 static void transmit_registerack(struct skinny_device *d)
@@ -3379,31 +2984,6 @@ static void transmit_backspace(struct skinny_device *d, int instance, unsigned c
 	transmit_response(d, req);
 }
 
-static void transmit_serviceurlstat(struct skinny_device *d, int instance)
-{
-	struct skinny_req *req;
-	struct skinny_serviceurl *surl;
-
-	if (!(req = req_alloc(sizeof(struct serviceurl_stat_message), SERVICEURL_STAT_MESSAGE)))
-		return;
-
-	AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
-		if (surl->instance == instance) {
-			break;
-		}
-	}
-
-	if (surl) {
-		memcpy(req->data.serviceurlmessage.displayName, surl->displayName, sizeof(req->data.serviceurlmessage.displayName));
-		memcpy(req->data.serviceurlmessage.url, surl->url, sizeof(req->data.serviceurlmessage.url));
-	}
-	req->data.serviceurlmessage.instance = htolel(instance);
-
-	SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SERVICEURL_STAT_MESSAGE to %s, inst %d\n",
-		d->name, instance);
-	transmit_response(d, req);
-}
-
 static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
 {
 	struct skinny_container *container = data;
@@ -3479,12 +3059,12 @@ static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state
 		case AST_EXTENSION_INUSE:
 			if (subline->sub && (subline->sub->substate == SKINNY_CONNECTED)) { /* Device has a real call */
 				transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED);
-				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL);
-				send_displaypromptstatus(d, OCTAL_CONNECTED, "", 0, l->instance, subline->callid);
+				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED);
+				transmit_displaypromptstatus(d, "Connected", 0, l->instance, subline->callid);
 			} else { /* Some other device has active call */
 				transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
-				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL);
-				send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
+				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE);
+				transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid);
 			}
 			transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
 			transmit_ringer_mode(d, SKINNY_RING_OFF);
@@ -3492,14 +3072,14 @@ static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state
 			break;
 		case AST_EXTENSION_ONHOLD:
 			transmit_callstate(d, l->instance, subline->callid, SKINNY_HOLD);
-			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLAHOLD, KEYMASK_ALL);
-			send_displaypromptstatus(d, "Hold", "", 0, l->instance, subline->callid);
+			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLAHOLD);
+			transmit_displaypromptstatus(d, "Hold", 0, l->instance, subline->callid);
 			transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
 			transmit_activatecallplane(d, l);
 			break;
 		case AST_EXTENSION_NOT_INUSE:
 			transmit_callstate(d, l->instance, subline->callid, SKINNY_ONHOOK);
-			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_ONHOOK, KEYMASK_ALL);
+			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_ONHOOK);
 			transmit_clearpromptmessage(d, l->instance, subline->callid);
 			transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
 			transmit_activatecallplane(d, l);
@@ -3525,14 +3105,6 @@ static void update_connectedline(struct skinny_subchannel *sub, const void *data
 		return;
 	}
 
-	if (sub->calldirection == SKINNY_OUTGOING && !sub->origtonum) {
-		/* Do not set origtonum before here or origtoname won't be set */
-		sub->origtonum = ast_strdup(sub->exten);
-		if (ast_channel_connected(c)->id.name.valid) {
-			sub->origtoname = ast_strdup(ast_channel_connected(c)->id.name.str);
-		}
-	}
-
 	if (!ast_channel_caller(c)->id.number.valid
 		|| ast_strlen_zero(ast_channel_caller(c)->id.number.str)
 		|| !ast_channel_connected(c)->id.number.valid
@@ -3544,20 +3116,19 @@ static void update_connectedline(struct skinny_subchannel *sub, const void *data
 	send_callinfo(sub);
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	struct skinny_line *l = userdata;
 	struct skinny_device *d = l->device;
 	struct skinny_line *l2;
 	int dev_msgs = 0;
-
+	
 	if (!d || !d->session) {
 		return;
 	}
 
-	if (msg && ast_mwi_state_type() == stasis_message_type(msg)) {
-		struct ast_mwi_state *mwi_state = stasis_message_data(msg);
-		l->newmsgs = mwi_state->new_msgs;
+	if (event) {
+		l->newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
 	}
 
 	if (l->newmsgs) {
@@ -3608,10 +3179,10 @@ static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struc
 	if (!(sub = ast_channel_tech_pvt(c)))
 		return AST_RTP_GLUE_RESULT_FORBID;
 
-	skinny_locksub(sub);
+	ast_mutex_lock(&sub->lock);
 
 	if (!(sub->rtp)){
-		skinny_unlocksub(sub);
+		ast_mutex_unlock(&sub->lock);
 		return AST_RTP_GLUE_RESULT_FORBID;
 	}
 
@@ -3625,7 +3196,7 @@ static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struc
 		SKINNY_DEBUG(DEBUG_AUDIO, 4, "skinny_get_rtp_peer() Using AST_RTP_GLUE_RESULT_LOCAL \n");
 	}
 
-	skinny_unlocksub(sub);
+	ast_mutex_unlock(&sub->lock);
 
 	return res;
 
@@ -3636,11 +3207,12 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r
 	struct skinny_subchannel *sub;
 	struct skinny_line *l;
 	struct skinny_device *d;
+	struct ast_format_list fmt;
 	struct sockaddr_in us = { 0, };
 	struct sockaddr_in them = { 0, };
 	struct ast_sockaddr them_tmp;
 	struct ast_sockaddr us_tmp;
-
+	
 	sub = ast_channel_tech_pvt(c);
 
 	if (ast_channel_state(c) != AST_STATE_UP)
@@ -3654,8 +3226,7 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r
 	d = l->device;
 
 	if (rtp){
-		struct ast_format *tmpfmt;
-		unsigned int framing;
+		struct ast_format tmpfmt;
 		ast_rtp_instance_get_remote_address(rtp, &them_tmp);
 		ast_sockaddr_to_sin(&them_tmp, &them);
 
@@ -3664,22 +3235,20 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r
 
 		SKINNY_DEBUG(DEBUG_AUDIO, 4, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port));
 
-		tmpfmt = ast_format_cap_get_format(l->cap, 0);
-		framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
+		ast_best_codec(l->cap, &tmpfmt);
+		fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt);
 
-		SKINNY_DEBUG(DEBUG_AUDIO, 4, "Setting payloadType to '%s' (%u ms)\n", ast_format_get_name(tmpfmt), framing);
+		SKINNY_DEBUG(DEBUG_AUDIO, 4, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms);
 
 		if (!(l->directmedia) || (l->nat)){
 			ast_rtp_instance_get_local_address(rtp, &us_tmp);
 			ast_sockaddr_to_sin(&us_tmp, &us);
 			us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
-			transmit_startmediatransmission(d, sub, us, tmpfmt, framing);
+			transmit_startmediatransmission(d, sub, us, fmt);
 		} else {
-			transmit_startmediatransmission(d, sub, them, tmpfmt, framing);
+			transmit_startmediatransmission(d, sub, them, fmt);
 		}
 
-		ao2_ref(tmpfmt, -1);
-
 		return 0;
 	}
 	/* Need a return here to break the bridge */
@@ -3741,47 +3310,12 @@ static char *skinny_debugs(void)
 		posn += 5;
 		ptr += 5;
 	}
-	if (skinnydebug & DEBUG_KEEPALIVE) {
-		strncpy(ptr, "keepalive ", 10);
-		posn += 10;
-		ptr += 10;
-	}
 	if (posn > 0) {
 		strncpy(--ptr, "\0", 1);
 	}
 	return dbgcli_buf;
 }
 
-static char *complete_skinny_debug(const char *line, const char *word, int pos, int state)
-{
-	const char *debugOpts[]={ "all","audio","hint","keepalive","lock","off","packet","show","sub","template","thread",NULL };
-	char *wordptr = (char *)word;
-	char buf[32];
-	char *bufptr = buf;
-	int buflen = sizeof(buf);
-	int wordlen;
-	int which = 0;
-	int i = 0;
-
-	if (*word == '+' || *word == '-' || *word == '!') {
-		*bufptr = *word;
-		wordptr++;
-		bufptr++;
-		buflen--;
-	}
-	wordlen = strlen(wordptr);
-
-	while (debugOpts[i]) {
-		if (!strncasecmp(wordptr, debugOpts[i], wordlen) && ++which > state) {
-			ast_copy_string(bufptr, debugOpts[i], buflen);
-			return ast_strdup(buf);
-		}
-		i++;
-	}
-
-	return NULL;
-}
-
 static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int i;
@@ -3792,14 +3326,13 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
 
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "skinny debug";
+		e->command = "skinny debug {audio|hint|lock|off|packet|show|sub|template|thread}";
 		e->usage =
-			"Usage: skinny debug {audio|hint|keepalive|lock|off|packet|show|sub|template|thread}\n"
+			"Usage: skinny debug {audio|hint|lock|off|packet|show|sub|template|thread}\n"
 			"       Enables/Disables various Skinny debugging messages\n";
 		return NULL;
 	case CLI_GENERATE:
-		return complete_skinny_debug(a->line, a->word, a->pos, a->n);
-
+		return NULL;
 	}
 
 	if (a->argc < 3)
@@ -3810,7 +3343,7 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
 		return CLI_SUCCESS;
 	}
 
-	for(i = e->args; i < a->argc; i++) {
+	for(i = e->args-1; i < a->argc; i++) {
 		result++;
 		arg = a->argv[i];
 
@@ -3819,11 +3352,6 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
 			continue;
 		}
 
-		if (!strncasecmp(arg, "all", 3)) {
-			skinnydebug = DEBUG_GENERAL|DEBUG_SUB|DEBUG_PACKET|DEBUG_AUDIO|DEBUG_LOCK|DEBUG_TEMPLATE|DEBUG_THREAD|DEBUG_HINT|DEBUG_KEEPALIVE;
-			continue;
-		}
-
 		if (!strncasecmp(arg, "-", 1) || !strncasecmp(arg, "!", 1)) {
 			negate = 1;
 			arg++;
@@ -3850,8 +3378,6 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
 			bitmask = DEBUG_THREAD;
 		} else if (!strncasecmp(arg, "hint", 4)) {
 			bitmask = DEBUG_HINT;
-		} else if (!strncasecmp(arg, "keepalive", 9)) {
-			bitmask = DEBUG_KEEPALIVE;
 		} else {
 			ast_cli(a->fd, "Skinny Debugging - option '%s' unknown\n", a->argv[i]);
 			result--;
@@ -3885,7 +3411,7 @@ static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_c
 	case CLI_GENERATE:
 		return NULL;
 	}
-
+	
 	if (a->argc != e->args)
 		return CLI_SHOWUSAGE;
 
@@ -3897,45 +3423,45 @@ static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_c
 static char *complete_skinny_devices(const char *word, int state)
 {
 	struct skinny_device *d;
+	char *result = NULL;
 	int wordlen = strlen(word), which = 0;
 
 	AST_LIST_TRAVERSE(&devices, d, list) {
-		if (!strncasecmp(word, d->name, wordlen) && ++which > state) {
-                       return ast_strdup(d->name);
-               }
+		if (!strncasecmp(word, d->id, wordlen) && ++which > state)
+			result = ast_strdup(d->id);
 	}
 
-	return NULL;
+	return result;
 }
 
 static char *complete_skinny_show_device(const char *line, const char *word, int pos, int state)
 {
-	return (pos == 3 ? complete_skinny_devices(word, state) : NULL);
+	return (pos == 3 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
 }
 
 static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
 {
-	return (pos == 2 ? complete_skinny_devices(word, state) : NULL);
+	return (pos == 2 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
 }
 
 static char *complete_skinny_show_line(const char *line, const char *word, int pos, int state)
 {
 	struct skinny_device *d;
 	struct skinny_line *l;
+	char *result = NULL;
 	int wordlen = strlen(word), which = 0;
 
 	if (pos != 3)
 		return NULL;
-
+	
 	AST_LIST_TRAVERSE(&devices, d, list) {
 		AST_LIST_TRAVERSE(&d->lines, l, list) {
-			if (!strncasecmp(word, l->name, wordlen) && ++which > state) {
-				return ast_strdup(l->name);
-			}
+			if (!strncasecmp(word, l->name, wordlen) && ++which > state)
+				result = ast_strdup(l->name);
 		}
 	}
 
-	return NULL;
+	return result;
 }
 
 static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -3958,15 +3484,15 @@ static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cl
 
 	AST_LIST_LOCK(&devices);
 	AST_LIST_TRAVERSE(&devices, d, list) {
-		int resetonly = 1;
+		int fullrestart = 0;
 		if (!strcasecmp(a->argv[2], d->id) || !strcasecmp(a->argv[2], d->name) || !strcasecmp(a->argv[2], "all")) {
 			if (!(d->session))
 				continue;
 
 			if (a->argc == 4 && !strcasecmp(a->argv[3], "restart"))
-				resetonly = 0;
-
-			transmit_reset(d, resetonly);
+				fullrestart = 1;
+			
+			transmit_reset(d, fullrestart);
 		}
 	}
 	AST_LIST_UNLOCK(&devices);
@@ -4062,7 +3588,26 @@ static char *device2str(int type)
 	}
 }
 
-static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char * const *argv)
+/*! \brief Print codec list from preference to CLI/manager */
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
+{
+	int x;
+	struct ast_format tmpfmt;
+
+	for(x = 0; x < 32 ; x++) {
+		ast_codec_pref_index(pref, x, &tmpfmt);
+		if (!tmpfmt.id)
+			break;
+		ast_cli(fd, "%s", ast_getformatname(&tmpfmt));
+		ast_cli(fd, ":%d", pref->framing[x]);
+		if (x < 31 && ast_codec_pref_index(pref, x + 1, &tmpfmt))
+			ast_cli(fd, ",");
+	}
+	if (!x)
+		ast_cli(fd, "none");
+}
+
+static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
 {
 	struct skinny_device *d;
 	struct skinny_line *l;
@@ -4127,7 +3672,7 @@ static char *_skinny_show_devices(int fd, int *total, struct mansession *s, cons
 
 	if (total)
 		*total = total_devices;
-
+	
 	return CLI_SUCCESS;
 }
 
@@ -4170,17 +3715,16 @@ static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct
 		return NULL;
 	}
 
-	return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, a->argv);
+	return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
 }
 
-static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
+static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
 {
 	struct skinny_device *d;
 	struct skinny_line *l;
 	struct skinny_speeddial *sd;
 	struct skinny_addon *sa;
-	struct skinny_serviceurl *surl;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	char codec_buf[512];
 
 	if (argc < 4) {
 		return CLI_SHOWUSAGE;
@@ -4189,7 +3733,7 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s
 	AST_LIST_LOCK(&devices);
 	AST_LIST_TRAVERSE(&devices, d, list) {
 		if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) {
-			int numlines = 0, numaddons = 0, numspeeddials = 0, numserviceurls = 0;
+			int numlines = 0, numaddons = 0, numspeeddials = 0;
 
 			AST_LIST_TRAVERSE(&d->lines, l, list){
 				numlines++;
@@ -4203,10 +3747,6 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s
 				numspeeddials++;
 			}
 
-			AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
-				numserviceurls++;
-			}
-
 			if (type == 0) { /* CLI */
 				ast_cli(fd, "Name:        %s\n", d->name);
 				ast_cli(fd, "Id:          %s\n", d->id);
@@ -4214,25 +3754,31 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s
 				ast_cli(fd, "Ip address:  %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
 				ast_cli(fd, "Port:        %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
 				ast_cli(fd, "Device Type: %s\n", device2str(d->type));
-				ast_cli(fd, "Conf Codecs: %s\n", ast_format_cap_get_names(d->confcap, &codec_buf));
-				ast_cli(fd, "Neg Codecs: %s\n", ast_format_cap_get_names(d->cap, &codec_buf));
+				ast_cli(fd, "Conf Codecs:");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcap);
+				ast_cli(fd, "%s\n", codec_buf);
+				ast_cli(fd, "Neg Codecs: ");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->cap);
+				ast_cli(fd, "%s\n", codec_buf);
 				ast_cli(fd, "Registered:  %s\n", (d->session ? "Yes" : "No"));
 				ast_cli(fd, "Lines:       %d\n", numlines);
 				AST_LIST_TRAVERSE(&d->lines, l, list) {
 					ast_cli(fd, "  %s (%s)\n", l->name, l->label);
 				}
+				AST_LIST_TRAVERSE(&d->addons, sa, list) {
+					numaddons++;
+				}	
 				ast_cli(fd, "Addons:      %d\n", numaddons);
 				AST_LIST_TRAVERSE(&d->addons, sa, list) {
 					ast_cli(fd, "  %s\n", sa->type);
 				}
+				AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
+					numspeeddials++;
+				}
 				ast_cli(fd, "Speeddials:  %d\n", numspeeddials);
 				AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
 					ast_cli(fd, "  %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint);
 				}
-				ast_cli(fd, "ServiceURLs:  %d\n", numserviceurls);
-				AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
-					ast_cli(fd, "  %s (%s)\n", surl->displayName, surl->url);
-				}
 			} else { /* manager */
 				astman_append(s, "Channeltype: SKINNY\r\n");
 				astman_append(s, "ObjectName: %s\r\n", d->name);
@@ -4242,8 +3788,12 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s
 				astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
 				astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
 				astman_append(s, "DeviceType: %s\r\n", device2str(d->type));
-				astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(d->confcap, &codec_buf));
-				astman_append(s, "CodecOrder: %s\r\n", ast_format_cap_get_names(d->cap, &codec_buf));
+				astman_append(s, "Codecs: ");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcap);
+				astman_append(s, "%s\r\n", codec_buf);
+				astman_append(s, "CodecOrder: ");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->cap);
+				astman_append(s, "%s\r\n", codec_buf);
 				astman_append(s, "Devicestatus: %s\r\n", (d->session?"registered":"unregistered"));
 				astman_append(s, "NumberOfLines: %d\r\n", numlines);
 				AST_LIST_TRAVERSE(&d->lines, l, list) {
@@ -4257,10 +3807,6 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s
 				AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
 					astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint);
 				}
-				astman_append(s, "ServiceURLs:  %d\r\n", numserviceurls);
-				AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
-					astman_append(s, "  %s (%s)\r\n", surl->displayName, surl->url);
-				}
 			}
 		}
 	}
@@ -4302,10 +3848,10 @@ static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct
 		return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
 	}
 
-	return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, a->argv);
+	return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
 }
 
-static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char * const *argv)
+static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
 {
 	struct skinny_line *l;
 	struct skinny_subchannel *sub;
@@ -4332,7 +3878,7 @@ static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const
 	}
 
 	if (!s) {
-		ast_cli(fd, "Name                 Device Name          Instance Label               \n");
+	 	ast_cli(fd, "Name                 Device Name          Instance Label               \n");
 		ast_cli(fd, "-------------------- -------------------- -------- --------------------\n");
 	}
 	AST_LIST_LOCK(&lines);
@@ -4346,12 +3892,10 @@ static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const
 				l->label);
 			if (verbose) {
 				AST_LIST_TRAVERSE(&l->sub, sub, list) {
-					RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(sub->owner), ao2_cleanup);
-
 					ast_cli(fd, "  %s> %s to %s\n",
 						(sub == l->activesub?"Active  ":"Inactive"),
 						ast_channel_name(sub->owner),
-						bridged ? ast_channel_name(bridged) : ""
+						(ast_bridged_channel(sub->owner)?ast_channel_name(ast_bridged_channel(sub->owner)):"")
 					);
 				}
 			}
@@ -4428,15 +3972,17 @@ static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct a
 		return CLI_SHOWUSAGE;
 	}
 
-	return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, a->argv);
+	return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
 }
 
-static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
+static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
 {
 	struct skinny_device *d;
 	struct skinny_line *l;
 	struct skinny_subline *subline;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	struct ast_codec_pref *pref;
+	int x = 0;
+	char codec_buf[512];
 	char group_buf[256];
 	char cbuf[256];
 
@@ -4457,8 +4003,6 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
 			continue;
 		}
 		AST_LIST_TRAVERSE(&d->lines, l, list) {
-			struct ast_str *tmp_str = ast_str_alloca(512);
-
 			if (strcasecmp(argv[3], l->name)) {
 				continue;
 			}
@@ -4470,20 +4014,15 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
 				ast_cli(fd, "Context:          %s\n", l->context);
 				ast_cli(fd, "CallGroup:        %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
 				ast_cli(fd, "PickupGroup:      %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
-				ast_cli(fd, "NamedCallGroup:   %s\n", ast_print_namedgroups(&tmp_str, l->named_callgroups));
-				ast_str_reset(tmp_str);
-				ast_cli(fd, "NamedPickupGroup: %s\n", ast_print_namedgroups(&tmp_str, l->named_pickupgroups));
-				ast_str_reset(tmp_str);
 				ast_cli(fd, "Language:         %s\n", S_OR(l->language, "<not set>"));
 				ast_cli(fd, "Accountcode:      %s\n", S_OR(l->accountcode, "<not set>"));
-				ast_cli(fd, "AmaFlag:          %s\n", ast_channel_amaflags2string(l->amaflags));
+				ast_cli(fd, "AmaFlag:          %s\n", ast_cdr_flags2str(l->amaflags));
 				ast_cli(fd, "CallerId Number:  %s\n", S_OR(l->cid_num, "<not set>"));
 				ast_cli(fd, "CallerId Name:    %s\n", S_OR(l->cid_name, "<not set>"));
 				ast_cli(fd, "Hide CallerId:    %s\n", (l->hidecallerid ? "Yes" : "No"));
 				ast_cli(fd, "CFwdAll:          %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
 				ast_cli(fd, "CFwdBusy:         %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
 				ast_cli(fd, "CFwdNoAnswer:     %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
-				ast_cli(fd, "CFwdTimeout:      %dms\n", l->callfwdtimeout);
 				ast_cli(fd, "VoicemailBox:     %s\n", S_OR(l->mailbox, "<not set>"));
 				ast_cli(fd, "VoicemailNumber:  %s\n", S_OR(l->vmexten, "<not set>"));
 				ast_cli(fd, "MWIblink:         %d\n", l->mwiblink);
@@ -4502,8 +4041,15 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
 				ast_cli(fd, "immediate:        %s\n", (l->immediate ? "Yes" : "No"));
 				ast_cli(fd, "Group:            %d\n", l->group);
 				ast_cli(fd, "Parkinglot:       %s\n", S_OR(l->parkinglot, "<not set>"));
-				ast_cli(fd, "Conf Codecs:      %s\n", ast_format_cap_get_names(l->confcap, &codec_buf));
-				ast_cli(fd, "Neg Codecs:       %s\n", ast_format_cap_get_names(l->cap, &codec_buf));
+				ast_cli(fd, "Conf Codecs:      ");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcap);
+				ast_cli(fd, "%s\n", codec_buf);
+				ast_cli(fd, "Neg Codecs:       ");
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->cap);
+				ast_cli(fd, "%s\n", codec_buf);
+				ast_cli(fd, "Codec Order:      (");
+				print_codec_to_cli(fd, &l->prefs);
+				ast_cli(fd, ")\n");
 				if  (AST_LIST_FIRST(&l->sublines)) {
 					ast_cli(fd, "Sublines:\n");
 					AST_LIST_TRAVERSE(&l->sublines, subline, list) {
@@ -4521,13 +4067,9 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
 				astman_append(s, "Context: %s\r\n", l->context);
 				astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
 				astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
-				astman_append(s, "NamedCallGroup: %s\r\n", ast_print_namedgroups(&tmp_str, l->named_callgroups));
-				ast_str_reset(tmp_str);
-				astman_append(s, "NamedPickupGroup: %s\r\n", ast_print_namedgroups(&tmp_str, l->named_pickupgroups));
-				ast_str_reset(tmp_str);
 				astman_append(s, "Language: %s\r\n", S_OR(l->language, "<not set>"));
 				astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
-				astman_append(s, "AMAflags: %s\r\n", ast_channel_amaflags2string(l->amaflags));
+				astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(l->amaflags));
 				astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, ""));
 				astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No"));
 				astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
@@ -4551,12 +4093,24 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
 				astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No"));
 				astman_append(s, "Group: %d\r\n", l->group);
 				astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>"));
-				astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(l->confcap, &codec_buf));
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcap);
+				astman_append(s, "Codecs: %s\r\n", codec_buf);
+				astman_append(s, "CodecOrder: ");
+				pref = &l->prefs;
+				for(x = 0; x < 32 ; x++) {
+					struct ast_format tmpfmt;
+					ast_codec_pref_index(pref, x, &tmpfmt);
+					if (!tmpfmt.id)
+						break;
+					astman_append(s, "%s", ast_getformatname(&tmpfmt));
+					if (x < 31 && ast_codec_pref_index(pref, x+1, &tmpfmt))
+						astman_append(s, ",");
+				}
 				astman_append(s, "\r\n");
 			}
 		}
 	}
-
+	
 	AST_LIST_UNLOCK(&devices);
 	return CLI_SUCCESS;
 }
@@ -4595,14 +4149,12 @@ static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct as
 		return complete_skinny_show_line(a->line, a->word, a->pos, a->n);
 	}
 
-	return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, a->argv);
+	return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
 }
 
 /*! \brief List global settings for the Skinny subsystem. */
 static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	char immed_str[2] = {immed_dialchar, '\0'};
-
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "skinny show settings";
@@ -4612,7 +4164,7 @@ static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struc
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
-	}
+	}	
 
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
@@ -4624,7 +4176,6 @@ static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struc
 	ast_cli(a->fd, "  Date Format:            %s\n", date_format);
 	ast_cli(a->fd, "  Voice Mail Extension:   %s\n", S_OR(vmexten, "(not set)"));
 	ast_cli(a->fd, "  Reg. context:           %s\n", S_OR(regcontext, "(not set)"));
-	ast_cli(a->fd, "  Immed. Dial Key:        %s\n", S_OR(immed_str, "(not set)"));
 	ast_cli(a->fd, "  Jitterbuffer enabled:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_ENABLED)));
 	 if (ast_test_flag(&global_jbconf, AST_JB_ENABLED)) {
 		ast_cli(a->fd, "  Jitterbuffer forced:    %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_FORCED)));
@@ -4640,92 +4191,6 @@ static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struc
 	return CLI_SUCCESS;
 }
 
-static char *_skinny_message_set(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
-{
-	struct skinny_device *d;
-	char text_buf[32];
-
-	if (argc < 7) {
-		return CLI_SHOWUSAGE;
-	}
-
-	AST_LIST_LOCK(&devices);
-	AST_LIST_TRAVERSE(&devices, d, list) {
-		if (!strcasecmp(argv[3], d->name)) {
-			int i;
-			char *strp = text_buf;
-			int charleft = sizeof(text_buf);
-			int priority = atoi(argv[4]);
-			int timeout = atoi(argv[5]);
-			ast_copy_string(strp, argv[6], charleft);
-			charleft -= strlen(strp);
-			strp += strlen(strp);
-			for(i=7; i<argc; i++) {
-				ast_copy_string(strp++, " ", charleft--);
-				ast_copy_string(strp, argv[i], charleft);
-				charleft -= strlen(strp);
-				strp += strlen(strp);
-			}
-			send_displayprinotify(d, text_buf, "", timeout, priority);
-		}
-	}
-	AST_LIST_UNLOCK(&devices);
-	return CLI_SUCCESS;
-}
-
-/*! \brief Handle sending messages to devices. */
-static char *handle_skinny_message_set(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "skinny message set";
-		e->usage =
-			"Usage: skinny message set <device> <priority> <timeout> <message>\n"
-			"       Set the current priority level message on a device.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
-	}
-
-	return _skinny_message_set(0, a->fd, NULL, NULL, a->argc, a->argv);
-}
-
-static char *_skinny_message_clear(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
-{
-	struct skinny_device *d;
-
-	if (argc != 5) {
-		return CLI_SHOWUSAGE;
-	}
-
-	AST_LIST_LOCK(&devices);
-	AST_LIST_TRAVERSE(&devices, d, list) {
-		if (!strcasecmp(argv[3], d->name)) {
-			int priority = atoi(argv[4]);
-			transmit_clearprinotify(d, priority);
-		}
-	}
-	AST_LIST_UNLOCK(&devices);
-	return CLI_SUCCESS;
-}
-
-/*! \brief Handle clearing messages to devices. */
-static char *handle_skinny_message_clear(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "skinny message clear";
-		e->usage =
-			"Usage: skinny message clear <device> <priority>\n"
-			"       Clear the current priority level message on device.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
-	}
-
-	return _skinny_message_clear(0, a->fd, NULL, NULL, a->argc, a->argv);
-}
-
 static struct ast_cli_entry cli_skinny[] = {
 	AST_CLI_DEFINE(handle_skinny_show_devices, "List defined Skinny devices"),
 	AST_CLI_DEFINE(handle_skinny_show_device, "List Skinny device information"),
@@ -4737,8 +4202,6 @@ static struct ast_cli_entry cli_skinny[] = {
 #endif
 	AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"),
 	AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"),
-	AST_CLI_DEFINE(handle_skinny_message_set, "Send message to devices"),
-	AST_CLI_DEFINE(handle_skinny_message_clear, "Clear message to devices"),
 };
 
 static void start_rtp(struct skinny_subchannel *sub)
@@ -4748,8 +4211,8 @@ static void start_rtp(struct skinny_subchannel *sub)
 	int hasvideo = 0;
 	struct ast_sockaddr bindaddr_tmp;
 
-	skinny_locksub(sub);
-	SKINNY_DEBUG(DEBUG_AUDIO, 3, "Sub %u - Starting RTP\n", sub->callid);
+	ast_mutex_lock(&sub->lock);
+	/* Allocate the RTP */
 	ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
 	sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
 	if (hasvideo)
@@ -4763,30 +4226,28 @@ static void start_rtp(struct skinny_subchannel *sub)
 	}
 
 	if (sub->rtp && sub->owner) {
-		ast_rtp_instance_set_channel_id(sub->rtp, ast_channel_uniqueid(sub->owner));
 		ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
 		ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
 	}
 	if (hasvideo && sub->vrtp && sub->owner) {
-		ast_rtp_instance_set_channel_id(sub->vrtp, ast_channel_uniqueid(sub->owner));
 		ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
 		ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
 	}
 	if (sub->rtp) {
 		ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
 		ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, l->nat);
-		/* Set frame packetization */
-		ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(sub->rtp),
-			ast_format_cap_get_framing(l->cap));
 	}
 	if (sub->vrtp) {
 		ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
 		ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_NAT, l->nat);
 	}
+	/* Set Frame packetization */
+	if (sub->rtp)
+		ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, &l->prefs);
 
 	/* Create the RTP connection */
 	transmit_connect(d, sub);
-	skinny_unlocksub(sub);
+	ast_mutex_unlock(&sub->lock);
 }
 
 static void destroy_rtp(struct skinny_subchannel *sub)
@@ -4813,7 +4274,6 @@ static void *skinny_newcall(void *data)
 	struct skinny_device *d = l->device;
 	int res = 0;
 
-	ast_channel_lock(c);
 	ast_set_callerid(c,
 		l->hidecallerid ? "" : l->cid_num,
 		l->hidecallerid ? "" : l->cid_name,
@@ -4827,7 +4287,6 @@ static void *skinny_newcall(void *data)
 	ast_party_name_init(&ast_channel_connected(c)->id.name);
 #endif
 	ast_setstate(c, AST_STATE_RING);
-	ast_channel_unlock(c);
 	if (!sub->rtp) {
 		start_rtp(sub);
 	}
@@ -4847,7 +4306,7 @@ static void skinny_dialer(struct skinny_subchannel *sub, int timedout)
 	struct skinny_device *d = l->device;
 
 	if (timedout || !ast_matchmore_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
-		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Force dialing '%s' because of %s\n", sub->callid, sub->exten, (timedout ? "timeout" : "exactmatch"));
+		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Force dialing '%s'\n", sub->callid, sub->exten);
 		if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
 			if (sub->substate == SUBSTATE_OFFHOOK) {
 				dialandactivatesub(sub, sub->exten);
@@ -4862,7 +4321,6 @@ static void skinny_dialer(struct skinny_subchannel *sub, int timedout)
 	} else {
 		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Wait for more digits\n", sub->callid);
 		if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
-			transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD, KEYMASK_ALL);
 			sub->dialer_sched = skinny_sched_add(matchdigittimeout, skinny_dialer_cb, sub);
 		} else {
 			sub->dialer_sched = skinny_sched_add(gendigittimeout, skinny_dialer_cb, sub);
@@ -4874,7 +4332,7 @@ static int skinny_dialer_cb(const void *data)
 {
 	struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Dialer called from SCHED %d\n", sub->callid, sub->dialer_sched);
-	sub->dialer_sched = 0;
+	sub->dialer_sched = -1;
 	skinny_dialer(sub, 1);
 	return 0;
 }
@@ -4882,21 +4340,8 @@ static int skinny_dialer_cb(const void *data)
 static int skinny_autoanswer_cb(const void *data)
 {
 	struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
-	skinny_locksub(sub);
-	sub->aa_sched = 0;
+	sub->aa_sched = -1;
 	setsubstate(sub, SKINNY_CONNECTED);
-	skinny_unlocksub(sub);
-	return 0;
-}
-
-static int skinny_cfwd_cb(const void *data)
-{
-	struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
-	struct skinny_line *l = sub->line;
-	sub->cfwd_sched = 0;
-	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDNOANS to %s.\n", sub->callid, l->call_forward_noanswer);
-	ast_channel_call_forward_set(sub->owner, l->call_forward_noanswer);
-	ast_queue_control(sub->owner, AST_CONTROL_REDIRECTING);
 	return 0;
 }
 
@@ -4932,10 +4377,9 @@ static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
 		return -1;
 	}
 
-	skinny_locksub(sub);
 	AST_LIST_TRAVERSE(ast_channel_varshead(ast), current, entries) {
-		if (!(strcmp(ast_var_name(current), "SKINNY_AUTOANSWER"))) {
-			if (d->hookstate == SKINNY_ONHOOK && !sub->aa_sched) {
+		if (!(strcasecmp(ast_var_name(current),"SKINNY_AUTOANSWER"))) {
+			if (d->hookstate == SKINNY_ONHOOK && !sub->aa_sched < 0) {
 				char buf[24];
 				int aatime;
 				char *stringp = buf, *curstr;
@@ -4965,7 +4409,6 @@ static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
 	if (doautoanswer) {
 		setsubstate(sub, SUBSTATE_CONNECTED);
 	}
-	skinny_unlocksub(sub);
 	return res;
 }
 
@@ -4982,11 +4425,11 @@ static int skinny_hangup(struct ast_channel *ast)
 
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Destroying\n", sub->callid);
 
-	skinny_set_owner(sub, NULL);
+	ast_mutex_lock(&sub->lock);
+	sub->owner = NULL;
 	ast_channel_tech_pvt_set(ast, NULL);
 	destroy_rtp(sub);
-	ast_free(sub->origtonum);
-	ast_free(sub->origtoname);
+	ast_mutex_unlock(&sub->lock);
 	ast_free(sub);
 	ast_module_unref(ast_module_info->self);
 	return 0;
@@ -4997,6 +4440,14 @@ static int skinny_answer(struct ast_channel *ast)
 	int res = 0;
 	struct skinny_subchannel *sub = ast_channel_tech_pvt(ast);
 
+	if (sub->blindxfer) {
+		SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_answer(%s) on %s@%s-%u with BlindXFER, transferring\n",
+			ast_channel_name(ast), sub->line->name, sub->line->device->name, sub->callid);
+		ast_setstate(ast, AST_STATE_UP);
+		skinny_transfer(sub);
+		return 0;
+	}
+
 	sub->cxmode = SKINNY_CX_SENDRECV;
 
 	SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_answer(%s) on %s@%s-%u\n",
@@ -5044,17 +4495,9 @@ static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
 	if (ast) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-				struct ast_format_cap *caps;
-
-				ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format));
-
-				caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-				if (caps) {
-					ast_format_cap_append(caps, f->subclass.format, 0);
-					ast_channel_nativeformats_set(ast, caps);
-					ao2_ref(caps, -1);
-				}
+			if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
+				ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+				ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format);
 				ast_set_read_format(ast, ast_channel_readformat(ast));
 				ast_set_write_format(ast, ast_channel_writeformat(ast));
 			}
@@ -5067,9 +4510,9 @@ static struct ast_frame *skinny_read(struct ast_channel *ast)
 {
 	struct ast_frame *fr;
 	struct skinny_subchannel *sub = ast_channel_tech_pvt(ast);
-	skinny_locksub(sub);
+	ast_mutex_lock(&sub->lock);
 	fr = skinny_rtp_read(sub);
-	skinny_unlocksub(sub);
+	ast_mutex_unlock(&sub->lock);
 	return fr;
 }
 
@@ -5085,22 +4528,22 @@ static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
 			return 0;
 		}
 	} else {
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *codec_buf = ast_str_alloca(64);
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+			char buf[256];
 			ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
-				ast_format_get_name(frame->subclass.format),
-				ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
-				ast_format_get_name(ast_channel_readformat(ast)),
-				ast_format_get_name(ast_channel_writeformat(ast)));
+				ast_getformatname(&frame->subclass.format),
+				ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+				ast_getformatname(ast_channel_readformat(ast)),
+				ast_getformatname(ast_channel_writeformat(ast)));
 			return -1;
 		}
 	}
 	if (sub) {
-		skinny_locksub(sub);
+		ast_mutex_lock(&sub->lock);
 		if (sub->rtp) {
 			res = ast_rtp_instance_write(sub->rtp, frame);
 		}
-		skinny_unlocksub(sub);
+		ast_mutex_unlock(&sub->lock);
 	}
 	return res;
 }
@@ -5113,7 +4556,7 @@ static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
 		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
 		return -1;
 	}
-	skinny_set_owner(sub, newchan);
+	sub->owner = newchan;
 	return 0;
 }
 
@@ -5231,52 +4674,67 @@ static char *control2str(int ind) {
 	}
 }
 
-static void skinny_transfer_attended(struct skinny_subchannel *sub)
-{
-	struct skinny_subchannel *xferee;
-	struct skinny_subchannel *xferor;
-	enum ast_transfer_result res;
-
-	if (sub->xferor) {
-		xferor = sub;
-		xferee = sub->related;
-	} else {
-		xferor = sub;
-		xferee = sub->related;
-	}
-
-	ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
-	if (ast_channel_state(xferor->owner) == AST_STATE_RINGING) {
-		ast_queue_control(xferee->owner, AST_CONTROL_RINGING);
-	}
-	res = ast_bridge_transfer_attended(xferee->owner, xferor->owner);
-
-	if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u failed to transfer %u to '%s'@'%s' - %u\n",
-			xferor->callid, xferee->callid, xferor->exten, xferor->line->context, res);
-		send_displayprinotify(xferor->line->device, "Transfer failed", NULL, 10, 5);
-		ast_queue_control(xferee->owner, AST_CONTROL_HOLD);
-	}
-}
-
-static void skinny_transfer_blind(struct skinny_subchannel *sub)
+static int skinny_transfer(struct skinny_subchannel *sub)
 {
-	struct skinny_subchannel *xferee = sub->related;
-	enum ast_transfer_result res;
+	struct skinny_subchannel *xferor; /* the sub doing the transferring */
+	struct skinny_subchannel *xferee; /* the sub being transferred */
+	struct ast_tone_zone_sound *ts = NULL;
 
-	sub->related = NULL;
-	xferee->related = NULL;
+	if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub->related->owner)) {
+		if (sub->xferor) {
+			xferor = sub;
+			xferee = sub->related;
+		} else {
+			xferor = sub;
+			xferee = sub->related;
+		}
 
-	ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
-	res = ast_bridge_transfer_blind(1, xferee->owner, sub->exten, sub->line->context, NULL, NULL);
+		SKINNY_DEBUG(DEBUG_SUB, 3, "Transferee channels (local/remote): %s and %s\n",
+			ast_channel_name(xferee->owner), ast_bridged_channel(xferee->owner) ? ast_channel_name(ast_bridged_channel(xferee->owner)) : "");
+		SKINNY_DEBUG(DEBUG_SUB, 3, "Transferor channels (local/remote): %s and %s\n",
+			ast_channel_name(xferor->owner), ast_bridged_channel(xferor->owner) ? ast_channel_name(ast_bridged_channel(xferor->owner)) : "");
 
-	if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u failed to blind transfer %u to '%s'@'%s' - %u\n",
-			sub->callid, xferee->callid, sub->exten, sub->line->context, res);
-		send_displayprinotify(sub->line->device, "Transfer failed", NULL, 10, 5);
-		ast_queue_control(xferee->owner, AST_CONTROL_HOLD);
+		if (ast_bridged_channel(xferor->owner)) {
+			if (ast_bridged_channel(xferee->owner)) {
+				ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
+			}
+			if (ast_channel_state(xferor->owner) == AST_STATE_RING) {
+				/* play ringing inband */
+				if ((ts = ast_get_indication_tone(ast_channel_zone(xferor->owner), "ring"))) {
+					ast_playtones_start(xferor->owner, 0, ts->data, 1);
+					ts = ast_tone_zone_sound_unref(ts);
+				}
+			}
+			SKINNY_DEBUG(DEBUG_SUB, 3, "Transfer Masquerading %s to %s\n",
+				ast_channel_name(xferee->owner), ast_bridged_channel(xferor->owner) ? ast_channel_name(ast_bridged_channel(xferor->owner)) : "");
+			if (ast_channel_masquerade(xferee->owner, ast_bridged_channel(xferor->owner))) {
+				ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+					ast_channel_name(ast_bridged_channel(xferor->owner)), ast_channel_name(xferee->owner));
+				return -1;
+			}
+		} else if (ast_bridged_channel(xferee->owner)) {
+			ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
+			if (ast_channel_state(xferor->owner) == AST_STATE_RING) {
+				/* play ringing inband */
+				if ((ts = ast_get_indication_tone(ast_channel_zone(xferor->owner), "ring"))) {
+					ast_playtones_start(xferor->owner, 0, ts->data, 1);
+					ts = ast_tone_zone_sound_unref(ts);
+				}
+			}
+			SKINNY_DEBUG(DEBUG_SUB, 3, "Transfer Masquerading %s to %s\n",
+				ast_channel_name(xferor->owner), ast_bridged_channel(xferee->owner) ? ast_channel_name(ast_bridged_channel(xferee->owner)) : "");
+			if (ast_channel_masquerade(xferor->owner, ast_bridged_channel(xferee->owner))) {
+				ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+					ast_channel_name(ast_bridged_channel(xferee->owner)), ast_channel_name(xferor->owner));
+				return -1;
+			}
+			return 0;
+		} else {
+			ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+				ast_channel_name(xferor->owner), ast_channel_name(xferee->owner));
+		}
 	}
-	dumpsub(sub, 1);
+	return 0;
 }
 
 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
@@ -5295,6 +4753,12 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
 		control2str(ind), ast_channel_name(ast), sub->callid);
 	switch(ind) {
 	case AST_CONTROL_RINGING:
+		if (sub->blindxfer) {
+			SKINNY_DEBUG(DEBUG_SUB, 3, "Channel %s (Sub %u) set up for Blind Xfer, so Xfer rather than ring device\n",
+				ast_channel_name(ast), sub->callid);
+			skinny_transfer(sub);
+			break;
+		}
 		setsubstate(sub, SUBSTATE_RINGOUT);
 		return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
 	case AST_CONTROL_BUSY:
@@ -5336,60 +4800,37 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
 		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
 		/* fallthrough */
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 		return -1; /* Tell asterisk to provide inband signalling */
 	}
 	return 0;
 }
 
-static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan)
-{
-	sub->owner = chan;
-	if (sub->rtp) {
-		ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
-	}
-	if (sub->vrtp) {
-		ast_rtp_instance_set_channel_id(sub->vrtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
-	}
-}
-
-static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subline *subline, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int direction)
+static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subline *subline, int state, const char *linkedid, int direction)
 {
 	struct ast_channel *tmp;
 	struct skinny_subchannel *sub;
 	struct skinny_device *d = l->device;
 	struct ast_variable *v = NULL;
-	struct ast_format *tmpfmt;
-	struct ast_format_cap *caps;
-#ifdef AST_DEVMODE
-	struct ast_str *codec_buf = ast_str_alloca(64);
-#endif
+	struct ast_format tmpfmt;
 
 	if (!l->device || !l->device->session) {
 		ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
 		return NULL;
 	}
 
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return NULL;
-	}
-
-	tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, assignedids, requestor, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
+	tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, linkedid, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
 	if (!tmp) {
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
-		ao2_ref(caps, -1);
 		return NULL;
 	} else {
 		sub = ast_calloc(1, sizeof(*sub));
 		if (!sub) {
 			ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
-			ast_channel_unlock(tmp);
-			ast_channel_unref(tmp);
-			ao2_ref(caps, -1);
 			return NULL;
 		} else {
-			skinny_set_owner(sub, tmp);
+			ast_mutex_init(&sub->lock);
+
+			sub->owner = tmp;
 			sub->callid = callnums++;
 			d->lastlineinstance = l->instance;
 			d->lastcallreference = sub->callid;
@@ -5400,11 +4841,8 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 			sub->xferor = 0;
 			sub->related = NULL;
 			sub->calldirection = direction;
-			sub->aa_sched = 0;
-			sub->dialer_sched = 0;
-			sub->cfwd_sched = 0;
-			sub->dialType = DIALTYPE_NORMAL;
-			sub->getforward = 0;
+			sub->aa_sched = -1;
+			sub->dialer_sched = -1;
 
 			if (subline) {
 				sub->subline = subline;
@@ -5412,35 +4850,31 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 			} else {
 				sub->subline = NULL;
 			}
-
+			
 			AST_LIST_INSERT_HEAD(&l->sub, sub, list);
 			//l->activesub = sub;
 		}
-		ast_channel_stage_snapshot(tmp);
 		ast_channel_tech_set(tmp, &skinny_tech);
 		ast_channel_tech_pvt_set(tmp, sub);
-		if (!ast_format_cap_count(l->cap)) {
-			ast_format_cap_append_from_cap(caps, l->cap, AST_MEDIA_TYPE_UNKNOWN);
-		} else {
-			ast_format_cap_append_from_cap(caps, default_cap, AST_MEDIA_TYPE_UNKNOWN);
+		ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap);
+		if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
+			// Should throw an error
+			ast_format_cap_copy(ast_channel_nativeformats(tmp), default_cap);
 		}
-		ast_channel_nativeformats_set(tmp, caps);
-		ao2_ref(caps, -1);
-		tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
+		ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
 		SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_new: tmp->nativeformats=%s fmt=%s\n",
-			ast_format_cap_get_names(ast_channel_nativeformats(tmp), &codec_buf),
-			ast_format_get_name(tmpfmt));
+			ast_getformatname_multiple(dbgsub_buf, sizeof(dbgsub_buf), ast_channel_nativeformats(tmp)),
+			ast_getformatname(&tmpfmt));
 		if (sub->rtp) {
 			ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
 		}
 		if (state == AST_STATE_RING) {
 			ast_channel_rings_set(tmp, 1);
 		}
-		ast_channel_set_writeformat(tmp, tmpfmt);
-		ast_channel_set_rawwriteformat(tmp, tmpfmt);
-		ast_channel_set_readformat(tmp, tmpfmt);
-		ast_channel_set_rawreadformat(tmp, tmpfmt);
-		ao2_ref(tmpfmt, -1);
+		ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
 
 		if (!ast_strlen_zero(l->language))
 			ast_channel_language_set(tmp, l->language);
@@ -5455,18 +4889,13 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 		ast_channel_callgroup_set(tmp, l->callgroup);
 		ast_channel_pickupgroup_set(tmp, l->pickupgroup);
 
-		ast_channel_named_callgroups_set(tmp, l->named_callgroups);
-		ast_channel_named_pickupgroups_set(tmp, l->named_pickupgroups);
-
+		/* XXX Need to figure out how to handle CFwdNoAnswer */
 		if (l->cfwdtype & SKINNY_CFWD_ALL) {
-			SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDALL to %s.\n", sub->callid, l->call_forward_all);
 			ast_channel_call_forward_set(tmp, l->call_forward_all);
-		} else if ((l->cfwdtype & SKINNY_CFWD_BUSY) && (get_devicestate(l) != AST_DEVICE_NOT_INUSE)) {
-			SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDBUSY to %s.\n", sub->callid, l->call_forward_busy);
-			ast_channel_call_forward_set(tmp, l->call_forward_busy);
-		} else if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
-			SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDNOANS Scheduling for %d seconds.\n", sub->callid, l->callfwdtimeout/1000);
-			sub->cfwd_sched = skinny_sched_add(l->callfwdtimeout, skinny_cfwd_cb, sub);
+		} else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
+			if (get_devicestate(l) != AST_DEVICE_NOT_INUSE) {
+				ast_channel_call_forward_set(tmp, l->call_forward_busy);
+			}
 		}
 
 		if (subline) {
@@ -5493,9 +4922,6 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 		for (v = l->chanvars ; v ; v = v->next)
 			pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
-		ast_channel_stage_snapshot_done(tmp);
-		ast_channel_unlock(tmp);
-
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
@@ -5548,51 +4974,29 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	struct skinny_subline *subline = sub->subline;
 	struct skinny_device *d = l->device;
 	struct ast_channel *c = sub->owner;
-	struct ast_party_id connected_id;
 	pthread_t t;
 	int actualstate = state;
-	char *fromnum;
 
 	if (sub->substate == SUBSTATE_ONHOOK) {
 		return;
 	}
 
-	skinny_locksub(sub);
-
 	if (sub->dialer_sched) {
 		skinny_sched_del(sub->dialer_sched, sub);
-		sub->dialer_sched = 0;
+		sub->dialer_sched = -1;
 	}
 
 	if (state != SUBSTATE_RINGIN && sub->aa_sched) {
 		skinny_sched_del(sub->aa_sched, sub);
-		sub->aa_sched = 0;
+		sub->aa_sched = -1;
 		sub->aa_beep = 0;
 		sub->aa_mute = 0;
 	}
 
-	if (sub->cfwd_sched) {
-		if (state == SUBSTATE_CONNECTED) {
-			if (skinny_sched_del(sub->cfwd_sched, sub)) {
-				SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - trying to change state from %s to %s, but already forwarded because no answer.\n",
-					sub->callid, substate2str(sub->substate), substate2str(actualstate));
-				skinny_unlocksub(sub);
-				return;
-			}
-			sub->cfwd_sched = 0;
-		} else if (state == SUBSTATE_ONHOOK) {
-			skinny_sched_del(sub->cfwd_sched, sub);
-		}
-	}
-
 	if ((state == SUBSTATE_RINGIN) && ((d->hookstate == SKINNY_OFFHOOK) || (AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list)))) {
 		actualstate = SUBSTATE_CALLWAIT;
 	}
 
-	if (sub->substate == SUBSTATE_RINGIN && state != SUBSTATE_RINGIN) {
-		transmit_clearprinotify(d, 5);
-	}
-
 	if ((state == SUBSTATE_CONNECTED) && (!subline) && (AST_LIST_FIRST(&l->sublines))) {
 		const char *slastation;
 		struct skinny_subline *tmpsubline;
@@ -5647,21 +5051,22 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			if (subline->callid) {
 				transmit_stop_tone(d, l->instance, sub->callid);
 				transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
-				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL);
-				send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
+				transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE);
+				transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid);
 			}
 
 			sub->cxmode = SKINNY_CX_RECVONLY;
 			sub->substate = SUBSTATE_ONHOOK;
+			destroy_rtp(sub);
 			sub->substate = SUBSTATE_ONHOOK;
 			if (sub->owner) {
 				ast_queue_hangup(sub->owner);
 			}
-			break;
+			return;
 		case SUBSTATE_CONNECTED:
 			transmit_activatecallplane(d, l);
 			transmit_stop_tone(d, l->instance, sub->callid);
-			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL);
+			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED);
 			transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED);
 			if (!sub->rtp) {
 				start_rtp(sub);
@@ -5670,14 +5075,14 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 				ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
 			}
 			if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
-				transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
+				transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
 			}
 			if (ast_channel_state(sub->owner) != AST_STATE_UP) {
 				ast_setstate(sub->owner, AST_STATE_UP);
 			}
 			sub->substate = SUBSTATE_CONNECTED;
 			l->activesub = sub;
-			break;
+			return; 
 		case SUBSTATE_HOLD:
 			if (sub->substate != SUBSTATE_CONNECTED) {
 				ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
@@ -5688,19 +5093,19 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			transmit_stopmediatransmission(d, sub);
 
 			transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
-			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL);
-			send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
-
+			transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE);
+			transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid);
+			
 			sub->substate = SUBSTATE_HOLD;
 
-			ast_queue_hold(sub->owner, l->mohsuggest);
+			ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
+				S_OR(l->mohsuggest, NULL),
+				!ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
 
-			break;
+			return;
 		default:
 			ast_log(LOG_WARNING, "Substate handling under subline for state %d not implemented on Sub-%u\n", state, sub->callid);
 		}
-		skinny_unlocksub(sub);
-		return;
 	}
 
 	if ((d->hookstate == SKINNY_ONHOOK) && ((actualstate == SUBSTATE_OFFHOOK) || (actualstate == SUBSTATE_DIALING)
@@ -5714,7 +5119,8 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		sub->callid, substate2str(sub->substate), substate2str(actualstate));
 
 	if (actualstate == sub->substate) {
-		skinny_unlocksub(sub);
+		send_callinfo(sub);
+		transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
 		return;
 	}
 
@@ -5726,8 +5132,8 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		transmit_activatecallplane(d, l);
 		transmit_clear_display_message(d, l->instance, sub->callid);
 		transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
-		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL);
-		send_displaypromptstatus(d, OCTAL_ENTRNUM, "", 0, l->instance, sub->callid);
+		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
+		transmit_displaypromptstatus(d, "Enter number", 0, l->instance, sub->callid);
 
 		sub->substate = SUBSTATE_OFFHOOK;
 		sub->dialer_sched = skinny_sched_add(firstdigittimeout, skinny_dialer_cb, sub);
@@ -5738,10 +5144,6 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			sub->related->related = NULL;
 		}
 
-		if ((sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) && ast_channel_hangupcause(sub->owner) == AST_CAUSE_ANSWERED_ELSEWHERE) {
-			transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
-		}
-
 		if (sub == l->activesub) {
 			l->activesub = NULL;
 			transmit_closereceivechannel(d, sub);
@@ -5750,7 +5152,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
 			transmit_clearpromptmessage(d, l->instance, sub->callid);
 			transmit_ringer_mode(d, SKINNY_RING_OFF);
-			transmit_definetimedate(d);
+			transmit_definetimedate(d); 
 			transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
 		} else {
 			transmit_stop_tone(d, l->instance, sub->callid);
@@ -5759,12 +5161,11 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		}
 
 		sub->cxmode = SKINNY_CX_RECVONLY;
+		destroy_rtp(sub);
 		if (sub->owner) {
 			if (sub->substate == SUBSTATE_OFFHOOK) {
 				sub->substate = SUBSTATE_ONHOOK;
-				skinny_unlocksub(sub);
 				ast_hangup(sub->owner);
-				return;
 			} else {
 				sub->substate = SUBSTATE_ONHOOK;
 				ast_queue_hangup(sub->owner);
@@ -5776,7 +5177,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_DIALING:
 		if (ast_strlen_zero(sub->exten) || !ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
 			ast_log(LOG_WARNING, "Exten (%s)@(%s) does not exist, unable to set substate DIALING on sub %u\n", sub->exten, ast_channel_context(c), sub->callid);
-			break;
+			return;
 		}
 
 		if (d->hookstate == SKINNY_ONHOOK) {
@@ -5789,8 +5190,8 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
 			transmit_stop_tone(d, l->instance, sub->callid);
 			transmit_clear_display_message(d, l->instance, sub->callid);
-			transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT, KEYMASK_ALL);
-			send_displaypromptstatus(d, "Dialing", "", 0, l->instance, sub->callid);
+			transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
+			transmit_displaypromptstatus(d, "Dialing", 0, l->instance, sub->callid);
 		}
 
 		if  (AST_LIST_FIRST(&l->sublines)) {
@@ -5808,9 +5209,9 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			ast_channel_exten_set(c, sub->exten);
 			ast_copy_string(l->lastnumberdialed, sub->exten, sizeof(l->lastnumberdialed));
 		}
-
+		
 		sub->substate = SUBSTATE_DIALING;
-
+	
 		if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
 			ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
 			ast_hangup(c);
@@ -5819,37 +5220,25 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_RINGOUT:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_RINGOUT from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
-			break;
+			return;
 		}
 		if (sub->substate != SUBSTATE_PROGRESS) {
 			transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
 		}
-
+	
 		if (!d->earlyrtp) {
 			transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
 		}
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
-		if (sub->related) {
-			transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUTWITHTRANS, KEYMASK_ALL);
-		} else {
-			transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT, KEYMASK_ALL);
-		}
-		transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
-		send_displaypromptstatus(d, OCTAL_RINGOUT, "", 0, l->instance, sub->callid);
+		transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
+		transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
 		send_callinfo(sub);
 		sub->substate = SUBSTATE_RINGOUT;
 		break;
 	case SUBSTATE_RINGIN:
-		connected_id = ast_channel_connected_effective_id(c);
-		if ((ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-			fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "Unknown");
-		} else {
-			fromnum = "Unknown";
-		}
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
-		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL);
-		send_displaypromptstatus(d, OCTAL_FROM, fromnum, 0, l->instance, sub->callid);
-		send_displayprinotify(d, OCTAL_FROM, fromnum, 10, 5);
+		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
+		transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
 		send_callinfo(sub);
 		transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
 		transmit_ringer_mode(d, SKINNY_RING_INSIDE);
@@ -5858,7 +5247,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		if (d->hookstate == SKINNY_ONHOOK) {
 			l->activesub = sub;
 		}
-
+	
 		if (sub->substate != SUBSTATE_RINGIN || sub->substate != SUBSTATE_CALLWAIT) {
 			ast_setstate(c, AST_STATE_RINGING);
 			ast_queue_control(c, AST_CONTROL_RINGING);
@@ -5868,12 +5257,12 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_CALLWAIT:
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_CALLWAIT);
-		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL);
-		send_displaypromptstatus(d, OCTAL_CALLWAITING, "", 0, l->instance, sub->callid);
+		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
+		transmit_displaypromptstatus(d, "Callwaiting", 0, l->instance, sub->callid);
 		send_callinfo(sub);
 		transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
 		transmit_start_tone(d, SKINNY_CALLWAITTONE, l->instance, sub->callid);
-
+	
 		ast_setstate(c, AST_STATE_RINGING);
 		ast_queue_control(c, AST_CONTROL_RINGING);
 		sub->substate = SUBSTATE_CALLWAIT;
@@ -5883,7 +5272,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
 		}
 		if (sub->substate == SUBSTATE_HOLD) {
-			ast_queue_unhold(sub->owner);
+			ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
 			transmit_connect(d, sub);
 		}
 		transmit_ringer_mode(d, SKINNY_RING_OFF);
@@ -5891,8 +5280,8 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		transmit_stop_tone(d, l->instance, sub->callid);
 		send_callinfo(sub);
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
-		send_displaypromptstatus(d, OCTAL_CONNECTED, "", 0, l->instance, sub->callid);
-		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED, KEYMASK_ALL);
+		transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
+		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
 		if (!sub->rtp) {
 			start_rtp(sub);
 		}
@@ -5906,7 +5295,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
 		}
 		if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
-			transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
+			transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
 		}
 		if (ast_channel_state(sub->owner) != AST_STATE_UP) {
 			ast_setstate(sub->owner, AST_STATE_UP);
@@ -5917,7 +5306,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_BUSY:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_BUSY from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
-			break;
+			return;
 		}
 
 		if (!d->earlyrtp) {
@@ -5925,13 +5314,13 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		}
 		send_callinfo(sub);
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_BUSY);
-		send_displaypromptstatus(d, OCTAL_BUSY, "", 0, l->instance, sub->callid);
+		transmit_displaypromptstatus(d, "Busy", 0, l->instance, sub->callid);
 		sub->substate = SUBSTATE_BUSY;
 		break;
 	case SUBSTATE_CONGESTION:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_CONGESTION from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
-			break;
+			return;
 		}
 
 		if (!d->earlyrtp) {
@@ -5939,13 +5328,13 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		}
 		send_callinfo(sub);
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_CONGESTION);
-		send_displaypromptstatus(d, "Congestion", "", 0, l->instance, sub->callid);
+		transmit_displaypromptstatus(d, "Congestion", 0, l->instance, sub->callid);
 		sub->substate = SUBSTATE_CONGESTION;
 		break;
 	case SUBSTATE_PROGRESS:
 		if (sub->substate != SUBSTATE_DIALING) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_PROGRESS from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
-			break;
+			return;
 		}
 
 		if (!d->earlyrtp) {
@@ -5953,15 +5342,17 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		}
 		send_callinfo(sub);
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
-		send_displaypromptstatus(d, "Call Progress", "", 0, l->instance, sub->callid);
+		transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
 		sub->substate = SUBSTATE_PROGRESS;
 		break;
 	case SUBSTATE_HOLD:
 		if (sub->substate != SUBSTATE_CONNECTED) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
-			break;
+			return;
 		}
-		ast_queue_hold(sub->owner, l->mohsuggest);
+		ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
+			S_OR(l->mohsuggest, NULL),
+			!ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
 
 		transmit_activatecallplane(d, l);
 		transmit_closereceivechannel(d, sub);
@@ -5969,13 +5360,12 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 
 		transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
 		transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK);
-		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD, KEYMASK_ALL);
+		transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
 		sub->substate = SUBSTATE_HOLD;
 		break;
 	default:
 		ast_log(LOG_WARNING, "Was asked to change to nonexistant substate %d on Sub-%u\n", state, sub->callid);
 	}
-	skinny_unlocksub(sub);
 }
 
 static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
@@ -5994,7 +5384,7 @@ static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
 
 	if (sub == l->activesub) {
 		d->hookstate = SKINNY_ONHOOK;
-		transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
+		transmit_speaker_mode(d, SKINNY_SPEAKEROFF); 
 		if (sub->related) {
 			activate_sub = sub->related;
 			setsubstate(sub, SUBSTATE_ONHOOK);
@@ -6037,6 +5427,8 @@ static void activatesub(struct skinny_subchannel *sub, int state)
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Activating, and deactivating sub %u\n",
 		sub->callid, l->activesub ? l->activesub->callid : 0);
 
+	ast_channel_lock(sub->owner);
+
 	if (sub == l->activesub) {
 		setsubstate(sub, state);
 	} else {
@@ -6050,26 +5442,32 @@ static void activatesub(struct skinny_subchannel *sub, int state)
 		l->activesub = sub;
 		setsubstate(sub, state);
 	}
+
+	ast_channel_unlock(sub->owner);
 }
 
 static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION])
 {
-	struct skinny_line *l = sub->line;
-	struct skinny_device *d = l->device;
+	if (sub->line->getforward) {
+		struct skinny_line *l = sub->line;
+		struct skinny_device *d = l->device;
 
-	if (sub->dialType == DIALTYPE_NORMAL) {
+		// FIXME: needs some love and remove sleeps
+		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Set callforward to %s\n", sub->callid, exten);
+		set_callforwards(l, sub->exten, l->getforward);
+		transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
+		transmit_lamp_indication(d, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
+		transmit_displaynotify(d, "CFwd enabled", 10);
+		transmit_cfwdstate(d, l);
+		ast_safe_sleep(sub->owner, 500);
+		ast_indicate(sub->owner, -1);
+		ast_safe_sleep(sub->owner, 1000);
+		l->getforward = 0;
+		dumpsub(sub, 0);
+	} else {
 		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Dial %s and Activate\n", sub->callid, exten);
 		ast_copy_string(sub->exten, exten, sizeof(sub->exten));
 		activatesub(sub, SUBSTATE_DIALING);
-	} else if (sub->dialType == DIALTYPE_CFWD) {
-		SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Set callforward(%d) to %s\n", sub->callid, sub->getforward, exten);
-		set_callforwards(l, sub->exten, sub->getforward);
-		dumpsub(sub, 1);
-		transmit_cfwdstate(d, l);
-		transmit_displaynotify(d, "CFwd enabled", 10);
-	} else if (sub->dialType == DIALTYPE_XFER) {
-		ast_copy_string(sub->exten, exten, sizeof(sub->exten));
-		skinny_transfer_blind(sub);
 	}
 }
 
@@ -6115,7 +5513,7 @@ static int handle_transfer_button(struct skinny_subchannel *sub)
 		if (!(sub->substate == SUBSTATE_HOLD)) {
 			setsubstate(sub, SUBSTATE_HOLD);
 		}
-		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		if (c) {
 			newsub = ast_channel_tech_pvt(c);
 			/* point the sub and newsub at each other so we know they are related */
@@ -6128,81 +5526,74 @@ static int handle_transfer_button(struct skinny_subchannel *sub)
 		}
 	} else {
 		/* We already have a related sub so we can either complete XFER or go into BLINDXFER (or cancel BLINDXFER */
-		if (sub->substate == SUBSTATE_OFFHOOK) {
-			if (sub->dialType == DIALTYPE_XFER) {
-				sub->dialType = DIALTYPE_NORMAL;
+		if (sub->blindxfer) {
+			/* toggle blindxfer off */
+			sub->blindxfer = 0;
+			sub->related->blindxfer = 0;
+			/* we really need some indications */
+		} else {
+			/* We were doing attended transfer */
+			if (ast_channel_state(sub->owner) == AST_STATE_DOWN || ast_channel_state(sub->related->owner) == AST_STATE_DOWN) {
+				/* one of the subs so we cant transfer yet, toggle blindxfer on */
+				sub->blindxfer = 1;
+				sub->related->blindxfer = 1;
 			} else {
-				sub->dialType = DIALTYPE_XFER;
+				/* big assumption we have two channels, lets transfer */
+				skinny_transfer(sub);
 			}
-		} else {
-			skinny_transfer_attended(sub);
 		}
 	}
 	return 0;
 }
 
-static void handle_callforward_button(struct skinny_line *l, struct skinny_subchannel *sub, int cfwdtype)
+static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
 {
+	struct skinny_line *l = sub->line;
 	struct skinny_device *d = l->device;
-	struct ast_channel *c;
+	struct ast_channel *c = sub->owner;
 
 	if (!d->session) {
 		ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
-		return;
+		return 0;
+	}
+
+	if (d->hookstate == SKINNY_ONHOOK) {
+		d->hookstate = SKINNY_OFFHOOK;
+		transmit_speaker_mode(d, SKINNY_SPEAKERON);
+		transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
+		transmit_activatecallplane(d, l);
 	}
+	transmit_clear_display_message(d, l->instance, sub->callid);
 
-	if (!sub && (l->cfwdtype & cfwdtype)) {
+	if (l->cfwdtype & cfwdtype) {
 		set_callforwards(l, NULL, cfwdtype);
-		if (sub) {
-			dumpsub(sub, 1);
+		ast_safe_sleep(c, 500);
+		transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
+		transmit_closereceivechannel(d, sub);
+		transmit_stopmediatransmission(d, sub);
+		transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
+		transmit_clearpromptmessage(d, l->instance, sub->callid);
+		transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
+		transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
+		transmit_activatecallplane(d, l);
+		transmit_displaynotify(d, "CFwd disabled", 10);
+		if (sub->owner && ast_channel_state(sub->owner) != AST_STATE_UP) {
+			ast_indicate(c, -1);
+			ast_hangup(c);
 		}
 		transmit_cfwdstate(d, l);
-		transmit_displaynotify(d, "CFwd disabled", 10);
 	} else {
-		if (!sub || !sub->owner) {
-			if (!(c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING))) {
-				ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
-				return;
-			}
-			sub = ast_channel_tech_pvt(c);
-			l->activesub = sub;
-			setsubstate(sub, SUBSTATE_OFFHOOK);
-		}
-		sub->getforward |= cfwdtype;
-		sub->dialType = DIALTYPE_CFWD;
+		l->getforward = cfwdtype;
+		setsubstate(sub, SUBSTATE_OFFHOOK);
 	}
+	return 0;
 }
-
 static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
 {
 	/* no response necessary */
 	return 1;
 }
 
-static void handle_keepalive_message(struct skinny_req *req, struct skinnysession *s)
-{
-	if (ast_sched_del(sched, s->keepalive_timeout_sched)) {
-		return;
-	}
-
-#ifdef AST_DEVMODE
-	{
-		long keepalive_diff;
-		keepalive_diff = (long) ast_tvdiff_ms(ast_tvnow(), ast_tvadd(s->last_keepalive, ast_tv(keep_alive, 0)));
-		SKINNY_DEBUG(DEBUG_PACKET|DEBUG_KEEPALIVE, 3,
-			"Keep_alive %d on %s, %.3fs %s\n",
-				++s->keepalive_count,
-				(s->device ? s->device->name : "unregistered"),
-				(float) labs(keepalive_diff) / 1000,
-				(keepalive_diff > 0 ? "late" : "early"));
-	}
-#endif
-
-	s->keepalive_timeout_sched = ast_sched_add(sched, keep_alive*3000, skinny_nokeepalive_cb, s);
-	s->last_keepalive = ast_tvnow();
-	transmit_keepaliveack(s);
-}
-
 static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
 {
 	struct skinny_subchannel *sub = NULL;
@@ -6249,19 +5640,19 @@ static int handle_keypad_button_message(struct skinny_req *req, struct skinnyses
 	}
 
 	if ((sub->owner && ast_channel_state(sub->owner) <  AST_STATE_UP)) {
-		if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) {
+		if (sub->dialer_sched &&	!skinny_sched_del(sub->dialer_sched, sub)) {
 			SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Got a digit and not timed out, so try dialing\n", sub->callid);
-			sub->dialer_sched = 0;
+			sub->dialer_sched = -1;
 			len = strlen(sub->exten);
 			if (len == 0) {
 				transmit_stop_tone(d, l->instance, sub->callid);
-				transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD, KEYMASK_ALL&~KEYMASK_FORCEDIAL);
+				transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD);
 			}
-			if (len < sizeof(sub->exten) - 1 && dgt != immed_dialchar) {
+			if (len < sizeof(sub->exten) - 1) {
 				sub->exten[len] = dgt;
 				sub->exten[len + 1] = '\0';
 			}
-			if (len == sizeof(sub->exten) - 1 || dgt == immed_dialchar) {
+			if (len == sizeof(sub->exten) - 1) {
 				skinny_dialer(sub, 1);
 			} else {
 				skinny_dialer(sub, 0);
@@ -6308,14 +5699,12 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 	struct ast_channel *c;
 	int event;
 	int instance;
-#ifdef AST_DEVMODE
 	int callreference;
-	/* This is only used in AST_DEVMODE, as an argument to SKINNY_DEBUG */
-	callreference = letohl(req->data.stimulus.callreference);
-#endif
+	/*int res = 0;*/
 
 	event = letohl(req->data.stimulus.stimulus);
 	instance = letohl(req->data.stimulus.stimulusInstance);
+	callreference = letohl(req->data.stimulus.callreference);
 
 	/*  Note that this call should be using the passed in instance and callreference */
 	sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
@@ -6340,7 +5729,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 			break;
 		}
 
-		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		if (!c) {
 			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
 		} else {
@@ -6361,7 +5750,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 		}
 
 		if (!sub || !sub->owner)
-			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		else
 			c = sub->owner;
 
@@ -6396,16 +5785,16 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 			d->name, instance, callreference);
 
 		if (!sub || !sub->owner) {
-			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		} else {
 			c = sub->owner;
 		}
-
+		
 		if (!c) {
 			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
 			break;
 		}
-
+		
 		sub = ast_channel_tech_pvt(c);
 		if (sub->substate == SUBSTATE_UNSET || sub->substate == SUBSTATE_OFFHOOK){
 			dialandactivatesub(sub, l->vmexten);
@@ -6413,35 +5802,25 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 		break;
 	case STIMULUS_CALLPARK:
 		{
-		char extout[AST_MAX_EXTENSION];
+		int extout;
 		char message[32];
-		RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_CALLPARK from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 
-		if (!ast_parking_provider_registered()) {
-			transmit_displaynotify(d, "Call Park not available", 10);
-			break;
-		}
-
-		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)) {
-			c = sub->owner;
-			ast_channel_lock(c);
-			bridge_channel = ast_channel_get_bridge_channel(c);
-			ast_channel_unlock(c);
-
-			if (!bridge_channel) {
-				transmit_displaynotify(d, "Call Park failed", 10);
-				break;
-			}
-
-			if (!ast_parking_park_call(bridge_channel, extout, sizeof(extout))) {
-				snprintf(message, sizeof(message), "Call Parked at: %s", extout);
-				transmit_displaynotify(d, message, 10);
-				break;
-			}
-			transmit_displaynotify(d, "Call Park failed", 10);
-		} else {
+		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)){
+			c = sub->owner;
+			if (ast_bridged_channel(c)) {
+				if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
+					snprintf(message, sizeof(message), "Call Parked at: %d", extout);
+					transmit_displaynotify(d, message, 10);
+				} else {
+					transmit_displaynotify(d, "Call Park failed", 10);
+				}
+			} else {
+				transmit_displaynotify(d, "Call Park not available", 10);
+			}
+		} else {
 			transmit_displaynotify(d, "Call Park not available", 10);
 		}
 		break;
@@ -6466,17 +5845,55 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 	case STIMULUS_FORWARDALL:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDALL from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_ALL);
+
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = ast_channel_tech_pvt(c);
+			handle_callforward_button(sub, SKINNY_CFWD_ALL);
+		}
 		break;
 	case STIMULUS_FORWARDBUSY:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDBUSY from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_BUSY);
+
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = ast_channel_tech_pvt(c);
+			handle_callforward_button(sub, SKINNY_CFWD_BUSY);
+		}
 		break;
 	case STIMULUS_FORWARDNOANSWER:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDNOANSWER from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_NOANSWER);
+
+#if 0 /* Not sure how to handle this yet */
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = c->tech_pvt;
+			handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
+		}
+#endif
 		break;
 	case STIMULUS_DISPLAY:
 		/* Not sure what this is */
@@ -6508,7 +5925,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
 			if (sub && sub->owner) {
 				ast_debug(1, "Current subchannel [%s] already has owner\n", ast_channel_name(sub->owner));
 			} else {
-				c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+				c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 				if (c) {
 					setsubstate(ast_channel_tech_pvt(c), SUBSTATE_OFFHOOK);
 				} else {
@@ -6579,7 +5996,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
 		if (sub && sub->owner) {
 			ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
 		} else {
-			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 			if (c) {
 				setsubstate(ast_channel_tech_pvt(c), SUBSTATE_OFFHOOK);
 			} else {
@@ -6628,13 +6045,13 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s
 		handle_transfer_button(sub);
 		return 0;
 	}
-
+	
 	ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
-
+	
 	dumpsub(sub, 0);
 
 	d->hookstate = SKINNY_ONHOOK;
-
+	
 	/* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
 	transmit_definetimedate(d);
 
@@ -6646,12 +6063,8 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny
 	struct skinny_device *d = s->device;
 	struct skinny_line *l;
 	uint32_t count = 0;
-	struct ast_format_cap *codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *codecs = ast_format_cap_alloc();
 	int i;
-#ifdef AST_DEVMODE
-	struct ast_str *codec_buf = ast_str_alloca(64);
-#endif
-	
 
 	if (!codecs) {
 		return 0;
@@ -6664,23 +6077,23 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny
 	}
 
 	for (i = 0; i < count; i++) {
-		struct ast_format *acodec;
+		struct ast_format acodec;
 		int scodec = 0;
 		scodec = letohl(req->data.caps.caps[i].codec);
-		acodec = codec_skinny2ast(scodec);
-		SKINNY_DEBUG(DEBUG_AUDIO, 4, "Adding codec capability %s (%d)\n", ast_format_get_name(acodec), scodec);
-		ast_format_cap_append(codecs, acodec, 0);
+		codec_skinny2ast(scodec, &acodec);
+		SKINNY_DEBUG(DEBUG_AUDIO, 4, "Adding codec capability %s (%d)\n", ast_getformatname(&acodec), scodec);
+		ast_format_cap_add(codecs, &acodec);
 	}
 
-	ast_format_cap_get_compatible(d->confcap, codecs, d->cap);
-	SKINNY_DEBUG(DEBUG_AUDIO, 4, "Device capability set to '%s'\n", ast_format_cap_get_names(d->cap, &codec_buf));
+	ast_format_cap_joint_copy(d->confcap, codecs, d->cap);
+	SKINNY_DEBUG(DEBUG_AUDIO, 4, "Device capability set to '%s'\n", ast_getformatname_multiple(dbgreg_buf, sizeof(dbgreg_buf), d->cap));
 	AST_LIST_TRAVERSE(&d->lines, l, list) {
 		ast_mutex_lock(&l->lock);
-		ast_format_cap_get_compatible(l->confcap, d->cap, l->cap);
+		ast_format_cap_joint_copy(l->confcap, d->cap, l->cap);
 		ast_mutex_unlock(&l->lock);
 	}
 
-	ao2_ref(codecs, -1);
+	codecs = ast_format_cap_destroy(codecs);
 	return 1;
 }
 
@@ -6689,12 +6102,11 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
 	struct skinny_device *d = s->device;
 	struct skinny_line *l;
 	int i;
+
 	struct skinny_speeddial *sd;
-	struct skinny_serviceurl *surl;
 	struct button_definition_template btn[42];
 	int lineInstance = 1;
 	int speeddialInstance = 1;
-	int serviceurlInstance = 1;
 	int buttonCount = 0;
 
 	if (!(req = req_alloc(sizeof(struct button_template_res_message), BUTTON_TEMPLATE_RES_MESSAGE)))
@@ -6777,20 +6189,6 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
 						}
 					}
 				}
-
-				if (!btnSet) {
-					AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
-						if (surl->instance == serviceurlInstance) {
-							SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_SERVICEURL, serviceurlInstance);
-							req->data.buttontemplate.definition[i].buttonDefinition = BT_SERVICEURL;
-							req->data.buttontemplate.definition[i].instanceNumber = serviceurlInstance;
-							serviceurlInstance++;
-							buttonCount++;
-							btnSet = 1;
-							break;
-						}
-					}
-				}
 				break;
 			case BT_LINE:
 				req->data.buttontemplate.definition[i].buttonDefinition = htolel(BT_NONE);
@@ -6851,16 +6249,16 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc
 	struct skinny_device *d = s->device;
 	struct skinny_line *l;
 	struct skinny_subchannel *sub;
+	struct ast_format_list fmt;
 	struct sockaddr_in sin = { 0, };
 	struct sockaddr_in us = { 0, };
 	struct ast_sockaddr sin_tmp;
 	struct ast_sockaddr us_tmp;
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 	uint32_t addr;
 	int port;
 	int status;
 	int callid;
-	unsigned int framing;
 
 	status = (d->protocolversion<17) ? letohl(req->data.openreceivechannelack_ip4.status) : letohl(req->data.openreceivechannelack_ip6.status);
 
@@ -6911,14 +6309,12 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc
 	SKINNY_DEBUG(DEBUG_PACKET, 4, "device ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 	SKINNY_DEBUG(DEBUG_PACKET, 4, "asterisk ipaddr = %s:%d\n", ast_inet_ntoa(us.sin_addr), ntohs(us.sin_port));
 
-	tmpfmt = ast_format_cap_get_format(l->cap, 0);
-	framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
-
-	SKINNY_DEBUG(DEBUG_PACKET, 4, "Setting payloadType to '%s' (%u ms)\n", ast_format_get_name(tmpfmt), framing);
+	ast_best_codec(l->cap, &tmpfmt);
+	fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt);
 
-	transmit_startmediatransmission(d, sub, us, tmpfmt, framing);
+	SKINNY_DEBUG(DEBUG_PACKET, 4, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms);
 
-	ao2_ref(tmpfmt, -1);
+	transmit_startmediatransmission(d, sub, us, fmt);
 
 	return 1;
 }
@@ -6941,7 +6337,7 @@ static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysessi
 		l = sub->line;
 	}
 
-	c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+	c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 
 	if(!c) {
 		ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
@@ -6951,10 +6347,11 @@ static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysessi
 		sub = ast_channel_tech_pvt(c);
 		dialandactivatesub(sub, req->data.enbloccallmessage.calledParty);
 	}
-
+	
 	return 1;
 }
 
+
 static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
 {
 	struct skinny_device *d = s->device;
@@ -7002,7 +6399,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		}
 
 		if (!sub || !sub->owner) {
-			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		} else {
 			c = sub->owner;
 		}
@@ -7019,7 +6416,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 			d->name, instance, callreference);
 
 		/* New Call ALWAYS gets a new sub-channel */
-		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+		c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 		sub = ast_channel_tech_pvt(c);
 
 		if (!c) {
@@ -7071,30 +6468,71 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 	case SOFTKEY_CFWDALL:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDALL from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_ALL);
+
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = ast_channel_tech_pvt(c);
+			l->activesub = sub;
+			handle_callforward_button(sub, SKINNY_CFWD_ALL);
+		}
 		break;
 	case SOFTKEY_CFWDBUSY:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDBUSY from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_BUSY);
+
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = ast_channel_tech_pvt(c);
+			l->activesub = sub;
+			handle_callforward_button(sub, SKINNY_CFWD_BUSY);
+		}
 		break;
 	case SOFTKEY_CFWDNOANSWER:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDNOANSWER from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		handle_callforward_button(l, sub, SKINNY_CFWD_NOANSWER);
+
+#if 0 /* Not sure how to handle this yet */
+		if (!sub || !sub->owner) {
+			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
+		} else {
+			c = sub->owner;
+		}
+
+		if (!c) {
+			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+		} else {
+			sub = c->tech_pvt;
+			l->activesub = sub;
+			handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
+		}
+#endif
 		break;
 	case SOFTKEY_BKSPC:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_BKSPC from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 		if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) {
 			size_t len;
-			sub->dialer_sched = 0;
+			sub->dialer_sched = -1;
 			len = strlen(sub->exten);
 			if (len > 0) {
 				sub->exten[len-1] = '\0';
 				if (len == 1) {
 					transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
-					transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL);
+					transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
 				}
 				transmit_backspace(d, l->instance, sub->callid);
 			}
@@ -7105,6 +6543,13 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_ENDCALL from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 
+		if (l->transfer && sub && sub->xferor && ast_channel_state(sub->owner) >= AST_STATE_RING) {
+			/* We're allowed to transfer, we have two active calls and
+			    we made at least one of the calls.  Let's try and transfer */
+			handle_transfer_button(sub);
+			return 0;
+		}
+	
 		ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
 		if (sub) {
@@ -7117,7 +6562,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		}
 
 		d->hookstate = SKINNY_ONHOOK;
-
+	
 		/* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
 		transmit_definetimedate(d);
 
@@ -7131,7 +6576,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		} else { /* No sub, maybe an inactive SLA call */
 			struct skinny_subline *subline;
 			subline = find_subline_by_callid(d, callreference);
-			c = skinny_new(l, subline, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, subline, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 			if (!c) {
 				ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
 			} else {
@@ -7166,34 +6611,24 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		break;
 	case SOFTKEY_PARK:
 		{
-		char extout[AST_MAX_EXTENSION];
+		int extout;
 		char message[32];
-		RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_PARK from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 
-		if (!ast_parking_provider_registered()) {
-			transmit_displaynotify(d, "Call Park not available", 10);
-			break;
-		}
-
-		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)) {
+		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)){
 			c = sub->owner;
-			ast_channel_lock(c);
-			bridge_channel = ast_channel_get_bridge_channel(c);
-			ast_channel_unlock(c);
-
-			if (!bridge_channel) {
-				transmit_displaynotify(d, "Call Park failed", 10);
-				break;
-			}
-
-			if (!ast_parking_park_call(bridge_channel, extout, sizeof(extout))) {
-				snprintf(message, sizeof(message), "Call Parked at: %s", extout);
-				transmit_displaynotify(d, message, 10);
-				break;
+			if (ast_bridged_channel(c)) {
+				if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
+					snprintf(message, sizeof(message), "Call Parked at: %d", extout);
+					transmit_displaynotify(d, message, 10);
+				} else {
+					transmit_displaynotify(d, "Call Park failed", 10);
+				}
+			} else {
+				transmit_displaynotify(d, "Call Park not available", 10);
 			}
-			transmit_displaynotify(d, "Call Park failed", 10);
 		} else {
 			transmit_displaynotify(d, "Call Park not available", 10);
 		}
@@ -7206,7 +6641,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 		{
 			struct skinny_subline *subline;
 			subline = find_subline_by_callid(d, callreference);
-			c = skinny_new(l, subline, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
+			c = skinny_new(l, subline, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
 			if (!c) {
 				ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
 			} else {
@@ -7227,33 +6662,6 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
 	case SOFTKEY_GPICKUP:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_GPICKUP from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
-		if (!sub || !sub->owner) {
-			c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_INCOMING);
-		} else {
-			c = sub->owner;
-		}
-
-		if (!c) {
-			ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
-		} else {
-			ast_channel_ref(c);
-			sub = ast_channel_tech_pvt(c);
-			ast_pickup_call(c);
-			if (sub->owner == c) {
-				ast_channel_unref(c);
-				dumpsub(sub, 1);
-			} else {
-				ast_hangup(c);
-				setsubstate(sub, SUBSTATE_CONNECTED);
-				ast_channel_unref(c);
-			}
-		}
-		break;
-	case SOFTKEY_FORCEDIAL:
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_FORCEDIAL from %s, inst %d, callref %d\n",
-			d->name, instance, callreference);
-		skinny_dialer(sub, 1);
-
 		break;
 	default:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_UNKNOWN(%d) from %s, inst %d, callref %d\n",
@@ -7270,34 +6678,30 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
 	struct skinny_speeddial *sd;
 	struct skinny_device *d = s->device;
 
-	if (!d && !(letohl(req->e) == REGISTER_MESSAGE || letohl(req->e) == ALARM_MESSAGE || letohl(req->e) == KEEP_ALIVE_MESSAGE)) {
-		ast_log(LOG_WARNING, "Client sent message #%u without first registering.\n", req->e);
+	if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
+		ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
+		ast_free(req);
 		return 0;
 	}
 
 	switch(letohl(req->e)) {
 	case KEEP_ALIVE_MESSAGE:
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEEP_ALIVE_MESSAGE from %s\n", (d ? d->name : "unregistered"));
-		handle_keepalive_message(req, s);
+		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEEP_ALIVE_MESSAGE from %s\n", d->name);
+		transmit_keepaliveack(s->device);
 		break;
 	case REGISTER_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_MESSAGE from %s, name %s, type %u, protovers %d\n",
 			d->name, req->data.reg.name, letohl(req->data.reg.type), letohl(req->data.reg.protocolVersion));
-		res = skinny_register(req, s);
-		if (!res) {
-			sleep(2);
-			res = skinny_register(req, s);
-		}
-		if (res != 1) {
+		if (skinny_register(req, s)) {
+			ast_atomic_fetchadd_int(&unauth_sessions, -1);
+			ast_verb(3, "Device '%s' successfully registered (protoVers %d)\n", s->device->name, s->device->protocolversion);
+			transmit_registerack(s->device);
+			transmit_capabilitiesreq(s->device);
+		} else {
 			transmit_registerrej(s);
+			ast_free(req);
 			return -1;
 		}
-		ast_atomic_fetchadd_int(&unauth_sessions, -1);
-		ast_verb(3, "Device '%s' successfully registered (protoVers %d)\n", s->device->name, s->device->protocolversion);
-		transmit_registerack(s->device);
-		transmit_capabilitiesreq(s->device);
-		res = 0;
-		break;
 	case IP_PORT_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received IP_PORT_MESSAGE from %s\n", d->name);
 		res = handle_ip_port_message(req, s);
@@ -7371,7 +6775,7 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
 	case SOFT_KEY_SET_REQ_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_SET_REQ_MESSAGE from %s\n", d->name);
 		transmit_softkeysetres(d);
-		transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK, KEYMASK_ALL);
+		transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
 		break;
 	case SOFT_KEY_EVENT_MESSAGE:
 		/* SKINNY_PACKETDEBUG handled in handle_soft_key_event_message */
@@ -7379,8 +6783,7 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
 		break;
 	case UNREGISTER_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNREGISTER_MESSAGE from %s\n", d->name);
-		ast_log(LOG_NOTICE, "Received UNREGISTER_MESSAGE from %s\n", d->name);
-		end_session(s);
+		res = skinny_unregister(req, s);
 		break;
 	case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_TEMPLATE_REQ_MESSAGE from %s\n", d->name);
@@ -7394,233 +6797,201 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
 		/* XXX I have no clue what this is for, but my phone was sending it, so... */
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_AVAILABLE_LINES_MESSAGE from %s\n", d->name);
 		break;
-	case SERVICEURL_STATREQ_MESSAGE:
-		SKINNY_DEBUG(DEBUG_PACKET, 3, "SERVICEURL_STATREQ_MESSAGE from %s\n", d->name);
-		transmit_serviceurlstat(d, letohl(req->data.serviceurlmessage.instance));
-		break;
 	default:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNKNOWN_MESSAGE(%x) from %s\n", (unsigned)letohl(req->e), d->name);
 		break;
 	}
+	if (res >= 0 && req)
+		ast_free(req);
 	return res;
 }
 
 static void destroy_session(struct skinnysession *s)
 {
-	ast_mutex_lock(&s->lock);
-	if (s->fd > -1) {
-		close(s->fd);
-	}
+	struct skinnysession *cur;
+	AST_LIST_LOCK(&sessions);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, cur, list) {
+		if (cur == s) {
+			AST_LIST_REMOVE_CURRENT(list);
+			if (s->fd > -1) {
+				close(s->fd);
+			}
 
-	if (s->device) {
-		s->device->session = NULL;
-	} else {
-		ast_atomic_fetchadd_int(&unauth_sessions, -1);
-	}
-	ast_mutex_unlock(&s->lock);
-	ast_mutex_destroy(&s->lock);
-	ast_free(s);
-}
+			if (s->device) {
+				s->device->session = NULL;
+			} else {
+				ast_atomic_fetchadd_int(&unauth_sessions, -1);
+			}
 
-static int skinny_noauth_cb(const void *data)
-{
-	struct skinnysession *s = (struct skinnysession *)data;
-	ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds (SCHED %d)\n", auth_timeout, s->auth_timeout_sched);
-	s->auth_timeout_sched = 0;
-	end_session(s);
-	return 0;
-}
+			ast_mutex_destroy(&s->lock);
 
-static int skinny_nokeepalive_cb(const void *data)
-{
-	struct skinnysession *s = (struct skinnysession *)data;
-	ast_log(LOG_WARNING, "Skinny Client failed to send keepalive in last %d seconds (SCHED %d)\n", keep_alive*3, s->keepalive_timeout_sched);
-	s->keepalive_timeout_sched = 0;
-	end_session(s);
-	return 0;
+			ast_free(s);
+
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+	AST_LIST_UNLOCK(&sessions);
 }
 
-static void skinny_session_cleanup(void *data)
+static int get_input(struct skinnysession *s)
 {
-	struct skinnysession *s = (struct skinnysession *)data;
-	struct skinny_device *d = s->device;
-	struct skinny_line *l;
-	struct skinny_speeddial *sd;
+	int res;
+	int dlen = 0;
+	int timeout = keep_alive * 1100;
+	time_t now;
+	int *bufaddr;
+	struct pollfd fds[1];
 
-	ast_log(LOG_NOTICE, "Ending Skinny session from %s at %s\n", d ? d->name : "unknown", ast_inet_ntoa(s->sin.sin_addr));
+	if (!s->device) {
+		if(time(&now) == -1) {
+			ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
+			return -1;
+		}
 
-	if (s->lockstate) {
-		ast_mutex_unlock(&s->lock);
+		timeout = (auth_timeout - (now - s->start)) * 1000;
+		if (timeout < 0) {
+			/* we have timed out */
+			ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
+			return -1;
+		}
 	}
 
-	if (s->auth_timeout_sched && !ast_sched_del(sched, s->auth_timeout_sched)) {
-		s->auth_timeout_sched = 0;
-	}
-	if (s->keepalive_timeout_sched && !ast_sched_del(sched, s->keepalive_timeout_sched)) {
-		s->keepalive_timeout_sched = 0;
+	fds[0].fd = s->fd;
+	fds[0].events = POLLIN;
+	fds[0].revents = 0;
+	res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
+						 /* we add 10% to the keep_alive to deal */
+						 /* with network delays, etc */
+	if (res < 0) {
+		if (errno != EINTR) {
+			ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
+			return res;
+		}
+	} else if (res == 0) {
+		if (s->device) {
+			ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
+		} else {
+			ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
+		}
+		skinny_unregister(NULL, s);
+		return -1;
 	}
 
-	if (d) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-		d->session = NULL;
+	if (fds[0].revents) {
+		ast_mutex_lock(&s->lock);
+		memset(s->inbuf, 0, sizeof(s->inbuf));
+		res = read(s->fd, s->inbuf, 4);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
 
-		AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
-			if (sd->stateid > -1)
-				ast_extension_state_del(sd->stateid, NULL);
-		}
-		AST_LIST_TRAVERSE(&d->lines, l, list) {
-			if (l->device != d) {
-				continue;
+			ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
+
+			skinny_unregister(NULL, s);
+			ast_mutex_unlock(&s->lock);
+			return res;
+		} else if (res != 4) {
+			ast_log(LOG_WARNING, "Skinny Client sent less data than expected.  Expected 4 but got %d.\n", res);
+			ast_mutex_unlock(&s->lock);
+
+			if (res == 0) {
+				ast_log(LOG_WARNING, "Skinny Client was lost, unregistering\n");
+				skinny_unregister(NULL, s);
 			}
-			ast_format_cap_remove_by_type(l->cap, AST_MEDIA_TYPE_UNKNOWN);
-			ast_format_cap_update_by_allow_disallow(l->cap, "all", 0);
-			l->instance = 0;
-			unregister_exten(l);
-			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
+
+			return -1;
 		}
-		ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_OFFLINE);
-		blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
-		ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
-	}
 
-	AST_LIST_LOCK(&sessions);
-	AST_LIST_REMOVE(&sessions, s, list);
-	AST_LIST_UNLOCK(&sessions);
+		bufaddr = (int *)s->inbuf;
+		dlen = letohl(*bufaddr);
+		if (dlen < 4) {
+			ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
+			ast_mutex_unlock(&s->lock);
+			return -1;
+		}
+		if (dlen+8 > sizeof(s->inbuf)) {
+			ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET);
+			dlen = sizeof(s->inbuf) - 8;
+		}
+		*bufaddr = htolel(dlen);
 
-	destroy_session(s);
+		res = read(s->fd, s->inbuf+4, dlen+4);
+		ast_mutex_unlock(&s->lock);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
+			return res;
+		} else if (res != (dlen+4)) {
+			ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
+			return -1;
+		}
+		return res;
+	}
+	return 0;
 }
 
-static void *skinny_session(void *data)
+static struct skinny_req *skinny_req_parse(struct skinnysession *s)
 {
-	int res;
-	int bytesread;
-	struct skinny_req *req = NULL;
-	struct skinnysession *s = data;
+	struct skinny_req *req;
+	int *bufaddr;
 
-	int dlen = 0;
-	struct pollfd fds[1];
+	if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
+		return NULL;
 
-	if (!s) {
-		ast_log(LOG_WARNING, "Bad Skinny Session\n");
-		return 0;
-	}
+	ast_mutex_lock(&s->lock);
+	memcpy(req, s->inbuf, skinny_header_size);
+	bufaddr = (int *)(s->inbuf);
+	memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*bufaddr)-4);
 
-	ast_log(LOG_NOTICE, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
+	ast_mutex_unlock(&s->lock);
 
-	pthread_cleanup_push(skinny_session_cleanup, s);
+	if (letohl(req->e) < 0) {
+		ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
+		ast_free(req);
+		return NULL;
+	}
 
-	s->start = ast_tvnow();
-	s->last_keepalive = ast_tvnow();
-	s->keepalive_count = 0;
-	s->lockstate = 0;
+	return req;
+}
 
-	AST_LIST_LOCK(&sessions);
-	AST_LIST_INSERT_HEAD(&sessions, s, list);
-	AST_LIST_UNLOCK(&sessions);
+static void *skinny_session(void *data)
+{
+	int res;
+	struct skinny_req *req;
+	struct skinnysession *s = data;
 
-	s->auth_timeout_sched = ast_sched_add(sched, auth_timeout*1000, skinny_noauth_cb, s);
-	s->keepalive_timeout_sched = ast_sched_add(sched, keep_alive*3000, skinny_nokeepalive_cb, s);
+	ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
 
 	for (;;) {
-
-		fds[0].fd = s->fd;
-		fds[0].events = POLLIN;
-		fds[0].revents = 0;
-		res = ast_poll(fds, 1, -1); /* block */
+		res = get_input(s);
 		if (res < 0) {
-			if (errno != EINTR) {
-				ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
-				ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
-				break;
-			}
+			ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
+			destroy_session(s);
+			return NULL;
 		}
 
-		if (fds[0].revents) {
-
-			if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) {
-				ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n");
-				break;
+		if (res > 0)
+		{
+			if (!(req = skinny_req_parse(s))) {
+				ast_verb(3, "Ending Skinny session from %s (failed parse)\n", ast_inet_ntoa(s->sin.sin_addr));
+				destroy_session(s);
+				return NULL;
 			}
 
-			ast_mutex_lock(&s->lock);
-			s->lockstate = 1;
-
-			if ((res = read(s->fd, req, skinny_header_size)) != skinny_header_size) {
-				if (res < 0) {
-					ast_log(LOG_WARNING, "Header read() returned error: %s\n", strerror(errno));
-				} else {
-					ast_log(LOG_WARNING, "Unable to read header. Only found %d bytes.\n", res);
-				}
-				break;
+			res = handle_message(req, s);
+			if (res < 0) {
+				ast_verb(3, "Ending Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
+				destroy_session(s);
+				return NULL;
 			}
+		}
+	}
+	ast_debug(3, "Skinny Session returned: %s\n", strerror(errno));
 
-			if (letohl(req->e) < 0) {
-				ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
-				break;
-			}
+	if (s)
+		destroy_session(s);
 
-			dlen = letohl(req->len) - 4;
-			if (dlen < 0) {
-				ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
-				break;
-			}
-			if (dlen > (SKINNY_MAX_PACKET - skinny_header_size)) {
-				ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET);
-				break;
-			}
-
-			bytesread = 0;
-			while (1) {
-				if ((res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread)) < 0) {
-					ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno));
-					break;
-				}
-				bytesread += res;
-				if (bytesread >= dlen) {
-					if (res < bytesread) {
-						ast_log(LOG_WARNING, "Rest of partial data received.\n");
-					}
-					if (bytesread > dlen) {
-						ast_log(LOG_WARNING, "Client sent wrong amount of data (%d), expected (%d).\n", bytesread, dlen);
-						res = -1;
-					}
-					break;
-				}
-
-				ast_log(LOG_WARNING, "Partial data received, waiting (%d bytes read of %d)\n", bytesread, dlen);
-				if (sched_yield() < 0) {
-					ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno));
-					res = -1;
-					break;
-				}
-			}
-
-			s->lockstate = 0;
-			ast_mutex_unlock(&s->lock);
-			if (res < 0) {
-				break;
-			}
-
-			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-			res = handle_message(req, s);
-			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
-		}
-
-		if (req) {
-			ast_free(req);
-			req = NULL;
-		}
-	}
-
-	ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
-	if (req) {
-		ast_free(req);
-	}
-
-	pthread_cleanup_pop(1);
-
-	return 0;
-}
+	return 0;
+}
 
 static void *accept_thread(void *ignore)
 {
@@ -7657,10 +7028,20 @@ static void *accept_thread(void *ignore)
 			continue;
 		}
 
-		ast_mutex_init(&s->lock);
 		memcpy(&s->sin, &sin, sizeof(sin));
+		ast_mutex_init(&s->lock);
 		s->fd = as;
 
+		if(time(&s->start) == -1) {
+			ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
+			destroy_session(s);
+			continue;
+		}
+
+		AST_LIST_LOCK(&sessions);
+		AST_LIST_INSERT_HEAD(&sessions, s, list);
+		AST_LIST_UNLOCK(&sessions);
+
 		if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
 			destroy_session(s);
 		}
@@ -7682,16 +7063,15 @@ static int skinny_devicestate(const char *data)
 	return get_devicestate(l);
 }
 
-static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause)
+static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause)
 {
 	struct skinny_line *l;
 	struct skinny_subline *subline = NULL;
 	struct ast_channel *tmpc = NULL;
 	char tmp[256];
 
-	if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
+	if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) {
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 		return NULL;
 	}
 
@@ -7710,7 +7090,7 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca
 		l = subline->line;
 	}
 	ast_verb(3, "skinny_request(%s)\n", tmp);
-	tmpc = skinny_new(l, subline, AST_STATE_DOWN, assignedids, requestor, SKINNY_INCOMING);
+	tmpc = skinny_new(l, subline, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, SKINNY_INCOMING);
 	if (!tmpc) {
 		ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
 	} else if (subline) {
@@ -7724,46 +7104,45 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca
 	return tmpc;
 }
 
-#define TYPE_GENERAL	1
-#define TYPE_DEF_DEVICE 2
-#define TYPE_DEF_LINE	4
-#define TYPE_DEVICE	8
-#define TYPE_LINE	16
-
-#define CLINE_OPTS	((struct skinny_line_options *)item)
-#define CLINE		((struct skinny_line *)item)
-#define CDEV_OPTS	((struct skinny_device_options *)item)
-#define CDEV		((struct skinny_device *)item)
-
-static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
-{
-	struct ast_variable *v;
-	int lineInstance = 1;
-	int speeddialInstance = 1;
-	int serviceUrlInstance = 1;
-
-	while(vptr) {
-		v = vptr;
-		vptr = vptr->next;
-
-		if (type & (TYPE_GENERAL)) {
-			char newcontexts[AST_MAX_CONTEXT];
+ #define TYPE_GENERAL 	1
+ #define TYPE_DEF_DEVICE 2
+ #define TYPE_DEF_LINE 	4
+ #define TYPE_DEVICE 	8
+ #define TYPE_LINE 	16
+ 
+ #define CLINE_OPTS	((struct skinny_line_options *)item)
+ #define CLINE		((struct skinny_line *)item)
+ #define CDEV_OPTS	((struct skinny_device_options *)item)
+ #define CDEV		((struct skinny_device *)item)
+ 
+ static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
+ {
+ 	struct ast_variable *v;
+ 	int lineInstance = 1;
+ 	int speeddialInstance = 1;
+ 	
+ 	while(vptr) {
+ 		v = vptr;
+ 		vptr = vptr->next;
+ 
+ 		if (type & (TYPE_GENERAL)) {
+ 			char newcontexts[AST_MAX_CONTEXT];
 			char oldcontexts[AST_MAX_CONTEXT];
-			char *stringp, *context, *oldregcontext;
-			if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
-				v = v->next;
-				continue;
-			}
-			if (!strcasecmp(v->name, "bindaddr")) {
-				if (!(hp = ast_gethostbyname(v->value, &ahp))) {
-					ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
-				} else {
-					memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
-				}
-				continue;
-			} else if (!strcasecmp(v->name, "keepalive")) {
-				keep_alive = atoi(v->value);
-				continue;
+ 			char *stringp, *context, *oldregcontext;
+ 			if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
+ 				v = v->next;
+ 				continue;
+ 			}
+ 			if (!strcasecmp(v->name, "bindaddr")) {
+ 				if (!(hp = ast_gethostbyname(v->value, &ahp))) {
+ 					ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
+ 				} else {
+ 					memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
+ 				}
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "keepalive")) {
+ 				keep_alive = atoi(v->value);
+ 				continue;
 			} else if (!strcasecmp(v->name, "authtimeout")) {
 				int timeout = atoi(v->value);
 
@@ -7784,305 +7163,271 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
 					auth_limit = limit;
 				}
 				continue;
-			} else if (!strcasecmp(v->name, "regcontext")) {
-				ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
-				stringp = newcontexts;
+ 			} else if (!strcasecmp(v->name, "regcontext")) {
+ 				ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
+ 				stringp = newcontexts;
 				/* Initialize copy of current global_regcontext for later use in removing stale contexts */
 				ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts));
 				oldregcontext = oldcontexts;
-				/* Let's remove any contexts that are no longer defined in regcontext */
-				cleanup_stale_contexts(stringp, oldregcontext);
-				/* Create contexts if they don't exist already */
-				while ((context = strsep(&stringp, "&"))) {
-					ast_copy_string(used_context, context, sizeof(used_context));
-					ast_context_find_or_create(NULL, NULL, context, "Skinny");
-				}
-				ast_copy_string(regcontext, v->value, sizeof(regcontext));
-				continue;
-			} else if (!strcasecmp(v->name, "vmexten")) {
-				ast_copy_string(vmexten, v->value, sizeof(vmexten));
-				continue;
-			} else if (!strcasecmp(v->name, "immeddialkey")) {
-				if (!strcmp(v->value,"#")) {
-					immed_dialchar = '#';
-				} else if (!strcmp(v->value,"*")) {
-					immed_dialchar = '*';
-				} else {
-					ast_log(LOG_WARNING, "Invalid immeddialkey '%s' at line %d, only # or * accepted. Immeddial key disabled\n", v->value, v->lineno);
-				}
-
-				continue;
-			} else if (!strcasecmp(v->name, "dateformat")) {
-				memcpy(date_format, v->value, sizeof(date_format));
-				continue;
-			} else if (!strcasecmp(v->name, "tos")) {
-				if (ast_str2tos(v->value, &qos.tos))
-					ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "tos_audio")) {
-				if (ast_str2tos(v->value, &qos.tos_audio))
-					ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "tos_video")) {
-				if (ast_str2tos(v->value, &qos.tos_video))
-					ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "cos")) {
-				if (ast_str2cos(v->value, &qos.cos))
-					ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "cos_audio")) {
-				if (ast_str2cos(v->value, &qos.cos_audio))
-					ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "cos_video")) {
-				if (ast_str2cos(v->value, &qos.cos_video))
-					ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
-				continue;
-			} else if (!strcasecmp(v->name, "bindport")) {
-				if (sscanf(v->value, "%5d", &ourport) == 1) {
-					bindaddr.sin_port = htons(ourport);
-				} else {
-					ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
-				}
-				continue;
-			} else if (!strcasecmp(v->name, "allow")) {
-				ast_format_cap_update_by_allow_disallow(default_cap, v->value, 1);
-				continue;
-			} else if (!strcasecmp(v->name, "disallow")) {
-				ast_format_cap_update_by_allow_disallow(default_cap, v->value, 0);
-				continue;
-			}
-		}
-
-		if (!strcasecmp(v->name, "transfer")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				CDEV_OPTS->transfer = ast_true(v->value);
-				continue;
-			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->transfer = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "callwaiting")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				CDEV_OPTS->callwaiting = ast_true(v->value);
-				continue;
-			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->callwaiting = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->directmedia = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "nat")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->nat = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "context")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
-				continue;
-			}
-		}else if (!strcasecmp(v->name, "vmexten")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
-				continue;
-			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "mwiblink")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				CDEV_OPTS->mwiblink = ast_true(v->value);
-				continue;
-			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->mwiblink = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "linelabel")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "callerid")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				if (!strcasecmp(v->value, "asreceived")) {
-					CLINE_OPTS->cid_num[0] = '\0';
-					CLINE_OPTS->cid_name[0] = '\0';
-				} else {
-					ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
-				}
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "amaflags")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				int tempamaflags = ast_channel_string2amaflag(v->value);
-				if (tempamaflags < 0) {
-					ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
-				} else {
-					CLINE_OPTS->amaflags = tempamaflags;
-				}
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "regexten")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "language")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "accountcode")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "mohsuggest")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "callgroup")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->callgroup = ast_get_group(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "pickupgroup")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->pickupgroup = ast_get_group(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "namedcallgroup")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->named_callgroups = ast_get_namedgroups(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "namedpickupgroup")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->named_pickupgroups = ast_get_namedgroups(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "immediate")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->immediate = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "cancallforward")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->cancallforward = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "callfwdtimeout")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->callfwdtimeout = atoi(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "mailbox")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
-				continue;
-			}
-		} else if ( !strcasecmp(v->name, "parkinglot")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "hasvoicemail")) {
-			if (type & (TYPE_LINE)) {
-				if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
-					/*
-					 * hasvoicemail is a users.conf legacy voicemail enable method.
-					 * hasvoicemail is only going to work for app_voicemail mailboxes.
-					 */
-					if (strchr(CLINE->name, '@')) {
-						ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
-					} else {
-						snprintf(CLINE->mailbox, sizeof(CLINE->mailbox), "%s at default",
-							CLINE->name);
-					}
-				}
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "threewaycalling")) {
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				CLINE_OPTS->threewaycalling = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "setvar")) {
-			if (type & (TYPE_LINE)) {
-				CLINE->chanvars = add_var(v->value, CLINE->chanvars);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "earlyrtp")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				CDEV_OPTS->earlyrtp = ast_true(v->value);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "host")) {
-			if (type & (TYPE_DEVICE)) {
+ 				/* Let's remove any contexts that are no longer defined in regcontext */
+ 				cleanup_stale_contexts(stringp, oldregcontext);
+ 				/* Create contexts if they don't exist already */
+ 				while ((context = strsep(&stringp, "&"))) {
+ 					ast_copy_string(used_context, context, sizeof(used_context));
+ 					ast_context_find_or_create(NULL, NULL, context, "Skinny");
+ 				}
+ 				ast_copy_string(regcontext, v->value, sizeof(regcontext));
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "vmexten")) {
+ 				ast_copy_string(vmexten, v->value, sizeof(vmexten));
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "dateformat")) {
+ 				memcpy(date_format, v->value, sizeof(date_format));
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "tos")) {
+ 				if (ast_str2tos(v->value, &qos.tos))
+ 					ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "tos_audio")) {
+ 				if (ast_str2tos(v->value, &qos.tos_audio))
+ 					ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "tos_video")) {
+ 				if (ast_str2tos(v->value, &qos.tos_video))
+ 					ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "cos")) {
+ 				if (ast_str2cos(v->value, &qos.cos))
+ 					ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "cos_audio")) {
+ 				if (ast_str2cos(v->value, &qos.cos_audio))
+ 					ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "cos_video")) {
+ 				if (ast_str2cos(v->value, &qos.cos_video))
+ 					ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "bindport")) {
+ 				if (sscanf(v->value, "%5d", &ourport) == 1) {
+ 					bindaddr.sin_port = htons(ourport);
+ 				} else {
+ 					ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
+ 				}
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "allow")) {
+ 				ast_parse_allow_disallow(&default_prefs, default_cap, v->value, 1);
+ 				continue;
+ 			} else if (!strcasecmp(v->name, "disallow")) {
+ 				ast_parse_allow_disallow(&default_prefs, default_cap, v->value, 0);
+ 				continue;
+ 			} 
+ 		}
+ 
+ 		if (!strcasecmp(v->name, "transfer")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				CDEV_OPTS->transfer = ast_true(v->value);
+ 				continue;
+ 			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->transfer = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "callwaiting")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				CDEV_OPTS->callwaiting = ast_true(v->value);
+ 				continue;
+ 			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->callwaiting = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->directmedia = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "nat")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->nat = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "context")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
+ 				continue;
+ 			}
+ 		}else if (!strcasecmp(v->name, "vmexten")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
+ 				continue;
+ 			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "mwiblink")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				CDEV_OPTS->mwiblink = ast_true(v->value);
+ 				continue;
+ 			} else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->mwiblink = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "linelabel")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "callerid")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				if (!strcasecmp(v->value, "asreceived")) {
+ 					CLINE_OPTS->cid_num[0] = '\0';
+ 					CLINE_OPTS->cid_name[0] = '\0';
+ 				} else {
+ 					ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
+ 				}
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "amaflags")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				int tempamaflags = ast_cdr_amaflags2int(v->value);
+ 				if (tempamaflags < 0) {
+ 					ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
+ 				} else {
+ 					CLINE_OPTS->amaflags = tempamaflags;
+ 				}
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "regexten")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "language")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "accountcode")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "mohsuggest")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "callgroup")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->callgroup = ast_get_group(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "pickupgroup")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->pickupgroup = ast_get_group(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "immediate")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->immediate = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "cancallforward")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->cancallforward = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "mailbox")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
+ 				continue;
+ 			}
+ 		} else if ( !strcasecmp(v->name, "parkinglot")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "hasvoicemail")) {
+ 			if (type & (TYPE_LINE)) {
+ 				if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
+ 					ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
+ 				}
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "threewaycalling")) {
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				CLINE_OPTS->threewaycalling = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "setvar")) {
+ 			if (type & (TYPE_LINE)) {
+ 				CLINE->chanvars = add_var(v->value, CLINE->chanvars);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "earlyrtp")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				CDEV_OPTS->earlyrtp = ast_true(v->value);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "host")) {
+ 			if (type & (TYPE_DEVICE)) {
 				struct ast_sockaddr CDEV_addr_tmp;
 
 				CDEV_addr_tmp.ss.ss_family = AF_INET;
 				if (ast_get_ip(&CDEV_addr_tmp, v->value)) {
-					ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
-				}
+ 					ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
+ 				}
 				ast_sockaddr_to_sin(&CDEV_addr_tmp,
 						    &CDEV->addr);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "port")) {
-			if (type & (TYPE_DEF_DEVICE)) {
-				CDEV->addr.sin_port = htons(atoi(v->value));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "device")) {
-			if (type & (TYPE_DEVICE)) {
-				ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
-			if (type & (TYPE_DEVICE)) {
-				CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "allow")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				ast_format_cap_update_by_allow_disallow(CDEV->confcap, v->value, 1);
-				continue;
-			}
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_format_cap_update_by_allow_disallow(CLINE->confcap, v->value, 1);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "disallow")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				ast_format_cap_update_by_allow_disallow(CDEV->confcap, v->value, 0);
-				continue;
-			}
-			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
-				ast_format_cap_update_by_allow_disallow(CLINE->confcap, v->value, 0);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "version")) {
-			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
-				ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "line")) {
-			if (type & (TYPE_DEVICE)) {
-				struct skinny_line *l;
-				AST_LIST_TRAVERSE(&lines, l, all) {
-					if (!strcasecmp(v->value, l->name) && !l->prune) {
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "port")) {
+ 			if (type & (TYPE_DEF_DEVICE)) {
+ 				CDEV->addr.sin_port = htons(atoi(v->value));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "device")) {
+ 			if (type & (TYPE_DEVICE)) {
+ 				ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
+ 			if (type & (TYPE_DEVICE)) {
+ 				CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "allow")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				ast_parse_allow_disallow(&CDEV->confprefs, CDEV->confcap, v->value, 1);
+ 				continue;
+ 			}
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_parse_allow_disallow(&CLINE->confprefs, CLINE->confcap, v->value, 1);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "disallow")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				ast_parse_allow_disallow(&CDEV->confprefs, CDEV->confcap, v->value, 0);
+ 				continue;
+ 			}
+ 			if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ 				ast_parse_allow_disallow(&CLINE->confprefs, CLINE->confcap, v->value, 0);
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "version")) {
+ 			if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
+ 				ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "line")) {
+ 			if (type & (TYPE_DEVICE)) {
+ 				struct skinny_line *l;
+ 				AST_LIST_TRAVERSE(&lines, l, all) {
+ 					if (!strcasecmp(v->value, l->name) && !l->prune) {
 
 						/* FIXME: temp solution about line conflicts */
 						struct skinny_device *d;
@@ -8104,28 +7449,28 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
 							AST_LIST_INSERT_HEAD(&CDEV->lines, l, list);
 							l->device = CDEV;
 						}
-						break;
-					}
-				}
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "subline")) {
-			if (type & (TYPE_LINE)) {
-				struct skinny_subline *subline;
-				struct skinny_container *container;
+ 						break;
+ 					}
+ 				}
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "subline")) {
+ 			if (type & (TYPE_LINE)) {
+ 				struct skinny_subline *subline;
+ 				struct skinny_container *container;
 				char buf[256];
 				char *stringp = buf, *exten, *stname, *context;
 
-				if (!(subline = ast_calloc(1, sizeof(*subline)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for subline %s. Ignoring subline.\n", v->value);
-					continue;
-				}
-				if (!(container = ast_calloc(1, sizeof(*container)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for subline %s container. Ignoring subline.\n", v->value);
+ 				if (!(subline = ast_calloc(1, sizeof(*subline)))) {
+ 					ast_log(LOG_WARNING, "Unable to allocate memory for subline %s. Ignoring subline.\n", v->value);
+ 					continue;
+ 				}
+ 				if (!(container = ast_calloc(1, sizeof(*container)))) {
+ 					ast_log(LOG_WARNING, "Unable to allocate memory for subline %s container. Ignoring subline.\n", v->value);
 					ast_free(subline);
-					continue;
-				}
-
+ 					continue;
+ 				}
+				
 				ast_copy_string(buf, v->value, sizeof(buf));
 				exten = strsep(&stringp, "@");
 				ast_copy_string(subline->exten, ast_strip(exten), sizeof(subline->exten));
@@ -8143,34 +7488,34 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
 				container->data = subline;
 				subline->container = container;
 				AST_LIST_INSERT_HEAD(&CLINE->sublines, subline, list);
-				continue;
+ 				continue;
 			}
-		} else if (!strcasecmp(v->name, "dialoutcontext")) {
-			if (type & (TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->dialoutcontext, v->value, sizeof(CLINE_OPTS->dialoutcontext));
+ 		} else if (!strcasecmp(v->name, "dialoutcontext")) {
+ 			if (type & (TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->dialoutcontext, v->value, sizeof(CLINE_OPTS->dialoutcontext));
 				continue;
 			}
-		} else if (!strcasecmp(v->name, "dialoutexten")) {
-			if (type & (TYPE_LINE)) {
-				ast_copy_string(CLINE_OPTS->dialoutexten, v->value, sizeof(CLINE_OPTS->dialoutexten));
+ 		} else if (!strcasecmp(v->name, "dialoutexten")) {
+ 			if (type & (TYPE_LINE)) {
+ 				ast_copy_string(CLINE_OPTS->dialoutexten, v->value, sizeof(CLINE_OPTS->dialoutexten));
 				continue;
 			}
-		} else if (!strcasecmp(v->name, "speeddial")) {
-			if (type & (TYPE_DEVICE)) {
-				struct skinny_speeddial *sd;
-				struct skinny_container *container;
+ 		} else if (!strcasecmp(v->name, "speeddial")) {
+ 			if (type & (TYPE_DEVICE)) {
+ 				struct skinny_speeddial *sd;
+ 				struct skinny_container *container;
 				char buf[256];
 				char *stringp = buf, *exten, *context, *label;
 
-				if (!(sd = ast_calloc(1, sizeof(*sd)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
-					continue;
-				}
-				if (!(container = ast_calloc(1, sizeof(*container)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s container. Ignoring speeddial.\n", v->name);
+ 				if (!(sd = ast_calloc(1, sizeof(*sd)))) {
+ 					ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
+ 					continue;
+ 				}
+ 				if (!(container = ast_calloc(1, sizeof(*container)))) {
+ 					ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s container. Ignoring speeddial.\n", v->name);
 					ast_free(sd);
-					continue;
-				}
+ 					continue;
+ 				}
 
 				ast_copy_string(buf, v->value, sizeof(buf));
 				exten = strsep(&stringp, ",");
@@ -8195,167 +7540,146 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
 				container->data = sd;
 				sd->container = container;
 				AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list);
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "serviceurl")) {
-			if (type & (TYPE_DEVICE)) {
-				struct skinny_serviceurl *surl;
-				char buf[256];
-				char *stringp = buf, *serviceUrl, *displayName;
-				if (!(surl = ast_calloc(1, sizeof(*surl)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for serviceurl %s. Ignoring service URL.\n", v->name);
-					continue;
-				}
-				ast_copy_string(buf, v->value, sizeof(buf));
-				displayName = strsep(&stringp, ",");
-				if (stringp) {
-					serviceUrl = stringp;
-					ast_copy_string(surl->url, ast_strip(serviceUrl), sizeof(surl->url));
-					ast_copy_string(surl->displayName, displayName, sizeof(surl->displayName));
-					surl->instance = serviceUrlInstance++;
-					surl->device = CDEV;
-					AST_LIST_INSERT_HEAD(&CDEV->serviceurls, surl, list);
-				} else {
-					ast_free(surl);
-					ast_log(LOG_WARNING, "Badly formed option for service URL in %s. Ignoring service URL.\n", v->name);
-				}
-				continue;
-			}
-		} else if (!strcasecmp(v->name, "addon")) {
-			if (type & (TYPE_DEVICE)) {
-				struct skinny_addon *a;
-				if (!(a = ast_calloc(1, sizeof(*a)))) {
-					ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
-					continue;
-				} else {
-					ast_mutex_init(&a->lock);
-					ast_copy_string(a->type, v->value, sizeof(a->type));
-					AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
-				}
-				continue;
-			}
-
-		} else {
-			ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
-			continue;
-		}
-		ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
-	}
-}
-
-static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
-{
-	struct skinny_line *l, *temp;
+ 				continue;
+ 			}
+ 		} else if (!strcasecmp(v->name, "addon")) {
+ 			if (type & (TYPE_DEVICE)) {
+ 				struct skinny_addon *a;
+ 				if (!(a = ast_calloc(1, sizeof(*a)))) {
+ 					ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
+ 					continue;
+ 				} else {
+ 					ast_mutex_init(&a->lock);
+ 					ast_copy_string(a->type, v->value, sizeof(a->type));
+ 					AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
+ 				}
+ 				continue;
+ 			}
+
+ 		} else {
+ 			ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
+ 			continue;
+ 		}
+ 		ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
+ 	}
+ }
+ 
+ static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
+ {
+ 	struct skinny_line *l, *temp;
 	int update = 0;
 	struct skinny_container *container;
-
-	ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
+ 
+ 	ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
 
 	/* We find the old line and remove it just before the new
 	   line is created */
-	AST_LIST_LOCK(&lines);
-	AST_LIST_TRAVERSE(&lines, temp, all) {
-		if (!strcasecmp(lname, temp->name) && temp->prune) {
+ 	AST_LIST_LOCK(&lines);
+ 	AST_LIST_TRAVERSE(&lines, temp, all) {
+ 		if (!strcasecmp(lname, temp->name) && temp->prune) {
 			update = 1;
-			break;
-		}
-	}
-
-	if (!(l = skinny_line_alloc())) {
-		ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
-		AST_LIST_UNLOCK(&lines);
-		return NULL;
-	}
+ 			break;
+ 		}
+ 	}
+
+ 	if (!(l = skinny_line_alloc())) {
+ 		ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
+ 		AST_LIST_UNLOCK(&lines);
+ 		return NULL;
+ 	}
 	if (!(container = ast_calloc(1, sizeof(*container)))) {
 		ast_log(LOG_WARNING, "Unable to allocate memory for line %s container.\n", lname);
 		skinny_line_destroy(l);
-		AST_LIST_UNLOCK(&lines);
-		return NULL;
+ 		AST_LIST_UNLOCK(&lines);
+ 		return NULL;
 	}
 
 	container->type = SKINNY_LINECONTAINER;
 	container->data = l;
 	l->container = container;
-
-	memcpy(l, default_line, sizeof(*default_line));
-	ast_mutex_init(&l->lock);
-	ast_copy_string(l->name, lname, sizeof(l->name));
-	ast_format_cap_append_from_cap(l->confcap, default_cap, AST_MEDIA_TYPE_UNKNOWN);
-	AST_LIST_INSERT_TAIL(&lines, l, all);
-
-	ast_mutex_lock(&l->lock);
-	AST_LIST_UNLOCK(&lines);
-
-	config_parse_variables(TYPE_LINE, l, v);
-
-	if (!ast_strlen_zero(l->mailbox)) {
-		struct stasis_topic *mailbox_specific_topic;
-
-		ast_verb(3, "Setting mailbox '%s' on line %s\n", l->mailbox, l->name);
-
-		mailbox_specific_topic = ast_mwi_topic(l->mailbox);
-		if (mailbox_specific_topic) {
-			l->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, l);
-		}
-	}
+	
+ 	memcpy(l, default_line, sizeof(*default_line));
+ 	ast_mutex_init(&l->lock);
+ 	ast_copy_string(l->name, lname, sizeof(l->name));
+	ast_format_cap_copy(l->confcap, default_cap);
+ 	AST_LIST_INSERT_TAIL(&lines, l, all);
+
+ 	ast_mutex_lock(&l->lock);
+ 	AST_LIST_UNLOCK(&lines);
+
+ 	config_parse_variables(TYPE_LINE, l, v);
+ 			
+ 	if (!ast_strlen_zero(l->mailbox)) {
+ 		char *cfg_mailbox, *cfg_context;
+ 		cfg_context = cfg_mailbox = ast_strdupa(l->mailbox);
+ 		ast_verb(3, "Setting mailbox '%s' on line %s\n", cfg_mailbox, l->name);
+ 		strsep(&cfg_context, "@");
+ 		if (ast_strlen_zero(cfg_context))
+ 			 cfg_context = "default";
+		l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "skinny MWI subsciption", l,
+ 			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, cfg_mailbox,
+ 			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cfg_context,
+ 			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+ 			AST_EVENT_IE_END);
+ 	}
 
 	if (!ast_strlen_zero(vmexten) && ast_strlen_zero(l->vmexten)) {
 		ast_copy_string(l->vmexten, vmexten, sizeof(l->vmexten));
 	}
-
-	ast_mutex_unlock(&l->lock);
-
+ 
+ 	ast_mutex_unlock(&l->lock);
+	
 	/* We do not want to unlink or free the line yet, it needs
 	   to be available to detect a device reconfig when we load the
 	   devices.  Old lines will be pruned after the reload completes */
 
 	ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
 
-	return l;
-}
-
-static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
-{
-	struct skinny_device *d, *temp;
-	struct skinny_line *l, *ltemp;
+ 	return l;
+ }
+ 
+ static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
+ {
+ 	struct skinny_device *d, *temp;
+ 	struct skinny_line *l, *ltemp;
 	struct skinny_subchannel *sub;
 	int update = 0;
+ 
+ 	ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
 
-	ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
-
-	AST_LIST_LOCK(&devices);
-	AST_LIST_TRAVERSE(&devices, temp, list) {
-		if (!strcasecmp(dname, temp->name) && temp->prune) {
+ 	AST_LIST_LOCK(&devices);
+ 	AST_LIST_TRAVERSE(&devices, temp, list) {
+ 		if (!strcasecmp(dname, temp->name) && temp->prune) {
 			update = 1;
-			break;
-		}
-	}
-
-	if (!(d = skinny_device_alloc(dname))) {
-		ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
-		AST_LIST_UNLOCK(&devices);
-		return NULL;
-	}
-	memcpy(d, default_device, sizeof(*default_device));
-	ast_mutex_init(&d->lock);
-	ast_copy_string(d->name, dname, sizeof(d->name));
-	ast_format_cap_append_from_cap(d->confcap, default_cap, AST_MEDIA_TYPE_UNKNOWN);
-	AST_LIST_INSERT_TAIL(&devices, d, list);
-
-	ast_mutex_lock(&d->lock);
-	AST_LIST_UNLOCK(&devices);
-
-	config_parse_variables(TYPE_DEVICE, d, v);
-
-	if (!AST_LIST_FIRST(&d->lines)) {
-		ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
-		ast_mutex_unlock(&d->lock);
-		return NULL;
-	}
-	if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
-		d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
-	}
-
+ 			break;
+ 		}
+ 	}
+
+ 	if (!(d = skinny_device_alloc())) {
+ 		ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
+ 		AST_LIST_UNLOCK(&devices);
+ 		return NULL;
+ 	}
+ 	memcpy(d, default_device, sizeof(*default_device));
+ 	ast_mutex_init(&d->lock);
+ 	ast_copy_string(d->name, dname, sizeof(d->name));
+	ast_format_cap_copy(d->confcap, default_cap);
+ 	AST_LIST_INSERT_TAIL(&devices, d, list);
+
+ 	ast_mutex_lock(&d->lock);
+ 	AST_LIST_UNLOCK(&devices);
+ 
+ 	config_parse_variables(TYPE_DEVICE, d, v);
+ 
+  	if (!AST_LIST_FIRST(&d->lines)) {
+ 		ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
+ 		ast_mutex_unlock(&d->lock);
+ 		return NULL;
+ 	}
+ 	if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
+ 		d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
+ 	}
+ 
 	if (skinnyreload){
 		AST_LIST_LOCK(&devices);
 		AST_LIST_TRAVERSE(&devices, temp, list) {
@@ -8399,41 +7723,39 @@ static struct skinny_device *config_device(const char *dname, struct ast_variabl
 		AST_LIST_UNLOCK(&devices);
 	}
 
-	ast_mutex_unlock(&d->lock);
+ 	ast_mutex_unlock(&d->lock);
 
 	ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
-
+	
 	return d;
 
-}
-
-static int config_load(void)
-{
-	int on = 1;
-	struct ast_config *cfg;
-	char *cat;
-	int oldport = ntohs(bindaddr.sin_port);
-	struct ast_flags config_flags = { 0 };
-
-	ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
-
-	if (gethostname(ourhost, sizeof(ourhost))) {
-		ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
-		return 0;
-	}
-	cfg = ast_config_load(config, config_flags);
-
-	/* We *must* have a config file otherwise stop immediately */
-	if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
-		return -1;
-	}
-
+ }
+ 
+ static int config_load(void)
+ {
+  	int on = 1;
+  	struct ast_config *cfg;
+  	char *cat;
+  	int oldport = ntohs(bindaddr.sin_port);
+  	struct ast_flags config_flags = { 0 };
+ 	
+ 	ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
+  
+  	if (gethostname(ourhost, sizeof(ourhost))) {
+ 		ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
+  		return 0;
+  	}
+  	cfg = ast_config_load(config, config_flags);
+  
+  	/* We *must* have a config file otherwise stop immediately */
+  	if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
+ 		ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
+  		return -1;
+  	}
 	memset(&bindaddr, 0, sizeof(bindaddr));
-	immed_dialchar = '\0';
+	memset(&default_prefs, 0, sizeof(default_prefs));
 	memset(&vmexten, '\0', sizeof(vmexten));
 
-
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
@@ -8458,14 +7780,16 @@ static int config_load(void)
 	bindaddr.sin_family = AF_INET;
 
 	/* load the lines sections */
+	default_line->confprefs = default_prefs;
 	config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines"));
 	cat = ast_category_browse(cfg, "lines");
 	while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) {
 		config_line(cat, ast_variable_browse(cfg, cat));
 		cat = ast_category_browse(cfg, cat);
 	}
-
+		
 	/* load the devices sections */
+	default_device->confprefs = default_prefs;
 	config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices"));
 	cat = ast_category_browse(cfg, "devices");
 	while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) {
@@ -8526,7 +7850,6 @@ static void delete_devices(void)
 	struct skinny_line *l;
 	struct skinny_speeddial *sd;
 	struct skinny_addon *a;
-	struct skinny_serviceurl *surl;
 
 	AST_LIST_LOCK(&devices);
 	AST_LIST_LOCK(&lines);
@@ -8544,10 +7867,6 @@ static void delete_devices(void)
 			free(sd->container);
 			free(sd);
 		}
-		/* Delete all serviceurls for this device */
-		while ((surl = AST_LIST_REMOVE_HEAD(&d->serviceurls, list))) {
-			free(surl);
-		}
 		/* Delete all addons for this device */
 		while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
 			free(a);
@@ -8594,13 +7913,10 @@ int skinny_reload(void)
 			continue;
 		}
 		ast_verb(3, "Removing device '%s'\n", d->name);
-		/* Delete all lines for this device.
+		/* Delete all lines for this device. 
 		   We do not want to free the line here, that
 		   will happen below. */
 		while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
-			if (l->mwi_event_sub) {
-				l->mwi_event_sub = stasis_unsubscribe(l->mwi_event_sub);
-			}
 		}
 		/* Delete all speeddials for this device */
 		while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
@@ -8616,7 +7932,7 @@ int skinny_reload(void)
 	AST_LIST_TRAVERSE_SAFE_END;
 	AST_LIST_UNLOCK(&devices);
 
-	AST_LIST_LOCK(&lines);
+	AST_LIST_LOCK(&lines);  
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&lines, l, all) {
 		if (l->prune) {
 			AST_LIST_REMOVE_CURRENT(all);
@@ -8624,7 +7940,7 @@ int skinny_reload(void)
 		}
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
-	AST_LIST_UNLOCK(&lines);
+	AST_LIST_UNLOCK(&lines);  
 
 	AST_LIST_TRAVERSE(&devices, d, list) {
 		/* Do a soft reset to re-register the devices after
@@ -8639,31 +7955,20 @@ int skinny_reload(void)
         return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res = 0;
-
-	if (!(default_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	struct ast_format tmpfmt;
+	if (!(default_cap = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	if (!(skinny_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ao2_ref(default_cap, -1);
+	if (!(skinny_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	ast_format_cap_append_by_type(skinny_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
-	ast_format_cap_append(default_cap, ast_format_ulaw, 0);
-	ast_format_cap_append(default_cap, ast_format_alaw, 0);
+	ast_format_cap_add_all_by_type(skinny_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
+	ast_format_cap_add(default_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(default_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
 
 	for (; res < ARRAY_LEN(soft_key_template_default); res++) {
 		soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
@@ -8671,23 +7976,11 @@ static int load_module(void)
 	/* load and parse config */
 	res = config_load();
 	if (res == -1) {
-		ao2_ref(skinny_tech.capabilities, -1);
-		ao2_ref(default_cap, -1);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	sched = ast_sched_context_create();
-	if (!sched) {
-		ao2_ref(skinny_tech.capabilities, -1);
-		ao2_ref(default_cap, -1);
-		ast_log(LOG_WARNING, "Unable to create schedule context\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
 	/* Make sure we can register our skinny channel type */
 	if (ast_channel_register(&skinny_tech)) {
-		ao2_ref(default_cap, -1);
-		ao2_ref(skinny_tech.capabilities, -1);
 		ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
 		return -1;
 	}
@@ -8700,12 +7993,14 @@ static int load_module(void)
 	ast_manager_register_xml("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines);
 	ast_manager_register_xml("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line);
 
+	sched = ast_sched_context_create();
+	if (!sched) {
+		ast_log(LOG_WARNING, "Unable to create schedule context\n");
+		return AST_MODULE_LOAD_FAILURE;
+	}
 	if (ast_sched_start_thread(sched)) {
 		ast_sched_context_destroy(sched);
 		sched = NULL;
-		ast_channel_unregister(&skinny_tech);
-		ao2_ref(default_cap, -1);
-		ao2_ref(skinny_tech.capabilities, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -8718,72 +8013,64 @@ static int unload_module(void)
 	struct skinny_device *d;
 	struct skinny_line *l;
 	struct skinny_subchannel *sub;
-	struct ast_context *con;
-	pthread_t tempthread;
 
 	ast_rtp_glue_unregister(&skinny_rtp_glue);
 	ast_channel_unregister(&skinny_tech);
-	ao2_cleanup(skinny_tech.capabilities);
 	ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
 
 	ast_manager_unregister("SKINNYdevices");
 	ast_manager_unregister("SKINNYshowdevice");
 	ast_manager_unregister("SKINNYlines");
 	ast_manager_unregister("SKINNYshowline");
-
-	ast_mutex_lock(&netlock);
-	if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
-		pthread_cancel(accept_t);
-		pthread_kill(accept_t, SIGURG);
-		pthread_join(accept_t, NULL);
-	}
-	accept_t = AST_PTHREADT_STOP;
-	ast_mutex_unlock(&netlock);
-
+	
 	AST_LIST_LOCK(&sessions);
 	/* Destroy all the interfaces and free their memory */
 	while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
-		RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-		AST_LIST_UNLOCK(&sessions);
 		d = s->device;
 		AST_LIST_TRAVERSE(&d->lines, l, list){
 			ast_mutex_lock(&l->lock);
 			AST_LIST_TRAVERSE(&l->sub, sub, list) {
-				skinny_locksub(sub);
+				ast_mutex_lock(&sub->lock);
 				if (sub->owner) {
 					ast_softhangup(sub->owner, AST_SOFTHANGUP_APPUNLOAD);
 				}
-				skinny_unlocksub(sub);
-			}
-			if (l->mwi_event_sub) {
-				l->mwi_event_sub = stasis_unsubscribe(l->mwi_event_sub);
+				ast_mutex_unlock(&sub->lock);
 			}
+			if (l->mwi_event_sub)
+				ast_event_unsubscribe(l->mwi_event_sub);
 			ast_mutex_unlock(&l->lock);
+			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
 			unregister_exten(l);
 		}
-		ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_OFFLINE);
-		blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
-		ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
-		tempthread = s->t;
-		pthread_cancel(tempthread);
-		pthread_join(tempthread, NULL);
-		AST_LIST_LOCK(&sessions);
+		if (s->fd > -1)
+			close(s->fd);
+		pthread_cancel(s->t);
+		pthread_kill(s->t, SIGURG);
+		pthread_join(s->t, NULL);
+		free(s);
 	}
 	AST_LIST_UNLOCK(&sessions);
 
 	delete_devices();
 
+	ast_mutex_lock(&netlock);
+	if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
+		pthread_cancel(accept_t);
+		pthread_kill(accept_t, SIGURG);
+		pthread_join(accept_t, NULL);
+	}
+	accept_t = AST_PTHREADT_STOP;
+	ast_mutex_unlock(&netlock);
+
 	close(skinnysock);
 	if (sched) {
 		ast_sched_context_destroy(sched);
 	}
 
-	con = ast_context_find(used_context);
-	if (con)
-		ast_context_destroy(con, "Skinny");
+	ast_context_destroy_by_name(used_context, "Skinny");
 
-	ao2_ref(default_cap, -1);
+	default_cap = ast_format_cap_destroy(default_cap);
+	skinny_tech.capabilities = ast_format_cap_destroy(skinny_tech.capabilities);
 	return 0;
 }
 
@@ -8794,7 +8081,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skinny Client Control Protocol (Skinny)",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index 80ba6f9..a5cbdf2 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -4,7 +4,7 @@
  * UNISTIM channel driver for asterisk
  *
  * Copyright (C) 2005 - 2007, Cedric Hans
- *
+ * 
  * Cedric Hans <cedric.hans at mlkj.net>
  *
  * Asterisk 1.4 patch by Peter Be
@@ -38,7 +38,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426668 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 #include <signal.h>
@@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426668 $")
 #include "asterisk/config.h"
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
+#include "asterisk/event.h"
 #include "asterisk/rtp_engine.h"
 #include "asterisk/netsock2.h"
 #include "asterisk/acl.h"
@@ -72,13 +73,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426668 $")
 #include "asterisk/musiconhold.h"
 #include "asterisk/causes.h"
 #include "asterisk/indications.h"
-#include "asterisk/pickup.h"
+#include "asterisk/features.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/astdb.h"
-#include "asterisk/features_config.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/format_cache.h"
+
 
 #define DEFAULTCONTEXT	  "default"
 #define DEFAULTCALLERID	 "Unknown"
@@ -90,11 +88,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426668 $")
 /*! Size of the transmit buffer */
 #define MAX_BUF_SIZE	    64
 /*! Number of slots for the transmit queue */
-#define MAX_BUF_NUMBER	  150
+#define MAX_BUF_NUMBER	  50
 /*! Number of digits displayed on screen */
 #define MAX_SCREEN_NUMBER   15
-/*! Length of month label size */
-#define MONTH_LABEL_SIZE 3
 /*! Try x times before removing the phone */
 #define NB_MAX_RETRANSMIT       8
 /*! Nb of milliseconds waited when no events are scheduled */
@@ -149,21 +145,6 @@ enum autoprov_extn {
 #define MUTE_ON		 0xFF
 #define MUTE_ON_DISCRET	 0xCE
 
-#define LED_BAR_OFF			0x00 /* bar off */
-#define LED_BAR_ON			0x01 /* bar on */
-#define LED_BAR_P2			0x02 /* bar 1s on/1s */
-#define LED_BAR_P3			0x03 /* bar 2.5s on/0.5s off */
-#define LED_BAR_P4			0x04 /* bar 0.6s on/0.3s off */
-#define LED_BAR_P5			0x05 /* bar 0.5s on/0.5s off */
-#define LED_BAR_P6			0x06 /* bar 2s on/0.5s off */
-#define LED_BAR_P7			0x07 /* bar off */
-#define LED_SPEAKER_OFF			0x08
-#define LED_SPEAKER_ON			0x09
-#define LED_HEADPHONE_OFF		0x010
-#define LED_HEADPHONE_ON		0x011
-#define LED_MUTE_OFF			0x018
-#define LED_MUTE_ON			0x019
-
 #define SIZE_HEADER	     6
 #define SIZE_MAC_ADDR	   17
 #define TEXT_LENGTH_MAX	 24
@@ -214,7 +195,6 @@ enum autoprov_extn {
 #define FAV_MAX_LENGTH		  0x0A
 
 #define FAVNUM                    6
-#define EXPNUM                    24
 #define FAV_LINE_ICON         FAV_ICON_ONHOOK_BLACK
 
 static void dummy(char *unused, ...)
@@ -233,7 +213,7 @@ static struct ast_jb_conf default_jbconf =
 	.target_extra = 40,
 };
 static struct ast_jb_conf global_jbconf;
-
+				
 
 /* #define DUMP_PACKET 1 */
 /* #define DEBUG_TIMER ast_verbose */
@@ -399,8 +379,6 @@ static struct unistim_device {
 	char redial_number[AST_MAX_EXTENSION];	 /*!< the last phone number entered by the user */
 	char id[18];			    /*!< mac address of the current phone in ascii */
 	char name[DEVICE_NAME_LEN];     /*!< name of the device */
-	int hasexp;                          /*!< if device have expansion connected */
-	char expsoftkeylabel[EXPNUM][11];       /*!< soft key label */
 	char softkeylabel[FAVNUM][11];       /*!< soft key label */
 	char softkeynumber[FAVNUM][AST_MAX_EXTENSION];      /*!< number dialed when the soft key is pressed */
 	char softkeyicon[FAVNUM];	    /*!< icon number */
@@ -423,7 +401,6 @@ static struct unistim_device {
 	char cwvolume;			/*!< Ring volume on call waiting */
 	char cwstyle;			 /*!< Ring melody on call waiting */
 	int interdigit_timer;		/*!< Interdigit timer for dialing number by timeout */
-	int dtmfduration;		/*!< DTMF playback duration */
 	time_t nextdial;		/*!< Timer used for dial by timeout */
 	int rtp_port;			   /*!< RTP port used by the phone */
 	int rtp_method;			 /*!< Select the unistim data used to establish a RTP session */
@@ -439,7 +416,7 @@ static struct unistim_device {
 	int previous_output;	    /*!< Previous output */
 	int volume;				     /*!< Default volume */
 	int selected;                           /*!< softkey selected */
-	int microphone;				/*!< Microphone mode (audio tx) */
+	int mute;				       /*!< Mute mode */
 	int lastmsgssent;                                                   /*! Used by MWI */
 	time_t nextmsgcheck;                                            /*! Used by MWI */
 	int nat;					/*!< Used by the obscure ast_rtp_setnat */
@@ -468,8 +445,7 @@ static struct unistimsession {
 	int state;				      /*!< state of the phone (see phone_state) */
 	int size_buff_entry;	    /*!< size of the buffer used to enter datas */
 	char buff_entry[16];	    /*!< Buffer for temporary datas */
-	char macaddr[18];		       /*!< mac adress of the phone (not always available) */
-	char firmware[8];		       /*!< firmware of the phone (not always available) */
+	char macaddr[18];		       /*!< mac address of the phone (not always available) */
 	struct wsabuf wsabufsend[MAX_BUF_NUMBER];      /*!< Size of each paquet stored in the buffer array & pointer to this buffer */
 	unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE];	/*!< Buffer array used to keep the lastest non-acked paquets */
 	struct unistim_device *device;
@@ -519,15 +495,6 @@ static const unsigned char packet_recv_hangup[] =
 	{ 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
 static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
 
-/*! Expansion module (i2004 KEM) */
-static const unsigned char packet_recv_expansion_pressed_key[] =
-	{ 0x00, 0x00, 0x00, 0x13, 0x89, 0x04, 0x59 };
-static const unsigned char packet_send_expansion_next[] = { 0x09, 0x03, 0x17 };
-static const unsigned char packet_send_expansion_icon[] = { 0x09, 0x06, 0x59, 0x05, /*pos */ 0x47, /*icon */ 0x20 };      /* display an icon in front of the text zone */
-static const unsigned char packet_send_expansion_text[] = { 0x09, 0x0f, 0x57, 0x19, /*pos */ 0x47, /*text */ 0x20,
-	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */ };
-
-
 /*! TransportAdapter */
 static const unsigned char packet_recv_resume_connection_with_server[] =
 	{ 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
@@ -566,9 +533,9 @@ static const unsigned char packet_send_call[] =
 static const unsigned char packet_send_stream_based_tone_off[] =
 	{ 0x16, 0x05, 0x1c, 0x00, 0x00 };
 
-static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
+/* static const unsigned char packet_send_Mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
 static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
-static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };
+static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };*/
 static const unsigned char packet_send_stream_based_tone_on[] =
 	{ 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
 static const unsigned char packet_send_stream_based_tone_single_freq[] =
@@ -577,17 +544,16 @@ static const unsigned char packet_send_stream_based_tone_dial_freq[] =
 	{ 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
 static const unsigned char packet_send_select_output[] =
 	{ 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
-
 static const unsigned char packet_send_ring[] =
 	{ 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16,
 	0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13 /* Ring type 10 to 17 */ , 0x18, 0x16, 0x04, 0x18,     /* volume 00, 10, 20... */
 	0x20, 0x16, 0x04, 0x10, 0x00
 };
-//static const unsigned char packet_send_end_call[] =
-//	{ 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Headset LED off */ 0x19, 0x04, 0x00,
-//0x10, /* Mute LED off */ 0x19, 0x04, 0x00, 0x18,/* Stream unmute */ 0x16, 0x05, 0x04, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
 static const unsigned char packet_send_end_call[] =
-	{ 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
+	{ 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, 0x19, 0x04, 0x00,
+0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
+	0x04, 0x00, 0x00, 0x16, 0x04, 0x37, 0x10
+};
 static const unsigned char packet_send_s9[] =
 	{ 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
 0x00 };
@@ -599,7 +565,7 @@ static const unsigned char packet_send_jitter_buffer_conf[] =
 	0x00, 0x00, /* late packet resync 2 bytes */ 0x3e, 0x80
 };
 
-/* Duration in ms div 2 (0x20 = 64ms, 0x08 = 16ms)
+/* Duration in ms div 2 (0x20 = 64ms, 0x08 = 16ms) 
 static unsigned char packet_send_StreamBasedToneCad[] =
   { 0x16, 0x0a, 0x1e, 0x00, duration on  0x0a, duration off  0x0d, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x2b }; */
 static const unsigned char packet_send_open_audio_stream_rx[] =
@@ -636,18 +602,15 @@ static const unsigned char packet_send_Contrast[] =
 	{ 0x17, 0x04, 0x24, /*Contrast */ 0x08 };
 static const unsigned char packet_send_start_timer[] =
 	{ 0x17, 0x05, 0x0b, /*Timer option*/0x05, /* Timer ID */0x00, 0x17, 0x08, 0x16,
-	/* Text */ 'T', 'i', 'm', 'e', 'r' };
+	/* Text */ 0x44, 0x75, 0x72, 0xe9, 0x65 };
 static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
 static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, /*pos */ 0x00, /*icon */ 0x25 };      /* display an icon in front of the text zone */
 static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
 static const unsigned char packet_send_set_pos_cursor[] =
 	{ 0x17, 0x06, 0x10, 0x81, 0x04, /*pos */ 0x20 };
 
-static unsigned char monthlabels[] =
-	{ 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r', 'M', 'a', 'y', 'J', 'u', 'n',
-		'J', 'u', 'l', 'A', 'u', 'g', 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c' };
-static unsigned char packet_send_monthlabels_download[] =
-  { 0x17, 0x0a, 0x15, /* Month (3 char) */ '-', '-', '-', '-', '-', '-', 0x20 };
+/*static unsigned char packet_send_MonthLabelsDownload[] =
+  { 0x17, 0x0a, 0x15,  Month (3 char)  0x46, 0x65, 0x62, 0x4d, 0xe4, 0x72, 0x20 }; */
 static const unsigned char packet_send_favorite[] =
 	{ 0x17, 0x0f, 0x19, 0x10, /*pos */ 0x01, /*name */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 0x20, 0x20, 0x20, 0x20, /*end_name */ 0x19,
@@ -704,14 +667,13 @@ static const char tdesc[] = "UNISTIM Channel Driver";
 static const char channel_type[] = "USTM";
 
 /*! Protos */
-static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
+static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid);
 static int load_module(void);
 static int reload(void);
 static int unload_module(void);
 static int reload_config(void);
-static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan);
 static void show_main_page(struct unistimsession *pte);
-static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
+static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor,
 	const char *dest, int *cause);
 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout);
 static int unistim_hangup(struct ast_channel *ast);
@@ -722,11 +684,11 @@ static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
 	size_t datalen);
 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
-static int unistim_senddigit_end(struct ast_channel *ast, char digit,
+static int unistim_senddigit_end(struct ast_channel *ast, char digit, 
 	unsigned int duration);
 static int unistim_sendtext(struct ast_channel *ast, const char *text);
 
-static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
+static int write_entry_history(struct unistimsession *pte, FILE * f, char c, 
 	char *line1);
 static void change_callerid(struct unistimsession *pte, int type, char *callerid);
 
@@ -745,6 +707,7 @@ static struct ast_channel_tech unistim_tech = {
 	.send_digit_begin = unistim_senddigit_begin,
 	.send_digit_end = unistim_senddigit_end,
 	.send_text = unistim_sendtext,
+	.bridge = ast_rtp_instance_bridge,
 };
 
 static void send_start_rtp(struct unistim_subchannel *);
@@ -800,7 +763,7 @@ static const char *ustmtext(const char *str, struct unistimsession *pte)
 	struct ustm_lang_entry le_search;
 	struct unistim_languages *lang = NULL;
 	int size;
-
+	
 	if (pte->device) {
 		lang = &options_languages[find_language(pte->device->language)];
 	}
@@ -935,7 +898,7 @@ static void send_raw_client(int size, const unsigned char *data, struct sockaddr
 					ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
 					ast_inet_ntoa(addr_to->sin_addr));
 		for (tmp = 0; tmp < size; tmp++)
-			ast_verb(0, "%.2x ", (unsigned char) data[tmp]);
+			ast_verb(0, "%02hhx ", data[tmp]);
 		ast_verb(0, "\n******************************************\n");
 
 	}
@@ -974,7 +937,7 @@ static void send_client(int size, const unsigned char *data, struct unistimsessi
 
 /*#ifdef DUMP_PACKET */
 	if (unistimdebug) {
-		ast_verb(0, "Sending datas with seq #0x%.4x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
+		ast_verb(6, "Sending datas with seq #0x%04x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
 	}
 /*#endif */
 	send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
@@ -987,7 +950,7 @@ static void send_ping(struct unistimsession *pte)
 {
 	BUFFSEND;
 	if (unistimdebug) {
-		ast_verb(0, "Sending ping\n");
+		ast_verb(6, "Sending ping\n");
 	}
 	pte->tick_next_ping = get_tick_count() + unistim_keepalive;
 	memcpy(buffsend + SIZE_HEADER, packet_send_ping, sizeof(packet_send_ping));
@@ -1085,7 +1048,7 @@ static void check_send_queue(struct unistimsession *pte)
 	/* Check if our send queue contained only one element */
 	if (pte->last_buf_available == 1) {
 		if (unistimdebug) {
-			ast_verb(0, "Our single packet was ACKed.\n");
+			ast_verb(6, "Our single packet was ACKed.\n");
 		}
 		pte->last_buf_available--;
 		set_ping_timer(pte);
@@ -1094,14 +1057,14 @@ static void check_send_queue(struct unistimsession *pte)
 	/* Check if this ACK catch up our latest packet */
 	else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
 		if (unistimdebug) {
-			ast_verb(0, "Our send queue is completely ACKed.\n");
+			ast_verb(6, "Our send queue is completely ACKed.\n");
 		}
 		pte->last_buf_available = 0;    /* Purge the send queue */
 		set_ping_timer(pte);
 		return;
 	}
 	if (unistimdebug) {
-		ast_verb(0, "We still have packets in our send queue\n");
+		ast_verb(6, "We still have packets in our send queue\n");
 	}
 	return;
 }
@@ -1130,7 +1093,7 @@ static void send_icon(unsigned char pos, unsigned char status, struct unistimses
 {
 	BUFFSEND;
 	if (unistimdebug) {
-		ast_verb(0, "Sending icon pos %d with status 0x%.2x\n", pos, (unsigned)status);
+		ast_verb(0, "Sending icon pos %d with status 0x%02hhx\n", pos, status);
 	}
 	memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
 	buffsend[9] = pos;
@@ -1138,48 +1101,6 @@ static void send_icon(unsigned char pos, unsigned char status, struct unistimses
 	send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
 }
 
-static void send_expansion_next(struct unistimsession *pte)
-{
-	BUFFSEND;
-	memcpy(buffsend + SIZE_HEADER, packet_send_expansion_next, sizeof(packet_send_expansion_next));
-	send_client(SIZE_HEADER + sizeof(packet_send_expansion_next), buffsend, pte);
-}
-
-
-static void send_expansion_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
-{
-	BUFFSEND;
-	if (unistimdebug) {
-		ast_verb(0, "Sending expansion icon pos %d with status 0x%.2x\n", pos, (unsigned)status);
-	}
-	memcpy(buffsend + SIZE_HEADER, packet_send_expansion_icon, sizeof(packet_send_expansion_icon));
-	buffsend[10] = pos;
-	buffsend[11] = status;
-	send_client(SIZE_HEADER + sizeof(packet_send_expansion_icon), buffsend, pte);
-}
-
-/* inverse : TEXT_INVERSE : yes, TEXT_NORMAL  : no */
-static void send_expansion_text(unsigned char pos, struct unistimsession *pte, const char *text)
-{
-	int i;
-	BUFFSEND;
-	if (!text) {
-		ast_log(LOG_ERROR, "[expansion] Asked to display NULL text (pos %d)\n", pos);
-		return;
-	}
-	if (unistimdebug) {
-		ast_verb(0, "[expansion] Sending text at pos %d\n", pos);
-	}
-	memcpy(buffsend + SIZE_HEADER, packet_send_expansion_text, sizeof(packet_send_expansion_text));
-	buffsend[10] = pos;
-	i = strlen(text);
-	if (i > TEXT_LENGTH_MAX) {
-		i = TEXT_LENGTH_MAX;
-	}
-	memcpy(buffsend + 11, text, i);
-	send_client(SIZE_HEADER + sizeof(packet_send_expansion_text), buffsend, pte);
-}
-
 static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
 {
 	BUFFSEND;
@@ -1233,24 +1154,6 @@ static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2
  |  5	         2    | <-- not on screen in i2002
  |  4	         1    |
  |  3	         0    |
-
-
- KEM Positions
-
- |--------------------|
- |  12	         24   |
- |  11	         23   |
- |  10	         22   |
- |  9	         21   |
- |  8	         20   |
- |  7	         19   |
- |  6	         18   |
- |  5	         17   |
- |  4	         16   |
- |  3	         15   |
- |  2	         14   |
- |  1	         13   |
-
 */
 
 /* status (icons) : 00 = nothing, 2x/3x = see parser.h, 4x/5x = blink fast, 6x/7x = blink slow */
@@ -1262,7 +1165,7 @@ send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pt
 	int i;
 
 	if (unistimdebug) {
-		ast_verb(0, "Sending favorite pos %d with status 0x%.2x\n", pos, (unsigned)status);
+		ast_verb(0, "Sending favorite pos %d with status 0x%02hhx\n", pos, status);
 	}
 	memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
 	buffsend[10] = pos;
@@ -1288,13 +1191,6 @@ static void send_favorite_selected(unsigned char status, struct unistimsession *
 	return;
 }
 
-static void send_expansion_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
-	send_expansion_icon(pos, status, pte);
-	send_expansion_text(pos, pte, ustmtext(pte->device->expsoftkeylabel[pos], pte));
-	send_expansion_next(pte);
-	return;
-}
-
 static int soft_key_visible(struct unistim_device* d, unsigned char num)
 {
 	if(d->height == 1 && num % 3 == 2) {
@@ -1327,11 +1223,6 @@ static void refresh_all_favorite(struct unistimsession *pte)
 
 		send_favorite_short(i, status, pte);
 	}
-	if (pte->device->hasexp) {
-		for (i = 0; i < EXPNUM; i++) {
-			send_expansion_short(i, FAV_ICON_NONE, pte);
-		}
-	}
 }
 
 static int is_key_favorite(struct unistim_device *d, int fav)
@@ -1539,7 +1430,7 @@ static int send_retransmit(struct unistimsession *pte)
 		 i < pte->last_buf_available; i++) {
 		if (i < 0) {
 			ast_log(LOG_WARNING,
-					"Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%.4x last_seq_ack = #0x%.4x\n",
+					"Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%04x last_seq_ack = #0x%04x\n",
 					pte->last_buf_available, (unsigned)pte->seq_server, (unsigned)pte->last_seq_ack);
 			continue;
 		}
@@ -1549,7 +1440,7 @@ static int send_retransmit(struct unistimsession *pte)
 			unsigned short seq;
 
 			seq = ntohs(sbuf[1]);
-			ast_verb(0, "Retransmit slot #%d (seq=#0x%.4x), last ack was #0x%.4x\n", i,
+			ast_verb(0, "Retransmit slot #%d (seq=#0x%04x), last ack was #0x%04x\n", i,
 						(unsigned)seq, (unsigned)pte->last_seq_ack);
 		}
 		send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
@@ -1560,7 +1451,8 @@ static int send_retransmit(struct unistimsession *pte)
 }
 
 /* inverse : TEXT_INVERSE : yes, TEXT_NORMAL  : no */
-static void send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
+static void
+send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
 		 const char *text)
 {
 	int i;
@@ -1611,6 +1503,7 @@ static void send_text_status(struct unistimsession *pte, const char *text)
 		}
 	}
 
+
 	memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
 	i = strlen(text);
 	if (i > STATUS_LENGTH_MAX) {
@@ -1621,6 +1514,10 @@ static void send_text_status(struct unistimsession *pte, const char *text)
 
 }
 
+/* led values in hexa : 0 = bar off, 1 = bar on, 2 = bar 1s on/1s off, 3 = bar 2.5s on/0.5s off
+ * 4 = bar 0.6s on/0.3s off, 5 = bar 0.5s on/0.5s off, 6 = bar 2s on/0.5s off
+ * 7 = bar off, 8 = speaker off, 9 = speaker on, 10 = headphone off, 11 = headphone on
+ * 18 = mute off, 19 mute on */
 static void send_led_update(struct unistimsession *pte, unsigned char led)
 {
 	BUFFSEND;
@@ -1632,22 +1529,6 @@ static void send_led_update(struct unistimsession *pte, unsigned char led)
 	send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
 }
 
-static void send_mute(struct unistimsession *pte, unsigned char mute)
-{
-/*
-	0x00 = unmute TX, 0x01 = mute TX
-	0x20 = unmute RX, 0x21 = mute RX
-*/
-	BUFFSEND;
-	if (unistimdebug) {
-		ast_verb(0, "Sending mute packet (%x)\n", (unsigned)mute);
-	}
-	memcpy(buffsend + SIZE_HEADER, packet_send_mute, sizeof(packet_send_mute));
-	buffsend[9] = mute;
-	send_client(SIZE_HEADER + sizeof(packet_send_mute), buffsend, pte);
-}
-
-
 /* output = OUTPUT_HANDSET, OUTPUT_HEADPHONE or OUTPUT_SPEAKER
  * volume = VOLUME_LOW, VOLUME_NORMAL, VOLUME_INSANELY_LOUD
  * mute = MUTE_OFF, MUTE_ON */
@@ -1656,7 +1537,6 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
 				 unsigned char mute)
 {
 	BUFFSEND;
-	int mute_icon = -1;
 	if (unistimdebug) {
 		ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n",
 			(unsigned)output, (unsigned)volume, (unsigned)mute);
@@ -1664,8 +1544,10 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
 	memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
 		   sizeof(packet_send_select_output));
 	buffsend[9] = output;
-	if (output == OUTPUT_SPEAKER && volume == VOLUME_LOW) {
+	if (output == OUTPUT_SPEAKER) {
 		volume = VOLUME_LOW_SPEAKER;
+	} else {
+		volume = VOLUME_LOW;
 	}
 	buffsend[10] = volume;
 	if (mute == MUTE_ON_DISCRET) {
@@ -1674,33 +1556,53 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
 		buffsend[11] = mute;
 	}
 	send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
+	if (mute == MUTE_OFF) {
+		send_led_update(pte, 0x18);
+	} else if (mute == MUTE_ON) {
+		send_led_update(pte, 0x19);
+	}
+	pte->device->mute = mute;
 	if (output == OUTPUT_HANDSET) {
-		mute_icon = (mute == MUTE_ON) ? FAV_ICON_ONHOLD_BLACK : FAV_ICON_OFFHOOK_BLACK;
-		send_led_update(pte, LED_SPEAKER_OFF);
-		send_led_update(pte, LED_HEADPHONE_OFF);
+		if (mute == MUTE_ON) {
+			change_favorite_icon(pte, FAV_ICON_ONHOLD_BLACK);
+		} else {
+			change_favorite_icon(pte, FAV_ICON_OFFHOOK_BLACK);
+		}
+		send_led_update(pte, 0x08);
+		send_led_update(pte, 0x10);
 	} else if (output == OUTPUT_HEADPHONE) {
-		mute_icon = (mute == MUTE_ON)? FAV_ICON_HEADPHONES_ONHOLD : FAV_ICON_HEADPHONES;
-		send_led_update(pte, LED_SPEAKER_OFF);
-		send_led_update(pte, LED_HEADPHONE_ON);
+		if (mute == MUTE_ON) {
+			change_favorite_icon(pte, FAV_ICON_HEADPHONES_ONHOLD);
+		} else {
+			change_favorite_icon(pte, FAV_ICON_HEADPHONES);
+		}
+		send_led_update(pte, 0x08);
+		send_led_update(pte, 0x11);
 	} else if (output == OUTPUT_SPEAKER) {
-		send_led_update(pte, LED_SPEAKER_ON);
-		send_led_update(pte, LED_HEADPHONE_OFF);
+		send_led_update(pte, 0x10);
+		send_led_update(pte, 0x09);
 		if (pte->device->receiver_state == STATE_OFFHOOK) {
-			mute_icon = (mute == MUTE_ON)? FAV_ICON_SPEAKER_ONHOLD_BLACK : FAV_ICON_SPEAKER_ONHOOK_BLACK;
+			if (mute == MUTE_ON) {
+				change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
+			} else {
+				change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOOK_BLACK);
+			}
 		} else {
-			mute_icon = (mute == MUTE_ON)? FAV_ICON_SPEAKER_ONHOLD_BLACK : FAV_ICON_SPEAKER_OFFHOOK_BLACK;
+			if (mute == MUTE_ON) {
+				change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
+			} else {
+				change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
+			}
 		}
 	} else {
 		ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
 	}
-	if (mute_icon != -1) {
-		change_favorite_icon(pte, mute_icon);
-	}
 	if (output != pte->device->output) {
 		pte->device->previous_output = pte->device->output;
 	}
 	pte->device->output = output;
 }
+
 static void send_ring(struct unistimsession *pte, char volume, char style)
 {
 	BUFFSEND;
@@ -1737,6 +1639,7 @@ static void send_texttitle(struct unistimsession *pte, const char *text)
 	}
 	memcpy(buffsend + 10, text, i);
 	send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
+
 }
 
 static void send_idle_clock(struct unistimsession *pte)
@@ -1744,28 +1647,6 @@ static void send_idle_clock(struct unistimsession *pte)
 	send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
 }
 
-static void send_month_labels(struct unistimsession *pte, int month)
-{
-	BUFFSEND;
-	char month_name[MONTH_LABEL_SIZE + 1];
-	int i = 0;
-	if (unistimdebug) {
-	        ast_verb(0, "Sending Month Labels\n");
-	}
-	month_name[MONTH_LABEL_SIZE] = '\0';
-	memcpy(buffsend + SIZE_HEADER, packet_send_monthlabels_download, sizeof(packet_send_monthlabels_download));
-	while (i < 2) {
-		memcpy(month_name, &monthlabels[month * MONTH_LABEL_SIZE], MONTH_LABEL_SIZE);
-		memcpy(buffsend + SIZE_HEADER + 3 + i*MONTH_LABEL_SIZE, ustmtext(month_name, pte), MONTH_LABEL_SIZE);
-		ast_log(LOG_WARNING,"%s\n", month_name);
-		ast_log(LOG_WARNING,"%s\n", ustmtext(month_name, pte));
-		month = (month + 1)%12;
-		i++;
-	}
-	send_client(SIZE_HEADER + sizeof(packet_send_monthlabels_download), buffsend, pte);
-}
-
-
 static void send_date_time(struct unistimsession *pte)
 {
 	BUFFSEND;
@@ -1782,7 +1663,6 @@ static void send_date_time(struct unistimsession *pte)
 	buffsend[12] = (unsigned char) atm.tm_hour;
 	buffsend[13] = (unsigned char) atm.tm_min;
 	send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
-	send_month_labels(pte, atm.tm_mon);
 }
 
 static void send_date_time2(struct unistimsession *pte)
@@ -1934,7 +1814,7 @@ static void unistim_line_copy(struct unistim_line *dst, struct unistim_line *src
 	struct ast_format_cap *tmp = src->cap;
 	memcpy(dst, src, sizeof(*dst)); /* this over writes the cap ptr, so we have to reset it */
 	src->cap = tmp;
-	ast_format_cap_append_from_cap(src->cap, dst->cap, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(src->cap, dst->cap);
 }
 
 static struct unistim_line *unistim_line_destroy(struct unistim_line *l)
@@ -1942,7 +1822,7 @@ static struct unistim_line *unistim_line_destroy(struct unistim_line *l)
 	if (!l) {
 		return NULL;
 	}
-	ao2_ref(l->cap, -1);
+	l->cap = ast_format_cap_destroy(l->cap);
 	ast_free(l);
 	return NULL;
 }
@@ -1954,7 +1834,7 @@ static struct unistim_line *unistim_line_alloc(void)
 		return NULL;
 	}
 
-	if (!(l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(l->cap = ast_format_cap_alloc_nolock())) {
 		ast_free(l);
 		return NULL;
 	}
@@ -2062,7 +1942,7 @@ static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
 	char addrmac[19];
 	int res = 0;
 	for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
-		sprintf(&addrmac[i], "%.2x", (unsigned) buf[tmp]);
+		sprintf(&addrmac[i], "%02hhx", buf[tmp]);
 		i += 2;
 	}
 	if (unistimdebug) {
@@ -2424,36 +2304,72 @@ static int write_history(struct unistimsession *pte, char way, char ismissed)
 	return 0;
 }
 
+static void unistim_quiet_chan(struct ast_channel *chan)
+{
+	if (chan && ast_channel_state(chan) == AST_STATE_UP) {
+		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH)) {
+			ast_moh_stop(chan);
+		} else if (ast_channel_generatordata(chan)) {
+			ast_deactivate_generator(chan);
+		}
+	}
+}
+
 static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subchannel *p2)
 {
-	RAII_VAR(struct ast_channel *, chana, NULL, ast_channel_unref);
-	RAII_VAR(struct ast_channel *, chanb, NULL, ast_channel_unref);
+	int res = 0;
+	struct ast_channel
+	 *chana = NULL, *chanb = NULL, *bridgea = NULL, *bridgeb = NULL, *peera =
+		NULL, *peerb = NULL, *peerc = NULL, *peerd = NULL;
 
 	if (!p1->owner || !p2->owner) {
 		ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
 		return -1;
 	}
-	chana = ast_channel_ref(p1->owner);
-	chanb = ast_channel_ref(p2->owner);
-
-	switch (ast_bridge_transfer_attended(chana, chanb)) {
-	case AST_BRIDGE_TRANSFER_INVALID:
-		ast_log(LOG_WARNING, "Transfer failed. Invalid bridge setup\n");
-		break;
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-		ast_log(LOG_WARNING, "Transfer not permitted\n");
-		break;
-	case AST_BRIDGE_TRANSFER_FAIL:
-		ast_log(LOG_WARNING, "Transfer encountered internal error\n");
-		break;
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		return 0;
+	chana = p1->owner;
+	chanb = p2->owner;
+	bridgea = ast_bridged_channel(chana);
+	bridgeb = ast_bridged_channel(chanb);
+
+	if (bridgea) {
+		peera = chana;
+		peerb = chanb;
+		peerc = bridgea;
+		peerd = bridgeb;
+	} else if (bridgeb) {
+		peera = chanb;
+		peerb = chana;
+		peerc = bridgeb;
+		peerd = bridgea;
+	}
+
+	if (peera && peerb && peerc && (peerb != peerc)) {
+		unistim_quiet_chan(peera);
+		unistim_quiet_chan(peerb);
+		unistim_quiet_chan(peerc);
+		if (peerd) {
+			unistim_quiet_chan(peerd);
+		}
+
+		ast_log(LOG_NOTICE, "UNISTIM transfer: trying to masquerade %s into %s\n", ast_channel_name(peerc), ast_channel_name(peerb));
+		if (ast_channel_masquerade(peerb, peerc)) {
+			ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", ast_channel_name(peerb),
+					ast_channel_name(peerc));
+			res = -1;
+		}
+		return res;
+	} else {
+		ast_log(LOG_NOTICE,
+				"Transfer attempted with no appropriate bridged calls to transfer\n");
+		if (chana) {
+			ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
+		}
+		if (chanb) {
+			ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
+		}
+		return -1;
 	}
-
-	/* Control only reaches this point if transfer has failed */
-	ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
-	ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
-	return -1;
+	return 0;
 }
 
 void change_callerid(struct unistimsession *pte, int type, char *callerid)
@@ -2537,7 +2453,7 @@ static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
 	send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
 	send_stop_timer(pte);
 	if (sub->owner) {
-		ast_queue_hold(sub->owner, NULL);
+		ast_queue_control_data(sub->owner, AST_CONTROL_HOLD, NULL, 0);
 		send_end_call(pte);
 	}
 	return;
@@ -2558,7 +2474,7 @@ static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *su
 	send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
 	send_start_timer(pte);
 	if (sub->owner) {
-		ast_queue_unhold(sub->owner);
+		ast_queue_control_data(sub->owner, AST_CONTROL_UNHOLD, NULL, 0);
 		if (sub->rtp) {
 			send_start_rtp(sub);
 		}
@@ -2638,12 +2554,10 @@ static void *unistim_ss(void *data)
 		return NULL;
 	}
 	ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number);
-	ast_channel_lock(chan);
 	ast_channel_exten_set(chan, s->device->phone_number);
-	ast_setstate(chan, AST_STATE_RING);
-	ast_channel_unlock(chan);
 	ast_copy_string(s->device->redial_number, s->device->phone_number,
 					sizeof(s->device->redial_number));
+	ast_setstate(chan, AST_STATE_RING);
 	res = ast_pbx_run(chan);
 	if (res) {
 		ast_log(LOG_WARNING, "PBX exited non-zero\n");
@@ -2703,15 +2617,15 @@ static void send_start_rtp(struct unistim_subchannel *sub)
 	if (unistimdebug) {
 		ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n",
 			 ast_inet_ntoa(us.sin_addr),
-			 htons(us.sin_port), ast_format_get_name(ast_channel_readformat(sub->owner)));
+			 htons(us.sin_port), ast_getformatname(ast_channel_readformat(sub->owner)));
 		ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
 					ast_inet_ntoa(public.sin_addr));
 	}
 
 	pte = sub->parent->parent->session;
 	codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0);
-	if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) ||
-		(ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) {
+	if ((ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) ||
+		(ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW)) {
 		if (unistimdebug) {
 			ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec);
 		}
@@ -2808,17 +2722,17 @@ static void send_start_rtp(struct unistim_subchannel *sub)
 		/* Codec */
 		buffsend[40] = codec;
 		buffsend[41] = codec;
-		if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+		if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) {
 			buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
-		} else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+		} else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW) {
 			buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
-		} else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
+		} else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G723_1) {
 			buffsend[42] = 2;       /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */
-		} else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
+		} else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G729A) {
 			buffsend[42] = 2;       /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */
 		} else {
 			ast_log(LOG_WARNING, "Unsupported codec %s!\n",
-				ast_format_get_name(ast_channel_readformat(sub->owner)));
+					ast_getformatname(ast_channel_readformat(sub->owner)));
 		}
 		/* Source port for transmit RTP and Destination port for receiving RTP */
 		buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
@@ -2872,7 +2786,6 @@ static void start_rtp(struct unistim_subchannel *sub)
 		return;
 	}
 	ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
-	ast_rtp_instance_set_channel_id(sub->rtp, ast_channel_uniqueid(sub->owner));
 	ast_channel_internal_fd_set(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
 	ast_channel_internal_fd_set(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
 	ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
@@ -2887,20 +2800,18 @@ static void start_rtp(struct unistim_subchannel *sub)
 	sin.sin_port = htons(find_rtp_port(sub));
 	ast_sockaddr_from_sin(&sin_tmp, &sin);
 	ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
-	if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner)) == AST_FORMAT_CMP_NOT_EQUAL) {
-		struct ast_format *tmpfmt;
-		struct ast_str *cap_buf = ast_str_alloca(64);
-
-		tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(sub->owner), 0);
+	if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner))) {
+		struct ast_format tmpfmt;
+		char tmp[256];
+		ast_best_codec(ast_channel_nativeformats(sub->owner), &tmpfmt);
 		ast_log(LOG_WARNING,
 				"Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n",
-				ast_format_get_name(ast_channel_readformat(sub->owner)),
-				ast_format_get_name(tmpfmt),
-				ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf));
+				ast_getformatname(ast_channel_readformat(sub->owner)),
+				ast_getformatname(&tmpfmt),
+				ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)));
 
-		ast_channel_set_readformat(sub->owner, tmpfmt);
-		ast_channel_set_writeformat(sub->owner, tmpfmt);
-        ao2_ref(tmpfmt, -1);
+                ast_format_copy(ast_channel_readformat(sub->owner), &tmpfmt);
+                ast_format_copy(ast_channel_writeformat(sub->owner), &tmpfmt);
 	}
 	send_start_rtp(sub);
 	ast_mutex_unlock(&sub->lock);
@@ -2962,7 +2873,7 @@ static void show_phone_number(struct unistimsession *pte)
 	send_text(line, TEXT_NORMAL, pte, tmp);
 	send_blink_cursor(pte);
 	send_cursor_pos(pte, (unsigned char) (line + offset));
-	send_led_update(pte, LED_BAR_OFF);
+	send_led_update(pte, 0);
 }
 
 static void handle_dial_page(struct unistimsession *pte)
@@ -2976,7 +2887,7 @@ static void handle_dial_page(struct unistimsession *pte)
 			ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
 							sizeof(pte->device->phone_number));
 			show_phone_number(pte);
-			send_led_update(pte, LED_BAR_OFF);
+			send_led_update(pte, 0);
 			return;
 		}
 	} else {
@@ -3005,7 +2916,7 @@ static void handle_dial_page(struct unistimsession *pte)
 	change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
 	send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
 	pte->device->missed_call = 0;
-	send_led_update(pte, LED_BAR_OFF);
+	send_led_update(pte, 0);
 	pte->device->lastmsgssent = -1;
 	return;
 }
@@ -3054,9 +2965,15 @@ static void transfer_call_step1(struct unistimsession *pte)
 	if (sub->moh) {
 		ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
 	} else {
-		ast_queue_hold(sub->owner, sub->parent->musicclass);
-		sub->moh = 1;
-		sub->subtype = SUB_THREEWAY;
+		if (ast_bridged_channel(sub->owner)) {
+			ast_moh_start(ast_bridged_channel(sub->owner),
+						  sub->parent->musicclass, NULL);
+			sub->moh = 1;
+			sub->subtype = SUB_THREEWAY;
+		} else {
+			ast_log(LOG_WARNING, "Unable to find peer subchannel for music on hold\n");
+			return;
+		}
 	}
 	sub_start_silence(pte, sub);
 	handle_dial_page(pte);
@@ -3080,7 +2997,7 @@ static void transfer_cancel_step2(struct unistimsession *pte)
 		}
 		if (sub->owner) {
 			swap_subs(sub, sub_trans);
-			ast_queue_unhold(sub_trans->owner);
+			ast_moh_stop(ast_bridged_channel(sub_trans->owner));
 			sub_trans->moh = 0;
 			sub_trans->subtype = SUB_REAL;
 			sub->subtype = SUB_THREEWAY;
@@ -3126,7 +3043,7 @@ static void handle_call_outgoing(struct unistimsession *s)
 		sub_stop_silence(s, sub);
 		send_tone(s, 0, 0);
 		/* Make new channel */
-		c = unistim_new(sub_trans, AST_STATE_DOWN, NULL, NULL);
+		c = unistim_new(sub_trans, AST_STATE_DOWN, NULL);
 		if (!c) {
 			ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", sub->parent);
 			return;
@@ -3167,7 +3084,7 @@ static void handle_call_outgoing(struct unistimsession *s)
 	}
 	if (!(sub = unistim_alloc_sub(s->device, SUB_REAL))) {
 		ast_log(LOG_WARNING, "Unable to allocate subchannel!\n");
-		return;
+		return;	    
 	}
 	sub->parent = s->device->sline[softkey];
 	s->device->ssub[softkey] = sub;
@@ -3179,25 +3096,11 @@ static void handle_call_outgoing(struct unistimsession *s)
 	send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
 	s->device->selected = -1;
 	if (!sub->owner) {		      /* A call is already in progress ? */
-		RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-		const char *pickupexten;
-
-		c = unistim_new(sub, AST_STATE_DOWN, NULL, NULL);   /* No, starting a new one */
+		c = unistim_new(sub, AST_STATE_DOWN, NULL);   /* No, starting a new one */
 		if (!sub->rtp) { /* Need to start RTP before calling ast_pbx_run */
 			start_rtp(sub);
 		}
-		if (c) {
-			ast_channel_lock(c);
-			pickup_cfg = ast_get_chan_features_pickup_config(c);
-			if (!pickup_cfg) {
-				ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-				pickupexten = "";
-			} else {
-				pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-			}
-			ast_channel_unlock(c);
-		}
-		if (c && !strcmp(s->device->phone_number, pickupexten)) {
+		if (c && !strcmp(s->device->phone_number, ast_pickup_ext())) {
 			if (unistimdebug) {
 				ast_verb(0, "Try to pickup in unistim_new\n");
 			}
@@ -3325,28 +3228,27 @@ static int unistim_do_senddigit(struct unistimsession *pte, char digit)
 
 	/* Send DTMF indication _before_ playing sounds */
 	ast_queue_frame(sub->owner, &f);
+
 	if (unistimdebug) {
-		ast_verb(0, "Send Digit %c (%i ms)\n", digit, pte->device->dtmfduration);
-	}
-	if (pte->device->dtmfduration > 0) {
-		row = (digit - '1') % 3;
-		col = (digit - '1' - row) / 3;
-		if (digit >= '1' && digit <='9') {
-			send_tone(pte, dtmf_row[row], dtmf_col[col]);
-		} else if (digit >= 'A' && digit <= 'D') {
-			send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
-		} else if (digit == '*') {
-			send_tone(pte, dtmf_row[3], dtmf_col[0]);
-		} else if (digit == '0') {
-			send_tone(pte, dtmf_row[3], dtmf_col[1]);
-		} else if (digit == '#') {
-			send_tone(pte, dtmf_row[3], dtmf_col[2]);
-		} else {
-			send_tone(pte, 500, 2000);
-		}
-		usleep(pte->device->dtmfduration * 1000);	 /* XXX Less than perfect, blocking an important thread is not a good idea */
-		send_tone(pte, 0, 0);
+		ast_verb(0, "Send Digit %c\n", digit);
+	}
+	row = (digit - '1') % 3;
+	col = (digit - '1' - row) / 3;
+	if (digit >= '1' && digit <='9') {
+		send_tone(pte, dtmf_row[row], dtmf_col[col]);
+	} else if (digit >= 'A' && digit <= 'D') {
+		send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
+	} else if (digit == '*') {
+		send_tone(pte, dtmf_row[3], dtmf_col[0]);
+	} else if (digit == '0') {
+		send_tone(pte, dtmf_row[3], dtmf_col[1]);
+	} else if (digit == '#') {
+		send_tone(pte, dtmf_row[3], dtmf_col[2]);
+	} else {
+		send_tone(pte, 500, 2000);
 	}
+	usleep(150000);			 /* XXX Less than perfect, blocking an important thread is not a good idea */
+	send_tone(pte, 0, 0);
 	return 0;
 }
 
@@ -3464,6 +3366,20 @@ static void key_call(struct unistimsession *pte, char keycode)
 			send_select_output(pte, pte->device->previous_output, pte->device->volume,
 							 MUTE_OFF);
 		break;
+	case KEY_MUTE:
+		if (!sub->owner) {
+			ast_log(LOG_WARNING, "Unable to find channel for music on hold\n");
+			return;
+		}
+		if (!sub->moh) {
+			if (pte->device->mute == MUTE_ON) {
+				send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
+			} else {
+				send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
+			}
+			break;
+		}
+		break;
 	case KEY_ONHOLD:
 		if (!sub) {
 			if(pte->device->ssub[pte->device->selected]) {
@@ -3557,9 +3473,9 @@ static void key_dial_page(struct unistimsession *pte, char keycode)
 		pte->device->phone_number[i + 1] = 0;
 		show_phone_number(pte);
 
-		if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) &&
+		if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) && 
 			!ast_matchmore_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL)) {
-			keycode = KEY_FUNC1;
+		    keycode = KEY_FUNC1;
 		} else {
 			if (pte->device->interdigit_timer) {
 				pte->device->nextdial = get_tick_count() + pte->device->interdigit_timer;
@@ -3579,8 +3495,8 @@ static void key_dial_page(struct unistimsession *pte, char keycode)
 			show_main_page(pte);
 		} else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
 			pte->device->call_forward[0] = '\0';
-			send_led_update(pte, LED_SPEAKER_OFF);
-			send_led_update(pte, LED_HEADPHONE_OFF);
+			send_led_update(pte, 0x08);
+			send_led_update(pte, 0x10);
 			show_main_page(pte);
 		}
 		return;
@@ -3597,9 +3513,13 @@ static void key_dial_page(struct unistimsession *pte, char keycode)
 		break;
 	case KEY_HANGUP:
 		if (sub && sub->owner) {
+			struct ast_channel *bridgepeer = NULL;
+
 			sub_stop_silence(pte, sub);
 			send_tone(pte, 0, 0);
-			ast_queue_unhold(sub->owner);
+			if ((bridgepeer = ast_bridged_channel(sub->owner))) {
+				ast_moh_stop(bridgepeer);
+			}
 			sub->moh = 0;
 			sub->subtype = SUB_REAL;
 			pte->state = STATE_CALL;
@@ -3607,10 +3527,10 @@ static void key_dial_page(struct unistimsession *pte, char keycode)
 			send_text_status(pte, ustmtext("       Transf        Hangup", pte));
 			send_callerid_screen(pte, sub);
 		} else {
-			send_led_update(pte, LED_SPEAKER_OFF);
-			send_led_update(pte, LED_HEADPHONE_OFF);
+			send_led_update(pte, 0x08);
+			send_led_update(pte, 0x10);
 			show_main_page(pte);
-		}
+                }
 		break;
 	case KEY_FAV0:
 	case KEY_FAV1:
@@ -4083,14 +4003,14 @@ static void show_main_page(struct unistimsession *pte)
 	}
 
 	pte->state = STATE_MAINPAGE;
-	send_led_update(pte, LED_BAR_OFF);
+	send_led_update(pte, 0);
 	pte->device->lastmsgssent = -1;
 
 	send_tone(pte, 0, 0);
 	send_stop_timer(pte); /* case of holding call */
 	send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
-	send_led_update(pte, LED_SPEAKER_OFF);
-	send_led_update(pte, LED_HEADPHONE_OFF);
+	send_led_update(pte, 0x08);
+	send_led_update(pte, 0x10);
 
 	if (!ast_strlen_zero(pte->device->call_forward)) {
 		if (pte->device->height == 1) {
@@ -4212,17 +4132,8 @@ static void key_main_page(struct unistimsession *pte, char keycode)
 			ast_mutex_unlock(&devicelock);
 			show_extension_page(pte);
 		} else { /* Pickup function */
-			/* XXX Is there a way to get a specific channel here? */
-			RAII_VAR(struct ast_features_pickup_config *, pickup_cfg,
-					ast_get_chan_features_pickup_config(NULL), ao2_cleanup);
-
-			if (!pickup_cfg) {
-				ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-				break;
-			}
-
 			pte->device->selected = -1;
-			ast_copy_string(pte->device->phone_number, pickup_cfg->pickupexten,
+			ast_copy_string(pte->device->phone_number, ast_pickup_ext(),
 						sizeof(pte->device->phone_number));
 			handle_call_outgoing(pte);
                 }
@@ -4379,7 +4290,7 @@ static void init_phone_step2(struct unistimsession *pte)
 	}
 	memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
 	send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
-	send_led_update(pte, LED_BAR_OFF);
+	send_led_update(pte, 0);
 	send_ping(pte);
 	if (unistimdebug) {
 		ast_verb(0, "Sending init language\n");
@@ -4418,19 +4329,6 @@ static void init_phone_step2(struct unistimsession *pte)
 	return;
 }
 
-/* Toggles the state of microphone muting */
-static void microphone_mute_toggle(struct unistimsession *pte)
-{
-	if (pte->device->microphone == MUTE_OFF) {
-		pte->device->microphone = MUTE_ON;
-		send_led_update(pte, LED_MUTE_ON);
-	} else if (pte->device->microphone == MUTE_ON) {
-		pte->device->microphone = MUTE_OFF;
-		send_led_update(pte, LED_MUTE_OFF);
-	}
-	send_mute(pte, (pte->device->microphone & 0x01));
-}
-
 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
 {
 	char tmpbuf[255];
@@ -4445,7 +4343,6 @@ static void process_request(int size, unsigned char *buf, struct unistimsession
 		if (unistimdebug) {
 			ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
 		}
-		ast_copy_string(pte->firmware, (char *) (buf + 13), sizeof(pte->firmware));
 		init_phone_step2(pte);
 		return;
 	}
@@ -4480,24 +4377,13 @@ static void process_request(int size, unsigned char *buf, struct unistimsession
 		}
 		return;
 	}
-	if (!memcmp(buf + SIZE_HEADER, packet_recv_expansion_pressed_key, sizeof(packet_recv_expansion_pressed_key))) {
-		char keycode = buf[13];
-		
-		if (unistimdebug) {
-			ast_verb(0, "Expansion key pressed: keycode = 0x%.2x - current state: %s\n", (unsigned)keycode,
-						ptestate_tostr(pte->state));
-		}
-	}
 	if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
 		char keycode = buf[13];
 
 		if (unistimdebug) {
-			ast_verb(0, "Key pressed: keycode = 0x%.2x - current state: %s\n", (unsigned)keycode,
+			ast_verb(0, "Key pressed: keycode = 0x%02hhx - current state: %s\n", (unsigned char)keycode,
 						ptestate_tostr(pte->state));
 		}
-		if (keycode == KEY_MUTE) {
-			microphone_mute_toggle(pte);
-		}
 		switch (pte->state) {
 		case STATE_INIT:
 			if (unistimdebug) {
@@ -4660,15 +4546,14 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
 		return;
 	}
 	if (buf[5] != 2) {
-		ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
-				(unsigned)buf[5]);
+		ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%02hhx expected 0x02\n", tmpbuf, buf[5]);
 		return;
 	}
 	seq = ntohs(sbuf[1]);
 	if (buf[4] == 1) {
 		ast_mutex_lock(&pte->lock);
 		if (unistimdebug) {
-			ast_verb(0, "ACK received for packet #0x%.4x\n", (unsigned)seq);
+			ast_verb(6, "ACK received for packet #0x%04x\n", (unsigned)seq);
 		}
 		pte->nb_retransmit = 0;
 
@@ -4684,7 +4569,7 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
 				pte->last_seq_ack = 0;
 			} else {
 				ast_log(LOG_NOTICE,
-						"%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
+						"%s Warning : ACK received for an already ACKed packet : #0x%04x we are at #0x%04x\n",
 						tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
 			}
 			ast_mutex_unlock(&pte->lock);
@@ -4692,13 +4577,13 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
 		}
 		if (pte->seq_server < seq) {
 			ast_log(LOG_NOTICE,
-					"%s Error : ACK received for a non-existent packet : #0x%.4x\n",
+					"%s Error : ACK received for a non-existent packet : #0x%04x\n",
 					tmpbuf, (unsigned)pte->seq_server);
 			ast_mutex_unlock(&pte->lock);
 			return;
 		}
 		if (unistimdebug) {
-			ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
+			ast_verb(0, "%s ACK gap : Received ACK #0x%04x, previous was #0x%04x\n",
 						tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
 		}
 		pte->last_seq_ack = seq;
@@ -4722,7 +4607,7 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
 		}
 		if (pte->seq_phone > seq) {
 			ast_log(LOG_NOTICE,
-					"%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
+					"%s Warning : received a retransmitted packet : #0x%04x (we are at #0x%04x)\n",
 					tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
 			/* BUG ? pte->device->seq_phone = seq; */
 			/* Send ACK */
@@ -4732,29 +4617,28 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
 			return;
 		}
 		ast_log(LOG_NOTICE,
-				"%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
+				"%s Warning : we lost a packet : received #0x%04x (we are at #0x%04x)\n",
 				tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
 		return;
 	}
 	if (buf[4] == 0) {
-		ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, (unsigned)seq);
+		ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%04x\n", tmpbuf, (unsigned)seq);
 		if (pte->last_seq_ack > seq) {
 			ast_log(LOG_NOTICE,
-					"%s Error : received a request for an already ACKed packet : #0x%.4x\n",
+					"%s Error : received a request for an already ACKed packet : #0x%04x\n",
 					tmpbuf, (unsigned)pte->last_seq_ack);
 			return;
 		}
 		if (pte->seq_server < seq) {
 			ast_log(LOG_NOTICE,
-					"%s Error : received a request for a non-existent packet : #0x%.4x\n",
+					"%s Error : received a request for a non-existent packet : #0x%04x\n",
 					tmpbuf, (unsigned)pte->seq_server);
 			return;
 		}
 		send_retransmit(pte);
 		return;
 	}
-	ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
-			tmpbuf, (unsigned)buf[4]);
+	ast_log(LOG_NOTICE, "%s Unknown request : got 0x%02hhx expected 0x00,0x01 or 0x02\n", tmpbuf, buf[4]);
 	return;
 }
 
@@ -4894,7 +4778,7 @@ static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
 static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchannel *sub) {
 	ast_mutex_lock(&sub->lock);
 	ast_channel_tech_pvt_set(ast, NULL);
-	unistim_set_owner(sub, NULL);
+	sub->owner = NULL;
 	sub->alreadygone = 0;
 	ast_mutex_unlock(&sub->lock);
 	if (sub->rtp) {
@@ -4934,7 +4818,9 @@ static int unistim_hangup(struct ast_channel *ast)
 		if (unistimdebug) {
 			ast_verb(0, "Threeway call disconnected, switching to real call\n");
 		}
-		ast_queue_unhold(sub_trans->owner);
+		if (ast_bridged_channel(sub_trans->owner)) {
+			ast_moh_stop(ast_bridged_channel(sub_trans->owner));
+		}
 		sub_trans->moh = 0;
 		sub_trans->subtype = SUB_REAL;
 		swap_subs(sub_trans, sub);
@@ -5004,7 +4890,7 @@ static int unistim_hangup(struct ast_channel *ast)
 				send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
 				send_text_status(s, ustmtext("       Transf        Hangup", s));
 				send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
-
+			
 		}
 	}
 	if (s->state == STATE_CALL && sub->subtype == SUB_REAL) {
@@ -5096,7 +4982,7 @@ static int unistimsock_read(int *id, int fd, short events, void *ignore)
 					dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
 	for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
 		 dw_num_bytes_rcvdd++)
-		ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
+		ast_verb(0, "%02hhx ", buff[dw_num_bytes_rcvdd]);
 	ast_verb(0, "\n******************************************\n");
 #endif
 
@@ -5143,21 +5029,14 @@ static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
 	if (sub->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-				struct ast_str *cap_buf = ast_str_alloca(64);
-				struct ast_format_cap *caps;
-
+			if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format))) {
+				char tmp[256];
 				ast_debug(1,
 						"Oooh, format changed from %s to %s\n",
-						ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf),
-						ast_format_get_name(f->subclass.format));
-
-				caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-				if (caps) {
-					ast_format_cap_append(caps, f->subclass.format, 0);
-					ast_channel_nativeformats_set(sub->owner, caps);
-					ao2_ref(caps, -1);
-				}
+						ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)),
+						ast_getformatname(&f->subclass.format));
+
+				ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format);
 				ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
 				ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
 			}
@@ -5193,15 +5072,14 @@ static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
 			return 0;
 		}
 	} else {
-		if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-			struct ast_str *cap_buf = ast_str_alloca(64);
-
+		if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+			char tmp[256];
 			ast_log(LOG_WARNING,
 					"Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
-					ast_format_get_name(frame->subclass.format),
-					ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
-					ast_format_get_name(ast_channel_readformat(ast)),
-					ast_format_get_name(ast_channel_writeformat(ast)));
+					ast_getformatname(&frame->subclass.format),
+					ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(ast)),
+					ast_getformatname(ast_channel_readformat(ast)),
+					ast_getformatname(ast_channel_writeformat(ast)));
 			return -1;
 		}
 	}
@@ -5234,7 +5112,7 @@ static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newcha
 		return -1;
 	}
 
-	unistim_set_owner(p, newchan);
+	p->owner = newchan;
 
 	ast_mutex_unlock(&p->lock);
 
@@ -5296,7 +5174,8 @@ static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zo
 	}
 }
 
-static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
+static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, 
+	size_t datalen)
 {
 	struct unistim_subchannel *sub;
 	struct unistim_line *l;
@@ -5354,7 +5233,6 @@ static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
 	case AST_CONTROL_PROGRESS:
 	case AST_CONTROL_SRCUPDATE:
 	case AST_CONTROL_PROCEEDING:
-	case AST_CONTROL_UPDATE_RTP_PEER:
 		break;
 	case -1:
 		ast_playtones_stop(ast);
@@ -5367,6 +5245,7 @@ static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
 		if (sub->subtype == SUB_REAL) {
 			send_callerid_screen(s, sub);
 		}
+	case AST_CONTROL_UPDATE_RTP_PEER:
 		break;
 	case AST_CONTROL_SRCCHANGE:
 		if (sub->rtp) {
@@ -5377,7 +5256,6 @@ static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
 		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
 		/* fallthrough */
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 		return -1;
 	}
 
@@ -5652,18 +5530,27 @@ static int unistim_sendtext(struct ast_channel *ast, const char *text)
 /*--- unistim_send_mwi_to_peer: Send message waiting indication ---*/
 static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick)
 {
+	struct ast_event *event;
 	int new;
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	char *mailbox, *context;
+
+	context = mailbox = ast_strdupa(peer->mailbox);
+	strsep(&context, "@");
+	if (ast_strlen_zero(context)) {
+		context = "default";
+	}
+	event = ast_event_get_cached(AST_EVENT_MWI,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+		AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+		AST_EVENT_IE_END);
 
-	msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), peer->mailbox);
-	if (msg) {
-		struct ast_mwi_state *mwi_state = stasis_message_data(msg);
-		new = mwi_state->new_msgs;
+	if (event) {
+		new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+		ast_event_destroy(event);
 	} else { /* Fall back on checking the mailbox directly */
-		new = ast_app_has_voicemail(peer->mailbox, NULL);
+		new = ast_app_has_voicemail(peer->mailbox, "INBOX");
 	}
-	ast_debug(3, "MWI Status for mailbox %s is %d, lastmsgsent:%d\n",
-		peer->mailbox, new, peer->parent->lastmsgssent);
+	ast_debug(3, "MWI Status for mailbox %s is %d, lastmsgsent:%d\n",mailbox,new,peer->parent->lastmsgssent);
 	peer->parent->nextmsgcheck = tick + TIMER_MWI;
 
 	/* Return now if it's the same thing we told them last time */
@@ -5672,19 +5559,18 @@ static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick
 	}
 
 	peer->parent->lastmsgssent = new;
-	send_led_update(peer->parent->session, (new > 0)?LED_BAR_ON:LED_BAR_OFF);
+	send_led_update(peer->parent->session, (new > 0));
 
 	return 0;
 }
 
 /*--- unistim_new: Initiate a call in the UNISTIM channel */
 /*      called from unistim_request (calls from the pbx ) */
-static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid)
 {
-	struct ast_format_cap *caps;
 	struct ast_channel *tmp;
 	struct unistim_line *l;
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 
 	if (!sub) {
 		ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
@@ -5694,46 +5580,30 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
 		ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
 		return NULL;
 	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return NULL;
-	}
-
 	l = sub->parent;
 	tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
-		l->parent->context, assignedids, requestor, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub);
+		l->parent->context, linkedid, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub);
 	if (unistimdebug) {
 		ast_verb(0, "unistim_new sub=%u (%p) chan=%p line=%s\n", sub->subtype, sub, tmp, l->name);
 	}
 	if (!tmp) {
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
-		ao2_ref(caps, -1);
 		return NULL;
 	}
 
-	ast_channel_stage_snapshot(tmp);
-
-	if (ast_format_cap_count(l->cap)) {
-		ast_format_cap_append_from_cap(caps, l->cap, AST_MEDIA_TYPE_UNKNOWN);
-	} else {
-		ast_format_cap_append_from_cap(caps, global_cap, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap);
+	if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
+		ast_format_cap_copy(ast_channel_nativeformats(tmp), global_cap);
 	}
-	ast_channel_nativeformats_set(tmp, caps);
-	ao2_ref(caps, -1);
-
-	tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
+	ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
 
 	if (unistimdebug) {
-		struct ast_str *native_buf = ast_str_alloca(64);
-		struct ast_str *cap_buf = ast_str_alloca(64);
-		struct ast_str *global_buf = ast_str_alloca(64);
-
+		char tmp1[256], tmp2[256], tmp3[256];
 		ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
-			ast_format_get_name(tmpfmt),
-			ast_format_cap_get_names(ast_channel_nativeformats(tmp), &native_buf),
-			ast_format_cap_get_names(l->cap, &cap_buf),
-			ast_format_cap_get_names(global_cap, &global_buf));
+			ast_getformatname(&tmpfmt),
+			ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(tmp)),
+			ast_getformatname_multiple(tmp2, sizeof(tmp2), l->cap),
+			ast_getformatname_multiple(tmp3, sizeof(tmp3), global_cap));
 	}
 	if ((sub->rtp) && (sub->subtype == 0)) {
 		if (unistimdebug) {
@@ -5751,20 +5621,17 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
 		ast_channel_rings_set(tmp, 1);
 	}
 	ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
-
-	ast_channel_set_writeformat(tmp, tmpfmt);
-	ast_channel_set_rawwriteformat(tmp, tmpfmt);
-	ast_channel_set_readformat(tmp, tmpfmt);
-	ast_channel_set_rawreadformat(tmp, tmpfmt);
-	ao2_ref(tmpfmt, -1);
-
+	ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
 	ast_channel_tech_pvt_set(tmp, sub);
 	ast_channel_tech_set(tmp, &unistim_tech);
 
 	if (!ast_strlen_zero(l->parent->language)) {
 		ast_channel_language_set(tmp, l->parent->language);
 	}
-	unistim_set_owner(sub, tmp);
+	sub->owner = tmp;
 	ast_update_use_count();
 	ast_channel_callgroup_set(tmp, l->callgroup);
 	ast_channel_pickupgroup_set(tmp, l->pickupgroup);
@@ -5784,10 +5651,6 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
 		}
 	}
 	ast_channel_priority_set(tmp, 1);
-
-	ast_channel_stage_snapshot_done(tmp);
-	ast_channel_unlock(tmp);
-
 	if (state != AST_STATE_DOWN) {
 		if (unistimdebug) {
 			ast_verb(0, "Starting pbx in unistim_new\n");
@@ -5802,14 +5665,6 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
 	return tmp;
 }
 
-static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan)
-{
-	sub->owner = chan;
-	if (sub->rtp) {
-		ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
-	}
-}
-
 static void *do_monitor(void *data)
 {
 	struct unistimsession *cur = NULL;
@@ -5931,21 +5786,19 @@ static int restart_monitor(void)
 
 /*--- unistim_request: PBX interface function ---*/
 /* UNISTIM calls initiated by the PBX arrive here */
-static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest,
+static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest,
 										   int *cause)
 {
 	struct unistim_subchannel *sub, *sub_ring, *sub_trans;
 	struct unistim_device *d;
 	struct ast_channel *tmpc = NULL;
 	char tmp[256];
+	char tmp2[256];
 
-	if (!(ast_format_cap_iscompatible(cap, global_cap))) {
-		struct ast_str *cap_buf = ast_str_alloca(64);
-		struct ast_str *global_buf = ast_str_alloca(64);
+	if (!(ast_format_cap_has_joint(cap, global_cap))) {
 		ast_log(LOG_NOTICE,
 				"Asked to get a channel of unsupported format %s while capability is %s\n",
-				ast_format_cap_get_names(cap, &cap_buf),
-				ast_format_cap_get_names(global_cap, &global_buf));
+				ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_getformatname_multiple(tmp, sizeof(tmp), global_cap));
 		return NULL;
 	}
 
@@ -5996,9 +5849,8 @@ static struct ast_channel *unistim_request(const char *type, struct ast_format_c
 	}
 	sub->subtype = SUB_RING;
 	sub->softkey = -1;
-
-	ast_format_cap_append_from_cap(sub->parent->cap, cap, AST_MEDIA_TYPE_UNKNOWN);
-	tmpc = unistim_new(sub, AST_STATE_DOWN, assignedids, requestor);
+	ast_format_cap_copy(sub->parent->cap, cap);
+	tmpc = unistim_new(sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
 	if (!tmpc) {
 		ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
 	}
@@ -6016,7 +5868,7 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	struct unistim_line *line;
 	struct unistim_subchannel *sub;
 	struct unistimsession *s;
-	struct ast_str *cap_buf = ast_str_alloca(64);
+	struct ast_channel *tmp;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -6047,10 +5899,11 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_
 				device, device->selected, device->height);
 		AST_LIST_LOCK(&device->lines);
 		AST_LIST_TRAVERSE(&device->lines,line,list) {
+			char tmp2[256];
 			ast_cli(a->fd,
 					"->name=%s fullname=%s exten=%s callid=%s cap=%s line=%p\n",
 					line->name, line->fullname, line->exten, line->cid_num,
-					ast_format_cap_get_names(line->cap, &cap_buf), line);
+					ast_getformatname_multiple(tmp2, sizeof(tmp2), line->cap), line);
 		}
 		AST_LIST_UNLOCK(&device->lines);
 
@@ -6059,9 +5912,14 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_
 			if (!sub) {
 				continue;
 			}
+			if (!sub->owner) {
+				tmp = (void *) -42;
+			} else {
+				tmp = ast_channel_internal_bridged_channel(sub->owner);
+			}
 			ast_cli(a->fd,
-					"-->subtype=%s chan=%p rtp=%p line=%p alreadygone=%d softkey=%d\n",
-					subtype_tostr(sub->subtype), sub->owner, sub->rtp, sub->parent,
+					"-->subtype=%s chan=%p rtp=%p bridge=%p line=%p alreadygone=%d softkey=%d\n",
+					subtype_tostr(sub->subtype), sub->owner, sub->rtp, tmp, sub->parent,
 					sub->alreadygone, sub->softkey);
 		}
 		AST_LIST_UNLOCK(&device->subs);
@@ -6110,13 +5968,12 @@ static char *unistim_show_devices(struct ast_cli_entry *e, int cmd, struct ast_c
 	if (a->argc != e->args)
 		return CLI_SHOWUSAGE;
 
-	ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %-15.15s %s\n", "Name/username", "MAC", "Host", "Firmware", "Status");
+	ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n", "Name/username", "MAC", "Host", "Status");
 	ast_mutex_lock(&devicelock);
 	while (device) {
-		ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %-15.15s %s\n",
+		ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n",
 			device->name, device->id,
 			(!device->session) ? "(Unspecified)" : ast_inet_ntoa(device->session->sin.sin_addr),
-			(!device->session) ? "(Unspecified)" : device->session->firmware,
 			(!device->session) ? "UNKNOWN" : "OK");
 		device = device->next;
 	}
@@ -6193,7 +6050,7 @@ static char *unistim_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	case CLI_INIT:
 		e->command = "unistim set debug {on|off}";
 		e->usage =
-			"Usage: unistim set debug\n"
+			"Usage: unistim set debug\n" 
 			"       Display debug messages.\n";
 		return NULL;
 
@@ -6226,7 +6083,7 @@ static char *unistim_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	case CLI_INIT:
 		e->command = "unistim reload";
 		e->usage =
-			"Usage: unistim reload\n"
+			"Usage: unistim reload\n" 
 			"       Reloads UNISTIM configuration from unistim.conf\n";
 		return NULL;
 
@@ -6299,12 +6156,12 @@ static int parse_bookmark(const char *text, struct unistim_device *d)
 		memmove(line, line + 2, sizeof(line) - 2);
 	} else {
 		/* No position specified, looking for a free slot */
-		for (p = 0; p < FAVNUM; p++) {
+		for (p = 0; p <= 5; p++) {
 			if (!d->softkeyicon[p]) {
 				break;
 			}
 		}
-		if (p == FAVNUM) {
+		if (p > 5) {
 			ast_log(LOG_WARNING, "No more free bookmark position\n");
 			return 0;
 		}
@@ -6435,16 +6292,13 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 		}
 		ast_mutex_init(&d->lock);
 		ast_copy_string(d->name, cat, sizeof(d->name));
-		
-		ast_copy_string(d->context, DEFAULTCONTEXT, sizeof(d->context));
 		d->contrast = -1;
 		d->output = OUTPUT_HANDSET;
 		d->previous_output = OUTPUT_HANDSET;
 		d->volume = VOLUME_LOW;
-		d->microphone = MUTE_OFF;
+		d->mute = MUTE_OFF;
 		d->height = DEFAULTHEIGHT;
 		d->selected = -1;
-		d->interdigit_timer = DEFAULT_INTERDIGIT_TIMER;
 	} else {
 		/* Delete existing line information */
 		AST_LIST_LOCK(&d->lines);
@@ -6464,6 +6318,9 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 		memset(d->sline, 0, sizeof(d->sline));
 		memset(d->sp, 0, sizeof(d->sp));
 	}
+	ast_copy_string(d->context, DEFAULTCONTEXT, sizeof(d->context));
+	d->selected = -1;
+	d->interdigit_timer = DEFAULT_INTERDIGIT_TIMER;
 	linelabel[0] = '\0';
 	dateformat = 1;
 	timeformat = 1;
@@ -6475,7 +6332,6 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 	cwstyle = 2;
 	nbsoftkey = 0;
 	linecnt = 0;
-	d->dtmfduration = 0;
 	while (v) {
 		if (!strcasecmp(v->name, "rtp_port")) {
 			d->rtp_port = atoi(v->value);
@@ -6511,8 +6367,6 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 			}
 		} else if (!strcasecmp(v->name, "nat")) {
 			d->nat = ast_true(v->value);
-		} else if (!strcasecmp(v->name, "hasexp")) {
-			d->hasexp = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "ringvolume")) {
 			ringvolume = atoi(v->value);
 		} else if (!strcasecmp(v->name, "ringstyle")) {
@@ -6527,11 +6381,6 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 			sharpdial = ast_true(v->value) ? 1 : 0;
 		} else if (!strcasecmp(v->name, "interdigit_timer")) {
 			d->interdigit_timer = atoi(v->value);
-		} else if (!strcasecmp(v->name, "dtmf_duration")) {
-			d->dtmfduration = atoi(v->value);
-			if (d->dtmfduration > 150) {
-				d->dtmfduration = 150;
-			}
 		} else if (!strcasecmp(v->name, "callerid")) {
 			if (!strcasecmp(v->value, "asreceived")) {
 				lt->cid_num[0] = '\0';
@@ -6546,7 +6395,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 			ast_copy_string(lt->accountcode, v->value, sizeof(lt->accountcode));
 		} else if (!strcasecmp(v->name, "amaflags")) {
 			int y;
-			y = ast_channel_string2amaflag(v->value);
+			y = ast_cdr_amaflags2int(v->value);
 			if (y < 0) {
 				ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value,
 						v->lineno);
@@ -6636,7 +6485,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 						ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name);
 					}
 				}
-				ast_format_cap_append_from_cap(l->cap, global_cap, AST_MEDIA_TYPE_UNKNOWN);
+				ast_format_cap_copy(l->cap, global_cap);
 				l->parent = d;
 				linecnt++;
 				AST_LIST_LOCK(&d->lines);
@@ -6669,7 +6518,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
 		ast_log(LOG_WARNING, "Country '%s' was not found in indications.conf\n",
 				d->country);
 	}
-	d->datetimeformat = 48 + (dateformat * 4);
+	d->datetimeformat = 56 + (dateformat * 4);
 	d->datetimeformat += timeformat;
 	if ((autoprovisioning == AUTOPROVISIONING_TN) &&
 		(!ast_strlen_zero(d->extension_number))) {
@@ -6758,7 +6607,7 @@ static int reload_config(void)
 		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
 		return -1;
 	}
-
+	
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
@@ -7016,7 +6865,7 @@ static enum ast_rtp_glue_result unistim_get_rtp_peer(struct ast_channel *chan, s
 
 static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active)
 {
-	struct unistim_subchannel *sub = ast_channel_tech_pvt(chan);
+	struct unistim_subchannel *sub;
 	struct sockaddr_in them = { 0, };
 	struct sockaddr_in us = { 0, };
 
@@ -7024,7 +6873,7 @@ static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instanc
 		return 0;
 	}
 	
-	sub = (struct unistim_subchannel *) ast_channel_tech_pvt(chan);
+	sub = ast_channel_tech_pvt(chan);
 	if (!sub) {
 		ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
 		return -1;
@@ -7052,18 +6901,17 @@ static struct ast_rtp_glue unistim_rtp_glue = {
 int load_module(void)
 {
 	int res;
-
-	if (!(global_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	struct ast_format tmpfmt;
+	if (!(global_cap = ast_format_cap_alloc())) {
 		goto buff_failed;
 	}
-	if (!(unistim_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(unistim_tech.capabilities = ast_format_cap_alloc())) {
 		goto buff_failed;
 	}
 
-	ast_format_cap_append(global_cap, ast_format_ulaw, 0);
-	ast_format_cap_append(global_cap, ast_format_alaw, 0);
-	ast_format_cap_append_from_cap(unistim_tech.capabilities, global_cap, AST_MEDIA_TYPE_AUDIO);
-
+	ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+	ast_format_cap_copy(unistim_tech.capabilities, global_cap);
 	if (!(buff = ast_malloc(SIZE_PAGE))) {
 		goto buff_failed;
 	}
@@ -7082,10 +6930,6 @@ int load_module(void)
 
 	res = reload_config();
 	if (res) {
-		ao2_ref(unistim_tech.capabilities, -1);
-		ao2_ref(global_cap, -1);
-		ast_sched_context_destroy(sched);
-		io_context_destroy(io);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 	/* Make sure we can register our unistim channel type */
@@ -7112,11 +6956,9 @@ sched_failed:
 io_failed:
 	ast_free(buff);
 	buff = NULL;
+	global_cap = ast_format_cap_destroy(global_cap);
+	unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
 buff_failed:
-	ao2_cleanup(global_cap);
-	global_cap = NULL;
-	ao2_cleanup(unistim_tech.capabilities);
-	unistim_tech.capabilities = NULL;
 	return AST_MODULE_LOAD_FAILURE;
 }
 
@@ -7130,7 +6972,6 @@ static int unload_module(void)
 	ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
 
 	ast_channel_unregister(&unistim_tech);
-	ao2_cleanup(unistim_tech.capabilities);
 	ast_rtp_glue_unregister(&unistim_rtp_glue);
 
 	ast_mutex_lock(&monlock);
@@ -7148,7 +6989,8 @@ static int unload_module(void)
 	if (unistimsock > -1) {
 		close(unistimsock);
 	}
-	ao2_ref(global_cap, -1);
+	global_cap = ast_format_cap_destroy(global_cap);
+	unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
 
 	return 0;
 }
@@ -7171,7 +7013,6 @@ int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
     .load = load_module,
     .unload = unload_module,
     .reload = reload,
diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc
index a04f89d..87b85a4 100644
--- a/channels/chan_vpb.cc
+++ b/channels/chan_vpb.cc
@@ -29,24 +29,6 @@
  * \ingroup channel_drivers
  */
 
-/*! \li \ref chan_vpb.cc uses the configuration file \ref vpb.conf
- * \addtogroup configuration_file
- */
-
-/*! \page vpb.conf vpb.conf
- * \verbinclude vpb.conf.sample
- */
-
-/*
- * XXX chan_vpb needs its native bridge code converted to the
- * new bridge technology scheme.  The chan_dahdi native bridge
- * code can be used as an example.  It is unlikely that this
- * will ever get done.
- *
- * The existing native bridge code is marked with the
- * VPB_NATIVE_BRIDGING conditional.
- */
-
 /*** MODULEINFO
 	<depend>vpb</depend>
 	<defaultenabled>no</defaultenabled>
@@ -59,7 +41,7 @@ extern "C" {
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
@@ -71,7 +53,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #include "asterisk/dsp.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"
-#include "asterisk/format_cache.h"
 }
 
 #include <sys/socket.h>
@@ -348,9 +329,9 @@ static struct vpb_pvt {
 
 } *iflist = NULL;
 
-static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
+static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, const char *context, const char *linkedid);
 static void *do_chanreads(void *pvt);
-static struct ast_channel *vpb_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *vpb_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
 static int vpb_digit_begin(struct ast_channel *ast, char digit);
 static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int vpb_call(struct ast_channel *ast, const char *dest, int timeout);
@@ -358,6 +339,7 @@ static int vpb_hangup(struct ast_channel *ast);
 static int vpb_answer(struct ast_channel *ast);
 static struct ast_frame *vpb_read(struct ast_channel *ast);
 static int vpb_write(struct ast_channel *ast, struct ast_frame *frame);
+static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
 static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 
@@ -379,6 +361,7 @@ static struct ast_channel_tech vpb_tech = {
 	send_image: NULL,
 	send_html: NULL,
 	exception: NULL,
+	bridge: ast_vpb_bridge,
 	early_bridge: NULL,
 	indicate: vpb_indicate,
 	fixup: vpb_fixup,
@@ -387,8 +370,11 @@ static struct ast_channel_tech vpb_tech = {
 	transfer: NULL,
 	write_video: NULL,
 	write_text: NULL,
+	bridged_channel: NULL,
 	func_channel_read: NULL,
 	func_channel_write: NULL,
+	get_base_channel: NULL,
+	set_base_channel: NULL
 };
 
 static struct ast_channel_tech vpb_tech_indicate = {
@@ -409,6 +395,7 @@ static struct ast_channel_tech vpb_tech_indicate = {
 	send_image: NULL,
 	send_html: NULL,
 	exception: NULL,
+	bridge: ast_vpb_bridge,
 	early_bridge: NULL,
 	indicate: NULL,
 	fixup: vpb_fixup,
@@ -417,11 +404,13 @@ static struct ast_channel_tech vpb_tech_indicate = {
 	transfer: NULL,
 	write_video: NULL,
 	write_text: NULL,
+	bridged_channel: NULL,
 	func_channel_read: NULL,
 	func_channel_write: NULL,
+	get_base_channel: NULL,
+	set_base_channel: NULL
 };
 
-#if defined(VPB_NATIVE_BRIDGING)
 /* Can't get ast_vpb_bridge() working on v4pci without either a horrible 
 *  high pitched feedback noise or bad hiss noise depending on gain settings
 *  Get asterisk to do the bridging
@@ -621,7 +610,6 @@ static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_
 */
 	return (res == VPB_OK) ? AST_BRIDGE_COMPLETE : AST_BRIDGE_FAILED;
 }
-#endif	/* defined(VPB_NATIVE_BRIDGING) */
 
 /* Caller ID can be located in different positions between the rings depending on your Telco
  * Australian (Telstra) callerid starts 700ms after 1st ring and finishes 1.5s after first ring
@@ -767,10 +755,11 @@ static void get_callerid_ast(struct vpb_pvt *p)
 #endif
 		vpb_record_buf_start(p->handle, VPB_MULAW);
 		while ((rc == 0) && (sam_count < 8000 * 3)) {
+			struct ast_format tmpfmt;
 			vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
 			if (vrc != VPB_OK)
 				ast_log(LOG_ERROR, "%s: Caller ID couldn't read audio buffer!\n", p->dev);
-			rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), ast_format_ulaw);
+			rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
 #ifdef ANALYSE_CID
 			vpb_wave_write(ws, (char *)buf, sizeof(buf)); 
 #endif
@@ -1033,7 +1022,15 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 			break;
 
 		case AST_FRAME_CONTROL:
-			endbridge = 1;
+			if (!(p->bridge->flags & AST_BRIDGE_IGNORE_SIGS)) {
+			#if 0
+			if (f.subclass == AST_CONTROL_BUSY ||
+			f.subclass == AST_CONTROL_CONGESTION ||
+			f.subclass == AST_CONTROL_HANGUP ||
+			f.subclass == AST_CONTROL_FLASH)
+			#endif
+				endbridge = 1;
+			}
 			break;
 
 		default:
@@ -1118,7 +1115,7 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
 		break;
 	case VPB_RING:
 		if (p->mode == MODE_FXO) /* FXO port ring, start * */ {
-			vpb_new(p, AST_STATE_RING, p->context, NULL, NULL);
+			vpb_new(p, AST_STATE_RING, p->context, NULL);
 			if (UsePolarityCID != 1) {
 				if (p->callerid_type == 1) {
 					ast_verb(4, "Using VPB Caller ID\n");
@@ -1142,7 +1139,7 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
 
 	case VPB_STATION_OFFHOOK:
 		if (p->mode == MODE_IMMEDIATE) {
-			vpb_new(p,AST_STATE_RING, p->context, NULL, NULL);
+			vpb_new(p,AST_STATE_RING, p->context, NULL);
 		} else {
 			ast_verb(4, "%s: handle_notowned: playing dialtone\n", p->dev);
 			playtone(p->handle, &Dialtone);
@@ -1187,7 +1184,7 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
 			if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)){
 				ast_verb(4, "%s: handle_notowned: DTMF IDD timer out, matching on [%s] in [%s]\n", p->dev, p->ext, p->context);
 
-				vpb_new(p, AST_STATE_RING, p->context, NULL, NULL);
+				vpb_new(p, AST_STATE_RING, p->context, NULL);
 			}
 		} else if (e->data == p->ring_timer_id) {
 			/* We didnt get another ring in time! */
@@ -1263,11 +1260,11 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
 				vpb_timer_start(p->dtmfidd_timer);
 			} else {
 				ast_verb(4, "%s: handle_notowned: Matched on [%s] in [%s]\n", p->dev, p->ext , p->context);
-				vpb_new(p, AST_STATE_UP, p->context, NULL, NULL);
+				vpb_new(p, AST_STATE_UP, p->context, NULL);
 			}
 		} else if (!ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)) {
 			if (ast_exists_extension(NULL, "default", p->ext, 1, p->callerid)) {
-				vpb_new(p, AST_STATE_UP, "default", NULL, NULL);
+				vpb_new(p, AST_STATE_UP, "default", NULL);
 			} else if (!ast_canmatch_extension(NULL, "default", p->ext, 1, p->callerid)) {
 				ast_verb(4, "%s: handle_notowned: can't match anything in %s or default\n", p->dev, p->context);
 				playtone(p->handle, &Busytone);
@@ -2070,41 +2067,46 @@ static struct ast_frame *vpb_read(struct ast_channel *ast)
 
 static inline AudioCompress ast2vpbformat(struct ast_format *format)
 {
-	if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	switch (format->id) {
+	case AST_FORMAT_ALAW:
 		return VPB_ALAW;
-	} else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_SLINEAR:
 		return VPB_LINEAR;
-	} else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ULAW:
 		return VPB_MULAW;
-	} else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ADPCM:
 		return VPB_OKIADPCM;
-	} else {
+	default:
 		return VPB_RAW;
 	}
 }
 
 static inline const char * ast2vpbformatname(struct ast_format *format)
 {
-	if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	switch(format->id) {
+	case AST_FORMAT_ALAW:
 		return "AST_FORMAT_ALAW:VPB_ALAW";
-	} else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_SLINEAR:
 		return "AST_FORMAT_SLINEAR:VPB_LINEAR";
-	} else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ULAW:
 		return "AST_FORMAT_ULAW:VPB_MULAW";
-	} else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ADPCM:
 		return "AST_FORMAT_ADPCM:VPB_OKIADPCM";
-	} else {
+	default:
 		return "UNKN:UNKN";
 	}
 }
 
 static inline int astformatbits(struct ast_format *format)
 {
-	if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	switch (format->id) {
+	case AST_FORMAT_SLINEAR:
 		return 16;
-	} else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) {
+	case AST_FORMAT_ADPCM:
 		return 4;
-	} else {
+	case AST_FORMAT_ALAW:
+	case AST_FORMAT_ULAW:
+	default:
 		return 8;
 	}
 }
@@ -2141,8 +2143,7 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 /*		ast_mutex_unlock(&p->lock); */
 		return 0;
 	} else if (ast_channel_state(ast) != AST_STATE_UP) {
-		ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%s] on not up chan(state[%d])\n",
-			ast_channel_name(ast), frame->frametype, ast_format_get_name(frame->subclass.format), ast_channel_state(ast));
+		ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%s] on not up chan(state[%d])\n", ast_channel_name(ast), frame->frametype, ast_getformatname(&frame->subclass.format), ast_channel_state(ast));
 		p->lastoutput = -1;
 /*		ast_mutex_unlock(&p->lock); */
 		return 0;
@@ -2150,10 +2151,9 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 /*	ast_debug(1, "%s: vpb_write: Checked frame type..\n", p->dev); */
 
 
-	fmt = ast2vpbformat(frame->subclass.format);
+	fmt = ast2vpbformat(&frame->subclass.format);
 	if (fmt < 0) {
-		ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %s format!\n", ast_channel_name(ast),
-			ast_format_get_name(frame->subclass.format));
+		ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %s format!\n", ast_channel_name(ast), ast_getformatname(&frame->subclass.format));
 		return -1;
 	}
 
@@ -2177,7 +2177,7 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 	/* Check if we have set up the play_buf */
 	if (p->lastoutput == -1) {
 		vpb_play_buf_start(p->handle, fmt);
-		ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(frame->subclass.format));
+		ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(&frame->subclass.format));
 		p->lastoutput = fmt;
 		ast_mutex_unlock(&p->play_lock);
 		return 0;
@@ -2227,7 +2227,7 @@ static void *do_chanreads(void *pvt)
 	struct ast_frame *fr = &p->fr;
 	char *readbuf = ((char *)p->buf) + AST_FRIENDLY_OFFSET;
 	int bridgerec = 0;
-	struct ast_format *tmpfmt;
+	struct ast_format tmpfmt;
 	int readlen, res, trycnt=0;
 	AudioCompress fmt;
 	int ignore_dtmf;
@@ -2252,9 +2252,20 @@ static void *do_chanreads(void *pvt)
 		ast_verb(5, "%s: chanreads: Starting cycle ...\n", p->dev);
 		ast_verb(5, "%s: chanreads: Checking bridge \n", p->dev);
 		if (p->bridge) {
-			bridgerec = 0;
+			if (p->bridge->c0 == p->owner && (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_0))
+				bridgerec = 1;
+			else if (p->bridge->c1 == p->owner && (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_1))
+				bridgerec = 1;
+			else 
+				bridgerec = 0;
 		} else {
-			bridgerec = ast_channel_is_bridged(p->owner) ? 1 : 0;
+			ast_verb(5, "%s: chanreads: No native bridge.\n", p->dev);
+			if (ast_channel_internal_bridged_channel(p->owner)) {
+				ast_verb(5, "%s: chanreads: Got Asterisk bridge with [%s].\n", p->dev, ast_channel_name(ast_channel_internal_bridged_channel(p->owner)));
+				bridgerec = 1;
+			} else {
+				bridgerec = 0;
+			}
 		}
 
 /*		if ((p->owner->_state != AST_STATE_UP) || !bridgerec) */
@@ -2312,22 +2323,22 @@ static void *do_chanreads(void *pvt)
 		ast_mutex_unlock(&p->play_dtmf_lock);
 
 		if (p->owner) {
-			tmpfmt = ast_channel_rawreadformat(p->owner);
+			ast_format_copy(&tmpfmt, ast_channel_rawreadformat(p->owner));
 		} else {
-			tmpfmt = ast_format_slin;
+			ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);
 		}
-		fmt = ast2vpbformat(tmpfmt);
+		fmt = ast2vpbformat(&tmpfmt);
 		if (fmt < 0) {
-			ast_log(LOG_WARNING, "%s: Record failure (unsupported format %s)\n", p->dev, ast_format_get_name(tmpfmt));
+			ast_log(LOG_WARNING, "%s: Record failure (unsupported format %s)\n", p->dev, ast_getformatname(&tmpfmt));
 			return NULL;
 		}
-		readlen = VPB_SAMPLES * astformatbits(tmpfmt) / 8;
+		readlen = VPB_SAMPLES * astformatbits(&tmpfmt) / 8;
 
 		if (p->lastinput == -1) {
 			vpb_record_buf_start(p->handle, fmt);
 /*			vpb_reset_record_fifo_alarm(p->handle); */
 			p->lastinput = fmt;
-			ast_verb(2, "%s: Starting record mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(tmpfmt));
+			ast_verb(2, "%s: Starting record mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(&tmpfmt));
 			continue;
 		} else if (p->lastinput != fmt) {
 			vpb_record_buf_finish(p->handle);
@@ -2346,7 +2357,7 @@ static void *do_chanreads(void *pvt)
 				a_gain_vector(p->rxswgain - MAX_VPB_GAIN, (short *)readbuf, readlen / sizeof(short));
 			ast_verb(6, "%s: chanreads: applied gain\n", p->dev);
 
-			fr->subclass.format = tmpfmt;
+			ast_format_copy(&fr->subclass.format, &tmpfmt);
 			fr->data.ptr = readbuf;
 			fr->datalen = readlen;
 			fr->frametype = AST_FRAME_VOICE;
@@ -2421,19 +2432,20 @@ static void *do_chanreads(void *pvt)
 	return NULL;
 }
 
-static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state state, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state state, const char *context, const char *linkedid)
 {
 	struct ast_channel *tmp; 
 	char cid_num[256];
 	char cid_name[256];
+	struct ast_format tmpfmt;
 
 	if (me->owner) {
 	    ast_log(LOG_WARNING, "Called vpb_new on owned channel (%s) ?!\n", me->dev);
 	    return NULL;
 	}
 	ast_verb(4, "%s: New call for context [%s]\n", me->dev, context);
-
-	tmp = ast_channel_alloc(1, state, 0, 0, "", me->ext, me->context, assignedids, requestor, AST_AMA_NONE, "%s", me->dev);
+	    
+	tmp = ast_channel_alloc(1, state, 0, 0, "", me->ext, me->context, linkedid, 0, "%s", me->dev);
 	if (tmp) {
 		if (use_ast_ind == 1){
 			ast_channel_tech_set(tmp, &vpb_tech_indicate);
@@ -2448,9 +2460,9 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st
 		 * they are all converted to/from linear in the vpb code. Best for us to use
 		 * linear since we can then adjust volume in this modules.
 		 */
-		ast_channel_nativeformats_set(tmp, vpb_tech.capabilities);
-		ast_channel_set_rawreadformat(tmp, ast_format_slin);
-		ast_channel_set_rawwriteformat(tmp, ast_format_slin);
+		ast_format_cap_add(ast_channel_nativeformats(tmp), ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+		ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
 		if (state == AST_STATE_RING) {
 			ast_channel_rings_set(tmp, 1);
 			cid_name[0] = '\0';
@@ -2467,7 +2479,6 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st
 			ast_channel_exten_set(tmp, "s");
 		if (!ast_strlen_zero(me->language))
 			ast_channel_language_set(tmp, me->language);
-		ast_channel_unlock(tmp);
 
 		me->owner = tmp;
 
@@ -2497,24 +2508,20 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st
 	return tmp;
 }
 
-static struct ast_channel *vpb_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) 
+static struct ast_channel *vpb_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) 
 {
 	struct vpb_pvt *p;
 	struct ast_channel *tmp = NULL;
 	char *sepstr, *name;
 	const char *s;
 	int group = -1;
+	struct ast_format slin;
 
-	if (!(ast_format_cap_iscompatible_format(cap, ast_format_slin))) {
-		struct ast_str *buf;
+	ast_format_set(&slin, AST_FORMAT_SLINEAR, 0);
 
-		buf = ast_str_create(256);
-		if (!buf) {
-			return NULL;
-		}
-		ast_log(LOG_NOTICE, "Asked to create a channel for unsupported formats: %s\n",
-			ast_format_cap_get_names(cap, &buf));
-		ast_free(buf);
+	if (!(ast_format_cap_iscompatible(cap, &slin))) {
+		char tmp[256];
+		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
 		return NULL;
 	}
 
@@ -2534,13 +2541,13 @@ static struct ast_channel *vpb_request(const char *type, struct ast_format_cap *
 		if (group == -1) {
 			if (strncmp(s, p->dev + 4, sizeof p->dev) == 0) {
 				if (!p->owner) {
-					tmp = vpb_new(p, AST_STATE_DOWN, p->context, assignedids, requestor);
+					tmp = vpb_new(p, AST_STATE_DOWN, p->context, requestor ? ast_channel_linkedid(requestor) : NULL);
 					break;
 				}
 			}
 		} else {
 			if ((p->group == group) && (!p->owner)) {
-				tmp = vpb_new(p, AST_STATE_DOWN, p->context, assignedids, requestor);
+				tmp = vpb_new(p, AST_STATE_DOWN, p->context, requestor ? ast_channel_linkedid(requestor) : NULL);
 				break;
 			}
 		}
@@ -2626,33 +2633,20 @@ static int unload_module(void)
 
 	if (bridges) {
 		ast_mutex_lock(&bridge_lock);
-		memset(bridges, 0, sizeof bridges);
-		ast_mutex_unlock(&bridge_lock);
-		ast_mutex_destroy(&bridge_lock);
 		for (int i = 0; i < max_bridges; i++) {
 			ast_mutex_destroy(&bridges[i].lock);
 			ast_cond_destroy(&bridges[i].cond);
 		}
 		ast_free(bridges);
+		bridges = NULL;
+		ast_mutex_unlock(&bridge_lock);
 	}
 
-	ao2_cleanup(vpb_tech.capabilities);
-	vpb_tech.capabilities = NULL;
-	ao2_cleanup(vpb_tech_indicate.capabilities);
-	vpb_tech_indicate.capabilities = NULL;
+	ast_format_cap_destroy(vpb_tech.capabilities);
+	ast_format_cap_destroy(vpb_tech_indicate.capabilities);
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static enum ast_module_load_result load_module()
 {
 	struct ast_config *cfg;
@@ -2673,18 +2667,17 @@ static enum ast_module_load_result load_module()
 	int bal2 = -1; 
 	int bal3 = -1;
 	char * callerid = NULL;
+	struct ast_format tmpfmt;
 	int num_cards = 0;
 
-	vpb_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!vpb_tech.capabilities) {
+	if (!(vpb_tech.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	vpb_tech_indicate.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!vpb_tech_indicate.capabilities) {
+	if (!(vpb_tech_indicate.capabilities = ast_format_cap_alloc())) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	ast_format_cap_append(vpb_tech.capabilities, ast_format_slin, 0);
-	ast_format_cap_append(vpb_tech_indicate.capabilities, ast_format_slin, 0);
+	ast_format_cap_add(vpb_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_format_cap_add(vpb_tech_indicate.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 	try {
 		num_cards = vpb_get_num_cards();
 	} catch (std::exception e) {
diff --git a/channels/console_board.c b/channels/console_board.c
index b988bb6..6c920a9 100644
--- a/channels/console_board.c
+++ b/channels/console_board.c
@@ -13,7 +13,7 @@
  * the GNU General Public License Version 2. See the LICENSE file
  * at the top of the source tree.
  *
- * $Revision: 369013 $
+ * $Revision$
  */
 
 /* 
@@ -42,7 +42,7 @@
  ***/
 
 #include "asterisk.h"	/* ast_strdupa */
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"	/* ast_strdupa */
 #include "console_video.h"	/* ast_strdupa */
 
diff --git a/channels/console_gui.c b/channels/console_gui.c
index 0b9d393..916c408 100644
--- a/channels/console_gui.c
+++ b/channels/console_gui.c
@@ -1,7 +1,7 @@
 /*
  * GUI for console video.
  * The routines here are in charge of loading the keypad and handling events.
- * $Revision: 369013 $
+ * $Revision$
  */
 
 /*
diff --git a/channels/console_video.c b/channels/console_video.c
index 5d2f20d..a1db5cd 100644
--- a/channels/console_video.c
+++ b/channels/console_video.c
@@ -30,7 +30,7 @@
  * thus not compiling in AST_DEVMODE, or don't have swscale, in which case
  * you can try to compile #defining OLD_FFMPEG here.
  *
- * $Revision: 369013 $
+ * $Revision$
  */
 
 //#define DROP_PACKETS 5       /* if set, drop this % of video packets */
@@ -41,7 +41,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <sys/ioctl.h>
 #include "asterisk/cli.h"
 #include "asterisk/file.h"
diff --git a/channels/console_video.h b/channels/console_video.h
index dee0147..f88e5fa 100644
--- a/channels/console_video.h
+++ b/channels/console_video.h
@@ -17,7 +17,7 @@
 /*
  * Common header for console video support
  *
- * $Revision: 126572 $
+ * $Revision$
  */
 
 #ifndef CONSOLE_VIDEO_H
diff --git a/channels/dahdi/bridge_native_dahdi.c b/channels/dahdi/bridge_native_dahdi.c
deleted file mode 100644
index b2cd2e0..0000000
--- a/channels/dahdi/bridge_native_dahdi.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Native DAHDI bridging support.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "../sig_analog.h"
-#if defined(HAVE_PRI)
-#include "../sig_pri.h"
-#endif	/* defined(HAVE_PRI) */
-#include "../chan_dahdi.h"
-
-#include "bridge_native_dahdi.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
-#include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
-
-/* ------------------------------------------------------------------- */
-
-static const struct ast_channel_tech *dahdi_tech;
-
-struct native_pvt_chan {
-	/*! Original private. */
-	struct dahdi_pvt *pvt;
-	/*! Original private owner. */
-	struct ast_channel *owner;
-	/*! Original owner index. */
-	int index;
-	/*! Original file descriptor 0. */
-	int fd0;
-	/*! Original channel state. */
-	int state;
-	/*! Original inthreeway. */
-	unsigned int inthreeway:1;
-};
-
-struct native_pvt_bridge {
-	/*! Master channel in the native bridge. */
-	struct dahdi_pvt *master;
-	/*! Slave channel in the native bridge. */
-	struct dahdi_pvt *slave;
-	/*! TRUE if the bridge can start when ready. */
-	unsigned int saw_start:1;
-	/*! TRUE if the channels are connected in a conference. */
-	unsigned int connected:1;
-#if defined(HAVE_PRI) && defined(PRI_2BCT)
-	/*!
-	 * \brief TRUE if tried to eliminate possible PRI tromboned call.
-	 *
-	 * \note A tromboned call uses two B channels of the same ISDN
-	 * span.  One leg comes into Asterisk, the other leg goes out of
-	 * Asterisk, and Asterisk is natively bridging the two legs.
-	 */
-	unsigned int tried_trombone_removal:1;
-#endif	/* defined(HAVE_PRI) && defined(PRI_2BCT) */
-};
-
-/*!
- * \internal
- * \brief Create a bridge technology instance for a bridge.
- * \since 12.0.0
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \note On entry, bridge may or may not already be locked.
- * However, it can be accessed as if it were locked.
- */
-static int native_bridge_create(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	ast_assert(!bridge->tech_pvt);
-
-	tech_pvt = ast_calloc(1, sizeof(*tech_pvt));
-	if (!tech_pvt) {
-		return -1;
-	}
-
-	bridge->tech_pvt = tech_pvt;
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Destroy a bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \note On entry, bridge must NOT be locked.
- */
-static void native_bridge_destroy(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	tech_pvt = bridge->tech_pvt;
-	bridge->tech_pvt = NULL;
-	ast_free(tech_pvt);
-}
-
-/*!
- * \internal
- * \brief Stop native bridging activity.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- *
- * \return Nothing
- *
- * \note On entry, bridge is already locked.
- */
-static void native_stop(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *bridge_tech_pvt;
-	struct ast_bridge_channel *cur;
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		struct native_pvt_chan *chan_tech_pvt;
-
-		chan_tech_pvt = cur->tech_pvt;
-		if (!chan_tech_pvt) {
-			continue;
-		}
-
-		ast_mutex_lock(&chan_tech_pvt->pvt->lock);
-		if (chan_tech_pvt->pvt == ast_channel_tech_pvt(cur->chan)) {
-			dahdi_ec_enable(chan_tech_pvt->pvt);
-		}
-		if (chan_tech_pvt->index == SUB_REAL) {
-			dahdi_dtmf_detect_enable(chan_tech_pvt->pvt);
-		}
-		ast_mutex_unlock(&chan_tech_pvt->pvt->lock);
-	}
-
-	bridge_tech_pvt = bridge->tech_pvt;
-	dahdi_master_slave_unlink(bridge_tech_pvt->slave, bridge_tech_pvt->master, 1);
-
-	ast_debug(2, "Stop native bridging %s and %s\n",
-		ast_channel_name(AST_LIST_FIRST(&bridge->channels)->chan),
-		ast_channel_name(AST_LIST_LAST(&bridge->channels)->chan));
-}
-
-/*!
- * \internal
- * \brief Request to stop native bridging activity.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- *
- * \return Nothing
- *
- * \note On entry, bridge is already locked.
- */
-static void native_request_stop(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	tech_pvt = bridge->tech_pvt;
-	if (!tech_pvt->connected) {
-		return;
-	}
-	tech_pvt->connected = 0;
-
-	/* Now to actually stop the bridge. */
-	native_stop(bridge);
-}
-
-/*!
- * \internal
- * \brief Start native bridging activity.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- *
- * \retval 0 on success.
- * \retval -1 on error.  Could not start the bridge.
- *
- * \note On entry, bridge may or may not already be locked.
- * However, it can be accessed as if it were locked.
- */
-static int native_start(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-	struct ast_bridge_channel *bc0;
-	struct ast_bridge_channel *bc1;
-	struct native_pvt_chan *npc0;
-	struct native_pvt_chan *npc1;
-	struct ast_channel *c0;
-	struct ast_channel *c1;
-	struct dahdi_pvt *p0;
-	struct dahdi_pvt *p1;
-	struct dahdi_pvt *master;
-	struct dahdi_pvt *slave;
-	int inconf;
-	int nothing_ok;
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	bc0 = AST_LIST_FIRST(&bridge->channels);
-	bc1 = AST_LIST_LAST(&bridge->channels);
-	c0 = bc0->chan;
-	c1 = bc1->chan;
-
-	/* Lock channels and privates */
-	for (;;) {
-		ast_channel_lock(c0);
-		if (!ast_channel_trylock(c1)) {
-			p0 = ast_channel_tech_pvt(c0);
-			if (!ast_mutex_trylock(&p0->lock)) {
-				p1 = ast_channel_tech_pvt(c1);
-				if (!ast_mutex_trylock(&p1->lock)) {
-					/* Got all locks */
-					break;
-				}
-				ast_mutex_unlock(&p0->lock);
-			}
-			ast_channel_unlock(c1);
-		}
-		ast_channel_unlock(c0);
-		sched_yield();
-	}
-
-	npc0 = bc0->tech_pvt;
-	ast_assert(npc0 != NULL);
-	npc0->pvt = p0;
-	npc0->owner = p0->owner;
-	npc0->index = dahdi_get_index(c0, p0, 0);
-	npc0->fd0 = ast_channel_fd(c0, 0);
-	npc0->state = -1;
-	npc0->inthreeway = p0->subs[SUB_REAL].inthreeway;
-
-	npc1 = bc1->tech_pvt;
-	ast_assert(npc1 != NULL);
-	npc1->pvt = p1;
-	npc1->owner = p1->owner;
-	npc1->index = dahdi_get_index(c1, p1, 0);
-	npc1->fd0 = ast_channel_fd(c1, 0);
-	npc1->state = -1;
-	npc1->inthreeway = p1->subs[SUB_REAL].inthreeway;
-
-	/*
-	 * Check things that can change on the privates while in native
-	 * bridging and cause native to not activate.
-	 */
-	if (npc0->index < 0 || npc1->index < 0
-#if defined(HAVE_PRI)
-		/*
-		 * PRI nobch channels (hold and call waiting) are equivalent to
-		 * pseudo channels and cannot be nativly bridged.
-		 */
-		|| (dahdi_sig_pri_lib_handles(p0->sig)
-			&& ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
-		|| (dahdi_sig_pri_lib_handles(p1->sig)
-			&& ((struct sig_pri_chan *) p1->sig_pvt)->no_b_channel)
-#endif	/* defined(HAVE_PRI) */
-		) {
-		ast_mutex_unlock(&p0->lock);
-		ast_mutex_unlock(&p1->lock);
-		ast_channel_unlock(c0);
-		ast_channel_unlock(c1);
-		return -1;
-	}
-
-	inconf = 0;
-	nothing_ok = 1;
-	master = NULL;
-	slave = NULL;
-	if (npc0->index == SUB_REAL && npc1->index == SUB_REAL) {
-		if (p0->owner && p1->owner) {
-			/*
-			 * If we don't have a call-wait in a 3-way, and we aren't in a
-			 * 3-way, we can be master.
-			 */
-			if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
-				master = p0;
-				slave = p1;
-				inconf = 1;
-			} else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
-				master = p1;
-				slave = p0;
-				inconf = 1;
-			} else {
-				ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
-				ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
-					p0->channel,
-					npc0->index, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
-					p0->subs[SUB_REAL].inthreeway,
-					p0->channel,
-					npc0->index, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
-					p1->subs[SUB_REAL].inthreeway);
-			}
-			nothing_ok = 0;
-		}
-	} else if (npc0->index == SUB_REAL && npc1->index == SUB_THREEWAY) {
-		if (p1->subs[SUB_THREEWAY].inthreeway) {
-			master = p1;
-			slave = p0;
-			nothing_ok = 0;
-		}
-	} else if (npc0->index == SUB_THREEWAY && npc1->index == SUB_REAL) {
-		if (p0->subs[SUB_THREEWAY].inthreeway) {
-			master = p0;
-			slave = p1;
-			nothing_ok = 0;
-		}
-	} else if (npc0->index == SUB_REAL && npc1->index == SUB_CALLWAIT) {
-		/*
-		 * We have a real and a call wait.  If we're in a three way
-		 * call, put us in it, otherwise, don't put us in anything.
-		 */
-		if (p1->subs[SUB_CALLWAIT].inthreeway) {
-			master = p1;
-			slave = p0;
-			nothing_ok = 0;
-		}
-	} else if (npc0->index == SUB_CALLWAIT && npc1->index == SUB_REAL) {
-		/* Same as previous */
-		if (p0->subs[SUB_CALLWAIT].inthreeway) {
-			master = p0;
-			slave = p1;
-			nothing_ok = 0;
-		}
-	}
-	ast_debug(3, "master: %d, slave: %d, nothing_ok: %d\n",
-		master ? master->channel : 0,
-		slave ? slave->channel : 0,
-		nothing_ok);
-	if (master && slave) {
-		/*
-		 * Stop any tones, or play ringtone as appropriate.  If they are
-		 * bridged in an active threeway call with a channel that is
-		 * ringing, we should indicate ringing.
-		 */
-		if (npc1->index == SUB_THREEWAY
-			&& p1->subs[SUB_THREEWAY].inthreeway
-			&& p1->subs[SUB_REAL].owner
-			&& p1->subs[SUB_REAL].inthreeway
-			&& ast_channel_state(p1->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
-			ast_debug(2,
-				"Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
-				p0->channel, npc0->index, ast_channel_name(c0),
-				p1->channel, npc1->index, ast_channel_name(c1));
-			tone_zone_play_tone(p0->subs[npc0->index].dfd, DAHDI_TONE_RINGTONE);
-			npc1->state = ast_channel_state(p1->subs[SUB_REAL].owner);
-		} else {
-			ast_debug(2, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
-				p0->channel, npc0->index, ast_channel_name(c0),
-				p1->channel, npc1->index, ast_channel_name(c1));
-			tone_zone_play_tone(p0->subs[npc0->index].dfd, -1);
-		}
-
-		if (npc0->index == SUB_THREEWAY
-			&& p0->subs[SUB_THREEWAY].inthreeway
-			&& p0->subs[SUB_REAL].owner
-			&& p0->subs[SUB_REAL].inthreeway
-			&& ast_channel_state(p0->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
-			ast_debug(2,
-				"Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
-				p1->channel, npc1->index, ast_channel_name(c1),
-				p0->channel, npc0->index, ast_channel_name(c0));
-			tone_zone_play_tone(p1->subs[npc1->index].dfd, DAHDI_TONE_RINGTONE);
-			npc0->state = ast_channel_state(p0->subs[SUB_REAL].owner);
-		} else {
-			ast_debug(2, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
-				p1->channel, npc1->index, ast_channel_name(c1),
-				p0->channel, npc0->index, ast_channel_name(c0));
-			tone_zone_play_tone(p1->subs[npc1->index].dfd, -1);
-		}
-
-		if (npc0->index == SUB_REAL && npc1->index == SUB_REAL) {
-			if (!p0->echocanbridged || !p1->echocanbridged) {
-				/* Disable echo cancellation if appropriate */
-				dahdi_ec_disable(p0);
-				dahdi_ec_disable(p1);
-			}
-		}
-		dahdi_master_slave_link(slave, master);
-		master->inconference = inconf;
-	} else if (!nothing_ok) {
-		ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n",
-			p0->channel, subnames[npc0->index],
-			p1->channel, subnames[npc1->index]);
-	}
-	dahdi_conf_update(p0);
-	dahdi_conf_update(p1);
-
-	ast_channel_unlock(c0);
-	ast_channel_unlock(c1);
-
-	/* Native bridge failed */
-	if ((!master || !slave) && !nothing_ok) {
-		ast_mutex_unlock(&p0->lock);
-		ast_mutex_unlock(&p1->lock);
-		return -1;
-	}
-
-	if (npc0->index == SUB_REAL) {
-		dahdi_dtmf_detect_disable(p0);
-	}
-	if (npc1->index == SUB_REAL) {
-		dahdi_dtmf_detect_disable(p1);
-	}
-
-	ast_mutex_unlock(&p0->lock);
-	ast_mutex_unlock(&p1->lock);
-
-	tech_pvt = bridge->tech_pvt;
-	tech_pvt->master = master;
-	tech_pvt->slave = slave;
-
-	ast_debug(2, "Start native bridging %s and %s\n",
-		ast_channel_name(c0), ast_channel_name(c1));
-
-#if defined(HAVE_PRI) && defined(PRI_2BCT)
-	if (!tech_pvt->tried_trombone_removal) {
-		tech_pvt->tried_trombone_removal = 1;
-
-		if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
-			q931_call *q931_c0;
-			q931_call *q931_c1;
-
-			/* Try to eliminate the tromboned call. */
-			ast_mutex_lock(&p0->pri->lock);
-			ast_assert(dahdi_sig_pri_lib_handles(p0->sig));
-			ast_assert(dahdi_sig_pri_lib_handles(p1->sig));
-			q931_c0 = ((struct sig_pri_chan *) (p0->sig_pvt))->call;
-			q931_c1 = ((struct sig_pri_chan *) (p1->sig_pvt))->call;
-			if (q931_c0 && q931_c1) {
-				pri_channel_bridge(q931_c0, q931_c1);
-				ast_debug(2, "Attempt to eliminate tromboned call with %s and %s\n",
-					ast_channel_name(c0), ast_channel_name(c1));
-			}
-			ast_mutex_unlock(&p0->pri->lock);
-		}
-	}
-#endif	/* defined(HAVE_PRI) && defined(PRI_2BCT) */
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Request to start native bridging activity.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- *
- * \return Nothing
- *
- * \note On entry, bridge may or may not already be locked.
- * However, it can be accessed as if it were locked.
- */
-static void native_request_start(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-	struct ast_bridge_channel *cur;
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	tech_pvt = bridge->tech_pvt;
-
-	if (bridge->num_channels != 2 || !tech_pvt->saw_start || tech_pvt->connected) {
-		return;
-	}
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		if (cur->suspended || !cur->tech_pvt) {
-			return;
-		}
-	}
-
-	/* Actually try starting the native bridge. */
-	if (native_start(bridge)) {
-		return;
-	}
-	tech_pvt->connected = 1;
-}
-
-/*!
- * \internal
- * \brief Request a bridge technology instance start operations.
- * \since 12.0.0
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \note On entry, bridge may or may not already be locked.
- * However, it can be accessed as if it were locked.
- */
-static int native_bridge_start(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	tech_pvt = bridge->tech_pvt;
-	tech_pvt->saw_start = 1;
-
-	native_request_start(bridge);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Request a bridge technology instance stop in preparation for being destroyed.
- * \since 12.0.0
- *
- * \note On entry, bridge is already locked.
- */
-static void native_bridge_stop(struct ast_bridge *bridge)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	tech_pvt = bridge->tech_pvt;
-	if (!tech_pvt) {
-		return;
-	}
-
-	tech_pvt->saw_start = 0;
-	native_request_stop(bridge);
-}
-
-/*!
- * \internal
- * \brief Add a channel to a bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \note On entry, bridge is already locked.
- */
-static int native_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct native_pvt_chan *tech_pvt;
-	struct ast_channel *c0;
-	struct ast_channel *c1;
-
-	ast_assert(!bridge_channel->tech_pvt);
-
-	tech_pvt = ast_calloc(1, sizeof(*tech_pvt));
-	if (!tech_pvt) {
-		return -1;
-	}
-
-	bridge_channel->tech_pvt = tech_pvt;
-	native_request_start(bridge);
-
-	/*
-	 * Make the channels compatible in case the native bridge did
-	 * not start for some reason and we need to fallback to 1-1
-	 * bridging.
-	 */
-	c0 = AST_LIST_FIRST(&bridge->channels)->chan;
-	c1 = AST_LIST_LAST(&bridge->channels)->chan;
-	if (c0 == c1) {
-		return 0;
-	}
-	return ast_channel_make_compatible(c0, c1);
-}
-
-/*!
- * \internal
- * \brief Remove a channel from a bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \note On entry, bridge is already locked.
- */
-static void native_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct native_pvt_chan *tech_pvt;
-
-	native_request_stop(bridge);
-
-	tech_pvt = bridge_channel->tech_pvt;
-	bridge_channel->tech_pvt = NULL;
-	ast_free(tech_pvt);
-}
-
-/*!
- * \internal
- * \brief Suspend a channel on a bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \note On entry, bridge is already locked.
- */
-static void native_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	native_request_stop(bridge);
-}
-
-/*!
- * \internal
- * \brief Unsuspend a channel on a bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \note On entry, bridge is already locked.
- */
-static void native_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	native_request_start(bridge);
-}
-
-/*!
- * \internal
- * \brief Check if channel is compatible.
- * \since 12.0.0
- *
- * \param bridge_channel Is this channel compatible.
- *
- * \retval TRUE if channel is compatible with native DAHDI bridge.
- */
-static int native_bridge_is_capable(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_channel *chan = bridge_channel->chan;
-	struct dahdi_pvt *pvt;
-	int is_capable;
-
-	if (ao2_container_count(bridge_channel->features->dtmf_hooks)) {
-		ast_debug(2, "Channel '%s' has DTMF hooks.\n", ast_channel_name(chan));
-		return 0;
-	}
-
-	ast_channel_lock(chan);
-
-	if (dahdi_tech != ast_channel_tech(chan)) {
-		ast_debug(2, "Channel '%s' is not %s.\n",
-			ast_channel_name(chan), dahdi_tech->type);
-		ast_channel_unlock(chan);
-		return 0;
-	}
-	if (ast_channel_has_audio_frame_or_monitor(chan)) {
-		ast_debug(2, "Channel '%s' has an active monitor, audiohook, or framehook.\n",
-			ast_channel_name(chan));
-		ast_channel_unlock(chan);
-		return 0;
-	}
-	pvt = ast_channel_tech_pvt(chan);
-	if (!pvt || !pvt->sig) {
-		/* No private; or signaling is for a pseudo channel. */
-		ast_channel_unlock(chan);
-		return 0;
-	}
-
-	is_capable = 1;
-	ast_mutex_lock(&pvt->lock);
-
-	if (pvt->callwaiting && pvt->callwaitingcallerid) {
-		/*
-		 * Call Waiting Caller ID requires DTMF detection to know if it
-		 * can send the CID spill.
-		 */
-		ast_debug(2, "Channel '%s' has call waiting caller ID enabled.\n",
-			ast_channel_name(chan));
-		is_capable = 0;
-	}
-
-	ast_mutex_unlock(&pvt->lock);
-	ast_channel_unlock(chan);
-
-	return is_capable;
-}
-
-/*!
- * \internal
- * \brief Check if a bridge is compatible with the bridging technology.
- * \since 12.0.0
- *
- * \retval 0 if not compatible
- * \retval non-zero if compatible
- *
- * \note On entry, bridge may or may not already be locked.
- * However, it can be accessed as if it were locked.
- */
-static int native_bridge_compatible(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *cur;
-
-	/* We require two channels before even considering native bridging. */
-	if (bridge->num_channels != 2) {
-		ast_debug(1, "Bridge %s: Cannot use native DAHDI.  Must have two channels.\n",
-			bridge->uniqueid);
-		return 0;
-	}
-
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		if (!native_bridge_is_capable(cur)) {
-			ast_debug(1, "Bridge %s: Cannot use native DAHDI.  Channel '%s' not compatible.\n",
-				bridge->uniqueid, ast_channel_name(cur->chan));
-			return 0;
-		}
-	}
-
-	return -1;
-}
-
-/*!
- * \internal
- * \brief Check if something changed on the channel.
- * \since 12.0.0
- *
- * \param bridge_channel What to operate upon.
- *
- * \retval 0 Nothing changed.
- * \retval -1 Something changed.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- */
-static int native_chan_changed(struct ast_bridge_channel *bridge_channel)
-{
-	struct native_pvt_chan *tech_pvt;
-	struct ast_channel *chan;
-	struct dahdi_pvt *pvt;
-	int idx = -1;
-
-	ast_assert(bridge_channel->tech_pvt != NULL);
-
-	tech_pvt = bridge_channel->tech_pvt;
-
-	chan = bridge_channel->chan;
-	ast_channel_lock(chan);
-	pvt = ast_channel_tech_pvt(chan);
-	if (tech_pvt->pvt == pvt) {
-		idx = dahdi_get_index(chan, pvt, 1);
-	}
-	ast_channel_unlock(chan);
-
-	if (/* Did chan get masqueraded or PRI change associated B channel? */
-		tech_pvt->pvt != pvt
-		/* Did the pvt active owner change? */
-		|| tech_pvt->owner != pvt->owner
-		/* Did the pvt three way call status change? */
-		|| tech_pvt->inthreeway != pvt->subs[SUB_REAL].inthreeway
-		/* Did the owner index change? */
-		|| tech_pvt->index != idx
-		/*
-		 * Did chan file descriptor change? (This seems redundant with
-		 * masquerade and active owner change checks.)
-		 */
-		|| tech_pvt->fd0 != ast_channel_fd(chan, 0)
-		/* Did chan state change? i.e. Did it stop ringing? */
-		|| (pvt->subs[SUB_REAL].owner
-			&& tech_pvt->state > -1
-			&& tech_pvt->state != ast_channel_state(pvt->subs[SUB_REAL].owner))) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Check if something changed on the bridge channels.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- *
- * \retval 0 Nothing changed.
- * \retval -1 Something changed.
- *
- * \note On entry, bridge is already locked.
- */
-static int native_bridge_changed(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *cur;
-
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		if (native_chan_changed(cur)) {
-			ast_debug(1, "Bridge %s: Something changed on channel '%s'.\n",
-				bridge->uniqueid, ast_channel_name(cur->chan));
-			return -1;
-		}
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Write a frame into the bridging technology instance for a bridge.
- * \since 12.0.0
- *
- * \note The bridge must be tolerant of bridge_channel being NULL.
- *
- * \retval 0 Frame accepted into the bridge.
- * \retval -1 Frame needs to be deferred.
- *
- * \note On entry, bridge is already locked.
- */
-static int native_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	struct native_pvt_bridge *tech_pvt;
-
-	/*
-	 * When we are not native bridged by DAHDI, we are like a normal
-	 * 1-1 bridge.
-	 */
-
-	ast_assert(bridge->tech_pvt != NULL);
-
-	/* Recheck native bridging validity. */
-	tech_pvt = bridge->tech_pvt;
-	switch (frame->frametype) {
-	case AST_FRAME_VOICE:
-	case AST_FRAME_VIDEO:
-		if (!tech_pvt->connected) {
-			/* Don't try to start native mode on media frames. */
-			break;
-		}
-		if (native_bridge_changed(bridge)) {
-			native_request_stop(bridge);
-			native_request_start(bridge);
-			if (!tech_pvt->connected) {
-				break;
-			}
-		}
-
-		/*
-		 * Native bridge handles voice frames in hardware.  However, it
-		 * also passes the frames up to Asterisk anyway.  Discard the
-		 * media frames.
-		 */
-		return 0;
-	default:
-		if (!tech_pvt->connected) {
-			native_request_start(bridge);
-			break;
-		}
-		if (native_bridge_changed(bridge)) {
-			native_request_stop(bridge);
-			native_request_start(bridge);
-		}
-		break;
-	}
-
-	return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
-}
-
-static struct ast_bridge_technology native_bridge = {
-	.name = "native_dahdi",
-	.capabilities = AST_BRIDGE_CAPABILITY_NATIVE,
-	.preference = AST_BRIDGE_PREFERENCE_BASE_NATIVE,
-	.create = native_bridge_create,
-	.start = native_bridge_start,
-	.stop = native_bridge_stop,
-	.destroy = native_bridge_destroy,
-	.join = native_bridge_join,
-	.leave = native_bridge_leave,
-	.suspend = native_bridge_suspend,
-	.unsuspend = native_bridge_unsuspend,
-	.compatible = native_bridge_compatible,
-	.write = native_bridge_write,
-};
-
-/*!
- * \internal
- * \brief Destroy the DAHDI native bridge support.
- * \since 12.0.0
- *
- * \return Nothing
- */
-void dahdi_native_unload(void)
-{
-	ast_bridge_technology_unregister(&native_bridge);
-	ao2_cleanup(native_bridge.format_capabilities);
-}
-
-/*!
- * \internal
- * \brief Initialize the DAHDI native bridge support.
- * \since 12.0.0
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech)
-{
-	dahdi_tech = tech;
-
-	native_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!native_bridge.format_capabilities) {
-		return -1;
-	}
-
-	/*
-	 * This is used to make channels compatible with the bridge
-	 * itself not with each other.
-	 */
-	ast_format_cap_append(native_bridge.format_capabilities, ast_format_slin, 0);
-	ast_format_cap_append(native_bridge.format_capabilities, ast_format_ulaw, 0);
-	ast_format_cap_append(native_bridge.format_capabilities, ast_format_alaw, 0);
-
-	return __ast_bridge_technology_register(&native_bridge, mod);
-}
diff --git a/channels/dahdi/bridge_native_dahdi.h b/channels/dahdi/bridge_native_dahdi.h
deleted file mode 100644
index 91e8d16..0000000
--- a/channels/dahdi/bridge_native_dahdi.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Native DAHDI bridging support.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_BRIDGE_NATIVE_DAHDI_H
-#define _ASTERISK_BRIDGE_NATIVE_DAHDI_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/* ------------------------------------------------------------------- */
-
-void dahdi_native_unload(void);
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech);
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_BRIDGE_NATIVE_DAHDI_H */
diff --git a/channels/h323/.gitignore b/channels/h323/.gitignore
new file mode 100644
index 0000000..ce4a48c
--- /dev/null
+++ b/channels/h323/.gitignore
@@ -0,0 +1,3 @@
+*.dep
+Makefile
+Makefile.ast
diff --git a/channels/h323/ChangeLog b/channels/h323/ChangeLog
new file mode 100644
index 0000000..ddbf081
--- /dev/null
+++ b/channels/h323/ChangeLog
@@ -0,0 +1,43 @@
+Build
+	-- Hold lock when creating new H.323 channel to sync the audio channels
+	-- Decrement usage counter when appropriate
+	-- Actually unregister everything in unload_module
+	-- Add IP based authentication using 'host'in type=user's
+0.1.0
+	-- Intergration into the mainline Asterisk codebase
+	-- Remove reduandant debug info
+	-- Add Caller*id support
+	-- Inband DTMF
+	-- Retool port usage (to avoid possible seg fault condition)
+0.0.6
+	-- Configurable support for user-input (DTMF)
+	-- Reworked Gatekeeper support
+	-- Native bridging (but is still broken, help!)
+	-- Locally implement a non-broken G.723.1 Capability
+	-- Utilize the cleaner RTP method implemented by Mark
+	-- AllowGkRouted, thanks to Panny from http://hotlinks.co.uk
+	-- Clened up inbound call flow
+	-- Prefix, E.164 and Gateway support
+	-- Multi-homed support
+	-- Killed more seg's 
+0.0.5
+	-- Added H.323 Alias support
+	-- Clened up inbound call flow
+	-- Fixed RTP port logic
+	-- Stomped on possible seg fault conditions thanks to Iain Stevenson 
+0.0.4
+        -- Fixed one-way audio on inbound calls. Found
+           race condition in monitor thread.
+
+0.0.3
+        -- Changed name to chan_h323
+        -- Also renamed file names to futher avoid confusion
+
+0.0.2
+        -- First public offering
+        -- removed most hardcoded values
+        -- lots of changes to alias/exension operation
+
+0.0.1
+        -- initial build, lots of hardcoded crap
+        -- Proof of concept for External RTP
diff --git a/channels/h323/INSTALL.openh323 b/channels/h323/INSTALL.openh323
new file mode 100644
index 0000000..f46c379
--- /dev/null
+++ b/channels/h323/INSTALL.openh323
@@ -0,0 +1,18 @@
+To build Open H.323 see: 
+
+http://www.openh323.org/build.html#unix
+
+You only need to do 'make opt'. Anything else you will be simply waisting time and HD space.
+Also, you will notice they never tell you to 'make install' so don't do it.
+
+
+On FreeBSD, the Makefiles are configured to
+locate the compiled openh323 port, if it has
+been built.  Here is one way to build
+openh323 and ptlib on such that the Makefiles
+find it:
+	# cd /usr/ports/net/openh323
+	# make
+It is not necessary to install the port.  The
+asterisk makefiles do not use any files
+installed by the port.
diff --git a/channels/h323/Makefile.in b/channels/h323/Makefile.in
new file mode 100644
index 0000000..2908c52
--- /dev/null
+++ b/channels/h323/Makefile.in
@@ -0,0 +1,53 @@
+#
+# Makefile
+#
+# Make file for OpenH323 support layer
+#
+
+.PHONY: Makefile.ast clean
+
+default::	@OPENH323_BUILD@
+
+# Verify those options with main Makefile
+STDCCFLAGS	= -DNDEBUG
+STDCCFLAGS	+= -I../../include -include ../../include/asterisk/autoconfig.h
+STDCCFLAGS	+= -fPIC
+#OPTCCFLAGS	+=
+CFLAGS		= -pipe
+TARGET		= libchanh323.a
+TARGET		+= Makefile.ast
+SOURCES		= ast_h323.cxx compat_h323.cxx cisco-h225.cxx caps_h323.cxx
+OBJDIR		= .
+OBJS		=
+
+ifndef OPENH323DIR
+OPENH323DIR=@OPENH323DIR@
+endif
+
+ifneq ($(wildcard $(OPENH323DIR)/openh323u.mak),)
+include $(OPENH323DIR)/openh323u.mak
+endif
+
+notrace::
+	$(MAKE) NOTRACE=1 opt
+
+$(SOURCES)::	Makefile ../../Makefile
+	touch $@
+
+libchanh323.a:	$(OBJS)
+	ar crv $@ $(OBJS)
+
+# 
+# We have this file in svn, so this is commented out to ensure it doesn't try
+# to run implicitly.  However, it's still here for reference.
+#
+#cisco-h225.cxx::	cisco-h225.asn
+#	asnparser -m CISCO_H225 -c $<
+
+Makefile.ast:
+	@echo H323CFLAGS  = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp
+	@echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp
+	@echo H323LDLIBS  = $(LDLIBS) $(ENDLDLIBS) $(ENDLDFLAGS) >>$@.tmp
+	@if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
+
+clean::
diff --git a/channels/h323/README b/channels/h323/README
new file mode 100644
index 0000000..27a24c7
--- /dev/null
+++ b/channels/h323/README
@@ -0,0 +1,144 @@
+		Open H.323 Channel Driver for Asterisk
+	  	        By Jeremy McNamara  
+		        For The NuFone Network
+
+	     First public release on November 10th, 2002
+
+		Dependancies (based on OpenH323/PWLib ones):
+						openssl-0.9.6b+
+						openssl-devel-0.9.6b+
+						expat-1.95+
+						expat-dev-1.95+
+
+Tested with Open H.323 version v1.18.0, PWLib v1.10.0 and GCC v3.2.2. Usage of any
+other (especially prior OpenH323 v1.17.3 and PWLib v1.9.2) versions is not
+supported.
+
+NOTICE: Whatever you do, DO NOT USE distrubution specific installs
+of Open H.323 and PWLib. In fact, you should check to make sure 
+your distro did not install them for you without your knowledge.
+
+
+To compile this code
+--------------------
+Once PWLib and Open H.323 have been compiled per their specific build
+instructions, issue a make in the asterisk/channels/h323 directory with
+argument used to build PWLib and OpenH323 (for example, make opt), then go
+back to the Asterisk source top level directory and issue a make install.
+
+
+The most common compile error  
+----------------------------
+If you receive ANYTHING that says 'undefined symbol' you are experiencing
+typical version skew.  For example:
+
+libh323_linux_x86_r.so.1: undefined symbol: GetNumberValueAt__C14PAbstractArrayi
+
+You need to search and destroy every version of libh323 and libpt then 
+completely recompile everything
+
+Example commands to make sure everything gets cleaned and then
+rebult in proper order:
+
+cd /path/to/pwlib
+./configure
+make clean opt
+cd /path/to/openh323
+./configure
+make clean opt 
+cd /path/to/asterisk/channels/h323
+make opt
+cd /path/to/asterisk
+make install 
+
+
+Most common run-time error
+-------------------------
+libpt_linux_x86_r.so.1: cannot open shared object file: No such 
+file or directory
+
+You have not set the LD_LIBRARY_PATH environment variable.
+
+Example environment for sh/bash:
+
+PWLIBDIR=$HOME/pwlib
+export PWLIBDIR
+OPENH323DIR=$HOME/openh323
+export OPENH323DIR
+LD_LIBRARY_PATH=$PWLIBDIR/lib:$OPENH323DIR/lib
+export LD_LIBRARY_PATH
+
+We recomend puting the above directives into your /etc/profile so 
+you do not have to remember to export those values every time you 
+want to recompile. Make sure to logout and log back in, so your
+envrionment can pick up the new variables.
+
+
+Upgrading Asterisk
+-----------------
+After you svn update (or make update) Asterisk you have to go into
+asterisk/channels/h323 and issue a make clean all, before compiling the
+rest of asterisk. Doing this process every time you upgrade Asterisk
+will ensure a sane build.
+
+
+Dialing an H.323 channel
+------------------------
+Without a gatekeeper:
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@peer
+or
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@ip.or.hostname
+
+'peer' is defined in h323.conf as:
+
+[peer]
+type=peer
+host=1.2.3.4
+disallow=all
+allow=ulaw
+
+Using a gatekeeper:
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}
+
+When using a gatekeeper you cannot utilize the type=peer features,
+since the H.323 spec states that when a Gatekeeper is part of an H.323 network, 
+the Gatekeeper shall be used for all communication. 
+
+
+Developer Contact
+----------------
+If you have trouble contact 'JerJer' in #Asterisk on 
+irc.freenode.net and/or send reasonable debug information to support at nufone.net.
+
+If are lucky enough to segfault this code please run a 
+backtrace and send the gory details. Segmentation faults are not
+tolerated, no matter what Distro you run (even debian)!
+
+a simple bt example:
+
+# /usr/sbin/asterisk -vvvgc
+...
+[chan_h323.so]
+Segmentation Fault (core dumped)
+
+# ls core.*
+core.1976
+
+# gdb /usr/sbin/asterisk core.1976
+...lots of useless garbage here...
+(gdb) bt
+
+Send whatever shows up right after the 'bt'
+
+Also, a full debug screen output is almost needed. Make sure you are 
+in the full console mode (-c) and turn on 'h.323 debug' or worst case
+senerio 'h.323 trace 4'. A nice way to capture debug info is with 
+script (man script). 
+
+If you are motivated to update/fix this code please submit a 
+disclaimer along with the patch to the Asterisk bug 
+tracker: https://issues.asterisk.org/
+
+
+Jeremy McNamara
+The NuFone Network 
diff --git a/channels/h323/TODO b/channels/h323/TODO
new file mode 100644
index 0000000..1e114ca
--- /dev/null
+++ b/channels/h323/TODO
@@ -0,0 +1,9 @@
+The NuFone Network's Open H.323 Channel Driver for Asterisk 
+	     
+	TODO:
+
+		- H.323 Native Bridging
+
+		- Gatekeeping support (started)
+	
+		- Acutally implement the options for broken H.323 stacks
diff --git a/channels/h323/ast_h323.cxx b/channels/h323/ast_h323.cxx
new file mode 100644
index 0000000..c086b64
--- /dev/null
+++ b/channels/h323/ast_h323.cxx
@@ -0,0 +1,2678 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/*
+ * ast_h323.cpp
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ *			By  Jeremy McNamara
+ *			For The NuFone Network
+ *
+ * chan_h323 has been derived from code created by
+ *               Michael Manousos and Mark Spencer
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * chan_h323 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Version Info: $Id$
+ */
+
+#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
+
+#include <arpa/inet.h>
+
+#include <list>
+#include <string>
+#include <algorithm>
+
+#include <ptlib.h>
+#include <h323.h>
+#include <h323pdu.h>
+#include <h323neg.h>
+#include <mediafmt.h>
+
+/* H323 Plus */
+#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4)
+
+#ifdef H323_H450
+#include "h450/h4501.h"
+#include "h450/h4504.h"
+#include "h450/h45011.h"
+#include "h450/h450pdu.h"
+#endif
+
+#ifdef H323_H460
+#include <h460/h4601.h>
+#endif
+
+#else /* !H323 Plus */
+
+#include <lid.h>
+#ifdef H323_H450
+#include "h4501.h"
+#include "h4504.h"
+#include "h45011.h"
+#include "h450pdu.h"
+#endif
+
+#endif /* H323 Plus */
+
+#include "compat_h323.h"
+
+#include "asterisk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "asterisk/compat.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/astobj.h"
+#ifdef __cplusplus
+}
+#endif
+
+#undef open
+#undef close
+
+#include "chan_h323.h"
+#include "ast_h323.h"
+#include "cisco-h225.h"
+#include "caps_h323.h"
+
+/* PWLIB_MAJOR renamed to PTLIB_MAJOR in 2.x.x */
+#if (defined(PTLIB_MAJOR) || VERSION(PWLIB_MAJOR, PWLIB_MINOR, PWLIB_BUILD) >= VERSION(1,12,0))
+#define SKIP_PWLIB_PIPE_BUG_WORKAROUND 1
+#endif
+
+///////////////////////////////////////////////
+/* We have to have a PProcess running for the life of the instance to give
+ * h323plus a static instance of PProcess to get system information.
+ * This class is defined with PDECLARE_PROCESS().  See pprocess.h from pwlib.
+ */
+
+/* PWlib Required Components  */
+#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4)
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 19
+#define BUILD_TYPE    ReleaseCode
+#define BUILD_NUMBER  6
+#else
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+#define BUILD_TYPE    ReleaseCode
+#define BUILD_NUMBER  0
+#endif
+ 
+const char *h323manufact = "The NuFone Networks";
+const char *h323product  = "H.323 Channel Driver for Asterisk";
+ 
+PDECLARE_PROCESS(MyProcess,PProcess,h323manufact,h323product,MAJOR_VERSION,MINOR_VERSION,BUILD_TYPE,BUILD_NUMBER)
+static MyProcess localProcess;  // active for the life of the DLL
+/* void MyProcess::Main()
+{
+}
+*/
+////////////////////////////////////////////////
+
+
+/** Counter for the number of connections */
+static int channelsOpen;
+
+/**
+ * We assume that only one endPoint should exist.
+ * The application cannot run the h323_end_point_create() more than once
+ * FIXME: Singleton this, for safety
+ */
+static MyH323EndPoint *endPoint = NULL;
+
+#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND
+static int _timerChangePipe[2];
+#endif
+
+static unsigned traceOptions = PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine;
+
+class PAsteriskLog : public PObject, public iostream {
+	PCLASSINFO(PAsteriskLog, PObject);
+
+	public:
+	PAsteriskLog() : iostream(cout.rdbuf()) { init(&buffer); }
+	~PAsteriskLog() { flush(); }
+
+	private:
+	PAsteriskLog(const PAsteriskLog &) : iostream(cout.rdbuf()) { }
+	PAsteriskLog & operator=(const PAsteriskLog &) { return *this; }
+
+	class Buffer : public streambuf {
+		public:
+		virtual int overflow(int=EOF);
+		virtual int underflow();
+		virtual int sync();
+		PString string;
+	} buffer;
+	friend class Buffer;
+};
+
+static PAsteriskLog *logstream = NULL;
+
+int PAsteriskLog::Buffer::overflow(int c)
+{
+	if (pptr() >= epptr()) {
+		int ppos = pptr() - pbase();
+		char *newptr = string.GetPointer(string.GetSize() + 2000);
+		setp(newptr, newptr + string.GetSize() - 1);
+		pbump(ppos);
+	}
+	if (c != EOF) {
+		*pptr() = (char)c;
+		pbump(1);
+	}
+	return 0;
+}
+
+int PAsteriskLog::Buffer::underflow()
+{
+	return EOF;
+}
+
+int PAsteriskLog::Buffer::sync()
+{
+	char *str = ast_strdup(string);
+	char *s, *s1;
+	char c;
+
+	/* Pass each line with different ast_verbose() call */
+	for (s = str; s && *s; s = s1) {
+		s1 = strchr(s, '\n');
+		if (!s1)
+			s1 = s + strlen(s);
+		else
+			s1++;
+		c = *s1;
+		*s1 = '\0';
+		ast_verbose("%s", s);
+		*s1 = c;
+	}
+	ast_free(str);
+
+	string = PString();
+	char *base = string.GetPointer(2000);
+	setp(base, base + string.GetSize() - 1);
+	return 0;
+}
+
+static ostream &my_endl(ostream &os)
+{
+	if (logstream) {
+		PTrace::SetOptions(traceOptions);
+		return PTrace::End(os);
+	}
+	return endl(os);
+}
+
+#define cout \
+	(logstream ? (PTrace::ClearOptions((unsigned)-1), PTrace::Begin(0, __FILE__, __LINE__)) : std::cout)
+#define endl my_endl
+
+void MyProcess::Main()
+{
+	PTrace::Initialise(PTrace::GetLevel(), NULL, traceOptions);
+	PTrace::SetStream(logstream);
+
+	cout << "  == Creating H.323 Endpoint" << endl;
+	if (endPoint) {
+		cout << "  == ENDPOINT ALREADY CREATED" << endl;
+		return;
+	}
+	endPoint = new MyH323EndPoint();
+	/* Due to a bug in the H.323 recomendation/stack we should request a sane
+	   amount of bandwidth from the GK - this function is ignored if not using a GK
+	   We are requesting 128 (64k in each direction), which is the worst case codec. */
+	endPoint->SetInitialBandwidth(1280);
+}
+
+void PAssertFunc(const char *msg)
+{
+	ast_log(LOG_ERROR, "%s\n", msg);
+	/* XXX: Probably we need to crash here */
+}
+
+
+/** MyH323EndPoint
+  */
+MyH323EndPoint::MyH323EndPoint()
+		: H323EndPoint()
+{
+	/* Capabilities will be negotiated on per-connection basis */
+	capabilities.RemoveAll();
+
+	/* Reset call setup timeout to some more reasonable value than 1 minute */
+	signallingChannelCallTimeout = PTimeInterval(0, 0, 10);	/* 10 minutes */
+}
+
+/** The fullAddress parameter is used directly in the MakeCall method so
+  * the General form for the fullAddress argument is :
+  * [alias@][transport$]host[:port]
+  * default values:	alias = the same value as host.
+  *					transport = ip.
+  *					port = 1720.
+  */
+int MyH323EndPoint::MyMakeCall(const PString & dest, PString & token, void *_callReference, void *_opts)
+{
+	PString fullAddress;
+	MyH323Connection * connection;
+	H323Transport *transport = NULL;
+	unsigned int *callReference = (unsigned int *)_callReference;
+	call_options_t *opts = (call_options_t *)_opts;
+
+	/* Determine whether we are using a gatekeeper or not. */
+	if (GetGatekeeper()) {
+		fullAddress = dest;
+		if (h323debug) {
+			cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl;
+		}
+	} else {
+		fullAddress = dest;
+		if (h323debug) {
+			cout << " -- Making call to " << fullAddress << " without gatekeeper." << endl;
+		}
+		/* Use bindaddr for outgoing calls too if we don't use gatekeeper */
+		if (listeners.GetSize() > 0) {
+			H323TransportAddress taddr = listeners[0].GetTransportAddress();
+			PIPSocket::Address addr;
+			WORD port;
+			if (taddr.GetIpAndPort(addr, port)) {
+				/* Create own transport for specific addresses only */
+				if (addr) {
+					if (h323debug)
+						cout << "Using " << addr << " for outbound call" << endl;
+					transport = new MyH323TransportTCP(*this, addr);
+					if (!transport)
+						cout << "Unable to create transport for outgoing call" << endl;
+				}
+			} else
+				cout << "Unable to get address and port" << endl;
+		}
+	}
+	if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts, transport))) {
+		if (h323debug) {
+			cout << "Error making call to \"" << fullAddress << '"' << endl;
+		}
+		return 1;
+	}
+	*callReference = connection->GetCallReference();
+
+	if (h323debug) {
+		cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
+		cout << "\t-- Call token is " << (const char *)token << endl;
+		cout << "\t-- Call reference is " << *callReference << endl;
+#ifdef PTRACING
+		cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
+#endif
+	}
+	connection->Unlock();
+	return 0;
+}
+
+void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const
+{
+	H323EndPoint::SetEndpointTypeInfo(info);
+
+	if (terminalType == e_GatewayOnly){
+		info.RemoveOptionalField(H225_EndpointType::e_terminal);
+		info.IncludeOptionalField(H225_EndpointType::e_gateway);
+	}
+
+	info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
+	info.m_gateway.m_protocol.SetSize(1);
+	H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
+	protocol.SetTag(H225_SupportedProtocols::e_voice);
+	PINDEX as=SupportedPrefixes.GetSize();
+	((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
+	for (PINDEX p=0; p<as; p++) {
+		H323SetAliasAddress(SupportedPrefixes[p], ((H225_VoiceCaps &)protocol).m_supportedPrefixes[p].m_prefix, H225_AliasAddress::e_dialedDigits);
+	}
+}
+
+void MyH323EndPoint::SetGateway(void)
+{
+	terminalType = e_GatewayOnly;
+}
+
+PBoolean MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason)
+{
+	if (h323debug) {
+#ifdef PTRACING
+		cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause " << reason << endl;
+#else
+		cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause [" << (int)reason << "]" << endl;
+#endif
+	}
+	return H323EndPoint::ClearCall(token, reason);
+}
+
+PBoolean MyH323EndPoint::ClearCall(const PString & token)
+{
+	if (h323debug) {
+		cout << "\t-- ClearCall: Request to clear call with token " << token << endl;
+	}
+	return H323EndPoint::ClearCall(token, H323Connection::EndedByLocalUser);
+}
+
+void MyH323EndPoint::SendUserTone(const PString &token, char tone)
+{
+	H323Connection *connection = NULL;
+
+	connection = FindConnectionWithLock(token);
+	if (connection != NULL) {
+		connection->SendUserInputTone(tone, 500);
+		connection->Unlock();
+	}
+}
+
+void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H323Channel & channel)
+{
+	channelsOpen--;
+	if (h323debug) {
+		cout << "\t\tchannelsOpen = " << channelsOpen << endl;
+	}
+	H323EndPoint::OnClosedLogicalChannel(connection, channel);
+}
+
+PBoolean MyH323EndPoint::OnConnectionForwarded(H323Connection & connection,
+		const PString & forwardParty,
+		const H323SignalPDU & pdu)
+{
+	if (h323debug) {
+		cout << "\t-- Call Forwarded to " << forwardParty << endl;
+	}
+	return FALSE;
+}
+
+PBoolean MyH323EndPoint::ForwardConnection(H323Connection & connection,
+		const PString & forwardParty,
+		const H323SignalPDU & pdu)
+{
+	if (h323debug) {
+		cout << "\t-- Forwarding call to " << forwardParty << endl;
+	}
+	return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
+}
+
+void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & estCallToken)
+{
+	if (h323debug) {
+		cout << "\t=-= In OnConnectionEstablished for call " << connection.GetCallReference() << endl;
+		cout << "\t\t-- Connection Established with \"" << connection.GetRemotePartyName() << "\"" << endl;
+	}
+	on_connection_established(connection.GetCallReference(), (const char *)connection.GetCallToken());
+}
+
+/** OnConnectionCleared callback function is called upon the dropping of an established
+  * H323 connection.
+  */
+void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
+{
+	PString remoteName = connection.GetRemotePartyName();
+
+	switch (connection.GetCallEndReason()) {
+		case H323Connection::EndedByCallForwarded:
+			if (h323debug) {
+				cout << "-- " << remoteName << " has forwarded the call" << endl;
+			}
+			break;
+		case H323Connection::EndedByRemoteUser:
+			if (h323debug) {
+				cout << "-- " << remoteName << " has cleared the call" << endl;
+			}
+			break;
+		case H323Connection::EndedByCallerAbort:
+			if (h323debug) {
+				cout << "-- " << remoteName << " has stopped calling" << endl;
+			}
+			break;
+		case H323Connection::EndedByRefusal:
+			if (h323debug) {
+				cout << "-- " << remoteName << " did not accept your call" << endl;
+			}
+			break;
+		case H323Connection::EndedByRemoteBusy:
+			if (h323debug) {
+				cout << "-- " << remoteName << " was busy" << endl;
+			}
+			break;
+		case H323Connection::EndedByRemoteCongestion:
+			if (h323debug) {
+				cout << "-- Congested link to " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByNoAnswer:
+			if (h323debug) {
+				cout << "-- " << remoteName << " did not answer your call" << endl;
+			}
+			break;
+		case H323Connection::EndedByTransportFail:
+			if (h323debug) {
+				cout << "-- Call with " << remoteName << " ended abnormally" << endl;
+			}
+			break;
+		case H323Connection::EndedByCapabilityExchange:
+			if (h323debug) {
+				cout << "-- Could not find common codec with " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByNoAccept:
+			if (h323debug) {
+				cout << "-- Did not accept incoming call from " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByAnswerDenied:
+			if (h323debug) {
+				cout << "-- Refused incoming call from " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByNoUser:
+			if (h323debug) {
+				cout << "-- Remote endpoint could not find user: " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByNoBandwidth:
+			if (h323debug) {
+				cout << "-- Call to " << remoteName << " aborted, insufficient bandwidth." << endl;
+			}
+			break;
+		case H323Connection::EndedByUnreachable:
+			if (h323debug) {
+				cout << "-- " << remoteName << " could not be reached." << endl;
+			}
+			break;
+		case H323Connection::EndedByHostOffline:
+			if (h323debug) {
+				cout << "-- " << remoteName << " is not online." << endl;
+			}
+			break;
+		case H323Connection::EndedByNoEndPoint:
+			if (h323debug) {
+				cout << "-- No phone running for " << remoteName << endl;
+			}
+			break;
+		case H323Connection::EndedByConnectFail:
+			if (h323debug) {
+				cout << "-- Transport error calling " << remoteName << endl;
+			}
+			break;
+		default:
+			if (h323debug) {
+#ifdef PTRACING
+				cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl;
+#else
+				cout << " -- Call with " << remoteName << " completed ([" << (int)connection.GetCallEndReason() << "])" << endl;
+#endif
+			}
+	}
+
+	if (connection.IsEstablished()) {
+		if (h323debug) {
+			cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl;
+		}
+	}
+	/* Invoke the PBX application registered callback */
+	on_connection_cleared(connection.GetCallReference(), clearedCallToken);
+	return;
+}
+
+H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *userData, H323Transport *transport, H323SignalPDU *setupPDU)
+{
+	unsigned options = 0;
+	call_options_t *opts = (call_options_t *)userData;
+	MyH323Connection *conn;
+
+	if (opts && opts->fastStart) {
+		options |= H323Connection::FastStartOptionEnable;
+	} else {
+		options |= H323Connection::FastStartOptionDisable;
+	}
+	if (opts && opts->h245Tunneling) {
+		options |= H323Connection::H245TunnelingOptionEnable;
+	} else {
+		options |= H323Connection::H245TunnelingOptionDisable;
+	}
+/* Disable until I can figure out the proper way to deal with this */
+#if 0
+	if (opts->silenceSuppression) {
+		options |= H323Connection::SilenceSuppresionOptionEnable;
+	} else {
+		options |= H323Connection::SilenceSUppressionOptionDisable;
+	}
+#endif
+	conn = new MyH323Connection(*this, callReference, options);
+	if (conn) {
+		if (opts)
+			conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE));
+	}
+	return conn;
+}
+
+/* MyH323Connection Implementation */
+MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
+							unsigned options)
+	: H323Connection(ep, callReference, options)
+{
+#ifdef H323_H450
+	/* Dispatcher will free out all registered handlers */
+	delete h450dispatcher;
+	h450dispatcher = new H450xDispatcher(*this);
+	h4502handler = new H4502Handler(*this, *h450dispatcher);
+	h4504handler = new MyH4504Handler(*this, *h450dispatcher);
+	h4506handler = new H4506Handler(*this, *h450dispatcher);
+	h45011handler = new H45011Handler(*this, *h450dispatcher);
+#endif
+	cause = -1;
+	sessionId = 0;
+	bridging = FALSE;
+	holdHandling = progressSetup = progressAlert = 0;
+	dtmfMode = 0;
+	dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0;
+	redirect_reason = -1;
+	transfer_capability = -1;
+#ifdef TUNNELLING
+	tunnelOptions = remoteTunnelOptions = 0;
+#endif
+	if (h323debug) {
+		cout << "	== New H.323 Connection created." << endl;
+	}
+	return;
+}
+
+MyH323Connection::~MyH323Connection()
+{
+	if (h323debug) {
+		cout << "	== H.323 Connection deleted." << endl;
+	}
+	return;
+}
+
+PBoolean MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
+{
+	PBoolean isInband;
+	unsigned pi;
+
+	if (!H323Connection::OnReceivedProgress(pdu)) {
+		return FALSE;
+	}
+
+	if (!pdu.GetQ931().GetProgressIndicator(pi))
+		pi = 0;
+	if (h323debug) {
+		cout << "\t- Progress Indicator: " << pi << endl;
+	}
+
+	switch(pi) {
+	case Q931::ProgressNotEndToEndISDN:
+	case Q931::ProgressInbandInformationAvailable:
+		isInband = TRUE;
+		break;
+	default:
+		isInband = FALSE;
+	}
+	on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
+
+	return connectionState != ShuttingDownConnection;
+}
+
+PBoolean MyH323Connection::MySendProgress()
+{
+	/* The code taken from H323Connection::AnsweringCall() but ALWAYS send
+	   PROGRESS message, including slow start operations */
+	H323SignalPDU progressPDU;
+	H225_Progress_UUIE &prog = progressPDU.BuildProgress(*this);
+
+	if (!mediaWaitForConnect) {
+		if (SendFastStartAcknowledge(prog.m_fastStart))
+			prog.IncludeOptionalField(H225_Progress_UUIE::e_fastStart);
+		else {
+			if (connectionState == ShuttingDownConnection)
+				return FALSE;
+
+			/* Do early H.245 start */
+			earlyStart = TRUE;
+			if (!h245Tunneling) {
+				if (!H323Connection::StartControlChannel())
+					return FALSE;
+				prog.IncludeOptionalField(H225_Progress_UUIE::e_h245Address);
+				controlChannel->SetUpTransportPDU(prog.m_h245Address, TRUE);
+			}
+		}
+	}
+	progressPDU.GetQ931().SetProgressIndicator(Q931::ProgressInbandInformationAvailable);
+
+#ifdef TUNNELLING
+	EmbedTunneledInfo(progressPDU);
+#endif
+	HandleTunnelPDU(&progressPDU);
+	WriteSignalPDU(progressPDU);
+
+	return TRUE;
+}
+
+H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
+								const H323SignalPDU & setupPDU,
+								H323SignalPDU & connectPDU)
+{
+	unsigned pi;
+
+	if (h323debug) {
+		cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
+	}
+
+	if (connectionState == ShuttingDownConnection)
+		return H323Connection::AnswerCallDenied;
+
+	if (!setupPDU.GetQ931().GetProgressIndicator(pi)) {
+		pi = 0;
+	}
+	if (h323debug) {
+		cout << "\t\t- Progress Indicator: " << pi << endl;
+	}
+	if (progressAlert) {
+		pi = progressAlert;
+	} else if (pi == Q931::ProgressOriginNotISDN) {
+		pi = Q931::ProgressInbandInformationAvailable;
+	}
+	if (pi && alertingPDU) {
+		alertingPDU->GetQ931().SetProgressIndicator(pi);
+	}
+	if (h323debug) {
+		cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl;
+	}
+
+#ifdef TUNNELLING
+	if (alertingPDU)
+		EmbedTunneledInfo(*alertingPDU);
+	EmbedTunneledInfo(connectPDU);
+#endif
+
+	if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) {
+		return H323Connection::AnswerCallDenied;
+	}
+	/* The call will be answered later with "AnsweringCall()" function.
+	 */
+	return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred);
+}
+
+PBoolean MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username)
+{
+	if (h323debug) {
+		cout << "\t=-= In OnAlerting for call " << GetCallReference()
+			<< ": sessionId=" << sessionId << endl;
+		cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
+	}
+
+	if (on_progress) {
+		PBoolean isInband;
+		unsigned alertingPI;
+
+		if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) {
+			alertingPI = 0;
+		}
+		if (h323debug) {
+			cout << "\t\t- Progress Indicator: " << alertingPI << endl;
+		}
+
+		switch(alertingPI) {
+		case Q931::ProgressNotEndToEndISDN:
+		case Q931::ProgressInbandInformationAvailable:
+			isInband = TRUE;
+			break;
+		default:
+			isInband = FALSE;
+		}
+		on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
+	}
+	on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
+	return connectionState != ShuttingDownConnection;
+}
+
+void MyH323Connection::SetCallOptions(void *o, PBoolean isIncoming)
+{
+	call_options_t *opts = (call_options_t *)o;
+
+	progressSetup = opts->progress_setup;
+	progressAlert = opts->progress_alert;
+	holdHandling = opts->holdHandling;
+	dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0];
+	dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1];
+	dtmfMode = opts->dtmfmode;
+
+	if (isIncoming) {
+		fastStartState = (opts->fastStart ? FastStartInitiate : FastStartDisabled);
+		h245Tunneling = (opts->h245Tunneling ? TRUE : FALSE);
+	} else {
+		sourceE164 = PString(opts->cid_num);
+		SetLocalPartyName(PString(opts->cid_name));
+		SetDisplayName(PString(opts->cid_name));
+		if (opts->redirect_reason >= 0) {
+			rdnis = PString(opts->cid_rdnis);
+			redirect_reason = opts->redirect_reason;
+		}
+		cid_presentation = opts->presentation;
+		cid_ton = opts->type_of_number;
+		if (opts->transfer_capability >= 0) {
+			transfer_capability = opts->transfer_capability;
+		}
+	}
+	tunnelOptions = opts->tunnelOptions;
+}
+
+void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming)
+{
+	PString sourceE164;
+	PString destE164;
+	PString sourceAliases;
+	PString destAliases;
+	char *s, *s1;
+	call_details_t *cd = (call_details_t *)callDetails;
+
+	memset(cd, 0, sizeof(*cd));
+	cd->call_reference = GetCallReference();
+	cd->call_token = strdup((const char *)GetCallToken());
+
+	sourceE164 = "";
+	setupPDU.GetSourceE164(sourceE164);
+	cd->call_source_e164 = strdup((const char *)sourceE164);
+
+	destE164 = "";
+	setupPDU.GetDestinationE164(destE164);
+	cd->call_dest_e164 = strdup((const char *)destE164);
+
+	/* XXX Is it possible to have this information for outgoing calls too? XXX */
+	if (isIncoming) {
+		PString sourceName;
+		PIPSocket::Address Ip;
+		WORD sourcePort;
+		PString redirect_number;
+		unsigned redirect_reason;
+		unsigned plan, type, screening, presentation;
+		Q931::InformationTransferCapability capability;
+		unsigned transferRate, codingStandard, userInfoLayer1;
+
+		/* Fetch presentation and type information about calling party's number */
+		if (setupPDU.GetQ931().GetCallingPartyNumber(sourceName, &plan, &type, &presentation, &screening, 0, 0)) {
+			/* Construct fields back */
+			cd->type_of_number = (type << 4) | plan;
+			cd->presentation = (presentation << 5) | screening;
+		} else if (cd->call_source_e164[0]) {
+			cd->type_of_number = 0;		/* UNKNOWN */
+			cd->presentation = 0x03;	/* ALLOWED NETWORK NUMBER - Default */
+			if (setupPDU.GetQ931().HasIE(Q931::UserUserIE)) {
+				const H225_Setup_UUIE &setup_uuie = setupPDU.m_h323_uu_pdu.m_h323_message_body;
+				if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_presentationIndicator))
+					cd->presentation = (cd->presentation & 0x9f) | (((unsigned int)setup_uuie.m_presentationIndicator.GetTag()) << 5);
+				if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_screeningIndicator))
+					cd->presentation = (cd->presentation & 0xe0) | (((unsigned int)setup_uuie.m_screeningIndicator.GetValue()) & 0x1f);
+			}
+		} else {
+			cd->type_of_number = 0;		/* UNKNOWN */
+			cd->presentation = 0x43;	/* NUMBER NOT AVAILABLE */
+		}
+
+		sourceName = setupPDU.GetQ931().GetDisplayName();
+		cd->call_source_name = strdup((const char *)sourceName);
+
+		GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
+		cd->sourceIp = strdup((const char *)Ip.AsString());
+
+		if (setupPDU.GetQ931().GetRedirectingNumber(redirect_number, NULL, NULL, NULL, NULL, &redirect_reason, 0, 0, 0)) {
+			cd->redirect_number = strdup((const char *)redirect_number);
+			cd->redirect_reason = redirect_reason;
+		}
+		else
+			cd->redirect_reason = -1;
+
+		/* Fetch Q.931's transfer capability */
+		if (((Q931 &)setupPDU.GetQ931()).GetBearerCapabilities(capability, transferRate, &codingStandard, &userInfoLayer1))
+			cd->transfer_capability = ((unsigned int)capability & 0x1f) | (codingStandard << 5);
+		else
+			cd->transfer_capability = 0x00;	/* ITU coding of Speech */
+
+		/* Don't show local username as called party name */
+		SetDisplayName(cd->call_dest_e164);
+	}
+
+	/* Convert complex strings */
+	//  FIXME: deal more than one source alias
+	sourceAliases = setupPDU.GetSourceAliases();
+	s1 = strdup((const char *)sourceAliases);
+	if ((s = strchr(s1, ' ')) != NULL)
+		*s = '\0';
+	if ((s = strchr(s1, '\t')) != NULL)
+		*s = '\0';
+	cd->call_source_aliases = s1;
+
+	destAliases = setupPDU.GetDestinationAlias();
+	s1 = strdup((const char *)destAliases);
+	if ((s = strchr(s1, ' ')) != NULL)
+		*s = '\0';
+	if ((s = strchr(s1, '\t')) != NULL)
+		*s = '\0';
+	cd->call_dest_alias = s1;
+}
+
+#ifdef TUNNELLING
+static PBoolean FetchInformationElements(Q931 &q931, const PBYTEArray &data)
+{
+	PINDEX offset = 0;
+
+	while (offset < data.GetSize()) {
+		// Get field discriminator
+		int discriminator = data[offset++];
+
+#if 0
+		/* Do not overwrite existing IEs */
+		if (q931.HasIE((Q931::InformationElementCodes)discriminator)) {
+			if ((discriminatir & 0x80) == 0)
+				offset += data[offset++];
+			if (offset > data.GetSize())
+				return FALSE;
+			continue;
+		}
+#endif
+
+		PBYTEArray * item = new PBYTEArray;
+
+		// For discriminator with high bit set there is no data
+		if ((discriminator & 0x80) == 0) {
+			int len = data[offset++];
+
+#if 0		// That is not H.225 but regular Q.931 (ISDN) IEs
+			if (discriminator == UserUserIE) {
+				// Special case of User-user field. See 7.2.2.31/H.225.0v4.
+				len <<= 8;
+				len |= data[offset++];
+
+				// we also have a protocol discriminator, which we ignore
+				offset++;
+
+				// before decrementing the length, make sure it is not zero
+				if (len == 0)
+					return FALSE;
+
+				// adjust for protocol discriminator
+				len--;
+			}
+#endif
+
+			if (offset + len > data.GetSize()) {
+				delete item;
+				return FALSE;
+			}
+
+			memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
+			offset += len;
+		}
+
+		q931.SetIE((Q931::InformationElementCodes)discriminator, *item);
+		delete item;
+	}
+	return TRUE;
+}
+
+static PBoolean FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+	PBoolean res = FALSE;
+	const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+
+	if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+		for(int i = 0; i < uuPDU.m_nonStandardControl.GetSize(); ++i) {
+			const H225_NonStandardParameter &np = uuPDU.m_nonStandardControl[i];
+			const H225_NonStandardIdentifier &id = np.m_nonStandardIdentifier;
+			if (id.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) {
+				const H225_H221NonStandard &ni = id;
+				/* Check for Cisco */
+				if ((ni.m_t35CountryCode == 181) && (ni.m_t35Extension == 0) && (ni.m_manufacturerCode == 18)) {
+					const PBYTEArray &data = np.m_data;
+					if (h323debug)
+						cout << setprecision(0) << "Received non-standard Cisco extension data " << np.m_data << endl;
+					CISCO_H225_H323_UU_NonStdInfo c;
+					PPER_Stream strm(data);
+					if (c.Decode(strm)) {
+						PBoolean haveIEs = FALSE;
+						if (h323debug)
+							cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl;
+						if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) {
+							FetchInformationElements(q931, c.m_protoParam.m_qsigNonStdInfo.m_rawMesg);
+							haveIEs = TRUE;
+						}
+						if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam)) {
+							FetchInformationElements(q931, c.m_commonParam.m_redirectIEinfo.m_redirectIE);
+							haveIEs = TRUE;
+						}
+						if (haveIEs && h323debug)
+							cout << setprecision(0) << "Information elements collected:" << q931 << endl;
+						res = TRUE;
+					} else {
+						cout << "ERROR while decoding non-standard Cisco extension" << endl;
+						return FALSE;
+					}
+				}
+			}
+		}
+	}
+	return res;
+}
+
+static PBoolean EmbedCiscoTunneledInfo(H323SignalPDU &pdu)
+{
+	static const struct {
+		Q931::InformationElementCodes ie;
+		PBoolean dontDelete;
+	} codes[] = {
+		{ Q931::RedirectingNumberIE, },
+		{ Q931::FacilityIE, },
+//		{ Q931::CallingPartyNumberIE, TRUE },
+	};
+
+	PBoolean res = FALSE;
+	PBoolean notRedirOnly = FALSE;
+	Q931 tmpQ931;
+	Q931 &q931 = pdu.GetQ931();
+
+	for(unsigned i = 0; i < ARRAY_LEN(codes); ++i) {
+		if (q931.HasIE(codes[i].ie)) {
+			tmpQ931.SetIE(codes[i].ie, q931.GetIE(codes[i].ie));
+			if (!codes[i].dontDelete)
+				q931.RemoveIE(codes[i].ie);
+			if (codes[i].ie != Q931::RedirectingNumberIE)
+				notRedirOnly = TRUE;
+			res = TRUE;
+		}
+	}
+	/* Have something to embed */
+	if (res) {
+		PBYTEArray msg;
+		if (!tmpQ931.Encode(msg))
+			return FALSE;
+		PBYTEArray ies(msg.GetPointer() + 5, msg.GetSize() - 5);
+
+		H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+		if(!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+			uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardControl);
+			uuPDU.m_nonStandardControl.SetSize(0);
+		}
+		H225_NonStandardParameter *np = new H225_NonStandardParameter;
+		uuPDU.m_nonStandardControl.Append(np);
+		H225_NonStandardIdentifier &nsi = (*np).m_nonStandardIdentifier;
+		nsi.SetTag(H225_NonStandardIdentifier::e_h221NonStandard);
+		H225_H221NonStandard &ns = nsi;
+		ns.m_t35CountryCode = 181;
+		ns.m_t35Extension = 0;
+		ns.m_manufacturerCode = 18;
+
+		CISCO_H225_H323_UU_NonStdInfo c;
+		c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_version);
+		c.m_version = 0;
+
+		if (notRedirOnly) {
+			c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam);
+			CISCO_H225_QsigNonStdInfo &qsigInfo = c.m_protoParam.m_qsigNonStdInfo;
+			qsigInfo.m_iei = ies[0];
+			qsigInfo.m_rawMesg = ies;
+		} else {
+			c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam);
+			c.m_commonParam.m_redirectIEinfo.m_redirectIE = ies;
+		}
+		PPER_Stream stream;
+		c.Encode(stream);
+		stream.CompleteEncoding();
+		(*np).m_data = stream;
+	}
+	return res;
+}
+
+static const char OID_QSIG[] = "1.3.12.9";
+
+static PBoolean FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+	PBoolean res = FALSE;
+	const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+	if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) {
+		const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+		const H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+		if ((proto.GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+				(((const PASN_ObjectId &)proto).AsString() == OID_QSIG)) {
+			const H225_ArrayOf_PASN_OctetString &sigs = sig.m_messageContent;
+			for(int i = 0; i < sigs.GetSize(); ++i) {
+				const PASN_OctetString &msg = sigs[i];
+				if (h323debug)
+					cout << setprecision(0) << "Q.931 message data is " << msg << endl;
+				if(!q931.Decode((const PBYTEArray &)msg)) {
+					cout << "Error while decoding Q.931 message" << endl;
+					return FALSE;
+				}
+				res = TRUE;
+				if (h323debug)
+					cout << setprecision(0) << "Received QSIG message " << q931 << endl;
+			}
+		}
+	}
+	return res;
+}
+
+static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu)
+{
+	if (!pdu.GetQ931().HasIE(Q931::UserUserIE))
+		return NULL;
+
+	H225_H323_UU_PDU_h323_message_body &body = pdu.m_h323_uu_pdu.m_h323_message_body;
+	switch (body.GetTag()) {
+	case H225_H323_UU_PDU_h323_message_body::e_setup:
+		return &((H225_Setup_UUIE &)body).m_sourceInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_callProceeding:
+		return &((H225_CallProceeding_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_connect:
+		return &((H225_Connect_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_alerting:
+		return &((H225_Alerting_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_facility:
+		return &((H225_Facility_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_progress:
+		return &((H225_Progress_UUIE &)body).m_destinationInfo;
+	}
+	return NULL;
+}
+
+static PBoolean QSIGTunnelRequested(H323SignalPDU &pdu)
+{
+	H225_EndpointType *epType = GetEndpointType(pdu);
+	if (epType) {
+		if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+			return FALSE;
+		}
+		H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+		for (int i = 0; i < protos.GetSize(); ++i)
+		{
+			if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+					(((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+				return TRUE;
+			}
+		}
+	}
+	return FALSE;
+}
+
+static PBoolean EmbedQSIGTunneledInfo(H323SignalPDU &pdu)
+{
+	static const Q931::InformationElementCodes codes[] =
+	{ Q931::RedirectingNumberIE, Q931::FacilityIE };
+
+	Q931 &q931 = pdu.GetQ931();
+	PBYTEArray message;
+
+	q931.Encode(message);
+
+	/* Remove non-standard IEs */
+	for(unsigned i = 0; i < ARRAY_LEN(codes); ++i) {
+		if (q931.HasIE(codes[i])) {
+			q931.RemoveIE(codes[i]);
+		}
+	}
+
+	H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+	H225_EndpointType *epType = GetEndpointType(pdu);
+	if (epType) {
+		if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+			(*epType).IncludeOptionalField(H225_EndpointType::e_supportedTunnelledProtocols);
+			(*epType).m_supportedTunnelledProtocols.SetSize(0);
+		}
+		H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+		PBoolean addQSIG = TRUE;
+		for (int i = 0; i < protos.GetSize(); ++i)
+		{
+			if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+					(((PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+				addQSIG = FALSE;
+				break;
+			}
+		}
+		if (addQSIG) {
+			H225_TunnelledProtocol *proto = new H225_TunnelledProtocol;
+			(*proto).m_id.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+			(PASN_ObjectId &)(proto->m_id) = OID_QSIG;
+			protos.Append(proto);
+		}
+	}
+	if (!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage))
+		uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage);
+	H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+	H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+	if ((proto.GetTag() != H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) ||
+			(((const PASN_ObjectId &)proto).AsString() != OID_QSIG)) {
+		proto.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+		(PASN_ObjectId &)proto = OID_QSIG;
+		sig.m_messageContent.SetSize(0);
+	}
+	PASN_OctetString *msg = new PASN_OctetString;
+	sig.m_messageContent.Append(msg);
+	*msg = message;
+	return TRUE;
+}
+
+PBoolean MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu)
+{
+	if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG))
+		EmbedQSIGTunneledInfo(pdu);
+	if ((tunnelOptions & H323_TUNNEL_CISCO) || (remoteTunnelOptions & H323_TUNNEL_CISCO))
+		EmbedCiscoTunneledInfo(pdu);
+
+	return TRUE;
+}
+
+/* Handle tunneled messages */
+PBoolean MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu)
+{
+	if (pdu.GetQ931().HasIE(Q931::UserUserIE)) {
+		Q931 tunneledInfo;
+		const Q931 *q931Info;
+
+		q931Info = NULL;
+		if (FetchCiscoTunneledInfo(tunneledInfo, pdu)) {
+			q931Info = &tunneledInfo;
+			remoteTunnelOptions |= H323_TUNNEL_CISCO;
+		}
+		if (FetchQSIGTunneledInfo(tunneledInfo, pdu)) {
+			q931Info = &tunneledInfo;
+			remoteTunnelOptions |= H323_TUNNEL_QSIG;
+		}
+		if (!(remoteTunnelOptions & H323_TUNNEL_QSIG) && QSIGTunnelRequested(pdu)) {
+			remoteTunnelOptions |= H323_TUNNEL_QSIG;
+		}
+		if (q931Info) {
+			if (q931Info->HasIE(Q931::RedirectingNumberIE)) {
+				pdu.GetQ931().SetIE(Q931::RedirectingNumberIE, q931Info->GetIE(Q931::RedirectingNumberIE));
+				if (h323debug) {
+					PString number;
+					unsigned reason;
+					if(q931Info->GetRedirectingNumber(number, NULL, NULL, NULL, NULL, &reason, 0, 0, 0))
+						cout << "Got redirection from " << number << ", reason " << reason << endl;
+				}
+			}
+		}
+	}
+
+	return H323Connection::HandleSignalPDU(pdu);
+}
+#endif
+
+PBoolean MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
+{
+	call_details_t cd;
+
+	if (h323debug) {
+		cout << "\t--Received SETUP message" << endl;
+	}
+
+	if (connectionState == ShuttingDownConnection)
+		return FALSE;
+
+	SetCallDetails(&cd, setupPDU, TRUE);
+
+	/* Notify Asterisk of the request */
+	call_options_t *res = on_incoming_call(&cd);
+
+	if (!res) {
+		if (h323debug) {
+			cout << "\t-- Call Failed" << endl;
+		}
+		return FALSE;
+	}
+
+	SetCallOptions(res, TRUE);
+
+	/* Disable fastStart if requested by remote side */
+	if (h245Tunneling && !setupPDU.m_h323_uu_pdu.m_h245Tunneling) {
+		masterSlaveDeterminationProcedure->Stop();
+		capabilityExchangeProcedure->Stop();
+		PTRACE(3, "H225\tFast Start DISABLED!");
+		h245Tunneling = FALSE;
+	}
+
+	return H323Connection::OnReceivedSignalSetup(setupPDU);
+}
+
+PBoolean MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
+{
+	call_details_t cd;
+
+	if (h323debug) {
+		cout << "\t-- Sending SETUP message" << endl;
+	}
+
+	if (connectionState == ShuttingDownConnection)
+		return FALSE;
+
+	if (progressSetup)
+		setupPDU.GetQ931().SetProgressIndicator(progressSetup);
+
+	if (redirect_reason >= 0) {
+		setupPDU.GetQ931().SetRedirectingNumber(rdnis, 0, 0, 0, 0, redirect_reason);
+		/* OpenH323 incorrectly fills number IE when redirecting reason is specified - fix it */
+		PBYTEArray IE(setupPDU.GetQ931().GetIE(Q931::RedirectingNumberIE));
+		IE[0] = IE[0] & 0x7f;
+		IE[1] = IE[1] & 0x7f;
+		setupPDU.GetQ931().SetIE(Q931::RedirectingNumberIE, IE);
+	}
+
+	if (transfer_capability)
+		setupPDU.GetQ931().SetBearerCapabilities((Q931::InformationTransferCapability)(transfer_capability & 0x1f), 1, ((transfer_capability >> 5) & 3));
+
+	SetCallDetails(&cd, setupPDU, FALSE);
+
+	int res = on_outgoing_call(&cd);
+	if (!res) {
+		if (h323debug) {
+			cout << "\t-- Call Failed" << endl;
+		}
+		return FALSE;
+	}
+
+	/* OpenH323 will build calling party information with default
+	   type and presentation information, so build it to be recorded
+	   by embedding routines */
+	setupPDU.GetQ931().SetCallingPartyNumber(sourceE164, (cid_ton >> 4) & 0x07,
+			cid_ton & 0x0f, (cid_presentation >> 5) & 0x03, cid_presentation & 0x1f);
+	setupPDU.GetQ931().SetDisplayName(GetDisplayName());
+
+#ifdef TUNNELLING
+	EmbedTunneledInfo(setupPDU);
+#endif
+
+	return H323Connection::OnSendSignalSetup(setupPDU);
+}
+
+static PBoolean BuildFastStartList(const H323Channel & channel,
+		H225_ArrayOf_PASN_OctetString & array,
+		H323Channel::Directions reverseDirection)
+{
+	H245_OpenLogicalChannel open;
+	const H323Capability & capability = channel.GetCapability();
+
+	if (channel.GetDirection() != reverseDirection) {
+		if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType))
+			return FALSE;
+	}
+	else {
+		if (!capability.OnSendingPDU(open.m_reverseLogicalChannelParameters.m_dataType))
+			return FALSE;
+
+		open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag(
+				H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_none);
+		open.m_forwardLogicalChannelParameters.m_dataType.SetTag(H245_DataType::e_nullData);
+		open.IncludeOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters);
+	}
+
+	if (!channel.OnSendingPDU(open))
+		return FALSE;
+
+	PTRACE(4, "H225\tBuild fastStart:\n	" << setprecision(2) << open);
+	PINDEX last = array.GetSize();
+	array.SetSize(last+1);
+	array[last].EncodeSubType(open);
+
+	PTRACE(3, "H225\tBuilt fastStart for " << capability);
+	return TRUE;
+}
+
+H323Connection::CallEndReason MyH323Connection::SendSignalSetup(const PString & alias,
+		const H323TransportAddress & address)
+{
+	// Start the call, first state is asking gatekeeper
+	connectionState = AwaitingGatekeeperAdmission;
+
+	// Indicate the direction of call.
+	if (alias.IsEmpty())
+		remotePartyName = remotePartyAddress = address;
+	else {
+		remotePartyName = alias;
+		remotePartyAddress = alias + '@' + address;
+	}
+
+	// Start building the setup PDU to get various ID's
+	H323SignalPDU setupPDU;
+	H225_Setup_UUIE & setup = setupPDU.BuildSetup(*this, address);
+
+#ifdef H323_H450
+	h450dispatcher->AttachToSetup(setupPDU);
+#endif
+
+	// Save the identifiers generated by BuildSetup
+	setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
+
+	H323TransportAddress gatekeeperRoute = address;
+
+	// Check for gatekeeper and do admission check if have one
+	H323Gatekeeper * gatekeeper = endpoint.GetGatekeeper();
+	H225_ArrayOf_AliasAddress newAliasAddresses;
+	if (gatekeeper != NULL) {
+		H323Gatekeeper::AdmissionResponse response;
+		response.transportAddress = &gatekeeperRoute;
+		response.aliasAddresses = &newAliasAddresses;
+		if (!gkAccessTokenOID)
+			response.accessTokenData = &gkAccessTokenData;
+		while (!gatekeeper->AdmissionRequest(*this, response, alias.IsEmpty())) {
+			PTRACE(1, "H225\tGatekeeper refused admission: "
+					<< (response.rejectReason == UINT_MAX
+					? PString("Transport error")
+					: H225_AdmissionRejectReason(response.rejectReason).GetTagName()));
+#ifdef H323_H450
+			h4502handler->onReceivedAdmissionReject(H4501_GeneralErrorList::e_notAvailable);
+#endif
+
+			switch (response.rejectReason) {
+			case H225_AdmissionRejectReason::e_calledPartyNotRegistered:
+				return EndedByNoUser;
+			case H225_AdmissionRejectReason::e_requestDenied:
+				return EndedByNoBandwidth;
+			case H225_AdmissionRejectReason::e_invalidPermission:
+			case H225_AdmissionRejectReason::e_securityDenial:
+				return EndedBySecurityDenial;
+			case H225_AdmissionRejectReason::e_resourceUnavailable:
+				return EndedByRemoteBusy;
+			case H225_AdmissionRejectReason::e_incompleteAddress:
+				if (OnInsufficientDigits())
+					break;
+				// Then default case
+			default:
+				return EndedByGatekeeper;
+			}
+
+			PString lastRemotePartyName = remotePartyName;
+			while (lastRemotePartyName == remotePartyName) {
+				Unlock(); // Release the mutex as can deadlock trying to clear call during connect.
+				digitsWaitFlag.Wait();
+				if (!Lock()) // Lock while checking for shutting down.
+					return EndedByCallerAbort;
+			}
+		}
+		mustSendDRQ = TRUE;
+		if (response.gatekeeperRouted) {
+			setup.IncludeOptionalField(H225_Setup_UUIE::e_endpointIdentifier);
+			setup.m_endpointIdentifier = gatekeeper->GetEndpointIdentifier();
+			gatekeeperRouted = TRUE;
+		}
+	}
+
+#ifdef H323_TRANSNEXUS_OSP
+	// check for OSP server (if not using GK)
+	if (gatekeeper == NULL) {
+		OpalOSP::Provider * ospProvider = endpoint.GetOSPProvider();
+		if (ospProvider != NULL) {
+			OpalOSP::Transaction * transaction = new OpalOSP::Transaction();
+			if (transaction->Open(*ospProvider) != 0) {
+				PTRACE(1, "H225\tCannot create OSP transaction");
+				return EndedByOSPRefusal;
+			}
+
+			OpalOSP::Transaction::DestinationInfo destInfo;
+			if (!AuthoriseOSPTransaction(*transaction, destInfo)) {
+				delete transaction;
+				return EndedByOSPRefusal;
+			}
+
+			// save the transaction for use by the call
+			ospTransaction = transaction;
+
+			// retrieve the call information
+			gatekeeperRoute = destInfo.destinationAddress;
+			newAliasAddresses.Append(new H225_AliasAddress(destInfo.calledNumber));
+
+			// insert the token
+			setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
+			destInfo.InsertToken(setup.m_tokens);
+		}
+	}
+#endif
+
+	// Update the field e_destinationAddress in the SETUP PDU to reflect the new 
+	// alias received in the ACF (m_destinationInfo).
+	if (newAliasAddresses.GetSize() > 0) {
+		setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress);
+		setup.m_destinationAddress = newAliasAddresses;
+
+		// Update the Q.931 Information Element (if is an E.164 address)
+		PString e164 = H323GetAliasAddressE164(newAliasAddresses);
+		if (!e164)
+			remotePartyNumber = e164;
+	}
+
+	if (addAccessTokenToSetup && !gkAccessTokenOID && !gkAccessTokenData.IsEmpty()) {
+		PString oid1, oid2;
+		PINDEX comma = gkAccessTokenOID.Find(',');
+		if (comma == P_MAX_INDEX)
+			oid1 = oid2 = gkAccessTokenOID;
+		else {
+			oid1 = gkAccessTokenOID.Left(comma);
+			oid2 = gkAccessTokenOID.Mid(comma+1);
+		}
+		setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
+		PINDEX last = setup.m_tokens.GetSize();
+		setup.m_tokens.SetSize(last+1);
+		setup.m_tokens[last].m_tokenOID = oid1;
+		setup.m_tokens[last].IncludeOptionalField(H235_ClearToken::e_nonStandard);
+		setup.m_tokens[last].m_nonStandard.m_nonStandardIdentifier = oid2;
+		setup.m_tokens[last].m_nonStandard.m_data = gkAccessTokenData;
+	}
+
+	if (!signallingChannel->SetRemoteAddress(gatekeeperRoute)) {
+		PTRACE(1, "H225\tInvalid "
+					 << (gatekeeperRoute != address ? "gatekeeper" : "user")
+					 << " supplied address: \"" << gatekeeperRoute << '"');
+		connectionState = AwaitingTransportConnect;
+		return EndedByConnectFail;
+	}
+
+	// Do the transport connect
+	connectionState = AwaitingTransportConnect;
+
+	// Release the mutex as can deadlock trying to clear call during connect.
+	Unlock();
+
+	signallingChannel->SetWriteTimeout(100);
+
+	PBoolean connectFailed = !signallingChannel->Connect();
+
+	// Lock while checking for shutting down.
+	if (!Lock())
+		return EndedByCallerAbort;
+
+	// See if transport connect failed, abort if so.
+	if (connectFailed) {
+		connectionState = NoConnectionActive;
+		switch (signallingChannel->GetErrorNumber()) {
+			case ENETUNREACH :
+				return EndedByUnreachable;
+			case ECONNREFUSED :
+				return EndedByNoEndPoint;
+			case ETIMEDOUT :
+				return EndedByHostOffline;
+		}
+		return EndedByConnectFail;
+	}
+
+	PTRACE(3, "H225\tSending Setup PDU");
+	connectionState = AwaitingSignalConnect;
+
+	// Put in all the signalling addresses for link
+	setup.IncludeOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress);
+	signallingChannel->SetUpTransportPDU(setup.m_sourceCallSignalAddress, TRUE);
+	if (!setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress)) {
+		setup.IncludeOptionalField(H225_Setup_UUIE::e_destCallSignalAddress);
+		signallingChannel->SetUpTransportPDU(setup.m_destCallSignalAddress, FALSE);
+	}
+
+	// If a standard call do Fast Start (if required)
+	if (setup.m_conferenceGoal.GetTag() == H225_Setup_UUIE_conferenceGoal::e_create) {
+
+		// Get the local capabilities before fast start is handled
+		OnSetLocalCapabilities();
+
+		// Ask the application what channels to open
+		PTRACE(3, "H225\tCheck for Fast start by local endpoint");
+		fastStartChannels.RemoveAll();
+		OnSelectLogicalChannels();
+
+		// If application called OpenLogicalChannel, put in the fastStart field
+		if (!fastStartChannels.IsEmpty()) {
+			PTRACE(3, "H225\tFast start begun by local endpoint");
+			for (PINDEX i = 0; i < fastStartChannels.GetSize(); i++)
+				BuildFastStartList(fastStartChannels[i], setup.m_fastStart, H323Channel::IsReceiver);
+			if (setup.m_fastStart.GetSize() > 0)
+				setup.IncludeOptionalField(H225_Setup_UUIE::e_fastStart);
+		}
+
+		// Search the capability set and see if we have video capability
+		for (PINDEX i = 0; i < localCapabilities.GetSize(); i++) {
+			switch (localCapabilities[i].GetMainType()) {
+			case H323Capability::e_Audio:
+			case H323Capability::e_UserInput:
+				break;
+
+			default:	// Is video or other data (eg T.120)
+				setupPDU.GetQ931().SetBearerCapabilities(Q931::TransferUnrestrictedDigital, 6);
+				i = localCapabilities.GetSize(); // Break out of the for loop
+				break;
+			}
+		}
+	}
+
+	if (!OnSendSignalSetup(setupPDU))
+		return EndedByNoAccept;
+
+	// Do this again (was done when PDU was constructed) in case
+	// OnSendSignalSetup() changed something.
+//	setupPDU.SetQ931Fields(*this, TRUE);
+	setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
+
+	fastStartState = FastStartDisabled;
+	PBoolean set_lastPDUWasH245inSETUP = FALSE;
+
+	if (h245Tunneling && doH245inSETUP) {
+		h245TunnelTxPDU = &setupPDU;
+
+		// Try and start the master/slave and capability exchange through the tunnel
+		// Note: this used to be disallowed but is now allowed as of H323v4
+		PBoolean ok = StartControlNegotiations();
+
+		h245TunnelTxPDU = NULL;
+
+		if (!ok)
+			return EndedByTransportFail;
+
+		if (setup.m_fastStart.GetSize() > 0) {
+			// Now if fast start as well need to put this in setup specific field
+			// and not the generic H.245 tunneling field
+			setup.IncludeOptionalField(H225_Setup_UUIE::e_parallelH245Control);
+			setup.m_parallelH245Control = setupPDU.m_h323_uu_pdu.m_h245Control;
+			setupPDU.m_h323_uu_pdu.RemoveOptionalField(H225_H323_UU_PDU::e_h245Control);
+			set_lastPDUWasH245inSETUP = TRUE;
+		}
+	}
+
+	// Send the initial PDU
+	setupTime = PTime();
+	if (!WriteSignalPDU(setupPDU))
+		return EndedByTransportFail;
+
+	// WriteSignalPDU always resets lastPDUWasH245inSETUP.
+	// So set it here if required
+	if (set_lastPDUWasH245inSETUP)
+		lastPDUWasH245inSETUP = TRUE;
+
+	// Set timeout for remote party to answer the call
+	signallingChannel->SetReadTimeout(endpoint.GetSignallingChannelCallTimeout());
+
+	return NumCallEndReasons;
+}
+
+
+PBoolean MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
+{
+	if (h323debug) {
+		cout << "\t-- Sending RELEASE COMPLETE" << endl;
+	}
+	if (cause > 0)
+		releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
+
+#ifdef TUNNELLING
+	EmbedTunneledInfo(releaseCompletePDU);
+#endif
+
+	return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
+}
+
+PBoolean MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu)
+{
+	if (h323debug) {
+		cout << "\t-- Received Facility message... " << endl;
+	}
+	return H323Connection::OnReceivedFacility(pdu);
+}
+
+void MyH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu)
+{
+	if (h323debug) {
+		cout << "\t-- Received RELEASE COMPLETE message..." << endl;
+	}
+	if (on_hangup)
+		on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
+	return H323Connection::OnReceivedReleaseComplete(pdu);
+}
+
+PBoolean MyH323Connection::OnClosingLogicalChannel(H323Channel & channel)
+{
+	if (h323debug) {
+		cout << "\t-- Closing logical channel..." << endl;
+	}
+	return H323Connection::OnClosingLogicalChannel(channel);
+}
+
+void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+	SendUserInputModes mode = GetRealSendUserInputMode();
+//	That is recursive call... Why?
+//	on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken());
+	if ((tone != ' ') || (mode == SendUserInputAsTone) || (mode == SendUserInputAsInlineRFC2833)) {
+		if (h323debug) {
+			cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
+		}
+		H323Connection::SendUserInputTone(tone, duration);
+	}
+}
+
+void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+	/* Why we should check this? */
+	if ((dtmfMode & (H323_DTMF_CISCO | H323_DTMF_RFC2833 | H323_DTMF_SIGNAL)) != 0) {
+		if (h323debug) {
+			cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
+		}
+		on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration);
+	}
+}
+
+void MyH323Connection::OnUserInputString(const PString &value)
+{
+	if (h323debug) {
+		cout << "\t-- Received user input string (" << value << ") from remote." << endl;
+	}
+	on_receive_digit(GetCallReference(), value[0], (const char *)GetCallToken(), 0);
+}
+
+void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
+{
+	PINDEX i;
+
+	H323Connection::OnSendCapabilitySet(pdu);
+
+	H245_ArrayOf_CapabilityTableEntry & tables = pdu.m_capabilityTable;
+	for(i = 0; i < tables.GetSize(); i++)
+	{
+		H245_CapabilityTableEntry & entry = tables[i];
+		if (entry.HasOptionalField(H245_CapabilityTableEntry::e_capability)) {
+			H245_Capability & cap = entry.m_capability;
+			if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
+				H245_AudioTelephonyEventCapability & atec = cap;
+				atec.m_dynamicRTPPayloadType = dtmfCodec[0];
+//				on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec[0]);
+#ifdef PTRACING
+				if (h323debug) {
+					cout << "\t-- Receiving RFC2833 on payload " <<
+						atec.m_dynamicRTPPayloadType << endl;
+				}
+#endif
+			}
+		}
+	}
+}
+
+void MyH323Connection::OnSetLocalCapabilities()
+{
+	if (on_setcapabilities)
+		on_setcapabilities(GetCallReference(), (const char *)callToken);
+}
+
+PBoolean MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
+							const H245_MultiplexCapability * muxCap,
+							H245_TerminalCapabilitySetReject & reject)
+{
+	struct __codec__ {
+		unsigned int asterisk_codec;
+		unsigned int h245_cap;
+		const char *oid;
+		const char *formatName;
+	};
+	static const struct __codec__ codecs[] = {
+		{ AST_FORMAT_G723_1, H245_AudioCapability::e_g7231 },
+		{ AST_FORMAT_GSM, H245_AudioCapability::e_gsmFullRate },
+		{ AST_FORMAT_ULAW, H245_AudioCapability::e_g711Ulaw64k },
+		{ AST_FORMAT_ALAW, H245_AudioCapability::e_g711Alaw64k },
+		{ AST_FORMAT_G729A, H245_AudioCapability::e_g729AnnexA },
+		{ AST_FORMAT_G729A, H245_AudioCapability::e_g729 },
+		{ AST_FORMAT_G726_AAL2, H245_AudioCapability::e_nonStandard, NULL, CISCO_G726r32 },
+#ifdef AST_FORMAT_MODEM
+		{ AST_FORMAT_MODEM, H245_DataApplicationCapability_application::e_t38fax },
+#endif
+		{ 0 }
+	};
+
+#if 0
+	static const struct __codec__ vcodecs[] = {
+#ifdef HAVE_H261
+		{ AST_FORMAT_H261, H245_VideoCapability::e_h261VideoCapability },
+#endif
+#ifdef HAVE_H263
+		{ AST_FORMAT_H263, H245_VideoCapability::e_h263VideoCapability },
+#endif
+#ifdef HAVE_H264
+		{ AST_FORMAT_H264, H245_VideoCapability::e_genericVideoCapability, "0.0.8.241.0.0.1" },
+#endif
+		{ 0 }
+	};
+#endif
+	struct ast_codec_pref prefs;
+	RTP_DataFrame::PayloadTypes pt;
+
+	if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
+		return FALSE;
+	}
+
+	memset(&prefs, 0, sizeof(prefs));
+	int peer_capabilities = 0;
+	for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
+		unsigned int subType = remoteCapabilities[i].GetSubType();
+		if (h323debug) {
+			cout << "Peer capability is " << remoteCapabilities[i] << endl;
+		}
+		switch(remoteCapabilities[i].GetMainType()) {
+		case H323Capability::e_Audio:
+			for (int x = 0; codecs[x].asterisk_codec > 0; ++x) {
+				if ((subType == codecs[x].h245_cap) && (!codecs[x].formatName || (!strcmp(codecs[x].formatName, (const char *)remoteCapabilities[i].GetFormatName())))) {
+					int ast_codec = codecs[x].asterisk_codec;
+					int ms = 0;
+					struct ast_format tmpfmt;
+					if (!(peer_capabilities & ast_format_id_to_old_bitfield((enum ast_format_id) ast_codec))) {
+						struct ast_format_list format;
+						ast_codec_pref_append(&prefs, ast_format_set(&tmpfmt, (enum ast_format_id) ast_codec, 0));
+						format = ast_codec_pref_getsize(&prefs, &tmpfmt);
+						if ((ast_codec == AST_FORMAT_ALAW) || (ast_codec == AST_FORMAT_ULAW)) {
+							ms = remoteCapabilities[i].GetTxFramesInPacket();
+						} else
+							ms = remoteCapabilities[i].GetTxFramesInPacket() * format.inc_ms;
+						ast_codec_pref_setsize(&prefs, &tmpfmt, ms);
+					}
+					if (h323debug) {
+						cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << ast_codec << ", frame size (in ms) is " << ms << endl;
+					}
+					peer_capabilities |= ast_format_id_to_old_bitfield((enum ast_format_id) ast_codec);
+				}
+			}
+			break;
+		case H323Capability::e_Data:
+			if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), CISCO_DTMF_RELAY)) {
+				pt = remoteCapabilities[i].GetPayloadType();
+				if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+					on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 1);
+//					if (sendUserInputMode == SendUserInputAsTone)
+//						sendUserInputMode = SendUserInputAsInlineRFC2833;
+				}
+#ifdef PTRACING
+				if (h323debug) {
+					cout << "\t-- Outbound Cisco RTP DTMF on payload " << pt << endl;
+				}
+#endif
+			}
+			break;
+		case H323Capability::e_UserInput:
+			if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833])) {
+				pt = remoteCapabilities[i].GetPayloadType();
+				if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+					on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 0);
+//					if (sendUserInputMode == SendUserInputAsTone)
+//						sendUserInputMode = SendUserInputAsInlineRFC2833;
+				}
+#ifdef PTRACING
+				if (h323debug) {
+					cout << "\t-- Outbound RFC2833 on payload " << pt << endl;
+				}
+#endif
+			}
+			break;
+#if 0
+		case H323Capability::e_Video:
+			for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
+				if (subType == vcodecs[x].h245_cap) {
+					H245_CapabilityIdentifier *cap = NULL;
+					H245_GenericCapability y;
+					if (vcodecs[x].oid) {
+						cap = new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard);
+						PASN_ObjectId &object_id = *cap;
+						object_id = vcodecs[x].oid;
+						y.m_capabilityIdentifier = *cap;
+					}
+					if ((subType != H245_VideoCapability::e_genericVideoCapability) ||
+							(vcodecs[x].oid && ((const H323GenericVideoCapability &)remoteCapabilities[i]).IsGenericMatch((const H245_GenericCapability)y))) {
+						if (h323debug) {
+							cout << "Found peer video capability " << remoteCapabilities[i] << ", Asterisk code is " << vcodecs[x].asterisk_codec << endl;
+						}
+						peer_capabilities |= vcodecs[x].asterisk_codec;
+					}
+					if (cap)
+						delete(cap);
+				}
+			}
+			break;
+#endif
+		default:
+			break;
+		}
+	}
+
+#if 0
+	redir_capabilities &= peer_capabilities;
+#endif
+	if (on_setpeercapabilities)
+		on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities, &prefs);
+
+	return TRUE;
+}
+
+H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
+									H323Channel::Directions dir,
+									unsigned sessionID,
+									const H245_H2250LogicalChannelParameters * /*param*/,
+									RTP_QOS * /*param*/ )
+{
+	/* Do not open tx channel when transmitter has been paused by empty TCS */
+	if ((dir == H323Channel::IsTransmitter) && transmitterSidePaused)
+		return NULL;
+
+	return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
+}
+
+/** This callback function is invoked once upon creation of each
+  * channel for an H323 session
+  */
+PBoolean MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
+{
+	/* Increase the count of channels we have open */
+	channelsOpen++;
+
+	if (h323debug) {
+		cout << "\t-- Started logical channel: "
+				<< ((channel.GetDirection() == H323Channel::IsTransmitter) ? "sending " : ((channel.GetDirection() == H323Channel::IsReceiver) ? "receiving " : " "))
+				<< (const char *)(channel.GetCapability()).GetFormatName() << endl;
+		cout << "\t\t-- channelsOpen = " << channelsOpen << endl;
+	}
+	return connectionState != ShuttingDownConnection;
+}
+
+void MyH323Connection::SetCapabilities(int caps, int dtmf_mode, void *_prefs, int pref_codec)
+{
+	PINDEX lastcap = -1; /* last common capability index */
+	int alreadysent = 0;
+	int codec;
+	int x, y;
+	struct ast_codec_pref *prefs = (struct ast_codec_pref *)_prefs;
+	struct ast_format_list format;
+	int frames_per_packet;
+	struct ast_format tmpfmt;
+	H323Capability *cap;
+
+	localCapabilities.RemoveAll();
+
+	/* Add audio codecs in preference order first, then
+	   audio codecs without preference as allowed by mask */
+	for (y = 0, x = -1; x < 32 + 32; ++x) {
+		ast_format_clear(&tmpfmt);
+		if (x < 0)
+			codec = pref_codec;
+		else if (y || (!(ast_codec_pref_index(prefs, x, &tmpfmt)))) {
+			if (!y)
+				y = 1;
+			else
+				y <<= 1;
+			codec = y;
+		}
+		if (tmpfmt.id) {
+			codec = ast_format_to_old_bitfield(&tmpfmt);
+		}
+		if (!(caps & codec) || (alreadysent & codec) || (AST_FORMAT_GET_TYPE(ast_format_id_from_old_bitfield(codec)) != AST_FORMAT_TYPE_AUDIO))
+			continue;
+		alreadysent |= codec;
+		/* format.cur_ms will be set to default if packetization is not explicitly set */
+		format = ast_codec_pref_getsize(prefs, ast_format_from_old_bitfield(&tmpfmt, codec));
+		frames_per_packet = (format.inc_ms ? format.cur_ms / format.inc_ms : format.cur_ms);
+		switch(ast_format_id_from_old_bitfield(codec)) {
+#if 0
+		case AST_FORMAT_SPEEX:
+			/* Not real sure if Asterisk acutally supports all
+			   of the various different bit rates so add them
+			   all and figure it out later*/
+
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
+			break;
+#endif
+		case AST_FORMAT_G729A:
+			AST_G729ACapability *g729aCap;
+			AST_G729Capability *g729Cap;
+			lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability(frames_per_packet));
+			lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability(frames_per_packet));
+			g729aCap->SetTxFramesInPacket(format.cur_ms);
+			g729Cap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		case AST_FORMAT_G723_1:
+			AST_G7231Capability *g7231Cap;
+			lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, TRUE));
+			g7231Cap->SetTxFramesInPacket(format.cur_ms);
+			lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, FALSE));
+			g7231Cap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		case AST_FORMAT_GSM:
+			AST_GSM0610Capability *gsmCap;
+			lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability(frames_per_packet));
+			gsmCap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		case AST_FORMAT_ULAW:
+			AST_G711Capability *g711uCap;
+			lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::muLaw));
+			g711uCap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		case AST_FORMAT_ALAW:
+			AST_G711Capability *g711aCap;
+			lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::ALaw));
+			g711aCap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		case AST_FORMAT_G726_AAL2:
+			AST_CiscoG726Capability *g726Cap;
+			lastcap = localCapabilities.SetCapability(0, 0, g726Cap = new AST_CiscoG726Capability(frames_per_packet));
+			g726Cap->SetTxFramesInPacket(format.cur_ms);
+			break;
+		default:
+			alreadysent &= ~codec;
+			break;
+		}
+	}
+
+	cap = new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245);
+	if (cap && cap->IsUsable(*this)) {
+		lastcap++;
+		lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+	} else {
+		delete cap;				/* Capability is not usable */
+	}
+
+	dtmfMode = dtmf_mode;
+	if (h323debug) {
+		cout << "DTMF mode is " << (int)dtmfMode << endl;
+	}
+	if (dtmfMode) {
+		lastcap++;
+		if (dtmfMode == H323_DTMF_INBAND) {
+			cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString);
+			if (cap && cap->IsUsable(*this)) {
+				lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+			} else {
+				delete cap;		/* Capability is not usable */
+			}	
+			sendUserInputMode = SendUserInputAsString;
+		} else {
+			if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+				cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833);
+				if (cap && cap->IsUsable(*this))
+					lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+				else {
+					dtmfMode |= H323_DTMF_SIGNAL;
+					delete cap;	/* Capability is not usable */
+				}
+			}
+			if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+				/* Try Cisco's RTP DTMF relay too, but prefer RFC2833 or h245-signal */
+				cap = new AST_CiscoDtmfCapability();
+				if (cap && cap->IsUsable(*this)) {
+					lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+					/* We cannot send Cisco RTP DTMFs, use h245-signal instead */
+					dtmfMode |= H323_DTMF_SIGNAL;
+				} else {
+					dtmfMode |= H323_DTMF_SIGNAL;
+					delete cap;	/* Capability is not usable */
+				}
+			}
+			if ((dtmfMode & H323_DTMF_SIGNAL) != 0) {
+				/* Cisco usually sends DTMF correctly only through h245-alphanumeric or h245-signal */
+				cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245);
+				if (cap && cap->IsUsable(*this))
+					lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+				else
+					delete cap;	/* Capability is not usable */
+			}
+			sendUserInputMode = SendUserInputAsTone;	/* RFC2833 transmission handled at Asterisk level */
+		}
+	}
+
+	if (h323debug) {
+		cout << "Allowed Codecs for " << GetCallToken() << " (" << GetSignallingChannel()->GetLocalAddress() << "):\n\t" << setprecision(2) << localCapabilities << endl;
+	}
+}
+
+PBoolean MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address)
+{
+	// Check that it is an IP address, all we support at the moment
+	if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress
+#if P_HAS_IPV6
+		&& h245Address.GetTag() != H225_TransportAddress::e_ip6Address
+#endif
+	) {
+		PTRACE(1, "H225\tConnect of H245 failed: Unsupported transport");
+		return FALSE;
+	}
+
+	// Already have the H245 channel up.
+	if (controlChannel != NULL)
+		return TRUE;
+
+	PIPSocket::Address addr;
+	WORD port;
+	GetSignallingChannel()->GetLocalAddress().GetIpAndPort(addr, port);
+	if (addr) {
+		if (h323debug)
+			cout << "Using " << addr << " for outbound H.245 transport" << endl;
+		controlChannel = new MyH323TransportTCP(endpoint, addr);
+	} else
+		controlChannel = new MyH323TransportTCP(endpoint);
+	if (!controlChannel->SetRemoteAddress(h245Address)) {
+		PTRACE(1, "H225\tCould not extract H245 address");
+		delete controlChannel;
+		controlChannel = NULL;
+		return FALSE;
+	}
+	if (!controlChannel->Connect()) {
+		PTRACE(1, "H225\tConnect of H245 failed: " << controlChannel->GetErrorText());
+		delete controlChannel;
+		controlChannel = NULL;
+		return FALSE;
+	}
+
+	controlChannel->StartControlChannel(*this);
+	return TRUE;
+}
+
+#ifdef H323_H450
+void MyH323Connection::OnReceivedLocalCallHold(int linkedId)
+{
+	if (on_hold)
+		on_hold(GetCallReference(), (const char *)GetCallToken(), 1);
+}
+
+void MyH323Connection::OnReceivedLocalCallRetrieve(int linkedId)
+{
+	if (on_hold)
+		on_hold(GetCallReference(), (const char *)GetCallToken(), 0);
+}
+#endif
+
+void MyH323Connection::MyHoldCall(PBoolean isHold)
+{
+	if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) {
+		PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1);
+		H323SignalPDU signal;
+		signal.BuildNotify(*this);
+		signal.GetQ931().SetIE((Q931::InformationElementCodes)39 /* Q931::NotifyIE */, x);
+		if (h323debug)
+			cout << "Sending " << (isHold ? "HOLD" : "RETRIEVE") << " notification: " << signal << endl;
+		if ((holdHandling & H323_HOLD_Q931ONLY) != 0) {
+			PBYTEArray rawData;
+			signal.GetQ931().RemoveIE(Q931::UserUserIE);
+			signal.GetQ931().Encode(rawData);
+			signallingChannel->WritePDU(rawData);
+		} else
+			WriteSignalPDU(signal);
+	}
+#ifdef H323_H450
+	if ((holdHandling & H323_HOLD_H450) != 0) {
+		if (isHold)
+			h4504handler->HoldCall(TRUE);
+		else if (IsLocalHold())
+			h4504handler->RetrieveCall();
+	}
+#endif
+}
+
+
+/* MyH323_ExternalRTPChannel */
+MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
+							const H323Capability & capability,
+							Directions direction,
+							unsigned id)
+	: H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
+{
+	struct rtp_info *info;
+
+	/* Determine the Local (A side) IP Address and port */
+	info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken());
+	if (!info) {
+		cout << "\tERROR: on_external_rtp_create failure" << endl;
+		return;
+	} else {
+		localIpAddr = info->addr;
+		localPort = info->port;
+		/* tell the H.323 stack */
+		SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
+		/* clean up allocated memory */
+		ast_free(info);
+	}
+
+	/* Get the payload code	*/
+	OpalMediaFormat format(capability.GetFormatName(), FALSE);
+	payloadCode = format.GetPayloadType();
+}
+
+MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
+{
+	if (h323debug) {
+		cout << "\tExternalRTPChannel Destroyed" << endl;
+	}
+}
+
+PBoolean MyH323_ExternalRTPChannel::Start(void)
+{
+	/* Call ancestor first */
+	if (!H323_ExternalRTPChannel::Start()) {
+		return FALSE;
+	}
+
+	if (h323debug) {
+		cout << "\t\tExternal RTP Session Starting" << endl;
+		cout << "\t\tRTP channel id " << sessionID << " parameters:" << endl;
+	}
+
+	/* Collect the remote information */
+	H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort);
+
+	if (h323debug) {
+		cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
+		cout << "\t\t-- remotePort: " << remotePort << endl;
+		cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl;
+		cout << "\t\t-- ExternalPort: " << localPort << endl;
+	}
+	/* Notify Asterisk of remote RTP information */
+	on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort,
+		(const char *)connection.GetCallToken(), (int)payloadCode);
+	return TRUE;
+}
+
+PBoolean MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
+{
+	if (h323debug) {
+		cout << "	MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
+	}
+
+	if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
+		GetRemoteAddress(remoteIpAddr, remotePort);
+		if (h323debug) {
+			cout << "		-- remoteIpAddress: " << remoteIpAddr << endl;
+			cout << "		-- remotePort: " << remotePort << endl;
+		}
+		on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(),
+				remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+#ifdef H323_H450
+MyH4504Handler::MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp)
+	:H4504Handler(_conn, _disp)
+{
+	conn = &_conn;
+}
+
+void MyH4504Handler::OnReceivedLocalCallHold(int linkedId)
+{
+	if (conn) {
+		conn->Lock();
+		conn->OnReceivedLocalCallHold(linkedId);
+		conn->Unlock();
+	}
+}
+
+void MyH4504Handler::OnReceivedLocalCallRetrieve(int linkedId)
+{
+	if (conn) {
+		conn->Lock();
+		conn->OnReceivedLocalCallRetrieve(linkedId);
+		conn->Unlock();
+	}
+}
+#endif
+
+
+/** IMPLEMENTATION OF C FUNCTIONS */
+
+/**
+ * The extern "C" directive takes care for
+ * the ANSI-C representation of linkable symbols
+ */
+
+extern "C" {
+
+int h323_end_point_exist(void)
+{
+	if (!endPoint) {
+		return 0;
+	}
+	return 1;
+}
+
+void h323_end_point_create(void)
+{
+	channelsOpen = 0;
+	logstream = new PAsteriskLog();
+	PTrace::SetStream(logstream); 
+	endPoint = new MyH323EndPoint();
+}
+
+void h323_gk_urq(void)
+{
+	if (!h323_end_point_exist()) {
+		cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl;
+		return;
+	}
+	endPoint->RemoveGatekeeper();
+}
+
+void h323_debug(int flag, unsigned level)
+{
+	if (flag) {
+		PTrace:: SetLevel(level);
+	} else {
+		PTrace:: SetLevel(0);
+	}
+}
+
+/** Installs the callback functions on behalf of the PBX application */
+void h323_callback_register(setup_incoming_cb		ifunc,
+							setup_outbound_cb		sfunc,
+							on_rtp_cb				rtpfunc,
+							start_rtp_cb			lfunc,
+							clear_con_cb			clfunc,
+							chan_ringing_cb			rfunc,
+							con_established_cb		efunc,
+							receive_digit_cb		dfunc,
+							answer_call_cb			acfunc,
+							progress_cb				pgfunc,
+							rfc2833_cb				dtmffunc,
+							hangup_cb				hangupfunc,
+							setcapabilities_cb		capabilityfunc,
+							setpeercapabilities_cb	peercapabilityfunc,
+							onhold_cb				holdfunc)
+{
+	on_incoming_call = ifunc;
+	on_outgoing_call = sfunc;
+	on_external_rtp_create = rtpfunc;
+	on_start_rtp_channel = lfunc;
+	on_connection_cleared = clfunc;
+	on_chan_ringing = rfunc;
+	on_connection_established = efunc;
+	on_receive_digit = dfunc;
+	on_answer_call = acfunc;
+	on_progress = pgfunc;
+	on_set_rfc2833_payload = dtmffunc;
+	on_hangup = hangupfunc;
+	on_setcapabilities = capabilityfunc;
+	on_setpeercapabilities = peercapabilityfunc;
+	on_hold = holdfunc;
+}
+
+/**
+ * Add capability to the capability table of the end point.
+ */
+int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec)
+{
+	MyH323Connection *conn;
+
+	if (!h323_end_point_exist()) {
+		cout << " ERROR: [h323_set_capablities] No Endpoint, this is bad" << endl;
+		return 1;
+	}
+	if (!token || !*token) {
+		cout << " ERROR: [h323_set_capabilities] Invalid call token specified." << endl;
+		return 1;
+	}
+
+	PString myToken(token);
+	conn = (MyH323Connection *)endPoint->FindConnectionWithLock(myToken);
+	if (!conn) {
+		cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl;
+		return 1;
+	}
+	conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec);
+	conn->Unlock();
+
+	return 0;
+}
+
+/** Start the H.323 listener */
+int h323_start_listener(int listenPort, struct sockaddr_in bindaddr)
+{
+
+	if (!h323_end_point_exist()) {
+		cout << "ERROR: [h323_start_listener] No Endpoint, this is bad!" << endl;
+		return 1;
+	}
+
+	PIPSocket::Address interfaceAddress(bindaddr.sin_addr);
+	if (!listenPort) {
+		listenPort = 1720;
+	}
+	/** H.323 listener */
+	H323ListenerTCP *tcpListener;
+	tcpListener = new H323ListenerTCP(*endPoint, interfaceAddress, (WORD)listenPort);
+	if (!endPoint->StartListener(tcpListener)) {
+		cout << "ERROR: Could not open H.323 listener port on " << ((H323ListenerTCP *) tcpListener)->GetListenerPort() << endl;
+		delete tcpListener;
+		return 1;
+	}
+	cout << "  == H.323 listener started" << endl;
+	return 0;
+};
+
+/* Addition of functions just to make the channel driver compile with H323Plus */
+#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4)
+/* Alternate RTP port information for Same NAT */
+BOOL MyH323_ExternalRTPChannel::OnReceivedAltPDU(const H245_ArrayOf_GenericInformation & alternate )
+{
+	return TRUE;
+}
+
+/* Alternate RTP port information for Same NAT */
+BOOL MyH323_ExternalRTPChannel::OnSendingAltPDU(H245_ArrayOf_GenericInformation & alternate) const
+{
+	return TRUE;
+}
+
+/* Alternate RTP port information for Same NAT */
+void MyH323_ExternalRTPChannel::OnSendOpenAckAlt(H245_ArrayOf_GenericInformation & alternate) const
+{
+}
+
+/* Alternate RTP port information for Same NAT */
+BOOL MyH323_ExternalRTPChannel::OnReceivedAckAltPDU(const H245_ArrayOf_GenericInformation & alternate)
+{
+	return TRUE;
+}
+#endif
+
+
+int h323_set_alias(struct oh323_alias *alias)
+{
+	char *p;
+	char *num;
+	PString h323id(alias->name);
+	PString e164(alias->e164);
+	char *prefix;
+
+	if (!h323_end_point_exist()) {
+		cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl;
+		return 1;
+	}
+
+	cout << "== Adding alias \"" << h323id << "\" to endpoint" << endl;
+	endPoint->AddAliasName(h323id);
+	endPoint->RemoveAliasName(PProcess::Current().GetName());
+
+	if (!e164.IsEmpty()) {
+		cout << "== Adding E.164 \"" << e164 << "\" to endpoint" << endl;
+		endPoint->AddAliasName(e164);
+	}
+	if (strlen(alias->prefix)) {
+		p = prefix = strdup(alias->prefix);
+		while((num = strsep(&p, ",")) != (char *)NULL) {
+			cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl;
+			endPoint->SupportedPrefixes += PString(num);
+			endPoint->SetGateway();
+		}
+		if (prefix)
+			ast_free(prefix);
+	}
+	return 0;
+}
+
+void h323_set_id(char *id)
+{
+	PString h323id(id);
+
+	if (h323debug) {
+		cout << "  == Using '" << h323id << "' as our H.323ID for this call" << endl;
+	}
+	/* EVIL HACK */
+	endPoint->SetLocalUserName(h323id);
+}
+
+void h323_show_tokens(void)
+{
+	cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl;
+}
+
+void h323_show_version(void)
+{
+    cout << "H.323 version: " << OPENH323_MAJOR << "." << OPENH323_MINOR << "." << OPENH323_BUILD << endl;
+}
+
+/** Establish Gatekeeper communiations, if so configured,
+  *	register aliases for the H.323 endpoint to respond to.
+  */
+int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
+{
+	PString gkName = PString(gatekeeper);
+	PString pass = PString(secret);
+	H323TransportUDP *rasChannel;
+
+	if (!h323_end_point_exist()) {
+		cout << "ERROR: [h323_set_gk] No Endpoint, this is bad!" << endl;
+		return 1;
+	}
+
+	if (!gatekeeper) {
+		cout << "Error: Gatekeeper cannot be NULL" << endl;
+		return 1;
+	}
+	if (strlen(secret)) {
+		endPoint->SetGatekeeperPassword(pass);
+	}
+	if (gatekeeper_discover) {
+		/* discover the gk using multicast */
+		if (endPoint->DiscoverGatekeeper(new MyH323TransportUDP(*endPoint))) {
+			cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
+		} else {
+			cout << "Warning: Could not find a gatekeeper." << endl;
+			return 1;
+		}
+	} else {
+		rasChannel = new MyH323TransportUDP(*endPoint);
+
+		if (!rasChannel) {
+			cout << "Error: No RAS Channel, this is bad" << endl;
+			return 1;
+		}
+		if (endPoint->SetGatekeeper(gkName, rasChannel)) {
+			cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
+		} else {
+			cout << "Error registering with gatekeeper \"" << gkName << "\". " << endl;
+			/* XXX Maybe we should fire a new thread to attempt to re-register later and not kill asterisk here? */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/** Send a DTMF tone over the H323Connection with the
+  * specified token.
+  */
+void h323_send_tone(const char *call_token, char tone)
+{
+	if (!h323_end_point_exist()) {
+		cout << "ERROR: [h323_send_tone] No Endpoint, this is bad!" << endl;
+		return;
+	}
+	PString token = PString(call_token);
+	endPoint->SendUserTone(token, tone);
+}
+
+/** Make a call to the remote endpoint.
+  */
+int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options)
+{
+	int res;
+	PString	token;
+	PString	host(dest);
+
+	if (!h323_end_point_exist()) {
+		return 1;
+	}
+
+	res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options);
+	memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength());
+	return res;
+};
+
+int h323_clear_call(const char *call_token, int cause)
+{
+	H225_ReleaseCompleteReason dummy;
+	H323Connection::CallEndReason r = H323Connection::EndedByLocalUser;
+	MyH323Connection *connection;
+	const PString currentToken(call_token);
+
+	if (!h323_end_point_exist()) {
+		return 1;
+	}
+
+	if (cause) {
+		r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy);
+	}
+
+	connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken);
+	if (connection) {
+		connection->SetCause(cause);
+		connection->SetCallEndReason(r);
+		connection->Unlock();
+	}
+	endPoint->ClearCall(currentToken, r);
+	return 0;
+};
+
+/* Send Alerting PDU to H.323 caller */
+int h323_send_alerting(const char *token)
+{
+	const PString currentToken(token);
+	H323Connection * connection;
+
+	if (h323debug) {
+		cout << "\tSending alerting" << endl;
+	}
+	connection = endPoint->FindConnectionWithLock(currentToken);
+	if (!connection) {
+		cout << "No connection found for " << token << endl;
+		return -1;
+	}
+	connection->AnsweringCall(H323Connection::AnswerCallPending);
+	connection->Unlock();
+	return 0;
+}
+
+/* Send Progress PDU to H.323 caller */
+int h323_send_progress(const char *token)
+{
+	const PString currentToken(token);
+	H323Connection * connection;
+
+	connection = endPoint->FindConnectionWithLock(currentToken);
+	if (!connection) {
+		cout << "No connection found for " << token << endl;
+		return -1;
+	}
+#if 1
+	((MyH323Connection *)connection)->MySendProgress();
+#else
+	connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
+#endif
+	connection->Unlock();
+	return 0;
+}
+
+/** This function tells the h.323 stack to either
+    answer or deny an incoming call */
+int h323_answering_call(const char *token, int busy)
+{
+	const PString currentToken(token);
+	H323Connection * connection;
+
+	connection = endPoint->FindConnectionWithLock(currentToken);
+
+	if (!connection) {
+		cout << "No connection found for " << token << endl;
+		return -1;
+	}
+	if (!busy) {
+		if (h323debug) {
+			cout << "\tAnswering call " << token << endl;
+		}
+		connection->AnsweringCall(H323Connection::AnswerCallNow);
+	} else {
+		if (h323debug) {
+			cout << "\tdenying call " << token << endl;
+		}
+		connection->AnsweringCall(H323Connection::AnswerCallDenied);
+	}
+	connection->Unlock();
+	return 0;
+}
+
+int h323_soft_hangup(const char *data)
+{
+	PString token(data);
+	PBoolean result;
+	cout << "Soft hangup" << endl;
+	result = endPoint->ClearCall(token);
+	return result;
+}
+
+/* alas, this doesn't work :( */
+void h323_native_bridge(const char *token, const char *them, char *capability)
+{
+	H323Channel *channel;
+	MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+
+	if (!connection) {
+		cout << "ERROR: No connection found, this is bad" << endl;
+		return;
+	}
+
+	cout << "Native Bridge:  them [" << them << "]" << endl;
+
+	channel = connection->FindChannel(connection->sessionId, TRUE);
+	connection->bridging = TRUE;
+	connection->CloseLogicalChannelNumber(channel->GetNumber());
+
+	connection->Unlock();
+	return;
+
+}
+
+int h323_hold_call(const char *token, int is_hold)
+{
+	MyH323Connection *conn = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+	if (!conn) {
+		cout << "ERROR: No connection found, this is bad" << endl;
+		return -1;
+	}
+	conn->MyHoldCall((PBoolean)is_hold);
+	conn->Unlock();
+	return 0;
+}
+
+#undef cout
+#undef endl
+void h323_end_process(void)
+{
+	if (endPoint) {
+		delete endPoint;
+		endPoint = NULL;
+	}
+#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND
+	close(_timerChangePipe[0]);
+	close(_timerChangePipe[1]);
+#endif
+	if (logstream) {
+		PTrace::SetStream(NULL);
+		delete logstream;
+		logstream = NULL;
+	}
+}
+
+} /* extern "C" */
+
diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h
new file mode 100644
index 0000000..b9e793c
--- /dev/null
+++ b/channels/h323/ast_h323.h
@@ -0,0 +1,187 @@
+/*
+ * ast_h323.h
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ *			By Jeremy McNamara
+ *                      For The NuFone Network 
+ * 
+ * This code has been derived from code created by
+ *              Michael Manousos and Mark Spencer
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * chan_h323 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Version Info: $Id$
+ */
+
+#ifndef AST_H323_H
+#define AST_H323_H
+
+#include "ast_ptlib.h"
+
+#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
+
+class MyH323EndPoint : public H323EndPoint
+{
+	PCLASSINFO(MyH323EndPoint, H323EndPoint);
+
+public:
+	MyH323EndPoint();
+	int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts);
+	PBoolean ClearCall(const PString &, H323Connection::CallEndReason reason);
+	PBoolean ClearCall(const PString &);
+
+	void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
+	void OnConnectionEstablished(H323Connection &, const PString &);
+	void OnConnectionCleared(H323Connection &, const PString &);
+	virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *);
+	void SendUserTone(const PString &, char);
+	PBoolean OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &);
+	PBoolean ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &);
+	void SetEndpointTypeInfo( H225_EndpointType & info ) const;
+	void SetGateway(void);
+	PStringArray SupportedPrefixes;
+};
+
+class MyH323Connection : public H323Connection
+{
+	PCLASSINFO(MyH323Connection, H323Connection);
+
+public:
+	MyH323Connection(MyH323EndPoint &, unsigned, unsigned);
+	~MyH323Connection();
+	H323Channel * CreateRealTimeLogicalChannel(const H323Capability &,
+			H323Channel::Directions,
+			unsigned,
+			const H245_H2250LogicalChannelParameters *,
+			RTP_QOS *);
+	H323Connection::AnswerCallResponse OnAnswerCall(const PString &,
+			const H323SignalPDU &,
+			H323SignalPDU &);
+	void OnReceivedReleaseComplete(const H323SignalPDU &);
+	PBoolean OnAlerting(const H323SignalPDU &, const PString &);
+	PBoolean OnSendReleaseComplete(H323SignalPDU &);
+	PBoolean OnReceivedSignalSetup(const H323SignalPDU &);
+	PBoolean OnReceivedFacility(const H323SignalPDU &);
+	PBoolean OnSendSignalSetup(H323SignalPDU &);
+	PBoolean OnStartLogicalChannel(H323Channel &);
+	PBoolean OnClosingLogicalChannel(H323Channel &);
+	virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
+	virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
+	virtual void OnUserInputString(const PString &value);
+	PBoolean OnReceivedProgress(const H323SignalPDU &);
+	PBoolean MySendProgress();
+	void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
+	void OnSetLocalCapabilities();
+	void SetCapabilities(int, int, void *, int);
+	PBoolean OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
+			H245_TerminalCapabilitySetReject &);
+	void SetCause(int _cause) { cause = _cause; };
+	virtual PBoolean StartControlChannel(const H225_TransportAddress & h245Address);
+	void SetCallOptions(void *opts, PBoolean isIncoming);
+	void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming);
+	virtual H323Connection::CallEndReason SendSignalSetup(const PString&, const H323TransportAddress&);
+#ifdef TUNNELLING
+	virtual PBoolean HandleSignalPDU(H323SignalPDU &pdu);
+	PBoolean EmbedTunneledInfo(H323SignalPDU &pdu);
+#endif
+#ifdef H323_H450
+	virtual void OnReceivedLocalCallHold(int linkedId);
+	virtual void OnReceivedLocalCallRetrieve(int linkedId);
+#endif
+	void MyHoldCall(BOOL localHold);
+
+	PString sourceAliases;
+	PString destAliases;
+	PString sourceE164;
+	PString destE164;
+	int cid_presentation;
+	int cid_ton;
+	PString rdnis;
+	int redirect_reason;
+	int transfer_capability;
+
+	WORD sessionId;
+	PBoolean bridging;
+#ifdef TUNNELLING
+	int remoteTunnelOptions;
+	int tunnelOptions;
+#endif
+
+	unsigned holdHandling;
+	unsigned progressSetup;
+	unsigned progressAlert;
+	int cause;
+
+	RTP_DataFrame::PayloadTypes dtmfCodec[2];
+	int dtmfMode;
+};
+
+class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
+{
+	PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
+
+public:
+	MyH323_ExternalRTPChannel(
+			MyH323Connection & connection,
+			const H323Capability & capability,
+			Directions direction,
+			unsigned sessionID);
+
+	~MyH323_ExternalRTPChannel();
+
+	/* Overrides */
+	PBoolean Start(void);
+	PBoolean OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
+
+protected:
+	BYTE payloadCode;
+
+	PIPSocket::Address localIpAddr;
+	PIPSocket::Address remoteIpAddr;
+	/* Additional functions in order to have chan_h323 compile with H323Plus */
+#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4)
+	BOOL OnReceivedAltPDU(const H245_ArrayOf_GenericInformation & alternate );
+	BOOL OnSendingAltPDU(H245_ArrayOf_GenericInformation & alternate) const;
+	void OnSendOpenAckAlt(H245_ArrayOf_GenericInformation & alternate) const;
+	BOOL OnReceivedAckAltPDU(const H245_ArrayOf_GenericInformation & alternate);
+#endif
+	WORD localPort;
+	WORD remotePort;
+};
+
+#ifdef H323_H450
+
+#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4)
+#include <h450/h450pdu.h>
+#else
+#include <h450pdu.h>
+#endif
+
+class MyH4504Handler : public H4504Handler
+{
+	PCLASSINFO(MyH4504Handler, H4504Handler);
+
+public:
+	MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp);
+	virtual void OnReceivedLocalCallHold(int linkedId);
+	virtual void OnReceivedLocalCallRetrieve(int linkedId);
+
+private:
+	MyH323Connection *conn;
+};
+#endif
+
+#endif /* !defined AST_H323_H */
diff --git a/rest-api-templates/param_cleanup.mustache b/channels/h323/ast_ptlib.h
similarity index 52%
rename from rest-api-templates/param_cleanup.mustache
rename to channels/h323/ast_ptlib.h
index 46edb41..4b8ebf3 100644
--- a/rest-api-templates/param_cleanup.mustache
+++ b/channels/h323/ast_ptlib.h
@@ -1,9 +1,7 @@
-{{!
+/*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
+ * Copyright (C) 2009, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -14,13 +12,23 @@
  * This program is free software, distributed under the terms of
  * the GNU General Public License Version 2. See the LICENSE file
  * at the top of the source tree.
-}}
-{{!
- * Snippet for cleaning up an _args struct.
-}}
-{{#query_parameters}}
-{{#allow_multiple}}
-	ast_free(args.{{c_name}}_parse);
-	ast_free(args.{{c_name}});
-{{/allow_multiple}}
-{{/query_parameters}}
+ */
+
+/* PTLib is Copyright (c) 2003 Equivalence Pty. Ltd. */
+
+/*! 
+ * \file
+ * \brief PTLib compatibility with previous versions of OPAL/PTLib/PWLib
+ */
+
+#ifndef AST_PTLIB_H
+#define AST_PTLIB_H
+
+#include <ptbuildopts.h>
+#if !defined(P_USE_STANDARD_CXX_BOOL) && !defined(P_USE_INTEGER_BOOL)
+typedef BOOL PBoolean;
+#define PTrue TRUE
+#define PFalse FALSE
+#endif
+
+#endif /* !defined AST_PTLIB_H */
diff --git a/channels/h323/caps_h323.cxx b/channels/h323/caps_h323.cxx
new file mode 100644
index 0000000..3f7230f
--- /dev/null
+++ b/channels/h323/caps_h323.cxx
@@ -0,0 +1,383 @@
+#include <ptlib.h>
+#include <h323.h>
+#include <h245.h>
+#include "ast_h323.h"
+#include "caps_h323.h"
+
+#define DEFINE_G711_CAPABILITY(cls, code, capName) \
+class cls : public AST_G711Capability { \
+public: \
+	cls() : AST_G711Capability(240, code) { } \
+}; \
+H323_REGISTER_CAPABILITY(cls, capName) \
+
+DEFINE_G711_CAPABILITY(AST_G711ALaw64Capability, H323_G711Capability::ALaw, OPAL_G711_ALAW_64K);
+DEFINE_G711_CAPABILITY(AST_G711uLaw64Capability, H323_G711Capability::muLaw, OPAL_G711_ULAW_64K);
+H323_REGISTER_CAPABILITY(AST_G7231Capability, OPAL_G7231);
+H323_REGISTER_CAPABILITY(AST_G729Capability,  OPAL_G729);
+H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A);
+H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610);
+H323_REGISTER_CAPABILITY(AST_CiscoG726Capability, CISCO_G726r32);
+H323_REGISTER_CAPABILITY(AST_CiscoDtmfCapability, CISCO_DTMF_RELAY);
+
+OPAL_MEDIA_FORMAT_DECLARE(OpalG711ALaw64kFormat,
+	OPAL_G711_ALAW_64K,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::PCMA,
+	TRUE,	// Needs jitter
+	64000,	// bits/sec
+	8,		// bytes/frame
+	8,		// 1 millisecond/frame
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG711uLaw64kFormat,
+	OPAL_G711_ULAW_64K,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::PCMU,
+	TRUE,	// Needs jitter
+	64000,	// bits/sec
+	8,		// bytes/frame
+	8,		// 1 millisecond/frame
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG729Format,
+	OPAL_G729,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::G729,
+	TRUE,	// Needs jitter
+	8000,	// bits/sec
+	10,		// bytes
+	80,		// 10 milliseconds
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG729AFormat,
+	OPAL_G729 "A",
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::G729,
+	TRUE,	// Needs jitter
+	8000,	// bits/sec
+	10,		// bytes
+	80,		// 10 milliseconds
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG7231_6k3Format,
+	OPAL_G7231_6k3,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::G7231,
+	TRUE,	// Needs jitter
+	6400,	// bits/sec
+	24,		// bytes
+	240,	// 30 milliseconds
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG7231A_6k3Format,
+	OPAL_G7231A_6k3,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::G7231,
+	TRUE,	// Needs jitter
+	6400,	// bits/sec
+	24,		// bytes
+	240,	// 30 milliseconds
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalGSM0610Format,
+	OPAL_GSM0610,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::GSM,
+	TRUE,	// Needs jitter
+	13200,	// bits/sec
+	33,		// bytes
+	160,	// 20 milliseconds
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoG726Format,
+	CISCO_G726r32,
+	OpalMediaFormat::DefaultAudioSessionID,
+	RTP_DataFrame::G726,
+	TRUE,	// Needs jitter
+	32000,	// bits/sec
+	4,		// bytes
+	8,		// 1 millisecond
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+#if 0
+OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoDTMFRelayFormat,
+	CISCO_DTMF_RELAY,
+	OpalMediaFormat::DefaultAudioSessionID,
+	(RTP_DataFrame::PayloadTypes)121, // Choose this for Cisco IOS compatibility
+	TRUE,	// Needs jitter
+	100,	// bits/sec
+	4,		// bytes/frame
+	8*150,	// 150 millisecond
+	OpalMediaFormat::AudioTimeUnits,
+	0);
+#endif
+
+/*
+ * Capability: G.711
+ */
+AST_G711Capability::AST_G711Capability(int rx_frames, H323_G711Capability::Mode m, H323_G711Capability::Speed s)
+	: H323AudioCapability(rx_frames, 30) // 240ms max, 30ms desired
+{
+	mode = m;
+	speed = s;
+}
+
+
+PObject * AST_G711Capability::Clone() const
+{
+	return new AST_G711Capability(*this);
+}
+
+
+unsigned AST_G711Capability::GetSubType() const
+{
+	static const unsigned G711SubType[2][2] = {
+		{ H245_AudioCapability::e_g711Alaw64k, H245_AudioCapability::e_g711Alaw56k },
+		{ H245_AudioCapability::e_g711Ulaw64k, H245_AudioCapability::e_g711Ulaw56k }
+	};
+	return G711SubType[mode][speed];
+}
+
+
+PString AST_G711Capability::GetFormatName() const
+{
+	static const char * const G711Name[2][2] = {
+		{ OPAL_G711_ALAW_64K, OPAL_G711_ALAW_56K },
+		{ OPAL_G711_ULAW_64K, OPAL_G711_ULAW_56K },
+	};
+	return G711Name[mode][speed];
+}
+
+
+H323Codec * AST_G711Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+
+/*
+ * Capability: G.723.1
+ */
+AST_G7231Capability::AST_G7231Capability(int rx_frames, PBoolean annexA_)
+	: H323AudioCapability(rx_frames, 4)
+{
+	annexA = annexA_;
+}
+
+PObject::Comparison AST_G7231Capability::Compare(const PObject & obj) const
+{
+	Comparison result = H323AudioCapability::Compare(obj);
+	if (result != EqualTo) {
+		return result;
+	}
+	PINDEX otherAnnexA = ((const AST_G7231Capability &)obj).annexA;
+	if (annexA < otherAnnexA) {
+		return LessThan;
+	}
+	if (annexA > otherAnnexA) {
+		return GreaterThan;
+	}
+	return EqualTo;
+}
+
+PObject * AST_G7231Capability::Clone() const
+{
+	return new AST_G7231Capability(*this);
+}
+
+PString AST_G7231Capability::GetFormatName() const
+{
+	return (annexA ? OPAL_G7231 "A" : OPAL_G7231);
+}
+
+unsigned AST_G7231Capability::GetSubType() const
+{
+	return H245_AudioCapability::e_g7231;
+}
+
+PBoolean AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap,
+										unsigned packetSize) const
+{
+	cap.SetTag(H245_AudioCapability::e_g7231);
+	H245_AudioCapability_g7231 & g7231 = cap;
+	g7231.m_maxAl_sduAudioFrames = packetSize;
+	g7231.m_silenceSuppression = annexA;
+	return TRUE;
+}
+
+PBoolean AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap,
+										unsigned & packetSize)
+{
+	if (cap.GetTag() != H245_AudioCapability::e_g7231) {
+		return FALSE;
+	}
+	const H245_AudioCapability_g7231 & g7231 = cap;
+	packetSize = g7231.m_maxAl_sduAudioFrames;
+	annexA = g7231.m_silenceSuppression;
+	return TRUE;
+}
+
+H323Codec * AST_G7231Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+/*
+ * Capability: G.729
+ */
+AST_G729Capability::AST_G729Capability(int rx_frames)
+	: H323AudioCapability(rx_frames, 2)
+{
+}
+
+PObject * AST_G729Capability::Clone() const
+{
+	return new AST_G729Capability(*this);
+}
+
+unsigned AST_G729Capability::GetSubType() const
+{
+	return H245_AudioCapability::e_g729;
+}
+
+PString AST_G729Capability::GetFormatName() const
+{
+	return OPAL_G729;
+}
+
+H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+/*
+ * Capability: G.729A
+ */
+AST_G729ACapability::AST_G729ACapability(int rx_frames)
+	: H323AudioCapability(rx_frames, 6)
+{
+}
+
+PObject * AST_G729ACapability::Clone() const
+{
+	return new AST_G729ACapability(*this);
+}
+
+unsigned AST_G729ACapability::GetSubType() const
+{
+	return H245_AudioCapability::e_g729AnnexA;
+}
+
+PString AST_G729ACapability::GetFormatName() const
+{
+	return OPAL_G729A;
+}
+
+H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+/*
+ * Capability: GSM full rate
+ */
+AST_GSM0610Capability::AST_GSM0610Capability(int rx_frames, int comfortNoise_, int scrambled_)
+	: H323AudioCapability(rx_frames, 2)
+{
+	comfortNoise = comfortNoise_;
+	scrambled = scrambled_;
+}
+
+PObject * AST_GSM0610Capability::Clone() const
+{
+	return new AST_GSM0610Capability(*this);
+}
+
+unsigned AST_GSM0610Capability::GetSubType() const
+{
+	return H245_AudioCapability::e_gsmFullRate;
+}
+
+PBoolean AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap,
+										unsigned packetSize) const
+{
+	cap.SetTag(H245_AudioCapability::e_gsmFullRate);
+	H245_GSMAudioCapability & gsm = cap;
+	gsm.m_audioUnitSize = packetSize * 33;
+	gsm.m_comfortNoise = comfortNoise;
+	gsm.m_scrambled = scrambled;
+	return TRUE;
+}
+
+PBoolean AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap,
+										unsigned & packetSize)
+{
+	if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate)
+		return FALSE;
+	const H245_GSMAudioCapability & gsm = cap;
+	packetSize = (gsm.m_audioUnitSize + 32) / 33;
+	comfortNoise = gsm.m_comfortNoise;
+	scrambled = gsm.m_scrambled;
+
+	return TRUE;
+}
+
+PString AST_GSM0610Capability::GetFormatName() const
+{
+	return OPAL_GSM0610;
+}
+
+H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+/*
+ * Capability: G.726 32 Kbps
+ */
+AST_CiscoG726Capability::AST_CiscoG726Capability(int rx_frames)
+	: H323NonStandardAudioCapability(rx_frames, 240,
+		181, 0, 18,
+		(const BYTE *)"G726r32", 0)
+{
+}
+
+PObject *AST_CiscoG726Capability::Clone() const
+{
+	return new AST_CiscoG726Capability(*this);
+}
+
+H323Codec *AST_CiscoG726Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+PString AST_CiscoG726Capability::GetFormatName() const
+{
+	return PString(CISCO_G726r32);
+}
+
+/*
+ * Capability: Cisco RTP DTMF Relay
+ */
+AST_CiscoDtmfCapability::AST_CiscoDtmfCapability()
+	: H323NonStandardDataCapability(0, 181, 0, 18, (const BYTE *)"RtpDtmfRelay", 0)
+{
+	rtpPayloadType = (RTP_DataFrame::PayloadTypes)121;
+}
+
+PObject *AST_CiscoDtmfCapability::Clone() const
+{
+	return new AST_CiscoDtmfCapability(*this);
+}
+
+H323Codec *AST_CiscoDtmfCapability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+PString AST_CiscoDtmfCapability::GetFormatName() const
+{
+	return PString(CISCO_DTMF_RELAY);
+}
diff --git a/channels/h323/caps_h323.h b/channels/h323/caps_h323.h
new file mode 100644
index 0000000..251c6e7
--- /dev/null
+++ b/channels/h323/caps_h323.h
@@ -0,0 +1,172 @@
+#ifndef __AST_H323CAPS_H
+#define __AST_H323CAPS_H
+
+/**This class describes the G.711 codec capability.
+ */
+class AST_G711Capability : public H323AudioCapability
+{
+	PCLASSINFO(AST_G711Capability, H323AudioCapability);
+
+public:
+	AST_G711Capability(int rx_frames = 125, H323_G711Capability::Mode _mode = H323_G711Capability::muLaw, H323_G711Capability::Speed _speed = H323_G711Capability::At64k);
+	virtual PObject *Clone() const;
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+	virtual unsigned GetSubType() const;
+	virtual PString GetFormatName() const;
+
+protected:
+	H323_G711Capability::Mode mode;
+	H323_G711Capability::Speed speed;
+};
+
+/**This class describes the G.723.1 codec capability.
+ */
+class AST_G7231Capability : public H323AudioCapability
+{
+	PCLASSINFO(AST_G7231Capability, H323AudioCapability);
+
+public:
+	AST_G7231Capability(int rx_frames = 7, PBoolean annexA = TRUE);
+	Comparison Compare(const PObject & obj) const;
+	virtual PObject * Clone() const;
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+	virtual unsigned GetSubType() const;
+	virtual PString GetFormatName() const;
+	virtual PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+	virtual PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+	PBoolean annexA;
+};
+
+/**This class describes the (fake) G729 codec capability.
+ */
+class AST_G729Capability : public H323AudioCapability
+{
+	PCLASSINFO(AST_G729Capability, H323AudioCapability);
+
+public:
+	AST_G729Capability(int rx_frames = 24);
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
+
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+};
+
+/* This class describes the VoiceAge G729A codec capability. */
+class AST_G729ACapability : public H323AudioCapability
+{
+	PCLASSINFO(AST_G729ACapability, H323AudioCapability);
+
+public:
+	/* Create a new G.729A capability. */
+	AST_G729ACapability(int rx_frames = 24);
+
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
+
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+};
+
+/* This class describes the GSM-06.10 codec capability. */
+class AST_GSM0610Capability : public H323AudioCapability
+{
+	PCLASSINFO(AST_GSM0610Capability, H323AudioCapability);
+
+public:
+	/* Create a new GSM capability. */
+	AST_GSM0610Capability(int rx_frames = 24, int comfortNoise = 0, int scrambled = 0);
+
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
+
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+
+	PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+	PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+	int comfortNoise;
+	int scrambled;
+};
+
+#define CISCO_G726r32 "G726r32"
+
+class AST_CiscoG726Capability : public H323NonStandardAudioCapability {
+	PCLASSINFO(AST_CiscoG726Capability, H323NonStandardAudioCapability);
+
+public:
+	/* Create a new Cisco G.726 capability */
+	AST_CiscoG726Capability(int rx_frames = 80);
+
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+};
+
+#define CISCO_DTMF_RELAY "UserInput/RtpDtmfRelay"
+
+class AST_CiscoDtmfCapability : public H323NonStandardDataCapability
+{
+	PCLASSINFO(AST_CiscoDtmfCapability, H323NonStandardDataCapability);
+
+public:
+	/* Create a new Cisco RTP DTMF Relay capability */
+	AST_CiscoDtmfCapability();
+
+	/* Create a copy of the object. */	
+	virtual PObject *Clone() const;
+
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+	
+	virtual H323Channel *CreateChannel(H323Connection &,
+										H323Channel::Directions,
+										unsigned,
+										const H245_H2250LogicalChannelParameters *) const
+	{
+		return NULL;
+	}
+};
+
+#endif /* __AST_H323CAPS_H */
diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h
new file mode 100644
index 0000000..ddabb66
--- /dev/null
+++ b/channels/h323/chan_h323.h
@@ -0,0 +1,275 @@
+/*
+ * chan_h323.h
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ *			By Jeremy McNamara
+ * 			For The NuFone Network
+ *
+ * This code has been derived from code created by
+ *		Michael Manousos and Mark Spencer
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * chan_h323 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Version Info: $Id$
+ */
+
+#ifndef CHAN_H323_H
+#define CHAN_H323_H
+
+#include <arpa/inet.h>
+#include "asterisk/format.h"
+
+/*
+ * Enable support for sending/reception of tunnelled Q.SIG messages and
+ * some sort of IEs (especially RedirectingNumber) which Cisco CallManager
+ * isn't like to pass in standard Q.931 message.
+ *
+ */
+#define TUNNELLING
+
+#define H323_TUNNEL_CISCO	(1 << 0)
+#define H323_TUNNEL_QSIG	(1 << 1)
+
+#define H323_HOLD_NOTIFY	(1 << 0)
+#define H323_HOLD_Q931ONLY	(1 << 1)
+#define H323_HOLD_H450		(1 << 2)
+
+typedef int64_t h323_format;
+
+/** call_option struct holds various bits
+ *         of information for each call */
+typedef struct call_options {
+	char			cid_num[80];
+	char			cid_name[80];
+	char			cid_rdnis[80];
+	int				redirect_reason;
+	int				presentation;
+	int				type_of_number;
+	int				transfer_capability;
+	int				fastStart;
+	int				h245Tunneling;
+	int				silenceSuppression;
+	int				progress_setup;
+	int				progress_alert;
+	int				progress_audio;
+	int				dtmfcodec[2];
+	int				dtmfmode;
+	h323_format     capability;
+	int				bridge;
+	int				nat;
+	int				tunnelOptions;
+	int				holdHandling;
+	int				autoframing; /*!< turn on to override local settings with remote framing length */
+	struct ast_codec_pref	prefs;
+} call_options_t;
+
+/* structure to hold the valid asterisk users */
+struct oh323_user {
+	ASTOBJ_COMPONENTS(struct oh323_user);
+//	char name[80];
+	char context[80];
+	char secret[80];
+	char accountcode[AST_MAX_ACCOUNT_CODE];
+	int amaflags;
+	int host;
+	struct sockaddr_in addr;
+	struct ast_ha *ha;
+	call_options_t options;
+};
+
+/* structure to hold the valid asterisk peers
+   All peers are registered to a GK if there is one */
+struct oh323_peer {
+	ASTOBJ_COMPONENTS(struct oh323_peer);
+	char mailbox[80];
+	int delme;
+	struct sockaddr_in addr;
+	struct ast_ha *ha;
+	call_options_t options;
+};
+
+/* structure to hold the H.323 aliases which get registered to
+   the H.323 endpoint and gatekeeper */
+struct oh323_alias {
+	ASTOBJ_COMPONENTS(struct oh323_alias);
+	char e164[20];				/* tells a GK to route this E.164 to this alias */
+	char prefix[500];			/* tells a GK this alias supports these prefixes */
+	char secret[20];			/* the H.235 password to send to the GK for authentication */
+	char context[80];
+};
+
+/** call_details struct call detail records
+	to asterisk for processing and used for matching up
+	asterisk channels to acutal h.323 connections */
+typedef struct call_details {
+	unsigned int call_reference;
+	char *call_token;
+	char *call_source_aliases;
+	char *call_dest_alias;
+	char *call_source_name;
+	char *call_source_e164;
+	char *call_dest_e164;
+	char *redirect_number;
+	int redirect_reason;
+	int presentation;
+	int type_of_number;
+	int transfer_capability;
+	char *sourceIp;
+} call_details_t;
+
+typedef struct rtp_info {
+	char addr[32];
+	unsigned int port;
+} rtp_info_t;
+
+/* This is a callback prototype function, called pass
+   DTMF down the RTP. */
+typedef int (*receive_digit_cb)(unsigned, char, const char *, int);
+extern receive_digit_cb on_receive_digit;
+
+/* This is a callback prototype function, called to collect
+   the external RTP port from Asterisk. */
+typedef rtp_info_t *(*on_rtp_cb)(unsigned, const char *);
+extern on_rtp_cb on_external_rtp_create;
+
+/* This is a callback prototype function, called to send
+   the remote IP and RTP port from H.323 to Asterisk */
+typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *, int);
+extern start_rtp_cb on_start_rtp_channel;
+
+/* This is a callback that happens when call progress is
+ * made, and handles inband progress */
+typedef int (*progress_cb)(unsigned, const char *, int);
+extern progress_cb on_progress;
+
+/* This is a callback prototype function, called upon
+   an incoming call happens. */
+typedef call_options_t *(*setup_incoming_cb)(call_details_t *);
+extern setup_incoming_cb on_incoming_call;
+
+/* This is a callback prototype function, called upon
+   an outbound call. */
+typedef int (*setup_outbound_cb)(call_details_t *);
+extern setup_outbound_cb on_outgoing_call;
+
+/* This is a callback prototype function, called when
+   OnAlerting is invoked */
+typedef void (*chan_ringing_cb)(unsigned, const char *);
+extern chan_ringing_cb on_chan_ringing;
+
+/* This is a callback protoype function, called when
+   OnConnectionEstablished is inovked */
+typedef void (*con_established_cb)(unsigned, const char *);
+extern con_established_cb on_connection_established;
+
+/* This is a callback prototype function, called when
+   OnConnectionCleared callback is invoked */
+typedef void (*clear_con_cb)(unsigned, const char *);
+extern clear_con_cb on_connection_cleared;
+
+/* This is a callback prototype function, called when
+   an H.323 call is answered */
+typedef int (*answer_call_cb)(unsigned, const char *);
+extern answer_call_cb on_answer_call;
+
+/* This is a callback prototype function, called when
+   we know which RTP payload type RFC2833 will be
+   transmitted */
+typedef void (*rfc2833_cb)(unsigned, const char *, int, int);
+extern rfc2833_cb on_set_rfc2833_payload;
+
+typedef void (*hangup_cb)(unsigned, const char *, int);
+extern hangup_cb on_hangup;
+
+typedef void (*setcapabilities_cb)(unsigned, const char *);
+extern setcapabilities_cb on_setcapabilities;
+
+typedef void (*setpeercapabilities_cb)(unsigned, const char *, int, struct ast_codec_pref *);
+extern setpeercapabilities_cb on_setpeercapabilities;
+
+typedef void (*onhold_cb)(unsigned, const char *, int);
+extern onhold_cb on_hold;
+
+/* debug flag */
+extern int h323debug;
+
+#define H323_DTMF_RFC2833	(1 << 0)
+#define H323_DTMF_CISCO		(1 << 1)
+#define H323_DTMF_SIGNAL	(1 << 2)
+#define H323_DTMF_INBAND	(1 << 3)
+
+#define H323_DTMF_RFC2833_PT	101
+#define H323_DTMF_CISCO_PT		121
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	void h323_gk_urq(void);
+	void h323_end_point_create(void);
+	void h323_end_process(void);
+	int  h323_end_point_exist(void);
+
+	void h323_debug(int, unsigned);
+
+	/* callback function handler*/
+	void h323_callback_register(setup_incoming_cb,
+					setup_outbound_cb,
+					on_rtp_cb,
+					start_rtp_cb,
+					clear_con_cb,
+					chan_ringing_cb,
+					con_established_cb,
+					receive_digit_cb,
+					answer_call_cb,
+					progress_cb,
+					rfc2833_cb,
+					hangup_cb,
+					setcapabilities_cb,
+					setpeercapabilities_cb,
+					onhold_cb);
+	int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int);
+	int h323_set_alias(struct oh323_alias *);
+	int h323_set_gk(int, char *, char *);
+	void h323_set_id(char *);
+	void h323_show_tokens(void);
+	void h323_show_version(void);
+
+	/* H323 listener related funcions */
+	int h323_start_listener(int, struct sockaddr_in);
+
+	void h323_native_bridge(const char *, const char *, char *);
+
+	/* Send a DTMF tone to remote endpoint */
+	void h323_send_tone(const char *call_token, char tone);
+
+	/* H323 create and destroy sessions */
+	int h323_make_call(char *dest, call_details_t *cd, call_options_t *);
+	int h323_clear_call(const char *, int cause);
+
+	/* H.323 alerting and progress */
+	int h323_send_alerting(const char *token);
+	int h323_send_progress(const char *token);
+	int h323_answering_call(const char *token, int);
+	int h323_soft_hangup(const char *data);
+	int h323_show_codec(int fd, int argc, char *argv[]);
+	int h323_hold_call(const char *token, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/channels/h323/cisco-h225.asn b/channels/h323/cisco-h225.asn
new file mode 100644
index 0000000..1372e67
--- /dev/null
+++ b/channels/h323/cisco-h225.asn
@@ -0,0 +1,74 @@
+CISCO-H225-MESSAGES DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+H323_UU_NonStdInfo ::= SEQUENCE
+{
+	version INTEGER OPTIONAL,
+	protoParam ProtoParam OPTIONAL,
+	commonParam CommonParam OPTIONAL,
+	...,
+	dummy1 OCTET STRING OPTIONAL,
+	progIndParam ProgIndParam OPTIONAL,
+	callMgrParam CallMgrParam OPTIONAL,
+	callSignallingParam CallSignallingParam OPTIONAL,
+	dummy2 OCTET STRING OPTIONAL,
+	callPreserveParam CallPreserveParam OPTIONAL
+}
+
+CommonParam ::= SEQUENCE
+{
+	redirectIEinfo RedirectIEinfo,
+	...
+}
+
+RedirectIEinfo ::= SEQUENCE
+{
+	redirectIE OCTET STRING,
+	...
+}
+
+ProgIndParam ::= SEQUENCE
+{
+	progIndIEinfo ProgIndIEinfo,
+	...
+}
+
+ProgIndIEinfo ::= SEQUENCE
+{
+	progIndIE OCTET STRING,
+	...
+}
+
+ProtoParam ::= SEQUENCE
+{
+	qsigNonStdInfo QsigNonStdInfo,
+	...
+}
+
+QsigNonStdInfo ::= SEQUENCE
+{
+	iei	INTEGER,
+	rawMesg OCTET STRING,
+	...
+}
+
+CallMgrParam ::= SEQUENCE
+{
+	interclusterVersion INTEGER,
+	enterpriseID OCTET STRING,
+	...
+}
+
+CallPreserveParam ::= SEQUENCE
+{
+	callPreserveIE BOOLEAN,
+	...
+}
+
+CallSignallingParam ::= SEQUENCE
+{
+	connectedNumber OCTET STRING (1..127) OPTIONAL,
+	...
+}
+
+END
diff --git a/channels/h323/cisco-h225.cxx b/channels/h323/cisco-h225.cxx
new file mode 100644
index 0000000..dac96a4
--- /dev/null
+++ b/channels/h323/cisco-h225.cxx
@@ -0,0 +1,853 @@
+//
+// cisco-h225.cxx
+//
+// Code automatically generated by asnparse.
+//
+
+#ifdef P_USE_PRAGMA
+#pragma implementation "cisco-h225.h"
+#endif
+
+#include <ptlib.h>
+#include "cisco-h225.h"
+
+#define new PNEW
+
+
+#if ! H323_DISABLE_CISCO_H225
+
+//
+// RedirectIEinfo
+//
+
+CISCO_H225_RedirectIEinfo::CISCO_H225_RedirectIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_RedirectIEinfo::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+13) << "redirectIE = " << setprecision(indent) << m_redirectIE << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_RedirectIEinfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_RedirectIEinfo), PInvalidCast);
+#endif
+  const CISCO_H225_RedirectIEinfo & other = (const CISCO_H225_RedirectIEinfo &)obj;
+
+  Comparison result;
+
+  if ((result = m_redirectIE.Compare(other.m_redirectIE)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_RedirectIEinfo::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_redirectIE.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_redirectIE.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_RedirectIEinfo::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_redirectIE.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_RedirectIEinfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_RedirectIEinfo::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_RedirectIEinfo(*this);
+}
+
+
+//
+// ProgIndIEinfo
+//
+
+CISCO_H225_ProgIndIEinfo::CISCO_H225_ProgIndIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProgIndIEinfo::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+12) << "progIndIE = " << setprecision(indent) << m_progIndIE << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProgIndIEinfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndIEinfo), PInvalidCast);
+#endif
+  const CISCO_H225_ProgIndIEinfo & other = (const CISCO_H225_ProgIndIEinfo &)obj;
+
+  Comparison result;
+
+  if ((result = m_progIndIE.Compare(other.m_progIndIE)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProgIndIEinfo::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_progIndIE.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_progIndIE.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProgIndIEinfo::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_progIndIE.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProgIndIEinfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_ProgIndIEinfo::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_ProgIndIEinfo(*this);
+}
+
+
+//
+// QsigNonStdInfo
+//
+
+CISCO_H225_QsigNonStdInfo::CISCO_H225_QsigNonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_QsigNonStdInfo::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+6) << "iei = " << setprecision(indent) << m_iei << '\n';
+  strm << setw(indent+10) << "rawMesg = " << setprecision(indent) << m_rawMesg << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_QsigNonStdInfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_QsigNonStdInfo), PInvalidCast);
+#endif
+  const CISCO_H225_QsigNonStdInfo & other = (const CISCO_H225_QsigNonStdInfo &)obj;
+
+  Comparison result;
+
+  if ((result = m_iei.Compare(other.m_iei)) != EqualTo)
+    return result;
+  if ((result = m_rawMesg.Compare(other.m_rawMesg)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_QsigNonStdInfo::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_iei.GetObjectLength();
+  length += m_rawMesg.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_iei.Decode(strm))
+    return FALSE;
+  if (!m_rawMesg.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_QsigNonStdInfo::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_iei.Encode(strm);
+  m_rawMesg.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_QsigNonStdInfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_QsigNonStdInfo::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_QsigNonStdInfo(*this);
+}
+
+
+//
+// CallMgrParam
+//
+
+CISCO_H225_CallMgrParam::CISCO_H225_CallMgrParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallMgrParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+22) << "interclusterVersion = " << setprecision(indent) << m_interclusterVersion << '\n';
+  strm << setw(indent+15) << "enterpriseID = " << setprecision(indent) << m_enterpriseID << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallMgrParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_CallMgrParam), PInvalidCast);
+#endif
+  const CISCO_H225_CallMgrParam & other = (const CISCO_H225_CallMgrParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_interclusterVersion.Compare(other.m_interclusterVersion)) != EqualTo)
+    return result;
+  if ((result = m_enterpriseID.Compare(other.m_enterpriseID)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallMgrParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_interclusterVersion.GetObjectLength();
+  length += m_enterpriseID.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_interclusterVersion.Decode(strm))
+    return FALSE;
+  if (!m_enterpriseID.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallMgrParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_interclusterVersion.Encode(strm);
+  m_enterpriseID.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallMgrParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_CallMgrParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_CallMgrParam(*this);
+}
+
+
+//
+// CallPreserveParam
+//
+
+CISCO_H225_CallPreserveParam::CISCO_H225_CallPreserveParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallPreserveParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+17) << "callPreserveIE = " << setprecision(indent) << m_callPreserveIE << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallPreserveParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_CallPreserveParam), PInvalidCast);
+#endif
+  const CISCO_H225_CallPreserveParam & other = (const CISCO_H225_CallPreserveParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_callPreserveIE.Compare(other.m_callPreserveIE)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallPreserveParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_callPreserveIE.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_callPreserveIE.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallPreserveParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_callPreserveIE.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallPreserveParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_CallPreserveParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_CallPreserveParam(*this);
+}
+
+
+//
+// CallSignallingParam
+//
+
+CISCO_H225_CallSignallingParam::CISCO_H225_CallSignallingParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 1, TRUE, 0)
+{
+  m_connectedNumber.SetConstraints(PASN_Object::FixedConstraint, 1, 127);
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallSignallingParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  if (HasOptionalField(e_connectedNumber))
+    strm << setw(indent+18) << "connectedNumber = " << setprecision(indent) << m_connectedNumber << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallSignallingParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_CallSignallingParam), PInvalidCast);
+#endif
+  const CISCO_H225_CallSignallingParam & other = (const CISCO_H225_CallSignallingParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_connectedNumber.Compare(other.m_connectedNumber)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallSignallingParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  if (HasOptionalField(e_connectedNumber))
+    length += m_connectedNumber.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (HasOptionalField(e_connectedNumber) && !m_connectedNumber.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallSignallingParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  if (HasOptionalField(e_connectedNumber))
+    m_connectedNumber.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallSignallingParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_CallSignallingParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_CallSignallingParam(*this);
+}
+
+
+//
+// CommonParam
+//
+
+CISCO_H225_CommonParam::CISCO_H225_CommonParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CommonParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+17) << "redirectIEinfo = " << setprecision(indent) << m_redirectIEinfo << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CommonParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_CommonParam), PInvalidCast);
+#endif
+  const CISCO_H225_CommonParam & other = (const CISCO_H225_CommonParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_redirectIEinfo.Compare(other.m_redirectIEinfo)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CommonParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_redirectIEinfo.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_CommonParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_redirectIEinfo.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CommonParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_redirectIEinfo.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CommonParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_CommonParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_CommonParam(*this);
+}
+
+
+//
+// ProgIndParam
+//
+
+CISCO_H225_ProgIndParam::CISCO_H225_ProgIndParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProgIndParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+16) << "progIndIEinfo = " << setprecision(indent) << m_progIndIEinfo << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProgIndParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndParam), PInvalidCast);
+#endif
+  const CISCO_H225_ProgIndParam & other = (const CISCO_H225_ProgIndParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_progIndIEinfo.Compare(other.m_progIndIEinfo)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProgIndParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_progIndIEinfo.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_progIndIEinfo.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProgIndParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_progIndIEinfo.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProgIndParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_ProgIndParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_ProgIndParam(*this);
+}
+
+
+//
+// ProtoParam
+//
+
+CISCO_H225_ProtoParam::CISCO_H225_ProtoParam(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProtoParam::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  strm << setw(indent+17) << "qsigNonStdInfo = " << setprecision(indent) << m_qsigNonStdInfo << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProtoParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_ProtoParam), PInvalidCast);
+#endif
+  const CISCO_H225_ProtoParam & other = (const CISCO_H225_ProtoParam &)obj;
+
+  Comparison result;
+
+  if ((result = m_qsigNonStdInfo.Compare(other.m_qsigNonStdInfo)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProtoParam::GetDataLength() const
+{
+  PINDEX length = 0;
+  length += m_qsigNonStdInfo.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_ProtoParam::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (!m_qsigNonStdInfo.Decode(strm))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProtoParam::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  m_qsigNonStdInfo.Encode(strm);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProtoParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_ProtoParam::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_ProtoParam(*this);
+}
+
+
+//
+// H323_UU_NonStdInfo
+//
+
+CISCO_H225_H323_UU_NonStdInfo::CISCO_H225_H323_UU_NonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
+  : PASN_Sequence(tag, tagClass, 3, TRUE, 6)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_H323_UU_NonStdInfo::PrintOn(ostream & strm) const
+{
+  int indent = strm.precision() + 2;
+  strm << "{\n";
+  if (HasOptionalField(e_version))
+    strm << setw(indent+10) << "version = " << setprecision(indent) << m_version << '\n';
+  if (HasOptionalField(e_protoParam))
+    strm << setw(indent+13) << "protoParam = " << setprecision(indent) << m_protoParam << '\n';
+  if (HasOptionalField(e_commonParam))
+    strm << setw(indent+14) << "commonParam = " << setprecision(indent) << m_commonParam << '\n';
+  if (HasOptionalField(e_dummy1))
+    strm << setw(indent+9) << "dummy1 = " << setprecision(indent) << m_dummy1 << '\n';
+  if (HasOptionalField(e_progIndParam))
+    strm << setw(indent+15) << "progIndParam = " << setprecision(indent) << m_progIndParam << '\n';
+  if (HasOptionalField(e_callMgrParam))
+    strm << setw(indent+15) << "callMgrParam = " << setprecision(indent) << m_callMgrParam << '\n';
+  if (HasOptionalField(e_callSignallingParam))
+    strm << setw(indent+22) << "callSignallingParam = " << setprecision(indent) << m_callSignallingParam << '\n';
+  if (HasOptionalField(e_dummy2))
+    strm << setw(indent+9) << "dummy2 = " << setprecision(indent) << m_dummy2 << '\n';
+  if (HasOptionalField(e_callPreserveParam))
+    strm << setw(indent+20) << "callPreserveParam = " << setprecision(indent) << m_callPreserveParam << '\n';
+  strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_H323_UU_NonStdInfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(PIsDescendant(&obj, CISCO_H225_H323_UU_NonStdInfo), PInvalidCast);
+#endif
+  const CISCO_H225_H323_UU_NonStdInfo & other = (const CISCO_H225_H323_UU_NonStdInfo &)obj;
+
+  Comparison result;
+
+  if ((result = m_version.Compare(other.m_version)) != EqualTo)
+    return result;
+  if ((result = m_protoParam.Compare(other.m_protoParam)) != EqualTo)
+    return result;
+  if ((result = m_commonParam.Compare(other.m_commonParam)) != EqualTo)
+    return result;
+
+  return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_H323_UU_NonStdInfo::GetDataLength() const
+{
+  PINDEX length = 0;
+  if (HasOptionalField(e_version))
+    length += m_version.GetObjectLength();
+  if (HasOptionalField(e_protoParam))
+    length += m_protoParam.GetObjectLength();
+  if (HasOptionalField(e_commonParam))
+    length += m_commonParam.GetObjectLength();
+  return length;
+}
+
+
+PBoolean CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm)
+{
+  if (!PreambleDecode(strm))
+    return FALSE;
+
+  if (HasOptionalField(e_version) && !m_version.Decode(strm))
+    return FALSE;
+  if (HasOptionalField(e_protoParam) && !m_protoParam.Decode(strm))
+    return FALSE;
+  if (HasOptionalField(e_commonParam) && !m_commonParam.Decode(strm))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_dummy1, m_dummy1))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_progIndParam, m_progIndParam))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_callMgrParam, m_callMgrParam))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_callSignallingParam, m_callSignallingParam))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_dummy2, m_dummy2))
+    return FALSE;
+  if (!KnownExtensionDecode(strm, e_callPreserveParam, m_callPreserveParam))
+    return FALSE;
+
+  return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_H323_UU_NonStdInfo::Encode(PASN_Stream & strm) const
+{
+  PreambleEncode(strm);
+
+  if (HasOptionalField(e_version))
+    m_version.Encode(strm);
+  if (HasOptionalField(e_protoParam))
+    m_protoParam.Encode(strm);
+  if (HasOptionalField(e_commonParam))
+    m_commonParam.Encode(strm);
+  KnownExtensionEncode(strm, e_dummy1, m_dummy1);
+  KnownExtensionEncode(strm, e_progIndParam, m_progIndParam);
+  KnownExtensionEncode(strm, e_callMgrParam, m_callMgrParam);
+  KnownExtensionEncode(strm, e_callSignallingParam, m_callSignallingParam);
+  KnownExtensionEncode(strm, e_dummy2, m_dummy2);
+  KnownExtensionEncode(strm, e_callPreserveParam, m_callPreserveParam);
+
+  UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_H323_UU_NonStdInfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+  PAssert(IsClass(CISCO_H225_H323_UU_NonStdInfo::Class()), PInvalidCast);
+#endif
+  return new CISCO_H225_H323_UU_NonStdInfo(*this);
+}
+
+
+#endif // if ! H323_DISABLE_CISCO_H225
+
+
+// End of cisco-h225.cxx
diff --git a/channels/h323/cisco-h225.h b/channels/h323/cisco-h225.h
new file mode 100644
index 0000000..55ed47e
--- /dev/null
+++ b/channels/h323/cisco-h225.h
@@ -0,0 +1,300 @@
+//
+// cisco-h225.h
+//
+// Code automatically generated by asnparse.
+//
+
+#if ! H323_DISABLE_CISCO_H225
+
+#ifndef __CISCO_H225_H
+#define __CISCO_H225_H
+
+#ifdef P_USE_PRAGMA
+#pragma interface
+#endif
+
+#include <ptclib/asner.h>
+#include "ast_ptlib.h"
+
+//
+// RedirectIEinfo
+//
+
+class CISCO_H225_RedirectIEinfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_RedirectIEinfo, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_RedirectIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    PASN_OctetString m_redirectIE;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// ProgIndIEinfo
+//
+
+class CISCO_H225_ProgIndIEinfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_ProgIndIEinfo, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_ProgIndIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    PASN_OctetString m_progIndIE;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// QsigNonStdInfo
+//
+
+class CISCO_H225_QsigNonStdInfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_QsigNonStdInfo, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_QsigNonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    PASN_Integer m_iei;
+    PASN_OctetString m_rawMesg;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// CallMgrParam
+//
+
+class CISCO_H225_CallMgrParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_CallMgrParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_CallMgrParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    PASN_Integer m_interclusterVersion;
+    PASN_OctetString m_enterpriseID;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// CallPreserveParam
+//
+
+class CISCO_H225_CallPreserveParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_CallPreserveParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_CallPreserveParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    PASN_Boolean m_callPreserveIE;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// CallSignallingParam
+//
+
+class CISCO_H225_CallSignallingParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_CallSignallingParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_CallSignallingParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    enum OptionalFields {
+      e_connectedNumber
+    };
+
+    PASN_OctetString m_connectedNumber;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// CommonParam
+//
+
+class CISCO_H225_CommonParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_CommonParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_CommonParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    CISCO_H225_RedirectIEinfo m_redirectIEinfo;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// ProgIndParam
+//
+
+class CISCO_H225_ProgIndParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_ProgIndParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_ProgIndParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    CISCO_H225_ProgIndIEinfo m_progIndIEinfo;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// ProtoParam
+//
+
+class CISCO_H225_ProtoParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_ProtoParam, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_ProtoParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    CISCO_H225_QsigNonStdInfo m_qsigNonStdInfo;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+//
+// H323_UU_NonStdInfo
+//
+
+class CISCO_H225_H323_UU_NonStdInfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+    PCLASSINFO(CISCO_H225_H323_UU_NonStdInfo, PASN_Sequence);
+#endif
+  public:
+    CISCO_H225_H323_UU_NonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+    enum OptionalFields {
+      e_version,
+      e_protoParam,
+      e_commonParam,
+      e_dummy1,
+      e_progIndParam,
+      e_callMgrParam,
+      e_callSignallingParam,
+      e_dummy2,
+      e_callPreserveParam
+    };
+
+    PASN_Integer m_version;
+    CISCO_H225_ProtoParam m_protoParam;
+    CISCO_H225_CommonParam m_commonParam;
+    PASN_OctetString m_dummy1;
+    CISCO_H225_ProgIndParam m_progIndParam;
+    CISCO_H225_CallMgrParam m_callMgrParam;
+    CISCO_H225_CallSignallingParam m_callSignallingParam;
+    PASN_OctetString m_dummy2;
+    CISCO_H225_CallPreserveParam m_callPreserveParam;
+
+    PINDEX GetDataLength() const;
+    PBoolean Decode(PASN_Stream & strm);
+    void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+    void PrintOn(ostream & strm) const;
+#endif
+    Comparison Compare(const PObject & obj) const;
+    PObject * Clone() const;
+};
+
+
+#endif // __CISCO_H225_H
+
+#endif // if ! H323_DISABLE_CISCO_H225
+
+
+// End of cisco-h225.h
diff --git a/channels/h323/compat_h323.cxx b/channels/h323/compat_h323.cxx
new file mode 100644
index 0000000..609d18e
--- /dev/null
+++ b/channels/h323/compat_h323.cxx
@@ -0,0 +1,139 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/*
+ * ast_h323.cpp
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ *			By  Jeremy McNamara
+ *			For The NuFone Network
+ * 
+ * chan_h323 has been derived from code created by
+ *               Michael Manousos and Mark Spencer
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * chan_h323 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version. 
+ *
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even 
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE. See the GNU General Public License for more details. 
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * Version Info: $Id$
+ */
+#include <ptlib.h>
+#include <h323.h>
+#include <transports.h>
+
+#include "ast_h323.h"
+#include "compat_h323.h"
+
+#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
+MyH323TransportTCP::MyH323TransportTCP(
+				H323EndPoint & endpoint,
+				PIPSocket::Address binding,
+				PBoolean listen)
+	: H323TransportTCP(endpoint, binding, listen)
+{
+}
+
+PBoolean MyH323TransportTCP::Connect()
+{
+	if (IsListening())
+		return TRUE;
+
+	PTCPSocket * socket = new PTCPSocket(remotePort);
+	Open(socket);
+
+	channelPointerMutex.StartRead();
+
+	socket->SetReadTimeout(10000/*endpoint.GetSignallingChannelConnectTimeout()*/);
+
+	localPort = endpoint.GetNextTCPPort();
+	WORD firstPort = localPort;
+	for (;;) {
+		PTRACE(4, "H323TCP\tConnecting to "
+				<< remoteAddress << ':' << remotePort
+				<< " (local port=" << localPort << ')');
+		if (socket->Connect(localAddress, localPort, remoteAddress))
+			break;
+
+		int errnum = socket->GetErrorNumber();
+		if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) {
+			PTRACE(1, "H323TCP\tCould not connect to "
+					<< remoteAddress << ':' << remotePort
+					<< " (local port=" << localPort << ") - "
+					<< socket->GetErrorText() << '(' << errnum << ')');
+			channelPointerMutex.EndRead();
+			return SetErrorValues(socket->GetErrorCode(), errnum);
+		}
+
+		localPort = endpoint.GetNextTCPPort();
+		if (localPort == firstPort) {
+			PTRACE(1, "H323TCP\tCould not bind to any port in range " <<
+					endpoint.GetTCPPortBase() << " to " << endpoint.GetTCPPortMax());
+			channelPointerMutex.EndRead();
+			return SetErrorValues(socket->GetErrorCode(), errnum);
+		}
+	}
+
+	socket->SetReadTimeout(PMaxTimeInterval);
+
+	channelPointerMutex.EndRead();
+
+	return OnOpen();
+}
+#endif
+
+PBoolean MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address)
+{
+	PThread *thd = PThread::Current();
+
+	/* If we run in OpenH323's thread use it instead of creating new one */
+	if (thd)
+		return H323TransportUDP::DiscoverGatekeeper(gk, pdu, address);
+
+	/* Make copy of arguments to pass them into thread */
+	discoverGatekeeper = &gk;
+	discoverPDU = &pdu;
+	discoverAddress = &address;
+
+	/* Assume discovery thread isn't finished */
+	discoverReady = FALSE;
+
+	/* Create discovery thread */
+	thd = PThread::Create(PCREATE_NOTIFIER(DiscoverMain), 0,
+							PThread::NoAutoDeleteThread,
+							PThread::NormalPriority,
+							"GkDiscovery:%x");
+
+	/* Wait until discovery thread signal us its finished */ 
+	for(;;) {
+		discoverMutex.Wait();
+		if (discoverReady)		/* Thread has been finished */
+			break;
+		discoverMutex.Signal();
+	}
+	discoverMutex.Signal();
+
+	/* Cleanup/delete thread */
+	thd->WaitForTermination();
+	delete thd;
+
+	return discoverResult;
+}
+
+void MyH323TransportUDP::DiscoverMain(PThread &thread, INT arg)
+{
+	PWaitAndSignal m(discoverMutex);
+
+	discoverResult = H323TransportUDP::DiscoverGatekeeper(*discoverGatekeeper, *discoverPDU, *discoverAddress);
+	discoverReady = TRUE;
+}
diff --git a/channels/h323/compat_h323.h b/channels/h323/compat_h323.h
new file mode 100644
index 0000000..61076f1
--- /dev/null
+++ b/channels/h323/compat_h323.h
@@ -0,0 +1,96 @@
+#ifndef COMPAT_H323_H
+#define COMPAT_H323_H
+
+#include "ast_ptlib.h"
+
+#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
+/**
+ *  Workaround for broken (less than 1.17.3) OpenH323 stack to be able to
+ *  make TCP connections from specific address
+ */
+class MyH323TransportTCP : public H323TransportTCP
+{
+	PCLASSINFO(MyH323TransportTCP, H323TransportTCP);
+
+public:
+	MyH323TransportTCP(
+		H323EndPoint & endpoint,    ///<  H323 End Point object
+		PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(), ///<  Local interface to use
+		PBoolean listen = FALSE         ///<  Flag for need to wait for remote to connect
+	);
+	/**Connect to the remote party.
+	 */
+	virtual PBoolean Connect();
+};
+#else
+#define MyH323TransportTCP H323TransportTCP
+#endif /* <VERSION(1,17,3) */
+
+class MyH323TransportUDP: public H323TransportUDP
+{
+	PCLASSINFO(MyH323TransportUDP, H323TransportUDP);
+
+public:
+	MyH323TransportUDP(H323EndPoint &endpoint,
+		PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(),
+		WORD localPort = 0,
+		WORD remotePort = 0): H323TransportUDP(endpoint, binding, localPort, remotePort)
+	{
+	}
+	virtual PBoolean DiscoverGatekeeper(H323Gatekeeper &,
+		H323RasPDU &,
+		const H323TransportAddress &);
+protected:
+	PDECLARE_NOTIFIER(PThread, MyH323TransportUDP, DiscoverMain);
+	H323Gatekeeper *discoverGatekeeper;
+	H323RasPDU *discoverPDU;
+	const H323TransportAddress *discoverAddress;
+	PBoolean discoverResult;
+	PBoolean discoverReady;
+	PMutex discoverMutex;
+};
+
+template <class _Abstract_T, typename _Key_T = PString>
+class MyPFactory: public PFactory<_Abstract_T, _Key_T>
+{
+public:
+	template <class _Concrete_T> class Worker: public PFactory<_Abstract_T, _Key_T>::WorkerBase
+	{
+	public:
+		Worker(const _Key_T &_key, bool singleton = false)
+			:PFactory<_Abstract_T, _Key_T>::WorkerBase(singleton), key(_key)
+		{
+			PFactory<_Abstract_T, _Key_T>::Register(key, this);
+		}
+		~Worker()
+		{
+			PFactory<_Abstract_T, _Key_T>::Unregister(key);
+		}
+	protected:
+		virtual _Abstract_T *Create(const _Key_T &) const { return new _Concrete_T; }
+
+	private:
+		PString key;
+    };
+};
+
+#ifdef H323_REGISTER_CAPABILITY
+#undef H323_REGISTER_CAPABILITY
+#endif
+#define H323_REGISTER_CAPABILITY(cls, capName) static MyPFactory<H323Capability>::Worker<cls> cls##Factory(capName, true)
+
+#ifdef OPAL_MEDIA_FORMAT_DECLARE
+#undef OPAL_MEDIA_FORMAT_DECLARE
+#endif
+
+#define OPAL_MEDIA_FORMAT_DECLARE(classname, _fullName, _defaultSessionID, _rtpPayloadType, _needsJitter,_bandwidth, _frameSize, _frameTime, _timeUnits, _timeStamp) \
+class classname : public OpalMediaFormat \
+{ \
+  public: \
+    classname() \
+      : OpalMediaFormat(_fullName, _defaultSessionID, _rtpPayloadType, _needsJitter, _bandwidth, \
+        _frameSize, _frameTime, _timeUnits, _timeStamp){} \
+}; \
+static MyPFactory<OpalMediaFormat>::Worker<classname> classname##Factory(_fullName, true)
+
+#endif /* !defined AST_H323_H */
diff --git a/channels/h323/noexport.map b/channels/h323/noexport.map
new file mode 100644
index 0000000..b51f842
--- /dev/null
+++ b/channels/h323/noexport.map
@@ -0,0 +1,5 @@
+{
+	global:
+		_Z11PAssertFuncPKc;
+	local:	*;
+};
\ No newline at end of file
diff --git a/channels/iax2/parser.c b/channels/iax2-parser.c
similarity index 94%
rename from channels/iax2/parser.c
rename to channels/iax2-parser.c
index 57f245b..ece2710 100644
--- a/channels/iax2/parser.c
+++ b/channels/iax2-parser.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -41,14 +41,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #include "asterisk/config.h"
 #include "asterisk/lock.h"
 #include "asterisk/threadstorage.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_compatibility.h"
 
-#include "include/iax2.h"
-#include "include/parser.h"
-#include "include/provision.h"
-#include "include/codec_pref.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+#include "iax2-provision.h"
 
 static int frames = 0;
 static int iframes = 0;
@@ -87,23 +83,13 @@ static void (*errorf)(const char *str) = internalerror;
 
 static void dump_addr(char *output, int maxlen, void *value, int len)
 {
-	struct ast_sockaddr addr;
-
-	if (len == (int)sizeof(struct sockaddr_in)) {
-		addr.ss.ss_family = AF_INET;
-	} else if (len == (int) sizeof(struct sockaddr_in6)) {
-		addr.ss.ss_family = AF_INET6;
+	struct sockaddr_in sin;
+	if (len == (int)sizeof(sin)) {
+		memcpy(&sin, value, len);
+		snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 	} else {
 		ast_copy_string(output, "Invalid Address", maxlen);
-		return;
 	}
-
-	memcpy(&addr, value, len);
-	addr.len = len;
-
-	snprintf(output, maxlen, "%s %s",
-				ast_sockaddr_is_ipv4(&addr) || ast_sockaddr_is_ipv4_mapped(&addr) ? "IPV4" : "IPV6",
-				ast_sockaddr_stringify(&addr));
 }
 
 static void dump_string_hex(char *output, int maxlen, void *value, int len)
@@ -111,7 +97,7 @@ static void dump_string_hex(char *output, int maxlen, void *value, int len)
 	int i = 0;
 
 	while (len-- && (i + 1) * 4 < maxlen) {
-		sprintf(output + (4 * i), "\\x%2.2x", (unsigned)*((unsigned char *)value + i));
+		sprintf(output + (4 * i), "\\x%02hhx", *((unsigned char *)value + i));
 		i++;
 	}
 }
@@ -127,7 +113,7 @@ static void dump_string(char *output, int maxlen, void *value, int len)
 
 static void dump_prefs(char *output, int maxlen, void *value, int len)
 {
-	struct iax2_codec_pref pref;
+	struct ast_codec_pref pref;
 	int total_len = 0;
 
 	maxlen--;
@@ -139,9 +125,9 @@ static void dump_prefs(char *output, int maxlen, void *value, int len)
 	strncpy(output, value, maxlen);
 	output[maxlen] = '\0';
 	
-	iax2_codec_pref_convert(&pref, output, total_len, 0);
+	ast_codec_pref_convert(&pref, output, total_len, 0);
 	memset(output,0,total_len);
-	iax2_codec_pref_string(&pref, output, total_len);
+	ast_codec_pref_string(&pref, output, total_len);
 }
 
 static void dump_int(char *output, int maxlen, void *value, int len)
@@ -186,23 +172,12 @@ static void dump_datetime(char *output, int maxlen, void *value, int len)
 
 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
 {
-	struct ast_sockaddr addr;
-	char *str_addr;
-
-	if (len == (int)sizeof(struct sockaddr_in)) {
-		addr.ss.ss_family = AF_INET;
-	} else if (len == (int)sizeof(struct sockaddr_in6)) {
-		addr.ss.ss_family = AF_INET6;
-	} else {
+	struct sockaddr_in sin;
+	if (len == (int)sizeof(unsigned int)) {
+		memcpy(&sin.sin_addr, value, len);
+		snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
+	} else
 		ast_copy_string(output, "Invalid IPADDR", maxlen);
-		return;
-	}
-
-	memcpy(&addr, value, len);
-	addr.len = len;
-
-	str_addr = ast_sockaddr_stringify(&addr);
-	ast_copy_string(output, str_addr, maxlen);
 }
 
 
@@ -589,7 +564,7 @@ void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t
 	ast_copy_string(str, cmd, len);
 }
 
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
 {
 	const char *framelist[] = {
 		"(0?)",
@@ -702,22 +677,19 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
 		snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
 		subclass = subclass2;
 	}
-
-	snprintf(tmp, sizeof(tmp),
-		"%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
+	snprintf(tmp, sizeof(tmp), 
+		 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
 		 dir,
 		 retries, fh->oseqno, fh->iseqno, class, subclass);
 	outputf(tmp);
-	snprintf(tmp, sizeof(tmp), "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d %s\n",
-			(unsigned long)ntohl(fh->ts),
-			ntohs(fh->scallno) & ~IAX_FLAG_FULL,
-			ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
-			ast_sockaddr_stringify(addr));
-
+	snprintf(tmp, sizeof(tmp), 
+		 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
+		 (unsigned long)ntohl(fh->ts),
+		 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
+		 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 	outputf(tmp);
 	if (fh->type == AST_FRAME_IAX)
 		dump_ies(fh->iedata, datalen);
-
 }
 
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
@@ -735,9 +707,9 @@ int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *dat
 	return 0;
 }
 
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct ast_sockaddr *addr)
+int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
 {
-	return iax_ie_append_raw(ied, ie, addr, addr->len);
+	return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
 }
 
 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
@@ -932,8 +904,7 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
 			ies->rsa_result = (char *)data + 2;
 			break;
 		case IAX_IE_APPARENT_ADDR:
-			memcpy(&ies->apparent_addr , (struct ast_sockaddr *) (data + 2), len);
-			ies->apparent_addr.len = len;
+			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
 			break;
 		case IAX_IE_REFRESH:
 			if (len != (int)sizeof(unsigned short)) {
@@ -1183,8 +1154,7 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
 {
 	fr->af.frametype = f->frametype;
-	fr->af.subclass.format = f->subclass.format;
-	fr->af.subclass.integer = f->subclass.integer;
+	ast_format_copy(&fr->af.subclass.format, &f->subclass.format);
 	fr->af.mallocd = 0;				/* Our frame is static relative to the container */
 	fr->af.datalen = f->datalen;
 	fr->af.samples = f->samples;
@@ -1203,8 +1173,7 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
 		}
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 		/* We need to byte-swap slinear samples from network byte order */
-		if ((fr->af.frametype == AST_FRAME_VOICE) &&
-			(ast_format_cmp(fr->af.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+		if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.format.id == AST_FORMAT_SLINEAR)) {
 			/* 2 bytes / sample for SLINEAR */
 			ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
 		} else
diff --git a/channels/iax2/include/parser.h b/channels/iax2-parser.h
similarity index 95%
rename from channels/iax2/include/parser.h
rename to channels/iax2-parser.h
index 7c9ba2a..978ca0d 100644
--- a/channels/iax2/include/parser.h
+++ b/channels/iax2-parser.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Implementation of Inter-Asterisk eXchange
  * 
@@ -18,10 +18,8 @@
 #ifndef _IAX2_PARSER_H
 #define _IAX2_PARSER_H
 
-#include "asterisk/frame.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/crypto.h"
-#include "asterisk/netsock2.h"
 #include "iax2.h"
 
 struct iax_ies {
@@ -48,7 +46,7 @@ struct iax_ies {
 	char *challenge;
 	char *md5_result;
 	char *rsa_result;
-	struct ast_sockaddr apparent_addr;
+	struct sockaddr_in *apparent_addr;
 	unsigned short refresh;
 	unsigned short dpstatus;
 	unsigned short callno;
@@ -154,13 +152,13 @@ struct iax_ie_data {
 void iax_set_output(void (*output)(const char *data));
 /* Choose a different function for errors */
 void iax_set_error(void (*output)(const char *data));
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen);
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
 void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len);
 
 const char *iax_ie2str(int ie);
 
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen);
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct ast_sockaddr *addr);
+int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin);
 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value);
 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
diff --git a/channels/iax2/provision.c b/channels/iax2-provision.c
similarity index 97%
rename from channels/iax2/provision.c
rename to channels/iax2-provision.c
index 968cf0e..a00d6f7 100644
--- a/channels/iax2/provision.c
+++ b/channels/iax2-provision.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <netdb.h>
 #include <netinet/in.h>
@@ -45,12 +45,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #include "asterisk/astdb.h"
 #include "asterisk/utils.h"
 #include "asterisk/acl.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_compatibility.h"
-
-#include "include/iax2.h"
-#include "include/provision.h"
-#include "include/parser.h"
+#include "iax2.h"
+#include "iax2-provision.h"
+#include "iax2-parser.h"
 
 static int provinit = 0;
 
@@ -347,10 +344,9 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg,
 			} else 
 				ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
 		} else if (!strcasecmp(v->name, "codec")) {
-			struct ast_format *tmpfmt;
-			if ((tmpfmt = ast_format_cache_get(v->value))) {
-				cur->format = ast_format_compatibility_format2bitfield(tmpfmt);
-				ao2_ref(tmpfmt, -1);
+			struct ast_format tmpfmt;
+			if ((ast_getformatbyname(v->value, &tmpfmt)) > 0) {
+				cur->format = ast_format_to_old_bitfield(&tmpfmt);
 			} else
 				ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno);
 		} else if (!strcasecmp(v->name, "tos")) {
diff --git a/channels/iax2/include/provision.h b/channels/iax2-provision.h
similarity index 95%
rename from channels/iax2/include/provision.h
rename to channels/iax2-provision.h
index fd5a829..b1dfd06 100644
--- a/channels/iax2/include/provision.h
+++ b/channels/iax2-provision.h
@@ -13,10 +13,7 @@
  *  \brief IAX2 Provisioning protocol
  */
 
-#ifndef __IAX2_PROVISION_H
-#define __IAX2_PROVISION_H
-
-#include "parser.h"
+#include "iax2-parser.h"
 
 #define PROV_IE_USEDHCP 	1	/* Presense only */
 #define PROV_IE_IPADDR		2	/* 32-bit */
@@ -54,5 +51,3 @@ int iax_provision_unload(void);
 int iax_provision_build(struct iax_ie_data *provdata, unsigned int *signature, const char *template, int force);
 int iax_provision_version(unsigned int *signature, const char *template, int force);
 char *iax_prov_complete_template(const char *line, const char *word, int pos, int state);
-
-#endif
diff --git a/channels/iax2/include/iax2.h b/channels/iax2.h
similarity index 99%
rename from channels/iax2/include/iax2.h
rename to channels/iax2.h
index ca9ab74..6615016 100644
--- a/channels/iax2/include/iax2.h
+++ b/channels/iax2.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Implementation of Inter-Asterisk eXchange
  * 
diff --git a/channels/iax2/codec_pref.c b/channels/iax2/codec_pref.c
deleted file mode 100644
index 814f850..0000000
--- a/channels/iax2/codec_pref.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420364 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/format_compatibility.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/utils.h"
-
-#include "include/codec_pref.h"
-#include "include/format_compatibility.h"
-
-void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right)
-{
-	static int differential = (int) 'A';
-	int x;
-
-	if (right) {
-		--size;/* Save room for the nul string terminator. */
-		for (x = 0; x < ARRAY_LEN(pref->order) && x < size; ++x) {
-			if (!pref->order[x]) {
-				break;
-			}
-
-			buf[x] = pref->order[x] + differential;
-		}
-
-		buf[x] = '\0';
-	} else {
-		for (x = 0; x < ARRAY_LEN(pref->order) && x < size; ++x) {
-			if (buf[x] == '\0') {
-				break;
-			}
-
-			pref->order[x] = buf[x] - differential;
-			pref->framing[x] = 0;
-		}
-
-		if (x < ARRAY_LEN(pref->order)) {
-			pref->order[x] = 0;
-			pref->framing[x] = 0;
-		}
-	}
-}
-
-struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int idx, struct ast_format **result)
-{
-	if (0 <= idx && idx < ARRAY_LEN(pref->order) && pref->order[idx]) {
-		uint64_t pref_bitfield;
-
-		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
-		*result = ast_format_compatibility_bitfield2format(pref_bitfield);
-	} else {
-		*result = NULL;
-	}
-
-	return *result;
-}
-
-int iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
-{
-	int idx;
-
-	for (idx = 0; idx < ARRAY_LEN(pref->order); ++idx) {
-		uint64_t pref_bitfield;
-		struct ast_format *pref_format;
-
-		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
-		if (!pref_bitfield) {
-			break;
-		}
-
-		pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
-		if (pref_format && ast_format_cap_append(cap, pref_format, pref->framing[idx])) {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-int iax2_codec_pref_best_bitfield2cap(uint64_t bitfield, struct iax2_codec_pref *prefs, struct ast_format_cap *cap)
-{
-	uint64_t best_bitfield;
-	struct ast_format *format;
-
-	/* Add any user preferred codecs first. */
-	if (prefs) {
-		int idx;
-
-		for (idx = 0; bitfield && idx < ARRAY_LEN(prefs->order); ++idx) {
-			best_bitfield = iax2_codec_pref_order_value_to_format_bitfield(prefs->order[idx]);
-			if (!best_bitfield) {
-				break;
-			}
-
-			if (best_bitfield & bitfield) {
-				format = ast_format_compatibility_bitfield2format(best_bitfield);
-				if (format && ast_format_cap_append(cap, format, prefs->framing[idx])) {
-					return -1;
-				}
-
-				/* Remove just added codec. */
-				bitfield &= ~best_bitfield;
-			}
-		}
-	}
-
-	/* Add the hard coded "best" codecs. */
-	while (bitfield) {
-		best_bitfield = iax2_format_compatibility_best(bitfield);
-		if (!best_bitfield) {
-			/* No more codecs considered best. */
-			break;
-		}
-
-		format = ast_format_compatibility_bitfield2format(best_bitfield);
-		/* The best_bitfield should always be convertible to a format. */
-		ast_assert(format != NULL);
-
-		if (ast_format_cap_append(cap, format, 0)) {
-			return -1;
-		}
-
-		/* Remove just added "best" codec to find the next "best". */
-		bitfield &= ~best_bitfield;
-	}
-
-	/* Add any remaining codecs. */
-	if (bitfield) {
-		int bit;
-
-		for (bit = 0; bit < 64; ++bit) {
-			uint64_t mask = (1ULL << bit);
-
-			if (mask & bitfield) {
-				format = ast_format_compatibility_bitfield2format(mask);
-				if (format && ast_format_cap_append(cap, format, 0)) {
-					return -1;
-				}
-			}
-		}
-	}
-
-	return 0;
-}
-
-int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size)
-{
-	int x;
-	struct ast_format_cap *cap;
-	size_t total_len;
-	char *cur;
-
-	/* This function is useless if you have less than a 6 character buffer.
-	 * '(...)' is six characters. */
-	if (size < 6) {
-		return -1;
-	}
-
-	/* Convert the preferences into a format cap so that we can read the format names */
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
-		strcpy(buf, "(...)"); /* Safe */
-		ao2_cleanup(cap);
-		return -1;
-	}
-
-	/* We know that at a minimum, 3 characters are used - (, ), and \0 */
-	total_len = size - 3;
-
-	/* This character has already been accounted for total_len purposes */
-	buf[0] = '(';
-	cur = buf + 1;
-
-	/* Loop through the formats and write as many into the buffer as we can */
-	for (x = 0; x < ast_format_cap_count(cap); x++) {
-		size_t name_len;
-		struct ast_format *fmt = ast_format_cap_get_format(cap, x);
-		const char *name = ast_format_get_name(fmt);
-
-		name_len = strlen(name);
-
-		/* all entries after the first need a delimiter character */
-		if (x) {
-			name_len++;
-		}
-
-		/* Terminate the list early if we don't have room for the entry.
-		 * If it's not the last entry in the list, save enough room to write '...'.
-		 */
-		if (((x == ast_format_cap_count(cap) - 1) && (total_len < name_len)) ||
-				((x < ast_format_cap_count(cap) - 1) && (total_len < name_len + 3))) {
-			strcpy(cur, "...");
-			cur += 3;
-			total_len -= 3;
-			ao2_ref(fmt, -1);
-			break;
-		}
-
-		sprintf(cur, "%s%s", x ? "|" : "", name);
-		cur += name_len;
-		total_len -= name_len;
-
-		ao2_ref(fmt, -1);
-	}
-	ao2_ref(cap, -1);
-
-	/* These two characters have already been accounted for total_len purposes */
-	cur[0] = ')';
-	cur[1] = '\0';
-
-	return size - total_len;
-}
-
-static void codec_pref_remove_index(struct iax2_codec_pref *pref, int codec_pref_index)
-{
-	int idx;
-
-	idx = codec_pref_index;
-	if (idx == ARRAY_LEN(pref->order) - 1) {
-		/* Remove from last array entry. */
-		pref->order[idx] = 0;
-		pref->framing[idx] = 0;
-		return;
-	}
-
-	for (; idx < ARRAY_LEN(pref->order); ++idx) {
-		pref->order[idx] = pref->order[idx + 1];
-		pref->framing[idx] = pref->framing[idx + 1];
-		if (!pref->order[idx]) {
-			return;
-		}
-	}
-}
-
-/*! \brief Remove codec from pref list */
-static void codec_pref_remove(struct iax2_codec_pref *pref, int format_index)
-{
-	int x;
-
-	if (!pref->order[0]) {
-		return;
-	}
-
-	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
-		if (!pref->order[x]) {
-			break;
-		}
-
-		if (pref->order[x] == format_index) {
-			codec_pref_remove_index(pref, x);
-			break;
-		}
-	}
-}
-
-void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield)
-{
-	int idx;
-
-	if (!pref->order[0]) {
-		return;
-	}
-
-	/*
-	 * Work from the end of the list so we always deal with
-	 * unmodified entries in case we have to remove a pref.
-	 */
-	for (idx = ARRAY_LEN(pref->order); idx--;) {
-		uint64_t pref_bitfield;
-
-		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
-		if (!pref_bitfield) {
-			continue;
-		}
-
-		/* If this format isn't in the bitfield, remove it from the prefs. */
-		if (!(pref_bitfield & bitfield)) {
-			codec_pref_remove_index(pref, idx);
-		}
-	}
-}
-
-/*!
- * \brief Formats supported by IAX2.
- *
- * \note All AST_FORMAT_xxx compatibility bit defines must be
- *  represented here.
- *
- * \note The order is important because the array index+1 values
- * go out over the wire.
- */
-static const uint64_t iax2_supported_formats[] = {
-	AST_FORMAT_G723,
-	AST_FORMAT_GSM,
-	AST_FORMAT_ULAW,
-	AST_FORMAT_ALAW,
-	AST_FORMAT_G726,
-	AST_FORMAT_ADPCM,
-	AST_FORMAT_SLIN,
-	AST_FORMAT_LPC10,
-	AST_FORMAT_G729,
-	AST_FORMAT_SPEEX,
-	AST_FORMAT_SPEEX16,
-	AST_FORMAT_ILBC,
-	AST_FORMAT_G726_AAL2,
-	AST_FORMAT_G722,
-	AST_FORMAT_SLIN16,
-	AST_FORMAT_JPEG,
-	AST_FORMAT_PNG,
-	AST_FORMAT_H261,
-	AST_FORMAT_H263,
-	AST_FORMAT_H263P,
-	AST_FORMAT_H264,
-	AST_FORMAT_MP4,
-	AST_FORMAT_T140_RED,
-	AST_FORMAT_T140,
-	AST_FORMAT_SIREN7,
-	AST_FORMAT_SIREN14,
-	AST_FORMAT_TESTLAW,
-	AST_FORMAT_G719,
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	0, /* Place holder */
-	AST_FORMAT_OPUS,
-	AST_FORMAT_VP8,
-	/* ONLY ADD TO THE END OF THIS LIST */
-	/* XXX Use up the place holder slots first. */
-};
-
-uint64_t iax2_codec_pref_order_value_to_format_bitfield(int order_value)
-{
-	if (order_value < 1 || ARRAY_LEN(iax2_supported_formats) < order_value) {
-		return 0;
-	}
-
-	return iax2_supported_formats[order_value - 1];
-}
-
-int iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield)
-{
-	int idx;
-
-	if (bitfield) {
-		for (idx = 0; idx < ARRAY_LEN(iax2_supported_formats); ++idx) {
-			if (iax2_supported_formats[idx] == bitfield) {
-				return idx + 1;
-			}
-		}
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Append the bitfield format to the codec preference list.
- * \since 13.0.0
- *
- * \param pref Codec preference list to append the given bitfield.
- * \param bitfield Format bitfield to append.
- * \param framing Framing size of the codec.
- *
- * \return Nothing
- */
-static void iax2_codec_pref_append_bitfield(struct iax2_codec_pref *pref, uint64_t bitfield, unsigned int framing)
-{
-	int format_index;
-	int x;
-
-	format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
-	if (!format_index) {
-		return;
-	}
-
-	codec_pref_remove(pref, format_index);
-
-	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
-		if (!pref->order[x]) {
-			pref->order[x] = format_index;
-			pref->framing[x] = framing;
-			break;
-		}
-	}
-}
-
-void iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing)
-{
-	uint64_t bitfield;
-
-	bitfield = ast_format_compatibility_format2bitfield(format);
-	if (!bitfield) {
-		return;
-	}
-
-	iax2_codec_pref_append_bitfield(pref, bitfield, framing);
-}
-
-void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing,
-	int only_if_existing)
-{
-	uint64_t bitfield;
-	int format_index;
-	int x;
-
-	bitfield = ast_format_compatibility_format2bitfield(format);
-	if (!bitfield) {
-		return;
-	}
-	format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
-	if (!format_index) {
-		return;
-	}
-
-	/* Now find any existing occurrence, or the end */
-	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
-		if (!pref->order[x] || pref->order[x] == format_index)
-			break;
-	}
-
-	/*
-	 * The array can never be full without format_index
-	 * also being in the array.
-	 */
-	ast_assert(x < ARRAY_LEN(pref->order));
-
-	/* If we failed to find any occurrence, set to the end for safety. */
-	if (ARRAY_LEN(pref->order) <= x) {
-		x = ARRAY_LEN(pref->order) - 1;
-	}
-
-	if (only_if_existing && !pref->order[x]) {
-		return;
-	}
-
-	/* Move down to make space to insert - either all the way to the end,
-	   or as far as the existing location (which will be overwritten) */
-	for (; x > 0; --x) {
-		pref->order[x] = pref->order[x - 1];
-		pref->framing[x] = pref->framing[x - 1];
-	}
-
-	/* And insert the new entry */
-	pref->order[0] = format_index;
-	pref->framing[0] = framing;
-}
-
-uint64_t iax2_codec_pref_from_bitfield(struct iax2_codec_pref *pref, uint64_t bitfield)
-{
-	int bit;
-	uint64_t working_bitfield;
-	uint64_t best_bitfield;
-	struct ast_format *format;
-
-	/* Init the preference list. */
-	memset(pref, 0, sizeof(*pref));
-
-	working_bitfield = bitfield;
-
-	/* Add the "best" codecs first. */
-	while (working_bitfield) {
-		best_bitfield = iax2_format_compatibility_best(working_bitfield);
-		if (!best_bitfield) {
-			/* No more codecs considered best. */
-			break;
-		}
-
-		/* Remove current "best" codec to find the next "best". */
-		working_bitfield &= ~best_bitfield;
-
-		format = ast_format_compatibility_bitfield2format(best_bitfield);
-		/* The best_bitfield should always be convertible to a format. */
-		ast_assert(format != NULL);
-
-		iax2_codec_pref_append_bitfield(pref, best_bitfield, 0);
-	}
-
-	/* Add any remaining codecs. */
-	if (working_bitfield) {
-		for (bit = 0; bit < 64; ++bit) {
-			uint64_t mask = (1ULL << bit);
-
-			if (mask & working_bitfield) {
-				format = ast_format_compatibility_bitfield2format(mask);
-				if (!format) {
-					/* The bit is not associated with any format. */
-					bitfield &= ~mask;
-					continue;
-				}
-
-				iax2_codec_pref_append_bitfield(pref, mask, 0);
-			}
-		}
-	}
-
-	return bitfield;
-}
diff --git a/channels/iax2/firmware.c b/channels/iax2/firmware.c
deleted file mode 100644
index ea240fb..0000000
--- a/channels/iax2/firmware.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief IAX Firmware Support
- *
- * \author Mark Spencer <markster at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/mman.h>
-#include <arpa/inet.h>
-
-#include "asterisk/linkedlists.h"
-#include "asterisk/md5.h"
-#include "asterisk/paths.h"
-#include "asterisk/utils.h"
-
-#include "include/firmware.h"
-
-struct iax_firmware {
-	AST_LIST_ENTRY(iax_firmware) list;
-	int fd;
-	int mmaplen;
-	int dead;
-	struct ast_iax2_firmware_header *fwh;
-	unsigned char *buf;
-};
-
-static AST_LIST_HEAD_STATIC(firmwares, iax_firmware);
-
-static int try_firmware(char *s)
-{
-	struct stat stbuf;
-	struct iax_firmware *cur = NULL;
-	int ifd, fd, res, len, chunk;
-	struct ast_iax2_firmware_header *fwh, fwh2;
-	struct MD5Context md5;
-	unsigned char sum[16], buf[1024];
-	char *s2, *last;
-
-	s2 = ast_alloca(strlen(s) + 100);
-
-	last = strrchr(s, '/');
-	if (last)
-		last++;
-	else
-		last = s;
-
-	snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, ast_random());
-
-	if (stat(s, &stbuf) < 0) {
-		ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));
-		return -1;
-	}
-
-	/* Make sure it's not a directory */
-	if (S_ISDIR(stbuf.st_mode))
-		return -1;
-	ifd = open(s, O_RDONLY);
-	if (ifd < 0) {
-		ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));
-		return -1;
-	}
-	fd = open(s2, O_RDWR | O_CREAT | O_EXCL, AST_FILE_MODE);
-	if (fd < 0) {
-		ast_log(LOG_WARNING, "Cannot open '%s' for writing: %s\n", s2, strerror(errno));
-		close(ifd);
-		return -1;
-	}
-	/* Unlink our newly created file */
-	unlink(s2);
-
-	/* Now copy the firmware into it */
-	len = stbuf.st_size;
-	while(len) {
-		chunk = len;
-		if (chunk > sizeof(buf))
-			chunk = sizeof(buf);
-		res = read(ifd, buf, chunk);
-		if (res != chunk) {
-			ast_log(LOG_WARNING, "Only read %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
-			close(ifd);
-			close(fd);
-			return -1;
-		}
-		res = write(fd, buf, chunk);
-		if (res != chunk) {
-			ast_log(LOG_WARNING, "Only write %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
-			close(ifd);
-			close(fd);
-			return -1;
-		}
-		len -= chunk;
-	}
-	close(ifd);
-	/* Return to the beginning */
-	lseek(fd, 0, SEEK_SET);
-	if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {
-		ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);
-		close(fd);
-		return -1;
-	}
-	if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {
-		ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);
-		close(fd);
-		return -1;
-	}
-	if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {
-		ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);
-		close(fd);
-		return -1;
-	}
-	if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {
-		ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
-		close(fd);
-		return -1;
-	}
-	fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if (fwh == MAP_FAILED) {
-		ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
-		close(fd);
-		return -1;
-	}
-	MD5Init(&md5);
-	MD5Update(&md5, fwh->data, ntohl(fwh->datalen));
-	MD5Final(sum, &md5);
-	if (memcmp(sum, fwh->chksum, sizeof(sum))) {
-		ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);
-		munmap((void*)fwh, stbuf.st_size);
-		close(fd);
-		return -1;
-	}
-
-	AST_LIST_TRAVERSE(&firmwares, cur, list) {
-		if (!strcmp((const char *) cur->fwh->devname, (const char *) fwh->devname)) {
-			/* Found a candidate */
-			if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
-				/* The version we have on loaded is older, load this one instead */
-				break;
-			/* This version is no newer than what we have.  Don't worry about it.
-			   We'll consider it a proper load anyhow though */
-			munmap((void*)fwh, stbuf.st_size);
-			close(fd);
-			return 0;
-		}
-	}
-
-	if (!cur && ((cur = ast_calloc(1, sizeof(*cur))))) {
-		cur->fd = -1;
-		AST_LIST_INSERT_TAIL(&firmwares, cur, list);
-	}
-
-	if (cur) {
-		if (cur->fwh)
-			munmap((void*)cur->fwh, cur->mmaplen);
-		if (cur->fd > -1)
-			close(cur->fd);
-		cur->fwh = fwh;
-		cur->fd = fd;
-		cur->mmaplen = stbuf.st_size;
-		cur->dead = 0;
-	}
-
-	return 0;
-}
-
-static void destroy_firmware(struct iax_firmware *cur)
-{
-	/* Close firmware */
-	if (cur->fwh) {
-		munmap((void*)cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
-	}
-	close(cur->fd);
-	ast_free(cur);
-}
-
-void iax_firmware_reload(void)
-{
-	struct iax_firmware *cur = NULL;
-	DIR *fwd;
-	struct dirent *de;
-	char dir[256], fn[256];
-
-	AST_LIST_LOCK(&firmwares);
-
-	/* Mark all as dead */
-	AST_LIST_TRAVERSE(&firmwares, cur, list) {
-		cur->dead = 1;
-	}
-
-	/* Now that we have marked them dead... load new ones */
-	snprintf(dir, sizeof(dir), "%s/firmware/iax", ast_config_AST_DATA_DIR);
-	fwd = opendir(dir);
-	if (fwd) {
-		while((de = readdir(fwd))) {
-			if (de->d_name[0] != '.') {
-				snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);
-				if (!try_firmware(fn)) {
-					ast_verb(2, "Loaded firmware '%s'\n", de->d_name);
-				}
-			}
-		}
-		closedir(fwd);
-	} else {
-		ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno));
-	}
-
-	/* Clean up leftovers */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&firmwares, cur, list) {
-		if (!cur->dead)
-			continue;
-		AST_LIST_REMOVE_CURRENT(list);
-		destroy_firmware(cur);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	AST_LIST_UNLOCK(&firmwares);
-}
-
-void iax_firmware_unload(void)
-{
-	struct iax_firmware *cur = NULL;
-
-	AST_LIST_LOCK(&firmwares);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&firmwares, cur, list) {
-		AST_LIST_REMOVE_CURRENT(list);
-		destroy_firmware(cur);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-	AST_LIST_UNLOCK(&firmwares);
-}
-
-int iax_firmware_get_version(const char *dev, uint16_t *version)
-{
-	struct iax_firmware *cur = NULL;
-
-	if (ast_strlen_zero(dev))
-		return 0;
-
-	AST_LIST_LOCK(&firmwares);
-	AST_LIST_TRAVERSE(&firmwares, cur, list) {
-		if (!strcmp(dev, (const char *) cur->fwh->devname)) {
-			*version = ntohs(cur->fwh->version);
-			AST_LIST_UNLOCK(&firmwares);
-			return 1;
-		}
-	}
-	AST_LIST_UNLOCK(&firmwares);
-
-	return 0;
-}
-
-int iax_firmware_append(struct iax_ie_data *ied, const char *dev, unsigned int desc)
-{
-	int res = -1;
-	unsigned int bs = desc & 0xff;
-	unsigned int start = (desc >> 8) & 0xffffff;
-	unsigned int bytes;
-	struct iax_firmware *cur;
-
-	if (ast_strlen_zero((char *)dev) || !bs)
-		return -1;
-
-	start *= bs;
-
-	AST_LIST_LOCK(&firmwares);
-	AST_LIST_TRAVERSE(&firmwares, cur, list) {
-		if (strcmp(dev, (const char *) cur->fwh->devname))
-			continue;
-		iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
-		if (start < ntohl(cur->fwh->datalen)) {
-			bytes = ntohl(cur->fwh->datalen) - start;
-			if (bytes > bs)
-				bytes = bs;
-			iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);
-		} else {
-			bytes = 0;
-			iax_ie_append(ied, IAX_IE_FWBLOCKDATA);
-		}
-		if (bytes == bs)
-			res = 0;
-		else
-			res = 1;
-		break;
-	}
-	AST_LIST_UNLOCK(&firmwares);
-
-	return res;
-}
-
-void iax_firmware_traverse(
-	const char *filter,
-	int (*callback)(struct ast_iax2_firmware_header *header, void *data),
-	void *data)
-{
-	struct iax_firmware *cur = NULL;
-
-	if (!callback) {
-		return;
-	}
-
-	AST_LIST_LOCK(&firmwares);
-	AST_LIST_TRAVERSE(&firmwares, cur, list) {
-		if (!filter || !strcasecmp(filter, (const char *) cur->fwh->devname)) {
-			if (callback(cur->fwh, data)) {
-				break;
-			}
-		}
-	}
-	AST_LIST_UNLOCK(&firmwares);
-}
diff --git a/channels/iax2/format_compatibility.c b/channels/iax2/format_compatibility.c
deleted file mode 100644
index ee61516..0000000
--- a/channels/iax2/format_compatibility.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420364 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/format_compatibility.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/utils.h"
-
-#include "include/format_compatibility.h"
-
-uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap)
-{
-	uint64_t bitfield = 0;
-	int x;
-
-	for (x = 0; x < ast_format_cap_count(cap); x++) {
-		struct ast_format *format = ast_format_cap_get_format(cap, x);
-
-		bitfield |= ast_format_compatibility_format2bitfield(format);
-
-		ao2_ref(format, -1);
-	}
-
-	return bitfield;
-}
-
-int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap)
-{
-	int bit;
-
-	for (bit = 0; bit < 64; ++bit) {
-		uint64_t mask = (1ULL << bit);
-
-		if (mask & bitfield) {
-			struct ast_format *format;
-
-			format = ast_format_compatibility_bitfield2format(mask);
-			if (format && ast_format_cap_append(cap, format, 0)) {
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-uint64_t iax2_format_compatibility_best(uint64_t formats)
-{
-	/*
-	 * This just our opinion, expressed in code.  We are
-	 * asked to choose the best codec to use, given no
-	 * information.
-	 */
-	static const uint64_t best[] = {
-		/*! Okay, ulaw is used by all telephony equipment, so start with it */
-		AST_FORMAT_ULAW,
-		/*! Unless of course, you're a silly European, so then prefer ALAW */
-		AST_FORMAT_ALAW,
-		AST_FORMAT_G719,
-		AST_FORMAT_SIREN14,
-		AST_FORMAT_SIREN7,
-		AST_FORMAT_TESTLAW,
-		/*! G.722 is better then all below, but not as common as the above... so give ulaw and alaw priority */
-		AST_FORMAT_G722,
-		/*! Okay, well, signed linear is easy to translate into other stuff */
-		AST_FORMAT_SLIN16,
-		AST_FORMAT_SLIN,
-		/*! G.726 is standard ADPCM, in RFC3551 packing order */
-		AST_FORMAT_G726,
-		/*! G.726 is standard ADPCM, in AAL2 packing order */
-		AST_FORMAT_G726_AAL2,
-		/*! ADPCM has great sound quality and is still pretty easy to translate */
-		AST_FORMAT_ADPCM,
-		/*! Okay, we're down to vocoders now, so pick GSM because it's small and easier to
-		    translate and sounds pretty good */
-		AST_FORMAT_GSM,
-		/*! iLBC is not too bad */
-		AST_FORMAT_ILBC,
-		/*! Speex is free, but computationally more expensive than GSM */
-		AST_FORMAT_SPEEX16,
-		AST_FORMAT_SPEEX,
-		/*! Opus */
-		AST_FORMAT_OPUS,
-		/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
-		    to use it */
-		AST_FORMAT_LPC10,
-		/*! G.729a is faster than 723 and slightly less expensive */
-		AST_FORMAT_G729,
-		/*! Down to G.723.1 which is proprietary but at least designed for voice */
-		AST_FORMAT_G723,
-	};
-	int idx;
-
-	/* Find the first preferred codec in the format given */
-	for (idx = 0; idx < ARRAY_LEN(best); ++idx) {
-		if (formats & best[idx]) {
-			return best[idx];
-		}
-	}
-
-	return 0;
-}
diff --git a/channels/iax2/include/codec_pref.h b/channels/iax2/include/codec_pref.h
deleted file mode 100644
index 2af3692..0000000
--- a/channels/iax2/include/codec_pref.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _IAX2_CODEC_PREF_H_
-#define _IAX2_CODEC_PREF_H_
-
-struct ast_format;
-struct ast_codec;
-struct ast_format_cap;
-
-#define IAX2_CODEC_PREF_SIZE 64
-struct iax2_codec_pref {
-	/*! Array is ordered by preference.  Contains the iax2_supported_formats[] index + 1. */
-	char order[IAX2_CODEC_PREF_SIZE];
-	/*! Framing size of the codec */
-	unsigned int framing[IAX2_CODEC_PREF_SIZE];
-};
-
-/*!
- * \brief Convert an iax2_codec_pref order value into a format bitfield
- *
- * \param order_value value being converted
- *
- * \return the bitfield value of the order_value format
- */
-uint64_t iax2_codec_pref_order_value_to_format_bitfield(int order_value);
-
-/*!
- * \brief Convert a format bitfield into an iax2_codec_pref order value
- *
- * \param bitfield value being converted
- *
- * \return the iax2_codec_pref order value of the most significant format
- *  in the bitfield.
- *
- * \note This is really meant to be used on single format bitfields.
- *  It will work with multiformat bitfields, but it can only return the
- *  index of the most significant one if that is the case.
- */
-int iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield);
-
-/*!
- * \brief Codec located at a particular place in the preference index.
- * \param pref preference structure to get the codec out of
- * \param index to retrieve from
- * \param result ast_format structure to store the index value in
- * \return pointer to input ast_format on success, NULL on failure
-*/
-struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int index, struct ast_format **result);
-
-/*!
- * \brief Convert a preference structure to a capabilities structure.
- *
- * \param pref Formats in preference order to build the capabilities.
- * \param cap Capabilities structure to place formats into
- *
- * \retval 0 on success.
- * \retval -1 on error.
- *
- * \note If failure occurs the capabilities structure may contain a partial set of formats
- */
-int iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap);
-
-/*!
- * \brief Convert a bitfield to a format capabilities structure in the "best" order.
- *
- * \param bitfield The bitfield for the media formats
- * \param prefs Format preference order to use as a guide. (May be NULL)
- * \param cap Capabilities structure to place formats into
- *
- * \retval 0 on success.
- * \retval -1 on error.
- *
- * \note If failure occurs the capabilities structure may contain a partial set of formats
- */
-int iax2_codec_pref_best_bitfield2cap(uint64_t bitfield, struct iax2_codec_pref *prefs, struct ast_format_cap *cap);
-
-/*! \brief Removes format from the pref list that aren't in the bitfield */
-void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield);
-
-/*!
- * \brief Dump audio codec preference list into a string
- *
- * \param pref preference structure to dump string representation of order for
- * \param buf character buffer to put string into
- * \param size size of the character buffer
- *
- * \return -1 on error. Otherwise returns the remaining spaaaaaace in the buffer.
- *
- * \note Format is (codec1|codec2|codec3|...) -- if the list is too long for the
- *  size of the buffer, codecs will be written until they exceed the length
- *  remaining in which case the list will be closed with '...)' after the last
- *  writable codec.
- */
-int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size);
-
-/*! \brief Append a audio codec to a preference list, removing it first if it was already there
-*/
-void iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing);
-
-/*! \brief Prepend an audio codec to a preference list, removing it first if it was already there
-*/
-void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing,
-	int only_if_existing);
-
-/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string
- * \note Due to a misunderstanding in how codec preferences are stored, this
- * list starts at 'B', not 'A'.  For backwards compatibility reasons, this
- * cannot change.
- * \param pref A codec preference list structure
- * \param buf A string denoting codec preference, appropriate for use in line transmission
- * \param size Size of \a buf
- * \param right Boolean:  if 0, convert from \a buf to \a pref; if 1, convert from \a pref to \a buf.
- */
-void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right);
-
-/*!
- * \brief Create codec preference list from the given bitfield formats.
- * \since 13.0.0
- *
- * \param pref Codec preference list to setup from the given bitfield.
- * \param bitfield Format bitfield to guide preference list creation.
- *
- * \return Updated bitfield with any bits not mapped to a format cleared.
- */
-uint64_t iax2_codec_pref_from_bitfield(struct iax2_codec_pref *pref, uint64_t bitfield);
-
-#endif /* _IAX2_CODEC_PREF_H_ */
diff --git a/channels/iax2/include/firmware.h b/channels/iax2/include/firmware.h
deleted file mode 100644
index f8063b7..0000000
--- a/channels/iax2/include/firmware.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief IAX Firmware Support header file
- */
-
-#ifndef _IAX2_FIRMWARE_H
-#define _IAX2_FIRMWARE_H
-
-#include "parser.h"
-
-/*!
- * \internal
- * \brief Reload the list of available firmware.
- *
- * Searches the IAX firmware directory, adding new firmware that is available
- * and removing firmware that is no longer available.
- *
- * \return Nothing
- */
-void iax_firmware_reload(void);
-
-/*!
- * \internal
- * \brief Unload all of the currently loaded firmware.
- *
- * return Nothing
- */
-void iax_firmware_unload(void);
-
-/*!
- * \internal
- * \brief Determine the version number of the specified firmware.
- *
- * \param      device_name The device name of the firmware for which we want the
- *                         version.
- * \param[out] version     Pointer to a variable where the version number is
- *                         stored upon return.
- *
- * \retval 1 on success
- * \retval 0 on failure
- */
-int iax_firmware_get_version(const char *device_name,
-	uint16_t *version);
-
-/*!
- * \internal
- * \brief Add firwmare related IEs to an IAX2 IE buffer.
- *
- * \param ie_data     The IE buffer being appended to.
- * \param device_name The name of the requested firmware.
- * \param block_desc  The requested firmware block identification.
- *
- * Search the list of loaded firmware for \c device_name and, if found, add the
- * appropriate FWBLOCKDESC and FWBLOCKDATA IEs to the specified \c ie_data
- * list.
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-int iax_firmware_append(struct iax_ie_data *ie_data,
-	const char *device_name, unsigned int block_desc);
-
-/*!
- * \internal
- * \brief Iterate over the list of currently loaded IAX firmware.
- *
- * \param prefix    The prefix of the device to filter for, or \c NULL to visit
- *                  all firmware records.
- * \param callback  A pointer to a function to call for each firmware record
- *                  that is visited.
- * \param user_data A pointer to user supplied data that will be passed to the
- *                  \c callback function each time it is invoked.
- *
- * This function visits each of the elements in the IAX firmware list, calling
- * the specfied \c callback for each element. Iteration continues until the end
- * of the list is reached, or the \c callback returns non-zero.
- *
- * The \c callback function receives a pointer to the firmware header and the
- * value of the \c user_data argument that was passed in, which may be \c NULL.
- *
- * \return Nothing
- */
-void iax_firmware_traverse(const char *prefix,
-	int (*callback)(struct ast_iax2_firmware_header *header, void *user_data),
-	void *user_data);
-
-#endif
diff --git a/channels/iax2/include/format_compatibility.h b/channels/iax2/include/format_compatibility.h
deleted file mode 100644
index e3839fc..0000000
--- a/channels/iax2/include/format_compatibility.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _IAX2_FORMAT_COMPATIBILITY_H_
-#define _IAX2_FORMAT_COMPATIBILITY_H_
-
-struct ast_format;
-struct ast_format_cap;
-
-/*!
- * \brief Convert a format capabilities structure to a bitfield
- *
- * \param cap Capabilities structure containing formats
- *
- * \retval non-zero success
- * \retval zero no formats present or no formats supported
- */
-uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap);
-
-/*!
- * \brief Convert a bitfield to a format capabilities structure
- *
- * \param bitfield The bitfield for the media formats
- * \param cap Capabilities structure to place formats into
- *
- * \retval 0 on success.
- * \retval -1 on error.
- *
- * \note If failure occurs the capabilities structure may contain a partial set of formats
- */
-int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap);
-
-/*!
- * \brief Pick the best format from the given bitfield formats.
- *
- * \param formats The bitfield for the media formats
- *
- * \retval non-zero Best format out of the given formats.
- * \retval zero No formats present or no formats considered best.
- */
-uint64_t iax2_format_compatibility_best(uint64_t formats);
-
-#endif /* _IAX2_FORMAT_COMPATIBILITY_H */
diff --git a/channels/misdn/Makefile b/channels/misdn/Makefile
index 194bef5..96d5a2a 100644
--- a/channels/misdn/Makefile
+++ b/channels/misdn/Makefile
@@ -14,4 +14,4 @@ portinfo: portinfo.o
 	$(CC) -o $@ $^ -lisdnnet -lmISDN -lpthread
 
 clean:
-	rm -rf *.a *.o *.so portinfo *.i
+	rm -rf *.a *.o *.so portinfo *.i *.gcda *.gcno
diff --git a/channels/misdn/ie.c b/channels/misdn/ie.c
index 74ae897..df5df9a 100644
--- a/channels/misdn/ie.c
+++ b/channels/misdn/ie.c
@@ -293,7 +293,7 @@ static void enc_ie_call_id(unsigned char **ntmode, msg_t *msg, char *callid, int
 	i = 0;
 	while(i < callid_len)
 	{
-		if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
+		if (MISDN_IE_DEBG) printf(debug+(i*3), " %02hhx", (unsigned char)callid[i]);
 		i++;
 	}
 
@@ -339,7 +339,7 @@ static void dec_ie_call_id(unsigned char *p, Q931_info_t *qi, char *callid, int
 	i = 0;
 	while(i < *callid_len)
 	{
-		if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
+		if (MISDN_IE_DEBG) printf(debug+(i*3), " %02hhx", (unsigned char)callid[i]);
 		i++;
 	}
 
@@ -745,7 +745,7 @@ static void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive,
 			p[0] = IE_CHANNEL_ID;
 			p[1] = l;
 			p[2] = 0x80 + 0x20 + 0x03;
-/* 			if (MISDN_IE_DEBG) printf("%02x\n", p[2]); */
+/* 			if (MISDN_IE_DEBG) printf("%02hhx\n", p[2]); */
 			return; /* end */
 		}
 		l = 3;
@@ -759,7 +759,7 @@ static void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive,
 		p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
 		p[3] = 0x80 + 3; /* CCITT, Number, B-type */
 		p[4] = 0x80 + channel;
-/* 		if (MISDN_IE_DEBG) printf("%02x %02x %02x\n", p[2], p[3], p[4]); */
+/* 		if (MISDN_IE_DEBG) printf("%02hhx %02hhx %02hhx\n", p[2], p[3], p[4]); */
 	}
 }
 
@@ -849,7 +849,7 @@ static void dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive,
 			printf("%s: ERROR: PRI interface channel out of range (%d).\n", __FUNCTION__, *channel);
 			return;
 		}
-/* 		if (MISDN_IE_DEBG) printf("%02x %02x %02x\n", p[1], p[2], p[3]); */
+/* 		if (MISDN_IE_DEBG) printf("%02hhx %02hhx %02hhx\n", p[1], p[2], p[3]); */
 	}
 
 	if (MISDN_IE_DEBG) printf("    exclusive=%d channel=%d\n", *exclusive, *channel);
@@ -1342,7 +1342,7 @@ static void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, ch
 		char debug[768];
 
 		for (i = 0; i < user_len; ++i) {
-			sprintf(debug + (i * 3), " %02x", user[i]);
+			sprintf(debug + (i * 3), " %02hhx", (unsigned char)user[i]);
 		}
 		debug[i * 3] = 0;
 		printf("    protocol=%d user-user%s\n", protocol, debug);
@@ -1387,7 +1387,7 @@ static void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, ch
 		char debug[768];
 
 		for (i = 0; i < *user_len; ++i) {
-			sprintf(debug + (i * 3), " %02x", user[i]);
+			sprintf(debug + (i * 3), " %02hhx", (unsigned char)user[i]);
 		}
 		debug[i * 3] = 0;
 		printf("    protocol=%d user-user%s\n", *protocol, debug);
diff --git a/channels/misdn_config.c b/channels/misdn_config.c
index d77cd34..32f92c3 100644
--- a/channels/misdn_config.c
+++ b/channels/misdn_config.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370831 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "chan_misdn_config.h"
 
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
deleted file mode 100644
index 91129a4..0000000
--- a/channels/pjsip/dialplan_functions.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \author \verbatim Joshua Colp <jcolp at digium.com> \endverbatim
- * \author \verbatim Matt Jordan <mjordan at digium.com> \endverbatim
- *
- * \ingroup functions
- *
- * \brief PJSIP channel dialplan functions
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-<function name="PJSIP_DIAL_CONTACTS" language="en_US">
-	<synopsis>
-		Return a dial string for dialing all contacts on an AOR.
-	</synopsis>
-	<syntax>
-		<parameter name="endpoint" required="true">
-			<para>Name of the endpoint</para>
-		</parameter>
-		<parameter name="aor" required="false">
-			<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
-		</parameter>
-		<parameter name="request_user" required="false">
-			<para>Optional request user to use in the request URI</para>
-		</parameter>
-	</syntax>
-	<description>
-		<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
-	</description>
-</function>
-<function name="PJSIP_MEDIA_OFFER" language="en_US">
-	<synopsis>
-		Media and codec offerings to be set on an outbound SIP channel prior to dialing.
-	</synopsis>
-	<syntax>
-		<parameter name="media" required="true">
-			<para>types of media offered</para>
-		</parameter>
-	</syntax>
-	<description>
-		<para>Returns the codecs offered based upon the media choice</para>
-	</description>
-</function>
-<info name="PJSIPCHANNEL" language="en_US" tech="PJSIP">
-	<enumlist>
-		<enum name="rtp">
-			<para>R/O Retrieve media related information.</para>
-			<parameter name="type" required="true">
-				<para>When <replaceable>rtp</replaceable> is specified, the
-				<literal>type</literal> parameter must be provided. It specifies
-				which RTP parameter to read.</para>
-				<enumlist>
-					<enum name="src">
-						<para>Retrieve the local address for RTP.</para>
-					</enum>
-					<enum name="dest">
-						<para>Retrieve the remote address for RTP.</para>
-					</enum>
-					<enum name="direct">
-						<para>If direct media is enabled, this address is the remote address
-						used for RTP.</para>
-					</enum>
-					<enum name="secure">
-						<para>Whether or not the media stream is encrypted.</para>
-						<enumlist>
-							<enum name="0">
-								<para>The media stream is not encrypted.</para>
-							</enum>
-							<enum name="1">
-								<para>The media stream is encrypted.</para>
-							</enum>
-						</enumlist>
-					</enum>
-					<enum name="hold">
-						<para>Whether or not the media stream is currently restricted
-						due to a call hold.</para>
-						<enumlist>
-							<enum name="0">
-								<para>The media stream is not held.</para>
-							</enum>
-							<enum name="1">
-								<para>The media stream is held.</para>
-							</enum>
-						</enumlist>
-					</enum>
-				</enumlist>
-			</parameter>
-			<parameter name="media_type" required="false">
-				<para>When <replaceable>rtp</replaceable> is specified, the
-				<literal>media_type</literal> parameter may be provided. It specifies
-				which media stream the chosen RTP parameter should be retrieved
-				from.</para>
-				<enumlist>
-					<enum name="audio">
-						<para>Retrieve information from the audio media stream.</para>
-						<note><para>If not specified, <literal>audio</literal> is used
-						by default.</para></note>
-					</enum>
-					<enum name="video">
-						<para>Retrieve information from the video media stream.</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</enum>
-		<enum name="rtcp">
-			<para>R/O Retrieve RTCP statistics.</para>
-			<parameter name="statistic" required="true">
-				<para>When <replaceable>rtcp</replaceable> is specified, the
-				<literal>statistic</literal> parameter must be provided. It specifies
-				which RTCP statistic parameter to read.</para>
-				<enumlist>
-					<enum name="all">
-						<para>Retrieve a summary of all RTCP statistics.</para>
-						<para>The following data items are returned in a semi-colon
-						delineated list:</para>
-						<enumlist>
-							<enum name="ssrc">
-								<para>Our Synchronization Source identifier</para>
-							</enum>
-							<enum name="themssrc">
-								<para>Their Synchronization Source identifier</para>
-							</enum>
-							<enum name="lp">
-								<para>Our lost packet count</para>
-							</enum>
-							<enum name="rxjitter">
-								<para>Received packet jitter</para>
-							</enum>
-							<enum name="rxcount">
-								<para>Received packet count</para>
-							</enum>
-							<enum name="txjitter">
-								<para>Transmitted packet jitter</para>
-							</enum>
-							<enum name="txcount">
-								<para>Transmitted packet count</para>
-							</enum>
-							<enum name="rlp">
-								<para>Remote lost packet count</para>
-							</enum>
-							<enum name="rtt">
-								<para>Round trip time</para>
-							</enum>
-						</enumlist>
-					</enum>
-					<enum name="all_jitter">
-						<para>Retrieve a summary of all RTCP Jitter statistics.</para>
-						<para>The following data items are returned in a semi-colon
-						delineated list:</para>
-						<enumlist>
-							<enum name="minrxjitter">
-								<para>Our minimum jitter</para>
-							</enum>
-							<enum name="maxrxjitter">
-								<para>Our max jitter</para>
-							</enum>
-							<enum name="avgrxjitter">
-								<para>Our average jitter</para>
-							</enum>
-							<enum name="stdevrxjitter">
-								<para>Our jitter standard deviation</para>
-							</enum>
-							<enum name="reported_minjitter">
-								<para>Their minimum jitter</para>
-							</enum>
-							<enum name="reported_maxjitter">
-								<para>Their max jitter</para>
-							</enum>
-							<enum name="reported_avgjitter">
-								<para>Their average jitter</para>
-							</enum>
-							<enum name="reported_stdevjitter">
-								<para>Their jitter standard deviation</para>
-							</enum>
-						</enumlist>
-					</enum>
-					<enum name="all_loss">
-						<para>Retrieve a summary of all RTCP packet loss statistics.</para>
-						<para>The following data items are returned in a semi-colon
-						delineated list:</para>
-						<enumlist>
-							<enum name="minrxlost">
-								<para>Our minimum lost packets</para>
-							</enum>
-							<enum name="maxrxlost">
-								<para>Our max lost packets</para>
-							</enum>
-							<enum name="avgrxlost">
-								<para>Our average lost packets</para>
-							</enum>
-							<enum name="stdevrxlost">
-								<para>Our lost packets standard deviation</para>
-							</enum>
-							<enum name="reported_minlost">
-								<para>Their minimum lost packets</para>
-							</enum>
-							<enum name="reported_maxlost">
-								<para>Their max lost packets</para>
-							</enum>
-							<enum name="reported_avglost">
-								<para>Their average lost packets</para>
-							</enum>
-							<enum name="reported_stdevlost">
-								<para>Their lost packets standard deviation</para>
-							</enum>
-						</enumlist>
-					</enum>
-					<enum name="all_rtt">
-						<para>Retrieve a summary of all RTCP round trip time information.</para>
-						<para>The following data items are returned in a semi-colon
-						delineated list:</para>
-						<enumlist>
-							<enum name="minrtt">
-								<para>Minimum round trip time</para>
-							</enum>
-							<enum name="maxrtt">
-								<para>Maximum round trip time</para>
-							</enum>
-							<enum name="avgrtt">
-								<para>Average round trip time</para>
-							</enum>
-							<enum name="stdevrtt">
-								<para>Standard deviation round trip time</para>
-							</enum>
-						</enumlist>
-					</enum>
-					<enum name="txcount"><para>Transmitted packet count</para></enum>
-					<enum name="rxcount"><para>Received packet count</para></enum>
-					<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
-					<enum name="rxjitter"><para>Received packet jitter</para></enum>
-					<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
-					<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
-					<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
-					<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
-					<enum name="local_maxjitter"><para>Our max jitter</para></enum>
-					<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
-					<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
-					<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
-					<enum name="txploss"><para>Transmitted packet loss</para></enum>
-					<enum name="rxploss"><para>Received packet loss</para></enum>
-					<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
-					<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
-					<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
-					<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
-					<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
-					<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
-					<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
-					<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
-					<enum name="rtt"><para>Round trip time</para></enum>
-					<enum name="maxrtt"><para>Maximum round trip time</para></enum>
-					<enum name="minrtt"><para>Minimum round trip time</para></enum>
-					<enum name="normdevrtt"><para>Average round trip time</para></enum>
-					<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
-					<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
-					<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
-				</enumlist>
-			</parameter>
-			<parameter name="media_type" required="false">
-				<para>When <replaceable>rtcp</replaceable> is specified, the
-				<literal>media_type</literal> parameter may be provided. It specifies
-				which media stream the chosen RTCP parameter should be retrieved
-				from.</para>
-				<enumlist>
-					<enum name="audio">
-						<para>Retrieve information from the audio media stream.</para>
-						<note><para>If not specified, <literal>audio</literal> is used
-						by default.</para></note>
-					</enum>
-					<enum name="video">
-						<para>Retrieve information from the video media stream.</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</enum>
-		<enum name="endpoint">
-			<para>R/O The name of the endpoint associated with this channel.
-			Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
-			further endpoint related information.</para>
-		</enum>
-		<enum name="pjsip">
-			<para>R/O Obtain information about the current PJSIP channel and its
-			session.</para>
-			<parameter name="type" required="true">
-				<para>When <replaceable>pjsip</replaceable> is specified, the
-				<literal>type</literal> parameter must be provided. It specifies
-				which signalling parameter to read.</para>
-				<enumlist>
-					<enum name="secure">
-						<para>Whether or not the signalling uses a secure transport.</para>
-						<enumlist>
-							<enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
-							<enum name="1"><para>The signalling uses a secure transport.</para></enum>
-						</enumlist>
-					</enum>
-					<enum name="target_uri">
-						<para>The request URI of the <literal>INVITE</literal> request associated with the creation of this channel.</para>
-					</enum>
-					<enum name="local_uri">
-						<para>The local URI.</para>
-					</enum>
-					<enum name="remote_uri">
-						<para>The remote URI.</para>
-					</enum>
-					<enum name="t38state">
-						<para>The current state of any T.38 fax on this channel.</para>
-						<enumlist>
-							<enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
-							<enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
-							<enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
-							<enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
-							<enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
-						</enumlist>
-					</enum>
-					<enum name="local_addr">
-						<para>On inbound calls, the full IP address and port number that
-						the <literal>INVITE</literal> request was received on. On outbound
-						calls, the full IP address and port number that the <literal>INVITE</literal>
-						request was transmitted from.</para>
-					</enum>
-					<enum name="remote_addr">
-						<para>On inbound calls, the full IP address and port number that
-						the <literal>INVITE</literal> request was received from. On outbound
-						calls, the full IP address and port number that the <literal>INVITE</literal>
-						request was transmitted to.</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</enum>
-	</enumlist>
-</info>
-***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-#include <pjsip_ua.h>
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424622 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/acl.h"
-#include "asterisk/app.h"
-#include "asterisk/channel.h"
-#include "asterisk/format.h"
-#include "asterisk/pbx.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "include/chan_pjsip.h"
-#include "include/dialplan_functions.h"
-
-/*!
- * \brief String representations of the T.38 state enum
- */
-static const char *t38state_to_string[T38_MAX_ENUM] = {
-	[T38_DISABLED] = "DISABLED",
-	[T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
-	[T38_PEER_REINVITE] = "REMOTE_REINVITE",
-	[T38_ENABLED] = "ENABLED",
-	[T38_REJECTED] = "REJECTED",
-};
-
-/*!
- * \internal \brief Handle reading RTP information
- */
-static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt;
-	struct ast_sip_session_media *media = NULL;
-	struct ast_sockaddr addr;
-
-	if (!channel) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	pvt = channel->pvt;
-	if (!pvt) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	if (ast_strlen_zero(type)) {
-		ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
-		media = pvt->media[SIP_MEDIA_AUDIO];
-	} else if (!strcmp(field, "video")) {
-		media = pvt->media[SIP_MEDIA_VIDEO];
-	} else {
-		ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
-		return -1;
-	}
-
-	if (!media || !media->rtp) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
-			ast_channel_name(chan), S_OR(field, "audio"));
-		return -1;
-	}
-
-	if (!strcmp(type, "src")) {
-		ast_rtp_instance_get_local_address(media->rtp, &addr);
-		ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
-	} else if (!strcmp(type, "dest")) {
-		ast_rtp_instance_get_remote_address(media->rtp, &addr);
-		ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
-	} else if (!strcmp(type, "direct")) {
-		ast_copy_string(buf, ast_sockaddr_stringify(&media->direct_media_addr), buflen);
-	} else if (!strcmp(type, "secure")) {
-		snprintf(buf, buflen, "%d", media->srtp ? 1 : 0);
-	} else if (!strcmp(type, "hold")) {
-		snprintf(buf, buflen, "%d", media->held ? 1 : 0);
-	} else {
-		ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal \brief Handle reading RTCP information
- */
-static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	struct chan_pjsip_pvt *pvt;
-	struct ast_sip_session_media *media = NULL;
-
-	if (!channel) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	pvt = channel->pvt;
-	if (!pvt) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	if (ast_strlen_zero(type)) {
-		ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
-		media = pvt->media[SIP_MEDIA_AUDIO];
-	} else if (!strcmp(field, "video")) {
-		media = pvt->media[SIP_MEDIA_VIDEO];
-	} else {
-		ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
-		return -1;
-	}
-
-	if (!media || !media->rtp) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
-			ast_channel_name(chan), S_OR(field, "audio"));
-		return -1;
-	}
-
-	if (!strncasecmp(type, "all", 3)) {
-		enum ast_rtp_instance_stat_field stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY;
-
-		if (!strcasecmp(type, "all_jitter")) {
-			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER;
-		} else if (!strcasecmp(type, "all_rtt")) {
-			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
-		} else if (!strcasecmp(type, "all_loss")) {
-			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
-		}
-
-		if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
-			ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
-			return -1;
-		}
-	} else {
-		struct ast_rtp_instance_stats stats;
-		int i;
-		struct {
-			const char *name;
-			enum { INT, DBL } type;
-			union {
-				unsigned int *i4;
-				double *d8;
-			};
-		} lookup[] = {
-			{ "txcount",               INT, { .i4 = &stats.txcount, }, },
-			{ "rxcount",               INT, { .i4 = &stats.rxcount, }, },
-			{ "txjitter",              DBL, { .d8 = &stats.txjitter, }, },
-			{ "rxjitter",              DBL, { .d8 = &stats.rxjitter, }, },
-			{ "remote_maxjitter",      DBL, { .d8 = &stats.remote_maxjitter, }, },
-			{ "remote_minjitter",      DBL, { .d8 = &stats.remote_minjitter, }, },
-			{ "remote_normdevjitter",  DBL, { .d8 = &stats.remote_normdevjitter, }, },
-			{ "remote_stdevjitter",    DBL, { .d8 = &stats.remote_stdevjitter, }, },
-			{ "local_maxjitter",       DBL, { .d8 = &stats.local_maxjitter, }, },
-			{ "local_minjitter",       DBL, { .d8 = &stats.local_minjitter, }, },
-			{ "local_normdevjitter",   DBL, { .d8 = &stats.local_normdevjitter, }, },
-			{ "local_stdevjitter",     DBL, { .d8 = &stats.local_stdevjitter, }, },
-			{ "txploss",               INT, { .i4 = &stats.txploss, }, },
-			{ "rxploss",               INT, { .i4 = &stats.rxploss, }, },
-			{ "remote_maxrxploss",     DBL, { .d8 = &stats.remote_maxrxploss, }, },
-			{ "remote_minrxploss",     DBL, { .d8 = &stats.remote_minrxploss, }, },
-			{ "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
-			{ "remote_stdevrxploss",   DBL, { .d8 = &stats.remote_stdevrxploss, }, },
-			{ "local_maxrxploss",      DBL, { .d8 = &stats.local_maxrxploss, }, },
-			{ "local_minrxploss",      DBL, { .d8 = &stats.local_minrxploss, }, },
-			{ "local_normdevrxploss",  DBL, { .d8 = &stats.local_normdevrxploss, }, },
-			{ "local_stdevrxploss",    DBL, { .d8 = &stats.local_stdevrxploss, }, },
-			{ "rtt",                   DBL, { .d8 = &stats.rtt, }, },
-			{ "maxrtt",                DBL, { .d8 = &stats.maxrtt, }, },
-			{ "minrtt",                DBL, { .d8 = &stats.minrtt, }, },
-			{ "normdevrtt",            DBL, { .d8 = &stats.normdevrtt, }, },
-			{ "stdevrtt",              DBL, { .d8 = &stats.stdevrtt, }, },
-			{ "local_ssrc",            INT, { .i4 = &stats.local_ssrc, }, },
-			{ "remote_ssrc",           INT, { .i4 = &stats.remote_ssrc, }, },
-			{ NULL, },
-		};
-
-		if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
-			ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
-			return -1;
-		}
-
-		for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
-			if (!strcasecmp(type, lookup[i].name)) {
-				if (lookup[i].type == INT) {
-					snprintf(buf, buflen, "%u", *lookup[i].i4);
-				} else {
-					snprintf(buf, buflen, "%f", *lookup[i].d8);
-				}
-				return 0;
-			}
-		}
-		ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal \brief Handle reading signalling information
- */
-static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-	char *buf_copy;
-	pjsip_dialog *dlg;
-
-	if (!channel) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	dlg = channel->session->inv_session->dlg;
-
-	if (!strcmp(type, "secure")) {
-		snprintf(buf, buflen, "%d", dlg->secure ? 1 : 0);
-	} else if (!strcmp(type, "target_uri")) {
-		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen);
-		buf_copy = ast_strdupa(buf);
-		ast_escape_quoted(buf_copy, buf, buflen);
-	} else if (!strcmp(type, "local_uri")) {
-		pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, buf, buflen);
-		buf_copy = ast_strdupa(buf);
-		ast_escape_quoted(buf_copy, buf, buflen);
-	} else if (!strcmp(type, "remote_uri")) {
-		pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, buf, buflen);
-		buf_copy = ast_strdupa(buf);
-		ast_escape_quoted(buf_copy, buf, buflen);
-	} else if (!strcmp(type, "t38state")) {
-		ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen);
-	} else if (!strcmp(type, "local_addr")) {
-		RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-		struct transport_info_data *transport_data;
-
-		datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
-		if (!datastore) {
-			ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
-			return -1;
-		}
-		transport_data = datastore->data;
-
-		if (pj_sockaddr_has_addr(&transport_data->local_addr)) {
-			pj_sockaddr_print(&transport_data->local_addr, buf, buflen, 3);
-		}
-	} else if (!strcmp(type, "remote_addr")) {
-		RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-		struct transport_info_data *transport_data;
-
-		datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
-		if (!datastore) {
-			ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
-			return -1;
-		}
-		transport_data = datastore->data;
-
-		if (pj_sockaddr_has_addr(&transport_data->remote_addr)) {
-			pj_sockaddr_print(&transport_data->remote_addr, buf, buflen, 3);
-		}
-	} else {
-		ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Struct used to push function arguments to task processor */
-struct pjsip_func_args {
-	struct ast_channel *chan;
-	const char *param;
-	const char *type;
-	const char *field;
-	char *buf;
-	size_t len;
-	int ret;
-};
-
-/*! \internal \brief Taskprocessor callback that handles the read on a PJSIP thread */
-static int read_pjsip(void *data)
-{
-	struct pjsip_func_args *func_args = data;
-
-	if (!strcmp(func_args->param, "rtp")) {
-		func_args->ret = channel_read_rtp(func_args->chan, func_args->type,
-		                                  func_args->field, func_args->buf,
-		                                  func_args->len);
-	} else if (!strcmp(func_args->param, "rtcp")) {
-		func_args->ret = channel_read_rtcp(func_args->chan, func_args->type,
-		                                   func_args->field, func_args->buf,
-		                                   func_args->len);
-	} else if (!strcmp(func_args->param, "endpoint")) {
-		struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
-
-		if (!pvt) {
-			ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
-			return -1;
-		}
-		if (!pvt->session || !pvt->session->endpoint) {
-			ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->chan));
-			return -1;
-		}
-		snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->endpoint));
-	} else if (!strcmp(func_args->param, "pjsip")) {
-		func_args->ret = channel_read_pjsip(func_args->chan, func_args->type,
-		                                    func_args->field, func_args->buf,
-		                                    func_args->len);
-	} else {
-		func_args->ret = -1;
-	}
-
-	return 0;
-}
-
-
-int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	struct pjsip_func_args func_args = { 0, };
-	struct ast_sip_channel_pvt *channel;
-	char *parse = ast_strdupa(data);
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(param);
-		AST_APP_ARG(type);
-		AST_APP_ARG(field);
-	);
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-	channel = ast_channel_tech_pvt(chan);
-
-	/* Check for zero arguments */
-	if (ast_strlen_zero(parse)) {
-		ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	/* Sanity check */
-	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
-		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
-		return 0;
-	}
-
-	if (!channel) {
-		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	memset(buf, 0, len);
-
-	func_args.chan = chan;
-	func_args.param = args.param;
-	func_args.type = args.type;
-	func_args.field = args.field;
-	func_args.buf = buf;
-	func_args.len = len;
-	if (ast_sip_push_task_synchronous(channel->session->serializer, read_pjsip, &func_args)) {
-		ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	return func_args.ret;
-}
-
-int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
-	const char *aor_name;
-	char *rest;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(endpoint_name);
-		AST_APP_ARG(aor_name);
-		AST_APP_ARG(request_user);
-	);
-
-	AST_STANDARD_APP_ARGS(args, data);
-
-	if (ast_strlen_zero(args.endpoint_name)) {
-		ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
-		return -1;
-	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
-		ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
-		return -1;
-	}
-
-	aor_name = S_OR(args.aor_name, endpoint->aors);
-
-	if (ast_strlen_zero(aor_name)) {
-		ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
-		return -1;
-	} else if (!(dial = ast_str_create(len))) {
-		ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
-		return -1;
-	} else if (!(rest = ast_strdupa(aor_name))) {
-		ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
-		return -1;
-	}
-
-	while ((aor_name = strsep(&rest, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-		struct ao2_iterator it_contacts;
-		struct ast_sip_contact *contact;
-
-		if (!aor) {
-			/* If the AOR provided is not found skip it, there may be more */
-			continue;
-		} else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
-			/* No contacts are available, skip it as well */
-			continue;
-		} else if (!ao2_container_count(contacts)) {
-			/* We were given a container but no contacts are in it... */
-			continue;
-		}
-
-		it_contacts = ao2_iterator_init(contacts, 0);
-		for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
-			ast_str_append(&dial, -1, "PJSIP/");
-
-			if (!ast_strlen_zero(args.request_user)) {
-				ast_str_append(&dial, -1, "%s@", args.request_user);
-			}
-			ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
-		}
-		ao2_iterator_destroy(&it_contacts);
-	}
-
-	/* Trim the '&' at the end off */
-	ast_str_truncate(dial, ast_str_strlen(dial) - 1);
-
-	ast_copy_string(buf, ast_str_buffer(dial), len);
-
-	return 0;
-}
-
-static int media_offer_read_av(struct ast_sip_session *session, char *buf,
-			       size_t len, enum ast_media_type media_type)
-{
-	int i, size = 0;
-
-	for (i = 0; i < ast_format_cap_count(session->req_caps); i++) {
-		struct ast_format *fmt = ast_format_cap_get_format(session->req_caps, i);
-
-		if (ast_format_get_type(fmt) != media_type) {
-			ao2_ref(fmt, -1);
-			continue;
-		}
-
-		/* add one since we'll include a comma */
-		size = strlen(ast_format_get_name(fmt)) + 1;
-		len -= size;
-		if ((len) < 0) {
-			ao2_ref(fmt, -1);
-			break;
-		}
-
-		/* no reason to use strncat here since we have already ensured buf has
-                   enough space, so strcat can be safely used */
-		strcat(buf, ast_format_get_name(fmt));
-		strcat(buf, ",");
-
-		ao2_ref(fmt, -1);
-	}
-
-	if (size) {
-		/* remove the extra comma */
-		buf[strlen(buf) - 1] = '\0';
-	}
-	return 0;
-}
-
-struct media_offer_data {
-	struct ast_sip_session *session;
-	enum ast_media_type media_type;
-	const char *value;
-};
-
-static int media_offer_write_av(void *obj)
-{
-	struct media_offer_data *data = obj;
-
-	ast_format_cap_remove_by_type(data->session->req_caps, data->media_type);
-	ast_format_cap_update_by_allow_disallow(data->session->req_caps, data->value, 1);
-
-	return 0;
-}
-
-int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	struct ast_sip_channel_pvt *channel;
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
-		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
-		return -1;
-	}
-
-	channel = ast_channel_tech_pvt(chan);
-
-	if (!strcmp(data, "audio")) {
-		return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_AUDIO);
-	} else if (!strcmp(data, "video")) {
-		return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_VIDEO);
-	}
-
-	return 0;
-}
-
-int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
-{
-	struct ast_sip_channel_pvt *channel;
-	struct media_offer_data mdata = {
-		.value = value
-	};
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
-		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
-		return -1;
-	}
-
-	channel = ast_channel_tech_pvt(chan);
-	mdata.session = channel->session;
-
-	if (!strcmp(data, "audio")) {
-		mdata.media_type = AST_MEDIA_TYPE_AUDIO;
-	} else if (!strcmp(data, "video")) {
-		mdata.media_type = AST_MEDIA_TYPE_VIDEO;
-	}
-
-	return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);
-}
diff --git a/channels/pjsip/include/chan_pjsip.h b/channels/pjsip/include/chan_pjsip.h
deleted file mode 100644
index b229a04..0000000
--- a/channels/pjsip/include/chan_pjsip.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief PJSIP Channel Driver shared data structures
- */
-
-#ifndef _CHAN_PJSIP_HEADER
-#define _CHAN_PJSIP_HEADER
-
-struct ast_sip_session_media;
-
-/*!
- * \brief Transport information stored in transport_info datastore
- */
-struct transport_info_data {
-	/*! \brief The address that sent the request */
-	pj_sockaddr remote_addr;
-	/*! \brief Our address that received the request */
-	pj_sockaddr local_addr;
-};
-
-/*!
- * \brief Positions of various media
- */
-enum sip_session_media_position {
-	/*! \brief First is audio */
-	SIP_MEDIA_AUDIO = 0,
-	/*! \brief Second is video */
-	SIP_MEDIA_VIDEO,
-	/*! \brief Last is the size for media details */
-	SIP_MEDIA_SIZE,
-};
-
-/*!
- * \brief The PJSIP channel driver pvt, stored in the \ref ast_sip_channel_pvt
- * data structure
- */
-struct chan_pjsip_pvt {
-	/*! \brief The available media sessions */
-	struct ast_sip_session_media *media[SIP_MEDIA_SIZE];
-};
-
-#endif /* _CHAN_PJSIP_HEADER */
diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h
deleted file mode 100644
index cbc06f0..0000000
--- a/channels/pjsip/include/dialplan_functions.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief PJSIP dialplan functions header file
- */
-
-#ifndef _PJSIP_DIALPLAN_FUNCTIONS
-#define _PJSIP_DIALPLAN_FUNCTIONS
-
-/*!
- * \brief CHANNEL function read callback
- * \param chan The channel the function is called on
- * \param cmd The name of the function
- * \param data Arguments passed to the function
- * \param buf Out buffer that should be populated with the data
- * \param len Size of the buffer
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
-
-/*!
- * \brief PJSIP_MEDIA_OFFER function write callback
- * \param chan The channel the function is called on
- * \param cmd The name of the function
- * \param data Arguments passed to the function
- * \param value Value to be set by the function
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
-
-/*!
- * \brief PJSIP_MEDIA_OFFER function read callback
- * \param chan The channel the function is called on
- * \param cmd The name of the function
- * \param data Arguments passed to the function
- * \param buf Out buffer that should be populated with the data
- * \param len Size of the buffer
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
-
-/*!
- * \brief PJSIP_DIAL_CONTACTS function read callback
- * \param chan The channel the function is called on
- * \param cmd The name of the function
- * \param data Arguments passed to the function
- * \param buf Out buffer that should be populated with the data
- * \param len Size of the buffer
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
-
-#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
\ No newline at end of file
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 140f509..2a87e1f 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -34,7 +34,6 @@
 
 #include "asterisk/utils.h"
 #include "asterisk/options.h"
-#include "asterisk/pickup.h"
 #include "asterisk/pbx.h"
 #include "asterisk/file.h"
 #include "asterisk/callerid.h"
@@ -42,10 +41,8 @@
 #include "asterisk/manager.h"
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
+#include "asterisk/cel.h"
 #include "asterisk/causes.h"
-#include "asterisk/features_config.h"
-#include "asterisk/bridge.h"
-#include "asterisk/parking.h"
 
 #include "sig_analog.h"
 
@@ -690,6 +687,7 @@ static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
  * \brief Attempt to transfer 3-way call.
  *
  * \param p Analog private structure.
+ * \param inthreeway TRUE if the 3-way call is conferenced.
  *
  * \note On entry these locks are held: real-call, private, 3-way call.
  * \note On exit these locks are held: real-call, private.
@@ -697,37 +695,72 @@ static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
  * \retval 0 on success.
  * \retval -1 on error.
  */
-static int analog_attempt_transfer(struct analog_pvt *p)
+static int analog_attempt_transfer(struct analog_pvt *p, int inthreeway)
 {
 	struct ast_channel *owner_real;
 	struct ast_channel *owner_3way;
-	enum ast_transfer_result xfer_res;
-	int res = 0;
-
-	owner_real = ast_channel_ref(p->subs[ANALOG_SUB_REAL].owner);
-	owner_3way = ast_channel_ref(p->subs[ANALOG_SUB_THREEWAY].owner);
-
-	ast_verb(3, "TRANSFERRING %s to %s\n",
-		ast_channel_name(owner_3way), ast_channel_name(owner_real));
+	struct ast_channel *bridge_real;
+	struct ast_channel *bridge_3way;
+	int ret = 0;
+
+	owner_real = p->subs[ANALOG_SUB_REAL].owner;
+	owner_3way = p->subs[ANALOG_SUB_THREEWAY].owner;
+	bridge_real = ast_bridged_channel(owner_real);
+	bridge_3way = ast_bridged_channel(owner_3way);
+
+	/*
+	 * In order to transfer, we need at least one of the channels to
+	 * actually be in a call bridge.  We can't conference two
+	 * applications together.  Why would we want to?
+	 */
+	if (bridge_3way) {
+		ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(owner_3way), ast_channel_name(owner_real));
+		ast_cel_report_event(owner_3way,
+			(ast_channel_state(owner_real) == AST_STATE_RINGING
+				|| ast_channel_state(owner_3way) == AST_STATE_RINGING)
+				? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
+			NULL, ast_channel_linkedid(owner_3way), NULL);
 
-	ast_channel_unlock(owner_real);
-	ast_channel_unlock(owner_3way);
-	analog_unlock_private(p);
+		/*
+		 * The three-way party we're about to transfer is on hold if he
+		 * is not in a three way conference.
+		 */
+		if (ast_channel_transfer_masquerade(owner_real, ast_channel_connected(owner_real), 0,
+			bridge_3way, ast_channel_connected(owner_3way), !inthreeway)) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+				ast_channel_name(bridge_3way), ast_channel_name(owner_real));
+			ret = -1;
+		}
+	} else if (bridge_real) {
+		/* Try transferring the other way. */
+		ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(owner_real), ast_channel_name(owner_3way));
+		ast_cel_report_event(owner_3way,
+			(ast_channel_state(owner_real) == AST_STATE_RINGING
+				|| ast_channel_state(owner_3way) == AST_STATE_RINGING)
+				? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
+			NULL, ast_channel_linkedid(owner_3way), NULL);
 
-	xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
-	if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
-		ast_softhangup(owner_3way, AST_SOFTHANGUP_DEV);
-		res = -1;
+		/*
+		 * The three-way party we're about to transfer is on hold if he
+		 * is not in a three way conference.
+		 */
+		if (ast_channel_transfer_masquerade(owner_3way, ast_channel_connected(owner_3way),
+			!inthreeway, bridge_real, ast_channel_connected(owner_real), 0)) {
+			ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+				ast_channel_name(bridge_real), ast_channel_name(owner_3way));
+			ret = -1;
+		}
+	} else {
+		ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+			ast_channel_name(owner_real), ast_channel_name(owner_3way));
+		ret = -1;
 	}
 
-	/* Must leave with these locked. */
-	ast_channel_lock(owner_real);
-	analog_lock_private(p);
-
-	ast_channel_unref(owner_real);
-	ast_channel_unref(owner_3way);
-
-	return res;
+	if (ret) {
+		ast_softhangup_nolock(owner_3way, AST_SOFTHANGUP_DEV);
+	}
+	ast_channel_unlock(owner_3way);
+	return ret;
 }
 
 static int analog_update_conf(struct analog_pvt *p)
@@ -1217,7 +1250,10 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest
 		analog_set_waitingfordt(p, ast);
 		if (!res) {
 			if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
+				int saveerr = errno;
+
 				analog_on_hook(p);
+				ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
 				return -1;
 			}
 		} else {
@@ -1314,7 +1350,9 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
 				if (ast_channel_state(p->owner) != AST_STATE_UP) {
 					ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
 				}
-				ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
+				if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
+					ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+				}
 				/* Unlock the call-waiting call that we swapped to real-call. */
 				ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);
 			} else if (p->subs[ANALOG_SUB_THREEWAY].allocd) {
@@ -1341,8 +1379,10 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
 
 				/* This is actually part of a three way, placed on hold.  Place the third part
 				   on music on hold now */
-				if (p->subs[ANALOG_SUB_THREEWAY].owner) {
-					ast_queue_hold(p->subs[ANALOG_SUB_THREEWAY].owner, p->mohsuggest);
+				if (p->subs[ANALOG_SUB_THREEWAY].owner && ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+					ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
 				analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
 				/* Make it the call wait now */
@@ -1363,8 +1403,10 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
 				/* The other party of the three way call is currently in a call-wait state.
 				   Start music on hold for them, and take the main guy out of the third call */
 				analog_set_inthreeway(p, ANALOG_SUB_CALLWAIT, 0);
-				if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
-					ast_queue_hold(p->subs[ANALOG_SUB_CALLWAIT].owner, p->mohsuggest);
+				if (p->subs[ANALOG_SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
+					ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
 			}
 			if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
@@ -1636,6 +1678,9 @@ static void analog_decrease_ss_count(void)
 
 static int analog_distinctive_ring(struct ast_channel *chan, struct analog_pvt *p, int idx, int *ringdata)
 {
+	if (!p->usedistinctiveringdetection) {
+		return 0;
+	}
 	if (analog_callbacks.distinctive_ring) {
 		return analog_callbacks.distinctive_ring(chan, p->chan_pvt, idx, ringdata);
 	}
@@ -1668,13 +1713,15 @@ static int analog_get_sub_fd(struct analog_pvt *p, enum analog_sub sub)
 
 #define ANALOG_NEED_MFDETECT(p) (((p)->sig == ANALOG_SIG_FEATDMF) || ((p)->sig == ANALOG_SIG_FEATDMF_TA) || ((p)->sig == ANALOG_SIG_E911) || ((p)->sig == ANALOG_SIG_FGC_CAMA) || ((p)->sig == ANALOG_SIG_FGC_CAMAMF) || ((p)->sig == ANALOG_SIG_FEATB))
 
-static int analog_canmatch_featurecode(const char *pickupexten, const char *exten)
+static int analog_canmatch_featurecode(const char *exten)
 {
 	int extlen = strlen(exten);
+	const char *pickup_ext;
 	if (!extlen) {
 		return 1;
 	}
-	if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
+	pickup_ext = ast_pickup_ext();
+	if (extlen < strlen(pickup_ext) && !strncmp(pickup_ext, exten, extlen)) {
 		return 1;
 	}
 	/* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
@@ -1703,7 +1750,6 @@ static void *__analog_ss_thread(void *data)
 	char dtmfbuf[300];
 	char namebuf[ANALOG_MAX_CID];
 	char numbuf[ANALOG_MAX_CID];
-	struct callerid_state *cs = NULL;
 	char *name = NULL, *number = NULL;
 	int flags = 0;
 	struct ast_smdi_md_message *smdi_msg = NULL;
@@ -1714,8 +1760,6 @@ static void *__analog_ss_thread(void *data)
 	int res;
 	int idx;
 	struct ast_callid *callid;
-	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-	const char *pickupexten;
 
 	analog_increase_ss_count();
 
@@ -1746,17 +1790,6 @@ static void *__analog_ss_thread(void *data)
 		ast_hangup(chan);
 		goto quit;
 	}
-
-	ast_channel_lock(chan);
-	pickup_cfg = ast_get_chan_features_pickup_config(chan);
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-		pickupexten = "";
-	} else {
-		pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-	}
-	ast_channel_unlock(chan);
-
 	analog_dsp_reset_and_flush_digits(p);
 	switch (p->sig) {
 	case ANALOG_SIG_FEATD:
@@ -1832,7 +1865,7 @@ static void *__analog_ss_thread(void *data)
 			case ANALOG_SIG_SF_FEATDMF:
 				res = analog_my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
 				/* if international caca, do it again to get real ANO */
-				if ((p->sig == ANALOG_SIG_FEATDMF) && (dtmfbuf[1] != '0')
+				if ((p->sig == ANALOG_SIG_FEATDMF) && (dtmfbuf[1] != '0') 
 					&& (strlen(dtmfbuf) != 14)) {
 					if (analog_wink(p, idx)) {
 						goto quit;
@@ -1963,6 +1996,8 @@ static void *__analog_ss_thread(void *data)
 		if ((p->sig == ANALOG_SIG_FEATDMF) || (p->sig == ANALOG_SIG_FEATDMF_TA)) {
 			if (exten[0] == '*') {
 				char *stringp=NULL;
+				struct ast_party_caller *caller;
+
 				ast_copy_string(exten2, exten, sizeof(exten2));
 				/* Parse out extension and callerid */
 				stringp=exten2 +1;
@@ -1980,6 +2015,11 @@ static void *__analog_ss_thread(void *data)
 				} else {
 					ast_copy_string(exten, s1 + 2, sizeof(exten));
 				}
+
+				/* The first two digits are ani2 information. */
+				caller = ast_channel_caller(chan);
+				s1[2] = '\0';
+				caller->ani2 = atoi(s1);
 			} else {
 				ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
 			}
@@ -2073,8 +2113,6 @@ static void *__analog_ss_thread(void *data)
 			timeout = 999999;
 		}
 		while (len < AST_MAX_EXTENSION-1) {
-			int is_exten_parking = 0;
-
 			/* Read digit unless it's supposed to be immediate, in which case the
 			   only answer is 's' */
 			if (p->immediate) {
@@ -2098,10 +2136,7 @@ static void *__analog_ss_thread(void *data)
 			} else {
 				analog_play_tone(p, idx, ANALOG_TONE_DIALTONE);
 			}
-			if (ast_parking_provider_registered()) {
-				is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
-			}
-			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
+			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
 				if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
 					if (getforward) {
 						/* Record this as the forwarding extension */
@@ -2120,7 +2155,6 @@ static void *__analog_ss_thread(void *data)
 						getforward = 0;
 					} else {
 						res = analog_play_tone(p, idx, -1);
-						ast_channel_lock(chan);
 						ast_channel_exten_set(chan, exten);
 						if (!ast_strlen_zero(p->cid_num)) {
 							if (!p->hidecallerid) {
@@ -2135,7 +2169,6 @@ static void *__analog_ss_thread(void *data)
 							}
 						}
 						ast_setstate(chan, AST_STATE_RING);
-						ast_channel_unlock(chan);
 						analog_set_echocanceller(p, 1);
 						res = ast_pbx_run(chan);
 						if (res) {
@@ -2168,7 +2201,7 @@ static void *__analog_ss_thread(void *data)
 				memset(exten, 0, sizeof(exten));
 				timeout = analog_firstdigittimeout;
 
-			} else if (!strcmp(exten, pickupexten)) {
+			} else if (!strcmp(exten,ast_pickup_ext())) {
 				/* Scan all channels and see if there are any
 				 * ringing channels that have call groups
 				 * that equal this channels pickup group
@@ -2247,35 +2280,15 @@ static void *__analog_ss_thread(void *data)
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if ((p->transfer || p->canpark) && is_exten_parking
-				&& p->subs[ANALOG_SUB_THREEWAY].owner) {
-				struct ast_bridge_channel *bridge_channel;
-
-				/*
-				 * This is a three way call, the main call being a real channel,
-				 * and we're parking the first call.
-				 */
-				ast_channel_lock(p->subs[ANALOG_SUB_THREEWAY].owner);
-				bridge_channel = ast_channel_get_bridge_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
-				ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
-				if (bridge_channel) {
-					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
-						/*
-						 * Swap things around between the three-way and real call so we
-						 * can hear where the channel got parked.
-						 */
-						analog_lock_private(p);
-						analog_set_new_owner(p, p->subs[ANALOG_SUB_THREEWAY].owner);
-						analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
-						analog_unlock_private(p);
-
-						ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
-						ast_hangup(chan);
-						ao2_ref(bridge_channel, -1);
-						goto quit;
-					}
-					ao2_ref(bridge_channel, -1);
-				}
+			} else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
+						p->subs[ANALOG_SUB_THREEWAY].owner &&
+						ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+				/* This is a three way call, the main call being a real channel,
+					and we're parking the first call. */
+				ast_masq_park_call_exten(
+					ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, exten,
+					ast_channel_context(chan), 0, NULL);
+				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
 				break;
 			} else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
 				ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);
@@ -2317,7 +2330,9 @@ static void *__analog_ss_thread(void *data)
 					analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_THREEWAY);
 					analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
 					analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
-					ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
+					if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
+						ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+					}
 					ast_hangup(chan);
 					goto quit;
 				} else {
@@ -2332,7 +2347,7 @@ static void *__analog_ss_thread(void *data)
 				}
 			} else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
 				ast_channel_caller(chan)->id.number.valid ? ast_channel_caller(chan)->id.number.str : NULL)
-				&& !analog_canmatch_featurecode(pickupexten, exten)) {
+				&& !analog_canmatch_featurecode(exten)) {
 				ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
 					ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str
 						? ast_channel_caller(chan)->id.number.str : "<Unknown Caller>",
@@ -2380,11 +2395,10 @@ static void *__analog_ss_thread(void *data)
 			/* If set to use DTMF CID signalling, listen for DTMF */
 			if (p->cid_signalling == CID_SIG_DTMF) {
 				int k = 0;
-				int oldlinearity;
+				int oldlinearity; 
 				int timeout_ms;
 				int ms;
 				struct timeval start = ast_tvnow();
-				cs = NULL;
 				ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
 
 				oldlinearity = analog_set_linear_mode(p, idx, 0);
@@ -2408,8 +2422,8 @@ static void *__analog_ss_thread(void *data)
 						 * or AST_FLAG_END_DTMF_ONLY flag settings since we
 						 * are hanging up the channel.
 						 */
-						ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
-							"Exiting simple switch\n");
+						ast_log(LOG_WARNING,
+							"DTMFCID timed out waiting for ring. Exiting simple switch\n");
 						ast_hangup(chan);
 						goto quit;
 					}
@@ -2448,50 +2462,53 @@ static void *__analog_ss_thread(void *data)
 
 			/* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
 			} else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
-				int timeout = 10000;  /* Ten seconds */
-				struct timeval start = ast_tvnow();
-				enum analog_event ev;
-
 				namebuf[0] = 0;
 				numbuf[0] = 0;
 
 				if (!analog_start_cid_detect(p, p->cid_signalling)) {
+					int timeout = 10000;  /* Ten seconds */
+					struct timeval start = ast_tvnow();
+					enum analog_event ev;
 					int off_ms;
 					int ms;
 					struct timeval off_start;
-					while (1) {
-						res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
 
+					if (!p->usedistinctiveringdetection) {
+						/* Disable distinctive ring timeout count */
+						analog_set_ringtimeout(p, 0);
+					}
+					while ((ms = ast_remaining_ms(start, timeout))) {
+						res = analog_get_callerid(p, namebuf, numbuf, &ev, ms);
+						if (res < 0) {
+							ast_log(LOG_WARNING,
+								"CallerID returned with error on channel '%s'\n",
+								ast_channel_name(chan));
+							break;
+						}
 						if (res == 0) {
 							break;
 						}
-
-						if (res == 1) {
-							if (ev == ANALOG_EVENT_NOALARM) {
-								analog_set_alarm(p, 0);
-							}
-							if (p->cid_signalling == CID_SIG_V23_JP) {
-								if (ev == ANALOG_EVENT_RINGBEGIN) {
-									analog_off_hook(p);
-									usleep(1);
-								}
-							} else {
-								ev = ANALOG_EVENT_NONE;
-								break;
-							}
+						if (res != 1) {
+							continue;
 						}
-
-						if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
+						if (ev == ANALOG_EVENT_NOALARM) {
+							analog_set_alarm(p, 0);
+						}
+						if (p->cid_signalling == CID_SIG_V23_JP) {
+							if (ev == ANALOG_EVENT_RINGBEGIN) {
+								analog_off_hook(p);
+								usleep(1);
+							}
+						} else {
 							break;
-
+						}
 					}
+
 					name = namebuf;
 					number = numbuf;
 
-					analog_stop_cid_detect(p);
-
 					if (p->cid_signalling == CID_SIG_V23_JP) {
-						res = analog_on_hook(p);
+						analog_on_hook(p);
 						usleep(1);
 					}
 
@@ -2503,13 +2520,15 @@ static void *__analog_ss_thread(void *data)
 
 						res = ast_waitfor(chan, ms);
 						if (res <= 0) {
-							ast_log(LOG_WARNING, "CID timed out waiting for ring. "
-								"Exiting simple switch\n");
+							ast_log(LOG_WARNING,
+								"CID timed out waiting for ring. Exiting simple switch\n");
+							analog_stop_cid_detect(p);
 							ast_hangup(chan);
 							goto quit;
 						}
 						if (!(f = ast_read(chan))) {
 							ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
+							analog_stop_cid_detect(p);
 							ast_hangup(chan);
 							goto quit;
 						}
@@ -2519,91 +2538,86 @@ static void *__analog_ss_thread(void *data)
 							break; /* Got ring */
 					}
 
-					if (analog_distinctive_ring(chan, p, idx, NULL)) {
+					res = analog_distinctive_ring(chan, p, idx, NULL);
+					analog_stop_cid_detect(p);
+					if (res) {
 						goto quit;
 					}
-
-					if (res < 0) {
-						ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
-					}
 				} else {
 					ast_log(LOG_WARNING, "Unable to get caller ID space\n");
 				}
 			} else {
-				ast_log(LOG_WARNING, "Channel %s in prering "
-					"state, but I have nothing to do. "
-					"Terminating simple switch, should be "
-					"restarted by the actual ring.\n",
+				ast_log(LOG_WARNING,
+					"Channel %s in prering state, but I have nothing to do. Terminating simple switch, should be restarted by the actual ring.\n",
 					ast_channel_name(chan));
 				ast_hangup(chan);
 				goto quit;
 			}
 		} else if (p->use_callerid && p->cid_start == ANALOG_CID_START_RING) {
-			int timeout = 10000;  /* Ten seconds */
-			struct timeval start = ast_tvnow();
-			enum analog_event ev;
-			int curRingData[RING_PATTERNS] = { 0 };
-			int receivedRingT = 0;
-
 			namebuf[0] = 0;
 			numbuf[0] = 0;
 
 			if (!analog_start_cid_detect(p, p->cid_signalling)) {
-				while (1) {
-					res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
+				int timeout = 10000;  /* Ten seconds */
+				struct timeval start = ast_tvnow();
+				enum analog_event ev;
+				int ring_data[RING_PATTERNS] = { 0 };
+				int ring_data_idx = 0;
+				int ms;
 
+				if (!p->usedistinctiveringdetection) {
+					/* Disable distinctive ring timeout count */
+					analog_set_ringtimeout(p, 0);
+				}
+				while ((ms = ast_remaining_ms(start, timeout))) {
+					res = analog_get_callerid(p, namebuf, numbuf, &ev, ms);
+					if (res < 0) {
+						ast_log(LOG_WARNING,
+							"CallerID returned with error on channel '%s'\n",
+							ast_channel_name(chan));
+						break;
+					}
 					if (res == 0) {
 						break;
 					}
-
-					if (res == 1 || res == 2) {
-						if (ev == ANALOG_EVENT_NOALARM) {
-							analog_set_alarm(p, 0);
-						} else if (ev == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
-							ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
-							p->polarity = POLARITY_IDLE;
-							ast_hangup(chan);
-							goto quit;
-						} else if (ev != ANALOG_EVENT_NONE && ev != ANALOG_EVENT_RINGBEGIN && ev != ANALOG_EVENT_RINGOFFHOOK) {
-							break;
-						}
-						if (res != 2) {
-							/* Let us detect callerid when the telco uses distinctive ring */
-							curRingData[receivedRingT] = p->ringt;
-
-							if (p->ringt < p->ringt_base/2) {
-								break;
-							}
-							/* Increment the ringT counter so we can match it against
-							   values in chan_dahdi.conf for distinctive ring */
-							if (++receivedRingT == RING_PATTERNS) {
-								break;
-							}
-						}
+					if (res != 1) {
+						continue;
 					}
-
-					if (ast_tvdiff_ms(ast_tvnow(), start) > timeout) {
-						break;
+					if (ev == ANALOG_EVENT_NOALARM) {
+						analog_set_alarm(p, 0);
+					} else if (ev == ANALOG_EVENT_POLARITY
+						&& p->hanguponpolarityswitch
+						&& p->polarity == POLARITY_REV) {
+						ast_debug(1,
+							"Hanging up due to polarity reversal on channel %d while detecting callerid\n",
+							p->channel);
+						p->polarity = POLARITY_IDLE;
+						analog_stop_cid_detect(p);
+						ast_hangup(chan);
+						goto quit;
+					} else if (ev == ANALOG_EVENT_RINGOFFHOOK
+						&& p->usedistinctiveringdetection
+						&& ring_data_idx < RING_PATTERNS) {
+						/*
+						 * Detect callerid while collecting possible
+						 * distinctive ring pattern.
+						 */
+						ring_data[ring_data_idx] = p->ringt;
+						++ring_data_idx;
 					}
-
 				}
+
 				name = namebuf;
 				number = numbuf;
 
+				res = analog_distinctive_ring(chan, p, idx, ring_data);
 				analog_stop_cid_detect(p);
-
-				if (analog_distinctive_ring(chan, p, idx, curRingData)) {
+				if (res) {
 					goto quit;
 				}
-
-				if (res < 0) {
-					ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
-				}
 			} else {
 				ast_log(LOG_WARNING, "Unable to get caller ID space\n");
 			}
-		} else {
-			cs = NULL;
 		}
 
 		if (number) {
@@ -2611,16 +2625,10 @@ static void *__analog_ss_thread(void *data)
 		}
 		ast_set_callerid(chan, number, name, number);
 
-		if (cs) {
-			callerid_free(cs);
-		}
-
 		analog_handle_notify_message(chan, p, flags, -1);
 
-		ast_channel_lock(chan);
 		ast_setstate(chan, AST_STATE_RING);
 		ast_channel_rings_set(chan, 1);
-		ast_channel_unlock(chan);
 		analog_set_ringtimeout(p, p->ringt_base);
 		res = ast_pbx_run(chan);
 		if (res) {
@@ -2638,7 +2646,9 @@ static void *__analog_ss_thread(void *data)
 	}
 	ast_hangup(chan);
 quit:
-	ao2_cleanup(smdi_msg);
+	if (smdi_msg) {
+		ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
+	}
 	analog_decrease_ss_count();
 	return NULL;
 }
@@ -2650,19 +2660,6 @@ int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
 	return ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, p);
 }
 
-static void analog_publish_channel_alarm_clear(int channel)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-
-	ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", channel);
-	body = ast_json_pack("{s: i}", "Channel", channel);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
-}
-
 static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_channel *ast)
 {
 	int res, x;
@@ -2778,7 +2775,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 				analog_train_echocanceller(p);
 				ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
 				p->dop.op = ANALOG_DIAL_OP_REPLACE;
-				analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
+				if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
+					int dial_err = errno;
+					ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(dial_err));
+				}
 				p->echobreak = 0;
 			} else {
 				analog_set_dialing(p, 0);
@@ -2892,6 +2892,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 						ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
 					} else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
 						if (p->transfer) {
+							int inthreeway;
+
+							inthreeway = p->subs[ANALOG_SUB_THREEWAY].inthreeway;
+
 							/* In any case this isn't a threeway call anymore */
 							analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
 							analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
@@ -2905,7 +2909,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 								analog_set_new_owner(p, NULL);
 								/* Ring the phone */
 								analog_ring(p);
-							} else if (!analog_attempt_transfer(p)) {
+							} else if (!analog_attempt_transfer(p, inthreeway)) {
 								/*
 								 * Transfer successful.  Don't actually hang up at this point.
 								 * Let our channel legs of the calls die off as the transfer
@@ -2964,7 +2968,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 				p->echobreak = 0;
 			}
 			if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
+				int saveerr = errno;
 				analog_on_hook(p);
+				ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
 				return NULL;
 			}
 			analog_set_dialing(p, 1);
@@ -2998,7 +3004,8 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 				} else if (!ast_strlen_zero(p->dop.dialstr)) {
 					/* nick at dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
 					res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
-					if (res) {
+					if (res < 0) {
+						ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 						p->dop.dialstr[0] = '\0';
 						return NULL;
 					} else {
@@ -3024,8 +3031,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 			case AST_STATE_UP:
 				/* Make sure it stops ringing */
 				analog_off_hook(p);
-				/* Okay -- probably call waiting */
-				ast_queue_unhold(p->owner);
+				/* Okay -- probably call waiting*/
+				if (ast_bridged_channel(p->owner)) {
+					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+				}
 				break;
 			case AST_STATE_RESERVED:
 				/* Start up dialtone */
@@ -3128,7 +3137,14 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		break;
 	case ANALOG_EVENT_NOALARM:
 		analog_set_alarm(p, 0);
-		analog_publish_channel_alarm_clear(p->channel);
+		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an Alarm is cleared on an Analog channel.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
+			"Channel: %d\r\n", p->channel);
 		break;
 	case ANALOG_EVENT_WINKFLASH:
 		if (p->inalarm) {
@@ -3176,11 +3192,17 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 				analog_stop_callwait(p);
 
 				/* Start music on hold if appropriate */
-				if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
-					ast_queue_hold(p->subs[ANALOG_SUB_CALLWAIT].owner, p->mohsuggest);
+				if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
+					ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
 				}
-				ast_queue_hold(p->subs[ANALOG_SUB_REAL].owner, p->mohsuggest);
-				ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
+				if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
+					ast_queue_control_data(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_HOLD,
+						S_OR(p->mohsuggest, NULL),
+						!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+				}
+				ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
 
 				/* Unlock the call-waiting call that we swapped to real-call. */
 				ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner);
@@ -3271,8 +3293,12 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 					} else {
 						ast_verb(3, "Started three way call on channel %d\n", p->channel);
 
-						/* Start music on hold */
-						ast_queue_hold(p->subs[ANALOG_SUB_THREEWAY].owner, p->mohsuggest);
+						/* Start music on hold if appropriate */
+						if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+							ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+								S_OR(p->mohsuggest, NULL),
+								!ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+						}
 					}
 					ast_callid_threadstorage_auto_clean(callid, callid_created);
 				}
@@ -3322,7 +3348,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 							analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
 							orig_3way_sub = ANALOG_SUB_REAL;
 						}
-						ast_queue_unhold(p->subs[orig_3way_sub].owner);
+						if (ast_bridged_channel(p->subs[orig_3way_sub].owner)) {
+							ast_queue_control(p->subs[orig_3way_sub].owner, AST_CONTROL_UNHOLD);
+						}
 						analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
 					} else {
 						ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[ANALOG_SUB_THREEWAY].owner));
@@ -3330,7 +3358,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 						orig_3way_sub = ANALOG_SUB_REAL;
 						ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
 						analog_set_new_owner(p, p->subs[ANALOG_SUB_REAL].owner);
-						ast_queue_unhold(p->subs[ANALOG_SUB_REAL].owner);
+						if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
+							ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+						}
 						analog_set_echocanceller(p, 1);
 					}
 				}
@@ -3384,7 +3414,8 @@ winkflashdone:
 			/* FGD MF and EMWINK *Must* wait for wink */
 			if (!ast_strlen_zero(p->dop.dialstr)) {
 				res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
-				if (res) {
+				if (res < 0) {
+					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 					p->dop.dialstr[0] = '\0';
 					return NULL;
 				} else {
@@ -3415,7 +3446,8 @@ winkflashdone:
 		case ANALOG_SIG_SF_FEATD:
 			if (!ast_strlen_zero(p->dop.dialstr)) {
 				res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
-				if (res) {
+				if (res < 0) {
+					ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
 					p->dop.dialstr[0] = '\0';
 					return NULL;
 				} else {
@@ -3572,8 +3604,8 @@ struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast
 				ast_log(LOG_WARNING, "Event %s on %s is not restored owner %s\n",
 					analog_event2str(res), ast_channel_name(ast), ast_channel_name(p->owner));
 			}
-			if (p->owner) {
-				ast_queue_unhold(p->owner);
+			if (p->owner && ast_bridged_channel(p->owner)) {
+				ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
 			}
 		}
 		switch (res) {
@@ -3612,7 +3644,9 @@ struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast
 					ast_setstate(p->owner, AST_STATE_UP);
 				}
 				analog_stop_callwait(p);
-				ast_queue_unhold(p->owner);
+				if (ast_bridged_channel(p->owner)) {
+					ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+				}
 			} else {
 				ast_log(LOG_WARNING, "Absorbed %s, but nobody is left!?!?\n",
 					analog_event2str(res));
@@ -3770,7 +3804,9 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
 		break;
 	case ANALOG_EVENT_NOALARM:
 		analog_set_alarm(i, 0);
-		analog_publish_channel_alarm_clear(i->channel);
+		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
+		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
+			"Channel: %d\r\n", i->channel);
 		break;
 	case ANALOG_EVENT_ALARM:
 		analog_set_alarm(i, 1);
@@ -3839,8 +3875,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
 			}
 			if (i->cid_start == ANALOG_CID_START_POLARITY || i->cid_start == ANALOG_CID_START_POLARITY_IN) {
 				i->polarity = POLARITY_REV;
-				ast_verb(2, "Starting post polarity "
-					"CID detection on channel %d\n",
+				ast_verb(2, "Starting post polarity CID detection on channel %d\n",
 					i->channel);
 				chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
 				i->ss_astchan = chan;
@@ -3854,9 +3889,9 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
 			ast_callid_threadstorage_auto_clean(callid, callid_created);
 			break;
 		default:
-			ast_log(LOG_WARNING, "handle_init_event detected "
-				"polarity reversal on non-FXO (ANALOG_SIG_FXS) "
-				"interface %d\n", i->channel);
+			ast_log(LOG_WARNING,
+				"handle_init_event detected polarity reversal on non-FXO (ANALOG_SIG_FXS) interface %d\n",
+				i->channel);
 			break;
 		}
 		break;
@@ -3881,9 +3916,9 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
 			ast_callid_threadstorage_auto_clean(callid, callid_created);
 			break;
 		default:
-			ast_log(LOG_WARNING, "handle_init_event detected "
-				"dtmfcid generation event on non-FXO (ANALOG_SIG_FXS) "
-				"interface %d\n", i->channel);
+			ast_log(LOG_WARNING,
+				"handle_init_event detected dtmfcid generation event on non-FXO (ANALOG_SIG_FXS) interface %d\n",
+				i->channel);
 			break;
 		}
 		break;
@@ -3973,26 +4008,6 @@ int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void
 	return 0;
 }
 
-static void analog_publish_dnd_state(int channel, const char *status)
-{
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
-	if (!dahdichan) {
-		return;
-	}
-
-	ast_str_set(&dahdichan, 0, "DAHDI/%d", channel);
-
-	body = ast_json_pack("{s: s, s: s}",
-		"Channel", ast_str_buffer(dahdichan),
-		"Status", status);
-	if (!body) {
-		return;
-	}
-
-	ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
-}
-
 int analog_dnd(struct analog_pvt *p, int flag)
 {
 	if (flag == -1) {
@@ -4004,7 +4019,23 @@ int analog_dnd(struct analog_pvt *p, int flag)
 	ast_verb(3, "%s DND on channel %d\n",
 			flag ? "Enabled" : "Disabled",
 			p->channel);
-	analog_publish_dnd_state(p->channel, flag ? "enabled" : "disabled");
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when the Do Not Disturb state is changed on an Analog channel.</synopsis>
+			<syntax>
+				<parameter name="Status">
+					<enumlist>
+						<enum name="enabled"/>
+						<enum name="disabled"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_SYSTEM, "DNDState",
+			"Channel: DAHDI/%d\r\n"
+			"Status: %s\r\n", p->channel,
+			flag ? "enabled" : "disabled");
 
 	return 0;
 }
diff --git a/channels/sig_analog.h b/channels/sig_analog.h
index 13c92c6..6415b6e 100644
--- a/channels/sig_analog.h
+++ b/channels/sig_analog.h
@@ -281,6 +281,7 @@ struct analog_pvt {
 	unsigned int transfer:1;
 	unsigned int transfertobusy:1;			/*!< allow flash-transfers to busy channels */
 	unsigned int use_callerid:1;			/*!< Whether or not to use caller id on this channel */
+	unsigned int usedistinctiveringdetection:1;
 	unsigned int callwaitingcallerid:1;		/*!< TRUE if send caller ID for Call Waiting */
 	/*!
 	 * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index a26b566..15a50c4 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -26,68 +26,6 @@
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="MCID">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Published when a malicious call ID request arrives.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="MCallerIDNumValid">
-				</parameter>
-				<parameter name="MCallerIDNum">
-				</parameter>
-				<parameter name="MCallerIDton">
-				</parameter>
-				<parameter name="MCallerIDNumPlan">
-				</parameter>
-				<parameter name="MCallerIDNumPres">
-				</parameter>
-				<parameter name="MCallerIDNameValid">
-				</parameter>
-				<parameter name="MCallerIDName">
-				</parameter>
-				<parameter name="MCallerIDNameCharSet">
-				</parameter>
-				<parameter name="MCallerIDNamePres">
-				</parameter>
-				<parameter name="MCallerIDSubaddr">
-				</parameter>
-				<parameter name="MCallerIDSubaddrType">
-				</parameter>
-				<parameter name="MCallerIDSubaddrOdd">
-				</parameter>
-				<parameter name="MCallerIDPres">
-				</parameter>
-				<parameter name="MConnectedIDNumValid">
-				</parameter>
-				<parameter name="MConnectedIDNum">
-				</parameter>
-				<parameter name="MConnectedIDton">
-				</parameter>
-				<parameter name="MConnectedIDNumPlan">
-				</parameter>
-				<parameter name="MConnectedIDNumPres">
-				</parameter>
-				<parameter name="MConnectedIDNameValid">
-				</parameter>
-				<parameter name="MConnectedIDName">
-				</parameter>
-				<parameter name="MConnectedIDNameCharSet">
-				</parameter>
-				<parameter name="MConnectedIDNamePres">
-				</parameter>
-				<parameter name="MConnectedIDSubaddr">
-				</parameter>
-				<parameter name="MConnectedIDSubaddrType">
-				</parameter>
-				<parameter name="MConnectedIDSubaddrOdd">
-				</parameter>
-				<parameter name="MConnectedIDPres">
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
- ***/
 
 #include "asterisk.h"
 
@@ -112,8 +50,6 @@
 #include "asterisk/transcap.h"
 #include "asterisk/features.h"
 #include "asterisk/aoc.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis_channels.h"
 
 #include "sig_pri.h"
 #ifndef PRI_EVENT_FACILITY
@@ -133,15 +69,6 @@
  */
 //#define ALWAYS_PICK_CHANNEL	1
 
-/*!
- * Define to force a RESTART on a channel that returns a cause
- * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
- * is because of a stuck channel on the peer and the channel is
- * always the next channel we pick for an outgoing call then
- * this can help.
- */
-#define FORCE_RESTART_UNAVAIL_CHANS		1
-
 #if defined(HAVE_PRI_CCSS)
 struct sig_pri_cc_agent_prv {
 	/*! Asterisk span D channel control structure. */
@@ -754,15 +681,15 @@ static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress,
 		ptr = cnum;
 		len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
 		for (x = 0; x < len; ++x) {
-			ptr += sprintf(ptr, "%02x", (unsigned)pri_subaddress->data[x]);
+			ptr += sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[x]);
 		}
 
 		if (pri_subaddress->odd_even_indicator) {
 			/* ODD */
-			sprintf(ptr, "%01x", (unsigned)((pri_subaddress->data[len]) >> 4));
+			sprintf(ptr, "%01hhx", (unsigned char)((pri_subaddress->data[len]) >> 4));
 		} else {
 			/* EVEN */
-			sprintf(ptr, "%02x", (unsigned)pri_subaddress->data[len]);
+			sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[len]);
 		}
 		ast_subaddress->str = cnum;
 	}
@@ -981,8 +908,8 @@ static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_chan
 	sig_pri_party_id_from_ast(&pri_redirecting.to, &redirecting_to);
 	sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &redirecting_orig);
 	pri_redirecting.count = ast_redirecting->count;
-	pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason.code);
-	pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason.code);
+	pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason);
+	pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason);
 
 	pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
 }
@@ -1028,14 +955,12 @@ static int sig_pri_play_tone(struct sig_pri_chan *p, enum sig_pri_tone tone)
 	}
 }
 
-static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state,
-	enum sig_pri_law law, int transfercapability, char *exten,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state, enum sig_pri_law law, int transfercapability, char *exten, const struct ast_channel *requestor)
 {
 	struct ast_channel *c;
 
 	if (sig_pri_callbacks.new_ast_channel) {
-		c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, law, exten, assignedids, requestor);
+		c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, law, exten, requestor);
 	} else {
 		return NULL;
 	}
@@ -1100,17 +1025,14 @@ static void sig_pri_ami_channel_event(struct sig_pri_chan *p)
 	}
 }
 
-struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	int transfercapability)
+struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability)
 {
 	struct ast_channel *ast;
 
 	ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
 
 	sig_pri_set_outgoing(p, 1);
-	ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability,
-		p->exten, assignedids, requestor);
+	ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
 	if (!ast) {
 		sig_pri_set_outgoing(p, 0);
 	}
@@ -1317,73 +1239,53 @@ static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_fr
 
 /*!
  * \internal
- * \brief Queue a hold frame onto the owner channel.
- * \since 12
+ * \brief Queue a control frame of the specified subclass onto the owner channel.
+ * \since 1.8
  *
  * \param pri PRI span control structure.
  * \param chanpos Channel position in the span.
+ * \param subclass Control frame subclass to queue onto the owner channel.
  *
  * \note Assumes the pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
  *
  * \return Nothing
  */
-static void sig_pri_queue_hold(struct sig_pri_span *pri, int chanpos)
+static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
 {
-	sig_pri_lock_owner(pri, chanpos);
-	if (pri->pvts[chanpos]->owner) {
-		ast_queue_hold(pri->pvts[chanpos]->owner, NULL);
-		ast_channel_unlock(pri->pvts[chanpos]->owner);
-	}
-}
+	struct ast_frame f = {AST_FRAME_CONTROL, };
 
-/*!
- * \internal
- * \brief Queue an unhold frame onto the owner channel.
- * \since 12
- *
- * \param pri PRI span control structure.
- * \param chanpos Channel position in the span.
- *
- * \note Assumes the pri->lock is already obtained.
- * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
- *
- * \return Nothing
- */
-static void sig_pri_queue_unhold(struct sig_pri_span *pri, int chanpos)
-{
-	sig_pri_lock_owner(pri, chanpos);
-	if (pri->pvts[chanpos]->owner) {
-		ast_queue_unhold(pri->pvts[chanpos]->owner);
-		ast_channel_unlock(pri->pvts[chanpos]->owner);
+	if (sig_pri_callbacks.queue_control) {
+		sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, subclass);
 	}
+
+	f.subclass.integer = subclass;
+	pri_queue_frame(pri, chanpos, &f);
 }
 
 /*!
  * \internal
- * \brief Queue a control frame of the specified subclass onto the owner channel.
- * \since 1.8
+ * \brief Queue a request to hangup control frame onto the owner channel.
  *
  * \param pri PRI span control structure.
  * \param chanpos Channel position in the span.
- * \param subclass Control frame subclass to queue onto the owner channel.
  *
  * \note Assumes the pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
  *
  * \return Nothing
  */
-static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
+static void sig_pri_queue_hangup(struct sig_pri_span *pri, int chanpos)
 {
-	struct ast_frame f = {AST_FRAME_CONTROL, };
-	struct sig_pri_chan *p = pri->pvts[chanpos];
-
 	if (sig_pri_callbacks.queue_control) {
-		sig_pri_callbacks.queue_control(p->chan_pvt, subclass);
+		sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, AST_CONTROL_HANGUP);
 	}
 
-	f.subclass.integer = subclass;
-	pri_queue_frame(pri, chanpos, &f);
+	sig_pri_lock_owner(pri, chanpos);
+	if (pri->pvts[chanpos]->owner) {
+		ast_queue_hangup(pri->pvts[chanpos]->owner);
+		ast_channel_unlock(pri->pvts[chanpos]->owner);
+	}
 }
 
 /*!
@@ -1452,27 +1354,6 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
 
 /*!
  * \internal
- * \brief Queue the span for destruction
- * \since 13.0
- *
- * \param pri PRI span control structure.
- *
- * Asks the channel driver to queue the span for destruction at a
- * possibly later time, if (e.g.) locking considerations don't allow
- * destroying it right now.
- *
- * \return Nothing
- */
-static void pri_destroy_later(struct sig_pri_span *pri)
-{
-	if (!sig_pri_callbacks.destroy_later) {
-		return;
-	}
-	sig_pri_callbacks.destroy_later(pri);
-}
-
-/*!
- * \internal
  * \brief Kill the call.
  * \since 10.0
  *
@@ -1685,10 +1566,6 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 		strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
 		new_chan->moh_state = old_chan->moh_state;
 		old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
-#if defined(HAVE_PRI_TRANSFER)
-		new_chan->xfer_data = old_chan->xfer_data;
-		old_chan->xfer_data = NULL;
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 
 #if defined(HAVE_PRI_AOC_EVENTS)
 		new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
@@ -2193,9 +2070,7 @@ static void *pri_ss_thread(void *data)
 #endif	/* defined(JIRA_ASTERISK_15594) */
 
 		sig_pri_set_echocanceller(p, 1);
-		ast_channel_lock(chan);
 		ast_setstate(chan, AST_STATE_RING);
-		ast_channel_unlock(chan);
 		res = ast_pbx_run(chan);
 		if (res) {
 			ast_log(LOG_WARNING, "PBX exited non-zero!\n");
@@ -2331,8 +2206,8 @@ static void sig_pri_redirecting_convert(struct ast_party_redirecting *ast_redire
 	sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
 	sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
 	ast_redirecting->count = pri_redirecting->count;
-	ast_redirecting->reason.code = pri_to_ast_reason(pri_redirecting->reason);
-	ast_redirecting->orig_reason.code = pri_to_ast_reason(pri_redirecting->orig_reason);
+	ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
+	ast_redirecting->orig_reason = pri_to_ast_reason(pri_redirecting->orig_reason);
 }
 
 /*!
@@ -2369,74 +2244,9 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
 }
 
 #if defined(HAVE_PRI_MCID)
-static void party_number_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *number)
-{
-	const char *num_txt, *pres_txt;
-	int plan, pres;
-	if (!number) {
-		ast_str_append(msg, 0,
-			"%sNumValid: 0\r\n"
-			"%sNum: \r\n"
-			"%ston: 0\r\n",
-			prefix, prefix, prefix);
-		return;
-	}
-
-	num_txt = ast_json_string_get(ast_json_object_get(number, "number"));
-	plan = ast_json_integer_get(ast_json_object_get(number, "plan"));
-	pres = ast_json_integer_get(ast_json_object_get(number, "presentation"));
-	pres_txt = ast_json_string_get(ast_json_object_get(number, "presentation_txt"));
-
-	ast_str_append(msg, 0, "%sNumValid: 1\r\n", prefix);
-	ast_str_append(msg, 0, "%sNum: %s\r\n", prefix, num_txt);
-	ast_str_append(msg, 0, "%ston: %d\r\n", prefix, plan);
-	ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, plan);
-	ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix, pres, pres_txt);
-}
-
-static void party_name_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *name)
-{
-	const char *name_txt, *pres_txt, *charset;
-	int pres;
-	if (!name) {
-		ast_str_append(msg, 0,
-			"%sNameValid: 0\r\n"
-			"%sName: \r\n",
-			prefix, prefix);
-		return;
-	}
-
-	name_txt = ast_json_string_get(ast_json_object_get(name, "name"));
-	charset = ast_json_string_get(ast_json_object_get(name, "character_set"));
-	pres = ast_json_integer_get(ast_json_object_get(name, "presentation"));
-	pres_txt = ast_json_string_get(ast_json_object_get(name, "presentation_txt"));
-
-	ast_str_append(msg, 0, "%sNameValid: 1\r\n", prefix);
-	ast_str_append(msg, 0, "%sName: %s\r\n", prefix, name_txt);
-	ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix, charset);
-	ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix, pres, pres_txt);
-}
-
-static void party_subaddress_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *subaddress)
-{
-	const char *subaddress_txt, *type_txt;
-	int odd;
-	if (!subaddress) {
-		return;
-	}
-
-	subaddress_txt = ast_json_string_get(ast_json_object_get(subaddress, "subaddress"));
-	type_txt = ast_json_string_get(ast_json_object_get(subaddress, "type"));
-	odd = ast_json_is_true(ast_json_object_get(subaddress, "odd")) ? 1 : 0;
-
-	ast_str_append(msg, 0, "%sSubaddr: %s\r\n", prefix, subaddress_txt);
-	ast_str_append(msg, 0, "%sSubaddrType: %s\r\n", prefix, type_txt);
-	ast_str_append(msg, 0, "%sSubaddrOdd: %d\r\n", prefix, odd);
-}
-
 /*!
  * \internal
- * \brief Append the given JSON party id to the event string.
+ * \brief Append the given party id to the event string.
  * \since 1.8
  *
  * \param msg Event message string being built.
@@ -2445,72 +2255,58 @@ static void party_subaddress_json_to_ami(struct ast_str **msg, const char *prefi
  *
  * \return Nothing
  */
-static void party_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *party)
+static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
 {
-	struct ast_json *presentation = ast_json_object_get(party, "presentation");
-	struct ast_json *presentation_txt = ast_json_object_get(party, "presentation_txt");
-	struct ast_json *name = ast_json_object_get(party, "name");
-	struct ast_json *number = ast_json_object_get(party, "number");
-	struct ast_json *subaddress = ast_json_object_get(party, "subaddress");
+	int pres;
 
 	/* Combined party presentation */
-	ast_str_append(msg, 0, "%sPres: %jd (%s)\r\n", prefix,
-		ast_json_integer_get(presentation),
-		ast_json_string_get(presentation_txt));
+	pres = ast_party_id_presentation(party);
+	ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
+		ast_describe_caller_presentation(pres));
 
 	/* Party number */
-	party_number_json_to_ami(msg, prefix, number);
+	ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
+		party->number.valid);
+	ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
+		S_COR(party->number.valid, party->number.str, ""));
+	ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
+	if (party->number.valid) {
+		ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
+		ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
+			party->number.presentation,
+			ast_describe_caller_presentation(party->number.presentation));
+	}
 
 	/* Party name */
-	party_name_json_to_ami(msg, prefix, name);
-
-	/* Party subaddress */
-	party_subaddress_json_to_ami(msg, prefix, subaddress);
-}
-
-static struct ast_manager_event_blob *mcid_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-
-	if (obj->snapshot) {
-		channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-		if (!channel_string) {
-			return NULL;
-		}
+	ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
+		party->name.valid);
+	ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
+		S_COR(party->name.valid, party->name.str, ""));
+	if (party->name.valid) {
+		ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
+			ast_party_name_charset_describe(party->name.char_set));
+		ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
+			party->name.presentation,
+			ast_describe_caller_presentation(party->name.presentation));
 	}
 
-	party_json_to_ami(&party_string, "MCallerID", ast_json_object_get(obj->blob, "caller"));
-	party_json_to_ami(&party_string, "MConnectedID", ast_json_object_get(obj->blob, "connected"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "MCID",
-		"%s"
-		"%s",
-		S_COR(obj->snapshot, ast_str_buffer(channel_string), ""), ast_str_buffer(party_string));
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(mcid_type,
-	.to_ami = mcid_to_ami,
-	);
-
-static void send_mcid(struct ast_channel *chan, struct ast_party_id *caller, struct ast_party_id *connected)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	ast_assert(caller != NULL);
-	ast_assert(connected != NULL);
+#if defined(HAVE_PRI_SUBADDR)
+	/* Party subaddress */
+	if (party->subaddress.valid) {
+		static const char subaddress[] = "Subaddr";
 
-	blob = ast_json_pack("{s: o, s: o}",
-		"caller", ast_json_party_id(caller),
-		"connected", ast_json_party_id(connected));
-	if (!blob) {
-		return;
+		ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
+			S_OR(party->subaddress.str, ""));
+		ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
+			party->subaddress.type);
+		ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
+			party->subaddress.odd_even_indicator);
 	}
-
-	ast_channel_publish_blob(chan, mcid_type(), blob);
+#endif	/* defined(HAVE_PRI_SUBADDR) */
 }
+#endif	/* defined(HAVE_PRI_MCID) */
 
+#if defined(HAVE_PRI_MCID)
 /*!
  * \internal
  * \brief Handle the MCID event.
@@ -2528,12 +2324,15 @@ static void send_mcid(struct ast_channel *chan, struct ast_party_id *caller, str
  */
 static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
 {
-	struct ast_party_id caller_party;
-	struct ast_party_id connected_party;
+	struct ast_channel *chans[1];
+	struct ast_str *msg;
+	struct ast_party_id party;
+
+	msg = ast_str_create(4096);
+	if (!msg) {
+		return;
+	}
 
-	/* Always use libpri's called party information. */
-	ast_party_id_init(&connected_party);
-	sig_pri_party_id_convert(&connected_party, &mcid->answerer, pri);
 	if (owner) {
 		/*
 		 * The owner channel is present.
@@ -2541,18 +2340,31 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
 		 */
 		ast_queue_control(owner, AST_CONTROL_MCID);
 
-		send_mcid(owner, &ast_channel_connected(owner)->id, &connected_party);
+		ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
+		ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
+
+		sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
 	} else {
 		/*
 		 * Since we no longer have an owner channel,
 		 * we have to use the caller information supplied by libpri.
 		 */
-		ast_party_id_init(&caller_party);
-		sig_pri_party_id_convert(&caller_party, &mcid->originator, pri);
-		send_mcid(owner, &caller_party, &connected_party);
-		ast_party_id_free(&caller_party);
+		ast_party_id_init(&party);
+		sig_pri_party_id_convert(&party, &mcid->originator, pri);
+		sig_pri_event_party_id(&msg, "CallerID", &party);
+		ast_party_id_free(&party);
 	}
-	ast_party_id_free(&connected_party);
+
+	/* Always use libpri's called party information. */
+	ast_party_id_init(&party);
+	sig_pri_party_id_convert(&party, &mcid->answerer, pri);
+	sig_pri_event_party_id(&msg, "ConnectedID", &party);
+	ast_party_id_free(&party);
+
+	chans[0] = owner;
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
+		ast_str_buffer(msg));
+	ast_free(msg);
 }
 #endif	/* defined(HAVE_PRI_MCID) */
 
@@ -2563,8 +2375,6 @@ struct xfer_rsp_data {
 	q931_call *call;
 	/*! Invocation ID to use when sending a reply to the transfer request. */
 	int invoke_id;
-	/*! TRUE if the transfer response has been made. */
-	int responded;
 };
 #endif	/* defined(HAVE_PRI_TRANSFER) */
 
@@ -2574,19 +2384,14 @@ struct xfer_rsp_data {
  * \brief Send the transfer success/fail response message.
  * \since 1.8
  *
- * \param rsp Transfer response data.
+ * \param data Callback user data pointer
  * \param is_successful TRUE if the transfer was successful.
  *
- * \note Assumes the rsp->pri->lock is already obtained.
- *
  * \return Nothing
  */
-static void sig_pri_transfer_rsp(struct xfer_rsp_data *rsp, int is_successful)
+static void sig_pri_transfer_rsp(void *data, int is_successful)
 {
-	if (rsp->responded) {
-		return;
-	}
-	rsp->responded = 1;
+	struct xfer_rsp_data *rsp = data;
 
 	pri_transfer_rsp(rsp->pri->pri, rsp->call, rsp->invoke_id, is_successful);
 }
@@ -2594,6 +2399,19 @@ static void sig_pri_transfer_rsp(struct xfer_rsp_data *rsp, int is_successful)
 
 #if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
 /*!
+ * \brief Protocol callback to indicate if transfer will happen.
+ * \since 1.8
+ *
+ * \param data Callback user data pointer
+ * \param is_successful TRUE if the transfer will happen.
+ *
+ * \return Nothing
+ */
+typedef void (*xfer_rsp_callback)(void *data, int is_successful);
+#endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
+
+#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
+/*!
  * \internal
  * \brief Attempt to transfer the two calls to each other.
  * \since 1.8
@@ -2603,14 +2421,15 @@ static void sig_pri_transfer_rsp(struct xfer_rsp_data *rsp, int is_successful)
  * \param call_1_held TRUE if call_1_pri is on hold.
  * \param call_2_pri Second call involved in the transfer. (target; usually active/ringing)
  * \param call_2_held TRUE if call_2_pri is on hold.
- * \param xfer_data Transfer response data if non-NULL.
+ * \param rsp_callback Protocol callback to indicate if transfer will happen. NULL if not used.
+ * \param data Callback user data pointer
  *
  * \note Assumes the pri->lock is already obtained.
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, struct xfer_rsp_data *xfer_data)
+static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, xfer_rsp_callback rsp_callback, void *data)
 {
 	struct attempt_xfer_call {
 		q931_call *pri;
@@ -2619,9 +2438,10 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
 		int chanpos;
 	};
 	int retval;
-	enum ast_transfer_result xfer_res;
+	struct ast_channel *transferee;
 	struct attempt_xfer_call *call_1;
 	struct attempt_xfer_call *call_2;
+	struct attempt_xfer_call *swap_call;
 	struct attempt_xfer_call c1;
 	struct attempt_xfer_call c2;
 
@@ -2637,104 +2457,118 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
 	call_2->chanpos = pri_find_principle_by_call(pri, call_2->pri);
 	if (call_1->chanpos < 0 || call_2->chanpos < 0) {
 		/* Calls not found in span control. */
-#if defined(HAVE_PRI_TRANSFER)
-		if (xfer_data) {
+		if (rsp_callback) {
 			/* Transfer failed. */
-			sig_pri_transfer_rsp(xfer_data, 0);
+			rsp_callback(data, 0);
 		}
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 		return -1;
 	}
 
-	/* Get call_1 owner. */
-	sig_pri_lock_private(pri->pvts[call_1->chanpos]);
-	sig_pri_lock_owner(pri, call_1->chanpos);
-	call_1->ast = pri->pvts[call_1->chanpos]->owner;
-	if (call_1->ast) {
-		ast_channel_ref(call_1->ast);
-		ast_channel_unlock(call_1->ast);
+	/* Attempt to make transferee and target consistent. */
+	if (!call_1->held && call_2->held) {
+		/*
+		 * Swap call_1 and call_2 to make call_1 the transferee(held call)
+		 * and call_2 the target(active call).
+		 */
+		swap_call = call_1;
+		call_1 = call_2;
+		call_2 = swap_call;
 	}
-	sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
 
-	/* Get call_2 owner. */
+	/* Deadlock avoidance is attempted. */
+	sig_pri_lock_private(pri->pvts[call_1->chanpos]);
+	sig_pri_lock_owner(pri, call_1->chanpos);
 	sig_pri_lock_private(pri->pvts[call_2->chanpos]);
 	sig_pri_lock_owner(pri, call_2->chanpos);
-	call_2->ast = pri->pvts[call_2->chanpos]->owner;
-	if (call_2->ast) {
-		ast_channel_ref(call_2->ast);
-		ast_channel_unlock(call_2->ast);
-	}
-	sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
 
+	call_1->ast = pri->pvts[call_1->chanpos]->owner;
+	call_2->ast = pri->pvts[call_2->chanpos]->owner;
 	if (!call_1->ast || !call_2->ast) {
 		/* At least one owner is not present. */
 		if (call_1->ast) {
-			ast_channel_unref(call_1->ast);
+			ast_channel_unlock(call_1->ast);
 		}
 		if (call_2->ast) {
-			ast_channel_unref(call_2->ast);
+			ast_channel_unlock(call_2->ast);
 		}
-#if defined(HAVE_PRI_TRANSFER)
-		if (xfer_data) {
+		sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
+		sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
+		if (rsp_callback) {
 			/* Transfer failed. */
-			sig_pri_transfer_rsp(xfer_data, 0);
+			rsp_callback(data, 0);
 		}
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 		return -1;
 	}
 
-	ast_verb(3, "TRANSFERRING %s to %s\n",
-		ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
+	for (;;) {
+		transferee = ast_bridged_channel(call_1->ast);
+		if (transferee) {
+			break;
+		}
+
+		/* Try masquerading the other way. */
+		swap_call = call_1;
+		call_1 = call_2;
+		call_2 = swap_call;
 
-#if defined(HAVE_PRI_TRANSFER)
-	if (xfer_data) {
-		/*
-		 * Add traps on the transferer channels in case threading causes
-		 * them to hangup before ast_bridge_transfer_attended() returns
-		 * and we can get the pri->lock back.
-		 */
-		sig_pri_lock_private(pri->pvts[call_1->chanpos]);
-		pri->pvts[call_1->chanpos]->xfer_data = xfer_data;
+		transferee = ast_bridged_channel(call_1->ast);
+		if (transferee) {
+			break;
+		}
+
+		/* Could not transfer.  Neither call is bridged. */
+		ast_channel_unlock(call_1->ast);
+		ast_channel_unlock(call_2->ast);
 		sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
-		sig_pri_lock_private(pri->pvts[call_2->chanpos]);
-		pri->pvts[call_2->chanpos]->xfer_data = xfer_data;
 		sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
+
+		if (rsp_callback) {
+			/* Transfer failed. */
+			rsp_callback(data, 0);
+		}
+		return -1;
 	}
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 
+	ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
+
+	/*
+	 * Setup transfer masquerade.
+	 *
+	 * Note:  There is an extremely nasty deadlock avoidance issue
+	 * with ast_channel_transfer_masquerade().  Deadlock may be possible if
+	 * the channels involved are proxies (chan_agent channels) and
+	 * it is called with locks.  Unfortunately, there is no simple
+	 * or even merely difficult way to guarantee deadlock avoidance
+	 * and still be able to send an ECT success response without the
+	 * possibility of the bridged channel hanging up on us.
+	 */
 	ast_mutex_unlock(&pri->lock);
-	xfer_res = ast_bridge_transfer_attended(call_1->ast, call_2->ast);
+	retval = ast_channel_transfer_masquerade(
+		call_2->ast,
+		ast_channel_connected(call_2->ast),
+		call_2->held,
+		transferee,
+		ast_channel_connected(call_1->ast),
+		call_1->held);
+
+	/* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
 	ast_mutex_lock(&pri->lock);
-	retval = (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) ? -1 : 0;
 
-#if defined(HAVE_PRI_TRANSFER)
-	if (xfer_data) {
-		int rsp_chanpos;
+	ast_channel_unlock(call_1->ast);
+	ast_channel_unlock(call_2->ast);
+	sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
+	sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
 
+	if (rsp_callback) {
 		/*
-		 * Remove the transferrer channel traps.
+		 * Report transfer status.
 		 *
-		 * We must refind chanpos because we released pri->lock.
+		 * Must do the callback before the masquerade completes to ensure
+		 * that the protocol message goes out before the call leg is
+		 * disconnected.
 		 */
-		rsp_chanpos = pri_find_principle_by_call(pri, call_1->pri);
-		if (0 <= rsp_chanpos) {
-			sig_pri_lock_private(pri->pvts[rsp_chanpos]);
-			pri->pvts[rsp_chanpos]->xfer_data = NULL;
-			sig_pri_unlock_private(pri->pvts[rsp_chanpos]);
-		}
-		rsp_chanpos = pri_find_principle_by_call(pri, call_2->pri);
-		if (0 <= rsp_chanpos) {
-			sig_pri_lock_private(pri->pvts[rsp_chanpos]);
-			pri->pvts[rsp_chanpos]->xfer_data = NULL;
-			sig_pri_unlock_private(pri->pvts[rsp_chanpos]);
-		}
-
-		/* Report transfer status. */
-		sig_pri_transfer_rsp(xfer_data, retval ? 0 : 1);
+		rsp_callback(data, retval ? 0 : 1);
 	}
-#endif	/* defined(HAVE_PRI_TRANSFER) */
-	ast_channel_unref(call_1->ast);
-	ast_channel_unref(call_2->ast);
 	return retval;
 }
 #endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
@@ -4037,14 +3871,14 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
 	}
 
 	if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E))) {
-		ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+		ast_queue_hangup(pvt->owner);
 		goto cleanup_termination_request;
 	}
 
 	ast_aoc_set_termination_request(decoded);
 
 	if (!(encoded = ast_aoc_encode(decoded, &encoded_size, pvt->owner))) {
-		ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+		ast_queue_hangup(pvt->owner);
 		goto cleanup_termination_request;
 	}
 
@@ -4053,7 +3887,7 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
 	whentohangup.tv_sec = ms / 1000;
 
 	if (ast_queue_control_data(pvt->owner, AST_CONTROL_AOC, encoded, encoded_size)) {
-		ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+		ast_queue_hangup(pvt->owner);
 		goto cleanup_termination_request;
 	}
 
@@ -4297,43 +4131,6 @@ static void sig_pri_handle_cis_subcmds(struct sig_pri_span *pri, int event_id,
 	}
 }
 
-#if defined(HAVE_PRI_AOC_EVENTS)
-/*!
- * \internal
- * \brief detect if AOC-S subcmd is present.
- * \since 1.8
- *
- * \param subcmds Subcommands to process if any. (Could be NULL).
- *
- * \note Knowing whether or not an AOC-E subcmd is present on certain
- * PRI hangup events is necessary to determine what method to use to hangup
- * the ast_channel.  If an AOC-E subcmd just came in, then a new AOC-E was queued
- * on the ast_channel.  If a soft hangup is used, the AOC-E msg will never make it
- * across the bridge, but if a AST_CONTROL_HANGUP frame is queued behind it
- * we can ensure the AOC-E frame makes it to it's destination before the hangup
- * frame is read.
- *
- *
- * \retval 0 AOC-E is not present in subcmd list
- * \retval 1 AOC-E is present in subcmd list
- */
-static int detect_aoc_e_subcmd(const struct pri_subcommands *subcmds)
-{
-	int i;
-
-	if (!subcmds) {
-		return 0;
-	}
-	for (i = 0; i < subcmds->counter_subcmd; ++i) {
-		const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
-		if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
-			return 1;
-		}
-	}
-	return 0;
-}
-#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-
 /*!
  * \internal
  * \brief Handle the call associated PRI subcommand events.
@@ -4600,11 +4397,10 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
 			xfer_rsp.pri = pri;
 			xfer_rsp.call = call_rsp;
 			xfer_rsp.invoke_id = subcmd->u.transfer.invoke_id;
-			xfer_rsp.responded = 0;
 			sig_pri_attempt_transfer(pri,
 				subcmd->u.transfer.call_1, subcmd->u.transfer.is_call_1_held,
 				subcmd->u.transfer.call_2, subcmd->u.transfer.is_call_2_held,
-				&xfer_rsp);
+				sig_pri_transfer_rsp, &xfer_rsp);
 			sig_pri_lock_private(pri->pvts[chanpos]);
 			break;
 #endif	/* defined(HAVE_PRI_TRANSFER) */
@@ -4826,7 +4622,7 @@ static const char *sig_pri_moh_event_str(enum sig_pri_moh_event event)
  * \since 10.0
  *
  * \param pvt Channel private control structure.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4870,7 +4666,7 @@ static enum sig_pri_moh_state sig_pri_moh_retrieve_call(struct sig_pri_chan *pvt
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4934,7 +4730,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_idle(struct ast_channel *chan, str
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -4974,7 +4770,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_notify(struct ast_channel *chan, s
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5011,7 +4807,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_moh(struct ast_channel *chan, stru
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5056,7 +4852,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_hold_req(struct ast_channel *chan,
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5097,7 +4893,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_pend_unhold(struct ast_channel *ch
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5139,7 +4935,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_hold(struct ast_channel *chan, str
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5181,7 +4977,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_req(struct ast_channel *c
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5259,7 +5055,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_pend_hold(struct ast_channel *chan
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5299,7 +5095,7 @@ static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_fail(struct ast_channel *
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5332,7 +5128,7 @@ static const sig_pri_moh_fsm_state sig_pri_moh_fsm[SIG_PRI_MOH_STATE_NUM] = {
  * \param chan Channel to post event to (Usually pvt->owner)
  * \param pvt Channel private control structure.
  * \param event MOH event to process.
- *
+ * 
  * \note Assumes the pvt->pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pvt) is already obtained.
  *
@@ -5365,6 +5161,42 @@ static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan
 		(orig_state == next_state) ? "$" : sig_pri_moh_state_str(next_state));
 }
 
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Post an AMI hold event.
+ * \since 10.0
+ *
+ * \param chan Channel to post event to
+ * \param is_held TRUE if the call was placed on hold.
+ *
+ * \return Nothing
+ */
+static void sig_pri_ami_hold_event(struct ast_channel *chan, int is_held)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a PRI channel is put on Hold.</synopsis>
+			<syntax>
+				<parameter name="Status">
+					<enumlist>
+						<enum name="On"/>
+						<enum name="Off"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "Hold",
+		"Status: %s\r\n"
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n",
+		is_held ? "On" : "Off",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan));
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
+
 /*!
  * \internal
  * \brief Set callid threadstorage for the pri_dchannel thread when a new call is created
@@ -5479,11 +5311,13 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
 		goto done_with_owner;
 	}
 	sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.subcmds, ev->hold.call);
-	sig_pri_queue_hold(pri, chanpos_old);
+	pri_queue_control(pri, chanpos_old, AST_CONTROL_HOLD);
 	chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
 	if (chanpos_new < 0) {
 		/* Should never happen. */
-		sig_pri_queue_unhold(pri, chanpos_old);
+		pri_queue_control(pri, chanpos_old, AST_CONTROL_UNHOLD);
+	} else {
+		sig_pri_ami_hold_event(owner, 1);
 	}
 
 done_with_owner:;
@@ -5671,7 +5505,12 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 	sig_pri_lock_private(pri->pvts[chanpos]);
 	callid = func_pri_dchannel_chanpos_callid(pri, chanpos);
 	sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.subcmds, ev->retrieve.call);
-	sig_pri_queue_unhold(pri, chanpos);
+	sig_pri_lock_owner(pri, chanpos);
+	pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
+	if (pri->pvts[chanpos]->owner) {
+		sig_pri_ami_hold_event(pri->pvts[chanpos]->owner, 0);
+		ast_channel_unlock(pri->pvts[chanpos]->owner);
+	}
 	pri_retrieve_ack(pri->pri, ev->retrieve.call,
 		PVT_TO_CHANNEL(pri->pvts[chanpos]));
 	sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
@@ -5803,8 +5642,6 @@ static void setup_incoming_channel(struct sig_pri_span *pri, int chanpos, pri_ev
 		return;
 	}
 
-	ast_channel_stage_snapshot(owner);
-
 #if defined(HAVE_PRI_SUBADDR)
 	if (ev->ring.calling.subaddress.valid) {
 		/* Set Calling Subaddress */
@@ -5862,16 +5699,10 @@ static void setup_incoming_channel(struct sig_pri_span *pri, int chanpos, pri_ev
 		ev->ring.keypad_digits, sizeof(pri->pvts[chanpos]->keypad_digits));
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
 
-	/*
-	 * It's ok to call this with the owner already locked here
-	 * since it will want to do this anyway if there are any
-	 * subcmds.
-	 */
+	ast_channel_unlock(owner);
+
 	sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->ring.subcmds,
 		ev->ring.call);
-
-	ast_channel_stage_snapshot_done(owner);
-	ast_channel_unlock(owner);
 }
 
 /*!
@@ -6185,7 +6016,7 @@ static void sig_pri_handle_setup(struct sig_pri_span *pri, pri_event *e)
 	ast_mutex_unlock(&pri->lock);
 	c = sig_pri_new_ast_channel(pri->pvts[chanpos],
 		could_match_more ? AST_STATE_RESERVED : AST_STATE_RING, law, e->ring.ctype,
-		pri->pvts[chanpos]->exten, NULL, NULL);
+		pri->pvts[chanpos]->exten, NULL);
 	ast_mutex_lock(&pri->lock);
 	sig_pri_lock_private(pri->pvts[chanpos]);
 
@@ -6357,7 +6188,7 @@ static void *pri_dchannel(void *vpri)
 					 */
 					sig_pri_lock_private(pri->pvts[nextidle]);
 					sig_pri_unlock_private(pri->pvts[nextidle]);
-					idle = sig_pri_request(pri->pvts[nextidle], SIG_PRI_ULAW, NULL, NULL, 0);
+					idle = sig_pri_request(pri->pvts[nextidle], SIG_PRI_ULAW, NULL, 0);
 					ast_mutex_lock(&pri->lock);
 					if (idle) {
 						pri->pvts[nextidle]->isidlecall = 1;
@@ -6454,14 +6285,6 @@ static void *pri_dchannel(void *vpri)
 				}
 				if (e)
 					break;
-
-				if ((errno != 0) && (errno != EINTR)) {
-					ast_log(LOG_NOTICE, "pri_check_event returned error %d (%s)\n",
-						errno, strerror(errno));
-				}
-				if (errno == ENODEV) {
-					pri_destroy_later(pri);
-				}
 			}
 		} else if (errno != EINTR)
 			ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
@@ -6579,9 +6402,8 @@ static void *pri_dchannel(void *vpri)
 								pri->pvts[chanpos]->call = NULL;
 							}
 						}
-						/* Force soft hangup if appropriate */
-						if (pri->pvts[chanpos]->owner)
-							ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+						/* Force hangup if appropriate */
+						sig_pri_queue_hangup(pri, chanpos);
 						sig_pri_unlock_private(pri->pvts[chanpos]);
 					}
 				} else {
@@ -6593,8 +6415,8 @@ static void *pri_dchannel(void *vpri)
 								pri_destroycall(pri->pri, pri->pvts[x]->call);
 								pri->pvts[x]->call = NULL;
 							}
- 							if (pri->pvts[x]->owner)
-								ast_channel_softhangup_internal_flag_add(pri->pvts[x]->owner, AST_SOFTHANGUP_DEV);
+							/* Force hangup if appropriate */
+							sig_pri_queue_hangup(pri, x);
 							sig_pri_unlock_private(pri->pvts[x]);
 						}
 				}
@@ -7125,10 +6947,11 @@ static void *pri_dchannel(void *vpri)
 						break;
 					}
 					if (pri->pvts[chanpos]->owner) {
-						int do_hangup = 0;
-
 						snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
 						pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+					}
+					if (pri->pvts[chanpos]->owner) {
+						int do_hangup = 0;
 
 						/* Queue a BUSY instead of a hangup if our cause is appropriate */
 						ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
@@ -7166,17 +6989,7 @@ static void *pri_dchannel(void *vpri)
 						}
 
 						if (do_hangup) {
-#if defined(HAVE_PRI_AOC_EVENTS)
-							if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-								/* If a AOC-E msg was sent during the release, we must use a
-								 * AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
-								pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-							} else {
-								ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-							}
-#else
-							ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+							sig_pri_queue_hangup(pri, chanpos);
 						}
 					} else {
 						/*
@@ -7194,9 +7007,9 @@ static void *pri_dchannel(void *vpri)
 					pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
 					pri->pvts[chanpos]->call = NULL;
 				}
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
 				if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
 					&& pri->sig != SIG_BRI_PTMP && !pri->resetting
+					&& pri->force_restart_unavailable_chans
 					&& pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
 					ast_verb(3,
 						"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7205,7 +7018,6 @@ static void *pri_dchannel(void *vpri)
 					pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
 					pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
 				}
-#endif	/* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 				if (e->hangup.aoc_units > -1)
 					ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
 						pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
@@ -7255,7 +7067,7 @@ static void *pri_dchannel(void *vpri)
 					/* We are to transfer the call instead of simply hanging up. */
 					sig_pri_unlock_private(pri->pvts[chanpos]);
 					if (!sig_pri_attempt_transfer(pri, e->hangup.call_held, 1,
-						e->hangup.call_active, 0, NULL)) {
+						e->hangup.call_active, 0, NULL, NULL)) {
 						break;
 					}
 					sig_pri_lock_private(pri->pvts[chanpos]);
@@ -7280,10 +7092,11 @@ static void *pri_dchannel(void *vpri)
 					break;
 				}
 				if (pri->pvts[chanpos]->owner) {
-					int do_hangup = 0;
-
 					snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
 					pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+				}
+				if (pri->pvts[chanpos]->owner) {
+					int do_hangup = 0;
 
 					ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
 					switch (ast_channel_state(pri->pvts[chanpos]->owner)) {
@@ -7323,19 +7136,14 @@ static void *pri_dchannel(void *vpri)
 #if defined(HAVE_PRI_AOC_EVENTS)
 						if (!pri->pvts[chanpos]->holding_aoce
 							&& pri->aoce_delayhangup
-							&& ast_channel_is_bridged(pri->pvts[chanpos]->owner)) {
+							&& ast_bridged_channel(pri->pvts[chanpos]->owner)) {
 							sig_pri_send_aoce_termination_request(pri, chanpos,
 								pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
-						} else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-							/* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
-							 * to guarantee that frame gets read before hangup */
-							pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-						} else {
-							ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-						}
-#else
-						ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+						} else
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+						{
+							sig_pri_queue_hangup(pri, chanpos);
+						}
 					}
 					ast_verb(3, "Span %d: Channel %d/%d got hangup request, cause %d\n",
 						pri->span, pri->pvts[chanpos]->logicalspan,
@@ -7348,9 +7156,9 @@ static void *pri_dchannel(void *vpri)
 					pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
 					pri->pvts[chanpos]->call = NULL;
 				}
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
 				if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
 					&& pri->sig != SIG_BRI_PTMP && !pri->resetting
+					&& pri->force_restart_unavailable_chans
 					&& pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
 					ast_verb(3,
 						"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7359,7 +7167,6 @@ static void *pri_dchannel(void *vpri)
 					pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
 					pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
 				}
-#endif	/* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 
 #ifdef SUPPORT_USERUSER
 				if (!ast_strlen_zero(e->hangup.useruserinfo)) {
@@ -7593,12 +7400,12 @@ static void *pri_dchannel(void *vpri)
 				switch (e->notify.info) {
 				case PRI_NOTIFY_REMOTE_HOLD:
 					if (!pri->discardremoteholdretrieval) {
-						sig_pri_queue_hold(pri, chanpos);
+						pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
 					}
 					break;
 				case PRI_NOTIFY_REMOTE_RETRIEVAL:
 					if (!pri->discardremoteholdretrieval) {
-						sig_pri_queue_unhold(pri, chanpos);
+						pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
 					}
 					break;
 				}
@@ -7759,20 +7566,6 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
 		}
 #endif	/* defined(SUPPORT_USERUSER) */
 
-#if defined(HAVE_PRI_TRANSFER)
-		if (p->xfer_data) {
-			/*
-			 * The transferrer call leg is disconnecting.  It must mean that
-			 * the transfer was successful and the core is disconnecting the
-			 * call legs involved.
-			 *
-			 * The transfer protocol response message must go out before the
-			 * call leg is disconnected.
-			 */
-			sig_pri_transfer_rsp(p->xfer_data, 1);
-		}
-#endif	/* defined(HAVE_PRI_TRANSFER) */
-
 #if defined(HAVE_PRI_AOC_EVENTS)
 		if (p->holding_aoce) {
 			pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
@@ -7801,9 +7594,6 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
 			pri_hangup(p->pri->pri, p->call, icause);
 		}
 	}
-#if defined(HAVE_PRI_TRANSFER)
-	p->xfer_data = NULL;
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 #if defined(HAVE_PRI_AOC_EVENTS)
 	p->aoc_s_request_invoke_id_valid = 0;
 	p->holding_aoce = 0;
@@ -8083,7 +7873,7 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
 	if (p->pri->facilityenable)
 		pri_facility_enable(p->pri->pri);
 
-	ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", (unsigned)ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
+	ast_verb(3, "Requested transfer capability: 0x%02hx - %s\n", ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
 	dp_strip = 0;
 	pridialplan = p->pri->dialplan - 1;
 	if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
@@ -8632,16 +8422,18 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
 					if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
 						sig_pri_aoc_e_from_ast(p, decoded);
 					}
-					/* if hangup was delayed for this AOC-E msg, waiting_for_aoc
+					/*
+					 * If hangup was delayed for this AOC-E msg, waiting_for_aoc
 					 * will be set.  A hangup is already occuring via a timeout during
 					 * this delay.  Instead of waiting for that timeout to occur, go ahead
-					 * and initiate the softhangup since the delay is no longer necessary */
+					 * and initiate the hangup since the delay is no longer necessary.
+					 */
 					if (p->waiting_for_aoce) {
 						p->waiting_for_aoce = 0;
 						ast_debug(1,
 							"Received final AOC-E msg, continue with hangup on %s\n",
 							ast_channel_name(chan));
-						ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
+						ast_queue_hangup(chan);
 					}
 					break;
 				case AST_AOC_REQUEST:
@@ -8894,25 +8686,25 @@ void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
  *
  * \param pri PRI span control structure.
  * \param vm_number Voicemail controlling number (NULL if not present).
- * \param vm_box Voicemail mailbox number
- * \param mbox_id Mailbox id
+ * \param mbox_number Mailbox number
+ * \param mbox_context Mailbox context
  * \param num_messages Number of messages waiting.
  *
  * \return Nothing
  */
-static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *vm_box, const char *mbox_id, int num_messages)
+static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *mbox_number, const char *mbox_context, int num_messages)
 {
 	struct pri_party_id voicemail;
 	struct pri_party_id mailbox;
 
-	ast_debug(1, "Send MWI indication for %s(%s) vm_number:%s num_messages:%d\n",
-		vm_box, mbox_id, S_OR(vm_number, "<not-present>"), num_messages);
+	ast_debug(1, "Send MWI indication for %s@%s vm_number:%s num_messages:%d\n",
+		mbox_number, mbox_context, S_OR(vm_number, "<not-present>"), num_messages);
 
 	memset(&mailbox, 0, sizeof(mailbox));
 	mailbox.number.valid = 1;
 	mailbox.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
 	mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
-	ast_copy_string(mailbox.number.str, vm_box, sizeof(mailbox.number.str));
+	ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str));
 
 	memset(&voicemail, 0, sizeof(voicemail));
 	voicemail.number.valid = 1;
@@ -8939,35 +8731,39 @@ static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm
  * \brief MWI subscription event callback.
  * \since 1.8
  *
- * \param userdata the data provider in the call to stasis_subscribe()
- * \param sub the subscription to which the message was delivered for this callback
- * \param topic the topic on which the message was published
- * \param msg the message being passed to the subscriber
+ * \param event the event being passed to the subscriber
+ * \param userdata the data provider in the call to ast_event_subscribe()
  *
  * \return Nothing
  */
-static void sig_pri_mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	struct sig_pri_span *pri = userdata;
+	const char *mbox_context;
+	const char *mbox_number;
+	int num_messages;
 	int idx;
-	struct ast_mwi_state *mwi_state;
 
-	if (ast_mwi_state_type() != stasis_message_type(msg)) {
+	mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+	if (ast_strlen_zero(mbox_number)) {
 		return;
 	}
-
-	mwi_state = stasis_message_data(msg);
+	mbox_context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
+	if (ast_strlen_zero(mbox_context)) {
+		return;
+	}
+	num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
 
 	for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
 		if (!pri->mbox[idx].sub) {
 			/* Mailbox slot is empty */
 			continue;
 		}
-
-		if (!strcmp(pri->mbox[idx].uniqueid, mwi_state->uniqueid)) {
+		if (!strcmp(pri->mbox[idx].number, mbox_number)
+			&& !strcmp(pri->mbox[idx].context, mbox_context)) {
 			/* Found the mailbox. */
-			sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number,
-				pri->mbox[idx].vm_box, pri->mbox[idx].uniqueid, mwi_state->new_msgs);
+			sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, mbox_number,
+				mbox_context, num_messages);
 			break;
 		}
 	}
@@ -8987,25 +8783,27 @@ static void sig_pri_mwi_event_cb(void *userdata, struct stasis_subscription *sub
 static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
 {
 	int idx;
-	struct ast_mwi_state *mwi_state;
+	int num_messages;
+	struct ast_event *event;
 
 	for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
-		RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 		if (!pri->mbox[idx].sub) {
 			/* Mailbox slot is empty */
 			continue;
 		}
 
-		msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(),
-			pri->mbox[idx].uniqueid);
-		if (!msg) {
+		event = ast_event_get_cached(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].number,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].context,
+			AST_EVENT_IE_END);
+		if (!event) {
 			/* No cached event for this mailbox. */
 			continue;
 		}
-
-		mwi_state = stasis_message_data(msg);
-		sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].vm_box,
-			pri->mbox[idx].uniqueid, mwi_state->new_msgs);
+		num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+		sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].number,
+			pri->mbox[idx].context, num_messages);
+		ast_event_destroy(event);
 	}
 }
 #endif	/* defined(HAVE_PRI_MWI) */
@@ -9027,7 +8825,7 @@ void sig_pri_stop_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
 	for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
 		if (pri->mbox[idx].sub) {
-			pri->mbox[idx].sub = stasis_unsubscribe(pri->mbox[idx].sub);
+			pri->mbox[idx].sub = ast_event_unsubscribe(pri->mbox[idx].sub);
 		}
 	}
 #endif	/* defined(HAVE_PRI_MWI) */
@@ -9090,13 +8888,14 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
 	char *saveptr;
 	char *prev_vm_number;
+	struct ast_str *mwi_description = ast_str_alloca(64);
 #endif	/* defined(HAVE_PRI_MWI) */
 
 #if defined(HAVE_PRI_MWI)
 	/* Prepare the mbox[] for use. */
 	for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
 		if (pri->mbox[i].sub) {
-			pri->mbox[i].sub = stasis_unsubscribe(pri->mbox[i].sub);
+			pri->mbox[i].sub = ast_event_unsubscribe(pri->mbox[i].sub);
 		}
 	}
 #endif	/* defined(HAVE_PRI_MWI) */
@@ -9129,61 +8928,53 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
 	}
 
 	/*
-	 * Split the mwi_vm_boxes configuration string into the mbox[].vm_box:
-	 * vm_box{,vm_box}
-	 */
-	saveptr = pri->mwi_vm_boxes;
-	for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
-		char *vm_box;
-
-		vm_box = strsep(&saveptr, ",");
-		if (vm_box) {
-			vm_box = ast_strip(vm_box);
-			if (ast_strlen_zero(vm_box)) {
-				vm_box = NULL;
-			}
-		}
-		pri->mbox[i].vm_box = vm_box;
-	}
-
-	/*
 	 * Split the mwi_mailboxes configuration string into the mbox[]:
-	 * vm_mailbox{,vm_mailbox}
+	 * mailbox_number[@context]{,mailbox_number[@context]}
 	 */
 	saveptr = pri->mwi_mailboxes;
 	for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
-		char *mbox_id;
-		struct stasis_topic *mailbox_specific_topic;
-
-		mbox_id = strsep(&saveptr, ",");
-		if (mbox_id) {
-			mbox_id = ast_strip(mbox_id);
-			if (ast_strlen_zero(mbox_id)) {
-				mbox_id = NULL;
-			}
+		char *mbox_number;
+		char *mbox_context;
+
+		mbox_number = strsep(&saveptr, ",");
+		if (!mbox_number) {
+			/* No more defined mailboxes. */
+			break;
 		}
-		pri->mbox[i].uniqueid = mbox_id;
-		if (!pri->mbox[i].vm_box || !mbox_id) {
-			/* The mailbox position is disabled. */
-			ast_debug(1, "%s span %d MWI position %d disabled.  vm_box:%s mbox_id:%s.\n",
-				sig_pri_cc_type_name, pri->span, i,
-				pri->mbox[i].vm_box ?: "<missing>",
-				mbox_id ?: "<missing>");
-			continue;
+		/* Split the mailbox_number and context */
+		mbox_context = strchr(mbox_number, '@');
+		if (mbox_context) {
+			*mbox_context++ = '\0';
+			mbox_context = ast_strip(mbox_context);
 		}
-
-		mailbox_specific_topic = ast_mwi_topic(mbox_id);
-		if (mailbox_specific_topic) {
-			pri->mbox[i].sub = stasis_subscribe_pool(mailbox_specific_topic, sig_pri_mwi_event_cb, pri);
+		mbox_number = ast_strip(mbox_number);
+		if (ast_strlen_zero(mbox_number)) {
+			/* There is no mailbox number.  Skip it. */
+			continue;
 		}
+		if (ast_strlen_zero(mbox_context)) {
+			/* There was no context so use the default. */
+			mbox_context = "default";
+		}
+
+		/* Fill the mbox[] element. */
+		pri->mbox[i].number = mbox_number;
+		pri->mbox[i].context = mbox_context;
+		ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
+			sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
+		pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb,
+			ast_str_buffer(mwi_description), pri,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox_number,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, mbox_context,
+			AST_EVENT_IE_END);
 		if (!pri->mbox[i].sub) {
-			ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s(%s).\n",
-				sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
+			ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.",
+				sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
 		}
 #if defined(HAVE_PRI_MWI_V2)
 		if (ast_strlen_zero(pri->mbox[i].vm_number)) {
-			ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s(%s) is empty.\n",
-				sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
+			ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s@%s is empty.\n",
+				sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
 		}
 #endif	/* defined(HAVE_PRI_MWI_V2) */
 	}
@@ -9312,7 +9103,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
  *
  * \param p Channel private pointer.
  * \param noalarm Non-zero if not in alarm mode.
- *
+ * 
  * \note Assumes the sig_pri_lock_private(p) is already obtained.
  *
  * \return Nothing
@@ -10171,12 +9962,6 @@ void sig_pri_cc_monitor_destructor(void *monitor_pvt)
  */
 int sig_pri_load(const char *cc_type_name)
 {
-#if defined(HAVE_PRI_MCID)
-	if (STASIS_MESSAGE_TYPE_INIT(mcid_type)) {
-		return -1;
-	}
-#endif	/* defined(HAVE_PRI_MCID) */
-
 #if defined(HAVE_PRI_CCSS)
 	sig_pri_cc_type_name = cc_type_name;
 	sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
@@ -10202,10 +9987,6 @@ void sig_pri_unload(void)
 		sig_pri_cc_monitors = NULL;
 	}
 #endif	/* defined(HAVE_PRI_CCSS) */
-
-#if defined(HAVE_PRI_MCID)
-	STASIS_MESSAGE_TYPE_CLEANUP(mcid_type);
-#endif	/* defined(HAVE_PRI_MCID) */
 }
 
 #endif /* HAVE_PRI */
diff --git a/channels/sig_pri.h b/channels/sig_pri.h
index 12f3dca..1a95b6e 100644
--- a/channels/sig_pri.h
+++ b/channels/sig_pri.h
@@ -27,6 +27,7 @@
 
 #include "asterisk/channel.h"
 #include "asterisk/frame.h"
+#include "asterisk/event.h"
 #include "asterisk/ccss.h"
 #include <libpri.h>
 #include <dahdi/user.h>
@@ -171,7 +172,6 @@ enum sig_pri_reset_state {
 };
 
 struct sig_pri_span;
-struct xfer_rsp_data;
 
 struct sig_pri_callback {
 	/* Unlock the private in the signalling private structure.  This is used for three way calling madness. */
@@ -192,9 +192,7 @@ struct sig_pri_callback {
 	int (* const train_echocanceller)(void *pvt);
 	int (* const dsp_reset_and_flush_digits)(void *pvt);
 
-	struct ast_channel * (* const new_ast_channel)(void *pvt, int state,
-		enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
-		const struct ast_channel *requestor);
+	struct ast_channel * (* const new_ast_channel)(void *pvt, int state, enum sig_pri_law law, char *exten, const struct ast_channel *chan);
 
 	void (* const fixup_chans)(void *old_chan, void *new_chan);
 
@@ -231,8 +229,6 @@ struct sig_pri_callback {
 	void (*module_ref)(void);
 	/*! Unreference the parent module. */
 	void (*module_unref)(void);
-	/*! Mark the span for destruction. */
-	void (*destroy_later)(struct sig_pri_span *pri);
 };
 
 /*! Global sig_pri callbacks to the upper layer. */
@@ -361,10 +357,6 @@ struct sig_pri_chan {
 	enum sig_pri_call_level call_level;
 	/*! \brief Channel reset/restart state. */
 	enum sig_pri_reset_state resetting;
-#if defined(HAVE_PRI_TRANSFER)
-	/*! If non-NULL, send transfer disconnect successfull response to first call disconnecting. */
-	struct xfer_rsp_data *xfer_data;
-#endif	/* defined(HAVE_PRI_TRANSFER) */
 	int prioffset;					/*!< channel number in span */
 	int logicalspan;				/*!< logical span number within trunk group */
 	int mastertrunkgroup;			/*!< what trunk group is our master */
@@ -396,7 +388,7 @@ struct sig_pri_chan {
 /*! Typical maximum length of mwi mailbox context */
 #define SIG_PRI_MAX_MWI_CONTEXT_LEN			10
 /*!
- * \brief Maximum mwi_vm_numbers and mwi_vm_boxes string length.
+ * \brief Maximum mwi_vm_numbers string length.
  * \details
  * max_length = #mailboxes * (vm_number + ',')
  * The last ',' is a null terminator instead.
@@ -404,32 +396,25 @@ struct sig_pri_chan {
 #define SIG_PRI_MAX_MWI_VM_NUMBER_STR	(SIG_PRI_MAX_MWI_MAILBOXES \
 	* (SIG_PRI_MAX_MWI_VM_NUMBER_LEN + 1))
 /*!
- * \brief Maximum length of vm_mailbox string.
- * \details
- * max_length = vm_box + '@' + context.
- */
-#define SIG_PRI_MAX_MWI_VM_MAILBOX		(SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN \
-	+ 1 + SIG_PRI_MAX_MWI_CONTEXT_LEN)
-/*!
  * \brief Maximum mwi_mailboxs string length.
  * \details
- * max_length = #mailboxes * (vm_mailbox + ',')
+ * max_length = #mailboxes * (mbox_number + '@' + context + ',')
  * The last ',' is a null terminator instead.
  */
 #define SIG_PRI_MAX_MWI_MAILBOX_STR		(SIG_PRI_MAX_MWI_MAILBOXES	\
-	* (SIG_PRI_MAX_MWI_VM_MAILBOX + 1))
+	* (SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN + 1 + SIG_PRI_MAX_MWI_CONTEXT_LEN + 1))
 
 struct sig_pri_mbox {
 	/*!
 	 * \brief MWI mailbox event subscription.
 	 * \note NULL if mailbox not configured.
 	 */
-	struct stasis_subscription *sub;
-	/*! \brief Mailbox uniqueid. */
-	const char *uniqueid;
-	/*! \brief Mailbox number sent to span. */
-	const char *vm_box;
-	/*! \brief Voicemail access controlling number sent to span. */
+	struct ast_event_sub *sub;
+	/*! \brief Mailbox number */
+	const char *number;
+	/*! \brief Mailbox context. */
+	const char *context;
+	/*! \brief Voicemail controlling number. */
 	const char *vm_number;
 };
 #endif	/* defined(HAVE_PRI_MWI) */
@@ -497,6 +482,8 @@ struct sig_pri_span {
 	/*! \brief TRUE if allow sending MCID request on this span. */
 	unsigned int mcid_send:1;
 #endif	/* defined(HAVE_PRI_MCID) */
+	/*! \brief TRUE if forcing RESTART when receive cause 44 on this span. */
+	unsigned int force_restart_unavailable_chans:1;
 #if defined(HAVE_PRI_DATETIME_SEND)
 	/*! \brief Configured date/time ie send policy option. */
 	int datetime_send;
@@ -523,18 +510,11 @@ struct sig_pri_span {
 	/*!
 	 * \brief Comma separated list of mailboxes to indicate MWI.
 	 * \note Empty if disabled.
-	 * \note Format: vm_mailbox{,vm_mailbox}
+	 * \note Format: mailbox_number[@context]{,mailbox_number[@context]}
 	 * \note String is split apart when span is started.
 	 */
 	char mwi_mailboxes[SIG_PRI_MAX_MWI_MAILBOX_STR];
 	/*!
-	 * \brief Comma separated list of mailbox numbers sent over ISDN span for MWI.
-	 * \note Empty if disabled.
-	 * \note Format: vm_box{,vm_box}
-	 * \note String is split apart when span is started.
-	 */
-	char mwi_vm_boxes[SIG_PRI_MAX_MWI_VM_NUMBER_STR];
-	/*!
 	 * \brief Comma separated list of voicemail access controlling numbers for MWI.
 	 * \note Format: vm_number{,vm_number}
 	 * \note String is split apart when span is started.
@@ -622,7 +602,7 @@ struct sig_pri_span {
 	 * AST_DEVICE_BUSY - All B channels are in use.
 	 * AST_DEVICE_UNAVAILABLE - Span is in alarm.
 	 * \note
-	 * Device name: \verbatim DAHDI/I<span>/congestion. \endverbatim
+	 * Device name: \startverbatim DAHDI/I<span>/congestion. \endverbatim
 	 */
 	int congestion_devstate;
 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
@@ -677,9 +657,7 @@ int sig_pri_is_alarm_ignored(struct sig_pri_span *pri);
 void pri_event_alarm(struct sig_pri_span *pri, int index, int before_start_pri);
 void pri_event_noalarm(struct sig_pri_span *pri, int index, int before_start_pri);
 
-struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	int transfercapability);
+struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability);
 
 struct sig_pri_chan *sig_pri_chan_new(void *pvt_data, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup);
 void sig_pri_chan_delete(struct sig_pri_chan *doomed);
diff --git a/channels/sig_ss7.c b/channels/sig_ss7.c
index a7df9e9..e6e11be 100644
--- a/channels/sig_ss7.c
+++ b/channels/sig_ss7.c
@@ -41,14 +41,10 @@
 #include "asterisk/causes.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/cli.h"
-#include "asterisk/callerid.h"
 #include "asterisk/transcap.h"
-#include "asterisk/stasis_channels.h"
 
 #include "sig_ss7.h"
-#if !defined(LIBSS7_ABI_COMPATIBILITY)
-#error "Upgrade your libss7"
-#elif LIBSS7_ABI_COMPATIBILITY != 2
+#if defined(LIBSS7_ABI_COMPATIBILITY)
 #error "Your installed libss7 is not compatible"
 #endif
 
@@ -71,6 +67,8 @@ static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level)
 		return "Alerting";
 	case SIG_SS7_CALL_LEVEL_CONNECT:
 		return "Connect";
+	case SIG_SS7_CALL_LEVEL_GLARE:
+		return "Glare";
 	}
 	return "Unknown";
 }
@@ -133,35 +131,24 @@ static void sig_ss7_set_outgoing(struct sig_ss7_chan *p, int is_outgoing)
 
 static void sig_ss7_set_inservice(struct sig_ss7_chan *p, int is_inservice)
 {
-	p->inservice = is_inservice;
 	if (sig_ss7_callbacks.set_inservice) {
 		sig_ss7_callbacks.set_inservice(p->chan_pvt, is_inservice);
 	}
 }
 
-static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked, int type)
+static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked)
 {
-	if (is_blocked) {
-		p->locallyblocked |= type;
-	} else {
-		p->locallyblocked &= ~type;
-	}
-
+	p->locallyblocked = is_blocked;
 	if (sig_ss7_callbacks.set_locallyblocked) {
-		sig_ss7_callbacks.set_locallyblocked(p->chan_pvt, p->locallyblocked);
+		sig_ss7_callbacks.set_locallyblocked(p->chan_pvt, is_blocked);
 	}
 }
 
-static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked, int type)
+static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked)
 {
-	if (is_blocked) {
-		p->remotelyblocked |= type;
-	} else {
-		p->remotelyblocked &= ~type;
-	}
-
+	p->remotelyblocked = is_blocked;
 	if (sig_ss7_callbacks.set_remotelyblocked) {
-		sig_ss7_callbacks.set_remotelyblocked(p->chan_pvt, p->remotelyblocked);
+		sig_ss7_callbacks.set_remotelyblocked(p->chan_pvt, is_blocked);
 	}
 }
 
@@ -270,15 +257,12 @@ static void sig_ss7_loopback(struct sig_ss7_chan *p, int enable)
 	}
 }
 
-static struct ast_channel *sig_ss7_new_ast_channel(struct sig_ss7_chan *p, int state,
-	int ulaw, int transfercapability, char *exten,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
+static struct ast_channel *sig_ss7_new_ast_channel(struct sig_ss7_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor)
 {
 	struct ast_channel *ast;
 
 	if (sig_ss7_callbacks.new_ast_channel) {
-		ast = sig_ss7_callbacks.new_ast_channel(p->chan_pvt, state, ulaw, exten,
-			assignedids, requestor);
+		ast = sig_ss7_callbacks.new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
 	} else {
 		return NULL;
 	}
@@ -289,13 +273,7 @@ static struct ast_channel *sig_ss7_new_ast_channel(struct sig_ss7_chan *p, int s
 	if (!p->owner) {
 		p->owner = ast;
 	}
-
-	if (p->outgoing) {
-		p->do_hangup = SS7_HANGUP_FREE_CALL;
-	} else {
-		p->do_hangup = SS7_HANGUP_SEND_REL;
-	}
-
+	p->alreadyhungup = 0;
 	ast_channel_transfercapability_set(ast, transfercapability);
 	pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY",
 		ast_transfercapability2str(transfercapability));
@@ -313,14 +291,6 @@ static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int w
 	}
 }
 
-static struct sig_ss7_linkset *sig_ss7_find_linkset(struct ss7 *ss7)
-{
-	if (sig_ss7_callbacks.find_linkset) {
-		return sig_ss7_callbacks.find_linkset(ss7);
-	}
-	return NULL;
-}
-
 /*!
  * \internal
  * \brief Determine if a private channel structure is available.
@@ -331,7 +301,7 @@ static struct sig_ss7_linkset *sig_ss7_find_linkset(struct ss7 *ss7)
  */
 static int sig_ss7_is_chan_available(struct sig_ss7_chan *pvt)
 {
-	if (pvt->inservice && !pvt->inalarm && !pvt->owner && !pvt->ss7call
+	if (!pvt->inalarm && !pvt->owner && !pvt->ss7call
 		&& pvt->call_level == SIG_SS7_CALL_LEVEL_IDLE
 		&& !pvt->locallyblocked && !pvt->remotelyblocked) {
 		return 1;
@@ -424,7 +394,7 @@ static void sig_ss7_queue_control(struct sig_ss7_linkset *ss7, int chanpos, int
 /*!
  * \internal
  * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
- * \since 11.0
+ * \since 11
  *
  * \param owner Owner channel of the pvt.
  * \param cause String describing the cause to be placed into the frame.
@@ -451,6 +421,7 @@ static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *caus
 
 
 /*!
+ * \internal
  * \brief Find the channel position by CIC/DPC.
  *
  * \param linkset SS7 linkset control structure.
@@ -460,7 +431,7 @@ static void ss7_queue_pvt_cause_data(struct ast_channel *owner, const char *caus
  * \retval chanpos on success.
  * \retval -1 on error.
  */
-int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
+static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
 {
 	int i;
 	int winner = -1;
@@ -489,206 +460,45 @@ static int ss7_find_cic_gripe(struct sig_ss7_linkset *linkset, int cic, unsigned
 {
 	int chanpos;
 
-	chanpos = sig_ss7_find_cic(linkset, cic, dpc);
+	chanpos = ss7_find_cic(linkset, cic, dpc);
 	if (chanpos < 0) {
-		ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested on unconfigured CIC/DPC %d/%d.\n",
+		ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d.\n",
 			linkset->span, msg_name, cic, dpc);
 		return -1;
 	}
 	return chanpos;
 }
 
-static struct sig_ss7_chan *ss7_find_pvt(struct ss7 *ss7, int cic, unsigned int dpc)
-{
-	int chanpos;
-	struct sig_ss7_linkset *winner;
-
-	winner = sig_ss7_find_linkset(ss7);
-	if (winner && (chanpos = sig_ss7_find_cic(winner, cic, dpc)) > -1) {
-		return winner->pvts[chanpos];
-	}
-	return NULL;
-}
-
-int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)
-{
-	struct sig_ss7_chan *p;
-	int res;
-
-	if (!(p = ss7_find_pvt(ss7, cic, dpc))) {
-		return SS7_CIC_NOT_EXISTS;
-	}
-
-	sig_ss7_lock_private(p);
-	if (p->owner) {
-		ast_channel_hangupcause_set(p->owner, cause);
-		ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
-		p->do_hangup = do_hangup;
-		res = SS7_CIC_USED;
-	} else {
-		res = SS7_CIC_IDLE;
-	}
-	sig_ss7_unlock_private(p);
-
-	return res;
-}
-
-void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *call, int lock)
-{
-	int i;
-	struct sig_ss7_linkset *winner;
-
-	winner = sig_ss7_find_linkset(ss7);
-	if (!winner) {
-		return;
-	}
-	for (i = 0; i < winner->numchans; i++) {
-		if (winner->pvts[i] && (winner->pvts[i]->ss7call == call)) {
-			if (lock) {
-				sig_ss7_lock_private(winner->pvts[i]);
-			}
-			winner->pvts[i]->ss7call = NULL;
-			if (winner->pvts[i]->owner) {
-				ast_channel_hangupcause_set(winner->pvts[i]->owner, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
-				ast_channel_softhangup_internal_flag_add(winner->pvts[i]->owner, AST_SOFTHANGUP_DEV);
-			}
-			if (lock) {
-				sig_ss7_unlock_private(winner->pvts[i]);
-			}
-			ast_log(LOG_WARNING, "libss7 asked set ss7 call to NULL on CIC %d DPC %d\n", winner->pvts[i]->cic, winner->pvts[i]->dpc);
-		}
-	}
-}
-
-void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc)
-{
-	struct sig_ss7_chan *p;
-
-	if (!(p = ss7_find_pvt(ss7, cic, dpc))) {
-		return;
-	}
-
-	sig_ss7_lock_private(p);
-	sig_ss7_set_inservice(p, 0);
-	sig_ss7_unlock_private(p);
-}
-
-/*!
- * \internal
- * \brief Check if CICs in a range belong to the linkset for a given DPC.
- * \since 11.0
- *
- * \param linkset SS7 linkset control structure.
- * \param startcic Circuit Identification Code to start from
- * \param endcic Circuit Identification Code to search up-to
- * \param dpc Destination Point Code
- * \param state Array containing the status of the search
- *
- * \retval Nothing.
- */
-static void ss7_check_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char *state)
-{
-	int cic;
-
-	for (cic = startcic; cic <= endcic; cic++) {
-		if (state[cic - startcic] && sig_ss7_find_cic(linkset, cic, dpc) == -1) {
-			state[cic - startcic] = 0;
-		}
-	}
-}
-
-static int ss7_match_range(struct sig_ss7_chan *pvt, int startcic, int endcic, unsigned int dpc)
-{
-	if (pvt && pvt->dpc == dpc && pvt->cic >= startcic && pvt->cic <= endcic) {
-		return 1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Check if a range is defined for the given DPC.
- * \since 11.0
- *
- * \param linkset SS7 linkset control structure.
- * \param startcic Start CIC of the range to clear.
- * \param endcic End CIC of the range to clear.
- * \param dpc Destination Point Code.
- *
- * \note Assumes the linkset->lock is already obtained.
- *
- * \return TRUE if all CICs in the range are present
- */
-int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
-{
-	int i, found = 0;
-
-	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
-			found++;
-		}
-	}
-
-	if (found == endcic - startcic + 1) {
-		return  1;
-	}
-
-	return 0;
-}
-
-static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, ss7_event *e)
+static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
 {
 	unsigned char status[32];
 	struct sig_ss7_chan *p = NULL;
-	int i;
-	int offset;
-	int chanpos;
+	int i, offset;
 
-	memset(status, 0, sizeof(status));
 	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], e->cqm.startcic, e->cqm.endcic, e->cqm.opc)) {
+		if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
 			p = linkset->pvts[i];
-			sig_ss7_lock_private(p);
-			offset = p->cic - e->cqm.startcic;
+			offset = p->cic - startcic;
 			status[offset] = 0;
-			if (p->locallyblocked) {
+			if (p->locallyblocked)
 				status[offset] |= (1 << 0) | (1 << 4);
-			}
-			if (p->remotelyblocked) {
+			if (p->remotelyblocked)
 				status[offset] |= (1 << 1) | (1 << 5);
-			}
 			if (p->ss7call) {
-				if (p->outgoing) {
+				if (p->outgoing)
 					status[offset] |= (1 << 3);
-				} else {
+				else
 					status[offset] |= (1 << 2);
-				}
-			} else {
+			} else
 				status[offset] |= 0x3 << 2;
-			}
-			sig_ss7_unlock_private(p);
 		}
 	}
 
-	if (p) {
-		isup_cqr(linkset->ss7, e->cqm.startcic, e->cqm.endcic, e->cqm.opc, status);
-	} else {
+	if (p)
+		isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
+	else
 		ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
-	}
 
-	chanpos = sig_ss7_find_cic(linkset, e->cqm.startcic, e->cqm.opc);
-	if (chanpos < 0) {
-		isup_free_call(linkset->ss7, e->cqm.call);
-		return;
-	}
-	p = linkset->pvts[chanpos];
-	sig_ss7_lock_private(p);
-	p->ss7call = e->cqm.call;
-	if (!p->owner) {
-		p->ss7call = isup_free_call_if_clear(linkset->ss7, e->cqm.call);
-	}
-	sig_ss7_unlock_private(p);
 }
 
 static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
@@ -696,7 +506,7 @@ static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic
 	int i;
 
 	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
+		if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
 			sig_ss7_lock_private(linkset->pvts[i]);
 			sig_ss7_lock_owner(linkset, i);
 			if (linkset->pvts[i]->owner) {
@@ -708,274 +518,67 @@ static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic
 	}
 }
 
-/*!
- * \param linkset SS7 linkset control structure.
- * \param startcic Start CIC of the range to clear.
- * \param endcic End CIC of the range to clear.
- * \param dpc Destination Point Code.
- * \param state Affected CICs from the operation. NULL for all CICs in the range.
- * \param block Operation to perform. TRUE to block.
- * \param remotely Direction of the blocking. TRUE to block/unblock remotely.
- * \param type Blocking type - hardware or maintenance.
- *
- * \note Assumes the linkset->lock is already obtained.
- * \note Must be called without sig_ss7_lock_private() obtained.
- *
- * \return Nothing.
- */
-static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block, int remotely, int type)
+static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
 {
 	int i;
 
+	/* XXX the use of state here seems questionable about matching up with the linkset channels */
 	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
-			sig_ss7_lock_private(linkset->pvts[i]);
+		if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
 			if (state) {
-				if (state[linkset->pvts[i]->cic - startcic]) {
-
-					if (remotely) {
-						sig_ss7_set_remotelyblocked(linkset->pvts[i], block, type);
-					} else {
-						sig_ss7_set_locallyblocked(linkset->pvts[i], block, type);
-					}
-
-					sig_ss7_lock_owner(linkset, i);
-					if (linkset->pvts[i]->owner) {
-						if (ast_channel_state(linkset->pvts[i]->owner) == AST_STATE_DIALING
-							&& linkset->pvts[i]->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
-							ast_channel_hangupcause_set(linkset->pvts[i]->owner, SS7_CAUSE_TRY_AGAIN);
-						}
-						ast_channel_unlock(linkset->pvts[i]->owner);
-					}
-				}
-			} else {
-				if (remotely) {
-					sig_ss7_set_remotelyblocked(linkset->pvts[i], block, type);
-				} else {
-					sig_ss7_set_locallyblocked(linkset->pvts[i], block, type);
-				}
-			}
-			sig_ss7_unlock_private(linkset->pvts[i]);
+				if (state[i])
+					sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
+			} else
+				sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
 		}
 	}
 }
 
-/*!
- * \param linkset SS7 linkset control structure.
- * \param startcic Start CIC of the range to set in service.
- * \param endcic End CIC of the range to set in service.
- * \param dpc Destination Point Code.
- *
- * \note Must be called without sig_ss7_lock_private() obtained.
- *
- * \return Nothing.
- */
 static void ss7_inservice(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
 {
 	int i;
 
 	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
-			sig_ss7_lock_private(linkset->pvts[i]);
+		if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
 			sig_ss7_set_inservice(linkset->pvts[i], 1);
-			sig_ss7_unlock_private(linkset->pvts[i]);
-		}
-	}
-}
-
-static int ss7_find_alloc_call(struct sig_ss7_chan *p)
-{
-	if (!p) {
-		return 0;
-	}
-
-	if (!p->ss7call) {
-		p->ss7call = isup_new_call(p->ss7->ss7, p->cic, p->dpc, 0);
-		if (!p->ss7call) {
-			return 0;
-		}
 	}
-	return 1;
 }
 
-/*
- * XXX This routine is not tolerant of holes in the pvts[] array.
- * XXX This routine assumes the cic's in the pvts[] array are sorted.
- *
- * Probably the easiest way to deal with the invalid assumptions
- * is to have a local pvts[] array and sort it by dpc and cic.
- * Then the existing algorithm could work.
- */
 static void ss7_reset_linkset(struct sig_ss7_linkset *linkset)
 {
-	int i, startcic, endcic, dpc;
-	struct sig_ss7_chan *p;
+	int i, startcic = -1, endcic, dpc;
 
-	if (linkset->numchans <= 0) {
+	if (linkset->numchans <= 0)
 		return;
-	}
 
 	startcic = linkset->pvts[0]->cic;
-	p = linkset->pvts[0];
 	/* DB: CIC's DPC fix */
 	dpc = linkset->pvts[0]->dpc;
 
 	for (i = 0; i < linkset->numchans; i++) {
-		if (linkset->pvts[i+1]
-			&& linkset->pvts[i+1]->dpc == dpc
-			&& linkset->pvts[i+1]->cic - linkset->pvts[i]->cic == 1
-			&& linkset->pvts[i]->cic - startcic < (linkset->type == SS7_ANSI ? 24 : 31)) {
+		if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
 			continue;
 		} else {
 			endcic = linkset->pvts[i]->cic;
-			ast_verb(1, "Resetting CICs %d to %d\n", startcic, endcic);
-
-			sig_ss7_lock_private(p);
-			if (!ss7_find_alloc_call(p)) {
-				ast_log(LOG_ERROR, "Unable to allocate new ss7call\n");
-			} else if (!(endcic - startcic)) {	/* GRS range can not be 0 - use RSC instead */
-				isup_rsc(linkset->ss7, p->ss7call);
-			} else {
-				isup_grs(linkset->ss7, p->ss7call, endcic);
-			}
-			sig_ss7_unlock_private(p);
+			ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
+			isup_grs(linkset->ss7, startcic, endcic, dpc);
 
 			/* DB: CIC's DPC fix */
 			if (linkset->pvts[i+1]) {
 				startcic = linkset->pvts[i+1]->cic;
 				dpc = linkset->pvts[i+1]->dpc;
-				p = linkset->pvts[i+1];
-			}
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Complete the RSC procedure started earlier
- * \since 11.0
- *
- * \param p Signaling private structure pointer.
- *
- * \note Assumes the ss7->lock is already obtained.
- * \note Assumes sig_ss7_lock_private(p) is already obtained.
- *
- * \return Nothing.
- */
-static void ss7_do_rsc(struct sig_ss7_chan *p)
-{
-	if (!p || !p->ss7call) {
-		return;
-	}
-
-	isup_rsc(p->ss7->ss7, p->ss7call);
-
-	if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
-		isup_blo(p->ss7->ss7, p->ss7call);
-	} else {
-		sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-	}
-}
-
-/*!
- * \internal
- * \brief Start RSC procedure on a specific link
- * \since 11.0
- *
- * \param ss7 SS7 linkset control structure.
- * \param which Channel position in the span.
- *
- * \note Assumes the ss7->lock is already obtained.
- * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
- *
- * \return TRUE on success
- */
-static int ss7_start_rsc(struct sig_ss7_linkset *linkset, int which)
-{
-	if (!linkset->pvts[which]) {
-		return 0;
-	}
-
-	if (!ss7_find_alloc_call(linkset->pvts[which])) {
-		return 0;
-	}
-
-	sig_ss7_set_remotelyblocked(linkset->pvts[which], 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-	sig_ss7_set_inservice(linkset->pvts[which], 0);
-	sig_ss7_loopback(linkset->pvts[which], 0);
-
-	sig_ss7_lock_owner(linkset, which);
-	if (linkset->pvts[which]->owner) {
-		ast_channel_hangupcause_set(linkset->pvts[which]->owner, AST_CAUSE_NORMAL_CLEARING);
-		ast_softhangup_nolock(linkset->pvts[which]->owner, AST_SOFTHANGUP_DEV);
-		ast_channel_unlock(linkset->pvts[which]->owner);
-		linkset->pvts[which]->do_hangup = SS7_HANGUP_SEND_RSC;
-	} else {
-		ss7_do_rsc(linkset->pvts[which]);
-	}
-
-	return 1;
-}
-
-/*!
- * \internal
- * \brief Determine if a private channel structure is available.
- * \since 11.0
- *
- * \param linkset SS7 linkset control structure.
- * \param startcic Start CIC of the range to clear.
- * \param endcic End CIC of the range to clear.
- * \param dpc Destination Point Code.
- * \param do_hangup What we have to do to clear the call.
- *
- * \note Assumes the linkset->lock is already obtained.
- * \note Must be called without sig_ss7_lock_private() obtained.
- *
- * \return Nothing.
- */
-static void ss7_clear_channels(struct sig_ss7_linkset *linkset, int startcic, int endcic, int dpc, int do_hangup)
-{
-	int i;
-
-	for (i = 0; i < linkset->numchans; i++) {
-		if (ss7_match_range(linkset->pvts[i], startcic, endcic, dpc)) {
-			sig_ss7_lock_private(linkset->pvts[i]);
-			sig_ss7_set_inservice(linkset->pvts[i], 0);
-			sig_ss7_lock_owner(linkset, i);
-			if (linkset->pvts[i]->owner) {
-				ast_channel_hangupcause_set(linkset->pvts[i]->owner,
-											AST_CAUSE_NORMAL_CLEARING);
-				ast_softhangup_nolock(linkset->pvts[i]->owner, AST_SOFTHANGUP_DEV);
-				ast_channel_unlock(linkset->pvts[i]->owner);
-				linkset->pvts[i]->do_hangup = (linkset->pvts[i]->cic != startcic) ?
-											do_hangup : SS7_HANGUP_DO_NOTHING;
-			} else if (linkset->pvts[i] && linkset->pvts[i]->cic != startcic) {
-				isup_free_call(linkset->pvts[i]->ss7->ss7, linkset->pvts[i]->ss7call);
-				linkset->pvts[i]->ss7call = NULL;
 			}
-			sig_ss7_unlock_private(linkset->pvts[i]);
 		}
 	}
 }
 
-/*!
- * \internal
- *
- * \param p Signaling private structure pointer.
- * \param linkset SS7 linkset control structure.
- *
- * \note Assumes the linkset->lock is already obtained.
- * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
- *
- * \return Nothing.
- */
+/* This function is assumed to be called with the private channel lock and linkset lock held */
 static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *linkset)
 {
 	struct ss7 *ss7 = linkset->ss7;
 	int law;
 	struct ast_channel *c;
 	char tmp[256];
-	char *strp;
 	struct ast_callid *callid = NULL;
 	int callid_created = ast_callid_threadstorage_auto(&callid);
 
@@ -993,8 +596,6 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
 		law = SIG_SS7_ULAW;
 	}
 
-	isup_set_echocontrol(p->ss7call, (linkset->flags & LINKSET_FLAG_DEFAULTECHOCONTROL) ? 1 : 0);
-
 	/*
 	 * Release the SS7 lock while we create the channel so other
 	 * threads can send messages.  We must also release the private
@@ -1002,13 +603,14 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
 	 */
 	ast_mutex_unlock(&linkset->lock);
 	sig_ss7_unlock_private(p);
-	c = sig_ss7_new_ast_channel(p, AST_STATE_RING, law, 0, p->exten, NULL, NULL);
+	c = sig_ss7_new_ast_channel(p, AST_STATE_RING, law, 0, p->exten, NULL);
 	if (!c) {
 		ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
 		ast_mutex_lock(&linkset->lock);
 		sig_ss7_lock_private(p);
 		isup_rel(linkset->ss7, p->ss7call, AST_CAUSE_SWITCH_CONGESTION);
 		p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+		p->alreadyhungup = 1;
 		ast_callid_threadstorage_auto_clean(callid, callid_created);
 		return;
 	}
@@ -1017,7 +619,7 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
 	ast_channel_lock(c);
 	sig_ss7_lock_private(p);
 
-	ast_channel_stage_snapshot(c);
+	sig_ss7_set_echocanceller(p, 1);
 
 	/*
 	 * It is reasonably safe to set the following
@@ -1050,6 +652,11 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
 		/* Clear this after we set it */
 		p->gen_dig_number[0] = 0;
 	}
+	if (!ast_strlen_zero(p->orig_called_num)) {
+		pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
+		/* Clear this after we set it */
+		p->orig_called_num[0] = 0;
+	}
 
 	snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
 	pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
@@ -1082,187 +689,26 @@ static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *links
 	/* Clear this after we set it */
 	p->calling_party_cat = 0;
 
-	if (p->redirect_counter) {
-		struct ast_party_redirecting redirecting;
-
-		switch (p->redirect_info_ind) {
-		case 0:
-			strp = "NO_REDIRECTION";
-			break;
-		case 1:
-			strp = "CALL_REROUTED_PRES_ALLOWED";
-			break;
-		case 2:
-			strp = "CALL_REROUTED_INFO_RESTRICTED";
-			break;
-		case 3:
-			strp = "CALL_DIVERTED_PRES_ALLOWED";
-			break;
-		case 4:
-			strp = "CALL_DIVERTED_INFO_RESTRICTED";
-			break;
-		case 5:
-			strp = "CALL_REROUTED_PRES_RESTRICTED";
-			break;
-		case 6:
-			strp = "CALL_DIVERTED_PRES_RESTRICTED";
-			break;
-		case 7:
-			strp = "SPARE";
-			break;
-		default:
-			strp = "NO_REDIRECTION";
-			break;
-		}
-		pbx_builtin_setvar_helper(c, "SS7_REDIRECT_INFO_IND", strp);
+	if (!ast_strlen_zero(p->redirecting_num)) {
+		pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
 		/* Clear this after we set it */
-		p->redirect_info_ind = 0;
-
-		ast_party_redirecting_init(&redirecting);
+		p->redirecting_num[0] = 0;
+	}
+	if (!ast_strlen_zero(p->generic_name)) {
+		pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
+		/* Clear this after we set it */
+		p->generic_name[0] = 0;
+	}
 
-		if (p->redirect_info_counter) {
-			redirecting.count = p->redirect_info_counter;
-			if (p->redirect_info_counter != p->redirect_counter) {
-				if (p->redirect_info_counter < p->redirect_counter) {
-					redirecting.count = p->redirect_counter;
-				}
-				ast_log(LOG_WARNING, "Redirect counters differ: %u while info says %u - using %u\n",
-					p->redirect_counter, p->redirect_info_counter, redirecting.count);
-			}
-			/* Clear this after we set it */
-			p->redirect_info_counter = 0;
-			p->redirect_counter = 0;
-		}
+	sig_ss7_unlock_private(p);
+	ast_channel_unlock(c);
 
-		if (p->redirect_counter) {
-			redirecting.count = p->redirect_counter;
-			/* Clear this after we set it */
-			p->redirect_counter = 0;
-		}
-
-		switch (p->redirect_info_orig_reas) {
-		case SS7_REDIRECTING_REASON_UNKNOWN:
-			redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-			break;
-		case SS7_REDIRECTING_REASON_USER_BUSY:
-			redirecting.orig_reason.code = AST_REDIRECTING_REASON_USER_BUSY;
-			break;
-		case SS7_REDIRECTING_REASON_NO_ANSWER:
-			redirecting.orig_reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
-			break;
-		case SS7_REDIRECTING_REASON_UNCONDITIONAL:
-			redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
-			break;
-		default:
-			redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-			break;
-		}
-
-		switch (p->redirect_info_reas) {
-		case SS7_REDIRECTING_REASON_UNKNOWN:
-			redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-			break;
-		case SS7_REDIRECTING_REASON_USER_BUSY:
-			redirecting.reason.code = AST_REDIRECTING_REASON_USER_BUSY;
-			if (!p->redirect_info_orig_reas && redirecting.count == 1) {
-				redirecting.orig_reason.code = AST_REDIRECTING_REASON_USER_BUSY;
-			}
-			break;
-		case SS7_REDIRECTING_REASON_NO_ANSWER:
-			redirecting.reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
-			if (!p->redirect_info_orig_reas && redirecting.count == 1) {
-				redirecting.orig_reason.code = AST_REDIRECTING_REASON_NO_ANSWER;
-			}
-			break;
-		case SS7_REDIRECTING_REASON_UNCONDITIONAL:
-			redirecting.reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
-			if (!p->redirect_info_orig_reas && redirecting.count == 1) {
-				redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNCONDITIONAL;
-			}
-			break;
-		case SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING:
-		case SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE:
-			redirecting.reason.code = AST_REDIRECTING_REASON_DEFLECTION;
-			break;
-		case SS7_REDIRECTING_REASON_UNAVAILABLE:
-			redirecting.reason.code = AST_REDIRECTING_REASON_UNAVAILABLE;
-			break;
-		default:
-			redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-			break;
-		}
-		/* Clear this after we set it */
-		p->redirect_info_orig_reas = 0;
-		p->redirect_info_reas = 0;
-
-		if (!ast_strlen_zero(p->redirecting_num)) {
-			redirecting.from.number.str = ast_strdup(p->redirecting_num);
-			redirecting.from.number.presentation = p->redirecting_presentation;
-			redirecting.from.number.valid = 1;
-			/* Clear this after we set it */
-			p->redirecting_num[0] = 0;
-		}
-
-		if (!ast_strlen_zero(p->generic_name)) {
-			redirecting.from.name.str = ast_strdup(p->generic_name);
-			redirecting.from.name.presentation = p->redirecting_presentation;
-			redirecting.from.name.valid = 1;
-			/* Clear this after we set it */
-			p->generic_name[0] = 0;
-		}
-
-		if (!ast_strlen_zero(p->orig_called_num)) {
-			redirecting.orig.number.str = ast_strdup(p->orig_called_num);
-			redirecting.orig.number.presentation = p->orig_called_presentation;
-			redirecting.orig.number.valid = 1;
-			/* Clear this after we set it */
-			p->orig_called_num[0] = 0;
-		} else if (redirecting.count == 1) {
-			ast_party_id_copy(&redirecting.orig, &redirecting.from);
-		}
-
-		ast_channel_update_redirecting(c, &redirecting, NULL);
-		ast_party_redirecting_free(&redirecting);
-	}
-
-	if (p->cug_indicator != ISUP_CUG_NON) {
-		sprintf(tmp, "%d", p->cug_interlock_code);
-		pbx_builtin_setvar_helper(c, "SS7_CUG_INTERLOCK_CODE", tmp);
-
-		switch (p->cug_indicator) {
-		case ISUP_CUG_NON:
-			strp = "NON_CUG";
-			break;
-		case ISUP_CUG_OUTGOING_ALLOWED:
-			strp = "OUTGOING_ALLOWED";
-			break;
-		case ISUP_CUG_OUTGOING_NOT_ALLOWED:
-			strp = "OUTGOING_NOT_ALLOWED";
-			break;
-		default:
-			strp = "SPARE";
-			break;
-		}
-		pbx_builtin_setvar_helper(c, "SS7_CUG_INDICATOR", strp);
-
-		if (!ast_strlen_zero(p->cug_interlock_ni)) {
-			pbx_builtin_setvar_helper(c, "SS7_CUG_INTERLOCK_NI", p->cug_interlock_ni);
-		}
-
-		p->cug_indicator = ISUP_CUG_NON;
-	}
-
-	ast_channel_stage_snapshot_done(c);
-
-	sig_ss7_unlock_private(p);
-	ast_channel_unlock(c);
-
-	if (ast_pbx_start(c)) {
-		ast_log(LOG_WARNING, "Unable to start PBX on %s (CIC %d)\n", ast_channel_name(c), p->cic);
-		ast_hangup(c);
-	} else {
-		ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
-	}
+	if (ast_pbx_start(c)) {
+		ast_log(LOG_WARNING, "Unable to start PBX on %s (CIC %d)\n", ast_channel_name(c), p->cic);
+		ast_hangup(c);
+	} else {
+		ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
+	}
 
 	/* Must return with linkset and private lock. */
 	ast_mutex_lock(&linkset->lock);
@@ -1291,9 +737,6 @@ static void ss7_apply_plan_to_number(char *buf, size_t size, const struct sig_ss
 	case SS7_NAI_UNKNOWN:
 		snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
 		break;
-	case SS7_NAI_NETWORKROUTED:
-		snprintf(buf, size, "%s%s", ss7->networkroutedprefix, number);
-		break;
 	default:
 		snprintf(buf, size, "%s", number);
 		break;
@@ -1335,50 +778,6 @@ static struct ast_callid *func_ss7_linkset_callid(struct sig_ss7_linkset *linkse
 	return callid;
 }
 
-/*!
- * \internal
- * \brief Proceed with the call based on the extension matching status
- * is matching in the dialplan.
- * \since 11.0
- *
- * \param linkset ss7 span control structure.
- * \param p Signaling private structure pointer.
- * \param e Event causing the match.
- *
- * \note Assumes the linkset->lock is already obtained.
- * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
- *
- * \return Nothing.
- */
-static void ss7_match_extension(struct sig_ss7_linkset *linkset, struct sig_ss7_chan *p, ss7_event *e)
-{
-	ast_verb(3, "SS7 exten: %s complete: %d\n", p->exten, p->called_complete);
-
-	if (!p->called_complete
-		&& linkset->type == SS7_ITU /* ANSI does not support overlap dialing. */
-		&& ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num)
-		&& !isup_start_digittimeout(linkset->ss7, p->ss7call)) {
-		/* Wait for more digits. */
-		return;
-	}
-	if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
-		/* DNID is complete */
-		p->called_complete = 1;
-		sig_ss7_set_dnid(p, p->exten);
-
-		/* If COT successful start call! */
-		if ((e->e == ISUP_EVENT_IAM)
-			? !(e->iam.cot_check_required || e->iam.cot_performed_on_previous_cic)
-			: (!(e->sam.cot_check_required || e->sam.cot_performed_on_previous_cic) || e->sam.cot_check_passed)) {
-			ss7_start_call(p, linkset);
-		}
-		return;
-	}
-
-	ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
-	isup_rel(linkset->ss7, (e->e == ISUP_EVENT_IAM) ? e->iam.call : e->sam.call, AST_CAUSE_UNALLOCATED);
-}
-
 /* This is a thread per linkset that handles all received events from libss7. */
 void *ss7_linkset(void *data)
 {
@@ -1389,7 +788,6 @@ void *ss7_linkset(void *data)
 	ss7_event *e = NULL;
 	struct sig_ss7_chan *p;
 	struct pollfd pollers[SIG_SS7_NUM_DCHANS];
-	unsigned char mb_state[255];
 	int nextms;
 
 #define SS7_MAX_POLL	60000	/* Maximum poll time in ms. */
@@ -1437,13 +835,16 @@ void *ss7_linkset(void *data)
 		pthread_testcancel();
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
-		ast_mutex_lock(&linkset->lock);
 		if ((res < 0) && (errno != EINTR)) {
 			ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
 		} else if (!res) {
+			ast_mutex_lock(&linkset->lock);
 			ss7_schedule_run(ss7);
+			ast_mutex_unlock(&linkset->lock);
+			continue;
 		}
 
+		ast_mutex_lock(&linkset->lock);
 		for (i = 0; i < linkset->numsigchans; i++) {
 			if (pollers[i].revents & POLLPRI) {
 				sig_ss7_handle_link_exception(linkset, i);
@@ -1472,26 +873,23 @@ void *ss7_linkset(void *data)
 			switch (e->e) {
 			case SS7_EVENT_UP:
 				if (linkset->state != LINKSET_STATE_UP) {
-					ast_verb(1, "--- SS7 Up ---\n");
+					ast_verbose("--- SS7 Up ---\n");
 					ss7_reset_linkset(linkset);
 				}
 				linkset->state = LINKSET_STATE_UP;
 				break;
 			case SS7_EVENT_DOWN:
-				ast_verb(1, "--- SS7 Down ---\n");
+				ast_verbose("--- SS7 Down ---\n");
 				linkset->state = LINKSET_STATE_DOWN;
 				for (i = 0; i < linkset->numchans; i++) {
 					p = linkset->pvts[i];
 					if (p) {
-						sig_ss7_set_inservice(p, 0);
-						if (linkset->flags & LINKSET_FLAG_INITIALHWBLO) {
-							sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_HARDWARE);
-						}
+						sig_ss7_set_alarm(p, 1);
 					}
 				}
 				break;
 			case MTP2_LINK_UP:
-				ast_verb(1, "MTP2 link up (SLC %d)\n", e->gen.data);
+				ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
 				break;
 			case MTP2_LINK_DOWN:
 				ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
@@ -1499,7 +897,6 @@ void *ss7_linkset(void *data)
 			case ISUP_EVENT_CPG:
 				chanpos = ss7_find_cic_gripe(linkset, e->cpg.cic, e->cpg.opc, "CPG");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->cpg.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
@@ -1514,21 +911,6 @@ void *ss7_linkset(void *data)
 					sig_ss7_lock_owner(linkset, chanpos);
 					if (p->owner) {
 						ast_setstate(p->owner, AST_STATE_RINGING);
-						if (!ast_strlen_zero(e->cpg.connected_num)) {
-							struct ast_party_connected_line ast_connected;
-							char connected_num[AST_MAX_EXTENSION];
-
-							ast_party_connected_line_init(&ast_connected);
-							ast_connected.id.number.presentation =
-								ss7_pres_scr2cid_pres(e->cpg.connected_presentation_ind,
-								e->cpg.connected_screening_ind);
-							ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
-								linkset, e->cpg.connected_num, e->cpg.connected_nai);
-							ast_connected.id.number.str = ast_strdup(connected_num);
-							ast_connected.id.number.valid = 1;
-							ast_channel_queue_connected_line_update(p->owner, &ast_connected, NULL);
-							ast_party_connected_line_free(&ast_connected);
-						}
 						ast_channel_unlock(p->owner);
 					}
 					sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
@@ -1551,201 +933,95 @@ void *ss7_linkset(void *data)
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_RSC:
-				ast_verb(1, "Resetting CIC %d\n", e->rsc.cic);
+				ast_verbose("Resetting CIC %d\n", e->rsc.cic);
 				chanpos = ss7_find_cic_gripe(linkset, e->rsc.cic, e->rsc.opc, "RSC");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->rsc.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 				sig_ss7_lock_private(p);
-				p->ss7call = e->rsc.call;
 				callid = func_ss7_linkset_callid(linkset, chanpos);
 				sig_ss7_set_inservice(p, 1);
-				sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-
-				if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
-					isup_blo(ss7, e->rsc.call);
-				} else if (p->locallyblocked & SS7_BLOCKED_HARDWARE) {
-					sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_HARDWARE);
-				}
-
+				sig_ss7_set_remotelyblocked(p, 0);
 				isup_set_call_dpc(e->rsc.call, p->dpc);
 				sig_ss7_lock_owner(linkset, chanpos);
+				p->ss7call = NULL;
 				if (p->owner) {
-					p->do_hangup = SS7_HANGUP_SEND_RLC;
-					if (!(e->rsc.got_sent_msg & ISUP_SENT_IAM)) {
-						/* Q.784 6.2.3 */
-						ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
-					} else {
-						ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
-					}
-
 					ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_RSC", AST_CAUSE_INTERWORKING);
-
 					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
 					ast_channel_unlock(p->owner);
-				} else {
-					isup_rlc(ss7, e->rsc.call);
-					p->ss7call = isup_free_call_if_clear(ss7, e->rsc.call);
 				}
-				/* End the loopback if we have one */
-				sig_ss7_loopback(p, 0);
-
 				sig_ss7_unlock_private(p);
+				isup_rlc(ss7, e->rsc.call);
 				break;
 			case ISUP_EVENT_GRS:
-				if (!sig_ss7_find_cic_range(linkset, e->grs.startcic, e->grs.endcic,
-					e->grs.opc)) {
-					ast_log(LOG_WARNING, "GRS on unconfigured range CIC %d - %d PC %d\n",
-						e->grs.startcic, e->grs.endcic, e->grs.opc);
-					chanpos = sig_ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
-					if (chanpos < 0) {
-						isup_free_call(ss7, e->grs.call);
-						break;
-					}
-					p = linkset->pvts[chanpos];
-					sig_ss7_lock_private(p);
-					p->ss7call = isup_free_call_if_clear(ss7, e->grs.call);
-					sig_ss7_unlock_private(p);
+				ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
+				chanpos = ss7_find_cic_gripe(linkset, e->grs.startcic, e->grs.opc, "GRS");
+				if (chanpos < 0) {
 					break;
 				}
-
-				/* Leave startcic last to collect all cics mb_state */
-				for (i = e->grs.endcic - e->grs.startcic; 0 <= i; --i) {
-					/*
-					 * We are guaranteed to find chanpos because
-					 * sig_ss7_find_cic_range() includes it.
-					 */
-					chanpos = sig_ss7_find_cic(linkset, e->grs.startcic + i, e->grs.opc);
-					p = linkset->pvts[chanpos];
-					sig_ss7_lock_private(p);
-
-					if (p->locallyblocked & SS7_BLOCKED_MAINTENANCE) {
-						mb_state[i] = 1;
-					} else {
-						mb_state[i] = 0;
-						sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_HARDWARE);
-					}
-
-					sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-
-					if (!i) {
-						p->ss7call = e->grs.call;
-						isup_gra(ss7, p->ss7call, e->grs.endcic, mb_state);
-					}
-
-					sig_ss7_lock_owner(linkset, chanpos);
-					if (p->owner) {
-						ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
-						if (ast_channel_state(p->owner) == AST_STATE_DIALING
-							&& linkset->pvts[i]->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
-							ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
-						} else {
-							ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CLEARING);
-						}
-						p->do_hangup = SS7_HANGUP_FREE_CALL;
-						ast_channel_unlock(p->owner);
-					} else if (!i) {
-						p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-					} else if (p->ss7call) {
-						/* clear any other session */
-						isup_free_call(ss7, p->ss7call);
-						p->ss7call = NULL;
-					}
-					sig_ss7_set_inservice(p, 1);
-					sig_ss7_unlock_private(p);
-				}
+				p = linkset->pvts[chanpos];
+				isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
+				ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
+				ss7_hangup_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc);
 				break;
 			case ISUP_EVENT_CQM:
-				ast_debug(1, "Got Circuit group query message from CICs %d to %d\n",
-							e->cqm.startcic, e->cqm.endcic);
-				ss7_handle_cqm(linkset, e);
+				ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
+				ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
 				break;
 			case ISUP_EVENT_GRA:
-				if (!sig_ss7_find_cic_range(linkset, e->gra.startcic,
-							e->gra.endcic, e->gra.opc)) {	/* Never will be true */
-					ast_log(LOG_WARNING, "GRA on unconfigured range CIC %d - %d PC %d\n",
-							e->gra.startcic, e->gra.endcic, e->gra.opc);
-					isup_free_call(ss7, e->gra.call);
-					break;
-				}
-				ast_verb(1, "Got reset acknowledgement from CIC %d to %d DPC: %d\n",
-					e->gra.startcic, e->gra.endcic, e->gra.opc);
-				ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc,
-					e->gra.status, 1, 1, SS7_BLOCKED_MAINTENANCE);
+				ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
 				ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
-
-				chanpos = sig_ss7_find_cic(linkset, e->gra.startcic, e->gra.opc);
-				if (chanpos < 0) {
-					isup_free_call(ss7, e->gra.call);
-					break;
-				}
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-
-				/* we may send a CBD with GRS! */
-				p->ss7call = isup_free_call_if_clear(ss7, e->gra.call);
-				sig_ss7_unlock_private(p);
+				ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
 				break;
-			case ISUP_EVENT_SAM:
-				chanpos = ss7_find_cic_gripe(linkset, e->sam.cic, e->sam.opc, "SAM");
+			case ISUP_EVENT_IAM:
+				ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
+				chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->sam.call);
+					isup_rel(ss7, e->iam.call, -1);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 				sig_ss7_lock_private(p);
 				sig_ss7_lock_owner(linkset, chanpos);
-				if (p->owner) {
-					ast_log(LOG_WARNING, "SAM on CIC %d PC %d already have call\n", e->sam.cic, e->sam.opc);
-					ast_channel_unlock(p->owner);
-					sig_ss7_unlock_private(p);
-					break;
-				}
-				p->called_complete = 0;
-				if (!ast_strlen_zero(e->sam.called_party_num)) {
-					char *st;
-					strncat(p->exten, e->sam.called_party_num, sizeof(p->exten) - strlen(p->exten) - 1);
-					st = strchr(p->exten, '#');
-					if (st) {
-						*st = '\0';
-						p->called_complete = 1;
+				if (p->call_level != SIG_SS7_CALL_LEVEL_IDLE) {
+					/*
+					 * Detected glare/dual-seizure
+					 *
+					 * Always abort both calls since we can't implement the dual
+					 * seizure procedures due to our channel assignment architecture
+					 * and the fact that we cannot tell libss7 to discard its call
+					 * structure to ignore the incoming IAM.
+					 */
+					ast_debug(1,
+						"Linkset %d: SS7 IAM glare on CIC/DPC %d/%d.  Dropping both calls.\n",
+						linkset->span, e->iam.cic, e->iam.opc);
+					if (p->call_level == SIG_SS7_CALL_LEVEL_ALLOCATED) {
+						/*
+						 * We have not sent our IAM yet and we never will at this point.
+						 */
+						p->alreadyhungup = 1;
+						isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
 					}
-					ss7_match_extension(linkset, p, e);
-				}
-				sig_ss7_unlock_private(p);
-				break;
-			case ISUP_EVENT_IAM:
-				ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
-				chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
-				if (chanpos < 0) {
-					isup_free_call(ss7, e->iam.call);
+					p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
+					if (p->owner) {
+						ss7_queue_pvt_cause_data(p->owner, "SS7 ISUP_EVENT_IAM (glare)", AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+						ast_channel_hangupcause_set(p->owner, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+						ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+						ast_channel_unlock(p->owner);
+					}
+					sig_ss7_unlock_private(p);
 					break;
 				}
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
 				/*
-				 * The channel should be idle and not have an owner at this point since we
+				 * The channel should not have an owner at this point since we
 				 * are in the process of creating an owner for it.
 				 */
-				ast_assert(!p->owner && p->call_level == SIG_SS7_CALL_LEVEL_IDLE);
-
-				if (p->remotelyblocked) {
-					ast_log(LOG_NOTICE, "Got IAM on remotely blocked CIC %d DPC %d remove blocking\n", e->iam.cic, e->iam.opc);
-					sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-					sig_ss7_set_inservice(p, 1);
-				}
+				ast_assert(!p->owner);
 
 				if (!sig_ss7_is_chan_available(p)) {
 					/* Circuit is likely blocked or in alarm. */
 					isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
-					if (p->locallyblocked) {
-						isup_clear_callflags(ss7, e->iam.call, ISUP_GOT_IAM);
-						p->ss7call = isup_free_call_if_clear(ss7, e->iam.call);
-						ast_log(LOG_WARNING, "Got IAM on locally blocked CIC %d DPC %d, ignore\n", e->iam.cic, e->iam.opc);
-					}
 					sig_ss7_unlock_private(p);
 					break;
 				}
@@ -1759,14 +1035,18 @@ void *ss7_linkset(void *data)
 				if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
 					ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
 					p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
-				} else {
+				} else
 					p->cid_num[0] = 0;
-					if (e->iam.presentation_ind) {
-						p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
-					}
+
+				/* Set DNID */
+				if (!ast_strlen_zero(e->iam.called_party_num)) {
+					ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset,
+						e->iam.called_party_num, e->iam.called_nai);
+				} else {
+					p->exten[0] = '\0';
 				}
+				sig_ss7_set_dnid(p, p->exten);
 
-				p->called_complete = 0;
 				if (p->immediate) {
 					p->exten[0] = 's';
 					p->exten[1] = '\0';
@@ -1776,18 +1056,16 @@ void *ss7_linkset(void *data)
 					st = strchr(p->exten, '#');
 					if (st) {
 						*st = '\0';
-						p->called_complete = 1;
 					}
 				} else {
 					p->exten[0] = '\0';
 				}
 
 				p->cid_ani[0] = '\0';
-				if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name))) {
+				if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
 					ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
-				} else {
+				else
 					p->cid_name[0] = '\0';
-				}
 
 				p->cid_ani2 = e->iam.oli_ani2;
 				p->cid_ton = 0;
@@ -1801,162 +1079,81 @@ void *ss7_linkset(void *data)
 				p->gen_dig_type = e->iam.gen_dig_type;
 				p->gen_dig_scheme = e->iam.gen_dig_scheme;
 				ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
-				if (!ast_strlen_zero(e->iam.orig_called_num)) {
-					ss7_apply_plan_to_number(p->orig_called_num, sizeof(p->orig_called_num), linkset, e->iam.orig_called_num, e->iam.orig_called_nai);
-					p->orig_called_presentation = ss7_pres_scr2cid_pres(e->iam.orig_called_pres_ind, e->iam.orig_called_screening_ind);
-				}
-				if (!ast_strlen_zero(e->iam.redirecting_num)) {
-					ss7_apply_plan_to_number(p->redirecting_num, sizeof(p->redirecting_num), linkset, e->iam.redirecting_num, e->iam.redirecting_num_nai);
-					p->redirecting_presentation = ss7_pres_scr2cid_pres(e->iam.redirecting_num_presentation_ind, e->iam.redirecting_num_screening_ind);
-				}
+				ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
+				ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
 				ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
 				p->calling_party_cat = e->iam.calling_party_cat;
-				p->redirect_counter = e->iam.redirect_counter;
-				p->redirect_info = e->iam.redirect_info;
-				p->redirect_info_ind = e->iam.redirect_info_ind;
-				p->redirect_info_orig_reas = e->iam.redirect_info_orig_reas;
-				p->redirect_info_counter = e->iam.redirect_info_counter;
-				if (p->redirect_info_counter && !p->redirect_counter) {
-					p->redirect_counter = p->redirect_info_counter;
-				}
-				p->redirect_info_reas = e->iam.redirect_info_reas;
-				p->cug_indicator = e->iam.cug_indicator;
-				p->cug_interlock_code = e->iam.cug_interlock_code;
-				ast_copy_string(p->cug_interlock_ni, e->iam.cug_interlock_ni, sizeof(p->cug_interlock_ni));
-
-				if (e->iam.cot_check_required) {
-					sig_ss7_loopback(p, 1);
-				}
 
-				p->echocontrol_ind = e->iam.echocontrol_ind;
 				sig_ss7_set_caller_id(p);
-				ss7_match_extension(linkset, p, e);
-				sig_ss7_unlock_private(p);
 
-				if (e->iam.cot_performed_on_previous_cic) {
-					chanpos = sig_ss7_find_cic(linkset, (e->iam.cic - 1), e->iam.opc);
-					if (chanpos < 0) {
-						/* some stupid switch do this */
-						ast_verb(1, "COT request on previous nonexistent CIC %d in IAM PC %d\n", (e->iam.cic - 1), e->iam.opc);
-						break;
-					}
-					ast_verb(1, "COT request on previous CIC %d in IAM PC %d\n", (e->iam.cic - 1), e->iam.opc);
-					p = linkset->pvts[chanpos];
-					sig_ss7_lock_private(p);
-					if (sig_ss7_is_chan_available(p)) {
-						sig_ss7_set_inservice(p, 0);	/* to prevent to use this circuit */
-						sig_ss7_loopback(p, 1);
-					} /* If already have a call don't loop */
-					sig_ss7_unlock_private(p);
-				}
-				break;
-			case ISUP_EVENT_DIGITTIMEOUT:
-				chanpos = ss7_find_cic_gripe(linkset, e->digittimeout.cic, e->digittimeout.opc, "DIGITTIMEOUT");
-				if (chanpos < 0) {
-					isup_free_call(ss7, e->digittimeout.call);
-					break;
-				}
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				ast_debug(1, "Digittimeout on CIC: %d PC: %d\n", e->digittimeout.cic, e->digittimeout.opc);
 				if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
-					/* DNID is complete */
-					p->called_complete = 1;
-					sig_ss7_set_dnid(p, p->exten);
-
-					/* If COT successful start call! */
-					if (!(e->digittimeout.cot_check_required || e->digittimeout.cot_performed_on_previous_cic) || e->digittimeout.cot_check_passed) {
+					if (e->iam.cot_check_required) {
+						p->call_level = SIG_SS7_CALL_LEVEL_CONTINUITY;
+						sig_ss7_loopback(p, 1);
+					} else {
 						ss7_start_call(p, linkset);
 					}
 				} else {
 					ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
-					isup_rel(linkset->ss7, e->digittimeout.call, AST_CAUSE_UNALLOCATED);
+					p->alreadyhungup = 1;
+					isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
 				}
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_COT:
-				if (e->cot.cot_performed_on_previous_cic) {
-					chanpos = sig_ss7_find_cic(linkset, (e->cot.cic - 1), e->cot.opc);
-					/* some stupid switches do this!!! */
-					if (-1 < chanpos) {
-						p = linkset->pvts[chanpos];
-						sig_ss7_lock_private(p);
-						sig_ss7_set_inservice(p, 1);
-						sig_ss7_loopback(p, 0);
-						sig_ss7_unlock_private(p);;
-						ast_verb(1, "Loop turned off on CIC: %d PC: %d\n",  (e->cot.cic - 1), e->cot.opc);
-					}
-				}
-
 				chanpos = ss7_find_cic_gripe(linkset, e->cot.cic, e->cot.opc, "COT");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->cot.call);
+					isup_rel(ss7, e->cot.call, -1);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 
 				sig_ss7_lock_private(p);
-				p->ss7call = e->cot.call;
-
 				if (p->loopedback) {
 					sig_ss7_loopback(p, 0);
-					ast_verb(1, "Loop turned off on CIC: %d PC: %d\n",  e->cot.cic, e->cot.opc);
-				}
-
-				/* Don't start call if we didn't get IAM or COT failed! */
-				if ((e->cot.got_sent_msg & ISUP_GOT_IAM) && e->cot.passed && p->called_complete) {
 					ss7_start_call(p, linkset);
 				}
-
-				p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_CCR:
 				ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
 				chanpos = ss7_find_cic_gripe(linkset, e->ccr.cic, e->ccr.opc, "CCR");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->ccr.call);
 					break;
 				}
 
 				p = linkset->pvts[chanpos];
 
 				sig_ss7_lock_private(p);
-				p->ss7call = e->ccr.call;
 				sig_ss7_loopback(p, 1);
-				if (linkset->type == SS7_ANSI) {
-					isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
-				}
 				sig_ss7_unlock_private(p);
+
+				isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
 				break;
 			case ISUP_EVENT_CVT:
 				ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
 				chanpos = ss7_find_cic_gripe(linkset, e->cvt.cic, e->cvt.opc, "CVT");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->cvt.call);
 					break;
 				}
 
 				p = linkset->pvts[chanpos];
 
 				sig_ss7_lock_private(p);
-				p->ss7call = e->cvt.call;
 				sig_ss7_loopback(p, 1);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, e->cvt.call);
-				}
-				isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
 				sig_ss7_unlock_private(p);
+
+				isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
 				break;
 			case ISUP_EVENT_REL:
 				chanpos = ss7_find_cic_gripe(linkset, e->rel.cic, e->rel.opc, "REL");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->rel.call);
+					/* Continue hanging up the call anyway. */
+					isup_rlc(ss7, e->rel.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 				sig_ss7_lock_private(p);
-				p->ss7call = e->rel.call;
 				callid = func_ss7_linkset_callid(linkset, chanpos);
 				sig_ss7_lock_owner(linkset, chanpos);
 				if (p->owner) {
@@ -1965,193 +1162,128 @@ void *ss7_linkset(void *data)
 
 					ast_channel_hangupcause_set(p->owner, e->rel.cause);
 					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
-					p->do_hangup = SS7_HANGUP_SEND_RLC;
 					ast_channel_unlock(p->owner);
-				} else {
-					ast_verb(1, "REL on CIC %d DPC %d without owner!\n", p->cic, p->dpc);
-					isup_rlc(ss7, p->ss7call);
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
 				}
 
 				/* End the loopback if we have one */
 				sig_ss7_loopback(p, 0);
 
-				/* the rel is not complete here!!! */
+				isup_rlc(ss7, e->rel.call);
+				p->ss7call = NULL;
+
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_ACM:
 				chanpos = ss7_find_cic_gripe(linkset, e->acm.cic, e->acm.opc, "ACM");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->acm.call);
+					isup_rel(ss7, e->acm.call, -1);
 					break;
 				}
+				{
+					p = linkset->pvts[chanpos];
 
-				p = linkset->pvts[chanpos];
-
-				ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
+					ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
 
-				if (e->acm.call_ref_ident > 0) {
-					p->rlt = 1; /* Setting it but not using it here*/
-				}
+					if (e->acm.call_ref_ident > 0) {
+						p->rlt = 1; /* Setting it but not using it here*/
+					}
 
-				sig_ss7_lock_private(p);
-				p->ss7call = e->acm.call;
-				callid = func_ss7_linkset_callid(linkset, chanpos);
-				sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
-				if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
-					p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
-				}
-				sig_ss7_set_dialing(p, 0);
-				/* Send alerting if subscriber is free */
-				if (e->acm.called_party_status_ind == 1) {
-					if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
-						p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
+					sig_ss7_lock_private(p);
+					callid = func_ss7_linkset_callid(linkset, chanpos);
+					sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
+					if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
+						p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
 					}
-					sig_ss7_lock_owner(linkset, chanpos);
-					if (p->owner) {
-						ast_setstate(p->owner, AST_STATE_RINGING);
-						ast_channel_unlock(p->owner);
+					sig_ss7_set_dialing(p, 0);
+					/* Send alerting if subscriber is free */
+					if (e->acm.called_party_status_ind == 1) {
+						if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
+							p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
+						}
+						sig_ss7_lock_owner(linkset, chanpos);
+						if (p->owner) {
+							ast_setstate(p->owner, AST_STATE_RINGING);
+							ast_channel_unlock(p->owner);
+						}
+						sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
 					}
-					sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
+					sig_ss7_unlock_private(p);
 				}
-				p->echocontrol_ind = e->acm.echocontrol_ind;
-				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_CGB:
 				chanpos = ss7_find_cic_gripe(linkset, e->cgb.startcic, e->cgb.opc, "CGB");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->cgb.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
-				ss7_check_range(linkset, e->cgb.startcic, e->cgb.endcic,
-					e->cgb.opc, e->cgb.status);
-				ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic,
-					e->cgb.opc, e->cgb.status, 1, 1,
-					(e->cgb.type) ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
-
-				sig_ss7_lock_private(p);
-				p->ss7call = e->cgb.call;
-
-				isup_cgba(linkset->ss7, p->ss7call, e->cgb.endcic, e->cgb.status);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, e->cgb.call);
-				}
-				sig_ss7_unlock_private(p);
+				ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
+				isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
 				break;
 			case ISUP_EVENT_CGU:
 				chanpos = ss7_find_cic_gripe(linkset, e->cgu.startcic, e->cgu.opc, "CGU");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->cgu.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
-				ss7_check_range(linkset, e->cgu.startcic, e->cgu.endcic,
-					e->cgu.opc, e->cgu.status);
-				ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic,
-					e->cgu.opc, e->cgu.status, 0, 1,
-					e->cgu.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
-
-				sig_ss7_lock_private(p);
-				p->ss7call = e->cgu.call;
-
-				isup_cgua(linkset->ss7, p->ss7call, e->cgu.endcic, e->cgu.status);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, e->cgu.call);
-				}
-				sig_ss7_unlock_private(p);
+				ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
+				isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
 				break;
 			case ISUP_EVENT_UCIC:
 				chanpos = ss7_find_cic_gripe(linkset, e->ucic.cic, e->ucic.opc, "UCIC");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->ucic.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 				ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
 				sig_ss7_lock_private(p);
-				sig_ss7_lock_owner(linkset, chanpos);
-				if (p->owner) {
-					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
-					ast_channel_unlock(p->owner);
-				}
-				sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
+				sig_ss7_set_remotelyblocked(p, 1);
 				sig_ss7_set_inservice(p, 0);
-				p->ss7call = NULL;
-				isup_free_call(ss7, e->ucic.call);
 				sig_ss7_unlock_private(p);/* doesn't require a SS7 acknowledgement */
 				break;
 			case ISUP_EVENT_BLO:
 				chanpos = ss7_find_cic_gripe(linkset, e->blo.cic, e->blo.opc, "BLO");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->blo.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
 				ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
 				sig_ss7_lock_private(p);
-				p->ss7call = e->blo.call;
-				sig_ss7_set_remotelyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
-				isup_bla(linkset->ss7, e->blo.call);
-				sig_ss7_lock_owner(linkset, chanpos);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, e->blo.call);
-				} else {
-					if (e->blo.got_sent_msg & ISUP_SENT_IAM) {
-						/* Q.784 6.2.2 */
-						ast_channel_hangupcause_set(p->owner, SS7_CAUSE_TRY_AGAIN);
-					}
-					ast_channel_unlock(p->owner);
-				}
+				sig_ss7_set_remotelyblocked(p, 1);
 				sig_ss7_unlock_private(p);
+				isup_bla(linkset->ss7, e->blo.cic, p->dpc);
 				break;
 			case ISUP_EVENT_BLA:
 				chanpos = ss7_find_cic_gripe(linkset, e->bla.cic, e->bla.opc, "BLA");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->bla.call);
 					break;
 				}
-				ast_debug(1, "Locally blocking CIC %d\n", e->bla.cic);
+				ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
 				p = linkset->pvts[chanpos];
 				sig_ss7_lock_private(p);
-				p->ss7call = e->bla.call;
-				sig_ss7_set_locallyblocked(p, 1, SS7_BLOCKED_MAINTENANCE);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
+				sig_ss7_set_locallyblocked(p, 1);
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_UBL:
 				chanpos = ss7_find_cic_gripe(linkset, e->ubl.cic, e->ubl.opc, "UBL");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->ubl.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
-				ast_debug(1, "Remotely unblocking CIC %d PC %d\n", e->ubl.cic, e->ubl.opc);
+				ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
 				sig_ss7_lock_private(p);
-				p->ss7call = e->ubl.call;
-				sig_ss7_set_remotelyblocked(p, 0, SS7_BLOCKED_MAINTENANCE);
-				isup_uba(linkset->ss7, e->ubl.call);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
+				sig_ss7_set_remotelyblocked(p, 0);
 				sig_ss7_unlock_private(p);
+				isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
 				break;
 			case ISUP_EVENT_UBA:
 				chanpos = ss7_find_cic_gripe(linkset, e->uba.cic, e->uba.opc, "UBA");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->uba.call);
 					break;
 				}
 				p = linkset->pvts[chanpos];
-				ast_debug(1, "Locally unblocking CIC %d PC %d\n", e->uba.cic, e->uba.opc);
+				ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
 				sig_ss7_lock_private(p);
-				p->ss7call = e->uba.call;
-				sig_ss7_set_locallyblocked(p, 0, SS7_BLOCKED_MAINTENANCE);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
+				sig_ss7_set_locallyblocked(p, 0);
 				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_CON:
@@ -2159,92 +1291,49 @@ void *ss7_linkset(void *data)
 				if (e->e == ISUP_EVENT_CON) {
 					chanpos = ss7_find_cic_gripe(linkset, e->con.cic, e->con.opc, "CON");
 					if (chanpos < 0) {
-						isup_free_call(ss7, e->con.call);
+						isup_rel(ss7, e->con.call, -1);
 						break;
 					}
 				} else {
 					chanpos = ss7_find_cic_gripe(linkset, e->anm.cic, e->anm.opc, "ANM");
 					if (chanpos < 0) {
-						isup_free_call(ss7, e->anm.call);
+						isup_rel(ss7, e->anm.call, -1);
 						break;
 					}
 				}
 
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = (e->e == ISUP_EVENT_ANM) ?  e->anm.call : e->con.call;
-				callid = func_ss7_linkset_callid(linkset, chanpos);
-				if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
-					p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+				{
+					p = linkset->pvts[chanpos];
+					sig_ss7_lock_private(p);
+					callid = func_ss7_linkset_callid(linkset, chanpos);
+					if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
+						p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
+					}
+					sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
+					sig_ss7_set_dialing(p, 0);
+					sig_ss7_open_media(p);
+					sig_ss7_set_echocanceller(p, 1);
+					sig_ss7_unlock_private(p);
 				}
-
-				if (!ast_strlen_zero((e->e == ISUP_EVENT_ANM)
-					? e->anm.connected_num : e->con.connected_num)) {
-					sig_ss7_lock_owner(linkset, chanpos);
-					if (p->owner) {
-						struct ast_party_connected_line ast_connected;
-						char connected_num[AST_MAX_EXTENSION];
-
-						ast_party_connected_line_init(&ast_connected);
-						if (e->e == ISUP_EVENT_ANM) {
-							ast_connected.id.number.presentation = ss7_pres_scr2cid_pres(
-								e->anm.connected_presentation_ind,
-								e->anm.connected_screening_ind);
-							ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
-								linkset, e->anm.connected_num, e->anm.connected_nai);
-							ast_connected.id.number.str = ast_strdup(connected_num);
-						} else {
-							ast_connected.id.number.presentation = ss7_pres_scr2cid_pres(
-								e->con.connected_presentation_ind,
-								e->con.connected_screening_ind);
-							ss7_apply_plan_to_number(connected_num, sizeof(connected_num),
-								linkset, e->con.connected_num, e->con.connected_nai);
-							ast_connected.id.number.str = ast_strdup(connected_num);
-						}
-						ast_connected.id.number.valid = 1;
-						ast_connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-						ast_channel_queue_connected_line_update(p->owner, &ast_connected, NULL);
-						ast_party_connected_line_free(&ast_connected);
-						ast_channel_unlock(p->owner);
-					}
-				}
-
-				sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
-				sig_ss7_set_dialing(p, 0);
-				sig_ss7_open_media(p);
-				if (((e->e == ISUP_EVENT_ANM) ? !e->anm.echocontrol_ind  :
-						!e->con.echocontrol_ind) || !(linkset->flags & LINKSET_FLAG_USEECHOCONTROL)) {
-					sig_ss7_set_echocanceller(p, 1);
-				}
-				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_RLC:
+				/* XXX Call ptr should be passed up from libss7! */
 				chanpos = ss7_find_cic_gripe(linkset, e->rlc.cic, e->rlc.opc, "RLC");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->rlc.call);
 					break;
 				}
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = e->rlc.call;
-				callid = func_ss7_linkset_callid(linkset, chanpos);
-				if (e->rlc.got_sent_msg & (ISUP_SENT_RSC | ISUP_SENT_REL)) {
-					sig_ss7_loopback(p, 0);
-					if (e->rlc.got_sent_msg & ISUP_SENT_RSC) {
-						sig_ss7_set_inservice(p, 1);
+				{
+					p = linkset->pvts[chanpos];
+					sig_ss7_lock_private(p);
+					callid = func_ss7_linkset_callid(linkset, chanpos);
+					if (p->alreadyhungup) {
+						if (!p->owner) {
+							p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+						}
+						p->ss7call = NULL;
 					}
+					sig_ss7_unlock_private(p);
 				}
-				sig_ss7_lock_owner(linkset, chanpos);
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, e->rlc.call);
-					p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
-				} else {
-					p->do_hangup = SS7_HANGUP_DO_NOTHING;
-					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
-					ast_channel_unlock(p->owner);
-				}
-				sig_ss7_unlock_private(p);
 				break;
 			case ISUP_EVENT_FAA:
 				/*!
@@ -2253,87 +1342,25 @@ void *ss7_linkset(void *data)
 				 */
 				chanpos = ss7_find_cic_gripe(linkset, e->faa.cic, e->faa.opc, "FAA");
 				if (chanpos < 0) {
-					isup_free_call(ss7, e->faa.call);
-					break;
-				}
-
-				/* XXX FAR and FAA used for something dealing with transfers? */
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				callid = func_ss7_linkset_callid(linkset, chanpos);
-				ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
-				p->ss7call = isup_free_call_if_clear(ss7, e->faa.call);
-				sig_ss7_unlock_private(p);
-				break;
-			case ISUP_EVENT_CGBA:
-				chanpos = ss7_find_cic_gripe(linkset, e->cgba.startcic, e->cgba.opc, "CGBA");
-				if (chanpos < 0) {	/* Never will be true */
-					isup_free_call(ss7, e->cgba.call);
-					break;
-				}
-
-				ss7_block_cics(linkset, e->cgba.startcic, e->cgba.endcic,
-					e->cgba.opc, e->cgba.status, 1, 0,
-					e->cgba.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = e->cgba.call;
-
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
-				sig_ss7_unlock_private(p);
-				break;
-			case ISUP_EVENT_CGUA:
-				chanpos = ss7_find_cic_gripe(linkset, e->cgua.startcic, e->cgua.opc, "CGUA");
-				if (chanpos < 0) { /* Never will be true */
-					isup_free_call(ss7, e->cgua.call);
-					break;
-				}
-
-				ss7_block_cics(linkset, e->cgua.startcic, e->cgua.endcic,
-					e->cgua.opc, e->cgua.status, 0, 0,
-					e->cgba.type ? SS7_BLOCKED_HARDWARE : SS7_BLOCKED_MAINTENANCE);
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = e->cgua.call;
-
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
-				sig_ss7_unlock_private(p);
-				break;
-			case ISUP_EVENT_SUS:
-				chanpos = ss7_find_cic_gripe(linkset, e->sus.cic, e->sus.opc, "SUS");
-				if (chanpos < 0) {
-					isup_free_call(ss7, e->sus.call);
-					break;
-				}
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = e->sus.call;
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
-				}
-				sig_ss7_unlock_private(p);
-				break;
-			case ISUP_EVENT_RES:
-				chanpos = ss7_find_cic_gripe(linkset, e->res.cic, e->res.opc, "RES");
-				if (chanpos < 0) {
-					isup_free_call(ss7, e->res.call);
+					isup_rel(linkset->ss7, e->faa.call, -1);
 					break;
 				}
-
-				p = linkset->pvts[chanpos];
-				sig_ss7_lock_private(p);
-				p->ss7call = e->res.call;
-				if (!p->owner) {
-					p->ss7call = isup_free_call_if_clear(ss7, p->ss7call);
+				{
+					/* XXX FAR and FAA used for something dealing with transfers? */
+					p = linkset->pvts[chanpos];
+					ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
+					sig_ss7_lock_private(p);
+					callid = func_ss7_linkset_callid(linkset, chanpos);
+					if (p->alreadyhungup){
+						if (!p->owner) {
+							p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+						}
+						/* XXX We seem to be leaking the isup call structure here. */
+						p->ss7call = NULL;
+						ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR.  Ignoring.\n");
+					}
+					sig_ss7_unlock_private(p);
 				}
-				sig_ss7_unlock_private(p);
 				break;
 			default:
 				ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
@@ -2352,15 +1379,9 @@ void *ss7_linkset(void *data)
 	return 0;
 }
 
-static void ss7_rel(struct sig_ss7_linkset *ss7)
+static inline void ss7_rel(struct sig_ss7_linkset *ss7)
 {
-	/* Release the lock first */
 	ast_mutex_unlock(&ss7->lock);
-
-	/* Then break the poll to send our messages */
-	if (ss7->master != AST_PTHREADT_NULL) {
-		pthread_kill(ss7->master, SIGURG);
-	}
 }
 
 static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
@@ -2370,177 +1391,10 @@ static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
 		/* Avoid deadlock */
 		sig_ss7_deadlock_avoidance_private(pvt);
 	}
-}
-
-/*!
- * \brief Reset a specific CIC.
- * \since 11.0
- *
- * \param linkset linkset control structure.
- * \param cic Circuit Identification Code
- * \param dpc Destination Point Code
- *
- * \return TRUE on success
- */
-int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
-{
-	int i;
-
-	ast_mutex_lock(&linkset->lock);
-	for (i = 0; i < linkset->numchans; i++) {
-		if (linkset->pvts[i] && linkset->pvts[i]->cic == cic && linkset->pvts[i]->dpc == dpc) {
-			int res;
-
-			sig_ss7_lock_private(linkset->pvts[i]);
-			sig_ss7_set_locallyblocked(linkset->pvts[i], 0, SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-			res = ss7_start_rsc(linkset, i);
-			sig_ss7_unlock_private(linkset->pvts[i]);
-			ss7_rel(linkset);	/* Also breaks the poll to send our messages */
-			return res;
-		}
-	}
-	ss7_rel(linkset);
-
-	return 0;
-}
-
-/*!
- * \brief Block or Unblock a specific CIC.
- * \since 11.0
- *
- * \param linkset linkset control structure.
- * \param do_block Action to perform. Block if TRUE.
- * \param which On which CIC to perform the operation.
- *
- * \return 0 on success
- */
-int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int which)
-{
-	ast_mutex_lock(&linkset->lock);
-	sig_ss7_lock_private(linkset->pvts[which]);
-	if (!ss7_find_alloc_call(linkset->pvts[which])) {
-		sig_ss7_unlock_private(linkset->pvts[which]);
-		ss7_rel(linkset);
-		return -1;
-	}
-
-	if (do_block) {
-		isup_blo(linkset->ss7, linkset->pvts[which]->ss7call);
-	} else {
-		isup_ubl(linkset->ss7, linkset->pvts[which]->ss7call);
-	}
-
-	sig_ss7_unlock_private(linkset->pvts[which]);
-	ss7_rel(linkset);	/* Also breaks the poll to send our messages */
-
-	return 0;
-}
-
-/*!
- * \brief Block or Unblock a range of CICs.
- * \since 11.0
- *
- * \param linkset linkset control structure.
- * \param do_block Action to perform. Block if TRUE.
- * \param chanpos Channel position to start from.
- * \param endcic Circuit Identification Code of the end of the range.
- * \param state Array of CIC blocking status.
- * \param type Type of the blocking - maintenance or hardware
- *
- * \note Assumes the linkset->lock is already obtained.
- *
- * \return 0 on success
- */
-int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int chanpos, int endcic, unsigned char state[], int type)
-{
-	sig_ss7_lock_private(linkset->pvts[chanpos]);
-	if (!ss7_find_alloc_call(linkset->pvts[chanpos])) {
-		sig_ss7_unlock_private(linkset->pvts[chanpos]);
-		return -1;
-	}
-
-	if (do_block) {
-		isup_cgb(linkset->ss7, linkset->pvts[chanpos]->ss7call, endcic, state, type);
-	} else {
-		isup_cgu(linkset->ss7, linkset->pvts[chanpos]->ss7call, endcic, state, type);
-	}
-
-	sig_ss7_unlock_private(linkset->pvts[chanpos]);
-	return 0;
-}
-
-/*!
- * \brief Reset a group of CICs.
- * \since 11.0
- *
- * \param linkset linkset control structure.
- * \param cic Circuit Identification Code
- * \param dpc Destination Point Code
- * \param range Range of the CICs to reset
- *
- * \note Assumes the linkset->lock is already obtained.
- *
- * \return 0 on success
- */
-int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range)
-{
-	int i;
-
-	for (i = 0; i < linkset->numchans; i++) {
-		if (linkset->pvts[i] && linkset->pvts[i]->cic == cic && linkset->pvts[i]->dpc == dpc) {
-			ss7_clear_channels(linkset, cic, cic + range, dpc, SS7_HANGUP_FREE_CALL);
-			ss7_block_cics(linkset, cic, cic + range, dpc, NULL, 0, 1,
-				SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-			ss7_block_cics(linkset, cic, cic + range, dpc, NULL, 0, 0,
-				SS7_BLOCKED_MAINTENANCE | SS7_BLOCKED_HARDWARE);
-
-			sig_ss7_lock_private(linkset->pvts[i]);
-			if (!ss7_find_alloc_call(linkset->pvts[i])) {
-				sig_ss7_unlock_private(linkset->pvts[i]);
-				return -1;
-			}
-			isup_grs(linkset->ss7, linkset->pvts[i]->ss7call, linkset->pvts[i]->cic + range);
-			sig_ss7_unlock_private(linkset->pvts[i]);
-			break;
-		}
-	}
-	return 0;
-}
-
-void sig_ss7_free_isup_call(struct sig_ss7_linkset *linkset, int channel)
-{
-	sig_ss7_lock_private(linkset->pvts[channel]);
-	if (linkset->pvts[channel]->ss7call) {
-		isup_free_call(linkset->ss7, linkset->pvts[channel]->ss7call);
-		linkset->pvts[channel]->ss7call = NULL;
-	}
-	sig_ss7_unlock_private(linkset->pvts[channel]);
-}
-
-static int ss7_parse_prefix(struct sig_ss7_chan *p, const char *number, char *nai)
-{
-	int strip = 0;
-
-	if (strncmp(number, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
-		strip = strlen(p->ss7->internationalprefix);
-		*nai = SS7_NAI_INTERNATIONAL;
-	} else if (strncmp(number, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
-		strip = strlen(p->ss7->nationalprefix);
-		*nai = SS7_NAI_NATIONAL;
-	} else if (strncmp(number, p->ss7->networkroutedprefix, strlen(p->ss7->networkroutedprefix)) == 0) {
-		strip = strlen(p->ss7->networkroutedprefix);
-		*nai = SS7_NAI_NETWORKROUTED;
-	} else if (strncmp(number, p->ss7->unknownprefix, strlen(p->ss7->unknownprefix)) == 0) {
-		strip = strlen(p->ss7->unknownprefix);
-		*nai = SS7_NAI_UNKNOWN;
-	} else if (strncmp(number, p->ss7->subscriberprefix, strlen(p->ss7->subscriberprefix)) == 0) {
-		strip = strlen(p->ss7->subscriberprefix);
-		*nai = SS7_NAI_SUBSCRIBER;
-	} else {
-		*nai = SS7_NAI_SUBSCRIBER;
+	/* Then break the poll */
+	if (ss7->master != AST_PTHREADT_NULL) {
+		pthread_kill(ss7->master, SIGURG);
 	}
-
-	return strip;
 }
 
 /*!
@@ -2591,7 +1445,7 @@ void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc)
+int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode)
 {
 	if (!linkset->ss7) {
 		linkset->type = ss7type;
@@ -2605,7 +1459,7 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
 	ss7_set_network_ind(linkset->ss7, networkindicator);
 	ss7_set_pc(linkset->ss7, pointcode);
 
-	if (ss7_add_link(linkset->ss7, transport, linkset->fds[which], cur_slc, adjpointcode)) {
+	if (ss7_add_link(linkset->ss7, transport, linkset->fds[which])) {
 		ast_log(LOG_WARNING, "Could not add SS7 link!\n");
 	}
 
@@ -2617,6 +1471,8 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
 		ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
 	}
 
+	ss7_set_adjpc(linkset->ss7, linkset->fds[which], adjpointcode);
+
 	return 0;
 }
 
@@ -2641,13 +1497,7 @@ int sig_ss7_available(struct sig_ss7_chan *p)
 	ast_mutex_lock(&p->ss7->lock);
 	available = sig_ss7_is_chan_available(p);
 	if (available) {
-		p->ss7call = isup_new_call(p->ss7->ss7, p->cic, p->dpc, 1);
-		if (!p->ss7call) {
-			ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
-			available = 0;
-		} else {
-			p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
-		}
+		p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
 	}
 	ast_mutex_unlock(&p->ss7->lock);
 
@@ -2664,159 +1514,6 @@ static unsigned char cid_pres2ss7screen(int cid_pres)
 	return cid_pres & 0x03;
 }
 
-static void ss7_connected_line_update(struct sig_ss7_chan *p, struct ast_party_connected_line *connected)
-{
-	int connected_strip = 0;
-	char connected_nai;
-	unsigned char connected_pres;
-	unsigned char connected_screen;
-	const char *connected_num;
-
-	if (!connected->id.number.valid) {
-		return;
-	}
-
-	connected_num = S_OR(connected->id.number.str, "");
-	if (p->ss7->called_nai ==  SS7_NAI_DYNAMIC) {
-		connected_strip = ss7_parse_prefix(p, connected_num, &connected_nai);
-	} else {
-		connected_nai = p->ss7->called_nai;
-	}
-
-	connected_pres = cid_pres2ss7pres(connected->id.number.presentation);
-	connected_screen = cid_pres2ss7screen(connected->id.number.presentation);
-
-	isup_set_connected(p->ss7call, connected_num + connected_strip, connected_nai, connected_pres, connected_screen);
-}
-
-static unsigned char ss7_redirect_reason(struct sig_ss7_chan *p, struct ast_party_redirecting *redirecting, int orig)
-{
-	int reason = (orig) ? redirecting->orig_reason.code : redirecting->reason.code;
-
-	switch (reason) {
-	case AST_REDIRECTING_REASON_USER_BUSY:
-		return SS7_REDIRECTING_REASON_USER_BUSY;
-	case AST_REDIRECTING_REASON_NO_ANSWER:
-		return SS7_REDIRECTING_REASON_NO_ANSWER;
-	case AST_REDIRECTING_REASON_UNCONDITIONAL:
-		return SS7_REDIRECTING_REASON_UNCONDITIONAL;
-	}
-
-	if (orig || reason == AST_REDIRECTING_REASON_UNKNOWN) {
-		return SS7_REDIRECTING_REASON_UNKNOWN;
-	}
-
-	if (reason == AST_REDIRECTING_REASON_UNAVAILABLE) {
-		return SS7_REDIRECTING_REASON_UNAVAILABLE;
-	}
-
-	if (reason == AST_REDIRECTING_REASON_DEFLECTION) {
-		if (p->call_level > SIG_SS7_CALL_LEVEL_PROCEEDING) {
-			return SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING;
-		}
-		return SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE;
-	}
-
-	return SS7_REDIRECTING_REASON_UNKNOWN;
-}
-
-static unsigned char ss7_redirect_info_ind(struct ast_channel *ast)
-{
-	const char *redirect_info_ind;
-	struct ast_party_redirecting *redirecting = ast_channel_redirecting(ast);
-
-	redirect_info_ind = pbx_builtin_getvar_helper(ast, "SS7_REDIRECT_INFO_IND");
-	if (!ast_strlen_zero(redirect_info_ind)) {
-		if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_PRES_ALLOWED")) {
-			return SS7_INDICATION_REROUTED_PRES_ALLOWED;
-		}
-		if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_INFO_RESTRICTED")) {
-			return SS7_INDICATION_REROUTED_INFO_RESTRICTED;
-		}
-		if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_PRES_ALLOWED")) {
-			return SS7_INDICATION_DIVERTED_PRES_ALLOWED;
-		}
-		if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_INFO_RESTRICTED")) {
-			return SS7_INDICATION_DIVERTED_INFO_RESTRICTED;
-		}
-		if (!strcasecmp(redirect_info_ind, "CALL_REROUTED_PRES_RESTRICTED")) {
-			return SS7_INDICATION_REROUTED_PRES_RESTRICTED;
-		}
-		if (!strcasecmp(redirect_info_ind, "CALL_DIVERTED_PRES_RESTRICTED")) {
-			return SS7_INDICATION_DIVERTED_PRES_RESTRICTED;
-		}
-		if (!strcasecmp(redirect_info_ind, "SPARE")) {
-			return SS7_INDICATION_SPARE;
-		}
-		return SS7_INDICATION_NO_REDIRECTION;
-	}
-
-	if (redirecting->reason.code == AST_REDIRECTING_REASON_DEFLECTION) {
-		if ((redirecting->to.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-			if ((redirecting->orig.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-				return SS7_INDICATION_DIVERTED_PRES_ALLOWED;
-			}
-			return SS7_INDICATION_DIVERTED_PRES_RESTRICTED;
-		}
-		return SS7_INDICATION_DIVERTED_INFO_RESTRICTED;
-	}
-
-	if ((redirecting->to.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-		if ((redirecting->orig.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-			return SS7_INDICATION_REROUTED_PRES_ALLOWED;
-		}
-		return SS7_INDICATION_REROUTED_PRES_RESTRICTED;
-	}
-	return SS7_INDICATION_REROUTED_INFO_RESTRICTED;
-}
-
-static void ss7_redirecting_update(struct sig_ss7_chan *p, struct ast_channel *ast)
-{
-	int num_nai_strip = 0;
-	struct ast_party_redirecting *redirecting = ast_channel_redirecting(ast);
-
-	if (!redirecting->count) {
-		return;
-	}
-
-	isup_set_redirect_counter(p->ss7call, redirecting->count);
-
-	if (redirecting->orig.number.valid) {
-		char ss7_orig_called_nai = p->ss7->called_nai;
-		const char *ss7_orig_called_num = S_OR(redirecting->orig.number.str, "");
-
-		if (ss7_orig_called_nai == SS7_NAI_DYNAMIC) {
-			num_nai_strip = ss7_parse_prefix(p, ss7_orig_called_num, &ss7_orig_called_nai);
-		} else {
-			num_nai_strip = 0;
-		}
-		isup_set_orig_called_num(p->ss7call, ss7_orig_called_num + num_nai_strip,
-			ss7_orig_called_nai,
-			cid_pres2ss7pres(redirecting->orig.number.presentation),
-			cid_pres2ss7screen(redirecting->orig.number.presentation));
-	}
-
-	if (redirecting->from.number.valid) {
-		char ss7_redirecting_num_nai = p->ss7->calling_nai;
-		const char *redirecting_number = S_OR(redirecting->from.number.str, "");
-
-		if (ss7_redirecting_num_nai == SS7_NAI_DYNAMIC) {
-			num_nai_strip = ss7_parse_prefix(p, redirecting_number, &ss7_redirecting_num_nai);
-		} else {
-			num_nai_strip = 0;
-		}
-
-		isup_set_redirecting_number(p->ss7call, redirecting_number + num_nai_strip,
-			ss7_redirecting_num_nai,
-			cid_pres2ss7pres(redirecting->from.number.presentation),
-			cid_pres2ss7screen(redirecting->from.number.presentation));
-	}
-
-	isup_set_redirection_info(p->ss7call, ss7_redirect_info_ind(ast),
-		ss7_redirect_reason(p, ast_channel_redirecting(ast), 1),
-		redirecting->count, ss7_redirect_reason(p, ast_channel_redirecting(ast), 0));
-}
-
 /*!
  * \brief Dial out using the specified SS7 channel.
  * \since 1.8
@@ -2834,13 +1531,6 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
 	int called_nai_strip;
 	char ss7_calling_nai;
 	int calling_nai_strip;
-	const char *col_req = NULL;
-	const char *ss7_cug_indicator_str;
-	const char *ss7_cug_interlock_ni;
-	const char *ss7_cug_interlock_code;
-	const char *ss7_interworking_indicator;
-	const char *ss7_forward_indicator_pmbits;
-	unsigned char ss7_cug_indicator;
 	const char *charge_str = NULL;
 	const char *gen_address = NULL;
 	const char *gen_digits = NULL;
@@ -2853,7 +1543,6 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
 	const char *call_ref_id = NULL;
 	const char *call_ref_pc = NULL;
 	const char *send_far = NULL;
-	const char *tmr = NULL;
 	char *c;
 	char *l;
 	char dest[256];
@@ -2885,27 +1574,47 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
 		return -1;
 	}
 
+	p->ss7call = isup_new_call(p->ss7->ss7);
+	if (!p->ss7call) {
+		ss7_rel(p->ss7);
+		ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
+		return -1;
+	}
+
 	called_nai_strip = 0;
 	ss7_called_nai = p->ss7->called_nai;
 	if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
-		called_nai_strip = ss7_parse_prefix(p, c + p->stripmsd, &ss7_called_nai);
+		if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
+			called_nai_strip = strlen(p->ss7->internationalprefix);
+			ss7_called_nai = SS7_NAI_INTERNATIONAL;
+		} else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
+			called_nai_strip = strlen(p->ss7->nationalprefix);
+			ss7_called_nai = SS7_NAI_NATIONAL;
+		} else {
+			ss7_called_nai = SS7_NAI_SUBSCRIBER;
+		}
 	}
 	isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
 
 	calling_nai_strip = 0;
 	ss7_calling_nai = p->ss7->calling_nai;
 	if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
-		calling_nai_strip = ss7_parse_prefix(p, l, &ss7_calling_nai);
+		if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
+			calling_nai_strip = strlen(p->ss7->internationalprefix);
+			ss7_calling_nai = SS7_NAI_INTERNATIONAL;
+		} else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
+			calling_nai_strip = strlen(p->ss7->nationalprefix);
+			ss7_calling_nai = SS7_NAI_NATIONAL;
+		} else {
+			ss7_calling_nai = SS7_NAI_SUBSCRIBER;
+		}
 	}
-
 	isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
-		p->use_callingpres ? cid_pres2ss7pres(ast_channel_connected(ast)->id.number.presentation)
-			: (l ? SS7_PRESENTATION_ALLOWED
-				: (ast_channel_connected(ast)->id.number.presentation == AST_PRES_UNAVAILABLE
-					? SS7_PRESENTATION_ADDR_NOT_AVAILABLE : SS7_PRESENTATION_RESTRICTED)),
+		p->use_callingpres ? cid_pres2ss7pres(ast_channel_connected(ast)->id.number.presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
 		p->use_callingpres ? cid_pres2ss7screen(ast_channel_connected(ast)->id.number.presentation) : SS7_SCREENING_USER_PROVIDED);
 
 	isup_set_oli(p->ss7call, ast_channel_connected(ast)->ani2);
+	isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
 
 	/* Set the charge number if it is set */
 	charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
@@ -2947,66 +1656,10 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
 	}
 
 	send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
-	if (send_far && strncmp("NO", send_far, strlen(send_far)) != 0) {
-		isup_far(p->ss7->ss7, p->ss7call);
-	}
-
-	tmr = pbx_builtin_getvar_helper(ast, "SS7_TMR_NUM");
-	if (tmr) {
-		isup_set_tmr(p->ss7call, atoi(tmr));
-	} else if ((tmr = pbx_builtin_getvar_helper(ast, "SS7_TMR")) && tmr[0] != '\0') {
-		if (!strcasecmp(tmr, "SPEECH")) {
-			isup_set_tmr(p->ss7call, SS7_TMR_SPEECH);
-		} else if (!strcasecmp(tmr, "SPARE")) {
-			isup_set_tmr(p->ss7call, SS7_TMR_SPARE);
-		} else if (!strcasecmp(tmr, "3K1_AUDIO")) {
-			isup_set_tmr(p->ss7call, SS7_TMR_3K1_AUDIO);
-		} else if (!strcasecmp(tmr, "64K_UNRESTRICTED")) {
-			isup_set_tmr(p->ss7call, SS7_TMR_64K_UNRESTRICTED);
-		} else {
-			isup_set_tmr(p->ss7call, SS7_TMR_N64K_OR_SPARE);
-		}
-	}
-
-	col_req = pbx_builtin_getvar_helper(ast, "SS7_COL_REQUEST");
-	if (ast_true(col_req)) {
-		isup_set_col_req(p->ss7call);
-	}
-
-	ss7_cug_indicator_str = pbx_builtin_getvar_helper(ast, "SS7_CUG_INDICATOR");
-	if (!ast_strlen_zero(ss7_cug_indicator_str)) {
-		if (!strcasecmp(ss7_cug_indicator_str, "OUTGOING_ALLOWED")) {
-			ss7_cug_indicator = ISUP_CUG_OUTGOING_ALLOWED;
-		} else if (!strcasecmp(ss7_cug_indicator_str, "OUTGOING_NOT_ALLOWED")) {
-			ss7_cug_indicator = ISUP_CUG_OUTGOING_NOT_ALLOWED;
-		} else {
-			ss7_cug_indicator = ISUP_CUG_NON;
-		}
-
-		if (ss7_cug_indicator != ISUP_CUG_NON) {
-			ss7_cug_interlock_code = pbx_builtin_getvar_helper(ast, "SS7_CUG_INTERLOCK_CODE");
-			ss7_cug_interlock_ni = pbx_builtin_getvar_helper(ast, "SS7_CUG_INTERLOCK_NI");
-			if (ss7_cug_interlock_code && ss7_cug_interlock_ni && strlen(ss7_cug_interlock_ni) == 4) {
-				isup_set_cug(p->ss7call, ss7_cug_indicator, ss7_cug_interlock_ni, atoi(ss7_cug_interlock_code));
-			}
-		}
-	}
-
-	ss7_redirecting_update(p, ast);
-
-	isup_set_echocontrol(p->ss7call, (p->ss7->flags & LINKSET_FLAG_DEFAULTECHOCONTROL) ? 1 : 0);
-	ss7_interworking_indicator = pbx_builtin_getvar_helper(ast, "SS7_INTERWORKING_INDICATOR");
-	if (ss7_interworking_indicator) {
-		isup_set_interworking_indicator(p->ss7call, ast_true(ss7_interworking_indicator));
-	}
-
-	ss7_forward_indicator_pmbits = pbx_builtin_getvar_helper(ast, "SS7_FORWARD_INDICATOR_PMBITS");
-	if (ss7_forward_indicator_pmbits) {
-		isup_set_forward_indicator_pmbits(p->ss7call, atoi(ss7_forward_indicator_pmbits));
-	}
+	if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
+		(isup_far(p->ss7->ss7, p->ss7call));
 
 	p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
-	p->do_hangup = SS7_HANGUP_SEND_REL;
 	isup_iam(p->ss7->ss7, p->ss7call);
 	sig_ss7_set_dialing(p, 1);
 	ast_setstate(ast, AST_STATE_DIALING);
@@ -3026,6 +1679,8 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rd
  */
 int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
 {
+	int res = 0;
+
 	if (!ast_channel_tech_pvt(ast)) {
 		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
 		return 0;
@@ -3041,51 +1696,22 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
 	ss7_grab(p, p->ss7);
 	p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
 	if (p->ss7call) {
-		switch (p->do_hangup) {
-		case SS7_HANGUP_SEND_REL:
-			{
-				const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
-				int icause = ast_channel_hangupcause(ast) ? ast_channel_hangupcause(ast) : -1;
-
-				if (cause) {
-					if (atoi(cause)) {
-						icause = atoi(cause);
-					}
-				}
-				if (icause > 255) {
-					icause = 16;
-				}
+		if (!p->alreadyhungup) {
+			const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
+			int icause = ast_channel_hangupcause(ast) ? ast_channel_hangupcause(ast) : -1;
 
-				isup_rel(p->ss7->ss7, p->ss7call, icause);
-				p->do_hangup = SS7_HANGUP_DO_NOTHING;
+			if (cause) {
+				if (atoi(cause)) {
+					icause = atoi(cause);
+				}
 			}
-			break;
-		case SS7_HANGUP_SEND_RSC:
-			ss7_do_rsc(p);
-			p->do_hangup = SS7_HANGUP_DO_NOTHING;
-			break;
-		case SS7_HANGUP_SEND_RLC:
-			isup_rlc(p->ss7->ss7, p->ss7call);
-			p->do_hangup = SS7_HANGUP_DO_NOTHING;
-			p->ss7call = isup_free_call_if_clear(p->ss7->ss7, p->ss7call);
-			break;
-		case SS7_HANGUP_FREE_CALL:
-			p->do_hangup = SS7_HANGUP_DO_NOTHING;
-			isup_free_call(p->ss7->ss7, p->ss7call);
-			p->ss7call = NULL;
-			break;
-		case SS7_HANGUP_REEVENT_IAM:
-			isup_event_iam(p->ss7->ss7, p->ss7call, p->dpc);
-			p->do_hangup = SS7_HANGUP_SEND_REL;
-			break;
-		case SS7_HANGUP_DO_NOTHING:
-			p->ss7call = isup_free_call_if_clear(p->ss7->ss7, p->ss7call);
-			break;
+			isup_rel(p->ss7->ss7, p->ss7call, icause);
+			p->alreadyhungup = 1;
 		}
 	}
 	ss7_rel(p->ss7);
 
-	return 0;
+	return res;
 }
 
 /*!
@@ -3104,14 +1730,10 @@ int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
 
 	ss7_grab(p, p->ss7);
 	if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
-		if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && (p->ss7->flags & LINKSET_FLAG_AUTOACM)) {
-			isup_acm(p->ss7->ss7, p->ss7call);
-		}
 		p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
 	}
-
-	res = isup_anm(p->ss7->ss7, p->ss7call);
 	sig_ss7_open_media(p);
+	res = isup_anm(p->ss7->ss7, p->ss7call);
 	ss7_rel(p->ss7);
 	return res;
 }
@@ -3134,7 +1756,7 @@ void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, str
 }
 
 /*!
- * \brief SS7 indication.
+ * \brief SS7 answer channel.
  * \since 1.8
  *
  * \param p Signaling private structure pointer.
@@ -3163,20 +1785,15 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
 	case AST_CONTROL_RINGING:
 		ss7_grab(p, p->ss7);
 		if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
+			p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
 			if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
 				p->rlt = 1;
 			}
 
-			if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && (p->ss7->flags & LINKSET_FLAG_AUTOACM)) {
-				isup_acm(p->ss7->ss7, p->ss7call);
-			}
-
 			/* No need to send CPG if call will be RELEASE */
 			if (p->rlt != 1) {
 				isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
 			}
-
-			p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
 		}
 		ss7_rel(p->ss7);
 
@@ -3208,15 +1825,15 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
 		ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",ast_channel_name(chan));
 		ss7_grab(p, p->ss7);
 		if (!p->progress && p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
-			p->progress = 1;	/* No need to send inband-information progress again. */
+			p->progress = 1;/* No need to send inband-information progress again. */
 			isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
+			ss7_rel(p->ss7);
 
 			/* enable echo canceler here on SS7 calls */
-			if (!p->echocontrol_ind || !(p->ss7->flags & LINKSET_FLAG_USEECHOCONTROL)) {
-				sig_ss7_set_echocanceller(p, 1);
-			}
+			sig_ss7_set_echocanceller(p, 1);
+		} else {
+			ss7_rel(p->ss7);
 		}
-		ss7_rel(p->ss7);
 		/* don't continue in ast_indicate */
 		res = 0;
 		break;
@@ -3248,14 +1865,6 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
 	case AST_CONTROL_SRCUPDATE:
 		res = 0;
 		break;
-	case AST_CONTROL_CONNECTED_LINE:
-		ss7_connected_line_update(p, ast_channel_connected(chan));
-		res = 0;
-		break;
-	case AST_CONTROL_REDIRECTING:
-		ss7_redirecting_update(p, chan);
-		res = 0;
-		break;
 	case -1:
 		res = sig_ss7_play_tone(p, -1);
 		break;
@@ -3275,9 +1884,7 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
  * \retval ast_channel on success.
  * \retval NULL on error.
  */
-struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	int transfercapability)
+struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_channel *requestor, int transfercapability)
 {
 	struct ast_channel *ast;
 
@@ -3289,15 +1896,13 @@ struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law
 	}
 
 	sig_ss7_set_outgoing(p, 1);
-	ast = sig_ss7_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability,
-		p->exten, assignedids, requestor);
+	ast = sig_ss7_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
 	if (!ast) {
 		sig_ss7_set_outgoing(p, 0);
 
 		/* Release the allocated channel.  Only have to deal with the linkset lock. */
 		ast_mutex_lock(&p->ss7->lock);
 		p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
-		isup_free_call(p->ss7->ss7, p->ss7call);
 		ast_mutex_unlock(&p->ss7->lock);
 	}
 	return ast;
diff --git a/channels/sig_ss7.h b/channels/sig_ss7.h
index e2bc8e4..6b62d85 100644
--- a/channels/sig_ss7.h
+++ b/channels/sig_ss7.h
@@ -66,13 +66,6 @@ extern "C" {
 #define SS7_NAI_DYNAMIC		-1
 
 #define LINKSET_FLAG_EXPLICITACM (1 << 0)
-#define LINKSET_FLAG_INITIALHWBLO (1 << 1)
-#define LINKSET_FLAG_USEECHOCONTROL (1 << 2)
-#define LINKSET_FLAG_DEFAULTECHOCONTROL (1 << 3)
-#define LINKSET_FLAG_AUTOACM (1 << 4)
-
-#define SS7_BLOCKED_MAINTENANCE	(1 << 0)
-#define SS7_BLOCKED_HARDWARE	(1 << 1)
 
 
 enum sig_ss7_tone {
@@ -91,27 +84,6 @@ enum sig_ss7_law {
 	SIG_SS7_ALAW
 };
 
-enum sig_ss7_redirect_idication {
-	SS7_INDICATION_NO_REDIRECTION = 0,
-	SS7_INDICATION_REROUTED_PRES_ALLOWED,
-	SS7_INDICATION_REROUTED_INFO_RESTRICTED,
-	SS7_INDICATION_DIVERTED_PRES_ALLOWED,
-	SS7_INDICATION_DIVERTED_INFO_RESTRICTED,
-	SS7_INDICATION_REROUTED_PRES_RESTRICTED,
-	SS7_INDICATION_DIVERTED_PRES_RESTRICTED,
-	SS7_INDICATION_SPARE
-};
-
-enum sig_ss7_redirect_reason {
-	SS7_REDIRECTING_REASON_UNKNOWN = 0,
-	SS7_REDIRECTING_REASON_USER_BUSY,
-	SS7_REDIRECTING_REASON_NO_ANSWER,
-	SS7_REDIRECTING_REASON_UNCONDITIONAL,
-	SS7_REDIRECTING_REASON_DEFLECTION_DURING_ALERTING,
-	SS7_REDIRECTING_REASON_DEFLECTION_IMMEDIATE_RESPONSE,
-	SS7_REDIRECTING_REASON_UNAVAILABLE
-};
-
 /*! Call establishment life cycle level for simple comparisons. */
 enum sig_ss7_call_level {
 	/*! Call does not exist. */
@@ -146,6 +118,8 @@ enum sig_ss7_call_level {
 	 * We have sent or received CON/ANM.
 	 */
 	SIG_SS7_CALL_LEVEL_CONNECT,
+	/*! Call has collided with incoming call. */
+	SIG_SS7_CALL_LEVEL_GLARE,
 };
 
 struct sig_ss7_linkset;
@@ -161,9 +135,7 @@ struct sig_ss7_callback {
 	int (* const set_echocanceller)(void *pvt, int enable);
 	void (* const set_loopback)(void *pvt, int enable);
 
-	struct ast_channel * (* const new_ast_channel)(void *pvt, int state,
-		enum sig_ss7_law law, char *exten, const struct ast_assigned_ids *assignedids,
-		const struct ast_channel *requestor);
+	struct ast_channel * (* const new_ast_channel)(void *pvt, int state, enum sig_ss7_law law, char *exten, const struct ast_channel *requestor);
 	int (* const play_tone)(void *pvt, enum sig_ss7_tone tone);
 
 	void (* const handle_link_exception)(struct sig_ss7_linkset *linkset, int which);
@@ -179,8 +151,6 @@ struct sig_ss7_callback {
 
 	void (* const queue_control)(void *pvt, int subclass);
 	void (* const open_media)(void *pvt);
-
-	struct sig_ss7_linkset *(* const find_linkset)(struct ss7 *ss7);
 };
 
 /*! Global sig_ss7 callbacks to the upper layer. */
@@ -220,19 +190,10 @@ struct sig_ss7_chan {
 	unsigned int use_callingpres:1;
 	unsigned int immediate:1;		/*!< Answer before getting digits? */
 
-	/*!
-	 * \brief Bitmask for the channel being locally blocked.
-	 * \note 1 maintenance blocked, 2 blocked in hardware.
-	 * \note Set by user and link.
-	 */
-	unsigned int locallyblocked:2;
-
-	/*!
-	 * \brief Bitmask for the channel being remotely blocked.
-	 * \note 1 maintenance blocked, 2 blocked in hardware.
-	 * \note Set by user and link.
-	 */
-	unsigned int remotelyblocked:2;
+	/*! \brief TRUE if the channel is locally blocked.  Set by user and link. */
+	unsigned int locallyblocked:1;
+	/*! \brief TRUE if the channel is remotely blocked.  Set by user and link. */
+	unsigned int remotelyblocked:1;
 
 	char context[AST_MAX_CONTEXT];
 	char mohinterpret[MAX_MUSICCLASS];
@@ -252,15 +213,7 @@ struct sig_ss7_chan {
 	char gen_add_number[50];
 	char gen_dig_number[50];
 	char orig_called_num[50];
-	int orig_called_presentation;
 	char redirecting_num[50];
-	int redirecting_presentation;
-	unsigned char redirect_counter;
-	unsigned char redirect_info;
-	unsigned char redirect_info_ind;
-	unsigned char redirect_info_orig_reas;
-	unsigned char redirect_info_counter;
-	unsigned char redirect_info_reas;
 	char generic_name[50];
 	unsigned char gen_add_num_plan;
 	unsigned char gen_add_nai;
@@ -278,41 +231,22 @@ struct sig_ss7_chan {
 	unsigned int call_ref_ident;
 	unsigned int call_ref_pc;
 	unsigned char calling_party_cat;
-	unsigned int do_hangup;	/* What we have to do to clear the call */
-	unsigned int echocontrol_ind;
 
 	/*
 	 * Channel status bits.
 	 */
-	/*! \brief TRUE if channel is associated with a link that is down. */
+	/*! TRUE if channel is associated with a link that is down. */
 	unsigned int inalarm:1;
-	/*! \brief TRUE if channel is in service. */
-	unsigned int inservice:1;
-	/*! \brief TRUE if this channel is being used for an outgoing call. */
+	/*! TRUE if this channel is being used for an outgoing call. */
 	unsigned int outgoing:1;
-	/*! \brief TRUE if the channel has completed collecting digits. */
-	unsigned int called_complete:1;
 	/*! \brief TRUE if the call has seen inband-information progress through the network. */
 	unsigned int progress:1;
+	/*! \brief TRUE if the call has already gone/hungup */
+	unsigned int alreadyhungup:1;
 	/*! \brief XXX BOOLEAN Purpose??? */
 	unsigned int rlt:1;
-	/*! \brief TRUE if this channel is in loopback. */
+	/*! TRUE if this channel is in loopback. */
 	unsigned int loopedback:1;
-
-	/*
-	 * Closed User Group fields Q.735.1
-	 */
-	/*! \brief Network Identify Code as per Q.763 3.15.a */
-	char cug_interlock_ni[5];
-	/*! \brief Binari Code to uniquely identify a CUG inside the network. */
-	unsigned short cug_interlock_code;
-	/*!
-	 * \brief Indication of the call being a CUG call and its permissions.
-	 * \note 0 or 1 - non-CUG call
-	 * \note 2 - CUG call, outgoing access alowed
-	 * \note 3 - CUG call, outgoing access not alowed
-	 */
-	unsigned char cug_indicator;
 };
 
 struct sig_ss7_linkset {
@@ -340,7 +274,6 @@ struct sig_ss7_linkset {
 	char nationalprefix[10];			/*!< area access code ('0' for european dialplans) */
 	char subscriberprefix[20];			/*!< area access code + area code ('0'+area code for european dialplans) */
 	char unknownprefix[20];				/*!< for unknown dialplans */
-	char networkroutedprefix[20];
 };
 
 void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm);
@@ -349,35 +282,22 @@ void *ss7_linkset(void *data);
 
 void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which);
 void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which);
-int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc);
-
-int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc);
-int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range);
-int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int cic);
-int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int startcic, int endcic, unsigned char state[], int type);
+int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode);
 
 int sig_ss7_available(struct sig_ss7_chan *p);
 int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rdest);
 int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast);
 int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast);
-int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc);
-int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc);
 void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan);
 int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen);
-struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law,
-	const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
-	int transfercapability);
+struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_channel *requestor, int transfercapability);
 void sig_ss7_chan_delete(struct sig_ss7_chan *doomed);
 struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_linkset *ss7);
 void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7);
-void sig_ss7_free_isup_call(struct sig_ss7_linkset *linkset, int channel);
 
 void sig_ss7_cli_show_channels_header(int fd);
 void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset);
 
-int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup);
-void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *c, int lock);
-void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc);
 
 /* ------------------------------------------------------------------- */
 
diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c
index 3546cb4..f86971c 100644
--- a/channels/sip/config_parser.c
+++ b/channels/sip/config_parser.c
@@ -20,12 +20,12 @@
  */
 
 /*** MODULEINFO
-	<support_level>extended</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420562 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "include/sip.h"
 #include "include/config_parser.h"
@@ -40,7 +40,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const
 {
 	int portnum = 0;
 	int domainport = 0;
-	enum ast_transport transport = AST_TRANSPORT_UDP;
+	enum sip_transport transport = SIP_TRANSPORT_UDP;
 	char buf[256] = "";
 	char *userpart = NULL, *hostpart = NULL;
 	/* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
@@ -230,21 +230,21 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const
 
 	/* set transport type */
 	if (!pre2.transport) {
-		transport = AST_TRANSPORT_UDP;
+		transport = SIP_TRANSPORT_UDP;
 	} else if (!strncasecmp(pre2.transport, "tcp", 3)) {
-		transport = AST_TRANSPORT_TCP;
+		transport = SIP_TRANSPORT_TCP;
 	} else if (!strncasecmp(pre2.transport, "tls", 3)) {
-		transport = AST_TRANSPORT_TLS;
+		transport = SIP_TRANSPORT_TLS;
 	} else if (!strncasecmp(pre2.transport, "udp", 3)) {
-		transport = AST_TRANSPORT_UDP;
+		transport = SIP_TRANSPORT_UDP;
 	} else {
-		transport = AST_TRANSPORT_UDP;
+		transport = SIP_TRANSPORT_UDP;
 		ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
 	}
 
 	/* if no portnum specified, set default for transport */
 	if (!portnum) {
-		if (transport == AST_TRANSPORT_TLS) {
+		if (transport == SIP_TRANSPORT_TLS) {
 			portnum = STANDARD_TLS_PORT;
 		} else {
 			portnum = STANDARD_SIP_PORT;
@@ -314,7 +314,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "")           ||
 		strcmp(reg->secret, "")             ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -343,7 +343,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -372,7 +372,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -401,7 +401,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -430,7 +430,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_TCP ||
+		reg->transport != SIP_TRANSPORT_TCP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -459,7 +459,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_TLS ||
+		reg->transport != SIP_TRANSPORT_TLS ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != 111 ||
@@ -488,7 +488,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "peer")           ||
-		reg->transport != AST_TRANSPORT_TCP ||
+		reg->transport != SIP_TRANSPORT_TCP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != 111 ||
@@ -517,7 +517,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "peer")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != 111 ||
@@ -587,7 +587,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "authuser")           ||
 		strcmp(reg->secret, "pass")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -616,7 +616,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test)
 		strcmp(reg->authuser, "")           ||
 		strcmp(reg->secret, "")         ||
 		strcmp(reg->peername, "")           ||
-		reg->transport != AST_TRANSPORT_UDP ||
+		reg->transport != SIP_TRANSPORT_UDP ||
 		reg->timeout != -1                  ||
 		reg->expire != -1                   ||
 		reg->refresh != default_expiry ||
@@ -641,7 +641,7 @@ alloc_fail:
 	return res;
 }
 
-int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport)
+int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport)
 {
 	char *port;
 
@@ -653,11 +653,11 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a
 		*hostname += 3;
 
 		if (!strncasecmp(line, "tcp", 3)) {
-			*transport = AST_TRANSPORT_TCP;
+			*transport = SIP_TRANSPORT_TCP;
 		} else if (!strncasecmp(line, "tls", 3)) {
-			*transport = AST_TRANSPORT_TLS;
+			*transport = SIP_TRANSPORT_TLS;
 		} else if (!strncasecmp(line, "udp", 3)) {
-			*transport = AST_TRANSPORT_UDP;
+			*transport = SIP_TRANSPORT_UDP;
 		} else if (lineno) {
 			ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
 		} else {
@@ -665,7 +665,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a
 		}
 	} else {
 		*hostname = line;
-		*transport = AST_TRANSPORT_UDP;
+		*transport = SIP_TRANSPORT_UDP;
 	}
 
 	if ((line = strrchr(*hostname, '@')))
@@ -695,7 +695,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a
 	}
 
 	if (!port) {
-		if (*transport & AST_TRANSPORT_TLS) {
+		if (*transport & SIP_TRANSPORT_TLS) {
 			*portnum = STANDARD_TLS_PORT;
 		} else {
 			*portnum = STANDARD_SIP_PORT;
@@ -710,7 +710,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	int res = AST_TEST_PASS;
 	char *host;
 	int port;
-	enum ast_transport transport;
+	enum sip_transport transport;
 	char host1[] = "www.blah.com";
 	char host2[] = "tcp://www.blah.com";
 	char host3[] = "tls://10.10.10.10";
@@ -734,7 +734,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	sip_parse_host(host1, 1, &host, &port, &transport);
 	if (port != STANDARD_SIP_PORT ||
 			ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
-			transport != AST_TRANSPORT_UDP) {
+			transport != SIP_TRANSPORT_UDP) {
 		ast_test_status_update(test, "Test 1: simple host failed.\n");
 		res = AST_TEST_FAIL;
 	}
@@ -743,7 +743,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	sip_parse_host(host2, 1, &host, &port, &transport);
 	if (port != STANDARD_SIP_PORT ||
 			ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
-			transport != AST_TRANSPORT_TCP) {
+			transport != SIP_TRANSPORT_TCP) {
 		ast_test_status_update(test, "Test 2: tcp host failed.\n");
 		res = AST_TEST_FAIL;
 	}
@@ -752,7 +752,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	sip_parse_host(host3, 1, &host, &port, &transport);
 	if (port != STANDARD_TLS_PORT ||
 			ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
-			transport != AST_TRANSPORT_TLS) {
+			transport != SIP_TRANSPORT_TLS) {
 		ast_test_status_update(test, "Test 3: tls host failed. \n");
 		res = AST_TEST_FAIL;
 	}
@@ -761,7 +761,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	sip_parse_host(host4, 1, &host, &port, &transport);
 	if (port != 1234 || ast_strlen_zero(host) ||
 			strcmp(host, "10.10.10.10") ||
-			transport != AST_TRANSPORT_TLS) {
+			transport != SIP_TRANSPORT_TLS) {
 		ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
 		res = AST_TEST_FAIL;
 	}
@@ -770,7 +770,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test)
 	sip_parse_host(host5, 1, &host, &port, &transport);
 	if (port != 1234 || ast_strlen_zero(host) ||
 			strcmp(host, "10.10.10.10") ||
-			transport != AST_TRANSPORT_UDP) {
+			transport != SIP_TRANSPORT_UDP) {
 		ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
 		res = AST_TEST_FAIL;
 	}
diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c
index e8c2e15..f0bcfea 100644
--- a/channels/sip/dialplan_functions.c
+++ b/channels/sip/dialplan_functions.c
@@ -20,12 +20,12 @@
  */
 
 /*** MODULEINFO
-	<support_level>extended</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420562 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
@@ -76,8 +76,6 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p
 		ast_copy_string(buf, ast_sockaddr_isnull(&p->sa) ? "" : ast_sockaddr_stringify_addr(&p->sa), buflen);
 	} else if (!strcasecmp(args.param, "recvip")) {
 		ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_addr(&p->recv), buflen);
-	} else if (!strcasecmp(args.param, "recvport")) {
-		ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_port(&p->recv), buflen);
 	} else if (!strcasecmp(args.param, "from")) {
 		ast_copy_string(buf, p->from, buflen);
 	} else if (!strcasecmp(args.param, "uri")) {
@@ -228,7 +226,7 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p
 			return -1;
 		}
 	} else if (!strcasecmp(args.param, "secure_signaling")) {
-		snprintf(buf, buflen, "%s", p->socket.type == AST_TRANSPORT_TLS ? "1" : "");
+		snprintf(buf, buflen, "%s", p->socket.type == SIP_TRANSPORT_TLS ? "1" : "");
 	} else if (!strcasecmp(args.param, "secure_media")) {
 		snprintf(buf, buflen, "%s", p->srtp ? "1" : "");
 	} else {
@@ -386,7 +384,7 @@ AST_TEST_DEFINE(test_sip_rtpqos_1)
 			for (j = 1.0; j < 10.0; j += 0.3) {
 				*lookup[i].d8 = j;
 				ast_str_substitute_variables(&buffer, 0, chan, ast_str_buffer(varstr));
-				if (sscanf(ast_str_buffer(buffer), "%lf", &cmpdbl) != 1 || fabs(j - cmpdbl > .05)) {
+				if (sscanf(ast_str_buffer(buffer), "%lf", &cmpdbl) != 1 || fabs(j - cmpdbl) > .05) {
 					res = AST_TEST_FAIL;
 					ast_test_status_update(test, "%s != %f != %s\n", ast_str_buffer(varstr), j, ast_str_buffer(buffer));
 					break;
diff --git a/channels/sip/include/config_parser.h b/channels/sip/include/config_parser.h
index fd055b1..2737016 100644
--- a/channels/sip/include/config_parser.h
+++ b/channels/sip/include/config_parser.h
@@ -41,7 +41,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const
  * \retval 0 on success
  * \retval -1 on failure
  */
-int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport);
+int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport);
 
 /*! \brief Parse the comma-separated nat= option values
  * \param value The comma-separated value
diff --git a/channels/sip/include/reqresp_parser.h b/channels/sip/include/reqresp_parser.h
index 2543329..8fb8035 100644
--- a/channels/sip/include/reqresp_parser.h
+++ b/channels/sip/include/reqresp_parser.h
@@ -22,30 +22,6 @@
 #ifndef _SIP_REQRESP_H
 #define _SIP_REQRESP_H
 
-/*! \brief uri parameters */
-struct uriparams {
-	char *transport;
-	char *user;
-	char *method;
-	char *ttl;
-	char *maddr;
-	int lr;
-};
-
-struct contact {
-	AST_LIST_ENTRY(contact) list;
-	char *name;
-	char *user;
-	char *pass;
-	char *hostport;
-	struct uriparams params;
-	char *headers;
-	char *expires;
-	char *q;
-};
-
-AST_LIST_HEAD_NOLOCK(contactliststruct, contact);
-
 /*!
  * \brief parses a URI in its components.
  *
diff --git a/channels/sip/include/route.h b/channels/sip/include/route.h
deleted file mode 100644
index 511f0ff..0000000
--- a/channels/sip/include/route.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief sip_route header file
- */
-
-#ifndef _SIP_ROUTE_H
-#define _SIP_ROUTE_H
-
-#include "asterisk/linkedlists.h"
-#include "asterisk/strings.h"
-
-/*!
- * \brief Opaque storage of a sip route hop
- */
-struct sip_route_hop;
-
-/*!
- * \internal \brief Internal enum to remember last calculated
- */
-enum sip_route_type {
-	route_loose = 0,    /*!< The first hop contains ;lr or does not exist */
-	route_strict,       /*!< The first hop exists and does not contain ;lr */
-	route_invalidated,  /*!< strict/loose routing needs to be rechecked */
-};
-
-/*!
- * \brief Structure to store route information
- *
- * \note This must be zero-filled on allocation
- */
-struct sip_route {
-	AST_LIST_HEAD_NOLOCK(, sip_route_hop) list;
-	enum sip_route_type type;
-};
-
-/*!
- * \brief Add a new hop to the route
- *
- * \param route Route
- * \param uri Address of this hop
- * \param len Length of hop not including null terminator
- * \param inserthead If true then inserted the new route to the top of the list
- *
- * \retval Pointer to null terminated copy of URI on success
- * \retval NULL on error
- */
-const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead);
-
-/*!
- * \brief Add routes from header
- *
- * \note This procedure is for headers that require use of <brackets>.
- */
-void sip_route_process_header(struct sip_route *route, const char *header, int inserthead);
-
-/*!
- * \brief copy route-set
- *
- * \retval non-zero on failure
- * \retval 0 on success
- */
-void sip_route_copy(struct sip_route *dst, const struct sip_route *src);
-
-/*!
- * \brief Free all routes in the list
- */
-void sip_route_clear(struct sip_route *route);
-
-/*!
- * \brief Verbose dump of all hops for debugging
- */
-void sip_route_dump(const struct sip_route *route);
-
-/*!
- * \brief Make the comma separated list of route hops
- *
- * \param route Source of route list
- * \param formatcli Add's space after comma's, print's N/A if list is empty.
- * \param skip Number of hops to skip
- *
- * \retval an allocated struct ast_str on success
- * \retval NULL on failure
- */
-struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
-		__attribute_malloc__ __attribute_warn_unused_result__;
-
-/*!
- * \brief Check if the route is strict
- *
- * \note The result is cached in route->type
- */
-int sip_route_is_strict(struct sip_route *route);
-
-/*!
- * \brief Get the URI of the route's first hop
- */
-const char *sip_route_first_uri(const struct sip_route *route);
-
-/*!
- * \brief Check if route has no URI's
- */
-#define sip_route_empty(route) AST_LIST_EMPTY(&(route)->list)
-
-#endif
diff --git a/channels/sip/include/sdp_crypto.h b/channels/sip/include/sdp_crypto.h
new file mode 100644
index 0000000..aa553cb
--- /dev/null
+++ b/channels/sip/include/sdp_crypto.h
@@ -0,0 +1,84 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006 - 2007, Mikael Magnusson
+ *
+ * Mikael Magnusson <mikma at users.sourceforge.net>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file sdp_crypto.h
+ *
+ * \brief SDP Security descriptions
+ *
+ * Specified in RFC 4568
+ *
+ * \author Mikael Magnusson <mikma at users.sourceforge.net>
+ */
+
+#ifndef _SDP_CRYPTO_H
+#define _SDP_CRYPTO_H
+
+#include <asterisk/rtp_engine.h>
+
+struct sdp_crypto;
+struct sip_srtp;
+
+/*! \brief Initialize an return an sdp_crypto struct
+ *
+ * \details
+ * This function allocates a new sdp_crypto struct and initializes its values
+ *
+ * \retval NULL on failure
+ * \retval a pointer to a  new sdp_crypto structure
+ */
+struct sdp_crypto *sdp_crypto_setup(void);
+
+/*! \brief Destroy a previously allocated sdp_crypto struct */
+void sdp_crypto_destroy(struct sdp_crypto *crypto);
+
+/*! \brief Parse the a=crypto line from SDP and set appropriate values on the
+ * sdp_crypto struct.
+ *
+ * \param p A valid sdp_crypto struct
+ * \param attr the a:crypto line from SDP
+ * \param rtp The rtp instance associated with the SDP being parsed
+ * \param srtp SRTP structure
+ *
+ * \retval 0 success
+ * \retval nonzero failure
+ */
+int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp);
+
+
+/*! \brief Generate an SRTP a=crypto offer
+ *
+ * \details
+ * The offer is stored on the sdp_crypto struct in a_crypto
+ *
+ * \param A valid sdp_crypto struct
+ *
+ * \retval 0 success
+ * \retval nonzero failure
+ */
+int sdp_crypto_offer(struct sdp_crypto *p, int taglen);
+
+
+/*! \brief Return the a_crypto value of the sdp_crypto struct
+ *
+ * \param p An sdp_crypto struct that has had sdp_crypto_offer called
+ *
+ * \retval The value of the a_crypto for p
+ */
+const char *sdp_crypto_attrib(struct sdp_crypto *p);
+
+#endif	/* _SDP_CRYPTO_H */
diff --git a/channels/sip/include/security_events.h b/channels/sip/include/security_events.h
index cee2fa7..1d0f58b 100644
--- a/channels/sip/include/security_events.h
+++ b/channels/sip/include/security_events.h
@@ -38,6 +38,7 @@ void sip_report_failed_challenge_response(const struct sip_pvt *p, const char *r
 void sip_report_chal_sent(const struct sip_pvt *p);
 void sip_report_inval_transport(const struct sip_pvt *p, const char *transport);
 void sip_digest_parser(char *c, struct digestkeys *keys);
-int sip_report_security_event(const struct sip_pvt *p, const struct sip_request *req, const int res);
+int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
+			      const struct sip_request *req, const int res);
 
 #endif
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 68c2ee8..87a8c68 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -31,14 +31,12 @@
 #include "asterisk/test.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
+#include "asterisk/astobj.h"
 #include "asterisk/indications.h"
 #include "asterisk/security_events.h"
 #include "asterisk/features.h"
+#include "asterisk/http_websocket.h"
 #include "asterisk/rtp_engine.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/features_config.h"
-
-#include "route.h"
 
 #ifndef FALSE
 #define FALSE    0
@@ -219,6 +217,7 @@
 #define DEFAULT_QUALIFY        FALSE    /*!< Don't monitor devices */
 #define DEFAULT_KEEPALIVE      0        /*!< Don't send keep alive packets */
 #define DEFAULT_KEEPALIVE_INTERVAL 60   /*!< Send keep alive packets at 60 second intervals */
+#define DEFAULT_CALLEVENTS     FALSE    /*!< Extra manager SIP call events */
 #define DEFAULT_ALWAYSAUTHREJECT  TRUE  /*!< Don't reject authentication requests always */
 #define DEFAULT_AUTH_OPTIONS  FALSE
 #define DEFAULT_AUTH_MESSAGE  TRUE
@@ -295,7 +294,6 @@
 #define SIP_PROG_INBAND_NO     (1 << 25)
 #define SIP_PROG_INBAND_YES    (2 << 25)
 
-#define SIP_USEPATH          (1 << 27) /*!< GDP: Trust and use incoming Path headers? */
 #define SIP_SENDRPID         (3 << 29) /*!< DP: Remote Party-ID Support */
 #define SIP_SENDRPID_NO      (0 << 29)
 #define SIP_SENDRPID_PAI     (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */
@@ -306,7 +304,7 @@
 #define SIP_FLAGS_TO_COPY \
 	(SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
 	 SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT_FORCE_RPORT | SIP_G726_NONSTANDARD | \
-	 SIP_USEREQPHONE | SIP_INSECURE | SIP_USEPATH)
+	 SIP_USEREQPHONE | SIP_INSECURE)
 /*@}*/
 
 /*! \name SIPflags2
@@ -381,14 +379,11 @@
 #define SIP_PAGE3_DIRECT_MEDIA_OUTGOING  (1 << 4)  /*!< DP: Only send direct media reinvites on outgoing calls */
 #define SIP_PAGE3_USE_AVPF               (1 << 5)  /*!< DGP: Support a minimal AVPF-compatible profile */
 #define SIP_PAGE3_ICE_SUPPORT            (1 << 6)  /*!< DGP: Enable ICE support */
-#define SIP_PAGE3_IGNORE_PREFCAPS        (1 << 7)  /*!< DP: Ignore prefcaps when setting up an outgoing call leg */
-#define SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL  (1 << 8)  /*!< DGP: Stop telling the peer to start music on hold */
-#define SIP_PAGE3_FORCE_AVP              (1 << 9)  /*!< DGP: Force 'RTP/AVP' for all streams, even DTLS */
+#define SIP_PAGE3_FORCE_AVP              (1 << 7)  /*!< DGP: Force 'RTP/AVP' for all streams, even DTLS */
 
 #define SIP_PAGE3_FLAGS_TO_COPY \
 	(SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_NAT_AUTO_RPORT | SIP_PAGE3_NAT_AUTO_COMEDIA | \
-	 SIP_PAGE3_DIRECT_MEDIA_OUTGOING | SIP_PAGE3_USE_AVPF | SIP_PAGE3_ICE_SUPPORT | SIP_PAGE3_IGNORE_PREFCAPS | \
-	 SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL | SIP_PAGE3_FORCE_AVP)
+	 SIP_PAGE3_DIRECT_MEDIA_OUTGOING | SIP_PAGE3_USE_AVPF | SIP_PAGE3_ICE_SUPPORT | SIP_PAGE3_FORCE_AVP)
 
 #define CHECK_AUTH_BUF_INITLEN   256
 
@@ -475,7 +470,7 @@ enum subscriptiontype {
 /*! \brief The number of media types in enum \ref media_type below. */
 #define OFFERED_MEDIA_COUNT	4
 
-/*! \brief Media types generate different "dummy answers" for not accepting the offer of
+/*! \brief Media types generate different "dummy answers" for not accepting the offer of 
 	a media stream. We need to add definitions for each RTP profile. Secure RTP is not
 	the same as normal RTP and will require a new definition */
 enum media_type {
@@ -578,6 +573,17 @@ enum st_refresher_param {
 	SESSION_TIMER_REFRESHER_PARAM_UAS,
 };
 
+/*! \brief Define some implemented SIP transports
+	\note Asterisk does not support SCTP or UDP/DTLS
+*/
+enum sip_transport {
+	SIP_TRANSPORT_UDP = 1,         /*!< Unreliable transport for SIP, needs retransmissions */
+	SIP_TRANSPORT_TCP = 1 << 1,    /*!< Reliable, but unsecure */
+	SIP_TRANSPORT_TLS = 1 << 2,    /*!< TCP/TLS - reliable and secure transport for signalling */
+        SIP_TRANSPORT_WS  = 1 << 3,    /*!< WebSocket, unsecure */
+        SIP_TRANSPORT_WSS = 1 << 4,    /*!< WebSocket, secure */
+};
+
 /*! \brief Automatic peer registration behavior
 */
 enum autocreatepeer_mode {
@@ -709,7 +715,7 @@ struct sip_proxy {
 	struct ast_sockaddr ip;          /*!< Currently used IP address and port */
 	int port;
 	time_t last_dnsupdate;          /*!< When this was resolved */
-	enum ast_transport transport;
+	enum sip_transport transport;
 	int force;                      /*!< If it's an outbound proxy, Force use of this outbound proxy for all outbound requests */
 	/* Room for a SRV record chain based on the name */
 };
@@ -735,7 +741,6 @@ struct __show_chan_arg {
 struct sip_settings {
 	int peer_rtupdate;          /*!< G: Update database with registration data for peer? */
 	int rtsave_sysname;         /*!< G: Save system name at registration? */
-	int rtsave_path;            /*!< G: Save path header on registration */
 	int ignore_regexpire;       /*!< G: Ignore expiration of peer  */
 	int rtautoclear;            /*!< Realtime ?? */
 	int directrtpsetup;         /*!< Enable support for Direct RTP setup (no re-invites) */
@@ -749,6 +754,7 @@ struct sip_settings {
 	int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
 	int compactheaders;         /*!< send compact sip headers */
 	int allow_external_domains; /*!< Accept calls to external SIP domains? */
+	int callevents;             /*!< Whether we send manager events or not */
 	int regextenonqualify;      /*!< Whether to add/remove regexten when qualifying peers */
 	int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */
 	int send_diversion;	        /*!< Whether to Send SIP Diversion headers */
@@ -767,8 +773,8 @@ struct sip_settings {
 	struct sip_proxy outboundproxy; /*!< Outbound proxy */
 	char default_context[AST_MAX_CONTEXT];
 	char default_subscribecontext[AST_MAX_CONTEXT];
-	char default_record_on_feature[AST_FEATURE_MAX_LEN];
-	char default_record_off_feature[AST_FEATURE_MAX_LEN];
+	char default_record_on_feature[FEATURE_MAX_LEN];
+	char default_record_off_feature[FEATURE_MAX_LEN];
 	struct ast_acl_list *contact_acl;  /*! \brief Global list of addresses dynamic peers are not allowed to use */
 	struct ast_format_cap *caps; /*!< Supported codecs */
 	int tcp_enabled;
@@ -776,11 +782,9 @@ struct sip_settings {
 	int websocket_write_timeout; /*!< Socket write timeout for websocket transports, in ms */
 };
 
-struct ast_websocket;
-
 /*! \brief The SIP socket definition */
 struct sip_socket {
-	enum ast_transport type;  /*!< UDP, TCP or TLS */
+	enum sip_transport type;  /*!< UDP, TCP or TLS */
 	int fd;                   /*!< Filed descriptor, the actual socket */
 	uint16_t port;
 	struct ast_tcptls_session_instance *tcptls_session;  /* If tcp or tls, a socket manager */
@@ -825,7 +829,7 @@ struct sip_request {
 	char authenticated;     /*!< non-zero if this request was authenticated */
 	ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/
 	ptrdiff_t line[SIP_MAX_LINES];     /*!< Array of offsets into the request string of each SDP line*/
-	struct ast_str *data;
+	struct ast_str *data;	
 	struct ast_str *content;
 	/* XXX Do we need to unref socket.ser when the request goes away? */
 	struct sip_socket socket;          /*!< The socket used for this request */
@@ -842,6 +846,16 @@ struct sip_request {
  */
 #define REQ_OFFSET_TO_STR(req,offset) (ast_str_buffer((req)->data) + ((req)->offset))
 
+/*! \brief structure used in transfers */
+struct sip_dual {
+	struct ast_channel *chan1;   /*!< First channel involved */
+	struct ast_channel *chan2;   /*!< Second channel involved */
+	struct sip_request req;      /*!< Request that caused the transfer (REFER) */
+	uint32_t seqno;              /*!< Sequence number */
+	char *park_exten;
+	char *park_context;
+};
+
 /*! \brief Parameters to the transmit_invite function */
 struct sip_invite_param {
 	int addsipheaders;          /*!< Add extra SIP headers */
@@ -855,6 +869,12 @@ struct sip_invite_param {
 	struct sip_proxy *outboundproxy; /*!< Outbound proxy URI */
 };
 
+/*! \brief Structure to save routing information for a SIP session */
+struct sip_route {
+	struct sip_route *next;
+	char hop[0];
+};
+
 /*! \brief Structure to store Via information */
 struct sip_via {
 	char *via;
@@ -927,6 +947,10 @@ struct sip_refer {
 		AST_STRING_FIELD(replaces_callid_totag);   /*!< Replace info: to-tag */
 		AST_STRING_FIELD(replaces_callid_fromtag); /*!< Replace info: from-tag */
 	);
+	struct sip_pvt *refer_call;                     /*!< Call we are referring. This is just a reference to a
+							 * dialog owned by someone else, so we should not destroy
+							 * it when the sip_refer object goes.
+							 */
 	int attendedtransfer;                           /*!< Attended or blind transfer? */
 	int localtransfer;                              /*!< Transfer to local domain? */
 	enum referstatus status;                        /*!< REFER status */
@@ -1044,7 +1068,6 @@ struct sip_pvt {
 		AST_STRING_FIELD(last_presence_subtype);   /*!< The last presence subtype sent for a subscription. */
 		AST_STRING_FIELD(last_presence_message);   /*!< The last presence message for a subscription */
 		AST_STRING_FIELD(msg_body);     /*!< Text for a MESSAGE body */
-		AST_STRING_FIELD(tel_phone_context);       /*!< The phone-context portion of a TEL URI */
 	);
 	char via[128];                          /*!< Via: header */
 	int maxforwards;                        /*!< SIP Loop prevention */
@@ -1077,10 +1100,12 @@ struct sip_pvt {
 	                                       */
 	unsigned short req_secure_signaling:1;/*!< Whether we are required to have secure signaling or not */
 	unsigned short natdetected:1;         /*!< Whether we detected a NAT when processing the Via */
+	unsigned short invitereplaces:1;      /*!< Whether we are doing an Invite: Replaces */
 	int timer_t1;                     /*!< SIP timer T1, ms rtt */
 	int timer_b;                      /*!< SIP timer B, ms */
 	unsigned int sipoptions;          /*!< Supported SIP options on the other end */
 	unsigned int reqsipoptions;       /*!< Required SIP options on the other end */
+	struct ast_codec_pref prefs;      /*!< codec prefs */
 	struct ast_format_cap *caps;             /*!< Special capability (codec) */
 	struct ast_format_cap *jointcaps;        /*!< Supported capability at both ends (codecs) */
 	struct ast_format_cap *peercaps;         /*!< Supported peer capability */
@@ -1088,8 +1113,8 @@ struct sip_pvt {
 	struct ast_format_cap *prefcaps;         /*!< Preferred codec (outbound only) */
 	int noncodeccapability;	          /*!< DTMF RFC2833 telephony-event */
 	int jointnoncodeccapability;      /*!< Joint Non codec capability */
-	int maxcallbitrate;               /*!< Maximum Call Bitrate for Video Calls */
-	int t38_maxdatagram;              /*!< T.38 FaxMaxDatagram override */
+	int maxcallbitrate;               /*!< Maximum Call Bitrate for Video Calls */	
+	unsigned int t38_maxdatagram;              /*!< T.38 FaxMaxDatagram override */
 	int request_queue_sched_id;       /*!< Scheduler ID of any scheduled action to process queued requests */
 	int provisional_keepalive_sched_id;   /*!< Scheduler ID for provisional responses that need to be sent out to avoid cancellation */
 	const char *last_provisional;         /*!< The last successfully transmitted provisonal response message */
@@ -1121,7 +1146,7 @@ struct sip_pvt {
 	struct ast_sockaddr ourip;           /*!< Our IP (as seen from the outside) */
 	enum transfermodes allowtransfer;   /*!< REFER: restriction scheme */
 	struct ast_channel *owner;          /*!< Who owns us (if we have an owner) */
-	struct sip_route route;             /*!< List of routing steps (fm Record-Route) */
+	struct sip_route *route;            /*!< Head of linked list of routing steps (fm Record-Route) */
 	struct sip_notify *notify;          /*!< Custom notify type */
 	struct sip_auth_container *peerauth;/*!< Realm authentication credentials */
 	int noncecount;                     /*!< Nonce-count */
@@ -1167,9 +1192,9 @@ struct sip_pvt {
 	AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
 	struct sip_invite_param *options;   /*!< Options for INVITE */
 	struct sip_st_dlg *stimer;          /*!< SIP Session-Timers */
-	struct ast_sdp_srtp *srtp;              /*!< Structure to hold Secure RTP session data for audio */
-	struct ast_sdp_srtp *vsrtp;             /*!< Structure to hold Secure RTP session data for video */
-	struct ast_sdp_srtp *tsrtp;             /*!< Structure to hold Secure RTP session data for text */
+	struct sip_srtp *srtp;              /*!< Structure to hold Secure RTP session data for audio */
+	struct sip_srtp *vsrtp;             /*!< Structure to hold Secure RTP session data for video */
+	struct sip_srtp *tsrtp;             /*!< Structure to hold Secure RTP session data for text */
 
 	int red;                            /*!< T.140 RTP Redundancy */
 	int hangupcause;                    /*!< Storage of hangupcause copied from our owner before we disconnect from the AST channel (only used at hangup) */
@@ -1234,15 +1259,16 @@ struct sip_pkt {
 /*!
  * \brief A peer's mailbox
  *
- * We could use STRINGFIELDS here, but for only one string, its
+ * We could use STRINGFIELDS here, but for only two strings, it seems like
  * too much effort ...
  */
 struct sip_mailbox {
 	/*! Associated MWI subscription */
-	struct stasis_subscription *event_sub;
+	struct ast_event_sub *event_sub;
 	AST_LIST_ENTRY(sip_mailbox) entry;
 	unsigned int delme:1;
-	char id[1];
+	char *context;
+	char mailbox[2];
 };
 
 /*! \brief Structure for SIP peer data, we place calls to peers if registered  or fixed IP address (host)
@@ -1283,15 +1309,15 @@ struct sip_peer {
 		AST_STRING_FIELD(callback); /*!< Callback extension */
 		);
 	struct sip_socket socket;       /*!< Socket used for this peer */
-	enum ast_transport default_outbound_transport;   /*!< Peer Registration may change the default outbound transport.
+	enum sip_transport default_outbound_transport;   /*!< Peer Registration may change the default outbound transport.
 	                                                     If register expires, default should be reset. to this value */
 	/* things that don't belong in flags */
-	unsigned short transports:5;    /*!< Transports (enum ast_transport) that are acceptable for this peer */
+	unsigned short transports:5;    /*!< Transports (enum sip_transport) that are acceptable for this peer */
 	unsigned short is_realtime:1;   /*!< this is a 'realtime' peer */
 	unsigned short rt_fromcontact:1;/*!< copy fromcontact from realtime */
 	unsigned short host_dynamic:1;  /*!< Dynamic Peers register with Asterisk */
 	unsigned short selfdestruct:1;  /*!< Automatic peers need to destruct themselves */
-	unsigned short the_mark:1;      /*!< That which bears the_mark should be deleted! */
+	unsigned short the_mark:1;      /*!< moved out of ASTOBJ into struct proper; That which bears the_mark should be deleted! */
 	unsigned short autoframing:1;   /*!< Whether to use our local configuration for frame sizes (off)
 	                                 *   or respect the other endpoint's request for frame sizes (on)
 	                                 *   for incoming calls
@@ -1308,6 +1334,7 @@ struct sip_peer {
 	int busy_level;                 /*!< Level of active channels where we signal busy */
 	int maxforwards;                /*!< SIP Loop prevention */
 	enum transfermodes allowtransfer;   /*! SIP Refer restriction scheme */
+	struct ast_codec_pref prefs;    /*!<  codec prefs */
 	int lastmsgssent;				/*!< The last known VM message counts (new/old) */
 	unsigned int sipoptions;        /*!<  Supported SIP options */
 	struct ast_flags flags[3];      /*!<  SIP_ flags */
@@ -1347,15 +1374,12 @@ struct sip_peer {
 	int timer_t1;                   /*!<  The maximum T1 value for the peer */
 	int timer_b;                    /*!<  The maximum timer B (transaction timeouts) */
 	int fromdomainport;             /*!<  The From: domain port */
-	struct sip_route path;          /*!<  List of out-of-dialog outgoing routing steps (fm Path headers) */
 
 	/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */
 	enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */
 	unsigned int disallowed_methods;
 	struct ast_cc_config_params *cc_params;
 
-	struct ast_endpoint *endpoint;
-
 	struct ast_rtp_dtls_cfg dtls_cfg;
 };
 
@@ -1370,10 +1394,12 @@ struct sip_peer {
  * or once the previously completed registration one expires).
  * The registration can be in one of many states, though at the moment
  * the handling is a bit mixed.
+ *
+ * \todo Convert this to astobj2
  */
 struct sip_registry {
+	ASTOBJ_COMPONENTS_FULL(struct sip_registry, 80, 1);
 	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(configvalue);/*!< register string from config */
 		AST_STRING_FIELD(callid);     /*!< Global Call-ID */
 		AST_STRING_FIELD(realm);      /*!< Authorization realm */
 		AST_STRING_FIELD(nonce);      /*!< Authorization nonce */
@@ -1390,7 +1416,7 @@ struct sip_registry {
 		AST_STRING_FIELD(peername);   /*!< Peer registering to */
 		AST_STRING_FIELD(localtag);   /*!< Local tag generated same time as callid */
 	);
-	enum ast_transport transport;   /*!< Transport for this registration UDP, TCP or TLS */
+	enum sip_transport transport;   /*!< Transport for this registration UDP, TCP or TLS */
 	int portno;                     /*!< Optional port override */
 	int regdomainport;              /*!< Port override for domainport */
 	int expire;                     /*!< Sched ID of expiration */
@@ -1422,14 +1448,17 @@ struct sip_threadinfo {
 	int alert_pipe[2];          /*! Used to alert tcptls thread when packet is ready to be written */
 	pthread_t threadid;
 	struct ast_tcptls_session_instance *tcptls_session;
-	enum ast_transport type;    /*!< We keep a copy of the type here so we can display it in the connection list */
+	enum sip_transport type;    /*!< We keep a copy of the type here so we can display it in the connection list */
 	AST_LIST_HEAD_NOLOCK(, tcptls_packet) packet_q;
 };
 
 /*!
  * \brief Definition of an MWI subscription to another server
+ * 
+ * \todo Convert this to astobj2.
  */
 struct sip_subscription_mwi {
+	ASTOBJ_COMPONENTS_FULL(struct sip_subscription_mwi,1,1);
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(username);     /*!< Who we are sending the subscription as */
 		AST_STRING_FIELD(authuser);     /*!< Who we *authenticate* as */
@@ -1437,7 +1466,7 @@ struct sip_subscription_mwi {
 		AST_STRING_FIELD(secret);       /*!< Password in clear text */
 		AST_STRING_FIELD(mailbox);      /*!< Mailbox store to put MWI into */
 		);
-	enum ast_transport transport;    /*!< Transport to use */
+	enum sip_transport transport;    /*!< Transport to use */
 	int portno;                      /*!< Optional port override */
 	int resub;                       /*!< Sched ID of resubscription */
 	unsigned int subscribed:1;       /*!< Whether we are currently subscribed or not */
@@ -1577,7 +1606,7 @@ enum sip_publish_type {
 	SIP_PUBLISH_MODIFY,
 	/*!
 	 * \brief Remove
-	 *
+	 * 
 	 * \details
 	 * Used to remove published state from an ESC. This will contain
 	 * an Expires header set to 0 and likely no body.
@@ -1800,6 +1829,34 @@ struct sip_monitor_instance {
 	struct sip_epa_entry *suspension_entry;
 };
 
+/*!
+ * \brief uri parameters
+ *
+ */
+
+struct uriparams {
+	char *transport;
+	char *user;
+	char *method;
+	char *ttl;
+	char *maddr;
+	int lr;
+};
+
+struct contact {
+	AST_LIST_ENTRY(contact) list;
+	char *name;
+	char *user;
+	char *pass;
+	char *hostport;
+	struct uriparams params;
+	char *headers;
+	char *expires;
+	char *q;
+};
+
+AST_LIST_HEAD_NOLOCK(contactliststruct, contact);
+
 /*! \brief List of well-known SIP options. If we get this in a require,
    we should check the list and answer accordingly. */
 static const struct cfsip_options {
@@ -1867,7 +1924,7 @@ AST_THREADSTORAGE(check_auth_buf);
 struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport);
 void sip_auth_headers(enum sip_auth_type code, char **header, char **respheader);
 const char *sip_get_header(const struct sip_request *req, const char *name);
-const char *sip_get_transport(enum ast_transport t);
+const char *sip_get_transport(enum sip_transport t);
 
 #ifdef REF_DEBUG
 #define sip_ref_peer(arg1,arg2) _ref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
diff --git a/channels/sip/include/srtp.h b/channels/sip/include/srtp.h
new file mode 100644
index 0000000..9528192
--- /dev/null
+++ b/channels/sip/include/srtp.h
@@ -0,0 +1,59 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006 - 2007, Mikael Magnusson
+ *
+ * Mikael Magnusson <mikma at users.sourceforge.net>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file sip_srtp.h
+ *
+ * \brief SIP Secure RTP (SRTP)
+ *
+ * Specified in RFC 3711
+ *
+ * \author Mikael Magnusson <mikma at users.sourceforge.net>
+ */
+
+#ifndef _SIP_SRTP_H
+#define _SIP_SRTP_H
+
+#include "sdp_crypto.h"
+
+/* SRTP flags */
+#define SRTP_ENCR_OPTIONAL	(1 << 1)	/* SRTP encryption optional */
+#define SRTP_CRYPTO_ENABLE	(1 << 2)
+#define SRTP_CRYPTO_OFFER_OK	(1 << 3)
+#define SRTP_CRYPTO_TAG_32	(1 << 4)
+#define SRTP_CRYPTO_TAG_80	(1 << 5)
+
+/*! \brief structure for secure RTP audio */
+struct sip_srtp {
+	unsigned int flags;
+	struct sdp_crypto *crypto;
+};
+
+/*!
+ * \brief allocate a sip_srtp structure
+ * \retval a new malloc'd sip_srtp structure on success
+ * \retval NULL on failure
+*/
+struct sip_srtp *sip_srtp_alloc(void);
+
+/*!
+ * \brief free a sip_srtp structure
+ * \param srtp a sip_srtp structure
+*/
+void sip_srtp_destroy(struct sip_srtp *srtp);
+
+#endif	/* _SIP_SRTP_H */
diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c
index 39e43f2..42bb04d 100644
--- a/channels/sip/reqresp_parser.c
+++ b/channels/sip/reqresp_parser.c
@@ -20,12 +20,12 @@
  */
 
 /*** MODULEINFO
-	<support_level>extended</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426865 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "include/sip.h"
 #include "include/sip_utils.h"
@@ -45,7 +45,6 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
 	char *endparams = NULL;
 	char *c = NULL;
 	int error = 0;
-	int teluri_scheme = 0;
 
 	/*
 	 * Initialize requested strings - some functions don't care if parse_uri fails
@@ -80,7 +79,6 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
 		for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
 			l = strlen(cur);
 			if (!strncasecmp(uri, cur, l)) {
-				teluri_scheme = !strncasecmp(uri, "tel:", 4);	/* TEL URI */
 				uri += l;
 				break;
 			}
@@ -95,42 +93,6 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
 		/* if we don't want to split around hostport, keep everything as a
 		 * userinfo - cos thats how old parse_uri operated*/
 		userinfo = uri;
-	} else if (teluri_scheme) {
-		/*
-		 * tel: TEL URI INVITE RFC 3966 patch
-		 * See http://www.ietf.org/rfc/rfc3966.txt
-		 *
-		 * Once the full RFC 3966 parsing is implemented,
-		 * the ext= or isub= parameters would be extracted from userinfo.
-		 * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
-		 * Those parameters would be used for ISDN or PSTN local extensions.
-		 *
-		 * Current restrictions:
-		 * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
-		 */
-
-		if ((c = strstr(uri, ";phone-context="))) {
-			/*
-			 * Local number with context or domain.
-			 * ext= or isub= TEL URI parameters should be upfront.
-			 * All other parameters should come after the ";phone-context=" parameter.
-			 * If other parameters would occur before ";phone-context=" they will be ignored.
-			 */
-
-                        *c = '\0';
-                        userinfo = uri;
-                        uri = c + 15;
-			*hostport = uri;
-                } else if ('+' == uri[0]) {
-			/* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
-
-                        userinfo = uri;
-			*hostport = uri;
-		} else {
-			ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
-                        userinfo = uri;		/* Return local number anyway */
-			error = -1;
-		}
 	} else {
 		char *dom = "";
 		if ((c = strchr(uri, '@'))) {
@@ -413,51 +375,6 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
 		.params.user = ""
 	};
 
-	/* RFC 3966 TEL URI INVITE */
-	struct testdata td11 = {
-		.desc = "tel local number",
-		.uri = "tel:0987654321;phone-context=+32987654321",
-		.user = "0987654321",
-		.pass = "",
-		.hostport = "+32987654321",
-		.headers = "",
-		.residue = "",
-		.params.transport = "",
-		.params.lr = 0,
-		.params.user = ""
-	};
-
-	struct testdata td12 = {
-		.desc = "tel global number",
-		.uri = "tel:+32987654321",
-		.user = "+32987654321",
-		.pass = "",
-		.hostport = "+32987654321",
-		.headers = "",
-		.residue = "",
-		.params.transport = "",
-		.params.lr = 0,
-		.params.user = ""
-	};
-
-	/*
-	 * Once the full RFC 3966 parsing is implemented,
-	 * only the ext= or isub= parameters would be extracted from .user
-	 * Then the ;param=discard would be ignored,
-	 * and the .user would only contain "0987654321"
-	 */
-	struct testdata td13 = {
-		.desc = "tel local number",
-		.uri = "tel:0987654321;ext=1234;param=discard;phone-context=+32987654321;transport=udp;param2=discard2?header=blah&header2=blah2;param3=residue",
-		.user = "0987654321;ext=1234;param=discard",
-		.pass = "",
-		.hostport = "+32987654321",
-		.headers = "header=blah&header2=blah2",
-		.residue = "param3=residue",
-		.params.transport = "udp",
-		.params.lr = 0,
-		.params.user = ""
-	};
 
 	AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
 	AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
@@ -469,9 +386,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
 	AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
 	AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
 	AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
-	AST_LIST_INSERT_TAIL(&testdatalist, &td11, list);
-	AST_LIST_INSERT_TAIL(&testdatalist, &td12, list);
-	AST_LIST_INSERT_TAIL(&testdatalist, &td13, list);
+
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -492,7 +407,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
 		params.lr = 0;
 
 		ast_copy_string(uri,testdataptr->uri,sizeof(uri));
-		if (parse_uri_full(uri, "sip:,sips:,tel:", &user,
+		if (parse_uri_full(uri, "sip:,sips:", &user,
 				   &pass, &hostport,
 				   &params,
 				   &headers,
@@ -545,7 +460,6 @@ AST_TEST_DEFINE(sip_parse_uri_test)
 	char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
 	char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
 	char uri11[] = "host";
-	char uri12[] = "tel:911";	/* TEL URI Local number without context or global number */
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -674,17 +588,6 @@ AST_TEST_DEFINE(sip_parse_uri_test)
 		res = AST_TEST_FAIL;
 	}
 
-	/* Test 12, simple URI */
-	name = pass = hostport = transport = NULL;
-	if (!parse_uri(uri12, "sip:,sips:,tel:", &name, &pass, &hostport, &transport) ||
-			strcmp(name, "911")      ||	/* We return local number anyway */
-			!ast_strlen_zero(pass)      ||
-			!ast_strlen_zero(hostport)      ||	/* No global number nor context */
-			!ast_strlen_zero(transport)) {
-		ast_test_status_update(test, "Test 12: TEL URI INVITE failed.\n");
-		res = AST_TEST_FAIL;
-	}
-
 	return res;
 }
 
@@ -1677,9 +1580,9 @@ AST_TEST_DEFINE(parse_contact_header_test)
  * item is found that is not supported, it is copied to the unsupported
  * out buffer.
  *
- * \param options list
+ * \param option list
  * \param unsupported out buffer (optional)
- * \param unsupported_len out buffer length (optional)
+ * \param unsupported out buffer length (optional)
  */
 unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
 {
diff --git a/channels/sip/route.c b/channels/sip/route.c
deleted file mode 100644
index fea5ab3..0000000
--- a/channels/sip/route.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief sip_route functions
- */
-
-/*** MODULEINFO
-	<support_level>extended</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420562 $")
-
-#include "asterisk/utils.h"
-
-#include "include/route.h"
-#include "include/reqresp_parser.h"
-
-/*!
- * \brief Traverse route hops
- */
-#define sip_route_traverse(route,elem) AST_LIST_TRAVERSE(&(route)->list, elem, list)
-#define sip_route_first(route) AST_LIST_FIRST(&(route)->list)
-
-/*!
- * \brief Structure to save a route hop
- */
-struct sip_route_hop {
-	AST_LIST_ENTRY(sip_route_hop) list;
-	char uri[0];
-};
-
-const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead)
-{
-	struct sip_route_hop *hop;
-
-	if (!uri || len < 1 || uri[0] == '\0') {
-		return NULL;
-	}
-
-	/* Expand len to include null terminator */
-	len++;
-
-	/* ast_calloc is not needed because all fields are initialized in this block */
-	hop = ast_malloc(sizeof(struct sip_route_hop) + len);
-	if (!hop) {
-		return NULL;
-	}
-	ast_copy_string(hop->uri, uri, len);
-
-	if (inserthead) {
-		AST_LIST_INSERT_HEAD(&route->list, hop, list);
-		route->type = route_invalidated;
-	} else {
-		if (sip_route_empty(route)) {
-			route->type = route_invalidated;
-		}
-		AST_LIST_INSERT_TAIL(&route->list, hop, list);
-		hop->list.next = NULL;
-	}
-
-	return hop->uri;
-}
-
-void sip_route_process_header(struct sip_route *route, const char *header, int inserthead)
-{
-	const char *hop;
-	int len = 0;
-	const char *uri;
-
-	if (!route) {
-		ast_log(LOG_ERROR, "sip_route_process_header requires non-null route");
-		ast_do_crash();
-		return;
-	}
-
-	while (!get_in_brackets_const(header, &uri, &len)) {
-		header = strchr(header, ',');
-		if (header >= uri && header <= (uri + len)) {
-			/* comma inside brackets */
-			const char *next_br = strchr(header, '<');
-			if (next_br && next_br <= (uri + len)) {
-				header++;
-				continue;
-			}
-			continue;
-		}
-		if ((hop = sip_route_add(route, uri, len, inserthead))) {
-			ast_debug(2, "sip_route_process_header: <%s>\n", hop);
-		}
-		header = strchr(uri + len + 1, ',');
-		if (header == NULL) {
-			/* No more field-values, we're done with this header */
-			break;
-		}
-		/* Advance past comma */
-		header++;
-	}
-}
-
-void sip_route_copy(struct sip_route *dst, const struct sip_route *src)
-{
-	struct sip_route_hop *hop;
-
-	/* make sure dst is empty */
-	sip_route_clear(dst);
-
-	sip_route_traverse(src, hop) {
-		const char *uri = sip_route_add(dst, hop->uri, strlen(hop->uri), 0);
-		if (uri) {
-			ast_debug(2, "sip_route_copy: copied hop: <%s>\n", uri);
-		}
-	}
-
-	dst->type = src->type;
-}
-
-void sip_route_clear(struct sip_route *route)
-{
-	struct sip_route_hop *hop;
-
-	while ((hop = AST_LIST_REMOVE_HEAD(&route->list, list))) {
-		ast_free(hop);
-	}
-
-	route->type = route_loose;
-}
-
-void sip_route_dump(const struct sip_route *route)
-{
-	if (sip_route_empty(route)) {
-		ast_verbose("sip_route_dump: no route/path\n");
-	} else {
-		struct sip_route_hop *hop;
-		sip_route_traverse(route, hop) {
-			ast_verbose("sip_route_dump: route/path hop: <%s>\n", hop->uri);
-		}
-	}
-}
-
-struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
-{
-	struct sip_route_hop *hop;
-	const char *comma;
-	struct ast_str *buf;
-	int i = 0 - skip;
-
-	buf = ast_str_create(64);
-	if (!buf) {
-		return NULL;
-	}
-
-	comma = formatcli ? ", " : ",";
-
-	sip_route_traverse(route, hop) {
-		if (i >= 0) {
-			ast_str_append(&buf, 0, "%s<%s>", i ? comma : "", hop->uri);
-		}
-		i++;
-	}
-
-	if (formatcli && i <= 0) {
-		ast_str_append(&buf, 0, "N/A");
-	}
-
-	return buf;
-}
-
-int sip_route_is_strict(struct sip_route *route)
-{
-	if (!route) {
-		return 0;
-	}
-
-	if (route->type == route_invalidated) {
-		struct sip_route_hop *hop = sip_route_first(route);
-		int ret = hop && (strstr(hop->uri, ";lr") == NULL);
-		route->type = ret ? route_strict : route_loose;
-		return ret;
-	}
-
-	return (route->type == route_strict) ? 1 : 0;
-}
-
-const char *sip_route_first_uri(const struct sip_route *route)
-{
-	struct sip_route_hop *hop = sip_route_first(route);
-	return hop ? hop->uri : NULL;
-}
diff --git a/main/sdp_srtp.c b/channels/sip/sdp_crypto.c
similarity index 59%
rename from main/sdp_srtp.c
rename to channels/sip/sdp_crypto.c
index 8b3e0c5..db5bf99 100644
--- a/main/sdp_srtp.c
+++ b/channels/sip/sdp_crypto.c
@@ -16,11 +16,10 @@
  * at the top of the source tree.
  */
 
-/*! \file ast_sdp_crypto.c
+/*! \file sdp_crypto.c
  *
- * \brief SRTP and SDP Security descriptions
+ * \brief SDP Security descriptions
  *
- * Specified in RFC 3711
  * Specified in RFC 4568
  *
  * \author Mikael Magnusson <mikma at users.sourceforge.net>
@@ -32,11 +31,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424647 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include <math.h>
 #include "asterisk/options.h"
 #include "asterisk/utils.h"
-#include "asterisk/sdp_srtp.h"
+#include "include/sdp_crypto.h"
+#include "include/srtp.h"
 
 #define SRTP_MASTER_LEN 30
 #define SRTP_MASTERKEY_LEN 16
@@ -46,47 +47,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424647 $")
 extern struct ast_srtp_res *res_srtp;
 extern struct ast_srtp_policy_res *res_srtp_policy;
 
-struct ast_sdp_srtp *ast_sdp_srtp_alloc(void)
-{
-	if (!ast_rtp_engine_srtp_is_registered()) {
-	       ast_debug(1, "No SRTP module loaded, can't setup SRTP session.\n");
-	       return NULL;
-	}
-
-	return ast_calloc(1, sizeof(struct ast_sdp_srtp));
-}
-
-void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp)
-{
-	if (srtp->crypto) {
-		ast_sdp_crypto_destroy(srtp->crypto);
-	}
-	srtp->crypto = NULL;
-	ast_free(srtp);
-}
-
-struct ast_sdp_crypto {
+struct sdp_crypto {
 	char *a_crypto;
 	unsigned char local_key[SRTP_MASTER_LEN];
-	char *tag;
+	int tag;
 	char local_key64[SRTP_MASTER_LEN64];
 	unsigned char remote_key[SRTP_MASTER_LEN];
 };
 
 static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound);
 
-void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto)
+void sdp_crypto_destroy(struct sdp_crypto *crypto)
 {
 	ast_free(crypto->a_crypto);
 	crypto->a_crypto = NULL;
-	ast_free(crypto->tag);
-	crypto->tag = NULL;
 	ast_free(crypto);
 }
 
-struct ast_sdp_crypto *ast_sdp_crypto_alloc(void)
+struct sdp_crypto *sdp_crypto_setup(void)
 {
-	struct ast_sdp_crypto *p;
+	struct sdp_crypto *p;
 	int key_len;
 	unsigned char remote_key[SRTP_MASTER_LEN];
 
@@ -94,12 +74,14 @@ struct ast_sdp_crypto *ast_sdp_crypto_alloc(void)
 		return NULL;
 	}
 
-	if (!(p = ast_calloc(1, sizeof(*p)))) {
+	p = ast_calloc(1, sizeof(*p));
+	if (!p) {
 		return NULL;
 	}
+	p->tag = 1;
 
 	if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) {
-		ast_sdp_crypto_destroy(p);
+		sdp_crypto_destroy(p);
 		return NULL;
 	}
 
@@ -109,13 +91,13 @@ struct ast_sdp_crypto *ast_sdp_crypto_alloc(void)
 
 	if (key_len != SRTP_MASTER_LEN) {
 		ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN);
-		ast_free(p);
+		sdp_crypto_destroy(p);
 		return NULL;
 	}
 
 	if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) {
 		ast_log(LOG_ERROR, "base64 encode/decode bad key\n");
-		ast_free(p);
+		sdp_crypto_destroy(p);
 		return NULL;
 	}
 
@@ -147,7 +129,7 @@ static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, cons
 	return 0;
 }
 
-static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp)
+static int sdp_crypto_activate(struct sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp)
 {
 	struct ast_srtp_policy *local_policy = NULL;
 	struct ast_srtp_policy *remote_policy = NULL;
@@ -203,7 +185,7 @@ err:
 	return res;
 }
 
-int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr)
+int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp)
 {
 	char *str = NULL;
 	char *tag = NULL;
@@ -211,14 +193,15 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr
 	char *key_params = NULL;
 	char *key_param = NULL;
 	char *session_params = NULL;
-	char *key_salt = NULL;
-	char *lifetime = NULL;
+	char *key_salt = NULL;       /* The actual master key and key salt */
+	char *lifetime = NULL;       /* Key lifetime (# of RTP packets) */
+	char *mki = NULL;            /* Master Key Index */
 	int found = 0;
 	int key_len = 0;
 	int suite_val = 0;
 	unsigned char remote_key[SRTP_MASTER_LEN];
 	int taglen = 0;
-	struct ast_sdp_crypto *crypto = srtp->crypto;
+	double sdes_lifetime;
 
 	if (!ast_rtp_engine_srtp_is_registered()) {
 		return -1;
@@ -226,13 +209,20 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr
 
 	str = ast_strdupa(attr);
 
+	strsep(&str, ":");
 	tag = strsep(&str, " ");
 	suite = strsep(&str, " ");
 	key_params = strsep(&str, " ");
 	session_params = strsep(&str, " ");
 
 	if (!tag || !suite) {
-		ast_log(LOG_WARNING, "Unrecognized crypto attribute a=%s\n", attr);
+		ast_log(LOG_WARNING, "Unrecognized a=%s\n", attr);
+		return -1;
+	}
+
+	/* RFC4568 9.1 - tag is 1-9 digits, greater than zero */
+	if (sscanf(tag, "%30d", &p->tag) != 1 || p->tag <= 0 || p->tag > 999999999) {
+		ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag);
 		return -1;
 	}
 
@@ -243,11 +233,11 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr
 
 	if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
 		suite_val = AST_AES_CM_128_HMAC_SHA1_80;
-		ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80);
+		ast_set_flag(srtp, SRTP_CRYPTO_TAG_80);
 		taglen = 80;
 	} else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
 		suite_val = AST_AES_CM_128_HMAC_SHA1_32;
-		ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32);
+		ast_set_flag(srtp, SRTP_CRYPTO_TAG_32);
 		taglen = 32;
 	} else {
 		ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite);
@@ -255,133 +245,124 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr
 	}
 
 	while ((key_param = strsep(&key_params, ";"))) {
+		unsigned int n_lifetime;
 		char *method = NULL;
 		char *info = NULL;
 
 		method = strsep(&key_param, ":");
 		info = strsep(&key_param, ";");
+		sdes_lifetime = 0;
 
-		if (!strcmp(method, "inline")) {
-			key_salt = strsep(&info, "|");
-			lifetime = strsep(&info, "|");
+		if (strcmp(method, "inline")) {
+			continue;
+		}
 
-			if (lifetime) {
-				ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n", attr);
-				continue;
-			}
+		key_salt = strsep(&info, "|");
 
+		/* The next parameter can be either lifetime or MKI */
+		lifetime = strsep(&info, "|");
+		if (!lifetime) {
 			found = 1;
 			break;
 		}
+
+		mki = strchr(lifetime, ':');
+		if (mki) {
+			mki = lifetime;
+			lifetime = NULL;
+		} else {
+			mki = strsep(&info, "|");
+		}
+
+		if (mki && *mki != '1') {
+			ast_log(LOG_NOTICE, "Crypto MKI handling is not supported: ignoring attribute %s\n", attr);
+			continue;
+		}
+
+		if (lifetime) {
+			if (!strncmp(lifetime, "2^", 2)) {
+				char *lifetime_val = lifetime + 2;
+
+				/* Exponential lifetime */
+				if (sscanf(lifetime_val, "%30u", &n_lifetime) != 1) {
+					ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr);
+					continue;
+				}
+
+				if (n_lifetime > 48) {
+					/* Yeah... that's a bit big. */
+					ast_log(LOG_NOTICE, "Crypto lifetime exponent of '%u' is a bit large; using 48\n", n_lifetime);
+					n_lifetime = 48;
+				}
+				sdes_lifetime = pow(2, n_lifetime);
+			} else {
+				/* Decimal lifetime */
+				if (sscanf(lifetime, "%30u", &n_lifetime) != 1) {
+					ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr);
+					continue;
+				}
+				sdes_lifetime = n_lifetime;
+			}
+
+			/* Accept anything above 10 hours. Less than 10; reject. */
+			if (sdes_lifetime < 1800000) {
+				ast_log(LOG_NOTICE, "Rejecting crypto attribute '%s': lifetime '%f' too short\n", attr, sdes_lifetime);
+				continue;
+			}
+		}
+
+		ast_debug(2, "Crypto attribute '%s' accepted with lifetime '%f', MKI '%s'\n",
+			attr, sdes_lifetime, mki ? mki : "-");
+
+		found = 1;
+		break;
 	}
 
 	if (!found) {
-		ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n");
+		ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable: '%s'\n", attr);
 		return -1;
 	}
 
-	if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) {
-		ast_log(LOG_WARNING, "SRTP descriptions key %d != %d\n", key_len, SRTP_MASTER_LEN);
+	key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key));
+	if (key_len != SRTP_MASTER_LEN) {
+		ast_log(LOG_WARNING, "SRTP descriptions key length '%d' != master length '%d'\n",
+			key_len, SRTP_MASTER_LEN);
 		return -1;
 	}
 
-	if (!memcmp(crypto->remote_key, remote_key, sizeof(crypto->remote_key))) {
+	if (!memcmp(p->remote_key, remote_key, sizeof(p->remote_key))) {
 		ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n");
-		ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK);
 		return 0;
 	}
-	memcpy(crypto->remote_key, remote_key, sizeof(crypto->remote_key));
+	memcpy(p->remote_key, remote_key, sizeof(p->remote_key));
 
-	if (crypto_activate(crypto, suite_val, remote_key, rtp) < 0) {
+	if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) {
 		return -1;
 	}
 
-	if (!crypto->tag) {
-		ast_debug(1, "Accepting crypto tag %s\n", tag);
-		crypto->tag = ast_strdup(tag);
-		if (!crypto->tag) {
-			ast_log(LOG_ERROR, "Could not allocate memory for tag\n");
-			return -1;
-		}
-	}
-
 	/* Finally, rebuild the crypto line */
-	if (ast_sdp_crypto_build_offer(crypto, taglen)) {
-		return -1;
-	}
-
-	ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK);
-	return 0;
+	return sdp_crypto_offer(p, taglen);
 }
 
-int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen)
+int sdp_crypto_offer(struct sdp_crypto *p, int taglen)
 {
 	/* Rebuild the crypto line */
 	if (p->a_crypto) {
 		ast_free(p->a_crypto);
 	}
 
-	if (ast_asprintf(&p->a_crypto, "%s AES_CM_128_HMAC_SHA1_%i inline:%s",
-			 p->tag ? p->tag : "1", taglen, p->local_key64) == -1) {
+	if (ast_asprintf(&p->a_crypto, "a=crypto:%d AES_CM_128_HMAC_SHA1_%i inline:%s\r\n",
+			 p->tag, taglen, p->local_key64) == -1) {
 			ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n");
 		return -1;
 	}
 
-	ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto);
+	ast_debug(1, "Crypto line: %s\n", p->a_crypto);
 
 	return 0;
 }
 
-const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
-{
-	int taglen = default_taglen_32 ? 32 : 80;
-
-	if (!srtp) {
-		return NULL;
-	}
-
-	/* Set encryption properties */
-	if (!srtp->crypto) {
-		srtp->crypto = ast_sdp_crypto_alloc();
-	}
-
-	if (dtls_enabled) {
-		/* If DTLS-SRTP is enabled the key details will be pulled from TLS */
-		return NULL;
-	}
-
-	/* set the key length based on INVITE or settings */
-	if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_80)) {
-		taglen = 80;
-	} else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) {
-		taglen = 32;
-	}
-
-	if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) {
-		return srtp->crypto->a_crypto;
-	}
-
-	ast_log(LOG_WARNING, "No SRTP key management enabled\n");
-	return NULL;
-}
-
-char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf,
-	unsigned int force_avp)
+const char *sdp_crypto_attrib(struct sdp_crypto *p)
 {
-	struct ast_rtp_engine_dtls *dtls;
-
-	if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) {
-		if (force_avp) {
-			return using_avpf ? "RTP/SAVPF" : "RTP/SAVP";
-		} else {
-			return using_avpf ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
-		}
-	} else {
-		if (using_avpf) {
-			return sdes_active ? "RTP/SAVPF" : "RTP/AVPF";
-		} else {
-			return sdes_active ? "RTP/SAVP" : "RTP/AVP";
-		}
-	}
+	return p->a_crypto;
 }
-
diff --git a/channels/sip/security_events.c b/channels/sip/security_events.c
index 293475e..24ad8db 100644
--- a/channels/sip/security_events.c
+++ b/channels/sip/security_events.c
@@ -25,21 +25,34 @@
  */
 
 /*** MODULEINFO
-	<support_level>extended</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428246 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "include/sip.h"
 #include "include/security_events.h"
 
 /*! \brief Determine transport type used to receive request*/
 
-static enum ast_transport security_event_get_transport(const struct sip_pvt *p)
+static enum ast_security_event_transport_type security_event_get_transport(const struct sip_pvt *p)
 {
-	return p->socket.type;
+	int res = 0;
+
+	switch (p->socket.type) {
+	case SIP_TRANSPORT_UDP:
+		return AST_SECURITY_EVENT_TRANSPORT_UDP;
+	case SIP_TRANSPORT_TCP:
+	case SIP_TRANSPORT_WS:
+		return AST_SECURITY_EVENT_TRANSPORT_TCP;
+	case SIP_TRANSPORT_TLS:
+	case SIP_TRANSPORT_WSS:
+		return AST_SECURITY_EVENT_TRANSPORT_TLS;
+	}
+
+	return res;
 }
 
 void sip_report_invalid_peer(const struct sip_pvt *p)
@@ -270,7 +283,8 @@ void sip_report_inval_transport(const struct sip_pvt *p, const char *transport)
         ast_security_event_report(AST_SEC_EVT(&inval_transport));
 }
 
-int sip_report_security_event(const struct sip_pvt *p, const struct sip_request *req, const int res) {
+int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
+			      const struct sip_request *req, const int res) {
 
 	struct sip_peer *peer_report;
 	enum check_auth_result res_report = res;
@@ -288,7 +302,7 @@ int sip_report_security_event(const struct sip_pvt *p, const struct sip_request
 		[K_LAST]  = { NULL, NULL}
 	};
 
-	peer_report = sip_find_peer(p->exten, NULL, TRUE, FINDPEERS, FALSE, 0);
+	peer_report = sip_find_peer(peer, addr, TRUE, FINDPEERS, FALSE, p->socket.type);
 
 	switch(res_report) {
 	case AUTH_DONT_KNOW:
diff --git a/channels/sip/srtp.c b/channels/sip/srtp.c
new file mode 100644
index 0000000..049bffc
--- /dev/null
+++ b/channels/sip/srtp.c
@@ -0,0 +1,55 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006 - 2007, Mikael Magnusson
+ *
+ * Mikael Magnusson <mikma at users.sourceforge.net>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file sip_srtp.c
+ *
+ * \brief SIP Secure RTP (SRTP)
+ *
+ * Specified in RFC 3711
+ *
+ * \author Mikael Magnusson <mikma at users.sourceforge.net>
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "include/srtp.h"
+
+struct sip_srtp *sip_srtp_alloc(void)
+{
+	struct sip_srtp *srtp;
+
+	srtp = ast_calloc(1, sizeof(*srtp));
+
+	return srtp;
+}
+
+void sip_srtp_destroy(struct sip_srtp *srtp)
+{
+	if (srtp->crypto) {
+		sdp_crypto_destroy(srtp->crypto);
+	}
+	srtp->crypto = NULL;
+	ast_free(srtp);
+}
diff --git a/channels/sip/utils.c b/channels/sip/utils.c
index 45a4128..4459ff1 100644
--- a/channels/sip/utils.c
+++ b/channels/sip/utils.c
@@ -22,7 +22,7 @@
  */
 
 /*** MODULEINFO
-	<support_level>extended</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
diff --git a/channels/vcodecs.c b/channels/vcodecs.c
index 5f9cb1a..76aeb67 100644
--- a/channels/vcodecs.c
+++ b/channels/vcodecs.c
@@ -16,7 +16,7 @@
 
 /*
  * Video codecs support for console_video.c
- * $Revision: 369013 $
+ * $Revision$
  */
 
 /*** MODULEINFO
@@ -209,9 +209,9 @@ void dump_buf(struct fbuf_t *b)
 			if (i != 0)
 				ast_log(LOG_WARNING, "%s\n", buf);
 			memset(buf, '\0', sizeof(buf));
-			sprintf(buf, "%04x: ", i);
+			sprintf(buf, "%04x: ", (unsigned)i);
 		}
-		sprintf(buf + 6 + x*3, "%02x ", b->data[i]);
+		sprintf(buf + 6 + x*3, "%02hhx ", b->data[i]);
 		if (i > 31 && i < last2lines)
 			i = last2lines - 1;
 	}
@@ -1056,7 +1056,7 @@ static int h264_decap(struct fbuf_t *b, uint8_t *data, int len)
 	}
 	/* first of all, check if the packet has F == 0 */
 	if (data[0] & 0x80) {
-		ast_log(LOG_WARNING, "--- forbidden packet; nal: %02x\n",
+		ast_log(LOG_WARNING, "--- forbidden packet; nal: %02hhx\n",
 			data[0]);
 		return 1;
 	}
diff --git a/channels/vgrabbers.c b/channels/vgrabbers.c
index 7374acc..45dced4 100644
--- a/channels/vgrabbers.c
+++ b/channels/vgrabbers.c
@@ -17,7 +17,7 @@
 /*
  * Video grabbers used in console_video.
  *
- * $Revision: 369013 $
+ * $Revision$
  *
  * Each grabber is implemented through open/read/close calls,
  * plus an additional move() function used e.g. to change origin
@@ -49,7 +49,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <sys/ioctl.h>
 #include "asterisk/file.h"
 #include "asterisk/utils.h"	/* ast_calloc */
diff --git a/codecs/Makefile b/codecs/Makefile
index 32230ae..f3f2605 100644
--- a/codecs/Makefile
+++ b/codecs/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for codec modules
 #
diff --git a/codecs/codec_a_mu.c b/codecs/codec_a_mu.c
index 2382f97..470f363 100644
--- a/codecs/codec_a_mu.c
+++ b/codecs/codec_a_mu.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
@@ -80,17 +80,6 @@ static int ulawtoalaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 
 static struct ast_translator alawtoulaw = {
 	.name = "alawtoulaw",
-	.src_codec = {
-		.name = "alaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "ulaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "ulaw",
 	.framein = alawtoulaw_framein,
 	.sample = alaw_sample,
 	.buffer_samples = BUFFER_SAMPLES,
@@ -99,17 +88,6 @@ static struct ast_translator alawtoulaw = {
 
 static struct ast_translator ulawtoalaw = {
 	.name = "ulawtoalaw",
-	.src_codec = {
-		.name = "ulaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "alaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "alaw",
 	.framein = ulawtoalaw_framein,
 	.sample = ulaw_sample,
 	.buffer_samples = BUFFER_SAMPLES,
@@ -133,19 +111,23 @@ static int load_module(void)
 	int res;
 	int x;
 
+	ast_format_set(&alawtoulaw.src_format, AST_FORMAT_ALAW, 0);
+	ast_format_set(&alawtoulaw.dst_format, AST_FORMAT_ULAW, 0);
+
+	ast_format_set(&ulawtoalaw.src_format, AST_FORMAT_ULAW, 0);
+	ast_format_set(&ulawtoalaw.dst_format, AST_FORMAT_ALAW, 0);
+
 	for (x=0;x<256;x++) {
 		mu2a[x] = AST_LIN2A(AST_MULAW(x));
 		a2mu[x] = AST_LIN2MU(AST_ALAW(x));
 	}
-
 	res = ast_register_translator(&alawtoulaw);
-	res |= ast_register_translator(&ulawtoalaw);
-
-	if (res) {
-		unload_module();
+	if (!res)
+		res = ast_register_translator(&ulawtoalaw);
+	else
+		ast_unregister_translator(&alawtoulaw);
+	if (res)
 		return AST_MODULE_LOAD_FAILURE;
-	}
-
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/codecs/codec_adpcm.c b/codecs/codec_adpcm.c
index ec80cac..96e19f0 100644
--- a/codecs/codec_adpcm.c
+++ b/codecs/codec_adpcm.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
@@ -154,7 +154,7 @@ static inline short decode(int encoded, struct adpcm_state *state)
 /*
  * Adpcm
  *  Takes a signed linear signal and encodes it as ADPCM
- *  For more information see http://en.wikipedia.org/wiki/Dialogic_ADPCM
+ *  For more information see http://support.dialogic.com/appnotes/adpcm.pdf
  *
  * Results:
  *  Foo.
@@ -290,17 +290,6 @@ static struct ast_frame *lintoadpcm_frameout(struct ast_trans_pvt *pvt)
 
 static struct ast_translator adpcmtolin = {
 	.name = "adpcmtolin",
-	.src_codec = {
-		.name = "adpcm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.framein = adpcmtolin_framein,
 	.sample = adpcm_sample,
 	.desc_size = sizeof(struct adpcm_decoder_pvt),
@@ -310,17 +299,6 @@ static struct ast_translator adpcmtolin = {
 
 static struct ast_translator lintoadpcm = {
 	.name = "lintoadpcm",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "adpcm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "adpcm",
 	.framein = lintoadpcm_framein,
 	.frameout = lintoadpcm_frameout,
 	.sample = slin8_sample,
@@ -329,6 +307,12 @@ static struct ast_translator lintoadpcm = {
 	.buf_size = BUFFER_SAMPLES/ 2,	/* 2 samples per byte */
 };
 
+/*! \brief standard module glue */
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res;
@@ -341,21 +325,26 @@ static int unload_module(void)
 
 static int load_module(void)
 {
-	int res = 0;
+	int res;
 
-	res = ast_register_translator(&adpcmtolin);
-	res |= ast_register_translator(&lintoadpcm);
+	ast_format_set(&adpcmtolin.src_format, AST_FORMAT_ADPCM, 0);
+	ast_format_set(&adpcmtolin.dst_format, AST_FORMAT_SLINEAR, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	ast_format_set(&lintoadpcm.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoadpcm.dst_format, AST_FORMAT_ADPCM, 0);
 
+	res = ast_register_translator(&adpcmtolin);
+	if (!res)
+		res = ast_register_translator(&lintoadpcm);
+	else
+		ast_unregister_translator(&adpcmtolin);
+	if (res)
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive Differential PCM Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_alaw.c b/codecs/codec_alaw.c
index e53d3f0..34a7138 100644
--- a/codecs/codec_alaw.c
+++ b/codecs/codec_alaw.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/config.h"
@@ -77,17 +77,6 @@ static int lintoalaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 
 static struct ast_translator alawtolin = {
 	.name = "alawtolin",
-	.src_codec = {
-		.name = "alaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.framein = alawtolin_framein,
 	.sample = alaw_sample,
 	.buffer_samples = BUFFER_SAMPLES,
@@ -95,24 +84,20 @@ static struct ast_translator alawtolin = {
 };
 
 static struct ast_translator lintoalaw = {
-	.name = "lintoalaw",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "alaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "alaw",
+	"lintoalaw",
 	.framein = lintoalaw_framein,
 	.sample = slin8_sample,
 	.buffer_samples = BUFFER_SAMPLES,
 	.buf_size = BUFFER_SAMPLES,
 };
 
+/*! \brief standard module stuff */
+
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res;
@@ -127,19 +112,24 @@ static int load_module(void)
 {
 	int res;
 
-	res = ast_register_translator(&alawtolin);
-	res |= ast_register_translator(&lintoalaw);
+	ast_format_set(&lintoalaw.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoalaw.dst_format, AST_FORMAT_ALAW, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	ast_format_set(&alawtolin.src_format, AST_FORMAT_ALAW, 0);
+	ast_format_set(&alawtolin.dst_format, AST_FORMAT_SLINEAR, 0);
 
+	res = ast_register_translator(&alawtolin);
+	if (!res)
+		res = ast_register_translator(&lintoalaw);
+	else
+		ast_unregister_translator(&alawtolin);
+	if (res)
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "A-law Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c
index 0ba3737..caaf99c 100644
--- a/codecs/codec_dahdi.c
+++ b/codecs/codec_dahdi.c
@@ -32,9 +32,8 @@
  ***/
 
 #include "asterisk.h"
-#include <stdbool.h>
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426097 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <fcntl.h>
 #include <netinet/in.h>
@@ -52,7 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426097 $")
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/ulaw.h"
-#include "asterisk/format_compatibility.h"
 
 #define BUFFER_SIZE 8000
 
@@ -60,29 +58,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426097 $")
 #define G729_SAMPLES 160
 #define ULAW_SAMPLES 160
 
-/* Defines from DAHDI. */
 #ifndef DAHDI_FORMAT_MAX_AUDIO
-/*! G.723.1 compression */
 #define DAHDI_FORMAT_G723_1    (1 << 0)
-/*! GSM compression */
 #define DAHDI_FORMAT_GSM       (1 << 1)
-/*! Raw mu-law data (G.711) */
 #define DAHDI_FORMAT_ULAW      (1 << 2)
-/*! Raw A-law data (G.711) */
 #define DAHDI_FORMAT_ALAW      (1 << 3)
-/*! ADPCM (G.726, 32kbps) */
 #define DAHDI_FORMAT_G726      (1 << 4)
-/*! ADPCM (IMA) */
 #define DAHDI_FORMAT_ADPCM     (1 << 5)
-/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
 #define DAHDI_FORMAT_SLINEAR   (1 << 6)
-/*! LPC10, 180 samples/frame */
 #define DAHDI_FORMAT_LPC10     (1 << 7)
-/*! G.729A audio */
 #define DAHDI_FORMAT_G729A     (1 << 8)
-/*! SpeeX Free Compression */
 #define DAHDI_FORMAT_SPEEX     (1 << 9)
-/*! iLBC Free Compression */
 #define DAHDI_FORMAT_ILBC      (1 << 10)
 #endif
 
@@ -92,194 +78,23 @@ static struct channel_usage {
 	int decoders;
 } channels;
 
-#if defined(NOT_NEEDED)
-/*!
- * \internal
- * \brief Convert DAHDI format bitfield to old Asterisk format bitfield.
- * \since 13.0.0
- *
- * \param dahdi Bitfield from DAHDI to convert.
- *
- * \note They should be the same values but they don't have to be.
- *
- * \return Old Asterisk bitfield equivalent.
- */
-static uint64_t bitfield_dahdi2ast(unsigned dahdi)
-{
-	uint64_t ast;
-
-	switch (dahdi) {
-	case DAHDI_FORMAT_G723_1:
-		ast = AST_FORMAT_G723;
-		break;
-	case DAHDI_FORMAT_GSM:
-		ast = AST_FORMAT_GSM;
-		break;
-	case DAHDI_FORMAT_ULAW:
-		ast = AST_FORMAT_ULAW;
-		break;
-	case DAHDI_FORMAT_ALAW:
-		ast = AST_FORMAT_ALAW;
-		break;
-	case DAHDI_FORMAT_G726:
-		ast = AST_FORMAT_G726_AAL2;
-		break;
-	case DAHDI_FORMAT_ADPCM:
-		ast = AST_FORMAT_ADPCM;
-		break;
-	case DAHDI_FORMAT_SLINEAR:
-		ast = AST_FORMAT_SLIN;
-		break;
-	case DAHDI_FORMAT_LPC10:
-		ast = AST_FORMAT_LPC10;
-		break;
-	case DAHDI_FORMAT_G729A:
-		ast = AST_FORMAT_G729;
-		break;
-	case DAHDI_FORMAT_SPEEX:
-		ast = AST_FORMAT_SPEEX;
-		break;
-	case DAHDI_FORMAT_ILBC:
-		ast = AST_FORMAT_ILBC;
-		break;
-	default:
-		ast = 0;
-		break;
-	}
-
-	return ast;
-}
-#endif	/* defined(NOT_NEEDED) */
-
-/*!
- * \internal
- * \brief Get the ast_codec by DAHDI format.
- * \since 13.0.0
- *
- * \param dahdi_fmt DAHDI specific codec identifier.
- *
- * \return Specified codec if exists otherwise NULL.
- */
-static const struct ast_codec *get_dahdi_codec(uint32_t dahdi_fmt)
-{
-	const struct ast_codec *codec;
-
-	static const struct ast_codec dahdi_g723_1 = {
-		.name = "g723",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_gsm = {
-		.name = "gsm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_ulaw = {
-		.name = "ulaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_alaw = {
-		.name = "alaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_g726 = {
-		.name = "g726",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_adpcm = {
-		.name = "adpcm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_slinear = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_lpc10 = {
-		.name = "lpc10",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_g729a = {
-		.name = "g729",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_speex = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-	static const struct ast_codec dahdi_ilbc = {
-		.name = "ilbc",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	};
-
-	switch (dahdi_fmt) {
-	case DAHDI_FORMAT_G723_1:
-		codec = &dahdi_g723_1;
-		break;
-	case DAHDI_FORMAT_GSM:
-		codec = &dahdi_gsm;
-		break;
-	case DAHDI_FORMAT_ULAW:
-		codec = &dahdi_ulaw;
-		break;
-	case DAHDI_FORMAT_ALAW:
-		codec = &dahdi_alaw;
-		break;
-	case DAHDI_FORMAT_G726:
-		codec = &dahdi_g726;
-		break;
-	case DAHDI_FORMAT_ADPCM:
-		codec = &dahdi_adpcm;
-		break;
-	case DAHDI_FORMAT_SLINEAR:
-		codec = &dahdi_slinear;
-		break;
-	case DAHDI_FORMAT_LPC10:
-		codec = &dahdi_lpc10;
-		break;
-	case DAHDI_FORMAT_G729A:
-		codec = &dahdi_g729a;
-		break;
-	case DAHDI_FORMAT_SPEEX:
-		codec = &dahdi_speex;
-		break;
-	case DAHDI_FORMAT_ILBC:
-		codec = &dahdi_ilbc;
-		break;
-	default:
-		codec = NULL;
-		break;
-	}
-
-	return codec;
-}
-
 static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 
 static struct ast_cli_entry cli[] = {
 	AST_CLI_DEFINE(handle_cli_transcoder_show, "Display DAHDI transcoder utilization.")
 };
 
+struct format_map {
+	unsigned int map[32][32];
+};
+
+static struct format_map global_format_map = { { { 0 } } };
+
 struct translator {
 	struct ast_translator t;
-	uint32_t src_dahdi_fmt;
-	uint32_t dst_dahdi_fmt;
 	AST_LIST_ENTRY(translator) entry;
 };
 
-#ifndef container_of
-#define container_of(ptr, type, member) \
-	((type *)((char *)(ptr) - offsetof(type, member)))
-#endif
-
 static AST_LIST_HEAD_STATIC(translators, translator);
 
 struct codec_dahdi_pvt {
@@ -375,7 +190,7 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
 	struct codec_dahdi_pvt *dahdip = pvt->pvt;
 
-	if (!f->subclass.format) {
+	if (!f->subclass.format.id) {
 		/* We're just faking a return for calculation purposes. */
 		dahdip->fake = 2;
 		pvt->samples = f->samples;
@@ -430,16 +245,18 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
 	int res;
 
 	if (2 == dahdip->fake) {
-		struct ast_frame frm = {
-			.frametype = AST_FRAME_VOICE,
-			.samples = dahdip->required_samples,
-			.src = pvt->t->name,
-		};
-
 		dahdip->fake = 1;
+		pvt->f.frametype = AST_FRAME_VOICE;
+		ast_format_clear(&pvt->f.subclass.format);
+		pvt->f.samples = dahdip->required_samples;
+		pvt->f.data.ptr = NULL;
+		pvt->f.offset = 0;
+		pvt->f.datalen = 0;
+		pvt->f.mallocd = 0;
 		pvt->samples = 0;
 
-		return ast_frisolate(&frm);
+		return ast_frisolate(&pvt->f);
+
 	} else if (1 == dahdip->fake) {
 		dahdip->fake = 0;
 		return NULL;
@@ -460,7 +277,13 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
 		}
 	} else {
 		pvt->f.datalen = res;
-		pvt->f.samples = ast_codec_samples_count(&pvt->f);
+		pvt->f.frametype = AST_FRAME_VOICE;
+		ast_format_copy(&pvt->f.subclass.format, &pvt->t->dst_format);
+		pvt->f.mallocd = 0;
+		pvt->f.offset = AST_FRIENDLY_OFFSET;
+		pvt->f.src = pvt->t->name;
+		pvt->f.data.ptr = pvt->outbuf.c;
+		pvt->f.samples = ast_codec_get_samples(&pvt->f);
 
 		dahdip->samples_written_to_hardware =
 		  (dahdip->samples_written_to_hardware >= pvt->f.samples) ?
@@ -479,7 +302,7 @@ static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
 	struct codec_dahdi_pvt *dahdip = pvt->pvt;
 
-	if (!f->subclass.format) {
+	if (!f->subclass.format.id) {
 		/* We're just faking a return for calculation purposes. */
 		dahdip->fake = 2;
 		pvt->samples = f->samples;
@@ -504,16 +327,16 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
 	struct codec_dahdi_pvt *dahdip = pvt->pvt;
 
 	if (2 == dahdip->fake) {
-		struct ast_frame frm = {
-			.frametype = AST_FRAME_VOICE,
-			.samples = dahdip->required_samples,
-			.src = pvt->t->name,
-		};
-
 		dahdip->fake = 1;
+		pvt->f.frametype = AST_FRAME_VOICE;
+		ast_format_clear(&pvt->f.subclass.format);
+		pvt->f.samples = dahdip->required_samples;
+		pvt->f.data.ptr = NULL;
+		pvt->f.offset = 0;
+		pvt->f.datalen = 0;
+		pvt->f.mallocd = 0;
 		pvt->samples = 0;
-
-		return ast_frisolate(&frm);
+		return ast_frisolate(&pvt->f);
 	} else if (1 == dahdip->fake) {
 		pvt->samples = 0;
 		dahdip->fake = 0;
@@ -547,6 +370,12 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
 			pvt->f.datalen = res;
 		}
 		pvt->datalen = 0;
+		pvt->f.frametype = AST_FRAME_VOICE;
+		ast_format_copy(&pvt->f.subclass.format, &pvt->t->dst_format);
+		pvt->f.mallocd = 0;
+		pvt->f.offset = AST_FRIENDLY_OFFSET;
+		pvt->f.src = pvt->t->name;
+		pvt->f.data.ptr = pvt->outbuf.c;
 		pvt->f.samples = res;
 		pvt->samples = 0;
 		dahdip->samples_written_to_hardware =
@@ -565,9 +394,9 @@ static void dahdi_destroy(struct ast_trans_pvt *pvt)
 {
 	struct codec_dahdi_pvt *dahdip = pvt->pvt;
 
-	switch (dahdip->fmts.dstfmt) {
-	case DAHDI_FORMAT_G729A:
-	case DAHDI_FORMAT_G723_1:
+	switch (ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) {
+	case AST_FORMAT_G729A:
+	case AST_FORMAT_G723_1:
 		ast_atomic_fetchadd_int(&channels.encoders, -1);
 		break;
 	default:
@@ -578,39 +407,7 @@ static void dahdi_destroy(struct ast_trans_pvt *pvt)
 	close(dahdip->fd);
 }
 
-static struct ast_format *dahdi_format_to_cached(int format)
-{
-	switch (format) {
-	case DAHDI_FORMAT_G723_1:
-		return ast_format_g723;
-	case DAHDI_FORMAT_GSM:
-		return ast_format_gsm;
-	case DAHDI_FORMAT_ULAW:
-		return ast_format_ulaw;
-	case DAHDI_FORMAT_ALAW:
-		return ast_format_alaw;
-	case DAHDI_FORMAT_G726:
-		return ast_format_g726;
-	case DAHDI_FORMAT_ADPCM:
-		return ast_format_adpcm;
-	case DAHDI_FORMAT_SLINEAR:
-		return ast_format_slin;
-	case DAHDI_FORMAT_LPC10:
-		return ast_format_lpc10;
-	case DAHDI_FORMAT_G729A:
-		return ast_format_g729;
-	case DAHDI_FORMAT_SPEEX:
-		return ast_format_speex;
-	case DAHDI_FORMAT_ILBC:
-		return ast_format_ilbc;
-	}
-
-	/* This will never be reached */
-	ast_assert(0);
-	return NULL;
-}
-
-static int dahdi_translate(struct ast_trans_pvt *pvt, uint32_t dst_dahdi_fmt, uint32_t src_dahdi_fmt)
+static int dahdi_translate(struct ast_trans_pvt *pvt, struct ast_format *dst_format, struct ast_format *src_format)
 {
 	/* Request translation through zap if possible */
 	int fd;
@@ -624,13 +421,10 @@ static int dahdi_translate(struct ast_trans_pvt *pvt, uint32_t dst_dahdi_fmt, ui
 		return -1;
 	}
 
-	dahdip->fmts.srcfmt = src_dahdi_fmt;
-	dahdip->fmts.dstfmt = dst_dahdi_fmt;
+	dahdip->fmts.srcfmt = ast_format_to_old_bitfield(src_format);
+	dahdip->fmts.dstfmt = ast_format_to_old_bitfield(dst_format);
 
-	ast_assert(pvt->f.subclass.format == NULL);
-	pvt->f.subclass.format = ao2_bump(dahdi_format_to_cached(dahdip->fmts.dstfmt));
-
-	ast_debug(1, "Opening transcoder channel from %s to %s.\n", pvt->t->src_codec.name, pvt->t->dst_codec.name);
+	ast_debug(1, "Opening transcoder channel from %s to %s.\n", ast_getformatname(src_format), ast_getformatname(dst_format));
 
 retry:
 	if (ioctl(fd, DAHDI_TC_ALLOCATE, &dahdip->fmts)) {
@@ -643,14 +437,14 @@ retry:
 			 * support for ULAW instead of signed linear and then
 			 * we'll just convert from ulaw to signed linear in
 			 * software. */
-			if (dahdip->fmts.srcfmt == DAHDI_FORMAT_SLINEAR) {
+			if (AST_FORMAT_SLINEAR == ast_format_id_from_old_bitfield(dahdip->fmts.srcfmt)) {
 				ast_debug(1, "Using soft_slin support on source\n");
 				dahdip->softslin = 1;
-				dahdip->fmts.srcfmt = DAHDI_FORMAT_ULAW;
-			} else if (dahdip->fmts.dstfmt == DAHDI_FORMAT_SLINEAR) {
+				dahdip->fmts.srcfmt = ast_format_id_to_old_bitfield(AST_FORMAT_ULAW);
+			} else if (AST_FORMAT_SLINEAR == ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) {
 				ast_debug(1, "Using soft_slin support on destination\n");
 				dahdip->softslin = 1;
-				dahdip->fmts.dstfmt = DAHDI_FORMAT_ULAW;
+				dahdip->fmts.dstfmt = ast_format_id_to_old_bitfield(AST_FORMAT_ULAW);
 			}
 			tried_once = 1;
 			goto retry;
@@ -669,13 +463,13 @@ retry:
 
 	dahdip->fd = fd;
 
-	dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt) & (DAHDI_FORMAT_G723_1)) ? G723_SAMPLES : G729_SAMPLES;
+	dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt) & (ast_format_id_to_old_bitfield(AST_FORMAT_G723_1))) ? G723_SAMPLES : G729_SAMPLES;
 
-	switch (dahdip->fmts.dstfmt) {
-	case DAHDI_FORMAT_G729A:
+	switch (ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) {
+	case AST_FORMAT_G729A:
 		ast_atomic_fetchadd_int(&channels.encoders, +1);
 		break;
-	case DAHDI_FORMAT_G723_1:
+	case AST_FORMAT_G723_1:
 		ast_atomic_fetchadd_int(&channels.encoders, +1);
 		break;
 	default:
@@ -688,9 +482,9 @@ retry:
 
 static int dahdi_new(struct ast_trans_pvt *pvt)
 {
-	struct translator *zt = container_of(pvt->t, struct translator, t);
-
-	return dahdi_translate(pvt, zt->dst_dahdi_fmt, zt->src_dahdi_fmt);
+	return dahdi_translate(pvt,
+		&pvt->t->dst_format,
+		&pvt->t->src_format);
 }
 
 static struct ast_frame *fakesrc_sample(void)
@@ -705,39 +499,37 @@ static struct ast_frame *fakesrc_sample(void)
 	return &f;
 }
 
-static bool is_encoder(uint32_t src_dahdi_fmt)
+static int is_encoder(struct translator *zt)
 {
-	return ((src_dahdi_fmt & (DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW | DAHDI_FORMAT_SLINEAR)) > 0);
+	if ((zt->t.src_format.id == AST_FORMAT_ULAW) ||
+		(zt->t.src_format.id == AST_FORMAT_ALAW) ||
+		(zt->t.src_format.id == AST_FORMAT_SLINEAR)) {
+		return 1;
+	} else {
+		return 0;
+	}
 }
 
-/* Must be called with the translators list locked. */
-static int register_translator(uint32_t dst_dahdi_fmt, uint32_t src_dahdi_fmt)
+static int register_translator(int dst, int src)
 {
-	const struct ast_codec *dst_codec;
-	const struct ast_codec *src_codec;
 	struct translator *zt;
 	int res;
+	struct ast_format dst_format;
+	struct ast_format src_format;
 
-	dst_codec = get_dahdi_codec(dst_dahdi_fmt);
-	src_codec = get_dahdi_codec(src_dahdi_fmt);
-	if (!dst_codec || !src_codec) {
-		return -1;
-	}
+	ast_format_from_old_bitfield(&dst_format, (1 << dst));
+	ast_format_from_old_bitfield(&src_format, (1 << src));
 
 	if (!(zt = ast_calloc(1, sizeof(*zt)))) {
 		return -1;
 	}
 
-	zt->src_dahdi_fmt = src_dahdi_fmt;
-	zt->dst_dahdi_fmt = dst_dahdi_fmt;
-
-	snprintf(zt->t.name, sizeof(zt->t.name), "dahdi_%s_to_%s",
-		src_codec->name, dst_codec->name);
-
-	memcpy(&zt->t.src_codec, src_codec, sizeof(*src_codec));
-	memcpy(&zt->t.dst_codec, dst_codec, sizeof(*dst_codec));
+	snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
+		 ast_getformatname(&src_format), ast_getformatname(&dst_format));
+	ast_format_copy(&zt->t.src_format, &src_format);
+	ast_format_copy(&zt->t.dst_format, &dst_format);
 	zt->t.buf_size = BUFFER_SIZE;
-	if (is_encoder(src_dahdi_fmt)) {
+	if (is_encoder(zt)) {
 		zt->t.framein = dahdi_encoder_framein;
 		zt->t.frameout = dahdi_encoder_frameout;
 	} else {
@@ -756,65 +548,76 @@ static int register_translator(uint32_t dst_dahdi_fmt, uint32_t src_dahdi_fmt)
 		return -1;
 	}
 
+	AST_LIST_LOCK(&translators);
 	AST_LIST_INSERT_HEAD(&translators, zt, entry);
+	AST_LIST_UNLOCK(&translators);
+
+	global_format_map.map[dst][src] = 1;
 
 	return res;
 }
 
-static void unregister_translators(void)
+static void drop_translator(int dst, int src)
 {
 	struct translator *cur;
 
 	AST_LIST_LOCK(&translators);
-	while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
+		if (cur->t.src_format.id != ast_format_id_from_old_bitfield((1 << src)))
+			continue;
+
+		if (cur->t.dst_format.id != ast_format_id_from_old_bitfield((1 << dst)))
+			continue;
+
+		AST_LIST_REMOVE_CURRENT(entry);
 		ast_unregister_translator(&cur->t);
 		ast_free(cur);
+		global_format_map.map[dst][src] = 0;
+		break;
 	}
+	AST_LIST_TRAVERSE_SAFE_END;
 	AST_LIST_UNLOCK(&translators);
 }
 
-/* Must be called with the translators list locked. */
-static bool is_already_registered(uint32_t dstfmt, uint32_t srcfmt)
+static void unregister_translators(void)
 {
-	bool res = false;
-	const struct translator *zt;
+	struct translator *cur;
 
-	AST_LIST_TRAVERSE(&translators, zt, entry) {
-		if ((zt->src_dahdi_fmt == srcfmt) && (zt->dst_dahdi_fmt == dstfmt)) {
-			res = true;
-			break;
-		}
+	AST_LIST_LOCK(&translators);
+	while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
+		ast_unregister_translator(&cur->t);
+		ast_free(cur);
 	}
-
-	return res;
+	AST_LIST_UNLOCK(&translators);
 }
 
-static void build_translators(uint32_t dstfmts, uint32_t srcfmts)
+static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
 {
-	uint32_t srcfmt;
-	uint32_t dstfmt;
+	unsigned int src, dst;
 
-	AST_LIST_LOCK(&translators);
+	for (src = 0; src < 32; src++) {
+		for (dst = 0; dst < 32; dst++) {
+			if (!(srcfmts & (1 << src)))
+				continue;
 
-	for (srcfmt = 1; srcfmt != 0; srcfmt <<= 1) {
-		for (dstfmt = 1; dstfmt != 0; dstfmt <<= 1) {
-			if (!(dstfmts & dstfmt) || !(srcfmts & srcfmt)) {
+			if (!(dstfmts & (1 << dst)))
 				continue;
-			}
-			if (is_already_registered(dstfmt, srcfmt)) {
+
+			if (global_format_map.map[dst][src])
 				continue;
-			}
-			register_translator(dstfmt, srcfmt);
+
+			if (!register_translator(dst, src))
+				map->map[dst][src] = 1;
 		}
 	}
-
-	AST_LIST_UNLOCK(&translators);
 }
 
 static int find_transcoders(void)
 {
 	struct dahdi_transcoder_info info = { 0, };
+	struct format_map map = { { { 0 } } };
 	int fd;
+	unsigned int x, y;
 
 	if ((fd = open("/dev/dahdi/transcode", O_RDWR)) < 0) {
 		ast_log(LOG_ERROR, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno));
@@ -839,8 +642,9 @@ static int find_transcoders(void)
 			info.srcfmts &= ~(DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW);
 		}
 
-		build_translators(info.dstfmts, info.srcfmts);
+		build_translators(&map, info.dstfmts, info.srcfmts);
 		ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
+
 	}
 
 	close(fd);
@@ -849,6 +653,13 @@ static int find_transcoders(void)
 		ast_verb(2, "No hardware transcoders found.\n");
 	}
 
+	for (x = 0; x < 32; x++) {
+		for (y = 0; y < 32; y++) {
+			if (!map.map[x][y] && global_format_map.map[x][y])
+				drop_translator(x, y);
+		}
+	}
+
 	return 0;
 }
 
@@ -867,13 +678,13 @@ static int unload_module(void)
 
 static int load_module(void)
 {
+	ast_ulaw_init();
 	find_transcoders();
 	ast_cli_register_multiple(cli, ARRAY_LEN(cli));
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/codecs/codec_g722.c b/codecs/codec_g722.c
index f423034..89641f1 100644
--- a/codecs/codec_g722.c
+++ b/codecs/codec_g722.c
@@ -39,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/linkedlists.h"
 #include "asterisk/module.h"
@@ -138,17 +138,6 @@ static int lintog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 
 static struct ast_translator g722tolin = {
 	.name = "g722tolin",
-	.src_codec = {
-		.name = "g722",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.newpvt = g722tolin_new,	/* same for both directions */
 	.framein = g722tolin_framein,
 	.sample = g722_sample,
@@ -159,17 +148,6 @@ static struct ast_translator g722tolin = {
 
 static struct ast_translator lintog722 = {
 	.name = "lintog722",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "g722",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.format = "g722",
 	.newpvt = lintog722_new,	/* same for both directions */
 	.framein = lintog722_framein,
 	.sample = slin8_sample,
@@ -180,17 +158,6 @@ static struct ast_translator lintog722 = {
 
 static struct ast_translator g722tolin16 = {
 	.name = "g722tolin16",
-	.src_codec = {
-		.name = "g722",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.format = "slin16",
 	.newpvt = g722tolin16_new,	/* same for both directions */
 	.framein = g722tolin_framein,
 	.sample = g722_sample,
@@ -201,17 +168,6 @@ static struct ast_translator g722tolin16 = {
 
 static struct ast_translator lin16tog722 = {
 	.name = "lin16tog722",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.dst_codec = {
-		.name = "g722",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.format = "g722",
 	.newpvt = lin16tog722_new,	/* same for both directions */
 	.framein = lintog722_framein,
 	.sample = slin16_sample,
@@ -220,6 +176,11 @@ static struct ast_translator lin16tog722 = {
 	.buf_size = BUFFER_SAMPLES,
 };
 
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res = 0;
@@ -236,6 +197,18 @@ static int load_module(void)
 {
 	int res = 0;
 
+	ast_format_set(&g722tolin.src_format, AST_FORMAT_G722, 0);
+	ast_format_set(&g722tolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&lintog722.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintog722.dst_format, AST_FORMAT_G722, 0);
+
+	ast_format_set(&g722tolin16.src_format, AST_FORMAT_G722, 0);
+	ast_format_set(&g722tolin16.dst_format, AST_FORMAT_SLINEAR16, 0);
+
+	ast_format_set(&lin16tog722.src_format, AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(&lin16tog722.dst_format, AST_FORMAT_G722, 0);
+
 	res |= ast_register_translator(&g722tolin);
 	res |= ast_register_translator(&lintog722);
 	res |= ast_register_translator(&g722tolin16);
@@ -250,7 +223,7 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.722-64kbps G722 Transcoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_g726.c b/codecs/codec_g726.c
index 6d75d3f..72e77f9 100644
--- a/codecs/codec_g726.c
+++ b/codecs/codec_g726.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
@@ -785,17 +785,6 @@ static int lintog726_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 
 static struct ast_translator g726tolin = {
 	.name = "g726tolin",
-	.src_codec = {
-		.name = "g726",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.newpvt = lintog726_new,	/* same for both directions */
 	.framein = g726tolin_framein,
 	.sample = g726_sample,
@@ -806,17 +795,6 @@ static struct ast_translator g726tolin = {
 
 static struct ast_translator lintog726 = {
 	.name = "lintog726",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "g726",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "g726",
 	.newpvt = lintog726_new,	/* same for both directions */
 	.framein = lintog726_framein,
 	.sample = slin8_sample,
@@ -827,17 +805,6 @@ static struct ast_translator lintog726 = {
 
 static struct ast_translator g726aal2tolin = {
 	.name = "g726aal2tolin",
-	.src_codec = {
-		.name = "g726aal2",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.newpvt = lintog726_new,	/* same for both directions */
 	.framein = g726aal2tolin_framein,
 	.sample = g726_sample,
@@ -848,17 +815,6 @@ static struct ast_translator g726aal2tolin = {
 
 static struct ast_translator lintog726aal2 = {
 	.name = "lintog726aal2",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "g726aal2",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "g726aal2",
 	.newpvt = lintog726_new,	/* same for both directions */
 	.framein = lintog726aal2_framein,
 	.sample = slin8_sample,
@@ -867,6 +823,11 @@ static struct ast_translator lintog726aal2 = {
 	.buf_size = BUFFER_SAMPLES / 2,
 };
 
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res = 0;
@@ -884,6 +845,18 @@ static int load_module(void)
 {
 	int res = 0;
 
+	ast_format_set(&g726tolin.src_format, AST_FORMAT_G726, 0);
+	ast_format_set(&g726tolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&lintog726.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintog726.dst_format, AST_FORMAT_G726, 0);
+
+	ast_format_set(&g726aal2tolin.src_format, AST_FORMAT_G726_AAL2, 0);
+	ast_format_set(&g726aal2tolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&lintog726aal2.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintog726aal2.dst_format, AST_FORMAT_G726_AAL2, 0);
+
 	res |= ast_register_translator(&g726tolin);
 	res |= ast_register_translator(&lintog726);
 
@@ -899,7 +872,7 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.726-32kbps G726 Transcoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_gsm.c b/codecs/codec_gsm.c
index 047a89f..7027fab 100644
--- a/codecs/codec_gsm.c
+++ b/codecs/codec_gsm.c
@@ -33,12 +33,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/translate.h"
 #include "asterisk/config.h"
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
 
 #ifdef HAVE_GSM_HEADER
 #include "gsm.h"
@@ -139,25 +140,35 @@ static int lintogsm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 static struct ast_frame *lintogsm_frameout(struct ast_trans_pvt *pvt)
 {
 	struct gsm_translator_pvt *tmp = pvt->pvt;
-	int datalen = 0;
-	int samples = 0;
+	struct ast_frame *result = NULL;
+	struct ast_frame *last = NULL;
+	int samples = 0; /* output samples */
 
-	/* We can't work on anything less than a frame in size */
-	if (pvt->samples < GSM_SAMPLES)
-		return NULL;
 	while (pvt->samples >= GSM_SAMPLES) {
+		struct ast_frame *current;
+
 		/* Encode a frame of data */
-		gsm_encode(tmp->gsm, tmp->buf + samples, (gsm_byte *) pvt->outbuf.c + datalen);
-		datalen += GSM_FRAME_LEN;
+		gsm_encode(tmp->gsm, tmp->buf + samples, (gsm_byte *) pvt->outbuf.c);
 		samples += GSM_SAMPLES;
 		pvt->samples -= GSM_SAMPLES;
+
+		current = ast_trans_frameout(pvt, GSM_FRAME_LEN, GSM_SAMPLES);
+		if (!current) {
+			continue;
+		} else if (last) {
+			AST_LIST_NEXT(last, frame_list) = current;
+		} else {
+			result = current;
+		}
+		last = current;
 	}
 
 	/* Move the data at the end of the buffer to the front */
-	if (pvt->samples)
+	if (samples) {
 		memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+	}
 
-	return ast_trans_frameout(pvt, datalen, samples);
+	return result;
 }
 
 static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
@@ -168,18 +179,7 @@ static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
 }
 
 static struct ast_translator gsmtolin = {
-	.name = "gsmtolin",
-	.src_codec = {
-		.name = "gsm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
+	.name = "gsmtolin", 
 	.newpvt = gsm_new,
 	.framein = gsmtolin_framein,
 	.destroy = gsm_destroy_stuff,
@@ -190,18 +190,7 @@ static struct ast_translator gsmtolin = {
 };
 
 static struct ast_translator lintogsm = {
-	.name = "lintogsm",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "gsm",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "gsm",
+	.name = "lintogsm", 
 	.newpvt = gsm_new,
 	.framein = lintogsm_framein,
 	.frameout = lintogsm_frameout,
@@ -211,12 +200,19 @@ static struct ast_translator lintogsm = {
 	.buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
 };
 
+/*! \brief standard module glue */
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res;
 
 	res = ast_unregister_translator(&lintogsm);
-	res |= ast_unregister_translator(&gsmtolin);
+	if (!res)
+		res = ast_unregister_translator(&gsmtolin);
 
 	return res;
 }
@@ -225,19 +221,24 @@ static int load_module(void)
 {
 	int res;
 
-	res = ast_register_translator(&gsmtolin);
-	res |= ast_register_translator(&lintogsm);
+	ast_format_set(&gsmtolin.src_format, AST_FORMAT_GSM, 0);
+	ast_format_set(&gsmtolin.dst_format, AST_FORMAT_SLINEAR, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	ast_format_set(&lintogsm.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintogsm.dst_format, AST_FORMAT_GSM, 0);
 
+	res = ast_register_translator(&gsmtolin);
+	if (!res) 
+		res=ast_register_translator(&lintogsm);
+	else
+		ast_unregister_translator(&gsmtolin);
+	if (res) 
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "GSM Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_ilbc.c b/codecs/codec_ilbc.c
index 75f8195..c0bb630 100644
--- a/codecs/codec_ilbc.c
+++ b/codecs/codec_ilbc.c
@@ -32,11 +32,12 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/translate.h"
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
 
 #ifdef ILBC_WEBRTC
 #include <ilbc.h>
@@ -150,46 +151,44 @@ static int lintoilbc_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 static struct ast_frame *lintoilbc_frameout(struct ast_trans_pvt *pvt)
 {
 	struct ilbc_coder_pvt *tmp = pvt->pvt;
-	int datalen = 0;
-	int samples = 0;
+	struct ast_frame *result = NULL;
+	struct ast_frame *last = NULL;
+	int samples = 0; /* output samples */
 
-	/* We can't work on anything less than a frame in size */
-	if (pvt->samples < ILBC_SAMPLES)
-		return NULL;
 	while (pvt->samples >= ILBC_SAMPLES) {
+		struct ast_frame *current;
 		ilbc_block tmpf[ILBC_SAMPLES];
 		int i;
 
 		/* Encode a frame of data */
 		for (i = 0 ; i < ILBC_SAMPLES ; i++)
 			tmpf[i] = tmp->buf[samples + i];
-		iLBC_encode( (ilbc_bytes*)pvt->outbuf.BUF_TYPE + datalen, tmpf, &tmp->enc);
+		iLBC_encode((ilbc_bytes *) pvt->outbuf.BUF_TYPE, tmpf, &tmp->enc);
 
-		datalen += ILBC_FRAME_LEN;
 		samples += ILBC_SAMPLES;
 		pvt->samples -= ILBC_SAMPLES;
+
+		current = ast_trans_frameout(pvt, ILBC_FRAME_LEN, ILBC_SAMPLES);
+		if (!current) {
+			continue;
+		} else if (last) {
+			AST_LIST_NEXT(last, frame_list) = current;
+		} else {
+			result = current;
+		}
+		last = current;
 	}
 
 	/* Move the data at the end of the buffer to the front */
-	if (pvt->samples)
+	if (samples) {
 		memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+	}
 
-	return ast_trans_frameout(pvt, datalen, samples);
+	return result;
 }
 
 static struct ast_translator ilbctolin = {
-	.name = "ilbctolin",
-	.src_codec = {
-		.name = "ilbc",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
+	.name = "ilbctolin", 
 	.newpvt = ilbctolin_new,
 	.framein = ilbctolin_framein,
 	.sample = ilbc_sample,
@@ -199,18 +198,7 @@ static struct ast_translator ilbctolin = {
 };
 
 static struct ast_translator lintoilbc = {
-	.name = "lintoilbc",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "ilbc",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "ilbc",
+	.name = "lintoilbc", 
 	.newpvt = lintoilbc_new,
 	.framein = lintoilbc_framein,
 	.frameout = lintoilbc_frameout,
@@ -233,14 +221,20 @@ static int load_module(void)
 {
 	int res;
 
-	res = ast_register_translator(&ilbctolin);
-	res |= ast_register_translator(&lintoilbc);
+	ast_format_set(&ilbctolin.src_format, AST_FORMAT_ILBC, 0);
+	ast_format_set(&ilbctolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&lintoilbc.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoilbc.dst_format, AST_FORMAT_ILBC, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
 
+	res = ast_register_translator(&ilbctolin);
+	if (!res) 
+		res=ast_register_translator(&lintoilbc);
+	else
+		ast_unregister_translator(&ilbctolin);
+	if (res)
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/codecs/codec_lpc10.c b/codecs/codec_lpc10.c
index c9509ce..770b056 100644
--- a/codecs/codec_lpc10.c
+++ b/codecs/codec_lpc10.c
@@ -33,12 +33,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/translate.h"
 #include "asterisk/config.h"
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
 
 #include "lpc10/lpc10.h"
 
@@ -160,31 +161,45 @@ static int lintolpc10_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 static struct ast_frame *lintolpc10_frameout(struct ast_trans_pvt *pvt)
 {
 	struct lpc10_coder_pvt *tmp = pvt->pvt;
-	int x;
-	int datalen = 0;	/* output frame */
-	int samples = 0;	/* output samples */
-	float tmpbuf[LPC10_SAMPLES_PER_FRAME];
-	INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];	/* XXX what ??? */
-	/* We can't work on anything less than a frame in size */
-	if (pvt->samples < LPC10_SAMPLES_PER_FRAME)
-		return NULL;
-	while (pvt->samples >=  LPC10_SAMPLES_PER_FRAME) {
+	struct ast_frame *result = NULL;
+	struct ast_frame *last = NULL;
+	int samples = 0; /* output samples */
+
+	while (pvt->samples >= LPC10_SAMPLES_PER_FRAME) {
+		struct ast_frame *current;
+		float tmpbuf[LPC10_SAMPLES_PER_FRAME];
+		INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];	/* XXX what ??? */
+		int x;
+
 		/* Encode a frame of data */
 		for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++)
 			tmpbuf[x] = (float)tmp->buf[x + samples] / 32768.0;
 		lpc10_encode(tmpbuf, bits, tmp->lpc10.enc);
-		build_bits(pvt->outbuf.uc + datalen, bits);
-		datalen += LPC10_BYTES_IN_COMPRESSED_FRAME;
+		build_bits(pvt->outbuf.uc, bits);
+
 		samples += LPC10_SAMPLES_PER_FRAME;
 		pvt->samples -= LPC10_SAMPLES_PER_FRAME;
 		/* Use one of the two left over bits to record if this is a 22 or 23 ms frame...
 		   important for IAX use */
 		tmp->longer = 1 - tmp->longer;
+
+		current = ast_trans_frameout(pvt, LPC10_BYTES_IN_COMPRESSED_FRAME, LPC10_SAMPLES_PER_FRAME);
+		if (!current) {
+			continue;
+		} else if (last) {
+			AST_LIST_NEXT(last, frame_list) = current;
+		} else {
+			result = current;
+		}
+		last = current;
 	}
+
 	/* Move the data at the end of the buffer to the front */
-	if (pvt->samples)
+	if (samples) {
 		memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
-	return ast_trans_frameout(pvt, datalen, samples);
+	}
+
+	return result;
 }
 
 
@@ -196,18 +211,7 @@ static void lpc10_destroy(struct ast_trans_pvt *arg)
 }
 
 static struct ast_translator lpc10tolin = {
-	.name = "lpc10tolin",
-	.src_codec = {
-		.name = "lpc10",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
+	.name = "lpc10tolin", 
 	.newpvt = lpc10_dec_new,
 	.framein = lpc10tolin_framein,
 	.destroy = lpc10_destroy,
@@ -218,18 +222,7 @@ static struct ast_translator lpc10tolin = {
 };
 
 static struct ast_translator lintolpc10 = {
-	.name = "lintolpc10",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "lpc10",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "lpc10",
+	.name = "lintolpc10", 
 	.newpvt = lpc10_enc_new,
 	.framein = lintolpc10_framein,
 	.frameout = lintolpc10_frameout,
@@ -240,6 +233,12 @@ static struct ast_translator lintolpc10 = {
 	.buf_size = LPC10_BYTES_IN_COMPRESSED_FRAME * (1 + BUFFER_SAMPLES / LPC10_SAMPLES_PER_FRAME),
 };
 
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+
 static int unload_module(void)
 {
 	int res;
@@ -254,19 +253,24 @@ static int load_module(void)
 {
 	int res;
 
-	res = ast_register_translator(&lpc10tolin);
-	res |= ast_register_translator(&lintolpc10);
+	ast_format_set(&lpc10tolin.src_format, AST_FORMAT_LPC10, 0);
+	ast_format_set(&lpc10tolin.dst_format, AST_FORMAT_SLINEAR, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	ast_format_set(&lintolpc10.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintolpc10.dst_format, AST_FORMAT_LPC10, 0);
 
+	res = ast_register_translator(&lpc10tolin);
+	if (!res) 
+		res = ast_register_translator(&lintolpc10);
+	else
+		ast_unregister_translator(&lpc10tolin);
+	if (res)
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "LPC10 2.4kbps Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c
index dc6dfd2..29d95a7 100644
--- a/codecs/codec_resample.c
+++ b/codecs/codec_resample.c
@@ -32,7 +32,7 @@
 #include "asterisk.h"
 #include "speex/speex_resampler.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/translate.h"
@@ -42,72 +42,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 
 static struct ast_translator *translators;
 static int trans_size;
-static struct ast_codec codec_list[] = {
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 12000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 24000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 32000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 44100,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 48000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 96000,
-	},
-	{
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 192000,
-	},
+static int id_list[] = {
+	AST_FORMAT_SLINEAR,
+	AST_FORMAT_SLINEAR12,
+	AST_FORMAT_SLINEAR16,
+	AST_FORMAT_SLINEAR24,
+	AST_FORMAT_SLINEAR32,
+	AST_FORMAT_SLINEAR44,
+	AST_FORMAT_SLINEAR48,
+	AST_FORMAT_SLINEAR96,
+	AST_FORMAT_SLINEAR192,
 };
 
 static int resamp_new(struct ast_trans_pvt *pvt)
 {
 	int err;
 
-	if (!(pvt->pvt = speex_resampler_init(1, pvt->t->src_codec.sample_rate, pvt->t->dst_codec.sample_rate, 5, &err))) {
+	if (!(pvt->pvt = speex_resampler_init(1, ast_format_rate(&pvt->t->src_format), ast_format_rate(&pvt->t->dst_format), 5, &err))) {
 		return -1;
 	}
 
-	ast_assert(pvt->f.subclass.format == NULL);
-	pvt->f.subclass.format = ao2_bump(ast_format_cache_get_slin_by_rate(pvt->t->dst_codec.sample_rate));
-
 	return 0;
 }
 
 static void resamp_destroy(struct ast_trans_pvt *pvt)
 {
 	SpeexResamplerState *resamp_pvt = pvt->pvt;
-
 	speex_resampler_destroy(resamp_pvt);
 }
 
@@ -153,13 +113,13 @@ static int load_module(void)
 	int res = 0;
 	int x, y, idx = 0;
 
-	trans_size = ARRAY_LEN(codec_list) * (ARRAY_LEN(codec_list) - 1);
+	trans_size = ARRAY_LEN(id_list) * (ARRAY_LEN(id_list) - 1);
 	if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	for (x = 0; x < ARRAY_LEN(codec_list); x++) {
-		for (y = 0; y < ARRAY_LEN(codec_list); y++) {
+	for (x = 0; x < ARRAY_LEN(id_list); x++) {
+		for (y = 0; y < ARRAY_LEN(id_list); y++) {
 			if (x == y) {
 				continue;
 			}
@@ -169,10 +129,10 @@ static int load_module(void)
 			translators[idx].desc_size = 0;
 			translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t));
 			translators[idx].buf_size = OUTBUF_SIZE;
-			memcpy(&translators[idx].src_codec, &codec_list[x], sizeof(struct ast_codec));
-			memcpy(&translators[idx].dst_codec, &codec_list[y], sizeof(struct ast_codec));
-			snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %ukhz -> %ukhz",
-				translators[idx].src_codec.sample_rate, translators[idx].dst_codec.sample_rate);
+			ast_format_set(&translators[idx].src_format, id_list[x], 0);
+			ast_format_set(&translators[idx].dst_format, id_list[y], 0);
+			snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %dkhz -> %dkhz",
+				ast_format_rate(&translators[idx].src_format), ast_format_rate(&translators[idx].dst_format));
 			res |= ast_register_translator(&translators[idx]);
 			idx++;
 		}
diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c
index 6bc8fcd..d66af79 100644
--- a/codecs/codec_speex.c
+++ b/codecs/codec_speex.c
@@ -26,7 +26,7 @@
  *
  * \ingroup codecs
  *
- * The Speex library - http://www.speex.org
+ * \extref The Speex library - http://www.speex.org
  *
  */
 
@@ -39,13 +39,12 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <speex/speex.h>
 
 /* We require a post 1.1.8 version of Speex to enable preprocessing
- * and better type handling
- */   
+   and better type handling */   
 #ifdef _SPEEX_TYPES_H
 #include <speex/speex_preprocess.h>
 #endif
@@ -54,6 +53,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/module.h"
 #include "asterisk/config.h"
 #include "asterisk/utils.h"
+#include "asterisk/frame.h"
+#include "asterisk/linkedlists.h"
 
 /* codec variables */
 static int quality = 3;
@@ -259,15 +260,16 @@ static int lintospeex_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
 {
 	struct speex_coder_pvt *tmp = pvt->pvt;
-	int is_speech=1;
-	int datalen = 0;	/* output bytes */
-	int samples = 0;	/* output samples */
+	struct ast_frame *result = NULL;
+	struct ast_frame *last = NULL;
+	int samples = 0; /* output samples */
 
-	/* We can't work on anything less than a frame in size */
-	if (pvt->samples < tmp->framesize)
-		return NULL;
-	speex_bits_reset(&tmp->bits);
 	while (pvt->samples >= tmp->framesize) {
+		struct ast_frame *current;
+		int is_speech = 1;
+
+		speex_bits_reset(&tmp->bits);
+
 #ifdef _SPEEX_TYPES_H
 		/* Preprocess audio */
 		if (preproc)
@@ -293,41 +295,44 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
 #endif
 		samples += tmp->framesize;
 		pvt->samples -= tmp->framesize;
-	}
-
-	/* Move the data at the end of the buffer to the front */
-	if (pvt->samples)
-		memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
 
-	/* Use AST_FRAME_CNG to signify the start of any silence period */
-	if (is_speech) {
-		tmp->silent_state = 0;
-	} else {
-		if (tmp->silent_state) {
-			return NULL;
+		/* Use AST_FRAME_CNG to signify the start of any silence period */
+		if (is_speech) {
+			int datalen = 0; /* output bytes */
+
+			tmp->silent_state = 0;
+			/* Terminate bit stream */
+			speex_bits_pack(&tmp->bits, 15, 5);
+			datalen = speex_bits_write(&tmp->bits, pvt->outbuf.c, pvt->t->buf_size);
+			current = ast_trans_frameout(pvt, datalen, tmp->framesize);
+		} else if (tmp->silent_state) {
+			current = NULL;
 		} else {
-			struct ast_frame frm = {
-				.frametype = AST_FRAME_CNG,
-				.src = pvt->t->name,
-			};
-
-			/*
-			 * XXX I don't think the AST_FRAME_CNG code has ever
-			 * really worked for speex.  There doesn't seem to be
-			 * any consumers of the frame type.  Everyone that
-			 * references the type seems to pass the frame on.
-			 */
 			tmp->silent_state = 1;
-
+			speex_bits_reset(&tmp->bits);
+			memset(&pvt->f, 0, sizeof(pvt->f));
+			pvt->f.frametype = AST_FRAME_CNG;
+			pvt->f.samples = tmp->framesize;
 			/* XXX what now ? format etc... */
-			return ast_frisolate(&frm);
+			current = ast_frisolate(&pvt->f);
+		}
+
+		if (!current) {
+			continue;
+		} else if (last) {
+			AST_LIST_NEXT(last, frame_list) = current;
+		} else {
+			result = current;
 		}
+		last = current;
 	}
 
-	/* Terminate bit stream */
-	speex_bits_pack(&tmp->bits, 15, 5);
-	datalen = speex_bits_write(&tmp->bits, pvt->outbuf.c, pvt->t->buf_size);
-	return ast_trans_frameout(pvt, datalen, samples);
+	/* Move the data at the end of the buffer to the front */
+	if (samples) {
+		memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+	}
+
+	return result;
 }
 
 static void speextolin_destroy(struct ast_trans_pvt *arg)
@@ -350,18 +355,7 @@ static void lintospeex_destroy(struct ast_trans_pvt *arg)
 }
 
 static struct ast_translator speextolin = {
-	.name = "speextolin",
-	.src_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
+	.name = "speextolin", 
 	.newpvt = speextolin_new,
 	.framein = speextolin_framein,
 	.destroy = speextolin_destroy,
@@ -374,17 +368,6 @@ static struct ast_translator speextolin = {
 
 static struct ast_translator lintospeex = {
 	.name = "lintospeex", 
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "speex",
 	.newpvt = lintospeex_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
@@ -396,18 +379,7 @@ static struct ast_translator lintospeex = {
 };
 
 static struct ast_translator speexwbtolin16 = {
-	.name = "speexwbtolin16",
-	.src_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	}, 
-	.format = "slin16",
+	.name = "speexwbtolin16", 
 	.newpvt = speexwbtolin16_new,
 	.framein = speextolin_framein,
 	.destroy = speextolin_destroy,
@@ -419,18 +391,7 @@ static struct ast_translator speexwbtolin16 = {
 };
 
 static struct ast_translator lin16tospeexwb = {
-	.name = "lin16tospeexwb",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.dst_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 16000,
-	},
-	.format = "speex16",
+	.name = "lin16tospeexwb", 
 	.newpvt = lin16tospeexwb_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
@@ -442,18 +403,7 @@ static struct ast_translator lin16tospeexwb = {
 };
 
 static struct ast_translator speexuwbtolin32 = {
-	.name = "speexuwbtolin32",
-	.src_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 32000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 32000,
-	},
-	.format = "slin32",
+	.name = "speexuwbtolin32", 
 	.newpvt = speexuwbtolin32_new,
 	.framein = speextolin_framein,
 	.destroy = speextolin_destroy,
@@ -464,18 +414,7 @@ static struct ast_translator speexuwbtolin32 = {
 };
 
 static struct ast_translator lin32tospeexuwb = {
-	.name = "lin32tospeexuwb",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 32000,
-	},
-	.dst_codec = {
-		.name = "speex",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 32000,
-	},
-	.format = "speex32",
+	.name = "lin32tospeexuwb", 
 	.newpvt = lin32tospeexuwb_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
@@ -609,6 +548,25 @@ static int load_module(void)
 	if (parse_config(0))
 		return AST_MODULE_LOAD_DECLINE;
 
+
+	ast_format_set(&speextolin.src_format, AST_FORMAT_SPEEX, 0);
+	ast_format_set(&speextolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&lintospeex.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintospeex.dst_format, AST_FORMAT_SPEEX, 0);
+
+	ast_format_set(&speexwbtolin16.src_format, AST_FORMAT_SPEEX16, 0);
+	ast_format_set(&speexwbtolin16.dst_format, AST_FORMAT_SLINEAR16, 0);
+
+	ast_format_set(&lin16tospeexwb.src_format, AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(&lin16tospeexwb.dst_format, AST_FORMAT_SPEEX16, 0);
+
+	ast_format_set(&speexuwbtolin32.src_format, AST_FORMAT_SPEEX32, 0);
+	ast_format_set(&speexuwbtolin32.dst_format, AST_FORMAT_SLINEAR32, 0);
+
+	ast_format_set(&lin32tospeexuwb.src_format, AST_FORMAT_SLINEAR32, 0);
+	ast_format_set(&lin32tospeexuwb.dst_format, AST_FORMAT_SPEEX32, 0);
+
 	res |= ast_register_translator(&speextolin);
 	res |= ast_register_translator(&lintospeex);
 	res |= ast_register_translator(&speexwbtolin16);
@@ -616,16 +574,11 @@ static int load_module(void)
 	res |= ast_register_translator(&speexuwbtolin32);
 	res |= ast_register_translator(&lin32tospeexuwb);
 
-	if (res) {
-		unload_module();
-		return res;
-	}
 
 	return res;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/codecs/codec_ulaw.c b/codecs/codec_ulaw.c
index 3ed8b40..86a0706 100644
--- a/codecs/codec_ulaw.c
+++ b/codecs/codec_ulaw.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/config.h"
@@ -82,17 +82,6 @@ static int lintoulaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 
 static struct ast_translator ulawtolin = {
 	.name = "ulawtolin",
-	.src_codec = {
-		.name = "ulaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.framein = ulawtolin_framein,
 	.sample = ulaw_sample,
 	.buffer_samples = BUFFER_SAMPLES,
@@ -101,17 +90,6 @@ static struct ast_translator ulawtolin = {
 
 static struct ast_translator testlawtolin = {
 	.name = "testlawtolin",
-	.src_codec = {
-		.name = "testlaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "slin",
 	.framein = ulawtolin_framein,
 	.sample = ulaw_sample,
 	.buffer_samples = BUFFER_SAMPLES,
@@ -124,17 +102,6 @@ static struct ast_translator testlawtolin = {
 
 static struct ast_translator lintoulaw = {
 	.name = "lintoulaw",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "ulaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "ulaw",
 	.framein = lintoulaw_framein,
 	.sample = slin8_sample,
 	.buf_size = BUFFER_SAMPLES,
@@ -143,23 +110,17 @@ static struct ast_translator lintoulaw = {
 
 static struct ast_translator lintotestlaw = {
 	.name = "lintotestlaw",
-	.src_codec = {
-		.name = "slin",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.dst_codec = {
-		.name = "testlaw",
-		.type = AST_MEDIA_TYPE_AUDIO,
-		.sample_rate = 8000,
-	},
-	.format = "testlaw",
 	.framein = lintoulaw_framein,
 	.sample = slin8_sample,
 	.buf_size = BUFFER_SAMPLES,
 	.buffer_samples = BUFFER_SAMPLES,
 };
 
+static int reload(void)
+{
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
 static int unload_module(void)
 {
 	int res;
@@ -176,21 +137,32 @@ static int load_module(void)
 {
 	int res;
 
-	res = ast_register_translator(&ulawtolin);
-	res |= ast_register_translator(&lintoulaw);
-	res |= ast_register_translator(&lintotestlaw);
-	res |= ast_register_translator(&testlawtolin);
+	ast_format_set(&lintoulaw.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoulaw.dst_format, AST_FORMAT_ULAW, 0);
 
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	ast_format_set(&lintotestlaw.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintotestlaw.dst_format, AST_FORMAT_TESTLAW, 0);
+
+	ast_format_set(&ulawtolin.src_format, AST_FORMAT_ULAW, 0);
+	ast_format_set(&ulawtolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+	ast_format_set(&testlawtolin.src_format, AST_FORMAT_TESTLAW, 0);
+	ast_format_set(&testlawtolin.dst_format, AST_FORMAT_SLINEAR, 0);
 
+	res = ast_register_translator(&ulawtolin);
+	if (!res) {
+		res = ast_register_translator(&lintoulaw);
+		res |= ast_register_translator(&lintotestlaw);
+		res |= ast_register_translator(&testlawtolin);
+	} else
+		ast_unregister_translator(&ulawtolin);
+	if (res)
+		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "mu-Law Coder/Decoder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
+		.reload = reload,
 	       );
diff --git a/codecs/ex_adpcm.h b/codecs/ex_adpcm.h
index 3602397..96b7c51 100644
--- a/codecs/ex_adpcm.h
+++ b/codecs/ex_adpcm.h
@@ -26,8 +26,7 @@ static struct ast_frame *adpcm_sample(void)
 		.src = __PRETTY_FUNCTION__,
 		.data.ptr = ex_adpcm,
 	};
-
-	f.subclass.format = ast_format_adpcm;
+	ast_format_set(&f.subclass.format, AST_FORMAT_ADPCM, 0);
 
 	return &f;
 }
diff --git a/codecs/ex_alaw.h b/codecs/ex_alaw.h
index e8629be..bbf8ad9 100644
--- a/codecs/ex_alaw.h
+++ b/codecs/ex_alaw.h
@@ -31,6 +31,6 @@ static struct ast_frame *alaw_sample(void)
 		.src = __PRETTY_FUNCTION__,
 		.data.ptr = ex_alaw,
 	};
-	f.subclass.format = ast_format_alaw;
+	ast_format_set(&f.subclass.format, AST_FORMAT_ALAW, 0);
 	return &f;
 }
diff --git a/codecs/ex_g722.h b/codecs/ex_g722.h
index 390cc7b..0e9f226 100644
--- a/codecs/ex_g722.h
+++ b/codecs/ex_g722.h
@@ -42,7 +42,7 @@ static struct ast_frame *g722_sample(void)
 		.data.ptr = ex_g722,
 	};
 
-	f.subclass.format = ast_format_slin;
+	ast_format_set(&f.subclass.format, AST_FORMAT_G722, 0);
 
 	return &f;
 }
diff --git a/codecs/ex_g726.h b/codecs/ex_g726.h
index f125253..d5438c9 100644
--- a/codecs/ex_g726.h
+++ b/codecs/ex_g726.h
@@ -27,7 +27,7 @@ static struct ast_frame *g726_sample(void)
 		.data.ptr = ex_g726,
 	};
 
-	f.subclass.format = ast_format_g726;
+	ast_format_set(&f.subclass.format, AST_FORMAT_G726, 0);
 
 	return &f;
 }
diff --git a/codecs/ex_gsm.h b/codecs/ex_gsm.h
index 0067060..8f8b4f9 100644
--- a/codecs/ex_gsm.h
+++ b/codecs/ex_gsm.h
@@ -27,7 +27,6 @@ static struct ast_frame *gsm_sample(void)
 		.data.ptr = ex_gsm,
 	};
 
-	f.subclass.format = ast_format_gsm;
-
+	ast_format_set(&f.subclass.format, AST_FORMAT_GSM, 0);
 	return &f;
 }
diff --git a/codecs/ex_ilbc.h b/codecs/ex_ilbc.h
index 3a79b09..93cf5ea 100644
--- a/codecs/ex_ilbc.h
+++ b/codecs/ex_ilbc.h
@@ -28,7 +28,6 @@ static struct ast_frame *ilbc_sample(void)
 		.data.ptr = ex_ilbc,
 	};
 
-	f.subclass.format = ast_format_ilbc;
-
+	ast_format_set(&f.subclass.format, AST_FORMAT_ILBC, 0);
 	return &f;
 }
diff --git a/codecs/ex_lpc10.h b/codecs/ex_lpc10.h
index 2e271c0..a36e06a 100644
--- a/codecs/ex_lpc10.h
+++ b/codecs/ex_lpc10.h
@@ -25,7 +25,7 @@ static struct ast_frame *lpc10_sample(void)
 		.data.ptr = ex_lpc10,
 	};
 
-	f.subclass.format = ast_format_lpc10;
+	ast_format_set(&f.subclass.format, AST_FORMAT_LPC10, 0);
 
 	return &f;
 }
diff --git a/codecs/ex_speex.h b/codecs/ex_speex.h
index 76e5925..e9411e5 100644
--- a/codecs/ex_speex.h
+++ b/codecs/ex_speex.h
@@ -27,7 +27,7 @@ static struct ast_frame *speex_sample(void)
 		.data.ptr = ex_speex,
 	};
 
-	f.subclass.format = ast_format_speex;
+	ast_format_set(&f.subclass.format, AST_FORMAT_SPEEX, 0);
 
 	return &f;
 }
@@ -58,8 +58,7 @@ static struct ast_frame *speex16_sample(void)
 		.src = __PRETTY_FUNCTION__,
 		.data.ptr = ex_speex16,
 	};
-
-	f.subclass.format = ast_format_speex16;
+	ast_format_set(&f.subclass.format, AST_FORMAT_SPEEX16, 0);
 
 	return &f;
 }
diff --git a/codecs/ex_ulaw.h b/codecs/ex_ulaw.h
index d18a08e..2ab9222 100644
--- a/codecs/ex_ulaw.h
+++ b/codecs/ex_ulaw.h
@@ -32,7 +32,6 @@ static struct ast_frame *ulaw_sample(void)
 		.data.ptr = ex_ulaw,
 	};
 
-	f.subclass.format = ast_format_ulaw;
-
+	ast_format_set(&f.subclass.format, AST_FORMAT_ULAW, 0);
 	return &f;
 }
diff --git a/codecs/g722/g722.h b/codecs/g722/g722.h
index a197ffd..f57b1c8 100644
--- a/codecs/g722/g722.h
+++ b/codecs/g722/g722.h
@@ -18,7 +18,7 @@
  * Computer Science, Speech Group
  * Chengxiang Lu and Alex Hauptmann
  *
- * $Id: g722.h 48959 2006-12-25 06:42:15Z rizzo $
+ * $Id$
  */
 
 
diff --git a/codecs/g722/g722_decode.c b/codecs/g722/g722_decode.c
index 233bee5..3e8f7d0 100644
--- a/codecs/g722/g722_decode.c
+++ b/codecs/g722/g722_decode.c
@@ -18,7 +18,7 @@
  * Computer Science, Speech Group
  * Chengxiang Lu and Alex Hauptmann
  *
- * $Id: g722_decode.c 194722 2009-05-15 17:59:08Z russell $
+ * $Id$
  */
 
 /*! \file */
diff --git a/codecs/g722/g722_encode.c b/codecs/g722/g722_encode.c
index db563a7..5890fbf 100644
--- a/codecs/g722/g722_encode.c
+++ b/codecs/g722/g722_encode.c
@@ -20,7 +20,7 @@
  * Computer Science, Speech Group
  * Chengxiang Lu and Alex Hauptmann
  *
- * $Id: g722_encode.c 194722 2009-05-15 17:59:08Z russell $
+ * $Id$
  */
 
 /*! \file */
diff --git a/codecs/gsm/src/gsm_create.c b/codecs/gsm/src/gsm_create.c
index a59aa2f..f952a7d 100644
--- a/codecs/gsm/src/gsm_create.c
+++ b/codecs/gsm/src/gsm_create.c
@@ -4,8 +4,6 @@
  * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
  */
 
-static char const	ident[] = "$Header$";
-
 #include	"config.h"
 
 #ifdef	HAS_STRING_H
diff --git a/codecs/log2comp.h b/codecs/log2comp.h
index 6dc59c3..aa397c8 100644
--- a/codecs/log2comp.h
+++ b/codecs/log2comp.h
@@ -1,7 +1,7 @@
 /*! \file 
  * \brief log2comp.h - various base 2 log computation versions
  * 
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * \author Alex Volkov <codepro at usa.net>
  *
diff --git a/codecs/speex/speex_resampler.h b/codecs/speex/speex_resampler.h
index 5dead0e..0247e18 100644
--- a/codecs/speex/speex_resampler.h
+++ b/codecs/speex/speex_resampler.h
@@ -113,15 +113,14 @@ enum {
 struct SpeexResamplerState_;
 typedef struct SpeexResamplerState_ SpeexResamplerState;
 
-/** \brief Create a new resampler with integer input and output rates.
- * \param nb_channels Number of channels to be processed
- * \param in_rate Input sampling rate (integer number of Hz).
- * \param out_rate Output sampling rate (integer number of Hz).
- * \param quality Resampling quality between 0 and 10, where 0 has poor quality
- * 	and 10 has very high quality.
- * \param err
- * \return Newly created resampler state
- * \retval NULL Error: not enough memory
+/** Create a new resampler with integer input and output rates.
+ * @param nb_channels Number of channels to be processed
+ * @param in_rate Input sampling rate (integer number of Hz).
+ * @param out_rate Output sampling rate (integer number of Hz).
+ * @param quality Resampling quality between 0 and 10, where 0 has poor quality
+ * and 10 has very high quality.
+ * @return Newly created resampler state
+ * @retval NULL Error: not enough memory
  */
 SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, 
                                           spx_uint32_t in_rate, 
@@ -138,8 +137,7 @@ SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
  * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
  * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
  * @param quality Resampling quality between 0 and 10, where 0 has poor quality
- * 	and 10 has very high quality.
- * @param err
+ * and 10 has very high quality.
  * @return Newly created resampler state
  * @retval NULL Error: not enough memory
  */
diff --git a/config.guess b/config.guess
index 1f5c50c..872b96a 100755
--- a/config.guess
+++ b/config.guess
@@ -1,12 +1,14 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2014-03-23'
+timestamp='2012-09-25'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful, but
@@ -20,17 +22,19 @@ timestamp='2014-03-23'
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program.  This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches at gnu.org> and include a ChangeLog
+# entry.
 #
-# Originally written by Per Bothner.
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
 #
 # You can get the latest version of this script from:
 # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
-#
-# Please send patches with a ChangeLog entry to config-patches at gnu.org.
-
 
 me=`echo "$0" | sed -e 's,.*/,,'`
 
@@ -50,7 +54,9 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -132,27 +138,6 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
 UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
 UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
-case "${UNAME_SYSTEM}" in
-Linux|GNU|GNU/*)
-	# If the system lacks a compiler, then just pick glibc.
-	# We could probably try harder.
-	LIBC=gnu
-
-	eval $set_cc_for_build
-	cat <<-EOF > $dummy.c
-	#include <features.h>
-	#if defined(__UCLIBC__)
-	LIBC=uclibc
-	#elif defined(__dietlibc__)
-	LIBC=dietlibc
-	#else
-	LIBC=gnu
-	#endif
-	EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
-	;;
-esac
-
 # Note: order is significant - the case branches are not exclusive.
 
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
@@ -826,7 +811,7 @@ EOF
     *:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit ;;
-    *:MSYS*:*)
+    i*:MSYS*:*)
 	echo ${UNAME_MACHINE}-pc-msys
 	exit ;;
     i*:windows32*:*)
@@ -874,21 +859,21 @@ EOF
 	exit ;;
     *:GNU:*:*)
 	# the GNU system
-	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
 	exit ;;
     *:GNU/*:*:*)
 	# other systems with GNU libc and userland
-	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
 	exit ;;
     i*86:Minix:*:*)
 	echo ${UNAME_MACHINE}-pc-minix
 	exit ;;
     aarch64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     aarch64_be:Linux:*:*)
 	UNAME_MACHINE=aarch64_be
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     alpha:Linux:*:*)
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -901,54 +886,59 @@ EOF
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
 	esac
 	objdump --private-headers /bin/sh | grep -q ld.so.1
-	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-	exit ;;
-    arc:Linux:*:* | arceb:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
 	exit ;;
     arm*:Linux:*:*)
 	eval $set_cc_for_build
 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
 	    | grep -q __ARM_EABI__
 	then
-	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
 	else
 	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
 		| grep -q __ARM_PCS_VFP
 	    then
-		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabi
 	    else
-		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
 	    fi
 	fi
 	exit ;;
     avr32*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     cris:Linux:*:*)
-	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	echo ${UNAME_MACHINE}-axis-linux-gnu
 	exit ;;
     crisv32:Linux:*:*)
-	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	echo ${UNAME_MACHINE}-axis-linux-gnu
 	exit ;;
     frv:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     hexagon:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     i*86:Linux:*:*)
-	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
 	exit ;;
     ia64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     m32r*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     m68*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     mips:Linux:*:* | mips64:Linux:*:*)
 	eval $set_cc_for_build
@@ -967,63 +957,54 @@ EOF
 	#endif
 EOF
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
 	;;
-    openrisc*:Linux:*:*)
-	echo or1k-unknown-linux-${LIBC}
-	exit ;;
-    or32:Linux:*:* | or1k*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     padre:Linux:*:*)
-	echo sparc-unknown-linux-${LIBC}
+	echo sparc-unknown-linux-gnu
 	exit ;;
     parisc64:Linux:*:* | hppa64:Linux:*:*)
-	echo hppa64-unknown-linux-${LIBC}
+	echo hppa64-unknown-linux-gnu
 	exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
 	# Look for CPU level
 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
-	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
-	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
 	esac
 	exit ;;
     ppc64:Linux:*:*)
-	echo powerpc64-unknown-linux-${LIBC}
+	echo powerpc64-unknown-linux-gnu
 	exit ;;
     ppc:Linux:*:*)
-	echo powerpc-unknown-linux-${LIBC}
-	exit ;;
-    ppc64le:Linux:*:*)
-	echo powerpc64le-unknown-linux-${LIBC}
-	exit ;;
-    ppcle:Linux:*:*)
-	echo powerpcle-unknown-linux-${LIBC}
+	echo powerpc-unknown-linux-gnu
 	exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
-	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	echo ${UNAME_MACHINE}-ibm-linux
 	exit ;;
     sh64*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     sh*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     sparc:Linux:*:* | sparc64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     tile*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     vax:Linux:*:*)
-	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	echo ${UNAME_MACHINE}-dec-linux-gnu
 	exit ;;
     x86_64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     xtensa*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     i*86:DYNIX/ptx:4*:*)
 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -1256,31 +1237,19 @@ EOF
 	exit ;;
     *:Darwin:*:*)
 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-	eval $set_cc_for_build
-	if test "$UNAME_PROCESSOR" = unknown ; then
-	    UNAME_PROCESSOR=powerpc
-	fi
-	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
-	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-		    grep IS_64BIT_ARCH >/dev/null
-		then
-		    case $UNAME_PROCESSOR in
-			i386) UNAME_PROCESSOR=x86_64 ;;
-			powerpc) UNAME_PROCESSOR=powerpc64 ;;
-		    esac
-		fi
-	    fi
-	elif test "$UNAME_PROCESSOR" = i386 ; then
-	    # Avoid executing cc on OS X 10.9, as it ships with a stub
-	    # that puts up a graphical alert prompting to install
-	    # developer tools.  Any system running Mac OS X 10.7 or
-	    # later (Darwin 11 and later) is required to have a 64-bit
-	    # processor. This is not true of the ARM version of Darwin
-	    # that Apple uses in portable devices.
-	    UNAME_PROCESSOR=x86_64
-	fi
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
 	exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
@@ -1371,6 +1340,154 @@ EOF
 	exit ;;
 esac
 
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+	"4"
+#else
+	""
+#endif
+	); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
 cat >&2 <<EOF
 $0: unable to guess system type
 
diff --git a/config.sub b/config.sub
index d654d03..826e4c6 100755
--- a/config.sub
+++ b/config.sub
@@ -1,18 +1,24 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2014-05-01'
+timestamp='2012-10-10'
 
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
 # (at your option) any later version.
 #
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
@@ -20,12 +26,11 @@ timestamp='2014-05-01'
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program.  This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
+# the same distribution terms that you use for the rest of that program.
 
 
-# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -68,7 +73,9 @@ Report bugs and patches to <config-patches at gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -252,12 +259,10 @@ case $basic_machine in
 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
 	| am33_2.0 \
-	| arc | arceb \
-	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
-	| avr | avr32 \
-	| be32 | be64 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+        | be32 | be64 \
 	| bfin \
-	| c4x | c8051 | clipper \
+	| c4x | clipper \
 	| d10v | d30v | dlx | dsp16xx \
 	| epiphany \
 	| fido | fr30 | frv \
@@ -265,7 +270,6 @@ case $basic_machine in
 	| hexagon \
 	| i370 | i860 | i960 | ia64 \
 	| ip2k | iq2000 \
-	| k1om \
 	| le32 | le64 \
 	| lm32 \
 	| m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -283,22 +287,20 @@ case $basic_machine in
 	| mips64vr5900 | mips64vr5900el \
 	| mipsisa32 | mipsisa32el \
 	| mipsisa32r2 | mipsisa32r2el \
-	| mipsisa32r6 | mipsisa32r6el \
 	| mipsisa64 | mipsisa64el \
 	| mipsisa64r2 | mipsisa64r2el \
-	| mipsisa64r6 | mipsisa64r6el \
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sr71k | mipsisa64sr71kel \
-	| mipsr5900 | mipsr5900el \
 	| mipstx39 | mipstx39el \
 	| mn10200 | mn10300 \
 	| moxie \
 	| mt \
 	| msp430 \
 	| nds32 | nds32le | nds32be \
-	| nios | nios2 | nios2eb | nios2el \
+	| nios | nios2 \
 	| ns16k | ns32k \
-	| open8 | or1k | or1knd | or32 \
+	| open8 \
+	| or32 \
 	| pdp10 | pdp11 | pj | pjl \
 	| powerpc | powerpc64 | powerpc64le | powerpcle \
 	| pyramid \
@@ -326,7 +328,7 @@ case $basic_machine in
 	c6x)
 		basic_machine=tic6x-unknown
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
 		basic_machine=$basic_machine-unknown
 		os=-none
 		;;
@@ -368,13 +370,13 @@ case $basic_machine in
 	| aarch64-* | aarch64_be-* \
 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
 	| avr-* | avr32-* \
 	| be32-* | be64-* \
 	| bfin-* | bs2000-* \
 	| c[123]* | c30-* | [cjt]90-* | c4x-* \
-	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| clipper-* | craynv-* | cydra-* \
 	| d10v-* | d30v-* | dlx-* \
 	| elxsi-* \
 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
@@ -383,7 +385,6 @@ case $basic_machine in
 	| hexagon-* \
 	| i*86-* | i860-* | i960-* | ia64-* \
 	| ip2k-* | iq2000-* \
-	| k1om-* \
 	| le32-* | le64-* \
 	| lm32-* \
 	| m32c-* | m32r-* | m32rle-* \
@@ -403,22 +404,18 @@ case $basic_machine in
 	| mips64vr5900-* | mips64vr5900el-* \
 	| mipsisa32-* | mipsisa32el-* \
 	| mipsisa32r2-* | mipsisa32r2el-* \
-	| mipsisa32r6-* | mipsisa32r6el-* \
 	| mipsisa64-* | mipsisa64el-* \
 	| mipsisa64r2-* | mipsisa64r2el-* \
-	| mipsisa64r6-* | mipsisa64r6el-* \
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
-	| mipsr5900-* | mipsr5900el-* \
 	| mipstx39-* | mipstx39el-* \
 	| mmix-* \
 	| mt-* \
 	| msp430-* \
 	| nds32-* | nds32le-* | nds32be-* \
-	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| nios-* | nios2-* \
 	| none-* | np1-* | ns16k-* | ns32k-* \
 	| open8-* \
-	| or1k*-* \
 	| orion-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
@@ -800,7 +797,7 @@ case $basic_machine in
 		os=-mingw64
 		;;
 	mingw32)
-		basic_machine=i686-pc
+		basic_machine=i386-pc
 		os=-mingw32
 		;;
 	mingw32ce)
@@ -836,7 +833,7 @@ case $basic_machine in
 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
 		;;
 	msys)
-		basic_machine=i686-pc
+		basic_machine=i386-pc
 		os=-msys
 		;;
 	mvs)
@@ -1027,11 +1024,7 @@ case $basic_machine in
 		basic_machine=i586-unknown
 		os=-pw32
 		;;
-	rdos | rdos64)
-		basic_machine=x86_64-pc
-		os=-rdos
-		;;
-	rdos32)
+	rdos)
 		basic_machine=i386-pc
 		os=-rdos
 		;;
@@ -1358,7 +1351,7 @@ case $os in
 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
-	      | -sym* | -kopensolaris* | -plan9* \
+	      | -sym* | -kopensolaris* \
 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
 	      | -aos* | -aros* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
@@ -1380,7 +1373,7 @@ case $os in
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 	-qnx*)
@@ -1504,6 +1497,9 @@ case $os in
 	-aros*)
 		os=-aros
 		;;
+	-kaos*)
+		os=-kaos
+		;;
 	-zvmoe)
 		os=-zvmoe
 		;;
@@ -1552,9 +1548,6 @@ case $basic_machine in
 	c4x-* | tic4x-*)
 		os=-coff
 		;;
-	c8051-*)
-		os=-elf
-		;;
 	hexagon-*)
 		os=-elf
 		;;
diff --git a/configs/samples/acl.conf.sample b/configs/acl.conf.sample
similarity index 100%
rename from configs/samples/acl.conf.sample
rename to configs/acl.conf.sample
diff --git a/configs/samples/adsi.conf.sample b/configs/adsi.conf.sample
similarity index 100%
rename from configs/samples/adsi.conf.sample
rename to configs/adsi.conf.sample
diff --git a/configs/agents.conf.sample b/configs/agents.conf.sample
new file mode 100644
index 0000000..a2d6294
--- /dev/null
+++ b/configs/agents.conf.sample
@@ -0,0 +1,97 @@
+;
+; Agent configuration
+;
+
+[general]
+
+[agents]
+;
+; Define maxlogintries to allow agent to try max logins before
+; failed.
+; default to 3
+;
+;maxlogintries=5
+;
+;
+; Define autologoff times if appropriate.  This is how long
+; the phone has to ring with no answer before the agent is
+; automatically logged off (in seconds)
+;
+;autologoff=15
+;
+; Define autologoffunavail to have agents automatically logged
+; out when the extension that they are at returns a CHANUNAVAIL
+; status when a call is attempted to be sent there.
+; Default is "no".
+;
+;autologoffunavail=yes
+;
+; Define ackcall to require a DTMF acknowledgement when
+; a logged-in agent receives a call.  Default is "no".
+; Use the acceptdtmf option to configure what DTMF key
+; press should be used to acknowledge the call. The
+; default is '#'.
+;
+;ackcall=no
+;acceptdtmf=#
+;
+; Define endcall to allow an agent to hangup a call with a
+; DTMF keypress. Default is "yes". Use the enddtmf option to
+; configure which DTMF key will end a call. The default is
+; '*'.
+;
+;endcall=yes
+;enddtmf=*
+;
+; Define wrapuptime.  This is the minimum amount of time when
+; after disconnecting before the caller can receive a new call
+; note this is in milliseconds.
+;
+;wrapuptime=5000
+;
+; Define the default musiconhold for agents
+; musiconhold => music_class
+;
+;musiconhold => default
+;
+; Define updatecdr. This is whether or not to change the source
+; channel in the CDR record for this call to agent/agent_id so
+; that we know which agent generates the call
+;
+;updatecdr=no
+;
+; Group memberships for agents (may change in mid-file)
+;
+;group=3
+;group=1,2
+;group=
+;
+; --------------------------------------------------
+; This section is devoted to recording agent's calls
+; The keywords are global to the chan_agent channel driver
+;
+; Enable recording calls addressed to agents. It's turned off by default.
+;recordagentcalls=yes
+;
+; The format to be used to record the calls: wav, gsm, wav49.
+; By default its "wav".
+;recordformat=gsm
+;
+; The text to be added to the name of the recording. Allows forming a url link.
+;urlprefix=http://localhost/calls/
+;
+; The optional directory to save the conversations in. The default is
+; /var/spool/asterisk/monitor
+;savecallsin=/var/calls
+;
+; An optional custom beep sound file to play to always-connected agents.
+;custom_beep=beep
+;
+; --------------------------------------------------
+;
+; This section contains the agent definitions, in the form:
+;
+; agent => agentid,agentpassword,name
+;
+;agent => 1001,4321,Mark Spencer
+;agent => 1002,4321,Will Meadows
diff --git a/configs/samples/alarmreceiver.conf.sample b/configs/alarmreceiver.conf.sample
similarity index 89%
rename from configs/samples/alarmreceiver.conf.sample
rename to configs/alarmreceiver.conf.sample
index e4815a9..7964701 100644
--- a/configs/samples/alarmreceiver.conf.sample
+++ b/configs/alarmreceiver.conf.sample
@@ -60,17 +60,6 @@ fdtimeout = 2000
 sdtimeout = 200
 
 ;
-; Wait for the connection to settle post-answer. Adjustable from 500 msec. to 10000 msec.
-; The default is 1250 msec.
-;
-
-answait = 1250
-
-; When logging individual events it may be desirable to skip grouping of metadata
-
-;no_group_meta = yes
-
-;
 ; The loudness of the ACK and Kissoff tones is adjustable from 100 to 8192.
 ; The default is 8192. This shouldn't need to be messed with, but is included
 ; just in case there are problems with signal levels.
diff --git a/configs/samples/alsa.conf.sample b/configs/alsa.conf.sample
similarity index 100%
rename from configs/samples/alsa.conf.sample
rename to configs/alsa.conf.sample
diff --git a/configs/samples/amd.conf.sample b/configs/amd.conf.sample
similarity index 90%
rename from configs/samples/amd.conf.sample
rename to configs/amd.conf.sample
index ce4808a..c4a5907 100644
--- a/configs/samples/amd.conf.sample
+++ b/configs/amd.conf.sample
@@ -15,4 +15,5 @@ between_words_silence = 50	; Minimum duration of silence after a word to conside
 				; the audio what follows as a new word
 maximum_number_of_words = 3	; Maximum number of words in the greeting.
 				; If exceeded then MACHINE
+maximum_word_length = 5000  ; Maximum duration of a single Voice utterance allowed.
 silence_threshold = 256
diff --git a/configs/samples/app_mysql.conf.sample b/configs/app_mysql.conf.sample
similarity index 100%
rename from configs/samples/app_mysql.conf.sample
rename to configs/app_mysql.conf.sample
diff --git a/configs/samples/app_skel.conf.sample b/configs/app_skel.conf.sample
similarity index 100%
rename from configs/samples/app_skel.conf.sample
rename to configs/app_skel.conf.sample
diff --git a/configs/samples/asterisk.adsi b/configs/asterisk.adsi
similarity index 100%
rename from configs/samples/asterisk.adsi
rename to configs/asterisk.adsi
diff --git a/configs/samples/asterisk.conf.sample b/configs/asterisk.conf.sample
similarity index 97%
rename from configs/samples/asterisk.conf.sample
rename to configs/asterisk.conf.sample
index e4883ec..ddedcb9 100644
--- a/configs/samples/asterisk.conf.sample
+++ b/configs/asterisk.conf.sample
@@ -87,7 +87,7 @@ documentation_language = en_US	; Set the language you want documentation
 				; etc.) These functions (such as SHELL) are
 				; considered dangerous because they can allow
 				; privilege escalation.
-				; Default no
+				; Default yes, for backward compatability.
 
 ; Changing the following lines may compromise your security.
 ;[files]
@@ -95,3 +95,8 @@ documentation_language = en_US	; Set the language you want documentation
 ;astctlowner = root
 ;astctlgroup = apache
 ;astctl = asterisk.ctl
+
+[compat]
+pbx_realtime=1.6
+res_agi=1.6
+app_set=1.6
diff --git a/configs/samples/calendar.conf.sample b/configs/calendar.conf.sample
similarity index 100%
rename from configs/samples/calendar.conf.sample
rename to configs/calendar.conf.sample
diff --git a/configs/samples/ccss.conf.sample b/configs/ccss.conf.sample
similarity index 100%
rename from configs/samples/ccss.conf.sample
rename to configs/ccss.conf.sample
diff --git a/configs/samples/cdr.conf.sample b/configs/cdr.conf.sample
similarity index 87%
rename from configs/samples/cdr.conf.sample
rename to configs/cdr.conf.sample
index 2c7cdf6..c1c00f7 100644
--- a/configs/samples/cdr.conf.sample
+++ b/configs/cdr.conf.sample
@@ -13,13 +13,20 @@
 ; any loading of backend CDR modules.  Default is "yes".
 ;enable=yes
 
-; Define whether or not to log unanswered calls that don't involve an outgoing
-; party. Setting this to "yes" will make calls to extensions that don't answer
-; and don't set a B side channel (such as by using the Dial application)
-; receive CDR log entries. If this option is set to "no", then those log
-; entries will not be created. Unasnwered Calls which get offered to an
-; outgoing line will always receive log entries regardless of this option, and
-; that is the intended behaviour.
+; Define whether or not to log unanswered calls. Setting this to "yes" will
+; report every attempt to ring a phone in dialing attempts, when it was not
+; answered. For example, if you try to dial 3 extensions, and this option is "yes",
+; you will get 3 CDR's, one for each phone that was rung. Default is "no". Some
+; find this information horribly useless. Others find it very valuable. Note, in "yes"
+; mode, you will see one CDR, with one of the call targets on one side, and the originating
+; channel on the other, and then one CDR for each channel attempted. This may seem
+; redundant, but cannot be helped.
+;
+; In brief, this option controls the reporting of unanswered calls which only have an A 
+; party. Calls which get offered to an outgoing line, but are unanswered, are still 
+; logged, and that is the intended behaviour. (It also results in some B side CDRs being
+; output, as they have the B side channel as their source channel, and no destination 
+; channel.)
 ;unanswered = no
 
 ; Define whether or not to log congested calls. Setting this to "yes" will
@@ -154,6 +161,8 @@ usegmtime=yes    ; log date/time in GMT.  Default is "no"
 loguniqueid=yes  ; log uniqueid.  Default is "no"
 loguserfield=yes ; log user field.  Default is "no"
 accountlogs=yes  ; create separate log file for each account code. Default is "yes"
+;newcdrcolumns=yes ; Enable logging of post-1.8 CDR columns (peeraccount, linkedid, sequence).
+                   ; Default is "no".
 
 ;[radius]
 ;usegmtime=yes    ; log date/time in GMT
diff --git a/configs/samples/cdr_adaptive_odbc.conf.sample b/configs/cdr_adaptive_odbc.conf.sample
similarity index 100%
rename from configs/samples/cdr_adaptive_odbc.conf.sample
rename to configs/cdr_adaptive_odbc.conf.sample
diff --git a/configs/samples/cdr_custom.conf.sample b/configs/cdr_custom.conf.sample
similarity index 100%
rename from configs/samples/cdr_custom.conf.sample
rename to configs/cdr_custom.conf.sample
diff --git a/configs/samples/cdr_manager.conf.sample b/configs/cdr_manager.conf.sample
similarity index 100%
rename from configs/samples/cdr_manager.conf.sample
rename to configs/cdr_manager.conf.sample
diff --git a/configs/samples/cdr_mysql.conf.sample b/configs/cdr_mysql.conf.sample
similarity index 100%
rename from configs/samples/cdr_mysql.conf.sample
rename to configs/cdr_mysql.conf.sample
diff --git a/configs/samples/cdr_odbc.conf.sample b/configs/cdr_odbc.conf.sample
similarity index 73%
rename from configs/samples/cdr_odbc.conf.sample
rename to configs/cdr_odbc.conf.sample
index 93bd6ff..663ce09 100644
--- a/configs/samples/cdr_odbc.conf.sample
+++ b/configs/cdr_odbc.conf.sample
@@ -9,3 +9,4 @@
 ;table=cdr		;"cdr" is default table name
 ;usegmtime=no             ; set to "yes" to log in GMT
 ;hrtime=yes		;Enables microsecond accuracy with the billsec and duration fields
+;newcdrcolumns=yes ; Enable logging of post-1.8 CDR columns (peeraccount, linkedid, sequence)
diff --git a/configs/samples/cdr_pgsql.conf.sample b/configs/cdr_pgsql.conf.sample
similarity index 84%
rename from configs/samples/cdr_pgsql.conf.sample
rename to configs/cdr_pgsql.conf.sample
index c5a989f..7a90910 100644
--- a/configs/samples/cdr_pgsql.conf.sample
+++ b/configs/cdr_pgsql.conf.sample
@@ -10,7 +10,6 @@
 ;dbname=asterisk
 ;password=password
 ;user=postgres
-;appname=asterisk    ; Postgres application_name support (optional). Whitespace not allowed.
 ;table=cdr		;SQL table where CDRs will be inserted
 ;encoding=LATIN9	; Encoding of logged characters in Asterisk
 ;timezone=UTC		; Uncomment if you want datetime fields in UTC/GMT
diff --git a/configs/samples/cdr_sqlite3_custom.conf.sample b/configs/cdr_sqlite3_custom.conf.sample
similarity index 100%
rename from configs/samples/cdr_sqlite3_custom.conf.sample
rename to configs/cdr_sqlite3_custom.conf.sample
diff --git a/configs/samples/cdr_syslog.conf.sample b/configs/cdr_syslog.conf.sample
similarity index 100%
rename from configs/samples/cdr_syslog.conf.sample
rename to configs/cdr_syslog.conf.sample
diff --git a/configs/samples/cdr_tds.conf.sample b/configs/cdr_tds.conf.sample
similarity index 100%
rename from configs/samples/cdr_tds.conf.sample
rename to configs/cdr_tds.conf.sample
diff --git a/configs/samples/cel.conf.sample b/configs/cel.conf.sample
similarity index 78%
rename from configs/samples/cel.conf.sample
rename to configs/cel.conf.sample
index d92e274..7bd7f89 100644
--- a/configs/samples/cel.conf.sample
+++ b/configs/cel.conf.sample
@@ -45,25 +45,35 @@ apps=dial,park
 ;  CHAN_END         -- The time a channel was terminated
 ;  ANSWER           -- The time a channel was answered (ie, phone taken off-hook)
 ;  HANGUP           -- The time at which a hangup occurred
-;  BRIDGE_ENTER       -- The time a channel was connected into a conference room
-;  BRIDGE_EXIT        -- The time a channel was removed from a conference room
+;  CONF_ENTER       -- The time a channel was connected into a conference room
+;  CONF_EXIT        -- The time a channel was removed from a conference room
+;  CONF_START       -- The time the first person enters a conference room
+;  CONF_END         -- The time the last person left a conference room (and
+;                      turned out the lights?)
 ;  APP_START        -- The time a tracked application was started
 ;  APP_END          -- the time a tracked application ended
 ;  PARK_START       -- The time a call was parked
 ;  PARK_END         -- Unpark event
+;  BRIDGE_START     -- The time a bridge is started
+;  BRIDGE_END       -- The time a bridge is ended
+;  BRIDGE_UPDATE    -- This is a replacement channel (Masquerade)
+;  3WAY_START       -- When a 3-way conference starts (usually via attended transfer)
+;  3WAY_END         -- When one or all exit a 3-way conference
 ;  BLINDTRANSFER    -- When a blind transfer is initiated
 ;  ATTENDEDTRANSFER -- When an attended transfer is initiated
-;  PICKUP           -- This channel picked up the specified channel
+;  TRANSFER         -- Generic transfer initiated; not used yet...?
+;  PICKUP           -- This channel picked up the peer channel
 ;  FORWARD          -- This channel is being forwarded somewhere else
+;  HOOKFLASH        -- So far, when a hookflash event occurs on a DAHDI
+;                      interface
 ;  LINKEDID_END     -- The last channel with the given linkedid is retired
 ;  USER_DEFINED     -- Triggered from the dialplan, and has a name given by the
 ;                      user
-;  LOCAL_OPTIMIZE   -- A local channel pair is optimizing away.
 ;
 ; Default value: none
 ;                (Track no events)
 
-events=APP_START,CHAN_START,CHAN_END,ANSWER,HANGUP,BRIDGE_ENTER,BRIDGE_EXIT
+events=APP_START,CHAN_START,CHAN_END,ANSWER,HANGUP,BRIDGE_START,BRIDGE_END
 
 ; Date Format
 ;
diff --git a/configs/samples/cel_custom.conf.sample b/configs/cel_custom.conf.sample
similarity index 100%
rename from configs/samples/cel_custom.conf.sample
rename to configs/cel_custom.conf.sample
diff --git a/configs/samples/cel_odbc.conf.sample b/configs/cel_odbc.conf.sample
similarity index 100%
rename from configs/samples/cel_odbc.conf.sample
rename to configs/cel_odbc.conf.sample
diff --git a/configs/samples/cel_pgsql.conf.sample b/configs/cel_pgsql.conf.sample
similarity index 93%
rename from configs/samples/cel_pgsql.conf.sample
rename to configs/cel_pgsql.conf.sample
index 2298b2d..cc9b9ff 100644
--- a/configs/samples/cel_pgsql.conf.sample
+++ b/configs/cel_pgsql.conf.sample
@@ -65,4 +65,3 @@
 ;password=password
 ;user=postgres
 ;table=cel		;SQL table where CEL's will be inserted
-;appname=asterisk   ; Postgres application_name support (optional). Whitespace not allowed.
\ No newline at end of file
diff --git a/configs/samples/cel_sqlite3_custom.conf.sample b/configs/cel_sqlite3_custom.conf.sample
similarity index 100%
rename from configs/samples/cel_sqlite3_custom.conf.sample
rename to configs/cel_sqlite3_custom.conf.sample
diff --git a/configs/samples/cel_tds.conf.sample b/configs/cel_tds.conf.sample
similarity index 100%
rename from configs/samples/cel_tds.conf.sample
rename to configs/cel_tds.conf.sample
diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/chan_dahdi.conf.sample
similarity index 91%
rename from configs/samples/chan_dahdi.conf.sample
rename to configs/chan_dahdi.conf.sample
index 13691fc..51f6daf 100644
--- a/configs/samples/chan_dahdi.conf.sample
+++ b/configs/chan_dahdi.conf.sample
@@ -196,6 +196,22 @@ context=public
 ;
 ;resetinterval = 3600
 ;
+; Enable per ISDN span to force a RESTART on a channel that returns a cause
+; code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If this option is enabled
+; and the reason the peer rejected the call with cause 44 was that the
+; channel is stuck in an unavailable state on the peer, then this might
+; help release the channel.  It is worth noting that the next outgoing call
+; Asterisk makes will likely try the same channel again.
+;
+; NOTE: Sending a RESTART in response to a cause 44 is not required
+; (nor prohibited) by the standards and is likely a primitive chan_dahdi
+; response to call collisions (glare) and buggy peers.  However, there
+; are telco switches out there that ignore the RESTART and continue to
+; send calls to the channel in the restarting state.
+; Default yes in current release branches for backward compatibility.
+;
+;force_restart_unavailable_chans=yes
+;
 ; Assume inband audio may be present when a SETUP ACK message is received.
 ; Q.931 Section 5.1.3 says that in scenarios with overlap dialing, when a
 ; dialtone is sent from the network side, progress indicator 8 "Inband info
@@ -209,7 +225,7 @@ context=public
 ; NOTE: For Q.SIG setups this option should be enabled when outgoing overlap
 ; dialing is also enabled because Q.SIG does not send the progress indicator
 ; with the SETUP ACK.
-; Default no.
+; Default yes in current release branches for backward compatibility.
 ;
 ;inband_on_setup_ack=yes
 ;
@@ -221,7 +237,7 @@ context=public
 ; without the progress indicator ie indicating inband audio is available and
 ; assume that the CPE device has connected the media path for listening to
 ; ringback and other messages.
-; Default no.
+; Default yes in current release branches for backward compatibility.
 ;
 ;inband_on_proceeding=yes
 ;
@@ -634,11 +650,8 @@ usecallerid=yes
 ;
 ; This option is used in conjunction with mwimonitor.  This will get executed
 ; when incoming MWI state changes.  The script is passed 2 arguments.  The
-; first is the corresponding configured mailbox, and the second is 1 or 0,
-; indicating if there are messages waiting or not.
-; Note: app_voicemail mailboxes are in the form of mailbox at context.
-;
-; /usr/local/bin/dahdinotify.sh 501 at mailboxes 1
+; first is the corresponding mailbox, and the second is 1 or 0, indicating if
+; there are messages waiting or not.
 ;
 ;mwimonitornotify=/usr/local/bin/dahdinotify.sh
 ;
@@ -674,24 +687,11 @@ callwaiting=yes
 ; Configure the ISDN span to indicate MWI for the list of mailboxes.
 ; You can give a comma separated list of up to 8 mailboxes per span.
 ; An empty list disables MWI.
-;
 ; The default is an empty list.
-;mwi_mailboxes=vm-mailbox{,vm-mailbox}
-;  vm-mailbox = Internal voicemail mailbox identifier.
-;  Note: app_voicemail mailboxes must be in the form of mailbox at context.
-;mwi_mailboxes=501 at mailboxes,502 at mailboxes
-
-; Configure the ISDN mailbox number sent over the span for MWI mailboxes.
-; The position of the number in the list corresponds to the position in
-; mwi_mailboxes.  If either position in mwi_mailboxes or mwi_vm_boxes is
-; empty then that position is disabled.
+;mwi_mailboxes=mailbox_number[@context]{,mailbox_number[@context]}
 ;
-; The default is an empty list.
-;mwi_vm_boxes=mailbox_number{,mailbox_number}
-;mwi_vm_boxes=501,502
-
-; Configure the ISDN span voicemail controlling numbers for MWI mailboxes.
-; What number to call for a user to retrieve voicemail messages.
+; Configure the ISDN span voicemail numbers for MWI mailboxes.  What number
+; to call for a user to retrieve voicemail messages.
 ;
 ; You can give a comma separated list of numbers.  The position of the number
 ; corresponds to the position in mwi_mailboxes.  If a position is empty then
@@ -700,7 +700,7 @@ callwaiting=yes
 ; For example:
 ;  mwi_vm_numbers=700,,800,,900
 ; is equivalent to:
-;  mwi_vm_numbers=700,700,800,800,900,900,900,900
+;  mwi_vm_numbers=700,700,800,800,900
 ;
 ; The default is no number.
 ;mwi_vm_numbers=
@@ -770,11 +770,19 @@ cancallforward=yes
 ;
 callreturn=yes
 ;
-; Stutter dialtone support: If voicemail is received in the mailbox then
-; taking the phone off hook will cause a stutter dialtone instead of a
-; normal one.
+; Stutter dialtone support: If a mailbox is specified without a voicemail
+; context, then when voicemail is received in a mailbox in the default
+; voicemail context in voicemail.conf, taking the phone off hook will cause a
+; stutter dialtone instead of a normal one.
+;
+; If a mailbox is specified *with* a voicemail context, the same will result
+; if voicemail received in mailbox in the specified voicemail context.
+;
+; for default voicemail context, the example below is fine:
 ;
-; Note: app_voicemail mailboxes must be in the form of mailbox at context.
+;mailbox=1234
+;
+; for any other voicemail context, the following will produce the stutter tone:
 ;
 ;mailbox=1234 at context
 ;
@@ -833,53 +841,31 @@ echocancelwhenbridged=yes
 ;
 ;relaxdtmf=yes
 ;
-; Hardware gain settings increase/decrease the analog volume level on a channel.
-;   The values are in db (decibels) and can be adjusted in 0.1 dB increments.
-;   A positive number increases the volume level on a channel, and a negavive
-;   value decreases volume level.
-;
-;   Hardware gain settings are only possible on hardware with analog ports
-;   because the gain is done on the analog side of the analog/digital conversion.
-;
-;   When hardware gains are disabled, Asterisk will NOT touch the gain setting
-;   already configured in hardware.
-;
-;   hwrxgain: Hardware receive gain for the channel (into Asterisk).
-;             Default: disabled
-;   hwtxgain: Hardware transmit gain for the channel (out of Asterisk).
-;             Default: disabled
-;
-;hwrxgain=disabled
-;hwtxgain=disabled
-;hwrxgain=2.0
-;hwtxgain=3.0
-;
-; Software gain settings digitally increase/decrease the volume level on a channel.
-;   The values are in db (decibels).  A positive number increases the volume
-;   level on a channel, and a negavive value decreases volume level.
-;
-;   Software gains work on the digital side of the analog/digital conversion
-;   and thus can also work with T1/E1 cards.
-;
-;   rxgain: Software receive gain for the channel (into Asterisk). Default: 0.0
-;   txgain: Software transmit gain for the channel (out of Asterisk).
-;             Default: 0.0
-;
-;   cid_rxgain: Add this gain to rxgain when Asterisk expects to receive
-;               a Caller ID stream.
-;               Default: 5.0 .
-;
-;rxgain=2.0
-;txgain=3.0
-;
-; Dynamic Range Compression: You can also enable dynamic range compression
-;   on a channel.  This will digitally amplify quiet sounds while leaving louder
-;   sounds untouched.  This is useful in situations where a linear gain setting
-;   would cause clipping.  Acceptable values are in the range of 0.0 to around
-;   6.0 with higher values causing more compression to be done.
-;
+; You may also set the default receive and transmit gains (in dB)
+;
+; Gain Settings: increasing / decreasing the volume level on a channel.
+;                The values are in db (decibells). A positive number
+;                increases the volume level on a channel, and a
+;                negavive value decreases volume level.
+;
+; Dynamic Range Compression: you can also enable dynamic range compression
+;                on a channel. This will amplify quiet sounds while leaving
+;                louder sounds untouched. This is useful in situations where
+;                a linear gain setting would cause clipping. Acceptable values
+;                are in the range of 0.0 to around 6.0 with higher values
+;                causing more compression to be done.
+;
+;                There are several independent gain settings:
+;   rxgain: gain for the rx (receive - into Asterisk) channel. Default: 0.0
+;   txgain: gain for the tx (transmit - out of Asterisk Asterisk) channel.
+;           Default: 0.0
+;   cid_rxgain: set the gain just for the caller ID sounds Asterisk
+;               emits. Default: 5.0 .
 ;   rxdrc: dynamic range compression for the rx channel. Default: 0.0
 ;   txdrc: dynamic range compression for the tx channel. Default: 0.0
+
+;rxgain=2.0
+;txgain=3.0
 ;
 ;rxdrc=1.0
 ;txdrc=4.0
@@ -911,13 +897,12 @@ pickupgroup=1
 ;namedcallgroup=engineering,sales,netgroup,protgroup
 ;namedpickupgroup=sales
 
-; Channel variables to be set for all calls from this channel
+; Channel variable to be set for all calls from this channel
 ;setvar=CHANNEL=42
 ;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep   ; This channel variable will
                                                 ; cause the given audio file to
                                                 ; be played upon completion of
-                                                ; an attended transfer to the
-                                                ; target of the transfer.
+                                                ; an attended transfer.
 
 ;
 ; Specify whether the channel should be answered immediately or if the simple
@@ -1184,11 +1169,12 @@ pickupgroup=1
 ;
 ;
 ; ignore_failed_channels: Continue even if some channels failed to configure.
-; True by default. Disable this if you can guarantee that DAHDI starts before
-; Asterisk and want to be sure chan_dahdi will not start with broken
-; configuration.
-;
-;ignore_failed_channels = false
+; False by default, as if even a single channel failed to configure, it might
+; mean other channels are misplaced and having them work may not be a good
+; idea. If enabled (set to true), chan_dahdi will nevertheless attempt to
+; configure other channels rather than giving up. This normally makes sense
+; only if you use names (<subdir>!<number>) for DAHDI channels.
+;ignore_failed_channels = true
 ;
 ; Configure jitter buffers in DAHDI (each one is 20ms, default is 4)
 ; This is set globally, rather than per-channel.
@@ -1388,35 +1374,12 @@ pickupgroup=1
 
 ; This option is used to disable automatic sending of ACM when the call is started
 ; in the dialplan.  If you do use this option, you will need to use the Proceeding()
-; application in the dialplan to send ACM or enable ss7_autoacm below.
-;ss7_explicitacm=yes
-
-; Use this option to automatically send ACM when the call rings or is answered and
-; has not seen proceeding yet. If you use this option, you should disable ss7_explicitacm.
-; You may still use Proceeding() to explicitly send an ACM from the dialplan.
-;ss7_autoacm=yes
-
-; Create the linkset with all CICs in hardware remotely blocked state.
-;ss7_initialhwblo=yes
-
-; This option is whether or not to trust the remote echo control indication.  This means
-; that in cases where echo control is reported by the remote end, we will trust them and
-; not enable echo cancellation on the call.
-;ss7_use_echocontrol=yes
-
-; This option is to set what our echo control indication is to the other end.  Set to
-; yes to indicate that we are using echo cancellation or no if we are not.
-;ss7_default_echocontrol=yes
+; application in the dialplan to send ACM.
+;ss7_explictacm=yes
 
 ; All settings apply to linkset 1
 ;linkset = 1
 
-; Set the Signaling Link Code (SLC) for each sigchan.
-; If you manually set any you need to manually set all.
-; Should be defined before sigchan.
-; The default SLC starts with zero and increases for each defined sigchan.
-;slc=
-
 ; Point code of the linkset.  For ITU, this is the decimal number
 ; format of the point code.  For ANSI, this can either be in decimal
 ; number format or in the xxx-xxx-xxx format
@@ -1450,30 +1413,6 @@ pickupgroup=1
 ; Channels to associate with CICs on this linkset
 ;channel = 25-47
 ;
-
-; Set this option if you wish to send an Information Request Message (INR) request
-; if no calling party number is specified. This will attempt to tell the other end
-; to send it anyways. Should be defined after sigchan.
-;inr_if_no_calling=yes
-
-; Set this to set whether or not the originating access is (non) ISDN in the forward and
-; backward call indicators. Should be defined after sigchan
-;non_isdn_access=yes
-
-; This sets the number of binary places to shift the CIC when doing load balancing between
-; sigchans on a linkset. Should be defined after sigchan. Default 0
-;sls_shift = 0
-
-; Send custom cause_location value
-; Should be defined after sigchan. Default 1 (private local)
-;cause_location=1
-
-; SS7 timers (ISUP and MTP3) should be explicitly defined for each linkset to be used.
-; For a full list of supported timers and their default values (applicable for both ITU
-; and ANSI) see ss7.timers
-; Should be defined after sigchan
-;#include ss7.timers
-
 ; For more information on setting up SS7, see the README file in libss7 or
 ; https://wiki.asterisk.org/wiki/display/AST/Signaling+System+Number+7
 ; ----------------- SS7 Options ----------------------------------------
diff --git a/configs/samples/chan_mobile.conf.sample b/configs/chan_mobile.conf.sample
similarity index 100%
rename from configs/samples/chan_mobile.conf.sample
rename to configs/chan_mobile.conf.sample
diff --git a/configs/samples/cli.conf.sample b/configs/cli.conf.sample
similarity index 100%
rename from configs/samples/cli.conf.sample
rename to configs/cli.conf.sample
diff --git a/configs/samples/cli_aliases.conf.sample b/configs/cli_aliases.conf.sample
similarity index 91%
rename from configs/samples/cli_aliases.conf.sample
rename to configs/cli_aliases.conf.sample
index adaed90..34a34ee 100644
--- a/configs/samples/cli_aliases.conf.sample
+++ b/configs/cli_aliases.conf.sample
@@ -10,8 +10,8 @@
 ; the first alias defined will win.
 ;
 template = friendly		; By default, include friendly aliases
-;template = asterisk_1dot2	; Asterisk 1.2 style syntax
-;template = asterisk_1dot4	; Asterisk 1.4 style syntax
+;template = asterisk12		; Asterisk 1.2 style syntax
+;template = asterisk14		; Asterisk 1.4 style syntax
 ;template = individual_custom	; see [individual_custom] example below which
 				; includes a list of aliases from an external
 				; file
@@ -28,7 +28,6 @@ originate=channel originate
 help=core show help
 pri intense debug span=pri set debug intense span
 reload=module reload
-pjsip reload=module reload res_pjsip.so res_pjsip_authenticator_digest.so res_pjsip_endpoint_identifier_ip.so res_pjsip_mwi.so res_pjsip_notify.so res_pjsip_outbound_publish.so res_pjsip_publish_asterisk.so res_pjsip_outbound_registration.so
 
 ; CLI Alias Templates
 ; -------------------
@@ -42,7 +41,7 @@ pjsip reload=module reload res_pjsip.so res_pjsip_authenticator_digest.so res_pj
 ;
 ;die die die=stop now
 
-;[asterisk_1dot6](asterisk)
+;[asterisk16](asterisk)
 ; Alias for making voicemail reload actually do module reload app_voicemail.so
 ;voicemail reload=module reload app_voicemail.so
 ; This will make the CLI command "mr" behave as though it is "module reload".
@@ -74,7 +73,7 @@ pjsip reload=module reload res_pjsip.so res_pjsip_authenticator_digest.so res_pj
 ; if you would like to use the Asterisk 1.2 style syntax, define in the
 ; [general] section
 
-[asterisk_1dot2_tpl](!)
+[asterisk12_tpl](!)
 show channeltypes=core show channeltypes
 show channeltype=core show channeltype
 show manager command=manager show command
@@ -156,11 +155,11 @@ show profile=core show profile
 clear profile=core clear profile
 soft hangup=channel request hangup
 
-[asterisk_1dot2](asterisk_1dot2_tpl)
+[asterisk12](asterisk12_tpl)
 ; add any additional custom commands you want below here, for example:
 ;die quickly=stop now
 
-[asterisk_1dot4_tpl](!)
+[asterisk14_tpl](!)
 cdr status=cdr show status
 rtp debug=rtp set debug on
 rtcp debug=rtcp set debug on
@@ -185,10 +184,10 @@ restart gracefully=core restart gracefully
 restart when convenient=core restart when convenient
 soft hangup=channel request hangup
 
-[asterisk_1dot4](asterisk_1dot4_tpl)
+[asterisk14](asterisk14_tpl)
 ; add any additional custom commands you want below here.
 
-[asterisk_11_tpl](!)
+[asterisk11_tpl](!)
 jabber list nodes=xmpp list nodes
 jabber purge nodes=xmpp purge nodes
 jabber delete node=xmpp delete node
@@ -197,7 +196,6 @@ jabber create leaf=xmpp create leaf
 jabber set debug=xmpp set debug
 jabber show connections=xmpp show connections
 jabber show buddies=xmpp show buddies
-features reload=module reload features
 
-[asterisk_11](asterisk_11_tpl)
+[asterisk11](asterisk11_tpl)
 ; add any additional custom commands you want below here.
diff --git a/configs/samples/cli_permissions.conf.sample b/configs/cli_permissions.conf.sample
similarity index 100%
rename from configs/samples/cli_permissions.conf.sample
rename to configs/cli_permissions.conf.sample
diff --git a/configs/samples/codecs.conf.sample b/configs/codecs.conf.sample
similarity index 100%
rename from configs/samples/codecs.conf.sample
rename to configs/codecs.conf.sample
diff --git a/configs/samples/confbridge.conf.sample b/configs/confbridge.conf.sample
similarity index 98%
rename from configs/samples/confbridge.conf.sample
rename to configs/confbridge.conf.sample
index 860f1cb..9e90e61 100644
--- a/configs/samples/confbridge.conf.sample
+++ b/configs/confbridge.conf.sample
@@ -128,11 +128,6 @@ type=user
                          ; name when entering the conference.  After the name is
                          ; recorded, it will be played as the user enters and exists
                          ; the conference. This option is off by default.
-;announce_join_leave_review=yes ; When enabled, implies announce_join_leave, but the user
-                                ; will be prompted to review their recording before
-                                ; entering the conference. During this phase, the recording
-                                ; may be listened to, re-recorded, or accepted as is. This
-                                ; option is off by default.
 ;dtmf_passthrough=yes  ; Sets whether or not DTMF should pass through the conference.
                        ; This option is off by default.
 ;announcement=</path/to/file> ; Play a sound file to the user when they join the conference.
diff --git a/configs/samples/config_test.conf.sample b/configs/config_test.conf.sample
similarity index 100%
rename from configs/samples/config_test.conf.sample
rename to configs/config_test.conf.sample
diff --git a/configs/samples/console.conf.sample b/configs/console.conf.sample
similarity index 100%
rename from configs/samples/console.conf.sample
rename to configs/console.conf.sample
diff --git a/configs/samples/dbsep.conf.sample b/configs/dbsep.conf.sample
similarity index 100%
rename from configs/samples/dbsep.conf.sample
rename to configs/dbsep.conf.sample
diff --git a/configs/samples/dnsmgr.conf.sample b/configs/dnsmgr.conf.sample
similarity index 100%
rename from configs/samples/dnsmgr.conf.sample
rename to configs/dnsmgr.conf.sample
diff --git a/configs/samples/dsp.conf.sample b/configs/dsp.conf.sample
similarity index 100%
rename from configs/samples/dsp.conf.sample
rename to configs/dsp.conf.sample
diff --git a/configs/samples/dundi.conf.sample b/configs/dundi.conf.sample
similarity index 100%
rename from configs/samples/dundi.conf.sample
rename to configs/dundi.conf.sample
diff --git a/configs/samples/enum.conf.sample b/configs/enum.conf.sample
similarity index 100%
rename from configs/samples/enum.conf.sample
rename to configs/enum.conf.sample
diff --git a/configs/samples/extconfig.conf.sample b/configs/extconfig.conf.sample
similarity index 93%
rename from configs/samples/extconfig.conf.sample
rename to configs/extconfig.conf.sample
index 8fb6cac..5f9ee21 100644
--- a/configs/samples/extconfig.conf.sample
+++ b/configs/extconfig.conf.sample
@@ -15,7 +15,7 @@
 ; database driver, database and table (or uses the
 ; name of the file as the table if not specified)
 ;
-; Uncomment to load queues.conf via the odbc engine.
+;uncomment to load queues.conf via the odbc engine.
 ;
 ;queues.conf => odbc,asterisk,ast_config
 ;extensions.conf => sqlite,asterisk,ast_config
@@ -65,7 +65,6 @@
 ; engine.  Here are several of the possible options:
 ;    odbc ... res_config_odbc
 ;    sqlite ... res_config_sqlite
-;    sqlite3 ... res_config_sqlite3
 ;    pgsql ... res_config_pgsql
 ;    curl ... res_config_curl
 ;    ldap ... res_config_ldap
@@ -79,17 +78,11 @@
 ;iaxpeers => odbc,asterisk
 ;sippeers => odbc,asterisk
 ;sipregs => odbc,asterisk ; (avoid sipregs if possible, e.g. by using a view)
-;ps_endpoints => odbc,asterisk
-;ps_auths => odbc,asterisk
-;ps_aors => odbc,asterisk
-;ps_domain_aliases => odbc,asterisk
-;ps_endpoint_id_ips => odbc,asterisk
 ;voicemail => odbc,asterisk
 ;extensions => odbc,asterisk
 ;meetme => mysql,general
 ;queues => odbc,asterisk
 ;queue_members => odbc,asterisk
-;queue_rules => odbc,asterisk
 ;acls => odbc,asterisk
 ;musiconhold => mysql,general
 ;queue_log => mysql,general
diff --git a/configs/samples/extensions.ael.sample b/configs/extensions.ael.sample
similarity index 100%
rename from configs/samples/extensions.ael.sample
rename to configs/extensions.ael.sample
diff --git a/configs/samples/extensions.conf.sample b/configs/extensions.conf.sample
similarity index 99%
rename from configs/samples/extensions.conf.sample
rename to configs/extensions.conf.sample
index f8770c5..34f25c0 100644
--- a/configs/samples/extensions.conf.sample
+++ b/configs/extensions.conf.sample
@@ -708,16 +708,17 @@ include => demo
 ;exten => 6600,hint,park:701 at parkedcalls
 ;exten => 6600,1,noop
 ;
-;To subscribe to the availability of a free member in the 'markq' queue.
-;Note: '_avail' is added to the QueueName
-;exten => 8501,hint,Queue:markq_avail
-;exten => 8501,1,Queue(markq)
-;
 ; You can also monitor the status of a queue by providing a hint for a
 ; particular queue name.
 ;exten => 8502,hint,Queue:markq
 ;exten => 8502,1,Queue(markq)
 ;
+
+;To subscribe to the availability of a free member in the 'markq' queue.
+;Note: '_avail' is added to the QueueName
+;exten => 8501,hint,Queue:markq_avail
+;exten => 8501,1,Queue(markq)
+
 ; Some other handy things are an extension for checking voicemail via
 ; voicemailmain
 ;
diff --git a/configs/samples/extensions.lua.sample b/configs/extensions.lua.sample
similarity index 100%
rename from configs/samples/extensions.lua.sample
rename to configs/extensions.lua.sample
diff --git a/configs/samples/extensions_minivm.conf.sample b/configs/extensions_minivm.conf.sample
similarity index 99%
rename from configs/samples/extensions_minivm.conf.sample
rename to configs/extensions_minivm.conf.sample
index 832e1d2..2f9d246 100644
--- a/configs/samples/extensions_minivm.conf.sample
+++ b/configs/extensions_minivm.conf.sample
@@ -1,6 +1,6 @@
 ; MINI-VOICEMAIL dialplan example
 ; ---------------------------------------------------------------------------------------
-; ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418870 $")
+; ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 ;
 ;
 ; This is an example on how to use the Mini-Voicemail system to build
diff --git a/configs/features.conf.sample b/configs/features.conf.sample
new file mode 100644
index 0000000..ed069dd
--- /dev/null
+++ b/configs/features.conf.sample
@@ -0,0 +1,238 @@
+;
+; Sample Call Features (parking, transfer, etc) configuration
+;
+
+[general]
+
+; OPTIONS THAT CAN ONLY BE SET IN THE GENERAL CONTEXT
+
+;featuredigittimeout = 1000     ; Max time (ms) between digits for
+                                ; feature activation  (default is 1000 ms)
+
+; Pickup Options
+;
+;pickupexten = *8               ; Configure the pickup extension. (default is *8)
+;pickupsound = beep             ; to indicate a successful pickup (default: no sound)
+;pickupfailsound = beeperr      ; to indicate that the pickup failed (default: no sound)
+
+; Transfer Options
+;
+;transferdigittimeout => 3      ; Number of seconds to wait between digits when transferring a call
+                                ; (default is 3 seconds)
+;xfersound = beep               ; to indicate an attended transfer is complete
+;xferfailsound = beeperr        ; to indicate a failed transfer
+;atxfernoanswertimeout = 15     ; Timeout for answer on attended transfer default is 15 seconds.
+;atxferloopdelay = 10           ; Number of seconds to sleep between retries (if atxferdropcall = no)
+;atxfercallbackretries = 2      ; Number of times to attempt to send the call back to the transferer.
+                                ; By default, this is 2.
+;atxferdropcall = no            ; If someone does an attended transfer, then hangs up before the transferred
+                                ; caller is connected, then by default, the system will try to call back the
+                                ; person that did the transfer.  If this is set to "yes", the callback will
+                                ; not be attempted and the transfer will just fail.
+                                ; For atxferdropcall=no to work properly, you also need to
+                                ; define ATXFER_NULL_TECH in main/features.c.  The reason the
+                                ; code is not enabled by default is spelled out in the comment
+                                ; block near the top of main/features.c describing ATXFER_NULL_TECH.
+
+; Parking Options
+;
+; These options apply to all parking lots, including the default lot defined in
+; the general context.
+;
+;courtesytone = beep            ; Sound file to play to when someone picks up a parked call
+                                ; and also when the Touch Monitor is activated/deactivated.
+                                ; Default is no tone.
+;parkedplay = caller            ; Who to play courtesytone to when picking up a parked call.
+                                ; One of: parked, caller, both  (default is caller)
+;parkeddynamic = yes            ; Enables dynamically created parkinglots. (default is no)
+;adsipark = yes                 ; if you want ADSI parking announcements
+
+
+; OPTIONS THAT CAN BE SET PER PARKING LOT
+;
+; If these options are set in the general context, they will *only* apply to the default
+; parking lot. If set in any other lot, they will *only* apply to that lot.
+
+parkext => 700                  ; What extension to dial to park. This option can take any alphanumeric string.
+                                ; (default is 700 for all lots)
+;parkext_exclusive=yes          ; Specify that the parkext created for this parking lot
+                                ; will only access this parking lot. (default is no for all lots)
+parkpos => 701-750              ; What extensions to park calls on.
+                                ; (default is 701-750 for the default lot and blank for custom lots)
+                                ; These need to be numeric, as Asterisk starts from the start position
+                                ; and increments with one for the next parked call. Hence, leading zeros
+                                ; and non-numerical characters will be ignored.
+context => parkedcalls          ; Which context parked calls are in (default is parkedcalls for the default lot and blank for custom lots)
+;parkinghints = no              ; Add hints priorities automatically for parking slots (default is no for all lots).
+;parkingtime => 45              ; Number of seconds a call can be parked before returning.
+                                ; (default is 45 for all lots)
+;parkedcalltransfers = caller   ; Enables or disables DTMF based transfers when picking up a parked call.
+                                ; one of: callee, caller, both, no (default is no for all lots)
+;parkedcallreparking = caller   ; Enables or disables DTMF based parking when picking up a parked call.
+                                ; one of: callee, caller, both, no (default is no for all lots)
+;parkedcallhangup = caller      ; Enables or disables DTMF based hangups when picking up a parked call.
+                                ; one of: callee, caller, both, no (default is no for all lots)
+;parkedcallrecording = caller   ; Enables or disables DTMF based one-touch recording when picking up a parked call.
+                                ; one of: callee, caller, both, no (default is no for all lots)
+;findslot => next               ; Continue to the 'next' free parking space.
+                                ; (Default is 'first' for all lots)
+;parkedmusicclass=default       ; This is the MOH class to use for the parked channel
+                                ; as long as the class is not set on the channel directly
+                                ; using Set(CHANNEL(musicclass)=whatever) in the dialplan.
+                                ; (Default is 'default' for the default parking lot. Non-default parkinglots
+                                ; don't specify a class so the class is picked by the channel put on hold
+                                ; which has the 'default' class by default.)
+;comebacktoorigin = yes         ; Setting this option configures the behavior of call parking when the
+                                ; parked call times out (See the parkingtime option).  The default value is 'yes'.
+                                ;
+                                ; 'yes' - When the parked call times out, attempt to send the call back to the peer
+                                ;         that parked this call. This is done by saving off the name of the channel
+                                ;         that parked the call. The call will return to the context 'park-dial' and
+                                ;         an extension created based on the name of the channel that originally parked
+                                ;         the call.  This extension will be created automatically to do a Dial() to the
+                                ;         device that originally parked the call for comebacktodialtime seconds. If the
+                                ;         call is not answered, the call will proceed to 'park-dial,t,1'.
+                                ;
+                                ; 'no'  - This option is useful for performing custom dialplan functionality prior to
+                                ;         sending the call back to the extension that initially parked the call, or to
+                                ;         an entirely different destination.
+                                ;
+                                ;         When the parked call times out, send it back to the dialplan.  The location
+                                ;         will be defined by the comebackcontext option. The extension will be built from
+                                ;         the saved channel name that parked the call. For example, if a SIP peer named
+                                ;         '0004F2040001' parked this call, the extension will be 'SIP_0004F2040001'.
+                                ;         (Note that an underscore is used here because the '/' character has a special
+                                ;         meaning in extension names for CallerID matching.)  If this extension does not
+                                ;         exist, the call will be sent to the 's' extension, instead.  Finally, if the 's'
+                                ;         extension of 'parkedcallstimeout' does not exist, the call will fall back to the
+                                ;         's' extension of the 'default' context.
+                                ;
+                                ;         Additionally, in this example an extension of 'SIP_0004F2040001' will be
+                                ;         created in the 'park-dial' context.  This extension will be set up to do a
+                                ;         Dial() to 'SIP/0004F2040001'.
+                                ;
+                                ;         During the timeout procedure, the following variables are set
+                                ;         PARKINGSLOT - extension that the call was parked in prior to timing out
+                                ;         PARKEDLOT - name of the lot that the call was parked in prior to timing out
+                                ;         PARKER - name of the device that parked the call
+
+;comebackdialtime = 30          ; When a parked call times out, this is the number of seconds to dial the device that
+                                ; originally parked the call.  It is also available as a channel variable COMEBACKDIALTIME
+                                ; after a parked call has timed out.
+                                ; The default value is 30 seconds.
+;comebackcontext = parkedcallstimeout
+                                ; The context a timed out call will return to if comebcktoorigin=no.
+                                ; The default value is 'parkedcallstimeout'.
+
+
+; EXAMPLE NON-DEFAULT PARKING LOT DEFINITION
+;
+; You can set parkinglot with the CHANNEL dialplan function
+; or by setting 'parkinglot' directly in the channel configuration file.
+;
+; (Note: Leading '0's and any non-numerical characters on parkpos extensions
+;  will be ignored.  Parkext on the other hand can be any string.)
+;
+;[parkinglot_edvina]
+;context => edvinapark
+;parkext => 799
+;parkpos => 800-850
+;findslot => next
+;comebacktoorigin = no
+;comebackdialtime = 90
+;comebackcontext = edvinapark-timeout ; Make sure you create the context!
+;parkedmusicclass = edvina
+
+; EXAMPLE DTMF FEATURE MAP
+;
+; Note that the DTMF features listed below only work when two channels have answered and are bridged together.
+; They can not be used while the remote party is ringing or in progress. If you require this feature you can use
+; chan_local in combination with Answer to accomplish it.
+
+[featuremap]
+;blindxfer => #1                ; Blind transfer  (default is #) -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
+;disconnect => *0               ; Disconnect  (default is *) -- Make sure to set the H and/or h option in the Dial() or Queue() app call!
+                                ; Note that Agents via chan_agent use * to disconnect a call by default. If you are wanting to use * 
+                                ; to abort a transfer you will either need to change the disconnect code here or set endcall to no in agents.conf 
+;automon => *1                  ; One Touch Record a.k.a. Touch Monitor -- Make sure to set the W and/or w option in the Dial() or Queue() app call!
+;atxfer => *2                   ; Attended transfer  -- Make sure to set the T and/or t option in the Dial() or Queue()  app call!
+;parkcall => #72                ; Park call (one step parking)  -- Make sure to set the K and/or k option in the Dial() app call!
+;automixmon => *3               ; One Touch Record a.k.a. Touch MixMonitor -- Make sure to set the X and/or x option in the Dial() or Queue() app call!
+
+; EXAMPLE DYNAMIC FEATURES APPLICATION MAP
+;
+
+[applicationmap]
+; Note that the DYNAMIC_FEATURES channel variable must be set to use the features
+; defined here.  The value of DYNAMIC_FEATURES should be the names of the features
+; to allow the channel to use separated by '#'.  For example:
+;
+;    Set(__DYNAMIC_FEATURES=myfeature1#myfeature2#myfeature3)
+;
+; (Note: The two leading underscores allow these feature settings to be set on
+;  on the outbound channels, as well.  Otherwise, only the original channel
+;  will have access to these features.)
+;
+; The syntax for declaring a dynamic feature is any of the following:
+;
+;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>[,<AppArguments>[,MOH_Class]]
+;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>[,"<AppArguments>"[,MOH_Class]]
+;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>([<AppArguments>])[,MOH_Class]
+
+;
+;  FeatureName   -> This is the name of the feature used when setting the
+;                   DYNAMIC_FEATURES variable to enable usage of this feature.
+;  DTMF_sequence -> This is the key sequence used to activate this feature.
+;  ActivateOn    -> This is the channel of the call that the application will be executed
+;                   on. Valid values are "self" and "peer". "self" means run the
+;                   application on the same channel that activated the feature. "peer"
+;                   means run the application on the opposite channel from the one that
+;                   has activated the feature.
+;  ActivatedBy   -> This is which channel is allowed to activate this feature. Valid
+;                   values are "caller", "callee", and "both". "both" is the default.
+;                   The "caller" is the channel that executed the Dial application, while
+;                   the "callee" is the channel called by the Dial application.
+;  Application   -> This is the application to execute.
+;  AppArguments  -> These are the arguments to be passed into the application.  If you need
+;                   commas in your arguments, you should use either the second or third
+;                   syntax, above.
+;  MOH_Class     -> This is the music on hold class to play while the idle
+;                   channel waits for the feature to complete. If left blank,
+;                   no music will be played.
+;
+
+;
+; IMPORTANT NOTE: The applicationmap is not intended to be used for all Asterisk
+;   applications. When applications are used in extensions.conf, they are executed
+;   by the PBX core. In this case, these applications are executed outside of the
+;   PBX core, so it does *not* make sense to use any application which has any
+;   concept of dialplan flow. Examples of this would be things like Macro, Goto,
+;   Background, WaitExten, and many more.
+;
+; Enabling these features means that the PBX needs to stay in the media flow and
+; media will not be re-directed if DTMF is sent in the media stream.
+;
+; Example Usage:
+;
+;testfeature => #9,peer,Playback,tt-monkeys  ;Allow both the caller and callee to play
+;                                            ;tt-monkeys to the opposite channel
+;
+; Set arbitrary channel variables, based upon CALLERID number (Note that the application
+; argument contains commas)
+;retrieveinfo => #8,peer,Set(ARRAY(CDR(mark),CDR(name))=${ODBC_FOO(${CALLERID(num)})})
+;
+;pauseMonitor   => #1,self/callee,Pausemonitor     ;Allow the callee to pause monitoring
+;                                                  ;on their channel
+;unpauseMonitor => #3,self/callee,UnPauseMonitor   ;Allow the callee to unpause monitoring
+;                                                  ;on their channel
+
+; Dynamic Feature Groups:
+;   Dynamic feature groups are groupings of features defined in [applicationmap]
+;   that can have their own custom key mappings.  To give a channel access to a dynamic
+;   feature group, add the group name to the value of the DYNAMIC_FEATURES variable.
+;
+; example:
+; [myGroupName]         ; defines the group named myGroupName
+; testfeature => #9     ; associates testfeature with the group and the keycode '#9'.
+; pauseMonitor =>       ; associates pauseMonitor with the group and uses the keycode specified
+;                       ; in the [applicationmap].
diff --git a/configs/samples/festival.conf.sample b/configs/festival.conf.sample
similarity index 100%
rename from configs/samples/festival.conf.sample
rename to configs/festival.conf.sample
diff --git a/configs/samples/followme.conf.sample b/configs/followme.conf.sample
similarity index 100%
rename from configs/samples/followme.conf.sample
rename to configs/followme.conf.sample
diff --git a/configs/samples/func_odbc.conf.sample b/configs/func_odbc.conf.sample
similarity index 100%
rename from configs/samples/func_odbc.conf.sample
rename to configs/func_odbc.conf.sample
diff --git a/configs/gtalk.conf.sample b/configs/gtalk.conf.sample
new file mode 100644
index 0000000..d15a58d
--- /dev/null
+++ b/configs/gtalk.conf.sample
@@ -0,0 +1,27 @@
+[general]
+;context=default		; Context to dump call into
+;bindaddr=0.0.0.0		; Address to bind to
+;externip=127.0.0.1		; Set your external ip if you are behind a NAT.
+;stunaddr=mystunserver.com	; Get your external ip from a STUN server.
+				; Note, if the STUN query is successful, this will
+				; replace any value placed in externip;
+;allowguest=yes			; Allow calls from people not in list of peers
+;disallow=all
+;allow=gsm
+;allow=ulaw
+;parkinglot=soccer		; Sets the default parking lot for call parking
+				; Parkinglots are configured in features.conf
+
+;[guest]			; special account for options on guest account
+;disallow=all
+;allow=ulaw
+;context=guest
+
+;[ogorman]
+;username=ogorman at gmail.com	; username of the peer your 
+				; calling or accepting calls from
+;disallow=all
+;allow=ulaw
+;context=default
+;connection=asterisk		; client or component in jabber.conf for the
+				; call to leave on.
diff --git a/configs/h323.conf.sample b/configs/h323.conf.sample
new file mode 100644
index 0000000..5692d3b
--- /dev/null
+++ b/configs/h323.conf.sample
@@ -0,0 +1,210 @@
+; The NuFone Network's
+; Open H.323 driver configuration
+;
+[general]
+port = 1720
+;bindaddr = 1.2.3.4 	; this SHALL contain a single, valid IP address for this machine
+;
+; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of these parameters.
+;tos_audio=ef		; Sets TOS for RTP audio packets.
+;cos_audio=5		; Sets 802.1p priority for RTP audio packets.
+;
+; You may specify a global default AMA flag for iaxtel calls.  It must be
+; one of 'default', 'omit', 'billing', or 'documentation'.  These flags
+; are used in the generation of call detail records.
+;
+;amaflags = default
+;
+; You may specify a default account for Call Detail Records in addition
+; to specifying on a per-user basis
+;
+;accountcode=lss0101
+;
+; You can fine tune codecs here using "allow" and "disallow" clauses
+; with specific codecs.  Use "all" to represent all formats.
+;
+;disallow=all
+;allow=all		; turns on all installed codecs
+;disallow=g723.1	; Hm...  Proprietary, don't use it...
+;allow=gsm		; Always allow GSM, it's cool :)
+;allow=ulaw		; see https://wiki.asterisk.org/wiki/display/AST/RTP+Packetization
+			; for framing options
+;autoframing=yes	; Set packetization based on the remote endpoint's (ptime)
+			; preferences. Defaults to no.
+;
+; User-Input Mode (DTMF)
+;
+; valid entries are:   rfc2833, inband, cisco, h245-signal
+; default is rfc2833
+;dtmfmode=rfc2833
+;
+; Default RTP Payload to send RFC2833 DTMF on.  This is used to
+; interoperate with broken gateways which cannot successfully
+; negotiate a RFC2833 payload type in the TerminalCapabilitySet.
+; To specify required payload type, put it after colon in dtmfmode
+; option like
+;dtmfmode=rfc2833:101
+; or
+;dtmfmode=cisco:121
+;
+; Set the gatekeeper
+; DISCOVER			- Find the Gk address using multicast
+; DISABLE			- Disable the use of a GK
+; <IP address> or <Host name>	- The acutal IP address or hostname of your GK
+;gatekeeper = DISABLE
+;
+;
+; Tell Asterisk whether or not to accept Gatekeeper
+; routed calls or not. Normally this should always
+; be set to yes, unless you want to have finer control
+; over which users are allowed access to Asterisk.
+; Default: YES
+;
+;AllowGKRouted = yes
+;
+; When the channel works without gatekeeper, there is possible to
+; reject calls from anonymous (not listed in users) callers.
+; Default is to allow anonymous calls.
+;
+;AcceptAnonymous = yes
+;
+; Optionally you can determine a user by Source IP versus its H.323 alias.
+; Default behavour is to determine user by H.323 alias.
+;
+;UserByAlias=no
+;
+; Default context gets used in siutations where you are using
+; the GK routed model or no type=user was found. This gives you
+; the ability to either play an invalid message or to simply not
+; use user authentication at all.
+;
+;context=default
+;
+; Use this option to help Cisco (or other) gateways to setup backward voice
+; path to pass inband tones to calling user (see, for example,
+; http://www.cisco.com/warp/public/788/voip/ringback.html)
+;
+; Add PROGRESS information element to SETUP message sent on outbound calls
+; to notify about required backward voice path. Valid values are:
+;   0 - don't add PROGRESS information element (default);
+;   1 - call is not end-end ISDN, further call progress information can
+;        possibly be available in-band;
+;   3 - origination address is non-ISDN (Cisco accepts this value only);
+;   8 - in-band information or an appropriate pattern is now available;
+;progress_setup = 3
+;
+; Add PROGRESS information element (IE) to ALERT message sent on incoming
+; calls to notify about required backwared voice path. Valid values are:
+;   0 - don't add PROGRESS IE (default);
+;   8 - in-band information or an appropriate pattern is now available;
+;progress_alert = 8
+;
+; Generate PROGRESS message when H.323 audio path has established to create
+; backward audio path at other end of a call.
+;progress_audio = yes
+;
+; Specify how to inject non-standard information into H.323 messages. When
+; the channel receives messages with tunneled information, it automatically
+; enables the same option for all further outgoing messages independedly on
+; options has been set by the configuration. This behavior is required, for
+; example, for Cisco CallManager when Q.SIG tunneling is enabled for a
+; gateway where Asterisk lives.
+; The option can be used multiple times, one option per line.
+;tunneling=none               ; Totally disable tunneling (default)
+;tunneling=cisco              ; Enable Cisco-specific tunneling
+;tunneling=qsig               ; Enable tunneling via Q.SIG messages
+;
+; Specify how to pass hold notification to remote party. Default is to
+; use H.450.4 supplementary service message.
+;hold=none                    ; Do not pass hold/retrieve notifications
+;hold=notify                  ; Use H.225 NOTIFY message
+;hold=q931only                ; Use stripped H.225 NOTIFY message (Q.931 part
+;                             ; only, usable for Cisco CallManager)
+;hold=h450                    ; Pass notification as H.450.4 supplementary
+;                             ; service
+;
+;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
+; jbenable = yes              ; Enables the use of a jitterbuffer on the receiving side of a
+                              ; H323 channel. Defaults to "no". An enabled jitterbuffer will
+                              ; be used only if the sending side can create and the receiving
+                              ; side can not accept jitter. The H323 channel can accept jitter,
+                              ; thus an enabled jitterbuffer on the receive H323 side will only
+                              ; be used if the sending side can create jitter and jbforce is
+                              ; also set to yes.
+
+; jbforce = no                ; Forces the use of a jitterbuffer on the receive side of a H323
+                              ; channel. Defaults to "no".
+
+; jbmaxsize = 200             ; Max length of the jitterbuffer in milliseconds.
+
+; jbresyncthreshold = 1000    ; Jump in the frame timestamps over which the jitterbuffer is
+                              ; resynchronized. Useful to improve the quality of the voice, with
+                              ; big jumps in/broken timestamps, usualy sent from exotic devices
+                              ; and programs. Defaults to 1000.
+
+; jbimpl = fixed              ; Jitterbuffer implementation, used on the receiving side of a H323
+                              ; channel. Two implementations are currenlty available - "fixed"
+                              ; (with size always equals to jbmax-size) and "adaptive" (with
+                              ; variable size, actually the new jb of IAX2). Defaults to fixed.
+
+; jblog = no                  ; Enables jitterbuffer frame logging. Defaults to "no".
+;-----------------------------------------------------------------------------------
+;
+; H.323 Alias definitions
+;
+; Type 'h323' will register aliases to the endpoint
+; and Gatekeeper, if there is one.
+;
+; Example: if someone calls time at your.asterisk.box.com
+; Asterisk will send the call to the extension 'time'
+; in the context default
+;
+;   [default]
+;   exten => time,1,Answer
+;   exten => time,2,Playback,current-time
+;
+; Keyword's 'prefix' and 'e164' are only make sense when
+; used with a gatekeeper. You can specify either a prefix
+; or E.164 this endpoint is responsible for terminating.
+;
+; Example: The H.323 alias 'det-gw' will tell the gatekeeper
+; to route any call with the prefix 1248 to this alias. Keyword
+; e164 is used when you want to specifiy a full telephone
+; number. So a call to the number 18102341212 would be
+; routed to the H.323 alias 'time'.
+;
+;[time]
+;type=h323
+;e164=18102341212
+;context=default
+;
+;[det-gw]
+;type=h323
+;prefix=1248,1313
+;context=detroit
+;
+;
+; Inbound H.323 calls from BillyBob would land in the incoming
+; context with a maximum of 4 concurrent incoming calls
+;
+;
+; Note: If keyword 'incominglimit' are omitted Asterisk will not
+; enforce any maximum number of concurrent calls.
+;
+;[BillyBob]
+;type=user
+;host=192.168.1.1
+;context=incoming
+;incominglimit=4
+;h245Tunneling=no
+;
+;
+; Outbound H.323 call to Larry using SlowStart
+;
+;[Larry]
+;type=peer
+;host=192.168.2.1
+;fastStart=no
+
+
+
diff --git a/configs/samples/http.conf.sample b/configs/http.conf.sample
similarity index 88%
rename from configs/samples/http.conf.sample
rename to configs/http.conf.sample
index 44095a1..98c672b 100644
--- a/configs/samples/http.conf.sample
+++ b/configs/http.conf.sample
@@ -45,14 +45,7 @@ bindaddr=127.0.0.1
 ; Default: 30000
 ;session_inactivity=30000
 ;
-; session_keep_alive specifies the number of milliseconds to wait for
-; the next HTTP request over a persistent connection.
-;
-; Set to 0 to disable persistent HTTP connections.
-; Default: 15000
-;session_keep_alive=15000
-;
-; Whether Asterisk should serve static content from static-http
+; Whether Asterisk should serve static content from http-static
 ; Default is no.
 ;
 ;enablestatic=yes
@@ -87,9 +80,6 @@ bindaddr=127.0.0.1
 ;
 ;[post_mappings]
 ;
-; NOTE: You need a valid HTTP AMI mansession_id cookie with the manager
-; config permission to POST files.
-;
 ; In this example, if the prefix option is set to "asterisk", then using the
 ; POST URL: /asterisk/uploads will put files in /var/lib/asterisk/uploads/.
 ;uploads = /var/lib/asterisk/uploads/
diff --git a/configs/samples/iax.conf.sample b/configs/iax.conf.sample
similarity index 98%
rename from configs/samples/iax.conf.sample
rename to configs/iax.conf.sample
index e17c7df..eb82ad8 100644
--- a/configs/samples/iax.conf.sample
+++ b/configs/iax.conf.sample
@@ -22,13 +22,11 @@
 ;bindport=4569           ; The default port to listen on
                          ; NOTE: bindport must be specified BEFORE bindaddr or
                          ; may be specified on a specific bindaddr if followed by
-                         ; colon and port (e.g. bindaddr=192.168.0.1:4569) or for
-                         ; IPv6 the address needs to be in brackets then colon
-                         ; and port (e.g. bindaddr=[2001:db8::1]:4569).
+                         ; colon and port (e.g. bindaddr=192.168.0.1:4569)
 
 ;bindaddr=192.168.0.1    ; You can specify 'bindaddr' more than once to bind to
                          ; multiple addresses, but the first will be the
-                         ; default. IPv6 addresses are accepted.
+                         ; default.
 
 ;
 ; Set 'iaxcompat' to yes if you plan to use layered switches or some other
@@ -552,8 +550,7 @@ inkeys=freeworlddialup
 ;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep   ; This channel variable will
                                                 ; cause the given audio file to
                                                 ; be played upon completion of
-                                                ; an attended transfer to the
-                                                ; target of the transfer.
+                                                ; an attended transfer.
 ;dbsecret=mysecrets/place    ; Secrets can be stored in astdb, too
 ;transfer=no                 ; Disable IAX2 native transfer
 ;transfer=mediaonly          ; When doing IAX2 native transfers, transfer only
@@ -627,7 +624,6 @@ description=Demo System At Digium    ; Description of this peer, as listed by
 ;[dynamichost]
 ;host=dynamic
 ;secret=mysecret
-; Note: app_voicemail mailboxes must be in the form of mailbox at context.
 ;mailbox=1234		; Notify about mailbox 1234
 ;inkeys=key1:key2
 ;peercontext=local	; Default context to request for calls to peer
diff --git a/configs/samples/iaxprov.conf.sample b/configs/iaxprov.conf.sample
similarity index 100%
rename from configs/samples/iaxprov.conf.sample
rename to configs/iaxprov.conf.sample
diff --git a/configs/samples/indications.conf.sample b/configs/indications.conf.sample
similarity index 100%
rename from configs/samples/indications.conf.sample
rename to configs/indications.conf.sample
diff --git a/configs/samples/xmpp.conf.sample b/configs/jabber.conf.sample
similarity index 96%
copy from configs/samples/xmpp.conf.sample
copy to configs/jabber.conf.sample
index dad0f79..a838568 100644
--- a/configs/samples/xmpp.conf.sample
+++ b/configs/jabber.conf.sample
@@ -37,6 +37,3 @@
 ;sendtodialplan=yes			; Send incoming messages into the dialplan.  Off by default.
 ;context=messages			; Dialplan context to send incoming messages to.  If not set,
 					; "default" will be used.
-;forceoldssl=no     ; Force the use of old-style SSL.
-;keepalive=
-
diff --git a/configs/jingle.conf.sample b/configs/jingle.conf.sample
new file mode 100644
index 0000000..8873d06
--- /dev/null
+++ b/configs/jingle.conf.sample
@@ -0,0 +1,20 @@
+;[general]
+;context=default		;;Context to dump call into
+;bindaddr=0.0.0.0		;;Address to bind to
+;allowguest=yes			;;Allow calls from people not in
+				;;list of peers
+;
+;[guest]			;;special account for options on guest account
+;disallow=all
+;allow=ulaw
+;context=guest
+;
+;[ogorman]
+;username=ogorman at gmail.com	;;username of the peer your
+				;;calling or accepting calls from
+;disallow=all
+;allow=ulaw
+;context=default
+;connection=asterisk		;;client or component in jabber.conf
+				;;for the call to leave on.
+;
diff --git a/configs/samples/logger.conf.sample b/configs/logger.conf.sample
similarity index 93%
rename from configs/samples/logger.conf.sample
rename to configs/logger.conf.sample
index 0fa7dcc..07d8f1b 100644
--- a/configs/samples/logger.conf.sample
+++ b/configs/logger.conf.sample
@@ -39,14 +39,7 @@
 ; (defaults to queue_log)
 ;queue_log_name = queue_log
 ;
-; When using realtime for the queue log, use GMT for the timestamp
-; instead of localtime.  The default of this option is 'no'.
-;queue_log_realtime_use_gmt = yes
-;
 ; Log rotation strategy:
-; none:  Do not perform any logrotation at all.  You should make
-;        very sure to set up some external logrotate mechanism
-;        as the asterisk logs can get very large, very quickly.
 ; sequential:  Rename archived logs in order, such that the newest
 ;              has the highest sequence number [default].  When
 ;              exec_after_rotate is set, ${filename} will specify
diff --git a/configs/samples/manager.conf.sample b/configs/manager.conf.sample
similarity index 93%
rename from configs/samples/manager.conf.sample
rename to configs/manager.conf.sample
index aec2d07..d21f46c 100644
--- a/configs/samples/manager.conf.sample
+++ b/configs/manager.conf.sample
@@ -92,14 +92,13 @@ bindaddr = 0.0.0.0
 ; user.
 ;
 ;eventfilter=Event: Newchannel
-;eventfilter=Channel: (PJ)?SIP/(james|jim|john)-
-;eventfilter=!Channel: DAHDI/
+;eventfilter=!Channel: DAHDI.*
 ; The eventfilter option is used to whitelist or blacklist events per user.
-; A filter consists of an (unanchored) regular expression that is run on the
-; entire event data. If the first character of the filter is an exclamation
-; mark (!), the filter is appended to the blacklist instead of the whitelist.
-; After first checking the read access below, the regular expression filters
-; are processed as follows:
+; A filter consists of a (basic/old-style and unanchored) regular expression
+; that is run on the entire event data. If the first character of the filter
+; is an exclamation mark (!), the filter is appended to the blacklist instead
+; of the whitelist. After first checking the read access below, the regular
+; expression filters are processed as follows:
 ; - If no filters are configured all events are reported as normal.
 ; - If there are white filters only: implied black all filter processed first,
 ; then white filters.
@@ -147,7 +146,6 @@ bindaddr = 0.0.0.0
 ; test      - Ability to read TestEvent notifications sent to the Asterisk Test
 ;             Suite.  Note that this is only enabled when the TEST_FRAMEWORK
 ;             compiler flag is defined.
-; security  - Security Events.  Read-only.
 ; message   - Permissions to send out of call messages. Write-only
 ;
 ;read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
diff --git a/configs/samples/meetme.conf.sample b/configs/meetme.conf.sample
similarity index 100%
rename from configs/samples/meetme.conf.sample
rename to configs/meetme.conf.sample
diff --git a/configs/samples/mgcp.conf.sample b/configs/mgcp.conf.sample
similarity index 100%
rename from configs/samples/mgcp.conf.sample
rename to configs/mgcp.conf.sample
diff --git a/configs/samples/minivm.conf.sample b/configs/minivm.conf.sample
similarity index 100%
rename from configs/samples/minivm.conf.sample
rename to configs/minivm.conf.sample
diff --git a/configs/samples/misdn.conf.sample b/configs/misdn.conf.sample
similarity index 100%
rename from configs/samples/misdn.conf.sample
rename to configs/misdn.conf.sample
diff --git a/configs/samples/modules.conf.sample b/configs/modules.conf.sample
similarity index 100%
rename from configs/samples/modules.conf.sample
rename to configs/modules.conf.sample
diff --git a/configs/samples/motif.conf.sample b/configs/motif.conf.sample
similarity index 84%
rename from configs/samples/motif.conf.sample
rename to configs/motif.conf.sample
index 9d5bc80..ae3ab30 100644
--- a/configs/samples/motif.conf.sample
+++ b/configs/motif.conf.sample
@@ -75,25 +75,18 @@ context=incoming-motif ; Default context that incoming sessions will land in
 ;maxpayloads = 30      ; Maximum number of payloads we will offer
 
 ; Sample configuration entry for Jingle
-;[jingle-endpoint](default)
-;transport=ice-udp               ; Change the default protocol of outgoing sessions to Jingle ICE-UDP
-;allow=g722                      ; Add G.722 as an allowed format since the other side may support it
-;connection=local-jabber-account ; Connection to accept traffic on and send traffic out
-;accountcode=jingle              ; Account code for CDR purposes
+[jingle-endpoint](default)
+transport=ice-udp               ; Change the default protocol of outgoing sessions to Jingle ICE-UDP
+allow=g722                      ; Add G.722 as an allowed format since the other side may support it
+connection=local-jabber-account ; Connection to accept traffic on and send traffic out
+accountcode=jingle              ; Account code for CDR purposes
 
 ; Sample configuration entry for Google Talk
 [gtalk-endpoint](default)
-;transport=google         ; Since this is a Google Talk endpoint we want to offer Google Jingle for outgoing sessions
-;connection=gtalk-account
+transport=google         ; Since this is a Google Talk endpoint we want to offer Google Jingle for outgoing sessions
+connection=gtalk-account
 
 ; Sample configuration entry for Google Voice
-;[gvoice](default)
-;transport=google-v1       ; Google Voice uses the original Google Talk protocol
-;connection=gvoice-account
-
-; Additional options
-; callgroup
-; pickupgroup
-; language
-; musicclass
-; parkinglot
+[gvoice](default)
+transport=google-v1       ; Google Voice uses the original Google Talk protocol
+connection=gvoice-account
diff --git a/configs/samples/musiconhold.conf.sample b/configs/musiconhold.conf.sample
similarity index 100%
rename from configs/samples/musiconhold.conf.sample
rename to configs/musiconhold.conf.sample
diff --git a/configs/samples/muted.conf.sample b/configs/muted.conf.sample
similarity index 100%
rename from configs/samples/muted.conf.sample
rename to configs/muted.conf.sample
diff --git a/configs/samples/ooh323.conf.sample b/configs/ooh323.conf.sample
similarity index 97%
rename from configs/samples/ooh323.conf.sample
rename to configs/ooh323.conf.sample
index aeeb02f..d8ccdcf 100644
--- a/configs/samples/ooh323.conf.sample
+++ b/configs/ooh323.conf.sample
@@ -72,10 +72,6 @@ e164=100
 ;Default - Same as h323id
 callerid=asterisk
 
-; Whether asterisk send back to caller own connected line id on incoming call as called number
-; Default - no
-aniasdni=no
-
 ;Whether this asterisk server will use gatekeeper.
 ;Default - DISABLE
 ;gatekeeper = DISCOVER
diff --git a/configs/samples/osp.conf.sample b/configs/osp.conf.sample
similarity index 100%
rename from configs/samples/osp.conf.sample
rename to configs/osp.conf.sample
diff --git a/configs/samples/oss.conf.sample b/configs/oss.conf.sample
similarity index 100%
rename from configs/samples/oss.conf.sample
rename to configs/oss.conf.sample
diff --git a/configs/samples/phone.conf.sample b/configs/phone.conf.sample
similarity index 100%
rename from configs/samples/phone.conf.sample
rename to configs/phone.conf.sample
diff --git a/configs/samples/phoneprov.conf.sample b/configs/phoneprov.conf.sample
similarity index 93%
rename from configs/samples/phoneprov.conf.sample
rename to configs/phoneprov.conf.sample
index 7d14013..17d8b1f 100644
--- a/configs/samples/phoneprov.conf.sample
+++ b/configs/phoneprov.conf.sample
@@ -1,7 +1,4 @@
 [general]
-; This section applies only to the default sip.conf/users.conf config provider
-; embedded in res_phoneprov.  Other providers may provide their own default settings.
-
 ; The default behavior of res_phoneprov will be to set the SERVER template variable to
 ; the IP address that the phone uses to contact the provisioning server and the
 ; SERVER_PORT variable to the bindport setting in sip.conf.  Unless you have a very
@@ -18,8 +15,7 @@ default_profile=polycom ; The default profile to use if none specified in users.
 ; with the provisioning server.  You can define either static files, or dynamically
 ; generated files that can have dynamic names and point to templates that variables
 ; can be substituted into.  You can also set arbitrary variables for the profiles
-; templates to have access to.  Profiles are shared across all config providers.
-; Example:
+; templates to have access to.  Example:
 
 ;[example]
 ;mime_type => application/octet-stream
@@ -29,9 +25,7 @@ default_profile=polycom ; The default profile to use if none specified in users.
 ;setvar => DB_CIDNAME=${ODBC_CID_NAME_LOOKUP(${USERNAME})}
 
 ; Dynamically generated files have a filename registered with variable substitution
-; with variables obtained from various config providers.  The default provider
-; embedded in res_phoneprov reads users.conf.  Other providers will have their own
-; sources for the variables and may provide additional variables not listed here.
+; with variables obtained while reading users.conf.
 
 ; Built in variables and the options in users.conf that they come from
 ;   MAC (macaddress)
diff --git a/configs/samples/queuerules.conf.sample b/configs/queuerules.conf.sample
similarity index 80%
rename from configs/samples/queuerules.conf.sample
rename to configs/queuerules.conf.sample
index 417f52d..fb2a1ba 100644
--- a/configs/samples/queuerules.conf.sample
+++ b/configs/queuerules.conf.sample
@@ -1,14 +1,3 @@
-
-[general]
-
-; Look for queue rules in the queue_rules database table through RealTime. Note
-; that this option is not strictly "RealTime", in the sense that the queue
-; rules are only loaded and parsed during module load/reload. Queue rules
-; must have a unique rule name and support relative min/max penalties.
-;
-; realtime_rules = yes
-;
-
 ; It is possible to change the value of the QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY
 ; channel variables in mid-call by defining rules in the queue for when to do so. This can allow for
 ; a call to be opened to more members or potentially a different set of members.
diff --git a/configs/samples/queues.conf.sample b/configs/queues.conf.sample
similarity index 93%
rename from configs/samples/queues.conf.sample
rename to configs/queues.conf.sample
index bea62e8..aa1b668 100644
--- a/configs/samples/queues.conf.sample
+++ b/configs/queues.conf.sample
@@ -224,8 +224,13 @@ monitor-type = MixMonitor
 ;
 ;maxlen = 0
 ;
+; Note: for below queue channel options (setinterfacevar, setqueueentryvar,
+; setqueuevar) if the caller channel is a local channel and optimizations
+; is enabled then after optimization has occurred only the queue member
+; channel will contain the variables.
+;
 ; If set to yes, just prior to the caller being bridged with a queue member
-; the following variables will be set
+; the following variables will be set on the caller and queue member channels:
 ; MEMBERINTERFACE is the interface name (eg. Agent/1234)
 ; MEMBERNAME is the member name (eg. Joe Soap)
 ; MEMBERCALLS is the number of calls that interface has taken,
@@ -237,15 +242,16 @@ monitor-type = MixMonitor
 ;setinterfacevar=no
 ;
 ; If set to yes, just prior to the caller being bridged with a queue member
-; the following variables will be set:
+; the following variables will be set on the caller and queue member channels:
 ; QEHOLDTIME callers hold time
 ; QEORIGINALPOS original position of the caller in the queue
 ;
 ;setqueueentryvar=no
 ;
 ; If set to yes, the following variables will be set
-; just prior to the caller being bridged with a queue member
-; and just prior to the caller leaving the queue
+; just prior to the caller being bridged with a queue member (set on the
+; caller and queue member channels) and just prior to the caller
+; leaving the queue
 ; QUEUENAME name of the queue
 ; QUEUEMAX maxmimum number of calls allowed
 ; QUEUESTRATEGY the strategy of the queue;
@@ -482,6 +488,20 @@ monitor-type = MixMonitor
 ; loose - penalty,invalid
 ;
 
+; If this is set to yes, the following manager events will be generated:
+; AgentCalled, AgentDump, AgentConnect, AgentComplete; setting this to
+; vars also sends all channel variables with the event.
+; (may generate some extra manager events, but probably ones you want)
+;
+; eventwhencalled = yes|no|vars
+;
+; If this is set to yes, the following manager events will be generated:
+; QueueMemberStatus
+; (may generate a WHOLE LOT of extra manager events)
+; The default value is yes and this can not be set globally.
+;
+; eventmemberstatus = no
+;
 ; If you wish to report the caller's hold time to the member before they are
 ; connected to the caller, set this to yes.
 ;
@@ -543,7 +563,18 @@ monitor-type = MixMonitor
 ;member => DAHDI/1
 ;member => DAHDI/2,10
 ;member => DAHDI/3,10,Bob Johnson
-;member => Local/1001 at agents,0,May Flowers,Agent:1001
-;member => Local/1002 at agents,0,John Doe,Agent:1002
+;member => Agent/1001
+;member => Agent/1002
 ;member => Local/1000 at default,0,John Smith,SIP/1000
 ;member => Local/2000 at default,0,Lorem Ipsum,SIP/2000,no
+
+;
+; Note that using agent groups is probably not what you want.  Strategies do
+; not propagate down to the Agent system so if you want round robin, least
+; recent, etc, you should list all the agents in this file individually and not
+; use agent groups.
+;
+;member => Agent/@1		; Any agent in group 1
+;member => Agent/:1,1		; Any agent in group 1, wait for first
+                                ; available, but consider with penalty
+
diff --git a/configs/samples/res_config_mysql.conf.sample b/configs/res_config_mysql.conf.sample
similarity index 100%
rename from configs/samples/res_config_mysql.conf.sample
rename to configs/res_config_mysql.conf.sample
diff --git a/configs/samples/res_config_sqlite.conf.sample b/configs/res_config_sqlite.conf.sample
similarity index 100%
rename from configs/samples/res_config_sqlite.conf.sample
rename to configs/res_config_sqlite.conf.sample
diff --git a/configs/samples/res_config_sqlite3.conf.sample b/configs/res_config_sqlite3.conf.sample
similarity index 100%
rename from configs/samples/res_config_sqlite3.conf.sample
rename to configs/res_config_sqlite3.conf.sample
diff --git a/configs/samples/res_corosync.conf.sample b/configs/res_corosync.conf.sample
similarity index 100%
rename from configs/samples/res_corosync.conf.sample
rename to configs/res_corosync.conf.sample
diff --git a/configs/samples/res_curl.conf.sample b/configs/res_curl.conf.sample
similarity index 100%
rename from configs/samples/res_curl.conf.sample
rename to configs/res_curl.conf.sample
diff --git a/configs/samples/res_fax.conf.sample b/configs/res_fax.conf.sample
similarity index 92%
rename from configs/samples/res_fax.conf.sample
rename to configs/res_fax.conf.sample
index dfaa4ce..022a23a 100644
--- a/configs/samples/res_fax.conf.sample
+++ b/configs/res_fax.conf.sample
@@ -26,3 +26,7 @@ statusevents=yes
 ; Enable/disable T.30 ECM (error correction mode) by default.
 ; Default: Enabled
 ;ecm=yes
+
+; T.38 Negotiation Timeout in milliseconds
+; Default: 5000
+t38timeout=5000
diff --git a/configs/samples/res_ldap.conf.sample b/configs/res_ldap.conf.sample
similarity index 99%
rename from configs/samples/res_ldap.conf.sample
rename to configs/res_ldap.conf.sample
index ac345cd..9a2accb 100644
--- a/configs/samples/res_ldap.conf.sample
+++ b/configs/res_ldap.conf.sample
@@ -121,7 +121,6 @@ ipaddr = AstAccountIPAddress
 defaultuser = AstAccountDefaultUser
 regserver = AstAccountRegistrationServer
 lastms = AstAccountLastQualifyMilliseconds
-supportpath = AstAccountPathSupport
 additionalFilter=(objectClass=AsteriskSIPUser)
 
 ;
diff --git a/configs/samples/res_odbc.conf.sample b/configs/res_odbc.conf.sample
similarity index 89%
rename from configs/samples/res_odbc.conf.sample
rename to configs/res_odbc.conf.sample
index 66659ae..035f38c 100644
--- a/configs/samples/res_odbc.conf.sample
+++ b/configs/res_odbc.conf.sample
@@ -23,7 +23,8 @@ enabled => no
 ; (or /usr/local/etc/odbc.ini, on FreeBSD and similar systems).
 dsn => asterisk
 ;
-; Username for connecting to the database.  The user defaults to the context name if unspecified.
+; Username for connecting to the database.  The user defaults to the context
+; name if unspecified.
 ;username => myuser
 ;
 ; Password for authenticating the user to the database.  The default
@@ -64,6 +65,15 @@ pre-connect => yes
 ; MS SQL Server, the answer is no.
 ;backslash_is_escape => yes
 ;
+; When enabled (default behavior), empty column values are stored as empty strings
+; during realtime updates. Disabling this option causes empty column values to be
+; stored as NULLs for non-text columns.
+; Disable it for PostgreSQL backend in order to avoid errors caused by updating
+; integer columns with an empty string instead of NULL (sippeers, sipregs, ..).
+; NOTE: This option will be removed in asterisk 13. At that point, it will always
+; behave as if it was set to 'no'.
+;allow_empty_string_in_nontext => yes
+;
 ; How long (in seconds) should we attempt to connect before considering the
 ; connection dead?  The default is 10 seconds, but you may wish to reduce it,
 ; to increase responsiveness.
diff --git a/configs/samples/res_pgsql.conf.sample b/configs/res_pgsql.conf.sample
similarity index 91%
rename from configs/samples/res_pgsql.conf.sample
rename to configs/res_pgsql.conf.sample
index cc7442f..b889244 100644
--- a/configs/samples/res_pgsql.conf.sample
+++ b/configs/res_pgsql.conf.sample
@@ -12,7 +12,6 @@ dbport=5432
 dbname=asterisk
 dbuser=asterisk
 dbpass=password
-;dbappname=asterisk    ; Postgres application_name support (optional). Whitespace not allowed.
 ;
 ; dbsock is specified as the directory where the socket file may be found. The
 ; actual socket is constructed as a combination of dbsock and dbport.  For
diff --git a/configs/samples/res_pktccops.conf.sample b/configs/res_pktccops.conf.sample
similarity index 100%
rename from configs/samples/res_pktccops.conf.sample
rename to configs/res_pktccops.conf.sample
diff --git a/configs/samples/res_snmp.conf.sample b/configs/res_snmp.conf.sample
similarity index 100%
rename from configs/samples/res_snmp.conf.sample
rename to configs/res_snmp.conf.sample
diff --git a/configs/samples/res_stun_monitor.conf.sample b/configs/res_stun_monitor.conf.sample
similarity index 100%
rename from configs/samples/res_stun_monitor.conf.sample
rename to configs/res_stun_monitor.conf.sample
diff --git a/configs/samples/rtp.conf.sample b/configs/rtp.conf.sample
similarity index 100%
rename from configs/samples/rtp.conf.sample
rename to configs/rtp.conf.sample
diff --git a/configs/samples/agents.conf.sample b/configs/samples/agents.conf.sample
deleted file mode 100644
index 0cf0c4c..0000000
--- a/configs/samples/agents.conf.sample
+++ /dev/null
@@ -1,70 +0,0 @@
-;
-; Agent pool configuration
-;
-
-[general]
-; The general section of this config is not currently used, but reserved
-; for future use.
-
-;[agent-id]
-; Define ackcall to require the agent to give a DTMF acknowledgement
-; when the agent receives a call.
-; The channel variable AGENTACKCALL overrides on agent login.
-; Default is "no".
-;ackcall=no
-;
-; Set what DTMF key sequence the agent should use to acknowledge a call.
-; The channel variable AGENTACCEPTDTMF overrides on agent login.
-; This option is ignored unless ackcall is enabled.
-; Default is "#".
-;acceptdtmf=##
-;
-; Set how many seconds a call for the agent has to wait for the agent to
-; acknowledge the call before the agent is automatically logged off.  If
-; set to zero then the call will wait forever for the agent to acknowledge.
-; The channel variable AGENTAUTOLOGOFF overrides on agent login.
-; This option is ignored unless ackcall is enabled.
-; Default is 0.
-;autologoff=15
-;
-; Set the minimum amount of time after disconnecting a call before
-; the agent can receive a new call in milliseconds.
-; The channel variable AGENTWRAPUPTIME overrides on agent login.
-; Default is 0.
-;wrapuptime=5000
-;
-; Set the musiconhold class for the agent.
-; Default is "default".
-;musiconhold=default
-;
-; Enable recording calls the agent takes automatically by invoking the
-; DTMF automixmon feature when the agent connects to a caller.
-; See features.conf.sample for information about the automixmon feature.
-; Default is "no".
-;recordagentcalls=yes
-;
-; The sound file played to alert the agent when a call is present.
-; Default is "beep".
-;custom_beep=beep
-;
-; A friendly name for the agent used in log messages.
-; Default is "".
-;fullname=Mark Spencer
-;
-; --------------------------------------------------
-;
-; This section contains example agent definitions:
-;
-; Define a template called my-agents:
-;[my-agents](!)
-;autologoff=15
-;ackcall=yes
-;acceptdtmf=##
-;
-; Define agent 1001 using the my-agents template:
-;[1001](my-agents)
-;fullname=Mark Spencer
-;
-; Define agent 1002 using the my-agents template:
-;[1002](my-agents)
-;fullname=Will Meadows
diff --git a/configs/samples/ari.conf.sample b/configs/samples/ari.conf.sample
deleted file mode 100644
index 59f9a44..0000000
--- a/configs/samples/ari.conf.sample
+++ /dev/null
@@ -1,31 +0,0 @@
-[general]
-enabled = yes       ; When set to no, ARI support is disabled.
-;pretty = no        ; When set to yes, responses from ARI are
-;                   ; formatted to be human readable.
-;allowed_origins =  ; Comma separated list of allowed origins, for
-;                   ; Cross-Origin Resource Sharing. May be set to * to
-;                   ; allow all origins.
-;auth_realm =       ; Realm to use for authentication. Defaults to Asterisk
-;                   ; REST Interface.
-;
-; Default write timeout to set on websockets. This value may need to be adjusted
-; for connections where Asterisk must write a substantial amount of data and the
-; receiving clients are slow to process the received information. Value is in
-; milliseconds; default is 100 ms.
-;websocket_write_timeout = 100
-
-;[username]
-;type = user        ; Specifies user configuration
-;read_only = no     ; When set to yes, user is only authorized for
-;                   ; read-only requests.
-;
-;password =         ; Crypted or plaintext password (see password_format).
-;
-; password_format may be set to plain (the default) or crypt. When set to crypt,
-; crypt(3) is used to validate the password. A crypted password can be generated
-; using mkpasswd -m sha-512.
-;
-; When set to plain, the password is in plaintext.
-;
-;password_format = plain
-
diff --git a/configs/samples/features.conf.sample b/configs/samples/features.conf.sample
deleted file mode 100644
index 56b334f..0000000
--- a/configs/samples/features.conf.sample
+++ /dev/null
@@ -1,119 +0,0 @@
-;
-; Sample Call Features (transfer, monitor/mixmonitor, etc) configuration
-;
-
-; Asterisk 12 Note - All parking lot configuration is now done in res_parking.conf
-
-[general]
-;transferdigittimeout => 3      ; Number of seconds to wait between digits when transferring a call
-                                ; (default is 3 seconds)
-;xfersound = beep               ; to indicate an attended transfer is complete
-;xferfailsound = beeperr        ; to indicate a failed transfer
-;pickupexten = *8               ; Configure the pickup extension. (default is *8)
-;pickupsound = beep             ; to indicate a successful pickup (default: no sound)
-;pickupfailsound = beeperr      ; to indicate that the pickup failed (default: no sound)
-;featuredigittimeout = 1000     ; Max time (ms) between digits for
-                                ; feature activation  (default is 1000 ms)
-;recordingfailsound = beeperr   ; indicates that a one-touch monitor or one-touch mixmonitor feature failed
-                                ; to be applied to the call. (default: no sound)
-;atxfernoanswertimeout = 15     ; Timeout for answer on attended transfer default is 15 seconds.
-;atxferdropcall = no            ; If someone does an attended transfer, then hangs up before the transfer
-                                ; target answers, then by default, the system will try to call back the
-                                ; person that did the transfer.  If this is set to "yes", the ringing
-                                ; transfer target is immediately transferred to the transferee.
-;atxferloopdelay = 10           ; Number of seconds to sleep between retries (if atxferdropcall = no)
-;atxfercallbackretries = 2      ; Number of times to attempt to send the call back to the transferer.
-                                ; By default, this is 2.
-;transferdialattempts = 3       ; Number of times that a transferer may attempt to dial an extension before
-                                ; being kicked back to the original call.
-;transferretrysound = "beep"    ; Sound to play when a transferer fails to dial a valid extension.
-;transferinvalidsound = "beeperr" ; Sound to play when a transferer fails to dial a valid extension and is out of retries.
-
-
-; Note that the DTMF features listed below only work when two channels have answered and are bridged together.
-; They can not be used while the remote party is ringing or in progress. If you require this feature you can use
-; chan_local in combination with Answer to accomplish it.
-
-[featuremap]
-;blindxfer => #1                ; Blind transfer  (default is #) -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
-;disconnect => *0               ; Disconnect  (default is *) -- Make sure to set the H and/or h option in the Dial() or Queue() app call!
-;automon => *1                  ; One Touch Record a.k.a. Touch Monitor -- Make sure to set the W and/or w option in the Dial() or Queue() app call!
-;atxfer => *2                   ; Attended transfer  -- Make sure to set the T and/or t option in the Dial() or Queue()  app call!
-;parkcall => #72                ; Park call (one step parking)  -- Make sure to set the K and/or k option in the Dial() app call!
-;automixmon => *3               ; One Touch Record a.k.a. Touch MixMonitor -- Make sure to set the X and/or x option in the Dial() or Queue() app call!
-
-[applicationmap]
-; Note that the DYNAMIC_FEATURES channel variable must be set to use the features
-; defined here.  The value of DYNAMIC_FEATURES should be the names of the features
-; to allow the channel to use separated by '#'.  For example:
-;
-;    Set(__DYNAMIC_FEATURES=myfeature1#myfeature2#myfeature3)
-;
-; (Note: The two leading underscores allow these feature settings to be set
-;  on the outbound channels, as well.  Otherwise, only the original channel
-;  will have access to these features.)
-;
-; The syntax for declaring a dynamic feature is any of the following:
-;
-;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>[,<AppArguments>[,MOH_Class]]
-;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>[,"<AppArguments>"[,MOH_Class]]
-;<FeatureName> => <DTMF_sequence>,<ActivateOn>[/<ActivatedBy>],<Application>([<AppArguments>])[,MOH_Class]
-
-;
-;  FeatureName   -> This is the name of the feature used when setting the
-;                   DYNAMIC_FEATURES variable to enable usage of this feature.
-;  DTMF_sequence -> This is the key sequence used to activate this feature.
-;  ActivateOn    -> This is the channel of the call that the application will be executed
-;                   on. Valid values are "self" and "peer". "self" means run the
-;                   application on the same channel that activated the feature. "peer"
-;                   means run the application on the opposite channel from the one that
-;                   has activated the feature.
-;  ActivatedBy   -> ActivatedBy is no longer honored.  The feature is activated by which
-;                   channel DYNAMIC_FEATURES includes the feature is on.  Use predial
-;                   to set different values of DYNAMIC_FEATURES on the channels.
-;                   Historic values are: "caller", "callee", and "both".
-;  Application   -> This is the application to execute.
-;  AppArguments  -> These are the arguments to be passed into the application.  If you need
-;                   commas in your arguments, you should use either the second or third
-;                   syntax, above.
-;  MOH_Class     -> This is the music on hold class to play while the idle
-;                   channel waits for the feature to complete. If left blank,
-;                   no music will be played.
-;
-
-;
-; IMPORTANT NOTE: The applicationmap is not intended to be used for all Asterisk
-;   applications. When applications are used in extensions.conf, they are executed
-;   by the PBX core. In this case, these applications are executed outside of the
-;   PBX core, so it does *not* make sense to use any application which has any
-;   concept of dialplan flow. Examples of this would be things like Goto,
-;   Background, WaitExten, and many more.  The exceptions to this are Gosub and
-;   Macro routines which must complete for the call to continue.
-;
-; Enabling these features means that the PBX needs to stay in the media flow and
-; media will not be re-directed if DTMF is sent in the media stream.
-;
-; Example Usage:
-;
-;testfeature => #9,peer,Playback,tt-monkeys  ;Allow both the caller and callee to play
-;                                            ;tt-monkeys to the opposite channel
-;
-; Set arbitrary channel variables, based upon CALLERID number (Note that the application
-; argument contains commas)
-;retrieveinfo => #8,peer,Set(ARRAY(CDR(mark),CDR(name))=${ODBC_FOO(${CALLERID(num)})})
-;
-;pauseMonitor   => #1,self/callee,Pausemonitor     ;Allow the callee to pause monitoring
-;                                                  ;on their channel
-;unpauseMonitor => #3,self/callee,UnPauseMonitor   ;Allow the callee to unpause monitoring
-;                                                  ;on their channel
-
-; Dynamic Feature Groups:
-;   Dynamic feature groups are groupings of features defined in [applicationmap]
-;   that can have their own custom key mappings.  To give a channel access to a dynamic
-;   feature group, add the group name to the value of the DYNAMIC_FEATURES variable.
-;
-; example:
-; [myGroupName]         ; defines the group named myGroupName
-; testfeature => #9     ; associates testfeature with the group and the keycode '#9'.
-; pauseMonitor =>       ; associates pauseMonitor with the group and uses the keycode specified
-;                       ; in the [applicationmap].
diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample
deleted file mode 100644
index 40b17aa..0000000
--- a/configs/samples/hep.conf.sample
+++ /dev/null
@@ -1,16 +0,0 @@
-;
-; res_hep Module configuration for Asterisk
-;
-
-; All settings are currently set in the general section.
-[general]
-enabled = yes                      ; Enable/disable forwarding of packets to a
-                                   ; HEP server. Default is "yes".
-capture_address = 192.168.1.1:9061 ; The address of the HEP capture server.
-capture_password = foo             ; If specified, the authorization passsword
-                                   ; for the HEP server. If not specified, no
-                                   ; authorization password will be sent.
-capture_id = 1234                  ; A unique integer identifier for this
-                                   ; server. This ID will be embedded sent
-                                   ; with each packet from this server.
-
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
deleted file mode 100644
index a9b2d2b..0000000
--- a/configs/samples/pjsip.conf.sample
+++ /dev/null
@@ -1,927 +0,0 @@
-; PJSIP Configuration Samples and Quick Reference
-;
-; This file has several very basic configuration examples, to serve as a quick
-; reference to jog your memory when you need to write up a new configuration.
-; It is not intended to teach PJSIP configuration or serve as an exhaustive
-; reference of options and potential scenarios.
-;
-; This file has two main sections.
-; First, manually written examples to serve as a handy reference.
-; Second, a list of all possible PJSIP config options by section. This is
-; pulled from the XML config help. It only shows the synopsis for every item.
-; If you want to see more detail please check the documentation sources
-; mentioned at the top of this file.
-
-; Documentation
-;
-; The official documentation is at http://wiki.asterisk.org
-; You can read the XML configuration help via Asterisk command line with
-; "config show help res_pjsip", then you can drill down through the various
-; sections and their options.
-;
-
-;========!!!!!!!!!!!!!!!!!!!  SECURITY NOTICE  !!!!!!!!!!!!!!!!!!!!===========
-;
-; At a minimum please read the file "README-SERIOUSLY.bestpractices.txt",
-; located in the Asterisk source directory before starting Asterisk.
-; Otherwise you risk allowing the security of the Asterisk system to be
-; compromised. Beyond that please visit and read the security information on
-; the wiki at: https://wiki.asterisk.org/wiki/x/EwFB
-;
-; A few basics to pay attention to:
-;
-; Anonymous Calls
-;
-; By default anonymous inbound calls via PJSIP are not allowed. If you want to
-; route anonymous calls you'll need to define an endpoint named "anonymous".
-; res_pjsip_endpoint_identifier_anonymous.so handles that functionality so it
-; must be loaded. It is not recommended to accept anonymous calls.
-;
-; Access Control Lists
-;
-; See the example ACL configuration in this file. Read the configuration help
-; for the section and all of its options. Look over the samples in acl.conf
-; and documentation at https://wiki.asterisk.org/wiki/x/uA80AQ
-; If possible, restrict access to only networks and addresses you trust.
-;
-; Dialplan Contexts
-;
-; When defining configuration (such as an endpoint) that links into
-; dialplan configuration, be aware of what that dialplan does. It's easy to
-; accidentally provide access to internal or outbound dialing extensions which
-; could cost you severely. The "context=" line in endpoint configuration
-; determines which dialplan context inbound calls will enter into.
-;
-;=============================================================================
-
-; Overview of Configuration Section Types Used in the Examples
-;
-; * Transport "transport"
-;   * Configures res_pjsip transport layer interaction.
-; * Endpoint "endpoint"
-;   * Configures core SIP functionality related to SIP endpoints.
-; * Authentication "auth"
-;   * Stores inbound or outbound authentication credentials for use by trunks,
-;     endpoints, registrations.
-; * Address of Record "aor"
-;   * Stores contact information for use by endpoints.
-; * Endpoint Identification "identify"
-;   * Maps a host directly to an endpoint
-; * Access Control List "acl"
-;   * Defines a permission list or references one stored in acl.conf
-; * Registration "registration"
-;   * Contains information about an outbound SIP registration
-; * Phone Provisioning "phoneprov"
-;   * Contains information needed by res_phoneprov for autoprovisioning
-
-; The following sections show example configurations for various scenarios.
-; Most require a couple or more configuration types configured in concert.
-
-;=============================================================================
-
-; Naming of Configuration Sections
-;
-; Configuration section names are denoted with enclosing brackets,
-; e.g. [6001]
-; In most cases, you can name a section whatever makes sense to you. For example
-; you might name a transport [transport-udp-nat] to help you remember how that
-; section is being used. However, in some cases, ("endpoint" and "aor" types)
-; the section name has a relationship to its function.
-;
-; Depending on the modules loaded, Asterisk can match SIP requests to an
-; endpoint or aor in a few ways:
-;
-; 1) Match a section name for endpoint type sections to the username in the
-;    "From" header of inbound SIP requests.
-; 2) Match a section name for aor type sections to the username in the "To"
-;    header of inbound SIP REGISTER requests.
-; 3) With an identify type section configured, match an inbound SIP request of
-;    any type to an endpoint or aor based on the IP source address of the
-;    request.
-;
-; Note that sections can have the same name as long as their "type" options are
-; set to different values. In most cases it makes sense to have associated
-; configuration sections use the same name, as you'll see in the examples within
-; this file.
-
-;===============EXAMPLE TRANSPORTS============================================
-;
-; A few examples for potential transport options.
-;
-; For the NAT transport example, be aware that the options starting with
-; the prefix "external_" will only apply to communication with addresses
-; outside the range set with "local_net=".
-;
-; IPv6: For endpoints using IPv6, remember to set "rtp_ipv6=yes" so that the RTP
-; engine will also be able to bind to an IPv6 address.
-;
-; You can have more than one of any type of transport, as long as it doesn't
-; use the same resources (bind address, port, etc) as the others.
-
-; Basic UDP transport
-;
-;[transport-udp]
-;type=transport
-;protocol=udp    ;udp,tcp,tls,ws,wss
-;bind=0.0.0.0
-
-; UDP transport behind NAT
-;
-;[transport-udp-nat]
-;type=transport
-;protocol=udp
-;bind=0.0.0.0
-;local_net=192.0.2.0/24
-;external_media_address=203.0.113.1
-;external_signaling_address=203.0.113.1
-
-; Basic IPv6 UDP transport
-;
-;[transport-udp-ipv6]
-;type=transport
-;protocol=udp
-;bind=::
-
-; Example IPv4 TLS transport
-;
-;[transport-tls]
-;type=transport
-;protocol=tls
-;bind=0.0.0.0
-;cert_file=/path/mycert.crt
-;priv_key_file=/path/mykey.key
-;cipher=ADH-AES256-SHA,ADH-AES128-SHA
-;method=tlsv1
-
-
-;===============OUTBOUND REGISTRATION WITH OUTBOUND AUTHENTICATION============
-;
-; This is a simple registration that works with some SIP trunking providers.
-; You'll need to set up the auth example "mytrunk_auth" below to enable outbound
-; authentication. Note that we "outbound_auth=" use for outbound authentication
-; instead of "auth=", which is for inbound authentication.
-;
-; If you are registering to a server from behind NAT, be sure you assign a transport
-; that is appropriately configured with NAT related settings. See the NAT transport example.
-;
-; "contact_user=" sets the SIP contact header's user portion of the SIP URI
-; this will affect the extension reached in dialplan when the far end calls you at this
-; registration. The default is 's'.
-
-;[mytrunk]
-;type=registration
-;transport=transport-udp
-;outbound_auth=mytrunk_auth
-;server_uri=sip:sip.example.com
-;client_uri=sip:1234567890 at sip.example.com
-;contact_user=1234567890
-;retry_interval=60
-;forbidden_retry_interval=600
-;expiration=3600
-
-;[mytrunk_auth]
-;type=auth
-;auth_type=userpass
-;password=1234567890
-;username=1234567890
-;realm=sip.example.com
-
-;===============ENDPOINT CONFIGURED AS A TRUNK, OUTBOUND AUTHENTICATION=======
-;
-; This is one way to configure an endpoint as a trunk. It is set up with
-; "outbound_auth=" to enable authentication when dialing out through this
-; endpoint. There is no inbound authentication set up since a provider will
-; not normally authenticate when calling you.
-;
-; The identify configuration enables IP address matching against this endpoint.
-; For calls from a trunking provider, the From user may be different every time,
-; so we want to match against IP address instead of From user.
-;
-; If you want the provider of your trunk to know where to send your calls
-; you'll need to use an outbound registration as in the example above this
-; section.
-;
-; NAT
-;
-; At a basic level configure the endpoint with a transport that is set up
-; with the appropriate NAT settings. There may be some additional settings you
-; need here based on your NAT/Firewall scenario. Look to the CLI config help
-; "config show help res_pjsip endpoint" or on the wiki for other NAT related
-; options and configuration. We've included a few below.
-;
-; AOR
-;
-; Endpoints use one or more AOR sections to store their contact details.
-; You can define multiple contact addresses in SIP URI format in multiple
-; "contact=" entries.
-;
-
-;[mytrunk]
-;type=endpoint
-;transport=transport-udp
-;context=from-external
-;disallow=all
-;allow=ulaw
-;outbound_auth=mytrunk_auth
-;aors=mytrunk
-;                   ;A few NAT relevant options that may come in handy.
-;force_rport=yes    ;It's a good idea to read the configuration help for each
-;direct_media=no    ;of these options.
-;ice_support=yes
-
-;[mytrunk]
-;type=aor
-;contact=sip:198.51.100.1:5060
-;contact=sip:198.51.100.2:5060
-
-;[mytrunk]
-;type=identify
-;endpoint=mytrunk
-;match=198.51.100.1
-;match=198.51.100.2
-
-
-;=============ENDPOINT CONFIGURED AS A TRUNK, INBOUND AUTH AND REGISTRATION===
-;
-; Here we are allowing a remote device to register to Asterisk and requiring
-; that they authenticate for registration and calls.
-; You'll note that this configuration is essentially the same as configuring
-; an endpoint for use with a SIP phone.
-
-
-;[7000]
-;type=endpoint
-;context=from-external
-;disallow=all
-;allow=ulaw
-;transport=transport-udp
-;auth=7000
-;aors=7000
-
-;[7000]
-;type=auth
-;auth_type=userpass
-;password=7000
-;username=7000
-
-;[7000]
-;type=aor
-;max_contacts=1
-
-
-;===============ENDPOINT CONFIGURED FOR USE WITH A SIP PHONE==================
-;
-; This example includes the endpoint, auth and aor configurations. It
-; requires inbound authentication and allows registration, as well as references
-; a transport that you'll need to uncomment from the previous examples.
-;
-; Uncomment one of the transport lines to choose which transport you want. If
-; not specified then the default transport chosen is the first defined transport
-; in the configuration file.
-;
-; Modify the "max_contacts=" line to change how many unique registrations to allow.
-;
-; Use the "contact=" line instead of max_contacts= if you want to statically
-; define the location of the device.
-;
-; If using the TLS enabled transport, you may want the "media_encryption=sdes"
-; option to additionally enable SRTP, though they are not mutually inclusive.
-;
-; Use the "rtp_ipv6=yes" option if you want to utilize RTP over an ipv6 transport.
-;
-; If this endpoint were remote, and it was using a transport configured for NAT
-; then you likely want to use "direct_media=no" to prevent audio issues.
-
-
-;[6001]
-;type=endpoint
-;transport=transport-udp
-;context=from-internal
-;disallow=all
-;allow=ulaw
-;allow=gsm
-;auth=6001
-;aors=6001
-;
-; A few more transports to pick from, and some related options below them.
-;
-;transport=transport-tls
-;media_encryption=sdes
-;transport=transport-udp-ipv6
-;rtp_ipv6=yes
-;transport=transport-udp-nat
-;direct_media=no
-;
-; MWI related options
-
-;aggregate_mwi=yes
-;mailboxes=6001 at default,7001 at default
-;mwi_from_user=6001
-;
-; Extension and Device state options
-;
-;device_state_busy_at=1
-;allow_subscribe=yes
-;sub_min_expiry=30
-
-;[6001]
-;type=auth
-;auth_type=userpass
-;password=6001
-;username=6001
-
-;[6001]
-;type=aor
-;max_contacts=1
-;contact=sip:6001 at 192.0.2.1:5060
-
-;===============ENDPOINT BEHIND NAT OR FIREWALL===============================
-;
-; This example assumes your transport is configured with a public IP and the
-; endpoint itself is behind NAT and maybe a firewall, rather than having
-; Asterisk behind NAT. For the sake of simplicity, we'll assume a typical
-; VOIP phone. The most important settings to configure are:
-;
-;  * direct_media, to ensure Asterisk stays in the media path
-;  * rtp_symmetric and force_rport options to help the far-end NAT/firewall
-;
-; Depending on the settings of your remote SIP device or NAT/firewall device
-; you may have to experiment with a combination of these settings.
-;
-; If both Asterisk and the remote phones are a behind NAT/firewall then you'll
-; have to make sure to use a transport with appropriate settings (as in the
-; transport-udp-nat example).
-;
-;[6002]
-;type=endpoint
-;transport=transport-udp
-;context=from-internal
-;disallow=all
-;allow=ulaw
-;auth=6002
-;aors=6002
-;direct_media=no
-;rtp_symmetric=yes
-;force_rport=yes
-;rewrite_contact=yes  ; necessary if endpoint does not know/register public ip:port
-;ice_support=yes   ;This is specific to clients that support NAT traversal
-                   ;for media via ICE,STUN,TURN. See the wiki at:
-                   ;https://wiki.asterisk.org/wiki/x/D4FHAQ
-                   ;for a deeper explanation of this topic.
-
-;[6002]
-;type=auth
-;auth_type=userpass
-;password=6002
-;username=6002
-
-;[6002]
-;type=aor
-;max_contacts=2
-
-
-;============EXAMPLE ACL CONFIGURATION==========================================
-;
-; The ACL or Access Control List section defines a set of permissions to permit
-; or deny access to various address or addresses. Alternatively it references an
-; ACL configuration already set in acl.conf.
-;
-; The ACL configuration is independent of individual endpoint configuration and
-; operates on all inbound SIP communication using res_pjsip.
-
-; Reference an ACL defined in acl.conf.
-;
-;[acl]
-;type=acl
-;acl=example_named_acl1
-
-; Reference a contactacl specifically.
-;
-;[acl]
-;type=acl
-;contact_acl=example_contact_acl1
-
-; Define your own ACL here in pjsip.conf and
-; permit or deny by IP address or range.
-;
-;[acl]
-;type=acl
-;deny=0.0.0.0/0.0.0.0
-;permit=209.16.236.0/24
-;deny=209.16.236.1
-
-; Restrict based on Contact Headers rather than IP.
-; Define options multiple times for various addresses or use a comma-delimited string.
-;
-;[acl]
-;type=acl
-;contact_deny=0.0.0.0/0.0.0.0
-;contact_permit=209.16.236.0/24
-;contact_permit=209.16.236.1
-;contact_permit=209.16.236.2,209.16.236.3
-
-; Restrict based on Contact Headers rather than IP and use
-; advanced syntax. Note the bang symbol used for "NOT", so we can deny
-; 209.16.236.12/32 within the permit= statement.
-;
-;[acl]
-;type=acl
-;contact_deny=0.0.0.0/0.0.0.0
-;contact_permit=209.16.236.0
-;permit=209.16.236.0/24, !209.16.236.12/32
-
-
-;============EXAMPLE RLS CONFIGURATION==========================================
-;
-;Asterisk provides support for RFC 4662 Resource List Subscriptions. This allows
-;for an endpoint to, through a single subscription, subscribe to the states of
-;multiple resources. Resource lists are configured in pjsip.conf using the
-;resource_list configuration object. Below is an example of a resource list that
-;allows an endpoint to subscribe to the presence of alice, bob, and carol.
-
-;[my_list]
-;type=resource_list
-;list_item=alice
-;list_item=bob
-;list_item=carol
-;event=presence
-
-;The "event" option in the resource list corresponds to the SIP event-package
-;that the subscribed resources belong to. A resource list can only provide states
-;for resources that belong to the same event-package. This means that you cannot
-;create a list that is a combination of presence and message-summary resources,
-;for instance. Any event-package that Asterisk supports can be used in a resource
-;list (presence, dialog, and message-summary). Whenever support for a new event-
-;package is added to Asterisk, support for that event-package in resource lists
-;will automatically be supported.
-
-;The "list_item" options indicate the names of resources to subscribe to. The
-;way these are interpreted is event-package specific. For instance, with presence
-;list_items, hints in the dialplan are looked up. With message-summary list_items,
-;mailboxes are looked up using your installed voicemail provider (app_voicemail
-;by default). Note that in the above example, the list_item options were given
-;one per line. However, it is also permissible to provide multiple list_item
-;options on a single line (e.g. list_item = alice,bob,carol).
-
-;In addition to the options presented in the above configuration, there are two
-;more configuration options that can be set.
-; * full_state: dictates whether Asterisk should always send the states of
-;   all resources in the list at once. Defaults to "no". You should only set
-;   this to "yes" if you are interoperating with an endpoint that does not
-;   behave correctly when partial state notifications are sent to it.
-; * notification_batch_interval: By default, Asterisk will send a NOTIFY request
-;   immediately when a resource changes state. This option causes Asterisk to
-;   start batching resource state changes for the specified number of milliseconds
-;   after a resource changes states. This way, if multiple resources change state
-;   within a brief interval, Asterisk can send a single NOTIFY request with all
-;   of the state changes reflected in it.
-
-;There is a limitation to the size of resource lists in Asterisk. If a constructed
-;notification from Asterisk will exceed 64000 bytes, then the message is deemed
-;too large to send. If you find that you are seeing error messages about SIP
-;NOTIFY requests being too large to send, consider breaking your lists into
-;sub-lists.
-
-;============EXAMPLE PHONEPROV CONFIGURATION================================
-
-; Before configuring provisioning here, see the documentation for res_phoneprov
-; and configure phoneprov.conf appropriately.
-
-; For each user to be autoprovisioned, a [phoneprov] configuration section
-; must be created.  At a minimum, the 'type', 'PROFILE' and 'MAC' variables must
-; be set.  All other variables are optional.
-; Example:
-
-;[1000]
-;type=phoneprov               ; must be specified as 'phoneprov'
-;endpoint=1000                ; Required only if automatic setting of
-                              ; USERNAME, SECRET, DISPLAY_NAME and CALLERID
-                              ; are needed.
-;PROFILE=digium               ; required
-;MAC=deadbeef4dad             ; required
-;SERVER=myserver.example.com  ; A standard variable
-;TIMEZONE=America/Denver      ; A standard variable
-;MYVAR=somevalue              ; A user confdigured variable
-
-; If the phoneprov sections have common variables, it is best to create a
-; phoneprov template.  The example below will produce the same configuration
-; as the one specified above except that MYVAR will be overridden for
-; the specific user.
-; Example:
-
-;[phoneprov_defaults](!)
-;type=phoneprov               ; must be specified as 'phoneprov'
-;PROFILE=digium               ; required
-;SERVER=myserver.example.com  ; A standard variable
-;TIMEZONE=America/Denver      ; A standard variable
-;MYVAR=somevalue              ; A user configured variable
-
-;[1000](phoneprov_defaults)
-;endpoint=1000                ; Required only if automatic setting of
-                              ; USERNAME, SECRET, DISPLAY_NAME and CALLERID
-                              ; are needed.
-;MAC=deadbeef4dad             ; required
-;MYVAR=someOTHERvalue         ; A user confdigured variable
-
-; To have USERNAME and SECRET automatically set, the endpoint
-; specified here must in turn have an outbound_auth section defined.
-
-; Fuller example:
-
-;[1000]
-;type=endpoint
-;outbound_auth=1000-auth
-;callerid=My Name <8005551212>
-;transport=transport-udp-nat
-
-;[1000-auth]
-;type=auth
-;auth_type=userpass
-;username=myname
-;password=mysecret
-
-;[phoneprov_defaults](!)
-;type=phoneprov               ; must be specified as 'phoneprov'
-;PROFILE=someprofile          ; required
-;SERVER=myserver.example.com  ; A standard variable
-;TIMEZONE=America/Denver      ; A standard variable
-;MYVAR=somevalue              ; A user configured variable
-
-;[1000](phoneprov_defaults)
-;endpoint=1000                ; Required only if automatic setting of
-                              ; USERNAME, SECRET, DISPLAY_NAME and CALLERID
-                              ; are needed.
-;MAC=deadbeef4dad             ; required
-;MYVAR=someUSERvalue          ; A user confdigured variable
-;LABEL=1000                   ; A standard variable
-
-; The previous sections would produce a template substitution map as follows:
-
-;MAC=deadbeef4dad               ;added by pp1000
-;USERNAME=myname                ;automatically added by 1000-auth username
-;SECRET=mysecret                ;automatically added by 1000-auth password
-;PROFILE=someprofile            ;added by defaults
-;SERVER=myserver.example.com    ;added by defaults
-;SERVER_PORT=5060               ;added by defaults
-;MYVAR=someUSERvalue            ;added by defaults but overdidden by user
-;CALLERID=8005551212            ;automatically added by 1000 callerid
-;DISPLAY_NAME=My Name           ;automatically added by 1000 callerid
-;TIMEZONE=America/Denver        ;added by defaults
-;TZOFFSET=252100                ;automatically calculated by res_phoneprov
-;DST_ENABLE=1                   ;automatically calculated by res_phoneprov
-;DST_START_MONTH=3              ;automatically calculated by res_phoneprov
-;DST_START_MDAY=9               ;automatically calculated by res_phoneprov
-;DST_START_HOUR=3               ;automatically calculated by res_phoneprov
-;DST_END_MONTH=11               ;automatically calculated by res_phoneprov
-;DST_END_MDAY=2                 ;automatically calculated by res_phoneprov
-;DST_END_HOUR=1                 ;automatically calculated by res_phoneprov
-;ENDPOINT_ID=1000               ;automatically added by this module
-;AUTH_ID=1000-auth              ;automatically added by this module
-;TRANSPORT_ID=transport-udp-nat ;automatically added by this module
-;LABEL=1000                     ;added by user
-
-; MODULE PROVIDING BELOW SECTION(S): res_pjsip
-;==========================ENDPOINT SECTION OPTIONS=========================
-;[endpoint]
-;  SYNOPSIS: Endpoint
-;100rel=yes     ; Allow support for RFC3262 provisional ACK tags (default:
-                ; "yes")
-;aggregate_mwi=yes      ;  (default: "yes")
-;allow= ; Media Codec s to allow (default: "")
-;aors=  ; AoR s to be used with the endpoint (default: "")
-;auth=  ; Authentication Object s associated with the endpoint (default: "")
-;callerid=      ; CallerID information for the endpoint (default: "")
-;callerid_privacy=allowed_not_screened      ; Default privacy level (default: "allowed_not_screened")
-;callerid_tag=  ; Internal id_tag for the endpoint (default: "")
-;context=default        ; Dialplan context for inbound sessions (default:
-                        ; "default")
-;direct_media_glare_mitigation=none     ; Mitigation of direct media re INVITE
-                                        ; glare (default: "none")
-;direct_media_method=invite     ; Direct Media method type (default: "invite")
-;connected_line_method=invite   ; Connected line method type (default:
-                                ; "invite")
-;direct_media=yes       ; Determines whether media may flow directly between
-                        ; endpoints (default: "yes")
-;disable_direct_media_on_nat=no ; Disable direct media session refreshes when
-                                ; NAT obstructs the media session (default:
-                                ; "no")
-;disallow=      ; Media Codec s to disallow (default: "")
-;dtmf_mode=rfc4733      ; DTMF mode (default: "rfc4733")
-;media_address=         ; IP address used in SDP for media handling (default: "")
-;force_rport=yes        ; Force use of return port (default: "yes")
-;ice_support=no ; Enable the ICE mechanism to help traverse NAT (default: "no")
-;identify_by=username   ; Way s for Endpoint to be identified (default:
-                        ; "username")
-;redirect_method=user   ; How redirects received from an endpoint are handled
-                        ; (default: "user")
-;mailboxes=     ; Mailbox es to be associated with (default: "")
-;moh_suggest=default    ; Default Music On Hold class (default: "default")
-;outbound_auth= ; Authentication object used for outbound requests (default:
-                ; "")
-;outbound_proxy=        ; Proxy through which to send requests a full SIP URI
-                        ; must be provided (default: "")
-;rewrite_contact=no     ; Allow Contact header to be rewritten with the source
-                        ; IP address port (default: "no")
-;rtp_ipv6=no    ; Allow use of IPv6 for RTP traffic (default: "no")
-;rtp_symmetric=no       ; Enforce that RTP must be symmetric (default: "no")
-;send_diversion=yes     ; Send the Diversion header conveying the diversion
-                        ; information to the called user agent (default: "yes")
-;send_pai=no    ; Send the P Asserted Identity header (default: "no")
-;send_rpid=no   ; Send the Remote Party ID header (default: "no")
-;timers_min_se=90       ; Minimum session timers expiration period (default:
-                        ; "90")
-;timers=yes     ; Session timers for SIP packets (default: "yes")
-;timers_sess_expires=1800       ; Maximum session timer expiration period
-                                ; (default: "1800")
-;transport=     ; Desired transport configuration (default: "")
-;trust_id_inbound=no    ; Accept identification information received from this
-                        ; endpoint (default: "no")
-;trust_id_outbound=no   ; Send private identification details to the endpoint
-                        ; (default: "no")
-;type=  ; Must be of type endpoint (default: "")
-;use_ptime=no   ; Use Endpoint s requested packetisation interval (default:
-                ; "no")
-;use_avpf=no    ; Determines whether res_pjsip will use and enforce usage of
-                ; AVPF for this endpoint (default: "no")
-;media_encryption=no    ; Determines whether res_pjsip will use and enforce
-                        ; usage of media encryption for this endpoint (default:
-                        ; "no")
-;media_encryption_optimistic=no ; Use encryption if possible but don't fail the call
-								; if not possible.
-;inband_progress=no     ; Determines whether chan_pjsip will indicate ringing
-                        ; using inband progress (default: "no")
-;call_group=    ; The numeric pickup groups for a channel (default: "")
-;pickup_group=  ; The numeric pickup groups that a channel can pickup (default:
-                ; "")
-;named_call_group=      ; The named pickup groups for a channel (default: "")
-;named_pickup_group=    ; The named pickup groups that a channel can pickup
-                        ; (default: "")
-;device_state_busy_at=0 ; The number of in use channels which will cause busy
-                        ; to be returned as device state (default: "0")
-;t38_udptl=no   ; Whether T 38 UDPTL support is enabled or not (default: "no")
-;t38_udptl_ec=none      ; T 38 UDPTL error correction method (default: "none")
-;t38_udptl_maxdatagram=0        ; T 38 UDPTL maximum datagram size (default:
-                                ; "0")
-;fax_detect=no  ; Whether CNG tone detection is enabled (default: "no")
-;t38_udptl_nat=no       ; Whether NAT support is enabled on UDPTL sessions
-                        ; (default: "no")
-;t38_udptl_ipv6=no      ; Whether IPv6 is used for UDPTL Sessions (default:
-                        ; "no")
-;tone_zone=     ; Set which country s indications to use for channels created
-                ; for this endpoint (default: "")
-;language=      ; Set the default language to use for channels created for this
-                ; endpoint (default: "")
-;one_touch_recording=no ; Determines whether one touch recording is allowed for
-                        ; this endpoint (default: "no")
-;record_on_feature=automixmon   ; The feature to enact when one touch recording
-                                ; is turned on (default: "automixmon")
-;record_off_feature=automixmon  ; The feature to enact when one touch recording
-                                ; is turned off (default: "automixmon")
-;rtp_engine=asterisk    ; Name of the RTP engine to use for channels created
-                        ; for this endpoint (default: "asterisk")
-;allow_transfer=yes     ; Determines whether SIP REFER transfers are allowed
-                        ; for this endpoint (default: "yes")
-;sdp_owner=-    ; String placed as the username portion of an SDP origin o line
-                ; (default: "-")
-;sdp_session=Asterisk   ; String used for the SDP session s line (default:
-                        ; "Asterisk")
-;tos_audio=0    ; DSCP TOS bits for audio streams (default: "0")
-;tos_video=0    ; DSCP TOS bits for video streams (default: "0")
-;cos_audio=0    ; Priority for audio streams (default: "0")
-;cos_video=0    ; Priority for video streams (default: "0")
-;allow_subscribe=yes    ; Determines if endpoint is allowed to initiate
-                        ; subscriptions with Asterisk (default: "yes")
-;sub_min_expiry=0       ; The minimum allowed expiry time for subscriptions
-                        ; initiated by the endpoint (default: "0")
-;from_user=     ; Username to use in From header for requests to this endpoint
-                ; (default: "")
-;mwi_from_user= ; Username to use in From header for unsolicited MWI NOTIFYs to
-                ; this endpoint (default: "")
-;from_domain=   ; Domain to user in From header for requests to this endpoint
-                ; (default: "")
-;dtls_verify=no ; Verify that the provided peer certificate is valid (default:
-                ; "no")
-;dtls_rekey=0   ; Interval at which to renegotiate the TLS session and rekey
-                ; the SRTP session (default: "0")
-;dtls_cert_file=        ; Path to certificate file to present to peer (default:
-                        ; "")
-;dtls_private_key=      ; Path to private key for certificate file (default:
-                        ; "")
-;dtls_cipher=   ; Cipher to use for DTLS negotiation (default: "")
-;dtls_ca_file=  ; Path to certificate authority certificate (default: "")
-;dtls_ca_path=  ; Path to a directory containing certificate authority
-                ; certificates (default: "")
-;dtls_setup=    ; Whether we are willing to accept connections connect to the
-                ; other party or both (default: "")
-;dtls_fingerprint= ; Hash to use for the fingerprint placed into SDP
-                   ; (default: "SHA-256")
-;srtp_tag_32=no ; Determines whether 32 byte tags should be used instead of 80
-                ; byte tags (default: "no")
-;set_var=       ; Variable set on a channel involving the endpoint. For multiple
-		; channel variables specify multiple 'set_var'(s)
-
-;==========================AUTH SECTION OPTIONS=========================
-;[auth]
-;  SYNOPSIS: Authentication type
-;auth_type=userpass     ; Authentication type (default: "userpass")
-;nonce_lifetime=32      ; Lifetime of a nonce associated with this
-                        ; authentication config (default: "32")
-;md5_cred=      ; MD5 Hash used for authentication (default: "")
-;password=      ; PlainText password used for authentication (default: "")
-;realm= ; SIP realm for endpoint (default: "")
-;type=  ; Must be auth (default: "")
-;username=      ; Username to use for account (default: "")
-
-
-;==========================DOMAIN_ALIAS SECTION OPTIONS=========================
-;[domain_alias]
-;  SYNOPSIS: Domain Alias
-;type=  ; Must be of type domain_alias (default: "")
-;domain=        ; Domain to be aliased (default: "")
-
-
-;==========================TRANSPORT SECTION OPTIONS=========================
-;[transport]
-;  SYNOPSIS: SIP Transport
-;async_operations=1     ; Number of simultaneous Asynchronous Operations
-                        ; (default: "1")
-;bind=  ; IP Address and optional port to bind to for this transport (default:
-        ; "")
-;ca_list_file=  ; File containing a list of certificates to read TLS ONLY
-                ; (default: "")
-;cert_file=     ; Certificate file for endpoint TLS ONLY
-                ; Will read .crt or .pem file but only uses cert,
-                ; a .key file must be specified via priv_key_file
-                ; (default: "")
-;cipher=        ; Preferred cryptography cipher names TLS ONLY (default: "")
-;domain=        ; Domain the transport comes from (default: "")
-;external_media_address=        ; External IP address to use in RTP handling
-                                ; (default: "")
-;external_signaling_address=    ; External address for SIP signalling (default:
-                                ; "")
-;external_signaling_port=0      ; External port for SIP signalling (default:
-                                ; "0")
-;method=        ; Method of SSL transport TLS ONLY (default: "")
-;local_net=     ; Network to consider local used for NAT purposes (default: "")
-;password=      ; Password required for transport (default: "")
-;priv_key_file= ; Private key file TLS ONLY (default: "")
-;protocol=udp   ; Protocol to use for SIP traffic (default: "udp")
-;require_client_cert=   ; Require client certificate TLS ONLY (default: "")
-;type=  ; Must be of type transport (default: "")
-;verify_client= ; Require verification of client certificate TLS ONLY (default:
-                ; "")
-;verify_server= ; Require verification of server certificate TLS ONLY (default:
-                ; "")
-;tos=0  ; Enable TOS for the signalling sent over this transport (default: "0")
-;cos=0  ; Enable COS for the signalling sent over this transport (default: "0")
-;websocket_write_timeout=100    ; Default write timeout to set on websocket
-                                ; transports. This value may need to be adjusted
-                                ; for connections where Asterisk must write a
-                                ; substantial amount of data and the receiving
-                                ; clients are slow to process the received
-                                ; information. Value is in milliseconds; default
-                                ; is 100 ms.
-
-;==========================CONTACT SECTION OPTIONS=========================
-;[contact]
-;  SYNOPSIS: A way of creating an aliased name to a SIP URI
-;type=  ; Must be of type contact (default: "")
-;uri=   ; SIP URI to contact peer (default: "")
-;expiration_time=       ; Time to keep alive a contact (default: "")
-;qualify_frequency=0    ; Interval at which to qualify a contact (default: "0")
-;outbound_proxy=        ; Outbound proxy used when sending OPTIONS request
-                        ; (default: "")
-
-
-;==========================AOR SECTION OPTIONS=========================
-;[aor]
-;  SYNOPSIS: The configuration for a location of an endpoint
-;contact=       ; Permanent contacts assigned to AoR (default: "")
-;default_expiration=3600        ; Default expiration time in seconds for
-                                ; contacts that are dynamically bound to an AoR
-                                ; (default: "3600")
-;mailboxes=     ; Mailbox es to be associated with (default: "")
-;maximum_expiration=7200        ; Maximum time to keep an AoR (default: "7200")
-;max_contacts=0 ; Maximum number of contacts that can bind to an AoR (default:
-                ; "0")
-;minimum_expiration=60  ; Minimum keep alive time for an AoR (default: "60")
-;remove_existing=no     ; Determines whether new contacts replace existing ones
-                        ; (default: "no")
-;type=  ; Must be of type aor (default: "")
-;qualify_frequency=0    ; Interval at which to qualify an AoR (default: "0")
-;authenticate_qualify=no        ; Authenticates a qualify request if needed
-                                ; (default: "no")
-;outbound_proxy=        ; Outbound proxy used when sending OPTIONS request
-                        ; (default: "")
-
-
-;==========================SYSTEM SECTION OPTIONS=========================
-;[system]
-;  SYNOPSIS: Options that apply to the SIP stack as well as other system-wide settings
-;timer_t1=500   ; Set transaction timer T1 value milliseconds (default: "500")
-;timer_b=32000  ; Set transaction timer B value milliseconds (default: "32000")
-;compact_headers=no     ; Use the short forms of common SIP header names
-                        ; (default: "no")
-;threadpool_initial_size=0      ; Initial number of threads in the res_pjsip
-                                ; threadpool (default: "0")
-;threadpool_auto_increment=5    ; The amount by which the number of threads is
-                                ; incremented when necessary (default: "5")
-;threadpool_idle_timeout=60     ; Number of seconds before an idle thread
-                                ; should be disposed of (default: "60")
-;threadpool_max_size=0  ; Maximum number of threads in the res_pjsip threadpool
-                        ; A value of 0 indicates no maximum (default: "0")
-;disable_tcp_switch=yes ; Disable automatic switching from UDP to TCP transports
-                        ; if outgoing request is too large.
-                        ; See RFC 3261 section 18.1.1.
-						; Disabling this option has been known to cause interoperability
-						; issues, so disable at your own risk.
-                        ; (default: "yes")
-;type=  ; Must be of type system (default: "")
-
-;==========================GLOBAL SECTION OPTIONS=========================
-;[global]
-;  SYNOPSIS: Options that apply globally to all SIP communications
-;max_forwards=70        ; Value used in Max Forwards header for SIP requests
-                        ; (default: "70")
-;type=  ; Must be of type global (default: "")
-;user_agent=Asterisk PBX SVN-branch-12-r404375  ; Value used in User Agent
-                                                ; header for SIP requests and
-                                                ; Server header for SIP
-                                                ; responses (default: "Asterisk
-                                                ; PBX SVN-branch-12-r404375")
-;default_outbound_endpoint=default_outbound_endpoint    ; Endpoint to use when
-                                                        ; sending an outbound
-                                                        ; request to a URI
-                                                        ; without a specified
-                                                        ; endpoint (default: "d
-                                                        ; efault_outbound_endpo
-                                                        ; int")
-;debug=no ; Enable/Disable SIP debug logging.  Valid options include yes|no
-          ; or a host address (default: "no")
-
-
-; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl
-;==========================ACL SECTION OPTIONS=========================
-;[acl]
-;  SYNOPSIS: Access Control List
-;acl=   ; List of IP ACL section names in acl conf (default: "")
-;contact_acl=   ; List of Contact ACL section names in acl conf (default: "")
-;contact_deny=  ; List of Contact header addresses to deny (default: "")
-;contact_permit=        ; List of Contact header addresses to permit (default:
-                        ; "")
-;deny=  ; List of IP addresses to deny access from (default: "")
-;permit=        ; List of IP addresses to permit access from (default: "")
-;type=  ; Must be of type acl (default: "")
-
-
-
-
-; MODULE PROVIDING BELOW SECTION(S): res_pjsip_outbound_registration
-;==========================REGISTRATION SECTION OPTIONS=========================
-;[registration]
-;  SYNOPSIS: The configuration for outbound registration
-;auth_rejection_permanent=yes   ; Determines whether failed authentication
-                                ; challenges are treated as permanent failures
-                                ; (default: "yes")
-;client_uri=    ; Client SIP URI used when attemping outbound registration
-                ; (default: "")
-;contact_user=  ; Contact User to use in request (default: "")
-;expiration=3600        ; Expiration time for registrations in seconds
-                        ; (default: "3600")
-;max_retries=10 ; Maximum number of registration attempts (default: "10")
-;outbound_auth= ; Authentication object to be used for outbound registrations
-                ; (default: "")
-;outbound_proxy=        ; Outbound Proxy used to send registrations (default:
-                        ; "")
-;retry_interval=60      ; Interval in seconds between retries if outbound
-                        ; registration is unsuccessful (default: "60")
-;forbidden_retry_interval=0     ; Interval used when receiving a 403 Forbidden
-                                ; response (default: "0")
-;server_uri=    ; SIP URI of the server to register against (default: "")
-;transport=     ; Transport used for outbound authentication (default: "")
-;type=  ; Must be of type registration (default: "")
-
-
-
-
-; MODULE PROVIDING BELOW SECTION(S): res_pjsip_endpoint_identifier_ip
-;==========================IDENTIFY SECTION OPTIONS=========================
-;[identify]
-;  SYNOPSIS: Identifies endpoints via source IP address
-;endpoint=      ; Name of Endpoint (default: "")
-;match= ; IP addresses or networks to match against (default: "")
-;type=  ; Must be of type identify (default: "")
-
-
-
-
-;========================PHONEPROV_USER SECTION OPTIONS=======================
-;[phoneprov]
-;  SYNOPSIS: Contains variables for autoprovisioning each user
-;endpoint=      ; The endpoint from which to gather username, secret, etc. (default: "")
-;PROFILE=       ; The name of a profile configured in phoneprov.conf (default: "")
-;MAC=           ; The mac address for this user (default: "")
-;OTHERVAR=      ; Any other name value pair to be used in templates (default: "")
-                ; Common variables include LINE, LINEKEYS, etc.
-                ; See phoneprov.conf.sample for others.
-;type=          ; Must be of type phoneprov (default: "")
diff --git a/configs/samples/pjsip_notify.conf.sample b/configs/samples/pjsip_notify.conf.sample
deleted file mode 100644
index 8224ee1..0000000
--- a/configs/samples/pjsip_notify.conf.sample
+++ /dev/null
@@ -1,57 +0,0 @@
-; rfc3842
-; put empty "Content=>" at the end to have CRLF after last body line
-
-[clear-mwi]
-Event=>message-summary
-Content-type=>application/simple-message-summary
-Content=>Messages-Waiting: no
-Content=>Message-Account: sip:asterisk at 127.0.0.1
-Content=>Voice-Message: 0/0 (0/0)
-Content=>
-
-; Aastra
-
-[aastra-check-cfg]
-Event=>check-sync
-
-[aastra-xml]
-Event=>aastra-xml
-
-; Digium
-
-[digium-check-cfg]
-Event=>check-sync
-
-; Linksys
-
-[linksys-cold-restart]
-Event=>reboot_now
-
-[linksys-warm-restart]
-Event=>restart_now
-
-; Polycom
-
-[polycom-check-cfg]
-Event=>check-sync
-
-; Sipura
-
-[sipura-check-cfg]
-Event=>resync
-
-[sipura-get-report]
-Event=>report
-
-; snom
-
-[snom-check-cfg]
-Event=>check-sync\;reboot=false
-
-[snom-reboot]
-Event=>check-sync\;reboot=true
-
-; Cisco
-
-[cisco-check-cfg]
-Event=>check-sync
diff --git a/configs/samples/res_parking.conf.sample b/configs/samples/res_parking.conf.sample
deleted file mode 100644
index d24be20..0000000
--- a/configs/samples/res_parking.conf.sample
+++ /dev/null
@@ -1,121 +0,0 @@
-[general]
-;parkeddynamic = yes            ; Enables dynamically created parkinglots. (default is no)
-
-; A parking lot named 'default' will automatically be used when no other
-; named parking lot is indicated for use by the park application or a
-; channel's parkinglot function and PARKINGLOT channel variable. This parking
-; lot is guaranteed to exist and will be created even if default is left out of
-; the configuration file.
-
-[default]                       ; Default Parking Lot
-parkext => 700                  ; What extension to dial to park. (optional; if
-                                ; specified, extensions will be created for parkext and
-                                ; the whole range of parkpos)
-
-;parkext_exclusive=yes          ; Specify that the parkext created for this parking lot
-                                ; will only access this parking lot. (default is no)
-
-parkpos => 701-720              ; What range of parking spaces to use - must be numeric
-                                ; Creates these spaces as extensions if parkext is set.
-                                ; Since this value is interpreted numerically, leading 0's
-                                ; will be ignored (so expect 00700-00720 to map to 700-720)
-
-context => parkedcalls          ; Which context parked calls and the default park
-
-;parkinghints = no              ; Add hints priorities automatically for parkpos
-                                ; extensions if parkext is set
-
-;parkingtime => 45              ; Number of seconds a call can be parked before returning
-
-;comebacktoorigin = yes         ; Setting this option configures the behavior of call parking when the
-                                ; parked call times out (See the parkingtime option).  The default value is 'yes'.
-                                ;
-                                ; 'yes' - When the parked call times out, attempt to send the call back to the peer
-                                ;         that parked this call. This is done by saving off the name of the channel
-                                ;         that parked the call. The call will return to the context 'park-dial' and
-                                ;         an extension created based on the name of the channel that originally parked
-                                ;         the call.  This extension will be created automatically to do a Dial() to the
-                                ;         device that originally parked the call for comebacktodialtime seconds. If the
-                                ;         call is not answered, the call will proceed to the next priority (usually none
-                                ;         unless you deliberately set up a catch-all second priority in the park-call
-                                ;         context) in the dialplan for extension matching the peer name (same as how
-                                ;         peer names are flattened into extensions when comebacktoorigin is 'no').
-                                ;
-                                ; 'no'  - This option is useful for performing custom dialplan functionality prior to
-                                ;         sending the call back to the extension that initially parked the call, or to
-                                ;         an entirely different destination.
-                                ;
-                                ;         When the parked call times out, send it back to the dialplan.  The location
-                                ;         will be defined by the comebackcontext option. The extension will be built from
-                                ;         the saved channel name that parked the call. For example, if a SIP peer named
-                                ;         '0004F2040001' parked this call, the extension will be 'SIP_0004F2040001'.
-                                ;         (Note that an underscore is used here because the '/' character has a special
-                                ;         meaning in extension names for CallerID matching.)  If this extension does not
-                                ;         exist, the call will be sent to the 's' extension, instead.  Finally, if the 's'
-                                ;         extension of 'parkedcallstimeout' does not exist, the call will fall back to the
-                                ;         's' extension of the 'default' context.
-                                ;
-                                ;         Additionally, in this example an extension of 'SIP_0004F2040001' will be
-                                ;         created in the 'park-dial' context.  This extension will be set up to do a
-                                ;         Dial() to 'SIP/0004F2040001'.
-                                ;
-                                ; During the timeout procedure, the following variables are set
-                                ; PARKINGSLOT - extension that the call was parked in prior to timing out
-                                ; PARKEDLOT - name of the lot that the call was parked in prior to timing out
-                                ; PARKER - dial string to call the device that parked the call
-
-;comebackdialtime = 30          ; When a parked call times out, this is the number of seconds to dial the device that
-                                ; originally parked the call.  It is also available as a channel variable COMEBACKDIALTIME
-                                ; after a parked call has timed out.
-                                ; The default value is 30 seconds.
-
-;comebackcontext = parkedcallstimeout
-                                ; The context a timed out call will return to if comebcktoorigin=no.
-                                ; The default value is 'parkedcallstimeout'.
-
-;courtesytone = beep            ; Sound file to play to when someone picks up a parked call
-                                ; and also when the Touch Monitor is activated/deactivated.
-                                ; Default is no tone.
-
-;parkedplay = caller            ; Who to play courtesytone to when picking up a parked call.
-                                ; One of: parked, caller, both  (default is caller)
-
-;parkedcalltransfers = caller   ; Enables or disables DTMF based transfers when picking up a parked call.
-                                ; one of: callee, caller, both, no (default is no)
-
-;parkedcallreparking = caller   ; Enables or disables DTMF based parking when picking up a parked call.
-                                ; one of: callee, caller, both, no (default is no)
-
-;parkedcallhangup = caller      ; Enables or disables DTMF based hangups when picking up a parked call.
-                                ; one of: callee, caller, both, no (default is no)
-
-;findslot => next               ; Sets the method for selecting parking spaces when a call is parked
-                                ; 'next' - use the next parking space from the most recently used one.
-                                ; 'first' - use the lowest numbered parking space available
-
-;parkedmusicclass = default     ; This is the MOH class to use for the parked channel
-                                ; as long as the class is not set on the channel directly
-                                ; using Set(CHANNEL(musicclass)=whatever) in the dialplan
-
-;*** Define another parking lot
-;
-; The parkinglot used can be set with the CHANNEL(parkinglot) dialplan function or by
-; setting the 'parkinglot' configuration for a channel in its configuration file.
-;
-; Parking lots can now be any named configuration category aside from
-; 'general' which is reserved for general options. They no longer need to be
-; prefixed with 'parkinglot_'
-;
-;[edvina]
-;context => edvina_park
-;parkpos => 800-850
-;findslot => next
-;comebacktoorigin = no
-;comebackdialtime = 90
-;comebackcontext = edvinapark-timeout
-;parkedmusicclass = edvina
-;
-; Since edvina doesn't define parkext, extensions won't automatically be
-; created for parking to it or for retrieving calls from it. These can be
-; created manually in the dial plan by using the Park and ParkedCall
-; applications.
diff --git a/configs/samples/sorcery.conf.sample b/configs/samples/sorcery.conf.sample
deleted file mode 100644
index 7406214..0000000
--- a/configs/samples/sorcery.conf.sample
+++ /dev/null
@@ -1,67 +0,0 @@
-; Sample configuration file for Sorcery Data Access Layer
-
-;
-; Wizards
-;
-; Wizards are the persistence mechanism for objects. They are loaded as Asterisk modules and register
-; themselves with the sorcery core. All implementation specific details of how objects are persisted is isolated
-; within wizards.
-;
-
-;
-; Caching
-;
-; A wizard can optionally be marked as an object cache by adding "/cache" to the object type within the mapping.
-; If an object is returned from a non-object cache it is immediately given to the cache to be created. Multiple
-; object caches can be configured for a single object type.
-;
-
-;
-; Object Type Mappings
-;
-; To allow configuration of where and how an object is persisted object mappings can be defined within this file
-; on a per-module basis. The mapping consists of the object type, options, wizard name, and wizard configuration
-; data. This has the following format:
-;
-; object type [/options] = wizard name, wizard configuration data
-;
-; For example to configure an in-memory wizard for the 'bob' object type:
-;
-; bob = memory
-;
-; Or to configure the object type 'joe' from a configuration file:
-;
-; joe = config,joe.conf
-;
-; Note that an object type can have multiple mappings defined. Each mapping will be consulted in the order in which
-; it appears within the configuration file. This means that if you are configuring a wizard as a cache it should
-; appear as the first mapping so the cache is consulted before all other mappings.
-;
-
-;
-; The following object mappings are used by the unit test to test certain functionality of sorcery.
-;
-[test_sorcery_section]
-test=memory
-
-[test_sorcery_cache]
-test/cache=test
-test=memory
-
-;
-; The following object mapping is the default mapping of external MWI mailbox
-; objects to give persistence to the message counts.
-;
-;[res_mwi_external]
-;mailboxes=astdb,mwi_external
-
-;
-; The following object mappings set PJSIP objects to use realtime database mappings from extconfig
-; with the table names used when automatically generating configuration from the alembic script.
-;
-;[res_pjsip]
-;endpoint=realtime,ps_endpoints
-;auth=realtime,ps_auths
-;aor=realtime,ps_aors
-;domain_alias=realtime,ps_domain_aliases
-;identify=realtime,ps_endpoint_id_ips
diff --git a/configs/samples/ss7.timers.sample b/configs/samples/ss7.timers.sample
deleted file mode 100644
index 9cf9bd1..0000000
--- a/configs/samples/ss7.timers.sample
+++ /dev/null
@@ -1,65 +0,0 @@
-;;;;;	ITU-T Q.707 timers
-
-;mtp3_timer.q707_t1 = 4000
-;mtp3_timer.q707_t2 = 30000
-
-;;;;;	MTP3 timers as specified in ITU-T Q.704 or ANSI T1.111-2001
-
-mtp3_timer.t1 = 500
-mtp3_timer.t2 = 700
-mtp3_timer.t3 = 500
-mtp3_timer.t4 = 500
-mtp3_timer.t5 = 500
-mtp3_timer.t6 = 500
-mtp3_timer.t7 = 1000
-
-mtp3_timer.t10 = 60000
-
-mtp3_timer.t12 = 800
-mtp3_timer.t13 = 800
-mtp3_timer.t14 = 2000
-
-;	enable for ITU only. Timers after T17 are defined differently for ANSI
-;mtp3_timer.t19 = 67000
-;mtp3_timer.t21 = 63000
-;
-;mtp3_timer.t22 = 300000
-;mtp3_timer.t23 = 300000
-
-
-;;;;;	ISUP timers as specified in ITU-T Q.764 or ANSI T1.113-2000
-
-isup_timer.t1 = 15000
-;isup_timer.t2 = 180000		; ITU only
-
-;isup_timer.t5 = 300000		; for ITU
-;isup_timer.t5 = 60000		; for ANSI
-isup_timer.t6 = 30000
-isup_timer.t7 = 20000
-isup_timer.t8 = 10000
-
-;isup_timer.t10 = 4000		; ITU only
-
-isup_timer.t12 = 15000
-;isup_timer.t13 = 300000	; for ITU
-;isup_timer.t13 = 60000		; for ANSI
-isup_timer.t14 = 15000
-;isup_timer.t15 = 300000	; for ITU
-;isup_timer.t15 = 60000		; for ANSI
-isup_timer.t16 = 15000
-;isup_timer.t17 = 300000	; for ITU
-;isup_timer.t17 = 60000		; for ANSI
-isup_timer.t18 = 15000
-;isup_timer.t19 = 300000	; for ITU
-;isup_timer.t19 = 60000		; for ANSI
-isup_timer.t20 = 15000
-;isup_timer.t21 = 300000	; for ITU
-;isup_timer.t21 = 60000		; for ANSI
-isup_timer.t22 = 15000
-;isup_timer.t23 = 300000	; for ITU
-;isup_timer.t23 = 60000		; for ANSI
-
-isup_timer.t27 = 240000
-
-isup_timer.t33 = 12000
-;isup_timer.t35 = 15000		; ITU only
diff --git a/configs/samples/stasis.conf.sample b/configs/samples/stasis.conf.sample
deleted file mode 100644
index e591e76..0000000
--- a/configs/samples/stasis.conf.sample
+++ /dev/null
@@ -1,132 +0,0 @@
-[threadpool]
-;initial_size = 5          ; Initial size of the threadpool.
-;                          ; 0 means the threadpool has no threads initially
-;                          ; until a task needs a thread.
-;idle_timeout_sec = 20     ; Number of seconds a thread should be idle before
-;                          ; dying. 0 means threads never time out.
-;max_size = 50             ; Maximum number of threads in the Stasis threadpool.
-;                          ; 0 means no limit to the number of threads in the
-;                          ; threadpool.
-
-[declined_message_types]
-; This config section contains the names of message types that should be prevented
-; from being created. By default, all message types are allowed to be created.
-;
-; Using this functionality requires knowledge of the names of internal stasis
-; message types which is generally the same as the name of the accessor function.
-;
-; Use of this functionality may break more complex functionality in Asterisk
-; such as CEL, CDR, transfers, etc. and will likely cause related messages in ARI
-; and AMI to go missing.
-; decline=stasis_app_recording_snapshot_type
-; decline=stasis_app_playback_snapshot_type
-; decline=stasis_test_message_type
-; decline=confbridge_start_type
-; decline=confbridge_end_type
-; decline=confbridge_join_type
-; decline=confbridge_leave_type
-; decline=confbridge_start_record_type
-; decline=confbridge_stop_record_type
-; decline=confbridge_mute_type
-; decline=confbridge_unmute_type
-; decline=confbridge_talking_type
-; decline=cel_generic_type
-; decline=ast_bridge_snapshot_type
-; decline=ast_bridge_merge_message_type
-; decline=ast_channel_entered_bridge_type
-; decline=ast_channel_left_bridge_type
-; decline=ast_blind_transfer_type
-; decline=ast_attended_transfer_type
-; decline=ast_endpoint_snapshot_type
-; decline=ast_endpoint_state_type
-; decline=ast_device_state_message_type
-; decline=ast_test_suite_message_type
-; decline=ast_mwi_state_type
-; decline=ast_mwi_vm_app_type
-; decline=ast_format_register_type
-; decline=ast_format_unregister_type
-; decline=ast_manager_get_generic_type
-; decline=ast_parked_call_type
-; decline=ast_channel_snapshot_type
-; decline=ast_channel_dial_type
-; decline=ast_channel_varset_type
-; decline=ast_channel_hangup_request_type
-; decline=ast_channel_dtmf_begin_type
-; decline=ast_channel_dtmf_end_type
-; decline=ast_channel_hold_type
-; decline=ast_channel_unhold_type
-; decline=ast_channel_chanspy_start_type
-; decline=ast_channel_chanspy_stop_type
-; decline=ast_channel_fax_type
-; decline=ast_channel_hangup_handler_type
-; decline=ast_channel_moh_start_type
-; decline=ast_channel_moh_stop_type
-; decline=ast_channel_monitor_start_type
-; decline=ast_channel_monitor_stop_type
-; decline=ast_channel_agent_login_type
-; decline=ast_channel_agent_logoff_type
-; decline=ast_channel_talking_start
-; decline=ast_channel_talking_stop
-; decline=ast_security_event_type
-; decline=ast_named_acl_change_type
-; decline=ast_local_bridge_type
-; decline=ast_local_optimization_begin_type
-; decline=ast_local_optimization_end_type
-; decline=stasis_subscription_change_type
-; decline=ast_multi_user_event_type
-; decline=stasis_cache_clear_type
-; decline=stasis_cache_update_type
-; decline=ast_network_change_type
-; decline=ast_system_registry_type
-; decline=ast_cc_available_type
-; decline=ast_cc_offertimerstart_type
-; decline=ast_cc_requested_type
-; decline=ast_cc_requestacknowledged_type
-; decline=ast_cc_callerstopmonitoring_type
-; decline=ast_cc_callerstartmonitoring_type
-; decline=ast_cc_callerrecalling_type
-; decline=ast_cc_recallcomplete_type
-; decline=ast_cc_failure_type
-; decline=ast_cc_monitorfailed_type
-; decline=ast_presence_state_message_type
-; decline=ast_rtp_rtcp_sent_type
-; decline=ast_rtp_rtcp_received_type
-; decline=ast_call_pickup_type
-; decline=aoc_s_type
-; decline=aoc_d_type
-; decline=aoc_e_type
-; decline=dahdichannel_type
-; decline=mcid_type
-; decline=session_timeout_type
-; decline=cdr_read_message_type
-; decline=cdr_write_message_type
-; decline=cdr_prop_write_message_type
-; decline=corosync_ping_message_type
-; decline=agi_exec_start_type
-; decline=agi_exec_end_type
-; decline=agi_async_start_type
-; decline=agi_async_exec_type
-; decline=agi_async_end_type
-; decline=queue_caller_join_type
-; decline=queue_caller_leave_type
-; decline=queue_caller_abandon_type
-; decline=queue_member_status_type
-; decline=queue_member_added_type
-; decline=queue_member_removed_type
-; decline=queue_member_pause_type
-; decline=queue_member_penalty_type
-; decline=queue_member_ringinuse_type
-; decline=queue_agent_called_type
-; decline=queue_agent_connect_type
-; decline=queue_agent_complete_type
-; decline=queue_agent_dump_type
-; decline=queue_agent_ringnoanswer_type
-; decline=meetme_join_type
-; decline=meetme_leave_type
-; decline=meetme_end_type
-; decline=meetme_mute_type
-; decline=meetme_talking_type
-; decline=meetme_talk_request_type
-; decline=appcdr_message_type
-; decline=forkcdr_message_type
-; decline=cdr_sync_message_type
diff --git a/configs/samples/statsd.conf.sample b/configs/samples/statsd.conf.sample
deleted file mode 100644
index 8060973..0000000
--- a/configs/samples/statsd.conf.sample
+++ /dev/null
@@ -1,8 +0,0 @@
-[general]
-;enabled = yes			; When set to yes, statsd support is enabled
-;server = 127.0.0.1		; server[:port] of statsd server to use.
-				; If not specified, the port is 8125
-;prefix =			; Prefix to prepend to all metrics
-;add_newline = no		; Append a newline to every event. This is
-				; useful if you want to run a fake statsd
-				; server using netcat (nc -lu 8125)
diff --git a/configs/samples/test_sorcery.conf.sample b/configs/samples/test_sorcery.conf.sample
deleted file mode 100644
index c465dbf..0000000
--- a/configs/samples/test_sorcery.conf.sample
+++ /dev/null
@@ -1,14 +0,0 @@
-; This is a res_sorcery_config compatible file for the sorcery unit tests
-
-[hey]
-bob=98
-joe=41
-
-[hey2]
-type=zombies
-bob=97
-joe=40
-
-[hey3]
-bob=96
-joe=39
diff --git a/configs/samples/say.conf.sample b/configs/say.conf.sample
similarity index 100%
rename from configs/samples/say.conf.sample
rename to configs/say.conf.sample
diff --git a/configs/samples/sip.conf.sample b/configs/sip.conf.sample
similarity index 98%
rename from configs/samples/sip.conf.sample
rename to configs/sip.conf.sample
index a438f46..1ac849c 100644
--- a/configs/samples/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -6,7 +6,7 @@
 ;	configuration. If your Asterisk is installed on a public
 ;	IP address connected to the Internet, you will want to learn
 ;	about the various security settings BEFORE you start
-;	Asterisk.
+;	Asterisk. 
 ;
 ;	Especially note the following settings:
 ;		- allowguest (default enabled)
@@ -419,6 +419,8 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;maxcallbitrate=384             ; Maximum bitrate for video calls (default 384 kb/s)
                                 ; Videosupport and maxcallbitrate is settable
                                 ; for peers and users as well
+;callevents=no                  ; generate manager events when sip ua
+                                ; performs events (e.g. hold)
 ;authfailureevents=no           ; generate manager "peerstatus" events when peer can't
                                 ; authenticate with Asterisk. Peerstatus will be "rejected".
 ;alwaysauthreject = yes         ; When an incoming INVITE or REGISTER is to be rejected,
@@ -462,21 +464,6 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;outboundproxy=[2001:db8::1]:5062               ; IPv6 address literal with explicit port
 ;                                               ; (could also be tcp,udp) - defining transports on the proxy line only
 ;                                               ; applies for the global proxy, otherwise use the transport= option
-
-;supportpath=yes		; This activates parsing and handling of Path header as defined in RFC 3327. This enables
-				; Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded
-				; route-set defined by the Path headers in the REGISTER request.
-				; NOTE: There are multiple things to consider with this setting:
-				;  * As this influences routing of SIP requests make sure to not trust Path headers provided
-				;    by the user's SIP client (the proxy in front of Asterisk should remove existing user
-				;    provided Path headers).
-				;  * When a peer has both a path and outboundproxy set, the path will be added to Route: header
-				;    but routing to next hop is done using the outboundproxy.
-				;  * If set globally, not only will all peers use the Path header, but outbound REGISTER
-				;    requests from Asterisk will add path to the Supported header.
-
-;rtsavepath=yes                 ; If using dynamic realtime, store the path headers
-
 ;matchexternaddrlocally = yes     ; Only substitute the externaddr or externhost setting if it matches
                                 ; your localnet setting. Unless you have some sort of strange network
                                 ; setup you will not need to enable this.
@@ -802,7 +789,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;
 ;register => tls://username:xxxxxx@sip-tls-proxy.example.org
 ;
-;    The 'transport' part defaults to 'udp' but may also be 'tcp', 'tls', 'ws', or 'wss'.
+;    The 'transport' part defaults to 'udp' but may also be 'tcp' or 'tls'.
 ;    Using 'udp://' explicitly is also useful in case the username part
 ;    contains a '/' ('user/name').
 
@@ -827,8 +814,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;mwi => 1234:password:authuser at myauthprovider.com/1234
 ;mwi => 1234:password:authuser at myauthportprovider.com:6969/1234
 ;
-; MWI received will be stored in the 1234 mailbox of the SIP_Remote context.
-; It can be used by other phones by following the below:
+; MWI received will be stored in the 1234 mailbox of the SIP_Remote context. It can be used by other phones by following the below:
 ; mailbox=1234 at SIP_Remote
 ;----------------------------------------- NAT SUPPORT ------------------------
 ;
@@ -1259,7 +1245,6 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ; videosupport
 ; maxcallbitrate
 ; rfc2833compensate
-; Note: app_voicemail mailboxes must be in the form of mailbox at context.
 ; mailbox
 ; session-timers
 ; session-expires
@@ -1307,8 +1292,6 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ; dtlscapath
 ; dtlssetup
 ; dtlsfingerprint
-; ignore_requested_pref ; Ignore the requested codec and determine the preferred codec
-;						; from the peer's configuration.
 ;
 
 ;------------------------------------------------------------------------------
@@ -1486,7 +1469,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;host=dynamic                    ; This peer register with us
 ;dtmfmode=inband                 ; Choices are inband, rfc2833, or info
 ;defaultip=192.168.0.59          ; IP used until peer registers
-;mailbox=1234 at context,2345 at context ; Mailbox(-es) for message waiting indicator
+;mailbox=1234 at context,2345       ; Mailbox(-es) for message waiting indicator
 ;subscribemwi=yes                ; Only send notifications if this phone
                                  ; subscribes for mailbox notification
 ;vmexten=voicemail               ; dialplan extension to reach mailbox
@@ -1558,8 +1541,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep   ; This channel variable will
                                                 ; cause the given audio file to
                                                 ; be played upon completion of
-                                                ; an attended transfer to the
-                                                ; target of the transfer.
+                                                ; an attended transfer.
 
 ;[pre14-asterisk]
 ;type=friend
diff --git a/configs/samples/sip_notify.conf.sample b/configs/sip_notify.conf.sample
similarity index 100%
rename from configs/samples/sip_notify.conf.sample
rename to configs/sip_notify.conf.sample
diff --git a/configs/samples/skinny.conf.sample b/configs/skinny.conf.sample
similarity index 91%
rename from configs/samples/skinny.conf.sample
rename to configs/skinny.conf.sample
index be88dc2..d40823e 100644
--- a/configs/samples/skinny.conf.sample
+++ b/configs/skinny.conf.sample
@@ -38,14 +38,6 @@ keepalive=120
 			; for framing options
 ;disallow=
 
-; The imeddialkey option allows for a key to be used to immediately dial the already
-; entered number. This is useful where the dialplan includes variable length pattern
-; matching. Valid options are '#' and '*'. On devices with soft buttons, a button will
-; be available to immediately dial when a pattern than can be dialed has been entered.
-; Default is unset, that is no immediated dial key (softbutton still exists).
-;
-;immeddialkey=#
-
 ; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of these parameters.
 ;tos=cs3		; Sets TOS for signaling packets.
 ;tos_audio=ef		; Sets TOS for RTP audio packets.
@@ -100,7 +92,6 @@ keepalive=120
 ;                            ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes
 ;transfer=1                  ; whether the device is allowed to transfer. default=yes
 ;context=default             ; context to use for this line.
-;callfwdtimeout=20000        ; ms before cfwd_noans occurs (default 20 secs)
 ;------------------------------- SPECIFIC LINE OPTIONS -----------------------------
 ;setvar=        	     ; allows for the setting of chanvars.
 ;-----------------------------------------------------------------------------------
@@ -108,7 +99,6 @@ keepalive=120
 ;[100]
 ;nat=yes
 ;callerid="Customer Support" <810-234-1212>
-; Note: app_voicemail mailboxes must be in the form of mailbox at context.
 ;mailbox=100
 ;vmexten=8500			; Device level voicemailmain pilot number
 ;regexten=100
@@ -132,8 +122,7 @@ keepalive=120
 ;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep   ; This channel variable will
                                                 ; cause the given audio file to
                                                 ; be played upon completion of
-                                                ; an attended transfer to the
-                                                ; target of the transfer.
+                                                ; an attended transfer.
 ;mailbox=500
 ;callwaiting=yes
 ;transfer=yes
@@ -181,12 +170,6 @@ keepalive=120
 ;directmedia=yes	; Allow media to go directly between two RTP endpoints.
 ;line=120		; Dial(Skinny/120 at florian)
 
-; Service URLs attached to line buttons (eg phone directory)
-; See http://www.voip-info.org/wiki/view/Asterisk+Cisco+79XX+XML+Services
-; for intro to xml structure.
-;serviceurl=Directory,http://host/file.xml
-
-
 ; Typical config for a 7910
 ;[duba]			; Device name
 ;device=SEP0007EB463101	; Official identifier
diff --git a/configs/samples/sla.conf.sample b/configs/sla.conf.sample
similarity index 100%
rename from configs/samples/sla.conf.sample
rename to configs/sla.conf.sample
diff --git a/configs/samples/smdi.conf.sample b/configs/smdi.conf.sample
similarity index 100%
rename from configs/samples/smdi.conf.sample
rename to configs/smdi.conf.sample
diff --git a/configs/samples/telcordia-1.adsi b/configs/telcordia-1.adsi
similarity index 100%
rename from configs/samples/telcordia-1.adsi
rename to configs/telcordia-1.adsi
diff --git a/configs/samples/udptl.conf.sample b/configs/udptl.conf.sample
similarity index 100%
rename from configs/samples/udptl.conf.sample
rename to configs/udptl.conf.sample
diff --git a/configs/samples/unistim.conf.sample b/configs/unistim.conf.sample
similarity index 94%
rename from configs/samples/unistim.conf.sample
rename to configs/unistim.conf.sample
index c33426b..44d6e3e 100644
--- a/configs/samples/unistim.conf.sample
+++ b/configs/unistim.conf.sample
@@ -57,17 +57,15 @@ port=5000                    ; UDP port
 ;maintext0="you can insert"  ; default = "Welcome", 24 characters max
 ;maintext1="a custom text"   ; default = the name of the device, 24 characters max
 ;maintext2="(main page)"     ; default = the public IP of the phone, 24 characters max
-;dateformat=0                ; 0 (default) = 31Jan, 1 = Jan31, 2 = month/day, 3 = day/month
+;dateformat=1                ; 0 = month/day, 1 (default) = day/month
 ;timeformat=1                ; 0 = 0:00am ; 1 (default) = 0h00, 2 = 0:00
 ;contrast=8                  ; define the contrast of the LCD. From 0 to 15. Default = 8
 ;country=us                  ; country (ccTLD) for dial tone frequency. See README, default = us
-;language=ru                 ; language used for audio files and onscreen messages translate
 ;ringvolume=2                ; ring volume : 0,1,2,3, can be overrided by Dial(), default = 2
 ;ringstyle=3                 ; ring style : 0 to 7, can be overrided by Dial(), default = 3
 ;cwvolume=2                  ; ring volume : 0,1,2,3, default = 0
 ;cwstyle=3                   ; ring style : 0 to 7, default = 2
 ;sharpdial=1                 ; dial number by pressing #, default = 0
-;dtmf_duration=0             ; DTMF playback duration (in milliseconds) 0..150 (0 = off (default), 150 = maximum)
 ;interdigit_timer=4000       ; timer for automatic dial after several digits of number entered (in ms, 0 is off)
 ;callhistory=1               ; 0 = disable, 1 = enable call history, default = 1
 ;callerid="Customer Support" <555-234-5678>
diff --git a/configs/samples/users.conf.sample b/configs/users.conf.sample
similarity index 100%
rename from configs/samples/users.conf.sample
rename to configs/users.conf.sample
diff --git a/configs/samples/voicemail.conf.sample b/configs/voicemail.conf.sample
similarity index 95%
rename from configs/samples/voicemail.conf.sample
rename to configs/voicemail.conf.sample
index bb5f249..e63553b 100644
--- a/configs/samples/voicemail.conf.sample
+++ b/configs/voicemail.conf.sample
@@ -2,20 +2,12 @@
 ; Voicemail Configuration
 ;
 
-; ********* NOTICE ************************************************************
 ;
 ; NOTE: Asterisk has to edit this file to change a user's password.  This does
 ; not currently work with the "#include <file>" directive for Asterisk
 ; configuration files, nor when using realtime static configuration.
 ; Do not use them with this configuration file.
 ;
-; NOTE: Mailboxes defined by app_voicemail MUST be referenced by the rest
-; of the system as mailbox at context.  The rest of the system cannot add
-; @default to mailbox identifiers for app_voicemail that do not specify a
-; context any longer.  It is a mailbox identifier format that should only
-; be interpreted by app_voicemail.
-;
-; ********* NOTICE ************************************************************
 
 [general]
 ; Formats for writing Voicemail.  Note that when using IMAP storage for
@@ -232,10 +224,10 @@ pagerdateformat=%A, %B %d, %Y at %r
 ;
 
 ; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options>
-; If email is specified, a message will be sent when a voicemail is received, to
-; the given mailbox, for each address listed (separated by |, ex. alice at foo.com|bob at foo.com).
-; If pager is specified, a message will be sent there as well. If the password
-; is prefixed by '-', then it is considered to be unchangeable.
+; if the e-mail is specified, a message will be sent when a message is
+; received, to the given mailbox. If pager is specified, a message will be
+; sent there as well. If the password is prefixed by '-', then it is
+; considered to be unchangeable.
 ;
 ; Advanced options example is extension 4069
 ; NOTE: All options can be expressed globally in the general section, and
@@ -291,10 +283,6 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside
 			;     This is intended for use with users who wish to receive their
 			;     voicemail ONLY by email. Note:  "deletevoicemail" is provided as an
 			;     equivalent option for Realtime configuration.
-; alias=Bongo       ; Use this additional string for comparison while looking
-                    ; for a match in the Directory application.  This option
-                    ; may be specified multiple times to specify additional
-                    ; strings [per-mailbox only]
 ; volgain=0.0		; Emails bearing the voicemail may arrive in a volume too
 			;     quiet to be heard.  This parameter allows you to specify how
 			;     much gain to add to the message when sending a voicemail.
@@ -419,7 +407,6 @@ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM
 
 
 [default]
-; Note: The rest of the system must reference mailboxes defined here as mailbox at default.
 
 1234 => 4242,Example Mailbox,root at localhost
 ;4200 => 9855,Mark Spencer,markster at linux-support.net,mypager at digium.com,attach=no|serveremail=myaddy at digium.com|tz=central|maxmsg=10
diff --git a/configs/samples/vpb.conf.sample b/configs/vpb.conf.sample
similarity index 100%
rename from configs/samples/vpb.conf.sample
rename to configs/vpb.conf.sample
diff --git a/configs/samples/xmpp.conf.sample b/configs/xmpp.conf.sample
similarity index 96%
rename from configs/samples/xmpp.conf.sample
rename to configs/xmpp.conf.sample
index dad0f79..a838568 100644
--- a/configs/samples/xmpp.conf.sample
+++ b/configs/xmpp.conf.sample
@@ -37,6 +37,3 @@
 ;sendtodialplan=yes			; Send incoming messages into the dialplan.  Off by default.
 ;context=messages			; Dialplan context to send incoming messages to.  If not set,
 					; "default" will be used.
-;forceoldssl=no     ; Force the use of old-style SSL.
-;keepalive=
-
diff --git a/configure b/configure
index 823e3cb..261f586 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 425965 .
+# From configure.ac Revision.
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.69 for asterisk trunk.
 #
@@ -649,6 +649,7 @@ CONFIG_SDL
 PBX_SO_NOSIGPIPE
 PBX_MSG_NOSIGNAL
 PBX_IXJUSER
+PBX_H323
 GMIME_LIBS
 GMIME_CFLAGS
 OPENH323_BUILD
@@ -661,8 +662,6 @@ PWLIB_LIBDIR
 PWLIB_INCDIR
 PWLIBDIR
 PTLIB_CONFIG
-PJPROJECT_LIBS
-PJPROJECT_CFLAGS
 PG_CONFIG
 CONFIG_NETSNMP
 CONFIG_NEON29
@@ -683,11 +682,9 @@ PKG_CONFIG_PATH
 PKG_CONFIG
 PBX_DLADDR
 PBX_IP_MTU_DISCOVER
-PBX_RTLD_NOLOAD
 PBX_GLOB_BRACE
 PBX_GLOB_NOMAGIC
 AST_RPATH
-AST_NESTED_FUNCTIONS
 AST_NATIVE_ARCH
 AST_SHADOW_WARNINGS
 AST_NO_STRICT_OVERFLOW
@@ -696,6 +693,7 @@ AST_TRAMPOLINES
 AST_DECLARATION_AFTER_STATEMENT
 GC_LDFLAGS
 GC_CFLAGS
+PBX_WEAKREF
 PBX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 PBX_PTHREAD_RWLOCK_INITIALIZER
 AST_ASTERISKSSL
@@ -705,8 +703,6 @@ POW_LIB
 PBX_WORKING_FORK
 LIBOBJS
 CONFIG_LIBXML2
-UUID_LIB
-UUID_INCLUDE
 EDITLINE_LIB
 ALLOCA
 PBX_ZLIB
@@ -725,6 +721,10 @@ PBX_VORBIS
 VORBIS_DIR
 VORBIS_INCLUDE
 VORBIS_LIB
+PBX_UUID
+UUID_DIR
+UUID_INCLUDE
+UUID_LIB
 PBX_UNIXODBC
 UNIXODBC_DIR
 UNIXODBC_INCLUDE
@@ -902,22 +902,10 @@ PBX_PORTAUDIO
 PORTAUDIO_DIR
 PORTAUDIO_INCLUDE
 PORTAUDIO_LIB
-PBX_PJSIP_REPLACE_MEDIA_STREAM
-PJSIP_REPLACE_MEDIA_STREAM_DIR
-PJSIP_REPLACE_MEDIA_STREAM_INCLUDE
-PJSIP_REPLACE_MEDIA_STREAM_LIB
-PBX_PJ_TRANSACTION_GRP_LOCK
-PJ_TRANSACTION_GRP_LOCK_DIR
-PJ_TRANSACTION_GRP_LOCK_INCLUDE
-PJ_TRANSACTION_GRP_LOCK_LIB
 PBX_POPT
 POPT_DIR
 POPT_INCLUDE
 POPT_LIB
-PBX_PJPROJECT
-PJPROJECT_DIR
-PJPROJECT_INCLUDE
-PJPROJECT_LIB
 PBX_PGSQL
 PGSQL_DIR
 PGSQL_INCLUDE
@@ -930,10 +918,6 @@ PBX_OSPTK
 OSPTK_DIR
 OSPTK_INCLUDE
 OSPTK_LIB
-PBX_OPUS
-OPUS_DIR
-OPUS_INCLUDE
-OPUS_LIB
 PBX_OPENR2
 OPENR2_DIR
 OPENR2_INCLUDE
@@ -982,14 +966,6 @@ PBX_LTDL
 LTDL_DIR
 LTDL_INCLUDE
 LTDL_LIB
-PBX_LIBXSLT_CLEANUP
-LIBXSLT_CLEANUP_DIR
-LIBXSLT_CLEANUP_INCLUDE
-LIBXSLT_CLEANUP_LIB
-PBX_LIBXSLT
-LIBXSLT_DIR
-LIBXSLT_INCLUDE
-LIBXSLT_LIB
 PBX_LIBXML2
 LIBXML2_DIR
 LIBXML2_INCLUDE
@@ -1010,14 +986,6 @@ PBX_KQUEUE
 KQUEUE_DIR
 KQUEUE_INCLUDE
 KQUEUE_LIB
-PBX_URIPARSER
-URIPARSER_DIR
-URIPARSER_INCLUDE
-URIPARSER_LIB
-PBX_JANSSON
-JANSSON_DIR
-JANSSON_INCLUDE
-JANSSON_LIB
 PBX_JACK
 JACK_DIR
 JACK_INCLUDE
@@ -1082,10 +1050,10 @@ PBX_DAHDI
 DAHDI_DIR
 DAHDI_INCLUDE
 DAHDI_LIB
-PBX_OPENSSL_EC
-OPENSSL_EC_DIR
-OPENSSL_EC_INCLUDE
-OPENSSL_EC_LIB
+PBX_OPENSSL_ECDH_AUTO
+OPENSSL_ECDH_AUTO_DIR
+OPENSSL_ECDH_AUTO_INCLUDE
+OPENSSL_ECDH_AUTO_LIB
 PBX_OPENSSL_SRTP
 OPENSSL_SRTP_DIR
 OPENSSL_SRTP_INCLUDE
@@ -1094,10 +1062,6 @@ PBX_CRYPTO
 CRYPTO_DIR
 CRYPTO_INCLUDE
 CRYPTO_LIB
-PBX_CRYPT
-CRYPT_DIR
-CRYPT_INCLUDE
-CRYPT_LIB
 PBX_CURSES
 CURSES_DIR
 CURSES_INCLUDE
@@ -1130,6 +1094,10 @@ PBX_ALSA
 ALSA_DIR
 ALSA_INCLUDE
 ALSA_LIB
+AST_C_COMPILER_FAMILY
+AST_CLANG_BLOCKS
+AST_CLANG_BLOCKS_LIBS
+AST_NESTED_FUNCTIONS
 AST_CODE_COVERAGE
 AST_DEVMODE_STRICT
 AST_DEVMODE
@@ -1156,7 +1124,6 @@ RUBBER
 CURL
 WGET
 DOT
-DOXYGEN
 LN
 DIRNAME
 BASENAME
@@ -1186,7 +1153,6 @@ LD
 CXX
 PBX_OSREV
 UNAME
-CONFIG_SIGNED_CHAR
 PBX_WINARCH
 OSARCH
 HOST_OS
@@ -1281,7 +1247,6 @@ with_bluetooth
 with_cap
 with_cpg
 with_curses
-with_crypt
 with_crypto
 with_dahdi
 with_avcodec
@@ -1299,14 +1264,11 @@ with_inotify
 with_iodbc
 with_isdnnet
 with_jack
-with_jansson
-with_uriparser
 with_kqueue
 with_ldap
 with_libcurl
 with_libedit
 with_libxml2
-with_libxslt
 with_ltdl
 with_lua
 with_misdn
@@ -1319,11 +1281,9 @@ with_netsnmp
 with_newt
 with_ogg
 with_openr2
-with_opus
 with_osptk
 with_oss
 with_postgres
-with_pjproject
 with_popt
 with_portaudio
 with_pri
@@ -1348,6 +1308,7 @@ with_timerfd
 with_tinfo
 with_tonezone
 with_unixodbc
+with_uuid
 with_vorbis
 with_vpb
 with_x11
@@ -1378,8 +1339,6 @@ ILBC_CFLAGS
 ILBC_LIBS
 LIBEDIT_CFLAGS
 LIBEDIT_LIBS
-PJPROJECT_CFLAGS
-PJPROJECT_LIBS
 GMIME_CFLAGS
 GMIME_LIBS
 GTK2_CFLAGS
@@ -2016,7 +1975,6 @@ Optional Packages:
   --with-cap=PATH         use POSIX 1.e capabilities files in PATH
   --with-cpg=PATH         use Corosync files in PATH
   --with-curses=PATH      use curses files in PATH
-  --with-crypt=PATH       use password and data encryption files in PATH
   --with-crypto=PATH      use OpenSSL Cryptography files in PATH
   --with-dahdi=PATH       use DAHDI files in PATH
   --with-avcodec=PATH     use Ffmpeg and avcodec files in PATH
@@ -2036,15 +1994,12 @@ Optional Packages:
   --with-iodbc=PATH       use iODBC files in PATH
   --with-isdnnet=PATH     use ISDN4Linux files in PATH
   --with-jack=PATH        use Jack Audio Connection Kit files in PATH
-  --with-jansson=PATH     use Jansson JSON library files in PATH
-  --with-uriparser=PATH   use uriparser library files in PATH
   --with-kqueue=PATH      use kqueue support files in PATH
   --with-ldap=PATH        use OpenLDAP files in PATH
   --with-libcurl=DIR      look for the curl library in DIR
   --with-libedit=PATH     use NetBSD Editline library files in PATH, use
                           'internal' Editline otherwise
   --with-libxml2=PATH     use LibXML2 files in PATH
-  --with-libxslt=PATH     use LibXSLT files in PATH
   --with-ltdl=PATH        use libtool files in PATH
   --with-lua=PATH         use Lua files in PATH
   --with-misdn=PATH       use mISDN user files in PATH
@@ -2057,11 +2012,9 @@ Optional Packages:
   --with-newt=PATH        use newt files in PATH
   --with-ogg=PATH         use OGG files in PATH
   --with-openr2=PATH      use MFR2 files in PATH
-  --with-opus=PATH        use Opus files in PATH
   --with-osptk=PATH       use OSP Toolkit files in PATH
   --with-oss=PATH         use Open Sound System files in PATH
   --with-postgres=PATH    use PostgreSQL files in PATH
-  --with-pjproject=PATH   use PJPROJECT files in PATH
   --with-popt=PATH        use popt files in PATH
   --with-portaudio=PATH   use PortAudio files in PATH
   --with-pri=PATH         use ISDN PRI files in PATH
@@ -2088,6 +2041,7 @@ Optional Packages:
   --with-tinfo=PATH       use Term Info files in PATH
   --with-tonezone=PATH    use tonezone files in PATH
   --with-unixodbc=PATH    use unixODBC files in PATH
+  --with-uuid=PATH        use UUID files in PATH
   --with-vorbis=PATH      use Vorbis files in PATH
   --with-vpb=PATH         use Voicetronix API files in PATH
   --with-x11=PATH         use X11 files in PATH
@@ -2116,10 +2070,6 @@ Some influential environment variables:
               C compiler flags for LIBEDIT, overriding pkg-config
   LIBEDIT_LIBS
               linker flags for LIBEDIT, overriding pkg-config
-  PJPROJECT_CFLAGS
-              C compiler flags for PJPROJECT, overriding pkg-config
-  PJPROJECT_LIBS
-              linker flags for PJPROJECT, overriding pkg-config
   GMIME_CFLAGS
               C compiler flags for GMIME, overriding pkg-config
   GMIME_LIBS  linker flags for GMIME, overriding pkg-config
@@ -4819,35 +4769,6 @@ esac
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5
-$as_echo_n "checking whether char is unsigned... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-		#include <limits.h>
-#if CHAR_MIN == 0
-#error
-#endif
-
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		CONFIG_SIGNED_CHAR=""
-
-else
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		CONFIG_SIGNED_CHAR="-fsigned-char"
-
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
 #  check for uname
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}uname", so it can be a program name with args.
@@ -7040,47 +6961,6 @@ $as_echo "no" >&6; }
 fi
 
 
-# Extract the first word of "doxygen", so it can be a program name with args.
-set dummy doxygen; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DOXYGEN+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $DOXYGEN in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_DOXYGEN="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  test -z "$ac_cv_path_DOXYGEN" && ac_cv_path_DOXYGEN=":"
-  ;;
-esac
-fi
-DOXYGEN=$ac_cv_path_DOXYGEN
-if test -n "$DOXYGEN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5
-$as_echo "$DOXYGEN" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
 # Extract the first word of "dot", so it can be a program name with args.
 set dummy dot; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -8207,6 +8087,146 @@ fi
 
 
 
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RAII support" >&5
+$as_echo_n "checking for RAII support... " >&6; }
+	AST_C_COMPILER_FAMILY=""
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+			int main() {
+				#if defined(__clang__)
+				choke
+				#endif
+				return 0;
+			}
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+						{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -fnested-functions" >&5
+$as_echo_n "checking for gcc -fnested-functions... " >&6; }
+			cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+auto void foo(void); void foo(void) {}
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+					AST_NESTED_FUNCTIONS=""
+					{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+					AST_NESTED_FUNCTIONS="-fnested-functions"
+					{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+			AST_C_COMPILER_FAMILY="gcc"
+
+else
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang -fblocks" >&5
+$as_echo_n "checking for clang -fblocks... " >&6; }
+			if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS=""
+				AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+				AST_CLANG_BLOCKS="-fblocks"
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			else
+				as_fn_error $? "BlocksRuntime is required for clang, please install libblocksruntime" "$LINENO" 5
+			fi
+
+
+			AST_C_COMPILER_FAMILY="clang"
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	if test -z "${AST_C_COMPILER_FAMILY}"; then
+		as_fn_error $? "Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev" "$LINENO" 5
+	fi
+
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang strsep/strcmp optimization" >&5
+$as_echo_n "checking for clang strsep/strcmp optimization... " >&6; }
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+				#include <stdio.h>
+				#include <string.h>
+
+				/* fails with clang and -O1 */
+				void test_strsep_strcmp (void) {
+					char *haystackstr = "test1,test2";
+					char *outstr;
+					if (!strcmp(haystackstr, ",")) {
+						printf("fail\n");
+					}
+					if ((outstr = strsep(&haystackstr, ","))) {
+						printf("fail:%s\n", outstr);
+					}
+				}
+				int main(int argc, char *argv) {
+					test_strsep_strcmp();
+					return 0;
+				}
+
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strcmp 1" >>confdefs.h
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strsep 1" >>confdefs.h
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&5
+$as_echo "prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+	CFLAGS="$save_CFLAGS"
+
+
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
 # various packages.
 # $1 is the prefix for the variables in makeopts and autoconfig.h
@@ -8457,38 +8477,6 @@ fi
 
 
 
-    CRYPT_DESCRIP="password and data encryption"
-    CRYPT_OPTION="crypt"
-    PBX_CRYPT=0
-
-# Check whether --with-crypt was given.
-if test "${with_crypt+set}" = set; then :
-  withval=$with_crypt;
-	case ${withval} in
-	n|no)
-	USE_CRYPT=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_CRYPT=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} CRYPT"
-	;;
-	*)
-	CRYPT_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} CRYPT"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
     CRYPTO_DESCRIP="OpenSSL Cryptography"
     CRYPTO_OPTION="crypto"
     PBX_CRYPTO=0
@@ -8533,11 +8521,11 @@ PBX_OPENSSL_SRTP=0
 
 
 
-OPENSSL_EC_DESCRIP="OpenSSL Elliptic Curve Support"
-OPENSSL_EC_OPTION=crypto
-OPENSSL_EC_DIR=${CRYPTO_DIR}
+OPENSSL_ECDH_AUTO_DESCRIP="OpenSSL Auto ECDH Support"
+OPENSSL_ECDH_AUTO_OPTION=crypto
+OPENSSL_ECDH_AUTO_DIR=${CRYPTO_DIR}
 
-PBX_OPENSSL_EC=0
+PBX_OPENSSL_ECDH_AUTO=0
 
 
 
@@ -9057,70 +9045,6 @@ fi
 
 
 
-    JANSSON_DESCRIP="Jansson JSON library"
-    JANSSON_OPTION="jansson"
-    PBX_JANSSON=0
-
-# Check whether --with-jansson was given.
-if test "${with_jansson+set}" = set; then :
-  withval=$with_jansson;
-	case ${withval} in
-	n|no)
-	USE_JANSSON=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_JANSSON=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} JANSSON"
-	;;
-	*)
-	JANSSON_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} JANSSON"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
-    URIPARSER_DESCRIP="uriparser library"
-    URIPARSER_OPTION="uriparser"
-    PBX_URIPARSER=0
-
-# Check whether --with-uriparser was given.
-if test "${with_uriparser+set}" = set; then :
-  withval=$with_uriparser;
-	case ${withval} in
-	n|no)
-	USE_URIPARSER=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_URIPARSER=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} URIPARSER"
-	;;
-	*)
-	URIPARSER_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} URIPARSER"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
     KQUEUE_DESCRIP="kqueue support"
     KQUEUE_OPTION="kqueue"
     PBX_KQUEUE=0
@@ -9626,50 +9550,6 @@ fi
 
 
 
-    LIBXSLT_DESCRIP="LibXSLT"
-    LIBXSLT_OPTION="libxslt"
-    PBX_LIBXSLT=0
-
-# Check whether --with-libxslt was given.
-if test "${with_libxslt+set}" = set; then :
-  withval=$with_libxslt;
-	case ${withval} in
-	n|no)
-	USE_LIBXSLT=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_LIBXSLT=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} LIBXSLT"
-	;;
-	*)
-	LIBXSLT_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} LIBXSLT"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
-LIBXSLT_CLEANUP_DESCRIP="LibXSLT Library Cleanup Function"
-LIBXSLT_CLEANUP_OPTION=libxslt
-LIBXSLT_CLEANUP_DIR=${LIBXSLT_DIR}
-
-PBX_LIBXSLT_CLEANUP=0
-
-
-
-
-
-
-
     LTDL_DESCRIP="libtool"
     LTDL_OPTION="ltdl"
     PBX_LTDL=0
@@ -10054,58 +9934,26 @@ fi
 
 
 
-    OPUS_DESCRIP="Opus"
-    OPUS_OPTION="opus"
-    PBX_OPUS=0
+    OSPTK_DESCRIP="OSP Toolkit"
+    OSPTK_OPTION="osptk"
+    PBX_OSPTK=0
 
-# Check whether --with-opus was given.
-if test "${with_opus+set}" = set; then :
-  withval=$with_opus;
+# Check whether --with-osptk was given.
+if test "${with_osptk+set}" = set; then :
+  withval=$with_osptk;
 	case ${withval} in
 	n|no)
-	USE_OPUS=no
+	USE_OSPTK=no
 	# -1 is a magic value used by menuselect to know that the package
 	# was disabled, other than 'not found'
-	PBX_OPUS=-1
+	PBX_OSPTK=-1
 	;;
 	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} OPUS"
+	ac_mandatory_list="${ac_mandatory_list} OSPTK"
 	;;
 	*)
-	OPUS_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} OPUS"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
-    OSPTK_DESCRIP="OSP Toolkit"
-    OSPTK_OPTION="osptk"
-    PBX_OSPTK=0
-
-# Check whether --with-osptk was given.
-if test "${with_osptk+set}" = set; then :
-  withval=$with_osptk;
-	case ${withval} in
-	n|no)
-	USE_OSPTK=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_OSPTK=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} OSPTK"
-	;;
-	*)
-	OSPTK_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} OSPTK"
+	OSPTK_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} OSPTK"
 	;;
 	esac
 
@@ -10182,38 +10030,6 @@ fi
 
 
 
-    PJPROJECT_DESCRIP="PJPROJECT"
-    PJPROJECT_OPTION="pjproject"
-    PBX_PJPROJECT=0
-
-# Check whether --with-pjproject was given.
-if test "${with_pjproject+set}" = set; then :
-  withval=$with_pjproject;
-	case ${withval} in
-	n|no)
-	USE_PJPROJECT=no
-	# -1 is a magic value used by menuselect to know that the package
-	# was disabled, other than 'not found'
-	PBX_PJPROJECT=-1
-	;;
-	y|ye|yes)
-	ac_mandatory_list="${ac_mandatory_list} PJPROJECT"
-	;;
-	*)
-	PJPROJECT_DIR="${withval}"
-	ac_mandatory_list="${ac_mandatory_list} PJPROJECT"
-	;;
-	esac
-
-fi
-
-
-
-
-
-
-
-
     POPT_DESCRIP="popt"
     POPT_OPTION="popt"
     PBX_POPT=0
@@ -10246,30 +10062,6 @@ fi
 
 
 
-PJ_TRANSACTION_GRP_LOCK_DESCRIP="PJSIP Transaction Group Lock Support"
-PJ_TRANSACTION_GRP_LOCK_OPTION=pjsip
-PJ_TRANSACTION_GRP_LOCK_DIR=${PJPROJECT_DIR}
-
-PBX_PJ_TRANSACTION_GRP_LOCK=0
-
-
-
-
-
-
-
-PJSIP_REPLACE_MEDIA_STREAM_DESCRIP="PJSIP Media Stream Replacement Support"
-PJSIP_REPLACE_MEDIA_STREAM_OPTION=pjsip
-PJSIP_REPLACE_MEDIA_STREAM_DIR=${PJPROJECT_DIR}
-
-PBX_PJSIP_REPLACE_MEDIA_STREAM=0
-
-
-
-
-
-
-
     PORTAUDIO_DESCRIP="PortAudio"
     PORTAUDIO_OPTION="portaudio"
     PBX_PORTAUDIO=0
@@ -11297,6 +11089,38 @@ fi
 
 
 
+    UUID_DESCRIP="UUID"
+    UUID_OPTION="uuid"
+    PBX_UUID=0
+
+# Check whether --with-uuid was given.
+if test "${with_uuid+set}" = set; then :
+  withval=$with_uuid;
+	case ${withval} in
+	n|no)
+	USE_UUID=no
+	# -1 is a magic value used by menuselect to know that the package
+	# was disabled, other than 'not found'
+	PBX_UUID=-1
+	;;
+	y|ye|yes)
+	ac_mandatory_list="${ac_mandatory_list} UUID"
+	;;
+	*)
+	UUID_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} UUID"
+	;;
+	esac
+
+fi
+
+
+
+
+
+
+
+
     VORBIS_DESCRIP="Vorbis"
     VORBIS_OPTION="vorbis"
     PBX_VORBIS=0
@@ -11950,7 +11774,7 @@ fi
 done
 
 
-# Any one of these packages support a mandatory requirement, so we want to check on them as early as possible.
+# Any one of these 4 packages support a mandatory requirement, so we want to check on them as early as possible.
 
 if test "x${PBX_TERMCAP}" != "x1" -a "${USE_TERMCAP}" != "no"; then
    pbxlibdir=""
@@ -12382,844 +12206,179 @@ else
 fi
 
 
-# Find required UUID support.
-#  * -luuid on Linux
-#  * -le2fs-uuid on OpenBSD
-#  * in libsystem on OS X
+# Another mandatory item (unless it's explicitly disabled)
+# Check whether --enable-xmldoc was given.
+if test "${enable_xmldoc+set}" = set; then :
+  enableval=$enable_xmldoc; case "${enableval}" in
+		y|ye|yes) disable_xmldoc=no ;;
+		n|no)  disable_xmldoc=yes ;;
+		*) as_fn_error $? "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5  ;;
+	esac
+else
+  disable_xmldoc=no
+fi
+
+
+if test "${disable_xmldoc}" != "yes"; then
 
-if test "x${PBX_LIBUUID}" != "x1" -a "${USE_LIBUUID}" != "no"; then
-   pbxlibdir=""
-   # if --with-LIBUUID=DIR has been specified, use it.
-   if test "x${LIBUUID_DIR}" != "x"; then
-      if test -d ${LIBUUID_DIR}/lib; then
-         pbxlibdir="-L${LIBUUID_DIR}/lib"
-      else
-         pbxlibdir="-L${LIBUUID_DIR}"
-      fi
-   fi
-   pbxfuncname="uuid_generate_random"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_LIBUUID_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_uuid_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -luuid" >&5
-$as_echo_n "checking for ${pbxfuncname} in -luuid... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+	if test "x${PBX_LIBXML2}" != "x1" -a "${USE_LIBXML2}" != "no"; then
+		PBX_LIBXML2=0
+		if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}xml2-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}xml2-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_CONFIG_LIBXML2+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luuid ${pbxlibdir}  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+  case $CONFIG_LIBXML2 in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CONFIG_LIBXML2="$CONFIG_LIBXML2" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${LIBXML2_DIR}/bin:$PATH"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
+  ;;
+esac
+fi
+CONFIG_LIBXML2=$ac_cv_path_CONFIG_LIBXML2
+if test -n "$CONFIG_LIBXML2"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONFIG_LIBXML2" >&5
+$as_echo "$CONFIG_LIBXML2" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_CONFIG_LIBXML2"; then
+  ac_pt_CONFIG_LIBXML2=$CONFIG_LIBXML2
+  # Extract the first word of "xml2-config", so it can be a program name with args.
+set dummy xml2-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_CONFIG_LIBXML2+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_CONFIG_LIBXML2 in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_CONFIG_LIBXML2="$ac_pt_CONFIG_LIBXML2" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${LIBXML2_DIR}/bin:$PATH"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_CONFIG_LIBXML2=$ac_cv_path_ac_pt_CONFIG_LIBXML2
+if test -n "$ac_pt_CONFIG_LIBXML2"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CONFIG_LIBXML2" >&5
+$as_echo "$ac_pt_CONFIG_LIBXML2" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_CONFIG_LIBXML2" = x; then
+    CONFIG_LIBXML2="No"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CONFIG_LIBXML2=$ac_pt_CONFIG_LIBXML2
+  fi
+else
+  CONFIG_LIBXML2="$ac_cv_path_CONFIG_LIBXML2"
+fi
+
+		if test ! "x${CONFIG_LIBXML2}" = xNo; then
+			if test x"" = x ; then A=--cflags ; else A="" ; fi
+			LIBXML2_INCLUDE=$(${CONFIG_LIBXML2} $A)
+			LIBXML2_INCLUDE=$(echo ${LIBXML2_INCLUDE} | $SED -e "s|-I|-I${LIBXML2_DIR}|g")
+
+			if test x"" = x ; then A=--libs ; else A="" ; fi
+			LIBXML2_LIB=$(${CONFIG_LIBXML2} $A)
+			LIBXML2_LIB=$(echo ${LIBXML2_LIB} | $SED -e "s|-L|-L${LIBXML2_DIR}|g")
+
+			if test x"#include <libxml/tree.h>
+	#include <libxml/parser.h>" != x ; then
+				saved_cppflags="${CPPFLAGS}"
+				CPPFLAGS="${CPPFLAGS} ${LIBXML2_INCLUDE}"
+
+				saved_libs="${LIBS}"
+				LIBS=${LIBXML2_LIB}
+
+				cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+  #include <libxml/tree.h>
+	#include <libxml/parser.h>
 int
 main ()
 {
-return ${pbxfuncname} ();
+ LIBXML_TEST_VERSION;
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
+   PBX_LIBXML2=1
+$as_echo "#define HAVE_LIBXML2 1" >>confdefs.h
+
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_LIBUUID_FOUND=yes
-else
-  AST_LIBUUID_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_LIBUUID_FOUND}" = "yes"; then
-      LIBUUID_LIB="${pbxlibdir} -luuid "
-      # if --with-LIBUUID=DIR has been specified, use it.
-      if test "x${LIBUUID_DIR}" != "x"; then
-         LIBUUID_INCLUDE="-I${LIBUUID_DIR}/include"
-      fi
-      LIBUUID_INCLUDE="${LIBUUID_INCLUDE} "
-      if test "xuuid/uuid.h" = "x" ; then	# no header, assume found
-         LIBUUID_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${LIBUUID_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
-if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
-  LIBUUID_HEADER_FOUND=1
-else
-  LIBUUID_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${LIBUUID_HEADER_FOUND}" = "x0" ; then
-         LIBUUID_LIB=""
-         LIBUUID_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            LIBUUID_LIB=""
-         fi
-         PBX_LIBUUID=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBUUID 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
-if test "x${PBX_E2FSUUID}" != "x1" -a "${USE_E2FSUUID}" != "no"; then
-   pbxlibdir=""
-   # if --with-E2FSUUID=DIR has been specified, use it.
-   if test "x${E2FSUUID_DIR}" != "x"; then
-      if test -d ${E2FSUUID_DIR}/lib; then
-         pbxlibdir="-L${E2FSUUID_DIR}/lib"
-      else
-         pbxlibdir="-L${E2FSUUID_DIR}"
-      fi
-   fi
-   pbxfuncname="uuid_generate_random"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_E2FSUUID_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_e2fs-uuid_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -le2fs-uuid" >&5
-$as_echo_n "checking for ${pbxfuncname} in -le2fs-uuid... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-le2fs-uuid ${pbxlibdir}  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_E2FSUUID_FOUND=yes
-else
-  AST_E2FSUUID_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_E2FSUUID_FOUND}" = "yes"; then
-      E2FSUUID_LIB="${pbxlibdir} -le2fs-uuid "
-      # if --with-E2FSUUID=DIR has been specified, use it.
-      if test "x${E2FSUUID_DIR}" != "x"; then
-         E2FSUUID_INCLUDE="-I${E2FSUUID_DIR}/include"
-      fi
-      E2FSUUID_INCLUDE="${E2FSUUID_INCLUDE} "
-      if test "xuuid/uuid.h" = "x" ; then	# no header, assume found
-         E2FSUUID_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${E2FSUUID_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
-if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
-  E2FSUUID_HEADER_FOUND=1
-else
-  E2FSUUID_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${E2FSUUID_HEADER_FOUND}" = "x0" ; then
-         E2FSUUID_LIB=""
-         E2FSUUID_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            E2FSUUID_LIB=""
-         fi
-         PBX_E2FSUUID=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_E2FSUUID 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-for ac_func in uuid_generate_random
-do :
-  ac_fn_c_check_func "$LINENO" "uuid_generate_random" "ac_cv_func_uuid_generate_random"
-if test "x$ac_cv_func_uuid_generate_random" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_UUID_GENERATE_RANDOM 1
-_ACEOF
- SYSUUID=true
-else
-  SYSUUID=""
-fi
-done
-
-
-if test "x$LIBUUID_LIB" != "x" ; then
-  UUID_INCLUDE="$LIBUUID_INCLUDE"
-  UUID_LIB="$LIBUUID_LIB"
-elif test "x$E2FSUUID_LIB" != "x" ; then
-  UUID_INCLUDE="$E2FSUUID_INCLUDE"
-  UUID_LIB="$E2FSUUID_LIB"
-elif test "x$SYSUUID" != "x" ; then
-  UUID_INCLUDE=""
-  UUID_LIB=""
-else
-  as_fn_error $? "*** uuid support not found (this typically means the uuid development package is missing)" "$LINENO" 5
-fi
-
-
-
-# Find required JSON support.
-
-if test "x${PBX_JANSSON}" != "x1" -a "${USE_JANSSON}" != "no"; then
-   pbxlibdir=""
-   # if --with-JANSSON=DIR has been specified, use it.
-   if test "x${JANSSON_DIR}" != "x"; then
-      if test -d ${JANSSON_DIR}/lib; then
-         pbxlibdir="-L${JANSSON_DIR}/lib"
-      else
-         pbxlibdir="-L${JANSSON_DIR}"
-      fi
-   fi
-   pbxfuncname="json_dumps"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_JANSSON_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_jansson_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ljansson" >&5
-$as_echo_n "checking for ${pbxfuncname} in -ljansson... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ljansson ${pbxlibdir}  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_JANSSON_FOUND=yes
-else
-  AST_JANSSON_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_JANSSON_FOUND}" = "yes"; then
-      JANSSON_LIB="${pbxlibdir} -ljansson "
-      # if --with-JANSSON=DIR has been specified, use it.
-      if test "x${JANSSON_DIR}" != "x"; then
-         JANSSON_INCLUDE="-I${JANSSON_DIR}/include"
-      fi
-      JANSSON_INCLUDE="${JANSSON_INCLUDE} "
-      if test "xjansson.h" = "x" ; then	# no header, assume found
-         JANSSON_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${JANSSON_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "jansson.h" "ac_cv_header_jansson_h" "$ac_includes_default"
-if test "x$ac_cv_header_jansson_h" = xyes; then :
-  JANSSON_HEADER_FOUND=1
-else
-  JANSSON_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${JANSSON_HEADER_FOUND}" = "x0" ; then
-         JANSSON_LIB=""
-         JANSSON_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            JANSSON_LIB=""
-         fi
-         PBX_JANSSON=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_JANSSON 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
-if test "x$JANSSON_LIB" == "x"; then
-  as_fn_error $? "*** JSON support not found (this typically means the libjansson development package is missing)" "$LINENO" 5
-fi
-
-
-		if test "x${PBX_LIBXML2}" != "x1" -a "${USE_LIBXML2}" != "no"; then
-		PBX_LIBXML2=0
-		if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}xml2-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}xml2-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_LIBXML2+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $CONFIG_LIBXML2 in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_CONFIG_LIBXML2="$CONFIG_LIBXML2" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_dummy="${LIBXML2_DIR}/bin:$PATH"
-for as_dir in $as_dummy
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-CONFIG_LIBXML2=$ac_cv_path_CONFIG_LIBXML2
-if test -n "$CONFIG_LIBXML2"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONFIG_LIBXML2" >&5
-$as_echo "$CONFIG_LIBXML2" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_CONFIG_LIBXML2"; then
-  ac_pt_CONFIG_LIBXML2=$CONFIG_LIBXML2
-  # Extract the first word of "xml2-config", so it can be a program name with args.
-set dummy xml2-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_LIBXML2+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_CONFIG_LIBXML2 in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_CONFIG_LIBXML2="$ac_pt_CONFIG_LIBXML2" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_dummy="${LIBXML2_DIR}/bin:$PATH"
-for as_dir in $as_dummy
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_CONFIG_LIBXML2=$ac_cv_path_ac_pt_CONFIG_LIBXML2
-if test -n "$ac_pt_CONFIG_LIBXML2"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CONFIG_LIBXML2" >&5
-$as_echo "$ac_pt_CONFIG_LIBXML2" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_pt_CONFIG_LIBXML2" = x; then
-    CONFIG_LIBXML2="No"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CONFIG_LIBXML2=$ac_pt_CONFIG_LIBXML2
-  fi
-else
-  CONFIG_LIBXML2="$ac_cv_path_CONFIG_LIBXML2"
-fi
-
-		if test ! "x${CONFIG_LIBXML2}" = xNo; then
-			if test x"" = x ; then A=--cflags ; else A="" ; fi
-			LIBXML2_INCLUDE=$(${CONFIG_LIBXML2} $A)
-			LIBXML2_INCLUDE=$(echo ${LIBXML2_INCLUDE} | $SED -e "s|-I|-I${LIBXML2_DIR}|g")
-
-			if test x"" = x ; then A=--libs ; else A="" ; fi
-			LIBXML2_LIB=$(${CONFIG_LIBXML2} $A)
-			LIBXML2_LIB=$(echo ${LIBXML2_LIB} | $SED -e "s|-L|-L${LIBXML2_DIR}|g")
-
-			if test x"#include <libxml/tree.h>
-        #include <libxml/parser.h>" != x ; then
-				saved_cppflags="${CPPFLAGS}"
-				CPPFLAGS="${CPPFLAGS} ${LIBXML2_INCLUDE}"
-
-				saved_libs="${LIBS}"
-				LIBS=${LIBXML2_LIB}
-
-				cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-  #include <libxml/tree.h>
-        #include <libxml/parser.h>
-int
-main ()
-{
- LIBXML_TEST_VERSION;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-   PBX_LIBXML2=1
-$as_echo "#define HAVE_LIBXML2 1" >>confdefs.h
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-				CPPFLAGS="${saved_cppflags}"
-				LIBS="${saved_libs}"
-			else
-				PBX_LIBXML2=1
-
-$as_echo "#define HAVE_LIBXML2 1" >>confdefs.h
-
-			fi
-		fi
-	fi
-
-
-if test "${PBX_LIBXML2}" != 1; then
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: *** The Asterisk menuselect tool requires the 'libxml2' development package." >&5
-$as_echo "$as_me: *** The Asterisk menuselect tool requires the 'libxml2' development package." >&6;}
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: *** Please install the 'libxml2' development package." >&5
-$as_echo "$as_me: *** Please install the 'libxml2' development package." >&6;}
-	exit 1
-fi
-
-
-if test "x${PBX_URIPARSER}" != "x1" -a "${USE_URIPARSER}" != "no"; then
-   pbxlibdir=""
-   # if --with-URIPARSER=DIR has been specified, use it.
-   if test "x${URIPARSER_DIR}" != "x"; then
-      if test -d ${URIPARSER_DIR}/lib; then
-         pbxlibdir="-L${URIPARSER_DIR}/lib"
-      else
-         pbxlibdir="-L${URIPARSER_DIR}"
-      fi
-   fi
-   pbxfuncname="uriParseUriA"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_URIPARSER_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_uriparser_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -luriparser" >&5
-$as_echo_n "checking for ${pbxfuncname} in -luriparser... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luriparser ${pbxlibdir}  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_URIPARSER_FOUND=yes
-else
-  AST_URIPARSER_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_URIPARSER_FOUND}" = "yes"; then
-      URIPARSER_LIB="${pbxlibdir} -luriparser "
-      # if --with-URIPARSER=DIR has been specified, use it.
-      if test "x${URIPARSER_DIR}" != "x"; then
-         URIPARSER_INCLUDE="-I${URIPARSER_DIR}/include"
-      fi
-      URIPARSER_INCLUDE="${URIPARSER_INCLUDE} "
-      if test "xuriparser/Uri.h" = "x" ; then	# no header, assume found
-         URIPARSER_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${URIPARSER_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "uriparser/Uri.h" "ac_cv_header_uriparser_Uri_h" "$ac_includes_default"
-if test "x$ac_cv_header_uriparser_Uri_h" = xyes; then :
-  URIPARSER_HEADER_FOUND=1
-else
-  URIPARSER_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${URIPARSER_HEADER_FOUND}" = "x0" ; then
-         URIPARSER_LIB=""
-         URIPARSER_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            URIPARSER_LIB=""
-         fi
-         PBX_URIPARSER=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_URIPARSER 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
-# Another mandatory item (unless it's explicitly disabled)
-# Check whether --enable-xmldoc was given.
-if test "${enable_xmldoc+set}" = set; then :
-  enableval=$enable_xmldoc; case "${enableval}" in
-		y|ye|yes) disable_xmldoc=no ;;
-		n|no)  disable_xmldoc=yes ;;
-		*) as_fn_error $? "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5  ;;
-	esac
-else
-  disable_xmldoc=no
-fi
-
-
-if test "${disable_xmldoc}" != "yes"; then
-
-if test "x${PBX_LIBXSLT}" != "x1" -a "${USE_LIBXSLT}" != "no"; then
-   pbxlibdir=""
-   # if --with-LIBXSLT=DIR has been specified, use it.
-   if test "x${LIBXSLT_DIR}" != "x"; then
-      if test -d ${LIBXSLT_DIR}/lib; then
-         pbxlibdir="-L${LIBXSLT_DIR}/lib"
-      else
-         pbxlibdir="-L${LIBXSLT_DIR}"
-      fi
-   fi
-   pbxfuncname="xsltLoadStylesheetPI"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_LIBXSLT_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} ${LIBXML2_INCLUDE}"
-      as_ac_Lib=`$as_echo "ac_cv_lib_xslt_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lxslt" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lxslt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lxslt ${pbxlibdir} ${LIBXML2_LIB} $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_LIBXSLT_FOUND=yes
-else
-  AST_LIBXSLT_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_LIBXSLT_FOUND}" = "yes"; then
-      LIBXSLT_LIB="${pbxlibdir} -lxslt ${LIBXML2_LIB}"
-      # if --with-LIBXSLT=DIR has been specified, use it.
-      if test "x${LIBXSLT_DIR}" != "x"; then
-         LIBXSLT_INCLUDE="-I${LIBXSLT_DIR}/include"
-      fi
-      LIBXSLT_INCLUDE="${LIBXSLT_INCLUDE} ${LIBXML2_INCLUDE}"
-      if test "xlibxslt/xsltInternals.h" = "x" ; then	# no header, assume found
-         LIBXSLT_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${LIBXSLT_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "libxslt/xsltInternals.h" "ac_cv_header_libxslt_xsltInternals_h" "$ac_includes_default"
-if test "x$ac_cv_header_libxslt_xsltInternals_h" = xyes; then :
-  LIBXSLT_HEADER_FOUND=1
-else
-  LIBXSLT_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${LIBXSLT_HEADER_FOUND}" = "x0" ; then
-         LIBXSLT_LIB=""
-         LIBXSLT_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            LIBXSLT_LIB=""
-         fi
-         PBX_LIBXSLT=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBXSLT 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
-if test "x${PBX_LIBXSLT_CLEANUP}" != "x1" -a "${USE_LIBXSLT_CLEANUP}" != "no"; then
-   pbxlibdir=""
-   # if --with-LIBXSLT_CLEANUP=DIR has been specified, use it.
-   if test "x${LIBXSLT_CLEANUP_DIR}" != "x"; then
-      if test -d ${LIBXSLT_CLEANUP_DIR}/lib; then
-         pbxlibdir="-L${LIBXSLT_CLEANUP_DIR}/lib"
-      else
-         pbxlibdir="-L${LIBXSLT_CLEANUP_DIR}"
-      fi
-   fi
-   pbxfuncname="xsltCleanupGlobals"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_LIBXSLT_CLEANUP_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} ${LIBXML2_INCLUDE}"
-      as_ac_Lib=`$as_echo "ac_cv_lib_xslt_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lxslt" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lxslt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lxslt ${pbxlibdir} ${LIBXML2_LIB} $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_LIBXSLT_CLEANUP_FOUND=yes
-else
-  AST_LIBXSLT_CLEANUP_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_LIBXSLT_CLEANUP_FOUND}" = "yes"; then
-      LIBXSLT_CLEANUP_LIB="${pbxlibdir} -lxslt ${LIBXML2_LIB}"
-      # if --with-LIBXSLT_CLEANUP=DIR has been specified, use it.
-      if test "x${LIBXSLT_CLEANUP_DIR}" != "x"; then
-         LIBXSLT_CLEANUP_INCLUDE="-I${LIBXSLT_CLEANUP_DIR}/include"
-      fi
-      LIBXSLT_CLEANUP_INCLUDE="${LIBXSLT_CLEANUP_INCLUDE} ${LIBXML2_INCLUDE}"
-      if test "xlibxslt/xsltInternals.h" = "x" ; then	# no header, assume found
-         LIBXSLT_CLEANUP_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${LIBXSLT_CLEANUP_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "libxslt/xsltInternals.h" "ac_cv_header_libxslt_xsltInternals_h" "$ac_includes_default"
-if test "x$ac_cv_header_libxslt_xsltInternals_h" = xyes; then :
-  LIBXSLT_CLEANUP_HEADER_FOUND=1
-else
-  LIBXSLT_CLEANUP_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${LIBXSLT_CLEANUP_HEADER_FOUND}" = "x0" ; then
-         LIBXSLT_CLEANUP_LIB=""
-         LIBXSLT_CLEANUP_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            LIBXSLT_CLEANUP_LIB=""
-         fi
-         PBX_LIBXSLT_CLEANUP=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBXSLT_CLEANUP 1
-_ACEOF
-
-      fi
-   fi
-fi
+				CPPFLAGS="${saved_cppflags}"
+				LIBS="${saved_libs}"
+			else
+				PBX_LIBXML2=1
 
+$as_echo "#define HAVE_LIBXML2 1" >>confdefs.h
 
+			fi
+		fi
+	fi
 
+	if test "${PBX_LIBXML2}" != 1; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: *** XML documentation will not be available because the 'libxml2' development package is missing." >&5
+$as_echo "$as_me: *** XML documentation will not be available because the 'libxml2' development package is missing." >&6;}
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&5
+$as_echo "$as_me: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&6;}
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: *** or install the 'libxml2' development package." >&5
+$as_echo "$as_me: *** or install the 'libxml2' development package." >&6;}
+		exit 1
+	fi
 fi
 
 # some embedded systems omit internationalization (locale) support
@@ -15754,6 +14913,31 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 
+if test "${cross_compiling}" = "no";
+then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+$as_echo_n "checking for /dev/urandom... " >&6; }
+if ${ac_cv_file__dev_urandom+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/dev/urandom"; then
+  ac_cv_file__dev_urandom=yes
+else
+  ac_cv_file__dev_urandom=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_urandom" >&5
+$as_echo "$ac_cv_file__dev_urandom" >&6; }
+if test "x$ac_cv_file__dev_urandom" = xyes; then :
+
+$as_echo "#define HAVE_DEV_URANDOM 1" >>confdefs.h
+
+fi
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for locale_t in locale.h" >&5
 $as_echo_n "checking for locale_t in locale.h... " >&6; }
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -15962,67 +15146,12 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_MUTEX_ADAPTIVE_NP in pthread.h" >&5
-$as_echo_n "checking for PTHREAD_MUTEX_ADAPTIVE_NP in pthread.h... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <pthread.h>
-int
-main ()
-{
-int a = PTHREAD_MUTEX_ADAPTIVE_NP;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1" >>confdefs.h
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_spinlock_t in pthread.h" >&5
-$as_echo_n "checking for pthread_spinlock_t in pthread.h... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <pthread.h>
-int
-main ()
-{
-pthread_spinlock_t spin;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PTHREAD_SPINLOCK 1" >>confdefs.h
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_rwlock_timedwrlock() in pthread.h" >&5
+$as_echo_n "checking for pthread_rwlock_timedwrlock() in pthread.h... " >&6; }
 save_LIBS="$LIBS"
 save_CFLAGS="$CFLAGS"
 LIBS="$PTHREAD_LIBS $LIBS"
 CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_rwlock_timedwrlock() in pthread.h" >&5
-$as_echo_n "checking for pthread_rwlock_timedwrlock() in pthread.h... " >&6; }
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <pthread.h>
@@ -16052,43 +15181,6 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-
-# Some platforms define sem_init(), but only support sem_open(). joyous.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working unnamed semaphores" >&5
-$as_echo_n "checking for working unnamed semaphores... " >&6; }
-if test "$cross_compiling" = yes; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <semaphore.h>
-int
-main ()
-{
-sem_t sem; return sem_init(&sem, 0, 0);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAS_WORKING_SEMAPHORE 1" >>confdefs.h
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
 LIBS="$save_LIBS"
 CFLAGS="$save_CFLAGS"
 if test "${ac_cv_pthread_rwlock_timedwrlock}" = "yes"; then
@@ -16434,7 +15526,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16502,7 +15594,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16570,7 +15662,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16638,7 +15730,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16706,7 +15798,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16774,7 +15866,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16842,7 +15934,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16910,7 +16002,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16941,17 +16033,28 @@ CFLAGS="$saved_CFLAGS"
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute may_alias' support" >&5
-$as_echo_n "checking for compiler 'attribute may_alias' support... " >&6; }
+# Support weak symbols on a platform specific basis.  The Mac OS X
+# (Darwin) support must be isolated from the other platforms because
+# it has caused other platforms to fail.
+#
+case "${OSARCH}" in
+	darwin*)
+	# Allow weak symbol support on Darwin platforms only because there
+	# is active community support for it.
+	# However, Darwin seems to break weak symbols for each new version.
+	#
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute weak_import' support" >&5
+$as_echo_n "checking for compiler 'attribute weak_import' support... " >&6; }
 saved_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
-
+PBX_WEAKREF=0
 
 if test "x" = "x"
 then
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__((may_alias)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((weak_import)) *test(void *muffin, ...) {return (void *) 0;}
 int
 main ()
 {
@@ -16963,10 +16066,10 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_may_alias 1
+#define HAVE_ATTRIBUTE_weak_import 1
 _ACEOF
 
 else
@@ -16978,7 +16081,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -16990,10 +16093,10 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_may_alias 1
+#define HAVE_ATTRIBUTE_weak_import 1
 _ACEOF
 
 else
@@ -17009,17 +16112,21 @@ CFLAGS="$saved_CFLAGS"
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute constructor' support" >&5
-$as_echo_n "checking for compiler 'attribute constructor' support... " >&6; }
+	# Several other platforms including Linux have GCC versions that
+	# define the weak attribute.  However, this attribute is only
+	# setup for use in the code by Darwin.
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute weak' support" >&5
+$as_echo_n "checking for compiler 'attribute weak' support... " >&6; }
 saved_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
-
+PBX_WEAKREF=0
 
 if test "x" = "x"
 then
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__((constructor)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((weak)) *test(void *muffin, ...) {return (void *) 0;}
 int
 main ()
 {
@@ -17031,10 +16138,10 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_constructor 1
+#define HAVE_ATTRIBUTE_weak 1
 _ACEOF
 
 else
@@ -17046,7 +16153,52 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	PBX_WEAKREF=1
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATTRIBUTE_weak 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+CFLAGS="$saved_CFLAGS"
+
+
+	;;
+	linux-gnu)
+	# Primarily support weak symbols on Linux platforms.
+	#
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute weakref' support" >&5
+$as_echo_n "checking for compiler 'attribute weakref' support... " >&6; }
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+PBX_WEAKREF=0
+
+if test "xweakref("foo")" = "x"
+then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+static void __attribute__((weakref)) *test(void *muffin, ...) {return (void *) 0;}
 int
 main ()
 {
@@ -17058,10 +16210,37 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
+	PBX_WEAKREF=1
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATTRIBUTE_weakref 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+static void __attribute__((weakref("foo"))) *test(void *muffin, ...) ;
+int
+main ()
+{
 
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_constructor 1
+#define HAVE_ATTRIBUTE_weakref 1
 _ACEOF
 
 else
@@ -17076,18 +16255,24 @@ fi
 CFLAGS="$saved_CFLAGS"
 
 
+	;;
+	*)
+	# Allow weak symbols on other platforms.  However, any problems
+	# with this feature on other platforms must be fixed by the
+	# community.
+	#
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute destructor' support" >&5
-$as_echo_n "checking for compiler 'attribute destructor' support... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute weakref' support" >&5
+$as_echo_n "checking for compiler 'attribute weakref' support... " >&6; }
 saved_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+PBX_WEAKREF=0
 
-
-if test "x" = "x"
+if test "xweakref("foo")" = "x"
 then
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__((destructor)) *test(void *muffin, ...) {return (void *) 0;}
+static void __attribute__((weakref)) *test(void *muffin, ...) {return (void *) 0;}
 int
 main ()
 {
@@ -17099,10 +16284,10 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_destructor 1
+#define HAVE_ATTRIBUTE_weakref 1
 _ACEOF
 
 else
@@ -17114,7 +16299,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+static void __attribute__((weakref("foo"))) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -17126,10 +16311,10 @@ _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-
+	PBX_WEAKREF=1
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_ATTRIBUTE_destructor 1
+#define HAVE_ATTRIBUTE_weakref 1
 _ACEOF
 
 else
@@ -17144,6 +16329,8 @@ fi
 CFLAGS="$saved_CFLAGS"
 
 
+	;;
+esac
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ffunction-sections support" >&5
 $as_echo_n "checking for -ffunction-sections support... " >&6; }
@@ -17216,7 +16403,7 @@ fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wtrampolines support" >&5
 $as_echo_n "checking for -Wtrampolines support... " >&6; }
-if $(${CC} -Wtrampolines -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+if $(${CC} -Wtrampolines -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 	AST_TRAMPOLINES=-Wtrampolines
@@ -17285,31 +16472,6 @@ $as_echo "no" >&6; }
 fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fnested-functions" >&5
-$as_echo_n "checking for -fnested-functions... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-auto void foo(void); void foo(void) {}
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-	AST_NESTED_FUNCTIONS=
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: required" >&5
-$as_echo "required" >&6; }
-	AST_NESTED_FUNCTIONS=-fnested-functions
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
 
 # Check whether --enable-rpath was given.
 if test "${enable_rpath+set}" = set; then :
@@ -17333,7 +16495,20 @@ elif test "${prefix}" = /usr || test "${prefix}" = NONE; then
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not needed" >&5
 $as_echo "not needed" >&6; }
 else
-	AST_RPATH="-Wl,-rpath,${libdir}"
+	case "${host_os}" in
+		darwin*)
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not supported" >&5
+$as_echo "not supported" >&6; }
+			# We set macosx_version_min to 10.4, which doesn't
+			# support rpath. However, we set install_name on our
+			# dylibs, so it's not strictly necessary.
+			;;
+		*)
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: required" >&5
+$as_echo "required" >&6; }
+			AST_RPATH="-Wl,-rpath,${libdir}"
+			;;
+	esac
 fi
 
 
@@ -17736,53 +16911,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
 
-    if test "x${PBX_RTLD_NOLOAD}" != "x1"; then
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RTLD_NOLOAD in dlfcn.h" >&5
-$as_echo_n "checking for RTLD_NOLOAD in dlfcn.h... " >&6; }
-	saved_cppflags="${CPPFLAGS}"
-	if test "x${RTLD_NOLOAD_DIR}" != "x"; then
-	    RTLD_NOLOAD_INCLUDE="-I${RTLD_NOLOAD_DIR}/include"
-	fi
-	CPPFLAGS="${CPPFLAGS} ${RTLD_NOLOAD_INCLUDE}"
-
-	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
- #include <dlfcn.h>
-int
-main ()
-{
-#if defined(RTLD_NOLOAD)
-				int foo = 0;
-			        #else
-			        int foo = bar;
-			        #endif
-				0
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		PBX_RTLD_NOLOAD=1
-
-$as_echo "#define HAVE_RTLD_NOLOAD 1" >>confdefs.h
-
-
-
-else
-     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-	CPPFLAGS="${saved_cppflags}"
-    fi
-
-
-
-
     if test "x${PBX_IP_MTU_DISCOVER}" != "x1"; then
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_MTU_DISCOVER in netinet/in.h" >&5
 $as_echo_n "checking for IP_MTU_DISCOVER in netinet/in.h... " >&6; }
@@ -21758,7 +20886,7 @@ fi
 fi
 
 
-		if test "x${PBX_MYSQLCLIENT}" != "x1" -a "${USE_MYSQLCLIENT}" != "no"; then
+	if test "x${PBX_MYSQLCLIENT}" != "x1" -a "${USE_MYSQLCLIENT}" != "no"; then
 		PBX_MYSQLCLIENT=0
 		if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}mysql_config", so it can be a program name with args.
@@ -22012,7 +21140,7 @@ fi
 
 
 
-		if test "x${PBX_NEON}" != "x1" -a "${USE_NEON}" != "no"; then
+	if test "x${PBX_NEON}" != "x1" -a "${USE_NEON}" != "no"; then
 		PBX_NEON=0
 		if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}neon-config", so it can be a program name with args.
@@ -22161,7 +21289,7 @@ $as_echo "#define HAVE_NEON 1" >>confdefs.h
 
 
 
-		if test "x${PBX_NEON29}" != "x1" -a "${USE_NEON29}" != "no"; then
+	if test "x${PBX_NEON29}" != "x1" -a "${USE_NEON29}" != "no"; then
 		PBX_NEON29=0
 		if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}neon-config", so it can be a program name with args.
@@ -22312,7 +21440,7 @@ $as_echo "#define HAVE_NEON29 1" >>confdefs.h
 
 
 
-		if test "x${PBX_NETSNMP}" != "x1" -a "${USE_NETSNMP}" != "no"; then
+	if test "x${PBX_NETSNMP}" != "x1" -a "${USE_NETSNMP}" != "no"; then
 		PBX_NETSNMP=0
 		if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}net-snmp-config", so it can be a program name with args.
@@ -23665,324 +22793,78 @@ return PQescapeStringConn ();
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_pq_PQescapeStringConn=yes
-else
-  ac_cv_lib_pq_PQescapeStringConn=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQescapeStringConn" >&5
-$as_echo "$ac_cv_lib_pq_PQescapeStringConn" >&6; }
-if test "x$ac_cv_lib_pq_PQescapeStringConn" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_PGSQL 1
-_ACEOF
-
-fi
-
-
-      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pg_encoding_to_char within Postgres headers" >&5
-$as_echo_n "checking for pg_encoding_to_char within Postgres headers... " >&6; }
-      old_CFLAGS=${CFLAGS}
-      CFLAGS="${CFLAGS} -I${PGSQL_includedir} -Werror"
-      old_LDFLAGS=${LDFLAGS}
-      LDFLAGS="${LDFLAGS} -L${PGSQL_libdir} -lpq -lz"
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <libpq-fe.h>
-int
-main ()
-{
-const char *foo = pg_encoding_to_char(1)
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_PGSQL_pg_encoding_to_char 1
-_ACEOF
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-      CFLAGS=${old_CFLAGS}
-      LDFLAGS=${old_LDFLAGS}
-
-      if test "${ac_cv_lib_pq_PQescapeStringConn}" = "yes"; then
-         PGSQL_LIB="-L${PGSQL_libdir} -lpq -lz"
-         PGSQL_INCLUDE="-I${PGSQL_includedir}"
-         PBX_PGSQL=1
-      elif test -n "${PGSQL_MANDATORY}";
-      then
-         { $as_echo "$as_me:${as_lineno-$LINENO}: ***" >&5
-$as_echo "$as_me: ***" >&6;}
-         { $as_echo "$as_me:${as_lineno-$LINENO}: *** The PostgreSQL installation on this system appears to be broken." >&5
-$as_echo "$as_me: *** The PostgreSQL installation on this system appears to be broken." >&6;}
-         { $as_echo "$as_me:${as_lineno-$LINENO}: *** Either correct the installation, or run configure" >&5
-$as_echo "$as_me: *** Either correct the installation, or run configure" >&6;}
-         { $as_echo "$as_me:${as_lineno-$LINENO}: *** including --without-postgres" >&5
-$as_echo "$as_me: *** including --without-postgres" >&6;}
-         exit 1
-      fi
-   fi
-fi
-
-
-   if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PJPROJECT" >&5
-$as_echo_n "checking for PJPROJECT... " >&6; }
-
-if test -n "$PJPROJECT_CFLAGS"; then
-    pkg_cv_PJPROJECT_CFLAGS="$PJPROJECT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpjproject\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpjproject") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PJPROJECT_CFLAGS=`$PKG_CONFIG --cflags "libpjproject" 2>/dev/null`
-		      test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$PJPROJECT_LIBS"; then
-    pkg_cv_PJPROJECT_LIBS="$PJPROJECT_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpjproject\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpjproject") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PJPROJECT_LIBS=`$PKG_CONFIG --libs "libpjproject" 2>/dev/null`
-		      test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-	        PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpjproject" 2>&1`
-        else
-	        PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpjproject" 2>&1`
-        fi
-	# Put the nasty error message in config.log where it belongs
-	echo "$PJPROJECT_PKG_ERRORS" >&5
-
-
-            PBX_PJPROJECT=0
-
-
-elif test $pkg_failed = untried; then
-     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-            PBX_PJPROJECT=0
-
-
-else
-	PJPROJECT_CFLAGS=$pkg_cv_PJPROJECT_CFLAGS
-	PJPROJECT_LIBS=$pkg_cv_PJPROJECT_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-            PBX_PJPROJECT=1
-            PJPROJECT_INCLUDE="$PJPROJECT_CFLAGS"
-            PJPROJECT_LIB="$PJPROJECT_LIBS"
-
-$as_echo "#define HAVE_PJPROJECT 1" >>confdefs.h
-
-
-fi
-   fi
-
-
-
-if test "x${PBX_PJ_TRANSACTION_GRP_LOCK}" != "x1" -a "${USE_PJ_TRANSACTION_GRP_LOCK}" != "no"; then
-   pbxlibdir=""
-   # if --with-PJ_TRANSACTION_GRP_LOCK=DIR has been specified, use it.
-   if test "x${PJ_TRANSACTION_GRP_LOCK_DIR}" != "x"; then
-      if test -d ${PJ_TRANSACTION_GRP_LOCK_DIR}/lib; then
-         pbxlibdir="-L${PJ_TRANSACTION_GRP_LOCK_DIR}/lib"
-      else
-         pbxlibdir="-L${PJ_TRANSACTION_GRP_LOCK_DIR}"
-      fi
-   fi
-   pbxfuncname="pjsip_tsx_create_uac2"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_PJ_TRANSACTION_GRP_LOCK_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS"
-      as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_PJ_TRANSACTION_GRP_LOCK_FOUND=yes
-else
-  AST_PJ_TRANSACTION_GRP_LOCK_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_PJ_TRANSACTION_GRP_LOCK_FOUND}" = "yes"; then
-      PJ_TRANSACTION_GRP_LOCK_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIBS"
-      # if --with-PJ_TRANSACTION_GRP_LOCK=DIR has been specified, use it.
-      if test "x${PJ_TRANSACTION_GRP_LOCK_DIR}" != "x"; then
-         PJ_TRANSACTION_GRP_LOCK_INCLUDE="-I${PJ_TRANSACTION_GRP_LOCK_DIR}/include"
-      fi
-      PJ_TRANSACTION_GRP_LOCK_INCLUDE="${PJ_TRANSACTION_GRP_LOCK_INCLUDE} $PJPROJECT_CFLAGS"
-      if test "xpjsip.h" = "x" ; then	# no header, assume found
-         PJ_TRANSACTION_GRP_LOCK_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${PJ_TRANSACTION_GRP_LOCK_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default"
-if test "x$ac_cv_header_pjsip_h" = xyes; then :
-  PJ_TRANSACTION_GRP_LOCK_HEADER_FOUND=1
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pq_PQescapeStringConn=yes
 else
-  PJ_TRANSACTION_GRP_LOCK_HEADER_FOUND=0
+  ac_cv_lib_pq_PQescapeStringConn=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQescapeStringConn" >&5
+$as_echo "$ac_cv_lib_pq_PQescapeStringConn" >&6; }
+if test "x$ac_cv_lib_pq_PQescapeStringConn" = xyes; then :
 
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${PJ_TRANSACTION_GRP_LOCK_HEADER_FOUND}" = "x0" ; then
-         PJ_TRANSACTION_GRP_LOCK_LIB=""
-         PJ_TRANSACTION_GRP_LOCK_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            PJ_TRANSACTION_GRP_LOCK_LIB=""
-         fi
-         PBX_PJ_TRANSACTION_GRP_LOCK=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_PJ_TRANSACTION_GRP_LOCK 1
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PGSQL 1
 _ACEOF
 
-      fi
-   fi
 fi
 
 
-
-saved_cppflags="${CPPFLAGS}"
-saved_libs="${LIBS}"
-CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}"
-LIBS="${LIBS} ${PJPROJECT_LIBS}"
-
-    if test "x${PBX_PJSIP_REPLACE_MEDIA_STREAM}" != "x1" -a "${USE_PJSIP_REPLACE_MEDIA_STREAM}" != "no"; then
-        if test "x" != "x"; then
-            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for " >&5
-$as_echo_n "checking for ... " >&6; }
-	else
-            { $as_echo "$as_me:${as_lineno-$LINENO}: checking if \"pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE\" compiles using pjmedia.h" >&5
-$as_echo_n "checking if \"pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE\" compiles using pjmedia.h... " >&6; }
-	fi
-	saved_cppflags="${CPPFLAGS}"
-	if test "x${PJSIP_REPLACE_MEDIA_STREAM_DIR}" != "x"; then
-	    PJSIP_REPLACE_MEDIA_STREAM_INCLUDE="-I${PJSIP_REPLACE_MEDIA_STREAM_DIR}/include"
-	fi
-	CPPFLAGS="${CPPFLAGS} ${PJSIP_REPLACE_MEDIA_STREAM_INCLUDE}"
-
-	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pg_encoding_to_char within Postgres headers" >&5
+$as_echo_n "checking for pg_encoding_to_char within Postgres headers... " >&6; }
+      old_CFLAGS=${CFLAGS}
+      CFLAGS="${CFLAGS} -I${PGSQL_includedir} -Werror"
+      old_LDFLAGS=${LDFLAGS}
+      LDFLAGS="${LDFLAGS} -L${PGSQL_libdir} -lpq -lz"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- #include <pjmedia.h>
+#include <libpq-fe.h>
 int
 main ()
 {
- pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
-
+const char *foo = pg_encoding_to_char(1)
   ;
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-		PBX_PJSIP_REPLACE_MEDIA_STREAM=1
-
-$as_echo "#define HAVE_PJSIP_REPLACE_MEDIA_STREAM 1" >>confdefs.h
-
 
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PGSQL_pg_encoding_to_char 1
+_ACEOF
 
 else
-         { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-	CPPFLAGS="${saved_cppflags}"
-    fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+      CFLAGS=${old_CFLAGS}
+      LDFLAGS=${old_LDFLAGS}
 
-LIBS="${saved_libs}"
-CPPFLAGS="${saved_cppflags}"
+      if test "${ac_cv_lib_pq_PQescapeStringConn}" = "yes"; then
+         PGSQL_LIB="-L${PGSQL_libdir} -lpq -lz"
+         PGSQL_INCLUDE="-I${PGSQL_includedir}"
+         PBX_PGSQL=1
+      elif test -n "${PGSQL_MANDATORY}";
+      then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: ***" >&5
+$as_echo "$as_me: ***" >&6;}
+         { $as_echo "$as_me:${as_lineno-$LINENO}: *** The PostgreSQL installation on this system appears to be broken." >&5
+$as_echo "$as_me: *** The PostgreSQL installation on this system appears to be broken." >&6;}
+         { $as_echo "$as_me:${as_lineno-$LINENO}: *** Either correct the installation, or run configure" >&5
+$as_echo "$as_me: *** Either correct the installation, or run configure" >&6;}
+         { $as_echo "$as_me:${as_lineno-$LINENO}: *** including --without-postgres" >&5
+$as_echo "$as_me: *** including --without-postgres" >&6;}
+         exit 1
+      fi
+   fi
+fi
 
 
 if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then
@@ -26766,7 +25648,7 @@ fi
 
 fi
 
-# Check for libss7 v2.0 branch compatible version.
+# Check for libss7 v1.0 branch compatible version.
 
 if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
    pbxlibdir=""
@@ -26778,7 +25660,7 @@ if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
          pbxlibdir="-L${SS7_DIR}"
       fi
    fi
-   pbxfuncname="ss7_set_isup_timer"
+   pbxfuncname="ss7_set_adjpc"
    if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
       AST_SS7_FOUND=yes
    else
@@ -26977,111 +25859,6 @@ fi
 
 
 
-
-if test "x${PBX_OPUS}" != "x1" -a "${USE_OPUS}" != "no"; then
-   pbxlibdir=""
-   # if --with-OPUS=DIR has been specified, use it.
-   if test "x${OPUS_DIR}" != "x"; then
-      if test -d ${OPUS_DIR}/lib; then
-         pbxlibdir="-L${OPUS_DIR}/lib"
-      else
-         pbxlibdir="-L${OPUS_DIR}"
-      fi
-   fi
-   pbxfuncname="opus_encoder_create"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_OPUS_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_opus_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lopus" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lopus... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lopus ${pbxlibdir}  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_OPUS_FOUND=yes
-else
-  AST_OPUS_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_OPUS_FOUND}" = "yes"; then
-      OPUS_LIB="${pbxlibdir} -lopus "
-      # if --with-OPUS=DIR has been specified, use it.
-      if test "x${OPUS_DIR}" != "x"; then
-         OPUS_INCLUDE="-I${OPUS_DIR}/include"
-      fi
-      OPUS_INCLUDE="${OPUS_INCLUDE} "
-      if test "xopus/opus.h" = "x" ; then	# no header, assume found
-         OPUS_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${OPUS_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "opus/opus.h" "ac_cv_header_opus_opus_h" "$ac_includes_default"
-if test "x$ac_cv_header_opus_opus_h" = xyes; then :
-  OPUS_HEADER_FOUND=1
-else
-  OPUS_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${OPUS_HEADER_FOUND}" = "x0" ; then
-         OPUS_LIB=""
-         OPUS_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            OPUS_LIB=""
-         fi
-         PBX_OPUS=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_OPUS 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
 if test "${USE_PWLIB}" != "no"; then
 	if test -n "${PWLIB_DIR}"; then
 		PWLIBDIR="${PWLIB_DIR}"
@@ -28981,129 +27758,24 @@ fi
          CPPFLAGS="${CPPFLAGS} ${SQLITE_INCLUDE}"
          ac_fn_c_check_header_mongrel "$LINENO" "sqlite.h" "ac_cv_header_sqlite_h" "$ac_includes_default"
 if test "x$ac_cv_header_sqlite_h" = xyes; then :
-  SQLITE_HEADER_FOUND=1
-else
-  SQLITE_HEADER_FOUND=0
-fi
-
-
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${SQLITE_HEADER_FOUND}" = "x0" ; then
-         SQLITE_LIB=""
-         SQLITE_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            SQLITE_LIB=""
-         fi
-         PBX_SQLITE=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_SQLITE 1
-_ACEOF
-
-      fi
-   fi
-fi
-
-
-
-
-if test "x${PBX_SQLITE3}" != "x1" -a "${USE_SQLITE3}" != "no"; then
-   pbxlibdir=""
-   # if --with-SQLITE3=DIR has been specified, use it.
-   if test "x${SQLITE3_DIR}" != "x"; then
-      if test -d ${SQLITE3_DIR}/lib; then
-         pbxlibdir="-L${SQLITE3_DIR}/lib"
-      else
-         pbxlibdir="-L${SQLITE3_DIR}"
-      fi
-   fi
-   pbxfuncname="sqlite3_open"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_SQLITE3_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}"
-      as_ac_Lib=`$as_echo "ac_cv_lib_sqlite3_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite3" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lsqlite3... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsqlite3 ${pbxlibdir} ${PTHREAD_LIBS} $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
-int
-main ()
-{
-return ${pbxfuncname} ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_SQLITE3_FOUND=yes
-else
-  AST_SQLITE3_FOUND=no
-fi
-
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
-
-   # now check for the header.
-   if test "${AST_SQLITE3_FOUND}" = "yes"; then
-      SQLITE3_LIB="${pbxlibdir} -lsqlite3 ${PTHREAD_LIBS}"
-      # if --with-SQLITE3=DIR has been specified, use it.
-      if test "x${SQLITE3_DIR}" != "x"; then
-         SQLITE3_INCLUDE="-I${SQLITE3_DIR}/include"
-      fi
-      SQLITE3_INCLUDE="${SQLITE3_INCLUDE} ${PTHREAD_CFLAGS}"
-      if test "xsqlite3.h" = "x" ; then	# no header, assume found
-         SQLITE3_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${SQLITE3_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite3_h" = xyes; then :
-  SQLITE3_HEADER_FOUND=1
+  SQLITE_HEADER_FOUND=1
 else
-  SQLITE3_HEADER_FOUND=0
+  SQLITE_HEADER_FOUND=0
 fi
 
 
          CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
       fi
-      if test "x${SQLITE3_HEADER_FOUND}" = "x0" ; then
-         SQLITE3_LIB=""
-         SQLITE3_INCLUDE=""
+      if test "x${SQLITE_HEADER_FOUND}" = "x0" ; then
+         SQLITE_LIB=""
+         SQLITE_INCLUDE=""
       else
          if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            SQLITE3_LIB=""
+            SQLITE_LIB=""
          fi
-         PBX_SQLITE3=1
+         PBX_SQLITE=1
          cat >>confdefs.h <<_ACEOF
-#define HAVE_SQLITE3 1
+#define HAVE_SQLITE 1
 _ACEOF
 
       fi
@@ -29112,42 +27784,31 @@ fi
 
 
 
-if test "${PBX_SQLITE3}" != 1; then
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Asterisk now uses SQLite3 for the internal Asterisk database." >&5
-$as_echo "$as_me: WARNING: *** Asterisk now uses SQLite3 for the internal Asterisk database." >&2;}
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Please install the SQLite3 development package." >&5
-$as_echo "$as_me: WARNING: *** Please install the SQLite3 development package." >&2;}
-	exit 1
-fi
-
-# Find crypt support
-# * -lcrypt on *NIX
-# * in libsystem on OS X
 
-if test "x${PBX_LIBCRYPT}" != "x1" -a "${USE_LIBCRYPT}" != "no"; then
+if test "x${PBX_SQLITE3}" != "x1" -a "${USE_SQLITE3}" != "no"; then
    pbxlibdir=""
-   # if --with-LIBCRYPT=DIR has been specified, use it.
-   if test "x${LIBCRYPT_DIR}" != "x"; then
-      if test -d ${LIBCRYPT_DIR}/lib; then
-         pbxlibdir="-L${LIBCRYPT_DIR}/lib"
+   # if --with-SQLITE3=DIR has been specified, use it.
+   if test "x${SQLITE3_DIR}" != "x"; then
+      if test -d ${SQLITE3_DIR}/lib; then
+         pbxlibdir="-L${SQLITE3_DIR}/lib"
       else
-         pbxlibdir="-L${LIBCRYPT_DIR}"
+         pbxlibdir="-L${SQLITE3_DIR}"
       fi
    fi
-   pbxfuncname="crypt"
+   pbxfuncname="sqlite3_open"
    if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_LIBCRYPT_FOUND=yes
+      AST_SQLITE3_FOUND=yes
    else
       ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_crypt_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcrypt" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lcrypt... " >&6; }
+      CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}"
+      as_ac_Lib=`$as_echo "ac_cv_lib_sqlite3_${pbxfuncname}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite3" >&5
+$as_echo_n "checking for ${pbxfuncname} in -lsqlite3... " >&6; }
 if eval \${$as_ac_Lib+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt ${pbxlibdir}  $LIBS"
+LIBS="-lsqlite3 ${pbxlibdir} ${PTHREAD_LIBS} $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -29179,47 +27840,47 @@ eval ac_res=\$$as_ac_Lib
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
 if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_LIBCRYPT_FOUND=yes
+  AST_SQLITE3_FOUND=yes
 else
-  AST_LIBCRYPT_FOUND=no
+  AST_SQLITE3_FOUND=no
 fi
 
       CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
    fi
 
    # now check for the header.
-   if test "${AST_LIBCRYPT_FOUND}" = "yes"; then
-      LIBCRYPT_LIB="${pbxlibdir} -lcrypt "
-      # if --with-LIBCRYPT=DIR has been specified, use it.
-      if test "x${LIBCRYPT_DIR}" != "x"; then
-         LIBCRYPT_INCLUDE="-I${LIBCRYPT_DIR}/include"
-      fi
-      LIBCRYPT_INCLUDE="${LIBCRYPT_INCLUDE} "
-      if test "xcrypt.h" = "x" ; then	# no header, assume found
-         LIBCRYPT_HEADER_FOUND="1"
+   if test "${AST_SQLITE3_FOUND}" = "yes"; then
+      SQLITE3_LIB="${pbxlibdir} -lsqlite3 ${PTHREAD_LIBS}"
+      # if --with-SQLITE3=DIR has been specified, use it.
+      if test "x${SQLITE3_DIR}" != "x"; then
+         SQLITE3_INCLUDE="-I${SQLITE3_DIR}/include"
+      fi
+      SQLITE3_INCLUDE="${SQLITE3_INCLUDE} ${PTHREAD_CFLAGS}"
+      if test "xsqlite3.h" = "x" ; then	# no header, assume found
+         SQLITE3_HEADER_FOUND="1"
       else				# check for the header
          ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${LIBCRYPT_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default"
-if test "x$ac_cv_header_crypt_h" = xyes; then :
-  LIBCRYPT_HEADER_FOUND=1
+         CPPFLAGS="${CPPFLAGS} ${SQLITE3_INCLUDE}"
+         ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default"
+if test "x$ac_cv_header_sqlite3_h" = xyes; then :
+  SQLITE3_HEADER_FOUND=1
 else
-  LIBCRYPT_HEADER_FOUND=0
+  SQLITE3_HEADER_FOUND=0
 fi
 
 
          CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
       fi
-      if test "x${LIBCRYPT_HEADER_FOUND}" = "x0" ; then
-         LIBCRYPT_LIB=""
-         LIBCRYPT_INCLUDE=""
+      if test "x${SQLITE3_HEADER_FOUND}" = "x0" ; then
+         SQLITE3_LIB=""
+         SQLITE3_INCLUDE=""
       else
          if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            LIBCRYPT_LIB=""
+            SQLITE3_LIB=""
          fi
-         PBX_LIBCRYPT=1
+         PBX_SQLITE3=1
          cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBCRYPT 1
+#define HAVE_SQLITE3 1
 _ACEOF
 
       fi
@@ -29227,76 +27888,14 @@ _ACEOF
 fi
 
 
-ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
-if test "x$ac_cv_func_crypt" = xyes; then :
-  SYSCRYPT=true
-else
-  SYSCRYPT=""
-fi
-
-
-if test "x$LIBCRYPT_LIB" != "x" ; then
-    CRYPT_LIB="$LIBCRYPT_LIB"
-    CRYPT_INCLUDE="$LIBCRYPT_INCLUDE"
-
-$as_echo "#define HAVE_CRYPT 1" >>confdefs.h
-
-elif test "x$SYSCRYPT" != "x" ; then
-    CRYPT_LIB=""
-    CRYPT_INCLUDE=""
-
-$as_echo "#define HAVE_CRYPT 1" >>confdefs.h
-
-fi
-
-
-
-
-# Find crypt_r support
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt_r in -lcrypt" >&5
-$as_echo_n "checking for crypt_r in -lcrypt... " >&6; }
-if ${ac_cv_lib_crypt_crypt_r+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crypt_r ();
-int
-main ()
-{
-return crypt_r ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_crypt_crypt_r=yes
-else
-  ac_cv_lib_crypt_crypt_r=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt_r" >&5
-$as_echo "$ac_cv_lib_crypt_crypt_r" >&6; }
-if test "x$ac_cv_lib_crypt_crypt_r" = xyes; then :
-
-$as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h
 
+if test "${PBX_SQLITE3}" != 1; then
+	as_fn_error $? "*** Asterisk now uses SQLite3 for the internal Asterisk database." "$LINENO" 5
+	as_fn_error $? "*** Please install the SQLite3 development package." "$LINENO" 5
+	exit 1
 fi
 
 
-
 if test "x${PBX_CRYPTO}" != "x1" -a "${USE_CRYPTO}" != "no"; then
    pbxlibdir=""
    # if --with-CRYPTO=DIR has been specified, use it.
@@ -29747,108 +28346,47 @@ fi
 if test "$PBX_OPENSSL" = "1";
 then
 
-if test "x${PBX_OPENSSL_EC}" != "x1" -a "${USE_OPENSSL_EC}" != "no"; then
-   pbxlibdir=""
-   # if --with-OPENSSL_EC=DIR has been specified, use it.
-   if test "x${OPENSSL_EC_DIR}" != "x"; then
-      if test -d ${OPENSSL_EC_DIR}/lib; then
-         pbxlibdir="-L${OPENSSL_EC_DIR}/lib"
-      else
-         pbxlibdir="-L${OPENSSL_EC_DIR}"
-      fi
-   fi
-   pbxfuncname="EC_KEY_new_by_curve_name"
-   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
-      AST_OPENSSL_EC_FOUND=yes
-   else
-      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
-      CFLAGS="${CFLAGS} "
-      as_ac_Lib=`$as_echo "ac_cv_lib_ssl_${pbxfuncname}" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lssl" >&5
-$as_echo_n "checking for ${pbxfuncname} in -lssl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lssl ${pbxlibdir} -lcrypto $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+    if test "x${PBX_OPENSSL_ECDH_AUTO}" != "x1" -a "${USE_OPENSSL_ECDH_AUTO}" != "no"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h" >&5
+$as_echo_n "checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h... " >&6; }
+        saved_cppflags="${CPPFLAGS}"
+        if test "x${OPENSSL_ECDH_AUTO_DIR}" != "x"; then
+            OPENSSL_ECDH_AUTO_INCLUDE="-I${OPENSSL_ECDH_AUTO_DIR}/include"
+        fi
+        CPPFLAGS="${CPPFLAGS} ${OPENSSL_ECDH_AUTO_INCLUDE}"
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ${pbxfuncname} ();
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+ #include <openssl/ssl.h>
 int
 main ()
 {
-return ${pbxfuncname} ();
+#if !defined(SSL_CTX_set_ecdh_auto)
+                                    (void) SSL_CTX_set_ecdh_auto;
+                                #endif
+
   ;
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$as_ac_Lib=yes"
-else
-  eval "$as_ac_Lib=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-eval ac_res=\$$as_ac_Lib
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
-  AST_OPENSSL_EC_FOUND=yes
-else
-  AST_OPENSSL_EC_FOUND=no
-fi
+if ac_fn_c_try_compile "$LINENO"; then :
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                PBX_OPENSSL_ECDH_AUTO=1
 
-      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
-   fi
+$as_echo "#define HAVE_OPENSSL_ECDH_AUTO 1" >>confdefs.h
 
-   # now check for the header.
-   if test "${AST_OPENSSL_EC_FOUND}" = "yes"; then
-      OPENSSL_EC_LIB="${pbxlibdir} -lssl -lcrypto"
-      # if --with-OPENSSL_EC=DIR has been specified, use it.
-      if test "x${OPENSSL_EC_DIR}" != "x"; then
-         OPENSSL_EC_INCLUDE="-I${OPENSSL_EC_DIR}/include"
-      fi
-      OPENSSL_EC_INCLUDE="${OPENSSL_EC_INCLUDE} "
-      if test "xopenssl/ec.h" = "x" ; then	# no header, assume found
-         OPENSSL_EC_HEADER_FOUND="1"
-      else				# check for the header
-         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
-         CPPFLAGS="${CPPFLAGS} ${OPENSSL_EC_INCLUDE}"
-         ac_fn_c_check_header_mongrel "$LINENO" "openssl/ec.h" "ac_cv_header_openssl_ec_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_ec_h" = xyes; then :
-  OPENSSL_EC_HEADER_FOUND=1
-else
-  OPENSSL_EC_HEADER_FOUND=0
-fi
 
 
-         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
-      fi
-      if test "x${OPENSSL_EC_HEADER_FOUND}" = "x0" ; then
-         OPENSSL_EC_LIB=""
-         OPENSSL_EC_INCLUDE=""
-      else
-         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
-            OPENSSL_EC_LIB=""
-         fi
-         PBX_OPENSSL_EC=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_OPENSSL_EC 1
-_ACEOF
+else
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-      fi
-   fi
 fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+        CPPFLAGS="${saved_cppflags}"
+    fi
 
 fi
 
@@ -30580,6 +29118,111 @@ fi
 
 
 
+
+if test "x${PBX_UUID}" != "x1" -a "${USE_UUID}" != "no"; then
+   pbxlibdir=""
+   # if --with-UUID=DIR has been specified, use it.
+   if test "x${UUID_DIR}" != "x"; then
+      if test -d ${UUID_DIR}/lib; then
+         pbxlibdir="-L${UUID_DIR}/lib"
+      else
+         pbxlibdir="-L${UUID_DIR}"
+      fi
+   fi
+   pbxfuncname="uuid_generate_random"
+   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
+      AST_UUID_FOUND=yes
+   else
+      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
+      CFLAGS="${CFLAGS} "
+      as_ac_Lib=`$as_echo "ac_cv_lib_uuid_${pbxfuncname}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -luuid" >&5
+$as_echo_n "checking for ${pbxfuncname} in -luuid... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-luuid ${pbxlibdir}  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ${pbxfuncname} ();
+int
+main ()
+{
+return ${pbxfuncname} ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+  AST_UUID_FOUND=yes
+else
+  AST_UUID_FOUND=no
+fi
+
+      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
+   fi
+
+   # now check for the header.
+   if test "${AST_UUID_FOUND}" = "yes"; then
+      UUID_LIB="${pbxlibdir} -luuid "
+      # if --with-UUID=DIR has been specified, use it.
+      if test "x${UUID_DIR}" != "x"; then
+         UUID_INCLUDE="-I${UUID_DIR}/include"
+      fi
+      UUID_INCLUDE="${UUID_INCLUDE} "
+      if test "xuuid/uuid.h" = "x" ; then	# no header, assume found
+         UUID_HEADER_FOUND="1"
+      else				# check for the header
+         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${UUID_INCLUDE}"
+         ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
+if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
+  UUID_HEADER_FOUND=1
+else
+  UUID_HEADER_FOUND=0
+fi
+
+
+         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+      fi
+      if test "x${UUID_HEADER_FOUND}" = "x0" ; then
+         UUID_LIB=""
+         UUID_INCLUDE=""
+      else
+         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
+            UUID_LIB=""
+         fi
+         PBX_UUID=1
+         cat >>confdefs.h <<_ACEOF
+#define HAVE_UUID 1
+_ACEOF
+
+      fi
+   fi
+fi
+
+
+
 if test "${OSARCH}" = "OpenBSD";
 then
 
@@ -31044,6 +29687,16 @@ rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 fi
 
+ac_fn_c_check_header_mongrel "$LINENO" "h323.h" "ac_cv_header_h323_h" "$ac_includes_default"
+if test "x$ac_cv_header_h323_h" = xyes; then :
+  PBX_H323=1
+else
+  PBX_H323=0
+fi
+
+
+
+
 ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default"
 if test "x$ac_cv_header_linux_compiler_h" = xyes; then :
 
@@ -31166,7 +29819,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
 
-		if test "x${PBX_SDL}" != "x1" -a "${USE_SDL}" != "no"; then
+	if test "x${PBX_SDL}" != "x1" -a "${USE_SDL}" != "no"; then
 		PBX_SDL=0
 		if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}sdl-config", so it can be a program name with args.
@@ -32411,7 +31064,7 @@ else
 	touch makeopts.acbak
 fi
 
-ac_config_files="$ac_config_files build_tools/menuselect-deps makeopts"
+ac_config_files="$ac_config_files build_tools/menuselect-deps makeopts channels/h323/Makefile"
 
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mandatory modules: ${ac_mandatory_list}" >&5
@@ -33144,6 +31797,7 @@ do
     "include/asterisk/autoconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS include/asterisk/autoconfig.h" ;;
     "build_tools/menuselect-deps") CONFIG_FILES="$CONFIG_FILES build_tools/menuselect-deps" ;;
     "makeopts") CONFIG_FILES="$CONFIG_FILES makeopts" ;;
+    "channels/h323/Makefile") CONFIG_FILES="$CONFIG_FILES channels/h323/Makefile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
diff --git a/configure.ac b/configure.ac
index 3aa8c28..0791046 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ AC_CONFIG_SRCDIR([main/asterisk.c])
 AC_CONFIG_AUX_DIR(`pwd`)
 
 AC_COPYRIGHT("Asterisk")
-AC_REVISION($Revision: 426234 $)
+AC_REVISION($Revision$)
 
 # preserve any CFLAGS or LDFLAGS that may be set
 # NOTE: This must be done before calling any macros that end up
@@ -192,25 +192,6 @@ esac
 AC_SUBST(OSARCH)
 AC_SUBST(PBX_WINARCH)
 
-AC_MSG_CHECKING(whether char is unsigned)
-AC_COMPILE_IFELSE(
-	[
-		AC_LANG_SOURCE(
-#include <limits.h>
-#if CHAR_MIN == 0
-#error
-#endif
-		)
-	],[
-		AC_MSG_RESULT(no)
-		CONFIG_SIGNED_CHAR=""
-	],[
-		AC_MSG_RESULT(yes)
-		CONFIG_SIGNED_CHAR="-fsigned-char"
-	]
-)
-AC_SUBST(CONFIG_SIGNED_CHAR)
-
 #  check for uname
 AC_PATH_TOOL([UNAME], [uname], No)
 if test ! x"${UNAME}" = xNo; then
@@ -273,7 +254,6 @@ AC_PATH_PROG([BASENAME], [basename], :)
 AC_PATH_PROG([DIRNAME], [dirname], :)
 AC_PATH_PROG([SHELL], [sh], :)
 AC_PATH_PROG([LN], [ln], :)
-AC_PATH_PROG([DOXYGEN], [doxygen], :)
 AC_PATH_PROG([DOT], [dot], :)
 AC_PATH_PROG([WGET], [wget], :)
 AC_PATH_PROG([CURL], [curl], :)
@@ -386,6 +366,9 @@ AC_ARG_ENABLE([coverage],
 	esac])
 AC_SUBST(AST_CODE_COVERAGE)
 
+AST_CHECK_RAII()
+AST_CHECK_STRSEP_ARRAY_BOUNDS()
+
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
 # various packages.
 # $1 is the prefix for the variables in makeopts and autoconfig.h
@@ -407,10 +390,9 @@ AST_EXT_LIB_SETUP([CAP], [POSIX 1.e capabilities], [cap])
 AST_EXT_LIB_SETUP([COROSYNC], [Corosync], [cpg])
 AST_EXT_LIB_SETUP_OPTIONAL([COROSYNC_CFG_STATE_TRACK], [A callback only in corosync 1.x], [COROSYNC], [cfg])
 AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
-AST_EXT_LIB_SETUP([CRYPT], [password and data encryption], [crypt])
 AST_EXT_LIB_SETUP([CRYPTO], [OpenSSL Cryptography], [crypto])
 AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_SRTP], [OpenSSL SRTP Extension Support], [CRYPTO], [crypto])
-AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_EC], [OpenSSL Elliptic Curve Support], [CRYPTO], [crypto])
+AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_ECDH_AUTO], [OpenSSL Auto ECDH Support], [CRYPTO], [crypto])
 AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi])
 AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec], [avcodec])
 AST_EXT_LIB_SETUP([GSM], [External GSM], [gsm], [, use 'internal' GSM otherwise])
@@ -427,15 +409,11 @@ AST_EXT_LIB_SETUP([INOTIFY], [inotify support], [inotify])
 AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc])
 AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet])
 AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
-AST_EXT_LIB_SETUP([JANSSON], [Jansson JSON library], [jansson])
-AST_EXT_LIB_SETUP([URIPARSER], [uriparser library], [uriparser])
 AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue])
 AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap])
 AST_LIBCURL_CHECK_CONFIG([], [7.10.1])
 AST_EXT_LIB_SETUP([LIBEDIT], [NetBSD Editline library], [libedit], [, use 'internal' Editline otherwise])
 AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2])
-AST_EXT_LIB_SETUP([LIBXSLT], [LibXSLT], [libxslt])
-AST_EXT_LIB_SETUP_OPTIONAL([LIBXSLT_CLEANUP], [LibXSLT Library Cleanup Function], [LIBXSLT], [libxslt])
 AST_EXT_LIB_SETUP([LTDL], [libtool], [ltdl])
 AST_EXT_LIB_SETUP([LUA], [Lua], [lua])
 AST_EXT_LIB_SETUP([MISDN], [mISDN user], [misdn])
@@ -448,14 +426,10 @@ AST_EXT_LIB_SETUP([NETSNMP], [Net-SNMP], [netsnmp])
 AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
 AST_EXT_LIB_SETUP([OGG], [OGG], [ogg])
 AST_EXT_LIB_SETUP([OPENR2], [MFR2], [openr2])
-AST_EXT_LIB_SETUP([OPUS], [Opus], [opus])
 AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk])
 AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss])
 AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
-AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject])
 AST_EXT_LIB_SETUP([POPT], [popt], [popt])
-AST_EXT_LIB_SETUP_OPTIONAL([PJ_TRANSACTION_GRP_LOCK], [PJSIP Transaction Group Lock Support], [PJPROJECT], [pjsip])
-AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_REPLACE_MEDIA_STREAM], [PJSIP Media Stream Replacement Support], [PJPROJECT], [pjsip])
 AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
 AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
 AST_EXT_LIB_SETUP_OPTIONAL([PRI_SETUP_ACK_INBAND], [ISDN PRI progress inband ie in SETUP ACK], [PRI], [pri])
@@ -506,6 +480,7 @@ AST_EXT_LIB_SETUP([TIMERFD], [timerfd], [timerfd])
 AST_EXT_LIB_SETUP([TINFO], [Term Info], [tinfo])
 AST_EXT_LIB_SETUP([TONEZONE], [tonezone], [tonezone])
 AST_EXT_LIB_SETUP([UNIXODBC], [unixODBC], [unixodbc])
+AST_EXT_LIB_SETUP([UUID], [UUID], [uuid])
 AST_EXT_LIB_SETUP([VORBIS], [Vorbis], [vorbis])
 AST_EXT_LIB_SETUP([VPB], [Voicetronix API], [vpb])
 AST_EXT_LIB_SETUP([X11], [X11], [x11])
@@ -520,7 +495,7 @@ AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h libintl.h limits.h locale.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/event.h sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h utime.h arpa/nameser.h sys/io.h])
 
-# Any one of these packages support a mandatory requirement, so we want to check on them as early as possible.
+# Any one of these 4 packages support a mandatory requirement, so we want to check on them as early as possible.
 AST_EXT_LIB_CHECK([TERMCAP], [termcap], [tgetent], [])
 AST_EXT_LIB_CHECK([TINFO], [tinfo], [tgetent], [])
 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
@@ -540,49 +515,6 @@ else
 fi
 AC_SUBST(EDITLINE_LIB)
 
-# Find required UUID support.
-#  * -luuid on Linux
-#  * -le2fs-uuid on OpenBSD
-#  * in libsystem on OS X
-AST_EXT_LIB_CHECK([LIBUUID], [uuid], [uuid_generate_random], [uuid/uuid.h], [])
-AST_EXT_LIB_CHECK([E2FSUUID], [e2fs-uuid], [uuid_generate_random], [uuid/uuid.h], [])
-AC_CHECK_FUNCS([uuid_generate_random], [SYSUUID=true], [SYSUUID=""])
-
-if test "x$LIBUUID_LIB" != "x" ; then
-  UUID_INCLUDE="$LIBUUID_INCLUDE"
-  UUID_LIB="$LIBUUID_LIB"
-elif test "x$E2FSUUID_LIB" != "x" ; then
-  UUID_INCLUDE="$E2FSUUID_INCLUDE"
-  UUID_LIB="$E2FSUUID_LIB"
-elif test "x$SYSUUID" != "x" ; then
-  UUID_INCLUDE=""
-  UUID_LIB=""
-else
-  AC_MSG_ERROR([*** uuid support not found (this typically means the uuid development package is missing)])
-fi
-AC_SUBST(UUID_INCLUDE)
-AC_SUBST(UUID_LIB)
-
-# Find required JSON support.
-AST_EXT_LIB_CHECK([JANSSON], [jansson], [json_dumps], [jansson.h])
-
-if test "x$JANSSON_LIB" == "x"; then
-  AC_MSG_ERROR([*** JSON support not found (this typically means the libjansson development package is missing)])
-fi
-
-AST_EXT_TOOL_CHECK([LIBXML2], [xml2-config], , ,
-        [#include <libxml/tree.h>
-        #include <libxml/parser.h>],
-        [LIBXML_TEST_VERSION])
-
-if test "${PBX_LIBXML2}" != 1; then
-	AC_MSG_NOTICE(*** The Asterisk menuselect tool requires the 'libxml2' development package.)
-	AC_MSG_NOTICE(*** Please install the 'libxml2' development package.)
-	exit 1
-fi
-
-AST_EXT_LIB_CHECK([URIPARSER], [uriparser], [uriParseUriA], [uriparser/Uri.h])
-
 # Another mandatory item (unless it's explicitly disabled)
 AC_ARG_ENABLE([xmldoc],
 	[AS_HELP_STRING([--disable-xmldoc],
@@ -594,9 +526,16 @@ AC_ARG_ENABLE([xmldoc],
 	esac], [disable_xmldoc=no])
 
 if test "${disable_xmldoc}" != "yes"; then
-        AST_EXT_LIB_CHECK([LIBXSLT], [xslt], [xsltLoadStylesheetPI], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
-        AST_EXT_LIB_CHECK([LIBXSLT_CLEANUP], [xslt], [xsltCleanupGlobals], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
-
+	AST_EXT_TOOL_CHECK([LIBXML2], [xml2-config], , ,
+	[#include <libxml/tree.h>
+	#include <libxml/parser.h>],
+	[LIBXML_TEST_VERSION])
+	if test "${PBX_LIBXML2}" != 1; then
+		AC_MSG_NOTICE(*** XML documentation will not be available because the 'libxml2' development package is missing.)
+		AC_MSG_NOTICE(*** Please run the 'configure' script with the '--disable-xmldoc' parameter option)
+		AC_MSG_NOTICE(*** or install the 'libxml2' development package.)
+		exit 1
+	fi
 fi
 
 # some embedded systems omit internationalization (locale) support
@@ -791,6 +730,11 @@ AC_DEFINE([HAVE_SYS_ENDIAN_BSWAP16], 1, [Define to 1 if your sys/endian.h header
 AC_MSG_RESULT(no)
 )
 
+if test "${cross_compiling}" = "no";
+then
+  AC_CHECK_FILE(/dev/urandom, AC_DEFINE([HAVE_DEV_URANDOM], 1, [Define to 1 if your system has /dev/urandom.]))
+fi
+
 AC_MSG_CHECKING(for locale_t in locale.h)
 AC_LINK_IFELSE(
 [AC_LANG_PROGRAM([#include <locale.h>], [locale_t lt = NULL])],
@@ -840,28 +784,11 @@ AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE_NP], 1, [Define to 1 if your system defi
 AC_MSG_RESULT(no)
 )
 
-AC_MSG_CHECKING(for PTHREAD_MUTEX_ADAPTIVE_NP in pthread.h)
-AC_LINK_IFELSE(
-[AC_LANG_PROGRAM([#include <pthread.h>], [int a = PTHREAD_MUTEX_ADAPTIVE_NP;])],
-AC_MSG_RESULT(yes)
-AC_DEFINE([HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], 1, [Define to 1 if your system defines PTHREAD_MUTEX_ADAPTIVE_NP in pthread.h]),
-AC_MSG_RESULT(no)
-)
-
-AC_MSG_CHECKING(for pthread_spinlock_t in pthread.h)
-AC_LINK_IFELSE(
-[AC_LANG_PROGRAM([#include <pthread.h>], [pthread_spinlock_t spin;])],
-AC_MSG_RESULT(yes)
-AC_DEFINE([HAVE_PTHREAD_SPINLOCK], 1, [Define to 1 if your system has pthread_spinlock_t in pthread.h]),
-AC_MSG_RESULT(no)
-)
-
+AC_MSG_CHECKING(for pthread_rwlock_timedwrlock() in pthread.h)
 save_LIBS="$LIBS"
 save_CFLAGS="$CFLAGS"
 LIBS="$PTHREAD_LIBS $LIBS"
 CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
-AC_MSG_CHECKING(for pthread_rwlock_timedwrlock() in pthread.h)
 AC_LINK_IFELSE(
   [AC_LANG_PROGRAM(
     [#include <pthread.h>
@@ -875,17 +802,6 @@ AC_LINK_IFELSE(
     ac_cv_pthread_rwlock_timedwrlock="no"
   ]
 )
-
-# Some platforms define sem_init(), but only support sem_open(). joyous.
-AC_MSG_CHECKING(for working unnamed semaphores)
-AC_RUN_IFELSE(
-	[AC_LANG_PROGRAM([#include <semaphore.h>],
-		[sem_t sem; return sem_init(&sem, 0, 0);])],
-	AC_MSG_RESULT(yes)
-	AC_DEFINE([HAS_WORKING_SEMAPHORE], 1, [Define to 1 if anonymous semaphores work.]),
-	AC_MSG_RESULT(no)
-)
-
 LIBS="$save_LIBS"
 CFLAGS="$save_CFLAGS"
 if test "${ac_cv_pthread_rwlock_timedwrlock}" = "yes"; then
@@ -1017,9 +933,37 @@ AST_GCC_ATTRIBUTE(always_inline)
 AST_GCC_ATTRIBUTE(deprecated)
 AST_GCC_ATTRIBUTE(sentinel)
 AST_GCC_ATTRIBUTE(warn_unused_result)
-AST_GCC_ATTRIBUTE(may_alias)
-AST_GCC_ATTRIBUTE(constructor)
-AST_GCC_ATTRIBUTE(destructor)
+
+# Support weak symbols on a platform specific basis.  The Mac OS X
+# (Darwin) support must be isolated from the other platforms because
+# it has caused other platforms to fail.
+#
+case "${OSARCH}" in
+	darwin*)
+	# Allow weak symbol support on Darwin platforms only because there
+	# is active community support for it.
+	# However, Darwin seems to break weak symbols for each new version.
+	#
+	AST_GCC_ATTRIBUTE(weak_import, [], [], PBX_WEAKREF)
+
+	# Several other platforms including Linux have GCC versions that
+	# define the weak attribute.  However, this attribute is only
+	# setup for use in the code by Darwin.
+	AST_GCC_ATTRIBUTE(weak, [], [], PBX_WEAKREF)
+	;;
+	linux-gnu)
+	# Primarily support weak symbols on Linux platforms.
+	#
+	AST_GCC_ATTRIBUTE(weakref, [weakref("foo")], static, PBX_WEAKREF)
+	;;
+	*)
+	# Allow weak symbols on other platforms.  However, any problems
+	# with this feature on other platforms must be fixed by the
+	# community.
+	#
+	AST_GCC_ATTRIBUTE(weakref, [weakref("foo")], static, PBX_WEAKREF)
+	;;
+esac
 
 AC_MSG_CHECKING(for -ffunction-sections support)
 saved_CFLAGS="${CFLAGS}"
@@ -1055,7 +999,7 @@ fi
 AC_SUBST(AST_DECLARATION_AFTER_STATEMENT)
 
 AC_MSG_CHECKING(for -Wtrampolines support)
-if $(${CC} -Wtrampolines -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+if $(${CC} -Wtrampolines -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
 	AC_MSG_RESULT(yes)
 	AST_TRAMPOLINES=-Wtrampolines
 else
@@ -1109,17 +1053,6 @@ else
 fi
 AC_SUBST(AST_NATIVE_ARCH)
 
-dnl Nested functions required for RAII implementation
-AC_MSG_CHECKING(for -fnested-functions)
-AC_COMPILE_IFELSE(
-	dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
-	[AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])],
-	AC_MSG_RESULT(no)
-	[AST_NESTED_FUNCTIONS=],
-	AC_MSG_RESULT(required)
-	[AST_NESTED_FUNCTIONS=-fnested-functions]
-)
-AC_SUBST(AST_NESTED_FUNCTIONS)
 
 dnl Check to see if rpath should be set in LDFLAGS
 AC_ARG_ENABLE(rpath,
@@ -1138,7 +1071,18 @@ if test "${check_rpath}" != yes; then
 elif test "${prefix}" = /usr || test "${prefix}" = NONE; then
 	AC_MSG_RESULT(not needed)
 else
-	AST_RPATH="-Wl,-rpath,${libdir}"
+	case "${host_os}" in
+		darwin*)
+			AC_MSG_RESULT(not supported)
+			# We set macosx_version_min to 10.4, which doesn't
+			# support rpath. However, we set install_name on our
+			# dylibs, so it's not strictly necessary.
+			;;
+		*)
+			AC_MSG_RESULT(required)
+			AST_RPATH="-Wl,-rpath,${libdir}"
+			;;
+	esac
 fi
 AC_SUBST(AST_RPATH)
 
@@ -1213,8 +1157,6 @@ AST_C_DEFINE_CHECK([GLOB_NOMAGIC], [GLOB_NOMAGIC], [glob.h])
 
 AST_C_DEFINE_CHECK([GLOB_BRACE], [GLOB_BRACE], [glob.h])
 
-AST_C_DEFINE_CHECK([RTLD_NOLOAD], [RTLD_NOLOAD], [dlfcn.h])
-
 AST_C_DEFINE_CHECK([IP_MTU_DISCOVER], [IP_MTU_DISCOVER], [netinet/in.h])
 
 AC_CHECK_HEADER([libkern/OSAtomic.h],
@@ -2059,18 +2001,6 @@ if test "${PG_CONFIG}" != No; then
    fi
 fi
 
-AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject])
-
-AST_EXT_LIB_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip], [pjsip_tsx_create_uac2], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS])
-
-saved_cppflags="${CPPFLAGS}"
-saved_libs="${LIBS}"
-CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}"
-LIBS="${LIBS} ${PJPROJECT_LIBS}"
-AST_C_COMPILE_CHECK([PJSIP_REPLACE_MEDIA_STREAM], [pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE], [pjmedia.h])
-LIBS="${saved_libs}"
-CPPFLAGS="${saved_cppflags}"
-
 AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
 
 AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h])
@@ -2123,13 +2053,11 @@ if test "x${PBX_SPANDSP}" = "x1" ; then
 	AST_EXT_LIB_CHECK([SPANDSP], [spandsp], [t38_terminal_init], [spandsp.h], [-ltiff])
 fi
 
-# Check for libss7 v2.0 branch compatible version.
-AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_isup_timer], [libss7.h])
+# Check for libss7 v1.0 branch compatible version.
+AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_adjpc], [libss7.h])
 
 AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h])
 
-AST_EXT_LIB_CHECK([OPUS], [opus], [opus_encoder_create], [opus/opus.h])
-
 if test "${USE_PWLIB}" != "no"; then
 	if test -n "${PWLIB_DIR}"; then
 		PWLIBDIR="${PWLIB_DIR}"
@@ -2219,34 +2147,11 @@ AST_EXT_LIB_CHECK([SQLITE], [sqlite], [sqlite_exec], [sqlite.h])
 AST_EXT_LIB_CHECK([SQLITE3], [sqlite3], [sqlite3_open], [sqlite3.h], [${PTHREAD_LIBS}], [${PTHREAD_CFLAGS}])
 
 if test "${PBX_SQLITE3}" != 1; then
-	AC_MSG_WARN(*** Asterisk now uses SQLite3 for the internal Asterisk database.)
-	AC_MSG_WARN(*** Please install the SQLite3 development package.)
+	AC_MSG_ERROR(*** Asterisk now uses SQLite3 for the internal Asterisk database.)
+	AC_MSG_ERROR(*** Please install the SQLite3 development package.)
 	exit 1
 fi
 
-# Find crypt support
-# * -lcrypt on *NIX
-# * in libsystem on OS X
-AST_EXT_LIB_CHECK([LIBCRYPT], [crypt], [crypt], [crypt.h])
-AC_CHECK_FUNC([crypt], [SYSCRYPT=true], [SYSCRYPT=""])
-
-if test "x$LIBCRYPT_LIB" != "x" ; then
-    CRYPT_LIB="$LIBCRYPT_LIB"
-    CRYPT_INCLUDE="$LIBCRYPT_INCLUDE"
-    AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the `crypt' function.])
-elif test "x$SYSCRYPT" != "x" ; then
-    CRYPT_LIB=""
-    CRYPT_INCLUDE=""
-    AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the `crypt' function.])
-fi
-
-AC_SUBST(CRYPT_LIB)
-AC_SUBST(CRYPT_INCLUDE)
-
-# Find crypt_r support
-AC_CHECK_LIB([crypt], [crypt_r],
-    [AC_DEFINE([HAVE_CRYPT_R], [1], [Define to 1 if you have the `crypt_r' function.])])
-
 AST_EXT_LIB_CHECK([CRYPTO], [crypto], [AES_encrypt], [openssl/aes.h])
 
 if test "$PBX_CRYPTO" = "1";
@@ -2262,7 +2167,7 @@ fi
 
 if test "$PBX_OPENSSL" = "1";
 then
-	AST_EXT_LIB_CHECK([OPENSSL_EC], [ssl], [EC_KEY_new_by_curve_name], [openssl/ec.h], [-lcrypto])
+        AST_C_DECLARE_CHECK([OPENSSL_ECDH_AUTO], [SSL_CTX_set_ecdh_auto], [openssl/ssl.h])
 fi
 
 AST_EXT_LIB_CHECK([SRTP], [srtp], [srtp_init], [srtp/srtp.h])
@@ -2325,6 +2230,8 @@ fi
 
 AST_EXT_LIB_CHECK([TONEZONE], [tonezone], [tone_zone_find], [dahdi/tonezone.h], [${tonezone_extra} ${DAHDI_INCLUDE}])
 
+AST_EXT_LIB_CHECK([UUID], [uuid], [uuid_generate_random], [uuid/uuid.h])
+
 if test "${OSARCH}" = "OpenBSD";
 then
 	AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc -lvorbisfile -logg])
@@ -2394,6 +2301,9 @@ if test "x${PBX_UNIXODBC}" = "x1" -o "x${PBX_IODBC}" = "x1"; then
 	)
 fi
 
+AC_CHECK_HEADER([h323.h], [PBX_H323=1], [PBX_H323=0])
+AC_SUBST(PBX_H323)
+
 AC_CHECK_HEADER([linux/compiler.h],
                 [AC_DEFINE_UNQUOTED([HAVE_LINUX_COMPILER_H], 1, [Define to 1 if your system has linux/compiler.h.])])
 
@@ -2478,7 +2388,7 @@ else
 	touch makeopts.acbak
 fi
 
-AC_CONFIG_FILES([build_tools/menuselect-deps makeopts])
+AC_CONFIG_FILES([build_tools/menuselect-deps makeopts channels/h323/Makefile])
 AST_CHECK_MANDATORY
 
 if test -f build_tools/menuselect-deps; then
diff --git a/contrib/ast-db-manage/README.md b/contrib/ast-db-manage/README.md
deleted file mode 100644
index 3444dd5..0000000
--- a/contrib/ast-db-manage/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-Asterisk Database Manager
-=========================
-
-Asterisk includes optional database integration for a variety of features.
-The purpose of this effort is to assist in managing the database schema
-for Asterisk database integration.
-
-This is implemented as a set of repositories that contain database schema
-migrations, using [Alembic](http://alembic.readthedocs.org).  The existing
-repositories include:
-
- * `config` - Tables used for Asterisk realtime configuration
- * `voicemail` - Tables used for `ODBC_STOARGE` of voicemail messages
-
-Alembic uses SQLAlchemy, which has support for
-[many databases](http://docs.sqlalchemy.org/en/rel_0_8/dialects/index.html).
-
-IMPORTANT NOTE: This is brand new and the initial migrations are still subject
-to change.  Only use this for testing purposes for now.
-
-Example Usage
--------------
-
-First, create an ini file that contains database connection details.  For help
-with connection string details, see the
-[SQLAlchemy docs](http://docs.sqlalchemy.org/en/rel_0_8/core/engines.html#database-urls).
-
-    $ cp config.ini.sample config.ini
-    ... edit config.ini and change sqlalchemy.url ...
-
-Next, bring the database up to date with the current schema.
-
-    $ alembic -c config.ini upgrade head
-
-In the future, as additional database migrations are added, you can run
-alembic again to migrate the existing tables to the latest schema.
-
-    $ alembic -c config.ini upgrade head
-
-The migrations support both upgrading and downgrading.  You could go all the
-way back to where you started with no tables by downgrading back to the base
-revision.
-
-    $ alembic -c config.ini downgrade base
-
-`base` and `head` are special revisions.  You can refer to specific revisions
-to upgrade or downgrade to, as well.
-
-    $ alembic -c config.ini upgrade 4da0c5f79a9c
-
-Offline Mode
-------------
-
-If you would like to just generate the SQL statements that would have been
-executed, you can use alembic's offline mode.
-
-    $ alembic -c config.ini upgrade head --sql
-
-Adding Database Migrations
---------------------------
-
-The best way to learn about how to add additional database migrations is to
-refer to the [Alembic documentation](http://alembic.readthedocs.org).
diff --git a/contrib/ast-db-manage/cdr.ini.sample b/contrib/ast-db-manage/cdr.ini.sample
deleted file mode 100644
index 58b8e6d..0000000
--- a/contrib/ast-db-manage/cdr.ini.sample
+++ /dev/null
@@ -1,57 +0,0 @@
-# A generic, single database configuration.
-
-[alembic]
-# path to migration scripts
-script_location = cdr
-
-# template used to generate migration files
-# file_template = %%(rev)s_%%(slug)s
-
-# max length of characters to apply to the
-# "slug" field
-#truncate_slug_length = 40
-
-# set to 'true' to run the environment during
-# the 'revision' command, regardless of autogenerate
-# revision_environment = false
-
-#sqlalchemy.url = driver://user:pass@localhost/dbname
-
-#sqlalchemy.url = postgresql://user:pass@localhost/cdr
-sqlalchemy.url = mysql://user:pass@localhost/cdr
-
-
-# Logging configuration
-[loggers]
-keys = root,sqlalchemy,alembic
-
-[handlers]
-keys = console
-
-[formatters]
-keys = generic
-
-[logger_root]
-level = WARN
-handlers = console
-qualname =
-
-[logger_sqlalchemy]
-level = WARN
-handlers =
-qualname = sqlalchemy.engine
-
-[logger_alembic]
-level = INFO
-handlers =
-qualname = alembic
-
-[handler_console]
-class = StreamHandler
-args = (sys.stderr,)
-level = NOTSET
-formatter = generic
-
-[formatter_generic]
-format = %(levelname)-5.5s [%(name)s] %(message)s
-datefmt = %H:%M:%S
diff --git a/contrib/ast-db-manage/cdr/env.py b/contrib/ast-db-manage/cdr/env.py
deleted file mode 100755
index 6740d59..0000000
--- a/contrib/ast-db-manage/cdr/env.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
-    fileConfig(config.config_file_name)
-except:
-    pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
-    """Run migrations in 'offline' mode.
-
-    This configures the context with just a URL
-    and not an Engine, though an Engine is acceptable
-    here as well.  By skipping the Engine creation
-    we don't even need a DBAPI to be available.
-
-    Calls to context.execute() here emit the given string to the
-    script output.
-
-    """
-    url = config.get_main_option("sqlalchemy.url")
-    context.configure(url=url)
-
-    with context.begin_transaction():
-        context.run_migrations()
-
-def run_migrations_online():
-    """Run migrations in 'online' mode.
-
-    In this scenario we need to create an Engine
-    and associate a connection with the context.
-
-    """
-    engine = engine_from_config(
-                config.get_section(config.config_ini_section),
-                prefix='sqlalchemy.',
-                poolclass=pool.NullPool)
-
-    connection = engine.connect()
-    context.configure(
-                connection=connection,
-                target_metadata=target_metadata
-                )
-
-    try:
-        with context.begin_transaction():
-            context.run_migrations()
-    finally:
-        connection.close()
-
-if context.is_offline_mode():
-    run_migrations_offline()
-else:
-    run_migrations_online()
-
diff --git a/contrib/ast-db-manage/cdr/script.py.mako b/contrib/ast-db-manage/cdr/script.py.mako
deleted file mode 100644
index 9570201..0000000
--- a/contrib/ast-db-manage/cdr/script.py.mako
+++ /dev/null
@@ -1,22 +0,0 @@
-"""${message}
-
-Revision ID: ${up_revision}
-Revises: ${down_revision}
-Create Date: ${create_date}
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = ${repr(up_revision)}
-down_revision = ${repr(down_revision)}
-
-from alembic import op
-import sqlalchemy as sa
-${imports if imports else ""}
-
-def upgrade():
-    ${upgrades if upgrades else "pass"}
-
-
-def downgrade():
-    ${downgrades if downgrades else "pass"}
diff --git a/contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py b/contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py
deleted file mode 100755
index 3ea9ed1..0000000
--- a/contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Richard Mudgett
-#
-# Richard Mudgett <rmudgett at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Create CDR table.
-
-Revision ID: 210693f3123d
-Revises: None
-Create Date: 2014-02-14 15:11:43.867292
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '210693f3123d'
-down_revision = None
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.create_table(
-        'cdr',
-        sa.Column('accountcode', sa.String(20)),
-        sa.Column('src', sa.String(80)),
-        sa.Column('dst', sa.String(80)),
-        sa.Column('dcontext', sa.String(80)),
-        sa.Column('clid', sa.String(80)),
-        sa.Column('channel', sa.String(80)),
-        sa.Column('dstchannel', sa.String(80)),
-        sa.Column('lastapp', sa.String(80)),
-        sa.Column('lastdata', sa.String(80)),
-        sa.Column('start', sa.DateTime()),
-        sa.Column('answer', sa.DateTime()),
-        sa.Column('end', sa.DateTime()),
-        sa.Column('duration', sa.Integer),
-        sa.Column('billsec', sa.Integer),
-        sa.Column('disposition', sa.String(45)),
-        sa.Column('amaflags', sa.String(45)),
-        sa.Column('userfield', sa.String(256)),
-        sa.Column('uniqueid', sa.String(150)),
-        sa.Column('linkedid', sa.String(150)),
-        sa.Column('peeraccount', sa.String(20)),
-        sa.Column('sequence', sa.Integer)
-    )
-
-
-def downgrade():
-    op.drop_table('cdr')
-
diff --git a/contrib/ast-db-manage/config.ini.sample b/contrib/ast-db-manage/config.ini.sample
deleted file mode 100644
index 107880e..0000000
--- a/contrib/ast-db-manage/config.ini.sample
+++ /dev/null
@@ -1,57 +0,0 @@
-# A generic, single database configuration.
-
-[alembic]
-# path to migration scripts
-script_location = config
-
-# template used to generate migration files
-# file_template = %%(rev)s_%%(slug)s
-
-# max length of characters to apply to the
-# "slug" field
-#truncate_slug_length = 40
-
-# set to 'true' to run the environment during
-# the 'revision' command, regardless of autogenerate
-# revision_environment = false
-
-#sqlalchemy.url = driver://user:pass@localhost/dbname
-
-#sqlalchemy.url = postgresql://user:pass@localhost/asterisk
-sqlalchemy.url = mysql://user:pass@localhost/asterisk
-
-
-# Logging configuration
-[loggers]
-keys = root,sqlalchemy,alembic
-
-[handlers]
-keys = console
-
-[formatters]
-keys = generic
-
-[logger_root]
-level = WARN
-handlers = console
-qualname =
-
-[logger_sqlalchemy]
-level = WARN
-handlers =
-qualname = sqlalchemy.engine
-
-[logger_alembic]
-level = INFO
-handlers =
-qualname = alembic
-
-[handler_console]
-class = StreamHandler
-args = (sys.stderr,)
-level = NOTSET
-formatter = generic
-
-[formatter_generic]
-format = %(levelname)-5.5s [%(name)s] %(message)s
-datefmt = %H:%M:%S
diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py
deleted file mode 100755
index 6740d59..0000000
--- a/contrib/ast-db-manage/config/env.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
-    fileConfig(config.config_file_name)
-except:
-    pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
-    """Run migrations in 'offline' mode.
-
-    This configures the context with just a URL
-    and not an Engine, though an Engine is acceptable
-    here as well.  By skipping the Engine creation
-    we don't even need a DBAPI to be available.
-
-    Calls to context.execute() here emit the given string to the
-    script output.
-
-    """
-    url = config.get_main_option("sqlalchemy.url")
-    context.configure(url=url)
-
-    with context.begin_transaction():
-        context.run_migrations()
-
-def run_migrations_online():
-    """Run migrations in 'online' mode.
-
-    In this scenario we need to create an Engine
-    and associate a connection with the context.
-
-    """
-    engine = engine_from_config(
-                config.get_section(config.config_ini_section),
-                prefix='sqlalchemy.',
-                poolclass=pool.NullPool)
-
-    connection = engine.connect()
-    context.configure(
-                connection=connection,
-                target_metadata=target_metadata
-                )
-
-    try:
-        with context.begin_transaction():
-            context.run_migrations()
-    finally:
-        connection.close()
-
-if context.is_offline_mode():
-    run_migrations_offline()
-else:
-    run_migrations_online()
-
diff --git a/contrib/ast-db-manage/config/script.py.mako b/contrib/ast-db-manage/config/script.py.mako
deleted file mode 100644
index 9570201..0000000
--- a/contrib/ast-db-manage/config/script.py.mako
+++ /dev/null
@@ -1,22 +0,0 @@
-"""${message}
-
-Revision ID: ${up_revision}
-Revises: ${down_revision}
-Create Date: ${create_date}
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = ${repr(up_revision)}
-down_revision = ${repr(down_revision)}
-
-from alembic import op
-import sqlalchemy as sa
-${imports if imports else ""}
-
-def upgrade():
-    ${upgrades if upgrades else "pass"}
-
-
-def downgrade():
-    ${downgrades if downgrades else "pass"}
diff --git a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
deleted file mode 100755
index b4ea71c..0000000
--- a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Jonathan Rose
-#
-# Jonathan R. Rose <jrose at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Add Outgoing enum value to sippeers directmedia
-
-Revision ID: 10aedae86a32
-Revises: 5950038a6ead
-Create Date: 2014-09-19 16:03:13.469436
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '10aedae86a32'
-down_revision = '5950038a6ead'
-
-from alembic import op
-from sqlalchemy.dialects.postgresql import ENUM
-import sqlalchemy as sa
-
-OLD_ENUM = ['yes', 'no', 'nonat', 'update']
-NEW_ENUM = ['yes', 'no', 'nonat', 'update', 'outgoing']
-
-old_type = sa.Enum(*OLD_ENUM, name='sip_directmedia_values')
-new_type = sa.Enum(*NEW_ENUM, name='sip_directmedia_values_v2')
-
-tcr = sa.sql.table('sippeers', sa.Column('directmedia', new_type,
-                   nullable=True))
-
-def upgrade():
-    context = op.get_context()
-
-    # Upgrading to this revision WILL clear your directmedia values.
-    if context.bind.dialect.name != 'postgresql':
-        op.alter_column('sippeers', 'directmedia',
-                        type_=new_type,
-                        existing_type=old_type)
-    else:
-        enum = ENUM("yes", "no", "nonat", "update", "outgoing",
-                    name="sip_directmedia_values_v2")
-        enum.create(op.get_bind(), checkfirst=False)
-
-        op.execute('ALTER TABLE sippeers ALTER COLUMN directmedia TYPE'
-                   ' sip_directmedia_values_v2 USING'
-                   ' directmedia::text::sip_directmedia_values_v2')
-
-        ENUM(name="sip_directmedia_values").drop(op.get_bind(), checkfirst=False)
-
-def downgrade():
-    context = op.get_context()
-
-    op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing')
-               .values(directmedia=None))
-
-    if context.bind.dialect.name != 'postgresql':
-        op.alter_column('sippeers', 'directmedia',
-                        type_=old_type,
-                        existing_type=new_type)
-    else:
-        enum = ENUM("yes", "no", "nonat", "update",
-                    name="sip_directmedia_values")
-        enum.create(op.get_bind(), checkfirst=False)
-
-        op.execute('ALTER TABLE sippeers ALTER COLUMN directmedia TYPE'
-                   ' sip_directmedia_values USING'
-                   ' directmedia::text::sip_directmedia_values')
-
-        ENUM(name="sip_directmedia_values_v2").drop(op.get_bind(),
-                                                checkfirst=False)
diff --git a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
deleted file mode 100755
index 215726f..0000000
--- a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Richard Mudgett
-#
-# Richard Mudgett <rmudgett at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""increase useragent column size
-
-Revision ID: 1758e8bbf6b
-Revises: 1d50859ed02e
-Create Date: 2014-07-28 14:04:17.874332
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '1758e8bbf6b'
-down_revision = '1d50859ed02e'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.alter_column('sippeers', 'useragent', type_=sa.String(255))
-
-
-def downgrade():
-    op.alter_column('sippeers', 'useragent', type_=sa.String(20))
-
diff --git a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
deleted file mode 100644
index eb20001..0000000
--- a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""create accountcode
-
-Revision ID: 1d50859ed02e
-Revises: 51f8cb66540e
-Create Date: 2014-07-07 21:07:01.661783
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '1d50859ed02e'
-down_revision = '51f8cb66540e'
-
-from alembic import op
-import sqlalchemy as sa
-
-def upgrade():
-    op.add_column('ps_endpoints', sa.Column('accountcode', sa.String(20)))
-
-def downgrade():
-    op.drop_column('ps_endpoints', 'accountcode')
diff --git a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
deleted file mode 100755
index 2adca62..0000000
--- a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""add pjsip debug option
-
-Revision ID: 21e526ad3040
-Revises: 2fc7930b41b3
-Create Date: 2014-01-30 10:44:02.297455
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '21e526ad3040'
-down_revision = '2fc7930b41b3'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.add_column('ps_globals', sa.Column('debug', sa.String(40)))
-
-def downgrade():
-    op.drop_column('ps_globals', 'debug')
diff --git a/contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py b/contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py
deleted file mode 100755
index 59ddac7..0000000
--- a/contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Richard Mudgett
-#
-# Richard Mudgett <rmudgett at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Create queue tables
-
-Revision ID: 28887f25a46f
-Revises: 21e526ad3040
-Create Date: 2014-03-03 12:26:25.261640
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '28887f25a46f'
-down_revision = '21e526ad3040'
-
-from alembic import op
-from alembic import context
-import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import ENUM
-
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-QUEUE_STRATEGY_NAME = 'queue_strategy_values'
-QUEUE_STRATEGY_VALUES = [ 'ringall', 'leastrecent', 'fewestcalls', 'random', 'rrmemory',
-    'linear', 'wrandom', 'rrordered', ]
-
-QUEUE_AUTOPAUSE_NAME = 'queue_autopause_values'
-QUEUE_AUTOPAUSE_VALUES = ['yes', 'no', 'all']
-
-
-def upgrade():
-    ############################# Enums ##############################
-
-    # yesno_values have already been created, so use postgres enum object
-    # type to get around "already created" issue - works okay with mysql
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-
-    queue_strategy_values = sa.Enum(*QUEUE_STRATEGY_VALUES, name=QUEUE_STRATEGY_NAME)
-    queue_autopause_values = sa.Enum(*QUEUE_AUTOPAUSE_VALUES, name=QUEUE_AUTOPAUSE_NAME)
-
-    ######################### create tables ##########################
-
-    op.create_table(
-        'queues',
-        sa.Column('name', sa.String(128), primary_key=True, nullable=False),
-        sa.Column('musiconhold', sa.String(128)),
-        sa.Column('announce', sa.String(128)),
-        sa.Column('context', sa.String(128)),
-        sa.Column('timeout', sa.Integer),
-        sa.Column('ringinuse', yesno_values),
-        sa.Column('setinterfacevar', yesno_values),
-        sa.Column('setqueuevar', yesno_values),
-        sa.Column('setqueueentryvar', yesno_values),
-        sa.Column('monitor_format', sa.String(8)),
-        sa.Column('membermacro', sa.String(512)),
-        sa.Column('membergosub', sa.String(512)),
-        sa.Column('queue_youarenext', sa.String(128)),
-        sa.Column('queue_thereare', sa.String(128)),
-        sa.Column('queue_callswaiting', sa.String(128)),
-        sa.Column('queue_quantity1', sa.String(128)),
-        sa.Column('queue_quantity2', sa.String(128)),
-        sa.Column('queue_holdtime', sa.String(128)),
-        sa.Column('queue_minutes', sa.String(128)),
-        sa.Column('queue_minute', sa.String(128)),
-        sa.Column('queue_seconds', sa.String(128)),
-        sa.Column('queue_thankyou', sa.String(128)),
-        sa.Column('queue_callerannounce', sa.String(128)),
-        sa.Column('queue_reporthold', sa.String(128)),
-        sa.Column('announce_frequency', sa.Integer),
-        sa.Column('announce_to_first_user', yesno_values),
-        sa.Column('min_announce_frequency', sa.Integer),
-        sa.Column('announce_round_seconds', sa.Integer),
-        sa.Column('announce_holdtime', sa.String(128)),
-        sa.Column('announce_position', sa.String(128)),
-        sa.Column('announce_position_limit', sa.Integer),
-        sa.Column('periodic_announce', sa.String(50)),
-        sa.Column('periodic_announce_frequency', sa.Integer),
-        sa.Column('relative_periodic_announce', yesno_values),
-        sa.Column('random_periodic_announce', yesno_values),
-        sa.Column('retry', sa.Integer),
-        sa.Column('wrapuptime', sa.Integer),
-        sa.Column('penaltymemberslimit', sa.Integer),
-        sa.Column('autofill', yesno_values),
-        sa.Column('monitor_type', sa.String(128)),
-        sa.Column('autopause', queue_autopause_values),
-        sa.Column('autopausedelay', sa.Integer),
-        sa.Column('autopausebusy', yesno_values),
-        sa.Column('autopauseunavail', yesno_values),
-        sa.Column('maxlen', sa.Integer),
-        sa.Column('servicelevel', sa.Integer),
-        sa.Column('strategy', queue_strategy_values),
-        sa.Column('joinempty', sa.String(128)),
-        sa.Column('leavewhenempty', sa.String(128)),
-        sa.Column('reportholdtime', yesno_values),
-        sa.Column('memberdelay', sa.Integer),
-        sa.Column('weight', sa.Integer),
-        sa.Column('timeoutrestart', yesno_values),
-        sa.Column('defaultrule', sa.String(128)),
-        sa.Column('timeoutpriority', sa.String(128))
-    )
-
-    op.create_table(
-        'queue_members',
-        sa.Column('queue_name', sa.String(80), primary_key=True, nullable=False),
-        sa.Column('interface', sa.String(80), primary_key=True, nullable=False),
-        sa.Column('uniqueid', sa.String(80), nullable=False),
-        sa.Column('membername', sa.String(80)),
-        sa.Column('state_interface', sa.String(80)),
-        sa.Column('penalty', sa.Integer),
-        sa.Column('paused', sa.Integer)
-    )
-
-
-def downgrade():
-    ########################## drop tables ###########################
-
-    op.drop_table('queues')
-    op.drop_table('queue_members')
-
-    ########################## drop enums ############################
-
-    sa.Enum(name=QUEUE_STRATEGY_NAME).drop(op.get_bind(), checkfirst=False)
-    sa.Enum(name=QUEUE_AUTOPAUSE_NAME).drop(op.get_bind(), checkfirst=False)
-
diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
deleted file mode 100755
index 564897e..0000000
--- a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
+++ /dev/null
@@ -1,176 +0,0 @@
-"""Add/Update tables for pjsip
-
-Revision ID: 2fc7930b41b3
-Revises: 581a4264e537
-Create Date: 2014-01-14 09:23:53.923454
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '2fc7930b41b3'
-down_revision = '581a4264e537'
-
-from alembic import op
-from alembic import context
-import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import ENUM
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-PJSIP_REDIRECT_METHOD_NAME = 'pjsip_redirect_method_values'
-PJSIP_REDIRECT_METHOD_VALUES = ['user', 'uri_core', 'uri_pjsip']
-
-PJSIP_TRANSPORT_METHOD_NAME = 'pjsip_transport_method_values'
-PJSIP_TRANSPORT_METHOD_VALUES = ['default', 'unspecified', 'tlsv1', 'sslv2',
-                                 'sslv3', 'sslv23']
-
-PJSIP_TRANSPORT_PROTOCOL_NAME = 'pjsip_transport_protocol_values'
-PJSIP_TRANSPORT_PROTOCOL_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss']
-
-def upgrade():
-    ############################# Enums ##############################
-
-    # yesno_values have already been created, so use postgres enum object
-    # type to get around "already created" issue - works okay with mysql
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-
-    # for some reason when using 'add_column' if you don't create the enum
-    # first it will think it already exists and fail
-    pjsip_redirect_method_values = sa.Enum(
-        *PJSIP_REDIRECT_METHOD_VALUES, name=PJSIP_REDIRECT_METHOD_NAME)
-    check = False if context.is_offline_mode() else True
-    pjsip_redirect_method_values.create(op.get_bind(), checkfirst=check)
-
-    pjsip_transport_method_values = sa.Enum(
-        *PJSIP_TRANSPORT_METHOD_VALUES, name=PJSIP_TRANSPORT_METHOD_NAME)
-
-    pjsip_transport_protocol_values = sa.Enum(
-        *PJSIP_TRANSPORT_PROTOCOL_VALUES, name=PJSIP_TRANSPORT_PROTOCOL_NAME)
-
-    ######################### create tables ##########################
-
-    op.create_table(
-        'ps_systems',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('timer_t1', sa.Integer),
-        sa.Column('timer_b', sa.Integer),
-        sa.Column('compact_headers', yesno_values),
-        sa.Column('threadpool_initial_size', sa.Integer),
-        sa.Column('threadpool_auto_increment', sa.Integer),
-        sa.Column('threadpool_idle_timeout', sa.Integer),
-        sa.Column('threadpool_max_size', sa.Integer),
-    )
-
-    op.create_index('ps_systems_id', 'ps_systems', ['id'])
-
-    op.create_table(
-        'ps_globals',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('max_forwards', sa.Integer),
-        sa.Column('user_agent', sa.String(40)),
-        sa.Column('default_outbound_endpoint', sa.String(40)),
-    )
-
-    op.create_index('ps_globals_id', 'ps_globals', ['id'])
-
-    op.create_table(
-        'ps_transports',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('async_operations', sa.Integer),
-        sa.Column('bind', sa.String(40)),
-        sa.Column('ca_list_file', sa.String(200)),
-        sa.Column('cert_file', sa.String(200)),
-        sa.Column('cipher', sa.String(200)),
-        sa.Column('domain', sa.String(40)),
-        sa.Column('external_media_address', sa.String(40)),
-        sa.Column('external_signaling_address', sa.String(40)),
-        sa.Column('external_signaling_port', sa.Integer),
-        sa.Column('method', pjsip_transport_method_values),
-        sa.Column('local_net', sa.String(40)),
-        sa.Column('password', sa.String(40)),
-        sa.Column('priv_key_file', sa.String(200)),
-        sa.Column('protocol', pjsip_transport_protocol_values),
-        sa.Column('require_client_cert', yesno_values),
-        sa.Column('verify_client', yesno_values),
-        sa.Column('verifiy_server', yesno_values),
-        sa.Column('tos', yesno_values),
-        sa.Column('cos', yesno_values),
-    )
-
-    op.create_index('ps_transports_id', 'ps_transports', ['id'])
-
-    op.create_table(
-        'ps_registrations',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('auth_rejection_permanent', yesno_values),
-        sa.Column('client_uri', sa.String(40)),
-        sa.Column('contact_user', sa.String(40)),
-        sa.Column('expiration', sa.Integer),
-        sa.Column('max_retries', sa.Integer),
-        sa.Column('outbound_auth', sa.String(40)),
-        sa.Column('outbound_proxy', sa.String(40)),
-        sa.Column('retry_interval', sa.Integer),
-        sa.Column('forbidden_retry_interval', sa.Integer),
-        sa.Column('server_uri', sa.String(40)),
-        sa.Column('transport', sa.String(40)),
-        sa.Column('support_path', yesno_values),
-    )
-
-    op.create_index('ps_registrations_id', 'ps_registrations', ['id'])
-
-    ########################## add columns ###########################
-
-    # new columns for endpoints
-    op.add_column('ps_endpoints', sa.Column('media_address', sa.String(40)))
-    op.add_column('ps_endpoints', sa.Column('redirect_method',
-                                            pjsip_redirect_method_values))
-    op.add_column('ps_endpoints', sa.Column('set_var', sa.Text()))
-
-    # rename mwi_fromuser to mwi_from_user
-    op.alter_column('ps_endpoints', 'mwi_fromuser',
-                    new_column_name='mwi_from_user',
-                    existing_type=sa.String(40))
-
-    # new columns for contacts
-    op.add_column('ps_contacts', sa.Column('outbound_proxy', sa.String(40)))
-    op.add_column('ps_contacts', sa.Column('path', sa.Text()))
-
-    # new columns for aors
-    op.add_column('ps_aors', sa.Column('maximum_expiration', sa.Integer))
-    op.add_column('ps_aors', sa.Column('outbound_proxy', sa.String(40)))
-    op.add_column('ps_aors', sa.Column('support_path', yesno_values))
-
-def downgrade():
-    ########################## drop columns ##########################
-
-    op.drop_column('ps_aors', 'support_path')
-    op.drop_column('ps_aors', 'outbound_proxy')
-    op.drop_column('ps_aors', 'maximum_expiration')
-
-    op.drop_column('ps_contacts', 'path')
-    op.drop_column('ps_contacts', 'outbound_proxy')
-
-    op.alter_column('ps_endpoints', 'mwi_from_user',
-                    new_column_name='mwi_fromuser',
-                    existing_type=sa.String(40))
-
-    op.drop_column('ps_endpoints', 'set_var')
-    op.drop_column('ps_endpoints', 'redirect_method')
-    op.drop_column('ps_endpoints', 'media_address')
-
-    ########################## drop tables ###########################
-
-    op.drop_table('ps_registrations')
-    op.drop_table('ps_transports')
-    op.drop_table('ps_globals')
-    op.drop_table('ps_systems')
-
-    ########################## drop enums ############################
-
-    sa.Enum(name=PJSIP_TRANSPORT_PROTOCOL_NAME).drop(
-        op.get_bind(), checkfirst=False)
-    sa.Enum(name=PJSIP_TRANSPORT_METHOD_NAME).drop(
-        op.get_bind(), checkfirst=False)
-    sa.Enum(name=PJSIP_REDIRECT_METHOD_NAME).drop(
-        op.get_bind(), checkfirst=False)
diff --git a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
deleted file mode 100644
index afc1beb..0000000
--- a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""add_missing_pjsip_options
-
-Revision ID: 3855ee4e5f85
-Revises: 4c573e7135bd
-Create Date: 2014-03-28 10:49:04.637730
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '3855ee4e5f85'
-down_revision = '4c573e7135bd'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.add_column('ps_endpoints', sa.Column('message_context', sa.String(40)))
-    op.add_column('ps_contacts', sa.Column('user_agent', sa.String(40)))
-
-
-def downgrade():
-    op.drop_column('ps_contacts', 'user_agent')
-    op.drop_column('ps_endpoints', 'message_context')
diff --git a/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py b/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py
deleted file mode 100755
index 0c4d9c8..0000000
--- a/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py
+++ /dev/null
@@ -1,189 +0,0 @@
-"""Add tables for pjsip
-
-Revision ID: 43956d550a44
-Revises: 4da0c5f79a9c
-Create Date: 2013-09-30 13:23:59.676690
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '43956d550a44'
-down_revision = '4da0c5f79a9c'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-YESNO_VALUES = ['yes', 'no']
-PJSIP_CID_PRIVACY_VALUES = ['allowed_not_screened', 'allowed_passed_screened',
-                            'allowed_failed_screened', 'allowed',
-                            'prohib_not_screened', 'prohib_passed_screened',
-                            'prohib_failed_screened', 'prohib', 'unavailable']
-PJSIP_100REL_VALUES = ['no', 'required', 'yes']
-PJSIP_CONNECTED_LINE_METHOD_VALUES = ['invite', 'reinvite', 'update']
-PJSIP_DIRECT_MEDIA_GLARE_MITIGATION_VALUES = ['none', 'outgoing', 'incoming']
-PJSIP_DTMF_MODE_VALUES = ['rfc4733', 'inband', 'info']
-PJSIP_IDENTIFY_BY_VALUES = ['username']
-PJSIP_TIMERS_VALUES = ['forced', 'no', 'required', 'yes']
-PJSIP_MEDIA_ENCRYPTION_VALUES = ['no', 'sdes', 'dtls']
-PJSIP_T38UDPTL_EC_VALUES = ['none', 'fec', 'redundancy']
-PJSIP_DTLS_SETUP_VALUES = ['active', 'passive', 'actpass']
-PJSIP_AUTH_TYPE_VALUES = ['md5', 'userpass']
-PJSIP_TRANSPORT_METHOD_VALUES = ['default', 'unspecified', 'tlsv1', 'sslv2',
-                                 'sslv3', 'sslv23']
-PJSIP_TRANSPORT_PROTOCOL_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss']
-
-
-def upgrade():
-    op.create_table(
-        'ps_endpoints',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('transport', sa.String(40)),
-        sa.Column('aors', sa.String(200)),
-        sa.Column('auth', sa.String(40)),
-        sa.Column('context', sa.String(40)),
-        sa.Column('disallow', sa.String(200)),
-        sa.Column('allow', sa.String(200)),
-        sa.Column('direct_media', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('connected_line_method',
-                  sa.Enum(*PJSIP_CONNECTED_LINE_METHOD_VALUES, name='pjsip_connected_line_method_values')),
-        sa.Column('direct_media_method',
-                  sa.Enum(*PJSIP_CONNECTED_LINE_METHOD_VALUES, name='pjsip_connected_line_method_values')),
-        sa.Column('direct_media_glare_mitigation',
-                  sa.Enum(*PJSIP_DIRECT_MEDIA_GLARE_MITIGATION_VALUES, name='pjsip_direct_media_glare_mitigation_values')),
-        sa.Column('disable_direct_media_on_nat', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('dtmf_mode', sa.Enum(*PJSIP_DTMF_MODE_VALUES, name='pjsip_dtmf_mode_values')),
-        sa.Column('external_media_address', sa.String(40)),
-        sa.Column('force_rport', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('ice_support', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('identify_by', sa.Enum(*PJSIP_IDENTIFY_BY_VALUES, name='pjsip_identify_by_values')),
-        sa.Column('mailboxes', sa.String(40)),
-        sa.Column('moh_suggest', sa.String(40)),
-        sa.Column('outbound_auth', sa.String(40)),
-        sa.Column('outbound_proxy', sa.String(40)),
-        sa.Column('rewrite_contact', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('rtp_ipv6', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('rtp_symmetric', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('send_diversion', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('send_pai', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('send_rpid', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('timers_min_se', sa.Integer),
-        sa.Column('timers', sa.Enum(*PJSIP_TIMERS_VALUES, name='pjsip_timer_values')),
-        sa.Column('timers_sess_expires', sa.Integer),
-        sa.Column('callerid', sa.String(40)),
-        sa.Column('callerid_privacy', sa.Enum(*PJSIP_CID_PRIVACY_VALUES, name='pjsip_cid_privacy_values')),
-        sa.Column('callerid_tag', sa.String(40)),
-        sa.Column('100rel', sa.Enum(*PJSIP_100REL_VALUES, name='pjsip_100rel_values')),
-        sa.Column('aggregate_mwi', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('trust_id_inbound', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('trust_id_outbound', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('use_ptime', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('use_avpf', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('media_encryption', sa.Enum(*PJSIP_MEDIA_ENCRYPTION_VALUES, name='pjsip_media_encryption_values')),
-        sa.Column('inband_progress', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('call_group', sa.String(40)),
-        sa.Column('pickup_group', sa.String(40)),
-        sa.Column('named_call_group', sa.String(40)),
-        sa.Column('named_pickup_group', sa.String(40)),
-        sa.Column('device_state_busy_at', sa.Integer),
-        sa.Column('fax_detect', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('t38_udptl', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('t38_udptl_ec', sa.Enum(*PJSIP_T38UDPTL_EC_VALUES, name='pjsip_t38udptl_ec_values')),
-        sa.Column('t38_udptl_maxdatagram', sa.Integer),
-        sa.Column('t38_udptl_nat', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('t38_udptl_ipv6', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('tone_zone', sa.String(40)),
-        sa.Column('language', sa.String(40)),
-        sa.Column('one_touch_recording', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('record_on_feature', sa.String(40)),
-        sa.Column('record_off_feature', sa.String(40)),
-        sa.Column('rtp_engine', sa.String(40)),
-        sa.Column('allow_transfer', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('allow_subscribe', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('sdp_owner', sa.String(40)),
-        sa.Column('sdp_session', sa.String(40)),
-        sa.Column('tos_audio', sa.Integer),
-        sa.Column('tos_video', sa.Integer),
-        sa.Column('cos_audio', sa.Integer),
-        sa.Column('cos_video', sa.Integer),
-        sa.Column('sub_min_expiry', sa.Integer),
-        sa.Column('from_domain', sa.String(40)),
-        sa.Column('from_user', sa.String(40)),
-        sa.Column('mwi_fromuser', sa.String(40)),
-        sa.Column('dtls_verify', sa.String(40)),
-        sa.Column('dtls_rekey', sa.String(40)),
-        sa.Column('dtls_cert_file', sa.String(200)),
-        sa.Column('dtls_private_key', sa.String(200)),
-        sa.Column('dtls_cipher', sa.String(200)),
-        sa.Column('dtls_ca_file', sa.String(200)),
-        sa.Column('dtls_ca_path', sa.String(200)),
-        sa.Column('dtls_setup', sa.Enum(*PJSIP_DTLS_SETUP_VALUES, name='pjsip_dtls_setup_values')),
-        sa.Column('srtp_tag_32', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-    )
-
-    op.create_index('ps_endpoints_id', 'ps_endpoints', ['id'])
-
-    op.create_table(
-        'ps_auths',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('auth_type', sa.Enum(*PJSIP_AUTH_TYPE_VALUES, name='pjsip_auth_type_values')),
-        sa.Column('nonce_lifetime', sa.Integer),
-        sa.Column('md5_cred', sa.String(40)),
-        sa.Column('password', sa.String(80)),
-        sa.Column('realm', sa.String(40)),
-        sa.Column('username', sa.String(40)),
-    )
-
-    op.create_index('ps_auths_id', 'ps_auths', ['id'])
-
-    op.create_table(
-        'ps_aors',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('contact', sa.String(40)),
-        sa.Column('default_expiration', sa.Integer),
-        sa.Column('mailboxes', sa.String(80)),
-        sa.Column('max_contacts', sa.Integer),
-        sa.Column('minimum_expiration', sa.Integer),
-        sa.Column('remove_existing', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-        sa.Column('qualify_frequency', sa.Integer),
-        sa.Column('authenticate_qualify', sa.Enum(*YESNO_VALUES, name='yesno_values')),
-    )
-
-    op.create_index('ps_aors_id', 'ps_aors', ['id'])
-
-    op.create_table(
-        'ps_contacts',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('uri', sa.String(40)),
-        sa.Column('expiration_time', sa.String(40)),
-        sa.Column('qualify_frequency', sa.Integer),
-    )
-
-    op.create_index('ps_contacts_id', 'ps_contacts', ['id'])
-
-    op.create_table(
-        'ps_domain_aliases',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('domain', sa.String(80)),
-    )
-
-    op.create_index('ps_domain_aliases_id', 'ps_domain_aliases', ['id'])
-
-    op.create_table(
-        'ps_endpoint_id_ips',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-        sa.Column('endpoint', sa.String(40)),
-        sa.Column('match', sa.String(80)),
-    )
-
-    op.create_index('ps_endpoint_id_ips_id',
-                    'ps_endpoint_id_ips', ['id'])
-
-
-def downgrade():
-    op.drop_table('ps_endpoints')
-    op.drop_table('ps_auths')
-    op.drop_table('ps_aors')
-    op.drop_table('ps_contacts')
-    op.drop_table('ps_domain_aliases')
-    op.drop_table('ps_endpoint_id_ips')
diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
deleted file mode 100755
index aefddd1..0000000
--- a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""Fix tos and cos field types
-
-Revision ID: 4c573e7135bd
-Revises: 28887f25a46f
-Create Date: 2014-03-05 12:16:56.618630
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '4c573e7135bd'
-down_revision = '28887f25a46f'
-
-from alembic import op
-from alembic import context
-import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import ENUM
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-def upgrade():
-    op.alter_column('ps_endpoints', 'tos_audio',
-                    type_=sa.String(10))
-    op.alter_column('ps_endpoints', 'tos_video',
-                    type_=sa.String(10))
-    op.alter_column('ps_transports', 'tos',
-                    type_=sa.String(10))
-
-    # Can't cast YENO_VALUES to Integers, so dropping and adding is required
-    op.drop_column('ps_endpoints', 'cos_audio')
-    op.drop_column('ps_endpoints', 'cos_video')
-    op.drop_column('ps_transports', 'cos')
-
-    op.add_column('ps_endpoints', sa.Column('cos_audio', sa.Integer))
-    op.add_column('ps_endpoints', sa.Column('cos_video', sa.Integer))
-    op.add_column('ps_transports', sa.Column('cos', sa.Integer))
-    pass
-
-
-def downgrade():
-
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-
-    # Can't cast string to YESNO_VALUES, so dropping and adding is required
-    op.drop_column('ps_endpoints', 'tos_audio')
-    op.drop_column('ps_endpoints', 'tos_video')
-    op.drop_column('ps_transports', 'tos')
-
-    op.add_column('ps_endpoints', sa.Column('tos_audio', yesno_values))
-    op.add_column('ps_endpoints', sa.Column('tos_video', yesno_values))
-    op.add_column('ps_transports', sa.Column('tos', yesno_values))
-
-    # Can't cast integers to YESNO_VALUES, so dropping and adding is required
-    op.drop_column('ps_endpoints', 'cos_audio')
-    op.drop_column('ps_endpoints', 'cos_video')
-    op.drop_column('ps_transports', 'cos')
-
-    op.add_column('ps_endpoints', sa.Column('cos_audio', yesno_values))
-    op.add_column('ps_endpoints', sa.Column('cos_video', yesno_values))
-    op.add_column('ps_transports', sa.Column('cos', yesno_values))
-    pass
diff --git a/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py b/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py
deleted file mode 100755
index ffaff92..0000000
--- a/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py
+++ /dev/null
@@ -1,330 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Russell Bryant
-#
-# Russell Bryant <russell at rusellbryant.net>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Create tables
-
-Revision ID: 4da0c5f79a9c
-Revises: None
-Create Date: 2013-07-28 12:28:03.091587
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '4da0c5f79a9c'
-down_revision = None
-
-from alembic import op
-import sqlalchemy as sa
-
-
-YESNO_VALUES = ['yes', 'no']
-TYPE_VALUES = ['friend', 'user', 'peer']
-
-SIP_TRANSPORT_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss', 'udp,tcp', 'tcp,udp']
-SIP_DTMFMODE_VALUES = ['rfc2833', 'info', 'shortinfo', 'inband', 'auto']
-SIP_DIRECTMEDIA_VALUES = ['yes', 'no', 'nonat', 'update']
-SIP_PROGRESSINBAND_VALUES = ['yes', 'no', 'never']
-SIP_SESSION_TIMERS_VALUES = ['accept', 'refuse', 'originate']
-SIP_SESSION_REFRESHER_VALUES = ['uac', 'uas']
-SIP_CALLINGPRES_VALUES = ['allowed_not_screened', 'allowed_passed_screen',
-                          'allowed_failed_screen', 'allowed',
-                          'prohib_not_screened', 'prohib_passed_screen',
-                          'prohib_failed_screen', 'prohib']
-
-IAX_REQUIRECALLTOKEN_VALUES = ['yes', 'no', 'auto']
-IAX_ENCRYPTION_VALUES = ['yes', 'no', 'aes128']
-IAX_TRANSFER_VALUES = ['yes', 'no', 'mediaonly']
-
-MOH_MODE_VALUES = ['custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3']
-
-
-def upgrade():
-    op.create_table(
-        'sippeers',
-        sa.Column('id', sa.Integer, primary_key=True, nullable=False,
-                  autoincrement=True),
-        sa.Column('name', sa.String(40), nullable=False, unique=True),
-        sa.Column('ipaddr', sa.String(45)),
-        sa.Column('port', sa.Integer),
-        sa.Column('regseconds', sa.Integer),
-        sa.Column('defaultuser', sa.String(40)),
-        sa.Column('fullcontact', sa.String(80)),
-        sa.Column('regserver', sa.String(20)),
-        sa.Column('useragent', sa.String(20)),
-        sa.Column('lastms', sa.Integer),
-        sa.Column('host', sa.String(40)),
-        sa.Column('type', sa.Enum(*TYPE_VALUES, name='type_values')),
-        sa.Column('context', sa.String(40)),
-        sa.Column('permit', sa.String(95)),
-        sa.Column('deny', sa.String(95)),
-        sa.Column('secret', sa.String(40)),
-        sa.Column('md5secret', sa.String(40)),
-        sa.Column('remotesecret', sa.String(40)),
-        sa.Column('transport', sa.Enum(*SIP_TRANSPORT_VALUES,
-                  name='sip_transport_values')),
-        sa.Column('dtmfmode', sa.Enum(*SIP_DTMFMODE_VALUES,
-                  name='sip_dtmfmode_values')),
-        sa.Column('directmedia', sa.Enum(*SIP_DIRECTMEDIA_VALUES,
-                  name='sip_directmedia_values')),
-        sa.Column('nat', sa.String(29)),
-        sa.Column('callgroup', sa.String(40)),
-        sa.Column('pickupgroup', sa.String(40)),
-        sa.Column('language', sa.String(40)),
-        sa.Column('disallow', sa.String(200)),
-        sa.Column('allow', sa.String(200)),
-        sa.Column('insecure', sa.String(40)),
-        sa.Column('trustrpid', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('progressinband', sa.Enum(*SIP_PROGRESSINBAND_VALUES,
-                  name='sip_progressinband_values')),
-        sa.Column('promiscredir', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('useclientcode', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('accountcode', sa.String(40)),
-        sa.Column('setvar', sa.String(200)),
-        sa.Column('callerid', sa.String(40)),
-        sa.Column('amaflags', sa.String(40)),
-        sa.Column('callcounter', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('busylevel', sa.Integer),
-        sa.Column('allowoverlap', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('allowsubscribe', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('videosupport', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('maxcallbitrate', sa.Integer),
-        sa.Column('rfc2833compensate', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('mailbox', sa.String(40)),
-        sa.Column('session-timers', sa.Enum(*SIP_SESSION_TIMERS_VALUES,
-                  name='sip_session_timers_values')),
-        sa.Column('session-expires', sa.Integer),
-        sa.Column('session-minse', sa.Integer),
-        sa.Column('session-refresher', sa.Enum(*SIP_SESSION_REFRESHER_VALUES,
-                  name='sip_session_refresher_values')),
-        sa.Column('t38pt_usertpsource', sa.String(40)),
-        sa.Column('regexten', sa.String(40)),
-        sa.Column('fromdomain', sa.String(40)),
-        sa.Column('fromuser', sa.String(40)),
-        sa.Column('qualify', sa.String(40)),
-        sa.Column('defaultip', sa.String(45)),
-        sa.Column('rtptimeout', sa.Integer),
-        sa.Column('rtpholdtimeout', sa.Integer),
-        sa.Column('sendrpid', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('outboundproxy', sa.String(40)),
-        sa.Column('callbackextension', sa.String(40)),
-        sa.Column('timert1', sa.Integer),
-        sa.Column('timerb', sa.Integer),
-        sa.Column('qualifyfreq', sa.Integer),
-        sa.Column('constantssrc', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('contactpermit', sa.String(95)),
-        sa.Column('contactdeny', sa.String(95)),
-        sa.Column('usereqphone', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('textsupport', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('faxdetect', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('buggymwi', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('auth', sa.String(40)),
-        sa.Column('fullname', sa.String(40)),
-        sa.Column('trunkname', sa.String(40)),
-        sa.Column('cid_number', sa.String(40)),
-        sa.Column('callingpres', sa.Enum(*SIP_CALLINGPRES_VALUES,
-                  name='sip_callingpres_values')),
-        sa.Column('mohinterpret', sa.String(40)),
-        sa.Column('mohsuggest', sa.String(40)),
-        sa.Column('parkinglot', sa.String(40)),
-        sa.Column('hasvoicemail', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('subscribemwi', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('vmexten', sa.String(40)),
-        sa.Column('autoframing', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('rtpkeepalive', sa.Integer),
-        sa.Column('call-limit', sa.Integer),
-        sa.Column('g726nonstandard', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('ignoresdpversion', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('allowtransfer', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('dynamic', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('path', sa.String(256)),
-        sa.Column('supportpath', sa.Enum(*YESNO_VALUES, name='yes_no_values'))
-    )
-    op.create_index('sippeers_name', 'sippeers', ['name'])
-    op.create_index('sippeers_name_host', 'sippeers', ['name', 'host'])
-    op.create_index('sippeers_ipaddr_port', 'sippeers', ['ipaddr', 'port'])
-    op.create_index('sippeers_host_port', 'sippeers', ['host', 'port'])
-
-    op.create_table(
-        'iaxfriends',
-        sa.Column('id', sa.Integer, primary_key=True, nullable=False,
-                  autoincrement=True),
-        sa.Column('name', sa.String(40), nullable=False, unique=True),
-        sa.Column('type', sa.Enum(*TYPE_VALUES, name='type_values')),
-        sa.Column('username', sa.String(40)),
-        sa.Column('mailbox', sa.String(40)),
-        sa.Column('secret', sa.String(40)),
-        sa.Column('dbsecret', sa.String(40)),
-        sa.Column('context', sa.String(40)),
-        sa.Column('regcontext', sa.String(40)),
-        sa.Column('host', sa.String(40)),
-        sa.Column('ipaddr', sa.String(40)),
-        sa.Column('port', sa.Integer),
-        sa.Column('defaultip', sa.String(20)),
-        sa.Column('sourceaddress', sa.String(20)),
-        sa.Column('mask', sa.String(20)),
-        sa.Column('regexten', sa.String(40)),
-        sa.Column('regseconds', sa.Integer),
-        sa.Column('accountcode', sa.String(20)),
-        sa.Column('mohinterpret', sa.String(20)),
-        sa.Column('mohsuggest', sa.String(20)),
-        sa.Column('inkeys', sa.String(40)),
-        sa.Column('outkeys', sa.String(40)),
-        sa.Column('language', sa.String(10)),
-        sa.Column('callerid', sa.String(100)),
-        sa.Column('cid_number', sa.String(40)),
-        sa.Column('sendani', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('fullname', sa.String(40)),
-        sa.Column('trunk', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('auth', sa.String(20)),
-        sa.Column('maxauthreq', sa.Integer),
-        sa.Column('requirecalltoken', sa.Enum(*IAX_REQUIRECALLTOKEN_VALUES,
-                  name='iax_requirecalltoken_values')),
-        sa.Column('encryption', sa.Enum(*IAX_ENCRYPTION_VALUES,
-                  name='iax_encryption_values')),
-        sa.Column('transfer', sa.Enum(*IAX_TRANSFER_VALUES,
-                  name='iax_transfer_values')),
-        sa.Column('jitterbuffer', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('forcejitterbuffer', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('disallow', sa.String(200)),
-        sa.Column('allow', sa.String(200)),
-        sa.Column('codecpriority', sa.String(40)),
-        sa.Column('qualify', sa.String(10)),
-        sa.Column('qualifysmoothing',
-                  sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('qualifyfreqok', sa.String(10)),
-        sa.Column('qualifyfreqnotok', sa.String(10)),
-        sa.Column('timezone', sa.String(20)),
-        sa.Column('adsi', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('amaflags', sa.String(20)),
-        sa.Column('setvar', sa.String(200))
-    )
-    op.create_index('iaxfriends_name', 'iaxfriends', ['name'])
-    op.create_index('iaxfriends_name_host', 'iaxfriends', ['name', 'host'])
-    op.create_index('iaxfriends_name_ipaddr_port', 'iaxfriends',
-                    ['name', 'ipaddr', 'port'])
-    op.create_index('iaxfriends_ipaddr_port', 'iaxfriends', ['ipaddr', 'port'])
-    op.create_index('iaxfriends_host_port', 'iaxfriends', ['host', 'port'])
-
-    op.create_table(
-        'voicemail',
-        sa.Column('uniqueid', sa.Integer, primary_key=True, nullable=False,
-                  autoincrement=True),
-        sa.Column('context', sa.String(80), nullable=False),
-        sa.Column('mailbox', sa.String(80), nullable=False),
-        sa.Column('password', sa.String(80), nullable=False),
-        sa.Column('fullname', sa.String(80)),
-        sa.Column('alias', sa.String(80)),
-        sa.Column('email', sa.String(80)),
-        sa.Column('pager', sa.String(80)),
-        sa.Column('attach', sa.Enum(*YESNO_VALUES, name='yes_no_values')),
-        sa.Column('attachfmt', sa.String(10)),
-        sa.Column('serveremail', sa.String(80)),
-        sa.Column('language', sa.String(20)),
-        sa.Column('tz', sa.String(30)),
-        sa.Column('deletevoicemail', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('saycid', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('sendvoicemail', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('review', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('tempgreetwarn', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('operator', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('envelope', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('sayduration', sa.Integer),
-        sa.Column('forcename', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('forcegreetings', sa.Enum(*YESNO_VALUES,
-                  name='yes_no_values')),
-        sa.Column('callback', sa.String(80)),
-        sa.Column('dialout', sa.String(80)),
-        sa.Column('exitcontext', sa.String(80)),
-        sa.Column('maxmsg', sa.Integer),
-        sa.Column('volgain', sa.Numeric(precision=5, scale=2)),
-        sa.Column('imapuser', sa.String(80)),
-        sa.Column('imappassword', sa.String(80)),
-        sa.Column('imapserver', sa.String(80)),
-        sa.Column('imapport', sa.String(8)),
-        sa.Column('imapflags', sa.String(80)),
-        sa.Column('stamp', sa.DateTime())
-    )
-    op.create_index('voicemail_mailbox', 'voicemail', ['mailbox'])
-    op.create_index('voicemail_context', 'voicemail', ['context'])
-    op.create_index('voicemail_mailbox_context', 'voicemail',
-                    ['mailbox', 'context'])
-    op.create_index('voicemail_imapuser', 'voicemail', ['imapuser'])
-
-    op.create_table(
-        'meetme',
-        sa.Column('bookid', sa.Integer, primary_key=True, nullable=False,
-                  autoincrement=True),
-        sa.Column('confno', sa.String(80), nullable=False),
-        sa.Column('starttime', sa.DateTime()),
-        sa.Column('endtime', sa.DateTime()),
-        sa.Column('pin', sa.String(20)),
-        sa.Column('adminpin', sa.String(20)),
-        sa.Column('opts', sa.String(20)),
-        sa.Column('adminopts', sa.String(20)),
-        sa.Column('recordingfilename', sa.String(80)),
-        sa.Column('recordingformat', sa.String(10)),
-        sa.Column('maxusers', sa.Integer),
-        sa.Column('members', sa.Integer, nullable=False, default=0)
-    )
-    op.create_index('meetme_confno_start_end', 'meetme',
-                    ['confno', 'starttime', 'endtime'])
-
-    op.create_table(
-        'musiconhold',
-        sa.Column('name', sa.String(80), primary_key=True, nullable=False),
-        sa.Column('mode', sa.Enum(*MOH_MODE_VALUES, name='moh_mode_values')),
-        sa.Column('directory', sa.String(255)),
-        sa.Column('application', sa.String(255)),
-        sa.Column('digit', sa.String(1)),
-        sa.Column('sort', sa.String(10)),
-        sa.Column('format', sa.String(10)),
-        sa.Column('stamp', sa.DateTime())
-    )
-
-
-def downgrade():
-    op.drop_table('sippeers')
-    op.drop_table('iaxfriends')
-    op.drop_table('voicemail')
-    op.drop_table('meetme')
-    op.drop_table('musiconhold')
diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
deleted file mode 100755
index 6bcaa9a..0000000
--- a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Richard Mudgett
-#
-# Richard Mudgett <rmudgett at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""make q member uniqueid autoinc
-
-Revision ID: 5139253c0423
-Revises: 1758e8bbf6b
-Create Date: 2014-07-29 16:26:51.184981
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '5139253c0423'
-down_revision = '1758e8bbf6b'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    # Was unable to find a way to use op.alter_column() to add the unique
-    # index property.
-    op.drop_column('queue_members', 'uniqueid')
-    op.add_column(
-        'queue_members',
-        sa.Column(
-            name='uniqueid', type_=sa.Integer, nullable=False,
-            unique=True))
-    # The postgres backend does not like the autoincrement needed for
-    # mysql here.  It is just the backend that is giving a warning and
-    # not the database itself.
-    op.alter_column(
-        table_name='queue_members', column_name='uniqueid',
-        existing_type=sa.Integer, existing_nullable=False,
-        autoincrement=True)
-
-
-def downgrade():
-    # Was unable to find a way to use op.alter_column() to remove the
-    # unique index property.
-    op.drop_column('queue_members', 'uniqueid')
-    op.add_column(
-        'queue_members',
-        sa.Column(name='uniqueid', type_=sa.String(80), nullable=False))
-
diff --git a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
deleted file mode 100644
index c2dacda..0000000
--- a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""add further dtls options
-
-Revision ID: 51f8cb66540e
-Revises: c6d929b23a8
-Create Date: 2014-06-30 07:16:12.291684
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '51f8cb66540e'
-down_revision = 'c6d929b23a8'
-
-from alembic import op
-import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import ENUM
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-def upgrade():
-    ############################# Enums ##############################
-
-    # yesno_values have already been created, so use postgres enum object
-    # type to get around "already created" issue - works okay with mysql
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-
-    op.add_column('ps_endpoints', sa.Column('force_avp', yesno_values))
-    op.add_column('ps_endpoints', sa.Column('media_use_received_transport', yesno_values))
-
-def downgrade():
-    op.drop_column('ps_endpoints', 'force_avp')
-    op.drop_column('ps_endpoints', 'media_use_received_transport')
diff --git a/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py b/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py
deleted file mode 100755
index ecee0e0..0000000
--- a/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# Scott Griepentrog <sgriepentrog at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""adding extensions
-
-Revision ID: 581a4264e537
-Revises: 43956d550a44
-Create Date: 2013-12-10 16:32:41.145327
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '581a4264e537'
-down_revision = '43956d550a44'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.create_table(
-        'extensions',
-        sa.Column('id', sa.BigInteger, primary_key=True, nullable=False,
-                  unique=True, autoincrement=True),
-        sa.Column('context', sa.String(40), primary_key=True, nullable=False),
-        sa.Column('exten', sa.String(40), primary_key=True, nullable=False),
-        sa.Column('priority', sa.Integer, primary_key=True, nullable=False,
-                  autoincrement=True),
-        sa.Column('app', sa.String(40), nullable=False),
-        sa.Column('appdata', sa.String(256), nullable=False),
-    )
-
-
-def downgrade():
-    op.drop_table('extensions')
diff --git a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
deleted file mode 100644
index 28ebc8b..0000000
--- a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""Fix pjsip transports verify column
-
-Revision ID: 5950038a6ead
-Revises: d39508cb8d8
-Create Date: 2014-09-15 06:21:35.047314
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '5950038a6ead'
-down_revision = 'd39508cb8d8'
-
-from alembic import op
-from sqlalchemy.dialects.postgresql import ENUM
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-
-def upgrade():
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-    op.alter_column('ps_transports', 'verifiy_server', type_=yesno_values,
-                    new_column_name='verify_server')
-
-
-def downgrade():
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-    op.alter_column('ps_transports', 'verify_server', type_=yesno_values,
-                    new_column_name='verifiy_server')
diff --git a/contrib/ast-db-manage/config/versions/c6d929b23a8_create_pjsip_subscription_persistence_.py b/contrib/ast-db-manage/config/versions/c6d929b23a8_create_pjsip_subscription_persistence_.py
deleted file mode 100644
index aa5c8c4..0000000
--- a/contrib/ast-db-manage/config/versions/c6d929b23a8_create_pjsip_subscription_persistence_.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""create pjsip subscription persistence table
-
-Revision ID: c6d929b23a8
-Revises: e96a0b8071c
-Create Date: 2014-06-06 02:17:38.660447
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = 'c6d929b23a8'
-down_revision = 'e96a0b8071c'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.create_table(
-        'ps_subscription_persistence',
-        sa.Column('id', sa.String(40), nullable=False, unique=True),
-	sa.Column('packet', sa.String(2048)),
-	sa.Column('src_name', sa.String(128)),
-	sa.Column('src_port', sa.Integer),
-	sa.Column('transport_key', sa.String(64)),
-	sa.Column('local_name', sa.String(128)),
-	sa.Column('local_port', sa.Integer),
-	sa.Column('cseq', sa.Integer),
-	sa.Column('tag', sa.String(128)),
-	sa.Column('endpoint', sa.String(40)),
-	sa.Column('expires', sa.Integer),
-    )
-
-    op.create_index('ps_subscription_persistence_id', 'ps_subscription_persistence', ['id'])
-
-def downgrade():
-	op.drop_table('ps_subscription_persistence')
diff --git a/contrib/ast-db-manage/config/versions/d39508cb8d8_create_queue_rules.py b/contrib/ast-db-manage/config/versions/d39508cb8d8_create_queue_rules.py
deleted file mode 100644
index 7409721..0000000
--- a/contrib/ast-db-manage/config/versions/d39508cb8d8_create_queue_rules.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""Create queue_rules
-
-Revision ID: d39508cb8d8
-Revises: 5139253c0423
-Create Date: 2014-08-10 17:27:32.973571
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = 'd39508cb8d8'
-down_revision = '5139253c0423'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.create_table(
-        'queue_rules',
-        sa.Column('rule_name', sa.String(80), nullable=False),
-        sa.Column('time', sa.String(32), nullable=False),
-        sa.Column('min_penalty', sa.String(32), nullable=False),
-        sa.Column('max_penalty', sa.String(32), nullable=False)
-    )
-
-
-def downgrade():
-    ########################## drop tables ###########################
-
-    op.drop_table('queue_rules')
-
diff --git a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
deleted file mode 100644
index d386ded..0000000
--- a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""increase pjsip columns size
-
-Revision ID: e96a0b8071c
-Revises: 3855ee4e5f85
-Create Date: 2014-04-23 11:38:02.333786
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = 'e96a0b8071c'
-down_revision = '3855ee4e5f85'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.alter_column('ps_globals', 'user_agent', type_=sa.String(255))
-
-    op.alter_column('ps_contacts', 'id', type_=sa.String(255))
-    op.alter_column('ps_contacts', 'uri', type_=sa.String(255))
-    op.alter_column('ps_contacts', 'user_agent', type_=sa.String(255))
-
-    op.alter_column('ps_registrations', 'client_uri', type_=sa.String(255))
-    op.alter_column('ps_registrations', 'server_uri', type_=sa.String(255))
-
-
-def downgrade():
-    op.alter_column('ps_registrations', 'server_uri', type_=sa.String(40))
-    op.alter_column('ps_registrations', 'client_uri', type_=sa.String(40))
-
-    op.alter_column('ps_contacts', 'user_agent', type_=sa.String(40))
-    op.alter_column('ps_contacts', 'uri', type_=sa.String(40))
-    op.alter_column('ps_contacts', 'id', type_=sa.String(40))
-
-    op.alter_column('ps_globals', 'user_agent', type_=sa.String(40))
-
-
-
diff --git a/contrib/ast-db-manage/config/versions/eb88a14f2a_add_media_encryption_optimistic_to_pjsip.py b/contrib/ast-db-manage/config/versions/eb88a14f2a_add_media_encryption_optimistic_to_pjsip.py
deleted file mode 100644
index 2d96b37..0000000
--- a/contrib/ast-db-manage/config/versions/eb88a14f2a_add_media_encryption_optimistic_to_pjsip.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""add media encryption optimistic to pjsip
-
-Revision ID: eb88a14f2a
-Revises: 10aedae86a32
-Create Date: 2014-11-19 07:08:55.423018
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = 'eb88a14f2a'
-down_revision = '10aedae86a32'
-
-from alembic import op
-import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import ENUM
-
-YESNO_NAME = 'yesno_values'
-YESNO_VALUES = ['yes', 'no']
-
-def upgrade():
-    ############################# Enums ##############################
-
-    # yesno_values have already been created, so use postgres enum object
-    # type to get around "already created" issue - works okay with mysql
-    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
-
-    op.add_column('ps_endpoints', sa.Column('media_encryption_optimistic', yesno_values))
-
-
-def downgrade():
-    op.drop_column('ps_endpoints', 'media_encryption_optimistic')
diff --git a/contrib/ast-db-manage/voicemail.ini.sample b/contrib/ast-db-manage/voicemail.ini.sample
deleted file mode 100644
index 8fae8f1..0000000
--- a/contrib/ast-db-manage/voicemail.ini.sample
+++ /dev/null
@@ -1,57 +0,0 @@
-# A generic, single database configuration.
-
-[alembic]
-# path to migration scripts
-script_location = voicemail
-
-# template used to generate migration files
-# file_template = %%(rev)s_%%(slug)s
-
-# max length of characters to apply to the
-# "slug" field
-#truncate_slug_length = 40
-
-# set to 'true' to run the environment during
-# the 'revision' command, regardless of autogenerate
-# revision_environment = false
-
-#sqlalchemy.url = driver://user:pass@localhost/dbname
-
-#sqlalchemy.url = postgresql://user:pass@localhost/voicemail
-sqlalchemy.url = mysql://user:pass@localhost/voicemail
-
-
-# Logging configuration
-[loggers]
-keys = root,sqlalchemy,alembic
-
-[handlers]
-keys = console
-
-[formatters]
-keys = generic
-
-[logger_root]
-level = WARN
-handlers = console
-qualname =
-
-[logger_sqlalchemy]
-level = WARN
-handlers =
-qualname = sqlalchemy.engine
-
-[logger_alembic]
-level = INFO
-handlers =
-qualname = alembic
-
-[handler_console]
-class = StreamHandler
-args = (sys.stderr,)
-level = NOTSET
-formatter = generic
-
-[formatter_generic]
-format = %(levelname)-5.5s [%(name)s] %(message)s
-datefmt = %H:%M:%S
diff --git a/contrib/ast-db-manage/voicemail/env.py b/contrib/ast-db-manage/voicemail/env.py
deleted file mode 100755
index 6740d59..0000000
--- a/contrib/ast-db-manage/voicemail/env.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
-    fileConfig(config.config_file_name)
-except:
-    pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
-    """Run migrations in 'offline' mode.
-
-    This configures the context with just a URL
-    and not an Engine, though an Engine is acceptable
-    here as well.  By skipping the Engine creation
-    we don't even need a DBAPI to be available.
-
-    Calls to context.execute() here emit the given string to the
-    script output.
-
-    """
-    url = config.get_main_option("sqlalchemy.url")
-    context.configure(url=url)
-
-    with context.begin_transaction():
-        context.run_migrations()
-
-def run_migrations_online():
-    """Run migrations in 'online' mode.
-
-    In this scenario we need to create an Engine
-    and associate a connection with the context.
-
-    """
-    engine = engine_from_config(
-                config.get_section(config.config_ini_section),
-                prefix='sqlalchemy.',
-                poolclass=pool.NullPool)
-
-    connection = engine.connect()
-    context.configure(
-                connection=connection,
-                target_metadata=target_metadata
-                )
-
-    try:
-        with context.begin_transaction():
-            context.run_migrations()
-    finally:
-        connection.close()
-
-if context.is_offline_mode():
-    run_migrations_offline()
-else:
-    run_migrations_online()
-
diff --git a/contrib/ast-db-manage/voicemail/script.py.mako b/contrib/ast-db-manage/voicemail/script.py.mako
deleted file mode 100644
index 9570201..0000000
--- a/contrib/ast-db-manage/voicemail/script.py.mako
+++ /dev/null
@@ -1,22 +0,0 @@
-"""${message}
-
-Revision ID: ${up_revision}
-Revises: ${down_revision}
-Create Date: ${create_date}
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = ${repr(up_revision)}
-down_revision = ${repr(down_revision)}
-
-from alembic import op
-import sqlalchemy as sa
-${imports if imports else ""}
-
-def upgrade():
-    ${upgrades if upgrades else "pass"}
-
-
-def downgrade():
-    ${downgrades if downgrades else "pass"}
diff --git a/contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py b/contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py
deleted file mode 100755
index f06cbf1..0000000
--- a/contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2014, Richard Mudgett
-#
-# Richard Mudgett <rmudgett at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""increase recording column size
-
-Revision ID: 39428242f7f5
-Revises: a2e9769475e
-Create Date: 2014-07-28 16:02:05.104895
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = '39428242f7f5'
-down_revision = 'a2e9769475e'
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    # Make BLOB a LONGBLOB for mysql so recordings longer than about
-    # four seconds can be stored.
-    # See LargeBinary http://docs.sqlalchemy.org/en/rel_0_9/core/types.html
-    op.alter_column('voicemail_messages', 'recording', type_=sa.LargeBinary(4294967295))
-
-
-def downgrade():
-    op.alter_column('voicemail_messages', 'recording', type_=sa.LargeBinary)
-
diff --git a/contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py b/contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py
deleted file mode 100755
index 3dc4d47..0000000
--- a/contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Russell Bryant
-#
-# Russell Bryant <russell at rusellbryant.net>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Create tables
-
-Revision ID: a2e9769475e
-Revises: None
-Create Date: 2013-07-29 23:43:09.431668
-
-"""
-
-# revision identifiers, used by Alembic.
-revision = 'a2e9769475e'
-down_revision = None
-
-from alembic import op
-import sqlalchemy as sa
-
-
-def upgrade():
-    op.create_table(
-        'voicemail_messages',
-        sa.Column('dir', sa.String(255), nullable=False),
-        sa.Column('msgnum', sa.Integer, nullable=False),
-        sa.Column('context', sa.String(80)),
-        sa.Column('macrocontext', sa.String(80)),
-        sa.Column('callerid', sa.String(80)),
-        sa.Column('origtime', sa.Integer),
-        sa.Column('duration', sa.Integer),
-        sa.Column('recording', sa.LargeBinary),
-        sa.Column('flag', sa.String(30)),
-        sa.Column('category', sa.String(30)),
-        sa.Column('mailboxuser', sa.String(30)),
-        sa.Column('mailboxcontext', sa.String(30)),
-        sa.Column('msg_id', sa.String(40))
-    )
-    op.create_primary_key('voicemail_messages_dir_msgnum',
-            'voicemail_messages', ['dir', 'msgnum'])
-    op.create_index('voicemail_messages_dir', 'voicemail_messages', ['dir'])
-
-
-def downgrade():
-    op.drop_table('voicemail_messages')
diff --git a/contrib/editors/asterisk.vim b/contrib/editors/asterisk.vim
index a96a836..dd53a70 100644
--- a/contrib/editors/asterisk.vim
+++ b/contrib/editors/asterisk.vim
@@ -14,7 +14,8 @@ syn sync clear
 syn sync fromstart
 
 syn keyword     asteriskTodo            TODO contained
-syn match       asteriskComment         ";.*" contains=asteriskTodo
+syn match       asteriskComment         "\\\@<!;.*" contains=asteriskTodo
+syn region      asteriskBlockComment    start=/\\\@<!;---\@!/ end=/--;/ contains=asteriskBlockComment,asteriskTodo
 syn match       asteriskContext         "\[.\{-}\]"
 syn match       asteriskExten           "^\s*exten\s*=>\?\s*[^,]\+" contains=asteriskPattern
 syn match       asteriskExten           "^\s*\(register\|channel\|ignorepat\|include\|\(no\)\?load\)\s*=>\?"
@@ -67,6 +68,7 @@ if version >= 508 || !exists("did_conf_syntax_inits")
   endif
 
   HiLink        asteriskComment         Comment
+  HiLink        asteriskBlockComment    Comment
   HiLink        asteriskExten           String
   HiLink        asteriskContext         Preproc
   HiLink        asteriskPattern         Type
diff --git a/contrib/init.d/rc.debian.asterisk b/contrib/init.d/rc.debian.asterisk
index ecd7aff..211737f 100755
--- a/contrib/init.d/rc.debian.asterisk
+++ b/contrib/init.d/rc.debian.asterisk
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $Id: rc.debian.asterisk 379791 2013-01-21 20:41:12Z mjordan $
+# $Id$
 #
 # Mon Jun 04 2007 Iñaki Baz Castillo <ibc at in.ilimit.es>
 # - Eliminated SAFE_ASTERISK since it doesn't work as LSB script (it could require a independent "safe_asterisk" init script).
diff --git a/contrib/init.d/rc.gentoo.asterisk b/contrib/init.d/rc.gentoo.asterisk
index 63cf6f5..04d1c7a 100755
--- a/contrib/init.d/rc.gentoo.asterisk
+++ b/contrib/init.d/rc.gentoo.asterisk
@@ -1,5 +1,5 @@
 #!/sbin/runscript
-# $Id: rc.gentoo.asterisk 379791 2013-01-21 20:41:12Z mjordan $
+# $Id$
 
 ### BEGIN INIT INFO
 # Provides:		asterisk
diff --git a/contrib/init.d/rc.mandriva.asterisk b/contrib/init.d/rc.mandriva.asterisk
index 67393f3..e095ccf 100755
--- a/contrib/init.d/rc.mandriva.asterisk
+++ b/contrib/init.d/rc.mandriva.asterisk
@@ -22,7 +22,7 @@
 # Description:		the Asterisk Open Source PBX
 ### END INIT INFO
 
-# $Id: rc.mandriva.asterisk 379791 2013-01-21 20:41:12Z mjordan $
+# $Id$
 
 TTY=9			# TTY (if you want one) for Asterisk to run on
 CONSOLE=yes		# Whether or not you want a console
diff --git a/contrib/init.d/rc.mandriva.zaptel b/contrib/init.d/rc.mandriva.zaptel
index 4bb3494..14a658b 100755
--- a/contrib/init.d/rc.mandriva.zaptel
+++ b/contrib/init.d/rc.mandriva.zaptel
@@ -9,7 +9,7 @@
 #
 # hide: true
 
-# $Id: rc.mandriva.zaptel 135485 2008-08-04 17:12:15Z tilghman $
+# $Id$
 
 # Source function library.
 . /etc/rc.d/init.d/functions
diff --git a/contrib/init.d/rc.redhat.asterisk b/contrib/init.d/rc.redhat.asterisk
index b04c472..45ea9bc 100755
--- a/contrib/init.d/rc.redhat.asterisk
+++ b/contrib/init.d/rc.redhat.asterisk
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Id: rc.redhat.asterisk 379791 2013-01-21 20:41:12Z mjordan $
+# $Id$
 #
 # asterisk    Starts, Stops and Reloads Asterisk.
 #
diff --git a/contrib/init.d/rc.slackware.asterisk b/contrib/init.d/rc.slackware.asterisk
index b87efd3..79c2b92 100755
--- a/contrib/init.d/rc.slackware.asterisk
+++ b/contrib/init.d/rc.slackware.asterisk
@@ -6,7 +6,7 @@
 #
 # 03.29.2005 - Initial Version
 #
-# $Id: rc.slackware.asterisk 379791 2013-01-21 20:41:12Z mjordan $
+# $Id$
 
 ### BEGIN INIT INFO
 # Provides:		asterisk
diff --git a/contrib/realtime/mysql/iaxfriends.sql b/contrib/realtime/mysql/iaxfriends.sql
new file mode 100644
index 0000000..f01fd73
--- /dev/null
+++ b/contrib/realtime/mysql/iaxfriends.sql
@@ -0,0 +1,56 @@
+#
+# Table structure for table `iaxfriends`
+#
+
+CREATE TABLE `iaxfriends` (
+  `name` varchar(40) NOT NULL default '',
+  `type` varchar(10) NOT NULL default 'friend', -- friend/user/peer
+  `username` varchar(40) NULL, -- username to send as peer
+  `mailbox` varchar(40) NULL, -- mailbox at context
+  `secret` varchar(40) NULL,
+  `dbsecret` varchar(40) NULL, -- In AstDB, location to store/retrieve secret
+  `context` varchar(40) NULL,
+  `regcontext` varchar(40) NULL,
+  `host` varchar(40) NULL default 'dynamic',
+  `ipaddr` varchar(40) NULL, -- Must be updateable by Asterisk user
+  `port` int(5) NULL, -- Must be updateable by Asterisk user
+  `defaultip` varchar(20) NULL,
+  `sourceaddress` varchar(20) NULL,
+  `mask` varchar(20) NULL,
+  `regexten` varchar(40) NULL,
+  `regseconds` int(11) NULL, -- Must be updateable by Asterisk user
+  `accountcode` varchar(20) NULL, 
+  `mohinterpret` varchar(20) NULL, 
+  `mohsuggest` varchar(20) NULL, 
+  `inkeys` varchar(40) NULL, 
+  `outkey` varchar(40) NULL, 
+  `language` varchar(10) NULL, 
+  `callerid` varchar(100) NULL, -- The whole callerid string, or broken down in the next 3 fields
+  `cid_number` varchar(40) NULL, -- The number portion of the callerid
+  `sendani` varchar(10) NULL, -- yes/no
+  `fullname` varchar(40) NULL, -- The name portion of the callerid
+  `trunk` varchar(3) NULL, -- Yes/no
+  `auth` varchar(20) NULL, -- RSA/md5/plaintext
+  `maxauthreq` varchar(5) NULL, -- Maximum outstanding AUTHREQ calls {1-32767}
+  `requirecalltoken` varchar(4) NULL, -- yes/no/auto
+  `encryption` varchar(20) NULL, -- aes128/yes/no
+  `transfer` varchar(10) NULL, -- mediaonly/yes/no
+  `jitterbuffer` varchar(3) NULL, -- yes/no
+  `forcejitterbuffer` varchar(3) NULL, -- yes/no
+  `allow` varchar(200) NULL, -- all/{list-of-codecs}
+  `codecpriority` varchar(40) NULL, 
+  `qualify` varchar(10) NULL, -- yes/no/{number of milliseconds}
+  `qualifysmoothing` varchar(10) NULL, -- yes/no
+  `qualifyfreqok` varchar(10) NULL, -- {number of milliseconds}|60000
+  `qualifyfreqnotok` varchar(10) NULL, -- {number of milliseconds}|10000
+  `timezone` varchar(20) NULL, 
+  `adsi` varchar(10) NULL, -- yes/no
+  `amaflags` varchar(20) NULL, 
+  `setvar` varchar(200) NULL, 
+  PRIMARY KEY  (`name`),
+  INDEX name (name, host),
+  INDEX name2 (name, ipaddr, port),
+  INDEX ipaddr (ipaddr, port),
+  INDEX host (host, port)
+);
+
diff --git a/contrib/realtime/mysql/meetme.sql b/contrib/realtime/mysql/meetme.sql
new file mode 100644
index 0000000..5a1bac4
--- /dev/null
+++ b/contrib/realtime/mysql/meetme.sql
@@ -0,0 +1,21 @@
+-- 
+-- Table structure for Realtime meetme
+-- 
+
+CREATE TABLE meetme (
+	bookid int(11) auto_increment,
+	confno char(80) DEFAULT '0' NOT NULL,
+	starttime datetime default '1900-01-01 12:00:00',
+	endtime datetime default '2038-01-01 12:00:00',
+	pin char(20) NULL,
+	adminpin char(20) NULL,
+	opts char(20) NULL,
+	adminopts char(20) NULL,
+	recordingfilename char(80) NULL,
+	recordingformat char(10) NULL,
+	maxusers int(11) NULL,
+	members integer DEFAULT 0 NOT NULL,
+	index confno (confno,starttime,endtime),
+	PRIMARY KEY (bookid)
+);
+
diff --git a/contrib/realtime/mysql/musiconhold.sql b/contrib/realtime/mysql/musiconhold.sql
new file mode 100644
index 0000000..63ccd8d
--- /dev/null
+++ b/contrib/realtime/mysql/musiconhold.sql
@@ -0,0 +1,19 @@
+CREATE TABLE musiconhold (
+	-- Name of the MOH class
+	name char(80) not null primary key,
+	-- One of 'custom', 'files', 'mp3nb', 'quietmp3nb', or 'quietmp3'
+	mode char(80) null,
+	-- If 'custom', directory is ignored.  Otherwise, specifies a directory with files to play or a stream URL
+	directory char(255) null,
+	-- If 'custom', application will be invoked to provide MOH.  Ignored otherwise.
+	application char(255) null,
+	-- Digit associated with this MOH class, when MOH is selectable by the caller.
+	digit char(1) null,
+	-- One of 'random' or 'alpha', to determine how files are played.  If NULL, files are played in directory order
+	sort char(10) null,
+	-- In custom mode, the format of the audio delivered.  Ignored otherwise.  Defaults to SLIN.
+	format char(10) null,
+	-- When this record was last modified
+	stamp timestamp
+);
+
diff --git a/contrib/realtime/mysql/mysql_cdr.sql b/contrib/realtime/mysql/mysql_cdr.sql
deleted file mode 100644
index 95d2282..0000000
--- a/contrib/realtime/mysql/mysql_cdr.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> 210693f3123d
-
-CREATE TABLE cdr (
-    accountcode VARCHAR(20), 
-    src VARCHAR(80), 
-    dst VARCHAR(80), 
-    dcontext VARCHAR(80), 
-    clid VARCHAR(80), 
-    channel VARCHAR(80), 
-    dstchannel VARCHAR(80), 
-    lastapp VARCHAR(80), 
-    lastdata VARCHAR(80), 
-    start DATETIME, 
-    answer DATETIME, 
-    end DATETIME, 
-    duration INTEGER, 
-    billsec INTEGER, 
-    disposition VARCHAR(45), 
-    amaflags VARCHAR(45), 
-    userfield VARCHAR(256), 
-    uniqueid VARCHAR(150), 
-    linkedid VARCHAR(150), 
-    peeraccount VARCHAR(20), 
-    sequence INTEGER
-);
-
-INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
-
diff --git a/contrib/realtime/mysql/mysql_config.sql b/contrib/realtime/mysql/mysql_config.sql
deleted file mode 100644
index de713fe..0000000
--- a/contrib/realtime/mysql/mysql_config.sql
+++ /dev/null
@@ -1,705 +0,0 @@
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> 4da0c5f79a9c
-
-CREATE TABLE sippeers (
-    id INTEGER NOT NULL AUTO_INCREMENT, 
-    name VARCHAR(40) NOT NULL, 
-    ipaddr VARCHAR(45), 
-    port INTEGER, 
-    regseconds INTEGER, 
-    defaultuser VARCHAR(40), 
-    fullcontact VARCHAR(80), 
-    regserver VARCHAR(20), 
-    useragent VARCHAR(20), 
-    lastms INTEGER, 
-    host VARCHAR(40), 
-    type ENUM('friend','user','peer'), 
-    context VARCHAR(40), 
-    permit VARCHAR(95), 
-    deny VARCHAR(95), 
-    secret VARCHAR(40), 
-    md5secret VARCHAR(40), 
-    remotesecret VARCHAR(40), 
-    transport ENUM('udp','tcp','tls','ws','wss','udp,tcp','tcp,udp'), 
-    dtmfmode ENUM('rfc2833','info','shortinfo','inband','auto'), 
-    directmedia ENUM('yes','no','nonat','update'), 
-    nat VARCHAR(29), 
-    callgroup VARCHAR(40), 
-    pickupgroup VARCHAR(40), 
-    language VARCHAR(40), 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    insecure VARCHAR(40), 
-    trustrpid ENUM('yes','no'), 
-    progressinband ENUM('yes','no','never'), 
-    promiscredir ENUM('yes','no'), 
-    useclientcode ENUM('yes','no'), 
-    accountcode VARCHAR(40), 
-    setvar VARCHAR(200), 
-    callerid VARCHAR(40), 
-    amaflags VARCHAR(40), 
-    callcounter ENUM('yes','no'), 
-    busylevel INTEGER, 
-    allowoverlap ENUM('yes','no'), 
-    allowsubscribe ENUM('yes','no'), 
-    videosupport ENUM('yes','no'), 
-    maxcallbitrate INTEGER, 
-    rfc2833compensate ENUM('yes','no'), 
-    mailbox VARCHAR(40), 
-    `session-timers` ENUM('accept','refuse','originate'), 
-    `session-expires` INTEGER, 
-    `session-minse` INTEGER, 
-    `session-refresher` ENUM('uac','uas'), 
-    t38pt_usertpsource VARCHAR(40), 
-    regexten VARCHAR(40), 
-    fromdomain VARCHAR(40), 
-    fromuser VARCHAR(40), 
-    qualify VARCHAR(40), 
-    defaultip VARCHAR(45), 
-    rtptimeout INTEGER, 
-    rtpholdtimeout INTEGER, 
-    sendrpid ENUM('yes','no'), 
-    outboundproxy VARCHAR(40), 
-    callbackextension VARCHAR(40), 
-    timert1 INTEGER, 
-    timerb INTEGER, 
-    qualifyfreq INTEGER, 
-    constantssrc ENUM('yes','no'), 
-    contactpermit VARCHAR(95), 
-    contactdeny VARCHAR(95), 
-    usereqphone ENUM('yes','no'), 
-    textsupport ENUM('yes','no'), 
-    faxdetect ENUM('yes','no'), 
-    buggymwi ENUM('yes','no'), 
-    auth VARCHAR(40), 
-    fullname VARCHAR(40), 
-    trunkname VARCHAR(40), 
-    cid_number VARCHAR(40), 
-    callingpres ENUM('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib'), 
-    mohinterpret VARCHAR(40), 
-    mohsuggest VARCHAR(40), 
-    parkinglot VARCHAR(40), 
-    hasvoicemail ENUM('yes','no'), 
-    subscribemwi ENUM('yes','no'), 
-    vmexten VARCHAR(40), 
-    autoframing ENUM('yes','no'), 
-    rtpkeepalive INTEGER, 
-    `call-limit` INTEGER, 
-    g726nonstandard ENUM('yes','no'), 
-    ignoresdpversion ENUM('yes','no'), 
-    allowtransfer ENUM('yes','no'), 
-    dynamic ENUM('yes','no'), 
-    path VARCHAR(256), 
-    supportpath ENUM('yes','no'), 
-    PRIMARY KEY (id), 
-    UNIQUE (name)
-);
-
-CREATE INDEX sippeers_name ON sippeers (name);
-
-CREATE INDEX sippeers_name_host ON sippeers (name, host);
-
-CREATE INDEX sippeers_ipaddr_port ON sippeers (ipaddr, port);
-
-CREATE INDEX sippeers_host_port ON sippeers (host, port);
-
-CREATE TABLE iaxfriends (
-    id INTEGER NOT NULL AUTO_INCREMENT, 
-    name VARCHAR(40) NOT NULL, 
-    type ENUM('friend','user','peer'), 
-    username VARCHAR(40), 
-    mailbox VARCHAR(40), 
-    secret VARCHAR(40), 
-    dbsecret VARCHAR(40), 
-    context VARCHAR(40), 
-    regcontext VARCHAR(40), 
-    host VARCHAR(40), 
-    ipaddr VARCHAR(40), 
-    port INTEGER, 
-    defaultip VARCHAR(20), 
-    sourceaddress VARCHAR(20), 
-    mask VARCHAR(20), 
-    regexten VARCHAR(40), 
-    regseconds INTEGER, 
-    accountcode VARCHAR(20), 
-    mohinterpret VARCHAR(20), 
-    mohsuggest VARCHAR(20), 
-    inkeys VARCHAR(40), 
-    outkeys VARCHAR(40), 
-    language VARCHAR(10), 
-    callerid VARCHAR(100), 
-    cid_number VARCHAR(40), 
-    sendani ENUM('yes','no'), 
-    fullname VARCHAR(40), 
-    trunk ENUM('yes','no'), 
-    auth VARCHAR(20), 
-    maxauthreq INTEGER, 
-    requirecalltoken ENUM('yes','no','auto'), 
-    encryption ENUM('yes','no','aes128'), 
-    transfer ENUM('yes','no','mediaonly'), 
-    jitterbuffer ENUM('yes','no'), 
-    forcejitterbuffer ENUM('yes','no'), 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    codecpriority VARCHAR(40), 
-    qualify VARCHAR(10), 
-    qualifysmoothing ENUM('yes','no'), 
-    qualifyfreqok VARCHAR(10), 
-    qualifyfreqnotok VARCHAR(10), 
-    timezone VARCHAR(20), 
-    adsi ENUM('yes','no'), 
-    amaflags VARCHAR(20), 
-    setvar VARCHAR(200), 
-    PRIMARY KEY (id), 
-    UNIQUE (name)
-);
-
-CREATE INDEX iaxfriends_name ON iaxfriends (name);
-
-CREATE INDEX iaxfriends_name_host ON iaxfriends (name, host);
-
-CREATE INDEX iaxfriends_name_ipaddr_port ON iaxfriends (name, ipaddr, port);
-
-CREATE INDEX iaxfriends_ipaddr_port ON iaxfriends (ipaddr, port);
-
-CREATE INDEX iaxfriends_host_port ON iaxfriends (host, port);
-
-CREATE TABLE voicemail (
-    uniqueid INTEGER NOT NULL AUTO_INCREMENT, 
-    context VARCHAR(80) NOT NULL, 
-    mailbox VARCHAR(80) NOT NULL, 
-    password VARCHAR(80) NOT NULL, 
-    fullname VARCHAR(80), 
-    alias VARCHAR(80), 
-    email VARCHAR(80), 
-    pager VARCHAR(80), 
-    attach ENUM('yes','no'), 
-    attachfmt VARCHAR(10), 
-    serveremail VARCHAR(80), 
-    language VARCHAR(20), 
-    tz VARCHAR(30), 
-    deletevoicemail ENUM('yes','no'), 
-    saycid ENUM('yes','no'), 
-    sendvoicemail ENUM('yes','no'), 
-    review ENUM('yes','no'), 
-    tempgreetwarn ENUM('yes','no'), 
-    operator ENUM('yes','no'), 
-    envelope ENUM('yes','no'), 
-    sayduration INTEGER, 
-    forcename ENUM('yes','no'), 
-    forcegreetings ENUM('yes','no'), 
-    callback VARCHAR(80), 
-    dialout VARCHAR(80), 
-    exitcontext VARCHAR(80), 
-    maxmsg INTEGER, 
-    volgain NUMERIC(5, 2), 
-    imapuser VARCHAR(80), 
-    imappassword VARCHAR(80), 
-    imapserver VARCHAR(80), 
-    imapport VARCHAR(8), 
-    imapflags VARCHAR(80), 
-    stamp DATETIME, 
-    PRIMARY KEY (uniqueid)
-);
-
-CREATE INDEX voicemail_mailbox ON voicemail (mailbox);
-
-CREATE INDEX voicemail_context ON voicemail (context);
-
-CREATE INDEX voicemail_mailbox_context ON voicemail (mailbox, context);
-
-CREATE INDEX voicemail_imapuser ON voicemail (imapuser);
-
-CREATE TABLE meetme (
-    bookid INTEGER NOT NULL AUTO_INCREMENT, 
-    confno VARCHAR(80) NOT NULL, 
-    starttime DATETIME, 
-    endtime DATETIME, 
-    pin VARCHAR(20), 
-    adminpin VARCHAR(20), 
-    opts VARCHAR(20), 
-    adminopts VARCHAR(20), 
-    recordingfilename VARCHAR(80), 
-    recordingformat VARCHAR(10), 
-    maxusers INTEGER, 
-    members INTEGER NOT NULL, 
-    PRIMARY KEY (bookid)
-);
-
-CREATE INDEX meetme_confno_start_end ON meetme (confno, starttime, endtime);
-
-CREATE TABLE musiconhold (
-    name VARCHAR(80) NOT NULL, 
-    mode ENUM('custom','files','mp3nb','quietmp3nb','quietmp3'), 
-    directory VARCHAR(255), 
-    application VARCHAR(255), 
-    digit VARCHAR(1), 
-    sort VARCHAR(10), 
-    format VARCHAR(10), 
-    stamp DATETIME, 
-    PRIMARY KEY (name)
-);
-
-INSERT INTO alembic_version (version_num) VALUES ('4da0c5f79a9c');
-
--- Running upgrade 4da0c5f79a9c -> 43956d550a44
-
-CREATE TABLE ps_endpoints (
-    id VARCHAR(40) NOT NULL, 
-    transport VARCHAR(40), 
-    aors VARCHAR(200), 
-    auth VARCHAR(40), 
-    context VARCHAR(40), 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    direct_media ENUM('yes','no'), 
-    connected_line_method ENUM('invite','reinvite','update'), 
-    direct_media_method ENUM('invite','reinvite','update'), 
-    direct_media_glare_mitigation ENUM('none','outgoing','incoming'), 
-    disable_direct_media_on_nat ENUM('yes','no'), 
-    dtmf_mode ENUM('rfc4733','inband','info'), 
-    external_media_address VARCHAR(40), 
-    force_rport ENUM('yes','no'), 
-    ice_support ENUM('yes','no'), 
-    identify_by ENUM('username'), 
-    mailboxes VARCHAR(40), 
-    moh_suggest VARCHAR(40), 
-    outbound_auth VARCHAR(40), 
-    outbound_proxy VARCHAR(40), 
-    rewrite_contact ENUM('yes','no'), 
-    rtp_ipv6 ENUM('yes','no'), 
-    rtp_symmetric ENUM('yes','no'), 
-    send_diversion ENUM('yes','no'), 
-    send_pai ENUM('yes','no'), 
-    send_rpid ENUM('yes','no'), 
-    timers_min_se INTEGER, 
-    timers ENUM('forced','no','required','yes'), 
-    timers_sess_expires INTEGER, 
-    callerid VARCHAR(40), 
-    callerid_privacy ENUM('allowed_not_screened','allowed_passed_screened','allowed_failed_screened','allowed','prohib_not_screened','prohib_passed_screened','prohib_failed_screened','prohib','unavailable'), 
-    callerid_tag VARCHAR(40), 
-    `100rel` ENUM('no','required','yes'), 
-    aggregate_mwi ENUM('yes','no'), 
-    trust_id_inbound ENUM('yes','no'), 
-    trust_id_outbound ENUM('yes','no'), 
-    use_ptime ENUM('yes','no'), 
-    use_avpf ENUM('yes','no'), 
-    media_encryption ENUM('no','sdes','dtls'), 
-    inband_progress ENUM('yes','no'), 
-    call_group VARCHAR(40), 
-    pickup_group VARCHAR(40), 
-    named_call_group VARCHAR(40), 
-    named_pickup_group VARCHAR(40), 
-    device_state_busy_at INTEGER, 
-    fax_detect ENUM('yes','no'), 
-    t38_udptl ENUM('yes','no'), 
-    t38_udptl_ec ENUM('none','fec','redundancy'), 
-    t38_udptl_maxdatagram INTEGER, 
-    t38_udptl_nat ENUM('yes','no'), 
-    t38_udptl_ipv6 ENUM('yes','no'), 
-    tone_zone VARCHAR(40), 
-    language VARCHAR(40), 
-    one_touch_recording ENUM('yes','no'), 
-    record_on_feature VARCHAR(40), 
-    record_off_feature VARCHAR(40), 
-    rtp_engine VARCHAR(40), 
-    allow_transfer ENUM('yes','no'), 
-    allow_subscribe ENUM('yes','no'), 
-    sdp_owner VARCHAR(40), 
-    sdp_session VARCHAR(40), 
-    tos_audio INTEGER, 
-    tos_video INTEGER, 
-    cos_audio INTEGER, 
-    cos_video INTEGER, 
-    sub_min_expiry INTEGER, 
-    from_domain VARCHAR(40), 
-    from_user VARCHAR(40), 
-    mwi_fromuser VARCHAR(40), 
-    dtls_verify VARCHAR(40), 
-    dtls_rekey VARCHAR(40), 
-    dtls_cert_file VARCHAR(200), 
-    dtls_private_key VARCHAR(200), 
-    dtls_cipher VARCHAR(200), 
-    dtls_ca_file VARCHAR(200), 
-    dtls_ca_path VARCHAR(200), 
-    dtls_setup ENUM('active','passive','actpass'), 
-    srtp_tag_32 ENUM('yes','no'), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_endpoints_id ON ps_endpoints (id);
-
-CREATE TABLE ps_auths (
-    id VARCHAR(40) NOT NULL, 
-    auth_type ENUM('md5','userpass'), 
-    nonce_lifetime INTEGER, 
-    md5_cred VARCHAR(40), 
-    password VARCHAR(80), 
-    realm VARCHAR(40), 
-    username VARCHAR(40), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_auths_id ON ps_auths (id);
-
-CREATE TABLE ps_aors (
-    id VARCHAR(40) NOT NULL, 
-    contact VARCHAR(40), 
-    default_expiration INTEGER, 
-    mailboxes VARCHAR(80), 
-    max_contacts INTEGER, 
-    minimum_expiration INTEGER, 
-    remove_existing ENUM('yes','no'), 
-    qualify_frequency INTEGER, 
-    authenticate_qualify ENUM('yes','no'), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_aors_id ON ps_aors (id);
-
-CREATE TABLE ps_contacts (
-    id VARCHAR(40) NOT NULL, 
-    uri VARCHAR(40), 
-    expiration_time VARCHAR(40), 
-    qualify_frequency INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_contacts_id ON ps_contacts (id);
-
-CREATE TABLE ps_domain_aliases (
-    id VARCHAR(40) NOT NULL, 
-    domain VARCHAR(80), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_domain_aliases_id ON ps_domain_aliases (id);
-
-CREATE TABLE ps_endpoint_id_ips (
-    id VARCHAR(40) NOT NULL, 
-    endpoint VARCHAR(40), 
-    `match` VARCHAR(80), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_endpoint_id_ips_id ON ps_endpoint_id_ips (id);
-
-UPDATE alembic_version SET version_num='43956d550a44';
-
--- Running upgrade 43956d550a44 -> 581a4264e537
-
-CREATE TABLE extensions (
-    id BIGINT NOT NULL AUTO_INCREMENT, 
-    context VARCHAR(40) NOT NULL, 
-    exten VARCHAR(40) NOT NULL, 
-    priority INTEGER NOT NULL, 
-    app VARCHAR(40) NOT NULL, 
-    appdata VARCHAR(256) NOT NULL, 
-    PRIMARY KEY (id, context, exten, priority), 
-    UNIQUE (id)
-);
-
-UPDATE alembic_version SET version_num='581a4264e537';
-
--- Running upgrade 581a4264e537 -> 2fc7930b41b3
-
-CREATE TABLE ps_systems (
-    id VARCHAR(40) NOT NULL, 
-    timer_t1 INTEGER, 
-    timer_b INTEGER, 
-    compact_headers ENUM('yes','no'), 
-    threadpool_initial_size INTEGER, 
-    threadpool_auto_increment INTEGER, 
-    threadpool_idle_timeout INTEGER, 
-    threadpool_max_size INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_systems_id ON ps_systems (id);
-
-CREATE TABLE ps_globals (
-    id VARCHAR(40) NOT NULL, 
-    max_forwards INTEGER, 
-    user_agent VARCHAR(40), 
-    default_outbound_endpoint VARCHAR(40), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_globals_id ON ps_globals (id);
-
-CREATE TABLE ps_transports (
-    id VARCHAR(40) NOT NULL, 
-    async_operations INTEGER, 
-    bind VARCHAR(40), 
-    ca_list_file VARCHAR(200), 
-    cert_file VARCHAR(200), 
-    cipher VARCHAR(200), 
-    domain VARCHAR(40), 
-    external_media_address VARCHAR(40), 
-    external_signaling_address VARCHAR(40), 
-    external_signaling_port INTEGER, 
-    method ENUM('default','unspecified','tlsv1','sslv2','sslv3','sslv23'), 
-    local_net VARCHAR(40), 
-    password VARCHAR(40), 
-    priv_key_file VARCHAR(200), 
-    protocol ENUM('udp','tcp','tls','ws','wss'), 
-    require_client_cert ENUM('yes','no'), 
-    verify_client ENUM('yes','no'), 
-    verifiy_server ENUM('yes','no'), 
-    tos ENUM('yes','no'), 
-    cos ENUM('yes','no'), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_transports_id ON ps_transports (id);
-
-CREATE TABLE ps_registrations (
-    id VARCHAR(40) NOT NULL, 
-    auth_rejection_permanent ENUM('yes','no'), 
-    client_uri VARCHAR(40), 
-    contact_user VARCHAR(40), 
-    expiration INTEGER, 
-    max_retries INTEGER, 
-    outbound_auth VARCHAR(40), 
-    outbound_proxy VARCHAR(40), 
-    retry_interval INTEGER, 
-    forbidden_retry_interval INTEGER, 
-    server_uri VARCHAR(40), 
-    transport VARCHAR(40), 
-    support_path ENUM('yes','no'), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_registrations_id ON ps_registrations (id);
-
-ALTER TABLE ps_endpoints ADD COLUMN media_address VARCHAR(40);
-
-ALTER TABLE ps_endpoints ADD COLUMN redirect_method ENUM('user','uri_core','uri_pjsip');
-
-ALTER TABLE ps_endpoints ADD COLUMN set_var TEXT;
-
-ALTER TABLE ps_endpoints CHANGE mwi_fromuser mwi_from_user VARCHAR(40) NULL;
-
-ALTER TABLE ps_contacts ADD COLUMN outbound_proxy VARCHAR(40);
-
-ALTER TABLE ps_contacts ADD COLUMN path TEXT;
-
-ALTER TABLE ps_aors ADD COLUMN maximum_expiration INTEGER;
-
-ALTER TABLE ps_aors ADD COLUMN outbound_proxy VARCHAR(40);
-
-ALTER TABLE ps_aors ADD COLUMN support_path ENUM('yes','no');
-
-UPDATE alembic_version SET version_num='2fc7930b41b3';
-
--- Running upgrade 2fc7930b41b3 -> 21e526ad3040
-
-ALTER TABLE ps_globals ADD COLUMN debug VARCHAR(40);
-
-UPDATE alembic_version SET version_num='21e526ad3040';
-
--- Running upgrade 21e526ad3040 -> 28887f25a46f
-
-CREATE TABLE queues (
-    name VARCHAR(128) NOT NULL, 
-    musiconhold VARCHAR(128), 
-    announce VARCHAR(128), 
-    context VARCHAR(128), 
-    timeout INTEGER, 
-    ringinuse ENUM('yes','no'), 
-    setinterfacevar ENUM('yes','no'), 
-    setqueuevar ENUM('yes','no'), 
-    setqueueentryvar ENUM('yes','no'), 
-    monitor_format VARCHAR(8), 
-    membermacro VARCHAR(512), 
-    membergosub VARCHAR(512), 
-    queue_youarenext VARCHAR(128), 
-    queue_thereare VARCHAR(128), 
-    queue_callswaiting VARCHAR(128), 
-    queue_quantity1 VARCHAR(128), 
-    queue_quantity2 VARCHAR(128), 
-    queue_holdtime VARCHAR(128), 
-    queue_minutes VARCHAR(128), 
-    queue_minute VARCHAR(128), 
-    queue_seconds VARCHAR(128), 
-    queue_thankyou VARCHAR(128), 
-    queue_callerannounce VARCHAR(128), 
-    queue_reporthold VARCHAR(128), 
-    announce_frequency INTEGER, 
-    announce_to_first_user ENUM('yes','no'), 
-    min_announce_frequency INTEGER, 
-    announce_round_seconds INTEGER, 
-    announce_holdtime VARCHAR(128), 
-    announce_position VARCHAR(128), 
-    announce_position_limit INTEGER, 
-    periodic_announce VARCHAR(50), 
-    periodic_announce_frequency INTEGER, 
-    relative_periodic_announce ENUM('yes','no'), 
-    random_periodic_announce ENUM('yes','no'), 
-    retry INTEGER, 
-    wrapuptime INTEGER, 
-    penaltymemberslimit INTEGER, 
-    autofill ENUM('yes','no'), 
-    monitor_type VARCHAR(128), 
-    autopause ENUM('yes','no','all'), 
-    autopausedelay INTEGER, 
-    autopausebusy ENUM('yes','no'), 
-    autopauseunavail ENUM('yes','no'), 
-    maxlen INTEGER, 
-    servicelevel INTEGER, 
-    strategy ENUM('ringall','leastrecent','fewestcalls','random','rrmemory','linear','wrandom','rrordered'), 
-    joinempty VARCHAR(128), 
-    leavewhenempty VARCHAR(128), 
-    reportholdtime ENUM('yes','no'), 
-    memberdelay INTEGER, 
-    weight INTEGER, 
-    timeoutrestart ENUM('yes','no'), 
-    defaultrule VARCHAR(128), 
-    timeoutpriority VARCHAR(128), 
-    PRIMARY KEY (name)
-);
-
-CREATE TABLE queue_members (
-    queue_name VARCHAR(80) NOT NULL, 
-    interface VARCHAR(80) NOT NULL, 
-    uniqueid VARCHAR(80) NOT NULL, 
-    membername VARCHAR(80), 
-    state_interface VARCHAR(80), 
-    penalty INTEGER, 
-    paused INTEGER, 
-    PRIMARY KEY (queue_name, interface)
-);
-
-UPDATE alembic_version SET version_num='28887f25a46f';
-
--- Running upgrade 28887f25a46f -> 4c573e7135bd
-
-ALTER TABLE ps_endpoints CHANGE tos_audio tos_audio VARCHAR(10) NULL;
-
-ALTER TABLE ps_endpoints CHANGE tos_video tos_video VARCHAR(10) NULL;
-
-ALTER TABLE ps_transports CHANGE tos tos VARCHAR(10) NULL;
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_audio;
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_video;
-
-ALTER TABLE ps_transports DROP COLUMN cos;
-
-ALTER TABLE ps_endpoints ADD COLUMN cos_audio INTEGER;
-
-ALTER TABLE ps_endpoints ADD COLUMN cos_video INTEGER;
-
-ALTER TABLE ps_transports ADD COLUMN cos INTEGER;
-
-UPDATE alembic_version SET version_num='4c573e7135bd';
-
--- Running upgrade 4c573e7135bd -> 3855ee4e5f85
-
-ALTER TABLE ps_endpoints ADD COLUMN message_context VARCHAR(40);
-
-ALTER TABLE ps_contacts ADD COLUMN user_agent VARCHAR(40);
-
-UPDATE alembic_version SET version_num='3855ee4e5f85';
-
--- Running upgrade 3855ee4e5f85 -> e96a0b8071c
-
-ALTER TABLE ps_globals CHANGE user_agent user_agent VARCHAR(255) NULL;
-
-ALTER TABLE ps_contacts CHANGE id id VARCHAR(255) NULL;
-
-ALTER TABLE ps_contacts CHANGE uri uri VARCHAR(255) NULL;
-
-ALTER TABLE ps_contacts CHANGE user_agent user_agent VARCHAR(255) NULL;
-
-ALTER TABLE ps_registrations CHANGE client_uri client_uri VARCHAR(255) NULL;
-
-ALTER TABLE ps_registrations CHANGE server_uri server_uri VARCHAR(255) NULL;
-
-UPDATE alembic_version SET version_num='e96a0b8071c';
-
--- Running upgrade e96a0b8071c -> c6d929b23a8
-
-CREATE TABLE ps_subscription_persistence (
-    id VARCHAR(40) NOT NULL, 
-    packet VARCHAR(2048), 
-    src_name VARCHAR(128), 
-    src_port INTEGER, 
-    transport_key VARCHAR(64), 
-    local_name VARCHAR(128), 
-    local_port INTEGER, 
-    cseq INTEGER, 
-    tag VARCHAR(128), 
-    endpoint VARCHAR(40), 
-    expires INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_subscription_persistence_id ON ps_subscription_persistence (id);
-
-UPDATE alembic_version SET version_num='c6d929b23a8';
-
--- Running upgrade c6d929b23a8 -> 51f8cb66540e
-
-ALTER TABLE ps_endpoints ADD COLUMN force_avp ENUM('yes','no');
-
-ALTER TABLE ps_endpoints ADD COLUMN media_use_received_transport ENUM('yes','no');
-
-UPDATE alembic_version SET version_num='51f8cb66540e';
-
--- Running upgrade 51f8cb66540e -> 1d50859ed02e
-
-ALTER TABLE ps_endpoints ADD COLUMN accountcode VARCHAR(20);
-
-UPDATE alembic_version SET version_num='1d50859ed02e';
-
--- Running upgrade 1d50859ed02e -> 1758e8bbf6b
-
-ALTER TABLE sippeers CHANGE useragent useragent VARCHAR(255) NULL;
-
-UPDATE alembic_version SET version_num='1758e8bbf6b';
-
--- Running upgrade 1758e8bbf6b -> 5139253c0423
-
-ALTER TABLE queue_members DROP COLUMN uniqueid;
-
-ALTER TABLE queue_members ADD COLUMN uniqueid INTEGER NOT NULL;
-
-ALTER TABLE queue_members ADD UNIQUE (uniqueid);
-
-ALTER TABLE queue_members CHANGE uniqueid uniqueid INTEGER NOT NULL AUTO_INCREMENT;
-
-UPDATE alembic_version SET version_num='5139253c0423';
-
--- Running upgrade 5139253c0423 -> d39508cb8d8
-
-CREATE TABLE queue_rules (
-    rule_name VARCHAR(80) NOT NULL, 
-    time VARCHAR(32) NOT NULL, 
-    min_penalty VARCHAR(32) NOT NULL, 
-    max_penalty VARCHAR(32) NOT NULL
-);
-
-UPDATE alembic_version SET version_num='d39508cb8d8';
-
--- Running upgrade d39508cb8d8 -> 5950038a6ead
-
-ALTER TABLE ps_transports CHANGE verifiy_server verify_server ENUM('yes','no') NULL;
-
-UPDATE alembic_version SET version_num='5950038a6ead';
-
--- Running upgrade 5950038a6ead -> 10aedae86a32
-
-ALTER TABLE sippeers CHANGE directmedia directmedia ENUM('yes','no','nonat','update','outgoing') NULL;
-
-UPDATE alembic_version SET version_num='10aedae86a32';
-
--- Running upgrade 10aedae86a32 -> eb88a14f2a
-
-ALTER TABLE ps_endpoints ADD COLUMN media_encryption_optimistic ENUM('yes','no');
-
-UPDATE alembic_version SET version_num='eb88a14f2a';
-
diff --git a/contrib/realtime/mysql/mysql_voicemail.sql b/contrib/realtime/mysql/mysql_voicemail.sql
deleted file mode 100644
index ff5b620..0000000
--- a/contrib/realtime/mysql/mysql_voicemail.sql
+++ /dev/null
@@ -1,34 +0,0 @@
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> a2e9769475e
-
-CREATE TABLE voicemail_messages (
-    dir VARCHAR(255) NOT NULL, 
-    msgnum INTEGER NOT NULL, 
-    context VARCHAR(80), 
-    macrocontext VARCHAR(80), 
-    callerid VARCHAR(80), 
-    origtime INTEGER, 
-    duration INTEGER, 
-    recording BLOB, 
-    flag VARCHAR(30), 
-    category VARCHAR(30), 
-    mailboxuser VARCHAR(30), 
-    mailboxcontext VARCHAR(30), 
-    msg_id VARCHAR(40)
-);
-
-ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
-
-CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
-
-INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
-
--- Running upgrade a2e9769475e -> 39428242f7f5
-
-ALTER TABLE voicemail_messages CHANGE recording recording BLOB(4294967295) NULL;
-
-UPDATE alembic_version SET version_num='39428242f7f5';
-
diff --git a/contrib/realtime/mysql/queue_log.sql b/contrib/realtime/mysql/queue_log.sql
new file mode 100644
index 0000000..bc95e85
--- /dev/null
+++ b/contrib/realtime/mysql/queue_log.sql
@@ -0,0 +1,24 @@
+CREATE TABLE queue_log (
+	-- Event date and time
+	time datetime,
+	-- "REALTIME", "NONE", or channel uniqueid
+	callid char(50),
+	-- Name of the queue affected
+	queuename char(50),
+	-- Interface name of the queue member
+	agent char(50),
+	-- One of ADDMEMBER, REMOVEMEMBER, RINGNOANSWER, EXITEMPTY, TRANSFER,
+	-- AGENTDUMP, ABANDON, SYSCOMPAT, CONNECT, COMPLETECALLER, COMPLETEAGENT,
+	-- PAUSEALL, UNPAUSEALL, PAUSE, UNPAUSE, PENALTY, ENTERQUEUE,
+	-- EXITWITHTIMEOUT, EXITEMPTY, EXITWITHKEY, or another defined by the user.
+	event char(20),
+	-- data1 through data5 are possible arguments to the event, the definitions
+	-- of which are dependent upon the type of event.
+	data1 char(50),
+	data2 char(50),
+	data3 char(50),
+	data4 char(50),
+	data5 char(50),
+	index bydate (time),
+	index qname (queuename,time)
+);
diff --git a/contrib/realtime/mysql/sippeers.sql b/contrib/realtime/mysql/sippeers.sql
new file mode 100644
index 0000000..902cd45
--- /dev/null
+++ b/contrib/realtime/mysql/sippeers.sql
@@ -0,0 +1,97 @@
+#
+# Table structure for table `sippeers`
+#
+
+CREATE TABLE IF NOT EXISTS `sippeers` (
+      `id` int(11) NOT NULL AUTO_INCREMENT,
+      `name` varchar(10) NOT NULL,
+      `ipaddr` varchar(45) DEFAULT NULL,
+      `port` int(5) DEFAULT NULL,
+      `regseconds` int(11) DEFAULT NULL,
+      `defaultuser` varchar(10) DEFAULT NULL,
+      `fullcontact` varchar(80) DEFAULT NULL,
+      `regserver` varchar(20) DEFAULT NULL,
+      `useragent` varchar(20) DEFAULT NULL,
+      `lastms` int(11) DEFAULT NULL,
+      `host` varchar(40) DEFAULT NULL,
+      `type` enum('friend','user','peer') DEFAULT NULL,
+      `context` varchar(40) DEFAULT NULL,
+      `permit` varchar(95) DEFAULT NULL,
+      `deny` varchar(95) DEFAULT NULL,
+      `secret` varchar(40) DEFAULT NULL,
+      `md5secret` varchar(40) DEFAULT NULL,
+      `remotesecret` varchar(40) DEFAULT NULL,
+      `transport` enum('udp','tcp','udp,tcp','tcp,udp') DEFAULT NULL,
+      `dtmfmode` enum('rfc2833','info','shortinfo','inband','auto') DEFAULT NULL,
+      `directmedia` enum('yes','no','nonat','update') DEFAULT NULL,
+      `nat` varchar(29) DEFAULT NULL,
+      `callgroup` varchar(40) DEFAULT NULL,
+      `pickupgroup` varchar(40) DEFAULT NULL,
+      `language` varchar(40) DEFAULT NULL,
+      `disallow` varchar(40) DEFAULT NULL,
+      `allow` varchar(40) DEFAULT NULL,
+      `insecure` varchar(40) DEFAULT NULL,
+      `trustrpid` enum('yes','no') DEFAULT NULL,
+      `progressinband` enum('yes','no','never') DEFAULT NULL,
+      `promiscredir` enum('yes','no') DEFAULT NULL,
+      `useclientcode` enum('yes','no') DEFAULT NULL,
+      `accountcode` varchar(40) DEFAULT NULL,
+      `setvar` varchar(40) DEFAULT NULL,
+      `callerid` varchar(40) DEFAULT NULL,
+      `amaflags` varchar(40) DEFAULT NULL,
+      `callcounter` enum('yes','no') DEFAULT NULL,
+      `busylevel` int(11) DEFAULT NULL,
+      `allowoverlap` enum('yes','no') DEFAULT NULL,
+      `allowsubscribe` enum('yes','no') DEFAULT NULL,
+      `videosupport` enum('yes','no') DEFAULT NULL,
+      `maxcallbitrate` int(11) DEFAULT NULL,
+      `rfc2833compensate` enum('yes','no') DEFAULT NULL,
+      `mailbox` varchar(40) DEFAULT NULL,
+      `session-timers` enum('accept','refuse','originate') DEFAULT NULL,
+      `session-expires` int(11) DEFAULT NULL,
+      `session-minse` int(11) DEFAULT NULL,
+      `session-refresher` enum('uac','uas') DEFAULT NULL,
+      `t38pt_usertpsource` varchar(40) DEFAULT NULL,
+      `regexten` varchar(40) DEFAULT NULL,
+      `fromdomain` varchar(40) DEFAULT NULL,
+      `fromuser` varchar(40) DEFAULT NULL,
+      `qualify` varchar(40) DEFAULT NULL,
+      `defaultip` varchar(45) DEFAULT NULL,
+      `rtptimeout` int(11) DEFAULT NULL,
+      `rtpholdtimeout` int(11) DEFAULT NULL,
+      `sendrpid` enum('yes','no') DEFAULT NULL,
+      `outboundproxy` varchar(40) DEFAULT NULL,
+      `callbackextension` varchar(40) DEFAULT NULL,
+      `timert1` int(11) DEFAULT NULL,
+      `timerb` int(11) DEFAULT NULL,
+      `qualifyfreq` int(11) DEFAULT NULL,
+      `constantssrc` enum('yes','no') DEFAULT NULL,
+      `contactpermit` varchar(95) DEFAULT NULL,
+      `contactdeny` varchar(95) DEFAULT NULL,
+      `usereqphone` enum('yes','no') DEFAULT NULL,
+      `textsupport` enum('yes','no') DEFAULT NULL,
+      `faxdetect` enum('yes','no') DEFAULT NULL,
+      `buggymwi` enum('yes','no') DEFAULT NULL,
+      `auth` varchar(40) DEFAULT NULL,
+      `fullname` varchar(40) DEFAULT NULL,
+      `trunkname` varchar(40) DEFAULT NULL,
+      `cid_number` varchar(40) DEFAULT NULL,
+      `callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib') DEFAULT NULL,
+      `mohinterpret` varchar(40) DEFAULT NULL,
+      `mohsuggest` varchar(40) DEFAULT NULL,
+      `parkinglot` varchar(40) DEFAULT NULL,
+      `hasvoicemail` enum('yes','no') DEFAULT NULL,
+      `subscribemwi` enum('yes','no') DEFAULT NULL,
+      `vmexten` varchar(40) DEFAULT NULL,
+      `autoframing` enum('yes','no') DEFAULT NULL,
+      `rtpkeepalive` int(11) DEFAULT NULL,
+      `call-limit` int(11) DEFAULT NULL,
+      `g726nonstandard` enum('yes','no') DEFAULT NULL,
+      `ignoresdpversion` enum('yes','no') DEFAULT NULL,
+      `allowtransfer` enum('yes','no') DEFAULT NULL,
+      `dynamic` enum('yes','no') DEFAULT NULL,
+      PRIMARY KEY (`id`),
+      UNIQUE KEY `name` (`name`),
+      KEY `ipaddr` (`ipaddr`,`port`),
+      KEY `host` (`host`,`port`)
+) ENGINE=MyISAM;
diff --git a/contrib/realtime/mysql/voicemail.sql b/contrib/realtime/mysql/voicemail.sql
new file mode 100644
index 0000000..bd924f4
--- /dev/null
+++ b/contrib/realtime/mysql/voicemail.sql
@@ -0,0 +1,70 @@
+DROP TABLE IF EXISTS voicemail;
+CREATE TABLE voicemail (
+	-- All of these column names are very specific, including "uniqueid".  Do not change them if you wish voicemail to work.
+	uniqueid INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+	-- Mailbox context.
+	context CHAR(80) NOT NULL DEFAULT 'default',
+	-- Mailbox number.  Should be numeric.
+	mailbox CHAR(80) NOT NULL,
+	-- Must be numeric.  Negative if you don't want it to be changed from VoicemailMain
+	password CHAR(80) NOT NULL,
+	-- Used in email and for Directory app
+	fullname CHAR(80),
+	-- Email address (will get sound file if attach=yes)
+	email CHAR(80),
+	-- Email address (won't get sound file)
+	pager CHAR(80),
+	-- Attach sound file to email - YES/no
+	attach CHAR(3),
+	-- Which sound format to attach
+	attachfmt CHAR(10),
+	-- Send email from this address
+	serveremail CHAR(80),
+	-- Prompts in alternative language
+	language CHAR(20),
+	-- Alternative timezone, as defined in voicemail.conf
+	tz CHAR(30),
+	-- Delete voicemail from server after sending email notification - yes/NO
+	deletevoicemail CHAR(3),
+	-- Read back CallerID information during playback - yes/NO
+	saycid CHAR(3),
+	-- Allow user to send voicemail from within VoicemailMain - YES/no
+	sendvoicemail CHAR(3),
+	-- Listen to voicemail and approve before sending - yes/NO
+	review CHAR(3),
+	-- Warn user a temporary greeting exists - yes/NO
+	tempgreetwarn CHAR(3),
+	-- Allow '0' to jump out during greeting - yes/NO
+	operator CHAR(3),
+	-- Hear date/time of message within VoicemailMain - YES/no
+	envelope CHAR(3),
+	-- Hear length of message within VoicemailMain - yes/NO
+	sayduration CHAR(3),
+	-- Minimum duration in minutes to say
+	saydurationm INT(3),
+	-- Force new user to record name when entering voicemail - yes/NO
+	forcename CHAR(3),
+	-- Force new user to record greetings when entering voicemail - yes/NO
+	forcegreetings CHAR(3),
+	-- Context in which to dial extension for callback
+	callback CHAR(80),
+	-- Context in which to dial extension (from advanced menu)
+	dialout CHAR(80),
+	-- Context in which to execute 0 or * escape during greeting
+	exitcontext CHAR(80),
+	-- Maximum messages in a folder (100 if not specified)
+	maxmsg INT(5),
+	-- Increase DB gain on recorded message by this amount (0.0 means none)
+	volgain DECIMAL(5,2),
+	-- IMAP user for authentication (if using IMAP storage)
+	imapuser VARCHAR(80),
+	-- IMAP password for authentication (if using IMAP storage)
+	imappassword VARCHAR(80),
+	-- IMAP server location (if using IMAP storage)
+	imapsever VARCHAR(80),
+	-- IMAP port (if using IMAP storage)
+	imapport VARCHAR(8),
+	-- IMAP flags (if using IMAP storage)
+	imapflags VARCHAR(80),
+	stamp timestamp
+);
diff --git a/contrib/realtime/mysql/voicemail_data.sql b/contrib/realtime/mysql/voicemail_data.sql
new file mode 100644
index 0000000..743bd44
--- /dev/null
+++ b/contrib/realtime/mysql/voicemail_data.sql
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS voicemail_data;
+CREATE TABLE voicemail_data (
+	-- Path to the recording
+	filename CHAR(255) NOT NULL PRIMARY KEY,
+	-- Mailbox number (without context)
+	origmailbox CHAR(80),
+	-- Dialplan context
+	context CHAR(80),
+	-- Dialplan context, if voicemail was invoked from a macro
+	macrocontext CHAR(80),
+	-- Dialplan extension
+	exten CHAR(80),
+	-- Dialplan priority
+	priority INT(5),
+	-- Name of the channel, when message was left
+	callerchan CHAR(80),
+	-- CallerID on the channel, when message was left
+	callerid CHAR(80),
+	-- Contrary to the name, origdate is a full datetime, in localized format
+	origdate CHAR(30),
+	-- Same date as origdate, but in Unixtime
+	origtime INT(11),
+	-- Value of the channel variable VM_CATEGORY, if set
+	category CHAR(30),
+	-- Length of the message, in seconds
+	duration INT(11)
+);
+
+
diff --git a/contrib/realtime/mysql/voicemail_messages.sql b/contrib/realtime/mysql/voicemail_messages.sql
new file mode 100644
index 0000000..7290a9a
--- /dev/null
+++ b/contrib/realtime/mysql/voicemail_messages.sql
@@ -0,0 +1,31 @@
+-- While this does not use the realtime backend, for brevity, we include this table here, as well.
+DROP TABLE IF EXISTS voicemail_messages;
+CREATE TABLE voicemail_messages (
+	-- Logical directory
+	dir CHAR(255),
+	-- Message number within the logical directory
+	msgnum INT(4),
+	-- Dialplan context
+	context CHAR(80),
+	-- Dialplan context, if Voicemail was invoked from a macro
+	macrocontext CHAR(80),
+	-- CallerID, when the message was left
+	callerid CHAR(80),
+	-- Date when the message was left, in Unixtime
+	origtime INT(11),
+	-- Length of the message, in seconds
+	duration INT(11),
+	-- The recording itself
+	recording BLOB,
+	-- Text flags indicating urgency of the message
+	flag CHAR(30),
+	-- Value of channel variable VM_CATEGORY, if set
+	category CHAR(30),
+	-- Owner of the mailbox
+	mailboxuser CHAR(30),
+	-- Context of the owner of the mailbox
+	mailboxcontext CHAR(30),
+	-- Unique ID of the message,
+	msg_id char(40),
+	PRIMARY KEY (dir, msgnum)
+);
diff --git a/contrib/realtime/oracle/oracle_cdr.sql b/contrib/realtime/oracle/oracle_cdr.sql
deleted file mode 100644
index 66302fc..0000000
--- a/contrib/realtime/oracle/oracle_cdr.sql
+++ /dev/null
@@ -1,46 +0,0 @@
-SET TRANSACTION READ WRITE
-
-/
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR2(32 CHAR) NOT NULL
-)
-
-/
-
--- Running upgrade None -> 210693f3123d
-
-CREATE TABLE cdr (
-    accountcode VARCHAR2(20 CHAR), 
-    src VARCHAR2(80 CHAR), 
-    dst VARCHAR2(80 CHAR), 
-    dcontext VARCHAR2(80 CHAR), 
-    clid VARCHAR2(80 CHAR), 
-    channel VARCHAR2(80 CHAR), 
-    dstchannel VARCHAR2(80 CHAR), 
-    lastapp VARCHAR2(80 CHAR), 
-    lastdata VARCHAR2(80 CHAR), 
-    "start" DATE, 
-    answer DATE, 
-    end DATE, 
-    duration INTEGER, 
-    billsec INTEGER, 
-    disposition VARCHAR2(45 CHAR), 
-    amaflags VARCHAR2(45 CHAR), 
-    userfield VARCHAR2(256 CHAR), 
-    uniqueid VARCHAR2(150 CHAR), 
-    linkedid VARCHAR2(150 CHAR), 
-    peeraccount VARCHAR2(20 CHAR), 
-    sequence INTEGER
-)
-
-/
-
-INSERT INTO alembic_version (version_num) VALUES ('210693f3123d')
-
-/
-
-COMMIT
-
-/
-
diff --git a/contrib/realtime/oracle/oracle_config.sql b/contrib/realtime/oracle/oracle_config.sql
deleted file mode 100644
index ff6f7d0..0000000
--- a/contrib/realtime/oracle/oracle_config.sql
+++ /dev/null
@@ -1,994 +0,0 @@
-SET TRANSACTION READ WRITE
-
-/
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR2(32 CHAR) NOT NULL
-)
-
-/
-
--- Running upgrade None -> 4da0c5f79a9c
-
-CREATE TABLE sippeers (
-    id INTEGER NOT NULL, 
-    name VARCHAR2(40 CHAR) NOT NULL, 
-    ipaddr VARCHAR2(45 CHAR), 
-    port INTEGER, 
-    regseconds INTEGER, 
-    defaultuser VARCHAR2(40 CHAR), 
-    fullcontact VARCHAR2(80 CHAR), 
-    regserver VARCHAR2(20 CHAR), 
-    useragent VARCHAR2(20 CHAR), 
-    lastms INTEGER, 
-    host VARCHAR2(40 CHAR), 
-    type VARCHAR(6 CHAR), 
-    context VARCHAR2(40 CHAR), 
-    permit VARCHAR2(95 CHAR), 
-    deny VARCHAR2(95 CHAR), 
-    secret VARCHAR2(40 CHAR), 
-    md5secret VARCHAR2(40 CHAR), 
-    remotesecret VARCHAR2(40 CHAR), 
-    transport VARCHAR(7 CHAR), 
-    dtmfmode VARCHAR(9 CHAR), 
-    directmedia VARCHAR(6 CHAR), 
-    nat VARCHAR2(29 CHAR), 
-    callgroup VARCHAR2(40 CHAR), 
-    pickupgroup VARCHAR2(40 CHAR), 
-    language VARCHAR2(40 CHAR), 
-    disallow VARCHAR2(200 CHAR), 
-    allow VARCHAR2(200 CHAR), 
-    insecure VARCHAR2(40 CHAR), 
-    trustrpid VARCHAR(3 CHAR), 
-    progressinband VARCHAR(5 CHAR), 
-    promiscredir VARCHAR(3 CHAR), 
-    useclientcode VARCHAR(3 CHAR), 
-    accountcode VARCHAR2(40 CHAR), 
-    setvar VARCHAR2(200 CHAR), 
-    callerid VARCHAR2(40 CHAR), 
-    amaflags VARCHAR2(40 CHAR), 
-    callcounter VARCHAR(3 CHAR), 
-    busylevel INTEGER, 
-    allowoverlap VARCHAR(3 CHAR), 
-    allowsubscribe VARCHAR(3 CHAR), 
-    videosupport VARCHAR(3 CHAR), 
-    maxcallbitrate INTEGER, 
-    rfc2833compensate VARCHAR(3 CHAR), 
-    mailbox VARCHAR2(40 CHAR), 
-    "session-timers" VARCHAR(9 CHAR), 
-    "session-expires" INTEGER, 
-    "session-minse" INTEGER, 
-    "session-refresher" VARCHAR(3 CHAR), 
-    t38pt_usertpsource VARCHAR2(40 CHAR), 
-    regexten VARCHAR2(40 CHAR), 
-    fromdomain VARCHAR2(40 CHAR), 
-    fromuser VARCHAR2(40 CHAR), 
-    qualify VARCHAR2(40 CHAR), 
-    defaultip VARCHAR2(45 CHAR), 
-    rtptimeout INTEGER, 
-    rtpholdtimeout INTEGER, 
-    sendrpid VARCHAR(3 CHAR), 
-    outboundproxy VARCHAR2(40 CHAR), 
-    callbackextension VARCHAR2(40 CHAR), 
-    timert1 INTEGER, 
-    timerb INTEGER, 
-    qualifyfreq INTEGER, 
-    constantssrc VARCHAR(3 CHAR), 
-    contactpermit VARCHAR2(95 CHAR), 
-    contactdeny VARCHAR2(95 CHAR), 
-    usereqphone VARCHAR(3 CHAR), 
-    textsupport VARCHAR(3 CHAR), 
-    faxdetect VARCHAR(3 CHAR), 
-    buggymwi VARCHAR(3 CHAR), 
-    auth VARCHAR2(40 CHAR), 
-    fullname VARCHAR2(40 CHAR), 
-    trunkname VARCHAR2(40 CHAR), 
-    cid_number VARCHAR2(40 CHAR), 
-    callingpres VARCHAR(21 CHAR), 
-    mohinterpret VARCHAR2(40 CHAR), 
-    mohsuggest VARCHAR2(40 CHAR), 
-    parkinglot VARCHAR2(40 CHAR), 
-    hasvoicemail VARCHAR(3 CHAR), 
-    subscribemwi VARCHAR(3 CHAR), 
-    vmexten VARCHAR2(40 CHAR), 
-    autoframing VARCHAR(3 CHAR), 
-    rtpkeepalive INTEGER, 
-    "call-limit" INTEGER, 
-    g726nonstandard VARCHAR(3 CHAR), 
-    ignoresdpversion VARCHAR(3 CHAR), 
-    allowtransfer VARCHAR(3 CHAR), 
-    dynamic VARCHAR(3 CHAR), 
-    path VARCHAR2(256 CHAR), 
-    supportpath VARCHAR(3 CHAR), 
-    PRIMARY KEY (id), 
-    UNIQUE (name), 
-    CONSTRAINT type_values CHECK (type IN ('friend', 'user', 'peer')), 
-    CONSTRAINT sip_transport_values CHECK (transport IN ('udp', 'tcp', 'tls', 'ws', 'wss', 'udp,tcp', 'tcp,udp')), 
-    CONSTRAINT sip_dtmfmode_values CHECK (dtmfmode IN ('rfc2833', 'info', 'shortinfo', 'inband', 'auto')), 
-    CONSTRAINT sip_directmedia_values CHECK (directmedia IN ('yes', 'no', 'nonat', 'update')), 
-    CONSTRAINT yes_no_values CHECK (trustrpid IN ('yes', 'no')), 
-    CONSTRAINT sip_progressinband_values CHECK (progressinband IN ('yes', 'no', 'never')), 
-    CONSTRAINT yes_no_values CHECK (promiscredir IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (useclientcode IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (callcounter IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowoverlap IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowsubscribe IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (videosupport IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (rfc2833compensate IN ('yes', 'no')), 
-    CONSTRAINT sip_session_timers_values CHECK ("session-timers" IN ('accept', 'refuse', 'originate')), 
-    CONSTRAINT sip_session_refresher_values CHECK ("session-refresher" IN ('uac', 'uas')), 
-    CONSTRAINT yes_no_values CHECK (sendrpid IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (constantssrc IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (usereqphone IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (textsupport IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (faxdetect IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (buggymwi IN ('yes', 'no')), 
-    CONSTRAINT sip_callingpres_values CHECK (callingpres IN ('allowed_not_screened', 'allowed_passed_screen', 'allowed_failed_screen', 'allowed', 'prohib_not_screened', 'prohib_passed_screen', 'prohib_failed_screen', 'prohib')), 
-    CONSTRAINT yes_no_values CHECK (hasvoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (subscribemwi IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (autoframing IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (g726nonstandard IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (ignoresdpversion IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowtransfer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (dynamic IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (supportpath IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX sippeers_name ON sippeers (name)
-
-/
-
-CREATE INDEX sippeers_name_host ON sippeers (name, host)
-
-/
-
-CREATE INDEX sippeers_ipaddr_port ON sippeers (ipaddr, port)
-
-/
-
-CREATE INDEX sippeers_host_port ON sippeers (host, port)
-
-/
-
-CREATE TABLE iaxfriends (
-    id INTEGER NOT NULL, 
-    name VARCHAR2(40 CHAR) NOT NULL, 
-    type VARCHAR(6 CHAR), 
-    username VARCHAR2(40 CHAR), 
-    mailbox VARCHAR2(40 CHAR), 
-    secret VARCHAR2(40 CHAR), 
-    dbsecret VARCHAR2(40 CHAR), 
-    context VARCHAR2(40 CHAR), 
-    regcontext VARCHAR2(40 CHAR), 
-    host VARCHAR2(40 CHAR), 
-    ipaddr VARCHAR2(40 CHAR), 
-    port INTEGER, 
-    defaultip VARCHAR2(20 CHAR), 
-    sourceaddress VARCHAR2(20 CHAR), 
-    mask VARCHAR2(20 CHAR), 
-    regexten VARCHAR2(40 CHAR), 
-    regseconds INTEGER, 
-    accountcode VARCHAR2(20 CHAR), 
-    mohinterpret VARCHAR2(20 CHAR), 
-    mohsuggest VARCHAR2(20 CHAR), 
-    inkeys VARCHAR2(40 CHAR), 
-    outkeys VARCHAR2(40 CHAR), 
-    language VARCHAR2(10 CHAR), 
-    callerid VARCHAR2(100 CHAR), 
-    cid_number VARCHAR2(40 CHAR), 
-    sendani VARCHAR(3 CHAR), 
-    fullname VARCHAR2(40 CHAR), 
-    trunk VARCHAR(3 CHAR), 
-    auth VARCHAR2(20 CHAR), 
-    maxauthreq INTEGER, 
-    requirecalltoken VARCHAR(4 CHAR), 
-    encryption VARCHAR(6 CHAR), 
-    transfer VARCHAR(9 CHAR), 
-    jitterbuffer VARCHAR(3 CHAR), 
-    forcejitterbuffer VARCHAR(3 CHAR), 
-    disallow VARCHAR2(200 CHAR), 
-    allow VARCHAR2(200 CHAR), 
-    codecpriority VARCHAR2(40 CHAR), 
-    qualify VARCHAR2(10 CHAR), 
-    qualifysmoothing VARCHAR(3 CHAR), 
-    qualifyfreqok VARCHAR2(10 CHAR), 
-    qualifyfreqnotok VARCHAR2(10 CHAR), 
-    timezone VARCHAR2(20 CHAR), 
-    adsi VARCHAR(3 CHAR), 
-    amaflags VARCHAR2(20 CHAR), 
-    setvar VARCHAR2(200 CHAR), 
-    PRIMARY KEY (id), 
-    UNIQUE (name), 
-    CONSTRAINT type_values CHECK (type IN ('friend', 'user', 'peer')), 
-    CONSTRAINT yes_no_values CHECK (sendani IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (trunk IN ('yes', 'no')), 
-    CONSTRAINT iax_requirecalltoken_values CHECK (requirecalltoken IN ('yes', 'no', 'auto')), 
-    CONSTRAINT iax_encryption_values CHECK (encryption IN ('yes', 'no', 'aes128')), 
-    CONSTRAINT iax_transfer_values CHECK (transfer IN ('yes', 'no', 'mediaonly')), 
-    CONSTRAINT yes_no_values CHECK (jitterbuffer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcejitterbuffer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (qualifysmoothing IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (adsi IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX iaxfriends_name ON iaxfriends (name)
-
-/
-
-CREATE INDEX iaxfriends_name_host ON iaxfriends (name, host)
-
-/
-
-CREATE INDEX iaxfriends_name_ipaddr_port ON iaxfriends (name, ipaddr, port)
-
-/
-
-CREATE INDEX iaxfriends_ipaddr_port ON iaxfriends (ipaddr, port)
-
-/
-
-CREATE INDEX iaxfriends_host_port ON iaxfriends (host, port)
-
-/
-
-CREATE TABLE voicemail (
-    uniqueid INTEGER NOT NULL, 
-    context VARCHAR2(80 CHAR) NOT NULL, 
-    mailbox VARCHAR2(80 CHAR) NOT NULL, 
-    password VARCHAR2(80 CHAR) NOT NULL, 
-    fullname VARCHAR2(80 CHAR), 
-    alias VARCHAR2(80 CHAR), 
-    email VARCHAR2(80 CHAR), 
-    pager VARCHAR2(80 CHAR), 
-    attach VARCHAR(3 CHAR), 
-    attachfmt VARCHAR2(10 CHAR), 
-    serveremail VARCHAR2(80 CHAR), 
-    language VARCHAR2(20 CHAR), 
-    tz VARCHAR2(30 CHAR), 
-    deletevoicemail VARCHAR(3 CHAR), 
-    saycid VARCHAR(3 CHAR), 
-    sendvoicemail VARCHAR(3 CHAR), 
-    review VARCHAR(3 CHAR), 
-    tempgreetwarn VARCHAR(3 CHAR), 
-    operator VARCHAR(3 CHAR), 
-    envelope VARCHAR(3 CHAR), 
-    sayduration INTEGER, 
-    forcename VARCHAR(3 CHAR), 
-    forcegreetings VARCHAR(3 CHAR), 
-    callback VARCHAR2(80 CHAR), 
-    dialout VARCHAR2(80 CHAR), 
-    exitcontext VARCHAR2(80 CHAR), 
-    maxmsg INTEGER, 
-    volgain NUMERIC(5, 2), 
-    imapuser VARCHAR2(80 CHAR), 
-    imappassword VARCHAR2(80 CHAR), 
-    imapserver VARCHAR2(80 CHAR), 
-    imapport VARCHAR2(8 CHAR), 
-    imapflags VARCHAR2(80 CHAR), 
-    stamp DATE, 
-    PRIMARY KEY (uniqueid), 
-    CONSTRAINT yes_no_values CHECK (attach IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (deletevoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (saycid IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (sendvoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (review IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (tempgreetwarn IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (operator IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (envelope IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcename IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcegreetings IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX voicemail_mailbox ON voicemail (mailbox)
-
-/
-
-CREATE INDEX voicemail_context ON voicemail (context)
-
-/
-
-CREATE INDEX voicemail_mailbox_context ON voicemail (mailbox, context)
-
-/
-
-CREATE INDEX voicemail_imapuser ON voicemail (imapuser)
-
-/
-
-CREATE TABLE meetme (
-    bookid INTEGER NOT NULL, 
-    confno VARCHAR2(80 CHAR) NOT NULL, 
-    starttime DATE, 
-    endtime DATE, 
-    pin VARCHAR2(20 CHAR), 
-    adminpin VARCHAR2(20 CHAR), 
-    opts VARCHAR2(20 CHAR), 
-    adminopts VARCHAR2(20 CHAR), 
-    recordingfilename VARCHAR2(80 CHAR), 
-    recordingformat VARCHAR2(10 CHAR), 
-    maxusers INTEGER, 
-    members INTEGER NOT NULL, 
-    PRIMARY KEY (bookid)
-)
-
-/
-
-CREATE INDEX meetme_confno_start_end ON meetme (confno, starttime, endtime)
-
-/
-
-CREATE TABLE musiconhold (
-    name VARCHAR2(80 CHAR) NOT NULL, 
-    "mode" VARCHAR(10 CHAR), 
-    directory VARCHAR2(255 CHAR), 
-    application VARCHAR2(255 CHAR), 
-    digit VARCHAR2(1 CHAR), 
-    sort VARCHAR2(10 CHAR), 
-    format VARCHAR2(10 CHAR), 
-    stamp DATE, 
-    PRIMARY KEY (name), 
-    CONSTRAINT moh_mode_values CHECK ("mode" IN ('custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3'))
-)
-
-/
-
--- Running upgrade 4da0c5f79a9c -> 43956d550a44
-
-CREATE TABLE ps_endpoints (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    transport VARCHAR2(40 CHAR), 
-    aors VARCHAR2(200 CHAR), 
-    auth VARCHAR2(40 CHAR), 
-    context VARCHAR2(40 CHAR), 
-    disallow VARCHAR2(200 CHAR), 
-    allow VARCHAR2(200 CHAR), 
-    direct_media VARCHAR(3 CHAR), 
-    connected_line_method VARCHAR(8 CHAR), 
-    direct_media_method VARCHAR(8 CHAR), 
-    direct_media_glare_mitigation VARCHAR(8 CHAR), 
-    disable_direct_media_on_nat VARCHAR(3 CHAR), 
-    dtmf_mode VARCHAR(7 CHAR), 
-    external_media_address VARCHAR2(40 CHAR), 
-    force_rport VARCHAR(3 CHAR), 
-    ice_support VARCHAR(3 CHAR), 
-    identify_by VARCHAR(8 CHAR), 
-    mailboxes VARCHAR2(40 CHAR), 
-    moh_suggest VARCHAR2(40 CHAR), 
-    outbound_auth VARCHAR2(40 CHAR), 
-    outbound_proxy VARCHAR2(40 CHAR), 
-    rewrite_contact VARCHAR(3 CHAR), 
-    rtp_ipv6 VARCHAR(3 CHAR), 
-    rtp_symmetric VARCHAR(3 CHAR), 
-    send_diversion VARCHAR(3 CHAR), 
-    send_pai VARCHAR(3 CHAR), 
-    send_rpid VARCHAR(3 CHAR), 
-    timers_min_se INTEGER, 
-    timers VARCHAR(8 CHAR), 
-    timers_sess_expires INTEGER, 
-    callerid VARCHAR2(40 CHAR), 
-    callerid_privacy VARCHAR(23 CHAR), 
-    callerid_tag VARCHAR2(40 CHAR), 
-    100rel VARCHAR(8 CHAR), 
-    aggregate_mwi VARCHAR(3 CHAR), 
-    trust_id_inbound VARCHAR(3 CHAR), 
-    trust_id_outbound VARCHAR(3 CHAR), 
-    use_ptime VARCHAR(3 CHAR), 
-    use_avpf VARCHAR(3 CHAR), 
-    media_encryption VARCHAR(4 CHAR), 
-    inband_progress VARCHAR(3 CHAR), 
-    call_group VARCHAR2(40 CHAR), 
-    pickup_group VARCHAR2(40 CHAR), 
-    named_call_group VARCHAR2(40 CHAR), 
-    named_pickup_group VARCHAR2(40 CHAR), 
-    device_state_busy_at INTEGER, 
-    fax_detect VARCHAR(3 CHAR), 
-    t38_udptl VARCHAR(3 CHAR), 
-    t38_udptl_ec VARCHAR(10 CHAR), 
-    t38_udptl_maxdatagram INTEGER, 
-    t38_udptl_nat VARCHAR(3 CHAR), 
-    t38_udptl_ipv6 VARCHAR(3 CHAR), 
-    tone_zone VARCHAR2(40 CHAR), 
-    language VARCHAR2(40 CHAR), 
-    one_touch_recording VARCHAR(3 CHAR), 
-    record_on_feature VARCHAR2(40 CHAR), 
-    record_off_feature VARCHAR2(40 CHAR), 
-    rtp_engine VARCHAR2(40 CHAR), 
-    allow_transfer VARCHAR(3 CHAR), 
-    allow_subscribe VARCHAR(3 CHAR), 
-    sdp_owner VARCHAR2(40 CHAR), 
-    sdp_session VARCHAR2(40 CHAR), 
-    tos_audio INTEGER, 
-    tos_video INTEGER, 
-    cos_audio INTEGER, 
-    cos_video INTEGER, 
-    sub_min_expiry INTEGER, 
-    from_domain VARCHAR2(40 CHAR), 
-    from_user VARCHAR2(40 CHAR), 
-    mwi_fromuser VARCHAR2(40 CHAR), 
-    dtls_verify VARCHAR2(40 CHAR), 
-    dtls_rekey VARCHAR2(40 CHAR), 
-    dtls_cert_file VARCHAR2(200 CHAR), 
-    dtls_private_key VARCHAR2(200 CHAR), 
-    dtls_cipher VARCHAR2(200 CHAR), 
-    dtls_ca_file VARCHAR2(200 CHAR), 
-    dtls_ca_path VARCHAR2(200 CHAR), 
-    dtls_setup VARCHAR(7 CHAR), 
-    srtp_tag_32 VARCHAR(3 CHAR), 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (direct_media IN ('yes', 'no')), 
-    CONSTRAINT pjsip_connected_line_method_values CHECK (connected_line_method IN ('invite', 'reinvite', 'update')), 
-    CONSTRAINT pjsip_connected_line_method_values CHECK (direct_media_method IN ('invite', 'reinvite', 'update')), 
-    CONSTRAINT pjsip_direct_media_glare_mitigation_values CHECK (direct_media_glare_mitigation IN ('none', 'outgoing', 'incoming')), 
-    CONSTRAINT yesno_values CHECK (disable_direct_media_on_nat IN ('yes', 'no')), 
-    CONSTRAINT pjsip_dtmf_mode_values CHECK (dtmf_mode IN ('rfc4733', 'inband', 'info')), 
-    CONSTRAINT yesno_values CHECK (force_rport IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (ice_support IN ('yes', 'no')), 
-    CONSTRAINT pjsip_identify_by_values CHECK (identify_by IN ('username')), 
-    CONSTRAINT yesno_values CHECK (rewrite_contact IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (rtp_ipv6 IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (rtp_symmetric IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_diversion IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_pai IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_rpid IN ('yes', 'no')), 
-    CONSTRAINT pjsip_timer_values CHECK (timers IN ('forced', 'no', 'required', 'yes')), 
-    CONSTRAINT pjsip_cid_privacy_values CHECK (callerid_privacy IN ('allowed_not_screened', 'allowed_passed_screened', 'allowed_failed_screened', 'allowed', 'prohib_not_screened', 'prohib_passed_screened', 'prohib_failed_screened', 'prohib', 'unavailable')), 
-    CONSTRAINT pjsip_100rel_values CHECK (100rel IN ('no', 'required', 'yes')), 
-    CONSTRAINT yesno_values CHECK (aggregate_mwi IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (trust_id_inbound IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (trust_id_outbound IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (use_ptime IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (use_avpf IN ('yes', 'no')), 
-    CONSTRAINT pjsip_media_encryption_values CHECK (media_encryption IN ('no', 'sdes', 'dtls')), 
-    CONSTRAINT yesno_values CHECK (inband_progress IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (fax_detect IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl IN ('yes', 'no')), 
-    CONSTRAINT pjsip_t38udptl_ec_values CHECK (t38_udptl_ec IN ('none', 'fec', 'redundancy')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl_nat IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl_ipv6 IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (one_touch_recording IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (allow_transfer IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (allow_subscribe IN ('yes', 'no')), 
-    CONSTRAINT pjsip_dtls_setup_values CHECK (dtls_setup IN ('active', 'passive', 'actpass')), 
-    CONSTRAINT yesno_values CHECK (srtp_tag_32 IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX ps_endpoints_id ON ps_endpoints (id)
-
-/
-
-CREATE TABLE ps_auths (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    auth_type VARCHAR(8 CHAR), 
-    nonce_lifetime INTEGER, 
-    md5_cred VARCHAR2(40 CHAR), 
-    password VARCHAR2(80 CHAR), 
-    realm VARCHAR2(40 CHAR), 
-    username VARCHAR2(40 CHAR), 
-    UNIQUE (id), 
-    CONSTRAINT pjsip_auth_type_values CHECK (auth_type IN ('md5', 'userpass'))
-)
-
-/
-
-CREATE INDEX ps_auths_id ON ps_auths (id)
-
-/
-
-CREATE TABLE ps_aors (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    contact VARCHAR2(40 CHAR), 
-    default_expiration INTEGER, 
-    mailboxes VARCHAR2(80 CHAR), 
-    max_contacts INTEGER, 
-    minimum_expiration INTEGER, 
-    remove_existing VARCHAR(3 CHAR), 
-    qualify_frequency INTEGER, 
-    authenticate_qualify VARCHAR(3 CHAR), 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (remove_existing IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (authenticate_qualify IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX ps_aors_id ON ps_aors (id)
-
-/
-
-CREATE TABLE ps_contacts (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    uri VARCHAR2(40 CHAR), 
-    expiration_time VARCHAR2(40 CHAR), 
-    qualify_frequency INTEGER, 
-    UNIQUE (id)
-)
-
-/
-
-CREATE INDEX ps_contacts_id ON ps_contacts (id)
-
-/
-
-CREATE TABLE ps_domain_aliases (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    domain VARCHAR2(80 CHAR), 
-    UNIQUE (id)
-)
-
-/
-
-CREATE INDEX ps_domain_aliases_id ON ps_domain_aliases (id)
-
-/
-
-CREATE TABLE ps_endpoint_id_ips (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    endpoint VARCHAR2(40 CHAR), 
-    match VARCHAR2(80 CHAR), 
-    UNIQUE (id)
-)
-
-/
-
-CREATE INDEX ps_endpoint_id_ips_id ON ps_endpoint_id_ips (id)
-
-/
-
--- Running upgrade 43956d550a44 -> 581a4264e537
-
-CREATE TABLE extensions (
-    id NUMBER(19) NOT NULL, 
-    context VARCHAR2(40 CHAR) NOT NULL, 
-    exten VARCHAR2(40 CHAR) NOT NULL, 
-    priority INTEGER NOT NULL, 
-    app VARCHAR2(40 CHAR) NOT NULL, 
-    appdata VARCHAR2(256 CHAR) NOT NULL, 
-    PRIMARY KEY (id, context, exten, priority), 
-    UNIQUE (id)
-)
-
-/
-
--- Running upgrade 581a4264e537 -> 2fc7930b41b3
-
-CREATE TABLE ps_systems (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    timer_t1 INTEGER, 
-    timer_b INTEGER, 
-    compact_headers VARCHAR(3 CHAR), 
-    threadpool_initial_size INTEGER, 
-    threadpool_auto_increment INTEGER, 
-    threadpool_idle_timeout INTEGER, 
-    threadpool_max_size INTEGER, 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (compact_headers IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX ps_systems_id ON ps_systems (id)
-
-/
-
-CREATE TABLE ps_globals (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    max_forwards INTEGER, 
-    user_agent VARCHAR2(40 CHAR), 
-    default_outbound_endpoint VARCHAR2(40 CHAR), 
-    UNIQUE (id)
-)
-
-/
-
-CREATE INDEX ps_globals_id ON ps_globals (id)
-
-/
-
-CREATE TABLE ps_transports (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    async_operations INTEGER, 
-    bind VARCHAR2(40 CHAR), 
-    ca_list_file VARCHAR2(200 CHAR), 
-    cert_file VARCHAR2(200 CHAR), 
-    cipher VARCHAR2(200 CHAR), 
-    domain VARCHAR2(40 CHAR), 
-    external_media_address VARCHAR2(40 CHAR), 
-    external_signaling_address VARCHAR2(40 CHAR), 
-    external_signaling_port INTEGER, 
-    method VARCHAR(11 CHAR), 
-    local_net VARCHAR2(40 CHAR), 
-    password VARCHAR2(40 CHAR), 
-    priv_key_file VARCHAR2(200 CHAR), 
-    protocol VARCHAR(3 CHAR), 
-    require_client_cert VARCHAR(3 CHAR), 
-    verify_client VARCHAR(3 CHAR), 
-    verifiy_server VARCHAR(3 CHAR), 
-    tos VARCHAR(3 CHAR), 
-    cos VARCHAR(3 CHAR), 
-    UNIQUE (id), 
-    CONSTRAINT pjsip_transport_method_values CHECK (method IN ('default', 'unspecified', 'tlsv1', 'sslv2', 'sslv3', 'sslv23')), 
-    CONSTRAINT pjsip_transport_protocol_values CHECK (protocol IN ('udp', 'tcp', 'tls', 'ws', 'wss')), 
-    CONSTRAINT yesno_values CHECK (require_client_cert IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (verify_client IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (verifiy_server IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (tos IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (cos IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX ps_transports_id ON ps_transports (id)
-
-/
-
-CREATE TABLE ps_registrations (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    auth_rejection_permanent VARCHAR(3 CHAR), 
-    client_uri VARCHAR2(40 CHAR), 
-    contact_user VARCHAR2(40 CHAR), 
-    expiration INTEGER, 
-    max_retries INTEGER, 
-    outbound_auth VARCHAR2(40 CHAR), 
-    outbound_proxy VARCHAR2(40 CHAR), 
-    retry_interval INTEGER, 
-    forbidden_retry_interval INTEGER, 
-    server_uri VARCHAR2(40 CHAR), 
-    transport VARCHAR2(40 CHAR), 
-    support_path VARCHAR(3 CHAR), 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (auth_rejection_permanent IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (support_path IN ('yes', 'no'))
-)
-
-/
-
-CREATE INDEX ps_registrations_id ON ps_registrations (id)
-
-/
-
-ALTER TABLE ps_endpoints ADD media_address VARCHAR2(40 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints ADD redirect_method VARCHAR(9 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT pjsip_redirect_method_values CHECK (redirect_method IN ('user', 'uri_core', 'uri_pjsip'))
-
-/
-
-ALTER TABLE ps_endpoints ADD set_var CLOB
-
-/
-
-ALTER TABLE ps_endpoints RENAME COLUMN mwi_fromuser TO mwi_from_user
-
-/
-
-ALTER TABLE ps_contacts ADD outbound_proxy VARCHAR2(40 CHAR)
-
-/
-
-ALTER TABLE ps_contacts ADD path CLOB
-
-/
-
-ALTER TABLE ps_aors ADD maximum_expiration INTEGER
-
-/
-
-ALTER TABLE ps_aors ADD outbound_proxy VARCHAR2(40 CHAR)
-
-/
-
-ALTER TABLE ps_aors ADD support_path VARCHAR(3 CHAR)
-
-/
-
-ALTER TABLE ps_aors ADD CONSTRAINT yesno_values CHECK (support_path IN ('yes', 'no'))
-
-/
-
--- Running upgrade 2fc7930b41b3 -> 21e526ad3040
-
-ALTER TABLE ps_globals ADD debug VARCHAR2(40 CHAR)
-
-/
-
--- Running upgrade 21e526ad3040 -> 28887f25a46f
-
-CREATE TABLE queues (
-    name VARCHAR2(128 CHAR) NOT NULL, 
-    musiconhold VARCHAR2(128 CHAR), 
-    announce VARCHAR2(128 CHAR), 
-    context VARCHAR2(128 CHAR), 
-    timeout INTEGER, 
-    ringinuse VARCHAR(3 CHAR), 
-    setinterfacevar VARCHAR(3 CHAR), 
-    setqueuevar VARCHAR(3 CHAR), 
-    setqueueentryvar VARCHAR(3 CHAR), 
-    monitor_format VARCHAR2(8 CHAR), 
-    membermacro VARCHAR2(512 CHAR), 
-    membergosub VARCHAR2(512 CHAR), 
-    queue_youarenext VARCHAR2(128 CHAR), 
-    queue_thereare VARCHAR2(128 CHAR), 
-    queue_callswaiting VARCHAR2(128 CHAR), 
-    queue_quantity1 VARCHAR2(128 CHAR), 
-    queue_quantity2 VARCHAR2(128 CHAR), 
-    queue_holdtime VARCHAR2(128 CHAR), 
-    queue_minutes VARCHAR2(128 CHAR), 
-    queue_minute VARCHAR2(128 CHAR), 
-    queue_seconds VARCHAR2(128 CHAR), 
-    queue_thankyou VARCHAR2(128 CHAR), 
-    queue_callerannounce VARCHAR2(128 CHAR), 
-    queue_reporthold VARCHAR2(128 CHAR), 
-    announce_frequency INTEGER, 
-    announce_to_first_user VARCHAR(3 CHAR), 
-    min_announce_frequency INTEGER, 
-    announce_round_seconds INTEGER, 
-    announce_holdtime VARCHAR2(128 CHAR), 
-    announce_position VARCHAR2(128 CHAR), 
-    announce_position_limit INTEGER, 
-    periodic_announce VARCHAR2(50 CHAR), 
-    periodic_announce_frequency INTEGER, 
-    relative_periodic_announce VARCHAR(3 CHAR), 
-    random_periodic_announce VARCHAR(3 CHAR), 
-    retry INTEGER, 
-    wrapuptime INTEGER, 
-    penaltymemberslimit INTEGER, 
-    autofill VARCHAR(3 CHAR), 
-    monitor_type VARCHAR2(128 CHAR), 
-    autopause VARCHAR(3 CHAR), 
-    autopausedelay INTEGER, 
-    autopausebusy VARCHAR(3 CHAR), 
-    autopauseunavail VARCHAR(3 CHAR), 
-    maxlen INTEGER, 
-    servicelevel INTEGER, 
-    strategy VARCHAR(11 CHAR), 
-    joinempty VARCHAR2(128 CHAR), 
-    leavewhenempty VARCHAR2(128 CHAR), 
-    reportholdtime VARCHAR(3 CHAR), 
-    memberdelay INTEGER, 
-    weight INTEGER, 
-    timeoutrestart VARCHAR(3 CHAR), 
-    defaultrule VARCHAR2(128 CHAR), 
-    timeoutpriority VARCHAR2(128 CHAR), 
-    PRIMARY KEY (name), 
-    CONSTRAINT yesno_values CHECK (ringinuse IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setinterfacevar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setqueuevar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setqueueentryvar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (announce_to_first_user IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (relative_periodic_announce IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (random_periodic_announce IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (autofill IN ('yes', 'no')), 
-    CONSTRAINT queue_autopause_values CHECK (autopause IN ('yes', 'no', 'all')), 
-    CONSTRAINT yesno_values CHECK (autopausebusy IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (autopauseunavail IN ('yes', 'no')), 
-    CONSTRAINT queue_strategy_values CHECK (strategy IN ('ringall', 'leastrecent', 'fewestcalls', 'random', 'rrmemory', 'linear', 'wrandom', 'rrordered')), 
-    CONSTRAINT yesno_values CHECK (reportholdtime IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (timeoutrestart IN ('yes', 'no'))
-)
-
-/
-
-CREATE TABLE queue_members (
-    queue_name VARCHAR2(80 CHAR) NOT NULL, 
-    interface VARCHAR2(80 CHAR) NOT NULL, 
-    uniqueid VARCHAR2(80 CHAR) NOT NULL, 
-    membername VARCHAR2(80 CHAR), 
-    state_interface VARCHAR2(80 CHAR), 
-    penalty INTEGER, 
-    paused INTEGER, 
-    PRIMARY KEY (queue_name, interface)
-)
-
-/
-
--- Running upgrade 28887f25a46f -> 4c573e7135bd
-
-ALTER TABLE ps_endpoints MODIFY tos_audio VARCHAR2(10 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints MODIFY tos_video VARCHAR2(10 CHAR)
-
-/
-
-ALTER TABLE ps_transports MODIFY tos VARCHAR2(10 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_audio
-
-/
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_video
-
-/
-
-ALTER TABLE ps_transports DROP COLUMN cos
-
-/
-
-ALTER TABLE ps_endpoints ADD cos_audio INTEGER
-
-/
-
-ALTER TABLE ps_endpoints ADD cos_video INTEGER
-
-/
-
-ALTER TABLE ps_transports ADD cos INTEGER
-
-/
-
--- Running upgrade 4c573e7135bd -> 3855ee4e5f85
-
-ALTER TABLE ps_endpoints ADD message_context VARCHAR2(40 CHAR)
-
-/
-
-ALTER TABLE ps_contacts ADD user_agent VARCHAR2(40 CHAR)
-
-/
-
--- Running upgrade 3855ee4e5f85 -> e96a0b8071c
-
-ALTER TABLE ps_globals MODIFY user_agent VARCHAR2(255 CHAR)
-
-/
-
-ALTER TABLE ps_contacts MODIFY id VARCHAR2(255 CHAR)
-
-/
-
-ALTER TABLE ps_contacts MODIFY uri VARCHAR2(255 CHAR)
-
-/
-
-ALTER TABLE ps_contacts MODIFY user_agent VARCHAR2(255 CHAR)
-
-/
-
-ALTER TABLE ps_registrations MODIFY client_uri VARCHAR2(255 CHAR)
-
-/
-
-ALTER TABLE ps_registrations MODIFY server_uri VARCHAR2(255 CHAR)
-
-/
-
--- Running upgrade e96a0b8071c -> c6d929b23a8
-
-CREATE TABLE ps_subscription_persistence (
-    id VARCHAR2(40 CHAR) NOT NULL, 
-    packet VARCHAR2(2048 CHAR), 
-    src_name VARCHAR2(128 CHAR), 
-    src_port INTEGER, 
-    transport_key VARCHAR2(64 CHAR), 
-    local_name VARCHAR2(128 CHAR), 
-    local_port INTEGER, 
-    cseq INTEGER, 
-    tag VARCHAR2(128 CHAR), 
-    endpoint VARCHAR2(40 CHAR), 
-    expires INTEGER, 
-    UNIQUE (id)
-)
-
-/
-
-CREATE INDEX ps_subscription_persistence_id ON ps_subscription_persistence (id)
-
-/
-
--- Running upgrade c6d929b23a8 -> 51f8cb66540e
-
-ALTER TABLE ps_endpoints ADD force_avp VARCHAR(3 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (force_avp IN ('yes', 'no'))
-
-/
-
-ALTER TABLE ps_endpoints ADD media_use_received_transport VARCHAR(3 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (media_use_received_transport IN ('yes', 'no'))
-
-/
-
--- Running upgrade 51f8cb66540e -> 1d50859ed02e
-
-ALTER TABLE ps_endpoints ADD accountcode VARCHAR2(20 CHAR)
-
-/
-
--- Running upgrade 1d50859ed02e -> 1758e8bbf6b
-
-ALTER TABLE sippeers MODIFY useragent VARCHAR2(255 CHAR)
-
-/
-
--- Running upgrade 1758e8bbf6b -> 5139253c0423
-
-ALTER TABLE queue_members DROP COLUMN uniqueid
-
-/
-
-ALTER TABLE queue_members ADD uniqueid INTEGER NOT NULL
-
-/
-
-ALTER TABLE queue_members ADD UNIQUE (uniqueid)
-
-/
-
--- Running upgrade 5139253c0423 -> d39508cb8d8
-
-CREATE TABLE queue_rules (
-    rule_name VARCHAR2(80 CHAR) NOT NULL, 
-    time VARCHAR2(32 CHAR) NOT NULL, 
-    min_penalty VARCHAR2(32 CHAR) NOT NULL, 
-    max_penalty VARCHAR2(32 CHAR) NOT NULL
-)
-
-/
-
--- Running upgrade d39508cb8d8 -> 5950038a6ead
-
-ALTER TABLE ps_transports MODIFY verifiy_server VARCHAR(3 CHAR)
-
-/
-
-ALTER TABLE ps_transports RENAME COLUMN verifiy_server TO verify_server
-
-/
-
-ALTER TABLE ps_transports ADD CONSTRAINT yesno_values CHECK (verifiy_server IN ('yes', 'no'))
-
-/
-
--- Running upgrade 5950038a6ead -> 10aedae86a32
-
-ALTER TABLE sippeers DROP CONSTRAINT sip_directmedia_values
-
-/
-
-ALTER TABLE sippeers MODIFY directmedia VARCHAR(8 CHAR)
-
-/
-
-ALTER TABLE sippeers ADD CONSTRAINT sip_directmedia_values_v2 CHECK (directmedia IN ('yes', 'no', 'nonat', 'update', 'outgoing'))
-
-/
-
--- Running upgrade 10aedae86a32 -> eb88a14f2a
-
-ALTER TABLE ps_endpoints ADD media_encryption_optimistic VARCHAR(3 CHAR)
-
-/
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (media_encryption_optimistic IN ('yes', 'no'))
-
-/
-
-INSERT INTO alembic_version (version_num) VALUES ('eb88a14f2a')
-
-/
-
-COMMIT
-
-/
-
diff --git a/contrib/realtime/oracle/oracle_voicemail.sql b/contrib/realtime/oracle/oracle_voicemail.sql
deleted file mode 100644
index 2c663e7..0000000
--- a/contrib/realtime/oracle/oracle_voicemail.sql
+++ /dev/null
@@ -1,52 +0,0 @@
-SET TRANSACTION READ WRITE
-
-/
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR2(32 CHAR) NOT NULL
-)
-
-/
-
--- Running upgrade None -> a2e9769475e
-
-CREATE TABLE voicemail_messages (
-    dir VARCHAR2(255 CHAR) NOT NULL, 
-    msgnum INTEGER NOT NULL, 
-    context VARCHAR2(80 CHAR), 
-    macrocontext VARCHAR2(80 CHAR), 
-    callerid VARCHAR2(80 CHAR), 
-    origtime INTEGER, 
-    duration INTEGER, 
-    recording BLOB, 
-    flag VARCHAR2(30 CHAR), 
-    category VARCHAR2(30 CHAR), 
-    mailboxuser VARCHAR2(30 CHAR), 
-    mailboxcontext VARCHAR2(30 CHAR), 
-    msg_id VARCHAR2(40 CHAR)
-)
-
-/
-
-ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum)
-
-/
-
-CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir)
-
-/
-
--- Running upgrade a2e9769475e -> 39428242f7f5
-
-ALTER TABLE voicemail_messages MODIFY recording BLOB
-
-/
-
-INSERT INTO alembic_version (version_num) VALUES ('39428242f7f5')
-
-/
-
-COMMIT
-
-/
-
diff --git a/contrib/realtime/postgresql/postgresql_cdr.sql b/contrib/realtime/postgresql/postgresql_cdr.sql
deleted file mode 100644
index 8aa1d97..0000000
--- a/contrib/realtime/postgresql/postgresql_cdr.sql
+++ /dev/null
@@ -1,36 +0,0 @@
-BEGIN;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> 210693f3123d
-
-CREATE TABLE cdr (
-    accountcode VARCHAR(20), 
-    src VARCHAR(80), 
-    dst VARCHAR(80), 
-    dcontext VARCHAR(80), 
-    clid VARCHAR(80), 
-    channel VARCHAR(80), 
-    dstchannel VARCHAR(80), 
-    lastapp VARCHAR(80), 
-    lastdata VARCHAR(80), 
-    start TIMESTAMP WITHOUT TIME ZONE, 
-    answer TIMESTAMP WITHOUT TIME ZONE, 
-    "end" TIMESTAMP WITHOUT TIME ZONE, 
-    duration INTEGER, 
-    billsec INTEGER, 
-    disposition VARCHAR(45), 
-    amaflags VARCHAR(45), 
-    userfield VARCHAR(256), 
-    uniqueid VARCHAR(150), 
-    linkedid VARCHAR(150), 
-    peeraccount VARCHAR(20), 
-    sequence INTEGER
-);
-
-INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
-
-COMMIT;
-
diff --git a/contrib/realtime/postgresql/postgresql_config.sql b/contrib/realtime/postgresql/postgresql_config.sql
deleted file mode 100644
index cb71ba6..0000000
--- a/contrib/realtime/postgresql/postgresql_config.sql
+++ /dev/null
@@ -1,739 +0,0 @@
-BEGIN;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> 4da0c5f79a9c
-
-CREATE TYPE type_values AS ENUM ('friend','user','peer');
-
-CREATE TYPE sip_transport_values AS ENUM ('udp','tcp','tls','ws','wss','udp,tcp','tcp,udp');
-
-CREATE TYPE sip_dtmfmode_values AS ENUM ('rfc2833','info','shortinfo','inband','auto');
-
-CREATE TYPE sip_directmedia_values AS ENUM ('yes','no','nonat','update');
-
-CREATE TYPE yes_no_values AS ENUM ('yes','no');
-
-CREATE TYPE sip_progressinband_values AS ENUM ('yes','no','never');
-
-CREATE TYPE sip_session_timers_values AS ENUM ('accept','refuse','originate');
-
-CREATE TYPE sip_session_refresher_values AS ENUM ('uac','uas');
-
-CREATE TYPE sip_callingpres_values AS ENUM ('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib');
-
-CREATE TABLE sippeers (
-    id SERIAL NOT NULL, 
-    name VARCHAR(40) NOT NULL, 
-    ipaddr VARCHAR(45), 
-    port INTEGER, 
-    regseconds INTEGER, 
-    defaultuser VARCHAR(40), 
-    fullcontact VARCHAR(80), 
-    regserver VARCHAR(20), 
-    useragent VARCHAR(20), 
-    lastms INTEGER, 
-    host VARCHAR(40), 
-    type type_values, 
-    context VARCHAR(40), 
-    permit VARCHAR(95), 
-    deny VARCHAR(95), 
-    secret VARCHAR(40), 
-    md5secret VARCHAR(40), 
-    remotesecret VARCHAR(40), 
-    transport sip_transport_values, 
-    dtmfmode sip_dtmfmode_values, 
-    directmedia sip_directmedia_values, 
-    nat VARCHAR(29), 
-    callgroup VARCHAR(40), 
-    pickupgroup VARCHAR(40), 
-    language VARCHAR(40), 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    insecure VARCHAR(40), 
-    trustrpid yes_no_values, 
-    progressinband sip_progressinband_values, 
-    promiscredir yes_no_values, 
-    useclientcode yes_no_values, 
-    accountcode VARCHAR(40), 
-    setvar VARCHAR(200), 
-    callerid VARCHAR(40), 
-    amaflags VARCHAR(40), 
-    callcounter yes_no_values, 
-    busylevel INTEGER, 
-    allowoverlap yes_no_values, 
-    allowsubscribe yes_no_values, 
-    videosupport yes_no_values, 
-    maxcallbitrate INTEGER, 
-    rfc2833compensate yes_no_values, 
-    mailbox VARCHAR(40), 
-    "session-timers" sip_session_timers_values, 
-    "session-expires" INTEGER, 
-    "session-minse" INTEGER, 
-    "session-refresher" sip_session_refresher_values, 
-    t38pt_usertpsource VARCHAR(40), 
-    regexten VARCHAR(40), 
-    fromdomain VARCHAR(40), 
-    fromuser VARCHAR(40), 
-    qualify VARCHAR(40), 
-    defaultip VARCHAR(45), 
-    rtptimeout INTEGER, 
-    rtpholdtimeout INTEGER, 
-    sendrpid yes_no_values, 
-    outboundproxy VARCHAR(40), 
-    callbackextension VARCHAR(40), 
-    timert1 INTEGER, 
-    timerb INTEGER, 
-    qualifyfreq INTEGER, 
-    constantssrc yes_no_values, 
-    contactpermit VARCHAR(95), 
-    contactdeny VARCHAR(95), 
-    usereqphone yes_no_values, 
-    textsupport yes_no_values, 
-    faxdetect yes_no_values, 
-    buggymwi yes_no_values, 
-    auth VARCHAR(40), 
-    fullname VARCHAR(40), 
-    trunkname VARCHAR(40), 
-    cid_number VARCHAR(40), 
-    callingpres sip_callingpres_values, 
-    mohinterpret VARCHAR(40), 
-    mohsuggest VARCHAR(40), 
-    parkinglot VARCHAR(40), 
-    hasvoicemail yes_no_values, 
-    subscribemwi yes_no_values, 
-    vmexten VARCHAR(40), 
-    autoframing yes_no_values, 
-    rtpkeepalive INTEGER, 
-    "call-limit" INTEGER, 
-    g726nonstandard yes_no_values, 
-    ignoresdpversion yes_no_values, 
-    allowtransfer yes_no_values, 
-    dynamic yes_no_values, 
-    path VARCHAR(256), 
-    supportpath yes_no_values, 
-    PRIMARY KEY (id), 
-    UNIQUE (name)
-);
-
-CREATE INDEX sippeers_name ON sippeers (name);
-
-CREATE INDEX sippeers_name_host ON sippeers (name, host);
-
-CREATE INDEX sippeers_ipaddr_port ON sippeers (ipaddr, port);
-
-CREATE INDEX sippeers_host_port ON sippeers (host, port);
-
-CREATE TYPE iax_requirecalltoken_values AS ENUM ('yes','no','auto');
-
-CREATE TYPE iax_encryption_values AS ENUM ('yes','no','aes128');
-
-CREATE TYPE iax_transfer_values AS ENUM ('yes','no','mediaonly');
-
-CREATE TABLE iaxfriends (
-    id SERIAL NOT NULL, 
-    name VARCHAR(40) NOT NULL, 
-    type type_values, 
-    username VARCHAR(40), 
-    mailbox VARCHAR(40), 
-    secret VARCHAR(40), 
-    dbsecret VARCHAR(40), 
-    context VARCHAR(40), 
-    regcontext VARCHAR(40), 
-    host VARCHAR(40), 
-    ipaddr VARCHAR(40), 
-    port INTEGER, 
-    defaultip VARCHAR(20), 
-    sourceaddress VARCHAR(20), 
-    mask VARCHAR(20), 
-    regexten VARCHAR(40), 
-    regseconds INTEGER, 
-    accountcode VARCHAR(20), 
-    mohinterpret VARCHAR(20), 
-    mohsuggest VARCHAR(20), 
-    inkeys VARCHAR(40), 
-    outkeys VARCHAR(40), 
-    language VARCHAR(10), 
-    callerid VARCHAR(100), 
-    cid_number VARCHAR(40), 
-    sendani yes_no_values, 
-    fullname VARCHAR(40), 
-    trunk yes_no_values, 
-    auth VARCHAR(20), 
-    maxauthreq INTEGER, 
-    requirecalltoken iax_requirecalltoken_values, 
-    encryption iax_encryption_values, 
-    transfer iax_transfer_values, 
-    jitterbuffer yes_no_values, 
-    forcejitterbuffer yes_no_values, 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    codecpriority VARCHAR(40), 
-    qualify VARCHAR(10), 
-    qualifysmoothing yes_no_values, 
-    qualifyfreqok VARCHAR(10), 
-    qualifyfreqnotok VARCHAR(10), 
-    timezone VARCHAR(20), 
-    adsi yes_no_values, 
-    amaflags VARCHAR(20), 
-    setvar VARCHAR(200), 
-    PRIMARY KEY (id), 
-    UNIQUE (name)
-);
-
-CREATE INDEX iaxfriends_name ON iaxfriends (name);
-
-CREATE INDEX iaxfriends_name_host ON iaxfriends (name, host);
-
-CREATE INDEX iaxfriends_name_ipaddr_port ON iaxfriends (name, ipaddr, port);
-
-CREATE INDEX iaxfriends_ipaddr_port ON iaxfriends (ipaddr, port);
-
-CREATE INDEX iaxfriends_host_port ON iaxfriends (host, port);
-
-CREATE TABLE voicemail (
-    uniqueid SERIAL NOT NULL, 
-    context VARCHAR(80) NOT NULL, 
-    mailbox VARCHAR(80) NOT NULL, 
-    password VARCHAR(80) NOT NULL, 
-    fullname VARCHAR(80), 
-    alias VARCHAR(80), 
-    email VARCHAR(80), 
-    pager VARCHAR(80), 
-    attach yes_no_values, 
-    attachfmt VARCHAR(10), 
-    serveremail VARCHAR(80), 
-    language VARCHAR(20), 
-    tz VARCHAR(30), 
-    deletevoicemail yes_no_values, 
-    saycid yes_no_values, 
-    sendvoicemail yes_no_values, 
-    review yes_no_values, 
-    tempgreetwarn yes_no_values, 
-    operator yes_no_values, 
-    envelope yes_no_values, 
-    sayduration INTEGER, 
-    forcename yes_no_values, 
-    forcegreetings yes_no_values, 
-    callback VARCHAR(80), 
-    dialout VARCHAR(80), 
-    exitcontext VARCHAR(80), 
-    maxmsg INTEGER, 
-    volgain NUMERIC(5, 2), 
-    imapuser VARCHAR(80), 
-    imappassword VARCHAR(80), 
-    imapserver VARCHAR(80), 
-    imapport VARCHAR(8), 
-    imapflags VARCHAR(80), 
-    stamp TIMESTAMP WITHOUT TIME ZONE, 
-    PRIMARY KEY (uniqueid)
-);
-
-CREATE INDEX voicemail_mailbox ON voicemail (mailbox);
-
-CREATE INDEX voicemail_context ON voicemail (context);
-
-CREATE INDEX voicemail_mailbox_context ON voicemail (mailbox, context);
-
-CREATE INDEX voicemail_imapuser ON voicemail (imapuser);
-
-CREATE TABLE meetme (
-    bookid SERIAL NOT NULL, 
-    confno VARCHAR(80) NOT NULL, 
-    starttime TIMESTAMP WITHOUT TIME ZONE, 
-    endtime TIMESTAMP WITHOUT TIME ZONE, 
-    pin VARCHAR(20), 
-    adminpin VARCHAR(20), 
-    opts VARCHAR(20), 
-    adminopts VARCHAR(20), 
-    recordingfilename VARCHAR(80), 
-    recordingformat VARCHAR(10), 
-    maxusers INTEGER, 
-    members INTEGER NOT NULL, 
-    PRIMARY KEY (bookid)
-);
-
-CREATE INDEX meetme_confno_start_end ON meetme (confno, starttime, endtime);
-
-CREATE TYPE moh_mode_values AS ENUM ('custom','files','mp3nb','quietmp3nb','quietmp3');
-
-CREATE TABLE musiconhold (
-    name VARCHAR(80) NOT NULL, 
-    mode moh_mode_values, 
-    directory VARCHAR(255), 
-    application VARCHAR(255), 
-    digit VARCHAR(1), 
-    sort VARCHAR(10), 
-    format VARCHAR(10), 
-    stamp TIMESTAMP WITHOUT TIME ZONE, 
-    PRIMARY KEY (name)
-);
-
--- Running upgrade 4da0c5f79a9c -> 43956d550a44
-
-CREATE TYPE yesno_values AS ENUM ('yes','no');
-
-CREATE TYPE pjsip_connected_line_method_values AS ENUM ('invite','reinvite','update');
-
-CREATE TYPE pjsip_direct_media_glare_mitigation_values AS ENUM ('none','outgoing','incoming');
-
-CREATE TYPE pjsip_dtmf_mode_values AS ENUM ('rfc4733','inband','info');
-
-CREATE TYPE pjsip_identify_by_values AS ENUM ('username');
-
-CREATE TYPE pjsip_timer_values AS ENUM ('forced','no','required','yes');
-
-CREATE TYPE pjsip_cid_privacy_values AS ENUM ('allowed_not_screened','allowed_passed_screened','allowed_failed_screened','allowed','prohib_not_screened','prohib_passed_screened','prohib_failed_screened','prohib','unavailable');
-
-CREATE TYPE pjsip_100rel_values AS ENUM ('no','required','yes');
-
-CREATE TYPE pjsip_media_encryption_values AS ENUM ('no','sdes','dtls');
-
-CREATE TYPE pjsip_t38udptl_ec_values AS ENUM ('none','fec','redundancy');
-
-CREATE TYPE pjsip_dtls_setup_values AS ENUM ('active','passive','actpass');
-
-CREATE TABLE ps_endpoints (
-    id VARCHAR(40) NOT NULL, 
-    transport VARCHAR(40), 
-    aors VARCHAR(200), 
-    auth VARCHAR(40), 
-    context VARCHAR(40), 
-    disallow VARCHAR(200), 
-    allow VARCHAR(200), 
-    direct_media yesno_values, 
-    connected_line_method pjsip_connected_line_method_values, 
-    direct_media_method pjsip_connected_line_method_values, 
-    direct_media_glare_mitigation pjsip_direct_media_glare_mitigation_values, 
-    disable_direct_media_on_nat yesno_values, 
-    dtmf_mode pjsip_dtmf_mode_values, 
-    external_media_address VARCHAR(40), 
-    force_rport yesno_values, 
-    ice_support yesno_values, 
-    identify_by pjsip_identify_by_values, 
-    mailboxes VARCHAR(40), 
-    moh_suggest VARCHAR(40), 
-    outbound_auth VARCHAR(40), 
-    outbound_proxy VARCHAR(40), 
-    rewrite_contact yesno_values, 
-    rtp_ipv6 yesno_values, 
-    rtp_symmetric yesno_values, 
-    send_diversion yesno_values, 
-    send_pai yesno_values, 
-    send_rpid yesno_values, 
-    timers_min_se INTEGER, 
-    timers pjsip_timer_values, 
-    timers_sess_expires INTEGER, 
-    callerid VARCHAR(40), 
-    callerid_privacy pjsip_cid_privacy_values, 
-    callerid_tag VARCHAR(40), 
-    "100rel" pjsip_100rel_values, 
-    aggregate_mwi yesno_values, 
-    trust_id_inbound yesno_values, 
-    trust_id_outbound yesno_values, 
-    use_ptime yesno_values, 
-    use_avpf yesno_values, 
-    media_encryption pjsip_media_encryption_values, 
-    inband_progress yesno_values, 
-    call_group VARCHAR(40), 
-    pickup_group VARCHAR(40), 
-    named_call_group VARCHAR(40), 
-    named_pickup_group VARCHAR(40), 
-    device_state_busy_at INTEGER, 
-    fax_detect yesno_values, 
-    t38_udptl yesno_values, 
-    t38_udptl_ec pjsip_t38udptl_ec_values, 
-    t38_udptl_maxdatagram INTEGER, 
-    t38_udptl_nat yesno_values, 
-    t38_udptl_ipv6 yesno_values, 
-    tone_zone VARCHAR(40), 
-    language VARCHAR(40), 
-    one_touch_recording yesno_values, 
-    record_on_feature VARCHAR(40), 
-    record_off_feature VARCHAR(40), 
-    rtp_engine VARCHAR(40), 
-    allow_transfer yesno_values, 
-    allow_subscribe yesno_values, 
-    sdp_owner VARCHAR(40), 
-    sdp_session VARCHAR(40), 
-    tos_audio INTEGER, 
-    tos_video INTEGER, 
-    cos_audio INTEGER, 
-    cos_video INTEGER, 
-    sub_min_expiry INTEGER, 
-    from_domain VARCHAR(40), 
-    from_user VARCHAR(40), 
-    mwi_fromuser VARCHAR(40), 
-    dtls_verify VARCHAR(40), 
-    dtls_rekey VARCHAR(40), 
-    dtls_cert_file VARCHAR(200), 
-    dtls_private_key VARCHAR(200), 
-    dtls_cipher VARCHAR(200), 
-    dtls_ca_file VARCHAR(200), 
-    dtls_ca_path VARCHAR(200), 
-    dtls_setup pjsip_dtls_setup_values, 
-    srtp_tag_32 yesno_values, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_endpoints_id ON ps_endpoints (id);
-
-CREATE TYPE pjsip_auth_type_values AS ENUM ('md5','userpass');
-
-CREATE TABLE ps_auths (
-    id VARCHAR(40) NOT NULL, 
-    auth_type pjsip_auth_type_values, 
-    nonce_lifetime INTEGER, 
-    md5_cred VARCHAR(40), 
-    password VARCHAR(80), 
-    realm VARCHAR(40), 
-    username VARCHAR(40), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_auths_id ON ps_auths (id);
-
-CREATE TABLE ps_aors (
-    id VARCHAR(40) NOT NULL, 
-    contact VARCHAR(40), 
-    default_expiration INTEGER, 
-    mailboxes VARCHAR(80), 
-    max_contacts INTEGER, 
-    minimum_expiration INTEGER, 
-    remove_existing yesno_values, 
-    qualify_frequency INTEGER, 
-    authenticate_qualify yesno_values, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_aors_id ON ps_aors (id);
-
-CREATE TABLE ps_contacts (
-    id VARCHAR(40) NOT NULL, 
-    uri VARCHAR(40), 
-    expiration_time VARCHAR(40), 
-    qualify_frequency INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_contacts_id ON ps_contacts (id);
-
-CREATE TABLE ps_domain_aliases (
-    id VARCHAR(40) NOT NULL, 
-    domain VARCHAR(80), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_domain_aliases_id ON ps_domain_aliases (id);
-
-CREATE TABLE ps_endpoint_id_ips (
-    id VARCHAR(40) NOT NULL, 
-    endpoint VARCHAR(40), 
-    match VARCHAR(80), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_endpoint_id_ips_id ON ps_endpoint_id_ips (id);
-
--- Running upgrade 43956d550a44 -> 581a4264e537
-
-CREATE TABLE extensions (
-    id BIGSERIAL NOT NULL, 
-    context VARCHAR(40) NOT NULL, 
-    exten VARCHAR(40) NOT NULL, 
-    priority INTEGER NOT NULL, 
-    app VARCHAR(40) NOT NULL, 
-    appdata VARCHAR(256) NOT NULL, 
-    PRIMARY KEY (id, context, exten, priority), 
-    UNIQUE (id)
-);
-
--- Running upgrade 581a4264e537 -> 2fc7930b41b3
-
-CREATE TYPE pjsip_redirect_method_values AS ENUM ('user','uri_core','uri_pjsip');
-
-CREATE TABLE ps_systems (
-    id VARCHAR(40) NOT NULL, 
-    timer_t1 INTEGER, 
-    timer_b INTEGER, 
-    compact_headers yesno_values, 
-    threadpool_initial_size INTEGER, 
-    threadpool_auto_increment INTEGER, 
-    threadpool_idle_timeout INTEGER, 
-    threadpool_max_size INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_systems_id ON ps_systems (id);
-
-CREATE TABLE ps_globals (
-    id VARCHAR(40) NOT NULL, 
-    max_forwards INTEGER, 
-    user_agent VARCHAR(40), 
-    default_outbound_endpoint VARCHAR(40), 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_globals_id ON ps_globals (id);
-
-CREATE TYPE pjsip_transport_method_values AS ENUM ('default','unspecified','tlsv1','sslv2','sslv3','sslv23');
-
-CREATE TYPE pjsip_transport_protocol_values AS ENUM ('udp','tcp','tls','ws','wss');
-
-CREATE TABLE ps_transports (
-    id VARCHAR(40) NOT NULL, 
-    async_operations INTEGER, 
-    bind VARCHAR(40), 
-    ca_list_file VARCHAR(200), 
-    cert_file VARCHAR(200), 
-    cipher VARCHAR(200), 
-    domain VARCHAR(40), 
-    external_media_address VARCHAR(40), 
-    external_signaling_address VARCHAR(40), 
-    external_signaling_port INTEGER, 
-    method pjsip_transport_method_values, 
-    local_net VARCHAR(40), 
-    password VARCHAR(40), 
-    priv_key_file VARCHAR(200), 
-    protocol pjsip_transport_protocol_values, 
-    require_client_cert yesno_values, 
-    verify_client yesno_values, 
-    verifiy_server yesno_values, 
-    tos yesno_values, 
-    cos yesno_values, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_transports_id ON ps_transports (id);
-
-CREATE TABLE ps_registrations (
-    id VARCHAR(40) NOT NULL, 
-    auth_rejection_permanent yesno_values, 
-    client_uri VARCHAR(40), 
-    contact_user VARCHAR(40), 
-    expiration INTEGER, 
-    max_retries INTEGER, 
-    outbound_auth VARCHAR(40), 
-    outbound_proxy VARCHAR(40), 
-    retry_interval INTEGER, 
-    forbidden_retry_interval INTEGER, 
-    server_uri VARCHAR(40), 
-    transport VARCHAR(40), 
-    support_path yesno_values, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_registrations_id ON ps_registrations (id);
-
-ALTER TABLE ps_endpoints ADD COLUMN media_address VARCHAR(40);
-
-ALTER TABLE ps_endpoints ADD COLUMN redirect_method pjsip_redirect_method_values;
-
-ALTER TABLE ps_endpoints ADD COLUMN set_var TEXT;
-
-ALTER TABLE ps_endpoints RENAME mwi_fromuser TO mwi_from_user;
-
-ALTER TABLE ps_contacts ADD COLUMN outbound_proxy VARCHAR(40);
-
-ALTER TABLE ps_contacts ADD COLUMN path TEXT;
-
-ALTER TABLE ps_aors ADD COLUMN maximum_expiration INTEGER;
-
-ALTER TABLE ps_aors ADD COLUMN outbound_proxy VARCHAR(40);
-
-ALTER TABLE ps_aors ADD COLUMN support_path yesno_values;
-
--- Running upgrade 2fc7930b41b3 -> 21e526ad3040
-
-ALTER TABLE ps_globals ADD COLUMN debug VARCHAR(40);
-
--- Running upgrade 21e526ad3040 -> 28887f25a46f
-
-CREATE TYPE queue_autopause_values AS ENUM ('yes','no','all');
-
-CREATE TYPE queue_strategy_values AS ENUM ('ringall','leastrecent','fewestcalls','random','rrmemory','linear','wrandom','rrordered');
-
-CREATE TABLE queues (
-    name VARCHAR(128) NOT NULL, 
-    musiconhold VARCHAR(128), 
-    announce VARCHAR(128), 
-    context VARCHAR(128), 
-    timeout INTEGER, 
-    ringinuse yesno_values, 
-    setinterfacevar yesno_values, 
-    setqueuevar yesno_values, 
-    setqueueentryvar yesno_values, 
-    monitor_format VARCHAR(8), 
-    membermacro VARCHAR(512), 
-    membergosub VARCHAR(512), 
-    queue_youarenext VARCHAR(128), 
-    queue_thereare VARCHAR(128), 
-    queue_callswaiting VARCHAR(128), 
-    queue_quantity1 VARCHAR(128), 
-    queue_quantity2 VARCHAR(128), 
-    queue_holdtime VARCHAR(128), 
-    queue_minutes VARCHAR(128), 
-    queue_minute VARCHAR(128), 
-    queue_seconds VARCHAR(128), 
-    queue_thankyou VARCHAR(128), 
-    queue_callerannounce VARCHAR(128), 
-    queue_reporthold VARCHAR(128), 
-    announce_frequency INTEGER, 
-    announce_to_first_user yesno_values, 
-    min_announce_frequency INTEGER, 
-    announce_round_seconds INTEGER, 
-    announce_holdtime VARCHAR(128), 
-    announce_position VARCHAR(128), 
-    announce_position_limit INTEGER, 
-    periodic_announce VARCHAR(50), 
-    periodic_announce_frequency INTEGER, 
-    relative_periodic_announce yesno_values, 
-    random_periodic_announce yesno_values, 
-    retry INTEGER, 
-    wrapuptime INTEGER, 
-    penaltymemberslimit INTEGER, 
-    autofill yesno_values, 
-    monitor_type VARCHAR(128), 
-    autopause queue_autopause_values, 
-    autopausedelay INTEGER, 
-    autopausebusy yesno_values, 
-    autopauseunavail yesno_values, 
-    maxlen INTEGER, 
-    servicelevel INTEGER, 
-    strategy queue_strategy_values, 
-    joinempty VARCHAR(128), 
-    leavewhenempty VARCHAR(128), 
-    reportholdtime yesno_values, 
-    memberdelay INTEGER, 
-    weight INTEGER, 
-    timeoutrestart yesno_values, 
-    defaultrule VARCHAR(128), 
-    timeoutpriority VARCHAR(128), 
-    PRIMARY KEY (name)
-);
-
-CREATE TABLE queue_members (
-    queue_name VARCHAR(80) NOT NULL, 
-    interface VARCHAR(80) NOT NULL, 
-    uniqueid VARCHAR(80) NOT NULL, 
-    membername VARCHAR(80), 
-    state_interface VARCHAR(80), 
-    penalty INTEGER, 
-    paused INTEGER, 
-    PRIMARY KEY (queue_name, interface)
-);
-
--- Running upgrade 28887f25a46f -> 4c573e7135bd
-
-ALTER TABLE ps_endpoints ALTER COLUMN tos_audio TYPE VARCHAR(10);
-
-ALTER TABLE ps_endpoints ALTER COLUMN tos_video TYPE VARCHAR(10);
-
-ALTER TABLE ps_transports ALTER COLUMN tos TYPE VARCHAR(10);
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_audio;
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_video;
-
-ALTER TABLE ps_transports DROP COLUMN cos;
-
-ALTER TABLE ps_endpoints ADD COLUMN cos_audio INTEGER;
-
-ALTER TABLE ps_endpoints ADD COLUMN cos_video INTEGER;
-
-ALTER TABLE ps_transports ADD COLUMN cos INTEGER;
-
--- Running upgrade 4c573e7135bd -> 3855ee4e5f85
-
-ALTER TABLE ps_endpoints ADD COLUMN message_context VARCHAR(40);
-
-ALTER TABLE ps_contacts ADD COLUMN user_agent VARCHAR(40);
-
--- Running upgrade 3855ee4e5f85 -> e96a0b8071c
-
-ALTER TABLE ps_globals ALTER COLUMN user_agent TYPE VARCHAR(255);
-
-ALTER TABLE ps_contacts ALTER COLUMN id TYPE VARCHAR(255);
-
-ALTER TABLE ps_contacts ALTER COLUMN uri TYPE VARCHAR(255);
-
-ALTER TABLE ps_contacts ALTER COLUMN user_agent TYPE VARCHAR(255);
-
-ALTER TABLE ps_registrations ALTER COLUMN client_uri TYPE VARCHAR(255);
-
-ALTER TABLE ps_registrations ALTER COLUMN server_uri TYPE VARCHAR(255);
-
--- Running upgrade e96a0b8071c -> c6d929b23a8
-
-CREATE TABLE ps_subscription_persistence (
-    id VARCHAR(40) NOT NULL, 
-    packet VARCHAR(2048), 
-    src_name VARCHAR(128), 
-    src_port INTEGER, 
-    transport_key VARCHAR(64), 
-    local_name VARCHAR(128), 
-    local_port INTEGER, 
-    cseq INTEGER, 
-    tag VARCHAR(128), 
-    endpoint VARCHAR(40), 
-    expires INTEGER, 
-    UNIQUE (id)
-);
-
-CREATE INDEX ps_subscription_persistence_id ON ps_subscription_persistence (id);
-
--- Running upgrade c6d929b23a8 -> 51f8cb66540e
-
-ALTER TABLE ps_endpoints ADD COLUMN force_avp yesno_values;
-
-ALTER TABLE ps_endpoints ADD COLUMN media_use_received_transport yesno_values;
-
--- Running upgrade 51f8cb66540e -> 1d50859ed02e
-
-ALTER TABLE ps_endpoints ADD COLUMN accountcode VARCHAR(20);
-
--- Running upgrade 1d50859ed02e -> 1758e8bbf6b
-
-ALTER TABLE sippeers ALTER COLUMN useragent TYPE VARCHAR(255);
-
--- Running upgrade 1758e8bbf6b -> 5139253c0423
-
-ALTER TABLE queue_members DROP COLUMN uniqueid;
-
-ALTER TABLE queue_members ADD COLUMN uniqueid INTEGER NOT NULL;
-
-ALTER TABLE queue_members ADD UNIQUE (uniqueid);
-
--- Running upgrade 5139253c0423 -> d39508cb8d8
-
-CREATE TABLE queue_rules (
-    rule_name VARCHAR(80) NOT NULL, 
-    time VARCHAR(32) NOT NULL, 
-    min_penalty VARCHAR(32) NOT NULL, 
-    max_penalty VARCHAR(32) NOT NULL
-);
-
--- Running upgrade d39508cb8d8 -> 5950038a6ead
-
-ALTER TABLE ps_transports ALTER COLUMN verifiy_server TYPE yesno_values;
-
-ALTER TABLE ps_transports RENAME verifiy_server TO verify_server;
-
--- Running upgrade 5950038a6ead -> 10aedae86a32
-
-CREATE TYPE sip_directmedia_values_v2 AS ENUM ('yes','no','nonat','update','outgoing');
-
-ALTER TABLE sippeers ALTER COLUMN directmedia TYPE sip_directmedia_values_v2 USING directmedia::text::sip_directmedia_values_v2;
-
-DROP TYPE sip_directmedia_values;
-
--- Running upgrade 10aedae86a32 -> eb88a14f2a
-
-ALTER TABLE ps_endpoints ADD COLUMN media_encryption_optimistic yesno_values;
-
-INSERT INTO alembic_version (version_num) VALUES ('eb88a14f2a');
-
-COMMIT;
-
diff --git a/contrib/realtime/postgresql/postgresql_voicemail.sql b/contrib/realtime/postgresql/postgresql_voicemail.sql
deleted file mode 100644
index 20caf39..0000000
--- a/contrib/realtime/postgresql/postgresql_voicemail.sql
+++ /dev/null
@@ -1,36 +0,0 @@
-BEGIN;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
--- Running upgrade None -> a2e9769475e
-
-CREATE TABLE voicemail_messages (
-    dir VARCHAR(255) NOT NULL, 
-    msgnum INTEGER NOT NULL, 
-    context VARCHAR(80), 
-    macrocontext VARCHAR(80), 
-    callerid VARCHAR(80), 
-    origtime INTEGER, 
-    duration INTEGER, 
-    recording BYTEA, 
-    flag VARCHAR(30), 
-    category VARCHAR(30), 
-    mailboxuser VARCHAR(30), 
-    mailboxcontext VARCHAR(30), 
-    msg_id VARCHAR(40)
-);
-
-ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
-
-CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
-
--- Running upgrade a2e9769475e -> 39428242f7f5
-
-ALTER TABLE voicemail_messages ALTER COLUMN recording TYPE BYTEA;
-
-INSERT INTO alembic_version (version_num) VALUES ('39428242f7f5');
-
-COMMIT;
-
diff --git a/contrib/realtime/postgresql/realtime.sql b/contrib/realtime/postgresql/realtime.sql
new file mode 100644
index 0000000..76c6acc
--- /dev/null
+++ b/contrib/realtime/postgresql/realtime.sql
@@ -0,0 +1,164 @@
+drop table extensions_conf;
+
+CREATE TABLE extensions_conf (
+id serial NOT NULL,
+context character varying(20) DEFAULT '' NOT NULL,
+exten character varying(20) DEFAULT '' NOT NULL,
+priority smallint DEFAULT 0 NOT NULL,
+app character varying(20) DEFAULT '' NOT NULL,
+appdata character varying(128)
+);
+
+drop table cdr;
+CREATE TABLE cdr (
+calldate timestamp with time zone DEFAULT now() NOT NULL,
+clid character varying(80) DEFAULT '' NOT NULL,
+src character varying(80) DEFAULT '' NOT NULL,
+dst character varying(80) DEFAULT '' NOT NULL,
+dcontext character varying(80) DEFAULT '' NOT NULL,
+channel character varying(80) DEFAULT '' NOT NULL,
+dstchannel character varying(80) DEFAULT '' NOT NULL,
+lastapp character varying(80) DEFAULT '' NOT NULL,
+lastdata character varying(80) DEFAULT '' NOT NULL,
+duration bigint DEFAULT 0::bigint NOT NULL,
+billsec bigint DEFAULT 0::bigint NOT NULL,
+disposition character varying(45) DEFAULT '' NOT NULL,
+amaflags bigint DEFAULT 0::bigint NOT NULL,
+accountcode character varying(20) DEFAULT '' NOT NULL,
+uniqueid character varying(32) DEFAULT '' NOT NULL,
+userfield character varying(255) DEFAULT '' NOT NULL
+);
+
+drop table sip_conf;
+CREATE TABLE sip_conf (
+id serial NOT NULL,
+name character varying(80) DEFAULT '' NOT NULL,
+accountcode character varying(20),
+amaflags character varying(7),
+callgroup character varying(10),
+callerid character varying(80),
+canreinvite character varying(3) DEFAULT 'yes',
+context character varying(80),
+defaultip character varying(45),
+dtmfmode character varying(7),
+fromuser character varying(80),
+fromdomain character varying(80),
+host character varying(31) DEFAULT '' NOT NULL,
+insecure character varying(4),
+"language" character varying(2),
+mailbox character varying(50),
+md5secret character varying(80),
+nat character varying(29) DEFAULT '' NOT NULL,
+permit character varying(95),
+deny character varying(95),
+mask character varying(95),
+pickupgroup character varying(10),
+port character varying(5) DEFAULT '' NOT NULL,
+qualify character varying(3),
+restrictcid character varying(1),
+rtptimeout character varying(3),
+rtpholdtimeout character varying(3),
+secret character varying(80),
+"type" character varying DEFAULT 'friend' NOT NULL,
+username character varying(80) DEFAULT '' NOT NULL,
+allow character varying(200) DEFAULT '!all,g729,ilbc,gsm,ulaw,alaw',
+musiconhold character varying(100),
+regseconds bigint DEFAULT 0::bigint NOT NULL,
+ipaddr character varying(45) DEFAULT '' NOT NULL,
+regexten character varying(80) DEFAULT '' NOT NULL,
+cancallforward character varying(3) DEFAULT 'yes',
+lastms integer DEFAULT 0 NOT NULL,
+defaultuser character varying(80),
+fullcontact character varying(80),
+regserver character varying(30),
+useragent character varying(40),
+callbackextension character varying(40)
+);
+
+drop table voicemail_users;
+CREATE TABLE voicemail_users (
+id serial NOT NULL,
+customer_id bigint DEFAULT (0)::bigint NOT NULL,
+context character varying(50) DEFAULT '' NOT NULL,
+mailbox bigint DEFAULT (0)::bigint NOT NULL,
+"password" character varying(4) DEFAULT '0' NOT NULL,
+fullname character varying(50) DEFAULT '' NOT NULL,
+email character varying(50) DEFAULT '' NOT NULL,
+pager character varying(50) DEFAULT '' NOT NULL,
+stamp timestamp(6) without time zone NOT NULL
+);
+
+drop table queue_table;
+CREATE TABLE queue_table (
+name varchar(128),
+musiconhold varchar(128),
+announce varchar(128),
+context varchar(128),
+timeout int8,
+monitor_join bool,
+monitor_format varchar(128),
+queue_youarenext varchar(128),
+queue_thereare varchar(128),
+queue_callswaiting varchar(128),
+queue_holdtime varchar(128),
+queue_minutes varchar(128),
+queue_seconds varchar(128),
+queue_lessthan varchar(128),
+queue_thankyou varchar(128),
+queue_reporthold varchar(128),
+announce_frequency int8,
+announce_round_seconds int8,
+announce_holdtime varchar(128),
+retry int8,
+wrapuptime int8,
+maxlen int8,
+servicelevel int8,
+strategy varchar(128),
+joinempty varchar(128),
+leavewhenempty varchar(128),
+eventmemberstatus bool,
+eventwhencalled bool,
+reportholdtime bool,
+memberdelay int8,
+weight int8,
+timeoutrestart bool,
+setinterfacevar bool,
+PRIMARY KEY (name)
+) WITHOUT OIDS;
+ALTER TABLE queue_table OWNER TO asterisk;
+
+drop table queue_member_table;
+CREATE TABLE queue_member_table
+(
+queue_name varchar(128),
+interface varchar(128),
+penalty int8,
+PRIMARY KEY (queue_name, interface)
+) WITHOUT OIDS;
+
+drop table queue_log;
+CREATE TABLE "queue_log" (
+"id" SERIAL,
+"time" TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL,
+"callid" character varying(50) NOT NULL,
+"queuename" character varying(50) NOT NULL,
+"agent" character varying(50) NOT NULL,
+"event" character varying(20) NOT NULL,
+"data1" character varying(50) NOT NULL,
+"data2" character varying(50) NOT NULL,
+"data3" character varying(50) NOT NULL,
+"data4" character varying(50) NOT NULL,
+"data5" character varying(50) NOT NULL,
+CONSTRAINT queue_log_pkey PRIMARY KEY (id)
+) WITHOUT OIDS;
+
+GRANT ALL ON TABLE queue_log TO asterisk;
+GRANT ALL ON TABLE cdr TO asterisk;
+GRANT ALL ON TABLE extensions_conf TO asterisk;
+GRANT ALL ON TABLE sip_conf TO asterisk;
+GRANT ALL ON TABLE voicemail_users TO asterisk;
+GRANT ALL ON TABLE queue_member_table TO asterisk;
+GRANT ALL ON TABLE queue_table TO asterisk;
+
+
+
diff --git a/contrib/realtime/sqlserver/mssql_cdr.sql b/contrib/realtime/sqlserver/mssql_cdr.sql
deleted file mode 100644
index dcd433f..0000000
--- a/contrib/realtime/sqlserver/mssql_cdr.sql
+++ /dev/null
@@ -1,42 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
-GO
-
--- Running upgrade None -> 210693f3123d
-
-CREATE TABLE cdr (
-    accountcode VARCHAR(20) NULL, 
-    src VARCHAR(80) NULL, 
-    dst VARCHAR(80) NULL, 
-    dcontext VARCHAR(80) NULL, 
-    clid VARCHAR(80) NULL, 
-    channel VARCHAR(80) NULL, 
-    dstchannel VARCHAR(80) NULL, 
-    lastapp VARCHAR(80) NULL, 
-    lastdata VARCHAR(80) NULL, 
-    start DATETIME NULL, 
-    answer DATETIME NULL, 
-    [end] DATETIME NULL, 
-    duration INTEGER NULL, 
-    billsec INTEGER NULL, 
-    disposition VARCHAR(45) NULL, 
-    amaflags VARCHAR(45) NULL, 
-    userfield VARCHAR(256) NULL, 
-    uniqueid VARCHAR(150) NULL, 
-    linkedid VARCHAR(150) NULL, 
-    peeraccount VARCHAR(20) NULL, 
-    sequence INTEGER NULL
-);
-
-GO
-
-INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
-
-GO
-
-COMMIT;
-
diff --git a/contrib/realtime/sqlserver/mssql_config.sql b/contrib/realtime/sqlserver/mssql_config.sql
deleted file mode 100644
index 4834bec..0000000
--- a/contrib/realtime/sqlserver/mssql_config.sql
+++ /dev/null
@@ -1,990 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
-GO
-
--- Running upgrade None -> 4da0c5f79a9c
-
-CREATE TABLE sippeers (
-    id INTEGER NOT NULL IDENTITY(1,1), 
-    name VARCHAR(40) NOT NULL, 
-    ipaddr VARCHAR(45) NULL, 
-    port INTEGER NULL, 
-    regseconds INTEGER NULL, 
-    defaultuser VARCHAR(40) NULL, 
-    fullcontact VARCHAR(80) NULL, 
-    regserver VARCHAR(20) NULL, 
-    useragent VARCHAR(20) NULL, 
-    lastms INTEGER NULL, 
-    host VARCHAR(40) NULL, 
-    type VARCHAR(6) NULL, 
-    context VARCHAR(40) NULL, 
-    permit VARCHAR(95) NULL, 
-    [deny] VARCHAR(95) NULL, 
-    secret VARCHAR(40) NULL, 
-    md5secret VARCHAR(40) NULL, 
-    remotesecret VARCHAR(40) NULL, 
-    transport VARCHAR(7) NULL, 
-    dtmfmode VARCHAR(9) NULL, 
-    directmedia VARCHAR(6) NULL, 
-    nat VARCHAR(29) NULL, 
-    callgroup VARCHAR(40) NULL, 
-    pickupgroup VARCHAR(40) NULL, 
-    language VARCHAR(40) NULL, 
-    disallow VARCHAR(200) NULL, 
-    allow VARCHAR(200) NULL, 
-    insecure VARCHAR(40) NULL, 
-    trustrpid VARCHAR(3) NULL, 
-    progressinband VARCHAR(5) NULL, 
-    promiscredir VARCHAR(3) NULL, 
-    useclientcode VARCHAR(3) NULL, 
-    accountcode VARCHAR(40) NULL, 
-    setvar VARCHAR(200) NULL, 
-    callerid VARCHAR(40) NULL, 
-    amaflags VARCHAR(40) NULL, 
-    callcounter VARCHAR(3) NULL, 
-    busylevel INTEGER NULL, 
-    allowoverlap VARCHAR(3) NULL, 
-    allowsubscribe VARCHAR(3) NULL, 
-    videosupport VARCHAR(3) NULL, 
-    maxcallbitrate INTEGER NULL, 
-    rfc2833compensate VARCHAR(3) NULL, 
-    mailbox VARCHAR(40) NULL, 
-    [session-timers] VARCHAR(9) NULL, 
-    [session-expires] INTEGER NULL, 
-    [session-minse] INTEGER NULL, 
-    [session-refresher] VARCHAR(3) NULL, 
-    t38pt_usertpsource VARCHAR(40) NULL, 
-    regexten VARCHAR(40) NULL, 
-    fromdomain VARCHAR(40) NULL, 
-    fromuser VARCHAR(40) NULL, 
-    qualify VARCHAR(40) NULL, 
-    defaultip VARCHAR(45) NULL, 
-    rtptimeout INTEGER NULL, 
-    rtpholdtimeout INTEGER NULL, 
-    sendrpid VARCHAR(3) NULL, 
-    outboundproxy VARCHAR(40) NULL, 
-    callbackextension VARCHAR(40) NULL, 
-    timert1 INTEGER NULL, 
-    timerb INTEGER NULL, 
-    qualifyfreq INTEGER NULL, 
-    constantssrc VARCHAR(3) NULL, 
-    contactpermit VARCHAR(95) NULL, 
-    contactdeny VARCHAR(95) NULL, 
-    usereqphone VARCHAR(3) NULL, 
-    textsupport VARCHAR(3) NULL, 
-    faxdetect VARCHAR(3) NULL, 
-    buggymwi VARCHAR(3) NULL, 
-    auth VARCHAR(40) NULL, 
-    fullname VARCHAR(40) NULL, 
-    trunkname VARCHAR(40) NULL, 
-    cid_number VARCHAR(40) NULL, 
-    callingpres VARCHAR(21) NULL, 
-    mohinterpret VARCHAR(40) NULL, 
-    mohsuggest VARCHAR(40) NULL, 
-    parkinglot VARCHAR(40) NULL, 
-    hasvoicemail VARCHAR(3) NULL, 
-    subscribemwi VARCHAR(3) NULL, 
-    vmexten VARCHAR(40) NULL, 
-    autoframing VARCHAR(3) NULL, 
-    rtpkeepalive INTEGER NULL, 
-    [call-limit] INTEGER NULL, 
-    g726nonstandard VARCHAR(3) NULL, 
-    ignoresdpversion VARCHAR(3) NULL, 
-    allowtransfer VARCHAR(3) NULL, 
-    dynamic VARCHAR(3) NULL, 
-    path VARCHAR(256) NULL, 
-    supportpath VARCHAR(3) NULL, 
-    PRIMARY KEY (id), 
-    UNIQUE (name), 
-    CONSTRAINT type_values CHECK (type IN ('friend', 'user', 'peer')), 
-    CONSTRAINT sip_transport_values CHECK (transport IN ('udp', 'tcp', 'tls', 'ws', 'wss', 'udp,tcp', 'tcp,udp')), 
-    CONSTRAINT sip_dtmfmode_values CHECK (dtmfmode IN ('rfc2833', 'info', 'shortinfo', 'inband', 'auto')), 
-    CONSTRAINT sip_directmedia_values CHECK (directmedia IN ('yes', 'no', 'nonat', 'update')), 
-    CONSTRAINT yes_no_values CHECK (trustrpid IN ('yes', 'no')), 
-    CONSTRAINT sip_progressinband_values CHECK (progressinband IN ('yes', 'no', 'never')), 
-    CONSTRAINT yes_no_values CHECK (promiscredir IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (useclientcode IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (callcounter IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowoverlap IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowsubscribe IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (videosupport IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (rfc2833compensate IN ('yes', 'no')), 
-    CONSTRAINT sip_session_timers_values CHECK ([session-timers] IN ('accept', 'refuse', 'originate')), 
-    CONSTRAINT sip_session_refresher_values CHECK ([session-refresher] IN ('uac', 'uas')), 
-    CONSTRAINT yes_no_values CHECK (sendrpid IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (constantssrc IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (usereqphone IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (textsupport IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (faxdetect IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (buggymwi IN ('yes', 'no')), 
-    CONSTRAINT sip_callingpres_values CHECK (callingpres IN ('allowed_not_screened', 'allowed_passed_screen', 'allowed_failed_screen', 'allowed', 'prohib_not_screened', 'prohib_passed_screen', 'prohib_failed_screen', 'prohib')), 
-    CONSTRAINT yes_no_values CHECK (hasvoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (subscribemwi IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (autoframing IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (g726nonstandard IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (ignoresdpversion IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (allowtransfer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (dynamic IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (supportpath IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX sippeers_name ON sippeers (name);
-
-GO
-
-CREATE INDEX sippeers_name_host ON sippeers (name, host);
-
-GO
-
-CREATE INDEX sippeers_ipaddr_port ON sippeers (ipaddr, port);
-
-GO
-
-CREATE INDEX sippeers_host_port ON sippeers (host, port);
-
-GO
-
-CREATE TABLE iaxfriends (
-    id INTEGER NOT NULL IDENTITY(1,1), 
-    name VARCHAR(40) NOT NULL, 
-    type VARCHAR(6) NULL, 
-    username VARCHAR(40) NULL, 
-    mailbox VARCHAR(40) NULL, 
-    secret VARCHAR(40) NULL, 
-    dbsecret VARCHAR(40) NULL, 
-    context VARCHAR(40) NULL, 
-    regcontext VARCHAR(40) NULL, 
-    host VARCHAR(40) NULL, 
-    ipaddr VARCHAR(40) NULL, 
-    port INTEGER NULL, 
-    defaultip VARCHAR(20) NULL, 
-    sourceaddress VARCHAR(20) NULL, 
-    mask VARCHAR(20) NULL, 
-    regexten VARCHAR(40) NULL, 
-    regseconds INTEGER NULL, 
-    accountcode VARCHAR(20) NULL, 
-    mohinterpret VARCHAR(20) NULL, 
-    mohsuggest VARCHAR(20) NULL, 
-    inkeys VARCHAR(40) NULL, 
-    outkeys VARCHAR(40) NULL, 
-    language VARCHAR(10) NULL, 
-    callerid VARCHAR(100) NULL, 
-    cid_number VARCHAR(40) NULL, 
-    sendani VARCHAR(3) NULL, 
-    fullname VARCHAR(40) NULL, 
-    trunk VARCHAR(3) NULL, 
-    auth VARCHAR(20) NULL, 
-    maxauthreq INTEGER NULL, 
-    requirecalltoken VARCHAR(4) NULL, 
-    encryption VARCHAR(6) NULL, 
-    transfer VARCHAR(9) NULL, 
-    jitterbuffer VARCHAR(3) NULL, 
-    forcejitterbuffer VARCHAR(3) NULL, 
-    disallow VARCHAR(200) NULL, 
-    allow VARCHAR(200) NULL, 
-    codecpriority VARCHAR(40) NULL, 
-    qualify VARCHAR(10) NULL, 
-    qualifysmoothing VARCHAR(3) NULL, 
-    qualifyfreqok VARCHAR(10) NULL, 
-    qualifyfreqnotok VARCHAR(10) NULL, 
-    timezone VARCHAR(20) NULL, 
-    adsi VARCHAR(3) NULL, 
-    amaflags VARCHAR(20) NULL, 
-    setvar VARCHAR(200) NULL, 
-    PRIMARY KEY (id), 
-    UNIQUE (name), 
-    CONSTRAINT type_values CHECK (type IN ('friend', 'user', 'peer')), 
-    CONSTRAINT yes_no_values CHECK (sendani IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (trunk IN ('yes', 'no')), 
-    CONSTRAINT iax_requirecalltoken_values CHECK (requirecalltoken IN ('yes', 'no', 'auto')), 
-    CONSTRAINT iax_encryption_values CHECK (encryption IN ('yes', 'no', 'aes128')), 
-    CONSTRAINT iax_transfer_values CHECK (transfer IN ('yes', 'no', 'mediaonly')), 
-    CONSTRAINT yes_no_values CHECK (jitterbuffer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcejitterbuffer IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (qualifysmoothing IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (adsi IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX iaxfriends_name ON iaxfriends (name);
-
-GO
-
-CREATE INDEX iaxfriends_name_host ON iaxfriends (name, host);
-
-GO
-
-CREATE INDEX iaxfriends_name_ipaddr_port ON iaxfriends (name, ipaddr, port);
-
-GO
-
-CREATE INDEX iaxfriends_ipaddr_port ON iaxfriends (ipaddr, port);
-
-GO
-
-CREATE INDEX iaxfriends_host_port ON iaxfriends (host, port);
-
-GO
-
-CREATE TABLE voicemail (
-    uniqueid INTEGER NOT NULL IDENTITY(1,1), 
-    context VARCHAR(80) NOT NULL, 
-    mailbox VARCHAR(80) NOT NULL, 
-    password VARCHAR(80) NOT NULL, 
-    fullname VARCHAR(80) NULL, 
-    alias VARCHAR(80) NULL, 
-    email VARCHAR(80) NULL, 
-    pager VARCHAR(80) NULL, 
-    attach VARCHAR(3) NULL, 
-    attachfmt VARCHAR(10) NULL, 
-    serveremail VARCHAR(80) NULL, 
-    language VARCHAR(20) NULL, 
-    tz VARCHAR(30) NULL, 
-    deletevoicemail VARCHAR(3) NULL, 
-    saycid VARCHAR(3) NULL, 
-    sendvoicemail VARCHAR(3) NULL, 
-    review VARCHAR(3) NULL, 
-    tempgreetwarn VARCHAR(3) NULL, 
-    operator VARCHAR(3) NULL, 
-    envelope VARCHAR(3) NULL, 
-    sayduration INTEGER NULL, 
-    forcename VARCHAR(3) NULL, 
-    forcegreetings VARCHAR(3) NULL, 
-    callback VARCHAR(80) NULL, 
-    dialout VARCHAR(80) NULL, 
-    exitcontext VARCHAR(80) NULL, 
-    maxmsg INTEGER NULL, 
-    volgain NUMERIC(5, 2) NULL, 
-    imapuser VARCHAR(80) NULL, 
-    imappassword VARCHAR(80) NULL, 
-    imapserver VARCHAR(80) NULL, 
-    imapport VARCHAR(8) NULL, 
-    imapflags VARCHAR(80) NULL, 
-    stamp DATETIME NULL, 
-    PRIMARY KEY (uniqueid), 
-    CONSTRAINT yes_no_values CHECK (attach IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (deletevoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (saycid IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (sendvoicemail IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (review IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (tempgreetwarn IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (operator IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (envelope IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcename IN ('yes', 'no')), 
-    CONSTRAINT yes_no_values CHECK (forcegreetings IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX voicemail_mailbox ON voicemail (mailbox);
-
-GO
-
-CREATE INDEX voicemail_context ON voicemail (context);
-
-GO
-
-CREATE INDEX voicemail_mailbox_context ON voicemail (mailbox, context);
-
-GO
-
-CREATE INDEX voicemail_imapuser ON voicemail (imapuser);
-
-GO
-
-CREATE TABLE meetme (
-    bookid INTEGER NOT NULL IDENTITY(1,1), 
-    confno VARCHAR(80) NOT NULL, 
-    starttime DATETIME NULL, 
-    endtime DATETIME NULL, 
-    pin VARCHAR(20) NULL, 
-    adminpin VARCHAR(20) NULL, 
-    opts VARCHAR(20) NULL, 
-    adminopts VARCHAR(20) NULL, 
-    recordingfilename VARCHAR(80) NULL, 
-    recordingformat VARCHAR(10) NULL, 
-    maxusers INTEGER NULL, 
-    members INTEGER NOT NULL, 
-    PRIMARY KEY (bookid)
-);
-
-GO
-
-CREATE INDEX meetme_confno_start_end ON meetme (confno, starttime, endtime);
-
-GO
-
-CREATE TABLE musiconhold (
-    name VARCHAR(80) NOT NULL, 
-    mode VARCHAR(10) NULL, 
-    directory VARCHAR(255) NULL, 
-    application VARCHAR(255) NULL, 
-    digit VARCHAR(1) NULL, 
-    sort VARCHAR(10) NULL, 
-    format VARCHAR(10) NULL, 
-    stamp DATETIME NULL, 
-    PRIMARY KEY (name), 
-    CONSTRAINT moh_mode_values CHECK (mode IN ('custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3'))
-);
-
-GO
-
--- Running upgrade 4da0c5f79a9c -> 43956d550a44
-
-CREATE TABLE ps_endpoints (
-    id VARCHAR(40) NOT NULL, 
-    transport VARCHAR(40) NULL, 
-    aors VARCHAR(200) NULL, 
-    auth VARCHAR(40) NULL, 
-    context VARCHAR(40) NULL, 
-    disallow VARCHAR(200) NULL, 
-    allow VARCHAR(200) NULL, 
-    direct_media VARCHAR(3) NULL, 
-    connected_line_method VARCHAR(8) NULL, 
-    direct_media_method VARCHAR(8) NULL, 
-    direct_media_glare_mitigation VARCHAR(8) NULL, 
-    disable_direct_media_on_nat VARCHAR(3) NULL, 
-    dtmf_mode VARCHAR(7) NULL, 
-    external_media_address VARCHAR(40) NULL, 
-    force_rport VARCHAR(3) NULL, 
-    ice_support VARCHAR(3) NULL, 
-    identify_by VARCHAR(8) NULL, 
-    mailboxes VARCHAR(40) NULL, 
-    moh_suggest VARCHAR(40) NULL, 
-    outbound_auth VARCHAR(40) NULL, 
-    outbound_proxy VARCHAR(40) NULL, 
-    rewrite_contact VARCHAR(3) NULL, 
-    rtp_ipv6 VARCHAR(3) NULL, 
-    rtp_symmetric VARCHAR(3) NULL, 
-    send_diversion VARCHAR(3) NULL, 
-    send_pai VARCHAR(3) NULL, 
-    send_rpid VARCHAR(3) NULL, 
-    timers_min_se INTEGER NULL, 
-    timers VARCHAR(8) NULL, 
-    timers_sess_expires INTEGER NULL, 
-    callerid VARCHAR(40) NULL, 
-    callerid_privacy VARCHAR(23) NULL, 
-    callerid_tag VARCHAR(40) NULL, 
-    [100rel] VARCHAR(8) NULL, 
-    aggregate_mwi VARCHAR(3) NULL, 
-    trust_id_inbound VARCHAR(3) NULL, 
-    trust_id_outbound VARCHAR(3) NULL, 
-    use_ptime VARCHAR(3) NULL, 
-    use_avpf VARCHAR(3) NULL, 
-    media_encryption VARCHAR(4) NULL, 
-    inband_progress VARCHAR(3) NULL, 
-    call_group VARCHAR(40) NULL, 
-    pickup_group VARCHAR(40) NULL, 
-    named_call_group VARCHAR(40) NULL, 
-    named_pickup_group VARCHAR(40) NULL, 
-    device_state_busy_at INTEGER NULL, 
-    fax_detect VARCHAR(3) NULL, 
-    t38_udptl VARCHAR(3) NULL, 
-    t38_udptl_ec VARCHAR(10) NULL, 
-    t38_udptl_maxdatagram INTEGER NULL, 
-    t38_udptl_nat VARCHAR(3) NULL, 
-    t38_udptl_ipv6 VARCHAR(3) NULL, 
-    tone_zone VARCHAR(40) NULL, 
-    language VARCHAR(40) NULL, 
-    one_touch_recording VARCHAR(3) NULL, 
-    record_on_feature VARCHAR(40) NULL, 
-    record_off_feature VARCHAR(40) NULL, 
-    rtp_engine VARCHAR(40) NULL, 
-    allow_transfer VARCHAR(3) NULL, 
-    allow_subscribe VARCHAR(3) NULL, 
-    sdp_owner VARCHAR(40) NULL, 
-    sdp_session VARCHAR(40) NULL, 
-    tos_audio INTEGER NULL, 
-    tos_video INTEGER NULL, 
-    cos_audio INTEGER NULL, 
-    cos_video INTEGER NULL, 
-    sub_min_expiry INTEGER NULL, 
-    from_domain VARCHAR(40) NULL, 
-    from_user VARCHAR(40) NULL, 
-    mwi_fromuser VARCHAR(40) NULL, 
-    dtls_verify VARCHAR(40) NULL, 
-    dtls_rekey VARCHAR(40) NULL, 
-    dtls_cert_file VARCHAR(200) NULL, 
-    dtls_private_key VARCHAR(200) NULL, 
-    dtls_cipher VARCHAR(200) NULL, 
-    dtls_ca_file VARCHAR(200) NULL, 
-    dtls_ca_path VARCHAR(200) NULL, 
-    dtls_setup VARCHAR(7) NULL, 
-    srtp_tag_32 VARCHAR(3) NULL, 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (direct_media IN ('yes', 'no')), 
-    CONSTRAINT pjsip_connected_line_method_values CHECK (connected_line_method IN ('invite', 'reinvite', 'update')), 
-    CONSTRAINT pjsip_connected_line_method_values CHECK (direct_media_method IN ('invite', 'reinvite', 'update')), 
-    CONSTRAINT pjsip_direct_media_glare_mitigation_values CHECK (direct_media_glare_mitigation IN ('none', 'outgoing', 'incoming')), 
-    CONSTRAINT yesno_values CHECK (disable_direct_media_on_nat IN ('yes', 'no')), 
-    CONSTRAINT pjsip_dtmf_mode_values CHECK (dtmf_mode IN ('rfc4733', 'inband', 'info')), 
-    CONSTRAINT yesno_values CHECK (force_rport IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (ice_support IN ('yes', 'no')), 
-    CONSTRAINT pjsip_identify_by_values CHECK (identify_by IN ('username')), 
-    CONSTRAINT yesno_values CHECK (rewrite_contact IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (rtp_ipv6 IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (rtp_symmetric IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_diversion IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_pai IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (send_rpid IN ('yes', 'no')), 
-    CONSTRAINT pjsip_timer_values CHECK (timers IN ('forced', 'no', 'required', 'yes')), 
-    CONSTRAINT pjsip_cid_privacy_values CHECK (callerid_privacy IN ('allowed_not_screened', 'allowed_passed_screened', 'allowed_failed_screened', 'allowed', 'prohib_not_screened', 'prohib_passed_screened', 'prohib_failed_screened', 'prohib', 'unavailable')), 
-    CONSTRAINT pjsip_100rel_values CHECK ([100rel] IN ('no', 'required', 'yes')), 
-    CONSTRAINT yesno_values CHECK (aggregate_mwi IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (trust_id_inbound IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (trust_id_outbound IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (use_ptime IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (use_avpf IN ('yes', 'no')), 
-    CONSTRAINT pjsip_media_encryption_values CHECK (media_encryption IN ('no', 'sdes', 'dtls')), 
-    CONSTRAINT yesno_values CHECK (inband_progress IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (fax_detect IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl IN ('yes', 'no')), 
-    CONSTRAINT pjsip_t38udptl_ec_values CHECK (t38_udptl_ec IN ('none', 'fec', 'redundancy')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl_nat IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (t38_udptl_ipv6 IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (one_touch_recording IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (allow_transfer IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (allow_subscribe IN ('yes', 'no')), 
-    CONSTRAINT pjsip_dtls_setup_values CHECK (dtls_setup IN ('active', 'passive', 'actpass')), 
-    CONSTRAINT yesno_values CHECK (srtp_tag_32 IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX ps_endpoints_id ON ps_endpoints (id);
-
-GO
-
-CREATE TABLE ps_auths (
-    id VARCHAR(40) NOT NULL, 
-    auth_type VARCHAR(8) NULL, 
-    nonce_lifetime INTEGER NULL, 
-    md5_cred VARCHAR(40) NULL, 
-    password VARCHAR(80) NULL, 
-    realm VARCHAR(40) NULL, 
-    username VARCHAR(40) NULL, 
-    UNIQUE (id), 
-    CONSTRAINT pjsip_auth_type_values CHECK (auth_type IN ('md5', 'userpass'))
-);
-
-GO
-
-CREATE INDEX ps_auths_id ON ps_auths (id);
-
-GO
-
-CREATE TABLE ps_aors (
-    id VARCHAR(40) NOT NULL, 
-    contact VARCHAR(40) NULL, 
-    default_expiration INTEGER NULL, 
-    mailboxes VARCHAR(80) NULL, 
-    max_contacts INTEGER NULL, 
-    minimum_expiration INTEGER NULL, 
-    remove_existing VARCHAR(3) NULL, 
-    qualify_frequency INTEGER NULL, 
-    authenticate_qualify VARCHAR(3) NULL, 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (remove_existing IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (authenticate_qualify IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX ps_aors_id ON ps_aors (id);
-
-GO
-
-CREATE TABLE ps_contacts (
-    id VARCHAR(40) NOT NULL, 
-    uri VARCHAR(40) NULL, 
-    expiration_time VARCHAR(40) NULL, 
-    qualify_frequency INTEGER NULL, 
-    UNIQUE (id)
-);
-
-GO
-
-CREATE INDEX ps_contacts_id ON ps_contacts (id);
-
-GO
-
-CREATE TABLE ps_domain_aliases (
-    id VARCHAR(40) NOT NULL, 
-    domain VARCHAR(80) NULL, 
-    UNIQUE (id)
-);
-
-GO
-
-CREATE INDEX ps_domain_aliases_id ON ps_domain_aliases (id);
-
-GO
-
-CREATE TABLE ps_endpoint_id_ips (
-    id VARCHAR(40) NOT NULL, 
-    endpoint VARCHAR(40) NULL, 
-    match VARCHAR(80) NULL, 
-    UNIQUE (id)
-);
-
-GO
-
-CREATE INDEX ps_endpoint_id_ips_id ON ps_endpoint_id_ips (id);
-
-GO
-
--- Running upgrade 43956d550a44 -> 581a4264e537
-
-CREATE TABLE extensions (
-    id BIGINT NOT NULL IDENTITY(1,1), 
-    context VARCHAR(40) NOT NULL, 
-    exten VARCHAR(40) NOT NULL, 
-    priority INTEGER NOT NULL, 
-    app VARCHAR(40) NOT NULL, 
-    appdata VARCHAR(256) NOT NULL, 
-    PRIMARY KEY (id, context, exten, priority), 
-    UNIQUE (id)
-);
-
-GO
-
--- Running upgrade 581a4264e537 -> 2fc7930b41b3
-
-CREATE TABLE ps_systems (
-    id VARCHAR(40) NOT NULL, 
-    timer_t1 INTEGER NULL, 
-    timer_b INTEGER NULL, 
-    compact_headers VARCHAR(3) NULL, 
-    threadpool_initial_size INTEGER NULL, 
-    threadpool_auto_increment INTEGER NULL, 
-    threadpool_idle_timeout INTEGER NULL, 
-    threadpool_max_size INTEGER NULL, 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (compact_headers IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX ps_systems_id ON ps_systems (id);
-
-GO
-
-CREATE TABLE ps_globals (
-    id VARCHAR(40) NOT NULL, 
-    max_forwards INTEGER NULL, 
-    user_agent VARCHAR(40) NULL, 
-    default_outbound_endpoint VARCHAR(40) NULL, 
-    UNIQUE (id)
-);
-
-GO
-
-CREATE INDEX ps_globals_id ON ps_globals (id);
-
-GO
-
-CREATE TABLE ps_transports (
-    id VARCHAR(40) NOT NULL, 
-    async_operations INTEGER NULL, 
-    bind VARCHAR(40) NULL, 
-    ca_list_file VARCHAR(200) NULL, 
-    cert_file VARCHAR(200) NULL, 
-    cipher VARCHAR(200) NULL, 
-    domain VARCHAR(40) NULL, 
-    external_media_address VARCHAR(40) NULL, 
-    external_signaling_address VARCHAR(40) NULL, 
-    external_signaling_port INTEGER NULL, 
-    method VARCHAR(11) NULL, 
-    local_net VARCHAR(40) NULL, 
-    password VARCHAR(40) NULL, 
-    priv_key_file VARCHAR(200) NULL, 
-    protocol VARCHAR(3) NULL, 
-    require_client_cert VARCHAR(3) NULL, 
-    verify_client VARCHAR(3) NULL, 
-    verifiy_server VARCHAR(3) NULL, 
-    tos VARCHAR(3) NULL, 
-    cos VARCHAR(3) NULL, 
-    UNIQUE (id), 
-    CONSTRAINT pjsip_transport_method_values CHECK (method IN ('default', 'unspecified', 'tlsv1', 'sslv2', 'sslv3', 'sslv23')), 
-    CONSTRAINT pjsip_transport_protocol_values CHECK (protocol IN ('udp', 'tcp', 'tls', 'ws', 'wss')), 
-    CONSTRAINT yesno_values CHECK (require_client_cert IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (verify_client IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (verifiy_server IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (tos IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (cos IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX ps_transports_id ON ps_transports (id);
-
-GO
-
-CREATE TABLE ps_registrations (
-    id VARCHAR(40) NOT NULL, 
-    auth_rejection_permanent VARCHAR(3) NULL, 
-    client_uri VARCHAR(40) NULL, 
-    contact_user VARCHAR(40) NULL, 
-    expiration INTEGER NULL, 
-    max_retries INTEGER NULL, 
-    outbound_auth VARCHAR(40) NULL, 
-    outbound_proxy VARCHAR(40) NULL, 
-    retry_interval INTEGER NULL, 
-    forbidden_retry_interval INTEGER NULL, 
-    server_uri VARCHAR(40) NULL, 
-    transport VARCHAR(40) NULL, 
-    support_path VARCHAR(3) NULL, 
-    UNIQUE (id), 
-    CONSTRAINT yesno_values CHECK (auth_rejection_permanent IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (support_path IN ('yes', 'no'))
-);
-
-GO
-
-CREATE INDEX ps_registrations_id ON ps_registrations (id);
-
-GO
-
-ALTER TABLE ps_endpoints ADD media_address VARCHAR(40) NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD redirect_method VARCHAR(9) NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT pjsip_redirect_method_values CHECK (redirect_method IN ('user', 'uri_core', 'uri_pjsip'));
-
-GO
-
-ALTER TABLE ps_endpoints ADD set_var TEXT NULL;
-
-GO
-
-EXEC sp_rename 'ps_endpoints.mwi_fromuser', mwi_from_user, 'COLUMN';
-
-GO
-
-ALTER TABLE ps_contacts ADD outbound_proxy VARCHAR(40) NULL;
-
-GO
-
-ALTER TABLE ps_contacts ADD path TEXT NULL;
-
-GO
-
-ALTER TABLE ps_aors ADD maximum_expiration INTEGER NULL;
-
-GO
-
-ALTER TABLE ps_aors ADD outbound_proxy VARCHAR(40) NULL;
-
-GO
-
-ALTER TABLE ps_aors ADD support_path VARCHAR(3) NULL;
-
-GO
-
-ALTER TABLE ps_aors ADD CONSTRAINT yesno_values CHECK (support_path IN ('yes', 'no'));
-
-GO
-
--- Running upgrade 2fc7930b41b3 -> 21e526ad3040
-
-ALTER TABLE ps_globals ADD debug VARCHAR(40) NULL;
-
-GO
-
--- Running upgrade 21e526ad3040 -> 28887f25a46f
-
-CREATE TABLE queues (
-    name VARCHAR(128) NOT NULL, 
-    musiconhold VARCHAR(128) NULL, 
-    announce VARCHAR(128) NULL, 
-    context VARCHAR(128) NULL, 
-    timeout INTEGER NULL, 
-    ringinuse VARCHAR(3) NULL, 
-    setinterfacevar VARCHAR(3) NULL, 
-    setqueuevar VARCHAR(3) NULL, 
-    setqueueentryvar VARCHAR(3) NULL, 
-    monitor_format VARCHAR(8) NULL, 
-    membermacro VARCHAR(512) NULL, 
-    membergosub VARCHAR(512) NULL, 
-    queue_youarenext VARCHAR(128) NULL, 
-    queue_thereare VARCHAR(128) NULL, 
-    queue_callswaiting VARCHAR(128) NULL, 
-    queue_quantity1 VARCHAR(128) NULL, 
-    queue_quantity2 VARCHAR(128) NULL, 
-    queue_holdtime VARCHAR(128) NULL, 
-    queue_minutes VARCHAR(128) NULL, 
-    queue_minute VARCHAR(128) NULL, 
-    queue_seconds VARCHAR(128) NULL, 
-    queue_thankyou VARCHAR(128) NULL, 
-    queue_callerannounce VARCHAR(128) NULL, 
-    queue_reporthold VARCHAR(128) NULL, 
-    announce_frequency INTEGER NULL, 
-    announce_to_first_user VARCHAR(3) NULL, 
-    min_announce_frequency INTEGER NULL, 
-    announce_round_seconds INTEGER NULL, 
-    announce_holdtime VARCHAR(128) NULL, 
-    announce_position VARCHAR(128) NULL, 
-    announce_position_limit INTEGER NULL, 
-    periodic_announce VARCHAR(50) NULL, 
-    periodic_announce_frequency INTEGER NULL, 
-    relative_periodic_announce VARCHAR(3) NULL, 
-    random_periodic_announce VARCHAR(3) NULL, 
-    retry INTEGER NULL, 
-    wrapuptime INTEGER NULL, 
-    penaltymemberslimit INTEGER NULL, 
-    autofill VARCHAR(3) NULL, 
-    monitor_type VARCHAR(128) NULL, 
-    autopause VARCHAR(3) NULL, 
-    autopausedelay INTEGER NULL, 
-    autopausebusy VARCHAR(3) NULL, 
-    autopauseunavail VARCHAR(3) NULL, 
-    maxlen INTEGER NULL, 
-    servicelevel INTEGER NULL, 
-    strategy VARCHAR(11) NULL, 
-    joinempty VARCHAR(128) NULL, 
-    leavewhenempty VARCHAR(128) NULL, 
-    reportholdtime VARCHAR(3) NULL, 
-    memberdelay INTEGER NULL, 
-    weight INTEGER NULL, 
-    timeoutrestart VARCHAR(3) NULL, 
-    defaultrule VARCHAR(128) NULL, 
-    timeoutpriority VARCHAR(128) NULL, 
-    PRIMARY KEY (name), 
-    CONSTRAINT yesno_values CHECK (ringinuse IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setinterfacevar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setqueuevar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (setqueueentryvar IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (announce_to_first_user IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (relative_periodic_announce IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (random_periodic_announce IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (autofill IN ('yes', 'no')), 
-    CONSTRAINT queue_autopause_values CHECK (autopause IN ('yes', 'no', 'all')), 
-    CONSTRAINT yesno_values CHECK (autopausebusy IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (autopauseunavail IN ('yes', 'no')), 
-    CONSTRAINT queue_strategy_values CHECK (strategy IN ('ringall', 'leastrecent', 'fewestcalls', 'random', 'rrmemory', 'linear', 'wrandom', 'rrordered')), 
-    CONSTRAINT yesno_values CHECK (reportholdtime IN ('yes', 'no')), 
-    CONSTRAINT yesno_values CHECK (timeoutrestart IN ('yes', 'no'))
-);
-
-GO
-
-CREATE TABLE queue_members (
-    queue_name VARCHAR(80) NOT NULL, 
-    interface VARCHAR(80) NOT NULL, 
-    uniqueid VARCHAR(80) NOT NULL, 
-    membername VARCHAR(80) NULL, 
-    state_interface VARCHAR(80) NULL, 
-    penalty INTEGER NULL, 
-    paused INTEGER NULL, 
-    PRIMARY KEY (queue_name, interface)
-);
-
-GO
-
--- Running upgrade 28887f25a46f -> 4c573e7135bd
-
-ALTER TABLE ps_endpoints ALTER COLUMN tos_audio VARCHAR(10);
-
-GO
-
-ALTER TABLE ps_endpoints ALTER COLUMN tos_video VARCHAR(10);
-
-GO
-
-ALTER TABLE ps_transports ALTER COLUMN tos VARCHAR(10);
-
-GO
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_audio;
-
-GO
-
-ALTER TABLE ps_endpoints DROP COLUMN cos_video;
-
-GO
-
-ALTER TABLE ps_transports DROP COLUMN cos;
-
-GO
-
-ALTER TABLE ps_endpoints ADD cos_audio INTEGER NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD cos_video INTEGER NULL;
-
-GO
-
-ALTER TABLE ps_transports ADD cos INTEGER NULL;
-
-GO
-
--- Running upgrade 4c573e7135bd -> 3855ee4e5f85
-
-ALTER TABLE ps_endpoints ADD message_context VARCHAR(40) NULL;
-
-GO
-
-ALTER TABLE ps_contacts ADD user_agent VARCHAR(40) NULL;
-
-GO
-
--- Running upgrade 3855ee4e5f85 -> e96a0b8071c
-
-ALTER TABLE ps_globals ALTER COLUMN user_agent VARCHAR(255);
-
-GO
-
-ALTER TABLE ps_contacts ALTER COLUMN id VARCHAR(255);
-
-GO
-
-ALTER TABLE ps_contacts ALTER COLUMN uri VARCHAR(255);
-
-GO
-
-ALTER TABLE ps_contacts ALTER COLUMN user_agent VARCHAR(255);
-
-GO
-
-ALTER TABLE ps_registrations ALTER COLUMN client_uri VARCHAR(255);
-
-GO
-
-ALTER TABLE ps_registrations ALTER COLUMN server_uri VARCHAR(255);
-
-GO
-
--- Running upgrade e96a0b8071c -> c6d929b23a8
-
-CREATE TABLE ps_subscription_persistence (
-    id VARCHAR(40) NOT NULL, 
-    packet VARCHAR(2048) NULL, 
-    src_name VARCHAR(128) NULL, 
-    src_port INTEGER NULL, 
-    transport_key VARCHAR(64) NULL, 
-    local_name VARCHAR(128) NULL, 
-    local_port INTEGER NULL, 
-    cseq INTEGER NULL, 
-    tag VARCHAR(128) NULL, 
-    endpoint VARCHAR(40) NULL, 
-    expires INTEGER NULL, 
-    UNIQUE (id)
-);
-
-GO
-
-CREATE INDEX ps_subscription_persistence_id ON ps_subscription_persistence (id);
-
-GO
-
--- Running upgrade c6d929b23a8 -> 51f8cb66540e
-
-ALTER TABLE ps_endpoints ADD force_avp VARCHAR(3) NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (force_avp IN ('yes', 'no'));
-
-GO
-
-ALTER TABLE ps_endpoints ADD media_use_received_transport VARCHAR(3) NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (media_use_received_transport IN ('yes', 'no'));
-
-GO
-
--- Running upgrade 51f8cb66540e -> 1d50859ed02e
-
-ALTER TABLE ps_endpoints ADD accountcode VARCHAR(20) NULL;
-
-GO
-
--- Running upgrade 1d50859ed02e -> 1758e8bbf6b
-
-ALTER TABLE sippeers ALTER COLUMN useragent VARCHAR(255);
-
-GO
-
--- Running upgrade 1758e8bbf6b -> 5139253c0423
-
-ALTER TABLE queue_members DROP COLUMN uniqueid;
-
-GO
-
-ALTER TABLE queue_members ADD uniqueid INTEGER NOT NULL;
-
-GO
-
-ALTER TABLE queue_members ADD UNIQUE (uniqueid);
-
-GO
-
--- Running upgrade 5139253c0423 -> d39508cb8d8
-
-CREATE TABLE queue_rules (
-    rule_name VARCHAR(80) NOT NULL, 
-    time VARCHAR(32) NOT NULL, 
-    min_penalty VARCHAR(32) NOT NULL, 
-    max_penalty VARCHAR(32) NOT NULL
-);
-
-GO
-
--- Running upgrade d39508cb8d8 -> 5950038a6ead
-
-ALTER TABLE ps_transports ALTER COLUMN verifiy_server VARCHAR(3);
-
-GO
-
-EXEC sp_rename 'ps_transports.verifiy_server', verify_server, 'COLUMN';
-
-GO
-
-ALTER TABLE ps_transports ADD CONSTRAINT yesno_values CHECK (verifiy_server IN ('yes', 'no'));
-
-GO
-
--- Running upgrade 5950038a6ead -> 10aedae86a32
-
-ALTER TABLE sippeers DROP CONSTRAINT sip_directmedia_values;
-
-GO
-
-ALTER TABLE sippeers ALTER COLUMN directmedia VARCHAR(8);
-
-GO
-
-ALTER TABLE sippeers ADD CONSTRAINT sip_directmedia_values_v2 CHECK (directmedia IN ('yes', 'no', 'nonat', 'update', 'outgoing'));
-
-GO
-
--- Running upgrade 10aedae86a32 -> eb88a14f2a
-
-ALTER TABLE ps_endpoints ADD media_encryption_optimistic VARCHAR(3) NULL;
-
-GO
-
-ALTER TABLE ps_endpoints ADD CONSTRAINT yesno_values CHECK (media_encryption_optimistic IN ('yes', 'no'));
-
-GO
-
-INSERT INTO alembic_version (version_num) VALUES ('eb88a14f2a');
-
-GO
-
-COMMIT;
-
diff --git a/contrib/realtime/sqlserver/mssql_voicemail.sql b/contrib/realtime/sqlserver/mssql_voicemail.sql
deleted file mode 100644
index 815d24e..0000000
--- a/contrib/realtime/sqlserver/mssql_voicemail.sql
+++ /dev/null
@@ -1,48 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE alembic_version (
-    version_num VARCHAR(32) NOT NULL
-);
-
-GO
-
--- Running upgrade None -> a2e9769475e
-
-CREATE TABLE voicemail_messages (
-    dir VARCHAR(255) NOT NULL, 
-    msgnum INTEGER NOT NULL, 
-    context VARCHAR(80) NULL, 
-    macrocontext VARCHAR(80) NULL, 
-    callerid VARCHAR(80) NULL, 
-    origtime INTEGER NULL, 
-    duration INTEGER NULL, 
-    recording IMAGE NULL, 
-    flag VARCHAR(30) NULL, 
-    category VARCHAR(30) NULL, 
-    mailboxuser VARCHAR(30) NULL, 
-    mailboxcontext VARCHAR(30) NULL, 
-    msg_id VARCHAR(40) NULL
-);
-
-GO
-
-ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
-
-GO
-
-CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
-
-GO
-
--- Running upgrade a2e9769475e -> 39428242f7f5
-
-ALTER TABLE voicemail_messages ALTER COLUMN recording IMAGE;
-
-GO
-
-INSERT INTO alembic_version (version_num) VALUES ('39428242f7f5');
-
-GO
-
-COMMIT;
-
diff --git a/contrib/scripts/ast_grab_core b/contrib/scripts/ast_grab_core
index a4e62e9..bc56b61 100644
--- a/contrib/scripts/ast_grab_core
+++ b/contrib/scripts/ast_grab_core
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Id: ast_grab_core 197824 2009-05-28 21:50:27Z seanbright $
+# $Id$
 # lame quickie script to snarf a core of a hung asterisk process.
 # bugs to ast_grab_core, blinky-lights.org  (derrick daugherty)
 
diff --git a/contrib/scripts/ast_tls_cert b/contrib/scripts/ast_tls_cert
index fe7d6ab..3c5363a 100755
--- a/contrib/scripts/ast_tls_cert
+++ b/contrib/scripts/ast_tls_cert
@@ -204,12 +204,8 @@ then
 	CAKEY=${OUTPUT_DIR}/ca.key
 	CACERT=${OUTPUT_DIR}/ca.crt
 	CACFG=${OUTPUT_DIR}/ca.cfg
-	if [ ! -r "$CAKEY" ] &&  [ ! -r "$CACFG" ]; then
-		create_config ca "${CACFG}" "${DEFAULT_CA_CN}" "${DEFAULT_CA_ORG}"
-	fi
-	if  [ ! -r "$CACERT" ]; then
-		create_ca
-	fi
+	create_config ca "${CACFG}" "${DEFAULT_CA_CN}" "${DEFAULT_CA_ORG}"
+	create_ca
 else
 	if [ -z ${CAKEY} ]
 	then
diff --git a/contrib/scripts/asterisk.ldap-schema b/contrib/scripts/asterisk.ldap-schema
index 85f9103..3d81a1b 100644
--- a/contrib/scripts/asterisk.ldap-schema
+++ b/contrib/scripts/asterisk.ldap-schema
@@ -112,7 +112,7 @@ objectIdentifier AstAccountSetVar AstAttrType:66
 objectIdentifier AstAccountAllowOverlap AstAttrType:67
 objectIdentifier AstAccountVideoSupport AstAttrType:68
 objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
-objectIdentifier AstAccountPathSupport AstAttrType:70
+
 
 #############################################################################
 # Object Class OIDs
@@ -640,13 +640,6 @@ attributetype ( AstAccountIgnoreSDPVersion
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
 
-attributetype ( AstAccountPathSupport
-        NAME 'AstAccountPathSupport'
-        DESC 'Asterisk account support Path RFC 3327'
-        EQUALITY caseIgnoreMatch
-        SUBSTR caseIgnoreSubstringsMatch
-        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
-
 #############################################################################
 # Object Class definitions
 #
@@ -769,8 +762,7 @@ objectclass ( AsteriskSIPUser
         AstAccountTransport $
         AstAccountType $ 
         AstAccountUserAgent $	
-        AstAccountVideoSupport $
-        AstAccountPathSupport
+        AstAccountVideoSupport
     )
     )
 
diff --git a/contrib/scripts/asterisk.ldif b/contrib/scripts/asterisk.ldif
index 5621057..0546cdd 100644
--- a/contrib/scripts/asterisk.ldif
+++ b/contrib/scripts/asterisk.ldif
@@ -108,7 +108,6 @@ olcObjectIdentifier: AstAccountSetVar AstAttrType:66
 olcObjectIdentifier: AstAccountAllowOverlap AstAttrType:67
 olcObjectIdentifier: AstAccountVideoSupport AstAttrType:68
 olcObjectIdentifier: AstAccountIgnoreSDPVersion AstAttrType:69
-olcObjectIdentifier: AstAccountPathSupport AstAttrType:70
 #
 #
 #############################################################################
@@ -637,13 +636,6 @@ olcAttributeTypes: ( AstAccountIgnoreSDPVersion
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
 #
-olcAttributeTypes: ( AstAccountPathSupport
-        NAME 'AstAccountPathSupport'
-        DESC 'Asterisk account support Path RFC 3327'
-        EQUALITY caseIgnoreMatch
-        SUBSTR caseIgnoreSubstringsMatch
-        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
-#
 #############################################################################
 # Object Class definitions
 #
@@ -766,8 +758,7 @@ olcObjectClasses: ( AsteriskSIPUser
         AstAccountTransport $
         AstAccountType $
         AstAccountUserAgent $
-        AstAccountVideoSupport $
-        AstAccountPathSupport
+        AstAccountVideoSupport
     )
     )
 #
diff --git a/contrib/scripts/autosupport b/contrib/scripts/autosupport
index 4d5ab59..30cefe1 100644
--- a/contrib/scripts/autosupport
+++ b/contrib/scripts/autosupport
@@ -1,9 +1,9 @@
 #!/bin/sh
 #
-# Autosupport Version 2.1.0
+# Autosupport Version 2.0.18
 # Collect support information
 #
-# Copyright (C) 2005-2013, Digium, Inc.
+# Copyright (C) 2005-2011, Digium, Inc.
 #
 # Written by John Bigelow (support at digium.com)
 #            Charles Moye (cmoye at digium.com)
@@ -21,7 +21,7 @@
 # Ensure the PATH variable includes '/usr/sbin' and '/sbin'
 PATH=/usr/sbin:/sbin:${PATH}
 
-DATE_STAMP=$(date +%F)
+DATE_STAMP=$(date +%Y%m%d)
 OUTPUT_FILE=digiuminfo.txt
 TARBALL_OUTPUT_FILE="digium-info_${DATE_STAMP}.tar"
 VAR_LIB_LIST_FILE="list-of-varlibasterisk.txt"
@@ -30,7 +30,6 @@ FOLDER_PREFIX="${HOME}/"
 files="n";
 NONINTERACTIVE=0
 
-
 # If a prefix is specified on command-line, add it.
 if (set -u; : $1) 2> /dev/null
 then
@@ -38,7 +37,7 @@ then
   -h | --help)
     echo
     echo "Digium autosupport script"
-    echo "Copyright (C) 2005-2013, Digium, Inc."
+    echo "Copyright (C) 2005-2010, Digium, Inc."
     echo "Licensed under the terms of the GNU General Public License"
     echo
     echo "usage: autosupport [prefix]"
@@ -192,10 +191,7 @@ if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then
       "core show uptime" "pri show spans" "misdn show stacks" "zap show channels" "dahdi show status" "dahdi show channels" \
       "dahdi show channel 1" "core show channels" "skype show version" "skype show licenses" "skype show users" \
       "skype show hostid" "show g729" "g729 show version" "g729 show licenses" "g729 show hostid" "fax show version" \
-      "fax show licenses" "fax show hostid" "fax show stats" "digium_phones show version" "digium_phones show alerts" \
-			"digium_phones show applications" "digium_phones show firmwares" "digium_phones show lines" "digium_phones show networks" \
-			"digium_phones show phones" "digium_phones show sessions" "digium_phones show settings" "digium_phones show translations" ;
-	do
+      "fax show licenses" "fax show hostid" "fax show stats"; do
     echo "asterisk -rx \"$command\"" >> $OUTPUT;
     asterisk -rx "$command" >> $OUTPUT;
     echo >> $OUTPUT;
@@ -204,67 +200,6 @@ if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then
   echo >> $OUTPUT;
 fi
 
-
-for type in alerts applications firmwares lines networks phones translations; 
-do 
-	echo "------------------" >> $OUTPUT; 
-	echo "DIGIUM PHONE: $type " >> $OUTPUT; 
-	echo "------------------" >> $OUTPUT; 
-	TEMP=$(asterisk -rx "digium_phones show $type"); 
-	if [ "$type" = "lines" ];
-	then
-		NUM=$(echo $TEMP | tail -n 1 | awk -F' ' '{print $(NF-4)}');
-		if [ $NUM -gt 0 ];
-		then
-			for l in $(echo $TEMP | sed 's/^--- [[:alpha:]]\+ --- //; 
-				s/Lines \(Un-\)\?Mapped to Phones --- //g; 
-				s/ Internal//g; 
-				s/---- [a-zA-Z0-9 ]\+ ----$//;
-				s/--- //g');
-			do
-				asterisk -rx "digium_phones show line $l" >> $OUTPUT;                                                                      
-				echo "--------" >> $OUTPUT;                                                                                                                         
-				echo >> $OUTPUT; 
-			done
-		else
-			echo "No configurations of type $type..." >> $OUTPUT;
-			echo >> $OUTPUT;
-		fi;
-	elif [ "$type" = "firmwares" ];
-	then
-		for f in $(echo $TEMP | sed 's/--- Configured Firmware Options --- //');
-		do
-			asterisk -rx "digium_phones show firmware $f" >> $OUTPUT;
-			echo "--------" >> $OUTPUT;                                                                                                                         
-			echo >> $OUTPUT; 
-		done
-	elif [ "$type" = "translations" ];
-	then
-		for t in $(echo $TEMP | sed 's/--- Translation tables ---//');
-		do
-			asterisk -rx "digium_phones show translation $t" 
-		done
-	else
-		NUM=$(echo $TEMP | tail -n 1 | awk -F' ' '{print $(NF-3)}'); 
-		if [ $NUM -gt 0 ]; 
-		then   
-			for t in $(echo $TEMP | sed 's/^--- [[:alpha:]]\+ --- //; 
-																	 s/---- [a-zA-Z0-9 ]\+ ----$//
-																	 s/---- Digium Phones ---- //'); 
-			do 
-				asterisk -rx "digium_phones show $(echo $type | sed 's/s\b//') $t" >> $OUTPUT; 
-				echo "--------" >> $OUTPUT; 
-				echo >> $OUTPUT; 
-			done; 
-		else 
-			echo "No configurations of type $type..." >> $OUTPUT;
-			echo >> $OUTPUT;
-		fi;
-	fi;
-done;
-echo >> $OUTPUT;
-
-
 echo "------------------" >> $OUTPUT;
 echo "OTHER INFO : cat /etc/*{issue,release,version}*" >> $OUTPUT;
 echo "------------------" >> $OUTPUT;
@@ -457,26 +392,6 @@ for file in /lib/modules/$(uname -r)/build/.config /usr/src/linux/.config; do
 done
 echo >> $OUTPUT;
 
-FIRMWARE_DIR=`grep firmware_package_directory /etc/asterisk/res_digium_phone.conf|sed 's/;.*$//;'|grep firmware|sed 's/firmware_package_directory=//;'`;
-if [ `echo $FIRMWARE_DIR|egrep -v '^$'|wc -l` -eq "0" ]
-then
-  FIRMWARE_DIR="/var/www/firmware_package_directory"
-fi
-echo "------------------" >> $OUTPUT;
-echo "FIRMWARE LISTING: ls -al $FIRMWARE_DIR" >> $OUTPUT;
-echo "------------------" >> $OUTPUT;
-ls -al $FIRMWARE_DIR >> $OUTPUT;
-echo >> $OUTPUT;
-
-FIRMWARE_URLS=`grep file_url_prefix /etc/asterisk/res_digium_phone.conf|sed 's/;.*$//;'|grep file|sed 's/file_url_prefix=//;'`;
-for FIRMWARE_URL in $FIRMWARE_URLS; do
-  echo "------------------" >> $OUTPUT;
-  echo "REMOTE FIRMWARE LISTING: wget $FIRMWARE_URL" >> $OUTPUT;
-  echo "------------------" >> $OUTPUT;
-  wget "$FIRMWARE_URL" -O- 2>/dev/null >> $OUTPUT;
-  echo >> $OUTPUT;
-done
-
 echo "done!"
 }
 
diff --git a/contrib/scripts/clang-scan-build b/contrib/scripts/clang-scan-build
new file mode 100755
index 0000000..c5f93ac
--- /dev/null
+++ b/contrib/scripts/clang-scan-build
@@ -0,0 +1,136 @@
+#!/bin/bash
+#
+# clang-scan-build: configure and compile asterisk using the llvm static analyzer
+
+# Options/Flags:
+# -c|--compiler	: either [clang|gcc]
+# --cflags	: cflags you would like to add to the default set
+# --configure	: configure flags you would like to use instead off the default set
+# --make	: make flags you would like to use instead off the default set
+# --scanbuild	: scanbuild flags you would like to use instead of the default set
+# --outputdir	: directory where scan-build should create the html files
+# -h|--help	: this help
+
+# Usage:
+# contrib/scripts/clang-scan-build
+# This script will use clang if available and no compiler has been specified
+#
+# Example usage:
+#
+#   contrib/scripts/clang-scan-build
+#   contrib/scripts/clang-scan-build -c gcc
+#   contrib/scripts/clang-scan-build --compiler clang --configure "--enable-dev-mode" --outputdir="/tmp/scan-build_output"
+#   contrib/scripts/clang-scan-build --make "-j2"
+#
+# scan-build will generate html files during the make process, which will be stored in the specified outputdir or ./scan-build_output" by default
+
+# Copyright (C) 2015 Diederik de Groot <dddegroot at users.sf.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+# USA
+
+COMPILER=clang
+SCANBUILD="`which scan-build`"
+CFLAGS=""
+CONFIGURE_FLAGS="--enable-coverage --disable-xmldoc"
+MAKE_FLAGS=""
+SCANBUILD_FLAGS="-maxloop 10 -disable-checker deadcode.DeadStores -enable-checker alpha.core.BoolAssignment -enable-checker alpha.core.CallAndMessageUnInitRefArg -enable-checker alpha.core.CastSize -enable-checker alpha.core.CastToStruct -enable-checker alpha.core.IdenticalExpr -enable-checker alpha.core.PointerArithm -enable-checker alpha.core.PointerSub -enable-checker alpha.core.SizeofPtr -enable-checker alpha.core.TestAfterDivZero -enable-checker alpha.security.ArrayBound -enable-che [...]
+OUTPUTDIR="scan-build_output"
+
+function print_usage {
+cat << EOF
+$0 Usage:
+
+Options/Flags:
+-c|--compiler	: either [clang|gcc]
+--cflags	: cflags you would like to add to the default set:
+		  "${CFLAGS}"
+
+--configure	: configure flags you would like to use instead off the default set:
+		  "${CONFIGURE_FLAGS}"
+
+--make		: make flags you would like to use instead off the default set:
+		  "${MAKE_FLAGS}"
+
+--scanbuild	: scanbuild flags you would like to use instead of the default set:
+		  "${SCANBUILD_FLAGS}"
+
+--outputdir	: directory where scan-build should create the html files. default:
+		  "`pwd`/${OUTPUTDIR}"
+
+-h|--help	: this help
+EOF
+}
+
+for i in "$@"
+do
+	case $i in
+		-c=*|--compiler=*)
+			COMPILER="${i#*=}"
+			shift
+		;;
+		--cflags=*)
+			CFLAGS="${i#*=}"
+			shift
+		;;
+		--configure=*)
+			CONFIGURE_FLAGS="${i#*=}"
+			shift
+		;;
+		--make=*)
+			MAKE_FLAGS="${i#*=}"
+			shift
+		;;
+		--scanbuild=*)
+			SCANBUILD_FLAGS="${i#*=}"
+			shift
+		;;
+		--outputdir=*)
+			OUTPUTDIR="${i#*=}"
+			shift
+		;;
+		-h|--help)
+			print_usage
+			exit
+		;;
+	esac
+done
+
+if [ "${COMPILER}" == "clang" ] && [ ! -z "`which clang`" ]; then
+	CCC_CC="`which`clang"
+	CCC_CXX="`which clang++`"
+	CFLAGS="-fblocks ${CFLAGS}"
+elif [ "${COMPILER}" == "gcc" ] && [ ! -z "`which gcc`" ]; then
+	CCC_CC="`which gcc`"
+	CCC_CXX="`which g++`"
+	CFLAGS="${CFLAGS}"
+else
+	echo "Unknown compiler: $2, needs to be either clang or gcc"
+	exit
+fi
+
+if [ ! -f config.status ]; then
+	echo "Running ./configure ${CONFIGURE_FLAGS} ..."
+	${SCANBUILD} ${SCANBUILD_FLAGS} -o ${OUTPUTDIR} ./configure ${CONFIGURE_FLAGS}
+	if [ $? != 0 ]; then
+		echo "Configure error occurred, see output / config.log"
+		exit
+	fi
+	make clean
+fi
+if [ -f config.status ]; then
+	echo "Running scan-build make ${MAKE_FLAGS} ..."
+	${SCANBUILD} ${SCANBUILD_FLAGS} -o ${OUTPUTDIR} make ${MAKE_FLAGS}
+fi
diff --git a/contrib/scripts/dahdi_span_config_hook b/contrib/scripts/dahdi_span_config_hook
deleted file mode 100755
index 13f3395..0000000
--- a/contrib/scripts/dahdi_span_config_hook
+++ /dev/null
@@ -1,32 +0,0 @@
-#! /bin/sh
-
-# This script is intended to be called from
-# /usr/share/dahdi/dahdi_span_config, which is is typically called from
-# a udev hook script.
-#
-# Environment is set in
-# http://git.asterisk.org/gitweb/?p=dahdi/tools.git;a=blob;f=hotplug/dahdi_span_config
-
-if [ "$ACTION" != 'add' ]; then
-	# Nothing to do here
-	exit 0
-fi
-
-# Add to asterisk
-asterisk -rx "dahdi create channels $BASECHAN $ENDCHAN"
-#! /bin/sh
-
-# This script is intended to be called from
-# /usr/share/dahdi/dahdi_span_config, which is is typically called from
-# a udev hook script.
-#
-# Environment is set in
-# http://git.asterisk.org/gitweb/?p=dahdi/tools.git;a=blob;f=hotplug/dahdi_span_config
-
-if [ "$ACTION" != 'add' ]; then
-	# Nothing to do here
-	exit 0
-fi
-
-# Add to asterisk
-asterisk -rx "dahdi create channels $BASECHAN $ENDCHAN"
diff --git a/contrib/scripts/dbsep.cgi b/contrib/scripts/dbsep.cgi
index 4e80479..d15390c 100755
--- a/contrib/scripts/dbsep.cgi
+++ b/contrib/scripts/dbsep.cgi
@@ -14,7 +14,7 @@
 # the GNU General Public License Version 2. See the LICENSE file
 # at the top of the source tree.
 #
-# $Id: dbsep.cgi 253758 2010-03-22 19:05:27Z tilghman $
+# $Id$
 #
 
 use CGI;
diff --git a/contrib/scripts/get_swagger_ui.sh b/contrib/scripts/get_swagger_ui.sh
deleted file mode 100755
index f6e9ced..0000000
--- a/contrib/scripts/get_swagger_ui.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-#
-# Downloads Swagger-UI to put in static-http.
-#
-# Swagger-UI is a Swagger compliant HTML+JavaScript web app, which can be used
-# to browse ARI (Asterisk REST Interface).
-#
-
-PROGNAME=$(basename $0)
-
-: ${GIT:=git}
-: ${REPO:=https://github.com/leedm777/swagger-ui.git}
-: ${BRANCH:=asterisk}
-
-if ! test -d static-http; then
-    echo "${PROGNAME}: Must run from Asterisk source directory" >&2
-    exit 1
-fi
-
-set -ex
-
-CLONE_DIR=$(mktemp -d /tmp/swagger-ui.XXXXXX) || exit 1
-trap "rm -rf ${CLONE_DIR}" EXIT
-
-${GIT} clone -q -b ${BRANCH} ${REPO} ${CLONE_DIR}
-
-rm -rf static-http/swagger-ui
-cp -a ${CLONE_DIR}/dist static-http/swagger-ui
-
-cat <<EOF
-Swagger-UI downloaded. Install using 'make install'.
-
-To use, enable  ARI (ari.conf), the HTTP server (http.conf) and static
-content (also http.conf).
-EOF
diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq
index a6127a9..f75037e 100755
--- a/contrib/scripts/install_prereq
+++ b/contrib/scripts/install_prereq
@@ -1,6 +1,6 @@
 #! /bin/sh
 #
-# $Id: install_prereq 395985 2013-08-01 17:07:52Z kmoore $
+# $Id$
 #
 
 # install_prereq: a script to install distribution-specific
@@ -9,13 +9,13 @@
 set -e
 
 usage() {
-	echo "$0: a script to install distribution-specific prerequirement"
-	echo 'Revision: $Id: install_prereq 395985 2013-08-01 17:07:52Z kmoore $'
-	echo ""
-	echo "Usage: $0:                    Shows this message."
-	echo "Usage: $0 test                Prints commands it is about to run."
-	echo "Usage: $0 install             Really install."
-	echo "Usage: $0 install-unpackaged  Really install unpackaged requirements."
+  echo "$0: a script to install distribution-specific prerequirement"
+  echo 'Revision: $Id$'
+  echo ""
+  echo "Usage: $0:                    Shows this message."
+  echo "Usage: $0 test                Prints commands it is about to run."
+  echo "Usage: $0 install             Really install."
+  echo "Usage: $0 install-unpackaged  Really install unpackaged requirements."
 }
 
 # Basic build system:
@@ -27,42 +27,26 @@ PACKAGES_DEBIAN="$PACKAGES_DEBIAN libcurl-dev libspeex-dev libspeexdsp-dev libog
 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libsqlite0-dev libmysqlclient15-dev libneon27-dev libgmime-dev libusb-dev liblua5.1-0-dev lua5.1"
 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libopenh323-dev libvpb-dev libgtk2.0-dev libmysqlclient-dev libbluetooth-dev libradiusclient-ng-dev freetds-dev"
 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev libjack-dev"
-PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample-dev libc-client-dev binutils-dev libsrtp-dev libgsm1-dev libedit-dev doxygen libjansson-dev libldap-dev"
-PACKAGES_DEBIAN="$PACKAGES_DEBIAN subversion git libxslt1-dev"
+PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample-dev libc-client-dev binutils-dev libsrtp-dev libgsm1-dev libedit-dev libldap-dev"
 PACKAGES_RH="automake gcc gcc-c++ ncurses-devel openssl-devel libxml2-devel unixODBC-devel libcurl-devel libogg-devel libvorbis-devel speex-devel"
 PACKAGES_RH="$PACKAGES_RH spandsp-devel freetds-devel net-snmp-devel iksemel-devel corosynclib-devel newt-devel popt-devel libtool-ltdl-devel lua-devel"
-PACKAGES_RH="$PACKAGES_RH libsqlite3x-devel radiusclient-ng-devel portaudio-devel postgresql-devel libresample-devel neon-devel libical-devel"
+PACKAGES_RH="$PACKAGES_RH sqlite-devel libsqlite3x-devel radiusclient-ng-devel portaudio-devel postgresql-devel libresample-devel neon-devel libical-devel"
 PACKAGES_RH="$PACKAGES_RH openldap-devel gmime22-devel sqlite2-devel mysql-devel bluez-libs-devel jack-audio-connection-kit-devel gsm-devel libedit-devel libuuid-devel"
-PACKAGES_RH="$PACKAGES_RH jansson-devel libsrtp-devel pjproject-devel subversion git libxslt-devel"
 
-PACKAGES_OBSD="popt gmake wget libxml libogg libvorbis curl iksemel spandsp speex iodbc freetds-0.63p1-msdblib mysql-client gmime sqlite sqlite3 jack libxslt"
+PACKAGES_OBSD="popt gmake wget libxml libogg libvorbis curl iksemel spandsp speex iodbc freetds-0.63p1-msdblib mysql-client gmime sqlite sqlite3 jack"
 
 KVERS=`uname -r`
 
-JANSSON_VER=2.4
-
 case "$1" in
-test)
-	testcmd=echo
-	;;
-install)
-	testcmd=''
-	;;
-install-unpackaged)
-	unpackaged="yes"
-	;;
-'')
-	usage
-	exit 0
-	;;
-*)
-	usage
-	exit 1
-	;;
+test)    testcmd=echo ;;
+install) testcmd='' ;;
+install-unpackaged) unpackaged="yes" ;;
+'') usage; exit 0 ;;
+*) usage; exit 1 ;;
 esac
 
 in_test_mode() {
-	test "$testcmd" != ''
+  test "$testcmd" != ''
 }
 
 check_installed_debs() {
@@ -71,7 +55,8 @@ check_installed_debs() {
 		tocheck="${tocheck} ^${pack}$"
 	done
 	aptitude -F '%c %p' search ${tocheck} 2>/dev/null \
- 	| awk '/^p/{print $2}'
+		| awk '/^p/{print $2}' \
+		| grep -v ':i386$'
 }
 
 # parsing the output of yum is close to impossible.
@@ -95,16 +80,20 @@ check_installed_pkgs() {
 }
 
 handle_debian() {
+	# echo "# Distribution is Debian or compatible"
 	extra_packs=`check_installed_debs $PACKAGES_DEBIAN`
 	$testcmd aptitude install -y $extra_packs
 }
 
 handle_rh() {
+	# echo "# Distribution is RedHat-based or compatible"
 	extra_packs=`check_installed_rpms $PACKAGES_RH`
+        # FIXME: is there yum with RHEL 4?
 	$testcmd yum install -y $extra_packs
 }
 
 handle_obsd() {
+	# echo "# Distribution is OpenBSD or compatible"
 	extra_packs=`check_installed_pkgs $PACKAGES_OBSD`
 	$testcmd pkg_add $extra_packs
 }
@@ -116,57 +105,11 @@ install_unpackaged() {
 	make && make install
 	cd ..
 
-	# Only install libresample if it wasn't installed via package
-	if ! test -f /usr/include/libresample.h; then
-		echo "*** Installing libresample ***"
-		svn co http://svn.digium.com/svn/thirdparty/libresample/trunk libresample-trunk
-		cd libresample-trunk
-		./configure && make && make install
-		cd ..
-	fi
-
-	# Only install Jansson if it wasn't installed via package
-	if ! test -f /usr/include/jansson.h; then
-		echo "*** Installing jansson ***"
-		wget -O - http://www.digip.org/jansson/releases/jansson-${JANSSON_VER}.tar.gz | zcat | tar -xf -
-		cd jansson-${JANSSON_VER}
-		./configure && make all && make install
-		cd ..
-		echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf
-		/sbin/ldconfig
-	fi
-
-	# Only install libsrtp if it wasn't installed via package
-	if ! test -f /usr/include/srtp/srtp.h; then
-		echo "*** Installing libsrtp ***"
-		if [ ! -d libsrtp ]; then
-			git clone https://github.com/cisco/libsrtp.git
-			cd libsrtp
-		else
-			cd libsrtp
-			git pull
-		fi
-		./configure CFLAGS=-fPIC && make libsrtp.a && make uninstall && make install
-		cd ..
-		echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf
-		/sbin/ldconfig
-	fi
-
-	# Only install pjproject if it wasn't installed via package
-	if ! test -f /usr/include/pjlib.h; then
-		echo "*** Installing pjproject ***"
-		if [ ! -d pjproject ]; then
-			git clone https://github.com/asterisk/pjproject.git
-			cd pjproject
-		else
-			cd pjproject
-			git pull
-		fi
-		./configure --enable-shared --with-external-speex --with-external-gsm --with-external-srtp --disable-sound --disable-resample && make && make install
-		cd ..
-		echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf
-		/sbin/ldconfig
-	fi
+	echo "*** Installing libresample ***"
+	svn co http://svn.digium.com/svn/thirdparty/libresample/trunk libresample-trunk
+	cd libresample-trunk
+	./configure && make && make install
+	cd ..
 }
 
 if in_test_mode; then
@@ -184,42 +127,42 @@ unsupported_distro=''
 
 # A number of distributions we don't (yet?) support.
 if [ "$OS" != 'Linux' -a "$OS" != 'OpenBSD' ]; then
-	echo >&2 "$0: Your OS ($OS) is currently not supported. Aborting."
-	exit 1
+  echo >&2 "$0: Your OS ($OS) is currently not supported. Aborting."
+  exit 1
 fi
 
 if [ -f /etc/gentoo-release ]; then
-	unsupported_distro='Gentoo'
+  unsupported_distro='Gentoo'
 fi
 
 if [ -f /etc/mandrake-release ]; then
-	unsupported_distro='Mandriva'
+  unsupported_distro='Mandriva'
 fi
 
 if [ -f /etc/SuSE-release ]; then
-	unsupported_distro='SUSE'
+  unsupported_distro='SUSE'
 fi
 
 if [ -f /etc/slackware-version ]; then
-	unsupported_distro='Slackware'
+  unsupported_distro='Slackware'
 fi
 
 if [ "$unsupported_distro" != '' ]; then
-	echo >&2 "$0: Your distribution ($unsupported_distro) is currently not supported. Aborting."
-	exit 1
+  echo >&2 "$0: Your distribution ($unsupported_distro) is currently not supported. Aborting."
+  exit 1
 fi
 
 # The distributions we do support:
 if [ -r /etc/debian_version ]; then
-	handle_debian
+  handle_debian
 elif [ -r /etc/redhat-release ]; then
-	handle_rh
+  handle_rh
 elif [ "$OS" = 'OpenBSD' ]; then
-	handle_obsd
+  handle_obsd
 fi
 
 if ! in_test_mode; then
-	echo "#############################################"
-	echo "## $1 completed successfully"
-	echo "#############################################"
+  echo "#############################################"
+  echo "## $1 completed successfully"
+  echo "#############################################"
 fi
diff --git a/contrib/scripts/live_ast b/contrib/scripts/live_ast
index 0b5151f..188720f 100755
--- a/contrib/scripts/live_ast
+++ b/contrib/scripts/live_ast
@@ -251,11 +251,11 @@ conf-file)
   ;;
 run)
   set_ld_env
-  exec $AST_BIN -C $AST_CONF "$@"
+  $AST_BIN -C $AST_CONF "$@"
   ;;
 valgrind)
   set_ld_env
-  exec valgrind $LIVE_AST_VALGRIND_ARGS $AST_BIN -C $AST_CONF "$@"
+  valgrind $LIVE_AST_VALGRIND_ARGS $AST_BIN -C $AST_CONF "$@"
   ;;
 rsync)
   remote_host="$1"
@@ -273,7 +273,7 @@ gen-live-asterisk)
   ;;
 gdb)
   set_ld_env
-  exec gdb -x $GDB_INIT $AST_BIN
+  gdb -x $GDB_INIT $AST_BIN
   ;;
 *)
   echo "$0: Unknown command '$command'. Aborting"
diff --git a/contrib/scripts/retrieve_extensions_from_sql.pl b/contrib/scripts/retrieve_extensions_from_sql.pl
index 848dbec..cf17d03 100644
--- a/contrib/scripts/retrieve_extensions_from_sql.pl
+++ b/contrib/scripts/retrieve_extensions_from_sql.pl
@@ -16,7 +16,7 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
-# $Id: retrieve_extensions_from_sql.pl 9991 2006-02-14 19:14:15Z kpfleming $
+# $Id$
 #
 # Use these commands to create the appropriate SQL tables
 # If flags is 1 then the record is not included in the output extensions file
diff --git a/contrib/scripts/safe_asterisk b/contrib/scripts/safe_asterisk
index 62f3dad..60d9806 100644
--- a/contrib/scripts/safe_asterisk
+++ b/contrib/scripts/safe_asterisk
@@ -1,6 +1,5 @@
 #!/bin/sh
 
-ASTETCDIR="__ASTERISK_ETC_DIR__"
 ASTSBINDIR="__ASTERISK_SBIN_DIR__"
 ASTVARRUNDIR="__ASTERISK_VARRUN_DIR__"
 ASTVARLOGDIR="__ASTERISK_LOG_DIR__"
@@ -152,10 +151,10 @@ trap '' PIPE
 # Run scripts to set any environment variables or do any other system-specific setup needed
 #
 
-if test -d "${ASTETCDIR}/startup.d"; then
-	for script in "${ASTETCDIR}/startup.d/"*.sh; do
-		if test -r "${script}"; then
-			. "${script}"
+if test -d /etc/asterisk/startup.d; then
+	for script in /etc/asterisk/startup.d/*.sh; do
+		if test -r ${script}; then
+			. ${script}
 		fi
 	done
 fi
@@ -179,10 +178,10 @@ run_asterisk()
 			exit 0
 		elif test $EXITSTATUS -gt 128; then
 			EXITSIGNAL=$((EXITSTATUS - 128))
-			message "Asterisk exited on signal $EXITSIGNAL."
+			message "Exited on signal $EXITSIGNAL"
 			if test -n "$NOTIFY"; then
 				echo "Asterisk on $MACHINE exited on signal $EXITSIGNAL.  Might want to take a peek." | \
-				mail -s "Asterisk on $MACHINE died (sig $EXITSIGNAL)" $NOTIFY
+				mail -s "Asterisk Died" $NOTIFY
 			fi
 			if test -n "$EXEC"; then
 				$EXEC
diff --git a/contrib/scripts/sip_to_pjsip/astconfigparser.py b/contrib/scripts/sip_to_pjsip/astconfigparser.py
deleted file mode 100644
index c93173d..0000000
--- a/contrib/scripts/sip_to_pjsip/astconfigparser.py
+++ /dev/null
@@ -1,467 +0,0 @@
-import re
-
-from astdicts import OrderedDict
-from astdicts import MultiOrderedDict
-
-
-def merge_values(left, right, key):
-    """Merges values from right into left."""
-    if isinstance(left, list):
-        vals0 = left
-    else:  # assume dictionary
-        vals0 = left[key] if key in left else []
-    vals1 = right[key] if key in right else []
-
-    return vals0 + [i for i in vals1 if i not in vals0]
-
-###############################################################################
-
-
-class Section(MultiOrderedDict):
-    """
-    A Section is a MultiOrderedDict itself that maintains a list of
-    key/value options.  However, in the case of an Asterisk config
-    file a section may have other defaults sections that is can pull
-    data from (i.e. templates).  So when an option is looked up by key
-    it first checks the base section and if not found looks in the
-    added default sections. If not found at that point then a 'KeyError'
-    exception is raised.
-    """
-    count = 0
-
-    def __init__(self, defaults=None, templates=None):
-        MultiOrderedDict.__init__(self)
-        # track an ordered id of sections
-        Section.count += 1
-        self.id = Section.count
-        self._defaults = [] if defaults is None else defaults
-        self._templates = [] if templates is None else templates
-
-    def __cmp__(self, other):
-        """
-        Use self.id as means of determining equality
-        """
-        return cmp(self.id, other.id)
-
-    def get(self, key, from_self=True, from_templates=True,
-            from_defaults=True):
-        """
-        Get the values corresponding to a given key. The parameters to this
-        function form a hierarchy that determines priority of the search.
-        from_self takes priority over from_templates, and from_templates takes
-        priority over from_defaults.
-
-        Parameters:
-        from_self - If True, search within the given section.
-        from_templates - If True, search in this section's templates.
-        from_defaults - If True, search within this section's defaults.
-        """
-        if from_self and key in self:
-            return MultiOrderedDict.__getitem__(self, key)
-
-        if from_templates:
-            if self in self._templates:
-                return []
-            for t in self._templates:
-                try:
-                    # fail if not found on the search - doing it this way
-                    # allows template's templates to be searched.
-                    return t.get(key, True, from_templates, from_defaults)
-                except KeyError:
-                    pass
-
-        if from_defaults:
-            for d in self._defaults:
-                try:
-                    return d.get(key, True, from_templates, from_defaults)
-                except KeyError:
-                    pass
-
-        raise KeyError(key)
-
-    def __getitem__(self, key):
-        """
-        Get the value for the given key. If it is not found in the 'self'
-        then check inside templates and defaults before declaring raising
-        a KeyError exception.
-        """
-        return self.get(key)
-
-    def keys(self, self_only=False):
-        """
-        Get the keys from this section. If self_only is True, then
-        keys from this section's defaults and templates are not
-        included in the returned value
-        """
-        res = MultiOrderedDict.keys(self)
-        if self_only:
-            return res
-
-        for d in self._templates:
-            for key in d.keys():
-                if key not in res:
-                    res.append(key)
-
-        for d in self._defaults:
-            for key in d.keys():
-                if key not in res:
-                    res.append(key)
-        return res
-
-    def add_defaults(self, defaults):
-        """
-        Add a list of defaults to the section. Defaults are
-        sections such as 'general'
-        """
-        defaults.sort()
-        for i in defaults:
-            self._defaults.insert(0, i)
-
-    def add_templates(self, templates):
-        """
-        Add a list of templates to the section.
-        """
-        templates.sort()
-        for i in templates:
-            self._templates.insert(0, i)
-
-    def get_merged(self, key):
-        """Return a list of values for a given key merged from default(s)"""
-        # first merge key/values from defaults together
-        merged = []
-        for i in reversed(self._defaults):
-            if not merged:
-                merged = i
-                continue
-            merged = merge_values(merged, i, key)
-
-        for i in reversed(self._templates):
-            if not merged:
-                merged = i
-                continue
-            merged = merge_values(merged, i, key)
-
-        # then merge self in
-        return merge_values(merged, self, key)
-
-###############################################################################
-
-COMMENT = ';'
-COMMENT_START = ';--'
-COMMENT_END = '--;'
-
-DEFAULTSECT = 'general'
-
-
-def remove_comment(line, is_comment):
-    """Remove any commented elements from the line."""
-    if not line:
-        return line, is_comment
-
-    if is_comment:
-        part = line.partition(COMMENT_END)
-        if part[1]:
-            # found multi-line comment end check string after it
-            return remove_comment(part[2], False)
-        return "", True
-
-    part = line.partition(COMMENT_START)
-    if part[1]:
-        # found multi-line comment start check string before
-        # it to make sure there wasn't an eol comment in it
-        has_comment = part[0].partition(COMMENT)
-        if has_comment[1]:
-            # eol comment found return anything before it
-            return has_comment[0], False
-
-        # check string after it to see if the comment ends
-        line, is_comment = remove_comment(part[2], True)
-        if is_comment:
-            # return possible string data before comment
-            return part[0].strip(), True
-
-        # otherwise it was an embedded comment so combine
-        return ''.join([part[0].strip(), ' ', line]).rstrip(), False
-
-    # check for eol comment
-    return line.partition(COMMENT)[0].strip(), False
-
-
-def try_include(line):
-    """
-    Checks to see if the given line is an include.  If so return the
-    included filename, otherwise None.
-    """
-
-    match = re.match('^#include\s*[<"]?(.*)[>"]?$', line)
-    return match.group(1) if match else None
-
-
-def try_section(line):
-    """
-    Checks to see if the given line is a section. If so return the section
-    name, otherwise return 'None'.
-    """
-    # leading spaces were stripped when checking for comments
-    if not line.startswith('['):
-        return None, False, []
-
-    section, delim, templates = line.partition(']')
-    if not templates:
-        return section[1:], False, []
-
-    # strip out the parens and parse into an array
-    templates = templates.replace('(', "").replace(')', "").split(',')
-    # go ahead and remove extra whitespace
-    templates = [i.strip() for i in templates]
-    try:
-        templates.remove('!')
-        return section[1:], True, templates
-    except:
-        return section[1:], False, templates
-
-
-def try_option(line):
-    """Parses the line as an option, returning the key/value pair."""
-    data = re.split('=>?', line)
-    # should split in two (key/val), but either way use first two elements
-    return data[0].rstrip(), data[1].lstrip()
-
-###############################################################################
-
-
-def find_dict(mdicts, key, val):
-    """
-    Given a list of mult-dicts, return the multi-dict that contains
-    the given key/value pair.
-    """
-
-    def found(d):
-        return key in d and val in d[key]
-
-    try:
-        return [d for d in mdicts if found(d)][0]
-    except IndexError:
-        raise LookupError("Dictionary not located for key = %s, value = %s"
-                          % (key, val))
-
-
-def write_dicts(config_file, mdicts):
-    """Write the contents of the mdicts to the specified config file"""
-    for section, sect_list in mdicts.iteritems():
-        # every section contains a list of dictionaries
-        for sect in sect_list:
-            config_file.write("[%s]\n" % section)
-            for key, val_list in sect.iteritems():
-                # every value is also a list
-                for v in val_list:
-                    key_val = key
-                    if v is not None:
-                        key_val += " = " + str(v)
-                        config_file.write("%s\n" % (key_val))
-            config_file.write("\n")
-
-###############################################################################
-
-
-class MultiOrderedConfigParser:
-    def __init__(self, parent=None):
-        self._parent = parent
-        self._defaults = MultiOrderedDict()
-        self._sections = MultiOrderedDict()
-        self._includes = OrderedDict()
-
-    def find_value(self, sections, key):
-        """Given a list of sections, try to find value(s) for the given key."""
-        # always start looking in the last one added
-        sections.sort(reverse=True)
-        for s in sections:
-            try:
-                # try to find in section and section's templates
-                return s.get(key, from_defaults=False)
-            except KeyError:
-                pass
-
-        # wasn't found in sections or a section's templates so check in
-        # defaults
-        for s in sections:
-            try:
-                # try to find in section's defaultsects
-                return s.get(key, from_self=False, from_templates=False)
-            except KeyError:
-                pass
-
-        raise KeyError(key)
-
-    def defaults(self):
-        return self._defaults
-
-    def default(self, key):
-        """Retrieves a list of dictionaries for a default section."""
-        return self.get_defaults(key)
-
-    def add_default(self, key, template_keys=None):
-        """
-        Adds a default section to defaults, returning the
-        default Section object.
-        """
-        if template_keys is None:
-            template_keys = []
-        return self.add_section(key, template_keys, self._defaults)
-
-    def sections(self):
-        return self._sections
-
-    def section(self, key):
-        """Retrieves a list of dictionaries for a section."""
-        return self.get_sections(key)
-
-    def get_sections(self, key, attr='_sections', searched=None):
-        """
-        Retrieve a list of sections that have values for the given key.
-        The attr parameter can be used to control what part of the parser
-        to retrieve values from.
-        """
-        if searched is None:
-            searched = []
-        if self in searched:
-            return []
-
-        sections = getattr(self, attr)
-        res = sections[key] if key in sections else []
-        searched.append(self)
-        if self._includes:
-            res += self._includes.get_sections(key, attr, searched)
-        if self._parent:
-            res += self._parent.get_sections(key, attr, searched)
-        return res
-
-    def get_defaults(self, key):
-        """
-        Retrieve a list of defaults that have values for the given key.
-        """
-        return self.get_sections(key, '_defaults')
-
-    def add_section(self, key, template_keys=None, mdicts=None):
-        """
-        Create a new section in the configuration. The name of the
-        new section is the 'key' parameter.
-        """
-        if template_keys is None:
-            template_keys = []
-        if mdicts is None:
-            mdicts = self._sections
-        res = Section()
-        for t in template_keys:
-            res.add_templates(self.get_defaults(t))
-        res.add_defaults(self.get_defaults(DEFAULTSECT))
-        mdicts.insert(0, key, res)
-        return res
-
-    def includes(self):
-        return self._includes
-
-    def add_include(self, filename, parser=None):
-        """
-        Add a new #include file to the configuration.
-        """
-        if filename in self._includes:
-            return self._includes[filename]
-
-        self._includes[filename] = res = \
-            MultiOrderedConfigParser(self) if parser is None else parser
-        return res
-
-    def get(self, section, key):
-        """Retrieves the list of values from a section for a key."""
-        try:
-            # search for the value in the list of sections
-            return self.find_value(self.section(section), key)
-        except KeyError:
-            pass
-
-        try:
-            # section may be a default section so, search
-            # for the value in the list of defaults
-            return self.find_value(self.default(section), key)
-        except KeyError:
-            raise LookupError("key %r not found for section %r"
-                              % (key, section))
-
-    def multi_get(self, section, key_list):
-        """
-        Retrieves the list of values from a section for a list of keys.
-        This method is intended to be used for equivalent keys. Thus, as soon
-        as any match is found for any key in the key_list, the match is
-        returned. This does not concatenate the lookups of all of the keys
-        together.
-        """
-        for i in key_list:
-            try:
-                return self.get(section, i)
-            except LookupError:
-                pass
-
-        # Making it here means all lookups failed.
-        raise LookupError("keys %r not found for section %r" %
-                          (key_list, section))
-
-    def set(self, section, key, val):
-        """Sets an option in the given section."""
-        # TODO - set in multiple sections? (for now set in first)
-        # TODO - set in both sections and defaults?
-        if section in self._sections:
-            self.section(section)[0][key] = val
-        else:
-            self.defaults(section)[0][key] = val
-
-    def read(self, filename):
-        """Parse configuration information from a file"""
-        try:
-            with open(filename, 'rt') as config_file:
-                self._read(config_file)
-        except IOError:
-            print "Could not open file ", filename, " for reading"
-
-    def _read(self, config_file):
-        """Parse configuration information from the config_file"""
-        is_comment = False  # used for multi-lined comments
-        for line in config_file:
-            line, is_comment = remove_comment(line, is_comment)
-            if not line:
-                # line was empty or was a comment
-                continue
-
-            include_name = try_include(line)
-            if include_name:
-                parser = self.add_include(include_name)
-                parser.read(include_name)
-                continue
-
-            section, is_template, templates = try_section(line)
-            if section:
-                if section == DEFAULTSECT or is_template:
-                    sect = self.add_default(section, templates)
-                else:
-                    sect = self.add_section(section, templates)
-                continue
-
-            key, val = try_option(line)
-            sect[key] = val
-
-    def write(self, config_file):
-        """Write configuration information out to a file"""
-        try:
-            for key, val in self._includes.iteritems():
-                val.write(key)
-                config_file.write('#include "%s"\n' % key)
-
-            config_file.write('\n')
-            write_dicts(config_file, self._defaults)
-            write_dicts(config_file, self._sections)
-        except:
-            try:
-                with open(config_file, 'wt') as fp:
-                    self.write(fp)
-            except IOError:
-                print "Could not open file ", config_file, " for writing"
diff --git a/contrib/scripts/sip_to_pjsip/astdicts.py b/contrib/scripts/sip_to_pjsip/astdicts.py
deleted file mode 100644
index ae63075..0000000
--- a/contrib/scripts/sip_to_pjsip/astdicts.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
-# Passes Python2.7's test suite and incorporates all the latest updates.
-# copied from http://code.activestate.com/recipes/576693/
-
-try:
-    from thread import get_ident as _get_ident
-except ImportError:
-    from dummy_thread import get_ident as _get_ident
-
-try:
-    from _abcoll import KeysView, ValuesView, ItemsView
-except ImportError:
-    pass
-
-
-class OrderedDict(dict):
-    'Dictionary that remembers insertion order'
-    # An inherited dict maps keys to values.
-    # The inherited dict provides __getitem__, __len__, __contains__, and get.
-    # The remaining methods are order-aware.
-    # Big-O running times for all methods are the same as for regular dictionaries.
-
-    # The internal self.__map dictionary maps keys to links in a doubly linked list.
-    # The circular doubly linked list starts and ends with a sentinel element.
-    # The sentinel element never gets deleted (this simplifies the algorithm).
-    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
-
-    def __init__(self, *args, **kwds):
-        '''Initialize an ordered dictionary.  Signature is the same as for
-        regular dictionaries, but keyword arguments are not recommended
-        because their insertion order is arbitrary.
-
-        '''
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__root
-        except AttributeError:
-            self.__root = root = []                     # sentinel node
-            root[:] = [root, root, None]
-            self.__map = {}
-        self.__update(*args, **kwds)
-
-    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
-        'od.__setitem__(i, y) <==> od[i]=y'
-        # Setting a new item creates a new link which goes at the end of the linked
-        # list, and the inherited dictionary is updated with the new key/value pair.
-        if key not in self:
-            root = self.__root
-            last = root[0]
-            last[1] = root[0] = self.__map[key] = [last, root, key]
-        dict_setitem(self, key, value)
-
-    def __delitem__(self, key, dict_delitem=dict.__delitem__):
-        'od.__delitem__(y) <==> del od[y]'
-        # Deleting an existing item uses self.__map to find the link which is
-        # then removed by updating the links in the predecessor and successor nodes.
-        dict_delitem(self, key)
-        link_prev, link_next, key = self.__map.pop(key)
-        link_prev[1] = link_next
-        link_next[0] = link_prev
-
-    def __iter__(self):
-        'od.__iter__() <==> iter(od)'
-        root = self.__root
-        curr = root[1]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[1]
-
-    def __reversed__(self):
-        'od.__reversed__() <==> reversed(od)'
-        root = self.__root
-        curr = root[0]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[0]
-
-    def clear(self):
-        'od.clear() -> None.  Remove all items from od.'
-        try:
-            for node in self.__map.itervalues():
-                del node[:]
-            root = self.__root
-            root[:] = [root, root, None]
-            self.__map.clear()
-        except AttributeError:
-            pass
-        dict.clear(self)
-
-    def popitem(self, last=True):
-        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
-        Pairs are returned in LIFO order if last is true or FIFO order if false.
-
-        '''
-        if not self:
-            raise KeyError('dictionary is empty')
-        root = self.__root
-        if last:
-            link = root[0]
-            link_prev = link[0]
-            link_prev[1] = root
-            root[0] = link_prev
-        else:
-            link = root[1]
-            link_next = link[1]
-            root[1] = link_next
-            link_next[0] = root
-        key = link[2]
-        del self.__map[key]
-        value = dict.pop(self, key)
-        return key, value
-
-    # -- the following methods do not depend on the internal structure --
-
-    def keys(self):
-        'od.keys() -> list of keys in od'
-        return list(self)
-
-    def values(self):
-        'od.values() -> list of values in od'
-        return [self[key] for key in self]
-
-    def items(self):
-        'od.items() -> list of (key, value) pairs in od'
-        return [(key, self[key]) for key in self]
-
-    def iterkeys(self):
-        'od.iterkeys() -> an iterator over the keys in od'
-        return iter(self)
-
-    def itervalues(self):
-        'od.itervalues -> an iterator over the values in od'
-        for k in self:
-            yield self[k]
-
-    def iteritems(self):
-        'od.iteritems -> an iterator over the (key, value) items in od'
-        for k in self:
-            yield (k, self[k])
-
-    def update(*args, **kwds):
-        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
-
-        If E is a dict instance, does:           for k in E: od[k] = E[k]
-        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
-        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
-        In either case, this is followed by:     for k, v in F.items(): od[k] = v
-
-        '''
-        if len(args) > 2:
-            raise TypeError('update() takes at most 2 positional '
-                            'arguments (%d given)' % (len(args),))
-        elif not args:
-            raise TypeError('update() takes at least 1 argument (0 given)')
-        self = args[0]
-        # Make progressively weaker assumptions about "other"
-        other = ()
-        if len(args) == 2:
-            other = args[1]
-        if isinstance(other, dict):
-            for key in other:
-                self[key] = other[key]
-        elif hasattr(other, 'keys'):
-            for key in other.keys():
-                self[key] = other[key]
-        else:
-            for key, value in other:
-                self[key] = value
-        for key, value in kwds.items():
-            self[key] = value
-
-    __update = update  # let subclasses override update without breaking __init__
-
-    __marker = object()
-
-    def pop(self, key, default=__marker):
-        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-        If key is not found, d is returned if given, otherwise KeyError is raised.
-
-        '''
-        if key in self:
-            result = self[key]
-            del self[key]
-            return result
-        if default is self.__marker:
-            raise KeyError(key)
-        return default
-
-    def setdefault(self, key, default=None):
-        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
-        if key in self:
-            return self[key]
-        self[key] = default
-        return default
-
-    def __repr__(self, _repr_running={}):
-        'od.__repr__() <==> repr(od)'
-        call_key = id(self), _get_ident()
-        if call_key in _repr_running:
-            return '...'
-        _repr_running[call_key] = 1
-        try:
-            if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
-        finally:
-            del _repr_running[call_key]
-
-    def __reduce__(self):
-        'Return state information for pickling'
-        items = [[k, self[k]] for k in self]
-        inst_dict = vars(self).copy()
-        for k in vars(OrderedDict()):
-            inst_dict.pop(k, None)
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def copy(self):
-        'od.copy() -> a shallow copy of od'
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
-        and values equal to v (which defaults to None).
-
-        '''
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
-        while comparison to a regular mapping is order-insensitive.
-
-        '''
-        if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
-
-    # -- the following methods are only used in Python 2.7 --
-
-    def viewkeys(self):
-        "od.viewkeys() -> a set-like object providing a view on od's keys"
-        return KeysView(self)
-
-    def viewvalues(self):
-        "od.viewvalues() -> an object providing a view on od's values"
-        return ValuesView(self)
-
-    def viewitems(self):
-        "od.viewitems() -> a set-like object providing a view on od's items"
-        return ItemsView(self)
-
-###############################################################################
-### MultiOrderedDict
-###############################################################################
-class MultiOrderedDict(OrderedDict):
-    def __init__(self, *args, **kwds):
-        OrderedDict.__init__(self, *args, **kwds)
-
-    def __setitem__(self, key, val, i=None):
-        if key not in self:
-#            print "__setitem__ key = ", key, " val = ", val
-            OrderedDict.__setitem__(
-                self, key, val if isinstance(val, list) else [val])
-            return
-#        print "inserting key = ", key, " val = ", val
-        vals = self[key]
-        if i is None:
-            i = len(vals)
-
-        if not isinstance(val, list):
-            if val not in vals:
-                vals.insert(i, val)
-        else:
-            for j in val.reverse():
-                if j not in vals:
-                    vals.insert(i, j)
-
-
-    def insert(self, i, key, val):
-        self.__setitem__(key, val, i)
-
-    def copy(self):
-        # TODO - find out why for some reason copies
-        #        the [] as an [[]], so do manually
-        c = MultiOrderedDict() #self.__class__(self)
-        for key, val in self.iteritems():
-            for v in val:
-                c[key] = v
-        return c
diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
deleted file mode 100755
index 8fdef31..0000000
--- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
+++ /dev/null
@@ -1,1159 +0,0 @@
-#!/usr/bin/python
-
-import optparse
-import astdicts
-import astconfigparser
-import socket
-import re
-
-PREFIX = 'pjsip_'
-
-###############################################################################
-### some utility functions
-###############################################################################
-
-
-def section_by_type(section, pjsip, type):
-    """Finds a section based upon the given type, adding it if not found."""
-    def __find_dict(mdicts, key, val):
-        """Given a list of mult-dicts, return the multi-dict that contains
-           the given key/value pair."""
-
-        def found(d):
-            return key in d and val in d[key]
-
-        try:
-            return [d for d in mdicts if found(d)][0]
-        except IndexError:
-            raise LookupError("Dictionary not located for key = %s, value = %s"
-                              % (key, val))
-
-    try:
-        return __find_dict(pjsip.section(section), 'type', type)
-    except LookupError:
-        # section for type doesn't exist, so add
-        sect = pjsip.add_section(section)
-        sect['type'] = type
-        return sect
-
-
-def set_value(key=None, val=None, section=None, pjsip=None,
-              nmapped=None, type='endpoint'):
-    """Sets the key to the value within the section in pjsip.conf"""
-    def _set_value(k, v, s, r, n):
-        set_value(key if key else k, v, s, r, n, type)
-
-    # if no value or section return the set_value
-    # function with the enclosed key and type
-    if not val and not section:
-        return _set_value
-
-    # otherwise try to set the value
-    section_by_type(section, pjsip, type)[key] = \
-        val[0] if isinstance(val, list) else val
-
-
-def merge_value(key=None, val=None, section=None, pjsip=None,
-                nmapped=None, type='endpoint', section_to=None):
-    """Merge values from the given section with those from the default."""
-    def _merge_value(k, v, s, r, n):
-        merge_value(key if key else k, v, s, r, n, type, section_to)
-
-    # if no value or section return the merge_value
-    # function with the enclosed key and type
-    if not val and not section:
-        return _merge_value
-
-    # should return a single value section list
-    try:
-        sect = sip.section(section)[0]
-    except LookupError:
-        sect = sip.default(section)[0]
-    # for each merged value add it to pjsip.conf
-    for i in sect.get_merged(key):
-        set_value(key, i, section_to if section_to else section,
-                  pjsip, nmapped, type)
-
-
-def non_mapped(nmapped):
-    """Write non-mapped sip.conf values to the non-mapped object"""
-    def _non_mapped(section, key, val):
-        """Writes a non-mapped value from sip.conf to the non-mapped object."""
-        if section not in nmapped:
-            nmapped[section] = astconfigparser.Section()
-            if isinstance(val, list):
-                for v in val:
-                    # since coming from sip.conf we can assume
-                    # single section lists
-                    nmapped[section][0][key] = v
-            else:
-                nmapped[section][0][key] = val
-    return _non_mapped
-
-###############################################################################
-### mapping functions -
-###      define f(key, val, section) where key/val are the key/value pair to
-###      write to given section in pjsip.conf
-###############################################################################
-
-
-def set_dtmfmode(key, val, section, pjsip, nmapped):
-    """
-    Sets the dtmfmode value.  If value matches allowable option in pjsip
-    then map it, otherwise set it to none.
-    """
-    key = 'dtmf_mode'
-    # available pjsip.conf values: rfc4733, inband, info, none
-    if val == 'inband' or val == 'info':
-        set_value(key, val, section, pjsip, nmapped)
-    elif val == 'rfc2833':
-        set_value(key, 'rfc4733', section, pjsip, nmapped)
-    else:
-        nmapped(section, key, val + " ; did not fully map - set to none")
-        set_value(key, 'none', section, pjsip, nmapped)
-
-
-def from_nat(key, val, section, pjsip, nmapped):
-    """Sets values from nat into the appropriate pjsip.conf options."""
-    # nat from sip.conf can be comma separated list of values:
-    # yes/no, [auto_]force_rport, [auto_]comedia
-    if 'yes' in val:
-        set_value('rtp_symmetric', 'yes', section, pjsip, nmapped)
-        set_value('rewrite_contact', 'yes', section, pjsip, nmapped)
-    if 'comedia' in val:
-        set_value('rtp_symmetric', 'yes', section, pjsip, nmapped)
-    if 'force_rport' in val:
-        set_value('force_rport', 'yes', section, pjsip, nmapped)
-        set_value('rewrite_contact', 'yes', section, pjsip, nmapped)
-
-
-def set_timers(key, val, section, pjsip, nmapped):
-    """
-    Sets the timers in pjsip.conf from the session-timers option
-    found in sip.conf.
-    """
-    # pjsip.conf values can be yes/no, required, always
-    if val == 'originate':
-        set_value('timers', 'always', section, pjsip, nmapped)
-    elif val == 'accept':
-        set_value('timers', 'required', section, pjsip, nmapped)
-    elif val == 'never':
-        set_value('timers', 'no', section, pjsip, nmapped)
-    else:
-        set_value('timers', 'yes', section, pjsip, nmapped)
-
-
-def set_direct_media(key, val, section, pjsip, nmapped):
-    """
-    Maps values from the sip.conf comma separated direct_media option
-    into pjsip.conf direct_media options.
-    """
-    if 'yes' in val:
-        set_value('direct_media', 'yes', section, pjsip, nmapped)
-    if 'update' in val:
-        set_value('direct_media_method', 'update', section, pjsip, nmapped)
-    if 'outgoing' in val:
-        set_value('directed_media_glare_mitigation', 'outgoing', section,
-                  pjsip, nmapped)
-    if 'nonat' in val:
-        set_value('disable_directed_media_on_nat', 'yes', section, pjsip,
-                  nmapped)
-    if 'no' in val:
-        set_value('direct_media', 'no', section, pjsip, nmapped)
-
-
-def from_sendrpid(key, val, section, pjsip, nmapped):
-    """Sets the send_rpid/pai values in pjsip.conf."""
-    if val == 'yes' or val == 'rpid':
-        set_value('send_rpid', 'yes', section, pjsip, nmapped)
-    elif val == 'pai':
-        set_value('send_pai', 'yes', section, pjsip, nmapped)
-
-
-def set_media_encryption(key, val, section, pjsip, nmapped):
-    """Sets the media_encryption value in pjsip.conf"""
-    try:
-        dtls = sip.get(section, 'dtlsenable')[0]
-        if dtls == 'yes':
-            # If DTLS is enabled, then that overrides SDES encryption.
-            return
-    except LookupError:
-        pass
-
-    if val == 'yes':
-        set_value('media_encryption', 'sdes', section, pjsip, nmapped)
-
-
-def from_recordfeature(key, val, section, pjsip, nmapped):
-    """
-    If record on/off feature is set to automixmon then set
-    one_touch_recording, otherwise it can't be mapped.
-    """
-    set_value('one_touch_recording', 'yes', section, pjsip, nmapped)
-    set_value(key, val, section, pjsip, nmapped)
-
-def set_record_on_feature(key, val, section, pjsip, nmapped):
-    """Sets the record_on_feature in pjsip.conf"""
-    from_recordfeature('record_on_feature', val, section, pjsip, nmapped)
-
-def set_record_off_feature(key, val, section, pjsip, nmapped):
-    """Sets the record_off_feature in pjsip.conf"""
-    from_recordfeature('record_off_feature', val, section, pjsip, nmapped)
-
-def from_progressinband(key, val, section, pjsip, nmapped):
-    """Sets the inband_progress value in pjsip.conf"""
-    # progressinband can = yes/no/never
-    if val == 'never':
-        val = 'no'
-    set_value('inband_progress', val, section, pjsip, nmapped)
-
-
-def build_host(config, host, section, port_key):
-    """
-    Returns a string composed of a host:port. This assumes that the host
-    may have a port as part of the initial value. The port_key is only used
-    if the host does not already have a port set on it.
-    Throws a LookupError if the key does not exist
-    """
-    port = None
-
-    try:
-        socket.inet_pton(socket.AF_INET6, host)
-        if not host.startswith('['):
-            # SIP URI will need brackets.
-            host = '[' + host + ']'
-        else:
-            # If brackets are present, there may be a port as well
-            port = re.match('\[.*\]:(\d+)', host)
-    except socket.error:
-        # No biggie. It's just not an IPv6 address
-        port = re.match('.*:(\d+)', host)
-
-    result = host
-
-    if not port:
-        try:
-            port = config.get(section, port_key)[0]
-            result += ':' + port
-        except LookupError:
-            pass
-
-    return result
-
-
-def from_host(key, val, section, pjsip, nmapped):
-    """
-    Sets contact info in an AOR section in pjsip.conf using 'host'
-    and 'port' data from sip.conf
-    """
-    # all aors have the same name as the endpoint so makes
-    # it easy to set endpoint's 'aors' value
-    set_value('aors', section, section, pjsip, nmapped)
-    if val == 'dynamic':
-        # Easy case. Just set the max_contacts on the aor and we're done
-        set_value('max_contacts', 1, section, pjsip, nmapped, 'aor')
-        return
-
-    result = 'sip:'
-
-    # More difficult case. The host will be either a hostname or
-    # IP address and may or may not have a port specified. pjsip.conf
-    # expects the contact to be a SIP URI.
-
-    user = None
-
-    try:
-        user = sip.multi_get(section, ['defaultuser', 'username'])[0]
-        result += user + '@'
-    except LookupError:
-        # It's fine if there's no user name
-        pass
-
-    result += build_host(sip, val, section, 'port')
-
-    set_value('contact', result, section, pjsip, nmapped, 'aor')
-
-
-def from_mailbox(key, val, section, pjsip, nmapped):
-    """
-    Determines whether a mailbox configured in sip.conf should map to
-    an endpoint or aor in pjsip.conf. If subscribemwi is true, then the
-    mailboxes are set on an aor. Otherwise the mailboxes are set on the
-    endpoint.
-    """
-
-    try:
-        subscribemwi = sip.get(section, 'subscribemwi')[0]
-    except LookupError:
-        # No subscribemwi option means default it to 'no'
-        subscribemwi = 'no'
-
-    set_value('mailboxes', val, section, pjsip, nmapped, 'aor'
-              if subscribemwi == 'yes' else 'endpoint')
-
-
-def setup_auth(key, val, section, pjsip, nmapped):
-    """
-    Sets up authentication information for a specific endpoint based on the
-    'secret' setting on a peer in sip.conf
-    """
-    set_value('username', section, section, pjsip, nmapped, 'auth')
-    # In chan_sip, if a secret and an md5secret are both specified on a peer,
-    # then in practice, only the md5secret is used. If both are encountered
-    # then we build an auth section that has both an md5_cred and password.
-    # However, the auth_type will indicate to authenticators to use the
-    # md5_cred, so like with sip.conf, the password will be there but have
-    # no purpose.
-    if key == 'secret':
-        set_value('password', val, section, pjsip, nmapped, 'auth')
-    else:
-        set_value('md5_cred', val, section, pjsip, nmapped, 'auth')
-        set_value('auth_type', 'md5', section, pjsip, nmapped, 'auth')
-
-    realms = [section]
-    try:
-        auths = sip.get('authentication', 'auth')
-        for i in auths:
-            user, at, realm = i.partition('@')
-            realms.append(realm)
-    except LookupError:
-        pass
-
-    realm_str = ','.join(realms)
-
-    set_value('auth', section, section, pjsip, nmapped)
-    set_value('outbound_auth', realm_str, section, pjsip, nmapped)
-
-
-def setup_ident(key, val, section, pjsip, nmapped):
-    """
-    Examines the 'type' field for a sip.conf peer and creates an identify
-    section if the type is either 'peer' or 'friend'. The identify section uses
-    either the host or defaultip field of the sip.conf peer.
-    """
-    if val != 'peer' and val != 'friend':
-        return
-
-    try:
-        ip = sip.get(section, 'host')[0]
-    except LookupError:
-        return
-
-    if ip == 'dynamic':
-        try:
-            ip = sip.get(section, 'defaultip')[0]
-        except LookupError:
-            return
-
-    set_value('endpoint', section, section, pjsip, nmapped, 'identify')
-    set_value('match', ip, section, pjsip, nmapped, 'identify')
-
-
-def from_encryption_taglen(key, val, section, pjsip, nmapped):
-    """Sets the srtp_tag32 option based on sip.conf encryption_taglen"""
-    if val == '32':
-        set_value('srtp_tag_32', 'yes', section, pjsip, nmapped)
-
-
-def from_dtlsenable(key, val, section, pjsip, nmapped):
-    """Optionally sets media_encryption=dtls based on sip.conf dtlsenable"""
-    if val == 'yes':
-        set_value('media_encryption', 'dtls', section, pjsip, nmapped)
-
-###############################################################################
-
-# options in pjsip.conf on an endpoint that have no sip.conf equivalent:
-# type, rtp_ipv6, 100rel, trust_id_outbound, aggregate_mwi,
-# connected_line_method
-
-# known sip.conf peer keys that can be mapped to a pjsip.conf section/key
-peer_map = [
-    # sip.conf option      mapping function     pjsip.conf option(s)
-    ###########################################################################
-    ['context',            set_value],
-    ['dtmfmode',           set_dtmfmode],
-    ['disallow',           merge_value],
-    ['allow',              merge_value],
-    ['nat',                from_nat],            # rtp_symmetric, force_rport,
-                                                 # rewrite_contact
-    ['icesupport',         set_value('ice_support')],
-    ['autoframing',        set_value('use_ptime')],
-    ['outboundproxy',      set_value('outbound_proxy')],
-    ['mohsuggest',         set_value('moh_suggest')],
-    ['session-timers',     set_timers],          # timers
-    ['session-minse',      set_value('timers_min_se')],
-    ['session-expires',    set_value('timers_sess_expires')],
-    ['externip',           set_value('external_media_address')],
-    ['externhost',         set_value('external_media_address')],
-    # identify_by ?
-    ['directmedia',        set_direct_media],    # direct_media
-                                                 # direct_media_method
-                                                 # directed_media_glare_mitigation
-                                                 # disable_directed_media_on_nat
-    ['callerid',           set_value],           # callerid
-    ['callingpres',        set_value('callerid_privacy')],
-    ['cid_tag',            set_value('callerid_tag')],
-    ['trustpid',           set_value('trust_id_inbound')],
-    ['sendrpid',           from_sendrpid],       # send_pai, send_rpid
-    ['send_diversion',     set_value],
-    ['encrpytion',         set_media_encryption],
-    ['avpf',               set_value('use_avpf')],
-    ['recordonfeature',    set_record_on_feature],  # automixon
-    ['recordofffeature',   set_record_off_feature],  # automixon
-    ['progressinband',     from_progressinband], # in_band_progress
-    ['callgroup',          set_value('call_group')],
-    ['pickupgroup',        set_value('pickup_group')],
-    ['namedcallgroup',     set_value('named_call_group')],
-    ['namedpickupgroup',   set_value('named_pickup_group')],
-    ['allowtransfer',      set_value('allow_transfer')],
-    ['fromuser',           set_value('from_user')],
-    ['fromdomain',         set_value('from_domain')],
-    ['mwifrom',            set_value('mwi_from_user')],
-    ['tos_audio',          set_value],
-    ['tos_video',          set_value],
-    ['cos_audio',          set_value],
-    ['cos_video',          set_value],
-    ['sdpowner',           set_value('sdp_owner')],
-    ['sdpsession',         set_value('sdp_session')],
-    ['tonezone',           set_value('tone_zone')],
-    ['language',           set_value],
-    ['allowsubscribe',     set_value('allow_subscribe')],
-    ['subminexpiry',       set_value('sub_min_expiry')],
-    ['rtp_engine',         set_value],
-    ['mailbox',            from_mailbox],
-    ['busylevel',          set_value('device_state_busy_at')],
-    ['secret',             setup_auth],
-    ['md5secret',          setup_auth],
-    ['type',               setup_ident],
-    ['dtlsenable',         from_dtlsenable],
-    ['dtlsverify',         set_value('dtls_verify')],
-    ['dtlsrekey',          set_value('dtls_rekey')],
-    ['dtlscertfile',       set_value('dtls_cert_file')],
-    ['dtlsprivatekey',     set_value('dtls_private_key')],
-    ['dtlscipher',         set_value('dtls_cipher')],
-    ['dtlscafile',         set_value('dtls_ca_file')],
-    ['dtlscapath',         set_value('dtls_ca_path')],
-    ['dtlssetup',          set_value('dtls_setup')],
-    ['encryption_taglen',  from_encryption_taglen],
-
-############################ maps to an aor ###################################
-
-    ['host',               from_host],           # contact, max_contacts
-    ['qualifyfreq',        set_value('qualify_frequency', type='aor')],
-
-############################# maps to auth#####################################
-#        type = auth
-#        username
-#        password
-#        md5_cred
-#        realm
-#        nonce_lifetime
-#        auth_type
-######################### maps to acl/security ################################
-
-    ['permit',             merge_value(type='acl', section_to='acl')],
-    ['deny',               merge_value(type='acl', section_to='acl')],
-    ['acl',                merge_value(type='acl', section_to='acl')],
-    ['contactpermit',      merge_value('contact_permit', type='acl', section_to='acl')],
-    ['contactdeny',        merge_value('contact_deny', type='acl', section_to='acl')],
-    ['contactacl',         merge_value('contact_acl', type='acl', section_to='acl')],
-
-########################### maps to transport #################################
-#        type = transport
-#        protocol
-#        bind
-#        async_operations
-#        ca_list_file
-#        cert_file
-#        privkey_file
-#        password
-#        external_signaling_address - externip & externhost
-#        external_signaling_port
-#        external_media_address
-#        domain
-#        verify_server
-#        verify_client
-#        require_client_cert
-#        method
-#        cipher
-#        localnet
-######################### maps to domain_alias ################################
-#        type = domain_alias
-#        domain
-######################### maps to registration ################################
-#        type = registration
-#        server_uri
-#        client_uri
-#        contact_user
-#        transport
-#        outbound_proxy
-#        expiration
-#        retry_interval
-#        max_retries
-#        auth_rejection_permanent
-#        outbound_auth
-########################### maps to identify ##################################
-#        type = identify
-#        endpoint
-#        match
-]
-
-
-def add_localnet(section, pjsip, nmapped):
-    """
-    Adds localnet values from sip.conf's general section to a transport in
-    pjsip.conf. Ideally, we would have just created a template with the
-    localnet sections, but because this is a script, it's not hard to add
-    the same thing on to every transport.
-    """
-    try:
-        merge_value('local_net', sip.get('general', 'localnet')[0], 'general',
-                    pjsip, nmapped, 'transport', section)
-    except LookupError:
-        # No localnet options configured. No biggie!
-        pass
-
-
-def set_transport_common(section, pjsip, nmapped):
-    """
-    sip.conf has several global settings that in pjsip.conf apply to individual
-    transports. This function adds these global settings to each individual
-    transport.
-
-    The settings included are:
-    localnet
-    tos_sip
-    cos_sip
-    """
-
-    try:
-        merge_value('local_net', sip.get('general', 'localnet')[0], 'general',
-                    pjsip, nmapped, 'transport', section)
-    except LookupError:
-        # No localnet options configured. Move on.
-        pass
-
-    try:
-        set_value('tos', sip.get('general', 'sip_tos')[0], 'general', pjsip,
-                  nmapped, 'transport', section)
-    except LookupError:
-        pass
-
-    try:
-        set_value('cos', sip.get('general', 'sip_cos')[0], 'general', pjsip,
-                  nmapped, 'transport', section)
-    except LookupError:
-        pass
-
-
-def split_hostport(addr):
-    """
-    Given an address in the form 'addr:port' separate the addr and port
-    components.
-    Returns a two-tuple of strings, (addr, port). If no port is present in the
-    string, then the port section of the tuple is None.
-    """
-    try:
-        socket.inet_pton(socket.AF_INET6, addr)
-        if not addr.startswith('['):
-            return (addr, None)
-        else:
-            # If brackets are present, there may be a port as well
-            match = re.match('\[(.*\)]:(\d+)', addr)
-            if match:
-                return (match.group(1), match.group(2))
-            else:
-                return (addr, None)
-    except socket.error:
-        pass
-
-    # IPv4 address or hostname
-    host, sep, port = addr.rpartition(':')
-
-    if not sep and not port:
-        return (host, None)
-    else:
-        return (host, port)
-
-
-def create_udp(sip, pjsip, nmapped):
-    """
-    Creates a 'transport-udp' section in the pjsip.conf file based
-    on the following settings from sip.conf:
-
-    bindaddr (or udpbindaddr)
-    bindport
-    externaddr (or externip)
-    externhost
-    """
-
-    bind = sip.multi_get('general', ['udpbindaddr', 'bindaddr'])[0]
-    bind = build_host(sip, bind, 'general', 'bindport')
-
-    try:
-        extern_addr = sip.multi_get('general', ['externaddr', 'externip',
-                                    'externhost'])[0]
-        host, port = split_hostport(extern_addr)
-        set_value('external_signaling_address', host, 'transport-udp', pjsip,
-                  nmapped, 'transport')
-        if port:
-            set_value('external_signaling_port', port, 'transport-udp', pjsip,
-                      nmapped, 'transport')
-    except LookupError:
-        pass
-
-    set_value('protocol', 'udp', 'transport-udp', pjsip, nmapped, 'transport')
-    set_value('bind', bind, 'transport-udp', pjsip, nmapped, 'transport')
-    set_transport_common('transport-udp', pjsip, nmapped)
-
-
-def create_tcp(sip, pjsip, nmapped):
-    """
-    Creates a 'transport-tcp' section in the pjsip.conf file based
-    on the following settings from sip.conf:
-
-    tcpenable
-    tcpbindaddr
-    externtcpport
-    """
-
-    try:
-        enabled = sip.get('general', 'tcpenable')[0]
-    except:
-        # No value means disabled by default. No need for a tranport
-        return
-
-    if enabled == 'no':
-        return
-
-    try:
-        bind = sip.get('general', 'tcpbindaddr')[0]
-        bind = build_host(sip, bind, 'general', 'bindport')
-    except LookupError:
-        # No tcpbindaddr means to default to the udpbindaddr
-        bind = pjsip.get('transport-udp', 'bind')[0]
-
-    try:
-        extern_addr = sip.multi_get('general', ['externaddr', 'externip',
-                                    'externhost'])[0]
-        host, port = split_hostport(extern_addr)
-        try:
-            tcpport = sip.get('general', 'externtcpport')[0]
-        except:
-            tcpport = port
-        set_value('external_signaling_address', host, 'transport-tcp', pjsip,
-                  nmapped, 'transport')
-        if tcpport:
-            set_value('external_signaling_port', tcpport, 'transport-tcp',
-                      pjsip, nmapped, 'transport')
-    except LookupError:
-        pass
-
-    set_value('protocol', 'tcp', 'transport-tcp', pjsip, nmapped, 'transport')
-    set_value('bind', bind, 'transport-tcp', pjsip, nmapped, 'transport')
-    set_transport_common('transport-tcp', pjsip, nmapped)
-
-
-def set_tls_bindaddr(val, pjsip, nmapped):
-    """
-    Creates the TCP bind address. This has two possible methods of
-    working:
-    Use the 'tlsbindaddr' option from sip.conf directly if it has both
-    an address and port. If no port is present, use 5061
-    If there is no 'tlsbindaddr' option present in sip.conf, use the
-    previously-established UDP bind address and port 5061
-    """
-    try:
-        bind = sip.get('general', 'tlsbindaddr')[0]
-        explicit = True
-    except LookupError:
-        # No tlsbindaddr means to default to the bindaddr but with standard TLS
-        # port
-        bind = pjsip.get('transport-udp', 'bind')[0]
-        explicit = False
-
-    matchv4 = re.match('\d+\.\d+\.\d+\.\d+:\d+', bind)
-    matchv6 = re.match('\[.*\]:d+', bind)
-    if matchv4 or matchv6:
-        if explicit:
-            # They provided a port. We'll just use it.
-            set_value('bind', bind, 'transport-tls', pjsip, nmapped,
-                      'transport')
-            return
-        else:
-            # Need to strip the port from the UDP address
-            index = bind.rfind(':')
-            bind = bind[:index]
-
-    # Reaching this point means either there was no port provided or we
-    # stripped the port off. We need to add on the default 5061 port
-
-    bind += ':5061'
-
-    set_value('bind', bind, 'transport-tls', pjsip, nmapped, 'transport')
-
-
-def set_tls_private_key(val, pjsip, nmapped):
-    """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey"""
-    set_value('priv_key_file', val, 'transport-tls', pjsip, nmapped,
-              'transport')
-
-
-def set_tls_cipher(val, pjsip, nmapped):
-    """Sets cipher based on sip.conf tlscipher or sslcipher"""
-    set_value('cipher', val, 'transport-tls', pjsip, nmapped, 'transport')
-
-
-def set_tls_cafile(val, pjsip, nmapped):
-    """Sets ca_list_file based on sip.conf tlscafile"""
-    set_value('ca_list_file', val, 'transport-tls', pjsip, nmapped,
-              'transport')
-
-
-def set_tls_verifyclient(val, pjsip, nmapped):
-    """Sets verify_client based on sip.conf tlsverifyclient"""
-    set_value('verify_client', val, 'transport-tls', pjsip, nmapped,
-              'transport')
-
-
-def set_tls_verifyserver(val, pjsip, nmapped):
-    """Sets verify_server based on sip.conf tlsdontverifyserver"""
-
-    if val == 'no':
-        set_value('verify_server', 'yes', 'transport-tls', pjsip, nmapped,
-                  'transport')
-    else:
-        set_value('verify_server', 'no', 'transport-tls', pjsip, nmapped,
-                  'transport')
-
-
-def set_tls_method(val, pjsip, nmapped):
-    """Sets method based on sip.conf tlsclientmethod or sslclientmethod"""
-    set_value('method', val, 'transport-tls', pjsip, nmapped, 'transport')
-
-
-def create_tls(sip, pjsip, nmapped):
-    """
-    Creates a 'transport-tls' section in pjsip.conf based on the following
-    settings from sip.conf:
-
-    tlsenable (or sslenable)
-    tlsbindaddr (or sslbindaddr)
-    tlsprivatekey (or sslprivatekey)
-    tlscipher (or sslcipher)
-    tlscafile
-    tlscapath (or tlscadir)
-    tlscertfile (or sslcert or tlscert)
-    tlsverifyclient
-    tlsdontverifyserver
-    tlsclientmethod (or sslclientmethod)
-    """
-
-    tls_map = [
-        (['tlsbindaddr', 'sslbindaddr'], set_tls_bindaddr),
-        (['tlsprivatekey', 'sslprivatekey'], set_tls_private_key),
-        (['tlscipher', 'sslcipher'], set_tls_cipher),
-        (['tlscafile'], set_tls_cafile),
-        (['tlsverifyclient'], set_tls_verifyclient),
-        (['tlsdontverifyserver'], set_tls_verifyserver),
-        (['tlsclientmethod', 'sslclientmethod'], set_tls_method)
-    ]
-
-    try:
-        enabled = sip.multi_get('general', ['tlsenable', 'sslenable'])[0]
-    except LookupError:
-        # Not enabled. Don't create a transport
-        return
-
-    if enabled == 'no':
-        return
-
-    set_value('protocol', 'tls', 'transport-tls', pjsip, nmapped, 'transport')
-
-    for i in tls_map:
-        try:
-            i[1](sip.multi_get('general', i[0])[0], pjsip, nmapped)
-        except LookupError:
-            pass
-
-    set_transport_common('transport-tls', pjsip, nmapped)
-    try:
-        extern_addr = sip.multi_get('general', ['externaddr', 'externip',
-                                    'externhost'])[0]
-        host, port = split_hostport(extern_addr)
-        try:
-            tlsport = sip.get('general', 'externtlsport')[0]
-        except:
-            tlsport = port
-        set_value('external_signaling_address', host, 'transport-tls', pjsip,
-                  nmapped, 'transport')
-        if tlsport:
-            set_value('external_signaling_port', tlsport, 'transport-tls',
-                      pjsip, nmapped, 'transport')
-    except LookupError:
-        pass
-
-
-def map_transports(sip, pjsip, nmapped):
-    """
-    Finds options in sip.conf general section pertaining to
-    transport configuration and creates appropriate transport
-    configuration sections in pjsip.conf.
-
-    sip.conf only allows a single UDP transport, TCP transport,
-    and TLS transport. As such, the mapping into PJSIP can be made
-    consistent by defining three sections:
-
-    transport-udp
-    transport-tcp
-    transport-tls
-
-    To accommodate the default behaviors in sip.conf, we'll need to
-    create the UDP transport first, followed by the TCP and TLS transports.
-    """
-
-    # First create a UDP transport. Even if no bind parameters were provided
-    # in sip.conf, chan_sip would always bind to UDP 0.0.0.0:5060
-    create_udp(sip, pjsip, nmapped)
-
-    # TCP settings may be dependent on UDP settings, so do it second.
-    create_tcp(sip, pjsip, nmapped)
-    create_tls(sip, pjsip, nmapped)
-
-
-def map_auth(sip, pjsip, nmapped):
-    """
-    Creates auth sections based on entries in the authentication section of
-    sip.conf. pjsip.conf section names consist of "auth_" followed by the name
-    of the realm.
-    """
-    try:
-        auths = sip.get('authentication', 'auth')
-    except LookupError:
-        return
-
-    for i in auths:
-        creds, at, realm = i.partition('@')
-        if not at and not realm:
-            # Invalid. Move on
-            continue
-        user, colon, secret = creds.partition(':')
-        if not secret:
-            user, sharp, md5 = creds.partition('#')
-            if not md5:
-                #Invalid. move on
-                continue
-        section = "auth_" + realm
-
-        set_value('realm', realm, section, pjsip, nmapped, 'auth')
-        set_value('username', user, section, pjsip, nmapped, 'auth')
-        if secret:
-            set_value('password', secret, section, pjsip, nmapped, 'auth')
-        else:
-            set_value('md5_cred', md5, section, pjsip, nmapped, 'auth')
-            set_value('auth_type', 'md5', section, pjsip, nmapped, 'auth')
-
-
-class Registration:
-    """
-    Class for parsing and storing information in a register line in sip.conf.
-    """
-    def __init__(self, line, retry_interval, max_attempts, outbound_proxy):
-        self.retry_interval = retry_interval
-        self.max_attempts = max_attempts
-        self.outbound_proxy = outbound_proxy
-        self.parse(line)
-
-    def parse(self, line):
-        """
-        Initial parsing routine for register lines in sip.conf.
-
-        This splits the line into the part before the host, and the part
-        after the '@' symbol. These two parts are then passed to their
-        own parsing routines
-        """
-
-        # register =>
-        # [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
-
-        prehost, at, host_part = line.rpartition('@')
-        if not prehost:
-            raise
-
-        self.parse_host_part(host_part)
-        self.parse_user_part(prehost)
-
-    def parse_host_part(self, host_part):
-        """
-        Parsing routine for the part after the final '@' in a register line.
-        The strategy is to use partition calls to peel away the data starting
-        from the right and working to the left.
-        """
-        pre_expiry, sep, expiry = host_part.partition('~')
-        pre_extension, sep, self.extension = pre_expiry.partition('/')
-        self.host, sep, self.port = pre_extension.partition(':')
-
-        self.expiry = expiry if expiry else '120'
-
-    def parse_user_part(self, user_part):
-        """
-        Parsing routine for the part before the final '@' in a register line.
-        The only mandatory part of this line is the user portion. The strategy
-        here is to start by using partition calls to remove everything to
-        the right of the user, then finish by using rpartition calls to remove
-        everything to the left of the user.
-        """
-        colons = user_part.count(':')
-        if (colons == 3):
-            # :domainport:secret:authuser
-            pre_auth, sep, port_auth = user_part.partition(':')
-            self.domainport, sep, auth = port_auth.partition(':')
-            self.secret, sep, self.authuser = auth.partition(':')
-        elif (colons == 2):
-            # :secret:authuser
-            pre_auth, sep, auth = user_part.partition(':')
-            self.secret, sep, self.authuser = auth.partition(':')
-        elif (colons == 1):
-            # :secret
-            pre_auth, sep, self.secret = user_part.partition(':')
-        elif (colons == 0):
-            # No port, secret, or authuser
-            pre_auth = user_part
-        else:
-            # Invalid setting
-            raise
-
-        pre_domain, sep, self.domain = pre_auth.partition('@')
-        self.peer, sep, post_peer = pre_domain.rpartition('?')
-        transport, sep, self.user = post_peer.rpartition('://')
-
-        self.protocol = transport if transport else 'udp'
-
-    def write(self, pjsip, nmapped):
-        """
-        Write parsed registration data into a section in pjsip.conf
-
-        Most of the data in self will get written to a registration section.
-        However, there will also need to be an auth section created if a
-        secret or authuser is present.
-
-        General mapping of values:
-        A combination of self.host and self.port is server_uri
-        A combination of self.user, self.domain, and self.domainport is
-          client_uri
-        self.expiry is expiration
-        self.extension is contact_user
-        self.protocol will map to one of the mapped transports
-        self.secret and self.authuser will result in a new auth section, and
-          outbound_auth will point to that section.
-        XXX self.peer really doesn't map to anything :(
-        """
-
-        section = 'reg_' + self.host
-
-        set_value('retry_interval', self.retry_interval, section, pjsip,
-                  nmapped, 'registration')
-        set_value('max_retries', self.max_attempts, section, pjsip, nmapped,
-                  'registration')
-        if self.extension:
-            set_value('contact_user', self.extension, section, pjsip, nmapped,
-                      'registration')
-
-        set_value('expiration', self.expiry, section, pjsip, nmapped,
-                  'registration')
-
-        if self.protocol == 'udp':
-            set_value('transport', 'transport-udp', section, pjsip, nmapped,
-                      'registration')
-        elif self.protocol == 'tcp':
-            set_value('transport', 'transport-tcp', section, pjsip, nmapped,
-                      'registration')
-        elif self.protocol == 'tls':
-            set_value('transport', 'transport-tls', section, pjsip, nmapped,
-                      'registration')
-
-        auth_section = 'auth_reg_' + self.host
-
-        if self.secret:
-            set_value('password', self.secret, auth_section, pjsip, nmapped,
-                      'auth')
-            set_value('username', self.authuser or self.user, auth_section,
-                      pjsip, nmapped, 'auth')
-            set_value('outbound_auth', auth_section, section, pjsip, nmapped,
-                      'registration')
-
-        client_uri = "sip:%s@" % self.user
-        if self.domain:
-            client_uri += self.domain
-        else:
-            client_uri += self.host
-
-        if self.domainport:
-            client_uri += ":" + self.domainport
-        elif self.port:
-            client_uri += ":" + self.port
-
-        set_value('client_uri', client_uri, section, pjsip, nmapped,
-                  'registration')
-
-        server_uri = "sip:%s" % self.host
-        if self.port:
-            server_uri += ":" + self.port
-
-        set_value('server_uri', server_uri, section, pjsip, nmapped,
-                  'registration')
-
-        if self.outbound_proxy:
-            set_value('outboundproxy', self.outbound_proxy, section, pjsip,
-                      nmapped, 'registartion')
-
-
-def map_registrations(sip, pjsip, nmapped):
-    """
-    Gathers all necessary outbound registration data in sip.conf and creates
-    corresponding registration sections in pjsip.conf
-    """
-    try:
-        regs = sip.get('general', 'register')
-    except LookupError:
-        return
-
-    try:
-        retry_interval = sip.get('general', 'registertimeout')[0]
-    except LookupError:
-        retry_interval = '20'
-
-    try:
-        max_attempts = sip.get('general', 'registerattempts')[0]
-    except LookupError:
-        max_attempts = '10'
-
-    try:
-        outbound_proxy = sip.get('general', 'outboundproxy')[0]
-    except LookupError:
-        outbound_proxy = ''
-
-    for i in regs:
-        reg = Registration(i, retry_interval, max_attempts, outbound_proxy)
-        reg.write(pjsip, nmapped)
-
-
-def map_peer(sip, section, pjsip, nmapped):
-    """
-    Map the options from a peer section in sip.conf into the appropriate
-    sections in pjsip.conf
-    """
-    for i in peer_map:
-        try:
-            # coming from sip.conf the values should mostly be a list with a
-            # single value.  In the few cases that they are not a specialized
-            # function (see merge_value) is used to retrieve the values.
-            i[1](i[0], sip.get(section, i[0])[0], section, pjsip, nmapped)
-        except LookupError:
-            pass  # key not found in sip.conf
-
-
-def find_non_mapped(sections, nmapped):
-    """
-    Determine sip.conf options that were not properly mapped to pjsip.conf
-    options.
-    """
-    for section, sect in sections.iteritems():
-        try:
-            # since we are pulling from sip.conf this should always
-            # be a single value list
-            sect = sect[0]
-            # loop through the section and store any values that were not
-            # mapped
-            for key in sect.keys(True):
-                for i in peer_map:
-                    if i[0] == key:
-                        break
-                else:
-                    nmapped(section, key, sect[key])
-        except LookupError:
-            pass
-
-
-def convert(sip, filename, non_mappings, include):
-    """
-    Entry point for configuration file conversion. This
-    function will create a pjsip.conf object and begin to
-    map specific sections from sip.conf into it.
-    Returns the new pjsip.conf object once completed
-    """
-    pjsip = astconfigparser.MultiOrderedConfigParser()
-    non_mappings[filename] = astdicts.MultiOrderedDict()
-    nmapped = non_mapped(non_mappings[filename])
-    if not include:
-        # Don't duplicate transport and registration configs
-        map_transports(sip, pjsip, nmapped)
-        map_registrations(sip, pjsip, nmapped)
-    map_auth(sip, pjsip, nmapped)
-    for section in sip.sections():
-        if section == 'authentication':
-            pass
-        else:
-            map_peer(sip, section, pjsip, nmapped)
-
-    find_non_mapped(sip.defaults(), nmapped)
-    find_non_mapped(sip.sections(), nmapped)
-
-    for key, val in sip.includes().iteritems():
-        pjsip.add_include(PREFIX + key, convert(val, PREFIX + key,
-                          non_mappings, True)[0])
-    return pjsip, non_mappings
-
-
-def write_pjsip(filename, pjsip, non_mappings):
-    """
-    Write pjsip.conf file to disk
-    """
-    try:
-        with open(filename, 'wt') as fp:
-            fp.write(';--\n')
-            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
-            fp.write('Non mapped elements start\n')
-            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n')
-            astconfigparser.write_dicts(fp, non_mappings[filename])
-            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
-            fp.write('Non mapped elements end\n')
-            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
-            fp.write('--;\n\n')
-            # write out include file(s)
-            pjsip.write(fp)
-
-    except IOError:
-        print "Could not open file ", filename, " for writing"
-
-###############################################################################
-
-
-def cli_options():
-    """
-    Parse command line options and apply them. If invalid input is given,
-    print usage information
-    """
-    global PREFIX
-    usage = "usage: %prog [options] [input-file [output-file]]\n\n" \
-        "input-file defaults to 'sip.conf'\n" \
-        "output-file defaults to 'pjsip.conf'"
-    parser = optparse.OptionParser(usage=usage)
-    parser.add_option('-p', '--prefix', dest='prefix', default=PREFIX,
-                      help='output prefix for include files')
-
-    options, args = parser.parse_args()
-    PREFIX = options.prefix
-
-    sip_filename = args[0] if len(args) else 'sip.conf'
-    pjsip_filename = args[1] if len(args) == 2 else 'pjsip.conf'
-
-    return sip_filename, pjsip_filename
-
-if __name__ == "__main__":
-    sip_filename, pjsip_filename = cli_options()
-    # configuration parser for sip.conf
-    sip = astconfigparser.MultiOrderedConfigParser()
-    sip.read(sip_filename)
-    pjsip, non_mappings = convert(sip, pjsip_filename, dict(), False)
-    write_pjsip(pjsip_filename, pjsip, non_mappings)
diff --git a/contrib/utils/eagi_proxy.c b/contrib/utils/eagi_proxy.c
index 03c7e06..0a96d5a 100644
--- a/contrib/utils/eagi_proxy.c
+++ b/contrib/utils/eagi_proxy.c
@@ -223,7 +223,7 @@ int connect_to_host(char* name, int port)
 	struct sockaddr_in host;
 	
 
-	/* get adress */	
+	/* get address */	
 	if(!strcmp(name,"localhost"))
 		address=htonl(2130706433); /*127.0.0.1*/
 	else
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..7d534df
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,3 @@
+core-en_US.xml
+api
+asterisk-ng-doxygen
diff --git a/doc/Asterisk-11-Reference.pdf b/doc/Asterisk-11-Reference.pdf
new file mode 100644
index 0000000..bece035
Binary files /dev/null and b/doc/Asterisk-11-Reference.pdf differ
diff --git a/doc/README.txt b/doc/README.txt
index 5adea86..68a87e1 100644
--- a/doc/README.txt
+++ b/doc/README.txt
@@ -1,14 +1,10 @@
 The vast majority of the Asterisk project documentation has been moved to the
 project wiki:
     
-    https://wiki.asterisk.org/
+    http://wiki.asterisk.org/
 
 Asterisk release tarballs contain an export of the wiki in PDF and plain text
 form, which you can find in:
 
     doc/AST.pdf
     doc/AST.txt
-
-Asterisk uses the Doxygen documentation software.  Run "make progdocs" and open
-the resulting documentation index at doc/api/index.html in a webbrowser or copy
-the directory to a directory served by a webserver for remote access.
diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd
index 511930f..561e3d3 100644
--- a/doc/appdocsxml.dtd
+++ b/doc/appdocsxml.dtd
@@ -1,13 +1,13 @@
-  <!ELEMENT docs (application|function|agi|manager|managerEvent|info|configInfo)*>
+  <!ELEMENT docs (application|function|agi|manager|managerEvent|info)*>
   <!ATTLIST docs xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
 
   <!ELEMENT xi:include (xi:fallback?) >
-  <!ATTLIST xi:include
+  <!ATTLIST xi:include 
   xmlns:xi	CDATA       #FIXED    "http://www.w3.org/2001/XInclude"
   href		CDATA       #IMPLIED
   parse		(xml|text)  "xml"
   xpointer	CDATA       #IMPLIED
-  encoding	CDATA       #IMPLIED
+  encoding	CDATA       #IMPLIED 
   accept	CDATA       #IMPLIED
   accept-language CDATA  #IMPLIED >
 
@@ -26,15 +26,11 @@
   <!ATTLIST agi language CDATA #REQUIRED>
   <!ATTLIST agi module CDATA #IMPLIED>
 
-  <!ELEMENT manager (synopsis?,syntax?,description?,see-also?,responses?)>
+  <!ELEMENT manager (synopsis?,syntax?,description?,see-also?)>
   <!ATTLIST manager name CDATA #REQUIRED>
   <!ATTLIST manager language CDATA #REQUIRED>
   <!ATTLIST manager module CDATA #IMPLIED>
 
-  <!ELEMENT responses (list-elements?,(managerEvent|xi:include))>
-
-  <!ELEMENT list-elements (managerEvent+|xi:include+)>
-
   <!ELEMENT managerEvent (managerEventInstance+)>
   <!ATTLIST managerEvent name CDATA #REQUIRED>
   <!ATTLIST managerEvent language CDATA #REQUIRED>
@@ -43,30 +39,6 @@
   <!ELEMENT managerEventInstance (synopsis?,syntax?,description?,see-also?)*>
   <!ATTLIST managerEventInstance class CDATA #REQUIRED>
 
-  <!ELEMENT configInfo (synopsis?,description?,configFile+)>
-  <!ATTLIST configInfo name CDATA #REQUIRED>
-  <!ATTLIST configInfo language CDATA #REQUIRED>
-
-  <!ELEMENT configFile (configObject+)>
-  <!ATTLIST configFile name CDATA #REQUIRED>
-
-  <!ELEMENT configObject (synopsis?|description?|syntax?|see-also?|configOption)*>
-  <!ATTLIST configObject name CDATA #REQUIRED>
-
-  <!ELEMENT configOption (synopsis,description?,syntax?,see-also?)*>
-  <!ATTLIST configOption name CDATA #REQUIRED>
-  <!ATTLIST configOption regex (yes|no|true|false) "false">
-  <!ATTLIST configOption default CDATA #IMPLIED>
-  <!ATTLIST configOption type CDATA #IMPLIED>
-
-  <!ELEMENT matchInfo (category|field?)>
-
-  <!ELEMENT category (#PCDATA)>
-  <!ATTLIST category match (yes|no|true|false) #REQUIRED>
-
-  <!ELEMENT field (#PCDATA)>
-  <!ATTLIST field name CDATA #REQUIRED>
-
   <!ELEMENT info (para|note|warning|variablelist|enumlist|info|xi:include)*>
   <!ATTLIST info name CDATA #REQUIRED>
   <!ATTLIST info language CDATA #REQUIRED>
@@ -75,24 +47,15 @@
   <!ELEMENT see-also (ref|xi:include)*>
 
   <!ELEMENT ref (#PCDATA)>
-  <!ATTLIST ref type (application|function|astcli|link|manpage|filename|agi|manager|managerEvent|configOption) #REQUIRED>
+  <!ATTLIST ref type (application|function|astcli|link|manpage|filename|agi|manager|managerEvent) #REQUIRED>
   <!ATTLIST ref module CDATA #IMPLIED>
 
   <!ELEMENT synopsis (#PCDATA)>
 
-  <!ELEMENT syntax (parameter|dataType|category|matchInfo|xi:include|channel_snapshot|bridge_snapshot)*>
+  <!ELEMENT syntax (parameter|xi:include)*>
   <!ATTLIST syntax argsep CDATA ",">
 
-  <!ELEMENT channel_snapshot (#PCDATA)>
-  <!ATTLIST channel_snapshot prefix CDATA "">
-
-  <!ELEMENT bridge_snapshot (#PCDATA)>
-  <!ATTLIST bridge_snapshot prefix CDATA "">
-
-  <!ELEMENT configOptionToEnum (configOption|xi:include)*>
-  <!ATTLIST configOptionToEnum prefix CDATA "">
-
-  <!ELEMENT description (para|note|warning|variablelist|enumlist|info|example|xi:include)*>
+  <!ELEMENT description (para|note|warning|variablelist|enumlist|info|xi:include)*>
 
   <!ELEMENT parameter (optionlist|enumlist|argument|para|note|warning|parameter|info|xi:include)*>
   <!ATTLIST parameter name CDATA "">
@@ -110,7 +73,7 @@
   <!ATTLIST option implies CDATA "">
   <!ATTLIST option hasparams CDATA "">
 
-  <!ELEMENT enumlist (configOptionToEnum|enum+)>
+  <!ELEMENT enumlist (enum+)>
   <!ELEMENT enum (para|note|warning|parameter|enumlist|info|xi:include)*>
   <!ATTLIST enum name CDATA "">
 
@@ -128,11 +91,7 @@
   <!ELEMENT replaceable (#PCDATA)>
   <!ELEMENT directory (#PCDATA)>
   <!ELEMENT astcli (#PCDATA)>
-
-  <!ELEMENT example (#PCDATA|xi:include)*>
-  <!ATTLIST example title CDATA "">
-  <!ATTLIST example language CDATA "" >
-
+ 
   <!ELEMENT note (para+|xi:include*)>
   <!ELEMENT warning (para+|xi:include*)>
 
diff --git a/doc/appdocsxml.xslt b/doc/appdocsxml.xslt
deleted file mode 100644
index 8cbeaa3..0000000
--- a/doc/appdocsxml.xslt
+++ /dev/null
@@ -1,140 +0,0 @@
-<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-    <xsl:output omit-xml-declaration="yes" indent="yes"/>
-
-    <xsl:param name="pNewType" select="'myNewType'"/>
-
-    <xsl:template match="node()|@*">
-        <xsl:copy>
-            <xsl:apply-templates select="node()|@*"/>
-        </xsl:copy>
-    </xsl:template>
-
-    <xsl:template match="configOptionToEnum">
-        <xsl:for-each select="configOption">
-            <xsl:element name="enum">
-                <xsl:attribute name="name">
-                    <xsl:value-of select="@name"/>
-                </xsl:attribute>
-                <xsl:element name="para">
-                    <xsl:value-of select="synopsis"/>
-                </xsl:element>
-            </xsl:element>
-        </xsl:for-each>
-    </xsl:template>
-
-    <xsl:template match="channel_snapshot">
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'Channel')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'ChannelState')"/>
-            </xsl:attribute>
-            <para>A numeric code for the channel's current state, related to <xsl:value-of select="concat(@prefix,'ChannelStateDesc')"/></para>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'ChannelStateDesc')"/>
-            </xsl:attribute>
-            <enumlist>
-                <enum name="Down"/>
-                <enum name="Rsrvd"/>
-                <enum name="OffHook"/>
-                <enum name="Dialing"/>
-                <enum name="Ring"/>
-                <enum name="Ringing"/>
-                <enum name="Up"/>
-                <enum name="Busy"/>
-                <enum name="Dialing Offhook"/>
-                <enum name="Pre-ring"/>
-                <enum name="Unknown"/>
-            </enumlist>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'CallerIDNum')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'CallerIDName')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'ConnectedLineNum')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'ConnectedLineName')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'AccountCode')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'Context')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'Exten')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'Priority')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'Uniqueid')"/>
-            </xsl:attribute>
-        </xsl:element>
-    </xsl:template>
-
-    <xsl:template match="bridge_snapshot">
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'BridgeUniqueid')"/>
-            </xsl:attribute>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'BridgeType')"/>
-            </xsl:attribute>
-            <para>The type of bridge</para>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'BridgeTechnology')"/>
-            </xsl:attribute>
-            <para>Technology in use by the bridge</para>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix, 'BridgeCreator')"/>
-            </xsl:attribute>
-            <para>Entity that created the bridge if applicable</para>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix, 'BridgeName')"/>
-            </xsl:attribute>
-            <para>Name used to refer to the bridge by its BridgeCreator if applicable</para>
-        </xsl:element>
-        <xsl:element name="parameter">
-            <xsl:attribute name="name">
-                <xsl:value-of select="concat(@prefix,'BridgeNumChannels')"/>
-            </xsl:attribute>
-            <para>Number of channels in the bridge</para>
-        </xsl:element>
-    </xsl:template>
-</xsl:stylesheet>
diff --git a/contrib/asterisk-ng-doxygen b/doc/asterisk-ng-doxygen.in
similarity index 55%
rename from contrib/asterisk-ng-doxygen
rename to doc/asterisk-ng-doxygen.in
index 51a3f5d..cffa12a 100644
--- a/contrib/asterisk-ng-doxygen
+++ b/doc/asterisk-ng-doxygen.in
@@ -1,4 +1,4 @@
-# Doxyfile 1.7.1
+# Doxyfile 1.5.2
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project
@@ -14,217 +14,191 @@
 # Project related configuration options
 #---------------------------------------------------------------------------
 
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # by quotes) that should identify the project.
 
 PROJECT_NAME           = "Asterisk - The Open Source Telephony Project"
 
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         =
+PROJECT_NUMBER         = 
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
 # where doxygen was started. If left blank the current directory will be used.
 
-OUTPUT_DIRECTORY       = doc
+OUTPUT_DIRECTORY       = doc/api
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
 # otherwise cause performance problems for the file system.
 
-CREATE_SUBDIRS         = YES
+CREATE_SUBDIRS         = NO
 
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
 # Set to NO to disable this.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
 # brief descriptions will be completely suppressed.
 
 REPEAT_BRIEF           = YES
 
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
 # "represents" "a" "an" "the"
 
-ABBREVIATE_BRIEF       =
+ABBREVIATE_BRIEF       = 
 
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
 # description.
 
 ALWAYS_DETAILED_SEC    = NO
 
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
 # operators of the base classes will not be shown.
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
 # to NO the shortest path that makes the file name unique will be used.
 
 FULL_PATH_NAMES        = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
 # path to strip.
 
-STRIP_FROM_PATH        =
+STRIP_FROM_PATH        = 
 
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
 # are normally passed to the compiler using the -I flag.
 
-STRIP_FROM_INC_PATH    =
+STRIP_FROM_INC_PATH    = 
 
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
 # doesn't support long names like on DOS, Mac, or CD-ROM.
 
 SHORT_NAMES            = NO
 
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
 
 JAVADOC_AUTOBRIEF      = NO
 
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
 # description. Set this tag to YES if you prefer the old behaviour instead.
 
 MULTILINE_CPP_IS_BRIEF = NO
 
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
 # re-implements.
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
 # be part of the file/class/namespace that contains it.
 
 SEPARATE_MEMBER_PAGES  = NO
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
 # Doxygen uses this value to replace tabs by spaces in code fragments.
 
 TAB_SIZE               = 3
 
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
 # You can put \n's in the value part of an alias to insert newlines.
 
-ALIASES                = "extref=\xrefitem extref \"ExtRef\" \"External references\"" \
-                         "AsteriskTrunkWarning=\note The information contained on this page may be out of date.  To make sure you get the most current information, please make sure that you are using the documentation generated from Asterisk trunk."
+ALIASES                = "extref=\xrefitem extref \"ExtRef\" \"External references\""
+ALIASES += "AsteriskTrunkWarning=\note The information contained on this page may be out of date.  To make sure you get the most current information, please make sure that you are using the documentation generated from Asterisk trunk."
 
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
 # of all members will be omitted, etc.
 
 OPTIMIZE_OUTPUT_FOR_C  = YES
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
 
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
 # diagrams that involve STL classes more complete and accurate.
 
 BUILTIN_STL_SUPPORT    = NO
@@ -234,467 +208,382 @@ BUILTIN_STL_SUPPORT    = NO
 
 CPP_CLI_SUPPORT        = NO
 
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen to replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
 # all members of a group must be documented explicitly.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
 # the \nosubgrouping command.
 
 SUBGROUPING            = YES
 
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE      = 0
-
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
 # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
 
 EXTRACT_ALL            = YES
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
 # will be included in the documentation.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
 # will be included in the documentation.
 
 EXTRACT_STATIC         = YES
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
 # If set to NO only classes defined in header files are included.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
 # If set to NO (the default) only methods in the interface are included.
 
 EXTRACT_LOCAL_METHODS  = NO
 
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespace are hidden.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
 # This option has no effect if EXTRACT_ALL is enabled.
 
 HIDE_UNDOC_MEMBERS     = NO
 
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
 # overviews. This option has no effect if EXTRACT_ALL is enabled.
 
 HIDE_UNDOC_CLASSES     = NO
 
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
 # documentation.
 
 HIDE_FRIEND_COMPOUNDS  = NO
 
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
 # function's detailed documentation block.
 
 HIDE_IN_BODY_DOCS      = NO
 
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
 # Set it to YES to include the internal documentation.
 
 INTERNAL_DOCS          = NO
 
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
 # and Mac users are advised to set this option to NO.
 
 CASE_SENSE_NAMES       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
 # documentation. If set to YES the scope will be hidden.
 
 HIDE_SCOPE_NAMES       = YES
 
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
 # of that file.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
 # is inserted in the documentation for inline members.
 
 INLINE_INFO            = YES
 
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
 # declaration order.
 
 SORT_MEMBER_DOCS       = YES
 
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
 # declaration order.
 
 SORT_BRIEF_DOCS        = YES
 
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
 # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
+# Note: This option applies only to the class list, not to the 
 # alphabetical list.
 
 SORT_BY_SCOPE_NAME     = NO
 
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
 # commands in the documentation.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
 # commands in the documentation.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
 # commands in the documentation.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
 # \deprecated commands in the documentation.
 
 GENERATE_DEPRECATEDLIST= YES
 
-# The ENABLED_SECTIONS tag can be used to enable conditional
+# The ENABLED_SECTIONS tag can be used to enable conditional 
 # documentation sections, marked by \if sectionname ... \endif.
 
-ENABLED_SECTIONS       =
+ENABLED_SECTIONS       = 
 
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
 # command in the documentation regardless of this setting.
 
 MAX_INITIALIZER_LINES  = 5
 
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
 # list will mention the files that were used to generate the documentation.
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
 # in the documentation. The default is NO.
 
 SHOW_DIRECTORIES       = YES
 
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
 # is used as the file version. See the manual for examples.
 
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE            =
+FILE_VERSION_FILTER    = 
 
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated
+# The QUIET tag can be used to turn on/off the messages that are generated 
 # by doxygen. Possible values are YES and NO. If left blank NO is used.
 
 QUIET                  = NO
 
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
 # NO is used.
 
 WARNINGS               = YES
 
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
 # automatically be disabled.
 
 WARN_IF_UNDOCUMENTED   = YES
 
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
 # don't exist or using markup commands wrongly.
 
-WARN_IF_DOC_ERROR      = NO
+WARN_IF_DOC_ERROR      = YES
 
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
 # documentation.
 
 WARN_NO_PARAMDOC       = NO
 
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
 # be obtained via FILE_VERSION_FILTER)
 
-WARN_FORMAT            =
+WARN_FORMAT            = 
 
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
 # to stderr.
 
-WARN_LOGFILE           = doxygen.log
+WARN_LOGFILE           = 
 
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-INPUT                  =
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+INPUT                  = ./ \
+                         agi \
+                         apps \
+                         bridges \
+                         cdr \
+                         channels \
+                         channels/sip \
+                         channels/misdn \
+                         codecs \
+                         formats \
+                         funcs \
+                         include \
+                         include/asterisk \
+                         include/asterisk/doxygen \
+                         main \
+                         main/stdtime \
+                         pbx \
+                         res \
+                         res/ael \
+                         res/ais \
+                         res/snmp
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
 
 INPUT_ENCODING         = UTF-8
 
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
 
 FILE_PATTERNS          = *.c \
-                         *.h \
-                         *.py
+                         *.h
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
 # If left blank NO is used.
 
-RECURSIVE              = yes
+RECURSIVE              = NO
 
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
 
-EXCLUDE                = doc/api \
-                         menuselect \
-                         res/pjproject \
-                         addons/ooh323c/src
+EXCLUDE                = 
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
 # from the input.
 
-EXCLUDE_SYMLINKS       = YES
+EXCLUDE_SYMLINKS       = NO
 
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
 # for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       = *.o \
-                         *.o.d \
-                         .*
+EXCLUDE_PATTERNS       = 
 
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
 
-EXCLUDE_SYMBOLS        =
+EXCLUDE_SYMBOLS        = 
 
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
 # the \include command).
 
-EXAMPLE_PATH           = . \
+EXAMPLE_PATH           = ./ \
                          doc \
-                         configs \
-                         contrib
+                         configs
 
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
 # blank all files are included.
 
-EXAMPLE_PATTERNS       =
+EXAMPLE_PATTERNS       = 
 
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
 # Possible values are YES and NO. If left blank NO is used.
 
 EXAMPLE_RECURSIVE      = NO
 
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
 # the \image command).
 
 IMAGE_PATH             = images
 
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
 # ignored.
 
-INPUT_FILTER           =
+INPUT_FILTER           = 
 
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
 # is applied to all files.
 
-FILTER_PATTERNS        =
+FILTER_PATTERNS        = 
 
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
 # files to browse (i.e. when SOURCE_BROWSER is set to YES).
 
 FILTER_SOURCE_FILES    = NO
@@ -703,32 +592,32 @@ FILTER_SOURCE_FILES    = NO
 # configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
 # VERBATIM_HEADERS is set to NO.
 
 SOURCE_BROWSER         = YES
 
-# Setting the INLINE_SOURCES tag to YES will include the body
+# Setting the INLINE_SOURCES tag to YES will include the body 
 # of functions and classes directly in the documentation.
 
 INLINE_SOURCES         = YES
 
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
 # fragments. Normal C and C++ comments will always remain visible.
 
 STRIP_CODE_COMMENTS    = NO
 
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
 # functions referencing it will be listed.
 
 REFERENCED_BY_RELATION = YES
 
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
 # called/used by that function will be listed.
 
 REFERENCES_RELATION    = YES
@@ -736,21 +625,20 @@ REFERENCES_RELATION    = YES
 # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
 # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
 # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# link to the source code.  Otherwise they will link to the documentstion.
 
 REFERENCES_LINK_SOURCE = YES
 
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
 # will need version 4.8.6 or higher.
 
 USE_HTAGS              = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
 # which an include is specified. Set to NO to disable this.
 
 VERBATIM_HEADERS       = YES
@@ -759,488 +647,279 @@ VERBATIM_HEADERS       = YES
 # configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
 # contains a lot of classes, structs, unions or interfaces.
 
 ALPHABETICAL_INDEX     = YES
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
 # in which this list will be split (can be a number in the range [1..20])
 
 COLS_IN_ALPHA_INDEX    = 5
 
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
 # should be ignored while generating the index headers.
 
-IGNORE_PREFIX          =
+IGNORE_PREFIX          = 
 
 #---------------------------------------------------------------------------
 # configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
 # generate HTML output.
 
 GENERATE_HTML          = YES
 
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `html' will be used as the default path.
 
-HTML_OUTPUT            = api
+HTML_OUTPUT            = 
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
 # doxygen will generate files with .html extension.
 
 HTML_FILE_EXTENSION    = .html
 
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
 # standard header.
 
-HTML_HEADER            =
+HTML_HEADER            = contrib/asterisk-doxygen-header
 
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
 # standard footer.
 
-HTML_FOOTER            =
+HTML_FOOTER            = 
 
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
 # stylesheet in the HTML output directory as well, or it will be erased!
 
-HTML_STYLESHEET        =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP         = YES
+HTML_STYLESHEET        = 
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
 # NO a bullet list will be used.
 
 HTML_ALIGN_MEMBERS     = YES
 
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET        = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
 # of the generated HTML documentation.
 
 GENERATE_HTMLHELP      = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
 # written to the html output directory.
 
-CHM_FILE               =
+CHM_FILE               = 
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
 # the HTML help compiler on the generated index.hhp.
 
-HHC_LOCATION           =
+HHC_LOCATION           = 
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
 # it should be included in the master .chm file (NO).
 
 GENERATE_CHI           = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING     =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
 # normal table of contents (NO) in the .chm file.
 
 BINARY_TOC             = NO
 
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
 # to the contents of the HTML help documentation and to the tree view.
 
 TOC_EXPAND             = NO
 
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-#  will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
 # the value YES disables it.
 
 DISABLE_INDEX          = NO
 
-# This tag can be used to set the number of enum values (range [1..20])
+# This tag can be used to set the number of enum values (range [1..20]) 
 # that doxygen will group on one line in the generated HTML documentation.
 
 ENUM_VALUES_PER_LINE   = 4
 
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW      = NO
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
 
-USE_INLINE_TREES       = NO
+GENERATE_TREEVIEW      = YES
 
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
 # is shown.
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT    = YES
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvances is that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH    = NO
-
 #---------------------------------------------------------------------------
 # configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
 # generate Latex output.
 
 GENERATE_LATEX         = NO
 
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `latex' will be used as the default path.
 
-LATEX_OUTPUT           =
+LATEX_OUTPUT           = 
 
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
 # invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
 
 LATEX_CMD_NAME         = latex
 
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
 # default command name.
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
 # save some trees in general.
 
 COMPACT_LATEX          = NO
 
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
 # executive. If left blank a4wide will be used.
 
-PAPER_TYPE             = letter
+PAPER_TYPE             = a4wide
 
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
 # packages that should be included in the LaTeX output.
 
-EXTRA_PACKAGES         =
+EXTRA_PACKAGES         = 
 
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
 # standard header. Notice: only use this tag if you know what you are doing!
 
-LATEX_HEADER           =
+LATEX_HEADER           = 
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
 # This makes the output suitable for online browsing using a pdf viewer.
 
 PDF_HYPERLINKS         = NO
 
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
 # higher quality PDF documentation.
 
 USE_PDFLATEX           = NO
 
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
 # This option is also used when generating formulas in HTML.
 
 LATEX_BATCHMODE        = NO
 
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
 # in the output.
 
 LATEX_HIDE_INDICES     = NO
 
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE      = NO
-
 #---------------------------------------------------------------------------
 # configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
 # other RTF readers or editors.
 
 GENERATE_RTF           = NO
 
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `rtf' will be used as the default path.
 
-RTF_OUTPUT             =
+RTF_OUTPUT             = 
 
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
 # save some trees in general.
 
 COMPACT_RTF            = NO
 
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
 # Note: wordpad (write) and others do not support links.
 
 RTF_HYPERLINKS         = NO
 
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
 # replacements, missing definitions are set to their default value.
 
-RTF_STYLESHEET_FILE    =
+RTF_STYLESHEET_FILE    = 
 
-# Set optional variables used in the generation of an rtf document.
+# Set optional variables used in the generation of an rtf document. 
 # Syntax is similar to doxygen's config file.
 
-RTF_EXTENSIONS_FILE    =
+RTF_EXTENSIONS_FILE    = 
 
 #---------------------------------------------------------------------------
 # configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
 # generate man pages
 
 GENERATE_MAN           = NO
 
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `man' will be used as the default path.
 
-MAN_OUTPUT             =
+MAN_OUTPUT             = 
 
-# The MAN_EXTENSION tag determines the extension that is added to
+# The MAN_EXTENSION tag determines the extension that is added to 
 # the generated man pages (default is the subroutine's section .3)
 
-MAN_EXTENSION          =
+MAN_EXTENSION          = 
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
 # would be unable to find the correct page. The default is NO.
 
 MAN_LINKS              = NO
@@ -1249,33 +928,33 @@ MAN_LINKS              = NO
 # configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
 # the code including all documentation.
 
 GENERATE_XML           = NO
 
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
 # put in front of it. If left blank `xml' will be used as the default path.
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
 # syntax of the XML files.
 
-XML_SCHEMA             =
+XML_SCHEMA             = 
 
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
 # syntax of the XML files.
 
-XML_DTD                =
+XML_DTD                = 
 
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
 # enabling this will significantly increase the size of the XML output.
 
 XML_PROGRAMLISTING     = YES
@@ -1284,10 +963,10 @@ XML_PROGRAMLISTING     = YES
 # configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
 # and incomplete at the moment.
 
 GENERATE_AUTOGEN_DEF   = NO
@@ -1296,393 +975,354 @@ GENERATE_AUTOGEN_DEF   = NO
 # configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
 # moment.
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
 # to generate PDF and DVI output from the Perl module output.
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
 # and Perl will parse it just the same.
 
 PERLMOD_PRETTY         = YES
 
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
 # Makefile don't overwrite each other's variables.
 
-PERLMOD_MAKEVAR_PREFIX =
+PERLMOD_MAKEVAR_PREFIX = 
 
 #---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
+# Configuration options related to the preprocessor   
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
 # files.
 
 ENABLE_PREPROCESSING   = YES
 
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
 MACRO_EXPANSION        = YES
 
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
 EXPAND_ONLY_PREDEF     = YES
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
 # in the INCLUDE_PATH (see below) will be search if a #include is found.
 
 SEARCH_INCLUDES        = YES
 
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
 # the preprocessor.
 
-INCLUDE_PATH           = ./ \
-                         include/ \
-                         include/asterisk/
+INCLUDE_PATH           = include/ include/asterisk/
 
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
 # be used.
 
-INCLUDE_FILE_PATTERNS  =
+INCLUDE_FILE_PATTERNS  = 
 
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
 # instead of the = operator.
 
-PREDEFINED             = __GNUC__ \
-                         __attribute__(x)=
+PREDEFINED             = \
+            __GNUC__ \
+            __attribute__(x)=
 
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
 # Use the PREDEFINED tag if you want to use a different macro definition.
 
-EXPAND_AS_DEFINED      = AST_INLINE_API \
-                         AST_DECLARE_STRING_FIELDS \
-                         AST_STRING_FIELD \
-                         AST_THREADSTORAGE \
-                         AST_THREADSTORAGE_CUSTOM \
-                         AST_MODULE_INFO \
-                         AST_MODULE_INFO_STANDARD \
-                         __AST_MUTEX_DEFINE \
-                         AST_MUTEX_DEFINE_STATIC \
-                         AST_MUTEX_DEFINE_STATIC_NOTRACKING \
-                         __AST_RWLOCK_DEFINE \
-                         AST_RWLOCK_DEFINE_STATIC \
-                         AST_LIST_HEAD \
-                         AST_RWLIST_HEAD \
-                         AST_LIST_HEAD_NOLOCK \
-                         AST_LIST_HEAD_STATIC \
-                         AST_RWLIST_HEAD_STATIC \
-                         AST_LIST_HEAD_NOLOCK_STATIC \
-                         AST_LIST_ENTRY \
-                         AST_RWLIST_ENTRY \
-                         __ASTOBJ_HASH \
-                         ASTOBJ_COMPONENTS_NOLOCK_FULL \
-                         ASTOBJ_COMPONENTS_NOLOCK \
-                         ASTOBJ_COMPONENTS_FULL \
-                         ASTOBJ_COMPONENTS \
-                         AST_IVR_DECLARE_MENU \
-                         AST_DECLARE_APP_ARGS \
-                         AST_DEFINE_APP_ARGS_TYPE \
-                         AST_APP_ARG \
-                         BEGIN_OPTIONS \
-                         END_OPTIONS \
-                         AST_APP_OPTIONS \
-                         AST_APP_OPTION \
-                         AST_APP_OPTION_ARG \
-                         AST_DLLIST_HEAD \
-                         AST_DLLIST_HEAD_STATIC \
-                         AST_DLLIST_HEAD_NOLOCK \
-                         AST_DLLIST_HEAD_NOLOCK_STATIC \
-                         AST_RWDLLIST_HEAD \
-                         AST_RWDLLIST_HEAD_STATIC \
-                         AST_DLLIST_ENTRY \
-                         AST_RWDLLIST_ENTRY \
-                         AST_CLI_DEFINE \
-                         AST_OPTIONAL_API \
-                         AST_OPTIONAL_API_ATTR
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
+EXPAND_AS_DEFINED      = \
+            AST_INLINE_API \
+            AST_DECLARE_STRING_FIELDS \
+            AST_STRING_FIELD \
+            AST_THREADSTORAGE \
+            AST_THREADSTORAGE_CUSTOM \
+            AST_MODULE_INFO \
+            AST_MODULE_INFO_STANDARD \
+            __AST_MUTEX_DEFINE \
+            AST_MUTEX_DEFINE_STATIC \
+            AST_MUTEX_DEFINE_STATIC_NOTRACKING \
+            __AST_RWLOCK_DEFINE \
+            AST_RWLOCK_DEFINE_STATIC \
+            AST_LIST_HEAD \
+            AST_RWLIST_HEAD \
+            AST_LIST_HEAD_NOLOCK \
+            AST_LIST_HEAD_STATIC \
+            AST_RWLIST_HEAD_STATIC \
+            AST_LIST_HEAD_NOLOCK_STATIC \
+            AST_LIST_ENTRY \
+            AST_RWLIST_ENTRY \
+            __ASTOBJ_HASH \
+            ASTOBJ_COMPONENTS_NOLOCK_FULL \
+            ASTOBJ_COMPONENTS_NOLOCK \
+            ASTOBJ_COMPONENTS_FULL \
+            ASTOBJ_COMPONENTS \
+            AST_IVR_DECLARE_MENU \
+            AST_DECLARE_APP_ARGS \
+            AST_DEFINE_APP_ARGS_TYPE \
+            AST_APP_ARG \
+            BEGIN_OPTIONS \
+            END_OPTIONS \
+            AST_APP_OPTIONS \
+            AST_APP_OPTION \
+            AST_APP_OPTION_ARG \
+            AST_DLLIST_HEAD \
+            AST_DLLIST_HEAD_STATIC \
+            AST_DLLIST_HEAD_NOLOCK \
+            AST_DLLIST_HEAD_NOLOCK_STATIC \
+            AST_RWDLLIST_HEAD \
+            AST_RWDLLIST_HEAD_STATIC \
+            AST_DLLIST_ENTRY \
+            AST_RWDLLIST_ENTRY \
+            AST_CLI_DEFINE \
+            AST_OPTIONAL_API \
+            AST_OPTIONAL_API_ATTR
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
 # the parser if not removed.
 
 SKIP_FUNCTION_MACROS   = YES
 
 #---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration::additions related to external references   
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-#
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
 # does not have to be run to correct the links.
 # Note that each tag file must have a unique name
 # (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
+# If a tag file is not located in the directory in which doxygen 
 # is run, you must also specify the path to the tagfile here.
 
-TAGFILES               =
+TAGFILES               = 
 
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
 # a tag file that is based on the input files it reads.
 
-GENERATE_TAGFILE       =
+GENERATE_TAGFILE       = 
 
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
 # will be listed.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
 # be listed.
 
 EXTERNAL_GROUPS        = YES
 
-# The PERL_PATH should be the absolute path and name of the perl script
+# The PERL_PATH should be the absolute path and name of the perl script 
 # interpreter (i.e. the result of `which perl').
 
 PERL_PATH              = /usr/bin/perl
 
 #---------------------------------------------------------------------------
-# Configuration options related to the dot tool
+# Configuration options related to the dot tool   
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
 # powerful graphs.
 
 CLASS_DIAGRAMS         = NO
 
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
 
-MSCGEN_PATH            =
+MSCGEN_PATH            = 
 
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
 # or is not a class.
 
 HIDE_UNDOC_RELATIONS   = YES
 
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
 # have no effect if this option is set to NO (the default)
 
 HAVE_DOT               = NO
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS        = 0
-
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
-
-DOT_FONTNAME           = FreeSans.ttf
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
 # the CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
 # class references variables) of the class with other documented classes.
 
 COLLABORATION_GRAPH    = YES
 
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
 # will generate a graph for groups, showing the direct groups dependencies
 
 GROUP_GRAPHS           = YES
 
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
 # Language.
 
 UML_LOOK               = NO
 
-# If set to YES, the inheritance and collaboration graphs will show the
+# If set to YES, the inheritance and collaboration graphs will show the 
 # relations between templates and their instances.
 
 TEMPLATE_RELATIONS     = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
 # other documented files.
 
 INCLUDE_GRAPH          = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
 # indirectly include this file.
 
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
 
 CALL_GRAPH             = NO
 
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
 
 CALLER_GRAPH           = NO
 
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
 # will graphical hierarchy of all classes instead of a textual one.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
 # in a graphical way. The dependency relations are determined by the #include
 # relations between the files in the directories.
 
 DIRECTORY_GRAPH        = YES
 
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
 # generated by dot. Possible values are png, jpg, or gif
 # If left blank png will be used.
 
 DOT_IMAGE_FORMAT       = png
 
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
 # found. If left blank, it is assumed the dot tool can be found in the path.
 
-DOT_PATH               =
+DOT_PATH               = 
 
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
 # \dotfile command).
 
-DOTFILE_DIRS           =
+DOTFILE_DIRS           = 
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen will always 
+# show the root nodes and its direct children regardless of this setting.
 
 DOT_GRAPH_MAX_NODES    = 50
 
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH    = 3
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
 
 DOT_TRANSPARENT        = NO
 
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
 # support this, this feature is disabled by default.
 
 DOT_MULTI_TARGETS      = NO
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
 # arrows in the dot generated graphs.
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
 # the various graphs.
 
 DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/formats/Makefile b/formats/Makefile
index 069d30b..4834701 100644
--- a/formats/Makefile
+++ b/formats/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for file format modules
 #
diff --git a/formats/format_g719.c b/formats/format_g719.c
index d18801c..ee92212 100644
--- a/formats/format_g719.c
+++ b/formats/format_g719.c
@@ -29,12 +29,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define BUF_SIZE	160		/* 20 milliseconds == 160 bytes, 960 samples */
 #define SAMPLES_TO_BYTES(x)	((typeof(x)) x / ((float) 960 / 160))
@@ -45,6 +44,9 @@ static struct ast_frame *g719read(struct ast_filestream *s, int *whennext)
 	int res;
 	/* Send a frame from the file to the appropriate channel */
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_G719, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -59,6 +61,14 @@ static int g719write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_G719) {
+		ast_log(LOG_WARNING, "Asked to write non-G.719 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
 		ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
 		return -1;
@@ -137,8 +147,7 @@ static struct ast_format_def g719_f = {
 
 static int load_module(void)
 {
-	g719_f.format = ast_format_g719;
-
+	ast_format_set(&g719_f.format, AST_FORMAT_G719, 0);
 	if (ast_format_def_register(&g719_f))
 		return AST_MODULE_LOAD_DECLINE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -150,7 +159,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ITU G.719",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_g723.c b/formats/format_g723.c
index 540f26a..c3c194d 100644
--- a/formats/format_g723.c
+++ b/formats/format_g723.c
@@ -31,11 +31,10 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
-#include "asterisk/format_cache.h"
 
 #define G723_MAX_SIZE 1024
 
@@ -65,6 +64,9 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
 		return NULL;
 	}
 	/* Read the data into the buffer */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_G723_1, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, size);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != size) {
 		ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
@@ -80,6 +82,14 @@ static int g723_write(struct ast_filestream *s, struct ast_frame *f)
 	uint16_t size;
 	int res;
 	/* XXX there used to be a check s->fr means a read stream */
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_G723_1) {
+		ast_log(LOG_WARNING, "Asked to write non-g723 frame!\n");
+		return -1;
+	}
 	delay = 0;
 	if (f->datalen <= 0) {
 		ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen);
@@ -141,7 +151,7 @@ static struct ast_format_def g723_1_f = {
 
 static int load_module(void)
 {
-	g723_1_f.format = ast_format_g723;
+	ast_format_set(&g723_1_f.format, AST_FORMAT_G723_1, 0);
 
 	if (ast_format_def_register(&g723_1_f))
 		return AST_MODULE_LOAD_FAILURE;
@@ -154,7 +164,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "G.723.1 Simple Timestamp File Format",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_g726.c b/formats/format_g726.c
index 740e6d6..636aff0 100644
--- a/formats/format_g726.c
+++ b/formats/format_g726.c
@@ -34,12 +34,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define	RATE_40		0
 #define	RATE_32		1
@@ -123,6 +122,9 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
 	struct g726_desc *fs = (struct g726_desc *)s->_private;
 
 	/* Send a frame from the file to the appropriate channel */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_G726, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
 	s->fr.samples = 8 * FRAME_TIME;
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
@@ -139,6 +141,15 @@ static int g726_write(struct ast_filestream *s, struct ast_frame *f)
 	int res;
 	struct g726_desc *fs = (struct g726_desc *)s->_private;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_G726) {
+		ast_log(LOG_WARNING, "Asked to write non-G726 frame (%s)!\n", 
+						ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if (f->datalen % frame_size[fs->rate]) {
 		ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", 
 						f->datalen, frame_size[fs->rate]);
@@ -228,7 +239,7 @@ static int load_module(void)
 	int i;
 
 	for (i = 0; f[i].desc_size ; i++) {
-		f[i].format = ast_format_g726;
+		ast_format_set(&f[i].format, AST_FORMAT_G726, 0);
 		if (ast_format_def_register(&f[i])) {	/* errors are fatal */
 			ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
 			return AST_MODULE_LOAD_FAILURE;
@@ -249,7 +260,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.726 (16/24/32/40kbps) data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_g729.c b/formats/format_g729.c
index fc3fadd..f11fa97 100644
--- a/formats/format_g729.c
+++ b/formats/format_g729.c
@@ -32,12 +32,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
 
@@ -50,6 +49,9 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
 {
 	int res;
 	/* Send a frame from the file to the appropriate channel */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_G729A, 0);
+	s->fr.mallocd = 0;
 	s->fr.samples = G729A_SAMPLES;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
@@ -64,7 +66,14 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
 static int g729_write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
-
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_G729A) {
+		ast_log(LOG_WARNING, "Asked to write non-G729 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if (f->datalen % 10) {
 		ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 10\n", f->datalen);
 		return -1;
@@ -138,7 +147,7 @@ static struct ast_format_def g729_f = {
 
 static int load_module(void)
 {
-	g729_f.format = ast_format_g729;
+	ast_format_set(&g729_f.format, AST_FORMAT_G729A, 0);
 	if (ast_format_def_register(&g729_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -150,7 +159,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.729 data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_gsm.c b/formats/format_gsm.c
index fb57834..47ed41c 100644
--- a/formats/format_gsm.c
+++ b/formats/format_gsm.c
@@ -29,12 +29,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #include "msgsm.h"
 
@@ -57,7 +56,10 @@ static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
 {
 	int res;
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_GSM, 0);
 	AST_FRAME_SET_BUFFER(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE)
+	s->fr.mallocd = 0;
 	if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) {
 		if (res)
 			ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
@@ -72,6 +74,14 @@ static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
 	int res;
 	unsigned char gsm[2*GSM_FRAME_SIZE];
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_GSM) {
+		ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if (!(f->datalen % 65)) {
 		/* This is in MSGSM format, need to be converted */
 		int len=0;
@@ -183,7 +193,7 @@ static struct ast_format_def gsm_f = {
 
 static int load_module(void)
 {
-	gsm_f.format = ast_format_gsm;
+	ast_format_set(&gsm_f.format, AST_FORMAT_GSM, 0);
 	if (ast_format_def_register(&gsm_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -195,7 +205,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw GSM data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_h263.c b/formats/format_h263.c
index d86e833..56e9b3a 100644
--- a/formats/format_h263.c
+++ b/formats/format_h263.c
@@ -30,12 +30,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 /* Some Ideas for this code came from makeh263e.c by Jeffrey Chilton */
 
@@ -49,8 +48,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
  * ridiculously large). */
 #define	BUF_SIZE	32768	/* Four real h.263 Frames */
 
-#define FRAME_ENDED 0x8000
-
 struct h263_desc {
 	unsigned int lastts;
 };
@@ -79,12 +76,15 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext)
 	if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
 		return NULL;
 	len = ntohs(len);
-	mark = (len & FRAME_ENDED) ? 1 : 0;
+	mark = (len & 0x8000) ? 1 : 0;
 	len &= 0x7fff;
 	if (len > BUF_SIZE) {
 		ast_log(LOG_WARNING, "Length %d is too long\n", len);
 		return NULL;
 	}
+	s->fr.frametype = AST_FRAME_VIDEO;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_H263, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -93,7 +93,11 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext)
 	}
 	s->fr.samples = fs->lastts;	/* XXX what ? */
 	s->fr.datalen = len;
-	s->fr.subclass.frame_ending = mark;
+	if (mark) {
+		ast_format_set_video_mark(&s->fr.subclass.format);
+	}
+	s->fr.delivery.tv_sec = 0;
+	s->fr.delivery.tv_usec = 0;
 	if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
 		fs->lastts = ntohl(ts);
 		*whennext = fs->lastts * 4/45;
@@ -108,7 +112,15 @@ static int h263_write(struct ast_filestream *fs, struct ast_frame *f)
 	unsigned int ts;
 	unsigned short len;
 	uint32_t mark = 0;
-	mark = f->subclass.frame_ending ? FRAME_ENDED : 0;
+	if (f->frametype != AST_FRAME_VIDEO) {
+		ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
+		return -1;
+	}
+	mark = ast_format_get_video_mark(&f->subclass.format) ? 0x8000 : 0;
+	if (f->subclass.format.id != AST_FORMAT_H263) {
+		ast_log(LOG_WARNING, "Asked to write non-h263 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	ts = htonl(f->samples);
 	if ((res = fwrite(&ts, 1, sizeof(ts), fs->f)) != sizeof(ts)) {
 			ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
@@ -170,7 +182,7 @@ static struct ast_format_def h263_f = {
 
 static int load_module(void)
 {
-	h263_f.format = ast_format_h263;
+	ast_format_set(&h263_f.format, AST_FORMAT_H263, 0);
 	if (ast_format_def_register(&h263_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -182,7 +194,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw H.263 data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_h264.c b/formats/format_h264.c
index 06500ec..e090c2b 100644
--- a/formats/format_h264.c
+++ b/formats/format_h264.c
@@ -30,20 +30,17 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 /* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */
 
 /* Portions of the conversion code are by guido at sienanet.it */
 /*! \todo Check this buf size estimate, it may be totally wrong for large frame video */
 
-#define FRAME_ENDED	0x8000
-
 #define BUF_SIZE	4096	/* Two Real h264 Frames */
 struct h264_desc {
 	unsigned int lastts;
@@ -71,12 +68,15 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext)
 	if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
 		return NULL;
 	len = ntohs(len);
-	mark = (len & FRAME_ENDED) ? 1 : 0;
+	mark = (len & 0x8000) ? 1 : 0;
 	len &= 0x7fff;
 	if (len > BUF_SIZE) {
 		ast_log(LOG_WARNING, "Length %d is too long\n", len);
 		len = BUF_SIZE;	/* XXX truncate */
 	}
+	s->fr.frametype = AST_FRAME_VIDEO;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_H264, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -85,7 +85,11 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext)
 	}
 	s->fr.samples = fs->lastts;
 	s->fr.datalen = len;
-	s->fr.subclass.frame_ending = mark;
+	if (mark) {
+		ast_format_set_video_mark(&s->fr.subclass.format);
+	}
+	s->fr.delivery.tv_sec = 0;
+	s->fr.delivery.tv_usec = 0;
 	if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
 		fs->lastts = ntohl(ts);
 		*whennext = fs->lastts * 4/45;
@@ -101,7 +105,15 @@ static int h264_write(struct ast_filestream *s, struct ast_frame *f)
 	unsigned short len;
 	int mark;
 
-	mark = f->subclass.frame_ending ? FRAME_ENDED : 0;
+	if (f->frametype != AST_FRAME_VIDEO) {
+		ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
+		return -1;
+	}
+	mark = ast_format_get_video_mark(&f->subclass.format) ? 0x8000 : 0;
+	if (f->subclass.format.id != AST_FORMAT_H264) {
+		ast_log(LOG_WARNING, "Asked to write non-h264 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	ts = htonl(f->samples);
 	if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
 		ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
@@ -163,7 +175,7 @@ static struct ast_format_def h264_f = {
 
 static int load_module(void)
 {
-	h264_f.format = ast_format_h264;
+	ast_format_set(&h264_f.format, AST_FORMAT_H264, 0);
 	if (ast_format_def_register(&h264_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -175,7 +187,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw H.264 data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c
index c3ef1b0..07155b7 100644
--- a/formats/format_ilbc.c
+++ b/formats/format_ilbc.c
@@ -31,12 +31,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
 
@@ -49,6 +48,9 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext)
 {
 	int res;
 	/* Send a frame from the file to the appropriate channel */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_ILBC, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -62,6 +64,14 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext)
 static int ilbc_write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_ILBC) {
+		ast_log(LOG_WARNING, "Asked to write non-iLBC frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if (f->datalen % 50) {
 		ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 50\n", f->datalen);
 		return -1;
@@ -135,7 +145,7 @@ static struct ast_format_def ilbc_f = {
 
 static int load_module(void)
 {
-	ilbc_f.format = ast_format_ilbc;
+	ast_format_set(&ilbc_f.format, AST_FORMAT_ILBC, 0);
 	if (ast_format_def_register(&ilbc_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -147,7 +157,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw iLBC data",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c
index 775d7ad..d673302 100644
--- a/formats/format_jpeg.c
+++ b/formats/format_jpeg.c
@@ -30,13 +30,12 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/image.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 static struct ast_frame *jpeg_read_image(int fd, int len)
 {
@@ -53,7 +52,7 @@ static struct ast_frame *jpeg_read_image(int fd, int len)
 	}
 	memset(&fr, 0, sizeof(fr));
 	fr.frametype = AST_FRAME_IMAGE;
-	fr.subclass.format = ast_format_jpeg;
+	ast_format_set(&fr.subclass.format, AST_FORMAT_JPEG, 0);
 	fr.data.ptr = buf;
 	fr.src = "JPEG Read";
 	fr.datalen = len;
@@ -75,6 +74,14 @@ static int jpeg_identify(int fd)
 static int jpeg_write_image(int fd, struct ast_frame *fr)
 {
 	int res=0;
+	if (fr->frametype != AST_FRAME_IMAGE) {
+		ast_log(LOG_WARNING, "Not an image\n");
+		return -1;
+	}
+	if (fr->subclass.format.id != AST_FORMAT_JPEG) {
+		ast_log(LOG_WARNING, "Not a jpeg image\n");
+		return -1;
+	}
 	if (fr->datalen) {
 		res = write(fd, fr->data.ptr, fr->datalen);
 		if (res != fr->datalen) {
@@ -96,7 +103,7 @@ static struct ast_imager jpeg_format = {
 
 static int load_module(void)
 {
-	jpeg_format.format = ast_format_jpeg;
+	ast_format_set(&jpeg_format.format, AST_FORMAT_JPEG, 0);
 	if (ast_image_register(&jpeg_format))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -110,7 +117,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "jpeg (joint picture experts group) image format",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c
index 69ea694..7ef3743 100644
--- a/formats/format_ogg_vorbis.c
+++ b/formats/format_ogg_vorbis.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <vorbis/codec.h>
 #include <vorbis/vorbisenc.h>
@@ -45,7 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
-#include "asterisk/format_cache.h"
 
 /*
  * this is the number of samples we deal with. Samples are converted
@@ -243,6 +242,16 @@ static int ogg_vorbis_write(struct ast_filestream *fs, struct ast_frame *f)
 		ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
 		return -1;
 	}
+
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_SLINEAR) {
+		ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n",
+			ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if (!f->datalen)
 		return -1;
 
@@ -301,6 +310,9 @@ static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs,
 	}
 
 	/* initialize frame */
+	fs->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&fs->fr.subclass.format, AST_FORMAT_SLINEAR, 0);
+	fs->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	out_buf = (char *) (fs->fr.data.ptr);	/* SLIN data buffer */
 
@@ -330,7 +342,7 @@ static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs,
 
 /*!
  * \brief Trucate an OGG/Vorbis filestream.
- * \param fs The filestream to truncate.
+ * \param s The filestream to truncate.
  * \return 0 on success, -1 on failure.
  */
 
@@ -342,7 +354,7 @@ static int ogg_vorbis_trunc(struct ast_filestream *fs)
 
 /*!
  * \brief Tell the current position in OGG/Vorbis filestream measured in pcms.
- * \param fs The filestream to take action on.
+ * \param s The filestream to take action on.
  * \return 0 or greater with the position measured in samples, or -1 for false.
  */
 static off_t ogg_vorbis_tell(struct ast_filestream *fs)
@@ -362,7 +374,7 @@ static off_t ogg_vorbis_tell(struct ast_filestream *fs)
 
 /*!
  * \brief Seek to a specific position in an OGG/Vorbis filestream.
- * \param fs The filestream to take action on.
+ * \param s The filestream to take action on.
  * \param sample_offset New position for the filestream, measured in 8KHz samples.
  * \param whence Location to measure 
  * \return 0 on success, -1 on failure.
@@ -423,7 +435,7 @@ static struct ast_format_def vorbis_f = {
 
 static int load_module(void)
 {
-	vorbis_f.format = ast_format_slin;
+	ast_format_set(&vorbis_f.format, AST_FORMAT_SLINEAR, 0);
 	if (ast_format_def_register(&vorbis_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -435,7 +447,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Vorbis audio",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_pcm.c b/formats/format_pcm.c
index fbee94f..1ee333f 100644
--- a/formats/format_pcm.c
+++ b/formats/format_pcm.c
@@ -30,14 +30,13 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
 #include "asterisk/ulaw.h"
 #include "asterisk/alaw.h"
-#include "asterisk/format_cache.h"
 
 #define BUF_SIZE 160		/* 160 bytes, and same number of samples */
 
@@ -67,7 +66,7 @@ static unsigned long get_time(void)
 
 static int pcma_open(struct ast_filestream *s)
 {
-	if (ast_format_cmp(s->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL)
+	if (s->fmt->format == AST_FORMAT_ALAW)
 		pd->starttime = get_time();
 	return 0;
 }
@@ -84,6 +83,9 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
 	
 	/* Send a frame from the file to the appropriate channel */
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_copy(&s->fr.subclass.format, &s->fmt->format);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) {
 		if (res)
@@ -91,7 +93,7 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
 		return NULL;
 	}
 	s->fr.datalen = res;
-	if (ast_format_cmp(s->fmt->format, ast_format_g722) == AST_FORMAT_CMP_EQUAL)
+	if (s->fmt->format.id == AST_FORMAT_G722)
 		*whennext = s->fr.samples = res * 2;
 	else
 		*whennext = s->fr.samples = res;
@@ -139,7 +141,7 @@ static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 	}
 	if (whence == SEEK_FORCECUR && offset > max) { /* extend the file */
 		size_t left = offset - max;
-		const char *src = (ast_format_cmp(fs->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? alaw_silence : ulaw_silence;
+		const char *src = (fs->fmt->format.id == AST_FORMAT_ALAW) ? alaw_silence : ulaw_silence;
 
 		while (left) {
 			size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
@@ -183,8 +185,17 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_log(LOG_WARNING, "Asked to write incompatible format frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
+
 #ifdef REALTIME_WRITE
-	if (ast_format_cmp(s->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
+	if (s->fmt->format == AST_FORMAT_ALAW) {
 		struct pcm_desc *pd = (struct pcm_desc *)fs->_private;
 		struct stat stat_buf;
 		unsigned long cur_time = get_time();
@@ -388,7 +399,7 @@ static int au_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 	off_t min = AU_HEADER_SIZE, max, cur;
 	long offset = 0, bytes;
 
-	if (ast_format_cmp(fs->fmt->format, ast_format_g722) == AST_FORMAT_CMP_EQUAL)
+	if (fs->fmt->format.id == AST_FORMAT_G722)
 		bytes = sample_offset / 2;
 	else
 		bytes = sample_offset;
@@ -512,10 +523,10 @@ static int load_module(void)
 	for (i = 0; i < ARRAY_LEN(alaw_silence); i++)
 		alaw_silence[i] = AST_LIN2A(0);
 
-	pcm_f.format = ast_format_ulaw;
-	alaw_f.format = ast_format_alaw;
-	au_f.format = ast_format_ulaw;
-	g722_f.format = ast_format_g722;
+	ast_format_set(&pcm_f.format, AST_FORMAT_ULAW, 0);
+	ast_format_set(&alaw_f.format, AST_FORMAT_ALAW, 0);
+	ast_format_set(&au_f.format, AST_FORMAT_ULAW, 0);
+	ast_format_set(&g722_f.format, AST_FORMAT_G722, 0);
 	if ( ast_format_def_register(&pcm_f)
 		|| ast_format_def_register(&alaw_f)
 		|| ast_format_def_register(&au_f)
@@ -533,7 +544,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw/Sun uLaw/ALaw 8KHz (PCM,PCMA,AU), G.722 16Khz",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_siren14.c b/formats/format_siren14.c
index 911a420..77a9fe3 100644
--- a/formats/format_siren14.c
+++ b/formats/format_siren14.c
@@ -29,12 +29,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define BUF_SIZE	120		/* 20 milliseconds == 120 bytes, 640 samples */
 #define SAMPLES_TO_BYTES(x)	((typeof(x)) x / ((float) 640 / 120))
@@ -45,6 +44,9 @@ static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext)
 	int res;
 	/* Send a frame from the file to the appropriate channel */
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_SIREN14, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -59,6 +61,14 @@ static int siren14write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_SIREN14) {
+		ast_log(LOG_WARNING, "Asked to write non-Siren14 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
 		ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
 		return -1;
@@ -138,7 +148,7 @@ static struct ast_format_def siren14_f = {
 
 static int load_module(void)
 {
-	siren14_f.format = ast_format_siren14;
+	ast_format_set(&siren14_f.format, AST_FORMAT_SIREN14, 0);
 	if (ast_format_def_register(&siren14_f))
 		return AST_MODULE_LOAD_DECLINE;
 
@@ -151,7 +161,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ITU G.722.1 Annex C (Siren14, licensed from Polycom)",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_siren7.c b/formats/format_siren7.c
index dcf2cd9..35e2a34 100644
--- a/formats/format_siren7.c
+++ b/formats/format_siren7.c
@@ -29,12 +29,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define BUF_SIZE	80		/* 20 milliseconds == 80 bytes, 320 samples */
 #define SAMPLES_TO_BYTES(x)	x / (320 / 80)
@@ -45,6 +44,9 @@ static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext)
 	int res;
 	/* Send a frame from the file to the appropriate channel */
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_SIREN7, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
 		if (res)
@@ -59,6 +61,14 @@ static int siren7write(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_SIREN7) {
+		ast_log(LOG_WARNING, "Asked to write non-Siren7 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
 		ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
 		return -1;
@@ -138,7 +148,7 @@ static struct ast_format_def siren7_f = {
 
 static int load_module(void)
 {
-	siren7_f.format = ast_format_siren7;
+	ast_format_set(&siren7_f.format, AST_FORMAT_SIREN7, 0);
 	if (ast_format_def_register(&siren7_f))
 		return AST_MODULE_LOAD_DECLINE;
 
@@ -151,7 +161,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ITU G.722.1 (Siren7, licensed from Polycom)",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_sln.c b/formats/format_sln.c
index 13833eb..30a1ebe 100644
--- a/formats/format_sln.c
+++ b/formats/format_sln.c
@@ -27,18 +27,20 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
-static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, unsigned int buf_size)
+static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, unsigned int buf_size, enum ast_format_id id)
 {
 	int res;
 	/* Send a frame from the file to the appropriate channel */
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, id, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, buf_size);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) {
 		if (res)
@@ -50,9 +52,17 @@ static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, u
 	return &s->fr;
 }
 
-static int slinear_write(struct ast_filestream *fs, struct ast_frame *f)
+static int generic_write(struct ast_filestream *fs, struct ast_frame *f, enum ast_format_id id)
 {
 	int res;
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != id) {
+		ast_log(LOG_WARNING, "Asked to write non-slinear frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
 			ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
 			return -1;
@@ -117,7 +127,8 @@ static off_t slinear_tell(struct ast_filestream *fs)
 	return ftello(fs->f) / 2;
 }
 
-static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 320);}
+static int slinear_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR);}
+static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 320, AST_FORMAT_SLINEAR);}
 static struct ast_format_def slin_f = {
 	.name = "sln",
 	.exts = "sln|raw",
@@ -129,11 +140,12 @@ static struct ast_format_def slin_f = {
 	.buf_size = 320 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear12_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 480);}
+static int slinear12_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR12);}
+static struct ast_frame *slinear12_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 480, AST_FORMAT_SLINEAR12);}
 static struct ast_format_def slin12_f = {
 	.name = "sln12",
 	.exts = "sln12",
-	.write = slinear_write,
+	.write = slinear12_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -141,11 +153,12 @@ static struct ast_format_def slin12_f = {
 	.buf_size = 480 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear16_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 640);}
+static int slinear16_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR16);}
+static struct ast_frame *slinear16_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 640, AST_FORMAT_SLINEAR16);}
 static struct ast_format_def slin16_f = {
 	.name = "sln16",
 	.exts = "sln16",
-	.write = slinear_write,
+	.write = slinear16_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -153,11 +166,12 @@ static struct ast_format_def slin16_f = {
 	.buf_size = 640 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear24_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 960);}
+static int slinear24_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR24);}
+static struct ast_frame *slinear24_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 960, AST_FORMAT_SLINEAR24);}
 static struct ast_format_def slin24_f = {
 	.name = "sln24",
 	.exts = "sln24",
-	.write = slinear_write,
+	.write = slinear24_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -165,11 +179,12 @@ static struct ast_format_def slin24_f = {
 	.buf_size = 960 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear32_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1280);}
+static int slinear32_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR32);}
+static struct ast_frame *slinear32_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1280, AST_FORMAT_SLINEAR32);}
 static struct ast_format_def slin32_f = {
 	.name = "sln32",
 	.exts = "sln32",
-	.write = slinear_write,
+	.write = slinear32_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -177,11 +192,12 @@ static struct ast_format_def slin32_f = {
 	.buf_size = 1280 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear44_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1764);}
+static int slinear44_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR44);}
+static struct ast_frame *slinear44_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1764, AST_FORMAT_SLINEAR44);}
 static struct ast_format_def slin44_f = {
 	.name = "sln44",
 	.exts = "sln44",
-	.write = slinear_write,
+	.write = slinear44_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -189,11 +205,12 @@ static struct ast_format_def slin44_f = {
 	.buf_size = 1764 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear48_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1920);}
+static int slinear48_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR48);}
+static struct ast_frame *slinear48_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1920, AST_FORMAT_SLINEAR48);}
 static struct ast_format_def slin48_f = {
 	.name = "sln48",
 	.exts = "sln48",
-	.write = slinear_write,
+	.write = slinear48_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -201,11 +218,12 @@ static struct ast_format_def slin48_f = {
 	.buf_size = 1920 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear96_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 3840);}
+static int slinear96_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR96);}
+static struct ast_frame *slinear96_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 3840, AST_FORMAT_SLINEAR96);}
 static struct ast_format_def slin96_f = {
 	.name = "sln96",
 	.exts = "sln96",
-	.write = slinear_write,
+	.write = slinear96_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -213,11 +231,12 @@ static struct ast_format_def slin96_f = {
 	.buf_size = 3840 + AST_FRIENDLY_OFFSET,
 };
 
-static struct ast_frame *slinear192_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 7680);}
+static int slinear192_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR192);}
+static struct ast_frame *slinear192_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 7680, AST_FORMAT_SLINEAR192);}
 static struct ast_format_def slin192_f = {
 	.name = "sln192",
 	.exts = "sln192",
-	.write = slinear_write,
+	.write = slinear192_write,
 	.seek = slinear_seek,
 	.trunc = slinear_trunc,
 	.tell = slinear_tell,
@@ -240,16 +259,15 @@ static struct ast_format_def *slin_list[] = {
 static int load_module(void)
 {
 	int i;
-
-	slin_f.format = ast_format_slin;
-	slin12_f.format = ast_format_slin12;
-	slin16_f.format = ast_format_slin16;
-	slin24_f.format = ast_format_slin24;
-	slin32_f.format = ast_format_slin32;
-	slin44_f.format = ast_format_slin44;
-	slin48_f.format = ast_format_slin48;
-	slin96_f.format = ast_format_slin96;
-	slin192_f.format = ast_format_slin192;
+	ast_format_set(&slin_f.format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&slin12_f.format, AST_FORMAT_SLINEAR12, 0);
+	ast_format_set(&slin16_f.format, AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(&slin24_f.format, AST_FORMAT_SLINEAR24, 0);
+	ast_format_set(&slin32_f.format, AST_FORMAT_SLINEAR32, 0);
+	ast_format_set(&slin44_f.format, AST_FORMAT_SLINEAR44, 0);
+	ast_format_set(&slin48_f.format, AST_FORMAT_SLINEAR48, 0);
+	ast_format_set(&slin96_f.format, AST_FORMAT_SLINEAR96, 0);
+	ast_format_set(&slin192_f.format, AST_FORMAT_SLINEAR192, 0);
 
 	for (i = 0; i < ARRAY_LEN(slin_list); i++) {
 		if (ast_format_def_register(slin_list[i])) {
@@ -274,7 +292,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw Signed Linear Audio support (SLN) 8khz-192khz",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_vox.c b/formats/format_vox.c
index 0440885..f640021 100644
--- a/formats/format_vox.c
+++ b/formats/format_vox.c
@@ -30,12 +30,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #define BUF_SIZE	80		/* 80 bytes, 160 samples */
 #define VOX_SAMPLES	160
@@ -45,6 +44,9 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext)
 	int res;
 
 	/* Send a frame from the file to the appropriate channel */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_ADPCM, 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
 	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) {
 		if (res)
@@ -59,6 +61,14 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext)
 static int vox_write(struct ast_filestream *s, struct ast_frame *f)
 {
 	int res;
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_ADPCM) {
+		ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
 			ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
 			return -1;
@@ -137,7 +147,7 @@ static struct ast_format_def vox_f = {
 
 static int load_module(void)
 {
-	vox_f.format = ast_format_adpcm;
+	ast_format_set(&vox_f.format, AST_FORMAT_ADPCM, 0);
 	if (ast_format_def_register(&vox_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -149,7 +159,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Dialogic VOX (ADPCM) File Format",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_wav.c b/formats/format_wav.c
index fb2e94c..5418ea0 100644
--- a/formats/format_wav.c
+++ b/formats/format_wav.c
@@ -30,14 +30,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/format.h"
-#include "asterisk/codec.h"
 
 /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
 
@@ -64,14 +61,14 @@ struct wav_desc {	/* format-specific parameters */
 #define ltohs(b) (b)
 #else
 #if __BYTE_ORDER == __BIG_ENDIAN
-#define htoll(b)  \
-          (((((b)      ) & 0xFF) << 24) | \
-	       ((((b) >>  8) & 0xFF) << 16) | \
-		   ((((b) >> 16) & 0xFF) <<  8) | \
-		   ((((b) >> 24) & 0xFF)      ))
+#define htoll(b) \
+	(((((b)      ) & 0xFF) << 24) | \
+	((( (b) >>  8) & 0xFF) << 16) | \
+	((( (b) >> 16) & 0xFF) <<  8) | \
+	((( (b) >> 24) & 0xFF)      ))
 #define htols(b) \
-          (((((b)      ) & 0xFF) << 8) | \
-		   ((((b) >> 8) & 0xFF)      ))
+	(((((b)      ) & 0xFF) <<  8) | \
+	((( (b) >>  8) & 0xFF)      ))
 #define ltohl(b) htoll(b)
 #define ltohs(b) htols(b)
 #else
@@ -110,8 +107,8 @@ static int check_header_fmt(FILE *f, int hsize, int hz)
 		return -1;
 	}
 	if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
-	    ((ltohl(freq) == 8000) && (hz != 8000)) ||
-	    ((ltohl(freq) == 16000) && (hz != 16000))) {
+		((ltohl(freq) == 8000) && (hz != 8000)) ||
+		((ltohl(freq) == 16000) && (hz != 16000))) {
 		ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
 		return -1;
 	}
@@ -153,7 +150,9 @@ static int check_header(FILE *f, int hz)
 		ast_log(LOG_WARNING, "Read failed (size)\n");
 		return -1;
 	}
+#if __BYTE_ORDER == __BIG_ENDIAN
 	size = ltohl(size);
+#endif
 	if (fread(&formtype, 1, 4, f) != 4) {
 		ast_log(LOG_WARNING, "Read failed (formtype)\n");
 		return -1;
@@ -170,30 +169,32 @@ static int check_header(FILE *f, int hz)
 	for(;;)
 	{ 
 		char buf[4];
-	    
-	    /* Begin data chunk */
-	    if (fread(&buf, 1, 4, f) != 4) {
+		
+		/* Begin data chunk */
+		if (fread(&buf, 1, 4, f) != 4) {
 			ast_log(LOG_WARNING, "Read failed (block header format)\n");
 			return -1;
-	    }
-	    /* Data has the actual length of data in it */
-	    if (fread(&data, 1, 4, f) != 4) {
+		}
+		/* Data has the actual length of data in it */
+		if (fread(&data, 1, 4, f) != 4) {
 			ast_log(LOG_WARNING, "Read failed (block '%.4s' header length)\n", buf);
 			return -1;
-	    }
-	    data = ltohl(data);
+		}
+#if __BYTE_ORDER == __BIG_ENDIAN
+		data = ltohl(data);
+#endif
 		if (memcmp(&buf, "fmt ", 4) == 0) {
 			if (check_header_fmt(f, data, hz))
 				return -1;
 			continue;
 		}
-	    if(memcmp(buf, "data", 4) == 0 ) 
+		if(memcmp(buf, "data", 4) == 0 ) 
 			break;
 		ast_log(LOG_DEBUG, "Skipping unknown block '%.4s'\n", buf);
-	    if (fseek(f,data,SEEK_CUR) == -1 ) {
+		if (fseek(f,data,SEEK_CUR) == -1 ) {
 			ast_log(LOG_WARNING, "Failed to skip '%.4s' block: %d\n", buf, data);
 			return -1;
-	    }
+		}
 	}
 #if 0
 	curpos = lseek(fd, 0, SEEK_CUR);
@@ -322,7 +323,7 @@ static int wav_open(struct ast_filestream *s)
 	   if we did, it would go here.  We also might want to check
 	   and be sure it's a valid file.  */
 	struct wav_desc *tmp = (struct wav_desc *)s->_private;
-	if ((tmp->maxlen = check_header(s->f, ast_format_get_sample_rate(s->fmt->format))) < 0)
+	if ((tmp->maxlen = check_header(s->f, (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0)
 		return -1;
 	return 0;
 }
@@ -334,7 +335,7 @@ static int wav_rewrite(struct ast_filestream *s, const char *comment)
 	   and be sure it's a valid file.  */
 
 	struct wav_desc *tmp = (struct wav_desc *)s->_private;
-	tmp->hz = ast_format_get_sample_rate(s->fmt->format);
+	tmp->hz = (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000);
 	if (write_header(s->f,tmp->hz))
 		return -1;
 	return 0;
@@ -382,6 +383,9 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
 	if (bytes < 0)
 		bytes = 0;
 /* 	ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, (fs->hz == 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR), 0);
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
 	
 	if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) {
@@ -412,6 +416,18 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
 	struct wav_desc *s = (struct wav_desc *)fs->_private;
 	int res;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if ((f->subclass.format.id != AST_FORMAT_SLINEAR) && (f->subclass.format.id != AST_FORMAT_SLINEAR16)) {
+		ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
+	if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n");
+		return -1;
+	}
 	if (!f->datalen)
 		return -1;
 
@@ -461,13 +477,14 @@ static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 		return -1;
 	}
 
-	if (whence == SEEK_SET)
+	if (whence == SEEK_SET) {
 		offset = samples + min;
-	else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
+	} else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) {
 		offset = samples + cur;
-	else if (whence == SEEK_END)
+	} else if (whence == SEEK_END) {
 		offset = max - samples;
-        if (whence != SEEK_FORCECUR) {
+	}
+	if (whence != SEEK_FORCECUR) {
 		offset = (offset > max)?max:offset;
 	}
 	/* always protect the header space. */
@@ -535,8 +552,8 @@ static struct ast_format_def wav_f = {
 
 static int load_module(void)
 {
-	wav_f.format = ast_format_slin;
-	wav16_f.format = ast_format_slin16;
+	ast_format_set(&wav_f.format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&wav16_f.format, AST_FORMAT_SLINEAR16, 0);
 	if (ast_format_def_register(&wav_f)
 		|| ast_format_def_register(&wav16_f))
 		return AST_MODULE_LOAD_FAILURE;
@@ -550,7 +567,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c
index 2591055..a559c83 100644
--- a/formats/format_wav_gsm.c
+++ b/formats/format_wav_gsm.c
@@ -33,12 +33,11 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/mod_format.h"
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
-#include "asterisk/format_cache.h"
 
 #include "msgsm.h"
 
@@ -74,14 +73,14 @@ struct wavg_desc {
 #define ltohs(b) (b)
 #else
 #if __BYTE_ORDER == __BIG_ENDIAN
-#define htoll(b)  \
-          (((((b)      ) & 0xFF) << 24) | \
-	       ((((b) >>  8) & 0xFF) << 16) | \
-		   ((((b) >> 16) & 0xFF) <<  8) | \
-		   ((((b) >> 24) & 0xFF)      ))
+#define htoll(b) \
+	(((((b)      ) & 0xFF) << 24) | \
+	((( (b) >>  8) & 0xFF) << 16) | \
+	((( (b) >> 16) & 0xFF) <<  8) | \
+	((( (b) >> 24) & 0xFF)      ))
 #define htols(b) \
-          (((((b)      ) & 0xFF) << 8) | \
-		   ((((b) >> 8) & 0xFF)      ))
+	(((((b)      ) & 0xFF) <<  8) | \
+	((( (b) >>  8) & 0xFF)      ))
 #define ltohl(b) htoll(b)
 #define ltohs(b) htols(b)
 #else
@@ -105,7 +104,9 @@ static int check_header(FILE *f)
 		ast_log(LOG_WARNING, "Read failed (size)\n");
 		return -1;
 	}
+#if __BYTE_ORDER == __BIG_ENDIAN
 	size = ltohl(size);
+#endif
 	if (fread(&formtype, 1, 4, f) != 4) {
 		ast_log(LOG_WARNING, "Read failed (formtype)\n");
 		return -1;
@@ -394,23 +395,16 @@ static int wav_rewrite(struct ast_filestream *s, const char *comment)
 	return 0;
 }
 
-static void wav_close(struct ast_filestream *s)
-{
-	if (s->mode == O_RDONLY) {
-		return;
-	}
-
-	if (s->filename) {
-		update_header(s->f);
-	}
-}
-
 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
 {
 	/* Send a frame from the file to the appropriate channel */
 	struct wavg_desc *fs = (struct wavg_desc *)s->_private;
 
+	s->fr.frametype = AST_FRAME_VOICE;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_GSM, 0);
+	s->fr.offset = AST_FRIENDLY_OFFSET;
 	s->fr.samples = GSM_SAMPLES;
+	s->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE);
 	if (fs->secondhalf) {
 		/* Just return a frame based on the second GSM frame */
@@ -440,6 +434,14 @@ static int wav_write(struct ast_filestream *s, struct ast_frame *f)
 	int size;
 	struct wavg_desc *fs = (struct wavg_desc *)s->_private;
 
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+		return -1;
+	}
+	if (f->subclass.format.id != AST_FORMAT_GSM) {
+		ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
 	/* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE
 	 * we assume it is already in the correct format.
 	 */
@@ -468,6 +470,7 @@ static int wav_write(struct ast_filestream *s, struct ast_frame *f)
 			ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
 			return -1;
 		}
+		update_header(s->f); /* XXX inefficient! */
 	}
 	return 0;
 }
@@ -559,14 +562,13 @@ static struct ast_format_def wav49_f = {
 	.trunc = wav_trunc,
 	.tell = wav_tell,
 	.read = wav_read,
-	.close = wav_close,
 	.buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET,
 	.desc_size = sizeof(struct wavg_desc),
 };
 
 static int load_module(void)
 {
-	wav49_f.format = ast_format_gsm;
+	ast_format_set(&wav49_f.format, AST_FORMAT_GSM, 0);
 	if (ast_format_def_register(&wav49_f))
 		return AST_MODULE_LOAD_FAILURE;
 	return AST_MODULE_LOAD_SUCCESS;
@@ -578,7 +580,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV format (Proprietary GSM)",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/funcs/Makefile b/funcs/Makefile
index 1caa7c3..2c1c1cb 100644
--- a/funcs/Makefile
+++ b/funcs/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for dialplan functions
 #
diff --git a/funcs/func_aes.c b/funcs/func_aes.c
index 47b35f0..2e1959c 100644
--- a/funcs/func_aes.c
+++ b/funcs/func_aes.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
@@ -179,7 +179,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "AES dialplan functions",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.nonoptreq = "res_crypto",
diff --git a/funcs/func_audiohookinherit.c b/funcs/func_audiohookinherit.c
index 737f04e..ea5c5e9 100644
--- a/funcs/func_audiohookinherit.c
+++ b/funcs/func_audiohookinherit.c
@@ -29,45 +29,262 @@
  */
 
 /*** MODULEINFO
-	<support_level>deprecated</support_level>
+	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
+#include "asterisk/datastore.h"
 #include "asterisk/channel.h"
 #include "asterisk/logger.h"
+#include "asterisk/audiohook.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 
 /*** DOCUMENTATION
-	<function name = "AUDIOHOOK_INHERIT" language="en_US">
+ 	<function name = "AUDIOHOOK_INHERIT" language="en_US">
 		<synopsis>
-			DEPRECATED: Used to set whether an audiohook may be inherited to another
-			channel. Due to architectural changes in Asterisk 12, audiohook inheritance
-			is performed automatically and this function now lacks function.
+			Set whether an audiohook may be inherited to another channel
 		</synopsis>
+		<syntax>
+			<parameter name="source" required="true">
+				<para>The built-in sources in Asterisk are</para>
+				<enumlist>
+					<enum name="MixMonitor" />
+					<enum name="Chanspy" />
+					<enum name="Volume" />
+					<enum name="Speex" />
+					<enum name="pitch_shift" />
+					<enum name="JACK_HOOK" />
+					<enum name="Mute" />
+				</enumlist>
+				<para>Note that the names are not case-sensitive</para>
+			</parameter>
+		</syntax>
 		<description>
-			<para>Prior to Asterisk 12, masquerades would occur under all sorts of
-			situations which were hard to predict.  In Asterisk 12, masquerades only
-			occur as a result of a small set of operations for which inheriting all
-			audiohooks from the original channel is now safe.  So in Asterisk 12.5+,
-			all audiohooks are inherited without needing other controls expressing
-			which audiohooks should be inherited under which conditions.</para>
+			<para>By enabling audiohook inheritance on the channel, you are giving
+			permission for an audiohook to be inherited by a descendent channel.
+			Inheritance may be be disabled at any point as well.</para>
+
+			<para>Example scenario:</para>
+			<para>exten => 2000,1,MixMonitor(blah.wav)</para>
+			<para>exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)</para>
+			<para>exten => 2000,n,Dial(SIP/2000)</para>
+			<para>
+			</para>
+			<para>exten => 4000,1,Dial(SIP/4000)</para>
+			<para>
+			</para>
+			<para>exten => 5000,1,MixMonitor(blah2.wav)</para>
+			<para>exten => 5000,n,Dial(SIP/5000)</para>
+			<para>
+			</para>
+			<para>In this basic dialplan scenario, let's consider the following sample calls</para>
+			<para>Call 1: Caller dials 2000. The person who answers then executes an attended</para>
+			<para>        transfer to 4000.</para>
+			<para>Result: Since extension 2000 set MixMonitor to be inheritable, after the</para>
+			<para>        transfer to 4000 has completed, the call will continue to be recorded
+			to blah.wav</para>
+			<para>
+			</para>
+			<para>Call 2: Caller dials 5000. The person who answers then executes an attended</para>
+			<para>        transfer to 4000.</para>
+			<para>Result: Since extension 5000 did not set MixMonitor to be inheritable, the</para>
+			<para>        recording will stop once the call has been transferred to 4000.</para>
 		</description>
 	</function>
  ***/
 
-static int func_inheritance_write(struct ast_channel *chan, const char *function, char *data, const char *value)
+struct inheritable_audiohook {
+	AST_LIST_ENTRY(inheritable_audiohook) list;
+	char source[1];
+};
+
+struct audiohook_inheritance_datastore {
+	AST_LIST_HEAD (, inheritable_audiohook) allowed_list;
+};
+
+static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+static void audiohook_inheritance_destroy (void *data);
+static const struct ast_datastore_info audiohook_inheritance_info = {
+	.type = "audiohook inheritance",
+	.destroy = audiohook_inheritance_destroy,
+	.chan_fixup = audiohook_inheritance_fixup,
+};
+
+/*! \brief Move audiohooks as defined by previous calls to the AUDIOHOOK_INHERIT function
+ *
+ * Move allowed audiohooks from the old channel to the new channel.
+ *
+ * \param data The ast_datastore containing audiohook inheritance information that will be moved
+ * \param old_chan The "clone" channel from a masquerade. We are moving the audiohook in question off of this channel
+ * \param new_chan The "original" channel from a masquerade. We are moving the audiohook in question to this channel
+ * \return Void
+ */
+static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct inheritable_audiohook *audiohook = NULL;
+	struct audiohook_inheritance_datastore *datastore = data;
+
+	ast_debug(2, "inheritance fixup occurring for channels %s(%p) and %s(%p)", ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
+
+	AST_LIST_TRAVERSE(&datastore->allowed_list, audiohook, list) {
+		ast_audiohook_move_by_source(old_chan, new_chan, audiohook->source);
+		ast_debug(3, "Moved audiohook %s from %s(%p) to %s(%p)\n",
+			audiohook->source, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
+	}
+	return;
+}
+
+/*! \brief Destroy dynamically allocated data on an audiohook_inheritance_datastore
+ *
+ * \param data Pointer to the audiohook_inheritance_datastore in question.
+ * \return Void
+ */
+static void audiohook_inheritance_destroy(void *data)
+{
+	struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = data;
+	struct inheritable_audiohook *inheritable_audiohook = NULL;
+
+	while ((inheritable_audiohook = AST_LIST_REMOVE_HEAD(&audiohook_inheritance_datastore->allowed_list, list))) {
+		ast_free(inheritable_audiohook);
+	}
+
+	ast_free(audiohook_inheritance_datastore);
+}
+
+/*! \brief create an audiohook_inheritance_datastore and attach it to a channel
+ *
+ * \param chan The channel to which we wish to attach the new datastore
+ * \return Returns the newly created audiohook_inheritance_datastore or NULL on error
+ */
+static struct audiohook_inheritance_datastore *setup_inheritance_datastore(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+	struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = NULL;
+
+	if (!(datastore = ast_datastore_alloc(&audiohook_inheritance_info, NULL))) {
+		return NULL;
+	}
+
+	if (!(audiohook_inheritance_datastore = ast_calloc(1, sizeof(*audiohook_inheritance_datastore)))) {
+		ast_datastore_free(datastore);
+		return NULL;
+	}
+
+	datastore->data = audiohook_inheritance_datastore;
+	ast_channel_lock(chan);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
+	return audiohook_inheritance_datastore;
+}
+
+/*! \brief Create a new inheritable_audiohook structure and add it to an audiohook_inheritance_datastore
+ *
+ * \param audiohook_inheritance_datastore The audiohook_inheritance_datastore we want to add the new inheritable_audiohook to
+ * \param source The audiohook source for the newly created inheritable_audiohook
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+static int setup_inheritable_audiohook(struct audiohook_inheritance_datastore *audiohook_inheritance_datastore, const char *source)
 {
-	static int warned = 0;
+	struct inheritable_audiohook *inheritable_audiohook = NULL;
+
+	inheritable_audiohook = ast_calloc(1, sizeof(*inheritable_audiohook) + strlen(source));
 
-	if (!warned) {
-		ast_log(LOG_NOTICE, "AUDIOHOOK_INHERIT is deprecated and now does nothing.\n");
-		warned++;
+	if (!inheritable_audiohook) {
+		return -1;
 	}
 
+	strcpy(inheritable_audiohook->source, source);
+	AST_LIST_INSERT_TAIL(&audiohook_inheritance_datastore->allowed_list, inheritable_audiohook, list);
+	ast_debug(3, "Set audiohook %s to be inheritable\n", source);
 	return 0;
 }
 
+/*! \brief Set the permissibility of inheritance for a particular audiohook source on a channel
+ *
+ * For details regarding what happens in the function, see the inline comments
+ *
+ * \param chan The channel we are operating on
+ * \param function The name of the dialplan function (AUDIOHOOK_INHERIT)
+ * \param data The audiohook source for which we are setting inheritance permissions
+ * \param value The value indicating the permission for audiohook inheritance
+ */
+static int func_inheritance_write(struct ast_channel *chan, const char *function, char *data, const char *value)
+{
+	int allow;
+	struct ast_datastore *datastore = NULL;
+	struct audiohook_inheritance_datastore *inheritance_datastore = NULL;
+	struct inheritable_audiohook *inheritable_audiohook;
+
+	/* Step 1: Get data from function call */
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "No argument provided to INHERITANCE function.\n");
+		return -1;
+	}
+
+	if (ast_strlen_zero(value)) {
+		ast_log(LOG_WARNING, "No value provided to INHERITANCE function.\n");
+		return -1;
+	}
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to INHERITANCE function.\n");
+		return -1;
+	}
+
+	allow = ast_true(value);
+
+	/* Step 2: retrieve or set up datastore */
+	ast_channel_lock(chan);
+	if (!(datastore = ast_channel_datastore_find(chan, &audiohook_inheritance_info, NULL))) {
+		ast_channel_unlock(chan);
+		/* In the case where we cannot find the datastore, we can take a few shortcuts */
+		if (!allow) {
+			ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
+			return 0;
+		} else if (!(inheritance_datastore = setup_inheritance_datastore(chan))) {
+			ast_log(LOG_WARNING, "Unable to set up audiohook inheritance datastore on channel %s\n", ast_channel_name(chan));
+			return -1;
+		} else {
+			return setup_inheritable_audiohook(inheritance_datastore, data);
+		}
+	} else {
+		inheritance_datastore = datastore->data;
+	}
+	ast_channel_unlock(chan);
+
+	/* Step 3: Traverse the list to see if we're trying something redundant */
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&inheritance_datastore->allowed_list, inheritable_audiohook, list) {
+		if (!strcasecmp(inheritable_audiohook->source, data)) {
+			if (allow) {
+				ast_debug(2, "Audiohook source %s is already set up to be inherited from channel %s\n", data, ast_channel_name(chan));
+				return 0;
+			} else {
+				ast_debug(2, "Removing inheritability of audiohook %s from channel %s\n", data, ast_channel_name(chan));
+				AST_LIST_REMOVE_CURRENT(list);
+				ast_free(inheritable_audiohook);
+				return 0;
+			}
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	/* Step 4: There is no step 4 */
+
+	/* Step 5: This means we are addressing an audiohook source which we have not encountered yet for the channel. Create a new inheritable
+	 * audiohook structure if we're allowing inheritance, or just return if not
+	 */
+
+	if (allow) {
+		return setup_inheritable_audiohook(inheritance_datastore, data);
+	} else {
+		ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
+		return 0;
+	}
+}
+
 static struct ast_custom_function inheritance_function = {
 	.name = "AUDIOHOOK_INHERIT",
 	.write = func_inheritance_write,
@@ -86,5 +303,4 @@ static int load_module(void)
 		return AST_MODULE_LOAD_SUCCESS;
 	}
 }
-AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Audiohook inheritance placeholder function");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audiohook inheritance function");
diff --git a/funcs/func_base64.c b/funcs/func_base64.c
index 583c1f8..1a7619d 100644
--- a/funcs/func_base64.c
+++ b/funcs/func_base64.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"	/* function register/unregister */
diff --git a/funcs/func_blacklist.c b/funcs/func_blacklist.c
index 9c2353a..bb04505 100644
--- a/funcs/func_blacklist.c
+++ b/funcs/func_blacklist.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
diff --git a/funcs/func_callcompletion.c b/funcs/func_callcompletion.c
index e3f7b32..cb1cd59 100644
--- a/funcs/func_callcompletion.c
+++ b/funcs/func_callcompletion.c
@@ -27,7 +27,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c
index 6f42e09..1af4218 100644
--- a/funcs/func_callerid.c
+++ b/funcs/func_callerid.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -1152,6 +1152,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 		ast_channel_redirecting(chan)->from.number.valid = 1;
 		ast_free(ast_channel_redirecting(chan)->from.number.str);
 		ast_channel_redirecting(chan)->from.number.str = ast_strdup(value);
+		if (ast_channel_cdr(chan)) {
+			ast_cdr_setcid(ast_channel_cdr(chan), chan);
+		}
 	} else if (!strcasecmp("dnid", member.argv[0])) {
 		ast_party_dialed_set_init(&dialed, ast_channel_dialed(chan));
 		if (member.argc == 1) {
@@ -1169,6 +1172,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 				dialed.number.str = ast_strdup(value);
 				ast_trim_blanks(dialed.number.str);
 				ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
+				if (ast_channel_cdr(chan)) {
+					ast_cdr_setcid(ast_channel_cdr(chan), chan);
+				}
 			} else if (member.argc == 3 && !strcasecmp("plan", member.argv[2])) {
 				/* dnid-num-plan */
 				val = ast_strdupa(value);
@@ -1176,6 +1182,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 
 				if (('0' <= val[0]) && (val[0] <= '9')) {
 					ast_channel_dialed(chan)->number.plan = atoi(val);
+					if (ast_channel_cdr(chan)) {
+						ast_cdr_setcid(ast_channel_cdr(chan), chan);
+					}
 				} else {
 					ast_log(LOG_ERROR,
 						"Unknown type-of-number/numbering-plan '%s', value unchanged\n", val);
@@ -1193,6 +1202,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 			switch (status) {
 			case ID_FIELD_VALID:
 				ast_party_dialed_set(ast_channel_dialed(chan), &dialed);
+				if (ast_channel_cdr(chan)) {
+					ast_cdr_setcid(ast_channel_cdr(chan), chan);
+				}
 				break;
 			case ID_FIELD_INVALID:
 				break;
@@ -1210,6 +1222,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 
 		if (('0' <= val[0]) && (val[0] <= '9')) {
 			ast_channel_caller(chan)->ani2 = atoi(val);
+			if (ast_channel_cdr(chan)) {
+				ast_cdr_setcid(ast_channel_cdr(chan), chan);
+			}
 		} else {
 			ast_log(LOG_ERROR, "Unknown callerid ani2 '%s', value unchanged\n", val);
 		}
@@ -1224,6 +1239,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 		switch (status) {
 		case ID_FIELD_VALID:
 			ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
+			if (ast_channel_cdr(chan)) {
+				ast_cdr_setcid(ast_channel_cdr(chan), chan);
+			}
 			break;
 		case ID_FIELD_INVALID:
 			break;
@@ -1238,6 +1256,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 		switch (status) {
 		case ID_FIELD_VALID:
 			ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
+			if (ast_channel_cdr(chan)) {
+				ast_cdr_setcid(ast_channel_cdr(chan), chan);
+			}
 			break;
 		case ID_FIELD_INVALID:
 			break;
@@ -1252,6 +1273,9 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
 		switch (status) {
 		case ID_FIELD_VALID:
 			ast_channel_set_caller_event(chan, &caller, NULL);
+			if (ast_channel_cdr(chan)) {
+				ast_cdr_setcid(ast_channel_cdr(chan), chan);
+			}
 			break;
 		case ID_FIELD_INVALID:
 			break;
@@ -1479,7 +1503,7 @@ static int redirecting_read(struct ast_channel *chan, const char *cmd, char *dat
 	if (!strcasecmp("orig", member.argv[0])) {
 		if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) {
 			ast_copy_string(buf,
-				ast_redirecting_reason_name(&ast_redirecting->orig_reason), len);
+				ast_redirecting_reason_name(ast_redirecting->orig_reason), len);
 		} else {
 			status = party_id_read(buf, len, member.argc - 1, member.argv + 1,
 				&ast_redirecting->orig);
@@ -1523,7 +1547,7 @@ static int redirecting_read(struct ast_channel *chan, const char *cmd, char *dat
 			ast_named_caller_presentation(
 				ast_party_id_presentation(&ast_redirecting->from)), len);
 	} else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) {
-		ast_copy_string(buf, ast_redirecting_reason_name(&ast_redirecting->reason), len);
+		ast_copy_string(buf, ast_redirecting_reason_name(ast_redirecting->reason), len);
 	} else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
 		snprintf(buf, len, "%d", ast_redirecting->count);
 	} else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) {
@@ -1645,16 +1669,10 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
 			}
 
 			if (reason < 0) {
-			/* The argument passed into the function does not correspond to a pre-defined
-			 * reason, so we can just set the reason string to what was given and set the
-			 * code to be unknown
-			 */
-				redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-				redirecting.orig_reason.str = val;
-				set_it(chan, &redirecting, NULL);
+				ast_log(LOG_ERROR,
+					"Unknown redirecting orig reason '%s', value unchanged\n", val);
 			} else {
-				redirecting.orig_reason.code = reason;
-				redirecting.orig_reason.str = "";
+				redirecting.orig_reason = reason;
 				set_it(chan, &redirecting, NULL);
 			}
 		} else {
@@ -1734,16 +1752,9 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
 		}
 
 		if (reason < 0) {
-			/* The argument passed into the function does not correspond to a pre-defined
-			 * reason, so we can just set the reason string to what was given and set the
-			 * code to be unknown
-			 */
-			redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
-			redirecting.reason.str = val;
-			set_it(chan, &redirecting, NULL);
+			ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val);
 		} else {
-			redirecting.reason.code = reason;
-			redirecting.reason.str = "";
+			redirecting.reason = reason;
 			set_it(chan, &redirecting, NULL);
 		}
 	} else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {
diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c
index 9042451..adb4274 100644
--- a/funcs/func_cdr.c
+++ b/funcs/func_cdr.c
@@ -20,7 +20,7 @@
  *
  * \brief  Call Detail Record related dialplan functions
  *
- * \author Anthony Minessale II
+ * \author Anthony Minessale II 
  *
  * \ingroup functions
  */
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -39,14 +39,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
 #include "asterisk/cdr.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
 
 /*** DOCUMENTATION
 	<function name="CDR" language="en_US">
 		<synopsis>
 			Gets or sets a CDR variable.
-		</synopsis>
+		</synopsis>	
 		<syntax>
 			<parameter name="name" required="true">
 				<para>CDR field name:</para>
@@ -58,27 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 						<para>Last application arguments.</para>
 					</enum>
 					<enum name="disposition">
-						<para>The final state of the CDR.</para>
-						<enumlist>
-							<enum name="0">
-								<para><literal>NO ANSWER</literal></para>
-							</enum>
-							<enum name="1">
-								<para><literal>NO ANSWER</literal> (NULL record)</para>
-							</enum>
-							<enum name="2">
-								<para><literal>FAILED</literal></para>
-							</enum>
-							<enum name="4">
-								<para><literal>BUSY</literal></para>
-							</enum>
-							<enum name="8">
-								<para><literal>ANSWERED</literal></para>
-							</enum>
-							<enum name="16">
-								<para><literal>CONGESTION</literal></para>
-							</enum>
-						</enumlist>
+						<para>ANSWERED, NO ANSWER, BUSY, FAILED.</para>
 					</enum>
 					<enum name="src">
 						<para>Source.</para>
@@ -87,16 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 						<para>Time the call started.</para>
 					</enum>
 					<enum name="amaflags">
-						<para>R/W the Automatic Message Accounting (AMA) flags on the channel.
-						When read from a channel, the integer value will always be returned.
-						When written to a channel, both the string format or integer value
-						is accepted.</para>
-						<enumlist>
-							<enum name="1"><para><literal>OMIT</literal></para></enum>
-							<enum name="2"><para><literal>BILLING</literal></para></enum>
-							<enum name="3"><para><literal>DOCUMENTATION</literal></para></enum>
-						</enumlist>
-						<warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
+						<para>DOCUMENTATION, BILL, IGNORE, etc.</para>
 					</enum>
 					<enum name="dst">
 						<para>Destination.</para>
@@ -106,7 +75,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 					</enum>
 					<enum name="accountcode">
 						<para>The channel's account code.</para>
-						<warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
 					</enum>
 					<enum name="dcontext">
 						<para>Destination context.</para>
@@ -145,6 +113,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 					<option name="f">
 						<para>Returns billsec or duration fields as floating point values.</para>
 					</option>
+					<option name="l">
+						<para>Uses the most recent CDR on a channel with multiple records</para>
+					</option>
+					<option name="r">
+						<para>Searches the entire stack of CDRs on the channel.</para>
+					</option>
+					<option name="s">
+						<para>Skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.
+						(on setting/writing CDR vars only)</para>
+					</option>
 					<option name="u">
 						<para>Retrieves the raw, unprocessed value.</para>
 						<para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
@@ -159,424 +137,177 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426252 $")
 			<para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
 			<literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
 			a name not on the above list, and create your own variable, whose value can be changed
-			with this function, and this variable will be stored on the CDR.</para>
-			<note><para>CDRs can only be modified before the bridge between two channels is
-			torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
-			application has returned.</para></note>
+			with this function, and this variable will be stored on the cdr.</para>
+			<note><para>For setting CDR values, the <literal>l</literal> flag does not apply to
+			setting the <literal>accountcode</literal>, <literal>userfield</literal>, or
+			<literal>amaflags</literal>.</para><para>CDRs can only be modified before the bridge
+			between two channels is torn down. For example, CDRs may not be modified after the
+			<literal>Dial</literal> application has returned.</para></note>
+			<para>Raw values for <literal>disposition</literal>:</para>
+			<enumlist>
+				<enum name="0">
+					<para>NO ANSWER</para>
+				</enum>
+				<enum name="1">
+					<para>NO ANSWER (NULL record)</para>
+				</enum>
+				<enum name="2">
+					<para>FAILED</para>
+				</enum>
+				<enum name="4">
+					<para>BUSY</para>
+				</enum>
+				<enum name="8">
+					<para>ANSWERED</para>
+				</enum>
+			</enumlist>
+			<para>Raw values for <literal>amaflags</literal>:</para>
+			<enumlist>
+				<enum name="1">
+					<para>OMIT</para>
+				</enum>
+				<enum name="2">
+					<para>BILLING</para>
+				</enum>
+				<enum name="3">
+					<para>DOCUMENTATION</para>
+				</enum>
+			</enumlist>
 			<para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
 		</description>
 	</function>
-	<function name="CDR_PROP" language="en_US">
-		<synopsis>
-			Set a property on a channel's CDR.
-		</synopsis>
-		<syntax>
-			<parameter name="name" required="true">
-				<para>The property to set on the CDR.</para>
-				<enumlist>
-					<enum name="party_a">
-						<para>Set this channel as the preferred Party A when
-						channels are associated together.</para>
-						<para>Write-Only</para>
-					</enum>
-					<enum name="disable">
-						<para>Disable CDRs for this channel.</para>
-						<para>Write-Only</para>
-					</enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>This function sets a property on a channel's CDR. Properties
-			alter the behavior of how the CDR operates for that channel.</para>
-		</description>
-	</function>
  ***/
 
 enum cdr_option_flags {
+	OPT_RECURSIVE = (1 << 0),
 	OPT_UNPARSED = (1 << 1),
-	OPT_FLOAT = (1 << 2),
+	OPT_LAST = (1 << 2),
+	OPT_SKIPLOCKED = (1 << 3),
+	OPT_FLOAT = (1 << 4),
 };
 
 AST_APP_OPTIONS(cdr_func_options, {
 	AST_APP_OPTION('f', OPT_FLOAT),
+	AST_APP_OPTION('l', OPT_LAST),
+	AST_APP_OPTION('r', OPT_RECURSIVE),
+	AST_APP_OPTION('s', OPT_SKIPLOCKED),
 	AST_APP_OPTION('u', OPT_UNPARSED),
 });
 
-struct cdr_func_payload {
-	struct ast_channel *chan;
-	const char *cmd;
-	const char *arguments;
-	const char *value;
-	void *data;
-};
-
-struct cdr_func_data {
-	char *buf;
-	size_t len;
-};
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_read_message_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_write_message_type);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type);
-
-static void cdr_read_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct cdr_func_payload *payload = stasis_message_data(message);
-	struct cdr_func_data *output;
-	char *info;
-	char *value = NULL;
-	struct ast_flags flags = { 0 };
-	char tempbuf[512];
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(variable);
-		AST_APP_ARG(options);
-	);
-
-	if (cdr_read_message_type() != stasis_message_type(message)) {
-		return;
-	}
-
-	ast_assert(payload != NULL);
-	output = payload->data;
-	ast_assert(output != NULL);
-
-	if (ast_strlen_zero(payload->arguments)) {
-		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable[,option]))\n)",
-			payload->cmd, payload->cmd);
-		return;
-	}
-	info = ast_strdupa(payload->arguments);
-	AST_STANDARD_APP_ARGS(args, info);
-
-	if (!ast_strlen_zero(args.options)) {
-		ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
-	}
-
-	if (ast_strlen_zero(ast_channel_name(payload->chan))) {
-		/* Format request on a dummy channel */
-		ast_cdr_format_var(ast_channel_cdr(payload->chan), args.variable, &value, tempbuf, sizeof(tempbuf), 0);
-		if (ast_strlen_zero(value)) {
-			return;
-		}
-		ast_copy_string(tempbuf, value, sizeof(tempbuf));
-		ast_set_flag(&flags, OPT_UNPARSED);
-	} else if (ast_cdr_getvar(ast_channel_name(payload->chan), args.variable, tempbuf, sizeof(tempbuf))) {
-		return;
-	}
-
-	if (ast_test_flag(&flags, OPT_FLOAT)
-		&& (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
-		long ms;
-		double dtime;
-
-		if (sscanf(tempbuf, "%30ld", &ms) != 1) {
-			ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-				args.variable, tempbuf, ast_channel_name(payload->chan));
-			return;
-		}
-		dtime = (double)(ms / 1000.0);
-		snprintf(tempbuf, sizeof(tempbuf), "%lf", dtime);
-	} else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
-		if (!strcasecmp("start", args.variable)
-			|| !strcasecmp("end", args.variable)
-			|| !strcasecmp("answer", args.variable)) {
-			struct timeval fmt_time;
-			struct ast_tm tm;
-			/* tv_usec is suseconds_t, which could be int or long */
-			long int tv_usec;
-
-			if (sscanf(tempbuf, "%ld.%ld", &fmt_time.tv_sec, &tv_usec) != 2) {
-				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(payload->chan));
-				return;
-			}
-			if (fmt_time.tv_sec) {
-				fmt_time.tv_usec = tv_usec;
-				ast_localtime(&fmt_time, &tm, NULL);
-				ast_strftime(tempbuf, sizeof(tempbuf), "%Y-%m-%d %T", &tm);
-			} else {
-				tempbuf[0] = '\0';
-			}
-		} else if (!strcasecmp("disposition", args.variable)) {
-			int disposition;
-
-			if (sscanf(tempbuf, "%8d", &disposition) != 1) {
-				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(payload->chan));
-				return;
-			}
-			snprintf(tempbuf, sizeof(tempbuf), "%s", ast_cdr_disp2str(disposition));
-		} else if (!strcasecmp("amaflags", args.variable)) {
-			int amaflags;
-
-			if (sscanf(tempbuf, "%8d", &amaflags) != 1) {
-				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(payload->chan));
-				return;
-			}
-			snprintf(tempbuf, sizeof(tempbuf), "%s", ast_channel_amaflags2string(amaflags));
-		}
-	}
-
-	ast_copy_string(output->buf, tempbuf, output->len);
-}
-
-static void cdr_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
+		    char *buf, size_t len)
 {
-	struct cdr_func_payload *payload = stasis_message_data(message);
+	char *ret = NULL;
 	struct ast_flags flags = { 0 };
+	struct ast_cdr *cdr;
 	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(variable);
-		AST_APP_ARG(options);
+			     AST_APP_ARG(variable);
+			     AST_APP_ARG(options);
 	);
-	char *parse;
 
-	if (cdr_write_message_type() != stasis_message_type(message)) {
-		return;
-	}
+	if (ast_strlen_zero(parse) || !chan)
+		return -1;
 
-	if (!payload) {
-		return;
+	ast_channel_lock(chan);
+	cdr = ast_channel_cdr(chan);
+	if (!cdr) {
+		ast_channel_unlock(chan);
+		return -1;
 	}
 
-	if (ast_strlen_zero(payload->arguments)) {
-		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
-			payload->cmd, payload->cmd);
-		return;
-	}
-	if (ast_strlen_zero(payload->value)) {
-		ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
-			payload->cmd, payload->cmd);
-		return;
-	}
-	parse = ast_strdupa(payload->arguments);
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	if (!ast_strlen_zero(args.options)) {
+	if (!ast_strlen_zero(args.options))
 		ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
-	}
-
-	if (!strcasecmp(args.variable, "accountcode")) {
-		ast_log(AST_LOG_WARNING, "Using the CDR function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n");
-		ast_channel_lock(payload->chan);
-		ast_channel_accountcode_set(payload->chan, payload->value);
-		ast_channel_unlock(payload->chan);
-	} else if (!strcasecmp(args.variable, "peeraccount")) {
-		ast_log(AST_LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
-	} else if (!strcasecmp(args.variable, "userfield")) {
-		ast_cdr_setuserfield(ast_channel_name(payload->chan), payload->value);
-	} else if (!strcasecmp(args.variable, "amaflags")) {
-		ast_log(AST_LOG_WARNING, "Using the CDR function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n");
-		if (isdigit(*payload->value)) {
-			int amaflags;
-			sscanf(payload->value, "%30d", &amaflags);
-			ast_channel_lock(payload->chan);
-			ast_channel_amaflags_set(payload->chan, amaflags);
-			ast_channel_unlock(payload->chan);
-		} else {
-			ast_channel_lock(payload->chan);
-			ast_channel_amaflags_set(payload->chan, ast_channel_string2amaflag(payload->value));
-			ast_channel_unlock(payload->chan);
-		}
-	} else {
-		ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value);
-	}
-	return;
-}
-
-static void cdr_prop_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct cdr_func_payload *payload = stasis_message_data(message);
-	enum ast_cdr_options option;
-	char *parse;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(variable);
-		AST_APP_ARG(options);
-	);
-
-	if (cdr_prop_write_message_type() != stasis_message_type(message)) {
-		return;
-	}
-
-	if (!payload) {
-		return;
-	}
-
-	if (ast_strlen_zero(payload->arguments)) {
-		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
-			payload->cmd, payload->cmd);
-		return;
-	}
-	if (ast_strlen_zero(payload->value)) {
-		ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
-			payload->cmd, payload->cmd);
-		return;
-	}
-	parse = ast_strdupa(payload->arguments);
-	AST_STANDARD_APP_ARGS(args, parse);
 
-	if (!strcasecmp("party_a", args.variable)) {
-		option = AST_CDR_FLAG_PARTY_A;
-	} else if (!strcasecmp("disable", args.variable)) {
-		option = AST_CDR_FLAG_DISABLE_ALL;
-	} else {
-		ast_log(AST_LOG_WARNING, "Unknown option %s used with %s\n", args.variable, payload->cmd);
-		return;
-	}
+	if (ast_test_flag(&flags, OPT_LAST))
+		while (cdr->next)
+			cdr = cdr->next;
 
-	if (ast_true(payload->value)) {
-		ast_cdr_set_property(ast_channel_name(payload->chan), option);
-	} else {
-		ast_cdr_clear_property(ast_channel_name(payload->chan), option);
-	}
-}
+	if (ast_test_flag(&flags, OPT_SKIPLOCKED))
+		while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next)
+			cdr = cdr->next;
 
+	if (!strcasecmp("billsec", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
+		if (!ast_tvzero(cdr->answer)) {
+			double hrtime;
 
-static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
-		    char *buf, size_t len)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
-	struct cdr_func_data output = { 0, };
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
+			if(!ast_tvzero(cdr->end))
+				hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
+			else
+				hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->answer) / 1000000.0);
 
-	if (!cdr_read_message_type()) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
-			ast_channel_name(chan));
-		return -1;
-	}
+			snprintf(buf, len, "%lf", hrtime);
+		} else {
+			snprintf(buf, len, "%lf", 0.0);
+		}
+		ret = buf;
+	} else if (!strcasecmp("duration", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
+			double hrtime;
 
-	payload = ao2_alloc(sizeof(*payload), NULL);
-	if (!payload) {
-		return -1;
-	}
-	payload->chan = chan;
-	payload->cmd = cmd;
-	payload->arguments = parse;
-	payload->data = &output;
-
-	buf[0] = '\0';/* Ensure the buffer is initialized. */
-	output.buf = buf;
-	output.len = len;
-
-	message = stasis_message_create(cdr_read_message_type(), payload);
-	if (!message) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
-			ast_channel_name(chan));
-		return -1;
-	}
+			if(!ast_tvzero(cdr->end))
+				hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
+			else
+				hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->start) / 1000000.0);
 
-	/* If this is a request on a dummy channel, we're doing post-processing on an
-	 * already dispatched CDR. Simply call the callback to calculate the value and
-	 * return, instead of posting to Stasis as we would for a running channel.
-	 */
-	if (ast_strlen_zero(ast_channel_name(chan))) {
-		cdr_read_callback(NULL, NULL, message);
-	} else {
-		RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
+			snprintf(buf, len, "%lf", hrtime);
 
-		if (!router) {
-			ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
-				ast_channel_name(chan));
-			return -1;
+		if (!ast_strlen_zero(buf)) {
+			ret = buf;
 		}
-		stasis_message_router_publish_sync(router, message);
+	} else {
+		ast_cdr_getvar(cdr, args.variable, &ret, buf, len,
+			       ast_test_flag(&flags, OPT_RECURSIVE),
+				   ast_test_flag(&flags, OPT_UNPARSED));
 	}
 
-	return 0;
+	ast_channel_unlock(chan);
+	return ret ? 0 : -1;
 }
 
 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
 		     const char *value)
 {
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, router,
-		     ast_cdr_message_router(), ao2_cleanup);
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	if (!router) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-
-	if (!cdr_write_message_type()) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-
-	payload = ao2_alloc(sizeof(*payload), NULL);
-	if (!payload) {
-		return -1;
-	}
-	payload->chan = chan;
-	payload->cmd = cmd;
-	payload->arguments = parse;
-	payload->value = value;
-
-	message = stasis_message_create(cdr_write_message_type(), payload);
-	if (!message) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-	stasis_message_router_publish_sync(router, message);
-
-	return 0;
-}
-
-static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
-		     const char *value)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
+	struct ast_cdr *cdr;
+	struct ast_flags flags = { 0 };
+	AST_DECLARE_APP_ARGS(args,
+			     AST_APP_ARG(variable);
+			     AST_APP_ARG(options);
+	);
 
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+	if (ast_strlen_zero(parse) || !value || !chan)
 		return -1;
-	}
 
-	if (!router) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
-			ast_channel_name(chan));
+	ast_channel_lock(chan);
+	cdr = ast_channel_cdr(chan);
+	if (!cdr) {
+		ast_channel_unlock(chan);
 		return -1;
 	}
 
-	if (!cdr_write_message_type()) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
-			ast_channel_name(chan));
-		return -1;
-	}
+	AST_STANDARD_APP_ARGS(args, parse);
 
-	payload = ao2_alloc(sizeof(*payload), NULL);
-	if (!payload) {
-		return -1;
-	}
-	payload->chan = chan;
-	payload->cmd = cmd;
-	payload->arguments = parse;
-	payload->value = value;
-
-	message = stasis_message_create(cdr_prop_write_message_type(), payload);
-	if (!message) {
-		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
-			ast_channel_name(chan));
-		return -1;
-	}
-	stasis_message_router_publish_sync(router, message);
+	if (!ast_strlen_zero(args.options))
+		ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
 
+	if (ast_test_flag(&flags, OPT_LAST))
+		while (cdr->next)
+			cdr = cdr->next;
+
+	if (!strcasecmp(args.variable, "accountcode"))  /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */
+		ast_cdr_setaccount(chan, value);
+	else if (!strcasecmp(args.variable, "peeraccount"))
+		ast_cdr_setpeeraccount(chan, value);
+	else if (!strcasecmp(args.variable, "userfield"))
+		ast_cdr_setuserfield(chan, value);
+	else if (!strcasecmp(args.variable, "amaflags"))
+		ast_cdr_setamaflags(chan, value);
+	else
+		ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
+		/* No need to worry about the u flag, as all fields for which setting
+		 * 'u' would do anything are marked as readonly. */
+
+	ast_channel_unlock(chan);
 	return 0;
 }
 
@@ -586,56 +317,14 @@ static struct ast_custom_function cdr_function = {
 	.write = cdr_write,
 };
 
-static struct ast_custom_function cdr_prop_function = {
-	.name = "CDR_PROP",
-	.read = NULL,
-	.write = cdr_prop_write,
-};
-
 static int unload_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-	int res = 0;
-
-	if (router) {
-		stasis_message_router_remove(router, cdr_prop_write_message_type());
-		stasis_message_router_remove(router, cdr_write_message_type());
-		stasis_message_router_remove(router, cdr_read_message_type());
-	}
-	STASIS_MESSAGE_TYPE_CLEANUP(cdr_read_message_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(cdr_write_message_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(cdr_prop_write_message_type);
-	res |= ast_custom_function_unregister(&cdr_function);
-	res |= ast_custom_function_unregister(&cdr_prop_function);
-
-	return res;
+	return ast_custom_function_unregister(&cdr_function);
 }
 
 static int load_module(void)
 {
-	RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
-	int res = 0;
-
-	if (!router) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(cdr_read_message_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(cdr_write_message_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(cdr_prop_write_message_type);
-	res |= ast_custom_function_register(&cdr_function);
-	res |= ast_custom_function_register(&cdr_prop_function);
-	res |= stasis_message_router_add(router, cdr_prop_write_message_type(),
-	                                 cdr_prop_write_callback, NULL);
-	res |= stasis_message_router_add(router, cdr_write_message_type(),
-	                                 cdr_write_callback, NULL);
-	res |= stasis_message_router_add(router, cdr_read_message_type(),
-	                                 cdr_read_callback, NULL);
-
-	if (res) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
+	return ast_custom_function_register(&cdr_function);
 }
 
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan functions");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan function");
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index ca45344..00dfba9 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -30,22 +30,19 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <regex.h>
 #include <ctype.h>
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
-#include "asterisk/bridge.h"
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
 #include "asterisk/indications.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/global_datastores.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/bridge_after.h"
 
 /*** DOCUMENTATION
 	<function name="CHANNELS" language="en_US">
@@ -103,12 +100,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
 					<enum name="audiowriteformat">
 						<para>R/O format currently being written.</para>
 					</enum>
-					<enum name="dtmf_features">
-						<para>R/W The channel's DTMF bridge features.
-						May include one or more of 'T' 'K' 'H' 'W' and 'X' in a similar manner to options
-						in the <literal>Dial</literal> application. When setting it, the features string
-						must be all upper case.</para>
-					</enum>
 					<enum name="callgroup">
 						<para>R/W numeric call pickup groups that this channel is a member.</para>
 					</enum>
@@ -127,12 +118,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
 					<enum name="checkhangup">
 						<para>R/O Whether the channel is hanging up (1/0)</para>
 					</enum>
-					<enum name="after_bridge_goto">
-						<para>R/W the parseable goto string indicating where the channel is
-						expected to return to in the PBX after exiting the next bridge it joins
-						on the condition that it doesn't hang up. The parseable goto string uses
-						the same syntax as the <literal>Goto</literal> application.</para>
-					</enum>
 					<enum name="hangup_handler_pop">
 						<para>W/O Replace the most recently added hangup handler
 						with a new hangup handler on the channel if supplied.  The
@@ -172,13 +157,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
 						<para>R/W set rxgain level on channel drivers that support it.</para>
 					</enum>
 					<enum name="secure_bridge_signaling">
-						<para>Whether or not channels bridged to this channel require secure signaling (1/0)</para>
+						<para>Whether or not channels bridged to this channel require secure signaling</para>
 					</enum>
 					<enum name="secure_bridge_media">
-						<para>Whether or not channels bridged to this channel require secure media (1/0)</para>
+						<para>Whether or not channels bridged to this channel require secure media</para>
 					</enum>
 					<enum name="state">
-						<para>R/O state of the channel</para>
+						<para>R/O state for channel</para>
 					</enum>
 					<enum name="tonezone">
 						<para>R/W zone for indications played</para>
@@ -213,9 +198,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
 					<enum name="recvip">
 						<para>R/O Get the source IP address of the peer.</para>
 					</enum>
-					<enum name="recvport">
-						<para>R/O Get the source port of the peer.</para>
-					</enum>
 					<enum name="from">
 						<para>R/O Get the URI from the From: header.</para>
 					</enum>
@@ -283,7 +265,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422700 $")
 						<para>   Defaults to <literal>audio</literal> if unspecified.</para>
 					</enum>
 				</enumlist>
-				<xi:include xpointer="xpointer(/docs/info[@name='PJSIPCHANNEL'])" />
 				<para><emphasis>chan_iax2</emphasis> provides the following additional options:</para>
 				<enumlist>
 					<enum name="osptoken">
@@ -430,42 +411,32 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 	}
 
 	if (!strcasecmp(data, "audionativeformat")) {
-		tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (tmpcap) {
-			struct ast_str *codec_buf = ast_str_alloca(128);
+		char tmp[512];
 
-			ast_channel_lock(chan);
-			ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO);
-			ast_channel_unlock(chan);
-			ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
-			ao2_ref(tmpcap, -1);
+		if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_AUDIO))) {
+			ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
+			tmpcap = ast_format_cap_destroy(tmpcap);
 		}
 	} else if (!strcasecmp(data, "videonativeformat")) {
-		tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (tmpcap) {
-			struct ast_str *codec_buf = ast_str_alloca(128);
+		char tmp[512];
 
-			ast_channel_lock(chan);
-			ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO);
-			ast_channel_unlock(chan);
-			ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
-			ao2_ref(tmpcap, -1);
+		if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO))) {
+			ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
+			tmpcap = ast_format_cap_destroy(tmpcap);
 		}
 	} else if (!strcasecmp(data, "audioreadformat")) {
-		locked_copy_string(chan, buf, ast_format_get_name(ast_channel_readformat(chan)), len);
+		ast_copy_string(buf, ast_getformatname(ast_channel_readformat(chan)), len);
 	} else if (!strcasecmp(data, "audiowriteformat")) {
-		locked_copy_string(chan, buf, ast_format_get_name(ast_channel_writeformat(chan)), len);
+		ast_copy_string(buf, ast_getformatname(ast_channel_writeformat(chan)), len);
 #ifdef CHANNEL_TRACE
 	} else if (!strcasecmp(data, "trace")) {
-		locked_copy_string(chan, buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
+		ast_channel_lock(chan);
+		ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
+		ast_channel_unlock(chan);
 #endif
-	} else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) {
+	} else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan))
 		locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len);
-	} else if (!strcasecmp(data, "dtmf_features")) {
-		if (ast_bridge_features_ds_get_string(chan, buf, len)) {
-			buf[0] = '\0';
-		}
-	} else if (!strcasecmp(data, "language"))
+	else if (!strcasecmp(data, "language"))
 		locked_copy_string(chan, buf, ast_channel_language(chan), len);
 	else if (!strcasecmp(data, "musicclass"))
 		locked_copy_string(chan, buf, ast_channel_musicclass(chan), len);
@@ -480,7 +451,9 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 	else if (!strcasecmp(data, "accountcode"))
 		locked_copy_string(chan, buf, ast_channel_accountcode(chan), len);
 	else if (!strcasecmp(data, "checkhangup")) {
-		locked_copy_string(chan, buf, ast_check_hangup(chan) ? "1" : "0", len);
+		ast_channel_lock(chan);
+		ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
+		ast_channel_unlock(chan);
 	} else if (!strcasecmp(data, "peeraccount"))
 		locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len);
 	else if (!strcasecmp(data, "hangupsource"))
@@ -508,11 +481,11 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 		}
 		ast_channel_unlock(chan);
 	} else if (!strcasecmp(data, "peer")) {
-		RAII_VAR(struct ast_channel *, p, NULL, ast_channel_cleanup);
+		struct ast_channel *p;
 
 		ast_channel_lock(chan);
-		p = ast_channel_bridge_peer(chan);
-		if (p || ast_channel_tech(chan)) /* dummy channel? if so, we hid the peer name in the language */
+		p = ast_bridged_channel(chan);
+		if (p || ast_channel_tech(chan) || ast_channel_cdr(chan)) /* dummy channel? if so, we hid the peer name in the language */
 			ast_copy_string(buf, (p ? ast_channel_name(p) : ""), len);
 		else {
 			/* a dummy channel can still pass along bridged peer info via
@@ -544,20 +517,16 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 		struct ast_str *tmp_str = ast_str_alloca(1024);
 
 		locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
-	} else if (!strcasecmp(data, "after_bridge_goto")) {
-		ast_bridge_read_after_goto(chan, buf, len);
 	} else if (!strcasecmp(data, "amaflags")) {
 		ast_channel_lock(chan);
-		snprintf(buf, len, "%u", ast_channel_amaflags(chan));
+		snprintf(buf, len, "%d", ast_channel_amaflags(chan));
 		ast_channel_unlock(chan);
 	} else if (!strncasecmp(data, "secure_bridge_", 14)) {
 		struct ast_datastore *ds;
 
-		buf[0] = '\0';
 		ast_channel_lock(chan);
 		if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
 			struct ast_secure_call_store *encrypt = ds->data;
-
 			if (!strcasecmp(data, "secure_bridge_signaling")) {
 				snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
 			} else if (!strcasecmp(data, "secure_bridge_media")) {
@@ -589,15 +558,9 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
 		locked_string_field_set(chan, accountcode, value);
 	else if (!strcasecmp(data, "userfield"))
 		locked_string_field_set(chan, userfield, value);
-	else if (!strcasecmp(data, "after_bridge_goto")) {
-		if (ast_strlen_zero(value)) {
-			ast_bridge_discard_after_goto(chan);
-		} else {
-			ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
-		}
-	} else if (!strcasecmp(data, "amaflags")) {
+	else if (!strcasecmp(data, "amaflags")) {
 		ast_channel_lock(chan);
-		if (isdigit(*value)) {
+		if(isdigit(*value)) {
 			int amaflags;
 			sscanf(value, "%30d", &amaflags);
 			ast_channel_amaflags_set(chan, amaflags);
@@ -642,8 +605,6 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
 			ast_channel_unlock(chan);
 			new_zone = ast_tone_zone_unref(new_zone);
 		}
-	} else if (!strcasecmp(data, "dtmf_features")) {
-		ret = ast_bridge_features_ds_set_string(chan, value);
 	} else if (!strcasecmp(data, "callgroup")) {
 		ast_channel_lock(chan);
 		ast_channel_callgroup_set(chan, ast_get_group(value));
diff --git a/funcs/func_config.c b/funcs/func_config.c
index 9f935b7..1123b0b 100644
--- a/funcs/func_config.c
+++ b/funcs/func_config.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421337 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_curl.c b/funcs/func_curl.c
index daf876e..1795a81 100644
--- a/funcs/func_curl.c
+++ b/funcs/func_curl.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431327 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <curl/curl.h>
 
@@ -171,7 +171,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431327 $")
 #define CURLVERSION_ATLEAST(a,b,c) \
 	((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))
 
-#define CURLOPT_SPECIAL_HASHCOMPAT -500
+#define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500)
 
 static void curlds_free(void *data);
 
@@ -199,6 +199,7 @@ static void curlds_free(void *data)
 		free(setting);
 	}
 	AST_LIST_HEAD_DESTROY(list);
+	ast_free(list);
 }
 
 enum optiontype {
@@ -653,6 +654,7 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info
 			curl_easy_setopt(*curl, cur->key, cur->value);
 		}
 	}
+	AST_LIST_UNLOCK(&global_curl_info);
 
 	if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
 		list = store->data;
@@ -691,7 +693,6 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info
 	if (store) {
 		AST_LIST_UNLOCK(list);
 	}
-	AST_LIST_UNLOCK(&global_curl_info);
 
 	if (args.postdata) {
 		curl_easy_setopt(*curl, CURLOPT_POST, 0);
@@ -873,7 +874,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Load external URL",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_REALTIME_DEPEND2,
diff --git a/funcs/func_cut.c b/funcs/func_cut.c
index 0a4fe20..4b6dc9d 100644
--- a/funcs/func_cut.c
+++ b/funcs/func_cut.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370655 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_db.c b/funcs/func_db.c
index 315eaa7..b56fef9 100644
--- a/funcs/func_db.c
+++ b/funcs/func_db.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428413 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <regex.h>
 
diff --git a/funcs/func_devstate.c b/funcs/func_devstate.c
index 7a66988..6472610 100644
--- a/funcs/func_devstate.c
+++ b/funcs/func_devstate.c
@@ -36,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -355,7 +355,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gets or sets a device state in the dialplan",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
diff --git a/funcs/func_dialgroup.c b/funcs/func_dialgroup.c
index 7fcaf89..37aba6a 100644
--- a/funcs/func_dialgroup.c
+++ b/funcs/func_dialgroup.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398760 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
diff --git a/funcs/func_dialplan.c b/funcs/func_dialplan.c
index cd60c91..02b4c7a 100644
--- a/funcs/func_dialplan.c
+++ b/funcs/func_dialplan.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -194,7 +194,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Dialplan Context/Extension/Priority Checking Functions",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_APP_DEPEND,
diff --git a/funcs/func_enum.c b/funcs/func_enum.c
index 108578f..4b5fb9f 100644
--- a/funcs/func_enum.c
+++ b/funcs/func_enum.c
@@ -39,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 331201 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_env.c b/funcs/func_env.c
index 33eff70..3c260a2 100644
--- a/funcs/func_env.c
+++ b/funcs/func_env.c
@@ -27,7 +27,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413599 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>   /* stat(2) */
 
@@ -561,7 +561,7 @@ static int file_read(struct ast_channel *chan, const char *cmd, char *data, stru
 
 			/* Don't go past the length requested */
 			if (off_i + toappend > offset + length) {
-				toappend = length - off_i;
+				toappend = MIN(offset + length - off_i, flength - off_i);
 			}
 
 			ast_str_append_substr(buf, len, fbuf, toappend);
@@ -725,7 +725,7 @@ static int file_read(struct ast_channel *chan, const char *cmd, char *data, stru
 				}
 			}
 			ast_debug(3, "length_offset=%" PRId64 ", length_offset - i=%" PRId64 "\n", length_offset, length_offset - i);
-			ast_str_append_substr(buf, len, fbuf, length_offset >= 0 ? length_offset - i : flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i;
+			ast_str_append_substr(buf, len, fbuf, (length_offset >= 0) ? length_offset - i : (flength > i + sizeof(fbuf)) ? sizeof(fbuf) : flength - i);
 
 			if (length_offset >= 0) {
 				break;
diff --git a/funcs/func_extstate.c b/funcs/func_extstate.c
index 53b0a56..940c455 100644
--- a/funcs/func_extstate.c
+++ b/funcs/func_extstate.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c
index bcf60bf..54156f2 100644
--- a/funcs/func_frame_trace.c
+++ b/funcs/func_frame_trace.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -215,19 +215,18 @@ static void print_frame(struct ast_frame *frame)
 	switch (frame->frametype) {
 	case AST_FRAME_DTMF_END:
 		ast_verbose("FrameType: DTMF END\n");
-		ast_verbose("Digit: 0x%02X '%c'\n", (unsigned)frame->subclass.integer,
-			frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
+		ast_verbose("Digit: %d\n", frame->subclass.integer);
 		break;
 	case AST_FRAME_VOICE:
 		ast_verbose("FrameType: VOICE\n");
-		ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format));
+		ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format));
 		ast_verbose("MS: %ld\n", frame->len);
 		ast_verbose("Samples: %d\n", frame->samples);
 		ast_verbose("Bytes: %d\n", frame->datalen);
 		break;
 	case AST_FRAME_VIDEO:
 		ast_verbose("FrameType: VIDEO\n");
-		ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format));
+		ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format));
 		ast_verbose("MS: %ld\n", frame->len);
 		ast_verbose("Samples: %d\n", frame->samples);
 		ast_verbose("Bytes: %d\n", frame->datalen);
@@ -334,39 +333,8 @@ static void print_frame(struct ast_frame *frame)
 		case AST_CONTROL_PVT_CAUSE_CODE:
 			ast_verbose("SubClass: PVT_CAUSE_CODE\n");
 			break;
-		case AST_CONTROL_MASQUERADE_NOTIFY:
-			/* Should never happen. */
-			ast_assert(0);
-			break;
-		case AST_CONTROL_STREAM_STOP:
-			ast_verbose("SubClass: STREAM_STOP\n");
-			break;
-		case AST_CONTROL_STREAM_SUSPEND:
-			ast_verbose("SubClass: STREAM_SUSPEND\n");
-			break;
-		case AST_CONTROL_STREAM_RESTART:
-			ast_verbose("SubClass: STREAM_RESTART\n");
-			break;
-		case AST_CONTROL_STREAM_REVERSE:
-			ast_verbose("SubClass: STREAM_REVERSE\n");
-			break;
-		case AST_CONTROL_STREAM_FORWARD:
-			ast_verbose("SubClass: STREAM_FORWARD\n");
-			break;
-		case AST_CONTROL_RECORD_CANCEL:
-			ast_verbose("SubClass: RECORD_CANCEL\n");
-			break;
-		case AST_CONTROL_RECORD_STOP:
-			ast_verbose("SubClass: RECORD_STOP\n");
-			break;
-		case AST_CONTROL_RECORD_SUSPEND:
-			ast_verbose("SubClass: RECORD_SUSPEND\n");
-			break;
-		case AST_CONTROL_RECORD_MUTE:
-			ast_verbose("SubClass: RECORD_MUTE\n");
-			break;
 		}
-
+		
 		if (frame->subclass.integer == -1) {
 			ast_verbose("SubClass: %d\n", frame->subclass.integer);
 		}
@@ -395,16 +363,7 @@ static void print_frame(struct ast_frame *frame)
 		break;
 	case AST_FRAME_DTMF_BEGIN:
 		ast_verbose("FrameType: DTMF BEGIN\n");
-		ast_verbose("Digit: 0x%02X '%c'\n", (unsigned)frame->subclass.integer,
-			frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
-		break;
-	case AST_FRAME_BRIDGE_ACTION:
-		ast_verbose("FrameType: Bridge\n");
-		ast_verbose("SubClass: %d\n", frame->subclass.integer);
-		break;
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
-		ast_verbose("Frametype: Synchronous Bridge\n");
-		ast_verbose("Subclass: %d\n", frame->subclass.integer);
+		ast_verbose("Digit: %d\n", frame->subclass.integer);
 		break;
 	}
 
@@ -428,6 +387,5 @@ static int load_module(void)
 	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Frame Trace for internal ast_frame debugging.");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frame Trace for internal ast_frame debugging.");
 
diff --git a/funcs/func_global.c b/funcs/func_global.c
index af238e9..dcf0393 100644
--- a/funcs/func_global.c
+++ b/funcs/func_global.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
@@ -39,7 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
 #include "asterisk/pbx.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
-#include "asterisk/stasis_channels.h"
+#include "asterisk/manager.h"
 
 /*** DOCUMENTATION
 	<function name="GLOBAL" language="en_US">
@@ -83,25 +83,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
 			using it in a set of calculations (or you might be surprised by the result).</para>
 		</description>
 	</function>
-	<managerEvent language="en_US" name="VarSet">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>Raised when a variable is shared between channels.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Variable">
-					<para>The SHARED variable being set.</para>
-					<note><para>The variable name will always be enclosed with
-					<literal>SHARED()</literal></para></note>
-				</parameter>
-				<parameter name="Value">
-					<para>The new value of the variable.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="function">SHARED</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
+
  ***/
 
 static void shared_variable_free(void *data);
@@ -218,8 +200,6 @@ static int shared_write(struct ast_channel *chan, const char *cmd, char *data, c
 		AST_APP_ARG(chan);
 	);
 	struct ast_channel *c_ref = NULL;
-	int len;
-	RAII_VAR(char *, shared_buffer, NULL, ast_free);
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
@@ -241,15 +221,6 @@ static int shared_write(struct ast_channel *chan, const char *cmd, char *data, c
 		return -1;
 	}
 
-	len = 9 + strlen(args.var); /* SHARED() + var */
-	shared_buffer = ast_malloc(len);
-	if (!shared_buffer) {
-		if (c_ref) {
-			ast_channel_unref(c_ref);
-		}
-		return -1;
-	}
-
 	ast_channel_lock(chan);
 
 	if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
@@ -290,9 +261,13 @@ static int shared_write(struct ast_channel *chan, const char *cmd, char *data, c
 
 	if ((var = ast_var_assign(args.var, S_OR(value, "")))) {
 		AST_LIST_INSERT_HEAD(varshead, var, entries);
-
-		sprintf(shared_buffer, "SHARED(%s)", args.var);
-		ast_channel_publish_varset(chan, shared_buffer, value);
+		manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
+			"Channel: %s\r\n"
+			"Variable: SHARED(%s)\r\n"
+			"Value: %s\r\n"
+			"Uniqueid: %s\r\n", 
+			chan ? ast_channel_name(chan) : "none", args.var, value, 
+			chan ? ast_channel_uniqueid(chan) : "none");
 	}
 
 	ast_channel_unlock(chan);
diff --git a/funcs/func_groupcount.c b/funcs/func_groupcount.c
index 610a6a7..fd775d9 100644
--- a/funcs/func_groupcount.c
+++ b/funcs/func_groupcount.c
@@ -27,7 +27,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -50,7 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
 		</syntax>
 		<description>
 			<para>Calculates the group count for the specified group, or uses the
-			channel's current group if not specifed (and non-empty).</para>
+			channel's current group if not specified (and non-empty).</para>
 		</description>
 	</function>
 	<function name="GROUP_MATCH_COUNT" language="en_US">
diff --git a/funcs/func_hangupcause.c b/funcs/func_hangupcause.c
index db77438..983a0e1 100644
--- a/funcs/func_hangupcause.c
+++ b/funcs/func_hangupcause.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -48,7 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
 		</synopsis>
 		<syntax>
 			<parameter name="channel" required="true">
-				<para>The name of the channel for which to retreive cause information.</para>
+				<para>The name of the channel for which to retrieve cause information.</para>
 			</parameter>
 			<parameter name="type" required="true">
 				<para>Parameter describing which type of information is requested. Types are:</para>
diff --git a/funcs/func_iconv.c b/funcs/func_iconv.c
index d90fe0f..c3d0286 100644
--- a/funcs/func_iconv.c
+++ b/funcs/func_iconv.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <iconv.h>
diff --git a/funcs/func_jitterbuffer.c b/funcs/func_jitterbuffer.c
index add25b7..21070e0 100644
--- a/funcs/func_jitterbuffer.c
+++ b/funcs/func_jitterbuffer.c
@@ -31,12 +31,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420639 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
 #include "asterisk/framehook.h"
-#include "asterisk/frame.h"
 #include "asterisk/pbx.h"
 #include "asterisk/abstract_jb.h"
 #include "asterisk/timing.h"
@@ -45,87 +44,111 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420639 $")
 /*** DOCUMENTATION
 	<function name="JITTERBUFFER" language="en_US">
 		<synopsis>
-			Add a Jitterbuffer to the Read side of the channel. This dejitters the audio stream before it reaches the Asterisk core. This is a write only function.
+			Add a Jitterbuffer to the Read side of the channel.  This dejitters the audio stream before it reaches the Asterisk core. This is a write only function.
 		</synopsis>
 		<syntax>
 			<parameter name="jitterbuffer type" required="true">
-				<optionlist>
-					<option name="fixed">
-						<para>Set a fixed jitterbuffer on the channel.</para>
-					</option>
-					<option name="adaptive">
-						<para>Set an adaptive jitterbuffer on the channel.</para>
-					</option>
-					<option name="disabled">
-						<para>Remove a previously set jitterbuffer from the channel.</para>
-					</option>
-				</optionlist>
+				<para>Jitterbuffer type can be either <literal>fixed</literal> or <literal>adaptive</literal>.</para>
+				<para>Used as follows. </para>
+				<para>Set(JITTERBUFFER(type)=max_size[,resync_threshold[,target_extra]])</para>
+				<para>Set(JITTERBUFFER(type)=default) </para>
 			</parameter>
 		</syntax>
 		<description>
-			<para>Jitterbuffers are constructed in two different ways.
-			The first always take three arguments: <replaceable>max_size</replaceable>,
-			<replaceable>resync_threshold</replaceable>, and <replaceable>target_extra</replaceable>.
-			Alternatively, a single argument of <literal>default</literal> can be provided,
-			which will construct the default jitterbuffer for the given
-			<replaceable>jitterbuffer type</replaceable>.</para>
-			<para>The arguments are:</para>
-			<para><replaceable>max_size</replaceable>: Length in milliseconds of the buffer.
-			Defaults to 200 ms.</para>
-			<para><replaceable>resync_threshold</replaceable>: The length in milliseconds over
-			which a timestamp difference will result in resyncing the jitterbuffer.
-			Defaults to 1000ms.</para>
-			<para>target_extra: This option only affects the adaptive jitterbuffer. It represents
-			the amount time in milliseconds by which the new jitter buffer will pad its size.
-			Defaults to 40ms.</para>
-			<example title="Fixed with defaults" language="text">
-			exten => 1,1,Set(JITTERBUFFER(fixed)=default)
-			</example>
-			<example title="Fixed with 200ms max size" language="text">
-			exten => 1,1,Set(JITTERBUFFER(fixed)=200)
-			</example>
-			<example title="Fixed with 200ms max size, resync threshold 1500" language="text">
-			exten => 1,1,Set(JITTERBUFFER(fixed)=200,1500)
-			</example>
-			<example title="Adaptive with defaults" language="text">
-			exten => 1,1,Set(JITTERBUFFER(adaptive)=default)
-			</example>
-			<example title="Adaptive with 200ms max size, 60ms target extra" language="text">
-			exten => 1,1,Set(JITTERBUFFER(adaptive)=200,,60)
-			</example>
-			<example title="Set a fixed jitterbuffer with defaults; then remove it" language="text">
-			exten => 1,1,Set(JITTERBUFFER(fixed)=default)
-			exten => 1,n,Set(JITTERBUFFER(disabled)=)
-			</example>
-			<note><para>If a channel specifies a jitterbuffer due to channel driver configuration and
-			the JITTERBUFFER function has set a jitterbuffer for that channel, the jitterbuffer set by
-			the JITTERBUFFER function will take priority and the jitterbuffer set by the channel
-			configuration will not be applied.</para></note>
+			<para>max_size: Defaults to 200 ms</para>
+			<para>Length in milliseconds of buffer.</para>
+			<para> </para>
+			<para>resync_threshold: Defaults to 1000ms </para>
+			<para>The length in milliseconds over which a timestamp difference will result in resyncing the jitterbuffer. </para>
+			<para> </para>
+			<para>target_extra: Defaults to 40ms</para>
+			<para>This option only affects the adaptive jitterbuffer. It represents the amount time in milliseconds by which the new jitter buffer will pad its size.</para>
+			<para> </para>
+			<para>Examples:</para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=default);Fixed with defaults. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=200);Fixed with max size 200ms, default resync threshold and target extra. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(fixed)=200,1500);Fixed with max size 200ms resync threshold 1500. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=default);Adaptive with defaults. </para>
+			<para>exten => 1,1,Set(JITTERBUFFER(adaptive)=200,,60);Adaptive with max size 200ms, default resync threshold and 40ms target extra. </para>
 		</description>
 	</function>
  ***/
 
-static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
-{
+#define DEFAULT_TIMER_INTERVAL 20
+#define DEFAULT_SIZE  200
+#define DEFAULT_TARGET_EXTRA  40
+#define DEFAULT_RESYNC  1000
+#define DEFAULT_TYPE AST_JB_FIXED
+
+struct jb_framedata {
+	const struct ast_jb_impl *jb_impl;
 	struct ast_jb_conf jb_conf;
+	struct timeval start_tv;
+	struct ast_format last_format;
+	struct ast_timer *timer;
+	int timer_interval; /* ms between deliveries */
+	int timer_fd;
+	int first;
+	void *jb_obj;
+};
 
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+static void jb_framedata_destroy(struct jb_framedata *framedata)
+{
+	if (framedata->timer) {
+		ast_timer_close(framedata->timer);
+		framedata->timer = NULL;
+	}
+	if (framedata->jb_impl && framedata->jb_obj) {
+		struct ast_frame *f;
+		while (framedata->jb_impl->remove(framedata->jb_obj, &f) == AST_JB_IMPL_OK) {
+			ast_frfree(f);
+		}
+		framedata->jb_impl->destroy(framedata->jb_obj);
+		framedata->jb_obj = NULL;
+	}
+	ast_free(framedata);
+}
+
+static void jb_conf_default(struct ast_jb_conf *conf)
+{
+	conf->max_size = DEFAULT_SIZE;
+	conf->resync_threshold = DEFAULT_RESYNC;
+	ast_copy_string(conf->impl, "fixed", sizeof(conf->impl));
+	conf->target_extra = DEFAULT_TARGET_EXTRA;
+}
+
+/* set defaults */
+static int jb_framedata_init(struct jb_framedata *framedata, const char *data, const char *value)
+{
+	int jb_impl_type = DEFAULT_TYPE;
+
+	/* Initialize defaults */
+	framedata->timer_fd = -1;
+	jb_conf_default(&framedata->jb_conf);
+	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
+		return -1;
+	}
+	if (!(framedata->timer = ast_timer_open())) {
 		return -1;
 	}
+	framedata->timer_fd = ast_timer_fd(framedata->timer);
+	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
+	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+	framedata->start_tv = ast_tvnow();
+
 
-	/* Initialize and set jb_conf */
-	ast_jb_conf_default(&jb_conf);
 
 	/* Now check user options to see if any of the defaults need to change. */
 	if (!ast_strlen_zero(data)) {
-		if (strcasecmp(data, "fixed") &&
-				strcasecmp(data, "adaptive") &&
-				strcasecmp(data, "disabled")) {
+		if (!strcasecmp(data, "fixed")) {
+			jb_impl_type = AST_JB_FIXED;
+		} else if (!strcasecmp(data, "adaptive")) {
+			jb_impl_type = AST_JB_ADAPTIVE;
+		} else {
 			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", data);
 			return -1;
 		}
-		ast_copy_string(jb_conf.impl, data, sizeof(jb_conf.impl));
+		ast_copy_string(framedata->jb_conf.impl, data, sizeof(framedata->jb_conf.impl));
 	}
 
 	if (!ast_strlen_zero(value) && strcasecmp(value, "default")) {
@@ -139,17 +162,17 @@ static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, cons
 
 		AST_STANDARD_APP_ARGS(args, parse);
 		if (!ast_strlen_zero(args.max_size)) {
-			res |= ast_jb_read_conf(&jb_conf,
+			res |= ast_jb_read_conf(&framedata->jb_conf,
 				"jbmaxsize",
 				args.max_size);
 		}
 		if (!ast_strlen_zero(args.resync_threshold)) {
-			res |= ast_jb_read_conf(&jb_conf,
+			res |= ast_jb_read_conf(&framedata->jb_conf,
 				"jbresyncthreshold",
 				args.resync_threshold);
 		}
 		if (!ast_strlen_zero(args.target_extra)) {
-			res |= ast_jb_read_conf(&jb_conf,
+			res |= ast_jb_read_conf(&framedata->jb_conf,
 				"jbtargetextra",
 				args.target_extra);
 		}
@@ -158,11 +181,214 @@ static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, cons
 		}
 	}
 
-	ast_jb_create_framehook(chan, &jb_conf, 0);
-
+	/* now that all the user parsing is done and nothing will change, create the jb obj */
+	framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
 	return 0;
 }
 
+static void datastore_destroy_cb(void *data) {
+	ast_free(data);
+	ast_debug(1, "JITTERBUFFER datastore destroyed\n");
+}
+
+static const struct ast_datastore_info jb_datastore = {
+	.type = "jitterbuffer",
+	.destroy = datastore_destroy_cb
+};
+
+static void hook_destroy_cb(void *framedata)
+{
+	ast_debug(1, "JITTERBUFFER hook destroyed\n");
+	jb_framedata_destroy((struct jb_framedata *) framedata);
+}
+
+static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
+{
+	struct jb_framedata *framedata = data;
+	struct timeval now_tv;
+	unsigned long now;
+	int putframe = 0; /* signifies if audio frame was placed into the buffer or not */
+
+	switch (event) {
+	case AST_FRAMEHOOK_EVENT_READ:
+		break;
+	case AST_FRAMEHOOK_EVENT_ATTACHED:
+	case AST_FRAMEHOOK_EVENT_DETACHED:
+	case AST_FRAMEHOOK_EVENT_WRITE:
+		return frame;
+	}
+
+	if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) {
+		if (ast_timer_ack(framedata->timer, 1) < 0) {
+			ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n");
+			return frame;
+		}
+	}
+
+	if (!frame) {
+		return frame;
+	}
+
+	now_tv = ast_tvnow();
+	now = ast_tvdiff_ms(now_tv, framedata->start_tv);
+
+	if (frame->frametype == AST_FRAME_VOICE) {
+		int res;
+		struct ast_frame *jbframe;
+
+		if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) {
+			/* only frames with timing info can enter the jitterbuffer */
+			return frame;
+		}
+
+		jbframe = ast_frisolate(frame);
+		ast_format_copy(&framedata->last_format, &frame->subclass.format);
+
+		if (frame->len && (frame->len != framedata->timer_interval)) {
+			framedata->timer_interval = frame->len;
+			ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
+		}
+		if (!framedata->first) {
+			framedata->first = 1;
+			res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now);
+		} else {
+			res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
+		}
+
+		if (res == AST_JB_IMPL_OK) {
+			if (jbframe != frame) {
+				ast_frfree(frame);
+			}
+			frame = &ast_null_frame;
+		} else if (jbframe != frame) {
+			ast_frfree(jbframe);
+		}
+		putframe = 1;
+	}
+
+	if (frame->frametype == AST_FRAME_NULL) {
+		int res;
+		long next = framedata->jb_impl->next(framedata->jb_obj);
+
+		/* If now is earlier than the next expected output frame
+		 * from the jitterbuffer we may choose to pass on retrieving
+		 * a frame during this read iteration.  The only exception
+		 * to this rule is when an audio frame is placed into the buffer
+		 * and the time for the next frame to come out of the buffer is
+		 * at least within the timer_interval of the next output frame. By
+		 * doing this we are able to feed off the timing of the input frames
+		 * and only rely on our jitterbuffer timer when frames are dropped.
+		 * During testing, this hybrid form of timing gave more reliable results. */
+		if (now < next) {
+			long int diff = next - now;
+			if (!putframe) {
+				return frame;
+			} else if (diff >= framedata->timer_interval) {
+				return frame;
+			}
+		}
+
+		ast_frfree(frame);
+		frame = &ast_null_frame;
+		res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
+		switch (res) {
+		case AST_JB_IMPL_OK:
+			/* got it, and pass it through */
+			break;
+		case AST_JB_IMPL_DROP:
+			ast_frfree(frame);
+			frame = &ast_null_frame;
+			break;
+		case AST_JB_IMPL_INTERP:
+			if (framedata->last_format.id) {
+				struct ast_frame tmp = { 0, };
+
+				tmp.frametype = AST_FRAME_VOICE;
+				ast_format_copy(&tmp.subclass.format, &framedata->last_format);
+				/* example: 8000hz / (1000 / 20ms) = 160 samples */
+				tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval);
+				tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
+				tmp.offset = AST_FRIENDLY_OFFSET;
+				tmp.src  = "func_jitterbuffer interpolation";
+				ast_frfree(frame);
+				frame = ast_frdup(&tmp);
+				break;
+			}
+			/* else fall through */
+		case AST_JB_IMPL_NOFRAME:
+			ast_frfree(frame);
+			frame = &ast_null_frame;
+			break;
+		}
+	}
+
+	return frame;
+}
+
+static int jb_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+	struct jb_framedata *framedata;
+	struct ast_datastore *datastore = NULL;
+	struct ast_framehook_interface interface = {
+		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
+		.event_cb = hook_event_cb,
+		.destroy_cb = hook_destroy_cb,
+	};
+	int i = 0;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
+		return 0;
+	}
+
+	if (jb_framedata_init(framedata, data, value)) {
+		jb_framedata_destroy(framedata);
+		return 0;
+	}
+
+	interface.data = framedata;
+
+	ast_channel_lock(chan);
+	i = ast_framehook_attach(chan, &interface);
+	if (i >= 0) {
+		int *id;
+		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
+			id = datastore->data;
+			ast_framehook_detach(chan, *id);
+			ast_channel_datastore_remove(chan, datastore);
+			ast_datastore_free(datastore);
+		}
+
+		if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
+			ast_framehook_detach(chan, i);
+			ast_channel_unlock(chan);
+			return 0;
+		}
+
+		if (!(id = ast_calloc(1, sizeof(int)))) {
+			ast_datastore_free(datastore);
+			ast_framehook_detach(chan, i);
+			ast_channel_unlock(chan);
+			return 0;
+		}
+
+		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
+		datastore->data = id;
+		ast_channel_datastore_add(chan, datastore);
+
+		ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
+	} else {
+		jb_framedata_destroy(framedata);
+		framedata = NULL;
+	}
+	ast_channel_unlock(chan);
+
+	return 0;
+}
 
 static struct ast_custom_function jb_function = {
 	.name = "JITTERBUFFER",
diff --git a/funcs/func_lock.c b/funcs/func_lock.c
index 2b11cfa..2102d5c 100644
--- a/funcs/func_lock.c
+++ b/funcs/func_lock.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403960 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 
diff --git a/funcs/func_logic.c b/funcs/func_logic.c
index bb0f074..e371f7e 100644
--- a/funcs/func_logic.c
+++ b/funcs/func_logic.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370655 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_math.c b/funcs/func_math.c
index e70a44a..5c8d3bc 100644
--- a/funcs/func_math.c
+++ b/funcs/func_math.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
@@ -482,13 +482,11 @@ AST_TEST_DEFINE(test_MATH_function)
 
 	ast_test_status_update(test, "Testing MATH() substitution ...\n");
 
-	if (!(expr = ast_str_create(16)) || !(result = ast_str_create(16))) {
-		if (expr) {
-			ast_free(expr);
-		}
-		if (result) {
-			ast_free(result);
-		}
+	if (!(expr = ast_str_create(16))) {
+		return AST_TEST_FAIL;
+	}
+	if (!(result = ast_str_create(16))) {
+		ast_free(expr);
 		return AST_TEST_FAIL;
 	}
 
diff --git a/funcs/func_md5.c b/funcs/func_md5.c
index 5cd10be..2e60185 100644
--- a/funcs/func_md5.c
+++ b/funcs/func_md5.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
diff --git a/funcs/func_module.c b/funcs/func_module.c
index 6053942..b0b3461 100644
--- a/funcs/func_module.c
+++ b/funcs/func_module.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c
index 9976801..779f685 100644
--- a/funcs/func_odbc.c
+++ b/funcs/func_odbc.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/file.h"
@@ -1580,7 +1580,6 @@ reload_out:
 /* XXX need to revise usecount - set if query_lock is set */
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/funcs/func_periodic_hook.c b/funcs/func_periodic_hook.c
deleted file mode 100644
index c171594..0000000
--- a/funcs/func_periodic_hook.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Russell Bryant
- *
- * Russell Bryant <russell at russellbryant.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Periodic dialplan hooks.
- *
- * \author Russell Bryant <russell at russellbryant.net>
- *
- * \ingroup functions
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
-	<depend>app_chanspy</depend>
-	<depend>func_cut</depend>
-	<depend>func_groupcount</depend>
-	<depend>func_uri</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/app.h"
-#include "asterisk/audiohook.h"
-#define AST_API_MODULE
-#include "asterisk/beep.h"
-
-/*** DOCUMENTATION
-	<function name="PERIODIC_HOOK" language="en_US">
-		<synopsis>
-			Execute a periodic dialplan hook into the audio of a call.
-		</synopsis>
-		<syntax>
-			<parameter name="context" required="true">
-				<para>(On Read Only) Context for the hook extension.</para>
-			</parameter>
-			<parameter name="extension" required="true">
-				<para>(On Read Only) The hook extension.</para>
-			</parameter>
-			<parameter name="interval" required="true">
-				<para>(On Read Only) Number of seconds in between hook runs.
-				Whole seconds only.</para>
-			</parameter>
-			<parameter name="hook_id" required="true">
-				<para>(On Write Only) The hook ID.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>For example, you could use this function to enable playing
-			a periodic <literal>beep</literal> sound in a call.</para>
-			<para/>
-			<para>To turn on:</para>
-			<para>  Set(BEEPID=${PERIODIC_HOOK(hooks,beep,180)})</para>
-			<para/>
-			<para>To turn off:</para>
-			<para>  Set(PERIODIC_HOOK(${BEEPID})=off)</para>
-			<para/>
-			<para>To turn back on again later:</para>
-			<para>Set(PERIODIC_HOOK(${BEEPID})=on)</para>
-			<para/>
-			<para>It is important to note that the hook does not actually
-			run on the channel itself.  It runs asynchronously on a new channel.
-			Any audio generated by the hook gets injected into the call for
-			the channel PERIODIC_HOOK() was set on.</para>
-			<para/>
-			<para>The hook dialplan will have two variables available.
-			<variable>HOOK_CHANNEL</variable> is the channel the hook is
-			enabled on.  <variable>HOOK_ID</variable> is the hook ID for
-			enabling or disabling the hook.</para>
-		</description>
-	</function>
- ***/
-
-static const char context_name[] = "__func_periodic_hook_context__";
-static const char exten_name[] = "hook";
-static const char full_exten_name[] = "hook at __func_periodic_hook_context__";
-
-static const char beep_exten[] = "beep";
-
-/*!
- * \brief Last used hook ID
- *
- * This is incremented each time a hook is created to give each hook a unique
- * ID.
- */
-static unsigned int global_hook_id;
-
-/*! State put in a datastore to track the state of the hook */
-struct hook_state {
-	/*!
-	 * \brief audiohook used as a callback into this module
-	 *
-	 * \note The code assumes this is the first element in the struct
-	 */
-	struct ast_audiohook audiohook;
-	/*! Seconds between each hook run */
-	unsigned int interval;
-	/*! The last time the hook ran */
-	struct timeval last_hook;
-	/*! Dialplan context for the hook */
-	char *context;
-	/*! Dialplan extension for the hook */
-	char *exten;
-	/*! Hook ID */
-	unsigned int hook_id;
-	/*! Non-zero if the hook is currently disabled */
-	unsigned char disabled;
-};
-
-static void hook_datastore_destroy_callback(void *data)
-{
-	struct hook_state *state = data;
-
-	ast_audiohook_lock(&state->audiohook);
-	ast_audiohook_detach(&state->audiohook);
-	ast_audiohook_unlock(&state->audiohook);
-	ast_audiohook_destroy(&state->audiohook);
-
-	ast_free(state->context);
-	ast_free(state->exten);
-	ast_free(state);
-
-	ast_module_unref(ast_module_info->self);
-}
-
-static const struct ast_datastore_info hook_datastore = {
-	.type = AST_MODULE,
-	.destroy = hook_datastore_destroy_callback,
-};
-
-/*! Arguments to the thread that launches the hook */
-struct hook_thread_arg {
-	/*! Hook ID */
-	char *hook_id;
-	/*! Name of the channel the hook was set on */
-	char *chan_name;
-	/*! Dialplan context for the hook */
-	char *context;
-	/*! Dialplan extension for the hook */
-	char *exten;
-};
-
-static void hook_thread_arg_destroy(struct hook_thread_arg *arg)
-{
-	ast_free(arg->hook_id);
-	ast_free(arg->chan_name);
-	ast_free(arg->context);
-	ast_free(arg->exten);
-	ast_free(arg);
-}
-
-static void *hook_launch_thread(void *data)
-{
-	struct hook_thread_arg *arg = data;
-	struct ast_variable hook_id = {
-		.name = "HOOK_ID",
-		.value = arg->hook_id,
-	};
-	struct ast_variable chan_name_var = {
-		.name = "HOOK_CHANNEL",
-		.value = arg->chan_name,
-		.next = &hook_id,
-	};
-
-	ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60,
-			arg->context, arg->exten, 1, NULL, 0, NULL, NULL, &chan_name_var,
-			NULL, NULL, 1, NULL);
-
-	hook_thread_arg_destroy(arg);
-
-	return NULL;
-}
-
-static struct hook_thread_arg *hook_thread_arg_alloc(struct ast_channel *chan,
-		struct hook_state *state)
-{
-	struct hook_thread_arg *arg;
-
-	if (!(arg = ast_calloc(1, sizeof(*arg)))) {
-		return NULL;
-	}
-
-	ast_channel_lock(chan);
-	arg->chan_name = ast_strdup(ast_channel_name(chan));
-	ast_channel_unlock(chan);
-	if (!arg->chan_name) {
-		hook_thread_arg_destroy(arg);
-		return NULL;
-	}
-
-	if (ast_asprintf(&arg->hook_id, "%u", state->hook_id) == -1) {
-		hook_thread_arg_destroy(arg);
-		return NULL;
-	}
-
-	if (!(arg->context = ast_strdup(state->context))) {
-		hook_thread_arg_destroy(arg);
-		return NULL;
-	}
-
-	if (!(arg->exten = ast_strdup(state->exten))) {
-		hook_thread_arg_destroy(arg);
-		return NULL;
-	}
-
-	return arg;
-}
-
-static int do_hook(struct ast_channel *chan, struct hook_state *state)
-{
-	pthread_t t;
-	struct hook_thread_arg *arg;
-	int res;
-
-	if (!(arg = hook_thread_arg_alloc(chan, state))) {
-		return -1;
-	}
-
-	/*
-	 * We don't want to block normal frame processing *at all* while we kick
-	 * this off, so do it in a new thread.
-	 */
-	res = ast_pthread_create_detached_background(&t, NULL, hook_launch_thread, arg);
-	if (res != 0) {
-		hook_thread_arg_destroy(arg);
-	}
-
-	return res;
-}
-
-static int hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
-		struct ast_frame *frame, enum ast_audiohook_direction direction)
-{
-	struct hook_state *state = (struct hook_state *) audiohook; /* trust me. */
-	struct timeval now;
-	int res = 0;
-
-	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || state->disabled) {
-		return 0;
-	}
-
-	now = ast_tvnow();
-	if (ast_tvdiff_ms(now, state->last_hook) > state->interval * 1000) {
-		if ((res = do_hook(chan, state))) {
-			const char *name;
-			ast_channel_lock(chan);
-			name = ast_strdupa(ast_channel_name(chan));
-			ast_channel_unlock(chan);
-			ast_log(LOG_WARNING, "Failed to run hook on '%s'\n", name);
-		}
-		state->last_hook = now;
-	}
-
-	return res;
-}
-
-static struct hook_state *hook_state_alloc(const char *context, const char *exten,
-		unsigned int interval, unsigned int hook_id)
-{
-	struct hook_state *state;
-
-	if (!(state = ast_calloc(1, sizeof(*state)))) {
-		return NULL;
-	}
-
-	state->context = ast_strdup(context);
-	state->exten = ast_strdup(exten);
-	state->interval = interval;
-	state->hook_id = hook_id;
-
-	ast_audiohook_init(&state->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE,
-			AST_MODULE, AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
-	state->audiohook.manipulate_callback = hook_callback;
-
-	return state;
-}
-
-static int init_hook(struct ast_channel *chan, const char *context, const char *exten,
-		unsigned int interval, unsigned int hook_id)
-{
-	struct hook_state *state;
-	struct ast_datastore *datastore;
-	char uid[32];
-
-	snprintf(uid, sizeof(uid), "%u", hook_id);
-
-	if (!(datastore = ast_datastore_alloc(&hook_datastore, uid))) {
-		return -1;
-	}
-	ast_module_ref(ast_module_info->self);
-	if (!(state = hook_state_alloc(context, exten, interval, hook_id))) {
-		ast_datastore_free(datastore);
-		return -1;
-	}
-	datastore->data = state;
-
-	ast_channel_lock(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_audiohook_attach(chan, &state->audiohook);
-	ast_channel_unlock(chan);
-
-	return 0;
-}
-
-static int hook_on(struct ast_channel *chan, const char *data, unsigned int hook_id)
-{
-	char *parse = ast_strdupa(S_OR(data, ""));
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(context);
-		AST_APP_ARG(exten);
-		AST_APP_ARG(interval);
-	);
-	unsigned int interval;
-
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.interval) ||
-			sscanf(args.interval, "%30u", &interval) != 1 || interval == 0) {
-		ast_log(LOG_WARNING, "Invalid hook interval: '%s'\n", S_OR(args.interval, ""));
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.context) || ast_strlen_zero(args.exten)) {
-		ast_log(LOG_WARNING, "A context and extension are required for PERIODIC_HOOK().\n");
-		return -1;
-	}
-
-	ast_debug(1, "hook to %s@%s enabled on %s with interval of %u seconds\n",
-			args.exten, args.context, ast_channel_name(chan), interval);
-
-	return init_hook(chan, args.context, args.exten, interval, hook_id);
-}
-
-static int hook_off(struct ast_channel *chan, const char *hook_id)
-{
-	struct ast_datastore *datastore;
-	struct hook_state *state;
-
-	if (ast_strlen_zero(hook_id)) {
-		return -1;
-	}
-
-	ast_channel_lock(chan);
-
-	if (!(datastore = ast_channel_datastore_find(chan, &hook_datastore, hook_id))) {
-		ast_log(LOG_WARNING, "Hook with ID '%s' not found on channel '%s'\n", hook_id,
-				ast_channel_name(chan));
-		ast_channel_unlock(chan);
-		return -1;
-	}
-
-	state = datastore->data;
-	state->disabled = 1;
-
-	ast_channel_unlock(chan);
-
-	return 0;
-}
-
-static int hook_read(struct ast_channel *chan, const char *cmd, char *data,
-	       char *buf, size_t len)
-{
-	unsigned int hook_id;
-
-	if (!chan) {
-		return -1;
-	}
-
-	hook_id = (unsigned int) ast_atomic_fetchadd_int((int *) &global_hook_id, 1);
-
-	snprintf(buf, len, "%u", hook_id);
-
-	return hook_on(chan, data, hook_id);
-}
-
-static int hook_re_enable(struct ast_channel *chan, const char *uid)
-{
-	struct ast_datastore *datastore;
-	struct hook_state *state;
-
-	if (ast_strlen_zero(uid)) {
-		return -1;
-	}
-
-	ast_channel_lock(chan);
-
-	if (!(datastore = ast_channel_datastore_find(chan, &hook_datastore, uid))) {
-		ast_log(LOG_WARNING, "Hook with ID '%s' not found on '%s'\n",
-				uid, ast_channel_name(chan));
-		ast_channel_unlock(chan);
-		return -1;
-	}
-
-	state = datastore->data;
-	state->disabled = 0;
-
-	ast_channel_unlock(chan);
-
-	return 0;
-}
-
-static int hook_write(struct ast_channel *chan, const char *cmd, char *data,
-		const char *value)
-{
-	int res;
-
-	if (!chan) {
-		return -1;
-	}
-
-	if (ast_false(value)) {
-		res = hook_off(chan, data);
-	} else if (ast_true(value)) {
-		res = hook_re_enable(chan, data);
-	} else {
-		ast_log(LOG_WARNING, "Invalid value for PERIODIC_HOOK function: '%s'\n", value);
-		res = -1;
-	}
-
-	return res;
-}
-
-static struct ast_custom_function hook_function = {
-	.name = "PERIODIC_HOOK",
-	.read = hook_read,
-	.write = hook_write,
-};
-
-static struct ast_context *func_periodic_hook_context;
-
-static int unload_module(void)
-{
-	if (func_periodic_hook_context) {
-		ast_context_destroy(func_periodic_hook_context, AST_MODULE);
-	}
-
-	return ast_custom_function_unregister(&hook_function);
-}
-
-static int load_module(void)
-{
-	int res;
-
-	func_periodic_hook_context = ast_context_find_or_create(NULL, NULL,
-			context_name, AST_MODULE);
-	if (!func_periodic_hook_context) {
-		ast_log(LOG_ERROR, "Failed to create %s dialplan context.\n", context_name);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	/*
-	 * Based on a handy recipe from the Asterisk Cookbook.
-	 */
-	ast_add_extension(context_name, 1, exten_name, 1, "", "",
-			"Set", "EncodedChannel=${CUT(HOOK_CHANNEL,-,1-2)}",
-			NULL, AST_MODULE);
-	ast_add_extension(context_name, 1, exten_name, 2, "", "",
-			"Set", "GROUP_NAME=${EncodedChannel}${HOOK_ID}",
-			NULL, AST_MODULE);
-	ast_add_extension(context_name, 1, exten_name, 3, "", "",
-			"Set", "GROUP(periodic-hook)=${GROUP_NAME}",
-			NULL, AST_MODULE);
-	ast_add_extension(context_name, 1, exten_name, 4, "", "", "ExecIf",
-			"$[${GROUP_COUNT(${GROUP_NAME}@periodic-hook)} > 1]?Hangup()",
-			NULL, AST_MODULE);
-	ast_add_extension(context_name, 1, exten_name, 5, "", "",
-			"Set", "ChannelToSpy=${URIDECODE(${EncodedChannel})}",
-			NULL, AST_MODULE);
-	ast_add_extension(context_name, 1, exten_name, 6, "", "",
-			"ChanSpy", "${ChannelToSpy},qEB", NULL, AST_MODULE);
-
-	res = ast_add_extension(context_name, 1, beep_exten, 1, "", "",
-			"Answer", "", NULL, AST_MODULE);
-	res |= ast_add_extension(context_name, 1, beep_exten, 2, "", "",
-			"Playback", "beep", NULL, AST_MODULE);
-
-	res = ast_custom_function_register_escalating(&hook_function, AST_CFE_BOTH);
-
-	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
-}
-
-int AST_OPTIONAL_API_NAME(ast_beep_start)(struct ast_channel *chan,
-		unsigned int interval, char *beep_id, size_t len)
-{
-	char args[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 32];
-
-	snprintf(args, sizeof(args), "%s,%s,%u",
-			context_name, beep_exten, interval);
-
-	if (hook_read(chan, NULL, args, beep_id, len)) {
-		ast_log(LOG_WARNING, "Failed to enable periodic beep.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-int AST_OPTIONAL_API_NAME(ast_beep_stop)(struct ast_channel *chan, const char *beep_id)
-{
-	return hook_write(chan, NULL, (char *) beep_id, "off");
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Periodic dialplan hooks.",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		);
diff --git a/funcs/func_periodic_hook.exports.in b/funcs/func_periodic_hook.exports.in
deleted file mode 100644
index 0ca2f0b..0000000
--- a/funcs/func_periodic_hook.exports.in
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIX*ast_beep_start;
-		LINKER_SYMBOL_PREFIX*ast_beep_stop;
-	local:
-		*;
-};
diff --git a/funcs/func_pitchshift.c b/funcs/func_pitchshift.c
index b7b25e0..e5091d9 100644
--- a/funcs/func_pitchshift.c
+++ b/funcs/func_pitchshift.c
@@ -64,7 +64,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -172,7 +172,9 @@ static int pitchshift_cb(struct ast_audiohook *audiohook, struct ast_channel *ch
 	if (!f) {
 		return 0;
 	}
-	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
+	if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) ||
+		(f->frametype != AST_FRAME_VOICE) ||
+		!(ast_format_is_slinear(&f->subclass.format))) {
 		return -1;
 	}
 
@@ -487,7 +489,7 @@ static int pitch_shift(struct ast_frame *f, float amount, struct fft_data *fft)
 		return 0;
 	}
 	for (samples = 0; samples < f->samples; samples += 32) {
-		smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_get_sample_rate(f->subclass.format), fun+samples, fun+samples, fft);
+		smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(&f->subclass.format), fun+samples, fun+samples, fft);
 	}
 
 	return 0;
@@ -509,5 +511,4 @@ static int load_module(void)
 	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Audio Effects Dialplan Functions");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audio Effects Dialplan Functions");
diff --git a/funcs/func_pjsip_endpoint.c b/funcs/func_pjsip_endpoint.c
deleted file mode 100644
index 98c884f..0000000
--- a/funcs/func_pjsip_endpoint.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Get information about a PJSIP endpoint
- *
- * \author \verbatim Matt Jordan <mjordan at digium.com> \endverbatim
- *
- * \ingroup functions
- *
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403617 $")
-
-#include <pjsip.h>
-#include <pjlib.h>
-
-#include "asterisk/app.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/res_pjsip.h"
-
-/*** DOCUMENTATION
-	<function name="PJSIP_ENDPOINT" language="en_US">
-		<synopsis>
-			Get information about a PJSIP endpoint
-		</synopsis>
-		<syntax>
-			<parameter name="name" required="true">
-				<para>The name of the endpoint to query.</para>
-			</parameter>
-			<parameter name="field" required="true">
-				<para>The configuration option for the endpoint to query for.
-				Supported options are those fields on the
-				<replaceable>endpoint</replaceable> object in
-				<filename>pjsip.conf</filename>.</para>
-				<enumlist>
-					<configOptionToEnum>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption)"/>
-					</configOptionToEnum>
-				</enumlist>
-			</parameter>
-		</syntax>
-	</function>
-***/
-
-static int pjsip_endpoint_function_read(struct ast_channel *chan,
-	const char *cmd, char *data, struct ast_str **buf, ssize_t len)
-{
-	struct ast_sorcery *pjsip_sorcery;
-	char *parsed_data = ast_strdupa(data);
-	RAII_VAR(void *, endpoint_obj, NULL, ao2_cleanup);
-	struct ast_variable *change_set;
-	struct ast_variable *it_change_set;
-	int res;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(endpoint_name);
-		AST_APP_ARG(field_name);
-	);
-
-	/* Check for zero arguments */
-	if (ast_strlen_zero(parsed_data)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s without arguments\n", cmd);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parsed_data);
-
-	if (ast_strlen_zero(args.endpoint_name)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s without an endpoint name to query\n", cmd);
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.field_name)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s with an empty field name to query\n", cmd);
-		return -1;
-	}
-
-	pjsip_sorcery = ast_sip_get_sorcery();
-	if (!pjsip_sorcery) {
-		ast_log(AST_LOG_ERROR, "Unable to retrieve PJSIP configuration: sorcery object is NULL\n");
-		return -1;
-	}
-
-	endpoint_obj = ast_sorcery_retrieve_by_id(pjsip_sorcery, "endpoint", args.endpoint_name);
-	if (!endpoint_obj) {
-		ast_log(AST_LOG_WARNING, "Failed to retrieve information for endpoint '%s'\n", args.endpoint_name);
-		return -1;
-	}
-
-	change_set = ast_sorcery_objectset_create(pjsip_sorcery, endpoint_obj);
-	if (!change_set) {
-		ast_log(AST_LOG_WARNING, "Failed to retrieve information for endpoint '%s': change set is NULL\n", args.endpoint_name);
-		return -1;
-	}
-
-	for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
-		if (!strcmp(it_change_set->name, args.field_name)) {
-			if (!strcmp(it_change_set->name, "disallow")) {
-				ast_str_set(buf, len, "!%s", it_change_set->value);
-			} else {
-				ast_str_set(buf, len, "%s", it_change_set->value);
-			}
-			break;
-		}
-	}
-
-	res = it_change_set ? 0 : 1;
-	if (res) {
-		ast_log(AST_LOG_WARNING, "Unknown property '%s' for PJSIP endpoint\n", args.field_name);
-	}
-
-	ast_variables_destroy(change_set);
-
-	return res;
-}
-
-
-static struct ast_custom_function pjsip_endpoint_function = {
-	.name = "PJSIP_ENDPOINT",
-	.read2 = pjsip_endpoint_function_read,
-};
-
-static int unload_module(void)
-{
-	return ast_custom_function_unregister(&pjsip_endpoint_function);
-}
-
-static int load_module(void)
-{
-	return ast_custom_function_register(&pjsip_endpoint_function);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get information about a PJSIP endpoint");
diff --git a/funcs/func_presencestate.c b/funcs/func_presencestate.c
index 2d76788..d57b8e3 100644
--- a/funcs/func_presencestate.c
+++ b/funcs/func_presencestate.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/app.h"
 #ifdef TEST_FRAMEWORK
 #include "asterisk/test.h"
+#include "asterisk/event.h"
 #include <semaphore.h>
 #endif
 
@@ -71,9 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 			  <optionlist>
 			    <option name="e">
 				  <para>On Write - Use this option when the subtype and message provided are Base64
-					encoded. The values will be stored encoded within Asterisk, but all consumers of
-					the presence state (e.g. the SIP presence event package) will receive decoded values.</para>
-					<para>On Read - Retrieves unencoded message/subtype in Base64 encoded form.</para>
+					encoded. On Read - Retrieves message/subtype in Base64 encoded form.</para>
 				</option>
 			  </optionlist>
 			</parameter>
@@ -231,18 +230,7 @@ static int presence_write(struct ast_channel *chan, const char *cmd, char *data,
 
 	ast_db_put(astdb_family, data, value);
 
-	if (strchr(options, 'e')) {
-		/* Let's decode the values before sending them to stasis, yes? */
-		char decoded_subtype[256] = { 0, };
-		char decoded_message[256] = { 0, };
-
-		ast_base64decode((unsigned char *) decoded_subtype, subtype, sizeof(decoded_subtype) -1);
-		ast_base64decode((unsigned char *) decoded_message, message, sizeof(decoded_message) -1);
-
-		ast_presence_state_changed_literal(state, decoded_subtype, decoded_message, tmp);
-	} else {
-		ast_presence_state_changed_literal(state, subtype, message, tmp);
-	}
+	ast_presence_state_changed_literal(state, subtype, message, tmp);
 
 	return 0;
 }
@@ -263,7 +251,6 @@ static enum ast_presence_state custom_presence_callback(const char *data, char *
 
 	if ((strchr(_options, 'e'))) {
 		char tmp[1301];
-
 		if (ast_strlen_zero(_subtype)) {
 			*subtype = NULL;
 		} else {
@@ -657,93 +644,34 @@ AST_TEST_DEFINE(test_invalid_parse_data)
 	return res;
 }
 
-#define PRES_STATE "away"
-#define PRES_SUBTYPE "down the hall"
-#define PRES_MESSAGE "Quarterly financial meeting"
-
 struct test_cb_data {
-	struct ast_presence_state_message *presence_state;
+	enum ast_presence_state presence;
+	const char *provider;
+	const char *subtype;
+	const char *message;
 	/* That's right. I'm using a semaphore */
 	sem_t sem;
 };
 
-static struct test_cb_data *test_cb_data_alloc(void)
-{
-	struct test_cb_data *cb_data = ast_calloc(1, sizeof(*cb_data));
-
-	if (!cb_data) {
-		return NULL;
-	}
-
-	if (sem_init(&cb_data->sem, 0, 0)) {
-		ast_free(cb_data);
-		return NULL;
-	}
-
-	return cb_data;
-}
-
-static void test_cb_data_destroy(struct test_cb_data *cb_data)
-{
-	ao2_cleanup(cb_data->presence_state);
-	sem_destroy(&cb_data->sem);
-	ast_free(cb_data);
-}
-
-static void test_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void test_cb(const struct ast_event *event, void *userdata)
 {
 	struct test_cb_data *cb_data = userdata;
-	if (stasis_message_type(msg) != ast_presence_state_message_type()) {
-		return;
-	}
-	cb_data->presence_state = stasis_message_data(msg);
-	ao2_ref(cb_data->presence_state, +1);
-
+	cb_data->presence = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+	cb_data->provider = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER));
+	cb_data->subtype = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE));
+	cb_data->message = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE));
 	sem_post(&cb_data->sem);
 }
 
-static enum ast_test_result_state presence_change_common(struct ast_test *test,
-		const char *state, const char *subtype, const char *message, const char *options,
-		char *out_state, size_t out_state_size,
-		char *out_subtype, size_t out_subtype_size,
-		char *out_message, size_t out_message_size)
-{
-	RAII_VAR(struct test_cb_data *, cb_data, test_cb_data_alloc(), test_cb_data_destroy);
-	struct stasis_subscription *test_sub;
-	char pres[1301];
-
-	if (!(test_sub = stasis_subscribe(ast_presence_state_topic_all(), test_cb, cb_data))) {
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_strlen_zero(options)) {
-		snprintf(pres, sizeof(pres), "%s,%s,%s", state, subtype, message);
-	} else {
-		snprintf(pres, sizeof(pres), "%s,%s,%s,%s", state, subtype, message, options);
-	}
-
-	if (presence_write(NULL, "PRESENCESTATE", "CustomPresence:TestPresenceStateChange", pres)) {
-		test_sub = stasis_unsubscribe_and_join(test_sub);
-		return AST_TEST_FAIL;
-	}
-
-	sem_wait(&cb_data->sem);
-
-	ast_copy_string(out_state, ast_presence_state2str(cb_data->presence_state->state), out_state_size);
-	ast_copy_string(out_subtype, cb_data->presence_state->subtype, out_subtype_size);
-	ast_copy_string(out_message, cb_data->presence_state->message, out_message_size);
-
-	test_sub = stasis_unsubscribe_and_join(test_sub);
-	ast_db_del("CustomPresence", "TestPresenceStateChange");
-
-	return AST_TEST_PASS;
-}
-
+/* XXX This test could probably stand to be moved since
+ * it does not test func_presencestate but rather code in
+ * presencestate.h and presencestate.c. However, the convenience
+ * of presence_write() makes this a nice location for this test.
+ */
 AST_TEST_DEFINE(test_presence_state_change)
 {
-	char out_state[32];
-	char out_subtype[32];
-	char out_message[32];
+	struct ast_event_sub *test_sub;
+	struct test_cb_data *cb_data;
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -757,67 +685,36 @@ AST_TEST_DEFINE(test_presence_state_change)
 		break;
 	}
 
-	if (presence_change_common(test, PRES_STATE, PRES_SUBTYPE, PRES_MESSAGE, NULL,
-				out_state, sizeof(out_state),
-				out_subtype, sizeof(out_subtype),
-				out_message, sizeof(out_message)) == AST_TEST_FAIL) {
+	cb_data = ast_calloc(1, sizeof(*cb_data));
+	if (!cb_data) {
 		return AST_TEST_FAIL;
 	}
 
-	if (strcmp(out_state, PRES_STATE) ||
-			strcmp(out_subtype, PRES_SUBTYPE) ||
-			strcmp(out_message, PRES_MESSAGE)) {
-		ast_test_status_update(test, "Unexpected presence values, %s != %s, %s != %s, or %s != %s\n",
-				PRES_STATE, out_state,
-				PRES_SUBTYPE, out_subtype,
-				PRES_MESSAGE, out_message);
+	if (!(test_sub = ast_event_subscribe(AST_EVENT_PRESENCE_STATE,
+			test_cb, "Test presence state callbacks", cb_data, AST_EVENT_IE_END))) {
 		return AST_TEST_FAIL;
 	}
 
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_presence_state_base64_encode)
-{
-	char out_state[32];
-	char out_subtype[32];
-	char out_message[32];
-	char encoded_subtype[64];
-	char encoded_message[64];
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "test_presence_state_base64_encode";
-		info->category = "/funcs/func_presence/";
-		info->summary = "presence state base64 encoding";
-		info->description =
-			"Ensure that base64-encoded presence state is stored base64-encoded but\n"
-			"is presented to consumers decoded.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_base64encode(encoded_subtype, (unsigned char *) PRES_SUBTYPE, strlen(PRES_SUBTYPE), sizeof(encoded_subtype) - 1);
-	ast_base64encode(encoded_message, (unsigned char *) PRES_MESSAGE, strlen(PRES_MESSAGE), sizeof(encoded_message) - 1);
-
-	if (presence_change_common(test, PRES_STATE, encoded_subtype, encoded_message, "e",
-				out_state, sizeof(out_state),
-				out_subtype, sizeof(out_subtype),
-				out_message, sizeof(out_message)) == AST_TEST_FAIL) {
+	if (sem_init(&cb_data->sem, 0, 0)) {
 		return AST_TEST_FAIL;
 	}
 
-	if (strcmp(out_state, PRES_STATE) ||
-			strcmp(out_subtype, PRES_SUBTYPE) ||
-			strcmp(out_message, PRES_MESSAGE)) {
-		ast_test_status_update(test, "Unexpected presence values, %s != %s, %s != %s, or %s != %s\n",
-				PRES_STATE, out_state,
-				PRES_SUBTYPE, out_subtype,
-				PRES_MESSAGE, out_message);
+	presence_write(NULL, "PRESENCESTATE", "CustomPresence:TestPresenceStateChange", "away,down the hall,Quarterly financial meeting");
+	sem_wait(&cb_data->sem);
+	if (cb_data->presence != AST_PRESENCE_AWAY ||
+			strcmp(cb_data->provider, "CustomPresence:TestPresenceStateChange") ||
+			strcmp(cb_data->subtype, "down the hall") ||
+			strcmp(cb_data->message, "Quarterly financial meeting")) {
 		return AST_TEST_FAIL;
 	}
 
+	ast_free((char *)cb_data->provider);
+	ast_free((char *)cb_data->subtype);
+	ast_free((char *)cb_data->message);
+	ast_free((char *)cb_data);
+
+	ast_db_del("CustomPresence", "TestPresenceStateChange");
+
 	return AST_TEST_PASS;
 }
 
@@ -834,7 +731,6 @@ static int unload_module(void)
 	AST_TEST_UNREGISTER(test_valid_parse_data);
 	AST_TEST_UNREGISTER(test_invalid_parse_data);
 	AST_TEST_UNREGISTER(test_presence_state_change);
-	AST_TEST_UNREGISTER(test_presence_state_base64_encode);
 #endif
 	return res;
 }
@@ -849,16 +745,20 @@ static int load_module(void)
 	db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
 	for (; db_entry; db_entry = db_entry->next) {
 		const char *dev_name = strrchr(db_entry->key, '/') + 1;
+		char state_info[1301];
 		enum ast_presence_state state;
 		char *message;
 		char *subtype;
+		char *options;
 		if (dev_name <= (const char *) 1) {
 			continue;
 		}
-		state = custom_presence_callback(dev_name, &subtype, &message);
+		ast_copy_string(state_info, db_entry->data, sizeof(state_info));
+		if (parse_data(state_info, &state, &subtype, &message, &options)) {
+			ast_log(LOG_WARNING, "Invalid CustomPresence entry %s encountered\n", db_entry->data);
+			continue;
+		}
 		ast_presence_state_changed(state, subtype, message, "CustomPresence:%s", dev_name);
-		ast_free(subtype);
-		ast_free(message);
 	}
 	ast_db_freetree(db_tree);
 	db_tree = NULL;
@@ -870,14 +770,12 @@ static int load_module(void)
 	AST_TEST_REGISTER(test_valid_parse_data);
 	AST_TEST_REGISTER(test_invalid_parse_data);
 	AST_TEST_REGISTER(test_presence_state_change);
-	AST_TEST_REGISTER(test_presence_state_base64_encode);
 #endif
 
 	return res;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gets or sets a presence state in the dialplan",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
diff --git a/funcs/func_rand.c b/funcs/func_rand.c
index 01e0d05..6491b37 100644
--- a/funcs/func_rand.c
+++ b/funcs/func_rand.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c
index 6253957..a870ab4 100644
--- a/funcs/func_realtime.c
+++ b/funcs/func_realtime.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403960 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_sha1.c b/funcs/func_sha1.c
index da1a86e..c6b7575 100644
--- a/funcs/func_sha1.c
+++ b/funcs/func_sha1.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
diff --git a/funcs/func_shell.c b/funcs/func_shell.c
index d3a1971..e403efc 100644
--- a/funcs/func_shell.c
+++ b/funcs/func_shell.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403960 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_sorcery.c b/funcs/func_sorcery.c
deleted file mode 100644
index 1671b3f..0000000
--- a/funcs/func_sorcery.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Get a field from a sorcery object
- *
- * \author \verbatim George Joseph <george.joseph at fairview5.com> \endverbatim
- *
- * \ingroup functions
- *
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/app.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-
-/*** DOCUMENTATION
-	<function name="AST_SORCERY" language="en_US">
-		<synopsis>
-			Get a field from a sorcery object
-		</synopsis>
-		<syntax>
-			<parameter name="module_name" required="true">
-				<para>The name of the module owning the sorcery instance.</para>
-			</parameter>
-			<parameter name="object_type" required="true">
-				<para>The type of object to query.</para>
-			</parameter>
-			<parameter name="object_id" required="true">
-				<para>The id of the object to query.</para>
-			</parameter>
-			<parameter name="field_name" required="true">
-				<para>The name of the field.</para>
-			</parameter>
-			<parameter name="retrieval_method" required="false">
-				<para>Fields that have multiple occurrences may be retrieved in two ways.</para>
-				<enumlist>
-					<enum name="concat"><para>Returns all matching fields concatenated
-					in a single string separated by <replaceable>separator</replaceable>
-					which defaults to <literal>,</literal>.</para></enum>
-
-					<enum name="single"><para>Returns the nth occurrence of the field
-					as specified by <replaceable>occurrence_number</replaceable> which defaults to <literal>1</literal>.
-					</para></enum>
-				</enumlist>
-				<para>The default is <literal>concat</literal> with separator <literal>,</literal>.</para>
-			</parameter>
-			<parameter name="retrieval_details" required="false">
-				<para>Specifies either the separator for <literal>concat</literal>
-				or the occurrence number for <literal>single</literal>.</para>
-			</parameter>
-		</syntax>
-	</function>
-***/
-
-static int sorcery_function_read(struct ast_channel *chan,
-	const char *cmd, char *data, struct ast_str **buf, ssize_t len)
-{
-	char *parsed_data = ast_strdupa(data);
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup);
-	struct ast_variable *change_set;
-	struct ast_variable *it_change_set;
-	int found, field_number = 1, ix, method;
-	char *separator = ",";
-
-	enum methods {
-		CONCAT,
-		SINGLE,
-	};
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(module_name);
-		AST_APP_ARG(object_type);
-		AST_APP_ARG(object_id);
-		AST_APP_ARG(field_name);
-		AST_APP_ARG(method);
-		AST_APP_ARG(method_arg);
-	);
-
-	/* Check for zero arguments */
-	if (ast_strlen_zero(parsed_data)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s without arguments\n", cmd);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parsed_data);
-
-	if (ast_strlen_zero(args.module_name)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s without a module name to query\n", cmd);
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.object_type)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object type\n", cmd);
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.object_id)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object name\n", cmd);
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.field_name)) {
-		ast_log(AST_LOG_ERROR, "Cannot call %s with an empty field name\n", cmd);
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.method)) {
-		method = CONCAT;
-	} else {
-		if (strcmp(args.method, "concat") == 0) {
-			method = CONCAT;
-			if (ast_strlen_zero(args.method_arg)) {
-				separator = ",";
-			} else {
-				separator = args.method_arg;
-			}
-
-		} else if (strcmp(args.method, "single") == 0) {
-			method = SINGLE;
-			if (!ast_strlen_zero(args.method_arg)) {
-				if (sscanf(args.method_arg, "%30d", &field_number) <= 0 || field_number <= 0 ) {
-					ast_log(AST_LOG_ERROR, "occurrence_number must be a positive integer\n");
-					return -1;
-				}
-			}
-		} else {
-			ast_log(AST_LOG_ERROR, "Retrieval method must be 'concat' or 'single'\n");
-			return -1;
-		}
-	}
-
-	sorcery = ast_sorcery_retrieve_by_module_name(args.module_name);
-	if (!sorcery) {
-		ast_log(AST_LOG_ERROR, "Failed to retrieve sorcery instance for module %s\n", args.module_name);
-		return -1;
-	}
-
-	sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args.object_type, args.object_id);
-	if (!sorcery_obj) {
-		return -1;
-	}
-
-	change_set = ast_sorcery_objectset_create(sorcery, sorcery_obj);
-	if (!change_set) {
-		return -1;
-	}
-
-	ix=1;
-	found = 0;
-	for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
-
-		if (method == CONCAT && strcmp(it_change_set->name, args.field_name) == 0) {
-			ast_str_append(buf, 0, "%s%s", it_change_set->value, separator);
-			found = 1;
-			continue;
-		}
-
-		if (method == SINGLE && strcmp(it_change_set->name, args.field_name) == 0  && ix++ == field_number) {
-			ast_str_set(buf, len, "%s", it_change_set->value);
-			found = 1;
-			break;
-		}
-	}
-
-	ast_variables_destroy(change_set);
-
-	if (!found) {
-		return -1;
-	}
-
-	if (method == CONCAT) {
-		ast_str_truncate(*buf, -1);
-	}
-
-	return 0;
-}
-
-static struct ast_custom_function sorcery_function = {
-	.name = "AST_SORCERY",
-	.read2 = sorcery_function_read,
-};
-
-static int unload_module(void)
-{
-	return ast_custom_function_unregister(&sorcery_function);
-}
-
-static int load_module(void)
-{
-	return ast_custom_function_register(&sorcery_function);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get a field from a sorcery object");
-
diff --git a/funcs/func_speex.c b/funcs/func_speex.c
index 738e6fc..7da3e87 100644
--- a/funcs/func_speex.c
+++ b/funcs/func_speex.c
@@ -26,7 +26,7 @@
  *
  * \ingroup functions
  *
- * The Speex 1.2 library - http://www.speex.org
+ * \extref The Speex 1.2 library - http://www.speex.org
  * \note Requires the 1.2 version of the Speex library (which might not be what you find in Linux packages)
  */
 
@@ -39,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <speex/speex_preprocess.h>
 #include "asterisk/module.h"
@@ -165,8 +165,8 @@ static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *c
 		return -1;
 	}
 
-	if ((sdi->samples != frame->samples) || (ast_format_get_sample_rate(frame->subclass.format) != si->lastrate)) {
-		si->lastrate = ast_format_get_sample_rate(frame->subclass.format);
+	if ((sdi->samples != frame->samples) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) {
+		si->lastrate = ast_format_rate(&frame->subclass.format);
 		if (sdi->state) {
 			speex_preprocess_state_destroy(sdi->state);
 		}
diff --git a/funcs/func_sprintf.c b/funcs/func_sprintf.c
index 7ffd2dc..4d5fc7a 100644
--- a/funcs/func_sprintf.c
+++ b/funcs/func_sprintf.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 
diff --git a/funcs/func_srv.c b/funcs/func_srv.c
index d455029..3786a2f 100644
--- a/funcs/func_srv.c
+++ b/funcs/func_srv.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/srv.h"
diff --git a/funcs/func_strings.c b/funcs/func_strings.c
index 7952a24..8573450 100644
--- a/funcs/func_strings.c
+++ b/funcs/func_strings.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416503 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <regex.h>
 #include <ctype.h>
@@ -1001,7 +1001,7 @@ static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
 	struct ast_var_t *var;
 	int len = strlen(prefix);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_varshead(chan), var, entries) {
-		if (strncmp(prefix, ast_var_name(var), len) == 0) {
+		if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
 			AST_LIST_REMOVE_CURRENT(entries);
 			ast_free(var);
 		}
@@ -1106,7 +1106,7 @@ static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data,
 	memset(buf, 0, len);
 
 	AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
-		if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
+		if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
 			/* Copy everything after the prefix */
 			strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
 			/* Trim the trailing ~ */
@@ -1132,7 +1132,7 @@ static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data,
 	ast_str_set(&prefix, -1, HASH_PREFIX, data);
 
 	AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
-		if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
+		if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
 			/* Copy everything after the prefix */
 			ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
 			/* Trim the trailing ~ */
diff --git a/funcs/func_sysinfo.c b/funcs/func_sysinfo.c
index 3072e93..8da94dd 100644
--- a/funcs/func_sysinfo.c
+++ b/funcs/func_sysinfo.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #if defined(HAVE_SYSINFO)
 #include <sys/sysinfo.h>
diff --git a/funcs/func_talkdetect.c b/funcs/func_talkdetect.c
deleted file mode 100644
index 45d1f5e..0000000
--- a/funcs/func_talkdetect.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Function that raises events when talking is detected on a channel
- *
- * \author Matt Jordan <mjordan at digium.com>
- *
- * \ingroup functions
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427204 $")
-
-#include "asterisk/module.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/app.h"
-#include "asterisk/dsp.h"
-#include "asterisk/audiohook.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-
-/*** DOCUMENTATION
-	<function name="TALK_DETECT" language="en_US">
-		<synopsis>
-			Raises notifications when Asterisk detects silence or talking on a channel.
-		</synopsis>
-		<syntax>
-			<parameter name="action" required="true">
-				<optionlist>
-					<option name="remove">
-						<para>W/O. Remove talk detection from the channel.</para>
-					</option>
-					<option name="set">
-						<para>W/O. Enable TALK_DETECT and/or configure talk detection
-						parameters. Can be called multiple times to change parameters
-						on a channel with talk detection already enabled.</para>
-						<argument name="dsp_silence_threshold" required="false">
-							<para>The time in milliseconds before which a user is considered silent.</para>
-						</argument>
-						<argument name="dsp_talking_threshold" required="false">
-							<para>The time in milliseconds after which a user is considered talking.</para>
-						</argument>
-					</option>
-				</optionlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>The TALK_DETECT function enables events on the channel
-			it is applied to. These events can be emited over AMI, ARI, and
-			potentially other Asterisk modules that listen for the internal
-			notification.</para>
-			<para>The function has two parameters that can optionally be passed
-			when <literal>set</literal> on a channel: <replaceable>dsp_talking_threshold</replaceable>
-			and <replaceable>dsp_silence_threshold</replaceable>.</para>
-			<para><replaceable>dsp_talking_threshold</replaceable> is the time in milliseconds of sound
-			above what the dsp has established as base line silence for a user
-			before a user is considered to be talking. By default, the value of
-			<replaceable>silencethreshold</replaceable> from <filename>dsp.conf</filename>
-			is used. If this value is set too tight events may be
-			falsely triggered by variants in room noise.</para>
-			<para>Valid values are 1 through 2^31.</para>
-			<para><replaceable>dsp_silence_threshold</replaceable> is the time in milliseconds of sound
-			falling within what the dsp has established as baseline silence before
-			a user is considered be silent. If this value is set too low events
-			indicating the user has stopped talking may get falsely sent out when
-			the user briefly pauses during mid sentence.</para>
-			<para>The best way to approach this option is to set it slightly above
-			the maximum amount of ms of silence a user may generate during
-			natural speech.</para>
-			<para>By default this value is 2500ms. Valid values are 1
-			through 2^31.</para>
-			<para>Example:</para>
-			<para>same => n,Set(TALK_DETECT(set)=)     ; Enable talk detection</para>
-			<para>same => n,Set(TALK_DETECT(set)=1200) ; Update existing talk detection's silence threshold to 1200 ms</para>
-			<para>same => n,Set(TALK_DETECT(remove)=)  ; Remove talk detection</para>
-			<para>same => n,Set(TALK_DETECT(set)=,128) ; Enable and set talk threshold to 128</para>
-			<para>This function will set the following variables:</para>
-			<note>
-				<para>The TALK_DETECT function uses an audiohook to inspect the
-				voice media frames on a channel. Other functions, such as JITTERBUFFER,
-				DENOISE, and AGC use a similar mechanism. Audiohooks are processed
-				in the order in which they are placed on the channel. As such,
-				it typically makes sense to place functions that modify the voice
-				media data prior to placing the TALK_DETECT function, as this will
-				yield better results.</para>
-				<para>Example:</para>
-				<para>same => n,Set(DENOISE(rx)=on)    ; Denoise received audio</para>
-				<para>same => n,Set(TALK_DETECT(set)=) ; Perform talk detection on the denoised received audio</para>
-			</note>
-		</description>
-	</function>
- ***/
-
-#define DEFAULT_SILENCE_THRESHOLD 2500
-
-/*! \brief Private data structure used with the function's datastore */
-struct talk_detect_params {
-	/*! The audiohook for the function */
-	struct ast_audiohook audiohook;
-	/*! Our threshold above which we consider someone talking */
-	int dsp_talking_threshold;
-	/*! How long we'll wait before we decide someone is silent */
-	int dsp_silence_threshold;
-	/*! Whether or not the user is currently talking */
-	int talking;
-	/*! The time the current burst of talking started */
-	struct timeval talking_start;
-	/*! The DSP used to do the heavy lifting */
-	struct ast_dsp *dsp;
-};
-
-/*! \internal \brief Destroy the datastore */
-static void datastore_destroy_cb(void *data) {
-	struct talk_detect_params *td_params = data;
-
-	ast_audiohook_destroy(&td_params->audiohook);
-
-	if (td_params->dsp) {
-		ast_dsp_free(td_params->dsp);
-	}
-	ast_free(data);
-}
-
-/*! \brief The channel datastore the function uses to store state */
-static const struct ast_datastore_info talk_detect_datastore = {
-	.type = "talk_detect",
-	.destroy = datastore_destroy_cb
-};
-
-/*! \internal \brief An audiohook modification callback
- *
- * This processes the read side of a channel's voice data to see if
- * they are talking
- *
- * \note We don't actually modify the audio, so this function always
- * returns a 'failure' indicating that it didn't modify the data
- */
-static int talk_detect_audiohook_cb(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
-{
-	int total_silence;
-	int update_talking = 0;
-	struct ast_datastore *datastore;
-	struct talk_detect_params *td_params;
-	struct stasis_message *message;
-
-	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
-		return 1;
-	}
-
-	if (direction != AST_AUDIOHOOK_DIRECTION_READ) {
-		return 1;
-	}
-
-	if (frame->frametype != AST_FRAME_VOICE) {
-		return 1;
-	}
-
-	if (!(datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL))) {
-		return 1;
-	}
-	td_params = datastore->data;
-
-	ast_dsp_silence(td_params->dsp, frame, &total_silence);
-
-	if (total_silence < td_params->dsp_silence_threshold) {
-		if (!td_params->talking) {
-			update_talking = 1;
-			td_params->talking_start = ast_tvnow();
-		}
-		td_params->talking = 1;
-	} else {
-		if (td_params->talking) {
-			update_talking = 1;
-		}
-		td_params->talking = 0;
-	}
-
-	if (update_talking) {
-		struct ast_json *blob = NULL;
-
-		if (!td_params->talking) {
-			int64_t diff_ms = ast_tvdiff_ms(ast_tvnow(), td_params->talking_start);
-			diff_ms -= td_params->dsp_silence_threshold;
-
-			blob = ast_json_pack("{s: i}", "duration", diff_ms);
-			if (!blob) {
-				return 1;
-			}
-		}
-
-		ast_verb(4, "%s is now %s\n", ast_channel_name(chan),
-		            td_params->talking ? "talking" : "silent");
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
-		                td_params->talking ? ast_channel_talking_start() : ast_channel_talking_stop(),
-		                blob);
-		if (message) {
-			stasis_publish(ast_channel_topic(chan), message);
-			ao2_ref(message, -1);
-		}
-
-		ast_json_unref(blob);
-	}
-
-	return 1;
-}
-
-/*! \internal \brief Disable talk detection on the channel */
-static int remove_talk_detect(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = NULL;
-	struct talk_detect_params *td_params;
-	SCOPED_CHANNELLOCK(chan_lock, chan);
-
-	datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL);
-	if (!datastore) {
-		ast_log(AST_LOG_WARNING, "Cannot remove TALK_DETECT from %s: TALK_DETECT not currently enabled\n",
-		        ast_channel_name(chan));
-		return -1;
-	}
-	td_params = datastore->data;
-
-	if (ast_audiohook_remove(chan, &td_params->audiohook)) {
-		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT audiohook from channel %s\n",
-		        ast_channel_name(chan));
-		return -1;
-	}
-
-	if (ast_channel_datastore_remove(chan, datastore)) {
-		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT datastore from channel %s\n",
-		        ast_channel_name(chan));
-		return -1;
-	}
-	ast_datastore_free(datastore);
-
-	return 0;
-}
-
-/*! \internal \brief Enable talk detection on the channel */
-static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
-{
-	struct ast_datastore *datastore = NULL;
-	struct talk_detect_params *td_params;
-	SCOPED_CHANNELLOCK(chan_lock, chan);
-
-	datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL);
-	if (!datastore) {
-		datastore = ast_datastore_alloc(&talk_detect_datastore, NULL);
-		if (!datastore) {
-			return -1;
-		}
-
-		td_params = ast_calloc(1, sizeof(*td_params));
-		if (!td_params) {
-			ast_datastore_free(datastore);
-			return -1;
-		}
-
-		ast_audiohook_init(&td_params->audiohook,
-		                   AST_AUDIOHOOK_TYPE_MANIPULATE,
-		                   "TALK_DETECT",
-		                   AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
-		td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb;
-		ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ);
-
-		td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan)));
-		if (!td_params->dsp) {
-			ast_datastore_free(datastore);
-			ast_free(td_params);
-			return -1;
-		}
-		datastore->data = td_params;
-
-		ast_channel_datastore_add(chan, datastore);
-		ast_audiohook_attach(chan, &td_params->audiohook);
-	} else {
-		/* Talk detection already enabled; update existing settings */
-		td_params = datastore->data;
-	}
-
-	td_params->dsp_talking_threshold = dsp_talking_threshold;
-	td_params->dsp_silence_threshold = dsp_silence_threshold;
-
-	ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold);
-
-	return 0;
-}
-
-/*! \internal \brief TALK_DETECT write function callback */
-static int talk_detect_fn_write(struct ast_channel *chan, const char *function, char *data, const char *value)
-{
-	int res;
-
-	if (!chan) {
-		return -1;
-	}
-
-	if (ast_strlen_zero(data)) {
-		ast_log(AST_LOG_WARNING, "TALK_DETECT requires an argument\n");
-		return -1;
-	}
-
-	if (!strcasecmp(data, "set")) {
-		int dsp_silence_threshold = DEFAULT_SILENCE_THRESHOLD;
-		int dsp_talking_threshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
-
-		if (!ast_strlen_zero(value)) {
-			char *parse = ast_strdupa(value);
-
-			AST_DECLARE_APP_ARGS(args,
-				AST_APP_ARG(silence_threshold);
-				AST_APP_ARG(talking_threshold);
-			);
-
-			AST_STANDARD_APP_ARGS(args, parse);
-
-			if (!ast_strlen_zero(args.silence_threshold)) {
-				if (sscanf(args.silence_threshold, "%30d", &dsp_silence_threshold) != 1) {
-					ast_log(AST_LOG_WARNING, "Failed to parse %s for dsp_silence_threshold\n",
-					        args.silence_threshold);
-					return -1;
-				}
-
-				if (dsp_silence_threshold < 1) {
-					ast_log(AST_LOG_WARNING, "Invalid value %d for dsp_silence_threshold\n",
-					        dsp_silence_threshold);
-					return -1;
-				}
-			}
-
-			if (!ast_strlen_zero(args.talking_threshold)) {
-				if (sscanf(args.talking_threshold, "%30d", &dsp_talking_threshold) != 1) {
-					ast_log(AST_LOG_WARNING, "Failed to parse %s for dsp_talking_threshold\n",
-					        args.talking_threshold);
-					return -1;
-				}
-
-				if (dsp_talking_threshold < 1) {
-					ast_log(AST_LOG_WARNING, "Invalid value %d for dsp_talking_threshold\n",
-					        dsp_silence_threshold);
-					return -1;
-				}
-			}
-		}
-
-		res = set_talk_detect(chan, dsp_silence_threshold, dsp_talking_threshold);
-	} else if (!strcasecmp(data, "remove")) {
-		res = remove_talk_detect(chan);
-	} else {
-		ast_log(AST_LOG_WARNING, "TALK_DETECT: unknown option %s\n", data);
-		res = -1;
-	}
-
-	return res;
-}
-
-/*! \brief Definition of the TALK_DETECT function */
-static struct ast_custom_function talk_detect_function = {
-	.name = "TALK_DETECT",
-	.write = talk_detect_fn_write,
-};
-
-/*! \internal \brief Unload the module */
-static int unload_module(void)
-{
-	int res = 0;
-
-	res |= ast_custom_function_unregister(&talk_detect_function);
-
-	return res;
-}
-
-/*! \internal \brief Load the module */
-static int load_module(void)
-{
-	int res = 0;
-
-	res |= ast_custom_function_register(&talk_detect_function);
-
-	return res ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Talk detection dialplan function");
diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c
index a4c8de5..ea4e64b 100644
--- a/funcs/func_timeout.c
+++ b/funcs/func_timeout.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405436 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
@@ -155,9 +155,7 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
 	switch (*data) {
 	case 'a':
 	case 'A':
-		ast_channel_lock(chan);
 		ast_channel_setwhentohangup_tv(chan, when);
-		ast_channel_unlock(chan);
 		if (VERBOSITY_ATLEAST(3)) {
 			if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
 				when = ast_tvadd(when, ast_tvnow());
diff --git a/funcs/func_uri.c b/funcs/func_uri.c
index bf1f550..f53b75f 100644
--- a/funcs/func_uri.c
+++ b/funcs/func_uri.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418654 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_version.c b/funcs/func_version.c
index 29e04d1..da733d1 100644
--- a/funcs/func_version.c
+++ b/funcs/func_version.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/funcs/func_vmcount.c b/funcs/func_vmcount.c
index 04099e1..c4d80d4 100644
--- a/funcs/func_vmcount.c
+++ b/funcs/func_vmcount.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 404350 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <dirent.h>
 
@@ -49,21 +49,27 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 404350 $")
 			Count the voicemails in a specified mailbox.
 		</synopsis>
 		<syntax>
-			<parameter name="vmbox" required="true" />
+			<parameter name="vmbox" required="true" argsep="@">
+				<argument name="vmbox" required="true" />
+				<argument name="context" required="false">
+					<para>If not specified, defaults to <literal>default</literal>.</para>
+				</argument>
+			</parameter>
 			<parameter name="folder" required="false">
 				<para>If not specified, defaults to <literal>INBOX</literal></para>
 			</parameter>
 		</syntax>
 		<description>
 			<para>Count the number of voicemails in a specified mailbox, you could also specify 
-			the mailbox <replaceable>folder</replaceable>.</para>
-			<para>Example: <literal>exten => s,1,Set(foo=${VMCOUNT(125 at default)})</literal></para>
+			the <replaceable>context</replaceable> and the mailbox <replaceable>folder</replaceable>.</para>
+			<para>Example: <literal>exten => s,1,Set(foo=${VMCOUNT(125)})</literal></para>
 		</description>
 	</function>
  ***/
 
 static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *argsstr, char *buf, size_t len)
 {
+	char *context;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(vmbox);
 		AST_APP_ARG(folder);
@@ -76,15 +82,18 @@ static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *arg
 
 	AST_STANDARD_APP_ARGS(args, argsstr);
 
-	if (ast_strlen_zero(args.vmbox)) {
-		return -1;
+	if (strchr(args.vmbox, '@')) {
+		context = args.vmbox;
+		args.vmbox = strsep(&context, "@");
+	} else {
+		context = "default";
 	}
 
 	if (ast_strlen_zero(args.folder)) {
 		args.folder = "INBOX";
 	}
 
-	snprintf(buf, len, "%d", ast_app_messagecount(args.vmbox, args.folder));
+	snprintf(buf, len, "%d", ast_app_messagecount(context, args.vmbox, args.folder));
 	
 	return 0;
 }
diff --git a/funcs/func_volume.c b/funcs/func_volume.c
index 738bcf8..9fd0200 100644
--- a/funcs/func_volume.c
+++ b/funcs/func_volume.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
diff --git a/include/asterisk.h b/include/asterisk.h
index ee1a9c3..5089e9c 100644
--- a/include/asterisk.h
+++ b/include/asterisk.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * General Definitions for Asterisk top level program
  *
@@ -86,6 +86,11 @@ int ast_pbx_init(void);				/*!< Provided by pbx.c */
  *
  * \retval 0 on success.
  * \retval -1 on error.
+ *
+ * \note This function should be rarely used in situations where
+ * something must be shutdown to avoid corruption, excessive data
+ * loss, or when external programs must be stopped.  All other
+ * cleanup in the core should use ast_register_cleanup.
  */
 int ast_register_atexit(void (*func)(void));
 
@@ -118,6 +123,8 @@ void ast_unregister_atexit(void (*func)(void));
  * \param version the version string (typically a SVN revision keyword string)
  * \return nothing
  *
+ * \note As of 11.18.0, the \c version parameter is ignored.
+ *
  * This function should not be called directly, but instead the
  * ASTERISK_FILE_VERSION macro should be used to register a file with the core.
  */
@@ -134,12 +141,29 @@ void ast_register_file_version(const char *file, const char *version);
  */
 void ast_unregister_file_version(const char *file);
 
-/*! \brief Find version for given module name
+/*!
+ * \brief Find version for given module name
  * \param file Module name (i.e. chan_sip.so)
- * \return version string or NULL if the module is not found
+ *
+ * \note As of 11.18.0, the file version is no longer tracked. As such,
+ * if the file exists, the Asterisk version will be returned.
+ *
+ * \retval NULL if the file doesn't exist.
+ * \retval The Asterisk version if the file does exist.
  */
 const char *ast_file_version_find(const char *file);
 
+/*!
+ * \brief Complete a source file name
+ * \param partial The partial name of the file to look up.
+ * \param n The n-th match to return.
+ *
+ * \retval NULL if there is no match for partial at the n-th position
+ * \retval Matching source file name
+ *
+ * \note A matching source file is allocataed on the heap, and must be
+ * free'd by the caller.
+ */
 char *ast_complete_source_filename(const char *partial, int n);
 
 /*!
@@ -229,6 +253,17 @@ struct ast_variable;
 struct ast_str;
 struct ast_sched_context;
 
+#ifdef bzero
+#undef bzero
+#endif
+
+#ifdef bcopy
+#undef bcopy
+#endif
+
+#define bzero  0x__dont_use_bzero__use_memset_instead""
+#define bcopy  0x__dont_use_bcopy__use_memmove_instead()
+
 /* Some handy macros for turning a preprocessor token into (effectively) a quoted string */
 #define __stringify_1(x)	#x
 #define __stringify(x)		__stringify_1(x)
diff --git a/include/asterisk/.gitignore b/include/asterisk/.gitignore
new file mode 100644
index 0000000..ae33b3c
--- /dev/null
+++ b/include/asterisk/.gitignore
@@ -0,0 +1,3 @@
+autoconfig.h
+build.h
+buildopts.h
diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index 01a8352..1bc2433 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -8,7 +8,7 @@
  *
  * \brief
  * Prototypes for public functions only of internal interest,
- *
+ * 
  */
 
 
@@ -19,16 +19,19 @@ int load_modules(unsigned int);		/*!< Provided by loader.c */
 int load_pbx(void);			/*!< Provided by pbx.c */
 int init_logger(void);			/*!< Provided by logger.c */
 void close_logger(void);		/*!< Provided by logger.c */
+void logger_queue_start(void);		/*!< Provided by logger.c */
 void clean_time_zones(void);			/*!< Provided by localtime.c */
+int init_framer(void);			/*!< Provided by frame.c */
 int ast_term_init(void);		/*!< Provided by term.c */
 int astdb_init(void);			/*!< Provided by db.c */
 void ast_channels_init(void);		/*!< Provided by channel.c */
 void ast_builtins_init(void);		/*!< Provided by cli.c */
 int ast_cli_perms_init(int reload);	/*!< Provided by cli.c */
-int dnsmgr_init(void);			/*!< Provided by dnsmgr.c */
+int dnsmgr_init(void);			/*!< Provided by dnsmgr.c */ 
 void dnsmgr_start_refresh(void);	/*!< Provided by dnsmgr.c */
 int dnsmgr_reload(void);		/*!< Provided by dnsmgr.c */
 void threadstorage_init(void);		/*!< Provided by threadstorage.c */
+int ast_event_init(void);		/*!< Provided by event.c */
 int ast_device_state_engine_init(void);	/*!< Provided by devicestate.c */
 int astobj2_init(void);			/*!< Provided by astobj2.c */
 int ast_file_init(void);		/*!< Provided by file.c */
@@ -48,39 +51,6 @@ int ast_ssl_init(void);                 /*!< Provided by ssl.c */
 int ast_test_init(void);            /*!< Provided by test.c */
 int ast_msg_init(void);             /*!< Provided by message.c */
 void ast_msg_shutdown(void);        /*!< Provided by message.c */
-int aco_init(void);             /*!< Provided by config_options.c */
-
-/*!
- * \since 12
- * \brief Possible return types for \ref ast_module_reload
- */
-enum ast_module_reload_result {
-	AST_MODULE_RELOAD_SUCCESS = 0,      /*!< The module was reloaded succesfully */
-	AST_MODULE_RELOAD_QUEUED,           /*!< The module reload request was queued */
-	AST_MODULE_RELOAD_NOT_FOUND,        /*!< The requested module was not found */
-	AST_MODULE_RELOAD_ERROR,            /*!< An error occurred while reloading the module */
-	AST_MODULE_RELOAD_IN_PROGRESS,      /*!< A module reload request is already in progress */
-	AST_MODULE_RELOAD_UNINITIALIZED,    /*!< The module has not been initialized */
-	AST_MODULE_RELOAD_NOT_IMPLEMENTED,  /*!< This module doesn't support reloading */
-};
-
-/*!
- * \brief Initialize the bridging system.
- * \since 12.0.0
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridging_init(void);
-
-/*!
- * \brief Initialize the local proxy channel.
- * \since 12.0.0
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_local_init(void);
 
 /*!
  * \brief Reload asterisk modules.
@@ -91,10 +61,13 @@ int ast_local_init(void);
  *
  * \note Modules are reloaded using their reload() functions, not unloading
  * them and loading them again.
- *
- * \retval The \ref ast_module_reload_result status of the module load request
+ * 
+ * \return 0 if the specified module was not found.
+ * \retval 1 if the module was found but cannot be reloaded.
+ * \retval -1 if a reload operation is already in progress.
+ * \retval 2 if the specfied module was found and reloaded.
  */
-enum ast_module_reload_result ast_module_reload(const char *name);
+int ast_module_reload(const char *name);
 
 /*!
  * \brief Process reload requests received during startup.
@@ -108,9 +81,9 @@ enum ast_module_reload_result ast_module_reload(const char *name);
  */
 void ast_process_pending_reloads(void);
 
-/*! \brief Load XML documentation. Provided by xmldoc.c
+/*! \brief Load XML documentation. Provided by xmldoc.c 
  *  \retval 1 on error.
- *  \retval 0 on success.
+ *  \retval 0 on success. 
  */
 int ast_xmldoc_load_documentation(void);
 
@@ -121,23 +94,16 @@ int ast_xmldoc_load_documentation(void);
  */
 int ast_plc_reload(void);
 
-/*! \brief initializes the rtp engine arrays */
-int ast_rtp_engine_init(void);
-
 /*!
- * \brief initializes the rtp engine arrays
- * \since 12.0.0
+ * \brief Init the ast_format attribute interface register container.
  */
-int ast_parking_stasis_init(void);
-
-/*! \brief initialize the sounds index */
-int ast_sounds_index_init(void);
+int ast_format_attr_init(void);
 
 /*!
- * \brief Endpoint support initialization.
- * \return 0 on success.
- * \return Non-zero on error.
+ * \brief Init the Asterisk global format list after all format attribute modules have been loaded
  */
-int ast_endpoint_init(void);
+int ast_format_list_init(void);
 
+/*! \brief initializes the rtp engine arrays */
+int ast_rtp_engine_init(void);
 #endif /* _ASTERISK__PRIVATE_H */
diff --git a/include/asterisk/abstract_jb.h b/include/asterisk/abstract_jb.h
index 8a5e3d2..3e6bedd 100644
--- a/include/asterisk/abstract_jb.h
+++ b/include/asterisk/abstract_jb.h
@@ -145,7 +145,7 @@ struct ast_jb
 	/*! \brief The time the next frame should be played. */
 	long next;
 	/*! \brief Voice format of the last frame in. */
-	struct ast_format *last_format;
+	struct ast_format last_format;
 	/*! \brief File for frame timestamp tracing. */
 	FILE *logfile;
 	/*! \brief Jitterbuffer internal state flags. */
@@ -246,14 +246,6 @@ void ast_jb_destroy(struct ast_channel *chan);
  */
 int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value);
 
-/*!
- * \since 12.0
- * \brief Sets a jitterbuffer frame hook on the channel based on the channel's stored
- *        jitterbuffer configuration
- *
- * \param chan Which channel is being set up
- */
-void ast_jb_enable_for_channel(struct ast_channel *chan);
 
 /*!
  * \brief Configures a jitterbuffer on a channel.
@@ -265,6 +257,7 @@ void ast_jb_enable_for_channel(struct ast_channel *chan);
  */
 void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf);
 
+
 /*!
  * \brief Copies a channel's jitterbuffer configuration.
  * \param chan channel.
@@ -281,25 +274,6 @@ void ast_jb_empty_and_reset(struct ast_channel *c0, struct ast_channel *c1);
 
 const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type);
 
-/*!
- * \since 12
- * \brief Sets the contents of an ast_jb_conf struct to the default jitterbuffer settings
- *
- * \param conf Which jitterbuffer is being set
- */
-void ast_jb_conf_default(struct ast_jb_conf *conf);
-
-/*!
- * \since 12
- * \brief Applies a jitterbuffer framehook to a channel based on a provided jitterbuffer config
- *
- * \param chan Which channel the jitterbuffer is being set on
- * \param jb_conf Configuration to use for the jitterbuffer
- * \param prefer_existing If this is true and a jitterbuffer already exists for the channel,
- *        use the existing jitterbuffer
- */
-void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h
index bda1c76..0dfb47f 100644
--- a/include/asterisk/acl.h
+++ b/include/asterisk/acl.h
@@ -135,20 +135,6 @@ void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to);
 struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error);
 
 /*!
- * \brief Convert HAs to a comma separated string value
- * \param ha the starting ha head
- * \param buf string buffer to convert data to
- */
-void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf);
-
-/*!
- * \brief Convert HAs to a comma separated string value using CIDR notation
- * \param ha the starting ha head
- * \param buf string buffer to convert data to
- */
-void ast_ha_join_cidr(const struct ast_ha *ha, struct ast_str **buf);
-
-/*!
  * \brief Add a rule to an ACL struct
  *
  * \details
@@ -203,7 +189,7 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
  * contained in the acl container. It will deny if any of the ast_ha lists
  * fail, and it will pass only if all of the rules pass.
  *
- * \param acl_list The head of the list of ACLs to evaluate
+ * \param acl The head of the list of ACLs to evaluate
  * \param addr An ast_sockaddr whose address is considered when matching rules
  * \param purpose Context for which the ACL is being applied - Establishes purpose of a notice when rejected
  *
@@ -222,7 +208,7 @@ enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast
  *
  * \param addr The IP address found.  The address family is used
  * as an input parameter to filter the returned addresses.  If
- * it is AST_AF_UNSPEC, both IPv4 and IPv6 addresses can be returned.
+ * it is 0, both IPv4 and IPv6 addresses can be returned.
  * \param hostname The hostname to look up
  *
  * \retval 0 Success
@@ -399,18 +385,6 @@ int ast_named_acl_init(void);
  */
 int ast_named_acl_reload(void);
 
-/*!
- * \brief a \ref stasis_message_type for changes against a named ACL or the set of all named ACLs
- * \since 12
- *
- * \retval NULL on error
- * \retval \ref stasis_message_type for named ACL changes
- *
- * \note Messages of this type should always be issued on and expected from the
- *       \ref ast_security_topic \ref stasis_topic
- */
-struct stasis_message_type *ast_named_acl_change_type(void);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/aoc.h b/include/asterisk/aoc.h
index 171fbb3..727362c 100644
--- a/include/asterisk/aoc.h
+++ b/include/asterisk/aoc.h
@@ -497,10 +497,7 @@ int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
  */
 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg);
 
-/*!
- * \brief generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg
- * \pre chan is locked
- */
+/*! \brief generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg */
 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan);
 
 /*! \brief get the message type, AOC-D, AOC-E, or AOC Request */
diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index d5a0e27..d10a0a6 100644
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -28,8 +28,6 @@
 #include "asterisk/threadstorage.h"
 #include "asterisk/file.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/utils.h"
-#include "asterisk/stasis.h"
 
 struct ast_flags64;
 
@@ -44,7 +42,7 @@ AST_THREADSTORAGE_EXTERNAL(ast_str_thread_global_buf);
 /*! \brief Callback function for IVR
     \return returns 0 on completion, -1 on hangup or digit if interrupted
   */
-typedef int (ast_ivr_callback)(struct ast_channel *chan, char *option, void *cbdata);
+typedef int (*ast_ivr_callback)(struct ast_channel *chan, char *option, void *cbdata);
 
 typedef enum {
 	AST_ACTION_UPONE,	/*!< adata is unused */
@@ -82,7 +80,7 @@ struct ast_ivr_menu {
 	unsigned int flags;	/*!< Flags */
 	struct ast_ivr_option *options;	/*!< All options */
 };
-
+ 
 /*!
  * \brief Structure used for ast_copy_recording_to_vm in order to cleanly supply
  * data needed for making the recording from the recorded file.
@@ -324,336 +322,69 @@ struct ast_vm_mailbox_snapshot {
 /*!
  * \brief Voicemail playback callback function definition
  *
- * \param chan Channel to play the file back on.
- * \param playfile Location of file on disk
+ * \param channel to play the file back on.
+ * \param location of file on disk
  * \param duration of file in seconds. This will be zero if msg is very short or
  * has an unknown duration.
  */
 typedef void (ast_vm_msg_play_cb)(struct ast_channel *chan, const char *playfile, int duration);
 
 /*!
- * \brief Determines if the given folder has messages.
- *
- * \param mailboxes Comma or & delimited list of mailboxes (user at context).
- *          If no context is found, uses 'default' for the context.
- * \param folder The folder to look in.  Default is INBOX if not provided.
- *
- * \retval 1 if the folder has one or more messages.
- * \retval 0 otherwise.
- */
-typedef int (ast_has_voicemail_fn)(const char *mailboxes, const char *folder);
-
-/*!
- * \brief Gets the number of messages that exist for the mailbox list.
- *
- * \param mailboxes Comma or space delimited list of mailboxes (user at context).
- *          If no context is found, uses 'default' for the context.
- * \param newmsgs Where to put the count of new messages. (Can be NULL)
- * \param oldmsgs Where to put the count of old messages. (Can be NULL)
- *
- * \details
- * Simultaneously determines the count of new + urgent and old
- * messages.  The total messages would then be the sum of these.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-typedef int (ast_inboxcount_fn)(const char *mailboxes, int *newmsgs, int *oldmsgs);
-
-/*!
- * \brief Gets the number of messages that exist for the mailbox list.
- *
- * \param mailboxes Comma or space delimited list of mailboxes (user at context).
- *          If no context is found, uses 'default' for the context.
- * \param urgentmsgs Where to put the count of urgent messages. (Can be NULL)
- * \param newmsgs Where to put the count of new messages. (Can be NULL)
- * \param oldmsgs Where to put the count of old messages. (Can be NULL)
- *
- * \details
- * Simultaneously determines the count of new, old, and urgent
- * messages.  The total messages would then be the sum of these
- * three.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-typedef int (ast_inboxcount2_fn)(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs);
-
-/*!
- * \brief Gets the number of messages that exist in a mailbox folder.
- *
- * \param mailbox_id The mailbox name.
- * \param folder The folder to look in.  Default is INBOX if not provided.
- *
- * \note If requesting INBOX then the returned count is INBOX + Urgent.
- *
- * \return The number of messages in the mailbox folder (zero or more).
- */
-typedef int (ast_messagecount_fn)(const char *mailbox_id, const char *folder);
-
-/*!
- * \brief Play a recorded user name for the mailbox to the specified channel.
- *
- * \param chan Where to play the recorded name file.
- * \param mailbox_id The mailbox name.
- *
- * \retval 0 Name played without interruption
- * \retval dtmf ASCII value of the DTMF which interrupted playback.
- * \retval -1 Unable to locate mailbox or hangup occurred.
- */
-typedef int (ast_sayname_fn)(struct ast_channel *chan, const char *mailbox_id);
-
-/*!
- * \brief Creates a voicemail based on a specified file to a mailbox.
- *
- * \param vm_rec_data A record containing filename and voicemail txt info.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-typedef int (ast_copy_recording_to_vm_fn)(struct ast_vm_recording_data *vm_rec_data);
-
-/*!
- * \brief Convert the mailbox folder id to a folder name.
- *
- * \param id Mailbox folder id to convert.
- *
- * \deprecated Nothing calls it and nothing ever should.
- *
- * \return The folder name associated with the id.
- */
-typedef const char *(ast_vm_index_to_foldername_fn)(int id);
-
-/*!
- * \brief Create a snapshot of a mailbox which contains information about every msg.
- *
- * \param user The user part of user at context.
- * \param context The context part of user at context.  Must be explicit.
- * \param folder When not NULL only msgs from the specified folder will be included.
- * \param descending list the msgs in descending order rather than ascending order.
- * \param sort_val What to sort in the snapshot.
- * \param combine_INBOX_and_OLD When this argument is set, The OLD folder will be represented
- *        in the INBOX folder of the snapshot. This allows the snapshot to represent the
- *        OLD and INBOX messages in sorted order merged together.
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval snapshot on success
- * \retval NULL on failure
- */
-typedef struct ast_vm_mailbox_snapshot *(ast_vm_mailbox_snapshot_create_fn)(const char *user,
-	const char *context, const char *folder, int descending,
-	enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
-
-/*!
- * \brief destroy a snapshot
- *
- * \param mailbox_snapshot The snapshot to destroy.
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval NULL
- */
-typedef struct ast_vm_mailbox_snapshot *(ast_vm_mailbox_snapshot_destroy_fn)(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
-
-/*!
- * \brief Move messages from one folder to another
- *
- * \param mailbox The mailbox to which the folders belong
- * \param context The voicemail context for the mailbox
- * \param num_msgs The number of messages to move
- * \param oldfolder The folder from where messages should be moved
- * \param old_msg_ids The message IDs of the messages to move
- * \param newfolder The folder to which messages should be moved
- *    new folder. This array must be num_msgs sized.
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval -1 Failure
- * \retval 0 Success
- */
-typedef int (ast_vm_msg_move_fn)(const char *mailbox, const char *context, size_t num_msgs,
-	const char *oldfolder, const char *old_msg_ids[], const char *newfolder);
-
-/*!
- * \brief Remove/delete messages from a mailbox folder.
- *
- * \param mailbox The mailbox from which to delete messages
- * \param context The voicemail context for the mailbox
- * \param num_msgs The number of messages to delete
- * \param folder The folder from which to remove messages
- * \param msgs The message IDs of the messages to delete
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval -1 Failure
- * \retval 0 Success
- */
-typedef int (ast_vm_msg_remove_fn)(const char *mailbox, const char *context, size_t num_msgs,
-	const char *folder, const char *msgs[]);
-
-/*!
- * \brief forward a message from one mailbox to another.
- *
- * \brief from_mailbox The original mailbox the message is being forwarded from
- * \brief from_context The voicemail context of the from_mailbox
- * \brief from_folder The folder from which the message is being forwarded
- * \brief to_mailbox The mailbox to forward the message to
- * \brief to_context The voicemail context of the to_mailbox
- * \brief to_folder The folder to which the message is being forwarded
- * \brief num_msgs The number of messages being forwarded
- * \brief msg_ids The message IDs of the messages in from_mailbox to forward
- * \brief delete_old If non-zero, the forwarded messages are also deleted from from_mailbox.
- * Otherwise, the messages will remain in the from_mailbox.
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval -1 Failure
- * \retval 0 Success
- */
-typedef int (ast_vm_msg_forward_fn)(const char *from_mailbox, const char *from_context,
-	const char *from_folder, const char *to_mailbox, const char *to_context,
-	const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old);
-
-/*!
- * \brief Play a voicemail msg back on a channel.
- *
- * \param chan
- * \param mailbox msg is in.
- * \param context of mailbox.
- * \param folder voicemail folder to look in.
- * \param msg_num message number in the voicemailbox to playback to the channel.
- * \param cb
- *
- * \note Only used by voicemail unit tests.
- *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef int (ast_vm_msg_play_fn)(struct ast_channel *chan, const char *mailbox,
-	const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb *cb);
-
-#define VM_MODULE_VERSION 2
-
-/*! \brief Voicemail function table definition. */
-struct ast_vm_functions {
-	/*!
-	 * \brief The version of this function table.
-	 *
-	 * \note If the ABI for this table changes, the module version
-	 * (\ref VM_MODULE_VERSION) should be incremented.
-	 */
-	unsigned int module_version;
-	/*! \brief The name of the module that provides the voicemail functionality */
-	const char *module_name;
-	/*! \brief The module for the voicemail provider */
-	struct ast_module *module;
-
-	ast_has_voicemail_fn *has_voicemail;
-	ast_inboxcount_fn *inboxcount;
-	ast_inboxcount2_fn *inboxcount2;
-	ast_messagecount_fn *messagecount;
-	ast_copy_recording_to_vm_fn *copy_recording_to_vm;
-	ast_vm_index_to_foldername_fn *index_to_foldername;
-	ast_vm_mailbox_snapshot_create_fn *mailbox_snapshot_create;
-	ast_vm_mailbox_snapshot_destroy_fn *mailbox_snapshot_destroy;
-	ast_vm_msg_move_fn *msg_move;
-	ast_vm_msg_remove_fn *msg_remove;
-	ast_vm_msg_forward_fn *msg_forward;
-	ast_vm_msg_play_fn *msg_play;
-};
-
-/*!
- * \brief Determine if a voicemail provider is registered.
- * \since 12.0.0
- *
- * \retval 0 if no provider registered.
- * \retval 1 if a provider is registered.
- */
-int ast_vm_is_registered(void);
-
-/*!
  * \brief Set voicemail function callbacks
- *
- * \param vm_table Voicemail function table to install.
- * \param module Pointer to the module implementing the interface
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module *module);
-
-/*! \brief See \ref __ast_vm_register() */
-#define ast_vm_register(vm_table) __ast_vm_register(vm_table, ast_module_info ? ast_module_info->self : NULL)
-
-/*!
- * \brief Unregister the specified voicemail provider
- *
- * \param The module name of the provider to unregister
- *
- * \return Nothing
- */
-void ast_vm_unregister(const char *module_name);
-
-#define VM_GREETER_MODULE_VERSION 1
-
-/*! \brief Voicemail greeter function table definition. */
-struct ast_vm_greeter_functions {
-	/*!
-	 * \brief The version of this function table.
-	 *
-	 * \note If the ABI for this table changes, the module version
-	 * (\ref VM_GREETER_MODULE_VERSION) should be incremented.
-	 */
-	unsigned int module_version;
-	/*! \brief The name of the module that provides the voicemail greeter functionality */
-	const char *module_name;
-	/*! \brief The module for the voicemail greeter provider */
-	struct ast_module *module;
-
-	ast_sayname_fn *sayname;
-};
-
-/*!
- * \brief Determine if a voicemail greeter provider is registered.
- * \since 13.0.0
- *
- * \retval 0 if no provider registered.
- * \retval 1 if a provider is registered.
- */
-int ast_vm_greeter_is_registered(void);
-
-/*!
- * \brief Set voicemail greeter function callbacks
- * \since 13.0.0
- *
- * \param vm_table Voicemail greeter function table to install.
- * \param module Pointer to the module implementing the interface
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module);
-
-/*! \brief See \ref __ast_vm_greeter_register() */
-#define ast_vm_greeter_register(vm_table) __ast_vm_greeter_register(vm_table, ast_module_info ? ast_module_info->self : NULL)
-
-/*!
- * \brief Unregister the specified voicemail greeter provider
- * \since 13.0.0
- *
- * \param The module name of the provider to unregister
- *
- * \return Nothing
- */
-void ast_vm_greeter_unregister(const char *module_name);
+ * \param[in] has_voicemail_func set function pointer
+ * \param[in] inboxcount_func set function pointer
+ * \param[in] inboxcount2_func set function pointer
+ * \param[in] messagecount_func set function pointer
+ * \param[in] sayname_func set function pointer
+ * \version 1.6.1 Added inboxcount2_func, sayname_func
+ */
+void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
+			      int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
+			      int (*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs),
+			      int (*messagecount_func)(const char *context, const char *mailbox, const char *folder),
+			      int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context),
+			      int (*copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data),
+			      const char *vm_index_to_foldername(int id),
+			      struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_create)(const char *mailbox,
+				const char *context,
+				const char *folder,
+				int descending,
+				enum ast_vm_snapshot_sort_val sort_val,
+				int combine_INBOX_and_OLD),
+			      struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_destroy)(struct ast_vm_mailbox_snapshot *mailbox_snapshot),
+			      int (*vm_msg_move)(const char *mailbox,
+				const char *context,
+				size_t num_msgs,
+				const char *oldfolder,
+				const char *old_msg_ids[],
+				const char *newfolder),
+			      int (*vm_msg_remove)(const char *mailbox,
+				const char *context,
+				size_t num_msgs,
+				const char *folder,
+				const char *msgs[]),
+			      int (*vm_msg_forward)(const char *from_mailbox,
+				const char *from_context,
+				const char *from_folder,
+				const char *to_mailbox,
+				const char *to_context,
+				const char *to_folder,
+				size_t num_msgs,
+				const char *msg_ids[],
+				int delete_old),
+			      int (*vm_msg_play)(struct ast_channel *chan,
+				const char *mailbox,
+				const char *context,
+				const char *folder,
+				const char *msg_num,
+				ast_vm_msg_play_cb cb));
+
+
+void ast_uninstall_vm_functions(void);
 
 #ifdef TEST_FRAMEWORK
-typedef int (ast_vm_test_create_user_fn)(const char *context, const char *user);
-typedef int (ast_vm_test_destroy_user_fn)(const char *context, const char *user);
-
-void ast_install_vm_test_functions(ast_vm_test_create_user_fn *vm_test_create_user_func,
-	ast_vm_test_destroy_user_fn *vm_test_destroy_user_func);
+void ast_install_vm_test_functions(int (*vm_test_destroy_user)(const char *context, const char *mailbox),
+				   int (*vm_test_create_user)(const char *context, const char *mailbox));
 
 void ast_uninstall_vm_test_functions(void);
 #endif
@@ -675,56 +406,51 @@ int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data);
  * \retval -1 Failure
  * \since 1.0
  */
-int ast_app_has_voicemail(const char *mailboxes, const char *folder);
+int ast_app_has_voicemail(const char *mailbox, const char *folder);
 
 /*!
  * \brief Determine number of new/old messages in a mailbox
  * \since 1.0
- * \param[in] mailboxes Mailbox specification in the format
- * 	/code
- *	 mbox[\@context][&mbox2[\@context2]][...]
- *	/code
+ * \param[in] mailbox Mailbox specification in the format mbox[@context][&mbox2[@context2]][...]
  * \param[out] newmsgs Number of messages in the "INBOX" folder.  Includes number of messages in the "Urgent" folder, if any.
  * \param[out] oldmsgs Number of messages in the "Old" folder.
  * \retval 0 Success
  * \retval -1 Failure
  */
-int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs);
+int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs);
 
 /*!
  * \brief Determine number of urgent/new/old messages in a mailbox
- * \param[in] mailboxes the mailbox context to use
+ * \param[in] mailbox the mailbox context to use
  * \param[out] urgentmsgs the urgent message count
  * \param[out] newmsgs the new message count
  * \param[out] oldmsgs the old message count
  * \return Returns 0 for success, negative upon error
  * \since 1.6.1
  */
-int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs);
+int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs);
 
 /*!
- * \brief Play a recorded user name for the mailbox to the specified channel.
- *
- * \param chan Where to play the recorded name file.
- * \param mailbox_id The mailbox name.
- *
+ * \brief Given a mailbox and context, play that mailbox owner's name to the channel specified
+ * \param[in] chan Channel on which to play the name
+ * \param[in] mailbox Mailbox number from which to retrieve the recording
+ * \param[in] context Mailbox context from which to locate the mailbox number
  * \retval 0 Name played without interruption
  * \retval dtmf ASCII value of the DTMF which interrupted playback.
  * \retval -1 Unable to locate mailbox or hangup occurred.
+ * \since 1.6.1
  */
-int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id);
+int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context);
 
 /*!
- * \brief Get the number of messages in a given mailbox folder
- *
- * \param[in] mailbox_id Mailbox name
- * \param[in] folder The folder to look in.  Default is INBOX if not provided.
- *
- * \note If requesting INBOX then the returned count is INBOX + Urgent.
- *
- * \return The number of messages in the mailbox folder (zero or more).
+ * \brief Check number of messages in a given context, mailbox, and folder
+ * \since 1.4
+ * \param[in] context Mailbox context
+ * \param[in] mailbox Mailbox number
+ * \param[in] folder Mailbox folder
+ * \return Number of messages in the given context, mailbox, and folder.  If folder is NULL, folder "INBOX" is assumed.  If folder is "INBOX", includes number of messages in the "Urgent" folder.
  */
-int ast_app_messagecount(const char *mailbox_id, const char *folder);
+int ast_app_messagecount(const char *context, const char *mailbox, const char *folder);
 
 /*!
  * \brief Return name of folder, given an id
@@ -733,13 +459,13 @@ int ast_app_messagecount(const char *mailbox_id, const char *folder);
  */
 const char *ast_vm_index_to_foldername(int id);
 
-/*!
+/*
  * \brief Create a snapshot of a mailbox which contains information about every msg.
  *
  * \param mailbox, the mailbox to look for
  * \param context, the context to look for the mailbox in
  * \param folder, OPTIONAL.  When not NULL only msgs from the specified folder will be included.
- * \param descending, list the msgs in descending order rather than ascending order.
+ * \param desending, list the msgs in descending order rather than ascending order.
  * \param combine_INBOX_and_OLD, When this argument is set, The OLD folder will be represented
  *        in the INBOX folder of the snapshot. This allows the snapshot to represent the
  *        OLD and INBOX messages in sorted order merged together.
@@ -754,7 +480,7 @@ struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailb
 	enum ast_vm_snapshot_sort_val sort_val,
 	int combine_INBOX_and_OLD);
 
-/*!
+/*
  * \brief destroy a snapshot
  *
  * \param mailbox_snapshot The snapshot to destroy.
@@ -769,7 +495,7 @@ struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_destroy(struct ast_vm_ma
  * \param context The voicemail context for the mailbox
  * \param num_msgs The number of messages to move
  * \param oldfolder The folder from where messages should be moved
- * \param old_msg_ids The message IDs of the messages to move
+ * \param old_msg_nums The message IDs of the messages to move
  * \param newfolder The folder to which messages should be moved
  * new folder. This array must be num_msgs sized.
  *
@@ -831,12 +557,10 @@ int ast_vm_msg_forward(const char *from_mailbox,
 /*!
  * \brief Play a voicemail msg back on a channel.
  *
- * \param chan
  * \param mailbox msg is in.
  * \param context of mailbox.
- * \param folder voicemail folder to look in.
- * \param msg_num message number in the voicemailbox to playback to the channel.
- * \param cb
+ * \param voicemail folder to look in.
+ * \param message number in the voicemailbox to playback to the channel.
  *
  * \retval 0 success
  * \retval -1 failure
@@ -846,7 +570,7 @@ int ast_vm_msg_play(struct ast_channel *chan,
 	const char *context,
 	const char *folder,
 	const char *msg_num,
-	ast_vm_msg_play_cb *cb);
+	ast_vm_msg_play_cb cb);
 
 #ifdef TEST_FRAMEWORK
 int ast_vm_test_destroy_user(const char *context, const char *mailbox);
@@ -903,47 +627,23 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
 
 /*!
  * \brief Stream a file with fast forward, pause, reverse, restart.
- * \param chan Channel
- * \param file File to play.
- * \param fwd, rev, stop, pause, restart DTMF keys for media control
- * \param skipms Number of milliseconds to skip for fwd/rev.
- * \param offsetms Number of milliseconds to skip when starting the media.
+ * \param chan
+ * \param file filename
+ * \param fwd, rev, stop, pause, restart, skipms, offsetms
  *
  * Before calling this function, set this to be the number
  * of ms to start from the beginning of the file.  When the function
  * returns, it will be the number of ms from the beginning where the
  * playback stopped.  Pass NULL if you don't care.
- *
- * \retval 0 on success
- * \retval Non-zero on failure
  */
 int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms);
 
 /*!
- * \brief Version of ast_control_streamfile() which allows the language of the
- * media file to be specified.
- *
- * \retval 0 on success
- * \retval Non-zero on failure
- */
-int ast_control_streamfile_lang(struct ast_channel *chan, const char *file,
-	const char *fwd, const char *rev, const char *stop, const char *suspend,
-	const char *restart, int skipms, const char *lang, long *offsetms);
-
-/*!
- * \brief Controls playback of a tone
- *
- * \retval 0 on success
- * \retval Non-zero on failure
- */
-int ast_control_tone(struct ast_channel *chan, const char *tone);
-
-/*!
  * \brief Stream a file with fast forward, pause, reverse, restart.
  * \param chan
  * \param file filename
  * \param fwd, rev, stop, pause, restart, skipms, offsetms
- * \param cb waitstream callback to invoke when fastforward or rewind occurrs.
+ * \param waitstream callback to invoke when fastforward or rewind occurrs.
  *
  * Before calling this function, set this to be the number
  * of ms to start from the beginning of the file.  When the function
@@ -965,45 +665,28 @@ int ast_control_streamfile_w_cb(struct ast_channel *chan,
 int ast_play_and_wait(struct ast_channel *chan, const char *fn);
 
 /*!
- * Possible actions to take if a recording already exists
- * \since 12
- */
-enum ast_record_if_exists {
-	/*! Fail the recording. */
-	AST_RECORD_IF_EXISTS_FAIL,
-	/*! Overwrite the existing recording. */
-	AST_RECORD_IF_EXISTS_OVERWRITE,
-	/*! Append to the existing recording. */
-	AST_RECORD_IF_EXISTS_APPEND,
-};
-
-/*!
  * \brief Record a file based on input from a channel
- *        This function will play "auth-thankyou" upon successful recording if
- *        skip_confirmation_sound is false.
+ *        This function will play "auth-thankyou" upon successful recording.
  *
  * \param chan the channel being recorded
- * \param playfile Filename of sound to play before recording begins. A beep is also played when playfile completes, before the recording begins.
+ * \param playfile Filename of sound to play before recording begins
  * \param recordfile Filename to save the recording
  * \param maxtime_sec Longest possible message length in seconds
  * \param fmt string containing all formats to be recorded delimited by '|'
  * \param duration pointer to integer for storing length of the recording
- * \param beep If true, play a beep before recording begins (and doesn't play \a playfile)
  * \param sound_duration pointer to integer for storing length of the recording minus all silence
  * \param silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default
  * \param maxsilence_ms Length of time in milliseconds which will trigger a timeout from silence, -1 for default
  * \param path Optional filesystem path to unlock
  * \param acceptdtmf Character of DTMF to end and accept the recording
  * \param canceldtmf Character of DTMF to end and cancel the recording
- * \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
- * \param if_exists Action to take if recording already exists.
  *
  * \retval -1 failure or hangup
  * \retval 'S' Recording ended from silence timeout
  * \retval 't' Recording ended from the message exceeding the maximum duration
  * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
  */
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists);
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf);
 
 /*!
  * \brief Record a file based on input from a channel. Use default accept and cancel DTMF.
@@ -1053,7 +736,7 @@ enum ast_getdata_result {
 	AST_GETDATA_COMPLETE = 0,
 	AST_GETDATA_TIMEOUT = 1,
 	AST_GETDATA_INTERRUPTED = 2,
-	/*! indicates a user terminated empty string rather than an empty string resulting
+	/*! indicates a user terminated empty string rather than an empty string resulting 
 	 * from a timeout or other factors */
 	AST_GETDATA_EMPTY_END_TERMINATED = 3,
 };
@@ -1344,8 +1027,7 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
 /*! \brief Allow to record message and have a review option */
 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path);
 
-/*!
- * \brief Decode an encoded control or extended ASCII character
+/*!\brief Decode an encoded control or extended ASCII character 
  * \param[in] stream String to decode
  * \param[out] result Decoded character
  * \param[out] consumed Number of characters used in stream to encode the character
@@ -1354,8 +1036,7 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
  */
 int ast_get_encoded_char(const char *stream, char *result, size_t *consumed);
 
-/*!
- * \brief Decode a stream of encoded control or extended ASCII characters
+/*!\brief Decode a stream of encoded control or extended ASCII characters
  * \param[in] stream Encoded string
  * \param[out] result Decoded string
  * \param[in] result_len Maximum size of the result buffer
@@ -1397,227 +1078,6 @@ void ast_safe_fork_cleanup(void);
  */
 int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit);
 
-/*!
- * \since 12
- * \brief Publish a MWI state update via stasis
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- * \param[in] new_msgs The number of new messages in this mailbox
- * \param[in] old_msgs The number of old messages in this mailbox
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \
-	ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL)
-
-/*!
- * \since 12
- * \brief Publish a MWI state update associated with some channel
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- * \param[in] new_msgs The number of new messages in this mailbox
- * \param[in] old_msgs The number of old messages in this mailbox
- * \param[in] channel_id A unique identifier for a channel associated with this
- * change in mailbox state
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \
-	ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL)
-
-/*!
- * \since 12
- * \brief Publish a MWI state update via stasis with all parameters
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- * \param[in] new_msgs The number of new messages in this mailbox
- * \param[in] old_msgs The number of old messages in this mailbox
- * \param[in] channel_id A unique identifier for a channel associated with this
- * change in mailbox state
- * \param[in] eid The EID of the server that originally published the message
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_publish_mwi_state_full(
-	const char *mailbox,
-	const char *context,
-	int new_msgs,
-	int old_msgs,
-	const char *channel_id,
-	struct ast_eid *eid);
-
-/*!
- * \since 12.2.0
- * \brief Delete MWI state cached by stasis
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-#define ast_delete_mwi_state(mailbox, context) \
-	ast_delete_mwi_state_full(mailbox, context, NULL)
-
-/*!
- * \since 12.2.0
- * \brief Delete MWI state cached by stasis with all parameters
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- * \param[in] eid The EID of the server that originally published the message
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid);
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief The structure that contains MWI state
- * \since 12
- */
-struct ast_mwi_state {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(uniqueid);  /*!< Unique identifier for this mailbox */
-	);
-	int new_msgs;                    /*!< The current number of new messages for this mailbox */
-	int old_msgs;                    /*!< The current number of old messages for this mailbox */
-	/*! If applicable, a snapshot of the channel that caused this MWI change */
-	struct ast_channel_snapshot *snapshot;
-	struct ast_eid eid;              /*!< The EID of the server where this message originated */
-};
-
-/*!
- * \brief Object that represents an MWI update with some additional application
- * defined data
- */
-struct ast_mwi_blob {
-	struct ast_mwi_state *mwi_state;    /*!< MWI state */
-	struct ast_json *blob;              /*!< JSON blob of data */
-};
-
-/*!
- * \since 12
- * \brief Create a \ref ast_mwi_state object
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- *
- * \retval \ref ast_mwi_state object on success
- * \retval NULL on error
- */
-struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context);
-
-/*!
- * \since 12
- * \brief Creates a \ref ast_mwi_blob message.
- *
- * The \a blob JSON object requires a \c "type" field describing the blob. It
- * should also be treated as immutable and not modified after it is put into the
- * message.
- *
- * \param mwi_state MWI state associated with the update
- * \param message_type The type of message to create
- * \param blob JSON object representing the data.
- * \return \ref ast_mwi_blob message.
- * \return \c NULL on error
- */
-struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state,
-					   struct stasis_message_type *message_type,
-					   struct ast_json *blob);
-
-/*!
- * \brief Get the \ref stasis topic for MWI messages
- * \retval The topic structure for MWI messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_topic *ast_mwi_topic_all(void);
-
-/*!
- * \brief Get the \ref stasis topic for MWI messages on a unique ID
- * \param uniqueid The unique id for which to get the topic
- * \retval The topic structure for MWI messages for a given uniqueid
- * \retval NULL if it failed to be found or allocated
- * \since 12
- */
-struct stasis_topic *ast_mwi_topic(const char *uniqueid);
-
-/*!
- * \brief Get the \ref stasis caching topic for MWI messages
- * \retval The caching topic structure for MWI messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_topic *ast_mwi_topic_cached(void);
-
-/*!
- * \brief Backend cache for ast_mwi_topic_cached().
- * \retval Cache of \ref ast_mwi_state.
- */
-struct stasis_cache *ast_mwi_state_cache(void);
-
-/*!
- * \brief Get the \ref stasis message type for MWI messages
- * \retval The message type structure for MWI messages
- * \retval NULL on error
- * \since 12
- */
-struct stasis_message_type *ast_mwi_state_type(void);
-
-/*!
- * \brief Get the \ref stasis message type for voicemail application specific messages
- *
- * This message type exists for those messages a voicemail application may wish to send
- * that have no logical relationship with other voicemail applications. Voicemail apps
- * that use this message type must pass a \ref ast_mwi_blob. Any extraneous information
- * in the JSON blob must be packed as key/value pair tuples of strings.
- *
- * At least one key/value tuple must have a key value of "Event".
- *
- * \retval The \ref stasis_message_type for voicemail application specific messages
- * \retval NULL on error
- * \since 12
- */
-struct stasis_message_type *ast_mwi_vm_app_type(void);
-
-/*!
- * \brief Get the \ref stasis topic for queue messages
- * \retval The topic structure for queue messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_topic *ast_queue_topic_all(void);
-
-/*!
- * \brief Get the \ref stasis topic for queue messages for a particular queue name
- * \param queuename The name for which to get the topic
- * \retval The topic structure for queue messages for a given name
- * \retval NULL if it failed to be found or allocated
- * \since 12
- */
-struct stasis_topic *ast_queue_topic(const char *queuename);
-/*! @} */
-
-/*!
- * \brief Initialize the application core
- * \retval 0 Success
- * \retval -1 Failure
- * \since 12
- */
-int app_init(void);
-
-#define AST_MAX_MAILBOX_UNIQUEID (AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2)
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h
deleted file mode 100644
index 00769ee..0000000
--- a/include/asterisk/ari.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_ARI_H
-#define _ASTERISK_ARI_H
-
-/*! \file
- *
- * \brief Asterisk RESTful API hooks.
- *
- * This header file is used mostly as glue code between generated declarations
- * and res_ari.c.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk/http.h"
-#include "asterisk/json.h"
-
-/* Forward-declare websocket structs. This avoids including http_websocket.h,
- * which causes optional_api stuff to happen, which makes optional_api more
- * difficult to debug. */
-
-struct ast_websocket_server;
-
-struct ast_websocket;
-
-/*!
- * \brief Configured encoding format for JSON output.
- * \return JSON output encoding (compact, pretty, etc.)
- */
-enum ast_json_encoding_format ast_ari_json_format(void);
-
-struct ast_ari_response;
-
-/*!
- * \brief Callback type for RESTful method handlers.
- * \param ser TCP/TLS session object
- * \param get_params GET parameters from the HTTP request.
- * \param path_vars Path variables from any wildcard path segments.
- * \param headers HTTP headers from the HTTP requiest.
- * \param[out] response The RESTful response.
- */
-typedef void (*stasis_rest_callback)(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response);
-
-/*!
- * \brief Handler for a single RESTful path segment.
- */
-struct stasis_rest_handlers {
-	/*! Path segement to handle */
-	const char *path_segment;
-	/*! If true (non-zero), path_segment is a wildcard, and will match all
-	 * values.
-	 *
-	 * Value of the segement will be passed into the \a path_vars parameter
-	 * of the callback.
-	 */
-	int is_wildcard;
-	/*! Callbacks for all handled HTTP methods. */
-	stasis_rest_callback callbacks[AST_HTTP_MAX_METHOD];
-	/*! WebSocket server for handling WebSocket upgrades. */
-	struct ast_websocket_server *ws_server;
-	/*! Number of children in the children array */
-	size_t num_children;
-	/*! Handlers for sub-paths */
-	struct stasis_rest_handlers *children[];
-};
-
-/*!
- * Response type for RESTful requests
- */
-struct ast_ari_response {
-	/*! Response message */
-	struct ast_json *message;
-	/*! \r\n seperated response headers */
-	struct ast_str *headers;
-	/*! HTTP response code.
-	 * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html */
-	int response_code;
-	/*! Corresponding text for the response code */
-	const char *response_text; /* Shouldn't http.c handle this? */
-	/*! Flag to indicate that no further response is needed */
-	int no_response:1;
-};
-
-/*!
- * Add a resource for REST handling.
- * \param handler Handler to add.
- * \return 0 on success.
- * \return non-zero on failure.
- */
-int ast_ari_add_handler(struct stasis_rest_handlers *handler);
-
-/*!
- * Remove a resource for REST handling.
- * \param handler Handler to add.
- * \return 0 on success.
- * \return non-zero on failure.
- */
-int ast_ari_remove_handler(struct stasis_rest_handlers *handler);
-
-/*!
- * \internal
- * \brief Stasis RESTful invocation handler.
- *
- * Only call from res_ari and test_ari. Only public to allow
- * for unit testing.
- *
- * \param ser TCP/TLS connection.
- * \param uri HTTP URI, relative to the API path.
- * \param method HTTP method.
- * \param get_params HTTP \c GET parameters.
- * \param headers HTTP headers.
- * \param[out] response RESTful HTTP response.
- */
-void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
-	const char *uri, enum ast_http_method method,
-	struct ast_variable *get_params, struct ast_variable *headers,
-	struct ast_ari_response *response);
-
-/*!
- * \internal
- * \brief Service function for API declarations.
- *
- * Only call from res_ari and test_ari. Only public to allow
- * for unit testing.
- *
- * \param uri Requested URI, relative to the docs path.
- * \param headers HTTP headers.
- * \param[out] response RESTful HTTP response.
- */
-void ast_ari_get_docs(const char *uri, struct ast_variable *headers, struct ast_ari_response *response);
-
-/*! \brief Abstraction for reading/writing JSON to a WebSocket */
-struct ast_ari_websocket_session;
-
-/*!
- * \brief Create an ARI WebSocket session.
- *
- * If \c NULL is given for the validator function, no validation will be
- * performed.
- *
- * \param ws_session Underlying WebSocket session.
- * \param validator Function to validate outgoing messages.
- * \return New ARI WebSocket session.
- * \return \c NULL on error.
- */
-struct ast_ari_websocket_session *ast_ari_websocket_session_create(
-	struct ast_websocket *ws_session, int (*validator)(struct ast_json *));
-
-/*!
- * \brief Read a message from an ARI WebSocket.
- *
- * \param session Session to read from.
- * \return Message received.
- * \return \c NULL if WebSocket could not be read.
- */
-struct ast_json *ast_ari_websocket_session_read(
-	struct ast_ari_websocket_session *session);
-
-/*!
- * \brief Send a message to an ARI WebSocket.
- *
- * \param session Session to write to.
- * \param message Message to send.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
-	struct ast_json *message);
-
-/*!
- * \brief The stock message to return when out of memory.
- *
- * The refcount is NOT bumped on this object, so ast_json_ref() if you want to
- * keep the reference.
- *
- * \return JSON message specifying an out-of-memory error.
- */
-struct ast_json *ast_ari_oom_json(void);
-
-/*!
- * \brief Fill in an error \a ast_ari_response.
- * \param response Response to fill in.
- * \param response_code HTTP response code.
- * \param response_text Text corresponding to the HTTP response code.
- * \param message_fmt Error message format string.
- */
-void ast_ari_response_error(struct ast_ari_response *response,
-				int response_code,
-				const char *response_text,
-				const char *message_fmt, ...)
-__attribute__((format(printf, 4, 5)));
-
-/*!
- * \brief Fill in an \c OK (200) \a ast_ari_response.
- * \param response Response to fill in.
- * \param message JSON response.  This reference is stolen, so just \ref
- *                ast_json_ref if you need to keep a reference to it.
- */
-void ast_ari_response_ok(struct ast_ari_response *response,
-			     struct ast_json *message);
-
-/*!
- * \brief Fill in a <tt>No Content</tt> (204) \a ast_ari_response.
- */
-void ast_ari_response_no_content(struct ast_ari_response *response);
-
-/*!
- * \brief Fill in a <tt>Created</tt> (201) \a ast_ari_response.
- * \param response Response to fill in.
- * \param url URL to the created resource.
- * \param message JSON response.  This reference is stolen, so just \ref
- *                ast_json_ref if you need to keep a reference to it.
- */
-void ast_ari_response_created(struct ast_ari_response *response,
-	const char *url, struct ast_json *message);
-
-/*!
- * \brief Fill in \a response with a 500 message for allocation failures.
- * \param response Response to fill in.
- */
-void ast_ari_response_alloc_failed(struct ast_ari_response *response);
-
-#endif /* _ASTERISK_ARI_H */
diff --git a/include/asterisk/astdb.h b/include/asterisk/astdb.h
index 8a870ae..e27a651 100644
--- a/include/asterisk/astdb.h
+++ b/include/asterisk/astdb.h
@@ -16,8 +16,7 @@
  * at the top of the source tree.
  */
 
-/*!
- * \file
+/*! \file
  * \brief Persistant data storage (akin to *doze registry)
  */
 
@@ -34,13 +33,11 @@ struct ast_db_entry {
 	char data[0];
 };
 
-/*! \brief Get key value specified by family/key */
-int ast_db_get(const char *family, const char *key, char *value, int valuelen);
+/*!\brief Get key value specified by family/key */
+int ast_db_get(const char *family, const char *key, char *out, int outlen);
 
-/*!
- * \brief Get key value specified by family/key as a heap allocated string.
+/*!\brief Get key value specified by family/key as a heap allocated string.
  *
- * \details
  * Given a \a family and \a key, sets \a out to a pointer to a heap
  * allocated string.  In the event of an error, \a out will be set to
  * NULL.  The string must be freed by calling ast_free().
@@ -50,16 +47,13 @@ int ast_db_get(const char *family, const char *key, char *value, int valuelen);
  */
 int ast_db_get_allocated(const char *family, const char *key, char **out);
 
-/*! \brief Store value addressed by family/key */
+/*!\brief Store value addressed by family/key */
 int ast_db_put(const char *family, const char *key, const char *value);
 
-/*! \brief Delete entry in astdb */
+/*!\brief Delete entry in astdb */
 int ast_db_del(const char *family, const char *key);
 
-/*!
- * \brief Delete one or more entries in astdb
- *
- * \details
+/*!\brief Delete one or more entries in astdb
  * If both parameters are NULL, the entire database will be purged.  If
  * only keytree is NULL, all entries within the family will be purged.
  * It is an error for keytree to have a value when family is NULL.
@@ -69,10 +63,7 @@ int ast_db_del(const char *family, const char *key);
  */
 int ast_db_deltree(const char *family, const char *keytree);
 
-/*!
- * \brief Get a list of values within the astdb tree
- *
- * \details
+/*!\brief Get a list of values within the astdb tree
  * If family is specified, only those keys will be returned.  If keytree
  * is specified, subkeys are expected to exist (separated from the key with
  * a slash).  If subkeys do not exist and keytree is specified, the tree will
@@ -83,7 +74,7 @@ int ast_db_deltree(const char *family, const char *keytree);
  */
 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree);
 
-/*! \brief Free structure created by ast_db_gettree() */
+/*!\brief Free structure created by ast_db_gettree() */
 void ast_db_freetree(struct ast_db_entry *entry);
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/include/asterisk/astobj.h b/include/asterisk/astobj.h
index 5959d40..a18d706 100644
--- a/include/asterisk/astobj.h
+++ b/include/asterisk/astobj.h
@@ -16,10 +16,8 @@
  * at the top of the source tree.
  */
 
-/*! \file
- * \brief Object Model for Asterisk
- *
- * \deprecated Use astobj2.h instead
+/*
+ * Object Model for Asterisk
  */
 
 #ifndef _ASTERISK_ASTOBJ_H
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 692cc7c..fe98add 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -394,19 +394,12 @@ murf
 
 
 
-/*!
- * \brief Typedef for an object destructor.
- *
- * \param vdoomed Object to destroy.
- *
- * \details
- * This is called just before freeing the memory for the object.
- * It is passed a pointer to the user-defined data of the
- * object.
- *
- * \return Nothing
+/*! \brief
+ * Typedef for an object destructor. This is called just before freeing
+ * the memory for the object. It is passed a pointer to the user-defined
+ * data of the object.
  */
-typedef void (*ao2_destructor_fn)(void *vdoomed);
+typedef void (*ao2_destructor_fn)(void *);
 
 /*! \brief Options available when allocating an ao2 object. */
 enum ao2_alloc_opts {
@@ -480,8 +473,8 @@ enum ao2_alloc_opts {
 #endif
 
 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
-	const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
-void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options) attribute_warn_unused_result;
+	const char *file, int line, const char *func, int ref_debug);
+void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options);
 
 /*! @} */
 
@@ -521,61 +514,9 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in
 
 #endif
 
-/*!
- * \brief Retrieve the ao2 options used to create the object.
- * \param obj pointer to the (user-defined part) of an object.
- * \return options from enum ao2_alloc_opts.
- */
-unsigned int ao2_options_get(void *obj);
-
-/*!
- * \since 12
- * \brief Bump refcount on an AO2 object by one, returning the object.
- *
- * This is useful for inlining a ref bump, and you don't care about the ref
- * count. Also \c NULL safe, for even more convenience.
- *
- * \param obj AO2 object to bump the refcount on.
- * \retval The given \a obj pointer.
- */
-#define ao2_t_bump(obj, tag)						\
-	({							\
-		typeof(obj) __obj_ ## __LINE__ = (obj);		\
-		if (__obj_ ## __LINE__) {			\
-			ao2_t_ref(__obj_ ## __LINE__, +1, (tag));	\
-		}						\
-		__obj_ ## __LINE__;				\
-	})
-#define ao2_bump(obj) \
-	ao2_t_bump((obj), "")
-
 int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *func);
 int __ao2_ref(void *o, int delta);
 
-/*!
- * \since 12.4.0
- * \brief Replace one object reference with another cleaning up the original.
- *
- * \param dst Pointer to the object that will be cleaned up.
- * \param src Pointer to the object replacing it.
- */
-#define ao2_t_replace(dst, src, tag) \
-	{\
-		typeof(dst) *__dst_ ## __LINE__ = &dst; \
-		typeof(src) __src_ ## __LINE__ = src; \
-		if (__src_ ## __LINE__ != *__dst_ ## __LINE__) { \
-			if (__src_ ## __LINE__) {\
-				ao2_t_ref(__src_ ## __LINE__, +1, (tag)); \
-			} \
-			if (*__dst_ ## __LINE__) {\
-				ao2_t_ref(*__dst_ ## __LINE__, -1, (tag)); \
-			} \
-			*__dst_ ## __LINE__ = __src_ ## __LINE__; \
-		} \
-	}
-#define ao2_replace(dst, src) \
-	ao2_t_replace((dst), (src), "")
-
 /*! @} */
 
 /*! \brief Which lock to request. */
@@ -592,7 +533,6 @@ enum ao2_lock_req {
  * Lock an object.
  *
  * \param a A pointer to the object we want to lock.
- * \param lock_how, file, func, line, var
  * \return 0 on success, other values on error.
  */
 int __ao2_lock(void *a, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var);
@@ -604,7 +544,6 @@ int __ao2_lock(void *a, enum ao2_lock_req lock_how, const char *file, const char
  * Unlock an object.
  *
  * \param a A pointer to the object we want unlock.
- * \param file, func, line, var
  * \return 0 on success, other values on error.
  */
 int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
@@ -614,7 +553,6 @@ int __ao2_unlock(void *a, const char *file, const char *func, int line, const ch
  * Try locking-- (don't block if fail)
  *
  * \param a A pointer to the object we want to lock.
- * \param lock_how, file, func, line, var
  * \return 0 on success, other values on error.
  */
 int __ao2_trylock(void *a, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var);
@@ -743,7 +681,7 @@ void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, co
 	__ao2_global_obj_replace(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 #endif
 
-void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
+void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name);
 
 /*!
  * \brief Replace an ao2 object in the global holder, throwing away any old object.
@@ -801,7 +739,7 @@ int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, con
 	__ao2_global_obj_ref(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 #endif
 
-void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
+void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name);
 
 
 /*!
@@ -833,12 +771,10 @@ Operations on container include:
     OBJ_UNLINK - to remove the object, once found, from the container.
     OBJ_NODATA - don't return the object if found (no ref count change)
     OBJ_MULTIPLE - don't stop at first match
-    OBJ_SEARCH_OBJECT - if set, 'arg' is an object pointer, and a hash table
+    OBJ_POINTER - if set, 'arg' is an object pointer, and a hash table
                   search will be done. If not, a traversal is done.
-    OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
-              Similar to OBJ_SEARCH_OBJECT and mutually exclusive.
-    OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
-              Similar to OBJ_SEARCH_KEY and mutually exclusive.
+    OBJ_KEY - if set, 'arg', is a hashable item that is not an object.
+              Similar to OBJ_POINTER and mutually exclusive.
 
   -  \b ao2_callback(c, flags, fn, arg)
     apply fn(obj, arg) to all objects in the container.
@@ -849,13 +785,11 @@ Operations on container include:
          OBJ_UNLINK   - to remove the object, once found, from the container.
          OBJ_NODATA   - don't return the object if found (no ref count change)
          OBJ_MULTIPLE - don't stop at first match
-         OBJ_SEARCH_OBJECT - if set, 'arg' is an object pointer, and a hash table
+         OBJ_POINTER  - if set, 'arg' is an object pointer, and a hash table
                         search will be done. If not, a traversal is done through
                         all the hash table 'buckets'..
-         OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
-                        Similar to OBJ_SEARCH_OBJECT and mutually exclusive.
-         OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
-                        Similar to OBJ_SEARCH_KEY and mutually exclusive.
+         OBJ_KEY      - if set, 'arg', is a hashable item that is not an object.
+                        Similar to OBJ_POINTER and mutually exclusive.
       - fn is a func that returns int, and takes 3 args:
         (void *obj, void *arg, int flags);
           obj is an object
@@ -912,6 +846,32 @@ to define callback and hash functions and their arguments.
  */
 
 /*! \brief
+ * Type of a generic callback function
+ * \param obj  pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * The return values are a combination of enum _cb_results.
+ * Callback functions are used to search or manipulate objects in a container.
+ */
+typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
+
+/*! \brief
+ * Type of a generic callback function
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param data arbitrary data from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * The return values are a combination of enum _cb_results.
+ * Callback functions are used to search or manipulate objects in a container.
+ */
+typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
+
+/*! \brief A common ao2_callback is one that matches by address. */
+int ao2_match_by_addr(void *obj, void *arg, int flags);
+
+/*! \brief
  * A callback function will return a combination of CMP_MATCH and CMP_STOP.
  * The latter will terminate the search in a container.
  */
@@ -920,8 +880,8 @@ enum _cb_results {
 	CMP_STOP	= 0x2,	/*!< stop the search now */
 };
 
-/*!
- * \brief Flags passed to ao2_callback_fn(), ao2_hash_fn(), and ao2_sort_fn() to modify behaviour.
+/*! \brief
+ * Flags passed to ao2_callback() and ao2_hash_fn() to modify its behaviour.
  */
 enum search_flags {
 	/*!
@@ -940,6 +900,24 @@ enum search_flags {
 	 */
 	OBJ_MULTIPLE = (1 << 2),
 	/*!
+	 * The given obj is an object of the same type as the one being
+	 * searched for, so use the object's hash function for optimized
+	 * searching.
+	 *
+	 * The matching function is unaffected (i.e. The cb_fn argument
+	 * to ao2_callback).
+	 */
+	OBJ_POINTER = (1 << 3),
+	/*!
+	 * \brief Continue if a match is not found in the hashed out bucket
+	 *
+	 * This flag is to be used in combination with OBJ_POINTER.  This tells
+	 * the ao2_callback() core to keep searching through the rest of the
+	 * buckets if a match is not found in the starting bucket defined by
+	 * the hash value on the argument.
+	 */
+	OBJ_CONTINUE = (1 << 4),
+	/*!
 	 * \brief Assume that the ao2_container is already locked.
 	 *
 	 * \note For ao2_containers that have mutexes, no locking will
@@ -952,221 +930,28 @@ enum search_flags {
 	 * \note Only use this flag if the ao2_container is manually
 	 * locked already.
 	 */
-	OBJ_NOLOCK = (1 << 4),
-
-	/*!
-	 * \brief Search option field mask.
-	 *
-	 * \todo Eventually OBJ_SEARCH_MASK will shrink to a two bit
-	 * field when the codebase is made to use the search field
-	 * values as a field instead of independent bits.
-	 */
-	OBJ_SEARCH_MASK = (0x07 << 5),
-	/*! \brief The arg parameter has no meaning to the astobj2 code. */
-	OBJ_SEARCH_NONE = (0 << 5),
-	/*!
-	 * \brief The arg parameter is an object of the same type.
-	 *
-	 * \details
-	 * The arg parameter is an object of the same type as the one
-	 * being searched for, so use the object's ao2_hash_fn and/or
-	 * ao2_sort_fn functions for optimized searching.
-	 *
-	 * \note The supplied ao2_callback_fn is called after the
-	 * container nodes have been filtered by the ao2_hash_fn and/or
-	 * ao2_sort_fn functions.
-	 */
-	OBJ_SEARCH_OBJECT = (1 << 5),
+	OBJ_NOLOCK = (1 << 5),
 	/*!
-	 * \brief The arg parameter is a search key, but is not an object.
+	 * \brief The data is hashable, but is not an object.
 	 *
 	 * \details
 	 * This can be used when you want to be able to pass custom data
-	 * to the container's stored ao2_hash_fn, ao2_sort_fn, and
-	 * ao2_find ao2_callback_fn functions that is not a full object,
-	 * but perhaps just a string.
-	 *
-	 * \note The supplied ao2_callback_fn is called after the
-	 * container nodes have been filtered by the ao2_hash_fn and/or
-	 * ao2_sort_fn functions.
-	 */
-	OBJ_SEARCH_KEY = (2 << 5),
-	/*!
-	 * \brief The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
-	 *
-	 * \details
-	 * The partial key can be used by the ao2_sort_fn to guide the
-	 * search to find a contiguous subset of a sorted container.
-	 * For example, a sorted container holds: "A", "B", "Bert",
-	 * "Beth", "Earnie".  Doing a partial key search with "B" will
-	 * find the sorted subset of all held objects starting with "B".
-	 *
-	 * \note The supplied ao2_callback_fn is called after the
-	 * container nodes have been filtered by the ao2_sort_fn
-	 * function.
-	 */
-	OBJ_SEARCH_PARTIAL_KEY = (4 << 5),
-
-	/*! \brief Traverse order option field mask. */
-	OBJ_ORDER_MASK = (0x03 << 8),
-	/*! \brief Traverse in ascending order (First to last container object) */
-	OBJ_ORDER_ASCENDING = (0 << 8),
-	/*! \brief Traverse in descending order (Last to first container object) */
-	OBJ_ORDER_DESCENDING = (1 << 8),
-	/*!
-	 * \brief Traverse in pre-order (Node then children, for tree container)
-	 *
-	 * \note For non-tree containers, it is up to the container type
-	 * to make the best interpretation of the order.  For list and
-	 * hash containers, this also means ascending order because a
-	 * binary tree can degenerate into a list.
-	 */
-	OBJ_ORDER_PRE = (2 << 8),
-	/*!
-	 * \brief Traverse in post-order (Children then node, for tree container)
-	 *
-	 * \note For non-tree containers, it is up to the container type
-	 * to make the best interpretation of the order.  For list and
-	 * hash containers, this also means descending order because a
-	 * binary tree can degenerate into a list.
-	 */
-	OBJ_ORDER_POST = (3 << 8),
-};
-
-/*
- * Deprecated backward compatible flag names.
- *
- * Note: OBJ_POINTER, OBJ_KEY, and OBJ_PARTIAL_KEY are mutually
- * exclusive.
- */
-#define OBJ_POINTER		OBJ_SEARCH_OBJECT		/*!< Deprecated name */
-#define OBJ_KEY			OBJ_SEARCH_KEY			/*!< Deprecated name */
-#define OBJ_PARTIAL_KEY	OBJ_SEARCH_PARTIAL_KEY	/*!< Deprecated name */
-
-/*!
- * \brief Options available when allocating an ao2 container object.
- *
- * \note Each option is open to some interpretation by the
- * container type as long as it makes sense with the option
- * name.
- */
-enum ao2_container_opts {
-	/*!
-	 * \brief Insert objects at the beginning of the container.
-	 * (Otherwise it is the opposite; insert at the end.)
-	 *
-	 * \note If an ao2_sort_fn is provided, the object is inserted
-	 * before any objects with duplicate keys.
+	 * to the container's stored ao2_hash_fn and ao2_find
+	 * ao2_callback_fn functions that is not a full object, but
+	 * perhaps just a string.
 	 *
-	 * \note Hash containers insert the object in the computed hash
-	 * bucket in the indicated manner.
+	 * \note OBJ_KEY and OBJ_POINTER are mutually exclusive options.
 	 */
-	AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN = (1 << 0),
-
-	/*!
-	 * \brief The ao2 container objects with duplicate keys option field mask.
-	 */
-	AO2_CONTAINER_ALLOC_OPT_DUPS_MASK = (3 << 1),
-	/*!
-	 * \brief Allow objects with duplicate keys in container.
-	 */
-	AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW = (0 << 1),
-	/*!
-	 * \brief Reject objects with duplicate keys in container.
-	 *
-	 * \note The container must be sorted.  i.e. have an
-	 * ao2_sort_fn.
-	 */
-	AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT = (1 << 1),
-	/*!
-	 * \brief Reject duplicate objects in container.
-	 *
-	 * \details Don't link the same object into the container twice.
-	 * However, you can link a different object with the same key.
-	 *
-	 * \note The container must be sorted.  i.e. have an
-	 * ao2_sort_fn.
-	 *
-	 * \note It is assumed that the objects are located where the
-	 * search key says they should be located.
-	 */
-	AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT = (2 << 1),
-	/*!
-	 * \brief Replace objects with duplicate keys in container.
-	 *
-	 * \details The existing duplicate object is removed and the new
-	 * object takes the old object's place.
-	 *
-	 * \note The container must be sorted.  i.e. have an
-	 * ao2_sort_fn.
-	 */
-	AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE = (3 << 1),
+	OBJ_KEY = (1 << 6),
 };
 
 /*!
- * \brief Type of a generic callback function
- * \param obj  pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'arg', is an object.
- *   OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
- *   OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
- *
- * The return values are a combination of enum _cb_results.
- * Callback functions are used to search or manipulate objects in a container.
- */
-typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
-
-/*! \brief A common ao2_callback is one that matches by address. */
-int ao2_match_by_addr(void *obj, void *arg, int flags);
-
-/*!
- * \brief Type of a generic callback function
- * \param obj pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param data arbitrary data from ao2_callback()
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'arg', is an object.
- *   OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
- *   OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
- *
- * The return values are a combination of enum _cb_results.
- * Callback functions are used to search or manipulate objects in a container.
- */
-typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
-
-/*!
  * Type of a generic function to generate a hash value from an object.
- *
- * \param obj pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'obj', is an object.
- *   OBJ_SEARCH_KEY - if set, 'obj', is a search key item that is not an object.
- *
- * \note This function must be idempotent.
- *
- * \return Computed hash value.
+ * flags is ignored at the moment. Eventually, it will include the
+ * value of OBJ_POINTER passed to ao2_callback().
  */
 typedef int (ao2_hash_fn)(const void *obj, int flags);
 
-/*!
- * \brief Type of generic container sort function.
- *
- * \param obj_left pointer to the (user-defined part) of an object.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
- *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- *
- * \note This function must be idempotent.
- *
- * \retval <0 if obj_left < obj_right
- * \retval =0 if obj_left == obj_right
- * \retval >0 if obj_left > obj_right
- */
-typedef int (ao2_sort_fn)(const void *obj_left, const void *obj_right, int flags);
-
 /*! \name Object Containers
  * Here start declarations of containers.
  */
@@ -1189,156 +974,51 @@ struct ao2_container;
  * \return A pointer to a struct container.
  *
  * \note Destructor is set implicitly.
- * \note This is legacy container creation that is mapped to the new method.
  */
 
+#if defined(REF_DEBUG)
+
 #define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
-	ao2_t_container_alloc_hash((options), 0, (n_buckets), (hash_fn), NULL, (cmp_fn), (tag))
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
 #define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
-	ao2_container_alloc_hash((options), 0, (n_buckets), (hash_fn), NULL, (cmp_fn))
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
 
 #define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	ao2_t_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag))
+	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
 #define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
-	ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
-
-/*!
- * \brief Allocate and initialize a hash container with the desired number of buckets.
- *
- * \details
- * We allocate space for a struct astobj_container, struct container
- * and the buckets[] array.
- *
- * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
- * \param container_options Container behaviour options (See enum ao2_container_opts)
- * \param n_buckets Number of buckets for hash
- * \param hash_fn Pointer to a function computing a hash value. (NULL if everyting goes in first bucket.)
- * \param sort_fn Pointer to a sort function. (NULL to not sort the buckets.)
- * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
- * \param tag used for debugging.
- *
- * \return A pointer to a struct container.
- *
- * \note Destructor is set implicitly.
- */
-
-#if defined(REF_DEBUG)
-
-#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
-	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
 
 #elif defined(__AST_DEBUG_MALLOC)
 
-#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
-	__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-
-#else
-
-#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
-#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
-	__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
-
-#endif
-
-struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
-	unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
-struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
-	unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
-
-/*!
- * \brief Allocate and initialize a list container.
- *
- * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
- * \param container_options Container behaviour options (See enum ao2_container_opts)
- * \param sort_fn Pointer to a sort function. (NULL if list not sorted.)
- * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
- * \param tag used for debugging.
- *
- * \return A pointer to a struct container.
- *
- * \note Destructor is set implicitly.
- * \note Implemented as a degenerate hash table.
- */
-
-#if defined(REF_DEBUG)
-
-#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-
-#elif defined(__AST_DEBUG_MALLOC)
+#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
 
-#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
+	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
 
 #else
 
-#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
-#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
-
-#endif
-
-struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
-	unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
-struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
-	unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
-
-/*!
- * \brief Allocate and initialize a red-black tree container.
- *
- * \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
- * \param container_options Container behaviour options (See enum ao2_container_opts)
- * \param sort_fn Pointer to a sort function.
- * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
- * \param tag used for debugging.
- *
- * \return A pointer to a struct container.
- *
- * \note Destructor is set implicitly.
- */
-
-#if defined(REF_DEBUG)
-
-#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-
-#elif defined(__AST_DEBUG_MALLOC)
-
-#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-
-#else
+#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+	__ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
+#define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
 
-#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
-	__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn))
-#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
-	__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn))
+#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
+	__ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
+#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
 
 #endif
 
-struct ao2_container *__ao2_container_alloc_rbtree(unsigned int ao2_options, unsigned int container_options,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
-struct ao2_container *__ao2_container_alloc_rbtree_debug(unsigned int ao2_options, unsigned int container_options,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
+struct ao2_container *__ao2_container_alloc(unsigned int options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
+	const char *tag, const char *file, int line, const char *func, int ref_debug);
 
 /*! \brief
  * Returns the number of elements in a container.
@@ -1378,8 +1058,8 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
  * \retval Clone container on success.
  * \retval NULL on error.
  */
-struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags) attribute_warn_unused_result;
-struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
+struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags);
+struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug);
 #if defined(REF_DEBUG)
 
 #define ao2_t_container_clone(orig, flags, tag)	__ao2_container_clone_debug(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
@@ -1397,93 +1077,6 @@ struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, en
 
 #endif
 
-/*!
- * \brief Print output.
- * \since 12.0.0
- *
- * \param where User data pointer needed to determine where to put output.
- * \param fmt printf type format string.
- *
- * \return Nothing
- */
-typedef void (ao2_prnt_fn)(void *where, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
-/*!
- * \brief Print object key.
- * \since 12.0.0
- *
- * \param v_obj A pointer to the object we want the key printed.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-typedef void (ao2_prnt_obj_fn)(void *v_obj, void *where, ao2_prnt_fn *prnt);
-
-/*!
- * \brief Display contents of the specified container.
- * \since 12.0.0
- *
- * \param self Container to dump.
- * \param flags OBJ_NOLOCK if a lock is already held on the container.
- * \param name Container name.  (NULL if anonymous)
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
- *
- * \return Nothing
- */
-void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj);
-
-/*!
- * \brief Display statistics of the specified container.
- * \since 12.0.0
- *
- * \param self Container to display statistics.
- * \param flags OBJ_NOLOCK if a lock is already held on the container.
- * \param name Container name.  (NULL if anonymous)
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt);
-
-/*!
- * \brief Perform an integrity check on the specified container.
- * \since 12.0.0
- *
- * \param self Container to check integrity.
- * \param flags OBJ_NOLOCK if a lock is already held on the container.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ao2_container_check(struct ao2_container *self, enum search_flags flags);
-
-/*!
- * \brief Register a container for CLI stats and integrity check.
- * \since 12.0.0
- *
- * \param name Name to register the container under.
- * \param self Container to register.
- * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj);
-
-/*!
- * \brief Unregister a container for CLI stats and integrity check.
- * \since 12.0.0
- *
- * \param name Name the container is registered under.
- *
- * \return Nothing
- */
-void ao2_container_unregister(const char *name);
-
 /*@} */
 
 /*! \name Object Management
@@ -1499,10 +1092,11 @@ void ao2_container_unregister(const char *name);
  *
  * \param container The container to operate on.
  * \param obj The object to be added.
+ * \param flags search_flags to control linking the object.  (OBJ_NOLOCK)
  * \param tag used for debugging.
  *
- * \retval 0 on errors.
- * \retval 1 on success.
+ * \retval NULL on errors.
+ * \retval !NULL on success.
  *
  * This function inserts an object in a container according its key.
  *
@@ -1516,24 +1110,6 @@ void ao2_container_unregister(const char *name);
 #define ao2_t_link(container, obj, tag)					__ao2_link_debug((container), (obj), 0, (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define ao2_link(container, obj)						__ao2_link_debug((container), (obj), 0, "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-/*!
- * \brief Add an object to a container.
- *
- * \param container The container to operate on.
- * \param obj The object to be added.
- * \param flags search_flags to control linking the object.  (OBJ_NOLOCK)
- * \param tag used for debugging.
- *
- * \retval 0 on errors.
- * \retval 1 on success.
- *
- * This function inserts an object in a container according its key.
- *
- * \note Remember to set the key before calling this function.
- *
- * \note This function automatically increases the reference count to account
- *       for the reference that the container now holds to the object.
- */
 #define ao2_t_link_flags(container, obj, flags, tag)	__ao2_link_debug((container), (obj), (flags), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define ao2_link_flags(container, obj, flags)			__ao2_link_debug((container), (obj), (flags), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
@@ -1547,14 +1123,15 @@ void ao2_container_unregister(const char *name);
 
 #endif
 
-int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func);
-int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
+void *__ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func);
+void *__ao2_link(struct ao2_container *c, void *obj_new, int flags);
 
 /*!
  * \brief Remove an object from a container
  *
  * \param container The container to operate on.
  * \param obj The object to unlink.
+ * \param flags search_flags to control unlinking the object.  (OBJ_NOLOCK)
  * \param tag used for debugging.
  *
  * \retval NULL, always
@@ -1572,25 +1149,6 @@ int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
 #define ao2_t_unlink(container, obj, tag)				__ao2_unlink_debug((container), (obj), 0, (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define ao2_unlink(container, obj)						__ao2_unlink_debug((container), (obj), 0, "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-/*!
- * \brief Remove an object from a container
- *
- * \param container The container to operate on.
- * \param obj The object to unlink.
- * \param flags search_flags to control unlinking the object.  (OBJ_NOLOCK)
- * \param tag used for debugging.
- *
- * \retval NULL, always
- *
- * \note The object requested to be unlinked must be valid.  However, if it turns
- *       out that it is not in the container, this function is still safe to
- *       be called.
- *
- * \note If the object gets unlinked from the container, the container's
- *       reference to the object will be automatically released. (The
- *       refcount will be decremented).
- */
-
 #define ao2_t_unlink_flags(container, obj, flags, tag)	__ao2_unlink_debug((container), (obj), (flags), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define ao2_unlink_flags(container, obj, flags)			__ao2_unlink_debug((container), (obj), (flags), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
@@ -1621,12 +1179,10 @@ void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
  *   - If OBJ_NODATA is set, ao2_callback will return NULL. No refcounts
  *     of any of the traversed objects will be incremented.
  *     On the converse, if it is NOT set (the default), the ref count
- *     of the first matching object will be incremented and returned.
- *   - If OBJ_MULTIPLE is set, the ref count of all matching objects will
+ *     of the first matching object will be incremented and returned.  If
+ *     OBJ_MULTIPLE is set, the ref count of all matching objects will
  *     be incremented in an iterator for a temporary container and returned.
- *   - If OBJ_SEARCH_OBJECT is set, the traversed items will be restricted
- *     to the objects in the bucket that the object key hashes to.
- *   - If OBJ_SEARCH_KEY is set, the traversed items will be restricted
+ *   - If OBJ_POINTER is set, the traversed items will be restricted
  *     to the objects in the bucket that the object key hashes to.
  * \param cb_fn A function pointer, that will be called on all
  *  objects, to see if they match. This function returns CMP_MATCH
@@ -1683,9 +1239,8 @@ void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
  *                              functions such as find() do
  *      OBJ_MULTIPLE            return multiple matches
  *                              Default is no.
- *      OBJ_SEARCH_OBJECT       the pointer is to an object
- *      OBJ_SEARCH_KEY          the pointer is to a search key
- *      OBJ_SEARCH_PARTIAL_KEY  the pointer is to a partial search key
+ *      OBJ_POINTER             the pointer is an object pointer
+ *      OBJ_KEY                 the pointer is to a hashable key
  *
  * \note When the returned object is no longer in use, ao2_ref() should
  * be used to free the additional reference possibly created by this function.
@@ -1722,9 +1277,9 @@ void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callb
  * allows the caller to pass in arbitrary data.
  *
  * This call would be used instead of ao2_callback() when the caller needs to pass
- * OBJ_SEARCH_OBJECT, OBJ_SEARCH_KEY, or OBJ_SEARCH_PARTIAL_KEY as part of the flags
- * argument (which in turn requires passing in a known pointer type for 'arg') and
- * also needs access to other non-global data to complete it's comparison or task.
+ * OBJ_POINTER as part of the flags argument (which in turn requires passing in a
+ * prototype ao2 object for 'arg') and also needs access to other non-global data
+ * to complete it's comparison or task.
  *
  * See the documentation for ao2_callback() for argument descriptions.
  *
@@ -1782,24 +1337,32 @@ void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags fla
  * ao2_iterator to keep track of the current position.
  *
  * Because the navigation is typically done without holding the
- * lock on the container across the loop, objects can be
- * inserted or deleted or moved while we work.  As a
- * consequence, there is no guarantee that we manage to touch
- * all the elements in the container, and it is possible that we
- * touch the same object multiple times.
- *
- * An iterator must be first initialized with
- * ao2_iterator_init(), then we can use o = ao2_iterator_next()
- * to move from one element to the next.  Remember that the
- * object returned by ao2_iterator_next() has its refcount
- * incremented, and the reference must be explicitly released
- * when done with it.
- *
- * In addition, ao2_iterator_init() will hold a reference to the
- * container being iterated and the last container node found.
- * Thes objects will be unreffed when ao2_iterator_destroy() is
- * called to free up the resources used by the iterator (if
- * any).
+ * lock on the container across the loop, objects can be inserted or deleted
+ * or moved while we work. As a consequence, there is no guarantee that
+ * we manage to touch all the elements in the container, and it is possible
+ * that we touch the same object multiple times.
+ *
+ * However, within the current hash table container, the following is true:
+ *  - It is not possible to miss an object in the container while iterating
+ *    unless it gets added after the iteration begins and is added to a bucket
+ *    that is before the one the current object is in.  In this case, even if
+ *    you locked the container around the entire iteration loop, you still would
+ *    not see this object, because it would still be waiting on the container
+ *    lock so that it can be added.
+ *  - It would be extremely rare to see an object twice.  The only way this can
+ *    happen is if an object got unlinked from the container and added again
+ *    during the same iteration.  Furthermore, when the object gets added back,
+ *    it has to be in the current or later bucket for it to be seen again.
+ *
+ * An iterator must be first initialized with ao2_iterator_init(),
+ * then we can use o = ao2_iterator_next() to move from one
+ * element to the next. Remember that the object returned by
+ * ao2_iterator_next() has its refcount incremented,
+ * and the reference must be explicitly released when done with it.
+ *
+ * In addition, ao2_iterator_init() will hold a reference to the container
+ * being iterated, which will be freed when ao2_iterator_destroy() is called
+ * to free up the resources used by the iterator (if any).
  *
  * Example:
  *
@@ -1816,20 +1379,14 @@ void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags fla
  *     ao2_ref(o, -1);
  *  }
  *
- *  ao2_iterator_restart(&i);
- *  while ((o = ao2_iterator_next(&i))) {
- *     ... do something on o ...
- *     ao2_ref(o, -1);
- *  }
- *
  *  ao2_iterator_destroy(&i);
  *
  *  \endcode
  *
  */
 
-/*!
- * \brief The astobj2 iterator
+/*! \brief
+ * The astobj2 iterator
  *
  * \note You are not supposed to know the internals of an iterator!
  * We would like the iterator to be opaque, unfortunately
@@ -1839,19 +1396,34 @@ void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags fla
  * The iterator has a pointer to the container, and a flags
  * field specifying various things e.g. whether the container
  * should be locked or not while navigating on it.
- * The iterator "points" to the current container node.
+ * The iterator "points" to the current object, which is identified
+ * by three values:
+ *
+ * - a bucket number;
+ * - the object_id, which is also the container version number
+ *   when the object was inserted. This identifies the object
+ *   uniquely, however reaching the desired object requires
+ *   scanning a list.
+ * - a pointer, and a container version when we saved the pointer.
+ *   If the container has not changed its version number, then we
+ *   can safely follow the pointer to reach the object in constant time.
  *
  * Details are in the implementation of ao2_iterator_next()
+ * A freshly-initialized iterator has bucket=0, version=0.
  */
 struct ao2_iterator {
-	/*! The container (Has a reference) */
+	/*! the container */
 	struct ao2_container *c;
-	/*! Last container node (Has a reference) */
-	void *last_node;
-	/*! Nonzero if the iteration has completed. */
-	int complete;
-	/*! operation flags (enum ao2_iterator_flags) */
+	/*! operation flags */
 	int flags;
+	/*! current bucket */
+	int bucket;
+	/*! container version */
+	unsigned int c_version;
+	/*! pointer to the current object */
+	void *obj;
+	/*! container version when the object was created */
+	unsigned int version;
 };
 
 /*! Flags that can be passed to ao2_iterator_init() to modify the behavior
@@ -1869,10 +1441,7 @@ enum ao2_iterator_flags {
 	 * to the original locked state.
 	 *
 	 * \note Only use this flag if the ao2_container is manually
-	 * locked already.  You should hold the lock until after
-	 * ao2_iterator_destroy().  If you must release the lock then
-	 * you must at least hold the lock whenever you call an
-	 * ao2_iterator_xxx function with this iterator.
+	 * locked already.
 	 */
 	AO2_ITERATOR_DONTLOCK = (1 << 0),
 	/*!
@@ -1886,25 +1455,13 @@ enum ao2_iterator_flags {
 	 * from the container.
 	 */
 	AO2_ITERATOR_UNLINK = (1 << 2),
-	/*!
-	 * Iterate in descending order (Last to first container object)
-	 * (Otherwise ascending order)
-	 *
-	 * \note Other traversal orders such as pre-order and post-order
-	 * do not make sense because they require the container
-	 * structure to be static during the traversal.  Iterators just
-	 * about guarantee that is not going to happen because the
-	 * container is allowed to change by other threads during the
-	 * iteration.
-	 */
-	AO2_ITERATOR_DESCENDING = (1 << 3),
 };
 
 /*!
  * \brief Create an iterator for a container
  *
  * \param c the container
- * \param flags one or more flags from ao2_iterator_flags.
+ * \param flags one or more flags from ao2_iterator_flags
  *
  * \retval the constructed iterator
  *
@@ -1914,8 +1471,9 @@ enum ao2_iterator_flags {
  *       allocated on the stack or on the heap.
  *
  * This function will take a reference on the container being iterated.
+ *
  */
-struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result;
+struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
 
 /*!
  * \brief Destroy a container iterator
@@ -1926,13 +1484,13 @@ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attrib
  *
  * This function will release the container reference held by the iterator
  * and any other resources it may be holding.
+ *
  */
 #if defined(TEST_FRAMEWORK)
 void ao2_iterator_destroy(struct ao2_iterator *iter) __attribute__((noinline));
 #else
 void ao2_iterator_destroy(struct ao2_iterator *iter);
-#endif	/* defined(TEST_FRAMEWORK) */
-
+#endif
 #ifdef REF_DEBUG
 
 #define ao2_t_iterator_next(iter, tag) __ao2_iterator_next_debug((iter), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
@@ -1945,44 +1503,22 @@ void ao2_iterator_destroy(struct ao2_iterator *iter);
 
 #endif
 
-void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
-void *__ao2_iterator_next(struct ao2_iterator *iter) attribute_warn_unused_result;
+void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func);
+void *__ao2_iterator_next(struct ao2_iterator *iter);
 
-/*!
- * \brief Restart an iteration.
- *
- * \param iter the iterator to restart
- *
- * \note A restart is not going to have any effect if the
- * iterator was created with the AO2_ITERATOR_UNLINK flag.  Any
- * previous objects returned were removed from the container.
- *
- * \retval none
- */
-void ao2_iterator_restart(struct ao2_iterator *iter);
+/* extra functions */
+void ao2_bt(void);	/* backtrace */
 
 /*! gcc __attribute__(cleanup()) functions
  * \note they must be able to handle NULL parameters because most of the
  * allocation/find functions can fail and we don't want to try to tear
  * down a NULL */
 void __ao2_cleanup(void *obj);
-void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function);
+void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *function);
 #ifdef REF_DEBUG
-#define ao2_cleanup(obj) __ao2_cleanup_debug((obj), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_t_cleanup(obj, tag) __ao2_cleanup_debug((obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_cleanup(obj) __ao2_cleanup_debug((obj), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #else
 #define ao2_cleanup(obj) __ao2_cleanup(obj)
-#define ao2_t_cleanup(obj, tag) __ao2_cleanup((obj))
 #endif
 void ao2_iterator_cleanup(struct ao2_iterator *iter);
-
-/*!
- * \brief Get a count of the iterated container objects.
- *
- * \param iter the iterator to query
- *
- * \retval The number of objects in the iterated container
- */
-int ao2_iterator_count(struct ao2_iterator *iter);
-
 #endif /* _ASTERISK_ASTOBJ2_H */
diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h
index 375b2dd..38bfd72 100644
--- a/include/asterisk/audiohook.h
+++ b/include/asterisk/audiohook.h
@@ -63,6 +63,7 @@ enum ast_audiohook_flags {
 	AST_AUDIOHOOK_SMALL_QUEUE   = (1 << 4),
 	AST_AUDIOHOOK_MUTE_READ     = (1 << 5), /*!< audiohook should be mute frames read */
 	AST_AUDIOHOOK_MUTE_WRITE    = (1 << 6), /*!< audiohook should be mute frames written */
+	AST_AUDIOHOOK_COMPATIBLE    = (1 << 7), /*!< is the audiohook native slin compatible */
 };
 
 enum ast_audiohook_init_flags {
@@ -109,7 +110,7 @@ struct ast_audiohook {
 	struct ast_slinfactory write_factory;                  /*!< Factory where frames written to the channel will go through */
 	struct timeval read_time;                              /*!< Last time read factory was fed */
 	struct timeval write_time;                             /*!< Last time write factory was fed */
-	struct ast_format *format;                             /*!< Format translation path is setup as */
+	struct ast_format format;                              /*!< Format translation path is setup as */
 	struct ast_trans_pvt *trans_pvt;                       /*!< Translation path for reading frames */
 	ast_audiohook_manipulate_callback manipulate_callback; /*!< Manipulation callback */
 	struct ast_audiohook_options options;                  /*!< Applicable options */
@@ -154,10 +155,10 @@ struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size
 /*! \brief Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame data to provided arguments.
  * \param audiohook Audiohook structure
  * \param samples Number of samples wanted
- * \param ast_format Format of frame remote side wants back
- * \param read_frame if available, we'll copy the read buffer to this.
- * \param write_frame if available, we'll copy the write buffer to this.
- * \param direction
+ * \param direction Direction the audio frame came from
+ * \param format Format of frame remote side wants back
+ * \param ast_frame read_frame - if available, we'll copy the read buffer to this.
+ * \param ast_frame write_frame - if available, we'll copy the write buffer to this.
  * \return Returns frame on success, NULL on failure
  */
 struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame);
@@ -175,12 +176,11 @@ int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audioho
  */
 int ast_audiohook_detach(struct ast_audiohook *audiohook);
 
-/*!
- * \brief Detach audiohooks from list and destroy said list
- * \param audiohook_list List of audiohooks (NULL tolerant)
- * \return Nothing
+/*! \brief Detach audiohooks from list and destroy said list
+ * \param audiohook_list List of audiohooks
+ * \return Returns 0 on success, -1 on failure
  */
-void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list);
+int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list);
 
 /*! \brief Move an audiohook from one channel to a new one
  *
@@ -197,17 +197,6 @@ void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list);
  */
 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source);
 
-/*! \brief Move all audiohooks from one channel to another
- *
- * \note It is required that both old_chan and new_chan are locked prior to calling
- * this function. Besides needing to protect the data within the channels, not locking
- * these channels can lead to a potential deadlock.
- *
- * \param old_chan The source of the audiohooks being moved
- * \param new_chan The destination channel for the audiohooks to be moved to
- */
-void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan);
-
 /*!
  * \brief Detach specified source audiohook from channel
  *
@@ -233,9 +222,7 @@ int ast_audiohook_detach_source(struct ast_channel *chan, const char *source);
 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook);
 
 /*!
- * \brief Determine if a audiohook_list is empty or not.
- *
- * \param audiohook Audiohook to check.  (NULL also means empty)
+ * \brief determines if a audiohook_list is empty or not.
  *
  * retval 0 false, 1 true
  */
diff --git a/include/asterisk/autochan.h b/include/asterisk/autochan.h
index a0981b7..2ace4f2 100644
--- a/include/asterisk/autochan.h
+++ b/include/asterisk/autochan.h
@@ -98,9 +98,8 @@ void ast_autochan_destroy(struct ast_autochan *autochan);
  * \details
  * Traverses the list of autochans. All autochans which point to
  * old_chan will be updated to point to new_chan instead. Currently
- * this is only called during an ast_channel_move() operation in
- * channel.c.
- *
+ * this is only called from ast_do_masquerade in channel.c.
+ * 
  * \pre Both channels must be locked before calling this function.
  *
  * \param old_chan The channel that autochans may currently point to
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 2752613..66c40b2 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -32,9 +32,6 @@
 /* Use the FreeRADIUS-client library */
 #undef FREERADIUS_CLIENT
 
-/* Define to 1 if anonymous semaphores work. */
-#undef HAS_WORKING_SEMAPHORE
-
 /* Define to 1 if you have the `acos' function. */
 #undef HAVE_ACOS
 
@@ -88,21 +85,12 @@
 /* Define to 1 if your GCC C compiler supports the 'const' attribute. */
 #undef HAVE_ATTRIBUTE_const
 
-/* Define to 1 if your GCC C compiler supports the 'constructor' attribute. */
-#undef HAVE_ATTRIBUTE_constructor
-
 /* Define to 1 if your GCC C compiler supports the 'deprecated' attribute. */
 #undef HAVE_ATTRIBUTE_deprecated
 
-/* Define to 1 if your GCC C compiler supports the 'destructor' attribute. */
-#undef HAVE_ATTRIBUTE_destructor
-
 /* Define to 1 if your GCC C compiler supports the 'malloc' attribute. */
 #undef HAVE_ATTRIBUTE_malloc
 
-/* Define to 1 if your GCC C compiler supports the 'may_alias' attribute. */
-#undef HAVE_ATTRIBUTE_may_alias
-
 /* Define to 1 if your GCC C compiler supports the 'pure' attribute. */
 #undef HAVE_ATTRIBUTE_pure
 
@@ -116,6 +104,15 @@
    attribute. */
 #undef HAVE_ATTRIBUTE_warn_unused_result
 
+/* Define to 1 if your GCC C compiler supports the 'weak' attribute. */
+#undef HAVE_ATTRIBUTE_weak
+
+/* Define to 1 if your GCC C compiler supports the 'weak_import' attribute. */
+#undef HAVE_ATTRIBUTE_weak_import
+
+/* Define to 1 if your GCC C compiler supports the 'weakref' attribute. */
+#undef HAVE_ATTRIBUTE_weakref
+
 /* Define to 1 if you have the Debug symbol decoding library. */
 #undef HAVE_BFD
 
@@ -155,15 +152,9 @@
 /* Define to 1 if you have the `cosl' function. */
 #undef HAVE_COSL
 
-/* Define to 1 if you have the `crypt' function. */
-#undef HAVE_CRYPT
-
 /* Define to 1 if you have the OpenSSL Cryptography library. */
 #undef HAVE_CRYPTO
 
-/* Define to 1 if you have the `crypt_r' function. */
-#undef HAVE_CRYPT_R
-
 /* Define to 1 if you have a functional curl library. */
 #undef HAVE_CURL
 
@@ -185,6 +176,9 @@
 /* Define DAHDI headers version */
 #undef HAVE_DAHDI_VERSION
 
+/* Define to 1 if your system has /dev/urandom. */
+#undef HAVE_DEV_URANDOM
+
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
    */
 #undef HAVE_DIRENT_H
@@ -376,9 +370,6 @@
 /* Define to 1 if you have the Jack Audio Connection Kit library. */
 #undef HAVE_JACK
 
-/* Define to 1 if you have the Jansson JSON library library. */
-#undef HAVE_JANSSON
-
 /* Define to 1 if you have the `kevent64' function. */
 #undef HAVE_KEVENT64
 
@@ -400,12 +391,6 @@
 /* Define if your system has the LIBXML2 libraries. */
 #undef HAVE_LIBXML2
 
-/* Define to 1 if you have the LibXSLT library. */
-#undef HAVE_LIBXSLT
-
-/* Define to 1 if LIBXSLT has the LibXSLT Library Cleanup Function feature. */
-#undef HAVE_LIBXSLT_CLEANUP
-
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
@@ -545,15 +530,12 @@
 /* Define to 1 if you have the OpenSSL Secure Sockets Layer library. */
 #undef HAVE_OPENSSL
 
-/* Define to 1 if CRYPTO has the OpenSSL Elliptic Curve Support feature. */
-#undef HAVE_OPENSSL_EC
+/* Define if your system has SSL_CTX_set_ecdh_auto declared. */
+#undef HAVE_OPENSSL_ECDH_AUTO
 
 /* Define to 1 if CRYPTO has the OpenSSL SRTP Extension Support feature. */
 #undef HAVE_OPENSSL_SRTP
 
-/* Define to 1 if you have the Opus library. */
-#undef HAVE_OPUS
-
 /* Define this to indicate the ${OSPTK_DESCRIP} library */
 #undef HAVE_OSPTK
 
@@ -575,16 +557,6 @@
 /* Define to indicate presence of the pg_encoding_to_char API. */
 #undef HAVE_PGSQL_pg_encoding_to_char
 
-/* Define if your system has the PJPROJECT libraries. */
-#undef HAVE_PJPROJECT
-
-/* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */
-#undef HAVE_PJSIP_REPLACE_MEDIA_STREAM
-
-/* Define to 1 if PJPROJECT has the PJSIP Transaction Group Lock Support
-   feature. */
-#undef HAVE_PJ_TRANSACTION_GRP_LOCK
-
 /* Define to 1 if your system defines IP_PKTINFO. */
 #undef HAVE_PKTINFO
 
@@ -677,10 +649,6 @@
 /* Define if you have POSIX threads libraries and header files. */
 #undef HAVE_PTHREAD
 
-/* Define to 1 if your system defines PTHREAD_MUTEX_ADAPTIVE_NP in pthread.h
-   */
-#undef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
-
 /* Define to 1 if your system defines PTHREAD_MUTEX_RECURSIVE_NP in pthread.h
    */
 #undef HAVE_PTHREAD_MUTEX_RECURSIVE_NP
@@ -699,9 +667,6 @@
 /* Define if your system has pthread_rwlock_timedwrlock() */
 #undef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
 
-/* Define to 1 if your system has pthread_spinlock_t in pthread.h */
-#undef HAVE_PTHREAD_SPINLOCK
-
 /* Define to 1 if the system has the type `ptrdiff_t'. */
 #undef HAVE_PTRDIFF_T
 
@@ -753,9 +718,6 @@
 /* Define to 1 if you have the `roundl' function. */
 #undef HAVE_ROUNDL
 
-/* Define if your system has the RTLD_NOLOAD headers. */
-#undef HAVE_RTLD_NOLOAD
-
 /* Define to 1 if your system has /sbin/launchd. */
 #undef HAVE_SBIN_LAUNCHD
 
@@ -1067,9 +1029,6 @@
 /* Define to 1 if you have the `unsetenv' function. */
 #undef HAVE_UNSETENV
 
-/* Define to 1 if you have the uriparser library library. */
-#undef HAVE_URIPARSER
-
 /* Define to 1 if you have the `utime' function. */
 #undef HAVE_UTIME
 
@@ -1079,8 +1038,8 @@
 /* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
 #undef HAVE_UTIME_NULL
 
-/* Define to 1 if you have the `uuid_generate_random' function. */
-#undef HAVE_UUID_GENERATE_RANDOM
+/* Define to 1 if you have the UUID library. */
+#undef HAVE_UUID
 
 /* Define to 1 if your system can support larger than default select bitmasks.
    */
@@ -1300,6 +1259,14 @@
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
+/* Prevent clang array-bounds warning by not using strcmp from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strcmp
+
+/* Prevent clang array-bounds warning by not using strsep from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strsep
+
 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 #undef _LARGEFILE_SOURCE
 
diff --git a/include/asterisk/backtrace.h b/include/asterisk/backtrace.h
deleted file mode 100644
index 95358bf..0000000
--- a/include/asterisk/backtrace.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Asterisk backtrace generation
- *
- * This file provides backtrace generation utilities
- */
-
-
-#ifndef BACKTRACE_H_
-#define BACKTRACE_H_
-
-#define AST_MAX_BT_FRAMES 32
-
-#ifdef HAVE_BKTR
-#define ast_bt_get_addresses(bt) __ast_bt_get_addresses((bt))
-#define ast_bt_create() __ast_bt_create()
-#define ast_bt_destroy(bt) __ast_bt_destroy((bt))
-#define ast_bt_get_symbols(addresses, num_frames) __ast_bt_get_symbols((addresses), (num_frames))
-#else
-#define ast_bt_get_addresses(bt) 0
-#define ast_bt_create() NULL
-#define ast_bt_destroy(bt) NULL
-#define ast_bt_get_symbols(addresses, num_frames) NULL
-#endif
-
-/* \brief
- *
- * A structure to hold backtrace information. This structure provides an easy means to
- * store backtrace information or pass backtraces to other functions.
- */
-struct ast_bt {
-	/*! The addresses of the stack frames. This is filled in by calling the glibc backtrace() function */
-	void *addresses[AST_MAX_BT_FRAMES];
-	/*! The number of stack frames in the backtrace */
-	int num_frames;
-	/*! Tells if the ast_bt structure was dynamically allocated */
-	unsigned int alloced:1;
-};
-
-#ifdef HAVE_BKTR
-
-/* \brief
- * Allocates memory for an ast_bt and stores addresses and symbols.
- *
- * \return Returns NULL on failure, or the allocated ast_bt on success
- * \since 1.6.1
- */
-struct ast_bt *__ast_bt_create(void);
-
-/* \brief
- * Fill an allocated ast_bt with addresses
- *
- * \retval 0 Success
- * \retval -1 Failure
- * \since 1.6.1
- */
-int __ast_bt_get_addresses(struct ast_bt *bt);
-
-/* \brief
- *
- * Free dynamically allocated portions of an ast_bt
- *
- * \retval NULL.
- * \since 1.6.1
- */
-void *__ast_bt_destroy(struct ast_bt *bt);
-
-/* \brief Retrieve symbols for a set of backtrace addresses
- *
- * \param addresses A list of addresses, such as the ->addresses structure element of struct ast_bt.
- * \param num_frames Number of addresses in the addresses list
- * \retval NULL Unable to allocate memory
- * \return List of strings. Free the entire list with a single ast_std_free call.
- * \since 1.6.2.16
- */
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames);
-
-#endif /* HAVE_BKTR */
-
-#endif /* BACKTRACE_H_ */
diff --git a/include/asterisk/beep.h b/include/asterisk/beep.h
deleted file mode 100644
index f436e9c..0000000
--- a/include/asterisk/beep.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Russell Bryant
- *
- * Russell Bryant <russell at russellbryant.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Periodic beeps into the audio of a call
- */
-
-#ifndef _ASTERISK_BEEP_H
-#define _ASTERISK_BEEP_H
-
-#include "asterisk/optional_api.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-AST_OPTIONAL_API(int, ast_beep_start,
-		(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len),
-		{ return -1; });
-
-AST_OPTIONAL_API(int, ast_beep_stop,
-		(struct ast_channel *chan, const char *beep_id),
-		{ return -1; });
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_BEEP_H */
diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h
deleted file mode 100644
index ccfb541..0000000
--- a/include/asterisk/bridge.h
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2007 - 2009, 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Bridging API
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- * \author Joshua Colp <jcolp at digium.com>
- * \ref AstBridging
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*!
- * \page AstBridging Bridging API
- *
- * The purpose of this API is to provide an easy and flexible way to bridge
- * channels of different technologies with different features.
- *
- * Bridging technologies provide the mechanism that do the actual handling
- * of frames between channels. They provide capability information, codec information,
- * and preference value to assist the bridging core in choosing a bridging technology when
- * creating a bridge. Different bridges may use different bridging technologies based on needs
- * but once chosen they all operate under the same premise; they receive frames and send frames.
- *
- * Bridges are a combination of bridging technology, channels, and features. A
- * developer creates a new bridge based on what they are currently expecting to do
- * with it or what they will do with it in the future. The bridging core determines what
- * available bridging technology will best fit the requirements and creates a new bridge.
- * Once created, channels can be added to the bridge in a blocking or non-blocking fashion.
- *
- * Features are such things as channel muting or DTMF based features such as attended transfer,
- * blind transfer, and hangup. Feature information must be set at the most granular level, on
- * the channel. While you can use features on a global scope the presence of a feature structure
- * on the channel will override the global scope. An example would be having the bridge muted
- * at global scope and attended transfer enabled on a channel. Since the channel itself is not muted
- * it would be able to speak.
- *
- * Feature hooks allow a developer to tell the bridging core that when a DTMF string
- * is received from a channel a callback should be called in their application. For
- * example, a conference bridge application may want to provide an IVR to control various
- * settings on the conference bridge. This can be accomplished by attaching a feature hook
- * that calls an IVR function when a DTMF string is entered.
- *
- */
-
-#ifndef _ASTERISK_BRIDGING_H
-#define _ASTERISK_BRIDGING_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/bridge_features.h"
-#include "asterisk/bridge_channel.h"
-#include "asterisk/bridge_roles.h"
-#include "asterisk/dsp.h"
-#include "asterisk/uuid.h"
-
-struct ast_bridge_technology;
-struct ast_bridge;
-struct ast_bridge_tech_optimizations;
-
-/*! \brief Capabilities for a bridge technology */
-enum ast_bridge_capability {
-	/*! Bridge technology can service calls on hold. */
-	AST_BRIDGE_CAPABILITY_HOLDING = (1 << 0),
-	/*! Bridge waits for channel to answer.  Passes early media. (XXX Not supported yet) */
-	AST_BRIDGE_CAPABILITY_EARLY = (1 << 1),
-	/*! Bridge is capable of natively bridging two channels. (Smart bridge only) */
-	AST_BRIDGE_CAPABILITY_NATIVE = (1 << 2),
-	/*! Bridge is capable of mixing at most two channels. (Smart bridgeable) */
-	AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 3),
-	/*! Bridge is capable of mixing an arbitrary number of channels. (Smart bridgeable) */
-	AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 4),
-};
-
-/*! \brief Video source modes */
-enum ast_bridge_video_mode_type {
-	/*! Video is not allowed in the bridge */
-	AST_BRIDGE_VIDEO_MODE_NONE = 0,
-	/*! A single user is picked as the only distributed of video across the bridge */
-	AST_BRIDGE_VIDEO_MODE_SINGLE_SRC,
-	/*! A single user's video feed is distributed to all bridge channels, but
-	 *  that feed is automatically picked based on who is talking the most. */
-	AST_BRIDGE_VIDEO_MODE_TALKER_SRC,
-};
-
-/*! \brief This is used for both SINGLE_SRC mode to set what channel
- *  should be the current single video feed */
-struct ast_bridge_video_single_src_data {
-	/*! Only accept video coming from this channel */
-	struct ast_channel *chan_vsrc;
-};
-
-/*! \brief This is used for both SINGLE_SRC_TALKER mode to set what channel
- *  should be the current single video feed */
-struct ast_bridge_video_talker_src_data {
-	/*! Only accept video coming from this channel */
-	struct ast_channel *chan_vsrc;
-	int average_talking_energy;
-
-	/*! Current talker see's this person */
-	struct ast_channel *chan_old_vsrc;
-};
-
-/*! \brief Data structure that defines a video source mode */
-struct ast_bridge_video_mode {
-	enum ast_bridge_video_mode_type mode;
-	/* Add data for all the video modes here. */
-	union {
-		struct ast_bridge_video_single_src_data single_src_data;
-		struct ast_bridge_video_talker_src_data talker_src_data;
-	} mode_data;
-};
-
-/*!
- * \brief Destroy the bridge.
- *
- * \param self Bridge to operate upon.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_destructor_fn)(struct ast_bridge *self);
-
-/*!
- * \brief The bridge is being dissolved.
- *
- * \param self Bridge to operate upon.
- *
- * \details
- * The bridge is being dissolved.  Remove any external
- * references to the bridge so it can be destroyed.
- *
- * \note On entry, self must NOT be locked.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_dissolving_fn)(struct ast_bridge *self);
-
-/*!
- * \brief Push this channel into the bridge.
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to push.
- * \param swap Bridge channel to swap places with if not NULL.
- *
- * \details
- * Setup any channel hooks controlled by the bridge.  Allocate
- * bridge_channel->bridge_pvt and initialize any resources put
- * in bridge_channel->bridge_pvt if needed.  If there is a swap
- * channel, use it as a guide to setting up the bridge_channel.
- *
- * \note On entry, self is already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.  The channel did not get pushed.
- */
-typedef int (*ast_bridge_push_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
-
-/*!
- * \brief Pull this channel from the bridge.
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to pull.
- *
- * \details
- * Remove any channel hooks controlled by the bridge.  Release
- * any resources held by bridge_channel->bridge_pvt and release
- * bridge_channel->bridge_pvt.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_pull_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Notify the bridge that this channel was just masqueraded.
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel that was masqueraded.
- *
- * \details
- * A masquerade just happened to this channel.  The bridge needs
- * to re-evaluate this a channel in the bridge.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_notify_masquerade_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Get the merge priority of this bridge.
- *
- * \param self Bridge to operate upon.
- *
- * \note On entry, self is already locked.
- *
- * \return Merge priority
- */
-typedef int (*ast_bridge_merge_priority_fn)(struct ast_bridge *self);
-
-/*!
- * \brief Bridge virtual methods table definition.
- *
- * \note Any changes to this struct must be reflected in
- * bridge_alloc() validity checking.
- */
-struct ast_bridge_methods {
-	/*! Bridge class name for log messages. */
-	const char *name;
-	/*! Destroy the bridge. */
-	ast_bridge_destructor_fn destroy;
-	/*! The bridge is being dissolved.  Remove any references to the bridge. */
-	ast_bridge_dissolving_fn dissolving;
-	/*! Push the bridge channel into the bridge. */
-	ast_bridge_push_channel_fn push;
-	/*! Pull the bridge channel from the bridge. */
-	ast_bridge_pull_channel_fn pull;
-	/*! Notify the bridge of a masquerade with the channel. */
-	ast_bridge_notify_masquerade_fn notify_masquerade;
-	/*! Get the bridge merge priority. */
-	ast_bridge_merge_priority_fn get_merge_priority;
-};
-
-/*! Softmix technology parameters. */
-struct ast_bridge_softmix {
-	/*! The video mode softmix is using */
-	struct ast_bridge_video_mode video_mode;
-	/*!
-	 * \brief The internal sample rate softmix uses to mix channels.
-	 *
-	 * \note If this value is 0, the sofmix may auto adjust the mixing rate.
-	 */
-	unsigned int internal_sample_rate;
-	/*!
-	 * \brief The mixing interval indicates how quickly softmix
-	 * mixing should occur to mix audio.
-	 *
-	 * \note When set to 0, softmix must choose a default interval
-	 * for itself.
-	 */
-	unsigned int internal_mixing_interval;
-};
-
-/*!
- * \brief Structure that contains information about a bridge
- */
-struct ast_bridge {
-	/*! Bridge virtual method table. */
-	const struct ast_bridge_methods *v_table;
-	/*! "Personality" currently exhibited by bridge subclass */
-	void *personality;
-	/*! Bridge technology that is handling the bridge */
-	struct ast_bridge_technology *technology;
-	/*! Private information unique to the bridge technology */
-	void *tech_pvt;
-	/*! Per-bridge topics */
-	struct stasis_cp_single *topics;
-	/*! Call ID associated with the bridge */
-	struct ast_callid *callid;
-	/*! Linked list of channels participating in the bridge */
-	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
-	/*! Queue of actions to perform on the bridge. */
-	AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
-	/*! Softmix technology parameters. */
-	struct ast_bridge_softmix softmix;
-	/*! Bridge flags to tweak behavior */
-	struct ast_flags feature_flags;
-	/*! Allowed bridge technology capabilities when AST_BRIDGE_FLAG_SMART enabled. */
-	uint32_t allowed_capabilities;
-	/*! Number of channels participating in the bridge */
-	unsigned int num_channels;
-	/*! Number of active channels in the bridge. */
-	unsigned int num_active;
-	/*! Number of channels with AST_BRIDGE_CHANNEL_FLAG_LONELY in the bridge. */
-	unsigned int num_lonely;
-	/*!
-	 * \brief Count of the active temporary requests to inhibit bridge merges.
-	 * Zero if merges are allowed.
-	 *
-	 * \note Temporary as in try again in a moment.
-	 */
-	unsigned int inhibit_merge;
-	/*! Cause code of the dissolved bridge. */
-	int cause;
-	/*! TRUE if the bridge was reconfigured. */
-	unsigned int reconfigured:1;
-	/*! TRUE if the bridge has been dissolved.  Any channel that now tries to join is immediately ejected. */
-	unsigned int dissolved:1;
-	/*! TRUE if the bridge construction was completed. */
-	unsigned int construction_completed:1;
-
-	AST_DECLARE_STRING_FIELDS(
-		/*! Immutable name of the creator for the bridge */
-		AST_STRING_FIELD(creator);
-		/*! Immutable name given to the bridge by its creator */
-		AST_STRING_FIELD(name);
-		/*! Immutable bridge UUID. */
-		AST_STRING_FIELD(uniqueid);
-	);
-};
-
-/*! \brief Bridge base class virtual method table. */
-extern struct ast_bridge_methods ast_bridge_base_v_table;
-
-/*!
- * \brief Create a new base class bridge
- *
- * \param capabilities The capabilities that we require to be used on the bridge
- * \param flags Flags that will alter the behavior of the bridge
- * \param creator Entity that created the bridge (optional)
- * \param name Name given to the bridge by its creator (optional, requires named creator)
- * \param id Unique ID given to the bridge by its creator (optional)
- *
- * \retval a pointer to a new bridge on success
- * \retval NULL on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge *bridge;
- * bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
- * \endcode
- *
- * This creates a no frills two party bridge that will be
- * destroyed once one of the channels hangs up.
- */
-struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id);
-
-/*!
- * \brief Try locking the bridge.
- *
- * \param bridge Bridge to try locking
- *
- * \retval 0 on success.
- * \retval non-zero on error.
- */
-#define ast_bridge_trylock(bridge)	_ast_bridge_trylock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
-static inline int _ast_bridge_trylock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
-{
-	return __ao2_trylock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var);
-}
-
-/*!
- * \brief Lock the bridge.
- *
- * \param bridge Bridge to lock
- *
- * \return Nothing
- */
-#define ast_bridge_lock(bridge)	_ast_bridge_lock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
-static inline void _ast_bridge_lock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_lock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var);
-}
-
-/*!
- * \brief Unlock the bridge.
- *
- * \param bridge Bridge to unlock
- *
- * \return Nothing
- */
-#define ast_bridge_unlock(bridge)	_ast_bridge_unlock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
-static inline void _ast_bridge_unlock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_unlock(bridge, file, function, line, var);
-}
-
-/*! \brief Lock two bridges. */
-#define ast_bridge_lock_both(bridge1, bridge2)		\
-	do {											\
-		for (;;) {									\
-			ast_bridge_lock(bridge1);				\
-			if (!ast_bridge_trylock(bridge2)) {		\
-				break;								\
-			}										\
-			ast_bridge_unlock(bridge1);				\
-			sched_yield();							\
-		}											\
-	} while (0)
-
-/*!
- * \brief Destroy a bridge
- *
- * \param bridge Bridge to destroy
- * \param cause Cause of bridge being destroyed.  (If cause <= 0 then use AST_CAUSE_NORMAL_CLEARING)
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_destroy(bridge, AST_CAUSE_NORMAL_CLEARING);
- * \endcode
- *
- * This destroys a bridge that was previously created.
- *
- * \note
- * While this function will kick all channels out of the bridge, channels that
- * were added to the bridge using ast_bridge_impart() with the flag
- * AST_BRIDGE_IMPART_CHAN_DEPARTABLE set must have ast_bridge_depart() called
- * on them.
- */
-int ast_bridge_destroy(struct ast_bridge *bridge, int cause);
-
-/*!
- * \brief Notify bridging that this channel was just masqueraded.
- * \since 12.0.0
- *
- * \param chan Channel just involved in a masquerade
- *
- * \return Nothing
- */
-void ast_bridge_notify_masquerade(struct ast_channel *chan);
-
-enum ast_bridge_join_flags {
-	/*! The bridge reference is being passed by the caller. */
-	AST_BRIDGE_JOIN_PASS_REFERENCE = (1 << 0),
-	/*! The initial bridge join does not cause a COLP exchange. */
-	AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP = (1 << 1),
-};
-
-/*!
- * \brief Join (blocking) a channel to a bridge
- *
- * \param bridge Bridge to join
- * \param chan Channel to join
- * \param swap Channel to swap out if swapping
- * \param features Bridge features structure
- * \param tech_args Optional Bridging tech optimization parameters for this channel.
- * \param flags defined by enum ast_bridge_join_flags.
- *
- * \note Absolutely _NO_ locks should be held before calling
- * this function since it blocks.
- *
- * \retval 0 if the channel successfully joined the bridge before it exited.
- * \retval -1 if the channel failed to join the bridge
- *
- * Example usage:
- *
- * \code
- * ast_bridge_join(bridge, chan, NULL, NULL, NULL, AST_BRIDGE_JOIN_PASS_REFERENCE);
- * \endcode
- *
- * This adds a channel pointed to by the chan pointer to the bridge pointed to by
- * the bridge pointer. This function will not return until the channel has been
- * removed from the bridge, swapped out for another channel, or has hung up.
- *
- * If this channel will be replacing another channel the other channel can be specified
- * in the swap parameter. The other channel will be thrown out of the bridge in an
- * atomic fashion.
- *
- * If channel specific features are enabled a pointer to the features structure
- * can be specified in the features parameter.
- */
-int ast_bridge_join(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_channel *swap,
-	struct ast_bridge_features *features,
-	struct ast_bridge_tech_optimizations *tech_args,
-	enum ast_bridge_join_flags flags);
-
-enum ast_bridge_impart_flags {
-	/*! Field describing what the caller can do with the channel after it is imparted. */
-	AST_BRIDGE_IMPART_CHAN_MASK = (1 << 0),
-	/*! The caller wants to reclaim the channel using ast_bridge_depart(). */
-	AST_BRIDGE_IMPART_CHAN_DEPARTABLE = (0 << 0),
-	/*! The caller is passing channel control entirely to the bridging system. */
-	AST_BRIDGE_IMPART_CHAN_INDEPENDENT = (1 << 0),
-	/*! The initial bridge join does not cause a COLP exchange. */
-	AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP = (1 << 1),
-};
-
-/*!
- * \brief Impart (non-blocking) a channel onto a bridge
- *
- * \param bridge Bridge to impart on
- * \param chan Channel to impart (The channel reference is stolen if impart successful.)
- * \param swap Channel to swap out if swapping.  NULL if not swapping.
- * \param features Bridge features structure.
- * \param flags defined by enum ast_bridge_impart_flags.
- *
- * \note The features parameter must be NULL or obtained by
- * ast_bridge_features_new().  You must not dereference features
- * after calling even if the call fails.
- *
- * \note chan is locked by this function.
- *
- * \retval 0 on success
- * \retval -1 on failure (Caller still has ownership of chan)
- *
- * Example usage:
- *
- * \code
- * ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
- * \endcode
- *
- * \details
- * This adds a channel pointed to by the chan pointer to the
- * bridge pointed to by the bridge pointer.  This function will
- * return immediately and will not wait until the channel is no
- * longer part of the bridge.
- *
- * If this channel will be replacing another channel the other
- * channel can be specified in the swap parameter.  The other
- * channel will be thrown out of the bridge in an atomic
- * fashion.
- *
- * If channel specific features are enabled, a pointer to the
- * features structure can be specified in the features
- * parameter.
- *
- * \note If you impart a channel with
- * AST_BRIDGE_IMPART_CHAN_DEPARTABLE you MUST
- * ast_bridge_depart() the channel if this call succeeds.  The
- * bridge channel thread is created join-able.  The implication
- * is that the channel is special and will not behave like a
- * normal channel.
- *
- * \note If you impart a channel with
- * AST_BRIDGE_IMPART_CHAN_INDEPENDENT you must not
- * ast_bridge_depart() the channel.  The bridge channel thread
- * is created non-join-able.  The channel must be treated as if
- * it were placed into the bridge by ast_bridge_join().
- * Channels placed into a bridge by ast_bridge_join() are
- * removed by a third party using ast_bridge_remove().
- */
-int ast_bridge_impart(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_channel *swap,
-	struct ast_bridge_features *features,
-	enum ast_bridge_impart_flags flags) attribute_warn_unused_result;
-
-/*!
- * \brief Depart a channel from a bridge
- *
- * \param chan Channel to depart
- *
- * \note chan is locked by this function.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_depart(chan);
- * \endcode
- *
- * This removes the channel pointed to by the chan pointer from any bridge
- * it may be in and gives control to the calling thread.
- * This does not hang up the channel.
- *
- * \note This API call can only be used on channels that were added to the bridge
- *       using the ast_bridge_impart API call with the AST_BRIDGE_IMPART_CHAN_DEPARTABLE
- *       flag.
- */
-int ast_bridge_depart(struct ast_channel *chan);
-
-/*!
- * \brief Remove a channel from a bridge
- *
- * \param bridge Bridge that the channel is to be removed from
- * \param chan Channel to remove
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_remove(bridge, chan);
- * \endcode
- *
- * This removes the channel pointed to by the chan pointer from the bridge
- * pointed to by the bridge pointer and requests that it be hung up. Control
- * over the channel will NOT be given to the calling thread.
- *
- * \note This API call can be used on channels that were added to the bridge
- *       using both ast_bridge_join and ast_bridge_impart.
- */
-int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Kick a channel from a bridge
- *
- * \param bridge Bridge that the channel is to be kicked from
- * \param chan Channel to kick
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_kick(bridge, chan);
- * \endcode
- *
- * \details
- * This kicks the channel pointed to by the chan pointer from
- * the bridge pointed to by the bridge pointer and requests that
- * it be hung up.  Control over the channel will NOT be given to
- * the calling thread.
- *
- * \note The functional difference between ast_bridge_kick() and
- * ast_bridge_remove() is that the bridge may dissolve as a
- * result of the channel being kicked.
- *
- * \note This API call can be used on channels that were added
- * to the bridge using both ast_bridge_join and
- * ast_bridge_impart.
- */
-int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Merge two bridges together
- *
- * \param dst_bridge Destination bridge of merge.
- * \param src_bridge Source bridge of merge.
- * \param merge_best_direction TRUE if don't care about which bridge merges into the other.
- * \param kick_me Array of channels to kick from the bridges.
- * \param num_kick Number of channels in the kick_me array.
- *
- * \note Absolutely _NO_ bridge or channel locks should be held
- * before calling this function.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_merge(dst_bridge, src_bridge, 0, NULL, 0);
- * \endcode
- *
- * This moves the channels in src_bridge into the bridge pointed
- * to by dst_bridge.
- */
-int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, int merge_best_direction, struct ast_channel **kick_me, unsigned int num_kick);
-
-/*!
- * \brief Move a channel from one bridge to another.
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of bridge channel move.
- * \param src_bridge Source bridge of bridge channel move.
- * \param chan Channel to move.
- * \param swap Channel to replace in dst_bridge.
- * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
- *
- * \note Absolutely _NO_ bridge or channel locks should be held
- * before calling this function.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery);
-
-/*!
- * \brief Adjust the bridge merge inhibit request count.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- * \param request Inhibit request increment.
- *     (Positive to add requests.  Negative to remove requests.)
- *
- * \return Nothing
- */
-void ast_bridge_merge_inhibit(struct ast_bridge *bridge, int request);
-
-/*!
- * \brief Suspend a channel temporarily from a bridge
- *
- * \param bridge Bridge to suspend the channel from
- * \param chan Channel to suspend
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_suspend(bridge, chan);
- * \endcode
- *
- * This suspends the channel pointed to by chan from the bridge pointed to by bridge temporarily.
- * Control of the channel is given to the calling thread. This differs from ast_bridge_depart as
- * the channel will not be removed from the bridge.
- *
- * \note This API call can be used on channels that were added to the bridge
- *       using both ast_bridge_join and ast_bridge_impart.
- */
-int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Unsuspend a channel from a bridge
- *
- * \param bridge Bridge to unsuspend the channel from
- * \param chan Channel to unsuspend
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_unsuspend(bridge, chan);
- * \endcode
- *
- * This unsuspends the channel pointed to by chan from the bridge pointed to by bridge.
- * The bridge will go back to handling the channel once this function returns.
- *
- * \note You must not mess with the channel once this function returns.
- *       Doing so may result in bad things happening.
- */
-int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan);
-
-struct ast_unreal_pvt;
-
-/*!
- * \brief Check and optimize out the unreal channels between bridges.
- * \since 12.0.0
- *
- * \param chan Unreal channel writing a frame into the channel driver.
- * \param peer Other unreal channel in the pair.
- * \param pvt Private data provided by an implementation of the unreal driver that
- * contains the callbacks that should be called when optimization begins/ends
- *
- * \note It is assumed that chan is already locked.
- *
- * \retval 0 if unreal channels were not optimized out.
- * \retval non-zero if unreal channels were optimized out.
- */
-int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt);
-
-/*!
- * \brief Tells, if optimization is allowed, how the optimization would be performed
- */
-enum ast_bridge_optimization {
-	/*! Optimization would swap peer into the chan_bridge */
-	AST_BRIDGE_OPTIMIZE_SWAP_TO_CHAN_BRIDGE,
-	/*! Optimization would swap chan into the peer_bridge */
-	AST_BRIDGE_OPTIMIZE_SWAP_TO_PEER_BRIDGE,
-	/*! Optimization would merge peer_bridge into chan_bridge */
-	AST_BRIDGE_OPTIMIZE_MERGE_TO_CHAN_BRIDGE,
-	/*! Optimization would merge chan_bridge into peer_bridge */
-	AST_BRIDGE_OPTIMIZE_MERGE_TO_PEER_BRIDGE,
-	/*! Optimization is not permitted on one or both bridges */
-	AST_BRIDGE_OPTIMIZE_PROHIBITED,
-};
-
-/*!
- * \brief Determine if bridges allow for optimization to occur betweem them
- * \since 12.0.0
- *
- * \param chan_bridge First bridge being tested
- * \param peer_bridge Second bridge being tested
- *
- * This determines if two bridges allow for unreal channel optimization
- * to occur between them. The function does not require for unreal channels
- * to already be in the bridges when called.
- *
- * \note It is assumed that both bridges are locked prior to calling this function
- *
- * \note A return other than AST_BRIDGE_OPTIMIZE_PROHIBITED does not guarantee
- * that an optimization attempt will succeed. However, a return of
- * AST_BRIDGE_OPTIMIZE_PROHIBITED guarantees that an optimization attempt will
- * never succeed.
- *
- * \returns Optimization allowability for the bridges
- */
-enum ast_bridge_optimization ast_bridges_allow_optimization(struct ast_bridge *chan_bridge,
-		struct ast_bridge *peer_bridge);
-
-/*!
- * \brief Put an action onto the specified bridge.
- * \since 12.0.0
- *
- * \param bridge What to queue the action on.
- * \param action What to do.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- *
- * \note This API call is meant for internal bridging operations.
- */
-int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action);
-
-/*!
- * \brief Queue the given frame to everyone else.
- * \since 12.0.0
- *
- * \param bridge What bridge to distribute frame.
- * \param bridge_channel Channel to optionally not pass frame to. (NULL to pass to everyone)
- * \param frame Frame to pass.
- *
- * \note This is intended to be called by bridge hooks and
- * bridge technologies.
- *
- * \retval 0 Frame written to at least one channel.
- * \retval -1 Frame written to no channels.
- */
-int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame);
-
-/*!
- * \brief Adjust the internal mixing sample rate of a bridge
- * used during multimix mode.
- *
- * \param bridge Channel to change the sample rate on.
- * \param sample_rate the sample rate to change to. If a
- *        value of 0 is passed here, the bridge will be free to pick
- *        what ever sample rate it chooses.
- *
- */
-void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate);
-
-/*!
- * \brief Adjust the internal mixing interval of a bridge used
- * during multimix mode.
- *
- * \param bridge Channel to change the sample rate on.
- * \param mixing_interval the sample rate to change to.  If 0 is set
- * the bridge tech is free to choose any mixing interval it uses by default.
- */
-void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval);
-
-/*!
- * \brief Set a bridge to feed a single video source to all participants.
- */
-void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan);
-
-/*!
- * \brief Set the bridge to pick the strongest talker supporting
- * video as the single source video feed
- */
-void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge);
-
-/*!
- * \brief Update information about talker energy for talker src video mode.
- */
-void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyfame);
-
-/*!
- * \brief Returns the number of video sources currently active in the bridge
- */
-int ast_bridge_number_video_src(struct ast_bridge *bridge);
-
-/*!
- * \brief Determine if a channel is a video src for the bridge
- *
- * \retval 0 Not a current video source of the bridge.
- * \retval None 0, is a video source of the bridge, The number
- *         returned represents the priority this video stream has
- *         on the bridge where 1 is the highest priority.
- */
-int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief remove a channel as a source of video for the bridge.
- */
-void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan);
-
-enum ast_transfer_result {
-	/*! The transfer completed successfully */
-	AST_BRIDGE_TRANSFER_SUCCESS,
-	/*! A bridge involved does not permit transferring */
-	AST_BRIDGE_TRANSFER_NOT_PERMITTED,
-	/*! The current bridge setup makes transferring an invalid operation */
-	AST_BRIDGE_TRANSFER_INVALID,
-	/*! The transfer operation failed for a miscellaneous reason */
-	AST_BRIDGE_TRANSFER_FAIL,
-};
-
-enum ast_transfer_type {
-	/*! Transfer of a single party */
-	AST_BRIDGE_TRANSFER_SINGLE_PARTY,
-	/*! Transfer of multiple parties */
-	AST_BRIDGE_TRANSFER_MULTI_PARTY,
-};
-
-/*!
- * \brief AO2 object that wraps data for transfer_channel_cb
- */
-struct transfer_channel_data {
-	void *data;    /*! Data to be used by the transfer_channel_cb -- note that this
-	                *  pointer is going to be pointing to something on the stack, so
-	                *  it must not be used at any point after returning from the
-	                *  transfer_channel_cb. */
-	int completed; /*! Initially 0, This will be set to 1 by either the transfer
-	                *  code or by transfer code hooks (e.g. parking) when the
-	                *  transfer is completed and any remaining actions have taken
-	                *  place (e.g. parking announcements). It will never be reset
-	                *  to 0. This is used for deferring progress for channel
-	                *  drivers that support deferred progress. */
-};
-
-/*!
- * \brief Callback function type called during blind transfers
- *
- * A caller of ast_bridge_transfer_blind() may wish to set data on
- * the channel that ends up running dialplan. For instance, it may
- * be useful to set channel variables on the channel.
- *
- * \param chan The involved channel
- * \param user_data User-provided data needed in the callback
- * \param transfer_type The type of transfer being completed
- */
-typedef void (*transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data,
-		enum ast_transfer_type transfer_type);
-
-/*!
- * \brief Blind transfer target to the extension and context provided
- *
- * The channel given is bridged to one or multiple channels. Depending on
- * the bridge and the number of participants, the entire bridge could be
- * transferred to the given destination, or a single channel may be redirected.
- *
- * Callers may also provide a callback to be called on the channel that will
- * be running dialplan. The user data passed into ast_bridge_transfer_blind
- * will be given as the argument to the callback to be interpreted as desired.
- * This callback is guaranteed to be called in the same thread as
- * ast_bridge_transfer_blind() and before ast_bridge_transfer_blind() returns.
- *
- * \note Absolutely _NO_ channel locks should be held before
- * calling this function.
- *
- * \param is_external Indicates that transfer was initiated externally
- * \param transferer The channel performing the blind transfer
- * \param exten The dialplan extension to send the call to
- * \param context The dialplan context to send the call to
- * \param new_channel_cb A callback to be called on the channel that will
- *        be executing dialplan
- * \param user_data Argument for new_channel_cb
- * \return The success or failure result of the blind transfer
- */
-enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
-		struct ast_channel *transferer, const char *exten, const char *context,
-		transfer_channel_cb new_channel_cb, void *user_data);
-
-/*!
- * \brief Attended transfer
- *
- * The two channels are both transferer channels. The first is the channel
- * that is bridged to the transferee (or if unbridged, the 'first' call of
- * the transfer). The second is the channel that is bridged to the transfer
- * target (or if unbridged, the 'second' call of the transfer).
- *
- * \note Absolutely _NO_ channel locks should be held before
- * calling this function.
- *
- * \param to_transferee Transferer channel on initial call (presumably bridged to transferee)
- * \param to_transfer_target Transferer channel on consultation call (presumably bridged to transfer target)
- * \return The success or failure of the attended transfer
- */
-enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee,
-		struct ast_channel *to_transfer_target);
-
-/*!
- * \brief Set the relevant transfer variables for a single channel
- *
- * Sets either the ATTENDEDTRANSFER or BLINDTRANSFER variable for a channel while clearing
- * the opposite.
- *
- * \param chan Channel the variable is being set for
- * \param value Value the variable is being set to
- * \param is_attended false  set BLINDTRANSFER and unset ATTENDEDTRANSFER
- *                    true   set ATTENDEDTRANSFER and unset BLINDTRANSFER
- */
-void ast_bridge_set_transfer_variables(struct ast_channel *chan, const char *value, int is_attended);
-
-/*!
- * \brief Get a container of all channels in the bridge
- * \since 12.0.0
- *
- * \param bridge The bridge which is already locked.
- *
- * \retval NULL Failed to create container
- * \retval non-NULL Container of channels in the bridge
- */
-struct ao2_container *ast_bridge_peers_nolock(struct ast_bridge *bridge);
-
-/*!
- * \brief Get a container of all channels in the bridge
- * \since 12.0.0
- *
- * \param bridge The bridge
- *
- * \note The returned container is a snapshot of channels in the
- * bridge when called.
- *
- * \retval NULL Failed to create container
- * \retval non-NULL Container of channels in the bridge
- */
-struct ao2_container *ast_bridge_peers(struct ast_bridge *bridge);
-
-/*!
- * \brief Get the channel's bridge peer only if the bridge is two-party.
- * \since 12.0.0
- *
- * \param bridge The bridge which is already locked.
- * \param chan Channel desiring the bridge peer channel.
- *
- * \note The returned peer channel is the current peer in the
- * bridge when called.
- *
- * \retval NULL Channel not in a bridge or the bridge is not two-party.
- * \retval non-NULL Reffed peer channel at time of calling.
- */
-struct ast_channel *ast_bridge_peer_nolock(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Get the channel's bridge peer only if the bridge is two-party.
- * \since 12.0.0
- *
- * \param bridge The bridge
- * \param chan Channel desiring the bridge peer channel.
- *
- * \note The returned peer channel is the current peer in the
- * bridge when called.
- *
- * \retval NULL Channel not in a bridge or the bridge is not two-party.
- * \retval non-NULL Reffed peer channel at time of calling.
- */
-struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Remove marked bridge channel feature hooks.
- * \since 12.0.0
- *
- * \param features Bridge features structure
- * \param flags Determinator for whether hook is removed.
- *
- * \return Nothing
- */
-void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags flags);
-
-/*!
- * \brief Find bridge by id
- * \since 12.0.0
- *
- * \param bridge_id Bridge identifier
- *
- * \return NULL bridge not found
- * \return non-NULL reference to bridge
- */
-struct ast_bridge *ast_bridge_find_by_id(const char *bridge_id);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_BRIDGING_H */
diff --git a/include/asterisk/bridge_after.h b/include/asterisk/bridge_after.h
deleted file mode 100644
index 53f30b9..0000000
--- a/include/asterisk/bridge_after.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief After Bridge Execution API
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_BRIDGING_AFTER_H
-#define _ASTERISK_BRIDGING_AFTER_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/*! Reason the the after bridge callback will not be called. */
-enum ast_bridge_after_cb_reason {
-	/*! The datastore is being destroyed.  Likely due to hangup. (Enum value must be zero.) */
-	AST_BRIDGE_AFTER_CB_REASON_DESTROY,
-	/*! Something else replaced the callback with another. */
-	AST_BRIDGE_AFTER_CB_REASON_REPLACED,
-	/*! The callback was removed because of a masquerade. (fixup) */
-	AST_BRIDGE_AFTER_CB_REASON_MASQUERADE,
-	/*! The channel was departed from the bridge. */
-	AST_BRIDGE_AFTER_CB_REASON_DEPART,
-	/*! Was explicitly removed by external code. */
-	AST_BRIDGE_AFTER_CB_REASON_REMOVED,
-};
-
-/*!
- * \brief Set channel to goto specific location after the bridge.
- * \since 12.0.0
- *
- * \param chan Channel to setup after bridge goto location.
- * \param context Context to goto after bridge.
- * \param exten Exten to goto after bridge.
- * \param priority Priority to goto after bridge.
- *
- * \note chan is locked by this function.
- *
- * \details Add a channel datastore to setup the goto location
- * when the channel leaves the bridge and run a PBX from there.
- *
- * \return Nothing
- */
-void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority);
-
-/*!
- * \brief Set channel to run the h exten after the bridge.
- * \since 12.0.0
- *
- * \param chan Channel to setup after bridge goto location.
- * \param context Context to goto after bridge.
- *
- * \note chan is locked by this function.
- *
- * \details Add a channel datastore to setup the goto location
- * when the channel leaves the bridge and run a PBX from there.
- *
- * \return Nothing
- */
-void ast_bridge_set_after_h(struct ast_channel *chan, const char *context);
-
-/*!
- * \brief Set channel to go on in the dialplan after the bridge.
- * \since 12.0.0
- *
- * \param chan Channel to setup after bridge goto location.
- * \param context Current context of the caller channel.
- * \param exten Current exten of the caller channel.
- * \param priority Current priority of the caller channel
- * \param parseable_goto User specified goto string from dialplan.
- *
- * \note chan is locked by this function.
- *
- * \details Add a channel datastore to setup the goto location
- * when the channel leaves the bridge and run a PBX from there.
- *
- * If parseable_goto then use the given context/exten/priority
- *   as the relative position for the parseable_goto.
- * Else goto the given context/exten/priority+1.
- *
- * \return Nothing
- */
-void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto);
-
-/*!
- * \brief Setup any after bridge goto location to begin execution.
- * \since 12.0.0
- *
- * \param chan Channel to setup after bridge goto location.
- *
- * \note chan is locked by this function.
- *
- * \details Pull off any after bridge goto location datastore and
- * setup for dialplan execution there.
- *
- * \retval 0 on success.  The goto location is set for a PBX to run it.
- * \retval non-zero on error or no goto location.
- *
- * \note If the after bridge goto is set to run an h exten it is
- * run here immediately.
- */
-int ast_bridge_setup_after_goto(struct ast_channel *chan);
-
-/*!
- * \brief Run any after bridge callback.
- * \since 12.0.0
- *
- * \param chan Channel to run after bridge callback.
- *
- * \return Nothing
- */
-void ast_bridge_run_after_callback(struct ast_channel *chan);
-
-/*!
- * \brief Run discarding any after bridge callbacks.
- * \since 12.0.0
- *
- * \param chan Channel to run after bridge callback.
- *
- * \return Nothing
- */
-void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason);
-
-/*!
- * \brief Run a PBX on any after bridge goto location.
- * \since 12.0.0
- *
- * \param chan Channel to execute after bridge goto location.
- *
- * \note chan is locked by this function.
- *
- * \details Pull off any after bridge goto location datastore
- * and run a PBX at that location.
- *
- * \note On return, the chan pointer is no longer valid because
- * the channel has hung up.
- *
- * \return Nothing
- */
-void ast_bridge_run_after_goto(struct ast_channel *chan);
-
-/*!
- * \brief Discard channel after bridge goto location.
- * \since 12.0.0
- *
- * \param chan Channel to discard after bridge goto location.
- *
- * \note chan is locked by this function.
- *
- * \return Nothing
- */
-void ast_bridge_discard_after_goto(struct ast_channel *chan);
-
-/*!
- * \brief Read after bridge goto if it exists
- * \since 12.0.0
- *
- * \param chan Channel to read the after bridge goto parseable goto string from
- * \param buffer Buffer to write the after bridge goto data to
- * \param buf_size size of the buffer being written to
- */
-void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size);
-
-/*!
- * \brief After bridge callback failed.
- * \since 12.0.0
- *
- * \param reason Reason callback is failing.
- * \param data Extra data what setup the callback wanted to pass.
- *
- * \note Called when the channel leaves the bridging system or
- * is destroyed.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_after_cb_failed)(enum ast_bridge_after_cb_reason reason, void *data);
-
-/*!
- * \brief After bridge callback function.
- * \since 12.0.0
- *
- * \param chan Channel just leaving bridging system.
- * \param data Extra data what setup the callback wanted to pass.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_after_cb)(struct ast_channel *chan, void *data);
-
-/*!
- * \brief Setup an after bridge callback for when the channel leaves the bridging system.
- * \since 12.0.0
- *
- * \param chan Channel to setup an after bridge callback on.
- * \param callback Function to call when the channel leaves the bridging system.
- * \param failed Function to call when it will not be calling the callback.
- * \param data Extra data to pass with the callback.
- *
- * \note chan is locked by this function.
- *
- * \note failed is called when the channel leaves the bridging
- * system or is destroyed.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data);
-
-/*!
- * \brief Get a string representation of an after bridge callback reason
- * \since 12.0.0
- *
- * \param reason The reason to interpret to a string
- * \retval NULL Unrecognized reason
- * \retval non-NULL String representation of reason
- */
-const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_BRIDGING_H */
diff --git a/include/asterisk/bridge_basic.h b/include/asterisk/bridge_basic.h
deleted file mode 100644
index 483bf23..0000000
--- a/include/asterisk/bridge_basic.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Basic bridge subclass API.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_BRIDGING_BASIC_H
-#define _ASTERISK_BRIDGING_BASIC_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#define AST_TRANSFERER_ROLE_NAME "transferer"
-/* ------------------------------------------------------------------- */
-
-/*!
- * \brief Sets the features a channel will use upon being bridged.
- * \since 12.0.0
- *
- * \param chan Which channel to set features for
- * \param features Which feature codes to set for the channel
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_bridge_features_ds_set_string(struct ast_channel *chan, const char *features);
-
-/*!
- * \brief writes a channel's DTMF features to a buffer string
- * \since 12.0.0
- *
- * \param chan channel whose feature flags should be checked
- * \param buffer pointer string buffer where the output should be stored
- * \param buf_size size of the provided buffer (ideally enough for all features, 6+)
- *
- * \retval 0 on successful write
- * \retval -1 on failure
- */
-int ast_bridge_features_ds_get_string(struct ast_channel *chan, char *buffer, size_t buf_size);
-
-/*!
- * \brief Get DTMF feature flags from the channel.
- * \since 12.0.0
- *
- * \param chan Channel to get DTMF features datastore.
- *
- * \note The channel should be locked before calling this function.
- * \note The channel must remain locked until the flags returned have been consumed.
- *
- * \retval flags on success.
- * \retval NULL if the datastore does not exist.
- */
-struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan);
-
-/*!
- * \brief Set basic bridge DTMF feature flags datastore on the channel.
- * \since 12.0.0
- *
- * \param chan Channel to set DTMF features datastore.
- * \param flags Builtin DTMF feature flags. (ast_bridge_config flags)
- *
- * \note The channel must be locked before calling this function.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags);
-
-/*!
- * \brief Append basic bridge DTMF feature flags on the channel.
- * \since 12.0.0
- *
- * \param chan Channel to append DTMF features datastore.
- * \param flags Builtin DTMF feature flags. (ast_bridge_config flags)
- *
- * \note The channel must be locked before calling this function.
- * \note This function differs from ast_bridge_features_ds_set only in that it won't
- *       remove features already set on the channel.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_features_ds_append(struct ast_channel *chan, struct ast_flags *flags);
-
-/*! \brief Bridge basic class virtual method table. */
-extern struct ast_bridge_methods ast_bridge_basic_v_table;
-
-/*!
- * \brief Create a new basic class bridge
- *
- * \retval a pointer to a new bridge on success
- * \retval NULL on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge *bridge;
- * bridge = ast_bridge_basic_new();
- * \endcode
- *
- * This creates a basic two party bridge with any configured
- * DTMF features enabled that will be destroyed once one of the
- * channels hangs up.
- */
-struct ast_bridge *ast_bridge_basic_new(void);
-
-/*!
- * \brief Set feature flags on a basic bridge
- *
- * Using this function instead of setting flags directly will
- * ensure that after operations such as an attended transfer,
- * the bridge will maintain the flags that were set on it.
- *
- * \params Flags to set on the bridge. These are added to the flags already set.
- */
-void ast_bridge_basic_set_flags(struct ast_bridge *bridge, unsigned int flags);
-
-/*! Initialize the basic bridge class for use by the system. */
-void ast_bridging_init_basic(void);
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_BRIDGING_BASIC_H */
diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h
deleted file mode 100644
index 1d071a0..0000000
--- a/include/asterisk/bridge_channel.h
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- * Richard Mudgett <rmudgett at digium.com>
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \page AstBridgeChannel Bridging Channel API
- *
- * An API that act on a channel in a bridge. Note that while the
- * \ref ast_bridge_channel is owned by a channel, it should only be used
- * by members of the bridging system. The only places where this API should
- * be used is:
- *  \arg \ref AstBridging API itself
- *  \arg Bridge mixing technologies
- *  \arg Bridge sub-classes
- *
- * In general, anywhere else it is unsafe to use this API. Care should be
- * taken when using this API to ensure that the locking order remains
- * correct. The locking order must be:
- *  \arg The \ref \c ast_bridge
- *  \arg The \ref \c ast_bridge_channel
- *  \arg The \ref \c ast_channel
- *
- * \author Joshua Colp <jcolp at digium.com>
- * \author Richard Mudgett <rmudgett at digium.com>
- * \author Matt Jordan <mjordan at digium.com>
- *
- * See Also:
- * \arg \ref AstBridging
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_BRIDGING_CHANNEL_H
-#define _ASTERISK_BRIDGING_CHANNEL_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/bridge_features.h"
-#include "asterisk/bridge_technology.h"
-
-/*! \brief State information about a bridged channel */
-enum bridge_channel_state {
-	/*! Waiting for a signal (Channel in the bridge) */
-	BRIDGE_CHANNEL_STATE_WAIT = 0,
-	/*! Bridged channel was forced out and should be hung up (Bridge may dissolve.) */
-	BRIDGE_CHANNEL_STATE_END,
-	/*! Bridged channel was forced out. Don't dissolve the bridge regardless */
-	BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
-};
-
-enum bridge_channel_thread_state {
-	/*! Bridge channel thread is idle/waiting. */
-	BRIDGE_CHANNEL_THREAD_IDLE,
-	/*! Bridge channel thread is writing a normal/simple frame. */
-	BRIDGE_CHANNEL_THREAD_SIMPLE,
-	/*! Bridge channel thread is processing a frame. */
-	BRIDGE_CHANNEL_THREAD_FRAME,
-};
-
-struct ast_bridge;
-struct ast_bridge_tech_optimizations;
-
- /*!
- * \brief Structure that contains information regarding a channel in a bridge
- */
-struct ast_bridge_channel {
-/* XXX ASTERISK-21271 cond is only here because of external party suspend/unsuspend support. */
-	/*! Condition, used if we want to wake up a thread waiting on the bridged channel */
-	ast_cond_t cond;
-	/*! Current bridged channel state */
-	enum bridge_channel_state state;
-	/*! Asterisk channel participating in the bridge */
-	struct ast_channel *chan;
-	/*! Asterisk channel we are swapping with (if swapping) */
-	struct ast_channel *swap;
-	/*!
-	 * \brief Bridge this channel is participating in
-	 *
-	 * \note The bridge pointer cannot change while the bridge or
-	 * bridge_channel is locked.
-	 */
-	struct ast_bridge *bridge;
-	/*!
-	 * \brief Bridge class private channel data.
-	 *
-	 * \note This information is added when the channel is pushed
-	 * into the bridge and removed when it is pulled from the
-	 * bridge.
-	 */
-	void *bridge_pvt;
-	/*!
-	 * \brief Private information unique to the bridge technology.
-	 *
-	 * \note This information is added when the channel joins the
-	 * bridge's technology and removed when it leaves the bridge's
-	 * technology.
-	 */
-	void *tech_pvt;
-	/*! Thread handling the bridged channel (Needed by ast_bridge_depart) */
-	pthread_t thread;
-	/* v-- These flags change while the bridge is locked or before the channel is in the bridge. */
-	/*! TRUE if the channel is in a bridge. */
-	unsigned int in_bridge:1;
-	/*! TRUE if the channel just joined the bridge. */
-	unsigned int just_joined:1;
-	/*! TRUE if the channel is suspended from the bridge. */
-	unsigned int suspended:1;
-	/*! TRUE if the COLP update on initial join is inhibited. */
-	unsigned int inhibit_colp:1;
-	/*! TRUE if the channel must wait for an ast_bridge_depart to reclaim the channel. */
-	unsigned int depart_wait:1;
-	/* ^-- These flags change while the bridge is locked or before the channel is in the bridge. */
-	/*! Features structure for features that are specific to this channel */
-	struct ast_bridge_features *features;
-	/*! Technology optimization parameters used by bridging technologies capable of
-	 *  optimizing based upon talk detection. */
-	struct ast_bridge_tech_optimizations tech_args;
-	/*! Copy of read format used by chan before join */
-	struct ast_format *read_format;
-	/*! Copy of write format used by chan before join */
-	struct ast_format *write_format;
-	/*! Call ID associated with bridge channel */
-	struct ast_callid *callid;
-	/*! A clone of the roles living on chan when the bridge channel joins the bridge. This may require some opacification */
-	struct bridge_roles_datastore *bridge_roles;
-	/*! Linked list information */
-	AST_LIST_ENTRY(ast_bridge_channel) entry;
-	/*! Queue of outgoing frames to the channel. */
-	AST_LIST_HEAD_NOLOCK(, ast_frame) wr_queue;
-	/*! Pipe to alert thread when frames are put into the wr_queue. */
-	int alert_pipe[2];
-	/*!
-	 * \brief The bridge channel thread activity.
-	 *
-	 * \details Used by local channel optimization to determine if
-	 * the thread is in an acceptable state to optimize.
-	 *
-	 * \note Needs to be atomically settable.
-	 */
-	enum bridge_channel_thread_state activity;
-	/*! Owed events to the bridge. */
-	struct {
-		/*! Time started sending the current digit. (Invalid if owed.dtmf_digit is zero.) */
-		struct timeval dtmf_tv;
-		/*! Digit currently sending into the bridge. (zero if not sending) */
-		char dtmf_digit;
-	} owed;
-	/*! DTMF hook sequence state */
-	struct {
-		/*! Time at which the DTMF hooks should stop waiting for more digits to come. */
-		struct timeval interdigit_timeout;
-		/*! Collected DTMF digits for DTMF hooks. */
-		char collected[MAXIMUM_DTMF_FEATURE_STRING];
-	} dtmf_hook_state;
-};
-
-/*!
- * \brief Try locking the bridge_channel.
- *
- * \param bridge_channel What to try locking
- *
- * \retval 0 on success.
- * \retval non-zero on error.
- */
-#define ast_bridge_channel_trylock(bridge_channel)	_ast_bridge_channel_trylock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
-static inline int _ast_bridge_channel_trylock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
-{
-	return __ao2_trylock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
-}
-
-/*!
- * \brief Lock the bridge_channel.
- *
- * \param bridge_channel What to lock
- *
- * \return Nothing
- */
-#define ast_bridge_channel_lock(bridge_channel)	_ast_bridge_channel_lock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
-static inline void _ast_bridge_channel_lock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_lock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
-}
-
-/*!
- * \brief Unlock the bridge_channel.
- *
- * \param bridge_channel What to unlock
- *
- * \return Nothing
- */
-#define ast_bridge_channel_unlock(bridge_channel)	_ast_bridge_channel_unlock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
-static inline void _ast_bridge_channel_unlock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
-{
-	__ao2_unlock(bridge_channel, file, function, line, var);
-}
-
-/*!
- * \brief Lock the bridge associated with the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Channel that wants to lock the bridge.
- *
- * \details
- * This is an upstream lock operation.  The defined locking
- * order is bridge then bridge_channel.
- *
- * \note On entry, neither the bridge nor bridge_channel is locked.
- *
- * \note The bridge_channel->bridge pointer changes because of a
- * bridge-merge/channel-move operation between bridges.
- *
- * \return Nothing
- */
-void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Lets the bridging indicate when a bridge channel has stopped or started talking.
- *
- * \note All DSP functionality on the bridge has been pushed down to the lowest possible
- * layer, which in this case is the specific bridging technology being used. Since it
- * is necessary for the knowledge of which channels are talking to make its way up to the
- * application, this function has been created to allow the bridging technology to communicate
- * that information with the bridging core.
- *
- * \param bridge_channel The bridge channel that has either started or stopped talking.
- * \param started_talking set to 1 when this indicates the channel has started talking set to 0
- * when this indicates the channel has stopped talking.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking);
-
-/*!
- * \brief Set bridge channel state to leave bridge (if not leaving already).
- *
- * \param bridge_channel Channel to change the state on
- * \param new_state The new state to place the channel into
- * \param cause Cause of channel leaving bridge.
- *   If cause <= 0 then use cause on channel if cause still <= 0 use AST_CAUSE_NORMAL_CLEARING.
- *
- * Example usage:
- *
- * \code
- * ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, AST_CAUSE_NORMAL_CLEARING);
- * \endcode
- *
- * This places the channel pointed to by bridge_channel into the
- * state BRIDGE_CHANNEL_STATE_END if it was
- * BRIDGE_CHANNEL_STATE_WAIT before.
- */
-void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause);
-
-/*!
- * \brief Set bridge channel state to leave bridge (if not leaving already).
- *
- * \param bridge_channel Channel to change the state on
- * \param new_state The new state to place the channel into
- * \param cause Cause of channel leaving bridge.
- *   If cause <= 0 then use cause on channel if cause still <= 0 use AST_CAUSE_NORMAL_CLEARING.
- *
- * Example usage:
- *
- * \code
- * ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, AST_CAUSE_NORMAL_CLEARING);
- * \endcode
- *
- * This places the channel pointed to by bridge_channel into the
- * state BRIDGE_CHANNEL_STATE_END if it was
- * BRIDGE_CHANNEL_STATE_WAIT before.
- */
-void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause);
-
-/*!
- * \brief Get the peer bridge channel of a two party bridge.
- * \since 12.0.0
- *
- * \param bridge_channel What to get the peer of.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \note This is an internal bridge function.
- *
- * \retval peer on success.
- * \retval NULL no peer channel.
- */
-struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_internal_join
- * \since 12.0.0
- *
- * \param bridge_channel Channel to restore
- */
-void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Adjust the bridge_channel's bridge merge inhibit request count.
- * \since 12.0.0
- *
- * \param bridge_channel What to operate on.
- * \param request Inhibit request increment.
- *     (Positive to add requests.  Negative to remove requests.)
- *
- * \note This API call is meant for internal bridging operations.
- *
- * \retval bridge adjusted merge inhibit with reference count.
- */
-struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request);
-
-/*!
- * \internal
- * \brief Update the linkedids for all channels in a bridge
- * \since 12.0.0
- *
- * \param bridge_channel The channel joining the bridge
- * \param swap The channel being swapped out of the bridge. May be NULL.
- *
- * \note The bridge must be locked prior to calling this function.
- * \note This should be called during a \ref bridge_channel_internal_push
- * operation, typically by a sub-class of a bridge.
- */
-void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
-
-/*!
- * \internal
- * \brief Update the accountcodes for channels joining/leaving a bridge
- * \since 12.0.0
- *
- * This function updates the accountcode and peeraccount on channels in two-party
- * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense -
- * however accountcode propagation will still occur if the channel joining has an
- * accountcode.
- *
- * \param joining The channel joining the bridge.  May be NULL.
- * \param leaving The channel leaving or being swapped out of the bridge. May be NULL.
- *
- * \note The joining and leaving parameters cannot both be NULL.
- *
- * \note The bridge must be locked prior to calling this function.
- * \note This should be called during a \ref bridge_channel_internal_push
- * or \ref bridge_channel_internal_pull operation, typically by a
- * sub-class of a bridge.
- */
-void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *joining, struct ast_bridge_channel *leaving);
-
-/*!
- * \brief Write a frame to the specified bridge_channel.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to queue the frame.
- * \param fr Frame to write.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr);
-
-/*!
- * \brief Queue a control frame onto the bridge channel with data.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param control Type of control frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen);
-
-/*!
- * \brief Write a control frame into the bridge with data.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the frame into the bridge.
- * \param control Type of control frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen);
-
-/*!
- * \brief Write a hold frame into the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the hold into the bridge.
- * \param moh_class The suggested music class for the other end to use.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, const char *moh_class);
-
-/*!
- * \brief Write an unhold frame into the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the hold into the bridge.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Run an application on the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to run the application on.
- * \param app_name Dialplan application name.
- * \param app_args Arguments for the application. (NULL tolerant)
- * \param moh_class MOH class to request bridge peers to hear while application is running.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \return Nothing
- */
-void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
-
-/*!
- * \brief Write a bridge action run application frame into the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the frame into the bridge
- * \param app_name Dialplan application name.
- * \param app_args Arguments for the application. (NULL or empty for no arguments)
- * \param moh_class MOH class to request bridge peers to hear while application is running.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
-
-/*!
- * \brief Queue a bridge action run application frame onto the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to put the frame onto
- * \param app_name Dialplan application name.
- * \param app_args Arguments for the application. (NULL or empty for no arguments)
- * \param moh_class MOH class to request bridge peers to hear while application is running.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_queue_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
-
-/*!
- * \brief Custom interpretation of the playfile name.
- *
- * \param bridge_channel Which channel to play the file on
- * \param playfile Sound filename to play.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_custom_play_fn)(struct ast_bridge_channel *bridge_channel, const char *playfile);
-
-/*!
- * \brief Play a file on the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to play the file on
- * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
- * \param playfile Sound filename to play.
- * \param moh_class MOH class to request bridge peers to hear while file is played.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \return Nothing
- */
-void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
-
-/*!
- * \brief Write a bridge action play file frame into the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the frame into the bridge
- * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
- * \param playfile Sound filename to play.
- * \param moh_class MOH class to request bridge peers to hear while file is played.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
-
-/*!
- * \brief Queue a bridge action play file frame onto the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to put the frame onto.
- * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
- * \param playfile Sound filename to play.
- * \param moh_class MOH class to request bridge peers to hear while file is played.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
-
-/*!
- * \brief Synchronously queue a bridge action play file frame onto the bridge channel.
- * \since 12.2.0
- *
- * \param bridge_channel Which channel to put the frame onto.
- * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
- * \param playfile Sound filename to play.
- * \param moh_class MOH class to request bridge peers to hear while file is played.
- *     NULL if no MOH.
- *     Empty if default MOH class.
- *
- * This function will block until the queued frame has been destroyed. This will happen
- * either if an error occurs or if the queued playback finishes.
- *
- * \note No locks may be held when calling this function.
- *
- * \retval 0 The playback was successfully queued.
- * \retval -1 The playback could not be queued.
- */
-int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel,
-		ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
-
-/*!
- * \brief Custom callback run on a bridge channel.
- *
- * \param bridge_channel Which channel to operate on.
- * \param payload Data to pass to the callback. (NULL if none).
- * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
- *
- * \note The payload MUST NOT have any resources that need to be freed.
- *
- * \return Nothing
- */
-typedef void (*ast_bridge_custom_callback_fn)(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size);
-
-enum ast_bridge_channel_custom_callback_option {
-	/*! The callback temporarily affects media. (Like a custom playfile.) */
-	AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA = (1 << 0),
-};
-
-/*!
- * \brief Write a bridge action custom callback frame into the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is putting the frame into the bridge
- * \param flags Custom callback option flags.
- * \param callback Custom callback run on a bridge channel.
- * \param payload Data to pass to the callback. (NULL if none).
- * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
- *
- * \note The payload MUST NOT have any resources that need to be freed.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel,
-	enum ast_bridge_channel_custom_callback_option flags,
-	ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size);
-
-/*!
- * \brief Queue a bridge action custom callback frame onto the bridge channel.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to put the frame onto.
- * \param flags Custom callback option flags.
- * \param callback Custom callback run on a bridge channel.
- * \param payload Data to pass to the callback. (NULL if none).
- * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
- *
- * \note The payload MUST NOT have any resources that need to be freed.
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel,
-	enum ast_bridge_channel_custom_callback_option flags,
-	ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size);
-
-/*!
- * \brief Have a bridge channel park a channel in the bridge
- * \since 12.0.0
- *
- * \param bridge_channel Bridge channel performing the parking
- * \param parkee_uuid Unique id of the channel we want to park
- * \param parker_uuid Unique id of the channel parking the call
- * \param app_data string indicating data used for park application (NULL allowed)
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
-	const char *parker_uuid, const char *app_data);
-
-/*!
- * \brief Kick the channel out of the bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is being kicked or hungup.
- * \param cause Cause of channel being kicked.
- *   If cause <= 0 then use cause on channel if cause still <= 0 use AST_CAUSE_NORMAL_CLEARING.
- *
- * \note This is intended to be called by bridge hooks and the
- * bridge channel thread.
- *
- * \return Nothing
- */
-void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int cause);
-
-/*!
- * \brief Add a DTMF digit to the collected digits to match against DTMF features.
- * \since 12.8.0
- *
- * \param bridge_channel Channel that received a DTMF digit.
- * \param digit DTMF digit to add to collected digits or 0 for timeout event.
- *
- * \note Neither the bridge nor the bridge_channel locks should be held
- * when entering this function.
- *
- * \note This is intended to be called by bridge hooks and the
- * bridge channel thread.
- *
- * \return Nothing
- */
-void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, int digit);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_BRIDGING_CHANNEL_H */
diff --git a/include/asterisk/bridge_channel_internal.h b/include/asterisk/bridge_channel_internal.h
deleted file mode 100644
index b5a3a8d..0000000
--- a/include/asterisk/bridge_channel_internal.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
-#define _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
-
-/*!
- * \file
- * \brief Private Bridging Channel API
- *
- * \author Matt Jordan <mjordan at digium.com>
- *
- * A private API to manipulate channels in a bridge. These can be called on a channel in
- * a bridge by \ref bridge.c. These functions should not be called elsewhere, including
- * by other members of the Bridging API.
- *
- * See Also:
- * \arg \ref AstCREDITS
- * \arg \ref Ast
- */
-
-/*!
- * \internal
- * \brief Actions that can be taken on a channel in a bridge
- */
-enum bridge_channel_action_type {
-	/*! Bridged channel is to send a DTMF stream out */
-	BRIDGE_CHANNEL_ACTION_DTMF_STREAM,
-	/*! Bridged channel is to indicate talking start */
-	BRIDGE_CHANNEL_ACTION_TALKING_START,
-	/*! Bridged channel is to indicate talking stop */
-	BRIDGE_CHANNEL_ACTION_TALKING_STOP,
-	/*! Bridge channel is to play the indicated sound file. */
-	BRIDGE_CHANNEL_ACTION_PLAY_FILE,
-	/*! Bridge channel is to run the indicated application. */
-	BRIDGE_CHANNEL_ACTION_RUN_APP,
-	/*! Bridge channel is to run the custom callback routine. */
-	BRIDGE_CHANNEL_ACTION_CALLBACK,
-	/*! Bridge channel is to get parked. */
-	BRIDGE_CHANNEL_ACTION_PARK,
-	/*! Bridge channel is to execute a blind transfer. */
-	BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER,
-	/*! Bridge channel is to execute an attended transfer */
-	BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER,
-
-	/*
-	 * Bridge actions put after this comment must never be put onto
-	 * the bridge_channel wr_queue because they have other resources
-	 * that must be freed.
-	 */
-
-	/*! Bridge reconfiguration deferred technology destruction. */
-	BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY = 1000,
-	/*! Bridge deferred dissolving. */
-	BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING,
-};
-
-/*!
- * \internal
- * \brief Allocate a new ao2 ref counted bridge_channel
- * \since 12.0.0
- *
- * \param bridge The bridge to make the bridge_channel for
- *
- * \retval NULL on error
- * \retval ao2 ref counted object on success
- */
-struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge);
-
-/*!
- * \internal
- * \brief Clear owed events by the channel to the original bridge.
- * \since 12.0.0
- *
- * \param orig_bridge Original bridge the channel was in before leaving.
- * \param bridge_channel Channel that owes events to the original bridge.
- *
- * \note On entry, the orig_bridge is already locked.
- *
- * \return Nothing
- */
-void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Push the bridge channel into its specified bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to push.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.  The channel did not get pushed.
- *
- * \note On failure the caller must call
- * ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
- */
-int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Pull the bridge channel out of its current bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to pull.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \return Nothing
- */
-void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Join the bridge_channel to the bridge
- *
- * \param bridge_channel The Channel in the bridge
- *
- * \retval 0 bridge channel successfully joined the bridge
- * \retval -1 bridge channel failed to join the bridge
- *
- * \note This API call starts the bridge_channel's processing of events while
- * it is in the bridge. It will return when the channel has been instructed to
- * leave the bridge.
- */
-int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Temporarily suspend a channel from a bridge, handing control over to some
- * other system
- *
- * \param bridge_channel The channel in the bridge
- * \note This function assumes that \ref bridge_channel is already locked
- */
-void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Unsuspend a channel that was previously suspended
- *
- * \param bridge_channel The channel in the bridge
- * \note This function assumes that \ref bridge_channel is already locked
- */
-void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \internal
- * \brief Queue a blind transfer action on a transferee bridge channel
- *
- * This is only relevant for when a blind transfer is performed on a two-party
- * bridge. The transferee's bridge channel will have a blind transfer bridge
- * action queued onto it, resulting in the party being redirected to a new
- * destination
- *
- * \param transferee The channel to have the action queued on
- * \param exten The destination extension for the transferee
- * \param context The destination context for the transferee
- * \param hook Frame hook to attach to transferee
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int bridge_channel_internal_queue_blind_transfer(struct ast_channel *transferee,
-		const char *exten, const char *context,
-		transfer_channel_cb new_channel_cb, void *user_data);
-
-/*!
- * \internal
- * \brief Queue an attended transfer action on a transferee bridge channel
- *
- * This is only relevant for when an attended transfer is performed on a two-party
- * bridge. The transferee's bridge channel will have an attended transfer bridge
- * action queued onto it.
- *
- * \param transferee The channel to have the action queued on
- * \param unbridged_chan The unbridged channel who is the target of the attended
- * transfer
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int bridge_channel_internal_queue_attended_transfer(struct ast_channel *transferee,
-		struct ast_channel *unbridged_chan);
-
-/*!
- * \internal
- * \brief Return whether or not the bridge_channel would allow optimization
- *
- * \retval 0 if optimization is not allowed
- * \retval non-zero if optimization is allowed
- */
-int bridge_channel_internal_allows_optimization(struct ast_bridge_channel *bridge_channel);
-
-#endif /* _ASTERISK_PRIVATE_BRIDGING_H */
diff --git a/include/asterisk/bridge_features.h b/include/asterisk/bridge_features.h
deleted file mode 100644
index df01a0d..0000000
--- a/include/asterisk/bridge_features.h
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2009, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Channel Bridging API
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _ASTERISK_BRIDGING_FEATURES_H
-#define _ASTERISK_BRIDGING_FEATURES_H
-
-#include "asterisk/channel.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/*! \brief Flags used for bridge features */
-enum ast_bridge_feature_flags {
-	/*! Upon channel hangup all bridge participants should be kicked out. */
-	AST_BRIDGE_FLAG_DISSOLVE_HANGUP = (1 << 0),
-	/*! The last channel to leave the bridge dissolves it. */
-	AST_BRIDGE_FLAG_DISSOLVE_EMPTY = (1 << 1),
-	/*! Move between bridging technologies as needed. */
-	AST_BRIDGE_FLAG_SMART = (1 << 2),
-	/*! Bridge channels cannot be merged from this bridge. */
-	AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM = (1 << 3),
-	/*! Bridge channels cannot be merged to this bridge. */
-	AST_BRIDGE_FLAG_MERGE_INHIBIT_TO = (1 << 4),
-	/*! Bridge channels cannot be local channel swap optimized from this bridge. */
-	AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM = (1 << 5),
-	/*! Bridge channels cannot be local channel swap optimized to this bridge. */
-	AST_BRIDGE_FLAG_SWAP_INHIBIT_TO = (1 << 6),
-	/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
-	AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 7),
-	/*! Bridge does not allow transfers of channels out */
-	AST_BRIDGE_FLAG_TRANSFER_PROHIBITED = (1 << 8),
-	/*! Bridge transfers require transfer of entire bridge rather than individual channels */
-	AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY = (1 << 9),
-};
-
-/*! \brief Flags used for per bridge channel features */
-enum ast_bridge_channel_feature_flags {
-	/*! Upon channel hangup all bridge participants should be kicked out. */
-	AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP = (1 << 0),
-	/*! This channel leaves the bridge if all participants have this flag set. */
-	AST_BRIDGE_CHANNEL_FLAG_LONELY = (1 << 1),
-	/*! This channel cannot be moved to another bridge. */
-	AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE = (1 << 2),
-};
-
-/*! \brief Built in DTMF features */
-enum ast_bridge_builtin_feature {
-	/*! DTMF based Blind Transfer */
-	AST_BRIDGE_BUILTIN_BLINDTRANSFER,
-	/*! DTMF based Attended Transfer */
-	AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER,
-	/*!
-	 * DTMF based depart bridge feature
-	 *
-	 * \note Imparted channels are optionally hangup depending upon
-	 * how it was imparted.
-	 *
-	 * \note Joined channels exit the bridge with
-	 * BRIDGE_CHANNEL_STATE_END_WITH_DISSOLVE.
-	 */
-	AST_BRIDGE_BUILTIN_HANGUP,
-	/*!
-	 * DTMF based Park
-	 *
-	 * \details The bridge is parked and the channel hears the
-	 * parking slot to which it was parked.
-	 */
-	AST_BRIDGE_BUILTIN_PARKCALL,
-	/*!
-	 * DTMF one-touch-record toggle using Monitor app.
-	 *
-	 * \note Only valid on two party bridges.
-	 */
-	AST_BRIDGE_BUILTIN_AUTOMON,
-	/*!
-	 * DTMF one-touch-record toggle using MixMonitor app.
-	 *
-	 * \note Only valid on two party bridges.
-	 */
-	AST_BRIDGE_BUILTIN_AUTOMIXMON,
-
-	/*! End terminator for list of built in features. Must remain last. */
-	AST_BRIDGE_BUILTIN_END
-};
-
-enum ast_bridge_builtin_interval {
-	/*! Apply Call Duration Limits */
-	AST_BRIDGE_BUILTIN_INTERVAL_LIMITS,
-
-	/*! End terminator for list of built in interval features. Must remain last. */
-	AST_BRIDGE_BUILTIN_INTERVAL_END
-};
-
-struct ast_bridge;
-struct ast_bridge_channel;
-
-/*!
- * \brief Hook callback type
- *
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- *
- * For interval hooks:
- * \retval 0 Setup to fire again at the last interval.
- * \retval positive Setup to fire again at the new interval returned.
- * \retval -1 Remove the callback hook.
- *
- * For other hooks:
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-typedef int (*ast_bridge_hook_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt);
-
-/*!
- * \brief Hook pvt destructor callback
- *
- * \param hook_pvt Private data passed in when the hook was created to destroy
- */
-typedef void (*ast_bridge_hook_pvt_destructor)(void *hook_pvt);
-
-/*!
- * \brief Talking indicator callback
- *
- * \details
- * This callback can be registered with the bridge channel in
- * order to receive updates when the bridge_channel has started
- * and stopped talking.
- *
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- * \param talking TRUE if the channel is now talking
- *
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking);
-
-/*!
- * \brief Move indicator callback
- *
- * \details
- * This callback can be registered with the bridge channel in order
- * to be notified when the bridge channel is being moved from one
- * bridge to another.
- *
- * \param bridge_channel The channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- * \param src The bridge from which the bridge channel is moving
- * \param dst The bridge into which the bridge channel is moving
- *
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-typedef int (*ast_bridge_move_indicate_callback)(struct ast_bridge_channel *bridge_channel,
-		void *hook_pvt, struct ast_bridge *src, struct ast_bridge *dst);
-
-enum ast_bridge_hook_remove_flags {
-	/*! The hook is removed when the channel is pulled from the bridge. */
-	AST_BRIDGE_HOOK_REMOVE_ON_PULL = (1 << 0),
-	/*! The hook is removed when the bridge's personality changes. */
-	AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE = (1 << 1),
-};
-
-enum ast_bridge_hook_type {
-	/*! The hook type has not been specified. */
-	AST_BRIDGE_HOOK_TYPE_NONE,
-	AST_BRIDGE_HOOK_TYPE_DTMF,
-	AST_BRIDGE_HOOK_TYPE_TIMER,
-	AST_BRIDGE_HOOK_TYPE_HANGUP,
-	AST_BRIDGE_HOOK_TYPE_JOIN,
-	AST_BRIDGE_HOOK_TYPE_LEAVE,
-	AST_BRIDGE_HOOK_TYPE_TALK,
-	AST_BRIDGE_HOOK_TYPE_MOVE,
-};
-
-/*! \brief Structure that is the essence of a feature hook. */
-struct ast_bridge_hook {
-	/*! Callback that is called when hook is tripped */
-	ast_bridge_hook_callback callback;
-	/*! Callback to destroy hook_pvt data right before destruction. */
-	ast_bridge_hook_pvt_destructor destructor;
-	/*! Unique data that was passed into us */
-	void *hook_pvt;
-	/*! Flags determining when hooks should be removed from a bridge channel */
-	struct ast_flags remove_flags;
-	/*! What kind of hook this is. */
-	enum ast_bridge_hook_type type;
-};
-
-/*!
- * \brief Maximum length of a DTMF feature string
- */
-#define MAXIMUM_DTMF_FEATURE_STRING (11 + 1)
-
-/*! Extra parameters for a DTMF feature hook. */
-struct ast_bridge_hook_dtmf_parms {
-	/*! DTMF String that is examined during a feature hook lookup */
-	char code[MAXIMUM_DTMF_FEATURE_STRING];
-};
-
-/*! DTMF specific hook. */
-struct ast_bridge_hook_dtmf {
-	/*! Generic feature hook information. */
-	struct ast_bridge_hook generic;
-	/*! Extra parameters for a DTMF feature hook. */
-	struct ast_bridge_hook_dtmf_parms dtmf;
-};
-
-enum ast_bridge_hook_timer_option {
-	/*! The timer temporarily affects media. (Like a custom playfile.) */
-	AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA = (1 << 0),
-};
-
-/*! Extra parameters for an interval timer hook. */
-struct ast_bridge_hook_timer_parms {
-	/*! Time at which the hook should actually trip */
-	struct timeval trip_time;
-	/*! Heap index for interval hook */
-	ssize_t heap_index;
-	/*! Interval that the hook should execute at in milliseconds */
-	unsigned int interval;
-	/*! Sequence number for the hook to ensure expiration ordering */
-	unsigned int seqno;
-	/*! Option flags determining how callback is called. */
-	unsigned int flags;
-};
-
-/*! Timer specific hook. */
-struct ast_bridge_hook_timer {
-	/*! Generic feature hook information. */
-	struct ast_bridge_hook generic;
-	/*! Extra parameters for an interval timer hook. */
-	struct ast_bridge_hook_timer_parms timer;
-};
-
-/*!
- * \brief Structure that contains features information
- */
-struct ast_bridge_features {
-	/*! Attached DTMF feature hooks */
-	struct ao2_container *dtmf_hooks;
-	/*! Attached miscellaneous other hooks. */
-	struct ao2_container *other_hooks;
-	/*! Attached interval hooks */
-	struct ast_heap *interval_hooks;
-	/*! Feature flags that are enabled */
-	struct ast_flags feature_flags;
-	/*! Used to assign the sequence number to the next interval hook added. */
-	unsigned int interval_sequence;
-	/*! TRUE if feature_flags is setup */
-	unsigned int usable:1;
-	/*! TRUE if the channel/bridge is muted. */
-	unsigned int mute:1;
-	/*! TRUE if DTMF should be passed into the bridge tech.  */
-	unsigned int dtmf_passthrough:1;
-};
-
-/*!
- * \brief Structure that contains configuration information for the blind transfer built in feature
- */
-struct ast_bridge_features_blind_transfer {
-	/*! Context to use for transfers (If not empty.) */
-	char context[AST_MAX_CONTEXT];
-};
-
-/*!
- * \brief Structure that contains configuration information for the attended transfer built in feature
- */
-struct ast_bridge_features_attended_transfer {
-	/*! Context to use for transfers (If not empty.) */
-	char context[AST_MAX_CONTEXT];
-	/*! DTMF string used to abort the transfer (If not empty.) */
-	char abort[MAXIMUM_DTMF_FEATURE_STRING];
-	/*! DTMF string used to turn the transfer into a three way conference (If not empty.) */
-	char threeway[MAXIMUM_DTMF_FEATURE_STRING];
-	/*! DTMF string used to complete the transfer (If not empty.) */
-	char complete[MAXIMUM_DTMF_FEATURE_STRING];
-	/*! DTMF string used to swap bridged targets (If not empty.) */
-	char swap[MAXIMUM_DTMF_FEATURE_STRING];
-};
-
-enum ast_bridge_features_monitor {
-	/*! Toggle start/stop of Monitor/MixMonitor. */
-	AUTO_MONITOR_TOGGLE,
-	/*! Start Monitor/MixMonitor if not already started. */
-	AUTO_MONITOR_START,
-	/*! Stop Monitor/MixMonitor if not already stopped. */
-	AUTO_MONITOR_STOP,
-};
-
-struct ast_bridge_features_automonitor {
-	/*! Start/Stop behavior. */
-	enum ast_bridge_features_monitor start_stop;
-};
-
-struct ast_bridge_features_automixmonitor {
-	/*! Start/Stop behavior. */
-	enum ast_bridge_features_monitor start_stop;
-};
-
-/*!
- * \brief Structure that contains configuration information for the limits feature
- */
-struct ast_bridge_features_limits {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Sound file to play when the maximum duration is reached (if empty, then nothing will be played) */
-		AST_STRING_FIELD(duration_sound);
-		/*! Sound file to play when the warning time is reached (if empty, then the remaining time will be played) */
-		AST_STRING_FIELD(warning_sound);
-		/*! Sound file to play when the call is first entered (if empty, then the remaining time will be played) */
-		AST_STRING_FIELD(connect_sound);
-	);
-	/*! Time when the bridge will be terminated by the limits feature */
-	struct timeval quitting_time;
-	/*! Maximum duration that the channel is allowed to be in the bridge (specified in milliseconds) */
-	unsigned int duration;
-	/*! Duration into the call when warnings should begin (specified in milliseconds or 0 to disable) */
-	unsigned int warning;
-	/*! Interval between the warnings (specified in milliseconds or 0 to disable) */
-	unsigned int frequency;
-};
-
-/*!
- * \brief Register a handler for a built in feature
- *
- * \param feature The feature that the handler will be responsible for
- * \param callback The callback function that will handle it
- * \param dtmf Default DTMF string used to activate the feature
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge_builtin_attended_transfer, "*1");
- * \endcode
- *
- * This registers the function bridge_builtin_attended_transfer as the function responsible for the built in
- * attended transfer feature.
- */
-int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf);
-
-/*!
- * \brief Unregister a handler for a built in feature
- *
- * \param feature The feature to unregister
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER);
- * \endcode
- *
- * This unregisters the function that is handling the built in attended transfer feature.
- */
-int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
-
-/*!
- * \brief Invoke a built in feature hook now.
- *
- * \param feature The feature to invoke
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- *
- * \note This API call is only meant to be used by bridge
- * subclasses and hook callbacks to request a builtin feature
- * hook to be executed.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge_channel, hook_pvt);
- * \endcode
- */
-int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
-
-/*!
- * \brief Attach interval hooks to a bridge features structure
- *
- * \param features Bridge features structure
- * \param limits Configured limits applicable to the channel
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-typedef int (*ast_bridge_builtin_set_limits_fn)(struct ast_bridge_features *features,
-		struct ast_bridge_features_limits *limits, enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Register a handler for a built in interval feature
- *
- * \param interval The interval feature that the handler will be responsible for
- * \param callback the Callback function that will handle it
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS, bridge_builtin_set_limits);
- * \endcode
- *
- * This registers the function bridge_builtin_set_limits as the function responsible for the built in
- * duration limit feature.
- */
-int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, ast_bridge_builtin_set_limits_fn callback);
-
-/*!
- * \brief Unregisters a handler for a built in interval feature
- *
- * \param interval the interval feature to unregister
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_interval_unregister(AST_BRIDGE_BULTIN_INTERVAL_LIMITS)
- * /endcode
- *
- * This unregisters the function that is handling the built in duration limit feature.
- */
-int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval);
-
-/*!
- * \brief Attach a bridge channel join hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_join_hook(&features, join_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call join_callback when a
- * channel successfully joins the bridging system.  A pointer to
- * useful data may be provided to the hook_pvt parameter.
- */
-int ast_bridge_join_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach a bridge channel leave hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_leave_hook(&features, leave_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call leave_callback when a
- * channel successfully leaves the bridging system.  A pointer
- * to useful data may be provided to the hook_pvt parameter.
- */
-int ast_bridge_leave_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach a hangup hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_hangup_hook(&features, hangup_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call hangup_callback if a
- * channel that has this hook hangs up.  A pointer to useful
- * data may be provided to the hook_pvt parameter.
- */
-int ast_bridge_hangup_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach a DTMF hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param dtmf DTMF string to be activated upon
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_dtmf_hook(&features, "#", pound_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call pound_callback if a channel that has this
- * feature structure inputs the DTMF string '#'. A pointer to useful data may be
- * provided to the hook_pvt parameter.
- */
-int ast_bridge_dtmf_hook(struct ast_bridge_features *features,
-	const char *dtmf,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach an interval hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param flags Interval timer callback option flags.
- * \param interval The interval that the hook should execute at in milliseconds
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_interval_hook(&features, 1000, playback_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call playback_callback every second. A pointer to useful
- * data may be provided to the hook_pvt parameter.
- */
-int ast_bridge_interval_hook(struct ast_bridge_features *features,
-	enum ast_bridge_hook_timer_option flags,
-	unsigned int interval,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach a bridge channel talk detection hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_talk_hook(&features, talk_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging technology call talk_callback when a
- * channel is recognized as starting and stopping talking.  A
- * pointer to useful data may be provided to the hook_pvt
- * parameter.
- *
- * \note This hook is currently only supported by softmix.
- */
-int ast_bridge_talk_detector_hook(struct ast_bridge_features *features,
-	ast_bridge_talking_indicate_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Attach a bridge channel move detection hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_move_hook(&features, move_callback, NULL, NULL, 0);
- * \endcode
- *
- * This makes the bridging core call \ref callback when a
- * channel is moved from one bridge to another.  A
- * pointer to useful data may be provided to the hook_pvt
- * parameter.
- */
-int ast_bridge_move_hook(struct ast_bridge_features *features,
-	ast_bridge_move_indicate_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Enable a built in feature on a bridge features structure
- *
- * \param features Bridge features structure
- * \param feature Feature to enable
- * \param dtmf Optionally the DTMF stream to trigger the feature, if not specified it will be the default
- * \param config Configuration structure unique to the built in type
- * \param destructor Optional destructor callback for config data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL, NULL, 0);
- * \endcode
- *
- * This enables the attended transfer DTMF option using the default DTMF string. An alternate
- * string may be provided using the dtmf parameter. Internally this is simply setting up a hook
- * to a built in feature callback function.
- */
-int ast_bridge_features_enable(struct ast_bridge_features *features,
-	enum ast_bridge_builtin_feature feature,
-	const char *dtmf,
-	void *config,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Constructor function for ast_bridge_features_limits
- *
- * \param limits pointer to a ast_bridge_features_limits struct that has been allocted, but not initialized
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits);
-
-/*!
- * \brief Destructor function for ast_bridge_features_limits
- *
- * \param limits pointer to an ast_bridge_features_limits struct that needs to be destroyed
- *
- * This function does not free memory allocated to the ast_bridge_features_limits struct, it only frees elements within the struct.
- * You must still call ast_free on the the struct if you allocated it with malloc.
- */
-void ast_bridge_features_limits_destroy(struct ast_bridge_features_limits *limits);
-
-/*!
- * \brief Limit the amount of time a channel may stay in the bridge and optionally play warning messages as time runs out
- *
- * \param features Bridge features structure
- * \param limits Configured limits applicable to the channel
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * struct ast_bridge_features_limits limits;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_limits_construct(&limits);
- * ast_bridge_features_set_limits(&features, &limits, 0);
- * ast_bridge_features_limits_destroy(&limits);
- * \endcode
- *
- * This sets the maximum time the channel can be in the bridge to 10 seconds and does not play any warnings.
- *
- * \note This API call can only be used on a features structure that will be used in association with a bridge channel.
- * \note The ast_bridge_features_limits structure must remain accessible for the lifetime of the features structure.
- */
-int ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, enum ast_bridge_hook_remove_flags remove_flags);
-
-/*!
- * \brief Set a flag on a bridge channel features structure
- *
- * \param features Bridge channel features structure
- * \param flag Flag to enable
- *
- * \return Nothing
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_set_flag(&features, AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP);
- * \endcode
- *
- * This sets the AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP feature
- * to be enabled on the features structure 'features'.
- */
-void ast_bridge_features_set_flag(struct ast_bridge_features *features, unsigned int flag);
-
-/*!
- * \brief Merge one ast_bridge_features into another
- *
- * \param into The ast_bridge_features that will be merged into
- * \param from The ast_bridge_features that will be merged from
- */
-void ast_bridge_features_merge(struct ast_bridge_features *into, const struct ast_bridge_features *from);
-
-/*!
- * \brief Initialize bridge features structure
- *
- * \param features Bridge featues structure
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * \endcode
- *
- * This initializes the feature structure 'features' to have nothing enabled.
- *
- * \note This MUST be called before enabling features or flags. Failure to do so
- *       may result in a crash.
- */
-int ast_bridge_features_init(struct ast_bridge_features *features);
-
-/*!
- * \brief Clean up the contents of a bridge features structure
- *
- * \param features Bridge features structure
- *
- * \return Nothing
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_cleanup(&features);
- * \endcode
- *
- * This cleans up the feature structure 'features'.
- *
- * \note This MUST be called after the features structure is done being used
- *       or a memory leak may occur.
- */
-void ast_bridge_features_cleanup(struct ast_bridge_features *features);
-
-/*!
- * \brief Allocate a new bridge features struct.
- * \since 12.0.0
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features *features;
- * features = ast_bridge_features_new();
- * ast_bridge_features_destroy(features);
- * \endcode
- *
- * \retval features New allocated features struct.
- * \retval NULL on error.
- */
-struct ast_bridge_features *ast_bridge_features_new(void);
-
-/*!
- * \brief Destroy an allocated bridge features struct.
- * \since 12.0.0
- *
- * \param features Bridge features structure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features *features;
- * features = ast_bridge_features_new();
- * ast_bridge_features_destroy(features);
- * \endcode
- *
- * \return Nothing
- */
-void ast_bridge_features_destroy(struct ast_bridge_features *features);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_BRIDGING_FEATURES_H */
diff --git a/include/asterisk/bridge_internal.h b/include/asterisk/bridge_internal.h
deleted file mode 100644
index e50e7f9..0000000
--- a/include/asterisk/bridge_internal.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Private Bridging API
- *
- * Functions in this file are intended to be used by the Bridging API,
- * bridge mixing technologies, and bridge sub-classes. Users of bridges
- * that do not fit those three categories should *not* use the API
- * defined in this file.
- *
- * \author Mark Michelson <mmichelson at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_PRIVATE_BRIDGING_H
-#define _ASTERISK_PRIVATE_BRIDGING_H
-
-struct ast_bridge;
-struct ast_bridge_channel;
-struct ast_bridge_methods;
-
-/*!
- * \brief Register the new bridge with the system.
- * \since 12.0.0
- *
- * \param bridge What to register. (Tolerates a NULL pointer)
- *
- * \code
- * struct ast_bridge *ast_bridge_basic_new(uint32_t capabilities, int flags, uint32 dtmf_features)
- * {
- *     void *bridge;
- *
- *     bridge = bridge_alloc(sizeof(struct ast_bridge_basic), &ast_bridge_basic_v_table);
- *     bridge = bridge_base_init(bridge, capabilities, flags);
- *     bridge = ast_bridge_basic_init(bridge, dtmf_features);
- *     bridge = bridge_register(bridge);
- *     return bridge;
- * }
- * \endcode
- *
- * \note This must be done after a bridge constructor has
- * completed setting up the new bridge but before it returns.
- *
- * \note After a bridge is registered, ast_bridge_destroy() must
- * eventually be called to get rid of the bridge.
- *
- * \retval bridge on success.
- * \retval NULL on error.
- */
-struct ast_bridge *bridge_register(struct ast_bridge *bridge);
-
-/*!
- * \internal
- * \brief Allocate the bridge class object memory.
- * \since 12.0.0
- *
- * \param size Size of the bridge class structure to allocate.
- * \param v_table Bridge class virtual method table.
- *
- * \retval bridge on success.
- * \retval NULL on error.
- */
-struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_table);
-
-/*!
- * \brief Initialize the base class of the bridge.
- *
- * \param self Bridge to operate upon. (Tolerates a NULL pointer)
- * \param capabilities The capabilities that we require to be used on the bridge
- * \param flags Flags that will alter the behavior of the bridge
- * \param creator Entity that created the bridge (optional)
- * \param name Name given to the bridge by its creator (optional, requires named creator)
- * \param id Unique ID given to the bridge by its creator (optional)
- *
- * \retval self on success
- * \retval NULL on failure, self is already destroyed
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge *bridge;
- * bridge = bridge_alloc(sizeof(*bridge), &ast_bridge_base_v_table);
- * bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP, NULL, NULL, NULL);
- * \endcode
- *
- * This creates a no frills two party bridge that will be
- * destroyed once one of the channels hangs up.
- */
-struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id);
-
-/*!
- * \internal
- * \brief Move a bridge channel from one bridge to another.
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of bridge channel move.
- * \param bridge_channel Channel moving from one bridge to another.
- * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
- * \param optimized Indicates whether the move is part of an unreal channel optimization.
- *
- * \note The dst_bridge and bridge_channel->bridge are assumed already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel,
-		int attempt_recovery, unsigned int optimized);
-
-/*!
- * \internal
- * \brief Do the merge of two bridges.
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of merge.
- * \param src_bridge Source bridge of merge.
- * \param kick_me Array of channels to kick from the bridges.
- * \param num_kick Number of channels in the kick_me array.
- * \param optimized Indicates whether the merge is part of an unreal channel optimization.
- *
- * \return Nothing
- *
- * \note The two bridges are assumed already locked.
- *
- * This moves the channels in src_bridge into the bridge pointed
- * to by dst_bridge.
- */
-void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge,
-		struct ast_bridge_channel **kick_me, unsigned int num_kick, unsigned int optimized);
-
-/*!
- * \internal
- * \brief Helper function to find a bridge channel given a channel.
- *
- * \param bridge What to search
- * \param chan What to search for.
- *
- * \note On entry, bridge is already locked.
- *
- * \retval bridge_channel if channel is in the bridge.
- * \retval NULL if not in bridge.
- */
-struct ast_bridge_channel *bridge_find_channel(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \internal
- * \brief Adjust the bridge merge inhibit request count.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- * \param request Inhibit request increment.
- *     (Positive to add requests.  Negative to remove requests.)
- *
- * \note This function assumes bridge is locked.
- *
- * \return Nothing
- */
-void bridge_merge_inhibit_nolock(struct ast_bridge *bridge, int request);
-
-/*!
- * \internal
- * \brief Notify the bridge that it has been reconfigured.
- * \since 12.0.0
- *
- * \param bridge Reconfigured bridge.
- * \param colp_update Whether to perform COLP updates.
- *
- * \details
- * After a series of bridge_channel_internal_push and
- * bridge_channel_internal_pull calls, you need to call this function
- * to cause the bridge to complete restructuring for the change
- * in the channel makeup of the bridge.
- *
- * \note On entry, the bridge is already locked.
- *
- * \return Nothing
- */
-void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update);
-
-/*!
- * \internal
- * \brief Dissolve the bridge.
- * \since 12.0.0
- *
- * \param bridge Bridge to eject all channels
- * \param cause Cause of bridge being dissolved.  (If cause <= 0 then use AST_CAUSE_NORMAL_CLEARING)
- *
- * \details
- * Force out all channels that are not already going out of the
- * bridge.  Any new channels joining will leave immediately.
- *
- * \note On entry, bridge is already locked.
- *
- * \return Nothing
- */
-void bridge_dissolve(struct ast_bridge *bridge, int cause);
-
-#endif /* _ASTERISK_PRIVATE_BRIDGING_H */
diff --git a/include/asterisk/bridge_roles.h b/include/asterisk/bridge_roles.h
deleted file mode 100644
index f91a6b0..0000000
--- a/include/asterisk/bridge_roles.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Channel Bridging Roles API
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#ifndef _ASTERISK_BRIDGING_ROLES_H
-#define _ASTERISK_BRIDGING_ROLES_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/linkedlists.h"
-
-#define AST_ROLE_LEN 32
-
-/*!
- * \brief Adds a bridge role to a channel
- *
- * \param chan Acquirer of the requested role
- * \param role_name Name of the role being attached
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name);
-
-/*!
- * \brief Removes a bridge role from a channel
- *
- * \param chan Channel the role is being removed from
- * \param role_name Name of the role being removed
- */
-void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name);
-
-/*!
- * \brief Removes all bridge roles currently on a channel
- *
- * \param chan Channel the roles are being removed from
- */
-void ast_channel_clear_bridge_roles(struct ast_channel *chan);
-
-/*!
- * \brief Set a role option on a channel
- * \param channel Channel receiving the role option
- * \param role_name Role the role option is applied to
- * \param option Name of the option
- * \param value Value of the option
- *
- * \param 0 on success
- * \retval -1 on failure
- */
-int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value);
-
-/*!
- * \brief Check if a role exists on a channel
- *
- * \param channel The channel to check
- * \param role_name The name of the role to search for
- *
- * \retval 0 The requested role does not exist on the channel
- * \retval 1 The requested role exists on the channel
- *
- * This is an alternative to \ref ast_bridge_channel_has_role that is useful if bridge
- * roles have not yet been established on a channel's bridge_channel. A possible example of
- * when this could be used is in a bridge v_table's push() callback.
- */
-int ast_channel_has_role(struct ast_channel *channel, const char *role_name);
-
-/*!
- * \brief Retrieve the value of a requested role option from a channel
- *
- * \param channel The channel to retrieve the requested option from
- * \param role_name The role to which the option belongs
- * \param option The name of the option to retrieve
- *
- * \retval NULL The option does not exist
- * \retval non-NULL The value of the option
- *
- * This is an alternative to \ref ast_bridge_channel_get_role_option that is useful if bridge
- * roles have not yet been esstablished on a channel's bridge_channel. A possible example of
- * when this could be used is in a bridge v_table's push() callback.
- */
-const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option);
-
-/*!
- * \brief Check to see if a bridge channel inherited a specific role from its channel
- *
- * \param bridge_channel The bridge channel being checked
- * \param role_name Name of the role being checked
- *
- * \retval 0 The bridge channel does not have the requested role
- * \retval 1 The bridge channel does have the requested role
- *
- * \note Before a bridge_channel can effectively check roles against a bridge, ast_bridge_channel_establish_roles
- *       should be called on the bridge_channel so that roles and their respective role options can be copied from the channel
- *       datastore into the bridge_channel roles list. Otherwise this function will just return 0 because the list will be NULL.
- */
-int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name);
-
-/*!
- * \brief Retrieve the value of a requested role option from a bridge channel
- *
- * \param bridge_channel The bridge channel we are retrieving the option from
- * \param role_name Name of the role the option will be retrieved from
- * \param option Name of the option we are retrieving the value of
- *
- * \retval NULL If either the role does not exist on the bridge_channel or the role does exist but the option has not been set
- * \retval The value of the option
- *
- * \note See ast_channel_set_role_option note about the need to call ast_bridge_channel_establish_roles.
- *
- * \note The returned character pointer is only valid as long as the bridge_channel is guaranteed to be alive and hasn't had
- *       ast_bridge_channel_clear_roles called against it (as this will free all roles and role options in the bridge
- *       channel). If you need this value after one of these destruction events occurs, you must make a local copy while it is
- *       still valid.
- */
-const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option);
-
-/*!
- * \brief Clone the roles from a bridge_channel's attached ast_channel onto the bridge_channel's role list
- *
- * \param bridge_channel The bridge channel that we are preparing
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \details
- * This function should always be called when the bridge_channel binds to an ast_channel at some point before the bridge_channel
- * joins or is imparted onto a bridge. Failure to do so will result in an empty role list. While the list remains established,
- * changes to roles on the ast_channel will not propogate to the bridge channel and roles can not be re-established on the bridge
- * channel without first clearing the roles with ast_bridge_roles_bridge_channel_clear_roles.
- */
-int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Clear all roles from a bridge_channel's role list
- *
- * \param bridge_channel the bridge channel that we are scrubbing
- *
- * \details
- * If roles are already established on a bridge channel, ast_bridge_channel_establish_roles will fail unconditionally
- * without changing any roles. In order to update a bridge channel's roles, they must first be cleared from the bridge channel using
- * this function.
- *
- * \note
- * ast_bridge_channel_clear_roles also serves as the destructor for the role list of a bridge channel.
- */
-void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_BRIDGING_ROLES_H */
diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h
new file mode 100644
index 0000000..6a397e3
--- /dev/null
+++ b/include/asterisk/bridging.h
@@ -0,0 +1,590 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2007 - 2009, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Channel Bridging API
+ * \author Joshua Colp <jcolp at digium.com>
+ * \ref AstBridging
+ */
+
+/*!
+ * \page AstBridging Channel Bridging API
+ *
+ * The purpose of this API is to provide an easy and flexible way to bridge
+ * channels of different technologies with different features.
+ *
+ * Bridging technologies provide the mechanism that do the actual handling
+ * of frames between channels. They provide capability information, codec information,
+ * and preference value to assist the bridging core in choosing a bridging technology when
+ * creating a bridge. Different bridges may use different bridging technologies based on needs
+ * but once chosen they all operate under the same premise; they receive frames and send frames.
+ *
+ * Bridges are a combination of bridging technology, channels, and features. A
+ * developer creates a new bridge based on what they are currently expecting to do
+ * with it or what they will do with it in the future. The bridging core determines what
+ * available bridging technology will best fit the requirements and creates a new bridge.
+ * Once created, channels can be added to the bridge in a blocking or non-blocking fashion.
+ *
+ * Features are such things as channel muting or DTMF based features such as attended transfer,
+ * blind transfer, and hangup. Feature information must be set at the most granular level, on
+ * the channel. While you can use features on a global scope the presence of a feature structure
+ * on the channel will override the global scope. An example would be having the bridge muted
+ * at global scope and attended transfer enabled on a channel. Since the channel itself is not muted
+ * it would be able to speak.
+ *
+ * Feature hooks allow a developer to tell the bridging core that when a DTMF string
+ * is received from a channel a callback should be called in their application. For
+ * example, a conference bridge application may want to provide an IVR to control various
+ * settings on the conference bridge. This can be accomplished by attaching a feature hook
+ * that calls an IVR function when a DTMF string is entered.
+ *
+ */
+
+#ifndef _ASTERISK_BRIDGING_H
+#define _ASTERISK_BRIDGING_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "asterisk/bridging_features.h"
+#include "asterisk/dsp.h"
+
+/*! \brief Capabilities for a bridge technology */
+enum ast_bridge_capability {
+	/*! Bridge is only capable of mixing 2 channels */
+	AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 1),
+	/*! Bridge is capable of mixing 2 or more channels */
+	AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 2),
+	/*! Bridge should natively bridge two channels if possible */
+	AST_BRIDGE_CAPABILITY_NATIVE = (1 << 3),
+	/*! Bridge should run using the multithreaded model */
+	AST_BRIDGE_CAPABILITY_MULTITHREADED = (1 << 4),
+	/*! Bridge should run a central bridge thread */
+	AST_BRIDGE_CAPABILITY_THREAD = (1 << 5),
+	/*! Bridge technology can do video mixing (or something along those lines) */
+	AST_BRIDGE_CAPABILITY_VIDEO = (1 << 6),
+	/*! Bridge technology can optimize things based on who is talking */
+	AST_BRIDGE_CAPABILITY_OPTIMIZE = (1 << 7),
+};
+
+/*! \brief State information about a bridged channel */
+enum ast_bridge_channel_state {
+	/*! Waiting for a signal */
+	AST_BRIDGE_CHANNEL_STATE_WAIT = 0,
+	/*! Bridged channel has ended itself (it has hung up) */
+	AST_BRIDGE_CHANNEL_STATE_END,
+	/*! Bridged channel should be hung up */
+	AST_BRIDGE_CHANNEL_STATE_HANGUP,
+	/*! Bridged channel should be removed from the bridge without being hung up */
+	AST_BRIDGE_CHANNEL_STATE_DEPART,
+	/*! Bridged channel is executing a feature hook */
+	AST_BRIDGE_CHANNEL_STATE_FEATURE,
+	/*! Bridged channel is sending a DTMF stream out */
+	AST_BRIDGE_CHANNEL_STATE_DTMF,
+	/*! Bridged channel began talking */
+	AST_BRIDGE_CHANNEL_STATE_START_TALKING,
+	/*! Bridged channel has stopped talking */
+	AST_BRIDGE_CHANNEL_STATE_STOP_TALKING,
+};
+
+/*! \brief Return values for bridge technology write function */
+enum ast_bridge_write_result {
+	/*! Bridge technology wrote out frame fine */
+	AST_BRIDGE_WRITE_SUCCESS = 0,
+	/*! Bridge technology attempted to write out the frame but failed */
+	AST_BRIDGE_WRITE_FAILED,
+	/*! Bridge technology does not support writing out a frame of this type */
+	AST_BRIDGE_WRITE_UNSUPPORTED,
+};
+
+struct ast_bridge_technology;
+struct ast_bridge;
+
+/*!
+ * \brief Structure specific to bridge technologies capable of
+ * performing talking optimizations.
+ */
+struct ast_bridge_tech_optimizations {
+	/*! The amount of time in ms that talking must be detected before
+	 *  the dsp determines that talking has occurred */
+	unsigned int talking_threshold;
+	/*! The amount of time in ms that silence must be detected before
+	 *  the dsp determines that talking has stopped */
+	unsigned int silence_threshold;
+	/*! Whether or not the bridging technology should drop audio
+	 *  detected as silence from the mix. */
+	unsigned int drop_silence:1;
+};
+
+/*!
+ * \brief Structure that contains information regarding a channel in a bridge
+ */
+struct ast_bridge_channel {
+	/*! Lock to protect this data structure */
+	ast_mutex_t lock;
+	/*! Condition, used if we want to wake up a thread waiting on the bridged channel */
+	ast_cond_t cond;
+	/*! Current bridged channel state */
+	enum ast_bridge_channel_state state;
+	/*! Asterisk channel participating in the bridge */
+	struct ast_channel *chan;
+	/*! Asterisk channel we are swapping with (if swapping) */
+	struct ast_channel *swap;
+	/*! Bridge this channel is participating in */
+	struct ast_bridge *bridge;
+	/*! Private information unique to the bridge technology */
+	void *bridge_pvt;
+	/*! Thread handling the bridged channel */
+	pthread_t thread;
+	/*! Additional file descriptors to look at */
+	int fds[4];
+	/*! Bit to indicate whether the channel is suspended from the bridge or not */
+	unsigned int suspended:1;
+	/*! Bit to indicate if a imparted channel is allowed to get hungup after leaving the bridge by the bridging core. */
+	unsigned int allow_impart_hangup:1;
+	/*! Features structure for features that are specific to this channel */
+	struct ast_bridge_features *features;
+	/*! Technology optimization parameters used by bridging technologies capable of
+	 *  optimizing based upon talk detection. */
+	struct ast_bridge_tech_optimizations tech_args;
+	/*! Queue of DTMF digits used for DTMF streaming */
+	char dtmf_stream_q[8];
+	/*! Call ID associated with bridge channel */
+	struct ast_callid *callid;
+	/*! Linked list information */
+	AST_LIST_ENTRY(ast_bridge_channel) entry;
+};
+
+enum ast_bridge_video_mode_type {
+	/*! Video is not allowed in the bridge */
+	AST_BRIDGE_VIDEO_MODE_NONE = 0,
+	/*! A single user is picked as the only distributed of video across the bridge */
+	AST_BRIDGE_VIDEO_MODE_SINGLE_SRC,
+	/*! A single user's video feed is distributed to all bridge channels, but
+	 *  that feed is automatically picked based on who is talking the most. */
+	AST_BRIDGE_VIDEO_MODE_TALKER_SRC,
+};
+
+/*! This is used for both SINGLE_SRC mode to set what channel
+ *  should be the current single video feed */
+struct ast_bridge_video_single_src_data {
+	/*! Only accept video coming from this channel */
+	struct ast_channel *chan_vsrc;
+};
+
+/*! This is used for both SINGLE_SRC_TALKER mode to set what channel
+ *  should be the current single video feed */
+struct ast_bridge_video_talker_src_data {
+	/*! Only accept video coming from this channel */
+	struct ast_channel *chan_vsrc;
+	int average_talking_energy;
+
+	/*! Current talker see's this person */
+	struct ast_channel *chan_old_vsrc;
+};
+
+struct ast_bridge_video_mode {
+	enum ast_bridge_video_mode_type mode;
+	/* Add data for all the video modes here. */
+	union {
+		struct ast_bridge_video_single_src_data single_src_data;
+		struct ast_bridge_video_talker_src_data talker_src_data;
+	} mode_data;
+};
+
+/*!
+ * \brief Structure that contains information about a bridge
+ */
+struct ast_bridge {
+	/*! Number of channels participating in the bridge */
+	int num;
+	/*! The video mode this bridge is using */
+	struct ast_bridge_video_mode video_mode;
+	/*! The internal sample rate this bridge is mixed at when multiple channels are being mixed.
+	 *  If this value is 0, the bridge technology may auto adjust the internal mixing rate. */
+	unsigned int internal_sample_rate;
+	/*! The mixing interval indicates how quickly the bridges internal mixing should occur
+	 * for bridge technologies that mix audio. When set to 0, the bridge tech must choose a
+	 * default interval for itself. */
+	unsigned int internal_mixing_interval;
+	/*! Bit to indicate that the bridge thread is waiting on channels in the bridge array */
+	unsigned int waiting:1;
+	/*! Bit to indicate the bridge thread should stop */
+	unsigned int stop:1;
+	/*! Bit to indicate the bridge thread should refresh itself */
+	unsigned int refresh:1;
+	/*! Bridge flags to tweak behavior */
+	struct ast_flags feature_flags;
+	/*! Bridge technology that is handling the bridge */
+	struct ast_bridge_technology *technology;
+	/*! Private information unique to the bridge technology */
+	void *bridge_pvt;
+	/*! Thread running the bridge */
+	pthread_t thread;
+	/*! Enabled features information */
+	struct ast_bridge_features features;
+	/*! Array of channels that the bridge thread is currently handling */
+	struct ast_channel **array;
+	/*! Number of channels in the above array */
+	size_t array_num;
+	/*! Number of channels the array can handle */
+	size_t array_size;
+	/*! Call ID associated with the bridge */
+	struct ast_callid *callid;
+	/*! Linked list of channels participating in the bridge */
+	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
+	};
+
+/*! \brief Create a new bridge
+ *
+ * \param capabilities The capabilities that we require to be used on the bridge
+ * \param flags Flags that will alter the behavior of the bridge
+ *
+ * \retval a pointer to a new bridge on success
+ * \retval NULL on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge *bridge;
+ * bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE);
+ * \endcode
+ *
+ * This creates a simple two party bridge that will be destroyed once one of
+ * the channels hangs up.
+ */
+struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags);
+
+/*!
+ * \brief Lock the bridge.
+ *
+ * \param bridge Bridge to lock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_lock(bridge)	_ast_bridge_lock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline void _ast_bridge_lock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+	__ao2_lock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
+
+/*!
+ * \brief Unlock the bridge.
+ *
+ * \param bridge Bridge to unlock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_unlock(bridge)	_ast_bridge_unlock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline void _ast_bridge_unlock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+	__ao2_unlock(bridge, file, function, line, var);
+}
+
+/*! \brief See if it is possible to create a bridge
+ *
+ * \param capabilities The capabilities that the bridge will use
+ *
+ * \retval 1 if possible
+ * \retval 0 if not possible
+ *
+ * Example usage:
+ *
+ * \code
+ * int possible = ast_bridge_check(AST_BRIDGE_CAPABILITY_1TO1MIX);
+ * \endcode
+ *
+ * This sees if it is possible to create a bridge capable of bridging two channels
+ * together.
+ */
+int ast_bridge_check(uint32_t capabilities);
+
+/*! \brief Destroy a bridge
+ *
+ * \param bridge Bridge to destroy
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_destroy(bridge);
+ * \endcode
+ *
+ * This destroys a bridge that was previously created using ast_bridge_new.
+ */
+int ast_bridge_destroy(struct ast_bridge *bridge);
+
+/*! \brief Join (blocking) a channel to a bridge
+ *
+ * \param bridge Bridge to join
+ * \param chan Channel to join
+ * \param swap Channel to swap out if swapping
+ * \param features Bridge features structure
+ * \param (Optional) Bridging tech optimization parameters for this channel.
+ *
+ * \retval state that channel exited the bridge with
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_join(bridge, chan, NULL, NULL);
+ * \endcode
+ *
+ * This adds a channel pointed to by the chan pointer to the bridge pointed to by
+ * the bridge pointer. This function will not return until the channel has been
+ * removed from the bridge, swapped out for another channel, or has hung up.
+ *
+ * If this channel will be replacing another channel the other channel can be specified
+ * in the swap parameter. The other channel will be thrown out of the bridge in an
+ * atomic fashion.
+ *
+ * If channel specific features are enabled a pointer to the features structure
+ * can be specified in the features parameter.
+ */
+enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+	struct ast_channel *chan,
+	struct ast_channel *swap,
+	struct ast_bridge_features *features,
+	struct ast_bridge_tech_optimizations *tech_args);
+
+/*! \brief Impart (non-blocking) a channel on a bridge
+ *
+ * \param bridge Bridge to impart on
+ * \param chan Channel to impart
+ * \param swap Channel to swap out if swapping
+ * \param features Bridge features structure
+ * \param allow_hangup  Indicates if the bridge thread should manage hanging up of the channel or not.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_impart(bridge, chan, NULL, NULL, 0);
+ * \endcode
+ *
+ * This adds a channel pointed to by the chan pointer to the bridge pointed to by
+ * the bridge pointer. This function will return immediately and will not wait
+ * until the channel is no longer part of the bridge.
+ *
+ * If this channel will be replacing another channel the other channel can be specified
+ * in the swap parameter. The other channel will be thrown out of the bridge in an
+ * atomic fashion.
+ *
+ * If channel specific features are enabled a pointer to the features structure
+ * can be specified in the features parameter.
+ */
+int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, int allow_hangup);
+
+/*! \brief Depart a channel from a bridge
+ *
+ * \param bridge Bridge to depart from
+ * \param chan Channel to depart
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_depart(bridge, chan);
+ * \endcode
+ *
+ * This removes the channel pointed to by the chan pointer from the bridge
+ * pointed to by the bridge pointer and gives control to the calling thread.
+ * This does not hang up the channel.
+ *
+ * \note This API call can only be used on channels that were added to the bridge
+ *       using the ast_bridge_impart API call.
+ */
+int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*! \brief Remove a channel from a bridge
+ *
+ * \param bridge Bridge that the channel is to be removed from
+ * \param chan Channel to remove
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_remove(bridge, chan);
+ * \endcode
+ *
+ * This removes the channel pointed to by the chan pointer from the bridge
+ * pointed to by the bridge pointer and requests that it be hung up. Control
+ * over the channel will NOT be given to the calling thread.
+ *
+ * \note This API call can be used on channels that were added to the bridge
+ *       using both ast_bridge_join and ast_bridge_impart.
+ */
+int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*! \brief Merge two bridges together
+ *
+ * \param bridge0 First bridge
+ * \param bridge1 Second bridge
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_merge(bridge0, bridge1);
+ * \endcode
+ *
+ * This merges the bridge pointed to by bridge1 with the bridge pointed to by bridge0.
+ * In reality all of the channels in bridge1 are simply moved to bridge0.
+ *
+ * \note The second bridge specified is not destroyed when this operation is
+ *       completed.
+ */
+int ast_bridge_merge(struct ast_bridge *bridge0, struct ast_bridge *bridge1);
+
+/*! \brief Suspend a channel temporarily from a bridge
+ *
+ * \param bridge Bridge to suspend the channel from
+ * \param chan Channel to suspend
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_suspend(bridge, chan);
+ * \endcode
+ *
+ * This suspends the channel pointed to by chan from the bridge pointed to by bridge temporarily.
+ * Control of the channel is given to the calling thread. This differs from ast_bridge_depart as
+ * the channel will not be removed from the bridge.
+ *
+ * \note This API call can be used on channels that were added to the bridge
+ *       using both ast_bridge_join and ast_bridge_impart.
+ */
+int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*! \brief Unsuspend a channel from a bridge
+ *
+ * \param bridge Bridge to unsuspend the channel from
+ * \param chan Channel to unsuspend
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_unsuspend(bridge, chan);
+ * \endcode
+ *
+ * This unsuspends the channel pointed to by chan from the bridge pointed to by bridge.
+ * The bridge will go back to handling the channel once this function returns.
+ *
+ * \note You must not mess with the channel once this function returns.
+ *       Doing so may result in bad things happening.
+ */
+int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*! \brief Change the state of a bridged channel
+ *
+ * \param bridge_channel Channel to change the state on
+ * \param new_state The new state to place the channel into
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+ * \endcode
+ *
+ * This places the channel pointed to by bridge_channel into the state
+ * AST_BRIDGE_CHANNEL_STATE_WAIT.
+ *
+ * \note This API call is only meant to be used in feature hook callbacks to
+ *       make sure the channel either hangs up or returns to the bridge.
+ */
+void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
+
+/*! \brief Adjust the internal mixing sample rate of a bridge used during
+ *         multimix mode.
+ *
+ * \param bridge_channel Channel to change the sample rate on.
+ * \param sample rate, the sample rate to change to. If a
+ *        value of 0 is passed here, the bridge will be free to pick
+ *        what ever sample rate it chooses.
+ *
+ */
+void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate);
+
+/*! \brief Adjust the internal mixing interval of a bridge used during
+ *         multimix mode.
+ *
+ * \param bridge_channel Channel to change the sample rate on.
+ * \param mixing_interval, the sample rate to change to.  If 0 is set
+ * the bridge tech is free to choose any mixing interval it uses by default.
+ */
+void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval);
+
+/*!
+ * \brief Set a bridge to feed a single video source to all participants.
+ */
+void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan);
+
+/*!
+ * \brief Set the bridge to pick the strongest talker supporting
+ * video as the single source video feed
+ */
+void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge);
+
+/*!
+ * \brief Update information about talker energy for talker src video mode.
+ */
+void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyfame);
+
+/*!
+ * \brief Returns the number of video sources currently active in the bridge
+ */
+int ast_bridge_number_video_src(struct ast_bridge *bridge);
+
+/*!
+ * \brief Determine if a channel is a video src for the bridge
+ *
+ * \retval 0 Not a current video source of the bridge.
+ * \retval None 0, is a video source of the bridge, The number
+ *         returned represents the priority this video stream has
+ *         on the bridge where 1 is the highest priority.
+ */
+int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*!
+ * \brief remove a channel as a source of video for the bridge.
+ */
+void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_BRIDGING_H */
diff --git a/include/asterisk/bridging_features.h b/include/asterisk/bridging_features.h
new file mode 100644
index 0000000..e377ca6
--- /dev/null
+++ b/include/asterisk/bridging_features.h
@@ -0,0 +1,354 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2009, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Channel Bridging API
+ * \author Joshua Colp <jcolp at digium.com>
+ */
+
+#ifndef _ASTERISK_BRIDGING_FEATURES_H
+#define _ASTERISK_BRIDGING_FEATURES_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*! \brief Flags used for bridge features */
+enum ast_bridge_feature_flags {
+	/*! Upon hangup the bridge should be discontinued */
+	AST_BRIDGE_FLAG_DISSOLVE = (1 << 0),
+	/*! Move between bridging technologies as needed. */
+	AST_BRIDGE_FLAG_SMART = (1 << 1),
+};
+
+/*! \brief Built in features */
+enum ast_bridge_builtin_feature {
+	/*! DTMF Based Blind Transfer */
+	AST_BRIDGE_BUILTIN_BLINDTRANSFER = 0,
+	/*! DTMF Based Attended Transfer */
+	AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER,
+	/*! DTMF Based Hangup Feature */
+	AST_BRIDGE_BUILTIN_HANGUP,
+	/*! End terminator for list of built in features. Must remain last. */
+	AST_BRIDGE_BUILTIN_END,
+};
+
+struct ast_bridge;
+struct ast_bridge_channel;
+
+/*!
+ * \brief Features hook callback type
+ *
+ * \param bridge The bridge that the channel is part of
+ * \param bridge_channel Channel executing the feature
+ * \param hook_pvt Private data passed in when the hook was created
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+typedef int (*ast_bridge_features_hook_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
+
+/*!
+ * \brief Features hook pvt destructor callback
+ *
+ * \param hook_pvt Private data passed in when the hook was create to destroy
+ */
+typedef void (*ast_bridge_features_hook_pvt_destructor)(void *hook_pvt);
+
+/*!
+ * \brief Talking indicator callback
+ *
+ * \details This callback can be registered with the bridge in order
+ * to receive updates on when a bridge_channel has started and stopped
+ * talking
+ *
+ * \param bridge The bridge that the channel is part of
+ * \param bridge_channel Channel executing the feature
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data);
+
+
+typedef void (*ast_bridge_talking_indicate_destructor)(void *pvt_data);
+
+/*!
+ * \brief Maximum length of a DTMF feature string
+ */
+#define MAXIMUM_DTMF_FEATURE_STRING 8
+
+/*!
+ * \brief Structure that is the essence of a features hook
+ */
+struct ast_bridge_features_hook {
+	/*! DTMF String that is examined during a feature hook lookup */
+	char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
+	/*! Callback that is called when DTMF string is matched */
+	ast_bridge_features_hook_callback callback;
+	/*! Callback to destroy hook_pvt data right before destruction. */
+	ast_bridge_features_hook_pvt_destructor destructor;
+	/*! Unique data that was passed into us */
+	void *hook_pvt;
+	/*! Linked list information */
+	AST_LIST_ENTRY(ast_bridge_features_hook) entry;
+};
+
+/*!
+ * \brief Structure that contains features information
+ */
+struct ast_bridge_features {
+	/*! Attached DTMF based feature hooks */
+	AST_LIST_HEAD_NOLOCK(, ast_bridge_features_hook) hooks;
+	/*! Callback to indicate when a bridge channel has started and stopped talking */
+	ast_bridge_talking_indicate_callback talker_cb;
+	/*! Callback to destroy any pvt data stored for the talker. */
+	ast_bridge_talking_indicate_destructor talker_destructor_cb;
+	/*! Talker callback pvt data */
+	void *talker_pvt_data;
+	/*! Feature flags that are enabled */
+	struct ast_flags feature_flags;
+	/*! Bit to indicate that the hook list is useful and should be considered when looking for DTMF features */
+	unsigned int usable:1;
+	/*! Bit to indicate whether the channel/bridge is muted or not */
+	unsigned int mute:1;
+	/*! Bit to indicate whether DTMF should be passed into the bridge tech or not.  */
+	unsigned int dtmf_passthrough:1;
+
+};
+
+/*!
+ * \brief Structure that contains configuration information for the blind transfer built in feature
+ */
+struct ast_bridge_features_blind_transfer {
+	/*! Context to use for transfers */
+	char context[AST_MAX_CONTEXT];
+};
+
+/*!
+ * \brief Structure that contains configuration information for the attended transfer built in feature
+ */
+struct ast_bridge_features_attended_transfer {
+	/*! DTMF string used to abort the transfer */
+	char abort[MAXIMUM_DTMF_FEATURE_STRING];
+	/*! DTMF string used to turn the transfer into a three way conference */
+	char threeway[MAXIMUM_DTMF_FEATURE_STRING];
+	/*! DTMF string used to complete the transfer */
+	char complete[MAXIMUM_DTMF_FEATURE_STRING];
+	/*! Context to use for transfers */
+	char context[AST_MAX_CONTEXT];
+};
+
+/*! \brief Register a handler for a built in feature
+ *
+ * \param feature The feature that the handler will be responsible for
+ * \param callback The callback function that will handle it
+ * \param dtmf Default DTMF string used to activate the feature
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge_builtin_attended_transfer, "*1");
+ * \endcode
+ *
+ * This registers the function bridge_builtin_attended_transfer as the function responsible for the built in
+ * attended transfer feature.
+ */
+int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_features_hook_callback callback, const char *dtmf);
+
+/*! \brief Unregister a handler for a built in feature
+ *
+ * \param feature The feature to unregister
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER);
+ * \endcode
+ *
+ * This unregisters the function that is handling the built in attended transfer feature.
+ */
+int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
+
+/*! \brief Attach a custom hook to a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param dtmf DTMF string to be activated upon
+ * \param callback Function to execute upon activation
+ * \param hook_pvt Unique data
+ * \param Optional destructor callback for hook_pvt data
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_hook(&features, "#", pound_callback, NULL, NULL);
+ * \endcode
+ *
+ * This makes the bridging core call pound_callback if a channel that has this
+ * feature structure inputs the DTMF string '#'. A pointer to useful data may be
+ * provided to the hook_pvt parameter.
+ *
+ * \note It is important that the callback set the bridge channel state back to
+ *       AST_BRIDGE_CHANNEL_STATE_WAIT or the bridge thread will not service the channel.
+ */
+int ast_bridge_features_hook(struct ast_bridge_features *features,
+	const char *dtmf,
+	ast_bridge_features_hook_callback callback,
+	void *hook_pvt,
+	ast_bridge_features_hook_pvt_destructor destructor);
+
+/*! \brief Set a callback on the features structure to receive talking notifications on.
+ *
+ * \param features Bridge features structure
+ * \param talker_cb, Callback function to execute when talking events occur in the bridge core.
+ * \param pvt_data Optional unique data that will be passed with the talking events.
+ * \param Optional destructor callback for pvt data.
+ *
+ * \retval 0, success
+ * \retval -1, failure
+ */
+int ast_bridge_features_set_talk_detector(struct ast_bridge_features *features,
+	ast_bridge_talking_indicate_callback talker_cb,
+	ast_bridge_talking_indicate_destructor talker_destructor,
+	void *pvt_data);
+
+/*! \brief Enable a built in feature on a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param feature Feature to enable
+ * \param dtmf Optionally the DTMF stream to trigger the feature, if not specified it will be the default
+ * \param config Configuration structure unique to the built in type
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL);
+ * \endcode
+ *
+ * This enables the attended transfer DTMF option using the default DTMF string. An alternate
+ * string may be provided using the dtmf parameter. Internally this is simply setting up a hook
+ * to a built in feature callback function.
+ */
+int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config);
+
+/*! \brief Set a flag on a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param flag Flag to enable
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_set_flag(&features, AST_BRIDGE_FLAG_DISSOLVE);
+ * \endcode
+ *
+ * This sets the AST_BRIDGE_FLAG_DISSOLVE feature to be enabled on the features structure
+ * 'features'.
+ */
+int ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag);
+
+/*! \brief Initialize bridge features structure
+ *
+ * \param features Bridge featues structure
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * \endcode
+ *
+ * This initializes the feature structure 'features' to have nothing enabled.
+ *
+ * \note This MUST be called before enabling features or flags. Failure to do so
+ *       may result in a crash.
+ */
+int ast_bridge_features_init(struct ast_bridge_features *features);
+
+/*! \brief Clean up the contents of a bridge features structure
+ *
+ * \param features Bridge features structure
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_cleanup(&features);
+ * \endcode
+ *
+ * This cleans up the feature structure 'features'.
+ *
+ * \note This MUST be called after the features structure is done being used
+ *       or a memory leak may occur.
+ */
+int ast_bridge_features_cleanup(struct ast_bridge_features *features);
+
+/*! \brief Play a DTMF stream into a bridge, optionally not to a given channel
+ *
+ * \param bridge Bridge to play stream into
+ * \param dtmf DTMF to play
+ * \param chan Channel to optionally not play to
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_dtmf_stream(bridge, "0123456789", NULL);
+ * \endcode
+ *
+ * This sends the DTMF digits '0123456789' to all channels in the bridge pointed to
+ * by the bridge pointer. Optionally a channel may be excluded by passing it's channel pointer
+ * using the chan parameter.
+ */
+int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct ast_channel *chan);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_BRIDGING_FEATURES_H */
diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridging_technology.h
similarity index 50%
rename from include/asterisk/bridge_technology.h
rename to include/asterisk/bridging_technology.h
index 9c39f74..3d2e870 100644
--- a/include/asterisk/bridge_technology.h
+++ b/include/asterisk/bridging_technology.h
@@ -28,33 +28,14 @@
 extern "C" {
 #endif
 
-/*!
- * \brief Base preference values for choosing a bridge technology.
- *
- * \note Higher is more preference.
- */
+/*! \brief Preference for choosing the bridge technology */
 enum ast_bridge_preference {
-	AST_BRIDGE_PREFERENCE_BASE_HOLDING  = 50,
-	AST_BRIDGE_PREFERENCE_BASE_EARLY    = 100,
-	AST_BRIDGE_PREFERENCE_BASE_NATIVE   = 90,
-	AST_BRIDGE_PREFERENCE_BASE_1TO1MIX  = 50,
-	AST_BRIDGE_PREFERENCE_BASE_MULTIMIX = 10,
-};
-
-/*!
- * \brief Structure specific to bridge technologies capable of
- * performing talking optimizations.
- */
-struct ast_bridge_tech_optimizations {
-	/*! The amount of time in ms that talking must be detected before
-	 *  the dsp determines that talking has occurred */
-	unsigned int talking_threshold;
-	/*! The amount of time in ms that silence must be detected before
-	 *  the dsp determines that talking has stopped */
-	unsigned int silence_threshold;
-	/*! Whether or not the bridging technology should drop audio
-	 *  detected as silence from the mix. */
-	unsigned int drop_silence:1;
+	/*! Bridge technology should have high precedence over other bridge technologies */
+	AST_BRIDGE_PREFERENCE_HIGH = 0,
+	/*! Bridge technology is decent, not the best but should still be considered over low */
+	AST_BRIDGE_PREFERENCE_MEDIUM,
+	/*! Bridge technology is low, it should not be considered unless it is absolutely needed */
+	AST_BRIDGE_PREFERENCE_LOW,
 };
 
 /*!
@@ -68,102 +49,39 @@ struct ast_bridge_technology {
 	uint32_t capabilities;
 	/*! Preference level that should be used when determining whether to use this bridge technology or not */
 	enum ast_bridge_preference preference;
-	/*!
-	 * \brief Create a bridge technology instance for a bridge.
-	 *
-	 * \retval 0 on success
-	 * \retval -1 on failure
-	 *
-	 * \note On entry, bridge may or may not already be locked.
-	 * However, it can be accessed as if it were locked.
-	 */
+	/*! Callback for when a bridge is being created */
 	int (*create)(struct ast_bridge *bridge);
-	/*!
-	 * \brief Request a bridge technology instance start operations.
-	 *
-	 * \retval 0 on success
-	 * \retval -1 on failure
-	 *
-	 * \note On entry, bridge may or may not already be locked.
-	 * However, it can be accessed as if it were locked.
-	 */
-	int (*start)(struct ast_bridge *bridge);
-	/*!
-	 * \brief Request a bridge technology instance stop in preparation for being destroyed.
-	 *
-	 * \note On entry, bridge is already locked.
-	 */
-	void (*stop)(struct ast_bridge *bridge);
-	/*!
-	 * \brief Destroy a bridging technology instance for a bridge.
-	 *
-	 * \note On entry, bridge must NOT be locked.
-	 */
-	void (*destroy)(struct ast_bridge *bridge);
-	/*!
-	 * \brief Add a channel to a bridging technology instance for a bridge.
-	 *
-	 * \retval 0 on success
-	 * \retval -1 on failure
-	 *
-	 * \note On entry, bridge is already locked.
-	 */
+	/*! Callback for when a bridge is being destroyed */
+	int (*destroy)(struct ast_bridge *bridge);
+	/*! Callback for when a channel is being added to a bridge */
 	int (*join)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-	/*!
-	 * \brief Remove a channel from a bridging technology instance for a bridge.
-	 *
-	 * \note On entry, bridge is already locked.
-	 * \note Do not make assumptions about the number of channels in the bridge when
-	 * this callback is called. When a channel is swapped into a bridge for another
-	 * channel, the leave callback is called after the new channel has been added to
-	 * the bridge.
-	 */
-	void (*leave)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-	/*!
-	 * \brief Suspend a channel on a bridging technology instance for a bridge.
-	 *
-	 * \note On entry, bridge is already locked.
-	 */
+	/*! Callback for when a channel is leaving a bridge */
+	int (*leave)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
+	/*! Callback for when a channel is suspended from the bridge */
 	void (*suspend)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-	/*!
-	 * \brief Unsuspend a channel on a bridging technology instance for a bridge.
-	 *
-	 * \note On entry, bridge is already locked.
-	 */
+	/*! Callback for when a channel is unsuspended from the bridge */
 	void (*unsuspend)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-	/*!
-	 * \brief Check if a bridge is compatible with the bridging technology.
-	 *
-	 * \retval 0 if not compatible
-	 * \retval non-zero if compatible
-	 *
-	 * \note On entry, bridge may or may not already be locked.
-	 * However, it can be accessed as if it were locked.
-	 */
-	int (*compatible)(struct ast_bridge *bridge);
-	/*!
-	 * \brief Write a frame into the bridging technology instance for a bridge.
-	 *
-	 * \note The bridge must be tolerant of bridge_channel being NULL.
-	 *
-	 * \retval 0 Frame accepted into the bridge.
-	 * \retval -1 Frame needs to be deferred.
-	 *
-	 * \note On entry, bridge is already locked.
-	 */
-	int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame);
+	/*! Callback to see if a channel is compatible with the bridging technology */
+	int (*compatible)(struct ast_bridge_channel *bridge_channel);
+	/*! Callback for writing a frame into the bridging technology */
+	enum ast_bridge_write_result (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridged_channel, struct ast_frame *frame);
+	/*! Callback for when a file descriptor trips */
+	int (*fd)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int fd);
+	/*! Callback for replacement thread function */
+	int (*thread)(struct ast_bridge *bridge);
+	/*! Callback for poking a bridge thread */
+	int (*poke)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
 	/*! Formats that the bridge technology supports */
 	struct ast_format_cap *format_capabilities;
-	/*! TRUE if the bridge technology is currently suspended. */
+	/*! Bit to indicate whether the bridge technology is currently suspended or not */
 	unsigned int suspended:1;
-	/*! Module this bridge technology belongs to. It is used for reference counting bridges using the technology. */
+	/*! Module this bridge technology belongs to. Is used for reference counting when creating/destroying a bridge. */
 	struct ast_module *mod;
 	/*! Linked list information */
 	AST_RWLIST_ENTRY(ast_bridge_technology) entry;
 };
 
-/*!
- * \brief Register a bridge technology for use
+/*! \brief Register a bridge technology for use
  *
  * \param technology The bridge technology to register
  * \param mod The module that is registering the bridge technology
@@ -186,8 +104,7 @@ int __ast_bridge_technology_register(struct ast_bridge_technology *technology, s
 /*! \brief See \ref __ast_bridge_technology_register() */
 #define ast_bridge_technology_register(technology) __ast_bridge_technology_register(technology, ast_module_info->self)
 
-/*!
- * \brief Unregister a bridge technology from use
+/*! \brief Unregister a bridge technology from use
  *
  * \param technology The bridge technology to unregister
  *
@@ -206,8 +123,42 @@ int __ast_bridge_technology_register(struct ast_bridge_technology *technology, s
  */
 int ast_bridge_technology_unregister(struct ast_bridge_technology *technology);
 
-/*!
- * \brief Suspend a bridge technology from consideration
+/*! \brief Feed notification that a frame is waiting on a channel into the bridging core
+ *
+ * \param bridge The bridge that the notification should influence
+ * \param bridge_channel Bridge channel the notification was received on (if known)
+ * \param chan Channel the notification was received on (if known)
+ * \param outfd File descriptor that the notification was received on (if known)
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_handle_trip(bridge, NULL, chan, -1);
+ * \endcode
+ *
+ * This tells the bridging core that a frame has been received on
+ * the channel pointed to by chan and that it should be read and handled.
+ *
+ * \note This should only be used by bridging technologies.
+ */
+void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd);
+
+/*! \brief Lets the bridging indicate when a bridge channel has stopped or started talking.
+ *
+ * \note All DSP functionality on the bridge has been pushed down to the lowest possible
+ * layer, which in this case is the specific bridging technology being used. Since it
+ * is necessary for the knowledge of which channels are talking to make its way up to the
+ * application, this function has been created to allow the bridging technology to communicate
+ * that information with the bridging core.
+ *
+ * \param bridge The bridge that the channel is a part of.
+ * \param bridge_channel The bridge channel that has either started or stopped talking.
+ * \param started_talking, set to 1 when this indicates the channel has started talking, set to 0
+ * when this indicates the channel has stopped talking.
+ */
+void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking);
+
+/*! \brief Suspend a bridge technology from consideration
  *
  * \param technology The bridge technology to suspend
  *
@@ -223,8 +174,7 @@ int ast_bridge_technology_unregister(struct ast_bridge_technology *technology);
  */
 void ast_bridge_technology_suspend(struct ast_bridge_technology *technology);
 
-/*!
- * \brief Unsuspend a bridge technology
+/*! \brief Unsuspend a bridge technology
  *
  * \param technology The bridge technology to unsuspend
  *
diff --git a/include/asterisk/bucket.h b/include/asterisk/bucket.h
deleted file mode 100644
index c07fb0c..0000000
--- a/include/asterisk/bucket.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Bucket File API
- * \author Joshua Colp <jcolp at digium.com>
- * \ref AstBucket
- */
-
-/*!
- * \page AstBucket Bucket File API
- *
- * Bucket is an API which provides directory and file access in a generic fashion. It is
- * implemented as a thin wrapper over the sorcery data access layer API and is written in
- * a pluggable fashion to allow different backend storage mechanisms.
- *
- */
-
-#ifndef _ASTERISK_BUCKET_H
-#define _ASTERISK_BUCKET_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/sorcery.h"
-
-/*! \brief Opaque structure for internal details about a scheme */
-struct ast_bucket_scheme;
-
-/*! \brief Bucket metadata structure, AO2 key value pair */
-struct ast_bucket_metadata {
-	/*! \brief Name of the attribute */
-	const char *name;
-	/*! \brief Value of the attribute */
-	const char *value;
-	/*! \brief Storage for the above name and value */
-	char data[0];
-};
-
-/*! \brief Bucket structure, contains other buckets and files */
-struct ast_bucket {
-	/*! \brief Sorcery object information */
-	SORCERY_OBJECT(details);
-	/*! \brief Scheme implementation in use */
-	struct ast_bucket_scheme *scheme_impl;
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! \brief Name of scheme in use */
-		AST_STRING_FIELD(scheme);
-	);
-	/*! \brief When this bucket was created */
-	struct timeval created;
-	/*! \brief When this bucket was last modified */
-	struct timeval modified;
-	/*! \brief Container of string URIs of buckets within this bucket */
-	struct ao2_container *buckets;
-	/*! \brief Container of string URIs of files within this bucket */
-	struct ao2_container *files;
-};
-
-/*! \brief Bucket file structure, contains reference to file and information about it */
-struct ast_bucket_file {
-	/*! \brief Sorcery object information */
-	SORCERY_OBJECT(details);
-	/*! \brief Scheme implementation in use */
-	struct ast_bucket_scheme *scheme_impl;
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! \brief Name of scheme in use */
-		AST_STRING_FIELD(scheme);
-	);
-	/*! \brief When this file was created */
-	struct timeval created;
-	/*! \brief When this file was last modified */
-	struct timeval modified;
-	/*! \brief Container of metadata attributes about file */
-	struct ao2_container *metadata;
-	/*! \brief Local path to this file */
-	char path[PATH_MAX];
-};
-
-/*!
- * \brief A callback function invoked when creating a file snapshot
- *
- * \param file Pointer to the file snapshot
- *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef int (*bucket_file_create_cb)(struct ast_bucket_file *file);
-
-/*!
- * \brief A callback function invoked when destroying a file snapshot
- *
- * \param file Pointer to the file snapshot
- */
-typedef void (*bucket_file_destroy_cb)(struct ast_bucket_file *file);
-
-/*!
- * \brief Initialize bucket support
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_init(void);
-
-/*!
- * \brief Register support for a specific scheme
- *
- * \param name Name of the scheme, used to find based on scheme in URIs
- * \param bucket Sorcery wizard used for buckets
- * \param file Sorcery wizard used for files
- * \param create_cb Required file snapshot creation callback
- * \param destroy_cb Optional file snapshot destruction callback
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note Once a scheme has been registered it can not be unregistered
- */
-#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb) __ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb, ast_module_info ? ast_module_info->self : NULL)
-
-/*!
- * \brief Register support for a specific scheme
- *
- * \param name Name of the scheme, used to find based on scheme in URIs
- * \param bucket Sorcery wizard used for buckets
- * \param file Sorcery wizard used for files
- * \param create_cb Required file snapshot creation callback
- * \param destroy_cb Optional file snapshot destruction callback
- * \param module The module which implements this scheme
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note Once a scheme has been registered it can not be unregistered
- */
-int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket,
-	struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb,
-	bucket_file_destroy_cb destroy_cb, struct ast_module *module);
-
-/*!
- * \brief Set a metadata attribute on a file to a specific value
- *
- * \param file The bucket file
- * \param name Name of the attribute
- * \param value Value of the attribute
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note This function will overwrite an existing attribute of the same name, unless an error
- * occurs. If an error occurs the existing attribute is left alone.
- */
-int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value);
-
-/*!
- * \brief Unset a specific metadata attribute on a file
- *
- * \param file The bucket file
- * \param name Name of the attribute
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_file_metadata_unset(struct ast_bucket_file *file, const char *name);
-
-/*!
- * \brief Retrieve a metadata attribute from a file
- *
- * \param file The bucket file
- * \param name Name of the attribute
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note The object is returned with reference count increased
- */
-struct ast_bucket_metadata *ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name);
-
-/*!
- * \brief Allocate a new bucket
- *
- * \param uri Complete URI for the bucket
- *
- * \param non-NULL success
- * \param NULL failure
- *
- * \note This only creates a local bucket object, to persist in backend storage you must call
- * ast_bucket_create
- */
-struct ast_bucket *ast_bucket_alloc(const char *uri);
-
-/*!
- * \brief Create a new bucket in backend storage
- *
- * \param bucket The bucket
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_create(struct ast_bucket *bucket);
-
-/*!
- * \brief Delete a bucket from backend storage
- *
- * \param bucket The bucket
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_delete(struct ast_bucket *bucket);
-
-/*!
- * \brief Retrieve information about a bucket
- *
- * \param uri Complete URI of the bucket
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note The object is returned with reference count increased
- */
-struct ast_bucket *ast_bucket_retrieve(const char *uri);
-
-/*!
- * \brief Add an observer for bucket creation and deletion operations
- *
- * \param callbacks Implementation of the sorcery observer interface
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_bucket_observer_add(const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Remove an observer from bucket creation and deletion
- *
- * \param callbacks Implementation of the sorcery observer interface
- */
-void ast_bucket_observer_remove(const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Get a JSON representation of a bucket
- *
- * \param bucket The specific bucket
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note The returned ast_json object must be unreferenced using ast_json_unref
- */
-struct ast_json *ast_bucket_json(const struct ast_bucket *bucket);
-
-/*!
- * \brief Allocate a new bucket file
- *
- * \param uri Complete URI for the bucket file
- *
- * \param non-NULL success
- * \param NULL failure
- *
- * \note This only creates a local bucket file object, to persist in backend storage you must call
- * ast_bucket_file_create
- */
-struct ast_bucket_file *ast_bucket_file_alloc(const char *uri);
-
-/*!
- * \brief Create a new bucket file in backend storage
- *
- * \param file The bucket file
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_file_create(struct ast_bucket_file *file);
-
-/*!
- * \brief Copy a bucket file to a new URI
- *
- * \param file The source bucket file
- * \param uri The new URI
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note This operation stages things locally, you must call ast_bucket_file_create on the file
- * that is returned to commit the copy to backend storage
- *
- */
-struct ast_bucket_file *ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri);
-
-/*!
- * \brief Update an existing bucket file in backend storage
- *
- * \param file The bucket file
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note This operation will update both the actual content of the file and the metadata associated with it
- */
-int ast_bucket_file_update(struct ast_bucket_file *file);
-
-/*!
- * \brief Delete a bucket file from backend storage
- *
- * \param file The bucket file
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_file_delete(struct ast_bucket_file *file);
-
-/*!
- * \brief Retrieve a bucket file
- *
- * \param uri Complete URI of the bucket file
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note The object is returned with reference count increased
- */
-struct ast_bucket_file *ast_bucket_file_retrieve(const char *uri);
-
-/*!
- * \brief Add an observer for bucket file creation and deletion operations
- *
- * \param callbacks Implementation of the sorcery observer interface
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Remove an observer from bucket file creation and deletion
- *
- * \param callbacks Implementation of the sorcery observer interface
- */
-void ast_bucket_file_observer_remove(const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Get a JSON representation of a bucket file
- *
- * \param file The specific bucket file
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note The returned ast_json object must be unreferenced using ast_json_unref
- */
-struct ast_json *ast_bucket_file_json(const struct ast_bucket_file *file);
-
-/*!
- * \brief Common file snapshot creation callback for creating a temporary file
- *
- * \param file Pointer to the file snapshot
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_bucket_file_temporary_create(struct ast_bucket_file *file);
-
-/*!
- * \brief Common file snapshot destruction callback for deleting a temporary file
- *
- * \param file Pointer to the file snapshot
- */
-void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_BUCKET_H */
diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h
index f7d7719..7c4905e 100644
--- a/include/asterisk/callerid.h
+++ b/include/asterisk/callerid.h
@@ -75,8 +75,8 @@
 /*! MWI MDMF format -- generate name, callerid, date and MWI fields */
 #define CID_MWI_TYPE_MDMF_FULL	0x02
 
-#define AST_LIN2X(a) ((ast_format_cmp(codec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? (AST_LIN2A(a)) : (AST_LIN2MU(a)))
-#define AST_XLAW(a) ((ast_format_cmp(codec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? (AST_ALAW(a)) : (AST_MULAW(a)))
+#define AST_LIN2X(a) ((codec->id == AST_FORMAT_ALAW) ? (AST_LIN2A(a)) : (AST_LIN2MU(a)))
+#define AST_XLAW(a) ((codec->id == AST_FORMAT_ALAW) ? (AST_ALAW(a)) : (AST_MULAW(a)))
 
 
 struct callerid_state;
@@ -424,17 +424,15 @@ int ast_redirecting_reason_parse(const char *data);
  */
 const char *ast_redirecting_reason_describe(int data);
 
-struct ast_party_redirecting_reason;
-
 /*!
  * \since 1.8
  * \brief Convert redirecting reason value to text code
  *
- * \param data ast_party_redirecting_reason structure from channel.h
+ * \param data Q931_REDIRECTING_REASON from callerid.h
  *
  * \return string for config file
  */
-const char *ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data);
+const char *ast_redirecting_reason_name(int data);
 
 /*!
  * \brief Connected line update source code
diff --git a/include/asterisk/ccss.h b/include/asterisk/ccss.h
index d8101cd..acb3148 100644
--- a/include/asterisk/ccss.h
+++ b/include/asterisk/ccss.h
@@ -1365,8 +1365,8 @@ int ast_cc_monitor_count(const char * const name, const char * const type);
  * The code in the core will take care of making sure that the information gets passed
  * up the ladder correctly.
  *
- * \par core_id The core ID of the corresponding CC transaction
- * \par debug
+ * \param core_id The core ID of the corresponding CC transaction
+ * \param debug
  * \retval 0 Request successfully queued
  * \retval -1 Request could not be queued
  */
@@ -1482,15 +1482,13 @@ int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan);
 /*!
  * \since 1.8
  * \brief Set the CC_INTERFACES channel variable for a channel using an
- * \verbatim extension at context \endverbatim as a starting point
+ * extension at context as a starting point
  *
  * \details
- * The CC_INTERFACES channel variable will have the interfaces
- * that should be called back for a specific PBX instance.  This
- * version of the function is used mainly by local channels,
- * wherein we need to set CC_INTERFACES based on an extension
- * and context that appear in the middle of the tree of dialed
- * interfaces.
+ * The CC_INTERFACES channel variable will have the interfaces that should be
+ * called back for a specific PBX instance. This version of the function is used
+ * mainly by chan_local, wherein we need to set CC_INTERFACES based on an extension
+ * and context that appear in the middle of the tree of dialed interfaces
  *
  * \note
  * This function will lock the channel as well as the list of monitors stored
@@ -1500,7 +1498,7 @@ int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan);
  *
  * \param chan The channel to set the CC_INTERFACES variable on
  * \param extension The name of the extension for which we're setting the variable.
- * This should be in the form of \verbatim exten at context \endverbatim
+ * This should be in the form of "exten at context"
  */
 int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const extension);
 
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 5654c38..c2268e3 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -26,250 +26,57 @@
 #ifndef _ASTERISK_CDR_H
 #define _ASTERISK_CDR_H
 
-#include "asterisk/channel.h"
+#include <sys/time.h>
 
-/*! \file
- *
- * \since 12
- *
- * \brief Call Detail Record Engine.
- *
- * \page CDR Call Detail Record Engine
- *
- * \par Intro
- *
- * The Call Detail Record (CDR) engine uses the \ref stasis Stasis Message Bus
- * to build records for the channels in Asterisk. As the state of a channel and
- * the bridges it participates in changes, notifications are sent over the
- * Stasis Message Bus. The CDR engine consumes these notifications and builds
- * records that reflect that state. Over the lifetime of a channel, many CDRs
- * may be generated for that channel or that involve that channel.
- *
- * CDRs have a lifecycle that is a subset of the channel that they reflect. A
- * single CDR for a channel represents a path of communication between the
- * endpoint behind a channel and Asterisk, or between two endpoints. When a
- * channel establishes a new path of communication, a new CDR is created for the
- * channel. Likewise, when a path of communication is terminated, a CDR is
- * finalized. Finally, when a channel is no longer present in Asterisk, all CDRs
- * for that channel are dispatched for recording.
- *
- * Dispatching of CDRs occurs to registered CDR backends. CDR backends register
- * through \ref ast_cdr_register and are responsible for taking the produced
- * CDRs and storing them in permanent storage.
- *
- * \par CDR attributes
- *
- * While a CDR can have many attributes, all CDRs have two parties: a Party A
- * and a Party B. The Party A is \em always the channel that owns the CDR. A CDR
- * may or may not have a Party B, depending on its state.
- *
- * For the most part, attributes on a CDR are reflective of those same
- * attributes on the channel at the time when the CDR was finalized. Specific
- * CDR attributes include:
- * \li \c start The time when the CDR was created
- * \li \c answer The time when the Party A was answered, or when the path of
- * communication between Party A and Party B was established
- * \li \c end The time when the CDR was finalized
- * \li \c duration \c end - \c start. If \c end is not known, the current time
- * is used
- * \li \c billsec \c end - \c answer. If \c end is not known, the current time
- * is used
- * \li \c userfield User set data on some party in the CDR
- *
- * Note that \c accountcode and \c amaflags are actually properties of a
- * channel, not the CDR.
- *
- * \par CDR States
- *
- * CDRs go through various states during their lifetime. State transitions occur
- * due to messages received over the \ref stasis Stasis Message Bus. The
- * following describes the possible states a CDR can be in, and how it
- * transitions through the states.
- *
- * \par Single
- *
- * When a CDR is created, it is put into the Single state. The Single state
- * represents a CDR for a channel that has no Party B. CDRs can be unanswered
- * or answered while in the Single state.
- *
- * The following transitions can occur while in the Single state:
- * \li If a \ref ast_channel_dial_type indicating a Dial Begin is received, the
- * state transitions to Dial
- * \li If a \ref ast_channel_snapshot is received indicating that the channel
- * has hung up, the state transitions to Finalized
- * \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
- * state transitions to Bridge
- * \li If a \ref ast_bridge_blob_type message indicating an entrance to a
- * holding bridge with a subclass type of "parking" is received, the CDR is
- * transitioned to the Parked state.
- *
- * \par Dial
- *
- * This state represents a dial that is occurring within Asterisk. The Party A
- * can either be the caller for a two party dial, or it can be the dialed party
- * if the calling party is Asterisk (that is, an Originated channel). In the
- * first case, the Party B is \em always the dialed channel; in the second case,
- * the channel is not considered to be a "dialed" channel as it is alone in the
- * dialed operation.
- *
- * While in the Dial state, multiple CDRs can be created for the Party A if a
- * parallel dial occurs. Each dialed party receives its own CDR with Party A.
- *
- * The following transitions can occur while in the Dial state:
- * \li If a \ref ast_channel_dial_type indicating a Dial End is received where
- * the \ref dial_status is not ANSWER, the state transitions to Finalized
- * \li If a \ref ast_channel_snapshot is received indicating that the channel
- * has hung up, the state transitions to Finalized
- * \li If a \ref ast_channel_dial_type indicating a Dial End is received where
- * the \ref dial_status is ANSWER, the state transitions to DialedPending
- * \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
- * state transitions to Bridge
- *
- * \par DialedPending
- *
- * Technically, after being dialed, a CDR does not have to transition to the
- * Bridge state. If the channel being dialed was originated, the channel may
- * being executing dialplan. Strangely enough, it is also valid to have both
- * Party A and Party B - after a dial - to not be bridged and instead execute
- * dialplan. DialedPending handles the state where we figure out if the CDR
- * showing the dial needs to move to the Bridge state; if the CDR should show
- * that we started executing dialplan; of if we need a new CDR.
- *
- * The following transition can occur while in the DialedPending state:
- * \li If a \ref ast_channel_snapshot is received that indicates that the
- * channel has begun executing dialplan, we transition to the Finalized state
- * if we have a Party B. Otherwise, we transition to the Single state.
- * \li If a \ref ast_bridge_blob_type is received indicating a Bridge Enter, the
- * state transitions to Bridge (through the Dial state)
- * \li If a \ref ast_bridge_blob_type message indicating an entrance to a
- * holding bridge with a subclass type of "parking" is received, the CDR is
- * transitioned to the Parked state.
- *
- * \par Bridge
- *
- * The Bridge state represents a path of communication between Party A and one
- * or more other parties. When a CDR enters into the Bridge state, the following
- * occurs:
- * \li The CDR attempts to find a Party B. If the CDR has a Party B, it looks
- * for that channel in the bridge and updates itself accordingly. If the CDR
- * does not yet have a Party B, it attempts to find a channel that can be its
- * Party B. If it finds one, it updates itself; otherwise, the CDR is
- * temporarily finalized.
- * \li Once the CDR has a Party B or it is determined that it cannot have a
- * Party B, new CDRs are created for each pairing of channels with the CDR's
- * Party A.
- *
- * As an example, consider the following:
- * \li A Dials B - both answer
- * \li B joins a bridge. Since no one is in the bridge and it was a dialed
- * channel, it cannot have a Party B.
- * \li A joins the bridge. Since A's Party B is B, A updates itself with B.
- * \li Now say an Originated channel, C, joins the bridge. The bridge becomes
- * a multi-party bridge.
- * \li C attempts to get a Party B. A cannot be C's Party B, as it was created
- * before it. B is a dialed channel and can thus be C's Party B, so C's CDR
- * updates its Party B to B.
- * \li New CDRs are now generated. A gets a new CDR for A -> C. B is dialed, and
- * hence cannot get any CDR.
- * \li Now say another Originated channel, D, joins the bridge. Say D has the
- * \ref party_a flag set on it, such that it is always the preferred Party A.
- * As such, it takes A as its Party B.
- * \li New CDRs are generated. D gets new CDRs for D -> B and D -> C.
- *
- * The following transitions can occur while in the Bridge state:
- * \li If a \ref ast_bridge_blob_type message indicating a leave is received,
- * the state transitions to the Finalized state.
- *
- * \par Parked
- *
- * Parking is technically just another bridge in the Asterisk bridging
- * framework. Unlike other bridges, however there are several key distinctions:
- * \li With normal bridges, you want to show paths of communication between
- * the participants. In parking, however, each participant is independent.
- * From the perspective of a CDR, a call in parking should look like a dialplan
- * application just executed.
- * \li Holding bridges are typically items using in more complex applications,
- * and so we usually don't want to show them. However, with Park, there is no
- * application execution - often, a channel will be put directly into the
- * holding bridge, bypassing the dialplan. This occurs when a call is blind
- * transferred to a parking extension.
- *
- * As such, if a channel enters a bridge and that happens to be a holding bridge
- * with a subclass type of "parking", we transition the CDR into the Parked
- * state. The parking Stasis message updates the application name and data to
- * reflect that the channel is in parking. When this occurs, a special flag is
- * set on the CDR that prevents the application name from being updates by
- * subsequent channel snapshot updates.
- *
- * The following transitions can occur while in the Parked state:
- * \li If a \ref ast_bridge_blob_type message indicating a leave is received,
- * the state transitions to the Finalized state
- *
- * \par Finalized
- *
- * Once a CDR enters the finalized state, it is finished. No further updates
- * can be made to the party information, and the CDR cannot be changed.
- *
- * One exception to this occurs during linkedid propagation, in which the CDRs
- * linkedids are updated based on who the channel is bridged with. In general,
- * however, a finalized CDR is waiting for dispatch to the CDR backends.
- */
-
-/*! \brief CDR engine settings */
-enum ast_cdr_settings {
-	CDR_ENABLED = 1 << 0,               /*< Enable CDRs */
-	CDR_BATCHMODE = 1 << 1,             /*< Whether or not we should dispatch CDRs in batches */
-	CDR_UNANSWERED = 1 << 2,            /*< Log unanswered CDRs */
-	CDR_CONGESTION = 1 << 3,            /*< Treat congestion as if it were a failed call */
-	CDR_END_BEFORE_H_EXTEN = 1 << 4,    /*< End the CDR before the 'h' extension runs */
-	CDR_INITIATED_SECONDS = 1 << 5,     /*< Include microseconds into the billing time */
-	CDR_DEBUG = 1 << 6,                 /*< Enables extra debug statements */
-};
-
-/*! \brief CDR Batch Mode settings */
-enum ast_cdr_batch_mode_settings {
-	BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*< Don't spawn a thread to handle the batches - do it on the scheduler */
-	BATCH_MODE_SAFE_SHUTDOWN = 1 << 1,  /*< During safe shutdown, submit the batched CDRs */
-};
+#include "asterisk/data.h"
 
 /*!
- * \brief CDR manipulation options. Certain function calls will manipulate the
- * state of a CDR object based on these flags.
+ * \brief CDR Flags
  */
-enum ast_cdr_options {
-	AST_CDR_FLAG_KEEP_VARS = (1 << 0),   /*< Copy variables during the operation */
-	AST_CDR_FLAG_DISABLE = (1 << 1),     /*< Disable the current CDR */
-	AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*< Disable the CDR and all future CDRs */
-	AST_CDR_FLAG_PARTY_A = (1 << 3),     /*< Set the channel as party A */
-	AST_CDR_FLAG_FINALIZE = (1 << 4),    /*< Finalize the current CDRs */
-	AST_CDR_FLAG_SET_ANSWER = (1 << 5),  /*< If the channel is answered, set the answer time to now */
-	AST_CDR_FLAG_RESET = (1 << 6),       /*< If set, set the start and answer time to now */
-	AST_CDR_LOCK_APP = (1 << 7),         /*< Prevent any further changes to the application field/data field for this CDR */
+enum {
+	AST_CDR_FLAG_KEEP_VARS     = (1 << 0),
+	AST_CDR_FLAG_POSTED        = (1 << 1),
+	AST_CDR_FLAG_LOCKED        = (1 << 2),
+	AST_CDR_FLAG_CHILD         = (1 << 3),
+	AST_CDR_FLAG_POST_DISABLED = (1 << 4),
+	AST_CDR_FLAG_BRIDGED       = (1 << 5),
+	AST_CDR_FLAG_MAIN          = (1 << 6),
+	AST_CDR_FLAG_ENABLE        = (1 << 7),
+	AST_CDR_FLAG_ANSLOCKED     = (1 << 8),
+	AST_CDR_FLAG_DONT_TOUCH    = (1 << 9),
+	AST_CDR_FLAG_POST_ENABLE   = (1 << 10),
+	AST_CDR_FLAG_DIALED        = (1 << 11),
+	AST_CDR_FLAG_ORIGINATED    = (1 << 12),
 };
 
 /*!
  * \brief CDR Flags - Disposition
  */
-enum ast_cdr_disposition {
-	AST_CDR_NOANSWER   = 0,
-	AST_CDR_NULL       = (1 << 0),
-	AST_CDR_FAILED     = (1 << 1),
-	AST_CDR_BUSY       = (1 << 2),
-	AST_CDR_ANSWERED   = (1 << 3),
+enum {
+	AST_CDR_NOANSWER = 0,
+	AST_CDR_NULL     = (1 << 0),
+	AST_CDR_FAILED   = (1 << 1),
+	AST_CDR_BUSY     = (1 << 2),
+	AST_CDR_ANSWERED = (1 << 3),
 	AST_CDR_CONGESTION = (1 << 4),
 };
 
-
-/*! \brief The global options available for CDRs */
-struct ast_cdr_config {
-	struct ast_flags settings;			/*< CDR settings */
-	struct batch_settings {
-		unsigned int time;				/*< Time between batches */
-		unsigned int size;				/*< Size to trigger a batch */
-		struct ast_flags settings;		/*< Settings for batches */
-	} batch_settings;
+/*!
+ * \brief CDR AMA Flags
+ */
+enum {
+	AST_CDR_OMIT          = 1,
+	AST_CDR_BILLING       = 2,
+	AST_CDR_DOCUMENTATION = 3,
 };
 
+#define AST_MAX_USER_FIELD     256
+#define AST_MAX_ACCOUNT_CODE   20
+
+/* Include channel.h after relevant declarations it will need */
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+
 /*!
  * \brief Responsible for call detail data
  */
@@ -310,10 +117,11 @@ struct ast_cdr {
 	char peeraccount[AST_MAX_ACCOUNT_CODE];
 	/*! flags */
 	unsigned int flags;
-	/*! Unique Channel Identifier */
-	char uniqueid[AST_MAX_UNIQUEID];
+	/*! Unique Channel Identifier
+	 * 150 = 127 (max systemname) + "-" + 10 (epoch timestamp) + "." + 10 (monotonically incrementing integer) + NULL */
+	char uniqueid[150];
 	/* Linked group Identifier */
-	char linkedid[AST_MAX_UNIQUEID];
+	char linkedid[32];
 	/*! User field */
 	char userfield[AST_MAX_USER_FIELD];
 	/*! Sequence field */
@@ -325,215 +133,249 @@ struct ast_cdr {
 	struct ast_cdr *next;
 };
 
+int ast_cdr_isset_unanswered(void);
+int ast_cdr_isset_congestion(void);
+void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw);
+int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur);
+int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur);
+void ast_cdr_free_vars(struct ast_cdr *cdr, int recur);
+int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr);
+
 /*!
- * \since 12
- * \brief Obtain the current CDR configuration
- *
- * The configuration is a ref counted object. The caller of this function must
- * decrement the ref count when finished with the configuration.
- *
- * \retval NULL on error
- * \retval The current CDR configuration
+ * \brief CDR backend callback
+ * \warning CDR backends should NOT attempt to access the channel associated
+ * with a CDR record.  This channel is not guaranteed to exist when the CDR
+ * backend is invoked.
  */
-struct ast_cdr_config *ast_cdr_get_config(void);
+typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
+
+/*! \brief Return TRUE if CDR subsystem is enabled */
+int check_cdr_enabled(void);
 
 /*!
- * \since 12
- * \brief Set the current CDR configuration
- *
- * \param config The new CDR configuration
+ * \brief Allocate a CDR record
+ * \retval a malloc'd ast_cdr structure
+ * \retval NULL on error (malloc failure)
  */
-void ast_cdr_set_config(struct ast_cdr_config *config);
+struct ast_cdr *ast_cdr_alloc(void);
 
 /*!
- * \since 12
- * \brief Format a CDR variable from an already posted CDR
- *
- * \param cdr The dispatched CDR to process
- * \param name The name of the variable
- * \param ret Pointer to the formatted buffer
- * \param workspace A pointer to the buffer to use to format the variable
- * \param workspacelen The size of \ref workspace
- * \param raw If non-zero and a date/time is extraced, provide epoch seconds. Otherwise format as a date/time stamp
+ * \brief Duplicate a record and increment the sequence number.
+ * \param cdr the record to duplicate
+ * \retval a malloc'd ast_cdr structure,
+ * \retval NULL on error (malloc failure)
+ * \see ast_cdr_dup()
+ * \see ast_cdr_dup_unique_swap()
  */
-void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw);
+struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr);
 
 /*!
- * \since 12
- * \brief Retrieve a CDR variable from a channel's current CDR
- *
- * \param channel_name The name of the party A channel that the CDR is associated with
- * \param name The name of the variable to retrieve
- * \param value Buffer to hold the value
- * \param length The size of the buffer
+ * \brief Duplicate a record and increment the sequence number of the old
+ * record.
+ * \param cdr the record to duplicate
+ * \retval a malloc'd ast_cdr structure,
+ * \retval NULL on error (malloc failure)
+ * \note This version increments the original CDR's sequence number rather than
+ * the duplicate's sequence number. The effect is as if the original CDR's
+ * sequence number was swapped with the duplicate's sequence number.
  *
- * \retval 0 on success
- * \retval non-zero on failure
+ * \see ast_cdr_dup()
+ * \see ast_cdr_dup_unique()
  */
-int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length);
+struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr);
 
 /*!
- * \since 12
- * \brief Set a variable on a CDR
- *
- * \param channel_name The channel to set the variable on
- * \param name The name of the variable to set
- * \param value The value of the variable to set
- *
- * \retval 0 on success
- * \retval non-zero on failure
+ * \brief Duplicate a record
+ * \param cdr the record to duplicate
+ * \retval a malloc'd ast_cdr structure,
+ * \retval NULL on error (malloc failure)
+ * \see ast_cdr_dup_unique()
+ * \see ast_cdr_dup_unique_swap()
  */
-int ast_cdr_setvar(const char *channel_name, const char *name, const char *value);
+struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
 
 /*!
- * \since 12
- * \brief Fork a CDR
- *
- * \param channel_name The name of the channel whose CDR should be forked
- * \param options Options to control how the fork occurs.
- *
- * \retval 0 on success
- * \retval -1 on failure
+ * \brief Free a CDR record
+ * \param cdr ast_cdr structure to free
+ * Returns nothing
  */
-int ast_cdr_fork(const char *channel_name, struct ast_flags *options);
+void ast_cdr_free(struct ast_cdr *cdr);
 
 /*!
- * \since 12
- * \brief Set a property on a CDR for a channel
- *
- * This function sets specific administrative properties on a CDR for a channel.
- * This includes properties like preventing a CDR from being dispatched, to
- * setting the channel as the preferred Party A in future CDRs. See
- * \ref enum ast_cdr_options for more information.
- *
- * \param channel_name The CDR's channel
- * \param option Option to apply to the CDR
- *
- * \retval 0 on success
- * \retval 1 on error
+ * \brief Discard and free a CDR record
+ * \param cdr ast_cdr structure to free
+ * Returns nothing  -- same as free, but no checks or complaints
  */
-int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option);
+void ast_cdr_discard(struct ast_cdr *cdr);
 
 /*!
- * \since 12
- * \brief Clear a property on a CDR for a channel
- *
- * Clears a flag previously set by \ref ast_cdr_set_property
- *
- * \param channel_name The CDR's channel
- * \param option Option to clear from the CDR
- *
- * \retval 0 on success
- * \retval 1 on error
+ * \brief Initialize based on a channel
+ * \param cdr Call Detail Record to use for channel
+ * \param chan Channel to bind CDR with
+ * Initializes a CDR and associates it with a particular channel
+ * \note The channel should be locked before calling.
+ * \return 0 by default
  */
-int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option);
+int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *chan);
 
 /*!
- * \brief Reset the detail record
- * \param channel_name The channel that the CDR is associated with
- * \param keep_variables Keep the variables during the reset. If zero,
- *        variables are discarded during the reset.
- *
- * \retval 0 on success
- * \retval -1 on failure
+ * \brief Initialize based on a channel
+ * \param cdr Call Detail Record to use for channel
+ * \param chan Channel to bind CDR with
+ * Initializes a CDR and associates it with a particular channel
+ * \note The channel should be locked before calling.
+ * \return 0 by default
  */
-int ast_cdr_reset(const char *channel_name, int keep_variables);
+int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *chan);
 
 /*!
- * \brief Serializes all the data and variables for a current CDR record
- * \param channel_name The channel to get the CDR for
- * \param buf A buffer to use for formatting the data
- * \param delim A delimeter to use to separate variable keys/values
- * \param sep A separator to use between nestings
- * \retval the total number of serialized variables
+ * \brief Register a CDR handling engine
+ * \param name name associated with the particular CDR handler
+ * \param desc description of the CDR handler
+ * \param be function pointer to a CDR handler
+ * Used to register a Call Detail Record handler.
+ * \retval 0 on success.
+ * \retval -1 on error
  */
-int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep);
+int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
 
 /*!
- * \brief CDR backend callback
- * \warning CDR backends should NOT attempt to access the channel associated
- * with a CDR record.  This channel is not guaranteed to exist when the CDR
- * backend is invoked.
+ * \brief Unregister a CDR handling engine
+ * \param name name of CDR handler to unregister
+ * Unregisters a CDR by it's name
  */
-typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
+void ast_cdr_unregister(const char *name);
 
-/*! \brief Return TRUE if CDR subsystem is enabled */
-int ast_cdr_is_enabled(void);
+/*!
+ * \brief Start a call
+ * \param cdr the cdr you wish to associate with the call
+ * Starts all CDR stuff necessary for monitoring a call
+ * Returns nothing
+ */
+void ast_cdr_start(struct ast_cdr *cdr);
+
+/*! \brief Answer a call
+ * \param cdr the cdr you wish to associate with the call
+ * Starts all CDR stuff necessary for doing CDR when answering a call
+ * \note NULL argument is just fine.
+ */
+void ast_cdr_answer(struct ast_cdr *cdr);
 
 /*!
- * \brief Allocate a CDR record
- * \retval a malloc'd ast_cdr structure
- * \retval NULL on error (malloc failure)
+ * \brief A call wasn't answered
+ * \param cdr the cdr you wish to associate with the call
+ * Marks the channel disposition as "NO ANSWER"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
  */
-struct ast_cdr *ast_cdr_alloc(void);
+extern void ast_cdr_noanswer(struct ast_cdr *cdr);
 
-struct stasis_message_router;
+/*!
+ * \brief A call was set to congestion
+ * \param cdr the cdr you wish to associate with the call
+ * Markst he channel disposition as "CONGESTION"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application
+ */
+extern void ast_cdr_congestion(struct ast_cdr *cdr);
 
 /*!
- * \brief Return the message router for the CDR engine
- *
- * This returns the \ref stasis_message_router that the CDR engine
- * uses for dispatching \ref stasis messages. The reference on the
- * message router is bumped and must be released by the caller of
- * this function.
- *
- * \retval NULL if the CDR engine is disabled or unavailable
- * \retval the \ref stasis_message_router otherwise
+ * \brief Busy a call
+ * \param cdr the cdr you wish to associate with the call
+ * Marks the channel disposition as "BUSY"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
+ * Returns nothing
  */
-struct stasis_message_router *ast_cdr_message_router(void);
+void ast_cdr_busy(struct ast_cdr *cdr);
 
 /*!
- * \brief Duplicate a public CDR
- * \param cdr the record to duplicate
- *
- * \retval a malloc'd ast_cdr structure,
- * \retval NULL on error (malloc failure)
+ * \brief Fail a call
+ * \param cdr the cdr you wish to associate with the call
+ * Marks the channel disposition as "FAILED"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
+ * Returns nothing
  */
-struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
+void ast_cdr_failed(struct ast_cdr *cdr);
 
 /*!
- * \brief Free a CDR record
- * \param cdr ast_cdr structure to free
+ * \brief Save the result of the call based on the AST_CAUSE_*
+ * \param cdr the cdr you wish to associate with the call
+ * \param cause the AST_CAUSE_*
  * Returns nothing
  */
-void ast_cdr_free(struct ast_cdr *cdr);
+int ast_cdr_disposition(struct ast_cdr *cdr, int cause);
 
 /*!
- * \brief Register a CDR handling engine
- * \param name name associated with the particular CDR handler
- * \param desc description of the CDR handler
- * \param be function pointer to a CDR handler
- * Used to register a Call Detail Record handler.
- * \retval 0 on success.
- * \retval -1 on error
+ * \brief End a call
+ * \param cdr the cdr you have associated the call with
+ * Registers the end of call time in the cdr structure.
+ * Returns nothing
  */
-int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
+void ast_cdr_end(struct ast_cdr *cdr);
 
 /*!
- * \brief Unregister a CDR handling engine
- * \param name name of CDR handler to unregister
- * Unregisters a CDR by it's name
- *
- * \retval 0 The backend unregistered successfully
- * \retval -1 The backend could not be unregistered at this time
+ * \brief Detaches the detail record for posting (and freeing) either now or at a
+ * later time in bulk with other records during batch mode operation.
+ * \param cdr Which CDR to detach from the channel thread
+ * Prevents the channel thread from blocking on the CDR handling
+ * Returns nothing
  */
-int ast_cdr_unregister(const char *name);
+void ast_cdr_detach(struct ast_cdr *cdr);
 
 /*!
- * \brief Suspend a CDR backend temporarily
- *
-  * \retval 0 The backend is suspdended
-  * \retval -1 The backend could not be suspended
-  */
-int ast_cdr_backend_suspend(const char *name);
+ * \brief Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines
+ * \param shutdown Whether or not we are shutting down
+ * Blocks the asterisk shutdown procedures until the CDR data is submitted.
+ * Returns nothing
+ */
+void ast_cdr_submit_batch(int shutdown);
 
 /*!
- * \brief Unsuspend a CDR backend
- *
- * \retval 0 The backend was unsuspended
- * \retval -1 The back could not be unsuspended
+ * \brief Set the destination channel, if there was one
+ * \param cdr Which cdr it's applied to
+ * \param chan Channel to which dest will be
+ * Sets the destination channel the CDR is applied to
+ * Returns nothing
  */
-int ast_cdr_backend_unsuspend(const char *name);
+void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chan);
+
+/*!
+ * \brief Set the last executed application
+ * \param cdr which cdr to act upon
+ * \param app the name of the app you wish to change it to
+ * \param data the data you want in the data field of app you set it to
+ * Changes the value of the last executed app
+ * Returns nothing
+ */
+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data);
+
+/*!
+ * \brief Set the answer time for a call
+ * \param cdr the cdr you wish to associate with the call
+ * \param t the answer time
+ * Starts all CDR stuff necessary for doing CDR when answering a call
+ * NULL argument is just fine.
+ */
+void ast_cdr_setanswer(struct ast_cdr *cdr, struct timeval t);
+
+/*!
+ * \brief Set the disposition for a call
+ * \param cdr the cdr you wish to associate with the call
+ * \param disposition the new disposition
+ * Set the disposition on a call.
+ * NULL argument is just fine.
+ */
+void ast_cdr_setdisposition(struct ast_cdr *cdr, long int disposition);
+
+/*!
+ * \brief Convert a string to a detail record AMA flag
+ * \param flag string form of flag
+ * Converts the string form of the flag to the binary form.
+ * \return the binary form of the flag
+ */
+int ast_cdr_amaflags2int(const char *flag);
 
 /*!
  * \brief Disposition to a string
@@ -541,15 +383,81 @@ int ast_cdr_backend_unsuspend(const char *name);
  * Converts the binary form of a disposition to string form.
  * \return a pointer to the string form
  */
-const char *ast_cdr_disp2str(int disposition);
+char *ast_cdr_disp2str(int disposition);
+
+/*!
+ * \brief Reset the detail record, optionally posting it first
+ * \param cdr which cdr to act upon
+ * \param flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it
+ *              |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's
+ */
+void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *flags);
+
+/*! Reset the detail record times, flags */
+/*!
+ * \param cdr which cdr to act upon
+ * \param flags |AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it
+ *              |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's
+ */
+void ast_cdr_specialized_reset(struct ast_cdr *cdr, struct ast_flags *flags);
+
+/*! Flags to a string */
+/*!
+ * \param flags binary flag
+ * Converts binary flags to string flags
+ * Returns string with flag name
+ */
+char *ast_cdr_flags2str(int flags);
+
+/*!
+ * \brief Move the non-null data from the "from" cdr to the "to" cdr
+ * \param to the cdr to get the goodies
+ * \param from the cdr to give the goodies
+ */
+void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from);
+
+/*!
+ * \brief Set account code, will generate AMI event
+ * \note The channel should be locked before calling.
+ */
+int ast_cdr_setaccount(struct ast_channel *chan, const char *account);
+
+/*!
+ * \brief Set the peer account
+ * \note The channel should be locked before calling.
+ */
+int ast_cdr_setpeeraccount(struct ast_channel *chan, const char *account);
+
+/*!
+ * \brief Set AMA flags for channel
+ * \note The channel should be locked before calling.
+ */
+int ast_cdr_setamaflags(struct ast_channel *chan, const char *amaflags);
 
 /*!
  * \brief Set CDR user field for channel (stored in CDR)
- *
- * \param channel_name The name of the channel that owns the CDR
- * \param userfield The user field to set
+ * \note The channel should be locked before calling.
+ */
+int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield);
+/*!
+ * \brief Append to CDR user field for channel (stored in CDR)
+ * \note The channel should be locked before calling.
  */
-void ast_cdr_setuserfield(const char *channel_name, const char *userfield);
+int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield);
+
+
+/*!
+ * \brief Update CDR on a channel
+ * \note The channel should be locked before calling.
+ */
+int ast_cdr_update(struct ast_channel *chan);
+
+
+extern int ast_default_amaflags;
+
+extern char ast_default_accountcode[AST_MAX_ACCOUNT_CODE];
+
+struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr);
 
 /*! \brief Reload the configuration file cdr.conf and start/stop CDR scheduling thread */
 int ast_cdr_engine_reload(void);
@@ -560,4 +468,14 @@ int ast_cdr_engine_init(void);
 /*! Submit any remaining CDRs and prepare for shutdown */
 void ast_cdr_engine_term(void);
 
+/*!
+ * \brief
+ * \param[in] tree Where to insert the cdr.
+ * \param[in] cdr The cdr structure to insert in 'tree'.
+ * \param[in] recur Go throw all the cdr levels.
+ * \retval <0 on error.
+ * \retval 0 on success.
+ */
+int ast_cdr_data_add_structure(struct ast_data *tree, struct ast_cdr *cdr, int recur);
+
 #endif /* _ASTERISK_CDR_H */
diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h
index 833b48b..883e250 100644
--- a/include/asterisk/cel.h
+++ b/include/asterisk/cel.h
@@ -36,9 +36,25 @@ extern "C" {
 #include "asterisk/event.h"
 
 /*!
+ * \brief AMA Flags
+ *
+ * \note This must much up with the AST_CDR_* defines for AMA flags.
+ */
+enum ast_cel_ama_flag {
+	AST_CEL_AMA_FLAG_NONE,
+	AST_CEL_AMA_FLAG_OMIT,
+	AST_CEL_AMA_FLAG_BILLING,
+	AST_CEL_AMA_FLAG_DOCUMENTATION,
+	/*! \brief Must be final entry */
+	AST_CEL_AMA_FLAG_TOTAL,
+};
+
+/*!
  * \brief CEL event types
  */
 enum ast_cel_event_type {
+	AST_CEL_INVALID_VALUE = -1,
+	AST_CEL_ALL = 0,
 	/*! \brief channel birth */
 	AST_CEL_CHANNEL_START = 1,
 	/*! \brief channel end */
@@ -51,31 +67,47 @@ enum ast_cel_event_type {
 	AST_CEL_APP_START = 5,
 	/*! \brief an app ends */
 	AST_CEL_APP_END = 6,
-	/*! \brief channel enters a bridge */
-	AST_CEL_BRIDGE_ENTER = 7,
-	/*! \brief channel exits a bridge */
-	AST_CEL_BRIDGE_EXIT = 8,
+	/*! \brief a bridge is established */
+	AST_CEL_BRIDGE_START = 7,
+	/*! \brief a bridge is torn down */
+	AST_CEL_BRIDGE_END = 8,
+	/*! \brief a conference is started */
+	AST_CEL_CONF_START = 9,
+	/*! \brief a conference is ended */
+	AST_CEL_CONF_END = 10,
 	/*! \brief a channel is parked */
-	AST_CEL_PARK_START = 9,
+	AST_CEL_PARK_START = 11,
 	/*! \brief channel out of the park */
-	AST_CEL_PARK_END = 10,
+	AST_CEL_PARK_END = 12,
+	/*! \brief a transfer occurs */
+	AST_CEL_BLINDTRANSFER = 13,
 	/*! \brief a transfer occurs */
-	AST_CEL_BLINDTRANSFER = 11,
+	AST_CEL_ATTENDEDTRANSFER = 14,
 	/*! \brief a transfer occurs */
-	AST_CEL_ATTENDEDTRANSFER = 12,
+	AST_CEL_TRANSFER = 15,
+	/*! \brief a 3-way conference, usually part of a transfer */
+	AST_CEL_HOOKFLASH = 16,
+	/*! \brief a 3-way conference, usually part of a transfer */
+	AST_CEL_3WAY_START = 17,
+	/*! \brief a 3-way conference, usually part of a transfer */
+	AST_CEL_3WAY_END = 18,
+	/*! \brief channel enters a conference */
+	AST_CEL_CONF_ENTER = 19,
+	/*! \brief channel exits a conference */
+	AST_CEL_CONF_EXIT = 20,
 	/*! \brief a user-defined event, the event name field should be set  */
-	AST_CEL_USER_DEFINED = 13,
+	AST_CEL_USER_DEFINED = 21,
 	/*! \brief the last channel with the given linkedid is retired  */
-	AST_CEL_LINKEDID_END = 14,
+	AST_CEL_LINKEDID_END = 22,
+	/*! \brief a masquerade happened to alter the participants on a bridge  */
+	AST_CEL_BRIDGE_UPDATE = 23,
 	/*! \brief a directed pickup was performed on this channel  */
-	AST_CEL_PICKUP = 15,
+	AST_CEL_PICKUP = 24,
 	/*! \brief this call was forwarded somewhere else  */
-	AST_CEL_FORWARD = 16,
-	/*! \brief A local channel optimization occurred */
-	AST_CEL_LOCAL_OPTIMIZE = 17,
+	AST_CEL_FORWARD = 25,
 };
 
-/*! 
+/*!
  * \brief Check to see if CEL is enabled
  *
  * \since 1.8
@@ -131,6 +163,42 @@ const char *ast_cel_get_type_name(enum ast_cel_event_type type);
 enum ast_cel_event_type ast_cel_str_to_event_type(const char *name);
 
 /*!
+ * \brief Convert AMA flag to printable string
+ * 
+ * \param[in] flag the flag to convert to a string
+ *
+ * \since 1.8
+ *
+ * \return the string representation of the flag
+ */
+const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag);
+
+/*! 
+ * \brief Check and potentially retire a Linked ID
+ *
+ * \param chan channel that is being destroyed or its linkedid is changing
+ *
+ * \since 1.8
+ *
+ * If at least one CEL backend is looking for CEL_LINKEDID_END
+ * events, this function will check if the given channel is the last
+ * active channel with that linkedid, and if it is, emit a
+ * CEL_LINKEDID_END event.
+ *
+ * \return nothing
+ */
+void ast_cel_check_retire_linkedid(struct ast_channel *chan);
+
+/*!
+ * \brief Inform CEL that a new linkedid is being used
+ * \since 11
+ *
+ * \retval -1 error
+ * \retval 0 success
+ */
+int ast_cel_linkedid_ref(const char *linkedid);
+
+/*!
  * \brief Create a fake channel from data in a CEL event
  *
  * \note
@@ -152,6 +220,31 @@ enum ast_cel_event_type ast_cel_str_to_event_type(const char *name);
 struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event);
 
 /*!
+ * \brief Report a channel event
+ *
+ * \param chan This argument is required.  This is the primary channel associated with
+ *        this channel event.
+ * \param event_type This is the type of call event being reported.
+ * \param userdefevname This is an optional custom name for the call event.
+ * \param extra This is an optional opaque field that will go into the "CEL_EXTRA"
+ *        information element of the call event.
+ * \param peer2 All CEL events contain a "peer name" information element.  The first
+ *        place the code will look to get a peer name is from the bridged channel to
+ *        chan.  If chan has no bridged channel and peer2 is specified, then the name
+ *        of peer2 will go into the "peer name" field.  If neither are available, the
+ *        peer name field will be blank.
+ *
+ * \since 1.8
+ *
+ * \pre chan and peer2 are both unlocked
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
+		const char *userdefevname, const char *extra, struct ast_channel *peer2);
+
+/*!
  * \brief Helper struct for getting the fields out of a CEL event
  */
 struct ast_cel_event_record {
@@ -202,117 +295,6 @@ struct ast_cel_event_record {
  */
 int ast_cel_fill_record(const struct ast_event *event, struct ast_cel_event_record *r);
 
-/*!
- * \brief Publish a CEL event
- * \since 12
- *
- * \param chan This is the primary channel associated with this channel event.
- * \param event_type This is the type of call event being reported.
- * \param blob This contains any additional parameters that need to be conveyed for this event.
- */
-void ast_cel_publish_event(struct ast_channel *chan,
-	enum ast_cel_event_type event_type,
-	struct ast_json *blob);
-
-/*!
- * \brief Get the CEL topic
- *
- * \retval The CEL topic
- * \retval NULL if not allocated
- */
-struct stasis_topic *ast_cel_topic(void);
-
-/*! \brief A structure to hold CEL global configuration options */
-struct ast_cel_general_config {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(date_format); /*!< The desired date format for logging */
-	);
-	int enable;			/*!< Whether CEL is enabled */
-	int64_t events;			/*!< The events to be logged */
-	/*! The apps for which to log app start and end events. This is
-	 * ast_str_container_alloc()ed and filled with ao2-allocated
-	 * char* which are all-lowercase application names. */
-	struct ao2_container *apps;
-};
-
-/*!
- * \brief Allocate a CEL configuration object
- *
- * \retval NULL on error
- * \retval The new CEL configuration object
- */
-void *ast_cel_general_config_alloc(void);
-
-/*!
- * \since 12
- * \brief Obtain the current CEL configuration
- *
- * The configuration is a ref counted object. The caller of this function must
- * decrement the ref count when finished with the configuration.
- *
- * \retval NULL on error
- * \retval The current CEL configuration
- */
-struct ast_cel_general_config *ast_cel_get_config(void);
-
-/*!
- * \since 12
- * \brief Set the current CEL configuration
- *
- * \param config The new CEL configuration
- */
-void ast_cel_set_config(struct ast_cel_general_config *config);
-
-struct ast_channel_snapshot;
-/*!
- * \brief Allocate and populate a CEL event structure
- *
- * \param snapshot An ast_channel_snapshot of the primary channel associated
- *        with this channel event.
- * \param event_type The type of call event being reported.
- * \param userdefevname Custom name for the call event. (optional)
- * \param extra An event-specific opaque JSON blob to be rendered and placed
- *        in the "CEL_EXTRA" information element of the call event. (optional)
- * \param peer_str A list of comma-separated peer channel names. (optional)
- *
- * \since 12
- *
- * \retval The created ast_event structure
- * \retval NULL on failure
- */
-struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
-		enum ast_cel_event_type event_type, const char *userdefevname,
-		struct ast_json *extra, const char *peer_str);
-
-/*!
- * \brief CEL backend callback
- */
-/*typedef int (*ast_cel_backend_cb)(struct ast_cel_event_record *cel);*/
-typedef void (*ast_cel_backend_cb)(struct ast_event *event);
-
-/*!
- * \brief Register a CEL backend
- *
- * \param name Name of backend to register
- * \param backend_callback Callback to register
- *
- * \retval zero on success
- * \retval non-zero on failure
- * \since 12
- */
-int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback);
-
-/*!
- * \brief Unregister a CEL backend
- *
- * \param name Name of backend to unregister
- *
- * \retval zero on success
- * \retval non-zero on failure
- * \since 12
- */
-int ast_cel_backend_unregister(const char *name);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 45e94ce..02aee5e 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -77,7 +77,7 @@
 
 	\par Reference
 	\arg channel.c - generic functions
-	\arg channel.h - declarations of functions, flags and structures
+ 	\arg channel.h - declarations of functions, flags and structures
 	\arg translate.h - Transcoding support functions
 	\arg \ref channel_drivers - Implemented channel drivers
 	\arg \ref Def_Frame Asterisk Multimedia Frames
@@ -125,44 +125,18 @@ References:
 
 #include "asterisk/abstract_jb.h"
 #include "asterisk/astobj2.h"
+
 #include "asterisk/poll-compat.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-#define AST_MAX_EXTENSION       80  /*!< Max length of an extension */
-#define AST_MAX_CONTEXT         80  /*!< Max length of a context */
-
-/*!
- * Max length of a channel uniqueid reported to the outside world.
- *
- * \details
- * 149 = 127 (max systemname) + "-" + 10 (epoch timestamp)
- *     + "." + 10 (monotonically incrementing integer).
- *
- * \note If this value is ever changed, MAX_CHANNEL_ID should
- * be updated in rtp_engine.h.
- */
-#define AST_MAX_PUBLIC_UNIQUEID 149
-
-/*!
- * Maximum size of an internal Asterisk channel unique ID.
- *
- * \details
- * Add two for the Local;2 channel to append a ';2' if needed
- * plus nul terminator.
- *
- * \note If this value is ever changed, MAX_CHANNEL_ID should
- * be updated in rtp_engine.h.
- */
-#define AST_MAX_UNIQUEID        (AST_MAX_PUBLIC_UNIQUEID + 2 + 1)
-
-#define AST_MAX_ACCOUNT_CODE    20  /*!< Max length of an account code */
-#define AST_CHANNEL_NAME        80  /*!< Max length of an ast_channel name */
-#define MAX_LANGUAGE            40  /*!< Max length of the language setting */
-#define MAX_MUSICCLASS          80  /*!< Max length of the music class setting */
-#define AST_MAX_USER_FIELD      256 /*!< Max length of the channel user field */
+#define AST_MAX_EXTENSION	80	/*!< Max length of an extension */
+#define AST_MAX_CONTEXT		80	/*!< Max length of a context */
+#define AST_CHANNEL_NAME	80	/*!< Max length of an ast_channel name */
+#define MAX_LANGUAGE		40	/*!< Max length of the language setting */
+#define MAX_MUSICCLASS		80	/*!< Max length of the music class setting */
 
 #include "asterisk/frame.h"
 #include "asterisk/chanvars.h"
@@ -177,9 +151,6 @@ extern "C" {
 #include "asterisk/channelstate.h"
 #include "asterisk/ccss.h"
 #include "asterisk/framehook.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/endpoints.h"
 
 #define DATASTORE_INHERIT_FOREVER	INT_MAX
 
@@ -393,7 +364,7 @@ struct ast_party_dialed {
  * PSTN gateway).
  *
  * \todo Implement settings for transliteration between UTF8 Caller ID names in
- *       to ASCII Caller ID's (DAHDI). Östen Åsklund might be transliterated into
+ *       to ASCII Caller ID's (DAHDI). �sten �sklund might be transliterated into
  *       Osten Asklund or Oesten Aasklund depending upon language and person...
  *       We need automatic routines for incoming calls and static settings for
  *       our own accounts.
@@ -479,21 +450,6 @@ struct ast_set_party_connected_line {
 };
 
 /*!
- * \brief Redirecting reason information
- */
-struct ast_party_redirecting_reason {
-	/*! \brief a string value for the redirecting reason
-	 *
-	 * Useful for cases where an endpoint has specified a redirecting reason
-	 * that does not correspond to an enum AST_REDIRECTING_REASON
-	 */
-	char *str;
-
-	/*! \brief enum AST_REDIRECTING_REASON value for redirection */
-	int code;
-};
-
-/*!
  * \since 1.8
  * \brief Redirecting Line information.
  * RDNIS (Redirecting Directory Number Information Service)
@@ -521,14 +477,14 @@ struct ast_party_redirecting {
 	/*! \brief Call is redirecting to a new party (Sent to the caller)  - private representation */
 	struct ast_party_id priv_to;
 
-	/*! \brief Reason for the redirection */
-	struct ast_party_redirecting_reason reason;
-
-	/*! \brief Reason for the redirection by the original party */
-	struct ast_party_redirecting_reason orig_reason;
-
 	/*! \brief Number of times the call was redirected */
 	int count;
+
+	/*! \brief enum AST_REDIRECTING_REASON value for redirection */
+	int reason;
+
+	/*! \brief enum AST_REDIRECTING_REASON value for redirection by original party */
+	int orig_reason;
 };
 
 /*!
@@ -581,15 +537,6 @@ typedef struct {
 } ast_chan_write_info_t;
 
 /*!
- * \brief Structure to pass both assignedid values to channel drivers
- * \note The second value is used only by core_unreal (LOCAL)
- */
-struct ast_assigned_ids {
-	const char *uniqueid;
-	const char *uniqueid2;
-};
-
-/*!
  * \brief
  * Structure to describe a channel "technology", ie a channel driver
  * See for examples:
@@ -616,7 +563,6 @@ struct ast_channel_tech {
 	 *
 	 * \param type type of channel to request
 	 * \param cap Format capabilities for requested channel
-	 * \param assignedid Unique ID string to assign to channel
 	 * \param requestor channel asking for data
 	 * \param addr destination of the call
 	 * \param cause Cause of failure
@@ -628,7 +574,7 @@ struct ast_channel_tech {
 	 * \retval NULL failure
 	 * \retval non-NULL channel on success
 	 */
-	struct ast_channel *(* const requester)(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause);
+	struct ast_channel *(* const requester)(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *addr, int *cause);
 
 	int (* const devicestate)(const char *device_number);	/*!< Devicestate call back */
 
@@ -681,6 +627,10 @@ struct ast_channel_tech {
 	/*! \brief Handle an exception, reading a frame */
 	struct ast_frame * (* const exception)(struct ast_channel *chan);
 
+	/*! \brief Bridge two channels of the same type together */
+	enum ast_bridge_result (* const bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags,
+						struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+
 	/*! \brief Bridge two channels of the same type together (early) */
 	enum ast_bridge_result (* const early_bridge)(struct ast_channel *c0, struct ast_channel *c1);
 
@@ -705,6 +655,9 @@ struct ast_channel_tech {
 	/*! \brief Write a text frame, in standard format */
 	int (* const write_text)(struct ast_channel *chan, struct ast_frame *frame);
 
+	/*! \brief Find bridged channel */
+	struct ast_channel *(* const bridged_channel)(struct ast_channel *chan, struct ast_channel *bridge);
+
 	/*!
 	 * \brief Provide additional read items for CHANNEL() dialplan function
 	 * \note data should be treated as a const char *.
@@ -717,6 +670,12 @@ struct ast_channel_tech {
 	 */
 	int (* func_channel_write)(struct ast_channel *chan, const char *function, char *data, const char *value);
 
+	/*! \brief Retrieve base channel (agent and local) */
+	struct ast_channel* (* get_base_channel)(struct ast_channel *chan);
+
+	/*! \brief Set base channel (agent and local) */
+	int (* set_base_channel)(struct ast_channel *chan, struct ast_channel *base);
+
 	/*! \brief Get the unique identifier for the PVT, i.e. SIP call-ID for SIP */
 	const char * (* get_pvt_uniqueid)(struct ast_channel *chan);
 
@@ -820,8 +779,7 @@ typedef int(*ast_timing_func_t)(const void *data);
  * active channels in the system.  The hash key is based on the channel name.  Because
  * of this, if you want to change the name, you _must_ use ast_change_name(), not change
  * the name field directly.  When ast_channel_alloc() returns a channel pointer, you now
- * hold both a reference to that channel and a lock on the channel. Once the channel has
- * been set up the lock can be released. In most cases the reference is given to ast_pbx_run().
+ * hold a reference to that channel.  In most cases this reference is given to ast_pbx_run().
  *
  * \par Channel Locking
  * There is a lock associated with every ast_channel.  It is allocated internally via astobj2.
@@ -868,21 +826,15 @@ struct ast_channel;
 /*! \brief ast_channel_tech Properties */
 enum {
 	/*!
-	 * \brief Channels have this property if they can accept input with jitter;
+     * \brief Channels have this property if they can accept input with jitter;
 	 * i.e. most VoIP channels
 	 */
 	AST_CHAN_TP_WANTSJITTER = (1 << 0),
 	/*!
-	 * \brief Channels have this property if they can create jitter;
+     * \brief Channels have this property if they can create jitter;
 	 * i.e. most VoIP channels
 	 */
 	AST_CHAN_TP_CREATESJITTER = (1 << 1),
-	/*!
-	 * \brief Channels with this particular technology are an implementation detail of
-	 * Asterisk and should generally not be exposed or manipulated by the outside
-	 * world
-	 */
-	AST_CHAN_TP_INTERNAL = (1 << 2),
 };
 
 /*! \brief ast_channel flags */
@@ -901,6 +853,8 @@ enum {
 	AST_FLAG_MOH =           (1 << 6),
 	/*! This channel is spying on another channel */
 	AST_FLAG_SPYING =        (1 << 7),
+	/*! This channel is in a native bridge */
+	AST_FLAG_NBRIDGE =       (1 << 8),
 	/*! the channel is in an auto-incrementing dialplan processor,
 	 *  so when ->priority is set, it will get incremented before
 	 *  finding the next priority to run */
@@ -916,8 +870,8 @@ enum {
 	 *  to instead only generate END frames. */
 	AST_FLAG_END_DTMF_ONLY = (1 << 14),
 	/* OBSOLETED in favor of AST_CAUSE_ANSWERED_ELSEWHERE
-	 * Flag to show channels that this call is hangup due to the fact that the call
-	 * was indeed answered, but in another channel */
+	Flag to show channels that this call is hangup due to the fact that the call
+	    was indeed answered, but in another channel */
 	/* AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15), */
 	/*! This flag indicates that on a masquerade, an active stream should not
 	 *  be carried over */
@@ -926,6 +880,10 @@ enum {
 	 *  a message aimed at preventing a subsequent hangup exten being run at the pbx_run
 	 *  level */
 	AST_FLAG_BRIDGE_HANGUP_RUN = (1 << 17),
+	/*! This flag indicates that the hangup exten should NOT be run when the
+	 *  bridge terminates, this will allow the hangup in the pbx loop to be run instead.
+	 *  */
+	AST_FLAG_BRIDGE_HANGUP_DONT = (1 << 18),
 	/*! Disable certain workarounds.  This reintroduces certain bugs, but allows
 	 *  some non-traditional dialplans (like AGI) to continue to function.
 	 */
@@ -944,28 +902,9 @@ enum {
 	 */
 	AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT = (1 << 22),
 	/*!
-	 * This flag indicates that the channel was originated.
-	 */
-	AST_FLAG_ORIGINATED = (1 << 23),
-	/*!
-	 * The channel is well and truly dead. Once this is set and published, no further
-	 * actions should be taken upon the channel, and no further publications should
-	 * occur.
-	 */
-	AST_FLAG_DEAD = (1 << 24),
-	/*!
-	 * Channel snapshot should not be published, it is being staged for an explicit
-	 * publish.
-	 */
-	AST_FLAG_SNAPSHOT_STAGE = (1 << 25),
-	/*!
 	 * The data on chan->timingdata is an astobj2 object.
 	 */
-	AST_FLAG_TIMINGDATA_IS_AO2_OBJ = (1 << 26),
-	/*!
-	 * The channel is executing a subroutine or macro
-	 */
-	AST_FLAG_SUBROUTINE_EXEC = (1 << 27),
+	AST_FLAG_TIMINGDATA_IS_AO2_OBJ = (1 << 23),
 };
 
 /*! \brief ast_bridge_config flags */
@@ -977,11 +916,10 @@ enum {
 	AST_FEATURE_AUTOMON =      (1 << 4),
 	AST_FEATURE_PARKCALL =     (1 << 5),
 	AST_FEATURE_AUTOMIXMON =   (1 << 6),
+	AST_FEATURE_NO_H_EXTEN =   (1 << 7),
+	AST_FEATURE_WARNING_ACTIVE = (1 << 8),
 };
 
-#define AST_FEATURE_DTMF_MASK (AST_FEATURE_REDIRECT | AST_FEATURE_DISCONNECT |\
-	AST_FEATURE_ATXFER | AST_FEATURE_AUTOMON | AST_FEATURE_PARKCALL | AST_FEATURE_AUTOMIXMON)
-
 /*! \brief bridge configuration */
 struct ast_bridge_config {
 	struct ast_flags features_caller;
@@ -1053,11 +991,12 @@ enum {
 	 */
 	AST_SOFTHANGUP_EXPLICIT =  (1 << 5),
 	/*!
-	 * Used to indicate that the channel is currently executing hangup
-	 * logic in the dialplan. The channel has been hungup when this is
-	 * set.
+	 * Used to break a bridge so the channel can be spied upon
+	 * instead of actually hanging up.
 	 */
-	AST_SOFTHANGUP_HANGUP_EXEC = (1 << 7),
+	AST_SOFTHANGUP_UNBRIDGE =  (1 << 6),
+
+
 	/*!
 	 * \brief All softhangup flags.
 	 *
@@ -1078,16 +1017,6 @@ enum channelreloadreason {
 };
 
 /*!
- * \brief Channel AMA Flags
- */
-enum ama_flags {
-	AST_AMA_NONE = 0,
-	AST_AMA_OMIT,
-	AST_AMA_BILLING,
-	AST_AMA_DOCUMENTATION,
-};
-
-/*!
  * \note None of the datastore API calls lock the ast_channel they are using.
  *       So, the channel should be locked before calling the functions that
  *       take a channel argument.
@@ -1155,16 +1084,14 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const
  * \note Absolutely _NO_ channel locks should be held before calling this function.
  * \note By default, new channels are set to the "s" extension
  *       and "default" context.
- * \note Since 12.0.0 this function returns with the newly created channel locked.
  */
-struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 16)))
+struct ast_channel * attribute_malloc __attribute__((format(printf, 13, 14)))
 	__ast_channel_alloc(int needqueue, int state, const char *cid_num,
-		const char *cid_name, const char *acctcode,
-		const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
-		const struct ast_channel *requestor, enum ama_flags amaflag,
-		struct ast_endpoint *endpoint,
-		const char *file, int line, const char *function,
-		const char *name_fmt, ...);
+			    const char *cid_name, const char *acctcode,
+			    const char *exten, const char *context,
+			    const char *linkedid, const int amaflag,
+			    const char *file, int line, const char *function,
+			    const char *name_fmt, ...);
 
 /*!
  * \brief Create a channel structure
@@ -1175,16 +1102,10 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 16)))
  * \note Absolutely _NO_ channel locks should be held before calling this function.
  * \note By default, new channels are set to the "s" extension
  *       and "default" context.
- * \note Since 12.0.0 this function returns with the newly created channel locked.
  */
-#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag, ...) \
-	__ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag, NULL, \
-		__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
-
-#define ast_channel_alloc_with_endpoint(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag, endpoint, ...) \
-	__ast_channel_alloc((needqueue), (state), (cid_num), (cid_name), (acctcode), (exten), (context), (assignedids), (requestor), (amaflag), (endpoint), \
-		__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
-
+#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, linkedid, amaflag, ...) \
+	__ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, linkedid, amaflag, \
+			    __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
 
 #if defined(REF_DEBUG) || defined(__AST_DEBUG_MALLOC)
 /*!
@@ -1272,32 +1193,7 @@ int ast_queue_hangup(struct ast_channel *chan);
 int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause);
 
 /*!
- * \brief Queue a hold frame
- *
- * \param chan channel to queue frame onto
- * \param musicclass The suggested musicclass for the other end to use
- *
- * \note The channel does not need to be locked before calling this function.
- *
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_queue_hold(struct ast_channel *chan, const char *musicclass);
-
-/*!
- * \brief Queue an unhold frame
- *
- * \param chan channel to queue frame onto
- *
- * \note The channel does not need to be locked before calling this function.
- *
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_queue_unhold(struct ast_channel *chan);
-
-/*!
- * \brief Queue a control frame without payload
+ * \brief Queue a control frame with payload
  *
  * \param chan channel to queue frame onto
  * \param control type of control frame
@@ -1372,7 +1268,6 @@ struct ast_channel *ast_channel_release(struct ast_channel *chan);
  *
  * \param type type of channel to request
  * \param request_cap Format capabilities for requested channel
- * \param assignedids Unique ID to create channel with
  * \param requestor channel asking for data
  * \param addr destination of the call
  * \param cause Cause of failure
@@ -1384,54 +1279,14 @@ struct ast_channel *ast_channel_release(struct ast_channel *chan);
  * \retval NULL failure
  * \retval non-NULL channel on success
  */
-struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause);
-
-enum ast_channel_requestor_relationship {
-	/*! The requestor is the future bridge peer of the channel. */
-	AST_CHANNEL_REQUESTOR_BRIDGE_PEER,
-	/*! The requestor is to be replaced by the channel. */
-	AST_CHANNEL_REQUESTOR_REPLACEMENT,
-};
-
-/*!
- * \brief Setup new channel accountcodes from the requestor channel after ast_request().
- * \since 13.0.0
- *
- * \param chan New channel to get accountcodes setup.
- * \param requestor Requesting channel to get accountcodes from.
- * \param relationship What the new channel was created for.
- *
- * \pre The chan and requestor channels are already locked.
- *
- * \note Pre-existing accountcodes on chan will be overwritten.
- *
- * \return Nothing
- */
-void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship);
-
-/*!
- * \brief Setup new channel accountcodes from the requestor channel after ast_request().
- * \since 13.0.0
- *
- * \param chan New channel to get accountcodes setup.
- * \param requestor Requesting channel to get accountcodes from.
- * \param relationship What the new channel was created for.
- *
- * \pre The chan and requestor channels are already locked.
- *
- * \note Pre-existing accountcodes on chan will not be overwritten.
- *
- * \return Nothing
- */
-void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship);
+struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_channel *requestor, const char *addr, int *cause);
 
 /*!
  * \brief Request a channel of a given type, with data as optional information used
  *        by the low level module and attempt to place a call on it
  *
  * \param type type of channel to request
- * \param cap format capabilities for requested channel
- * \param assignedids Unique Id to assign to channel
+ * \param format capabilities for requested channel
  * \param requestor channel asking for data
  * \param addr destination of the call
  * \param timeout maximum amount of time to wait for an answer
@@ -1442,15 +1297,14 @@ void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struc
  * \return Returns an ast_channel on success or no answer, NULL on failure.  Check the value of chan->_state
  * to know if the call was answered or not.
  */
-struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr,
+struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *addr,
 	int timeout, int *reason, const char *cid_num, const char *cid_name);
 
 /*!
  * \brief Request a channel of a given type, with data as optional information used
  * by the low level module and attempt to place a call on it
  * \param type type of channel to request
- * \param cap format capabilities for requested channel
- * \param assignedids Unique Id to assign to channel
+ * \param format capabilities for requested channel
  * \param requestor channel requesting data
  * \param addr destination of the call
  * \param timeout maximum amount of time to wait for an answer
@@ -1461,7 +1315,7 @@ struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap
  * \return Returns an ast_channel on success or no answer, NULL on failure.  Check the value of chan->_state
  * to know if the call was answered or not.
  */
-struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr,
+struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *addr,
 	int timeout, int *reason, const char *cid_num, const char *cid_name, struct outgoing_helper *oh);
 
 /*!
@@ -1469,7 +1323,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
  * \param caller in channel that requested orig
  * \param orig channel being replaced by the call forward channel
  * \param timeout maximum amount of time to wait for setup of new forward channel
- * \param cap format capabilities for requested channel
+ * \param format capabilities for requested channel
  * \param oh outgoing helper used with original channel
  * \param outstate reason why unsuccessful (if uncuccessful)
  * \return Returns the forwarded call's ast_channel on success or NULL on failure
@@ -1498,16 +1352,49 @@ void ast_channel_unregister(const struct ast_channel_tech *tech);
  */
 const struct ast_channel_tech *ast_get_channel_tech(const char *name);
 
+#ifdef CHANNEL_TRACE
+/*!
+ * \brief Update the context backtrace if tracing is enabled
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_channel_trace_update(struct ast_channel *chan);
+
+/*!
+ * \brief Enable context tracing in the channel
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_channel_trace_enable(struct ast_channel *chan);
+
+/*!
+ * \brief Disable context tracing in the channel.
+ * \note Does not remove current trace entries
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_channel_trace_disable(struct ast_channel *chan);
+
+/*!
+ * \brief Whether or not context tracing is enabled
+ * \return Returns -1 when the trace is enabled. 0 if not.
+ */
+int ast_channel_trace_is_enabled(struct ast_channel *chan);
+
+/*!
+ * \brief Put the channel backtrace in a string
+ * \return Returns the amount of lines in the backtrace. -1 on error.
+ */
+int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
+#endif
+
 /*!
  * \brief Hang up a channel
  * \note Absolutely _NO_ channel locks should be held before calling this function.
  * \note This function performs a hard hangup on a channel.  Unlike the soft-hangup, this function
  * performs all stream stopping, etc, on the channel that needs to end.
  * chan is no longer valid after this call.
- * \param chan channel to hang up (NULL tolerant)
- * \return Nothing
+ * \param chan channel to hang up
+ * \return Returns 0 on success, -1 on failure.
  */
-void ast_hangup(struct ast_channel *chan);
+int ast_hangup(struct ast_channel *chan);
 
 /*!
  * \brief Softly hangup up a channel
@@ -1573,40 +1460,6 @@ int ast_check_hangup(struct ast_channel *chan);
 
 int ast_check_hangup_locked(struct ast_channel *chan);
 
-/*! \brief This function will check if the bridge needs to be re-evaluated due to
- *         external changes.
- *
- *  \param chan Channel on which to check the unbridge_eval flag
- *
- *  \return Returns 0 if the flag is down or 1 if the flag is up.
- */
-int ast_channel_unbridged(struct ast_channel *chan);
-
-/*! \brief ast_channel_unbridged variant. Use this if the channel
- *         is already locked prior to calling.
- *
- *  \param chan Channel on which to check the unbridge flag
- *
- *  \return Returns 0 if the flag is down or 1 if the flag is up.
- */
-int ast_channel_unbridged_nolock(struct ast_channel *chan);
-
-/*! \brief Sets the unbridged flag and queues a NULL frame on the channel to trigger
- *         a check by bridge_channel_wait
- *
- *  \param chan Which channel is having its unbridged value set
- *  \param value What the unbridge value is being set to
- */
-void ast_channel_set_unbridged(struct ast_channel *chan, int value);
-
-/*! \brief Variant of ast_channel_set_unbridged. Use this if the channel
- *         is already locked prior to calling.
- *
- *  \param chan Which channel is having its unbridged value set
- *  \param value What the unbridge value is being set to
- */
-void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value);
-
 /*!
  * \brief Lock the given channel, then request softhangup on the channel with the given causecode
  * \param chan channel on which to hang up
@@ -1652,7 +1505,8 @@ int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offs
  * \details
  * This function sets the absolute time out on a channel (when to hang up).
  *
- * \pre chan is locked
+ * \note This function does not require that the channel is locked before
+ *       calling it.
  *
  * \return Nothing
  * \sa ast_channel_setwhentohangup_tv()
@@ -1668,7 +1522,8 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attr
  *
  * This function sets the absolute time out on a channel (when to hang up).
  *
- * \pre chan is locked
+ * \note This function does not require that the channel is locked before
+ * calling it.
  *
  * \return Nothing
  * \since 1.6.1
@@ -1697,21 +1552,10 @@ void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval off
 int ast_answer(struct ast_channel *chan);
 
 /*!
- * \brief Answer a channel, if it's not already answered.
- *
- * \param chan channel to answer
- *
- * \details See ast_answer()
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-int ast_auto_answer(struct ast_channel *chan);
-
-/*!
  * \brief Answer a channel
  *
  * \param chan channel to answer
+ * \param cdr_answer flag to control whether any associated CDR should be marked as 'answered'
  *
  * This function answers a channel and handles all necessary call
  * setup functions.
@@ -1727,13 +1571,14 @@ int ast_auto_answer(struct ast_channel *chan);
  * \retval 0 on success
  * \retval non-zero on failure
  */
-int ast_raw_answer(struct ast_channel *chan);
+int ast_raw_answer(struct ast_channel *chan, int cdr_answer);
 
 /*!
  * \brief Answer a channel, with a selectable delay before returning
  *
  * \param chan channel to answer
  * \param delay maximum amount of time to wait for incoming media
+ * \param cdr_answer flag to control whether any associated CDR should be marked as 'answered'
  *
  * This function answers a channel and handles all necessary call
  * setup functions.
@@ -1749,7 +1594,7 @@ int ast_raw_answer(struct ast_channel *chan);
  * \retval 0 on success
  * \retval non-zero on failure
  */
-int __ast_answer(struct ast_channel *chan, unsigned int delay);
+int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer);
 
 /*!
  * \brief Execute a Gosub call on the channel before a call is placed.
@@ -1955,12 +1800,20 @@ int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap
 /*!
  * \brief Sets read format on channel chan
  * \param chan channel to change
- * \param format format to set for reading
+ * \param formats, format to set for reading
  * \return Returns 0 on success, -1 on failure
  */
 int ast_set_read_format(struct ast_channel *chan, struct ast_format *format);
 
 /*!
+ * \brief Sets read format on channel chan by id
+ * \param chan channel to change
+ * \param format id to set for reading, only used for formats without attributes
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id);
+
+/*!
  * \brief Sets write format on channel chan
  * Set write format for channel to whichever component of "format" is best.
  * \param chan channel to change
@@ -1972,12 +1825,20 @@ int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_ca
 /*!
  * \brief Sets write format on channel chan
  * \param chan channel to change
- * \param format format to set for writing
+ * \param formats, format to set for writing
  * \return Returns 0 on success, -1 on failure
  */
 int ast_set_write_format(struct ast_channel *chan, struct ast_format *format);
 
 /*!
+ * \brief Sets write format on channel chan
+ * \param chan channel to change
+ * \param format id to set for writing, only used for formats without attributes
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id);
+
+/*!
  * \brief Sends text to a channel
  *
  * \param chan channel to act upon
@@ -2080,26 +1941,23 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in
 #define AST_BRIDGE_DTMF_CHANNEL_0		(1 << 0)
 /*! \brief Report DTMF on channel 1 */
 #define AST_BRIDGE_DTMF_CHANNEL_1		(1 << 1)
+/*! \brief Return all voice frames on channel 0 */
+#define AST_BRIDGE_REC_CHANNEL_0		(1 << 2)
+/*! \brief Return all voice frames on channel 1 */
+#define AST_BRIDGE_REC_CHANNEL_1		(1 << 3)
+/*! \brief Ignore all signal frames except NULL */
+#define AST_BRIDGE_IGNORE_SIGS			(1 << 4)
 
 
 /*!
- * \brief Make the frame formats of two channels compatible.
- *
- * \param chan First channel to make compatible.  Should be the calling party.
- * \param peer Other channel to make compatible.  Should be the called party.
- *
- * \note Absolutely _NO_ channel locks should be held before calling this function.
- *
+ * \brief Makes two channel formats compatible
+ * \param c0 first channel to make compatible
+ * \param c1 other channel to make compatible
  * \details
- * Set two channels to compatible frame formats in both
- * directions.  The path from peer to chan is made compatible
- * first to allow for in-band audio in case the other direction
- * cannot be made compatible.
- *
- * \retval 0 on success.
- * \retval -1 on error.
+ * Set two channels to compatible formats -- call before ast_channel_bridge in general.
+ * \return Returns 0 on success and -1 if it could not be done
  */
-int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer);
+int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
 
 /*!
  * \brief Bridge two channels together (early)
@@ -2112,6 +1970,87 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
 int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
 
 /*!
+ * \brief Bridge two channels together
+ * \param c0 first channel to bridge
+ * \param c1 second channel to bridge
+ * \param config config for the channels
+ * \param fo destination frame(?)
+ * \param rc destination channel(?)
+ * \details
+ * Bridge two channels (c0 and c1) together.  If an important frame occurs, we return that frame in
+ * *rf (remember, it could be NULL) and which channel (0 or 1) in rc
+ */
+/* int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); */
+int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
+	struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc);
+
+/*!
+ * \brief Weird function made for call transfers
+ *
+ * \param original channel to make a copy of
+ * \param clone copy of the original channel
+ *
+ * \details
+ * This is a very strange and freaky function used primarily for transfer.  Suppose that
+ * "original" and "clone" are two channels in random situations.  This function takes
+ * the guts out of "clone" and puts them into the "original" channel, then alerts the
+ * channel driver of the change, asking it to fixup any private information (like the
+ * p->owner pointer) that is affected by the change.  The physical layer of the original
+ * channel is hung up.
+ *
+ * \note Neither channel passed here should be locked before
+ * calling this function.  This function performs deadlock
+ * avoidance involving these two channels.
+ */
+int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
+
+/*!
+ * \brief Setup a masquerade to transfer a call.
+ * \since 1.8
+ *
+ * \param target_chan Target of the call transfer.  (Masquerade original channel)
+ * \param target_id New connected line information for the target channel.
+ * \param target_held TRUE if the target call is on hold.
+ * \param transferee_chan Transferee of the call transfer. (Masquerade clone channel)
+ * \param transferee_id New connected line information for the transferee channel.
+ * \param transferee_held TRUE if the transferee call is on hold.
+ *
+ * \details
+ * Party A - Transferee
+ * Party B - Transferer
+ * Party C - Target of transfer
+ *
+ * Party B transfers A to C.
+ *
+ * Party A is connected to bridged channel B1.
+ * Party B is connected to channels C1 and C2.
+ * Party C is connected to bridged channel B2.
+ *
+ * Party B -- C1 == B1 -- Party A
+ *               __/
+ *              /
+ * Party B -- C2 == B2 -- Party C
+ *
+ * Bridged channel B1 is masqueraded into channel C2.  Where B1
+ * is the masquerade clone channel and C2 is the masquerade
+ * original channel.
+ *
+ * \see ast_channel_masquerade()
+ *
+ * \note Has the same locking requirements as ast_channel_masquerade().
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_channel_transfer_masquerade(
+	struct ast_channel *target_chan,
+	const struct ast_party_connected_line *target_id,
+	int target_held,
+	struct ast_channel *transferee_chan,
+	const struct ast_party_connected_line *transferee_id,
+	int transferee_held);
+
+/*!
  * \brief Gives the string form of a given cause code.
  *
  * \param state cause to get the description of
@@ -2165,6 +2104,17 @@ char *ast_transfercapability2str(int transfercapability) attribute_const;
 int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
 
 /*!
+ * \brief Pick the best codec
+ *
+ * \param capabilities to pick best codec out of
+ * \param result stucture to store the best codec in.
+ * \retval on success, pointer to result structure
+ * \retval on failure, NULL
+ */
+struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format *result);
+
+
+/*!
  * \brief Checks the value of an option
  *
  * Query the value of an option
@@ -2226,28 +2176,6 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen,
 void ast_deactivate_generator(struct ast_channel *chan);
 
 /*!
- * \since 12
- * \brief Obtain how long the channel since the channel was created
- *
- * \param chan The channel object
- *
- * \retval 0 if the time value cannot be computed (or you called this really fast)
- * \retval The number of seconds the channel has been up
- */
-int ast_channel_get_duration(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Obtain how long it has been since the channel was answered
- *
- * \param chan The channel object
- *
- * \retval 0 if the channel isn't answered (or you called this really fast)
- * \retval The number of seconds the channel has been up
- */
-int ast_channel_get_up_time(struct ast_channel *chan);
-
-/*!
  * \brief Set caller ID number, name and ANI and generate AMI event.
  *
  * \note Use ast_channel_set_caller() and ast_channel_set_caller_event() instead.
@@ -2375,6 +2303,38 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co
 int ast_transfer(struct ast_channel *chan, char *dest);
 
 /*!
+ * \brief Start masquerading a channel
+ * \note absolutely _NO_ channel locks should be held before calling this function.
+ * \details
+ * XXX This is a seriously whacked out operation.  We're essentially putting the guts of
+ *     the clone channel into the original channel.  Start by killing off the original
+ *     channel's backend.   I'm not sure we're going to keep this function, because
+ *     while the features are nice, the cost is very high in terms of pure nastiness. XXX
+ * \param chan Channel to masquerade
+ */
+int ast_do_masquerade(struct ast_channel *chan);
+
+/*!
+ * \brief Find bridged channel
+ *
+ * \note This function does _not_ return a reference to the bridged channel.
+ * The reason for this is mostly historical.  It _should_ return a reference,
+ * but it will take a lot of work to make the code base account for that.
+ * So, for now, the old rules still apply for how to handle this function.
+ * If this function is being used from the channel thread that owns the channel,
+ * then a reference is already held, and channel locking is not required to
+ * guarantee that the channel will stay around.  If this function is used
+ * outside of the associated channel thread, the channel parameter 'chan'
+ * MUST be locked before calling this function.  Also, 'chan' must remain locked
+ * for the entire time that the result of this function is being used.
+ *
+ * \param chan Current channel
+ *
+ * \return A pointer to the bridged channel
+*/
+struct ast_channel *ast_bridged_channel(struct ast_channel *chan);
+
+/*!
  * \brief Inherits channel variable from parent to child channel
  * \param parent Parent channel
  * \param child Child channel
@@ -2394,8 +2354,6 @@ void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_
  * \param chan the channel
  * \param vars a linked list of variables
  *
- * \pre chan is locked
- *
  * \details
  * Variable names can be for a regular channel variable or a dialplan function
  * that has the ability to be written to.
@@ -2438,55 +2396,15 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha
 void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state);
 
 /*!
- * \brief Determine which channel has an older linkedid
- * \param a First channel
- * \param b Second channel
- * \return Returns an ast_channel structure that has oldest linkedid
- */
-struct ast_channel *ast_channel_internal_oldest_linkedid(struct ast_channel *a, struct ast_channel *b);
-
-/*!
- * \brief Copy the full linkedid channel id structure from one channel to another
- * \param dest Destination to copy linkedid to
- * \param source Source channel to copy linkedid from
- * \return void
- */
-void ast_channel_internal_copy_linkedid(struct ast_channel *dest, struct ast_channel *source);
-
-/*!
- * \brief Swap uniqueid and linkedid beteween two channels
- * \param a First channel
- * \param b Second channel
- * \return void
- *
- * \note
- * This is used in masquerade to exchange identities
- */
-void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, struct ast_channel *b);
-
-/*!
- * \brief Swap topics beteween two channels
- * \param a First channel
- * \param b Second channel
- * \return void
+ * \brief Check if the channel can run in internal timing mode.
+ * \param chan The channel to check
+ * \return boolean
  *
- * \note
- * This is used in masquerade to exchange topics for message routing
- */
-void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b);
-
-/*!
- * \brief Set uniqueid and linkedid string value only (not time)
- * \param chan The channel to set the uniqueid to
- * \param uniqueid The uniqueid to set
- * \param linkedid The linkedid to set
- * \return void
- *
- * \note
- * This is used only by ast_cel_fabricate_channel_from_event()
- * to create a temporary fake channel - time values are invalid
+ * \details
+ * This function will return 1 if internal timing is enabled and the timing
+ * device is available.
  */
-void ast_channel_internal_set_fake_ids(struct ast_channel *chan, const char *uniqueid, const char *linkedid);
+int ast_internal_timing_enabled(struct ast_channel *chan);
 
 /* Misc. functions below */
 
@@ -2622,17 +2540,6 @@ struct ast_group_info {
  */
 #define ast_channel_unref(c) ({ ao2_ref(c, -1); (struct ast_channel *) (NULL); })
 
-/*!
- * \brief Cleanup a channel reference
- *
- * \param c the channel (NULL tolerant)
- *
- * \retval NULL always
- *
- * \since 12.0.0
- */
-#define ast_channel_cleanup(c) ({ ao2_cleanup(c); (struct ast_channel *) (NULL); })
-
 /*! Channel Iterating @{ */
 
 /*!
@@ -2801,6 +2708,12 @@ struct ast_channel *ast_channel_get_by_exten(const char *exten, const char *cont
 /*! @} End channel search functions. */
 
 /*!
+  \brief propagate the linked id between chan and peer
+ */
+void ast_channel_set_linkgroup(struct ast_channel *chan, struct ast_channel *peer);
+
+
+/*!
  * \brief Initialize the given name structure.
  * \since 1.8
  *
@@ -3091,7 +3004,7 @@ void ast_party_id_reset(struct ast_party_id *id);
  *
  * \details
  * This function will generate an effective party id.
- *
+ * 
  * Each party id component of the party id 'base' is overwritten
  * by components of the party id 'overlay' if the overlay
  * component is marked as valid.  However the component 'tag' of
@@ -3335,68 +3248,6 @@ void ast_party_connected_line_collect_caller(struct ast_party_connected_line *co
 void ast_party_connected_line_free(struct ast_party_connected_line *doomed);
 
 /*!
- * \brief Initialize the given redirecting reason structure
- *
- * \param init Redirecting reason structure to initialize
- *
- * \return Nothing
- */
-void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init);
-
-/*!
- * \brief Copy the source redirecting reason information to the destination redirecting reason.
- *
- * \param dest Destination redirecting reason
- * \param src Source redirecting reason
- *
- * \return Nothing
- */
-void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest,
-		const struct ast_party_redirecting_reason *src);
-
-/*!
- * \brief Initialize the given redirecting reason structure using the given guide
- * for a set update operation.
- *
- * \details
- * The initialization is needed to allow a set operation to know if a
- * value needs to be updated.  Simple integers need the guide's original
- * value in case the set operation is not trying to set a new value.
- * String values are simply set to NULL pointers if they are not going
- * to be updated.
- *
- * \param init Redirecting reason structure to initialize.
- * \param guide Source redirecting reason to use as a guide in initializing.
- *
- * \return Nothing
- */
-void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init,
-		const struct ast_party_redirecting_reason *guide);
-
-/*!
- * \brief Set the redirecting reason information based on another redirecting reason source
- *
- * This is similar to ast_party_redirecting_reason_copy, except that NULL values for
- * strings in the src parameter indicate not to update the corresponding dest values.
- *
- * \param dest The redirecting reason one wishes to update
- * \param src The new redirecting reason values to update the dest
- *
- * \return Nothing
- */
-void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest,
-		const struct ast_party_redirecting_reason *src);
-
-/*!
- * \brief Destroy the redirecting reason contents
- *
- * \param doomed The redirecting reason to destroy.
- *
- * \return Nothing
- */
-void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed);
-
-/*!
  * \brief Initialize the given redirecting structure.
  * \since 1.8
  *
@@ -3864,7 +3715,7 @@ int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, si
 void ast_channel_unlink(struct ast_channel *chan);
 
 /*!
- * \brief Sets the HANGUPCAUSE hash and optionally the SIP_CAUSE hash
+ * \brief Sets the HANGUPCAUSE hash and optionally the SIP_CAUSE hash 
  * on the given channel
  *
  * \param chan channel on which to set the cause information
@@ -3873,26 +3724,6 @@ void ast_channel_unlink(struct ast_channel *chan);
  */
 void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast_control_pvt_cause_code *cause_code, int datalen);
 
-/*!
- * \since 12
- * \brief Convert a string to a detail record AMA flag
- *
- * \param flag string form of flag
- *
- * \retval the enum (integer) form of the flag
- */
-enum ama_flags ast_channel_string2amaflag(const char *flag);
-
-/*!
- * \since 12
- * \brief Convert the enum representation of an AMA flag to a string representation
- *
- * \param flags integer flag
- *
- * \retval A string representation of the flag
- */
-const char *ast_channel_amaflags2string(enum ama_flags flags);
-
 /* ACCESSOR FUNTIONS */
 /*! \brief Set the channel name */
 void ast_channel_name_set(struct ast_channel *chan, const char *name);
@@ -3902,19 +3733,9 @@ void ast_channel_name_set(struct ast_channel *chan, const char *name);
 	void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) __attribute__((format(printf, 2, 0))); \
 	void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) __attribute__((format(printf, 2, 3)))
 
-/*!
- * The following string fields result in channel snapshot creation and
- * should have the channel locked when called:
- *
- * \li language
- * \li accountcode
- * \li peeracccount
- * \li linkedid
- */
 DECLARE_STRINGFIELD_SETTERS_FOR(name);
 DECLARE_STRINGFIELD_SETTERS_FOR(language);
 DECLARE_STRINGFIELD_SETTERS_FOR(musicclass);
-DECLARE_STRINGFIELD_SETTERS_FOR(latest_musicclass);
 DECLARE_STRINGFIELD_SETTERS_FOR(accountcode);
 DECLARE_STRINGFIELD_SETTERS_FOR(peeraccount);
 DECLARE_STRINGFIELD_SETTERS_FOR(userfield);
@@ -3928,7 +3749,6 @@ DECLARE_STRINGFIELD_SETTERS_FOR(dialcontext);
 const char *ast_channel_name(const struct ast_channel *chan);
 const char *ast_channel_language(const struct ast_channel *chan);
 const char *ast_channel_musicclass(const struct ast_channel *chan);
-const char *ast_channel_latest_musicclass(const struct ast_channel *chan);
 const char *ast_channel_accountcode(const struct ast_channel *chan);
 const char *ast_channel_peeraccount(const struct ast_channel *chan);
 const char *ast_channel_userfield(const struct ast_channel *chan);
@@ -3961,12 +3781,8 @@ char ast_channel_sending_dtmf_digit(const struct ast_channel *chan);
 void ast_channel_sending_dtmf_digit_set(struct ast_channel *chan, char value);
 struct timeval ast_channel_sending_dtmf_tv(const struct ast_channel *chan);
 void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval value);
-enum ama_flags ast_channel_amaflags(const struct ast_channel *chan);
-
-/*!
- * \pre chan is locked
- */
-void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value);
+int ast_channel_amaflags(const struct ast_channel *chan);
+void ast_channel_amaflags_set(struct ast_channel *chan, int value);
 int ast_channel_epfd(const struct ast_channel *chan);
 void ast_channel_epfd_set(struct ast_channel *chan, int value);
 int ast_channel_fdno(const struct ast_channel *chan);
@@ -3985,8 +3801,6 @@ int ast_channel_timingfd(const struct ast_channel *chan);
 void ast_channel_timingfd_set(struct ast_channel *chan, int value);
 int ast_channel_visible_indication(const struct ast_channel *chan);
 void ast_channel_visible_indication_set(struct ast_channel *chan, int value);
-int ast_channel_hold_state(const struct ast_channel *chan);
-void ast_channel_hold_state_set(struct ast_channel *chan, int value);
 int ast_channel_vstreamid(const struct ast_channel *chan);
 void ast_channel_vstreamid_set(struct ast_channel *chan, int value);
 unsigned short ast_channel_transfercapability(const struct ast_channel *chan);
@@ -4049,10 +3863,6 @@ enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan);
 void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value);
 enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 struct ast_callid *ast_channel_callid(const struct ast_channel *chan);
-
-/*!
- * \pre chan is locked
- */
 void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *value);
 
 /* XXX Internal use only, make sure to move later */
@@ -4070,19 +3880,11 @@ struct ast_format *ast_channel_rawwriteformat(struct ast_channel *chan);
 struct ast_format *ast_channel_readformat(struct ast_channel *chan);
 struct ast_format *ast_channel_writeformat(struct ast_channel *chan);
 
-/* Format setters - all of these functions will increment the reference count of the format passed in */
-void ast_channel_set_oldwriteformat(struct ast_channel *chan, struct ast_format *format);
-void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format);
-void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format);
-void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format);
-void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format);
-
 /* Other struct getters */
 struct ast_frame *ast_channel_dtmff(struct ast_channel *chan);
 struct ast_jb *ast_channel_jb(struct ast_channel *chan);
 struct ast_party_caller *ast_channel_caller(struct ast_channel *chan);
 struct ast_party_connected_line *ast_channel_connected(struct ast_channel *chan);
-struct ast_party_connected_line *ast_channel_connected_indicated(struct ast_channel *chan);
 struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan);
 struct ast_party_dialed *ast_channel_dialed(struct ast_channel *chan);
 struct ast_party_redirecting *ast_channel_redirecting(struct ast_channel *chan);
@@ -4100,16 +3902,10 @@ void ast_channel_connected_set(struct ast_channel *chan, struct ast_party_connec
 void ast_channel_dialed_set(struct ast_channel *chan, struct ast_party_dialed *value);
 void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redirecting *value);
 void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value);
-
-/*!
- * \pre chan is locked
- */
 void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value);
 void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value);
 struct timeval ast_channel_creationtime(struct ast_channel *chan);
 void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value);
-struct timeval ast_channel_answertime(struct ast_channel *chan);
-void ast_channel_answertime_set(struct ast_channel *chan, struct timeval *value);
 
 /* List getters */
 struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan);
@@ -4119,14 +3915,8 @@ struct ast_readq_list *ast_channel_readq(struct ast_channel *chan);
 
 /* Typedef accessors */
 ast_group_t ast_channel_callgroup(const struct ast_channel *chan);
-/*!
- * \pre chan is locked
- */
 void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value);
 ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan);
-/*!
- * \pre chan is locked
- */
 void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value);
 struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan);
 void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value);
@@ -4173,26 +3963,20 @@ ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan);
 void ast_channel_timingfunc_set(struct ast_channel *chan, ast_timing_func_t value);
 
 struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan);
-/*!
- * \pre chan is locked
- */
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value);
 
-struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan);
-void ast_channel_internal_bridge_channel_set(struct ast_channel *chan, struct ast_bridge_channel *value);
-
 struct ast_channel *ast_channel_internal_bridged_channel(const struct ast_channel *chan);
 void ast_channel_internal_bridged_channel_set(struct ast_channel *chan, struct ast_channel *value);
 
 /*!
  * \since 11
- * \brief Retreive a comma-separated list of channels for which dialed cause information is available
+ * \brief Retrieve a comma-separated list of channels for which dialed cause information is available
  *
  * \details
  * This function makes use of datastore operations on the channel, so
  * it is important to lock the channel before calling this function.
  *
- * \param chan The channel from which to retreive information
+ * \param chan The channel from which to retrieve information
  * \retval NULL on allocation failure
  * \retval Pointer to an ast_str object containing the desired information which must be freed
  */
@@ -4200,7 +3984,7 @@ struct ast_str *ast_channel_dialed_causes_channels(const struct ast_channel *cha
 
 /*!
  * \since 11
- * \brief Retreive a ref-counted cause code information structure
+ * \brief Retrieve a ref-counted cause code information structure
  *
  * \details
  * This function makes use of datastore operations on the channel, so
@@ -4209,8 +3993,8 @@ struct ast_str *ast_channel_dialed_causes_channels(const struct ast_channel *cha
  * calling function must decrease the reference count when it is finished
  * with the object.
  *
- * \param chan The channel from which to retreive information
- * \param chan_name The name of the channel about which to retreive information
+ * \param chan The channel from which to retrieve information
+ * \param chan_name The name of the channel about which to retrieve information
  * \retval NULL on search failure
  * \retval Pointer to a ref-counted ast_control_pvt_cause_code object containing the desired information
  */
@@ -4246,355 +4030,4 @@ int ast_channel_dialed_causes_add(const struct ast_channel *chan, const struct a
 void ast_channel_dialed_causes_clear(const struct ast_channel *chan);
 
 struct ast_flags *ast_channel_flags(struct ast_channel *chan);
-
-/*!
- * \since 12.4.0
- * \brief Return whether or not any manager variables have been set
- *
- * \retval 0 if no manager variables are expected
- * \retval 1 if manager variables are expected
- */
-int ast_channel_has_manager_vars(void);
-
-/*!
- * \since 12
- * \brief Sets the variables to be stored in the \a manager_vars field of all
- * snapshots.
- * \param varc Number of variable names.
- * \param vars Array of variable names.
- */
-void ast_channel_set_manager_vars(size_t varc, char **vars);
-
-/*!
- * \since 12
- * \brief Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
- *
- * The returned variable list is an AO2 object, so ao2_cleanup() to free it.
- *
- * \param chan Channel to get variables for.
- * \return List of channel variables.
- * \return \c NULL on error
- */
-struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper().
- *
- * The returned variable list is an AO2 object, so ao2_cleanup() to free it.
- *
- * \param chan Channel to get variables for
- * \return List of channel variables.
- * \return \c NULL on error
- */
-struct varshead *ast_channel_get_vars(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for a particular channel.
- *
- * If the given \a chan is \c NULL, ast_channel_topic_all() is returned.
- *
- * \param chan Channel, or \c NULL.
- *
- * \retval Topic for channel's events.
- * \retval ast_channel_topic_all() if \a chan is \c NULL.
- */
-struct stasis_topic *ast_channel_topic(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for a particular channel.
- *
- * \ref ast_channel_snapshot messages are replaced with \ref stasis_cache_update
- *
- * If the given \a chan is \c NULL, ast_channel_topic_all_cached() is returned.
- *
- * \param chan Channel, or \c NULL.
- *
- * \retval Topic for channel's events.
- * \retval ast_channel_topic_all() if \a chan is \c NULL.
- */
-struct stasis_topic *ast_channel_topic_cached(struct ast_channel *chan);
-
-/*!
- * \brief Get the bridge associated with a channel
- * \since 12.0.0
- *
- * \param chan The channel whose bridge we want
- *
- * \details
- * The bridge returned has its reference count incremented.  Use
- * ao2_cleanup() or ao2_ref() in order to decrement the
- * reference count when you are finished with the bridge.
- *
- * \note This function expects the channel to be locked prior to
- * being called and will not grab the channel lock.
- *
- * \retval NULL No bridge present on the channel
- * \retval non-NULL The bridge the channel is in
- */
-struct ast_bridge *ast_channel_get_bridge(const struct ast_channel *chan);
-
-/*!
- * \brief Determine if a channel is in a bridge
- * \since 12.0.0
- *
- * \param chan The channel to test
- *
- * \note This function expects the channel to be locked prior to
- * being called and will not grab the channel lock.
- *
- * \retval 0 The channel is not bridged
- * \retval non-zero The channel is bridged
- */
-int ast_channel_is_bridged(const struct ast_channel *chan);
-
-/*!
- * \brief Determine if a channel is leaving a bridge, but \em not hung up
- * \since 12.4.0
- *
- * \param chan The channel to test
- *
- * \note If a channel is hung up, it is implicitly leaving any bridge it
- * may be in. This function is used to test if a channel is leaving a bridge
- * but may survive the experience, if it has a place to go to (dialplan or
- * otherwise)
- *
- * \retval 0 The channel is not leaving the bridge or is hung up
- * \retval non-zero The channel is leaving the bridge
- */
-int ast_channel_is_leaving_bridge(struct ast_channel *chan);
-
-/*!
- * \brief Get the channel's bridge peer only if the bridge is two-party.
- * \since 12.0.0
- *
- * \param chan Channel desiring the bridge peer channel.
- *
- * \note The returned peer channel is the current peer in the
- * bridge when called.
- *
- * \note Absolutely _NO_ channel locks should be held when calling this function.
- *
- * \retval NULL Channel not in a bridge or the bridge is not two-party.
- * \retval non-NULL Reffed peer channel at time of calling.
- */
-struct ast_channel *ast_channel_bridge_peer(struct ast_channel *chan);
-
-/*!
- * \brief Get a reference to the channel's bridge pointer.
- * \since 12.0.0
- *
- * \param chan The channel whose bridge channel is desired
- *
- * \note This increases the reference count of the bridge_channel.
- * Use ao2_ref() or ao2_cleanup() to decrement the refcount when
- * you are finished with it.
- *
- * \note It is expected that the channel is locked prior to
- * placing this call.
- *
- * \retval NULL The channel has no bridge_channel
- * \retval non-NULL A reference to the bridge_channel
- */
-struct ast_bridge_channel *ast_channel_get_bridge_channel(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Gain control of a channel in the system
- *
- * The intention of this function is to take a channel that currently
- * is running in one thread and gain control of it in the current thread.
- * This can be used to redirect a channel to a different place in the dialplan,
- * for instance.
- *
- * \note This function is NOT intended to be used on bridged channels. If you
- * need to control a bridged channel, you can set a callback to be called
- * once the channel exits the bridge, and run your controlling logic in that
- * callback
- *
- * XXX Put name of callback-setting function in above paragraph once it is written
- *
- * \note When this function returns successfully, the yankee channel is in a state where
- * it cannot be used any further. Always use the returned channel instead.
- *
- * \note absolutely _NO_ channel locks should be held before calling this function.
- *
- * \param yankee The channel to gain control of
- * \retval NULL Could not gain control of the channel
- * \retval non-NULL The channel
- */
-struct ast_channel *ast_channel_yank(struct ast_channel *yankee);
-
-/*!
- * \since 12
- * \brief Move a channel from its current location to a new location
- *
- * The intention of this function is to have the destination channel
- * take on the identity of the source channel.
- *
- * \note This function is NOT intended to be used on bridged channels. If you
- * wish to move an unbridged channel into the place of a bridged channel, then
- * use ast_bridge_join() or ast_bridge_impart(). If you wish to move a bridged
- * channel into the place of another bridged channel, then use ast_bridge_move().
- *
- * \note When this function returns succesfully, the source channel is in a
- * state where its continued use is unreliable.
- *
- * \note absolutely _NO_ channel locks should be held before calling this function.
- *
- * \param dest The place to move the source channel
- * \param source The channel to move
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_channel_move(struct ast_channel *dest, struct ast_channel *source);
-
-/*!
- * \since 12
- * \brief Forward channel stasis messages to the given endpoint
- *
- * \param chan The channel to forward from
- * \param endpoint The endpoint to forward to
- *
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_channel_forward_endpoint(struct ast_channel *chan, struct ast_endpoint *endpoint);
-
-/*!
- * \brief Return the oldest linkedid between two channels.
- *
- * A channel linkedid is derived from the channel uniqueid which is formed like this:
- * [systemname-]ctime.seq
- *
- * The systemname, and the dash are optional, followed by the epoch time followed by an
- * integer sequence.  Note that this is not a decimal number, since 1.2 is less than 1.11
- * in uniqueid land.
- *
- * To compare two uniqueids, we parse out the integer values of the time and the sequence
- * numbers and compare them, with time trumping sequence.
- *
- * \param a The linkedid value of the first channel to compare
- * \param b The linkedid value of the second channel to compare
- *
- * \retval NULL on failure
- * \retval The oldest linkedid value
- * \since 12.0.0
-*/
-const char *ast_channel_oldest_linkedid(const char *a, const char *b);
-
-/*!
- * \brief Check if the channel has active audiohooks, active framehooks, or a monitor.
- * \since 12.0.0
- *
- * \param chan The channel to check.
- *
- * \retval non-zero if channel has active audiohooks, framehooks, or monitor.
- */
-int ast_channel_has_audio_frame_or_monitor(struct ast_channel *chan);
-
-/*!
- * \brief Check if the channel has any active hooks that require audio.
- * \since 12.3.0
- *
- * \param chan The channel to check.
- *
- * \retval non-zero if channel has active audiohooks, audio framehooks, or monitor.
- */
-int ast_channel_has_hook_requiring_audio(struct ast_channel *chan);
-
-/*!
- * \brief Removes the trailing identifiers from a channel name string
- * \since 12.0.0
- *
- * \param channel_name string that you wish to turn into a dial string.
- *                     This string will be edited in place.
- */
-void ast_channel_name_to_dial_string(char *channel_name);
-
-#define AST_MUTE_DIRECTION_READ (1 << 0)
-#define AST_MUTE_DIRECTION_WRITE (1 << 1)
-
-/*!
- * \brief Suppress passing of a frame type on a channel
- *
- * \note The channel should be locked before calling this function.
- *
- * \param chan The channel to suppress
- * \param direction The direction in which to suppress
- * \param frametype The type of frame (AST_FRAME_VOICE, etc) to suppress
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype);
-
-/*!
- * \brief Stop suppressing of a frame type on a channel
- *
- * \note The channel should be locked before calling this function.
- *
- * \param chan The channel to stop suppressing
- * \param direction The direction in which to stop suppressing
- * \param frametype The type of frame (AST_FRAME_VOICE, etc) to stop suppressing
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_channel_unsuppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype);
-
-/*!
- * \brief Simulate a DTMF end on a broken bridge channel.
- *
- * \param chan Channel sending DTMF that has not ended.
- * \param digit DTMF digit to stop.
- * \param start DTMF digit start time.
- * \param why Reason bridge broken.
- *
- * \return Nothing
- */
-void ast_channel_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why);
-
-struct ast_bridge_features;
-
-/*!
- * \brief Gets the channel-attached features a channel has access to upon being bridged.
- *
- * \note The channel must be locked when calling this function.
- *
- * \param chan Which channel to get features for
- *
- * \retval non-NULL The features currently set for this channel
- * \retval NULL if the features have not been set
- */
-struct ast_bridge_features *ast_channel_feature_hooks_get(struct ast_channel *chan);
-
-/*!
- * \brief Appends to the channel-attached features a channel has access to upon being bridged.
- *
- * \note The channel must be locked when calling this function.
- *
- * \param chan Which channel to set features for
- * \param features The feature set to append to the channel's features
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_channel_feature_hooks_append(struct ast_channel *chan, struct ast_bridge_features *features);
-
-/*!
- * \brief Sets the channel-attached features a channel has access to upon being bridged.
- *
- * \note The channel must be locked when calling this function.
- *
- * \param chan Which channel to set features for
- * \param features The feature set with which to replace the channel's features
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_channel_feature_hooks_replace(struct ast_channel *chan, struct ast_bridge_features *features);
-
 #endif /* _ASTERISK_CHANNEL_H */
diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h
index d1231b4..1b01fe0 100644
--- a/include/asterisk/channel_internal.h
+++ b/include/asterisk/channel_internal.h
@@ -18,10 +18,9 @@
  * \brief Internal channel functions for channel.c to use
  */
 
-#define ast_channel_internal_alloc(destructor, assignedid, requestor) __ast_channel_internal_alloc(destructor, assignedid, requestor, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function);
+#define ast_channel_internal_alloc(destructor) __ast_channel_internal_alloc(destructor, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *file, int line, const char *function);
 void ast_channel_internal_finalize(struct ast_channel *chan);
 int ast_channel_internal_is_finalized(struct ast_channel *chan);
 void ast_channel_internal_cleanup(struct ast_channel *chan);
-int ast_channel_internal_setup_topics(struct ast_channel *chan);
 
diff --git a/include/asterisk/channelstate.h b/include/asterisk/channelstate.h
index 08f9082..f5f7392 100644
--- a/include/asterisk/channelstate.h
+++ b/include/asterisk/channelstate.h
@@ -47,10 +47,7 @@ enum ast_channel_state {
 	AST_STATE_MUTE = (1 << 16),	/*!< Do not transmit voice data */
 };
 
-/*!
- * \brief Change the state of a channel
- * \pre chan is locked
- */
+/*! \brief Change the state of a channel */
 int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
 
 #endif /* __AST_CHANNELSTATE_H__ */
diff --git a/include/asterisk/chanvars.h b/include/asterisk/chanvars.h
index 3693e2a..7ebc64a 100644
--- a/include/asterisk/chanvars.h
+++ b/include/asterisk/chanvars.h
@@ -33,8 +33,6 @@ struct ast_var_t {
 
 AST_LIST_HEAD_NOLOCK(varshead, ast_var_t);
 
-struct varshead *ast_var_list_create(void);
-void ast_var_list_destroy(struct varshead *head);
 #ifdef MALLOC_DEBUG
 struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function);
 #define ast_var_assign(a,b)	_ast_var_assign(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
@@ -45,21 +43,5 @@ void ast_var_delete(struct ast_var_t *var);
 const char *ast_var_name(const struct ast_var_t *var);
 const char *ast_var_full_name(const struct ast_var_t *var);
 const char *ast_var_value(const struct ast_var_t *var);
-char *ast_var_find(const struct varshead *head, const char *name);
-struct varshead *ast_var_list_clone(struct varshead *head);
-
-#define AST_VAR_LIST_TRAVERSE(head, var) AST_LIST_TRAVERSE(head, var, entries)
-
-static inline void AST_VAR_LIST_INSERT_TAIL(struct varshead *head, struct ast_var_t *var) {
-	if (var) {
-		AST_LIST_INSERT_TAIL(head, var, entries);
-	}
-}
-
-static inline void AST_VAR_LIST_INSERT_HEAD(struct varshead *head, struct ast_var_t *var) {
-	if (var) {
-		AST_LIST_INSERT_HEAD(head, var, entries);
-	}
-}
 
 #endif /* _ASTERISK_CHANVARS_H */
diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h
index 458ebc8..21a0383 100644
--- a/include/asterisk/cli.h
+++ b/include/asterisk/cli.h
@@ -28,7 +28,6 @@ extern "C" {
 #endif
 
 #include "asterisk/linkedlists.h"
-#include "asterisk/strings.h"
 
 void ast_cli(int fd, const char *fmt, ...)
 	__attribute__((format(printf, 2, 3)));
@@ -58,17 +57,12 @@ void ast_cli(int fd, const char *fmt, ...)
  */
 #define ESS(x) ((x) == 1 ? "" : "s")
 
-/*!
- * \brief Return Yes or No depending on the argument.
- *
- * Note that this should probably still be used for CLI commands instead of
- * AST_YESNO(), in the off chance we someday want to translate the CLI.
- *
- * \param x Boolean value
- * \return "Yes" if x is true (non-zero)
- * \return "No" if x is false (zero)
+/*! \brief return Yes or No depending on the argument.
+ * This is used in many places in CLI command, having a function to generate
+ * this helps maintaining a consistent output (and possibly emitting the
+ * output in other languages, at some point).
  */
-#define AST_CLI_YESNO(x) AST_YESNO(x)
+#define AST_CLI_YESNO(x) (x) ? "Yes" : "No"
 
 /*! \brief return On or Off depending on the argument.
  * This is used in many places in CLI command, having a function to generate
diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h
deleted file mode 100644
index 28befec..0000000
--- a/include/asterisk/codec.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Codec API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _AST_CODEC_H_
-#define _AST_CODEC_H_
-
-/*! \brief Types of media */
-enum ast_media_type {
-	AST_MEDIA_TYPE_UNKNOWN = 0,
-	AST_MEDIA_TYPE_AUDIO,
-	AST_MEDIA_TYPE_VIDEO,
-	AST_MEDIA_TYPE_IMAGE,
-	AST_MEDIA_TYPE_TEXT,
-};
-
-struct ast_module;
-
-/*! \brief Represents a media codec within Asterisk. */
-struct ast_codec {
-	/*! \brief Internal unique identifier for this codec, set at registration time (starts at 1) */
-	unsigned int id;
-	/*! \brief Name for this codec */
-	const char *name;
-	/*! \brief Brief description */
-	const char *description;
-	/*! \brief Type of media this codec contains */
-	enum ast_media_type type;
-	/*! \brief Sample rate (number of samples carried in a second) */
-	unsigned int sample_rate;
-	/*! \brief Minimum length of media that can be carried (in milliseconds) in a frame */
-	unsigned int minimum_ms;
-	/*! \brief Maximum length of media that can be carried (in milliseconds) in a frame */
-	unsigned int maximum_ms;
-	/*! \brief Default length of media carried (in milliseconds) in a frame */
-	unsigned int default_ms;
-	/*! \brief Length in bytes of the data payload of a minimum_ms frame */
-	unsigned int minimum_bytes;
-	/*!
-	 * \brief Retrieve the number of samples in a frame
-	 *
-	 * \param frame The frame to examine
-	 *
-	 * \return the number of samples
-	 */
-	int (*samples_count)(struct ast_frame *frame);
-	/*!
-	 * \brief Retrieve the length of media from number of samples
-	 *
-	 * \param samples The number of samples
-	 *
-	 * \return The length of media in milliseconds
-	 */
-	int (*get_length)(unsigned int samples);
-	/*! \brief Whether the media can be smoothed or not */
-	unsigned int smooth;
-	/*! \brief The module that registered this codec */
-	struct ast_module *mod;
-};
-
-/*!
- * \brief Initialize codec support within the core.
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_codec_init(void);
-
-/*!
- * \brief Initialize built-in codecs within the core.
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_codec_builtin_init(void);
-
-/*!
- * \brief This function is used to register a codec with the Asterisk core. Registering
- * allows it to be passed through in frames and configured in channel drivers.
- *
- * \param codec to register
- * \param mod the module this codec is provided by
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod);
-
-/*!
- * \brief This function is used to register a codec with the Asterisk core. Registering
- * allows it to be passed through in frames and configured in channel drivers.
- *
- * \param codec to register
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_codec_register(codec) __ast_codec_register(codec, ast_module_info->self)
-
-/*!
- * \brief Retrieve a codec given a name, type, and sample rate
- *
- * \param name The name of the codec
- * \param type The type of the codec
- * \param sample_rate Optional sample rate, may not be applicable for some types
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note The returned codec is reference counted and ao2_ref or ao2_cleanup
- * must be used to release the reference.
- */
-struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate);
-
-/*!
- * \brief Retrieve a codec given the unique identifier
- *
- * \param id The unique identifier
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note Identifiers start at 1 so if iterating don't start at 0.
- *
- * \note The returned codec is reference counted and ao2_ref or ao2_cleanup
- * must be used to release the reference.
- */
-struct ast_codec *ast_codec_get_by_id(int id);
-
-/*!
- * \brief Retrieve the current maximum identifier for codec iteration
- *
- * \return Maximum codec identifier
- */
-int ast_codec_get_max(void);
-
-/*!
- * \brief Conversion function to take a media type and turn it into a string
- *
- * \param type The media type
- *
- * \retval string representation of the media type
- */
-const char *ast_codec_media_type2str(enum ast_media_type type);
-
-/*!
- * \brief Get the number of samples contained within a frame
- *
- * \param frame The frame itself
- *
- * \retval number of samples in the frame
- */
-unsigned int ast_codec_samples_count(struct ast_frame *frame);
-
-/*!
- * \brief Get the length of media (in milliseconds) given a number of samples
- *
- * \param codec The codec itself
- * \param samples The number of samples
- *
- * \retval length of media (in milliseconds)
- */
-unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples);
-
-#endif /* _AST_CODEC_H */
diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h
index c9c99c1..d5db6dd 100644
--- a/include/asterisk/compat.h
+++ b/include/asterisk/compat.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  * 
  * Copyright (C) 1999-2006, Digium, Inc.
  *
@@ -224,12 +224,4 @@ float roundf(float x);
 #endif
 #endif
 
-#ifndef INFINITY
-#define INFINITY (1.0/0.0)
-#endif
-
-#ifndef NAN
-#define NAN (0.0/0.0)
-#endif
-
 #endif
diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h
index 77b5de4..91112db 100644
--- a/include/asterisk/compiler.h
+++ b/include/asterisk/compiler.h
@@ -71,12 +71,6 @@
 #define attribute_warn_unused_result
 #endif
 
-#ifdef HAVE_ATTRIBUTE_may_alias
-#define attribute_may_alias __attribute__((may_alias))
-#else
-#define attribute_may_alias
-#endif
-
 /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */
 #define SENTINEL ((char *)NULL)
 
diff --git a/include/asterisk/config.h b/include/asterisk/config.h
index 7f0434d..711a4f4 100644
--- a/include/asterisk/config.h
+++ b/include/asterisk/config.h
@@ -98,12 +98,12 @@ struct ast_variable {
 };
 
 typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
-typedef struct ast_variable *realtime_var_get(const char *database, const char *table, const struct ast_variable *fields);
-typedef struct ast_config *realtime_multi_get(const char *database, const char *table, const struct ast_variable *fields);
-typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
-typedef int realtime_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
-typedef int realtime_store(const char *database, const char *table, const struct ast_variable *fields);
-typedef int realtime_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
+typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
+typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
+typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
+typedef int realtime_update2(const char *database, const char *table, va_list ap);
+typedef int realtime_store(const char *database, const char *table, va_list ap);
+typedef int realtime_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
 
 /*!
  * \brief Function pointer called to ensure database schema is properly configured for realtime use
@@ -193,7 +193,7 @@ struct ast_variable *ast_category_root(struct ast_config *config, char *cat);
  * \brief Sorts categories in a config in the order of a numerical value contained within them.
  *
  * \param config The config structure you wish to sort
- * \param comparator variable Which numerical value you wish to sort by
+ * \param variable Which numerical value you wish to sort by
  * \param descending If true, we sort highest to lowest instead of lowest to highest
  *
  * \details
@@ -203,30 +203,10 @@ void ast_config_sort_categories(struct ast_config *config, int descending,
 								int (*comparator)(struct ast_category *p, struct ast_category *q));
 
 /*!
- * \brief Browse categories with filters
+ * \brief Goes through categories
  *
  * \param config Which config structure you wish to "browse"
- * \param category_name An optional category name.
- * Pass NULL to not restrict by category name.
- * \param prev A pointer to the starting category structure.
- * Pass NULL to start at the beginning.
- * \param filter An optional comma-separated list of <name_regex>=<value_regex>
- * pairs.  Only categories with matching variables will be returned.
- * The special name 'TEMPLATES' can be used with the special values
- * 'include' or 'restrict' to include templates in the result or
- * restrict the result to only templates.
- *
- * \retval a category on success
- * \retval NULL on failure/no-more-categories
- */
-struct ast_category *ast_category_browse_filtered(struct ast_config *config,
-	const char *category_name, struct ast_category *prev, const char *filter);
-
-/*!
- * \brief Browse categories
- *
- * \param config Which config structure you wish to "browse"
- * \param prev_name A pointer to a previous category name.
+ * \param prev A pointer to a previous category.
  *
  * \details
  * This function is kind of non-intuitive in it's use.
@@ -236,25 +216,13 @@ struct ast_category *ast_category_browse_filtered(struct ast_config *config,
  * as the second pointer, and it will return a pointer to the category name
  * afterwards.
  *
- * \retval a category name on success
+ * \retval a category on success
  * \retval NULL on failure/no-more-categories
- *
- * \note ast_category_browse maintains internal state.  Therefore is not thread
- * safe, cannot be called recursively, and it is not safe to add or remove
- * categories while browsing.
- * ast_category_browse_filtered does not have these restrictions.
  */
-char *ast_category_browse(struct ast_config *config, const char *prev_name);
+char *ast_category_browse(struct ast_config *config, const char *prev);
 
 /*!
- * \brief Browse variables
- * \param config Which config structure you wish to "browse"
- * \param category_name Which category to "browse"
- * \param filter an optional comma-separated list of <name_regex>=<value_regex>
- * pairs.  Only categories with matching variables will be browsed.
- * The special name 'TEMPLATES' can be used with the special values
- * 'include' or 'restrict' to include templates in the result or
- * restrict the result to only templates.
+ * \brief Goes through variables
  *
  * \details
  * Somewhat similar in intent as the ast_category_browse.
@@ -263,10 +231,7 @@ char *ast_category_browse(struct ast_config *config, const char *prev_name);
  * \retval ast_variable list on success
  * \retval NULL on failure
  */
-struct ast_variable *ast_variable_browse_filtered(const struct ast_config *config,
-	const char *category_name, const char *filter);
-struct ast_variable *ast_variable_browse(const struct ast_config *config,
-	const char *category_name);
+struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
 
 /*!
  * \brief given a pointer to a category, return the root variable.
@@ -278,64 +243,25 @@ struct ast_variable *ast_variable_browse(const struct ast_config *config,
 struct ast_variable *ast_category_first(struct ast_category *cat);
 
 /*!
- * \brief Gets a variable by context and variable names
+ * \brief Gets a variable
  *
  * \param config which (opened) config to use
  * \param category category under which the variable lies
  * \param variable which variable you wish to get the data for
- * \param filter an optional comma-separated list of <name_regex>=<value_regex>
- * pairs.  Only categories with matching variables will be searched.
- * The special name 'TEMPLATES' can be used with the special values
- * 'include' or 'restrict' to include templates in the result or
- * restrict the result to only templates.
- *
- * \retval The variable value on success
- * \retval NULL if unable to find it.
- */
-const char *ast_variable_retrieve_filtered(struct ast_config *config,
-	const char *category, const char *variable, const char *filter);
-const char *ast_variable_retrieve(struct ast_config *config,
-	const char *category, const char *variable);
-
-/*!
- * \brief Gets a variable from a specific category structure
- *
- * \param category category structure under which the variable lies
- * \param variable which variable you wish to get the data for
- *
- * \details
- * Goes through a given category and searches for the given variable
- *
- * \retval The variable value on success
- * \retval NULL if unable to find it.
- */
-const char *ast_variable_find(const struct ast_category *category, const char *variable);
-
-/*!
- * \brief Gets a variable from a variable list
- *
- * \param list variable list to search
- * \param variable which variable you wish to get the data for
  *
  * \details
- * Goes through a given variable list and searches for the given variable
+ * Goes through a given config file in the given category and searches for the given variable
  *
  * \retval The variable value on success
  * \retval NULL if unable to find it.
  */
-const char *ast_variable_find_in_list(const struct ast_variable *list, const char *variable);
+const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
 
 /*!
  * \brief Retrieve a category if it exists
  *
  * \param config which config to use
  * \param category_name name of the category you're looking for
- * \param filter If a config contains more than 1 category with the same name,
- * you can specify a filter to narrow the search.  The filter is a comma-separated
- * list of <name_regex>=<value_regex> pairs.  Only a category with matching
- * variables will be returned. The special name 'TEMPLATES' can be used with the
- * special values 'include' or 'restrict' to include templates in the result or
- * restrict the result to only templates.
  *
  * \details
  * This will search through the categories within a given config file for a match.
@@ -343,57 +269,20 @@ const char *ast_variable_find_in_list(const struct ast_variable *list, const cha
  * \retval pointer to category if found
  * \retval NULL if not.
  */
-struct ast_category *ast_category_get(const struct ast_config *config,
-	const char *category_name, const char *filter);
-
-/*!
- * \brief Return the name of the category
- *
- * \param category category structure
- *
- * \retval pointer to category name if found
- * \retval NULL if not.
- */
-const char *ast_category_get_name(const struct ast_category *category);
-
-/*!
- * \brief Check if category is a template
- *
- * \param category category structure
- *
- * \retval 1 if a template.
- * \retval 0 if not.
- */
-int ast_category_is_template(const struct ast_category *category);
-
-/*!
- * \brief Return the template names this category inherits from
- *
- * \param category category structure
- *
- * \return an ast_str (which must be freed after use) with a comma
- * separated list of templates names or NULL if there were no templates.
- */
-struct ast_str *ast_category_get_templates(const struct ast_category *category);
+struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name);
 
 /*!
  * \brief Check for category duplicates
  *
  * \param config which config to use
  * \param category_name name of the category you're looking for
- * \param filter an optional comma-separated list of <name_regex>=<value_regex>
- * pairs.  Only categories with matching variables will be returned.
- * The special name 'TEMPLATES' can be used with the special values
- * 'include' or 'restrict' to include templates in the result or
- * restrict the result to only templates.
  *
  * \details
  * This will search through the categories within a given config file for a match.
  *
  * \return non-zero if found
  */
-int ast_category_exist(const struct ast_config *config, const char *category_name,
-	const char *filter);
+int ast_category_exist(const struct ast_config *config, const char *category_name);
 
 /*!
  * \brief Retrieve realtime configuration
@@ -416,9 +305,7 @@ int ast_category_exist(const struct ast_config *config, const char *category_nam
  * You should use the constant SENTINEL to terminate arguments, in
  * order to preserve cross-platform compatibility.
  */
-struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields);
 struct ast_variable *ast_load_realtime(const char *family, ...) attribute_sentinel;
-struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields);
 struct ast_variable *ast_load_realtime_all(const char *family, ...) attribute_sentinel;
 
 /*!
@@ -476,24 +363,6 @@ int ast_realtime_require_field(const char *family, ...) attribute_sentinel;
  * \brief Retrieve realtime configuration
  *
  * \param family which family/config to lookup
- * \param fields list of fields
- *
- * \details
- * This will use builtin configuration backends to look up a particular
- * entity in realtime and return a variable list of its parameters. Unlike
- * the ast_load_realtime, this function can return more than one entry and
- * is thus stored inside a traditional ast_config structure rather than
- * just returning a linked list of variables.
- *
- * \return An ast_config with one or more results
- * \retval NULL Error or no results returned
- */
-struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields);
-
-/*!
- * \brief Retrieve realtime configuration
- *
- * \param family which family/config to lookup
  *
  * \details
  * This will use builtin configuration backends to look up a particular
@@ -516,21 +385,6 @@ struct ast_config *ast_load_realtime_multientry(const char *family, ...) attribu
  * \param family which family/config to be updated
  * \param keyfield which field to use as the key
  * \param lookup which value to look for in the key field to match the entry.
- * \param fields fields to update
- *
- * \details
- * This function is used to update a parameter in realtime configuration space.
- *
- * \return Number of rows affected, or -1 on error.
- */
-int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields);
-
-/*!
- * \brief Update realtime configuration
- *
- * \param family which family/config to be updated
- * \param keyfield which field to use as the key
- * \param lookup which value to look for in the key field to match the entry.
  *
  * \details
  * This function is used to update a parameter in realtime configuration space.
@@ -546,23 +400,6 @@ int ast_update_realtime(const char *family, const char *keyfield, const char *lo
  * \brief Update realtime configuration
  *
  * \param family which family/config to be updated
- * \param lookup_fields fields used to look up entries
- * \param update_fields fields to update
- *
- * \details
- * This function is used to update a parameter in realtime configuration space.
- * It includes the ability to lookup a row based upon multiple key criteria.
- * As a result, this function includes two sentinel values, one to terminate
- * lookup values and the other to terminate the listing of fields to update.
- *
- * \return Number of rows affected, or -1 on error.
- */
-int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
-
-/*!
- * \brief Update realtime configuration
- *
- * \param family which family/config to be updated
  *
  * \details
  * This function is used to update a parameter in realtime configuration space.
@@ -581,24 +418,6 @@ int ast_update2_realtime(const char *family, ...) attribute_sentinel;
  * \brief Create realtime configuration
  *
  * \param family which family/config to be created
- * \param fields fields themselves
- *
- * \details
- * This function is used to create a parameter in realtime configuration space.
- *
- * \return Number of rows affected, or -1 on error.
- *
- * \note
- * On the MySQL engine only, for reasons of backwards compatibility, the return
- * value is the insert ID.  This value is nonportable and may be changed in a
- * future version to match the other engines.
- */
-int ast_store_realtime_fields(const char *family, const struct ast_variable *fields);
-
-/*!
- * \brief Create realtime configuration
- *
- * \param family which family/config to be created
  *
  * \details
  * This function is used to create a parameter in realtime configuration space.
@@ -621,22 +440,6 @@ int ast_store_realtime(const char *family, ...) attribute_sentinel;
  * \param family which family/config to be destroyed
  * \param keyfield which field to use as the key
  * \param lookup which value to look for in the key field to match the entry.
- * \param fields fields themselves
- *
- * \details
- * This function is used to destroy an entry in realtime configuration space.
- * Additional params are used as keys.
- *
- * \return Number of rows affected, or -1 on error.
- */
-int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields);
-
-/*!
- * \brief Destroy realtime configuration
- *
- * \param family which family/config to be destroyed
- * \param keyfield which field to use as the key
- * \param lookup which value to look for in the key field to match the entry.
  *
  * \details
  * This function is used to destroy an entry in realtime configuration space.
@@ -710,19 +513,6 @@ int ast_config_engine_deregister(struct ast_config_engine *del);
  */
 int ast_realtime_is_mapping_defined(const char *family);
 
-#ifdef TEST_FRAMEWORK
-/*!
- * \brief Add an explicit mapping for a family
- *
- * \param name Family name
- * \param driver Driver to use
- * \param database Database to access
- * \param table Table to use
- * \param priority Priority of this mapping
- */
-int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority);
-#endif
-
 /*!
  * \brief Exposed initialization method for core process
  *
@@ -772,23 +562,9 @@ void ast_config_set_current_category(struct ast_config *cfg, const struct ast_ca
  */
 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var);
 
-/*!
- * \brief Create a category
- *
- * \param name name of new category
- * \param in_file filename which contained the new config
- * \param lineno line number
- */
+/*! \brief Create a category structure */
 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
-
-/*!
- * \brief Create a category making it a template
- *
- * \param name name of new template
- * \param in_file filename which contained the new config
- * \param lineno line number
- */
-struct ast_category *ast_category_new_template(const char *name, const char *in_file, int lineno);
+void ast_category_append(struct ast_config *config, struct ast_category *cat);
 
 /*!
  * \brief Inserts new category
@@ -802,52 +578,17 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_
  * matching the match parameter.
  *
  * \retval 0 if succeeded
- * \retval -1 if the specified match category wasn't found
+ * \retval -1 if NULL parameters or match category was not found
  */
 int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match);
+int ast_category_delete(struct ast_config *cfg, const char *category);
 
 /*!
- * \brief Delete a category
- *
- * \param config which config to use
- * \param category category to delete
- *
- * \return the category after the deleted one which could be NULL.
- *
- * \note It is not safe to call ast_category_delete while browsing with
- * ast_category_browse.  It is safe with ast_category_browse_filtered.
+ * \brief Removes and destroys all variables within a category
+ * \retval 0 if the category was found and emptied
+ * \retval -1 if the category was not found
  */
-struct ast_category *ast_category_delete(struct ast_config *cfg, struct ast_category *category);
-
-/*!
- * \brief Appends a category to a config
- *
- * \param config which config to use
- * \param cat category to insert
- */
-void ast_category_append(struct ast_config *config, struct ast_category *cat);
-
-/*!
- * \brief Applies base (template) to category.
- *
- * \param existing existing category
- * \param base base category
- *
- * \details
- * This function is used to apply a base (template) to an existing category
- */
-void ast_category_inherit(struct ast_category *existing, const struct ast_category *base);
-
-/*!
- * \brief Removes and destroys all variables in a category
- *
- * \param category category to empty
- *
- * \retval 0 if succeeded
- * \retval -1 if categopry is NULL
- */
-int ast_category_empty(struct ast_category *category);
-
+int ast_category_empty(struct ast_config *cfg, const char *category);
 void ast_category_destroy(struct ast_category *cat);
 struct ast_variable *ast_category_detach_variables(struct ast_category *cat);
 void ast_category_rename(struct ast_category *cat, const char *name);
@@ -866,34 +607,6 @@ void ast_variable_insert(struct ast_category *category, struct ast_variable *var
 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line);
 
 /*!
- * \brief Performs an in-place sort on the variable list by ascending name
- *
- * \param head The variable list head
- *
- * \return The new list head
- */
-struct ast_variable *ast_variable_list_sort(struct ast_variable *head);
-
-/*!
- * \brief Appends a variable list to the end of another list
- *
- * \param head A pointer to an ast_variable * of the existing variable list head. May NOT be NULL
- * but the content may be to initialize a new list.  If so, upon return, this parameter will be updated
- * with a pointer to the new list head.
- * \param search_hint The place in the current list to start searching for the end of the list.
- * Might help performance on longer lists.  If NULL, it defaults to head.
- * \param new_var The head of the new variable list to be appended
- *
- * \return The tail of the resulting list.
- *
- * \note If the existing *head is NULL, it will be updated to new_var.  This allows you to call
- * ast_variable_list_append in a loop or callback without initializing the list first.
- */
-struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint,
-	struct ast_variable *new_var);
-#define ast_variable_list_append(head, new_var) ast_variable_list_append_hint(head, NULL, new_var)
-
-/*!
  * \brief Update variable value within a config
  *
  * \param category Category element within the config
@@ -1041,9 +754,9 @@ enum ast_parse_flags {
  *
  * \param arg the string to parse. It is not modified.
  * \param flags combination of ast_parse_flags to specify the
- * 	return type and additional checks.
+ * return type and additional checks.
  * \param result pointer to the result. NULL is valid here, and can
- * 	be used to perform only the validity checks.
+ * be used to perform only the validity checks.
  * \param ... extra arguments are required according to flags.
  *
  * \retval 0 in case of success, != 0 otherwise.
@@ -1141,7 +854,7 @@ int ast_rq_is_int(require_type type),
  * \param chunk Data to be decoded
  * \return The decoded data, in the original buffer
  * \since 1.8
- * \warning This function modifies the original buffer
+ * \warn This function modifies the original buffer
  */
 char *ast_realtime_decode_chunk(char *chunk);
 
diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h
index 30c0421..6de8d28 100644
--- a/include/asterisk/config_options.h
+++ b/include/asterisk/config_options.h
@@ -109,14 +109,12 @@ typedef int (*aco_matchvalue_func)(const char *text);
 struct aco_type {
 	/* common stuff */
 	enum aco_type_t type;   /*!< Whether this is a global or item type */
-	const char *name;       /*!< The name of this type (must match XML documentation) */
 	const char *category;   /*!< A regular expression for matching categories to be allowed or denied */
 	const char *matchfield; /*!< An option name to match for this type (i.e. a 'type'-like column) */
 	const char *matchvalue; /*!< The value of the option to require for matching (i.e. 'peer' for type= in sip.conf) */
 	aco_matchvalue_func matchfunc;       /*!< A function for determing whether the option value matches (i.e. hassip= requires ast_true()) */
 	enum aco_category_op category_match; /*!< Whether the following category regex is a whitelist or blacklist */
 	size_t item_offset;                  /*!< The offset in the config snapshot for the global config or item config container */
-	unsigned int hidden;  /*!< Type is for internal purposes only and it and all options should not be visible to users */
 
 	/* non-global callbacks */
 	aco_type_item_alloc item_alloc;         /*!< An allocation function for item associated with this type */
@@ -147,16 +145,14 @@ typedef void *(*aco_snapshot_alloc)(void);
 
 /*! \brief The representation of a single configuration file to be processed */
 struct aco_file {
-	const char *filename;       /*!< The filename to be processed */
-	const char *alias;          /*!< An alias filename to be tried if 'filename' cannot be found */
-	const char **preload;       /*!< A null-terminated ordered array of categories to be loaded first */
-	const char *skip_category;  /*!< A regular expression of categories to skip in the file. Use when a file is processed by multiple modules */
-	struct aco_type *types[];   /*!< The list of types for this config. Required. Use a sentinel! */
+	const char *filename; /*!< \brief The filename to be processed */
+	const char *alias;    /*!< \brief An alias filename to be tried if 'filename' cannot be found */
+	const char **preload; /*!< \brief A null-terminated oredered array of categories to be loaded first */
+	struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */
 };
 
 struct aco_info {
 	const char *module; /*!< The name of the module whose config is being processed */
-	int hidden:1;                /*!< If enabled, this config item is hidden from users */
 	aco_pre_apply_config pre_apply_config; /*!< A callback called after processing, but before changes are applied */
 	aco_post_apply_config post_apply_config;/*!< A callback called after changes are applied */
 	aco_snapshot_alloc snapshot_alloc;     /*!< Allocate an object to hold all global configs and item containers */
@@ -180,6 +176,7 @@ void *aco_pending_config(struct aco_info *info);
 /*! \def CONFIG_INFO_STANDARD
  * \brief Declare an aco_info struct with default module and preload values
  * \param name The name of the struct
+ * \param fn The filename of the config
  * \param arr The global object array for holding the user-defined config object
  * \param alloc The allocater for the user-defined config object
  *
@@ -206,23 +203,6 @@ static struct aco_info name = { \
 	__VA_ARGS__ \
 };
 
-#define CONFIG_INFO_CORE(mod, name, arr, alloc, ...) \
-static struct aco_info name = { \
-	.module = mod, \
-	.global_obj = &arr, \
-	.snapshot_alloc = alloc, \
-	__VA_ARGS__ \
-};
-
-#define CONFIG_INFO_TEST(name, arr, alloc, ...) \
-static struct aco_info name = { \
-	.module = AST_MODULE, \
-	.global_obj = &arr, \
-	.snapshot_alloc = alloc, \
-	.hidden = 1, \
-	__VA_ARGS__ \
-};
-
 /*! \brief Initialize an aco_info structure
  * \note aco_info_destroy must be called if this succeeds
  * \param info The address of an aco_info struct to initialize
@@ -276,7 +256,7 @@ enum aco_option_type {
 	 * struct test_item {
 	 *     int enabled;
 	 * };
-	 * aco_option_register(&cfg_info, "enabled", ACO_EXACT, my_types, "no", OPT_BOOL_T, 1, FLDSET(struct test_item, enabled));
+		aco_option_register(&cfg_info, "enabled", ACO_EXACT, my_types, "no", OPT_BOOL_T, 1, FLDSET(struct test_item, enabled));
 	 * {endcode}
 	 */
 	OPT_BOOL_T,
@@ -295,15 +275,13 @@ enum aco_option_type {
 	 * struct test_item {
 	 *     unsigned int flags;
 	 * };
-	 * aco_option_register(&cfg_info, "quiet", ACO_EXACT, my_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), MY_TYPE_ISQUIET);
+		aco_option_register(&cfg_info, "quiet", ACO_EXACT, my_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), MY_TYPE_ISQUIET);
 	 * {endcode}
 	 */
+
 	OPT_BOOLFLAG_T,
 
-	/*! \brief Type for default option handler for character array strings
-	 * \note aco_option_register flags:
-	 *   non-zero : String cannot be empty.
-	 *   0        : String can be empty.
+	/*! \brief Type for default option handler for character arrays
 	 * \note aco_option_register varargs:
 	 *   CHARFLDSET macro with a field of type char[]
 	 *
@@ -312,25 +290,26 @@ enum aco_option_type {
 	 * struct test_item {
 	 *     char description[128];
 	 * };
-	 * aco_option_register(&cfg_info, "description", ACO_EXACT, my_types, "none", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct test_item, description));
+	 * aco_option_register(&cfg_info, "description", ACO_EXACT, my_types, "none", OPT_CHAR_ARRAY_T, CHARFLDSET(struct test_item, description));
 	 * {endcode}
 	 */
 	OPT_CHAR_ARRAY_T,
 
-	/*! \brief Type for default option handler for format capabilities
+	/*! \brief Type for default option handler for codec preferences/capabilities
 	 * \note aco_option_register flags:
 	 *   non-zero : This is an "allow" style option
 	 *   0        : This is a "disallow" style option
 	 * aco_option_register varargs:
-	 *   FLDSET macro with field representing a struct ast_format_cap *
+	 *   FLDSET macro with fields representing a struct ast_codec_pref and a struct ast_format_cap *
 	 *
 	 * Example:
 	 * {code}
 	 * struct test_item {
+	 *     struct ast_codec_pref pref;
 	 *     struct ast_format cap *cap;
 	 * };
-	 * aco_option_register(&cfg_info, "allow", ACO_EXACT, my_types, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct test_item, cap));
-	 * aco_option_register(&cfg_info, "disallow", ACO_EXACT, my_types, "all", OPT_CODEC_T, 0, FLDSET(struct test_item, cap));
+	 * aco_option_register(&cfg_info, "allow", ACO_EXACT, my_types, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct test_item, pref, cap));
+	 * aco_option_register(&cfg_info, "disallow", ACO_EXACT, my_types, "all", OPT_CODEC_T, 0, FLDSET(struct test_item, pref, cap));
 	 * {endcode}
 	 */
 	OPT_CODEC_T,
@@ -350,7 +329,7 @@ enum aco_option_type {
 	 *     double dub;
 	 * };
 	 * {code}
-	 * aco_option_register(&cfg_info, "doubleopt", ACO_EXACT, my_types, "3", OPT_DOUBLE_T, 0, FLDSET(struct test_item, dub));
+	 * aco_option_register(&cfg_info, "doubleopt", ACO_EXACT, my_types, "3", OPT_DOUBLE_T, FLDSET(struct test_item, dub));
 	 * {endcode}
 	 */
 	OPT_DOUBLE_T,
@@ -405,8 +384,7 @@ enum aco_option_type {
 
 	/*! \brief Type for default option handler for stringfields
 	 * \note aco_option_register flags:
-	 *   non-zero : String cannot be empty.
-	 *   0        : String can be empty.
+	 *   none
 	 * aco_option_register varargs:
 	 *   STRFLDSET macro with the field being the field created by AST_STRING_FIELD
 	 *
@@ -471,7 +449,7 @@ enum aco_process_status {
 /*! \brief Process a config info via the options registered with an aco_info
  *
  * \param info The config_options_info to be used for handling the config
- * \param reload Non-zero if this is for a reload.
+ * \param reload Whether or not this is a reload
  *
  * \retval ACO_PROCESS_OK Success
  * \retval ACO_PROCESS_ERROR Failure
@@ -484,6 +462,7 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload);
  * \param info The aco_info to be used for handling the config
  * \param file The file attached to aco_info that the config represents
  * \param cfg A pointer to a loaded ast_config to parse
+ * \param reload Whether or not this is a reload
  *
  * \retval ACO_PROCESS_OK Success
  * \retval ACO_PROCESS_ERROR Failure
@@ -517,7 +496,7 @@ int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable
 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj);
 
 /*! \brief Set all default options of \a obj
- * \param type The aco_type with the options
+ * \param info The aco_type with the options
  * \param category The configuration category from which \a obj is being configured
  * \param obj The object being configured
  *
@@ -532,13 +511,11 @@ int aco_set_defaults(struct aco_type *type, const char *category, void *obj);
  *
  * \param info The aco_info holding this module's config information
  * \param name The name of the option
- * \param match_type
  * \param types An array of valid option types for matching categories to the correct struct type
  * \param default_val The default value of the option in the same format as defined in a config file
  * \param type The option type (only for default handlers)
  * \param handler The handler function for the option (only for non-default types)
- * \param flags a type specific flags, stored in the option and available to the handler
- * \param no_doc if non-zero, this option should not have documentation
+ * \param flags \a type specific flags, stored in the option and available to the handler
  * \param argc The number for variadic arguments
  * \param ... field offsets to store for default handlers
  *
@@ -546,28 +523,25 @@ int aco_set_defaults(struct aco_type *type, const char *category, void *obj);
  * \retval -1 failure
  */
 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype match_type, struct aco_type **types,
-	const char *default_val, enum aco_option_type type, aco_option_handler handler, unsigned int flags, unsigned int no_doc, size_t argc, ...);
+	const char *default_val, enum aco_option_type type, aco_option_handler handler, unsigned int flags, size_t argc, ...);
 
 /*! \brief Register a config option
  * \param info A pointer to the aco_info struct
  * \param name The name of the option
- * \param matchtype
  * \param types An array of valid option types for matching categories to the correct struct type
  * \param default_val The default value of the option in the same format as defined in a config file
  * \param opt_type The option type for default option type handling
- * \param flags a type specific flags, stored in the option and available to the handler
- * \param ...
+ * \param flags \a type specific flags, stored in the option and available to the handler
  *
  * \retval 0 Success
  * \retval -1 Failure
  */
 #define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags, ...) \
-	__aco_option_register(info, name, matchtype, types, default_val, opt_type, NULL, flags, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
+	__aco_option_register(info, name, matchtype, types, default_val, opt_type, NULL, flags, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
 
 /*! \brief Register a config option
  * \param info A pointer to the aco_info struct
  * \param name The name of the option
- * \param matchtype
  * \param types An array of valid option types for matching categories to the correct struct type
  * \param default_val The default value of the option in the same format as defined in a config file
  * \param handler The handler callback for the option
@@ -577,25 +551,7 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc
  * \retval -1 Failure
  */
 #define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags) \
-	__aco_option_register(info, name, matchtype, types, default_val, OPT_CUSTOM_T, handler, flags, 0, 0);
-
-/*! \brief Register a config option with no expected documentation
- * \param info A pointer to the aco_info struct
- * \param name The name of the option
- * \param matchtype
- * \param types An array of valid option types for matching categories to the correct struct type
- * \param default_val The default value of the option in the same format as defined in a config file
- * \param handler The handler callback for the option
- * \param flags \a type specific flags, stored in the option and available to the handler
- *
- * \note This is used primarily with custom options that only have internal purposes
- * and that should be ignored by the user.
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-#define aco_option_register_custom_nodoc(info, name, matchtype, types, default_val, handler, flags) \
-	__aco_option_register(info, name, matchtype, types, default_val, OPT_CUSTOM_T, handler, flags, 1, 0);
+	__aco_option_register(info, name, matchtype, types, default_val, OPT_CUSTOM_T, handler, flags, 0);
 
 /*! \brief Register a deprecated (and aliased) config option
  * \param info A pointer to the aco_info struct
@@ -608,41 +564,20 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc
  */
 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to);
 
-/*!
- * \brief Read the flags of a config option - useful when using a custom callback for a config option
- * \since 12
- *
- * \param option Pointer to the aco_option struct
- *
- * \retval value of the flags on the config option
- */
-unsigned int aco_option_get_flags(const struct aco_option *option);
-
-/*!
- * \brief Get the offset position for an argument within a config option
- *
- * \param option Pointer to the aco_option struct
- * \param arg Argument number
- *
- * \retval position of the argument
- */
-intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position);
-
 /*! \note  Everything below this point is to handle converting varargs
  * containing field names, to varargs containing a count of args, followed
  * by the offset of each of the field names in the struct type that is
  * passed in. It is currently limited to 8 arguments, but 8 variadic
  * arguments, like 640K, should be good enough for anyone. If not, it is
  * easy to add more.
- *
- */
+ * */
 
-/*!
+/*! \def ARGMAP(func, func_arg, x, ...)
  * \brief Map \a func(\a func_arg, field) across all fields including \a x
  * \param func The function (almost certainly offsetof) to map across the fields
  * \param func_arg The first argument (almost certainly a type (e.g. "struct mystruct")
  * \param x The first field
- * \param ... varargs The rest of the fields
+ * \param varargs The rest of the fields
  *
  * Example usage:
  * \code
@@ -653,19 +588,17 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * };
  * ARGMAP(offsetof, struct foo, a, c)
  * \endcode
- *
  * produces the string:
- *
  * \code
  * 2, offsetof(struct foo, a), offsetof(struct foo, b)
- * \endcode
+ * \encode
  * which can be passed as the varargs to some other function
  *
  * The macro isn't limited to offsetof, but that is the only purpose for
  * which it has been tested.
  *
  * As an example of how the processing works:
- * \verbatim
+ *
  * ARGMAP(offsetof, struct foo, a, b, c) ->
  * ARGMAP_(3, offsetof, struct foo, a, b, c) ->
  * ARGMAP_3(offsetof, struct foo, 3, a, b, c) ->
@@ -673,15 +606,12 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * ARGMAP_1(offsetof, struct foo, ARGIFY(3, offsetof(struct foo, a), offsetof(struct foo, b)), c) ->
  * ARGIFY(3, offsetof(struct foo, a), offsetof(struct foo, b), offsetof(struct foo, c)) ->
  * 3, offsetof(struct foo, a), offsetof(struct foo, b), offsetof(struct foo, c)
- * \endverbatim
- *
  */
 #define ARGMAP(func, func_arg, x, ...) ARGMAP_(VA_NARGS(x, ##__VA_ARGS__), func, func_arg, x, __VA_ARGS__)
 
 /*! \note This is sneaky. On the very first argument, we set "in" to N, the number of arguments, so
  * that the accumulation both works properly for the first argument (since "in" can't be empty) and
- * we get the number of arguments in our varargs as a bonus
- */
+ * we get the number of arguments in our varargs as a bonus */
 #define ARGMAP_(N, func, func_arg, x, ...) PASTE(ARGMAP_, N)(func, func_arg, N, x, __VA_ARGS__)
 
 /*! \def PASTE(arg1, arg2)
@@ -699,7 +629,7 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * \param func_arg The first argument to func (most likely a type e.g. "struct my_struct")
  * \param in The accumulated function-mapped field names so far
  * \param x The next field name
- * \param ... varargs The rest of the field names
+ * \param varargs The rest of the field names
  */
 #define ARGMAP_1(func, func_arg, in, x, ...) ARGIFY(in, func(func_arg, x))
 #define ARGMAP_2(func, func_arg, in, x, ...)\
@@ -721,19 +651,18 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * \brief Results in the number of arguments passed to it
  * \note Currently only up to 8, but expanding is easy. This macro basically counts
  * commas + 1. To visualize:
- * \verbatim
+ *
  * VA_NARGS(one, two, three) ->                    v
  * VA_NARGS1(one, two, three,  8,  7,  6,  5,  4,  3,  2,  1,  0) ->
  * VA_NARGS1( _1,  _2,    _3, _4, _5, _6, _7, _8,  N, ...       ) N -> 3
- * 
+ *
  * Note that VA_NARGS *does not* work when there are no arguments passed. Pasting an empty
  * __VA_ARGS__ with a comma like ", ##__VA_ARGS__" will delete the leading comma, but it
  * does not work when __VA_ARGS__ is the first argument. Instead, 1 is returned instead of 0:
- * 
+ *
  * VA_NARGS() ->                              v
  * VA_NARGS1(  ,  8,  7,  6,  5,  4,  3,  2,  1,  0) ->
  * VA_NARGS1(_1, _2, _3, _4, _5, _6, _7, _8,  N) -> 1
- * \endverbatim
  */
 #define VA_NARGS(...) VA_NARGS1(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 #define VA_NARGS1(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
@@ -741,7 +670,7 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
 /*! \def FLDSET(type, ...)
  * \brief Convert a struct and list of fields to an argument list of field offsets
  * \param type The type with the fields (e.g. "struct my_struct")
- * \param ... varags The fields in the struct whose offsets are needed as arguments
+ * \param varags The fields in the struct whose offsets are needed as arguments
  *
  * For example:
  * \code
@@ -763,7 +692,7 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * default stringfield option handler, so registering options that point to stringfields requires
  * this macro to be called instead of the FLDSET macro.
  * \param type The type with the fields (e.g. "struct my_struct")
- * \param ... varargs The fields in the struct whose offsets are needed as arguments
+ * \param varargs The fields in the struct whose offsets are needed as arguments
  */
 #define STRFLDSET(type, ...) FLDSET(type, __VA_ARGS__, __field_mgr_pool, __field_mgr)
 
@@ -781,10 +710,9 @@ intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int p
  * FLDSET. This is because a call to FLDSET may be followed by additional arguments in
  * aco_register_option, so the true number of arguments will possibly be different than what
  * ARGMAP returns.
- * \param ... varags A list of arguments
- * \verbatim
+ * \params varags A list of arguments
+ *
  * POPPED(a, b, c) -> b, c
- * \endverbatim
  */
 #define POPPED(...) POPPED1(__VA_ARGS__)
 #define POPPED1(x, ...) __VA_ARGS__
diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h
deleted file mode 100644
index 491112d..0000000
--- a/include/asterisk/core_local.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Local proxy channel special access.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_CORE_LOCAL_H
-#define _ASTERISK_CORE_LOCAL_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/* Forward declare some struct names */
-struct ast_channel;
-struct ast_bridge;
-struct ast_bridge_features;
-struct stasis_message_type;
-
-/* ------------------------------------------------------------------- */
-
-/*!
- * \brief Get the other local channel in the pair.
- * \since 12.0.0
- *
- * \param ast Local channel to get peer.
- *
- * \note On entry, ast must be locked.
- *
- * \retval peer reffed on success.
- * \retval NULL if no peer or error.
- */
-struct ast_channel *ast_local_get_peer(struct ast_channel *ast);
-
-/*!
- * \brief Setup the outgoing local channel to join a bridge on ast_call().
- * \since 12.0.0
- *
- * \param ast Either channel of a local channel pair.
- * \param bridge Bridge to join.
- * \param swap Channel to swap with when joining.
- * \param features Bridge features structure.
- *
- * \note The features parameter must be NULL or obtained by
- * ast_bridge_features_new().  You must not dereference features
- * after calling even if the call fails.
- *
- * \note Intended to be called after ast_request() and before
- * ast_call() on a local channel.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features);
-
-/*!
- * \brief Setup the outgoing local channel to masquerade into a channel on ast_call().
- * \since 12.0.0
- *
- * \param ast Either channel of a local channel pair.
- * \param masq Channel to masquerade into.
- *
- * \note Intended to be called after ast_request() and before
- * ast_call() on a local channel.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq);
-
-/* ------------------------------------------------------------------- */
-
-/*!
- * \brief Message type for when two local channel halves are bridged together
- * \since 12.0.0
- *
- * \note Payloads for the \ref ast_local_bridge_type are a \ref ast_multi_channel_blob.
- * Roles for the channels in the \ref ast_multi_channel_blob are "1" and "2", reflecting
- * the two halves. Unlike most other bridges, the 'bridge' between two local channels is
- * not part of the bridge framework; as such, the message simply references the two local
- * channel halves that are now bridged.
- *
- * \retval A \ref stasis message type
- */
-struct stasis_message_type *ast_local_bridge_type(void);
-
-/*!
- * \brief Message type for when a local channel optimization begins
- * \since 12.0.0
- *
- * \note Payloads for the \ref ast_local_optimization_begin_type are a
- * \ref ast_multi_channel_blob. Roles for the channels in the \ref ast_multi_channel_blob
- * are "1" and "2", reflecting the two halves.
- *
- * \retval A \ref stasis message type
- */
-struct stasis_message_type *ast_local_optimization_begin_type(void);
-
-/*!
- * \brief Message type for when a local channel optimization completes
- * \since 12.0.0
- *
- * \note Payloads for the \ref ast_local_optimization_end_type are a
- * \ref ast_multi_channel_blob. Roles for the channels in the \ref ast_multi_channel_blob
- * are "1" and "2", reflecting the two halves.
- *
- * \retval A \ref stasis message type
- */
-struct stasis_message_type *ast_local_optimization_end_type(void);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_CORE_LOCAL_H */
diff --git a/include/asterisk/core_unreal.h b/include/asterisk/core_unreal.h
deleted file mode 100644
index e118c74..0000000
--- a/include/asterisk/core_unreal.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Unreal channel derivative framework.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_CORE_UNREAL_H
-#define _ASTERISK_CORE_UNREAL_H
-
-#include "asterisk/astobj2.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/abstract_jb.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/* Forward declare some struct names */
-struct ast_format_cap;
-struct ast_callid;
-
-/* ------------------------------------------------------------------- */
-
-struct ast_unreal_pvt;
-
-enum ast_unreal_channel_indicator {
-	AST_UNREAL_OWNER,
-	AST_UNREAL_CHAN,
-};
-
-/*!
- * \brief Callbacks that can be provided by concrete implementations of the unreal
- * channel driver that will be called when events occur in the unreal layer
- */
-struct ast_unreal_pvt_callbacks {
-	/*!
-	 * \brief Called when an optimization attempt has started
-	 * \note p is locked when this callback is called
-	 * \param p The \ref ast_unreal_pvt object
-	 * \param source The channel that is optimizing into an unreal_pvt channel's bridge.
-	 * If NULL, the optimization is being accomplished via a bridge merge.
-	 * \param dest Indicator of which channel's bridge in the unreal_pvt will survive the
-	 * optimization
-	 * \param id Unique identifier for this optimization operation.
-	 */
-	void (* const optimization_started)(struct ast_unreal_pvt *p, struct ast_channel *source,
-			enum ast_unreal_channel_indicator dest, unsigned int id);
-
-	/*!
-	 * \brief Called when an optimization attempt completed successfully
-	 * \note p is locked when this callback is called
-	 * \param p The \ref ast_unreal_pvt object
-	 * \param success Non-zero if the optimization succeeded, zero if the optimization
-	 * met with fatal and permanent error
-	 * \param id Unique identifier for this optimization. Same as the one from the optimization_started
-	 * call
-	 */
-	void (* const optimization_finished)(struct ast_unreal_pvt *p, int success, unsigned int id);
-};
-
-/*!
- * \brief The base pvt structure for local channel derivatives.
- *
- * The unreal pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
- *
- * ast_chan owner -> ast_unreal_pvt -> ast_chan chan
- */
-struct ast_unreal_pvt {
-	struct ast_unreal_pvt_callbacks *callbacks; /*!< Event callbacks */
-	struct ast_channel *owner;                  /*!< Master Channel - ;1 side */
-	struct ast_channel *chan;                   /*!< Outbound channel - ;2 side */
-	struct ast_format_cap *reqcap;              /*!< Requested format capabilities */
-	struct ast_jb_conf jb_conf;                 /*!< jitterbuffer configuration */
-	unsigned int flags;                         /*!< Private option flags */
-	/*! Base name of the unreal channels.  exten at context or other name. */
-	char name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
-};
-
-#define AST_UNREAL_IS_OUTBOUND(a, b) ((a) == (b)->chan ? 1 : 0)
-
-#define AST_UNREAL_CARETAKER_THREAD (1 << 0) /*!< The ;2 side launched a PBX, was pushed into a bridge, or was masqueraded into an application. */
-#define AST_UNREAL_NO_OPTIMIZATION  (1 << 1) /*!< Do not optimize out the unreal channels */
-#define AST_UNREAL_MOH_INTERCEPT    (1 << 2) /*!< Intercept and act on hold/unhold control frames */
-#define AST_UNREAL_OPTIMIZE_BEGUN   (1 << 3) /*!< Indicates that an optimization attempt has been started */
-
-/*!
- * \brief Send an unreal pvt in with no locks held and get all locks
- *
- * \note NO locks should be held prior to calling this function
- * \note The pvt must have a ref held before calling this function
- * \note if outchan or outowner is set != NULL after calling this function
- *       those channels are locked and reffed.
- * \note Batman.
- */
-void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner);
-
-/*!
- * \brief Hangup one end (maybe both ends) of an unreal channel derivative.
- * \since 12.0.0
- *
- * \param p Private channel struct (reffed)
- * \param ast Channel being hung up.  (locked)
- *
- * \note Common hangup code for unreal channels.  Derived
- * channels will need to deal with any additional resources.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast);
-
-/*! Unreal channel framework struct ast_channel_tech.send_digit_begin callback */
-int ast_unreal_digit_begin(struct ast_channel *ast, char digit);
-
-/*! Unreal channel framework struct ast_channel_tech.send_digit_end callback */
-int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-
-/*! Unreal channel framework struct ast_channel_tech.answer callback */
-int ast_unreal_answer(struct ast_channel *ast);
-
-/*! Unreal channel framework struct ast_channel_tech.read and struct ast_channel_tech.exception callback */
-struct ast_frame *ast_unreal_read(struct ast_channel *ast);
-
-/*! Unreal channel framework struct ast_channel_tech.write callback */
-int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f);
-
-/*! Unreal channel framework struct ast_channel_tech.indicate callback */
-int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-
-/*! Unreal channel framework struct ast_channel_tech.fixup callback */
-int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-
-/*! Unreal channel framework struct ast_channel_tech.send_html callback */
-int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-
-/*! Unreal channel framework struct ast_channel_tech.send_text callback */
-int ast_unreal_sendtext(struct ast_channel *ast, const char *text);
-
-/*! Unreal channel framework struct ast_channel_tech.queryoption callback */
-int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
-
-/*! Unreal channel framework struct ast_channel_tech.setoption callback */
-int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen);
-
-/*!
- * \brief struct ast_unreal_pvt destructor.
- * \since 12.0.0
- *
- * \param vdoomed Object to destroy.
- *
- * \return Nothing
- */
-void ast_unreal_destructor(void *vdoomed);
-
-/*!
- * \brief Allocate the base unreal struct for a derivative.
- * \since 12.0.0
- *
- * \param size Size of the unreal struct to allocate.
- * \param destructor Destructor callback.
- * \param cap Format capabilities to give the unreal private struct.
- *
- * \retval pvt on success.
- * \retval NULL on error.
- */
-struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap);
-
-/*!
- * \brief Create the semi1 and semi2 unreal channels.
- * \since 12.0.0
- *
- * \param p Unreal channel private struct.
- * \param tech Channel technology to use.
- * \param semi1_state State to start the semi1(owner) channel in.
- * \param semi2_state State to start the semi2(outgoing chan) channel in.
- * \param exten Exten to start the chennels in. (NULL if s)
- * \param context Context to start the channels in. (NULL if default)
- * \param requestor Channel requesting creation. (NULL if none)
- * \param callid Thread callid to use.
- *
- * \retval semi1_channel on success.
- * \retval NULL on error.
- */
-struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
-	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
-	const char *exten, const char *context, const struct ast_assigned_ids *assignedids, 
-	const struct ast_channel *requestor, struct ast_callid *callid);
-
-/*!
- * \brief Setup unreal owner and chan channels before initiating call.
- * \since 12.0.0
- *
- * \param semi1 Owner channel of unreal channel pair.
- * \param semi2 Outgoing channel of unreal channel pair.
- *
- * \note On entry, the semi1 and semi2 channels are already locked.
- *
- * \return Nothing
- */
-void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2);
-
-/*!
- * \brief Push the semi2 unreal channel into a bridge from either member of the unreal pair
- * \since 12.0.0
- *
- * \param ast A member of the unreal channel being pushed
- * \param bridge Which bridge we want to push the channel to
- * \param flags Feature flags to be set on the bridge channel.
- *
- * \retval 0 if the channel is successfully imparted onto the bridge
- * \retval -1 on failure
- *
- * \note This is equivalent to ast_call() on unreal based channel drivers that are designed to use it instead.
- */
-int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags);
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_CORE_UNREAL_H */
diff --git a/include/asterisk/crypto.h b/include/asterisk/crypto.h
index c911404..1f87811 100644
--- a/include/asterisk/crypto.h
+++ b/include/asterisk/crypto.h
@@ -46,8 +46,8 @@ struct ast_key;
 
 /*!
  * \brief Retrieve a key
- * \param key Name of the key we are retrieving
- * \param type Intger type of key (AST_KEY_PUBLIC or AST_KEY_PRIVATE)
+ * \param name of the key we are retrieving
+ * \param int type of key (AST_KEY_PUBLIC or AST_KEY_PRIVATE)
  *
  * \retval the key on success.
  * \retval NULL on failure.
@@ -70,7 +70,6 @@ AST_OPTIONAL_API(int, ast_check_signature, (struct ast_key *key, const char *msg
  * \brief Check the authenticity of a message signature using a given public key
  * \param key a public key to use to verify
  * \param msg the message that has been signed
- * \param msglen
  * \param sig the proposed valid signature in raw binary representation
  *
  * \retval 0 if the signature is valid.
@@ -96,7 +95,6 @@ AST_OPTIONAL_API(int, ast_sign, (struct ast_key *key, char *msg, char *sig), { r
  * \brief Sign a message signature using a given private key
  * \param key a private key to use to create the signature
  * \param msg the message to sign
- * \param msglen
  * \param sig a pointer to a buffer of at least 128 bytes in which the
  * raw encoded signature will be stored
  *
diff --git a/include/asterisk/data.h b/include/asterisk/data.h
index 3676b8d..e325337 100644
--- a/include/asterisk/data.h
+++ b/include/asterisk/data.h
@@ -26,7 +26,6 @@
 #define ASTERISK_DATA_H
 
 #include "asterisk/frame.h"
-#include "asterisk/format_cap.h"
 
 /*!
  * \page AstDataRetrieval The Asterisk DATA retrieval API.
diff --git a/include/asterisk/datastore.h b/include/asterisk/datastore.h
index 8f59fd3..5f7e523 100644
--- a/include/asterisk/datastore.h
+++ b/include/asterisk/datastore.h
@@ -34,7 +34,7 @@ struct ast_datastore_info {
 	void (*destroy)(void *data);		/*!< Destroy function */
 
 	/*!
-	 * \brief Fix up channel references on the masquerading channel
+	 * \brief Fix up channel references
 	 *
 	 * \arg data The datastore data
 	 * \arg old_chan The old channel owning the datastore
@@ -48,20 +48,6 @@ struct ast_datastore_info {
 	 * \return nothing.
 	 */
 	void (*chan_fixup)(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
-
-	/*!
-	 * \brief Fix up channel references on the channel being masqueraded into
-	 *
-	 * \arg data The datastore data
-	 * \arg old_chan The old channel owning the datastore
-	 * \arg new_chan The new channel owning the datastore
-	 *
-	 * This is the same as the above callback, except it is called for the channel
-	 * being masqueraded into instead of the channel that is masquerading.
-	 *
-	 * \return nothing.
-	 */
-	void (*chan_breakdown)(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
 };
 
 /*! \brief Structure for a data store object */
@@ -77,7 +63,6 @@ struct ast_datastore {
  * \brief Create a data store object
  * \param[in] info information describing the data store object
  * \param[in] uid unique identifer
- * \param file, line, function
  * \version 1.6.1 moved here and renamed from ast_channel_datastore_alloc
  */
 struct ast_datastore * attribute_malloc __ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid,
diff --git a/include/asterisk/devicestate.h b/include/asterisk/devicestate.h
index 4f9aa73..29a736d 100644
--- a/include/asterisk/devicestate.h
+++ b/include/asterisk/devicestate.h
@@ -19,7 +19,7 @@
 /*! \file
  * \brief Device state management
  *
- * To subscribe to device state changes, use the stasis_subscribe
+ * To subscribe to device state changes, use the generic ast_event_subscribe
  * method.  For an example, see apps/app_queue.c.
  *
  * \todo Currently, when the state of a device changes, the device state provider
@@ -38,7 +38,6 @@
 #define _ASTERISK_DEVICESTATE_H
 
 #include "asterisk/channelstate.h"
-#include "asterisk/utils.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -59,7 +58,7 @@ enum ast_device_state {
 	AST_DEVICE_RINGING,      /*!< Device is ringing */
 	AST_DEVICE_RINGINUSE,    /*!< Device is ringing *and* in use */
 	AST_DEVICE_ONHOLD,       /*!< Device is on hold */
-	AST_DEVICE_TOTAL,        /*!< Total num of device states, used for testing */
+	AST_DEVICE_TOTAL,        /*/ Total num of device states, used for testing */
 };
 
 /*! \brief Device State Cachability
@@ -270,110 +269,19 @@ struct ast_devstate_aggregate {
 };
 
 /*!
- * \brief The structure that contains device state
- * \since 12
- */
-struct ast_device_state_message {
-	/*! The name of the device */
-	const char *device;
-	/*!
-	 * \brief The EID of the server where this message originated.
-	 *
-	 * \note A NULL EID means aggregate state.
-	 */
-	const struct ast_eid *eid;
-	/*! The state of the device */
-	enum ast_device_state state;
-	/*! Flag designating the cachability of this device state */
-	enum ast_devstate_cache cachable;
-	/*! The device and eid data is stuffed here when the struct is allocated. */
-	struct ast_eid stuff[0];
-};
-
-/*!
- * \brief Get the Stasis topic for device state messages
- * \retval The topic for device state messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_topic *ast_device_state_topic_all(void);
-
-/*!
- * \brief Get the Stasis topic for device state messages for a specific device
- * \param uniqueid The device for which to get the topic
- * \retval The topic structure for MWI messages for a given device
- * \retval NULL if it failed to be found or allocated
- * \since 12
- */
-struct stasis_topic *ast_device_state_topic(const char *device);
-
-/*!
- * \brief Get the Stasis caching topic for device state messages
- * \retval The caching topic for device state messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_topic *ast_device_state_topic_cached(void);
-
-/*!
- * \brief Backend cache for ast_device_state_topic_cached()
- * \retval Cache of \ref ast_device_state_message.
- * \since 12
- */
-struct stasis_cache *ast_device_state_cache(void);
-
-/*!
- * \brief Get the Stasis message type for device state messages
- * \retval The message type for device state messages
- * \retval NULL if it has not been allocated
- * \since 12
- */
-struct stasis_message_type *ast_device_state_message_type(void);
-
-/*!
- * \brief Clear the device from the stasis cache.
- * \param The device to clear
- * \retval 0 if successful
- * \retval -1 nothing to clear
- * \since 12
- */
-int ast_device_state_clear_cache(const char *device);
-
-/*!
- * \brief Initialize the device state core
- * \retval 0 Success
- * \retval -1 Failure
- * \since 12
- */
-int devstate_init(void);
-
-/*!
- * \brief Publish a device state update
- * \param[in] device The device name
- * \param[in] state The state of the device
- * \param[in] cachable Whether the device state can be cached
- * \retval 0 Success
- * \retval -1 Failure
- * \since 12
- */
-#define ast_publish_device_state(device, state, cachable) \
-	ast_publish_device_state_full(device, state, cachable, &ast_eid_default)
-
-/*!
- * \brief Publish a device state update with EID
- * \param[in] device The device name
- * \param[in] state The state of the device
- * \param[in] cachable Whether the device state can be cached
- * \param[in] eid The EID of the server that originally published the message
- * \retval 0 Success
- * \retval -1 Failure
- * \since 12
+ * \brief Enable distributed device state processing.
+ *
+ * \details
+ * By default, Asterisk assumes that device state change events will only be
+ * originating from one instance.  If a module gets loaded and configured such
+ * that multiple instances of Asterisk will be sharing device state, this
+ * function should be called to enable distributed device state processing.
+ * It is off by default to save on unnecessary processing.
+ *
+ * \retval 0 success
+ * \retval -1 failure
  */
-int ast_publish_device_state_full(
-			const char *device,
-			enum ast_device_state state,
-			enum ast_devstate_cache cachable,
-			struct ast_eid *eid);
+int ast_enable_distributed_devstate(void);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
diff --git a/include/asterisk/dial.h b/include/asterisk/dial.h
index ab92198..04721d2 100644
--- a/include/asterisk/dial.h
+++ b/include/asterisk/dial.h
@@ -33,9 +33,6 @@ struct ast_dial;
 /*! \brief Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! */
 struct ast_dial_channel;
 
-/*! \brief Forward declaration for format capabilities, used in prerun */
-struct ast_format_cap;
-
 typedef void (*ast_dial_state_callback)(struct ast_dial *);
 
 /*! \brief List of options that are applicable either globally or per dialed channel */
@@ -44,8 +41,6 @@ enum ast_dial_option {
 	AST_DIAL_OPTION_ANSWER_EXEC,             /*!< Execute application upon answer in async mode */
 	AST_DIAL_OPTION_MUSIC,                   /*!< Play music on hold instead of ringing to the calling channel */
 	AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, /*!< Disable call forwarding on channels */
-	AST_DIAL_OPTION_PREDIAL,                 /*!< Execute a predial subroutine before dialing */
-	AST_DIAL_OPTION_DIAL_REPLACES_SELF,      /*!< The dial operation is a replacement for the requester */
 	AST_DIAL_OPTION_MAX,                     /*!< End terminator -- must always remain last */
 };
 
@@ -73,16 +68,7 @@ struct ast_dial *ast_dial_create(void);
  * \note Appends a channel to a dialing structure
  * \return Returns channel reference number on success, -1 on failure
  */
-int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids);
-
-/*! \brief Request all appended channels, but do not dial
- * \param dial Dialing structure
- * \param chan Optional dialing channel
- * \param cap Optional requested capabilities
- * \retval -1 failure
- * \reval 0 success
- */
-int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_format_cap *cap);
+int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device);
 
 /*! \brief Execute dialing synchronously or asynchronously
  * \note Dials channels in a dial structure.
@@ -159,20 +145,6 @@ int ast_dial_option_global_disable(struct ast_dial *dial, enum ast_dial_option o
  */
 int ast_dial_option_disable(struct ast_dial *dial, int num, enum ast_dial_option option);
 
-/*! \brief Get the reason an outgoing channel has failed
- * \param dial Dial structure
- * \param num Channel number to get the reason from
- * \return Numerical cause code
- */
-int ast_dial_reason(struct ast_dial *dial, int num);
-
-/*! \brief Get the dialing channel, if prerun has been executed
- * \param dial Dial structure
- * \param num Channel number to get channel of
- * \return Pointer to channel, without reference
- */
-struct ast_channel *ast_dial_get_channel(struct ast_dial *dial, int num);
-
 /*! \brief Set a callback for state changes
  * \param dial The dial structure to watch for state changes
  * \param callback the callback
@@ -208,11 +180,6 @@ void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout);
  */
 void ast_dial_set_timeout(struct ast_dial *dial, int num, int timeout);
 
-/*! \since 12
- * \brief Convert a hangup cause to a publishable dial status
- */
-const char *ast_hangup_cause_to_dial_status(int hangup_cause);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/dns.h b/include/asterisk/dns.h
index 4899fa8..64cf68c 100644
--- a/include/asterisk/dns.h
+++ b/include/asterisk/dns.h
@@ -36,7 +36,4 @@
 int ast_search_dns(void *context, const char *dname, int class, int type,
 	 int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer));
 
-/*! \brief Retrieve the configured nameservers of the system */
-struct ao2_container *ast_dns_get_nameservers(void);
-
 #endif /* _ASTERISK_DNS_H */
diff --git a/include/asterisk/doxygen/architecture.h b/include/asterisk/doxygen/architecture.h
index 0809d6b..c157697 100644
--- a/include/asterisk/doxygen/architecture.h
+++ b/include/asterisk/doxygen/architecture.h
@@ -24,8 +24,9 @@
 /*!
 \page AsteriskArchitecture Asterisk Architecture Overview
 \author Russell Bryant <russell at digium.com>
+\AsteriskTrunkWarning
 
-<hr>
+<hr/>
 
 \section ArchTOC Table of Contents
 
@@ -53,7 +54,7 @@
     -# \ref ArchConceptBridging
  -# \ref ArchCodeFlows
     -# \ref ArchCodeFlowPlayback
-    -# \ref ArchCodeFlowBridge
+    -# \ref ArchCodeFlowBridge 
  -# \ref ArchDataStructures
     -# \ref ArchAstobj2
     -# \ref ArchLinkedLists
@@ -63,7 +64,7 @@
     -# \ref ArchThreadDebugging
     -# \ref ArchMemoryDebugging
 
-<hr>
+<hr/>
 
 \section ArchIntro Introduction
 
@@ -258,14 +259,11 @@ in the source tree.
 For a list of bridge technology implementations, see \ref bridges.
 
 For additional information on the bridging API, see
-\arg <code>include/asterisk/bridge.h</code>
-\arg <code>include/asterisk/bridge_technology.h</code>
-\arg <code>include/asterisk/bridge_channel.h</code>
-\arg <code>include/asterisk/bridge_features.h</code>
-\arg <code>include/asterisk/bridge_after.h</code>
+<code>include/asterisk/bridging.h</code> and
+<code>include/asterisk/bridging_technology.h</code>.
 
 For additional implementation details regarding the core bridging API, see
-<code>main/bridge.c</code> and <code>main/bridge_channel.c</code>.
+<code>main/bridging.c</code>.
 
 \subsection ArchInterfaceCDR Call Detail Record (CDR) Handlers
 
@@ -297,7 +295,7 @@ many events to one call.  The CEL modules look very similar to CDR modules.
 
 CEL modules typically live in the <code>cel/</code> directory in the source tree.
 
-For a list of CEL handlers, see cel_drivers.
+For a list of CEL handlers, see \ref cel_drivers.
 
 For additional information about the CEL API, see
 <code>include/asterisk/cel.h</code>.
@@ -409,7 +407,7 @@ When an inbound channel executes an application such as <code>Dial()</code>, an
 outbound channel is created and bridged to the inbound channel once it answers.
 
 Dialplan applications always execute in the context of a channel thread.  Dialplan
-functions almost always do, as well.  However, it is possible to read and write
+functions \i almost always do, as well.  However, it is possible to read and write
 dialplan functions from an asynchronous interface such as the Asterisk CLI or the
 manager interface (AMI).  However, it is still always the channel thread that is
 the owner of the ast_channel data structure.
@@ -439,7 +437,7 @@ Asterisk CLI operates using connections to a UNIX %domain socket.
 There are other miscellaneous threads throughout the system that perform a specific task.
 For example, the event API (include/asterisk/event.h) uses a thread internally
 (main/event.c) to handle asychronous event dispatching.  The devicestate API
-(include/asterisk/devicestate.h) uses a thread internally (main/devicestate.c)
+(include/asterisk/devicestate.h) uses a thread internally (main/devicestate.c) 
 to asynchronously process device state changes.
 
 
@@ -712,7 +710,7 @@ The implementation of this memory debugging system can be found in
 <code>main/astmm.c</code>.
 
 
-<hr>
+<hr/>
 Return to the \ref ArchTOC
  */
 
diff --git a/include/asterisk/doxygen/asterisk-git-howto.h b/include/asterisk/doxygen/asterisk-git-howto.h
index 1ecce15..ee35b76 100644
--- a/include/asterisk/doxygen/asterisk-git-howto.h
+++ b/include/asterisk/doxygen/asterisk-git-howto.h
@@ -21,7 +21,9 @@
 /*!
  * \page AsteriskGitHowto How to setup a local GIT mirror of the Asterisk SVN repository
  *
- * <hr>
+ * \AsteriskTrunkWarning
+ *
+ * <hr/>
  *
  * \section Introduction Introduction
  * This document will instruct you how to setup a local git mirror of the 
@@ -30,7 +32,7 @@
  * Why would you want that? for starters, it's a fast repository browser
  * and works well even when offline. More on why and why not at 'Pros and Cons'
  * in the end of this document. 
- * <hr>
+ * <hr/>
  *
  * \section Setup Setup
  *
@@ -108,7 +110,7 @@
  * If you don't like the extra 'v', just edit the sed command.
  *
  \verbatim
-  ../asterisk-tools/update_tags
+  ../asterisk-tools/update-tags
  \endverbatim
  * 
  * Example configuration (refer to menuselect/menuselelct for more
@@ -118,7 +120,7 @@
   echo 'exclude res_snmp' >build_tools/conf
  \endverbatim
  *
- * <hr>
+ * <hr/>
  *
  * \section Update Update
  * The main Asterisk repository tends to get new commits occasionally. I
@@ -131,7 +133,7 @@
  \endverbatim
  *
  * Next, get all updates.
- * <hr>
+ * <hr/>
  *
  * \section Usage Usage
  *
@@ -181,7 +183,7 @@
   git svn rebase --fetch-all
  \endverbatim
  *
- * <hr>
+ * <hr/>
  *
  * \section ProsAndCons Pros and Cons
  *
@@ -231,5 +233,5 @@
  *  to test that. Even if it will, it will require an extra step of manual
  *  editing.
  *
- * <hr>
+ * <hr/>
  */
diff --git a/include/asterisk/doxygen/commits.h b/include/asterisk/doxygen/commits.h
index 032bfc5..33df679 100644
--- a/include/asterisk/doxygen/commits.h
+++ b/include/asterisk/doxygen/commits.h
@@ -21,23 +21,25 @@
 /*!
  * \page CommitMessages Guidelines for Commit Messages
  *
- * <hr>
+ * \AsteriskTrunkWarning
+ *
+ * <hr/>
  *
  * \section CommitMsgFormatting Commit Message Formatting
  *
  * The following illustrates the basic outline for commit messages:
  *
- * \verbatim
- * <One-liner summary of changes>
- *
- * <Empty Line> 
- *
- * <Verbose description of the changes>
- *
- * <Empty Line> 
- *
- * <Special Tags>
- * \endverbatim
+  \verbatim
+  <One-liner summary of changes>
+
+  <Empty Line> 
+
+  <Verbose description of the changes>
+
+  <Empty Line> 
+
+  <Special Tags>
+  \endverbatim
  *
  * Some commit history viewers treat the first line of commit messages as the
  * summary for the commit.  So, an effort should be made to format our commit
@@ -50,7 +52,7 @@
  * \note For trivial commits, such as "fix the build", or "fix spelling mistake",
  *       the verbose description may not be necessary.
  *
- * <hr>
+ * <hr/>
  *
  * \section CommitMsgTags Special Tags for Commit Messages
  *
@@ -75,12 +77,12 @@
  *
  * Here is an example of what the template will generate for you:
  *
- * \verbatim
- * (closes issue #1234)
- * Reported by: SomeGuy
- * Patches:
- *      fix_bug_1234.diff uploaded by SomeDeveloper (license 5678)
- * \endverbatim
+  \verbatim
+  (closes issue #1234)
+  Reported by: SomeGuy
+  Patches:
+       fix_bug_1234.diff uploaded by SomeDeveloper (license 5678)
+  \endverbatim
  *
  * If the patch being committed was written by the person doing the commit,
  * and is not available to reference as an upload to the issue, there is no
@@ -95,7 +97,7 @@
  *
  * \note The trailing slash in the review URL is required.
  *
- * <hr>
+ * <hr/>
  *
  * \section CommitMsgSvnmerge Commit Messages with svnmerge
  *
@@ -110,5 +112,7 @@
  *
  * For more detailed information about working with branches and merging,
  * see the following page on %asterisk.org:
- * \arg https://wiki.asterisk.org/wiki/display/AST/Subversion+Usage
+ * \arg http://www.asterisk.org/developers/svn-branching-merging
  */
+
+
diff --git a/include/asterisk/doxygen/licensing.h b/include/asterisk/doxygen/licensing.h
index 27d55bf..3875540 100644
--- a/include/asterisk/doxygen/licensing.h
+++ b/include/asterisk/doxygen/licensing.h
@@ -22,7 +22,7 @@
  * \page Licensing Asterisk Licensing Information
  *
  * \section license Asterisk License
- * \note See the LICENSE file for up to date info
+ * \verbinclude LICENSE
  *
  * \section otherlicenses Licensing of 3rd Party Code
  *
diff --git a/include/asterisk/doxygen/mantisworkflow.h b/include/asterisk/doxygen/mantisworkflow.h
new file mode 100644
index 0000000..3e17557
--- /dev/null
+++ b/include/asterisk/doxygen/mantisworkflow.h
@@ -0,0 +1,206 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2009, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ */
+
+/*!
+ * \page MantisWorkflow Workflow Guidelines for Asterisk Open Source Issue Tracker
+ *
+ * \AsteriskTrunkWarning
+ *
+ * <hr/>
+ * \section WorkflowDescription Description of the Issue Tracker Workflow
+ * 
+ * (This document is most beneficial for Asterisk bug marshals, however it is good
+ * reading for anyone who may be filing issues or wondering how the Asterisk Open
+ * Source project moves issues through from filing to completion.)
+ * 
+ * The workflow in the issue tracker should be handled in the following way:
+ * 
+ * -# A bug is reported and is automatically placed in the 'New' status.
+ * -# The Bug Marshall team should go through bugs in the 'New' status to determine 
+ *    whether the report is valid (not a duplicate, hasn't already been fixed, not 
+ *    a Digium tech support issue, etc.).  Invalid reports should be set to 
+ *    'Closed' with the appropriate resolution set. Categories and descriptions 
+ *    should be corrected at this point.[Note1]\n
+ *    Issues should also have enough information for a developer to either 
+ *    reproduce the issue or determine where an issue exists (or both). If this is 
+ *    not the case then the issue should be moved to 'Feedback' prior to moving 
+ *    forward in the workflow.
+ * -# The next step is to determine whether the report is about a bug or a 
+ *    submission of a new feature:
+ *       -# BUG: A bug should be moved into the status 'Acknowledged' if enough
+ *          information has been provided by the reporter to either reproduce the
+ *          issue or clearly see where an issue may lie. The bug may also be
+ *          assigned to a developer for the creation of the initial patch, or
+ *          review of the issue.\n
+ *          Once a patch has been created for the issue and attached, the issue can
+ *          then be moved to the 'Confirmed' status. At this point, initial code 
+ *          review and discussion about the patch will take place. Once an adequate
+ *          amount of support for the implementation of the patch is acquired, then
+ *          the bug can be moved to the 'Ready for Testing' status for wider 
+ *          testing by the community. After the testing phase is complete and it
+ *          appears the issue is resolved, the patch can be committed by a 
+ *          developer and closed.
+ *       -# FEATURE: As new features should be filed with a patch, it can be 
+ *          immediately moved to the 'confirmed' status, making it ready for basic
+ *          formatting and code review. From there any changes to style or feel of
+ *          the patch based on feedback from the community can be discussed, and
+ *          changes to the patch made. It can then be moved forward to the 'Ready 
+ *          for Testing' status. Once the feature has been merged, or a decision
+ *          has been made that it will not be merged, the issue should be taken to 
+ *          'Closed' with the appropriate resolution.[Note2]
+ * -# If at any point in the workflow, an issue requires feedback from the original
+ *    poster of the issue, the status should be changed to 'Feedback'.  Once the 
+ *    required information has been provided, it should be placed back in the
+ *    appropriate point of the workflow.
+ * -# If at any point in the workflow, a developer or bug marshal would like to 
+ *    take responsibility for doing the work that is necessary to progress an 
+ *    issue, the status can be changed to 'Assigned'. At that point the developer
+ *    assigned to the issue will be responsible for moving the issue to completion.
+ * 
+ * \section WorkflowSummary Workflow Summary
+ * 
+ * The following is a list of valid statuses and what they mean to the work flow.
+ *
+ * \subsection New New
+ *    This issue is awaiting review by bug marshals.  Categorization and summaries
+ *    should be fixed as appropriate.
+ * 
+ * \subsection Feedback
+ *    This issue requires feedback from the poster of the issue before any
+ *    additional progress in the workflow can be made. This may include providing
+ *    additional debugging information, or a backtrace with DONT_OPTIMIZE enabled,
+ *    for example. (See the doc/HOWTO_collect_debug_information.txt file in your
+ *    Asterisk source.)
+ * 
+ * \subsection Acknowledged
+ *    This is a submitted bug which has no patch associated with it, but appears
+ *    to be a valid bug based on the description and provided debugging
+ *    information.
+ * 
+ * \subsection Confirmed
+ *    The patch associated with this issue requires initial formatting and code
+ *    review, and may have some initial testing done. It is waiting for a 
+ *    developer to confirm the patch will no longer need large changes made to it,
+ *    and is ready for wider testing from the community. This stage is used for
+ *    discussing the feel and style of a patch, in addition to the coding style
+ *    utilized.
+ * 
+ * \subsection Ready For Testing
+ *    This is an issue which has a patch that is waiting for testing feedback from
+ *    the community after it has been deemed to no longer need larger changes.
+ * 
+ * \subsection Assigned
+ *    A developer or bug marshal has taken responsibility for taking the necessary
+ *    steps to move forward in the workflow.  Once the issue is ready to be
+ *    reviewed and feedback provided, it should be placed back into the
+ *    appropriate place of the workflow.
+ * 
+ * \subsection Resolved
+ *    A resolution for this issue has been reached.  This issue should immediately
+ *    be Closed.
+ * 
+ * \subsection Closed
+ *    No further action is necessary for this issue.
+ * 
+ * \section SeverityLevels Severity Levels
+ * 
+ * Severity levels generally represent the number of users who are potentially
+ * affected by the reported issue. 
+ * 
+ * \subsection Feature Feature
+ *    This issue is a new feature and will only be committed to Asterisk trunk.
+ *    Asterisk trunk is where future branches will be created and thus this
+ *    feature will only be found in future branches of Asterisk and not merged
+ *    into existing branches. (See Release Branch Commit Policy below.)
+ * 
+ * \subsection Trivial Trivial
+ *    A trivial issue is something that either affects an insignificant number of
+ *    Asterisk users, or is a minimally invasive change that does not affect
+ *    functionality.
+ * 
+ * \subsection Text Text
+ *    A text issue is typically something like a spelling fix, a clarifying of a
+ *    debugging or verbose message, or changes to documentation.
+ * 
+ * \subsection Tweak Tweak
+ *    A tweak to the code the has the potential to either make code clearer to
+ *    read, or a change that could speed up processing in certain circumstances.
+ *    These changes are typically only a couple of lines.
+ * 
+ * \subsection Minor Minor
+ *    An issue that does not affect a large number of Asterisk users, but not an
+ *    insignificant number. The number of lines of code and development effort to
+ *    resolve this issue could be non-trivial.
+ * 
+ * \subsection Major Major
+ *    As issue that affects the majority of Asterisk users. The number of lines of
+ *    code and development effort required to resolve this issue could be
+ *    non-trivial.
+ * 
+ * \subsection Crash Crash
+ *    An issue marked as a Crash is something that would cause Asterisk to be
+ *    unusable for a majority of Asterisk users and is an issue that causes a
+ *    deadlock or crash of the Asterisk process.
+ * 
+ * \subsection Block Block
+ *    A blocking issue is an issue that must be resolved before the next release
+ *    of Asterisk as would affect a significant number of Asterisk users, or could
+ *    be a highly visible regression. A severity of block should only be set by
+ *    Asterisk bug marshals at their discretion.
+ * 
+ *        *** USERS SHOULD NOT FILE ISSUES WITH A SEVERITY OF BLOCK ***
+ * 
+ * \section PriorityLevels Priority Levels
+ *
+ * Currently, the following priority levels are listed on the issue tracker:
+ * - None
+ * - Low
+ * - Normal
+ * - High
+ * - Urgent
+ * - Immediate
+ *
+ * However, at this time they are not utilized and all new issue should have a priority of 'Normal'.
+ *
+ * \section Notes Notes
+ * 
+ * -# Using the "Need Triage" filter is useful for finding these issues quickly.
+ * -# The issue tracker now has the ability to monitor the commits list, and if
+ *    the commit message contains something like, "(Closes issue #9999)", the bug
+ *    will be automatically closed.\n
+ *    See http://www.asterisk.org/doxygen/trunk/CommitMessages.html for more
+ *    information on commit messages.
+ * 
+ * \section ReleaseBranchCommitPolicy Release Branch Commit Policy
+ * 
+ * The code in the release branches should be changed as little as possible.  The 
+ * only time the release branches will be changed is to fix a bug.  New features 
+ * will never be included in the release branch unless a special exception is made
+ * by the release branch maintainers.
+ * 
+ * Sometimes it is difficult to determine whether a patch is considered to fix a 
+ * bug or if it is a new feature.  Patches that are considered code cleanup, or to 
+ * improve performance, are NOT to be included in the release branches. Performance
+ * issues will only be considered for the release branch if they are considered 
+ * significant, and should be approved by the maintainers.
+ * 
+ * If there is ever a question about what should be included in the release branch,
+ * the maintainers should be allowed to make the decision.
+ */
diff --git a/include/asterisk/doxygen/releases.h b/include/asterisk/doxygen/releases.h
index d1b33ff..c895d1c 100644
--- a/include/asterisk/doxygen/releases.h
+++ b/include/asterisk/doxygen/releases.h
@@ -21,6 +21,8 @@
 /*!
  * \page ReleaseStatus Asterisk Release Status
  *
+ * @AsteriskTrunkWarning
+ *
  * \section warranty Warranty
  * The following warranty applies to all open source releases of Asterisk:
  *
@@ -122,6 +124,8 @@
 /*!
  * \page ReleasePolicies Asterisk Release and Commit Policies
  *
+ * \AsteriskTrunkWarning
+ *
  * \section releasestatus Asterisk Release Status
  *
  * For more information on the current status of each Asterisk release series,
@@ -129,7 +133,7 @@
  *
  * \arg \ref ReleaseStatus
  *
- * <hr>
+ * <hr/>
  *
  * \section commitmonitoring Commit Monitoring
  *
@@ -137,7 +141,7 @@
  * <a href="http://lists.digium.com/">http://lists.digium.com</a>.  The Digium
  * mailing list server hosts a %number of mailing lists for commits.
  *
- * <hr>
+ * <hr/>
  *
  * \section ast10policy Asterisk 1.0
  *
@@ -150,7 +154,7 @@
  *
  * No commits should be made to the Asterisk 1.0 branch.
  * 
- * <hr>
+ * <hr/>
  *
  * \section ast12policy Asterisk 1.2
  *
@@ -177,7 +181,7 @@
  *  - 1.2.X.Y - a release that contains fixes to the security patches released in
  *    version 1.2.X
  *
- * <hr>
+ * <hr/>
  *
  * \section ast14policy Asterisk 1.4
  *
@@ -204,7 +208,7 @@
  *  - 1.4.X.Y - a release that contains very few changes on top of 1.4.X.  This
  *    may be for a security patch, or for a regression introduced in 1.4.X.
  *
- * <hr>
+ * <hr/>
  *
  * \section ast16policy Asterisk 1.6
  *
@@ -240,7 +244,7 @@
  *  - 1.6.X.Y - a release that contains fixes for bugs or security issues identified
  *    in the 1.6.X release series.
  *
- * <hr>
+ * <hr/>
  *
  * \section asttrunk Asterisk Trunk
  *
@@ -265,7 +269,7 @@
  * tested and reviewed such that there is reasonable belief that the code
  * is ready to go.
  *
- * <hr>
+ * <hr/>
  *
  * \section astteam Asterisk Team Branches
  *
diff --git a/include/asterisk/doxygen/reviewboard.h b/include/asterisk/doxygen/reviewboard.h
index 59ab852..b864454 100644
--- a/include/asterisk/doxygen/reviewboard.h
+++ b/include/asterisk/doxygen/reviewboard.h
@@ -21,7 +21,9 @@
 /*!
  * \page Reviewboard Reviewboard Usage and Guidelines
  *
- * <hr>
+ * \AsteriskTrunkWarning
+ *
+ * <hr/>
  *
  * \section ReviewboardGuidelines Usage Guidelines
  *
@@ -50,7 +52,7 @@
  * testing and should not have blatant coding guidelines violations.  Lack of
  * these things is careless and shows disrespect for those reviewing your code.
  *
- * <hr>
+ * <hr/>
  *
  * \section ReviewboardPosting Posting Code to Reviewboard
  *
@@ -59,25 +61,25 @@
  * The easiest way to post a patch to reviewboard is by using the
  * post-review tool.  We have post-review in our repotools svn repository.
  *
- * \verbatim
- * $ svn co http://svn.digium.com/svn/repotools
- * \endverbatim
+   \verbatim
+   $ svn co http://svn.digium.com/svn/repotools
+   \endverbatim
  *
  * Essentially, post-review is a script that will take the output of "svn
  * diff" and create a review request out of it for you.  So, once you have
  * a working copy with the changes you expect in the output of "svn diff",
  * you just run the following command:
  *
- * \verbatim
- * $ post-review
- * \endverbatim
+   \verbatim
+   $ post-review
+   \endverbatim
  * 
  * If it complains about not knowing which reviewboard server to use, add
  * the server option:
  * 
- * \verbatim
- * $ post-review --server=https://reviewboard.asterisk.org
- * \endverbatim
+   \verbatim
+   $ post-review --server=https://reviewboard.asterisk.org
+   \endverbatim
  *
  * \subsection postreviewnewfiles Dealing with New Files
  * 
@@ -88,15 +90,15 @@
  * 
  * You would start by getting your changes applied to a trunk working copy:
  * 
- * \verbatim
- * $ cd .../trunk
- * \endverbatim
+   \verbatim
+   $ cd .../trunk
+   \endverbatim
  * 
  * Then, apply the changes from your branch:
  * 
- * \verbatim
- * $ svn merge .../trunk .../team/group/my_new_code
- * \endverbatim
+   \verbatim
+   $ svn merge .../trunk .../team/group/my_new_code
+   \endverbatim
  * 
  * Now, the code is merged into your working copy.  However, for a new
  * file, subversion treats it as a copy of existing content and not new
@@ -104,10 +106,10 @@
  * it to show up in the diff, use the following commands so svn treats it
  * as new content and publishes it in the diff:
  * 
- * \verbatim
- * $ svn revert my_new_file.c
- * $ svn add my_new_file.c
- * \endverbatim
+   \verbatim
+   $ svn revert my_new_file.c
+   $ svn add my_new_file.c
+   \endverbatim
  * 
  * Now, it should work, and you can run "post-review" as usual.
  *
@@ -119,7 +121,7 @@
  * Apply the current version of the diff to a working copy as described above,
  * and then run the following command:
  * 
- * \verbatim
- * $ post-review -r <review request number>
- * \endverbatim
+   \verbatim
+   $ post-review -r <review request number>
+   \endverbatim
  */
diff --git a/include/asterisk/doxyref.h b/include/asterisk/doxyref.h
index 5550023..314ad83 100644
--- a/include/asterisk/doxyref.h
+++ b/include/asterisk/doxyref.h
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2012, Digium, Inc.
+ * Copyright (C) 1999 - 2009, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -17,9 +17,9 @@
 /*! 
  * \file
  *
- * This is the main header file used for generating miscellaneous documentation
- * using Doxygen.  This also utilizes the documentation in 
- * include/asterisk/doxygen/ header files.
+ * This is the main header file used for generating miscellaneous developer
+ * documentation using doxygen.  This also pulls in all of the documentation
+ * that is in include/asterisk/doxygen/.
  */
 
 /* 
@@ -58,6 +58,7 @@
  * \arg \ref AstSpeech
  *
  * \section debugconfig Debugging and Configuration References
+ * \arg \ref AstREADME : General Administrator README file
  * \arg \ref AstDebug : Hints on debugging
  * \arg \ref extref 
  * \arg \ref ConfigFiles
@@ -91,6 +92,22 @@
  * \arg \ref AstExtState
  * \arg \ref AstDataRetrieval
  *
+ * \subsection model_txt Generic Model
+ * Description of call model:
+ * Incoming Call:
+ * 	Channel backend waits for a RING or equivalent on some sort of
+ * interface. Typically this is done in its own thread.  When a RING is
+ * detected, the backend should create a channel structure and then call
+ * ast_pbx_start() on that channel, which will create a thread to monitor
+ * that interface.  At this point, the PBX and/or applications it launches
+ * will manage the interface, and it need not be monitored by the
+ * aforementioned thread.  When the applications are finished, the requisite
+ * hangup function will be called, at which the channel can be considered to
+ * be no longer valid, and the thread that controls it will imminently be
+ * terminated. 
+ *
+ *
+ * \todo Link to wiki content
  * \subsection channel_txt Channels
  * \arg See \ref Def_Channel
  */
@@ -99,6 +116,7 @@
  * \page AstAPIChanges Asterisk API Changes
  *
  * \section Changes161 Version 1.6.1
+ * \li ast_install_vm_functions()
  * \li vmwi_generate()
  * \li ast_channel_datastore_alloc()
  * \li ast_channel_datastore_free()
@@ -129,11 +147,37 @@
  */
 
 /*! 
+ * \page AstDebug Debugging
+ * \section debug Debugging
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Getting+a+Backtrace
+ * for more information
+ */
+
+/*!
+ * \page AstSpeech The Generic Speech Recognition API
+ * \section debug The Generic Speech Recognition API
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Speech+Recognition+API
+ * for more information
+ */
+
+/*! 
+ * \page DataStores Channel Data Stores
+ * \section debug Channel Data Stores
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Asterisk+Channel+Data+Stores
+ * for more information
+ */
+
+/*! 
  * \page AstAMI AMI - The Manager Interface
  * \section ami AMI - The manager Interface
  * \arg \link Config_ami Configuration file \endlink
  * \arg \ref manager.c
- * \todo include missing manager txt
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Asterisk+Manager+Interface+%28AMI%29
+ * for more information
  */
 
 /*!
@@ -141,8 +185,7 @@
  * \section realtime ARA - a generic API to storage and retrieval
  * Implemented in \ref config.c 
  * Implemented in \ref pbx_realtime.c 
- * \todo include missing realtime txt
- * \todo include missing extconfig txt
+ * https://wiki.asterisk.org/wiki/display/AST/Realtime+Database+Configuration
  */
 
 /*! 
@@ -171,10 +214,17 @@
  * \arg \ref cdr_drivers
  * \arg \ref Config_cdr CDR configuration files
  *
- * \todo include missing cdrdriver txt
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/CDR+Storage+Backends
+ * for more information
  */
 
 /*! 
+ * \page AstREADME README
+ * \verbinclude README
+ */
+ 
+/*! 
  * \page AstCREDITS CREDITS
  * \verbinclude CREDITS
  */
@@ -182,7 +232,9 @@
 /*! 
  * \page AstVideo Video support in Asterisk
  * \section sectAstVideo Video support in Asterisk
- * \todo include missing video txt
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Video+Telephony
+ * for more information
  */
 
 /*! 
@@ -197,6 +249,9 @@
  * - \ref pbx_retrieve_variable()
  * - \ref AstChanVar
  *
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Channel+Variables
+ * for more information
  */
 
 /*! 
@@ -247,21 +302,206 @@
  */
 
 /*! 
+ * \page AstENUM ENUM
+ * \section enumreadme ENUM
+ * \arg Configuration: \ref Config_enum
+ * \arg \ref enum.c
+ * \arg \ref func_enum.c
+ *
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/The+ENUMLOOKUP+Dialplan+Function
+ * for more information
+ */
+
+/*! 
+ * \page ConfigFiles Configuration files
+ * \section config Main configuration files
+ * \arg \link Config_ast asterisk.conf - the main configuration file \endlink
+ * \arg \link Config_ext extensions.conf - The Dial Plan \endlink
+ * \arg \link Config_mod modules.conf - which modules to load and not to load \endlink
+ * \arg \link Config_fea features.conf - call features (transfer, parking, etc) \endlink
+ * \section chanconf Channel configuration files
+ * \arg \link Config_iax IAX2 configuration  \endlink
+ * \arg \link Config_sip SIP configuration  \endlink
+ * \arg \link Config_mgcp MGCP configuration  \endlink
+ * \arg \link Config_rtp RTP configuration  \endlink
+ * \arg \link Config_dahdi DAHDI configuration  \endlink
+ * \arg \link Config_oss OSS (sound card) configuration  \endlink
+ * \arg \link Config_alsa ALSA (sound card) configuration  \endlink
+ * \arg \link Config_agent Agent (proxy channel) configuration  \endlink
+ * \arg \link Config_misdn MISDN Experimental ISDN BRI channel configuration  \endlink
+ * \arg \link Config_h323 H.323 configuration  \endlink
+ * \section appconf Application configuration files
+ * \arg \link Config_mm Meetme (conference bridge) configuration  \endlink
+ * \arg \link Config_qu Queue system configuration  \endlink
+ * \arg \link Config_vm Voicemail configuration  \endlink
+ * \arg \link Config_followme Followme configuration  \endlink
+ * \section cdrconf CDR configuration files
+ * \arg \link Config_cdr CDR configuration  \endlink
+ * \arg \link cdr_csv Default CDR driver configuration \endlink
+ * \arg \link cdr_custom Custom CDR driver configuration \endlink
+ * \arg \link cdr_ami Manager CDR driver configuration \endlink
+ * \arg \link cdr_odbc ODBC CDR driver configuration \endlink
+ * \arg \link cdr_adaptive_odbc Adaptive ODBC CDR driver configuration \endlink
+ * \arg \link cdr_pgsql PostgreSQL CDR driver configuration \endlink
+ * \arg \link cdr_radius RADIUS CDR driver configuration \endlink
+ * \arg \link cdr_sqlite SQLite 2 CDR driver configuration \endlink
+ * \arg \link cdr_sqlite3_custom SQLite 3 CDR driver configuration \endlink
+ * \arg \link cdr_syslog Syslog CDR driver configuration \endlink
+ * \arg \link cdr_tds FreeTDS CDR driver configuration (Microsoft SQL Server) \endlink
+ * \section miscconf Miscellenaous configuration files
+ * \arg \link Config_adsi ADSI configuration  \endlink
+ * \arg \link Config_ami AMI - Manager configuration  \endlink
+ * \arg \link Config_ara Realtime configuration  \endlink
+ * \arg \link Config_codec Codec configuration  \endlink
+ * \arg \link Config_dun DUNDi configuration  \endlink
+ * \arg \link Config_enum ENUM configuration  \endlink
+ * \arg \link Config_moh Music on Hold configuration  \endlink
+ * \arg \link Config_vm Voicemail configuration  \endlink
+ * \arg \link res_config_sqlite SQLite Resource driver configuration \endlink
+ */
+
+/*! 
+ * \page Config_ast Asterisk.conf
+ * \verbinclude asterisk-conf.txt
+ */
+
+/*! 
  * \page Config_mod Modules configuration
  * All res_ resource modules are loaded with globals on, which means
  * that non-static functions are callable from other modules.
  *
  * If you want your non res_* module to export functions to other modules
  * you have to include it in the [global] section.
+ * \verbinclude modules.conf.sample
  */
 
-/*!
+/*! 
+ * \page Config_fea Call features configuration
+ * \par See also
+ * \arg \ref features.c : Call feature implementation
+ * \section featconf features.conf
+ * \verbinclude features.conf.sample
+ */
+
+/*! 
+ * \page Config_followme Followme: An application for simple follow-me calls
+ * \section followmeconf Followme.conf
+ * - See app_followme.c
+ * \verbinclude followme.conf.sample
+ */
+
+/*! 
  * \page Config_ext Extensions.conf - the Dial Plan
  * \section dialplan Extensions.conf 
  * \verbinclude extensions.conf.sample
  */
 
 /*! 
+ * \page Config_iax IAX2 configuration
+ * IAX2 is implemented in \ref chan_iax2.c
+ * \arg \link Config_iax iax.conf Configuration file example \endlink
+ * \section iaxreadme IAX2
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/Inter-Asterisk+eXchange+protocol%2C+version+2+%28IAX2%29
+ * for more information
+ * \section Config_iax IAX Configuration example
+ * \verbinclude iax.conf.sample
+ * \section iaxjitter IAX Jitterbuffer information
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/IAX2+Jitterbuffer
+ * for more information
+ */
+
+/*! 
+ * \page Config_iax IAX configuration
+ * \arg Implemented in \ref chan_iax2.c
+ * \section iaxconf iax.conf
+ * \verbinclude iax.conf.sample
+ */
+
+/*! 
+ * \page Config_sip SIP configuration
+ * Also see \ref Config_rtp RTP configuration
+ * \arg Implemented in \ref chan_sip.c
+ * \section sipconf sip.conf
+ * \verbinclude sip.conf.sample
+ *
+ * \arg \b Back \ref chanconf
+ */
+
+/*! 
+ * \page Config_mgcp MGCP configuration
+ * Also see \ref Config_rtp RTP configuration
+ * \arg Implemented in \ref chan_mgcp.c
+ * \section mgcpconf mgcp.conf
+ * \verbinclude mgcp.conf.sample
+ */
+
+/*! 
+ * \page README_misdn MISDN documentation
+ * \arg See \ref Config_misdn
+ * \section mISDN configuration
+ * Please see the documentation on the wiki at
+ * https://wiki.asterisk.org/wiki/display/AST/mISDN
+ * for more information
+ */
+
+/*! 
+ * \page Config_misdn MISDN configuration
+ * \arg Implemented in \ref chan_misdn.c
+ * \arg \ref README_misdn
+ * \arg See the mISDN home page: http://www.isdn4linux.de/mISDN/
+ * \section misdnconf misdn.conf
+ * \verbinclude misdn.conf.sample
+ */
+
+/*! 
+ * \page Config_vm VoiceMail configuration
+ * \section vmconf voicemail.conf
+ * \arg Implemented in \ref app_voicemail.c
+ * \verbinclude voicemail.conf.sample
+ */
+
+/*! 
+ * \page Config_dahdi DAHDI configuration
+ * \section dahdiconf dahdi.conf
+ * \arg Implemented in \ref chan_dahdi.c
+ * \verbinclude dahdi.conf.sample
+ */
+
+/*! 
+ * \page Config_h323 H.323 channel driver information
+ * This is the configuration of the H.323 channel driver within the Asterisk
+ * distribution. There's another one, called OH323, in asterisk-addons
+ * \arg Implemented in \ref chan_h323.c
+ * \section h323conf h323.conf
+ * \ref chan_h323.c
+ */
+
+/*! 
+ * \page Config_oss OSS configuration
+ * \section ossconf oss.conf
+ * \arg Implemented in \ref chan_oss.c
+ * \verbinclude oss.conf.sample
+ */
+
+/*! 
+ * \page Config_alsa ALSA configuration
+ * \section alsaconf alsa.conf
+ * \arg Implemented in \ref chan_alsa.c
+ * \verbinclude alsa.conf.sample
+ */
+
+/*! 
+ * \page Config_agent Agent configuration
+ * \section agentconf agents.conf
+ * The agent channel is a proxy channel for queues
+ * \arg Implemented in \ref chan_agent.c
+ * \verbinclude agents.conf.sample
+ */
+
+/*! 
  * \page Config_rtp RTP configuration
  * \arg Implemented in \ref rtp.c
  * Used in \ref chan_sip.c and \ref chan_mgcp.c (and various H.323 channels)
@@ -270,6 +510,144 @@
  */
 
 /*! 
+ * \page Config_dun DUNDi Configuration
+ * \arg See also \ref AstDUNDi
+ * \section dundiconf dundi.conf
+ * \verbinclude dundi.conf.sample
+ */
+
+/*! 
+ * \page Config_enum ENUM Configuration
+ * \section enumconf enum.conf
+ * \arg See also \ref enumreadme
+ * \arg Implemented in \ref func_enum.c and \ref enum.c
+ * \verbinclude enum.conf.sample
+ */
+
+/*!
+ * \page cdr_csv Default CDR driver configuration
+ * \par See also
+ * \arg \ref cdrconf
+ * \arg Implemented in \ref cdr_csv.c
+ * \verbinclude cdr_csv.conf.sample
+ */
+
+/*! 
+ * \page cdr_custom Custom CDR Configuration
+ * \par See also 
+ * \arg \ref cdrconf
+ * \arg Implemented in \ref cdr_custom.c
+ * \verbinclude cdr_custom.conf.sample
+ */
+
+/*! 
+ * \page cdr_ami Manager CDR driver configuration
+ * \par See also 
+ * \arg \ref cdrconf
+ * \arg \ref AstAMI
+ * \arg Implemented in \ref cdr_manager.c
+ * \verbinclude cdr_manager.conf.sample
+ */
+
+/*! 
+ * \page cdr_odbc ODBC CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_odbc.c
+ * \verbinclude cdr_odbc.conf.sample
+ * See also:
+ * \arg http://www.unixodbc.org
+ */
+
+/*! 
+ * \page cdr_odbc Adaptive ODBC CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_adaptive_odbc.c
+ * \verbinclude cdr_adaptive_odbc.conf.sample
+ * See also:
+ * \arg http://www.unixodbc.org
+ */
+
+/*! 
+ * \page cdr_pgsql PostgreSQL CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_pgsql.c
+ * See also:
+ * \arg http://www.postgresql.org
+ * \verbinclude cdr_pgsql.conf.sample
+ */
+
+/*!
+ * \page cdr_radius RADIUS CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_radius.c
+ * \verbinclude cdr_radius.conf.sample
+ */
+
+/*! 
+ * \page cdr_sqlite SQLite 2 CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_sqlite.c
+ * See also:
+ * \arg http://www.sqlite.org
+ */
+
+/*!
+ * \page cdr_sqlite3_custom SQLite 3 CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg Implemented in \ref cdr_sqlite3_custom.c
+ * See also:
+ * \arg http://www.sqlite.org
+ * \verbinclude cdr_sqlite3_custom.conf.sample
+ */
+
+/*!
+ * \page cdr_syslog Syslog CDR driver configuration
+ * \arg See also \ref cdrconf
+ * \arg \ref cdr_syslog.c
+ * \verbinclude cdr_syslog.conf.sample
+ */
+
+/*! 
+ * \page cdr_tds FreeTDS CDR driver configuration
+ * \arg See also \ref cdrconf
+ * See also:
+ * \arg http://www.freetds.org
+ * \verbinclude cdr_tds.conf.sample
+ */
+
+/*! 
+ * \page Config_cdr CDR configuration
+ * \par See also
+ * \arg \ref cdr_drivers
+ * \arg \link Config_cdr CDR configuration  \endlink  
+ * \arg \link cdr_csv Default CDR driver configuration \endlink
+ * \arg \link cdr_custom Custom CDR driver configuration \endlink
+ * \arg \link cdr_ami Manager CDR driver configuration \endlink
+ * \arg \link cdr_odbc ODBC CDR driver configuration \endlink
+ * \arg \link cdr_adaptive_odbc Adaptive ODBC CDR driver configuration \endlink
+ * \arg \link cdr_pgsql PostgreSQL CDR driver configuration \endlink
+ * \arg \link cdr_radius RADIUS CDR driver configuration \endlink
+ * \arg \link cdr_sqlite SQLite 2 CDR driver configuration \endlink
+ * \arg \link cdr_sqlite3_custom SQLite 3 CDR driver configuration \endlink
+ * \arg \link cdr_syslog Syslog CDR driver configuration \endlink
+ * \arg \link cdr_tds FreeTDS CDR driver configuration (Microsoft SQL Server) \endlink
+ * \verbinclude cdr.conf.sample
+ */
+
+/*! 
+ * \page Config_moh Music on Hold Configuration
+ * \arg Implemented in \ref res_musiconhold.c
+ * \section mohconf musiconhold.conf
+ * \verbinclude musiconhold.conf.sample
+ */
+
+/*! 
+ * \page Config_adsi ADSI Configuration
+ * \section adsiconf adsi.conf
+ * \verbinclude adsi.conf.sample
+ */
+
+/*! 
  * \page Config_codec CODEC Configuration
  * \section codecsconf codecs.conf
  * \verbinclude codecs.conf.sample
@@ -290,6 +668,20 @@
  */
 
 /*! 
+ * \page Config_qu ACD - Queue system configuration
+ * \arg Implemented in \ref app_queue.c
+ * \section quconf queues.conf
+ * \verbinclude queues.conf.sample
+ */
+
+/*! 
+ * \page Config_mm Meetme - The conference bridge configuration
+ * \arg Implemented in \ref app_meetme.c
+ * \section mmconf meetme.conf
+ * \verbinclude meetme.conf.sample
+ */
+
+/*! 
  * \page SoundFiles Sound files
  * \section SecSound Asterisk Sound files
  * Asterisk includes a large number of sound files. Many of these
@@ -299,21 +691,6 @@
  * repository on svn.digium.com
  */
 
-/*!
- * \page AstHTTP AMI over HTTP support
- * The http.c file includes support for manager transactions over
- * http.
- * \section ami AMI - The manager Interface
- * \arg \link Config_ami Configuration file \endlink
- */
-
-/*
- * Doxygen Groups
- */
-
-/*! \addtogroup configuration_file Configuration Files
- */
-
 /*! 
  * \addtogroup cdr_drivers Module: CDR Drivers
  * \section CDR_generic Asterisk CDR Drivers
@@ -323,6 +700,7 @@
  * \arg \ref Config_cdr "CDR Configuration"
  */
 
+
 /*! 
  * \addtogroup channel_drivers Module: Asterisk Channel Drivers
  * \section channel_generic Asterisk Channel Drivers
@@ -331,7 +709,7 @@
  */
 
 /*! 
- * \addtogroup applications Dial plan applications
+ * \addtogroup applications Module: Dial plan applications
  * \section app_generic Asterisk Dial Plan Applications
  * \brief Applications support the dialplan. They register dynamically with 
  *        \see ast_register_application() and unregister with 
@@ -370,3 +748,24 @@
  * \addtogroup rtp_engines Module: RTP Engines
  * \section rtp_engine_blah Asterisk RTP Engines
  */
+
+/*! 
+ * \page AstHTTP AMI over HTTP support
+ * The http.c file includes support for manager transactions over
+ * http.
+ * \section ami AMI - The manager Interface
+ * \arg \link Config_ami Configuration file \endlink
+ */
+
+/*! 
+ * \page res_config_sqlite SQLite Resource driver configuration
+ * \arg Implemented in \ref res_config_sqlite.c
+ * \arg Configuration file:
+ * \verbinclude res_config_sqlite.conf
+ * \arg SQL tables:
+ * https://wiki.asterisk.org/wiki/display/AST/SQLite+Tables
+ * \arg See also:
+ * http://www.sqlite.org
+ */
+
+
diff --git a/include/asterisk/endpoints.h b/include/asterisk/endpoints.h
deleted file mode 100644
index 663dd94..0000000
--- a/include/asterisk/endpoints.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_ENDPOINTS_H
-#define _ASTERISK_ENDPOINTS_H
-
-/*! \file
- *
- * \brief Endpoint abstractions.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- *
- * An endpoint is an external device/system that may offer/accept channels
- * to/from Asterisk. While this is a very useful concept for end users, it is
- * surprisingly \a not a core concept within Asterisk iteself.
- *
- * This file defines \ref ast_endpoint as a seperate object, which channel
- * drivers may use to expose their concept of an endpoint. As the channel driver
- * creates channels, it can use ast_endpoint_add_channel() to associate channels
- * to the endpoint. This updates the endpoint appropriately, and forwards all of
- * the channel's events to the endpoint's topic.
- *
- * In order to avoid excessive locking on the endpoint object itself, the
- * mutable state is not accessible via getters. Instead, you can create a
- * snapshot using ast_endpoint_snapshot_create() to get a consistent snapshot of
- * the internal state.
- */
-
-#include "asterisk/json.h"
-
-/*!
- * \brief Valid states for an endpoint.
- * \since 12
- */
-enum ast_endpoint_state {
-	/*! The endpoint state is not known. */
-	AST_ENDPOINT_UNKNOWN,
-	/*! The endpoint is not available. */
-	AST_ENDPOINT_OFFLINE,
-	/*! The endpoint is available. */
-	AST_ENDPOINT_ONLINE,
-};
-
-/*!
- * \brief Returns a string representation of the given endpoint state.
- *
- * \param state Endpoint state.
- * \return String representation of \a state.
- * \return \c "?" if \a state isn't in \ref ast_endpoint_state.
- */
-const char *ast_endpoint_state_to_string(enum ast_endpoint_state state);
-
-/*!
- * \brief Opaque struct representing an endpoint.
- *
- * An endpoint is an external device/system that may offer/accept channels
- * to/from Asterisk.
- *
- * \since 12
- */
-struct ast_endpoint;
-
-/*!
- * \brief Finds the endpoint with the given tech[/resource] id.
- *
- * Endpoints are refcounted, so ao2_cleanup() when you're done.
- *
- * \note The resource portion of an ID is optional. If not provided,
- *       an aggregate endpoint for the entire technology is returned.
- *       These endpoints must not be modified, but can be subscribed
- *       to in order to receive updates for all endpoints of a given
- *       technology.
- *
- * \param id Tech[/resource] id to look for.
- * \return Associated endpoint.
- * \return \c NULL if not found.
- *
- * \since 12
- */
-struct ast_endpoint *ast_endpoint_find_by_id(const char *id);
-
-/*!
- * \brief Create an endpoint struct.
- *
- * The endpoint is created with a state of UNKNOWN and max_channels of -1
- * (unlimited). While \ref ast_endpoint is AO2 managed, you have to
- * shut it down with ast_endpoint_shutdown() to clean up references from
- * subscriptions.
- *
- * \param tech Technology for this endpoint.
- * \param resource Name of this endpoint.
- * \return Newly created endpoint.
- * \return \c NULL on error.
- * \since 12
- */
-struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource);
-
-/*!
- * \brief Shutsdown an \ref ast_endpoint.
- *
- * \param endpoint Endpoint to shut down.
- * \since 12
- */
-void ast_endpoint_shutdown(struct ast_endpoint *endpoint);
-
-/*!
- * \brief Gets the technology of the given endpoint.
- *
- * This is an immutable string describing the channel provider technology
- * (SIP, IAX2, etc.).
- *
- * \param endpoint The endpoint.
- * \return Tec of the endpoint.
- * \return \c NULL if endpoint is \c NULL.
- * \since 12
- */
-const char *ast_endpoint_get_tech(const struct ast_endpoint *endpoint);
-
-/*!
- * \brief Gets the resource name of the given endpoint.
- *
- * This is unique for the endpoint's technology, and immutable.
- *
- * \note If the endpoint being queried is a technology aggregate
- *       endpoint, this will be an empty string.
- *
- * \param endpoint The endpoint.
- * \return Resource name of the endpoint.
- * \return \c NULL if endpoint is \c NULL.
- * \since 12
- */
-const char *ast_endpoint_get_resource(const struct ast_endpoint *endpoint);
-
-/*!
- * \brief Gets the tech/resource id of the given endpoint.
- *
- * This is unique across all endpoints, and immutable.
- *
- * \param endpoint The endpoint.
- * \return Tech/resource id of the endpoint.
- * \return \c NULL if endpoint is \c NULL.
- * \since 12
- */
-const char *ast_endpoint_get_id(const struct ast_endpoint *endpoint);
-
-/*!
- * \brief Updates the state of the given endpoint.
- *
- * \param endpoint Endpoint to modify.
- * \param state New state.
- * \since 12
- */
-void ast_endpoint_set_state(struct ast_endpoint *endpoint,
-	enum ast_endpoint_state state);
-
-/*!
- * \brief Updates the maximum number of channels an endpoint supports.
- *
- * Set to -1 for unlimited channels.
- *
- * \param endpoint Endpoint to modify.
- * \param max_channels Maximum number of concurrent channels this endpoint
- *        supports.
- */
-void ast_endpoint_set_max_channels(struct ast_endpoint *endpoint,
-	int max_channels);
-
-
-/*!
- * \since 12
- * \brief Adds a channel to the given endpoint.
- *
- * This updates the endpoint's statistics, as well as forwarding all of the
- * channel's messages to the endpoint's topic.
- *
- * The channel is automagically removed from the endpoint when it is disposed
- * of.
- *
- * \param endpoint
- * \param chan Channel.
- * \retval 0 on success.
- * \retval Non-zero on error.
- */
-int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
-	struct ast_channel *chan);
-
-
-#endif /* _ASTERISK_ENDPOINTS_H */
diff --git a/include/asterisk/event.h b/include/asterisk/event.h
index 7eea058..90e27b2 100644
--- a/include/asterisk/event.h
+++ b/include/asterisk/event.h
@@ -25,27 +25,33 @@
 /*!
  * \page AstGenericEvents Generic event system
  *
- * Prior to the creation of \ref stasis, the purpose of this API was to provide
- * a generic way to share events between Asterisk modules. Once there was a need
- * to disseminate data whose definition was provided by the producers/consumers,
- * it was no longer possible to use the binary representation in the generic
- * event system.
- *
- * That aside, the generic event system is still useful and used by several
- * modules in Asterisk.
- *  - CEL uses the \ref ast_event representation to pass information to registered
- *    backends.
- *  - The \file res_corosync module publishes \ref ast_event representations of
- *    information to other Asterisk instances in a cluster.
- *  - Security event represent their event types and data using this system.
- *  - Theoretically, any \ref stasis message can use this system to pass
- *    information around in a binary format.
+ * The purpose of this API is to provide a generic way to share events between
+ * Asterisk modules.  Code can generate events, and other code can subscribe to
+ * them.
  *
  * Events have an associated event type, as well as information elements.  The
  * information elements are the meta data that go along with each event.  For
  * example, in the case of message waiting indication, the event type is MWI,
  * and each MWI event contains at least three information elements: the
  * mailbox, the number of new messages, and the number of old messages.
+ *
+ * Subscriptions to events consist of an event type and information elements,
+ * as well.  Subscriptions can be to all events, or a certain subset of events.
+ * If an event type is provided, only events of that type will be sent to this
+ * subscriber.  Furthermore, if information elements are supplied with the
+ * subscription, only events that contain the specified information elements
+ * with specified values will be sent to the subscriber.  For example, when a
+ * SIP phone subscribes to MWI for mailbox 1234, then chan_sip can subscribe
+ * to internal Asterisk MWI events with the MAILBOX information element with
+ * a value of "1234".
+ *
+ * Another key feature of this event system is the ability to cache events.
+ * It is useful for some types of events to be able to remember the last known
+ * value.  These are usually events that indicate some kind of state change.
+ * In the example of MWI, app_voicemail can instruct the event core to cache
+ * these events based on the mailbox.  So, the last known MWI state of each
+ * mailbox will be cached, and other modules can retrieve this information
+ * on demand without having to poll the mailbox directly.
  */
 
 #ifndef AST_EVENT_H
@@ -58,6 +64,258 @@ extern "C" {
 #include "asterisk/event_defs.h"
 
 /*!
+ * \brief Subscriber event callback type
+ *
+ * \param event the event being passed to the subscriber
+ * \param userdata the data provider in the call to ast_event_subscribe()
+ *
+ * \return The event callbacks do not return anything.
+ */
+typedef void (*ast_event_cb_t)(const struct ast_event *event, void *userdata);
+
+/*!
+ * \brief Subscribe to events
+ *
+ * \param event_type The type of events to subscribe to
+ * \param cb The function to be called with events
+ * \param description Description of the subscription.
+ * \param userdata data to be passed to the event callback
+ *
+ * The rest of the arguments to this function specify additional parameters for
+ * the subscription to filter which events are passed to this subscriber.  The
+ * arguments must be in sets of:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return This returns a reference to the subscription for use with
+ *         un-subscribing later.  If there is a failure in creating the
+ *         subscription, NULL will be returned.
+ *
+ * Example usage:
+ *
+ * \code
+ * peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, peer,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, peer->mailbox,
+ *     AST_EVENT_IE_END);
+ * \endcode
+ *
+ * This creates a subscription to AST_EVENT_MWI events that contain an
+ * information element, AST_EVENT_IE_MAILBOX, with the same string value
+ * contained in peer->mailbox.  Also, the event callback will be passed a
+ * pointer to the peer.
+ *
+ * \note A NULL description will cause this function to crash, so watch out!
+ */
+struct ast_event_sub *ast_event_subscribe(enum ast_event_type event_type,
+       ast_event_cb_t cb, const char *description, void *userdata, ...);
+
+/*!
+ * \brief Allocate a subscription, but do not activate it
+ *
+ * \param type the event type to subscribe to
+ * \param cb the function to call when an event matches this subscription
+ * \param userdata data to pass to the provided callback
+ *
+ * This function should be used when you want to dynamically build a
+ * subscription.
+ *
+ * \return the allocated subscription, or NULL on failure
+ * \since 1.6.1
+ */
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+	ast_event_cb_t cb, void *userdata);
+
+/*!
+ * \brief Destroy an allocated subscription
+ *
+ * \param sub the subscription to destroy
+ *
+ * This function should be used when a subscription is allocated with
+ * ast_event_subscribe_new(), but for some reason, you want to destroy it
+ * instead of activating it.  This could be because of an error when
+ * reading in the configuration for the dynamically built subscription.
+ * \since 1.6.1
+ */
+void ast_event_sub_destroy(struct ast_event_sub *sub);
+
+/*!
+ * \brief Append a uint parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \param ie_type the information element type for the parameter
+ * \param uint the value that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, uint32_t uint);
+
+/*!
+ * \brief Append a bitflags parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \param ie_type the information element type for the parameter
+ * \param flags the flags that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.8
+ */
+int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, uint32_t flags);
+
+/*!
+ * \brief Append a string parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \param ie_type the information element type for the parameter
+ * \param str the string that must be present in the event to match this subscription
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, const char *str);
+
+/*!
+ * \brief Append a raw parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \param ie_type the information element type for the parameter
+ * \param data the data that must be present in the event to match this subscription
+ * \param raw_datalen length of data
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, void *data, size_t raw_datalen);
+
+/*!
+ * \brief Append an 'exists' parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+ * \param ie_type the information element type that must be present in the event
+ *      for it to match this subscription.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Activate a dynamically built subscription
+ *
+ * \param sub the subscription to activate that was allocated using
+ *      ast_event_subscribe_new()
+ *
+ * Once a dynamically built subscription has had all of the parameters added
+ * to it, it should be activated using this function.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_sub_activate(struct ast_event_sub *sub);
+
+/*!
+ * \brief Un-subscribe from events
+ *
+ * \param event_sub This is the reference to the subscription returned by
+ *        ast_event_subscribe.
+ *
+ * This function will remove a subscription and free the associated data
+ * structures.
+ *
+ * \return NULL for convenience.
+ * \version 1.6.1 return changed to NULL
+ */
+struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *event_sub);
+
+/*!
+ * \brief Get description for a subscription
+ *
+ * \param sub subscription
+ *
+ * \return string description of the subscription
+ */
+const char *ast_event_subscriber_get_description(struct ast_event_sub *sub);
+
+/*!
+ * \brief Check if subscribers exist
+ *
+ * \param event_type This is the type of event that the caller would like to
+ *        check for subscribers to.
+ *
+ * The rest of the arguments to this function specify additional parameters for
+ * checking for subscriptions to subsets of an event type. The arguments must
+ * in sets of:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return This returns one of the values defined in the ast_event_subscriber_res
+ *         enum which will indicate if subscribers exist that match the given
+ *         criteria.
+ *
+ * Example usage:
+ *
+ * \code
+ * if (ast_event_check_subscriber(AST_EVENT_MWI,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ *     AST_EVENT_IE_END) == AST_EVENT_SUB_NONE) {
+ *       return;
+ * }
+ * \endcode
+ *
+ * This example will check if there are any subscribers to MWI events for the
+ * mailbox defined in the "mailbox" variable.
+ */
+enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type event_type, ...);
+
+/*!
+ * \brief Report current subscriptions to a subscription subscriber
+ *
+ * \arg sub the subscription subscriber
+ *
+ * \return nothing
+ *
+ * This reports all of the current subscribers to a subscriber of
+ * subscribers to a specific event type.  (Try saying that a few times fast).
+ *
+ * The idea here is that it is sometimes very useful for a module to know when
+ * someone subscribes to events.  However, when they first subscribe, this
+ * provides that module the ability to request the event core report to them
+ * all of the subscriptions to that event type that already exist.
+ */
+void ast_event_report_subs(const struct ast_event_sub *sub);
+
+/*!
+ * \brief Dump the event cache for the subscriber
+ * \since 1.6.1
+ */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub);
+
+/*!
  * \brief Create a new event
  *
  * \param event_type The type of event to create
@@ -70,7 +328,8 @@ extern "C" {
  * and must end with AST_EVENT_IE_END.
  *
  * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
- * by a valid IE payload type.  A payload must also be specified
+ * by a valid IE payload type.  The payload type, EXISTS, should not be used here
+ * because it makes no sense to do so.  So, a payload must also be specified
  * after the IE payload type.
  *
  * \note The EID IE will be appended automatically when this function is used
@@ -103,10 +362,86 @@ struct ast_event *ast_event_new(enum ast_event_type event_type, ...);
  *
  * \return Nothing
  *
+ * \note Events that have been queued should *not* be destroyed by the code that
+ *       created the event.  It will be automatically destroyed after being
+ *       dispatched to the appropriate subscribers.
  */
 void ast_event_destroy(struct ast_event *event);
 
 /*!
+ * \brief Queue an event
+ *
+ * \param event the event to be queued
+ *
+ * \retval zero success
+ * \retval non-zero failure.  Note that the caller of this function is
+ *         responsible for destroying the event in the case of a failure.
+ *
+ * This function queues an event to be dispatched to all of the appropriate
+ * subscribers.  This function will not block while the event is being
+ * dispatched because the event is queued up for a dispatching thread 
+ * to handle.
+ */
+int ast_event_queue(struct ast_event *event);
+
+/*!
+ * \brief Queue and cache an event
+ *
+ * \param event the event to be queued and cached
+ *
+ * \details
+ * The purpose of caching events is so that the core can retain the last known
+ * information for events that represent some sort of state.  That way, when
+ * code needs to find out the current state, it can query the cache.
+ *
+ * The event API already knows which events can be cached and how to cache them.
+ *
+ * \retval 0 success
+ * \retval non-zero failure.
+ */
+int ast_event_queue_and_cache(struct ast_event *event);
+
+/*!
+ * \brief Retrieve an event from the cache
+ *
+ * \param ast_event_type The type of event to retrieve from the cache
+ *
+ * The rest of the arguments to this function specify information elements to
+ * match for retrieving events from the cache.  They are specified in the form:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return A reference to an event retrieved from the cache.  If no event was
+ *         found that matches the specified criteria, then NULL will be returned.
+ *
+ * \note If more than one event in the cache matches the specified criteria, only
+ *       one will be returned, and it is undefined which one it will be.
+ *
+ * \note The caller of this function *must* call ast_event_destroy() on the
+ *       returned event after it is done using it.
+ *
+ * Example Usage:
+ *
+ * \code
+ * event = ast_event_get_cached(AST_EVENT_MWI,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ *     AST_EVENT_IE_END);
+ * \endcode
+ *
+ * This example will check for an MWI event in the cache that matches the
+ * specified mailbox.  This would be the way to find out the last known state
+ * of a mailbox without having to poll the mailbox directly.
+ */
+struct ast_event *ast_event_get_cached(enum ast_event_type, ...);
+
+/*!
  * \brief Append an information element that has a string payload
  *
  * \param event the event that the IE will be appended to
@@ -202,6 +537,18 @@ int ast_event_append_eid(struct ast_event **event);
 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type);
 
 /*!
+ * \brief Get the value of an information element that has a bitflags payload
+ *
+ * \param event The event to get the IE from
+ * \param ie_type the type of information element to retrieve
+ *
+ * \return This returns the payload of the information element with the given type.
+ *         However, an IE with a payload of 0, and the case where no IE is found
+ *         yield the same return value.
+ */
+uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+/*!
  * \brief Get the value of an information element that has a string payload
  *
  * \param event The event to get the IE from
@@ -213,6 +560,18 @@ uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_
 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type);
 
 /*!
+ * \brief Get the hash for the string payload of an IE
+ *
+ * \param event The event to get the IE from
+ * \param ie_type the type of information element to retrieve the hash for
+ *
+ * \return This function returns the hash value as calculated by ast_str_hash()
+ *         for the string payload.  This is stored in the event to avoid
+ *         unnecessary string comparisons.
+ */
+uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+/*!
  * \brief Get the value of an information element that has a raw payload
  *
  * \param event The event to get the IE from
@@ -235,16 +594,6 @@ const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_i
 uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type);
 
 /*!
- * \brief Get the string representation of the type of the given event
- *
- * \arg event the event to get the type of
- *
- * \return the string representation of the event type of the provided event
- * \since 1.6.1
- */
-const char *ast_event_get_type_name(const struct ast_event *event);
-
-/*!
  * \brief Get the string representation of an information element type
  *
  * \param ie_type the information element type to get the string representation of
@@ -275,6 +624,28 @@ enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
 enum ast_event_type ast_event_get_type(const struct ast_event *event);
 
 /*!
+ * \brief Get the string representation of the type of the given event
+ *
+ * \arg event the event to get the type of
+ *
+ * \return the string representation of the event type of the provided event
+ * \since 1.6.1
+ */
+const char *ast_event_get_type_name(const struct ast_event *event);
+
+/*!
+ * \brief Convert a string into an event type
+ *
+ * \param str the string to convert
+ * \param event_type an output parameter for the event type
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ * \since 1.6.1
+ */
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type);
+
+/*!
  * \brief Convert a string to an IE type
  *
  * \param str the string to convert
@@ -337,6 +708,15 @@ enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator
 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator);
 
 /*!
+ * \brief Get the value of the current IE in the iterator as a bitflags payload
+ *
+ * \param iterator The iterator instance
+ *
+ * \return This returns the payload of the information element as bitflags.
+ */
+uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator);
+
+/*!
  * \brief Get the value of the current IE in the iterator as a string payload
  *
  * \param iterator The iterator instance
@@ -346,6 +726,24 @@ uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator);
 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator);
 
 /*!
+ * \brief Get the value of the current IE in the iterator instance that has a raw payload
+ *
+ * \param iterator The iterator instance
+ *
+ * \return This returns the payload of the information element as type raw.
+ */
+void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator);
+
+/*!
+ * \brief Get the length of the raw payload for the current IE for an iterator
+ *
+ * \param iterator The IE iterator
+ *
+ * \return The payload length of the current IE
+ */
+uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator);
+
+/*!
  * \brief Get the minimum length of an ast_event.
  *
  * \return minimum amount of memory that will be consumed by any ast_event.
diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h
index 80a8d7d..10c76d0 100644
--- a/include/asterisk/event_defs.h
+++ b/include/asterisk/event_defs.h
@@ -25,12 +25,14 @@
 #ifndef AST_EVENT_DEFS_H
 #define AST_EVENT_DEFS_H
 
+/*! \brief Event types
+ * \note These values can *never* change. */
 enum ast_event_type {
 	/*! Reserved to provide the ability to subscribe to all events.  A specific
 	 *  event should never have a payload of 0. */
 	AST_EVENT_ALL                 = 0x00,
 	/*! This event type is reserved for use by third-party modules to create
-	 *  custom events without having to modify this file.
+	 *  custom events without having to modify this file. 
 	 *  \note There are no "custom" IE types, because IEs only have to be
 	 *  unique to the event itself, not necessarily across all events. */
 	AST_EVENT_CUSTOM              = 0x01,
@@ -67,32 +69,32 @@ enum ast_event_ie_type {
 	/*! Used to terminate the arguments to event functions */
 	AST_EVENT_IE_END                 = -1,
 
-	/*!
+	/*! 
 	 * \brief Number of new messages
-	 * Used by: AST_EVENT_MWI
+	 * Used by: AST_EVENT_MWI 
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_NEWMSGS             = 0x0001,
-	/*!
+	/*! 
 	 * \brief Number of
-	 * Used by: AST_EVENT_MWI
+	 * Used by: AST_EVENT_MWI 
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_OLDMSGS             = 0x0002,
-	/*!
+	/*! 
 	 * \brief Mailbox name \verbatim (mailbox[@context]) \endverbatim
 	 * Used by: AST_EVENT_MWI 
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_MAILBOX             = 0x0003,
-	/*!
+	/*! 
 	 * \brief Unique ID
 	 * Used by: AST_EVENT_SUB, AST_EVENT_UNSUB
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_UNIQUEID            = 0x0004,
-	/*!
-	 * \brief Event type
+	/*! 
+	 * \brief Event type 
 	 * Used by: AST_EVENT_SUB, AST_EVENT_UNSUB
 	 * Payload type: UINT
 	 */
@@ -117,139 +119,139 @@ enum ast_event_ie_type {
 	 * this IE is a part of.
 	 */
 	 AST_EVENT_IE_STATE              = 0x0008,
-	/*!
-	 * \brief Context IE
-	 * Used by AST_EVENT_MWI
-	 * Payload type: str
-	 */
+	 /*!
+	  * \brief Context IE
+	  * Used by AST_EVENT_MWI
+	  * Payload type: str
+	  */
 	 AST_EVENT_IE_CONTEXT            = 0x0009,
-	/*!
+	/*! 
 	 * \brief Channel Event Type
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_CEL_EVENT_TYPE      = 0x000a,
-	/*!
+	/*! 
 	 * \brief Channel Event Time (seconds)
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_CEL_EVENT_TIME      = 0x000b,
-	/*!
+	/*! 
 	 * \brief Channel Event Time (micro-seconds)
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_CEL_EVENT_TIME_USEC = 0x000c,
-	/*!
+	/*! 
 	 * \brief Channel Event User Event Name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_USEREVENT_NAME  = 0x000d,
-	/*!
+	/*! 
 	 * \brief Channel Event CID name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CIDNAME         = 0x000e,
-	/*!
+	/*! 
 	 * \brief Channel Event CID num
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CIDNUM          = 0x000f,
-	/*!
+	/*! 
 	 * \brief Channel Event extension name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_EXTEN           = 0x0010,
-	/*!
+	/*! 
 	 * \brief Channel Event context name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CONTEXT         = 0x0011,
-	/*!
+	/*! 
 	 * \brief Channel Event channel name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CHANNAME        = 0x0012,
-	/*!
+	/*! 
 	 * \brief Channel Event app name
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_APPNAME         = 0x0013,
-	/*!
+	/*! 
 	 * \brief Channel Event app args/data
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_APPDATA         = 0x0014,
-	/*!
+	/*! 
 	 * \brief Channel Event AMA flags
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: UINT
 	 */
 	AST_EVENT_IE_CEL_AMAFLAGS        = 0x0015,
-	/*!
+	/*! 
 	 * \brief Channel Event AccountCode
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_ACCTCODE        = 0x0016,
-	/*!
+	/*! 
 	 * \brief Channel Event UniqueID
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_UNIQUEID        = 0x0017,
-	/*!
+	/*! 
 	 * \brief Channel Event Userfield
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_USERFIELD       = 0x0018,
-	/*!
+	/*! 
 	 * \brief Channel Event CID ANI field
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CIDANI          = 0x0019,
-	/*!
+	/*! 
 	 * \brief Channel Event CID RDNIS field
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CIDRDNIS        = 0x001a,
-	/*!
+	/*! 
 	 * \brief Channel Event CID dnid
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_CIDDNID         = 0x001b,
-	/*!
+	/*! 
 	 * \brief Channel Event Peer -- for Things involving multiple channels, like BRIDGE
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_PEER            = 0x001c,
-	/*!
+	/*! 
 	 * \brief Channel Event LinkedID
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_LINKEDID        = 0x001d,
-	/*!
+	/*! 
 	 * \brief Channel Event peeraccount
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
 	 */
 	AST_EVENT_IE_CEL_PEERACCT        = 0x001e,
-	/*!
+	/*! 
 	 * \brief Channel Event extra data
 	 * Used by: AST_EVENT_CEL
 	 * Payload type: STR
@@ -337,6 +339,7 @@ enum ast_event_subscriber_res {
 
 struct ast_event;
 struct ast_event_ie;
+struct ast_event_sub;
 struct ast_event_iterator;
 
 /*!
diff --git a/include/asterisk/features.h b/include/asterisk/features.h
index b63124c..4f55613 100644
--- a/include/asterisk/features.h
+++ b/include/asterisk/features.h
@@ -17,7 +17,7 @@
  */
 
 /*! \file
- * \brief Call Parking and Pickup API
+ * \brief Call Parking and Pickup API 
  * Includes code and algorithms from the Zapata library.
  */
 
@@ -26,7 +26,30 @@
 
 #include "asterisk/pbx.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/bridge.h"
+
+#define FEATURE_MAX_LEN		11
+#define FEATURE_APP_LEN		64
+#define FEATURE_APP_ARGS_LEN	256
+#define FEATURE_SNAME_LEN	32
+#define FEATURE_EXTEN_LEN	32
+#define FEATURE_MOH_LEN		80  /* same as MAX_MUSICCLASS from channel.h */
+
+#define DEFAULT_PARKINGLOT "default"	/*!< Default parking lot */
+
+#define AST_FEATURE_RETURN_HANGUP           -1
+#define AST_FEATURE_RETURN_SUCCESSBREAK     0
+#define AST_FEATURE_RETURN_PBX_KEEPALIVE    AST_PBX_KEEPALIVE
+#define AST_FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
+#define AST_FEATURE_RETURN_PASSDIGITS       21
+#define AST_FEATURE_RETURN_STOREDIGITS      22
+#define AST_FEATURE_RETURN_SUCCESS          23
+#define AST_FEATURE_RETURN_KEEPTRYING       24
+#define AST_FEATURE_RETURN_PARKFAILED       25
+
+#define FEATURE_SENSE_CHAN	(1 << 0)
+#define FEATURE_SENSE_PEER	(1 << 1)
+
+typedef int (*ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data);
 
 /*! \brief main call feature structure */
 
@@ -39,61 +62,200 @@ enum {
 	AST_FEATURE_FLAG_BYBOTH	 =   (3 << 3),
 };
 
+struct ast_call_feature {
+	int feature_mask;
+	char *fname;
+	char sname[FEATURE_SNAME_LEN];
+	char exten[FEATURE_MAX_LEN];
+	char default_exten[FEATURE_MAX_LEN];
+	ast_feature_operation operation;
+	unsigned int flags;
+	char app[FEATURE_APP_LEN];		
+	char app_args[FEATURE_APP_ARGS_LEN];
+	char moh_class[FEATURE_MOH_LEN];
+	AST_LIST_ENTRY(ast_call_feature) feature_entry;
+};
+
+/*!
+ * \brief Park a call and read back parked location
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param timeout is a timeout in milliseconds
+ * \param park_exten Parking lot access extension (Not used)
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Park the park_me channel, and read back the parked location
+ * to the parker channel.  If the call is not picked up within a
+ * specified period of time, then the call will return to the
+ * last step that it was in (in terms of exten, priority and
+ * context).
+ *
+ * \note Use ast_park_call_exten() instead.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout);
+
 /*!
- * \brief Bridge a call, optionally allowing redirection
+ * \brief Park a call and read back parked location
+ * \since 1.8.9
  *
- * \note The function caller is assumed to have already done the
- * COLP exchange for the initial bridging of the two channels if
- * it was desired.
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot access extension
+ * \param park_context Parking lot context
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Park the park_me channel, and read back the parked location
+ * to the parker channel.  If the call is not picked up within a
+ * specified period of time, then the call will return to the
+ * last step that it was in (in terms of exten, priority and
+ * context).
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout);
+
+/*!
+ * \brief Park a call via a masqueraded channel
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Masquerade the park_me channel into a new, empty channel which is then parked.
+ *
+ * \note Use ast_masq_park_call_exten() instead.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
  */
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config);
+int ast_masq_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout);
 
 /*!
- * \brief Bridge a call, and add additional flags to the bridge
+ * \brief Park a call via a masqueraded channel
+ * \since 1.8.9
  *
- * This does the same thing as \ref ast_bridge_call, except that once the bridge
- * is created, the provided flags are set on the bridge. The provided flags are
- * added to the bridge's flags; they will not clear any flags already set.
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot access extension
+ * \param park_context Parking lot context
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
  *
- * \param chan The calling channel
- * \param peer The called channel
- * \param config Bridge configuration for the channels
- * \param flags Additional flags to set on the created bridge
+ * \details
+ * Masquerade the park_me channel into a new, empty channel which is then parked.
  *
- * \note The function caller is assumed to have already done the
- * COLP exchange for the initial bridging of the two channels if
- * it was desired.
+ * \retval 0 on success.
+ * \retval -1 on failure.
  */
-int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags);
+int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout);
+
+/*! 
+ * \brief Determine if parking extension exists in a given context
+ * \retval 0 if extension does not exist
+ * \retval 1 if extension does exist
+*/
+int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context);
+
+/*! \brief Determine system call pickup extension */
+const char *ast_pickup_ext(void);
 
 /*!
- * \brief Add an arbitrary channel to a bridge
- * \since 12.0.0
- *
- * The channel that is being added to the bridge can be in any state: unbridged,
- * bridged, answered, unanswered, etc. The channel will be added asynchronously,
- * meaning that when this function returns once the channel has been added to
- * the bridge, not once the channel has been removed from the bridge.
- *
- * In addition, a tone can optionally be played to the channel once the
- * channel is placed into the bridge.
- *
- * \note When this function returns, there is no guarantee that the channel that
- * was passed in is valid any longer. Do not attempt to operate on the channel
- * after this function returns.
- *
- * \param bridge Bridge to which the channel should be added
- * \param chan The channel to add to the bridge
- * \param features Features for this channel in the bridge
- * \param play_tone Indicates if a tone should be played to the channel
- * \param xfersound Sound that should be used to indicate transfer with play_tone
- * \retval 0 Success
- * \retval -1 Failure
+ * \brief Simulate a DTMF end on a broken bridge channel.
+ *
+ * \param chan Channel sending DTMF that has not ended.
+ * \param digit DTMF digit to stop.
+ * \param start DTMF digit start time.
+ * \param why Reason bridge broken.
+ *
+ * \return Nothing
  */
-int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
-		struct ast_bridge_features *features, int play_tone, const char *xfersound);
+void ast_bridge_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why);
+
+/*! \brief Bridge a call, optionally allowing redirection */
+int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
+
+/*!
+ * \brief Test if a channel can be picked up.
+ *
+ * \param chan Channel to test if can be picked up.
+ *
+ * \note This function assumes that chan is locked.
+ *
+ * \return TRUE if channel can be picked up.
+ */
+int ast_can_pickup(struct ast_channel *chan);
+
+/*!
+ * \brief Find a pickup channel target by group.
+ *
+ * \param chan channel that initiated pickup.
+ *
+ * \retval target on success.  The returned channel is locked and reffed.
+ * \retval NULL on error.
+ */
+struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan);
+
+/*! \brief Pickup a call */
+int ast_pickup_call(struct ast_channel *chan);
+
+/*!
+ * \brief Pickup a call target.
+ *
+ * \param chan channel that initiated pickup.
+ * \param target channel to be picked up.
+ *
+ * \note This function assumes that target is locked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target);
+
+/*! 
+ * \brief register new feature into feature_set 
+ * \param feature an ast_call_feature object which contains a keysequence
+ * and a callback function which is called when this keysequence is pressed
+ * during a call. 
+*/
+void ast_register_feature(struct ast_call_feature *feature);
+
+/*! 
+ * \brief unregister feature from feature_set
+ * \param feature the ast_call_feature object which was registered before
+*/
+void ast_unregister_feature(struct ast_call_feature *feature);
+
+/*! 
+ * \brief detect a feature before bridging 
+ * \param chan
+ * \param features an ast_flags ptr
+ * \param code ptr of input code
+ * \param feature
+ * \retval ast_call_feature ptr to be set if found 
+*/
+int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature);
+
+/*! 
+ * \brief look for a call feature entry by its sname
+ * \param name a string ptr, should match "automon", "blindxfer", "atxfer", etc. 
+*/
+struct ast_call_feature *ast_find_call_feature(const char *name);
 
+void ast_rdlock_call_features(void);
+void ast_unlock_call_features(void);
 
+/*! \brief Reload call features from features.conf */
+int ast_features_reload(void);
 
 /*!
  * \brief parse L option and read associated channel variables to set warning, warning frequency, and timelimit
diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h
deleted file mode 100644
index b15759b..0000000
--- a/include/asterisk/features_config.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* Asterisk -- An open source telephony toolkit.
-*
-* Copyright (C) 2013, Digium, Inc.
-*
-* Mark Michelson <mmichelson at digium.com>
-*
-* See http://www.asterisk.org for more information about
-* the Asterisk project. Please do not directly contact
-* any of the maintainers of this project for assistance;
-* the project provides a web site, mailing lists and IRC
-* channels for your use.
-*
-* This program is free software, distributed under the terms of
-* the GNU General Public License Version 2. See the LICENSE file
-* at the top of the source tree.
-*/
-
-#ifndef _FEATURES_CONFIG_H
-#define _FEATURES_CONFIG_H
-
-#include "asterisk/stringfields.h"
-
-struct ast_channel;
-
-/*!
- * \brief General features configuration items
- */
-struct ast_features_general_config {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Sound played when automon or automixmon features are used */
-		AST_STRING_FIELD(courtesytone);
-		/*! Sound played when automon or automixmon features fail when used */
-		AST_STRING_FIELD(recordingfailsound);
-	);
-	/*! Milliseconds allowed between digit presses when entering feature code */
-	unsigned int featuredigittimeout;
-};
-
-/*!
- * \brief Get the general configuration options for a channel
- *
- * \note The channel should be locked before calling this function.
- * \note The returned value has its reference count incremented.
- *
- * If no channel is provided, then the global features configuration is returned.
- *
- * \param chan The channel to get configuration options for
- * \retval NULL Failed to get configuration
- * \retval non-NULL The general features configuration
- */
-struct ast_features_general_config *ast_get_chan_features_general_config(struct ast_channel *chan);
-
-/*!
- * \brief Feature configuration relating to transfers
- */
-struct ast_features_xfer_config {
-	AST_DECLARE_STRING_FIELDS (
-		/*! Sound to play when transfer succeeds */
-		AST_STRING_FIELD(xfersound);
-		/*! Sound to play when transfer fails */
-		AST_STRING_FIELD(xferfailsound);
-		/*! DTMF sequence used to abort an attempted atxfer */
-		AST_STRING_FIELD(atxferabort);
-		/*! DTMF sequence used to complete an attempted atxfer */
-		AST_STRING_FIELD(atxfercomplete);
-		/*! DTMF sequence used to turn an attempted atxfer into a three-way call */
-		AST_STRING_FIELD(atxferthreeway);
-		/*! DTMF sequence used to swap which party the transferer is talking to */
-		AST_STRING_FIELD(atxferswap);
-		/*! Sound played when an invalid extension is dialed, and the transferer should retry. */
-		AST_STRING_FIELD(transferretrysound);
-		/*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */
-		AST_STRING_FIELD(transferinvalidsound);
-	);
-	/*! Seconds allowed between digit presses when dialing transfer destination */
-	unsigned int transferdigittimeout;
-	/*! Seconds to wait for the transfer target to answer a transferred call */
-	unsigned int atxfernoanswertimeout;
-	/*! Seconds to wait before attempting to re-dial the transfer target */
-	unsigned int atxferloopdelay;
-	/*! Number of times to re-attempt dialing the transfer target */
-	unsigned int atxfercallbackretries;
-	/*! Determines if the call is dropped on attended transfer failure */
-	unsigned int atxferdropcall;
-	/*! Number of dial attempts allowed for blind/attended transfers */
-	unsigned int transferdialattempts;
-};
-
-/*!
- * \brief Get the transfer configuration options for a channel
- *
- * \note The channel should be locked before calling this function.
- * \note The returned value has its reference count incremented.
- *
- * If no channel is provided, then the global transfer configuration is returned.
- *
- * \param chan The channel to get configuration options for
- * \retval NULL Failed to get configuration
- * \retval non-NULL The transfer features configuration
- */
-struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan);
-
-/*!
- * \brief Configuration relating to call pickup
- */
-struct ast_features_pickup_config {
-	AST_DECLARE_STRING_FIELDS (
-		/*! Digit sequence to press to pick up a ringing call */
-		AST_STRING_FIELD(pickupexten);
-		/*! Sound to play to picker when pickup succeeds */
-		AST_STRING_FIELD(pickupsound);
-		/*! Sound to play to picker when pickup fails */
-		AST_STRING_FIELD(pickupfailsound);
-	);
-};
-
-/*!
- * \brief Get the pickup configuration options for a channel
- *
- * \note The channel should be locked before calling this function.
- * \note The returned value has its reference count incremented.
- *
- * If no channel is provided, then the global pickup configuration is returned.
- *
- * \param chan The channel to get configuration options for
- * \retval NULL Failed to get configuration
- * \retval non-NULL The pickup features configuration
- */
-struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan);
-
-/*!
- * \brief Configuration for the builtin features
- */
-struct ast_featuremap_config {
-	AST_DECLARE_STRING_FIELDS (
-		/*! Blind transfer DTMF code */
-		AST_STRING_FIELD(blindxfer);
-		/*! Disconnect DTMF code */
-		AST_STRING_FIELD(disconnect);
-		/*! Automon DTMF code */
-		AST_STRING_FIELD(automon);
-		/*! Attended Transfer DTMF code */
-		AST_STRING_FIELD(atxfer);
-		/*! One-touch parking DTMF code */
-		AST_STRING_FIELD(parkcall);
-		/*! Automixmon DTMF code */
-		AST_STRING_FIELD(automixmon);
-	);
-};
-
-/*!
- * \brief Get the featuremap configuration options for a channel
- *
- * \note The channel should be locked before calling this function.
- * \note The returned value has its reference count incremented.
- *
- * If no channel is provided, then the global featuremap configuration is returned.
- *
- * \param chan The channel to get configuration options for
- * \retval NULL Failed to get configuration
- * \retval non-NULL The pickup features configuration
- */
-struct ast_featuremap_config *ast_get_chan_featuremap_config(struct ast_channel *chan);
-
-/*!
- * \brief Get the DTMF code for a builtin feature
- *
- * \note The channel should be locked before calling this function
- *
- * If no channel is provided, then the global setting for the option is returned.
- *
- * \param chan The channel to get the option from
- * \param feature The short name of the feature (as it appears in features.conf)
- * \param[out] buf The buffer to write the DTMF value into
- * \param size The size of the buffer in bytes
- * \retval 0 Success
- * \retval non-zero Unrecognized builtin feature name
- */
-int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len);
-
-/*!
- * \brief Get the DTMF code for a call feature
- *
- * \note The channel should be locked before calling this function
- *
- * If no channel is provided, then the global setting for the option is returned.
- *
- * This function is like \ref ast_get_builtin_feature except that it will
- * also check the applicationmap in addition to the builtin features.
- *
- * \param chan The channel to get the option from
- * \param feature The short name of the feature
- * \param[out] buf The buffer to write the DTMF value into
- * \param size The size of the buffer in bytes
- * \retval 0 Success
- * \retval non-zero Unrecognized feature name
- */
-int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len);
-
-#define AST_FEATURE_MAX_LEN 11
-
-/*!
- * \brief An applicationmap configuration item
- */
-struct ast_applicationmap_item {
-	AST_DECLARE_STRING_FIELDS (
-		/* Name of the item */
-		AST_STRING_FIELD(name);
-		/* Name Dialplan application that is invoked by the feature */
-		AST_STRING_FIELD(app);
-		/* Data to pass to the application */
-		AST_STRING_FIELD(app_data);
-		/* Music-on-hold class to play to party on which feature is not activated */
-		AST_STRING_FIELD(moh_class);
-	);
-	/* DTMF key sequence used to activate the feature */
-	char dtmf[AST_FEATURE_MAX_LEN];
-	/* If true, activate on party that input the sequence, otherwise activate on the other party */
-	unsigned int activate_on_self;
-};
-
-/*!
- * \brief Get the applicationmap for a given channel.
- *
- * \note The channel should be locked before calling this function.
- *
- * This uses the value of the DYNAMIC_FEATURES channel variable to build a
- * custom applicationmap for this channel. The returned container has
- * applicationmap_items inside.
- *
- * \param chan The channel for which applicationmap is being retrieved.
- * \retval NULL An error occurred or the channel has no dynamic features.
- * \retval non-NULL A container of applicationmap_items pertaining to the channel.
- */
-struct ao2_container *ast_get_chan_applicationmap(struct ast_channel *chan);
-
-void ast_features_config_shutdown(void);
-
-int ast_features_config_reload(void);
-
-int ast_features_config_init(void);
-
-#endif /* _FEATURES_CONFIG_H */
diff --git a/include/asterisk/file.h b/include/asterisk/file.h
index c71866e..ec2a38e 100644
--- a/include/asterisk/file.h
+++ b/include/asterisk/file.h
@@ -64,8 +64,8 @@ enum ast_waitstream_fr_cb_values {
  */
 typedef void (ast_waitstream_fr_cb)(struct ast_channel *chan, long ms, enum ast_waitstream_fr_cb_values val);
 
-/*!
- * \brief Streams a file
+/*! 
+ * \brief Streams a file 
  * \param c channel to stream the file to
  * \param filename the name of the file you wish to stream, minus the extension
  * \param preflang the preferred language you wish to have the file streamed to you in
@@ -86,12 +86,12 @@ int ast_streamfile(struct ast_channel *c, const char *filename, const char *pref
  */
 int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits);
 
-/*!
- * \brief Stops a stream
+/*! 
+ * \brief Stops a stream 
  *
  * \param c The channel you wish to stop playback on
  *
- * Stop playback of a stream
+ * Stop playback of a stream 
  *
  * \retval 0 always
  *
@@ -137,47 +137,46 @@ int ast_filedelete(const char *filename, const char *fmt);
  */
 int ast_filecopy(const char *oldname, const char *newname, const char *fmt);
 
-/*!
+/*! 
  * \brief Waits for a stream to stop or digit to be pressed
  * \param c channel to waitstream on
  * \param breakon string of DTMF digits to break upon
  * Begins playback of a stream...
- * Wait for a stream to stop or for any one of a given digit to arrive,
+ * Wait for a stream to stop or for any one of a given digit to arrive,  
  * \retval 0 if the stream finishes
- * \retval the character if it was interrupted by the channel.
- * \retval -1 on error
+ * \retval the character if it was interrupted,
+ * \retval -1 on error 
  */
 int ast_waitstream(struct ast_channel *c, const char *breakon);
 
-/*!
- * \brief Waits for a stream to stop or digit matching a valid one digit exten to be pressed
+/*! 
+ * \brief Waits for a stream to stop or digit matching a valid one digit exten to be pressed 
  * \param c channel to waitstream on
  * \param context string of context to match digits to break upon
  * Begins playback of a stream...
- * Wait for a stream to stop or for any one of a valid extension digit to arrive,
+ * Wait for a stream to stop or for any one of a valid extension digit to arrive,  
  * \retval 0 if the stream finishes.
  * \retval the character if it was interrupted.
  * \retval -1 on error.
  */
 int ast_waitstream_exten(struct ast_channel *c, const char *context);
 
-/*!
- * \brief Same as waitstream but allows stream to be forwarded or rewound
+/*! 
+ * \brief Same as waitstream but allows stream to be forwarded or rewound 
  * \param c channel to waitstream on
  * \param breakon string of DTMF digits to break upon
  * \param forward DTMF digit to fast forward upon
  * \param rewind DTMF digit to rewind upon
  * \param ms How many miliseconds to skip forward/back
  * Begins playback of a stream...
- * Wait for a stream to stop or for any one of a given digit to arrive,
+ * Wait for a stream to stop or for any one of a given digit to arrive,  
  * \retval 0 if the stream finishes.
- * \retval the character if it was interrupted,
- * \retval the value of the control frame if it was interrupted by some other party,
+ * \retval the character if it was interrupted.
  * \retval -1 on error.
  */
 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms);
 
-/*!
+/*! 
  * \brief Same as waitstream_fr but allows a callback to be alerted when a user
  * fastforwards or rewinds the file.
  * \param c channel to waitstream on
@@ -185,12 +184,11 @@ int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *fo
  * \param forward DTMF digit to fast forward upon
  * \param rewind DTMF digit to rewind upon
  * \param ms How many milliseconds to skip forward/back
- * \param cb to call when rewind or fastfoward occurs.
+ * \param cb to call when rewind or fastfoward occurs. 
  * Begins playback of a stream...
- * Wait for a stream to stop or for any one of a given digit to arrive,
+ * Wait for a stream to stop or for any one of a given digit to arrive,  
  * \retval 0 if the stream finishes.
- * \retval the character if it was interrupted,
- * \retval the value of the control frame if it was interrupted by some other party,
+ * \retval the character if it was interrupted.
  * \retval -1 on error.
  */
 int ast_waitstream_fr_w_cb(struct ast_channel *c,
@@ -350,13 +348,6 @@ int ast_stream_rewind(struct ast_filestream *fs, off_t ms);
  */
 off_t ast_tellstream(struct ast_filestream *fs);
 
-/*!
- * \brief Return the sample rate of the stream's format
- * \param fs fs to act on
- * \return sample rate in Hz
- */
-int ast_ratestream(struct ast_filestream *fs);
-
 /*! 
  * \brief Read a frame from a filestream 
  * \param s ast_filestream to act on
@@ -383,17 +374,6 @@ int ast_file_init(void);
  */
 char *ast_format_str_reduce(char *fmts);
 
-/*!
- * \brief Get the ast_format associated with the given file extension
- * \since 12
- *
- * \param file_ext The file extension for which to find the format
- *
- * \retval NULL if not found
- * \retval A pointer to the ast_format associated with this file extension
- */
-struct ast_format *ast_get_format_for_file_ext(const char *file_ext);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/format.h b/include/asterisk/format.h
index 32f9f2b..61ddf90 100644
--- a/include/asterisk/format.h
+++ b/include/asterisk/format.h
@@ -1,9 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2014, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
  *
- * Joshua Colp <jcolp at digium.com>
+ * David Vossel <dvossel at digium.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -18,371 +18,457 @@
 
 /*!
  * \file
- * \brief Media Format API
+ * \brief Format API
  *
- * \author Joshua Colp <jcolp at digium.com>
+ * \author David Vossel <dvossel at digium.com>
  */
 
-#include "asterisk/codec.h"
-
 #ifndef _AST_FORMAT_H_
 #define _AST_FORMAT_H_
 
-struct ast_format;
+#include "asterisk/astobj2.h"
+#include "asterisk/silk.h"
+#include "asterisk/celt.h"
+#define AST_FORMAT_ATTR_SIZE 64
+#define AST_FORMAT_INC 100000
+
+/*! This is the value that ends a var list of format attribute
+ * key value pairs. */
+#define AST_FORMAT_ATTR_END -1
+
+/* \brief Format Categories*/
+enum ast_format_type {
+	AST_FORMAT_TYPE_AUDIO = 1 * AST_FORMAT_INC,
+	AST_FORMAT_TYPE_VIDEO = 2 * AST_FORMAT_INC,
+	AST_FORMAT_TYPE_IMAGE = 3 * AST_FORMAT_INC,
+	AST_FORMAT_TYPE_TEXT  = 4 * AST_FORMAT_INC,
+};
+
+enum ast_format_id {
+	/*! G.723.1 compression */
+	AST_FORMAT_G723_1           = 1 + AST_FORMAT_TYPE_AUDIO,
+	/*! GSM compression */
+	AST_FORMAT_GSM              = 2 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw mu-law data (G.711) */
+	AST_FORMAT_ULAW             = 3 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw A-law data (G.711) */
+	AST_FORMAT_ALAW             = 4 + AST_FORMAT_TYPE_AUDIO,
+	/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
+	AST_FORMAT_G726_AAL2        = 5 + AST_FORMAT_TYPE_AUDIO,
+	/*! ADPCM (IMA) */
+	AST_FORMAT_ADPCM            = 6 + AST_FORMAT_TYPE_AUDIO,
+	/*! LPC10, 180 samples/frame */
+	AST_FORMAT_LPC10            = 7 + AST_FORMAT_TYPE_AUDIO,
+	/*! G.729A audio */
+	AST_FORMAT_G729A            = 8 + AST_FORMAT_TYPE_AUDIO,
+	/*! SpeeX Free Compression */
+	AST_FORMAT_SPEEX            = 9 + AST_FORMAT_TYPE_AUDIO,
+	/*! iLBC Free Compression */
+	AST_FORMAT_ILBC             = 10 + AST_FORMAT_TYPE_AUDIO,
+	/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
+	AST_FORMAT_G726             = 11 + AST_FORMAT_TYPE_AUDIO,
+	/*! G.722 */
+	AST_FORMAT_G722             = 12 + AST_FORMAT_TYPE_AUDIO,
+	/*! G.722.1 (also known as Siren7, 32kbps assumed) */
+	AST_FORMAT_SIREN7           = 13 + AST_FORMAT_TYPE_AUDIO,
+	/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+	AST_FORMAT_SIREN14          = 14 + AST_FORMAT_TYPE_AUDIO,
+	/*! G.719 (64 kbps assumed) */
+	AST_FORMAT_G719             = 15 + AST_FORMAT_TYPE_AUDIO,
+	/*! SpeeX Wideband (16kHz) Free Compression */
+	AST_FORMAT_SPEEX16          = 16 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw mu-law data (G.711) */
+	AST_FORMAT_TESTLAW          = 17 + AST_FORMAT_TYPE_AUDIO,
+	/*! SILK format */
+	AST_FORMAT_SILK             = 18 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+	AST_FORMAT_SLINEAR          = 19 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (12000 Hz) PCM */
+	AST_FORMAT_SLINEAR12        = 20 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+	AST_FORMAT_SLINEAR16        = 21 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (24000 Hz) PCM */
+	AST_FORMAT_SLINEAR24        = 22 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (32000 Hz) PCM */
+	AST_FORMAT_SLINEAR32        = 23 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (44100 Hz) PCM just because we can. */
+	AST_FORMAT_SLINEAR44        = 24 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (48000 Hz) PCM */
+	AST_FORMAT_SLINEAR48        = 25 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (96000 Hz) PCM */
+	AST_FORMAT_SLINEAR96        = 26 + AST_FORMAT_TYPE_AUDIO,
+	/*! Raw 16-bit Signed Linear (192000 Hz) PCM.  maybe we're taking this too far. */
+	AST_FORMAT_SLINEAR192       = 27 + AST_FORMAT_TYPE_AUDIO,
+	AST_FORMAT_SPEEX32          = 28 + AST_FORMAT_TYPE_AUDIO,
+	AST_FORMAT_CELT             = 29 + AST_FORMAT_TYPE_AUDIO,
+
+	/*! H.261 Video */
+	AST_FORMAT_H261             = 1 + AST_FORMAT_TYPE_VIDEO,
+	/*! H.263 Video */
+	AST_FORMAT_H263             = 2 + AST_FORMAT_TYPE_VIDEO,
+	/*! H.263+ Video */
+	AST_FORMAT_H263_PLUS        = 3 + AST_FORMAT_TYPE_VIDEO,
+	/*! H.264 Video */
+	AST_FORMAT_H264             = 4 + AST_FORMAT_TYPE_VIDEO,
+	/*! MPEG4 Video */
+	AST_FORMAT_MP4_VIDEO        = 5 + AST_FORMAT_TYPE_VIDEO,
+
+	/*! JPEG Images */
+	AST_FORMAT_JPEG             = 1 + AST_FORMAT_TYPE_IMAGE,
+	/*! PNG Images */
+	AST_FORMAT_PNG              = 2 + AST_FORMAT_TYPE_IMAGE,
+
+	/*! T.140 RED Text format RFC 4103 */
+	AST_FORMAT_T140RED          = 1 + AST_FORMAT_TYPE_TEXT,
+	/*! T.140 Text format - ITU T.140, RFC 4103 */
+	AST_FORMAT_T140             = 2 + AST_FORMAT_TYPE_TEXT,
+};
+
+/*! Determine what type of media a ast_format_id is. */
+#define AST_FORMAT_GET_TYPE(id) (((int) (id / AST_FORMAT_INC)) * AST_FORMAT_INC)
+
+
+/*! \brief This structure contains the buffer used for format attributes */
+struct ast_format_attr {
+	/*! The buffer formats can use to represent attributes */
+	uint32_t format_attr[AST_FORMAT_ATTR_SIZE];
+	/*! If a format's payload needs to pass through that a new marker is required
+	 * for RTP, this variable will be set. */
+	uint8_t rtp_marker_bit;
+};
+
+/*! \brief Represents a media format within Asterisk. */
+struct ast_format {
+	/*! The unique id representing this format from all the other formats. */
+	enum ast_format_id id;
+	/*!  Attribute structure used to associate attributes with a format. */
+	struct ast_format_attr fattr;
+};
 
-/*! \brief Format comparison results */
 enum ast_format_cmp_res {
-	/*! Both formats are equivalent to eachother */
+	/*! structure 1 is identical to structure 2. */
 	AST_FORMAT_CMP_EQUAL = 0,
-	/*! Both formats are completely different and not the same in any way */
+	/*! structure 1 contains elements not in structure 2. */
 	AST_FORMAT_CMP_NOT_EQUAL,
-	/*! Both formats are similar but not equivalent */
+	/*! structure 1 is a proper subset of the elements in structure 2.*/
 	AST_FORMAT_CMP_SUBSET,
 };
 
-/*! \brief Optional format interface to extend format operations */
-struct ast_format_interface {
-	/*!
-	 * \brief Callback for when the format is destroyed, used to release attribute resources
+/*! \brief Definition of supported media formats (codecs) */
+struct ast_format_list {
+	struct ast_format format; /*!< The unique format. */
+	char name[64];	/*!< short name */
+	unsigned int samplespersecond; /*!< Number of samples per second (8000/16000) */
+	char desc[128];	/*!< Description */
+	int fr_len;	/*!< Single frame length in bytes */
+	int min_ms;	/*!< Min value */
+	int max_ms;	/*!< Max value */
+	int inc_ms;	/*!< Increment */
+	int def_ms;	/*!< Default value */
+	unsigned int flags;	/*!< Smoother flags */
+	int cur_ms;	/*!< Current value */
+	int custom_entry;
+};
+
+/*! \brief A format must register an attribute interface if it requires the use of the format attributes void pointer */
+struct ast_format_attr_interface {
+	/*! format type */
+	enum ast_format_id id;
+
+	/*! \brief Determine if format_attr 1 is a subset of format_attr 2.
 	 *
-	 * \param format The format structure to destroy
+	 * \retval ast_format_cmp_res representing the result of comparing fattr1 and fattr2.
 	 */
-	void (*const format_destroy)(struct ast_format *format);
+	enum ast_format_cmp_res (* const format_attr_cmp)(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2);
 
-	/*!
-	 * \brief Callback for when the format is cloned, used to clone attributes
-	 *
-	 * \param src Source format of attributes
-	 * \param dst Destination format for attributes
+	/*! \brief Get joint attributes of same format type if they exist.
 	 *
-	 * \retval 0 success
-	 * \retval -1 failure
+	 * \retval 0 if joint attributes exist
+	 * \retval -1 if no joint attributes are present
 	 */
-	int (*const format_clone)(const struct ast_format *src, struct ast_format *dst);
+	int (* const format_attr_get_joint)(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result);
+
+	/*! \brief Set format capabilities from a list of key value pairs ending with AST_FORMAT_ATTR_END.
+	 * \note This function does not need to call va_end of the va_list. */
+	void (* const format_attr_set)(struct ast_format_attr *format_attr, va_list ap);
 
 	/*!
-	 * \brief Determine if format 1 is a subset of format 2.
+	 * \brief Find out if format capabilities in va_list are in format.
+	 * \note This function does not need to call va_end of the va_list.
 	 *
-	 * \param format1 First format to compare
-	 * \param format2 Second format which the first is compared against
+	 * \note This function is optional.  In many cases the format_attr_cmp
+	 * function can be used to derive these results.  If it is possible
+	 * that some format attributes have no bearing on the equality of two formats, this
+	 * function must exist.
 	 *
-	 * \retval ast_format_cmp_res representing the result of comparing format1 and format2.
+	 * \retval 0 if all attributes exist
+	 * \retval -1 if any of the attributes not present
 	 */
-	enum ast_format_cmp_res (* const format_cmp)(const struct ast_format *format1,
-		const struct ast_format *format2);
+	int (* const format_attr_isset)(const struct ast_format_attr *format_attr, va_list ap);
 
-	/*! 
-	 * \brief Get a format with the joint compatible attributes of both provided formats.
-	 *
-	 * \param format1 The first format
-	 * \param format2 The second format
-	 *
-	 * \retval non-NULL if joint format
-	 * \retval NULL if no joint format
+	/*
+	 * \brief Return a value for a specific format key.   Return that value in the void pointer.
 	 *
-	 * \note The returned format has its reference count incremented and must be released using
-	 * ao2_ref or ao2_cleanup.
-	 */
-	struct ast_format *(* const format_get_joint)(const struct ast_format *format1,
-		const struct ast_format *format2);
-
-	/*!
-	 * \brief Set an attribute on a format
+	 * \note It is not expected that all key value pairs can be returned, but those that can should
+	 * be documented as such.
 	 *
-	 * \param name The name of the attribute
-	 * \param value The value of the attribute
+	 * \note This function is optional if key value pairs are not allowed to be accessed.  This
+	 * will result in -1 always being returned.
 	 *
-	 * \retval non-NULL success
-	 * \retval NULL failure
+	 * \retval 0 Success, value was found and copied into void pointer.
+	 * \retval -1 failure, Value was either not found, or not allowed to be accessed.
 	 */
-	struct ast_format *(* const format_attribute_set)(const struct ast_format *format,
-		const char *name, const char *value);
+	int (* const format_attr_get_val)(const struct ast_format_attr *format_attr, int key, void *val);
 
-	/*!
-	 * \brief Parse SDP attribute information, interpret it, and store it in the format structure.
-	 *
-	 * \param format Format to set attributes on
-	 * \param attributes A string containing only the attributes from the fmtp line
+	/*
+	 * \brief Parse SDP attribute information, interpret it, and store it in ast_format_attr structure.
 	 *
-	 * \retval non-NULL Success, values were valid
-	 * \retval NULL Failure, some values were not acceptable
+	 * \retval 0 Success, values were valid
+	 * \retval -1 Failure, some values were not acceptable
 	 */
-	struct ast_format *(* const format_parse_sdp_fmtp)(const struct ast_format *format, const char *attributes);
+	int (* const format_attr_sdp_parse)(struct ast_format_attr *format_attr, const char *attributes);
 
 	/*!
 	 * \brief Generate SDP attribute information from an ast_format_attr structure.
 	 *
-	 * \param format The format containing attributes
-	 * \param payload The payload number to place into the fmtp line
-	 * \param str The generated fmtp line
-	 *
 	 * \note This callback should generate a full fmtp line using the provided payload number.
 	 */
-	void (* const format_generate_sdp_fmtp)(const struct ast_format *format, unsigned int payload,
-		struct ast_str **str);
+	void (* const format_attr_sdp_generate)(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str);
 };
 
 /*!
- * \brief Initialize media format support
+ * \brief This function is used to have a media format aware module parse and interpret
+ * SDP attribute information. Once interpreted this information is stored on the format
+ * itself using Asterisk format attributes.
  *
- * \retval 0 success
- * \retval -1 failure
+ * \param format to set
+ * \param attributes string containing the fmtp line from the SDP
+ *
+ * \retval 0 success, attribute values were valid
+ * \retval -1 failure, values were not acceptable
  */
-int ast_format_init(void);
+int ast_format_sdp_parse(struct ast_format *format, const char *attributes);
 
 /*!
- * \brief Create a new media format
- *
- * \param codec The codec to use
- *
- * \retval non-NULL success
- * \retval NULL failure
+ * \brief This function is used to produce an fmtp SDP line for an Asterisk format. The
+ * attributes present on the Asterisk format are translated into the SDP equivalent.
  *
- * \note The format is returned with reference count incremented. It must be released using
- * ao2_ref or ao2_cleanup.
+ * \param format to generate an fmtp line for
+ * \param payload numerical payload for the fmtp line
+ * \param str structure that the fmtp line will be appended to
  */
-struct ast_format *ast_format_create(struct ast_codec *codec);
+void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str);
 
 /*!
- * \brief Create a new media format with a specific name
- *
- * \param format_name The name to use for the format
- * \param codec The codec to use
+ * \brief This function is used to set an ast_format object to represent a media format
+ * with optional format attributes represented by format specific key value pairs.
  *
- * \note This creation function should be used when the name of the \c codec
- * cannot be explicitly used for the name of the format. This is the case for
- * codecs with multiple sample rates
- *
- * \note The format is returned with reference count incremented. It must be released using
- * ao2_ref or ao2_cleanup.
+ * \param format to set
+ * \param id, format id to set on format
+ * \param set_attributes, are there attributes to set on this format. 0 == false, 1 == True.
+ * \param var list of attribute key value pairs, must end with AST_FORMAT_ATTR_END;
  *
- * \retval non-NULL success
- * \retval NULL failure
- */
-struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec);
-
-/*!
- * \brief Clone an existing media format so it can be modified
+ * \details Example usage.
+ * ast_format_set(format, AST_FORMAT_ULAW, 0); // no capability attributes are needed for ULAW
  *
- * \param format The existing media format
+ * ast_format_set(format, AST_FORMAT_SILK, 1, // SILK has capability attributes.
+ *	  AST_FORMAT_SILK_ATTR_RATE, 24000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 16000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 12000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 8000,
+ *	  AST_FORMAT_ATTR_END);
  *
- * \note The returned format is a new ao2 object. It must be released using ao2_cleanup.
+ * \note This function will initialize the ast_format structure.
  *
- * \retval non-NULL success
- * \retval NULL failure
+ * \return Pointer to ast_format object, same pointer that is passed in
+ * by the first argument.
  */
-struct ast_format *ast_format_clone(const struct ast_format *format);
+struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... );
 
 /*!
- * \brief Compare two formats
+ * \brief After ast_format_set has been used on a function, this function can be used to
+ * set additional format attributes to the structure.
  *
- * \retval ast_format_cmp_res representing the result of comparing format1 and format2.
+ * \param format to set
+ * \param var list of attribute key value pairs, must end with AST_FORMAT_ATTR_END;
+ *
+ * \details Example usage.
+ * ast_format_set(format, AST_FORMAT_SILK, 0);
+ * ast_format_append(format, // SILK has capability attributes.
+ *	  AST_FORMAT_SILK_ATTR_RATE, 24000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 16000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 12000,
+ *	  AST_FORMAT_SILK_ATTR_RATE, 8000,
+ *	  AST_FORMAT_ATTR_END);
+ *
+ * \return Pointer to ast_format object, same pointer that is passed in
+ * by the first argument.
  */
-enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2);
+struct ast_format *ast_format_append(struct ast_format *format, ... );
 
 /*!
- * \brief Get a common joint capability between two formats
- *
- * \retval non-NULL if joint capability exists
- * \retval NULL if no joint capability exists
- *
- * \note The returned format must be treated as immutable.
+ * \brief Clears the format stucture.
  */
-struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2);
+void ast_format_clear(struct ast_format *format);
 
 /*!
- * \brief Set an attribute on a format to a specific value
+ * \brief This function is used to set an ast_format object to represent a media format
+ * with optional capability attributes represented by format specific key value pairs.
  *
- * \param format The format to set the attribute on
- * \param name Attribute name
- * \param value Attribute value
+ * \details Example usage. Is this SILK format capable of 8khz
+ * is_8khz = ast_format_isset(format, AST_FORMAT_SILK_CAP_RATE, 8000);
  *
- * \retval non-NULL success
- * \retval NULL failure
+ * \return 0, The format key value pairs are within the capabilities defined in this structure.
+ * \return -1, The format key value pairs are _NOT_ within the capabilities of this structure.
  */
-struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name,
-	const char *value);
+int ast_format_isset(const struct ast_format *format, ... );
 
 /*!
- * \brief This function is used to have a media format aware module parse and interpret
- * SDP attribute information. Once interpreted this information is stored on the format
- * itself using Asterisk format attributes.
- *
- * \param format to set
- * \param attributes string containing the fmtp line from the SDP
+ * \brief Get a value from a format containing attributes.
+ * \note The key represents the format attribute to be retrieved, and the void pointer
+ * is to the structure that value will be stored in.  It must be known what structure a
+ * key represents.
  *
- * \retval non-NULL success, attribute values were valid
- * \retval NULL failure, values were not acceptable
+ * \retval 0, success
+ * \retval -1, failure
  */
-struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes);
+int ast_format_get_value(const struct ast_format *format, int key, void *value);
 
 /*!
- * \brief This function is used to produce an fmtp SDP line for an Asterisk format. The
- * attributes present on the Asterisk format are translated into the SDP equivalent.
+ * \brief Compare ast_formats structures
  *
- * \param format to generate an fmtp line for
- * \param payload numerical payload for the fmtp line
- * \param str structure that the fmtp line will be appended to
+ * \retval ast_format_cmp_res representing the result of comparing format1 and format2.
  */
-void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str);
+enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2);
 
 /*!
- * \brief Register a format interface for use with the provided codec
- *
- * \param codec The name of codec the interface is applicable to
- * \param interface A pointer to the interface implementation
- * \param mod The module this format interface is provided by
+ * \brief Find joint format attributes of two ast_format
+ * structures containing the same uid and return the intersection in the
+ * result structure.
  *
- * \retval 0 success
- * \retval -1 failure
+ * retval 0, joint attribute capabilities exist.
+ * retval -1, no joint attribute capabilities exist.
  */
-int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod);
+int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result);
 
 /*!
- * \brief Register a format interface for use with the provided codec
- *
- * \param codec The name of codec the interface is applicable to
- * \param interface A pointer to the interface implementation
- *
- * \retval 0 success
- * \retval -1 failure
+ * \brief copy format src into format dst.
  */
-#define ast_format_interface_register(codec, interface) __ast_format_interface_register(codec, interface, ast_module_info->self)
+void ast_format_copy(struct ast_format *dst, const struct ast_format *src);
 
 /*!
- * \brief Get the attribute data on a format
- *
- * \param format The media format
- *
- * \return Currently set attribute data
+ * \brief Set the rtp mark value on the format to indicate to the interface
+ * writing this format's payload that a new RTP marker is necessary.
  */
-void *ast_format_get_attribute_data(const struct ast_format *format);
+void ast_format_set_video_mark(struct ast_format *format);
 
 /*!
- * \brief Set the attribute data on a format
+ * \brief Determine of the marker bit is set or not on this format.
  *
- * \param format The media format
- * \param attribute_data The attribute data
+ * \retval 1, true
+ * \retval 0, false
  */
-void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data);
+int ast_format_get_video_mark(const struct ast_format *format);
 
 /*!
- * \brief Get the name associated with a format
+ * \brief ast_format to old bitfield format represenatation
  *
- * \param format The media format
+ * \note This is only to be used for IAX2 compatibility 
  *
- * \return The name of the format
+ * \retval iax2 representation of ast_format
+ * \retval 0, if no representation existis for iax2
  */
-const char *ast_format_get_name(const struct ast_format *format);
+uint64_t ast_format_to_old_bitfield(const struct ast_format *format);
 
 /*!
- * \brief Get the codec identifier associated with a format
- *
- * \param format The media format
+ * \brief ast_format_id to old bitfield format represenatation
  *
- * \return codec identifier
  */
-unsigned int ast_format_get_codec_id(const struct ast_format *format);
+uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id);
 
 /*!
- * \brief Get the codec name associated with a format
- *
- * \param format The media format
+ * \brief convert old bitfield format to ast_format represenatation
+ * \note This is only to be used for IAX2 compatibility 
  *
- * \return The codec name
+ * \retval on success, pointer to the dst format in the input parameters
+ * \retval on failure, NULL
  */
-const char *ast_format_get_codec_name(const struct ast_format *format);
+struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src);
 
 /*!
- * \brief Get whether or not the format can be smoothed
- *
- * \param format The media format
- *
- * \retval 0 the format cannot be smoothed
- * \retval 1 the format can be smoothed
+ * \brief convert old bitfield format to ast_format_id value
  */
-int ast_format_can_be_smoothed(const struct ast_format *format);
+enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src);
 
 /*!
- * \brief Get the media type of a format
- *
- * \param format The media format
- *
- * \return the media type
+ * \brief Retrieve the global format list in a read only array.
+ * \note ast_format_list_destroy must be called on every format
+ * list retrieved from this function.
  */
-enum ast_media_type ast_format_get_type(const struct ast_format *format);
+const struct ast_format_list *ast_format_list_get(size_t *size);
 
 /*!
- * \brief Get the default framing size (in milliseconds) for a format
- *
- * \param format The media format
- *
- * \return default framing size in milliseconds
+ * \brief Destroy an ast_format_list gotten from ast_format_list_get()
  */
-unsigned int ast_format_get_default_ms(const struct ast_format *format);
+const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list);
 
-/*!
- * \brief Get the minimum amount of media carried in this format
- *
- * \param format The media format
- *
- * \return minimum framing size in milliseconds
+/*! \brief Get the name of a format
+ * \param format id of format
+ * \return A static string containing the name of the format or "unknown" if unknown.
+ */
+const char* ast_getformatname(const struct ast_format *format);
+
+/*! \brief Returns a string containing all formats pertaining to an format id.
+ * \param buf a buffer for the output string
+ * \param size size of buf (bytes)
+ * \param format id.
+ * \return The return value is buf.
  */
-unsigned int ast_format_get_minimum_ms(const struct ast_format *format);
+char* ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id);
 
 /*!
- * \brief Get the maximum amount of media carried in this format
- *
- * \param format The media format
- *
- * \return maximum framing size in milliseconds
+ * \brief Gets a format from a name.
+ * \param name string of format
+ * \param format structure to return the format in.
+ * \return This returns the format pointer given to it on success and NULL on failure
  */
-unsigned int ast_format_get_maximum_ms(const struct ast_format *format);
+struct ast_format *ast_getformatbyname(const char *name, struct ast_format *format);
 
 /*!
- * \brief Get the minimum number of bytes expected in a frame for this format
- *
- * \param format The media format
- *
- * \return minimum expected bytes in a frame for this format
+ * \brief Get a name from a format 
+ * \param format to get name of
+ * \return This returns a static string identifying the format on success, 0 on error.
  */
-unsigned int ast_format_get_minimum_bytes(const struct ast_format *format);
+const char *ast_codec2str(struct ast_format *format);
 
 /*!
- * \brief Get the sample rate of a media format
- *
- * \param format The media format
- *
- * \return sample rate
+ * \brief Get the sample rate for a given format.
  */
-unsigned int ast_format_get_sample_rate(const struct ast_format *format);
+int ast_format_rate(const struct ast_format *format);
 
 /*!
- * \brief Get the length (in milliseconds) for the format with a given number of samples
- *
- * \param format The media format
- * \param samples The number of samples
+ * \brief register ast_format_attr_interface with core.
  *
- * \return length of media (in milliseconds)
+ * \retval 0 success
+ * \retval -1 failure
  */
-unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples);
+int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface);
 
 /*!
- * \since 12
- * \brief Get the message type used for signaling a format registration
+ * \brief unregister format_attr interface with core.
  *
- * \retval Stasis message type for format registration
- * \retval NULL on error
+ * \retval 0 success
+ * \retval -1 failure
  */
-struct stasis_message_type *ast_format_register_type(void);
+int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface);
 
 /*!
- * \since 12
- * \brief Get the message type used for signaling a format unregistration
- *
- * \retval Stasis message type for format unregistration
- * \retval NULL on error
+ * \brief Determine if a format is 16bit signed linear of any sample rate. 
  */
-struct stasis_message_type *ast_format_unregister_type(void);
+int ast_format_is_slinear(const struct ast_format *format);
 
+/*!
+ * \brief Get the best slinear format id for a given sample rate
+ */
+enum ast_format_id ast_format_slin_by_rate(unsigned int rate);
 #endif /* _AST_FORMAT_H */
diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h
deleted file mode 100644
index 9f4e06a..0000000
--- a/include/asterisk/format_cache.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Media Format Cache API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _AST_FORMAT_CACHE_H_
-#define _AST_FORMAT_CACHE_H_
-
-struct ast_format;
-
-/*!
- * \brief Built-in cached signed linear 8kHz format.
- */
-extern struct ast_format *ast_format_slin;
-
-/*!
- * \brief Built-in cached signed linear 12kHz format.
- */
-extern struct ast_format *ast_format_slin12;
-
-/*!
- * \brief Built-in cached signed linear 16kHz format.
- */
-extern struct ast_format *ast_format_slin16;
-
-/*!
- * \brief Built-in cached signed linear 24kHz format.
- */
-extern struct ast_format *ast_format_slin24;
-
-/*!
- * \brief Built-in cached signed linear 32kHz format.
- */
-extern struct ast_format *ast_format_slin32;
-
-/*!
- * \brief Built-in cached signed linear 44kHz format.
- */
-extern struct ast_format *ast_format_slin44;
-
-/*!
- * \brief Built-in cached signed linear 48kHz format.
- */
-extern struct ast_format *ast_format_slin48;
-
-/*!
- * \brief Built-in cached signed linear 96kHz format.
- */
-extern struct ast_format *ast_format_slin96;
-
-/*!
- * \brief Built-in cached signed linear 192kHz format.
- */
-extern struct ast_format *ast_format_slin192;
-
-/*!
- * \brief Built-in cached ulaw format.
- */
-extern struct ast_format *ast_format_ulaw;
-
-/*!
- * \brief Built-in cached alaw format.
- */
-extern struct ast_format *ast_format_alaw;
-
-/*!
- * \brief Built-in cached testlaw format.
- */
-extern struct ast_format *ast_format_testlaw;
-
-/*!
- * \brief Built-in cached gsm format.
- */
-extern struct ast_format *ast_format_gsm;
-
-/*!
- * \brief Built-in cached adpcm format.
- */
-extern struct ast_format *ast_format_adpcm;
-
-/*!
- * \brief Built-in cached g722 format.
- */
-extern struct ast_format *ast_format_g722;
-
-/*!
- * \brief Built-in cached g726 format.
- */
-extern struct ast_format *ast_format_g726;
-
-/*!
- * \brief Built-in cached g726 aal2 format.
- */
-extern struct ast_format *ast_format_g726_aal2;
-
-/*!
- * \brief Built-in cached ilbc format.
- */
-extern struct ast_format *ast_format_ilbc;
-
-/*!
- * \brief Built-in cached ilbc format.
- */
-extern struct ast_format *ast_format_lpc10;
-
-/*!
- * \brief Built-in cached speex format.
- */
-extern struct ast_format *ast_format_speex;
-
-/*!
- * \brief Built-in cached speex at 16kHz format.
- */
-extern struct ast_format *ast_format_speex16;
-
-/*!
- * \brief Built-in cached speex at 32kHz format.
- */
-extern struct ast_format *ast_format_speex32;
-
-/*!
- * \brief Built-in cached g723.1 format.
- */
-extern struct ast_format *ast_format_g723;
-
-/*!
- * \brief Built-in cached g729 format.
- */
-extern struct ast_format *ast_format_g729;
-
-/*!
- * \brief Built-in cached g719 format.
- */
-extern struct ast_format *ast_format_g719;
-
-/*!
- * \brief Built-in cached h261 format.
- */
-extern struct ast_format *ast_format_h261;
-
-/*!
- * \brief Built-in cached h263 format.
- */
-extern struct ast_format *ast_format_h263;
-
-/*!
- * \brief Built-in cached h263 plus format.
- */
-extern struct ast_format *ast_format_h263p;
-
-/*!
- * \brief Built-in cached h264 format.
- */
-extern struct ast_format *ast_format_h264;
-
-/*!
- * \brief Built-in cached mp4 format.
- */
-extern struct ast_format *ast_format_mp4;
-
-/*!
- * \brief Built-in cached vp8 format.
- */
-extern struct ast_format *ast_format_vp8;
-
-/*!
- * \brief Built-in cached jpeg format.
- */
-extern struct ast_format *ast_format_jpeg;
-
-/*!
- * \brief Built-in cached png format.
- */
-extern struct ast_format *ast_format_png;
-
-/*!
- * \brief Built-in cached siren14 format.
- */
-extern struct ast_format *ast_format_siren14;
-
-/*!
- * \brief Built-in cached siren7 format.
- */
-extern struct ast_format *ast_format_siren7;
-
-/*!
- * \brief Built-in cached opus format.
- */
-extern struct ast_format *ast_format_opus;
-
-/*!
- * \brief Built-in cached t140 format.
- */
-extern struct ast_format *ast_format_t140;
-
-/*!
- * \brief Built-in cached t140 red format.
- */
-extern struct ast_format *ast_format_t140_red;
-
-/*!
- * \brief Built-in "null" format.
- */
-extern struct ast_format *ast_format_none;
-
-/*!
- * \brief Initialize format cache support within the core.
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_format_cache_init(void);
-
-/*!
- * \brief Set a named format cache entry.
- *
- * \param format A pointer to the format to cache
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_format_cache_set(struct ast_format *format);
-
-/*!
- * \brief Retrieve a named format from the cache.
- *
- * \param name Name of the cached format
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note The returned format has its reference count incremented. It must be
- * dropped using ao2_ref or ao2_cleanup.
- */
-struct ast_format *__ast_format_cache_get(const char *name);
-struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func);
-
-#ifdef REF_DEBUG
-#define ast_format_cache_get(name) \
-	__ast_format_cache_get_debug((name), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ast_t_format_cache_get(name, tag) \
-	__ast_format_cache_get_debug((name), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#else
-#define ast_format_cache_get(name) \
-	__ast_format_cache_get((name))
-#define ast_t_format_cache_get(name, tag) \
-	__ast_format_cache_get((name))
-#endif
-
-
-/*!
- * \brief Retrieve the best signed linear format given a sample rate.
- *
- * \param rate The sample rate
- *
- * \details
- * This is a convenience function that returns one of the global
- * ast_format_slinxxx formats.
- *
- * \return pointer to the signed linear format
- *
- * \note The returned format has NOT had its reference count incremented.
- */
-struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate);
-
-/*!
- * \brief Determines if a format is one of the cached slin formats
- *
- * \param format The format to check
- *
- * \retval 0 if the format is not an SLIN format
- * \retval 1 if the format is an SLIN format
- */
-int ast_format_cache_is_slinear(struct ast_format *format);
-
-#endif /* _AST_FORMAT_CACHE_H */
diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h
index 94e81f8..2347676 100644
--- a/include/asterisk/format_cap.h
+++ b/include/asterisk/format_cap.h
@@ -1,9 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2014, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
  *
- * Joshua Colp <jcolp at digium.com>
+ * David Vossel <dvossel at digium.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -18,289 +18,220 @@
 
 /*!
  * \file
- * \brief Format Capabilities API
+ * \brief Format Capability API
  *
- * \author Joshua Colp <jcolp at digium.com>
+ * \author David Vossel <dvossel at digium.com>
  */
 
-#ifndef _AST_FORMAT_CAP_H_
-#define _AST_FORMAT_CAP_H_
+#ifndef _AST_FORMATCAP_H_
+#define _AST_FORMATCAP_H_
 
-#include "asterisk/codec.h"
-
-/*! Capabilities are represented by an opaque structure statically defined in format_cap.c */
+/*! Capabilities are represented by an opaque structure statically defined in format_capability.c */
 struct ast_format_cap;
 
-enum ast_format_cap_flags {
-	/*!
-	 * Default format capabilities settings
-	 */
-	AST_FORMAT_CAP_FLAG_DEFAULT = 0,
-};
-
 /*!
- * \brief Allocate a new ast_format_cap structure
+ * \brief Allocate a new ast_format_cap structure.
  *
- * \param flags Modifiers of struct behavior.
+ * \note Allocation of this object assumes locking
+ * is already occuring and that the point of contention
+ * is above this capabilities structure.  For example,
+ * a tech_pvt object referencing a capabilities structure
+ * can use this function as long as it always holds the
+ * tech_pvt lock while accessing its capabilities.
  *
  * \retval ast_format_cap object on success.
  * \retval NULL on failure.
  */
-struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags);
-struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func);
-
-#ifdef REF_DEBUG
-#define ast_format_cap_alloc(flags) \
-	__ast_format_cap_alloc_debug((flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ast_t_format_cap_alloc(flags, tag) \
-	__ast_format_cap_alloc_debug((flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#else
-#define ast_format_cap_alloc(flags) \
-	__ast_format_cap_alloc((flags))
-#define ast_t_format_cap_alloc(flags, tag) \
-	__ast_format_cap_alloc((flags))
-#endif
+struct ast_format_cap *ast_format_cap_alloc_nolock(void);
 
 /*!
- * \brief Set the global framing.
+ * \brief Allocate a new ast_format_cap structure with locking
  *
- * \param cap The capabilities structure.
- * \param framing The framing value (in milliseconds).
+ * \note If no other form of locking is taking place, use this function.
+ * This function makes most sense for globally accessible capabilities structures
+ * that have no other means of locking.
  *
- * \note This is used if a format does not provide a framing itself. Note that
- *       adding subsequent formats to the \c ast_format_cap structure may
- *       override this value, if the framing they require is less than the
- *       value set by this function.
+ * \retval ast_format_cap object on success.
+ * \retval NULL on failure.
  */
-void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing);
+struct ast_format_cap *ast_format_cap_alloc(void);
 
 /*!
- * \brief Get the global framing.
- *
- * \param cap The capabilities structure.
+ * \brief Destroy an ast_format_cap structure.
  *
- * \retval 0 if no formats are in the structure and no framing has been provided
- * \retval The global framing value (in milliseconds)
- *
- * \note This will be the minimum framing allowed across all formats in the
- *       capabilities structure, or an overridden value
+ * \return NULL
  */
-unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap);
+void *ast_format_cap_destroy(struct ast_format_cap *cap);
 
 /*!
  * \brief Add format capability to capabilities structure.
  *
- * \param cap The capabilities structure to add to.
- * \param format The format to add.
- * \param framing The framing for the format (in milliseconds).
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note A reference to the format is taken and used in the capabilities structure.
- *
- * \note The order in which add is called determines the format preference order.
- *
- * \note If framing is specified here it overrides any global framing that has been set.
+ * \note A copy of the input format is made and that copy is
+ * what is placed in the ast_format_cap structure.  The actual
+ * input format ptr is not stored.
  */
-int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing);
-int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func);
-
-#ifdef REF_DEBUG
-#define ast_format_cap_append(cap, format, framing) \
-	__ast_format_cap_append_debug((cap), (format), (framing), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ast_t_format_cap_append(cap, format, framing, tag) \
-	__ast_format_cap_append_debug((cap), (format), (framing), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#else
-#define ast_format_cap_append(cap, format, framing) \
-	__ast_format_cap_append((cap), (format), (framing))
-#define ast_t_format_cap_append(cap, format, framing, tag) \
-	__ast_format_cap_append((cap), (format), (framing))
-#endif
+void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format);
 
 /*!
- * \brief Add all codecs Asterisk knows about for a specific type to
- * the capabilities structure.
- *
- * \param cap The capabilities structure to add to.
- * \param type The type of formats to add.
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note A generic format with no attributes is created using the codec.
- *
- * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be added.
+ * \brief Add all formats Asterisk knows about for a specific type to
+ * the capabilities structure.  Formats with attributes are set, but their
+ * attributes are initilized to 0's.  An attribute structure of 0's should
+ * indicate to the format attribute interface that the format has full
+ * capabilities.
+ *
+ * \note A copy of the input format is made and that copy is
+ * what is placed in the ast_format_cap structure.  The actual
+ * input format ptr is not stored.
  */
-int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type);
+void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type);
 
 /*!
- * \brief Append the formats of provided type in src to dst
- *
- * \param dst The destination capabilities structure
- * \param src The source capabilities structure
- * \param type The type of formats to append.
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be added.
+ * \brief Add all known formats to the capabilities structure using default format attribute. */
+void ast_format_cap_add_all(struct ast_format_cap *cap);
+
+/*!
+ * \brief Append the formats in src to dst
  */
-int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type);
+void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src);
 
 /*!
- * \brief Replace the formats of provided type in dst with equivalent formats from src
- *
- * \param dst The destination capabilities structure
- * \param src The source capabilities structure
- * \param type The type of formats to replace.
- *
- * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be replaced.
- * \note Formats present in src but not dst will not be appended to dst.
+ * \brief Copy all items in src to dst.
+ * \note any items in dst will be removed before copying
  */
-void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type);
+void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src);
 
 /*!
- * \brief Parse an "allow" or "deny" list and modify a format capabilities structure accordingly
- *
- * \param cap The capabilities structure to modify
- * \param list The list containing formats to append or remove
- * \param allowing If zero, start removing formats specified in the list. If non-zero,
- *        start appending formats specified in the list.
+ * \brief create a deep copy of an ast_format_cap structure
  *
- * \retval 0 on success
- * \retval -1 on failure
+ * \retval cap on success
+ * \retval NULL on failure
  */
-int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing);
+struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *src);
 
 /*!
- * \brief Get the number of formats present within the capabilities structure
- *
- * \param cap The capabilities structure
+ * \brief determine if a capabilities structure is empty or not
  *
- * \return the number of formats
+ * \retval 1, true is empty
+ * \retval 0, false, not empty
  */
-size_t ast_format_cap_count(const struct ast_format_cap *cap);
+int ast_format_cap_is_empty(const struct ast_format_cap *cap);
 
 /*!
- * \brief Get the format at a specific index
- *
- * \param cap The capabilities structure
- * \param position The position to get
- *
- * \retval non-NULL success
- * \retval NULL failure
- *
- * \note This is a zero based index.
+ * \brief Remove format capability from capability structure.
  *
- * \note Formats are returned in order of preference.
+ * \Note format must match Exactly to format in ast_format_cap object in order
+ * to be removed.
  *
- * \note The reference count of the returned format is increased. It must be released using ao2_ref
- * or ao2_cleanup.
+ * \retval 0, remove was successful
+ * \retval -1, remove failed. Could not find format to remove
  */
-struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position);
+int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format);
 
 /*!
- * \brief Get the most preferred format for a particular media type
- *
- * \param cap The capabilities structure
- * \param type The type of media to get
+ * \brief Remove all format capabilities from capability
+ * structure for a specific format id.
  *
- * \retval non-NULL the preferred format
- * \retval NULL no media of \c type present
+ * \Note This will remove _ALL_ formats matching the format id from the
+ * capabilities structure.
  *
- * \note The reference count of the returned format is increased. It must be released using ao2_ref
- * or ao2_cleanup.
+ * \retval 0, remove was successful
+ * \retval -1, remove failed. Could not find formats to remove
  */
-struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type);
+int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id);
 
 /*!
- * \brief Get the framing for a format
- *
- * \param cap The capabilities structure
- * \param format The format to retrieve
- *
- * \return the framing (in milliseconds)
+ * \brief Remove all formats matching a specific format type.
  */
-unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format);
+void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type);
 
 /*!
- * \brief Remove format capability from capability structure.
- *
- * \note format must be an exact pointer match to remove from capabilities structure.
- *
- * \retval 0, remove was successful
- * \retval -1, remove failed. Could not find format to remove
+ * \brief Remove all format capabilities from capability structure
  */
-int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format);
+void ast_format_cap_remove_all(struct ast_format_cap *cap);
 
 /*!
- * \brief Remove all formats matching a specific format type.
- *
- * \param cap The capabilities structure
- * \param type The media type to remove formats of
- *
- * \note All formats can be removed by using the AST_MEDIA_TYPE_UNKNOWN type.
+ * \brief Remove all previous formats and set a single new format.
  */
-void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type);
+void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format);
 
 /*!
  * \brief Find if input ast_format is within the capabilities of the ast_format_cap object
  * then return the compatible format from the capabilities structure in the result.
  *
- * \retval non-NULL if format is compatible
- * \retval NULL if not compatible
- *
- * \note The reference count of the returned format is increased. It must be released using ao2_ref
- * or ao2_cleanup.
+ * \retval 1 format is compatible with formats held in ast_format_cap object.
+ * \retval 0 format is not compatible with any formats in ast_format_cap object.
  */
-struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format);
+int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result);
 
 /*!
  * \brief Find if ast_format is within the capabilities of the ast_format_cap object.
  *
-* \retval ast_format_cmp_res representing the result of the compatibility check between cap and format.
+ * retval 1 format is compatible with formats held in ast_format_cap object.
+ * retval 0 format is not compatible with any formats in ast_format_cap object.
  */
-enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format);
+int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format);
 
 /*!
- * \brief Find the compatible formats between two capabilities structures
+ * \brief Finds the best quality audio format for a given format id and returns it in result.
  *
- * \param cap1 The first capabilities structure
- * \param cap2 The second capabilities structure
- * \param[out] result The capabilities structure to place the results into
+ * \retval 1 format found and set to result structure.
+ * \retval 0 no format found, result structure is cleared.
+ */
+int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id, struct ast_format *result);
+
+/*!
+ * \brief is cap1 identical to cap2
  *
- * \retval 0 success
- * \retval -1 failure
+ * retval 1 true, identical
+ * retval 0 false, not identical
+ */
+int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2);
+
+/*!
+ * \brief Get joint capability structure.
  *
- * \note The preference order of cap1 is respected.
+ * \note returns an ast_format_cap object containing the joint capabilities on success.  This new
+ * capabilities structure is allocated with _NO_ locking enabled.  If a joint structure requires
+ * locking, allocate it and use the ast_format_cap_joint_copy function to fill it with the joint
+ * capabilities.
  *
- * \note If failure occurs the result format capabilities structure may contain a partial result.
+ * \retval !NULL success, joint capabilties structure with _NO_ locking enabled.
+ * \retval NULL failure
  */
-int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
-	struct ast_format_cap *result);
+struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2);
 
 /*!
- * \brief Determine if any joint capabilities exist between two capabilities structures
+ * \brief Get joint capability structure, copy into result capabilities structure
  *
- * \param cap1 The first capabilities structure
- * \param cap2 The second capabilities structure
+ * \retval 1, joint capabilities exist
+ * \retval 0, joint capabilities do not exist
+ */
+int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result);
+
+/*!
+ * \brief Get joint capability structure, append into result capabilities structure
  *
- * \retval 0 no joint capabilities exist
- * \retval 1 joint capabilities exist
+ * \retval 1, joint capabilities exist
+ * \retval 0, joint capabilities do not exist
  */
-int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2);
+int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result);
 
 /*!
- * \brief Determine if two capabilities structures are identical
+ * \brief Find out if capability structures have any joint capabilities without
+ * returning those capabilities.
  *
- * \param cap1 The first capabilities structure
- * \param cap2 The second capabilities structure
+ * \retval 1 true, has joint capabilities
+ * \retval 0 false, failure
+ */
+int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2);
+
+/*!
+ * \brief Get all capabilities for a specific media type
  *
- * \retval 0 capabilities are not identical
- * \retval 1 capabilities are identical
+ * \retval !NULL success, new capabilities structure with _NO_ locking enabled on the new structure.
+ * \retval NULL failure
  */
-int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2);
+struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype);
 
 /*!
  * \brief Find out if the capabilities structure has any formats
@@ -309,25 +240,69 @@ int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast
  * \retval 1 true
  * \retval 0 false, no formats of specific type.
  */
-int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type);
+int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type);
+
+/*! \brief Start iterating formats */
+void ast_format_cap_iter_start(struct ast_format_cap *cap);
 
 /*!
- * \brief Get the names of codecs of a set of formats
+ * \brief Next format in interation
+ *
+ * \details
+ * Here is how to use the ast_format_cap iterator.
+ *
+ * 1. call ast_format_cap_iter_start
+ * 2. call ast_format_cap_iter_next in a loop until it returns -1
+ * 3. call ast_format_cap_iter_end to terminate the iterator.
+ *
+ * example:
+ *
+ * ast_format_cap_iter_start(cap);
+ * while (!ast_format_cap_iter_next(cap, &format)) {
+ *
+ * }
+ * ast_format_cap_iter_end(Cap);
  *
- * \param cap The capabilities structure containing the formats
- * \param buf A \c ast_str buffer to populate with the names of the formats
+ * \Note Unless the container was alloced using no_lock, the container
+ * will be locked during the entire iteration until ast_format_cap_iter_end
+ * is called. XXX Remember this, and do not attempt to lock any containers
+ * within this iteration that will violate locking order.
  *
- * \return The contents of the buffer in \c buf
+ * \retval 0 on success, new format is copied into input format struct
+ * \retval -1, no more formats are present.
  */
-const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf);
+int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format);
 
 /*!
- * \brief Determine if a format cap has no formats in it.
+ * \brief Ends ast_format_cap iteration.
+ * \note this must be call after every ast_format_cap_iter_start
+ */
+void ast_format_cap_iter_end(struct ast_format_cap *cap);
+
+/*!
+ * \brief ast_format_cap to old bitfield format represenatation
  *
- * \param cap The format cap to check for emptiness
- * \retval 1 The format cap has zero formats or only ast_format_none
- * \retval 0 The format cap has at least one format
+ * \note This is only to be used for IAX2 compatibility 
+ *
+ * \retval old bitfield representation of ast_format_cap
+ * \retval 0, if no old bitfield capabilities are present in ast_format_cap
+ */
+uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap);
+
+/*!
+ * \brief convert old bitfield format to ast_format_cap represenatation
+ * \note This is only to be used for IAX2 compatibility 
+ */
+void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src);
+
+/*! \brief Get the names of a set of formats
+ * \param buf a buffer for the output string
+ * \param size size of buf (bytes)
+ * \param format the format (combined IDs of codecs)
+ * Prints a list of readable codec names corresponding to "format".
+ * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)"
+ * \return The return value is buf.
  */
-int ast_format_cap_empty(struct ast_format_cap *cap);
+char* ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap);
 
-#endif /* _AST_FORMAT_CAP_H */
+#endif /* _AST_FORMATCAP_H */
diff --git a/include/asterisk/format_compatibility.h b/include/asterisk/format_compatibility.h
deleted file mode 100644
index 0420ec6..0000000
--- a/include/asterisk/format_compatibility.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#ifndef _AST_FORMAT_COMPATIBILITY_H_
-#define _AST_FORMAT_COMPATIBILITY_H_
-
-struct ast_format;
-struct ast_codec;
-
-/*
- * Legacy bitfields for specific formats
- */
-
-/*! G.723.1 compression */
-#define AST_FORMAT_G723 (1ULL << 0)
-/*! GSM compression */
-#define AST_FORMAT_GSM (1ULL << 1)
-/*! Raw mu-law data (G.711) */
-#define AST_FORMAT_ULAW (1ULL << 2)
-/*! Raw A-law data (G.711) */
-#define AST_FORMAT_ALAW (1ULL << 3)
-/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
-#define AST_FORMAT_G726_AAL2 (1ULL << 4)
-/*! ADPCM (IMA) */
-#define AST_FORMAT_ADPCM (1ULL << 5)
-/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
-#define AST_FORMAT_SLIN (1ULL << 6)
-/*! LPC10, 180 samples/frame */
-#define AST_FORMAT_LPC10 (1ULL << 7)
-/*! G.729A audio */
-#define AST_FORMAT_G729 (1ULL << 8)
-/*! SpeeX Free Compression */
-#define AST_FORMAT_SPEEX (1ULL << 9)
-/*! iLBC Free Compression */
-#define AST_FORMAT_ILBC (1ULL << 10)
-/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
-#define AST_FORMAT_G726 (1ULL << 11)
-/*! G.722 */
-#define AST_FORMAT_G722 (1ULL << 12)
-/*! G.722.1 (also known as Siren7, 32kbps assumed) */
-#define AST_FORMAT_SIREN7 (1ULL << 13)
-/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
-#define AST_FORMAT_SIREN14 (1ULL << 14)
-/*! Raw 16-bit Signed Linear (16000 Hz) PCM */
-#define AST_FORMAT_SLIN16 (1ULL << 15)
-/*! G.719 (64 kbps assumed) */
-#define AST_FORMAT_G719 (1ULL << 32)
-/*! SpeeX Wideband (16kHz) Free Compression */
-#define AST_FORMAT_SPEEX16 (1ULL << 33)
-/*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
-#define AST_FORMAT_OPUS (1ULL << 34)
-/*! Raw testing-law data (G.711) */
-#define AST_FORMAT_TESTLAW (1ULL << 47)
-/*! H.261 Video */
-#define AST_FORMAT_H261 (1ULL << 18)
-/*! H.263 Video */
-#define AST_FORMAT_H263 (1ULL << 19)
-/*! H.263+ Video */
-#define AST_FORMAT_H263P (1ULL << 20)
-/*! H.264 Video */
-#define AST_FORMAT_H264 (1ULL << 21)
-/*! MPEG4 Video */
-#define AST_FORMAT_MP4 (1ULL << 22)
-/*! VP8 Video */
-#define AST_FORMAT_VP8 (1ULL << 23)
-/*! JPEG Images */
-#define AST_FORMAT_JPEG (1ULL << 16)
-/*! PNG Images */
-#define AST_FORMAT_PNG (1ULL << 17)
-/*! T.140 RED Text format RFC 4103 */
-#define AST_FORMAT_T140_RED (1ULL << 26)
-/*! T.140 Text format - ITU T.140, RFC 4103 */
-#define AST_FORMAT_T140 (1ULL << 27)
-
-/*!
- * \brief Convert a format structure to its respective bitfield
- *
- * \param format The media format
- *
- * \retval non-zero success
- * \retval zero format not supported
- */
-uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format);
-
-/*!
- * \brief Convert a codec structure to its respective bitfield
- *
- * \param codec The media codec
- *
- * \retval non-zero success
- * \retval zero format not supported
- */
-uint64_t ast_format_compatibility_codec2bitfield(const struct ast_codec *codec);
-
-/*!
- * \brief Convert a bitfield to its respective format structure
- *
- * \param bitfield The bitfield for the media format
- *
- * \retval non-NULL success
- * \retval NULL failure (The format bitfield value is not supported)
- *
- * \note The reference count of the returned format is NOT incremented
- */
-struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield);
-
-#endif /* _AST_FORMAT_COMPATIBILITY_H */
diff --git a/include/asterisk/format_pref.h b/include/asterisk/format_pref.h
new file mode 100644
index 0000000..b034c18
--- /dev/null
+++ b/include/asterisk/format_pref.h
@@ -0,0 +1,114 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Format Preference API
+ */
+
+#ifndef _AST_FORMATPREF_H_
+#define _AST_FORMATPREF_H_
+
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+
+#define AST_CODEC_PREF_SIZE 64
+struct ast_codec_pref {
+	/*! This array represents the each format in the pref list */
+	struct ast_format formats[AST_CODEC_PREF_SIZE];
+	/*! This array represents the format id's index in the global format list. */
+	char order[AST_CODEC_PREF_SIZE];
+	/*! This array represents the format's framing size if present. */
+	int framing[AST_CODEC_PREF_SIZE];
+};
+
+/*! \page AudioCodecPref Audio Codec Preferences
+
+	In order to negotiate audio codecs in the order they are configured
+	in \<channel\>.conf for a device, we set up codec preference lists
+	in addition to the codec capabilities setting. The capabilities
+	setting is a bitmask of audio and video codecs with no internal
+	order. This will reflect the offer given to the other side, where
+	the prefered codecs will be added to the top of the list in the
+	order indicated by the "allow" lines in the device configuration.
+
+	Video codecs are not included in the preference lists since they
+	can't be transcoded and we just have to pick whatever is supported
+*/
+
+/*!
+ *\brief Initialize an audio codec preference to "no preference".
+ * \arg \ref AudioCodecPref
+*/
+void ast_codec_pref_init(struct ast_codec_pref *pref);
+
+/*!
+ * \brief Codec located at a particular place in the preference index.
+ * \param preference structure to get the codec out of
+ * \param index to retrieve from
+ * \param retult ast_format structure to store the index value in
+ * \return pointer to input ast_format on success, NULL on failure
+*/
+struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int index, struct ast_format *result);
+
+/*! \brief Remove audio a codec from a preference list */
+void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format);
+
+/*! \brief Append a audio codec to a preference list, removing it first if it was already there
+*/
+int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format);
+
+/*! \brief Prepend an audio codec to a preference list, removing it first if it was already there
+*/
+void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing);
+
+/*! \brief Select the best audio format according to preference list from supplied options.
+ * Best audio format is returned in the result format.
+ *
+ * \note If "find_best" is non-zero then if nothing is found, the "Best" format of
+ * the format list is selected and returned in the result structure, otherwise
+ * NULL is returned
+ *
+ * \retval ptr to result struture.
+ * \retval NULL, best codec was not found
+ */
+struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result);
+
+/*! \brief Set packet size for codec
+*/
+int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems);
+
+/*! \brief Get packet size for codec
+*/
+struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format);
+
+/*! \brief Dump audio codec preference list into a string */
+int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size);
+
+/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string
+ * \note Due to a misunderstanding in how codec preferences are stored, this
+ * list starts at 'B', not 'A'.  For backwards compatibility reasons, this
+ * cannot change.
+ * \param pref A codec preference list structure
+ * \param buf A string denoting codec preference, appropriate for use in line transmission
+ * \param size Size of \a buf
+ * \param right Boolean:  if 0, convert from \a buf to \a pref; if 1, convert from \a pref to \a buf.
+ */
+void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right);
+
+#endif /* _AST_FORMATPREF_H */
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 20f40f8..0ac0d5f 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -31,6 +31,7 @@ extern "C" {
 
 #include <sys/time.h>
 
+#include "asterisk/format_pref.h"
 #include "asterisk/format.h"
 #include "asterisk/endian.h"
 #include "asterisk/linkedlists.h"
@@ -38,11 +39,11 @@ extern "C" {
 /*!
  * \page Def_Frame AST Multimedia and signalling frames
  * \section Def_AstFrame What is an ast_frame ?
- * A frame of data read used to communicate between
+ * A frame of data read used to communicate between 
  * between channels and applications.
  * Frames are divided into frame types and subclasses.
  *
- * \par Frame types
+ * \par Frame types 
  * \arg \b VOICE:  Voice data, subclass is codec (AST_FORMAT_*)
  * \arg \b VIDEO:  Video data, subclass is codec (AST_FORMAT_*)
  * \arg \b DTMF:   A DTMF digit, subclass is the digit
@@ -87,7 +88,7 @@ extern "C" {
  */
 
 /*!
- * \brief Frame types
+ * \brief Frame types 
  *
  * \note It is important that the values of each frame type are never changed,
  *       because it will break backwards compatability with older versions.
@@ -112,21 +113,13 @@ enum ast_frame_type {
 	AST_FRAME_IMAGE,
 	/*! HTML Frame */
 	AST_FRAME_HTML,
-	/*! Comfort Noise frame (subclass is level of CNG in -dBov),
+	/*! Comfort Noise frame (subclass is level of CNG in -dBov), 
 	    body may include zero or more 8-bit quantization coefficients */
 	AST_FRAME_CNG,
 	/*! Modem-over-IP data streams */
-	AST_FRAME_MODEM,
+	AST_FRAME_MODEM,	
 	/*! DTMF begin event, subclass is the digit */
 	AST_FRAME_DTMF_BEGIN,
-	/*! Internal bridge module action. */
-	AST_FRAME_BRIDGE_ACTION,
-	/*! Internal synchronous bridge module action.
-	 * Synchronous bridge actions may be queued onto bridge
-	 * channels, but they absolutely must not ever be written
-	 * directly into bridges.
-	 */
-	AST_FRAME_BRIDGE_ACTION_SYNC,
 };
 #define AST_FRAME_DTMF AST_FRAME_DTMF_END
 
@@ -135,37 +128,33 @@ enum {
 	AST_FRFLAG_HAS_TIMING_INFO = (1 << 0),
 };
 
-struct ast_frame_subclass {
-	/*! A frame specific code */
+union ast_frame_subclass {
 	int integer;
-	/*! The asterisk media format */
-	struct ast_format *format;
-	/*! For video formats, an indication that a frame ended */
-	unsigned int frame_ending;
+	struct ast_format format;
 };
 
 /*! \brief Data structure associated with a single frame of data
  */
 struct ast_frame {
 	/*! Kind of frame */
-	enum ast_frame_type frametype;
+	enum ast_frame_type frametype;				
 	/*! Subclass, frame dependent */
-	struct ast_frame_subclass subclass;
+	union ast_frame_subclass subclass;
 	/*! Length of data */
-	int datalen;
+	int datalen;				
 	/*! Number of samples in this frame */
-	int samples;
+	int samples;				
 	/*! Was the data malloc'd?  i.e. should we free it when we discard the frame? */
-	int mallocd;
+	int mallocd;				
 	/*! The number of bytes allocated for a malloc'd frame header */
 	size_t mallocd_hdr_len;
 	/*! How many bytes exist _before_ "data" that can be used if needed */
-	int offset;
+	int offset;				
 	/*! Optional source of frame for debugging */
-	const char *src;
+	const char *src;				
 	/*! Pointer to actual data */
 	union { void *ptr; uint32_t uint32; char pad[8]; } data;
-	/*! Global delivery time */
+	/*! Global delivery time */		
 	struct timeval delivery;
 	/*! For placing in a linked list */
 	AST_LIST_ENTRY(ast_frame) frame_list;
@@ -208,7 +197,7 @@ extern struct ast_frame ast_null_frame;
  * RTP header information into the space provided by AST_FRIENDLY_OFFSET instead
  * of having to create a new buffer with the necessary space allocated.
  */
-#define AST_FRIENDLY_OFFSET 	64
+#define AST_FRIENDLY_OFFSET 	64	
 #define AST_MIN_OFFSET 		32	/*! Make sure we keep at least this much handy */
 
 /*! Need the header be free'd? */
@@ -290,7 +279,6 @@ enum ast_control_frame_type {
 	AST_CONTROL_MCID = 31,			/*!< Indicate that the caller is being malicious. */
 	AST_CONTROL_UPDATE_RTP_PEER = 32, /*!< Interrupt the bridge and have it update the peer */
 	AST_CONTROL_PVT_CAUSE_CODE = 33, /*!< Contains an update to the protocol-specific cause-code stored for branching dials */
-	AST_CONTROL_MASQUERADE_NOTIFY = 34,	/*!< A masquerade is about to begin/end. (Never sent as a frame but directly with ast_indicate_data().) */
 
 	/*
 	 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
@@ -305,20 +293,6 @@ enum ast_control_frame_type {
 	 *
 	 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 	 */
-
-	/* Control frames used to manipulate a stream on a channel. The values for these
-	 * must be greater than the allowed value for a 8-bit char, so that they avoid
-	 * conflicts with DTMF values. */
-	AST_CONTROL_STREAM_STOP = 1000,		/*!< Indicate to a channel in playback to stop the stream */
-	AST_CONTROL_STREAM_SUSPEND = 1001,	/*!< Indicate to a channel in playback to suspend the stream */
-	AST_CONTROL_STREAM_RESTART = 1002,	/*!< Indicate to a channel in playback to restart the stream */
-	AST_CONTROL_STREAM_REVERSE = 1003,	/*!< Indicate to a channel in playback to rewind */
-	AST_CONTROL_STREAM_FORWARD = 1004,	/*!< Indicate to a channel in playback to fast forward */
-	/* Control frames to manipulate recording on a channel. */
-	AST_CONTROL_RECORD_CANCEL = 1100,	/*!< Indicated to a channel in record to stop recording and discard the file */
-	AST_CONTROL_RECORD_STOP = 1101,	/*!< Indicated to a channel in record to stop recording */
-	AST_CONTROL_RECORD_SUSPEND = 1102,	/*!< Indicated to a channel in record to suspend/unsuspend recording */
-	AST_CONTROL_RECORD_MUTE = 1103,	/*!< Indicated to a channel in record to mute/unmute (i.e. write silence) recording */
 };
 
 enum ast_frame_read_action {
@@ -388,6 +362,9 @@ struct ast_control_pvt_cause_code {
 	char code[1];				/*!< Tech-specific cause code information, beginning with the name of the tech */
 };
 
+#define AST_SMOOTHER_FLAG_G729		(1 << 0)
+#define AST_SMOOTHER_FLAG_BE		(1 << 1)
+
 /* Option identifiers and flags */
 #define AST_OPTION_FLAG_REQUEST		0
 #define AST_OPTION_FLAG_ACCEPT		1
@@ -396,10 +373,10 @@ struct ast_control_pvt_cause_code {
 #define AST_OPTION_FLAG_ANSWER		5
 #define AST_OPTION_FLAG_WTF		6
 
-/*! Verify touchtones by muting audio transmission
+/*! Verify touchtones by muting audio transmission 
  * (and reception) and verify the tone is still present
  * Option data is a single signed char value 0 or 1 */
-#define AST_OPTION_TONE_VERIFY		1
+#define AST_OPTION_TONE_VERIFY		1		
 
 /*! Put a compatible channel into TDD (TTY for the hearing-impared) mode
  * Option data is a single signed char value 0 or 1 */
@@ -413,7 +390,7 @@ struct ast_control_pvt_cause_code {
  * Option data is a single signed char value 0 or 1 */
 #define	AST_OPTION_AUDIO_MODE		4
 
-/*! Set channel transmit gain
+/*! Set channel transmit gain 
  * Option data is a single signed char representing number of decibels (dB)
  * to set gain to (on top of any gain specified in channel driver) */
 #define AST_OPTION_TXGAIN		5
@@ -423,7 +400,7 @@ struct ast_control_pvt_cause_code {
  * to set gain to (on top of any gain specified in channel driver) */
 #define AST_OPTION_RXGAIN		6
 
-/* set channel into "Operator Services" mode
+/* set channel into "Operator Services" mode 
  * Option data is a struct oprmode
  *
  * \note This option should never be sent over the network */
@@ -476,7 +453,7 @@ struct ast_control_pvt_cause_code {
  * Option data is a character buffer of suitable length */
 #define AST_OPTION_DEVICE_NAME		16
 
-/*! Get the CC agent type from the channel (Read only)
+/*! Get the CC agent type from the channel (Read only) 
  * Option data is a character buffer of suitable length */
 #define AST_OPTION_CC_AGENT_TYPE    17
 
@@ -493,12 +470,12 @@ struct oprmode {
 struct ast_option_header {
 	/* Always keep in network byte order */
 #if __BYTE_ORDER == __BIG_ENDIAN
-	uint16_t flag:3;
-	uint16_t option:13;
+        uint16_t flag:3;
+        uint16_t option:13;
 #else
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	uint16_t option:13;
-	uint16_t flag:3;
+        uint16_t option:13;
+        uint16_t flag:3;
 #else
 #error Byte order not defined
 #endif
@@ -506,19 +483,19 @@ struct ast_option_header {
 		uint8_t data[0];
 };
 
-/*! \brief  Requests a frame to be allocated
- *
- * \param source
- * Request a frame be allocated.  source is an optional source of the frame,
- * len is the requested length, or "0" if the caller will supply the buffer
+/*! \brief  Requests a frame to be allocated 
+ * 
+ * \param source 
+ * Request a frame be allocated.  source is an optional source of the frame, 
+ * len is the requested length, or "0" if the caller will supply the buffer 
  */
 #if 0 /* Unimplemented */
 struct ast_frame *ast_fralloc(char *source, int len);
 #endif
 
-/*!
+/*!  
  * \brief Frees a frame or list of frames
- *
+ * 
  * \param fr Frame to free, or head of list to free
  * \param cache Whether to consider this frame for frame caching
  */
@@ -526,12 +503,6 @@ void ast_frame_free(struct ast_frame *fr, int cache);
 
 #define ast_frfree(fr) ast_frame_free(fr, 1)
 
-/*!
- * \brief NULL-safe wrapper for \ref ast_frfree, good for \ref RAII_VAR.
- * \param frame Frame to free, or head of list to free.
- */
-void ast_frame_dtor(struct ast_frame *frame);
-
 /*! \brief Makes a frame independent of any static storage
  * \param fr frame to act upon
  * Take a frame, and if it's not been malloc'd, make a malloc'd copy
@@ -547,7 +518,7 @@ void ast_frame_dtor(struct ast_frame *frame);
  */
 struct ast_frame *ast_frisolate(struct ast_frame *fr);
 
-/*! \brief Copies a frame
+/*! \brief Copies a frame 
  * \param fr frame to copy
  * Duplicates a frame -- should only rarely be used, typically frisolate is good enough
  * \return Returns a frame on success, NULL on error
@@ -556,7 +527,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *fr);
 
 void ast_swapcopy_samples(void *dst, const void *src, int samples);
 
-/* Helpers for byteswapping native samples to/from
+/* Helpers for byteswapping native samples to/from 
    little-endian and big-endian. */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define ast_frame_byteswap_le(fr) do { ; } while(0)
@@ -566,11 +537,77 @@ void ast_swapcopy_samples(void *dst, const void *src, int samples);
 #define ast_frame_byteswap_be(fr) do { ; } while(0)
 #endif
 
+/*! \brief Parse an "allow" or "deny" line in a channel or device configuration
+        and update the capabilities and pref if provided.
+	Video codecs are not added to codec preference lists, since we can not transcode
+	\return Returns number of errors encountered during parsing
+ */
+int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing);
+
+/*! \name AST_Smoother 
+*/
+/*@{ */
+/*! \page ast_smooth The AST Frame Smoother
+The ast_smoother interface was designed specifically
+to take frames of variant sizes and produce frames of a single expected
+size, precisely what you want to do.
+
+The basic interface is:
+
+- Initialize with ast_smoother_new()
+- Queue input frames with ast_smoother_feed()
+- Get output frames with ast_smoother_read()
+- when you're done, free the structure with ast_smoother_free()
+- Also see ast_smoother_test_flag(), ast_smoother_set_flags(), ast_smoother_get_flags(), ast_smoother_reset()
+*/
+struct ast_smoother;
+
+struct ast_smoother *ast_smoother_new(int bytes);
+void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
+int ast_smoother_get_flags(struct ast_smoother *smoother);
+int ast_smoother_test_flag(struct ast_smoother *s, int flag);
+void ast_smoother_free(struct ast_smoother *s);
+void ast_smoother_reset(struct ast_smoother *s, int bytes);
+
+/*!
+ * \brief Reconfigure an existing smoother to output a different number of bytes per frame
+ * \param s the smoother to reconfigure
+ * \param bytes the desired number of bytes per output frame
+ * \return nothing
+ *
+ */
+void ast_smoother_reconfigure(struct ast_smoother *s, int bytes);
+
+int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
+struct ast_frame *ast_smoother_read(struct ast_smoother *s);
+#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1)
+#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0)
+#else
+#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0)
+#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1)
+#endif
+/*@} Doxygen marker */
+
 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix);
 
+/*! \brief Returns the number of samples contained in the frame */
+int ast_codec_get_samples(struct ast_frame *f);
+
+/*! \brief Returns the number of bytes for the number of samples of the given format */
+int ast_codec_get_len(struct ast_format *format, int samples);
+
 /*! \brief Appends a frame to the end of a list of frames, truncating the maximum length of the list */
 struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe);
 
+
+/*! \brief Gets duration in ms of interpolation frame for a format */
+static inline int ast_codec_interp_len(struct ast_format *format)
+{ 
+	return (format->id == AST_FORMAT_ILBC) ? 30 : 20;
+}
+
 /*!
   \brief Adjusts the volume of the audio samples contained in a frame.
   \param f The frame containing the samples (must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR)
diff --git a/include/asterisk/frame_defs.h b/include/asterisk/frame_defs.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/asterisk/framehook.h b/include/asterisk/framehook.h
index d388f2e..0b2e6cd 100644
--- a/include/asterisk/framehook.h
+++ b/include/asterisk/framehook.h
@@ -25,114 +25,114 @@
 \page AstFrameHookAPI Asterisk FrameHook API
 
 \section FrameHookFunctionality How FrameHooks Work
-	FrameHooks work by intercepting all frames being written and read off
-	a channel and allowing those frames to be viewed and manipulated within a
-	call back function.  Frame interception occurs before any processing is
-	done on the frame, which means this hook can be used to transparently
-	manipulate a frame before it is read from the channel or written
-	to the tech_pvt.  This API can be thought of as a layer between the
-	channel API and the Asterisk core when going in the READ direction, and
-	as a layer between the Channel API and the tech_pvt when going in the
-	WRITE direction.
+    FrameHooks work by intercepting all frames being written and read off
+    a channel and allowing those frames to be viewed and manipulated within a
+    call back function.  Frame interception occurs before any processing is
+    done on the frame, which means this hook can be used to transparently
+    manipulate a frame before it is read from the channel or written
+    to the tech_pvt.  This API can be thought of as a layer between the
+    channel API and the Asterisk core when going in the READ direction, and
+    as a layer between the Channel API and the tech_pvt when going in the
+    WRITE direction.
 
 \section FrameHookAPIUsage How to Use an FrameHook
-	Attaching and detaching an FrameHook to a channel is very simple.  There are only
-	two functions involved, ast_framehook_attach() which will return an id representing
-	the new FrameHook on the channel, and ast_framehook_detach() which signals the
-	FrameHook for detachment and destruction. Below is detailed information each of these
-	functions and their usage.
+    Attaching and detaching an FrameHook to a channel is very simple.  There are only
+    two functions involved, ast_framehook_attach() which will return an id representing
+    the new FrameHook on the channel, and ast_framehook_detach() which signals the
+    FrameHook for detachment and destruction. Below is detailed information each of these
+    functions and their usage.
 
 \code
-	struct ast_framehook_interface interface = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = hook_event_cb,
-		.destroy_cb = hook_destroy_cb,
-		.data = data, // where the data ptr points to any custom data used later by the hook cb.
-	};
-	int id = ast_framehook_attach(channel, &interface);
+    struct ast_framehook_interface interface = {
+        .version = AST_FRAMEHOOK_INTERFACE_VERSION,
+        .event_cb = hook_event_cb,
+        .destroy_cb = hook_destroy_cb,
+        .data = data, // where the data ptr points to any custom data used later by the hook cb.
+    };
+    int id = ast_framehook_attach(channel, &interface);
 \endcode
 
-	The ast_framehook_attach() function creates and attaches a new FrameHook onto
-	a channel. Once attached to the channel, the FrameHook will call the event_callback
-	function each time a frame is written or read on the channel.  A custom data
-	pointer can be provided to this function to store on the FrameHook as well.  This
-	pointer can be used to keep up with any statefull information associated with the FrameHook
-	and is provided during the event_callback function.  The destroy_callback function is optional.
-	This function exists so any custom data stored on the FrameHook can be destroyed before
-	the Framehook if destroyed.
+    The ast_framehook_attach() function creates and attaches a new FrameHook onto
+    a channel. Once attached to the channel, the FrameHook will call the event_callback
+    function each time a frame is written or read on the channel.  A custom data
+    pointer can be provided to this function to store on the FrameHook as well.  This
+    pointer can be used to keep up with any statefull information associated with the FrameHook
+    and is provided during the event_callback function.  The destroy_callback function is optional.
+    This function exists so any custom data stored on the FrameHook can be destroyed before
+    the Framehook if destroyed.
 
 \code
-	ast_framehook_detach(channel, id);
+    ast_framehook_detach(channel, id);
 \endcode
 
-	The ast_framehook_detach() function signals the FrameHook represented by an id to
-	be detached and destroyed on a channel.  Since it is possible this function may be called
-	during the FrameHook's event callback, it is impossible to synchronously detach the
-	FrameHook from the channel during this function call.  It is guaranteed that the next
-	event proceeding the ast_framehook_detach() will be of type AST_FRAMEHOOK_EVENT_DETACH,
-	and that after that event occurs no other event will ever be issued for that FrameHook.
-	Once the FrameHook is destroyed, the destroy callback function will be called if it was
-	provided. Note that if this function is never called, the FrameHook will be detached
-	on channel destruction.
+    The ast_framehook_detach() function signals the FrameHook represented by an id to
+    be detached and destroyed on a channel.  Since it is possible this function may be called
+    during the FrameHook's event callback, it is impossible to synchronously detach the
+    FrameHook from the channel during this function call.  It is guaranteed that the next
+    event proceeding the ast_framehook_detach() will be of type AST_FRAMEHOOK_EVENT_DETACH,
+    and that after that event occurs no other event will ever be issued for that FrameHook.
+    Once the FrameHook is destroyed, the destroy callback function will be called if it was
+    provided. Note that if this function is never called, the FrameHook will be detached
+    on channel destruction.
 
 \section FrameHookAPICodeExample FrameHook Example Code
-	The example code below attaches an FrameHook on a channel, and then detachs it when
-	the first ast_frame is read or written to the event callback function.  The Framehook's id
-	is stored on the FrameHook's data pointer so it can be detached within the callback.
+    The example code below attaches an FrameHook on a channel, and then detachs it when
+    the first ast_frame is read or written to the event callback function.  The Framehook's id
+    is stored on the FrameHook's data pointer so it can be detached within the callback.
 
 \code
-	static void destroy_cb(void *data) {
-		ast_free(data);
-	}
-
-	static struct ast_frame *event_cb(struct ast_channel *chan,
-			struct ast_frame *frame,
-			enum ast_framehook_event event,
-			void *data) {
-
-		int *id = data;
-
-		if (!frame) {
-			return frame;
-		}
-
-		if (event == AST_FRAMEHOOK_EVENT_WRITE) {
-			ast_log(LOG_NOTICE, "YAY we received a frame in the write direction, Type: %d\n", frame->frametype)
-			ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
-		} else if (event == AST_FRAMEHOOK_EVENT_READ) {
-			ast_log(LOG_NOTICE, "YAY we received a frame in the read direction: Type: %d\n", frame->frametype);
-			ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
-		}
-
-		return frame;
-	{
-
-	int some_function()
-	{
-		struct ast_framehook_interface interface = {
-			.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-			.event_cb = hook_event_cb,
-			.destroy_cb = hook_destroy_cb,
-		};
-		int *id = ast_calloc(1, sizeof(int));
-
-		if (!id) {
-			return -1;
-		}
-
-		interface.data = id; // This data will be returned to us in the callbacks.
-
-		ast_channel_lock(chan);
-		*id = ast_framehook_attach(chan, &interface);
-		ast_channel_unlock(chan);
-
-		if (*id < 0) {
-			// framehook attach failed, free data
-			ast_free(id);
-			return -1;
-		}
-		return 0;
-	}
+    static void destroy_cb(void *data) {
+	    ast_free(data);
+    }
+
+    static struct ast_frame *event_cb(struct ast_channel *chan,
+            struct ast_frame *frame,
+            enum ast_framehook_event event,
+            void *data) {
+
+        int *id = data;
+
+        if (!frame) {
+            return frame;
+        }
+
+        if (event == AST_FRAMEHOOK_EVENT_WRITE) {
+            ast_log(LOG_NOTICE, "YAY we received a frame in the write direction, Type: %d\n", frame->frametype)
+            ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
+        } else if (event == AST_FRAMEHOOK_EVENT_READ) {
+            ast_log(LOG_NOTICE, "YAY we received a frame in the read direction: Type: %d\n", frame->frametype);
+            ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
+        }
+
+        return frame;
+    {
+
+    int some_function()
+    {
+        struct ast_framehook_interface interface = {
+            .version = AST_FRAMEHOOK_INTERFACE_VERSION,
+            .event_cb = hook_event_cb,
+            .destroy_cb = hook_destroy_cb,
+        };
+        int *id = ast_calloc(1, sizeof(int));
+
+        if (!id) {
+            return -1;
+        }
+
+        interface.data = id; // This data will be returned to us in the callbacks.
+
+        ast_channel_lock(chan);
+        *id = ast_framehook_attach(chan, &interface);
+        ast_channel_unlock(chan);
+
+        if (*id < 0) {
+            // framehook attach failed, free data
+            ast_free(id);
+            return -1;
+        }
+        return 0;
+    }
 \endcode
 */
 
@@ -199,32 +199,7 @@ typedef struct ast_frame *(*ast_framehook_event_callback)(
  */
 typedef void (*ast_framehook_destroy_callback)(void *data);
 
-/*!
- * \brief This callback is called to determine if the framehook is currently consuming
- * frames of a given type
- * \since 12
- *
- * \param data, The data pointer provided at framehook initilization.
- * \param type, The type of frame.
- *
- * \return 0 if frame type is being ignored
- * \return 1 if frame type is not being ignored
- */
-typedef int (*ast_framehook_consume_callback)(void *data, enum ast_frame_type type);
-
-/*!
- * \brief This callback is called when a masquerade occurs on a channel with a framehook
- * \since 12
- *
- * \param data, The data pointer provided at framehook initialization.
- * \param framehook_id, The framehook ID where the framehook lives now
- * \param old_chan, The channel that was masqueraded.
- * \param new_chan, The channel that the masqueraded channel became.
- */
-typedef void (*ast_framehook_chan_fixup_callback)(void *data, int framehook_id,
-	struct ast_channel *old_chan, struct ast_channel *new_chan);
-
-#define AST_FRAMEHOOK_INTERFACE_VERSION 4
+#define AST_FRAMEHOOK_INTERFACE_VERSION 1
 /*! This interface is required for attaching a framehook to a channel. */
 struct ast_framehook_interface {
 	/*! framehook interface version number */
@@ -234,21 +209,6 @@ struct ast_framehook_interface {
 	/*! destroy_cb is optional.  This function is called immediately before the framehook
 	 * is destroyed to allow for stored_data cleanup. */
 	ast_framehook_destroy_callback destroy_cb;
-	/*! consume_cb is optional. This function is called to query whether the framehook is consuming
-	* frames of a specific type at this time. If this callback is not implemented it is assumed that the
-	* framehook will consume frames of all types. */
-	ast_framehook_consume_callback consume_cb;
-	/*! chan_fixup_cb is optional. This function is called when the channel that a framehook is running
-	 * on is masqueraded and should be used to move any essential framehook data onto the channel the
-	 * old channel was masqueraded to. */
-	ast_framehook_chan_fixup_callback chan_fixup_cb;
-	/*! chan_breakdown_cb is optional. This function is called when another channel is masqueraded into
-	 * the channel that a framehook is running on and should be used to evaluate whether the framehook
-	 * should remain on the channel. */
-	ast_framehook_chan_fixup_callback chan_breakdown_cb;
-	/*! disable_inheritance is optional. If set to non-zero, when a channel using this framehook is
-	 * masqueraded, detach and destroy the framehook instead of moving it to the new channel. */
-	int disable_inheritance;
 	 /*! This pointer can represent any custom data to be stored on the !framehook. This
 	 * data pointer will be provided during each event callback which allows the framehook
 	 * to store any stateful data associated with the application using the hook. */
@@ -259,16 +219,16 @@ struct ast_framehook_interface {
  * \brief Attach an framehook onto a channel for frame interception.
  * \since 1.8
  *
- * \param chan ast_channel The channel to attach the hook on to.
- * \param i framehook interface, The framehook's callback functions and stored data.
- *
- * \pre The Channel must be locked during this function call.
+ * \param ast_channel, The channel to attach the hook on to.
+ * \param framehook interface, The framehook's callback functions and stored data.
+*
+ * \pre XXX The Channel must be locked during this function all.
  *
  * \note The data pointer is never touched by the framehook API except to
  * provide it during the event and destruction callbacks.  It is entirely up to the
  * application using this API to manage the memory associated with the data pointer.
  *
- * \retval On success, non-negative id representing this hook on the channel
+ * \retval On success, positive id representing this hook on the channel 
  * \retval On failure, -1
  */
 int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i);
@@ -277,13 +237,13 @@ int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interfac
  * \brief Detach an framehook from a channel.
  * \since 1.8
  * 
- * \pre The Channel must be locked during this function call.
+ * \pre XXX The Channel must be locked during this function all.
  * If this function is never called after attaching an framehook,
  * the framehook will be detached and destroyed during channel
  * destruction.
  *
- * \param chan The channel the framehook is attached to
- * \param framehook_id The framehook's id
+ * \param The channel the framehook is attached to
+ * \param The framehook's id
  *
  * \retval 0 success
  * \retval -1 framehook did not exist on the channel. This means the
@@ -296,27 +256,15 @@ int ast_framehook_detach(struct ast_channel *chan, int framehook_id);
  * framehooks on a channel during channel destruction.
  * \since 1.8
  *
- * \pre The Channel must be locked during this function call.
+ * \pre XXX The Channel must be locked during this function all.
  * 
- * \param chan channel containing the framehook list to destroy.
+ * \param channel containing the framehook list to destroy.
  * \retval 0 success
  * \retval -1 failure
  */
 int ast_framehook_list_destroy(struct ast_channel *chan);
 
 /*!
- * \brief This is used by the channel API during a masquerade operation
- * to move all mobile framehooks from the original channel to the clone channel.
- * \since 12.5.0
- *
- * \pre Both channels must be locked prior to this function call.
- *
- * \param old_chan The channel being cloned from
- * \param new_chan The channel being cloned to
- */
-void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan);
-
-/*!
  * \brief This is used by the channel API push a frame read event to a channel's framehook list.
  * \since 1.8
  *
@@ -324,9 +272,9 @@ void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * framehook callback is in charge of any memory management associated with that modification.
  *
- * \pre The Channel must be locked during this function call.
+ * \pre XXX The Channel must be locked during this function all.
  *
- * \param framehooks list to push event to.
+ * \param framehook list to push event to.
  * \param frame being pushed to the framehook list.
  *
  * \return The resulting frame after being viewed and modified by the framehook callbacks.
@@ -341,9 +289,9 @@ struct ast_frame *ast_framehook_list_read_event(struct ast_framehook_list *frame
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * framehook callback is in charge of any memory management associated with that modification.
  *
- * \pre The Channel must be locked during this function call.
+ * \pre XXX The Channel must be locked during this function all.
  *
- * \param framehooks list to push event to.
+ * \param framehook list to push event to.
  * \param frame being pushed to the framehook list.
  *
  * \return The resulting frame after being viewed and modified by the framehook callbacks.
@@ -353,41 +301,11 @@ struct ast_frame *ast_framehook_list_write_event(struct ast_framehook_list *fram
 /*!
  * \brief Determine if an framehook list is empty or not
  * \since 1.8
- * \pre The Channel must be locked during this function call.
+ * \pre XXX The Channel must be locked during this function all.
  *
- * \param framehooks the framehook list
+ * \param the framehook list
  * \retval 0, not empty
  * \retval 1, is empty
  */
 int ast_framehook_list_is_empty(struct ast_framehook_list *framehooks);
-
-/*!
- * \brief Determine if a framehook list is free of active framehooks or not
- * \since 12.0.0
- * \pre The channel must be locked during this function call.
- *
- * \param framehooks the framehook list
- * \retval 0, not empty
- * \retval 1, is empty (aside from dying framehooks)
- *
- * \note This function is very similar to ast_framehook_list_is_empty, but it checks individual
- *       framehooks to see if they have been marked for destruction and doesn't count them if they are.
- */
-int ast_framehook_list_contains_no_active(struct ast_framehook_list *framehooks);
-
-/*!
- * \brief Determine if a framehook list is free of active framehooks consuming a specific type of frame
- * \since 12.3.0
- * \pre The channel must be locked during this function call.
- *
- * \param framehooks the framehook list
- * \retval 0, not empty
- * \retval 1, is empty (aside from dying framehooks)
- *
- * \note This function is very similar to ast_framehook_list_is_empty, but it checks individual
- *       framehooks to see if they have been marked for destruction and doesn't count them if they are.
- */
-int ast_framehook_list_contains_no_active_of_type(struct ast_framehook_list *framehooks,
-	enum ast_frame_type type);
-
 #endif /* _AST_FRAMEHOOK_H */
diff --git a/include/asterisk/heap.h b/include/asterisk/heap.h
index a868ac5..86f4e3d 100644
--- a/include/asterisk/heap.h
+++ b/include/asterisk/heap.h
@@ -213,7 +213,6 @@ size_t ast_heap_size(struct ast_heap *h);
  * \brief Write-Lock a heap
  *
  * \param h the heap
- * \param file, func, line
  *
  * A lock is provided for convenience.  It can be assumed that none of the
  * ast_heap API calls are thread safe.  This lock does not have to be used
@@ -228,7 +227,6 @@ int __ast_heap_wrlock(struct ast_heap *h, const char *file, const char *func, in
  * \brief Read-Lock a heap
  *
  * \param h the heap
- * \param file, func, line
  *
  * A lock is provided for convenience.  It can be assumed that none of the
  * ast_heap API calls are thread safe.  This lock does not have to be used
@@ -243,7 +241,6 @@ int __ast_heap_rdlock(struct ast_heap *h, const char *file, const char *func, in
  * \brief Unlock a heap
  *
  * \param h the heap
- * \param file, func, line
  *
  * \return see the documentation for pthread_rwlock_unlock()
  * \since 1.6.1
diff --git a/include/asterisk/http.h b/include/asterisk/http.h
index ad91823..3400240 100644
--- a/include/asterisk/http.h
+++ b/include/asterisk/http.h
@@ -58,42 +58,33 @@ enum ast_http_method {
 	AST_HTTP_GET = 0,
 	AST_HTTP_POST,
 	AST_HTTP_HEAD,
-	AST_HTTP_PUT,
-	AST_HTTP_DELETE,
-	AST_HTTP_OPTIONS,
-	AST_HTTP_MAX_METHOD, /*!< Last entry in ast_http_method enum */
+	AST_HTTP_PUT,            /*!< Not supported in Asterisk */
 };
 
 struct ast_http_uri;
 
-/*!
- * \brief HTTP Callbacks
- *
- * \param ser TCP/TLS session object
- * \param urih Registered URI handler struct for the URI.
- * \param uri Remaining request URI path (also with the get_params removed).
- * \param method enum ast_http_method GET, POST, etc.
- * \param get_params URI argument list passed with the HTTP request.
- * \param headers HTTP request header-name/value pair list
+/*! \brief HTTP Callbacks
  *
- * \note Should use the ast_http_send() function for sending content
- * allocated with ast_str and/or content from an opened file descriptor.
+ * \note The callback function receives server instance, uri, http method,
+ * get method (if present in URI), and http headers as arguments and should
+ * use the ast_http_send() function for sending content allocated with ast_str
+ * and/or content from an opened file descriptor.
  *
  * Status and status text should be sent as arguments to the ast_http_send()
  * function to reflect the status of the request (200 or 304, for example).
  * Content length is calculated by ast_http_send() automatically.
  *
- * Static content may be indicated to the ast_http_send() function,
- * to indicate that it may be cached.
- *
- * For a need authentication response, the ast_http_auth() function
- * should be used.
+ * Static content may be indicated to the ast_http_send() function, to indicate
+ * that it may be cached.
  *
- * For an error response, the ast_http_error() function should be used.
+ * \verbatim
+ * The return value may include additional headers at the front and MUST
+ * include a blank line with \r\n to provide separation between user headers
+ * and content (even if no content is specified)
+ * \endverbatim
  *
- * \retval 0 Continue and process the next HTTP request.
- * \retval -1 Fatal HTTP connection error.  Force the HTTP connection closed.
- */
+ * For an error response, the ast_http_error() function may be used.
+*/
 typedef int (*ast_http_callback)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers);
 
 /*! \brief Definition of a URI handler */
@@ -107,8 +98,6 @@ struct ast_http_uri {
 	unsigned int mallocd:1;
 	/*! Data structure is malloc'd */
 	unsigned int dmallocd:1;
-	/*! Don't automatically decode URI before passing it to the callback */
-	unsigned int no_decode_uri:1;
 	/*! Data to bind to the uri if needed */
 	void *data;
 	/*! Key to be used for unlinking if multiple URIs registered */
@@ -118,26 +107,6 @@ struct ast_http_uri {
 /*! \brief Get cookie from Request headers */
 struct ast_variable *ast_http_get_cookies(struct ast_variable *headers);
 
-/*! \brief HTTP authentication information. */
-struct ast_http_auth {
-	/*! Provided userid. */
-	char *userid;
-	/*! For Basic auth, the provided password. */
-	char *password;
-};
-
-/*!
- * \brief Get HTTP authentication information from headers.
- *
- * The returned object is AO2 managed, so clean up with ao2_cleanup().
- *
- * \param headers HTTP request headers.
- * \return HTTP auth structure.
- * \return \c NULL if no supported HTTP auth headers present.
- * \since 12
- */
-struct ast_http_auth *ast_http_get_auth(struct ast_variable *headers);
-
 /*! \brief Register a URI handler */
 int ast_http_uri_link(struct ast_http_uri *urihandler);
 
@@ -147,30 +116,26 @@ void ast_http_uri_unlink(struct ast_http_uri *urihandler);
 /*! \brief Unregister all handlers with matching key */
 void ast_http_uri_unlink_all_with_key(const char *key);
 
-/*!
- * \brief Return http method name string
+/*!\brief Return http method name string
  * \since 1.8
  */
 const char *ast_get_http_method(enum ast_http_method method) attribute_pure;
 
-/*!
- * \brief Return mime type based on extension
+/*!\brief Return mime type based on extension
  * \param ftype filename extension
  * \return String containing associated MIME type
  * \since 1.8
  */
 const char *ast_http_ftype2mtype(const char *ftype) attribute_pure;
 
-/*!
- * \brief Return manager id, if exist, from request headers
+/*!\brief Return manager id, if exist, from request headers
  * \param headers List of HTTP headers
  * \return 32-bit associated manager session identifier
  * \since 1.8
  */
 uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure;
 
-/*!
- * \brief Generic function for sending HTTP/1.1 response.
+/*! \brief Generic function for sending http/1.1 response.
  * \param ser TCP/TLS session object
  * \param method GET/POST/HEAD
  * \param status_code HTTP response code (200/401/403/404/500)
@@ -196,14 +161,12 @@ uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure;
  *
  * \since 1.8
  */
-void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method,
-	int status_code, const char *status_title, struct ast_str *http_header,
-	struct ast_str *out, int fd, unsigned int static_content);
+void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content);
 
-/*! \brief Send http "401 Unauthorized" response and close socket */
+/*!\brief Send http "401 Unauthorized" response and close socket */
 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text);
 
-/*! \brief Send HTTP error message and close socket */
+/*!\brief Send HTTP error message and close socket */
 void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text);
 
 /*!
@@ -214,42 +177,8 @@ void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const c
  */
 void ast_http_prefix(char *buf, int len);
 
-/*!
- * \brief Request the HTTP connection be closed after this HTTP request.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \note Call before ast_http_error() to make the connection close.
- *
- * \return Nothing
- */
-void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser);
-
-/*!
- * \brief Update the body read success status.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- * \param read_success TRUE if body was read successfully.
- *
- * \return Nothing
- */
-void ast_http_body_read_status(struct ast_tcptls_session_instance *ser, int read_success);
 
-/*!
- * \brief Read and discard any unread HTTP request body.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_http_body_discard(struct ast_tcptls_session_instance *ser);
-
-/*!
- * \brief Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
+/*!\brief Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
  * \param ser TCP/TLS session object
  * \param headers List of HTTP headers
  * \return List of variables within the POST body
@@ -258,77 +187,5 @@ int ast_http_body_discard(struct ast_tcptls_session_instance *ser);
  */
 struct ast_variable *ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers);
 
-struct ast_json;
-
-/*!
- * \brief Get JSON from client Request Entity-Body, if content type is
- *        application/json.
- * \param ser TCP/TLS session object
- * \param headers List of HTTP headers
- * \return Parsed JSON content body
- * \return \c NULL on error, if no content, or if different content type.
- * \since 12
- */
-struct ast_json *ast_http_get_json(
-	struct ast_tcptls_session_instance *ser, struct ast_variable *headers);
-
-/*!\brief Parse the http response status line.
- *
- * \param buf the http response line information
- * \param version the expected http version (e.g. HTTP/1.1)
- * \param code the expected status code
- * \return -1 if version didn't match or status code conversion fails.
- * \return status code (>0)
- * \since 13
- */
-int ast_http_response_status_line(const char *buf, const char *version, int code);
-
-/*!\brief Parse a header into the given name/value strings.
- *
- * \note This modifies the given buffer and the out parameters point (not
- *       allocated) to the start of the header name and header value,
- *       respectively.
- *
- * \param buf a string containing the name/value to point to
- * \param name out parameter pointing to the header name
- * \param value out parameter pointing to header value
- * \return -1 if buf is empty
- * \return 0 if buf could be separated into into name and value
- * \return 1 if name or value portion don't exist
- * \since 13
- */
-int ast_http_header_parse(char *buf, char **name, char **value);
-
-/*!\brief Check if the header and value match (case insensitive) their
- *        associated expected values.
- *
- * \param name header name to check
- * \param expected_name the expected name of the header
- * \param value header value to check
- * \param expected_value the expected value of the header
- * \return 0 if the name and expected name do not match
- * \return -1 if the value and expected value do not match
- * \return 1 if the both the name and value match their expected value
- * \since 13
- */
-int ast_http_header_match(const char *name, const char *expected_name,
-			  const char *value, const char *expected_value);
-
-/*!\brief Check if the header name matches the expected header name.  If so,
- *        then check to see if the value can be located in the expected value.
- *
- * \note Both header and value checks are case insensitive.
- *
- * \param name header name to check
- * \param expected_name the expected name of the header
- * \param value header value to check if in expected value
- * \param expected_value the expected value(s)
- * \return 0 if the name and expected name do not match
- * \return -1 if the value and is not in the expected value
- * \return 1 if the name matches expected name and value is in expected value
- * \since 13
- */
-int ast_http_header_match_in(const char *name, const char *expected_name,
-			     const char *value, const char *expected_value);
 
 #endif /* _ASTERISK_SRV_H */
diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h
index 3e07e60..5ddd1fb 100644
--- a/include/asterisk/http_websocket.h
+++ b/include/asterisk/http_websocket.h
@@ -19,28 +19,14 @@
 #ifndef _ASTERISK_HTTP_WEBSOCKET_H
 #define _ASTERISK_HTTP_WEBSOCKET_H
 
-#include "asterisk/http.h"
 #include "asterisk/optional_api.h"
 
-#include <errno.h>
-
 /*! \brief Default websocket write timeout, in ms */
 #define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT 100
 
-/*! \brief Default websocket write timeout, in ms (as a string) */
-#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR "100"
-
 /*!
  * \file http_websocket.h
- * \brief Support for WebSocket connections within the Asterisk HTTP server and client
- *        WebSocket connections to a server.
- *
- * Supported WebSocket versions in server implementation:
- *     Version 7 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
- *     Version 8 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
- *     Version 13 defined in specification http://tools.ietf.org/html/rfc6455
- * Supported WebSocket versions in client implementation:
- *     Version 13 defined in specification http://tools.ietf.org/html/rfc6455
+ * \brief Support for WebSocket connections within the Asterisk HTTP server.
  *
  * \author Joshua Colp <jcolp at digium.com>
  *
@@ -57,13 +43,7 @@ enum ast_websocket_opcode {
 };
 
 /*!
- * \brief Opaque structure for WebSocket server.
- * \since 12
- */
-struct ast_websocket_server;
-
-/*!
- * \brief Opaque structure for WebSocket sessions.
+ * \brief Opaque structure for WebSocket sessions
  */
 struct ast_websocket;
 
@@ -81,24 +61,7 @@ struct ast_websocket;
 typedef void (*ast_websocket_callback)(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers);
 
 /*!
- * \brief Creates a \ref websocket_server
- *
- * \retval New \ref websocket_server instance
- * \retval \c NULL on error
- * \since 12
- */
-AST_OPTIONAL_API(struct ast_websocket_server *, ast_websocket_server_create, (void), { return NULL; });
-
-/*!
- * \brief Callback suitable for use with a \ref ast_http_uri.
- *
- * Set the data field of the ast_http_uri to \ref ast_websocket_server.
- * \since 12
- */
-AST_OPTIONAL_API(int, ast_websocket_uri_cb, (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers), { return -1; });
-
-/*!
- * \brief Add a sub-protocol handler to the default /ws server
+ * \brief Add a sub-protocol handler to the server
  *
  * \param name Name of the sub-protocol to register
  * \param callback Callback called when a new connection requesting the sub-protocol is established
@@ -109,7 +72,7 @@ AST_OPTIONAL_API(int, ast_websocket_uri_cb, (struct ast_tcptls_session_instance
 AST_OPTIONAL_API(int, ast_websocket_add_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
 
 /*!
- * \brief Remove a sub-protocol handler from the default /ws server.
+ * \brief Remove a sub-protocol handler from the server
  *
  * \param name Name of the sub-protocol to unregister
  * \param callback Callback that was previously registered with the sub-protocol
@@ -120,30 +83,6 @@ AST_OPTIONAL_API(int, ast_websocket_add_protocol, (const char *name, ast_websock
 AST_OPTIONAL_API(int, ast_websocket_remove_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
 
 /*!
- * \brief Add a sub-protocol handler to the given server.
- *
- * \param name Name of the sub-protocol to register
- * \param callback Callback called when a new connection requesting the sub-protocol is established
- *
- * \retval 0 success
- * \retval -1 if sub-protocol handler could not be registered
- * \since 12
- */
-AST_OPTIONAL_API(int, ast_websocket_server_add_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
-
-/*!
- * \brief Remove a sub-protocol handler from the given server.
- *
- * \param name Name of the sub-protocol to unregister
- * \param callback Callback that was previously registered with the sub-protocol
- *
- * \retval 0 success
- * \retval -1 if sub-protocol was not found or if callback did not match
- * \since 12
- */
-AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
-
-/*!
  * \brief Read a WebSocket frame and handle it
  *
  * \param session Pointer to the WebSocket session
@@ -157,23 +96,7 @@ AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocke
  *
  * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
  */
-AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), { errno = ENOSYS; return -1;});
-
-/*!
- * \brief Read a WebSocket frame containing string data.
- *
- * \note The caller is responsible for freeing the output "buf".
- *
- * \param ws pointer to the websocket
- * \param buf string buffer to populate with data read from socket
- * \retval -1 on error
- * \retval number of bytes read on success
- *
- * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
- */
-AST_OPTIONAL_API(int, ast_websocket_read_string,
-		 (struct ast_websocket *ws, char **buf),
-		 { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), {return -1;});
 
 /*!
  * \brief Construct and transmit a WebSocket frame
@@ -186,20 +109,9 @@ AST_OPTIONAL_API(int, ast_websocket_read_string,
  * \retval 0 if successfully written
  * \retval -1 if error occurred
  */
-AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), {return -1;});
 
 /*!
- * \brief Construct and transmit a WebSocket frame containing string data.
- *
- * \param ws pointer to the websocket
- * \param buf string data to write to socket
- * \retval 0 if successfully written
- * \retval -1 if error occurred
- */
-AST_OPTIONAL_API(int, ast_websocket_write_string,
-		 (struct ast_websocket *ws, const char *buf),
-		 { errno = ENOSYS; return -1;});
-/*!
  * \brief Close a WebSocket session by sending a message with the CLOSE opcode and an optional code
  *
  * \param session Pointer to the WebSocket session
@@ -208,7 +120,7 @@ AST_OPTIONAL_API(int, ast_websocket_write_string,
  * \retval 0 if successfully written
  * \retval -1 if error occurred
  */
-AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), {return -1;});
 
 /*!
  * \brief Enable multi-frame reconstruction up to a certain number of bytes
@@ -250,7 +162,7 @@ AST_OPTIONAL_API(void, ast_websocket_unref, (struct ast_websocket *session), {re
  *
  * \note You must *not* directly read from or write to this file descriptor. It should only be used for polling.
  */
-AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), {return -1;});
 
 /*!
  * \brief Get the remote address for a WebSocket connected session.
@@ -265,7 +177,7 @@ AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct as
  * \retval 0 if unsecure
  * \retval 1 if secure
  */
-AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), {return -1;});
 
 /*!
  * \brief Set the socket of a WebSocket session to be non-blocking.
@@ -273,69 +185,12 @@ AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session),
  * \retval 0 on success
  * \retval -1 on failure
  */
-AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
-
-/*!
- * \brief Result code for a websocket client.
- */
-enum ast_websocket_result {
-	WS_OK,
-	WS_ALLOCATE_ERROR,
-	WS_KEY_ERROR,
-	WS_URI_PARSE_ERROR,
-	WS_URI_RESOLVE_ERROR,
-	WS_BAD_STATUS,
-	WS_INVALID_RESPONSE,
-	WS_BAD_REQUEST,
-	WS_URL_NOT_FOUND,
-	WS_HEADER_MISMATCH,
-	WS_HEADER_MISSING,
-	WS_NOT_SUPPORTED,
-	WS_WRITE_ERROR,
-	WS_CLIENT_START_ERROR,
-};
-
-/*!
- * \brief Create, and connect, a websocket client.
- *
- * \detail If the client websocket successfully connects, then the accepted protocol
- *         can be checked via a call to ast_websocket_client_accept_protocol.
- *
- * \note While connecting this *will* block until a response is
- *       received from the remote host.
- * \note Expected uri form: ws[s]://<address>[:port][/<path>] The address (can be a
- *       host name) and port are parsed out and used to connect to the remote server.
- *       If multiple IPs are returned during address resolution then the first one is
- *       chosen.
- *
- * \param uri uri to connect to
- * \param protocols a comma separated string of supported protocols
- * \param tls_cfg secure websocket credentials
- * \param result result code set on client failure
- * \retval a client websocket.
- * \retval NULL if object could not be created or connected
- * \since 13
- */
-AST_OPTIONAL_API(struct ast_websocket *, ast_websocket_client_create,
-		 (const char *uri, const char *protocols,
-		  struct ast_tls_config *tls_cfg,
-		  enum ast_websocket_result *result), { return NULL;});
-
-/*!
- * \brief Retrieve the server accepted sub-protocol on the client.
- *
- * \param ws the websocket client
- * \retval the accepted client sub-protocol.
- * \since 13
- */
-AST_OPTIONAL_API(const char *, ast_websocket_client_accept_protocol,
-		 (struct ast_websocket *ws), { return NULL;});
+AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), {return -1;});
 
 /*!
  * \brief Set the timeout on a non-blocking WebSocket session.
  *
  * \since 11.11.0
- * \since 12.4.0
  *
  * \retval 0 on success
  * \retval -1 on failure
diff --git a/include/asterisk/image.h b/include/asterisk/image.h
index 9e358ad..302f09e 100644
--- a/include/asterisk/image.h
+++ b/include/asterisk/image.h
@@ -28,7 +28,7 @@ struct ast_imager {
 	char *name;			/*!< Name */
 	char *desc;			/*!< Description */
 	char *exts;			/*!< Extension(s) (separated by '|' ) */
-	struct ast_format *format; /*!< Image format */
+	struct ast_format format; /*!< Image format */
 	struct ast_frame *(*read_image)(int fd, int len);	/*!< Read an image from a file descriptor */
 	int (*identify)(int fd);				/*!< Identify if this is that type of file */
 	int (*write_image)(int fd, struct ast_frame *frame);	/*!< Returns length written */
diff --git a/include/asterisk/inline_api.h b/include/asterisk/inline_api.h
index 5f6911d..7ede751 100644
--- a/include/asterisk/inline_api.h
+++ b/include/asterisk/inline_api.h
@@ -25,12 +25,14 @@
   Small API functions that are candidates for inlining need to be specially
   declared and defined, to ensure that the 'right thing' always happens.
   For example:
-  	- there must _always_ be a non-inlined version of the function
+	- there must _always_ be a non-inlined version of the function
 	available for modules compiled out of the tree to link to
 	- references to a function that cannot be inlined (for any
 	reason that the compiler deems proper) must devolve into an
 	'extern' reference, instead of 'static', so that multiple
-	copies of the function body are not built in different modules
+	copies of the function body are not built in different modules.
+	However, since this doesn't work for clang, we go with 'static'
+	anyway and hope for the best!
 	- when LOW_MEMORY is defined, inlining should be disabled
 	completely, even if the compiler is configured to support it
 
@@ -43,11 +45,15 @@
   including the header file
  */
 
-#if !defined(LOW_MEMORY) && !defined(DISABLE_INLINE)
+#if !defined(LOW_MEMORY)
 
 #if !defined(AST_API_MODULE)
+#if defined(__clang__) || defined(__GNUC_STDC_INLINE__)
+#define AST_INLINE_API(hdr, body) static hdr; static inline hdr body
+#else /* if defined(__clang__) */
 #define AST_INLINE_API(hdr, body) hdr; extern inline hdr body
-#else
+#endif
+#else /* if !defined(AST_API_MODULE) */
 #define AST_INLINE_API(hdr, body) hdr; hdr body
 #endif
 
diff --git a/include/asterisk/jabber.h b/include/asterisk/jabber.h
new file mode 100644
index 0000000..8c62746
--- /dev/null
+++ b/include/asterisk/jabber.h
@@ -0,0 +1,224 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2010, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief AJI - The Asterisk Jabber Interface
+ * \arg \ref AJI_intro
+ * \ref res_jabber.c
+ * \author Matt O'Gorman <mogorman at digium.com>
+ * \extref IKSEMEL http://iksemel.jabberstudio.org
+ *
+ * \page AJI_intro AJI - The Asterisk Jabber Interface
+ * 
+ * The Asterisk Jabber Interface, AJI, publishes an API for
+ * modules to use jabber communication. res_jabber.c implements
+ * a Jabber client and a component that can connect as a service
+ * to Jabber servers.
+ *
+ * \section External dependencies
+ * AJI use the IKSEMEL library found at http://iksemel.jabberstudio.org/
+ *
+ * \section Files
+ * - res_jabber.c
+ * - jabber.h
+ * - chan_gtalk.c
+ *
+ */
+
+#ifndef _ASTERISK_JABBER_H
+#define _ASTERISK_JABBER_H
+
+#ifdef HAVE_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#define TRY_SECURE 2
+#define SECURE 4
+
+#endif /* HAVE_OPENSSL */
+/* file is read by blocks with this size */
+#define NET_IO_BUF_SIZE 4096
+/* Return value for timeout connection expiration */
+#define IKS_NET_EXPIRED 12
+
+#include <iksemel.h>
+#include "asterisk/astobj.h"
+#include "asterisk/linkedlists.h"
+
+/* 
+ * As per RFC 3920 - section 3.1, the maximum length for a full Jabber ID 
+ * is 3071 bytes.
+ * The ABNF syntax for jid :
+ * jid = [node "@" ] domain [ "/" resource ]
+ * Each allowable portion of a JID (node identifier, domain identifier,
+ * and resource identifier) MUST NOT be more than 1023 bytes in length,
+ * resulting in a maximum total size (including the '@' and '/' separators) 
+ * of 3071 bytes.
+ */
+#define AJI_MAX_JIDLEN 3071
+#define AJI_MAX_RESJIDLEN 1023
+#define AJI_MAX_ATTRLEN   256
+
+#define MUC_NS "http://jabber.org/protocol/muc"
+
+enum aji_state {
+	AJI_DISCONNECTING,
+	AJI_DISCONNECTED,
+	AJI_CONNECTING,
+	AJI_CONNECTED
+};
+
+enum {
+	AJI_AUTOPRUNE = (1 << 0),
+	AJI_AUTOREGISTER = (1 << 1),
+	AJI_AUTOACCEPT = (1 << 2),
+};
+
+enum {
+	AJI_XEP0248 = (1 << 0),
+	AJI_PUBSUB = (1 << 1),
+	AJI_PUBSUB_AUTOCREATE = (1 << 2),
+};
+
+enum aji_btype {
+	AJI_USER = 0,
+	AJI_TRANS = 1,
+	AJI_UTRANS = 2,
+};
+
+struct aji_version {
+	char version[50];
+	int jingle;
+	struct aji_capabilities *parent;
+	struct aji_version *next;
+};
+
+struct aji_capabilities {
+	char node[200];
+	struct aji_version *versions;
+	struct aji_capabilities *next;
+};
+
+struct aji_resource {
+	int status;
+	char resource[AJI_MAX_RESJIDLEN];
+	char *description;
+	struct aji_version *cap;
+	int priority;
+	struct aji_resource *next;
+};
+
+struct aji_message {
+	char *from;
+	char *message;
+	char id[25];
+	struct timeval arrived;
+	AST_LIST_ENTRY(aji_message) list;
+};
+
+struct aji_buddy {
+	ASTOBJ_COMPONENTS_FULL(struct aji_buddy, AJI_MAX_JIDLEN, 1);
+	char channel[160];
+	struct aji_resource *resources;
+	enum aji_btype btype;
+	struct ast_flags flags;
+};
+
+struct aji_buddy_container {
+	ASTOBJ_CONTAINER_COMPONENTS(struct aji_buddy);
+};
+
+struct aji_transport_container {
+	ASTOBJ_CONTAINER_COMPONENTS(struct aji_transport);
+};
+
+struct aji_client {
+	ASTOBJ_COMPONENTS(struct aji_client);
+	char password[160];
+	char user[AJI_MAX_JIDLEN];
+	char serverhost[AJI_MAX_RESJIDLEN];
+	char pubsub_node[AJI_MAX_RESJIDLEN];
+	char statusmessage[256];
+	char name_space[256];
+	char sid[10]; /* Session ID */
+	char mid[6]; /* Message ID */
+	char context[AST_MAX_CONTEXT];
+	iksid *jid;
+	iksparser *p;
+	iksfilter *f;
+	ikstack *stack;
+#ifdef HAVE_OPENSSL
+	SSL_CTX *ssl_context;
+	SSL *ssl_session;
+	const SSL_METHOD *ssl_method;
+	unsigned int stream_flags;
+#endif /* HAVE_OPENSSL */
+	enum aji_state state;
+	int port;
+	int debug;
+	int usetls;
+	int forcessl;
+	int usesasl;
+	int keepalive;
+	int allowguest;
+	int timeout;
+	int message_timeout;
+	int authorized;
+	int distribute_events;
+	int send_to_dialplan;
+	struct ast_flags flags;
+	int component; /* 0 client,  1 component */
+	struct aji_buddy_container buddies;
+	AST_LIST_HEAD(messages,aji_message) messages;
+	void *jingle;
+	pthread_t thread;
+	int priority;
+	enum ikshowtype status;
+};
+
+struct aji_client_container{
+	ASTOBJ_CONTAINER_COMPONENTS(struct aji_client);
+};
+
+/* !Send XML stanza over the established XMPP connection */
+int ast_aji_send(struct aji_client *client, iks *x);
+/*! Send jabber chat message from connected client to jabber URI */
+int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message);
+/*! Send jabber chat message from connected client to a groupchat using 
+ *  a given nickname */
+int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message);
+/*! Disconnect jabber client */
+int ast_aji_disconnect(struct aji_client *client);
+int ast_aji_check_roster(void);
+void ast_aji_increment_mid(char *mid);
+/*! Open Chat session */
+int ast_aji_create_chat(struct aji_client *client,char *room, char *server, char *topic);
+/*! Invite to opened Chat session */
+int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message);
+/*! Join/leave existing Chat session */
+int ast_aji_join_chat(struct aji_client *client, char *room, char *nick);
+int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick);
+/*! Get a client via its name. Increases refcount of client by 1 */
+struct aji_client *ast_aji_get_client(const char *name);
+struct aji_client_container *ast_aji_get_clients(void);
+/*! Destructor function for buddies to be used with ASTOBJ_UNREF */
+void ast_aji_buddy_destroy(struct aji_buddy *obj);
+/*! Destructor function for clients to be used with ASTOBJ_UNREF after calls to ast_aji_get_client */
+void ast_aji_client_destroy(struct aji_client *obj);
+
+#endif
diff --git a/include/asterisk/jingle.h b/include/asterisk/jingle.h
new file mode 100644
index 0000000..7782065
--- /dev/null
+++ b/include/asterisk/jingle.h
@@ -0,0 +1,66 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Jingle definitions for chan_jingle
+ *
+ * \ref chan_jingle.c
+ *
+ * \author Matt O'Gorman <mogorman at digium.com>
+ */
+
+
+#ifndef _ASTERISK_JINGLE_H
+#define _ASTERISK_JINGLE_H
+
+#include <iksemel.h>
+#include "asterisk/astobj.h"
+
+
+/* Jingle Constants */
+
+#define JINGLE_NODE "jingle"
+#define GOOGLE_NODE "session"
+
+#define JINGLE_NS "urn:xmpp:tmp:jingle"
+#define JINGLE_AUDIO_RTP_NS "urn:xmpp:tmp:jingle:apps:audio-rtp"
+#define JINGLE_VIDEO_RTP_NS "urn:xmpp:tmp:jingle:apps:video"
+#define JINGLE_ICE_UDP_NS "urn:xmpp:tmp:jingle:transports:ice-udp"
+#define JINGLE_DTMF_NS "urn:xmpp:tmp:jingle:dtmf"
+
+#define GOOGLE_NS "http://www.google.com/session"
+#define GOOGLE_JINGLE_NS "urn:xmpp:jingle:1"
+#define GOOGLE_AUDIO_NS "http://www.google.com/session/phone"
+#define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
+#define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
+
+#define JINGLE_SID "sid"
+#define GOOGLE_SID "id"
+
+#define JINGLE_INITIATE "session-initiate"
+
+#define JINGLE_ACCEPT "session-accept"
+#define GOOGLE_ACCEPT "accept"
+
+#define JINGLE_NEGOTIATE "transport-info"
+#define GOOGLE_NEGOTIATE "candidates"
+
+#define JINGLE_INFO "session-info"
+#define JINGLE_TERMINATE "session-terminate"
+
+#endif
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
deleted file mode 100644
index 8cb74a4..0000000
--- a/include/asterisk/json.h
+++ /dev/null
@@ -1,1036 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_JSON_H
-#define _ASTERISK_JSON_H
-
-#include "asterisk/netsock2.h"
-
-/*! \file
- *
- * \brief Asterisk JSON abstraction layer.
- * \since 12.0.0
- *
- * This is a very thin wrapper around the Jansson API. For more details on it,
- * see its docs at http://www.digip.org/jansson/doc/2.4/apiref.html.
- *
- * Rather than provide the multiple ways of doing things that the Jansson API
- * does, the Asterisk wrapper is always reference-stealing, and always NULL
- * safe.
- *
- * And by always, I mean that the reference is stolen even if the function
- * fails. This avoids lots of conditional logic, and also avoids having to track
- * zillions of local variables when building complex JSON objects. You can
- * instead chain \c ast_json_* calls together safely and only worry about
- * cleaning up the root object.
- *
- * In the cases where you have a need to introduce intermediate objects, just
- * wrap them with json_ref() when passing them to other \c ast_json_*()
- * functions.
- *
- * \par Thread Safety
- *
- * Jansson (as of 2.4) provides fairly weak thread safety guarantees. The
- * Asterisk wrapper improves upon that slightly. The remaining refcounting
- * problems are issues when slicing/sharing/mixing instances between JSON
- * objects and arrays, which we avoid.
- *
- * The \c ast_json_dump_* functions are thread safe for multiple concurrent
- * dumps of the same object, so long as the concurrent dumps start from the same
- * \c root object. But if an object is shared by other JSON objects/arrays, then
- * concurrent dumps of the outer objects/arrays are not thread safe. This can be
- * avoided by using ast_json_deep_copy() when sharing JSON instances between
- * objects.
- *
- * The ast_json_ref() and ast_json_unref() functions are thread safe. Since the
- * Asterisk wrapper exclusively uses the reference stealing API, Jansson won't
- * be performing many refcount modifications behind our backs. There are a few
- * exceptions.
- *
- * The first is the transitive json_decref() that occurs when \ref
- * AST_JSON_OBJECT and \ref AST_JSON_ARRAY instances are deleted. This can be
- * avoided by using ast_json_deep_copy() when sharing JSON instances between
- * objects.
- *
- * The second is when using the reference borrowing specifier in
- * ast_json_pack() (capital \c O). This can be avoided by using the reference
- * stealing specifier (lowercase \c o) and wrapping the JSON object parameter
- * with ast_json_ref() for an explicit ref-bump.
- *
- * \par Example code
- *
- * \code
- *	// Example of how to use the Asterisk JSON API
- *	static struct ast_json *foo(void) {
- *		RAII_VAR(struct ast_json *, array, NULL, ast_json_unref);
- *		RAII_VAR(struct ast_json *, obj, NULL, ast_json_unref);
- *		int i, res;
- *
- *		array = ast_json_array_create();
- *		if (!array) { return NULL; }
- *
- *		for (i = 0; i < 10; ++i) {
- *			// NULL safety and object stealing means calls can
- *			// be chained together directly.
- *			res = ast_json_array_append(array,
- *				ast_json_integer_create(i));
- *			if (res != 0) { return NULL; }
- *		}
- *
- *		obj = ast_json_object_create();
- *		if (!obj) { return NULL; }
- *
- *		// If you already have an object reference, ast_json_ref()
- *		// can be used inline to bump the ref before passing it along
- *		// to a ref-stealing call
- *		res = ast_json_object_set(obj, "foo", ast_json_ref(array));
- *		if (!res) { return NULL; }
- *
- *		return obj;
- *	}
- * \endcode
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*!@{*/
-
-/*!
- * \brief Initialize the JSON library.
- */
-void ast_json_init(void);
-
-/*!
- * \brief Set custom allocators instead of the standard ast_malloc() and ast_free().
- * \since 12.0.0
- *
- * This is used by the unit tests to do JSON specific memory leak detection. Since it
- * affects all users of the JSON library, shouldn't normally be used.
- *
- * \param malloc_fn Custom allocation function.
- * \param free_fn Matching free function.
- */
-void ast_json_set_alloc_funcs(void *(*malloc_fn)(size_t), void (*free_fn)(void*));
-
-/*!
- * \brief Change alloc funcs back to the resource module defaults.
- * \since 12.0.0
- *
- * If you use ast_json_set_alloc_funcs() to temporarily change the allocator functions
- * (i.e., from in a unit test), this function sets them back to ast_malloc() and
- * ast_free().
- */
-void ast_json_reset_alloc_funcs(void);
-
-/*!
- * \brief Asterisk's custom JSON allocator. Exposed for use by unit tests.
- * \since 12.0.0
- * \internal
- */
-void *ast_json_malloc(size_t size);
-
-/*!
- * \brief Asterisk's custom JSON allocator. Exposed for use by unit tests.
- * \since 12.0.0
- * \internal
- */
-void ast_json_free(void *p);
-
-/*!
- * \struct ast_json
- * \brief Abstract JSON element (object, array, string, int, ...).
- * \since 12.0.0
- */
-struct ast_json;
-
-/*!
- * \brief Increase refcount on \a value.
- * \since 12.0.0
- *
- * \param value JSON value to reference.
- * \return The given \a value.
- */
-struct ast_json *ast_json_ref(struct ast_json *value);
-
-/*!
- * \brief Decrease refcount on \a value. If refcount reaches zero, \a value is freed.
- * \since 12.0.0
- *
- * \note It is safe to pass \c NULL to this function.
- */
-void ast_json_unref(struct ast_json *value);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Valid types of a JSON element.
- * \since 12.0.0
- */
-enum ast_json_type
-{
-	AST_JSON_OBJECT,
-	AST_JSON_ARRAY,
-	AST_JSON_STRING,
-	AST_JSON_INTEGER,
-	AST_JSON_REAL,
-	AST_JSON_TRUE,
-	AST_JSON_FALSE,
-	AST_JSON_NULL,
-};
-
-/*!
- * \brief Get the type of \a value.
- * \since 12.0.0
- * \param value Value to query.
- * \return Type of \a value.
- */
-enum ast_json_type ast_json_typeof(const struct ast_json *value);
-
-/*!
- * \brief Get the string name for the given type.
- * \since 12.0.0
- * \param type Type to convert to string.
- * \return Simple string for the type name (object, array, string, etc.)
- * \return \c "?" for invalid types.
- */
-const char *ast_json_typename(enum ast_json_type type);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Get the JSON true value.
- * \since 12.0.0
- *
- * The returned value is a singleton, and does not need to be
- * ast_json_unref()'ed.
- *
- * \return JSON true.
- */
-struct ast_json *ast_json_true(void);
-
-/*!
- * \brief Get the JSON false value.
- * \since 12.0.0
- *
- * The returned value is a singleton, and does not need to be
- * ast_json_unref()'ed.
- *
- * \return JSON false.
- */
-struct ast_json *ast_json_false(void);
-
-/*!
- * \brief Get the JSON boolean corresponding to \a value.
- * \since 12.0.0
- * \return JSON true if value is true (non-zero).
- * \return JSON false if value is false (zero).
- */
-struct ast_json *ast_json_boolean(int value);
-
-/*!
- * \brief Get the JSON null value.
- * \since 12.0.0
- *
- * The returned value is a singleton, and does not need to be
- * ast_json_unref()'ed.
- *
- * \return JSON null.
- */
-struct ast_json *ast_json_null(void);
-
-/*!
- * \brief Check if \a value is JSON true.
- * \since 12.0.0
- * \return True (non-zero) if \a value == \ref ast_json_true().
- * \return False (zero) otherwise..
- */
-int ast_json_is_true(const struct ast_json *value);
-
-/*!
- * \brief Check if \a value is JSON false.
- * \since 12.0.0
- * \return True (non-zero) if \a value == \ref ast_json_false().
- * \return False (zero) otherwise.
- */
-int ast_json_is_false(const struct ast_json *value);
-
-/*!
- * \brief Check if \a value is JSON null.
- * \since 12.0.0
- * \return True (non-zero) if \a value == \ref ast_json_false().
- * \return False (zero) otherwise.
- */
-int ast_json_is_null(const struct ast_json *value);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Construct a JSON string from \a value.
- * \since 12.0.0
- *
- * The given \a value must be a valid ASCII or UTF-8 encoded string.
- *
- * \param value Value of new JSON string.
- * \return Newly constructed string element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_string_create(const char *value);
-
-/*!
- * \brief Get the value of a JSON string.
- * \since 12.0.0
- * \param string JSON string.
- * \return Value of the string.
- * \return \c NULL on error.
- */
-const char *ast_json_string_get(const struct ast_json *string);
-
-/*!
- * \brief Change the value of a JSON string.
- * \since 12.0.0
- *
- * The given \a value must be a valid ASCII or UTF-8 encoded string.
- *
- * \param string JSON string to modify.
- * \param value New value to store in \a string.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_string_set(struct ast_json *string, const char *value);
-
-/*!
- * \brief Create a JSON string, printf style.
- * \since 12.0.0
- *
- * The formatted value must be a valid ASCII or UTF-8 encoded string.
- *
- * \param format \c printf style format string.
- * \return Newly allocated string.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_stringf(const char *format, ...) __attribute__((format(printf, 1, 2)));
-
-/*!
- * \brief Create a JSON string, vprintf style.
- * \since 12.0.0
- *
- * The formatted value must be a valid ASCII or UTF-8 encoded string.
- *
- * \param format \c printf style format string.
- * \return Newly allocated string.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_vstringf(const char *format, va_list args) __attribute__((format(printf, 1, 0)));
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Create a JSON integer.
- * \since 12.0.0
- * \param value Value of the new JSON integer.
- * \return Newly allocated integer.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_integer_create(intmax_t value);
-
-/*!
- * \brief Get the value from a JSON integer.
- * \since 12.0.0
- * \param integer JSON integer.
- * \return Value of a JSON integer.
- * \return 0 if \a integer is not a JSON integer.
- */
-intmax_t ast_json_integer_get(const struct ast_json *integer);
-
-/*!
- * \brief Set the value of a JSON integer.
- * \since 12.0.0
- * \param integer JSON integer to modify.
- * \param value New value for \a integer.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_integer_set(struct ast_json *integer, intmax_t value);
-
-/*!
- * \brief Create a JSON real number.
- * \since 12.0.0
- * \param value Value of the new JSON real number.
- * \return Newly allocated real number.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_real_create(double value);
-
-/*!
- * \brief Get the value from a JSON real number.
- * \since 12.0.0
- * \param real JSON real number.
- * \return Value of a JSON real number.
- * \return 0 if \a real is not a JSON real number.
- */
-double ast_json_real_get(const struct ast_json *real);
-
-/*!
- * \brief Set the value of a JSON real number.
- * \since 12.0.0
- * \param integer JSON real number to modify.
- * \param value New value for \a real.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_real_set(struct ast_json *real, double value);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Create a empty JSON array.
- * \since 12.0.0
- * \return Newly allocated array.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_array_create(void);
-
-/*!
- * \brief Get the size of a JSON array.
- * \since 12.0.0
- * \param array JSON array.
- * \return Size of \a array.
- * \return 0 if array is not a JSON array.
- */
-size_t ast_json_array_size(const struct ast_json *array);
-
-/*!
- * \brief Get an element from an array.
- * \since 12.0.0
- *
- * The returned element is a borrowed reference; use ast_json_ref() to safely keep a
- * pointer to it.
- *
- * \param array JSON array.
- * \param index Zero-based index into \a array.
- * \return The specified element.
- * \return \c NULL if \a array not an array.
- * \return \c NULL if \a index is out of bounds.
- */
-struct ast_json *ast_json_array_get(const struct ast_json *array, size_t index);
-
-/*!
- * \brief Change an element in an array.
- * \since 12.0.0
- *
- * \note The \a array steals the \a value reference even if it returns error;
- * use ast_json_ref() to safely keep a pointer to it.
- *
- * \param array JSON array to modify.
- * \param index Zero-based index into array.
- * \param value New JSON value to store in \a array at \a index.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_set(struct ast_json *array, size_t index, struct ast_json *value);
-
-/*!
- * \brief Append to an array.
- * \since 12.0.0
- *
- * \note The \a array steals the \a value reference even if it returns error;
- * use ast_json_ref() to safely keep a pointer to it.
- *
- * \param array JSON array to modify.
- * \param value New JSON value to store at the end of \a array.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_append(struct ast_json *array, struct ast_json *value);
-
-/*!
- * \brief Insert into an array.
- * \since 12.0.0
- *
- * \note The \a array steals the \a value reference even if it returns error;
- * use ast_json_ref() to safely keep a pointer to it.
- *
- * \param array JSON array to modify.
- * \param index Zero-based index into array.
- * \param value New JSON value to store in \a array at \a index.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_insert(struct ast_json *array, size_t index, struct ast_json *value);
-
-/*!
- * \brief Remove an element from an array.
- * \since 12.0.0
- * \param array JSON array to modify.
- * \param index Zero-based index into array.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_remove(struct ast_json *array, size_t index);
-
-/*!
- * \brief Remove all elements from an array.
- * \since 12.0.0
- * \param array JSON array to clear.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_clear(struct ast_json *array);
-
-/*!
- * \brief Append all elements from \a tail to \a array.
- * \since 12.0.0
- *
- * The \a tail argument is not changed, so ast_json_unref() it when you are done with it.
- *
- * \param array JSON array to modify.
- * \param tail JSON array with contents to append to \a array.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_array_extend(struct ast_json *array, struct ast_json *tail);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Create a new JSON object.
- * \since 12.0.0
- * \return Newly allocated object.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_object_create(void);
-
-/*!
- * \brief Get size of JSON object.
- * \since 12.0.0
- * \param object JSON object.
- * \return Size of \a object.
- * \return Zero of \a object is not a JSON object.
- */
-size_t ast_json_object_size(struct ast_json *object);
-
-/*!
- * \brief Get a field from a JSON object.
- * \since 12.0.0
- *
- * The returned element is a borrowed reference; use ast_json_ref() to safely keep a
- * pointer to it.
- *
- * \param object JSON object.
- * \param key Key of field to look up.
- * \return Value with given \a key.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_object_get(struct ast_json *object, const char *key);
-
-/*!
- * \brief Set a field in a JSON object.
- * \since 12.0.0
- *
- * \note The object steals the \a value reference even if it returns error;
- * use ast_json_ref() to safely keep a pointer to it.
- *
- * \param object JSON object to modify.
- * \param key Key of field to set.
- * \param value JSON value to set for field.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value);
-
-/*!
- * \brief Delete a field from a JSON object.
- * \since 12.0.0
- *
- * \param object JSON object to modify.
- * \param key Key of field to delete.
- * \return 0 on success, or -1 if key does not exist.
- */
-int ast_json_object_del(struct ast_json *object, const char *key);
-
-/*!
- * \brief Delete all elements from a JSON object.
- * \since 12.0.0
- * \param object JSON object to clear.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_clear(struct ast_json *object);
-
-/*!
- * \brief Update \a object with all of the fields of \a other.
- * \since 12.0.0
- *
- * All of the fields of \a other are copied into \a object, overwriting existing keys.
- * The \a other object is not changed, so ast_json_unref() it when you are done with it.
- *
- * \param object JSON object to modify.
- * \param other JSON object to copy into \a object.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_update(struct ast_json *object, struct ast_json *other);
-
-/*!
- * \brief Update existing fields in \a object with the fields of \a other.
- * \since 12.0.0
- *
- * Like ast_json_object_update(), but only existing fields are updated. No new fields
- * will get added. The \a other object is not changed, so ast_json_unref() it when you
- * are done with it.
- *
- * \param object JSON object to modify.
- * \param other JSON object to copy into \a object.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_update_existing(struct ast_json *object, struct ast_json *other);
-
-/*!
- * \brief Add new fields to \a object with the fields of \a other.
- * \since 12.0.0
- *
- * Like ast_json_object_update(), but only missing fields are added. No existing fields
- * will be modified. The \a other object is not changed, so ast_json_unref() it when you
- * are done with it.
- *
- * \param object JSON object to modify.
- * \param other JSON object to copy into \a object.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_update_missing(struct ast_json *object, struct ast_json *other);
-
-/*!
- * \struct ast_json_iter
- * \brief Iterator for JSON object key/values.
- * \since 12.0.0
- *
- * Note that iteration order is not specified, and may change as fields are added to
- * and removed from the object.
- */
-struct ast_json_iter;
-
-/*!
- * \brief Get an iterator pointing to the first field in a JSON object.
- * \since 12.0.0
- *
- * The order of the fields in an object are not specified. However, iterating forward
- * from this iterator will cover all fields in \a object. Adding or removing fields from
- * \a object may invalidate its iterators.
- *
- * \param object JSON object.
- * \return Iterator to the first field in \a object.
- * \return \c NULL \a object is empty.
- * \return \c NULL on error.
- */
-struct ast_json_iter *ast_json_object_iter(struct ast_json *object);
-
-/*!
- * \brief Get an iterator pointing to a specified \a key in \a object.
- * \since 12.0.0
- *
- * Iterating forward from this iterator may not to cover all elements in \a object.
- *
- * \param object JSON object to iterate.
- * \param key Key of field to lookup.
- * \return Iterator pointing to the field with the given \a key.
- * \return \c NULL if \a key does not exist.
- * \return \c NULL on error.
- */
-struct ast_json_iter *ast_json_object_iter_at(struct ast_json *object, const char *key);
-
-/*!
- * \brief Get the next iterator.
- * \since 12.0.0
- * \param object JSON object \a iter was obtained from.
- * \param iter JSON object iterator.
- * \return Iterator to next field in \a object.
- * \return \c NULL if \a iter was the last field.
- */
-struct ast_json_iter *ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter);
-
-/*!
- * \brief Get the key from an iterator.
- * \since 12.0.0
- * \param iter JSON object iterator.
- * \return Key of the field \a iter points to.
- */
-const char *ast_json_object_iter_key(struct ast_json_iter *iter);
-
-/*!
- * \brief Get the value from an iterator.
- * \since 12.0.0
- *
- * The returned element is a borrowed reference; use ast_json_ref() to safely
- * keep a pointer to it.
- *
- * \param iter JSON object iterator.
- * \return Value of the field \a iter points to.
- */
-struct ast_json *ast_json_object_iter_value(struct ast_json_iter *iter);
-
-/*!
- * \brief Set the value of the field pointed to by an iterator.
- * \since 12.0.0
- *
- * \note The object steals the \a value reference even if it returns error;
- * use ast_json_ref() to safely keep a pointer to it.
- *
- * \param object JSON object \a iter was obtained from.
- * \param iter JSON object iterator.
- * \param value JSON value to store in \iter's field.
- * \return 0 on success.
- * \return -1 on error.
- */
-int ast_json_object_iter_set(struct ast_json *object, struct ast_json_iter *iter, struct ast_json *value);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Encoding format type.
- * \since 12.0.0
- */
-enum ast_json_encoding_format
-{
-	/*! Compact format, low human readability */
-	AST_JSON_COMPACT,
-	/*! Formatted for human readability */
-	AST_JSON_PRETTY,
-};
-
-/*!
- * \brief Encode a JSON value to a compact string.
- * \since 12.0.0
- *
- * Returned string must be freed by calling ast_json_free().
- *
- * \param root JSON value.
- * \return String encoding of \a root.
- * \return \c NULL on error.
- */
-#define ast_json_dump_string(root) ast_json_dump_string_format(root, AST_JSON_COMPACT)
-
-/*!
- * \brief Encode a JSON value to a string.
- * \since 12.0.0
- *
- * Returned string must be freed by calling ast_json_free().
- *
- * \param root JSON value.
- * \param format encoding format type.
- * \return String encoding of \a root.
- * \return \c NULL on error.
- */
-char *ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format);
-
-#define ast_json_dump_str(root, dst) ast_json_dump_str_format(root, dst, AST_JSON_COMPACT)
-
-/*!
- * \brief Encode a JSON value to an \ref ast_str.
- * \since 12.0.0
- *
- * If \a dst is too small, it will be grown as needed.
- *
- * \param root JSON value.
- * \param dst \ref ast_str to store JSON encoding.
- * \param format encoding format type.
- * \return 0 on success.
- * \return -1 on error. The contents of \a dst are undefined.
- */
-int ast_json_dump_str_format(struct ast_json *root, struct ast_str **dst, enum ast_json_encoding_format format);
-
-#define ast_json_dump_file(root, output) ast_json_dump_file_format(root, output, AST_JSON_COMPACT)
-
-/*!
- * \brief Encode a JSON value to a \c FILE.
- * \since 12.0.0
- *
- * \param root JSON value.
- * \param output File to write JSON encoding to.
- * \param format encoding format type.
- * \return 0 on success.
- * \return -1 on error. The contents of \a output are undefined.
- */
-int ast_json_dump_file_format(struct ast_json *root, FILE *output, enum ast_json_encoding_format format);
-
-#define ast_json_dump_new_file(root, path) ast_json_dump_new_file_format(root, path, AST_JSON_COMPACT)
-
-/*!
- * \brief Encode a JSON value to a file at the given location.
- * \since 12.0.0
- *
- * \param root JSON value.
- * \param path Path to file to write JSON encoding to.
- * \param format encoding format type.
- * \return 0 on success.
- * \return -1 on error. The contents of \a output are undefined.
- */
-int ast_json_dump_new_file_format(struct ast_json *root, const char *path, enum ast_json_encoding_format format);
-
-#define AST_JSON_ERROR_TEXT_LENGTH    160
-#define AST_JSON_ERROR_SOURCE_LENGTH   80
-
-/*!
- * \brief JSON parsing error information.
- * \since 12.0.0
- */
-struct ast_json_error {
-	/*! Line number error occured on */
-	int line;
-	/*! Character (not byte, can be different for UTF-8) column on which the error occurred. */
-	int column;
-	/*! Position in bytes from start of input */
-	int position;
-	/*! Error message */
-	char text[AST_JSON_ERROR_TEXT_LENGTH];
-	/*! Source of the error (filename or <string>) */
-	char source[AST_JSON_ERROR_TEXT_LENGTH];
-};
-
-/*!
- * \brief Parse null terminated string into a JSON object or array.
- * \since 12.0.0
- * \param input String to parse.
- * \param[out] error Filled with information on error.
- * \return Parsed JSON element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_load_string(const char *input, struct ast_json_error *error);
-
-/*!
- * \brief Parse \ref ast_str into a JSON object or array.
- * \since 12.0.0
- * \param input \ref ast_str to parse.
- * \param[out] error Filled with information on error.
- * \return Parsed JSON element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_load_str(const struct ast_str *input, struct ast_json_error *error);
-
-/*!
- * \brief Parse buffer with known length into a JSON object or array.
- * \since 12.0.0
- * \param buffer Buffer to parse.
- * \param buflen Length of \a buffer.
- * \param[out] error Filled with information on error.
- * \return Parsed JSON element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_load_buf(const char *buffer, size_t buflen, struct ast_json_error *error);
-
-/*!
- * \brief Parse a \c FILE into JSON object or array.
- * \since 12.0.0
- * \param input \c FILE to parse.
- * \param[out] error Filled with information on error.
- * \return Parsed JSON element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_load_file(FILE *input, struct ast_json_error *error);
-
-/*!
- * \brief Parse file at \a path into JSON object or array.
- * \since 12.0.0
- * \param path Path of file to parse.
- * \param[out] error Filled with information on error.
- * \return Parsed JSON element.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_load_new_file(const char *path, struct ast_json_error *error);
-
-/*!
- * \brief Helper for creating complex JSON values.
- * \since 12.0.0
- *
- * See original Jansson docs at http://www.digip.org/jansson/doc/2.4/apiref.html#apiref-pack
- * for more details.
- */
-struct ast_json *ast_json_pack(char const *format, ...);
-
-/*!
- * \brief Helper for creating complex JSON values simply.
- * \since 12.0.0
- *
- * See original Jansson docs at http://www.digip.org/jansson/doc/2.4/apiref.html#apiref-pack
- * for more details.
- */
-struct ast_json *ast_json_vpack(char const *format, va_list ap);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Compare two JSON objects.
- * \since 12.0.0
- *
- * Two JSON objects are equal if they are of the same type, and their contents are equal.
- *
- * \param lhs Value to compare.
- * \param rhs Other value to compare.
- * \return True (non-zero) if \a lhs and \a rhs are equal.
- * \return False (zero) if they are not.
- */
-int ast_json_equal(const struct ast_json *lhs, const struct ast_json *rhs);
-
-/*!
- * \brief Copy a JSON value, but not its children.
- * \since 12.0.0
- *
- * If \a value is a JSON object or array, its children are shared with the returned copy.
- *
- * \param value JSON value to copy.
- * \return Shallow copy of \a value.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_copy(const struct ast_json *value);
-
-/*!
- * \brief Copy a JSON value, and its children.
- * \since 12.0.0
- *
- * If \a value is a JSON object or array, they are also copied.
- *
- * \param value JSON value to copy.
- * \return Deep copy of \a value.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_deep_copy(const struct ast_json *value);
-
-/*!@}*/
-
-/*!@{*/
-
-/*!
- * \brief Common JSON rendering functions for common 'objects'.
- */
-
-/*!
- * \brief Simple name/number pair.
- * \param name Name
- * \param number Number
- * \return NULL if error (non-UTF8 characters, NULL inputs, etc.)
- * \return JSON object with name and number fields
- */
-struct ast_json *ast_json_name_number(const char *name, const char *number);
-
-/*!
- * \brief Construct a timeval as JSON.
- *
- * JSON does not define a standard date format (boo), but the de facto standard
- * is to use ISO 8601 formatted string. We build a millisecond resolution string
- * from the \c timeval
- *
- * \param tv \c timeval to encode.
- * \param zone Text string of a standard system zoneinfo file.  If NULL, the system localtime will be used.
- * \return JSON string with ISO 8601 formatted date/time.
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_timeval(const struct timeval tv, const char *zone);
-
-/*!
- * \brief Construct an IP address as JSON
- *
- * XXX some comments describing the need for this here
- *
- * \param addr ast_sockaddr to encode
- * \param transport_type ast_transport to include in the address string if any. Should just be one.
- * \return JSON string containing the IP address with optional transport information
- * \return \c NULL on error.
- */
-struct ast_json *ast_json_ipaddr(const struct ast_sockaddr *addr, enum ast_transport transport_type);
-
-/*!
- * \brief Construct a context/exten/priority as JSON.
- *
- * If a \c NULL is passed for \c context or \c exten, or -1 for \c priority,
- * the fields is set to ast_json_null().
- *
- * \param context Context name.
- * \param exten Extension.
- * \param priority Dialplan priority.
- * \return JSON object with \c context, \c exten and \c priority fields
- */
-struct ast_json *ast_json_dialplan_cep(const char *context, const char *exten, int priority);
-
-struct ast_json_payload {
-	struct ast_json *json;
-};
-
-/*!
- * \brief Create an ao2 object to pass json blobs as data payloads for stasis
- * \since 12.0.0
- *
- * \param json the ast_json blob we are loading
- *
- * \retval NULL if we fail to alloc it
- * \retval pointer to the ast_json_payload created
- */
-struct ast_json_payload *ast_json_payload_create(struct ast_json *json);
-
-struct ast_party_id;
-/*!
- * \brief Construct an ast_party_id as JSON.
- * \since 12.0.0
- *
- * \param party The party ID to represent as JSON.
- *
- * \return JSON object with \c name, \c number and \c subaddress objects
- * for those that are valid in the party ID
- */
-struct ast_json *ast_json_party_id(struct ast_party_id *party);
-
-/*!
- * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
- * \since 12.5.0
- *
- * \param json_variables The JSON blob containing the variable
- * \param variables An out reference to the variables to populate.
- *        The pointer to the variables should be NULL when calling this.
- *
- * \code
- * struct ast_json *json_variables = ast_json_pack("[ { s: s } ]", "foo", "bar");
- * struct ast_variable *variables = NULL;
- * int res;
- *
- * res = ast_json_to_ast_variables(json_variables, &variables);
- * \endcode
- *
- * \retval 0 success
- * \retval -1 error
- */
-int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
-
-/*!@}*/
-
-#endif /* _ASTERISK_JSON_H */
diff --git a/include/asterisk/localtime.h b/include/asterisk/localtime.h
index 74f342c..5da28df 100644
--- a/include/asterisk/localtime.h
+++ b/include/asterisk/localtime.h
@@ -75,6 +75,7 @@ const char *ast_setlocale(const char *locale);
  * \param len Size of the chunk of memory buf.
  * \param format A string specifying the format of time to be placed into buf.
  * \param tm Pointer to the broken out time to be used for the format.
+ * \param locale Text string specifying the locale to be used for language strings.
  * \retval An integer value specifying the number of bytes placed into buf or -1 on error.
  */
 int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm);
@@ -86,6 +87,7 @@ int ast_strftime_locale(char *buf, size_t len, const char *format, const struct
  * \param s A string specifying some portion of a date and time.
  * \param format The format in which the string, s, is expected.
  * \param tm The broken-out time structure into which the parsed data is expected.
+ * \param locale Text string specifying the locale to be used for language strings.
  * \retval A pointer to the first character within s not used to parse the date and time.
  */
 char *ast_strptime(const char *s, const char *format, struct ast_tm *tm);
@@ -99,9 +101,4 @@ char *ast_strptime_locale(const char *s, const char *format, struct ast_tm *tm,
 struct ast_test;
 void ast_localtime_wakeup_monitor(struct ast_test *info);
 
-/*! \brief ast_strftime for ISO8601 formatting timestamps. */
-#define AST_ISO8601_FORMAT "%FT%T.%q%z"
-/*! \brief Max length of an null terminated, millisecond resolution, ISO8601 timestamp string. */
-#define AST_ISO8601_LEN 29
-
 #endif /* _ASTERISK_LOCALTIME_H */
diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h
index 7741654..5d3c5a5 100644
--- a/include/asterisk/lock.h
+++ b/include/asterisk/lock.h
@@ -18,7 +18,7 @@
 
 /*! \file
  * \brief Asterisk locking-related definitions:
- * - ast_mutext_t, ast_rwlock_t and related functions;
+ * - ast_mutex_t, ast_rwlock_t and related functions;
  * - atomic arithmetic instructions;
  * - wrappers for channel locking.
  *
@@ -59,7 +59,6 @@
 #include "asterisk/time.h"
 #endif
 
-#include "asterisk/backtrace.h"
 #include "asterisk/logger.h"
 #include "asterisk/compiler.h"
 
@@ -102,6 +101,12 @@
 
 struct ast_channel;
 
+/*!
+ * \brief Lock tracking information.
+ *
+ * \note Any changes to this struct MUST be reflected in the
+ * lock.c:restore_lock_tracking() function.
+ */
 struct ast_lock_track {
 	const char *file[AST_MAX_REENTRANCY];
 	int lineno[AST_MAX_REENTRANCY];
@@ -304,22 +309,7 @@ void ast_restore_lock_info(void *lock_addr);
  * \param this_lock_addr lock address to return lock information
  * \since 1.6.1
  */
-void ast_log_show_lock(void *this_lock_addr);
-
-/*!
- * \brief Generate a lock dump equivalent to "core show locks".
- *
- * The lock dump generated is generally too large to be output by a
- * single ast_verbose/log/debug/etc. call. Only ast_cli() handles it
- * properly without changing BUFSIZ in logger.c.
- *
- * Note: This must be ast_free()d when you're done with it.
- *
- * \retval An ast_str containing the lock dump
- * \retval NULL on error
- * \since 12
- */
-struct ast_str *ast_dump_locks(void);
+void log_show_lock(void *this_lock_addr);
 
 /*!
  * \brief retrieve lock info for the specified mutex
@@ -339,28 +329,6 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in
  * used during deadlock avoidance, to preserve the original location where
  * a lock was originally acquired.
  */
-#define AO2_DEADLOCK_AVOIDANCE(obj) \
-	do { \
-		char __filename[80], __func[80], __mutex_name[80]; \
-		int __lineno; \
-		int __res = ast_find_lock_info(ao2_object_get_lockaddr(obj), __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
-		int __res2 = ao2_unlock(obj); \
-		usleep(1); \
-		if (__res < 0) { /* Could happen if the ao2 object does not have a mutex. */ \
-			if (__res2) { \
-				ast_log(LOG_WARNING, "Could not unlock ao2 object '%s': %s and no lock info found!  I will NOT try to relock.\n", #obj, strerror(__res2)); \
-			} else { \
-				ao2_lock(obj); \
-			} \
-		} else { \
-			if (__res2) { \
-				ast_log(LOG_WARNING, "Could not unlock ao2 object '%s': %s.  {{{Originally locked at %s line %d: (%s) '%s'}}}  I will NOT try to relock.\n", #obj, strerror(__res2), __filename, __lineno, __func, __mutex_name); \
-			} else { \
-				__ao2_lock(obj, AO2_LOCK_REQ_MUTEX, __filename, __func, __lineno, __mutex_name); \
-			} \
-		} \
-	} while (0)
-
 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
 	do { \
 		char __filename[80], __func[80], __mutex_name[80]; \
@@ -474,58 +442,14 @@ static inline void ast_reentrancy_unlock(struct ast_lock_track *lt)
 	}
 }
 
-static inline void ast_reentrancy_init(struct ast_lock_track **plt)
-{
-	int i;
-	pthread_mutexattr_t reentr_attr;
-	struct ast_lock_track *lt = *plt;
-
-	if (!lt) {
-		lt = *plt = (struct ast_lock_track *) calloc(1, sizeof(*lt));
-	}
-
-	for (i = 0; i < AST_MAX_REENTRANCY; i++) {
-		lt->file[i] = NULL;
-		lt->lineno[i] = 0;
-		lt->func[i] = NULL;
-		lt->thread[i] = 0;
-#ifdef HAVE_BKTR
-		memset(&lt->backtrace[i], 0, sizeof(lt->backtrace[i]));
-#endif
-	}
-
-	lt->reentrancy = 0;
-
-	pthread_mutexattr_init(&reentr_attr);
-	pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
-	pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
-	pthread_mutexattr_destroy(&reentr_attr);
-}
-
-static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
-{
-	struct ast_lock_track *lt;
-	if (*plt) {
-		lt = *plt;
-		pthread_mutex_destroy(&lt->reentr_mutex);
-		free(lt);
-		*plt = NULL;
-	}
-}
-
 #else /* !DEBUG_THREADS */
 
-#define AO2_DEADLOCK_AVOIDANCE(obj) \
-	ao2_unlock(obj); \
-	usleep(1); \
-	ao2_lock(obj);
-
-#define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
+#define	CHANNEL_DEADLOCK_AVOIDANCE(chan) \
 	ast_channel_unlock(chan); \
 	usleep(1); \
 	ast_channel_lock(chan);
 
-#define DEADLOCK_AVOIDANCE(lock) \
+#define	DEADLOCK_AVOIDANCE(lock) \
 	do { \
 		int __res; \
 		if (!(__res = ast_mutex_unlock(lock))) { \
@@ -592,81 +516,6 @@ static void  __attribute__((destructor)) fini_##rwlock(void) \
 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
 #define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
 
-/*!
- * \brief Scoped Locks
- *
- * Scoped locks provide a way to use RAII locks. In other words,
- * declaration of a scoped lock will automatically define and lock
- * the lock. When the lock goes out of scope, it will automatically
- * be unlocked.
- *
- * \code
- * int some_function(struct ast_channel *chan)
- * {
- *     SCOPED_LOCK(lock, chan, ast_channel_lock, ast_channel_unlock);
- *
- *     if (!strcmp(ast_channel_name(chan, "foo")) {
- *         return 0;
- *     }
- *
- *     return -1;
- * }
- * \endcode
- *
- * In the above example, neither return path requires explicit unlocking
- * of the channel.
- *
- * \note
- * Care should be taken when using SCOPED_LOCKS in conjunction with ao2 objects.
- * ao2 objects should be unlocked before they are unreffed. Since SCOPED_LOCK runs
- * once the variable goes out of scope, this can easily lead to situations where the
- * variable gets unlocked after it is unreffed.
- *
- * \param varname The unique name to give to the scoped lock. You are not likely to reference
- * this outside of the SCOPED_LOCK invocation.
- * \param lock The variable to lock. This can be anything that can be passed to a locking
- * or unlocking function.
- * \param lockfunc The function to call to lock the lock
- * \param unlockfunc The function to call to unlock the lock
- */
-#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc) \
-	RAII_VAR(typeof((lock)), varname, ({lockfunc((lock)); (lock); }), unlockfunc)
-
-/*!
- * \brief scoped lock specialization for mutexes
- */
-#define SCOPED_MUTEX(varname, lock) SCOPED_LOCK(varname, (lock), ast_mutex_lock, ast_mutex_unlock)
-
-/*!
- * \brief scoped lock specialization for read locks
- */
-#define SCOPED_RDLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_rdlock, ast_rwlock_unlock)
-
-/*!
- * \brief scoped lock specialization for write locks
- */
-#define SCOPED_WRLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_wrlock, ast_rwlock_unlock)
-
-/*!
- * \brief scoped lock specialization for ao2 mutexes.
- */
-#define SCOPED_AO2LOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_lock, ao2_unlock)
-
-/*!
- * \brief scoped lock specialization for ao2 read locks.
- */
-#define SCOPED_AO2RDLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_rdlock, ao2_unlock)
-
-/*!
- * \brief scoped lock specialization for ao2 write locks.
- */
-#define SCOPED_AO2WRLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_wrlock, ao2_unlock)
-
-/*!
- * \brief scoped lock specialization for channels.
- */
-#define SCOPED_CHANNELLOCK(varname, chan) SCOPED_LOCK(varname, (chan), ast_channel_lock, ast_channel_unlock)
-
 #ifndef __CYGWIN__	/* temporary disabled for cygwin */
 #define pthread_mutex_t		use_ast_mutex_t_instead_of_pthread_mutex_t
 #define pthread_cond_t		use_ast_cond_t_instead_of_pthread_cond_t
@@ -728,6 +577,7 @@ AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
 {
 	return OSAtomicAdd64(v, (int64_t *) p) - v;
+})
 #elif defined (__i386__) || defined(__x86_64__)
 #ifdef sun
 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
@@ -774,6 +624,7 @@ AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
 {
 	return OSAtomicAdd64( -1, (int64_t *) p) == 0;
+})
 #else
 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
 {
diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h
index 84e6991..b044972 100644
--- a/include/asterisk/logger.h
+++ b/include/asterisk/logger.h
@@ -62,6 +62,17 @@ extern "C" {
 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
 	__attribute__((format(printf, 5, 6)));
 
+/*!
+ * \brief Used for sending a log message with protection against recursion.
+ *
+ * \note This function should be used by all error messages that might be directly
+ * or indirectly caused by logging.
+ *
+ * \see ast_log for documentation on the parameters.
+ */
+void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
+	__attribute__((format(printf, 5, 6)));
+
 /* XXX needs documentation */
 struct ast_callid;
 
@@ -80,17 +91,11 @@ struct ast_callid;
 void ast_log_callid(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, ...)
 	__attribute__((format(printf, 6, 7)));
 
-/*!
- * \brief Log a backtrace of the current thread's execution stack to the Asterisk log
- */
-void ast_log_backtrace(void);
+void ast_backtrace(void);
 
 /*! \brief Reload logger without rotating log files */
 int logger_reload(void);
 
-/*! \brief Reload logger while rotating log files */
-int ast_logger_rotate(void);
-
 void __attribute__((format(printf, 5, 6))) ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...);
 
 /*!
@@ -266,15 +271,6 @@ int ast_logger_register_level(const char *name);
 void ast_logger_unregister_level(const char *name);
 
 /*!
- * \brief Get the logger configured date format
- *
- * \retval The date format string
- *
- * \since 13.0.0
- */
-const char *ast_logger_get_dateformat(void);
-
-/*!
  * \brief factory function to create a new uniquely identifying callid.
  *
  * \retval ast_callid struct pointer containing the call id
@@ -310,16 +306,7 @@ struct ast_callid *ast_read_threadstorage_callid(void);
  *
  * \retval NULL always
  */
-#define ast_callid_unref(c) ({ ao2_ref(c, -1); (struct ast_callid *) (NULL); })
-
-/*!
- * \brief Cleanup a callid reference (NULL safe ao2 unreference)
- *
- * \param c the ast_callid
- *
- * \retval NULL always
- */
-#define ast_callid_cleanup(c) ({ ao2_cleanup(c); (struct ast_callid *) (NULL); })
+#define ast_callid_unref(c) ({ ao2_ref(c, -1); (NULL); })
 
 /*!
  * \brief Sets what is stored in the thread storage to the given
@@ -390,21 +377,15 @@ void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *c
 
 #define ast_log_dynamic_level(level, ...) ast_log(level, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__)
 
-#define DEBUG_ATLEAST(level) \
-	(option_debug >= (level) \
-		|| (ast_opt_dbg_module && ast_debug_get_by_module(AST_MODULE) >= (level)))
-
 /*!
  * \brief Log a DEBUG message
  * \param level The minimum value of option_debug for this message
  *        to get logged
  */
-#define ast_debug(level, ...) \
-	do { \
-		if (DEBUG_ATLEAST(level)) { \
-			ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
-		} \
-	} while (0)
+#define ast_debug(level, ...) do {       \
+	if (option_debug >= (level) || (ast_opt_dbg_module && ast_debug_get_by_module(AST_MODULE) >= (level)) ) \
+		ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
+} while (0)
 
 extern int ast_verb_sys_level;
 
@@ -463,6 +444,63 @@ int ast_verb_console_get(void);
  */
 void ast_verb_console_set(int verb_level);
 
+#ifndef _LOGGER_BACKTRACE_H
+#define _LOGGER_BACKTRACE_H
+#ifdef HAVE_BKTR
+#define AST_MAX_BT_FRAMES 32
+/* \brief
+ *
+ * A structure to hold backtrace information. This structure provides an easy means to
+ * store backtrace information or pass backtraces to other functions.
+ */
+struct ast_bt {
+	/*! The addresses of the stack frames. This is filled in by calling the glibc backtrace() function */
+	void *addresses[AST_MAX_BT_FRAMES];
+	/*! The number of stack frames in the backtrace */
+	int num_frames;
+	/*! Tells if the ast_bt structure was dynamically allocated */
+	unsigned int alloced:1;
+};
+
+/* \brief
+ * Allocates memory for an ast_bt and stores addresses and symbols.
+ *
+ * \return Returns NULL on failure, or the allocated ast_bt on success
+ * \since 1.6.1
+ */
+struct ast_bt *ast_bt_create(void);
+
+/* \brief
+ * Fill an allocated ast_bt with addresses
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ * \since 1.6.1
+ */
+int ast_bt_get_addresses(struct ast_bt *bt);
+
+/* \brief
+ *
+ * Free dynamically allocated portions of an ast_bt
+ *
+ * \retval NULL.
+ * \since 1.6.1
+ */
+void *ast_bt_destroy(struct ast_bt *bt);
+
+/* \brief Retrieve symbols for a set of backtrace addresses
+ *
+ * \param addresses A list of addresses, such as the ->addresses structure element of struct ast_bt.
+ * \param num_frames Number of addresses in the addresses list
+ * \retval NULL Unable to allocate memory
+ * \return List of strings. Free the entire list with a single ast_std_free call.
+ * \since 1.6.2.16
+ */
+char **ast_bt_get_symbols(void **addresses, size_t num_frames);
+
+#endif /* HAVE_BKTR */
+#endif /* _LOGGER_BACKTRACE_H */
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h
index 387430f..e4c199f 100644
--- a/include/asterisk/manager.h
+++ b/include/asterisk/manager.h
@@ -54,7 +54,7 @@
 - \ref manager.c Main manager code file
  */
 
-#define AMI_VERSION                     "2.6.0"
+#define AMI_VERSION                     "1.3"
 #define DEFAULT_MANAGER_PORT 5038	/* Default port for Asterisk management via TCP */
 #define DEFAULT_MANAGER_TLS_PORT 5039	/* Default port for Asterisk management via TCP */
 
@@ -68,42 +68,33 @@
 
 /*! \name Manager event classes */
 /*@{ */
-#define EVENT_FLAG_SYSTEM           (1 << 0) /* System events such as module load/unload */
-#define EVENT_FLAG_CALL             (1 << 1) /* Call event, such as state change, etc */
-#define EVENT_FLAG_LOG              (1 << 2) /* Log events */
-#define EVENT_FLAG_VERBOSE          (1 << 3) /* Verbose messages */
-#define EVENT_FLAG_COMMAND          (1 << 4) /* Ability to read/set commands */
-#define EVENT_FLAG_AGENT            (1 << 5) /* Ability to read/set agent info */
-#define EVENT_FLAG_USER             (1 << 6) /* Ability to read/set user info */
-#define EVENT_FLAG_CONFIG           (1 << 7) /* Ability to modify configurations */
-#define EVENT_FLAG_DTMF             (1 << 8) /* Ability to read DTMF events */
-#define EVENT_FLAG_REPORTING        (1 << 9) /* Reporting events such as rtcp sent */
-#define EVENT_FLAG_CDR              (1 << 10) /* CDR events */
-#define EVENT_FLAG_DIALPLAN         (1 << 11) /* Dialplan events (VarSet, NewExten) */
-#define EVENT_FLAG_ORIGINATE        (1 << 12) /* Originate a call to an extension */
-#define EVENT_FLAG_AGI              (1 << 13) /* AGI events */
-#define EVENT_FLAG_HOOKRESPONSE     (1 << 14) /* Hook Response */
-#define EVENT_FLAG_CC               (1 << 15) /* Call Completion events */
-#define EVENT_FLAG_AOC              (1 << 16) /* Advice Of Charge events */
-#define EVENT_FLAG_TEST             (1 << 17) /* Test event used to signal the Asterisk Test Suite */
-#define EVENT_FLAG_SECURITY         (1 << 18) /* Security Message as AMI Event */
+#define EVENT_FLAG_SYSTEM 		(1 << 0) /* System events such as module load/unload */
+#define EVENT_FLAG_CALL			(1 << 1) /* Call event, such as state change, etc */
+#define EVENT_FLAG_LOG			(1 << 2) /* Log events */
+#define EVENT_FLAG_VERBOSE		(1 << 3) /* Verbose messages */
+#define EVENT_FLAG_COMMAND		(1 << 4) /* Ability to read/set commands */
+#define EVENT_FLAG_AGENT		(1 << 5) /* Ability to read/set agent info */
+#define EVENT_FLAG_USER                 (1 << 6) /* Ability to read/set user info */
+#define EVENT_FLAG_CONFIG		(1 << 7) /* Ability to modify configurations */
+#define EVENT_FLAG_DTMF  		(1 << 8) /* Ability to read DTMF events */
+#define EVENT_FLAG_REPORTING		(1 << 9) /* Reporting events such as rtcp sent */
+#define EVENT_FLAG_CDR			(1 << 10) /* CDR events */
+#define EVENT_FLAG_DIALPLAN		(1 << 11) /* Dialplan events (VarSet, NewExten) */
+#define EVENT_FLAG_ORIGINATE	(1 << 12) /* Originate a call to an extension */
+#define EVENT_FLAG_AGI			(1 << 13) /* AGI events */
+#define EVENT_FLAG_HOOKRESPONSE		(1 << 14) /* Hook Response */
+#define EVENT_FLAG_CC			(1 << 15) /* Call Completion events */
+#define EVENT_FLAG_AOC			(1 << 16) /* Advice Of Charge events */
+#define EVENT_FLAG_TEST			(1 << 17) /* Test event used to signal the Asterisk Test Suite */
 /*XXX Why shifted by 30? XXX */
-#define EVENT_FLAG_MESSAGE          (1 << 30) /* MESSAGE events. */
+#define EVENT_FLAG_MESSAGE		(1 << 30) /* MESSAGE events. */
 /*@} */
 
 /*! \brief Export manager structures */
 #define AST_MAX_MANHEADERS 128
 
-/*! \brief Manager Helper Function
- *
- * \param category The class authorization category of the event
- * \param event The name of the event being raised
- * \param body The body of the event
- *
- * \retval 0 Success
- * \retval non-zero Error
- */
-typedef int (*manager_hook_t)(int category, const char *event, char *body);
+/*! \brief Manager Helper Function */
+typedef int (*manager_hook_t)(int, const char *, char *);
 
 struct manager_custom_hook {
 	/*! Identifier */
@@ -156,10 +147,6 @@ struct manager_action {
 		AST_STRING_FIELD(arguments);	/*!< Description of each argument. */
 		AST_STRING_FIELD(seealso);	/*!< See also */
 	);
-	/*! Possible list element response events. */
-	struct ast_xml_doc_item *list_responses;
-	/*! Final response event. */
-	struct ast_xml_doc_item *final_response;
 	/*! Permission required for action.  EVENT_FLAG_* */
 	int authority;
 	/*! Function to be called */
@@ -260,9 +247,7 @@ int astman_verify_session_writepermissions(uint32_t ident, int perm);
  * \param event Event name
  * \param chancount Number of channels in chans parameter
  * \param chans A pointer to an array of channels involved in the event
- * \param file, line, func
  * \param contents Format string describing event
- * \param ...
  * \since 1.8
 */
 int __ast_manager_event_multichan(int category, const char *event, int chancount,
@@ -341,230 +326,4 @@ int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastor
  */
 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid);
 
-/*!
- * \brief append an event header to an ast string
- * \since 12
- *
- * \param fields_string pointer to an ast_string pointer. It may be a pointer to a
- *        NULL ast_str pointer, in which case the ast_str will be initialized.
- * \param header The header being applied
- * \param value the value of the header
- *
- * \retval 0 if successful
- * \retval non-zero on failure
- */
-int ast_str_append_event_header(struct ast_str **fields_string,
-	const char *header, const char *value);
-
-/*! \brief Struct representing a snapshot of channel state */
-struct ast_channel_snapshot;
-
-/*!
- * \brief Generate the AMI message body from a channel snapshot
- * \since 12
- *
- * \param snapshot the channel snapshot for which to generate an AMI message
- *                 body
- * \param prefix What to prepend to the channel fields
- *
- * \retval NULL on error
- * \retval ast_str* on success (must be ast_freed by caller)
- */
-struct ast_str *ast_manager_build_channel_state_string_prefix(
-		const struct ast_channel_snapshot *snapshot,
-		const char *prefix);
-
-/*!
- * \brief Generate the AMI message body from a channel snapshot
- * \since 12
- *
- * \param snapshot the channel snapshot for which to generate an AMI message
- *                 body
- *
- * \retval NULL on error
- * \retval ast_str* on success (must be ast_freed by caller)
- */
-struct ast_str *ast_manager_build_channel_state_string(
-		const struct ast_channel_snapshot *snapshot);
-
-/*! \brief Struct representing a snapshot of bridge state */
-struct ast_bridge_snapshot;
-
-/*!
- * \since 12
- * \brief Callback used to determine whether a key should be skipped when converting a
- *  JSON object to a manager blob
- * \param key Key from JSON blob to be evaluated
- * \retval non-zero if the key should be excluded
- * \retval zero if the key should not be excluded
- */
-typedef int (*key_exclusion_cb)(const char *key);
-
-struct ast_json;
-
-/*!
- * \since 12
- * \brief Convert a JSON object into an AMI compatible string
- *
- * \param blob The JSON blob containing key/value pairs to convert
- * \param exclusion_cb A \ref key_exclusion_cb pointer to a function that will exclude
- * keys from the final AMI string
- *
- * \retval A malloc'd \ref ast_str object. Callers of this function should free
- * the returned \ref ast_str object
- * \retval NULL on error
- */
-struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb);
-
-/*!
- * \brief Generate the AMI message body from a bridge snapshot
- * \since 12
- *
- * \param snapshot the bridge snapshot for which to generate an AMI message
- *                 body
- * \param prefix What to prepend to the bridge fields
- *
- * \retval NULL on error
- * \retval ast_str* on success (must be ast_freed by caller)
- */
-struct ast_str *ast_manager_build_bridge_state_string_prefix(
-	const struct ast_bridge_snapshot *snapshot,
-	const char *prefix);
-
-/*!
- * \brief Generate the AMI message body from a bridge snapshot
- * \since 12
- *
- * \param snapshot the bridge snapshot for which to generate an AMI message
- *                 body
- *
- * \retval NULL on error
- * \retval ast_str* on success (must be ast_freed by caller)
- */
-struct ast_str *ast_manager_build_bridge_state_string(
-	const struct ast_bridge_snapshot *snapshot);
-
-/*! \brief Struct containing info for an AMI event to send out. */
-struct ast_manager_event_blob {
-	int event_flags;		/*!< Flags the event should be raised with. */
-	const char *manager_event;	/*!< The event to be raised, should be a string literal. */
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(extra_fields);	/*!< Extra fields to include in the event. */
-	);
-};
-
-/*!
- * \since 12
- * \brief Construct a \ref ast_manager_event_blob.
- *
- * The returned object is AO2 managed, so clean up with ao2_cleanup().
- *
- * \param event_flags Flags the event should be raised with.
- * \param manager_event The event to be raised, should be a string literal.
- * \param extra_fields_fmt Format string for extra fields to include.
- *                         Or NO_EXTRA_FIELDS for no extra fields.
- *
- * \return New \ref ast_manager_snapshot_event object.
- * \return \c NULL on error.
- */
-struct ast_manager_event_blob *
-__attribute__((format(printf, 3, 4)))
-ast_manager_event_blob_create(
-	int event_flags,
-	const char *manager_event,
-	const char *extra_fields_fmt,
-	...);
-
-/*! GCC warns about blank or NULL format strings. So, shenanigans! */
-#define NO_EXTRA_FIELDS "%s", ""
-
-/*!
- * \since 12
- * \brief Initialize support for AMI system events.
- * \retval 0 on success
- * \retval non-zero on error
- */
-int manager_system_init(void);
-
-/*!
- * \brief Initialize support for AMI channel events.
- * \retval 0 on success.
- * \retval non-zero on error.
- * \since 12
- */
-int manager_channels_init(void);
-
-/*!
- * \since 12
- * \brief Initialize support for AMI MWI events.
- * \retval 0 on success
- * \retval non-zero on error
- */
-int manager_mwi_init(void);
-
-/*!
- * \brief Initialize support for AMI channel events.
- * \return 0 on success.
- * \return non-zero on error.
- * \since 12
- */
-int manager_bridging_init(void);
-
-/*!
- * \brief Initialize support for AMI endpoint events.
- * \return 0 on success.
- * \return non-zero on error.
- * \since 12
- */
-int manager_endpoints_init(void);
-
-/*!
- * \since 12
- * \brief Get the \ref stasis_message_type for generic messages
- *
- * A generic AMI message expects a JSON only payload. The payload must have the following
- * structure:
- * {type: s, class_type: i, event: [ {s: s}, ...] }
- *
- * - type is the AMI event type
- * - class_type is the class authorization type for the event
- * - event is a list of key/value tuples to be sent out in the message
- *
- * \retval A \ref stasis_message_type for AMI messages
- */
-struct stasis_message_type *ast_manager_get_generic_type(void);
-
-/*!
- * \since 12
- * \brief Get the \ref stasis topic for AMI
- *
- * \retval The \ref stasis topic for AMI
- * \retval NULL on error
- */
-struct stasis_topic *ast_manager_get_topic(void);
-
-/*!
- * \since 12
- * \brief Publish an event to AMI
- *
- * \param type The type of AMI event to publish
- * \param class_type The class on which to publish the event
- * \param obj The event data to be published.
- *
- * Publishes a message to the \ref stasis message bus solely for the consumption of AMI.
- * The message will be of the type provided by \ref ast_manager_get_type, and will be
- * published to the topic provided by \ref ast_manager_get_topic. As such, the JSON must
- * be constructed as defined by the \ref ast_manager_get_type message.
- */
-void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj);
-
-/*!
- * \since 12
- * \brief Get the \ref stasis_message_router for AMI
- *
- * \retval The \ref stasis_message_router for AMI
- * \retval NULL on error
- */
-struct stasis_message_router *ast_manager_get_message_router(void);
-
 #endif /* _ASTERISK_MANAGER_H */
diff --git a/include/asterisk/md5.h b/include/asterisk/md5.h
index 3014292..714267d 100644
--- a/include/asterisk/md5.h
+++ b/include/asterisk/md5.h
@@ -26,8 +26,7 @@
 struct MD5Context {
 	uint32_t buf[4];
 	uint32_t bits[2];
-	/*! Align because we cast this buffer to uint32s */
-	unsigned char in[64] __attribute__((aligned(__alignof__(uint32_t))));
+	unsigned char in[64];
 };
 
 void MD5Init(struct MD5Context *context);
diff --git a/include/asterisk/media_index.h b/include/asterisk/media_index.h
deleted file mode 100644
index 40fb721..0000000
--- a/include/asterisk/media_index.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Media file format and description indexing engine.
- */
-
-#ifndef _ASTERISK_MEDIA_INDEX_H
-#define _ASTERISK_MEDIA_INDEX_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-struct ast_format_cap;
-
-/*!
- * \brief Object representing a media index
- */
-struct ast_media_index;
-
-/*!
- * \brief Creates a new media index
- *
- * \param base_dir Base directory for indexing
- *
- * \retval NULL on error
- * \retval A new AO2 refcounted media index
- */
-struct ast_media_index *ast_media_index_create(
-	const char *base_dir);
-
-/*!
- * \brief Get the description for a media file
- *
- * \param index Media index in which to query information
- * \param filename Name of the file for which to get the description
- * \param variant Media variant for which to get the description
- *
- * \retval NULL if not found
- * \return The description requested (must be copied to be kept)
- */
-const char *ast_media_get_description(struct ast_media_index *index, const char *filename, const char *variant);
-
-/*!
- * \brief Get the ast_format_cap for a media file
- *
- * \param index Media index in which to query information
- * \param filename Name of the file for which to get the description
- * \param variant Media variant for which to get the description
- *
- * \retval NULL if not found
- * \return a copy of the format capabilities (must be destroyed with ast_format_cap_destroy)
- */
-struct ast_format_cap *ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant);
-
-/*!
- * \brief Get the languages in which a media file is available
- *
- * \param index Media index in which to query information
- * \param filename Name of the file for which to get available languages
- *
- * \retval NULL on error
- * \return an ast_str_container filled with language strings
- */
-struct ao2_container *ast_media_get_variants(struct ast_media_index *index, const char *filename);
-
-/*!
- * \brief Get the a container of all media available on the system
- *
- * \param index Media index in which to query information
- *
- * \retval NULL on error
- * \return an ast_str_container filled with media file name strings
- */
-struct ao2_container *ast_media_get_media(struct ast_media_index *index);
-
-/*!
- * \brief Update a media index
- *
- * \param index Media index in which to query information
- * \param variant Media variant for which to get the description
- *
- * \retval non-zero on error
- * \return zero on success
- */
-int ast_media_index_update(struct ast_media_index *index,
-	const char *variant);
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_MEDIA_INDEX_H */
diff --git a/include/asterisk/message.h b/include/asterisk/message.h
index f81574c..7e5c77a 100644
--- a/include/asterisk/message.h
+++ b/include/asterisk/message.h
@@ -25,9 +25,8 @@
  *
  * The purpose of this API is to provide support for text messages that
  * are not session based.  The messages are passed into the Asterisk core
- * to be routed through the dialplan or another interface and potentially
- * sent back out through a message technology that has been registered
- * through this API.
+ * to be routed through the dialplan and potentially sent back out through
+ * a message technology that has been registered through this API.
  */
 
 #ifndef __AST_MESSAGE_H__
@@ -92,64 +91,6 @@ int ast_msg_tech_register(const struct ast_msg_tech *tech);
 int ast_msg_tech_unregister(const struct ast_msg_tech *tech);
 
 /*!
- * \brief An external processor of received messages
- * \since 12.5.0
- */
-struct ast_msg_handler {
-	/*!
-	 * \brief Name of the message handler
-	 */
-	const char *name;
-
-	/*!
-	 * \brief The function callback that will handle the message
-	 *
-	 * \param msg The message to handle
-	 *
-	 * \retval 0 The handler processed the message successfull
-	 * \retval non-zero The handler passed or could not process the message
-	 */
-	int (* const handle_msg)(struct ast_msg *msg);
-
-	/*!
-	 * \brief Return whether or not the message has a valid destination
-	 *
-	 * A message may be delivered to the dialplan and/or other locations,
-	 * depending on whether or not other handlers have been registered. This
-	 * function is called by the message core to determine if any handler can
-	 * process a message.
-	 *
-	 * \param msg The message to inspect
-	 *
-	 * \retval 0 The message does not have a valid destination
-	 * \retval 1 The message has a valid destination
-	 */
-	int (* const has_destination)(const struct ast_msg *msg);
-};
-
-/*!
- * \brief Register a \c ast_msg_handler
- * \since 12.5.0
- *
- * \param handler The handler to register
- *
- * \retval 0 Success
- * \retval non-zero Error
- */
-int ast_msg_handler_register(const struct ast_msg_handler *handler);
-
-/*!
- * \brief Unregister a \c ast_msg_handler
- * \since 12.5.0
- *
- * \param handler The handler to unregister
- *
- * \retval 0 Success
- * \retval non-zero Error
- */
-int ast_msg_handler_unregister(const struct ast_msg_handler *handler);
-
-/*!
  * \brief Allocate a message.
  *
  * Allocate a message for the purposes of passing it into the Asterisk core
@@ -221,29 +162,7 @@ int __attribute__((format(printf, 2, 3)))
  */
 int __attribute__((format(printf, 2, 3)))
 		ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...);
-
-/*!
- * \brief Set the technology associated with this message
- *
- * \since 12.5.0
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __attribute__((format(printf, 2, 3)))
-		ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...);
-
-/*!
- * \brief Set the technology's endpoint associated with this message
- *
- * \since 12.5.0
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __attribute__((format(printf, 2, 3)))
-		ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...);
-
+	
 /*!
  * \brief Set a variable on the message going to the dialplan.
  * \note Setting a variable that already exists overwrites the existing variable value
@@ -290,66 +209,6 @@ const char *ast_msg_get_var(struct ast_msg *msg, const char *name);
 const char *ast_msg_get_body(const struct ast_msg *msg);
 
 /*!
- * \brief Retrieve the source of this message
- *
- * \since 12.5.0
- *
- * \param msg The message to get the soure from
- *
- * \retval The source of the message
- * \retval NULL or empty string if the message has no source
- */
-const char *ast_msg_get_from(const struct ast_msg *msg);
-
-/*!
- * \brief Retrieve the destination of this message
- *
- * \since 12.5.0
- *
- * \param msg The message to get the destination from
- *
- * \retval The destination of the message
- * \retval NULL or empty string if the message has no destination
- */
-const char *ast_msg_get_to(const struct ast_msg *msg);
-
-/*!
- * \brief Retrieve the technology associated with this message
- *
- * \since 12.5.0
- *
- * \param msg The message to get the technology from
- *
- * \retval The technology of the message
- * \retval NULL or empty string if the message has no associated technology
- */
-const char *ast_msg_get_tech(const struct ast_msg *msg);
-
-/*!
- * \brief Retrieve the endpoint associated with this message
- *
- * \since 12.5.0
- *
- * \param msg The message to get the endpoint from
- *
- * \retval The endpoint associated with the message
- * \retval NULL or empty string if the message has no associated endpoint
- */
-const char *ast_msg_get_endpoint(const struct ast_msg *msg);
-
-/*!
- * \brief Determine if a particular message has a destination via some handler
- *
- * \since 12.5.0
- *
- * \param msg The message to check
- *
- * \retval 0 if the message has no handler that can find a destination
- * \retval 1 if the message has a handler that can find a destination
- */
-int ast_msg_has_destination(const struct ast_msg *msg);
-
-/*!
  * \brief Queue a message for routing through the dialplan.
  *
  * Regardless of the return value of this function, this funciton will take
diff --git a/include/asterisk/mixmonitor.h b/include/asterisk/mixmonitor.h
deleted file mode 100644
index 892cd2a..0000000
--- a/include/asterisk/mixmonitor.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief loadable MixMonitor functionality
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*!
- * \brief Start a mixmonitor on a channel.
- * \since 12.0.0
- *
- * \param chan Which channel to put the MixMonitor on
- * \param filename What the name of the file should be
- * \param options What options should be used for the mixmonitor
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-typedef int (*ast_mixmonitor_start_fn)(struct ast_channel *chan, const char *filename, const char *options);
-
-/*!
- * \brief Stop a mixmonitor on a channel.
- * \since 12.0.0
- *
- * \param chan Which channel to stop a MixMonitor on
- * \param mixmon_id Stop the MixMonitor with this mixmonid if it is on the channel (may be NULL)
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-typedef int (*ast_mixmonitor_stop_fn)(struct ast_channel *chan, const char *mixmon_id);
-
-/*!
- * \brief MixMonitor virtual methods table definition
- * \since 12.0.0
- */
-struct ast_mixmonitor_methods {
-	ast_mixmonitor_start_fn start;
-	ast_mixmonitor_stop_fn stop;
-};
-
-/*!
- * \brief Setup MixMonitor virtual methods table. Use this to provide the MixMonitor functionality from a loadable module.
- * \since 12.0.0
- *
- * \param vmethod_table pointer to vmethod table providing mixmonitor functions
- *
- * \retval 0 if successful
- * \retval non-zero on failure
- */
-int ast_set_mixmonitor_methods(struct ast_mixmonitor_methods *vmethod_table);
-
-/*!
- * \brief Clear the MixMonitor virtual methods table. Use this to cleanup function pointers provided by a module that set.
- * \since 12.0.0
- *
- * \retval 0 if successful
- * \retval non-zero on failure (occurs when methods aren't loaded)
- */
-int ast_clear_mixmonitor_methods(void);
-
-/*!
- * \brief Start a mixmonitor on a channel with the given parameters
- * \since 12.0.0
- *
- * \param chan Which channel to apply the MixMonitor to
- * \param filename filename to use for the recording
- * \param options Optional arguments to be interpreted by the MixMonitor start function
- *
- * \retval 0 if successful
- * \retval non-zero on failure
- *
- * \note This function will always fail is nothing has set the mixmonitor methods
- */
-int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options);
-
-/*!
- * \brief Stop a mixmonitor on a channel with the given parameters
- * \since 12.0.0
- *
- * \param chan Which channel to stop a MixMonitor on (may be NULL if mixmon_id is provided)
- * \param mixmon_id Which mixmon_id should be stopped (may be NULL if chan is provided)
- *
- * \retval 0 if successful
- * \retval non-zero on failure
- */
-int ast_stop_mixmonitor(struct ast_channel *chan, const char *mixmon_id);
diff --git a/include/asterisk/mod_format.h b/include/asterisk/mod_format.h
index 7f17741..ff3ab7b 100644
--- a/include/asterisk/mod_format.h
+++ b/include/asterisk/mod_format.h
@@ -43,10 +43,10 @@ extern "C" {
 struct ast_format_def {
 	char name[80];		/*!< Name of format */
 	char exts[80];		/*!< Extensions (separated by | if more than one) 
-						 * this format can read.  First is assumed for writing (e.g. .mp3) */
-	struct ast_format *format;	/*!< Format of frames it uses/provides (one only) */
-	/*!
-	 * \brief Prepare an input stream for playback.
+	    			this format can read.  First is assumed for writing (e.g. .mp3) */
+	struct ast_format format;	/*!< Format of frames it uses/provides (one only) */
+	/*! 
+	 * \brief Prepare an input stream for playback. 
 	 * \return 0 on success, -1 on error.
 	 * The FILE is already open (in s->f) so this function only needs to perform
 	 * any applicable validity checks on the file. If none is required, the
@@ -110,7 +110,7 @@ struct ast_filestream {
 	/*! Transparently translate from another format -- just once */
 	struct ast_trans_pvt *trans;
 	struct ast_tranlator_pvt *tr;
-	struct ast_format *lastwriteformat;
+	struct ast_format lastwriteformat;
 	int lasttimeout;
 	struct ast_channel *owner;
 	FILE *f;
diff --git a/include/asterisk/module.h b/include/asterisk/module.h
index 7f9cecf..e4c6696 100644
--- a/include/asterisk/module.h
+++ b/include/asterisk/module.h
@@ -25,14 +25,6 @@
  * provide and some other module related functions.
  */
 
-/*! \li \ref module.h uses the configuration file \ref modules.conf
- * \addtogroup configuration_file
- */
-
-/*! \page modules.conf modules.conf
- * \verbinclude modules.conf.sample
- */
-
 #ifndef _ASTERISK_MODULE_H
 #define _ASTERISK_MODULE_H
 
@@ -73,13 +65,6 @@ enum ast_module_load_result {
 	AST_MODULE_LOAD_FAILURE = -1,   /*!< Module could not be loaded properly */
 };
 
-enum ast_module_support_level {
-	AST_MODULE_SUPPORT_UNKNOWN,
-	AST_MODULE_SUPPORT_CORE,
-	AST_MODULE_SUPPORT_EXTENDED,
-	AST_MODULE_SUPPORT_DEPRECATED,
-};
-
 /*! 
  * \brief Load a module.
  * \param resource_name The name of the module to load.
@@ -117,20 +102,18 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode);
  */
 void ast_update_use_count(void);
 
-/*!
- * \brief Ask for a list of modules, descriptions, use counts and status.
+/*! 
+ * \brief Ask for a list of modules, descriptions, and use counts.
  * \param modentry A callback to an updater function.
  * \param like
  *
  * For each of the modules loaded, modentry will be executed with the resource,
  * description, and usecount values of each particular module.
- *
+ * 
  * \return the number of modules loaded
  */
-int ast_update_module_list(int (*modentry)(const char *module, const char *description,
-                                           int usecnt, const char *status, const char *like,
-                                           enum ast_module_support_level support_level),
-                           const char *like);
+int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
+			   const char *like);
 
 /*!
  * \brief Check if module with the name given is loaded
@@ -273,8 +256,6 @@ struct ast_module_info {
 	 * These are only required for loading, when the optional_api header file
 	 * detects that the compiler does not support the optional API featureset. */
 	const char *nonoptreq;
-	/*! The support level for the given module */
-	enum ast_module_support_level support_level;
 };
 
 void ast_module_register(const struct ast_module_info *);
@@ -288,63 +269,65 @@ void __ast_module_user_hangup_all(struct ast_module *);
 #define ast_module_user_remove(user) __ast_module_user_remove(ast_module_info->self, user)
 #define ast_module_user_hangup_all() __ast_module_user_hangup_all(ast_module_info->self)
 
-struct ast_module *ast_module_ref(struct ast_module *);
-void ast_module_unref(struct ast_module *);
+struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func);
+void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func);
+void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func);
+
+/*!
+ * \brief Hold a reference to the module
+ * \param mod Module to reference
+ * \return mod
+ *
+ * \note A module reference will prevent the module
+ * from being unloaded.
+ */
+#define ast_module_ref(mod)           __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+/*!
+ * \brief Prevent unload of the module before shutdown
+ * \param mod Module to hold
+ *
+ * \note This should not be balanced by a call to ast_module_unref.
+ */
+#define ast_module_shutdown_ref(mod)  __ast_module_shutdown_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+/*!
+ * \brief Release a reference to the module
+ * \param mod Module to release
+ */
+#define ast_module_unref(mod)         __ast_module_unref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 #if defined(__cplusplus) || defined(c_plusplus)
-#define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func, load_pri, support_level)	\
+#define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func, load_pri)	\
 	static struct ast_module_info __mod_info = {	\
-		NULL,                                                          \
-		load_func,                                                     \
-		reload_func,                                                   \
-		unload_func,                                                   \
-		NULL,                                                          \
-		NULL,                                                          \
-		AST_MODULE,                                                    \
-		desc,                                                          \
-		keystr,                                                        \
-		flags_to_set,                                                  \
-		AST_BUILDOPT_SUM,                                              \
-		load_pri,                                                      \
-		NULL,                                                          \
-		support_level,                                                 \
-	};                                                                 \
-	static void  __attribute__((constructor)) __reg_module(void)       \
-	{                                                                  \
-		ast_module_register(&__mod_info);                              \
-	}                                                                  \
-	static void  __attribute__((destructor)) __unreg_module(void)      \
-	{                                                                  \
-		ast_module_unregister(&__mod_info);                            \
-	}                                                                  \
+		NULL,					\
+		load_func,				\
+		reload_func,				\
+		unload_func,				\
+		NULL,					\
+		NULL,					\
+		AST_MODULE,				\
+		desc,					\
+		keystr,					\
+		flags_to_set,				\
+		AST_BUILDOPT_SUM,			\
+		load_pri,           \
+	};						\
+	static void  __attribute__((constructor)) __reg_module(void) \
+	{ \
+		ast_module_register(&__mod_info); \
+	} \
+	static void  __attribute__((destructor)) __unreg_module(void) \
+	{ \
+		ast_module_unregister(&__mod_info); \
+	} \
 	static const __attribute__((unused)) struct ast_module_info *ast_module_info = &__mod_info
 
-#define AST_MODULE_INFO_STANDARD(keystr, desc)              \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			load_module,                                    \
-			unload_module,                                  \
-			NULL,                                           \
-			AST_MODPRI_DEFAULT,                             \
-			AST_MODULE_SUPPORT_CORE                         \
-		       )
-
-#define AST_MODULE_INFO_STANDARD_EXTENDED(keystr, desc)     \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			load_module,                                    \
-			unload_module,                                  \
-			NULL,                                           \
-			AST_MODPRI_DEFAULT,                             \
-			AST_MODULE_SUPPORT_EXTENDED                     \
-		       )
-#define AST_MODULE_INFO_STANDARD_DEPRECATED(keystr, desc)   \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			load_module,                                    \
-			unload_module,                                  \
-			NULL,                                           \
-			AST_MODPRI_DEFAULT,                             \
-			AST_MODULE_SUPPORT_DEPRECATED                   \
+#define AST_MODULE_INFO_STANDARD(keystr, desc)		\
+	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,	\
+			load_module,			\
+			unload_module,		\
+			NULL,			\
+			AST_MODPRI_DEFAULT \
 		       )
-
 #else /* plain C */
 
 /* forward declare this pointer in modules, so that macro/function
@@ -433,30 +416,12 @@ static void __restore_globals(void)
 	} \
 	static const struct ast_module_info *ast_module_info = &__mod_info
 
-#define AST_MODULE_INFO_STANDARD(keystr, desc)              \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			.load = load_module,                            \
-			.unload = unload_module,                        \
-			.load_pri = AST_MODPRI_DEFAULT,                 \
-			.support_level = AST_MODULE_SUPPORT_CORE,       \
-		       )
-
-#define AST_MODULE_INFO_STANDARD_EXTENDED(keystr, desc)     \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			.load = load_module,                            \
-			.unload = unload_module,                        \
-			.load_pri = AST_MODPRI_DEFAULT,                 \
-			.support_level = AST_MODULE_SUPPORT_EXTENDED,   \
+#define AST_MODULE_INFO_STANDARD(keystr, desc)		\
+	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,	\
+			.load = load_module,			\
+			.unload = unload_module,		\
+			.load_pri = AST_MODPRI_DEFAULT, \
 		       )
-
-#define AST_MODULE_INFO_STANDARD_DEPRECATED(keystr, desc)   \
-	AST_MODULE_INFO(keystr, AST_MODFLAG_LOAD_ORDER, desc,   \
-			.load = load_module,                            \
-			.unload = unload_module,                        \
-			.load_pri = AST_MODPRI_DEFAULT,                 \
-			.support_level = AST_MODULE_SUPPORT_DEPRECATED, \
-		       )
-
 #endif	/* plain C */
 
 /*! 
@@ -528,11 +493,6 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel
  */
 int ast_unregister_application(const char *app);
 
-const char *ast_module_support_level_to_string(enum ast_module_support_level support_level);
-
-/*! Macro to safely ref and unref the self module for the current scope */
-#define SCOPED_MODULE_USE(module) \
-	RAII_VAR(struct ast_module *, __self__ ## __LINE__, ast_module_ref(module), ast_module_unref)
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
diff --git a/include/asterisk/monitor.h b/include/asterisk/monitor.h
index 6030221..e29622e 100644
--- a/include/asterisk/monitor.h
+++ b/include/asterisk/monitor.h
@@ -43,7 +43,6 @@ struct ast_channel_monitor {
 	char read_filename[FILENAME_MAX];
 	char write_filename[FILENAME_MAX];
 	char filename_base[FILENAME_MAX];
-	char beep_id[64];
 	int filename_changed;
 	char *format;
 	int joinfiles;
@@ -54,8 +53,7 @@ struct ast_channel_monitor {
 /* Start monitoring a channel */
 AST_OPTIONAL_API(int, ast_monitor_start,
 		 (struct ast_channel *chan, const char *format_spec,
-		  const char *fname_base, int need_lock, int stream_action,
-		  const char *beep_id),
+		  const char *fname_base, int need_lock, int stream_action),
 		 { return -1; });
 
 /* Stop monitoring a channel */
diff --git a/include/asterisk/musiconhold.h b/include/asterisk/musiconhold.h
index 46cdc1f..480f2ff 100644
--- a/include/asterisk/musiconhold.h
+++ b/include/asterisk/musiconhold.h
@@ -28,21 +28,20 @@ extern "C" {
 #endif
 
 /*!
- * \brief Turn on music on hold on a given channel
+ * \brief Turn on music on hold on a given channel 
  *
  * \param chan The channel structure that will get music on hold
  * \param mclass The class to use if the musicclass is not currently set on
- *               the channel structure.  NULL and the empty string are equivalent.
+ *               the channel structure.
  * \param interpclass The class to use if the musicclass is not currently set on
  *                    the channel structure or in the mclass argument.
- *                    NULL and the empty string are equivalent.
  *
  * \retval Zero on success
  * \retval non-zero on failure
  */
 int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass);
 
-/*! \brief Turn off music on hold on a given channel */
+/*! Turn off music on hold on a given channel */
 void ast_moh_stop(struct ast_channel *chan);
 
 void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, const char *, const char *),
diff --git a/include/asterisk/netsock.h b/include/asterisk/netsock.h
index bd80072..f85bd38 100644
--- a/include/asterisk/netsock.h
+++ b/include/asterisk/netsock.h
@@ -19,8 +19,6 @@
 
 /*! \file
  * \brief Network socket handling
- *
- * \deprecated Use netsock2.h instead
  */
 
 #ifndef _ASTERISK_NETSOCK_H
diff --git a/include/asterisk/netsock2.h b/include/asterisk/netsock2.h
index 3ede990..b14c1af 100644
--- a/include/asterisk/netsock2.h
+++ b/include/asterisk/netsock2.h
@@ -37,31 +37,11 @@ extern "C" {
  * ever include socket.h.
  */
 enum {
-	AST_AF_UNSPEC = AF_UNSPEC,
-	AST_AF_INET   = AF_INET,
-	AST_AF_INET6  = AF_INET6,
+	AST_AF_UNSPEC	= 0,
+	AST_AF_INET	= 2,
+	AST_AF_INET6	= 10,
 };
 
-enum ast_transport {
-	AST_TRANSPORT_UDP   = 1,
-	AST_TRANSPORT_TCP   = 1 << 1,
-	AST_TRANSPORT_TLS   = 1 << 2,
-	AST_TRANSPORT_WS    = 1 << 3,
-	AST_TRANSPORT_WSS   = 1 << 4,
-};
-
-/*!
- * \brief
- * Isolate a 32-bit section of an IPv6 address
- *
- * An IPv6 address can be divided into 4 32-bit chunks. This gives
- * easy access to one of these chunks.
- *
- * \param sin6 A pointer to a struct sockaddr_in6
- * \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
- */
-#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
-
 /*!
  * \brief Socket address structure.
  *
@@ -93,7 +73,7 @@ struct ast_sockaddr {
  * if you know what you're doing.
  *
  * \param addr The IPv4-mapped address to convert
- * \param ast_mapped The resulting IPv4 address
+ * \param mapped_addr The resulting IPv4 address
  * \retval 0 Unable to make the conversion
  * \retval 1 Successful conversion
  */
@@ -263,16 +243,6 @@ static inline char *ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
 }
 
 /*!
- * \since 12.4
- *
- * \brief
- * Count the 1 bits in a netmask
- *
- * \return number of 1 bits
- */
-int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa);
-
-/*!
  * \since 1.8
  *
  * \brief
@@ -340,10 +310,10 @@ static inline char *ast_sockaddr_stringify_port(const struct ast_sockaddr *addr)
  * \brief
  * Splits a string into its host and port components
  *
- * \param[in] str The string to parse. May be modified by writing a NUL at the end of
+ * \param str[in]   The string to parse. May be modified by writing a NUL at the end of
  *                  the host part.
- * \param[out] host Pointer to the host component within \a str.
- * \param[out] port Pointer to the port component within \a str.
+ * \param host[out] Pointer to the host component within \a str.
+ * \param port[out] Pointer to the port component within \a str.
  * \param flags     If set to zero, a port MAY be present. If set to PARSE_PORT_IGNORE, a
  *                  port MAY be present but will be ignored. If set to PARSE_PORT_REQUIRE,
  *                  a port MUST be present. If set to PARSE_PORT_FORBID, a port MUST NOT
@@ -422,23 +392,6 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
 			 int flags, int family);
 
 /*!
- * \brief
- * Apply a netmask to an address and store the result in a separate structure.
- *
- * When dealing with IPv6 addresses, one cannot apply a netmask with a simple
- * logical AND operation.  Futhermore, the incoming address may be an IPv4
- * address and needs to be mapped properly before attempting to apply a rule.
- *
- * \param addr The IP address to apply the mask to.
- * \param netmask The netmask configured in the host access rule.
- * \param result The resultant address after applying the netmask to the given address
- * \retval 0 Successfully applied netmask
- * \retval -1 Failed to apply netmask
- */
-int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
-		struct ast_sockaddr *result);
-
-/*!
  * \since 1.8
  *
  * \brief
@@ -514,7 +467,7 @@ int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr);
  * \brief
  * Determine if an IPv4 address is a multicast address
  *
- * \param addr the address to check
+ * \parm addr the address to check
  *
  * This function checks if an address is in the 224.0.0.0/4 network block.
  *
@@ -577,17 +530,6 @@ int ast_sockaddr_is_any(const struct ast_sockaddr *addr);
 int ast_sockaddr_hash(const struct ast_sockaddr *addr);
 
 /*!
- * \since 12.3
- *
- * \brief
- * Returns a string representation of an ast_transport
- *
- * \retval Name of the tranpsort if it is defined
- * \retval Undefined if the transport is undefined
- */
-const char *ast_transport2str(enum ast_transport transport);
-
-/*!
  * \since 1.8
  *
  * \brief
@@ -705,9 +647,9 @@ int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
 /*!
  * \since 1.8
  *
- * \brief Converts a struct sockaddr_in to a struct ast_sockaddr.
+ * \brief
+ * Converts a struct sockaddr_in to a struct ast_sockaddr.
  *
- * \param addr
  * \param sin The sockaddr_in to convert
  * \return an ast_sockaddr structure
  */
diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h
index 394aed0..cc31ce0 100644
--- a/include/asterisk/optional_api.h
+++ b/include/asterisk/optional_api.h
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2008-2013, Digium, Inc.
+ * Copyright (C) 2008, Digium, Inc.
  *
  * Kevin P. Fleming <kpfleming at digium.com>
  *
@@ -30,6 +30,19 @@
  * have only a part of their functionality dependent on the APIs, and can
  * provide the remainder even if the APIs are not available.
  *
+ * To accomodate this situation, the AST_OPTIONAL_API macro allows an API
+ * function to be declared in a special way, if Asterisk being built on a
+ * platform that supports special compiler and dynamic linker attributes.
+ * If so the API function will actually be a weak symbol, which means if the
+ * provider of the API is not loaded, the symbol can still be referenced (unlike a
+ * strong symbol, which would cause an immediate fault if not defined when
+ * referenced), but it will return NULL signifying the linker/loader was
+ * not able to resolve the symbol. In addition, the macro defines a hidden
+ * 'stub' version of the API call, using a provided function body, and uses
+ * various methods to make the API function symbol actually resolve to
+ * that hidden stub, but only when the *real* provider of the symbol has
+ * not been found.
+ *
  * An example can be found in agi.h:
  *
  * \code
@@ -61,6 +74,19 @@
  * apply special aliases to the function prototype; this can be done
  * by defining AST_API_MODULE just before including the header file
  * containing the AST_OPTIONAL_API macro calls.
+ *
+ * \note If the platform does not provide adequate resources,
+ * then the AST_OPTIONAL_API macro will result in a non-optional function
+ * definition; this means that any consumers of the API functions so
+ * defined will require that the provider of the API functions be
+ * loaded before they can reference the symbols.
+ *
+ * WARNING WARNING WARNING WARNING WARNING
+ *
+ * You MUST add the AST_MODFLAG_GLOBAL_SYMBOLS to the module for which you
+ * are enabling optional_api functionality, or it will fail to work.
+ *
+ * WARNING WARNING WARNING WARNING WARNING
  */
 
 /*!
@@ -73,177 +99,150 @@
  */
 #define AST_OPTIONAL_API_UNAVAILABLE	INT_MIN
 
-/*!
- * \def AST_OPTIONAL_API_NAME(name)
- * \brief Expands to the name of the implementation function.
- */
 
-/*!
- * \def AST_OPTIONAL_API(result, name, proto, stub)
- * \brief Declare an optional API function
- *
- * \param result The type of result the function returns
- * \param name The name of the function
- * \param proto The prototype (arguments) of the function
- * \param stub The code block that will be used by the hidden stub when needed
- *
- * Example usage:
- * \code
- * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd),
- *                  { return AST_OPTIONAL_API_UNAVAILABLE; });
- * \endcode
- */
+#if defined(HAVE_ATTRIBUTE_weak_import) || defined(HAVE_ATTRIBUTE_weak)
 
-/*!
- * \def AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)
- * \brief Declare an optional API function with compiler attributes
- *
- * \param result The type of result the function returns
- * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper)
- * \param name The name of the function
- * \param proto The prototype (arguments) of the function
- * \param stub The code block that will be used by the hidden stub when needed
+/*
+ * This is the Darwin (Mac OS/X) implementation, that only provides the 'weak'
+ * or 'weak_import' compiler attribute for weak symbols. On this platform,
+ *
+ * - The module providing the API will only provide a '__' prefixed version
+ *   of the API function to other modules (this will be hidden from the other
+ *   modules by the macros), so any modules compiled against older versions
+ *   of the module that provided a non-prefixed version of the API function
+ *   will fail to link at runtime.
+ * - In the API module itself, access to the API function without using a
+ *   prefixed name is provided by a static pointer variable that holds the
+ *   function address.
+ * - 'Consumer' modules of the API will use a combination of a weak_import or
+ *   weak symbol, a local stub function, a pointer variable and a constructor
+ *   function (which initializes that pointer variable as the module is being
+ *   loaded) to provide safe, optional access to the API function without any
+ *   special code being required.
  */
 
-#if defined(OPTIONAL_API)
-
-#if !defined(HAVE_ATTRIBUTE_constructor) || !defined(HAVE_ATTRIBUTE_constructor)
-#error OPTIONAL_API requires compiler constructor/destructor support
+#if defined(HAVE_ATTRIBUTE_weak_import)
+#define	__default_attribute	weak_import /* pre-Lion */
+#else
+#define	__default_attribute	weak        /* Lion-onwards */
 #endif
 
-/*!
- * \internal
- * \brief Function pointer to an optional API function.
- *
- * Functions that are declared as optional may have any signature they want;
- * they are cast to this type as needed. We don't use a \c void pointer, because
- * technically data and function pointers are incompatible.
- *
- * \note
- * The may_alias attribute is to avoid type punning/strict aliasing warnings
- * with older GCC's.
- */
-typedef void (*ast_optional_fn)(void) attribute_may_alias;
+#define AST_OPTIONAL_API_NAME(name) __##name
 
-/*!
- * \internal
- * \brief Provide an implementation of an optional API.
- *
- * Any declared usages of this function are linked.
- *
- * \param symname Name of the provided function.
- * \param impl Function pointer to the implementation function.
- */
-void ast_optional_api_provide(const char *symname, ast_optional_fn impl);
+#if defined(AST_API_MODULE)
 
-/*!
- * \internal
- * \brief Remove an implementation of an optional API.
- *
- * Any declared usages of this function are unlinked.
- *
- * \param symname Name of the provided function.
- * \param impl Function pointer to the implementation function.
- */
-void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl);
+#define AST_OPTIONAL_API(result, name, proto, stub) \
+	result AST_OPTIONAL_API_NAME(name) proto; \
+	static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name);
 
-/*!
- * \internal
- * \brief Define a usage of an optional API.
- *
- * If the API has been provided, it will be linked into \a optional_ref.
- * Otherwise, it will be linked to \a stub until an implementation is provided.
- *
- * \param symname Name of the function to use.
- * \param optional_ref Pointer-to-function-pointer to link to impl/stub.
- * \param stub Stub function to link to when impl is not available.
- * \param module Name of the module requesting the API.
- */
-void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref,
-	ast_optional_fn stub, const char *module);
+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)	\
+	result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \
+	static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name);
 
-/*!
- * \internal
- * \brief Remove a usage of an optional API.
- *
- * The \a optional_ref will be linked to the \a stub provided at use time,
- * will no longer be updated if the API is provided/removed.
- *
- * \param symname Name of the function to use.
- * \param optional_ref Pointer-to-function-pointer to link to impl/stub.
- * \param module Name of the module requesting the API.
+#else
+
+#define AST_OPTIONAL_API(result, name, proto, stub) \
+	static result __stub__##name proto stub; \
+	__attribute__((__default_attribute)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \
+	static attribute_unused typeof(__stub__##name) * name; \
+	static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; }
+
+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
+	static __attribute__((attr)) result __stub__##name proto stub; \
+	__attribute__((attr, __default_attribute)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \
+	static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \
+	static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; }
+
+#endif
+
+/* End of Darwin (Mac OS/X) implementation */
+
+#elif defined(HAVE_ATTRIBUTE_weakref)
+
+/*
+ * This is the generic GCC implementation, used when the 'weakref'
+ * compiler attribute is available. On these platforms:
+ *
+ * - The module providing the API will provide a '__' prefixed version
+ *   of the API function to other modules (this will be hidden from the other
+ *   modules by the macros), and also a non-prefixed alias so that modules
+ *   compiled against older versions of the module that provided a non-prefixed
+ *    version of the API function will continue to link properly.
+ * - In the API module itself, access to the API function without using a
+ *   prefixed name is provided by the non-prefixed alias described above.
+ * - 'Consumer' modules of the API will use a combination of a weakref
+ *   symbol, a local stub function, a pointer variable and a constructor function
+ *   (which initializes that pointer variable as the module is being loaded)
+ *   to provide safe, optional access to the API function without any special
+ *   code being required.
  */
-void ast_optional_api_unuse(const char *symname, ast_optional_fn *optional_ref,
-	const char *module);
 
 #define AST_OPTIONAL_API_NAME(name) __##name
 
 #if defined(AST_API_MODULE)
-/* Module defining the API */
-
-#define AST_OPTIONAL_API_IMPL_INIT(name)				\
-	static void __attribute__((constructor)) __init__##name##_impl(void) { \
-		ast_optional_api_provide(#name,				\
-			(ast_optional_fn)AST_OPTIONAL_API_NAME(name));	\
-	}								\
-	static void __attribute__((destructor)) __dtor__##name##_impl(void) { \
-		ast_optional_api_unprovide(#name,			\
-			(ast_optional_fn)AST_OPTIONAL_API_NAME(name));	\
-	}
-
-#define AST_OPTIONAL_API(result, name, proto, stub)			\
-	result AST_OPTIONAL_API_NAME(name) proto;			\
-	static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const \
-	     name = AST_OPTIONAL_API_NAME(name);			\
-	AST_OPTIONAL_API_IMPL_INIT(name)
-
-#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)		\
-	result  __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \
-	static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const \
-	     name = AST_OPTIONAL_API_NAME(name);			\
-	AST_OPTIONAL_API_IMPL_INIT(name)
+
+#define AST_OPTIONAL_API(result, name, proto, stub) \
+	result AST_OPTIONAL_API_NAME(name) proto; \
+	static __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name;
+
+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)	\
+	result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \
+	static __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name;
 
 #else
-/* Module using the API */
 
-#define AST_OPTIONAL_API_INIT(name)					\
-	static void __attribute__((constructor)) __init__##name(void) {	\
-		ast_optional_api_use(#name, (ast_optional_fn *)&name,	\
-			(ast_optional_fn)__stub__##name,		\
-			AST_MODULE);					\
-	}								\
-	static void __attribute__((destructor)) __dtor__##name(void) {	\
-		ast_optional_api_unuse(#name, (ast_optional_fn *)&name, \
-			AST_MODULE);					\
-	}
+#define AST_OPTIONAL_API(result, name, proto, stub) \
+	static result __stub__##name proto stub; \
+	static __attribute__((weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \
+	static attribute_unused typeof(__stub__##name) * name; \
+	static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; }
 
-#define AST_OPTIONAL_API(result, name, proto, stub)			\
-	static result __stub__##name proto stub;			\
-	static attribute_unused						\
-		typeof(__stub__##name) * name;				\
-	AST_OPTIONAL_API_INIT(name)
+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
+	static __attribute__((attr)) result __stub__##name proto stub; \
+	static __attribute__((attr, weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \
+	static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \
+	static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; }
 
-#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)		\
-	static __attribute__((attr)) result __stub__##name proto stub;	\
-	static attribute_unused	__attribute__((attr))			\
-		typeof(__stub__##name) * name;				\
-	AST_OPTIONAL_API_INIT(name)
+#endif
 
-#endif /* defined(AST_API_MODULE) */
+/* End of GCC implementation */
 
-#else /* defined(OPTIONAL_API) */
+#else
 
-/* Non-optional API */
+/* This is the non-optional implementation. */
 
 #define AST_OPTIONAL_API_NAME(name) name
 
-#define AST_OPTIONAL_API(result, name, proto, stub)	\
-	result AST_OPTIONAL_API_NAME(name) proto
+/*!
+ * \brief Define an optional API function
+ *
+ * \param result The type of result the function returns
+ * \param name The name of the function
+ * \param proto The prototype (arguments) of the function
+ * \param stub The code block that will be used by the hidden stub when needed
+ *
+ * Example usage:
+ * \code
+ * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd),
+ *                  { return AST_OPTIONAL_API_UNAVAILABLE; });
+ * \endcode		 
+ */
+#define AST_OPTIONAL_API(result, name, proto, stub) result AST_OPTIONAL_API_NAME(name) proto
+
+/*!
+ * \brief Define an optional API function with compiler attributes
+ *
+ * \param result The type of result the function returns
+ * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper)
+ * \param name The name of the function
+ * \param proto The prototype (arguments) of the function
+ * \param stub The code block that will be used by the hidden stub when needed
+ */
+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto
 
-#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub)	\
-	result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto
+/* End of non-optional implementation */
 
-#endif /* defined(OPTIONAL_API) */
+#endif
 
 #undef AST_API_MODULE
 
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index 0da5799..c922631 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -76,6 +76,8 @@ enum ast_option_flags {
 	AST_OPT_FLAG_DONT_WARN = (1 << 18),
 	/*! End CDRs before the 'h' extension */
 	AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
+	/*! Use DAHDI Timing for generators if available (No longer used) */
+	AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
 	/*! Always fork, even if verbose or debug settings are non-zero */
 	AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
 	/*! Disable log/verbose output to remote consoles */
@@ -122,6 +124,7 @@ enum ast_option_flags {
 #define ast_opt_transmit_silence	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
 #define ast_opt_dont_warn		ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
 #define ast_opt_end_cdr_before_h_exten	ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
+#define ast_opt_internal_timing		ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
 #define ast_opt_always_fork		ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
 #define ast_opt_mute			ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
 #define ast_opt_dbg_module		ast_test_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE)
@@ -134,12 +137,24 @@ enum ast_option_flags {
 
 extern struct ast_flags ast_options;
 
+enum ast_compat_flags {
+	AST_COMPAT_DELIM_PBX_REALTIME = (1 << 0),
+	AST_COMPAT_DELIM_RES_AGI = (1 << 1),
+	AST_COMPAT_APP_SET = (1 << 2),
+};
+
+#define	ast_compat_pbx_realtime	ast_test_flag(&ast_compat, AST_COMPAT_DELIM_PBX_REALTIME)
+#define ast_compat_res_agi	ast_test_flag(&ast_compat, AST_COMPAT_DELIM_RES_AGI)
+#define	ast_compat_app_set	ast_test_flag(&ast_compat, AST_COMPAT_APP_SET)
+
+extern struct ast_flags ast_compat;
+
 extern int option_verbose;
-extern int ast_option_maxfiles;		/*!< Max number of open file handles (files, sockets) */
+extern int option_maxfiles;		/*!< Max number of open file handles (files, sockets) */
 extern int option_debug;		/*!< Debugging */
-extern int ast_option_maxcalls;		/*!< Maximum number of simultaneous channels */
+extern int option_maxcalls;		/*!< Maximum number of simultaneous channels */
 extern unsigned int option_dtmfminduration;	/*!< Minimum duration of DTMF (channel.c) in ms */
-extern double ast_option_maxload;
+extern double option_maxload;
 #if defined(HAVE_SYSINFO)
 extern long option_minmemfree;		/*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
 #endif
diff --git a/include/asterisk/opus.h b/include/asterisk/opus.h
deleted file mode 100644
index 0fbcfa1..0000000
--- a/include/asterisk/opus.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Lorenzo Miniero <lorenzo at meetecho.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Opus Format Attributes (http://tools.ietf.org/html/draft-ietf-payload-rtp-opus)
- *
- * \author Lorenzo Miniero <lorenzo at meetecho.com>
- */
-#ifndef _AST_FORMAT_OPUS_H_
-#define _AST_FORMAT_OPUS_H_
-
-/*! Opus format attribute key value pairs, all are accessible through ast_format_get_value()*/
-enum opus_attr_keys {
-	OPUS_ATTR_KEY_MAX_BITRATE, /*! value is an int (6000-510000 in spec). */
-	OPUS_ATTR_KEY_MAX_PLAYRATE, /*! value is an int (8000-48000), maximum output rate the receiver can render. */
-	OPUS_ATTR_KEY_MINPTIME, /*! value is an int (3-120 in spec, 10-60 in format.c), decoder's minimum length of time in milliseconds. */
-	OPUS_ATTR_KEY_STEREO, /*! value is an int, 1 prefer receiving stereo, 0 prefer mono. */
-	OPUS_ATTR_KEY_CBR, /*! value is an int, 1 use constant bitrate, 0 use variable bitrate. */
-	OPUS_ATTR_KEY_FEC, /*! value is an int, 1 encode with FEC, 0 do not use FEC. */
-	OPUS_ATTR_KEY_DTX, /*! value is an int, 1 dtx is enabled, 0 dtx not enabled. */
-	OPUS_ATTR_KEY_SPROP_CAPTURE_RATE, /*! value is an int (8000-48000), likely input rate we're going to produce. */
-	OPUS_ATTR_KEY_SPROP_STEREO, /*! value is an int, 1 likely to send stereo, 0 likely to send mono. */
-};
-
-#endif /* _AST_FORMAT_OPUS_H */
diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h
deleted file mode 100644
index a8832cd..0000000
--- a/include/asterisk/parking.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking API
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk/stringfields.h"
-#include "asterisk/bridge.h"
-
-/*!
- * \brief The default parking application that Asterisk expects.
- */
-#define PARK_APPLICATION "Park"
-
-/*!
- * \brief The default parking lot
- */
-#define DEFAULT_PARKINGLOT "default"
-
-/*!
- * \brief Defines the type of parked call message being published
- * \since 12
- */
-enum ast_parked_call_event_type {
-	PARKED_CALL = 0,
-	PARKED_CALL_TIMEOUT,
-	PARKED_CALL_GIVEUP,
-	PARKED_CALL_UNPARKED,
-	PARKED_CALL_FAILED,
-	PARKED_CALL_SWAP,
-};
-
-/*!
- * \brief A parked call message payload
- * \since 12
- */
-struct ast_parked_call_payload {
-	struct ast_channel_snapshot *parkee;             /*!< Snapshot of the channel that is parked */
-	struct ast_channel_snapshot *retriever;          /*!< Snapshot of the channel that retrieved the call (may be NULL) */
-	enum ast_parked_call_event_type event_type;      /*!< Reason for issuing the parked call message */
-	long unsigned int timeout;                       /*!< Time remaining before the call times out (seconds ) */
-	long unsigned int duration;                      /*!< How long the parkee has been parked (seconds) */
-	unsigned int parkingspace;                       /*!< Which Parking Space the parkee occupies */
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(parkinglot);                /*!< Name of the parking lot used to park the parkee */
-		AST_STRING_FIELD(parker_dial_string);          /*!< The device string used for call control on parking timeout */
-	);
-};
-
-struct ast_exten;
-
-/*!
- * \brief Constructor for parked_call_payload objects
- * \since 12
- *
- * \param event_type What kind of parked call event is happening
- * \param parkee_snapshot channel snapshot of the parkee
- * \param parker_dial_string dialstring used when the call times out
- * \param retriever_snapshot channel snapshot of the retriever (NULL allowed)
- * \param parkinglot name of the parking lot where the parked call is parked
- * \param parkingspace what numerical parking space the parked call is parked in
- * \param timeout how long the parked call can remain at the point this snapshot is created before timing out
- * \param duration how long the parked call has currently been parked
- *
- * \retval NULL if the parked call payload can't be allocated
- * \retval reference to a newly created parked call payload
- */
-struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
-		struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
-		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
-		unsigned int parkingspace, unsigned long int timeout, unsigned long int duration);
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief accessor for the parking stasis topic
- * \since 12
- *
- * \retval NULL if the parking topic hasn't been created or has been disabled
- * \retval a pointer to the parking topic
- */
-struct stasis_topic *ast_parking_topic(void);
-
-/*!
- * \brief accessor for the parked call stasis message type
- * \since 12
- *
- * \retval NULL if the parking topic hasn't been created or has been canceled
- * \retval a pointer to the parked call message type
- */
-struct stasis_message_type *ast_parked_call_type(void);
-
-/*! @} */
-
-#define PARKING_MODULE_VERSION 1
-
-struct ast_module_info;
-
-/*!
- * \brief A function table providing parking functionality to the \ref AstBridging
- * Bridging API and other consumers
- */
-struct ast_parking_bridge_feature_fn_table {
-
-	/*!
-	 * \brief The version of this function table. If the ABI for this table
-	 * changes, the module version (/ref PARKING_MODULE_VERSION) should be
-	 * incremented.
-	 */
-	unsigned int module_version;
-
-	/*!
-	 * \brief The name of the module that provides this parking functionality
-	 */
-	const char *module_name;
-
-	/*!
-	 * \brief Determine if the context/exten is a "parking" extension
-	 *
-	 * \retval 0 if the extension is not a parking extension
-	 * \retval 1 if the extension is a parking extension
-	 */
-	int (* parking_is_exten_park)(const char *context, const char *exten);
-
-	/*!
-	 * \brief Park the bridge and/or callers that this channel is in
-	 *
-	 * \param parker The bridge_channel parking the bridge
-	 * \param exten Optional. The extension the channel or bridge was parked at if the
-	 * call succeeds.
-	 * \param length Optional. If \c exten is specified, the size of the buffer.
-	 *
-	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
-	 *
-	 * \retval 0 on success
-	 * \retval non-zero on error
-	 */
-	int (* parking_park_call)(struct ast_bridge_channel *parker, char *exten, size_t length);
-
-	/*!
-	 * \brief Perform a blind transfer to a parking extension.
-	 *
-	 * \param parker The \ref bridge_channel object that is initiating the parking
-	 * \param context The context to blind transfer to
-	 * \param exten The extension to blind transfer to
-	 * \param parked_channel_cb Execute the following function on the the channel that gets parked
-	 * \param parked_channel_data Data for the parked_channel_cb
-	 *
-	 * \note If the bridge \ref parker is in has more than one other occupant, the entire
-	 * bridge will be parked using a Local channel
-	 *
-	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
-	 *
-	 * \retval 0 on success
-	 * \retval non-zero on error
-	 */
-	int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context,
-		const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
-
-	/*!
-	 * \brief Perform a direct park on a channel in a bridge.
-	 *
-	 * \param parkee The channel in the bridge to be parked.
-	 * \param parkee_uuid The UUID of the channel being packed.
-	 * \param parker_uuid The UUID of the channel performing the park.
-	 * \param app_data Data to pass to the Park application
-	 *
-	 * \note This must be called within the context of the \ref AstBridging Bridging API.
-	 * External entities should not call this method directly, but should instead use
-	 * the direct call parking method or the blind transfer method.
-	 *
-	 * \retval 0 on success
-	 * \retval non-zero on error
-	 */
-	int (* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);
-
-	/*! \brief The module info for the module registering this parking provider */
-	const struct ast_module_info *module_info;
-};
-
-/*!
- * \brief Determine if the context/exten is a "parking" extension
- *
- * \retval 0 if the extension is not a parking extension
- * \retval 1 if the extension is a parking extension
- */
-int ast_parking_is_exten_park(const char *context, const char *exten);
-
-/*!
- * \brief Park the bridge and/or callers that this channel is in
- *
- * \param parker The bridge_channel parking the bridge
- * \param exten Optional. The extension the channel or bridge was parked at if the
- * call succeeds.
- * \param length Optional. If \c exten is specified, the size of the buffer.
- *
- * \note This is safe to be called outside of the \ref AstBridging Bridging API.
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length);
-
-/*!
- * \brief Perform a blind transfer to a parking extension.
- *
- * \param parker The \ref bridge_channel object that is initiating the parking
- * \param context The context to blind transfer to
- * \param exten The extension to blind transfer to
- * \param exten The extension to blind transfer to
- * \param parked_channel_cb Execute the following function on the the channel that gets parked
- * \param parked_channel_data Data for the parked_channel_cb
- *
- * \note If the bridge \ref parker is in has more than one other occupant, the entire
- * bridge will be parked using a Local channel
- *
- * \note This is safe to be called outside of the \ref AstBridging Bridging API.
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context,
-	const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
-
-/*!
- * \brief Perform a direct park on a channel in a bridge.
- *
- * \param parkee The channel in the bridge to be parked.
- * \param parkee_uuid The UUID of the channel being packed.
- * \param parker_uuid The UUID of the channel performing the park.
- * \param app_data Data to pass to the Park application
- *
- * \note This must be called within the context of the \ref AstBridging Bridging API.
- * External entities should not call this method directly, but should instead use
- * the direct call parking method or the blind transfer method.
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);
-
-/*!
- * \brief Register a parking provider
- *
- * \param fn_table The \ref ast_parking_bridge_feature_fn_table to register
- *
- * \retval 0 on success
- * \retval -1 on error
- */
-int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table);
-
-/*!
- * \brief Unregister the current parking provider
- *
- * \param The module name of the provider to unregister
- *
- * \retval 0 if the parking provider \c module_name was unregsistered
- * \retval -1 on error
- */
-int ast_parking_unregister_bridge_features(const char *module_name);
-
-/*!
- * \brief Check whether a parking provider is registered
- *
- * \retval 0 if there is no parking provider regsistered
- * \retval 1 if there is a parking provider regsistered
- */
-int ast_parking_provider_registered(void);
diff --git a/include/asterisk/paths.h b/include/asterisk/paths.h
index ea0c561..987ac81 100644
--- a/include/asterisk/paths.h
+++ b/include/asterisk/paths.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Paths to configurable Asterisk directories
  * 
@@ -23,7 +23,6 @@ extern const char *ast_config_AST_CONFIG_FILE;
 extern const char *ast_config_AST_MODULE_DIR;
 extern const char *ast_config_AST_SPOOL_DIR;
 extern const char *ast_config_AST_MONITOR_DIR;
-extern const char *ast_config_AST_RECORDING_DIR;
 extern const char *ast_config_AST_VAR_DIR;
 extern const char *ast_config_AST_DATA_DIR;
 extern const char *ast_config_AST_LOG_DIR;
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index 795af05..40bd6d3 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -140,15 +140,6 @@ struct ast_custom_function {
 	/*! Write function, if write is supported */
 	ast_acf_write_fn_t write;	/*!< Write function, if write is supported */
 	struct ast_module *mod;         /*!< Module this custom function belongs to */
-	unsigned int read_escalates:1;  /*!< The read function is to be considered
-					 * 'dangerous', and should not be run directly
-					 * from external interfaces (AMI, ARI, etc.)
-					 * \since 12 */
-	unsigned int write_escalates:1; /*!< The write function is to be considerd
-					 * 'dangerous', and should not be run directly
-					 * from external interfaces (AMI, ARI, etc.)
-					 * \since 12 */
-
 	AST_RWLIST_ENTRY(ast_custom_function) acflist;
 };
 
@@ -300,7 +291,21 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
 
 /*!
- * \brief Destroy a context (matches the specified context (or ANY context if NULL)
+ * \brief Destroy a context by name
+ *
+ * \param context Name of the context to destroy
+ * \param registrar who registered it
+ *
+ * You can optionally leave out the registrar parameter.  It will find it
+ * based on the context name.
+ *
+ * \retval -1 context not found
+ * \retval 0 Success
+ */
+int ast_context_destroy_by_name(const char *context, const char *registrar);
+
+/*!
+ * \brief Destroy a context (matches the specified context or ANY context if NULL)
  *
  * \param con context to destroy
  * \param registrar who registered it
@@ -489,17 +494,6 @@ int ast_add_extension2(struct ast_context *con, int replace, const char *extensi
 	const char *application, void *data, void (*datad)(void *), const char *registrar);
 
 /*!
- * \brief Same as ast_add_extension2, but assumes you have already locked context
- * \since 12.0.0
- *
- * \note con must be write locked prior to calling. For details about the arguments,
- *       check ast_add_extension2()
- */
-int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension,
-	int priority, const char *label, const char *callerid,
-	const char *application, void *data, void (*datad)(void *), const char *registrar);
-
-/*!
  * \brief Map devstate to an extension state.
  *
  * \param[in] devstate device state
@@ -851,7 +845,7 @@ int ast_context_add_include(const char *context, const char *include,
  * \brief Add a context include
  *
  * \param con context to add the include to
- * \param value include value to add
+ * \param include include to add
  * \param registrar who registered the context
  *
  * Adds an include taking a struct ast_context as the first parameter
@@ -1102,77 +1096,13 @@ int ast_async_goto(struct ast_channel *chan, const char *context, const char *ex
  */
 int ast_async_goto_by_name(const char *chan, const char *context, const char *exten, int priority);
 
-/*!
- * \brief Synchronously or asynchronously make an outbound call and send it to a
- * particular extension
- *
- * \param type The channel technology to create
- * \param cap The format capabilities for the channel
- * \param addr Address data to pass to the channel technology driver
- * \param timeout How long we should attempt to dial the outbound channel
- * \param context The destination context for the outbound channel
- * \param exten The destination extension for the outbound channel
- * \param priority The destination priority for the outbound channel
- * \param reason Optional.  If provided, the dialed status of the outgoing channel.
- *        Codes are AST_CONTROL_xxx values.  Valid only if synchronous is non-zero.
- * \param synchronous If zero then don't wait for anything.
- *        If one then block until the outbound channel answers or the call fails.
- *        If greater than one then wait for the call to complete or if the call doesn't
- *        answer and failed at context exists then run a channel named OutgoingSpoolFailed
- *        at failed at context.
- * \param cid_num The caller ID number to set on the outbound channel
- * \param cid_name The caller ID name to set on the outbound channel
- * \param vars Variables to set on the outbound channel
- * \param account The accountcode for the outbound channel
- * \param locked_channel Optional.  The outbound channel that was created if success
- *        is returned.  Otherwise it is set to NULL.  This is returned both locked
- *        and reference bumped.
- * \param early_media If non-zero the channel "answers" when progress is indicated.
- * \param assignedids Optional. The uniqueid(s) to assign the channel(s) that are created.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
-	int timeout, const char *context, const char *exten, int priority, int *reason,
-	int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
-	const char *account, struct ast_channel **locked_channel, int early_media,
-	const struct ast_assigned_ids *assignedids);
-
-/*!
- * \brief Synchronously or asynchronously make an outbound call and execute an
- *  application on the channel.
- *
- * Note that when the application stops executing, the channel is hungup.
- *
- * \param type The channel technology to create
- * \param cap The format capabilities for the channel
- * \param addr Address data to pass to the channel technology driver
- * \param timeout How long we should attempt to dial the outbound channel
- * \param app The name of the application to execute
- * \param appdata Data to pass to the application
- * \param reason Optional.  If provided, the dialed status of the outgoing channel.
- *        Codes are AST_CONTROL_xxx values.  Valid only if synchronous is non-zero.
- * \param synchronous If zero then don't wait for anything.
- *        If one then block until the outbound channel answers or the call fails.
- *        If greater than one then wait for the call to complete.
- * \param cid_num The caller ID number to set on the outbound channel
- * \param cid_name The caller ID name to set on the outbound channel
- * \param vars Variables to set on the outbound channel
- * \param account The accountcode for the outbound channel
- * \param locked_channel Optional.  The outbound channel that was created if success
- *        is returned.  Otherwise it is set to NULL.  This is returned both locked
- *        and reference bumped.
- * \param assignedids Optional. The uniqueid(s) to assign the channel(s) that are created.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
-	int timeout, const char *app, const char *appdata, int *reason, int synchronous,
-	const char *cid_num, const char *cid_name, struct ast_variable *vars,
-	const char *account, struct ast_channel **locked_channel,
-	const struct ast_assigned_ids *assignedids);
+/*! Synchronously or asynchronously make an outbound call and send it to a
+   particular extension */
+int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media);
+
+/*! Synchronously or asynchronously make an outbound call and send it to a
+   particular application with given extension */
+int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
 
 /*!
  * \brief Evaluate a condition
diff --git a/include/asterisk/phoneprov.h b/include/asterisk/phoneprov.h
deleted file mode 100644
index 24e8cc9..0000000
--- a/include/asterisk/phoneprov.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014 - Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _ASTERISK_PHONEPROV_H
-#define _ASTERISK_PHONEPROV_H
-
-#include "asterisk.h"
-#include "asterisk/inline_api.h"
-
-enum ast_phoneprov_std_variables {
-	AST_PHONEPROV_STD_MAC = 0,
-	AST_PHONEPROV_STD_PROFILE,
-	AST_PHONEPROV_STD_USERNAME,
-	AST_PHONEPROV_STD_DISPLAY_NAME,
-	AST_PHONEPROV_STD_SECRET,
-	AST_PHONEPROV_STD_LABEL,
-	AST_PHONEPROV_STD_CALLERID,
-	AST_PHONEPROV_STD_TIMEZONE,
-	AST_PHONEPROV_STD_LINENUMBER,
-	AST_PHONEPROV_STD_LINEKEYS,
-	AST_PHONEPROV_STD_SERVER,
-	AST_PHONEPROV_STD_SERVER_PORT,
-	AST_PHONEPROV_STD_SERVER_IFACE,
-	AST_PHONEPROV_STD_VOICEMAIL_EXTEN,
-	AST_PHONEPROV_STD_EXTENSION_LENGTH,
-	AST_PHONEPROV_STD_TZOFFSET,
-	AST_PHONEPROV_STD_DST_ENABLE,
-	AST_PHONEPROV_STD_DST_START_MONTH,
-	AST_PHONEPROV_STD_DST_START_MDAY,
-	AST_PHONEPROV_STD_DST_START_HOUR,
-	AST_PHONEPROV_STD_DST_END_MONTH,
-	AST_PHONEPROV_STD_DST_END_MDAY,
-	AST_PHONEPROV_STD_DST_END_HOUR,
-	AST_PHONEPROV_STD_VAR_LIST_LENGTH,	/* This entry must always be the last in the list */
-};
-
-/*!
- * \brief Returns the string respresentation of a phoneprov standard variable.
- * \param var One of enum ast_phoneprov_std_variables
- *
- * \return The string representation or NULL if not found.
- */
-const char *ast_phoneprov_std_variable_lookup(enum ast_phoneprov_std_variables var);
-
-/*!
- * \brief Causes the provider to load its users.
- *
- * This function is called by phoneprov in response to a
- * ast_phoneprov_provider_register call by the provider.
- * It may also be called by phoneprov to request a reload in
- * response to the res_phoneprov module being reloaded.
- *
- * \retval 0 if successful
- * \retval non-zero if failure
- */
-typedef int(*ast_phoneprov_load_users_cb)(void);
-
-/*!
- * \brief Registers a config provider to phoneprov.
- * \param provider_name The name of the provider
- * \param load_users Callback that gathers user variables then loads them by
- * calling ast_phoneprov_add_extension once for each extension.
- *
- * \retval 0 if successful
- * \retval non-zero if failure
- */
-int ast_phoneprov_provider_register(char *provider_name,
-	ast_phoneprov_load_users_cb load_users);
-
-/*!
- * \brief Unegisters a config provider from phoneprov and frees its resources.
- * \param provider_name The name of the provider
- */
-void ast_phoneprov_provider_unregister(char *provider_name);
-
-/*!
- * \brief Adds an extension
- * \param provider_name The name of the provider
- * \param defaults An ast_vat_t linked list of the extension's variables.
- * The list is automatically cloned and it must contain at least MACADDRESS
- * and USERNAME entries.
- *
- * \retval 0 if successful
- * \retval non-zero if failure
- */
-int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars);
-
-/*!
- * \brief Deletes an extension
- * \param provider_name The name of the provider
- * \param macaddress The mac address of the extension
- */
-void ast_phoneprov_delete_extension(char *provider_name, char *macaddress);
-
-/*!
- * \brief Deletes all extensions for this provider
- * \param provider_name The name of the provider
- */
-void ast_phoneprov_delete_extensions(char *provider_name);
-
-#endif /* _ASTERISK_PHONEPROV_H */
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/include/asterisk/pickup.h b/include/asterisk/pickup.h
deleted file mode 100644
index 17b38e7..0000000
--- a/include/asterisk/pickup.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Call Pickup API
- *
- * Includes code and algorithms from the Zapata library.
- *
- */
-
-#ifndef _AST_PICKUP_H
-#define _AST_PICKUP_H
-
-/*!
- * \brief Test if a channel can be picked up.
- *
- * \param chan Channel to test if can be picked up.
- *
- * \note This function assumes that chan is locked.
- *
- * \return TRUE if channel can be picked up.
- */
-int ast_can_pickup(struct ast_channel *chan);
-
-/*!
- * \brief Find a pickup channel target by group.
- *
- * \param chan channel that initiated pickup.
- *
- * \retval target on success.  The returned channel is locked and reffed.
- * \retval NULL on error.
- */
-struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan);
-
-/*!
- * \brief Pickup a call
- *
- * \param chan The channel that initiated the pickup
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_pickup_call(struct ast_channel *chan);
-
-/*!
- * \brief Pickup a call target.
- *
- * \param chan channel that initiated pickup.
- * \param target channel to be picked up.
- *
- * \note This function assumes that target is locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target);
-
-/*!
- * \brief accessor for call pickup message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-struct stasis_message_type *ast_call_pickup_type(void);
-
-/*!
- * \brief Initialize pickup
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-int ast_pickup_init(void);
-
-#endif /* _AST_PICKUP_H */
diff --git a/include/asterisk/poll-compat.h b/include/asterisk/poll-compat.h
index a0f1fe9..cbb6109 100644
--- a/include/asterisk/poll-compat.h
+++ b/include/asterisk/poll-compat.h
@@ -9,7 +9,7 @@
  */
 
 /*---------------------------------------------------------------------------*\
-  $Id: poll-compat.h 284598 2010-09-02 05:02:54Z tilghman $
+  $Id$
 
   NAME
 
diff --git a/include/asterisk/presencestate.h b/include/asterisk/presencestate.h
index 1cdf73e..dbbe5dc 100644
--- a/include/asterisk/presencestate.h
+++ b/include/asterisk/presencestate.h
@@ -62,9 +62,9 @@ enum ast_presence_state ast_presence_state_val(const char *val);
 /*!
  * \brief Asks a presence state provider for the current presence state.
  *
- * \param presence_provider The presence provider to retrieve the state from.
- * \param subtype The output paramenter to store the subtype string in. Must be freed if returned
- * \param message The output paramenter to store the message string in. Must be freed if returned
+ * \param presence_provider, The presence provider to retrieve the state from.
+ * \param subtype, The output paramenter to store the subtype string in. Must be freed if returned
+ * \param message, The output paramenter to store the message string in. Must be freed if returned
  *
  * \retval presence state value on success,
  * \retval -1 on failure.
@@ -78,9 +78,9 @@ enum ast_presence_state ast_presence_state(const char *presence_provider, char *
  * requested (such as a base64 decode). In such instances, use of the event cache is not suitable
  * and should be bypassed.
  *
- * \param presence_provider The presence provider to retrieve the state from.
- * \param subtype The output paramenter to store the subtype string in. Must be freed if returned
- * \param message The output paramenter to store the message string in. Must be freed if returned
+ * \param presence_provider, The presence provider to retrieve the state from.
+ * \param subtype, The output paramenter to store the subtype string in. Must be freed if returned
+ * \param message, The output paramenter to store the message string in. Must be freed if returned
  *
  * \retval presence state value on success,
  * \retval -1 on failure.
@@ -149,47 +149,6 @@ int ast_presence_state_prov_add(const char *label, ast_presence_state_prov_cb_ty
  */
 int ast_presence_state_prov_del(const char *label);
 
-/*!
- * \brief Get presence state message type
- * \retval Stasis message type for presence state messages
- * \since 12
- */
-struct stasis_message_type *ast_presence_state_message_type(void);
-
-/*!
- * \brief Get presence state topic
- * \retval Stasis topic for presence state messages
- * \since 12
- */
-struct stasis_topic *ast_presence_state_topic_all(void);
-
-/*!
- * \brief Get caching presence state topic
- * \retval Caching Stasis topic for presence state messages
- * \since 12
- */
-struct stasis_topic *ast_presence_state_topic_cached(void);
-
-/*!
- * \brief Backend cache for ast_presence_state_topic_cached()
- * \retval Cache of \ref ast_presence_state_message.
- * \since 12
- */
-struct stasis_cache *ast_presence_state_cache(void);
-
-/*!
- * \brief Stasis message payload representing a presence state update
- * \since 12
- */
-struct ast_presence_state_message {
-		AST_DECLARE_STRING_FIELDS(
-			AST_STRING_FIELD(provider);	/*!< Provider that produced this presence state message */
-			AST_STRING_FIELD(subtype);	/*!< Subtype associated with this presence state message */
-			AST_STRING_FIELD(message);	/*!< The message to convey */
-		);
-		enum ast_presence_state state;		/*!< The state associated with this presence state message */
-};
-
 int ast_presence_state_engine_init(void);
 #endif
 
diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h
index b0a1a22..802dcd9 100644
--- a/include/asterisk/res_fax.h
+++ b/include/asterisk/res_fax.h
@@ -29,7 +29,6 @@
 #include <asterisk/frame.h>
 #include <asterisk/cli.h>
 #include <asterisk/stringfields.h>
-#include <asterisk/manager.h>
 
 /*! \brief capabilities for res_fax to locate a fax technology module */
 enum ast_fax_capabilities {
@@ -53,8 +52,8 @@ enum ast_fax_capabilities {
 enum ast_fax_modems {
 	/*! V.17 */
 	AST_FAX_MODEM_V17 = (1 << 0),
-	/*! V.27 */
-	AST_FAX_MODEM_V27 = (1 << 1),
+	/*! V.27ter */
+	AST_FAX_MODEM_V27TER = (1 << 1),
 	/*! V.29 */
 	AST_FAX_MODEM_V29 = (1 << 2),
 	/*! V.34 */
@@ -175,16 +174,14 @@ struct ast_fax_session_details {
 	struct ast_fax_t38_parameters our_t38_parameters;
 	/*! the other endpoint's T.38 session parameters, if any */
 	struct ast_fax_t38_parameters their_t38_parameters;
+	/*! T.38 negotiation in ms */
+	unsigned int t38timeout;
 	/*! the id of the t.38 gateway framehook for this channel */
 	int gateway_id;
 	/*! the timeout for this gateway in seconds */
 	int gateway_timeout;
 	/*! the id of the faxdetect framehook for this channel */
 	int faxdetect_id;
-	/*! The timeout for this fax detect in seconds */
-	int faxdetect_timeout;
-	/*! flags used for fax detection */
-	int faxdetect_flags;
 };
 
 struct ast_fax_tech;
@@ -260,9 +257,6 @@ struct ast_fax_tech {
 	char * (* const cli_show_capabilities)(int);
 	/*! displays details about the fax session */
 	char * (* const cli_show_session)(struct ast_fax_session *, int);
-	/*! Generates manager event detailing the fax session */
-	void (* const manager_fax_session)(struct mansession *,
-		const char *, struct ast_fax_session *);
 	/*! displays statistics from the fax technology module */
 	char * (* const cli_show_stats)(int);
 	/*! displays settings from the fax technology module */
@@ -284,9 +278,6 @@ unsigned int ast_fax_maxrate(void);
 /*! \brief convert an ast_fax_state to a string */
 const char *ast_fax_state_to_str(enum ast_fax_state state);
 
-/*! \brief get string representation of a FAX session's operation */
-const char *ast_fax_session_operation_str(struct ast_fax_session *s);
-
 /*!
  * \brief Log message at FAX or recommended level
  *
diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h
deleted file mode 100644
index 8839fd6..0000000
--- a/include/asterisk/res_hep.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2014, Digium, Inc.
- *
- * Alexandr Dubovikov <alexandr.dubovikov at sipcapture.org>
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Routines for integration with Homer using HEPv3
- *
- * \author Alexandr Dubovikov <alexandr.dubovikov at sipcapture.org>
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-#ifndef _ASTERISK_RES_HEPV3_H
-#define _ASTERISK_RES_HEPV3_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/netsock2.h"
-
-/*! \brief HEPv3 Packet Capture Types */
-enum hepv3_capture_type {
-	HEPV3_CAPTURE_TYPE_SIP    = 0x01,
-	HEPV3_CAPTURE_TYPE_H323   = 0x02,
-	HEPV3_CAPTURE_TYPE_SDP    = 0x03,
-	HEPV3_CAPTURE_TYPE_RTP    = 0x04,
-	HEPV3_CAPTURE_TYPE_RTCP   = 0x05,
-	HEPV3_CAPTURE_TYPE_MGCP   = 0x06,
-	HEPV3_CAPTURE_TYPE_MEGACO = 0x07,
-	HEPV3_CAPTURE_TYPE_M2UA   = 0x08,
-	HEPV3_CAPTURE_TYPE_M3UA   = 0x09,
-	HEPV3_CAPTURE_TYPE_IAX    = 0x10,
-};
-
-/*! \brief HEPv3 Capture Info */
-struct hepv3_capture_info {
-	/*! The source address of the packet */
-	struct ast_sockaddr src_addr;
-	/*! The destination address of the packet */
-	struct ast_sockaddr dst_addr;
-	/*! The time the packet was captured */
-	struct timeval capture_time;
-	/*! The actual payload */
-	void *payload;
-	/*! Some UUID for the packet */
-	char *uuid;
-	/*! The \ref hepv3_capture_type packet type captured */
-	enum hepv3_capture_type capture_type;
-	/*! The size of the payload */
-	size_t len;
-	/*! If non-zero, the payload accompanying this capture info will be compressed */
-	unsigned int zipped:1;
-};
-
-/*!
- * \brief Create a \ref hepv3_capture_info object
- *
- * This returned object is an ao2 reference counted object.
- *
- * Any attribute in the returned \ref hepv3_capture_info that is a
- * pointer should point to something that is allocated on the heap,
- * as it will be free'd when the \ref hepv3_capture_info object is
- * reclaimed.
- *
- * \param payload The payload to send to the HEP capture node
- * \param len     Length of \ref payload
- *
- * \retval A \ref hepv3_capture_info ref counted object on success
- * \retval NULL on error
- */
-struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len);
-
-/*!
- * \brief Send a generic packet capture to HEPv3
- *
- * \param capture_info Information describing the packet. This
- * should be a reference counted object, created via
- * \ref hepv3_create_capture_info.
- *
- * Once this function is called, it assumes ownership of the
- * \ref capture_info object and steals the reference of the
- * object. Regardless of success or failure, the calling function
- * should assumed that this function will own the object.
- *
- * \retval 0 on success
- * \retval -1 on error
- */
-int hepv3_send_packet(struct hepv3_capture_info *capture_info);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_RES_HEPV3_H */
diff --git a/include/asterisk/res_mwi_external.h b/include/asterisk/res_mwi_external.h
deleted file mode 100644
index 7698a1b..0000000
--- a/include/asterisk/res_mwi_external.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Core external MWI support.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_RES_MWI_EXTERNAL_H
-#define _ASTERISK_RES_MWI_EXTERNAL_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C"
-{
-#endif
-
-/* ------------------------------------------------------------------- */
-
-/*!
- * \brief Increase the external MWI resource module reference count.
- * \since 12.1.0
- *
- * \return Nothing
- */
-void ast_mwi_external_ref(void);
-
-/*!
- * \brief Decrease the external MWI resource module reference count.
- * \since 12.1.0
- *
- * \return Nothing
- */
-void ast_mwi_external_unref(void);
-
-struct ast_mwi_mailbox_object;
-
-/*! \brief Convienience unref function for mailbox object. */
-#define ast_mwi_mailbox_unref(mailbox) ao2_ref((struct ast_mwi_mailbox_object *) mailbox, -1)
-
-/*!
- * \brief Allocate an external MWI object.
- * \since 12.1.0
- *
- * \param mailbox_id Name of mailbox.
- *
- * \retval object on success.  The object is an ao2 object.
- * \retval NULL on error.
- */
-struct ast_mwi_mailbox_object *ast_mwi_mailbox_alloc(const char *mailbox_id);
-
-/*!
- * \brief Get mailbox id.
- * \since 12.1.0
- *
- * \param mailbox Object to get id.
- *
- * \return mailbox_id of the object.
- *
- * \note This should never return NULL unless there is a bug in sorcery.
- */
-const char *ast_mwi_mailbox_get_id(const struct ast_mwi_mailbox_object *mailbox);
-
-/*!
- * \brief Get the number of new messages.
- * \since 12.1.0
- *
- * \param mailbox Object to get number of new messages.
- *
- * \return Number of new messages.
- */
-unsigned int ast_mwi_mailbox_get_msgs_new(const struct ast_mwi_mailbox_object *mailbox);
-
-/*!
- * \brief Get the number of old messages.
- * \since 12.1.0
- *
- * \param mailbox Object to get number of old messages.
- *
- * \return Number of old messages.
- */
-unsigned int ast_mwi_mailbox_get_msgs_old(const struct ast_mwi_mailbox_object *mailbox);
-
-/*!
- * \brief Copy the external MWI counts object.
- * \since 12.1.0
- *
- * \param mailbox What to copy.
- *
- * \retval copy on success.  The object is an ao2 object.
- * \retval NULL on error.
- */
-struct ast_mwi_mailbox_object *ast_mwi_mailbox_copy(const struct ast_mwi_mailbox_object *mailbox);
-
-/*!
- * \brief Set the number of new messages.
- * \since 12.1.0
- *
- * \param mailbox Object to set number of new messages.
- * \param num_msgs Number of messages to set.
- *
- * \return Nothing
- */
-void ast_mwi_mailbox_set_msgs_new(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs);
-
-/*!
- * \brief Set the number of old messages.
- * \since 12.1.0
- *
- * \param mailbox Object to set number of old messages.
- * \param num_msgs Number of messages to set.
- *
- * \return Nothing
- */
-void ast_mwi_mailbox_set_msgs_old(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs);
-
-/*!
- * \brief Update the external MWI counts with the given object.
- * \since 12.1.0
- *
- * \param mailbox What to update.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_mwi_mailbox_update(struct ast_mwi_mailbox_object *mailbox);
-
-/*!
- * \brief Delete matching external MWI object.
- * \since 12.1.0
- *
- * \param mailbox_id Name of mailbox to delete.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_mwi_mailbox_delete(const char *mailbox_id);
-
-/*!
- * \brief Delete all external MWI objects selected by the regular expression.
- * \since 12.1.0
- *
- * \param regex Regular expression in extended syntax.  (NULL is same as "")
- *
- * \note The provided regex is treated as extended case sensitive.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_mwi_mailbox_delete_by_regex(const char *regex);
-
-/*!
- * \brief Delete all external MWI objects.
- * \since 12.1.0
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_mwi_mailbox_delete_all(void);
-
-/*!
- * \brief Get matching external MWI object.
- * \since 12.1.0
- *
- * \param mailbox_id Name of mailbox to retrieve.
- *
- * \retval requested mailbox on success.  The object is an ao2 object.
- * \retval NULL on error or no mailbox.
- *
- * \note The object must be treated as read-only.
- */
-const struct ast_mwi_mailbox_object *ast_mwi_mailbox_get(const char *mailbox_id);
-
-/*!
- * \brief Get all external MWI objects selected by the regular expression.
- * \since 12.1.0
- *
- * \param regex Regular expression in extended syntax.  (NULL is same as "")
- *
- * \note The provided regex is treated as extended case sensitive.
- *
- * \retval container of struct ast_mwi_mailbox_object on success.
- * \retval NULL on error.
- *
- * \note The objects in the container must be treated as read-only.
- */
-struct ao2_container *ast_mwi_mailbox_get_by_regex(const char *regex);
-
-/*!
- * \brief Get all external MWI objects.
- * \since 12.1.0
- *
- * \retval container of struct ast_mwi_mailbox_object on success.
- * \retval NULL on error.
- *
- * \note The objects in the container must be treated as read-only.
- */
-struct ao2_container *ast_mwi_mailbox_get_all(void);
-
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_RES_MWI_EXTERNAL_H */
diff --git a/include/asterisk/res_odbc.h b/include/asterisk/res_odbc.h
index 7d9d4a1..2f63ec5 100644
--- a/include/asterisk/res_odbc.h
+++ b/include/asterisk/res_odbc.h
@@ -104,11 +104,9 @@ int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) __attribute__((d
  * \brief Retrieves a connected ODBC object
  * \param name The name of the ODBC class for which a connection is needed.
  * \param flags One or more of the following flags:
- *	\li RES_ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle.  Usually unnecessary.
- *	\li RES_ODBC_INDEPENDENT_CONNECTION Return a handle which is independent from all others.  Usually used when starting a transaction.
- *	\li RES_ODBC_CONNECTED Only return a connected handle.  Intended for use with peers which use idlecheck, which are checked periodically for reachability.
- * \param  file, function, lineno
- *
+ * \li RES_ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle.  Usually unnecessary.
+ * \li RES_ODBC_INDEPENDENT_CONNECTION Return a handle which is independent from all others.  Usually used when starting a transaction.
+ * \li RES_ODBC_CONNECTED Only return a connected handle.  Intended for use with peers which use idlecheck, which are checked periodically for reachability.
  * \return ODBC object
  * \retval NULL if there is no connection available with the requested name.
  *
@@ -223,4 +221,10 @@ int ast_odbc_clear_cache(const char *database, const char *tablename);
  */
 SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind);
 
+/*! \brief Checks if the database natively supports implicit conversion from an empty string to a number (0).
+ * \param obj The ODBC object
+ * \return Returns 1 if the implicit conversion is valid and non-text columns can take empty strings, 0 if the conversion is not valid and NULLs should be used instead '\'
+ */
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj);
+
 #endif /* _ASTERISK_RES_ODBC_H */
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
deleted file mode 100644
index 2617e95..0000000
--- a/include/asterisk/res_pjsip.h
+++ /dev/null
@@ -1,1959 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _RES_PJSIP_H
-#define _RES_PJSIP_H
-
-#include "asterisk/stringfields.h"
-/* Needed for struct ast_sockaddr */
-#include "asterisk/netsock2.h"
-/* Needed for linked list macros */
-#include "asterisk/linkedlists.h"
-/* Needed for ast_party_id */
-#include "asterisk/channel.h"
-/* Needed for ast_sorcery */
-#include "asterisk/sorcery.h"
-/* Needed for ast_dnsmgr */
-#include "asterisk/dnsmgr.h"
-/* Needed for ast_endpoint */
-#include "asterisk/endpoints.h"
-/* Needed for ast_t38_ec_modes */
-#include "asterisk/udptl.h"
-/* Needed for pj_sockaddr */
-#include <pjlib.h>
-/* Needed for ast_rtp_dtls_cfg struct */
-#include "asterisk/rtp_engine.h"
-/* Needed for AST_VECTOR macro */
-#include "asterisk/vector.h"
-/* Needed for ast_sip_for_each_channel_snapshot struct */
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
-
-/* Forward declarations of PJSIP stuff */
-struct pjsip_rx_data;
-struct pjsip_module;
-struct pjsip_tx_data;
-struct pjsip_dialog;
-struct pjsip_transport;
-struct pjsip_tpfactory;
-struct pjsip_tls_setting;
-struct pjsip_tpselector;
-
-/*!
- * \brief Structure for SIP transport information
- */
-struct ast_sip_transport_state {
-	/*! \brief Transport itself */
-	struct pjsip_transport *transport;
-
-	/*! \brief Transport factory */
-	struct pjsip_tpfactory *factory;
-};
-
-#define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias"
-
-/*!
- * Details about a SIP domain alias
- */
-struct ast_sip_domain_alias {
-	/*! Sorcery object details */
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/*! Domain to be aliased to */
-		AST_STRING_FIELD(domain);
-	);
-};
-
-/*! \brief Maximum number of ciphers supported for a TLS transport */
-#define SIP_TLS_MAX_CIPHERS 64
-
-/*
- * \brief Transport to bind to
- */
-struct ast_sip_transport {
-	/*! Sorcery object details */
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/*! Certificate of authority list file */
-		AST_STRING_FIELD(ca_list_file);
-		/*! Public certificate file */
-		AST_STRING_FIELD(cert_file);
-		/*! Optional private key of the certificate file */
-		AST_STRING_FIELD(privkey_file);
-		/*! Password to open the private key */
-		AST_STRING_FIELD(password);
-		/*! External signaling address */
-		AST_STRING_FIELD(external_signaling_address);
-		/*! External media address */
-		AST_STRING_FIELD(external_media_address);
-		/*! Optional domain to use for messages if provided could not be found */
-		AST_STRING_FIELD(domain);
-		);
-	/*! Type of transport */
-	enum ast_transport type;
-	/*! Address and port to bind to */
-	pj_sockaddr host;
-	/*! Number of simultaneous asynchronous operations */
-	unsigned int async_operations;
-	/*! Optional external port for signaling */
-	unsigned int external_signaling_port;
-	/*! TLS settings */
-	pjsip_tls_setting tls;
-	/*! Configured TLS ciphers */
-	pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS];
-	/*! Optional local network information, used for NAT purposes */
-	struct ast_ha *localnet;
-	/*! DNS manager for refreshing the external address */
-	struct ast_dnsmgr_entry *external_address_refresher;
-	/*! Optional external address information */
-	struct ast_sockaddr external_address;
-	/*! Transport state information */
-	struct ast_sip_transport_state *state;
-	/*! QOS DSCP TOS bits */
-	unsigned int tos;
-	/*! QOS COS value */
-	unsigned int cos;
-	/*! Write timeout */
-	int write_timeout;
-};
-
-/*!
- * \brief Structure for SIP nat hook information
- */
-struct ast_sip_nat_hook {
-	/*! Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! Callback for when a message is going outside of our local network */
-	void (*outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport);
-};
-
-/*!
- * \brief Contact associated with an address of record
- */
-struct ast_sip_contact {
-	/*! Sorcery object details, the id is the aor name plus a random string */
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/*! Full URI of the contact */
-		AST_STRING_FIELD(uri);
-		/*! Outbound proxy to use for qualify */
-		AST_STRING_FIELD(outbound_proxy);
-		/*! Path information to place in Route headers */
-		AST_STRING_FIELD(path);
-		/*! Content of the User-Agent header in REGISTER request */
-		AST_STRING_FIELD(user_agent);
-	);
-	/*! Absolute time that this contact is no longer valid after */
-	struct timeval expiration_time;
-	/*! Frequency to send OPTIONS requests to contact. 0 is disabled. */
-	unsigned int qualify_frequency;
-	/*! If true authenticate the qualify if needed */
-	int authenticate_qualify;
-};
-
-#define CONTACT_STATUS "contact_status"
-
-/*!
- * \brief Status type for a contact.
- */
-enum ast_sip_contact_status_type {
-	UNAVAILABLE,
-	AVAILABLE
-};
-
-/*!
- * \brief A contact's status.
- *
- * \detail Maintains a contact's current status and round trip time
- *         if available.
- */
-struct ast_sip_contact_status {
-	SORCERY_OBJECT(details);
-	/*! Current status for a contact (default - unavailable) */
-	enum ast_sip_contact_status_type status;
-	/*! The round trip start time set before sending a qualify request */
-	struct timeval rtt_start;
-	/*! The round trip time in microseconds */
-	int64_t rtt;
-};
-
-/*!
- * \brief A SIP address of record
- */
-struct ast_sip_aor {
-	/*! Sorcery object details, the id is the AOR name */
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/*! Voicemail boxes for this AOR */
-		AST_STRING_FIELD(mailboxes);
-		/*! Outbound proxy for OPTIONS requests */
-		AST_STRING_FIELD(outbound_proxy);
-	);
-	/*! Minimum expiration time */
-	unsigned int minimum_expiration;
-	/*! Maximum expiration time */
-	unsigned int maximum_expiration;
-	/*! Default contact expiration if one is not provided in the contact */
-	unsigned int default_expiration;
-	/*! Frequency to send OPTIONS requests to AOR contacts. 0 is disabled. */
-	unsigned int qualify_frequency;
-	/*! If true authenticate the qualify if needed */
-	int authenticate_qualify;
-	/*! Maximum number of external contacts, 0 to disable */
-	unsigned int max_contacts;
-	/*! Whether to remove any existing contacts not related to an incoming REGISTER when it comes in */
-	unsigned int remove_existing;
-	/*! Any permanent configured contacts */
-	struct ao2_container *permanent_contacts;
-	/*! Determines whether SIP Path headers are supported */
-	unsigned int support_path;
-};
-
-/*!
- * \brief A wrapper for contact that adds the aor_id and
- * a consistent contact id.  Used by ast_sip_for_each_contact.
- */
-struct ast_sip_contact_wrapper {
-	/*! The id of the parent aor. */
-	char *aor_id;
-	/*! The id of contact in form of aor_id/contact_uri. */
-	char *contact_id;
-	/*! Pointer to the actual contact. */
-	struct ast_sip_contact *contact;
-};
-
-/*!
- * \brief DTMF modes for SIP endpoints
- */
-enum ast_sip_dtmf_mode {
-	/*! No DTMF to be used */
-	AST_SIP_DTMF_NONE,
-	/* XXX Should this be 2833 instead? */
-	/*! Use RFC 4733 events for DTMF */
-	AST_SIP_DTMF_RFC_4733,
-	/*! Use DTMF in the audio stream */
-	AST_SIP_DTMF_INBAND,
-	/*! Use SIP INFO DTMF (blech) */
-	AST_SIP_DTMF_INFO,
-};
-
-/*!
- * \brief Methods of storing SIP digest authentication credentials.
- *
- * Note that both methods result in MD5 digest authentication being
- * used. The two methods simply alter how Asterisk determines the
- * credentials for a SIP authentication
- */
-enum ast_sip_auth_type {
-	/*! Credentials stored as a username and password combination */
-	AST_SIP_AUTH_TYPE_USER_PASS,
-	/*! Credentials stored as an MD5 sum */
-	AST_SIP_AUTH_TYPE_MD5,
-	/*! Credentials not stored this is a fake auth */
-	AST_SIP_AUTH_TYPE_ARTIFICIAL
-};
-
-#define SIP_SORCERY_AUTH_TYPE "auth"
-
-struct ast_sip_auth {
-	/* Sorcery ID of the auth is its name */
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/* Identification for these credentials */
-		AST_STRING_FIELD(realm);
-		/* Authentication username */
-		AST_STRING_FIELD(auth_user);
-		/* Authentication password */
-		AST_STRING_FIELD(auth_pass);
-		/* Authentication credentials in MD5 format (hash of user:realm:pass) */
-		AST_STRING_FIELD(md5_creds);
-	);
-	/* The time period (in seconds) that a nonce may be reused */
-	unsigned int nonce_lifetime;
-	/* Used to determine what to use when authenticating */
-	enum ast_sip_auth_type type;
-};
-
-AST_VECTOR(ast_sip_auth_vector, const char *);
-
-/*!
- * \brief Different methods by which incoming requests can be matched to endpoints
- */
-enum ast_sip_endpoint_identifier_type {
-	/*! Identify based on user name in From header */
-	AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME = (1 << 0),
-};
-
-enum ast_sip_session_refresh_method {
-	/*! Use reinvite to negotiate direct media */
-	AST_SIP_SESSION_REFRESH_METHOD_INVITE,
-	/*! Use UPDATE to negotiate direct media */
-	AST_SIP_SESSION_REFRESH_METHOD_UPDATE,
-};
-
-enum ast_sip_direct_media_glare_mitigation {
-	/*! Take no special action to mitigate reinvite glare */
-	AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE,
-	/*! Do not send an initial direct media session refresh on outgoing call legs
-	 * Subsequent session refreshes will be sent no matter the session direction
-	 */
-	AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING,
-	/*! Do not send an initial direct media session refresh on incoming call legs
-	 * Subsequent session refreshes will be sent no matter the session direction
-	 */
-	AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING,
-};
-
-enum ast_sip_session_media_encryption {
-	/*! Invalid media encryption configuration */
-	AST_SIP_MEDIA_TRANSPORT_INVALID = 0,
-	/*! Do not allow any encryption of session media */
-	AST_SIP_MEDIA_ENCRYPT_NONE,
-	/*! Offer SDES-encrypted session media */
-	AST_SIP_MEDIA_ENCRYPT_SDES,
-	/*! Offer encrypted session media with datagram TLS key exchange */
-	AST_SIP_MEDIA_ENCRYPT_DTLS,
-};
-
-enum ast_sip_session_redirect {
-	/*! User portion of the target URI should be used as the target in the dialplan */
-	AST_SIP_REDIRECT_USER = 0,
-	/*! Target URI should be used as the target in the dialplan */
-	AST_SIP_REDIRECT_URI_CORE,
-	/*! Target URI should be used as the target within chan_pjsip itself */
-	AST_SIP_REDIRECT_URI_PJSIP,
-};
-
-/*!
- * \brief Session timers options
- */
-struct ast_sip_timer_options {
-	/*! Minimum session expiration period, in seconds */
-	unsigned int min_se;
-	/*! Session expiration period, in seconds */
-	unsigned int sess_expires;
-};
-
-/*!
- * \brief Endpoint configuration for SIP extensions.
- *
- * SIP extensions, in this case refers to features
- * indicated in Supported or Required headers.
- */
-struct ast_sip_endpoint_extensions {
-	/*! Enabled SIP extensions */
-	unsigned int flags;
-	/*! Timer options */
-	struct ast_sip_timer_options timer;
-};
-
-/*!
- * \brief Endpoint configuration for unsolicited MWI
- */
-struct ast_sip_mwi_configuration {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Configured voicemail boxes for this endpoint. Used for MWI */
-		AST_STRING_FIELD(mailboxes);
-		/*! Username to use when sending MWI NOTIFYs to this endpoint */
-		AST_STRING_FIELD(fromuser);
-	);
-	/* Should mailbox states be combined into a single notification? */
-	unsigned int aggregate;
-};
-
-/*!
- * \brief Endpoint subscription configuration
- */
-struct ast_sip_endpoint_subscription_configuration {
-	/*! Indicates if endpoint is allowed to initiate subscriptions */
-	unsigned int allow;
-	/*! The minimum allowed expiration for subscriptions from endpoint */
-	unsigned int minexpiry;
-	/*! Message waiting configuration */
-	struct ast_sip_mwi_configuration mwi;
-};
-
-/*!
- * \brief NAT configuration options for endpoints
- */
-struct ast_sip_endpoint_nat_configuration {
-	/*! Whether to force using the source IP address/port for sending responses */
-	unsigned int force_rport;
-	/*! Whether to rewrite the Contact header with the source IP address/port or not */
-	unsigned int rewrite_contact;
-};
-
-/*!
- * \brief Party identification options for endpoints
- *
- * This includes caller ID, connected line, and redirecting-related options
- */
-struct ast_sip_endpoint_id_configuration {
-	struct ast_party_id self;
-	/*! Do we accept identification information from this endpoint */
-	unsigned int trust_inbound;
-	/*! Do we send private identification information to this endpoint? */
-	unsigned int trust_outbound;
-	/*! Do we send P-Asserted-Identity headers to this endpoint? */
-	unsigned int send_pai;
-	/*! Do we send Remote-Party-ID headers to this endpoint? */
-	unsigned int send_rpid;
-	/*! Do we add Diversion headers to applicable outgoing requests/responses? */
-	unsigned int send_diversion;
-	/*! When performing connected line update, which method should be used */
-	enum ast_sip_session_refresh_method refresh_method;
-};
-
-/*!
- * \brief Call pickup configuration options for endpoints
- */
-struct ast_sip_endpoint_pickup_configuration {
-	/*! Call group */
-	ast_group_t callgroup;
-	/*! Pickup group */
-	ast_group_t pickupgroup;
-	/*! Named call group */
-	struct ast_namedgroups *named_callgroups;
-	/*! Named pickup group */
-	struct ast_namedgroups *named_pickupgroups;
-};
-
-/*!
- * \brief Configuration for one-touch INFO recording
- */
-struct ast_sip_info_recording_configuration {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Feature to enact when one-touch recording INFO with Record: On is received */
-		AST_STRING_FIELD(onfeature);
-		/*! Feature to enact when one-touch recording INFO with Record: Off is received */
-		AST_STRING_FIELD(offfeature);
-	);
-	/*! Is one-touch recording permitted? */
-	unsigned int enabled;
-};
-
-/*!
- * \brief Endpoint configuration options for INFO packages
- */
-struct ast_sip_endpoint_info_configuration {
-	/*! Configuration for one-touch recording */
-	struct ast_sip_info_recording_configuration recording;
-};
-
-/*!
- * \brief RTP configuration for SIP endpoints
- */
-struct ast_sip_media_rtp_configuration {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Configured RTP engine for this endpoint. */
-		AST_STRING_FIELD(engine);
-	);
-	/*! Whether IPv6 RTP is enabled or not */
-	unsigned int ipv6;
-	/*! Whether symmetric RTP is enabled or not */
-	unsigned int symmetric;
-	/*! Whether ICE support is enabled or not */
-	unsigned int ice_support;
-	/*! Whether to use the "ptime" attribute received from the endpoint or not */
-	unsigned int use_ptime;
-	/*! Do we use AVPF exclusively for this endpoint? */
-	unsigned int use_avpf;
-	/*! Do we force AVP, AVPF, SAVP, or SAVPF even for DTLS media streams? */
-	unsigned int force_avp;
-	/*! Do we use the received media transport in our answer SDP */
-	unsigned int use_received_transport;
-	/*! \brief DTLS-SRTP configuration information */
-	struct ast_rtp_dtls_cfg dtls_cfg;
-	/*! Should SRTP use a 32 byte tag instead of an 80 byte tag? */
-	unsigned int srtp_tag_32;
-	/*! Do we use media encryption? what type? */
-	enum ast_sip_session_media_encryption encryption;
-	/*! Do we want to optimistically support encryption if possible? */
-	unsigned int encryption_optimistic;
-};
-
-/*!
- * \brief Direct media options for SIP endpoints
- */
-struct ast_sip_direct_media_configuration {
-	/*! Boolean indicating if direct_media is permissible */
-	unsigned int enabled;
-	/*! When using direct media, which method should be used */
-	enum ast_sip_session_refresh_method method;
-	/*! Take steps to mitigate glare for direct media */
-	enum ast_sip_direct_media_glare_mitigation glare_mitigation;
-	/*! Do not attempt direct media session refreshes if a media NAT is detected */
-	unsigned int disable_on_nat;
-};
-
-struct ast_sip_t38_configuration {
-	/*! Whether T.38 UDPTL support is enabled or not */
-	unsigned int enabled;
-	/*! Error correction setting for T.38 UDPTL */
-	enum ast_t38_ec_modes error_correction;
-	/*! Explicit T.38 max datagram value, may be 0 to indicate the remote side can be trusted */
-	unsigned int maxdatagram;
-	/*! Whether NAT Support is enabled for T.38 UDPTL sessions or not */
-	unsigned int nat;
-	/*! Whether to use IPv6 for UDPTL or not */
-	unsigned int ipv6;
-};
-
-/*!
- * \brief Media configuration for SIP endpoints
- */
-struct ast_sip_endpoint_media_configuration {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Optional media address to use in SDP */
-		AST_STRING_FIELD(address);
-		/*! SDP origin username */
-		AST_STRING_FIELD(sdpowner);
-		/*! SDP session name */
-		AST_STRING_FIELD(sdpsession);
-	);
-	/*! RTP media configuration */
-	struct ast_sip_media_rtp_configuration rtp;
-	/*! Direct media options */
-	struct ast_sip_direct_media_configuration direct_media;
-	/*! T.38 (FoIP) options */
-	struct ast_sip_t38_configuration t38;
-	/*! Configured codecs */
-	struct ast_format_cap *codecs;
-	/*! DSCP TOS bits for audio streams */
-	unsigned int tos_audio;
-	/*! Priority for audio streams */
-	unsigned int cos_audio;
-	/*! DSCP TOS bits for video streams */
-	unsigned int tos_video;
-	/*! Priority for video streams */
-	unsigned int cos_video;
-};
-
-/*!
- * \brief An entity with which Asterisk communicates
- */
-struct ast_sip_endpoint {
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		/*! Context to send incoming calls to */
-		AST_STRING_FIELD(context);
-		/*! Name of an explicit transport to use */
-		AST_STRING_FIELD(transport);
-		/*! Outbound proxy to use */
-		AST_STRING_FIELD(outbound_proxy);
-		/*! Explicit AORs to dial if none are specified */
-		AST_STRING_FIELD(aors);
-		/*! Musiconhold class to suggest that the other side use when placing on hold */
-		AST_STRING_FIELD(mohsuggest);
-		/*! Configured tone zone for this endpoint. */
-		AST_STRING_FIELD(zone);
-		/*! Configured language for this endpoint. */
-		AST_STRING_FIELD(language);
-		/*! Default username to place in From header */
-		AST_STRING_FIELD(fromuser);
-		/*! Domain to place in From header */
-		AST_STRING_FIELD(fromdomain);
-		/*! Context to route incoming MESSAGE requests to */
-		AST_STRING_FIELD(message_context);
-		/*! Accountcode to auto-set on channels */
-		AST_STRING_FIELD(accountcode);
-	);
-	/*! Configuration for extensions */
-	struct ast_sip_endpoint_extensions extensions;
-	/*! Configuration relating to media */
-	struct ast_sip_endpoint_media_configuration media;
-	/*! SUBSCRIBE/NOTIFY configuration options */
-	struct ast_sip_endpoint_subscription_configuration subscription;
-	/*! NAT configuration */
-	struct ast_sip_endpoint_nat_configuration nat;
-	/*! Party identification options */
-	struct ast_sip_endpoint_id_configuration id;
-	/*! Configuration options for INFO packages */
-	struct ast_sip_endpoint_info_configuration info;
-	/*! Call pickup configuration */
-	struct ast_sip_endpoint_pickup_configuration pickup;
-	/*! Inbound authentication credentials */
-	struct ast_sip_auth_vector inbound_auths;
-	/*! Outbound authentication credentials */
-	struct ast_sip_auth_vector outbound_auths;
-	/*! DTMF mode to use with this endpoint */
-	enum ast_sip_dtmf_mode dtmf;
-	/*! Method(s) by which the endpoint should be identified. */
-	enum ast_sip_endpoint_identifier_type ident_method;
-	/*! Boolean indicating if ringing should be sent as inband progress */
-	unsigned int inband_progress;
-	/*! Pointer to the persistent Asterisk endpoint */
-	struct ast_endpoint *persistent;
-	/*! The number of channels at which busy device state is returned */
-	unsigned int devicestate_busy_at;
-	/*! Whether fax detection is enabled or not (CNG tone detection) */
-	unsigned int faxdetect;
-	/*! Determines if transfers (using REFER) are allowed by this endpoint */
-	unsigned int allowtransfer;
-	/*! Method used when handling redirects */
-	enum ast_sip_session_redirect redirect_method;
-	/*! Variables set on channel creation */
-	struct ast_variable *channel_vars;
-};
-
-/*!
- * \brief Initialize an auth vector with the configured values.
- *
- * \param vector Vector to initialize
- * \param auth_names Comma-separated list of names to set in the array
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_auth_vector_init(struct ast_sip_auth_vector *vector, const char *auth_names);
-
-/*!
- * \brief Free contents of an auth vector.
- *
- * \param array Vector whose contents are to be freed
- */
-void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *vector);
-
-/*!
- * \brief Possible returns from ast_sip_check_authentication
- */
-enum ast_sip_check_auth_result {
-    /*! Authentication needs to be challenged */
-    AST_SIP_AUTHENTICATION_CHALLENGE,
-    /*! Authentication succeeded */
-    AST_SIP_AUTHENTICATION_SUCCESS,
-    /*! Authentication failed */
-    AST_SIP_AUTHENTICATION_FAILED,
-    /*! Authentication encountered some internal error */
-    AST_SIP_AUTHENTICATION_ERROR,
-};
-
-/*!
- * \brief An interchangeable way of handling digest authentication for SIP.
- *
- * An authenticator is responsible for filling in the callbacks provided below. Each is called from a publicly available
- * function in res_sip. The authenticator can use configuration or other local policy to determine whether authentication
- * should take place and what credentials should be used when challenging and authenticating a request.
- */
-struct ast_sip_authenticator {
-    /*!
-     * \brief Check if a request requires authentication
-     * See ast_sip_requires_authentication for more details
-     */
-    int (*requires_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-	/*!
-	 * \brief Check that an incoming request passes authentication.
-	 *
-	 * The tdata parameter is useful for adding information such as digest challenges.
-	 *
-	 * \param endpoint The endpoint sending the incoming request
-	 * \param rdata The incoming request
-	 * \param tdata Tentative outgoing request.
-	 */
-	enum ast_sip_check_auth_result (*check_authentication)(struct ast_sip_endpoint *endpoint,
-			pjsip_rx_data *rdata, pjsip_tx_data *tdata);
-};
-
-/*!
- * \brief an interchangeable way of responding to authentication challenges
- *
- * An outbound authenticator takes incoming challenges and formulates a new SIP request with
- * credentials.
- */
-struct ast_sip_outbound_authenticator {
-	/*!
-	 * \brief Create a new request with authentication credentials
-	 *
-	 * \param auths A vector of IDs of auth sorcery objects
-	 * \param challenge The SIP response with authentication challenge(s)
-	 * \param tsx The transaction in which the challenge was received
-	 * \param new_request The new SIP request with challenge response(s)
-	 * \retval 0 Successfully created new request
-	 * \retval -1 Failed to create a new request
-	 */
-	int (*create_request_with_auth)(const struct ast_sip_auth_vector *auths, struct pjsip_rx_data *challenge,
-			struct pjsip_transaction *tsx, struct pjsip_tx_data **new_request);
-};
-
-/*!
- * \brief An entity responsible for identifying the source of a SIP message
- */
-struct ast_sip_endpoint_identifier {
-    /*!
-     * \brief Callback used to identify the source of a message.
-     * See ast_sip_identify_endpoint for more details
-     */
-    struct ast_sip_endpoint *(*identify_endpoint)(pjsip_rx_data *rdata);
-};
-
-/*!
- * \brief Register a SIP service in Asterisk.
- *
- * This is more-or-less a wrapper around pjsip_endpt_register_module().
- * Registering a service makes it so that PJSIP will call into the
- * service at appropriate times. For more information about PJSIP module
- * callbacks, see the PJSIP documentation. Asterisk modules that call
- * this function will likely do so at module load time.
- *
- * \param module The module that is to be registered with PJSIP
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_service(pjsip_module *module);
-
-/*!
- * This is the opposite of ast_sip_register_service().  Unregistering a
- * service means that PJSIP will no longer call into the module any more.
- * This will likely occur when an Asterisk module is unloaded.
- *
- * \param module The PJSIP module to unregister
- */
-void ast_sip_unregister_service(pjsip_module *module);
-
-/*!
- * \brief Register a SIP authenticator
- *
- * An authenticator has three main purposes:
- * 1) Determining if authentication should be performed on an incoming request
- * 2) Gathering credentials necessary for issuing an authentication challenge
- * 3) Authenticating a request that has credentials
- *
- * Asterisk provides a default authenticator, but it may be replaced by a
- * custom one if desired.
- *
- * \param auth The authenticator to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_authenticator(struct ast_sip_authenticator *auth);
-
-/*!
- * \brief Unregister a SIP authenticator
- *
- * When there is no authenticator registered, requests cannot be challenged
- * or authenticated.
- *
- * \param auth The authenticator to unregister
- */
-void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth);
-
- /*!
- * \brief Register an outbound SIP authenticator
- *
- * An outbound authenticator is responsible for creating responses to
- * authentication challenges by remote endpoints.
- *
- * \param auth The authenticator to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticator *outbound_auth);
-
-/*!
- * \brief Unregister an outbound SIP authenticator
- *
- * When there is no outbound authenticator registered, authentication challenges
- * will be handled as any other final response would be.
- *
- * \param auth The authenticator to unregister
- */
-void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authenticator *auth);
-
-/*!
- * \brief Register a SIP endpoint identifier
- *
- * An endpoint identifier's purpose is to determine which endpoint a given SIP
- * message has come from.
- *
- * Multiple endpoint identifiers may be registered so that if an endpoint
- * cannot be identified by one identifier, it may be identified by another.
- *
- * Asterisk provides two endpoint identifiers. One identifies endpoints based
- * on the user part of the From header URI. The other identifies endpoints based
- * on the source IP address.
- *
- * If the order in which endpoint identifiers is run is important to you, then
- * be sure to load individual endpoint identifier modules in the order you wish
- * for them to be run in modules.conf
- *
- * \param identifier The SIP endpoint identifier to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);
-
-/*!
- * \brief Unregister a SIP endpoint identifier
- *
- * This stops an endpoint identifier from being used.
- *
- * \param identifier The SIP endoint identifier to unregister
- */
-void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);
-
-/*!
- * \brief Allocate a new SIP endpoint
- *
- * This will return an endpoint with its refcount increased by one. This reference
- * can be released using ao2_ref().
- *
- * \param name The name of the endpoint.
- * \retval NULL Endpoint allocation failed
- * \retval non-NULL The newly allocated endpoint
- */
-void *ast_sip_endpoint_alloc(const char *name);
-
-/*!
- * \brief Get a pointer to the PJSIP endpoint.
- *
- * This is useful when modules have specific information they need
- * to register with the PJSIP core.
- * \retval NULL endpoint has not been created yet.
- * \retval non-NULL PJSIP endpoint.
- */
-pjsip_endpoint *ast_sip_get_pjsip_endpoint(void);
-
-/*!
- * \brief Get a pointer to the SIP sorcery structure.
- *
- * \retval NULL sorcery has not been initialized
- * \retval non-NULL sorcery structure
- */
-struct ast_sorcery *ast_sip_get_sorcery(void);
-
-/*!
- * \brief Initialize transport support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_initialize_sorcery_transport(void);
-
-/*!
- * \brief Destroy transport support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_destroy_sorcery_transport(void);
-
-/*!
- * \brief Initialize qualify support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_initialize_sorcery_qualify(void);
-
-/*!
- * \brief Initialize location support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_initialize_sorcery_location(void);
-
-/*!
- * \brief Destroy location support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_destroy_sorcery_location(void);
-
-/*!
- * \brief Retrieve a named AOR
- *
- * \param aor_name Name of the AOR
- *
- * \retval NULL if not found
- * \retval non-NULL if found
- */
-struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name);
-
-/*!
- * \brief Retrieve the first bound contact for an AOR
- *
- * \param aor Pointer to the AOR
- * \retval NULL if no contacts available
- * \retval non-NULL if contacts available
- */
-struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor);
-
-/*!
- * \brief Retrieve all contacts currently available for an AOR
- *
- * \param aor Pointer to the AOR
- *
- * \retval NULL if no contacts available
- * \retval non-NULL if contacts available
- */
-struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor);
-
-/*!
- * \brief Retrieve the first bound contact from a list of AORs
- *
- * \param aor_list A comma-separated list of AOR names
- * \retval NULL if no contacts available
- * \retval non-NULL if contacts available
- */
-struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list);
-
-/*!
- * \brief Retrieve a named contact
- *
- * \param contact_name Name of the contact
- *
- * \retval NULL if not found
- * \retval non-NULL if found
- */
-struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name);
-
-/*!
- * \brief Add a new contact to an AOR
- *
- * \param aor Pointer to the AOR
- * \param uri Full contact URI
- * \param expiration_time Optional expiration time of the contact
- * \param path_info Path information
- * \param user_agent User-Agent header from REGISTER request
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
-	struct timeval expiration_time, const char *path_info, const char *user_agent);
-
-/*!
- * \brief Update a contact
- *
- * \param contact New contact object with details
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_location_update_contact(struct ast_sip_contact *contact);
-
-/*!
-* \brief Delete a contact
-*
-* \param contact Contact object to delete
-*
-* \retval -1 failure
-* \retval 0 success
-*/
-int ast_sip_location_delete_contact(struct ast_sip_contact *contact);
-
-/*!
- * \brief Initialize domain aliases support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_initialize_sorcery_domain_alias(void);
-
-/*!
- * \brief Initialize authentication support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_initialize_sorcery_auth(void);
-
-/*!
- * \brief Destroy authentication support on a sorcery instance
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_destroy_sorcery_auth(void);
-
-/*!
- * \brief Callback called when an outbound request with authentication credentials is to be sent in dialog
- *
- * This callback will have the created request on it. The callback's purpose is to do any extra
- * housekeeping that needs to be done as well as to send the request out.
- *
- * This callback is only necessary if working with a PJSIP API that sits between the application
- * and the dialog layer.
- *
- * \param dlg The dialog to which the request belongs
- * \param tdata The created request to be sent out
- * \param user_data Data supplied with the callback
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-typedef int (*ast_sip_dialog_outbound_auth_cb)(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *user_data);
-
-/*!
- * \brief Set up outbound authentication on a SIP dialog
- *
- * This sets up the infrastructure so that all requests associated with a created dialog
- * can be re-sent with authentication credentials if the original request is challenged.
- *
- * \param dlg The dialog on which requests will be authenticated
- * \param endpoint The endpoint whom this dialog pertains to
- * \param cb Callback to call to send requests with authentication
- * \param user_data Data to be provided to the callback when it is called
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_dialog_setup_outbound_authentication(pjsip_dialog *dlg, const struct ast_sip_endpoint *endpoint,
-		ast_sip_dialog_outbound_auth_cb cb, void *user_data);
-
-/*!
- * \brief Initialize the distributor module
- *
- * The distributor module is responsible for taking an incoming
- * SIP message and placing it into the threadpool. Once in the threadpool,
- * the distributor will perform endpoint lookups and authentication, and
- * then distribute the message up the stack to any further modules.
- *
- * \retval -1 Failure
- * \retval 0 Success
- */
-int ast_sip_initialize_distributor(void);
-
-/*!
- * \brief Destruct the distributor module.
- *
- * Unregisters pjsip modules and cleans up any allocated resources.
- */
-void ast_sip_destroy_distributor(void);
-
-/*!
- * \brief Retrieves a reference to the artificial auth.
- *
- * \retval The artificial auth
- */
-struct ast_sip_auth *ast_sip_get_artificial_auth(void);
-
-/*!
- * \brief Retrieves a reference to the artificial endpoint.
- *
- * \retval The artificial endpoint
- */
-struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void);
-
-/*!
- * \page Threading model for SIP
- *
- * There are three major types of threads that SIP will have to deal with:
- * \li Asterisk threads
- * \li PJSIP threads
- * \li SIP threadpool threads (a.k.a. "servants")
- *
- * \par Asterisk Threads
- *
- * Asterisk threads are those that originate from outside of SIP but within
- * Asterisk. The most common of these threads are PBX (channel) threads and
- * the autoservice thread. Most interaction with these threads will be through
- * channel technology callbacks. Within these threads, it is fine to handle
- * Asterisk data from outside of SIP, but any handling of SIP data should be
- * left to servants, \b especially if you wish to call into PJSIP for anything.
- * Asterisk threads are not registered with PJLIB, so attempting to call into
- * PJSIP will cause an assertion to be triggered, thus causing the program to
- * crash.
- *
- * \par PJSIP Threads
- *
- * PJSIP threads are those that originate from handling of PJSIP events, such
- * as an incoming SIP request or response, or a transaction timeout. The role
- * of these threads is to process information as quickly as possible so that
- * the next item on the SIP socket(s) can be serviced. On incoming messages,
- * Asterisk automatically will push the request to a servant thread. When your
- * module callback is called, processing will already be in a servant. However,
- * for other PSJIP events, such as transaction state changes due to timer
- * expirations, your module will be called into from a PJSIP thread. If you
- * are called into from a PJSIP thread, then you should push whatever processing
- * is needed to a servant as soon as possible. You can discern if you are currently
- * in a SIP servant thread using the \ref ast_sip_thread_is_servant function.
- *
- * \par Servants
- *
- * Servants are where the bulk of SIP work should be performed. These threads
- * exist in order to do the work that Asterisk threads and PJSIP threads hand
- * off to them. Servant threads register themselves with PJLIB, meaning that
- * they are capable of calling PJSIP and PJLIB functions if they wish.
- *
- * \par Serializer
- *
- * Tasks are handed off to servant threads using the API call \ref ast_sip_push_task.
- * The first parameter of this call is a serializer. If this pointer
- * is NULL, then the work will be handed off to whatever servant can currently handle
- * the task. If this pointer is non-NULL, then the task will not be executed until
- * previous tasks pushed with the same serializer have completed. For more information
- * on serializers and the benefits they provide, see \ref ast_threadpool_serializer
- *
- * \note
- *
- * Do not make assumptions about individual threads based on a corresponding serializer.
- * In other words, just because several tasks use the same serializer when being pushed
- * to servants, it does not mean that the same thread is necessarily going to execute those
- * tasks, even though they are all guaranteed to be executed in sequence.
- */
-
-/*!
- * \brief Create a new serializer for SIP tasks
- *
- * See \ref ast_threadpool_serializer for more information on serializers.
- * SIP creates serializers so that tasks operating on similar data will run
- * in sequence.
- *
- * \retval NULL Failure
- * \retval non-NULL Newly-created serializer
- */
-struct ast_taskprocessor *ast_sip_create_serializer(void);
-
-/*!
- * \brief Set a serializer on a SIP dialog so requests and responses are automatically serialized
- *
- * Passing a NULL serializer is a way to remove a serializer from a dialog.
- *
- * \param dlg The SIP dialog itself
- * \param serializer The serializer to use
- */
-void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer);
-
-/*!
- * \brief Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
- *
- * \param dlg The SIP dialog itself
- * \param endpoint The endpoint that this dialog is communicating with
- */
-void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint);
-
-/*!
- * \brief Get the endpoint associated with this dialog
- *
- * This function increases the refcount of the endpoint by one. Release
- * the reference once you are finished with the endpoint.
- *
- * \param dlg The SIP dialog from which to retrieve the endpoint
- * \retval NULL No endpoint associated with this dialog
- * \retval non-NULL The endpoint.
- */
-struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg);
-
-/*!
- * \brief Pushes a task to SIP servants
- *
- * This uses the serializer provided to determine how to push the task.
- * If the serializer is NULL, then the task will be pushed to the
- * servants directly. If the serializer is non-NULL, then the task will be
- * queued behind other tasks associated with the same serializer.
- *
- * \param serializer The serializer to which the task belongs. Can be NULL
- * \param sip_task The task to execute
- * \param task_data The parameter to pass to the task when it executes
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_push_task(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data);
-
-/*!
- * \brief Push a task to SIP servants and wait for it to complete
- *
- * Like \ref ast_sip_push_task except that it blocks until the task completes.
- *
- * \warning \b Never use this function in a SIP servant thread. This can potentially
- * cause a deadlock. If you are in a SIP servant thread, just call your function
- * in-line.
- *
- * \param serializer The SIP serializer to which the task belongs. May be NULL.
- * \param sip_task The task to execute
- * \param task_data The parameter to pass to the task when it executes
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data);
-
-/*!
- * \brief Determine if the current thread is a SIP servant thread
- *
- * \retval 0 This is not a SIP servant thread
- * \retval 1 This is a SIP servant thread
- */
-int ast_sip_thread_is_servant(void);
-
-/*!
- * \brief SIP body description
- *
- * This contains a type and subtype that will be added as
- * the "Content-Type" for the message as well as the body
- * text.
- */
-struct ast_sip_body {
-	/*! Type of the body, such as "application" */
-	const char *type;
-	/*! Subtype of the body, such as "sdp" */
-	const char *subtype;
-	/*! The text to go in the body */
-	const char *body_text;
-};
-
-/*!
- * \brief General purpose method for creating a UAC dialog with an endpoint
- *
- * \param endpoint A pointer to the endpoint
- * \param aor_name Optional name of the AOR to target, may even be an explicit SIP URI
- * \param request_user Optional user to place into the target URI
- *
- * \retval non-NULL success
- * \retval NULL failure
- */
-pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user);
-
-/*!
- * \brief General purpose method for creating a UAS dialog with an endpoint
- *
- * \param endpoint A pointer to the endpoint
- * \param rdata The request that is starting the dialog
- * \param[out] status On failure, the reason for failure in creating the dialog
- */
-pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status);
-
-/*!
- * \brief General purpose method for creating an rdata structure using specific information
- *
- * \param rdata[out] The rdata structure that will be populated
- * \param packet A SIP message
- * \param src_name The source IP address of the message
- * \param src_port The source port of the message
- * \param transport_type The type of transport the message was received on
- * \param local_name The local IP address the message was received on
- * \param local_port The local port the message was received on
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type,
-	const char *local_name, int local_port);
-
-/*!
- * \brief General purpose method for creating a SIP request
- *
- * Its typical use would be to create one-off requests such as an out of dialog
- * SIP MESSAGE.
- *
- * The request can either be in- or out-of-dialog. If in-dialog, the
- * dlg parameter MUST be present. If out-of-dialog the endpoint parameter
- * MUST be present. If both are present, then we will assume that the message
- * is to be sent in-dialog.
- *
- * The uri parameter can be specified if the request should be sent to an explicit
- * URI rather than one configured on the endpoint.
- *
- * \param method The method of the SIP request to send
- * \param dlg Optional. If specified, the dialog on which to request the message.
- * \param endpoint Optional. If specified, the request will be created out-of-dialog to the endpoint.
- * \param uri Optional. If specified, the request will be sent to this URI rather
- * than one configured for the endpoint.
- * \param contact The contact with which this request is associated for out-of-dialog requests.
- * \param[out] tdata The newly-created request
- *
- * The provided contact is attached to tdata with its reference bumped, but will
- * not survive for the entire lifetime of tdata since the contact is cleaned up
- * when all supplements have completed execution.
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
-		struct ast_sip_endpoint *endpoint, const char *uri,
-		struct ast_sip_contact *contact, pjsip_tx_data **tdata);
-
-/*!
- * \brief General purpose method for sending a SIP request
- *
- * This is a companion function for \ref ast_sip_create_request. The request
- * created there can be passed to this function, though any request may be
- * passed in.
- *
- * This will automatically set up handling outbound authentication challenges if
- * they arrive.
- *
- * \param tdata The request to send
- * \param dlg Optional. The dialog in which the request is sent.  Otherwise it is out-of-dialog.
- * \param endpoint Optional. If specified, the out-of-dialog request is sent to the endpoint.
- * \param token Data to be passed to the callback upon receipt of out-of-dialog response.
- * \param callback Callback to be called upon receipt of out-of-dialog response.
- *
- * \retval 0 Success
- * \retval -1 Failure (out-of-dialog callback will not be called.)
- */
-int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
-	struct ast_sip_endpoint *endpoint, void *token,
-	void (*callback)(void *token, pjsip_event *e));
-
-/*!
- * \brief General purpose method for creating a SIP response
- *
- * Its typical use would be to create responses for out of dialog
- * requests.
- *
- * \param rdata The rdata from the incoming request.
- * \param st_code The response code to transmit.
- * \param contact The contact with which this request is associated.
- * \param[out] tdata The newly-created response
- *
- * The provided contact is attached to tdata with its reference bumped, but will
- * not survive for the entire lifetime of tdata since the contact is cleaned up
- * when all supplements have completed execution.
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
-	struct ast_sip_contact *contact, pjsip_tx_data **p_tdata);
-
-/*!
- * \brief Send a response to an out of dialog request
- *
- * \param res_addr The response address for this response
- * \param tdata The response to send
- * \param endpoint The ast_sip_endpoint associated with this response
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint);
-
-/*!
- * \brief Determine if an incoming request requires authentication
- *
- * This calls into the registered authenticator's requires_authentication callback
- * in order to determine if the request requires authentication.
- *
- * If there is no registered authenticator, then authentication will be assumed
- * not to be required.
- *
- * \param endpoint The endpoint from which the request originates
- * \param rdata The incoming SIP request
- * \retval non-zero The request requires authentication
- * \retval 0 The request does not require authentication
- */
-int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-
-/*!
- * \brief Method to determine authentication status of an incoming request
- *
- * This will call into a registered authenticator. The registered authenticator will
- * do what is necessary to determine whether the incoming request passes authentication.
- * A tentative response is passed into this function so that if, say, a digest authentication
- * challenge should be sent in the ensuing response, it can be added to the response.
- *
- * \param endpoint The endpoint from the request was sent
- * \param rdata The request to potentially authenticate
- * \param tdata Tentative response to the request
- * \return The result of checking authentication.
- */
-enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
-		pjsip_rx_data *rdata, pjsip_tx_data *tdata);
-
-/*!
- * \brief Create a response to an authentication challenge
- *
- * This will call into an outbound authenticator's create_request_with_auth callback
- * to create a new request with authentication credentials. See the create_request_with_auth
- * callback in the \ref ast_sip_outbound_authenticator structure for details about
- * the parameters and return values.
- */
-int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge,
-		pjsip_transaction *tsx, pjsip_tx_data **new_request);
-
-/*!
- * \brief Determine the endpoint that has sent a SIP message
- *
- * This will call into each of the registered endpoint identifiers'
- * identify_endpoint() callbacks until one returns a non-NULL endpoint.
- * This will return an ao2 object. Its reference count will need to be
- * decremented when completed using the endpoint.
- *
- * \param rdata The inbound SIP message to use when identifying the endpoint.
- * \retval NULL No matching endpoint
- * \retval non-NULL The matching endpoint
- */
-struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata);
-
-/*!
- * \brief Set the outbound proxy for an outbound SIP message
- *
- * \param tdata The message to set the outbound proxy on
- * \param proxy SIP uri of the proxy
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy);
-
-/*!
- * \brief Add a header to an outbound SIP message
- *
- * \param tdata The message to add the header to
- * \param name The header name
- * \param value The header value
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value);
-
-/*!
- * \brief Add a body to an outbound SIP message
- *
- * If this is called multiple times, the latest body will replace the current
- * body.
- *
- * \param tdata The message to add the body to
- * \param body The message body to add
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body);
-
-/*!
- * \brief Add a multipart body to an outbound SIP message
- *
- * This will treat each part of the input vector as part of a multipart body and
- * add each part to the SIP message.
- *
- * \param tdata The message to add the body to
- * \param bodies The parts of the body to add
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_add_body_multipart(pjsip_tx_data *tdata, const struct ast_sip_body *bodies[], int num_bodies);
-
-/*!
- * \brief Append body data to a SIP message
- *
- * This acts mostly the same as ast_sip_add_body, except that rather than replacing
- * a body if it currently exists, it appends data to an existing body.
- *
- * \param tdata The message to append the body to
- * \param body The string to append to the end of the current body
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text);
-
-/*!
- * \brief Copy a pj_str_t into a standard character buffer.
- *
- * pj_str_t is not NULL-terminated. Any place that expects a NULL-
- * terminated string needs to have the pj_str_t copied into a separate
- * buffer.
- *
- * This method copies the pj_str_t contents into the destination buffer
- * and NULL-terminates the buffer.
- *
- * \param dest The destination buffer
- * \param src The pj_str_t to copy
- * \param size The size of the destination buffer.
- */
-void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size);
-
-/*!
- * \brief Get the looked-up endpoint on an out-of dialog request or response
- *
- * The function may ONLY be called on out-of-dialog requests or responses. For
- * in-dialog requests and responses, it is required that the user of the dialog
- * has the looked-up endpoint stored locally.
- *
- * This function should never return NULL if the message is out-of-dialog. It will
- * always return NULL if the message is in-dialog.
- *
- * This function will increase the reference count of the returned endpoint by one.
- * Release your reference using the ao2_ref function when finished.
- *
- * \param rdata Out-of-dialog request or response
- * \return The looked up endpoint
- */
-struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata);
-
-/*!
- * \brief Retrieve any endpoints available to sorcery.
- *
- * \retval Endpoints available to sorcery, NULL if no endpoints found.
- */
-struct ao2_container *ast_sip_get_endpoints(void);
-
-/*!
- * \brief Retrieve the default outbound endpoint.
- *
- * \retval The default outbound endpoint, NULL if not found.
- */
-struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void);
-
-/*!
- * \brief Retrieve relevant SIP auth structures from sorcery
- *
- * \param auths Vector of sorcery IDs of auth credentials to retrieve
- * \param[out] out The retrieved auths are stored here
- */
-int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out);
-
-/*!
- * \brief Clean up retrieved auth structures from memory
- *
- * Call this function once you have completed operating on auths
- * retrieved from \ref ast_sip_retrieve_auths
- *
- * \param auths An vector of auth structures to clean up
- * \param num_auths The number of auths in the vector
- */
-void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths);
-
-/*!
- * \brief Checks if the given content type matches type/subtype.
- *
- * Compares the pjsip_media_type with the passed type and subtype and
- * returns the result of that comparison.  The media type parameters are
- * ignored.
- *
- * \param content_type The pjsip_media_type structure to compare
- * \param type The media type to compare
- * \param subtype The media subtype to compare
- * \retval 0 No match
- * \retval -1 Match
- */
-int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype);
-
-/*!
- * \brief Send a security event notification for when an invalid endpoint is requested
- *
- * \param name Name of the endpoint requested
- * \param rdata Received message
- */
-void ast_sip_report_invalid_endpoint(const char *name, pjsip_rx_data *rdata);
-
-/*!
- * \brief Send a security event notification for when an ACL check fails
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- * \param name Name of the ACL
- */
-void ast_sip_report_failed_acl(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *name);
-
-/*!
- * \brief Send a security event notification for when a challenge response has failed
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- */
-void ast_sip_report_auth_failed_challenge_response(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-
-/*!
- * \brief Send a security event notification for when authentication succeeds
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- */
-void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-
-/*!
- * \brief Send a security event notification for when an authentication challenge is sent
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- * \param tdata Sent message
- */
-void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata);
-
-/*!
- * \brief Send a security event notification for when a request is not supported
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- * \param req_type the type of request
- */
-void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
-				   const char* req_type);
-
-/*!
- * \brief Send a security event notification for when a memory limit is hit.
- *
- * \param endpoint Pointer to the endpoint in use
- * \param rdata Received message
- */
-void ast_sip_report_mem_limit(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-
-void ast_sip_initialize_global_headers(void);
-void ast_sip_destroy_global_headers(void);
-
-int ast_sip_add_global_request_header(const char *name, const char *value, int replace);
-int ast_sip_add_global_response_header(const char *name, const char *value, int replace);
-
-int ast_sip_initialize_sorcery_global(void);
-
-/*!
- * \brief Retrieves the value associated with the given key.
- *
- * \param ht the hash table/dictionary to search
- * \param key the key to find
- *
- * \retval the value associated with the key, NULL otherwise.
- */
-void *ast_sip_dict_get(void *ht, const char *key);
-
-/*!
- * \brief Using the dictionary stored in mod_data array at a given id,
- *        retrieve the value associated with the given key.
- *
- * \param mod_data a module data array
- * \param id the mod_data array index
- * \param key the key to find
- *
- * \retval the value associated with the key, NULL otherwise.
- */
-#define ast_sip_mod_data_get(mod_data, id, key)		\
-	ast_sip_dict_get(mod_data[id], key)
-
-/*!
- * \brief Set the value for the given key.
- *
- * Note - if the hash table does not exist one is created first, the key/value
- * pair is set, and the hash table returned.
- *
- * \param pool the pool to allocate memory in
- * \param ht the hash table/dictionary in which to store the key/value pair
- * \param key the key to associate a value with
- * \param val the value to associate with a key
- *
- * \retval the given, or newly created, hash table.
- */
-void *ast_sip_dict_set(pj_pool_t* pool, void *ht,
-		       const char *key, void *val);
-
-/*!
- * \brief Utilizing a mod_data array for a given id, set the value
- *        associated with the given key.
- *
- * For a given structure's mod_data array set the element indexed by id to
- * be a dictionary containing the key/val pair.
- *
- * \param pool a memory allocation pool
- * \param mod_data a module data array
- * \param id the mod_data array index
- * \param key the key to find
- * \param val the value to associate with a key
- */
-#define ast_sip_mod_data_set(pool, mod_data, id, key, val)		\
-	mod_data[id] = ast_sip_dict_set(pool, mod_data[id], key, val)
-
-/*!
- * \brief For every contact on an AOR call the given 'on_contact' handler.
- *
- * \param aor the aor containing a list of contacts to iterate
- * \param on_contact callback on each contact on an AOR.  The object
- * received by the callback will be a ast_sip_contact_wrapper structure.
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
-		ao2_callback_fn on_contact, void *arg);
-
-/*!
- * \brief Handler used to convert a contact to a string.
- *
- * \param object the ast_sip_aor_contact_pair containing a list of contacts to iterate and the contact
- * \param arg user data passed to handler
- * \param flags
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_contact_to_str(void *object, void *arg, int flags);
-
-/*!
- * \brief For every aor in the comma separated aors string call the
- *        given 'on_aor' handler.
- *
- * \param aors a comma separated list of aors
- * \param on_aor callback for each aor
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg);
-
-/*!
- * \brief For every auth in the array call the given 'on_auth' handler.
- *
- * \param array an array of auths
- * \param on_auth callback for each auth
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_auth(const struct ast_sip_auth_vector *array,
-			  ao2_callback_fn on_auth, void *arg);
-
-/*!
- * \brief Converts the given auth type to a string
- *
- * \param type the auth type to convert
- * \retval a string representative of the auth type
- */
-const char *ast_sip_auth_type_to_str(enum ast_sip_auth_type type);
-
-/*!
- * \brief Converts an auths array to a string of comma separated values
- *
- * \param auths an auth array
- * \param buf the string buffer to write the object data
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf);
-
-/*
- * \brief AMI variable container
- */
-struct ast_sip_ami {
-	/*! Manager session */
-	struct mansession *s;
-	/*! Manager message */
-	const struct message *m;
-	/*! Manager Action ID */
-	const char *action_id;
-	/*! user specified argument data */
-	void *arg;
-	/*! count of objects */
-	int count;
-};
-
-/*!
- * \brief Creates a string to store AMI event data in.
- *
- * \param event the event to set
- * \param ami AMI session and message container
- * \retval an initialized ast_str or NULL on error.
- */
-struct ast_str *ast_sip_create_ami_event(const char *event,
-					 struct ast_sip_ami *ami);
-
-/*!
- * \brief An entity responsible formatting endpoint information.
- */
-struct ast_sip_endpoint_formatter {
-	/*!
-	 * \brief Callback used to format endpoint information over AMI.
-	 */
-	int (*format_ami)(const struct ast_sip_endpoint *endpoint,
-			  struct ast_sip_ami *ami);
-	AST_RWLIST_ENTRY(ast_sip_endpoint_formatter) next;
-};
-
-/*!
- * \brief Register an endpoint formatter.
- *
- * \param obj the formatter to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj);
-
-/*!
- * \brief Unregister an endpoint formatter.
- *
- * \param obj the formatter to unregister
- */
-void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj);
-
-/*!
- * \brief Converts a sorcery object to a string of object properties.
- *
- * \param obj the sorcery object to convert
- * \param str the string buffer to write the object data
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf);
-
-/*!
- * \brief Formats the endpoint and sends over AMI.
- *
- * \param endpoint the endpoint to format and send
- * \param endpoint ami AMI variable container
- * \param count the number of formatters operated on
- * \retval 0 Success, otherwise non-zero on error
- */
-int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint,
-				struct ast_sip_ami *ami, int *count);
-
-/*!
- * \brief Format auth details for AMI.
- *
- * \param auths an auth array
- * \param ami ami variable container
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_format_auths_ami(const struct ast_sip_auth_vector *auths,
-			     struct ast_sip_ami *ami);
-
-/*!
- * \brief Retrieve the endpoint snapshot for an endpoint
- *
- * \param endpoint The endpoint whose snapshot is to be retreieved.
- * \retval The endpoint snapshot
- */
-struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
-	const struct ast_sip_endpoint *endpoint);
-
-/*!
- * \brief Retrieve the device state for an endpoint.
- *
- * \param endpoint The endpoint whose state is to be retrieved.
- * \retval The device state.
- */
-const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint);
-
-/*!
- * \brief For every channel snapshot on an endpoint snapshot call the given
- *        'on_channel_snapshot' handler.
- *
- * \param endpoint_snapshot snapshot of an endpoint
- * \param on_channel_snapshot callback for each channel snapshot
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_channel_snapshot(const struct ast_endpoint_snapshot *endpoint_snapshot,
-		ao2_callback_fn on_channel_snapshot,
-				      void *arg);
-
-/*!
- * \brief For every channel snapshot on an endpoint all the given
- *        'on_channel_snapshot' handler.
- *
- * \param endpoint endpoint
- * \param on_channel_snapshot callback for each channel snapshot
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_channel(const struct ast_sip_endpoint *endpoint,
-		ao2_callback_fn on_channel_snapshot,
-				      void *arg);
-
-enum ast_sip_supplement_priority {
-	/*! Top priority. Supplements with this priority are those that need to run before any others */
-	AST_SIP_SUPPLEMENT_PRIORITY_FIRST = 0,
-	/*! Channel creation priority.
-	 * chan_pjsip creates a channel at this priority. If your supplement depends on being run before
-	 * or after channel creation, then set your priority to be lower or higher than this value.
-	 */
-	AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL = 1000000,
-	/*! Lowest priority. Supplements with this priority should be run after all other supplements */
-	AST_SIP_SUPPLEMENT_PRIORITY_LAST = INT_MAX,
-};
-
-/*!
- * \brief A supplement to SIP message processing
- *
- * These can be registered by any module in order to add
- * processing to incoming and outgoing SIP out of dialog
- * requests and responses
- */
-struct ast_sip_supplement {
-	/*! Method on which to call the callbacks. If NULL, call on all methods */
-	const char *method;
-	/*! Priority for this supplement. Lower numbers are visited before higher numbers */
-	enum ast_sip_supplement_priority priority;
-	/*!
-	 * \brief Called on incoming SIP request
-	 * This method can indicate a failure in processing in its return. If there
-	 * is a failure, it is required that this method sends a response to the request.
-	 * This method is always called from a SIP servant thread.
-	 *
-	 * \note
-	 * The following PJSIP methods will not work properly:
-	 * pjsip_rdata_get_dlg()
-	 * pjsip_rdata_get_tsx()
-	 * The reason is that the rdata passed into this function is a cloned rdata structure,
-	 * and its module data is not copied during the cloning operation.
-	 * If you need to get the dialog, you can get it via session->inv_session->dlg.
-	 *
-	 * \note
-	 * There is no guarantee that a channel will be present on the session when this is called.
-	 */
-	int (*incoming_request)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
-	/*!
-	 * \brief Called on an incoming SIP response
-	 * This method is always called from a SIP servant thread.
-	 *
-	 * \note
-	 * The following PJSIP methods will not work properly:
-	 * pjsip_rdata_get_dlg()
-	 * pjsip_rdata_get_tsx()
-	 * The reason is that the rdata passed into this function is a cloned rdata structure,
-	 * and its module data is not copied during the cloning operation.
-	 * If you need to get the dialog, you can get it via session->inv_session->dlg.
-	 *
-	 * \note
-	 * There is no guarantee that a channel will be present on the session when this is called.
-	 */
-	void (*incoming_response)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
-	/*!
-	 * \brief Called on an outgoing SIP request
-	 * This method is always called from a SIP servant thread.
-	 */
-	void (*outgoing_request)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata);
-	/*!
-	 * \brief Called on an outgoing SIP response
-	 * This method is always called from a SIP servant thread.
-	 */
-	void (*outgoing_response)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata);
-	/*! Next item in the list */
-	AST_LIST_ENTRY(ast_sip_supplement) next;
-};
-
-/*!
- * \brief Register a supplement to SIP out of dialog processing
- *
- * This allows for someone to insert themselves in the processing of out
- * of dialog SIP requests and responses. This, for example could allow for
- * a module to set channel data based on headers in an incoming message.
- * Similarly, a module could reject an incoming request if desired.
- *
- * \param supplement The supplement to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_register_supplement(struct ast_sip_supplement *supplement);
-
-/*!
- * \brief Unregister a an supplement to SIP out of dialog processing
- *
- * \param supplement The supplement to unregister
- */
-void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement);
-
-/*!
- * \brief Retrieve the system debug setting (yes|no|host).
- *
- * \note returned string needs to be de-allocated by caller.
- *
- * \retval the system debug setting.
- */
-char *ast_sip_get_debug(void);
-
-/*! \brief Determines whether the res_pjsip module is loaded */
-#define CHECK_PJSIP_MODULE_LOADED()				\
-	do {							\
-		if (!ast_module_check("res_pjsip.so")		\
-			|| !ast_sip_get_pjsip_endpoint()) {	\
-			return AST_MODULE_LOAD_DECLINE;		\
-		}						\
-	} while(0)
-
-#endif /* _RES_PJSIP_H */
diff --git a/include/asterisk/res_pjsip_body_generator_types.h b/include/asterisk/res_pjsip_body_generator_types.h
deleted file mode 100644
index a2cc043..0000000
--- a/include/asterisk/res_pjsip_body_generator_types.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _RES_PJSIP_BODY_GENERATOR_TYPES_H
-#define _RES_PJSIP_BODY_GENERATOR_TYPES_H
-
-#include "asterisk/pbx.h"
-
-/*!
- * \brief structure used for presence XML bodies
- *
- * This is used for the following body types:
- * \li application/pidf+xml
- * \li application/xpidf+xml
- * \li application/cpim-pidf+xml
- * \li application/dialog-info+xml
- */
-struct ast_sip_exten_state_data {
-	/*! The extension of the current state change */
-	const char *exten;
-	/*! The extension state of the change */
-	enum ast_extension_states exten_state;
-	/*! The presence state of the change */
-	enum ast_presence_state presence_state;
-	/*! The presence subtype of the change */
-	char *presence_subtype;
-	/*! The presence message of the change */
-	char *presence_message;
-	/*! Subscriber user agent */
-	char *user_agent;
-	/*! Current device state information */
-	struct ao2_container *device_state_info;
-	/*! Local dialog URI */
-	char local[PJSIP_MAX_URL_SIZE];
-	/*! Remote dialog URI */
-	char remote[PJSIP_MAX_URL_SIZE];
-	/*! Optional subscription */
-	struct ast_sip_subscription *sub;
-	/*! Allocation pool */
-	pj_pool_t *pool;
-};
-
-/*!
- * \brief Message counter used for message-summary XML bodies
- *
- * This is used for application/simple-message-summary bodies.
- */
-struct ast_sip_message_accumulator {
-	/*! Number of old messages */
-	int old_msgs;
-	/*! Number of new messages */
-	int new_msgs;
-};
-
-#endif /* _RES_PJSIP_BODY_GENERATOR_TYPES_H */
diff --git a/include/asterisk/res_pjsip_cli.h b/include/asterisk/res_pjsip_cli.h
deleted file mode 100644
index 44979b7..0000000
--- a/include/asterisk/res_pjsip_cli.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Fairview 5 Engineering, LLC.
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef RES_PJSIP_CLI_H_
-#define RES_PJSIP_CLI_H_
-
-#include "asterisk/cli.h"
-
-#define CLI_HEADER_FILLER ".........................................................................................."
-#define CLI_DETAIL_FILLER "                                                                                          "
-#define CLI_MAX_WIDTH 90
-#define CLI_LAST_TABSTOP 62
-#define CLI_MAX_TITLE_NAME 8
-#define CLI_INDENT_TO_SPACES(x) ((x * 2) + 1 + CLI_MAX_TITLE_NAME)
-
-/*
- * \brief CLI Formatter Context passed to all formatters.
- */
-struct ast_sip_cli_context {
-	/*! Buffer used to accumulate cli output. */
-	struct ast_str *output_buffer;
-	/*! Used to indicate which direction an auth is used for. "I" or "O" */
-	char *auth_direction;
-	/*! Allows formatters to know how far to indent their output. */
-	int indent_level;
-	/*! Tells a formatter to dump its object_set. */
-	unsigned show_details : 1;
-	/*! Tells a formatter to descend into child objects. */
-	unsigned recurse : 1;
-	/*! Tells a formatter to dump it's object_set only if it's the root object. */
-	unsigned show_details_only_level_0 : 1;
-};
-
-/*
- * \brief CLI Formatter Registry Entry
- */
-struct ast_sip_cli_formatter_entry {
-	/*! A globally unique name for this formatter.  If this formatter entry
-	 * is for an existing sorcery object type, then this name must match
-	 * the sorcery object type.  Otherwise it can be any string as long as
-	 * it's globally unique.
-	 */
-	const char *name;
-	/*! The callback used to print the object's column headers. */
-	ao2_callback_fn *print_header;
-	/*! The callback used to print the details of the object. */
-	ao2_callback_fn *print_body;
-	/*! The function used to retrieve a container of all objects of this type. */
-	struct ao2_container *(* get_container)(void);
-	/*! The function used to iterate over a container of objects. */
-	int (* iterate)(void *container, ao2_callback_fn callback, void *args);
-	/*! The function used to retrieve a specific object from it's container. */
-	void *(* retrieve_by_id)(const char *id);
-	/*! The function used to retrieve an id string from an object. */
-	const char *(* get_id)(const void *obj);
-};
-
-/*!
- * \brief Registers a CLI formatter.
- *
- * \param name The name of the formatter, usually the sorcery object type.
- * \param formatter An ao2_callback_fn that outputs the formatted data.
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter);
-
-/*!
- * \brief Unregisters a CLI formatter.
- *
- * \param name The name of the formatter, usually the sorcery object type.
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter);
-
-/*!
- * \brief Looks up a CLI formatter by type.
- *
- * \param name The name of the formatter, usually the sorcery object type.
- * \retval Pointer to formatter entry structure
- */
-struct ast_sip_cli_formatter_entry *ast_sip_lookup_cli_formatter(const char *name);
-
-/*!
- * \brief Prints a sorcery object's ast_variable list
- *
- * \param obj The sorcery object
- * \param arg The ast_sip_cli_context.
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags);
-
-char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
-
-
-#endif /* RES_PJSIP_CLI_H_ */
diff --git a/include/asterisk/res_pjsip_outbound_publish.h b/include/asterisk/res_pjsip_outbound_publish.h
deleted file mode 100644
index debec94..0000000
--- a/include/asterisk/res_pjsip_outbound_publish.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _RES_PJSIP_OUTBOUND_PUBLISH_H
-#define _RES_PJSIP_OUTBOUND_PUBLISH_H
-
-#include "asterisk/linkedlists.h"
-
-/* Forward declarations */
-struct ast_datastore;
-struct ast_datastore_info;
-
-/*!
- * \brief Opaque structure representing outbound publish configuration
- */
-struct ast_sip_outbound_publish;
-
-/*!
- * \brief Opaque structure representing an outbound publish client
- */
-struct ast_sip_outbound_publish_client;
-
-/*!
- * \brief Callbacks that event publisher handlers will define
- */
-struct ast_sip_event_publisher_handler {
-	/*! \brief The name of the event this handler deals with */
-	const char *event_name;
-
-	/*!
-	 * \brief Called when a publisher should start publishing.
-	 *
-	 * \param configuration The outbound publish configuration, event-specific configuration
-	 *        is accessible using extended sorcery fields
-	 * \param client The publish client that can be used to send PUBLISH messages.
-	 * \retval 0 success
-	 * \retval -1 failure
-	 */
-	int (*start_publishing)(struct ast_sip_outbound_publish *configuration,
-		struct ast_sip_outbound_publish_client *client);
-
-	/*!
-	 * \brief Called when a publisher should stop publishing.
-	 *
-	 * \param client The publish client that was used to send PUBLISH messages.
-	 * \retval 0 success
-	 * \retval -1 failure
-	 */
-	int (*stop_publishing)(struct ast_sip_outbound_publish_client *client);
-
-	AST_LIST_ENTRY(ast_sip_event_publisher_handler) next;
-};
-
-/*!
- * \brief Register an event publisher handler
- *
- * \retval 0 Handler was registered successfully
- * \retval non-zero Handler was not registered successfully
- */
-int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler);
-
-/*!
- * \brief Unregister a publish handler
- */
-void ast_sip_unregister_event_publisher_handler(struct ast_sip_event_publisher_handler *handler);
-
-/*!
- * \brief Find a publish client using its name
- *
- * \param name The name of the publish client
- *
- * \retval NULL failure
- * \retval non-NULL success
- *
- * \note The publish client is returned with its reference count increased and must be released using
- *       ao2_cleanup.
- */
-struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name);
-
-/*!
- * \brief Alternative for ast_datastore_alloc()
- *
- * There are two major differences between this and ast_datastore_alloc()
- * 1) This allocates a refcounted object
- * 2) This will fill in a uid if one is not provided
- *
- * DO NOT call ast_datastore_free() on a datastore allocated in this
- * way since that function will attempt to free the datastore rather
- * than play nicely with its refcount.
- *
- * \param info Callbacks for datastore
- * \param uid Identifier for datastore
- * \retval NULL Failed to allocate datastore
- * \retval non-NULL Newly allocated datastore
- */
-struct ast_datastore *ast_sip_publish_client_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
-
-/*!
- * \brief Add a datastore to a SIP event publisher
- *
- * Note that SIP uses reference counted datastores. The datastore passed into this function
- * must have been allocated using ao2_alloc() or there will be serious problems.
- *
- * \param client The publication client to add the datastore to
- * \param datastore The datastore to be added to the subscription
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_publish_client_add_datastore(struct ast_sip_outbound_publish_client *client,
-	struct ast_datastore *datastore);
-
-/*!
- * \brief Retrieve an event publisher datastore
- *
- * The datastore retrieved will have its reference count incremented. When the caller is done
- * with the datastore, the reference counted needs to be decremented using ao2_ref().
- *
- * \param client The publication client from which to retrieve the datastore
- * \param name The name of the datastore to retrieve
- * \retval NULL Failed to find the specified datastore
- * \retval non-NULL The specified datastore
- */
-struct ast_datastore *ast_sip_publish_client_get_datastore(struct ast_sip_outbound_publish_client *client,
-	const char *name);
-
-/*!
- * \brief Remove a publication datastore from an event publisher
- *
- * This operation may cause the datastore's free() callback to be called if the reference
- * count reaches zero.
- *
- * \param client The publication client to remove the datastore from
- * \param name The name of the datastore to remove
- */
-void ast_sip_publish_client_remove_datastore(struct ast_sip_outbound_publish_client *client,
-	const char *name);
-
-/*!
- * \brief Send an outgoing PUBLISH message using a client
- *
- * \param client The publication client to send from
- * \param body An optional body to add to the PUBLISH
- *
- * \retval -1 failure
- * \retval 0 success
- */
-int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client,
-	const struct ast_sip_body *body);
-
-#endif /* RES_PJSIP_OUTBOUND_PUBLISH_H */
diff --git a/include/asterisk/res_pjsip_presence_xml.h b/include/asterisk/res_pjsip_presence_xml.h
deleted file mode 100644
index add5f89..0000000
--- a/include/asterisk/res_pjsip_presence_xml.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \brief The length of the XML prolog when printing
- * presence or other XML in PJSIP.
- *
- * When calling any variant of pj_xml_print(), the documentation
- * claims that it will return -1 if the provided buffer is not
- * large enough. However, if the XML prolog is requested to be
- * printed, then the length of the XML prolog is returned upon
- * failure instead of -1.
- *
- * This constant is useful to check against when trying to determine
- * if printing XML succeeded or failed.
- */
-#define AST_PJSIP_XML_PROLOG_LEN 39
-
-/*!
- * PIDF state
- */
-enum ast_sip_pidf_state {
-	/*! Device is not in use */
-	NOTIFY_OPEN,
-	/*! Device is in use or ringing */
-	NOTIFY_INUSE,
-	/*! Device is unavailable, on hold, or busy */
-	NOTIFY_CLOSED
-};
-
-/*!
- * \brief Replace offensive XML characters with XML entities
- *
- * " = "
- * < = <
- * > = >
- * ' = '
- * & = &
- *
- * \param input String to sanitize
- * \param[out] output Sanitized string
- * \param len Size of output buffer
- */
-void ast_sip_sanitize_xml(const char *input, char *output, size_t len);
-
-/*!
- * \brief Convert extension state to relevant PIDF strings
- *
- * \param state The extension state
- * \param[out] statestring
- * \param[out] pidfstate
- * \param[out] pidfnote
- * \param[out] local_state
- */
-void ast_sip_presence_exten_state_to_str(int state, char **statestring,
-		char **pidfstate, char **pidfnote, enum ast_sip_pidf_state *local_state);
-
-/*!
- * \brief Create XML attribute
- *
- * \param pool Allocation pool
- * \param node Node to add attribute to
- * \param name The attribute name
- * \param value The attribute value
- *
- * \return The created attribute
- */
-pj_xml_attr *ast_sip_presence_xml_create_attr(pj_pool_t *pool,
-		pj_xml_node *node, const char *name, const char *value);
-
-/*!
- * \brief Create XML node
- *
- * \param pool Allocation pool
- * \param parent Optional node that will be parent to the created node
- * \param name The name for the new node
- * \return The created node
- */
-pj_xml_node *ast_sip_presence_xml_create_node(pj_pool_t *pool,
-		pj_xml_node *parent, const char* name);
-
-/*!
- * \brief Find an attribute within a given node
- *
- * Given a starting node, this will find an attribute that belongs
- * to a specific node. If the node does not exist, it will be created
- * under the passed-in parent. If the attribute does not exist, then
- * it will be created on the node with an empty string as its value.
- *
- * \param pool Allocation pool
- * \param parent Starting node for search
- * \param node_name Name of node where to find attribute
- * \param attr_name Name of attribute to find
- * \param[out] node Node that was found or created
- * \param[out] attr Attribute that was found or created
- * \return The found attribute
- */
-void ast_sip_presence_xml_find_node_attr(pj_pool_t* pool,
-		pj_xml_node *parent, const char *node_name, const char *attr_name,
-		pj_xml_node **node, pj_xml_attr **attr);
diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h
deleted file mode 100644
index d32b246..0000000
--- a/include/asterisk/res_pjsip_pubsub.h
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _RES_PJSIP_PUBSUB_H
-#define _RES_PJSIP_PUBSUB_H
-
-#include "asterisk/linkedlists.h"
-
-/* Forward declarations */
-struct pjsip_rx_data;
-struct pjsip_tx_data;
-struct pjsip_evsub;
-struct ast_sip_endpoint;
-struct ast_datastore;
-struct ast_datastore_info;
-
-/*!
- * \brief Opaque structure representing a publication
- */
-struct ast_sip_publication;
-
-enum ast_sip_publish_state {
-    /*! Publication has just been initialized */
-    AST_SIP_PUBLISH_STATE_INITIALIZED,
-    /*! Publication is currently active */
-    AST_SIP_PUBLISH_STATE_ACTIVE,
-    /*! Publication has been terminated */
-    AST_SIP_PUBLISH_STATE_TERMINATED,
-};
-
-/*!
- * \brief Callbacks that publication handlers will define
- */
-struct ast_sip_publish_handler {
-	/*! \brief The name of the event this handler deals with */
-	const char *event_name;
-
-	/*! \brief Publications */
-	struct ao2_container *publications;
-
-	/*!
-	 * \brief Called when a PUBLISH to establish a new publication arrives.
-	 *
-	 * \param endpoint The endpoint from whom the PUBLISH arrived.
-	 * \param resource The resource whose state is being published.
-	 * \param event_configuration The name of the event type configuration to use for this resource.
-	 * \return Response code for the incoming PUBLISH
-	 */
-	int (*new_publication)(struct ast_sip_endpoint *endpoint, const char *resource, const char *event_configuration);
-	/*!
-	 * \brief Called when a publication has reached its expiration.
-	 */
-	void (*publish_expire)(struct ast_sip_publication *pub);
-	/*!
-	 * \brief Published resource has changed states.
-	 *
-	 * The state parameter can be used to take further action. For instance,
-	 * if the state is AST_SIP_PUBLISH_STATE_INITIALIZED, then this is the initial
-	 * PUBLISH request. This is a good time to set up datastores on the publication
-	 * or any other initial needs.
-	 *
-	 * AST_SIP_PUBLISH_STATE_TERMINATED is used when the remote end is terminating
-	 * its publication. This is a good opportunity to free any resources associated with
-	 * the publication.
-	 *
-	 * AST_SIP_PUBLISH_STATE_ACTIVE is used when a publication that modifies state
-	 * arrives.
-	 *
-	 * \param pub The publication whose state has changed
-	 * \param body The body of the inbound PUBLISH
-	 * \param state The state of the publication
-	 */
-	int (*publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body,
-			enum ast_sip_publish_state state);
-	AST_LIST_ENTRY(ast_sip_publish_handler) next;
-};
-
-/*!
- * \brief Given a publication, get the associated endpoint
- *
- * \param pub The publication
- * \retval NULL Failure
- * \retval non-NULL The associated endpoint
- */
-struct ast_sip_endpoint *ast_sip_publication_get_endpoint(struct ast_sip_publication *pub);
-
-/*!
- * \brief Given a publication, get the resource the publication is to
- *
- * \param pub The publication
- * \return The resource
- */
-const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub);
-
-/*!
- * \brief Given a publication, get the configuration name for the event type in use
- *
- * \param pub The publication
- * \return The configuration name
- */
-const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub);
-
-/*!
- * \brief Register a publish handler
- *
- * \retval 0 Handler was registered successfully
- * \retval non-zero Handler was not registered successfully
- */
-int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler);
-
-/*!
- * \brief Unregister a publish handler
- */
-void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler);
-
-/*!
- * \brief Add a datastore to a SIP publication
- *
- * Note that SIP uses reference counted datastores. The datastore passed into this function
- * must have been allocated using ao2_alloc() or there will be serious problems.
- *
- * \param publication The publication to add the datastore to
- * \param datastore The datastore to be added to the subscription
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore);
-
-/*!
- * \brief Retrieve a publication datastore
- *
- * The datastore retrieved will have its reference count incremented. When the caller is done
- * with the datastore, the reference counted needs to be decremented using ao2_ref().
- *
- * \param publication The publication from which to retrieve the datastore
- * \param name The name of the datastore to retrieve
- * \retval NULL Failed to find the specified datastore
- * \retval non-NULL The specified datastore
- */
-struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name);
-
-/*!
- * \brief Remove a publication datastore from the publication
- *
- * This operation may cause the datastore's free() callback to be called if the reference
- * count reaches zero.
- *
- * \param publication The publication to remove the datastore from
- * \param name The name of the datastore to remove
- */
-void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name);
-
-/*!
- * \brief Opaque structure representing an RFC 3265 SIP subscription
- */
-struct ast_sip_subscription;
-
-/*!
- * \brief Role for the subscription that is being created
- */
-enum ast_sip_subscription_role {
-	/* Sending SUBSCRIBEs, receiving NOTIFYs */
-	AST_SIP_SUBSCRIBER,
-	/* Sending NOTIFYs, receiving SUBSCRIBEs */
-	AST_SIP_NOTIFIER,
-};
-
-/*!
- * \brief Data for responses to SUBSCRIBEs and NOTIFIEs
- *
- * Some of PJSIP's evsub callbacks expect us to provide them
- * with data so that they can craft a response rather than have
- * us create our own response.
- *
- * Filling in the structure is optional, since the framework
- * will automatically respond with a 200 OK response if we do
- * not provide it with any additional data.
- */
-struct ast_sip_subscription_response_data {
-	/*! Status code of the response */
-	int status_code;
-	/*! Optional status text */
-	const char *status_text;
-	/*! Optional additional headers to add to the response */
-	struct ast_variable *headers;
-	/*! Optional body to add to the response */
-	struct ast_sip_body *body;
-};
-
-#define AST_SIP_MAX_ACCEPT 32
-enum ast_sip_subscription_notify_reason {
-	/*! Initial NOTIFY for subscription */
-	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED,
-	/*! Subscription has been renewed */
-	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_RENEWED,
-	/*! Subscription is being terminated */
-	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_TERMINATED,
-	/*! Other unspecified reason */
-	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_OTHER
-};
-
-/*! Type used for conveying mailbox state */
-#define AST_SIP_EXTEN_STATE_DATA "ast_sip_exten_state_data"
-/*! Type used for extension state/presence */
-#define AST_SIP_MESSAGE_ACCUMULATOR "ast_sip_message_accumulator"
-
-/*!
- * \brief Data used to create bodies for NOTIFY/PUBLISH requests.
- */
-struct ast_sip_body_data {
-	/*! The type of the data */
-	const char *body_type;
-	/*! The actual data from which the body is generated */
-	void *body_data;
-};
-
-struct ast_sip_notifier {
-	/*!
-	 * \brief Default body type defined for the event package this notifier handles.
-	 *
-	 * Typically, a SUBSCRIBE request will contain one or more Accept headers that tell
-	 * what format they expect the body of NOTIFY requests to use. However, every event
-	 * package is required to define a default body format type to be used if a SUBSCRIBE
-	 * request for the event contains no Accept header.
-	 */
-	const char *default_accept;
-	/*!
-	 * \brief Called when a SUBSCRIBE arrives attempting to establish a new subscription.
-	 *
-	 * The notifier is expected to return the response that should be sent to the
-	 * SUBSCRIBE request.
-	 *
-	 * If a 200-class response is returned, then the notifier's notify_required
-	 * callback will immediately be called into with a reason of
-	 * AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED.
-	 *
-	 * \param endpoint The endpoint from which we received the SUBSCRIBE
-	 * \param resource The name of the resource to which the subscription is being made
-	 * \return The response code to send to the SUBSCRIBE.
-	 */
-	int (*new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource);
-	/*!
-	 * \brief Called when an inbound subscription has been accepted.
-	 *
-	 * This is a prime opportunity for notifiers to add any notifier-specific
-	 * data to the subscription (such as datastores) that it needs to.
-	 *
-	 * \note There is no need to send a NOTIFY request when this callback
-	 * is called
-	 *
-	 * \param sub The new subscription
-	 * \retval 0 Success
-	 * \retval -1 Failure
-	 */
-	int (*subscription_established)(struct ast_sip_subscription *sub);
-	/*!
-	 * \brief Supply data needed to create a NOTIFY body.
-	 *
-	 * The returned data must be an ao2 object. The caller of this function
-	 * will be responsible for decrementing the refcount of the returned object
-	 *
-	 * \param sub The subscription
-	 * \return An ao2 object that can be used to create a NOTIFY body.
-	 */
-	void *(*get_notify_data)(struct ast_sip_subscription *sub);
-};
-
-struct ast_sip_subscriber {
-	/*!
-	 * \brief A NOTIFY has been received.
-	 *
-	 * The body of the NOTIFY is provided so that it may be parsed and appropriate
-	 * internal state change may be generated.
-	 *
-	 * The state can be used to determine if the subscription has been terminated
-	 * by the far end or if this is just a typical resource state change.
-	 *
-	 * \param sub The subscription on which the NOTIFY arrived
-	 * \param body The body of the NOTIFY
-	 * \param state The subscription state
-	 */
-	void (*state_change)(struct ast_sip_subscription *sub, pjsip_msg_body *body, enum pjsip_evsub_state state);
-};
-
-struct ast_sip_subscription_handler {
-	/*! The name of the event this subscriber deals with */
-	const char *event_name;
-	/*! Type of data used to generate NOTIFY bodies */
-	const char *body_type;
-	/*! The types of body this subscriber accepts. */
-	const char *accept[AST_SIP_MAX_ACCEPT];
-	/*!
-	 * \brief Called when a subscription is to be destroyed
-	 *
-	 * The handler is not expected to send any sort of requests or responses
-	 * during this callback. The handler MUST, however, begin the destruction
-	 * process for the subscription during this callback.
-	 */
-	void (*subscription_shutdown)(struct ast_sip_subscription *subscription);
-	/*!
-	 * \brief Converts the subscriber to AMI
-	 *
-	 * \param sub The subscription
-	 * \param buf The string to write AMI data
-	 */
-	void (*to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf);
-	/*! Subscriber callbacks for this handler */
-	struct ast_sip_subscriber *subscriber;
-	/*! Notifier callbacks for this handler */
-	struct ast_sip_notifier *notifier;
-	AST_LIST_ENTRY(ast_sip_subscription_handler) next;
-};
-
-/*!
- * \brief Create a new ast_sip_subscription structure
- *
- * When a subscriber wishes to create a subscription, it may call this function
- * to allocate resources and to send the initial SUBSCRIBE out.
- *
- * \param subscriber The subscriber that is making the request.
- * \param endpoint The endpoint to whome the SUBSCRIBE will be sent.
- * \param resource The resource to place in the SUBSCRIBE's Request-URI.
- */
-struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
-		struct ast_sip_endpoint *endpoint, const char *resource);
-
-
-/*!
- * \brief Get the endpoint that is associated with this subscription
- *
- * This function will increase the reference count of the endpoint. Be sure to
- * release the reference to it when you are finished with the endpoint.
- *
- * \retval NULL Could not get endpoint
- * \retval non-NULL The endpoint
- */
-struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub);
-
-/*!
- * \brief Get the serializer for the subscription
- *
- * Tasks that originate outside of a SIP servant thread should get the serializer
- * and push the task to the serializer.
- *
- * \param sub The subscription
- * \retval NULL Failure
- * \retval non-NULL The subscription's serializer
- */
-struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub);
-
-/*!
- * \brief Notify a SIP subscription of a state change.
- *
- * This tells the pubsub core that the state of a subscribed resource has changed.
- * The pubsub core will generate an appropriate NOTIFY request to send to the
- * subscriber.
- *
- * \param sub The subscription on which a state change is occurring.
- * \param notify_data Event package-specific data used to create the NOTIFY body.
- * \param terminate True if this NOTIFY is intended to terminate the subscription.
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate);
-
-/*!
- * \brief Retrieve the local URI for this subscription
- *
- * This is the local URI of the subscribed resource.
- *
- * \param sub The subscription
- * \param[out] buf The buffer into which to store the URI.
- * \param size The size of the buffer.
- */
-void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size);
-
-/*!
- * \brief Retrive the remote URI for this subscription
- *
- * This is the remote URI as determined by the underlying SIP dialog.
- *
- * \param sub The subscription
- * \param[out] buf The buffer into which to store the URI.
- * \param size The size of the buffer.
- */
-void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size);
-
-/*!
- * \brief Get the name of the subscribed resource.
- */
-const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub);
-
-/*!
- * \brief Get a header value for a subscription.
- *
- * For notifiers, the headers of the inbound SUBSCRIBE that started the dialog
- * are stored on the subscription. This method allows access to the header. The
- * return is the same as pjsip_msg_find_hdr_by_name(), meaning that it is dependent
- * on the header being searched for.
- *
- * \param sub The subscription to search in.
- * \param header The name of the header to search for.
- * \return The discovered header, or NULL if the header cannot be found.
- */
-void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header);
-
-/*!
- * \brief Send a request created via a PJSIP evsub method
- *
- * Callers of this function should take care to do so within a SIP servant
- * thread.
- *
- * \param sub The subscription on which to send the request
- * \param tdata The request to send
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_subscription_send_request(struct ast_sip_subscription *sub, pjsip_tx_data *tdata);
-
-/*!
- * \brief Alternative for ast_datastore_alloc()
- *
- * There are two major differences between this and ast_datastore_alloc()
- * 1) This allocates a refcounted object
- * 2) This will fill in a uid if one is not provided
- *
- * DO NOT call ast_datastore_free() on a datastore allocated in this
- * way since that function will attempt to free the datastore rather
- * than play nicely with its refcount.
- *
- * \param info Callbacks for datastore
- * \param uid Identifier for datastore
- * \retval NULL Failed to allocate datastore
- * \retval non-NULL Newly allocated datastore
- */
-struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
-
-/*!
- * \brief Add a datastore to a SIP subscription
- *
- * Note that SIP uses reference counted datastores. The datastore passed into this function
- * must have been allocated using ao2_alloc() or there will be serious problems.
- *
- * \param subscription The ssubscription to add the datastore to
- * \param datastore The datastore to be added to the subscription
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore);
-
-/*!
- * \brief Retrieve a subscription datastore
- *
- * The datastore retrieved will have its reference count incremented. When the caller is done
- * with the datastore, the reference counted needs to be decremented using ao2_ref().
- *
- * \param subscription The subscription from which to retrieve the datastore
- * \param name The name of the datastore to retrieve
- * \retval NULL Failed to find the specified datastore
- * \retval non-NULL The specified datastore
- */
-struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name);
-
-/*!
- * \brief Remove a subscription datastore from the subscription
- *
- * This operation may cause the datastore's free() callback to be called if the reference
- * count reaches zero.
- *
- * \param subscription The subscription to remove the datastore from
- * \param name The name of the datastore to remove
- */
-void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);
-
-/*!
- * \brief Register a subscription handler
- *
- * \retval 0 Handler was registered successfully
- * \retval non-zero Handler was not registered successfully
- */
-int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler);
-
-/*!
- * \brief Unregister a subscription handler
- */
-void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler);
-
-/*!
- * \brief Pubsub body generator
- *
- * A body generator is responsible for taking Asterisk content
- * and converting it into a body format to be placed in an outbound
- * SIP NOTIFY or PUBLISH request.
- */
-struct ast_sip_pubsub_body_generator {
-	/*!
-	 * \brief Content type
-	 * In "plain/text", "plain" is the type
-	 */
-	const char *type;
-	/*!
-	 * \brief Content subtype
-	 * In "plain/text", "text" is the subtype
-	 */
-	const char *subtype;
-	/*! Type of data the body generator takes as input */
-	const char *body_type;
-	/*!
-	 * \brief allocate body structure.
-	 *
-	 * Body generators will have this method called when a NOTIFY
-	 * or PUBLISH body needs to be created. The type returned depends on
-	 * the type of content being produced for the body. The data parameter
-	 * is provided by the subscription handler and will vary between different
-	 * event types.
-	 *
-	 * \param data The subscription data provided by the event handler
-	 * \retval non-NULL The allocated body
-	 * \retval NULL Failure
-	 */
-	void *(*allocate_body)(void *data);
-	/*!
-	 * \brief Add content to the body of a SIP request
-	 *
-	 * The body of the request has already been allocated by the body generator's
-	 * allocate_body callback.
-	 *
-	 * \param body The body of the SIP request. The type is determined by the
-	 * content type.
-	 * \param data The subscription data used to populate the body. The type is
-	 * determined by the content type.
-	 */
-	int (*generate_body_content)(void *body, void *data);
-	/*!
-	 * \brief Convert the body to a string.
-	 *
-	 * \param body The request body.
-	 * \param str The converted string form of the request body
-	 */
-	void (*to_string)(void *body, struct ast_str **str);
-	/*!
-	 * \brief Deallocate resources created for the body
-	 *
-	 * Optional callback to destroy resources allocated for the
-	 * message body.
-	 *
-	 * \param body Body to be destroyed
-	 */
-	void (*destroy_body)(void *body);
-	AST_LIST_ENTRY(ast_sip_pubsub_body_generator) list;
-};
-
-/*!
- * \brief Body supplement
- *
- * Body supplements provide additions to bodies not already
- * provided by body generators. This may include proprietary
- * extensions, optional content, or other nonstandard fare.
- */
-struct ast_sip_pubsub_body_supplement {
-	/*!
-	 * \brief Content type
-	 * In "plain/text", "plain" is the type
-	 */
-	const char *type;
-	/*!
-	 * \brief Content subtype
-	 * In "plain/text", "text" is the subtype
-	 */
-	const char *subtype;
-	/*!
-	 * \brief Add additional content to a SIP request body.
-	 *
-	 * A body generator will have already allocated a body and populated
-	 * it with base data for the event. The supplement's duty is, if desired,
-	 * to extend the body to have optional data beyond what a base RFC specifies.
-	 *
-	 * \param body The body of the SIP request. The type is determined by the
-	 * body generator that allocated the body.
-	 * \param data The subscription data used to populate the body. The type is
-	 * determined by the content type.
-	 */
-	int (*supplement_body)(void *body, void *data);
-	AST_LIST_ENTRY(ast_sip_pubsub_body_supplement) list;
-};
-
-/*!
- * \since 13.0.0
- * \brief Generate body content for a PUBLISH or NOTIFY
- *
- * This function takes a pre-allocated body and calls into registered body
- * generators in order to fill in the body with appropriate details.
- * The primary body generator will be called first, followed by the
- * supplementary body generators
- *
- * \param content_type The content type of the body
- * \param content_subtype The content subtype of the body
- * \param data The data associated with body generation.
- * \param[out] str The string representation of the generated body
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_pubsub_generate_body_content(const char *content_type,
-		const char *content_subtype, struct ast_sip_body_data *data, struct ast_str **str);
-
-/*!
- * \since 13.0.0
- * \brief Register a body generator with the pubsub core.
- *
- * This may fail if an attempt is made to register a primary body supplement
- * for a given content type if a primary body supplement for that content type
- * has already been registered.
- *
- * \param generator Body generator to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator);
-
-/*!
- * \since 13.0.0
- * \brief Unregister a body generator with the pubsub core.
- *
- * \param generator Body generator to unregister
- */
-void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator);
-
-/*!
- * \since 13.0.0
- * \brief Register a body generator with the pubsub core.
- *
- * This may fail if an attempt is made to register a primary body supplement
- * for a given content type if a primary body supplement for that content type
- * has already been registered.
- *
- * \param generator Body generator to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement);
-
-/*!
- * \since 13.0.0
- * \brief Unregister a body generator with the pubsub core.
- *
- * \param generator Body generator to unregister
- */
-void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement);
-
-/*!
- * \since 13.0.0
- * \brief Get the body type used for this subscription
- */
-const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub);
-
-/*!
- * \since 13.0.0
- * \brief Get the body subtype used for this subscription
- */
-const char *ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub);
-
-/*! \brief Determines whether the res_pjsip_pubsub module is loaded */
-#define CHECK_PJSIP_PUBSUB_MODULE_LOADED()			\
-	do {							\
-		CHECK_PJSIP_MODULE_LOADED();			\
-		if (!ast_module_check("res_pjsip_pubsub.so")) {	\
-			return AST_MODULE_LOAD_DECLINE;		\
-		}						\
-	} while(0)
-
-#endif /* RES_PJSIP_PUBSUB_H */
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
deleted file mode 100644
index 30d325e..0000000
--- a/include/asterisk/res_pjsip_session.h
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _RES_PJSIP_SESSION_H
-#define _RES_PJSIP_SESSION_H
-
-/* Needed for pj_timer_entry definition */
-#include "pjlib.h"
-#include "asterisk/linkedlists.h"
-/* Needed for AST_MAX_EXTENSION constant */
-#include "asterisk/channel.h"
-/* Needed for ast_sockaddr struct */
-#include "asterisk/netsock2.h"
-/* Needed for ast_sdp_srtp struct */
-#include "asterisk/sdp_srtp.h"
-
-/* Forward declarations */
-struct ast_sip_endpoint;
-struct ast_sip_transport;
-struct pjsip_inv_session;
-struct ast_channel;
-struct ast_datastore;
-struct ast_datastore_info;
-struct ao2_container;
-struct pjsip_tx_data;
-struct pjsip_rx_data;
-struct ast_party_id;
-struct pjmedia_sdp_media;
-struct pjmedia_sdp_session;
-struct ast_dsp;
-struct ast_udptl;
-
-/*! \brief T.38 states for a session */
-enum ast_sip_session_t38state {
-	T38_DISABLED = 0,   /*!< Not enabled */
-	T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
-	T38_PEER_REINVITE,  /*!< Offered from peer - REINVITE */
-	T38_ENABLED,        /*!< Negotiated (enabled) */
-	T38_REJECTED,       /*!< Refused */
-	T38_MAX_ENUM,       /*!< Not an actual state; used as max value in the enum */
-};
-
-struct ast_sip_session_sdp_handler;
-
-/*!
- * \brief A structure containing SIP session media information
- */
-struct ast_sip_session_media {
-	union {
-		/*! \brief RTP instance itself */
-		struct ast_rtp_instance *rtp;
-		/*! \brief UDPTL instance itself */
-		struct ast_udptl *udptl;
-	};
-	/*! \brief Direct media address */
-	struct ast_sockaddr direct_media_addr;
-	/*! \brief SDP handler that setup the RTP */
-	struct ast_sip_session_sdp_handler *handler;
-	/*! \brief Holds SRTP information */
-	struct ast_sdp_srtp *srtp;
-	/*! \brief What type of encryption is in use on this stream */
-	enum ast_sip_session_media_encryption encryption;
-	/*! \brief The media transport in use for this stream */
-	pj_str_t transport;
-	/*! \brief Stream is on hold */
-	unsigned int held:1;
-	/*! \brief Stream type this session media handles */
-	char stream_type[1];
-};
-
-/*!
- * \brief Opaque structure representing a request that could not be sent
- * due to an outstanding INVITE transaction
- */
-struct ast_sip_session_delayed_request;
-
-/*! \brief Opaque struct controlling the suspension of the session's serializer. */
-struct ast_sip_session_suspender;
-
-/*!
- * \brief A structure describing a SIP session
- *
- * For the sake of brevity, a "SIP session" in Asterisk is referring to
- * a dialog initiated by an INVITE. While "session" is typically interpreted
- * to refer to the negotiated media within a SIP dialog, we have opted
- * to use the term "SIP session" to refer to the INVITE dialog itself.
- */
-struct ast_sip_session {
-	/*! Dialplan extension where incoming call is destined */
-	char exten[AST_MAX_EXTENSION];
-	/*! The endpoint with which Asterisk is communicating */
-	struct ast_sip_endpoint *endpoint;
-	/*! The contact associated with this session */
-	struct ast_sip_contact *contact;
-	/*! The PJSIP details of the session, which includes the dialog */
-	struct pjsip_inv_session *inv_session;
-	/*! The Asterisk channel associated with the session */
-	struct ast_channel *channel;
-	/*! Registered session supplements */
-	AST_LIST_HEAD(, ast_sip_session_supplement) supplements;
-	/*! Datastores added to the session by supplements to the session */
-	struct ao2_container *datastores;
-	/*! Media streams */
-	struct ao2_container *media;
-	/*! Serializer for tasks relating to this SIP session */
-	struct ast_taskprocessor *serializer;
-	/*! Non-null if the session serializer is suspended or being suspended. */
-	struct ast_sip_session_suspender *suspended;
-	/*! Requests that could not be sent due to current inv_session state */
-	AST_LIST_HEAD_NOLOCK(, ast_sip_session_delayed_request) delayed_requests;
-	/*! When we need to reschedule a reinvite, we use this structure to do it */
-	pj_timer_entry rescheduled_reinvite;
-	/*! Format capabilities pertaining to direct media */
-	struct ast_format_cap *direct_media_cap;
-	/*! When we need to forcefully end the session */
-	pj_timer_entry scheduled_termination;
-	/*! Identity of endpoint this session deals with */
-	struct ast_party_id id;
-	/*! Requested capabilities */
-	struct ast_format_cap *req_caps;
-	/*! Optional DSP, used only for inband DTMF detection if configured */
-	struct ast_dsp *dsp;
-	/*! Whether the termination of the session should be deferred */
-	unsigned int defer_terminate:1;
-	/*! Deferred incoming re-invite */
-	pjsip_rx_data *deferred_reinvite;
-	/*! Current T.38 state */
-	enum ast_sip_session_t38state t38state;
-};
-
-typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
-typedef int (*ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata);
-typedef int (*ast_sip_session_sdp_creation_cb)(struct ast_sip_session *session, pjmedia_sdp_session *sdp);
-
-/*!
- * \brief Describes when a supplement should be called into on incoming responses.
- *
- * In most cases, session supplements will not need to worry about this because in most cases,
- * the correct value will be automatically applied. However, there are rare circumstances
- * when a supplement will want to specify when it should be called.
- *
- * The values below are listed in chronological order.
- */
-enum ast_sip_session_response_priority {
-	/*!
-	 * When processing 3XX responses, the supplement is called into before
-	 * the redirecting information is processed.
-	 */
-	AST_SIP_SESSION_BEFORE_REDIRECTING = (1 << 0),
-	/*!
-	 * For responses to INVITE transactions, the supplement is called into
-	 * before media is negotiated.
-	 *
-	 * This priority is applied by default to any session supplement that
-	 * does not specify a response priority.
-	 */
-	AST_SIP_SESSION_BEFORE_MEDIA = (1 << 1),
-	/*!
-	 * For INVITE transactions, the supplement is called into after media
-	 * is negotiated.
-	 */
-	AST_SIP_SESSION_AFTER_MEDIA = (1 << 2),
-};
-
-/*!
- * \brief A supplement to SIP message processing
- *
- * These can be registered by any module in order to add
- * processing to incoming and outgoing SIP requests and responses
- */
-struct ast_sip_session_supplement {
-	/*! Method on which to call the callbacks. If NULL, call on all methods */
-	const char *method;
-	/*! Priority for this supplement. Lower numbers are visited before higher numbers */
-	enum ast_sip_supplement_priority priority;
-	/*!
-	 * \brief Notification that the session has begun
-	 * This method will always be called from a SIP servant thread.
-	 */
-	void (*session_begin)(struct ast_sip_session *session);
-	/*! 
-	 * \brief Notification that the session has ended
-	 *
-	 * This method may or may not be called from a SIP servant thread. Do
-	 * not make assumptions about being able to call PJSIP methods from within
-	 * this method.
-	 */
-	void (*session_end)(struct ast_sip_session *session);
-	/*!
-	 * \brief Notification that the session is being destroyed
-	 */
-	void (*session_destroy)(struct ast_sip_session *session);
-	/*!
-	 * \brief Called on incoming SIP request
-	 * This method can indicate a failure in processing in its return. If there
-	 * is a failure, it is required that this method sends a response to the request.
-	 * This method is always called from a SIP servant thread.
-	 *
-	 * \note
-	 * The following PJSIP methods will not work properly:
-	 * pjsip_rdata_get_dlg()
-	 * pjsip_rdata_get_tsx()
-	 * The reason is that the rdata passed into this function is a cloned rdata structure,
-	 * and its module data is not copied during the cloning operation.
-	 * If you need to get the dialog, you can get it via session->inv_session->dlg.
-	 *
-	 * \note
-	 * There is no guarantee that a channel will be present on the session when this is called.
-	 */
-	int (*incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
-	/*! 
-	 * \brief Called on an incoming SIP response
-	 * This method is always called from a SIP servant thread.
-	 *
-	 * \note
-	 * The following PJSIP methods will not work properly:
-	 * pjsip_rdata_get_dlg()
-	 * pjsip_rdata_get_tsx()
-	 * The reason is that the rdata passed into this function is a cloned rdata structure,
-	 * and its module data is not copied during the cloning operation.
-	 * If you need to get the dialog, you can get it via session->inv_session->dlg.
-	 *
-	 * \note
-	 * There is no guarantee that a channel will be present on the session when this is called.
-	 */
-	void (*incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
-	/*!
-	 * \brief Called on an outgoing SIP request
-	 * This method is always called from a SIP servant thread.
-	 */
-	void (*outgoing_request)(struct ast_sip_session *session, struct pjsip_tx_data *tdata);
-	/*! 
-	 * \brief Called on an outgoing SIP response
-	 * This method is always called from a SIP servant thread.
-	 */
-	void (*outgoing_response)(struct ast_sip_session *session, struct pjsip_tx_data *tdata);
-	/*! Next item in the list */
-	AST_LIST_ENTRY(ast_sip_session_supplement) next;
-	/*!
-	 * Determines when the supplement is processed when handling a response.
-	 * Defaults to AST_SIP_SESSION_BEFORE_MEDIA
-	 */
-	enum ast_sip_session_response_priority response_priority;
-};
-
-enum ast_sip_session_sdp_stream_defer {
-	/*! The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. */
-	AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED,
-	/*! There was an error encountered. No further operations will take place and the current negotiation will be abandoned. */
-	AST_SIP_SESSION_SDP_DEFER_ERROR,
-	/*! Re-invite is not needed */
-	AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED,
-	/*! Re-invite should be deferred and will be resumed later. No further operations will take place. */
-	AST_SIP_SESSION_SDP_DEFER_NEEDED,
-};
-
-/*!
- * \brief A handler for SDPs in SIP sessions
- *
- * An SDP handler is registered by a module that is interested in being the
- * responsible party for specific types of SDP streams.
- */
-struct ast_sip_session_sdp_handler {
-	/*! An identifier for this handler */
-	const char *id;
-	/*!
-	 * \brief Determine whether a stream requires that the re-invite be deferred.
-	 * If a stream can not be immediately negotiated the re-invite can be deferred and
-	 * resumed at a later time. It is up to the handler which caused deferral to occur
-	 * to resume it.
-	 *
-	 * \param session The session for which the media is being re-invited
-	 * \param session_media The media being reinvited
-	 * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes
-	 * \param stream PJSIP incoming SDP media lines to parse by handler.
-	 *
-	 * \return enum ast_sip_session_defer_stream
-	 *
-	 * \note This is optional, if not implemented the stream is assumed to not be deferred.
-	 */
-	enum ast_sip_session_sdp_stream_defer (*defer_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
-	/*!
-	 * \brief Set session details based on a stream in an incoming SDP offer or answer
-	 * \param session The session for which the media is being negotiated
-	 * \param session_media The media to be setup for this session
-	 * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes
-	 * \param stream The stream on which to operate
-	 * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
-	 * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
-	 * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
-	 */
-	int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
-	/*!
-	 * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
-	 * \param session The session for which media is being added
-	 * \param session_media The media to be setup for this session
-	 * \param stream The stream on which to operate
-	 * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
-	 * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
-	 * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
-	 */
-	int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream);
-	/*!
-	 * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
-	 * \param session The session for which media is being added
-	 * \param session_media The media to be setup for this session
-	 * \param sdp The entire SDP as currently built
-	 * \retval 0 This handler has no stream to add. If there are other registered handlers for this stream type, they will be called.
-	 * \retval <0 There was an error encountered. No further operation will take place and the current SDP negotiation will be abandoned.
-	 * \retval >0 The handler has a stream to be added to the SDP. No further handler of this stream type will be called.
-	 */
-	int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp);
-	/*!
-	 * \brief Update media stream with external address if applicable
-	 * \param tdata The outgoing message itself
-	 * \param stream The stream on which to operate
-	 * \param transport The transport the SDP is going out on
-	 */
-	void (*change_outgoing_sdp_stream_media_address)(struct pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport);
-	/*!
-	 * \brief Apply a negotiated SDP media stream
-	 * \param session The session for which media is being applied
-	 * \param session_media The media to be setup for this session
-	 * \param local The entire local negotiated SDP
-	 * \param local_stream The local stream which to apply
-	 * \param remote The entire remote negotiated SDP
-	 * \param remote_stream The remote stream which to apply
-	 * \retval 0 The stream was not applied by this handler. If there are other registered handlers for this stream type, they will be called.
-	 * \retval <0 There was an error encountered. No further operation will take place and the current application will be abandoned.
-	 * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
-	 */
-	int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
-		const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream);
-	/*!
-	 * \brief Destroy a session_media created by this handler
-	 * \param session The session for which media is being destroyed
-	 * \param session_media The media to destroy
-	 */
-	void (*stream_destroy)(struct ast_sip_session_media *session_media);
-	/*! Next item in the list. */
-	AST_LIST_ENTRY(ast_sip_session_sdp_handler) next;
-};
-
-/*!
- * \brief A structure which contains a channel implementation and session
- */
-struct ast_sip_channel_pvt {
-	/*! \brief Pointer to channel specific implementation information, must be ao2 object */
-	void *pvt;
-	/*! \brief Pointer to session */
-	struct ast_sip_session *session;
-};
-
-/*!
- * \brief Allocate a new SIP channel pvt structure
- *
- * \param pvt Pointer to channel specific implementation
- * \param session Pointer to SIP session
- *
- * \retval non-NULL success
- * \retval NULL failure
- */
-struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_session *session);
-
-/*!
- * \brief Allocate a new SIP session
- *
- * This will take care of allocating the datastores container on the session as well
- * as placing all registered supplements onto the session.
- *
- * The endpoint that is passed in will have its reference count increased by one since
- * the session will be keeping a reference to the endpoint. The session will relinquish
- * this reference when the session is destroyed.
- *
- * \param endpoint The endpoint that this session communicates with
- * \param contact The contact associated with this session
- * \param inv_session The PJSIP INVITE session data
- */
-struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
-	struct ast_sip_contact *contact, pjsip_inv_session *inv);
-
-/*!
- * \brief Request and wait for the session serializer to be suspended.
- * \since 12.7.0
- *
- * \param session Which session to suspend the serializer.
- *
- * \note No channel locks can be held while calling without risk of deadlock.
- *
- * \return Nothing
- */
-void ast_sip_session_suspend(struct ast_sip_session *session);
-
-/*!
- * \brief Request the session serializer be unsuspended.
- * \since 12.7.0
- *
- * \param session Which session to unsuspend the serializer.
- *
- * \return Nothing
- */
-void ast_sip_session_unsuspend(struct ast_sip_session *session);
-
-/*!
- * \brief Create a new outgoing SIP session
- *
- * The endpoint that is passed in will have its reference count increased by one since
- * the session will be keeping a reference to the endpoint. The session will relinquish
- * this reference when the session is destroyed.
- *
- * \param endpoint The endpoint that this session uses for settings
- * \param contact The contact that this session will communicate with
- * \param location Name of the location to call, be it named location or explicit URI. Overrides contact if present.
- * \param request_user Optional request user to place in the request URI if permitted
- * \param req_caps The requested capabilities
- */
-struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint,
-	struct ast_sip_contact *contact, const char *location, const char *request_user,
-	struct ast_format_cap *req_caps);
-
-/*!
- * \brief Defer local termination of a session until remote side terminates, or an amount of time passes
- *
- * \param session The session to defer termination on
- */
-void ast_sip_session_defer_termination(struct ast_sip_session *session);
-
-/*!
- * \brief Register an SDP handler
- *
- * An SDP handler is responsible for parsing incoming SDP streams and ensuring that
- * Asterisk can cope with the contents. Similarly, the SDP handler will be
- * responsible for constructing outgoing SDP streams.
- *
- * Multiple handlers for the same stream type may be registered. They will be
- * visited in the order they were registered. Handlers will be visited for each
- * stream type until one claims to have handled the stream.
- *
- * \param handler The SDP handler to register
- * \param stream_type The type of media stream for which to call the handler
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type);
-
-/*!
- * \brief Unregister an SDP handler
- *
- * \param handler The SDP handler to unregister
- * \param stream_type Stream type for which the SDP handler was registered
- */
-void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type);
-
-/*!
- * \brief Register a supplement to SIP session processing
- *
- * This allows for someone to insert themselves in the processing of SIP
- * requests and responses. This, for example could allow for a module to
- * set channel data based on headers in an incoming message. Similarly,
- * a module could reject an incoming request if desired.
- *
- * \param supplement The supplement to register
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement);
-
-/*!
- * \brief Unregister a an supplement to SIP session processing
- *
- * \param supplement The supplement to unregister
- */
-void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement);
-
-/*!
- * \brief Alternative for ast_datastore_alloc()
- *
- * There are two major differences between this and ast_datastore_alloc()
- * 1) This allocates a refcounted object
- * 2) This will fill in a uid if one is not provided
- *
- * DO NOT call ast_datastore_free() on a datastore allocated in this
- * way since that function will attempt to free the datastore rather
- * than play nicely with its refcount.
- *
- * \param info Callbacks for datastore
- * \param uid Identifier for datastore
- * \retval NULL Failed to allocate datastore
- * \retval non-NULL Newly allocated datastore
- */
-struct ast_datastore *ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
-
-/*!
- * \brief Add a datastore to a SIP session
- *
- * Note that SIP uses reference counted datastores. The datastore passed into this function
- * must have been allocated using ao2_alloc() or there will be serious problems.
- *
- * \param session The session to add the datastore to
- * \param datastore The datastore to be added to the session
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore);
-
-/*!
- * \brief Retrieve a session datastore
- *
- * The datastore retrieved will have its reference count incremented. When the caller is done
- * with the datastore, the reference counted needs to be decremented using ao2_ref().
- *
- * \param session The session from which to retrieve the datastore
- * \param name The name of the datastore to retrieve
- * \retval NULL Failed to find the specified datastore
- * \retval non-NULL The specified datastore
- */
-struct ast_datastore *ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name);
-
-/*!
- * \brief Remove a session datastore from the session
- *
- * This operation may cause the datastore's free() callback to be called if the reference
- * count reaches zero.
- *
- * \param session The session to remove the datastore from
- * \param name The name of the datastore to remove
- */
-void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name);
-
-/*!
- * \brief Send a reinvite or UPDATE on a session
- *
- * This method will inspect the session in order to construct an appropriate
- * session refresh request. As with any outgoing request in res_pjsip_session,
- * this will call into registered supplements in case they wish to add anything.
- *
- * Note: The on_request_creation callback may or may not be called in the same
- * thread where this function is called. Request creation may need to be delayed
- * due to the current INVITE transaction state.
- * 
- * \param session The session on which the reinvite will be sent
- * \param on_request_creation Callback called when request is created
- * \param on_sdp_creation Callback called when SDP is created
- * \param on_response Callback called when response for request is received
- * \param method The method that should be used when constructing the session refresh
- * \param generate_new_sdp Boolean to indicate if a new SDP should be created
- * \retval 0 Successfully sent refresh
- * \retval -1 Failure to send refresh
- */
-int ast_sip_session_refresh(struct ast_sip_session *session,
-		ast_sip_session_request_creation_cb on_request_creation,
-		ast_sip_session_sdp_creation_cb on_sdp_creation,
-		ast_sip_session_response_cb on_response,
-		enum ast_sip_session_refresh_method method,
-		int generate_new_sdp);
-
-/*!
- * \brief Send a SIP response
- *
- * This will send the SIP response specified in tdata and
- * call into any registered supplements' outgoing_response callback.
- *
- * \param session The session on which to send the response.
- * \param tdata The response to send
- */
-void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata);
-
-/*!
- * \brief Send a SIP request
- *
- * This will send the SIP request specified in tdata and
- * call into any registered supplements' outgoing_request callback.
- *
- * \param session The session to which to send the request
- * \param tdata The request to send
- */
-void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata);
-
-/*!
- * \brief Creates an INVITE request.
- *
- * \param session Starting session for the INVITE
- * \param tdata The created request.
- */
-int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data **tdata);
-
-/*!
- * \brief Send a SIP request and get called back when a response is received
- *
- * This will send the request out exactly the same as ast_sip_send_request() does.
- * The difference is that when a response arrives, the specified callback will be
- * called into
- *
- * \param session The session on which to send the request
- * \param tdata The request to send
- * \param on_response Callback to be called when a response is received
- */
-void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
-		ast_sip_session_response_cb on_response);
-
-/*!
- * \brief Retrieves a session from a dialog
- *
- * \param dlg The dialog to retrieve the session from
- *
- * \retval non-NULL if session exists
- * \retval NULL if no session
- *
- * \note The reference count of the session is increased when returned
- *
- * \note This function *must* be called with the dialog locked
- */
-struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg);
-
-/*!
- * \brief Resumes processing of a deferred incoming re-invite
- *
- * \param session The session which has a pending incoming re-invite
- *
- * \note When resuming a re-invite it is given to the pjsip stack as if it
- *       had just been received from a transport, this means that the deferral
- *       callback will be called again.
- */
-void ast_sip_session_resume_reinvite(struct ast_sip_session *session);
-
-/*! \brief Determines whether the res_pjsip_session module is loaded */
-#define CHECK_PJSIP_SESSION_MODULE_LOADED()				\
-	do {								\
-		CHECK_PJSIP_MODULE_LOADED();				\
-		if (!ast_module_check("res_pjsip_session.so")) {	\
-			return AST_MODULE_LOAD_DECLINE;			\
-		}							\
-	} while(0)
-
-#endif /* _RES_PJSIP_SESSION_H */
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index db5cd34..d1d1f40 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -1,4 +1,4 @@
- /*
+/*
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 1999 - 2009, Digium, Inc.
@@ -71,12 +71,9 @@ extern "C" {
 
 #include "asterisk/astobj2.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cap.h"
 #include "asterisk/netsock2.h"
 #include "asterisk/sched.h"
 #include "asterisk/res_srtp.h"
-#include "asterisk/stasis.h"
-#include "asterisk/vector.h"
 
 /* Maximum number of payloads supported */
 #if defined(LOW_MEMORY)
@@ -88,15 +85,6 @@ extern "C" {
 /* Maximum number of generations */
 #define AST_RED_MAX_GENERATION 5
 
-/*!
- * Maximum size of an internal Asterisk channel unique ID.
- *
- * \note Must match the AST_MAX_UNIQUEID(AST_MAX_PUBLIC_UNIQUEID) value.
- * We don't use that defined value directly here to avoid a hard
- * dependency on channel.h.
- */
-#define MAX_CHANNEL_ID 152
-
 struct ast_rtp_instance;
 struct ast_rtp_glue;
 
@@ -227,8 +215,6 @@ enum ast_rtp_instance_stat {
 	AST_RTP_INSTANCE_STAT_LOCAL_SSRC,
 	/*! Retrieve remote SSRC */
 	AST_RTP_INSTANCE_STAT_REMOTE_SSRC,
-	/*! Retrieve channel unique ID */
-	AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID,
 };
 
 /* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
@@ -247,53 +233,13 @@ struct ast_rtp_payload_type {
 	int asterisk_format;
 	/*! If asterisk_format is set, this is the internal
 	 * asterisk format represented by the payload */
-	struct ast_format *format;
+	struct ast_format format;
 	/*! Actual internal RTP specific value of the payload */
 	int rtp_code;
 	/*! Actual payload number */
 	int payload;
 };
 
-/* Common RTCP report types */
-/*! Sender Report */
-#define AST_RTP_RTCP_SR 200
-/*! Receiver Report */
-#define AST_RTP_RTCP_RR 201
-
-/*!
- * \since 12
- * \brief A report block within a SR/RR report */
-struct ast_rtp_rtcp_report_block {
-	unsigned int source_ssrc;         /*< The SSRC of the source for this report block */
-	struct {
-		unsigned short fraction;      /*< The fraction of packets lost since last SR/RR */
-		unsigned int packets;         /*< The cumulative packets since the beginning */
-	} lost_count;                     /*< Statistics regarding missed packets */
-	unsigned int highest_seq_no;      /*< Extended highest sequence number received */
-	unsigned int ia_jitter;           /*< Calculated interarrival jitter */
-	unsigned int lsr;                 /*< The time the last SR report was received */
-	unsigned int dlsr;                /*< Delay in sending this report */
-};
-
-/*!
- * \since 12
- * \brief An object that represents data sent during a SR/RR RTCP report */
-struct ast_rtp_rtcp_report {
-	unsigned short reception_report_count;     /*< The number of report blocks */
-	unsigned int ssrc;                         /*< Our SSRC */
-	unsigned int type;                         /*< The type of report. 200=SR; 201=RR */
-	struct {
-		struct timeval ntp_timestamp;          /*< Our NTP timestamp */
-		unsigned int rtp_timestamp;            /*< Our last RTP timestamp */
-		unsigned int packet_count;             /*< Number of packets sent */
-		unsigned int octet_count;              /*< Number of bytes sent */
-	} sender_information;                      /*< Sender information for SR */
-	/*! A dynamic array of report blocks. The number of elements is given by
-	 * \c reception_report_count.
-	 */
-	struct ast_rtp_rtcp_report_block *report_block[0];
-};
-
 /*! Structure that represents statistics from an RTP instance */
 struct ast_rtp_instance_stats {
 	/*! Number of packets transmitted */
@@ -354,8 +300,6 @@ struct ast_rtp_instance_stats {
 	unsigned int local_ssrc;
 	/*! Their SSRC */
 	unsigned int remote_ssrc;
-	/*! The Asterisk channel's unique ID that owns this instance */
-	char channel_uniqueid[MAX_CHANNEL_ID];
 };
 
 #define AST_RTP_STAT_SET(current_stat, combined, placement, value) \
@@ -366,14 +310,6 @@ return 0; \
 } \
 }
 
-#define AST_RTP_STAT_STRCPY(current_stat, combined, placement, value) \
-if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \
-	ast_copy_string(placement, value, sizeof(placement)); \
-	if (stat == current_stat) { \
-		return 0; \
-	} \
-}
-
 #define AST_RTP_STAT_TERMINATOR(combined) \
 if (stat == combined) { \
 return 0; \
@@ -429,10 +365,6 @@ struct ast_rtp_engine_ice {
 	void (*ice_lite)(struct ast_rtp_instance *instance);
 	/*! Callback for changing our role in negotiation */
 	void (*set_role)(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role);
-	/*! Callback for requesting a TURN session */
-	void (*turn_request)(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component,
-		enum ast_transport transport, const char *server, unsigned int port,
-		const char *username, const char *password);
 };
 
 /*! \brief DTLS setup types */
@@ -532,8 +464,12 @@ struct ast_rtp_engine {
 	void (*prop_set)(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
 	/*! Callback for setting a payload.  If asterisk  is to be used, asterisk_format will be set, otherwise value in code is used. */
 	void (*payload_set)(struct ast_rtp_instance *instance, int payload, int asterisk_format, struct ast_format *format, int code);
+	/*! Callback for setting packetization preferences */
+	void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref);
 	/*! Callback for setting the remote address that RTP is to be sent to */
 	void (*remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa);
+	/*! Callback for setting an alternate remote address */
+	void (*alt_remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa);
 	/*! Callback for changing DTMF mode */
 	int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode);
 	/*! Callback for getting DTMF mode */
@@ -579,16 +515,11 @@ struct ast_rtp_engine {
 /*! Structure that represents codec and packetization information */
 struct ast_rtp_codecs {
 	/*! Payloads present */
-	AST_VECTOR(, struct ast_rtp_payload_type *) payloads;
-	/*! The framing for this media session */
-	unsigned int framing;
-	/*! RW lock that protects elements in this structure */
-	ast_rwlock_t codecs_lock;
+	struct ao2_container *payloads;
+	/*! Codec packetization preferences */
+	struct ast_codec_pref pref;
 };
 
-#define AST_RTP_CODECS_NULL_INIT \
-    { .payloads = { 0, }, .framing = 0, .codecs_lock = AST_RWLOCK_INIT_VALUE, }
-
 /*! Structure that represents the glue that binds an RTP instance to a channel */
 struct ast_rtp_glue {
 	/*! Name of the channel driver that this glue is responsible for */
@@ -603,9 +534,10 @@ struct ast_rtp_glue {
 	/*!
 	 * \brief Used to prevent two channels from remotely bridging audio rtp if the channel tech has a
 	 *        reason for prohibiting it based on qualities that need to be compared from both channels.
+	 * \note This function should only be called with two channels of the same technology
 	 * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, function this is not used.
 	 */
-	int (*allow_rtp_remote)(struct ast_channel *chan1, struct ast_rtp_instance *instance);
+	int (*allow_rtp_remote)(struct ast_channel *chan1, struct ast_channel *chan2);
 	/*!
 	 * \brief Callback for retrieving the RTP instance carrying video
 	 * \note This function increases the reference count on the returned RTP instance.
@@ -614,9 +546,10 @@ struct ast_rtp_glue {
 	/*!
 	 * \brief Used to prevent two channels from remotely bridging video rtp if the channel tech has a
 	 *        reason for prohibiting it based on qualities that need to be compared from both channels.
+	 * \note This function should only be called with two channels of the same technology
 	 * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, this function is not used.
 	 */
-	int (*allow_vrtp_remote)(struct ast_channel *chan1, struct ast_rtp_instance *instance);
+	int (*allow_vrtp_remote)(struct ast_channel *chan1, struct ast_channel *chan2);
 
 	/*!
 	 * \brief Callback for retrieving the RTP instance carrying text
@@ -625,24 +558,14 @@ struct ast_rtp_glue {
 	enum ast_rtp_glue_result (*get_trtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance);
 	/*! Callback for updating the destination that the remote side should send RTP to */
 	int (*update_peer)(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active);
-	/*! Callback for retrieving codecs that the channel can do.  Result returned in result_cap*/
+	/*! Callback for retrieving codecs that the channel can do.  Result returned in result_cap.
+	 * \note The channel chan will be locked during this call.
+	 */
 	void (*get_codec)(struct ast_channel *chan, struct ast_format_cap *result_cap);
 	/*! Linked list information */
 	AST_RWLIST_ENTRY(ast_rtp_glue) entry;
 };
 
-/*!
- * \brief Allocation routine for \ref ast_rtp_payload_type
- *
- * \retval NULL on error
- * \retval An ao2 ref counted \c ast_rtp_payload_type on success.
- *
- * \note The \c ast_rtp_payload_type returned by this function is an
- *       ao2 ref counted object.
- *
- */
-struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void);
-
 #define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, ast_module_info->self)
 
 /*!
@@ -897,6 +820,29 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r
  */
 int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address);
 
+
+/*!
+ * \brief Set the address of an an alternate RTP address to receive from
+ *
+ * \param instance The RTP instance to change the address on
+ * \param address Address to set it to
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_rtp_instance_set_alt_remote_address(instance, &address);
+ * \endcode
+ *
+ * This changes the alternate remote address that RTP will be sent to on instance to the address given in the sin
+ * structure.
+ *
+ * \since 1.8
+ */
+int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address);
+
 /*!
  * \brief Set the address that we are expecting to receive RTP on
  *
@@ -1138,6 +1084,25 @@ void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs);
 void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
 
 /*!
+ * \brief Set payload information on an RTP instance to the default
+ *
+ * \param codecs The codecs structure to set defaults on
+ * \param instance Optionally the instance that the codecs structure belongs to
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_rtp_codecs codecs;
+ * ast_rtp_codecs_payloads_default(&codecs, NULL);
+ * \endcode
+ *
+ * This sets the default payloads on the codecs structure.
+ *
+ * \since 1.8
+ */
+void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
+
+/*!
  * \brief Copy payload information from one RTP instance to another
  *
  * \param src The source codecs structure
@@ -1251,36 +1216,20 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
  * \param codecs Codecs structure to look in
  * \param payload Numerical payload to look up
  *
- * \retval Payload information.
- * \retval NULL if payload does not exist.
- *
- * \note The payload returned by this function has its reference count increased.
- *       Callers are responsible for decrementing the reference count.
+ * \retval Payload information
  *
  * Example usage:
  *
  * \code
- * struct ast_rtp_payload_type *payload_type;
- * payload_type = ast_rtp_codecs_get_payload(&codecs, 0);
+ * struct ast_rtp_payload_type payload_type;
+ * payload_type = ast_rtp_codecs_payload_lookup(&codecs, 0);
  * \endcode
  *
  * This looks up the information for payload '0' from the codecs structure.
- */
-struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload);
-
-/*!
- * \brief Update the format associated with a payload in a codecs structure
- *
- * \param codecs Codecs structure to operate on
- * \param payload Numerical payload to look up
- * \param format The format to replace the existing one
  *
- * \retval 0 success
- * \retval -1 failure
- *
- * \since 13
+ * \since 1.8
  */
-int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format);
+struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload);
 
 /*!
  * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload
@@ -1291,39 +1240,15 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay
  * \retval pointer to format structure on success
  * \retval NULL on failure
  *
- * \note The format returned by this function has its reference count increased.
- *       Callers are responsible for decrementing the reference count.
- *
  * \since 10.0
  */
 struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload);
 
 /*!
- * \brief Set the framing used for a set of codecs
- *
- * \param codecs Codecs structure to set framing on
- * \param framing The framing value to set on the codecs
- *
- * \since 13.0.0
- */
-void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing);
-
-/*!
- * \brief Get the framing used for a set of codecs
- *
- * \param codecs Codecs structure to get the framing from
- *
- * \retval The framing to be used for the media stream associated with these codecs
- *
- * \since 13.0.0
- */
-unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs);
-
-/*!
  * \brief Get the sample rate associated with known RTP payload types
  *
  * \param asterisk_format True if the value in format is to be used.
- * \param format An asterisk format
+ * \param An asterisk format
  * \param code from AST_RTP list
  *
  * \return the sample rate if the format was found, zero if it was not found
@@ -1435,8 +1360,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
  * char buf[256] = "";
  * struct ast_format tmp_fmt;
  * struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
- * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0));
- * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
+ * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0));
+ * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
  * char *mime = ast_rtp_lookup_mime_multiple2(&buf, sizeof(buf), cap, 0, 1, 0);
  * ast_format_cap_destroy(cap);
  * \endcode
@@ -1448,6 +1373,25 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
 char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *ast_format_capability, int rtp_capability, const int asterisk_format, enum ast_rtp_options options);
 
 /*!
+ * \brief Set codec packetization preferences
+ *
+ * \param codecs Codecs structure to muck with
+ * \param instance Optionally the instance that the codecs structure belongs to
+ * \param prefs Codec packetization preferences
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_rtp_codecs_packetization_set(&codecs, NULL, &prefs);
+ * \endcode
+ *
+ * This sets the packetization preferences pointed to by prefs on the codecs structure pointed to by codecs.
+ *
+ * \since 1.8
+ */
+void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs);
+
+/*!
  * \brief Begin sending a DTMF digit
  *
  * \param instance The RTP instance to send the DTMF on
@@ -1651,28 +1595,22 @@ int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp);
 struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type);
 
 /*!
- * \brief Get the unique ID of the channel that owns this RTP instance
- *
- * Note that this should remain valid for the lifetime of the RTP instance.
- *
- * \param instance The RTP instance
+ * \brief Bridge two channels that use RTP instances
  *
- * \retval The unique ID of the channel
- * \retval Empty string if no channel owns this RTP instance
+ * \param c0 First channel part of the bridge
+ * \param c1 Second channel part of the bridge
+ * \param flags Bridging flags
+ * \param fo If a frame needs to be passed up it is stored here
+ * \param rc Channel that passed the above frame up
+ * \param timeoutms How long the channels should be bridged for
  *
- * \since 12
- */
-const char *ast_rtp_instance_get_channel_id(struct ast_rtp_instance *instance);
-
-/*!
- * \brief Set the channel that owns this RTP instance
+ * \retval Bridge result
  *
- * \param instance The RTP instance
- * \param uniqueid The uniqueid of the channel
+ * \note This should only be used by channel drivers in their technology declaration.
  *
- * \since 12
+ * \since 1.8
  */
-void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid);
+enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 
 /*!
  * \brief Get the other RTP instance that an instance is bridged to
@@ -1695,16 +1633,6 @@ void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const ch
 struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance);
 
 /*!
- * \brief Set the other RTP instance that an instance is bridged to
- *
- * \param instance The RTP instance that we want to set the bridged value on
- * \param bridged The RTP instance they are bridged to
- *
- * \since 12
- */
-void ast_rtp_instance_set_bridged(struct ast_rtp_instance *instance, struct ast_rtp_instance *bridged);
-
-/*!
  * \brief Make two channels compatible for early bridging
  *
  * \param c_dst Destination channel to copy to
@@ -1787,8 +1715,6 @@ int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp
  * \param chan Channel to set the statistics on
  * \param instance The RTP instance that statistics will be retrieved from
  *
- * \note Absolutely _NO_ channel locks should be held before calling this function.
- *
  * Example usage:
  *
  * \code
@@ -1991,7 +1917,7 @@ void ast_rtp_instance_set_hold_timeout(struct ast_rtp_instance *instance, int ti
  * \brief Set the RTP keepalive interval
  *
  * \param instance The RTP instance
- * \param timeout Value to set the keepalive interval to
+ * \param period Value to set the keepalive interval to
  *
  * Example usage:
  *
@@ -2101,6 +2027,27 @@ struct ast_rtp_engine *ast_rtp_instance_get_engine(struct ast_rtp_instance *inst
 struct ast_rtp_glue *ast_rtp_instance_get_active_glue(struct ast_rtp_instance *instance);
 
 /*!
+ * \brief Get the channel that is associated with an RTP instance while in a bridge
+ *
+ * \param instance The RTP instance
+ *
+ * \retval pointer to the channel
+ *
+ * Example:
+ *
+ * \code
+ * struct ast_channel *chan = ast_rtp_instance_get_chan(instance);
+ * \endcode
+ *
+ * This gets the channel associated with the RTP instance pointed to by 'instance'.
+ *
+ * \note This will only return a channel while in a local or remote bridge.
+ *
+ * \since 1.8
+ */
+struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance);
+
+/*!
  * \brief Send a comfort noise packet to the RTP instance
  *
  * \param instance The RTP instance
@@ -2134,12 +2081,12 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance);
 
 /*! \brief Custom formats declared in codecs.conf at startup must be communicated to the rtp_engine
  * so their mime type can payload number can be initialized. */
-int ast_rtp_engine_load_format(struct ast_format *format);
+int ast_rtp_engine_load_format(const struct ast_format *format);
 
 /*! \brief Formats requiring the use of a format attribute interface must have that
  * interface registered in order for the rtp engine to handle it correctly.  If an
  * attribute interface is unloaded, this function must be called to notify the rtp_engine. */
-int ast_rtp_engine_unload_format(struct ast_format *format);
+int ast_rtp_engine_unload_format(const struct ast_format *format);
 
 /*!
  * \brief Obtain a pointer to the ICE support present on an RTP instance
@@ -2188,62 +2135,6 @@ void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rt
  */
 void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg);
 
-struct ast_json;
-
-/*!
- * \brief Allocate an ao2 ref counted instance of \ref ast_rtp_rtcp_report
- *
- * \param report_blocks The number of report blocks to allocate
- * \retval An ao2 ref counted \ref ast_rtp_rtcp_report object on success
- * \retval NULL on error
- */
-struct ast_rtp_rtcp_report *ast_rtp_rtcp_report_alloc(unsigned int report_blocks);
-
-/*!
- * \since 12
- * \brief Publish an RTCP message to \ref stasis
- *
- * \param rtp The rtp instance object
- * \param message_type The RTP message type to publish
- * \param report The RTCP report object to publish. This should be an ao2 ref counted
- *  object. This routine will increase the reference count of the object.
- * \param blob Additional JSON objects to publish along with the RTCP information
- */
-void ast_rtp_publish_rtcp_message(struct ast_rtp_instance *rtp,
-		struct stasis_message_type *message_type,
-		struct ast_rtp_rtcp_report *report,
-		struct ast_json *blob);
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \since 12
- * \brief Message type for an RTCP message sent from this Asterisk instance
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_rtp_rtcp_sent_type(void);
-
-/*!
- * \since 12
- * \brief Message type for an RTCP message received from some external source
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_rtp_rtcp_received_type(void);
-
-/*!
- * \since 12
- * \brief \ref stasis topic for RTP and RTCP related messages
- *
- * \retval A \ref stasis topic
- */
-struct stasis_topic *ast_rtp_topic(void);
-
-/* }@ */
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/include/asterisk/say.h b/include/asterisk/say.h
index 93c525d..fac606a 100644
--- a/include/asterisk/say.h
+++ b/include/asterisk/say.h
@@ -148,23 +148,13 @@ SAY_EXTERN int (* ast_say_digit_str_full)(struct ast_channel *chan, const char *
  */
 SAY_EXTERN int (* ast_say_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_full);
 
-/*!
- * \brief Controls how ast_say_character_str denotes the case of characters in a string
- */
-enum ast_say_case_sensitivity {
-	AST_SAY_CASE_NONE,  /*!< Do not distinguish case on any letters */
-	AST_SAY_CASE_LOWER, /*!< Denote case only on lower case letters, upper case is assumed otherwise */
-	AST_SAY_CASE_UPPER, /*!< Denote case only on upper case letters, lower case is assumed otherwise */
-	AST_SAY_CASE_ALL,   /*!< Denote case on all letters, upper and lower */
-};
-
 /*! \brief
  * function to pronounce character and phonetic strings
  */
 int ast_say_character_str(struct ast_channel *chan, const char *num,
-	const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity);
+	const char *ints, const char *lang);
 
-SAY_EXTERN int (* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full);
+SAY_EXTERN int (* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full);
 
 int ast_say_phonetic_str(struct ast_channel *chan, const char *num,
 	const char *ints, const char *lang);
diff --git a/include/asterisk/sched.h b/include/asterisk/sched.h
index 67dbf21..256d067 100644
--- a/include/asterisk/sched.h
+++ b/include/asterisk/sched.h
@@ -165,11 +165,22 @@ void ast_sched_context_destroy(struct ast_sched_context *c);
  * A scheduler callback takes a pointer with callback data and
  *
  * \retval 0 if the callback should not be rescheduled
- * \retval non-zero if the callback should be scheduled again
+ * \retval non-zero if the callback should be scheduled agai
  */
 typedef int (*ast_sched_cb)(const void *data);
 #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
 
+/*!
+ * \brief Clean all scheduled events with matching callback.
+ *
+ * \param con Scheduler Context
+ * \param match Callback to match
+ * \param cleanup_cb Callback to run
+ *
+ * \note The return of cleanup_cb is ignored. No events are rescheduled.
+ */
+void ast_sched_clean_by_callback(struct ast_sched_context *con, ast_sched_cb match, ast_sched_cb cleanup_cb);
+
 struct ast_cb_names {
 	int numassocs;
 	char *list[10];
diff --git a/include/asterisk/sdp_srtp.h b/include/asterisk/sdp_srtp.h
deleted file mode 100644
index 772c3c3..0000000
--- a/include/asterisk/sdp_srtp.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2006 - 2007, Mikael Magnusson
- *
- * Mikael Magnusson <mikma at users.sourceforge.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file sdp_srtp.h
- *
- * \brief SRTP and SDP Security descriptions
- *
- * Specified in RFC 4568
- * Specified in RFC 3711
- *
- * \author Mikael Magnusson <mikma at users.sourceforge.net>
- */
-
-#ifndef _SDP_SRTP_H
-#define _SDP_SRTP_H
-
-#include <asterisk/rtp_engine.h>
-
-struct ast_sdp_crypto;
-
-/*! \brief structure for secure RTP audio */
-struct ast_sdp_srtp {
-	unsigned int flags;
-	struct ast_sdp_crypto *crypto;
-};
-
-/* SRTP flags */
-#define AST_SRTP_CRYPTO_OFFER_OK	(1 << 1)
-#define AST_SRTP_CRYPTO_TAG_32		(1 << 2)
-#define AST_SRTP_CRYPTO_TAG_80		(1 << 3)
-
-/*!
- * \brief allocate a ast_sdp_srtp structure
- * \retval a new malloc'd ast_sdp_srtp structure on success
- * \retval NULL on failure
-*/
-struct ast_sdp_srtp *ast_sdp_srtp_alloc(void);
-
-/*!
- * \brief free a ast_sdp_srtp structure
- * \param srtp a ast_sdp_srtp structure
-*/
-void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp);
-
-/*! \brief Initialize an return an ast_sdp_crypto struct
- *
- * \details
- * This function allocates a new ast_sdp_crypto struct and initializes its values
- *
- * \retval NULL on failure
- * \retval a pointer to a  new ast_sdp_crypto structure
- */
-struct ast_sdp_crypto *ast_sdp_crypto_alloc(void);
-
-/*! \brief Destroy a previously allocated ast_sdp_crypto struct */
-void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto);
-
-/*! \brief Parse the a=crypto line from SDP and set appropriate values on the
- * ast_sdp_crypto struct.
- *
- * The attribute line should already have "a=crypto:" removed.
- *
- * \param p A valid ast_sdp_crypto struct
- * \param attr the a:crypto line from SDP
- * \param rtp The rtp instance associated with the SDP being parsed
- * \param srtp SRTP structure
- *
- * \retval 0 success
- * \retval nonzero failure
- */
-int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr);
-
-/*! \brief Generate an SRTP a=crypto offer
- *
- * \details
- * The offer is stored on the ast_sdp_crypto struct in a_crypto
- *
- * \param p A valid ast_sdp_crypto struct
- * \param taglen Length
- *
- * \retval 0 success
- * \retval nonzero failure
- */
-int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen);
-
-
-/*! \brief Get the crypto attribute line for the srtp structure
- *
- * The attribute line does not contain the initial "a=crypto:" and does
- * not terminate with "\r\n".
- *
- * \param srtp The ast_sdp_srtp structure for which to get an attribute line
- * \param dtls_enabled Whether this connection is encrypted with datagram TLS
- * \param default_taglen_32 Whether to default to a tag length of 32 instead of 80
- *
- * \retval An attribute line containing cryptographic information
- * \retval NULL if the srtp structure does not require an attribute line containing crypto information
- */
-const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32);
-
-/*! \brief Get the RTP profile in use by a media session
- *
- * \param sdes_active Whether the media session is using SDES-SRTP
- * \param instance The RTP instance associated with this media session
- * \param using_avpf Whether the media session is using early feedback (AVPF)
- * \param force_avp Force SAVP or SAVPF profile when DTLS is in use
- *
- * \retval A non-allocated string describing the profile in use (does not need to be freed)
- */
-char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf,
-	unsigned int force_avp);
-#endif	/* _SDP_CRYPTO_H */
diff --git a/include/asterisk/security_events.h b/include/asterisk/security_events.h
index 547b547..461b671 100644
--- a/include/asterisk/security_events.h
+++ b/include/asterisk/security_events.h
@@ -57,36 +57,6 @@ struct ast_security_event_ie_type {
 };
 
 /*!
- * \brief A \ref stasis_topic which publishes messages for security related issues.
- * \since 12
- *
- * \retval \ref stasis_topic for security related issues.
- * \retval NULL on error
- */
-struct stasis_topic *ast_security_topic(void);
-
-/*!
- * \brief A \ref stasis_message_type for security events
- * \since 12
- *
- * \retval NULL on error
- * \retval \ref stasis_message_type for security events
- *
- * \note Messages of this type should always be issued on and expected from
- *       the \ref ast_security_topic \ref stasis_topic
- */
-struct stasis_message_type *ast_security_event_type(void);
-
-/*!
- * \brief initializes stasis topic/event types for \ref ast_security_topic and \ref ast_security_event_type
- * \since 12
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_security_stasis_init(void);
-
-/*!
  * \brief Get the list of required IEs for a given security event sub-type
  *
  * \param[in] event_type security event sub-type
diff --git a/include/asterisk/security_events_defs.h b/include/asterisk/security_events_defs.h
index 30a7136..c73eb29 100644
--- a/include/asterisk/security_events_defs.h
+++ b/include/asterisk/security_events_defs.h
@@ -28,7 +28,6 @@
 #define __AST_SECURITY_EVENTS_DEFS_H__
 
 #include "asterisk/network.h"
-#include "asterisk/netsock2.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -36,6 +35,11 @@ extern "C" {
 
 /*!
  * \brief Security event types
+ *
+ * AST_EVENT_SECURITY is the event type of an ast_event generated as a security
+ * event.  The event will have an information element of type
+ * AST_EVENT_IE_SECURITY_EVENT which identifies the security event sub-type.
+ * This enum defines the possible values for this sub-type.
  */
 enum ast_security_event_type {
 	/*!
@@ -136,11 +140,20 @@ enum ast_security_event_severity {
 	AST_SECURITY_EVENT_SEVERITY_ERROR = (1 << 1),
 };
 
+/*!
+ * \brief Transport types
+ */
+enum ast_security_event_transport_type {
+	AST_SECURITY_EVENT_TRANSPORT_UDP,
+	AST_SECURITY_EVENT_TRANSPORT_TCP,
+	AST_SECURITY_EVENT_TRANSPORT_TLS,
+};
+
 #define AST_SEC_EVT(e) ((struct ast_security_event_common *) e)
 
 struct ast_security_event_ip_addr {
 	const struct ast_sockaddr *addr;
-	enum ast_transport transport;
+	enum ast_security_event_transport_type transport;
 };
 
 /*!
diff --git a/include/asterisk/sem.h b/include/asterisk/sem.h
deleted file mode 100644
index 8f6356c..0000000
--- a/include/asterisk/sem.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef ASTERISK_SEMAPHORE_H
-#define ASTERISK_SEMAPHORE_H
-
-/*!
- * \file Asterisk semaphore API
- *
- * This API is a thin wrapper around the POSIX semaphore API (when available),
- * so see the POSIX documentation for further details.
- */
-
-#ifdef HAS_WORKING_SEMAPHORE
-/* Working semaphore implementation detected */
-
-#include <semaphore.h>
-
-struct ast_sem {
-	sem_t real_sem;
-};
-
-#define AST_SEM_VALUE_MAX SEM_VALUE_MAX
-
-/* These are thin wrappers; might as well inline them */
-
-static force_inline int ast_sem_init(struct ast_sem *sem, int pshared, unsigned int value)
-{
-	return sem_init(&sem->real_sem, pshared, value);
-}
-
-static force_inline int ast_sem_destroy(struct ast_sem *sem)
-{
-	return sem_destroy(&sem->real_sem);
-}
-
-static force_inline int ast_sem_post(struct ast_sem *sem)
-{
-	return sem_post(&sem->real_sem);
-}
-
-static force_inline int ast_sem_wait(struct ast_sem *sem)
-{
-	return sem_wait(&sem->real_sem);
-}
-
-static force_inline int ast_sem_getvalue(struct ast_sem *sem, int *sval)
-{
-	return sem_getvalue(&sem->real_sem, sval);
-}
-
-#else
-/* Unnamed semaphores don't work. Rolling our own, I guess... */
-
-#include "asterisk/lock.h"
-
-#include <limits.h>
-
-struct ast_sem {
-	/*! Current count of this semaphore */
-	int count;
-	/*! Number of threads currently waiting for this semaphore */
-	int waiters;
-	/*! Mutual exclusion */
-	ast_mutex_t mutex;
-	/*! Condition for singalling waiters */
-	ast_cond_t cond;
-};
-
-#define AST_SEM_VALUE_MAX INT_MAX
-
-/*!
- * \brief Initialize a semaphore.
- *
- * \param sem Semaphore to initialize.
- * \param pshared Pass true (nonzero) to share this thread between processes.
- *                Not be supported on all platforms, so be wary!
- *                But leave the parameter, to be compatible with the POSIX ABI
- *                in case we need to add support in the future.
- * \param value Initial value of the semaphore.
- *
- * \return 0 on success.
- * \return -1 on error, errno set to indicate error.
- */
-int ast_sem_init(struct ast_sem *sem, int pshared, unsigned int value);
-
-/*!
- * \brief Destroy a semaphore.
- *
- * Destroying a semaphore that other threads are currently blocked on produces
- * undefined behavior.
- *
- * \param sem Semaphore to destroy.
- *
- * \return 0 on success.
- * \return -1 on error, errno set to indicate error.
- */
-int ast_sem_destroy(struct ast_sem *sem);
-
-/*!
- * \brief Increments the semaphore, unblocking a waiter if necessary.
- *
- * \param sem Semaphore to increment.
- *
- * \return 0 on success.
- * \return -1 on error, errno set to indicate error.
- */
-int ast_sem_post(struct ast_sem *sem);
-
-/*!
- * \brief Decrements the semaphore.
- *
- * If the semaphore's current value is zero, this function blocks until another
- * thread posts (ast_sem_post()) to the semaphore (or is interrupted by a signal
- * handler, which sets errno to EINTR).
- *
- * \param sem Semaphore to decrement.
- *
- * \return 0 on success.
- * \return -1 on error, errno set to indicate error.
- */
-int ast_sem_wait(struct ast_sem *sem);
-
-/*!
- * \brief Gets the current value of the semaphore.
- *
- * If threads are blocked on this semaphore, POSIX allows the return value to be
- * either 0 or a negative number whose absolute value is the number of threads
- * blocked. Don't assume that it will give you one or the other; Asterisk has
- * been ported to just about everything.
- *
- * \param sem Semaphore to query.
- * \param[out] sval Output value.
- *
- * \return 0 on success.
- * \return -1 on error, errno set to indicate error.
- */
-int ast_sem_getvalue(struct ast_sem *sem, int *sval);
-
-#endif
-
-#endif /* ASTERISK_SEMAPHORE_H */
diff --git a/include/asterisk/sip_api.h b/include/asterisk/sip_api.h
index 2b8a3f2..89d7389 100644
--- a/include/asterisk/sip_api.h
+++ b/include/asterisk/sip_api.h
@@ -39,10 +39,9 @@ struct ast_sip_api_tech {
 /*!
  * \brief Send a customized SIP INFO request
  *
- * \param chan Channel
  * \param headers The headers to add to the INFO request
  * \param content_type The content type header to add
- * \param content The body of the INFO request
+ * \param conten The body of the INFO request
  * \param useragent_filter If non-NULL, only send the INFO if the
  * recipient's User-Agent contains useragent_filter as a substring
  *
diff --git a/include/asterisk/slin.h b/include/asterisk/slin.h
index 148ee09..e9971a7 100644
--- a/include/asterisk/slin.h
+++ b/include/asterisk/slin.h
@@ -62,7 +62,7 @@ static inline struct ast_frame *slin8_sample(void)
 {
 	static struct ast_frame f = {
 		.frametype = AST_FRAME_VOICE,
-		.datalen = sizeof(ex_slin8) * 2,
+		.datalen = sizeof(ex_slin8),
 		.samples = ARRAY_LEN(ex_slin8),
 		.mallocd = 0,
 		.offset = 0,
@@ -70,8 +70,7 @@ static inline struct ast_frame *slin8_sample(void)
 		.data.ptr = ex_slin8,
 	};
 
-	f.subclass.format = ast_format_slin;
-
+	ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
 	return &f;
 }
 
@@ -79,7 +78,7 @@ static inline struct ast_frame *slin16_sample(void)
 {
 	static struct ast_frame f = {
 		.frametype = AST_FRAME_VOICE,
-		.datalen = sizeof(ex_slin16) * 2,
+		.datalen = sizeof(ex_slin16),
 		.samples = ARRAY_LEN(ex_slin16),
 		.mallocd = 0,
 		.offset = 0,
@@ -87,7 +86,6 @@ static inline struct ast_frame *slin16_sample(void)
 		.data.ptr = ex_slin16,
 	};
 
-	f.subclass.format = ast_format_slin16;
-
+	ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR16, 0);
 	return &f;
 }
diff --git a/include/asterisk/slinfactory.h b/include/asterisk/slinfactory.h
index 9a8ceae..324c0ae 100644
--- a/include/asterisk/slinfactory.h
+++ b/include/asterisk/slinfactory.h
@@ -39,8 +39,8 @@ struct ast_slinfactory {
 	short *offset;                           /*!< Offset into the hold where audio begins */
 	size_t holdlen;                          /*!< Number of samples currently in the hold */
 	unsigned int size;                       /*!< Number of samples currently in the factory */
-	struct ast_format *format;               /*!< Current format the translation path is converting from */
-	struct ast_format *output_format;        /*!< The output format desired */
+	struct ast_format format;                /*!< Current format the translation path is converting from */
+	struct ast_format output_format;         /*!< The output format desired */
 };
 
 /*!
@@ -60,7 +60,7 @@ void ast_slinfactory_init(struct ast_slinfactory *sf);
  *
  * \return 0 on success, non-zero on failure
  */
-int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out);
+int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, const struct ast_format *slin_out);
 
 /*!
  * \brief Destroy the contents of a slinfactory
diff --git a/include/asterisk/smdi.h b/include/asterisk/smdi.h
index c3a5c7e..090470d 100644
--- a/include/asterisk/smdi.h
+++ b/include/asterisk/smdi.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Copyright (C) 2005-2008, Digium, Inc.
  *
@@ -24,6 +24,10 @@
  * \author Russell Bryant <russell at digium.com>
  */
 
+
+/* C is simply a ego booster for those who want to do objects the hard way. */
+
+
 #ifndef ASTERISK_SMDI_H
 #define ASTERISK_SMDI_H
 
@@ -32,9 +36,9 @@
 
 #include "asterisk/config.h"
 #include "asterisk/module.h"
+#include "asterisk/astobj.h"
 #include "asterisk/optional_api.h"
 
-#define SMDI_MESG_NAME_LEN 80
 #define SMDI_MESG_DESK_NUM_LEN 3
 #define SMDI_MESG_DESK_TERM_LEN 4
 #define SMDI_MWI_FAIL_CAUSE_LEN 3
@@ -49,7 +53,7 @@
  * ast_smdi_mwi_message structures. 
  */
 struct ast_smdi_mwi_message {
-	char name[SMDI_MESG_NAME_LEN];
+	ASTOBJ_COMPONENTS(struct ast_smdi_mwi_message);
 	char fwd_st[SMDI_MAX_STATION_NUM_LEN + 1];		/* forwarding station number */
 	char cause[SMDI_MWI_FAIL_CAUSE_LEN + 1];		/* the type of failure */
 	struct timeval timestamp;				/* a timestamp for the message */
@@ -63,7 +67,7 @@ struct ast_smdi_mwi_message {
  * ast_smdi_md_message structures. 
  */
 struct ast_smdi_md_message {
-	char name[SMDI_MESG_NAME_LEN];
+	ASTOBJ_COMPONENTS(struct ast_smdi_md_message);
 	char mesg_desk_num[SMDI_MESG_DESK_NUM_LEN + 1];		/* message desk number */
 	char mesg_desk_term[SMDI_MESG_DESK_TERM_LEN + 1];	/* message desk terminal */
 	char fwd_st[SMDI_MAX_STATION_NUM_LEN + 1];		/* forwarding station number */
@@ -81,6 +85,10 @@ struct ast_smdi_md_message {
  */
 struct ast_smdi_interface;
 
+AST_OPTIONAL_API(void, ast_smdi_interface_unref,
+		 (struct ast_smdi_interface *iface),
+		 { return; });
+
 /*! 
  * \brief Get the next SMDI message from the queue.
  * \param iface a pointer to the interface to use.
@@ -112,6 +120,19 @@ AST_OPTIONAL_API(struct ast_smdi_md_message *, ast_smdi_md_message_wait,
 		 { return NULL; });
 
 /*!
+ * \brief Put an SMDI message back in the front of the queue.
+ * \param iface a pointer to the interface to use.
+ * \param msg a pointer to the message to use.
+ *
+ * This function puts a message back in the front of the specified queue.  It
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+AST_OPTIONAL_API(void, ast_smdi_md_message_putback,
+		 (struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg),
+		 { return; });
+
+/*!
  * \brief Get the next SMDI message from the queue.
  * \param iface a pointer to the interface to use.
  *
@@ -146,10 +167,25 @@ AST_OPTIONAL_API(struct ast_smdi_mwi_message *, ast_smdi_mwi_message_wait_statio
 		 { return NULL; });
 
 /*!
+ * \brief Put an SMDI message back in the front of the queue.
+ * \param iface a pointer to the interface to use.
+ * \param msg a pointer to the message to use.
+ *
+ * This function puts a message back in the front of the specified queue.  It
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+AST_OPTIONAL_API(void, ast_smdi_mwi_message_putback,
+		 (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg),
+		 { return; });
+
+/*!
  * \brief Find an SMDI interface with the specified name.
  * \param iface_name the name/port of the interface to search for.
  *
- * \return an ao2 reference to the interface located or NULL if none was found.
+ * \return a pointer to the interface located or NULL if none was found.  This
+ * actually returns an ASTOBJ reference and should be released using
+ * #ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).
  */
 AST_OPTIONAL_API(struct ast_smdi_interface *, ast_smdi_interface_find,
 		 (const char *iface_name),
@@ -173,4 +209,14 @@ AST_OPTIONAL_API(int, ast_smdi_mwi_unset,
 		 (struct ast_smdi_interface *iface, const char *mailbox),
 		 { return -1; });
 
+/*! \brief ast_smdi_md_message destructor. */
+AST_OPTIONAL_API(void, ast_smdi_md_message_destroy,
+		 (struct ast_smdi_md_message *msg),
+		 { return; });
+
+/*! \brief ast_smdi_mwi_message destructor. */
+AST_OPTIONAL_API(void, ast_smdi_mwi_message_destroy,
+		 (struct ast_smdi_mwi_message *msg),
+		 { return; });
+
 #endif /* !ASTERISK_SMDI_H */
diff --git a/include/asterisk/smoother.h b/include/asterisk/smoother.h
deleted file mode 100644
index e63aa77..0000000
--- a/include/asterisk/smoother.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Asterisk internal frame definitions.
- * \arg For an explanation of frames, see \ref Def_Frame
- * \arg Frames are send of Asterisk channels, see \ref Def_Channel
- */
-
-#ifndef _ASTERISK_SMOOTHER_H
-#define _ASTERISK_SMOOTHER_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/endian.h"
-
-#define AST_SMOOTHER_FLAG_G729		(1 << 0)
-#define AST_SMOOTHER_FLAG_BE		(1 << 1)
-
-/*! \name AST_Smoother
-*/
-/*@{ */
-/*! \page ast_smooth The AST Frame Smoother
-The ast_smoother interface was designed specifically
-to take frames of variant sizes and produce frames of a single expected
-size, precisely what you want to do.
-
-The basic interface is:
-
-- Initialize with ast_smoother_new()
-- Queue input frames with ast_smoother_feed()
-- Get output frames with ast_smoother_read()
-- when you're done, free the structure with ast_smoother_free()
-- Also see ast_smoother_test_flag(), ast_smoother_set_flags(), ast_smoother_get_flags(), ast_smoother_reset()
-*/
-struct ast_smoother;
-
-struct ast_frame;
-
-struct ast_smoother *ast_smoother_new(int bytes);
-void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
-int ast_smoother_get_flags(struct ast_smoother *smoother);
-int ast_smoother_test_flag(struct ast_smoother *s, int flag);
-void ast_smoother_free(struct ast_smoother *s);
-void ast_smoother_reset(struct ast_smoother *s, int bytes);
-
-/*!
- * \brief Reconfigure an existing smoother to output a different number of bytes per frame
- * \param s the smoother to reconfigure
- * \param bytes the desired number of bytes per output frame
- * \return nothing
- *
- */
-void ast_smoother_reconfigure(struct ast_smoother *s, int bytes);
-
-int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
-struct ast_frame *ast_smoother_read(struct ast_smoother *s);
-#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0)
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1)
-#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0)
-#else
-#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0)
-#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1)
-#endif
-/*@} Doxygen marker */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_SMOOTHER_H */
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
deleted file mode 100644
index 874dac2..0000000
--- a/include/asterisk/sorcery.h
+++ /dev/null
@@ -1,1167 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Sorcery Data Access Layer API
- * \author Joshua Colp <jcolp at digium.com>
- * \ref AstSorcery
- */
-
-/*!
- * \page AstSorcery Data Access Layer API
- *
- * Sorcery is a unifying data access layer which utilizes the configuration framework,
- * realtime, and astdb to allow object creation, retrieval, updating, and deletion.
- *
- * \par Initialization
- *
- * Usage of sorcery is accomplished by first opening a sorcery structure. This structure holds
- * all information about the object types, object fields, and object mappings. All API functions
- * require the sorcery structure to operate. When sorcery is no longer needed the structure can
- * be unreferenced using \ref ast_sorcery_unref
- *
- * Once opened the sorcery structure must have object mappings applied to it. This maps the
- * object types to their respective wizards (object storage modules). If the developer would like
- * to allow the user to configure this using the sorcery.conf configuration file the
- * \ref ast_sorcery_apply_config API call can be used to read in the configuration file and apply the
- * mappings. \ref ast_sorcery_open will automatically call \ref ast_sorcery_apply_config to allow
- * for configuration of objects using the same category name as the module that is opening the
- * sorcery instance. Direct calls to \ref ast_sorcery_apply_config should only be performed if a
- * module wishes to allow for additional configuration sections in sorcery.conf to be used.
- * If the storage of the object types are such that a default wizard can be used this can
- * be applied using the \ref ast_sorcery_apply_default API call. Note that the default mappings will not
- * override configured mappings. They are only used in the case where no configured mapping exists.
- *
- * Configuring object mappings implicitly creates a basic version of an object type. The object type
- * must be fully registered, however, using the \ref ast_sorcery_object_register API call before any
- * objects of the type can be allocated, created, or retrieved.
- *
- * Once the object type itself has been fully registered the individual fields within the object must
- * be registered using the \ref ast_sorcery_object_field_register API call. Note that not all fields *need*
- * be registered. Only fields that should be accessible using the sorcery API have to be registered.
- *
- * \par Creating Objects
- *
- * Before an object can be created within the sorcery API it must first be allocated using the
- * \ref ast_sorcery_alloc API call. This allocates a new instance of the object, sets sorcery specific
- * details, and applies default values to the object. A unique identifier can optionally be specified
- * when allocating an object. If it is not provided one will be automatically generated. Allocating
- * an object does not create it within any object storage mechanisms that are configured for the
- * object type. Creation must explicitly be done using the \ref ast_sorcery_create API call. This API call
- * passes the object to each configured object storage mechanism for the object type until one
- * successfully persists the object.
- *
- * \par Retrieving Objects
- *
- * To retrieve a single object using its unique identifier the \ref ast_sorcery_retrieve_by_id API call
- * can be used.
- *
- * To retrieve potentially multiple objects using specific fields the \ref ast_sorcery_retrieve_by_fields
- * API call can be used. The behavior of this API call is controlled using different flags. If the
- * AST_RETRIEVE_FLAG_MULTIPLE flag is used a container will be returned which contains all matching objects.
- * To retrieve all objects the AST_RETRIEVE_FLAG_ALL flag can be specified. Note that when specifying this flag
- * you do not need to pass any fields.
- *
- * Both API calls return shared objects. Modification of the object can not occur until it has been copied.
- *
- * \par Updating Objects
- *
- * As retrieved objects may be shared the first step to updating the object with new details is creating a
- * copy using the \ref ast_sorcery_copy API call. This will return a new object which is specific to the caller.
- * Any field within the object may be modified as needed. Once changes are done the changes can be committed
- * using the \ref ast_sorcery_update API call. Note that as the copied object is specific to the caller it must
- * be unreferenced after use.
- *
- * \par Deleting Objects
- *
- * To delete an object simply call the \ref ast_sorcery_delete API call with an object retrieved using the
- * ast_sorcery_retrieve_by_* API calls or a copy returned from \ref ast_sorcery_copy.
- */
-
-#ifndef _ASTERISK_SORCERY_H
-#define _ASTERISK_SORCERY_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/config_options.h"
-#include "asterisk/uuid.h"
-
-/*! \brief Maximum size of an object type */
-#define MAX_OBJECT_TYPE 64
-
-/*! \brief Maximum length of an object field name */
-#define MAX_OBJECT_FIELD 128
-
-/*!
- * \brief Retrieval flags
- */
-enum ast_sorcery_retrieve_flags {
-	/*! \brief Default retrieval flags */
-	AST_RETRIEVE_FLAG_DEFAULT = 0,
-
-	/*! \brief Return all matching objects */
-	AST_RETRIEVE_FLAG_MULTIPLE = (1 << 0),
-
-	/*! \brief Perform no matching, return all objects */
-	AST_RETRIEVE_FLAG_ALL = (1 << 1),
-};
-
-/*!
- * \brief Field handler flags
- */
-enum ast_sorcery_field_handler_flags {
-	/*! \brief Try both handlers, string first */
-	AST_HANDLER_PREFER_STRING,
-
-	/*! \brief Try both handlers, list first */
-	AST_HANDLER_PREFER_LIST,
-
-	/*! \brief Use string handler only */
-	AST_HANDLER_ONLY_STRING,
-
-	/*! \brief Use list handler only */
-	AST_HANDLER_ONLY_LIST,
-};
-
-
-/*! \brief Forward declaration for the sorcery main structure and wizard structure */
-struct ast_sorcery;
-struct ast_sorcery_wizard;
-
-/*!
- * \brief A callback function for translating a value into a string
- *
- * \param obj Object to get value from
- * \param args Where the field is
- * \param buf Pointer to the buffer that the handler has created which contains the field value
- *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef int (*sorcery_field_handler)(const void *obj, const intptr_t *args, char **buf);
-
-/*!
- * \brief A callback function for translating multiple values into an ast_variable list
- *
- * \param obj Object to get values from
- * \param fields Pointer to store the list of fields
- *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef int (*sorcery_fields_handler)(const void *obj, struct ast_variable **fields);
-
-/*!
- * \brief A callback function for performing a transformation on an object set
- *
- * \param set The existing object set
- *
- * \retval non-NULL new object set if changed
- * \retval NULL if no changes present
- *
- * \note The returned ast_variable list must be *new*. You can not return the input set.
- */
-typedef struct ast_variable *(*sorcery_transform_handler)(struct ast_variable *set);
-
-/*!
- * \brief A callback function for when an object set is successfully applied to an object
- *
- * \note On a failure return, the state of the object is left undefined. It is a bad
- * idea to try to use this object.
- *
- * \param sorcery Sorcery structure in use
- * \param obj The object itself
- * \retval 0 Success
- * \retval non-zero Failure
- */
-typedef int (*sorcery_apply_handler)(const struct ast_sorcery *sorcery, void *obj);
-
-/*!
- * \brief A callback function for copying the contents of one object to another
- *
- * \param src The source object
- * \param dst The destination object
- *
- * \retval 0 success
- * \retval -1 failure
- */
-typedef int (*sorcery_copy_handler)(const void *src, void *dst);
-
-/*!
- * \brief A callback function for generating a changeset between two objects
- *
- * \param original The original object
- * \param modified The modified object
- * \param changes The changeset
- *
- * \param 0 success
- * \param -1 failure
- */
-typedef int (*sorcery_diff_handler)(const void *original, const void *modified, struct ast_variable **changes);
-
-/*! \brief Interface for the global sorcery observer */
-struct ast_sorcery_global_observer {
-	/*! \brief Callback after an instance is created */
-	void (*instance_created)(const char *name, struct ast_sorcery *sorcery);
-
-	/*! \brief Callback after an wizard is registered */
-	void (*wizard_registered)(const char *name,
-		const struct ast_sorcery_wizard *wizard);
-
-	/*! \brief Callback before an instance is destroyed */
-	void (*instance_destroying)(const char *name, struct ast_sorcery *sorcery);
-
-	/*! \brief Callback before a wizard is unregistered */
-	void (*wizard_unregistering)(const char *name,
-		const struct ast_sorcery_wizard *wizard);
-};
-
-/*! \brief Interface for the sorcery instance observer */
-struct ast_sorcery_instance_observer {
-	/*! \brief Callback before instance is loaded/reloaded */
-	void (*instance_loading)(const char *name, const struct ast_sorcery *sorcery,
-		int reloaded);
-
-	/*! \brief Callback after instance is loaded/reloaded */
-	void (*instance_loaded)(const char *name, const struct ast_sorcery *sorcery,
-		int reloaded);
-
-	/*! \brief Callback after a wizard is mapped to an object_type */
-	void (*wizard_mapped)(const char *name, struct ast_sorcery *sorcery,
-		const char *object_type, struct ast_sorcery_wizard *wizard,
-		const char *wizard_args, void *wizard_data);
-
-	/*! \brief Callback after any object_type is registered */
-	void (*object_type_registered)(const char *name, struct ast_sorcery *sorcery,
-		const char *object_type);
-
-	/*! \brief Callback before any object_type is loaded/reloaded */
-	void (*object_type_loading)(const char *name, const struct ast_sorcery *sorcery,
-		const char *object_type, int reloaded);
-
-	/*! \brief Callback after any object_type is loaded/reloaded */
-	void (*object_type_loaded)(const char *name, const struct ast_sorcery *sorcery,
-		const char *object_type, int reloaded);
-};
-
-/*! \brief Interface for the sorcery wizard observer */
-struct ast_sorcery_wizard_observer {
-	/*! \brief Callback before a wizard is loaded/reloaded for any type */
-	void (*wizard_loading)(const char *name, const struct ast_sorcery_wizard *wizard,
-		const char *object_type, int reloaded);
-
-	/*! \brief Callback after a wizard is loaded/reloaded for any type */
-	void (*wizard_loaded)(const char *name, const struct ast_sorcery_wizard *wizard,
-		const char *object_type, int reloaded);
-};
-
-/*! \brief Interface for a sorcery wizard */
-struct ast_sorcery_wizard {
-	/*! \brief Name of the wizard */
-	const char *name;
-
-	/*! \brief Pointer to the Asterisk module this wizard is implemented by */
-	struct ast_module *module;
-
-	/*! \brief Callback for opening a wizard */
-	void *(*open)(const char *data);
-
-	/*! \brief Optional callback for loading persistent objects */
-	void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
-
-	/*! \brief Optional callback for reloading persistent objects */
-	void (*reload)(void *data, const struct ast_sorcery *sorcery, const char *type);
-
-	/*! \brief Callback for creating an object */
-	int (*create)(const struct ast_sorcery *sorcery, void *data, void *object);
-
-	/*! \brief Callback for retrieving an object using an id */
-	void *(*retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
-
-	/*! \brief Callback for retrieving multiple objects using a regex on their id */
-	void (*retrieve_regex)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
-
-	/*! \brief Optional callback for retrieving an object using fields */
-	void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
-
-	/*! \brief Optional callback for retrieving multiple objects using some optional field criteria */
-	void (*retrieve_multiple)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields);
-
-	/*! \brief Callback for updating an object */
-	int (*update)(const struct ast_sorcery *sorcery, void *data, void *object);
-
-	/*! \brief Callback for deleting an object */
-	int (*delete)(const struct ast_sorcery *sorcery, void *data, void *object);
-
-	/*! \brief Callback for closing a wizard */
-	void (*close)(void *data);
-};
-
-/*! \brief Interface for a sorcery object type observer */
-struct ast_sorcery_observer {
-	/*! \brief Callback for when an object is created */
-	void (*created)(const void *object);
-
-	/*! \brief Callback for when an object is updated */
-	void (*updated)(const void *object);
-
-	/*! \brief Callback for when an object is deleted */
-	void (*deleted)(const void *object);
-
-	/*! \brief Callback for when an object type is loaded/reloaded */
-	void (*loaded)(const char *object_type);
-};
-
-/*! \brief Opaque structure for internal sorcery object */
-struct ast_sorcery_object;
-
-/*! \brief Structure which contains details about a sorcery object */
-struct ast_sorcery_object_details {
-	/*! \brief Pointer to internal sorcery object information */
-	struct ast_sorcery_object *object;
-};
-
-/*! \brief Macro which must be used at the beginning of each sorcery capable object */
-#define SORCERY_OBJECT(details)                    \
-struct {                                           \
-	struct ast_sorcery_object_details details; \
-}                                                  \
-
-/*!
- * \brief Initialize the sorcery API
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_init(void);
-
-/*!
- * \brief Register a sorcery wizard
- *
- * \param interface Pointer to a wizard interface
- * \param module Pointer to the module implementing the interface
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module);
-
-/*!
- * \brief See \ref __ast_sorcery_wizard_register()
- */
-#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, ast_module_info ? ast_module_info->self : NULL)
-
-/*!
- * \brief Unregister a sorcery wizard
- *
- * \param interface Pointer to the wizard interface
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface);
-
-/*!
- * \brief Open a new sorcery structure
- *
- * \param module The module name (AST_MODULE)
- *
- * When called, this will automatically also call __ast_sorcery_apply_config()
- * with the module name as the configuration section.
- *
- * \retval non-NULL success
- * \retval NULL if allocation failed
- */
-struct ast_sorcery *__ast_sorcery_open(const char *module);
-
-#define ast_sorcery_open() __ast_sorcery_open(AST_MODULE)
-
-/*!
- * \brief Retrieves an existing sorcery instance by module name
- *
- * \param module The module name
- *
- * \retval non-NULL success
- * \retval NULL if no instance was found
- *
- * \note The returned instance has its reference count incremented.  The caller
- * must decrement the count when they're finished with it.
- *
- */
-struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module);
-
-enum ast_sorcery_apply_result {
-	/*! Sorcery wizard failed to apply. */
-	AST_SORCERY_APPLY_FAIL = -1,
-	/*! Sorcery wizard applied successfully. */
-	AST_SORCERY_APPLY_SUCCESS = 0,
-	/*! Sorcery wizard has already been applied to the object type. */
-	AST_SORCERY_APPLY_DUPLICATE = 1,
-	/*! Default sorcery wizard is unnecessary since a wizard has already been applied to the object type. */
-	AST_SORCERY_APPLY_DEFAULT_UNNECESSARY = 2,
-	/*! No sorcery.conf configuration file was found to apply. */
-	AST_SORCERY_APPLY_NO_CONFIGURATION = 3,
-};
-
-/*!
- * \brief Apply configured wizard mappings
- *
- * \param sorcery Pointer to a sorcery structure
- * \param name Name of the category to use within the configuration file, normally the module name
- * \param module The module name (AST_MODULE)
- *
- * This function is called automatically by __ast_sorcery_open() using the module name as the
- * configuration category. The only reason you should call this function is if your module
- * wishes to apply configuration from additional sections of sorcery.conf.
- *
- * If a configuration section attempts to apply the same sorcery wizard to an object type
- * more than once, the wizard will only be applied one time.
- *
- * \return What happened when attempting to apply the config.
- */
-enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery,
-		const char *name, const char *module);
-
-#define ast_sorcery_apply_config(sorcery, name) \
-	__ast_sorcery_apply_config((sorcery), (name), AST_MODULE)
-
-/*!
- * \brief Apply default object wizard mappings
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to apply to
- * \param module The name of the module, typically AST_MODULE
- * \param name Name of the wizard to use
- * \param data Data to be passed to wizard
- *
- * \return What occurred when applying the default
- *
- * \note This should be called *after* applying configuration sourced mappings
- *
- * \note Only a single default can exist per object type
- */
-enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery,
-		const char *type, const char *module, const char *name, const char *data);
-
-#define ast_sorcery_apply_default(sorcery, type, name, data) \
-	__ast_sorcery_apply_default((sorcery), (type), AST_MODULE, (name), (data))
-
-
-/*!
- * \brief Apply additional object wizard mappings
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to apply to
- * \param module The name of the module, typically AST_MODULE
- * \param name Name of the wizard to use
- * \param data Data to be passed to wizard
- * \param caching Wizard should cache
- *
- * \return What occurred when applying the mapping
- *
- * \note This should be called *after* applying default mappings
- */
-enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
-		const char *type, const char *module, const char *name, const char *data, unsigned int caching);
-
-/*!
- * \brief Apply additional object wizard mappings
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to apply to
- * \param module The name of the module, typically AST_MODULE
- * \param name Name of the wizard to use
- * \param data Data to be passed to wizard
- *
- * \return What occurred when applying the mapping
- *
- * \note This should be called *after* applying default mappings
- */
-#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching) \
-	__ast_sorcery_apply_wizard_mapping((sorcery), (type), AST_MODULE, (name), (data), (caching));
-
-/*!
- * \brief Register an object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param hidden All objects of this type are internal and should not be manipulated by users
- * \param reloadable All objects of this type are reloadable
- * \param alloc Required object allocation callback
- * \param transform Optional transformation callback
- * \param apply Optional object set apply callback
- *
- * \note In general, this function should not be used directly. One of the various
- * macro'd versions should be used instead.
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, unsigned int hidden, unsigned int reloadable, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply);
-
-/*!
- * \brief Register an object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param alloc Required object allocation callback
- * \param transform Optional transformation callback
- * \param apply Optional object set apply callback
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply) \
-	__ast_sorcery_object_register((sorcery), (type), 0, 1, (alloc), (transform), (apply))
-
-/*!
- * \brief Register an object type that is not reloadable
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param alloc Required object allocation callback
- * \param transform Optional transformation callback
- * \param apply Optional object set apply callback
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_register_no_reload(sorcery, type, alloc, transform, apply) \
-	__ast_sorcery_object_register((sorcery), (type), 0, 0, (alloc), (transform), (apply))
-
-/*!
- * \brief Register an internal, hidden object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param alloc Required object allocation callback
- * \param transform Optional transformation callback
- * \param apply Optional object set apply callback
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply) \
-	__ast_sorcery_object_register((sorcery), (type), 1, 1, (alloc), (transform), (apply))
-
-/*!
- * \brief Set the copy handler for an object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param copy Copy handler
- */
-void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy);
-
-/*!
- * \brief Set the diff handler for an object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param diff Diff handler
- */
-void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff);
-
-/*!
- * \brief Register a regex for multiple fields within an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param regex A regular expression pattern for the fields
- * \param config_handler A custom handler for translating the string representation of the fields
- * \param sorcery_handler A custom handler for translating the native representation of the fields
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler,
-									   sorcery_fields_handler sorcery_handler);
-
-/*!
- * \brief Register a field within an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param config_handler A custom handler for translating the string representation of the fields
- * \param sorcery_handler A custom handler for translating the native representation of the fields
- * \param multiple_handler A custom handler for translating the native representation of the fields
- * \param opt_type Option type
- * \param flags Option type specific flags
- * \param no_doc Field should not be documented
- * \param alias Interpret and apply field value only
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type,
-	const char *name, const char *default_val, enum aco_option_type opt_type,
-	aco_option_handler config_handler, sorcery_field_handler sorcery_handler,
-	sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc,
-	unsigned int alias, size_t argc, ...);
-
-/*!
- * \brief Register a field within an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param opt_type Option type
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, NULL, flags, 0, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
-
-/*!
- * \brief Register a field within an object as an alias
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param opt_type Option type
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register_alias(sorcery, type, name, default_val, opt_type, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, NULL, flags, 1, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
-
-/*!
- * \brief Register a field within an object without documentation
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param opt_type Option type
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, NULL, flags, 1, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
-
-/*!
- * \brief Register a field within an object with custom handlers
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param config_handler Custom configuration handler
- * \param sorcery_handler Custom sorcery handler
- * \param multiple_handler Custom multiple handler
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, multiple_handler, flags, 0, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
-
-/*!
- * \brief Register a field within an object with custom handlers as an alias
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param config_handler Custom configuration handler
- * \param sorcery_handler Custom sorcery handler
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register_custom_alias(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, multiple_handler, flags, 1, 1, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
-
-/*!
- * \brief Register a field within an object with custom handlers without documentation
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object
- * \param name Name of the field
- * \param default_val Default value of the field
- * \param config_handler Custom configuration handler
- * \param sorcery_handler Custom sorcery handler
- * \param multiple_handler Custom multiple handler
- * \param flags Option type specific flags
- *
- * \retval 0 success
- * \retval -1 failure
- */
-#define ast_sorcery_object_field_register_custom_nodoc(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags, ...) \
-    __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, multiple_handler, flags, 1, 0, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
-
-/*!
- * \brief Inform any wizards to load persistent objects
- *
- * \param sorcery Pointer to a sorcery structure
- */
-void ast_sorcery_load(const struct ast_sorcery *sorcery);
-
-/*!
- * \brief Inform any wizards of a specific object type to load persistent objects
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Name of the object type to load
- */
-void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type);
-
-/*!
- * \brief Inform any wizards to reload persistent objects
- *
- * \param sorcery Pointer to a sorcery structure
- */
-void ast_sorcery_reload(const struct ast_sorcery *sorcery);
-
-/*!
- * \brief Inform any wizards of a specific object type to reload persistent objects
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Name of the object type to reload
- */
-void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type);
-
-/*!
- * \brief Increase the reference count of a sorcery structure
- *
- * \param sorcery Pointer to a sorcery structure
- */
-void ast_sorcery_ref(struct ast_sorcery *sorcery);
-
-
-/*!
- * \brief Create an object set (KVP list) for an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- * \param flags Flags indicating which handler to use and in what order.
- *
- * \retval non-NULL success
- * \retval NULL if error occurred
- *
- * \note The returned ast_variable list must be destroyed using ast_variables_destroy
- */
-struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
-	const void *object, enum ast_sorcery_field_handler_flags flags);
-
-/*!
- * \brief Create an object set (KVP list) for an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- *
- * \retval non-NULL success
- * \retval NULL if error occurred
- *
- * \note The returned ast_variable list must be destroyed using ast_variables_destroy
- *
- * \note This function attempts to use a field's sorcery_fields_handler first and if that
- * doesn't exist or fails, a field's sorcery_field_handler is used.  The difference is
- * that the former may return multiple list entries for the same field and the latter will only
- * return 1.  It's up to the field itself to determine what the appropriate content is.
- */
-#define ast_sorcery_objectset_create(sorcery, object) \
-	ast_sorcery_objectset_create2(sorcery, object, AST_HANDLER_PREFER_LIST)
-
-/*!
- * \brief Create an object set in JSON format for an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- *
- * \retval non-NULL success
- * \retval NULL if error occurred
- *
- * \note The returned ast_json object must be unreferenced using ast_json_unref
- */
-struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object);
-
-/*!
- * \brief Apply an object set (KVP list) to an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- * \param objectset Object set itself
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note This operation is *not* atomic. If this fails it is possible for the object to be left with a partially
- *       applied object set.
- */
-int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset);
-
-/*!
- * \brief Create a changeset given two object sets
- *
- * \param original Original object set
- * \param modified Modified object set
- * \param changes Pointer to hold any changes between the object sets
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note The returned ast_variable list must be destroyed using ast_variables_destroy
- */
-int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes);
-
-/*!
- * \brief Allocate a generic sorcery capable object
- *
- * \param size Size of the object
- * \param destructor Optional destructor function
- *
- * \retval non-NULL success
- * \retval NULL failure
- */
-void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor);
-
-/*!
- * \brief Allocate an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to allocate
- * \param id Optional unique identifier, if none is provided one will be generated
- *
- * \retval non-NULL success
- * \retval NULL failure
- */
-void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id);
-
-/*!
- * \brief Create a copy of an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Existing object
- *
- * \retval non-NULL success
- * \retval NULL failure
- */
-void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object);
-
-/*!
- * \brief Create a changeset of two objects
- *
- * \param sorcery Pointer to a sorcery structure
- * \param original Original object
- * \param modified Modified object
- * \param changes Pointer which will be populated with changes if any exist
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note The returned ast_variable list must be destroyed using ast_variables_destroy
- *
- * \note While the objects must be of the same type they do not have to be the same object
- */
-int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes);
-
-/*!
- * \brief Add a global observer to sorcery
- *
- * \param callbacks Implementation of the global observer interface
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks);
-
-/*!
- * \brief Remove a global observer from sorcery.
- *
- * A global observer is notified...
- * After a new wizard is registered.
- * After a new sorcery instance is opened.
- * Before an instance is destroyed.
- * Before a wizard is unregistered.
- *
- * \param callbacks Implementation of the global observer interface
- */
-void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks);
-
-/*!
- * \brief Add an observer to a sorcery instance
- *
- * \param sorcery Pointer to a sorcery structure
- * \param callbacks Implementation of the instance observer interface
- *
- * An instance observer is notified...
- * Before an instance is loaded or reloaded.
- * After an instance is loaded or reloaded.
- * After a wizard is mapped to an object type.
- * After an object type is registered.
- * Before an object type is loaded or reloaded.
- * After an object type is loaded or reloaded.
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
-	const struct ast_sorcery_instance_observer *callbacks);
-
-/*!
- * \brief Remove an observer from a sorcery instance
- *
- * \param sorcery Pointer to a sorcery structure
- * \param callbacks Implementation of the instance observer interface
- */
-void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
-	const struct ast_sorcery_instance_observer *callbacks);
-
-/*!
- * \brief Add an observer to a sorcery wizard
- *
- * \param sorcery Pointer to a previously registered wizard structure
- * \param callbacks Implementation of the wizard observer interface
- *
- * A wizard observer is notified...
- * Before a wizard is loaded or reloaded.
- * After a wizard is loaded or reloaded.
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *wizard,
-	const struct ast_sorcery_wizard_observer *callbacks);
-
-/*!
- * \brief Remove an observer from a sorcery wizard.
- *
- * \param sorcery Pointer to a sorcery structure
- * \param callbacks Implementation of the wizard observer interface
- */
-void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *wizard,
-	const struct ast_sorcery_wizard_observer *callbacks);
-
-/*!
- * \brief Add an observer to a specific object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object that should be observed
- * \param callbacks Implementation of the observer interface
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note You must be ready to accept observer invocations before this function is called
- */
-int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Remove an observer from a specific object type
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object that should no longer be observed
- * \param callbacks Implementation of the observer interface
- *
- * \retval 0 success
- * \retval -1 failure
- */
-void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks);
-
-/*!
- * \brief Create and potentially persist an object using an available wizard
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object);
-
-/*!
- * \brief Retrieve an object using its unique identifier
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to retrieve
- * \param id Unique object identifier
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- */
-void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id);
-
-/*!
- * \brief Retrieve an object or multiple objects using specific fields
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to retrieve
- * \param flags Flags to control behavior
- * \param fields Optional object fields and values to match against
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note If the AST_RETRIEVE_FLAG_MULTIPLE flag is specified the returned value will be an
- *       ao2_container that must be unreferenced after use.
- *
- * \note If the AST_RETRIEVE_FLAG_ALL flag is used you may omit fields to retrieve all objects
- *       of the given type.
- */
-void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields);
-
-/*!
- * \brief Retrieve multiple objects using a regular expression on their id
- *
- * \param sorcery Pointer to a sorcery structure
- * \param type Type of object to retrieve
- * \param regex Regular expression
- *
- * \retval non-NULL if error occurs
- * \retval NULL success
- *
- * \note The provided regex is treated as extended case sensitive.
- */
-struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex);
-
-/*!
- * \brief Update an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object);
-
-/*!
- * \brief Delete an object
- *
- * \param sorcery Pointer to a sorcery structure
- * \param object Pointer to a sorcery object
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object);
-
-/*!
- * \brief Decrease the reference count of a sorcery structure
- *
- * \param sorcery Pointer to a sorcery structure
- */
-void ast_sorcery_unref(struct ast_sorcery *sorcery);
-
-/*!
- * \brief Get the unique identifier of a sorcery object
- *
- * \param object Pointer to a sorcery object
- *
- * \retval unique identifier
- */
-const char *ast_sorcery_object_get_id(const void *object);
-
-/*!
- * \brief Get the type of a sorcery object
- *
- * \param object Pointer to a sorcery object
- *
- * \retval type of object
- */
-const char *ast_sorcery_object_get_type(const void *object);
-
-/*!
- * \brief Get an extended field value from a sorcery object
- *
- * \param object Pointer to a sorcery object
- * \param name Name of the extended field value
- *
- * \retval non-NULL if found
- * \retval NULL if not found
- *
- * \note The returned string does NOT need to be freed and is guaranteed to remain valid for the lifetime of the object
- */
-const char *ast_sorcery_object_get_extended(const void *object, const char *name);
-
-/*!
- * \brief Set an extended field value on a sorcery object
- *
- * \param object Pointer to a sorcery object
- * \param name Name of the extended field
- * \param value Value of the extended field
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note The field name MUST begin with '@' to indicate it is an extended field.
- * \note If the extended field already exists it will be overwritten with the new value.
- */
-int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value);
-
-/*!
- * \brief ao2 object comparator based on sorcery id.
- */
-int ast_sorcery_object_id_compare(void *obj, void *arg, int flags);
-
-/*!
- * \brief ao2 object sorter based on sorcery id.
- */
-int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags);
-
-/*!
- * \brief ao2 object hasher based on sorcery id.
- */
-int ast_sorcery_object_id_hash(const void *obj, int flags);
-
-/*!
- * \brief Get the sorcery object type given a type name.
- *
- * \param sorcery The sorcery from which to retrieve the object type
- * \param type The type name
- */
-struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
-		const char *type);
-
-/*!
- * \brief Determine if a particular object field has been registered with sorcery
- *
- * \param object_type The object type to check against
- * \param field_name The name of the field to check
- *
- * \retval 0 The field is not registered for this sorcery type
- * \retval 1 The field is registered for this sorcery type
- */
-int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
-		const char *field_name);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_SORCERY_H */
diff --git a/include/asterisk/sounds_index.h b/include/asterisk/sounds_index.h
deleted file mode 100644
index d7eb053..0000000
--- a/include/asterisk/sounds_index.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Sound file format and description indexer.
- */
-
-#ifndef _ASTERISK_SOUNDS_INDEX_H
-#define _ASTERISK_SOUNDS_INDEX_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/*!
- * \brief Object representing a media index
- */
-struct ast_media_index;
-
-/*!
- * \brief Reload the sounds index
- *
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_sounds_reindex(void);
-
-/*!
- * \brief Get the sounds index
- *
- * \retval sounds index (must be ao2_cleanup()'ed)
- * \retval NULL on failure
- */
-struct ast_media_index *ast_sounds_get_index(void);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif /* _ASTERISK_SOUNDS_INDEX_H */
diff --git a/include/asterisk/speech.h b/include/asterisk/speech.h
index 0da6f5c..5397d8a 100644
--- a/include/asterisk/speech.h
+++ b/include/asterisk/speech.h
@@ -58,7 +58,7 @@ struct ast_speech {
 	/*! Current state of structure */
 	int state;
 	/*! Expected write format */
-	struct ast_format *format;
+	struct ast_format format;
 	/*! Data for speech engine */
 	void *data;
 	/*! Cached results */
@@ -93,8 +93,6 @@ struct ast_speech_engine {
 	int (*start)(struct ast_speech *speech);
 	/*! Change an engine specific setting */
 	int (*change)(struct ast_speech *speech, const char *name, const char *value);
-	/*! Get an engine specific setting */
-	int (*get_setting)(struct ast_speech *speech, const char *name, char *buf, size_t len);
 	/*! Change the type of results we want back */
 	int (*change_results_type)(struct ast_speech *speech, enum ast_speech_results_type results_type);
 	/*! Try to get results */
@@ -142,8 +140,6 @@ int ast_speech_write(struct ast_speech *speech, void *data, int len);
 int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf);
 /*! \brief Change an engine specific attribute */
 int ast_speech_change(struct ast_speech *speech, const char *name, const char *value);
-/*! \brief Get an engine specific attribute */
-int ast_speech_get_setting(struct ast_speech *speech, const char *name, char *buf, size_t len);
 /*! \brief Change the type of results we want */
 int ast_speech_change_results_type(struct ast_speech *speech, enum ast_speech_results_type results_type);
 /*! \brief Change state of a speech structure */
diff --git a/include/asterisk/spinlock.h b/include/asterisk/spinlock.h
deleted file mode 100644
index dacb582..0000000
--- a/include/asterisk/spinlock.h
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Spin Locks.
- *
- * In some atomic operation circumstances the __atomic calls are not quite
- * flexible enough but a full fledged mutex or rwlock is too expensive.
- *
- * Spin locks should be used only for protecting short blocks of critical
- * code such as simple compares and assignments.  Operations that may block,
- * hold a lock, or cause the thread to give up it's timeslice should NEVER
- * be attempted in a spin lock.
- *
- * Because spinlocks must be as lightweight as possible, there are no
- * recursion or deadlock checks.
- *
- */
-
-#ifndef _ASTERISK_SPINLOCK_H
-#define _ASTERISK_SPINLOCK_H
-
-#include <pthread.h>
-#include "asterisk/compiler.h"
-
-/*!
- * \brief Spinlock Implementation Types
- *
- * Not all implementations will be available on all platforms.
- *
- */
-enum ast_spinlock_type {
-	AST_SPINLOCK_TYPE_GCC_ATOMICS,
-	AST_SPINLOCK_TYPE_GAS_X86,
-	AST_SPINLOCK_TYPE_GAS_ARM,
-	AST_SPINLOCK_TYPE_GAS_SPARC,
-	AST_SPINLOCK_TYPE_OSX_ATOMICS,
-	AST_SPINLOCK_TYPE_PTHREAD_SPINLOCK,
-	AST_SPINLOCK_TYPE_PTHREAD_MUTEX,
-};
-
-/*!
- * \brief Implementation using GCC Atomics
- *
- * Specifically, __sync_lock_test_and_set is used to atomically
- * set/unset the lock variable.
- *
- * Most recent gcc implementations support this method and it's performance
- * is equal to or better than the assembly implementations hence it is the
- * most preferred implementation on all platforms.
- *
- */
-#ifdef HAVE_GCC_ATOMICS
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_GCC_ATOMICS
-#define AST_SPINLOCK_TYPE_LABEL "gcc_atomics"
-typedef volatile unsigned int ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	*lock = 0;
-	return 0;
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	while (__sync_lock_test_and_set(lock, 1)) {
-		while(*lock) {
-		}
-	}
-	return 0;
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	return __sync_lock_test_and_set(lock, 1);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	__sync_lock_release(lock);
-	return 0;
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return 0;
-}
-#endif
-
-/*!
- * \brief Implementation using x86 Assembly
- *
- * For x86 implementations that don't support gcc atomics,
- * this is the next best method.
- *
- */
-#if (defined(__x86_64__) || defined(__i386__)) && !defined(AST_SPINLOCK_TYPE)
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_GAS_X86
-#define AST_SPINLOCK_TYPE_LABEL "gas_x86"
-typedef volatile unsigned int ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	*lock = 0;
-	return 0;
-}
-
-static force_inline int x86chgl(ast_spinlock_t *p, unsigned int v)
-{
-	__asm __volatile (
-		"	xchg   %0, %1 ;"
-		: "+r" (v), "=m" (*p)
-		: "m" (*p)
-	);
-
-	return (v);
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	while (x86chgl(lock, 1)) {
-		while(*lock) {
-		}
-	}
-	return 0;
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	return x86chgl(lock, 1);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	x86chgl(lock, 0);
-	return 0;
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return 0;
-}
-#endif
-
-/*!
- * \brief Implementation using ARM Assembly
- *
- * For ARM implementations that don't support gcc atomics,
- * this is the next best method.
- *
- */
-#if defined(__arm__) && !defined(AST_SPINLOCK_TYPE)
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_GAS_ARM
-#define AST_SPINLOCK_TYPE_LABEL "gas_arm"
-typedef volatile unsigned int ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	*lock = 0;
-	return 0;
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	unsigned int tmp;
-
-	__asm __volatile (
-		"1:	ldrex %[tmp], %[lock];"
-		"	teq %[tmp], #0;"
-#if defined __ARM_ARCH && __ARM_ARCH >= 7
-		"	wfene;"
-#endif
-		"	strexeq %[tmp], %[c1], %[lock];"
-		"	teqeq %[tmp], #0;"
-		"	bne 1b;"
-		: [tmp] "=&r" (tmp)
-		: [lock] "m" (*lock) [c1] "r" (1)
-		: "cc"
-	);
-
-	return tmp;
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	unsigned int tmp;
-
-	__asm __volatile (
-		"	ldrex %[tmp], %[lock];"
-		"	teq %[tmp], #0;"
-#if defined __ARM_ARCH && __ARM_ARCH >= 7
-		"	wfene;"
-#endif
-		"	strexeq %[tmp], %[c1], %[lock];"
-		: [tmp] "=&r" (tmp)
-		: [lock] "m" (*lock) [c1] "r" (1)
-		: "cc"
-	);
-
-	return tmp;
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	__asm __volatile (
-		"	dmb;"
-		"	str %[c0], %[lock];"
-#if defined __ARM_ARCH && __ARM_ARCH >= 7
-		"	dsb;"
-		"	sev;"
-#endif
-		:
-		: [lock] "m" (*lock) [c0] "r" (0)
-		: "cc"
-	);
-
-	return 0;
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return 0;
-}
-#endif
-
-/*!
- * \brief Implementation using Sparc Assembly
- *
- * For Sparc implementations that don't support gcc atomics,
- * this is the next best method.
- *
- */
-#if defined(__sparc__) && !defined(AST_SPINLOCK_TYPE)
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_GAS_SPARC
-#define AST_SPINLOCK_TYPE_LABEL "gas_sparc"
-typedef volatile unsigned char ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	*lock = 0;
-	return 0;
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	unsigned char tmp;
-
-	__asm__ __volatile__(
-		"1:	ldstub		%[lock], %[tmp]\n"
-		"	brnz,pn		%[tmp], 2f\n"
-		"	 nop\n"
-		"	.subsection	2\n"
-		"2:	ldub		%[lock], %[tmp]\n"
-		"	brnz,pt		%[tmp], 2b\n"
-		"	 nop\n"
-		"	ba,a,pt		%%xcc, 1b\n"
-		"	.previous"
-		: [tmp] "=&r" (tmp)
-		: [lock] "m" (*lock)
-		: "memory"
-	);
-
-	return 0;
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	unsigned long result = 1;
-
-	__asm__ __volatile__(
-		"	ldstub		%[lock], %[result]\n"
-		: [result] "=&r" (result)
-		: [lock] "m" (*lock)
-		: "memory", "cc"
-	);
-
-	return (result != 0);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	__asm__ __volatile__(
-		"	stb		%%g0, %[lock]"
-		:
-		: [lock] "m" (*lock)
-		: "memory", "cc"
-	);
-
-	return 0;
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return 0;
-}
-#endif
-
-/*!
- * \brief Implementation using pthread_spinlock
- *
- * pthread_spinlocks are not supported on all platforms
- * but if for some reason none of the previous implementations are
- * available, it can be used with reasonable performance.
- *
- */
-#if defined (HAVE_PTHREAD_SPINLOCK) && !defined(AST_SPINLOCK_TYPE)
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_PTHREAD_SPINLOCK
-#define AST_SPINLOCK_TYPE_LABEL "pthread_spinlock"
-typedef pthread_spinlock_t ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	return pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE);
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	return pthread_spin_lock(lock);
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	return pthread_spin_trylock(lock);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	return pthread_spin_unlock(lock);
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return pthread_spin_destroy(lock);
-}
-#endif
-
-/*!
- * \brief Implementation using OSX Atomics
- *
- * The Darwin/Mac OSX platform has its own atomics
- * implementation but it uses more kernel time than
- * GCC atomics and x86 assembly.  It is included
- * as an unlikely fallback.
- *
- */
-#if defined(HAVE_OSX_ATOMICS) && !defined(AST_SPINLOCK_TYPE)
-#include <libkern/OSAtomic.h>
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_OSX_ATOMICS
-#define AST_SPINLOCK_TYPE_LABEL "osx_atomics"
-typedef OSSpinLock ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	*lock = OS_SPINLOCK_INIT;
-	return 0;
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	OSSpinLockLock(lock);
-	return 0;
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	return !OSSpinLockTry(lock);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	OSSpinLockUnlock(lock);
-	return 0;
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return 0;
-}
-#endif
-
-/*!
- * \brief Implementation using pthread_mutex
- *
- * pthread_mutex is supported on all platforms but
- * it is also the worst performing. It is included
- * as an unlikely fallback.
- *
- */
-#if !defined(AST_SPINLOCK_TYPE)
-#define AST_SPINLOCK_TYPE AST_SPINLOCK_TYPE_PTHREAD_MUTEX
-#define AST_SPINLOCK_TYPE_LABEL "pthread_mutex"
-typedef pthread_mutex_t ast_spinlock_t;
-
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock)
-{
-	pthread_mutex_init(lock, NULL);
-	return 0;
-}
-
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock)
-{
-	return pthread_mutex_lock(lock);
-}
-
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock)
-{
-	return pthread_mutex_trylock(lock);
-}
-
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock)
-{
-	return pthread_mutex_unlock(lock);
-}
-
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock)
-{
-	return pthread_mutex_destroy(lock);
-}
-#endif
-
-#if !defined(AST_SPINLOCK_TYPE)
-#error "No spinlock implementation could be found."
-#endif
-
-/* Prototypes are declared here to insure that each implementation provides
- * the same API and to act as placeholders for the documentation.
- */
-
-/*!
- * \brief Initialize a spin lock
- * \param lock Address of the lock
- * \retval 0 Success
- * \retval other Failure
- */
-static force_inline int ast_spinlock_init(ast_spinlock_t *lock);
-
-/*!
- * \brief Lock a spin lock
- * \param lock Address of the lock
- * \retval 0 Success
- * \retval other Failure
- */
-static force_inline int ast_spinlock_lock(ast_spinlock_t *lock);
-
-/*!
- * \brief Try to lock a spin lock
- *
- * Attempt to gain a lock.  Return immediately
- * regardless of result.
- *
- * \param lock Address of the lock
- * \retval 0 Success
- * \retval other Lock was not obtained
- */
-static force_inline int ast_spinlock_trylock(ast_spinlock_t *lock);
-
-/*!
- * \brief Unlock a spin lock
- * \param lock Address of the lock
- * \retval 0 Success
- * \retval other Failure
- */
-static force_inline int ast_spinlock_unlock(ast_spinlock_t *lock);
-
-/*!
- * \brief Destroy a spin lock
- * \param lock Address of the lock
- * \retval 0 Success
- * \retval other Failure
- */
-static force_inline int ast_spinlock_destroy(ast_spinlock_t *lock);
-
-#endif /* _ASTERISK_SPINLOCK_H */
diff --git a/include/asterisk/srv.h b/include/asterisk/srv.h
index f8fa864..d98a1d0 100644
--- a/include/asterisk/srv.h
+++ b/include/asterisk/srv.h
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2013, Digium, Inc.
+ * Copyright (C) 1999 - 2005, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -23,47 +23,42 @@
 #ifndef _ASTERISK_SRV_H
 #define _ASTERISK_SRV_H
 
-/*! \file srv.h
- *
- * \brief Support for DNS SRV records, used in to locate SIP services.
- *
- * \note Note: This SRV record support will respect the priority and weight
- *	elements of the records that are returned, but there are no provisions
- * 	for retrying or failover between records.
- */
+/*!
+  \file srv.h
+  \brief Support for DNS SRV records, used in to locate SIP services.
+  \note Note: This SRV record support will respect the priority and
+        weight elements of the records that are returned, but there are
+	no provisions for retrying or failover between records.
+*/
 
-/*! \brief An opaque type, for lookup usage */
+/*!\brief An opaque type, for lookup usage */
 struct srv_context;
 
-/*! \brief Retrieve set of SRV lookups, in order
- *
+/*!\brief Retrieve set of SRV lookups, in order
  * \param[in] context A pointer in which to hold the result
  * \param[in] service The service name to look up
  * \param[out] host Result host
  * \param[out] port Associated TCP portnum
- *
  * \retval -1 Query failed
  * \retval 0 Result exists in host and port
  * \retval 1 No more results
  */
 extern int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port);
 
-/*! \brief Cleanup resources associated with ast_srv_lookup
- *
+/*!\brief Cleanup resources associated with ast_srv_lookup
  * \param context Pointer passed into ast_srv_lookup
  */
 void ast_srv_cleanup(struct srv_context **context);
 
-/*! \brief Lookup entry in SRV records Returns 1 if found, 0 if not found, -1 on hangup 
- *
- * Only do SRV record lookup if you get a domain without a port. If you get a port #, it's a DNS host name.
- *
- * \param chan Ast channel
- * \param host host name (return value)
- * \param hostlen Length of string "host"
- * \param port Port number (return value)
- * \param service Service tag for SRV lookup (like "_sip._udp" or "_stun._udp"
- */
+/*! Lookup entry in SRV records Returns 1 if found, 0 if not found, -1 on hangup 
+	Only do SRV record lookup if you get a domain without a port. If you get a port #, it's a DNS host name.
+*/
+/*!	\param	chan Ast channel
+	\param	host host name (return value)
+	\param	hostlen Length of string "host"
+	\param	port Port number (return value)
+	\param service Service tag for SRV lookup (like "_sip._udp" or "_stun._udp"
+*/
 extern int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service);
 
 /*!
@@ -75,7 +70,6 @@ extern int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *p
  * SRV lookup.
  *
  * \param context The context returned by ast_srv_lookup
- *
  * \return Number of records in context
  */
 unsigned int ast_srv_get_record_count(struct srv_context *context);
@@ -96,9 +90,8 @@ unsigned int ast_srv_get_record_count(struct srv_context *context);
  * \param[out] port The port portion of the record
  * \param[out] priority The priority portion of the record
  * \param[out] weight The weight portion of the record
- *
- * \retval -1 Failed to retrieve information. 
- * 	Likely due to an out of range record_num
+ * \retval -1 Failed to retrieve information. Likely due to an out of
+ * range record_num
  * \retval 0 Success
  */
 int ast_srv_get_nth_record(struct srv_context *context, int record_num, const char **host,
diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h
deleted file mode 100644
index 0b1b1e8..0000000
--- a/include/asterisk/stasis.h
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_H
-#define _ASTERISK_STASIS_H
-
-/*! \file
- *
- * \brief Stasis Message Bus API. See \ref stasis "Stasis Message Bus API" for
- * detailed documentation.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- *
- * \page stasis Stasis Message Bus API
- *
- * \par Intro
- *
- * The Stasis Message Bus is a loosely typed mechanism for distributing messages
- * within Asterisk. It is designed to be:
- *  - Loosely coupled; new message types can be added in seperate modules.
- *  - Easy to use; publishing and subscribing are straightforward operations.
- *
- * There are three main concepts for using the Stasis Message Bus:
- *  - \ref stasis_message
- *  - \ref stasis_topic
- *  - \ref stasis_subscription
- *
- * \par stasis_message
- *
- * Central to the Stasis Message Bus is the \ref stasis_message, the messages
- * that are sent on the bus. These messages have:
- *  - a type (as defined by a \ref stasis_message_type)
- *  - a value - a \c void pointer to an AO2 object
- *  - a timestamp when it was created
- *
- * Once a \ref stasis_message has been created, it is immutable and cannot
- * change. The same goes for the value of the message (although this cannot be
- * enforced in code). Messages themselves are reference-counted, AO2 objects,
- * along with their values. By being both reference counted and immutable,
- * messages can be shared throughout the system without any concerns for
- * threading.
- *
- * The type of a message is defined by an instance of \ref stasis_message_type,
- * which can be created by calling stasis_message_type_create(). Message types
- * are named, which is useful in debugging. It is recommended that the string
- * name for a message type match the name of the struct that's stored in the
- * message. For example, name for \ref stasis_cache_update's message type is \c
- * "stasis_cache_update".
- *
- * \par stasis_topic
- *
- * A \ref stasis_topic is an object to which \ref stasis_subscriber's may be
- * subscribed, and \ref stasis_message's may be published. Any message published
- * to the topic is dispatched to all of its subscribers. The topic itself may be
- * named, which is useful in debugging.
- *
- * Topics themselves are reference counted objects. Since topics are referred to
- * by their subscibers, they will not be freed until all of their subscribers
- * have unsubscribed. Topics are also thread safe, so no worries about
- * publishing/subscribing/unsubscribing to a topic concurrently from multiple
- * threads. It's also designed to handle the case of unsubscribing from a topic
- * from within the subscription handler.
- *
- * \par Forwarding
- *
- * There is one special case of topics that's worth noting: forwarding
- * messages. It's a fairly common use case to want to forward all the messages
- * published on one topic to another one (for example, an aggregator topic that
- * publishes all the events from a set of other topics). This can be
- * accomplished easily using stasis_forward_all(). This sets up the forwarding
- * between the two topics, and returns a \ref stasis_subscription, which can be
- * unsubscribed to stop the forwarding.
- *
- * \par Caching
- *
- * Another common use case is to want to cache certain messages that are
- * published on the bus. Usually these events are snapshots of the current state
- * in the system, and it's desirable to query that state from the cache without
- * locking the original object. It's also desirable for subscribers of the
- * caching topic to receive messages that have both the old cache value and the
- * new value being put into the cache. For this, we have stasis_cache_create()
- * and stasis_caching_topic_create(), providing them with the topic which
- * publishes the messages that you wish to cache, and a function that can
- * identify cacheable messages.
- *
- * The \ref stasis_cache is designed so that it may be shared amongst several
- * \ref stasis_caching_topic objects. This allows you to have individual caching
- * topics per-object (i.e. so you can subscribe to updates for a single object),
- * and still have a single cache to query for the state of all objects. While a
- * cache may be shared amongst different message types, such a usage is probably
- * not a good idea.
- *
- * The \ref stasis_cache can only be written to by \ref stasis_caching_topics.
- * It's a thread safe container, so freely use the stasis_cache_get() and
- * stasis_cache_dump() to query the cache.
- *
- * The \ref stasis_caching_topic discards non-cacheable messages. A cacheable
- * message is wrapped in a \ref stasis_cache_update message which provides the
- * old snapshot (or \c NULL if this is a new cache entry), and the new snapshot
- * (or \c NULL if the entry was removed from the cache). A
- * stasis_cache_clear_create() message must be sent to the topic in order to
- * remove entries from the cache.
- *
- * In order to unsubscribe a \ref stasis_caching_topic from the upstream topic,
- * call stasis_caching_unsubscribe(). Due to cyclic references, the \ref
- * stasis_caching_topic will not be freed until after it has been unsubscribed,
- * and all other ao2_ref()'s have been cleaned up.
- *
- * The \ref stasis_cache object is a normal AO2 managed object, which can be
- * release with ao2_cleanup().
- *
- * \par stasis_subscriber
- *
- * Any topic may be subscribed to by simply providing stasis_subscribe() the
- * \ref stasis_topic to subscribe to, a handler function and \c void pointer to
- * data that is passed back to the handler. Invocations on the subscription's
- * handler are serialized, but different invocations may occur on different
- * threads (this usually isn't important unless you use thread locals or
- * something similar).
- *
- * In order to stop receiving messages, call stasis_unsubscribe() with your \ref
- * stasis_subscription. Due to cyclic references, the \ref
- * stasis_subscription will not be freed until after it has been unsubscribed,
- * and all other ao2_ref()'s have been cleaned up.
- *
- * \par Shutdown
- *
- * Subscriptions have two options for unsubscribing, depending upon the context
- * in which you need to unsubscribe.
- *
- * If your subscription is owned by a module, and you must unsubscribe from the
- * module_unload() function, then you'll want to use the
- * stasis_unsubscribe_and_join() function. This will block until the final
- * message has been received on the subscription. Otherwise, there's the danger
- * of invoking the callback function after it has been unloaded.
- *
- * If your subscription is owned by an object, then your object should have an
- * explicit shutdown() function, which calls stasis_unsubscribe(). In your
- * subscription handler, when the stasis_subscription_final_message() has been
- * received, decrement the refcount on your object. In your object's destructor,
- * you may assert that stasis_subscription_is_done() to validate that the
- * subscription's callback will no longer be invoked.
- *
- * \b Note: You may be tempted to simply call stasis_unsubscribe_and_join() from
- * an object's destructor. While code that does this may work most of the time,
- * it's got one big downside. There's a general assumption that object
- * destruction is non-blocking. If you block the destruction waiting for the
- * subscription to complete, there's the danger that the subscription may
- * process a message which will bump the refcount up by one. Then it does
- * whatever it does, decrements the refcount, which then proceeds to re-destroy
- * the object. Now you've got hard to reproduce bugs that only show up under
- * certain loads.
- */
-
-#include "asterisk/json.h"
-#include "asterisk/manager.h"
-#include "asterisk/utils.h"
-#include "asterisk/event.h"
-
-/*! @{ */
-
-/*!
- * \brief Metadata about a \ref stasis_message.
- * \since 12
- */
-struct stasis_message_type;
-
-/*!
- * \brief Opaque type for a Stasis message.
- * \since 12
- */
-struct stasis_message;
-
-/*!
- * \brief Opaque type for a Stasis subscription.
- * \since 12
- */
-struct stasis_subscription;
-
-/*!
- * \brief Structure containing callbacks for Stasis message sanitization
- *
- * \note If either callback is implemented, both should be implemented since
- * not all callers may have access to the full snapshot.
- */
-struct stasis_message_sanitizer {
-	/*!
-	 * \brief Callback which determines whether a channel should be sanitized from
-	 * a message based on the channel's unique ID
-	 *
-	 * \param channel_id The unique ID of the channel
-	 *
-	 * \retval non-zero if the channel should be left out of the message
-	 * \retval zero if the channel should remain in the message
-	 */
-	int (*channel_id)(const char *channel_id);
-
-	/*!
-	 * \brief Callback which determines whether a channel should be sanitized from
-	 * a message based on the channel's snapshot
-	 *
-	 * \param snapshot A snapshot generated from the channel
-	 *
-	 * \retval non-zero if the channel should be left out of the message
-	 * \retval zero if the channel should remain in the message
-	 */
-	int (*channel_snapshot)(const struct ast_channel_snapshot *snapshot);
-
-	/*!
-	 * \brief Callback which determines whether a channel should be sanitized from
-	 * a message based on the channel
-	 *
-	 * \param chan The channel to be checked
-	 *
-	 * \retval non-zero if the channel should be left out of the message
-	 * \retval zero if the channel should remain in the message
-	 */
-	int (*channel)(const struct ast_channel *chan);
-};
-
-/*!
- * \brief Virtual table providing methods for messages.
- * \since 12
- */
-struct stasis_message_vtable {
-	/*!
-	 * \brief Build the JSON representation of the message.
-	 *
-	 * May be \c NULL, or may return \c NULL, to indicate no representation.
-	 * The returned object should be ast_json_unref()'ed.
-	 *
-	 * \param message Message to convert to JSON string.
-	 * \param sanitize Snapshot sanitization callback.
-	 *
-	 * \return Newly allocated JSON message.
-	 * \return \c NULL on error.
-	 * \return \c NULL if JSON format is not supported.
-	 */
-	struct ast_json *(*to_json)(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize);
-
-	/*!
-	 * \brief Build the AMI representation of the message.
-	 *
-	 * May be \c NULL, or may return \c NULL, to indicate no representation.
-	 * The returned object should be ao2_cleanup()'ed.
-	 *
-	 * \param message Message to convert to AMI string.
-	 * \return Newly allocated \ref ast_manager_event_blob.
-	 * \return \c NULL on error.
-	 * \return \c NULL if AMI format is not supported.
-	 */
-	struct ast_manager_event_blob *(*to_ami)(
-		struct stasis_message *message);
-
-	/*!
-	 * \since 12.3.0
-	 * \brief Build the \ref ast_event representation of the message.
-	 *
-	 * May be \c NULL, or may return \c NULL, to indicate no representation.
-	 * The returned object should be free'd.
-	 *
-	 * \param message Message to convert to an \ref ast_event.
-	 * \return Newly allocated \ref ast_event.
-	 * \return \c NULL on error.
-	 * \return \c NULL if AMI format is not supported.
-	 */
-	struct ast_event *(*to_event)(
-		struct stasis_message *message);
-};
-
-/*!
- * \brief Return code for Stasis message type creation attempts
- */
-enum stasis_message_type_result {
-	STASIS_MESSAGE_TYPE_ERROR = -1,	/*!< Message type was not created due to allocation failure */
-	STASIS_MESSAGE_TYPE_SUCCESS,	/*!< Message type was created successfully */
-	STASIS_MESSAGE_TYPE_DECLINED,	/*!< Message type was not created due to configuration */
-};
-
-/*!
- * \brief Create a new message type.
- *
- * \ref stasis_message_type is an AO2 object, so ao2_cleanup() when you're done
- * with it.
- *
- * \param name Name of the new type.
- * \param vtable Virtual table of message methods. May be \c NULL.
- * \param[out] result The location where the new message type will be placed
- *
- * \note Stasis message type creation may be declined if the message type is disabled
- *
- * \returns A stasis_message_type_result enum
- * \since 12
- */
-enum stasis_message_type_result stasis_message_type_create(const char *name,
-	struct stasis_message_vtable *vtable, struct stasis_message_type **result);
-
-/*!
- * \brief Gets the name of a given message type
- * \param type The type to get.
- * \return Name of the type.
- * \return \c NULL if \a type is \c NULL.
- * \since 12
- */
-const char *stasis_message_type_name(const struct stasis_message_type *type);
-
-/*!
- * \brief Check whether a message type is declined
- *
- * \param name The name of the message type to check
- *
- * \retval zero The message type is not declined
- * \retval non-zero The message type is declined
- */
-int stasis_message_type_declined(const char *name);
-
-/*!
- * \brief Create a new message.
- *
- * This message is an \c ao2 object, and must be ao2_cleanup()'ed when you are done
- * with it. Messages are also immutable, and must not be modified after they
- * are initialized. Especially the \a data in the message.
- *
- * \param type Type of the message
- * \param data Immutable data that is the actual contents of the message
- *
- * \return New message
- * \return \c NULL on error
- *
- * \since 12
- */
-struct stasis_message *stasis_message_create(struct stasis_message_type *type, void *data);
-
-/*!
- * \brief Create a new message for an entity.
- *
- * This message is an \c ao2 object, and must be ao2_cleanup()'ed when you are done
- * with it. Messages are also immutable, and must not be modified after they
- * are initialized. Especially the \a data in the message.
- *
- * \param type Type of the message
- * \param data Immutable data that is the actual contents of the message
- * \param eid What entity originated this message. (NULL for aggregate)
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \retval New message
- * \retval \c NULL on error
- *
- * \since 12.2.0
- */
-struct stasis_message *stasis_message_create_full(struct stasis_message_type *type, void *data, const struct ast_eid *eid);
-
-/*!
- * \brief Get the entity id for a \ref stasis_message.
- * \since 12.2.0
- *
- * \param msg Message to get eid.
- *
- * \retval Entity id of \a msg
- * \retval \c NULL if \a msg is an aggregate or \a msg is \c NULL.
- */
-const struct ast_eid *stasis_message_eid(const struct stasis_message *msg);
-
-/*!
- * \brief Get the message type for a \ref stasis_message.
- * \param msg Message to type
- * \return Type of \a msg
- * \return \c NULL if \a msg is \c NULL.
- * \since 12
- */
-struct stasis_message_type *stasis_message_type(const struct stasis_message *msg);
-
-/*!
- * \brief Get the data contained in a message.
- * \param msg Message.
- * \return Immutable data pointer
- * \return \c NULL if msg is \c NULL.
- * \since 12
- */
-void *stasis_message_data(const struct stasis_message *msg);
-
-/*!
- * \brief Get the time when a message was created.
- * \param msg Message.
- * \return Pointer to the \a timeval when the message was created.
- * \return \c NULL if msg is \c NULL.
- * \since 12
- */
-const struct timeval *stasis_message_timestamp(const struct stasis_message *msg);
-
-/*!
- * \brief Build the JSON representation of the message.
- *
- * May return \c NULL, to indicate no representation. The returned object should
- * be ast_json_unref()'ed.
- *
- * \param message Message to convert to JSON string.
- * \param sanitize Snapshot sanitization callback.
- *
- * \return Newly allocated string with JSON message.
- * \return \c NULL on error.
- * \return \c NULL if JSON format is not supported.
- */
-struct ast_json *stasis_message_to_json(struct stasis_message *message, struct stasis_message_sanitizer *sanitize);
-
-/*!
- * \brief Build the AMI representation of the message.
- *
- * May return \c NULL, to indicate no representation. The returned object should
- * be ao2_cleanup()'ed.
- *
- * \param message Message to convert to AMI.
- * \return \c NULL on error.
- * \return \c NULL if AMI format is not supported.
- */
-struct ast_manager_event_blob *stasis_message_to_ami(
-	struct stasis_message *message);
-
-/*!
- * \brief Build the \ref AstGenericEvents representation of the message.
- *
- * May return \c NULL, to indicate no representation. The returned object should
- * be disposed of via \ref ast_event_destroy.
- *
- * \param message Message to convert to AMI.
- * \return \c NULL on error.
- * \return \c NULL if AMI format is not supported.
- */
-struct ast_event *stasis_message_to_event(
-	struct stasis_message *message);
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \brief A topic to which messages may be posted, and subscribers, well, subscribe
- * \since 12
- */
-struct stasis_topic;
-
-/*!
- * \brief Create a new topic.
- * \param name Name of the new topic.
- * \return New topic instance.
- * \return \c NULL on error.
- * \since 12
- */
-struct stasis_topic *stasis_topic_create(const char *name);
-
-/*!
- * \brief Return the name of a topic.
- * \param topic Topic.
- * \return Name of the topic.
- * \return \c NULL if topic is \c NULL.
- * \since 12
- */
-const char *stasis_topic_name(const struct stasis_topic *topic);
-
-/*!
- * \brief Publish a message to a topic's subscribers.
- * \param topic Topic.
- * \param message Message to publish.
- *
- * This call is asynchronous and will return immediately upon queueing
- * the message for delivery to the topic's subscribers.
- *
- * \since 12
- */
-void stasis_publish(struct stasis_topic *topic, struct stasis_message *message);
-
-/*!
- * \brief Publish a message to a topic's subscribers, synchronizing
- * on the specified subscriber
- * \param sub Subscription to synchronize on.
- * \param message Message to publish.
- *
- * The caller of stasis_publish_sync will block until the specified
- * subscriber completes handling of the message.
- *
- * All other subscribers to the topic the \ref stasis_subpscription
- * is subscribed to are also delivered the message; this delivery however
- * happens asynchronously.
- *
- * \since 12.1.0
- */
-void stasis_publish_sync(struct stasis_subscription *sub, struct stasis_message *message);
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \brief Callback function type for Stasis subscriptions.
- * \param data Data field provided with subscription.
- * \param message Published message.
- * \since 12
- */
-typedef void (*stasis_subscription_cb)(void *data, struct stasis_subscription *sub, struct stasis_message *message);
-
-/*!
- * \brief Create a subscription.
- *
- * In addition to being AO2 managed memory (requiring an ao2_cleanup() to free
- * up this reference), the subscription must be explicitly unsubscribed from its
- * topic using stasis_unsubscribe().
- *
- * The invocations of the callback are serialized, but may not always occur on
- * the same thread. The invocation order of different subscriptions is
- * unspecified.
- *
- * \param topic Topic to subscribe to.
- * \param callback Callback function for subscription messages.
- * \param data Data to be passed to the callback, in addition to the message.
- * \return New \ref stasis_subscription object.
- * \return \c NULL on error.
- * \since 12
- */
-struct stasis_subscription *stasis_subscribe(struct stasis_topic *topic,
-	stasis_subscription_cb callback, void *data);
-
-/*!
- * \brief Create a subscription whose callbacks occur on a thread pool
- *
- * In addition to being AO2 managed memory (requiring an ao2_cleanup() to free
- * up this reference), the subscription must be explicitly unsubscribed from its
- * topic using stasis_unsubscribe().
- *
- * The invocations of the callback are serialized, but will almost certainly not
- * always happen on the same thread. The invocation order of different subscriptions
- * is unspecified.
- *
- * Unlike \ref stasis_subscribe, this function will explicitly use a threadpool to
- * dispatch items to its \c callback. This form of subscription should be used
- * when many subscriptions may be made to the specified \c topic.
- *
- * \param topic Topic to subscribe to.
- * \param callback Callback function for subscription messages.
- * \param data Data to be passed to the callback, in addition to the message.
- * \return New \ref stasis_subscription object.
- * \return \c NULL on error.
- * \since 12.8.0
- */
-struct stasis_subscription *stasis_subscribe_pool(struct stasis_topic *topic,
-	stasis_subscription_cb callback, void *data);
-
-/*!
- * \brief Cancel a subscription.
- *
- * Note that in an asynchronous system, there may still be messages queued or
- * in transit to the subscription's callback. These will still be delivered.
- * There will be a final 'SubscriptionCancelled' message, indicating the
- * delivery of the final message.
- *
- * \param subscription Subscription to cancel.
- * \return \c NULL for convenience
- * \since 12
- */
-struct stasis_subscription *stasis_unsubscribe(
-	struct stasis_subscription *subscription);
-
-/*!
- * \brief Block until the last message is processed on a subscription.
- *
- * This function will not return until the \a subscription's callback for the
- * stasis_subscription_final_message() completes. This allows cleanup routines
- * to run before unblocking the joining thread.
- *
- * \param subscription Subscription to block on.
- * \since 12
- */
-void stasis_subscription_join(struct stasis_subscription *subscription);
-
-/*!
- * \brief Returns whether \a subscription has received its final message.
- *
- * Note that a subscription is considered done even while the
- * stasis_subscription_final_message() is being processed. This allows cleanup
- * routines to check the status of the subscription.
- *
- * \param subscription Subscription.
- * \return True (non-zero) if stasis_subscription_final_message() has been
- *         received.
- * \return False (zero) if waiting for the end.
- */
-int stasis_subscription_is_done(struct stasis_subscription *subscription);
-
-/*!
- * \brief Cancel a subscription, blocking until the last message is processed.
- *
- * While normally it's recommended to stasis_unsubscribe() and wait for
- * stasis_subscription_final_message(), there are times (like during a module
- * unload) where you have to wait for the final message (otherwise you'll call
- * a function in a shared module that no longer exists).
- *
- * \param subscription Subscription to cancel.
- * \return \c NULL for convenience
- * \since 12
- */
-struct stasis_subscription *stasis_unsubscribe_and_join(
-	struct stasis_subscription *subscription);
-
-struct stasis_forward;
-
-/*!
- * \brief Create a subscription which forwards all messages from one topic to
- * another.
- *
- * Note that the \a topic parameter of the invoked callback will the be the
- * \a topic the message was sent to, not the topic the subscriber subscribed to.
- *
- * \param from_topic Topic to forward.
- * \param to_topic Destination topic of forwarded messages.
- * \return New forwarding subscription.
- * \return \c NULL on error.
- * \since 12
- */
-struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic,
-	struct stasis_topic *to_topic);
-
-struct stasis_forward *stasis_forward_cancel(struct stasis_forward *forward);
-
-/*!
- * \brief Get the unique ID for the subscription.
- *
- * \param sub Subscription for which to get the unique ID.
- * \return Unique ID for the subscription.
- * \since 12
- */
-const char *stasis_subscription_uniqueid(const struct stasis_subscription *sub);
-
-/*!
- * \brief Returns whether a subscription is currently subscribed.
- *
- * Note that there may still be messages queued up to be dispatched to this
- * subscription, but the stasis_subscription_final_message() has been enqueued.
- *
- * \param sub Subscription to check
- * \return False (zero) if subscription is not subscribed.
- * \return True (non-zero) if still subscribed.
- */
-int stasis_subscription_is_subscribed(const struct stasis_subscription *sub);
-
-/*!
- * \brief Determine whether a message is the final message to be received on a subscription.
- *
- * \param sub Subscription on which the message was received.
- * \param msg Message to check.
- * \return zero if the provided message is not the final message.
- * \return non-zero if the provided message is the final message.
- * \since 12
- */
-int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg);
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief Holds details about changes to subscriptions for the specified topic
- * \since 12
- */
-struct stasis_subscription_change {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(uniqueid);	/*!< The unique ID associated with this subscription */
-		AST_STRING_FIELD(description);	/*!< The description of the change to the subscription associated with the uniqueid */
-	);
-	struct stasis_topic *topic;		/*!< The topic the subscription is/was subscribing to */
-};
-
-/*!
- * \brief Gets the message type for subscription change notices
- * \return The stasis_message_type for subscription change notices
- * \since 12
- */
-struct stasis_message_type *stasis_subscription_change_type(void);
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \brief Pool for topic aggregation
- */
-struct stasis_topic_pool;
-
-/*!
- * \brief Create a topic pool that routes messages from dynamically generated topics to the given topic
- * \param pooled_topic Topic to which messages will be routed
- * \return the new stasis_topic_pool
- * \return \c NULL on failure
- */
-struct stasis_topic_pool *stasis_topic_pool_create(struct stasis_topic *pooled_topic);
-
-/*!
- * \brief Find or create a topic in the pool
- * \param pool Pool for which to get the topic
- * \param topic_name Name of the topic to get
- * \return The already stored or newly allocated topic
- * \return \c NULL if the topic was not found and could not be allocated
- */
-struct stasis_topic *stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name);
-
-/*! @} */
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief Message type for cache update messages.
- * \return Message type for cache update messages.
- * \since 12
- */
-struct stasis_message_type *stasis_cache_update_type(void);
-
-/*!
- * \brief Cache update message
- * \since 12
- */
-struct stasis_cache_update {
-	/*! \brief Convenience reference to snapshot type */
-	struct stasis_message_type *type;
-	/*! \brief Old value from the cache */
-	struct stasis_message *old_snapshot;
-	/*! \brief New value */
-	struct stasis_message *new_snapshot;
-};
-
-/*!
- * \brief Message type for clearing a message from a stasis cache.
- * \since 12
- */
-struct stasis_message_type *stasis_cache_clear_type(void);
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \brief A message cache, for use with \ref stasis_caching_topic.
- * \since 12
- */
-struct stasis_cache;
-
-/*! Cache entry used for calculating the aggregate snapshot. */
-struct stasis_cache_entry;
-
-/*!
- * \brief A topic wrapper, which caches certain messages.
- * \since 12
- */
-struct stasis_caching_topic;
-
-
-/*!
- * \brief Callback extract a unique identity from a snapshot message.
- *
- * This identity is unique to the underlying object of the snapshot, such as the
- * UniqueId field of a channel.
- *
- * \param message Message to extract id from.
- * \return String representing the snapshot's id.
- * \return \c NULL if the message_type of the message isn't a handled snapshot.
- * \since 12
- */
-typedef const char *(*snapshot_get_id)(struct stasis_message *message);
-
-/*!
- * \brief Callback to calculate the aggregate cache entry.
- * \since 12.2.0
- *
- * \param entry Cache entry to calculate a new aggregate snapshot.
- * \param new_snapshot The shapshot that is being updated.
- *
- * \note Return a ref bumped pointer from stasis_cache_entry_get_aggregate()
- * if a new aggregate could not be calculated because of error.
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \return New aggregate-snapshot calculated on success.
- * Caller has a reference on return.
- */
-typedef struct stasis_message *(*cache_aggregate_calc_fn)(struct stasis_cache_entry *entry, struct stasis_message *new_snapshot);
-
-/*!
- * \brief Callback to publish the aggregate cache entry message.
- * \since 12.2.0
- *
- * \details
- * Once an aggregate message is calculated.  This callback publishes the
- * message so subscribers will know the new value of an aggregated state.
- *
- * \param topic The aggregate message may be published to this topic.
- *        It is the topic to which the cache itself is subscribed.
- * \param aggregate The aggregate shapshot message to publish.
- *
- * \note It is up to the function to determine if there is a better topic
- * the aggregate message should be published over.
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \return Nothing
- */
-typedef void (*cache_aggregate_publish_fn)(struct stasis_topic *topic, struct stasis_message *aggregate);
-
-/*!
- * \brief Get the aggregate cache entry snapshot.
- * \since 12.2.0
- *
- * \param entry Cache entry to get the aggregate snapshot.
- *
- * \note A reference is not given to the returned pointer so don't unref it.
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \retval Aggregate-snapshot in cache.
- * \retval NULL if not present.
- */
-struct stasis_message *stasis_cache_entry_get_aggregate(struct stasis_cache_entry *entry);
-
-/*!
- * \brief Get the local entity's cache entry snapshot.
- * \since 12.2.0
- *
- * \param entry Cache entry to get the local entity's snapshot.
- *
- * \note A reference is not given to the returned pointer so don't unref it.
- *
- * \retval Internal-snapshot in cache.
- * \retval NULL if not present.
- */
-struct stasis_message *stasis_cache_entry_get_local(struct stasis_cache_entry *entry);
-
-/*!
- * \brief Get a remote entity's cache entry snapshot by index.
- * \since 12.2.0
- *
- * \param entry Cache entry to get a remote entity's snapshot.
- * \param idx Which remote entity's snapshot to get.
- *
- * \note A reference is not given to the returned pointer so don't unref it.
- *
- * \retval Remote-entity-snapshot in cache.
- * \retval NULL if not present.
- */
-struct stasis_message *stasis_cache_entry_get_remote(struct stasis_cache_entry *entry, int idx);
-
-/*!
- * \brief Create a cache.
- *
- * This is the backend store for a \ref stasis_caching_topic. The cache is
- * thread safe, allowing concurrent reads and writes.
- *
- * The returned object is AO2 managed, so ao2_cleanup() when you're done.
- *
- * \param id_fn Callback to extract the id from a snapshot message.
- *
- * \retval New cache indexed by \a id_fn.
- * \retval \c NULL on error
- *
- * \since 12
- */
-struct stasis_cache *stasis_cache_create(snapshot_get_id id_fn);
-
-/*!
- * \brief Create a cache.
- *
- * This is the backend store for a \ref stasis_caching_topic. The cache is
- * thread safe, allowing concurrent reads and writes.
- *
- * The returned object is AO2 managed, so ao2_cleanup() when you're done.
- *
- * \param id_fn Callback to extract the id from a snapshot message.
- * \param aggregate_calc_fn Callback to calculate the aggregate cache entry.
- * \param aggregate_publish_fn Callback to publish the aggregate cache entry.
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \retval New cache indexed by \a id_fn.
- * \retval \c NULL on error
- *
- * \since 12.2.0
- */
-struct stasis_cache *stasis_cache_create_full(snapshot_get_id id_fn, cache_aggregate_calc_fn aggregate_calc_fn, cache_aggregate_publish_fn aggregate_publish_fn);
-
-/*!
- * \brief Create a topic which monitors and caches messages from another topic.
- *
- * The idea is that some topics publish 'snapshots' of some other object's state
- * that should be cached. When these snapshot messages are received, the cache
- * is updated, and a stasis_cache_update() message is forwarded, which has both
- * the original snapshot message and the new message.
- *
- * The returned object is AO2 managed, so ao2_cleanup() when done with it.
- *
- * \param original_topic Topic publishing snapshot messages.
- * \param cache Backend cache in which to keep snapshots.
- * \return New topic which changes snapshot messages to stasis_cache_update()
- *         messages, and forwards all other messages from the original topic.
- * \return \c NULL on error
- * \since 12
- */
-struct stasis_caching_topic *stasis_caching_topic_create(
-	struct stasis_topic *original_topic, struct stasis_cache *cache);
-
-/*!
- * \brief Unsubscribes a caching topic from its upstream topic.
- *
- * This function returns immediately, so be sure to cleanup when
- * stasis_subscription_final_message() is received.
- *
- * \param caching_topic Caching topic to unsubscribe
- * \return \c NULL for convenience
- * \since 12
- */
-struct stasis_caching_topic *stasis_caching_unsubscribe(
-	struct stasis_caching_topic *caching_topic);
-
-/*!
- * \brief Unsubscribes a caching topic from its upstream topic, blocking until
- * all messages have been forwarded.
- *
- * See stasis_unsubscriben_and_join() for more info on when to use this as
- * opposed to stasis_caching_unsubscribe().
- *
- * \param caching_topic Caching topic to unsubscribe
- * \return \c NULL for convenience
- * \since 12
- */
-struct stasis_caching_topic *stasis_caching_unsubscribe_and_join(
-	struct stasis_caching_topic *caching_topic);
-
-/*!
- * \brief Returns the topic of cached events from a caching topics.
- * \param caching_topic The caching topic.
- * \return The topic that publishes cache update events, along with passthrough
- *         events from the underlying topic.
- * \return \c NULL if \a caching_topic is \c NULL.
- * \since 12
- */
-struct stasis_topic *stasis_caching_get_topic(
-	struct stasis_caching_topic *caching_topic);
-
-/*!
- * \brief A message which instructs the caching topic to remove an entry from
- * its cache.
- *
- * \param message Message representative of the cache entry that should be
- *                cleared. This will become the data held in the
- *                stasis_cache_clear message.
- *
- * \return Message which, when sent to a \ref stasis_caching_topic, will clear
- *         the item from the cache.
- * \return \c NULL on error.
- * \since 12
- */
-struct stasis_message *stasis_cache_clear_create(struct stasis_message *message);
-
-/*!
- * \brief Retrieve an item from the cache for the ast_eid_default entity.
- *
- * The returned item is AO2 managed, so ao2_cleanup() when you're done with it.
- *
- * \param cache The cache to query.
- * \param type Type of message to retrieve.
- * \param id Identity of the snapshot to retrieve.
- *
- * \retval Message from the cache.
- * \retval \c NULL if message is not found.
- *
- * \since 12
- */
-struct stasis_message *stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id);
-
-/*!
- * \brief Retrieve an item from the cache for a specific entity.
- *
- * The returned item is AO2 managed, so ao2_cleanup() when you're done with it.
- *
- * \param cache The cache to query.
- * \param type Type of message to retrieve.
- * \param id Identity of the snapshot to retrieve.
- * \param eid Specific entity id to retrieve.  NULL for aggregate.
- *
- * \note An aggregate message is a combined representation of the local
- * and remote entities publishing the message data.  e.g., An aggregate
- * device state represents the combined device state from the local and
- * any remote entities publishing state for a device.  e.g., An aggregate
- * MWI message is the old/new MWI counts accumulated from the local and
- * any remote entities publishing to a mailbox.
- *
- * \retval Message from the cache.
- * \retval \c NULL if message is not found.
- *
- * \since 12.2.0
- */
-struct stasis_message *stasis_cache_get_by_eid(struct stasis_cache *cache, struct stasis_message_type *type, const char *id, const struct ast_eid *eid);
-
-/*!
- * \brief Retrieve all matching entity items from the cache.
- * \since 12.2.0
- *
- * \param cache The cache to query.
- * \param type Type of message to retrieve.
- * \param id Identity of the snapshot to retrieve.
- *
- * \retval Container of matching items found.
- * \retval \c NULL if error.
- */
-struct ao2_container *stasis_cache_get_all(struct stasis_cache *cache, struct stasis_message_type *type, const char *id);
-
-/*!
- * \brief Dump cached items to a subscription for the ast_eid_default entity.
- *
- * \param cache The cache to query.
- * \param type Type of message to dump (any type if \c NULL).
- *
- * \retval ao2_container containing all matches (must be unreffed by caller)
- * \retval \c NULL on allocation error
- *
- * \since 12
- */
-struct ao2_container *stasis_cache_dump(struct stasis_cache *cache, struct stasis_message_type *type);
-
-/*!
- * \brief Dump cached items to a subscription for a specific entity.
- * \since 12.2.0
- *
- * \param cache The cache to query.
- * \param type Type of message to dump (any type if \c NULL).
- * \param eid Specific entity id to retrieve.  NULL for aggregate.
- *
- * \retval ao2_container containing all matches (must be unreffed by caller)
- * \retval \c NULL on allocation error
- */
-struct ao2_container *stasis_cache_dump_by_eid(struct stasis_cache *cache, struct stasis_message_type *type, const struct ast_eid *eid);
-
-/*!
- * \brief Dump all entity items from the cache to a subscription.
- * \since 12.2.0
- *
- * \param cache The cache to query.
- * \param type Type of message to dump (any type if \c NULL).
- *
- * \retval ao2_container containing all matches (must be unreffed by caller)
- * \retval \c NULL on allocation error
- */
-struct ao2_container *stasis_cache_dump_all(struct stasis_cache *cache, struct stasis_message_type *type);
-
-/*!
- * \brief Object type code for multi user object snapshots
- */
-enum stasis_user_multi_object_snapshot_type {
-	STASIS_UMOS_CHANNEL = 0,     /*!< Channel Snapshots */
-	STASIS_UMOS_BRIDGE,          /*!< Bridge Snapshots */
-	STASIS_UMOS_ENDPOINT,        /*!< Endpoint Snapshots */
-};
-
-/*! \brief Number of snapshot types */
-#define STASIS_UMOS_MAX (STASIS_UMOS_ENDPOINT + 1)
-
-/*!
- * \brief Message type for custom user defined events with multi object blobs
- * \return The stasis_message_type for user event
- * \since 12.3.0
- */
-struct stasis_message_type *ast_multi_user_event_type(void);
-
-/*!
- * \brief Create a stasis multi object blob
- * \since 12.3.0
- *
- * \details
- * Multi object blob can store a combination of arbitrary json values
- * (the blob) and also snapshots of various other system objects (such
- * as channels, bridges, etc) for delivery through a stasis message.
- * The multi object blob is first created, then optionally objects
- * are added to it, before being attached to a message and delivered
- * to stasis topic.
- *
- * \param blob Json blob
- *
- * \note When used for an ast_multi_user_event_type message, the
- * json blob should contain at minimum {eventname: name}.
- *
- * \retval ast_multi_object_blob* if succeeded
- * \retval NULL if creation failed
- */
-struct ast_multi_object_blob *ast_multi_object_blob_create(struct ast_json *blob);
-
-/*!
- * \brief Add an object to a multi object blob previously created
- * \since 12.3.0
- *
- * \param multi The multi object blob previously created
- * \param type Type code for the object such as channel, bridge, etc.
- * \param object Snapshot object of the type supplied to typename
- *
- * \return Nothing
- */
-void ast_multi_object_blob_add(struct ast_multi_object_blob *multi, enum stasis_user_multi_object_snapshot_type type, void *object);
-
-/*!
- * \brief Create and publish a stasis message blob on a channel with it's snapshot
- * \since 12.3.0
- *
- * \details
- * For compatibility with app_userevent, this creates a multi object
- * blob message, attaches the channel snapshot to it, and publishes it
- * to the channel's topic.
- *
- * \param chan The channel to snapshot and publish event to
- * \param type The message type
- * \param blob A json blob to publish with the snapshot
- *
- * \return Nothing
- */
-void ast_multi_object_blob_single_channel_publish(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob);
-
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \internal
- * \brief Log a message about invalid attempt to access a type.
- */
-void stasis_log_bad_type_access(const char *name);
-
-/*!
- * \brief Boiler-plate messaging macro for defining public message types.
- *
- * \code
- *	STASIS_MESSAGE_TYPE_DEFN(ast_foo_type,
- *		.to_ami = foo_to_ami,
- *		.to_json = foo_to_json,
- *		.to_event = foo_to_event,
- *		);
- * \endcode
- *
- * \param name Name of message type.
- * \param ... Virtual table methods for messages of this type.
- * \since 12
- */
-#define STASIS_MESSAGE_TYPE_DEFN(name, ...)				\
-	static struct stasis_message_vtable _priv_ ## name ## _v = {	\
-		__VA_ARGS__						\
-	};								\
-	static struct stasis_message_type *_priv_ ## name;		\
-	struct stasis_message_type *name(void) {			\
-		if (_priv_ ## name == NULL) {				\
-			stasis_log_bad_type_access(#name);		\
-		}							\
-		return _priv_ ## name;					\
-	}
-
-/*!
- * \brief Boiler-plate messaging macro for defining local message types.
- *
- * \code
- *	STASIS_MESSAGE_TYPE_DEFN_LOCAL(ast_foo_type,
- *		.to_ami = foo_to_ami,
- *		.to_json = foo_to_json,
- *		.to_event = foo_to_event,
- *		);
- * \endcode
- *
- * \param name Name of message type.
- * \param ... Virtual table methods for messages of this type.
- * \since 12
- */
-#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name, ...)			\
-	static struct stasis_message_vtable _priv_ ## name ## _v = {	\
-		__VA_ARGS__						\
-	};								\
-	static struct stasis_message_type *_priv_ ## name;		\
-	static struct stasis_message_type *name(void) {			\
-		if (_priv_ ## name == NULL) {				\
-			stasis_log_bad_type_access(#name);		\
-		}							\
-		return _priv_ ## name;					\
-	}
-
-/*!
-* \brief Boiler-plate messaging macro for initializing message types.
- *
- * \code
- *	if (STASIS_MESSAGE_TYPE_INIT(ast_foo_type) != 0) {
- *		return -1;
- *	}
- * \endcode
- *
- * \param name Name of message type.
- * \return 0 if initialization is successful.
- * \return Non-zero on failure.
- * \since 12
- */
-#define STASIS_MESSAGE_TYPE_INIT(name)					\
-	({								\
-		ast_assert(_priv_ ## name == NULL);			\
-		stasis_message_type_create(#name,	\
-			&_priv_ ## name ## _v, &_priv_ ## name) == STASIS_MESSAGE_TYPE_ERROR ? 1 : 0;	\
-	})
-
-/*!
- * \brief Boiler-plate messaging macro for cleaning up message types.
- *
- * Note that if your type is defined in core instead of a loadable module, you
- * should call message type cleanup from an ast_register_cleanup() handler
- * instead of an ast_register_atexit() handler.
- *
- * The reason is that during an immediate shutdown, loadable modules (which may
- * refer to core message types) are not unloaded. While the atexit handlers are
- * run, there's a window of time where a module subscription might reference a
- * core message type after it's been cleaned up. Which is bad.
- *
- * \param name Name of message type.
- * \since 12
- */
-#define STASIS_MESSAGE_TYPE_CLEANUP(name)	\
-	({					\
-		ao2_cleanup(_priv_ ## name);	\
-		_priv_ ## name = NULL;		\
-	})
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \brief Initialize the Stasis subsystem.
- * \return 0 on success.
- * \return Non-zero on error.
- * \since 12
- */
-int stasis_init(void);
-
-/*! @} */
-
-/*! @{ */
-
-/*!
- * \internal
- * \brief called by stasis_init() for cache initialization.
- * \return 0 on success.
- * \return Non-zero on error.
- * \since 12
- */
-int stasis_cache_init(void);
-
-/*!
- * \internal
- * \brief called by stasis_init() for config initialization.
- * \return 0 on success.
- * \return Non-zero on error.
- * \since 12
- */
-int stasis_config_init(void);
-
-/*! @} */
-
-/*!
- * \defgroup StasisTopicsAndMessages Stasis topics, and their messages.
- *
- * This group contains the topics, messages and corresponding message types
- * found within Asterisk.
- */
-
-#endif /* _ASTERISK_STASIS_H */
diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h
deleted file mode 100644
index e472754..0000000
--- a/include/asterisk/stasis_app.h
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_H
-#define _ASTERISK_STASIS_APP_H
-
-/*! \file
- *
- * \brief Stasis Application API. See \ref res_stasis "Stasis Application API"
- * for detailed documentation.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- *
- * \page res_stasis Stasis Application API
- *
- * This is the API that binds the Stasis dialplan application to external
- * Stasis applications, such as \c res_stasis_websocket.
- *
- * The associated \c res_stasis module registers a dialplan function named \c
- * Stasis, which uses \c res_stasis to put a channel into the named Stasis
- * app. As a channel enters and leaves the Stasis diaplan application, the
- * Stasis app receives a \c 'stasis-start' and \c 'stasis-end' events.
- *
- * Stasis apps register themselves using the \ref stasis_app_register and
- * stasis_app_unregister functions. Messages are sent to an appliction using
- * \ref stasis_app_send.
- *
- * Finally, Stasis apps control channels through the use of the \ref
- * stasis_app_control object, and the family of \c stasis_app_control_*
- * functions.
- *
- * Since module unload order is based on reference counting, any module that
- * uses the API defined in this file must call stasis_app_ref() when loaded,
- * and stasis_app_unref() when unloaded.
- */
-
-#include "asterisk/channel.h"
-#include "asterisk/json.h"
-
-/*! @{ */
-
-/*!
- * \brief Callback for Stasis application handler.
- *
- * The message given to the handler is a borrowed copy. If you want to keep a
- * reference to it, you should use \c ao2_ref() to keep it around.
- *
- * \param data Data ptr given when registered.
- * \param app_name Name of the application being dispatched to.
- * \param message Message to handle. (borrowed copy)
- */
-typedef void (*stasis_app_cb)(void *data, const char *app_name,
-	struct ast_json *message);
-
-/*!
- * \brief Gets the names of all registered Stasis applications.
- *
- * \return \c ast_str_container of container names.
- * \return \c NULL on error.
- */
-struct ao2_container *stasis_app_get_all(void);
-
-/*!
- * \brief Register a new Stasis application.
- *
- * If an application is already registered with the given name, the old
- * application is sent a 'replaced' message and unregistered.
- *
- * \param app_name Name of this application.
- * \param handler Callback for application messages.
- * \param data Data blob to pass to the callback. Must be AO2 managed.
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data);
-
-/*!
- * \brief Unregister a Stasis application.
- * \param app_name Name of the application to unregister.
- */
-void stasis_app_unregister(const char *app_name);
-
-/*!
- * \brief Send a message to the given Stasis application.
- *
- * The message given to the handler is a borrowed copy. If you want to keep a
- * reference to it, you should use \c ao2_ref() to keep it around.
- *
- * \param app_name Name of the application to invoke.
- * \param message Message to send (borrowed reference)
- *
- * \return 0 for success.
- * \return -1 for error.
- */
-int stasis_app_send(const char *app_name, struct ast_json *message);
-
-/*! \brief Forward declare app */
-struct stasis_app;
-
-/*!
- * \brief Retrieve an application's name
- *
- * \param app An application
- *
- * \return The name of the application.
- */
-const char *stasis_app_name(const struct stasis_app *app);
-
-/*!
- * \brief Return the JSON representation of a Stasis application.
- *
- * \param app_name Name of the application.
- *
- * \return JSON representation of app with given name.
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_to_json(const char *app_name);
-
-/*!
- * \brief Event source information and callbacks.
- */
-struct stasis_app_event_source {
-	/*! \brief The scheme to match against on [un]subscribes */
-	const char *scheme;
-
-	/*!
-	 * \brief Find an event source data object by the given id/name.
-	 *
-	 * \param app Application
-	 * \param id A unique identifier to search on
-	 *
-	 * \return The data object associated with the id/name.
-	 */
-	void *(*find)(const struct stasis_app *app, const char *id);
-
-	/*!
-	 * \brief Subscribe an application to an event source.
-	 *
-	 * \param app Application
-	 * \param obj an event source data object
-	 *
-	 * \return 0 on success, failure code otherwise
-	 */
-	int (*subscribe)(struct stasis_app *app, void *obj);
-
-	/*!
-	 * \brief Cancel the subscription an app has to an event source.
-	 *
-	 * \param app Application
-	 * \param id a previously subscribed object id
-	 *
-	 * \return 0 on success, failure code otherwise
-	 */
-	int (*unsubscribe)(struct stasis_app *app, const char *id);
-
-	/*!
-	 * \brief Find an event source by the given id/name.
-	 *
-	 * \param app Application
-	 * \param id A unique identifier to check
-	 *
-	 * \return true if id is subscribed, false otherwise.
-	 */
-	int (*is_subscribed)(struct stasis_app *app, const char *id);
-
-	/*!
-	 * \brief Convert event source data to json
-	 *
-	 * \param app Application
-	 * \param id json object to fill
-	 */
-	void (*to_json)(const struct stasis_app *app, struct ast_json *json);
-
-	/*! Next item in the list */
-	AST_LIST_ENTRY(stasis_app_event_source) next;
-};
-
-/*!
- * \brief Register an application event source.
- *
- * \param obj the event source to register
- */
-void stasis_app_register_event_source(struct stasis_app_event_source *obj);
-
-/*!
- * \brief Register core event sources.
- */
-void stasis_app_register_event_sources(void);
-
-/*!
- * \brief Checks to see if the given object is a core event source
- *
- * \note core event sources are currently only endpoint, bridge, and channel.
- *
- * \param obj event source object to check
- *
- * \return non-zero if core event source, otherwise 0 (false)
-
- */
-int stasis_app_is_core_event_source(struct stasis_app_event_source *obj);
-
-/*!
- * \brief Unregister an application event source.
- *
- * \param obj the event source to unregister
- */
-void stasis_app_unregister_event_source(struct stasis_app_event_source *obj);
-
-/*!
- * \brief Unregister core event sources.
- */
-void stasis_app_unregister_event_sources(void);
-
-/*! \brief Return code for stasis_app_user_event */
-enum stasis_app_user_event_res {
-	STASIS_APP_USER_OK,
-	STASIS_APP_USER_APP_NOT_FOUND,
-	STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND,
-	STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME,
-	STASIS_APP_USER_USEREVENT_INVALID,
-	STASIS_APP_USER_INTERNAL_ERROR,
-};
-
-/*!
- * \brief Generate a Userevent for stasis app (echo to AMI)
- *
- * \param app_name Name of the application to generate event for/to.
- * \param event_name Name of the Userevent.
- * \param source_uris URIs for the source objects to attach to event.
- * \param sources_count Array size of source_uris.
- * \param userevent_data Custom parameters for the user event
- * \param userevents_count Array size of userevent_data
- *
- * \return \ref stasis_app_user_event_res return code.
- */
-enum stasis_app_user_event_res stasis_app_user_event(const char *app_name,
-	const char *event_name,
-	const char **source_uris, int sources_count,
-	struct ast_json *json_variables);
-
-
-/*! \brief Return code for stasis_app_[un]subscribe */
-enum stasis_app_subscribe_res {
-	STASIS_ASR_OK,
-	STASIS_ASR_APP_NOT_FOUND,
-	STASIS_ASR_EVENT_SOURCE_NOT_FOUND,
-	STASIS_ASR_EVENT_SOURCE_BAD_SCHEME,
-	STASIS_ASR_INTERNAL_ERROR,
-};
-
-/*!
- * \brief Subscribes an application to a list of event sources.
- *
- * \param app_name Name of the application to subscribe.
- * \param event_source_uris URIs for the event sources to subscribe to.
- * \param event_sources_count Array size of event_source_uris.
- * \param json Optional output pointer for JSON representation of the app
- *             after adding the subscription.
- *
- * \return \ref stasis_app_subscribe_res return code.
- *
- * \note Do not hold any channel locks if subscribing to a channel.
- */
-enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name,
-	const char **event_source_uris, int event_sources_count,
-	struct ast_json **json);
-
-/*!
- * \brief Unsubscribes an application from a list of event sources.
- *
- * \param app_name Name of the application to subscribe.
- * \param event_source_uris URIs for the event sources to subscribe to.
- * \param event_sources_count Array size of event_source_uris.
- * \param json Optional output pointer for JSON representation of the app
- *             after adding the subscription.
- *
- * \return \ref stasis_app_subscribe_res return code.
- */
-enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name,
-	const char **event_source_uris, int event_sources_count,
-	struct ast_json **json);
-
-/*!
- * \brief Directly subscribe an application to a channel
- *
- * \param app_name Name of the application to subscribe.
- * \param chan The channel to subscribe to
- *
- * \return \ref stasis_app_subscribe_res return code.
- *
- * \note This method can be used when you already hold a channel and its
- *       lock. This bypasses the channel lookup that would normally be
- *       performed by \ref stasis_app_subscribe.
- */
-enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name,
-	struct ast_channel *chan);
-
-/*! @} */
-
-/*! @{ */
-
-/*! \brief Handler for controlling a channel that's in a Stasis application */
-struct stasis_app_control;
-
-/*! \brief Rule to check to see if an operation is allowed */
-struct stasis_app_control_rule {
-	/*!
-	 * \brief Checks to see if an operation is allowed on the control
-	 *
-	 * \param control Control object to check
-	 * \return 0 on success, otherwise a failure code
-	 */
-	enum stasis_app_control_channel_result (*check_rule)(
-		const struct stasis_app_control *control);
-	/*! Next item in the list */
-	AST_LIST_ENTRY(stasis_app_control_rule) next;
-};
-
-/*!
- * \brief Registers an add channel to bridge rule.
- *
- * \param control Control object
- * \param rule The rule to register
- */
-void stasis_app_control_register_add_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule);
-
-/*!
- * \brief UnRegister an add channel to bridge rule.
- *
- * \param control Control object
- * \param rule The rule to unregister
- */
-void stasis_app_control_unregister_add_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule);
-
-/*!
- * \brief Registers a remove channel from bridge rule.
- *
- * \param control Control object
- * \param rule The rule to register
- */
-void stasis_app_control_register_remove_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule);
-
-/*!
- * \brief Unregisters a remove channel from bridge rule.
- *
- * \param control Control object
- * \param rule The rule to unregister
- */
-void stasis_app_control_unregister_remove_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule);
-
-/*!
- * \brief Returns the handler for the given channel.
- * \param chan Channel to handle.
- *
- * \return NULL channel not in Stasis application.
- * \return Pointer to \c res_stasis handler.
- */
-struct stasis_app_control *stasis_app_control_find_by_channel(
-	const struct ast_channel *chan);
-
-/*!
- * \brief Returns the handler for the channel with the given id.
- * \param channel_id Uniqueid of the channel.
- *
- * \return NULL channel not in Stasis application, or channel does not exist.
- * \return Pointer to \c res_stasis handler.
- */
-struct stasis_app_control *stasis_app_control_find_by_channel_id(
-	const char *channel_id);
-
-/*!
- * \brief Creates a control handler for a channel that isn't in a stasis app.
- * \since 12.0.0
- *
- * \param chan Channel to create controller handle for
- *
- * \return NULL on failure to create the handle
- * \return Pointer to \c res_stasis handler.
- */
-struct stasis_app_control *stasis_app_control_create(
-	struct ast_channel *chan);
-
-/*!
- * \brief Act on a stasis app control queue until it is empty
- * \since 12.0.0
- *
- * \param chan Channel to handle
- * \param control Control object to execute
- */
-void stasis_app_control_execute_until_exhausted(
-	struct ast_channel *chan,
-	struct stasis_app_control *control);
-
-/*!
- * \brief Check if a control is marked as done
- * \since 12.2.0
- *
- * \param control Which control object is being evaluated
- */
-int stasis_app_control_is_done(
-	struct stasis_app_control *control);
-
-/*!
- * \brief Returns the uniqueid of the channel associated with this control
- *
- * \param control Control object.
- *
- * \return Uniqueid of the associate channel.
- * \return \c NULL if \a control is \c NULL.
- */
-const char *stasis_app_control_get_channel_id(
-	const struct stasis_app_control *control);
-
-/*!
- * \brief Dial an endpoint and bridge it to a channel in \c res_stasis
- *
- * If the channel is no longer in \c res_stasis, this function does nothing.
- *
- * \param control Control for \c res_stasis
- * \param endpoint The endpoint to dial.
- * \param exten Extension to dial if no endpoint specified.
- * \param context Context to use with extension.
- * \param timeout The amount of time to wait for answer, before giving up.
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten,
-                            const char *context, int timeout);
-
-/*!
- * \brief Apply a bridge role to a channel controlled by a stasis app control
- *
- * \param control Control for \c res_stasis
- * \param role Role to apply
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_control_add_role(struct stasis_app_control *control, const char *role);
-
-/*!
- * \brief Clear bridge roles currently applied to a channel controlled by a stasis app control
- *
- * \param control Control for \c res_stasis
- */
-void stasis_app_control_clear_roles(struct stasis_app_control *control);
-
-/*!
- * \brief Exit \c res_stasis and continue execution in the dialplan.
- *
- * If the channel is no longer in \c res_stasis, this function does nothing.
- *
- * \param control Control for \c res_stasis
- * \param context An optional context to continue to
- * \param extension An optional extension to continue to
- * \param priority An optional priority to continue to
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority);
-
-/*!
- * \brief Indicate ringing to the channel associated with this control.
- *
- * \param control Control for \c res_stasis.
- *
- * \return 0 for success.
- * \return -1 for error.
- */
-int stasis_app_control_ring(struct stasis_app_control *control);
-
-/*!
- * \brief Stop locally generated ringing on the channel associated with this control.
- *
- * \param control Control for \c res_stasis.
- *
- * \return 0 for success.
- * \return -1 for error.
- */
-int stasis_app_control_ring_stop(struct stasis_app_control *control);
-
-/*!
- * \brief Send DTMF to the channel associated with this control.
- *
- * \param control Control for \c res_stasis.
- * \param dtmf DTMF string.
- * \param before Amount of time to wait before sending DTMF digits.
- * \param between Amount of time between each DTMF digit.
- * \param duration Amount of time each DTMF digit lasts for.
- * \param after Amount of time to wait after sending DTMF digits.
- *
- * \return 0 for success.
- * \return -1 for error.
- */
-int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after);
-
-/*!
- * \brief Mute the channel associated with this control.
- *
- * \param control Control for \c res_stasis.
- * \param direction The direction in which the audio should be muted.
- * \param frametype The type of stream that should be muted.
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype);
-
-/*!
- * \brief Unmute the channel associated with this control.
- *
- * \param control Control for \c res_stasis.
- * \param direction The direction in which the audio should be unmuted.
- * \param frametype The type of stream that should be unmuted.
- *
- * \return 0 for success
- * \return -1 for error.
- */
-int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype);
-
-/*!
- * \brief Answer the channel associated with this control.
- * \param control Control for \c res_stasis.
- * \return 0 for success.
- * \return Non-zero for error.
- */
-int stasis_app_control_answer(struct stasis_app_control *control);
-
-/*!
- * \brief Set a variable on the channel associated with this control to value.
- * \param control Control for \c res_stasis.
- * \param variable The name of the variable
- * \param value The value to set the variable to
- *
- * \return 0 for success.
- * \return -1 for error.
- */
-int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value);
-
-/*!
- * \brief Place the channel associated with the control on hold.
- * \param control Control for \c res_stasis.
- */
-void stasis_app_control_hold(struct stasis_app_control *control);
-
-/*!
- * \brief Remove the channel associated with the control from hold.
- * \param control Control for \c res_stasis.
- */
-void stasis_app_control_unhold(struct stasis_app_control *control);
-
-/*!
- * \brief Play music on hold to a channel (does not affect hold status)
- * \param control Control for \c res_stasis.
- * \param moh_class class of music on hold to play (NULL allowed)
- */
-void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class);
-
-/*!
- * \brief Stop playing music on hold to a channel (does not affect hold status)
- * \param control Control for \c res_stasis.
- */
-void stasis_app_control_moh_stop(struct stasis_app_control *control);
-
-/*!
- * \brief Start playing silence to a channel.
- * \param control Control for \c res_stasis.
- */
-void stasis_app_control_silence_start(struct stasis_app_control *control);
-
-/*!
- * \brief Stop playing silence to a channel.
- * \param control Control for \c res_stasis.
- */
-void stasis_app_control_silence_stop(struct stasis_app_control *control);
-
-/*!
- * \brief Returns the most recent snapshot for the associated channel.
- *
- * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.
- *
- * \param control Control for \c res_stasis.
- *
- * \return Most recent snapshot. ao2_cleanup() when done.
- * \return \c NULL if channel isn't in cache.
- */
-struct ast_channel_snapshot *stasis_app_control_get_snapshot(
-	const struct stasis_app_control *control);
-
-/*!
- * \brief Publish a message to the \a control's channel's topic.
- *
- * \param control Control to publish to
- * \param message Message to publish
- */
-void stasis_app_control_publish(
-	struct stasis_app_control *control, struct stasis_message *message);
-
-/*!
- * \brief Returns the stasis topic for an app
- *
- * \param app Stasis app to get topic of
- */
-struct stasis_topic *ast_app_get_topic(struct stasis_app *app);
-
-/*!
- * \brief Queue a control frame without payload.
- *
- * \param control Control to publish to.
- * \param frame_type type of control frame.
- *
- * \return zero on success
- * \return non-zero on failure
- */
-int stasis_app_control_queue_control(struct stasis_app_control *control,
-	enum ast_control_frame_type frame_type);
-
-/*!
- * \brief Create a bridge of the specified type.
- *
- * \param type The type of bridge to be created
- * \param name Optional name to give to the bridge
- * \param id Optional Unique ID to give to the bridge
- *
- * \return New bridge.
- * \return \c NULL on error.
- */
-struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id);
-
-/*!
- * \brief Returns the bridge with the given id.
- * \param bridge_id Uniqueid of the bridge.
- *
- * \return NULL bridge not created by a Stasis application, or bridge does not exist.
- * \return Pointer to bridge.
- */
-struct ast_bridge *stasis_app_bridge_find_by_id(
-	const char *bridge_id);
-
-/*!
- * \brief Finds or creates an announcer channel in a bridge that can play music on hold.
- *
- * \param bridge Bridge we want an MOH channel for
- *
- * \return NULL if the music on hold channel fails to be created or join the bridge for any reason.
- * \return Pointer to the ;1 end of the announcer channel chain.
- */
-struct ast_channel *stasis_app_bridge_moh_channel(
-	struct ast_bridge *bridge);
-
-/*!
- * \brief Breaks down MOH channels playing on the bridge created by stasis_app_bridge_moh_channel
- *
- * \param bridge Bridge we want to stop the MOH on
- *
- * \return -1 if no moh channel could be found and stopped
- * \return 0 on success
- */
-int stasis_app_bridge_moh_stop(
-	struct ast_bridge *bridge);
-
-/*!
- * \brief Finds an existing ARI playback channel in a bridge
- *
- * \param bridge Bridge we want to find the playback channel for
- *
- * \return NULL if the playback channel can not be found for any reason.
- * \return Pointer to the ;1 end of the playback channel chain.
- */
-struct ast_channel *stasis_app_bridge_playback_channel_find(
-	struct ast_bridge *bridge);
-
-/*!
- * \brief Adds a channel to the list of ARI playback channels for bridges.
- *
- * \param bridge Bridge we are adding the playback channel for
- * \param chan Channel being added as a playback channel (must be ;1)
- *
- * \retval -1 failed to add channel for any reason
- * \retval 0 on success
- */
-int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct stasis_app_control *control);
-
-/*!
- * \brief Result codes used when adding/removing channels to/from bridges.
- */
-enum stasis_app_control_channel_result {
-	/*! The channel is okay to be added/removed */
-	STASIS_APP_CHANNEL_OKAY = 0,
-	/*! The channel is currently recording */
-	STASIS_APP_CHANNEL_RECORDING
-};
-
-/*!
- * \brief Add a channel to the bridge.
- *
- * \param control Control whose channel should be added to the bridge
- * \param bridge Pointer to the bridge
- *
- * \return non-zero on failure
- * \return zero on success
- */
-int stasis_app_control_add_channel_to_bridge(
-	struct stasis_app_control *control, struct ast_bridge *bridge);
-
-/*!
- * \brief Remove a channel from the bridge.
- *
- * \param control Control whose channel should be removed from the bridge
- * \param bridge Pointer to the bridge
- *
- * \return non-zero on failure
- * \return zero on success
- */
-int stasis_app_control_remove_channel_from_bridge(
-	struct stasis_app_control *control, struct ast_bridge *bridge);
-
-/*!
- * \since 12
- * \brief Gets the bridge currently associated with a control object.
- *
- * \note If the bridge returned by this function is to be held for any
- *       length of time, its refcount should be incremented until the
- *       caller is finished with it.
- *
- * \param control Control object for the channel to query.
- *
- * \return Associated \ref ast_bridge.
- * \return \c NULL if not associated with a bridge.
- */
-struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control);
-
-/*!
- * \brief Destroy the bridge.
- *
- * \param bridge_id Uniqueid of bridge to be destroyed
- *
- * \retval non-zero on failure
- * \retval zero on success
- */
-void stasis_app_bridge_destroy(const char *bridge_id);
-
-/*!
- * \brief Increment the res_stasis reference count.
- *
- * This ensures graceful shutdown happens in the proper order.
- */
-void stasis_app_ref(void);
-
-/*!
- * \brief Decrement the res_stasis reference count.
- *
- * This ensures graceful shutdown happens in the proper order.
- */
-void stasis_app_unref(void);
-
-/*!
- * \brief Get the Stasis message sanitizer for app_stasis applications
- *
- * \retval The stasis message sanitizer
- */
-struct stasis_message_sanitizer *stasis_app_get_sanitizer(void);
-
-/*!
- * \brief Indicate that this channel has had a StasisEnd published for it
- *
- * \param The channel that is exiting Stasis.
- */
-void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan);
-
-/*!
- * \brief Has this channel had a StasisEnd published on it?
- *
- * \param chan The channel upon which the query rests.
- *
- * \retval 0 No
- * \retval 1 Yes
- */
-int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan);
-
-/*!
- * \brief Is this channel internal to Stasis?
- *
- * \param chan The channel to check.
- *
- * \retval 0 No
- * \retval 1 Yes
- */
-int stasis_app_channel_is_internal(struct ast_channel *chan);
-
-/*!
- * \brief Mark this unreal channel and it's other half as being internal to Stasis.
- *
- * \param chan The channel to mark.
- *
- * \retval zero Success
- * \retval non-zero Failure
- */
-int stasis_app_channel_unreal_set_internal(struct ast_channel *chan);
-
-/*!
- * \brief Mark this channel as being internal to Stasis.
- *
- * \param chan The channel to mark.
- *
- * \retval zero Success
- * \retval non-zero Failure
- */
-int stasis_app_channel_set_internal(struct ast_channel *chan);
-
-/*! @} */
-
-#endif /* _ASTERISK_STASIS_APP_H */
diff --git a/include/asterisk/stasis_app_device_state.h b/include/asterisk/stasis_app_device_state.h
deleted file mode 100644
index 2bc521a..0000000
--- a/include/asterisk/stasis_app_device_state.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_DEVICE_STATE_H
-#define _ASTERISK_STASIS_APP_DEVICE_STATE_H
-
-/*! \file
- *
- * \brief Stasis Application Device State API. See \ref res_stasis "Stasis
- * Application API" for detailed documentation.
- *
- * \author Kevin Harwell <kharwell at digium.com>
- * \since 12
- */
-
-#include "asterisk/app.h"
-#include "asterisk/stasis_app.h"
-
-/*! @{ */
-
-/*!
- * \brief Convert device state to json.
- *
- * \param name the name of the device
- * \param state the device state
- * \return JSON representation.
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_device_state_to_json(
-	const char *name, enum ast_device_state state);
-
-/*!
- * \brief Convert device states to json array.
- *
- * \return JSON representation.
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_device_states_to_json(void);
-
-/*! Stasis device state application result codes */
-enum stasis_device_state_result {
-	/*! Application controlled device state is okay */
-	STASIS_DEVICE_STATE_OK,
-	/*! The device name is not application controlled */
-	STASIS_DEVICE_STATE_NOT_CONTROLLED,
-	/*! The application controlled device name is missing */
-	STASIS_DEVICE_STATE_MISSING,
-	/*! The application controlled device is unknown */
-	STASIS_DEVICE_STATE_UNKNOWN,
-	/*! The application controlled device has subscribers */
-	STASIS_DEVICE_STATE_SUBSCRIBERS
-};
-
-/*!
- * \brief Changes the state of a device controlled by ARI.
- *
- * \note The controlled device must be prefixed with 'Stasis:'.
- * \note Implicitly creates the device state.
- *
- * \param name the name of the ARI controlled device
- * \param value a valid device state value
- *
- * \return a stasis device state application result.
- */
-enum stasis_device_state_result stasis_app_device_state_update(
-	const char *name, const char *value);
-
-/*!
- * \brief Delete a device controlled by ARI.
- *
- * \param name the name of the ARI controlled device
- *
- * \returna stasis device state application result.
- */
-enum stasis_device_state_result stasis_app_device_state_delete(
-	const char *name);
-
-/*! @} */
-
-#endif /* _ASTERISK_STASIS_APP_DEVICE_STATE_H */
diff --git a/include/asterisk/stasis_app_impl.h b/include/asterisk/stasis_app_impl.h
deleted file mode 100644
index ce60804..0000000
--- a/include/asterisk/stasis_app_impl.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_H
-#define _ASTERISK_RES_STASIS_H
-
-/*! \file
- *
- * \brief Backend API for implementing components of res_stasis.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- *
- * This file defines functions useful for defining new commands to execute
- * on channels while they are in Stasis.
- */
-
-#include "asterisk/stasis_app.h"
-
-/*!
- * \since 12
- * \brief Control a channel using \c stasis_app.
- *
- * This function blocks until the channel hangs up, or
- * stasis_app_control_continue() is called on the channel's \ref
- * stasis_app_control struct.
- *
- * \param chan Channel to control with Stasis.
- * \param app_name Application controlling the channel.
- * \param argc Number of arguments for the application.
- * \param argv Arguments for the application.
- */
-int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
-	char *argv[]);
-
-/*!
- * \brief Typedef for data destructor for stasis app commands
- *
- * \param data Data to destroy.
- *
- * \details
- * This is called during destruction of the command or if we fail to schedule
- * a command. It is passed a pointer to the user-defined data of the command.
- *
- * \return Nothing
- */
-typedef void (*command_data_destructor_fn)(void *data);
-
-/*! Callback type for stasis app commands */
-typedef int (*stasis_app_command_cb)(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data);
-
-/*!
- * \since 12
- * \brief Invokes a \a command on a \a control's channel.
- *
- * This function dispatches the command to be executed in the context of
- * stasis_app_exec(), so this command will block waiting for the results of
- * the command.
- *
- * \param control Control object for the channel to send the command to.
- * \param command Command function to execute.
- * \param data Optional data to pass along with the control function.
- * \param data_destructor Optional function which will be called on
- *        the data in either the event of command completion or failure
- *        to schedule or complete the command
- *
- * \return zero on success.
- * \return error code otherwise.
- */
-int stasis_app_send_command(struct stasis_app_control *control,
-	stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor);
-
-/*!
- * \since 12
- * \brief Asynchronous version of stasis_app_send_command().
- *
- * This function enqueues a command for execution, but returns immediately
- * without waiting for the response.
- *
- * \param control Control object for the channel to send the command to.
- * \param command Command function to execute.
- * \param data Optional data to pass along with the control function.
- * \param data_destructor Optional function which will be called on
- *        the data in either the event of command completion or failure
- *        to schedule or complete the command
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int stasis_app_send_command_async(struct stasis_app_control *control,
-	stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor);
-
-#endif /* _ASTERISK_RES_STASIS_H */
diff --git a/include/asterisk/stasis_app_mailbox.h b/include/asterisk/stasis_app_mailbox.h
deleted file mode 100644
index f2a0a56..0000000
--- a/include/asterisk/stasis_app_mailbox.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_MAILBOX_H
-#define _ASTERISK_STASIS_APP_MAILBOX_H
-
-/*! \file
- *
- * \brief Stasis Application Mailbox API. See \ref res_stasis "Stasis
- * Application API" for detailed documentation.
- *
- * \author Jonathan Rose <kharwell at digium.com>
- * \since 12
- */
-
-#include "asterisk/app.h"
-#include "asterisk/stasis_app.h"
-
-/*! @{ */
-
-/*! Stasis mailbox operation result codes */
-enum stasis_mailbox_result {
-	/*! Mailbox operation completed successfully */
-	STASIS_MAILBOX_OK,
-	/*! Mailbox of the requested name does not exist */
-	STASIS_MAILBOX_MISSING,
-	/*! Mailbox operation failed internally */
-	STASIS_MAILBOX_ERROR,
-};
-
-/*!
- * \brief Convert mailbox to JSON
- *
- * \param name the name of the mailbox
- * \param json If the query is successful, this pointer at this address will
- *        be set to the JSON representation of the mailbox
- *
- * \return stasis mailbox result code indicating success or failure and cause
- * \return \c NULL on error.
- */
-enum stasis_mailbox_result stasis_app_mailbox_to_json(const char *name, struct ast_json **json);
-
-/*!
- * brief Convert mailboxes to json array
- *
- * \return JSON representation of the mailboxes
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_mailboxes_to_json(void);
-
-/*!
- * \brief Changes the state of a mailbox.
- *
- * \note Implicitly creates the mailbox.
- *
- * \param name The name of the ARI controlled mailbox
- * \param old_messages count of old (read) messages in the mailbox
- * \param new_messages count of new (unread) messages in the mailbox
- *
- * \return 0 if successful
- * \return -1 on internal error.
- */
-int stasis_app_mailbox_update(
-	const char *name, int old_messages, int new_messages);
-
-/*!
- * \brief Delete a mailbox controlled by ARI.
- *
- * \param name the name of the ARI controlled mailbox
- *
- * \return a stasis mailbox application result
- */
-enum stasis_mailbox_result stasis_app_mailbox_delete(
-	const char *name);
-
-#endif /* _ASTERISK_STASIS_APP_MAILBOX_H */
diff --git a/include/asterisk/stasis_app_playback.h b/include/asterisk/stasis_app_playback.h
deleted file mode 100644
index b352995..0000000
--- a/include/asterisk/stasis_app_playback.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_PLAYBACK_H
-#define _ASTERISK_STASIS_APP_PLAYBACK_H
-
-/*! \file
- *
- * \brief Stasis Application Playback API. See \ref res_stasis "Stasis
- * Application API" for detailed documentation.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/stasis_app.h"
-
-/*! Opaque struct for handling the playback of a single file */
-struct stasis_app_playback;
-
-/*! State of a playback operation */
-enum stasis_app_playback_state {
-	/*! The playback has not started yet */
-	STASIS_PLAYBACK_STATE_QUEUED,
-	/*! The media is currently playing */
-	STASIS_PLAYBACK_STATE_PLAYING,
-	/*! The media is currently playing */
-	STASIS_PLAYBACK_STATE_PAUSED,
-	/*! The media has stopped playing */
-	STASIS_PLAYBACK_STATE_COMPLETE,
-	/*! The playback was canceled. */
-	STASIS_PLAYBACK_STATE_CANCELED,
-	/*! The playback was stopped. */
-	STASIS_PLAYBACK_STATE_STOPPED,
-	/*! Enum end sentinel. */
-	STASIS_PLAYBACK_STATE_MAX,
-};
-
-/*! Valid operation for controlling a playback. */
-enum stasis_app_playback_media_operation {
-	/*! Stop the playback operation. */
-	STASIS_PLAYBACK_STOP,
-	/*! Restart the media from the beginning. */
-	STASIS_PLAYBACK_RESTART,
-	/*! Pause playback. */
-	STASIS_PLAYBACK_PAUSE,
-	/*! Resume paused playback. */
-	STASIS_PLAYBACK_UNPAUSE,
-	/*! Rewind playback. */
-	STASIS_PLAYBACK_REVERSE,
-	/*! Fast forward playback. */
-	STASIS_PLAYBACK_FORWARD,
-	/*! Enum end sentinel. */
-	STASIS_PLAYBACK_MEDIA_OP_MAX,
-};
-
-enum stasis_app_playback_target_type {
-	/*! The target is a channel */
-	STASIS_PLAYBACK_TARGET_CHANNEL = 0,
-	/*! The target is a bridge */
-	STASIS_PLAYBACK_TARGET_BRIDGE,
-};
-
-/*!
- * \brief Play a file to the control's channel.
- *
- * Note that the file isn't the full path to the file. Asterisk's internal
- * playback mechanism will automagically select the best format based on the
- * available codecs for the channel.
- *
- * \param control Control for \c res_stasis.
- * \param file Base filename for the file to play.
- * \param language Selects the file based on language.
- * \param target_id ID of the target bridge or channel.
- * \param target_type What the target type is
- * \param skipms Number of milliseconds to skip for forward/reverse operations.
- * \param offsetms Number of milliseconds to skip before playing.
- * \param id ID to assign the new playback or NULL for default.
- * \return Playback control object.
- * \return \c NULL on error.
- */
-struct stasis_app_playback *stasis_app_control_play_uri(
-	struct stasis_app_control *control, const char *file,
-	const char *language, const char *target_id,
-	enum stasis_app_playback_target_type target_type,
-	int skipms, long offsetms, const char *id);
-
-/*!
- * \brief Gets the current state of a playback operation.
- *
- * \param playback Playback control object.
- * \return The state of the \a playback object.
- */
-enum stasis_app_playback_state stasis_app_playback_get_state(
-	struct stasis_app_playback *playback);
-
-/*!
- * \brief Gets the unique id of a playback object.
- *
- * \param playback Playback control object.
- * \return \a playback's id.
- * \return \c NULL if \a playback ic \c NULL
- */
-const char *stasis_app_playback_get_id(
-	struct stasis_app_playback *playback);
-
-/*!
- * \brief Finds the playback object with the given id.
- *
- * \param id Id of the playback object to find.
- * \return Associated \ref stasis_app_playback object.
- * \return \c NULL if \a id not found.
- */
-struct stasis_app_playback *stasis_app_playback_find_by_id(const char *id);
-
-struct ast_json *stasis_app_playback_to_json(
-	const struct stasis_app_playback *playback);
-
-enum stasis_playback_oper_results {
-	STASIS_PLAYBACK_OPER_OK,
-	STASIS_PLAYBACK_OPER_FAILED,
-	STASIS_PLAYBACK_OPER_NOT_PLAYING,
-};
-/*!
- * \brief Controls the media for a given playback operation.
- *
- * \param playback Playback control object.
- * \param control Media control operation.
- * \return \c STASIS_PLAYBACK_OPER_OK on success.
- * \return \ref stasis_playback_oper_results indicating failure.
- */
-enum stasis_playback_oper_results stasis_app_playback_operation(
-	struct stasis_app_playback *playback,
-	enum stasis_app_playback_media_operation operation);
-
-/*!
- * \brief Message type for playback updates. The data is an
- * \ref ast_channel_blob.
- */
-struct stasis_message_type *stasis_app_playback_snapshot_type(void);
-
-#endif /* _ASTERISK_STASIS_APP_PLAYBACK_H */
diff --git a/include/asterisk/stasis_app_recording.h b/include/asterisk/stasis_app_recording.h
deleted file mode 100644
index 543207a..0000000
--- a/include/asterisk/stasis_app_recording.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_RECORDING_H
-#define _ASTERISK_STASIS_APP_RECORDING_H
-
-/*! \file
- *
- * \brief Stasis Application Recording API. See \ref res_stasis "Stasis
- * Application API" for detailed documentation.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/app.h"
-#include "asterisk/stasis_app.h"
-
-/*! @{ */
-
-/*! \brief Structure representing a recording stored on disk */
-struct stasis_app_stored_recording;
-
-/*!
- * \brief Returns the filename for this recording, for use with streamfile.
- *
- * The returned string will be valid until the \a recording object is freed.
- *
- * \param recording Recording to query.
- * \return Absolute path to the recording file, without the extension.
- * \return \c NULL on error.
- */
-const char *stasis_app_stored_recording_get_file(
-	struct stasis_app_stored_recording *recording);
-
-/*!
- * \brief Convert stored recording info to JSON.
- *
- * \param recording Recording to convert.
- * \return JSON representation.
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_stored_recording_to_json(
-	struct stasis_app_stored_recording *recording);
-
-/*!
- * \brief Find all stored recordings on disk.
- *
- * \return Container of \ref stasis_app_stored_recording objects.
- * \return \c NULL on error.
- */
-struct ao2_container *stasis_app_stored_recording_find_all(void);
-
-/*!
- * \brief Creates a stored recording object, with the given name.
- *
- * \param name Name of the recording.
- * \return New recording object.
- * \return \c NULL if recording is not found. \c errno is set to indicate why
- *	- \c ENOMEM - out of memeory
- *	- \c EACCES - file permissions (or recording is outside the config dir)
- *	- Any of the error codes for stat(), opendir(), readdir()
- */
-struct stasis_app_stored_recording *stasis_app_stored_recording_find_by_name(
-	const char *name);
-
-/*!
- * \brief Copy a recording.
- *
- * \param src_recording The recording to copy
- * \param dst The destination of the recording to make
- * \param dst_recording If successful, the stored recording created as a result of the copy
- *
- * \retval 0 on success
- * \retval Non-zero on error
- */
-int stasis_app_stored_recording_copy(struct stasis_app_stored_recording *src_recording, const char *dst,
-	struct stasis_app_stored_recording **dst_recording);
-
-/*!
- * \brief Delete a recording from disk.
- *
- * \param recording Recording to delete.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int stasis_app_stored_recording_delete(
-	struct stasis_app_stored_recording *recording);
-
-/*! @} */
-
-/*! @{ */
-
-/*! Opaque struct for handling the recording of media to a file. */
-struct stasis_app_recording;
-
-/*! State of a recording operation */
-enum stasis_app_recording_state {
-	/*! The recording has not started yet */
-	STASIS_APP_RECORDING_STATE_QUEUED,
-	/*! The media is currently recording */
-	STASIS_APP_RECORDING_STATE_RECORDING,
-	/*! The media is currently paused */
-	STASIS_APP_RECORDING_STATE_PAUSED,
-	/*! The media has stopped recording */
-	STASIS_APP_RECORDING_STATE_COMPLETE,
-	/*! The media has stopped recording, with error */
-	STASIS_APP_RECORDING_STATE_FAILED,
-	/*! The media has stopped recording, discard the recording file */
-	STASIS_APP_RECORDING_STATE_CANCELED,
-	/*! Sentinel */
-	STASIS_APP_RECORDING_STATE_MAX,
-};
-
-/*! Valid operation for controlling a recording. */
-enum stasis_app_recording_media_operation {
-	/*! Stop the recording, deleting the media file(s) */
-	STASIS_APP_RECORDING_CANCEL,
-	/*! Stop the recording. */
-	STASIS_APP_RECORDING_STOP,
-	/*! Pause the recording */
-	STASIS_APP_RECORDING_PAUSE,
-	/*! Unpause the recording */
-	STASIS_APP_RECORDING_UNPAUSE,
-	/*! Mute the recording (record silence) */
-	STASIS_APP_RECORDING_MUTE,
-	/*! Unmute the recording */
-	STASIS_APP_RECORDING_UNMUTE,
-	/*! Sentinel */
-	STASIS_APP_RECORDING_OPER_MAX,
-};
-
-#define STASIS_APP_RECORDING_TERMINATE_INVALID 0
-#define STASIS_APP_RECORDING_TERMINATE_NONE -1
-#define STASIS_APP_RECORDING_TERMINATE_ANY -2
-
-struct stasis_app_recording_options {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);	/*!< name Name of the recording. */
-		AST_STRING_FIELD(format);	/*!< Format to be recorded (wav, gsm, etc.) */
-		AST_STRING_FIELD(target); /*!< URI of what is being recorded */
-		);
-	/*! Number of seconds of silence before ending the recording. */
-	int max_silence_seconds;
-	/*! Maximum recording duration. 0 for no maximum. */
-	int max_duration_seconds;
-	/*! Which DTMF to use to terminate the recording
-	 *  \c STASIS_APP_RECORDING_TERMINATE_NONE to terminate only on hangup
-	 *  \c STASIS_APP_RECORDING_TERMINATE_ANY to terminate on any DTMF
-	 */
-	char terminate_on;
-	/*! How to handle recording when a file already exists */
-	enum ast_record_if_exists if_exists;
-	/*! If true, a beep is played at the start of recording */
-	int beep:1;
-};
-
-/*!
- * \brief Allocate a recording options object.
- *
- * Clean up with ao2_cleanup().
- *
- * \param name Name of the recording.
- * \param format Format to record in.
- * \return Newly allocated options object.
- * \return \c NULL on error.
- */
-struct stasis_app_recording_options *stasis_app_recording_options_create(
-	const char *name, const char *format);
-
-/*!
- * \brief Parse a string into the recording termination enum.
- *
- * \param str String to parse.
- * \return DTMF value to terminate on.
- * \return \c STASIS_APP_RECORDING_TERMINATE_NONE to not terminate on DTMF.
- * \return \c STASIS_APP_RECORDING_TERMINATE_ANY to terminate on any DTMF.
- * \return \c STASIS_APP_RECORDING_TERMINATE_INVALID if input was invalid.
- */
-char stasis_app_recording_termination_parse(const char *str);
-
-/*!
- * \brief Parse a string into the if_exists enum.
- *
- * \param str String to parse.
- * \return How to handle an existing file.
- * \return -1 on error.
- */
-enum ast_record_if_exists stasis_app_recording_if_exists_parse(
-	const char *str);
-
-/*!
- * \brief Record media from a channel.
- *
- * A reference to the \a options object may be kept, so it MUST NOT be modified
- * after calling this function.
- *
- * On error, \c errno is set to indicate the failure reason.
- *  - \c EINVAL: Invalid input.
- *  - \c EEXIST: A recording with that name is in session.
- *  - \c ENOMEM: Out of memory.
- *
- * \param control Control for \c res_stasis.
- * \param options Recording options.
- * \return Recording control object.
- * \return \c NULL on error.
- */
-struct stasis_app_recording *stasis_app_control_record(
-	struct stasis_app_control *control,
-	struct stasis_app_recording_options *options);
-
-/*!
- * \brief Gets the current state of a recording operation.
- *
- * \param recording Recording control object.
- * \return The state of the \a recording object.
- */
-enum stasis_app_recording_state stasis_app_recording_get_state(
-	struct stasis_app_recording *recording);
-
-/*!
- * \brief Gets the unique name of a recording object.
- *
- * \param recording Recording control object.
- * \return \a recording's name.
- * \return \c NULL if \a recording ic \c NULL
- */
-const char *stasis_app_recording_get_name(
-	struct stasis_app_recording *recording);
-
-/*!
- * \brief Finds the recording object with the given name.
- *
- * \param name Name of the recording object to find.
- * \return Associated \ref stasis_app_recording object.
- * \return \c NULL if \a name not found.
- */
-struct stasis_app_recording *stasis_app_recording_find_by_name(const char *name);
-
-/*!
- * \brief Construct a JSON model of a recording.
- *
- * \param recording Recording to conver.
- * \return JSON model.
- * \return \c NULL on error.
- */
-struct ast_json *stasis_app_recording_to_json(
-	const struct stasis_app_recording *recording);
-
-/*!
- * \brief Possible results from a recording operation.
- */
-enum stasis_app_recording_oper_results {
-	/*! Operation completed successfully. */
-	STASIS_APP_RECORDING_OPER_OK,
-	/*! Operation failed. */
-	STASIS_APP_RECORDING_OPER_FAILED,
-	/*! Operation failed b/c recording is not in session. */
-	STASIS_APP_RECORDING_OPER_NOT_RECORDING,
-};
-
-/*!
- * \brief Controls the media for a given recording operation.
- *
- * \param recording Recording control object.
- * \param control Media control operation.
- * \return \c STASIS_APP_RECORDING_OPER_OK on success.
- * \return \ref stasis_app_recording_oper_results indicating failure.
- */
-enum stasis_app_recording_oper_results stasis_app_recording_operation(
-	struct stasis_app_recording *recording,
-	enum stasis_app_recording_media_operation operation);
-
-/*!
- * \brief Message type for recording updates. The data is an
- * \ref ast_channel_blob.
- */
-struct stasis_message_type *stasis_app_recording_snapshot_type(void);
-
-/*! @} */
-
-#endif /* _ASTERISK_STASIS_APP_RECORDING_H */
diff --git a/include/asterisk/stasis_app_snoop.h b/include/asterisk/stasis_app_snoop.h
deleted file mode 100644
index c261a88..0000000
--- a/include/asterisk/stasis_app_snoop.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_APP_SNOOP_H
-#define _ASTERISK_STASIS_APP_SNOOP_H
-
-/*! \file
- *
- * \brief Stasis Application Snoop API. See \ref res_stasis "Stasis
- * Application API" for detailed documentation.
- *
- * \author Joshua Colp <jcolp at digium.com>
- * \since 12
- */
-
-#include "asterisk/stasis_app.h"
-
-/*! \brief Directions for audio stream flow */
-enum stasis_app_snoop_direction {
-	/*! \brief No direction */
-	STASIS_SNOOP_DIRECTION_NONE = 0,
-	/*! \brief Audio stream out to the channel */
-	STASIS_SNOOP_DIRECTION_OUT,
-	/*! \brief Audio stream in from the channel */
-	STASIS_SNOOP_DIRECTION_IN,
-	/*! \brief Audio stream to AND from the channel */
-	STASIS_SNOOP_DIRECTION_BOTH,
-};
-
-/*!
- * \brief Create a snoop on the provided channel.
- *
- * \param chan Channel to snoop on.
- * \param spy Direction of media that should be spied on.
- * \param whisper Direction of media that should be whispered into.
- * \param app Stasis application to execute on the snoop channel.
- * \param app_args Stasis application arguments.
- * \return Snoop channel. ast_channel_unref() when done.
- * \return \c NULL if snoop channel couldn't be created.
- */
-struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
-	enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
-	const char *app, const char *app_args, const char *snoop_id);
-
-#endif /* _ASTERISK_STASIS_APP_SNOOP_H */
diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h
deleted file mode 100644
index d549e46..0000000
--- a/include/asterisk/stasis_bridges.h
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _STASIS_BRIDGING_H
-#define _STASIS_BRIDGING_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#include "asterisk/stringfields.h"
-#include "asterisk/utils.h"
-#include "asterisk/lock.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/pbx.h"
-
-/*!
- * \brief Structure that contains a snapshot of information about a bridge
- */
-struct ast_bridge_snapshot {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Immutable bridge UUID. */
-		AST_STRING_FIELD(uniqueid);
-		/*! Bridge technology that is handling the bridge */
-		AST_STRING_FIELD(technology);
-		/*! Bridge subclass that is handling the bridge */
-		AST_STRING_FIELD(subclass);
-		/*! Creator of the bridge */
-		AST_STRING_FIELD(creator);
-		/*! Name given to the bridge by its creator */
-		AST_STRING_FIELD(name);
-	);
-	/*! AO2 container of bare channel uniqueid strings participating in the bridge.
-	 * Allocated from ast_str_container_alloc() */
-	struct ao2_container *channels;
-	/*! Bridge flags to tweak behavior */
-	struct ast_flags feature_flags;
-	/*! Bridge capabilities */
-	uint32_t capabilities;
-	/*! Number of channels participating in the bridge */
-	unsigned int num_channels;
-	/*! Number of active channels in the bridge. */
-	unsigned int num_active;
-};
-
-/*!
- * \since 12
- * \brief Generate a snapshot of the bridge state. This is an ao2 object, so
- * ao2_cleanup() to deallocate.
- *
- * \pre Bridge is locked
- *
- * \param bridge The bridge from which to generate a snapshot
- *
- * \retval AO2 refcounted snapshot on success
- * \retval NULL on error
- */
-struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge);
-
-/*!
- * \since 12
- * \brief Message type for \ref ast_bridge_snapshot.
- *
- * \retval Message type for \ref ast_bridge_snapshot.
- */
-struct stasis_message_type *ast_bridge_snapshot_type(void);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for a particular bridge.
- *
- * If the given \a bridge is \c NULL, ast_bridge_topic_all() is returned.
- *
- * \param bridge Bridge for which to get a topic or \c NULL.
- *
- * \retval Topic for bridge's events.
- * \retval ast_bridge_topic_all() if \a bridge is \c NULL.
- */
-struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for a particular bridge.
- *
- * \ref ast_bridge_snapshot messages are replaced with stasis_cache_update
- * messages.
- *
- * If the given \a bridge is \c NULL, ast_bridge_topic_all_cached() is returned.
- *
- * \param bridge Bridge for which to get a topic or \c NULL.
- *
- * \retval Topic for bridge's events.
- * \retval ast_bridge_topic_all() if \a bridge is \c NULL.
- */
-struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for all bridges.
- * \retval Topic for all bridge events.
- */
-struct stasis_topic *ast_bridge_topic_all(void);
-
-/*!
- * \since 12
- * \brief A caching topic which caches \ref ast_bridge_snapshot messages from
- * ast_bridge_events_all(void).
- *
- * \retval Caching topic for all bridge events.
- */
-struct stasis_topic *ast_bridge_topic_all_cached(void);
-
-/*!
- * \since 12
- * \brief Backend cache for ast_bridge_topic_all_cached().
- * \retval Cache of \ref ast_bridge_snapshot.
- */
-struct stasis_cache *ast_bridge_cache(void);
-
-/*!
- * \since 12
- * \brief Publish the state of a bridge
- *
- * \pre Bridge is locked
- *
- * \param bridge The bridge for which to publish state
- */
-void ast_bridge_publish_state(struct ast_bridge *bridge);
-
-/*! \brief Message representing the merge of two bridges */
-struct ast_bridge_merge_message {
-	struct ast_bridge_snapshot *from;	/*!< Bridge from which channels will be removed during the merge */
-	struct ast_bridge_snapshot *to;		/*!< Bridge to which channels will be added during the merge */
-};
-
-/*!
- * \since 12
- * \brief Message type for \ref ast_bridge_merge_message.
- *
- * \retval Message type for \ref ast_bridge_merge_message.
- */
-struct stasis_message_type *ast_bridge_merge_message_type(void);
-
-/*!
- * \since 12
- * \brief Publish a bridge merge
- *
- * \pre Bridges involved are locked
- *
- * \param to The bridge to which channels are being added
- * \param from The bridge from which channels are being removed
- */
-void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from);
-
-/*!
- * \since 12
- * \brief Blob of data associated with a bridge.
- *
- * The \c blob is actually a JSON object of structured data. It has a "type" field
- * which contains the type string describing this blob.
- */
-struct ast_bridge_blob {
-	/*! Bridge blob is associated with (or NULL for global/all bridges) */
-	struct ast_bridge_snapshot *bridge;
-	/*! Channel blob is associated with (may be NULL for some messages) */
-	struct ast_channel_snapshot *channel;
-	/*! JSON blob of data */
-	struct ast_json *blob;
-};
-
-/*!
- * \since 12
- * \brief Message type for \ref channel enter bridge blob messages.
- *
- * \retval Message type for \ref channel enter bridge blob messages.
- */
-struct stasis_message_type *ast_channel_entered_bridge_type(void);
-
-/*!
- * \since 12
- * \brief Message type for \ref channel leave bridge blob messages.
- *
- * \retval Message type for \ref channel leave bridge blob messages.
- */
-struct stasis_message_type *ast_channel_left_bridge_type(void);
-
-/*!
- * \since 12
- * \brief Creates a \ref ast_bridge_blob message.
- *
- * The \a blob JSON object requires a \c "type" field describing the blob. It
- * should also be treated as immutable and not modified after it is put into the
- * message.
- *
- * \pre bridge is locked.
- * \pre No channels are locked.
- *
- * \param bridge Channel blob is associated with, or NULL for global/all bridges.
- * \param blob JSON object representing the data.
- * \return \ref ast_bridge_blob message.
- * \return \c NULL on error
- */
-struct stasis_message *ast_bridge_blob_create(struct stasis_message_type *type,
-	struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Publish a bridge channel enter event
- *
- * \pre bridge is locked.
- * \pre No channels are locked.
- *
- * \param bridge The bridge a channel entered
- * \param chan The channel that entered the bridge
- * \param swap The channel being swapped out of the bridge
- */
-void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
-		struct ast_channel *swap);
-
-/*!
- * \since 12
- * \brief Publish a bridge channel leave event
- *
- * \pre bridge is locked.
- * \pre No channels are locked.
- *
- * \param bridge The bridge a channel left
- * \param chan The channel that left the bridge
- */
-void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan);
-
-/*!
- * \brief Build a JSON object from a \ref ast_bridge_snapshot.
- *
- * \param snapshot The bridge snapshot to convert to JSON
- * \param sanitize The message sanitizer to use on the snapshot
- *
- * \return JSON object representing bridge snapshot.
- * \return \c NULL on error
- */
-struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize);
-
-/*!
- * \brief Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge
- */
-struct ast_bridge_channel_snapshot_pair {
-	struct ast_bridge_snapshot *bridge_snapshot;
-	struct ast_channel_snapshot *channel_snapshot;
-};
-
-/*!
- * \since 12
- * \brief Message type for \ref ast_blind_transfer_message.
- *
- * \retval Message type for \ref ast_blind_transfer_message.
- */
-struct stasis_message_type *ast_blind_transfer_type(void);
-
-/*!
- * \brief Message published during a blind transfer
- */
-struct ast_blind_transfer_message {
-	/*! Result of the transfer */
-	enum ast_transfer_result result;
-	/*! True if the transfer was initiated by an external source (i.e. not DTMF-initiated) */
-	int is_external;
-	/*! The transferring channel */
-	struct ast_channel_snapshot *transferer;
-	/*! The bridge between the transferer and the transferee */
-	struct ast_bridge_snapshot *bridge;
-	/*! Destination context */
-	char context[AST_MAX_CONTEXT];
-	/*! Destination extension */
-	char exten[AST_MAX_EXTENSION];
-	/*! Transferee channel. NULL if there were multiple transferee channels */
-	struct ast_channel_snapshot *transferee;
-	/*! The channel replacing the transferer when multiple parties are being transferred */
-	struct ast_channel_snapshot *replace_channel;
-};
-
-/*!
- * \brief Create a blind transfer message to be published
- *
- * \param is_external Whether the blind transfer was initiated externally (e.g. via AMI or native protocol)
- * \param transferer The transferer's channel that is bridged to the transferee
- * \param bridge The bridge the transferer and transferee are in
- * \param context The destination context for the blind transfer
- * \param exten The destination extension for the blind transfer
- *
- * \retval NULL Failure to allocate or create snapshots
- * \retval non-NULL The created blind transfer message
- */
-struct ast_blind_transfer_message *ast_blind_transfer_message_create(int is_external,
-		struct ast_channel *transferer, const char *exten, const char *context);
-
-/*!
- * \brief Publish a blind transfer event
- *
- * \pre Bridges involved are locked. Channels involved are not locked.
- *
- * \param is_external Whether the blind transfer was initiated externally (e.g. via AMI or native protocol)
- * \param result The success or failure of the transfer
- * \param to_transferee The bridge between the transferer and transferee plus the transferer channel
- * \param context The destination context for the blind transfer
- * \param exten The destination extension for the blind transfer
- * \param transferee_channel If a single channel is being transferred, this is it. If
- *                           multiple parties are being transferred, this is NULL.
- * \param replace_channel If multiple parties are being transferred or the transfer
- *                        cannot reach across the bridge due to bridge flags, this is
- *                        the channel connecting their bridge to the destination.
- */
-void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message);
-
-enum ast_attended_transfer_dest_type {
-	/*! The transfer failed, so there is no appropriate final state */
-	AST_ATTENDED_TRANSFER_DEST_FAIL,
-	/*! The transfer results in a single bridge remaining due to a merge or swap */
-	AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE,
-	/*! The transfer results in a channel or bridge running an application */
-	AST_ATTENDED_TRANSFER_DEST_APP,
-	/*! The transfer results in a channel or bridge running an application via a local channel */
-	AST_ATTENDED_TRANSFER_DEST_LOCAL_APP,
-	/*! The transfer results in both bridges remaining with a local channel linking them */
-	AST_ATTENDED_TRANSFER_DEST_LINK,
-	/*! The transfer results in a threeway call between transferer, transferee, and transfer target */
-	AST_ATTENDED_TRANSFER_DEST_THREEWAY,
-};
-
-/*!
- * \brief Message representing attended transfer
- */
-struct ast_attended_transfer_message {
-	/*! Result of the attended transfer */
-	enum ast_transfer_result result;
-	/*! Indicates if the transfer was initiated externally*/
-	int is_external;
-	/*! Bridge between transferer <-> transferee and the transferer channel in that bridge. May be NULL */
-	struct ast_bridge_channel_snapshot_pair to_transferee;
-	/*! Bridge between transferer <-> transfer target and the transferer channel in that bridge. May be NULL */
-	struct ast_bridge_channel_snapshot_pair to_transfer_target;
-	/*! Local channel connecting transferee bridge to application */
-	struct ast_channel_snapshot *replace_channel;
-	/*! Transferee channel. Will be NULL if there were multiple channels transferred. */
-	struct ast_channel_snapshot *transferee;
-	/*! Transfer target channel. Will be NULL if there were multiple channels targeted. */
-	struct ast_channel_snapshot *target;
-	/*! Indicates the final state of the transfer */
-	enum ast_attended_transfer_dest_type dest_type;
-	union {
-		/*! ID of the surviving bridge. Applicable for AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE */
-		char bridge[AST_UUID_STR_LEN];
-		/*! Destination application of transfer. Applicable for AST_ATTENDED_TRANSFER_DEST_APP */
-		char app[AST_MAX_APP];
-		/*! Pair of local channels linking the bridges. Applicable for AST_ATTENDED_TRANSFER_DEST_LINK */
-		struct ast_channel_snapshot *links[2];
-		/*! Transferer channel and bridge that survived the transition to a threeway call. Applicable for AST_ATTENDED_TRANSFER_DEST_THREEWAY */
-		struct ast_bridge_channel_snapshot_pair threeway;
-	} dest;
-};
-
-/*!
- * \brief Create an Attended transfer message to be published.
- *
- * The parameters to this function are the basic necessities in order to create the
- * initial attended transfer message.
- *
- * The transferee and transfer_target parameters are optional. If not provided, then this
- * function will attempt to determine who the transferee and transfer target are based on
- * the input transferer channels and bridges. You typically will not need to provide an
- * explicit transferee and transfer target channel unless your attended transfer is implemented
- * in a strange way.
- *
- * \param is_external Non-zero if the transfer was initiated by a native channel driver protocol.
- * \param to_transferee The transferer channel that is bridged to the transferee channel.
- * \param transferee_bridge The bridge between the transferer and transferee. May be NULL.
- * \param to_transfer_target The transferer channel that is bridged to the transfer target.
- * \param target_bridge The bridge between the transferer and transfer target. May be NULL.
- * \param transferee The channel that is being transferred. Optional.
- * \param transfer_target The channel that is being transferred to. Optional.
- *
- * \retval NULL Failure to allocate or create snapshots
- * \retval non-NULL The created attended transfer message
- */
-struct ast_attended_transfer_message *ast_attended_transfer_message_create(
-		int is_external, struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
-		struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
-		struct ast_channel *transferee, struct ast_channel *transfer_target);
-
-/*!
- * \brief Add details for a bridge merge to an attended transfer message.
- *
- * If the transfer is accomplished by a bridge merge (or swap optimization), then this should
- * be called on the created attended transfer message to have the appropriate details added on.
- *
- * \param transfer_msg The transfer message to add details to
- * \param final_bridge The bridge where the surviving parties reside
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_bridge *final_bridge);
-
-/*!
- * \brief Add details for an attended transfer that was resolved as a three-way call
- *
- * If the transfer results in a three-way call between the transferer, the transferee, and the
- * transfer target, then this should be called in order to add appropriate details to the
- * transfer message to be published.
- *
- * \param transfer_msg The message to add details to
- * \param survivor_channel The transferer channel that exists in the three-way call
- * \param survivor_bridge The bridge where the three-way call takes place.
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge);
-
-/*!
- * \brief Add details for an attended transfer to an application
- *
- * If the transfer is sending one or more parties into an application, then this should be called
- * to add appropriate details to the transfer message being published.
- *
- * \param transfer_msg The message to add details to
- * \param app The name of the application that the parties are being transferred to
- * \param replace_channel The local channel that is in the bridge and running the application
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg,
-		const char *app, struct ast_channel *replace_channel);
-
-/*!
- * \brief Add details for an attended transfer that has a link between bridges.
- *
- * An attended transfer may be accomplished by linking two bridges together with local channels.
- * If this is how the transfer is to be completed, call this function in order to fill in details
- * about the transfer.
- *
- * \param transfer_msg The message to add details to.
- * \param locals An array of local channel halves that each are in one of the involved bridges.
- *
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_channel *locals[2]);
-
-/*!
- * \brief Publish an attended transfer
- *
- * \param transfer_msg The transfer message to publish
- */
-void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg);
-
-/*!
- * \since 12
- * \brief Message type for \ref ast_attended_transfer_message.
- *
- * \retval Message type for \ref ast_attended_transfer_message.
- */
-struct stasis_message_type *ast_attended_transfer_type(void);
-
-/*!
- * \brief Returns the most recent snapshot for the bridge.
- *
- * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.
- *
- * \param bridge_id Uniqueid of the bridge for which to get the snapshot.
- * \return Most recent snapshot. ao2_cleanup() when done.
- * \return \c NULL if channel isn't in cache.
- */
-struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(
-	const char *bridge_id);
-
-/*!
- * \internal
- * \brief Initialize the topics for a single bridge.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int bridge_topics_init(struct ast_bridge *bridge);
-
-/*!
- * \internal
- * \brief Initialize the stasis bridging topic and message types
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_stasis_bridging_init(void);
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _STASIS_BRIDGING_H */
diff --git a/include/asterisk/stasis_cache_pattern.h b/include/asterisk/stasis_cache_pattern.h
deleted file mode 100644
index 2ea643e..0000000
--- a/include/asterisk/stasis_cache_pattern.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_CACHE_PATTERN_H
-#define _ASTERISK_STASIS_CACHE_PATTERN_H
-
-/*! \file
- *
- * \brief Caching pattern for \ref stasis topics.
- *
- * A typical pattern for Stasis objects is to have individual objects, which
- * have their own topic and caching topic. These individual topics feed an
- * upstream aggregate topics, and a shared cache.
- *
- * The \ref stasis_cp_all object contains the aggregate topics and shared cache.
- * This is built with the base name for the topics, and the identity function to
- * identify messages in the cache.
- *
- * The \ref stasis_cp_single object contains the \ref stasis_topic for a single
- * instance, and the corresponding \ref stasis_caching_topic.
- *
- * Since the \ref stasis_cp_single object has subscriptions for forwarding
- * and caching, it must be disposed of using stasis_cp_single_unsubscribe()
- * instead of simply ao2_cleanup().
- */
-
-#include "asterisk/stasis.h"
-
-/*!
- * \brief The 'all' side of the cache pattern. These are typically built as
- * global objects for specific modules.
- */
-struct stasis_cp_all;
-
-/*!
- * \brief Create an all instance of the cache pattern.
- *
- * This object is AO2 managed, so dispose of it with ao2_cleanup().
- *
- * \param name Base name of the topics.
- * \param id_fn Identity function for the cache.
- * \return All side instance.
- * \return \c NULL on error.
- */
-struct stasis_cp_all *stasis_cp_all_create(const char *name,
-	snapshot_get_id id_fn);
-
-/*!
- * \brief Get the aggregate topic.
- *
- * This topic aggregates all messages published to corresponding
- * stasis_cp_single_topic() topics.
- *
- * \param all All side caching pattern object.
- * \return The aggregate topic.
- * \return \c NULL if \a all is \c NULL
- */
-struct stasis_topic *stasis_cp_all_topic(struct stasis_cp_all *all);
-
-/*!
- * \brief Get the caching topic.
- *
- * This topic aggregates all messages from the corresponding
- * stasis_cp_single_topic_cached() topics.
- *
- * Note that one normally only subscribes to the caching topic, since data
- * is fed to it from its upstream topic.
- *
- * \param all All side caching pattern object.
- * \return The aggregate caching topic.
- * \return \c NULL if \a all is \c NULL
- */
-struct stasis_topic *stasis_cp_all_topic_cached(
-	struct stasis_cp_all *all);
-
-/*!
- * \brief Get the cache.
- *
- * This is the shared cache for all corresponding \ref stasis_cp_single objects.
- *
- * \param all All side caching pattern object.
- * \return The cache.
- * \return \c NULL if \a all is \c NULL
- */
-struct stasis_cache *stasis_cp_all_cache(struct stasis_cp_all *all);
-
-/*!
- * \brief The 'one' side of the cache pattern. These are built per-instance for
- * some corresponding object, and must be explicitly disposed of using
- * stasis_cp_single_unsubscribe().
- */
-struct stasis_cp_single;
-
-/*!
- * \brief Create the 'one' side of the cache pattern.
- *
- * Dispose of using stasis_cp_single_unsubscribe().
- *
- * \param all Corresponding all side.
- * \param name Base name for the topics.
- * \return One side instance
- */
-struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
-	const char *name);
-
-/*!
- * \brief Stops caching and forwarding messages.
- *
- * \param one One side of the cache pattern.
- */
-void stasis_cp_single_unsubscribe(struct stasis_cp_single *one);
-
-/*!
- * \brief Get the topic for this instance.
- *
- * This is the topic to which one would post instance-specific messages, or
- * subscribe for single-instance, uncached messages.
- *
- * \param one One side of the cache pattern.
- * \return The main topic.
- * \return \c NULL if \a one is \c NULL
- */
-struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one);
-
-/*!
- * \brief Get the caching topic for this instance.
- *
- * Note that one normally only subscribes to the caching topic, since data
- * is fed to it from its upstream topic.
- *
- * \param one One side of the cache pattern.
- * \return The caching topic.
- * \return \c NULL if \a one is \c NULL
- */
-struct stasis_topic *stasis_cp_single_topic_cached(
-	struct stasis_cp_single *one);
-
-#endif /* _ASTERISK_STASIS_CACHE_PATTERN_H */
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
deleted file mode 100644
index 6c6cd51..0000000
--- a/include/asterisk/stasis_channels.h
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-
-#ifndef STASIS_CHANNELS_H_
-#define STASIS_CHANNELS_H_
-
-#include "asterisk/stringfields.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/channel.h"
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \since 12
- * \brief Structure representing a snapshot of channel state.
- *
- * While not enforced programmatically, this object is shared across multiple
- * threads, and should be treated as an immutable object.
- */
-struct ast_channel_snapshot {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
-		AST_STRING_FIELD(uniqueid);         /*!< Unique Channel Identifier */
-		AST_STRING_FIELD(linkedid);         /*!< Linked Channel Identifier -- gets propagated by linkage */
-		AST_STRING_FIELD(appl);             /*!< Current application */
-		AST_STRING_FIELD(data);             /*!< Data passed to current application */
-		AST_STRING_FIELD(context);          /*!< Dialplan: Current extension context */
-		AST_STRING_FIELD(exten);            /*!< Dialplan: Current extension number */
-		AST_STRING_FIELD(accountcode);      /*!< Account code for billing */
-		AST_STRING_FIELD(peeraccount);      /*!< Peer account code for billing */
-		AST_STRING_FIELD(userfield);        /*!< Userfield for CEL billing */
-		AST_STRING_FIELD(hangupsource);     /*!< Who is responsible for hanging up this channel */
-		AST_STRING_FIELD(caller_name);      /*!< Caller ID Name */
-		AST_STRING_FIELD(caller_number);    /*!< Caller ID Number */
-		AST_STRING_FIELD(caller_dnid);      /*!< Dialed ID Number */
-		AST_STRING_FIELD(caller_ani);       /*!< Caller ID ANI Number */
-		AST_STRING_FIELD(caller_rdnis);     /*!< Caller ID RDNIS Number */
-		AST_STRING_FIELD(caller_subaddr);   /*!< Caller subaddress */
-		AST_STRING_FIELD(dialed_subaddr);   /*!< Dialed subaddress */
-		AST_STRING_FIELD(connected_name);   /*!< Connected Line Name */
-		AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
-		AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
-		AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
-		AST_STRING_FIELD(type);             /*!< Type of channel technology */
-	);
-
-	struct timeval creationtime;            /*!< The time of channel creation */
-	enum ast_channel_state state;           /*!< State of line */
-	int priority;                           /*!< Dialplan: Current extension priority */
-	int amaflags;                           /*!< AMA flags for billing */
-	int hangupcause;                        /*!< Why is the channel hanged up. See causes.h */
-	int caller_pres;                        /*!< Caller ID presentation. */
-	struct ast_flags flags;                 /*!< channel flags of AST_FLAG_ type */
-	struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
-	struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
-	int tech_properties;                    /*!< Properties of the channel's technology */
-};
-
-/*!
- * \since 12
- * \brief Blob of data associated with a channel.
- *
- * This blob is actually shared amongst several \ref stasis_message_type's.
- */
-struct ast_channel_blob {
-	/*! Channel blob is associated with (or NULL for global/all channels) */
-	struct ast_channel_snapshot *snapshot;
-	/*! JSON blob of data */
-	struct ast_json *blob;
-};
-
-/*!
- * \since 12
- * \brief A set of channels with blob objects - see \ref ast_channel_blob
- */
-struct ast_multi_channel_blob;
-
-struct stasis_cp_all *ast_channel_cache_all(void);
-
-/*!
- * \since 12
- * \brief A topic which publishes the events for all channels.
- * \retval Topic for all channel events.
- */
-struct stasis_topic *ast_channel_topic_all(void);
-
-/*!
- * \since 12
- * \brief A caching topic which caches \ref ast_channel_snapshot messages from
- * ast_channel_events_all(void).
- *
- * \retval Topic for all channel events.
- */
-struct stasis_topic *ast_channel_topic_all_cached(void);
-
-/*!
- * \since 12
- * \brief Primary channel cache, indexed by Uniqueid.
- *
- * \retval Cache of \ref ast_channel_snapshot.
- */
-struct stasis_cache *ast_channel_cache(void);
-
-/*!
- * \since 12
- * \brief Secondary channel cache, indexed by name.
- *
- * \retval Cache of \ref ast_channel_snapshot.
- */
-struct stasis_cache *ast_channel_cache_by_name(void);
-
-/*!
- * \since 12
- * \brief Message type for \ref ast_channel_snapshot.
- *
- * \retval Message type for \ref ast_channel_snapshot.
- */
-struct stasis_message_type *ast_channel_snapshot_type(void);
-
-/*!
- * \since 12
- * \brief Generate a snapshot of the channel state. This is an ao2 object, so
- * ao2_cleanup() to deallocate.
- *
- * \pre chan is locked
- *
- * \param chan The channel from which to generate a snapshot
- *
- * \retval pointer on success (must be unreffed)
- * \retval NULL on error
- */
-struct ast_channel_snapshot *ast_channel_snapshot_create(
-	struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Obtain the latest \ref ast_channel_snapshot from the \ref stasis cache. This is
- * an ao2 object, so use \ref ao2_cleanup() to deallocate.
- *
- * \param unique_id The channel's unique ID
- *
- * \retval A \ref ast_channel_snapshot on success
- * \retval NULL on error
- */
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid);
-
-/*!
- * \since 12
- * \brief Obtain the latest \ref ast_channel_snapshot from the \ref stasis cache. This is
- * an ao2 object, so use \ref ao2_cleanup() to deallocate.
- *
- * \param name The channel's name
- *
- * \retval A \ref ast_channel_snapshot on success
- * \retval NULL on error
- */
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name);
-
-/*!
- * \since 12
- * \brief Creates a \ref ast_channel_blob message.
- *
- * The given \a blob should be treated as immutable and not modified after it is
- * put into the message.
- *
- * \pre chan is locked
- *
- * \param chan Channel blob is associated with, or \c NULL for global/all channels.
- * \param type Message type for this blob.
- * \param blob JSON object representing the data, or \c NULL for no data. If
- *             \c NULL, ast_json_null() is put into the object.
- *
- * \return \ref ast_channel_blob message.
- * \return \c NULL on error
- */
-struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
-	struct stasis_message_type *type, struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Create a \ref ast_channel_blob message, pulling channel state from
- *        the cache.
- *
- * \param uniqueid Uniqueid of the channel.
- * \param type Message type for this blob.
- * \param blob JSON object representing the data, or \c NULL for no data. If
- *             \c NULL, ast_json_null() is put into the object.
- *
- * \return \ref ast_channel_blob message.
- * \return \c NULL on error
- */
-struct stasis_message *ast_channel_blob_create_from_cache(
-	const char *uniqueid, struct stasis_message_type *type,
-	struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Create a \ref ast_multi_channel_blob suitable for a \ref stasis_message.
- *
- * The given \a blob should be treated as immutable and not modified after it is
- * put into the message.
- *
- * \param blob The JSON blob that defines the data of this \ref ast_multi_channel_blob
- *
- * \return \ref ast_multi_channel_blob object
- * \return \c NULL on error
-*/
-struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Retrieve a channel snapshot associated with a specific role from a
- * \ref ast_multi_channel_blob
- *
- * \note The reference count of the \ref ast_channel_snapshot returned from
- * this function is not changed. The caller of this function does not own the
- * reference to the snapshot.
- *
- * \param obj The \ref ast_multi_channel_blob containing the channel snapshot
- * to retrieve
- * \param role The role associated with the channel snapshot
- *
- * \retval \ref ast_channel_snapshot matching the role on success
- * \retval NULL on error or not found for the role specified
- */
-struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(
-	struct ast_multi_channel_blob *obj, const char *role);
-
-/*!
- * \since 12
- * \brief Retrieve all channel snapshots associated with a specific role from
- * a \ref ast_multi_channel_blob
- *
- * \note Because this function returns an ao2_container (hashed by channel name)
- * of all channel snapshots that matched the passed in role, the reference of
- * the snapshots is increased by this function. The caller of this function must
- * release the reference to the snapshots by disposing of the container
- * appropriately.
- *
- * \param obj The \ref ast_multi_channel_blob containing the channel snapshots to
- * retrieve
- * \param role The role associated with the channel snapshots
- *
- * \retval A container containing all \ref ast_channel_snapshot objects matching
- * the role on success.
- * \retval NULL on error or not found for the role specified
- */
-struct ao2_container *ast_multi_channel_blob_get_channels(
-	struct ast_multi_channel_blob *obj, const char *role);
-
-/*!
- * \since 12
- * \brief Retrieve the JSON blob from a \ref ast_multi_channel_blob.
- * Returned \ref ast_json is still owned by \a obj
- *
- * \param obj Channel blob object.
- * \return Type field value from the blob.
- * \return \c NULL on error.
- */
-struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj);
-
-/*!
- * \since 12
- * \brief Add a \ref ast_channel_snapshot to a \ref ast_multi_channel_blob object
- *
- * \note This will increase the reference count by 1 for the channel snapshot. It is
- * assumed that the \ref ast_multi_channel_blob will own a reference to the object.
- *
- * \param obj The \ref ast_multi_channel_blob object that will reference the snapshot
- * \param role A \a role that the snapshot has in the multi channel relationship
- * \param snapshot The \ref ast_channel_snapshot being added to the
- * \ref ast_multi_channel_blob object
- */
-void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj,
-	const char *role, struct ast_channel_snapshot *snapshot);
-
-/*!
- * \brief Publish a channel blob message.
- * \since 12.0.0
- *
- * \pre chan is locked
- *
- * \param chan Channel publishing the blob.
- * \param type Type of stasis message.
- * \param blob The blob being published. (NULL if no blob)
- *
- * \return Nothing
- */
-void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type,
-	struct ast_json *blob);
-
-/*!
- * \brief Publish a channel blob message using the latest snapshot from the cache
- * \since 12.4.0
- *
- * \param chan Channel publishing the blob.
- * \param type Type of stasis message.
- * \param blob The blob being published. (NULL if no blob)
- *
- * \note As this only accesses the uniqueid and topic of the channel - neither of
- * which should ever be changed on a channel anyhow - a channel does not have to
- * be locked when calling this function.
- *
- * \return Nothing
- */
-void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type,
-	struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Set flag to indicate channel snapshot is being staged.
- *
- * \pre chan is locked
- *
- * \param chan Channel being staged.
- */
-void ast_channel_stage_snapshot(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Clear flag to indicate channel snapshot is being staged, and publish snapshot.
- *
- * \pre chan is locked
- *
- * \param chan Channel being staged.
- */
-void ast_channel_stage_snapshot_done(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Publish a \ref ast_channel_snapshot for a channel.
- *
- * \pre chan is locked
- *
- * \param chan Channel to publish.
- */
-void ast_channel_publish_snapshot(struct ast_channel *chan);
-
-/*!
- * \since 12
- * \brief Publish a \ref ast_channel_varset for a channel.
- *
- * \pre chan is locked
- *
- * \param chan Channel to publish the event for, or \c NULL for 'none'.
- * \param variable Name of the variable being set
- * \param value Value.
- */
-void ast_channel_publish_varset(struct ast_channel *chan,
-				const char *variable, const char *value);
-
-/*!
- * \since 12
- * \brief Message type for when a channel dials another channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_dial_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a variable is set on a channel.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_varset_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a hangup is requested on a channel.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_hangup_request_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when DTMF begins on a channel.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_dtmf_begin_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when DTMF ends on a channel.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_dtmf_end_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a channel is placed on hold.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_hold_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a channel is removed from hold.
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_unhold_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a channel starts spying on another channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_chanspy_start_type(void);
-
-/*!
- * \since 12
- * \brief Message type for when a channel stops spying on another channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_chanspy_stop_type(void);
-
-/*!
- * \since 12
- * \brief Message type for a fax operation
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_fax_type(void);
-
-/*!
- * \since 12
- * \brief Message type for hangup handler related actions
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_hangup_handler_type(void);
-
-/*!
- * \since 12
- * \brief Message type for starting monitor on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_monitor_start_type(void);
-
-/*!
- * \since 12
- * \brief Message type for stopping monitor on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_monitor_stop_type(void);
-
-/*!
- * \since 12.0.0
- * \brief Message type for agent login on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_agent_login_type(void);
-
-/*!
- * \since 12.0.0
- * \brief Message type for agent logoff on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_agent_logoff_type(void);
-
-/*!
- * \since 12
- * \brief Message type for starting music on hold on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_moh_start_type(void);
-
-/*!
- * \since 12
- * \brief Message type for stopping music on hold on a channel
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_moh_stop_type(void);
-
-/*!
- * \since 12.4.0
- * \brief Message type for a channel starting talking
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_talking_start(void);
-
-/*!
- * \since 12.4.0
- * \brief Message type for a channel stopping talking
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_channel_talking_stop(void);
-
-/*!
- * \since 12
- * \brief Publish in the \ref ast_channel_topic or \ref ast_channel_topic_all
- * topics a stasis message for the channels involved in a dial operation.
- *
- * \param caller The channel performing the dial operation
- * \param peer The channel being dialed
- * \param dialstring When beginning a dial, the information passed to the
- * dialing application
- * \param dialstatus The current status of the dial operation (NULL if no
- * status is known)
- */
-void ast_channel_publish_dial(struct ast_channel *caller,
-		struct ast_channel *peer,
-		const char *dialstring,
-		const char *dialstatus);
-
-/*!
- * \since 12
- * \brief Publish in the \ref ast_channel_topic or \ref ast_channel_topic_all
- * topics a stasis message for the channels involved in a dial operation that
- * is forwarded.
- *
- * \param caller The channel performing the dial operation
- * \param peer The channel being dialed
- * \param forwarded The channel created as a result of the call forwarding
- * \param dialstring The information passed to the dialing application when beginning a dial
- * \param dialstatus The current status of the dial operation
- * \param forward The call forward string provided by the dialed channel
- */
-void ast_channel_publish_dial_forward(struct ast_channel *caller,
-		struct ast_channel *peer,
-		struct ast_channel *forwarded,
-		const char *dialstring,
-		const char *dialstatus,
-		const char *forward);
-
-/*!
- * \since 12
- * \brief Publish in the \ref ast_channel_topic a \ref ast_channel_snapshot
- * message indicating a change in channel state
- *
- * \pre chan is locked
- *
- * \param chan The channel whose state has changed
- */
-void ast_publish_channel_state(struct ast_channel *chan);
-
-/*! @} */
-
-/*!
- * \brief Build a JSON object from a \ref ast_channel_snapshot.
- *
- * \param snapshot The snapshot to convert to JSON
- * \param sanitize The message sanitizer to use on the snapshot
- *
- * \return JSON object representing channel snapshot.
- * \return \c NULL on error
- */
-struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize);
-
-/*!
- * \brief Compares the context, exten and priority of two snapshots.
- * \since 12
- *
- * \param old_snapshot Old snapshot
- * \param new_snapshot New snapshot
- *
- * \return True (non-zero) if context, exten or priority are identical.
- * \return False (zero) if context, exten and priority changed.
- */
-int ast_channel_snapshot_cep_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot);
-
-/*!
- * \brief Compares the callerid info of two snapshots.
- * \since 12
- *
- * \param old_snapshot Old snapshot
- * \param new_snapshot New snapshot
- *
- * \return True (non-zero) if callerid are identical.
- * \return False (zero) if callerid changed.
- */
-int ast_channel_snapshot_caller_id_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot);
-
-/*!
- * \brief Compares the connected line info of two snapshots.
- * \since 13.1.0
- *
- * \param old_snapshot Old snapshot
- * \param new_snapshot New snapshot
- *
- * \return True (non-zero) if callerid are identical.
- * \return False (zero) if callerid changed.
- */
-int ast_channel_snapshot_connected_line_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot);
-
-/*!
- * \brief Initialize the stasis channel topic and message types
- * \return 0 on success
- * \return Non-zero on error
- */
-int ast_stasis_channels_init(void);
-
-#endif /* STASIS_CHANNELS_H_ */
diff --git a/include/asterisk/stasis_endpoints.h b/include/asterisk/stasis_endpoints.h
deleted file mode 100644
index 1d56a8f..0000000
--- a/include/asterisk/stasis_endpoints.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_ENDPOINTS_H
-#define _ASTERISK_STASIS_ENDPOINTS_H
-
-/*! \file
- *
- * \brief Endpoint abstractions.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/endpoints.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_cache_pattern.h"
-#include "asterisk/stringfields.h"
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief A snapshot of an endpoint's state.
- *
- * The id for an endpoint is tech/resource. The duplication is needed because
- * there are several cases where any of the three values would be needed, and
- * constantly splitting or reassembling would be a pain.
- *
- * \since 12
- */
-struct ast_endpoint_snapshot {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(id);	/*!< unique id for this endpoint. */
-		AST_STRING_FIELD(tech);	/*!< Channel technology */
-		AST_STRING_FIELD(resource);	/*!< Tech-unique name */
-		);
-
-	/*! Endpoint state */
-	enum ast_endpoint_state state;
-	/*!
-	 * Maximum number of channels this endpoint supports. If the upper limit
-	 * for an endpoint is unknown, this field is set to -1.
-	 */
-	int max_channels;
-	/*! Number of channels currently active on this endpoint */
-	int num_channels;
-	/*! Channel ids */
-	char *channel_ids[];
-};
-
-/*!
- * \brief Blob of data associated with an endpoint.
- *
- * The blob is actually a JSON object of structured data. It has a "type" field
- * which contains the type string describing this blob.
- *
- * \since 12
- */
-struct ast_endpoint_blob {
-	struct ast_endpoint_snapshot *snapshot;
-	struct ast_json *blob;
-};
-
-/*!
- * \since 12
- * \brief Creates a \ref ast_endpoint_blob message.
- *
- * The given \a blob should be treated as immutable and not modified after it is
- * put into the message.
- *
- * \param endpoint Endpoint blob is associated with.
- * \param type Message type for this blob.
- * \param blob JSON object representing the data, or \c NULL for no data. If
- *             \c NULL, ast_json_null() is put into the object.
- *
- * \return \ref ast_endpoint_blob message.
- * \return \c NULL on error
- */
-struct stasis_message *ast_endpoint_blob_create(struct ast_endpoint *endpoint,
-	struct stasis_message_type *type, struct ast_json *blob);
-
-/*!
- * \since 12
- * \brief Creates and publishes a \ref ast_endpoint_blob message.
- *
- * The given \a blob should be treated as immutable and not modified after it is
- * put into the message.
- *
- * \param endpoint Endpoint blob is associated with.
- * \param type Message type for this blob.
- * \param blob JSON object representing the data, or \c NULL for no data. If
- *             \c NULL, ast_json_null() is put into the object.
- */
-void ast_endpoint_blob_publish(struct ast_endpoint *endpoint, struct stasis_message_type *type,
-	struct ast_json *blob);
-
-/*!
- * \brief Message type for endpoint state changes.
- * \since 12
- */
-struct stasis_message_type *ast_endpoint_state_type(void);
-
-/*!
- * \brief Message type for \ref ast_endpoint_snapshot.
- * \since 12
- */
-struct stasis_message_type *ast_endpoint_snapshot_type(void);
-
-/*!
- * \brief Create a snapshot of an endpoint
- * \param endpoint Endpoint to snap a shot of.
- * \return Snapshot of the endpoint.
- * \return \c NULL on error.
- * \since 12
- */
-struct ast_endpoint_snapshot *ast_endpoint_snapshot_create(
-	struct ast_endpoint *endpoint);
-
-/*!
- * \brief Returns the topic for a specific endpoint.
- *
- * \param endpoint The endpoint.
- * \return The topic for the given endpoint.
- * \return ast_endpoint_topic_all() if endpoint is \c NULL.
- * \since 12
- */
-struct stasis_topic *ast_endpoint_topic(struct ast_endpoint *endpoint);
-
-/*!
- * \brief Returns the topic for a specific endpoint.
- *
- * \ref ast_endpoint_snapshot messages are replaced with
- * \ref stasis_cache_update
- *
- * \param endpoint The endpoint.
- * \return The topic for the given endpoint.
- * \return ast_endpoint_topic_all() if endpoint is \c NULL.
- * \since 12
- */
-struct stasis_topic *ast_endpoint_topic_cached(struct ast_endpoint *endpoint);
-
-/*!
- * \internal
- * \brief Cache and global topics for endpoints.
- *
- * This is public simply to be used by endpoints.c. Please use the accessor
- * functions (ast_endpoint_topic_all(), ast_endpoint_topic_all_cached(),
- * ast_endpoint_cache(), etc.) instead of calling this directly.
- *
- * \since 12
- */
-struct stasis_cp_all *ast_endpoint_cache_all(void);
-
-/*!
- * \brief Topic for all endpoint releated messages.
- * \since 12
- */
-struct stasis_topic *ast_endpoint_topic_all(void);
-
-/*!
- * \brief Cached topic for all endpoint related messages.
- * \since 12
- */
-struct stasis_topic *ast_endpoint_topic_all_cached(void);
-
-/*!
- * \brief Backend cache for ast_endpoint_topic_all_cached().
- * \return Cache of \ref ast_endpoint_snapshot.
- * \since 12
- */
-struct stasis_cache *ast_endpoint_cache(void);
-
-/*!
- * \brief Retrieve the most recent snapshot for the endpoint with the given
- * name.
- *
- * \param tech Name of the endpoint's technology.
- * \param resource Resource name of the endpoint.
- * \return Snapshot of the endpoint with the given name.
- * \return \c NULL if endpoint is not found, or on error.
- * \since 12
- */
-struct ast_endpoint_snapshot *ast_endpoint_latest_snapshot(const char *tech,
-	const char *resource
-);
-
-/*! @} */
-
-/*!
- * \brief Build a JSON object from a \ref ast_endpoint_snapshot.
- *
- * \param snapshot Endpoint snapshot.
- * \param sanitize The message sanitizer to use on the snapshot
- *
- * \return JSON object representing endpoint snapshot.
- * \return \c NULL on error
- */
-struct ast_json *ast_endpoint_snapshot_to_json(
-	const struct ast_endpoint_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize);
-
-/*!
- * \brief Initialization function for endpoint stasis support.
- *
- * \return 0 on success.
- * \return non-zero on error.
- * \since 12
- */
-int ast_endpoint_stasis_init(void);
-
-#endif /* _ASTERISK_STASIS_ENDPOINTS_H */
diff --git a/include/asterisk/stasis_internal.h b/include/asterisk/stasis_internal.h
deleted file mode 100644
index bc6122c..0000000
--- a/include/asterisk/stasis_internal.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Internal Stasis APIs.
- *
- * This header file is used to define functions that are shared between files that make
- * up \ref stasis. Functions declared here should not be used by any module outside of
- * Stasis.
- *
- * If you find yourself needing to call one of these functions directly, something has
- * probably gone horribly wrong.
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-#include "asterisk/stasis.h"
-
-#ifndef STASIS_INTERNAL_H_
-#define STASIS_INTERNAL_H_
-
-/*!
- * \brief Create a subscription.
- *
- * In addition to being AO2 managed memory (requiring an ao2_cleanup() to free
- * up this reference), the subscription must be explicitly unsubscribed from its
- * topic using stasis_unsubscribe().
- *
- * The invocations of the callback are serialized, but may not always occur on
- * the same thread. The invocation order of different subscriptions is
- * unspecified.
- *
- * Note: modules outside of Stasis should use \ref stasis_subscribe.
- *
- * \param topic Topic to subscribe to.
- * \param callback Callback function for subscription messages.
- * \param data Data to be passed to the callback, in addition to the message.
- * \param needs_mailbox Determines whether or not the subscription requires a mailbox.
- *  Subscriptions with mailboxes will be delivered on some non-publisher thread;
- *  subscriptions without mailboxes will be delivered on the publisher thread.
- * \param use_thread_pool Use the thread pool for the subscription. This is only
- *  relevant if \c needs_mailbox is non-zero.
- * \return New \ref stasis_subscription object.
- * \return \c NULL on error.
- * \since 12
- */
-struct stasis_subscription *internal_stasis_subscribe(
-	struct stasis_topic *topic,
-	stasis_subscription_cb callback,
-	void *data,
-	int needs_mailbox,
-	int use_thread_pool);
-
-#endif /* STASIS_INTERNAL_H_ */
diff --git a/include/asterisk/stasis_message_router.h b/include/asterisk/stasis_message_router.h
deleted file mode 100644
index 89657a5..0000000
--- a/include/asterisk/stasis_message_router.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_MESSAGE_ROUTER_H
-#define _ASTERISK_STASIS_MESSAGE_ROUTER_H
-
-/*!
- * \brief A simplistic router for \ref stasis_message's.
- *
- * Often times, when subscribing to a topic, one wants to handle different
- * message types differently. While one could cascade if/else statements through
- * the subscription handler, it is much cleaner to specify a different callback
- * for each message type. The \ref stasis_message_router is here to help!
- *
- * A \ref stasis_message_router is constructed for a particular \ref
- * stasis_topic, which is subscribes to. Call
- * stasis_message_router_unsubscribe() to cancel that subscription.
- *
- * Once constructed, routes can be added using stasis_message_router_add() (or
- * stasis_message_router_set_default() for any messages not handled by other
- * routes). There may be only one route per \ref stasis_message_type. The
- * route's \a callback is invoked just as if it were a callback for a
- * subscription; but it only gets called for messages of the specified type.
- *
- * \since 12
- */
-
-#include "asterisk/stasis.h"
-
-/*! \brief Stasis message routing object */
-struct stasis_message_router;
-
-/*!
- * \brief Create a new message router object.
- *
- * \param topic Topic to subscribe route to.
- *
- * \return New \ref stasis_message_router.
- * \return \c NULL on error.
- *
- * \since 12
- */
-struct stasis_message_router *stasis_message_router_create(
-	struct stasis_topic *topic);
-
-/*!
- * \brief Create a new message router object.
- *
- * The subscription created for this message router will dispatch
- * callbacks on a thread pool.
- *
- * \param topic Topic to subscribe route to.
- *
- * \return New \ref stasis_message_router.
- * \return \c NULL on error.
- *
- * \since 12.8.0
- */
-struct stasis_message_router *stasis_message_router_create_pool(
-	struct stasis_topic *topic);
-
-/*!
- * \brief Unsubscribe the router from the upstream topic.
- *
- * \param router Router to unsubscribe.
- *
- * \since 12
- */
-void stasis_message_router_unsubscribe(struct stasis_message_router *router);
-
-/*!
- * \brief Unsubscribe the router from the upstream topic, blocking until the
- * final message has been processed.
- *
- * See stasis_unsubscribe_and_join() for info on when to use this
- * vs. stasis_message_router_unsubscribe().
- *
- * \param router Router to unsubscribe.
- *
- * \since 12
- */
-void stasis_message_router_unsubscribe_and_join(
-	struct stasis_message_router *router);
-
-/*!
- * \brief Returns whether \a router has received its final message.
- *
- * \param router Router.
- *
- * \return True (non-zero) if stasis_subscription_final_message() has been
- *         received.
- * \return False (zero) if waiting for the end.
- */
-int stasis_message_router_is_done(struct stasis_message_router *router);
-
-/*!
- * \brief Publish a message to a message router's subscription synchronously
- *
- * \param router Router
- * \param message The \ref stasis message
- *
- * This should be used when a message needs to be published synchronously to
- * the underlying subscription created by a message router. This is analagous
- * to \ref stasis_publish_sync.
- *
- * Note that the caller will be blocked until the thread servicing the message
- * on the message router's subscription completes handling of the message.
- *
- * \since 12.1.0
- */
-void stasis_message_router_publish_sync(struct stasis_message_router *router,
-	struct stasis_message *message);
-
-/*!
- * \brief Add a route to a message router.
- *
- * A particular \a message_type may have at most one route per \a router. If
- * you route \ref stasis_cache_update messages, the callback will only receive
- * updates for types not handled by routes added with
- * stasis_message_router_add_cache_update().
- *
- * Adding multiple routes for the same message type results in undefined
- * behavior.
- *
- * \param router Router to add the route to.
- * \param message_type Type of message to route.
- * \param callback Callback to forard messages of \a message_type to.
- * \param data Data pointer to pass to \a callback.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \since 12
- */
-int stasis_message_router_add(struct stasis_message_router *router,
-	struct stasis_message_type *message_type,
-	stasis_subscription_cb callback, void *data);
-
-/*!
- * \brief Add a route for \ref stasis_cache_update messages to a message router.
- *
- * A particular \a message_type may have at most one cache route per \a router.
- * These are distinct from regular routes, so one could have both a regular
- * route and a cache route for the same \a message_type.
- *
- * Adding multiple routes for the same message type results in undefined
- * behavior.
- *
- * \param router Router to add the route to.
- * \param message_type Subtype of cache update to route.
- * \param callback Callback to forard messages of \a message_type to.
- * \param data Data pointer to pass to \a callback.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \since 12
- */
-int stasis_message_router_add_cache_update(struct stasis_message_router *router,
-	struct stasis_message_type *message_type,
-	stasis_subscription_cb callback, void *data);
-
-/*!
- * \brief Remove a route from a message router.
- *
- * If a route is removed from another thread, there is no notification that
- * all messages using this route have been processed. This typically means that
- * the associated \c data pointer for this route must be kept until the
- * route itself is disposed of.
- *
- * \param router Router to remove the route from.
- * \param message_type Type of message to route.
- *
- * \since 12
- */
-void stasis_message_router_remove(struct stasis_message_router *router,
-	struct stasis_message_type *message_type);
-
-/*!
- * \brief Remove a cache route from a message router.
- *
- * If a route is removed from another thread, there is no notification that
- * all messages using this route have been processed. This typically means that
- * the associated \c data pointer for this route must be kept until the
- * route itself is disposed of.
- *
- * \param router Router to remove the route from.
- * \param message_type Type of message to route.
- *
- * \since 12
- */
-void stasis_message_router_remove_cache_update(
-	struct stasis_message_router *router,
-	struct stasis_message_type *message_type);
-
-/*!
- * \brief Sets the default route of a router.
- *
- * \param router Router to set the default route of.
- * \param callback Callback to forard messages which otherwise have no home.
- * \param data Data pointer to pass to \a callback.
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \since 12
- */
-int stasis_message_router_set_default(struct stasis_message_router *router,
-				      stasis_subscription_cb callback,
-				      void *data);
-
-#endif /* _ASTERISK_STASIS_MESSAGE_ROUTER_H */
diff --git a/include/asterisk/stasis_system.h b/include/asterisk/stasis_system.h
deleted file mode 100644
index 8c6e60f..0000000
--- a/include/asterisk/stasis_system.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jason Parker <jparker at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_SYSTEM_H
-#define _ASTERISK_STASIS_SYSTEM_H
-
-#include "asterisk/json.h"
-#include "asterisk/stasis.h"
-
-/*!
- * \since 12
- * \brief Publish a channel driver outgoing registration message
- *
- * \param channeltype The channel driver that published the message
- * \param username The username that was used to register
- * \param domain The domain that was used to register
- * \param status The result of the registration
- * \param cause The reason for the result
- */
-void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause);
-
-/*!
- * \since 12
- * \brief A \ref stasis topic which publishes messages regarding system changes
- *
- * \retval \ref stasis_topic for system level changes
- * \retval NULL on error
- */
-struct stasis_topic *ast_system_topic(void);
-
-/*!
- * \since 12
- * \brief A \ref stasis_message_type for network changes
- *
- * \retval NULL on error
- * \retval \ref stasis_message_type for network changes
- *
- * \note Messages of this type should always be issued on and expected from
- *       the \ref ast_system_topic \ref stasis topic
- */
-struct stasis_message_type *ast_network_change_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for outbound registration.
- * \since 12
- */
-struct stasis_message_type *ast_system_registry_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Available messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_available_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Offer Timer Start messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_offertimerstart_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Requested messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_requested_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Request Acknowledged messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_requestacknowledged_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Caller Stop Monitoring messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_callerstopmonitoring_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Caller Start Monitoring messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_callerstartmonitoring_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Caller Recalling messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_callerrecalling_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Recall Complete messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_recallcomplete_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Failure messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_failure_type(void);
-
-/*!
- * \brief A \ref stasis_message_type for CCSS Monitor Failed messages.
- * \since 12
- */
-struct stasis_message_type *ast_cc_monitorfailed_type(void);
-
-/*!
- * \brief Initialize the stasis system topic and message types
- * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_stasis_system_init(void);
-
-#endif /* _ASTERISK_STASIS_SYSTEM_H */
diff --git a/include/asterisk/stasis_test.h b/include/asterisk/stasis_test.h
deleted file mode 100644
index ad4020a..0000000
--- a/include/asterisk/stasis_test.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STASIS_TEST_H
-#define _ASTERISK_STASIS_TEST_H
-
-/*!
- * \file \brief Test infrastructure for dealing with Stasis.
- *
- * \author David M. Lee, II <dlee at digium.com>
- *
- * This file contains some helpful utilities for testing Stasis related topics
- * and messages. The \ref stasis_message_sink is something you can subscribe to
- * a topic which will receive all of the messages from the topic. This messages
- * are accumulated in its \c messages field.
- *
- * There are a set of wait functions (stasis_message_sink_wait_for_count(),
- * stasis_message_sink_wait_for(), etc.) which will block waiting for conditions
- * to be met in the \ref stasis_message_sink.
- */
-
-#include "asterisk/lock.h"
-#include "asterisk/stasis.h"
-
-#define STASIS_SINK_DEFAULT_WAIT 5000
-
-/*! \brief Structure that collects messages from a topic */
-struct stasis_message_sink {
-	/*! Condition mutex. */
-	ast_mutex_t lock;
-	/*! Condition to signal state changes */
-	ast_cond_t cond;
-	/*! Maximum number of messages messages field can hold without
-	 * realloc */
-	size_t max_messages;
-	/*! Current number of messages in messages field. */
-	size_t num_messages;
-	/*! Boolean flag to be set when unsubscribe is received */
-	int is_done:1;
-	/*! Ordered array of messages received */
-	struct stasis_message **messages;
-};
-
-/*!
- * \brief Create a message sink.
- *
- * This is an AO2 managed object, which you ao2_cleanup() when done. The
- * destructor waits for an unsubscribe message to be received, to ensure the
- * object isn't disposed of before the topic is finished.
- */
-struct stasis_message_sink *stasis_message_sink_create(void);
-
-/*!
- * \brief Topic callback to receive messages.
- *
- * We return a function pointer instead of simply exposing the function because
- * of the vagaries of dlopen(), \c RTLD_LAZY, and function pointers. See the
- * comment on the implementation for details why.
- *
- * \return Function pointer to \ref stasis_message_sink's message handling
- *         function
- */
-stasis_subscription_cb stasis_message_sink_cb(void);
-
-/*!
- * \brief Wait for a sink's num_messages field to reach a certain level.
- *
- * The optional timeout prevents complete deadlock in a test.
- *
- * \param sink Sink to wait on.
- * \param num_messages sink->num_messages value to wait for.
- * \param timeout_millis Number of milliseconds to wait. -1 to wait forever.
- * \return Actual sink->num_messages value at return.
- *         If this is < \a num_messages, then the timeout expired.
- */
-int stasis_message_sink_wait_for_count(struct stasis_message_sink *sink,
-	int num_messages, int timeout_millis);
-
-typedef int (*stasis_wait_cb)(struct stasis_message *msg, const void *data);
-
-/*!
- * \brief Wait for a message that matches the given criteria.
- *
- * \param sink Sink to wait on.
- * \param start Index of message to start with.
- * \param cmp_cb comparison function. This returns true (non-zero) on match
- *               and false (zero) on match.
- * \param timeout_millis Number of milliseconds to wait.
- * \return Index of the matching message.
- * \return Negative for no match.
- */
-int stasis_message_sink_wait_for(struct stasis_message_sink *sink, int start,
-	stasis_wait_cb cmp_cb, const void *data, int timeout_millis);
-
-/*!
- * \brief Ensures that no new messages are received.
- *
- * The optional timeout prevents complete deadlock in a test.
- *
- * \param sink Sink to wait on.
- * \param num_messages expecte \a sink->num_messages.
- * \param timeout_millis Number of milliseconds to wait for.
- * \return Actual sink->num_messages value at return.
- *         If this is < \a num_messages, then the timeout expired.
- */
-int stasis_message_sink_should_stay(struct stasis_message_sink *sink,
-	int num_messages, int timeout_millis);
-
-/*! \addtogroup StasisTopicsAndMessages
- * @{
- */
-
-/*!
- * \brief Creates a test message.
- */
-struct stasis_message *stasis_test_message_create(void);
-
-/*!
- * \brief Gets the type of messages created by stasis_test_message_create().
- */
-struct stasis_message_type *stasis_test_message_type(void);
-
-/*!
- * @}
- */
-
-#endif /* _ASTERISK_STASIS_TEST_H */
diff --git a/include/asterisk/statsd.h b/include/asterisk/statsd.h
deleted file mode 100644
index 8e5e2f9..0000000
--- a/include/asterisk/statsd.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_STATSD_H
-#define _ASTERISK_STATSD_H
-
-/*!
- * \brief Support for publishing to a statsd server.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/optional_api.h"
-
-/*! An instantaneous measurement of a value. */
-#define AST_STATSD_GUAGE "g"
-/*! A change in a value. */
-#define AST_STATSD_COUNTER "c"
-/*! Measure of milliseconds. */
-#define AST_STATSD_TIMER "ms"
-/*! Distribution of values over time. */
-#define AST_STATSD_HISTOGRAM "h"
-/*! Events over time. Sorta like increment-only counters. */
-#define AST_STATSD_METER "m"
-
-/*!
- * \brief Send a stat to the configured statsd server.
- *
- * The is the most flexible function for sending a message to the statsd server,
- * but also the least easy to use. See ast_statsd_log() or
- * ast_statsd_log_sample() for a slightly more convenient interface.
- *
- * \param metric_name String (UTF-8) name of the metric.
- * \param type_str Type of metric to send.
- * \param value Value to send.
- * \param sample_rate Percentage of samples to send.
- * \since 12
- */
-AST_OPTIONAL_API(void, ast_statsd_log_full, (const char *metric_name,
-	const char *metric_type, intmax_t value, double sample_rate), {});
-
-/*!
- * \brief Send a stat to the configured statsd server.
- * \param metric_name String (UTF-8) name of the metric.
- * \param metric_type Type of metric to send.
- * \param value Value to send.
- * \since 12
- */
-AST_OPTIONAL_API(void, ast_statsd_log, (const char *metric_name,
-	const char *metric_type, intmax_t value), {});
-
-/*!
- * \brief Send a random sampling of a stat to the configured statsd server.
- *
- * The type of sampled metrics is always \ref AST_STATSD_COUNTER. The given
- * \a sample_rate should be a percentage between 0.0 and 1.0. If it's <= 0.0,
- * then no samples will be sent. If it's >= 1.0, then all samples will be sent.
- *
- * \param metric_name String (UTF-8) name of the metric.
- * \param value Value to send.
- * \param sample_rate Percentage of samples to send.
- * \since 12
- */
-AST_OPTIONAL_API(void, ast_statsd_log_sample, (const char *metric_name,
-		intmax_t value, double sample_rate), {});
-
-
-#endif /* _ASTERISK_STATSD_H */
-
diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h
index d0879b2..e507183 100644
--- a/include/asterisk/stringfields.h
+++ b/include/asterisk/stringfields.h
@@ -311,44 +311,39 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
   \param x Pointer to a structure containing fields
   \param ptr Pointer to a field within the structure
   \param data String value to be copied into the field
-  \retval zero on success
-  \retval non-zero on error
+  \return nothing
 */
 #define ast_string_field_ptr_set(x, ptr, data) ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data)
 
-#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data)               \
-({                                                                                             \
-    int __res__ = 0;                                                                           \
-    const char *__d__ = (data);                                                                \
-    size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1;                                         \
-    ast_string_field *__p__ = (ast_string_field *) (ptr);                                      \
-    ast_string_field target = *__p__;                                                          \
-    if (__dlen__ == 1) {                                                                       \
-        __ast_string_field_release_active(field_mgr_pool, *__p__);                             \
-        *__p__ = __ast_string_field_empty;                                                     \
-    } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) ||                            \
-           (!__ast_string_field_ptr_grow(&field_mgr, &field_mgr_pool, __dlen__, __p__)) ||     \
-           (target = __ast_string_field_alloc_space(&field_mgr, &field_mgr_pool, __dlen__))) { \
-        if (target != *__p__) {                                                                \
-            __ast_string_field_release_active(field_mgr_pool, *__p__);                         \
-            *__p__ = target;                                                                   \
-        }                                                                                      \
-        memcpy(* (void **) __p__, __d__, __dlen__);                                            \
-    } else {                                                                                   \
-        __res__ = -1;                                                                          \
-    }                                                                                          \
-    __res__;                                                                                   \
-})
+#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) do {            \
+    const char *__d__ = (data);                                                                  \
+    size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1;                                           \
+    ast_string_field *__p__ = (ast_string_field *) (ptr);                                        \
+    ast_string_field target = *__p__;                                                            \
+    if (__dlen__ == 1) {                                                                         \
+        __ast_string_field_release_active(field_mgr_pool, *__p__);                               \
+        *__p__ = __ast_string_field_empty;                                                       \
+    } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) ||                              \
+           (!__ast_string_field_ptr_grow(&field_mgr, &field_mgr_pool, __dlen__, __p__)) ||       \
+           (target = __ast_string_field_alloc_space(&field_mgr, &field_mgr_pool, __dlen__))) {   \
+        if (target != (*__p__)) {                                                                \
+            __ast_string_field_release_active(field_mgr_pool, *__p__);                           \
+            *__p__ = target;                                                                     \
+        }                                                                                        \
+        memcpy(* (void **) __p__, __d__, __dlen__);                                              \
+    }                                                                                            \
+    } while (0)
 
 /*!
   \brief Set a field to a simple string value
   \param x Pointer to a structure containing fields
   \param field Name of the field to set
   \param data String value to be copied into the field
-  \retval zero on success
-  \retval non-zero on error
+  \return nothing
 */
-#define ast_string_field_set(x, field, data) ast_string_field_ptr_set(x, &(x)->field, data)
+#define ast_string_field_set(x, field, data) do {		\
+	ast_string_field_ptr_set(x, &(x)->field, data);		\
+	} while (0)
 
 /*!
   \brief Set a field to a complex (built) value
@@ -394,66 +389,4 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
 #define ast_string_field_build_va(x, field, fmt, args) \
 	__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
 
-/*!
-  \brief Compare the string fields in two instances of the same structure
-  \since 12
-  \param instance1 The first instance of the structure to be compared
-  \param instance2 The second instance of the structure to be compared
-  \retval zero if all string fields are equal (does not compare non-string field data)
-  \retval non-zero if the values of the string fields differ
-*/
-#define ast_string_fields_cmp(instance1, instance2) \
-({ \
-	int __res__ = 0; \
-	size_t __ptr_size__ = sizeof(char *); \
-	int __len__ = ((void *)&(instance1)->__field_mgr - (void *)&(instance1)->__field_mgr_pool)/__ptr_size__ - 1; \
-	int __len2__ = ((void *)&(instance2)->__field_mgr - (void *)&(instance2)->__field_mgr_pool)/__ptr_size__ - 1; \
-	if (__len__ == __len2__) { \
-		char **__head1__ = (void *)&(instance1)->__field_mgr_pool + __ptr_size__; \
-		char **__head2__ = (void *)&(instance2)->__field_mgr_pool + __ptr_size__; \
-		for (__len__ -= 1; __len__ >= 0; __len__--) { \
-			__res__ = strcmp(__head1__[__len__], __head2__[__len__]); \
-			if (__res__) { \
-				break; \
-			} \
-		} \
-	} else { \
-		__res__ = -1; \
-	} \
-	__res__; \
-})
-
-/*!
-  \brief Copy all string fields from one instance to another of the same structure
-  \since 12
-  \param copy The instance of the structure to be copied into
-  \param orig The instance of the structure to be copied from
-  \retval zero on success
-  \retval non-zero on error
-*/
-#define ast_string_fields_copy(copy, orig) \
-({ \
-	int __outer_res__ = 0; \
-	size_t __ptr_size__ = sizeof(char *); \
-	int __len__ = ((void *)&(copy)->__field_mgr - (void *)&(copy)->__field_mgr_pool)/__ptr_size__ - 1; \
-	int __len2__ = ((void *)&(orig)->__field_mgr - (void *)&(orig)->__field_mgr_pool)/__ptr_size__ - 1; \
-	if (__len__ == __len2__) { \
-		ast_string_field *__copy_head__ = (void *)&(copy)->__field_mgr_pool + __ptr_size__; \
-		ast_string_field *__orig_head__ = (void *)&(orig)->__field_mgr_pool + __ptr_size__; \
-		for (__len2__ -= 1; __len2__ >= 0; __len2__--) { \
-			__ast_string_field_release_active((copy)->__field_mgr_pool, __copy_head__[__len2__]); \
-			__copy_head__[__len2__] = __ast_string_field_empty; \
-		} \
-		for (__len__ -= 1; __len__ >= 0; __len__--) { \
-			if (ast_string_field_ptr_set((copy), &__copy_head__[__len__], __orig_head__[__len__])) { \
-				__outer_res__ = -1; \
-				break; \
-			} \
-		} \
-	} else { \
-		__outer_res__ = -1; \
-	} \
-	__outer_res__; \
-})
-
 #endif /* _ASTERISK_STRINGFIELDS_H */
diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h
index 79a2e49..aae26ab 100644
--- a/include/asterisk/strings.h
+++ b/include/asterisk/strings.h
@@ -29,7 +29,6 @@
 
 #include "asterisk/utils.h"
 #include "asterisk/threadstorage.h"
-#include "asterisk/astobj2.h"
 
 #if defined(DEBUG_OPAQUE)
 #define __AST_STR_USED used2
@@ -83,60 +82,6 @@ static force_inline int attribute_pure ast_strlen_zero(const char *s)
  */
 #define S_COR(a, b, c) ({typeof(&((b)[0])) __x = (b); (a) && !ast_strlen_zero(__x) ? (__x) : (c);})
 
-/*
-  \brief Checks whether a string begins with another.
-  \since 12.0.0
-  \param str String to check.
-  \param prefix Prefix to look for.
-  \param 1 if \a str begins with \a prefix, 0 otherwise.
- */
-static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
-{
-	ast_assert(str != NULL);
-	ast_assert(prefix != NULL);
-	while (*str == *prefix && *prefix != '\0') {
-		++str;
-		++prefix;
-	}
-	return *prefix == '\0';
-}
-
-/*
-  \brief Checks whether a string ends with another.
-  \since 12.0.0
-  \param str String to check.
-  \param suffix Suffix to look for.
-  \param 1 if \a str ends with \a suffix, 0 otherwise.
- */
-static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
-{
-	size_t str_len;
-	size_t suffix_len;
-
-	ast_assert(str != NULL);
-	ast_assert(suffix != NULL);
-	str_len = strlen(str);
-	suffix_len = strlen(suffix);
-
-	if (suffix_len > str_len) {
-		return 0;
-	}
-
-	return strcmp(str + str_len - suffix_len, suffix) == 0;
-}
-
-/*!
- * \brief return Yes or No depending on the argument.
- *
- * Note that this macro is used my AMI, where a literal "Yes" and "No" are
- * expected, and translations would cause problems.
- *
- * \param x Boolean value
- * \return "Yes" if x is true (non-zero)
- * \return "No" if x is false (zero)
- */
-#define AST_YESNO(x) ((x) ? "Yes" : "No")
-
 /*!
   \brief Gets a pointer to the first non-whitespace character in a string.
   \param str the input string
@@ -236,66 +181,6 @@ char *ast_strip(char *s),
 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes);
 
 /*!
-  \brief Flags for ast_strsep
- */
-enum ast_strsep_flags {
-	AST_STRSEP_STRIP =    0x01, /*!< Trim, then strip quotes.  You may want to trim again */
-	AST_STRSEP_TRIM =     0x02, /*!< Trim leading and trailing whitespace */
-	AST_STRSEP_UNESCAPE = 0x04, /*!< Unescape '\' */
-	AST_STRSEP_ALL =      0x07, /*!< Trim, strip, unescape */
-};
-
-/*!
-  \brief Act like strsep but ignore separators inside quotes.
-  \param s Pointer to address of the the string to be processed.
-  Will be modified and can't be constant.
-  \param sep A single character delimiter.
-  \param flags Controls post-processing of the result.
-  AST_STRSEP_TRIM trims all leading and trailing whitespace from the result.
-  AST_STRSEP_STRIP does a trim then strips the outermost quotes.  You may want
-  to trim again after the strip.  Just OR both the TRIM and STRIP flags.
-  AST_STRSEP_UNESCAPE unescapes '\' sequences.
-  AST_STRSEP_ALL does all of the above processing.
-  \return The next token or NULL if done or if there are more than 8 levels of
-  nested quotes.
-
-  This function acts like strsep with three exceptions...
-  The separator is a single character instead of a string.
-  Separators inside quotes are treated literally instead of like separators.
-  You can elect to have leading and trailing whitespace and quotes
-  stripped from the result and have '\' sequences unescaped.
-
-  Like strsep, ast_strsep maintains no internal state and you can call it
-  recursively using different separators on the same storage.
-
-  Also like strsep, for consistent results, consecutive separators are not
-  collapsed so you may get an empty string as a valid result.
-
-  Examples:
-  \code
-	char *mystr = ast_strdupa("abc=def,ghi='zzz=yyy,456',jkl");
-	char *token, *token2, *token3;
-
-	while((token = ast_strsep(&mystr, ',', AST_SEP_STRIP))) {
-		// 1st token will be aaa=def
-		// 2nd token will be ghi='zzz=yyy,456'
-		while((token2 = ast_strsep(&token, '=', AST_SEP_STRIP))) {
-			// 1st token2 will be ghi
-			// 2nd token2 will be zzz=yyy,456
-			while((token3 = ast_strsep(&token2, ',', AST_SEP_STRIP))) {
-				// 1st token3 will be zzz=yyy
-				// 2nd token3 will be 456
-				// and so on
-			}
-		}
-		// 3rd token will be jkl
-	}
-
-  \endcode
- */
-char *ast_strsep(char **s, const char sep, uint32_t flags);
-
-/*!
   \brief Strip backslash for "escaped" semicolons, 
 	the string to be stripped (will be modified).
   \return The stripped string.
@@ -392,23 +277,7 @@ int attribute_pure ast_true(const char *val);
 int attribute_pure ast_false(const char *val);
 
 /*
- * \brief Join an array of strings into a single string.
- * \param s the resulting string buffer
- * \param len the length of the result buffer, s
- * \param w an array of strings to join.
- * \param size the number of elements to join
- * \param delim delimiter between elements
- *
- * This function will join all of the strings in the array 'w' into a single
- * string.  It will also place 'delim' in the result buffer in between each
- * string from 'w'.
- * \since 12
-*/
-void ast_join_delim(char *s, size_t len, const char * const w[],
-		    unsigned int size, char delim);
-
-/*
- * \brief Join an array of strings into a single string.
+ *  \brief Join an array of strings into a single string.
  * \param s the resulting string buffer
  * \param len the length of the result buffer, s
  * \param w an array of strings to join.
@@ -417,33 +286,7 @@ void ast_join_delim(char *s, size_t len, const char * const w[],
  * string.  It will also place a space in the result buffer in between each
  * string from 'w'.
 */
-#define ast_join(s, len, w) ast_join_delim(s, len, w, -1, ' ')
-
-/*
- * \brief Attempts to convert the given string to camel case using
- *        the specified delimiter.
- *
- * note - returned string needs to be freed
- *
- * \param s the string to convert
- * \param delim delimiter to parse out
- *
- * \retval The string converted to "CamelCase"
- * \since 12
-*/
-char *ast_to_camel_case_delim(const char *s, const char *delim);
-
-/*
- * \brief Attempts to convert the given string to camel case using
- *        an underscore as the specified delimiter.
- *
- * note - returned string needs to be freed
- *
- * \param s the string to convert
- *
- * \retval The string converted to "CamelCase"
-*/
-#define ast_to_camel_case(s) ast_to_camel_case_delim(s, "_")
+void ast_join(char *s, size_t len, const char * const w[]);
 
 /*
   \brief Parse a time (integer) string.
@@ -973,7 +816,6 @@ AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_set_va(struct a
  * by value to a function that calls ast_str_append_va(), then the original ast_str
  * pointer may be invalidated due to a reallocation.
  *
- * \param buf, max_len, fmt, ap
  */
 AST_INLINE_API(int __attribute__((format(printf, 3, 0))) ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap),
 {
@@ -1170,106 +1012,4 @@ static force_inline int attribute_pure ast_str_case_hash(const char *str)
 	return abs(hash);
 }
 
-/*!
- * \brief Convert a string to all lower-case
- *
- * \param str The string to be converted to lower case
- *
- * \retval str for convenience
- */
-static force_inline char *attribute_pure ast_str_to_lower(char *str)
-{
-	char *str_orig = str;
-	if (!str) {
-		return str;
-	}
-
-	for (; *str; ++str) {
-		*str = tolower(*str);
-	}
-
-	return str_orig;
-}
-
-/*!
- * \brief Convert a string to all upper-case
- *
- * \param str The string to be converted to upper case
- *
- * \retval str for convenience
- */
-static force_inline char *attribute_pure ast_str_to_upper(char *str)
-{
-	char *str_orig = str;
-	if (!str) {
-		return str;
-	}
-
-	for (; *str; ++str) {
-		*str = toupper(*str);
-	}
-
-	return str_orig;
-}
-
-/*!
- * \since 12
- * \brief Allocates a hash container for bare strings
- *
- * \param buckets The number of buckets to use for the hash container
- *
- * \retval AO2 container for strings
- * \retval NULL if allocation failed
- */
-#define ast_str_container_alloc(buckets) ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, buckets)
-
-/*!
- * \since 12
- * \brief Allocates a hash container for bare strings
- *
- * \param opts Options to be provided to the container
- * \param buckets The number of buckets to use for the hash container
- *
- * \retval AO2 container for strings
- * \retval NULL if allocation failed
- */
-struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets);
-
-/*!
- * \since 12
- * \brief Adds a string to a string container allocated by ast_str_container_alloc
- *
- * \param str_container The container to which to add a string
- * \param add The string to add to the container
- *
- * \retval zero on success
- * \retval non-zero if the operation failed
- */
-int ast_str_container_add(struct ao2_container *str_container, const char *add);
-
-/*!
- * \since 12
- * \brief Removes a string from a string container allocated by ast_str_container_alloc
- *
- * \param str_container The container from which to remove a string
- * \param remove The string to remove from the container
- */
-void ast_str_container_remove(struct ao2_container *str_container, const char *remove);
-
-/*!
- * \brief Create a pseudo-random string of a fixed length.
- *
- * This function is useful for generating a string whose randomness
- * does not need to be across all time and space, does not need to
- * be cryptographically secure, and needs to fit in a limited space.
- *
- * This function will write a null byte at the final position
- * in the buffer (buf[size - 1]). So if you pass in a size of
- * 10, then this will generate a random 9-character string.
- *
- * \param buf Buffer to write random string into.
- * \param size The size of the buffer.
- * \return A pointer to buf
- */
-char *ast_generate_random_string(char *buf, size_t size);
 #endif /* _ASTERISK_STRINGS_H */
diff --git a/include/asterisk/syslog.h b/include/asterisk/syslog.h
index a0dc9e9..45d351a 100644
--- a/include/asterisk/syslog.h
+++ b/include/asterisk/syslog.h
@@ -28,6 +28,8 @@
 extern "C" {
 #endif
 
+#define ASTNUMLOGLEVELS 32
+
 /*!
  * \since 1.8
  * \brief Maps a syslog facility name from a string to a syslog facility
diff --git a/include/asterisk/taskprocessor.h b/include/asterisk/taskprocessor.h
index f16f144..0f1876e 100644
--- a/include/asterisk/taskprocessor.h
+++ b/include/asterisk/taskprocessor.h
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007-2013, Digium, Inc.
+ * Copyright (C) 2007-2008, Digium, Inc.
  *
  * Dwayne M. Hubbard <dhubbard at digium.com>
  *
@@ -22,33 +22,22 @@
  *
  * \author Dwayne M. Hubbard <dhubbard at digium.com>
  *
- * \note A taskprocessor is a named object containing a task queue that
- * serializes tasks pushed into it by [a] module(s) that reference the taskprocessor.
- * A taskprocessor is created the first time its name is requested via the
- * ast_taskprocessor_get() function or the ast_taskprocessor_create_with_listener()
- * function and destroyed when the taskprocessor reference count reaches zero. A
- * taskprocessor also contains an accompanying listener that is notified when changes
- * in the task queue occur.
+ * \note A taskprocessor is a named singleton containing a processing thread and
+ * a task queue that serializes tasks pushed into it by [a] module(s) that reference the taskprocessor.  
+ * A taskprocessor is created the first time its name is requested via the ast_taskprocessor_get()
+ * function and destroyed when the taskprocessor reference count reaches zero.
  *
- * A task is a wrapper around a task-handling function pointer and a data
- * pointer.  A task is pushed into a taskprocessor queue using the
+ * Modules that obtain a reference to a taskprocessor can queue tasks into the taskprocessor
+ * to be processed by the singleton processing thread when the task is popped off the front 
+ * of the queue.  A task is a wrapper around a task-handling function pointer and a data
+ * pointer.  It is the responsibility of the task handling function to free memory allocated for
+ * the task data pointer.  A task is pushed into a taskprocessor queue using the 
  * ast_taskprocessor_push(taskprocessor, taskhandler, taskdata) function and freed by the
- * taskprocessor after the task handling function returns.  A module releases its
- * reference to a taskprocessor using the ast_taskprocessor_unreference() function which
- * may result in the destruction of the taskprocessor if the taskprocessor's reference
- * count reaches zero. When the taskprocessor's reference count reaches zero, its
- * listener's shutdown() callback will be called. Any further attempts to execute tasks
- * will be denied.
- *
- * The taskprocessor listener has the flexibility of doling out tasks to best fit the
- * module's needs. For instance, a taskprocessor listener may have a single dispatch
- * thread that handles all tasks, or it may dispatch tasks to a thread pool.
- *
- * There is a default taskprocessor listener that will be used if a taskprocessor is
- * created without any explicit listener. This default listener runs tasks sequentially
- * in a single thread. The listener will execute tasks as long as there are tasks to be
- * processed. When the taskprocessor is shut down, the default listener will stop
- * processing tasks and join its execution thread.
+ * taskprocessor after the task handling function returns.  A module releases its reference to a
+ * taskprocessor using the ast_taskprocessor_unreference() function which may result in the
+ * destruction of the taskprocessor if the taskprocessor's reference count reaches zero.  Tasks waiting
+ * to be processed in the taskprocessor queue when the taskprocessor reference count reaches zero
+ * will be purged and released from the taskprocessor queue without being processed.
  */
 
 #ifndef __AST_TASKPROCESSOR_H__
@@ -59,9 +48,9 @@ struct ast_taskprocessor;
 /*!
  * \brief ast_tps_options for specification of taskprocessor options
  *
- * Specify whether a taskprocessor should be created via ast_taskprocessor_get() if the taskprocessor
- * does not already exist.  The default behavior is to create a taskprocessor if it does not already exist
- * and provide its reference to the calling function.  To only return a reference to a taskprocessor if
+ * Specify whether a taskprocessor should be created via ast_taskprocessor_get() if the taskprocessor 
+ * does not already exist.  The default behavior is to create a taskprocessor if it does not already exist 
+ * and provide its reference to the calling function.  To only return a reference to a taskprocessor if 
  * and only if it exists, use the TPS_REF_IF_EXISTS option in ast_taskprocessor_get().
  */
 enum ast_tps_options {
@@ -71,87 +60,13 @@ enum ast_tps_options {
 	TPS_REF_IF_EXISTS = (1 << 0),
 };
 
-struct ast_taskprocessor_listener;
-
-struct ast_taskprocessor_listener_callbacks {
-	/*!
-	 * \brief The taskprocessor has started completely
-	 *
-	 * This indicates that the taskprocessor is fully set up and the listener
-	 * can now start interacting with it.
-	 *
-	 * \param listener The listener to start
-	 */
-	int (*start)(struct ast_taskprocessor_listener *listener);
-	/*!
-	 * \brief Indicates a task was pushed to the processor
-	 *
-	 * \param listener The listener
-	 * \param was_empty If non-zero, the taskprocessor was empty prior to the task being pushed
-	 */
-	void (*task_pushed)(struct ast_taskprocessor_listener *listener, int was_empty);
-	/*!
-	 * \brief Indicates the task processor has become empty
-	 *
-	 * \param listener The listener
-	 */
-	void (*emptied)(struct ast_taskprocessor_listener *listener);
-	/*!
-	 * \brief Indicates the taskprocessor wishes to die.
-	 *
-	 * All operations on the task processor must to be stopped in
-	 * this callback. This is an opportune time to free the listener's
-	 * user data if it is not going to be used anywhere else.
-	 *
-	 * After this callback returns, it is NOT safe to operate on the
-	 * listener's reference to the taskprocessor.
-	 *
-	 * \param listener The listener
-	 */
-	void (*shutdown)(struct ast_taskprocessor_listener *listener);
-	void (*dtor)(struct ast_taskprocessor_listener *listener);
-};
-
-/*!
- * \brief Get a reference to the listener's taskprocessor
- *
- * This will return the taskprocessor with its reference count increased. Release
- * the reference to this object by using ast_taskprocessor_unreference()
- *
- * \param listener The listener that has the taskprocessor
- * \return The taskprocessor
- */
-struct ast_taskprocessor *ast_taskprocessor_listener_get_tps(const struct ast_taskprocessor_listener *listener);
-
-/*!
- * \brief Get the user data from the listener
- * \param listener The taskprocessor listener
- * \return The listener's user data
- */
-void *ast_taskprocessor_listener_get_user_data(const struct ast_taskprocessor_listener *listener);
-
-/*!
- * \brief Allocate a taskprocessor listener
- *
- * \since 12.0.0
- *
- * This will result in the listener being allocated with the specified
- * callbacks.
- *
- * \param callbacks The callbacks to assign to the listener
- * \param user_data The user data for the listener
- * \retval NULL Failure
- * \retval non-NULL The newly allocated taskprocessor listener
- */
-struct ast_taskprocessor_listener *ast_taskprocessor_listener_alloc(const struct ast_taskprocessor_listener_callbacks *callbacks, void *user_data);
-
 /*!
  * \brief Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary
  *
  * The default behavior of instantiating a taskprocessor if one does not already exist can be
  * disabled by specifying the TPS_REF_IF_EXISTS ast_tps_options as the second argument to ast_taskprocessor_get().
  * \param name The name of the taskprocessor
- * \param create Use 0 by default or specify TPS_REF_IF_EXISTS to return NULL if the taskprocessor does
+ * \param create Use 0 by default or specify TPS_REF_IF_EXISTS to return NULL if the taskprocessor does 
  * not already exist
  * return A pointer to a reference counted taskprocessor under normal conditions, or NULL if the
  * TPS_REF_IF_EXISTS reference type is specified and the taskprocessor does not exist
@@ -160,34 +75,6 @@ struct ast_taskprocessor_listener *ast_taskprocessor_listener_alloc(const struct
 struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_options create);
 
 /*!
- * \brief Create a taskprocessor with a custom listener
- *
- * \since 12.0.0
- *
- * Note that when a taskprocessor is created in this way, it does not create
- * any threads to execute the tasks. This job is left up to the listener.
- * The listener's start() callback will be called during this function.
- *
- * \param name The name of the taskprocessor to create
- * \param listener The listener for operations on this taskprocessor
- * \retval NULL Failure
- * \reval non-NULL success
- */
-struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener);
-
-/*!
- * \brief Sets the local data associated with a taskprocessor.
- *
- * \since 12.0.0
- *
- * See ast_taskprocessor_push_local().
- *
- * \param tps Task processor.
- * \param local_data Local data to associate with \a tps.
- */
-void ast_taskprocessor_set_local(struct ast_taskprocessor *tps, void *local_data);
-
-/*!
  * \brief Unreference the specified taskprocessor and its reference count will decrement.
  *
  * Taskprocessors use astobj2 and will unlink from the taskprocessor singleton container and destroy
@@ -209,53 +96,6 @@ void *ast_taskprocessor_unreference(struct ast_taskprocessor *tps);
  */
 int ast_taskprocessor_push(struct ast_taskprocessor *tps, int (*task_exe)(void *datap), void *datap);
 
-/*! \brief Local data parameter */
-struct ast_taskprocessor_local {
-	/*! Local data, associated with the taskprocessor. */
-	void *local_data;
-	/*! Data pointer passed with this task. */
-	void *data;
-};
-
-/*!
- * \brief Push a task into the specified taskprocessor queue and signal the
- * taskprocessor thread.
- *
- * The callback receives a \ref ast_taskprocessor_local struct, which contains
- * both the provided \a datap pointer, and any local data set on the
- * taskprocessor with ast_taskprocessor_set_local().
- *
- * \param tps The taskprocessor structure
- * \param task_exe The task handling function to push into the taskprocessor queue
- * \param datap The data to be used by the task handling function
- * \retval 0 success
- * \retval -1 failure
- * \since 12.0.0
- */
-int ast_taskprocessor_push_local(struct ast_taskprocessor *tps,
-	int (*task_exe)(struct ast_taskprocessor_local *local), void *datap);
-
-/*!
- * \brief Pop a task off the taskprocessor and execute it.
- *
- * \since 12.0.0
- *
- * \param tps The taskprocessor from which to execute.
- * \retval 0 There is no further work to be done.
- * \retval 1 Tasks still remain in the taskprocessor queue.
- */
-int ast_taskprocessor_execute(struct ast_taskprocessor *tps);
-
-/*!
- * \brief Am I the given taskprocessor's current task.
- * \since 12.7.0
- *
- * \param tps Taskprocessor to check.
- *
- * \retval non-zero if current thread is the taskprocessor thread.
- */
-int ast_taskprocessor_is_task(struct ast_taskprocessor *tps);
-
 /*!
  * \brief Return the name of the taskprocessor singleton
  * \since 1.6.1
diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 0e8d9d0..3356a92 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -210,6 +210,7 @@ struct ast_tcptls_session_instance {
 	FILE *f;    /*!< fopen/funopen result */
 	int fd;     /*!< the socket returned by accept() */
 	SSL *ssl;   /*!< ssl state */
+/*	iint (*ssl_setup)(SSL *); */
 	int client;
 	struct ast_sockaddr remote_address;
 	struct ast_tcptls_session_args *parent;
@@ -221,8 +222,6 @@ struct ast_tcptls_session_instance {
 	struct ast_str *overflow_buf;
 	/*! ao2 FILE stream cookie object associated with f. */
 	struct ast_tcptls_stream *stream_cookie;
-	/*! ao2 object private data of parent->worker_fn */
-	void *private_data;
 };
 
 #if defined(HAVE_FUNOPEN)
diff --git a/include/asterisk/term.h b/include/asterisk/term.h
index 18d743b..bbdc753 100644
--- a/include/asterisk/term.h
+++ b/include/asterisk/term.h
@@ -29,7 +29,7 @@ extern "C" {
 
 #define ESC 0x1b
 
-/*! \name Terminal Attributes
+/*! \name Terminal Attributes 
 */
 /*@{ */
 #define ATTR_RESET	0
@@ -44,17 +44,17 @@ extern "C" {
 /*! \name Terminal Colors
 */
 /*@{ */
-#define COLOR_BLACK     30
-#define COLOR_GRAY      (30 | 128)
-#define COLOR_RED       31
-#define COLOR_BRRED     (31 | 128)
-#define COLOR_GREEN     32
-#define COLOR_BRGREEN   (32 | 128)
-#define COLOR_BROWN     33
-#define COLOR_YELLOW    (33 | 128)
-#define COLOR_BLUE      34
-#define COLOR_BRBLUE    (34 | 128)
-#define COLOR_MAGENTA   35
+#define COLOR_BLACK 	30
+#define COLOR_GRAY  	(30 | 128)
+#define COLOR_RED	31
+#define COLOR_BRRED	(31 | 128)
+#define COLOR_GREEN	32
+#define COLOR_BRGREEN	(32 | 128)
+#define COLOR_BROWN	33
+#define COLOR_YELLOW	(33 | 128)
+#define COLOR_BLUE	34
+#define COLOR_BRBLUE	(34 | 128)
+#define COLOR_MAGENTA	35
 #define COLOR_BRMAGENTA (35 | 128)
 #define COLOR_CYAN      36
 #define COLOR_BRCYAN    (36 | 128)
@@ -62,27 +62,10 @@ extern "C" {
 #define COLOR_BRWHITE   (37 | 128)
 /*@} */
 
-/*! \brief Shortcut macros for coloring a set of text
- */
-#define COLORIZE_FMT	"%s%s%s"
-#define COLORIZE(fg, bg, str)	ast_term_color(fg,bg),str,ast_term_reset()
 /*! \brief Maximum number of characters needed for a color escape sequence,
  *         plus a null char */
-#define AST_TERM_MAX_ESCAPE_CHARS   12
-#define AST_TERM_MAX_ROTATING_BUFFERS	15
+#define AST_TERM_MAX_ESCAPE_CHARS   23
 
-/*! \brief Colorize a specified string by adding terminal color codes
- *
- * \param outbuf Result buffer
- * \param inbuf Starting string
- * \param fgcolor Foreground color, specified as one of the constants in include/asterisk/term.h.  Use '0' if the want the normal terminal foreground color.
- * \param bgcolor Background color, specified as one of the constants in include/asterisk/term.h.  Use '0' if you want the normal terminal background color.
- * \param maxout Maximum size of outbuf
- *
- * \return outbuf
- *
- * \deprecated Due to the necessity of pre-sizing a result buffer, new code should avoid using this function in preference to ast_term_color_code() or ast_term_color().
- */
 char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout);
 
 /*!
@@ -98,52 +81,28 @@ char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int
 int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor);
 
 /*!
- * \brief Return a color sequence string
- * \param fgcolor foreground color
- * \param bgcolor background color
- * \note This function may be called up to 15 times within the arguments to a single function without the danger of overwriting a common buffer.
- *
- * \return A color sequence string, or the empty string, on error
- */
-const char *ast_term_color(int fgcolor, int bgcolor);
-
-/*!
- * \brief Returns the terminal reset code
- * \return String which, when sent to the screen, resets the terminal colors
- */
-const char *ast_term_reset(void);
-
-/*!
  * \brief Write a color sequence to a string
  *
  * \param outbuf the location to write to
  * \param fgcolor foreground color
  * \param bgcolor background color
  * \param maxout maximum number of characters to write
- * \deprecated You should use ast_term_color_code or ast_term_color, instead.
  *
  * \return outbuf
  */
 char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout);
 
-/*!
- * \brief Remove colorings from a specified string
- * \param outbuf the location to write to
- * \param inbuf the original string
- * \param maxout the available size of outbuf
- * \return outbuf
- */
 char *term_strip(char *outbuf, const char *inbuf, int maxout);
 
 void term_filter_escapes(char *line);
 
 char *term_prompt(char *outbuf, const char *inbuf, int maxout);
 
-const char *term_prep(void);
+char *term_prep(void);
 
-const char *term_end(void);
+char *term_end(void);
 
-const char *term_quit(void);
+char *term_quit(void);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
diff --git a/include/asterisk/test.h b/include/asterisk/test.h
index 2ea8332..964f5ad 100644
--- a/include/asterisk/test.h
+++ b/include/asterisk/test.h
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2009-2013, Digium, Inc.
+ * Copyright (C) 2009-2010, Digium, Inc.
  *
  * David Vossel <dvossel at digium.com>
  * Russell Bryant <russell at digium.com>
@@ -35,7 +35,7 @@
 #include "asterisk/strings.h"
 #endif
 
-/*!
+/*! 
 
 \page AstUnitTestAPI Asterisk Unit Test API
 
@@ -57,7 +57,7 @@
 
 \code
    AST_TEST_DEFINE(sample_test_cb) \\The name of the callback function
-   {                               \\The the function's body
+   {                               \\The the function's body 
       switch (cmd) {
       case TEST_INIT:
           info->name = "sample_test";
@@ -86,7 +86,7 @@
       Details of the test execution, especially failure details, should be provided
       by using the ast_test_status_update() function.
 
-\subsection RegisterTest Register a Test
+\subsection RegisterTest Register a Test 
 
    Register the test using the AST_TEST_REGISTER macro.
 
@@ -127,48 +127,12 @@
 #define AST_TEST_REGISTER(cb)
 #define AST_TEST_UNREGISTER(cb)
 #define ast_test_status_update(a,b,c...)
-#define ast_test_debug(test, fmt, ...)	ast_cli		/* Dummy function that should not be called. */
 
 #endif
 
 /*! Macros used for the Asterisk Test Suite AMI events */
 #ifdef TEST_FRAMEWORK
 
-struct stasis_topic;
-struct stasis_message_type;
-
-/*!
- * \since 12
- * \brief Obtain the \ref stasis_topic for \ref ast_test_suite_event_notify
- * messages
- *
- * \retval A stasis topic
- */
-struct stasis_topic *ast_test_suite_topic(void);
-
-/*!
- * \since 12
- * \brief Obtain the \ref stasis_message_type for \ref ast_test_suite_event_notify
- * messages
- *
- * \retval A stasis message type
- */
-struct stasis_message_type *ast_test_suite_message_type(void);
-
-/*!
- * \since 12
- * \brief The message payload in a \ref ast_test_suite_message_type
- */
-struct ast_test_suite_message_payload;
-
-/*!
- * \since 12
- * \brief Get the JSON for a \ref ast_test_suite_message_payload
- *
- * \retval An \ref ast_json object
- */
-struct ast_json *ast_test_suite_get_blob(struct ast_test_suite_message_payload *payload);
-
 /*!
  * \brief Notifies the test suite of a change in application state
  *
@@ -180,10 +144,28 @@ struct ast_json *ast_test_suite_get_blob(struct ast_test_suite_message_payload *
  * \param state		The state the application has changed to
  * \param fmt		The message with format parameters to add to the manager event
  *
- * \return Nothing
+ * \returns 0 on success
+ * \returns any other value on failure
  */
-void __ast_test_suite_event_notify(const char *file, const char *func, int line, const char *state, const char *fmt, ...)
-	__attribute__((format(printf, 5, 6)));
+int __ast_test_suite_event_notify(const char *file, const char *func, int line,
+		const char *state, const char *fmt, ...)
+		__attribute__((format(printf, 5, 6)));
+
+/*!
+ * \brief Notifies the test suite of a failed assert on an expression
+ *
+ * \details
+ * If the expression provided evaluates to true, no action is taken.  If the expression
+ * evaluates to a false, a TestEvent manager event is raised with a subtype of Assert, notifying
+ * the test suite that the expression failed to evaluate to true.
+ *
+ * \param exp	The expression to evaluate
+ *
+ * \returns 0 on success
+ * \returns any other value on failure
+ */
+int __ast_test_suite_assert_notify(const char *file, const char *func, int line,
+		const char *exp);
 
 /*!
  * \ref __ast_test_suite_event_notify()
@@ -191,9 +173,16 @@ void __ast_test_suite_event_notify(const char *file, const char *func, int line,
 #define ast_test_suite_event_notify(s, f, ...) \
 	__ast_test_suite_event_notify(__FILE__, __PRETTY_FUNCTION__, __LINE__, (s), (f), ## __VA_ARGS__)
 
+/*!
+ * \ref __ast_test_suite_assert_notify()
+ */
+#define ast_test_suite_assert(exp) \
+	( (exp) ? (void)0 : __ast_test_suite_assert_notify(__FILE__, __PRETTY_FUNCTION__, __LINE__, #exp))
+
 #else
 
-#define ast_test_suite_event_notify(s, f, ...)
+#define ast_test_suite_event_notify(s, f, ...) (void)0;
+#define ast_test_suite_assert(exp) (void)0;
 
 #endif
 
@@ -238,39 +227,13 @@ struct ast_test_info {
 /*!
  * \brief Generic test callback function
  *
- * \param info The test info object
- * \param cmd What to perform in the test
- * \param test The actual test object being manipulated
+ * \param error buffer string for failure results
  *
  * \retval AST_TEST_PASS for pass
  * \retval AST_TEST_FAIL for failure
  */
 typedef enum ast_test_result_state (ast_test_cb_t)(struct ast_test_info *info,
-	enum ast_test_command cmd, struct ast_test *test);
-
-/*!
- * \since 12
- * \brief A test initialization callback function
- *
- * \param info The test info object
- * \param test The actual test object that will be manipulated
- *
- * \retval 0 success
- * \retval other failure. This will fail the test.
- */
-typedef int (ast_test_init_cb_t)(struct ast_test_info *info, struct ast_test *test);
-
-/*!
- * \since 12
- * \brief A test cleanup callback function
- *
- * \param info The test info object
- * \param test The actual test object that was executed
- *
- * \retval 0 success
- * \retval other failure. This will fail the test.
- */
-typedef int (ast_test_cleanup_cb_t)(struct ast_test_info *info, struct ast_test *test);
+		enum ast_test_command cmd, struct ast_test *test);
 
 /*!
  * \brief unregisters a test with the test framework
@@ -293,62 +256,6 @@ int ast_test_unregister(ast_test_cb_t *cb);
 int ast_test_register(ast_test_cb_t *cb);
 
 /*!
- * \since 12
- * \brief Register an initialization function to be run before each test
- * executes
- *
- * This function lets a registered test have an initialization function that
- * will be run prior to test execution. Each category may have a single init
- * function.
- *
- * If the initialization function returns a non-zero value, the test will not
- * be executed and the result will be set to \ref AST_TEST_FAIL.
- *
- * \retval 0 success
- * \retval other failure
- */
-int ast_test_register_init(const char *category, ast_test_init_cb_t *cb);
-
-/*!
- * \since 12
- * \brief Register a cleanup function to be run after each test executes
- *
- * This function lets a registered test have a cleanup function that will be
- * run immediately after test execution. Each category may have a single
- * cleanup function.
- *
- * If the cleanup function returns a non-zero value, the test result will be
- * set to \ref AST_TEST_FAIL.
- *
- * \retval 0 success
- * \retval other failure
- */
-int ast_test_register_cleanup(const char *category, ast_test_cleanup_cb_t *cb);
-
-
-/*!
- * \brief Unit test debug output.
- * \since 12.0.0
- *
- * \param test Unit test control structure.
- * \param fmt printf type format string.
- *
- * \return Nothing
- */
-void ast_test_debug(struct ast_test *test, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
-/*!
- * \brief Set the result of a test.
- *
- * If the caller of this function sets the result to AST_TEST_FAIL, returning
- * AST_TEST_PASS from the test will not pass the test. This lets a test writer
- * end and fail a test and continue on with logic, catching multiple failure
- * conditions within a single test.
- */
-void ast_test_set_result(struct ast_test *test, enum ast_test_result_state state);
-
-
-/*!
  * \brief update test's status during testing.
  *
  * \param test currently executing test
@@ -356,8 +263,9 @@ void ast_test_set_result(struct ast_test *test, enum ast_test_result_state state
  * \retval 0 success
  * \retval -1 failure
  */
-int __ast_test_status_update(const char *file, const char *func, int line, struct ast_test *test, const char *fmt, ...)
-	__attribute__((format(printf, 5, 6)));
+int __ast_test_status_update(const char *file, const char *func, int line,
+		struct ast_test *test, const char *fmt, ...)
+		__attribute__((format(printf, 5, 6)));
 
 /*!
  * \ref __ast_test_status_update()
@@ -367,7 +275,7 @@ int __ast_test_status_update(const char *file, const char *func, int line, struc
 /*!
  * \brief Check a test condition, failing the test if it's not true.
  *
- * \since 12.0.0
+ * \since 11.14.0
  *
  * This macro evaluates \a condition. If the condition evaluates to true (non-zero),
  * nothing happens. If it evaluates to false (zero), then the failure is printed
@@ -381,14 +289,13 @@ int __ast_test_status_update(const char *file, const char *func, int line, struc
  * \param test Currently executing test
  * \param condition Boolean condition to check.
  */
-#define ast_test_validate(test, condition, ...)				\
+#define ast_test_validate(test, condition)				\
 	do {								\
 		if (!(condition)) {					\
-			__ast_test_status_update(__FILE__, __PRETTY_FUNCTION__, __LINE__, (test), "%s: %s\n", strlen(#__VA_ARGS__) ? #__VA_ARGS__ : "Condition failed", #condition); \
+			__ast_test_status_update(__FILE__, __PRETTY_FUNCTION__, __LINE__, (test), "Condition failed: %s\n", #condition); \
 			return AST_TEST_FAIL;				\
 		}							\
 	} while(0)
 
-
 #endif /* TEST_FRAMEWORK */
 #endif /* _AST_TEST_H */
diff --git a/include/asterisk/threadpool.h b/include/asterisk/threadpool.h
deleted file mode 100644
index e1e7727..0000000
--- a/include/asterisk/threadpool.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012-2013, Digium, Inc.
- *
- * Mark Michelson <mmmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-
-#ifndef _ASTERISK_THREADPOOL_H
-#define _ASTERISK_THREADPOOL_H
-
-struct ast_threadpool;
-struct ast_taskprocessor;
-struct ast_threadpool_listener;
-
-struct ast_threadpool_listener_callbacks {
-	/*!
-	 * \brief Indicates that the state of threads in the pool has changed
-	 *
-	 * \param pool The pool whose state has changed
-	 * \param listener The threadpool listener
-	 * \param active_threads The number of active threads in the pool
-	 * \param idle_threads The number of idle threads in the pool
-	 */
-	void (*state_changed)(struct ast_threadpool *pool,
-			struct ast_threadpool_listener *listener,
-			int active_threads,
-			int idle_threads);
-	/*!
-	 * \brief Indicates that a task was pushed to the threadpool
-	 *
-	 * \param pool The pool that had a task pushed
-	 * \param listener The threadpool listener
-	 * \param was_empty Indicates whether there were any tasks prior to adding the new one.
-	 */
-	void (*task_pushed)(struct ast_threadpool *pool,
-			struct ast_threadpool_listener *listener,
-			int was_empty);
-	/*!
-	 * \brief Indicates the threadpool's taskprocessor has become empty
-	 *
-	 * \param pool The pool that has become empty
-	 * \param listener The threadpool's listener
-	 */
-	void (*emptied)(struct ast_threadpool *pool, struct ast_threadpool_listener *listener);
-
-	/*!
-	 * \brief The threadpool is shutting down
-	 *
-	 * This would be an opportune time to free the listener's user data
-	 * if one wishes. However, it is acceptable to not do so if the user data
-	 * should persist beyond the lifetime of the pool.
-	 *
-	 * \param listener The threadpool's listener
-	 */
-	void (*shutdown)(struct ast_threadpool_listener *listener);
-};
-
-struct ast_threadpool_options {
-#define AST_THREADPOOL_OPTIONS_VERSION 1
-	/*! Version of threadpool options in use */
-	int version;
-	/*!
-	 * \brief Time limit in seconds for idle threads
-	 *
-	 * A time of 0 or less will mean no timeout.
-	 */
-	int idle_timeout;
-	/*!
-	 * \brief Number of threads to increment pool by
-	 *
-	 * If a task is added into a pool and no idle thread is
-	 * available to activate, then the pool can automatically
-	 * grow by the given amount.
-	 *
-	 * Zero is a perfectly valid value to give here if you want
-	 * to control threadpool growth yourself via your listener.
-	 */
-	int auto_increment;
-	/*!
-	 * \brief Number of threads the pool will start with
-	 *
-	 * When the threadpool is allocated, it will immediately size
-	 * itself to have this number of threads in it.
-	 *
-	 * Zero is a valid value if the threadpool should start
-	 * without any threads allocated.
-	 */
-	int initial_size;
-	/*!
-	 * \brief Maximum number of threads a pool may have
-	 *
-	 * When the threadpool's size increases, it can never increase
-	 * beyond this number of threads.
-	 *
-	 * Zero is a valid value if the threadpool does not have a
-	 * maximum size.
-	 */
-	int max_size;
-	/*!
-	 * \brief Function to call when a thread starts
-	 *
-	 * This is useful if there is something common that all threads
-	 * in a threadpool need to do when they start.
-	 */
-	void (*thread_start)(void);
-	/*!
-	 * \brief Function to call when a thread ends
-	 *
-	 * This is useful if there is common cleanup to execute when
-	 * a thread completes
-	 */
-	void (*thread_end)(void);
-};
-
-/*!
- * \brief Allocate a threadpool listener
- *
- * This function will call back into the alloc callback for the
- * listener.
- *
- * \param callbacks Listener callbacks to assign to the listener
- * \param user_data User data to be stored in the threadpool listener
- * \retval NULL Failed to allocate the listener
- * \retval non-NULL The newly-created threadpool listener
- */
-struct ast_threadpool_listener *ast_threadpool_listener_alloc(
-		const struct ast_threadpool_listener_callbacks *callbacks, void *user_data);
-
-/*!
- * \brief Get the threadpool listener's user data
- * \param listener The threadpool listener
- * \return The user data
- */
-void *ast_threadpool_listener_get_user_data(const struct ast_threadpool_listener *listener);
-
-/*!
- * \brief Create a new threadpool
- *
- * This function creates a threadpool. Tasks may be pushed onto this thread pool
- * and will be automatically acted upon by threads within the pool.
- *
- * Only a single threadpool with a given name may exist. This function will fail
- * if a threadpool with the given name already exists.
- *
- * \param name The unique name for the threadpool
- * \param listener The listener the threadpool will notify of changes. Can be NULL.
- * \param options The behavioral options for this threadpool
- * \retval NULL Failed to create the threadpool
- * \retval non-NULL The newly-created threadpool
- */
-struct ast_threadpool *ast_threadpool_create(const char *name,
-		struct ast_threadpool_listener *listener,
-		const struct ast_threadpool_options *options);
-
-/*!
- * \brief Set the number of threads for the thread pool
- *
- * This number may be more or less than the current number of
- * threads in the threadpool.
- *
- * \param threadpool The threadpool to adjust
- * \param size The new desired size of the threadpool
- */
-void ast_threadpool_set_size(struct ast_threadpool *threadpool, unsigned int size);
-
-/*!
- * \brief Push a task to the threadpool
- *
- * Tasks pushed into the threadpool will be automatically taken by
- * one of the threads within
- * \param pool The threadpool to add the task to
- * \param task The task to add
- * \param data The parameter for the task
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_threadpool_push(struct ast_threadpool *pool, int (*task)(void *data), void *data);
-
-/*!
- * \brief Shut down a threadpool and destroy it
- *
- * \param pool The pool to shut down
- */
-void ast_threadpool_shutdown(struct ast_threadpool *pool);
-
-/*!
- * \brief Serialized execution of tasks within a \ref ast_threadpool.
- *
- * \since 12.0.0
- *
- * A \ref ast_taskprocessor with the same contract as a default taskprocessor
- * (tasks execute serially) except instead of executing out of a dedicated
- * thread, execution occurs in a thread from a \ref ast_threadpool. Think of it
- * as a lightweight thread.
- *
- * While it guarantees that each task will complete before executing the next,
- * there is no guarantee as to which thread from the \c pool individual tasks
- * will execute. This normally only matters if your code relys on thread
- * specific information, such as thread locals.
- *
- * Use ast_taskprocessor_unreference() to dispose of the returned \ref
- * ast_taskprocessor.
- *
- * Only a single taskprocessor with a given name may exist. This function will fail
- * if a taskprocessor with the given name already exists.
- *
- * \param name Name of the serializer. (must be unique)
- * \param pool \ref ast_threadpool for execution.
- * \return \ref ast_taskprocessor for enqueuing work.
- * \return \c NULL on error.
- */
-struct ast_taskprocessor *ast_threadpool_serializer(const char *name, struct ast_threadpool *pool);
-
-#endif /* ASTERISK_THREADPOOL_H */
diff --git a/include/asterisk/threadstorage.h b/include/asterisk/threadstorage.h
index e3ece8b..4d8a80e 100644
--- a/include/asterisk/threadstorage.h
+++ b/include/asterisk/threadstorage.h
@@ -64,6 +64,9 @@ struct ast_threadstorage {
 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line);
 void __ast_threadstorage_object_remove(void *key);
 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len);
+#define THREADSTORAGE_RAW_CLEANUP(v) {}
+#else
+#define THREADSTORAGE_RAW_CLEANUP NULL
 #endif /* defined(DEBUG_THREADLOCALS) */
 
 /*!
@@ -84,6 +87,8 @@ void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len
 	AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr,) 
 #define AST_THREADSTORAGE_EXTERNAL(name) \
 	extern struct ast_threadstorage name
+#define AST_THREADSTORAGE_RAW(name) \
+	AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, THREADSTORAGE_RAW_CLEANUP,)
 
 /*!
  * \brief Define a thread storage variable, with custom initialization and cleanup
@@ -177,11 +182,10 @@ void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size),
 
 	pthread_once(&ts->once, ts->key_init);
 	if (!(buf = pthread_getspecific(ts->key))) {
-		if (!(buf = ast_calloc(1, init_size))) {
+		if (!(buf = ast_calloc(1, init_size)))
 			return NULL;
-		}
 		if (ts->custom_init && ts->custom_init(buf)) {
-			ast_free(buf);
+			free(buf);
 			return NULL;
 		}
 		pthread_setspecific(ts->key, buf);
@@ -198,11 +202,10 @@ void *__ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size, co
 
 	pthread_once(&ts->once, ts->key_init);
 	if (!(buf = pthread_getspecific(ts->key))) {
-		if (!(buf = ast_calloc(1, init_size))) {
+		if (!(buf = ast_calloc(1, init_size)))
 			return NULL;
-		}
 		if (ts->custom_init && ts->custom_init(buf)) {
-			ast_free(buf);
+			free(buf);
 			return NULL;
 		}
 		pthread_setspecific(ts->key, buf);
@@ -216,4 +219,42 @@ void *__ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size, co
 #define ast_threadstorage_get(ts, init_size) __ast_threadstorage_get(ts, init_size, __FILE__, __PRETTY_FUNCTION__, __LINE__)
 #endif /* defined(DEBUG_THREADLOCALS) */
 
+/*!
+ * \brief Retrieve a raw pointer from threadstorage.
+ * \param ts Threadstorage object to operate on.
+ *
+ * \return A pointer associated with the current thread, NULL
+ * if no pointer is associated yet.
+ *
+ * \note This should only be used on threadstorage declared
+ * by AST_THREADSTORAGE_RAW unless you really know what
+ * you are doing.
+ */
+AST_INLINE_API(
+void *ast_threadstorage_get_ptr(struct ast_threadstorage *ts),
+{
+	pthread_once(&ts->once, ts->key_init);
+	return pthread_getspecific(ts->key);
+}
+)
+
+/*!
+ * \brief Set a raw pointer from threadstorage.
+ * \param ts Threadstorage object to operate on.
+ *
+ * \retval 0 Success
+ * \retval non-zero Failure
+ *
+ * \note This should only be used on threadstorage declared
+ * by AST_THREADSTORAGE_RAW unless you really know what
+ * you are doing.
+ */
+AST_INLINE_API(
+int ast_threadstorage_set_ptr(struct ast_threadstorage *ts, void *ptr),
+{
+	pthread_once(&ts->once, ts->key_init);
+	return pthread_setspecific(ts->key, ptr);
+}
+)
+
 #endif /* ASTERISK_THREADSTORAGE_H */
diff --git a/include/asterisk/time.h b/include/asterisk/time.h
index f2382df..dd68db7 100644
--- a/include/asterisk/time.h
+++ b/include/asterisk/time.h
@@ -152,17 +152,6 @@ struct timeval ast_tvadd(struct timeval a, struct timeval b);
 struct timeval ast_tvsub(struct timeval a, struct timeval b);
 
 /*!
- * \since 12
- * \brief Formats a duration into HH:MM:SS
- *
- * \param duration The time (in seconds) to format
- * \param buf A buffer to hold the formatted string'
- * \param length The size of the buffer
- */
-void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length);
-
-
-/*!
  * \brief Calculate remaining milliseconds given a starting timestamp
  * and upper bound
  *
diff --git a/include/asterisk/timing.h b/include/asterisk/timing.h
index ff4947a..9cbb0eb 100644
--- a/include/asterisk/timing.h
+++ b/include/asterisk/timing.h
@@ -18,33 +18,33 @@
  */
 
 /*!
-	\file timing.h
-	\brief Timing source management
-	\author Kevin P. Fleming <kpfleming at digium.com>
-	\author Russell Bryant <russell at digium.com>
+  \file timing.h
+  \brief Timing source management
+  \author Kevin P. Fleming <kpfleming at digium.com>
+  \author Russell Bryant <russell at digium.com>
 
-	Portions of Asterisk require a timing source, a periodic trigger
-	for media handling activities. The functions in this file allow
-	a loadable module to provide a timing source for Asterisk and its
-	modules, so that those modules can request a 'timing handle' when
-	they require one. These handles are file descriptors, which can be
-	used with select() or poll().
+  Portions of Asterisk require a timing source, a periodic trigger
+  for media handling activities. The functions in this file allow
+  a loadable module to provide a timing source for Asterisk and its
+  modules, so that those modules can request a 'timing handle' when
+  they require one. These handles are file descriptors, which can be
+  used with select() or poll().
 
-	The timing source used by Asterisk must provide the following
-	features:
+  The timing source used by Asterisk must provide the following
+  features:
 
-	1) Periodic triggers, with a configurable interval (specified as
-		 number of triggers per second).
+  1) Periodic triggers, with a configurable interval (specified as
+     number of triggers per second).
 
-	2) Multiple outstanding triggers, each of which must be 'acked'
-		 to clear it. Triggers must also be 'ackable' in quantity.
+  2) Multiple outstanding triggers, each of which must be 'acked'
+     to clear it. Triggers must also be 'ackable' in quantity.
 
-	3) Continuous trigger mode, which when enabled causes every call
-		 to poll() on the timer handle to immediately return.
+  3) Continuous trigger mode, which when enabled causes every call
+     to poll() on the timer handle to immediately return.
 
-	4) Multiple 'event types', so that the code using the timer can
-		 know whether the wakeup it received was due to a periodic trigger
-		 or a continuous trigger.
+  4) Multiple 'event types', so that the code using the timer can
+     know whether the wakeup it received was due to a periodic trigger
+     or a continuous trigger.
  */
 
 #ifndef _ASTERISK_TIMING_H
@@ -71,15 +71,14 @@ struct ast_timing_interface {
 	/*! This handles the case where multiple timing modules are loaded.
 	 *  The highest priority timing interface available will be used. */
 	unsigned int priority;
-	void *(*timer_open)(void);
-	void (*timer_close)(void *data);
-	int (*timer_set_rate)(void *data, unsigned int rate);
-	int (*timer_ack)(void *data, unsigned int quantity);
-	int (*timer_enable_continuous)(void *data);
-	int (*timer_disable_continuous)(void *data);
-	enum ast_timer_event (*timer_get_event)(void *data);
-	unsigned int (*timer_get_max_rate)(void *data);
-	int (*timer_fd)(void *data);
+	int (*timer_open)(void);
+	void (*timer_close)(int handle);
+	int (*timer_set_rate)(int handle, unsigned int rate);
+	int (*timer_ack)(int handle, unsigned int quantity);
+	int (*timer_enable_continuous)(int handle);
+	int (*timer_disable_continuous)(int handle);
+	enum ast_timer_event (*timer_get_event)(int handle);
+	unsigned int (*timer_get_max_rate)(int handle);
 };
 
 /*!
@@ -94,7 +93,7 @@ struct ast_timing_interface {
  */
 #define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
 void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
-						 struct ast_module *mod);
+				     struct ast_module *mod);
 
 /*!
  * \brief Unregister a previously registered timing interface.
diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h
index e8e4c02..8545f0a 100644
--- a/include/asterisk/translate.h
+++ b/include/asterisk/translate.h
@@ -32,8 +32,6 @@ extern "C" {
 #include "asterisk/frame.h"
 #include "asterisk/plc.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/format_cache.h"
 #endif
 
 struct ast_trans_pvt;	/* declared below */
@@ -136,11 +134,8 @@ enum ast_trans_cost_table {
  */
 struct ast_translator {
 	char name[80];                         /*!< Name of translator */
-	struct ast_codec src_codec;		       /*!< Source codec */
-	struct ast_codec dst_codec;		   	   /*!< Destination codec */
-	struct ast_codec *core_src_codec;	   /*!< Core registered source codec */
-	struct ast_codec *core_dst_codec;      /*!< Core registered destination codec */
-	const char *format;					   /*!< Optional name of a cached format this translator produces */
+	struct ast_format src_format;          /*!< Source format */
+	struct ast_format dst_format;          /*!< Destination format */
 
 	int table_cost;                        /*!< Cost value associated with this translator based
 	                                        *   on translation cost table. */
@@ -209,6 +204,12 @@ struct ast_translator {
 struct ast_trans_pvt {
 	struct ast_translator *t;
 	struct ast_frame f;         /*!< used in frameout */
+	/*! If a translation path using a format with attributes requires the output
+	 * to be a specific set of attributes, this variable will be set describing those
+	 * attributes to the translator.  Otherwise, the translator must choose a set
+	 * of format attributes for the destination that preserves the quality of the
+	 * audio in the best way possible. */
+	struct ast_format explicit_dst;
 	int samples;                /*!< samples available in outbuf */
 	/*! \brief actual space used in outbuf */
 	int datalen;
@@ -235,7 +236,7 @@ struct ast_trans_pvt;
  * \brief Register a translator
  * This registers a codec translator with asterisk
  * \param t populated ast_translator structure
- * \param mod module handle to the module that owns this translator
+ * \param module handle to the module that owns this translator
  * \return 0 on success, -1 on failure
  */
 int __ast_register_translator(struct ast_translator *t, struct ast_module *module);
@@ -275,24 +276,24 @@ void ast_translator_deactivate(struct ast_translator *t);
  * Given a list of sources, and a designed destination format, which should
  * I choose?
  *
- * \param dst_cap destination capabilities
- * \param src_cap source capabilities
- * \param dst_fmt_out destination format chosen out of destination capabilities
- * \param src_fmt_out source format chosen out of source capabilities
+ * \param destination capabilities
+ * \param source capabilities
+ * \param destination format chosen out of destination capabilities
+ * \param source format chosen out of source capabilities
  * \return Returns 0 on success, -1 if no path could be found.
  *
  * \note dst_cap and src_cap are not mondified.
  */
 int ast_translator_best_choice(struct ast_format_cap *dst_cap,
 	struct ast_format_cap *src_cap,
-	struct ast_format **dst_fmt_out,
-	struct ast_format **src_fmt_out);
+	struct ast_format *dst_fmt_out,
+	struct ast_format *src_fmt_out);
 
 /*! 
  * \brief Builds a translator path
  * Build a path (possibly NULL) from source to dest 
- * \param dst dest destination format
- * \param src source source format
+ * \param dest destination format
+ * \param source source format
  * \return ast_trans_pvt on success, NULL on failure
  * */
 struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dest, struct ast_format *source);
@@ -308,7 +309,7 @@ void ast_translator_free_path(struct ast_trans_pvt *tr);
  * \brief translates one or more frames
  * Apply an input frame into the translator and receive zero or one output frames.  Consume
  * determines whether the original frame should be freed
- * \param path tr translator structure to use for translation
+ * \param tr translator structure to use for translation
  * \param f frame to translate
  * \param consume Whether or not to free the original frame
  * \return an ast_frame of the new translation format on success, NULL on failure
@@ -341,8 +342,8 @@ void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_for
 
 /*!
  * \brief Puts a string representation of the translation path into outbuf
- * \param t translator structure containing the translation path
- * \param str ast_str output buffer
+ * \param translator structure containing the translation path
+ * \param ast_str output buffer
  * \retval on success pointer to beginning of outbuf. on failure "".
  */
 const char *ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str);
diff --git a/include/asterisk/udptl.h b/include/asterisk/udptl.h
index 456a5ad..ae5c5a5 100644
--- a/include/asterisk/udptl.h
+++ b/include/asterisk/udptl.h
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * UDPTL support for T.38
  * 
@@ -44,6 +44,15 @@ enum ast_t38_ec_modes {
 extern "C" {
 #endif
 
+struct ast_udptl_protocol {
+	/*! \brief Get UDPTL struct, or NULL if unwilling to transfer */
+	struct ast_udptl *(*get_udptl_info)(struct ast_channel *chan);
+	/*! \brief Set UDPTL peer */
+	int (* const set_udptl_peer)(struct ast_channel *chan, struct ast_udptl *peer);
+	const char * const type;
+	AST_RWLIST_ENTRY(ast_udptl_protocol) list;
+};
+
 struct ast_udptl;
 
 typedef int (*ast_udptl_callback)(struct ast_udptl *udptl, struct ast_frame *f, void *data);
@@ -124,6 +133,13 @@ unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl);
 
 void ast_udptl_setnat(struct ast_udptl *udptl, int nat);
 
+int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
+		     struct ast_frame **fo, struct ast_channel **rc);
+
+int ast_udptl_proto_register(struct ast_udptl_protocol *proto);
+
+void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto);
+
 void ast_udptl_stop(struct ast_udptl *udptl);
 
 void ast_udptl_init(void);
diff --git a/include/asterisk/uri.h b/include/asterisk/uri.h
deleted file mode 100644
index f5f70a5..0000000
--- a/include/asterisk/uri.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_URI_H
-#define _ASTERISK_URI_H
-
-/*! \brief Opaque structure that stores uri information. */
-struct ast_uri;
-
-/*!
- * \brief Create a uri with the given parameters
- *
- * \param scheme the uri scheme (ex: http)
- * \param user_info user credentials (ex: <name>@<pass>)
- * \param host host name or ip address
- * \param port the port
- * \param path the path
- * \param query query parameters
- * \return a structure containing parsed uri data.
- * \return \c NULL on error
- * \since 13
- */
-struct ast_uri *ast_uri_create(const char *scheme, const char *user_info,
-			       const char *host, const char *port,
-			       const char *path, const char *query);
-
-/*!
- * \brief Copy the given uri replacing any value in the new uri with
- *        any given.
- *
- * \param uri the uri object to copy
- * \param scheme the uri scheme (ex: http)
- * \param user_info user credentials (ex: <name>@<pass>)
- * \param host host name or ip address
- * \param port the port
- * \param path the path
- * \param query query parameters
- * \return a copy of the given uri with specified values replaced.
- * \return \c NULL on error
- * \since 13
- */
-struct ast_uri *ast_uri_copy_replace(const struct ast_uri *uri, const char *scheme,
-				     const char *user_info, const char *host,
-				     const char *port, const char *path,
-				     const char *query);
-/*!
- * \brief Retrieve the uri scheme.
- *
- * \return the uri scheme.
- * \since 13
- */
-const char *ast_uri_scheme(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve the uri user information.
- *
- * \return the uri user information.
- * \since 13
- */
-const char *ast_uri_user_info(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve the uri host.
- *
- * \return the uri host.
- * \since 13
- */
-const char *ast_uri_host(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve the uri port
- *
- * \return the uri port.
- * \since 13
- */
-const char *ast_uri_port(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve the uri path.
- *
- * \return the uri path.
- * \since 13
- */
-const char *ast_uri_path(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve the uri query parameters.
- *
- * \return the uri query parameters.
- * \since 13
- */
-const char *ast_uri_query(const struct ast_uri *uri);
-
-/*!
- * \brief Retrieve if the uri is of a secure type
- *
- * \note Secure types are recognized by an 's' at the end
- *       of the scheme.
- *
- * \return True if secure, False otherwise.
- * \since 13
- */
-int attribute_pure ast_uri_is_secure(const struct ast_uri *uri);
-
-/*!
- * \brief Parse the given uri into a structure.
- *
- * \note Expects the following form:
- *           <scheme>://[user:pass@]<host>[:port][/<path>]
- *
- * \param uri a string uri to parse
- * \return a structure containing parsed uri data.
- * \return \c NULL on error
- * \since 13
- */
-struct ast_uri *ast_uri_parse(const char *uri);
-
-/*!
- * \brief Parse the given http uri into a structure.
- *
- * \note Expects the following form:
- *           [http[s]://][user:pass@]<host>[:port][/<path>]
- *
- * \note If no scheme is given it defaults to 'http' and if
- *       no port is specified it will default to 443 if marked
- *       secure, otherwise to 80.
- *
- * \param uri an http string uri to parse
- * \return a structure containing parsed http uri data.
- * \return \c NULL on error
- * \since 13
- */
-struct ast_uri *ast_uri_parse_http(const char *uri);
-
-/*!
- * \brief Parse the given websocket uri into a structure.
- *
- * \note Expects the following form:
- *           [ws[s]://][user:pass@]<host>[:port][/<path>]
- *
- * \note If no scheme is given it defaults to 'ws' and if
- *       no port is specified it will default to 443 if marked
- *       secure, otherwise to 80.
- *
- * \param uri a websocket string uri to parse
- * \return a structure containing parsed http uri data.
- * \return \c NULL on error
- * \since 13
- */
-struct ast_uri *ast_uri_parse_websocket(const char *uri);
-
-/*!
- * \brief Retrieve a string of the host and port.
- *
- * \detail Combine the host and port (<host>:<port>) if the port
- *         is available, otherwise just return the host.
- *
- * \note Caller is responsible for release the returned string.
- *
- * \param uri the uri object
- * \return a string value of the host and optional port.
- * \since 13
- */
-char *ast_uri_make_host_with_port(const struct ast_uri *uri);
-
-#endif /* _ASTERISK_URI_H */
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index a0e7cb6..bf17876 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -25,7 +25,6 @@
 
 #include "asterisk/network.h"
 
-#include <execinfo.h>
 #include <time.h>	/* we want to override localtime_r */
 #include <unistd.h>
 #include <string.h>
@@ -479,11 +478,6 @@ char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
 
 long int ast_random(void);
 
-/*!
- * \brief Returns a random number between 0.0 and 1.0, inclusive.
- * \since 12
- */
-#define ast_random_double() (((double)ast_random()) / RAND_MAX)
 
 #ifndef __AST_DEBUG_MALLOC
 #define ast_std_malloc malloc
@@ -500,26 +494,13 @@ long int ast_random(void);
 #define ast_free free
 #define ast_free_ptr ast_free
 
-/*
- * This buffer is in static memory. We never intend to read it,
- * nor do we care about multiple threads writing to it at the
- * same time. We only want to know if we're recursing too deep
- * already. 60 entries should be more than enough.  Function
- * call depth rarely exceeds 20 or so.
- */
-#define _AST_MEM_BACKTRACE_BUFLEN 60
-extern void *_ast_mem_backtrace_buffer[_AST_MEM_BACKTRACE_BUFLEN];
-
-/*
- * Ok, this sucks. But if we're already out of mem, we don't
- * want the logger to create infinite recursion (and a crash).
- */
+#if defined(AST_IN_CORE)
+#define MALLOC_FAILURE_MSG \
+	ast_log_safe(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file)
+#else
 #define MALLOC_FAILURE_MSG \
-	do { \
-		if (backtrace(_ast_mem_backtrace_buffer, _AST_MEM_BACKTRACE_BUFLEN) < _AST_MEM_BACKTRACE_BUFLEN) { \
-			ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file); \
-		} \
-	} while (0)
+	ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file)
+#endif
 
 /*!
  * \brief A wrapper for malloc()
@@ -537,9 +518,8 @@ void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, co
 {
 	void *p;
 
-	if (!(p = malloc(len))) {
+	if (!(p = malloc(len)))
 		MALLOC_FAILURE_MSG;
-	}
 
 	return p;
 }
@@ -561,9 +541,8 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in
 {
 	void *p;
 
-	if (!(p = calloc(num, len))) {
+	if (!(p = calloc(num, len)))
 		MALLOC_FAILURE_MSG;
-	}
 
 	return p;
 }
@@ -598,9 +577,8 @@ void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int
 {
 	void *newp;
 
-	if (!(newp = realloc(p, len))) {
+	if (!(newp = realloc(p, len)))
 		MALLOC_FAILURE_MSG;
-	}
 
 	return newp;
 }
@@ -627,9 +605,8 @@ char * attribute_malloc _ast_strdup(const char *str, const char *file, int linen
 	char *newstr = NULL;
 
 	if (str) {
-		if (!(newstr = strdup(str))) {
+		if (!(newstr = strdup(str)))
 			MALLOC_FAILURE_MSG;
-		}
 	}
 
 	return newstr;
@@ -657,9 +634,8 @@ char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *fi
 	char *newstr = NULL;
 
 	if (str) {
-		if (!(newstr = strndup(str, len))) {
+		if (!(newstr = strndup(str, len)))
 			MALLOC_FAILURE_MSG;
-		}
 	}
 
 	return newstr;
@@ -697,9 +673,8 @@ int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, c
 {
 	int res;
 
-	if ((res = vasprintf(ret, fmt, ap)) == -1) {
+	if ((res = vasprintf(ret, fmt, ap)) == -1)
 		MALLOC_FAILURE_MSG;
-	}
 
 	return res;
 }
@@ -760,39 +735,8 @@ void ast_enable_packet_fragmentation(int sock);
  */
 int ast_mkdir(const char *path, int mode);
 
-/*!
- * \brief Recursively create directory path, but only if it resolves within
- * the given \a base_path.
- *
- * If \a base_path does not exist, it will not be created and this function
- * returns \c EPERM.
- *
- * \param path The directory path to create
- * \param mode The permissions with which to try to create the directory
- * \return 0 on success or an error code otherwise
- */
-int ast_safe_mkdir(const char *base_path, const char *path, int mode);
-
 #define ARRAY_LEN(a) (size_t) (sizeof(a) / sizeof(0[a]))
 
-/*!
- * \brief Checks to see if value is within the given bounds
- *
- * \param v the value to check
- * \param min minimum lower bound (inclusive)
- * \param max maximum upper bound (inclusive)
- * \return 0 if value out of bounds, otherwise true (non-zero)
- */
-#define IN_BOUNDS(v, min, max) ((v) >= (min)) && ((v) <= (max))
-
-/*!
- * \brief Checks to see if value is within the bounds of the given array
- *
- * \param v the value to check
- * \param a the array to bound check
- * \return 0 if value out of bounds, otherwise true (non-zero)
- */
-#define ARRAY_IN_BOUNDS(v, a) IN_BOUNDS(v, 0, ARRAY_LEN(a) - 1)
 
 /* Definition for Digest authorization */
 struct ast_http_digest {
@@ -945,6 +889,7 @@ int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2);
 
 /*!
  * \brief Get current thread ID
+ * \param None
  * \return the ID if platform is supported, else -1
  */
 int ast_get_tid(void);
@@ -983,14 +928,12 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size);
  *     RAII_VAR(struct mything *, thing, mything_alloc(name), mything_cleanup);
  *     ...
  * }
- * \endcode
  *
  * \note This macro is especially useful for working with ao2 objects. A common idiom
  * would be a function that needed to look up an ao2 object and might have several error
  * conditions after the allocation that would normally need to unref the ao2 object.
  * With RAII_VAR, it is possible to just return and leave the cleanup to the destructor
  * function. For example:
- *
  * \code
  * void do_stuff(const char *name)
  * {
@@ -1003,51 +946,27 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size);
  *     }
  *     do_stuff_with_thing(thing);
  * }
- * \endcode
+ * \encode
  */
-#define RAII_VAR(vartype, varname, initval, dtor) \
-    /* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \
-    auto void _dtor_ ## varname (vartype * v); \
-    void _dtor_ ## varname (vartype * v) { dtor(*v); } \
-    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
 
-/*!
- * \brief Asterisk wrapper around crypt(3).
- *
- * The interpretation of the salt (which determines the password hashing
- * algorithm) is system specific. Application code should prefer to use
- * ast_crypt_encrypt() or ast_crypt_validate().
- *
- * The returned string is heap allocated, and should be freed with ast_free().
- *
- * \param key User's password to crypt.
- * \param salt Salt to crypt with.
- * \return Crypted password.
- * \return \c NULL on error.
- */
-char *ast_crypt(const char *key, const char *salt);
+#if defined(__clang__)
+typedef void (^_raii_cleanup_block_t)(void);
+static inline void _raii_cleanup_block(_raii_cleanup_block_t *b) { (*b)(); }
 
-/*
- * \brief Asterisk wrapper around crypt(3) for encrypting passwords.
- *
- * This function will generate a random salt and encrypt the given password.
- *
- * The returned string is heap allocated, and should be freed with ast_free().
- *
- * \param key User's password to crypt.
- * \return Crypted password.
- * \return \c NULL on error.
- */
-char *ast_crypt_encrypt(const char *key);
+#define RAII_VAR(vartype, varname, initval, dtor)                                                                \
+    _raii_cleanup_block_t _raii_cleanup_ ## varname __attribute__((cleanup(_raii_cleanup_block),unused)) = NULL; \
+    __block vartype varname = initval;                                                                           \
+    _raii_cleanup_ ## varname = ^{ {(void)dtor(varname);} }
 
-/*
- * \brief Asterisk wrapper around crypt(3) for validating passwords.
- *
- * \param key User's password to validate.
- * \param expected Expected result from crypt.
- * \return True (non-zero) if \a key matches \a expected.
- * \return False (zero) if \a key doesn't match.
- */
-int ast_crypt_validate(const char *key, const char *expected);
+#elif defined(__GNUC__)
+
+#define RAII_VAR(vartype, varname, initval, dtor)                              \
+    auto void _dtor_ ## varname (vartype * v);                                 \
+    void _dtor_ ## varname (vartype * v) { dtor(*v); }                         \
+    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
+
+#else
+    #error "Cannot compile Asterisk: unknown and unsupported compiler."
+#endif /* #if __GNUC__ */
 
 #endif /* _ASTERISK_UTILS_H */
diff --git a/include/asterisk/uuid.h b/include/asterisk/uuid.h
deleted file mode 100644
index 223ad18..0000000
--- a/include/asterisk/uuid.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012, Digium, Inc.
- *
- * Mark Michelson <mmmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Universally unique identifier support
- */
-
-#ifndef _ASTERISK_UUID_H
-#define _ASTERISK_UUID_H
-
-/* Size of an RFC 4122 UUID string plus terminating null byte */
-#define AST_UUID_STR_LEN (36 + 1)
-
-struct ast_uuid;
-
-/*!
- * \brief Initialize the UUID system
- */
-void ast_uuid_init(void);
-
-/*!
- * \brief Generate a UUID
- *
- * This function allocates memory on the heap. The returned
- * pointer must be freed using ast_free()
- *
- * \retval NULL Generation failed
- * \retval non-NULL heap-allocated UUID
- */
-struct ast_uuid *ast_uuid_generate(void);
-
-/*!
- * \brief Convert a UUID to a string
- *
- * \param uuid The UUID to convert to a string
- * \param[out] buf The buffer where the UUID string will be stored
- * \param size The size of the buffer. Must be at least AST_UUID_STR_LEN.
- * \return The UUID string (a pointer to buf)
- */
-char *ast_uuid_to_str(const struct ast_uuid *uuid, char *buf, size_t size);
-
-/*!
- * \brief Generate a UUID string.
- * \since 12.0.0
- *
- * \param buf The buffer where the UUID string will be stored
- * \param size The size of the buffer. Must be at least AST_UUID_STR_LEN.
- *
- * \return The UUID string (a pointer to buf)
- */
-char *ast_uuid_generate_str(char *buf, size_t size);
-
-/*!
- * \brief Convert a string to a UUID
- *
- * This function allocates memory on the heap. The returned
- * pointer must be freed using ast_free()
- *
- * \param str The string to convert to a UUID
- * \retval NULL Failed to convert
- * \retval non-NULL The heap-allocated converted UUID
- */
-struct ast_uuid *ast_str_to_uuid(const char *str);
-
-/*!
- * \brief Make a copy of a UUID
- *
- * This function allocates memory on the heap. The returned
- * pointer must be freed using ast_free()
- *
- * \param src The source UUID to copy
- * \retval NULL Failed to copy
- * \retval non-NULL The heap-allocated duplicate UUID
- */
-struct ast_uuid *ast_uuid_copy(const struct ast_uuid *src);
-
-/*!
- * \brief Compare two UUIDs
- *
- * \param left First UUID to compare
- * \param right Second UUID to compare
- * \retval <0 left is lexicographically less than right
- * \retval 0 left and right are the same
- * \retval >0 left is lexicographically greater than right
- */
-int ast_uuid_compare(const struct ast_uuid *left, const struct ast_uuid *right);
-
-/*!
- * \brief Clear a UUID by setting it to be a nil UUID (all 0s)
- *
- * \param uuid UUID to clear
- */
-void ast_uuid_clear(struct ast_uuid *uuid);
-
-/*!
- * \brief Check if a UUID is a nil UUID (all 0s)
- *
- * \param uuid UUID to check
- * \retval 0 The UUID is not nil
- * \retval non-zero The UUID is nil
- */
-int ast_uuid_is_nil(const struct ast_uuid *uuid);
-#endif
diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h
index 063e8c0..ddfcc25 100644
--- a/include/asterisk/xml.h
+++ b/include/asterisk/xml.h
@@ -23,7 +23,6 @@
 
 struct ast_xml_node;
 struct ast_xml_doc;
-struct ast_xml_xpath_results;
 
 /*!
  * \brief Initialize the XML library implementation.
@@ -208,44 +207,6 @@ struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node);
  * \brief Dump the specified document to a file. */
 int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc);
 
-/*!
- * \brief Free the XPath results
- * \param results The XPath results object to dispose of
- *
- * \since 12
- */
-void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results);
-
-/*!
- * \brief Return the number of results from an XPath query
- * \param results The XPath results object to count
- * \retval The number of results in the XPath object
- *
- * \since 12
- */
-int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results);
-
-/*!
- * \brief Return the first result node of an XPath query
- * \param results The XPath results object to get the first result from
- * \retval The first result in the XPath object on success
- * \retval NULL on error
- *
- * \since 12
- */
-struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results);
-
-/*!
- * \brief Execute an XPath query on an XML document
- * \param doc The XML document to query
- * \param xpath_str The XPath query string to execute on the document
- * \retval An object containing the results of the XPath query on success
- * \retval NULL on failure
- *
- * \since 12
- */
-struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char *xpath_str);
-
 /* Features using ast_xml_ */
 #ifdef HAVE_LIBXML2
 #define AST_XML_DOCS
diff --git a/include/asterisk/xmldoc.h b/include/asterisk/xmldoc.h
index 782fa1e..9bf6476 100644
--- a/include/asterisk/xmldoc.h
+++ b/include/asterisk/xmldoc.h
@@ -35,14 +35,6 @@ enum ast_doc_src {
 #ifdef AST_XML_DOCS
 
 struct ao2_container;
-struct ast_xml_node;
-
-/*!
- * \brief The struct to be used as the head of an ast_xml_doc_item list
- *        when being manipulated
- * \since 13.0.0
- */
-AST_LIST_HEAD(ast_xml_doc_item_list, ast_xml_doc_item);
 
 /*! \brief Struct that contains the XML documentation for a particular item.  Note
  * that this is an ao2 ref counted object.
@@ -69,27 +61,11 @@ struct ast_xml_doc_item {
 		AST_STRING_FIELD(name);
 		/*! The type of the item */
 		AST_STRING_FIELD(type);
-		/*! Reference to another field */
-		AST_STRING_FIELD(ref);
 	);
-	/*! The node that this item was created from. Note that the life time of
-	 * the node is not tied to the lifetime of this object.
-	 */
-	struct ast_xml_node *node;
 	/*! The next XML documentation item that matches the same name/item type */
-	AST_LIST_ENTRY(ast_xml_doc_item) next;
+	struct ast_xml_doc_item *next;
 };
 
-/*! \brief Execute an XPath query on the loaded XML documentation
- * \param query The XPath query string to execute
- * \param ... Variable printf style format arguments
- * \retval An XPath results object on success
- * \retval NULL if no match found
- *
- * \since 12
- */
-struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_query(const char *fmt, ...);
-
 /*!
  *  \brief Get the syntax for a specified application or function.
  *  \param type Application, Function or AGI ?
@@ -122,34 +98,6 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *m
 char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module);
 
 /*!
- * \brief Generate the [final response] tag based on type of node ('application',
- *        'function' or 'agi') and name.
- *
- * \param type 'application', 'function' or 'agi'
- * \param name Name of the application or function to build the 'responses' tag.
- * \param module The module the item is in (optional, can be NULL)
- *
- * \return An XMLDoc item list with the [final response] tag content.
- *
- * \since 13.0.0
- */
-struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module);
-
-/*!
- * \brief Generate the [list responses] tag based on type of node ('application',
- *        'function' or 'agi') and name.
- *
- * \param type 'application', 'function' or 'agi'
- * \param name Name of the application or function to build the 'responses' tag.
- * \param module The module the item is in (optional, can be NULL)
- *
- * \return An XMLDoc item list with the [list responses] tag content.
- *
- * \since 13.0.0
- */
-struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module);
-
-/*!
  *  \brief Colorize and put delimiters (instead of tags) to the xmldoc output.
  *  \param bwinput Not colorized input with tags.
  *  \param withcolors Result output with colors.
@@ -190,17 +138,6 @@ char *ast_xmldoc_build_description(const char *type, const char *name, const cha
  */
 struct ao2_container *ast_xmldoc_build_documentation(const char *type);
 
-/*!
- *  \brief Regenerate the documentation for a particular item
- *  \param item The documentation item to regenerate
- *
- *  \retval -1 on error
- *  \retval 0 on success
- *
- *  \since 12
- */
-int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item);
-
 #endif /* AST_XML_DOCS */
 
 #endif /* _ASTERISK_XMLDOC_H */
diff --git a/include/asterisk/xmpp.h b/include/asterisk/xmpp.h
index 294b4fd..ffaef72 100644
--- a/include/asterisk/xmpp.h
+++ b/include/asterisk/xmpp.h
@@ -19,7 +19,7 @@
 /*! \file
  * \brief XMPP Interface
  * \author Joshua Colp <jcolp at digium.com>
- * IKSEMEL http://iksemel.jabberstudio.org
+ * \extref IKSEMEL http://iksemel.jabberstudio.org
  */
 
 #ifndef _ASTERISK_XMPP_H
@@ -47,7 +47,6 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/pbx.h"
-#include "asterisk/stasis.h"
 
 /*
  * As per RFC 3920 - section 3.1, the maximum length for a full Jabber ID
@@ -106,8 +105,6 @@ struct ast_xmpp_message {
 	AST_LIST_ENTRY(ast_xmpp_message) list; /*!< Linked list information */
 };
 
-struct ast_endpoint;
-
 /*! \brief XMPP Buddy */
 struct ast_xmpp_buddy {
 	char id[XMPP_MAX_JIDLEN];        /*!< JID of the buddy */
@@ -118,11 +115,9 @@ struct ast_xmpp_buddy {
 /*! \brief XMPP Client Connection */
 struct ast_xmpp_client {
 	AST_DECLARE_STRING_FIELDS(
-		/*! Name of the client configuration */
-		AST_STRING_FIELD(name);
+		AST_STRING_FIELD(name); /*!< Name of the client configuration */
 		);
-	/*! Message ID */
-	char mid[6];
+	char mid[6]; /* Message ID */
 	iksid *jid;
 	iksparser *parser;
 	iksfilter *filter;
@@ -138,14 +133,9 @@ struct ast_xmpp_client {
 	AST_LIST_HEAD(, ast_xmpp_message) messages;
 	pthread_t thread;
 	int timeout;
-	/*! Reconnect this client */
-	unsigned int reconnect:1;
-	/*! If distributing event information the MWI subscription */
-	struct stasis_subscription *mwi_sub;
-	/*! If distributing event information the device state subscription */
-	struct stasis_subscription *device_state_sub;
-	/*! The endpoint associated with this client */
-	struct ast_endpoint *endpoint;
+	unsigned int reconnect:1; /*!< Reconnect this client */
+	struct ast_event_sub *mwi_sub; /*!< If distributing event information the MWI subscription */
+	struct ast_event_sub *device_state_sub; /*!< If distributing event information the device state subscription */
 };
 
 /*!
@@ -244,7 +234,7 @@ int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, con
  *
  * \param client Pointer to the client
  * \param nickname Nickname to use
- * \param address Address of the room
+ * \param Address Address of the room
  * \param message Message itself
  *
  * \retval 0 on success
diff --git a/main/.gitignore b/main/.gitignore
new file mode 100644
index 0000000..23f5c58
--- /dev/null
+++ b/main/.gitignore
@@ -0,0 +1,3 @@
+asterisk
+libasteriskssl.so.1
+version.c
diff --git a/main/Makefile b/main/Makefile
index 0fa2192..69b4202 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 #
 # Makefile to build main Asterisk binary
 #
@@ -33,13 +33,9 @@ OBJS+=stdtime/localtime.o
 ASTSSL_LIBS:=$(OPENSSL_LIB)
 AST_LIBS+=$(BKTR_LIB)
 AST_LIBS+=$(LIBXML2_LIB)
-AST_LIBS+=$(LIBXSLT_LIB)
 AST_LIBS+=$(SQLITE3_LIB)
 AST_LIBS+=$(ASTSSL_LIBS)
-AST_LIBS+=$(JANSSON_LIB)
-AST_LIBS+=$(URIPARSER_LIB)
-AST_LIBS+=$(UUID_LIB)
-AST_LIBS+=$(CRYPT_LIB)
+AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
@@ -59,8 +55,10 @@ endif
 
 ifneq ($(findstring darwin,$(OSARCH)),)
   AST_LIBS+=-lresolv
-  ASTLINK=-mmacosx-version-min=10.6 -Xlinker -undefined -Xlinker dynamic_lookup -force_flat_namespace
-  ASTLINK+=/usr/lib/bundle1.o
+  ASTLINK=-Xlinker -macosx_version_min -Xlinker 10.4 -Xlinker -undefined -Xlinker dynamic_lookup -force_flat_namespace
+  ifeq ($(shell if test `/usr/bin/sw_vers -productVersion | cut -c4` -gt 5; then echo 6; else echo 0; fi),6)
+    ASTLINK+=/usr/lib/bundle1.o
+  endif
 else
 # These are used for all but Darwin
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
@@ -155,10 +153,6 @@ endif
 db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE)
 asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
 cli.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
-json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE)
-bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)
-crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)
-uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE)
 
 ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
 http.o: _ASTCFLAGS+=$(GMIME_INCLUDE)
@@ -171,6 +165,13 @@ AST_EMBED_LDFLAGS:=$(foreach dep,$(EMBED_LDFLAGS),$(value $(dep)))
 AST_EMBED_LIBS:=$(foreach dep,$(EMBED_LIBS),$(value $(dep)))
 OBJS:=$(sort $(OBJS))
 
+ifneq ($(wildcard ../channels/h323/Makefile.ast),)
+  include ../channels/h323/Makefile.ast
+else
+  H323LDFLAGS=
+  H323LDLIBS=
+endif
+
 ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
 MAIN_TGT:=asterisk.dll
 asterisk: cygload
@@ -185,7 +186,7 @@ ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
 GMIMELDFLAGS+=$(GMIME_LIB)
 endif
 
-$(OBJS): _ASTCFLAGS+=-DAST_MODULE=\"core\"
+$(OBJS): _ASTCFLAGS+=-DAST_MODULE=\"core\" -DAST_IN_CORE
 
 libasteriskssl.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE)
 
@@ -247,7 +248,11 @@ tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE)
 $(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS)
 	@$(CC) -c -o buildinfo.o $(_ASTCFLAGS) buildinfo.c $(ASTCFLAGS)
 	$(ECHO_PREFIX) echo "   [LD] $(OBJS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) -> $@"
-	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB)
+ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
+	$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB)
+else
+	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB)
+endif
 
 ifeq ($(GNU_LD),1)
 $(MAIN_TGT): asterisk.exports
diff --git a/main/abstract_jb.c b/main/abstract_jb.c
index 6413465..2a606de 100644
--- a/main/abstract_jb.c
+++ b/main/abstract_jb.c
@@ -35,14 +35,12 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427021 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/term.h"
 #include "asterisk/utils.h"
-#include "asterisk/pbx.h"
-#include "asterisk/timing.h"
 
 #include "asterisk/abstract_jb.h"
 #include "fixedjitterbuf.h"
@@ -360,7 +358,7 @@ static void jb_get_and_deliver(struct ast_channel *chan)
 	}
 
 	while (now >= jb->next) {
-		interpolation_len = ast_format_get_default_ms(jb->last_format);
+		interpolation_len = ast_codec_interp_len(&jb->last_format);
 
 		res = jbimpl->get(jbobj, &f, now, interpolation_len);
 
@@ -371,13 +369,13 @@ static void jb_get_and_deliver(struct ast_channel *chan)
 		case AST_JB_IMPL_DROP:
 			jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
 				now, jb_get_actions[res], f->ts, f->len);
-			ao2_replace(jb->last_format, f->subclass.format);
+			ast_format_copy(&jb->last_format, &f->subclass.format);
 			ast_frfree(f);
 			break;
 		case AST_JB_IMPL_INTERP:
 			/* interpolate a frame */
 			f = &finterp;
-			f->subclass.format = jb->last_format;
+			ast_format_copy(&f->subclass.format, &jb->last_format);
 			f->samples  = interpolation_len * 8;
 			f->src  = "JB interpolation";
 			f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000));
@@ -409,6 +407,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
 	struct ast_jb_conf *jbconf = &jb->conf;
 	const struct ast_jb_impl *jbimpl = jb->impl;
 	void *jbobj;
+	struct ast_channel *bridged;
 	long now;
 	char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1];
 	char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp;
@@ -437,19 +436,18 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
 	jb->next = jbimpl->next(jbobj);
 
 	/* Init last format for a first time. */
-	jb->last_format = ao2_bump(frr->subclass.format);
+	ast_format_copy(&jb->last_format, &frr->subclass.format);
 
 	/* Create a frame log file */
 	if (ast_test_flag(jbconf, AST_JB_LOG)) {
-		RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup);
 		char safe_logfile[30] = "/tmp/logfile-XXXXXX";
 		int safe_fd;
-
 		snprintf(name2, sizeof(name2), "%s", ast_channel_name(chan));
 		while ((tmp = strchr(name2, '/'))) {
 			*tmp = '#';
 		}
 
+		bridged = ast_bridged_channel(chan);
 		/* We should always have bridged chan if a jitterbuffer is in use */
 		ast_assert(bridged != NULL);
 
@@ -502,8 +500,6 @@ void ast_jb_destroy(struct ast_channel *chan)
 		jb->logfile = NULL;
 	}
 
-	ao2_cleanup(jb->last_format);
-
 	if (ast_test_flag(jb, JB_CREATED)) {
 		/* Remove and free all frames still queued in jb */
 		while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
@@ -571,13 +567,6 @@ int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *
 	return 0;
 }
 
-void ast_jb_enable_for_channel(struct ast_channel *chan)
-{
-	struct ast_jb_conf conf = ast_channel_jb(chan)->conf;
-	if (ast_test_flag(&conf, AST_JB_ENABLED)) {
-		ast_jb_create_framehook(chan, &conf, 1);
-	}
-}
 
 void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
 {
@@ -811,318 +800,3 @@ const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type)
 	}
 	return NULL;
 }
-
-#define DEFAULT_TIMER_INTERVAL 20
-#define DEFAULT_SIZE  200
-#define DEFAULT_TARGET_EXTRA  40
-#define DEFAULT_RESYNC  1000
-#define DEFAULT_TYPE AST_JB_FIXED
-
-struct jb_framedata {
-	const struct ast_jb_impl *jb_impl;
-	struct ast_jb_conf jb_conf;
-	struct timeval start_tv;
-	struct ast_format *last_format;
-	struct ast_timer *timer;
-	int timer_interval; /* ms between deliveries */
-	int timer_fd;
-	int first;
-	void *jb_obj;
-};
-
-static void jb_framedata_destroy(struct jb_framedata *framedata)
-{
-	if (framedata->timer) {
-		ast_timer_close(framedata->timer);
-		framedata->timer = NULL;
-	}
-	if (framedata->jb_impl && framedata->jb_obj) {
-		struct ast_frame *f;
-		while (framedata->jb_impl->remove(framedata->jb_obj, &f) == AST_JB_IMPL_OK) {
-			ast_frfree(f);
-		}
-		framedata->jb_impl->destroy(framedata->jb_obj);
-		framedata->jb_obj = NULL;
-	}
-	ao2_cleanup(framedata->last_format);
-	ast_free(framedata);
-}
-
-void ast_jb_conf_default(struct ast_jb_conf *conf)
-{
-	conf->max_size = DEFAULT_SIZE;
-	conf->resync_threshold = DEFAULT_RESYNC;
-	ast_copy_string(conf->impl, "fixed", sizeof(conf->impl));
-	conf->target_extra = DEFAULT_TARGET_EXTRA;
-}
-
-static void datastore_destroy_cb(void *data) {
-	ast_free(data);
-	ast_debug(1, "JITTERBUFFER datastore destroyed\n");
-}
-
-static const struct ast_datastore_info jb_datastore = {
-	.type = "jitterbuffer",
-	.destroy = datastore_destroy_cb
-};
-
-static void hook_destroy_cb(void *framedata)
-{
-	ast_debug(1, "JITTERBUFFER hook destroyed\n");
-	jb_framedata_destroy((struct jb_framedata *) framedata);
-}
-
-static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
-{
-	struct jb_framedata *framedata = data;
-	struct timeval now_tv;
-	unsigned long now;
-	int putframe = 0; /* signifies if audio frame was placed into the buffer or not */
-
-	switch (event) {
-	case AST_FRAMEHOOK_EVENT_READ:
-		break;
-	case AST_FRAMEHOOK_EVENT_ATTACHED:
-	case AST_FRAMEHOOK_EVENT_DETACHED:
-	case AST_FRAMEHOOK_EVENT_WRITE:
-		return frame;
-	}
-
-	if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) {
-		if (ast_timer_ack(framedata->timer, 1) < 0) {
-			ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n");
-			return frame;
-		}
-	}
-
-	if (!frame) {
-		return frame;
-	}
-
-	now_tv = ast_tvnow();
-	now = ast_tvdiff_ms(now_tv, framedata->start_tv);
-
-	if (frame->frametype == AST_FRAME_VOICE) {
-		int res;
-		struct ast_frame *jbframe;
-
-		if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) {
-			/* only frames with timing info can enter the jitterbuffer */
-			return frame;
-		}
-
-		jbframe = ast_frisolate(frame);
-		ao2_replace(framedata->last_format, frame->subclass.format);
-
-		if (frame->len && (frame->len != framedata->timer_interval)) {
-			framedata->timer_interval = frame->len;
-			ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
-		}
-		if (!framedata->first) {
-			framedata->first = 1;
-			res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now);
-		} else {
-			res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
-		}
-
-		if (res == AST_JB_IMPL_OK) {
-			if (jbframe != frame) {
-				ast_frfree(frame);
-			}
-			frame = &ast_null_frame;
-		} else if (jbframe != frame) {
-			ast_frfree(jbframe);
-		}
-		putframe = 1;
-	}
-
-	if (frame->frametype == AST_FRAME_NULL) {
-		int res;
-		long next = framedata->jb_impl->next(framedata->jb_obj);
-
-		/* If now is earlier than the next expected output frame
-		 * from the jitterbuffer we may choose to pass on retrieving
-		 * a frame during this read iteration.  The only exception
-		 * to this rule is when an audio frame is placed into the buffer
-		 * and the time for the next frame to come out of the buffer is
-		 * at least within the timer_interval of the next output frame. By
-		 * doing this we are able to feed off the timing of the input frames
-		 * and only rely on our jitterbuffer timer when frames are dropped.
-		 * During testing, this hybrid form of timing gave more reliable results. */
-		if (now < next) {
-			long int diff = next - now;
-			if (!putframe) {
-				return frame;
-			} else if (diff >= framedata->timer_interval) {
-				return frame;
-			}
-		}
-
-		ast_frfree(frame);
-		frame = &ast_null_frame;
-		res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
-		switch (res) {
-		case AST_JB_IMPL_OK:
-			/* got it, and pass it through */
-			break;
-		case AST_JB_IMPL_DROP:
-			ast_frfree(frame);
-			frame = &ast_null_frame;
-			break;
-		case AST_JB_IMPL_INTERP:
-			if (framedata->last_format) {
-				struct ast_frame tmp = { 0, };
-
-				tmp.frametype = AST_FRAME_VOICE;
-				tmp.subclass.format = framedata->last_format;
-				/* example: 8000hz / (1000 / 20ms) = 160 samples */
-				tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval);
-				tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
-				tmp.offset = AST_FRIENDLY_OFFSET;
-				tmp.src  = "func_jitterbuffer interpolation";
-				ast_frfree(frame);
-				frame = ast_frdup(&tmp);
-				break;
-			}
-			/* else fall through */
-		case AST_JB_IMPL_NOFRAME:
-			ast_frfree(frame);
-			frame = &ast_null_frame;
-			break;
-		}
-	}
-
-	if (frame->frametype == AST_FRAME_CONTROL) {
-		switch(frame->subclass.integer) {
-		case AST_CONTROL_HOLD:
-		case AST_CONTROL_UNHOLD:
-		case AST_CONTROL_T38_PARAMETERS:
-		case AST_CONTROL_SRCUPDATE:
-		case AST_CONTROL_SRCCHANGE:
-			framedata->jb_impl->force_resync(framedata->jb_obj);
-			break;
-		default:
-			break;
-		}
-	}
-
-	return frame;
-}
-
-/* set defaults */
-static int jb_framedata_init(struct jb_framedata *framedata, struct ast_jb_conf *jb_conf)
-{
-	int jb_impl_type = DEFAULT_TYPE;
-	/* Initialize defaults */
-	framedata->timer_fd = -1;
-	memcpy(&framedata->jb_conf, jb_conf, sizeof(*jb_conf));
-
-	/* Figure out implementation type from the configuration implementation string */
-	if (!ast_strlen_zero(jb_conf->impl)) {
-		if (!strcasecmp(jb_conf->impl, "fixed")) {
-			jb_impl_type = AST_JB_FIXED;
-		} else if (!strcasecmp(jb_conf->impl, "adaptive")) {
-			jb_impl_type = AST_JB_ADAPTIVE;
-		} else {
-			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", jb_conf->impl);
-			return -1;
-		}
-	}
-
-	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
-		return -1;
-	}
-
-	if (!(framedata->timer = ast_timer_open())) {
-		return -1;
-	}
-
-	framedata->timer_fd = ast_timer_fd(framedata->timer);
-	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
-	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
-	framedata->start_tv = ast_tvnow();
-
-	framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
-	return 0;
-}
-
-
-void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing)
-{
-	struct jb_framedata *framedata;
-	struct ast_datastore *datastore = NULL;
-	struct ast_framehook_interface interface = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = hook_event_cb,
-		.destroy_cb = hook_destroy_cb,
-	};
-	int i = 0;
-
-	/* If disabled, strip any existing jitterbuffer and don't replace it. */
-	if (!strcasecmp(jb_conf->impl, "disabled")) {
-		int *id;
-		ast_channel_lock(chan);
-		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
-			id = datastore->data;
-			ast_framehook_detach(chan, *id);
-			ast_channel_datastore_remove(chan, datastore);
-			ast_datastore_free(datastore);
-		}
-		ast_channel_unlock(chan);
-		return;
-	}
-
-	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
-		return;
-	}
-
-	if (jb_framedata_init(framedata, jb_conf)) {
-		jb_framedata_destroy(framedata);
-		return;
-	}
-
-	interface.data = framedata;
-
-	ast_channel_lock(chan);
-	i = ast_framehook_attach(chan, &interface);
-	if (i >= 0) {
-		int *id;
-		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
-			/* There is already a jitterbuffer on the channel. */
-			if (prefer_existing) {
-				/* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */
-				ast_framehook_detach(chan, i);
-				ast_channel_unlock(chan);
-				return;
-			}
-			/* We prefer the new jitterbuffer, so strip the old one. */
-			id = datastore->data;
-			ast_framehook_detach(chan, *id);
-			ast_channel_datastore_remove(chan, datastore);
-			ast_datastore_free(datastore);
-		}
-
-		if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
-			ast_framehook_detach(chan, i);
-			ast_channel_unlock(chan);
-			return;
-		}
-
-		if (!(id = ast_calloc(1, sizeof(int)))) {
-			ast_datastore_free(datastore);
-			ast_framehook_detach(chan, i);
-			ast_channel_unlock(chan);
-			return;
-		}
-
-		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
-		datastore->data = id;
-		ast_channel_datastore_add(chan, datastore);
-
-		ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
-	} else {
-		jb_framedata_destroy(framedata);
-		framedata = NULL;
-	}
-	ast_channel_unlock(chan);
-}
diff --git a/main/acl.c b/main/acl.c
index c4c1d7a..65d0f1d 100644
--- a/main/acl.c
+++ b/main/acl.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428425 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/network.h"
 
@@ -349,6 +349,63 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original)
 
 /*!
  * \brief
+ * Isolate a 32-bit section of an IPv6 address
+ *
+ * An IPv6 address can be divided into 4 32-bit chunks. This gives
+ * easy access to one of these chunks.
+ *
+ * \param sin6 A pointer to a struct sockaddr_in6
+ * \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
+ */
+#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
+
+/*!
+ * \brief
+ * Apply a netmask to an address and store the result in a separate structure.
+ *
+ * When dealing with IPv6 addresses, one cannot apply a netmask with a simple
+ * logical and operation. Furthermore, the incoming address may be an IPv4 address
+ * and need to be mapped properly before attempting to apply a rule.
+ *
+ * \param addr The IP address to apply the mask to.
+ * \param netmask The netmask configured in the host access rule.
+ * \param result The resultant address after applying the netmask to the given address
+ * \retval 0 Successfully applied netmask
+ * \reval -1 Failed to apply netmask
+ */
+static int apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
+		struct ast_sockaddr *result)
+{
+	int res = 0;
+
+	if (ast_sockaddr_is_ipv4(addr)) {
+		struct sockaddr_in result4 = { 0, };
+		struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
+		struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
+		result4.sin_family = AF_INET;
+		result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
+		ast_sockaddr_from_sin(result, &result4);
+	} else if (ast_sockaddr_is_ipv6(addr)) {
+		struct sockaddr_in6 result6 = { 0, };
+		struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
+		struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
+		int i;
+		result6.sin6_family = AF_INET6;
+		for (i = 0; i < 4; ++i) {
+			V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
+		}
+		memcpy(&result->ss, &result6, sizeof(result6));
+		result->len = sizeof(result6);
+	} else {
+		/* Unsupported address scheme */
+		res = -1;
+	}
+
+	return res;
+}
+
+/*!
+ * \brief
  * Parse a netmask in CIDR notation
  *
  * \details
@@ -411,6 +468,8 @@ static int parse_cidr_mask(struct ast_sockaddr *addr, int is_v4, const char *mas
 	return 0;
 }
 
+
+
 void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
 {
 	struct ast_acl *acl = NULL;
@@ -634,7 +693,7 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
 			return ret;
 		}
 
-		if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
+		if (apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
 			/* This shouldn't happen because ast_sockaddr_parse would
 			 * have failed much earlier on an unsupported address scheme
 			 */
@@ -664,32 +723,6 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
 	return ret;
 }
 
-void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
-{
-	for (; ha; ha = ha->next) {
-		const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
-		ast_str_append(buf, 0, "%s%s/%s",
-			       ha->sense == AST_SENSE_ALLOW ? "!" : "",
-			       addr, ast_sockaddr_stringify_addr(&ha->netmask));
-		if (ha->next) {
-			ast_str_append(buf, 0, ",");
-		}
-	}
-}
-
-void ast_ha_join_cidr(const struct ast_ha *ha, struct ast_str **buf)
-{
-	for (; ha; ha = ha->next) {
-		const char *addr = ast_sockaddr_stringify_addr(&ha->addr);
-		ast_str_append(buf, 0, "%s%s/%d",
-			       ha->sense == AST_SENSE_ALLOW ? "!" : "",
-			       addr, ast_sockaddr_cidr_bits(&ha->netmask));
-		if (ha->next) {
-			ast_str_append(buf, 0, ",");
-		}
-	}
-}
-
 enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
 {
 	struct ast_acl *acl;
@@ -772,7 +805,7 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
 
 		/* For each rule, if this address and the netmask = the net address
 		   apply the current rule */
-		if (ast_sockaddr_apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
+		if (apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
 			/* Unlikely to happen since we know the address to be IPv4 or IPv6 */
 			continue;
 		}
diff --git a/main/alaw.c b/main/alaw.c
index 51ffe72..c5069f3 100644
--- a/main/alaw.c
+++ b/main/alaw.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/alaw.h"
 #include "asterisk/logger.h"
diff --git a/main/aoc.c b/main/aoc.c
index 413c741..a9e6d7b 100644
--- a/main/aoc.c
+++ b/main/aoc.c
@@ -28,7 +28,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416216 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/aoc.h"
 #include "asterisk/utils.h"
@@ -36,124 +36,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416216 $");
 #include "asterisk/_private.h"
 #include "asterisk/cli.h"
 #include "asterisk/manager.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_message_router.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="AOC-S">
-		<managerEventInstance class="EVENT_FLAG_AOC">
-			<synopsis>Raised when an Advice of Charge message is sent at the beginning of a call.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Chargeable" />
-				<parameter name="RateType">
-					<enumlist>
-						<enum name="NotAvailable" />
-						<enum name="Free" />
-						<enum name="FreeFromBeginning" />
-						<enum name="Duration" />
-						<enum name="Flag" />
-						<enum name="Volume" />
-						<enum name="SpecialCode" />
-					</enumlist>
-				</parameter>
-				<parameter name="Currency" />
-				<parameter name="Name" />
-				<parameter name="Cost" />
-				<parameter name="Multiplier">
-					<enumlist>
-						<enum name="1/1000" />
-						<enum name="1/100" />
-						<enum name="1/10" />
-						<enum name="1" />
-						<enum name="10" />
-						<enum name="100" />
-						<enum name="1000" />
-					</enumlist>
-				</parameter>
-				<parameter name="ChargingType" />
-				<parameter name="StepFunction" />
-				<parameter name="Granularity" />
-				<parameter name="Length" />
-				<parameter name="Scale" />
-				<parameter name="Unit">
-					<enumlist>
-						<enum name="Octect" />
-						<enum name="Segment" />
-						<enum name="Message" />
-					</enumlist>
-				</parameter>
-				<parameter name="SpecialCode" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AOC-D">
-		<managerEventInstance class="EVENT_FLAG_AOC">
-			<synopsis>Raised when an Advice of Charge message is sent during a call.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Charge" />
-				<parameter name="Type">
-					<enumlist>
-						<enum name="NotAvailable" />
-						<enum name="Free" />
-						<enum name="Currency" />
-						<enum name="Units" />
-					</enumlist>
-				</parameter>
-				<parameter name="BillingID">
-					<enumlist>
-						<enum name="Normal" />
-						<enum name="Reverse" />
-						<enum name="CreditCard" />
-						<enum name="CallForwardingUnconditional" />
-						<enum name="CallForwardingBusy" />
-						<enum name="CallForwardingNoReply" />
-						<enum name="CallDeflection" />
-						<enum name="CallTransfer" />
-						<enum name="NotAvailable" />
-					</enumlist>
-				</parameter>
-				<parameter name="TotalType">
-					<enumlist>
-						<enum name="SubTotal" />
-						<enum name="Total" />
-					</enumlist>
-				</parameter>
-				<parameter name="Currency" />
-				<parameter name="Name" />
-				<parameter name="Cost" />
-				<parameter name="Multiplier">
-					<enumlist>
-						<enum name="1/1000" />
-						<enum name="1/100" />
-						<enum name="1/10" />
-						<enum name="1" />
-						<enum name="10" />
-						<enum name="100" />
-						<enum name="1000" />
-					</enumlist>
-				</parameter>
-				<parameter name="Units" />
-				<parameter name="NumberOf" />
-				<parameter name="TypeOf" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AOC-E">
-		<managerEventInstance class="EVENT_FLAG_AOC">
-			<synopsis>Raised when an Advice of Charge message is sent at the end of a call.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="ChargingAssociation" />
-				<parameter name="Number" />
-				<parameter name="Plan" />
-				<parameter name="ID" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AOC-D']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-***/
 
 /* Encoded Payload Flags */
 #define AST_AOC_ENCODED_TYPE_REQUEST    (0 << 0)
@@ -1407,8 +1289,13 @@ static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned in
 		aoc_multiplier_str(mult));
 }
 
-static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
+static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
 {
+	if (chan) {
+		ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
+		ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
+	}
+
 	if (decoded->request_flag) {
 		ast_str_append(msg, 0, "AOCRequest:");
 		if (decoded->request_flag & AST_AOC_REQUEST_S) {
@@ -1427,12 +1314,17 @@ static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_
 	}
 }
 
-static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
+static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_channel *owner, struct ast_str **msg)
 {
 	const char *rate_str;
 	char prefix[32];
 	int idx;
 
+	if (owner) {
+		ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
+		ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
+	}
+
 	ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
 	for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
 		snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
@@ -1495,12 +1387,17 @@ static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **
 	}
 }
 
-static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
+static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
 {
 	const char *charge_str;
 	int idx;
 	char prefix[32];
 
+	if (chan) {
+		ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
+		ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
+	}
+
 	charge_str = aoc_charge_type_str(decoded->charge_type);
 	ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
 
@@ -1544,12 +1441,17 @@ static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **
 	}
 }
 
-static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
+static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
 {
 	const char *charge_str;
 	int idx;
 	char prefix[32];
 
+	if (chan) {
+		ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
+		ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
+	}
+
 	charge_str = "ChargingAssociation";
 
 	switch (decoded->charging_association.charging_type) {
@@ -1607,271 +1509,41 @@ static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **
 	}
 }
 
-static struct ast_json *units_to_json(const struct ast_aoc_decoded *decoded)
-{
-	int i;
-	struct ast_json *units = ast_json_array_create();
-
-	if (!units) {
-		return ast_json_null();
-	}
-
-	for (i = 0; i < decoded->unit_count; ++i) {
-		struct ast_json *unit = ast_json_object_create();
-
-		if (decoded->unit_list[i].valid_amount) {
-			ast_json_object_set(
-				unit, "NumberOf", ast_json_stringf(
-					"%u", decoded->unit_list[i].amount));
-			}
-
-		if (decoded->unit_list[i].valid_type) {
-			ast_json_object_set(
-				unit, "TypeOf", ast_json_stringf(
-					"%u", decoded->unit_list[i].type));
-		}
-
-		if (ast_json_array_append(units, unit)) {
-			break;
-		}
-	}
-
-	return units;
-}
-
-static struct ast_json *currency_to_json(const char *name, int cost,
-					 enum ast_aoc_currency_multiplier mult)
-{
-	return ast_json_pack("{s:s, s:i, s:s}",	"Name", name,
-			     "Cost", cost, "Multiplier", aoc_multiplier_str(mult));
-}
-
-static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded)
-{
-	RAII_VAR(struct ast_json *, obj, NULL, ast_json_unref);
-	const char *obj_type;
-
-	if (decoded->charge_type != AST_AOC_CHARGE_CURRENCY &&
-	    decoded->charge_type != AST_AOC_CHARGE_UNIT) {
-		return ast_json_pack("{s:s}", "Type",
-				     aoc_charge_type_str(decoded->charge_type));
-	}
-
-	if (decoded->charge_type == AST_AOC_CHARGE_CURRENCY) {
-		obj_type = "Currency";
-		obj = currency_to_json(decoded->currency_name, decoded->currency_amount,
-				       decoded->multiplier);
-	} else { /* decoded->charge_type == AST_AOC_CHARGE_UNIT */
-		obj_type = "Units";
-		obj = units_to_json(decoded);
-	}
-
-	return ast_json_pack(
-		"{s:s, s:s, s:s, s:O}",
-		"Type", aoc_charge_type_str(decoded->charge_type),
-		"BillingID", aoc_billingid_str(decoded->billing_id),
-		"TotalType", aoc_type_of_totaling_str(decoded->total_type),
-		obj_type, obj);
-}
-
-static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded)
-{
-	switch (decoded->charging_association.charging_type) {
-	case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
-		return ast_json_pack(
-			"{s:s, s:i}",
-			"Number", decoded->charging_association.charge.number.number,
-			"Plan", decoded->charging_association.charge.number.plan);
-	case AST_AOC_CHARGING_ASSOCIATION_ID:
-		return ast_json_pack(
-			"{s:i}", "ID", decoded->charging_association.charge.id);
-	case AST_AOC_CHARGING_ASSOCIATION_NA:
-	default:
-		return ast_json_null();
-	}
-}
-
-static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
-{
-	int i;
-	struct ast_json *rates = ast_json_array_create();
-
-	if (!rates) {
-		return ast_json_null();
-	}
-
-	for (i = 0; i < decoded->aoc_s_count; ++i) {
-		struct ast_json *rate = ast_json_object_create();
-		RAII_VAR(struct ast_json *, type, NULL, ast_json_unref);
-		RAII_VAR(struct ast_json *, currency, NULL, ast_json_unref);
-		const char *charge_item = aoc_charged_item_str(
-			decoded->aoc_s_entries[i].charged_item);
-
-		if (decoded->aoc_s_entries[i].charged_item == AST_AOC_CHARGED_ITEM_NA) {
-			rate = ast_json_pack("{s:s}", "Chargeable", charge_item);
-			if (ast_json_array_append(rates, rate)) {
-				break;
-			}
-			continue;
-		}
-
-		switch (decoded->aoc_s_entries[i].rate_type) {
-		case AST_AOC_RATE_TYPE_DURATION:
-		{
-			RAII_VAR(struct ast_json *, time, NULL, ast_json_unref);
-			RAII_VAR(struct ast_json *, granularity, NULL, ast_json_unref);
-
-			currency = currency_to_json(
-				decoded->aoc_s_entries[i].rate.duration.currency_name,
-				decoded->aoc_s_entries[i].rate.duration.amount,
-				decoded->aoc_s_entries[i].rate.duration.multiplier);
-
-			time = ast_json_pack(
-				"{s:i, s:s}",
-				"Length", decoded->aoc_s_entries[i].rate.duration.time,
-				"Scale", decoded->aoc_s_entries[i].rate.duration.time_scale);
-
-			if (decoded->aoc_s_entries[i].rate.duration.granularity_time) {
-				granularity = ast_json_pack(
-					"{s:i, s:s}",
-					"Length", decoded->aoc_s_entries[i].rate.duration.granularity_time,
-					"Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
-			}
-
-			type = ast_json_pack("{s:O, s:s, s:O, s:O}", "Currency", currency, "ChargingType",
-					     decoded->aoc_s_entries[i].rate.duration.charging_type ?
-					     "StepFunction" : "ContinuousCharging", "Time", time,
-					     "Granularity", granularity ? granularity : ast_json_null());
-
-			break;
-		}
-		case AST_AOC_RATE_TYPE_FLAT:
-			currency = currency_to_json(
-				decoded->aoc_s_entries[i].rate.flat.currency_name,
-				decoded->aoc_s_entries[i].rate.flat.amount,
-				decoded->aoc_s_entries[i].rate.flat.multiplier);
-
-			type = ast_json_pack("{s:O}", "Currency", currency);
-			break;
-		case AST_AOC_RATE_TYPE_VOLUME:
-			currency = currency_to_json(
-				decoded->aoc_s_entries[i].rate.volume.currency_name,
-				decoded->aoc_s_entries[i].rate.volume.amount,
-				decoded->aoc_s_entries[i].rate.volume.multiplier);
-
-			type = ast_json_pack(
-				"{s:s, s:O}", "Unit", aoc_volume_unit_str(
-					decoded->aoc_s_entries[i].rate.volume.volume_unit),
-				"Currency", currency);
-			break;
-		case AST_AOC_RATE_TYPE_SPECIAL_CODE:
-			type = ast_json_pack("{s:i}", "SpecialCode",
-					    decoded->aoc_s_entries[i].rate.special_code);
-			break;
-		default:
-			break;
-		}
-
-		rate = ast_json_pack("{s:s, s:O}", "Chargeable", charge_item,
-				     aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
-		if (ast_json_array_append(rates, rate)) {
-			break;
-		}
-	}
-	return rates;
-}
-
-static struct ast_json *d_to_json(const struct ast_aoc_decoded *decoded)
-{
-	return ast_json_pack("{s:o}", "Charge", charge_to_json(decoded));
-}
-
-static struct ast_json *e_to_json(const struct ast_aoc_decoded *decoded)
-{
-	return ast_json_pack("{s:o, s:o}",
-			     "ChargingAssociation", association_to_json(decoded),
-			     "Charge", charge_to_json(decoded));
-}
-
-static struct ast_manager_event_blob *aoc_to_ami(struct stasis_message *message,
-						 const char *event_name)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel, NULL, ast_free);
-	RAII_VAR(struct ast_str *, aoc, NULL, ast_free);
-
-	if (!(channel = ast_manager_build_channel_state_string(
-		      obj->snapshot))) {
-		return NULL;
-	}
-
-	if (!(aoc = ast_manager_str_from_json_object(obj->blob, NULL))) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AOC, event_name, "%s%s",
-					     AS_OR(channel, ""), ast_str_buffer(aoc));
-}
-
-static struct ast_manager_event_blob *aoc_s_to_ami(struct stasis_message *message)
-{
-	return aoc_to_ami(message, "AOC-S");
-}
-
-static struct ast_manager_event_blob *aoc_d_to_ami(struct stasis_message *message)
-{
-	return aoc_to_ami(message, "AOC-D");
-}
-
-static struct ast_manager_event_blob *aoc_e_to_ami(struct stasis_message *message)
-{
-	return aoc_to_ami(message, "AOC-E");
-}
-
-struct stasis_message_type *aoc_s_type(void);
-struct stasis_message_type *aoc_d_type(void);
-struct stasis_message_type *aoc_e_type(void);
-
-STASIS_MESSAGE_TYPE_DEFN(
-	aoc_s_type,
-	.to_ami = aoc_s_to_ami);
-
-STASIS_MESSAGE_TYPE_DEFN(
-	aoc_d_type,
-	.to_ami = aoc_d_to_ami);
-
-STASIS_MESSAGE_TYPE_DEFN(
-	aoc_e_type,
-	.to_ami = aoc_e_to_ami);
-
 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	struct stasis_message_type *msg_type;
+	struct ast_str *msg;
 
-	if (!decoded) {
+	if (!decoded || !(msg = ast_str_create(1024))) {
 		return -1;
 	}
 
 	switch (decoded->msg_type) {
 	case AST_AOC_S:
-		blob = s_to_json(decoded);
-		msg_type = aoc_s_type();
+		if (chan) {
+			aoc_s_event(decoded, chan, &msg);
+			ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-S", "%s", ast_str_buffer(msg));
+		}
 		break;
 	case AST_AOC_D:
-		blob = d_to_json(decoded);
-		msg_type = aoc_d_type();
+		if (chan) {
+			aoc_d_event(decoded, chan, &msg);
+			ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-D", "%s", ast_str_buffer(msg));
+		}
 		break;
 	case AST_AOC_E:
-		blob = e_to_json(decoded);
-		msg_type = aoc_e_type();
+		{
+			struct ast_channel *chans[1];
+			aoc_e_event(decoded, chan, &msg);
+			chans[0] = chan;
+			ast_manager_event_multichan(EVENT_FLAG_AOC, "AOC-E", chan ? 1 : 0, chans, "%s", ast_str_buffer(msg));
+		}
 		break;
 	default:
 		/* events for AST_AOC_REQUEST are not generated here */
-		return 0;
+		break;
 	}
 
-	ast_channel_publish_cached_blob(chan, msg_type, blob);
+	ast_free(msg);
 	return 0;
 }
 
@@ -1884,19 +1556,19 @@ int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **
 	switch (decoded->msg_type) {
 	case AST_AOC_S:
 		ast_str_append(msg, 0, "AOC-S\r\n");
-		aoc_s_event(decoded, msg);
+		aoc_s_event(decoded, NULL, msg);
 		break;
 	case AST_AOC_D:
 		ast_str_append(msg, 0, "AOC-D\r\n");
-		aoc_d_event(decoded, msg);
+		aoc_d_event(decoded, NULL, msg);
 		break;
 	case AST_AOC_E:
 		ast_str_append(msg, 0, "AOC-E\r\n");
-		aoc_e_event(decoded, msg);
+		aoc_e_event(decoded, NULL, msg);
 		break;
 	case AST_AOC_REQUEST:
 		ast_str_append(msg, 0, "AOC-Request\r\n");
-		aoc_request_event(decoded, msg);
+		aoc_request_event(decoded, NULL, msg);
 		break;
 	}
 
@@ -1935,18 +1607,10 @@ static struct ast_cli_entry aoc_cli[] = {
 
 static void aoc_shutdown(void)
 {
-	STASIS_MESSAGE_TYPE_CLEANUP(aoc_s_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(aoc_d_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(aoc_e_type);
-
 	ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
 }
 int ast_aoc_cli_init(void)
 {
-	STASIS_MESSAGE_TYPE_INIT(aoc_s_type);
-	STASIS_MESSAGE_TYPE_INIT(aoc_d_type);
-	STASIS_MESSAGE_TYPE_INIT(aoc_e_type);
-
-	ast_register_atexit(aoc_shutdown);
+	ast_register_cleanup(aoc_shutdown);
 	return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
 }
diff --git a/main/app.c b/main/app.c
index c69eeea..a31fa0c 100644
--- a/main/app.c
+++ b/main/app.c
@@ -23,19 +23,13 @@
  * \author Mark Spencer <markster at digium.com>
  */
 
-/** \example
- * \par This is an example of how to develop an app.
- * Application Skeleton is an example of creating an application for Asterisk.
- * \verbinclude app_skel.c
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427181 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -66,13 +60,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427181 $")
 #include "asterisk/threadstorage.h"
 #include "asterisk/test.h"
 #include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/json.h"
-#include "asterisk/format_cache.h"
-
-#define MWI_TOPIC_BUCKETS 57
 
 AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
 
@@ -85,60 +72,6 @@ struct zombie {
 
 static AST_LIST_HEAD_STATIC(zombies, zombie);
 
-/*
- * @{ \brief Define \ref stasis topic objects
- */
-static struct stasis_topic *mwi_topic_all;
-static struct stasis_cache *mwi_state_cache;
-static struct stasis_caching_topic *mwi_topic_cached;
-static struct stasis_topic_pool *mwi_topic_pool;
-
-static struct stasis_topic *queue_topic_all;
-static struct stasis_topic_pool *queue_topic_pool;
-/* @} */
-
-/*! \brief Convert a MWI \ref stasis_message to a \ref ast_event */
-static struct ast_event *mwi_to_event(struct stasis_message *message)
-{
-	struct ast_event *event;
-	struct ast_mwi_state *mwi_state;
-	char *mailbox;
-	char *context;
-
-	if (!message) {
-		return NULL;
-	}
-
-	mwi_state = stasis_message_data(message);
-
-	/* Strip off @context */
-	context = mailbox = ast_strdupa(mwi_state->uniqueid);
-	strsep(&context, "@");
-	if (ast_strlen_zero(context)) {
-		context = "default";
-	}
-
-	event = ast_event_new(AST_EVENT_MWI,
-				AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-				AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-				AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->new_msgs,
-				AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, mwi_state->old_msgs,
-				AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &mwi_state->eid, sizeof(mwi_state->eid),
-				AST_EVENT_IE_END);
-
-	return event;
-}
-
-/*
- * @{ \brief Define \ref stasis message types for MWI
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_mwi_state_type,
-	.to_event = mwi_to_event, );
-STASIS_MESSAGE_TYPE_DEFN(ast_mwi_vm_app_type);
-/* @} */
-
-
-
 static void *shaun_of_the_dead(void *data)
 {
 	struct zombie *cur;
@@ -459,132 +392,126 @@ int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *su
 	return res;
 }
 
-/*! \brief The container for the voicemail provider */
-static AO2_GLOBAL_OBJ_STATIC(vm_provider);
-
-/*! Voicemail not registered warning */
-static int vm_warnings;
-
-int ast_vm_is_registered(void)
-{
-	struct ast_vm_functions *table;
-	int is_registered;
-
-	table = ao2_global_obj_ref(vm_provider);
-	is_registered = table ? 1 : 0;
-	ao2_cleanup(table);
-	return is_registered;
-}
-
-int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module *module)
-{
-	RAII_VAR(struct ast_vm_functions *, table, NULL, ao2_cleanup);
-
-	if (!vm_table->module_name) {
-		ast_log(LOG_ERROR, "Voicemail provider missing required information.\n");
-		return -1;
-	}
-	if (vm_table->module_version != VM_MODULE_VERSION) {
-		ast_log(LOG_ERROR, "Voicemail provider '%s' has incorrect version\n",
-			vm_table->module_name);
-		return -1;
-	}
-
-	table = ao2_global_obj_ref(vm_provider);
-	if (table) {
-		ast_log(LOG_WARNING, "Voicemail provider already registered by %s.\n",
-			table->module_name);
-		return -1;
-	}
-
-	table = ao2_alloc_options(sizeof(*table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!table) {
-		return -1;
-	}
-	*table = *vm_table;
-	table->module = module;
-
-	ao2_global_obj_replace_unref(vm_provider, table);
-	return 0;
-}
-
-void ast_vm_unregister(const char *module_name)
-{
-	struct ast_vm_functions *table;
-
-	table = ao2_global_obj_ref(vm_provider);
-	if (table && !strcmp(table->module_name, module_name)) {
-		ao2_global_obj_release(vm_provider);
-	}
-	ao2_cleanup(table);
-}
-
-/*! \brief The container for the voicemail greeter provider */
-static AO2_GLOBAL_OBJ_STATIC(vm_greeter_provider);
-
-/*! Voicemail greeter not registered warning */
-static int vm_greeter_warnings;
-
-int ast_vm_greeter_is_registered(void)
-{
-	struct ast_vm_greeter_functions *table;
-	int is_registered;
-
-	table = ao2_global_obj_ref(vm_greeter_provider);
-	is_registered = table ? 1 : 0;
-	ao2_cleanup(table);
-	return is_registered;
-}
-
-int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module)
-{
-	RAII_VAR(struct ast_vm_greeter_functions *, table, NULL, ao2_cleanup);
-
-	if (!vm_table->module_name) {
-		ast_log(LOG_ERROR, "Voicemail greeter provider missing required information.\n");
-		return -1;
-	}
-	if (vm_table->module_version != VM_GREETER_MODULE_VERSION) {
-		ast_log(LOG_ERROR, "Voicemail greeter provider '%s' has incorrect version\n",
-			vm_table->module_name);
-		return -1;
-	}
-
-	table = ao2_global_obj_ref(vm_greeter_provider);
-	if (table) {
-		ast_log(LOG_WARNING, "Voicemail greeter provider already registered by %s.\n",
-			table->module_name);
-		return -1;
-	}
-
-	table = ao2_alloc_options(sizeof(*table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!table) {
-		return -1;
-	}
-	*table = *vm_table;
-	table->module = module;
-
-	ao2_global_obj_replace_unref(vm_greeter_provider, table);
-	return 0;
-}
-
-void ast_vm_greeter_unregister(const char *module_name)
-{
-	struct ast_vm_greeter_functions *table;
-
-	table = ao2_global_obj_ref(vm_greeter_provider);
-	if (table && !strcmp(table->module_name, module_name)) {
-		ao2_global_obj_release(vm_greeter_provider);
-	}
-	ao2_cleanup(table);
+static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
+static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
+static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL;
+static int (*ast_sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context) = NULL;
+static int (*ast_messagecount_func)(const char *context, const char *mailbox, const char *folder) = NULL;
+static int (*ast_copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data) = NULL;
+static const char *(*ast_vm_index_to_foldername_func)(int id) = NULL;
+static struct ast_vm_mailbox_snapshot *(*ast_vm_mailbox_snapshot_create_func)(const char *mailbox,
+	const char *context,
+	const char *folder,
+	int descending,
+	enum ast_vm_snapshot_sort_val sort_val,
+	int combine_INBOX_and_OLD) = NULL;
+static struct ast_vm_mailbox_snapshot *(*ast_vm_mailbox_snapshot_destroy_func)(struct ast_vm_mailbox_snapshot *mailbox_snapshot) = NULL;
+static int (*ast_vm_msg_move_func)(const char *mailbox,
+	const char *context,
+	size_t num_msgs,
+	const char *oldfolder,
+	const char *old_msg_ids[],
+	const char *newfolder) = NULL;
+static int (*ast_vm_msg_remove_func)(const char *mailbox,
+	const char *context,
+	size_t num_msgs,
+	const char *folder,
+	const char *msgs[]) = NULL;
+static int (*ast_vm_msg_forward_func)(const char *from_mailbox,
+	const char *from_context,
+	const char *from_folder,
+	const char *to_mailbox,
+	const char *to_context,
+	const char *to_folder,
+	size_t num_msgs,
+	const char *msg_ids[],
+	int delete_old) = NULL;
+static int (*ast_vm_msg_play_func)(struct ast_channel *chan,
+	const char *mailbox,
+	const char *context,
+	const char *folder,
+	const char *msg_num,
+	ast_vm_msg_play_cb cb) = NULL;
+
+void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
+			      int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
+			      int (*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs),
+			      int (*messagecount_func)(const char *context, const char *mailbox, const char *folder),
+			      int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context),
+			      int (*copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data),
+			      const char *vm_index_to_foldername_func(int id),
+			      struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_create_func)(const char *mailbox,
+				const char *context,
+				const char *folder,
+				int descending,
+				enum ast_vm_snapshot_sort_val sort_val,
+				int combine_INBOX_and_OLD),
+			      struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_destroy_func)(struct ast_vm_mailbox_snapshot *mailbox_snapshot),
+			      int (*vm_msg_move_func)(const char *mailbox,
+				const char *context,
+				size_t num_msgs,
+				const char *oldfolder,
+				const char *old_msg_ids[],
+				const char *newfolder),
+			      int (*vm_msg_remove_func)(const char *mailbox,
+				const char *context,
+				size_t num_msgs,
+				const char *folder,
+				const char *msgs[]),
+			      int (*vm_msg_forward_func)(const char *from_mailbox,
+				const char *from_context,
+				const char *from_folder,
+				const char *to_mailbox,
+				const char *to_context,
+				const char *to_folder,
+				size_t num_msgs,
+				const char *msg_ids[],
+				int delete_old),
+			      int (*vm_msg_play_func)(struct ast_channel *chan,
+				const char *mailbox,
+				const char *context,
+				const char *folder,
+				const char *msg_num,
+				ast_vm_msg_play_cb cb))
+{
+	ast_has_voicemail_func = has_voicemail_func;
+	ast_inboxcount_func = inboxcount_func;
+	ast_inboxcount2_func = inboxcount2_func;
+	ast_messagecount_func = messagecount_func;
+	ast_sayname_func = sayname_func;
+	ast_copy_recording_to_vm_func = copy_recording_to_vm_func;
+	ast_vm_index_to_foldername_func = vm_index_to_foldername_func;
+	ast_vm_mailbox_snapshot_create_func = vm_mailbox_snapshot_create_func;
+	ast_vm_mailbox_snapshot_destroy_func = vm_mailbox_snapshot_destroy_func;
+	ast_vm_msg_move_func = vm_msg_move_func;
+	ast_vm_msg_remove_func = vm_msg_remove_func;
+	ast_vm_msg_forward_func = vm_msg_forward_func;
+	ast_vm_msg_play_func = vm_msg_play_func;
+}
+
+void ast_uninstall_vm_functions(void)
+{
+	ast_has_voicemail_func = NULL;
+	ast_inboxcount_func = NULL;
+	ast_inboxcount2_func = NULL;
+	ast_messagecount_func = NULL;
+	ast_sayname_func = NULL;
+	ast_copy_recording_to_vm_func = NULL;
+	ast_vm_index_to_foldername_func = NULL;
+	ast_vm_mailbox_snapshot_create_func = NULL;
+	ast_vm_mailbox_snapshot_destroy_func = NULL;
+	ast_vm_msg_move_func = NULL;
+	ast_vm_msg_remove_func = NULL;
+	ast_vm_msg_forward_func = NULL;
+	ast_vm_msg_play_func = NULL;
 }
 
 #ifdef TEST_FRAMEWORK
-static ast_vm_test_create_user_fn *ast_vm_test_create_user_func = NULL;
-static ast_vm_test_destroy_user_fn *ast_vm_test_destroy_user_func = NULL;
+int (*ast_vm_test_create_user_func)(const char *context, const char *mailbox) = NULL;
+int (*ast_vm_test_destroy_user_func)(const char *context, const char *mailbox) = NULL;
 
-void ast_install_vm_test_functions(ast_vm_test_create_user_fn *vm_test_create_user_func,
-	ast_vm_test_destroy_user_fn *vm_test_destroy_user_func)
+void ast_install_vm_test_functions(int (*vm_test_create_user_func)(const char *context, const char *mailbox),
+				   int (*vm_test_destroy_user_func)(const char *context, const char *mailbox))
 {
 	ast_vm_test_create_user_func = vm_test_create_user_func;
 	ast_vm_test_destroy_user_func = vm_test_destroy_user_func;
@@ -597,54 +524,17 @@ void ast_uninstall_vm_test_functions(void)
 }
 #endif
 
-static void vm_warn_no_provider(void)
+int ast_app_has_voicemail(const char *mailbox, const char *folder)
 {
-	if (vm_warnings++ % 10 == 0) {
-		ast_verb(3, "No voicemail provider registered.\n");
+	static int warned = 0;
+	if (ast_has_voicemail_func) {
+		return ast_has_voicemail_func(mailbox, folder);
 	}
-}
-
-#define VM_API_CALL(res, api_call, api_parms)								\
-	do {																	\
-		struct ast_vm_functions *table;										\
-		table = ao2_global_obj_ref(vm_provider);							\
-		if (!table) {														\
-			vm_warn_no_provider();											\
-		} else if (table->api_call) {										\
-			ast_module_ref(table->module);									\
-			(res) = table->api_call api_parms;								\
-			ast_module_unref(table->module);								\
-		}																	\
-		ao2_cleanup(table);													\
-	} while (0)
 
-static void vm_greeter_warn_no_provider(void)
-{
-	if (vm_greeter_warnings++ % 10 == 0) {
-		ast_verb(3, "No voicemail greeter provider registered.\n");
+	if (warned++ % 10 == 0) {
+		ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
 	}
-}
-
-#define VM_GREETER_API_CALL(res, api_call, api_parms)						\
-	do {																	\
-		struct ast_vm_greeter_functions *table;								\
-		table = ao2_global_obj_ref(vm_greeter_provider);					\
-		if (!table) {														\
-			vm_greeter_warn_no_provider();									\
-		} else if (table->api_call) {										\
-			ast_module_ref(table->module);									\
-			(res) = table->api_call api_parms;								\
-			ast_module_unref(table->module);								\
-		}																	\
-		ao2_cleanup(table);													\
-	} while (0)
-
-int ast_app_has_voicemail(const char *mailboxes, const char *folder)
-{
-	int res = 0;
-
-	VM_API_CALL(res, has_voicemail, (mailboxes, folder));
-	return res;
+	return 0;
 }
 
 /*!
@@ -655,31 +545,44 @@ int ast_app_has_voicemail(const char *mailboxes, const char *folder)
  */
 int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data)
 {
-	int res = -1;
+	static int warned = 0;
 
-	VM_API_CALL(res, copy_recording_to_vm, (vm_rec_data));
-	return res;
+	if (ast_copy_recording_to_vm_func) {
+		return ast_copy_recording_to_vm_func(vm_rec_data);
+	}
+
+	if (warned++ % 10 == 0) {
+		ast_verb(3, "copy recording to voicemail called to copy %s.%s to %s@%s, but voicemail not loaded.\n",
+			vm_rec_data->recording_file, vm_rec_data->recording_ext,
+			vm_rec_data->mailbox, vm_rec_data->context);
+	}
+
+	return -1;
 }
 
-int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
+int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
 {
-	int res = 0;
-
+	static int warned = 0;
 	if (newmsgs) {
 		*newmsgs = 0;
 	}
 	if (oldmsgs) {
 		*oldmsgs = 0;
 	}
+	if (ast_inboxcount_func) {
+		return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
+	}
 
-	VM_API_CALL(res, inboxcount, (mailboxes, newmsgs, oldmsgs));
-	return res;
+	if (warned++ % 10 == 0) {
+		ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
+	}
+
+	return 0;
 }
 
-int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
+int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
 {
-	int res = 0;
-
+	static int warned = 0;
 	if (newmsgs) {
 		*newmsgs = 0;
 	}
@@ -689,33 +592,46 @@ int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, in
 	if (urgentmsgs) {
 		*urgentmsgs = 0;
 	}
+	if (ast_inboxcount2_func) {
+		return ast_inboxcount2_func(mailbox, urgentmsgs, newmsgs, oldmsgs);
+	}
 
-	VM_API_CALL(res, inboxcount2, (mailboxes, urgentmsgs, newmsgs, oldmsgs));
-	return res;
+	if (warned++ % 10 == 0) {
+		ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
+	}
+
+	return 0;
 }
 
-int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
+int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
 {
-	int res = -1;
-
-	VM_GREETER_API_CALL(res, sayname, (chan, mailbox_id));
-	return res;
+	if (ast_sayname_func) {
+		return ast_sayname_func(chan, mailbox, context);
+	}
+	return -1;
 }
 
-int ast_app_messagecount(const char *mailbox_id, const char *folder)
+int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
 {
-	int res = 0;
+	static int warned = 0;
+	if (ast_messagecount_func) {
+		return ast_messagecount_func(context, mailbox, folder);
+	}
 
-	VM_API_CALL(res, messagecount, (mailbox_id, folder));
-	return res;
+	if (!warned) {
+		warned++;
+		ast_verb(3, "Message count requested for mailbox %s@%s/%s but voicemail not loaded.\n", mailbox, context, folder);
+	}
+
+	return 0;
 }
 
 const char *ast_vm_index_to_foldername(int id)
 {
-	const char *res = NULL;
-
-	VM_API_CALL(res, index_to_foldername, (id));
-	return res;
+	if (ast_vm_index_to_foldername_func) {
+		return ast_vm_index_to_foldername_func(id);
+	}
+	return NULL;
 }
 
 struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailbox,
@@ -725,19 +641,18 @@ struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailb
 	enum ast_vm_snapshot_sort_val sort_val,
 	int combine_INBOX_and_OLD)
 {
-	struct ast_vm_mailbox_snapshot *res = NULL;
-
-	VM_API_CALL(res, mailbox_snapshot_create, (mailbox, context, folder, descending,
-		sort_val, combine_INBOX_and_OLD));
-	return res;
+	if (ast_vm_mailbox_snapshot_create_func) {
+		return ast_vm_mailbox_snapshot_create_func(mailbox, context, folder, descending, sort_val, combine_INBOX_and_OLD);
+	}
+	return NULL;
 }
 
 struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
 {
-	struct ast_vm_mailbox_snapshot *res = NULL;
-
-	VM_API_CALL(res, mailbox_snapshot_destroy, (mailbox_snapshot));
-	return res;
+	if (ast_vm_mailbox_snapshot_destroy_func) {
+		return ast_vm_mailbox_snapshot_destroy_func(mailbox_snapshot);
+	}
+	return NULL;
 }
 
 int ast_vm_msg_move(const char *mailbox,
@@ -747,11 +662,10 @@ int ast_vm_msg_move(const char *mailbox,
 	const char *old_msg_ids[],
 	const char *newfolder)
 {
-	int res = 0;
-
-	VM_API_CALL(res, msg_move, (mailbox, context, num_msgs, oldfolder, old_msg_ids,
-		newfolder));
-	return res;
+	if (ast_vm_msg_move_func) {
+		return ast_vm_msg_move_func(mailbox, context, num_msgs, oldfolder, old_msg_ids, newfolder);
+	}
+	return 0;
 }
 
 int ast_vm_msg_remove(const char *mailbox,
@@ -760,10 +674,10 @@ int ast_vm_msg_remove(const char *mailbox,
 	const char *folder,
 	const char *msgs[])
 {
-	int res = 0;
-
-	VM_API_CALL(res, msg_remove, (mailbox, context, num_msgs, folder, msgs));
-	return res;
+	if (ast_vm_msg_remove_func) {
+		return ast_vm_msg_remove_func(mailbox, context, num_msgs, folder, msgs);
+	}
+	return 0;
 }
 
 int ast_vm_msg_forward(const char *from_mailbox,
@@ -776,11 +690,10 @@ int ast_vm_msg_forward(const char *from_mailbox,
 	const char *msg_ids[],
 	int delete_old)
 {
-	int res = 0;
-
-	VM_API_CALL(res, msg_forward, (from_mailbox, from_context, from_folder, to_mailbox,
-		to_context, to_folder, num_msgs, msg_ids, delete_old));
-	return res;
+	if (ast_vm_msg_forward_func) {
+		return ast_vm_msg_forward_func(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, num_msgs, msg_ids, delete_old);
+	}
+	return 0;
 }
 
 int ast_vm_msg_play(struct ast_channel *chan,
@@ -788,12 +701,12 @@ int ast_vm_msg_play(struct ast_channel *chan,
 	const char *context,
 	const char *folder,
 	const char *msg_num,
-	ast_vm_msg_play_cb *cb)
+	ast_vm_msg_play_cb cb)
 {
-	int res = 0;
-
-	VM_API_CALL(res, msg_play, (chan, mailbox, context, folder, msg_num, cb));
-	return res;
+	if (ast_vm_msg_play_func) {
+		return ast_vm_msg_play_func(chan, mailbox, context, folder, msg_num, cb);
+	}
+	return 0;
 }
 
 #ifdef TEST_FRAMEWORK
@@ -817,25 +730,32 @@ int ast_vm_test_destroy_user(const char *context, const char *mailbox)
 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
 {
 	const char *ptr;
-	int res;
+	int res = 0;
 	struct ast_silence_generator *silgen = NULL;
 
 	if (!between) {
 		between = 100;
 	}
 
-	if (peer && ast_autoservice_start(peer)) {
-		return -1;
+	if (peer) {
+		res = ast_autoservice_start(peer);
+	}
+
+	if (!res) {
+		res = ast_waitfor(chan, 100);
+	}
+
+	/* ast_waitfor will return the number of remaining ms on success */
+	if (res < 0) {
+		if (peer) {
+			ast_autoservice_stop(peer);
+		}
+		return res;
 	}
 
-	/* Need a quiet time before sending digits. */
 	if (ast_opt_transmit_silence) {
 		silgen = ast_channel_start_silence_generator(chan);
 	}
-	res = ast_safe_sleep(chan, 100);
-	if (res) {
-		goto dtmf_stream_cleanup;
-	}
 
 	for (ptr = digits; *ptr; ptr++) {
 		if (*ptr == 'w') {
@@ -843,17 +763,12 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
 			if ((res = ast_safe_sleep(chan, 500))) {
 				break;
 			}
-		} else if (*ptr == 'W') {
-			/* 'W' -- wait a second */
-			if ((res = ast_safe_sleep(chan, 1000))) {
-				break;
-			}
 		} else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
+			/* Character represents valid DTMF */
 			if (*ptr == 'f' || *ptr == 'F') {
 				/* ignore return values if not supported by channel */
 				ast_indicate(chan, AST_CONTROL_FLASH);
 			} else {
-				/* Character represents valid DTMF */
 				ast_senddigit(chan, *ptr, duration);
 			}
 			/* pause between digits */
@@ -865,13 +780,17 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
 		}
 	}
 
-dtmf_stream_cleanup:
+	if (peer) {
+		/* Stop autoservice on the peer channel, but don't overwrite any error condition
+		   that has occurred previously while acting on the primary channel */
+		if (ast_autoservice_stop(peer) && !res) {
+			res = -1;
+		}
+	}
+
 	if (silgen) {
 		ast_channel_stop_silence_generator(chan, silgen);
 	}
-	if (peer && ast_autoservice_stop(peer)) {
-		res = -1;
-	}
 
 	return res;
 }
@@ -880,18 +799,16 @@ struct linear_state {
 	int fd;
 	int autoclose;
 	int allowoverride;
-	struct ast_format *origwfmt;
+	struct ast_format origwfmt;
 };
 
 static void linear_release(struct ast_channel *chan, void *params)
 {
 	struct linear_state *ls = params;
 
-	if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
-		ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n",
-			ast_channel_name(chan), ast_format_get_name(ls->origwfmt));
+	if (ls->origwfmt.id && ast_set_write_format(chan, &ls->origwfmt)) {
+		ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%u'\n", ast_channel_name(chan), ls->origwfmt.id);
 	}
-	ao2_cleanup(ls->origwfmt);
 
 	if (ls->autoclose) {
 		close(ls->fd);
@@ -911,7 +828,7 @@ static int linear_generator(struct ast_channel *chan, void *data, int len, int s
 	};
 	int res;
 
-	f.subclass.format = ast_format_slin;
+	ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	len = samples * 2;
 	if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
@@ -945,11 +862,10 @@ static void *linear_alloc(struct ast_channel *chan, void *params)
 		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
 	}
 
-	ls->origwfmt = ao2_bump(ast_channel_writeformat(chan));
+	ast_format_copy(&ls->origwfmt, ast_channel_writeformat(chan));
 
-	if (ast_set_write_format(chan, ast_format_slin)) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", ast_channel_name(chan));
-		ao2_cleanup(ls->origwfmt);
 		ast_free(ls);
 		ls = params = NULL;
 	}
@@ -1003,7 +919,6 @@ static int control_streamfile(struct ast_channel *chan,
 	const char *restart,
 	int skipms,
 	long *offsetms,
-	const char *lang,
 	ast_waitstream_fr_cb cb)
 {
 	char *breaks = NULL;
@@ -1019,9 +934,6 @@ static int control_streamfile(struct ast_channel *chan,
 	if (offsetms) {
 		offset = *offsetms * 8; /* XXX Assumes 8kHz */
 	}
-	if (lang == NULL) {
-		lang = ast_channel_language(chan);
-	}
 
 	if (stop) {
 		blen += strlen(stop);
@@ -1046,6 +958,9 @@ static int control_streamfile(struct ast_channel *chan,
 			strcat(breaks, restart);
 		}
 	}
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		res = ast_answer(chan);
+	}
 
 	if ((end = strchr(file, ':'))) {
 		if (!strcasecmp(end, ":end")) {
@@ -1056,7 +971,7 @@ static int control_streamfile(struct ast_channel *chan,
 
 	for (;;) {
 		ast_stopstream(chan);
-		res = ast_streamfile(chan, file, lang);
+		res = ast_streamfile(chan, file, ast_channel_language(chan));
 		if (!res) {
 			if (pause_restart_point) {
 				ast_seekstream(ast_channel_stream(chan), pause_restart_point, SEEK_SET);
@@ -1088,37 +1003,24 @@ static int control_streamfile(struct ast_channel *chan,
 		}
 
 		/* We go at next loop if we got the restart char */
-		if ((restart && strchr(restart, res)) || res == AST_CONTROL_STREAM_RESTART) {
+		if (restart && strchr(restart, res)) {
 			ast_debug(1, "we'll restart the stream here at next loop\n");
 			pause_restart_point = 0;
-			ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-				"Control: %s\r\n",
-				ast_channel_name(chan),
-				"Restart");
 			continue;
 		}
 
-		if ((suspend && strchr(suspend, res)) || res == AST_CONTROL_STREAM_SUSPEND) {
+		if (suspend && strchr(suspend, res)) {
 			pause_restart_point = ast_tellstream(ast_channel_stream(chan));
-			ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-				"Control: %s\r\n",
-				ast_channel_name(chan),
-				"Pause");
 			for (;;) {
 				ast_stopstream(chan);
 				if (!(res = ast_waitfordigit(chan, 1000))) {
 					continue;
-				} else if (res == -1 || (suspend && strchr(suspend, res)) || (stop && strchr(stop, res))
-						|| res == AST_CONTROL_STREAM_SUSPEND || res == AST_CONTROL_STREAM_STOP) {
+				} else if (res == -1 || strchr(suspend, res) || (stop && strchr(stop, res))) {
 					break;
 				}
 			}
-			if ((suspend && (res == *suspend)) || res == AST_CONTROL_STREAM_SUSPEND) {
+			if (res == *suspend) {
 				res = 0;
-				ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-					"Control: %s\r\n",
-					ast_channel_name(chan),
-					"Unpause");
 				continue;
 			}
 		}
@@ -1128,11 +1030,7 @@ static int control_streamfile(struct ast_channel *chan,
 		}
 
 		/* if we get one of our stop chars, return it to the calling function */
-		if ((stop && strchr(stop, res)) || res == AST_CONTROL_STREAM_STOP) {
-			ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-				"Control: %s\r\n",
-				ast_channel_name(chan),
-				"Stop");
+		if (stop && strchr(stop, res)) {
 			break;
 		}
 	}
@@ -1151,6 +1049,11 @@ static int control_streamfile(struct ast_channel *chan,
 		*offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
 	}
 
+	/* If we are returning a digit cast it as char */
+	if (res > 0 || ast_channel_stream(chan)) {
+		res = (char)res;
+	}
+
 	ast_stopstream(chan);
 
 	return res;
@@ -1167,7 +1070,7 @@ int ast_control_streamfile_w_cb(struct ast_channel *chan,
 	long *offsetms,
 	ast_waitstream_fr_cb cb)
 {
-	return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL, cb);
+	return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, cb);
 }
 
 int ast_control_streamfile(struct ast_channel *chan, const char *file,
@@ -1175,150 +1078,7 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
 			   const char *stop, const char *suspend,
 			   const char *restart, int skipms, long *offsetms)
 {
-	return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL, NULL);
-}
-
-int ast_control_streamfile_lang(struct ast_channel *chan, const char *file,
-	const char *fwd, const char *rev, const char *stop, const char *suspend,
-	const char *restart, int skipms, const char *lang, long *offsetms)
-{
-	return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, lang, NULL);
-}
-
-enum control_tone_frame_response_result {
-	CONTROL_TONE_RESPONSE_FAILED = -1,
-	CONTROL_TONE_RESPONSE_NORMAL = 0,
-	CONTROL_TONE_RESPONSE_FINISHED = 1,
-};
-
-static enum control_tone_frame_response_result control_tone_frame_response(struct ast_channel *chan, struct ast_frame *fr, struct ast_tone_zone_sound *ts, const char *tone, int *paused)
-{
-	switch (fr->subclass.integer) {
-	case AST_CONTROL_STREAM_STOP:
-		ast_playtones_stop(chan);
-		return CONTROL_TONE_RESPONSE_FINISHED;
-	case AST_CONTROL_STREAM_SUSPEND:
-		if (*paused) {
-			*paused = 0;
-			if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) {
-				return CONTROL_TONE_RESPONSE_FAILED;
-			}
-		} else {
-			*paused = 1;
-			ast_playtones_stop(chan);
-		}
-		return CONTROL_TONE_RESPONSE_NORMAL;
-	case AST_CONTROL_STREAM_RESTART:
-		ast_playtones_stop(chan);
-		if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) {
-			return CONTROL_TONE_RESPONSE_FAILED;
-		}
-		return CONTROL_TONE_RESPONSE_NORMAL;
-	case AST_CONTROL_STREAM_REVERSE:
-		ast_log(LOG_NOTICE, "Media control operation 'reverse' not supported for media type 'tone'\n");
-		return CONTROL_TONE_RESPONSE_NORMAL;
-	case AST_CONTROL_STREAM_FORWARD:
-		ast_log(LOG_NOTICE, "Media control operation 'forward' not supported for media type 'tone'\n");
-		return CONTROL_TONE_RESPONSE_NORMAL;
-	case AST_CONTROL_HANGUP:
-	case AST_CONTROL_BUSY:
-	case AST_CONTROL_CONGESTION:
-		return CONTROL_TONE_RESPONSE_FINISHED;
-	}
-
-	return CONTROL_TONE_RESPONSE_NORMAL;
-}
-
-static int parse_tone_uri(char *tone_parser,
-	const char **tone_indication,
-	const char **tone_zone)
-{
-	*tone_indication = strsep(&tone_parser, ";");
-
-	if (ast_strlen_zero(tone_parser)) {
-		/* Only the indication is included */
-		return 0;
-	}
-
-	if (!(strncmp(tone_parser, "tonezone=", 9))) {
-		*tone_zone = tone_parser + 9;
-	} else {
-		ast_log(LOG_ERROR, "Unexpected Tone URI component: %s\n", tone_parser);
-		return -1;
-	}
-
-	return 0;
-}
-
-int ast_control_tone(struct ast_channel *chan, const char *tone)
-{
-	struct ast_tone_zone *zone = NULL;
-	struct ast_tone_zone_sound *ts;
-	int paused = 0;
-	int res = 0;
-
-	const char *tone_indication = NULL;
-	const char *tone_zone = NULL;
-	char *tone_uri_parser;
-
-	if (ast_strlen_zero(tone)) {
-		return -1;
-	}
-
-	tone_uri_parser = ast_strdupa(tone);
-
-	if (parse_tone_uri(tone_uri_parser, &tone_indication, &tone_zone)) {
-		return -1;
-	}
-
-	if (tone_zone) {
-		zone = ast_get_indication_zone(tone_zone);
-	}
-
-	ts = ast_get_indication_tone(zone ? zone : ast_channel_zone(chan), tone_indication);
-
-	if (ast_playtones_start(chan, 0, ts ? ts->data : tone_indication, 0)) {
-		return -1;
-	}
-
-	for (;;) {
-		struct ast_frame *fr;
-
-		if (ast_waitfor(chan, -1) < 0) {
-			res = -1;
-			break;
-		}
-
-		fr = ast_read_noaudio(chan);
-
-		if (!fr) {
-			res = -1;
-			break;
-		}
-
-		if (fr->frametype != AST_FRAME_CONTROL) {
-			continue;
-		}
-
-		res = control_tone_frame_response(chan, fr, ts, tone_indication, &paused);
-		if (res == CONTROL_TONE_RESPONSE_FINISHED) {
-			res = 0;
-			break;
-		} else if (res == CONTROL_TONE_RESPONSE_FAILED) {
-			res = -1;
-			break;
-		}
-	}
-
-	if (ts) {
-		ast_tone_zone_sound_unref(ts);
-	}
-
-	if (zone) {
-		ast_tone_zone_unref(zone);
-	}
-
-	return res;
+	return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL);
 }
 
 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
@@ -1336,78 +1096,6 @@ int ast_play_and_wait(struct ast_channel *chan, const char *fn)
 	return d;
 }
 
-/*!
- * \brief Construct a silence frame of the same duration as \a orig.
- *
- * The \a orig frame must be \ref AST_FORMAT_SLINEAR.
- *
- * \param orig Frame as basis for silence to generate.
- * \return New frame of silence; free with ast_frfree().
- * \return \c NULL on error.
- */
-static struct ast_frame *make_silence(const struct ast_frame *orig)
-{
-	struct ast_frame *silence;
-	size_t size;
-	size_t datalen;
-	size_t samples = 0;
-	struct ast_frame *next;
-
-	if (!orig) {
-		return NULL;
-	}
-
-	if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
-		return NULL;
-	}
-
-	for (next = AST_LIST_NEXT(orig, frame_list);
-		 orig;
-		 orig = next, next = orig ? AST_LIST_NEXT(orig, frame_list) : NULL) {
-		samples += orig->samples;
-	}
-
-	ast_verb(4, "Silencing %zu samples\n", samples);
-
-
-	datalen = sizeof(short) * samples;
-	size = sizeof(*silence) + datalen;
-	silence = ast_calloc(1, size);
-	if (!silence) {
-		return NULL;
-	}
-
-	silence->mallocd = AST_MALLOCD_HDR;
-	silence->frametype = AST_FRAME_VOICE;
-	silence->data.ptr = (void *)(silence + 1);
-	silence->samples = samples;
-	silence->datalen = datalen;
-
-	silence->subclass.format = ast_format_slin;
-
-	return silence;
-}
-
-/*!
- * \brief Sets a channel's read format to \ref AST_FORMAT_SLINEAR, recording
- * its original format.
- *
- * \param chan Channel to modify.
- * \param[out] orig_format Output variable to store channel's original read
- *                         format.
- * \return 0 on success.
- * \return -1 on error.
- */
-static int set_read_to_slin(struct ast_channel *chan, struct ast_format **orig_format)
-{
-	if (!chan || !orig_format) {
-		return -1;
-	}
-	*orig_format = ao2_bump(ast_channel_readformat(chan));
-	return ast_set_read_format(chan, ast_format_slin);
-}
-
 static int global_silence_threshold = 128;
 static int global_maxsilence = 0;
 
@@ -1433,7 +1121,7 @@ static int global_maxsilence = 0;
  * \retval 't' Recording ended from the message exceeding the maximum duration, or via DTMF in prepend mode
  * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
  */
-static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
+static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound)
 {
 	int d = 0;
 	char *fmts;
@@ -1447,25 +1135,11 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 	int totalsilence = 0;
 	int dspsilence = 0;
 	int olddspsilence = 0;
-	struct ast_format *rfmt = NULL;
+	struct ast_format rfmt;
 	struct ast_silence_generator *silgen = NULL;
 	char prependfile[PATH_MAX];
-	int ioflags;	/* IO flags for writing output file */
-
-	ioflags = O_CREAT|O_WRONLY;
-
-	switch (if_exists) {
-	case AST_RECORD_IF_EXISTS_FAIL:
-		ioflags |= O_EXCL;
-		break;
-	case AST_RECORD_IF_EXISTS_OVERWRITE:
-		ioflags |= O_TRUNC;
-		break;
-	case AST_RECORD_IF_EXISTS_APPEND:
-		ioflags |= O_APPEND;
-		break;
-	}
 
+	ast_format_clear(&rfmt);
 	if (silencethreshold < 0) {
 		silencethreshold = global_silence_threshold;
 	}
@@ -1517,7 +1191,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 
 	end = start = time(NULL);  /* pre-initialize end to be same as start in case we never get into loop */
 	for (x = 0; x < fmtcnt; x++) {
-		others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, ioflags, 0, AST_FILE_MODE);
+		others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
 		ast_verb(3, "x=%d, open writing:  %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
 
 		if (!others[x]) {
@@ -1536,11 +1210,11 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 			return -1;
 		}
 		ast_dsp_set_threshold(sildet, silencethreshold);
-		res = set_read_to_slin(chan, &rfmt);
+		ast_format_copy(&rfmt, ast_channel_readformat(chan));
+		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
 			ast_dsp_free(sildet);
-			ao2_cleanup(rfmt);
 			return -1;
 		}
 	}
@@ -1555,15 +1229,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 	}
 
 	if (x == fmtcnt) {
-		/* Loop, writing the packets we read to the writer(s), until
-		 * we have reason to stop. */
+		/* Loop forever, writing the packets we read to the writer(s), until
+		   we read a digit or get a hangup */
 		struct ast_frame *f;
-		int paused = 0;
-		int muted = 0;
-		time_t pause_start = 0;
-		int paused_secs = 0;
-		int pausedsilence = 0;
-
 		for (;;) {
 			if (!(res = ast_waitfor(chan, 2000))) {
 				ast_debug(1, "One waitfor failed, trying another\n");
@@ -1583,29 +1251,11 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 			}
 			if (f->frametype == AST_FRAME_VOICE) {
 				/* write each format */
-				if (paused) {
-					/* It's all good */
-					res = 0;
-				} else {
-					RAII_VAR(struct ast_frame *, silence, NULL, ast_frame_dtor);
-					struct ast_frame *orig = f;
-
-					if (muted) {
-						silence = make_silence(orig);
-						if (!silence) {
-							ast_log(LOG_WARNING,
-								"Error creating silence\n");
-							break;
-						}
-						f = silence;
-					}
-					for (x = 0; x < fmtcnt; x++) {
-						if (prepend && !others[x]) {
-							break;
-						}
-						res = ast_writestream(others[x], f);
+				for (x = 0; x < fmtcnt; x++) {
+					if (prepend && !others[x]) {
+						break;
 					}
-					f = orig;
+					res = ast_writestream(others[x], f);
 				}
 
 				/* Silence Detection */
@@ -1617,17 +1267,6 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 					}
 					olddspsilence = dspsilence;
 
-					if (paused) {
-						/* record how much silence there was while we are paused */
-						pausedsilence = dspsilence;
-					} else if (dspsilence > pausedsilence) {
-						/* ignore the paused silence */
-						dspsilence -= pausedsilence;
-					} else {
-						/* dspsilence has reset, reset pausedsilence */
-						pausedsilence = 0;
-					}
-
 					if (dspsilence > maxsilence) {
 						/* Ended happily with silence */
 						ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", dspsilence/1000);
@@ -1659,51 +1298,15 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 					break;
 				}
 				if (strchr(canceldtmf, f->subclass.integer)) {
-					ast_verb(3, "User canceled message by pressing %c\n", f->subclass.integer);
+					ast_verb(3, "User cancelled message by pressing %c\n", f->subclass.integer);
 					res = f->subclass.integer;
 					outmsg = 0;
 					break;
 				}
-			} else if (f->frametype == AST_FRAME_CONTROL) {
-				if (f->subclass.integer == AST_CONTROL_RECORD_CANCEL) {
-					ast_verb(3, "Message canceled by control\n");
-					outmsg = 0; /* cancels the recording */
-					res = 0;
-					break;
-				} else if (f->subclass.integer == AST_CONTROL_RECORD_STOP) {
-					ast_verb(3, "Message ended by control\n");
-					res = 0;
-					break;
-				} else if (f->subclass.integer == AST_CONTROL_RECORD_SUSPEND) {
-					paused = !paused;
-					ast_verb(3, "Message %spaused by control\n",
-						paused ? "" : "un");
-					if (paused) {
-						pause_start = time(NULL);
-					} else {
-						paused_secs += time(NULL) - pause_start;
-					}
-				} else if (f->subclass.integer == AST_CONTROL_RECORD_MUTE) {
-					muted = !muted;
-					ast_verb(3, "Message %smuted by control\n",
-						muted ? "" : "un");
-					/* We can only silence slin frames, so
-					 * set the mode, if we haven't already
-					 * for sildet
-					 */
-					if (muted && !rfmt) {
-						ast_verb(3, "Setting read format to linear mode\n");
-						res = set_read_to_slin(chan, &rfmt);
-						if (res < 0) {
-							ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
-							break;
-						}
-					}
-				}
 			}
-			if (maxtime && !paused) {
+			if (maxtime) {
 				end = time(NULL);
-				if (maxtime < (end - start - paused_secs)) {
+				if (maxtime < (end - start)) {
 					ast_verb(3, "Took too long, cutting it short...\n");
 					res = 't';
 					outmsg = 2;
@@ -1821,10 +1424,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 		}
 	}
 
-	if (rfmt && ast_set_read_format(chan, rfmt)) {
-		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan));
+	if (rfmt.id && ast_set_read_format(chan, &rfmt)) {
+		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), ast_channel_name(chan));
 	}
-	ao2_cleanup(rfmt);
 	if ((outmsg == 2) && (!skip_confirmation_sound)) {
 		ast_stream_and_wait(chan, "auth-thankyou", "");
 	}
@@ -1837,19 +1439,19 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
 static const char default_acceptdtmf[] = "#";
 static const char default_canceldtmf[] = "";
 
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
 {
-	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, ""), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
+	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), 0);
 }
 
 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
 {
-	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
+	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0);
 }
 
 int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence)
 {
-	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1, AST_RECORD_IF_EXISTS_OVERWRITE);
+	return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1);
 }
 
 /* Channel group core functions */
@@ -3028,318 +2630,3 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen uni
 	return 0;
 }
 
-
-
-static void mwi_state_dtor(void *obj)
-{
-	struct ast_mwi_state *mwi_state = obj;
-	ast_string_field_free_memory(mwi_state);
-	ao2_cleanup(mwi_state->snapshot);
-	mwi_state->snapshot = NULL;
-}
-
-struct stasis_topic *ast_mwi_topic_all(void)
-{
-	return mwi_topic_all;
-}
-
-struct stasis_cache *ast_mwi_state_cache(void)
-{
-	return mwi_state_cache;
-}
-
-struct stasis_topic *ast_mwi_topic_cached(void)
-{
-	return stasis_caching_get_topic(mwi_topic_cached);
-}
-
-struct stasis_topic *ast_mwi_topic(const char *uniqueid)
-{
-	return stasis_topic_pool_get_topic(mwi_topic_pool, uniqueid);
-}
-
-struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context)
-{
-	RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
-
-	ast_assert(!ast_strlen_zero(mailbox));
-
-	mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor);
-	if (!mwi_state) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(mwi_state, 256)) {
-		return NULL;
-	}
-	if (!ast_strlen_zero(context)) {
-		ast_string_field_build(mwi_state, uniqueid, "%s@%s", mailbox, context);
-	} else {
-		ast_string_field_set(mwi_state, uniqueid, mailbox);
-	}
-
-	ao2_ref(mwi_state, +1);
-	return mwi_state;
-}
-
-/*!
- * \internal
- * \brief Create a MWI state snapshot message.
- * \since 12.2.0
- *
- * \param[in] mailbox The mailbox identifier string.
- * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
- * \param[in] new_msgs The number of new messages in this mailbox
- * \param[in] old_msgs The number of old messages in this mailbox
- * \param[in] channel_id A unique identifier for a channel associated with this
- * change in mailbox state
- * \param[in] eid The EID of the server that originally published the message
- *
- * \retval message on success.  Use ao2_cleanup() when done with it.
- * \retval NULL on error.
- */
-static struct stasis_message *mwi_state_create_message(
-	const char *mailbox,
-	const char *context,
-	int new_msgs,
-	int old_msgs,
-	const char *channel_id,
-	struct ast_eid *eid)
-{
-	struct ast_mwi_state *mwi_state;
-	struct stasis_message *message;
-
-	if (!ast_mwi_state_type()) {
-		return NULL;
-	}
-
-	mwi_state = ast_mwi_create(mailbox, context);
-	if (!mwi_state) {
-		return NULL;
-	}
-
-	mwi_state->new_msgs = new_msgs;
-	mwi_state->old_msgs = old_msgs;
-
-	if (!ast_strlen_zero(channel_id)) {
-		struct stasis_message *chan_message;
-
-		chan_message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
-			channel_id);
-		if (chan_message) {
-			mwi_state->snapshot = stasis_message_data(chan_message);
-			ao2_ref(mwi_state->snapshot, +1);
-		}
-		ao2_cleanup(chan_message);
-	}
-
-	if (eid) {
-		mwi_state->eid = *eid;
-	} else {
-		mwi_state->eid = ast_eid_default;
-	}
-
-	/*
-	 * XXX As far as stasis is concerned, all MWI events are local.
-	 *
-	 * We may in the future want to make MWI aggregate local/remote
-	 * message counts similar to how device state aggregates state.
-	 */
-	message = stasis_message_create_full(ast_mwi_state_type(), mwi_state, &ast_eid_default);
-	ao2_cleanup(mwi_state);
-	return message;
-}
-
-int ast_publish_mwi_state_full(
-	const char *mailbox,
-	const char *context,
-	int new_msgs,
-	int old_msgs,
-	const char *channel_id,
-	struct ast_eid *eid)
-{
-	struct ast_mwi_state *mwi_state;
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct stasis_topic *mailbox_specific_topic;
-
-	message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid);
-	if (!message) {
-		return -1;
-	}
-
-	mwi_state = stasis_message_data(message);
-	mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);
-	if (!mailbox_specific_topic) {
-		return -1;
-	}
-
-	stasis_publish(mailbox_specific_topic, message);
-
-	return 0;
-}
-
-int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct stasis_message *cached_msg;
-	struct stasis_message *clear_msg;
-	struct ast_mwi_state *mwi_state;
-	struct stasis_topic *mailbox_specific_topic;
-
-	msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid);
-	if (!msg) {
-		return -1;
-	}
-
-	mwi_state = stasis_message_data(msg);
-
-	/*
-	 * XXX As far as stasis is concerned, all MWI events are local.
-	 *
-	 * For now, it is assumed that there is only one entity
-	 * maintaining the state of a particular mailbox.
-	 *
-	 * If we ever have multiple MWI event entities maintaining
-	 * the same mailbox that wish to delete their cached entry
-	 * we will need to do something about the race condition
-	 * potential between checking the cache and removing the
-	 * cache entry.
-	 */
-	cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(),
-		ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default);
-	if (!cached_msg) {
-		/* Nothing to clear */
-		return -1;
-	}
-	ao2_cleanup(cached_msg);
-
-	mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);
-	if (!mailbox_specific_topic) {
-		return -1;
-	}
-
-	clear_msg = stasis_cache_clear_create(msg);
-	if (clear_msg) {
-		stasis_publish(mailbox_specific_topic, clear_msg);
-	}
-	ao2_cleanup(clear_msg);
-	return 0;
-}
-
-static const char *mwi_state_get_id(struct stasis_message *message)
-{
-	if (ast_mwi_state_type() == stasis_message_type(message)) {
-		struct ast_mwi_state *mwi_state = stasis_message_data(message);
-		return mwi_state->uniqueid;
-	} else if (stasis_subscription_change_type() == stasis_message_type(message)) {
-		struct stasis_subscription_change *change = stasis_message_data(message);
-		return change->uniqueid;
-	}
-
-	return NULL;
-}
-
-static void mwi_blob_dtor(void *obj)
-{
-	struct ast_mwi_blob *mwi_blob = obj;
-
-	ao2_cleanup(mwi_blob->mwi_state);
-	ast_json_unref(mwi_blob->blob);
-}
-
-struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state,
-					       struct stasis_message_type *message_type,
-					       struct ast_json *blob)
-{
-	RAII_VAR(struct ast_mwi_blob *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	ast_assert(blob != NULL);
-
-	if (!message_type) {
-		return NULL;
-	}
-
-	obj = ao2_alloc(sizeof(*obj), mwi_blob_dtor);
-	if (!obj) {
-		return NULL;
-	}
-
-	obj->mwi_state = mwi_state;
-	ao2_ref(obj->mwi_state, +1);
-	obj->blob = ast_json_ref(blob);
-
-	/* This is not a normal MWI event.  Only used by the MinivmNotify app. */
-	msg = stasis_message_create(message_type, obj);
-	if (!msg) {
-		return NULL;
-	}
-
-	ao2_ref(msg, +1);
-	return msg;
-}
-
-struct stasis_topic *ast_queue_topic_all(void)
-{
-	return queue_topic_all;
-}
-
-struct stasis_topic *ast_queue_topic(const char *queuename)
-{
-	return stasis_topic_pool_get_topic(queue_topic_pool, queuename);
-}
-
-static void app_cleanup(void)
-{
-	ao2_cleanup(queue_topic_pool);
-	queue_topic_pool = NULL;
-	ao2_cleanup(queue_topic_all);
-	queue_topic_all = NULL;
-	ao2_cleanup(mwi_topic_pool);
-	mwi_topic_pool = NULL;
-	ao2_cleanup(mwi_topic_all);
-	mwi_topic_all = NULL;
-	ao2_cleanup(mwi_state_cache);
-	mwi_state_cache = NULL;
-	mwi_topic_cached = stasis_caching_unsubscribe_and_join(mwi_topic_cached);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_state_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_vm_app_type);
-}
-
-int app_init(void)
-{
-	ast_register_cleanup(app_cleanup);
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_state_type) != 0) {
-		return -1;
-	}
-	if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_vm_app_type) != 0) {
-		return -1;
-	}
-	mwi_topic_all = stasis_topic_create("stasis_mwi_topic");
-	if (!mwi_topic_all) {
-		return -1;
-	}
-	mwi_state_cache = stasis_cache_create(mwi_state_get_id);
-	if (!mwi_state_cache) {
-		return -1;
-	}
-	mwi_topic_cached = stasis_caching_topic_create(mwi_topic_all, mwi_state_cache);
-	if (!mwi_topic_cached) {
-		return -1;
-	}
-	mwi_topic_pool = stasis_topic_pool_create(mwi_topic_all);
-	if (!mwi_topic_pool) {
-		return -1;
-	}
-	queue_topic_all = stasis_topic_create("stasis_queue_topic");
-	if (!queue_topic_all) {
-		return -1;
-	}
-	queue_topic_pool = stasis_topic_pool_create(queue_topic_all);
-	if (!queue_topic_pool) {
-		return -1;
-	}
-	return 0;
-}
-
diff --git a/main/ast_expr2.c b/main/ast_expr2.c
index 5c9e01d..798e3d3 100644
--- a/main/ast_expr2.c
+++ b/main/ast_expr2.c
@@ -98,7 +98,7 @@
 
 #if !defined(STANDALONE) && !defined(STANDALONE2)	\
 	
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369940 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #ifndef __USE_ISOC99
 #define __USE_ISOC99 1
diff --git a/main/ast_expr2.fl b/main/ast_expr2.fl
index 8bc33fd..e10dde2 100644
--- a/main/ast_expr2.fl
+++ b/main/ast_expr2.fl
@@ -26,7 +26,7 @@
 #include <stdio.h>
 
 #if !defined(STANDALONE)
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 362307 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #ifndef __USE_ISOC99
 #define __USE_ISOC99 1
diff --git a/main/ast_expr2.y b/main/ast_expr2.y
index b3c2585..83d3eff 100644
--- a/main/ast_expr2.y
+++ b/main/ast_expr2.y
@@ -19,7 +19,7 @@
 
 #if !defined(STANDALONE) && !defined(STANDALONE2)	\
 	
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 360359 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #ifndef __USE_ISOC99
 #define __USE_ISOC99 1
diff --git a/main/ast_expr2f.c b/main/ast_expr2f.c
index 68860fd..622f033 100644
--- a/main/ast_expr2f.c
+++ b/main/ast_expr2f.c
@@ -520,7 +520,7 @@ static yyconst flex_int16_t yy_chk[159] =
 #include <stdio.h>
 
 #if !defined(STANDALONE)
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 373330 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #ifndef __USE_ISOC99
 #define __USE_ISOC99 1
@@ -2142,8 +2142,8 @@ void ast_yyset_lineno (int  line_number , yyscan_t yyscanner)
 }
 
 /** Set the current column.
- * \param column_no line_number
- * \param yyscanner The scanner object.
+ * @param line_number
+ * @param yyscanner The scanner object.
  */
 void ast_yyset_column (int  column_no , yyscan_t yyscanner)
 {
diff --git a/main/asterisk.c b/main/asterisk.c
index 5e127b3..ba5ac18 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2014, Digium, Inc.
+ * Copyright (C) 1999 - 2013, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -21,18 +21,6 @@
 /*!
  * \mainpage Asterisk -- The Open Source Telephony Project
  *
- * \par Welcome
- *
- * This documentation created by the Doxygen project clearly explains the
- * internals of the Asterisk software. This documentation contains basic
- * examples, developer documentation, support information, and information
- * for upgrading.
- *
- * \section community Community
- * Asterisk is a big project and has a busy community. Look at the
- * resources for questions and stick around to help answer questions.
- * \li \ref asterisk_community_resources
- *
  * \par Developer Documentation for Asterisk
  *
  * This is the main developer documentation for Asterisk. It is
@@ -47,100 +35,28 @@
  * \par Additional documentation
  * \arg \ref Licensing
  * \arg \ref DevDoc
- * \arg \ref configuration_file
- * \arg \ref channel_drivers
- * \arg \ref applications
+ * \arg \ref ConfigFiles
  *
  * \section copyright Copyright and Author
  *
- * Copyright (C) 1999 - 2014, Digium, Inc.
+ * Copyright (C) 1999 - 2013, Digium, Inc.
  * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
  * of <a rel="nofollow" href="http://www.digium.com">Digium, Inc</a>.
  *
  * \author Mark Spencer <markster at digium.com>
+ * Also see \ref AstCREDITS
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
  * any of the maintainers of this project for assistance;
  * the project provides a web site, mailing lists, and IRC
  * channels for your use.
- *
- */
-
-/*!
- * \page asterisk_community_resources Asterisk Community Resources
- * \par Websites
- * \li http://www.asterisk.org Asterisk Homepage
- * \li http://wiki.asterisk.org Asterisk Wiki
- *
- * \par Mailing Lists
- * \par
- * All lists: http://lists.digium.com/mailman/listinfo
- * \li aadk-commits	SVN commits to the AADK repository
- * \li asterisk-addons-commits	SVN commits to the Asterisk addons project
- * \li asterisk-announce	[no description available]
- * \li asterisk-biz	Commercial and Business-Oriented Asterisk Discussion
- * \li Asterisk-BSD	Asterisk on BSD discussion
- * \li asterisk-bugs	[no description available]
- * \li asterisk-commits	SVN commits to the Asterisk project
- * \li asterisk-dev	Asterisk Developers Mailing List
- * \li asterisk-doc	Discussions regarding The Asterisk Documentation Project
- * \li asterisk-embedded	Asterisk Embedded Development
- * \li asterisk-gui	Asterisk GUI project discussion
- * \li asterisk-gui-commits	SVN commits to the Asterisk-GUI project
- * \li asterisk-ha-clustering	Asterisk High Availability and Clustering List - Non-Commercial Discussion
- * \li Asterisk-i18n	Discussion of Asterisk internationalization
- * \li asterisk-r2	[no description available]
- * \li asterisk-scf-commits	Commits to the Asterisk SCF project code repositories
- * \li asterisk-scf-committee	Asterisk SCF Steering Committee discussions
- * \li asterisk-scf-dev	Asterisk SCF Developers Mailing List
- * \li asterisk-scf-wiki-changes	Changes to the Asterisk SCF space on wiki.asterisk.org
- * \li asterisk-security	Asterisk Security Discussion
- * \li asterisk-speech-rec	Use of speech recognition in Asterisk
- * \li asterisk-ss7	[no description available]
- * \li asterisk-users	Asterisk Users Mailing List - Non-Commercial Discussion
- * \li asterisk-video	Development discussion of video media support in Asterisk
- * \li asterisk-wiki-changes	Changes to the Asterisk space on wiki.asterisk.org
- * \li asterisknow	AsteriskNOW Discussion
- * \li dahdi-commits	SVN commits to the DAHDI project
- * \li digium-announce	Digium Product Announcements
- * \li Dundi	Distributed Universal Number Discovery
- * \li libiax2-commits	SVN commits to the libiax2 project
- * \li libpri-commits	SVN commits to the libpri project
- * \li libss7-commits	SVN commits to the libss7 project
- * \li svn-commits	SVN commits to the Digium repositories
- * \li Test-results	Results from automated testing
- * \li thirdparty-commits	SVN commits to the Digium third-party software repository
- * \li zaptel-commits	SVN commits to the Zaptel project
- *
- * \par Forums
- * \li Forums are located at http://forums.asterisk.org/
- *
- * \par IRC
- * \par
- * Use http://www.freenode.net IRC server to connect with Asterisk
- * developers and users in realtime.
- *
- * \li \verbatim #asterisk \endverbatim Asterisk Users Room
- * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
- *
- * \par More
- * \par
- * If you would like to add a resource to this list please create an issue
- * on the issue tracker with a patch.
  */
 
 /*! \file
- * \brief Top level source file for Asterisk - the Open Source PBX.
- *	Implementation of PBX core functions and CLI interface.
- */
-
-/*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
- * \addtogroup configuration_file
- */
+  \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
+  of PBX core functions and CLI interface.
 
-/*! \page asterisk.conf asterisk.conf
- * \verbinclude asterisk.conf.sample
  */
 
 /*** MODULEINFO
@@ -149,7 +65,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -171,12 +87,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #elif defined(HAVE_SYSCTL)
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#if !defined(__OpenBSD__)
 #include <sys/vmmeter.h>
 #if defined(__FreeBSD__)
 #include <vm/vm_param.h>
 #endif
-#endif
 #if defined(HAVE_SWAPCTL)
 #include <sys/swap.h>
 #endif
@@ -196,13 +110,11 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #endif /* HAVE_CAP */
 #endif /* linux */
 
-/* we define here the variables so to better agree on the prototype */
-#include "asterisk/paths.h"
+#include "asterisk/paths.h"	/* we define here the variables so better agree on the prototype */
 #include "asterisk/network.h"
 #include "asterisk/cli.h"
 #include "asterisk/channel.h"
 #include "asterisk/translate.h"
-#include "asterisk/pickup.h"
 #include "asterisk/features.h"
 #include "asterisk/acl.h"
 #include "asterisk/ulaw.h"
@@ -239,54 +151,10 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #include "asterisk/rtp_engine.h"
 #include "asterisk/format.h"
 #include "asterisk/aoc.h"
-#include "asterisk/uuid.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/bucket.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_system.h"
-#include "asterisk/security_events.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/codec.h"
-#include "asterisk/format_cache.h"
 
 #include "../defaults.h"
 
 /*** DOCUMENTATION
-	<managerEvent language="en_US" name="FullyBooted">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
-			<syntax>
-				<parameter name="Status">
-					<para>Informational message</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Shutdown">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
-			<syntax>
-				<parameter name="Shutdown">
-					<para>Whether the shutdown is proceeding cleanly (all channels
-					were hungup successfully) or uncleanly (channels will be
-					terminated)</para>
-					<enumlist>
-						<enum name="Uncleanly"/>
-						<enum name="Cleanly"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Restart">
-					<para>Whether or not a restart will occur.</para>
-					<enumlist>
-						<enum name="True"/>
-						<enum name="False"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #ifndef AF_LOCAL
@@ -303,7 +171,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 
 /*! \brief Welcome message when starting a CLI interface */
 #define WELCOME_MESSAGE \
-    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n" \
+    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2013 Digium, Inc. and others.\n" \
                 "Created by Mark Spencer <markster at digium.com>\n" \
                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
                 "This is free software, with components licensed under the GNU General Public\n" \
@@ -319,15 +187,16 @@ int daemon(int, int);  /* defined in libresolv of all places */
 /*! @{ */
 
 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
+struct ast_flags ast_compat = { 0 };
 
 /*! Maximum active system verbosity level. */
 int ast_verb_sys_level;
 
 int option_verbose;				/*!< Verbosity level */
 int option_debug;				/*!< Debug level */
-double ast_option_maxload;			/*!< Max load avg on system */
-int ast_option_maxcalls;			/*!< Max number of active calls */
-int ast_option_maxfiles;			/*!< Max number of open file handles (files, sockets) */
+double option_maxload;				/*!< Max load avg on system */
+int option_maxcalls;				/*!< Max number of active calls */
+int option_maxfiles;				/*!< Max number of open file handles (files, sockets) */
 unsigned int option_dtmfminduration;		/*!< Minimum duration of DTMF. */
 #if defined(HAVE_SYSINFO)
 long option_minmemfree;				/*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
@@ -383,7 +252,6 @@ struct _cfg_paths {
 	char module_dir[PATH_MAX];
 	char spool_dir[PATH_MAX];
 	char monitor_dir[PATH_MAX];
-	char recording_dir[PATH_MAX];
 	char var_dir[PATH_MAX];
 	char data_dir[PATH_MAX];
 	char log_dir[PATH_MAX];
@@ -408,7 +276,6 @@ const char *ast_config_AST_CONFIG_FILE	= cfg_paths.config_file;
 const char *ast_config_AST_MODULE_DIR	= cfg_paths.module_dir;
 const char *ast_config_AST_SPOOL_DIR	= cfg_paths.spool_dir;
 const char *ast_config_AST_MONITOR_DIR	= cfg_paths.monitor_dir;
-const char *ast_config_AST_RECORDING_DIR	= cfg_paths.recording_dir;
 const char *ast_config_AST_VAR_DIR	= cfg_paths.var_dir;
 const char *ast_config_AST_DATA_DIR	= cfg_paths.data_dir;
 const char *ast_config_AST_LOG_DIR	= cfg_paths.log_dir;
@@ -459,84 +326,81 @@ static struct {
 } sig_flags;
 
 #if !defined(LOW_MEMORY)
-struct file_version {
-	AST_RWLIST_ENTRY(file_version) list;
+struct registered_file {
+	AST_RWLIST_ENTRY(registered_file) list;
 	const char *file;
-	char *version;
 };
 
-static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
+static AST_RWLIST_HEAD_STATIC(registered_files, registered_file);
 
 void ast_register_file_version(const char *file, const char *version)
 {
-	struct file_version *new;
-	char *work;
-	size_t version_length;
-
-	work = ast_strdupa(version);
-	work = ast_strip(ast_strip_quoted(work, "$", "$"));
-	version_length = strlen(work) + 1;
+	struct registered_file *reg;
 
-	if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
+	reg = ast_calloc(1, sizeof(*reg));
+	if (!reg) {
 		return;
+	}
 
-	new->file = file;
-	new->version = (char *) new + sizeof(*new);
-	memcpy(new->version, work, version_length);
-	AST_RWLIST_WRLOCK(&file_versions);
-	AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
-	AST_RWLIST_UNLOCK(&file_versions);
+	reg->file = file;
+	AST_RWLIST_WRLOCK(&registered_files);
+	AST_RWLIST_INSERT_HEAD(&registered_files, reg, list);
+	AST_RWLIST_UNLOCK(&registered_files);
 }
 
 void ast_unregister_file_version(const char *file)
 {
-	struct file_version *find;
+	struct registered_file *find;
 
-	AST_RWLIST_WRLOCK(&file_versions);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
+	AST_RWLIST_WRLOCK(&registered_files);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&registered_files, find, list) {
 		if (!strcasecmp(find->file, file)) {
 			AST_RWLIST_REMOVE_CURRENT(list);
 			break;
 		}
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END;
-	AST_RWLIST_UNLOCK(&file_versions);
+	AST_RWLIST_UNLOCK(&registered_files);
 
-	if (find)
+	if (find) {
 		ast_free(find);
+	}
 }
 
 char *ast_complete_source_filename(const char *partial, int n)
 {
-	struct file_version *find;
+	struct registered_file *find;
 	size_t len = strlen(partial);
 	int count = 0;
 	char *res = NULL;
 
-	AST_RWLIST_RDLOCK(&file_versions);
-	AST_RWLIST_TRAVERSE(&file_versions, find, list) {
+	AST_RWLIST_RDLOCK(&registered_files);
+	AST_RWLIST_TRAVERSE(&registered_files, find, list) {
 		if (!strncasecmp(find->file, partial, len) && ++count > n) {
 			res = ast_strdup(find->file);
 			break;
 		}
 	}
-	AST_RWLIST_UNLOCK(&file_versions);
+	AST_RWLIST_UNLOCK(&registered_files);
 	return res;
 }
 
-/*! \brief Find version for given module name */
 const char *ast_file_version_find(const char *file)
 {
-	struct file_version *iterator;
+	struct registered_file *iterator;
 
-	AST_RWLIST_WRLOCK(&file_versions);
-	AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
-		if (!strcasecmp(iterator->file, file))
+	AST_RWLIST_RDLOCK(&registered_files);
+	AST_RWLIST_TRAVERSE(&registered_files, iterator, list) {
+		if (!strcasecmp(iterator->file, file)) {
 			break;
+		}
 	}
-	AST_RWLIST_UNLOCK(&file_versions);
-	if (iterator)
-		return iterator->version;
+	AST_RWLIST_UNLOCK(&registered_files);
+
+	if (iterator) {
+		return ast_get_version();
+	}
+
 	return NULL;
 }
 
@@ -607,18 +471,18 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
 	ast_cli(a->fd, "-----------------\n");
 	ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
 	ast_cli(a->fd, "  Build Options:               %s\n", S_OR(AST_BUILDOPTS, "(none)"));
-	if (ast_option_maxcalls)
-		ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
+	if (option_maxcalls)
+		ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", option_maxcalls, ast_active_channels());
 	else
 		ast_cli(a->fd, "  Maximum calls:               Not set\n");
-	if (ast_option_maxfiles)
-		ast_cli(a->fd, "  Maximum open file handles:   %d\n", ast_option_maxfiles);
+	if (option_maxfiles)
+		ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles);
 	else
 		ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
 	ast_cli(a->fd, "  Root console verbosity:      %d\n", option_verbose);
 	ast_cli(a->fd, "  Current console verbosity:   %d\n", ast_verb_console_get());
 	ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
-	ast_cli(a->fd, "  Maximum load average:        %lf\n", ast_option_maxload);
+	ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
 #if defined(HAVE_SYSINFO)
 	ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
 #endif
@@ -646,7 +510,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
 	ast_cli(a->fd, "  -------------\n");
 	ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
-	ast_cli(a->fd, "  Call data records:           %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
+	ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
 
 	/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
@@ -1019,35 +883,35 @@ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_c
 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 #define FORMAT "%-25.25s %-40.40s\n"
-	struct file_version *iterator;
+	struct registered_file *iterator;
 	regex_t regexbuf;
 	int havepattern = 0;
 	int havename = 0;
 	int count_files = 0;
 	char *ret = NULL;
 	int matchlen, which = 0;
-	struct file_version *find;
+	struct registered_file *find;
 
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "core show file version [like]";
 		e->usage =
 			"Usage: core show file version [like <pattern>]\n"
-			"       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
+			"       Lists the files along with the Asterisk version.\n"
 			"       Optional regular expression pattern is used to filter the file list.\n";
 		return NULL;
 	case CLI_GENERATE:
 		matchlen = strlen(a->word);
 		if (a->pos != 3)
 			return NULL;
-		AST_RWLIST_RDLOCK(&file_versions);
-		AST_RWLIST_TRAVERSE(&file_versions, find, list) {
+		AST_RWLIST_RDLOCK(&registered_files);
+		AST_RWLIST_TRAVERSE(&registered_files, find, list) {
 			if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
 				ret = ast_strdup(find->file);
 				break;
 			}
 		}
-		AST_RWLIST_UNLOCK(&file_versions);
+		AST_RWLIST_UNLOCK(&registered_files);
 		return ret;
 	}
 
@@ -1072,20 +936,20 @@ static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct
 
 	ast_cli(a->fd, FORMAT, "File", "Revision");
 	ast_cli(a->fd, FORMAT, "----", "--------");
-	AST_RWLIST_RDLOCK(&file_versions);
-	AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
+	AST_RWLIST_RDLOCK(&registered_files);
+	AST_RWLIST_TRAVERSE(&registered_files, iterator, list) {
 		if (havename && strcasecmp(iterator->file, a->argv[4]))
 			continue;
 
 		if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
 			continue;
 
-		ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
+		ast_cli(a->fd, FORMAT, iterator->file, ast_get_version());
 		count_files++;
 		if (havename)
 			break;
 	}
-	AST_RWLIST_UNLOCK(&file_versions);
+	AST_RWLIST_UNLOCK(&registered_files);
 	if (!havename) {
 		ast_cli(a->fd, "%d files listed.\n", count_files);
 	}
@@ -1099,15 +963,6 @@ static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct
 
 #endif /* ! LOW_MEMORY */
 
-static void publish_fully_booted(void)
-{
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
-	json_object = ast_json_pack("{s: s}",
-			"Status", "Fully Booted");
-	ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
-}
-
 static void ast_run_atexits(int run_cleanups)
 {
 	struct ast_atexit *ae;
@@ -1200,8 +1055,7 @@ static struct sigaction ignore_sig_handler = {
 
 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
 /*! \brief Keep track of how many threads are currently trying to wait*() on
- *  a child process
- */
+ *  a child process */
 static unsigned int safe_system_level = 0;
 static struct sigaction safe_system_prev_handler;
 
@@ -1239,6 +1093,7 @@ int ast_safe_system(const char *s)
 {
 	pid_t pid;
 	int res;
+	struct rusage rusage;
 	int status;
 
 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
@@ -1270,7 +1125,7 @@ int ast_safe_system(const char *s)
 		_exit(1);
 	} else if (pid > 0) {
 		for (;;) {
-			res = waitpid(pid, &status, 0);
+			res = wait4(pid, &status, 0, &rusage);
 			if (res > -1) {
 				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
 				break;
@@ -1383,7 +1238,7 @@ static void ast_network_puts(const char *string)
 }
 
 /*!
- * \brief write the string to the root console, and all attached
+ * write the string to the root console, and all attached
  * network console clients
  */
 void ast_console_puts(const char *string)
@@ -1740,10 +1595,10 @@ static int ast_tryconnect(void)
 }
 
 /*! \brief Urgent handler
- *
- * Called by soft_hangup to interrupt the poll, read, or other
- * system call.  We don't actually need to do anything though.
- * Remember: Cannot EVER ast_log from within a signal handler
+
+ Called by soft_hangup to interrupt the poll, read, or other
+ system call.  We don't actually need to do anything though.
+ Remember: Cannot EVER ast_log from within a signal handler
  */
 static void _urg_handler(int num)
 {
@@ -1783,7 +1638,7 @@ static void _child_handler(int sig)
 	/*
 	 * Reap all dead children -- not just one
 	 */
-	for (n = 0; waitpid(-1, &status, WNOHANG) > 0; n++)
+	for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
 		;
 	if (n == 0 && option_debug)
 		printf("Huh?  Child handler, but nobody there?\n");
@@ -1831,10 +1686,8 @@ static void set_icon(char *text)
 		fprintf(stdout, "\033]1;%s\007", text);
 }
 
-/*! \brief We set ourselves to a high priority, that we might pre-empt
- * everything else.  If your PBX has heavy activity on it, this is a
- * good thing.
- */
+/*! \brief We set ourselves to a high priority, that we might pre-empt everything
+   else.  If your PBX has heavy activity on it, this is a good thing.  */
 int ast_set_priority(int pri)
 {
 	struct sched_param sched;
@@ -1934,8 +1787,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
 	}
 
 	/* Re-acquire lock and check if someone changed the niceness, in which
-	 * case someone else has taken over the shutdown.
-	 */
+	 * case someone else has taken over the shutdown. */
 	ast_mutex_lock(&safe_system_lock);
 	if (shuttingdown != niceness) {
 		if (shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console) {
@@ -1954,7 +1806,6 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
 static void really_quit(int num, shutdown_nice_t niceness, int restart)
 {
 	int active_channels;
-	struct ast_json *json_object = NULL;
 	int run_cleanups = niceness >= SHUTDOWN_NICE;
 
 	if (run_cleanups) {
@@ -1984,17 +1835,33 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
 		}
 	}
 	active_channels = ast_active_channels();
-	/* Don't publish messages if we're a remote console - we won't have all of the Stasis
-	 * topics or message types
+	/* The manager event for shutdown must happen prior to ast_run_atexits, as
+	 * the manager interface will dispose of its sessions as part of its
+	 * shutdown.
 	 */
-	if (!ast_opt_remote) {
-		json_object = ast_json_pack("{s: s, s: s}",
-				"Shutdown", active_channels ? "Uncleanly" : "Cleanly",
-				"Restart", restart ? "True" : "False");
-		ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
-		ast_json_unref(json_object);
-		json_object = NULL;
-	}
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
+			<syntax>
+				<parameter name="Shutdown">
+					<enumlist>
+						<enum name="Uncleanly"/>
+						<enum name="Cleanly"/>
+					</enumlist>
+				</parameter>
+				<parameter name="Restart">
+					<enumlist>
+						<enum name="True"/>
+						<enum name="False"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
+		"Restart: %s\r\n",
+		active_channels ? "Uncleanly" : "Cleanly",
+		restart ? "True" : "False");
 	ast_verb(0, "Asterisk %s ending (%d).\n",
 		active_channels ? "uncleanly" : "cleanly", num);
 
@@ -2069,14 +1936,13 @@ static void __remote_quit_handler(int num)
 	sig_flags.need_quit = 1;
 }
 
-static void set_header(char *outbuf, int maxout, char level)
+static const char *fix_header(char *outbuf, int maxout, const char *s, char level)
 {
 	const char *cmp;
-	char date[40];
 
 	switch (level) {
-	case 0: cmp = NULL;
-		break;
+	case 0: *outbuf = '\0';
+		return s;
 	case 1: cmp = VERBOSE_PREFIX_1;
 		break;
 	case 2: cmp = VERBOSE_PREFIX_2;
@@ -2087,20 +1953,12 @@ static void set_header(char *outbuf, int maxout, char level)
 		break;
 	}
 
-	if (ast_opt_timestamp) {
-		struct ast_tm tm;
-		struct timeval now = ast_tvnow();
-		ast_localtime(&now, &tm, NULL);
-		ast_strftime(date, sizeof(date), ast_logger_get_dateformat(), &tm);
+	if (!strncmp(s, cmp, strlen(cmp))) {
+		s += strlen(cmp);
 	}
+	term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
 
-	snprintf(outbuf, maxout, "%s%s%s%s%s%s",
-		ast_opt_timestamp ? "[" : "",
-		ast_opt_timestamp ? date : "",
-		ast_opt_timestamp ? "] " : "",
-		cmp ? ast_term_color(COLOR_GRAY, 0) : "",
-		cmp ? cmp : "",
-		cmp ? ast_term_reset() : "");
+	return s;
 }
 
 struct console_state_data {
@@ -2128,15 +1986,16 @@ static int console_print(const char *s, int local)
 
 	do {
 		if (VERBOSE_HASMAGIC(s)) {
-
 			/* always use the given line's level, otherwise
 			   we'll use the last line's level */
 			state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
-
 			/* move past magic */
 			s++;
 
-			set_header(prefix, sizeof(prefix), state->verbose_line_level);
+			if (local) {
+				s = fix_header(prefix, sizeof(prefix), s,
+					       state->verbose_line_level);
+			}
 		} else {
 			*prefix = '\0';
 		}
@@ -2158,7 +2017,7 @@ static int console_print(const char *s, int local)
 			continue;
 		}
 
-		if (!ast_strlen_zero(prefix)) {
+		if (local && !ast_strlen_zero(prefix)) {
 			fputs(prefix, stdout);
 		}
 
@@ -2581,6 +2440,8 @@ static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 
 #define ASTERISK_PROMPT "*CLI> "
 
+#define ASTERISK_PROMPT2 "%s*CLI> "
+
 /*!
  * \brief Shutdown Asterisk CLI commands.
  *
@@ -2737,6 +2598,7 @@ static char *cli_prompt(EditLine *editline)
 	char *pfmt;
 	int color_used = 0;
 	static int cli_prompt_changes = 0;
+	char term_code[20];
 	struct passwd *pw;
 	struct group *gr;
 
@@ -2763,10 +2625,10 @@ static char *cli_prompt(EditLine *editline)
 				case 'C': /* color */
 					t++;
 					if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
-						ast_term_color_code(&prompt, fgcolor, bgcolor);
+						ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
 						t += i - 1;
 					} else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
-						ast_term_color_code(&prompt, fgcolor, 0);
+						ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
 						t += i - 1;
 					}
 
@@ -2846,12 +2708,12 @@ static char *cli_prompt(EditLine *editline)
 		}
 		if (color_used) {
 			/* Force colors back to normal at end */
-			ast_term_color_code(&prompt, 0, 0);
+			ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
 		}
+	} else if (remotehostname) {
+		ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
 	} else {
-		ast_str_set(&prompt, 0, "%s%s",
-			remotehostname ? remotehostname : "",
-			ASTERISK_PROMPT);
+		ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
 	}
 
 	return ast_str_buffer(prompt);
@@ -3158,23 +3020,12 @@ static int ast_el_initialize(void)
 static int ast_el_add_history(char *buf)
 {
 	HistEvent ev;
-	char *stripped_buf;
 
-	if (el_hist == NULL || el == NULL) {
+	if (el_hist == NULL || el == NULL)
 		ast_el_initialize();
-	}
-	if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
-		return 0;
-	}
-
-	stripped_buf = ast_strip(ast_strdupa(buf));
-
-	/* HISTCONTROL=ignoredups */
-	if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
+	if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
 		return 0;
-	}
-
-	return history(el_hist, &ev, H_ENTER, stripped_buf);
+	return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
 }
 
 static int ast_el_write_history(char *filename)
@@ -3200,7 +3051,7 @@ static int ast_el_read_history(char *filename)
 
 static void ast_remotecontrol(char *data)
 {
-	char buf[80];
+	char buf[256] = "";
 	int res;
 	char filename[80] = "";
 	char *hostname;
@@ -3217,7 +3068,7 @@ static void ast_remotecontrol(char *data)
 	signal(SIGTERM, __remote_quit_handler);
 	signal(SIGHUP, __remote_quit_handler);
 
-	if (read(ast_consock, buf, sizeof(buf)) < 0) {
+	if (read(ast_consock, buf, sizeof(buf) - 1) < 0) {
 		ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
 		return;
 	}
@@ -3353,7 +3204,7 @@ static int show_version(void)
 
 static int show_cli_help(void)
 {
-	printf("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n", ast_get_version());
+	printf("Asterisk %s, Copyright (C) 1999 - 2013, Digium, Inc. and others.\n", ast_get_version());
 	printf("Usage: asterisk [OPTIONS]\n");
 	printf("Valid Options:\n");
 	printf("   -V              Display version number and exit\n");
@@ -3401,8 +3252,8 @@ static void ast_readconfig(void)
 		unsigned int dbdir:1;
 		unsigned int keydir:1;
 	} found = { 0, 0 };
-	/* Default to false for security */
-	int live_dangerously = 0;
+	/* Default to true for backward compatibility */
+	int live_dangerously = 1;
 
 	/* Set default value */
 	option_dtmfminduration = AST_MIN_DTMF_DURATION;
@@ -3421,7 +3272,6 @@ static void ast_readconfig(void)
 	ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
 	ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
 	snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
-	snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
 	ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
 	ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
 	ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
@@ -3457,7 +3307,6 @@ static void ast_readconfig(void)
 		} else if (!strcasecmp(v->name, "astspooldir")) {
 			ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
 			snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
-			snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
 		} else if (!strcasecmp(v->name, "astvarlibdir")) {
 			ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
 			if (!found.dbdir)
@@ -3501,7 +3350,7 @@ static void ast_readconfig(void)
 		} else if (!strcasecmp(v->name, "debug")) {
 			option_debug = 0;
 			if (sscanf(v->value, "%30d", &option_debug) != 1) {
-				option_debug = ast_true(v->value);
+				option_debug = ast_true(v->value) ? 1 : 0;
 			}
 #if HAVE_WORKING_FORK
 		/* Disable forking (-f at startup) */
@@ -3556,22 +3405,22 @@ static void ast_readconfig(void)
 				option_dtmfminduration = AST_MIN_DTMF_DURATION;
 			}
 		} else if (!strcasecmp(v->name, "maxcalls")) {
-			if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
-				ast_option_maxcalls = 0;
+			if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
+				option_maxcalls = 0;
 			}
 		} else if (!strcasecmp(v->name, "maxload")) {
 			double test[1];
 
 			if (getloadavg(test, 1) == -1) {
 				ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
-				ast_option_maxload = 0.0;
-			} else if ((sscanf(v->value, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
-				ast_option_maxload = 0.0;
+				option_maxload = 0.0;
+			} else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
+				option_maxload = 0.0;
 			}
 		/* Set the maximum amount of open files */
 		} else if (!strcasecmp(v->name, "maxfiles")) {
-			ast_option_maxfiles = atoi(v->value);
-			set_ulimit(ast_option_maxfiles);
+			option_maxfiles = atoi(v->value);
+			set_ulimit(option_maxfiles);
 		/* What user to run as */
 		} else if (!strcasecmp(v->name, "runuser")) {
 			ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
@@ -3647,7 +3496,20 @@ static void ast_readconfig(void)
 	if (!ast_opt_remote) {
 		pbx_live_dangerously(live_dangerously);
 	}
-
+	for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
+		float version;
+		if (sscanf(v->value, "%30f", &version) != 1) {
+			fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
+			continue;
+		}
+		if (!strcasecmp(v->name, "app_set")) {
+			ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
+		} else if (!strcasecmp(v->name, "res_agi")) {
+			ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
+		} else if (!strcasecmp(v->name, "pbx_realtime")) {
+			ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
+		}
+	}
 	ast_config_destroy(cfg);
 }
 
@@ -3780,6 +3642,7 @@ int main(int argc, char *argv[])
 	int c;
 	char filename[80] = "";
 	char hostname[MAXHOSTNAMELEN] = "";
+	char tmp[80];
 	char * xarg = NULL;
 	int x;
 	FILE *f;
@@ -3814,10 +3677,7 @@ int main(int argc, char *argv[])
 
 	if (getenv("HOME"))
 		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
-	/*! \brief Check for options
-	 *
-	 * \todo Document these options
-	 */
+	/* Check for options */
 	while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
 		/*!\note Please keep the ordering here to alphabetical, capital letters
 		 * first.  This will make it easier in the future to select unused
@@ -3874,13 +3734,13 @@ int main(int argc, char *argv[])
 			ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
 			break;
 		case 'L':
-			if ((sscanf(optarg, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
-				ast_option_maxload = 0.0;
+			if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
+				option_maxload = 0.0;
 			}
 			break;
 		case 'M':
-			if ((sscanf(optarg, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
-				ast_option_maxcalls = 0;
+			if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
+				option_maxcalls = 0;
 			}
 			break;
 		case 'm':
@@ -4271,7 +4131,6 @@ int main(int argc, char *argv[])
 			ast_el_read_history(filename);
 	}
 
-	ast_json_init();
 	ast_ulaw_init();
 	ast_alaw_init();
 	tdd_init();
@@ -4279,91 +4138,43 @@ int main(int argc, char *argv[])
 	ast_builtins_init();
 
 	if (ast_utils_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_utils_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_tps_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_tps_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_fd_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_fd_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_pbx_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_pbx_init\n%s", term_quit());
+		exit(1);
+	}
+
+	if (ast_event_init()) {
+		printf("Failed: ast_event_init\n%s", term_quit());
 		exit(1);
 	}
 
 #ifdef TEST_FRAMEWORK
 	if (ast_test_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_test_init\n%s", term_quit());
 		exit(1);
 	}
 #endif
 
 	if (ast_translate_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_translate_init\n%s", term_quit());
 		exit(1);
 	}
 
 	ast_aoc_cli_init();
-	ast_uuid_init();
-
-	if (ast_sorcery_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_codec_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_format_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_format_cache_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_codec_builtin_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-#ifdef AST_XML_DOCS
-	/* Load XML documentation. */
-	ast_xmldoc_load_documentation();
-#endif
-
-	aco_init();
-
-	if (ast_bucket_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (stasis_init()) {
-		printf("Stasis initialization failed.\n%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_stasis_system_init()) {
-		printf("Stasis system-level information initialization failed.\n%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_endpoint_stasis_init()) {
-		printf("Endpoint initialization failed.\n%s", term_quit());
-		exit(1);
-	}
 
 	ast_makesocket();
 	sigemptyset(&sigs);
@@ -4386,121 +4197,90 @@ int main(int argc, char *argv[])
 	initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
 
 	if (init_logger()) {		/* Start logging subsystem */
-		printf("%s", term_quit());
+		printf("Failed: init_logger\n%s", term_quit());
 		exit(1);
 	}
 
 	threadstorage_init();
 
-	if (ast_rtp_engine_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
+	ast_format_attr_init();
+	ast_format_list_init();
+	ast_rtp_engine_init();
 
 	ast_autoservice_init();
 
 	if (ast_timing_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_timing_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_ssl_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_ssl_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (app_init()) {
-		printf("App core initialization failed.\n%s", term_quit());
-		exit(1);
-	}
-
-	if (devstate_init()) {
-		printf("Device state core initialization failed.\n%s", term_quit());
-		exit(1);
-	}
+#ifdef AST_XML_DOCS
+	/* Load XML documentation. */
+	ast_xmldoc_load_documentation();
+#endif
 
 	if (astdb_init()) {
-		printf("%s", term_quit());
+		printf("Failed: astdb_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_msg_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_msg_init\n%s", term_quit());
 		exit(1);
 	}
 
 	/* initialize the data retrieval API */
 	if (ast_data_init()) {
-		printf ("%s", term_quit());
+		printf ("Failed: ast_data_init\n%s", term_quit());
 		exit(1);
 	}
 
 	ast_channels_init();
 
-	if (ast_endpoint_init()) {
-		printf ("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_pickup_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_bridging_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_parking_stasis_init()) {
-		printf("%s", term_quit());
-		exit(1);
+	if ((moduleresult = load_modules(1))) {		/* Load modules, pre-load only */
+		printf("Failed: load_modules(1)\n%s", term_quit());
+		exit(moduleresult == -2 ? 2 : 1);
 	}
 
-	if (ast_device_state_engine_init()) {
-		printf("%s", term_quit());
+	if (dnsmgr_init()) {		/* Initialize the DNS manager */
+		printf("Failed: dnsmgr_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_presence_state_engine_init()) {
-		printf("%s", term_quit());
+	if (ast_named_acl_init()) { /* Initialize the Named ACL system */
+		printf("Failed: ast_named_acl_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if ((moduleresult = load_modules(1))) {		/* Load modules, pre-load only */
-		printf("%s", term_quit());
-		exit(moduleresult == -2 ? 2 : 1);
-	}
-
-	if (ast_features_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
+	ast_http_init();		/* Start the HTTP server, if needed */
 
-	if (dnsmgr_init()) {		/* Initialize the DNS manager */
-		printf("%s", term_quit());
+	if (init_manager()) {
+		printf("Failed: init_manager\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_security_stasis_init()) {		/* Initialize Security Stasis Topic and Events */
-		printf("%s", term_quit());
+	if (ast_cdr_engine_init()) {
+		printf("Failed: ast_cdr_engine_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_named_acl_init()) { /* Initialize the Named ACL system */
-		printf("%s", term_quit());
+	if (ast_cel_engine_init()) {
+		printf("Failed: ast_cel_engine_init\n%s", term_quit());
 		exit(1);
 	}
 
-	ast_http_init();		/* Start the HTTP server, if needed */
-
-	if (ast_indications_init()) {
-		printf("%s", term_quit());
+	if (ast_device_state_engine_init()) {
+		printf("Failed: ast_device_state_engine_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_cdr_engine_init()) {
-		printf("%s", term_quit());
+	if (ast_presence_state_engine_init()) {
+		printf("Failed: ast_presence_state_engine_init\n%s", term_quit());
 		exit(1);
 	}
 
@@ -4508,52 +4288,47 @@ int main(int argc, char *argv[])
 	ast_udptl_init();
 
 	if (ast_image_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_image_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_file_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_file_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (load_pbx()) {
-		printf("%s", term_quit());
+		printf("Failed: load_pbx\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_local_init()) {
-		printf("%s", term_quit());
+	if (ast_indications_init()) {
+		printf("Failed: ast_indications_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (ast_cel_engine_init()) {
-		printf("%s", term_quit());
+	if (ast_features_init()) {
+		printf("Failed: ast_features_init\n%s", term_quit());
 		exit(1);
 	}
 
-	if (init_manager()) {
-		printf("%s", term_quit());
+	if (init_framer()) {
+		printf("Failed: init_framer\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_enum_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_enum_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if (ast_cc_init()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (ast_sounds_index_init()) {
-		printf("%s", term_quit());
+		printf("Failed: ast_cc_init\n%s", term_quit());
 		exit(1);
 	}
 
 	if ((moduleresult = load_modules(0))) {		/* Load modules */
-		printf("%s", term_quit());
+		printf("Failed: load_modules(0)\n%s", term_quit());
 		exit(moduleresult == -2 ? 2 : 1);
 	}
 
@@ -4564,6 +4339,9 @@ int main(int argc, char *argv[])
 
 	dnsmgr_start_refresh();
 
+	/* We might have the option of showing a console, but for now just
+	   do nothing... */
+	ast_verb(0, "%s\n", term_color(tmp, "Asterisk Ready.", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
 	if (ast_opt_no_fork) {
 		consolethread = pthread_self();
 	}
@@ -4573,7 +4351,12 @@ int main(int argc, char *argv[])
 	}
 
 	ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
-	publish_fully_booted();
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
 
 	ast_process_pending_reloads();
 
@@ -4586,11 +4369,11 @@ int main(int argc, char *argv[])
 	ast_lastreloadtime = ast_startuptime = ast_tvnow();
 	ast_cli_register_multiple(cli_asterisk_shutdown, ARRAY_LEN(cli_asterisk_shutdown));
 	ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
-	ast_register_atexit(main_atexit);
+	ast_register_cleanup(main_atexit);
 
 	run_startup_commands();
 
-	ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRGREEN, 0, "Asterisk Ready."));
+	logger_queue_start();
 
 	if (ast_opt_console) {
 		/* Console stuff now... */
diff --git a/main/asterisk.dynamics b/main/asterisk.dynamics
index 1c4b1b1..28f801b 100644
--- a/main/asterisk.dynamics
+++ b/main/asterisk.dynamics
@@ -1,7 +1,6 @@
 {
 	*ast_adsi_*;
 	*ast_agi_*;
-	*ast_beep_*;
 	*ast_pktccops_*;
 	*ast_smdi_*;
 	*ast_monitor_*;
diff --git a/main/asterisk.exports.in b/main/asterisk.exports.in
index 364b3b0..e521d10 100644
--- a/main/asterisk.exports.in
+++ b/main/asterisk.exports.in
@@ -1,8 +1,6 @@
 {
 	global:
 		LINKER_SYMBOL_PREFIXast_*;
-		LINKER_SYMBOL_PREFIXbridge_*;
-		LINKER_SYMBOL_PREFIXbridge_channel_*;
 		LINKER_SYMBOL_PREFIX_ast_*;
 		LINKER_SYMBOL_PREFIX__ast_*;
 		LINKER_SYMBOL_PREFIXpbx_*;
@@ -34,7 +32,6 @@
 		LINKER_SYMBOL_PREFIXdialed_interface_info;
 		LINKER_SYMBOL_PREFIXstrsep;
 		LINKER_SYMBOL_PREFIXsetenv;
-		LINKER_SYMBOL_PREFIXstasis_*;
 		LINKER_SYMBOL_PREFIXunsetenv;
 		LINKER_SYMBOL_PREFIXstrcasestr;
 		LINKER_SYMBOL_PREFIXstrnlen;
diff --git a/main/astfd.c b/main/astfd.c
index 577a5c7..35f9454 100644
--- a/main/astfd.c
+++ b/main/astfd.c
@@ -20,7 +20,7 @@
  *
  * \brief Debugging routines for file descriptor leaks
  *
- * \author Tilghman Lesher \verbatim <tlesher at digium.com> \endverbatim
+ * \author Tilghman Lesher <tlesher at digium.com>
  */
 
 /*** MODULEINFO
@@ -31,7 +31,7 @@
 
 #ifdef DEBUG_FD_LEAKS
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397110 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <string.h>
@@ -48,19 +48,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397110 $")
 #include "asterisk/unaligned.h"
 
 static struct fdleaks {
-	char file[40];
+	const char *callname;
 	int line;
+	unsigned int isopen:1;
+	char file[40];
 	char function[25];
-	char callname[10];
 	char callargs[60];
-	unsigned int isopen:1;
 } fdleaks[1024] = { { "", }, };
 
+/* COPY does ast_copy_string(dst, src, sizeof(dst)), except:
+ * - if it doesn't fit, it copies the value after the slash
+ *   (possibly truncated)
+ * - if there is no slash, it copies the value with the head
+ *   truncated */
 #define	COPY(dst, src)                                             \
 	do {                                                           \
 		int dlen = sizeof(dst), slen = strlen(src);                \
 		if (slen + 1 > dlen) {                                     \
-			char *slash = strrchr(src, '/');                       \
+			const char *slash = strrchr(src, '/');                 \
 			if (slash) {                                           \
 				ast_copy_string(dst, slash + 1, dlen);             \
 			} else {                                               \
@@ -72,12 +77,15 @@ static struct fdleaks {
 	} while (0)
 
 #define STORE_COMMON(offset, name, ...)     \
-	COPY(fdleaks[offset].file, file);       \
-	fdleaks[offset].line = line;            \
-	COPY(fdleaks[offset].function, func);   \
-	strcpy(fdleaks[offset].callname, name); \
-	snprintf(fdleaks[offset].callargs, sizeof(fdleaks[offset].callargs), __VA_ARGS__); \
-	fdleaks[offset].isopen = 1;
+	do { \
+		struct fdleaks *tmp = &fdleaks[offset]; \
+		COPY(tmp->file, file);      \
+		tmp->line = line;           \
+		COPY(tmp->function, func);  \
+		tmp->callname = name;       \
+		snprintf(tmp->callargs, sizeof(tmp->callargs), __VA_ARGS__); \
+		tmp->isopen = 1;            \
+	} while (0)
 
 #undef open
 int __ast_fdleak_open(const char *file, int line, const char *func, const char *path, int flags, ...)
@@ -91,7 +99,7 @@ int __ast_fdleak_open(const char *file, int line, const char *func, const char *
 		mode = va_arg(ap, int);
 		va_end(ap);
 		res = open(path, flags, mode);
-		if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
+		if (res > -1 && res < ARRAY_LEN(fdleaks)) {
 			char sflags[80];
 			snprintf(sflags, sizeof(sflags), "O_CREAT%s%s%s%s%s%s%s%s",
 				flags & O_APPEND ? "|O_APPEND" : "",
@@ -115,7 +123,7 @@ int __ast_fdleak_open(const char *file, int line, const char *func, const char *
 		}
 	} else {
 		res = open(path, flags);
-		if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
+		if (res > -1 && res < ARRAY_LEN(fdleaks)) {
 			STORE_COMMON(res, "open", "\"%s\",%d", path, flags);
 		}
 	}
@@ -130,7 +138,9 @@ int __ast_fdleak_pipe(int *fds, const char *file, int line, const char *func)
 		return res;
 	}
 	for (i = 0; i < 2; i++) {
-		STORE_COMMON(fds[i], "pipe", "{%d,%d}", fds[0], fds[1]);
+		if (fds[i] > -1 && fds[i] < ARRAY_LEN(fdleaks)) {
+			STORE_COMMON(fds[i], "pipe", "{%d,%d}", fds[0], fds[1]);
+		}
 	}
 	return 0;
 }
@@ -141,7 +151,7 @@ int __ast_fdleak_socket(int domain, int type, int protocol, const char *file, in
 	char sdomain[20], stype[20], *sproto = NULL;
 	struct protoent *pe;
 	int res = socket(domain, type, protocol);
-	if (res < 0 || res > 1023) {
+	if (res < 0 || res >= ARRAY_LEN(fdleaks)) {
 		return res;
 	}
 
@@ -183,7 +193,7 @@ int __ast_fdleak_socket(int domain, int type, int protocol, const char *file, in
 int __ast_fdleak_close(int fd)
 {
 	int res = close(fd);
-	if (!res && fd > -1 && fd < 1024) {
+	if (!res && fd > -1 && fd < ARRAY_LEN(fdleaks)) {
 		fdleaks[fd].isopen = 0;
 	}
 	return res;
@@ -198,7 +208,9 @@ FILE *__ast_fdleak_fopen(const char *path, const char *mode, const char *file, i
 		return res;
 	}
 	fd = fileno(res);
-	STORE_COMMON(fd, "fopen", "\"%s\",\"%s\"", path, mode);
+	if (fd > -1 && fd < ARRAY_LEN(fdleaks)) {
+		STORE_COMMON(fd, "fopen", "\"%s\",\"%s\"", path, mode);
+	}
 	return res;
 }
 
@@ -211,7 +223,7 @@ int __ast_fdleak_fclose(FILE *ptr)
 	}
 
 	fd = fileno(ptr);
-	if ((res = fclose(ptr)) || fd < 0 || fd > 1023) {
+	if ((res = fclose(ptr)) || fd < 0 || fd >= ARRAY_LEN(fdleaks)) {
 		return res;
 	}
 	fdleaks[fd].isopen = 0;
@@ -222,10 +234,13 @@ int __ast_fdleak_fclose(FILE *ptr)
 int __ast_fdleak_dup2(int oldfd, int newfd, const char *file, int line, const char *func)
 {
 	int res = dup2(oldfd, newfd);
-	if (res < 0 || res > 1023) {
+	if (res < 0 || res >= ARRAY_LEN(fdleaks)) {
 		return res;
 	}
-	STORE_COMMON(res, "dup2", "%d,%d", oldfd, newfd);
+	/* On success, newfd will be closed automatically if it was already
+	 * open. We don't need to mention anything about that, we're updating
+	 * the value anway. */
+	STORE_COMMON(res, "dup2", "%d,%d", oldfd, newfd); /* res == newfd */
 	return res;
 }
 
@@ -233,7 +248,7 @@ int __ast_fdleak_dup2(int oldfd, int newfd, const char *file, int line, const ch
 int __ast_fdleak_dup(int oldfd, const char *file, int line, const char *func)
 {
 	int res = dup(oldfd);
-	if (res < 0 || res > 1023) {
+	if (res < 0 || res >= ARRAY_LEN(fdleaks)) {
 		return res;
 	}
 	STORE_COMMON(res, "dup2", "%d", oldfd);
@@ -263,7 +278,7 @@ static char *handle_show_fd(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 		snprintf(line, sizeof(line), "%d/%d", (int) rl.rlim_cur, (int) rl.rlim_max);
 	}
 	ast_cli(a->fd, "Current maxfiles: %s\n", line);
-	for (i = 0; i < 1024; i++) {
+	for (i = 0; i < ARRAY_LEN(fdleaks); i++) {
 		if (fdleaks[i].isopen) {
 			snprintf(line, sizeof(line), "%d", fdleaks[i].line);
 			ast_cli(a->fd, "%5d %15s:%-7.7s (%-25s): %s(%s)\n", i, fdleaks[i].file, line, fdleaks[i].function, fdleaks[i].callname, fdleaks[i].callargs);
@@ -281,7 +296,7 @@ static void fd_shutdown(void)
 
 int ast_fd_init(void)
 {
-	ast_register_atexit(fd_shutdown);
+	ast_register_cleanup(fd_shutdown);
 	return ast_cli_register(&cli_show_fd);
 }
 
diff --git a/main/astmm.c b/main/astmm.c
index 262ab45..04feae4 100644
--- a/main/astmm.c
+++ b/main/astmm.c
@@ -32,7 +32,7 @@
 
 #if defined(__AST_DEBUG_MALLOC)
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398732 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_LOG_DIR */
 #include <stddef.h>
@@ -42,7 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398732 $")
 #include "asterisk/lock.h"
 #include "asterisk/strings.h"
 #include "asterisk/unaligned.h"
-#include "asterisk/backtrace.h"
 
 /*!
  * The larger the number the faster memory can be freed.
@@ -79,13 +78,13 @@ static FILE *mmlog;
 
 struct ast_region {
 	AST_LIST_ENTRY(ast_region) node;
-	struct ast_bt *bt;
 	size_t len;
 	unsigned int cache;		/* region was allocated as part of a cache pool */
 	unsigned int lineno;
 	enum func_type which;
 	char file[64];
 	char func[40];
+
 	/*!
 	 * \brief Lower guard fence.
 	 *
@@ -142,8 +141,6 @@ enum summary_opts {
 static enum summary_opts atexit_summary;
 /*! Nonzero if the unfreed regions are listed at exit. */
 static int atexit_list;
-/*! Nonzero if the memory allocation backtrace is enabled. */
-static int backtrace_enabled;
 
 #define HASH(a)		(((unsigned long)(a)) % ARRAY_LEN(regions))
 
@@ -185,24 +182,6 @@ void ast_free_ptr(void *ptr)
 	ast_free(ptr);
 }
 
-static void print_backtrace(struct ast_bt *bt)
-{
-	int i = 0;
-	char **strings;
-
-	if (!bt) {
-		return;
-	}
-
-	if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
-		astmm_log("Memory allocation backtrace:\n");
-		for (i = 3; i < bt->num_frames - 2; i++) {
-			astmm_log("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
-		}
-		ast_std_free(strings);
-	}
-}
-
 /*!
  * \internal
  *
@@ -237,7 +216,6 @@ static void *__ast_alloc_region(size_t size, const enum func_type which, const c
 	reg->cache = cache;
 	reg->lineno = lineno;
 	reg->which = which;
-	reg->bt = backtrace_enabled ? ast_bt_create() : NULL;
 	ast_copy_string(reg->file, file, sizeof(reg->file));
 	ast_copy_string(reg->func, func, sizeof(reg->func));
 
@@ -309,7 +287,6 @@ static void region_data_check(struct ast_region *reg)
 		if (*pos != FREED_MAGIC) {
 			astmm_log("WARNING: Memory corrupted after free of %p allocated at %s %s() line %d\n",
 				reg->data, reg->file, reg->func, reg->lineno);
-			print_backtrace(reg->bt);
 			my_do_crash();
 			break;
 		}
@@ -369,7 +346,6 @@ static void region_free(struct ast_freed_regions *freed, struct ast_region *reg)
 
 	if (old) {
 		region_data_check(old);
-		old->bt = ast_bt_destroy(old->bt);
 		free(old);
 	}
 }
@@ -429,14 +405,12 @@ static void region_check_fences(struct ast_region *reg)
 	if (*fence != FENCE_MAGIC) {
 		astmm_log("WARNING: Low fence violation of %p allocated at %s %s() line %d\n",
 			reg->data, reg->file, reg->func, reg->lineno);
-		print_backtrace(reg->bt);
 		my_do_crash();
 	}
 	fence = (unsigned int *) (reg->data + reg->len);
 	if (get_unaligned_uint32(fence) != FENCE_MAGIC) {
 		astmm_log("WARNING: High fence violation of %p allocated at %s %s() line %d\n",
 			reg->data, reg->file, reg->func, reg->lineno);
-		print_backtrace(reg->bt);
 		my_do_crash();
 	}
 }
@@ -977,49 +951,11 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
 	return CLI_SUCCESS;
 }
 
-static char *handle_memory_backtrace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "memory backtrace";
-		e->usage =
-			"Usage: memory backtrace {on|off}\n"
-			"       Enable dumping an allocation backtrace with memory diagnostics.\n"
-			"       Note that saving the backtrace data for each allocation\n"
-			"       can be CPU intensive.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			const char * const options[] = { "off", "on", NULL };
-
-			return ast_cli_complete(a->word, options, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (ast_true(a->argv[2])) {
-		backtrace_enabled = 1;
-	} else if (ast_false(a->argv[2])) {
-		backtrace_enabled = 0;
-	} else {
-		return CLI_SHOWUSAGE;
-	}
-
-	ast_cli(a->fd, "The memory backtrace is: %s\n", backtrace_enabled ? "On" : "Off");
-
-	return CLI_SUCCESS;
-}
-
 static struct ast_cli_entry cli_memory[] = {
 	AST_CLI_DEFINE(handle_memory_atexit_list, "Enable memory allocations not freed at exit list."),
 	AST_CLI_DEFINE(handle_memory_atexit_summary, "Enable memory allocations not freed at exit summary."),
 	AST_CLI_DEFINE(handle_memory_show_allocations, "Display outstanding memory allocations"),
 	AST_CLI_DEFINE(handle_memory_show_summary, "Summarize outstanding memory allocations"),
-	AST_CLI_DEFINE(handle_memory_backtrace, "Enable dumping an allocation backtrace with memory diagnostics."),
 };
 
 AST_LIST_HEAD_NOLOCK(region_list, ast_region);
@@ -1493,7 +1429,7 @@ void __ast_mm_init_phase_2(void)
 		ast_log(LOG_ERROR, "Could not open malloc debug log file: %s\n", filename);
 	}
 
-	ast_register_atexit(mm_atexit_ast);
+	ast_register_cleanup(mm_atexit_ast);
 }
 
 #endif	/* defined(__AST_DEBUG_MALLOC) */
diff --git a/main/astobj2.c b/main/astobj2.c
index 39b2a64..c434209 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -14,11 +14,8 @@
  * at the top of the source tree.
  */
 
-/*! \file
- *
- * \brief Functions implementing astobj2 objects.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
+/*
+ * Function implementing astobj2 objects.
  */
 
 /*** MODULEINFO
@@ -27,15 +24,23 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423418 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/astobj2.h"
-#include "astobj2_private.h"
-#include "astobj2_container_private.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/utils.h"
 #include "asterisk/cli.h"
 #include "asterisk/paths.h"
 
+/* Use ast_log_safe in place of ast_log. */
+#define ast_log ast_log_safe
+
+#if defined(TEST_FRAMEWORK)
+/* We are building with the test framework enabled so enable AO2 debug tests as well. */
+#define AO2_DEBUG 1
+#endif	/* defined(TEST_FRAMEWORK) */
+
 static FILE *ref_log;
 
 /*!
@@ -94,7 +99,37 @@ struct astobj2_rwlock {
 };
 
 #ifdef AO2_DEBUG
-struct ao2_stats ao2;
+struct ao2_stats {
+	volatile int total_objects;
+	volatile int total_mem;
+	volatile int total_containers;
+	volatile int total_refs;
+	volatile int total_locked;
+};
+
+static struct ao2_stats ao2;
+#endif
+
+#ifndef HAVE_BKTR	/* backtrace support */
+void ao2_bt(void) {}
+#else
+#include <execinfo.h>    /* for backtrace */
+
+void ao2_bt(void)
+{
+	int c, i;
+#define N1	20
+	void *addresses[N1];
+	char **strings;
+
+	c = backtrace(addresses, N1);
+	strings = ast_bt_get_symbols(addresses,c);
+	ast_verbose("backtrace returned: %d\n", c);
+	for(i = 0; i < c; i++) {
+		ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]);
+	}
+	ast_std_free(strings);
+}
 #endif
 
 #define INTERNAL_OBJ_MUTEX(user_data) \
@@ -108,7 +143,7 @@ struct ao2_stats ao2;
  *
  * \return the pointer to the astobj2 structure
  */
-static struct astobj2 *INTERNAL_OBJ(void *user_data)
+static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
 {
 	struct astobj2 *p;
 
@@ -134,6 +169,11 @@ static struct astobj2 *INTERNAL_OBJ(void *user_data)
 	return p;
 }
 
+enum ao2_callback_type {
+	DEFAULT,
+	WITH_DATA,
+};
+
 /*!
  * \brief convert from a pointer _p to an astobj2 object
  *
@@ -141,11 +181,6 @@ static struct astobj2 *INTERNAL_OBJ(void *user_data)
  */
 #define EXTERNAL_OBJ(_p)	((_p) == NULL ? NULL : (_p)->user_data)
 
-int is_ao2_object(void *user_data)
-{
-	return (INTERNAL_OBJ(user_data) != NULL);
-}
-
 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
 {
 	struct astobj2 *obj = INTERNAL_OBJ(user_data);
@@ -154,7 +189,6 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co
 	int res = 0;
 
 	if (obj == NULL) {
-		ast_assert(0);
 		return -1;
 	}
 
@@ -213,7 +247,6 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line,
 	int current_value;
 
 	if (obj == NULL) {
-		ast_assert(0);
 		return -1;
 	}
 
@@ -262,7 +295,6 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file,
 	int res = 0;
 
 	if (obj == NULL) {
-		ast_assert(0);
 		return -1;
 	}
 
@@ -330,7 +362,7 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file,
  *
  * \return Original lock level.
  */
-enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
+static enum ao2_lock_req adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
 {
 	struct astobj2 *obj = INTERNAL_OBJ(user_data);
 	struct astobj2_rwlock *obj_rwlock;
@@ -382,7 +414,6 @@ void *ao2_object_get_lockaddr(void *user_data)
 	struct astobj2_lock *obj_mutex;
 
 	if (obj == NULL) {
-		ast_assert(0);
 		return NULL;
 	}
 
@@ -406,7 +437,6 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
 	int ret;
 
 	if (obj == NULL) {
-		ast_assert(0);
 		return -1;
 	}
 
@@ -432,9 +462,6 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
 	if (current_value < 0) {
 		ast_log(__LOG_ERROR, file, line, func,
 			"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
-		ast_assert(0);
-		/* stop here even if assert doesn't DO_CRASH */
-		return -1;
 	}
 
 	/* last reference, destroy the object */
@@ -447,23 +474,38 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
 	ast_atomic_fetchadd_int(&ao2.total_objects, -1);
 #endif
 
-	/* In case someone uses an object after it's been freed */
-	obj->priv_data.magic = 0;
-
 	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
 	case AO2_ALLOC_OPT_LOCK_MUTEX:
 		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
 		ast_mutex_destroy(&obj_mutex->mutex.lock);
 
+		/*
+		 * For safety, zero-out the astobj2_lock header and also the
+		 * first word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj_mutex, '\0', sizeof(*obj_mutex) + sizeof(void *) );
 		ast_free(obj_mutex);
 		break;
 	case AO2_ALLOC_OPT_LOCK_RWLOCK:
 		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
 		ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
 
+		/*
+		 * For safety, zero-out the astobj2_rwlock header and also the
+		 * first word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj_rwlock, '\0', sizeof(*obj_rwlock) + sizeof(void *) );
 		ast_free(obj_rwlock);
 		break;
 	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+		/*
+		 * For safety, zero-out the astobj2 header and also the first
+		 * word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj, '\0', sizeof(*obj) + sizeof(void *) );
 		ast_free(obj);
 		break;
 	default:
@@ -501,10 +543,6 @@ int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *fil
 		}
 	}
 
-	if (obj == NULL) {
-		ast_assert(0);
-	}
-
 	return old_refcount;
 }
 
@@ -513,20 +551,6 @@ int __ao2_ref(void *user_data, int delta)
 	return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
 }
 
-void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
-{
-	if (obj) {
-		__ao2_ref_debug(obj, -1, tag, file, line, function);
-	}
-}
-
-void __ao2_cleanup(void *obj)
-{
-	if (obj) {
-		ao2_ref(obj, -1);
-	}
-}
-
 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func)
 {
 	/* allocation */
@@ -534,6 +558,14 @@ static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_f
 	struct astobj2_lock *obj_mutex;
 	struct astobj2_rwlock *obj_rwlock;
 
+	if (data_size < sizeof(void *)) {
+		/*
+		 * We always alloc at least the size of a void *,
+		 * for debugging purposes.
+		 */
+		data_size = sizeof(void *);
+	}
+
 	switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
 	case AO2_ALLOC_OPT_LOCK_MUTEX:
 #if defined(__AST_DEBUG_MALLOC)
@@ -594,15 +626,6 @@ static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_f
 	return EXTERNAL_OBJ(obj);
 }
 
-unsigned int ao2_options_get(void *obj)
-{
-	struct astobj2 *orig_obj = INTERNAL_OBJ(obj);
-	if (!orig_obj) {
-		return 0;
-	}
-	return orig_obj->priv_data.options;
-}
-
 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
 	const char *file, int line, const char *func, int ref_debug)
 {
@@ -633,12 +656,10 @@ void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, co
 	if (!holder) {
 		/* For sanity */
 		ast_log(LOG_ERROR, "Must be called with a global object!\n");
-		ast_assert(0);
 		return;
 	}
 	if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
 		/* Could not get the write lock. */
-		ast_assert(0);
 		return;
 	}
 
@@ -662,12 +683,10 @@ void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const c
 	if (!holder) {
 		/* For sanity */
 		ast_log(LOG_ERROR, "Must be called with a global object!\n");
-		ast_assert(0);
 		return NULL;
 	}
 	if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
 		/* Could not get the write lock. */
-		ast_assert(0);
 		return NULL;
 	}
 
@@ -709,13 +728,11 @@ void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const
 	if (!holder) {
 		/* For sanity */
 		ast_log(LOG_ERROR, "Must be called with a global object!\n");
-		ast_assert(0);
 		return NULL;
 	}
 
 	if (__ast_rwlock_rdlock(file, line, func, &holder->lock, name)) {
 		/* Could not get the read lock. */
-		ast_assert(0);
 		return NULL;
 	}
 
@@ -733,6 +750,831 @@ void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const
 	return obj;
 }
 
+/* internal callback to destroy a container. */
+static void container_destruct(void *c);
+
+/* internal callback to destroy a container. */
+static void container_destruct_debug(void *c);
+
+/*!
+ * A structure to create a linked list of entries,
+ * used within a bucket.
+ * XXX \todo this should be private to the container code
+ */
+struct bucket_entry {
+	AST_LIST_ENTRY(bucket_entry) entry;
+	int version;
+	struct astobj2 *astobj;/* pointer to internal data */
+};
+
+/* each bucket in the container is a tailq. */
+AST_LIST_HEAD_NOLOCK(bucket, bucket_entry);
+
+/*!
+ * A container; stores the hash and callback functions, information on
+ * the size, the hash bucket heads, and a version number, starting at 0
+ * (for a newly created, empty container)
+ * and incremented every time an object is inserted or deleted.
+ * The assumption is that an object is never moved in a container,
+ * but removed and readded with the new number.
+ * The version number is especially useful when implementing iterators.
+ * In fact, we can associate a unique, monotonically increasing number to
+ * each object, which means that, within an iterator, we can store the
+ * version number of the current object, and easily look for the next one,
+ * which is the next one in the list with a higher number.
+ * Since all objects have a version >0, we can use 0 as a marker for
+ * 'we need the first object in the bucket'.
+ *
+ * \todo Linking and unlink objects is typically expensive, as it
+ * involves a malloc() of a small object which is very inefficient.
+ * To optimize this, we allocate larger arrays of bucket_entry's
+ * when we run out of them, and then manage our own freelist.
+ * This will be more efficient as we can do the freelist management while
+ * we hold the lock (that we need anyways).
+ */
+struct ao2_container {
+	ao2_hash_fn *hash_fn;
+	ao2_callback_fn *cmp_fn;
+	int n_buckets;
+	/*! Number of elements in the container */
+	int elements;
+	/*! described above */
+	int version;
+	/*! variable size */
+	struct bucket buckets[0];
+};
+
+/*!
+ * \brief always zero hash function
+ *
+ * it is convenient to have a hash function that always returns 0.
+ * This is basically used when we want to have a container that is
+ * a simple linked list.
+ *
+ * \returns 0
+ */
+static int hash_zero(const void *user_obj, const int flags)
+{
+	return 0;
+}
+
+/*
+ * A container is just an object, after all!
+ */
+static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
+{
+	/* XXX maybe consistency check on arguments ? */
+	/* compute the container size */
+
+	if (!c) {
+		return NULL;
+	}
+
+	c->version = 1;	/* 0 is a reserved value here */
+	c->n_buckets = hash_fn ? n_buckets : 1;
+	c->hash_fn = hash_fn ? hash_fn : hash_zero;
+	c->cmp_fn = cmp_fn;
+
+#ifdef AO2_DEBUG
+	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
+#endif
+
+	return c;
+}
+
+struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
+	const char *tag, const char *file, int line, const char *func, int ref_debug)
+{
+	/* XXX maybe consistency check on arguments ? */
+	/* compute the container size */
+	unsigned int num_buckets = hash_fn ? n_buckets : 1;
+	size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
+	struct ao2_container *c = __ao2_alloc_debug(container_size, ref_debug ? container_destruct_debug : container_destruct, options, tag, file, line, func, ref_debug);
+
+	return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
+}
+
+struct ao2_container *__ao2_container_alloc(unsigned int options,
+	unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
+{
+	/* XXX maybe consistency check on arguments ? */
+	/* compute the container size */
+	const unsigned int num_buckets = hash_fn ? n_buckets : 1;
+	size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
+	struct ao2_container *c = __ao2_alloc(container_size, container_destruct, options);
+
+	return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
+}
+
+/*!
+ * return the number of elements in the container
+ */
+int ao2_container_count(struct ao2_container *c)
+{
+	return c->elements;
+}
+
+/*
+ * link an object to a container
+ */
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, int flags, const char *tag, const char *file, int line, const char *func)
+{
+	int i;
+	enum ao2_lock_req orig_lock;
+	/* create a new list entry */
+	struct bucket_entry *p;
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+	if (obj == NULL) {
+		return NULL;
+	}
+
+	if (INTERNAL_OBJ(c) == NULL) {
+		return NULL;
+	}
+
+	p = ast_calloc(1, sizeof(*p));
+	if (!p) {
+		return NULL;
+	}
+
+	i = abs(c->hash_fn(user_data, OBJ_POINTER) % c->n_buckets);
+
+	if (flags & OBJ_NOLOCK) {
+		orig_lock = adjust_lock(c, AO2_LOCK_REQ_WRLOCK, 1);
+	} else {
+		ao2_wrlock(c);
+		orig_lock = AO2_LOCK_REQ_MUTEX;
+	}
+
+	p->astobj = obj;
+	p->version = ast_atomic_fetchadd_int(&c->version, 1);
+	AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
+	ast_atomic_fetchadd_int(&c->elements, 1);
+
+	if (tag) {
+		__ao2_ref_debug(user_data, +1, tag, file, line, func);
+	} else {
+		__ao2_ref(user_data, +1);
+	}
+
+	if (flags & OBJ_NOLOCK) {
+		adjust_lock(c, orig_lock, 0);
+	} else {
+		ao2_unlock(c);
+	}
+
+	return p;
+}
+
+void *__ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
+{
+	return internal_ao2_link(c, obj_new, flags, tag, file, line, func);
+}
+
+void *__ao2_link(struct ao2_container *c, void *obj_new, int flags)
+{
+	return internal_ao2_link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+}
+
+/*!
+ * \brief another convenience function is a callback that matches on address
+ */
+int ao2_match_by_addr(void *user_data, void *arg, int flags)
+{
+	return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
+}
+
+/*
+ * Unlink an object from the container
+ * and destroy the associated * bucket_entry structure.
+ */
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
+	const char *tag, const char *file, int line, const char *func)
+{
+	if (INTERNAL_OBJ(user_data) == NULL) {	/* safety check on the argument */
+		return NULL;
+	}
+
+	flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+	__ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
+
+	return NULL;
+}
+
+void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
+{
+	if (INTERNAL_OBJ(user_data) == NULL) {	/* safety check on the argument */
+		return NULL;
+	}
+
+	flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+	__ao2_callback(c, flags, ao2_match_by_addr, user_data);
+
+	return NULL;
+}
+
+/*!
+ * \brief special callback that matches all
+ */
+static int cb_true(void *user_data, void *arg, int flags)
+{
+	return CMP_MATCH;
+}
+
+/*!
+ * \brief similar to cb_true, but is an ao2_callback_data_fn instead
+ */
+static int cb_true_data(void *user_data, void *arg, void *data, int flags)
+{
+	return CMP_MATCH;
+}
+
+/*!
+ * Browse the container using different stategies accoding the flags.
+ * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
+ * specified.
+ * Luckily, for debug purposes, the added args (tag, file, line, func)
+ * aren't an excessive load to the system, as the callback should not be
+ * called as often as, say, the ao2_ref func is called.
+ */
+static void *internal_ao2_callback(struct ao2_container *c, enum search_flags flags,
+	void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag,
+	const char *file, int line, const char *func)
+{
+	int i, start, last;	/* search boundaries */
+	enum ao2_lock_req orig_lock;
+	void *ret = NULL;
+	ao2_callback_fn *cb_default = NULL;
+	ao2_callback_data_fn *cb_withdata = NULL;
+	struct ao2_container *multi_container = NULL;
+	struct ao2_iterator *multi_iterator = NULL;
+
+	if (INTERNAL_OBJ(c) == NULL) {	/* safety check on the argument */
+		return NULL;
+	}
+
+	/*
+	 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
+	 * turned off.  This if statement checks for the special condition
+	 * where multiple items may need to be returned.
+	 */
+	if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
+		/* we need to return an ao2_iterator with the results,
+		 * as there could be more than one. the iterator will
+		 * hold the only reference to a container that has all the
+		 * matching objects linked into it, so when the iterator
+		 * is destroyed, the container will be automatically
+		 * destroyed as well.
+		 */
+		multi_container = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
+		if (!multi_container) {
+			return NULL;
+		}
+		if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
+			ao2_ref(multi_container, -1);
+			return NULL;
+		}
+	}
+
+	/* override the match function if necessary */
+	if (cb_fn == NULL) { /* if NULL, match everything */
+		if (type == WITH_DATA) {
+			cb_withdata = cb_true_data;
+		} else {
+			cb_default = cb_true;
+		}
+	} else {
+		/* We do this here to avoid the per object casting penalty (even though
+		   that is probably optimized away anyway). */
+		if (type == WITH_DATA) {
+			cb_withdata = cb_fn;
+		} else {
+			cb_default = cb_fn;
+		}
+	}
+
+	/*
+	 * XXX this can be optimized.
+	 * If we have a hash function and lookup by pointer,
+	 * run the hash function. Otherwise, scan the whole container
+	 * (this only for the time being. We need to optimize this.)
+	 */
+	if ((flags & (OBJ_POINTER | OBJ_KEY))) {
+		/* we know hash can handle this case */
+		start = i = abs(c->hash_fn(arg, flags & (OBJ_POINTER | OBJ_KEY)) % c->n_buckets);
+	} else {
+		/* don't know, let's scan all buckets */
+		start = i = -1;		/* XXX this must be fixed later. */
+	}
+
+	/* determine the search boundaries: i..last-1 */
+	if (i < 0) {
+		start = i = 0;
+		last = c->n_buckets;
+	} else if ((flags & OBJ_CONTINUE)) {
+		last = c->n_buckets;
+	} else {
+		last = i + 1;
+	}
+
+	/* avoid modifications to the content */
+	if (flags & OBJ_NOLOCK) {
+		if (flags & OBJ_UNLINK) {
+			orig_lock = adjust_lock(c, AO2_LOCK_REQ_WRLOCK, 1);
+		} else {
+			orig_lock = adjust_lock(c, AO2_LOCK_REQ_RDLOCK, 1);
+		}
+	} else {
+		orig_lock = AO2_LOCK_REQ_MUTEX;
+		if (flags & OBJ_UNLINK) {
+			ao2_wrlock(c);
+		} else {
+			ao2_rdlock(c);
+		}
+	}
+
+	for (; i < last ; i++) {
+		/* scan the list with prev-cur pointers */
+		struct bucket_entry *cur;
+
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
+			int match = (CMP_MATCH | CMP_STOP);
+
+			if (type == WITH_DATA) {
+				match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags);
+			} else {
+				match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags);
+			}
+
+			/* we found the object, performing operations according flags */
+			if (match == 0) {	/* no match, no stop, continue */
+				continue;
+			} else if (match == CMP_STOP) {	/* no match but stop, we are done */
+				i = last;
+				break;
+			}
+
+			/* we have a match (CMP_MATCH) here */
+			if (!(flags & OBJ_NODATA)) {	/* if must return the object, record the value */
+				/* it is important to handle this case before the unlink */
+				ret = EXTERNAL_OBJ(cur->astobj);
+				if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) {
+					if (tag) {
+						__ao2_ref_debug(ret, 1, tag, file, line, func);
+					} else {
+						__ao2_ref(ret, 1);
+					}
+				}
+			}
+
+			/* If we are in OBJ_MULTIPLE mode and OBJ_NODATA is off,
+			 * link the object into the container that will hold the results.
+			 */
+			if (ret && (multi_container != NULL)) {
+				if (tag) {
+					__ao2_link_debug(multi_container, ret, flags, tag, file, line, func);
+				} else {
+					__ao2_link(multi_container, ret, flags);
+				}
+				ret = NULL;
+			}
+
+			if (flags & OBJ_UNLINK) {	/* must unlink */
+				/* we are going to modify the container, so update version */
+				ast_atomic_fetchadd_int(&c->version, 1);
+				AST_LIST_REMOVE_CURRENT(entry);
+				/* update number of elements */
+				ast_atomic_fetchadd_int(&c->elements, -1);
+
+				/* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container
+				 * must be decremented.
+				 * - When unlinking with OBJ_MULTIPLE the ref from the original container
+				 * must be decremented regardless if OBJ_NODATA is used. This is because the result is
+				 * returned in a new container that already holds its own ref for the object. If the ref
+				 * from the original container is not accounted for here a memory leak occurs. */
+				if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) {
+					if (tag)
+						__ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, func);
+					else
+						__ao2_ref(EXTERNAL_OBJ(cur->astobj), -1);
+				}
+				ast_free(cur);	/* free the link record */
+			}
+
+			if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
+				/* We found our only (or last) match, so force an exit from
+				   the outside loop. */
+				i = last;
+				break;
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END;
+
+		if (ret) {
+			break;
+		}
+
+		if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
+			/* Move to the beginning to ensure we check every bucket */
+			i = -1;
+			last = start;
+		}
+	}
+
+	if (flags & OBJ_NOLOCK) {
+		adjust_lock(c, orig_lock, 0);
+	} else {
+		ao2_unlock(c);
+	}
+
+	/* if multi_container was created, we are returning multiple objects */
+	if (multi_container != NULL) {
+		*multi_iterator = ao2_iterator_init(multi_container,
+			AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD);
+		ao2_ref(multi_container, -1);
+		return multi_iterator;
+	} else {
+		return ret;
+	}
+}
+
+void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
+	const char *func)
+{
+	return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, func);
+}
+
+void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_fn *cb_fn, void *arg)
+{
+	return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
+}
+
+void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
+	int line, const char *func)
+{
+	return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, func);
+}
+
+void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_data_fn *cb_fn, void *arg, void *data)
+{
+	return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
+}
+
+/*!
+ * the find function just invokes the default callback with some reasonable flags.
+ */
+void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
+	const char *tag, const char *file, int line, const char *func)
+{
+	void *arged = (void *) arg;/* Done to avoid compiler const warning */
+
+	return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, func);
+}
+
+void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags)
+{
+	void *arged = (void *) arg;/* Done to avoid compiler const warning */
+
+	return __ao2_callback(c, flags, c->cmp_fn, arged);
+}
+
+/*!
+ * initialize an iterator so we start from the first object
+ */
+struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
+{
+	struct ao2_iterator a = {
+		.c = c,
+		.flags = flags
+	};
+
+	ao2_ref(c, +1);
+
+	return a;
+}
+
+/*!
+ * destroy an iterator
+ */
+void ao2_iterator_destroy(struct ao2_iterator *iter)
+{
+	ao2_ref(iter->c, -1);
+	if (iter->flags & AO2_ITERATOR_MALLOCD) {
+		ast_free(iter);
+	} else {
+		iter->c = NULL;
+	}
+}
+
+/*
+ * move to the next element in the container.
+ */
+static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
+{
+	int lim;
+	enum ao2_lock_req orig_lock;
+	struct bucket_entry *p = NULL;
+	void *ret;
+
+	if (INTERNAL_OBJ(iter->c) == NULL) {
+		return NULL;
+	}
+
+	if (iter->flags & AO2_ITERATOR_DONTLOCK) {
+		if (iter->flags & AO2_ITERATOR_UNLINK) {
+			orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_WRLOCK, 1);
+		} else {
+			orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
+		}
+	} else {
+		orig_lock = AO2_LOCK_REQ_MUTEX;
+		if (iter->flags & AO2_ITERATOR_UNLINK) {
+			ao2_wrlock(iter->c);
+		} else {
+			ao2_rdlock(iter->c);
+		}
+	}
+
+	/* optimization. If the container is unchanged and
+	 * we have a pointer, try follow it
+	 */
+	if (iter->c->version == iter->c_version && (p = iter->obj)) {
+		if ((p = AST_LIST_NEXT(p, entry))) {
+			goto found;
+		}
+		/* nope, start from the next bucket */
+		iter->bucket++;
+		iter->version = 0;
+		iter->obj = NULL;
+	}
+
+	lim = iter->c->n_buckets;
+
+	/* Browse the buckets array, moving to the next
+	 * buckets if we don't find the entry in the current one.
+	 * Stop when we find an element with version number greater
+	 * than the current one (we reset the version to 0 when we
+	 * switch buckets).
+	 */
+	for (; iter->bucket < lim; iter->bucket++, iter->version = 0) {
+		/* scan the current bucket */
+		AST_LIST_TRAVERSE(&iter->c->buckets[iter->bucket], p, entry) {
+			if (p->version > iter->version) {
+				goto found;
+			}
+		}
+	}
+
+found:
+	if (p) {
+		ret = EXTERNAL_OBJ(p->astobj);
+		if (iter->flags & AO2_ITERATOR_UNLINK) {
+			/* we are going to modify the container, so update version */
+			ast_atomic_fetchadd_int(&iter->c->version, 1);
+			AST_LIST_REMOVE(&iter->c->buckets[iter->bucket], p, entry);
+			/* update number of elements */
+			ast_atomic_fetchadd_int(&iter->c->elements, -1);
+			iter->version = 0;
+			iter->obj = NULL;
+			iter->c_version = iter->c->version;
+			ast_free(p);
+		} else {
+			iter->version = p->version;
+			iter->obj = p;
+			iter->c_version = iter->c->version;
+
+			/* inc refcount of returned object */
+			if (tag) {
+				__ao2_ref_debug(ret, 1, tag, file, line, func);
+			} else {
+				__ao2_ref(ret, 1);
+			}
+		}
+	} else {
+		ret = NULL;
+	}
+
+	if (iter->flags & AO2_ITERATOR_DONTLOCK) {
+		adjust_lock(iter->c, orig_lock, 0);
+	} else {
+		ao2_unlock(iter->c);
+	}
+
+	return ret;
+}
+
+void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
+{
+	return internal_ao2_iterator_next(iter, tag, file, line, func);
+}
+
+void *__ao2_iterator_next(struct ao2_iterator *iter)
+{
+	return internal_ao2_iterator_next(iter, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+}
+
+/* callback for destroying container.
+ * we can make it simple as we know what it does
+ */
+static int cd_cb(void *obj, void *arg, int flag)
+{
+	__ao2_ref(obj, -1);
+	return 0;
+}
+
+static int cd_cb_debug(void *obj, void *arg, int flag)
+{
+	__ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	return 0;
+}
+
+static void container_destruct(void *_c)
+{
+	struct ao2_container *c = _c;
+	int i;
+
+	__ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
+
+	for (i = 0; i < c->n_buckets; i++) {
+		struct bucket_entry *current;
+
+		while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
+			ast_free(current);
+		}
+	}
+
+#ifdef AO2_DEBUG
+	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
+#endif
+}
+
+static void container_destruct_debug(void *_c)
+{
+	struct ao2_container *c = _c;
+	int i;
+
+	__ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+	for (i = 0; i < c->n_buckets; i++) {
+		struct bucket_entry *current;
+
+		while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
+			ast_free(current);
+		}
+	}
+
+#ifdef AO2_DEBUG
+	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
+#endif
+}
+
+/*!
+ * \internal
+ * \brief Put obj into the arg container.
+ * \since 11.0
+ *
+ * \param obj  pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \retval 0 on success.
+ * \retval CMP_STOP|CMP_MATCH on error.
+ */
+static int dup_obj_cb(void *obj, void *arg, int flags)
+{
+	struct ao2_container *dest = arg;
+
+	return __ao2_link(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
+{
+	void *obj;
+	int res = 0;
+
+	if (!(flags & OBJ_NOLOCK)) {
+		ao2_rdlock(src);
+		ao2_wrlock(dest);
+	}
+	obj = __ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
+	if (obj) {
+		/* Failed to put this obj into the dest container. */
+		__ao2_ref(obj, -1);
+
+		/* Remove all items from the dest container. */
+		__ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
+			NULL);
+		res = -1;
+	}
+	if (!(flags & OBJ_NOLOCK)) {
+		ao2_unlock(dest);
+		ao2_unlock(src);
+	}
+
+	return res;
+}
+
+struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags)
+{
+	struct ao2_container *clone;
+	struct astobj2 *orig_obj;
+	unsigned int options;
+	int failed;
+
+	orig_obj = INTERNAL_OBJ(orig);
+	if (!orig_obj) {
+		return NULL;
+	}
+	options = orig_obj->priv_data.options;
+
+	/* Create the clone container with the same properties as the original. */
+	clone = __ao2_container_alloc(options, orig->n_buckets, orig->hash_fn, orig->cmp_fn);
+	if (!clone) {
+		return NULL;
+	}
+
+	if (flags & OBJ_NOLOCK) {
+		ao2_wrlock(clone);
+	}
+	failed = ao2_container_dup(clone, orig, flags);
+	if (flags & OBJ_NOLOCK) {
+		ao2_unlock(clone);
+	}
+	if (failed) {
+		/* Object copy into the clone container failed. */
+		__ao2_ref(clone, -1);
+		clone = NULL;
+	}
+	return clone;
+}
+
+struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug)
+{
+	struct ao2_container *clone;
+	struct astobj2 *orig_obj;
+	unsigned int options;
+	int failed;
+
+	orig_obj = INTERNAL_OBJ(orig);
+	if (!orig_obj) {
+		return NULL;
+	}
+	options = orig_obj->priv_data.options;
+
+	/* Create the clone container with the same properties as the original. */
+	clone = __ao2_container_alloc_debug(options, orig->n_buckets, orig->hash_fn,
+		orig->cmp_fn, tag, file, line, func, ref_debug);
+	if (!clone) {
+		return NULL;
+	}
+
+	if (flags & OBJ_NOLOCK) {
+		ao2_wrlock(clone);
+	}
+	failed = ao2_container_dup(clone, orig, flags);
+	if (flags & OBJ_NOLOCK) {
+		ao2_unlock(clone);
+	}
+	if (failed) {
+		/* Object copy into the clone container failed. */
+		if (ref_debug) {
+			__ao2_ref_debug(clone, -1, tag, file, line, func);
+		} else {
+			__ao2_ref(clone, -1);
+		}
+		clone = NULL;
+	}
+	return clone;
+}
+
+void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *function)
+{
+	if (obj) {
+		__ao2_ref_debug(obj, -1, "ao2_cleanup", file, line, function);
+	}
+}
+
+void __ao2_cleanup(void *obj)
+{
+	if (obj) {
+		ao2_ref(obj, -1);
+	}
+}
+
+void ao2_iterator_cleanup(struct ao2_iterator *iter)
+{
+	if (iter) {
+		ao2_iterator_destroy(iter);
+	}
+}
+
 #ifdef AO2_DEBUG
 static int print_cb(void *obj, void *arg, int flag)
 {
@@ -782,7 +1624,7 @@ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cl
 		e->command = "astobj2 test";
 		e->usage = "Usage: astobj2 test <num>\n"
 			   "       Runs astobj2 test. Creates 'num' objects,\n"
-			   "       and test iterators, callbacks and maybe other stuff\n";
+			   "       and test iterators, callbacks and may be other stuff\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
@@ -792,9 +1634,8 @@ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cl
 		return CLI_SHOWUSAGE;
 	}
 
-	if (prof_id == -1) {
+	if (prof_id == -1)
 		prof_id = ast_add_profile("ao2_alloc", 0);
-	}
 
 	ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
 	lim = atoi(a->argv[2]);
@@ -802,10 +1643,10 @@ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cl
 
 	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
 	/*
-	 * Allocate a list container.
+	 * allocate a container with no default callback, and no hash function.
+	 * No hash means everything goes in the same bucket.
 	 */
-	c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
-		NULL /* no callback */, "test");
+	c1 = ao2_t_container_alloc(100, NULL /* no callback */, NULL /* no hash */,"test");
 	ast_cli(a->fd, "container allocated as %p\n", c1);
 
 	/*
@@ -863,7 +1704,7 @@ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cl
 	ast_cli(a->fd, "testing callbacks again\n");
 	ao2_t_callback(c1, 0, print_cb, a, "test callback");
 
-	ast_verbose("now you should see an error and possible assertion failure messages:\n");
+	ast_verbose("now you should see an error message:\n");
 	ao2_t_ref(&i, -1, "");	/* i is not a valid object so we print an error here */
 
 	ast_cli(a->fd, "destroy container\n");
@@ -872,9 +1713,7 @@ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cl
 	handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
 	return CLI_SUCCESS;
 }
-#endif /* AO2_DEBUG */
 
-#if defined(AO2_DEBUG)
 static struct ast_cli_entry cli_astobj2[] = {
 	AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
 	AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
@@ -883,9 +1722,10 @@ static struct ast_cli_entry cli_astobj2[] = {
 
 static void astobj2_cleanup(void)
 {
-#if defined(AO2_DEBUG)
+#ifdef AO2_DEBUG
 	ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
 #endif
+
 #ifdef REF_DEBUG
 	fclose(ref_log);
 	ref_log = NULL;
@@ -898,10 +1738,6 @@ int astobj2_init(void)
 	char ref_filename[1024];
 #endif
 
-	if (container_init() != 0) {
-		return -1;
-	}
-
 #ifdef REF_DEBUG
 	snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
 	ref_log = fopen(ref_filename, "w");
@@ -910,11 +1746,11 @@ int astobj2_init(void)
 	}
 #endif
 
-#if defined(AO2_DEBUG)
+#ifdef AO2_DEBUG
 	ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
-#endif	/* defined(AO2_DEBUG) */
+#endif
 
-	ast_register_atexit(astobj2_cleanup);
+	ast_register_cleanup(astobj2_cleanup);
 
 	return 0;
 }
diff --git a/main/astobj2_container.c b/main/astobj2_container.c
deleted file mode 100644
index 918d1e0..0000000
--- a/main/astobj2_container.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/* astobj2 - replacement containers for asterisk data structures.
- *
- * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Functions implementing astobj2 objects.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417213 $")
-
-#include "asterisk/_private.h"
-#include "asterisk/astobj2.h"
-#include "astobj2_private.h"
-#include "astobj2_container_private.h"
-#include "asterisk/cli.h"
-
-/*!
- * return the number of elements in the container
- */
-int ao2_container_count(struct ao2_container *c)
-{
-	return ast_atomic_fetchadd_int(&c->elements, 0);
-}
-
-int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags,
-	const char *tag, const char *file, int line, const char *func)
-{
-	struct ao2_container *container = node->my_container;
-
-	if (container == NULL && (flags & AO2_UNLINK_NODE_DEC_COUNT)) {
-		return 0;
-	}
-
-	if ((flags & AO2_UNLINK_NODE_UNLINK_OBJECT)
-		&& !(flags & AO2_UNLINK_NODE_NOUNREF_OBJECT)) {
-		if (tag) {
-			__ao2_ref_debug(node->obj, -1, tag, file, line, func);
-		} else {
-			ao2_t_ref(node->obj, -1, "Remove obj from container");
-		}
-	}
-
-	node->obj = NULL;
-
-	if (flags & AO2_UNLINK_NODE_DEC_COUNT) {
-		ast_atomic_fetchadd_int(&container->elements, -1);
-#if defined(AO2_DEBUG)
-		{
-			int empty = container->nodes - container->elements;
-
-			if (container->max_empty_nodes < empty) {
-				container->max_empty_nodes = empty;
-			}
-			if (container->v_table->unlink_stat) {
-				container->v_table->unlink_stat(container, node);
-			}
-		}
-#endif	/* defined(AO2_DEBUG) */
-	}
-
-	if (flags & AO2_UNLINK_NODE_UNREF_NODE) {
-		/* Remove node from container */
-		__ao2_ref(node, -1);
-	}
-
-	return 1;
-}
-
-/*!
- * \internal
- * \brief Link an object into this container.  (internal)
- *
- * \param self Container to operate upon.
- * \param obj_new Object to insert into the container.
- * \param flags search_flags to control linking the object.  (OBJ_NOLOCK)
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- *
- * \retval 0 on errors.
- * \retval 1 on success.
- */
-static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
-{
-	int res;
-	enum ao2_lock_req orig_lock;
-	struct ao2_container_node *node;
-
-	if (!is_ao2_object(obj_new) || !is_ao2_object(self)
-		|| !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return 0;
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		orig_lock = __adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
-	} else {
-		ao2_wrlock(self);
-		orig_lock = AO2_LOCK_REQ_MUTEX;
-	}
-
-	res = 0;
-	node = self->v_table->new_node(self, obj_new, tag, file, line, func);
-	if (node) {
-#if defined(AO2_DEBUG)
-		if (ao2_container_check(self, OBJ_NOLOCK)) {
-			ast_log(LOG_ERROR, "Container integrity failed before insert.\n");
-		}
-#endif	/* defined(AO2_DEBUG) */
-
-		/* Insert the new node. */
-		switch (self->v_table->insert(self, node)) {
-		case AO2_CONTAINER_INSERT_NODE_INSERTED:
-			node->is_linked = 1;
-			ast_atomic_fetchadd_int(&self->elements, 1);
-#if defined(AO2_DEBUG)
-			AO2_DEVMODE_STAT(++self->nodes);
-			if (self->v_table->link_stat) {
-				self->v_table->link_stat(self, node);
-			}
-#endif	/* defined(AO2_DEBUG) */
-			/* Fall through */
-		case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
-#if defined(AO2_DEBUG)
-			if (ao2_container_check(self, OBJ_NOLOCK)) {
-				ast_log(LOG_ERROR, "Container integrity failed after insert or replace.\n");
-			}
-#endif	/* defined(AO2_DEBUG) */
-			res = 1;
-			break;
-		case AO2_CONTAINER_INSERT_NODE_REJECTED:
-			__ao2_ref(node, -1);
-			break;
-		}
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		__adjust_lock(self, orig_lock, 0);
-	} else {
-		ao2_unlock(self);
-	}
-
-	return res;
-}
-
-int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
-{
-	return internal_ao2_link(c, obj_new, flags, tag, file, line, func);
-}
-
-int __ao2_link(struct ao2_container *c, void *obj_new, int flags)
-{
-	return internal_ao2_link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
-}
-
-/*!
- * \brief another convenience function is a callback that matches on address
- */
-int ao2_match_by_addr(void *user_data, void *arg, int flags)
-{
-	return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
-}
-
-/*
- * Unlink an object from the container
- * and destroy the associated * bucket_entry structure.
- */
-void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
-	const char *tag, const char *file, int line, const char *func)
-{
-	if (!is_ao2_object(user_data)) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-
-	flags &= ~OBJ_SEARCH_MASK;
-	flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
-	__ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
-
-	return NULL;
-}
-
-void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
-{
-	if (!is_ao2_object(user_data)) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-
-	flags &= ~OBJ_SEARCH_MASK;
-	flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
-	__ao2_callback(c, flags, ao2_match_by_addr, user_data);
-
-	return NULL;
-}
-
-/*!
- * \brief special callback that matches all
- */
-static int cb_true(void *user_data, void *arg, int flags)
-{
-	return CMP_MATCH;
-}
-
-/*!
- * \brief similar to cb_true, but is an ao2_callback_data_fn instead
- */
-static int cb_true_data(void *user_data, void *arg, void *data, int flags)
-{
-	return CMP_MATCH;
-}
-
-/*!
- * \internal
- * \brief Traverse the container.  (internal)
- *
- * \param self Container to operate upon.
- * \param flags search_flags to control traversing the container
- * \param cb_fn Comparison callback function.
- * \param arg Comparison callback arg parameter.
- * \param data Data comparison callback data parameter.
- * \param type Type of comparison callback cb_fn.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- *
- * \retval NULL on failure or no matching object found.
- *
- * \retval object found if OBJ_MULTIPLE is not set in the flags
- * parameter.
- *
- * \retval ao2_iterator pointer if OBJ_MULTIPLE is set in the
- * flags parameter.  The iterator must be destroyed with
- * ao2_iterator_destroy() when the caller no longer needs it.
- */
-static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags flags,
-	void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
-	const char *tag, const char *file, int line, const char *func)
-{
-	void *ret;
-	ao2_callback_fn *cb_default = NULL;
-	ao2_callback_data_fn *cb_withdata = NULL;
-	struct ao2_container_node *node;
-	void *traversal_state;
-
-	enum ao2_lock_req orig_lock;
-	struct ao2_container *multi_container = NULL;
-	struct ao2_iterator *multi_iterator = NULL;
-
-	if (!is_ao2_object(self) || !self->v_table || !self->v_table->traverse_first
-		|| !self->v_table->traverse_next) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-
-	/*
-	 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
-	 * turned off.  This if statement checks for the special condition
-	 * where multiple items may need to be returned.
-	 */
-	if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
-		/* we need to return an ao2_iterator with the results,
-		 * as there could be more than one. the iterator will
-		 * hold the only reference to a container that has all the
-		 * matching objects linked into it, so when the iterator
-		 * is destroyed, the container will be automatically
-		 * destroyed as well.
-		 */
-		multi_container = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL,
-			NULL, "OBJ_MULTIPLE return container creation");
-		if (!multi_container) {
-			return NULL;
-		}
-		if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
-			ao2_t_ref(multi_container, -1, "OBJ_MULTIPLE interator creation failed.");
-			return NULL;
-		}
-	}
-
-	if (!cb_fn) {
-		/* Match everything if no callback match function provided. */
-		if (type == AO2_CALLBACK_WITH_DATA) {
-			cb_withdata = cb_true_data;
-		} else {
-			cb_default = cb_true;
-		}
-	} else {
-		/*
-		 * We do this here to avoid the per object casting penalty (even
-		 * though that is probably optimized away anyway).
-		 */
-		if (type == AO2_CALLBACK_WITH_DATA) {
-			cb_withdata = cb_fn;
-		} else {
-			cb_default = cb_fn;
-		}
-	}
-
-	/* avoid modifications to the content */
-	if (flags & OBJ_NOLOCK) {
-		if (flags & OBJ_UNLINK) {
-			orig_lock = __adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
-		} else {
-			orig_lock = __adjust_lock(self, AO2_LOCK_REQ_RDLOCK, 1);
-		}
-	} else {
-		orig_lock = AO2_LOCK_REQ_MUTEX;
-		if (flags & OBJ_UNLINK) {
-			ao2_wrlock(self);
-		} else {
-			ao2_rdlock(self);
-		}
-	}
-
-	/* Create a buffer for the traversal state. */
-	traversal_state = alloca(AO2_TRAVERSAL_STATE_SIZE);
-
-	ret = NULL;
-	for (node = self->v_table->traverse_first(self, flags, arg, traversal_state);
-		node;
-		node = self->v_table->traverse_next(self, traversal_state, node)) {
-		int match;
-
-		/* Visit the current node. */
-		match = (CMP_MATCH | CMP_STOP);
-		if (type == AO2_CALLBACK_WITH_DATA) {
-			match &= cb_withdata(node->obj, arg, data, flags);
-		} else {
-			match &= cb_default(node->obj, arg, flags);
-		}
-		if (match == 0) {
-			/* no match, no stop, continue */
-			continue;
-		}
-		if (match == CMP_STOP) {
-			/* no match but stop, we are done */
-			break;
-		}
-
-		/*
-		 * CMP_MATCH is set here
-		 *
-		 * we found the object, performing operations according to flags
-		 */
-		if (node->obj) {
-			/* The object is still in the container. */
-			if (!(flags & OBJ_NODATA)) {
-				/*
-				 * We are returning the object, record the value.  It is
-				 * important to handle this case before the unlink.
-				 */
-				if (multi_container) {
-					/*
-					 * Link the object into the container that will hold the
-					 * results.
-					 */
-					if (tag) {
-						__ao2_link_debug(multi_container, node->obj, flags,
-							tag, file, line, func);
-					} else {
-						__ao2_link(multi_container, node->obj, flags);
-					}
-				} else {
-					ret = node->obj;
-					/* Returning a single object. */
-					if (!(flags & OBJ_UNLINK)) {
-						/*
-						 * Bump the ref count since we are not going to unlink and
-						 * transfer the container's object ref to the returned object.
-						 */
-						if (tag) {
-							__ao2_ref_debug(ret, 1, tag, file, line, func);
-						} else {
-							ao2_t_ref(ret, 1, "Traversal found object");
-						}
-					}
-				}
-			}
-
-			if (flags & OBJ_UNLINK) {
-				int ulflag = AO2_UNLINK_NODE_UNREF_NODE | AO2_UNLINK_NODE_DEC_COUNT;
-				if (multi_container || (flags & OBJ_NODATA)) {
-					ulflag |= AO2_UNLINK_NODE_UNLINK_OBJECT;
-				}
-				__container_unlink_node_debug(node, ulflag, tag, file, line, func);
-			}
-		}
-
-		if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
-			/* We found our only (or last) match, so we are done */
-			break;
-		}
-	}
-	if (self->v_table->traverse_cleanup) {
-		self->v_table->traverse_cleanup(traversal_state);
-	}
-	if (node) {
-		/* Unref the node from self->v_table->traverse_first/traverse_next() */
-		__ao2_ref(node, -1);
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		__adjust_lock(self, orig_lock, 0);
-	} else {
-		ao2_unlock(self);
-	}
-
-	/* if multi_container was created, we are returning multiple objects */
-	if (multi_container) {
-		*multi_iterator = ao2_iterator_init(multi_container,
-			AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD);
-		ao2_t_ref(multi_container, -1,
-			"OBJ_MULTIPLE for multiple objects traversal complete.");
-		return multi_iterator;
-	} else {
-		return ret;
-	}
-}
-
-void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
-	const char *func)
-{
-	return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, file, line, func);
-}
-
-void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_fn *cb_fn, void *arg)
-{
-	return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, NULL, NULL, 0, NULL);
-}
-
-void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
-	int line, const char *func)
-{
-	return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, file, line, func);
-}
-
-void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_data_fn *cb_fn, void *arg, void *data)
-{
-	return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, NULL, NULL, 0, NULL);
-}
-
-/*!
- * the find function just invokes the default callback with some reasonable flags.
- */
-void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
-	const char *tag, const char *file, int line, const char *func)
-{
-	void *arged = (void *) arg;/* Done to avoid compiler const warning */
-
-	if (!c) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-	return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, func);
-}
-
-void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags)
-{
-	void *arged = (void *) arg;/* Done to avoid compiler const warning */
-
-	if (!c) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-	return __ao2_callback(c, flags, c->cmp_fn, arged);
-}
-
-/*!
- * initialize an iterator so we start from the first object
- */
-struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
-{
-	struct ao2_iterator a = {
-		.c = c,
-		.flags = flags
-	};
-
-	ao2_t_ref(c, +1, "Init iterator with container.");
-
-	return a;
-}
-
-void ao2_iterator_restart(struct ao2_iterator *iter)
-{
-	/* Release the last container node reference if we have one. */
-	if (iter->last_node) {
-		enum ao2_lock_req orig_lock;
-
-		/*
-		 * Do a read lock in case the container node unref does not
-		 * destroy the node.  If the container node is destroyed then
-		 * the lock will be upgraded to a write lock.
-		 */
-		if (iter->flags & AO2_ITERATOR_DONTLOCK) {
-			orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
-		} else {
-			orig_lock = AO2_LOCK_REQ_MUTEX;
-			ao2_rdlock(iter->c);
-		}
-
-		__ao2_ref(iter->last_node, -1);
-		iter->last_node = NULL;
-
-		if (iter->flags & AO2_ITERATOR_DONTLOCK) {
-			__adjust_lock(iter->c, orig_lock, 0);
-		} else {
-			ao2_unlock(iter->c);
-		}
-	}
-
-	/* The iteration is no longer complete. */
-	iter->complete = 0;
-}
-
-void ao2_iterator_destroy(struct ao2_iterator *iter)
-{
-	/* Release any last container node reference. */
-	ao2_iterator_restart(iter);
-
-	/* Release the iterated container reference. */
-	ao2_t_ref(iter->c, -1, "Unref iterator in ao2_iterator_destroy");
-	iter->c = NULL;
-
-	/* Free the malloced iterator. */
-	if (iter->flags & AO2_ITERATOR_MALLOCD) {
-		ast_free(iter);
-	}
-}
-
-void ao2_iterator_cleanup(struct ao2_iterator *iter)
-{
-	if (iter) {
-		ao2_iterator_destroy(iter);
-	}
-}
-
-/*
- * move to the next element in the container.
- */
-static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
-{
-	enum ao2_lock_req orig_lock;
-	struct ao2_container_node *node;
-	void *ret;
-
-	if (!is_ao2_object(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-
-	if (iter->complete) {
-		/* Don't return any more objects. */
-		return NULL;
-	}
-
-	if (iter->flags & AO2_ITERATOR_DONTLOCK) {
-		if (iter->flags & AO2_ITERATOR_UNLINK) {
-			orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_WRLOCK, 1);
-		} else {
-			orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
-		}
-	} else {
-		orig_lock = AO2_LOCK_REQ_MUTEX;
-		if (iter->flags & AO2_ITERATOR_UNLINK) {
-			ao2_wrlock(iter->c);
-		} else {
-			ao2_rdlock(iter->c);
-		}
-	}
-
-	node = iter->c->v_table->iterator_next(iter->c, iter->last_node, iter->flags);
-	if (node) {
-		ret = node->obj;
-
-		if (iter->flags & AO2_ITERATOR_UNLINK) {
-			/* Transfer the object ref from the container to the returned object. */
-			__container_unlink_node_debug(node, AO2_UNLINK_NODE_DEC_COUNT, tag, file, line, func);
-
-			/* Transfer the container's node ref to the iterator. */
-		} else {
-			/* Bump ref of returned object */
-			if (tag) {
-				__ao2_ref_debug(ret, +1, tag, file, line, func);
-			} else {
-				ao2_t_ref(ret, +1, "Next iterator object.");
-			}
-
-			/* Bump the container's node ref for the iterator. */
-			__ao2_ref(node, +1);
-		}
-	} else {
-		/* The iteration has completed. */
-		iter->complete = 1;
-		ret = NULL;
-	}
-
-	/* Replace the iterator's node */
-	if (iter->last_node) {
-		__ao2_ref(iter->last_node, -1);
-	}
-	iter->last_node = node;
-
-	if (iter->flags & AO2_ITERATOR_DONTLOCK) {
-		__adjust_lock(iter->c, orig_lock, 0);
-	} else {
-		ao2_unlock(iter->c);
-	}
-
-	return ret;
-}
-
-void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
-{
-	return internal_ao2_iterator_next(iter, tag, file, line, func);
-}
-
-void *__ao2_iterator_next(struct ao2_iterator *iter)
-{
-	return internal_ao2_iterator_next(iter, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
-}
-
-int ao2_iterator_count(struct ao2_iterator *iter)
-{
-	return ao2_container_count(iter->c);
-}
-
-void container_destruct(void *_c)
-{
-	struct ao2_container *c = _c;
-
-	/* Unlink any stored objects in the container. */
-	c->destroying = 1;
-	__ao2_callback(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-
-	/* Perform any extra container cleanup. */
-	if (c->v_table && c->v_table->destroy) {
-		c->v_table->destroy(c);
-	}
-
-#if defined(AO2_DEBUG)
-	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
-#endif
-}
-
-void container_destruct_debug(void *_c)
-{
-	struct ao2_container *c = _c;
-
-	/* Unlink any stored objects in the container. */
-	c->destroying = 1;
-	__ao2_callback_debug(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL,
-		"container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
-
-	/* Perform any extra container cleanup. */
-	if (c->v_table && c->v_table->destroy) {
-		c->v_table->destroy(c);
-	}
-
-#if defined(AO2_DEBUG)
-	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
-#endif
-}
-
-/*!
- * \internal
- * \brief Put obj into the arg container.
- * \since 11.0
- *
- * \param obj  pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param flags flags from ao2_callback()
- *
- * \retval 0 on success.
- * \retval CMP_STOP|CMP_MATCH on error.
- */
-static int dup_obj_cb(void *obj, void *arg, int flags)
-{
-	struct ao2_container *dest = arg;
-
-	return __ao2_link(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
-{
-	void *obj;
-	int res = 0;
-
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_rdlock(src);
-		ao2_wrlock(dest);
-	}
-	obj = __ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
-	if (obj) {
-		/* Failed to put this obj into the dest container. */
-		ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
-
-		/* Remove all items from the dest container. */
-		__ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
-			NULL);
-		res = -1;
-	}
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_unlock(dest);
-		ao2_unlock(src);
-	}
-
-	return res;
-}
-
-struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags)
-{
-	struct ao2_container *clone;
-	int failed;
-
-	/* Create the clone container with the same properties as the original. */
-	if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-	clone = orig->v_table->alloc_empty_clone(orig);
-	if (!clone) {
-		return NULL;
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		ao2_wrlock(clone);
-	}
-	failed = ao2_container_dup(clone, orig, flags);
-	if (flags & OBJ_NOLOCK) {
-		ao2_unlock(clone);
-	}
-	if (failed) {
-		/* Object copy into the clone container failed. */
-		ao2_t_ref(clone, -1, "Clone creation failed.");
-		clone = NULL;
-	}
-	return clone;
-}
-
-struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	struct ao2_container *clone;
-	int failed;
-
-	/* Create the clone container with the same properties as the original. */
-	if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone_debug) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return NULL;
-	}
-	clone = orig->v_table->alloc_empty_clone_debug(orig, tag, file, line, func, ref_debug);
-	if (!clone) {
-		return NULL;
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		ao2_wrlock(clone);
-	}
-	failed = ao2_container_dup(clone, orig, flags);
-	if (flags & OBJ_NOLOCK) {
-		ao2_unlock(clone);
-	}
-	if (failed) {
-		/* Object copy into the clone container failed. */
-		if (ref_debug) {
-			__ao2_ref_debug(clone, -1, tag, file, line, func);
-		} else {
-			ao2_t_ref(clone, -1, "Clone creation failed.");
-		}
-		clone = NULL;
-	}
-	return clone;
-}
-
-void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
-{
-	if (!is_ao2_object(self) || !self->v_table) {
-		prnt(where, "Invalid container\n");
-		ast_assert(0);
-		return;
-	}
-
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_rdlock(self);
-	}
-	if (name) {
-		prnt(where, "Container name: %s\n", name);
-	}
-#if defined(AO2_DEBUG)
-	if (self->v_table->dump) {
-		self->v_table->dump(self, where, prnt, prnt_obj);
-	} else
-#endif	/* defined(AO2_DEBUG) */
-	{
-		prnt(where, "Container dump not available.\n");
-	}
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_unlock(self);
-	}
-}
-
-void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
-{
-	if (!is_ao2_object(self) || !self->v_table) {
-		prnt(where, "Invalid container\n");
-		ast_assert(0);
-		return;
-	}
-
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_rdlock(self);
-	}
-	if (name) {
-		prnt(where, "Container name: %s\n", name);
-	}
-	prnt(where, "Number of objects: %d\n", self->elements);
-#if defined(AO2_DEBUG)
-	prnt(where, "Number of nodes: %d\n", self->nodes);
-	prnt(where, "Number of empty nodes: %d\n", self->nodes - self->elements);
-	/*
-	 * XXX
-	 * If the max_empty_nodes count gets out of single digits you
-	 * likely have a code path where ao2_iterator_destroy() is not
-	 * called.
-	 *
-	 * Empty nodes do not harm the container but they do make
-	 * container operations less efficient.
-	 */
-	prnt(where, "Maximum empty nodes: %d\n", self->max_empty_nodes);
-	if (self->v_table->stats) {
-		self->v_table->stats(self, where, prnt);
-	}
-#endif	/* defined(AO2_DEBUG) */
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_unlock(self);
-	}
-}
-
-int ao2_container_check(struct ao2_container *self, enum search_flags flags)
-{
-	int res = 0;
-
-	if (!is_ao2_object(self) || !self->v_table) {
-		/* Sanity checks. */
-		ast_assert(0);
-		return -1;
-	}
-#if defined(AO2_DEBUG)
-	if (!self->v_table->integrity) {
-		/* No ingetrigy check available.  Assume container is ok. */
-		return 0;
-	}
-
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_rdlock(self);
-	}
-	res = self->v_table->integrity(self);
-	if (!(flags & OBJ_NOLOCK)) {
-		ao2_unlock(self);
-	}
-#endif	/* defined(AO2_DEBUG) */
-	return res;
-}
-
-#if defined(AO2_DEBUG)
-static struct ao2_container *reg_containers;
-
-struct ao2_reg_container {
-	/*! Registered container pointer. */
-	struct ao2_container *registered;
-	/*! Callback function to print the given object's key. (NULL if not available) */
-	ao2_prnt_obj_fn *prnt_obj;
-	/*! Name container registered under. */
-	char name[1];
-};
-
-struct ao2_reg_partial_key {
-	/*! Length of partial key match. */
-	int len;
-	/*! Registration partial key name. */
-	const char *name;
-};
-
-struct ao2_reg_match {
-	/*! The nth match to find. */
-	int find_nth;
-	/*! Count of the matches already found. */
-	int count;
-};
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-static int ao2_reg_sort_cb(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct ao2_reg_container *reg_left = obj_left;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		{
-			const struct ao2_reg_container *reg_right = obj_right;
-
-			cmp = strcasecmp(reg_left->name, reg_right->name);
-		}
-		break;
-	case OBJ_SEARCH_KEY:
-		{
-			const char *name = obj_right;
-
-			cmp = strcasecmp(reg_left->name, name);
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		{
-			const struct ao2_reg_partial_key *partial_key = obj_right;
-
-			cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
-		}
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-static void ao2_reg_destructor(void *v_doomed)
-{
-	struct ao2_reg_container *doomed = v_doomed;
-
-	if (doomed->registered) {
-		ao2_t_ref(doomed->registered, -1, "Releasing registered container.");
-	}
-}
-#endif	/* defined(AO2_DEBUG) */
-
-int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
-{
-	int res = 0;
-#if defined(AO2_DEBUG)
-	struct ao2_reg_container *reg;
-
-	reg = ao2_t_alloc_options(sizeof(*reg) + strlen(name), ao2_reg_destructor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK, "Container registration object.");
-	if (!reg) {
-		return -1;
-	}
-
-	/* Fill in registered entry */
-	ao2_t_ref(self, +1, "Registering container.");
-	reg->registered = self;
-	reg->prnt_obj = prnt_obj;
-	strcpy(reg->name, name);/* safe */
-
-	if (!ao2_t_link(reg_containers, reg, "Save registration object.")) {
-		res = -1;
-	}
-
-	ao2_t_ref(reg, -1, "Done registering container.");
-#endif	/* defined(AO2_DEBUG) */
-	return res;
-}
-
-void ao2_container_unregister(const char *name)
-{
-#if defined(AO2_DEBUG)
-	ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY,
-		"Unregister container");
-#endif	/* defined(AO2_DEBUG) */
-}
-
-#if defined(AO2_DEBUG)
-static int ao2_complete_reg_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct ao2_reg_match *which = data;
-
-	/* ao2_reg_sort_cb() has already filtered the search to matching keys */
-	return (which->find_nth < ++which->count) ? (CMP_MATCH | CMP_STOP) : 0;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-static char *complete_container_names(struct ast_cli_args *a)
-{
-	struct ao2_reg_partial_key partial_key;
-	struct ao2_reg_match which;
-	struct ao2_reg_container *reg;
-	char *name;
-
-	if (a->pos != 3) {
-		return NULL;
-	}
-
-	partial_key.len = strlen(a->word);
-	partial_key.name = a->word;
-	which.find_nth = a->n;
-	which.count = 0;
-	reg = ao2_t_callback_data(reg_containers, partial_key.len ? OBJ_SEARCH_PARTIAL_KEY : 0,
-		ao2_complete_reg_cb, &partial_key, &which, "Find partial registered container");
-	if (reg) {
-		name = ast_strdup(reg->name);
-		ao2_t_ref(reg, -1, "Done with registered container object.");
-	} else {
-		name = NULL;
-	}
-	return name;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-AST_THREADSTORAGE(ao2_out_buf);
-
-/*!
- * \brief Print CLI output.
- * \since 12.0.0
- *
- * \param where User data pointer needed to determine where to put output.
- * \param fmt printf type format string.
- *
- * \return Nothing
- */
-static void cli_output(void *where, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-static void cli_output(void *where, const char *fmt, ...)
-{
-	int res;
-	struct ast_str *buf;
-	va_list ap;
-
-	buf = ast_str_thread_get(&ao2_out_buf, 256);
-	if (!buf) {
-		return;
-	}
-
-	va_start(ap, fmt);
-	res = ast_str_set_va(&buf, 0, fmt, ap);
-	va_end(ap);
-
-	if (res != AST_DYNSTR_BUILD_FAILED) {
-		ast_cli(*(int *) where, "%s", ast_str_buffer(buf));
-	}
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*! \brief Show container contents - CLI command */
-static char *handle_cli_astobj2_container_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *name;
-	struct ao2_reg_container *reg;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "astobj2 container dump";
-		e->usage =
-			"Usage: astobj2 container dump <name>\n"
-			"	Show contents of the container <name>.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_container_names(a);
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
-	if (reg) {
-		ao2_container_dump(reg->registered, 0, name, (void *) &a->fd, cli_output,
-			reg->prnt_obj);
-		ao2_t_ref(reg, -1, "Done with registered container object.");
-	} else {
-		ast_cli(a->fd, "Container '%s' not found.\n", name);
-	}
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*! \brief Show container statistics - CLI command */
-static char *handle_cli_astobj2_container_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *name;
-	struct ao2_reg_container *reg;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "astobj2 container stats";
-		e->usage =
-			"Usage: astobj2 container stats <name>\n"
-			"	Show statistics about the specified container <name>.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_container_names(a);
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
-	if (reg) {
-		ao2_container_stats(reg->registered, 0, name, (void *) &a->fd, cli_output);
-		ao2_t_ref(reg, -1, "Done with registered container object.");
-	} else {
-		ast_cli(a->fd, "Container '%s' not found.\n", name);
-	}
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*! \brief Show container check results - CLI command */
-static char *handle_cli_astobj2_container_check(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *name;
-	struct ao2_reg_container *reg;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "astobj2 container check";
-		e->usage =
-			"Usage: astobj2 container check <name>\n"
-			"	Perform a container integrity check on <name>.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_container_names(a);
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
-	if (reg) {
-		ast_cli(a->fd, "Container check of '%s': %s.\n", name,
-			ao2_container_check(reg->registered, 0) ? "failed" : "OK");
-		ao2_t_ref(reg, -1, "Done with registered container object.");
-	} else {
-		ast_cli(a->fd, "Container '%s' not found.\n", name);
-	}
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-static struct ast_cli_entry cli_astobj2[] = {
-	AST_CLI_DEFINE(handle_cli_astobj2_container_dump, "Show container contents"),
-	AST_CLI_DEFINE(handle_cli_astobj2_container_stats, "Show container statistics"),
-	AST_CLI_DEFINE(handle_cli_astobj2_container_check, "Perform a container integrity check"),
-};
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-static void container_cleanup(void)
-{
-	ao2_t_ref(reg_containers, -1, "Releasing container registration container");
-	reg_containers = NULL;
-
-	ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
-}
-#endif	/* defined(AO2_DEBUG) */
-
-int container_init(void)
-{
-#if defined(AO2_DEBUG)
-	reg_containers = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_reg_sort_cb, NULL,
-		"Container registration container.");
-	if (!reg_containers) {
-		return -1;
-	}
-
-	ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
-	ast_register_atexit(container_cleanup);
-#endif	/* defined(AO2_DEBUG) */
-
-	return 0;
-}
-
diff --git a/main/astobj2_container_private.h b/main/astobj2_container_private.h
deleted file mode 100644
index 07779a5..0000000
--- a/main/astobj2_container_private.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * astobj2 - replacement containers for asterisk data structures.
- *
- * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Common, private definitions for astobj2 containers.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- */
-
-#ifndef ASTOBJ2_CONTAINER_PRIVATE_H_
-#define ASTOBJ2_CONTAINER_PRIVATE_H_
-
-#include "asterisk/astobj2.h"
-
-/*!
- * \internal
- * \brief Enum for internal_ao2_unlink_node.
- */
-enum ao2_unlink_node_flags {
-	/*! Remove the node from the object's weak link list
-	 * OR unref the object if it's a strong reference. */
-	AO2_UNLINK_NODE_UNLINK_OBJECT = (1 << 0),
-	/*! Modified unlink_object to skip the unref of the object. */
-	AO2_UNLINK_NODE_NOUNREF_OBJECT = (1 << 1),
-	/*! Unref the node. */
-	AO2_UNLINK_NODE_UNREF_NODE = (1 << 2),
-	/*! Decrement the container's element count. */
-	AO2_UNLINK_NODE_DEC_COUNT = (1 << 3),
-};
-
-enum ao2_callback_type {
-	AO2_CALLBACK_DEFAULT,
-	AO2_CALLBACK_WITH_DATA,
-};
-
-enum ao2_container_insert {
-	/*! The node was inserted into the container. */
-	AO2_CONTAINER_INSERT_NODE_INSERTED,
-	/*! The node object replaced an existing node object. */
-	AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED,
-	/*! The node was rejected (duplicate). */
-	AO2_CONTAINER_INSERT_NODE_REJECTED,
-};
-
-/*! Allow enough room for container specific traversal state structs */
-#define AO2_TRAVERSAL_STATE_SIZE	100
-
-/*!
- * \brief Generic container node.
- *
- * \details This is the base container node type that contains
- * values common to all container nodes.
- */
-struct ao2_container_node {
-	/*! Stored object in node. */
-	void *obj;
-	/*! Container holding the node.  (Does not hold a reference.) */
-	struct ao2_container *my_container;
-	/*! TRUE if the node is linked into the container. */
-	unsigned int is_linked:1;
-};
-
-/*!
- * \brief Destroy this container.
- *
- * \param self Container to operate upon.
- *
- * \return Nothing
- */
-typedef void (*ao2_container_destroy_fn)(struct ao2_container *self);
-
-/*!
- * \brief Create an empty copy of this container.
- *
- * \param self Container to operate upon.
- *
- * \retval empty-container on success.
- * \retval NULL on error.
- */
-typedef struct ao2_container *(*ao2_container_alloc_empty_clone_fn)(struct ao2_container *self);
-
-/*!
- * \brief Create an empty copy of this container. (Debug version)
- *
- * \param self Container to operate upon.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- * \param ref_debug TRUE if to output a debug reference message.
- *
- * \retval empty-container on success.
- * \retval NULL on error.
- */
-typedef struct ao2_container *(*ao2_container_alloc_empty_clone_debug_fn)(struct ao2_container *self, const char *tag, const char *file, int line, const char *func, int ref_debug);
-
-/*!
- * \brief Create a new container node.
- *
- * \param self Container to operate upon.
- * \param obj_new Object to put into the node.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- *
- * \retval initialized-node on success.
- * \retval NULL on error.
- */
-typedef struct ao2_container_node *(*ao2_container_new_node_fn)(struct ao2_container *self, void *obj_new, const char *tag, const char *file, int line, const char *func);
-
-/*!
- * \brief Insert a node into this container.
- *
- * \param self Container to operate upon.
- * \param node Container node to insert into the container.
- *
- * \return enum ao2_container_insert value.
- */
-typedef enum ao2_container_insert (*ao2_container_insert_fn)(struct ao2_container *self, struct ao2_container_node *node);
-
-/*!
- * \brief Find the first container node in a traversal.
- *
- * \param self Container to operate upon.
- * \param flags search_flags to control traversing the container
- * \param arg Comparison callback arg parameter.
- * \param v_state Traversal state to restart container traversal.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-typedef struct ao2_container_node *(*ao2_container_find_first_fn)(struct ao2_container *self, enum search_flags flags, void *arg, void *v_state);
-
-/*!
- * \brief Find the next container node in a traversal.
- *
- * \param self Container to operate upon.
- * \param v_state Traversal state to restart container traversal.
- * \param prev Previous node returned by the traversal search functions.
- *    The ref ownership is passed back to this function.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-typedef struct ao2_container_node *(*ao2_container_find_next_fn)(struct ao2_container *self, void *v_state, struct ao2_container_node *prev);
-
-/*!
- * \brief Cleanup the container traversal state.
- *
- * \param v_state Traversal state to cleanup.
- *
- * \return Nothing
- */
-typedef void (*ao2_container_find_cleanup_fn)(void *v_state);
-
-/*!
- * \brief Find the next non-empty iteration node in the container.
- *
- * \param self Container to operate upon.
- * \param prev Previous node returned by the iterator.
- * \param flags search_flags to control iterating the container.
- *   Only AO2_ITERATOR_DESCENDING is useful by the method.
- *
- * \note The container is already locked.
- *
- * \retval node on success.
- * \retval NULL on error or no more nodes in the container.
- */
-typedef struct ao2_container_node *(*ao2_iterator_next_fn)(struct ao2_container *self, struct ao2_container_node *prev, enum ao2_iterator_flags flags);
-
-/*!
- * \brief Display contents of the specified container.
- *
- * \param self Container to dump.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
- *
- * \return Nothing
- */
-typedef void (*ao2_container_display)(struct ao2_container *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj);
-
-/*!
- * \brief Display statistics of the specified container.
- *
- * \param self Container to display statistics.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \note The container is already locked for reading.
- *
- * \return Nothing
- */
-typedef void (*ao2_container_statistics)(struct ao2_container *self, void *where, ao2_prnt_fn *prnt);
-
-/*!
- * \brief Perform an integrity check on the specified container.
- *
- * \param self Container to check integrity.
- *
- * \note The container is already locked for reading.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-typedef int (*ao2_container_integrity)(struct ao2_container *self);
-
-/*!
- * \internal
- * \brief Increment the container linked object statistic.
- * \since 12.4.0
- *
- * \param container Container to operate upon.
- * \param node Container node linking object to.
- *
- * \return Nothing
- */
-typedef void (*ao2_link_node_stat_fn)(struct ao2_container *container, struct ao2_container_node *node);
-
-/*!
- * \internal
- * \brief Decrement the container linked object statistic.
- * \since 12.4.0
- *
- * \param container Container to operate upon.
- * \param node Container node unlinking object from.
- *
- * \return Nothing
- */
-typedef void (*ao2_unlink_node_stat_fn)(struct ao2_container *container, struct ao2_container_node *node);
-
-/*! Container virtual methods template. */
-struct ao2_container_methods {
-	/*! Destroy this container. */
-	ao2_container_destroy_fn destroy;
-	/*! \brief Create an empty copy of this container. */
-	ao2_container_alloc_empty_clone_fn alloc_empty_clone;
-	/*! \brief Create an empty copy of this container. (Debug version) */
-	ao2_container_alloc_empty_clone_debug_fn alloc_empty_clone_debug;
-	/*! Create a new container node. */
-	ao2_container_new_node_fn new_node;
-	/*! Insert a node into this container. */
-	ao2_container_insert_fn insert;
-	/*! Traverse the container, find the first node. */
-	ao2_container_find_first_fn traverse_first;
-	/*! Traverse the container, find the next node. */
-	ao2_container_find_next_fn traverse_next;
-	/*! Traverse the container, cleanup state. */
-	ao2_container_find_cleanup_fn traverse_cleanup;
-	/*! Find the next iteration element in the container. */
-	ao2_iterator_next_fn iterator_next;
-#if defined(AO2_DEBUG)
-	/*! Increment the container linked object statistic. */
-	ao2_link_node_stat_fn link_stat;
-	/*! Deccrement the container linked object statistic. */
-	ao2_unlink_node_stat_fn unlink_stat;
-	/*! Display container contents. (Method for debug purposes) */
-	ao2_container_display dump;
-	/*! Display container debug statistics. (Method for debug purposes) */
-	ao2_container_statistics stats;
-	/*! Perform an integrity check on the container. (Method for debug purposes) */
-	ao2_container_integrity integrity;
-#endif	/* defined(AO2_DEBUG) */
-};
-
-/*!
- * \brief Generic container type.
- *
- * \details This is the base container type that contains values
- * common to all container types.
- *
- * \todo Linking and unlinking container objects is typically
- * expensive, as it involves a malloc()/free() of a small object
- * which is very inefficient.  To optimize this, we can allocate
- * larger arrays of container nodes when we run out of them, and
- * then manage our own freelist.  This will be more efficient as
- * we can do the freelist management while we hold the lock
- * (that we need anyway).
- */
-struct ao2_container {
-	/*! Container virtual method table. */
-	const struct ao2_container_methods *v_table;
-	/*! Container sort function if the container is sorted. */
-	ao2_sort_fn *sort_fn;
-	/*! Container traversal matching function for ao2_find. */
-	ao2_callback_fn *cmp_fn;
-	/*! The container option flags */
-	uint32_t options;
-	/*! Number of elements in the container. */
-	int elements;
-#if defined(AO2_DEBUG)
-	/*! Number of nodes in the container. */
-	int nodes;
-	/*! Maximum number of empty nodes in the container. (nodes - elements) */
-	int max_empty_nodes;
-#endif	/* defined(AO2_DEBUG) */
-	/*!
-	 * \brief TRUE if the container is being destroyed.
-	 *
-	 * \note The destruction traversal should override any requested
-	 * search order to do the most efficient order for destruction.
-	 *
-	 * \note There should not be any empty nodes in the container
-	 * during destruction.  If there are then an error needs to be
-	 * issued about container node reference leaks.
-	 */
-	unsigned int destroying:1;
-};
-
-/*!
- * \internal
- * \brief Unlink a node from this container.
- *
- * \param node Node to operate upon.
- * \param flags ao2_unlink_node_flags governing behavior.
- *
- * \retval 0 on errors.
- * \retval 1 on success.
- */
-int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags,
-	const char *tag, const char *file, int line, const char *func);
-
-#define __container_unlink_node(node, flags) \
-	__container_unlink_node_debug(node, flags, NULL, NULL, 0, NULL)
-
-void container_destruct(void *_c);
-void container_destruct_debug(void *_c);
-int container_init(void);
-
-#endif /* ASTOBJ2_CONTAINER_PRIVATE_H_ */
diff --git a/main/astobj2_hash.c b/main/astobj2_hash.c
deleted file mode 100644
index 08e01bd..0000000
--- a/main/astobj2_hash.c
+++ /dev/null
@@ -1,1153 +0,0 @@
-/*
- * astobj2_hash - Hash table implementation for astobj2.
- *
- * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Hash table functions implementing astobj2 containers.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416807 $")
-
-#include "asterisk/_private.h"
-#include "asterisk/astobj2.h"
-#include "astobj2_private.h"
-#include "astobj2_container_private.h"
-#include "asterisk/dlinkedlists.h"
-#include "asterisk/utils.h"
-
-/*!
- * A structure to create a linked list of entries,
- * used within a bucket.
- */
-struct hash_bucket_node {
-	/*!
-	 * \brief Items common to all container nodes.
-	 * \note Must be first in the specific node struct.
-	 */
-	struct ao2_container_node common;
-	/*! Next node links in the list. */
-	AST_DLLIST_ENTRY(hash_bucket_node) links;
-	/*! Hash bucket holding the node. */
-	int my_bucket;
-};
-
-struct hash_bucket {
-	/*! List of objects held in the bucket. */
-	AST_DLLIST_HEAD_NOLOCK(, hash_bucket_node) list;
-#if defined(AO2_DEBUG)
-	/*! Number of elements currently in the bucket. */
-	int elements;
-	/*! Maximum number of elements in the bucket. */
-	int max_elements;
-#endif	/* defined(AO2_DEBUG) */
-};
-
-/*!
- * A hash container in addition to values common to all
- * container types, stores the hash callback function, the
- * number of hash buckets, and the hash bucket heads.
- */
-struct ao2_container_hash {
-	/*!
-	 * \brief Items common to all containers.
-	 * \note Must be first in the specific container struct.
-	 */
-	struct ao2_container common;
-	ao2_hash_fn *hash_fn;
-	/*! Number of hash buckets in this container. */
-	int n_buckets;
-	/*! Hash bucket array of n_buckets.  Variable size. */
-	struct hash_bucket buckets[0];
-};
-
-/*! Traversal state to restart a hash container traversal. */
-struct hash_traversal_state {
-	/*! Active sort function in the traversal if not NULL. */
-	ao2_sort_fn *sort_fn;
-	/*! Saved comparison callback arg pointer. */
-	void *arg;
-	/*! Starting hash bucket */
-	int bucket_start;
-	/*! Stopping hash bucket */
-	int bucket_last;
-	/*! Saved search flags to control traversing the container. */
-	enum search_flags flags;
-	/*! TRUE if it is a descending search */
-	unsigned int descending:1;
-};
-
-struct hash_traversal_state_check {
-	/*
-	 * If we have a division by zero compile error here then there
-	 * is not enough room for the state.  Increase AO2_TRAVERSAL_STATE_SIZE.
-	 */
-	char check[1 / (AO2_TRAVERSAL_STATE_SIZE / sizeof(struct hash_traversal_state))];
-};
-
-/*!
- * \internal
- * \brief Create an empty copy of this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- *
- * \retval empty-clone-container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *hash_ao2_alloc_empty_clone(struct ao2_container_hash *self)
-{
-	if (!is_ao2_object(self)) {
-		return NULL;
-	}
-
-	return ao2_t_container_alloc_hash(ao2_options_get(self), self->common.options, self->n_buckets,
-		self->hash_fn, self->common.sort_fn, self->common.cmp_fn, "Clone hash container");
-}
-
-/*!
- * \internal
- * \brief Create an empty copy of this container. (Debug version)
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- * \param ref_debug TRUE if to output a debug reference message.
- *
- * \retval empty-clone-container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *hash_ao2_alloc_empty_clone_debug(struct ao2_container_hash *self, const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	if (!is_ao2_object(self)) {
-		return NULL;
-	}
-
-	return __ao2_container_alloc_hash_debug(ao2_options_get(self), self->common.options,
-		self->n_buckets, self->hash_fn, self->common.sort_fn, self->common.cmp_fn,
-		tag, file, line, func, ref_debug);
-}
-
-/*!
- * \internal
- * \brief Destroy a hash container list node.
- * \since 12.0.0
- *
- * \param v_doomed Container node to destroy.
- *
- * \details
- * The container node unlinks itself from the container as part
- * of its destruction.  The node must be destroyed while the
- * container is already locked.
- *
- * \note The container must be locked when the node is
- * unreferenced.
- *
- * \return Nothing
- */
-static void hash_ao2_node_destructor(void *v_doomed)
-{
-	struct hash_bucket_node *doomed = v_doomed;
-
-	if (doomed->common.is_linked) {
-		struct ao2_container_hash *my_container;
-		struct hash_bucket *bucket;
-
-		/*
-		 * Promote to write lock if not already there.  Since
-		 * adjust_lock() can potentially release and block waiting for a
-		 * write lock, care must be taken to ensure that node references
-		 * are released before releasing the container references.
-		 *
-		 * Node references held by an iterator can only be held while
-		 * the iterator also holds a reference to the container.  These
-		 * node references must be unreferenced before the container can
-		 * be unreferenced to ensure that the node will not get a
-		 * negative reference and the destructor called twice for the
-		 * same node.
-		 */
-		my_container = (struct ao2_container_hash *) doomed->common.my_container;
-		__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
-
-#if defined(AO2_DEBUG)
-		if (!my_container->common.destroying
-			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
-			ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
-		}
-#endif	/* defined(AO2_DEBUG) */
-		bucket = &my_container->buckets[doomed->my_bucket];
-		AST_DLLIST_REMOVE(&bucket->list, doomed, links);
-		AO2_DEVMODE_STAT(--my_container->common.nodes);
-	}
-
-	/*
-	 * We could have an object in the node if the container is being
-	 * destroyed or the node had not been linked in yet.
-	 */
-	if (doomed->common.obj) {
-		__container_unlink_node(&doomed->common, AO2_UNLINK_NODE_UNLINK_OBJECT);
-	}
-}
-
-/*!
- * \internal
- * \brief Create a new container node.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param obj_new Object to put into the node.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- *
- * \retval initialized-node on success.
- * \retval NULL on error.
- */
-static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *self, void *obj_new, const char *tag, const char *file, int line, const char *func)
-{
-	struct hash_bucket_node *node;
-	int i;
-
-	node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!node) {
-		return NULL;
-	}
-
-	i = abs(self->hash_fn(obj_new, OBJ_SEARCH_OBJECT));
-	i %= self->n_buckets;
-
-	if (tag) {
-		__ao2_ref_debug(obj_new, +1, tag, file, line, func);
-	} else {
-		ao2_t_ref(obj_new, +1, "Container node creation");
-	}
-	node->common.obj = obj_new;
-	node->common.my_container = (struct ao2_container *) self;
-	node->my_bucket = i;
-
-	return node;
-}
-
-/*!
- * \internal
- * \brief Insert a node into this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param node Container node to insert into the container.
- *
- * \return enum ao2_container_insert value.
- */
-static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash *self,
-	struct hash_bucket_node *node)
-{
-	int cmp;
-	struct hash_bucket *bucket;
-	struct hash_bucket_node *cur;
-	ao2_sort_fn *sort_fn;
-	uint32_t options;
-
-	bucket = &self->buckets[node->my_bucket];
-	sort_fn = self->common.sort_fn;
-	options = self->common.options;
-
-	if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
-		if (sort_fn) {
-			AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
-				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp > 0) {
-					continue;
-				}
-				if (cmp < 0) {
-					AST_DLLIST_INSERT_AFTER_CURRENT(node, links);
-					return AO2_CONTAINER_INSERT_NODE_INSERTED;
-				}
-				switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-				default:
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-					break;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-					/* Reject all objects with the same key. */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-					if (cur->common.obj == node->common.obj) {
-						/* Reject inserting the same object */
-						return AO2_CONTAINER_INSERT_NODE_REJECTED;
-					}
-					break;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-					SWAP(cur->common.obj, node->common.obj);
-					ao2_t_ref(node, -1, "Discard the new node.");
-					return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
-				}
-			}
-			AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
-		}
-		AST_DLLIST_INSERT_HEAD(&bucket->list, node, links);
-	} else {
-		if (sort_fn) {
-			AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
-				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp < 0) {
-					continue;
-				}
-				if (cmp > 0) {
-					AST_DLLIST_INSERT_BEFORE_CURRENT(node, links);
-					return AO2_CONTAINER_INSERT_NODE_INSERTED;
-				}
-				switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-				default:
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-					break;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-					/* Reject all objects with the same key. */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-					if (cur->common.obj == node->common.obj) {
-						/* Reject inserting the same object */
-						return AO2_CONTAINER_INSERT_NODE_REJECTED;
-					}
-					break;
-				case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-					SWAP(cur->common.obj, node->common.obj);
-					ao2_t_ref(node, -1, "Discard the new node.");
-					return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
-				}
-			}
-			AST_DLLIST_TRAVERSE_SAFE_END;
-		}
-		AST_DLLIST_INSERT_TAIL(&bucket->list, node, links);
-	}
-	return AO2_CONTAINER_INSERT_NODE_INSERTED;
-}
-
-/*!
- * \internal
- * \brief Find the first hash container node in a traversal.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param flags search_flags to control traversing the container
- * \param arg Comparison callback arg parameter.
- * \param state Traversal state to restart hash container traversal.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *self, enum search_flags flags, void *arg, struct hash_traversal_state *state)
-{
-	struct hash_bucket_node *node;
-	int bucket_cur;
-	int cmp;
-
-	memset(state, 0, sizeof(*state));
-	state->arg = arg;
-	state->flags = flags;
-
-	/* Determine traversal order. */
-	switch (flags & OBJ_ORDER_MASK) {
-	case OBJ_ORDER_POST:
-	case OBJ_ORDER_DESCENDING:
-		state->descending = 1;
-		break;
-	case OBJ_ORDER_PRE:
-	case OBJ_ORDER_ASCENDING:
-	default:
-		break;
-	}
-
-	/*
-	 * If lookup by pointer or search key, run the hash and optional
-	 * sort functions.  Otherwise, traverse the whole container.
-	 */
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-	case OBJ_SEARCH_KEY:
-		/* we know hash can handle this case */
-		bucket_cur = abs(self->hash_fn(arg, flags & OBJ_SEARCH_MASK));
-		bucket_cur %= self->n_buckets;
-		state->sort_fn = self->common.sort_fn;
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* scan all buckets for partial key matches */
-		bucket_cur = -1;
-		state->sort_fn = self->common.sort_fn;
-		break;
-	default:
-		/* don't know, let's scan all buckets */
-		bucket_cur = -1;
-		state->sort_fn = NULL;
-		break;
-	}
-
-	if (state->descending) {
-		/*
-		 * Determine the search boundaries of a descending traversal.
-		 *
-		 * bucket_cur downto state->bucket_last
-		 */
-		if (bucket_cur < 0) {
-			bucket_cur = self->n_buckets - 1;
-			state->bucket_last = 0;
-		} else {
-			state->bucket_last = bucket_cur;
-		}
-		state->bucket_start = bucket_cur;
-
-		/* For each bucket */
-		for (; state->bucket_last <= bucket_cur; --bucket_cur) {
-			/* For each node in the bucket. */
-			for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
-				node;
-				node = AST_DLLIST_PREV(node, links)) {
-				if (!node->common.obj) {
-					/* Node is empty */
-					continue;
-				}
-
-				if (state->sort_fn) {
-					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
-					if (cmp > 0) {
-						continue;
-					}
-					if (cmp < 0) {
-						/* No more nodes in this bucket are possible to match. */
-						break;
-					}
-				}
-
-				/* We have the first traversal node */
-				__ao2_ref(node, +1);
-				return node;
-			}
-		}
-	} else {
-		/*
-		 * Determine the search boundaries of an ascending traversal.
-		 *
-		 * bucket_cur to state->bucket_last-1
-		 */
-		if (bucket_cur < 0) {
-			bucket_cur = 0;
-			state->bucket_last = self->n_buckets;
-		} else {
-			state->bucket_last = bucket_cur + 1;
-		}
-		state->bucket_start = bucket_cur;
-
-		/* For each bucket */
-		for (; bucket_cur < state->bucket_last; ++bucket_cur) {
-			/* For each node in the bucket. */
-			for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
-				node;
-				node = AST_DLLIST_NEXT(node, links)) {
-				if (!node->common.obj) {
-					/* Node is empty */
-					continue;
-				}
-
-				if (state->sort_fn) {
-					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
-					if (cmp < 0) {
-						continue;
-					}
-					if (cmp > 0) {
-						/* No more nodes in this bucket are possible to match. */
-						break;
-					}
-				}
-
-				/* We have the first traversal node */
-				__ao2_ref(node, +1);
-				return node;
-			}
-		}
-	}
-
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Find the next hash container node in a traversal.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param state Traversal state to restart hash container traversal.
- * \param prev Previous node returned by the traversal search functions.
- *    The ref ownership is passed back to this function.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *self, struct hash_traversal_state *state, struct hash_bucket_node *prev)
-{
-	struct hash_bucket_node *node;
-	void *arg;
-	enum search_flags flags;
-	int bucket_cur;
-	int cmp;
-
-	arg = state->arg;
-	flags = state->flags;
-	bucket_cur = prev->my_bucket;
-	node = prev;
-
-	/*
-	 * This function is structured the same as hash_ao2_find_first()
-	 * intentionally.  We are resuming the search loops from
-	 * hash_ao2_find_first() in order to find the next node.  The
-	 * search loops must be resumed where hash_ao2_find_first()
-	 * returned with the first node.
-	 */
-	if (state->descending) {
-		goto hash_descending_resume;
-
-		/* For each bucket */
-		for (; state->bucket_last <= bucket_cur; --bucket_cur) {
-			/* For each node in the bucket. */
-			for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
-				node;
-				node = AST_DLLIST_PREV(node, links)) {
-				if (!node->common.obj) {
-					/* Node is empty */
-					continue;
-				}
-
-				if (state->sort_fn) {
-					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
-					if (cmp > 0) {
-						continue;
-					}
-					if (cmp < 0) {
-						/* No more nodes in this bucket are possible to match. */
-						break;
-					}
-				}
-
-				/* We have the next traversal node */
-				__ao2_ref(node, +1);
-
-				/*
-				 * Dereferencing the prev node may result in our next node
-				 * object being removed by another thread.  This could happen if
-				 * the container uses RW locks and the container was read
-				 * locked.
-				 */
-				__ao2_ref(prev, -1);
-				if (node->common.obj) {
-					return node;
-				}
-				prev = node;
-
-hash_descending_resume:;
-			}
-		}
-	} else {
-		goto hash_ascending_resume;
-
-		/* For each bucket */
-		for (; bucket_cur < state->bucket_last; ++bucket_cur) {
-			/* For each node in the bucket. */
-			for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
-				node;
-				node = AST_DLLIST_NEXT(node, links)) {
-				if (!node->common.obj) {
-					/* Node is empty */
-					continue;
-				}
-
-				if (state->sort_fn) {
-					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
-					if (cmp < 0) {
-						continue;
-					}
-					if (cmp > 0) {
-						/* No more nodes in this bucket are possible to match. */
-						break;
-					}
-				}
-
-				/* We have the next traversal node */
-				__ao2_ref(node, +1);
-
-				/*
-				 * Dereferencing the prev node may result in our next node
-				 * object being removed by another thread.  This could happen if
-				 * the container uses RW locks and the container was read
-				 * locked.
-				 */
-				__ao2_ref(prev, -1);
-				if (node->common.obj) {
-					return node;
-				}
-				prev = node;
-
-hash_ascending_resume:;
-			}
-		}
-	}
-
-	/* No more nodes in the container left to traverse. */
-	__ao2_ref(prev, -1);
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Find the next non-empty iteration node in the container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param node Previous node returned by the iterator.
- * \param flags search_flags to control iterating the container.
- *   Only AO2_ITERATOR_DESCENDING is useful by the method.
- *
- * \note The container is already locked.
- *
- * \retval node on success.
- * \retval NULL on error or no more nodes in the container.
- */
-static struct hash_bucket_node *hash_ao2_iterator_next(struct ao2_container_hash *self, struct hash_bucket_node *node, enum ao2_iterator_flags flags)
-{
-	int cur_bucket;
-
-	if (flags & AO2_ITERATOR_DESCENDING) {
-		if (node) {
-			cur_bucket = node->my_bucket;
-
-			/* Find next non-empty node. */
-			for (;;) {
-				node = AST_DLLIST_PREV(node, links);
-				if (!node) {
-					break;
-				}
-				if (node->common.obj) {
-					/* Found a non-empty node. */
-					return node;
-				}
-			}
-		} else {
-			/* Find first non-empty node. */
-			cur_bucket = self->n_buckets;
-		}
-
-		/* Find a non-empty node in the remaining buckets */
-		while (0 <= --cur_bucket) {
-			node = AST_DLLIST_LAST(&self->buckets[cur_bucket].list);
-			while (node) {
-				if (node->common.obj) {
-					/* Found a non-empty node. */
-					return node;
-				}
-				node = AST_DLLIST_PREV(node, links);
-			}
-		}
-	} else {
-		if (node) {
-			cur_bucket = node->my_bucket;
-
-			/* Find next non-empty node. */
-			for (;;) {
-				node = AST_DLLIST_NEXT(node, links);
-				if (!node) {
-					break;
-				}
-				if (node->common.obj) {
-					/* Found a non-empty node. */
-					return node;
-				}
-			}
-		} else {
-			/* Find first non-empty node. */
-			cur_bucket = -1;
-		}
-
-		/* Find a non-empty node in the remaining buckets */
-		while (++cur_bucket < self->n_buckets) {
-			node = AST_DLLIST_FIRST(&self->buckets[cur_bucket].list);
-			while (node) {
-				if (node->common.obj) {
-					/* Found a non-empty node. */
-					return node;
-				}
-				node = AST_DLLIST_NEXT(node, links);
-			}
-		}
-	}
-
-	/* No more nodes to visit in the container. */
-	return NULL;
-}
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Increment the hash container linked object statistic.
- * \since 12.0.0
- *
- * \param hash Container to operate upon.
- * \param hash_node Container node linking object to.
- *
- * \return Nothing
- */
-static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
-{
-	struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
-	struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
-	int i = node->my_bucket;
-
-	++self->buckets[i].elements;
-	if (self->buckets[i].max_elements < self->buckets[i].elements) {
-		self->buckets[i].max_elements = self->buckets[i].elements;
-	}
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Decrement the hash container linked object statistic.
- * \since 12.0.0
- *
- * \param hash Container to operate upon.
- * \param hash_node Container node unlinking object from.
- *
- * \return Nothing
- */
-static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
-{
-	struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
-	struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
-
-	--self->buckets[node->my_bucket].elements;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-/*!
- * \internal
- *
- * \brief Destroy this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- *
- * \return Nothing
- */
-static void hash_ao2_destroy(struct ao2_container_hash *self)
-{
-	int idx;
-
-	/* Check that the container no longer has any nodes */
-	for (idx = self->n_buckets; idx--;) {
-		if (!AST_DLLIST_EMPTY(&self->buckets[idx].list)) {
-			ast_log(LOG_ERROR, "Node ref leak.  Hash container still has nodes!\n");
-			ast_assert(0);
-			break;
-		}
-	}
-}
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Display contents of the specified container.
- * \since 12.0.0
- *
- * \param self Container to dump.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
- *
- * \return Nothing
- */
-static void hash_ao2_dump(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
-{
-#define FORMAT  "%6s, %16s, %16s, %16s, %16s, %s\n"
-#define FORMAT2 "%6d, %16p, %16p, %16p, %16p, "
-
-	int bucket;
-	int suppressed_buckets = 0;
-	struct hash_bucket_node *node;
-
-	prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
-
-	prnt(where, FORMAT, "Bucket", "Node", "Prev", "Next", "Obj", "Key");
-	for (bucket = 0; bucket < self->n_buckets; ++bucket) {
-		node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
-		if (node) {
-			suppressed_buckets = 0;
-			do {
-				prnt(where, FORMAT2,
-					bucket,
-					node,
-					AST_DLLIST_PREV(node, links),
-					AST_DLLIST_NEXT(node, links),
-					node->common.obj);
-				if (node->common.obj && prnt_obj) {
-					prnt_obj(node->common.obj, where, prnt);
-				}
-				prnt(where, "\n");
-
-				node = AST_DLLIST_NEXT(node, links);
-			} while (node);
-		} else if (!suppressed_buckets) {
-			suppressed_buckets = 1;
-			prnt(where, "...\n");
-		}
-	}
-
-#undef FORMAT
-#undef FORMAT2
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Display statistics of the specified container.
- * \since 12.0.0
- *
- * \param self Container to display statistics.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \note The container is already locked for reading.
- *
- * \return Nothing
- */
-static void hash_ao2_stats(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt)
-{
-#define FORMAT  "%10.10s %10.10s %10.10s\n"
-#define FORMAT2 "%10d %10d %10d\n"
-
-	int bucket;
-	int suppressed_buckets = 0;
-
-	prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
-
-	prnt(where, FORMAT, "Bucket", "Objects", "Max");
-	for (bucket = 0; bucket < self->n_buckets; ++bucket) {
-		if (self->buckets[bucket].max_elements) {
-			suppressed_buckets = 0;
-			prnt(where, FORMAT2, bucket, self->buckets[bucket].elements,
-				self->buckets[bucket].max_elements);
-		} else if (!suppressed_buckets) {
-			suppressed_buckets = 1;
-			prnt(where, "...\n");
-		}
-	}
-
-#undef FORMAT
-#undef FORMAT2
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Perform an integrity check on the specified container.
- * \since 12.0.0
- *
- * \param self Container to check integrity.
- *
- * \note The container is already locked for reading.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int hash_ao2_integrity(struct ao2_container_hash *self)
-{
-	int bucket_exp;
-	int bucket;
-	int count_obj;
-	int count_total_obj;
-	int count_total_node;
-	void *obj_last;
-	struct hash_bucket_node *node;
-	struct hash_bucket_node *prev;
-	struct hash_bucket_node *next;
-
-	count_total_obj = 0;
-	count_total_node = 0;
-
-	/* For each bucket in the container. */
-	for (bucket = 0; bucket < self->n_buckets; ++bucket) {
-		if (!AST_DLLIST_FIRST(&self->buckets[bucket].list)
-			&& !AST_DLLIST_LAST(&self->buckets[bucket].list)) {
-			/* The bucket list is empty. */
-			continue;
-		}
-
-		count_obj = 0;
-		obj_last = NULL;
-
-		/* Check bucket list links and nodes. */
-		node = AST_DLLIST_LAST(&self->buckets[bucket].list);
-		if (!node) {
-			ast_log(LOG_ERROR, "Bucket %d list tail is NULL when it should not be!\n",
-				bucket);
-			return -1;
-		}
-		if (AST_DLLIST_NEXT(node, links)) {
-			ast_log(LOG_ERROR, "Bucket %d list tail node is not the last node!\n",
-				bucket);
-			return -1;
-		}
-		node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
-		if (!node) {
-			ast_log(LOG_ERROR, "Bucket %d list head is NULL when it should not be!\n",
-				bucket);
-			return -1;
-		}
-		if (AST_DLLIST_PREV(node, links)) {
-			ast_log(LOG_ERROR, "Bucket %d list head node is not the first node!\n",
-				bucket);
-			return -1;
-		}
-		for (; node; node = next) {
-			/* Check backward link. */
-			prev = AST_DLLIST_PREV(node, links);
-			if (prev) {
-				if (prev == node) {
-					ast_log(LOG_ERROR, "Bucket %d list node's prev pointer points to itself!\n",
-						bucket);
-					return -1;
-				}
-				if (node != AST_DLLIST_NEXT(prev, links)) {
-					ast_log(LOG_ERROR, "Bucket %d list node's prev node does not link back!\n",
-						bucket);
-					return -1;
-				}
-			} else if (node != AST_DLLIST_FIRST(&self->buckets[bucket].list)) {
-				ast_log(LOG_ERROR, "Bucket %d backward list chain is broken!\n",
-					bucket);
-				return -1;
-			}
-
-			/* Check forward link. */
-			next = AST_DLLIST_NEXT(node, links);
-			if (next) {
-				if (next == node) {
-					ast_log(LOG_ERROR, "Bucket %d list node's next pointer points to itself!\n",
-						bucket);
-					return -1;
-				}
-				if (node != AST_DLLIST_PREV(next, links)) {
-					ast_log(LOG_ERROR, "Bucket %d list node's next node does not link back!\n",
-						bucket);
-					return -1;
-				}
-			} else if (node != AST_DLLIST_LAST(&self->buckets[bucket].list)) {
-				ast_log(LOG_ERROR, "Bucket %d forward list chain is broken!\n",
-					bucket);
-				return -1;
-			}
-
-			if (bucket != node->my_bucket) {
-				ast_log(LOG_ERROR, "Bucket %d node claims to be in bucket %d!\n",
-					bucket, node->my_bucket);
-				return -1;
-			}
-
-			++count_total_node;
-			if (!node->common.obj) {
-				/* Node is empty. */
-				continue;
-			}
-			++count_obj;
-
-			/* Check container hash key for expected bucket. */
-			bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_SEARCH_OBJECT));
-			bucket_exp %= self->n_buckets;
-			if (bucket != bucket_exp) {
-				ast_log(LOG_ERROR, "Bucket %d node hashes to bucket %d!\n",
-					bucket, bucket_exp);
-				return -1;
-			}
-
-			/* Check sort if configured. */
-			if (self->common.sort_fn) {
-				if (obj_last
-					&& self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
-					ast_log(LOG_ERROR, "Bucket %d nodes out of sorted order!\n",
-						bucket);
-					return -1;
-				}
-				obj_last = node->common.obj;
-			}
-		}
-
-		/* Check bucket obj count statistic. */
-		if (count_obj != self->buckets[bucket].elements) {
-			ast_log(LOG_ERROR, "Bucket %d object count of %d does not match stat of %d!\n",
-				bucket, count_obj, self->buckets[bucket].elements);
-			return -1;
-		}
-
-		/* Accumulate found object counts. */
-		count_total_obj += count_obj;
-	}
-
-	/* Check total obj count. */
-	if (count_total_obj != ao2_container_count(&self->common)) {
-		ast_log(LOG_ERROR,
-			"Total object count of %d does not match ao2_container_count() of %d!\n",
-			count_total_obj, ao2_container_count(&self->common));
-		return -1;
-	}
-
-	/* Check total node count. */
-	if (count_total_node != self->common.nodes) {
-		ast_log(LOG_ERROR, "Total node count of %d does not match stat of %d!\n",
-			count_total_node, self->common.nodes);
-		return -1;
-	}
-
-	return 0;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-/*! Hash container virtual method table. */
-static const struct ao2_container_methods v_table_hash = {
-	.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) hash_ao2_alloc_empty_clone,
-	.alloc_empty_clone_debug =
-		(ao2_container_alloc_empty_clone_debug_fn) hash_ao2_alloc_empty_clone_debug,
-	.new_node = (ao2_container_new_node_fn) hash_ao2_new_node,
-	.insert = (ao2_container_insert_fn) hash_ao2_insert_node,
-	.traverse_first = (ao2_container_find_first_fn) hash_ao2_find_first,
-	.traverse_next = (ao2_container_find_next_fn) hash_ao2_find_next,
-	.iterator_next = (ao2_iterator_next_fn) hash_ao2_iterator_next,
-	.destroy = (ao2_container_destroy_fn) hash_ao2_destroy,
-#if defined(AO2_DEBUG)
-	.link_stat = hash_ao2_link_node_stat,
-	.unlink_stat = hash_ao2_unlink_node_stat,
-	.dump = (ao2_container_display) hash_ao2_dump,
-	.stats = (ao2_container_statistics) hash_ao2_stats,
-	.integrity = (ao2_container_integrity) hash_ao2_integrity,
-#endif	/* defined(AO2_DEBUG) */
-};
-
-/*!
- * \brief always zero hash function
- *
- * it is convenient to have a hash function that always returns 0.
- * This is basically used when we want to have a container that is
- * a simple linked list.
- *
- * \returns 0
- */
-static int hash_zero(const void *user_obj, const int flags)
-{
-	return 0;
-}
-
-/*!
- * \brief Initialize a hash container with the desired number of buckets.
- *
- * \param self Container to initialize.
- * \param options Container behaviour options (See enum ao2_container_opts)
- * \param n_buckets Number of buckets for hash
- * \param hash_fn Pointer to a function computing a hash value.
- * \param sort_fn Pointer to a sort function.
- * \param cmp_fn Pointer to a compare function used by ao2_find.
- *
- * \return A pointer to a struct container.
- */
-static struct ao2_container *hash_ao2_container_init(
-	struct ao2_container_hash *self, unsigned int options, unsigned int n_buckets,
-	ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
-{
-	if (!self) {
-		return NULL;
-	}
-
-	self->common.v_table = &v_table_hash;
-	self->common.sort_fn = sort_fn;
-	self->common.cmp_fn = cmp_fn;
-	self->common.options = options;
-	self->hash_fn = hash_fn ? hash_fn : hash_zero;
-	self->n_buckets = n_buckets;
-
-#ifdef AO2_DEBUG
-	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif	/* defined(AO2_DEBUG) */
-
-	return (struct ao2_container *) self;
-}
-
-struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
-	unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
-{
-	unsigned int num_buckets;
-	size_t container_size;
-	struct ao2_container_hash *self;
-
-	num_buckets = hash_fn ? n_buckets : 1;
-	container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
-
-	self = ao2_t_alloc_options(container_size, container_destruct, ao2_options,
-		"New hash container");
-	return hash_ao2_container_init(self, container_options, num_buckets,
-		hash_fn, sort_fn, cmp_fn);
-}
-
-struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
-	unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	unsigned int num_buckets;
-	size_t container_size;
-	struct ao2_container_hash *self;
-
-	num_buckets = hash_fn ? n_buckets : 1;
-	container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
-
-	self = __ao2_alloc_debug(container_size,
-		ref_debug ? container_destruct_debug : container_destruct, ao2_options,
-		tag, file, line, func, ref_debug);
-	return hash_ao2_container_init(self, container_options, num_buckets, hash_fn,
-		sort_fn, cmp_fn);
-}
-
-struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
-	unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
-{
-	return __ao2_container_alloc_hash(ao2_options, container_options, 1, NULL, sort_fn,
-		cmp_fn);
-}
-
-struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
-	unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	return __ao2_container_alloc_hash_debug(ao2_options, container_options, 1, NULL,
-		sort_fn, cmp_fn, tag, file, line, func, ref_debug);
-}
-
diff --git a/main/astobj2_private.h b/main/astobj2_private.h
deleted file mode 100644
index 0583faf..0000000
--- a/main/astobj2_private.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * astobj2 - replacement containers for asterisk data structures.
- *
- * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Common, private definitions for astobj2.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- */
-
-#ifndef ASTOBJ2_PRIVATE_H_
-#define ASTOBJ2_PRIVATE_H_
-
-#include "asterisk/astobj2.h"
-
-#if defined(AO2_DEBUG)
-#define AO2_DEVMODE_STAT(stat)	stat
-#else
-#define AO2_DEVMODE_STAT(stat)
-#endif	/* defined(AO2_DEBUG) */
-
-#ifdef AO2_DEBUG
-struct ao2_stats {
-	volatile int total_objects;
-	volatile int total_mem;
-	volatile int total_containers;
-	volatile int total_refs;
-	volatile int total_locked;
-};
-extern struct ao2_stats ao2;
-#endif	/* defined(AO2_DEBUG) */
-
-int is_ao2_object(void *user_data);
-enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger);
-
-#endif /* ASTOBJ2_PRIVATE_H_ */
diff --git a/main/astobj2_rbtree.c b/main/astobj2_rbtree.c
deleted file mode 100644
index 8599078..0000000
--- a/main/astobj2_rbtree.c
+++ /dev/null
@@ -1,2096 +0,0 @@
-/*
- * astobj2_hash - RBTree implementation for astobj2.
- *
- * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief RBTree functions implementing astobj2 containers.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416807 $")
-
-#include "asterisk/_private.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/utils.h"
-#include "astobj2_private.h"
-#include "astobj2_container_private.h"
-
-/*!
- * A structure to hold the object held by the container and
- * where it is located in it.
- *
- * A red-black tree has the following properties:
- *
- * 1) Every node is either black or red.
- *
- * 2) The root is black.
- *
- * 3) If a node has a NULL child, that "child" is considered
- * black.
- *
- * 4) If a node is red, then both of its children are black.
- *
- * 5) Every path from a node to a descendant NULL child has the
- * same number of black nodes.  (Including the black NULL
- * child.)
- */
-struct rbtree_node {
-	/*!
-	 * \brief Items common to all container nodes.
-	 * \note Must be first in the specific node struct.
-	 */
-	struct ao2_container_node common;
-	/*! Parent node of this node. NULL if this is the root node. */
-	struct rbtree_node *parent;
-	/*! Left child node of this node.  NULL if does not have this child. */
-	struct rbtree_node *left;
-	/*! Right child node of this node.  NULL if does not have this child. */
-	struct rbtree_node *right;
-	/*! TRUE if the node is red. */
-	unsigned int is_red:1;
-};
-
-/*!
- * A rbtree container in addition to values common to all
- * container types, stores the pointer to the root node of the
- * tree.
- */
-struct ao2_container_rbtree {
-	/*!
-	 * \brief Items common to all containers.
-	 * \note Must be first in the specific container struct.
-	 */
-	struct ao2_container common;
-	/*! Root node of the tree.  NULL if the tree is empty. */
-	struct rbtree_node *root;
-#if defined(AO2_DEBUG)
-	struct {
-		/*! Fixup insert left cases 1-3 */
-		int fixup_insert_left[3];
-		/*! Fixup insert right cases 1-3 */
-		int fixup_insert_right[3];
-		/*! Fixup delete left cases 1-4 */
-		int fixup_delete_left[4];
-		/*! Fixup delete right cases 1-4 */
-		int fixup_delete_right[4];
-		/*! Deletion of node with number of children (0-2). */
-		int delete_children[3];
-	} stats;
-#endif	/* defined(AO2_DEBUG) */
-};
-
-enum equal_node_bias {
-	/*! Bias search toward first matching node in the container. */
-	BIAS_FIRST,
-	/*! Bias search toward any matching node. */
-	BIAS_EQUAL,
-	/*! Bias search toward last matching node in the container. */
-	BIAS_LAST,
-};
-
-enum empty_node_direction {
-	GO_LEFT,
-	GO_RIGHT,
-};
-
-/*! Traversal state to restart a rbtree container traversal. */
-struct rbtree_traversal_state {
-	/*! Active sort function in the traversal if not NULL. */
-	ao2_sort_fn *sort_fn;
-	/*! Saved comparison callback arg pointer. */
-	void *arg;
-	/*! Saved search flags to control traversing the container. */
-	enum search_flags flags;
-};
-
-struct rbtree_traversal_state_check {
-	/*
-	 * If we have a division by zero compile error here then there
-	 * is not enough room for the state.  Increase AO2_TRAVERSAL_STATE_SIZE.
-	 */
-	char check[1 / (AO2_TRAVERSAL_STATE_SIZE / sizeof(struct rbtree_traversal_state))];
-};
-
-/*!
- * \internal
- * \brief Get the most left node in the tree.
- * \since 12.0.0
- *
- * \param node Starting node to find the most left node.
- *
- * \return Left most node.  Never NULL.
- */
-static struct rbtree_node *rb_node_most_left(struct rbtree_node *node)
-{
-	while (node->left) {
-		node = node->left;
-	}
-
-	return node;
-}
-
-/*!
- * \internal
- * \brief Get the most right node in the tree.
- * \since 12.0.0
- *
- * \param node Starting node to find the most right node.
- *
- * \return Right most node.  Never NULL.
- */
-static struct rbtree_node *rb_node_most_right(struct rbtree_node *node)
-{
-	while (node->right) {
-		node = node->right;
-	}
-
-	return node;
-}
-
-/*!
- * \internal
- * \brief Get the next node in ascending sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the next node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_next(struct rbtree_node *node)
-{
-	if (node->right) {
-		return rb_node_most_left(node->right);
-	}
-
-	/* Find the parent that the node is a left child of. */
-	while (node->parent) {
-		if (node->parent->left == node) {
-			/* We are the left child.  The parent is the next node. */
-			return node->parent;
-		}
-		node = node->parent;
-	}
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Get the next node in descending sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the previous node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_prev(struct rbtree_node *node)
-{
-	if (node->left) {
-		return rb_node_most_right(node->left);
-	}
-
-	/* Find the parent that the node is a right child of. */
-	while (node->parent) {
-		if (node->parent->right == node) {
-			/* We are the right child.  The parent is the previous node. */
-			return node->parent;
-		}
-		node = node->parent;
-	}
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Get the next node in pre-order sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the next node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_pre(struct rbtree_node *node)
-{
-	/* Visit the children if the node has any. */
-	if (node->left) {
-		return node->left;
-	}
-	if (node->right) {
-		return node->right;
-	}
-
-	/* Time to go back up. */
-	for (;;) {
-		if (!node->parent) {
-			return NULL;
-		}
-		if (node->parent->left == node && node->parent->right) {
-			/*
-			 * We came up the left child and there's a right child.  Visit
-			 * it.
-			 */
-			return node->parent->right;
-		}
-		node = node->parent;
-	}
-}
-
-/*!
- * \internal
- * \brief Get the next node in post-order sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the next node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_post(struct rbtree_node *node)
-{
-	/* This node's children have already been visited. */
-	for (;;) {
-		if (!node->parent) {
-			return NULL;
-		}
-		if (node->parent->left == node) {
-			/* We came up the left child. */
-			node = node->parent;
-
-			/*
-			 * Find the right child's left most childless node.
-			 */
-			while (node->right) {
-				node = rb_node_most_left(node->right);
-			}
-
-			/*
-			 * This node's left child has already been visited or it doesn't
-			 * have any children.
-			 */
-			return node;
-		}
-
-		/*
-		 * We came up the right child.
-		 *
-		 * This node's children have already been visited.  Time to
-		 * visit the parent.
-		 */
-		return node->parent;
-	}
-}
-
-/*!
- * \internal
- * \brief Get the next non-empty node in ascending sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the next node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_next_full(struct rbtree_node *node)
-{
-	for (;;) {
-		node = rb_node_next(node);
-		if (!node || node->common.obj) {
-			return node;
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Get the next non-empty node in descending sequence.
- * \since 12.0.0
- *
- * \param node Starting node to find the previous node.
- *
- * \retval node on success.
- * \retval NULL if no node.
- */
-static struct rbtree_node *rb_node_prev_full(struct rbtree_node *node)
-{
-	for (;;) {
-		node = rb_node_prev(node);
-		if (!node || node->common.obj) {
-			return node;
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Determine which way to go from an empty node.
- * \since 12.0.0
- *
- * \param empty Empty node to determine which side obj_right goes on.
- * \param sort_fn Sort comparison function for non-empty nodes.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
- *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- * \param bias How to bias search direction for duplicates
- *
- * \return enum empty_node_direction to proceed.
- */
-static enum empty_node_direction rb_find_empty_direction(struct rbtree_node *empty, ao2_sort_fn *sort_fn, void *obj_right, enum search_flags flags, enum equal_node_bias bias)
-{
-	int cmp;
-	struct rbtree_node *cur;
-	struct rbtree_node *right_most;
-
-	/* Try for a quick definite go left. */
-	if (!empty->left) {
-		/* The empty node has no left child. */
-		return GO_RIGHT;
-	}
-	right_most = rb_node_most_right(empty->left);
-	if (right_most->common.obj) {
-		cmp = sort_fn(right_most->common.obj, obj_right, flags);
-		if (cmp < 0) {
-			return GO_RIGHT;
-		}
-		if (cmp == 0 && bias == BIAS_LAST) {
-			return GO_RIGHT;
-		}
-		return GO_LEFT;
-	}
-
-	/* Try for a quick definite go right. */
-	if (!empty->right) {
-		/* The empty node has no right child. */
-		return GO_LEFT;
-	}
-	cur = rb_node_most_left(empty->right);
-	if (cur->common.obj) {
-		cmp = sort_fn(cur->common.obj, obj_right, flags);
-		if (cmp > 0) {
-			return GO_LEFT;
-		}
-		if (cmp == 0 && bias == BIAS_FIRST) {
-			return GO_LEFT;
-		}
-		return GO_RIGHT;
-	}
-
-	/*
-	 * Have to scan the previous nodes from the right_most node of
-	 * the left subtree for the first non-empty node to determine
-	 * direction.
-	 */
-	cur = right_most;
-	for (;;) {
-		/* Find previous node. */
-		if (cur->left) {
-			cur = rb_node_most_right(cur->left);
-		} else {
-			/* Find the parent that the node is a right child of. */
-			for (;;) {
-				if (cur->parent == empty) {
-					/* The left side of the empty node is all empty nodes. */
-					return GO_RIGHT;
-				}
-				if (cur->parent->right == cur) {
-					/* We are the right child.  The parent is the previous node. */
-					cur = cur->parent;
-					break;
-				}
-				cur = cur->parent;
-			}
-		}
-
-		if (cur->common.obj) {
-			cmp = sort_fn(cur->common.obj, obj_right, flags);
-			if (cmp < 0) {
-				return GO_RIGHT;
-			}
-			if (cmp == 0 && bias == BIAS_LAST) {
-				return GO_RIGHT;
-			}
-			return GO_LEFT;
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Tree node rotation left.
- * \since 12.0.0
- *
- * \param self Container holding node.
- * \param node Node to perform a left rotation with.
- *
- *        p                         p
- *        |     Left rotation       |
- *        N        --->             Ch
- *       / \                       / \
- *      a  Ch                     N   c
- *        / \                    / \
- *       b   c                  a   b
- *
- * N = node
- * Ch = child
- * p = parent
- * a,b,c = other nodes that are unaffected by the rotation.
- *
- * \note It is assumed that the node's right child exists.
- *
- * \return Nothing
- */
-static void rb_rotate_left(struct ao2_container_rbtree *self, struct rbtree_node *node)
-{
-	struct rbtree_node *child;	/*!< Node's right child. */
-
-	child = node->right;
-
-	/* Link the node's parent to the child. */
-	if (!node->parent) {
-		/* Node is the root so we get a new root node. */
-		self->root = child;
-	} else if (node->parent->left == node) {
-		/* Node is a left child. */
-		node->parent->left = child;
-	} else {
-		/* Node is a right child. */
-		node->parent->right = child;
-	}
-	child->parent = node->parent;
-
-	/* Link node's right subtree to the child's left subtree. */
-	node->right = child->left;
-	if (node->right) {
-		node->right->parent = node;
-	}
-
-	/* Link the node to the child's left. */
-	node->parent = child;
-	child->left = node;
-}
-
-/*!
- * \internal
- * \brief Tree node rotation right.
- * \since 12.0.0
- *
- * \param self Container holding node.
- * \param node Node to perform a right rotation with.
- *
- *        p                         p
- *        |     Right rotation      |
- *        Ch                        N
- *       / \       <---            / \
- *      a  N                      Ch  c
- *        / \                    / \
- *       b   c                  a   b
- *
- * N = node
- * Ch = child
- * p = parent
- * a,b,c = other nodes that are unaffected by the rotation.
- *
- * \note It is assumed that the node's left child exists.
- *
- * \return Nothing
- */
-static void rb_rotate_right(struct ao2_container_rbtree *self, struct rbtree_node *node)
-{
-	struct rbtree_node *child;	/*!< Node's left child. */
-
-	child = node->left;
-
-	/* Link the node's parent to the child. */
-	if (!node->parent) {
-		/* Node is the root so we get a new root node. */
-		self->root = child;
-	} else if (node->parent->right == node) {
-		/* Node is a right child. */
-		node->parent->right = child;
-	} else {
-		/* Node is a left child. */
-		node->parent->left = child;
-	}
-	child->parent = node->parent;
-
-	/* Link node's left subtree to the child's right subtree. */
-	node->left = child->right;
-	if (node->left) {
-		node->left->parent = node;
-	}
-
-	/* Link the node to the child's right. */
-	node->parent = child;
-	child->right = node;
-}
-
-/*!
- * \internal
- * \brief Create an empty copy of this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- *
- * \retval empty-clone-container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *rb_ao2_alloc_empty_clone(struct ao2_container_rbtree *self)
-{
-	if (!is_ao2_object(self)) {
-		return NULL;
-	}
-
-	return ao2_t_container_alloc_rbtree(ao2_options_get(self), self->common.options,
-		self->common.sort_fn, self->common.cmp_fn, "Clone rbtree container");
-}
-
-/*!
- * \internal
- * \brief Create an empty copy of this container. (Debug version)
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- * \param ref_debug TRUE if to output a debug reference message.
- *
- * \retval empty-clone-container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *rb_ao2_alloc_empty_clone_debug(struct ao2_container_rbtree *self, const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	if (!is_ao2_object(self)) {
-		return NULL;
-	}
-
-	return __ao2_container_alloc_rbtree_debug(ao2_options_get(self), self->common.options,
-		self->common.sort_fn, self->common.cmp_fn, tag, file, line, func, ref_debug);
-}
-
-/*!
- * \internal
- * \brief Fixup the rbtree after deleting a node.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param child Child of the node just deleted from the container.
- *
- * \note The child must be a dummy black node if there really
- * was no child of the deleted node.  Otherwise, the caller must
- * pass in the parent node and which child was deleted.  In
- * addition, the fixup routine would be more complicated.
- *
- * \return Nothing
- */
-static void rb_delete_fixup(struct ao2_container_rbtree *self, struct rbtree_node *child)
-{
-	struct rbtree_node *sibling;
-
-	while (self->root != child && !child->is_red) {
-		if (child->parent->left == child) {
-			/* Child is a left child. */
-			sibling = child->parent->right;
-			ast_assert(sibling != NULL);
-			if (sibling->is_red) {
-				/* Case 1: The child's sibling is red. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_left[0]);
-				sibling->is_red = 0;
-				child->parent->is_red = 1;
-				rb_rotate_left(self, child->parent);
-				sibling = child->parent->right;
-				ast_assert(sibling != NULL);
-			}
-			/*
-			 * The sibling is black.  A black node must have two children,
-			 * or one red child, or no children.
-			 */
-			if ((!sibling->left || !sibling->left->is_red)
-				&& (!sibling->right || !sibling->right->is_red)) {
-				/*
-				 * Case 2: The sibling is black and both of its children are black.
-				 *
-				 * This case handles the two black children or no children
-				 * possibilities of a black node.
-				 */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_left[1]);
-				sibling->is_red = 1;
-				child = child->parent;
-			} else {
-				/* At this point the sibling has at least one red child. */
-				if (!sibling->right || !sibling->right->is_red) {
-					/*
-					 * Case 3: The sibling is black, its left child is red, and its
-					 * right child is black.
-					 */
-					AO2_DEVMODE_STAT(++self->stats.fixup_delete_left[2]);
-					ast_assert(sibling->left != NULL);
-					ast_assert(sibling->left->is_red);
-					sibling->left->is_red = 0;
-					sibling->is_red = 1;
-					rb_rotate_right(self, sibling);
-					sibling = child->parent->right;
-					ast_assert(sibling != NULL);
-				}
-				/* Case 4: The sibling is black and its right child is red. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_left[3]);
-				sibling->is_red = child->parent->is_red;
-				child->parent->is_red = 0;
-				if (sibling->right) {
-					sibling->right->is_red = 0;
-				}
-				rb_rotate_left(self, child->parent);
-				child = self->root;
-			}
-		} else {
-			/* Child is a right child. */
-			sibling = child->parent->left;
-			ast_assert(sibling != NULL);
-			if (sibling->is_red) {
-				/* Case 1: The child's sibling is red. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_right[0]);
-				sibling->is_red = 0;
-				child->parent->is_red = 1;
-				rb_rotate_right(self, child->parent);
-				sibling = child->parent->left;
-				ast_assert(sibling != NULL);
-			}
-			/*
-			 * The sibling is black.  A black node must have two children,
-			 * or one red child, or no children.
-			 */
-			if ((!sibling->right || !sibling->right->is_red)
-				&& (!sibling->left || !sibling->left->is_red)) {
-				/*
-				 * Case 2: The sibling is black and both of its children are black.
-				 *
-				 * This case handles the two black children or no children
-				 * possibilities of a black node.
-				 */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_right[1]);
-				sibling->is_red = 1;
-				child = child->parent;
-			} else {
-				/* At this point the sibling has at least one red child. */
-				if (!sibling->left || !sibling->left->is_red) {
-					/*
-					 * Case 3: The sibling is black, its right child is red, and its
-					 * left child is black.
-					 */
-					AO2_DEVMODE_STAT(++self->stats.fixup_delete_right[2]);
-					ast_assert(sibling->right != NULL);
-					ast_assert(sibling->right->is_red);
-					sibling->right->is_red = 0;
-					sibling->is_red = 1;
-					rb_rotate_left(self, sibling);
-					sibling = child->parent->left;
-					ast_assert(sibling != NULL);
-				}
-				/* Case 4: The sibling is black and its left child is red. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_delete_right[3]);
-				sibling->is_red = child->parent->is_red;
-				child->parent->is_red = 0;
-				if (sibling->left) {
-					sibling->left->is_red = 0;
-				}
-				rb_rotate_right(self, child->parent);
-				child = self->root;
-			}
-		}
-	}
-
-	/*
-	 * Case 2 could leave the child node red and it needs to leave
-	 * with it black.
-	 *
-	 * Case 4 sets the child node to the root which of course must
-	 * be black.
-	 */
-	child->is_red = 0;
-}
-
-/*!
- * \internal
- * \brief Delete the doomed node from this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param doomed Container node to delete from the container.
- *
- * \return Nothing
- */
-static void rb_delete_node(struct ao2_container_rbtree *self, struct rbtree_node *doomed)
-{
-	struct rbtree_node *child;
-	int need_fixup;
-
-	if (doomed->left && doomed->right) {
-		struct rbtree_node *next;
-		int is_red;
-
-		/*
-		 * The doomed node has two children.
-		 *
-		 * Find the next child node and swap it with the doomed node in
-		 * the tree.
-		 */
-		AO2_DEVMODE_STAT(++self->stats.delete_children[2]);
-		next = rb_node_most_left(doomed->right);
-		SWAP(doomed->parent, next->parent);
-		SWAP(doomed->left, next->left);
-		SWAP(doomed->right, next->right);
-		is_red = doomed->is_red;
-		doomed->is_red = next->is_red;
-		next->is_red = is_red;
-
-		/* Link back in the next node. */
-		if (!next->parent) {
-			/* Doomed was the root so we get a new root node. */
-			self->root = next;
-		} else if (next->parent->left == doomed) {
-			/* Doomed was the left child. */
-			next->parent->left = next;
-		} else {
-			/* Doomed was the right child. */
-			next->parent->right = next;
-		}
-		next->left->parent = next;
-		if (next->right == next) {
-			/* The next node was the right child of doomed. */
-			next->right = doomed;
-			doomed->parent = next;
-		} else {
-			next->right->parent = next;
-			doomed->parent->left = doomed;
-		}
-
-		/* The doomed node has no left child now. */
-		ast_assert(doomed->left == NULL);
-
-		/*
-		 * We don't have to link the right child back in with doomed
-		 * since we are going to link it with doomed's parent anyway.
-		 */
-		child = doomed->right;
-	} else {
-		/* Doomed has at most one child. */
-		child = doomed->left;
-		if (!child) {
-			child = doomed->right;
-		}
-	}
-	if (child) {
-		AO2_DEVMODE_STAT(++self->stats.delete_children[1]);
-	} else {
-		AO2_DEVMODE_STAT(++self->stats.delete_children[0]);
-	}
-
-	need_fixup = (!doomed->is_red && !self->common.destroying);
-	if (need_fixup && !child) {
-		/*
-		 * Use the doomed node as a place holder node for the
-		 * nonexistent child so we also don't have to pass to the fixup
-		 * routine the parent and which child the deleted node came
-		 * from.
-		 */
-		rb_delete_fixup(self, doomed);
-		ast_assert(doomed->left == NULL);
-		ast_assert(doomed->right == NULL);
-		ast_assert(!doomed->is_red);
-	}
-
-	/* Link the child in place of doomed. */
-	if (!doomed->parent) {
-		/* Doomed was the root so we get a new root node. */
-		self->root = child;
-	} else if (doomed->parent->left == doomed) {
-		/* Doomed was the left child. */
-		doomed->parent->left = child;
-	} else {
-		/* Doomed was the right child. */
-		doomed->parent->right = child;
-	}
-	if (child) {
-		child->parent = doomed->parent;
-		if (need_fixup) {
-			rb_delete_fixup(self, child);
-		}
-	}
-
-	AO2_DEVMODE_STAT(--self->common.nodes);
-}
-
-/*!
- * \internal
- * \brief Destroy a rbtree container node.
- * \since 12.0.0
- *
- * \param v_doomed Container node to destroy.
- *
- * \details
- * The container node unlinks itself from the container as part
- * of its destruction.  The node must be destroyed while the
- * container is already locked.
- *
- * \note The container must be locked when the node is
- * unreferenced.
- *
- * \return Nothing
- */
-static void rb_ao2_node_destructor(void *v_doomed)
-{
-	struct rbtree_node *doomed = v_doomed;
-
-	if (doomed->common.is_linked) {
-		struct ao2_container_rbtree *my_container;
-
-		/*
-		 * Promote to write lock if not already there.  Since
-		 * adjust_lock() can potentially release and block waiting for a
-		 * write lock, care must be taken to ensure that node references
-		 * are released before releasing the container references.
-		 *
-		 * Node references held by an iterator can only be held while
-		 * the iterator also holds a reference to the container.  These
-		 * node references must be unreferenced before the container can
-		 * be unreferenced to ensure that the node will not get a
-		 * negative reference and the destructor called twice for the
-		 * same node.
-		 */
-		my_container = (struct ao2_container_rbtree *) doomed->common.my_container;
-		__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
-
-#if defined(AO2_DEBUG)
-		if (!my_container->common.destroying
-			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
-			ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
-		}
-#endif	/* defined(AO2_DEBUG) */
-		rb_delete_node(my_container, doomed);
-#if defined(AO2_DEBUG)
-		if (!my_container->common.destroying
-			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
-			ast_log(LOG_ERROR, "Container integrity failed after node deletion.\n");
-		}
-#endif	/* defined(AO2_DEBUG) */
-	}
-
-	/*
-	 * We could have an object in the node if the container is being
-	 * destroyed or the node had not been linked in yet.
-	 */
-	if (doomed->common.obj) {
-		__container_unlink_node(&doomed->common, AO2_UNLINK_NODE_UNLINK_OBJECT);
-	}
-}
-
-/*!
- * \internal
- * \brief Create a new container node.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param obj_new Object to put into the node.
- * \param tag used for debugging.
- * \param file Debug file name invoked from
- * \param line Debug line invoked from
- * \param func Debug function name invoked from
- *
- * \retval initialized-node on success.
- * \retval NULL on error.
- */
-static struct rbtree_node *rb_ao2_new_node(struct ao2_container_rbtree *self, void *obj_new, const char *tag, const char *file, int line, const char *func)
-{
-	struct rbtree_node *node;
-
-	node = __ao2_alloc(sizeof(*node), rb_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!node) {
-		return NULL;
-	}
-
-	if (tag) {
-		__ao2_ref_debug(obj_new, +1, tag, file, line, func);
-	} else {
-		ao2_t_ref(obj_new, +1, "Container node creation");
-	}
-	node->common.obj = obj_new;
-	node->common.my_container = (struct ao2_container *) self;
-
-	return node;
-}
-
-/*!
- * \internal
- * \brief Fixup the rbtree after inserting a node.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param node Container node just inserted into the container.
- *
- * \note The just inserted node is red.
- *
- * \return Nothing
- */
-static void rb_insert_fixup(struct ao2_container_rbtree *self, struct rbtree_node *node)
-{
-	struct rbtree_node *g_parent;	/* Grand parent node. */
-
-	while (node->parent && node->parent->is_red) {
-		g_parent = node->parent->parent;
-
-		/* The grand parent must exist if the parent is red. */
-		ast_assert(g_parent != NULL);
-
-		if (node->parent == g_parent->left) {
-			/* The parent is a left child. */
-			if (g_parent->right && g_parent->right->is_red) {
-				/* Case 1: Push the black down from the grand parent node. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_insert_left[0]);
-				g_parent->right->is_red = 0;
-				g_parent->left->is_red = 0;
-				g_parent->is_red = 1;
-
-				node = g_parent;
-			} else {
-				/* The uncle node is black. */
-				if (node->parent->right == node) {
-					/*
-					 * Case 2: The node is a right child.
-					 *
-					 * Which node is the grand parent does not change.
-					 */
-					AO2_DEVMODE_STAT(++self->stats.fixup_insert_left[1]);
-					node = node->parent;
-					rb_rotate_left(self, node);
-				}
-				/* Case 3: The node is a left child. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_insert_left[2]);
-				node->parent->is_red = 0;
-				g_parent->is_red = 1;
-				rb_rotate_right(self, g_parent);
-			}
-		} else {
-			/* The parent is a right child. */
-			if (g_parent->left && g_parent->left->is_red) {
-				/* Case 1: Push the black down from the grand parent node. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_insert_right[0]);
-				g_parent->left->is_red = 0;
-				g_parent->right->is_red = 0;
-				g_parent->is_red = 1;
-
-				node = g_parent;
-			} else {
-				/* The uncle node is black. */
-				if (node->parent->left == node) {
-					/*
-					 * Case 2: The node is a left child.
-					 *
-					 * Which node is the grand parent does not change.
-					 */
-					AO2_DEVMODE_STAT(++self->stats.fixup_insert_right[1]);
-					node = node->parent;
-					rb_rotate_right(self, node);
-				}
-				/* Case 3: The node is a right child. */
-				AO2_DEVMODE_STAT(++self->stats.fixup_insert_right[2]);
-				node->parent->is_red = 0;
-				g_parent->is_red = 1;
-				rb_rotate_left(self, g_parent);
-			}
-		}
-	}
-
-	/*
-	 * The root could be red here because:
-	 * 1) We just inserted the root node in an empty tree.
-	 *
-	 * 2) Case 1 could leave the root red if the grand parent were
-	 * the root.
-	 */
-	self->root->is_red = 0;
-}
-
-/*!
- * \internal
- * \brief Insert a node into this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param node Container node to insert into the container.
- *
- * \return enum ao2_container_insert value.
- */
-static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree *self, struct rbtree_node *node)
-{
-	int cmp;
-	struct rbtree_node *cur;
-	struct rbtree_node *next;
-	ao2_sort_fn *sort_fn;
-	uint32_t options;
-	enum equal_node_bias bias;
-
-	if (!self->root) {
-		/* The tree is empty. */
-		self->root = node;
-		return AO2_CONTAINER_INSERT_NODE_INSERTED;
-	}
-
-	sort_fn = self->common.sort_fn;
-	options = self->common.options;
-	switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-	default:
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-		if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
-			bias = BIAS_FIRST;
-		} else {
-			bias = BIAS_LAST;
-		}
-		break;
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-		bias = BIAS_EQUAL;
-		break;
-	}
-
-	/*
-	 * New nodes are always colored red when initially inserted into
-	 * the tree.  (Except for the root which is always black.)
-	 */
-	node->is_red = 1;
-
-	/* Find node where normal insert would put a new node. */
-	cur = self->root;
-	for (;;) {
-		if (!cur->common.obj) {
-			/* Which direction do we go to insert this node? */
-			if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_SEARCH_OBJECT, bias)
-				== GO_LEFT) {
-				if (cur->left) {
-					cur = cur->left;
-					continue;
-				}
-
-				/* Node becomes a left child */
-				cur->left = node;
-				node->parent = cur;
-				rb_insert_fixup(self, node);
-				return AO2_CONTAINER_INSERT_NODE_INSERTED;
-			}
-			if (cur->right) {
-				cur = cur->right;
-				continue;
-			}
-
-			/* Node becomes a right child */
-			cur->right = node;
-			node->parent = cur;
-			rb_insert_fixup(self, node);
-			return AO2_CONTAINER_INSERT_NODE_INSERTED;
-		}
-		cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-		if (cmp > 0) {
-			if (cur->left) {
-				cur = cur->left;
-				continue;
-			}
-
-			/* Node becomes a left child */
-			cur->left = node;
-			node->parent = cur;
-			rb_insert_fixup(self, node);
-			return AO2_CONTAINER_INSERT_NODE_INSERTED;
-		} else if (cmp < 0) {
-			if (cur->right) {
-				cur = cur->right;
-				continue;
-			}
-
-			/* Node becomes a right child */
-			cur->right = node;
-			node->parent = cur;
-			rb_insert_fixup(self, node);
-			return AO2_CONTAINER_INSERT_NODE_INSERTED;
-		}
-		switch (bias) {
-		case BIAS_FIRST:
-			/* Duplicate nodes unconditionally accepted. */
-			if (cur->left) {
-				cur = cur->left;
-				continue;
-			}
-
-			/* Node becomes a left child */
-			cur->left = node;
-			node->parent = cur;
-			rb_insert_fixup(self, node);
-			return AO2_CONTAINER_INSERT_NODE_INSERTED;
-		case BIAS_EQUAL:
-			break;
-		case BIAS_LAST:
-			/* Duplicate nodes unconditionally accepted. */
-			if (cur->right) {
-				cur = cur->right;
-				continue;
-			}
-
-			/* Node becomes a right child */
-			cur->right = node;
-			node->parent = cur;
-			rb_insert_fixup(self, node);
-			return AO2_CONTAINER_INSERT_NODE_INSERTED;
-		}
-
-		break;
-	}
-
-	/* Node is a dupliate */
-	switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-	default:
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-		ast_assert(0);/* Case already handled by BIAS_FIRST/BIAS_LAST. */
-		return AO2_CONTAINER_INSERT_NODE_REJECTED;
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-		/* Reject all objects with the same key. */
-		return AO2_CONTAINER_INSERT_NODE_REJECTED;
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-		if (cur->common.obj == node->common.obj) {
-			/* Reject inserting the same object */
-			return AO2_CONTAINER_INSERT_NODE_REJECTED;
-		}
-		next = cur;
-		if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
-			/* Search to end of duplicates for the same object. */
-			for (;;) {
-				next = rb_node_next_full(next);
-				if (!next) {
-					break;
-				}
-				if (next->common.obj == node->common.obj) {
-					/* Reject inserting the same object */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp) {
-					break;
-				}
-			}
-
-			/* Find first duplicate node. */
-			for (;;) {
-				next = rb_node_prev_full(cur);
-				if (!next) {
-					break;
-				}
-				if (next->common.obj == node->common.obj) {
-					/* Reject inserting the same object */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp) {
-					break;
-				}
-				cur = next;
-			}
-			if (!cur->left) {
-				/* Node becomes a left child */
-				cur->left = node;
-			} else {
-				/* Node becomes a right child */
-				cur = rb_node_most_right(cur->left);
-				cur->right = node;
-			}
-		} else {
-			/* Search to beginning of duplicates for the same object. */
-			for (;;) {
-				next = rb_node_prev_full(next);
-				if (!next) {
-					break;
-				}
-				if (next->common.obj == node->common.obj) {
-					/* Reject inserting the same object */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp) {
-					break;
-				}
-			}
-
-			/* Find last duplicate node. */
-			for (;;) {
-				next = rb_node_next_full(cur);
-				if (!next) {
-					break;
-				}
-				if (next->common.obj == node->common.obj) {
-					/* Reject inserting the same object */
-					return AO2_CONTAINER_INSERT_NODE_REJECTED;
-				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
-				if (cmp) {
-					break;
-				}
-				cur = next;
-			}
-			if (!cur->right) {
-				/* Node becomes a right child */
-				cur->right = node;
-			} else {
-				/* Node becomes a left child */
-				cur = rb_node_most_left(cur->right);
-				cur->left = node;
-			}
-		}
-		break;
-	case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-		SWAP(cur->common.obj, node->common.obj);
-		ao2_t_ref(node, -1, "Don't need the new node.");
-		return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
-	}
-
-	/* Complete inserting duplicate node. */
-	node->parent = cur;
-	rb_insert_fixup(self, node);
-	return AO2_CONTAINER_INSERT_NODE_INSERTED;
-}
-
-/*!
- * \internal
- * \brief Find the next rbtree container node in a traversal.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param state Traversal state to restart rbtree container traversal.
- * \param prev Previous node returned by the traversal search functions.
- *    The ref ownership is passed back to this function.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, struct rbtree_traversal_state *state, struct rbtree_node *prev)
-{
-	struct rbtree_node *node;
-	void *arg;
-	enum search_flags flags;
-	int cmp;
-
-	arg = state->arg;
-	flags = state->flags;
-
-	node = prev;
-	for (;;) {
-		/* Find next node in traversal order. */
-		switch (flags & OBJ_ORDER_MASK) {
-		default:
-		case OBJ_ORDER_ASCENDING:
-			node = rb_node_next(node);
-			break;
-		case OBJ_ORDER_DESCENDING:
-			node = rb_node_prev(node);
-			break;
-		case OBJ_ORDER_PRE:
-			node = rb_node_pre(node);
-			break;
-		case OBJ_ORDER_POST:
-			node = rb_node_post(node);
-			break;
-		}
-		if (!node) {
-			/* No more nodes left to traverse. */
-			break;
-		}
-		if (!node->common.obj) {
-			/* Node is empty */
-			continue;
-		}
-
-		if (state->sort_fn) {
-			/* Filter node through the sort_fn */
-			cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
-			if (cmp) {
-				/* No more nodes in this container are possible to match. */
-				break;
-			}
-		}
-
-		/* We have the next traversal node */
-		__ao2_ref(node, +1);
-
-		/*
-		 * Dereferencing the prev node may result in our next node
-		 * object being removed by another thread.  This could happen if
-		 * the container uses RW locks and the container was read
-		 * locked.
-		 */
-		__ao2_ref(prev, -1);
-		if (node->common.obj) {
-			return node;
-		}
-		prev = node;
-	}
-
-	/* No more nodes in the container left to traverse. */
-	__ao2_ref(prev, -1);
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Find an initial matching node.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
- *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- * \param bias How to bias search direction for duplicates
- *
- * \retval node on success.
- * \retval NULL if not found.
- */
-static struct rbtree_node *rb_find_initial(struct ao2_container_rbtree *self, void *obj_right, enum search_flags flags, enum equal_node_bias bias)
-{
-	int cmp;
-	enum search_flags sort_flags;
-	struct rbtree_node *node;
-	struct rbtree_node *next = NULL;
-	ao2_sort_fn *sort_fn;
-
-	sort_flags = flags & OBJ_SEARCH_MASK;
-	sort_fn = self->common.sort_fn;
-
-	/* Find node where normal search would find it. */
-	node = self->root;
-	if (!node) {
-		return NULL;
-	}
-	for (;;) {
-		if (!node->common.obj) {
-			/* Which direction do we go to find the node? */
-			if (rb_find_empty_direction(node, sort_fn, obj_right, sort_flags, bias)
-				== GO_LEFT) {
-				next = node->left;
-			} else {
-				next = node->right;
-			}
-			if (!next) {
-				switch (bias) {
-				case BIAS_FIRST:
-					/* Check successor node for match. */
-					next = rb_node_next_full(node);
-					break;
-				case BIAS_EQUAL:
-					break;
-				case BIAS_LAST:
-					/* Check previous node for match. */
-					next = rb_node_prev_full(node);
-					break;
-				}
-				if (next) {
-					cmp = sort_fn(next->common.obj, obj_right, sort_flags);
-					if (cmp == 0) {
-						/* Found the first/last matching node. */
-						return next;
-					}
-					next = NULL;
-				}
-
-				/* No match found. */
-				return next;
-			}
-		} else {
-			cmp = sort_fn(node->common.obj, obj_right, sort_flags);
-			if (cmp > 0) {
-				next = node->left;
-			} else if (cmp < 0) {
-				next = node->right;
-			} else {
-				switch (bias) {
-				case BIAS_FIRST:
-					next = node->left;
-					break;
-				case BIAS_EQUAL:
-					return node;
-				case BIAS_LAST:
-					next = node->right;
-					break;
-				}
-				if (!next) {
-					/* Found the first/last matching node. */
-					return node;
-				}
-			}
-			if (!next) {
-				switch (bias) {
-				case BIAS_FIRST:
-					if (cmp < 0) {
-						/* Check successor node for match. */
-						next = rb_node_next_full(node);
-					}
-					break;
-				case BIAS_EQUAL:
-					break;
-				case BIAS_LAST:
-					if (cmp > 0) {
-						/* Check previous node for match. */
-						next = rb_node_prev_full(node);
-					}
-					break;
-				}
-				if (next) {
-					cmp = sort_fn(next->common.obj, obj_right, sort_flags);
-					if (cmp == 0) {
-						/* Found the first/last matching node. */
-						return next;
-					}
-				}
-
-				/* No match found. */
-				return NULL;
-			}
-		}
-		node = next;
-	}
-}
-
-/*!
- * \internal
- * \brief Find the first rbtree container node in a traversal.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param flags search_flags to control traversing the container
- * \param arg Comparison callback arg parameter.
- * \param state Traversal state to restart rbtree container traversal.
- *
- * \retval node-ptr of found node (Reffed).
- * \retval NULL when no node found.
- */
-static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self, enum search_flags flags, void *arg, struct rbtree_traversal_state *state)
-{
-	struct rbtree_node *node;
-	enum equal_node_bias bias;
-
-	if (self->common.destroying) {
-		/* Force traversal to be post order for tree destruction. */
-		flags = OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | OBJ_ORDER_POST;
-	}
-
-	memset(state, 0, sizeof(*state));
-	state->arg = arg;
-	state->flags = flags;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-	case OBJ_SEARCH_KEY:
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* We are asked to do a directed search. */
-		state->sort_fn = self->common.sort_fn;
-		break;
-	default:
-		/* Don't know, let's visit all nodes */
-		state->sort_fn = NULL;
-		break;
-	}
-
-	if (!self->root) {
-		/* Tree is empty. */
-		return NULL;
-	}
-
-	/* Find first traversal node. */
-	switch (flags & OBJ_ORDER_MASK) {
-	default:
-	case OBJ_ORDER_ASCENDING:
-		if (!state->sort_fn) {
-			/* Find left most child. */
-			node = rb_node_most_left(self->root);
-			if (!node->common.obj) {
-				node = rb_node_next_full(node);
-				if (!node) {
-					return NULL;
-				}
-			}
-			break;
-		}
-
-		/* Search for initial node. */
-		switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-			if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
-				/* There are no duplicates allowed. */
-				bias = BIAS_EQUAL;
-				break;
-			}
-			/* Fall through */
-		default:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-			/* Find first duplicate node. */
-			bias = BIAS_FIRST;
-			break;
-		}
-		node = rb_find_initial(self, arg, flags, bias);
-		if (!node) {
-			return NULL;
-		}
-		break;
-	case OBJ_ORDER_DESCENDING:
-		if (!state->sort_fn) {
-			/* Find right most child. */
-			node = rb_node_most_right(self->root);
-			if (!node->common.obj) {
-				node = rb_node_prev_full(node);
-				if (!node) {
-					return NULL;
-				}
-			}
-			break;
-		}
-
-		/* Search for initial node. */
-		switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-			if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
-				/* There are no duplicates allowed. */
-				bias = BIAS_EQUAL;
-				break;
-			}
-			/* Fall through */
-		default:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
-		case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
-			/* Find last duplicate node. */
-			bias = BIAS_LAST;
-			break;
-		}
-		node = rb_find_initial(self, arg, flags, bias);
-		if (!node) {
-			return NULL;
-		}
-		break;
-	case OBJ_ORDER_PRE:
-		/* This is a tree structure traversal so we must visit all nodes. */
-		state->sort_fn = NULL;
-
-		node = self->root;
-
-		/* Find a non-empty node. */
-		while (!node->common.obj) {
-			node = rb_node_pre(node);
-			if (!node) {
-				return NULL;
-			}
-		}
-		break;
-	case OBJ_ORDER_POST:
-		/* This is a tree structure traversal so we must visit all nodes. */
-		state->sort_fn = NULL;
-
-		/* Find the left most childless node. */
-		node = self->root;
-		for (;;) {
-			node = rb_node_most_left(node);
-			if (!node->right) {
-				/* This node has no children. */
-				break;
-			}
-			node = node->right;
-		}
-
-		/* Find a non-empty node. */
-		while (!node->common.obj) {
-			node = rb_node_post(node);
-			if (!node) {
-				return NULL;
-			}
-		}
-		break;
-	}
-
-	/* We have the first traversal node */
-	__ao2_ref(node, +1);
-	return node;
-}
-
-/*!
- * \internal
- * \brief Find the next non-empty iteration node in the container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- * \param node Previous node returned by the iterator.
- * \param flags search_flags to control iterating the container.
- *   Only AO2_ITERATOR_DESCENDING is useful by the method.
- *
- * \note The container is already locked.
- *
- * \retval node on success.
- * \retval NULL on error or no more nodes in the container.
- */
-static struct rbtree_node *rb_ao2_iterator_next(struct ao2_container_rbtree *self, struct rbtree_node *node, enum ao2_iterator_flags flags)
-{
-	if (flags & AO2_ITERATOR_DESCENDING) {
-		if (!node) {
-			/* Find right most node. */
-			if (!self->root) {
-				return NULL;
-			}
-			node = rb_node_most_right(self->root);
-			if (node->common.obj) {
-				/* Found a non-empty node. */
-				return node;
-			}
-		}
-		/* Find next non-empty node. */
-		node = rb_node_prev_full(node);
-	} else {
-		if (!node) {
-			/* Find left most node. */
-			if (!self->root) {
-				return NULL;
-			}
-			node = rb_node_most_left(self->root);
-			if (node->common.obj) {
-				/* Found a non-empty node. */
-				return node;
-			}
-		}
-		/* Find next non-empty node. */
-		node = rb_node_next_full(node);
-	}
-
-	return node;
-}
-
-/*!
- * \internal
- *
- * \brief Destroy this container.
- * \since 12.0.0
- *
- * \param self Container to operate upon.
- *
- * \return Nothing
- */
-static void rb_ao2_destroy(struct ao2_container_rbtree *self)
-{
-	/* Check that the container no longer has any nodes */
-	if (self->root) {
-		ast_log(LOG_ERROR, "Node ref leak.  Red-Black tree container still has nodes!\n");
-		ast_assert(0);
-	}
-}
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Display contents of the specified container.
- * \since 12.0.0
- *
- * \param self Container to dump.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
- *
- * \return Nothing
- */
-static void rb_ao2_dump(struct ao2_container_rbtree *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
-{
-#define FORMAT  "%16s, %16s, %16s, %16s, %5s, %16s, %s\n"
-#define FORMAT2 "%16p, %16p, %16p, %16p, %5s, %16p, "
-
-	struct rbtree_node *node;
-
-	prnt(where, FORMAT, "Node", "Parent", "Left", "Right", "Color", "Obj", "Key");
-	for (node = self->root; node; node = rb_node_pre(node)) {
-		prnt(where, FORMAT2,
-			node,
-			node->parent,
-			node->left,
-			node->right,
-			node->is_red ? "Red" : "Black",
-			node->common.obj);
-		if (node->common.obj && prnt_obj) {
-			prnt_obj(node->common.obj, where, prnt);
-		}
-		prnt(where, "\n");
-	}
-
-#undef FORMAT
-#undef FORMAT2
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Display statistics of the specified container.
- * \since 12.0.0
- *
- * \param self Container to display statistics.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \note The container is already locked for reading.
- *
- * \return Nothing
- */
-static void rb_ao2_stats(struct ao2_container_rbtree *self, void *where, ao2_prnt_fn *prnt)
-{
-	int idx;
-
-	for (idx = 0; idx < ARRAY_LEN(self->stats.fixup_insert_left); ++idx) {
-		prnt(where, "Number of left insert fixups case %d: %d\n", idx + 1,
-			self->stats.fixup_insert_left[idx]);
-	}
-	for (idx = 0; idx < ARRAY_LEN(self->stats.fixup_insert_right); ++idx) {
-		prnt(where, "Number of right insert fixups case %d: %d\n", idx + 1,
-			self->stats.fixup_insert_right[idx]);
-	}
-
-	for (idx = 0; idx < ARRAY_LEN(self->stats.delete_children); ++idx) {
-		prnt(where, "Number of nodes deleted with %d children: %d\n", idx,
-			self->stats.delete_children[idx]);
-	}
-	for (idx = 0; idx < ARRAY_LEN(self->stats.fixup_delete_left); ++idx) {
-		prnt(where, "Number of left delete fixups case %d: %d\n", idx + 1,
-			self->stats.fixup_delete_left[idx]);
-	}
-	for (idx = 0; idx < ARRAY_LEN(self->stats.fixup_delete_right); ++idx) {
-		prnt(where, "Number of right delete fixups case %d: %d\n", idx + 1,
-			self->stats.fixup_delete_right[idx]);
-	}
-}
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Check the black height of the given node.
- * \since 12.0.0
- *
- * \param node Node to check black height.
- *
- * \retval black-height of node on success.
- * \retval -1 on error.  Node black height did not balance.
- */
-static int rb_check_black_height(struct rbtree_node *node)
-{
-	int height_left;
-	int height_right;
-
-	if (!node) {
-		/* A NULL child is a black node. */
-		return 0;
-	}
-
-	height_left = rb_check_black_height(node->left);
-	if (height_left < 0) {
-		return -1;
-	}
-	height_right = rb_check_black_height(node->right);
-	if (height_right < 0) {
-		return -1;
-	}
-	if (height_left != height_right) {
-		ast_log(LOG_ERROR,
-			"Tree node black height of children does not match! L:%d != R:%d\n",
-			height_left, height_right);
-		return -1;
-	}
-	if (!node->is_red) {
-		/* The node itself is black. */
-		++height_left;
-	}
-	return height_left;
-}
-
-#endif	/* defined(AO2_DEBUG) */
-
-#if defined(AO2_DEBUG)
-/*!
- * \internal
- * \brief Perform an integrity check on the specified container.
- * \since 12.0.0
- *
- * \param self Container to check integrity.
- *
- * \note The container is already locked for reading.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int rb_ao2_integrity(struct ao2_container_rbtree *self)
-{
-	int res;
-	int count_node;
-	int count_obj;
-	void *obj_last;
-	struct rbtree_node *node;
-
-	res = 0;
-
-	count_node = 0;
-	count_obj = 0;
-
-	/*
-	 * See the properties listed at struct rbtree_node definition.
-	 *
-	 * The rbtree properties 1 and 3 are not testable.
-	 *
-	 * Property 1 is not testable because we are not rebalancing at
-	 * this time so all nodes are either red or black.
-	 *
-	 * Property 3 is not testable because it is the definition of a
-	 * NULL child.
-	 */
-	if (self->root) {
-		/* Check tree links. */
-		if (self->root->parent) {
-			if (self->root->parent == self->root) {
-				ast_log(LOG_ERROR, "Tree root parent pointer points to itself!\n");
-			} else {
-				ast_log(LOG_ERROR, "Tree root is not a root node!\n");
-			}
-			return -1;
-		}
-		if (self->root->is_red) {
-			/* Violation rbtree property 2. */
-			ast_log(LOG_ERROR, "Tree root is red!\n");
-			res = -1;
-		}
-		node = self->root;
-		do {
-			if (node->left) {
-				if (node->left == node) {
-					ast_log(LOG_ERROR, "Tree node's left pointer points to itself!\n");
-					return -1;
-				}
-				if (node->left->parent != node) {
-					ast_log(LOG_ERROR, "Tree node's left child does not link back!\n");
-					return -1;
-				}
-			}
-			if (node->right) {
-				if (node->right == node) {
-					ast_log(LOG_ERROR, "Tree node's right pointer points to itself!\n");
-					return -1;
-				}
-				if (node->right->parent != node) {
-					ast_log(LOG_ERROR, "Tree node's right child does not link back!\n");
-					return -1;
-				}
-			}
-
-			/* Check red/black node flags. */
-			if (node->is_red) {
-				/* A red node must have two black children or no children. */
-				if (node->left && node->right) {
-					/* Node has two children. */
-					if (node->left->is_red) {
-						/* Violation rbtree property 4. */
-						ast_log(LOG_ERROR, "Tree node is red and its left child is red!\n");
-						res = -1;
-					}
-					if (node->right->is_red) {
-						/* Violation rbtree property 4. */
-						ast_log(LOG_ERROR, "Tree node is red and its right child is red!\n");
-						res = -1;
-					}
-				} else if (node->left || node->right) {
-					/*
-					 * Violation rbtree property 4 if the child is red.
-					 * Violation rbtree property 5 if the child is black.
-					 */
-					ast_log(LOG_ERROR, "Tree node is red and it only has one child!\n");
-					res = -1;
-				}
-			} else {
-				/*
-				 * A black node must have two children, or one red child, or no
-				 * children.  If the black node has two children and only one of
-				 * them is red, that red child must have two children.
-				 */
-				if (node->left && node->right) {
-					/* Node has two children. */
-					if (node->left->is_red != node->right->is_red) {
-						/* The children are not the same color. */
-						struct rbtree_node *red;
-
-						if (node->left->is_red) {
-							red = node->left;
-						} else {
-							red = node->right;
-						}
-						if (!red->left || !red->right) {
-							/* Violation rbtree property 5. */
-							ast_log(LOG_ERROR,
-								"Tree node is black and the red child does not have two children!\n");
-							res = -1;
-						}
-					}
-				} else if ((node->left && !node->left->is_red)
-					|| (node->right && !node->right->is_red)) {
-					/* Violation rbtree property 5. */
-					ast_log(LOG_ERROR, "Tree node is black and its only child is black!\n");
-					res = -1;
-				}
-			}
-
-			/* Count nodes and objects. */
-			++count_node;
-			if (node->common.obj) {
-				++count_obj;
-			}
-
-			node = rb_node_pre(node);
-		} while (node);
-
-		/* Check node key sort order. */
-		obj_last = NULL;
-		for (node = rb_node_most_left(self->root); node; node = rb_node_next(node)) {
-			if (!node->common.obj) {
-				/* Node is empty. */
-				continue;
-			}
-
-			if (obj_last) {
-				if (self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
-					ast_log(LOG_ERROR, "Tree nodes are out of sorted order!\n");
-					return -1;
-				}
-			}
-			obj_last = node->common.obj;
-		}
-
-		/* Completely check property 5 */
-		if (!res && rb_check_black_height(self->root) < 0) {
-			/* Violation rbtree property 5. */
-			res = -1;
-		}
-	}
-
-	/* Check total obj count. */
-	if (count_obj != ao2_container_count(&self->common)) {
-		ast_log(LOG_ERROR, "Total object count does not match ao2_container_count()!\n");
-		return -1;
-	}
-
-	/* Check total node count. */
-	if (count_node != self->common.nodes) {
-		ast_log(LOG_ERROR, "Total node count of %d does not match stat of %d!\n",
-			count_node, self->common.nodes);
-		return -1;
-	}
-
-	return res;
-}
-#endif	/* defined(AO2_DEBUG) */
-
-/*! rbtree container virtual method table. */
-static const struct ao2_container_methods v_table_rbtree = {
-	.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) rb_ao2_alloc_empty_clone,
-	.alloc_empty_clone_debug =
-		(ao2_container_alloc_empty_clone_debug_fn) rb_ao2_alloc_empty_clone_debug,
-	.new_node = (ao2_container_new_node_fn) rb_ao2_new_node,
-	.insert = (ao2_container_insert_fn) rb_ao2_insert_node,
-	.traverse_first = (ao2_container_find_first_fn) rb_ao2_find_first,
-	.traverse_next = (ao2_container_find_next_fn) rb_ao2_find_next,
-	.iterator_next = (ao2_iterator_next_fn) rb_ao2_iterator_next,
-	.destroy = (ao2_container_destroy_fn) rb_ao2_destroy,
-#if defined(AO2_DEBUG)
-	.dump = (ao2_container_display) rb_ao2_dump,
-	.stats = (ao2_container_statistics) rb_ao2_stats,
-	.integrity = (ao2_container_integrity) rb_ao2_integrity,
-#endif	/* defined(AO2_DEBUG) */
-};
-
-/*!
- * \brief Initialize a rbtree container.
- *
- * \param self Container to initialize.
- * \param options Container behaviour options (See enum ao2_container_opts)
- * \param sort_fn Pointer to a sort function.
- * \param cmp_fn Pointer to a compare function used by ao2_find.
- *
- * \return A pointer to a struct container.
- */
-static struct ao2_container *rb_ao2_container_init(struct ao2_container_rbtree *self,
-	unsigned int options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
-{
-	if (!self) {
-		return NULL;
-	}
-
-	self->common.v_table = &v_table_rbtree;
-	self->common.sort_fn = sort_fn;
-	self->common.cmp_fn = cmp_fn;
-	self->common.options = options;
-
-#ifdef AO2_DEBUG
-	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif	/* defined(AO2_DEBUG) */
-
-	return (struct ao2_container *) self;
-}
-
-struct ao2_container *__ao2_container_alloc_rbtree(unsigned int ao2_options, unsigned int container_options,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
-{
-	struct ao2_container_rbtree *self;
-
-	if (!sort_fn) {
-		/* Sanity checks. */
-		ast_log(LOG_ERROR, "Missing sort_fn()!\n");
-		return NULL;
-	}
-
-	self = ao2_t_alloc_options(sizeof(*self), container_destruct, ao2_options,
-		"New rbtree container");
-	return rb_ao2_container_init(self, container_options, sort_fn, cmp_fn);
-}
-
-struct ao2_container *__ao2_container_alloc_rbtree_debug(unsigned int ao2_options, unsigned int container_options,
-	ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
-	const char *tag, const char *file, int line, const char *func, int ref_debug)
-{
-	struct ao2_container_rbtree *self;
-
-	if (!sort_fn) {
-		/* Sanity checks. */
-		ast_log(__LOG_ERROR, file, line, func, "Missing sort_fn()!\n");
-		return NULL;
-	}
-
-	self = __ao2_alloc_debug(sizeof(*self),
-		ref_debug ? container_destruct_debug : container_destruct, ao2_options,
-		tag, file, line, func, ref_debug);
-	return rb_ao2_container_init(self, container_options, sort_fn, cmp_fn);
-}
-
diff --git a/main/audiohook.c b/main/audiohook.c
index 01b5ee0..c1df580 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426803 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 
@@ -41,14 +41,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426803 $")
 #include "asterisk/slinfactory.h"
 #include "asterisk/frame.h"
 #include "asterisk/translate.h"
-#include "asterisk/format_cache.h"
 
 #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */
 #define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE 100 /*!< When small queue is enabled, this is the maximum amount of audio that can remain queued at a time. */
 
+#define DEFAULT_INTERNAL_SAMPLE_RATE 8000
+
 struct ast_audiohook_translate {
 	struct ast_trans_pvt *trans_pvt;
-	struct ast_format *format;
+	struct ast_format format;
 };
 
 struct ast_audiohook_list {
@@ -57,7 +58,17 @@ struct ast_audiohook_list {
 	 * variable will be set and the sample rate will
 	 * be preserved during ast_audiohook_write_list()*/
 	int native_slin_compatible;
-	int list_internal_samp_rate;/*!< Internal sample rate used when writing to the audiohook list */
+
+	/*
+	 * The internal sample rate is used when writing to the audiohook lists and
+	 * should always be set to the highest value between formats and audiohooks.
+	 *
+	 * During audiohook invocation (see write_list) if native slin is turned off
+ 	 * the highest sample rate is determined as each audiohook is processed.
+	 * If it is turned on then the audiohooks are also updated with the current
+	 * highest sample rate.
+	*/
+	int list_internal_samp_rate;
 
 	struct ast_audiohook_translate in_translate[2];
 	struct ast_audiohook_translate out_translate[2];
@@ -68,7 +79,7 @@ struct ast_audiohook_list {
 
 static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset)
 {
-	struct ast_format *slin;
+	struct ast_format slin;
 
 	if (audiohook->hook_internal_samp_rate == rate) {
 		return 0;
@@ -76,32 +87,31 @@ static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate
 
 	audiohook->hook_internal_samp_rate = rate;
 
-	slin = ast_format_cache_get_slin_by_rate(rate);
-
+	ast_format_set(&slin, ast_format_slin_by_rate(rate), 0);
 	/* Setup the factories that are needed for this audiohook type */
 	switch (audiohook->type) {
 	case AST_AUDIOHOOK_TYPE_SPY:
-	case AST_AUDIOHOOK_TYPE_WHISPER:
 		if (reset) {
 			ast_slinfactory_destroy(&audiohook->read_factory);
+		}
+		ast_slinfactory_init_with_format(&audiohook->read_factory, &slin);
+		/* fall through */
+	case AST_AUDIOHOOK_TYPE_WHISPER:
+		if (reset) {
 			ast_slinfactory_destroy(&audiohook->write_factory);
 		}
-		ast_slinfactory_init_with_format(&audiohook->read_factory, slin);
-		ast_slinfactory_init_with_format(&audiohook->write_factory, slin);
+		ast_slinfactory_init_with_format(&audiohook->write_factory, &slin);
 		break;
 	default:
 		break;
 	}
-
 	return 0;
 }
 
 /*! \brief Initialize an audiohook structure
- *
  * \param audiohook Audiohook structure
  * \param type
- * \param source, init_flags
- *
+ * \param source
  * \return Returns 0 on success, -1 on failure
  */
 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
@@ -117,7 +127,7 @@ int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type
 	audiohook->init_flags = init_flags;
 
 	/* initialize internal rate at 8khz, this will adjust if necessary */
-	audiohook_set_internal_rate(audiohook, 8000, 0);
+	audiohook_set_internal_rate(audiohook, DEFAULT_INTERNAL_SAMPLE_RATE, 0);
 
 	/* Since we are just starting out... this audiohook is new */
 	ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);
@@ -134,8 +144,8 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook)
 	/* Drop the factories used by this audiohook type */
 	switch (audiohook->type) {
 	case AST_AUDIOHOOK_TYPE_SPY:
-	case AST_AUDIOHOOK_TYPE_WHISPER:
 		ast_slinfactory_destroy(&audiohook->read_factory);
+	case AST_AUDIOHOOK_TYPE_WHISPER:
 		ast_slinfactory_destroy(&audiohook->write_factory);
 		break;
 	default:
@@ -146,8 +156,6 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook)
 	if (audiohook->trans_pvt)
 		ast_translator_free_path(audiohook->trans_pvt);
 
-	ao2_cleanup(audiohook->format);
-
 	/* Lock and trigger be gone! */
 	ast_cond_destroy(&audiohook->trigger);
 	ast_mutex_destroy(&audiohook->lock);
@@ -225,26 +233,23 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio
 	short buf[samples];
 	struct ast_frame frame = {
 		.frametype = AST_FRAME_VOICE,
-		.subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate),
 		.data.ptr = buf,
 		.datalen = sizeof(buf),
 		.samples = samples,
 	};
+	ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
 
 	/* Ensure the factory is able to give us the samples we want */
-	if (samples > ast_slinfactory_available(factory)) {
+	if (samples > ast_slinfactory_available(factory))
 		return NULL;
-	}
 
 	/* Read data in from factory */
-	if (!ast_slinfactory_read(factory, buf, samples)) {
+	if (!ast_slinfactory_read(factory, buf, samples))
 		return NULL;
-	}
 
 	/* If a volume adjustment needs to be applied apply it */
-	if (vol) {
+	if (vol)
 		ast_frame_adjust_volume(&frame, vol);
-	}
 
 	return ast_frdup(&frame);
 }
@@ -259,6 +264,7 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
 		.datalen = sizeof(buf1),
 		.samples = samples,
 	};
+	ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
 
 	/* Make sure both factories have the required samples */
 	usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
@@ -291,11 +297,10 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
 				int count = 0;
 				short adjust_value = abs(audiohook->options.read_volume);
 				for (count = 0; count < samples; count++) {
-					if (audiohook->options.read_volume > 0) {
+					if (audiohook->options.read_volume > 0)
 						ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
-					} else if (audiohook->options.read_volume < 0) {
+					else if (audiohook->options.read_volume < 0)
 						ast_slinear_saturated_divide(&buf1[count], &adjust_value);
-					}
 				}
 			}
 		}
@@ -312,11 +317,10 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
 				int count = 0;
 				short adjust_value = abs(audiohook->options.write_volume);
 				for (count = 0; count < samples; count++) {
-					if (audiohook->options.write_volume > 0) {
+					if (audiohook->options.write_volume > 0)
 						ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
-					} else if (audiohook->options.write_volume < 0) {
+					else if (audiohook->options.write_volume < 0)
 						ast_slinear_saturated_divide(&buf2[count], &adjust_value);
-					}
 				}
 			}
 		}
@@ -350,8 +354,6 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
 	/* Make the final buffer part of the frame, so it gets duplicated fine */
 	frame.data.ptr = final_buf;
 
-	frame.subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate);
-
 	/* Yahoo, a combined copy of the audio! */
 	return ast_frdup(&frame);
 }
@@ -359,42 +361,53 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
 static struct ast_frame *audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
 {
 	struct ast_frame *read_frame = NULL, *final_frame = NULL;
-	struct ast_format *slin;
-	int samples_converted;
-
-	/* the number of samples requested is based on the format they are requesting.  Inorder
-	 * to process this correctly samples must be converted to our internal sample rate */
-	if (audiohook->hook_internal_samp_rate == ast_format_get_sample_rate(format)) {
-		samples_converted = samples;
-	} else if (audiohook->hook_internal_samp_rate > ast_format_get_sample_rate(format)) {
-		samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_get_sample_rate(format));
-	} else {
-		samples_converted = samples * (ast_format_get_sample_rate(format) / (float) audiohook->hook_internal_samp_rate);
+	struct ast_format tmp_fmt;
+
+	/*
+	 * Update the rate if compatibility mode is turned off or if it is
+	 * turned on and the format rate is higher than the current rate.
+	 *
+	 * This makes it so any unnecessary rate switching/resetting does
+	 * not take place and also any associated audiohook_list's internal
+	 * sample rate maintains the highest sample rate between hooks.
+	 */
+	if (!ast_test_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE) ||
+	    (ast_test_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE) &&
+	     ast_format_rate(format) > audiohook->hook_internal_samp_rate)) {
+		audiohook_set_internal_rate(audiohook, ast_format_rate(format), 1);
+	}
+
+	/* If the sample rate of the requested format differs from that of the underlying audiohook
+	 * sample rate determine how many samples we actually need to get from the audiohook. This
+	 * needs to occur as the signed linear factory stores them at the rate of the audiohook.
+	 * We do this by determining the duration of audio they've requested and then determining
+	 * how many samples that would be in the audiohook format.
+	 */
+	if (ast_format_rate(format) != audiohook->hook_internal_samp_rate) {
+		samples = (audiohook->hook_internal_samp_rate / 1000) * (samples / (ast_format_rate(format) / 1000));
 	}
 
 	if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
-		audiohook_read_frame_both(audiohook, samples_converted, read_reference, write_reference) :
-		audiohook_read_frame_single(audiohook, samples_converted, direction)))) {
+		audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) :
+		audiohook_read_frame_single(audiohook, samples, direction)))) {
 		return NULL;
 	}
 
-	slin = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate);
-
 	/* If they don't want signed linear back out, we'll have to send it through the translation path */
-	if (ast_format_cmp(format, slin) != AST_FORMAT_CMP_EQUAL) {
+	if (format->id != ast_format_slin_by_rate(audiohook->hook_internal_samp_rate)) {
 		/* Rebuild translation path if different format then previously */
-		if (ast_format_cmp(format, audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+		if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
 			if (audiohook->trans_pvt) {
 				ast_translator_free_path(audiohook->trans_pvt);
 				audiohook->trans_pvt = NULL;
 			}
 
 			/* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
-			if (!(audiohook->trans_pvt = ast_translator_build_path(format, slin))) {
+			if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0)))) {
 				ast_frfree(read_frame);
 				return NULL;
 			}
-			ao2_replace(audiohook->format, format);
+			ast_format_copy(&audiohook->format, format);
 		}
 		/* Convert to requested format, and allow the read in frame to be freed */
 		final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
@@ -434,6 +447,22 @@ struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook,
 static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
 {
 	struct ast_audiohook *ah = NULL;
+
+	/*
+	 * Anytime the samplerate compatibility is set (attach/remove an audiohook) the
+	 * list's internal sample rate needs to be reset so that the next time processing
+	 * through write_list, if needed, it will get updated to the correct rate.
+	 *
+	 * A list's internal rate always chooses the higher between its own rate and a
+	 * given rate. If the current rate is being driven by an audiohook that wanted a
+	 * higher rate then when this audiohook is removed the list's rate would remain
+	 * at that level when it should be lower, and with no way to lower it since any
+	 * rate compared against it would be lower.
+	 *
+	 * By setting it back to the lowest rate it can recalulate the new highest rate.
+	 */
+	audiohook_list->list_internal_samp_rate = DEFAULT_INTERNAL_SAMPLE_RATE;
+
 	audiohook_list->native_slin_compatible = 1;
 	AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, ah, list) {
 		if (!(ah->init_flags & AST_AUDIOHOOK_MANIPULATE_ALL_RATES)) {
@@ -464,29 +493,28 @@ int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audioho
 		AST_LIST_HEAD_INIT_NOLOCK(&ast_channel_audiohooks(chan)->whisper_list);
 		AST_LIST_HEAD_INIT_NOLOCK(&ast_channel_audiohooks(chan)->manipulate_list);
 		/* This sample rate will adjust as necessary when writing to the list. */
-		ast_channel_audiohooks(chan)->list_internal_samp_rate = 8000;
+		ast_channel_audiohooks(chan)->list_internal_samp_rate = DEFAULT_INTERNAL_SAMPLE_RATE;
 	}
 
 	/* Drop into respective list */
-	if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
+	if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
 		AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
-	} else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
+	else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
 		AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
-	} else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
+	else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
 		AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->manipulate_list, audiohook, list);
-	}
 
 
-	audiohook_set_internal_rate(audiohook, ast_channel_audiohooks(chan)->list_internal_samp_rate, 1);
+	/*
+	 * Initialize the audiohook's rate to the default. If it needs to be,
+	 * it will get updated later.
+	 */
+	audiohook_set_internal_rate(audiohook, DEFAULT_INTERNAL_SAMPLE_RATE, 1);
 	audiohook_list_set_samplerate_compatibility(ast_channel_audiohooks(chan));
 
 	/* Change status over to running since it is now attached */
 	ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
 
-	if (ast_channel_is_bridged(chan)) {
-		ast_channel_set_unbridged_nolock(chan, 1);
-	}
-
 	ast_channel_unlock(chan);
 
 	return 0;
@@ -516,27 +544,25 @@ void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audio
  */
 int ast_audiohook_detach(struct ast_audiohook *audiohook)
 {
-	if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
+	if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
 		return 0;
-	}
 
 	ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
 
-	while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
+	while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
 		ast_audiohook_trigger_wait(audiohook);
-	}
 
 	return 0;
 }
 
-void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
+/*! \brief Detach audiohooks from list and destroy said list
+ * \param audiohook_list List of audiohooks
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
 {
-	int i;
-	struct ast_audiohook *audiohook;
-
-	if (!audiohook_list) {
-		return;
-	}
+	int i = 0;
+	struct ast_audiohook *audiohook = NULL;
 
 	/* Drop any spies */
 	while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
@@ -556,18 +582,16 @@ void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
 
 	/* Drop translation paths if present */
 	for (i = 0; i < 2; i++) {
-		if (audiohook_list->in_translate[i].trans_pvt) {
+		if (audiohook_list->in_translate[i].trans_pvt)
 			ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
-			ao2_cleanup(audiohook_list->in_translate[i].format);
-		}
-		if (audiohook_list->out_translate[i].trans_pvt) {
+		if (audiohook_list->out_translate[i].trans_pvt)
 			ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
-			ao2_cleanup(audiohook_list->in_translate[i].format);
-		}
 	}
 
 	/* Free ourselves */
 	ast_free(audiohook_list);
+
+	return 0;
 }
 
 /*! \brief find an audiohook based on its source
@@ -580,30 +604,32 @@ static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list
 	struct ast_audiohook *audiohook = NULL;
 
 	AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
-		if (!strcasecmp(audiohook->source, source)) {
+		if (!strcasecmp(audiohook->source, source))
 			return audiohook;
-		}
 	}
 
 	AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
-		if (!strcasecmp(audiohook->source, source)) {
+		if (!strcasecmp(audiohook->source, source))
 			return audiohook;
-		}
 	}
 
 	AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
-		if (!strcasecmp(audiohook->source, source)) {
+		if (!strcasecmp(audiohook->source, source))
 			return audiohook;
-		}
 	}
 
 	return NULL;
 }
 
-static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
+void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
 {
+	struct ast_audiohook *audiohook;
 	enum ast_audiohook_status oldstatus;
 
+	if (!ast_channel_audiohooks(old_chan) || !(audiohook = find_audiohook_by_source(ast_channel_audiohooks(old_chan), source))) {
+		return;
+	}
+
 	/* By locking both channels and the audiohook, we can assure that
 	 * another thread will not have a chance to read the audiohook's status
 	 * as done, even though ast_audiohook_remove signals the trigger
@@ -619,48 +645,6 @@ static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new
 	ast_audiohook_unlock(audiohook);
 }
 
-void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
-{
-	struct ast_audiohook *audiohook;
-
-	if (!ast_channel_audiohooks(old_chan)) {
-		return;
-	}
-
-	audiohook = find_audiohook_by_source(ast_channel_audiohooks(old_chan), source);
-	if (!audiohook) {
-		return;
-	}
-
-	audiohook_move(old_chan, new_chan, audiohook);
-}
-
-void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct ast_audiohook *audiohook;
-	struct ast_audiohook_list *audiohook_list;
-
-	audiohook_list = ast_channel_audiohooks(old_chan);
-	if (!audiohook_list) {
-		return;
-	}
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
-		audiohook_move(old_chan, new_chan, audiohook);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
-		audiohook_move(old_chan, new_chan, audiohook);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
-		audiohook_move(old_chan, new_chan, audiohook);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-}
-
 /*! \brief Detach specified source audiohook from channel
  * \param chan Channel to detach from
  * \param source Name of source to detach
@@ -682,9 +666,8 @@ int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
 
 	ast_channel_unlock(chan);
 
-	if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
+	if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
 		ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
-	}
 
 	return (audiohook ? 0 : -1);
 }
@@ -708,21 +691,15 @@ int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audioho
 		return -1;
 	}
 
-	if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
+	if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
 		AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
-	} else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
+	else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
 		AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
-	} else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
+	else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
 		AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->manipulate_list, audiohook, list);
-	}
 
 	audiohook_list_set_samplerate_compatibility(ast_channel_audiohooks(chan));
 	ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
-
-	if (ast_channel_is_bridged(chan)) {
-		ast_channel_set_unbridged_nolock(chan, 1);
-	}
-
 	ast_channel_unlock(chan);
 
 	return 0;
@@ -748,14 +725,10 @@ static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, str
 			ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
 			ast_audiohook_unlock(audiohook);
 			audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
-			if (ast_channel_is_bridged(chan)) {
-				ast_channel_set_unbridged_nolock(chan, 1);
-			}
 			continue;
 		}
-		if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF)) {
+		if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
 			audiohook->manipulate_callback(audiohook, chan, frame, direction);
-		}
 		ast_audiohook_unlock(audiohook);
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
@@ -773,32 +746,33 @@ static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_l
 	struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ?
 		&audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
 	struct ast_frame *new_frame = frame;
-	struct ast_format *slin;
+	struct ast_format tmp_fmt;
+	enum ast_format_id slin_id;
+
+	/*
+	 * If we are capable of sample rates other that 8khz, update the internal
+	 * audiohook_list's rate and higher sample rate audio arrives. If native
+	 * slin compatibility is turned on all audiohooks in the list will be
+	 * updated as well during read/write processing.
+	 */
+	audiohook_list->list_internal_samp_rate =
+		MAX(ast_format_rate(&frame->subclass.format), audiohook_list->list_internal_samp_rate);
 
-	/* If we are capable of maintaining doing samplerates other that 8khz, update
-	 * the internal audiohook_list's rate and higher samplerate audio arrives. By
-	 * updating the list's rate, all the audiohooks in the list will be updated as well
-	 * as the are written and read from. */
-	if (audiohook_list->native_slin_compatible) {
-		audiohook_list->list_internal_samp_rate =
-			MAX(ast_format_get_sample_rate(frame->subclass.format), audiohook_list->list_internal_samp_rate);
-	}
+	slin_id = ast_format_slin_by_rate(audiohook_list->list_internal_samp_rate);
 
-	slin = ast_format_cache_get_slin_by_rate(audiohook_list->list_internal_samp_rate);
-	if (ast_format_cmp(frame->subclass.format, slin) == AST_FORMAT_CMP_EQUAL) {
+	if (frame->subclass.format.id == slin_id) {
 		return new_frame;
 	}
 
-	if (ast_format_cmp(frame->subclass.format, in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+	if (ast_format_cmp(&frame->subclass.format, &in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) {
 		if (in_translate->trans_pvt) {
 			ast_translator_free_path(in_translate->trans_pvt);
 		}
-		if (!(in_translate->trans_pvt = ast_translator_build_path(slin, frame->subclass.format))) {
+		if (!(in_translate->trans_pvt = ast_translator_build_path(ast_format_set(&tmp_fmt, slin_id, 0), &frame->subclass.format))) {
 			return NULL;
 		}
-		ao2_replace(in_translate->format, frame->subclass.format);
+		ast_format_copy(&in_translate->format, &frame->subclass.format);
 	}
-
 	if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) {
 		return NULL;
 	}
@@ -811,16 +785,16 @@ static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook
 {
 	struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
 	struct ast_frame *outframe = NULL;
-	if (ast_format_cmp(slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
+	if (ast_format_cmp(&slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
 		/* rebuild translators if necessary */
-		if (ast_format_cmp(out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
+		if (ast_format_cmp(&out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
 			if (out_translate->trans_pvt) {
 				ast_translator_free_path(out_translate->trans_pvt);
 			}
-			if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, slin_frame->subclass.format))) {
+			if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, &slin_frame->subclass.format))) {
 				return NULL;
 			}
-			ao2_replace(out_translate->format, outformat);
+			ast_format_copy(&out_translate->format, outformat);
 		}
 		/* translate back to the format the frame came in as. */
 		if (!(outframe = ast_translate(out_translate->trans_pvt, slin_frame, 0))) {
@@ -831,6 +805,36 @@ static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook
 }
 
 /*!
+ *\brief Set the audiohook's internal sample rate to the audiohook_list's rate,
+ *       but only when native slin compatibility is turned on.
+ *
+ * \param audiohook_list audiohook_list data object
+ * \param audiohook the audiohook to update
+ * \param rate the current max internal sample rate
+ */
+static void audiohook_list_set_hook_rate(struct ast_audiohook_list *audiohook_list,
+					 struct ast_audiohook *audiohook, int *rate)
+{
+	/* The rate should always be the max between itself and the hook */
+	if (audiohook->hook_internal_samp_rate > *rate) {
+		*rate = audiohook->hook_internal_samp_rate;
+	}
+
+	/*
+	 * If native slin compatibility is turned on then update the audiohook
+	 * with the audiohook_list's current rate. Note, the audiohook's rate is
+	 * set to the audiohook_list's rate and not the given rate. If there is
+	 * a change in rate the hook's rate is changed on its next check.
+	 */
+	if (audiohook_list->native_slin_compatible) {
+		ast_set_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE);
+		audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
+	} else {
+		ast_clear_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE);
+	}
+}
+
+/*!
  * \brief Pass an AUDIO frame off to be handled by the audiohook core
  *
  * \details
@@ -860,6 +864,7 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 	int samples;
 	int middle_frame_manipulated = 0;
 	int removed = 0;
+	int internal_sample_rate;
 
 	/* ---Part_1. translate start_frame to SLINEAR if necessary. */
 	if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) {
@@ -867,6 +872,19 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 	}
 	samples = middle_frame->samples;
 
+	/*
+	 * While processing each audiohook check to see if the internal sample rate needs
+	 * to be adjusted (it should be the highest rate specified between formats and
+	 * hooks). The given audiohook_list's internal sample rate is then set to the
+	 * updated value before returning.
+	 *
+	 * If slin compatibility mode is turned on then an audiohook's internal sample
+	 * rate is set to its audiohook_list's rate. If an audiohook_list's rate is
+	 * adjusted during this pass then the change is picked up by the audiohooks
+	 * on the next pass.
+	 */
+	internal_sample_rate = audiohook_list->list_internal_samp_rate;
+
 	/* ---Part_2: Send middle_frame to spy and manipulator lists.  middle_frame is guaranteed to be SLINEAR here.*/
 	/* Queue up signed linear frame to each spy */
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
@@ -876,41 +894,34 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 			removed = 1;
 			ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
 			ast_audiohook_unlock(audiohook);
-			if (ast_channel_is_bridged(chan)) {
-				ast_channel_set_unbridged_nolock(chan, 1);
-			}
 			continue;
 		}
-		audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
+		audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
 		ast_audiohook_write_frame(audiohook, direction, middle_frame);
 		ast_audiohook_unlock(audiohook);
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
 
 	/* If this frame is being written out to the channel then we need to use whisper sources */
-	if (!AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
+	if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
 		int i = 0;
 		short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
 		memset(&combine_buf, 0, sizeof(combine_buf));
 		AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
-			struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
 			ast_audiohook_lock(audiohook);
 			if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
 				AST_LIST_REMOVE_CURRENT(list);
 				removed = 1;
 				ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
 				ast_audiohook_unlock(audiohook);
-				if (ast_channel_is_bridged(chan)) {
-					ast_channel_set_unbridged_nolock(chan, 1);
-				}
 				continue;
 			}
-			audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
-			if (ast_slinfactory_available(factory) >= samples && ast_slinfactory_read(factory, read_buf, samples)) {
+			audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
+			if (ast_slinfactory_available(&audiohook->write_factory) >= samples &&
+			    ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
 				/* Take audio from this whisper source and combine it into our main buffer */
-				for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++) {
+				for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
 					ast_slinear_saturated_add(data1, data2);
-				}
 			}
 			ast_audiohook_unlock(audiohook);
 		}
@@ -933,27 +944,27 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 				ast_audiohook_unlock(audiohook);
 				/* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
 				audiohook->manipulate_callback(audiohook, chan, NULL, direction);
-				if (ast_channel_is_bridged(chan)) {
-					ast_channel_set_unbridged_nolock(chan, 1);
-				}
 				continue;
 			}
-			audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
-			/* Feed in frame to manipulation. */
-			if (!audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
-				/* If the manipulation fails then the frame will be returned in its original state.
-				 * Since there are potentially more manipulator callbacks in the list, no action should
-				 * be taken here to exit early. */
-				 middle_frame_manipulated = 1;
-			}
+			audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
+			/*
+			 * Feed in frame to manipulation.
+			 *
+			 * XXX FAILURES ARE IGNORED XXX
+			 * If the manipulation fails then the frame will be returned in its original state.
+			 * Since there are potentially more manipulator callbacks in the list, no action should
+			 * be taken here to exit early.
+			 */
+			audiohook->manipulate_callback(audiohook, chan, middle_frame, direction);
 			ast_audiohook_unlock(audiohook);
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
+		middle_frame_manipulated = 1;
 	}
 
 	/* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
 	if (middle_frame_manipulated) {
-		if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, start_frame->subclass.format))) {
+		if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, &start_frame->subclass.format))) {
 			/* translation failed, so just pass back the input frame */
 			end_frame = start_frame;
 		}
@@ -969,6 +980,12 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 	/* Before returning, if an audiohook got removed, reset samplerate compatibility */
 	if (removed) {
 		audiohook_list_set_samplerate_compatibility(audiohook_list);
+	} else {
+		/*
+		 * Set the audiohook_list's rate to the updated rate. Note that if a hook
+		 * was removed then the list's internal rate is reset to the default.
+		 */
+		audiohook_list->list_internal_samp_rate = internal_sample_rate;
 	}
 
 	return end_frame;
@@ -976,10 +993,13 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
 
 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
 {
-	return !audiohook_list
-		|| (AST_LIST_EMPTY(&audiohook_list->spy_list)
-			&& AST_LIST_EMPTY(&audiohook_list->whisper_list)
-			&& AST_LIST_EMPTY(&audiohook_list->manipulate_list));
+	if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
+		AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
+		AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
+
+		return 1;
+	}
+	return 0;
 }
 
 /*! \brief Pass a frame off to be handled by the audiohook core
@@ -992,13 +1012,12 @@ int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
 struct ast_frame *ast_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
 {
 	/* Pass off frame to it's respective list write function */
-	if (frame->frametype == AST_FRAME_VOICE) {
+	if (frame->frametype == AST_FRAME_VOICE)
 		return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
-	} else if (frame->frametype == AST_FRAME_DTMF) {
+	else if (frame->frametype == AST_FRAME_DTMF)
 		return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
-	} else {
+	else
 		return frame;
-	}
 }
 
 /*! \brief Wait for audiohook trigger to be triggered
@@ -1024,9 +1043,8 @@ int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *
 	int count = 0;
 	struct ast_audiohook *ah = NULL;
 
-	if (!ast_channel_audiohooks(chan)) {
+	if (!ast_channel_audiohooks(chan))
 		return -1;
-	}
 
 	switch (type) {
 		case AST_AUDIOHOOK_TYPE_SPY:
diff --git a/main/autochan.c b/main/autochan.c
index 6a0fcd3..7da249a 100644
--- a/main/autochan.c
+++ b/main/autochan.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/autochan.h"
 #include "asterisk/utils.h"
diff --git a/main/autoservice.c b/main/autoservice.c
index 3a4a91b..2a5b007 100644
--- a/main/autoservice.c
+++ b/main/autoservice.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 415466 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -148,40 +148,34 @@ static void *autoservice_run(void *ign)
 			defer_frame = &hangup_frame;
 		} else if (ast_is_deferrable_frame(f)) {
 			defer_frame = f;
-		} else {
-			/* Can't defer. Discard and continue with next. */
-			ast_frfree(f);
-			continue;
 		}
 
-		for (i = 0; i < x; i++) {
-			struct ast_frame *dup_f;
+		if (defer_frame) {
+			for (i = 0; i < x; i++) {
+				struct ast_frame *dup_f;
 
-			if (mons[i] != chan) {
-				continue;
-			}
-
-			if (!f) { /* defer_frame == &hangup_frame */
-				if ((dup_f = ast_frdup(defer_frame))) {
-					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
-				}
-			} else {
-				if ((dup_f = ast_frisolate(defer_frame))) {
-					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+				if (mons[i] != chan) {
+					continue;
 				}
-				if (dup_f != defer_frame) {
-					ast_frfree(defer_frame);
+
+				if (defer_frame != f) {
+					if ((dup_f = ast_frdup(defer_frame))) {
+						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+					}
+				} else {
+					if ((dup_f = ast_frisolate(defer_frame))) {
+						if (dup_f != defer_frame) {
+							ast_frfree(defer_frame);
+						}
+						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+					}
 				}
-			}
 
-			break;
+				break;
+			}
+		} else if (f) {
+			ast_frfree(f);
 		}
-		/* The ast_waitfor_n() call will only read frames from
-		 * the channels' file descriptors. If ast_waitfor_n()
-		 * returns non-NULL, then one of the channels in the
-		 * mons array must have triggered the return. It's
-		 * therefore impossible that we got here while (i >= x).
-		 * If we did, we'd need to ast_frfree(f) if (f). */
 	}
 
 	ast_callid_threadassoc_change(NULL);
diff --git a/main/backtrace.c b/main/backtrace.c
deleted file mode 100644
index bf976ba..0000000
--- a/main/backtrace.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Asterisk backtrace generation
- *
- * This file provides backtrace generation utilities
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397570 $");
-
-#include "asterisk/backtrace.h"
-#include "asterisk/utils.h"
-#include "asterisk/strings.h"
-
-#ifdef HAVE_BKTR
-#include <execinfo.h>
-#if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
-#include <dlfcn.h>
-#include <bfd.h>
-#endif
-
-struct ast_bt *__ast_bt_create(void)
-{
-	struct ast_bt *bt = ast_std_calloc(1, sizeof(*bt));
-
-	if (!bt) {
-		return NULL;
-	}
-	bt->alloced = 1;
-
-	ast_bt_get_addresses(bt);
-
-	return bt;
-}
-
-int __ast_bt_get_addresses(struct ast_bt *bt)
-{
-	bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
-	return 0;
-}
-
-void *__ast_bt_destroy(struct ast_bt *bt)
-{
-	if (bt && bt->alloced) {
-		ast_std_free(bt);
-	}
-	return NULL;
-}
-
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
-{
-	char **strings;
-#if defined(BETTER_BACKTRACES)
-	int stackfr;
-	bfd *bfdobj;           /* bfd.h */
-	Dl_info dli;           /* dlfcn.h */
-	long allocsize;
-	asymbol **syms = NULL; /* bfd.h */
-	bfd_vma offset;        /* bfd.h */
-	const char *lastslash;
-	asection *section;
-	const char *file, *func;
-	unsigned int line;
-	char address_str[128];
-	char msg[1024];
-	size_t strings_size;
-	size_t *eachlen;
-#endif
-
-#if defined(BETTER_BACKTRACES)
-	strings_size = num_frames * sizeof(*strings);
-
-	eachlen = ast_std_calloc(num_frames, sizeof(*eachlen));
-	strings = ast_std_calloc(num_frames, sizeof(*strings));
-	if (!eachlen || !strings) {
-		ast_std_free(eachlen);
-		ast_std_free(strings);
-		return NULL;
-	}
-
-	for (stackfr = 0; stackfr < num_frames; stackfr++) {
-		int found = 0, symbolcount;
-
-		msg[0] = '\0';
-
-		if (!dladdr(addresses[stackfr], &dli)) {
-			continue;
-		}
-
-		if (strcmp(dli.dli_fname, "asterisk") == 0) {
-			char asteriskpath[256];
-
-			if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
-				/* This will fail to find symbols */
-				dli.dli_fname = "asterisk";
-			}
-		}
-
-		lastslash = strrchr(dli.dli_fname, '/');
-		if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
-			bfd_check_format(bfdobj, bfd_object) &&
-			(allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
-			(syms = ast_std_malloc(allocsize)) &&
-			(symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
-
-			if (bfdobj->flags & DYNAMIC) {
-				offset = addresses[stackfr] - dli.dli_fbase;
-			} else {
-				offset = addresses[stackfr] - (void *) 0;
-			}
-
-			for (section = bfdobj->sections; section; section = section->next) {
-				if (!bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
-					section->vma > offset ||
-					section->size + section->vma < offset) {
-					continue;
-				}
-
-				if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
-					continue;
-				}
-
-				/* file can possibly be null even with a success result from bfd_find_nearest_line */
-				file = file ? file : "";
-
-				/* Stack trace output */
-				found++;
-				if ((lastslash = strrchr(file, '/'))) {
-					const char *prevslash;
-
-					for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) {
-					}
-					if (prevslash >= file) {
-						lastslash = prevslash;
-					}
-				}
-				if (dli.dli_saddr == NULL) {
-					address_str[0] = '\0';
-				} else {
-					snprintf(address_str, sizeof(address_str), " (%p+%lX)",
-						dli.dli_saddr,
-						(unsigned long) (addresses[stackfr] - dli.dli_saddr));
-				}
-				snprintf(msg, sizeof(msg), "%s:%u %s()%s",
-					lastslash ? lastslash + 1 : file, line,
-					S_OR(func, "???"),
-					address_str);
-
-				break; /* out of section iteration */
-			}
-		}
-		if (bfdobj) {
-			bfd_close(bfdobj);
-			ast_std_free(syms);
-		}
-
-		/* Default output, if we cannot find the information within BFD */
-		if (!found) {
-			if (dli.dli_saddr == NULL) {
-				address_str[0] = '\0';
-			} else {
-				snprintf(address_str, sizeof(address_str), " (%p+%lX)",
-					dli.dli_saddr,
-					(unsigned long) (addresses[stackfr] - dli.dli_saddr));
-			}
-			snprintf(msg, sizeof(msg), "%s %s()%s",
-				lastslash ? lastslash + 1 : dli.dli_fname,
-				S_OR(dli.dli_sname, "<unknown>"),
-				address_str);
-		}
-
-		if (!ast_strlen_zero(msg)) {
-			char **tmp;
-
-			eachlen[stackfr] = strlen(msg) + 1;
-			if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) {
-				ast_std_free(strings);
-				strings = NULL;
-				break; /* out of stack frame iteration */
-			}
-			strings = tmp;
-			strings[stackfr] = (char *) strings + strings_size;
-			strcpy(strings[stackfr], msg);/* Safe since we just allocated the room. */
-			strings_size += eachlen[stackfr];
-		}
-	}
-
-	if (strings) {
-		/* Recalculate the offset pointers because of the reallocs. */
-		strings[0] = (char *) strings + num_frames * sizeof(*strings);
-		for (stackfr = 1; stackfr < num_frames; stackfr++) {
-			strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1];
-		}
-	}
-	ast_std_free(eachlen);
-
-#else /* !defined(BETTER_BACKTRACES) */
-
-	strings = backtrace_symbols(addresses, num_frames);
-#endif /* defined(BETTER_BACKTRACES) */
-	return strings;
-}
-
-#endif /* HAVE_BKTR */
diff --git a/main/bridge.c b/main/bridge.c
deleted file mode 100644
index 3ddf407..0000000
--- a/main/bridge.c
+++ /dev/null
@@ -1,5312 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2007 - 2009, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Bridging API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<manager name="BridgeTechnologyList" language="en_US">
-		<synopsis>
-			List available bridging technologies and their statuses.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>Returns detailed information about the available bridging technologies.</para>
-		</description>
-	</manager>
-	<manager name="BridgeTechnologySuspend" language="en_US">
-		<synopsis>
-			Suspend a bridging technology.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeTechnology" required="true">
-				<para>The name of the bridging technology to suspend.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Marks a bridging technology as suspended, which prevents subsequently created bridges from using it.</para>
-		</description>
-	</manager>
-	<manager name="BridgeTechnologyUnsuspend" language="en_US">
-		<synopsis>
-			Unsuspend a bridging technology.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeTechnology" required="true">
-				<para>The name of the bridging technology to unsuspend.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Clears a previously suspended bridging technology, which allows subsequently created bridges to use it.</para>
-		</description>
-	</manager>
-***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428602 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/options.h"
-#include "asterisk/utils.h"
-#include "asterisk/lock.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/bridge_channel_internal.h"
-#include "asterisk/bridge_features.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/bridge_technology.h"
-#include "asterisk/bridge_channel.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_cache_pattern.h"
-#include "asterisk/app.h"
-#include "asterisk/file.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/test.h"
-#include "asterisk/_private.h"
-#include "asterisk/heap.h"
-#include "asterisk/say.h"
-#include "asterisk/timing.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/features.h"
-#include "asterisk/cli.h"
-#include "asterisk/parking.h"
-#include "asterisk/core_local.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/causes.h"
-
-/*! All bridges container. */
-static struct ao2_container *bridges;
-
-static AST_RWLIST_HEAD_STATIC(bridge_technologies, ast_bridge_technology);
-
-static unsigned int optimization_id;
-
-/* Initial starting point for the bridge array of channels */
-#define BRIDGE_ARRAY_START 128
-
-/* Grow rate of bridge array of channels */
-#define BRIDGE_ARRAY_GROW 32
-
-/* Variable name - stores peer information about the most recent blind transfer */
-#define BLINDTRANSFER "BLINDTRANSFER"
-
-/* Variable name - stores peer information about the most recent attended transfer */
-#define ATTENDEDTRANSFER "ATTENDEDTRANSFER"
-
-static void cleanup_video_mode(struct ast_bridge *bridge);
-static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
-
-/*! Default DTMF keys for built in features */
-static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING];
-
-/*! Function handlers for the built in features */
-static ast_bridge_hook_callback builtin_features_handlers[AST_BRIDGE_BUILTIN_END];
-
-/*! Function handlers for built in interval features */
-static ast_bridge_builtin_set_limits_fn builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_END];
-
-/*! Bridge manager service request */
-struct bridge_manager_request {
-	/*! List of bridge service requests. */
-	AST_LIST_ENTRY(bridge_manager_request) node;
-	/*! Refed bridge requesting service. */
-	struct ast_bridge *bridge;
-};
-
-struct bridge_manager_controller {
-	/*! Condition, used to wake up the bridge manager thread. */
-	ast_cond_t cond;
-	/*! Queue of bridge service requests. */
-	AST_LIST_HEAD_NOLOCK(, bridge_manager_request) service_requests;
-	/*! Manager thread */
-	pthread_t thread;
-	/*! TRUE if the manager needs to stop. */
-	unsigned int stop:1;
-};
-
-/*! Bridge manager controller. */
-static struct bridge_manager_controller *bridge_manager;
-
-/*!
- * \internal
- * \brief Request service for a bridge from the bridge manager.
- * \since 12.0.0
- *
- * \param bridge Requesting service.
- *
- * \return Nothing
- */
-static void bridge_manager_service_req(struct ast_bridge *bridge)
-{
-	struct bridge_manager_request *request;
-
-	ao2_lock(bridge_manager);
-	if (bridge_manager->stop) {
-		ao2_unlock(bridge_manager);
-		return;
-	}
-
-	/* Create the service request. */
-	request = ast_calloc(1, sizeof(*request));
-	if (!request) {
-		/* Well. This isn't good. */
-		ao2_unlock(bridge_manager);
-		return;
-	}
-	ao2_ref(bridge, +1);
-	request->bridge = bridge;
-
-	/* Put request into the queue and wake the bridge manager. */
-	AST_LIST_INSERT_TAIL(&bridge_manager->service_requests, request, node);
-	ast_cond_signal(&bridge_manager->cond);
-	ao2_unlock(bridge_manager);
-}
-
-int __ast_bridge_technology_register(struct ast_bridge_technology *technology, struct ast_module *module)
-{
-	struct ast_bridge_technology *current;
-
-	/* Perform a sanity check to make sure the bridge technology conforms to our needed requirements */
-	if (ast_strlen_zero(technology->name)
-		|| !technology->capabilities
-		|| !technology->write) {
-		ast_log(LOG_WARNING, "Bridge technology %s failed registration sanity check.\n",
-			technology->name);
-		return -1;
-	}
-
-	AST_RWLIST_WRLOCK(&bridge_technologies);
-
-	/* Look for duplicate bridge technology already using this name, or already registered */
-	AST_RWLIST_TRAVERSE(&bridge_technologies, current, entry) {
-		if ((!strcasecmp(current->name, technology->name)) || (current == technology)) {
-			ast_log(LOG_WARNING, "A bridge technology of %s already claims to exist in our world.\n",
-				technology->name);
-			AST_RWLIST_UNLOCK(&bridge_technologies);
-			return -1;
-		}
-	}
-
-	/* Copy module pointer so reference counting can keep the module from unloading */
-	technology->mod = module;
-
-	/* Insert our new bridge technology into the list and print out a pretty message */
-	AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
-
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-
-	ast_verb(2, "Registered bridge technology %s\n", technology->name);
-
-	return 0;
-}
-
-int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
-{
-	struct ast_bridge_technology *current;
-
-	AST_RWLIST_WRLOCK(&bridge_technologies);
-
-	/* Ensure the bridge technology is registered before removing it */
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&bridge_technologies, current, entry) {
-		if (current == technology) {
-			AST_RWLIST_REMOVE_CURRENT(entry);
-			ast_verb(2, "Unregistered bridge technology %s\n", technology->name);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-
-	return current ? 0 : -1;
-}
-
-/*!
- * \internal
- * \brief Put an action onto the specified bridge. Don't dup the action frame.
- * \since 12.0.0
- *
- * \param bridge What to queue the action on.
- * \param action What to do.
- *
- * \return Nothing
- */
-static void bridge_queue_action_nodup(struct ast_bridge *bridge, struct ast_frame *action)
-{
-	ast_debug(1, "Bridge %s: queueing action type:%u sub:%d\n",
-		bridge->uniqueid, action->frametype, action->subclass.integer);
-
-	ast_bridge_lock(bridge);
-	AST_LIST_INSERT_TAIL(&bridge->action_queue, action, frame_list);
-	ast_bridge_unlock(bridge);
-	bridge_manager_service_req(bridge);
-}
-
-int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action)
-{
-	struct ast_frame *dup;
-
-	dup = ast_frdup(action);
-	if (!dup) {
-		return -1;
-	}
-	bridge_queue_action_nodup(bridge, dup);
-	return 0;
-}
-
-void bridge_dissolve(struct ast_bridge *bridge, int cause)
-{
-	struct ast_bridge_channel *bridge_channel;
-	struct ast_frame action = {
-		.frametype = AST_FRAME_BRIDGE_ACTION,
-		.subclass.integer = BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING,
-	};
-
-	if (bridge->dissolved) {
-		return;
-	}
-	bridge->dissolved = 1;
-
-	if (cause <= 0) {
-		cause = AST_CAUSE_NORMAL_CLEARING;
-	}
-	bridge->cause = cause;
-
-	ast_debug(1, "Bridge %s: dissolving bridge with cause %d(%s)\n",
-		bridge->uniqueid, cause, ast_cause2str(cause));
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		ast_bridge_channel_leave_bridge(bridge_channel,
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, cause);
-	}
-
-	/* Must defer dissolving bridge because it is already locked. */
-	ast_bridge_queue_action(bridge, &action);
-}
-
-/*!
- * \internal
- * \brief Check if a bridge should dissolve because of a stolen channel and do it.
- * \since 12.0.0
- *
- * \param bridge Bridge to check.
- * \param bridge_channel Stolen channel causing the check.  It is not in the bridge to check and may be in another bridge.
- *
- * \note On entry, bridge and bridge_channel->bridge are already locked.
- *
- * \return Nothing
- */
-static void bridge_dissolve_check_stolen(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	if (bridge->dissolved) {
-		return;
-	}
-
-	if (bridge_channel->features->usable
-		&& ast_test_flag(&bridge_channel->features->feature_flags,
-			AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP)) {
-		/* The stolen channel controlled the bridge it was stolen from. */
-		bridge_dissolve(bridge, 0);
-		return;
-	}
-	if (bridge->num_channels < 2
-		&& ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)) {
-		/*
-		 * The stolen channel has not left enough channels to keep the
-		 * bridge alive.  Assume the stolen channel hung up.
-		 */
-		bridge_dissolve(bridge, 0);
-		return;
-	}
-}
-
-/*!
- * \internal
- * \brief Update connected line information after a bridge has been reconfigured.
- *
- * \param bridge The bridge itself.
- *
- * \return Nothing
- */
-static void bridge_reconfigured_connected_line_update(struct ast_bridge *bridge)
-{
-	struct ast_party_connected_line connected;
-	struct ast_bridge_channel *bridge_channel = AST_LIST_FIRST(&bridge->channels), *peer;
-	unsigned char data[1024];
-	size_t datalen;
-
-	if (!bridge_channel ||
-		!(bridge->technology->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) ||
-		!(peer = ast_bridge_channel_peer(bridge_channel)) ||
-		ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE) ||
-		ast_test_flag(ast_channel_flags(peer->chan), AST_FLAG_ZOMBIE) ||
-		ast_check_hangup_locked(bridge_channel->chan) ||
-		ast_check_hangup_locked(peer->chan)) {
-		return;
-	}
-
-	ast_party_connected_line_init(&connected);
-
-	ast_channel_lock(bridge_channel->chan);
-	ast_connected_line_copy_from_caller(&connected, ast_channel_caller(bridge_channel->chan));
-	ast_channel_unlock(bridge_channel->chan);
-
-	if ((datalen = ast_connected_line_build_data(data, sizeof(data), &connected, NULL)) != (size_t) -1) {
-		ast_bridge_channel_queue_control_data(peer, AST_CONTROL_CONNECTED_LINE, data, datalen);
-	}
-
-	ast_channel_lock(peer->chan);
-	ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer->chan));
-	ast_channel_unlock(peer->chan);
-
-	if ((datalen = ast_connected_line_build_data(data, sizeof(data), &connected, NULL)) != (size_t) -1) {
-		ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_CONNECTED_LINE, data, datalen);
-	}
-
-	ast_party_connected_line_free(&connected);
-}
-
-/*!
- * \internal
- * \brief Complete joining a channel to the bridge.
- * \since 12.0.0
- *
- * \param bridge What to operate upon.
- * \param bridge_channel What is joining the bridge technology.
- *
- * \note On entry, bridge is already locked.
- *
- * \return Nothing
- */
-static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	/* Make the channel compatible with the bridge */
-	bridge_make_compatible(bridge, bridge_channel);
-
-	/* Tell the bridge technology we are joining so they set us up */
-	ast_debug(1, "Bridge %s: %p(%s) is joining %s technology\n",
-		bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
-		bridge->technology->name);
-	if (bridge->technology->join
-		&& bridge->technology->join(bridge, bridge_channel)) {
-		ast_debug(1, "Bridge %s: %p(%s) failed to join %s technology\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
-			bridge->technology->name);
-		bridge_channel->just_joined = 1;
-		return;
-	}
-
-	bridge_channel->just_joined = 0;
-}
-
-/*!
- * \internal
- * \brief Complete joining new channels to the bridge.
- * \since 12.0.0
- *
- * \param bridge Check for new channels on this bridge.
- *
- * \note On entry, bridge is already locked.
- *
- * \return Nothing
- */
-static void bridge_complete_join(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	if (bridge->dissolved) {
-		/*
-		 * No sense in completing the join on channels for a dissolved
-		 * bridge.  They are just going to be removed soon anyway.
-		 * However, we do have reason to abort here because the bridge
-		 * technology may not be able to handle the number of channels
-		 * still in the bridge.
-		 */
-		return;
-	}
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		if (!bridge_channel->just_joined) {
-			continue;
-		}
-		bridge_channel_complete_join(bridge, bridge_channel);
-	}
-}
-
-/*! \brief Helper function used to find the "best" bridge technology given specified capabilities */
-static struct ast_bridge_technology *find_best_technology(uint32_t capabilities, struct ast_bridge *bridge)
-{
-	struct ast_bridge_technology *current;
-	struct ast_bridge_technology *best = NULL;
-
-	AST_RWLIST_RDLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, current, entry) {
-		if (current->suspended) {
-			ast_debug(1, "Bridge technology %s is suspended. Skipping.\n",
-				current->name);
-			continue;
-		}
-		if (!(current->capabilities & capabilities)) {
-			ast_debug(1, "Bridge technology %s does not have any capabilities we want.\n",
-				current->name);
-			continue;
-		}
-		if (best && current->preference <= best->preference) {
-			ast_debug(1, "Bridge technology %s has less preference than %s (%u <= %u). Skipping.\n",
-				current->name, best->name, current->preference, best->preference);
-			continue;
-		}
-		if (current->compatible && !current->compatible(bridge)) {
-			ast_debug(1, "Bridge technology %s is not compatible with properties of existing bridge.\n",
-				current->name);
-			continue;
-		}
-		best = current;
-	}
-
-	if (best) {
-		/* Increment it's module reference count if present so it does not get unloaded while in use */
-		ast_module_ref(best->mod);
-		ast_debug(1, "Chose bridge technology %s\n", best->name);
-	}
-
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-
-	return best;
-}
-
-struct tech_deferred_destroy {
-	struct ast_bridge_technology *tech;
-	void *tech_pvt;
-};
-
-/*!
- * \internal
- * \brief Deferred destruction of bridge tech private structure.
- * \since 12.0.0
- *
- * \param bridge What to execute the action on.
- * \param action Deferred bridge tech destruction.
- *
- * \note On entry, bridge must not be locked.
- *
- * \return Nothing
- */
-static void bridge_tech_deferred_destroy(struct ast_bridge *bridge, struct ast_frame *action)
-{
-	struct tech_deferred_destroy *deferred = action->data.ptr;
-	struct ast_bridge dummy_bridge = {
-		.technology = deferred->tech,
-		.tech_pvt = deferred->tech_pvt,
-		.creator = bridge->creator,
-		.name = bridge->name,
-		.uniqueid = bridge->uniqueid,
-		};
-
-	ast_debug(1, "Bridge %s: calling %s technology destructor (deferred, dummy)\n",
-		dummy_bridge.uniqueid, dummy_bridge.technology->name);
-	dummy_bridge.technology->destroy(&dummy_bridge);
-	ast_module_unref(dummy_bridge.technology->mod);
-}
-
-/*!
- * \internal
- * \brief Handle bridge action frame.
- * \since 12.0.0
- *
- * \param bridge What to execute the action on.
- * \param action What to do.
- *
- * \note On entry, bridge is already locked.
- * \note Can be called by the bridge destructor.
- *
- * \return Nothing
- */
-static void bridge_action_bridge(struct ast_bridge *bridge, struct ast_frame *action)
-{
-#if 0	/* In case we need to know when the destructor is calling us. */
-	int in_destructor = !ao2_ref(bridge, 0);
-#endif
-
-	switch (action->subclass.integer) {
-	case BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY:
-		ast_bridge_unlock(bridge);
-		bridge_tech_deferred_destroy(bridge, action);
-		ast_bridge_lock(bridge);
-		break;
-	case BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING:
-		ast_bridge_unlock(bridge);
-		bridge->v_table->dissolving(bridge);
-		ast_bridge_lock(bridge);
-		break;
-	default:
-		/* Unexpected deferred action type.  Should never happen. */
-		ast_assert(0);
-		break;
-	}
-}
-
-/*!
- * \internal
- * \brief Do any pending bridge actions.
- * \since 12.0.0
- *
- * \param bridge What to do actions on.
- *
- * \note On entry, bridge is already locked.
- * \note Can be called by the bridge destructor.
- *
- * \return Nothing
- */
-static void bridge_handle_actions(struct ast_bridge *bridge)
-{
-	struct ast_frame *action;
-
-	while ((action = AST_LIST_REMOVE_HEAD(&bridge->action_queue, frame_list))) {
-		switch (action->frametype) {
-		case AST_FRAME_BRIDGE_ACTION:
-			bridge_action_bridge(bridge, action);
-			break;
-		default:
-			/* Unexpected deferred frame type.  Should never happen. */
-			ast_assert(0);
-			break;
-		}
-		ast_frfree(action);
-	}
-}
-
-static struct stasis_message *create_bridge_snapshot_message(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (!ast_bridge_snapshot_type()) {
-		return NULL;
-	}
-
-	ast_bridge_lock(bridge);
-	snapshot = ast_bridge_snapshot_create(bridge);
-	ast_bridge_unlock(bridge);
-
-	if (!snapshot) {
-		return NULL;
-	}
-
-	return stasis_message_create(ast_bridge_snapshot_type(), snapshot);
-}
-
-static void destroy_bridge(void *obj)
-{
-	struct ast_bridge *bridge = obj;
-
-	ast_debug(1, "Bridge %s: actually destroying %s bridge, nobody wants it anymore\n",
-		bridge->uniqueid, bridge->v_table->name);
-
-	if (bridge->construction_completed) {
-		RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup);
-
-		clear_msg = create_bridge_snapshot_message(bridge);
-		if (clear_msg) {
-			RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-			msg = stasis_cache_clear_create(clear_msg);
-			if (msg) {
-				stasis_publish(ast_bridge_topic(bridge), msg);
-			}
-		}
-	}
-
-	/* Do any pending actions in the context of destruction. */
-	ast_bridge_lock(bridge);
-	bridge_handle_actions(bridge);
-	ast_bridge_unlock(bridge);
-
-	/* There should not be any channels left in the bridge. */
-	ast_assert(AST_LIST_EMPTY(&bridge->channels));
-
-	ast_debug(1, "Bridge %s: calling %s bridge destructor\n",
-		bridge->uniqueid, bridge->v_table->name);
-	bridge->v_table->destroy(bridge);
-
-	/* Pass off the bridge to the technology to destroy if needed */
-	if (bridge->technology) {
-		ast_debug(1, "Bridge %s: calling %s technology stop\n",
-			bridge->uniqueid, bridge->technology->name);
-		if (bridge->technology->stop) {
-			ast_bridge_lock(bridge);
-			bridge->technology->stop(bridge);
-			ast_bridge_unlock(bridge);
-		}
-		ast_debug(1, "Bridge %s: calling %s technology destructor\n",
-			bridge->uniqueid, bridge->technology->name);
-		if (bridge->technology->destroy) {
-			bridge->technology->destroy(bridge);
-		}
-		ast_module_unref(bridge->technology->mod);
-		bridge->technology = NULL;
-	}
-
-	if (bridge->callid) {
-		bridge->callid = ast_callid_unref(bridge->callid);
-	}
-
-	cleanup_video_mode(bridge);
-
-	stasis_cp_single_unsubscribe(bridge->topics);
-
-	ast_string_field_free_memory(bridge);
-}
-
-struct ast_bridge *bridge_register(struct ast_bridge *bridge)
-{
-	if (bridge) {
-		bridge->construction_completed = 1;
-		ast_bridge_lock(bridge);
-		ast_bridge_publish_state(bridge);
-		ast_bridge_unlock(bridge);
-		if (!ao2_link(bridges, bridge)) {
-			ast_bridge_destroy(bridge, 0);
-			bridge = NULL;
-		}
-	}
-	return bridge;
-}
-
-struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_table)
-{
-	struct ast_bridge *bridge;
-
-	/* Check v_table that all methods are present. */
-	if (!v_table
-		|| !v_table->name
-		|| !v_table->destroy
-		|| !v_table->dissolving
-		|| !v_table->push
-		|| !v_table->pull
-		|| !v_table->notify_masquerade
-		|| !v_table->get_merge_priority) {
-		ast_log(LOG_ERROR, "Virtual method table for bridge class %s not complete.\n",
-			v_table && v_table->name ? v_table->name : "<unknown>");
-		ast_assert(0);
-		return NULL;
-	}
-
-	bridge = ao2_alloc(size, destroy_bridge);
-	if (!bridge) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(bridge, 80)) {
-		ao2_cleanup(bridge);
-		return NULL;
-	}
-
-	bridge->v_table = v_table;
-
-	return bridge;
-}
-
-struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
-{
-	char uuid_hold[AST_UUID_STR_LEN];
-
-	if (!self) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(id)) {
-		ast_string_field_set(self, uniqueid, id);
-	} else {
-		ast_uuid_generate_str(uuid_hold, AST_UUID_STR_LEN);
-		ast_string_field_set(self, uniqueid, uuid_hold);
-	}
-	ast_string_field_set(self, creator, creator);
-	if (!ast_strlen_zero(creator)) {
-		ast_string_field_set(self, name, name);
-	}
-
-	ast_set_flag(&self->feature_flags, flags);
-	self->allowed_capabilities = capabilities;
-
-	if (bridge_topics_init(self) != 0) {
-		ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n",
-			self->uniqueid);
-		ao2_ref(self, -1);
-		return NULL;
-	}
-
-	/* Use our helper function to find the "best" bridge technology. */
-	self->technology = find_best_technology(capabilities, self);
-	if (!self->technology) {
-		ast_log(LOG_WARNING, "Bridge %s: Could not create class %s.  No technology to support it.\n",
-			self->uniqueid, self->v_table->name);
-		ao2_ref(self, -1);
-		return NULL;
-	}
-
-	/* Pass off the bridge to the technology to manipulate if needed */
-	ast_debug(1, "Bridge %s: calling %s technology constructor\n",
-		self->uniqueid, self->technology->name);
-	if (self->technology->create && self->technology->create(self)) {
-		ast_log(LOG_WARNING, "Bridge %s: failed to setup bridge technology %s\n",
-			self->uniqueid, self->technology->name);
-		ao2_ref(self, -1);
-		return NULL;
-	}
-	ast_debug(1, "Bridge %s: calling %s technology start\n",
-		self->uniqueid, self->technology->name);
-	if (self->technology->start && self->technology->start(self)) {
-		ast_log(LOG_WARNING, "Bridge %s: failed to start bridge technology %s\n",
-			self->uniqueid, self->technology->name);
-		ao2_ref(self, -1);
-		return NULL;
-	}
-
-	if (!ast_bridge_topic(self)) {
-		ao2_ref(self, -1);
-		return NULL;
-	}
-
-	return self;
-}
-
-/*!
- * \internal
- * \brief ast_bridge base class destructor.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- *
- * \note Stub because of nothing to do.
- *
- * \return Nothing
- */
-static void bridge_base_destroy(struct ast_bridge *self)
-{
-}
-
-/*!
- * \internal
- * \brief The bridge is being dissolved.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- *
- * \return Nothing
- */
-static void bridge_base_dissolving(struct ast_bridge *self)
-{
-	ao2_unlink(bridges, self);
-}
-
-/*!
- * \internal
- * \brief ast_bridge base push method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to push.
- * \param swap Bridge channel to swap places with if not NULL.
- *
- * \note On entry, self is already locked.
- * \note Stub because of nothing to do.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int bridge_base_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	return 0;
-}
-
-/*!
- * \internal
- * \brief ast_bridge base pull method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to pull.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-static void bridge_base_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-}
-
-/*!
- * \internal
- * \brief ast_bridge base notify_masquerade method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel that was masqueraded.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-static void bridge_base_notify_masquerade(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	self->reconfigured = 1;
-}
-
-/*!
- * \internal
- * \brief Get the merge priority of this bridge.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- *
- * \note On entry, self is already locked.
- *
- * \return Merge priority
- */
-static int bridge_base_get_merge_priority(struct ast_bridge *self)
-{
-	return 0;
-}
-
-struct ast_bridge_methods ast_bridge_base_v_table = {
-	.name = "base",
-	.destroy = bridge_base_destroy,
-	.dissolving = bridge_base_dissolving,
-	.push = bridge_base_push,
-	.pull = bridge_base_pull,
-	.notify_masquerade = bridge_base_notify_masquerade,
-	.get_merge_priority = bridge_base_get_merge_priority,
-};
-
-struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
-{
-	void *bridge;
-
-	bridge = bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_base_v_table);
-	bridge = bridge_base_init(bridge, capabilities, flags, creator, name, id);
-	bridge = bridge_register(bridge);
-	return bridge;
-}
-
-int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
-{
-	ast_debug(1, "Bridge %s: telling all channels to leave the party\n", bridge->uniqueid);
-	ast_bridge_lock(bridge);
-	bridge_dissolve(bridge, cause);
-	ast_bridge_unlock(bridge);
-
-	ao2_ref(bridge, -1);
-
-	return 0;
-}
-
-static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_str *codec_buf = ast_str_alloca(64);
-	struct ast_format *best_format;
-	RAII_VAR(struct ast_format *, read_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, write_format, NULL, ao2_cleanup);
-
-	ast_channel_lock(bridge_channel->chan);
-	read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan));
-	write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan));
-	ast_channel_unlock(bridge_channel->chan);
-
-	/* Are the formats currently in use something this bridge can handle? */
-	if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, read_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0);
-
-		/* Read format is a no go... */
-		ast_debug(1, "Bridge technology %s wants to read any of formats %s but channel has %s\n",
-			bridge->technology->name,
-			ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf),
-			ast_format_get_name(read_format));
-
-		/* Switch read format to the best one chosen */
-		if (ast_set_read_format(bridge_channel->chan, best_format)) {
-			ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n",
-				ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format));
-			ao2_cleanup(best_format);
-			return -1;
-		}
-		ast_debug(1, "Bridge %s put channel %s into read format %s\n",
-			bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(best_format));
-		ao2_cleanup(best_format);
-	} else {
-		ast_debug(1, "Bridge %s is happy that channel %s already has read format %s\n",
-			bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(read_format));
-	}
-
-	if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, write_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0);
-
-		/* Write format is a no go... */
-		ast_debug(1, "Bridge technology %s wants to write any of formats %s but channel has %s\n",
-			bridge->technology->name,
-			ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf),
-			ast_format_get_name(write_format));
-
-		/* Switch write format to the best one chosen */
-		if (ast_set_write_format(bridge_channel->chan, best_format)) {
-			ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n",
-				ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format));
-			ao2_cleanup(best_format);
-			return -1;
-		}
-		ast_debug(1, "Bridge %s put channel %s into write format %s\n",
-			bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(best_format));
-		ao2_cleanup(best_format);
-	} else {
-		ast_debug(1, "Bridge %s is happy that channel %s already has write format %s\n",
-			bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(write_format));
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Perform the smart bridge operation.
- * \since 12.0.0
- *
- * \param bridge Work on this bridge.
- *
- * \details
- * Basically see if a new bridge technology should be used instead
- * of the current one.
- *
- * \note On entry, bridge is already locked.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int smart_bridge_operation(struct ast_bridge *bridge)
-{
-	uint32_t new_capabilities;
-	struct ast_bridge_technology *new_technology;
-	struct ast_bridge_technology *old_technology = bridge->technology;
-	struct ast_bridge_channel *bridge_channel;
-	struct ast_frame *deferred_action;
-	struct ast_bridge dummy_bridge = {
-		.technology = bridge->technology,
-		.tech_pvt = bridge->tech_pvt,
-		.creator = bridge->creator,
-		.name = bridge->name,
-		.uniqueid = bridge->uniqueid,
-	};
-
-	if (bridge->dissolved) {
-		ast_debug(1, "Bridge %s is dissolved, not performing smart bridge operation.\n",
-			bridge->uniqueid);
-		return 0;
-	}
-
-	/* Determine new bridge technology capabilities needed. */
-	if (2 < bridge->num_channels) {
-		new_capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
-		new_capabilities &= bridge->allowed_capabilities;
-	} else {
-		new_capabilities = AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX;
-		new_capabilities &= bridge->allowed_capabilities;
-		if (!new_capabilities
-			&& (bridge->allowed_capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)) {
-			/* Allow switching between different multimix bridge technologies. */
-			new_capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
-		}
-	}
-
-	/* Find a bridge technology to satisfy the new capabilities. */
-	new_technology = find_best_technology(new_capabilities, bridge);
-	if (!new_technology) {
-		int is_compatible = 0;
-
-		if (old_technology->compatible) {
-			is_compatible = old_technology->compatible(bridge);
-		} else if (old_technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
-			is_compatible = 1;
-		} else if (bridge->num_channels <= 2
-			&& (old_technology->capabilities & AST_BRIDGE_CAPABILITY_1TO1MIX)) {
-			is_compatible = 1;
-		}
-
-		if (is_compatible) {
-			ast_debug(1, "Bridge %s could not get a new technology, staying with old technology.\n",
-				bridge->uniqueid);
-			return 0;
-		}
-		ast_log(LOG_WARNING, "Bridge %s has no technology available to support it.\n",
-			bridge->uniqueid);
-		return -1;
-	}
-	if (new_technology == old_technology) {
-		ast_debug(1, "Bridge %s is already using the new technology.\n",
-			bridge->uniqueid);
-		ast_module_unref(old_technology->mod);
-		return 0;
-	}
-
-	if (old_technology->destroy) {
-		struct tech_deferred_destroy deferred_tech_destroy = {
-			.tech = dummy_bridge.technology,
-			.tech_pvt = dummy_bridge.tech_pvt,
-		};
-		struct ast_frame action = {
-			.frametype = AST_FRAME_BRIDGE_ACTION,
-			.subclass.integer = BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY,
-			.data.ptr = &deferred_tech_destroy,
-			.datalen = sizeof(deferred_tech_destroy),
-		};
-
-		/*
-		 * We need to defer the bridge technology destroy callback
-		 * because we have the bridge locked.
-		 */
-		deferred_action = ast_frdup(&action);
-		if (!deferred_action) {
-			ast_module_unref(new_technology->mod);
-			return -1;
-		}
-	} else {
-		deferred_action = NULL;
-	}
-
-	/*
-	 * We are now committed to changing the bridge technology.  We
-	 * must not release the bridge lock until we have installed the
-	 * new bridge technology.
-	 */
-	ast_verb(4, "Bridge %s: switching from %s technology to %s\n",
-		bridge->uniqueid, old_technology->name, new_technology->name);
-
-	/*
-	 * Since we are soon going to pass this bridge to a new
-	 * technology we need to NULL out the tech_pvt pointer but
-	 * don't worry as it still exists in dummy_bridge, ditto for the
-	 * old technology.
-	 */
-	bridge->tech_pvt = NULL;
-	bridge->technology = new_technology;
-
-	/* Setup the new bridge technology. */
-	ast_debug(1, "Bridge %s: calling %s technology constructor\n",
-		bridge->uniqueid, new_technology->name);
-	if (new_technology->create && new_technology->create(bridge)) {
-		ast_log(LOG_WARNING, "Bridge %s: failed to setup bridge technology %s\n",
-			bridge->uniqueid, new_technology->name);
-		bridge->tech_pvt = dummy_bridge.tech_pvt;
-		bridge->technology = dummy_bridge.technology;
-		ast_module_unref(new_technology->mod);
-		return -1;
-	}
-
-	/* To ensure that things are sane for the old technology move the channels it
-	 * expects to the dummy bridge
-	 */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&bridge->channels, bridge_channel, entry) {
-		if (bridge_channel->just_joined) {
-			continue;
-		}
-		ast_debug(1, "Bridge %s: moving %p(%s) to dummy bridge temporarily\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
-		AST_LIST_REMOVE_CURRENT(entry);
-		AST_LIST_INSERT_TAIL(&dummy_bridge.channels, bridge_channel, entry);
-		dummy_bridge.num_channels++;
-		if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-			dummy_bridge.num_lonely++;
-		}
-		if (!bridge_channel->suspended) {
-			dummy_bridge.num_active++;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	/* Take all the channels out of the old technology */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&dummy_bridge.channels, bridge_channel, entry) {
-		ast_debug(1, "Bridge %s: %p(%s) is leaving %s technology (dummy)\n",
-			dummy_bridge.uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
-			old_technology->name);
-		if (old_technology->leave) {
-			old_technology->leave(&dummy_bridge, bridge_channel);
-		}
-		AST_LIST_REMOVE_CURRENT(entry);
-		AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, entry);
-		dummy_bridge.num_channels--;
-		if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-			dummy_bridge.num_lonely--;
-		}
-		if (!bridge_channel->suspended) {
-			dummy_bridge.num_active--;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	ast_debug(1, "Bridge %s: calling %s technology stop\n",
-		dummy_bridge.uniqueid, old_technology->name);
-	if (old_technology->stop) {
-		old_technology->stop(&dummy_bridge);
-	}
-
-	/* Add any new channels or re-add existing channels to the bridge. */
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		bridge_channel_complete_join(bridge, bridge_channel);
-	}
-
-	ast_debug(1, "Bridge %s: calling %s technology start\n",
-		bridge->uniqueid, new_technology->name);
-	if (new_technology->start && new_technology->start(bridge)) {
-		ast_log(LOG_WARNING, "Bridge %s: failed to start bridge technology %s\n",
-			bridge->uniqueid, new_technology->name);
-	}
-
-	/*
-	 * Now that all the channels have been moved over we need to get
-	 * rid of all the information the old technology may have left
-	 * around.
-	 */
-	if (old_technology->destroy) {
-		ast_debug(1, "Bridge %s: deferring %s technology destructor\n",
-			dummy_bridge.uniqueid, old_technology->name);
-		bridge_queue_action_nodup(bridge, deferred_action);
-	} else {
-		ast_debug(1, "Bridge %s: calling %s technology destructor\n",
-			dummy_bridge.uniqueid, old_technology->name);
-		ast_module_unref(old_technology->mod);
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Bridge channel to check if a BRIDGE_PLAY_SOUND needs to be played.
- * \since 12.0.0
- *
- * \param bridge_channel What to check.
- *
- * \return Nothing
- */
-static void check_bridge_play_sound(struct ast_bridge_channel *bridge_channel)
-{
-	const char *play_file;
-
-	ast_channel_lock(bridge_channel->chan);
-	play_file = pbx_builtin_getvar_helper(bridge_channel->chan, "BRIDGE_PLAY_SOUND");
-	if (!ast_strlen_zero(play_file)) {
-		play_file = ast_strdupa(play_file);
-		pbx_builtin_setvar_helper(bridge_channel->chan, "BRIDGE_PLAY_SOUND", NULL);
-	} else {
-		play_file = NULL;
-	}
-	ast_channel_unlock(bridge_channel->chan);
-
-	if (play_file) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, play_file, NULL);
-	}
-}
-
-/*!
- * \internal
- * \brief Check for any BRIDGE_PLAY_SOUND channel variables in the bridge.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- *
- * \note On entry, the bridge is already locked.
- *
- * \return Nothing
- */
-static void check_bridge_play_sounds(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		check_bridge_play_sound(bridge_channel);
-	}
-}
-
-static void update_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid)
-{
-	ast_channel_stage_snapshot(chan);
-	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", name);
-	pbx_builtin_setvar_helper(chan, "BRIDGEPVTCALLID", pvtid);
-	ast_channel_stage_snapshot_done(chan);
-}
-
-/*!
- * \internal
- * \brief Set BRIDGEPEER and BRIDGEPVTCALLID channel variables in a 2 party bridge.
- * \since 12.0.0
- *
- * \param c0 Party of the first part.
- * \param c1 Party of the second part.
- *
- * \note On entry, the bridge is already locked.
- * \note The bridge is expected to have exactly two parties.
- *
- * \return Nothing
- */
-static void set_bridge_peer_vars_2party(struct ast_channel *c0, struct ast_channel *c1)
-{
-	const char *c0_name;
-	const char *c1_name;
-	const char *c0_pvtid = NULL;
-	const char *c1_pvtid = NULL;
-#define UPDATE_BRIDGE_VARS_GET(chan, name, pvtid)									\
-	do {																			\
-		name = ast_strdupa(ast_channel_name(chan));									\
-		if (ast_channel_tech(chan)->get_pvt_uniqueid) {								\
-			pvtid = ast_strdupa(ast_channel_tech(chan)->get_pvt_uniqueid(chan));	\
-		}																			\
-	} while (0)
-
-	ast_channel_lock(c1);
-	UPDATE_BRIDGE_VARS_GET(c1, c1_name, c1_pvtid);
-	ast_channel_unlock(c1);
-
-	ast_channel_lock(c0);
-	update_bridge_vars_set(c0, c1_name, c1_pvtid);
-	UPDATE_BRIDGE_VARS_GET(c0, c0_name, c0_pvtid);
-	ast_channel_unlock(c0);
-
-	ast_channel_lock(c1);
-	update_bridge_vars_set(c1, c0_name, c0_pvtid);
-	ast_channel_unlock(c1);
-}
-
-/*!
- * \internal
- * \brief Fill the BRIDGEPEER value buffer with a comma separated list of channel names.
- * \since 12.0.0
- *
- * \param buf Buffer to fill.  The caller must guarantee the buffer is large enough.
- * \param cur_idx Which index into names[] to skip.
- * \param names Channel names to put in the buffer.
- * \param num_names Number of names in the array.
- *
- * \return Nothing
- */
-static void fill_bridgepeer_buf(char *buf, unsigned int cur_idx, const char *names[], unsigned int num_names)
-{
-	int need_separator = 0;
-	unsigned int idx;
-	const char *src;
-	char *pos;
-
-	pos = buf;
-	for (idx = 0; idx < num_names; ++idx) {
-		if (idx == cur_idx) {
-			continue;
-		}
-
-		if (need_separator) {
-			*pos++ = ',';
-		}
-		need_separator = 1;
-
-		/* Copy name into buffer. */
-		src = names[idx];
-		while (*src) {
-			*pos++ = *src++;
-		}
-	}
-	*pos = '\0';
-}
-
-/*!
- * \internal
- * \brief Set BRIDGEPEER and BRIDGEPVTCALLID channel variables in a multi-party bridge.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- *
- * \note On entry, the bridge is already locked.
- * \note The bridge is expected to have more than two parties.
- *
- * \return Nothing
- */
-static void set_bridge_peer_vars_multiparty(struct ast_bridge *bridge)
-{
-/*
- * Set a maximum number of channel names for the BRIDGEPEER
- * list.  The plus one is for the current channel which is not
- * put in the list.
- */
-#define MAX_BRIDGEPEER_CHANS	(10 + 1)
-
-	unsigned int idx;
-	unsigned int num_names;
-	unsigned int len;
-	const char **names;
-	char *buf;
-	struct ast_bridge_channel *bridge_channel;
-
-	/* Get first MAX_BRIDGEPEER_CHANS channel names. */
-	num_names = MIN(bridge->num_channels, MAX_BRIDGEPEER_CHANS);
-	names = ast_alloca(num_names * sizeof(*names));
-	idx = 0;
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		if (num_names <= idx) {
-			break;
-		}
-		ast_channel_lock(bridge_channel->chan);
-		names[idx++] = ast_strdupa(ast_channel_name(bridge_channel->chan));
-		ast_channel_unlock(bridge_channel->chan);
-	}
-
-	/* Determine maximum buf size needed. */
-	len = num_names;
-	for (idx = 0; idx < num_names; ++idx) {
-		len += strlen(names[idx]);
-	}
-	buf = ast_alloca(len);
-
-	/* Set the bridge channel variables. */
-	idx = 0;
-	buf[0] = '\0';
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		if (idx < num_names) {
-			fill_bridgepeer_buf(buf, idx, names, num_names);
-		}
-		++idx;
-
-		ast_channel_lock(bridge_channel->chan);
-		update_bridge_vars_set(bridge_channel->chan, buf, NULL);
-		ast_channel_unlock(bridge_channel->chan);
-	}
-}
-
-/*!
- * \internal
- * \brief Set BRIDGEPEER and BRIDGEPVTCALLID channel variables in a holding bridge.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- *
- * \note On entry, the bridge is already locked.
- *
- * \return Nothing
- */
-static void set_bridge_peer_vars_holding(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		ast_channel_lock(bridge_channel->chan);
-		update_bridge_vars_set(bridge_channel->chan, NULL, NULL);
-		ast_channel_unlock(bridge_channel->chan);
-	}
-}
-
-/*!
- * \internal
- * \brief Set BRIDGEPEER and BRIDGEPVTCALLID channel variables in the bridge.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- *
- * \note On entry, the bridge is already locked.
- *
- * \return Nothing
- */
-static void set_bridge_peer_vars(struct ast_bridge *bridge)
-{
-	if (bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
-		set_bridge_peer_vars_holding(bridge);
-		return;
-	}
-	if (bridge->num_channels < 2) {
-		return;
-	}
-	if (bridge->num_channels == 2) {
-		set_bridge_peer_vars_2party(AST_LIST_FIRST(&bridge->channels)->chan,
-			AST_LIST_LAST(&bridge->channels)->chan);
-	} else {
-		set_bridge_peer_vars_multiparty(bridge);
-	}
-}
-
-void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update)
-{
-	if (!bridge->reconfigured) {
-		return;
-	}
-	bridge->reconfigured = 0;
-	if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_SMART)
-		&& smart_bridge_operation(bridge)) {
-		/* Smart bridge failed. */
-		bridge_dissolve(bridge, 0);
-		return;
-	}
-	bridge_complete_join(bridge);
-
-	if (bridge->dissolved) {
-		return;
-	}
-	check_bridge_play_sounds(bridge);
-	set_bridge_peer_vars(bridge);
-	ast_bridge_publish_state(bridge);
-
-	if (colp_update) {
-		bridge_reconfigured_connected_line_update(bridge);
-	}
-}
-
-struct ast_bridge_channel *bridge_find_channel(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		if (bridge_channel->chan == chan) {
-			break;
-		}
-	}
-
-	return bridge_channel;
-}
-
-void ast_bridge_notify_masquerade(struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-	struct ast_bridge *bridge;
-
-	/* Safely get the bridge_channel pointer for the chan. */
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-	if (!bridge_channel) {
-		/* Not in a bridge */
-		return;
-	}
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	bridge = bridge_channel->bridge;
-	if (bridge_channel == bridge_find_channel(bridge, chan)) {
-/*
- * XXX ASTERISK-22366 this needs more work.  The channels need
- * to be made compatible again if the formats change. The
- * bridge_channel thread needs to monitor for this case.
- */
-		/* The channel we want to notify is still in a bridge. */
-		bridge->v_table->notify_masquerade(bridge, bridge_channel);
-		bridge_reconfigured(bridge, 1);
-	}
-	ast_bridge_unlock(bridge);
-	ao2_ref(bridge_channel, -1);
-}
-
-/*
- * XXX ASTERISK-21271 make ast_bridge_join() require features to be allocated just like ast_bridge_impart() and not expect the struct back.
- *
- * This change is really going to break ConfBridge.  All other
- * users are easily changed.  However, it is needed so the
- * bridging code can manipulate features on all channels
- * consistently no matter how they joined.
- *
- * Need to update the features parameter doxygen when this
- * change is made to be like ast_bridge_impart().
- */
-int ast_bridge_join(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_channel *swap,
-	struct ast_bridge_features *features,
-	struct ast_bridge_tech_optimizations *tech_args,
-	enum ast_bridge_join_flags flags)
-{
-	struct ast_bridge_channel *bridge_channel;
-	int res = 0;
-
-	bridge_channel = bridge_channel_internal_alloc(bridge);
-	if (flags & AST_BRIDGE_JOIN_PASS_REFERENCE) {
-		ao2_ref(bridge, -1);
-	}
-	if (!bridge_channel) {
-		res = -1;
-		goto join_exit;
-	}
-/* XXX ASTERISK-21271 features cannot be NULL when passed in. When it is changed to allocated we can do like ast_bridge_impart() and allocate one. */
-	ast_assert(features != NULL);
-	if (!features) {
-		ao2_ref(bridge_channel, -1);
-		res = -1;
-		goto join_exit;
-	}
-	if (tech_args) {
-		bridge_channel->tech_args = *tech_args;
-	}
-
-	ast_channel_lock(chan);
-	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
-		res = -1;
-	} else {
-		ast_channel_internal_bridge_channel_set(chan, bridge_channel);
-	}
-	ast_channel_unlock(chan);
-	bridge_channel->thread = pthread_self();
-	bridge_channel->chan = chan;
-	bridge_channel->swap = swap;
-	bridge_channel->features = features;
-	bridge_channel->inhibit_colp = !!(flags & AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP);
-
-	if (!res) {
-		res = bridge_channel_internal_join(bridge_channel);
-	}
-
-	/* Cleanup all the data in the bridge channel after it leaves the bridge. */
-	ast_channel_lock(chan);
-	ast_channel_internal_bridge_channel_set(chan, NULL);
-	ast_channel_unlock(chan);
-	bridge_channel->chan = NULL;
-	bridge_channel->swap = NULL;
-	bridge_channel->features = NULL;
-
-	ao2_ref(bridge_channel, -1);
-
-join_exit:;
-	ast_bridge_run_after_callback(chan);
-	if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)
-		&& !ast_bridge_setup_after_goto(chan)) {
-		/* Claim the after bridge goto is an async goto destination. */
-		ast_channel_lock(chan);
-		ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
-		ast_channel_unlock(chan);
-	}
-	return res;
-}
-
-/*! \brief Thread responsible for imparted bridged channels to be departed */
-static void *bridge_channel_depart_thread(void *data)
-{
-	struct ast_bridge_channel *bridge_channel = data;
-
-	if (bridge_channel->callid) {
-		ast_callid_threadassoc_add(bridge_channel->callid);
-	}
-
-	bridge_channel_internal_join(bridge_channel);
-
-	/* cleanup */
-	bridge_channel->swap = NULL;
-	ast_bridge_features_destroy(bridge_channel->features);
-	bridge_channel->features = NULL;
-
-	ast_bridge_discard_after_callback(bridge_channel->chan, AST_BRIDGE_AFTER_CB_REASON_DEPART);
-	ast_bridge_discard_after_goto(bridge_channel->chan);
-
-	return NULL;
-}
-
-/*! \brief Thread responsible for independent imparted bridged channels */
-static void *bridge_channel_ind_thread(void *data)
-{
-	struct ast_bridge_channel *bridge_channel = data;
-	struct ast_channel *chan;
-
-	if (bridge_channel->callid) {
-		ast_callid_threadassoc_add(bridge_channel->callid);
-	}
-
-	bridge_channel_internal_join(bridge_channel);
-	chan = bridge_channel->chan;
-
-	/* cleanup */
-	ast_channel_lock(chan);
-	ast_channel_internal_bridge_channel_set(chan, NULL);
-	ast_channel_unlock(chan);
-	bridge_channel->chan = NULL;
-	bridge_channel->swap = NULL;
-	ast_bridge_features_destroy(bridge_channel->features);
-	bridge_channel->features = NULL;
-
-	ao2_ref(bridge_channel, -1);
-
-	ast_bridge_run_after_callback(chan);
-	ast_bridge_run_after_goto(chan);
-	return NULL;
-}
-
-int ast_bridge_impart(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_channel *swap,
-	struct ast_bridge_features *features,
-	enum ast_bridge_impart_flags flags)
-{
-	int res = 0;
-	struct ast_bridge_channel *bridge_channel;
-
-	/* Imparted channels cannot have a PBX. */
-	if (ast_channel_pbx(chan)) {
-		ast_log(AST_LOG_WARNING, "Channel %s has a PBX thread and cannot be imparted into bridge %s\n",
-			ast_channel_name(chan), bridge->uniqueid);
-		ast_bridge_features_destroy(features);
-		return -1;
-	}
-
-	/* Supply an empty features structure if the caller did not. */
-	if (!features) {
-		features = ast_bridge_features_new();
-		if (!features) {
-			return -1;
-		}
-	}
-
-	/* Try to allocate a structure for the bridge channel */
-	bridge_channel = bridge_channel_internal_alloc(bridge);
-	if (!bridge_channel) {
-		ast_bridge_features_destroy(features);
-		return -1;
-	}
-
-	ast_channel_lock(chan);
-	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
-		ast_log(AST_LOG_NOTICE, "Channel %s is a zombie and cannot be imparted into bridge %s\n",
-			ast_channel_name(chan), bridge->uniqueid);
-		res = -1;
-	} else {
-		ast_channel_internal_bridge_channel_set(chan, bridge_channel);
-	}
-	ast_channel_unlock(chan);
-	bridge_channel->chan = chan;
-	bridge_channel->swap = swap;
-	bridge_channel->features = features;
-	bridge_channel->inhibit_colp = !!(flags & AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP);
-	bridge_channel->depart_wait =
-		(flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_DEPARTABLE;
-	bridge_channel->callid = ast_read_threadstorage_callid();
-
-	/* Actually create the thread that will handle the channel */
-	if (!res) {
-		if ((flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_INDEPENDENT) {
-			res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
-				bridge_channel_ind_thread, bridge_channel);
-		} else {
-			res = ast_pthread_create(&bridge_channel->thread, NULL,
-				bridge_channel_depart_thread, bridge_channel);
-		}
-	}
-
-	if (res) {
-		/* cleanup */
-		ast_channel_lock(chan);
-		ast_channel_internal_bridge_channel_set(chan, NULL);
-		ast_channel_unlock(chan);
-		bridge_channel->chan = NULL;
-		bridge_channel->swap = NULL;
-		ast_bridge_features_destroy(bridge_channel->features);
-		bridge_channel->features = NULL;
-
-		ao2_ref(bridge_channel, -1);
-		return -1;
-	}
-
-	return 0;
-}
-
-int ast_bridge_depart(struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-	int departable;
-
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_internal_bridge_channel(chan);
-	departable = bridge_channel && bridge_channel->depart_wait;
-	ast_channel_unlock(chan);
-	if (!departable) {
-		ast_log(LOG_ERROR, "Channel %s cannot be departed.\n",
-			ast_channel_name(chan));
-		/*
-		 * Should never happen.  It likely means that
-		 * ast_bridge_depart() is called by two threads for the same
-		 * channel, the channel was never imparted to be departed, or it
-		 * has already been departed.
-		 */
-		ast_assert(0);
-		return -1;
-	}
-
-	/*
-	 * We are claiming the bridge_channel reference held by
-	 * bridge_channel_depart_thread().
-	 */
-
-	ast_bridge_channel_leave_bridge(bridge_channel,
-		BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-
-	/* Wait for the depart thread to die */
-	ast_debug(1, "Waiting for %p(%s) bridge thread to die.\n",
-		bridge_channel, ast_channel_name(bridge_channel->chan));
-	pthread_join(bridge_channel->thread, NULL);
-
-	ast_channel_lock(chan);
-	ast_channel_internal_bridge_channel_set(chan, NULL);
-	ast_channel_unlock(chan);
-
-	/* We can get rid of the bridge_channel after the depart thread has died. */
-	ao2_ref(bridge_channel, -1);
-	return 0;
-}
-
-int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	ast_bridge_lock(bridge);
-
-	/* Try to find the channel that we want to remove */
-	if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
-		ast_bridge_unlock(bridge);
-		return -1;
-	}
-
-	ast_bridge_channel_leave_bridge(bridge_channel,
-		BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-
-	ast_bridge_unlock(bridge);
-
-	return 0;
-}
-
-static void kick_it(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
-{
-	ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
-}
-
-int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-	int res;
-
-	ast_bridge_lock(bridge);
-
-	/* Try to find the channel that we want to kick. */
-	if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
-		ast_bridge_unlock(bridge);
-		return -1;
-	}
-
-	res = ast_bridge_channel_queue_callback(bridge_channel, 0, kick_it, NULL, 0);
-
-	ast_bridge_unlock(bridge);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Point the bridge_channel to a new bridge.
- * \since 12.0.0
- *
- * \param bridge_channel What is to point to a new bridge.
- * \param new_bridge Where the bridge channel should point.
- *
- * \return Nothing
- */
-static void bridge_channel_change_bridge(struct ast_bridge_channel *bridge_channel, struct ast_bridge *new_bridge)
-{
-	struct ast_bridge *old_bridge;
-
-	ao2_ref(new_bridge, +1);
-	ast_bridge_channel_lock(bridge_channel);
-	ast_channel_lock(bridge_channel->chan);
-	old_bridge = bridge_channel->bridge;
-	bridge_channel->bridge = new_bridge;
-	ast_channel_internal_bridge_set(bridge_channel->chan, new_bridge);
-	ast_channel_unlock(bridge_channel->chan);
-	ast_bridge_channel_unlock(bridge_channel);
-	ao2_ref(old_bridge, -1);
-}
-
-static void bridge_channel_moving(struct ast_bridge_channel *bridge_channel, struct ast_bridge *src, struct ast_bridge *dst)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
-	struct ao2_iterator iter;
-
-	/* Run any moving hooks. */
-	iter = ao2_iterator_init(features->other_hooks, 0);
-	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
-		int remove_me;
-		ast_bridge_move_indicate_callback move_cb;
-
-		if (hook->type != AST_BRIDGE_HOOK_TYPE_MOVE) {
-			continue;
-		}
-		move_cb = (ast_bridge_move_indicate_callback) hook->callback;
-		remove_me = move_cb(bridge_channel, hook->hook_pvt, src, dst);
-		if (remove_me) {
-			ast_debug(1, "Move detection hook %p is being removed from %p(%s)\n",
-				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			ao2_unlink(features->other_hooks, hook);
-		}
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick,
-	unsigned int optimized)
-{
-	struct ast_bridge_channel *bridge_channel;
-	unsigned int idx;
-
-	ast_debug(1, "Merging bridge %s into bridge %s\n",
-		src_bridge->uniqueid, dst_bridge->uniqueid);
-
-	ast_bridge_publish_merge(dst_bridge, src_bridge);
-
-	/*
-	 * Move channels from src_bridge over to dst_bridge.
-	 *
-	 * We must use AST_LIST_TRAVERSE_SAFE_BEGIN() because
-	 * bridge_channel_internal_pull() alters the list we are traversing.
-	 */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&src_bridge->channels, bridge_channel, entry) {
-		if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-			/*
-			 * The channel is already leaving let it leave normally because
-			 * pulling it may delete hooks that should run for this channel.
-			 */
-			continue;
-		}
-		if (ast_test_flag(&bridge_channel->features->feature_flags,
-			AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
-			continue;
-		}
-
-		if (kick_me) {
-			for (idx = 0; idx < num_kick; ++idx) {
-				if (bridge_channel == kick_me[idx]) {
-					ast_bridge_channel_leave_bridge(bridge_channel,
-						BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-					break;
-				}
-			}
-		}
-		bridge_channel_internal_pull(bridge_channel);
-		if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-			/*
-			 * The channel died as a result of being pulled or it was
-			 * kicked.  Leave it pointing to the original bridge.
-			 */
-			continue;
-		}
-
-		bridge_channel_moving(bridge_channel, bridge_channel->bridge, dst_bridge);
-
-		/* Point to new bridge.*/
-		bridge_channel_change_bridge(bridge_channel, dst_bridge);
-
-		if (bridge_channel_internal_push(bridge_channel)) {
-			ast_bridge_features_remove(bridge_channel->features,
-				AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-			ast_bridge_channel_leave_bridge(bridge_channel,
-				BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	if (kick_me) {
-		/*
-		 * Now we can kick any channels in the dst_bridge without
-		 * potentially dissolving the bridge.
-		 */
-		for (idx = 0; idx < num_kick; ++idx) {
-			bridge_channel = kick_me[idx];
-			ast_bridge_channel_lock(bridge_channel);
-			if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-				ast_bridge_channel_leave_bridge_nolock(bridge_channel,
-					BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-				bridge_channel_internal_pull(bridge_channel);
-			}
-			ast_bridge_channel_unlock(bridge_channel);
-		}
-	}
-
-	bridge_reconfigured(dst_bridge, !optimized);
-	bridge_reconfigured(src_bridge, !optimized);
-
-	ast_debug(1, "Merged bridge %s into bridge %s\n",
-		src_bridge->uniqueid, dst_bridge->uniqueid);
-}
-
-struct merge_direction {
-	/*! Destination merge bridge. */
-	struct ast_bridge *dest;
-	/*! Source merge bridge. */
-	struct ast_bridge *src;
-};
-
-/*!
- * \internal
- * \brief Determine which bridge should merge into the other.
- * \since 12.0.0
- *
- * \param bridge1 A bridge for merging
- * \param bridge2 A bridge for merging
- *
- * \note The two bridges are assumed already locked.
- *
- * \return Which bridge merges into which or NULL bridges if cannot merge.
- */
-static struct merge_direction bridge_merge_determine_direction(struct ast_bridge *bridge1, struct ast_bridge *bridge2)
-{
-	struct merge_direction merge = { NULL, NULL };
-	int bridge1_priority;
-	int bridge2_priority;
-
-	if (!ast_test_flag(&bridge1->feature_flags,
-			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)
-		&& !ast_test_flag(&bridge2->feature_flags,
-			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-		/*
-		 * Can merge either way.  Merge to the higher priority merge
-		 * bridge.  Otherwise merge to the larger bridge.
-		 */
-		bridge1_priority = bridge1->v_table->get_merge_priority(bridge1);
-		bridge2_priority = bridge2->v_table->get_merge_priority(bridge2);
-		if (bridge2_priority < bridge1_priority) {
-			merge.dest = bridge1;
-			merge.src = bridge2;
-		} else if (bridge1_priority < bridge2_priority) {
-			merge.dest = bridge2;
-			merge.src = bridge1;
-		} else {
-			/* Merge to the larger bridge. */
-			if (bridge2->num_channels <= bridge1->num_channels) {
-				merge.dest = bridge1;
-				merge.src = bridge2;
-			} else {
-				merge.dest = bridge2;
-				merge.src = bridge1;
-			}
-		}
-	} else if (!ast_test_flag(&bridge1->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
-		&& !ast_test_flag(&bridge2->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-		/* Can merge only one way. */
-		merge.dest = bridge1;
-		merge.src = bridge2;
-	} else if (!ast_test_flag(&bridge2->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
-		&& !ast_test_flag(&bridge1->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-		/* Can merge only one way. */
-		merge.dest = bridge2;
-		merge.src = bridge1;
-	}
-
-	return merge;
-}
-
-/*!
- * \internal
- * \brief Merge two bridges together
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of merge.
- * \param src_bridge Source bridge of merge.
- * \param merge_best_direction TRUE if don't care about which bridge merges into the other.
- * \param kick_me Array of channels to kick from the bridges.
- * \param num_kick Number of channels in the kick_me array.
- *
- * \note The dst_bridge and src_bridge are assumed already locked.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int bridge_merge_locked(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, int merge_best_direction, struct ast_channel **kick_me, unsigned int num_kick)
-{
-	struct merge_direction merge;
-	struct ast_bridge_channel **kick_them = NULL;
-
-	/* Sanity check. */
-	ast_assert(dst_bridge && src_bridge && dst_bridge != src_bridge && (!num_kick || kick_me));
-
-	if (dst_bridge->dissolved || src_bridge->dissolved) {
-		ast_debug(1, "Can't merge bridges %s and %s, at least one bridge is dissolved.\n",
-			src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
-		|| ast_test_flag(&src_bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) {
-		ast_debug(1, "Can't merge bridges %s and %s, masquerade only.\n",
-			src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (dst_bridge->inhibit_merge || src_bridge->inhibit_merge) {
-		ast_debug(1, "Can't merge bridges %s and %s, merging temporarily inhibited.\n",
-			src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-
-	if (merge_best_direction) {
-		merge = bridge_merge_determine_direction(dst_bridge, src_bridge);
-	} else {
-		merge.dest = dst_bridge;
-		merge.src = src_bridge;
-	}
-
-	if (!merge.dest
-		|| ast_test_flag(&merge.dest->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
-		|| ast_test_flag(&merge.src->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-		ast_debug(1, "Can't merge bridges %s and %s, merging inhibited.\n",
-			src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (merge.src->num_channels < 2) {
-		/*
-		 * For a two party bridge, a channel may be temporarily removed
-		 * from the source bridge or the initial bridge members have not
-		 * joined yet.
-		 */
-		ast_debug(1, "Can't merge bridge %s into bridge %s, not enough channels in source bridge.\n",
-			merge.src->uniqueid, merge.dest->uniqueid);
-		return -1;
-	}
-	if (2 + num_kick < merge.dest->num_channels + merge.src->num_channels
-		&& !(merge.dest->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
-		&& (!ast_test_flag(&merge.dest->feature_flags, AST_BRIDGE_FLAG_SMART)
-			|| !(merge.dest->allowed_capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX))) {
-		ast_debug(1, "Can't merge bridge %s into bridge %s, multimix is needed and it cannot be acquired.\n",
-			merge.src->uniqueid, merge.dest->uniqueid);
-		return -1;
-	}
-
-	if (num_kick) {
-		unsigned int num_to_kick = 0;
-		unsigned int idx;
-
-		kick_them = ast_alloca(num_kick * sizeof(*kick_them));
-		for (idx = 0; idx < num_kick; ++idx) {
-			kick_them[num_to_kick] = bridge_find_channel(merge.src, kick_me[idx]);
-			if (!kick_them[num_to_kick]) {
-				kick_them[num_to_kick] = bridge_find_channel(merge.dest, kick_me[idx]);
-			}
-			if (kick_them[num_to_kick]) {
-				++num_to_kick;
-			}
-		}
-
-		if (num_to_kick != num_kick) {
-			ast_debug(1, "Can't merge bridge %s into bridge %s, at least one kicked channel is not in either bridge.\n",
-				merge.src->uniqueid, merge.dest->uniqueid);
-			return -1;
-		}
-	}
-
-	bridge_do_merge(merge.dest, merge.src, kick_them, num_kick, 0);
-	return 0;
-}
-
-int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, int merge_best_direction, struct ast_channel **kick_me, unsigned int num_kick)
-{
-	int res;
-
-	/* Sanity check. */
-	ast_assert(dst_bridge && src_bridge);
-
-	ast_bridge_lock_both(dst_bridge, src_bridge);
-	res = bridge_merge_locked(dst_bridge, src_bridge, merge_best_direction, kick_me, num_kick);
-	ast_bridge_unlock(src_bridge);
-	ast_bridge_unlock(dst_bridge);
-	return res;
-}
-
-int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery,
-	unsigned int optimized)
-{
-	struct ast_bridge *orig_bridge;
-	int was_in_bridge;
-	int res = 0;
-
-	if (bridge_channel->swap) {
-		ast_debug(1, "Moving %p(%s) into bridge %s swapping with %s\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid,
-			ast_channel_name(bridge_channel->swap));
-	} else {
-		ast_debug(1, "Moving %p(%s) into bridge %s\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid);
-	}
-
-	orig_bridge = bridge_channel->bridge;
-	was_in_bridge = bridge_channel->in_bridge;
-
-	bridge_channel_internal_pull(bridge_channel);
-	if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-		/*
-		 * The channel died as a result of being pulled.  Leave it
-		 * pointing to the original bridge.
-		 */
-		bridge_reconfigured(orig_bridge, 0);
-		return -1;
-	}
-
-	/* Point to new bridge.*/
-	ao2_ref(orig_bridge, +1);/* Keep a ref in case the push fails. */
-	bridge_channel_change_bridge(bridge_channel, dst_bridge);
-
-	bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge);
-
-	if (bridge_channel_internal_push(bridge_channel)) {
-		/* Try to put the channel back into the original bridge. */
-		ast_bridge_features_remove(bridge_channel->features,
-			AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-		if (attempt_recovery && was_in_bridge) {
-			/* Point back to original bridge. */
-			bridge_channel_change_bridge(bridge_channel, orig_bridge);
-
-			if (bridge_channel_internal_push(bridge_channel)) {
-				ast_bridge_features_remove(bridge_channel->features,
-					AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-				ast_bridge_channel_leave_bridge(bridge_channel,
-					BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
-				bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
-			}
-		} else {
-			ast_bridge_channel_leave_bridge(bridge_channel,
-				BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
-			bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
-		}
-		res = -1;
-	} else {
-		bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
-	}
-
-	bridge_reconfigured(dst_bridge, !optimized);
-	bridge_reconfigured(orig_bridge, !optimized);
-	ao2_ref(orig_bridge, -1);
-	return res;
-}
-
-/*!
- * \internal
- * \brief Move a channel from one bridge to another.
- * \since 12.0.0
- *
- * \param dst_bridge Destination bridge of bridge channel move.
- * \param src_bridge Source bridge of bridge channel move.
- * \param chan Channel to move.
- * \param swap Channel to replace in dst_bridge.
- * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
- *
- * \note The dst_bridge and src_bridge are assumed already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-static int bridge_move_locked(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	if (dst_bridge->dissolved || src_bridge->dissolved) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, at least one bridge is dissolved.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
-		|| ast_test_flag(&src_bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, masquerade only.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (dst_bridge->inhibit_merge || src_bridge->inhibit_merge) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, temporarily inhibited.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-
-	bridge_channel = bridge_find_channel(src_bridge, chan);
-	if (!bridge_channel) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel not in bridge.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel leaving bridge.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-	if (ast_test_flag(&bridge_channel->features->feature_flags,
-		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
-		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel immovable.\n",
-			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
-		return -1;
-	}
-
-	if (swap) {
-		struct ast_bridge_channel *bridge_channel_swap;
-
-		bridge_channel_swap = bridge_find_channel(dst_bridge, swap);
-		if (!bridge_channel_swap) {
-			ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, swap channel %s not in bridge.\n",
-				ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid,
-				ast_channel_name(swap));
-			return -1;
-		}
-		if (bridge_channel_swap->state != BRIDGE_CHANNEL_STATE_WAIT) {
-			ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, swap channel %s leaving bridge.\n",
-				ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid,
-				ast_channel_name(swap));
-			return -1;
-		}
-	}
-
-	bridge_channel->swap = swap;
-	return bridge_do_move(dst_bridge, bridge_channel, attempt_recovery, 0);
-}
-
-int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
-{
-	int res;
-
-	ast_bridge_lock_both(dst_bridge, src_bridge);
-	res = bridge_move_locked(dst_bridge, src_bridge, chan, swap, attempt_recovery);
-	ast_bridge_unlock(src_bridge);
-	ast_bridge_unlock(dst_bridge);
-	return res;
-}
-
-int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
-	struct ast_bridge_features *features, int play_tone, const char *xfersound)
-{
-	RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, yanked_chan, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	chan_bridge = ast_channel_get_bridge(chan);
-	ast_channel_unlock(chan);
-
-	if (chan_bridge) {
-		struct ast_bridge_channel *bridge_channel;
-
-		ast_bridge_lock_both(bridge, chan_bridge);
-		bridge_channel = bridge_find_channel(chan_bridge, chan);
-
-		if (bridge_move_locked(bridge, chan_bridge, chan, NULL, 1)) {
-			ast_bridge_unlock(chan_bridge);
-			ast_bridge_unlock(bridge);
-			return -1;
-		}
-
-		/*
-		 * bridge_move_locked() will implicitly ensure that
-		 * bridge_channel is not NULL.
-		 */
-		ast_assert(bridge_channel != NULL);
-
-		/*
-		 * Additional checks if the channel we just stole dissolves the
-		 * original bridge.
-		 */
-		bridge_dissolve_check_stolen(chan_bridge, bridge_channel);
-		ast_bridge_unlock(chan_bridge);
-		ast_bridge_unlock(bridge);
-
-		/* The channel was in a bridge so it is not getting any new features. */
-		ast_bridge_features_destroy(features);
-	} else {
-		/* Slightly less easy case. We need to yank channel A from
-		 * where he currently is and impart him into our bridge.
-		 */
-		yanked_chan = ast_channel_yank(chan);
-		if (!yanked_chan) {
-			ast_log(LOG_WARNING, "Could not gain control of channel %s\n", ast_channel_name(chan));
-			return -1;
-		}
-		if (ast_channel_state(yanked_chan) != AST_STATE_UP) {
-			ast_answer(yanked_chan);
-		}
-		ast_channel_ref(yanked_chan);
-		if (ast_bridge_impart(bridge, yanked_chan, NULL, features,
-			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-			/* It is possible for us to yank a channel and have some other
-			 * thread start a PBX on the channl after we yanked it. In particular,
-			 * this can theoretically happen on the ;2 of a Local channel if we
-			 * yank it prior to the ;1 being answered. Make sure that it isn't
-			 * executing a PBX before hanging it up.
-			 */
-			if (ast_channel_pbx(yanked_chan)) {
-				ast_channel_unref(yanked_chan);
-			} else {
-				ast_hangup(yanked_chan);
-			}
-			return -1;
-		}
-	}
-
-	if (play_tone && !ast_strlen_zero(xfersound)) {
-		struct ast_channel *play_chan = yanked_chan ?: chan;
-		RAII_VAR(struct ast_bridge_channel *, play_bridge_channel, NULL, ao2_cleanup);
-
-		ast_channel_lock(play_chan);
-		play_bridge_channel = ast_channel_get_bridge_channel(play_chan);
-		ast_channel_unlock(play_chan);
-
-		if (!play_bridge_channel) {
-			ast_log(LOG_WARNING, "Unable to play tone for channel %s. No longer in a bridge.\n",
-				ast_channel_name(play_chan));
-		} else {
-			ast_bridge_channel_queue_playfile(play_bridge_channel, NULL, xfersound, NULL);
-		}
-	}
-	return 0;
-}
-
-static int bridge_allows_optimization(struct ast_bridge *bridge)
-{
-	return !(bridge->inhibit_merge
-		|| bridge->dissolved
-		|| ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY));
-}
-
-/*!
- * \internal
- * \brief Lock the unreal channel stack for chan and prequalify it.
- * \since 12.0.0
- *
- * \param chan Unreal channel writing a frame into the channel driver.
- *
- * \note It is assumed that chan is already locked.
- *
- * \retval bridge on success with bridge and bridge_channel locked.
- * \retval NULL if cannot do optimization now.
- */
-static struct ast_bridge *optimize_lock_chan_stack(struct ast_channel *chan)
-{
-	struct ast_bridge *bridge;
-	struct ast_bridge_channel *bridge_channel;
-
-	if (!AST_LIST_EMPTY(ast_channel_readq(chan))) {
-		return NULL;
-	}
-	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF)) {
-		return NULL;
-	}
-	if (ast_channel_has_audio_frame_or_monitor(chan)) {
-		/* Channel has an active monitor, audiohook, or framehook. */
-		return NULL;
-	}
-	bridge_channel = ast_channel_internal_bridge_channel(chan);
-	if (!bridge_channel || ast_bridge_channel_trylock(bridge_channel)) {
-		return NULL;
-	}
-	bridge = bridge_channel->bridge;
-	if (bridge_channel->activity != BRIDGE_CHANNEL_THREAD_SIMPLE
-		|| bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
-		|| ast_bridge_trylock(bridge)) {
-		ast_bridge_channel_unlock(bridge_channel);
-		return NULL;
-	}
-	if (!bridge_channel_internal_allows_optimization(bridge_channel) ||
-			!bridge_allows_optimization(bridge)) {
-		ast_bridge_unlock(bridge);
-		ast_bridge_channel_unlock(bridge_channel);
-		return NULL;
-	}
-	return bridge;
-}
-
-/*!
- * \internal
- * \brief Lock the unreal channel stack for peer and prequalify it.
- * \since 12.0.0
- *
- * \param peer Other unreal channel in the pair.
- *
- * \retval bridge on success with bridge, bridge_channel, and peer locked.
- * \retval NULL if cannot do optimization now.
- */
-static struct ast_bridge *optimize_lock_peer_stack(struct ast_channel *peer)
-{
-	struct ast_bridge *bridge;
-	struct ast_bridge_channel *bridge_channel;
-
-	if (ast_channel_trylock(peer)) {
-		return NULL;
-	}
-	if (!AST_LIST_EMPTY(ast_channel_readq(peer))) {
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	if (ast_test_flag(ast_channel_flags(peer), AST_FLAG_EMULATE_DTMF)) {
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	if (ast_channel_has_audio_frame_or_monitor(peer)) {
-		/* Peer has an active monitor, audiohook, or framehook. */
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	bridge_channel = ast_channel_internal_bridge_channel(peer);
-	if (!bridge_channel || ast_bridge_channel_trylock(bridge_channel)) {
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	bridge = bridge_channel->bridge;
-	if (bridge_channel->activity != BRIDGE_CHANNEL_THREAD_IDLE
-		|| bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
-		|| ast_bridge_trylock(bridge)) {
-		ast_bridge_channel_unlock(bridge_channel);
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	if (!bridge_allows_optimization(bridge) ||
-			!bridge_channel_internal_allows_optimization(bridge_channel)) {
-		ast_bridge_unlock(bridge);
-		ast_bridge_channel_unlock(bridge_channel);
-		ast_channel_unlock(peer);
-		return NULL;
-	}
-	return bridge;
-}
-
-/*!
- * \internal
- * \brief Indicates allowability of a swap optimization
- */
-enum bridge_allow_swap {
-	/*! Bridges cannot allow for a swap optimization to occur */
-	SWAP_PROHIBITED,
-	/*! Bridge swap optimization can occur into the chan_bridge */
-	SWAP_TO_CHAN_BRIDGE,
-	/*! Bridge swap optimization can occur into the peer_bridge */
-	SWAP_TO_PEER_BRIDGE,
-};
-
-/*!
- * \internal
- * \brief Determine if two bridges allow for swap optimization to occur
- *
- * \param chan_bridge First bridge being tested
- * \param peer_bridge Second bridge being tested
- * \return Allowability of swap optimization
- */
-static enum bridge_allow_swap bridges_allow_swap_optimization(struct ast_bridge *chan_bridge,
-		struct ast_bridge *peer_bridge)
-{
-	int chan_priority;
-	int peer_priority;
-
-	if (!ast_test_flag(&chan_bridge->feature_flags,
-			AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM |
-			AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY)
-		&& !ast_test_flag(&peer_bridge->feature_flags,
-			AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM |
-			AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY)) {
-		/*
-		 * Can swap either way.  Swap to the higher priority merge
-		 * bridge.
-		 */
-		chan_priority = chan_bridge->v_table->get_merge_priority(chan_bridge);
-		peer_priority = peer_bridge->v_table->get_merge_priority(peer_bridge);
-		if (chan_bridge->num_channels == 2
-			&& chan_priority <= peer_priority) {
-			return SWAP_TO_PEER_BRIDGE;
-		} else if (peer_bridge->num_channels == 2
-			&& peer_priority <= chan_priority) {
-			return SWAP_TO_CHAN_BRIDGE;
-		}
-	} else if (chan_bridge->num_channels == 2
-		&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY)
-		&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
-		/* Can swap optimize only one way. */
-		return SWAP_TO_PEER_BRIDGE;
-	} else if (peer_bridge->num_channels == 2
-		&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY)
-		&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
-		/* Can swap optimize only one way. */
-		return SWAP_TO_CHAN_BRIDGE;
-	}
-
-	return SWAP_PROHIBITED;
-}
-
-/*!
- * \internal
- * \brief Check and attempt to swap optimize out the unreal channels.
- * \since 12.0.0
- *
- * \param chan_bridge
- * \param chan_bridge_channel
- * \param peer_bridge
- * \param peer_bridge_channel
- * \param pvt Unreal data containing callbacks to call if the optimization actually
- * happens
- *
- * \retval 1 if unreal channels failed to optimize out.
- * \retval 0 if unreal channels were not optimized out.
- * \retval -1 if unreal channels were optimized out.
- */
-static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
-	struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
-	struct ast_bridge_channel *peer_bridge_channel,
-	struct ast_unreal_pvt *pvt)
-{
-	struct ast_bridge *dst_bridge;
-	struct ast_bridge_channel *dst_bridge_channel;
-	struct ast_bridge_channel *src_bridge_channel;
-	struct ast_bridge_channel *other;
-	int res = 1;
-
-	switch (bridges_allow_swap_optimization(chan_bridge, peer_bridge)) {
-	case SWAP_TO_CHAN_BRIDGE:
-		dst_bridge = chan_bridge;
-		dst_bridge_channel = chan_bridge_channel;
-		src_bridge_channel = peer_bridge_channel;
-		break;
-	case SWAP_TO_PEER_BRIDGE:
-		dst_bridge = peer_bridge;
-		dst_bridge_channel = peer_bridge_channel;
-		src_bridge_channel = chan_bridge_channel;
-		break;
-	case SWAP_PROHIBITED:
-	default:
-		return 0;
-	}
-
-	other = ast_bridge_channel_peer(src_bridge_channel);
-	if (other && other->state == BRIDGE_CHANNEL_STATE_WAIT) {
-		unsigned int id;
-
-		if (ast_channel_trylock(other->chan)) {
-			return 1;
-		}
-
-		id = ast_atomic_fetchadd_int((int *) &optimization_id, +1);
-
-		ast_verb(4, "Move-swap optimizing %s <-- %s.\n",
-			ast_channel_name(dst_bridge_channel->chan),
-			ast_channel_name(other->chan));
-
-		if (pvt && !ast_test_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN) && pvt->callbacks
-				&& pvt->callbacks->optimization_started) {
-			pvt->callbacks->optimization_started(pvt, other->chan,
-					dst_bridge_channel->chan == pvt->owner ? AST_UNREAL_OWNER : AST_UNREAL_CHAN,
-					id);
-			ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN);
-		}
-		other->swap = dst_bridge_channel->chan;
-		if (!bridge_do_move(dst_bridge, other, 1, 1)) {
-			ast_bridge_channel_leave_bridge(src_bridge_channel,
-				BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-			res = -1;
-		}
-		if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
-			pvt->callbacks->optimization_finished(pvt, res == 1, id);
-		}
-		ast_channel_unlock(other->chan);
-	}
-	return res;
-}
-
-/*!
- * \internal
- * \brief Indicates allowability of a merge optimization
- */
-enum bridge_allow_merge {
-	/*! Bridge properties prohibit merge optimization */
-	MERGE_PROHIBITED,
-	/*! Merge optimization cannot occur because the source bridge has too few channels */
-	MERGE_NOT_ENOUGH_CHANNELS,
-	/*! Merge optimization cannot occur because multimix capability could not be requested */
-	MERGE_NO_MULTIMIX,
-	/*! Merge optimization allowed between bridges */
-	MERGE_ALLOWED,
-};
-
-/*!
- * \internal
- * \brief Determines allowability of a merge optimization
- *
- * \note The merge output parameter is undefined if MERGE_PROHIBITED is returned. For success
- * and other failure returns, a merge direction was determined, and the parameter is safe to
- * access.
- *
- * \param chan_bridge First bridge being tested
- * \param peer_bridge Second bridge being tested
- * \param num_kick_channels The number of channels to remove from the bridges during merging
- * \param[out] merge Indicates the recommended direction for the bridge merge
- */
-static enum bridge_allow_merge bridges_allow_merge_optimization(struct ast_bridge *chan_bridge,
-		struct ast_bridge *peer_bridge, int num_kick_channels, struct merge_direction *merge)
-{
-	*merge = bridge_merge_determine_direction(chan_bridge, peer_bridge);
-	if (!merge->dest) {
-		return MERGE_PROHIBITED;
-	}
-	if (merge->src->num_channels < 2) {
-		return MERGE_NOT_ENOUGH_CHANNELS;
-	} else if ((2 + num_kick_channels) < merge->dest->num_channels + merge->src->num_channels
-		&& !(merge->dest->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
-		&& (!ast_test_flag(&merge->dest->feature_flags, AST_BRIDGE_FLAG_SMART)
-			|| !(merge->dest->allowed_capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX))) {
-		return MERGE_NO_MULTIMIX;
-	}
-
-	return MERGE_ALLOWED;
-}
-
-/*!
- * \internal
- * \brief Check and attempt to merge optimize out the unreal channels.
- * \since 12.0.0
- *
- * \param chan_bridge
- * \param chan_bridge_channel
- * \param peer_bridge
- * \param peer_bridge_channel
- * \param pvt Unreal data containing callbacks to call if the optimization actually
- * happens
- *
- * \retval 0 if unreal channels were not optimized out.
- * \retval -1 if unreal channels were optimized out.
- */
-static int try_merge_optimize_out(struct ast_bridge *chan_bridge,
-	struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
-	struct ast_bridge_channel *peer_bridge_channel,
-	struct ast_unreal_pvt *pvt)
-{
-	struct merge_direction merge;
-	struct ast_bridge_channel *kick_me[] = {
-		chan_bridge_channel,
-		peer_bridge_channel,
-	};
-	unsigned int id;
-
-	switch (bridges_allow_merge_optimization(chan_bridge, peer_bridge, ARRAY_LEN(kick_me), &merge)) {
-	case MERGE_ALLOWED:
-		break;
-	case MERGE_PROHIBITED:
-		return 0;
-	case MERGE_NOT_ENOUGH_CHANNELS:
-		ast_debug(4, "Can't optimize %s -- %s out, not enough channels in bridge %s.\n",
-			ast_channel_name(chan_bridge_channel->chan),
-			ast_channel_name(peer_bridge_channel->chan),
-			merge.src->uniqueid);
-		return 0;
-	case MERGE_NO_MULTIMIX:
-		ast_debug(4, "Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
-			ast_channel_name(chan_bridge_channel->chan),
-			ast_channel_name(peer_bridge_channel->chan));
-		return 0;
-	}
-
-	ast_verb(4, "Merge optimizing %s -- %s out.\n",
-		ast_channel_name(chan_bridge_channel->chan),
-		ast_channel_name(peer_bridge_channel->chan));
-
-	id = ast_atomic_fetchadd_int((int *) &optimization_id, +1);
-
-	if (pvt && !ast_test_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN) && pvt->callbacks
-			&& pvt->callbacks->optimization_started) {
-		pvt->callbacks->optimization_started(pvt, NULL,
-				merge.dest == ast_channel_internal_bridge(pvt->owner) ? AST_UNREAL_OWNER : AST_UNREAL_CHAN,
-				id);
-		ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN);
-	}
-	bridge_do_merge(merge.dest, merge.src, kick_me, ARRAY_LEN(kick_me), 1);
-	if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
-		pvt->callbacks->optimization_finished(pvt, 1, id);
-	}
-
-	return -1;
-}
-
-int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt)
-{
-	struct ast_bridge *chan_bridge;
-	struct ast_bridge *peer_bridge;
-	struct ast_bridge_channel *chan_bridge_channel;
-	struct ast_bridge_channel *peer_bridge_channel;
-	int res = 0;
-
-	chan_bridge = optimize_lock_chan_stack(chan);
-	if (!chan_bridge) {
-		return res;
-	}
-	chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
-
-	peer_bridge = optimize_lock_peer_stack(peer);
-	if (peer_bridge) {
-		peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
-
-		res = try_swap_optimize_out(chan_bridge, chan_bridge_channel,
-			peer_bridge, peer_bridge_channel, pvt);
-		if (!res) {
-			res = try_merge_optimize_out(chan_bridge, chan_bridge_channel,
-				peer_bridge, peer_bridge_channel, pvt);
-		} else if (0 < res) {
-			res = 0;
-		}
-
-		/* Release peer locks. */
-		ast_bridge_unlock(peer_bridge);
-		ast_bridge_channel_unlock(peer_bridge_channel);
-		ast_channel_unlock(peer);
-	}
-
-	/* Release chan locks. */
-	ast_bridge_unlock(chan_bridge);
-	ast_bridge_channel_unlock(chan_bridge_channel);
-
-	return res;
-}
-
-enum ast_bridge_optimization ast_bridges_allow_optimization(struct ast_bridge *chan_bridge,
-		struct ast_bridge *peer_bridge)
-{
-	struct merge_direction merge;
-
-	if (!bridge_allows_optimization(chan_bridge) || !bridge_allows_optimization(peer_bridge)) {
-		return AST_BRIDGE_OPTIMIZE_PROHIBITED;
-	}
-
-	switch (bridges_allow_swap_optimization(chan_bridge, peer_bridge)) {
-	case SWAP_TO_CHAN_BRIDGE:
-		return AST_BRIDGE_OPTIMIZE_SWAP_TO_CHAN_BRIDGE;
-	case SWAP_TO_PEER_BRIDGE:
-		return AST_BRIDGE_OPTIMIZE_SWAP_TO_PEER_BRIDGE;
-	case SWAP_PROHIBITED:
-	default:
-		break;
-	}
-
-	/* Two channels will be kicked from the bridges, the unreal;1 and unreal;2 channels */
-	if (bridges_allow_merge_optimization(chan_bridge, peer_bridge, 2, &merge) != MERGE_ALLOWED) {
-		return AST_BRIDGE_OPTIMIZE_PROHIBITED;
-	}
-
-	if (merge.dest == chan_bridge) {
-		return AST_BRIDGE_OPTIMIZE_MERGE_TO_CHAN_BRIDGE;
-	} else {
-		return AST_BRIDGE_OPTIMIZE_MERGE_TO_PEER_BRIDGE;
-	}
-}
-
-/*!
- * \internal
- * \brief Adjust the bridge merge inhibit request count.
- * \since 12.0.0
- *
- * \param bridge What to operate on.
- * \param request Inhibit request increment.
- *     (Positive to add requests.  Negative to remove requests.)
- *
- * \note This function assumes bridge is locked.
- *
- * \return Nothing
- */
-void bridge_merge_inhibit_nolock(struct ast_bridge *bridge, int request)
-{
-	int new_request;
-
-	new_request = bridge->inhibit_merge + request;
-	ast_assert(0 <= new_request);
-	bridge->inhibit_merge = new_request;
-}
-
-void ast_bridge_merge_inhibit(struct ast_bridge *bridge, int request)
-{
-	ast_bridge_lock(bridge);
-	bridge_merge_inhibit_nolock(bridge, request);
-	ast_bridge_unlock(bridge);
-}
-
-int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-/* XXX ASTERISK-21271 the case of a disolved bridge while channel is suspended is not handled. */
-/* XXX ASTERISK-21271 suspend/unsuspend needs to be rethought. The caller must block until it has successfully suspended the channel for temporary control. */
-/* XXX ASTERISK-21271 external suspend/unsuspend needs to be eliminated. The channel may be playing a file at the time and stealing it then is not good. */
-
-	ast_bridge_lock(bridge);
-
-	if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
-		ast_bridge_unlock(bridge);
-		return -1;
-	}
-
-	bridge_channel_internal_suspend_nolock(bridge_channel);
-
-	ast_bridge_unlock(bridge);
-
-	return 0;
-}
-
-int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-/* XXX ASTERISK-21271 the case of a disolved bridge while channel is suspended is not handled. */
-
-	ast_bridge_lock(bridge);
-
-	if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
-		ast_bridge_unlock(bridge);
-		return -1;
-	}
-
-	bridge_channel_internal_unsuspend_nolock(bridge_channel);
-
-	ast_bridge_unlock(bridge);
-
-	return 0;
-}
-
-void ast_bridge_technology_suspend(struct ast_bridge_technology *technology)
-{
-	technology->suspended = 1;
-}
-
-void ast_bridge_technology_unsuspend(struct ast_bridge_technology *technology)
-{
-	/*
-	 * XXX We may want the act of unsuspending a bridge technology
-	 * to prod all existing bridges to see if they should start
-	 * using it.
-	 */
-	technology->suspended = 0;
-}
-
-int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf)
-{
-	if (ARRAY_LEN(builtin_features_handlers) <= feature
-		|| builtin_features_handlers[feature]) {
-		return -1;
-	}
-
-	if (!ast_strlen_zero(dtmf)) {
-		ast_copy_string(builtin_features_dtmf[feature], dtmf, sizeof(builtin_features_dtmf[feature]));
-	}
-
-	builtin_features_handlers[feature] = callback;
-
-	return 0;
-}
-
-int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
-{
-	if (ARRAY_LEN(builtin_features_handlers) <= feature
-		|| !builtin_features_handlers[feature]) {
-		return -1;
-	}
-
-	builtin_features_handlers[feature] = NULL;
-
-	return 0;
-}
-
-int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	ast_bridge_hook_callback callback;
-
-	if (ARRAY_LEN(builtin_features_handlers) <= feature) {
-		return -1;
-	}
-
-	callback = builtin_features_handlers[feature];
-	if (!callback) {
-		return -1;
-	}
-	callback(bridge_channel, hook_pvt);
-
-	return 0;
-}
-
-int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, ast_bridge_builtin_set_limits_fn callback)
-{
-	if (ARRAY_LEN(builtin_interval_handlers) <= interval
-		|| builtin_interval_handlers[interval]) {
-		return -1;
-	}
-
-	builtin_interval_handlers[interval] = callback;
-
-	return 0;
-}
-
-int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval)
-{
-	if (ARRAY_LEN(builtin_interval_handlers) <= interval
-		|| !builtin_interval_handlers[interval]) {
-		return -1;
-	}
-
-	builtin_interval_handlers[interval] = NULL;
-
-	return 0;
-
-}
-
-/*!
- * \internal
- * \brief Bridge hook destructor.
- * \since 12.0.0
- *
- * \param vhook Object to destroy.
- *
- * \return Nothing
- */
-static void bridge_hook_destroy(void *vhook)
-{
-	struct ast_bridge_hook *hook = vhook;
-
-	if (hook->destructor) {
-		hook->destructor(hook->hook_pvt);
-	}
-}
-
-/*!
- * \internal
- * \brief Allocate and setup a generic bridge hook.
- * \since 12.0.0
- *
- * \param size How big an object to allocate.
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- *
- * \retval hook on success.
- * \retval NULL on error.
- */
-static struct ast_bridge_hook *bridge_hook_generic(size_t size,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	struct ast_bridge_hook *hook;
-
-	/* Allocate new hook and setup it's basic variables */
-	hook = ao2_alloc_options(size, bridge_hook_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (hook) {
-		hook->callback = callback;
-		hook->destructor = destructor;
-		hook->hook_pvt = hook_pvt;
-		ast_set_flag(&hook->remove_flags, remove_flags);
-	}
-
-	return hook;
-}
-
-int ast_bridge_dtmf_hook(struct ast_bridge_features *features,
-	const char *dtmf,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	struct ast_bridge_hook_dtmf *hook;
-	int res;
-
-	/* Allocate new hook and setup it's various variables */
-	hook = (struct ast_bridge_hook_dtmf *) bridge_hook_generic(sizeof(*hook), callback,
-		hook_pvt, destructor, remove_flags);
-	if (!hook) {
-		return -1;
-	}
-	hook->generic.type = AST_BRIDGE_HOOK_TYPE_DTMF;
-	ast_copy_string(hook->dtmf.code, dtmf, sizeof(hook->dtmf.code));
-
-	/* Once done we put it in the container. */
-	res = ao2_link(features->dtmf_hooks, hook) ? 0 : -1;
-	if (res) {
-		/*
-		 * Could not link the hook into the container.
-		 *
-		 * Remove the hook_pvt destructor call from the hook since we
-		 * are returning failure to install the hook.
-		 */
-		hook->generic.destructor = NULL;
-	}
-	ao2_ref(hook, -1);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Attach an other hook to a bridge features structure
- *
- * \param features Bridge features structure
- * \param callback Function to execute upon activation
- * \param hook_pvt Unique data
- * \param destructor Optional destructor callback for hook_pvt data
- * \param remove_flags Dictates what situations the hook should be removed.
- * \param type What type of hook is being attached.
- *
- * \retval 0 on success
- * \retval -1 on failure (The caller must cleanup any hook_pvt resources.)
- */
-static int bridge_other_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags,
-	enum ast_bridge_hook_type type)
-{
-	struct ast_bridge_hook *hook;
-	int res;
-
-	/* Allocate new hook and setup it's various variables */
-	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor,
-		remove_flags);
-	if (!hook) {
-		return -1;
-	}
-	hook->type = type;
-
-	/* Once done we put it in the container. */
-	res = ao2_link(features->other_hooks, hook) ? 0 : -1;
-	if (res) {
-		/*
-		 * Could not link the hook into the container.
-		 *
-		 * Remove the hook_pvt destructor call from the hook since we
-		 * are returning failure to install the hook.
-		 */
-		hook->destructor = NULL;
-	}
-	ao2_ref(hook, -1);
-
-	return res;
-}
-
-int ast_bridge_hangup_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
-		AST_BRIDGE_HOOK_TYPE_HANGUP);
-}
-
-int ast_bridge_join_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
-		AST_BRIDGE_HOOK_TYPE_JOIN);
-}
-
-int ast_bridge_leave_hook(struct ast_bridge_features *features,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
-		AST_BRIDGE_HOOK_TYPE_LEAVE);
-}
-
-int ast_bridge_talk_detector_hook(struct ast_bridge_features *features,
-	ast_bridge_talking_indicate_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	ast_bridge_hook_callback hook_cb = (ast_bridge_hook_callback) callback;
-
-	return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
-		AST_BRIDGE_HOOK_TYPE_TALK);
-}
-
-int ast_bridge_move_hook(struct ast_bridge_features *features,
-	ast_bridge_move_indicate_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	ast_bridge_hook_callback hook_cb = (ast_bridge_hook_callback) callback;
-
-	return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
-		AST_BRIDGE_HOOK_TYPE_MOVE);
-}
-
-int ast_bridge_interval_hook(struct ast_bridge_features *features,
-	enum ast_bridge_hook_timer_option flags,
-	unsigned int interval,
-	ast_bridge_hook_callback callback,
-	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	struct ast_bridge_hook_timer *hook;
-	int res;
-
-	if (!features ||!interval || !callback) {
-		return -1;
-	}
-
-	/* Allocate new hook and setup it's various variables */
-	hook = (struct ast_bridge_hook_timer *) bridge_hook_generic(sizeof(*hook), callback,
-		hook_pvt, destructor, remove_flags);
-	if (!hook) {
-		return -1;
-	}
-	hook->generic.type = AST_BRIDGE_HOOK_TYPE_TIMER;
-	hook->timer.interval = interval;
-	hook->timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(interval, 1000));
-	hook->timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1);
-	hook->timer.flags = flags;
-
-	ast_debug(1, "Putting interval hook %p with interval %u in the heap on features %p\n",
-		hook, hook->timer.interval, features);
-	ast_heap_wrlock(features->interval_hooks);
-	res = ast_heap_push(features->interval_hooks, hook);
-	ast_heap_unlock(features->interval_hooks);
-	if (res) {
-		/*
-		 * Could not push the hook into the heap
-		 *
-		 * Remove the hook_pvt destructor call from the hook since we
-		 * are returning failure to install the hook.
-		 */
-		hook->generic.destructor = NULL;
-		ao2_ref(hook, -1);
-	}
-
-	return res ? -1 : 0;
-}
-
-int ast_bridge_features_enable(struct ast_bridge_features *features,
-	enum ast_bridge_builtin_feature feature,
-	const char *dtmf,
-	void *config,
-	ast_bridge_hook_pvt_destructor destructor,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	if (ARRAY_LEN(builtin_features_handlers) <= feature
-		|| !builtin_features_handlers[feature]) {
-		return -1;
-	}
-
-	/* If no alternate DTMF stream was provided use the default one */
-	if (ast_strlen_zero(dtmf)) {
-		dtmf = builtin_features_dtmf[feature];
-		/* If no DTMF is still available (ie: it has been disabled) then error out now */
-		if (ast_strlen_zero(dtmf)) {
-			ast_debug(1, "Failed to enable built in feature %u on %p, no DTMF string is available for it.\n",
-				feature, features);
-			return -1;
-		}
-	}
-
-	/*
-	 * The rest is basically pretty easy.  We create another hook
-	 * using the built in feature's DTMF callback.  Easy as pie.
-	 */
-	return ast_bridge_dtmf_hook(features, dtmf, builtin_features_handlers[feature],
-		config, destructor, remove_flags);
-}
-
-int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits)
-{
-	memset(limits, 0, sizeof(*limits));
-
-	if (ast_string_field_init(limits, 256)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-void ast_bridge_features_limits_destroy(struct ast_bridge_features_limits *limits)
-{
-	ast_string_field_free_memory(limits);
-}
-
-int ast_bridge_features_set_limits(struct ast_bridge_features *features,
-	struct ast_bridge_features_limits *limits,
-	enum ast_bridge_hook_remove_flags remove_flags)
-{
-	if (builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS]) {
-		ast_bridge_builtin_set_limits_fn callback;
-
-		callback = builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS];
-		return callback(features, limits, remove_flags);
-	}
-
-	ast_log(LOG_ERROR, "Attempted to set limits without an AST_BRIDGE_BUILTIN_INTERVAL_LIMITS callback registered.\n");
-	return -1;
-}
-
-void ast_bridge_features_set_flag(struct ast_bridge_features *features, unsigned int flag)
-{
-	ast_set_flag(&features->feature_flags, flag);
-	features->usable = 1;
-}
-
-/*!
- * \internal
- * \brief ao2 object match hooks with appropriate remove_flags.
- * \since 12.0.0
- *
- * \param obj Feature hook object.
- * \param arg Removal flags
- * \param flags Not used
- *
- * \retval CMP_MATCH if hook's remove_flags match the removal flags set.
- * \retval 0 if not match.
- */
-static int hook_remove_match(void *obj, void *arg, int flags)
-{
-	struct ast_bridge_hook *hook = obj;
-	enum ast_bridge_hook_remove_flags *remove_flags = arg;
-
-	if (ast_test_flag(&hook->remove_flags, *remove_flags)) {
-		return CMP_MATCH;
-	} else {
-		return 0;
-	}
-}
-
-/*!
- * \internal
- * \brief Remove all hooks with appropriate remove_flags in the container.
- * \since 12.0.0
- *
- * \param hooks Hooks container to work on.
- * \param remove_flags Determinator for whether hook is removed
- *
- * \return Nothing
- */
-static void hooks_remove_container(struct ao2_container *hooks, enum ast_bridge_hook_remove_flags remove_flags)
-{
-	ao2_callback(hooks, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
-		hook_remove_match, &remove_flags);
-}
-
-/*!
- * \internal
- * \brief Remove all hooks in the heap with appropriate remove_flags set.
- * \since 12.0.0
- *
- * \param hooks Hooks heap to work on.
- * \param remove_flags Determinator for whether hook is removed
- *
- * \return Nothing
- */
-static void hooks_remove_heap(struct ast_heap *hooks, enum ast_bridge_hook_remove_flags remove_flags)
-{
-	struct ast_bridge_hook *hook;
-	int changed;
-
-	ast_heap_wrlock(hooks);
-	do {
-		int idx;
-
-		changed = 0;
-		for (idx = ast_heap_size(hooks); idx; --idx) {
-			hook = ast_heap_peek(hooks, idx);
-			if (ast_test_flag(&hook->remove_flags, remove_flags)) {
-				ast_heap_remove(hooks, hook);
-				ao2_ref(hook, -1);
-				changed = 1;
-			}
-		}
-	} while (changed);
-	ast_heap_unlock(hooks);
-}
-
-void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags)
-{
-	hooks_remove_container(features->dtmf_hooks, remove_flags);
-	hooks_remove_container(features->other_hooks, remove_flags);
-	hooks_remove_heap(features->interval_hooks, remove_flags);
-}
-
-static int interval_hook_time_cmp(void *a, void *b)
-{
-	struct ast_bridge_hook_timer *hook_a = a;
-	struct ast_bridge_hook_timer *hook_b = b;
-	int cmp;
-
-	cmp = ast_tvcmp(hook_b->timer.trip_time, hook_a->timer.trip_time);
-	if (cmp) {
-		return cmp;
-	}
-
-	cmp = hook_b->timer.seqno - hook_a->timer.seqno;
-	return cmp;
-}
-
-/*!
- * \internal
- * \brief DTMF hook container sort comparison function.
- * \since 12.0.0
- *
- * \param obj_left pointer to the (user-defined part) of an object.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- *
- * \retval <0 if obj_left < obj_right
- * \retval =0 if obj_left == obj_right
- * \retval >0 if obj_left > obj_right
- */
-static int bridge_dtmf_hook_sort(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct ast_bridge_hook_dtmf *hook_left = obj_left;
-	const struct ast_bridge_hook_dtmf *hook_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_key = hook_right->dtmf.code;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcasecmp(hook_left->dtmf.code, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncasecmp(hook_left->dtmf.code, right_key, strlen(right_key));
-		break;
-	}
-	return cmp;
-}
-
-/*! \brief Callback for merging hook ao2_containers */
-static int merge_container_cb(void *obj, void *data, int flags)
-{
-	ao2_link(data, obj);
-	return 0;
-}
-
-/*! \brief Wrapper for interval hooks that calls into the wrapped hook */
-static int interval_wrapper_cb(struct ast_bridge_channel *bridge_channel, void *obj)
-{
-	struct ast_bridge_hook_timer *hook = obj;
-
-	return hook->generic.callback(bridge_channel, hook->generic.hook_pvt);
-}
-
-/*! \brief Destructor for the hook wrapper */
-static void interval_wrapper_pvt_dtor(void *obj)
-{
-	ao2_cleanup(obj);
-}
-
-/*! \brief Wrap the provided interval hook and add it to features */
-static void wrap_hook(struct ast_bridge_features *features, struct ast_bridge_hook_timer *hook)
-{
-	/* Break out of the current wrapper if it exists to avoid multiple layers */
-	if (hook->generic.callback == interval_wrapper_cb) {
-		hook = hook->generic.hook_pvt;
-	}
-
-	ast_bridge_interval_hook(features, hook->timer.flags, hook->timer.interval,
-		interval_wrapper_cb, ao2_bump(hook), interval_wrapper_pvt_dtor,
-		hook->generic.remove_flags.flags);
-}
-
-void ast_bridge_features_merge(struct ast_bridge_features *into, const struct ast_bridge_features *from)
-{
-	struct ast_bridge_hook_timer *hook;
-	int idx;
-
-	/* Merge hook containers */
-	ao2_callback(from->dtmf_hooks, 0, merge_container_cb, into->dtmf_hooks);
-	ao2_callback(from->other_hooks, 0, merge_container_cb, into->other_hooks);
-
-	/* Merge hook heaps */
-	ast_heap_wrlock(from->interval_hooks);
-	for (idx = 1; (hook = ast_heap_peek(from->interval_hooks, idx)); idx++) {
-		wrap_hook(into, hook);
-	}
-	ast_heap_unlock(from->interval_hooks);
-
-	/* Merge feature flags */
-	into->feature_flags.flags |= from->feature_flags.flags;
-	into->usable |= from->usable;
-
-	into->mute |= from->mute;
-	into->dtmf_passthrough |= from->dtmf_passthrough;
-}
-
-/* XXX ASTERISK-21271 make ast_bridge_features_init() static when make ast_bridge_join() requires features to be allocated. */
-int ast_bridge_features_init(struct ast_bridge_features *features)
-{
-	/* Zero out the structure */
-	memset(features, 0, sizeof(*features));
-
-	/* Initialize the DTMF hooks container */
-	features->dtmf_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, bridge_dtmf_hook_sort, NULL);
-	if (!features->dtmf_hooks) {
-		return -1;
-	}
-
-	/* Initialize the miscellaneous other hooks container */
-	features->other_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
-		NULL);
-	if (!features->other_hooks) {
-		return -1;
-	}
-
-	/* Initialize the interval hooks heap */
-	features->interval_hooks = ast_heap_create(8, interval_hook_time_cmp,
-		offsetof(struct ast_bridge_hook_timer, timer.heap_index));
-	if (!features->interval_hooks) {
-		return -1;
-	}
-
-	features->dtmf_passthrough = 1;
-
-	return 0;
-}
-
-/* XXX ASTERISK-21271 make ast_bridge_features_cleanup() static when make ast_bridge_join() requires features to be allocated. */
-void ast_bridge_features_cleanup(struct ast_bridge_features *features)
-{
-	struct ast_bridge_hook_timer *hook;
-
-	/* Destroy the interval hooks heap. */
-	if (features->interval_hooks) {
-		while ((hook = ast_heap_pop(features->interval_hooks))) {
-			ao2_ref(hook, -1);
-		}
-		features->interval_hooks = ast_heap_destroy(features->interval_hooks);
-	}
-
-	/* Destroy the miscellaneous other hooks container. */
-	ao2_cleanup(features->other_hooks);
-	features->other_hooks = NULL;
-
-	/* Destroy the DTMF hooks container. */
-	ao2_cleanup(features->dtmf_hooks);
-	features->dtmf_hooks = NULL;
-}
-
-void ast_bridge_features_destroy(struct ast_bridge_features *features)
-{
-	if (!features) {
-		return;
-	}
-	ast_bridge_features_cleanup(features);
-	ast_free(features);
-}
-
-struct ast_bridge_features *ast_bridge_features_new(void)
-{
-	struct ast_bridge_features *features;
-
-	features = ast_malloc(sizeof(*features));
-	if (features) {
-		if (ast_bridge_features_init(features)) {
-			ast_bridge_features_destroy(features);
-			features = NULL;
-		}
-	}
-
-	return features;
-}
-
-void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
-{
-	ast_bridge_lock(bridge);
-	bridge->softmix.internal_mixing_interval = mixing_interval;
-	ast_bridge_unlock(bridge);
-}
-
-void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
-{
-	ast_bridge_lock(bridge);
-	bridge->softmix.internal_sample_rate = sample_rate;
-	ast_bridge_unlock(bridge);
-}
-
-static void cleanup_video_mode(struct ast_bridge *bridge)
-{
-	switch (bridge->softmix.video_mode.mode) {
-	case AST_BRIDGE_VIDEO_MODE_NONE:
-		break;
-	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
-		if (bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
-			ast_channel_unref(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc);
-		}
-		break;
-	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
-			ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc);
-		}
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) {
-			ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc);
-		}
-	}
-	memset(&bridge->softmix.video_mode, 0, sizeof(bridge->softmix.video_mode));
-}
-
-void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
-{
-	ast_bridge_lock(bridge);
-	cleanup_video_mode(bridge);
-	bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
-	bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
-	ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s",
-		bridge->softmix.video_mode.mode, ast_channel_name(video_src_chan));
-	ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
-	ast_bridge_unlock(bridge);
-}
-
-void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
-{
-	ast_bridge_lock(bridge);
-	cleanup_video_mode(bridge);
-	bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC;
-	ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %u",
-		bridge->softmix.video_mode.mode);
-	ast_bridge_unlock(bridge);
-}
-
-void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe)
-{
-	struct ast_bridge_video_talker_src_data *data;
-
-	/* If the channel doesn't support video, we don't care about it */
-	if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) {
-		return;
-	}
-
-	ast_bridge_lock(bridge);
-	data = &bridge->softmix.video_mode.mode_data.talker_src_data;
-
-	if (data->chan_vsrc == chan) {
-		data->average_talking_energy = talker_energy;
-	} else if ((data->average_talking_energy < talker_energy) && is_keyframe) {
-		if (data->chan_old_vsrc) {
-			ast_channel_unref(data->chan_old_vsrc);
-		}
-		if (data->chan_vsrc) {
-			data->chan_old_vsrc = data->chan_vsrc;
-			ast_indicate(data->chan_old_vsrc, AST_CONTROL_VIDUPDATE);
-		}
-		data->chan_vsrc = ast_channel_ref(chan);
-		data->average_talking_energy = talker_energy;
-		ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
-		ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE);
-	} else if ((data->average_talking_energy < talker_energy) && !is_keyframe) {
-		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
-	} else if (!data->chan_vsrc && is_keyframe) {
-		data->chan_vsrc = ast_channel_ref(chan);
-		data->average_talking_energy = talker_energy;
-		ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
-		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
-	} else if (!data->chan_old_vsrc && is_keyframe) {
-		data->chan_old_vsrc = ast_channel_ref(chan);
-		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
-	}
-	ast_bridge_unlock(bridge);
-}
-
-int ast_bridge_number_video_src(struct ast_bridge *bridge)
-{
-	int res = 0;
-
-	ast_bridge_lock(bridge);
-	switch (bridge->softmix.video_mode.mode) {
-	case AST_BRIDGE_VIDEO_MODE_NONE:
-		break;
-	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
-		if (bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
-			res = 1;
-		}
-		break;
-	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
-			res++;
-		}
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) {
-			res++;
-		}
-	}
-	ast_bridge_unlock(bridge);
-	return res;
-}
-
-int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	int res = 0;
-
-	ast_bridge_lock(bridge);
-	switch (bridge->softmix.video_mode.mode) {
-	case AST_BRIDGE_VIDEO_MODE_NONE:
-		break;
-	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
-		if (bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc == chan) {
-			res = 1;
-		}
-		break;
-	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc == chan) {
-			res = 1;
-		} else if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) {
-			res = 2;
-		}
-
-	}
-	ast_bridge_unlock(bridge);
-	return res;
-}
-
-void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	ast_bridge_lock(bridge);
-	switch (bridge->softmix.video_mode.mode) {
-	case AST_BRIDGE_VIDEO_MODE_NONE:
-		break;
-	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
-		if (bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc == chan) {
-			if (bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
-				ast_channel_unref(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc);
-			}
-			bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = NULL;
-		}
-		break;
-	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc == chan) {
-			if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
-				ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc);
-			}
-			bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc = NULL;
-			bridge->softmix.video_mode.mode_data.talker_src_data.average_talking_energy = 0;
-		}
-		if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) {
-			if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) {
-				ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc);
-			}
-			bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL;
-		}
-	}
-	ast_bridge_unlock(bridge);
-}
-
-static int channel_hash(const void *obj, int flags)
-{
-	const struct ast_channel *chan = obj;
-	const char *name = obj;
-	int hash;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		name = ast_channel_name(chan);
-		/* Fall through */
-	case OBJ_KEY:
-		hash = ast_str_hash(name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/* Should never happen in hash callback. */
-		ast_assert(0);
-		hash = 0;
-		break;
-	}
-	return hash;
-}
-
-static int channel_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_channel *left = obj;
-	const struct ast_channel *right = arg;
-	const char *right_name = arg;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_name = ast_channel_name(right);
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(ast_channel_name(left), right_name);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(ast_channel_name(left), right_name, strlen(right_name));
-		break;
-	}
-	return cmp ? 0 : CMP_MATCH;
-}
-
-struct ao2_container *ast_bridge_peers_nolock(struct ast_bridge *bridge)
-{
-	struct ao2_container *channels;
-	struct ast_bridge_channel *iter;
-
-	channels = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		13, channel_hash, channel_cmp);
-	if (!channels) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
-		ao2_link(channels, iter->chan);
-	}
-
-	return channels;
-}
-
-struct ao2_container *ast_bridge_peers(struct ast_bridge *bridge)
-{
-	struct ao2_container *channels;
-
-	ast_bridge_lock(bridge);
-	channels = ast_bridge_peers_nolock(bridge);
-	ast_bridge_unlock(bridge);
-
-	return channels;
-}
-
-struct ast_channel *ast_bridge_peer_nolock(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_channel *peer = NULL;
-	struct ast_bridge_channel *iter;
-
-	/* Asking for the peer channel only makes sense on a two-party bridge. */
-	if (bridge->num_channels == 2
-		&& bridge->technology->capabilities
-			& (AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX)) {
-		int in_bridge = 0;
-
-		AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
-			if (iter->chan != chan) {
-				peer = iter->chan;
-			} else {
-				in_bridge = 1;
-			}
-		}
-		if (in_bridge && peer) {
-			ast_channel_ref(peer);
-		} else {
-			peer = NULL;
-		}
-	}
-
-	return peer;
-}
-
-struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	struct ast_channel *peer;
-
-	ast_bridge_lock(bridge);
-	peer = ast_bridge_peer_nolock(bridge, chan);
-	ast_bridge_unlock(bridge);
-
-	return peer;
-}
-
-/*!
- * \internal
- * \brief Transfer an entire bridge to a specific destination.
- *
- * This creates a local channel to dial out and swaps the called local channel
- * with the transferer channel. By doing so, all participants in the bridge are
- * connected to the specified destination.
- *
- * While this means of transferring would work for both two-party and multi-party
- * bridges, this method is only used for multi-party bridges since this method would
- * be less efficient for two-party bridges.
- *
- * \param is_external Whether the transfer is externally initiated
- * \param transferer The channel performing a transfer
- * \param bridge The bridge where the transfer is being performed
- * \param exten The destination extension for the blind transfer
- * \param context The destination context for the blind transfer
- * \param transferee The party being transferred if there is only one
- * \param new_channel_cb Callback to call on channel that is created to
- *        facilitate the blind transfer.
- * \param user_data_wrapper User-provided data needed in new_channel_cb
- * \param transfer_message The Stasis publication for this transfer.
- *
- * \return The success or failure of the operation
- */
-static enum ast_transfer_result blind_transfer_bridge(int is_external,
-		struct ast_channel *transferer, struct ast_bridge *bridge,
-		const char *exten, const char *context, struct ast_channel *transferee,
-		transfer_channel_cb new_channel_cb,
-		struct transfer_channel_data *user_data_wrapper,
-		struct ast_blind_transfer_message *transfer_message)
-{
-	struct ast_channel *local;
-	char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
-	int cause;
-
-	snprintf(chan_name, sizeof(chan_name), "%s@%s", exten, context);
-	local = ast_request("Local", ast_channel_nativeformats(transferer), NULL, transferer,
-			chan_name, &cause);
-	if (!local) {
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	ast_channel_lock_both(local, transferer);
-	ast_channel_req_accountcodes(local, transferer, AST_CHANNEL_REQUESTOR_REPLACEMENT);
-
-	transfer_message->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(local));
-	if (!transfer_message->replace_channel) {
-		ast_hangup(local);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	pbx_builtin_setvar_helper(local, BLINDTRANSFER, ast_channel_name(transferer));
-	ast_channel_unlock(local);
-	ast_channel_unlock(transferer);
-
-	if (new_channel_cb) {
-		new_channel_cb(local, user_data_wrapper, AST_BRIDGE_TRANSFER_MULTI_PARTY);
-	}
-
-	if (ast_call(local, chan_name, 0)) {
-		ast_hangup(local);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	if (ast_bridge_impart(bridge, local, transferer, NULL,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_hangup(local);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	return AST_BRIDGE_TRANSFER_SUCCESS;
-}
-
-/*!
- * \internal
- * \brief Get the transferee channel
- *
- * This is only applicable to cases where a transfer is occurring on a
- * two-party bridge. The channels container passed in is expected to only
- * contain two channels, the transferer and the transferee. The transferer
- * channel is passed in as a parameter to ensure we don't return it as
- * the transferee channel.
- *
- * \param channels A two-channel container containing the transferer and transferee
- * \param transferer The party that is transfering the call
- * \return The party that is being transferred
- */
-static struct ast_channel *get_transferee(struct ao2_container *channels, struct ast_channel *transferer)
-{
-	struct ao2_iterator channel_iter;
-	struct ast_channel *transferee;
-
-	for (channel_iter = ao2_iterator_init(channels, 0);
-			(transferee = ao2_iterator_next(&channel_iter));
-			ao2_cleanup(transferee)) {
-		if (transferee != transferer) {
-			break;
-		}
-	}
-
-	ao2_iterator_destroy(&channel_iter);
-	return transferee;
-}
-
-/*!
- * \brief Perform an attended transfer of a bridge
- *
- * This performs an attended transfer of an entire bridge to a target.
- * The target varies, depending on what bridges exist during the transfer
- * attempt.
- *
- * If two bridges exist, then a local channel is created to link the two
- * bridges together.
- *
- * If only one bridge exists, then a local channel is created with one end
- * placed into the existing bridge and the other end masquerading into
- * the unbridged channel.
- *
- * \param chan1 Transferer channel. Guaranteed to be bridged.
- * \param chan2 Other transferer channel. May or may not be bridged.
- * \param bridge1 Bridge that chan1 is in. Guaranteed to be non-NULL.
- * \param bridge2 Bridge that chan2 is in. If NULL, then chan2 is not bridged.
- * \param publication Data to publish for a stasis attended transfer message.
- * \retval AST_BRIDGE_TRANSFER_FAIL Internal error occurred
- * \retval AST_BRIDGE_TRANSFER_SUCCESS Succesfully transferred the bridge
- */
-static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *chan1,
-		struct ast_channel *chan2, struct ast_bridge *bridge1, struct ast_bridge *bridge2,
-		struct ast_attended_transfer_message *transfer_msg)
-{
-	static const char *dest = "_attended at transfer/m";
-	struct ast_channel *local_chan;
-	int cause;
-	int res;
-	const char *app = NULL;
-
-	local_chan = ast_request("Local", ast_channel_nativeformats(chan1), NULL, chan1,
-			dest, &cause);
-	if (!local_chan) {
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	ast_channel_lock_both(local_chan, chan1);
-	ast_channel_req_accountcodes(local_chan, chan1, AST_CHANNEL_REQUESTOR_REPLACEMENT);
-	pbx_builtin_setvar_helper(local_chan, ATTENDEDTRANSFER, ast_channel_name(chan1));
-	ast_channel_unlock(local_chan);
-	ast_channel_unlock(chan1);
-
-	if (bridge2) {
-		res = ast_local_setup_bridge(local_chan, bridge2, chan2, NULL);
-	} else {
-		app = ast_strdupa(ast_channel_appl(chan2));
-		res = ast_local_setup_masquerade(local_chan, chan2);
-	}
-
-	if (res) {
-		ast_hangup(local_chan);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	if (ast_call(local_chan, dest, 0)) {
-		ast_hangup(local_chan);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	/* Get a ref for use later since this one is being stolen */
-	ao2_ref(local_chan, +1);
-	if (ast_bridge_impart(bridge1, local_chan, chan1, NULL,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_hangup(local_chan);
-		ao2_cleanup(local_chan);
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	if (bridge2) {
-		RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup);
-		struct ast_channel *locals[2];
-
-		ast_channel_lock(local_chan);
-		local_chan2 = ast_local_get_peer(local_chan);
-		ast_channel_unlock(local_chan);
-
-		ast_assert(local_chan2 != NULL);
-
-		locals[0] = local_chan;
-		locals[1] = local_chan2;
-
-		ast_attended_transfer_message_add_link(transfer_msg, locals);
-	} else {
-		ast_attended_transfer_message_add_app(transfer_msg, app, local_chan);
-	}
-
-	ao2_cleanup(local_chan);
-	return AST_BRIDGE_TRANSFER_SUCCESS;
-}
-
-static enum ast_transfer_result try_parking(struct ast_channel *transferer,
-	const char *context, const char *exten, transfer_channel_cb new_channel_cb,
-	struct transfer_channel_data *user_data_wrapper)
-{
-	RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
-
-	if (!ast_parking_provider_registered()) {
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	ast_channel_lock(transferer);
-	transferer_bridge_channel = ast_channel_get_bridge_channel(transferer);
-	ast_channel_unlock(transferer);
-
-	if (!transferer_bridge_channel) {
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	if (ast_parking_blind_transfer_park(transferer_bridge_channel,
-		context, exten, new_channel_cb, user_data_wrapper)) {
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	return AST_BRIDGE_TRANSFER_SUCCESS;
-}
-
-void ast_bridge_set_transfer_variables(struct ast_channel *chan, const char *value, int attended)
-{
-	char *writevar;
-	char *erasevar;
-
-	if (attended) {
-		writevar = ATTENDEDTRANSFER;
-		erasevar = BLINDTRANSFER;
-	} else {
-		writevar = BLINDTRANSFER;
-		erasevar = ATTENDEDTRANSFER;
-	}
-
-	pbx_builtin_setvar_helper(chan, writevar, value);
-	pbx_builtin_setvar_helper(chan, erasevar, NULL);
-}
-
-/*!
- * \internal
- * \brief Set the transfer variable as appropriate on channels involved in the transfer
- *
- * The transferer channel will have its variable set the same as its BRIDGEPEER
- * variable. This will account for all channels that it is bridged to. The other channels
- * involved in the transfer will have their variable set to the transferer
- * channel's name.
- *
- * \param transferer The channel performing the transfer
- * \param channels The channels belonging to the bridge
- * \param is_attended false  set BLINDTRANSFER and unset ATTENDEDTRANSFER
- *                    true   set ATTENDEDTRANSFER and unset BLINDTRANSFER
- */
-static void set_transfer_variables_all(struct ast_channel *transferer, struct ao2_container *channels, int is_attended)
-{
-	struct ao2_iterator iter;
-	struct ast_channel *chan;
-	const char *transferer_name;
-	const char *transferer_bridgepeer;
-
-	ast_channel_lock(transferer);
-	transferer_name = ast_strdupa(ast_channel_name(transferer));
-	transferer_bridgepeer = ast_strdupa(S_OR(pbx_builtin_getvar_helper(transferer, "BRIDGEPEER"), ""));
-	ast_channel_unlock(transferer);
-
-	for (iter = ao2_iterator_init(channels, 0);
-			(chan = ao2_iterator_next(&iter));
-			ao2_cleanup(chan)) {
-		if (chan == transferer) {
-			ast_bridge_set_transfer_variables(chan, transferer_bridgepeer, is_attended);
-		} else {
-			ast_bridge_set_transfer_variables(chan, transferer_name, is_attended);
-		}
-	}
-
-	ao2_iterator_destroy(&iter);
-}
-
-static struct ast_bridge *acquire_bridge(struct ast_channel *chan)
-{
-	struct ast_bridge *bridge;
-
-	ast_channel_lock(chan);
-	bridge = ast_channel_get_bridge(chan);
-	ast_channel_unlock(chan);
-
-	if (bridge
-		&& ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) {
-		ao2_ref(bridge, -1);
-		bridge = NULL;
-	}
-
-	return bridge;
-}
-
-enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
-		struct ast_channel *transferer, const char *exten, const char *context,
-		transfer_channel_cb new_channel_cb, void *user_data)
-{
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup);
-	RAII_VAR(struct transfer_channel_data *, user_data_wrapper, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_blind_transfer_message *, transfer_message, NULL, ao2_cleanup);
-	int do_bridge_transfer;
-	int transfer_prohibited;
-	enum ast_transfer_result transfer_result;
-
-	transfer_message = ast_blind_transfer_message_create(is_external, transferer, exten, context);
-	if (!transfer_message) {
-		/* Out of memory. Not even possible to publish a Stasis message about the
-		 * failure
-		 */
-		ast_log(LOG_ERROR, "Unable to allocate memory for blind transfer publication from %s\n",
-				ast_channel_name(transferer));
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	bridge = acquire_bridge(transferer);
-	if (!bridge) {
-		transfer_result = AST_BRIDGE_TRANSFER_INVALID;
-		goto publish;
-	}
-
-	ast_bridge_lock(bridge);
-	transfer_message->bridge = ast_bridge_snapshot_create(bridge);
-	ast_bridge_unlock(bridge);
-	if (!transfer_message->bridge) {
-		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-		goto publish;
-	}
-
-	transferee = ast_bridge_peer(bridge, transferer);
-	if (transferee) {
-		transfer_message->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
-		if (!transfer_message->transferee) {
-			transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-			goto publish;
-		}
-	}
-
-	ast_channel_lock(transferer);
-	bridge_channel = ast_channel_get_bridge_channel(transferer);
-	ast_channel_unlock(transferer);
-	if (!bridge_channel) {
-		transfer_result = AST_BRIDGE_TRANSFER_INVALID;
-		goto publish;
-	}
-
-	user_data_wrapper = ao2_alloc(sizeof(*user_data_wrapper), NULL);
-	if (!user_data_wrapper) {
-		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-		goto publish;
-	}
-
-	user_data_wrapper->data = user_data;
-
-	/* Take off hold if they are on hold. */
-	ast_bridge_channel_write_unhold(bridge_channel);
-
-	transfer_result = try_parking(transferer, context, exten, new_channel_cb, user_data_wrapper);
-	if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
-		goto publish;
-	}
-
-	/* Since parking didn't take control of the user_data_wrapper, we are just going to raise the completed flag now. */
-	user_data_wrapper->completed = 1;
-
-	{
-		SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
-
-		channels = ast_bridge_peers_nolock(bridge);
-		if (!channels) {
-			transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-			goto publish;
-		}
-		if (ao2_container_count(channels) <= 1) {
-			transfer_result = AST_BRIDGE_TRANSFER_INVALID;
-			goto publish;
-		}
-		transfer_prohibited = ast_test_flag(&bridge->feature_flags,
-				AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
-		do_bridge_transfer = ast_test_flag(&bridge->feature_flags,
-				AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY) ||
-				ao2_container_count(channels) > 2;
-	}
-
-	if (transfer_prohibited) {
-		transfer_result = AST_BRIDGE_TRANSFER_NOT_PERMITTED;
-		goto publish;
-	}
-
-	set_transfer_variables_all(transferer, channels, 0);
-
-	if (do_bridge_transfer) {
-		transfer_result = blind_transfer_bridge(is_external, transferer, bridge,
-			exten, context, transferee, new_channel_cb, user_data_wrapper, transfer_message);
-		goto publish;
-	}
-
-	/* Reaching this portion means that we're dealing with a two-party bridge */
-
-	if (!transferee) {
-		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-		goto publish;
-	}
-
-	if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
-				new_channel_cb, user_data_wrapper)) {
-		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-		goto publish;
-	}
-
-	ast_bridge_remove(bridge, transferer);
-	transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
-
-publish:
-	transfer_message->result = transfer_result;
-	ast_bridge_publish_blind_transfer(transfer_message);
-	return transfer_result;
-}
-
-/*!
- * \internal
- * \brief Performs an attended transfer by moving a channel from one bridge to another
- *
- * The channel that is bridged to the source_channel is moved into the dest_bridge from
- * the source_bridge_channel's bridge. The swap_channel is swapped out of the dest_bridge and placed in
- * the source_bridge_channel's bridge.
- *
- * \note dest_bridge and source_bridge_channel's bridge MUST be locked before calling this function.
- *
- * \param dest_bridge The final bridge for the attended transfer
- * \param source_channel Channel who is bridged to the channel that will move
- * \param swap_channel Channel to be swapped out of the dest_bridge
- * \return The success or failure of the swap attempt
- */
-static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge *dest_bridge,
-		struct ast_bridge_channel *source_bridge_channel, struct ast_channel *swap_channel)
-{
-	struct ast_bridge_channel *bridged_to_source;
-
-	bridged_to_source = ast_bridge_channel_peer(source_bridge_channel);
-	if (bridged_to_source
-		&& bridged_to_source->state == BRIDGE_CHANNEL_STATE_WAIT
-		&& !ast_test_flag(&bridged_to_source->features->feature_flags,
-			AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
-		bridged_to_source->swap = swap_channel;
-		if (bridge_do_move(dest_bridge, bridged_to_source, 1, 0)) {
-			return AST_BRIDGE_TRANSFER_FAIL;
-		}
-		/* Must kick the source channel out of its bridge. */
-		ast_bridge_channel_leave_bridge(source_bridge_channel,
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-		return AST_BRIDGE_TRANSFER_SUCCESS;
-	} else {
-		return AST_BRIDGE_TRANSFER_INVALID;
-	}
-}
-
-/*!
- * \internal
- * \brief Function that performs an attended transfer when both transferer channels are bridged
- *
- * The method by which the transfer is performed is dependent on whether the bridges allow for
- * optimization to occur between them. If no optimization is permitted, then an unreal channel
- * is placed as a link between the two bridges. If optimization is permitted, then that means
- * we are free to perform move or merge operations in order to perform the transfer.
- *
- * \note to_transferee_bridge and to_target_bridge MUST be locked before calling this function
- *
- * \param to_transferee The channel that is bridged to the transferee
- * \param to_transferee_bridge_channel to_transferee's bridge_channel
- * \param to_transfer_target The channel that is bridged to the transfer target
- * \param to_target_bridge_channel to_transfer_target's bridge_channel
- * \param to_transferee_bridge The bridge between to_transferee and the transferee
- * \param to_target_bridge The bridge between to_transfer_target and the transfer_target
- * \param publication Data to publish for a stasis attended transfer message
- * \return The success or failure of the attended transfer
- */
-static enum ast_transfer_result two_bridge_attended_transfer(struct ast_channel *to_transferee,
-		struct ast_bridge_channel *to_transferee_bridge_channel,
-		struct ast_channel *to_transfer_target,
-		struct ast_bridge_channel *to_target_bridge_channel,
-		struct ast_bridge *to_transferee_bridge, struct ast_bridge *to_target_bridge,
-		struct ast_attended_transfer_message *transfer_msg)
-{
-	struct ast_bridge_channel *kick_me[] = {
-			to_transferee_bridge_channel,
-			to_target_bridge_channel,
-	};
-	enum ast_transfer_result res;
-	struct ast_bridge *final_bridge = NULL;
-	RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
-
-	channels = ast_bridge_peers_nolock(to_transferee_bridge);
-
-	if (!channels) {
-		res = AST_BRIDGE_TRANSFER_FAIL;
-		goto end;
-	}
-
-	set_transfer_variables_all(to_transferee, channels, 1);
-
-	switch (ast_bridges_allow_optimization(to_transferee_bridge, to_target_bridge)) {
-	case AST_BRIDGE_OPTIMIZE_SWAP_TO_CHAN_BRIDGE:
-		final_bridge = to_transferee_bridge;
-		res = bridge_swap_attended_transfer(to_transferee_bridge, to_target_bridge_channel, to_transferee);
-		goto end;
-	case AST_BRIDGE_OPTIMIZE_SWAP_TO_PEER_BRIDGE:
-		final_bridge = to_target_bridge;
-		res = bridge_swap_attended_transfer(to_target_bridge, to_transferee_bridge_channel, to_transfer_target);
-		goto end;
-	case AST_BRIDGE_OPTIMIZE_MERGE_TO_CHAN_BRIDGE:
-		final_bridge = to_transferee_bridge;
-		bridge_do_merge(to_transferee_bridge, to_target_bridge, kick_me, ARRAY_LEN(kick_me), 0);
-		res = AST_BRIDGE_TRANSFER_SUCCESS;
-		goto end;
-	case AST_BRIDGE_OPTIMIZE_MERGE_TO_PEER_BRIDGE:
-		final_bridge = to_target_bridge;
-		bridge_do_merge(to_target_bridge, to_transferee_bridge, kick_me, ARRAY_LEN(kick_me), 0);
-		res = AST_BRIDGE_TRANSFER_SUCCESS;
-		goto end;
-	case AST_BRIDGE_OPTIMIZE_PROHIBITED:
-	default:
-		/* Just because optimization wasn't doable doesn't necessarily mean
-		 * that we can actually perform the transfer. Some reasons for non-optimization
-		 * indicate bridge invalidity, so let's check those before proceeding.
-		 */
-		if (to_transferee_bridge->inhibit_merge || to_transferee_bridge->dissolved ||
-				to_target_bridge->inhibit_merge || to_target_bridge->dissolved) {
-			return AST_BRIDGE_TRANSFER_INVALID;
-		}
-
-		return attended_transfer_bridge(to_transferee, to_transfer_target,
-			to_transferee_bridge, to_target_bridge, transfer_msg);
-	}
-
-end:
-	if (res == AST_BRIDGE_TRANSFER_SUCCESS) {
-		ast_attended_transfer_message_add_merge(transfer_msg, final_bridge);
-	}
-
-	return res;
-}
-
-enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee,
-		struct ast_channel *to_transfer_target)
-{
-	RAII_VAR(struct ast_bridge *, to_transferee_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bridge *, to_target_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bridge_channel *, to_transferee_bridge_channel, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bridge_channel *, to_target_bridge_channel, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, transferee, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
-	struct ast_bridge *the_bridge = NULL;
-	struct ast_channel *chan_bridged;
-	struct ast_channel *chan_unbridged;
-	int transfer_prohibited;
-	int do_bridge_transfer;
-	enum ast_transfer_result res;
-	const char *app = NULL;
-
-	to_transferee_bridge = acquire_bridge(to_transferee);
-	to_target_bridge = acquire_bridge(to_transfer_target);
-
-	transfer_msg = ast_attended_transfer_message_create(1, to_transferee, to_transferee_bridge,
-			to_transfer_target, to_target_bridge, NULL, NULL);
-	if (!transfer_msg) {
-		ast_log(LOG_ERROR, "Unable to create Stasis publication for attended transfer from %s\n",
-				ast_channel_name(to_transferee));
-		return AST_BRIDGE_TRANSFER_FAIL;
-	}
-
-	/* They can't both be unbridged, you silly goose! */
-	if (!to_transferee_bridge && !to_target_bridge) {
-		res = AST_BRIDGE_TRANSFER_INVALID;
-		goto end;
-	}
-
-	ast_channel_lock(to_transferee);
-	to_transferee_bridge_channel = ast_channel_get_bridge_channel(to_transferee);
-	ast_channel_unlock(to_transferee);
-
-	ast_channel_lock(to_transfer_target);
-	to_target_bridge_channel = ast_channel_get_bridge_channel(to_transfer_target);
-	ast_channel_unlock(to_transfer_target);
-
-	if (to_transferee_bridge_channel) {
-		/* Take off hold if they are on hold. */
-		ast_bridge_channel_write_unhold(to_transferee_bridge_channel);
-	}
-
-	if (to_target_bridge_channel) {
-		const char *target_complete_sound;
-
-		/* Take off hold if they are on hold. */
-		ast_bridge_channel_write_unhold(to_target_bridge_channel);
-
-		/* Is there a courtesy sound to play to the target? */
-		ast_channel_lock(to_transfer_target);
-		target_complete_sound = pbx_builtin_getvar_helper(to_transfer_target,
-			"ATTENDED_TRANSFER_COMPLETE_SOUND");
-		if (!ast_strlen_zero(target_complete_sound)) {
-			target_complete_sound = ast_strdupa(target_complete_sound);
-		} else {
-			target_complete_sound = NULL;
-		}
-		ast_channel_unlock(to_transfer_target);
-		if (!target_complete_sound) {
-			ast_channel_lock(to_transferee);
-			target_complete_sound = pbx_builtin_getvar_helper(to_transferee,
-				"ATTENDED_TRANSFER_COMPLETE_SOUND");
-			if (!ast_strlen_zero(target_complete_sound)) {
-				target_complete_sound = ast_strdupa(target_complete_sound);
-			} else {
-				target_complete_sound = NULL;
-			}
-			ast_channel_unlock(to_transferee);
-		}
-		if (target_complete_sound) {
-			ast_bridge_channel_write_playfile(to_target_bridge_channel, NULL,
-				target_complete_sound, NULL);
-		}
-	}
-
-	/* Let's get the easy one out of the way first */
-	if (to_transferee_bridge && to_target_bridge) {
-
-		if (!to_transferee_bridge_channel || !to_target_bridge_channel) {
-			res = AST_BRIDGE_TRANSFER_INVALID;
-			goto end;
-		}
-
-		ast_bridge_lock_both(to_transferee_bridge, to_target_bridge);
-		res = two_bridge_attended_transfer(to_transferee, to_transferee_bridge_channel,
-				to_transfer_target, to_target_bridge_channel,
-				to_transferee_bridge, to_target_bridge, transfer_msg);
-		ast_bridge_unlock(to_transferee_bridge);
-		ast_bridge_unlock(to_target_bridge);
-
-		goto end;
-	}
-
-	the_bridge = to_transferee_bridge ?: to_target_bridge;
-	chan_bridged = to_transferee_bridge ? to_transferee : to_transfer_target;
-	chan_unbridged = to_transferee_bridge ? to_transfer_target : to_transferee;
-
-	{
-		int chan_count;
-		SCOPED_LOCK(lock, the_bridge, ast_bridge_lock, ast_bridge_unlock);
-
-		channels = ast_bridge_peers_nolock(the_bridge);
-		if (!channels) {
-			res = AST_BRIDGE_TRANSFER_FAIL;
-			goto end;
-		}
-		chan_count = ao2_container_count(channels);
-		if (chan_count <= 1) {
-			res = AST_BRIDGE_TRANSFER_INVALID;
-			goto end;
-		}
-		transfer_prohibited = ast_test_flag(&the_bridge->feature_flags,
-				AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
-		do_bridge_transfer = ast_test_flag(&the_bridge->feature_flags,
-				AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY) ||
-				chan_count > 2;
-	}
-
-	if (transfer_prohibited) {
-		res = AST_BRIDGE_TRANSFER_NOT_PERMITTED;
-		goto end;
-	}
-
-	set_transfer_variables_all(to_transferee, channels, 1);
-
-	if (do_bridge_transfer) {
-		ast_bridge_lock(the_bridge);
-		res = attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL, transfer_msg);
-		ast_bridge_unlock(the_bridge);
-		goto end;
-	}
-
-	transferee = get_transferee(channels, chan_bridged);
-	if (!transferee) {
-		res = AST_BRIDGE_TRANSFER_FAIL;
-		goto end;
-	}
-
-	app = ast_strdupa(ast_channel_appl(chan_unbridged));
-	if (bridge_channel_internal_queue_attended_transfer(transferee, chan_unbridged)) {
-		res = AST_BRIDGE_TRANSFER_FAIL;
-		goto end;
-	}
-
-	ast_bridge_remove(the_bridge, chan_bridged);
-
-	ast_attended_transfer_message_add_app(transfer_msg, app, NULL);
-	res = AST_BRIDGE_TRANSFER_SUCCESS;
-
-end:
-	transfer_msg->result = res;
-	ast_bridge_publish_attended_transfer(transfer_msg);
-	return res;
-}
-
-/*!
- * \internal
- * \brief Service the bridge manager request.
- * \since 12.0.0
- *
- * \param bridge requesting service.
- *
- * \return Nothing
- */
-static void bridge_manager_service(struct ast_bridge *bridge)
-{
-	ast_bridge_lock(bridge);
-	if (bridge->callid) {
-		ast_callid_threadassoc_change(bridge->callid);
-	}
-
-	/* Do any pending bridge actions. */
-	bridge_handle_actions(bridge);
-	ast_bridge_unlock(bridge);
-}
-
-/*!
- * \internal
- * \brief Bridge manager service thread.
- * \since 12.0.0
- *
- * \return Nothing
- */
-static void *bridge_manager_thread(void *data)
-{
-	struct bridge_manager_controller *manager = data;
-	struct bridge_manager_request *request;
-
-	ao2_lock(manager);
-	while (!manager->stop) {
-		request = AST_LIST_REMOVE_HEAD(&manager->service_requests, node);
-		if (!request) {
-			ast_cond_wait(&manager->cond, ao2_object_get_lockaddr(manager));
-			continue;
-		}
-		ao2_unlock(manager);
-
-		/* Service the bridge. */
-		bridge_manager_service(request->bridge);
-		ao2_ref(request->bridge, -1);
-		ast_free(request);
-
-		ao2_lock(manager);
-	}
-	ao2_unlock(manager);
-
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Destroy the bridge manager controller.
- * \since 12.0.0
- *
- * \param obj Bridge manager to destroy.
- *
- * \return Nothing
- */
-static void bridge_manager_destroy(void *obj)
-{
-	struct bridge_manager_controller *manager = obj;
-	struct bridge_manager_request *request;
-
-	if (manager->thread != AST_PTHREADT_NULL) {
-		/* Stop the manager thread. */
-		ao2_lock(manager);
-		manager->stop = 1;
-		ast_cond_signal(&manager->cond);
-		ao2_unlock(manager);
-		ast_debug(1, "Waiting for bridge manager thread to die.\n");
-		pthread_join(manager->thread, NULL);
-	}
-
-	/* Destroy the service request queue. */
-	while ((request = AST_LIST_REMOVE_HEAD(&manager->service_requests, node))) {
-		ao2_ref(request->bridge, -1);
-		ast_free(request);
-	}
-
-	ast_cond_destroy(&manager->cond);
-}
-
-/*!
- * \internal
- * \brief Create the bridge manager controller.
- * \since 12.0.0
- *
- * \retval manager on success.
- * \retval NULL on error.
- */
-static struct bridge_manager_controller *bridge_manager_create(void)
-{
-	struct bridge_manager_controller *manager;
-
-	manager = ao2_alloc(sizeof(*manager), bridge_manager_destroy);
-	if (!manager) {
-		/* Well. This isn't good. */
-		return NULL;
-	}
-	ast_cond_init(&manager->cond, NULL);
-	AST_LIST_HEAD_INIT_NOLOCK(&manager->service_requests);
-
-	/* Create the bridge manager thread. */
-	if (ast_pthread_create(&manager->thread, NULL, bridge_manager_thread, manager)) {
-		/* Well. This isn't good either. */
-		manager->thread = AST_PTHREADT_NULL;
-		ao2_ref(manager, -1);
-		manager = NULL;
-	}
-
-	return manager;
-}
-
-/*!
- * \internal
- * \brief Bridge ao2 container sort function.
- * \since 12.0.0
- *
- * \param obj_left pointer to the (user-defined part) of an object.
- * \param obj_right pointer to the (user-defined part) of an object.
- * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
- *
- * \retval <0 if obj_left < obj_right
- * \retval =0 if obj_left == obj_right
- * \retval >0 if obj_left > obj_right
- */
-static int bridge_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct ast_bridge *bridge_left = obj_left;
-	const struct ast_bridge *bridge_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_key = bridge_right->uniqueid;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(bridge_left->uniqueid, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(bridge_left->uniqueid, right_key, strlen(right_key));
-		break;
-	}
-	return cmp;
-}
-
-struct ast_bridge *ast_bridge_find_by_id(const char *bridge_id)
-{
-	return ao2_find(bridges, bridge_id, OBJ_SEARCH_KEY);
-}
-
-struct bridge_complete {
-	/*! Nth match to return. */
-	int state;
-	/*! Which match currently on. */
-	int which;
-};
-
-static int complete_bridge_live_search(void *obj, void *arg, void *data, int flags)
-{
-	struct bridge_complete *search = data;
-
-	if (++search->which > search->state) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_bridge_live(const char *word, int state)
-{
-	char *ret;
-	struct ast_bridge *bridge;
-	struct bridge_complete search = {
-		.state = state,
-		};
-
-	bridge = ao2_callback_data(bridges, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_bridge_live_search, (char *) word, &search);
-	if (!bridge) {
-		return NULL;
-	}
-	ret = ast_strdup(bridge->uniqueid);
-	ao2_ref(bridge, -1);
-	return ret;
-}
-
-static char *complete_bridge_stasis(const char *word, int state)
-{
-	char *ret = NULL;
-	int wordlen = strlen(word), which = 0;
-	RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup);
-	struct ao2_iterator iter;
-	struct stasis_message *msg;
-
-	cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
-	if (!cached_bridges) {
-		return NULL;
-	}
-
-	iter = ao2_iterator_init(cached_bridges, 0);
-	for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
-		struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
-
-		if (!strncasecmp(word, snapshot->uniqueid, wordlen) && (++which > state)) {
-			ret = ast_strdup(snapshot->uniqueid);
-			ao2_ref(msg, -1);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	return ret;
-}
-
-static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-#define FORMAT_HDR "%-36s %5s %-15s %s\n"
-#define FORMAT_ROW "%-36s %5u %-15s %s\n"
-
-	RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup);
-	struct ao2_iterator iter;
-	struct stasis_message *msg;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge show all";
-		e->usage =
-			"Usage: bridge show all\n"
-			"       List all bridges\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
-	if (!cached_bridges) {
-		ast_cli(a->fd, "Failed to retrieve cached bridges\n");
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, FORMAT_HDR, "Bridge-ID", "Chans", "Type", "Technology");
-
-	iter = ao2_iterator_init(cached_bridges, 0);
-	for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
-		struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
-
-		ast_cli(a->fd, FORMAT_ROW,
-			snapshot->uniqueid,
-			snapshot->num_channels,
-			S_OR(snapshot->subclass, "<unknown>"),
-			S_OR(snapshot->technology, "<unknown>"));
-	}
-	ao2_iterator_destroy(&iter);
-	return CLI_SUCCESS;
-
-#undef FORMAT_HDR
-#undef FORMAT_ROW
-}
-
-/*! \brief Internal callback function for sending channels in a bridge to the CLI */
-static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
-{
-	const char *uniqueid = obj;
-	struct ast_cli_args *a = arg;
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
-
-	msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(), uniqueid);
-	if (!msg) {
-		return 0;
-	}
-	snapshot = stasis_message_data(msg);
-
-	ast_cli(a->fd, "Channel: %s\n", snapshot->name);
-
-	return 0;
-}
-
-static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_bridge_snapshot *snapshot;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge show";
-		e->usage =
-			"Usage: bridge show <bridge-id>\n"
-			"       Show information about the <bridge-id> bridge\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_bridge_stasis(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), a->argv[2]);
-	if (!msg) {
-		ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
-		return CLI_SUCCESS;
-	}
-
-	snapshot = stasis_message_data(msg);
-	ast_cli(a->fd, "Id: %s\n", snapshot->uniqueid);
-	ast_cli(a->fd, "Type: %s\n", S_OR(snapshot->subclass, "<unknown>"));
-	ast_cli(a->fd, "Technology: %s\n", S_OR(snapshot->technology, "<unknown>"));
-	ast_cli(a->fd, "Num-Channels: %u\n", snapshot->num_channels);
-	ao2_callback(snapshot->channels, OBJ_NODATA, bridge_show_specific_print_channel, a);
-
-	return CLI_SUCCESS;
-}
-
-#ifdef AST_DEVMODE
-static char *handle_bridge_destroy_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ast_bridge *bridge;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge destroy";
-		e->usage =
-			"Usage: bridge destroy <bridge-id>\n"
-			"       Destroy the <bridge-id> bridge\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_bridge_live(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	bridge = ast_bridge_find_by_id(a->argv[2]);
-	if (!bridge) {
-		ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, "Destroying bridge '%s'\n", a->argv[2]);
-	ast_bridge_destroy(bridge, 0);
-
-	return CLI_SUCCESS;
-}
-#endif
-
-static char *complete_bridge_participant(const char *bridge_name, const char *line, const char *word, int pos, int state)
-{
-	struct ast_bridge *bridge;
-	struct ast_bridge_channel *bridge_channel;
-	int which;
-	int wordlen;
-
-	bridge = ast_bridge_find_by_id(bridge_name);
-	if (!bridge) {
-		return NULL;
-	}
-
-	if (!state) {
-		ao2_ref(bridge, -1);
-		return ast_strdup("all");
-	}
-	state--;
-
-	{
-		SCOPED_LOCK(bridge_lock, bridge, ast_bridge_lock, ast_bridge_unlock);
-
-		which = 0;
-		wordlen = strlen(word);
-		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			if (!strncasecmp(ast_channel_name(bridge_channel->chan), word, wordlen)
-				&& ++which > state) {
-				ao2_ref(bridge, -1);
-				return ast_strdup(ast_channel_name(bridge_channel->chan));
-			}
-		}
-	}
-
-	ao2_ref(bridge, -1);
-
-	return NULL;
-}
-
-static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ast_bridge *bridge;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge kick";
-		e->usage =
-			"Usage: bridge kick <bridge-id> <channel-name | all>\n"
-			"       Kick the <channel-name> channel out of the <bridge-id> bridge\n"
-			"       If all is specified as the channel name then all channels will be\n"
-			"       kicked out of the bridge.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_bridge_live(a->word, a->n);
-		}
-		if (a->pos == 3) {
-			return complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	bridge = ast_bridge_find_by_id(a->argv[2]);
-	if (!bridge) {
-		ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
-		return CLI_SUCCESS;
-	}
-
-	if (!strcasecmp(a->argv[3], "all")) {
-		struct ast_bridge_channel *bridge_channel;
-
-		ast_cli(a->fd, "Kicking all channels from bridge '%s'\n", a->argv[2]);
-
-		ast_bridge_lock(bridge);
-		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			ast_bridge_channel_queue_callback(bridge_channel, 0, kick_it, NULL, 0);
-		}
-		ast_bridge_unlock(bridge);
-	} else {
-		struct ast_channel *chan;
-
-		chan = ast_channel_get_by_name_prefix(a->argv[3], strlen(a->argv[3]));
-		if (!chan) {
-			ast_cli(a->fd, "Channel '%s' not found\n", a->argv[3]);
-			ao2_ref(bridge, -1);
-			return CLI_SUCCESS;
-		}
-
-		ast_cli(a->fd, "Kicking channel '%s' from bridge '%s'\n",
-			ast_channel_name(chan), a->argv[2]);
-		ast_bridge_kick(bridge, chan);
-		ast_channel_unref(chan);
-	}
-
-	ao2_ref(bridge, -1);
-	return CLI_SUCCESS;
-}
-
-/*! Bridge technology capabilities to string. */
-static const char *tech_capability2str(uint32_t capabilities)
-{
-	const char *type;
-
-	if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
-		type = "Holding";
-	} else if (capabilities & AST_BRIDGE_CAPABILITY_EARLY) {
-		type = "Early";
-	} else if (capabilities & AST_BRIDGE_CAPABILITY_NATIVE) {
-		type = "Native";
-	} else if (capabilities & AST_BRIDGE_CAPABILITY_1TO1MIX) {
-		type = "1to1Mix";
-	} else if (capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
-		type = "MultiMix";
-	} else {
-		type = "<Unknown>";
-	}
-	return type;
-}
-
-static char *handle_bridge_technology_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-#define FORMAT_HDR "%-20s %-20s %8s %s\n"
-#define FORMAT_ROW "%-20s %-20s %8u %s\n"
-
-	struct ast_bridge_technology *cur;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge technology show";
-		e->usage =
-			"Usage: bridge technology show\n"
-			"       List registered bridge technologies\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	ast_cli(a->fd, FORMAT_HDR, "Name", "Type", "Priority", "Suspended");
-	AST_RWLIST_RDLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
-		const char *type;
-
-		/* Decode type for display */
-		type = tech_capability2str(cur->capabilities);
-
-		ast_cli(a->fd, FORMAT_ROW, cur->name, type, cur->preference,
-			AST_CLI_YESNO(cur->suspended));
-	}
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-	return CLI_SUCCESS;
-
-#undef FORMAT
-}
-
-static char *complete_bridge_technology(const char *word, int state)
-{
-	struct ast_bridge_technology *cur;
-	char *res;
-	int which;
-	int wordlen;
-
-	which = 0;
-	wordlen = strlen(word);
-	AST_RWLIST_RDLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
-		if (!strncasecmp(cur->name, word, wordlen) && ++which > state) {
-			res = ast_strdup(cur->name);
-			AST_RWLIST_UNLOCK(&bridge_technologies);
-			return res;
-		}
-	}
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-	return NULL;
-}
-
-static char *handle_bridge_technology_suspend(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ast_bridge_technology *cur;
-	int suspend;
-	int successful;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "bridge technology {suspend|unsuspend}";
-		e->usage =
-			"Usage: bridge technology {suspend|unsuspend} <technology-name>\n"
-			"       Suspend or unsuspend a bridge technology.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 3) {
-			return complete_bridge_technology(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	suspend = !strcasecmp(a->argv[2], "suspend");
-	successful = 0;
-	AST_RWLIST_WRLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
-		if (!strcasecmp(cur->name, a->argv[3])) {
-			successful = 1;
-			if (suspend) {
-				ast_bridge_technology_suspend(cur);
-			} else {
-				ast_bridge_technology_unsuspend(cur);
-			}
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-
-	if (successful) {
-		if (suspend) {
-			ast_cli(a->fd, "Suspended bridge technology '%s'\n", a->argv[3]);
-		} else {
-			ast_cli(a->fd, "Unsuspended bridge technology '%s'\n", a->argv[3]);
-		}
-	} else {
-		ast_cli(a->fd, "Bridge technology '%s' not found\n", a->argv[3]);
-	}
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry bridge_cli[] = {
-	AST_CLI_DEFINE(handle_bridge_show_all, "List all bridges"),
-	AST_CLI_DEFINE(handle_bridge_show_specific, "Show information about a bridge"),
-#ifdef AST_DEVMODE
-	AST_CLI_DEFINE(handle_bridge_destroy_specific, "Destroy a bridge"),
-#endif
-	AST_CLI_DEFINE(handle_bridge_kick_channel, "Kick a channel from a bridge"),
-	AST_CLI_DEFINE(handle_bridge_technology_show, "List registered bridge technologies"),
-	AST_CLI_DEFINE(handle_bridge_technology_suspend, "Suspend/unsuspend a bridge technology"),
-};
-
-
-static int handle_manager_bridge_tech_suspend(struct mansession *s, const struct message *m, int suspend)
-{
-	const char *name = astman_get_header(m, "BridgeTechnology");
-	struct ast_bridge_technology *cur;
-	int successful = 0;
-
-	if (ast_strlen_zero(name)) {
-		astman_send_error(s, m, "BridgeTechnology must be provided");
-		return 0;
-	}
-
-	AST_RWLIST_RDLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
-
-		if (!strcasecmp(cur->name, name)) {
-			successful = 1;
-			if (suspend) {
-				ast_bridge_technology_suspend(cur);
-			} else {
-				ast_bridge_technology_unsuspend(cur);
-			}
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-	if (!successful) {
-		astman_send_error(s, m, "BridgeTechnology not found");
-		return 0;
-	}
-
-	astman_send_ack(s, m, (suspend ? "Suspended bridge technology" : "Unsuspended bridge technology"));
-	return 0;
-}
-
-static int manager_bridge_tech_suspend(struct mansession *s, const struct message *m)
-{
-	return handle_manager_bridge_tech_suspend(s, m, 1);
-}
-
-static int manager_bridge_tech_unsuspend(struct mansession *s, const struct message *m)
-{
-	return handle_manager_bridge_tech_suspend(s, m, 0);
-}
-
-static int manager_bridge_tech_list(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
-	struct ast_bridge_technology *cur;
-
-	if (!id_text) {
-		astman_send_error(s, m, "Internal error");
-		return -1;
-	}
-
-	if (!ast_strlen_zero(id)) {
-		ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
-	}
-
-	astman_send_ack(s, m, "Bridge technology listing will follow");
-
-	AST_RWLIST_RDLOCK(&bridge_technologies);
-	AST_RWLIST_TRAVERSE(&bridge_technologies, cur, entry) {
-		const char *type;
-
-		type = tech_capability2str(cur->capabilities);
-
-		astman_append(s,
-			"Event: BridgeTechnologyListItem\r\n"
-			"BridgeTechnology: %s\r\n"
-			"BridgeType: %s\r\n"
-			"BridgePriority: %u\r\n"
-			"BridgeSuspended: %s\r\n"
-			"%s"
-			"\r\n",
-			cur->name, type, cur->preference, AST_YESNO(cur->suspended),
-			ast_str_buffer(id_text));
-	}
-	AST_RWLIST_UNLOCK(&bridge_technologies);
-
-	astman_append(s,
-		"Event: BridgeTechnologyListComplete\r\n"
-		"%s"
-		"\r\n",
-		ast_str_buffer(id_text));
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Print bridge object key (name).
- * \since 12.0.0
- *
- * \param v_obj A pointer to the object we want the key printed.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-static void bridge_prnt_obj(void *v_obj, void *where, ao2_prnt_fn *prnt)
-{
-	struct ast_bridge *bridge = v_obj;
-
-	if (!bridge) {
-		return;
-	}
-	prnt(where, "%s %s chans:%u",
-		bridge->uniqueid, bridge->v_table->name, bridge->num_channels);
-}
-
-/*!
- * \internal
- * \brief Shutdown the bridging system.
- * \since 12.0.0
- *
- * \return Nothing
- */
-static void bridge_shutdown(void)
-{
-	ast_manager_unregister("BridgeTechnologyList");
-	ast_manager_unregister("BridgeTechnologySuspend");
-	ast_manager_unregister("BridgeTechnologyUnsuspend");
-	ast_cli_unregister_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
-	ao2_container_unregister("bridges");
-	ao2_cleanup(bridges);
-	bridges = NULL;
-	ao2_cleanup(bridge_manager);
-	bridge_manager = NULL;
-}
-
-int ast_bridging_init(void)
-{
-	ast_register_atexit(bridge_shutdown);
-
-	if (ast_stasis_bridging_init()) {
-		return -1;
-	}
-
-	bridge_manager = bridge_manager_create();
-	if (!bridge_manager) {
-		return -1;
-	}
-
-	bridges = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, bridge_sort_cmp, NULL);
-	if (!bridges) {
-		return -1;
-	}
-	ao2_container_register("bridges", bridges, bridge_prnt_obj);
-
-	ast_bridging_init_basic();
-
-	ast_cli_register_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
-
-	ast_manager_register_xml_core("BridgeTechnologyList", 0, manager_bridge_tech_list);
-	ast_manager_register_xml_core("BridgeTechnologySuspend", 0, manager_bridge_tech_suspend);
-	ast_manager_register_xml_core("BridgeTechnologyUnsuspend", 0, manager_bridge_tech_unsuspend);
-
-	return 0;
-}
diff --git a/main/bridge_after.c b/main/bridge_after.c
deleted file mode 100644
index 63b87b5..0000000
--- a/main/bridge_after.c
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2007 - 2009, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief After Bridge Execution API
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420940 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/bridge_after.h"
-
-struct after_bridge_cb_node {
-	/*! Next list node. */
-	AST_LIST_ENTRY(after_bridge_cb_node) list;
-	/*! Desired callback function. */
-	ast_bridge_after_cb callback;
-	/*! After bridge callback will not be called and destroy any resources data may contain. */
-	ast_bridge_after_cb_failed failed;
-	/*! Extra data to pass to the callback. */
-	void *data;
-	/*! Reason the after bridge callback failed. */
-	enum ast_bridge_after_cb_reason reason;
-};
-
-struct after_bridge_cb_ds {
-	/*! After bridge callbacks container. */
-	AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
-};
-
-/*!
- * \internal
- * \brief Indicate after bridge callback failed.
- * \since 12.0.0
- *
- * \param node After bridge callback node.
- *
- * \return Nothing
- */
-static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
-{
-	if (node->failed) {
-		node->failed(node->reason, node->data);
-		node->failed = NULL;
-	}
-}
-
-/*!
- * \internal
- * \brief Run discarding any after bridge callbacks.
- * \since 12.0.0
- *
- * \param after_bridge After bridge callback container process.
- * \param reason Why are we doing this.
- *
- * \return Nothing
- */
-static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
-{
-	struct after_bridge_cb_node *node;
-
-	for (;;) {
-		AST_LIST_LOCK(&after_bridge->callbacks);
-		node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
-		AST_LIST_UNLOCK(&after_bridge->callbacks);
-		if (!node) {
-			break;
-		}
-		if (!node->reason) {
-			node->reason = reason;
-		}
-		after_bridge_cb_failed(node);
-		ast_free(node);
-	}
-}
-
-/*!
- * \internal
- * \brief Destroy the after bridge callback datastore.
- * \since 12.0.0
- *
- * \param data After bridge callback data to destroy.
- *
- * \return Nothing
- */
-static void after_bridge_cb_destroy(void *data)
-{
-	struct after_bridge_cb_ds *after_bridge = data;
-
-	after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
-
-	AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
-	ast_free(after_bridge);
-}
-
-static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
-
-/*!
- * \internal
- * \brief Fixup the after bridge callback datastore.
- * \since 12.0.0
- *
- * \param data After bridge callback data to fixup.
- * \param old_chan The datastore is moving from this channel.
- * \param new_chan The datastore is moving to this channel.
- *
- * \return Nothing
- */
-static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct after_bridge_cb_ds *after_bridge;
-	struct after_bridge_cb_node *node;
-
-	after_bridge = after_bridge_cb_find(new_chan);
-	if (!after_bridge) {
-		return;
-	}
-
-	AST_LIST_LOCK(&after_bridge->callbacks);
-	node = AST_LIST_LAST(&after_bridge->callbacks);
-	if (node && !node->reason) {
-		node->reason = AST_BRIDGE_AFTER_CB_REASON_MASQUERADE;
-	}
-	AST_LIST_UNLOCK(&after_bridge->callbacks);
-}
-
-static const struct ast_datastore_info after_bridge_cb_info = {
-	.type = "after-bridge-cb",
-	.destroy = after_bridge_cb_destroy,
-	.chan_fixup = after_bridge_cb_fixup,
-};
-
-/*!
- * \internal
- * \brief Find an after bridge callback datastore container.
- * \since 12.0.0
- *
- * \param chan Channel to find the after bridge callback container on.
- *
- * \retval after_bridge datastore container on success.
- * \retval NULL on error.
- */
-static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
-	if (!datastore) {
-		return NULL;
-	}
-	return datastore->data;
-}
-
-/*!
- * \internal
- * \brief Setup/create an after bridge callback datastore container.
- * \since 12.0.0
- *
- * \param chan Channel to setup/create the after bridge callback container on.
- *
- * \retval after_bridge datastore container on success.
- * \retval NULL on error.
- */
-static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-	struct after_bridge_cb_ds *after_bridge;
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
-	if (datastore) {
-		return datastore->data;
-	}
-
-	/* Create a new datastore. */
-	datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
-	if (!datastore) {
-		return NULL;
-	}
-	after_bridge = ast_calloc(1, sizeof(*after_bridge));
-	if (!after_bridge) {
-		ast_datastore_free(datastore);
-		return NULL;
-	}
-	AST_LIST_HEAD_INIT(&after_bridge->callbacks);
-	datastore->data = after_bridge;
-	ast_channel_datastore_add(chan, datastore);
-
-	return datastore->data;
-}
-
-void ast_bridge_run_after_callback(struct ast_channel *chan)
-{
-	struct after_bridge_cb_ds *after_bridge;
-	struct after_bridge_cb_node *node;
-
-	after_bridge = after_bridge_cb_find(chan);
-	if (!after_bridge) {
-		return;
-	}
-
-	for (;;) {
-		AST_LIST_LOCK(&after_bridge->callbacks);
-		node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
-		AST_LIST_UNLOCK(&after_bridge->callbacks);
-		if (!node) {
-			break;
-		}
-		if (node->reason) {
-			after_bridge_cb_failed(node);
-		} else {
-			node->failed = NULL;
-			node->callback(chan, node->data);
-		}
-		ast_free(node);
-	}
-}
-
-void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
-{
-	struct after_bridge_cb_ds *after_bridge;
-
-	after_bridge = after_bridge_cb_find(chan);
-	if (!after_bridge) {
-		return;
-	}
-
-	after_bridge_cb_run_discard(after_bridge, reason);
-}
-
-int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
-{
-	struct after_bridge_cb_ds *after_bridge;
-	struct after_bridge_cb_node *new_node;
-	struct after_bridge_cb_node *last_node;
-
-	/* Sanity checks. */
-	ast_assert(chan != NULL);
-	if (!chan || !callback) {
-		return -1;
-	}
-
-	after_bridge = after_bridge_cb_setup(chan);
-	if (!after_bridge) {
-		return -1;
-	}
-
-	/* Create a new callback node. */
-	new_node = ast_calloc(1, sizeof(*new_node));
-	if (!new_node) {
-		return -1;
-	}
-	new_node->callback = callback;
-	new_node->failed = failed;
-	new_node->data = data;
-
-	/* Put it in the container disabling any previously active one. */
-	AST_LIST_LOCK(&after_bridge->callbacks);
-	last_node = AST_LIST_LAST(&after_bridge->callbacks);
-	if (last_node && !last_node->reason) {
-		last_node->reason = AST_BRIDGE_AFTER_CB_REASON_REPLACED;
-	}
-	AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
-	AST_LIST_UNLOCK(&after_bridge->callbacks);
-	return 0;
-}
-
-const char *reason_strings[] = {
-	[AST_BRIDGE_AFTER_CB_REASON_DESTROY] = "Channel destroyed (hungup)",
-	[AST_BRIDGE_AFTER_CB_REASON_REPLACED] = "Callback was replaced",
-	[AST_BRIDGE_AFTER_CB_REASON_MASQUERADE] = "Channel masqueraded",
-	[AST_BRIDGE_AFTER_CB_REASON_DEPART] = "Channel was departed from bridge",
-	[AST_BRIDGE_AFTER_CB_REASON_REMOVED] = "Callback was removed",
-};
-
-const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
-{
-	if (reason < AST_BRIDGE_AFTER_CB_REASON_DESTROY
-		|| AST_BRIDGE_AFTER_CB_REASON_REMOVED < reason
-		|| !reason_strings[reason]) {
-		return "Unknown";
-	}
-
-	return reason_strings[reason];
-}
-
-struct after_bridge_goto_ds {
-	/*! Goto string that can be parsed by ast_parseable_goto(). */
-	const char *parseable_goto;
-	/*! Specific goto context or default context for parseable_goto. */
-	const char *context;
-	/*! Specific goto exten or default exten for parseable_goto. */
-	const char *exten;
-	/*! Specific goto priority or default priority for parseable_goto. */
-	int priority;
-	/*! TRUE if the peer should run the h exten. */
-	unsigned int run_h_exten:1;
-	/*! Specific goto location */
-	unsigned int specific:1;
-};
-
-/*!
- * \internal
- * \brief Destroy the after bridge goto datastore.
- * \since 12.0.0
- *
- * \param data After bridge goto data to destroy.
- *
- * \return Nothing
- */
-static void after_bridge_goto_destroy(void *data)
-{
-	struct after_bridge_goto_ds *after_bridge = data;
-
-	ast_free((char *) after_bridge->parseable_goto);
-	ast_free((char *) after_bridge->context);
-	ast_free((char *) after_bridge->exten);
-}
-
-/*!
- * \internal
- * \brief Fixup the after bridge goto datastore.
- * \since 12.0.0
- *
- * \param data After bridge goto data to fixup.
- * \param old_chan The datastore is moving from this channel.
- * \param new_chan The datastore is moving to this channel.
- *
- * \return Nothing
- */
-static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	/* There can be only one.  Discard any already on the new channel. */
-	ast_bridge_discard_after_goto(new_chan);
-}
-
-static const struct ast_datastore_info after_bridge_goto_info = {
-	.type = "after-bridge-goto",
-	.destroy = after_bridge_goto_destroy,
-	.chan_fixup = after_bridge_goto_fixup,
-};
-
-/*!
- * \internal
- * \brief Remove channel goto location after the bridge and return it.
- * \since 12.0.0
- *
- * \param chan Channel to remove after bridge goto location.
- *
- * \retval datastore on success.
- * \retval NULL on error or not found.
- */
-static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
-	if (datastore && ast_channel_datastore_remove(chan, datastore)) {
-		datastore = NULL;
-	}
-	ast_channel_unlock(chan);
-
-	return datastore;
-}
-
-void ast_bridge_discard_after_goto(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	datastore = after_bridge_goto_remove(chan);
-	if (datastore) {
-		ast_datastore_free(datastore);
-	}
-}
-
-void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
-{
-	struct ast_datastore *datastore;
-	struct after_bridge_goto_ds *after_bridge;
-	char *current_pos = buffer;
-	size_t remaining_size = buf_size;
-
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
-	if (!datastore) {
-		buffer[0] = '\0';
-		return;
-	}
-
-	after_bridge = datastore->data;
-
-	if (after_bridge->parseable_goto) {
-		snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
-		return;
-	}
-
-	if (!ast_strlen_zero(after_bridge->context)) {
-		snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
-		remaining_size = remaining_size - strlen(current_pos);
-		current_pos += strlen(current_pos);
-	}
-
-	if (after_bridge->run_h_exten) {
-		snprintf(current_pos, remaining_size, "h,");
-		remaining_size = remaining_size - strlen(current_pos);
-		current_pos += strlen(current_pos);
-	} else if (!ast_strlen_zero(after_bridge->exten)) {
-		snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
-		remaining_size = remaining_size - strlen(current_pos);
-		current_pos += strlen(current_pos);
-	}
-
-	snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
-}
-
-int ast_bridge_setup_after_goto(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-	struct after_bridge_goto_ds *after_bridge;
-	int goto_failed = -1;
-
-	/* We are going to be leaving the bridging system now;
-	 * clear any pending unbridge flags
-	 */
-	ast_channel_set_unbridged(chan, 0);
-
-	/* Determine if we are going to setup a dialplan location and where. */
-	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
-		/* An async goto has already setup a location. */
-		ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
-		if (!ast_check_hangup(chan)) {
-			goto_failed = 0;
-		}
-		return goto_failed;
-	}
-
-	/* Get after bridge goto datastore. */
-	datastore = after_bridge_goto_remove(chan);
-	if (!datastore) {
-		return goto_failed;
-	}
-
-	after_bridge = datastore->data;
-	if (after_bridge->run_h_exten) {
-		if (ast_exists_extension(chan, after_bridge->context, "h", 1,
-			S_COR(ast_channel_caller(chan)->id.number.valid,
-				ast_channel_caller(chan)->id.number.str, NULL))) {
-			ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
-				ast_channel_context(chan));
-			ast_pbx_h_exten_run(chan, after_bridge->context);
-		}
-	} else if (!ast_check_hangup(chan)) {
-		/* Clear the outgoing flag */
-		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
-
-		if (after_bridge->specific) {
-			goto_failed = ast_explicit_goto(chan, after_bridge->context,
-				after_bridge->exten, after_bridge->priority);
-		} else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
-			char *context;
-			char *exten;
-			int priority;
-
-			/* Option F(x) for Bridge(), Dial(), and Queue() */
-
-			/* Save current dialplan location in case of failure. */
-			context = ast_strdupa(ast_channel_context(chan));
-			exten = ast_strdupa(ast_channel_exten(chan));
-			priority = ast_channel_priority(chan);
-
-			/* Set current dialplan position to default dialplan position */
-			ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
-				after_bridge->priority);
-
-			/* Then perform the goto */
-			goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
-			if (goto_failed) {
-				/* Restore original dialplan location. */
-				ast_channel_context_set(chan, context);
-				ast_channel_exten_set(chan, exten);
-				ast_channel_priority_set(chan, priority);
-			}
-		} else {
-			/* Option F() for Bridge(), Dial(), and Queue() */
-			goto_failed = ast_goto_if_exists(chan, after_bridge->context,
-				after_bridge->exten, after_bridge->priority + 1);
-		}
-		if (!goto_failed) {
-			if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
-				ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
-			}
-
-			ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
-				ast_channel_context(chan),
-				ast_channel_exten(chan),
-				ast_channel_priority(chan));
-		}
-	}
-
-	/* Discard after bridge goto datastore. */
-	ast_datastore_free(datastore);
-
-	return goto_failed;
-}
-
-void ast_bridge_run_after_goto(struct ast_channel *chan)
-{
-	int goto_failed;
-
-	goto_failed = ast_bridge_setup_after_goto(chan);
-	if (goto_failed || ast_pbx_run(chan)) {
-		ast_hangup(chan);
-	}
-}
-
-/*!
- * \internal
- * \brief Set after bridge goto location of channel.
- * \since 12.0.0
- *
- * \param chan Channel to setup after bridge goto location.
- * \param run_h_exten TRUE if the h exten should be run.
- * \param specific TRUE if the context/exten/priority is exactly specified.
- * \param context Context to goto after bridge.
- * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
- * \param priority Priority to goto after bridge.
- * \param parseable_goto User specified goto string. (Could be NULL)
- *
- * \details Add a channel datastore to setup the goto location
- * when the channel leaves the bridge and run a PBX from there.
- *
- * If run_h_exten then execute the h exten found in the given context.
- * Else if specific then goto the given context/exten/priority.
- * Else if parseable_goto then use the given context/exten/priority
- *   as the relative position for the parseable_goto.
- * Else goto the given context/exten/priority+1.
- *
- * \return Nothing
- */
-static void __after_bridge_set_goto(struct ast_channel *chan, int run_h_exten, int specific, const char *context, const char *exten, int priority, const char *parseable_goto)
-{
-	struct ast_datastore *datastore;
-	struct after_bridge_goto_ds *after_bridge;
-
-	/* Sanity checks. */
-	ast_assert(chan != NULL);
-	if (!chan) {
-		return;
-	}
-	if (run_h_exten) {
-		ast_assert(run_h_exten && context);
-		if (!context) {
-			return;
-		}
-	} else {
-		ast_assert(context && exten && 0 < priority);
-		if (!context || !exten || priority < 1) {
-			return;
-		}
-	}
-
-	/* Create a new datastore. */
-	datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
-	if (!datastore) {
-		return;
-	}
-	after_bridge = ast_calloc(1, sizeof(*after_bridge));
-	if (!after_bridge) {
-		ast_datastore_free(datastore);
-		return;
-	}
-
-	/* Initialize it. */
-	after_bridge->parseable_goto = ast_strdup(parseable_goto);
-	after_bridge->context = ast_strdup(context);
-	after_bridge->exten = ast_strdup(exten);
-	after_bridge->priority = priority;
-	after_bridge->run_h_exten = run_h_exten ? 1 : 0;
-	after_bridge->specific = specific ? 1 : 0;
-	datastore->data = after_bridge;
-	if ((parseable_goto && !after_bridge->parseable_goto)
-		|| (context && !after_bridge->context)
-		|| (exten && !after_bridge->exten)) {
-		ast_datastore_free(datastore);
-		return;
-	}
-
-	/* Put it on the channel replacing any existing one. */
-	ast_channel_lock(chan);
-	ast_bridge_discard_after_goto(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_channel_unlock(chan);
-}
-
-void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
-{
-	__after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
-}
-
-void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
-{
-	__after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
-}
-
-void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
-{
-	char *p_goto;
-
-	if (!ast_strlen_zero(parseable_goto)) {
-		p_goto = ast_strdupa(parseable_goto);
-		ast_replace_subargument_delimiter(p_goto);
-	} else {
-		p_goto = NULL;
-	}
-	__after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
-}
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
deleted file mode 100644
index 132988d..0000000
--- a/main/bridge_basic.c
+++ /dev/null
@@ -1,3443 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Basic bridge class.  It is a subclass of struct ast_bridge.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428505 $")
-
-#include "asterisk/channel.h"
-#include "asterisk/utils.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/features_config.h"
-#include "asterisk/pbx.h"
-#include "asterisk/file.h"
-#include "asterisk/app.h"
-#include "asterisk/dial.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/features.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/test.h"
-
-#define NORMAL_FLAGS	(AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY \
-			| AST_BRIDGE_FLAG_SMART)
-
-#define TRANSFER_FLAGS AST_BRIDGE_FLAG_SMART
-
-struct attended_transfer_properties;
-
-enum bridge_basic_personality_type {
-	/*! Index for "normal" basic bridge personality */
-	BRIDGE_BASIC_PERSONALITY_NORMAL,
-	/*! Index for attended transfer basic bridge personality */
-	BRIDGE_BASIC_PERSONALITY_ATXFER,
-	/*! Indicates end of enum. Must always remain the last element */
-	BRIDGE_BASIC_PERSONALITY_END,
-};
-
-/*!
- * \brief Change basic bridge personality
- *
- * Changing personalities allows for the bridge to remain in use but have
- * properties such as its v_table and its flags change.
- *
- * \param bridge The bridge
- * \param type The personality to change the bridge to
- * \user_data Private data to attach to the personality.
- */
-static void bridge_basic_change_personality(struct ast_bridge *bridge,
-		enum bridge_basic_personality_type type, void *user_data);
-
-/* ------------------------------------------------------------------- */
-
-static const struct ast_datastore_info dtmf_features_info = {
-	.type = "bridge-dtmf-features",
-	.destroy = ast_free_ptr,
-};
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief read a feature code character and set it on for the give feature_flags struct
- *
- * \param feature_flags flags being modifed
- * \param feature feature code provided - should be an uppercase letter
- *
- * \retval 0 if the feature was set successfully
- * \retval -1 failure because the requested feature code isn't handled by this function
- */
-static int set_feature_flag_from_char(struct ast_flags *feature_flags, char feature)
-{
-	switch (feature) {
-	case 'T':
-		ast_set_flag(feature_flags, AST_FEATURE_REDIRECT);
-		return 0;
-	case 'K':
-		ast_set_flag(feature_flags, AST_FEATURE_PARKCALL);
-		return 0;
-	case 'H':
-		ast_set_flag(feature_flags, AST_FEATURE_DISCONNECT);
-		return 0;
-	case 'W':
-		ast_set_flag(feature_flags, AST_FEATURE_AUTOMON);
-		return 0;
-	case 'X':
-		ast_set_flag(feature_flags, AST_FEATURE_AUTOMIXMON);
-		return 0;
-	default:
-		return -1;
-	}
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Write a features string to a string buffer based on the feature flags provided
- *
- * \param feature_flags pointer to the feature flags to write from.
- * \param buffer pointer to a string buffer to write the features
- * \param buffer_size size of the buffer provided (should be able to fit all feature codes)
- *
- * \retval 0 on successful write
- * \retval -1 failure due to running out of buffer space
- */
-static int dtmf_features_flags_to_string(struct ast_flags *feature_flags, char *buffer, size_t buffer_size)
-{
-	size_t buffer_expended = 0;
-	unsigned int cur_feature;
-	static const struct {
-		char letter;
-		unsigned int flag;
-	} associations[] = {
-		{ 'T', AST_FEATURE_REDIRECT },
-		{ 'K', AST_FEATURE_PARKCALL },
-		{ 'H', AST_FEATURE_DISCONNECT },
-		{ 'W', AST_FEATURE_AUTOMON },
-		{ 'X', AST_FEATURE_AUTOMIXMON },
-	};
-
-	for (cur_feature = 0; cur_feature < ARRAY_LEN(associations); cur_feature++) {
-		if (ast_test_flag(feature_flags, associations[cur_feature].flag)) {
-			if (buffer_expended == buffer_size - 1) {
-				buffer[buffer_expended] = '\0';
-				return -1;
-			}
-			buffer[buffer_expended++] = associations[cur_feature].letter;
-		}
-	}
-
-	buffer[buffer_expended] = '\0';
-	return 0;
-}
-
-static int build_dtmf_features(struct ast_flags *flags, const char *features)
-{
-	const char *feature;
-
-	char missing_features[strlen(features) + 1];
-	size_t number_of_missing_features = 0;
-
-	for (feature = features; *feature; feature++) {
-		if (!isupper(*feature)) {
-			ast_log(LOG_ERROR, "Features string '%s' rejected because it contains non-uppercase feature.\n", features);
-			return -1;
-		}
-
-		if (set_feature_flag_from_char(flags, *feature)) {
-			missing_features[number_of_missing_features++] = *feature;
-		}
-	}
-
-	missing_features[number_of_missing_features] = '\0';
-
-	if (number_of_missing_features) {
-		ast_log(LOG_WARNING, "Features '%s' from features string '%s' can not be applied.\n", missing_features, features);
-	}
-
-	return 0;
-}
-
-int ast_bridge_features_ds_set_string(struct ast_channel *chan, const char *features)
-{
-	struct ast_flags flags = {0};
-
-	if (build_dtmf_features(&flags, features)) {
-		return -1;
-	}
-
-	ast_channel_lock(chan);
-	if (ast_bridge_features_ds_set(chan, &flags)) {
-		ast_channel_unlock(chan);
-		ast_log(LOG_ERROR, "Failed to apply features datastore for '%s' to channel '%s'\n", features, ast_channel_name(chan));
-		return -1;
-	}
-	ast_channel_unlock(chan);
-
-	return 0;
-}
-
-int ast_bridge_features_ds_get_string(struct ast_channel *chan, char *buffer, size_t buf_size)
-{
-	struct ast_flags *channel_flags;
-	struct ast_flags held_copy;
-
-	ast_channel_lock(chan);
-	if (!(channel_flags = ast_bridge_features_ds_get(chan))) {
-		ast_channel_unlock(chan);
-		return -1;
-	}
-	held_copy = *channel_flags;
-	ast_channel_unlock(chan);
-
-	return dtmf_features_flags_to_string(&held_copy, buffer, buf_size);
-}
-
-static int bridge_features_ds_set_full(struct ast_channel *chan, struct ast_flags *flags, int replace)
-{
-	struct ast_datastore *datastore;
-	struct ast_flags *ds_flags;
-
-	datastore = ast_channel_datastore_find(chan, &dtmf_features_info, NULL);
-	if (datastore) {
-		ds_flags = datastore->data;
-		if (replace) {
-			*ds_flags = *flags;
-		} else {
-			flags->flags = flags->flags | ds_flags->flags;
-			*ds_flags = *flags;
-		}
-		return 0;
-	}
-
-	datastore = ast_datastore_alloc(&dtmf_features_info, NULL);
-	if (!datastore) {
-		return -1;
-	}
-
-	ds_flags = ast_malloc(sizeof(*ds_flags));
-	if (!ds_flags) {
-		ast_datastore_free(datastore);
-		return -1;
-	}
-
-	*ds_flags = *flags;
-	datastore->data = ds_flags;
-	ast_channel_datastore_add(chan, datastore);
-	return 0;
-}
-
-int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags)
-{
-	return bridge_features_ds_set_full(chan, flags, 1);
-}
-
-int ast_bridge_features_ds_append(struct ast_channel *chan, struct ast_flags *flags)
-{
-	return bridge_features_ds_set_full(chan, flags, 0);
-}
-
-struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	datastore = ast_channel_datastore_find(chan, &dtmf_features_info, NULL);
-	if (!datastore) {
-		return NULL;
-	}
-	return datastore->data;
-}
-
-/*!
- * \internal
- * \brief Determine if we should dissolve the bridge from a hangup.
- * \since 12.0.0
- *
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- *
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-static int basic_hangup_hook(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	int bridge_count = 0;
-	struct ast_bridge_channel *iter;
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	AST_LIST_TRAVERSE(&bridge_channel->bridge->channels, iter, entry) {
-		if (iter != bridge_channel && iter->state == BRIDGE_CHANNEL_STATE_WAIT) {
-			++bridge_count;
-		}
-	}
-	if (2 <= bridge_count) {
-		/* Just allow this channel to leave the multi-party bridge. */
-		ast_bridge_channel_leave_bridge(bridge_channel,
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0);
-	}
-	ast_bridge_unlock(bridge_channel->bridge);
-	return 0;
-}
-
-/*!
- * \brief Details for specific basic bridge personalities
- */
-struct personality_details {
-	/*! The v_table to use for this personality */
-	struct ast_bridge_methods *v_table;
-	/*! Flags to set on this type of bridge */
-	unsigned int bridge_flags;
-	/*! User data for this personality. If used, must be an ao2 object */
-	void *pvt;
-	/*! Callback to be called when changing to the personality */
-	void (*on_personality_change)(struct ast_bridge *bridge);
-};
-
-/*!
- * \brief structure that organizes different personalities for basic bridges.
- */
-struct bridge_basic_personality {
-	/*! The current bridge personality in use */
-	enum bridge_basic_personality_type current;
-	/*! Array of details for the types of bridge personalities supported */
-	struct personality_details details[BRIDGE_BASIC_PERSONALITY_END];
-};
-
-/*
- * \internal
- * \brief Get the extension for a given builtin feature.
- *
- * \param chan Get the feature extension for this channel.
- * \param feature_name features.conf name of feature.
- * \param buf Where to put the extension.
- * \param len Length of the given extension buffer.
- *
- * \retval 0 success
- * \retval non-zero failiure
- */
-static int builtin_feature_get_exten(struct ast_channel *chan, const char *feature_name, char *buf, size_t len)
-{
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	return ast_get_builtin_feature(chan, feature_name, buf, len);
-}
-
-/*!
- * \internal
- * \brief Helper to add a builtin DTMF feature hook to the features struct.
- * \since 12.0.0
- *
- * \param features Bridge features to setup.
- * \param chan Get features from this channel.
- * \param flags Feature flags on the channel.
- * \param feature_flag Feature flag to test.
- * \param feature_name features.conf name of feature.
- * \param feature_bridge Bridge feature enum to get hook callback.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int builtin_features_helper(struct ast_bridge_features *features, struct ast_channel *chan,
-	struct ast_flags *flags, unsigned int feature_flag, const char *feature_name, enum ast_bridge_builtin_feature feature_bridge)
-{
-	char dtmf[AST_FEATURE_MAX_LEN];
-	int res;
-
-	res = 0;
-	if (ast_test_flag(flags, feature_flag)
-		&& !builtin_feature_get_exten(chan, feature_name, dtmf, sizeof(dtmf))
-		&& !ast_strlen_zero(dtmf)) {
-		res = ast_bridge_features_enable(features, feature_bridge, dtmf, NULL, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PULL | AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE);
-		if (res) {
-			ast_log(LOG_ERROR, "Channel %s: Requested DTMF feature %s not available.\n",
-				ast_channel_name(chan), feature_name);
-		}
-	}
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Setup bridge builtin features.
- * \since 12.0.0
- *
- * \param features Bridge features to setup.
- * \param chan Get features from this channel.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int setup_bridge_features_builtin(struct ast_bridge_features *features, struct ast_channel *chan)
-{
-	struct ast_flags *flags;
-	int res;
-
-	ast_channel_lock(chan);
-	flags = ast_bridge_features_ds_get(chan);
-	ast_channel_unlock(chan);
-	if (!flags) {
-		return 0;
-	}
-
-	res = 0;
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "blindxfer", AST_BRIDGE_BUILTIN_BLINDTRANSFER);
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "atxfer", AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER);
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_DISCONNECT, "disconnect", AST_BRIDGE_BUILTIN_HANGUP);
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_PARKCALL, "parkcall", AST_BRIDGE_BUILTIN_PARKCALL);
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMON, "automon", AST_BRIDGE_BUILTIN_AUTOMON);
-	res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMIXMON, "automixmon", AST_BRIDGE_BUILTIN_AUTOMIXMON);
-
-	return res ? -1 : 0;
-}
-
-struct dynamic_dtmf_hook_run {
-	/*! Offset into app_name[] where the channel name that activated the hook starts. */
-	int activated_offset;
-	/*! Offset into app_name[] where the dynamic feature name starts. */
-	int feature_offset;
-	/*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH) */
-	int moh_offset;
-	/*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */
-	int app_args_offset;
-	/*! Application name to run. */
-	char app_name[0];
-};
-
-static void dynamic_dtmf_hook_callback(struct ast_bridge_channel *bridge_channel,
-	const void *payload, size_t payload_size)
-{
-	struct ast_channel *chan = bridge_channel->chan;
-	const struct dynamic_dtmf_hook_run *run_data = payload;
-
-	pbx_builtin_setvar_helper(chan, "DYNAMIC_FEATURENAME",
-		&run_data->app_name[run_data->feature_offset]);
-	pbx_builtin_setvar_helper(chan, "DYNAMIC_WHO_ACTIVATED",
-		&run_data->app_name[run_data->activated_offset]);
-
-	ast_bridge_channel_run_app(bridge_channel, run_data->app_name,
-		run_data->app_args_offset ? &run_data->app_name[run_data->app_args_offset] : NULL,
-		run_data->moh_offset ? &run_data->app_name[run_data->moh_offset] : NULL);
-}
-
-struct dynamic_dtmf_hook_data {
-	/*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */
-	unsigned int flags;
-	/*! Offset into app_name[] where the dynamic feature name starts. */
-	int feature_offset;
-	/*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH) */
-	int moh_offset;
-	/*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */
-	int app_args_offset;
-	/*! Application name to run. */
-	char app_name[0];
-};
-
-/*!
- * \internal
- * \brief Activated dynamic DTMF feature hook.
- * \since 12.0.0
- *
- * \param bridge_channel Channel executing the feature
- * \param hook_pvt Private data passed in when the hook was created
- *
- * \retval 0 Keep the callback hook.
- * \retval -1 Remove the callback hook.
- */
-static int dynamic_dtmf_hook_trip(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct dynamic_dtmf_hook_data *pvt = hook_pvt;
-	struct dynamic_dtmf_hook_run *run_data;
-	const char *activated_name;
-	size_t len_name;
-	size_t len_args;
-	size_t len_moh;
-	size_t len_feature;
-	size_t len_activated;
-	size_t len_data;
-
-	/* Determine lengths of things. */
-	len_name = strlen(pvt->app_name) + 1;
-	len_args = pvt->app_args_offset ? strlen(&pvt->app_name[pvt->app_args_offset]) + 1 : 0;
-	len_moh = pvt->moh_offset ? strlen(&pvt->app_name[pvt->moh_offset]) + 1 : 0;
-	len_feature = strlen(&pvt->app_name[pvt->feature_offset]) + 1;
-	ast_channel_lock(bridge_channel->chan);
-	activated_name = ast_strdupa(ast_channel_name(bridge_channel->chan));
-	ast_channel_unlock(bridge_channel->chan);
-	len_activated = strlen(activated_name) + 1;
-	len_data = sizeof(*run_data) + len_name + len_args + len_moh + len_feature + len_activated;
-
-	/* Fill in dynamic feature run hook data. */
-	run_data = ast_alloca(len_data);
-	run_data->app_args_offset = len_args ? len_name : 0;
-	run_data->moh_offset = len_moh ? len_name + len_args : 0;
-	run_data->feature_offset = len_name + len_args + len_moh;
-	run_data->activated_offset = len_name + len_args + len_moh + len_feature;
-	strcpy(run_data->app_name, pvt->app_name);/* Safe */
-	if (len_args) {
-		strcpy(&run_data->app_name[run_data->app_args_offset],
-			&pvt->app_name[pvt->app_args_offset]);/* Safe */
-	}
-	if (len_moh) {
-		strcpy(&run_data->app_name[run_data->moh_offset],
-			&pvt->app_name[pvt->moh_offset]);/* Safe */
-	}
-	strcpy(&run_data->app_name[run_data->feature_offset],
-		&pvt->app_name[pvt->feature_offset]);/* Safe */
-	strcpy(&run_data->app_name[run_data->activated_offset], activated_name);/* Safe */
-
-	if (ast_test_flag(pvt, AST_FEATURE_FLAG_ONPEER)) {
-		ast_bridge_channel_write_callback(bridge_channel,
-			AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA,
-			dynamic_dtmf_hook_callback, run_data, len_data);
-	} else {
-		dynamic_dtmf_hook_callback(bridge_channel, run_data, len_data);
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Add a dynamic DTMF feature hook to the bridge features.
- * \since 12.0.0
- *
- * \param features Bridge features to setup.
- * \param flags Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER).
- * \param dtmf DTMF trigger sequence.
- * \param feature_name Name of the dynamic feature.
- * \param app_name Dialplan application name to run.
- * \param app_args Dialplan application arguments. (Empty or NULL if no arguments)
- * \param moh_class MOH class to play to peer. (Empty or NULL if no MOH played)
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int dynamic_dtmf_hook_add(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *feature_name, const char *app_name, const char *app_args, const char *moh_class)
-{
-	struct dynamic_dtmf_hook_data *hook_data;
-	size_t len_name = strlen(app_name) + 1;
-	size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1;
-	size_t len_moh = ast_strlen_zero(moh_class) ? 0 : strlen(moh_class) + 1;
-	size_t len_feature = strlen(feature_name) + 1;
-	size_t len_data = sizeof(*hook_data) + len_name + len_args + len_moh + len_feature;
-	int res;
-
-	/* Fill in application run hook data. */
-	hook_data = ast_malloc(len_data);
-	if (!hook_data) {
-		return -1;
-	}
-	hook_data->flags = flags;
-	hook_data->app_args_offset = len_args ? len_name : 0;
-	hook_data->moh_offset = len_moh ? len_name + len_args : 0;
-	hook_data->feature_offset = len_name + len_args + len_moh;
-	strcpy(hook_data->app_name, app_name);/* Safe */
-	if (len_args) {
-		strcpy(&hook_data->app_name[hook_data->app_args_offset], app_args);/* Safe */
-	}
-	if (len_moh) {
-		strcpy(&hook_data->app_name[hook_data->moh_offset], moh_class);/* Safe */
-	}
-	strcpy(&hook_data->app_name[hook_data->feature_offset], feature_name);/* Safe */
-
-	res = ast_bridge_dtmf_hook(features, dtmf, dynamic_dtmf_hook_trip, hook_data,
-		ast_free_ptr,
-		AST_BRIDGE_HOOK_REMOVE_ON_PULL | AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE);
-	if (res) {
-		ast_free(hook_data);
-	}
-	return res;
-}
-
-static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_applicationmap_item *item = obj;
-	struct ast_bridge_features *features = arg;
-	int *res = data;
-
-	*res |= dynamic_dtmf_hook_add(features,
-		item->activate_on_self ? AST_FEATURE_FLAG_ONSELF : AST_FEATURE_FLAG_ONPEER,
-		item->dtmf, item->name, item->app, item->app_data, item->moh_class);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Setup bridge dynamic features.
- * \since 12.0.0
- *
- * \param features Bridge features to setup.
- * \param chan Get features from this channel.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int setup_bridge_features_dynamic(struct ast_bridge_features *features, struct ast_channel *chan)
-{
-	RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
-	int res = 0;
-
-	ast_channel_lock(chan);
-	applicationmap = ast_get_chan_applicationmap(chan);
-	ast_channel_unlock(chan);
-	if (!applicationmap) {
-		return 0;
-	}
-
-	ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Setup DTMF feature hooks using the channel features datastore property.
- * \since 12.0.0
- *
- * \param bridge_channel What to setup DTMF features on.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int bridge_basic_setup_features(struct ast_bridge_channel *bridge_channel)
-{
-	int res = 0;
-
-	res |= setup_bridge_features_builtin(bridge_channel->features, bridge_channel->chan);
-	res |= setup_bridge_features_dynamic(bridge_channel->features, bridge_channel->chan);
-
-	return res;
-}
-
-static int add_normal_hooks(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	return ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook,
-			NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)
-		|| bridge_basic_setup_features(bridge_channel);
-}
-
-/*!
- * \internal
- * \brief ast_bridge basic push method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to push.
- * \param swap Bridge channel to swap places with if not NULL.
- *
- * \note On entry, self is already locked.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int bridge_personality_normal_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	if (add_normal_hooks(self, bridge_channel)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int bridge_basic_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	struct bridge_basic_personality *personality = self->personality;
-
-	ast_assert(personality != NULL);
-
-	if (personality->details[personality->current].v_table->push
-		&& personality->details[personality->current].v_table->push(self, bridge_channel, swap)) {
-		return -1;
-	}
-
-	ast_bridge_channel_update_linkedids(bridge_channel, swap);
-	ast_bridge_channel_update_accountcodes(bridge_channel, swap);
-
-	return ast_bridge_base_v_table.push(self, bridge_channel, swap);
-}
-
-static void bridge_basic_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	struct bridge_basic_personality *personality = self->personality;
-
-	ast_assert(personality != NULL);
-
-	if (personality->details[personality->current].v_table->pull) {
-		personality->details[personality->current].v_table->pull(self, bridge_channel);
-	}
-
-	ast_bridge_channel_update_accountcodes(NULL, bridge_channel);
-
-	ast_bridge_base_v_table.pull(self, bridge_channel);
-}
-
-static void bridge_basic_destroy(struct ast_bridge *self)
-{
-	struct bridge_basic_personality *personality = self->personality;
-
-	ao2_cleanup(personality);
-
-	ast_bridge_base_v_table.destroy(self);
-}
-
-/*!
- * \brief Remove appropriate hooks when basic bridge personality changes
- *
- * Hooks that have the AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE flag
- * set will be removed from all bridge channels in the bridge.
- *
- * \param bridge Basic bridge undergoing personality change
- */
-static void remove_hooks_on_personality_change(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *iter;
-
-	AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
-		SCOPED_LOCK(lock, iter, ast_bridge_channel_lock, ast_bridge_channel_unlock);
-		ast_bridge_features_remove(iter->features, AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE);
-	}
-}
-
-/*!
- * \brief Attended transfer superstates.
- *
- * An attended transfer's progress is facilitated by a state machine.
- * The individual states of the state machine fall into the realm of
- * one of two superstates.
- */
-enum attended_transfer_superstate {
-	/*!
-	 * \brief Transfer superstate
-	 *
-	 * The attended transfer state machine begins in this superstate. The
-	 * goal of this state is for a transferer channel to facilitate a
-	 * transfer from a transferee to a transfer target.
-	 *
-	 * There are two bridges used in this superstate. The transferee bridge is
-	 * the bridge that the transferer and transferee channels originally
-	 * communicate in, and the target bridge is the bridge where the transfer
-	 * target is being dialed.
-	 *
-	 * The transferer channel is capable of moving between the bridges using
-	 * the DTMF swap sequence.
-	 */
-	SUPERSTATE_TRANSFER,
-	/*!
-	 * \brief Recall superstate
-	 *
-	 * The attended transfer state machine moves to this superstate if
-	 * atxferdropcall is set to "no" and the transferer channel hangs up
-	 * during a transfer. The goal in this superstate is to call back either
-	 * the transfer target or transferer and rebridge with the transferee
-	 * channel(s).
-	 *
-	 * In this superstate, there is only a single bridge used, the original
-	 * transferee bridge. Rather than distinguishing between a transferer
-	 * and transfer target, all outbound calls are toward a "recall_target"
-	 * channel.
-	 */
-	SUPERSTATE_RECALL,
-};
-
-/*!
- * The states in the attended transfer state machine.
- */
-enum attended_transfer_state {
-	/*!
-	 * \brief Calling Target state
-	 *
-	 * This state describes the initial state of a transfer. The transferer
-	 * waits in the transfer target's bridge for the transfer target to answer.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is RINGING
-	 * 2) Transferer is in transferee bridge
-	 * 3) Transferee is on hold
-	 *
-	 * Transitions to TRANSFER_CALLING_TARGET:
-	 * 1) This is the initial state for an attended transfer.
-	 * 2) TRANSFER_HESITANT: Transferer presses DTMF swap sequence
-	 *
-	 * State operation:
-	 * The transferer is moved from the transferee bridge into the transfer
-	 * target bridge.
-	 *
-	 * Transitions from TRANSFER_CALLING_TARGET:
-	 * 1) TRANSFER_FAIL: Transferee hangs up.
-	 * 2) TRANSFER_BLOND: Transferer hangs up or presses DTMF swap sequence
-	 * and configured atxferdropcall setting is yes.
-	 * 3) TRANSFER_BLOND_NONFINAL: Transferer hangs up or presses DTMF swap
-	 * sequence and configured atxferdroppcall setting is no.
-	 * 4) TRANSFER_CONSULTING: Transfer target answers the call.
-	 * 5) TRANSFER_REBRIDGE: Transfer target hangs up, call to transfer target
-	 * times out, or transferer presses DTMF abort sequence.
-	 * 6) TRANSFER_THREEWAY: Transferer presses DTMF threeway sequence.
-	 * 7) TRANSFER_HESITANT: Transferer presses DTMF swap sequence.
-	 */
-	TRANSFER_CALLING_TARGET,
-	/*!
-	 * \brief Hesitant state
-	 *
-	 * This state only arises if when waiting for the transfer target to
-	 * answer, the transferer presses the DTMF swap sequence. This will
-	 * cause the transferer to be rebridged with the transferee temporarily.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is in ringing state
-	 * 2) Transferer is in transfer target bridge
-	 * 3) Transferee is on hold
-	 *
-	 * Transitions to TRANSFER_HESITANT:
-	 * 1) TRANSFER_CALLING_TARGET: Transferer presses DTMF swap sequence.
-	 *
-	 * State operation:
-	 * The transferer is moved from the transfer target bridge into the
-	 * transferee bridge, and the transferee is taken off hold.
-	 *
-	 * Transitions from TRANSFER_HESITANT:
-	 * 1) TRANSFER_FAIL: Transferee hangs up
-	 * 2) TRANSFER_BLOND: Transferer hangs up or presses DTMF swap sequence
-	 * and configured atxferdropcall setting is yes.
-	 * 3) TRANSFER_BLOND_NONFINAL: Transferer hangs up or presses DTMF swap
-	 * sequence and configured atxferdroppcall setting is no.
-	 * 4) TRANSFER_DOUBLECHECKING: Transfer target answers the call
-	 * 5) TRANSFER_RESUME: Transfer target hangs up, call to transfer target
-	 * times out, or transferer presses DTMF abort sequence.
-	 * 6) TRANSFER_THREEWAY: Transferer presses DTMF threeway sequence.
-	 * 7) TRANSFER_CALLING_TARGET: Transferer presses DTMF swap sequence.
-	 */
-	TRANSFER_HESITANT,
-	/*!
-	 * \brief Rebridge state
-	 *
-	 * This is a terminal state that indicates that the transferer needs
-	 * to move back to the transferee's bridge. This is a failed attended
-	 * transfer result.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transferer is in transfer target bridge
-	 * 2) Transferee is on hold
-	 *
-	 * Transitions to TRANSFER_REBRIDGE:
-	 * 1) TRANSFER_CALLING_TARGET: Transfer target hangs up, call to transfer target
-	 * times out, or transferer presses DTMF abort sequence.
-	 * 2) TRANSFER_STATE_CONSULTING: Transfer target hangs up, or transferer presses
-	 * DTMF abort sequence.
-	 *
-	 * State operation:
-	 * The transferer channel is moved from the transfer target bridge to the
-	 * transferee bridge. The transferee is taken off hold. A stasis transfer
-	 * message is published indicating a failed attended transfer.
-	 *
-	 * Transitions from TRANSFER_REBRIDGE:
-	 * None
-	 */
-	TRANSFER_REBRIDGE,
-	/*!
-	 * \brief Resume state
-	 *
-	 * This is a terminal state that indicates that the party bridged with the
-	 * transferee is the final party to be bridged with that transferee. This state
-	 * may come about due to a successful recall or due to a failed transfer.
-	 *
-	 * Superstate: Transfer or Recall
-	 *
-	 * Preconditions:
-	 * In Transfer Superstate:
-	 * 1) Transferer is in transferee bridge
-	 * 2) Transferee is not on hold
-	 * In Recall Superstate:
-	 * 1) The recall target is in the transferee bridge
-	 * 2) Transferee is not on hold
-	 *
-	 * Transitions to TRANSFER_RESUME:
-	 * TRANSFER_HESITANT: Transfer target hangs up, call to transfer target times out,
-	 * or transferer presses DTMF abort sequence.
-	 * TRANSFER_DOUBLECHECKING: Transfer target hangs up or transferer presses DTMF
-	 * abort sequence.
-	 * TRANSFER_BLOND_NONFINAL: Recall target answers
-	 * TRANSFER_RECALLING: Recall target answers
-	 * TRANSFER_RETRANSFER: Recall target answers
-	 *
-	 * State operations:
-	 * None
-	 *
-	 * Transitions from TRANSFER_RESUME:
-	 * None
-	 */
-	TRANSFER_RESUME,
-	/*!
-	 * \brief Threeway state
-	 *
-	 * This state results when the transferer wishes to have all parties involved
-	 * in a transfer to be in the same bridge together.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target state is either RINGING or UP
-	 * 2) Transferer is in either bridge
-	 * 3) Transferee is not on hold
-	 *
-	 * Transitions to TRANSFER_THREEWAY:
-	 * 1) TRANSFER_CALLING_TARGET: Transferer presses DTMF threeway sequence.
-	 * 2) TRANSFER_HESITANT: Transferer presses DTMF threeway sequence.
-	 * 3) TRANSFER_CONSULTING: Transferer presses DTMF threeway sequence.
-	 * 4) TRANSFER_DOUBLECHECKING: Transferer presses DTMF threeway sequence.
-	 *
-	 * State operation:
-	 * The transfer target bridge is merged into the transferee bridge.
-	 *
-	 * Transitions from TRANSFER_THREEWAY:
-	 * None.
-	 */
-	TRANSFER_THREEWAY,
-	/*!
-	 * \brief Consulting state
-	 *
-	 * This state describes the case where the transferer and transfer target
-	 * are able to converse in the transfer target's bridge prior to completing
-	 * the transfer.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is UP
-	 * 2) Transferer is in target bridge
-	 * 3) Transferee is on hold
-	 *
-	 * Transitions to TRANSFER_CONSULTING:
-	 * 1) TRANSFER_CALLING_TARGET: Transfer target answers.
-	 * 2) TRANSFER_DOUBLECHECKING: Transferer presses DTMF swap sequence.
-	 *
-	 * State operations:
-	 * None.
-	 *
-	 * Transitions from TRANSFER_CONSULTING:
-	 * TRANSFER_COMPLETE: Transferer hangs up or transferer presses DTMF complete sequence.
-	 * TRANSFER_REBRIDGE: Transfer target hangs up or transferer presses DTMF abort sequence.
-	 * TRANSFER_THREEWAY: Transferer presses DTMF threeway sequence.
-	 * TRANSFER_DOUBLECHECKING: Transferer presses DTMF swap sequence.
-	 */
-	TRANSFER_CONSULTING,
-	/*!
-	 * \brief Double-checking state
-	 *
-	 * This state describes the case where the transferer and transferee are
-	 * able to converse in the transferee's bridge prior to completing the transfer. The
-	 * difference between this and TRANSFER_HESITANT is that the transfer target is
-	 * UP in this case.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is UP and on hold
-	 * 2) Transferer is in transferee bridge
-	 * 3) Transferee is off hold
-	 *
-	 * Transitions to TRANSFER_DOUBLECHECKING:
-	 * 1) TRANSFER_HESITANT: Transfer target answers.
-	 * 2) TRANSFER_CONSULTING: Transferer presses DTMF swap sequence.
-	 *
-	 * State operations:
-	 * None.
-	 *
-	 * Transitions from TRANSFER_DOUBLECHECKING:
-	 * 1) TRANSFER_FAIL: Transferee hangs up.
-	 * 2) TRANSFER_COMPLETE: Transferer hangs up or presses DTMF complete sequence.
-	 * 3) TRANSFER_RESUME: Transfer target hangs up or transferer presses DTMF abort sequence.
-	 * 4) TRANSFER_THREEWAY: Transferer presses DTMF threeway sequence.
-	 * 5) TRANSFER_CONSULTING: Transferer presses the DTMF swap sequence.
-	 */
-	TRANSFER_DOUBLECHECKING,
-	/*!
-	 * \brief Complete state
-	 *
-	 * This is a terminal state where a transferer has successfully completed an attended
-	 * transfer. This state's goal is to get the transfer target and transferee into
-	 * the same bridge and the transferer off the call.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is UP and off hold.
-	 * 2) Transferer is in either bridge.
-	 * 3) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_COMPLETE:
-	 * 1) TRANSFER_CONSULTING: transferer hangs up or presses the DTMF complete sequence.
-	 * 2) TRANSFER_DOUBLECHECKING: transferer hangs up or presses the DTMF complete sequence.
-	 *
-	 * State operation:
-	 * The transfer target bridge is merged into the transferee bridge. The transferer
-	 * channel is kicked out of the bridges as part of the merge.
-	 *
-	 * State operations:
-	 * 1) Merge the transfer target bridge into the transferee bridge,
-	 * excluding the transferer channel from the merge.
-	 * 2) Publish a stasis transfer message.
-	 *
-	 * Exit operations:
-	 * This is a terminal state, so there are no exit operations.
-	 */
-	TRANSFER_COMPLETE,
-	/*!
-	 * \brief Blond state
-	 *
-	 * This is a terminal state where a transferer has completed an attended transfer prior
-	 * to the transfer target answering. This state is only entered if atxferdropcall
-	 * is set to 'yes'. This is considered to be a successful attended transfer.
-	 *
-	 * Superstate: Transfer
-	 *
-	 * Preconditions:
-	 * 1) Transfer target is RINGING.
-	 * 2) Transferer is in either bridge.
-	 * 3) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_BLOND:
-	 * 1) TRANSFER_CALLING_TARGET: Transferer hangs up or presses the DTMF complete sequence.
-	 *    atxferdropcall is set to 'yes'.
-	 * 2) TRANSFER_HESITANT: Transferer hangs up or presses the DTMF complete sequence.
-	 *    atxferdropcall is set to 'yes'.
-	 *
-	 * State operations:
-	 * The transfer target bridge is merged into the transferee bridge. The transferer
-	 * channel is kicked out of the bridges as part of the merge. A stasis transfer
-	 * publication is sent indicating a successful transfer.
-	 *
-	 * Transitions from TRANSFER_BLOND:
-	 * None
-	 */
-	TRANSFER_BLOND,
-	/*!
-	 * \brief Blond non-final state
-	 *
-	 * This state is very similar to the TRANSFER_BLOND state, except that
-	 * this state is entered when atxferdropcall is set to 'no'. This is the
-	 * initial state of the Recall superstate, so state operations mainly involve
-	 * moving to the Recall superstate. This means that the transfer target, that
-	 * is currently ringing is now known as the recall target.
-	 *
-	 * Superstate: Recall
-	 *
-	 * Preconditions:
-	 * 1) Recall target is RINGING.
-	 * 2) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_BLOND_NONFINAL:
-	 * 1) TRANSFER_CALLING_TARGET: Transferer hangs up or presses the DTMF complete sequence.
-	 *    atxferdropcall is set to 'no'.
-	 * 2) TRANSFER_HESITANT: Transferer hangs up or presses the DTMF complete sequence.
-	 *    atxferdropcall is set to 'no'.
-	 *
-	 * State operation:
-	 * The superstate of the attended transfer is changed from Transfer to Recall.
-	 * The transfer target bridge is merged into the transferee bridge. The transferer
-	 * channel is kicked out of the bridges as part of the merge.
-	 *
-	 * Transitions from TRANSFER_BLOND_NONFINAL:
-	 * 1) TRANSFER_FAIL: Transferee hangs up
-	 * 2) TRANSFER_RESUME: Recall target answers
-	 * 3) TRANSFER_RECALLING: Recall target hangs up or time expires.
-	 */
-	TRANSFER_BLOND_NONFINAL,
-	/*!
-	 * \brief Recalling state
-	 *
-	 * This state is entered if the recall target from the TRANSFER_BLOND_NONFINAL
-	 * or TRANSFER_RETRANSFER states hangs up or does not answer. The goal of this
-	 * state is to call back the original transferer in an attempt to recover the
-	 * original call.
-	 *
-	 * Superstate: Recall
-	 *
-	 * Preconditions:
-	 * 1) Recall target is down.
-	 * 2) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_RECALLING:
-	 * 1) TRANSFER_BLOND_NONFINAL: Recall target hangs up or time expires.
-	 * 2) TRANSFER_RETRANSFER: Recall target hangs up or time expires.
-	 *    atxferloopdelay is non-zero.
-	 * 3) TRANSFER_WAIT_TO_RECALL: Time expires.
-	 *
-	 * State operation:
-	 * The original transferer becomes the recall target and is called using the Dialing API.
-	 * Ringing is indicated to the transferee.
-	 *
-	 * Transitions from TRANSFER_RECALLING:
-	 * 1) TRANSFER_FAIL:
-	 *    a) Transferee hangs up.
-	 *    b) Recall target hangs up or time expires, and number of recall attempts exceeds atxfercallbackretries
-	 * 2) TRANSFER_WAIT_TO_RETRANSFER: Recall target hangs up or time expires.
-	 *    atxferloopdelay is non-zero.
-	 * 3) TRANSFER_RETRANSFER: Recall target hangs up or time expires.
-	 *    atxferloopdelay is zero.
-	 * 4) TRANSFER_RESUME: Recall target answers.
-	 */
-	TRANSFER_RECALLING,
-	/*!
-	 * \brief Wait to Retransfer state
-	 *
-	 * This state is used simply to give a bit of breathing room between attempting
-	 * to call back the original transferer and attempting to call back the original
-	 * transfer target. The transferee hears music on hold during this state as an
-	 * auditory clue that no one is currently being dialed.
-	 *
-	 * Superstate: Recall
-	 *
-	 * Preconditions:
-	 * 1) Recall target is down.
-	 * 2) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_WAIT_TO_RETRANSFER:
-	 * 1) TRANSFER_RECALLING: Recall target hangs up or time expires.
-	 *    atxferloopdelay is non-zero.
-	 *
-	 * State operation:
-	 * The transferee is placed on hold.
-	 *
-	 * Transitions from TRANSFER_WAIT_TO_RETRANSFER:
-	 * 1) TRANSFER_FAIL: Transferee hangs up.
-	 * 2) TRANSFER_RETRANSFER: Time expires.
-	 */
-	TRANSFER_WAIT_TO_RETRANSFER,
-	/*!
-	 * \brief Retransfer state
-	 *
-	 * This state is used in order to attempt to call back the original
-	 * transfer target channel from the transfer. The transferee hears
-	 * ringing during this state as an auditory cue that a party is being
-	 * dialed.
-	 *
-	 * Superstate: Recall
-	 *
-	 * Preconditions:
-	 * 1) Recall target is down.
-	 * 2) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_RETRANSFER:
-	 * 1) TRANSFER_RECALLING: Recall target hangs up or time expires.
-	 *    atxferloopdelay is zero.
-	 * 2) TRANSFER_WAIT_TO_RETRANSFER: Time expires.
-	 *
-	 * State operation:
-	 * The original transfer target is requested and is set as the recall target.
-	 * The recall target is called and placed into the transferee bridge.
-	 *
-	 * Transitions from TRANSFER_RETRANSFER:
-	 * 1) TRANSFER_FAIL: Transferee hangs up.
-	 * 2) TRANSFER_WAIT_TO_RECALL: Recall target hangs up or time expires.
-	 *    atxferloopdelay is non-zero.
-	 * 3) TRANSFER_RECALLING: Recall target hangs up or time expires.
-	 *    atxferloopdelay is zero.
-	 */
-	TRANSFER_RETRANSFER,
-	/*!
-	 * \brief Wait to recall state
-	 *
-	 * This state is used simply to give a bit of breathing room between attempting
-	 * to call back the original transfer target and attempting to call back the
-	 * original transferer. The transferee hears music on hold during this state as an
-	 * auditory clue that no one is currently being dialed.
-	 *
-	 * Superstate: Recall
-	 *
-	 * Preconditions:
-	 * 1) Recall target is down.
-	 * 2) Transferee is off hold.
-	 *
-	 * Transitions to TRANSFER_WAIT_TO_RECALL:
-	 * 1) TRANSFER_RETRANSFER: Recall target hangs up or time expires.
-	 *    atxferloopdelay is non-zero.
-	 *
-	 * State operation:
-	 * Transferee is placed on hold.
-	 *
-	 * Transitions from TRANSFER_WAIT_TO_RECALL:
-	 * 1) TRANSFER_FAIL: Transferee hangs up
-	 * 2) TRANSFER_RECALLING: Time expires
-	 */
-	TRANSFER_WAIT_TO_RECALL,
-	/*!
-	 * \brief Fail state
-	 *
-	 * This state indicates that something occurred during the transfer that
-	 * makes a graceful completion impossible. The most common stimulus for this
-	 * state is when the transferee hangs up.
-	 *
-	 * Superstate: Transfer and Recall
-	 *
-	 * Preconditions:
-	 * None
-	 *
-	 * Transitions to TRANSFER_FAIL:
-	 * 1) TRANSFER_CALLING_TARGET: Transferee hangs up.
-	 * 2) TRANSFER_HESITANT: Transferee hangs up.
-	 * 3) TRANSFER_DOUBLECHECKING: Transferee hangs up.
-	 * 4) TRANSFER_BLOND_NONFINAL: Transferee hangs up.
-	 * 5) TRANSFER_RECALLING:
-	 *    a) Transferee hangs up.
-	 *    b) Recall target hangs up or time expires, and number of
-	 *       recall attempts exceeds atxfercallbackretries.
-	 * 6) TRANSFER_WAIT_TO_RETRANSFER: Transferee hangs up.
-	 * 7) TRANSFER_RETRANSFER: Transferee hangs up.
-	 * 8) TRANSFER_WAIT_TO_RECALL: Transferee hangs up.
-	 *
-	 * State operation:
-	 * A transfer stasis publication is made indicating a failed transfer.
-	 * The transferee bridge is destroyed.
-	 *
-	 * Transitions from TRANSFER_FAIL:
-	 * None.
-	 */
-	TRANSFER_FAIL,
-};
-
-/*!
- * \brief Stimuli that can cause transfer state changes
- */
-enum attended_transfer_stimulus {
-	/*! No stimulus. This literally can never happen. */
-	STIMULUS_NONE,
-	/*! All of the transferee channels have been hung up. */
-	STIMULUS_TRANSFEREE_HANGUP,
-	/*! The transferer has hung up. */
-	STIMULUS_TRANSFERER_HANGUP,
-	/*! The transfer target channel has hung up. */
-	STIMULUS_TRANSFER_TARGET_HANGUP,
-	/*! The transfer target channel has answered. */
-	STIMULUS_TRANSFER_TARGET_ANSWER,
-	/*! The recall target channel has hung up. */
-	STIMULUS_RECALL_TARGET_HANGUP,
-	/*! The recall target channel has answered. */
-	STIMULUS_RECALL_TARGET_ANSWER,
-	/*! The current state's timer has expired. */
-	STIMULUS_TIMEOUT,
-	/*! The transferer pressed the abort DTMF sequence. */
-	STIMULUS_DTMF_ATXFER_ABORT,
-	/*! The transferer pressed the complete DTMF sequence. */
-	STIMULUS_DTMF_ATXFER_COMPLETE,
-	/*! The transferer pressed the three-way DTMF sequence. */
-	STIMULUS_DTMF_ATXFER_THREEWAY,
-	/*! The transferer pressed the swap DTMF sequence. */
-	STIMULUS_DTMF_ATXFER_SWAP,
-};
-
-/*!
- * \brief String representations of the various stimuli
- *
- * Used for debugging purposes
- */
-const char *stimulus_strs[] = {
-	[STIMULUS_NONE] = "None",
-	[STIMULUS_TRANSFEREE_HANGUP] = "Transferee Hangup",
-	[STIMULUS_TRANSFERER_HANGUP] = "Transferer Hangup",
-	[STIMULUS_TRANSFER_TARGET_HANGUP] = "Transfer Target Hangup",
-	[STIMULUS_TRANSFER_TARGET_ANSWER] = "Transfer Target Answer",
-	[STIMULUS_RECALL_TARGET_HANGUP] = "Recall Target Hangup",
-	[STIMULUS_RECALL_TARGET_ANSWER] = "Recall Target Answer",
-	[STIMULUS_TIMEOUT] = "Timeout",
-	[STIMULUS_DTMF_ATXFER_ABORT] = "DTMF Abort",
-	[STIMULUS_DTMF_ATXFER_COMPLETE] = "DTMF Complete",
-	[STIMULUS_DTMF_ATXFER_THREEWAY] = "DTMF Threeway",
-	[STIMULUS_DTMF_ATXFER_SWAP] = "DTMF Swap",
-};
-
-struct stimulus_list {
-	enum attended_transfer_stimulus stimulus;
-	AST_LIST_ENTRY(stimulus_list) next;
-};
-
-/*!
- * \brief Collection of data related to an attended transfer attempt
- */
-struct attended_transfer_properties {
-	AST_DECLARE_STRING_FIELDS (
-		/*! Extension of transfer target */
-		AST_STRING_FIELD(exten);
-		/*! Context of transfer target */
-		AST_STRING_FIELD(context);
-		/*! Sound to play on failure */
-		AST_STRING_FIELD(failsound);
-		/*! Sound to play when transfer completes */
-		AST_STRING_FIELD(xfersound);
-		/*! The channel technology of the transferer channel */
-		AST_STRING_FIELD(transferer_type);
-		/*! The transferer channel address */
-		AST_STRING_FIELD(transferer_addr);
-	);
-	/*! Condition used to synchronize when stimuli are reported to the monitor thread */
-	ast_cond_t cond;
-	/*! The bridge where the transferee resides. This bridge is also the bridge that
-	 * survives a successful attended transfer.
-	 */
-	struct ast_bridge *transferee_bridge;
-	/*! The bridge used to place an outbound call to the transfer target. This
-	 * bridge is merged with the transferee_bridge on a successful transfer.
-	 */
-	struct ast_bridge *target_bridge;
-	/*! The party that performs the attended transfer. */
-	struct ast_channel *transferer;
-	/*! The local channel dialed to reach the transfer target. */
-	struct ast_channel *transfer_target;
-	/*! The party that is currently being recalled. Depending on
-	 * the current state, this may be either the party that originally
-	 * was the transferer or the original transfer target
-	 */
-	struct ast_channel *recall_target;
-	/*! The absolute starting time for running timers */
-	struct timeval start;
-	AST_LIST_HEAD_NOLOCK(,stimulus_list) stimulus_queue;
-	/*! The current state of the attended transfer */
-	enum attended_transfer_state state;
-	/*! The current superstate of the attended transfer */
-	enum attended_transfer_superstate superstate;
-	/*! Configured atxferdropcall from features.conf */
-	int atxferdropcall;
-	/*! Configured atxfercallbackretries from features.conf */
-	int atxfercallbackretries;
-	/*! Configured atxferloopdelay from features.conf */
-	int atxferloopdelay;
-	/*! Configured atxfernoanswertimeout from features.conf */
-	int atxfernoanswertimeout;
-	/*! Count of the number of times that recalls have been attempted */
-	int retry_attempts;
-	/*! Framehook ID for outbounc call to transfer target or recall target */
-	int target_framehook_id;
-	/*! Dial structure used when recalling transferer channel */
-	struct ast_dial *dial;
-	/*! The bridging features the transferer has available */
-	struct ast_flags transferer_features;
-};
-
-static void attended_transfer_properties_destructor(void *obj)
-{
-	struct attended_transfer_properties *props = obj;
-
-	ast_debug(1, "Destroy attended transfer properties %p\n", props);
-
-	ao2_cleanup(props->target_bridge);
-	ao2_cleanup(props->transferee_bridge);
-	/* Use ast_channel_cleanup() instead of ast_channel_unref() for channels since they may be NULL */
-	ast_channel_cleanup(props->transferer);
-	ast_channel_cleanup(props->transfer_target);
-	ast_channel_cleanup(props->recall_target);
-	ast_string_field_free_memory(props);
-	ast_cond_destroy(&props->cond);
-}
-
-/*!
- * \internal
- * \brief Determine the transfer context to use.
- * \since 12.0.0
- *
- * \param transferer Channel initiating the transfer.
- * \param context User supplied context if available.  May be NULL.
- *
- * \return The context to use for the transfer.
- */
-static const char *get_transfer_context(struct ast_channel *transferer, const char *context)
-{
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = ast_channel_macrocontext(transferer);
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = ast_channel_context(transferer);
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	return "default";
-}
-
-/*!
- * \brief Allocate and initialize attended transfer properties
- *
- * \param transferer The channel performing the attended transfer
- * \param context Suggestion for what context the transfer target extension can be found in
- *
- * \retval NULL Failure to allocate or initialize
- * \retval non-NULL Newly allocated properties
- */
-static struct attended_transfer_properties *attended_transfer_properties_alloc(
-	struct ast_channel *transferer, const char *context)
-{
-	struct attended_transfer_properties *props;
-	char *tech;
-	char *addr;
-	char *serial;
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-	struct ast_flags *transferer_features;
-
-	props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor);
-	if (!props || ast_string_field_init(props, 64)) {
-		return NULL;
-	}
-
-	ast_cond_init(&props->cond, NULL);
-
-	props->target_framehook_id = -1;
-	props->transferer = ast_channel_ref(transferer);
-
-	ast_channel_lock(props->transferer);
-	xfer_cfg = ast_get_chan_features_xfer_config(props->transferer);
-	if (!xfer_cfg) {
-		ast_log(LOG_ERROR, "Unable to get transfer configuration from channel %s\n", ast_channel_name(props->transferer));
-		ao2_ref(props, -1);
-		return NULL;
-	}
-	transferer_features = ast_bridge_features_ds_get(props->transferer);
-	if (transferer_features) {
-		props->transferer_features = *transferer_features;
-	}
-	props->atxferdropcall = xfer_cfg->atxferdropcall;
-	props->atxfercallbackretries = xfer_cfg->atxfercallbackretries;
-	props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;
-	props->atxferloopdelay = xfer_cfg->atxferloopdelay;
-	ast_string_field_set(props, context, get_transfer_context(transferer, context));
-	ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
-	ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
-
-	tech = ast_strdupa(ast_channel_name(props->transferer));
-	addr = strchr(tech, '/');
-	if (!addr) {
-		ast_log(LOG_ERROR, "Transferer channel name does not follow typical channel naming format (tech/address)\n");
-		ast_channel_unref(props->transferer);
-		return NULL;
-	}
-	*addr++ = '\0';
-	serial = strrchr(addr, '-');
-	if (serial) {
-		*serial = '\0';
-	}
-	ast_string_field_set(props, transferer_type, tech);
-	ast_string_field_set(props, transferer_addr, addr);
-
-	ast_channel_unlock(props->transferer);
-
-	ast_debug(1, "Allocated attended transfer properties %p for transfer from %s\n",
-			props, ast_channel_name(props->transferer));
-	return props;
-}
-
-/*!
- * \brief Free backlog of stimuli in the queue
- */
-static void clear_stimulus_queue(struct attended_transfer_properties *props)
-{
-	struct stimulus_list *list;
-	SCOPED_AO2LOCK(lock, props);
-
-	while ((list = AST_LIST_REMOVE_HEAD(&props->stimulus_queue, next))) {
-		ast_free(list);
-	}
-}
-
-/*!
- * \brief Initiate shutdown of attended transfer properties
- *
- * Calling this indicates that the attended transfer properties are no longer needed
- * because the transfer operation has concluded.
- */
-static void attended_transfer_properties_shutdown(struct attended_transfer_properties *props)
-{
-	ast_debug(1, "Shutting down attended transfer %p\n", props);
-
-	if (props->transferee_bridge) {
-		bridge_basic_change_personality(props->transferee_bridge,
-				BRIDGE_BASIC_PERSONALITY_NORMAL, NULL);
-		ast_bridge_merge_inhibit(props->transferee_bridge, -1);
-	}
-
-	if (props->target_bridge) {
-		ast_bridge_destroy(props->target_bridge, 0);
-		props->target_bridge = NULL;
-	}
-
-	if (props->transferer) {
-		ast_channel_remove_bridge_role(props->transferer, AST_TRANSFERER_ROLE_NAME);
-	}
-
-	clear_stimulus_queue(props);
-
-	ao2_cleanup(props);
-}
-
-static void stimulate_attended_transfer(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	struct stimulus_list *list;
-
-	list = ast_calloc(1, sizeof(*list));
-	if (!list) {
-		ast_log(LOG_ERROR, "Unable to push event to attended transfer queue. Expect transfer to fail\n");
-		return;
-	}
-
-	list->stimulus = stimulus;
-	ao2_lock(props);
-	AST_LIST_INSERT_TAIL(&props->stimulus_queue, list, next);
-	ast_cond_signal(&props->cond);
-	ao2_unlock(props);
-}
-
-/*!
- * \brief Get a desired transfer party for a bridge the transferer is not in.
- *
- * \param bridge The bridge to get the party from. May be NULL.
- * \param[out] party The lone channel in the bridge. Will be set NULL if bridge is NULL or multiple parties are present.
- */
-static void get_transfer_party_non_transferer_bridge(struct ast_bridge *bridge,
-		struct ast_channel **party)
-{
-	if (bridge && bridge->num_channels == 1) {
-		*party = ast_channel_ref(AST_LIST_FIRST(&bridge->channels)->chan);
-	} else {
-		*party = NULL;
-	}
-}
-
-/*!
- * \brief Get the transferee and transfer target when the transferer is in a bridge with
- * one of the desired parties.
- *
- * \param transferer_bridge The bridge the transferer is in
- * \param other_bridge The bridge the transferer is not in. May be NULL.
- * \param transferer The transferer party
- * \param[out] transferer_peer The party that is in the bridge with the transferer
- * \param[out] other_party The party that is in the other_bridge
- */
-static void get_transfer_parties_transferer_bridge(struct ast_bridge *transferer_bridge,
-		struct ast_bridge *other_bridge, struct ast_channel *transferer,
-		struct ast_channel **transferer_peer, struct ast_channel **other_party)
-{
-	*transferer_peer = ast_bridge_peer(transferer_bridge, transferer);
-	get_transfer_party_non_transferer_bridge(other_bridge, other_party);
-}
-
-/*!
- * \brief determine transferee and transfer target for an attended transfer
- *
- * In builtin attended transfers, there is a single transferer channel that jumps between
- * the two bridges involved. At the time the attended transfer occurs, the transferer could
- * be in either bridge, so determining the parties is a bit more complex than normal.
- *
- * The method used here is to determine which of the two bridges the transferer is in, and
- * grabbing the peer from that bridge. The other bridge, if it only has a single channel in it,
- * has the other desired channel.
- *
- * \param transferer The channel performing the transfer
- * \param transferee_bridge The bridge that the transferee is in
- * \param target_bridge The bridge that the transfer target is in
- * \param[out] transferee The transferee channel
- * \param[out] transfer_target The transfer target channel
- */
-static void get_transfer_parties(struct ast_channel *transferer, struct ast_bridge *transferee_bridge,
-		struct ast_bridge *target_bridge, struct ast_channel **transferee,
-		struct ast_channel **transfer_target)
-{
-	struct ast_bridge *transferer_bridge;
-
-	ast_channel_lock(transferer);
-	transferer_bridge = ast_channel_get_bridge(transferer);
-	ast_channel_unlock(transferer);
-
-	if (transferer_bridge == transferee_bridge) {
-		get_transfer_parties_transferer_bridge(transferee_bridge, target_bridge,
-				transferer, transferee, transfer_target);
-	} else if (transferer_bridge == target_bridge) {
-		get_transfer_parties_transferer_bridge(target_bridge, transferee_bridge,
-				transferer, transfer_target, transferee);
-	} else {
-		get_transfer_party_non_transferer_bridge(transferee_bridge, transferee);
-		get_transfer_party_non_transferer_bridge(target_bridge, transfer_target);
-	}
-
-	ao2_cleanup(transferer_bridge);
-}
-
-/*!
- * \brief Send a stasis publication for a successful attended transfer
- */
-static void publish_transfer_success(struct attended_transfer_properties *props,
-		struct ast_channel *transferee_channel, struct ast_channel *target_channel)
-{
-	struct ast_attended_transfer_message *transfer_msg;
-
-	transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
-			props->transferee_bridge, props->transferer, props->target_bridge,
-			transferee_channel, target_channel);
-
-	if (!transfer_msg) {
-		ast_log(LOG_ERROR, "Unable to publish successful attended transfer from %s\n",
-				ast_channel_name(props->transferer));
-		return;
-	}
-
-	ast_attended_transfer_message_add_merge(transfer_msg, props->transferee_bridge);
-	ast_bridge_publish_attended_transfer(transfer_msg);
-	ao2_cleanup(transfer_msg);
-}
-
-/*!
- * \brief Send a stasis publication for an attended transfer that ends in a threeway call
- */
-static void publish_transfer_threeway(struct attended_transfer_properties *props,
-		struct ast_channel *transferee_channel, struct ast_channel *target_channel)
-{
-	struct ast_attended_transfer_message *transfer_msg;
-
-	transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
-			props->transferee_bridge, props->transferer, props->target_bridge,
-			transferee_channel, target_channel);
-
-	if (!transfer_msg) {
-		ast_log(LOG_ERROR, "Unable to publish successful three-way transfer from %s\n",
-				ast_channel_name(props->transferer));
-		return;
-	}
-
-	ast_attended_transfer_message_add_threeway(transfer_msg, props->transferer,
-			props->transferee_bridge);
-	ast_bridge_publish_attended_transfer(transfer_msg);
-	ao2_cleanup(transfer_msg);
-}
-
-/*!
- * \brief Send a stasis publication for a failed attended transfer
- */
-static void publish_transfer_fail(struct attended_transfer_properties *props)
-{
-	struct ast_attended_transfer_message *transfer_msg;
-
-	transfer_msg = ast_attended_transfer_message_create(0, props->transferer,
-			props->transferee_bridge, props->transferer, props->target_bridge,
-			NULL, NULL);
-
-	if (!transfer_msg) {
-		ast_log(LOG_ERROR, "Unable to publish failed transfer from %s\n",
-				ast_channel_name(props->transferer));
-		return;
-	}
-
-	transfer_msg->result = AST_BRIDGE_TRANSFER_FAIL;
-	ast_bridge_publish_attended_transfer(transfer_msg);
-	ao2_cleanup(transfer_msg);
-}
-
-/*!
- * \brief Helper method to play a sound on a channel in a bridge
- *
- * \param chan The channel to play the sound to
- * \param sound The sound to play
- */
-static void play_sound(struct ast_channel *chan, const char *sound)
-{
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-
-	if (!bridge_channel) {
-		return;
-	}
-
-	ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
-}
-
-/*!
- * \brief Helper method to place a channel in a bridge on hold
- */
-static void hold(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	if (chan) {
-		ast_channel_lock(chan);
-		bridge_channel = ast_channel_get_bridge_channel(chan);
-		ast_channel_unlock(chan);
-
-		ast_assert(bridge_channel != NULL);
-
-		ast_bridge_channel_write_hold(bridge_channel, NULL);
-	}
-}
-
-/*!
- * \brief Helper method to take a channel in a bridge off hold
- */
-static void unhold(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-
-	ast_assert(bridge_channel != NULL);
-
-	ast_bridge_channel_write_unhold(bridge_channel);
-}
-
-/*!
- * \brief Helper method to send a ringing indication to a channel in a bridge
- */
-static void ringing(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-
-	ast_assert(bridge_channel != NULL);
-
-	ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_RINGING, NULL, 0);
-}
-
-/*!
- * \brief Helper method to send a ringing indication to all channels in a bridge
- */
-static void bridge_ringing(struct ast_bridge *bridge)
-{
-	struct ast_frame ringing = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = AST_CONTROL_RINGING,
-	};
-
-	ast_bridge_queue_everyone_else(bridge, NULL, &ringing);
-}
-
-/*!
- * \brief Helper method to send a hold frame to all channels in a bridge
- */
-static void bridge_hold(struct ast_bridge *bridge)
-{
-	struct ast_frame hold = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = AST_CONTROL_HOLD,
-	};
-
-	ast_bridge_queue_everyone_else(bridge, NULL, &hold);
-}
-
-/*!
- * \brief Helper method to send an unhold frame to all channels in a bridge
- */
-static void bridge_unhold(struct ast_bridge *bridge)
-{
-	struct ast_frame unhold = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = AST_CONTROL_UNHOLD,
-	};
-
-	ast_bridge_queue_everyone_else(bridge, NULL, &unhold);
-}
-
-/*!
- * \brief Wrapper for \ref bridge_do_move
- */
-static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
-{
-	int res;
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	ast_bridge_lock_both(src, dest);
-
-	ast_channel_lock(channel);
-	bridge_channel = ast_channel_get_bridge_channel(channel);
-	ast_channel_unlock(channel);
-
-	ast_assert(bridge_channel != NULL);
-
-	ao2_lock(bridge_channel);
-	bridge_channel->swap = swap;
-	ao2_unlock(bridge_channel);
-
-	res = bridge_do_move(dest, bridge_channel, 1, 0);
-
-	ast_bridge_unlock(dest);
-	ast_bridge_unlock(src);
-
-	return res;
-}
-
-/*!
- * \brief Wrapper for \ref bridge_do_merge
- */
-static void bridge_merge(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel **kick_channels, unsigned int num_channels)
-{
-	struct ast_bridge_channel **kick_bridge_channels = num_channels ?
-		ast_alloca(num_channels * sizeof(*kick_bridge_channels)) : NULL;
-	int i;
-	int num_bridge_channels = 0;
-
-	ast_bridge_lock_both(dest, src);
-
-	for (i = 0; i < num_channels; ++i) {
-		struct ast_bridge_channel *kick_bridge_channel;
-
-		kick_bridge_channel = bridge_find_channel(src, kick_channels[i]);
-		if (!kick_bridge_channel) {
-			kick_bridge_channel = bridge_find_channel(dest, kick_channels[i]);
-		}
-
-		/* It's possible (and fine) for the bridge channel to be NULL at this point if the
-		 * channel has hung up already. If that happens, we can just remove it from the list
-		 * of bridge channels to kick from the bridge
-		 */
-		if (!kick_bridge_channel) {
-			continue;
-		}
-
-		kick_bridge_channels[num_bridge_channels++] = kick_bridge_channel;
-	}
-
-	bridge_do_merge(dest, src, kick_bridge_channels, num_bridge_channels, 0);
-	ast_bridge_unlock(dest);
-	ast_bridge_unlock(src);
-}
-
-/*!
- * \brief Flags that indicate properties of attended transfer states
- */
-enum attended_transfer_state_flags {
-	/*! This state requires that the timer be reset when entering the state */
-	TRANSFER_STATE_FLAG_TIMER_RESET = (1 << 0),
-	/*! This state's timer uses atxferloopdelay */
-	TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY = (1 << 1),
-	/*! This state's timer uses atxfernoanswertimeout */
-	TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER = (1 << 2),
-	/*! This state has a time limit associated with it */
-	TRANSFER_STATE_FLAG_TIMED = (TRANSFER_STATE_FLAG_TIMER_RESET |
-			TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY | TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER),
-	/*! This state does not transition to any other states */
-	TRANSFER_STATE_FLAG_TERMINAL = (1 << 3),
-};
-
-static int calling_target_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state calling_target_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int hesitant_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state hesitant_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int rebridge_enter(struct attended_transfer_properties *props);
-
-static int resume_enter(struct attended_transfer_properties *props);
-
-static int threeway_enter(struct attended_transfer_properties *props);
-
-static int consulting_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state consulting_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int double_checking_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state double_checking_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int complete_enter(struct attended_transfer_properties *props);
-
-static int blond_enter(struct attended_transfer_properties *props);
-
-static int blond_nonfinal_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state blond_nonfinal_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int recalling_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state recalling_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int wait_to_retransfer_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state wait_to_retransfer_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int retransfer_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state retransfer_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int wait_to_recall_enter(struct attended_transfer_properties *props);
-static enum attended_transfer_state wait_to_recall_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus);
-
-static int fail_enter(struct attended_transfer_properties *props);
-
-/*!
- * \brief Properties of an attended transfer state
- */
-struct attended_transfer_state_properties {
-	/*! The name of the state. Used for debugging */
-	const char *state_name;
-	/*! Function used to enter a state */
-	int (*enter)(struct attended_transfer_properties *props);
-	/*!
-	 * Function used to exit a state
-	 * This is used both to determine what the next state
-	 * to transition to will be and to perform any cleanup
-	 * necessary before exiting the current state.
-	 */
-	enum attended_transfer_state (*exit)(struct attended_transfer_properties *props,
-			enum attended_transfer_stimulus stimulus);
-	/*! Flags associated with this state */
-	enum attended_transfer_state_flags flags;
-};
-
-static const struct attended_transfer_state_properties state_properties[] = {
-	[TRANSFER_CALLING_TARGET] = {
-		.state_name = "Calling Target",
-		.enter = calling_target_enter,
-		.exit = calling_target_exit,
-		.flags = TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER | TRANSFER_STATE_FLAG_TIMER_RESET,
-	},
-	[TRANSFER_HESITANT] = {
-		.state_name = "Hesitant",
-		.enter = hesitant_enter,
-		.exit = hesitant_exit,
-		.flags = TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER,
-	},
-	[TRANSFER_REBRIDGE] = {
-		.state_name = "Rebridge",
-		.enter = rebridge_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-	[TRANSFER_RESUME] = {
-		.state_name = "Resume",
-		.enter = resume_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-	[TRANSFER_THREEWAY] = {
-		.state_name = "Threeway",
-		.enter = threeway_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-	[TRANSFER_CONSULTING] = {
-		.state_name = "Consulting",
-		.enter = consulting_enter,
-		.exit = consulting_exit,
-	},
-	[TRANSFER_DOUBLECHECKING] = {
-		.state_name = "Double Checking",
-		.enter = double_checking_enter,
-		.exit = double_checking_exit,
-	},
-	[TRANSFER_COMPLETE] = {
-		.state_name = "Complete",
-		.enter = complete_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-	[TRANSFER_BLOND] = {
-		.state_name = "Blond",
-		.enter = blond_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-	[TRANSFER_BLOND_NONFINAL] = {
-		.state_name = "Blond Non-Final",
-		.enter = blond_nonfinal_enter,
-		.exit = blond_nonfinal_exit,
-		.flags = TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER,
-	},
-	[TRANSFER_RECALLING] = {
-		.state_name = "Recalling",
-		.enter = recalling_enter,
-		.exit = recalling_exit,
-		.flags = TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER | TRANSFER_STATE_FLAG_TIMER_RESET,
-	},
-	[TRANSFER_WAIT_TO_RETRANSFER] = {
-		.state_name = "Wait to Retransfer",
-		.enter = wait_to_retransfer_enter,
-		.exit = wait_to_retransfer_exit,
-		.flags = TRANSFER_STATE_FLAG_TIMER_RESET | TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY,
-	},
-	[TRANSFER_RETRANSFER] = {
-		.state_name = "Retransfer",
-		.enter = retransfer_enter,
-		.exit = retransfer_exit,
-		.flags = TRANSFER_STATE_FLAG_ATXFER_NO_ANSWER | TRANSFER_STATE_FLAG_TIMER_RESET,
-	},
-	[TRANSFER_WAIT_TO_RECALL] = {
-		.state_name = "Wait to Recall",
-		.enter = wait_to_recall_enter,
-		.exit = wait_to_recall_exit,
-		.flags = TRANSFER_STATE_FLAG_TIMER_RESET | TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY,
-	},
-	[TRANSFER_FAIL] = {
-		.state_name = "Fail",
-		.enter = fail_enter,
-		.flags = TRANSFER_STATE_FLAG_TERMINAL,
-	},
-};
-
-static int calling_target_enter(struct attended_transfer_properties *props)
-{
-	return bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
-}
-
-static enum attended_transfer_state calling_target_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
-		publish_transfer_fail(props);
-		return TRANSFER_FAIL;
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_TRANSFERER_HANGUP:
-		bridge_unhold(props->transferee_bridge);
-		return props->atxferdropcall ? TRANSFER_BLOND : TRANSFER_BLOND_NONFINAL;
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-		return TRANSFER_CONSULTING;
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TIMEOUT:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
-		return TRANSFER_REBRIDGE;
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-		bridge_unhold(props->transferee_bridge);
-		return TRANSFER_THREEWAY;
-	case STIMULUS_DTMF_ATXFER_SWAP:
-		return TRANSFER_HESITANT;
-	case STIMULUS_NONE:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int hesitant_enter(struct attended_transfer_properties *props)
-{
-	if (bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL)) {
-		return -1;
-	}
-
-	unhold(props->transferer);
-	return 0;
-}
-
-static enum attended_transfer_state hesitant_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
-		publish_transfer_fail(props);
-		return TRANSFER_FAIL;
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_TRANSFERER_HANGUP:
-		return props->atxferdropcall ? TRANSFER_BLOND : TRANSFER_BLOND_NONFINAL;
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-		return TRANSFER_DOUBLECHECKING;
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TIMEOUT:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
-		return TRANSFER_RESUME;
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-		return TRANSFER_THREEWAY;
-	case STIMULUS_DTMF_ATXFER_SWAP:
-		hold(props->transferer);
-		return TRANSFER_CALLING_TARGET;
-	case STIMULUS_NONE:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int rebridge_enter(struct attended_transfer_properties *props)
-{
-	if (bridge_move(props->transferee_bridge, props->target_bridge,
-			props->transferer, NULL)) {
-		return -1;
-	}
-
-	unhold(props->transferer);
-	return 0;
-}
-
-static int resume_enter(struct attended_transfer_properties *props)
-{
-	return 0;
-}
-
-static int threeway_enter(struct attended_transfer_properties *props)
-{
-	struct ast_channel *transferee_channel;
-	struct ast_channel *target_channel;
-
-	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
-			&transferee_channel, &target_channel);
-	bridge_merge(props->transferee_bridge, props->target_bridge, NULL, 0);
-	play_sound(props->transfer_target, props->xfersound);
-	play_sound(props->transferer, props->xfersound);
-	publish_transfer_threeway(props, transferee_channel, target_channel);
-
-	ast_channel_cleanup(transferee_channel);
-	ast_channel_cleanup(target_channel);
-	return 0;
-}
-
-static int consulting_enter(struct attended_transfer_properties *props)
-{
-	return 0;
-}
-
-static enum attended_transfer_state consulting_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		/* This is a one-of-a-kind event. The transferer and transfer target are talking in
-		 * one bridge, and the transferee has hung up in a separate bridge. In this case, we
-		 * will change the personality of the transfer target bridge back to normal, and play
-		 * a sound to the transferer to indicate the transferee is gone.
-		 */
-		bridge_basic_change_personality(props->target_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL);
-		play_sound(props->transferer, props->failsound);
-		ast_bridge_merge_inhibit(props->target_bridge, -1);
-		/* These next two lines are here to ensure that our reference to the target bridge
-		 * is cleaned up properly and that the target bridge is not destroyed when the
-		 * monitor thread exits
-		 */
-		ao2_ref(props->target_bridge, -1);
-		props->target_bridge = NULL;
-		return TRANSFER_FAIL;
-	case STIMULUS_TRANSFERER_HANGUP:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-		/* We know the transferer is in the target_bridge, so take the other bridge off hold */
-		bridge_unhold(props->transferee_bridge);
-		return TRANSFER_COMPLETE;
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
-		return TRANSFER_REBRIDGE;
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-		bridge_unhold(props->transferee_bridge);
-		return TRANSFER_THREEWAY;
-	case STIMULUS_DTMF_ATXFER_SWAP:
-		hold(props->transferer);
-		bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL);
-		unhold(props->transferer);
-		return TRANSFER_DOUBLECHECKING;
-	case STIMULUS_NONE:
-	case STIMULUS_TIMEOUT:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int double_checking_enter(struct attended_transfer_properties *props)
-{
-	return 0;
-}
-
-static enum attended_transfer_state double_checking_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
-		publish_transfer_fail(props);
-		return TRANSFER_FAIL;
-	case STIMULUS_TRANSFERER_HANGUP:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-		/* We know the transferer is in the transferee, so take the other bridge off hold */
-		bridge_unhold(props->target_bridge);
-		return TRANSFER_COMPLETE;
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
-		return TRANSFER_RESUME;
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-		bridge_unhold(props->target_bridge);
-		return TRANSFER_THREEWAY;
-	case STIMULUS_DTMF_ATXFER_SWAP:
-		hold(props->transferer);
-		bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
-		unhold(props->transferer);
-		return TRANSFER_CONSULTING;
-	case STIMULUS_NONE:
-	case STIMULUS_TIMEOUT:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int complete_enter(struct attended_transfer_properties *props)
-{
-	struct ast_channel *transferee_channel;
-	struct ast_channel *target_channel;
-
-	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
-			&transferee_channel, &target_channel);
-	bridge_merge(props->transferee_bridge, props->target_bridge, &props->transferer, 1);
-	play_sound(props->transfer_target, props->xfersound);
-	publish_transfer_success(props, transferee_channel, target_channel);
-
-	ast_channel_cleanup(transferee_channel);
-	ast_channel_cleanup(target_channel);
-	return 0;
-}
-
-static int blond_enter(struct attended_transfer_properties *props)
-{
-	struct ast_channel *transferee_channel;
-	struct ast_channel *target_channel;
-
-	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
-			&transferee_channel, &target_channel);
-	bridge_merge(props->transferee_bridge, props->target_bridge, &props->transferer, 1);
-	ringing(props->transfer_target);
-	publish_transfer_success(props, transferee_channel, target_channel);
-
-	ast_channel_cleanup(transferee_channel);
-	ast_channel_cleanup(target_channel);
-	return 0;
-}
-
-static int blond_nonfinal_enter(struct attended_transfer_properties *props)
-{
-	int res;
-	props->superstate = SUPERSTATE_RECALL;
-	props->recall_target = ast_channel_ref(props->transfer_target);
-	res = blond_enter(props);
-	props->transfer_target = ast_channel_unref(props->transfer_target);
-	return res;
-}
-
-static enum attended_transfer_state blond_nonfinal_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		return TRANSFER_FAIL;
-	case STIMULUS_RECALL_TARGET_ANSWER:
-		return TRANSFER_RESUME;
-	case STIMULUS_TIMEOUT:
-		ast_softhangup(props->recall_target, AST_SOFTHANGUP_EXPLICIT);
-		props->recall_target = ast_channel_unref(props->recall_target);
-	case STIMULUS_RECALL_TARGET_HANGUP:
-		return TRANSFER_RECALLING;
-	case STIMULUS_NONE:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-	case STIMULUS_DTMF_ATXFER_SWAP:
-	case STIMULUS_TRANSFERER_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-/*!
- * \brief Dial callback when attempting to recall the original transferer channel
- *
- * This is how we can monitor if the recall target has answered or has hung up.
- * If one of the two is detected, then an appropriate stimulus is sent to the
- * attended transfer monitor thread.
- */
-static void recall_callback(struct ast_dial *dial)
-{
-	struct attended_transfer_properties *props = ast_dial_get_user_data(dial);
-
-	switch (ast_dial_state(dial)) {
-	default:
-	case AST_DIAL_RESULT_INVALID:
-	case AST_DIAL_RESULT_FAILED:
-	case AST_DIAL_RESULT_TIMEOUT:
-	case AST_DIAL_RESULT_HANGUP:
-	case AST_DIAL_RESULT_UNANSWERED:
-		/* Failure cases */
-		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_HANGUP);
-		break;
-	case AST_DIAL_RESULT_RINGING:
-	case AST_DIAL_RESULT_PROGRESS:
-	case AST_DIAL_RESULT_PROCEEDING:
-	case AST_DIAL_RESULT_TRYING:
-		/* Don't care about these cases */
-		break;
-	case AST_DIAL_RESULT_ANSWERED:
-		/* We struck gold! */
-		props->recall_target = ast_dial_answered_steal(dial);
-		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_ANSWER);
-		break;
-	}
-}
-
-
-static int recalling_enter(struct attended_transfer_properties *props)
-{
-	RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-
-	if (!cap) {
-		return -1;
-	}
-
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	/* When we dial the transfer target, since we are communicating
-	 * with a local channel, we can place the local channel in a bridge
-	 * and then call out to it. When recalling the transferer, though, we
-	 * have to use the dialing API because the channel is not local.
-	 */
-	props->dial = ast_dial_create();
-	if (!props->dial) {
-		return -1;
-	}
-
-	if (ast_dial_append(props->dial, props->transferer_type, props->transferer_addr, NULL)) {
-		return -1;
-	}
-
-	if (ast_dial_prerun(props->dial, NULL, cap)) {
-		return -1;
-	}
-
-	ast_dial_set_state_callback(props->dial, &recall_callback);
-
-	ao2_ref(props, +1);
-	ast_dial_set_user_data(props->dial, props);
-
-	if (ast_dial_run(props->dial, NULL, 1) == AST_DIAL_RESULT_FAILED) {
-		ao2_ref(props, -1);
-		return -1;
-	}
-
-	bridge_ringing(props->transferee_bridge);
-	return 0;
-}
-
-static enum attended_transfer_state recalling_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	/* No matter what the outcome was, we need to kill off the dial */
-	ast_dial_join(props->dial);
-	ast_dial_destroy(props->dial);
-	props->dial = NULL;
-	/* This reference is the one we incremented for the dial state callback (recall_callback) to use */
-	ao2_ref(props, -1);
-
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		return TRANSFER_FAIL;
-	case STIMULUS_TIMEOUT:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-		++props->retry_attempts;
-		if (props->retry_attempts >= props->atxfercallbackretries) {
-			return TRANSFER_FAIL;
-		}
-		if (props->atxferloopdelay) {
-			return TRANSFER_WAIT_TO_RETRANSFER;
-		}
-		return TRANSFER_RETRANSFER;
-	case STIMULUS_RECALL_TARGET_ANSWER:
-		/* Setting this datastore up will allow the transferer to have all of his
-		 * call features set up automatically when the bridge changes back to a
-		 * normal personality
-		 */
-		ast_bridge_features_ds_set(props->recall_target, &props->transferer_features);
-		ast_channel_ref(props->recall_target);
-		if (ast_bridge_impart(props->transferee_bridge, props->recall_target, NULL, NULL,
-			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-			ast_hangup(props->recall_target);
-			return TRANSFER_FAIL;
-		}
-		return TRANSFER_RESUME;
-	case STIMULUS_NONE:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-	case STIMULUS_DTMF_ATXFER_SWAP:
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_TRANSFERER_HANGUP:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int wait_to_retransfer_enter(struct attended_transfer_properties *props)
-{
-	bridge_hold(props->transferee_bridge);
-	return 0;
-}
-
-static enum attended_transfer_state wait_to_retransfer_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	bridge_unhold(props->transferee_bridge);
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		return TRANSFER_FAIL;
-	case STIMULUS_TIMEOUT:
-		return TRANSFER_RETRANSFER;
-	case STIMULUS_NONE:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-	case STIMULUS_DTMF_ATXFER_SWAP:
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_TRANSFERER_HANGUP:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int attach_framehook(struct attended_transfer_properties *props, struct ast_channel *channel);
-
-static int retransfer_enter(struct attended_transfer_properties *props)
-{
-	RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
-	int cause;
-
-	if (!cap) {
-		return -1;
-	}
-
-	snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context);
-
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	/* Get a channel that is the destination we wish to call */
-	props->recall_target = ast_request("Local", cap, NULL, NULL, destination, &cause);
-	if (!props->recall_target) {
-		ast_log(LOG_ERROR, "Unable to request outbound channel for recall target\n");
-		return -1;
-	}
-
-	if (attach_framehook(props, props->recall_target)) {
-		ast_log(LOG_ERROR, "Unable to attach framehook to recall target\n");
-		ast_hangup(props->recall_target);
-		props->recall_target = NULL;
-		return -1;
-	}
-
-	if (ast_call(props->recall_target, destination, 0)) {
-		ast_log(LOG_ERROR, "Unable to place outbound call to recall target\n");
-		ast_hangup(props->recall_target);
-		props->recall_target = NULL;
-		return -1;
-	}
-
-	ast_channel_ref(props->recall_target);
-	if (ast_bridge_impart(props->transferee_bridge, props->recall_target, NULL, NULL,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_log(LOG_ERROR, "Unable to place recall target into bridge\n");
-		ast_hangup(props->recall_target);
-		return -1;
-	}
-
-	return 0;
-}
-
-static enum attended_transfer_state retransfer_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		return TRANSFER_FAIL;
-	case STIMULUS_TIMEOUT:
-		ast_softhangup(props->recall_target, AST_SOFTHANGUP_EXPLICIT);
-	case STIMULUS_RECALL_TARGET_HANGUP:
-		props->recall_target = ast_channel_unref(props->recall_target);
-		if (props->atxferloopdelay) {
-			return TRANSFER_WAIT_TO_RECALL;
-		}
-		return TRANSFER_RECALLING;
-	case STIMULUS_RECALL_TARGET_ANSWER:
-		return TRANSFER_RESUME;
-	case STIMULUS_NONE:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-	case STIMULUS_DTMF_ATXFER_SWAP:
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_TRANSFERER_HANGUP:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int wait_to_recall_enter(struct attended_transfer_properties *props)
-{
-	bridge_hold(props->transferee_bridge);
-	return 0;
-}
-
-static enum attended_transfer_state wait_to_recall_exit(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	bridge_unhold(props->transferee_bridge);
-	switch (stimulus) {
-	case STIMULUS_TRANSFEREE_HANGUP:
-		return TRANSFER_FAIL;
-	case STIMULUS_TIMEOUT:
-		return TRANSFER_RECALLING;
-	case STIMULUS_NONE:
-	case STIMULUS_DTMF_ATXFER_ABORT:
-	case STIMULUS_DTMF_ATXFER_COMPLETE:
-	case STIMULUS_DTMF_ATXFER_THREEWAY:
-	case STIMULUS_DTMF_ATXFER_SWAP:
-	case STIMULUS_TRANSFER_TARGET_HANGUP:
-	case STIMULUS_TRANSFER_TARGET_ANSWER:
-	case STIMULUS_TRANSFERER_HANGUP:
-	case STIMULUS_RECALL_TARGET_HANGUP:
-	case STIMULUS_RECALL_TARGET_ANSWER:
-	default:
-		ast_log(LOG_WARNING, "Unexpected stimulus '%s' received in attended transfer state '%s'\n",
-				stimulus_strs[stimulus], state_properties[props->state].state_name);
-		return props->state;
-	}
-}
-
-static int fail_enter(struct attended_transfer_properties *props)
-{
-	if (props->transferee_bridge) {
-		ast_bridge_destroy(props->transferee_bridge, 0);
-		props->transferee_bridge = NULL;
-	}
-	return 0;
-}
-
-/*!
- * \brief DTMF hook when transferer presses abort sequence.
- *
- * Sends a stimulus to the attended transfer monitor thread that the abort sequence has been pressed
- */
-static int atxfer_abort(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct attended_transfer_properties *props = hook_pvt;
-
-	ast_debug(1, "Transferer on attended transfer %p pressed abort sequence\n", props);
-	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_ABORT);
-	return 0;
-}
-
-/*!
- * \brief DTMF hook when transferer presses complete sequence.
- *
- * Sends a stimulus to the attended transfer monitor thread that the complete sequence has been pressed
- */
-static int atxfer_complete(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct attended_transfer_properties *props = hook_pvt;
-
-	ast_debug(1, "Transferer on attended transfer %p pressed complete sequence\n", props);
-	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_COMPLETE);
-	return 0;
-}
-
-/*!
- * \brief DTMF hook when transferer presses threeway sequence.
- *
- * Sends a stimulus to the attended transfer monitor thread that the threeway sequence has been pressed
- */
-static int atxfer_threeway(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct attended_transfer_properties *props = hook_pvt;
-
-	ast_debug(1, "Transferer on attended transfer %p pressed threeway sequence\n", props);
-	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_THREEWAY);
-	return 0;
-}
-
-/*!
- * \brief DTMF hook when transferer presses swap sequence.
- *
- * Sends a stimulus to the attended transfer monitor thread that the swap sequence has been pressed
- */
-static int atxfer_swap(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct attended_transfer_properties *props = hook_pvt;
-
-	ast_debug(1, "Transferer on attended transfer %p pressed swap sequence\n", props);
-	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_SWAP);
-	return 0;
-}
-
-/*!
- * \brief Hangup hook for transferer channel.
- *
- * Sends a stimulus to the attended transfer monitor thread that the transferer has hung up.
- */
-static int atxfer_transferer_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct attended_transfer_properties *props = hook_pvt;
-
-	ast_debug(1, "Transferer on attended transfer %p hung up\n", props);
-	stimulate_attended_transfer(props, STIMULUS_TRANSFERER_HANGUP);
-	return 0;
-}
-
-/*!
- * \brief Frame hook for transfer target channel
- *
- * This is used to determine if the transfer target or recall target has answered
- * the outgoing call.
- *
- * When an answer is detected, a stimulus is sent to the attended transfer monitor
- * thread to indicate that the transfer target or recall target has answered.
- *
- * \param chan The channel the framehook is attached to.
- * \param frame The frame being read or written.
- * \param event What is being done with the frame.
- * \param data The attended transfer properties.
- */
-static struct ast_frame *transfer_target_framehook_cb(struct ast_channel *chan,
-		struct ast_frame *frame, enum ast_framehook_event event, void *data)
-{
-	struct attended_transfer_properties *props = data;
-
-	if (event == AST_FRAMEHOOK_EVENT_READ &&
-			frame && frame->frametype == AST_FRAME_CONTROL &&
-			frame->subclass.integer == AST_CONTROL_ANSWER) {
-
-		ast_debug(1, "Detected an answer for recall attempt on attended transfer %p\n", props);
-		if (props->superstate == SUPERSTATE_TRANSFER) {
-			stimulate_attended_transfer(props, STIMULUS_TRANSFER_TARGET_ANSWER);
-		} else {
-			stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_ANSWER);
-		}
-		ast_framehook_detach(chan, props->target_framehook_id);
-		props->target_framehook_id = -1;
-	}
-
-	return frame;
-}
-
-/*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */
-static int transfer_target_framehook_consume(void *data, enum ast_frame_type type)
-{
-	return (type == AST_FRAME_CONTROL ? 1 : 0);
-}
-
-static void transfer_target_framehook_destroy_cb(void *data)
-{
-	struct attended_transfer_properties *props = data;
-	ao2_cleanup(props);
-}
-
-static int bridge_personality_atxfer_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	const char *abort_dtmf;
-	const char *complete_dtmf;
-	const char *threeway_dtmf;
-	const char *swap_dtmf;
-	struct bridge_basic_personality *personality = self->personality;
-
-	if (!ast_channel_has_role(bridge_channel->chan, AST_TRANSFERER_ROLE_NAME)) {
-		return 0;
-	}
-
-	abort_dtmf = ast_channel_get_role_option(bridge_channel->chan, AST_TRANSFERER_ROLE_NAME, "abort");
-	complete_dtmf = ast_channel_get_role_option(bridge_channel->chan, AST_TRANSFERER_ROLE_NAME, "complete");
-	threeway_dtmf = ast_channel_get_role_option(bridge_channel->chan, AST_TRANSFERER_ROLE_NAME, "threeway");
-	swap_dtmf = ast_channel_get_role_option(bridge_channel->chan, AST_TRANSFERER_ROLE_NAME, "swap");
-
-	if (!ast_strlen_zero(abort_dtmf) && ast_bridge_dtmf_hook(bridge_channel->features,
-			abort_dtmf, atxfer_abort, personality->details[personality->current].pvt, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE | AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		return -1;
-	}
-	if (!ast_strlen_zero(complete_dtmf) && ast_bridge_dtmf_hook(bridge_channel->features,
-			complete_dtmf, atxfer_complete, personality->details[personality->current].pvt, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE | AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		return -1;
-	}
-	if (!ast_strlen_zero(threeway_dtmf) && ast_bridge_dtmf_hook(bridge_channel->features,
-			threeway_dtmf, atxfer_threeway, personality->details[personality->current].pvt, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE | AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		return -1;
-	}
-	if (!ast_strlen_zero(swap_dtmf) && ast_bridge_dtmf_hook(bridge_channel->features,
-			swap_dtmf, atxfer_swap, personality->details[personality->current].pvt, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE | AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		return -1;
-	}
-	if (ast_bridge_hangup_hook(bridge_channel->features, atxfer_transferer_hangup,
-			personality->details[personality->current].pvt, NULL,
-			AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE | AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct attended_transfer_properties *props)
-{
-	if (self->num_channels > 1 || bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-		return;
-	}
-
-	if (self->num_channels == 1) {
-		RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
-
-		ast_channel_lock(props->transferer);
-		transferer_bridge_channel = ast_channel_get_bridge_channel(props->transferer);
-		ast_channel_unlock(props->transferer);
-
-		if (!transferer_bridge_channel) {
-			return;
-		}
-
-		if (AST_LIST_FIRST(&self->channels) != transferer_bridge_channel) {
-			return;
-		}
-	}
-
-	/* Reaching this point means that either
-	 * 1) The bridge has no channels in it
-	 * 2) The bridge has one channel, and it's the transferer
-	 * In either case, it indicates that the non-transferer parties
-	 * are no longer in the bridge.
-	 */
-	if (self == props->transferee_bridge) {
-		stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
-	} else {
-		stimulate_attended_transfer(props, STIMULUS_TRANSFER_TARGET_HANGUP);
-	}
-}
-
-static void recall_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct attended_transfer_properties *props)
-{
-	if (self == props->target_bridge) {
-		/* Once we're in the recall superstate, we no longer care about this bridge */
-		return;
-	}
-
-	if (bridge_channel->chan == props->recall_target) {
-		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_HANGUP);
-		return;
-	}
-
-	if (self->num_channels == 0) {
-		/* Empty bridge means all transferees are gone for sure */
-		stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
-		return;
-	}
-
-	if (self->num_channels == 1) {
-		RAII_VAR(struct ast_bridge_channel *, target_bridge_channel, NULL, ao2_cleanup);
-		if (!props->recall_target) {
-			/* No recall target means that the pull happened on a transferee. If there's still
-			 * a channel left in the bridge, we don't need to send a stimulus
-			 */
-			return;
-		}
-
-		ast_channel_lock(props->recall_target);
-		target_bridge_channel = ast_channel_get_bridge_channel(props->recall_target);
-		ast_channel_unlock(props->recall_target);
-
-		if (!target_bridge_channel) {
-			return;
-		}
-
-		if (AST_LIST_FIRST(&self->channels) == target_bridge_channel) {
-			stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
-		}
-	}
-}
-
-static void bridge_personality_atxfer_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	struct bridge_basic_personality *personality = self->personality;
-	struct attended_transfer_properties *props = personality->details[personality->current].pvt;
-
-	switch (props->superstate) {
-	case SUPERSTATE_TRANSFER:
-		transfer_pull(self, bridge_channel, props);
-		break;
-	case SUPERSTATE_RECALL:
-		recall_pull(self, bridge_channel, props);
-		break;
-	}
-}
-
-static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfer_properties *props)
-{
-	RAII_VAR(struct stimulus_list *, list, NULL, ast_free_ptr);
-	SCOPED_MUTEX(lock, ao2_object_get_lockaddr(props));
-
-	while (!(list = AST_LIST_REMOVE_HEAD(&props->stimulus_queue, next))) {
-		if (!(state_properties[props->state].flags & TRANSFER_STATE_FLAG_TIMED)) {
-			ast_cond_wait(&props->cond, lock);
-		} else {
-			struct timeval relative_timeout = { 0, };
-			struct timeval absolute_timeout;
-			struct timespec timeout_arg;
-
-			if (state_properties[props->state].flags & TRANSFER_STATE_FLAG_TIMER_RESET) {
-				props->start = ast_tvnow();
-			}
-
-			if (state_properties[props->state].flags & TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY) {
-				relative_timeout.tv_sec = props->atxferloopdelay;
-			} else {
-				/* Implied TRANSFER_STATE_FLAG_TIMER_ATXFER_NO_ANSWER */
-				relative_timeout.tv_sec = props->atxfernoanswertimeout;
-			}
-
-			absolute_timeout = ast_tvadd(props->start, relative_timeout);
-			timeout_arg.tv_sec = absolute_timeout.tv_sec;
-			timeout_arg.tv_nsec = absolute_timeout.tv_usec * 1000;
-
-			if (ast_cond_timedwait(&props->cond, lock, &timeout_arg) == ETIMEDOUT) {
-				return STIMULUS_TIMEOUT;
-			}
-		}
-	}
-	return list->stimulus;
-}
-
-/*!
- * \brief The main loop for the attended transfer monitor thread.
- *
- * This loop runs continuously until the attended transfer reaches
- * a terminal state. Stimuli for changes in the attended transfer
- * state are handled in this thread so that all factors in an
- * attended transfer can be handled in an orderly fashion.
- *
- * \param data The attended transfer properties
- */
-static void *attended_transfer_monitor_thread(void *data)
-{
-	struct attended_transfer_properties *props = data;
-
-	for (;;) {
-		enum attended_transfer_stimulus stimulus;
-
-		ast_debug(1, "About to enter state %s for attended transfer %p\n", state_properties[props->state].state_name, props);
-
-		if (state_properties[props->state].enter &&
-				state_properties[props->state].enter(props)) {
-			ast_log(LOG_ERROR, "State %s enter function returned an error for attended transfer %p\n",
-					state_properties[props->state].state_name, props);
-			break;
-		}
-
-		if (state_properties[props->state].flags & TRANSFER_STATE_FLAG_TERMINAL) {
-			ast_debug(1, "State %s is a terminal state. Ending attended transfer %p\n",
-					state_properties[props->state].state_name, props);
-			break;
-		}
-
-		stimulus = wait_for_stimulus(props);
-
-		ast_debug(1, "Received stimulus %s on attended transfer %p\n", stimulus_strs[stimulus], props);
-
-		ast_assert(state_properties[props->state].exit != NULL);
-
-		props->state = state_properties[props->state].exit(props, stimulus);
-
-		ast_debug(1, "Told to enter state %s exit on attended transfer %p\n", state_properties[props->state].state_name, props);
-	}
-
-	attended_transfer_properties_shutdown(props);
-
-	return NULL;
-}
-
-static int attach_framehook(struct attended_transfer_properties *props, struct ast_channel *channel)
-{
-	struct ast_framehook_interface target_interface = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = transfer_target_framehook_cb,
-		.destroy_cb = transfer_target_framehook_destroy_cb,
-		.consume_cb = transfer_target_framehook_consume,
-		.disable_inheritance = 1,
-	};
-
-	ao2_ref(props, +1);
-	target_interface.data = props;
-
-	props->target_framehook_id = ast_framehook_attach(channel, &target_interface);
-	if (props->target_framehook_id == -1) {
-		ao2_ref(props, -1);
-		return -1;
-	}
-	return 0;
-}
-
-static int add_transferer_role(struct ast_channel *chan, struct ast_bridge_features_attended_transfer *attended_transfer)
-{
-	const char *atxfer_abort;
-	const char *atxfer_threeway;
-	const char *atxfer_complete;
-	const char *atxfer_swap;
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	xfer_cfg = ast_get_chan_features_xfer_config(chan);
-	if (!xfer_cfg) {
-		return -1;
-	}
-	if (attended_transfer) {
-		atxfer_abort = ast_strdupa(S_OR(attended_transfer->abort, xfer_cfg->atxferabort));
-		atxfer_threeway = ast_strdupa(S_OR(attended_transfer->threeway, xfer_cfg->atxferthreeway));
-		atxfer_complete = ast_strdupa(S_OR(attended_transfer->complete, xfer_cfg->atxfercomplete));
-		atxfer_swap = ast_strdupa(S_OR(attended_transfer->swap, xfer_cfg->atxferswap));
-	} else {
-		atxfer_abort = ast_strdupa(xfer_cfg->atxferabort);
-		atxfer_threeway = ast_strdupa(xfer_cfg->atxferthreeway);
-		atxfer_complete = ast_strdupa(xfer_cfg->atxfercomplete);
-		atxfer_swap = ast_strdupa(xfer_cfg->atxferswap);
-	}
-
-	return ast_channel_add_bridge_role(chan, AST_TRANSFERER_ROLE_NAME) ||
-		ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "abort", atxfer_abort) ||
-		ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "complete", atxfer_complete) ||
-		ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "threeway", atxfer_threeway) ||
-		ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "swap", atxfer_swap);
-}
-
-/*!
- * \brief Helper function that presents dialtone and grabs extension
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
-{
-	int res;
-	int digit_timeout;
-	int attempts = 0;
-	int max_attempts;
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-	char *retry_sound;
-	char *invalid_sound;
-
-	ast_channel_lock(chan);
-	xfer_cfg = ast_get_chan_features_xfer_config(chan);
-	if (!xfer_cfg) {
-		ast_log(LOG_ERROR, "Unable to get transfer configuration\n");
-		ast_channel_unlock(chan);
-		return -1;
-	}
-	digit_timeout = xfer_cfg->transferdigittimeout * 1000;
-	max_attempts = xfer_cfg->transferdialattempts;
-	retry_sound = ast_strdupa(xfer_cfg->transferretrysound);
-	invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);
-	ast_channel_unlock(chan);
-
-	/* Play the simple "transfer" prompt out and wait */
-	res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
-	ast_stopstream(chan);
-	if (res < 0) {
-		/* Hangup or error */
-		return -1;
-	}
-	if (res) {
-		/* Store the DTMF digit that interrupted playback of the file. */
-		exten[0] = res;
-	}
-
-	/* Drop to dialtone so they can enter the extension they want to transfer to */
-	do {
-		++attempts;
-
-		ast_test_suite_event_notify("TRANSFER_BEGIN_DIAL",
-				"Channel: %s\r\n"
-				"Attempt: %d",
-				ast_channel_name(chan), attempts);
-		res = ast_app_dtget(chan, context, exten, exten_len, exten_len - 1, digit_timeout);
-		ast_test_suite_event_notify("TRANSFER_DIALLED",
-				"Channel: %s\r\n"
-				"Attempt: %d\r\n"
-				"Dialled: %s\r\n"
-				"Result: %s",
-				ast_channel_name(chan), attempts, exten, res > 0 ? "Success" : "Failure");
-		if (res < 0) {
-			/* Hangup or error */
-			res = -1;
-		} else if (!res) {
-			/* 0 for invalid extension dialed. */
-			if (ast_strlen_zero(exten)) {
-				ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan));
-			} else {
-				ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
-					ast_channel_name(chan), exten, context);
-			}
-			if (attempts < max_attempts) {
-				ast_stream_and_wait(chan, retry_sound, AST_DIGIT_NONE);
-			} else {
-				ast_stream_and_wait(chan, invalid_sound, AST_DIGIT_NONE);
-			}
-			memset(exten, 0, exten_len);
-			res = 1;
-		} else {
-			/* Dialed extension is valid. */
-			res = 0;
-		}
-	} while (res > 0 && attempts < max_attempts);
-
-	ast_test_suite_event_notify("TRANSFER_DIAL_FINAL",
-			"Channel: %s\r\n"
-			"Result: %s",
-			ast_channel_name(chan), res == 0 ? "Success" : "Failure");
-
-	return res ? -1 : 0;
-}
-
-static void copy_caller_data(struct ast_channel *dest, struct ast_channel *caller)
-{
-	ast_channel_lock_both(caller, dest);
-	ast_connected_line_copy_from_caller(ast_channel_connected(dest), ast_channel_caller(caller));
-	ast_channel_inherit_variables(caller, dest);
-	ast_channel_datastore_inherit(caller, dest);
-	ast_channel_unlock(dest);
-	ast_channel_unlock(caller);
-}
-
-/*! \brief Helper function that creates an outgoing channel and returns it immediately */
-static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *destination)
-{
-	struct ast_channel *chan;
-	int cause;
-
-	/* Now we request a local channel to prepare to call the destination */
-	chan = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller, destination,
-		&cause);
-	if (!chan) {
-		return NULL;
-	}
-
-	ast_channel_lock_both(chan, caller);
-
-	ast_channel_req_accountcodes(chan, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
-
-	/* Who is transferring the call. */
-	pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller));
-
-	ast_bridge_set_transfer_variables(chan, ast_channel_name(caller), 1);
-
-	ast_channel_unlock(chan);
-	ast_channel_unlock(caller);
-
-	/* Before we actually dial out let's inherit appropriate information. */
-	copy_caller_data(chan, caller);
-
-	return chan;
-}
-
-/*!
- * \brief Internal built in feature for attended transfers
- *
- * This hook will set up a thread for monitoring the progress of
- * an attended transfer. For more information about attended transfer
- * progress, see documentation on the transfer state machine.
- *
- * \param bridge_channel The channel that pressed the attended transfer DTMF sequence
- * \param hook_pvt Structure with further information about the attended transfer
- */
-static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
-	struct attended_transfer_properties *props;
-	struct ast_bridge *bridge;
-	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
-	char exten[AST_MAX_EXTENSION] = "";
-	pthread_t thread;
-
-	/* Inhibit the bridge before we do anything else. */
-	bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1);
-
-	if (strcmp(bridge->v_table->name, "basic")) {
-		ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'.\n",
-			bridge->v_table->name);
-		ast_bridge_merge_inhibit(bridge, -1);
-		ao2_ref(bridge, -1);
-		return 0;
-	}
-
-	/* Was the bridge inhibited before we inhibited it? */
-	if (1 < bridge->inhibit_merge) {
-		/*
-		 * The peer likely initiated attended transfer at the same time
-		 * and we lost the race.
-		 */
-		ast_verb(3, "Channel %s: Bridge '%s' does not permit merging at this time.\n",
-			ast_channel_name(bridge_channel->chan), bridge->uniqueid);
-		ast_bridge_merge_inhibit(bridge, -1);
-		ao2_ref(bridge, -1);
-		return 0;
-	}
-
-	props = attended_transfer_properties_alloc(bridge_channel->chan,
-		attended_transfer ? attended_transfer->context : NULL);
-	if (!props) {
-		ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer.\n");
-		ast_bridge_merge_inhibit(bridge, -1);
-		ao2_ref(bridge, -1);
-		return 0;
-	}
-
-	props->transferee_bridge = bridge;
-
-	if (add_transferer_role(props->transferer, attended_transfer)) {
-		ast_log(LOG_ERROR, "Unable to set transferrer bridge role.\n");
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	ast_bridge_channel_write_hold(bridge_channel, NULL);
-
-	/* Grab the extension to transfer to */
-	if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) {
-		ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer.\n");
-		ast_bridge_channel_write_unhold(bridge_channel);
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	ast_string_field_set(props, exten, exten);
-
-	/* Fill the variable with the extension and context we want to call */
-	snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context);
-
-	ast_debug(1, "Attended transfer to '%s'\n", destination);
-
-	/* Get a channel that is the destination we wish to call */
-	props->transfer_target = dial_transfer(bridge_channel->chan, destination);
-	if (!props->transfer_target) {
-		ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-
-	/* Create a bridge to use to talk to the person we are calling */
-	props->target_bridge = ast_bridge_basic_new();
-	if (!props->target_bridge) {
-		ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		ast_hangup(props->transfer_target);
-		props->transfer_target = NULL;
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-	ast_bridge_merge_inhibit(props->target_bridge, +1);
-
-	if (attach_framehook(props, props->transfer_target)) {
-		ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		ast_hangup(props->transfer_target);
-		props->transfer_target = NULL;
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	bridge_basic_change_personality(props->target_bridge,
-			BRIDGE_BASIC_PERSONALITY_ATXFER, props);
-	bridge_basic_change_personality(bridge,
-			BRIDGE_BASIC_PERSONALITY_ATXFER, props);
-
-	if (ast_call(props->transfer_target, destination, 0)) {
-		ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		ast_hangup(props->transfer_target);
-		props->transfer_target = NULL;
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	/* We increase the refcount of the transfer target because ast_bridge_impart() will
-	 * steal the reference we already have. We need to keep a reference, so the only
-	 * choice is to give it a bump
-	 */
-	ast_channel_ref(props->transfer_target);
-	if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		ast_hangup(props->transfer_target);
-		props->transfer_target = NULL;
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) {
-		ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
-		ast_bridge_channel_write_unhold(bridge_channel);
-		attended_transfer_properties_shutdown(props);
-		return 0;
-	}
-
-	/* Once the monitoring thread has been created, it is responsible for destroying all
-	 * of the necessary components.
-	 */
-	return 0;
-}
-
-static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_channel_data *user_data_wrapper,
-		enum ast_transfer_type transfer_type)
-{
-	struct ast_channel *transferer_channel = user_data_wrapper->data;
-
-	if (transfer_type == AST_BRIDGE_TRANSFER_MULTI_PARTY) {
-		copy_caller_data(new_channel, transferer_channel);
-	}
-}
-
-/*! \brief Internal built in feature for blind transfers */
-static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	char exten[AST_MAX_EXTENSION] = "";
-	struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
-	const char *context;
-	char *goto_on_blindxfr;
-
-	ast_bridge_channel_write_hold(bridge_channel, NULL);
-
-	ast_channel_lock(bridge_channel->chan);
-	context = ast_strdupa(get_transfer_context(bridge_channel->chan,
-		blind_transfer ? blind_transfer->context : NULL));
-	goto_on_blindxfr = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,
-		"GOTO_ON_BLINDXFR"), ""));
-	ast_channel_unlock(bridge_channel->chan);
-
-	/* Grab the extension to transfer to */
-	if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
-		ast_bridge_channel_write_unhold(bridge_channel);
-		return 0;
-	}
-
-	if (!ast_strlen_zero(goto_on_blindxfr)) {
-		ast_debug(1, "After transfer, transferer %s goes to %s\n",
-				ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
-		ast_bridge_set_after_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
-	}
-
-	if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb,
-			bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS &&
-			!ast_strlen_zero(goto_on_blindxfr)) {
-		ast_bridge_discard_after_goto(bridge_channel->chan);
-	}
-
-	return 0;
-}
-
-struct ast_bridge_methods ast_bridge_basic_v_table;
-struct ast_bridge_methods personality_normal_v_table;
-struct ast_bridge_methods personality_atxfer_v_table;
-
-static void bridge_basic_change_personality(struct ast_bridge *bridge,
-		enum bridge_basic_personality_type type, void *user_data)
-{
-	struct bridge_basic_personality *personality = bridge->personality;
-	SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
-
-	remove_hooks_on_personality_change(bridge);
-
-	ao2_cleanup(personality->details[personality->current].pvt);
-	personality->details[personality->current].pvt = NULL;
-	ast_clear_flag(&bridge->feature_flags, AST_FLAGS_ALL);
-
-	personality->current = type;
-	if (user_data) {
-		ao2_ref(user_data, +1);
-	}
-	personality->details[personality->current].pvt = user_data;
-	ast_set_flag(&bridge->feature_flags, personality->details[personality->current].bridge_flags);
-	if (personality->details[personality->current].on_personality_change) {
-		personality->details[personality->current].on_personality_change(bridge);
-	}
-}
-
-static void personality_destructor(void *obj)
-{
-	struct bridge_basic_personality *personality = obj;
-	int i;
-
-	for (i = 0; i < BRIDGE_BASIC_PERSONALITY_END; ++i) {
-		ao2_cleanup(personality->details[i].pvt);
-	}
-}
-
-static void on_personality_change_normal(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *iter;
-
-	AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
-		if (add_normal_hooks(bridge, iter)) {
-			ast_log(LOG_WARNING, "Unable to set up bridge hooks for channel %s. Features may not work properly\n",
-					ast_channel_name(iter->chan));
-		}
-	}
-}
-
-static void init_details(struct personality_details *details,
-		enum bridge_basic_personality_type type)
-{
-	switch (type) {
-	case BRIDGE_BASIC_PERSONALITY_NORMAL:
-		details->v_table = &personality_normal_v_table;
-		details->bridge_flags = NORMAL_FLAGS;
-		details->on_personality_change = on_personality_change_normal;
-		break;
-	case BRIDGE_BASIC_PERSONALITY_ATXFER:
-		details->v_table = &personality_atxfer_v_table;
-		details->bridge_flags = TRANSFER_FLAGS;
-		break;
-	default:
-		ast_log(LOG_WARNING, "Asked to initialize unexpected basic bridge personality type.\n");
-		break;
-	}
-}
-
-static struct ast_bridge *bridge_basic_personality_alloc(struct ast_bridge *bridge)
-{
-	struct bridge_basic_personality *personality;
-	int i;
-
-	if (!bridge) {
-		return NULL;
-	}
-
-	personality = ao2_alloc(sizeof(*personality), personality_destructor);
-	if (!personality) {
-		ao2_ref(bridge, -1);
-		return NULL;
-	}
-	for (i = 0; i < BRIDGE_BASIC_PERSONALITY_END; ++i) {
-		init_details(&personality->details[i], i);
-	}
-	personality->current = BRIDGE_BASIC_PERSONALITY_NORMAL;
-	bridge->personality = personality;
-
-	return bridge;
-}
-
-struct ast_bridge *ast_bridge_basic_new(void)
-{
-	struct ast_bridge *bridge;
-
-	bridge = bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_basic_v_table);
-	bridge = bridge_base_init(bridge,
-		AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX
-			| AST_BRIDGE_CAPABILITY_MULTIMIX, NORMAL_FLAGS, NULL, NULL, NULL);
-	bridge = bridge_basic_personality_alloc(bridge);
-	bridge = bridge_register(bridge);
-	return bridge;
-}
-
-void ast_bridge_basic_set_flags(struct ast_bridge *bridge, unsigned int flags)
-{
-	SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
-	struct bridge_basic_personality *personality = bridge->personality;
-
-	personality->details[personality->current].bridge_flags |= flags;
-	ast_set_flag(&bridge->feature_flags, flags);
-}
-
-void ast_bridging_init_basic(void)
-{
-	/* Setup bridge basic subclass v_table. */
-	ast_bridge_basic_v_table = ast_bridge_base_v_table;
-	ast_bridge_basic_v_table.name = "basic";
-	ast_bridge_basic_v_table.push = bridge_basic_push;
-	ast_bridge_basic_v_table.pull = bridge_basic_pull;
-	ast_bridge_basic_v_table.destroy = bridge_basic_destroy;
-
-	/*
-	 * Personality vtables don't have the same rules as
-	 * normal bridge vtables.  These vtable functions are
-	 * used as alterations to the ast_bridge_basic_v_table
-	 * method functionality and are checked for NULL before
-	 * calling.
-	 */
-	personality_normal_v_table.name = "normal";
-	personality_normal_v_table.push = bridge_personality_normal_push;
-
-	personality_atxfer_v_table.name = "attended transfer";
-	personality_atxfer_v_table.push = bridge_personality_atxfer_push;
-	personality_atxfer_v_table.pull = bridge_personality_atxfer_pull;
-
-	ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
-	ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
-}
-
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
deleted file mode 100644
index 232141c..0000000
--- a/main/bridge_channel.c
+++ /dev/null
@@ -1,2777 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2007 - 2009, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Bridging Channel API
- *
- * \author Joshua Colp <jcolp at digium.com>
- * \author Richard Mudgett <rmudgett at digium.com>
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428602 $")
-
-#include <signal.h>
-#include <semaphore.h>
-
-#include "asterisk/heap.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/app.h"
-#include "asterisk/pbx.h"
-#include "asterisk/channel.h"
-#include "asterisk/timing.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_channel.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/bridge_channel_internal.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/features_config.h"
-#include "asterisk/parking.h"
-#include "asterisk/causes.h"
-#include "asterisk/test.h"
-
-/*!
- * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel work with.
- * \param action Type of bridge action frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen);
-
-/*!
- * \brief Counter used for assigning synchronous bridge action IDs
- */
-static int sync_ids;
-
-/*!
- * \brief Frame payload for synchronous bridge actions.
- *
- * The payload serves as a wrapper around the actual payload of the
- * frame, with the addition of an id used to find the associated
- * bridge_sync object.
- */
-struct sync_payload {
-	/*! Unique ID for this synchronous action */
-	unsigned int id;
-	/*! Actual frame data to process */
-	unsigned char data[0];
-};
-
-/*!
- * \brief Synchronous bridge action object.
- *
- * Synchronous bridge actions require the ability for one thread to wait
- * and for another thread to indicate that the action has completed. This
- * structure facilitates that goal by providing synchronization structures.
- */
-struct bridge_sync {
-	/*! Unique ID of this synchronization object. Corresponds with ID in synchronous frame payload */
-	unsigned int id;
-	/*! Semaphore used for synchronization */
-	sem_t sem;
-	/*! Pointer to next entry in the list */
-	AST_LIST_ENTRY(bridge_sync) list;
-};
-
-/*!
- * \brief List holding active synchronous action objects.
- */
-static AST_RWLIST_HEAD_STATIC(sync_structs, bridge_sync);
-
-/*!
- * \brief initialize a synchronous bridge object.
- *
- * This both initializes the structure and adds it to the list of
- * synchronization structures.
- *
- * \param sync_struct The synchronization object to initialize.
- * \param id ID to assign to the synchronization object.
- */
-static void bridge_sync_init(struct bridge_sync *sync_struct, unsigned int id)
-{
-	memset(sync_struct, 0, sizeof(*sync_struct));
-	sync_struct->id = id;
-	sem_init(&sync_struct->sem, 0, 0);
-
-	AST_RWLIST_WRLOCK(&sync_structs);
-	AST_RWLIST_INSERT_TAIL(&sync_structs, sync_struct, list);
-	AST_RWLIST_UNLOCK(&sync_structs);
-}
-
-/*!
- * \brief Clean up a syncrhonization bridge object.
- *
- * This frees fields within the synchronization object and removes
- * it from the list of active synchronization objects.
- *
- * Since synchronization objects are stack-allocated, it is vital
- * that this is called before the synchronization object goes
- * out of scope.
- *
- * \param sync_struct Synchronization object to clean up.
- */
-static void bridge_sync_cleanup(struct bridge_sync *sync_struct)
-{
-	struct bridge_sync *iter;
-
-	AST_RWLIST_WRLOCK(&sync_structs);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&sync_structs, iter, list) {
-		if (iter->id == sync_struct->id) {
-			AST_LIST_REMOVE_CURRENT(list);
-			break;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-	AST_RWLIST_UNLOCK(&sync_structs);
-
-	sem_destroy(&sync_struct->sem);
-}
-
-/*!
- * \brief Failsafe for synchronous bridge action waiting.
- *
- * When waiting for a synchronous bridge action to complete,
- * if there is a frame resource leak somewhere, it is possible
- * that we will never get notified that the synchronous action
- * completed.
- *
- * If a significant amount of time passes, then we will abandon
- * waiting for the synchrnous bridge action to complete.
- *
- * This constant represents the number of milliseconds we will
- * wait for the bridge action to complete.
- */
-#define PLAYBACK_TIMEOUT (600 * 1000)
-
-/*!
- * \brief Wait for a synchronous bridge action to complete.
- *
- * \param sync_struct Synchronization object corresponding to the bridge action.
- */
-static void bridge_sync_wait(struct bridge_sync *sync_struct)
-{
-	struct timeval timeout_val = ast_tvadd(ast_tvnow(), ast_samp2tv(PLAYBACK_TIMEOUT, 1000));
-	struct timespec timeout_spec = {
-		.tv_sec = timeout_val.tv_sec,
-		.tv_nsec = timeout_val.tv_usec * 1000,
-	};
-
-	sem_timedwait(&sync_struct->sem, &timeout_spec);
-}
-
-/*!
- * \brief Signal that waiting for a synchronous bridge action is no longer necessary.
- *
- * This may occur for several reasons
- * \li The synchronous bridge action has completed.
- * \li The bridge channel has been removed from the bridge.
- * \li The synchronous bridge action could not be queued.
- *
- * \param sync_struct Synchronization object corresponding to the bridge action.
- */
-static void bridge_sync_signal(struct bridge_sync *sync_struct)
-{
-	sem_post(&sync_struct->sem);
-}
-
-void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge *bridge;
-
-	for (;;) {
-		/* Safely get the bridge pointer */
-		ast_bridge_channel_lock(bridge_channel);
-		bridge = bridge_channel->bridge;
-		ao2_ref(bridge, +1);
-		ast_bridge_channel_unlock(bridge_channel);
-
-		/* Lock the bridge and see if it is still the bridge we need to lock. */
-		ast_bridge_lock(bridge);
-		if (bridge == bridge_channel->bridge) {
-			ao2_ref(bridge, -1);
-			return;
-		}
-		ast_bridge_unlock(bridge);
-		ao2_ref(bridge, -1);
-	}
-}
-
-int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
-{
-	struct ast_frame action = {
-		.frametype = AST_FRAME_BRIDGE_ACTION,
-		.subclass.integer = started_talking
-			? BRIDGE_CHANNEL_ACTION_TALKING_START : BRIDGE_CHANNEL_ACTION_TALKING_STOP,
-	};
-
-	return ast_bridge_channel_queue_frame(bridge_channel, &action);
-}
-
-/*!
- * \internal
- * \brief Poke the bridge_channel thread
- */
-static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel)
-{
-	if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
-		/* Wake up the bridge channel thread. */
-		ast_queue_frame(bridge_channel->chan, &ast_null_frame);
-	}
-}
-
-/*!
- * \internal
- * \brief Set actual cause on channel.
- * \since 12.0.0
- *
- * \param chan Channel to set cause.
- * \param cause Cause to set on channel.
- *   If cause <= 0 then use cause on channel if cause still <= 0 use AST_CAUSE_NORMAL_CLEARING.
- *
- * \return Actual cause set on channel.
- */
-static int channel_set_cause(struct ast_channel *chan, int cause)
-{
-	ast_channel_lock(chan);
-	if (cause <= 0) {
-		cause = ast_channel_hangupcause(chan);
-		if (cause <= 0) {
-			cause = AST_CAUSE_NORMAL_CLEARING;
-		}
-	}
-	ast_channel_hangupcause_set(chan, cause);
-	ast_channel_unlock(chan);
-	return cause;
-}
-
-void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
-{
-	if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-		return;
-	}
-
-	ast_debug(1, "Setting %p(%s) state from:%u to:%u\n",
-		bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state,
-		new_state);
-
-	channel_set_cause(bridge_channel->chan, cause);
-
-	/* Change the state on the bridge channel */
-	bridge_channel->state = new_state;
-
-	bridge_channel_poke(bridge_channel);
-}
-
-void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
-{
-	ast_bridge_channel_lock(bridge_channel);
-	ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state, cause);
-	ast_bridge_channel_unlock(bridge_channel);
-}
-
-struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge *bridge = bridge_channel->bridge;
-	struct ast_bridge_channel *other = NULL;
-
-	if (bridge_channel->in_bridge && bridge->num_channels == 2) {
-		AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-			if (other != bridge_channel) {
-				break;
-			}
-		}
-	}
-
-	return other;
-}
-
-void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
-{
-	ast_assert(bridge_channel->read_format != NULL);
-	ast_assert(bridge_channel->write_format != NULL);
-
-	ast_channel_lock(bridge_channel->chan);
-
-	/* Restore original formats of the channel as they came in */
-	if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_debug(1, "Bridge is returning %p(%s) to read format %s\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(bridge_channel->read_format));
-		if (ast_set_read_format(bridge_channel->chan, bridge_channel->read_format)) {
-			ast_debug(1, "Bridge failed to return %p(%s) to read format %s\n",
-				bridge_channel, ast_channel_name(bridge_channel->chan),
-				ast_format_get_name(bridge_channel->read_format));
-		}
-	}
-	if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), bridge_channel->write_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_debug(1, "Bridge is returning %p(%s) to write format %s\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan),
-			ast_format_get_name(bridge_channel->write_format));
-		if (ast_set_write_format(bridge_channel->chan, bridge_channel->write_format)) {
-			ast_debug(1, "Bridge failed to return %p(%s) to write format %s\n",
-				bridge_channel, ast_channel_name(bridge_channel->chan),
-				ast_format_get_name(bridge_channel->write_format));
-		}
-	}
-
-	ast_channel_unlock(bridge_channel->chan);
-}
-
-struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request)
-{
-	struct ast_bridge *bridge;
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	bridge = bridge_channel->bridge;
-	ao2_ref(bridge, +1);
-	bridge_merge_inhibit_nolock(bridge, request);
-	ast_bridge_unlock(bridge);
-	return bridge;
-}
-
-void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	struct ast_bridge_channel *other;
-	struct ast_bridge *bridge = bridge_channel->bridge;
-	struct ast_channel *oldest_linkedid_chan = bridge_channel->chan;
-
-	AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-		if (other == swap) {
-			continue;
-		}
-		oldest_linkedid_chan = ast_channel_internal_oldest_linkedid(
-			oldest_linkedid_chan, other->chan);
-	}
-
-	ast_channel_lock(bridge_channel->chan);
-	ast_channel_internal_copy_linkedid(bridge_channel->chan, oldest_linkedid_chan);
-	ast_channel_unlock(bridge_channel->chan);
-	AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-		if (other == swap) {
-			continue;
-		}
-		ast_channel_lock(other->chan);
-		ast_channel_internal_copy_linkedid(other->chan, oldest_linkedid_chan);
-		ast_channel_unlock(other->chan);
-	}
-}
-
-/*!
- * \internal
- * \brief Set dest's empty peeraccount with the src's non-empty accountcode.
- * \since 12.5.0
- *
- * \param dest Channel to update peeraccount.
- * \param src Channel to get accountcode from.
- *
- * \note Both channels are already locked.
- *
- * \return Nothing
- */
-static void channel_fill_empty_peeraccount(struct ast_channel *dest, struct ast_channel *src)
-{
-	if (ast_strlen_zero(ast_channel_peeraccount(dest))
-		&& !ast_strlen_zero(ast_channel_accountcode(src))) {
-		ast_debug(1, "Setting channel %s peeraccount with channel %s accountcode '%s'.\n",
-			ast_channel_name(dest),
-			ast_channel_name(src), ast_channel_accountcode(src));
-		ast_channel_peeraccount_set(dest, ast_channel_accountcode(src));
-	}
-}
-
-/*!
- * \internal
- * \brief Set dest's empty accountcode with the src's non-empty peeraccount.
- * \since 12.5.0
- *
- * \param dest Channel to update accountcode.
- * \param src Channel to get peeraccount from.
- *
- * \note Both channels are already locked.
- *
- * \return Nothing
- */
-static void channel_fill_empty_accountcode(struct ast_channel *dest, struct ast_channel *src)
-{
-	if (ast_strlen_zero(ast_channel_accountcode(dest))
-		&& !ast_strlen_zero(ast_channel_peeraccount(src))) {
-		ast_debug(1, "Setting channel %s accountcode with channel %s peeraccount '%s'.\n",
-			ast_channel_name(dest),
-			ast_channel_name(src), ast_channel_peeraccount(src));
-		ast_channel_accountcode_set(dest, ast_channel_peeraccount(src));
-	}
-}
-
-/*!
- * \internal
- * \brief Set empty peeraccount and accountcode in a channel from the other channel.
- * \since 12.5.0
- *
- * \param c0 First bridge channel to update.
- * \param c1 Second bridge channel to update.
- *
- * \note Both channels are already locked.
- *
- * \return Nothing
- */
-static void channel_set_empty_accountcodes(struct ast_channel *c0, struct ast_channel *c1)
-{
-	/* Set empty peeraccount from the other channel's accountcode. */
-	channel_fill_empty_peeraccount(c0, c1);
-	channel_fill_empty_peeraccount(c1, c0);
-
-	/* Set empty accountcode from the other channel's peeraccount. */
-	channel_fill_empty_accountcode(c0, c1);
-	channel_fill_empty_accountcode(c1, c0);
-}
-
-/*!
- * \internal
- * \brief Update dest's peeraccount with the src's different accountcode.
- * \since 12.5.0
- *
- * \param dest Channel to update peeraccount.
- * \param src Channel to get accountcode from.
- *
- * \note Both channels are already locked.
- *
- * \return Nothing
- */
-static void channel_update_peeraccount(struct ast_channel *dest, struct ast_channel *src)
-{
-	if (strcmp(ast_channel_accountcode(src), ast_channel_peeraccount(dest))) {
-		ast_debug(1, "Changing channel %s peeraccount '%s' to match channel %s accountcode '%s'.\n",
-			ast_channel_name(dest), ast_channel_peeraccount(dest),
-			ast_channel_name(src), ast_channel_accountcode(src));
-		ast_channel_peeraccount_set(dest, ast_channel_accountcode(src));
-	}
-}
-
-/*!
- * \internal
- * \brief Update peeraccounts to match the other channel's accountcode.
- * \since 12.5.0
- *
- * \param c0 First channel to update.
- * \param c1 Second channel to update.
- *
- * \note Both channels are already locked.
- *
- * \return Nothing
- */
-static void channel_update_peeraccounts(struct ast_channel *c0, struct ast_channel *c1)
-{
-	channel_update_peeraccount(c0, c1);
-	channel_update_peeraccount(c1, c0);
-}
-
-/*!
- * \internal
- * \brief Update channel accountcodes because a channel is joining a bridge.
- * \since 12.5.0
- *
- * \param joining Channel joining the bridge.
- * \param swap Channel being replaced by the joining channel.  May be NULL.
- *
- * \note The bridge must be locked prior to calling this function.
- *
- * \return Nothing
- */
-static void bridge_channel_update_accountcodes_joining(struct ast_bridge_channel *joining, struct ast_bridge_channel *swap)
-{
-	struct ast_bridge *bridge = joining->bridge;
-	struct ast_bridge_channel *other;
-	unsigned int swap_in_bridge = 0;
-	unsigned int will_be_two_party;
-
-	/*
-	 * Only update the peeraccount to match if the joining channel
-	 * will make it a two party bridge.
-	 */
-	if (bridge->num_channels <= 2 && swap) {
-		AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-			if (other == swap) {
-				swap_in_bridge = 1;
-				break;
-			}
-		}
-	}
-	will_be_two_party = (1 == bridge->num_channels - swap_in_bridge);
-
-	AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-		if (other == swap) {
-			continue;
-		}
-		ast_assert(joining != other);
-		ast_channel_lock_both(joining->chan, other->chan);
-		channel_set_empty_accountcodes(joining->chan, other->chan);
-		if (will_be_two_party) {
-			channel_update_peeraccounts(joining->chan, other->chan);
-		}
-		ast_channel_unlock(joining->chan);
-		ast_channel_unlock(other->chan);
-	}
-}
-
-/*!
- * \internal
- * \brief Update channel peeraccount codes because a channel has left a bridge.
- * \since 12.5.0
- *
- * \param leaving Channel leaving the bridge. (Has already been removed actually)
- *
- * \note The bridge must be locked prior to calling this function.
- *
- * \return Nothing
- */
-static void bridge_channel_update_accountcodes_leaving(struct ast_bridge_channel *leaving)
-{
-	struct ast_bridge *bridge = leaving->bridge;
-	struct ast_bridge_channel *first;
-	struct ast_bridge_channel *second;
-
-	if (bridge->num_channels != 2 || bridge->dissolved) {
-		return;
-	}
-
-	first = AST_LIST_FIRST(&bridge->channels);
-	second = AST_LIST_LAST(&bridge->channels);
-	ast_assert(first && first != second);
-	ast_channel_lock_both(first->chan, second->chan);
-	channel_set_empty_accountcodes(first->chan, second->chan);
-	channel_update_peeraccounts(first->chan, second->chan);
-	ast_channel_unlock(second->chan);
-	ast_channel_unlock(first->chan);
-}
-
-void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *joining, struct ast_bridge_channel *leaving)
-{
-	if (joining) {
-		bridge_channel_update_accountcodes_joining(joining, leaving);
-	} else {
-		bridge_channel_update_accountcodes_leaving(leaving);
-	}
-}
-
-void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int cause)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
-	struct ao2_iterator iter;
-
-	ast_bridge_channel_lock(bridge_channel);
-	if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-		channel_set_cause(bridge_channel->chan, cause);
-		cause = 0;
-	}
-	ast_bridge_channel_unlock(bridge_channel);
-
-	/* Run any hangup hooks. */
-	iter = ao2_iterator_init(features->other_hooks, 0);
-	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
-		int remove_me;
-
-		if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) {
-			continue;
-		}
-		remove_me = hook->callback(bridge_channel, hook->hook_pvt);
-		if (remove_me) {
-			ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n",
-				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			ao2_unlink(features->other_hooks, hook);
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	/* Default hangup action. */
-	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, cause);
-}
-
-/*!
- * \internal
- * \brief Write an \ref ast_frame onto the bridge channel
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param frame The frame to write onto the bridge_channel
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC);
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-/*
- * XXX need to implement a deferred write queue for when there
- * is no peer channel in the bridge (yet or it was kicked).
- *
- * The tech decides if a frame needs to be pushed back for deferral.
- * simple_bridge/native_bridge are likely the only techs that will do this.
- */
-	bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
-
-	/* Remember any owed events to the bridge. */
-	switch (frame->frametype) {
-	case AST_FRAME_DTMF_BEGIN:
-		bridge_channel->owed.dtmf_tv = ast_tvnow();
-		bridge_channel->owed.dtmf_digit = frame->subclass.integer;
-		break;
-	case AST_FRAME_DTMF_END:
-		bridge_channel->owed.dtmf_digit = '\0';
-		break;
-	case AST_FRAME_CONTROL:
-		/*
-		 * We explicitly will not remember HOLD/UNHOLD frames because
-		 * things like attended transfers will handle them.
-		 */
-	default:
-		break;
-	}
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	/*
-	 * Claim successful write to bridge.  If deferred frame
-	 * support is added, claim successfully deferred.
-	 */
-	return 0;
-}
-
-void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel)
-{
-	if (bridge_channel->owed.dtmf_digit) {
-		struct ast_frame frame = {
-			.frametype = AST_FRAME_DTMF_END,
-			.subclass.integer = bridge_channel->owed.dtmf_digit,
-			.src = "Bridge channel owed DTMF",
-		};
-
-		frame.len = ast_tvdiff_ms(ast_tvnow(), bridge_channel->owed.dtmf_tv);
-		if (frame.len < option_dtmfminduration) {
-			frame.len = option_dtmfminduration;
-		}
-		ast_log(LOG_DTMF, "DTMF end '%c' simulated to bridge %s because %s left.  Duration %ld ms.\n",
-			bridge_channel->owed.dtmf_digit, orig_bridge->uniqueid,
-			ast_channel_name(bridge_channel->chan), frame.len);
-		bridge_channel->owed.dtmf_digit = '\0';
-		orig_bridge->technology->write(orig_bridge, NULL, &frame);
-	}
-}
-
-/*!
- * \internal
- * \brief Suspend a channel from a bridge.
- *
- * \param bridge_channel Channel to suspend.
- *
- * \note This function assumes bridge_channel->bridge is locked.
- *
- * \return Nothing
- */
-void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel)
-{
-	bridge_channel->suspended = 1;
-	if (bridge_channel->in_bridge) {
-		--bridge_channel->bridge->num_active;
-	}
-
-	/* Get technology bridge threads off of the channel. */
-	if (bridge_channel->bridge->technology->suspend) {
-		bridge_channel->bridge->technology->suspend(bridge_channel->bridge, bridge_channel);
-	}
-}
-
-/*!
- * \internal
- * \brief Suspend a channel from a bridge.
- *
- * \param bridge_channel Channel to suspend.
- *
- * \return Nothing
- */
-static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel)
-{
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	bridge_channel_internal_suspend_nolock(bridge_channel);
-	ast_bridge_unlock(bridge_channel->bridge);
-}
-
-/*!
- * \internal
- * \brief Unsuspend a channel from a bridge.
- *
- * \param bridge_channel Channel to unsuspend.
- *
- * \note This function assumes bridge_channel->bridge is locked.
- *
- * \return Nothing
- */
-void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel)
-{
-	bridge_channel->suspended = 0;
-	if (bridge_channel->in_bridge) {
-		++bridge_channel->bridge->num_active;
-	}
-
-	/* Wake technology bridge threads to take care of channel again. */
-	if (bridge_channel->bridge->technology->unsuspend) {
-		bridge_channel->bridge->technology->unsuspend(bridge_channel->bridge, bridge_channel);
-	}
-
-	/* Wake suspended channel. */
-	ast_bridge_channel_lock(bridge_channel);
-	ast_cond_signal(&bridge_channel->cond);
-	ast_bridge_channel_unlock(bridge_channel);
-}
-
-/*!
- * \internal
- * \brief Unsuspend a channel from a bridge.
- *
- * \param bridge_channel Channel to unsuspend.
- *
- * \return Nothing
- */
-static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel)
-{
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	bridge_channel_internal_unsuspend_nolock(bridge_channel);
-	ast_bridge_unlock(bridge_channel->bridge);
-}
-
-/*!
- * \internal
- * \brief Queue an action frame onto the bridge channel with data.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param action Type of bridge action frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel,
-	enum bridge_channel_action_type action, const void *data, size_t datalen)
-{
-	struct ast_frame frame = {
-		.frametype = AST_FRAME_BRIDGE_ACTION,
-		.subclass.integer = action,
-		.datalen = datalen,
-		.data.ptr = (void *) data,
-	};
-
-	return ast_bridge_channel_queue_frame(bridge_channel, &frame);
-}
-
-/*!
- * \internal
- * \brief Queue an action frame onto the bridge channel with data synchronously.
- * \since 12.2.0
- *
- * The function will not return until the queued frame is freed.
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param action Type of bridge action frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int bridge_channel_queue_action_data_sync(struct ast_bridge_channel *bridge_channel,
-	enum bridge_channel_action_type action, const void *data, size_t datalen)
-{
-	struct sync_payload *sync_payload;
-	int sync_payload_len = sizeof(*sync_payload) + datalen;
-	struct bridge_sync sync_struct;
-	struct ast_frame frame = {
-		.frametype = AST_FRAME_BRIDGE_ACTION_SYNC,
-		.subclass.integer = action,
-	};
-
-	/* Make sure we don't end up trying to wait on ourself to deliver the frame */
-	ast_assert(!pthread_equal(pthread_self(), bridge_channel->thread));
-
-	sync_payload = ast_alloca(sync_payload_len);
-	sync_payload->id = ast_atomic_fetchadd_int(&sync_ids, +1);
-	memcpy(sync_payload->data, data, datalen);
-
-	frame.datalen = sync_payload_len;
-	frame.data.ptr = sync_payload;
-
-	bridge_sync_init(&sync_struct, sync_payload->id);
-	if (ast_bridge_channel_queue_frame(bridge_channel, &frame)) {
-		bridge_sync_cleanup(&sync_struct);
-		return -1;
-	}
-
-	bridge_sync_wait(&sync_struct);
-	bridge_sync_cleanup(&sync_struct);
-	return 0;
-}
-/*!
- * \internal
- * \brief Write an action frame onto the bridge channel with data.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param action Type of bridge action frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel,
-	enum bridge_channel_action_type action, const void *data, size_t datalen)
-{
-	struct ast_frame frame = {
-		.frametype = AST_FRAME_BRIDGE_ACTION,
-		.subclass.integer = action,
-		.datalen = datalen,
-		.data.ptr = (void *) data,
-	};
-
-	return bridge_channel_write_frame(bridge_channel, &frame);
-}
-
-static void bridge_frame_free(struct ast_frame *frame)
-{
-	if (frame->frametype == AST_FRAME_BRIDGE_ACTION_SYNC) {
-		struct sync_payload *sync_payload = frame->data.ptr;
-		struct bridge_sync *sync;
-
-		AST_RWLIST_RDLOCK(&sync_structs);
-		AST_RWLIST_TRAVERSE(&sync_structs, sync, list) {
-			if (sync->id == sync_payload->id) {
-				break;
-			}
-		}
-		if (sync) {
-			bridge_sync_signal(sync);
-		}
-		AST_RWLIST_UNLOCK(&sync_structs);
-	}
-
-	ast_frfree(frame);
-}
-
-int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
-{
-	struct ast_frame *dup;
-	char nudge = 0;
-
-	if (bridge_channel->suspended
-		/* Also defer DTMF frames. */
-		&& fr->frametype != AST_FRAME_DTMF_BEGIN
-		&& fr->frametype != AST_FRAME_DTMF_END
-		&& !ast_is_deferrable_frame(fr)) {
-		/* Drop non-deferable frames when suspended. */
-		return 0;
-	}
-	if (fr->frametype == AST_FRAME_NULL) {
-		/* "Accept" the frame and discard it. */
-		return 0;
-	}
-
-	dup = ast_frdup(fr);
-	if (!dup) {
-		return -1;
-	}
-
-	ast_bridge_channel_lock(bridge_channel);
-	if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-		/* Drop frames on channels leaving the bridge. */
-		ast_bridge_channel_unlock(bridge_channel);
-		bridge_frame_free(dup);
-		return 0;
-	}
-
-	AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list);
-	if (write(bridge_channel->alert_pipe[1], &nudge, sizeof(nudge)) != sizeof(nudge)) {
-		ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan));
-	}
-	ast_bridge_channel_unlock(bridge_channel);
-	return 0;
-}
-
-int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	struct ast_bridge_channel *cur;
-	int not_written = -1;
-
-	if (frame->frametype == AST_FRAME_NULL) {
-		/* "Accept" the frame and discard it. */
-		return 0;
-	}
-
-	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
-		if (cur == bridge_channel) {
-			continue;
-		}
-		if (!ast_bridge_channel_queue_frame(cur, frame)) {
-			not_written = 0;
-		}
-	}
-	return not_written;
-}
-
-int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
-{
-	struct ast_frame frame = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = control,
-		.datalen = datalen,
-		.data.ptr = (void *) data,
-	};
-
-	return ast_bridge_channel_queue_frame(bridge_channel, &frame);
-}
-
-int ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
-{
-	struct ast_frame frame = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = control,
-		.datalen = datalen,
-		.data.ptr = (void *) data,
-	};
-
-	return bridge_channel_write_frame(bridge_channel, &frame);
-}
-
-int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, const char *moh_class)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	size_t datalen;
-
-	if (!ast_strlen_zero(moh_class)) {
-		datalen = strlen(moh_class) + 1;
-
-		blob = ast_json_pack("{s: s}",
-			"musicclass", moh_class);
-	} else {
-		moh_class = NULL;
-		datalen = 0;
-	}
-
-	ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_hold_type(), blob);
-
-	return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
-		moh_class, datalen);
-}
-
-int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
-{
-	ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL);
-
-	return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
-}
-
-/*!
- * \internal
- * \brief Helper function to kick off a PBX app on a bridge_channel
- */
-static int run_app_helper(struct ast_channel *chan, const char *app_name, const char *app_args)
-{
-	int res = 0;
-
-	if (!strcasecmp("Gosub", app_name)) {
-		ast_app_exec_sub(NULL, chan, app_args, 0);
-	} else if (!strcasecmp("Macro", app_name)) {
-		ast_app_exec_macro(NULL, chan, app_args);
-	} else {
-		struct ast_app *app;
-
-		app = pbx_findapp(app_name);
-		if (!app) {
-			ast_log(LOG_WARNING, "Could not find application (%s)\n", app_name);
-		} else {
-			struct ast_str *substituted_args = ast_str_create(16);
-
-			if (substituted_args) {
-				ast_str_substitute_variables(&substituted_args, 0, chan, app_args);
-				res = pbx_exec(chan, app, ast_str_buffer(substituted_args));
-				ast_free(substituted_args);
-			} else {
-				ast_log(LOG_WARNING, "Could not substitute application argument variables for %s\n", app_name);
-				res = pbx_exec(chan, app, app_args);
-			}
-		}
-	}
-	return res;
-}
-
-void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
-{
-	if (moh_class) {
-		ast_bridge_channel_write_hold(bridge_channel, moh_class);
-	}
-	if (run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""))) {
-		/* Break the bridge if the app returns non-zero. */
-		ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
-	}
-	if (moh_class) {
-		ast_bridge_channel_write_unhold(bridge_channel);
-	}
-}
-
-struct bridge_run_app {
-	/*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH) */
-	int moh_offset;
-	/*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */
-	int app_args_offset;
-	/*! Application name to run. */
-	char app_name[0];
-};
-
-/*!
- * \internal
- * \brief Handle the run application bridge action.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to run the application on.
- * \param data Action frame data to run the application.
- *
- * \return Nothing
- */
-static void bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, struct bridge_run_app *data)
-{
-	ast_bridge_channel_run_app(bridge_channel, data->app_name,
-		data->app_args_offset ? &data->app_name[data->app_args_offset] : NULL,
-		data->moh_offset ? &data->app_name[data->moh_offset] : NULL);
-}
-
-/*!
- * \internal
- * \brief Marshal an application to be executed on a bridge_channel
- */
-static int payload_helper_app(ast_bridge_channel_post_action_data post_it,
-	struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
-{
-	struct bridge_run_app *app_data;
-	size_t len_name = strlen(app_name) + 1;
-	size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1;
-	size_t len_moh = !moh_class ? 0 : strlen(moh_class) + 1;
-	size_t len_data = sizeof(*app_data) + len_name + len_args + len_moh;
-
-	/* Fill in application run frame data. */
-	app_data = alloca(len_data);
-	app_data->app_args_offset = len_args ? len_name : 0;
-	app_data->moh_offset = len_moh ? len_name + len_args : 0;
-	strcpy(app_data->app_name, app_name);/* Safe */
-	if (len_args) {
-		strcpy(&app_data->app_name[app_data->app_args_offset], app_args);/* Safe */
-	}
-	if (moh_class) {
-		strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */
-	}
-
-	return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_RUN_APP, app_data, len_data);
-}
-
-int ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
-{
-	return payload_helper_app(bridge_channel_write_action_data,
-		bridge_channel, app_name, app_args, moh_class);
-}
-
-int ast_bridge_channel_queue_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
-{
-	return payload_helper_app(bridge_channel_queue_action_data,
-		bridge_channel, app_name, app_args, moh_class);
-}
-
-void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
-{
-	if (moh_class) {
-		ast_bridge_channel_write_hold(bridge_channel, moh_class);
-	}
-	if (custom_play) {
-		custom_play(bridge_channel, playfile);
-	} else {
-		ast_stream_and_wait(bridge_channel->chan, playfile, AST_DIGIT_NONE);
-	}
-	if (moh_class) {
-		ast_bridge_channel_write_unhold(bridge_channel);
-	}
-
-	/*
-	 * It may be necessary to resume music on hold after we finish
-	 * playing the announcment.
-	 */
-	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
-		const char *latest_musicclass;
-
-		ast_channel_lock(bridge_channel->chan);
-		latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan));
-		ast_channel_unlock(bridge_channel->chan);
-		ast_moh_start(bridge_channel->chan, latest_musicclass, NULL);
-	}
-}
-
-struct bridge_playfile {
-	/*! Call this function to play the playfile. (NULL if normal sound file to play) */
-	ast_bridge_custom_play_fn custom_play;
-	/*! Offset into playfile[] where the MOH class name starts.  (zero if no MOH)*/
-	int moh_offset;
-	/*! Filename to play. */
-	char playfile[0];
-};
-
-/*!
- * \internal
- * \brief Handle the playfile bridge action.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to play a file on.
- * \param payload Action frame payload to play a file.
- *
- * \return Nothing
- */
-static void bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, struct bridge_playfile *payload)
-{
-	ast_bridge_channel_playfile(bridge_channel, payload->custom_play, payload->playfile,
-		payload->moh_offset ? &payload->playfile[payload->moh_offset] : NULL);
-}
-
-/*!
- * \internal
- * \brief Marshal a file to be played on a bridge_channel
- */
-static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
-	struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
-{
-	struct bridge_playfile *payload;
-	size_t len_name = strlen(playfile) + 1;
-	size_t len_moh = !moh_class ? 0 : strlen(moh_class) + 1;
-	size_t len_payload = sizeof(*payload) + len_name + len_moh;
-
-	/* Fill in play file frame data. */
-	payload = ast_alloca(len_payload);
-	payload->custom_play = custom_play;
-	payload->moh_offset = len_moh ? len_name : 0;
-	strcpy(payload->playfile, playfile);/* Safe */
-	if (moh_class) {
-		strcpy(&payload->playfile[payload->moh_offset], moh_class);/* Safe */
-	}
-
-	return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_PLAY_FILE, payload, len_payload);
-}
-
-int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
-{
-	return payload_helper_playfile(bridge_channel_write_action_data,
-		bridge_channel, custom_play, playfile, moh_class);
-}
-
-int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
-{
-	return payload_helper_playfile(bridge_channel_queue_action_data,
-		bridge_channel, custom_play, playfile, moh_class);
-}
-
-int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel,
-		ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
-{
-	return payload_helper_playfile(bridge_channel_queue_action_data_sync,
-		bridge_channel, custom_play, playfile, moh_class);
-}
-
-struct bridge_custom_callback {
-	/*! Call this function on the bridge channel thread. */
-	ast_bridge_custom_callback_fn callback;
-	/*! Size of the payload if it exists.  A number otherwise. */
-	size_t payload_size;
-	/*! Option flags determining how callback is called. */
-	unsigned int flags;
-	/*! Nonzero if the payload exists. */
-	char payload_exists;
-	/*! Payload to give to callback. */
-	char payload[0];
-};
-
-/*!
- * \internal
- * \brief Handle the do custom callback bridge action.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to call the callback on.
- * \param data Action frame data to call the callback.
- *
- * \return Nothing
- */
-static void bridge_channel_do_callback(struct ast_bridge_channel *bridge_channel, struct bridge_custom_callback *data)
-{
-	if (ast_test_flag(data, AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA)) {
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-	}
-	data->callback(bridge_channel, data->payload_exists ? data->payload : NULL, data->payload_size);
-	if (ast_test_flag(data, AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA)) {
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-	}
-}
-
-/*!
- * \internal
- * \brief Marshal a custom callback function to be called on a bridge_channel
- */
-static int payload_helper_cb(ast_bridge_channel_post_action_data post_it,
-	struct ast_bridge_channel *bridge_channel,
-	enum ast_bridge_channel_custom_callback_option flags,
-	ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
-{
-	struct bridge_custom_callback *cb_data;
-	size_t len_data = sizeof(*cb_data) + (payload ? payload_size : 0);
-
-	/* Sanity check. */
-	if (!callback) {
-		ast_assert(0);
-		return -1;
-	}
-
-	/* Fill in custom callback frame data. */
-	cb_data = alloca(len_data);
-	cb_data->callback = callback;
-	cb_data->payload_size = payload_size;
-	cb_data->flags = flags;
-	cb_data->payload_exists = payload && payload_size;
-	if (cb_data->payload_exists) {
-		memcpy(cb_data->payload, payload, payload_size);/* Safe */
-	}
-
-	return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_CALLBACK, cb_data, len_data);
-}
-
-int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel,
-	enum ast_bridge_channel_custom_callback_option flags,
-	ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
-{
-	return payload_helper_cb(bridge_channel_write_action_data,
-		bridge_channel, flags, callback, payload, payload_size);
-}
-
-int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel,
-	enum ast_bridge_channel_custom_callback_option flags,
-	ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
-{
-	return payload_helper_cb(bridge_channel_queue_action_data,
-		bridge_channel, flags, callback, payload, payload_size);
-}
-
-struct bridge_park {
-	int parker_uuid_offset;
-	int app_data_offset;
-	/* buffer used for holding those strings */
-	char parkee_uuid[0];
-};
-
-/*!
- * \internal
- * \brief Park a bridge_cahnnel
- */
-static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struct bridge_park *payload)
-{
-	if (!ast_parking_provider_registered()) {
-		ast_log(AST_LOG_WARNING, "Unable to park %s: No parking provider loaded!\n",
-			ast_channel_name(bridge_channel->chan));
-		return;
-	}
-
-	if (ast_parking_park_bridge_channel(bridge_channel, payload->parkee_uuid,
-		&payload->parkee_uuid[payload->parker_uuid_offset],
-		payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL)) {
-		ast_log(AST_LOG_WARNING, "Error occurred while parking %s\n",
-			ast_channel_name(bridge_channel->chan));
-	}
-}
-
-/*!
- * \internal
- * \brief Marshal a park action onto a bridge_channel
- */
-static int payload_helper_park(ast_bridge_channel_post_action_data post_it,
-	struct ast_bridge_channel *bridge_channel,
-	const char *parkee_uuid,
-	const char *parker_uuid,
-	const char *app_data)
-{
-	struct bridge_park *payload;
-	size_t len_parkee_uuid = strlen(parkee_uuid) + 1;
-	size_t len_parker_uuid = strlen(parker_uuid) + 1;
-	size_t len_app_data = !app_data ? 0 : strlen(app_data) + 1;
-	size_t len_payload = sizeof(*payload) + len_parker_uuid + len_parkee_uuid + len_app_data;
-
-	payload = alloca(len_payload);
-	payload->app_data_offset = len_app_data ? len_parkee_uuid + len_parker_uuid : 0;
-	payload->parker_uuid_offset = len_parkee_uuid;
-	strcpy(payload->parkee_uuid, parkee_uuid);
-	strcpy(&payload->parkee_uuid[payload->parker_uuid_offset], parker_uuid);
-	if (app_data) {
-		strcpy(&payload->parkee_uuid[payload->app_data_offset], app_data);
-	}
-
-	return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_PARK, payload, len_payload);
-}
-
-int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
-{
-	return payload_helper_park(bridge_channel_write_action_data,
-		bridge_channel, parkee_uuid, parker_uuid, app_data);
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel interval expiration.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to run expired intervals on.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_heap *interval_hooks;
-	struct ast_bridge_hook_timer *hook;
-	struct timeval start;
-	int chan_suspended = 0;
-
-	interval_hooks = bridge_channel->features->interval_hooks;
-	ast_heap_wrlock(interval_hooks);
-	start = ast_tvnow();
-	while ((hook = ast_heap_peek(interval_hooks, 1))) {
-		int interval;
-		unsigned int execution_time;
-
-		if (ast_tvdiff_ms(hook->timer.trip_time, start) > 0) {
-			ast_debug(1, "Hook %p on %p(%s) wants to happen in the future, stopping our traversal\n",
-				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			break;
-		}
-		ao2_ref(hook, +1);
-		ast_heap_unlock(interval_hooks);
-
-		if (!chan_suspended
-			&& ast_test_flag(&hook->timer, AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA)) {
-			chan_suspended = 1;
-			bridge_channel_suspend(bridge_channel);
-			ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		}
-
-		ast_debug(1, "Executing hook %p on %p(%s)\n",
-			hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-		interval = hook->generic.callback(bridge_channel, hook->generic.hook_pvt);
-
-		ast_heap_wrlock(interval_hooks);
-		if (ast_heap_peek(interval_hooks, hook->timer.heap_index) != hook
-			|| !ast_heap_remove(interval_hooks, hook)) {
-			/* Interval hook is already removed from the bridge_channel. */
-			ao2_ref(hook, -1);
-			continue;
-		}
-		ao2_ref(hook, -1);
-
-		if (interval < 0) {
-			ast_debug(1, "Removed interval hook %p from %p(%s)\n",
-				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			ao2_ref(hook, -1);
-			continue;
-		}
-		if (interval) {
-			/* Set new interval for the hook. */
-			hook->timer.interval = interval;
-		}
-
-		ast_debug(1, "Updating interval hook %p with interval %u on %p(%s)\n",
-			hook, hook->timer.interval, bridge_channel,
-			ast_channel_name(bridge_channel->chan));
-
-		/* resetting start */
-		start = ast_tvnow();
-
-		/*
-		 * Resetup the interval hook for the next interval.  We may need
-		 * to skip over any missed intervals because the hook was
-		 * delayed or took too long.
-		 */
-		execution_time = ast_tvdiff_ms(start, hook->timer.trip_time);
-		while (hook->timer.interval < execution_time) {
-			execution_time -= hook->timer.interval;
-		}
-		hook->timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->timer.interval - execution_time, 1000));
-		hook->timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1);
-
-		if (ast_heap_push(interval_hooks, hook)) {
-			/* Could not push the hook back onto the heap. */
-			ao2_ref(hook, -1);
-		}
-	}
-	ast_heap_unlock(interval_hooks);
-
-	if (chan_suspended) {
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-	}
-}
-
-/*!
- * \internal
- * \brief Write a DTMF stream out to a channel
- */
-static int bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
-{
-	return bridge_channel_write_action_data(bridge_channel,
-		BRIDGE_CHANNEL_ACTION_DTMF_STREAM, dtmf, strlen(dtmf) + 1);
-}
-
-/*!
- * \internal
- * \brief Indicate to the testsuite a feature was successfully detected.
- *
- * Currently, this function only will relay built-in features to the testsuite,
- * but it could be modified to detect applicationmap items should the need arise.
- *
- * \param chan The channel that activated the feature
- * \param dtmf The DTMF sequence entered to activate the feature
- */
-static void testsuite_notify_feature_success(struct ast_channel *chan, const char *dtmf)
-{
-#ifdef TEST_FRAMEWORK
-	char *feature = "unknown";
-	struct ast_featuremap_config *featuremap = ast_get_chan_featuremap_config(chan);
-	struct ast_features_xfer_config *xfer = ast_get_chan_features_xfer_config(chan);
-
-	if (featuremap) {
-		if (!strcmp(dtmf, featuremap->blindxfer)) {
-			feature = "blindxfer";
-		} else if (!strcmp(dtmf, featuremap->atxfer)) {
-			feature = "atxfer";
-		} else if (!strcmp(dtmf, featuremap->disconnect)) {
-			feature = "disconnect";
-		} else if (!strcmp(dtmf, featuremap->automon)) {
-			feature = "automon";
-		} else if (!strcmp(dtmf, featuremap->automixmon)) {
-			feature = "automixmon";
-		} else if (!strcmp(dtmf, featuremap->parkcall)) {
-			feature = "parkcall";
-		}
-	}
-	if (xfer) {
-		if (!strcmp(dtmf, xfer->atxferthreeway)) {
-			feature = "atxferthreeway";
-		}
-	}
-
-	ao2_cleanup(featuremap);
-	ao2_cleanup(xfer);
-
-	ast_test_suite_event_notify("FEATURE_DETECTION",
-			"Result: success\r\n"
-			"Feature: %s", feature);
-#endif /* TEST_FRAMEWORK */
-}
-
-void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, int digit)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook_dtmf *hook = NULL;
-	size_t dtmf_len;
-
-	struct sanity_check_of_dtmf_size {
-		char check[1 / (ARRAY_LEN(bridge_channel->dtmf_hook_state.collected) == ARRAY_LEN(hook->dtmf.code))];
-	};
-
-	dtmf_len = strlen(bridge_channel->dtmf_hook_state.collected);
-	if (!dtmf_len && !digit) {
-		/* Nothing to do */
-		return;
-	}
-
-	if (digit) {
-		/* There should always be room for the new digit. */
-		ast_assert(dtmf_len < ARRAY_LEN(bridge_channel->dtmf_hook_state.collected) - 1);
-
-		/* Add the new digit to the DTMF string so we can do our matching */
-		bridge_channel->dtmf_hook_state.collected[dtmf_len++] = digit;
-		bridge_channel->dtmf_hook_state.collected[dtmf_len] = '\0';
-
-		ast_debug(1, "DTMF feature string on %p(%s) is now '%s'\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan),
-			bridge_channel->dtmf_hook_state.collected);
-
-		/* See if a DTMF feature hook matches or can match */
-		hook = ao2_find(features->dtmf_hooks, bridge_channel->dtmf_hook_state.collected,
-			OBJ_SEARCH_PARTIAL_KEY);
-		if (!hook) {
-			ast_debug(1, "No DTMF feature hooks on %p(%s) match '%s'\n",
-				bridge_channel, ast_channel_name(bridge_channel->chan),
-				bridge_channel->dtmf_hook_state.collected);
-		} else if (dtmf_len != strlen(hook->dtmf.code)) {
-			unsigned int digit_timeout;
-			struct ast_features_general_config *gen_cfg;
-
-			/* Need more digits to match */
-			ao2_ref(hook, -1);
-
-			/* Determine interdigit timeout */
-			ast_channel_lock(bridge_channel->chan);
-			gen_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
-			ast_channel_unlock(bridge_channel->chan);
-			if (!gen_cfg) {
-				ast_log(LOG_ERROR, "Unable to retrieve features configuration.\n");
-				digit_timeout = 3000; /* Pick a reasonable failsafe timeout in ms */
-			} else {
-				digit_timeout = gen_cfg->featuredigittimeout;
-				ao2_ref(gen_cfg, -1);
-			}
-
-			bridge_channel->dtmf_hook_state.interdigit_timeout =
-				ast_tvadd(ast_tvnow(), ast_samp2tv(digit_timeout, 1000));
-			return;
-		} else {
-			int remove_me;
-			int already_suspended;
-
-			ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on %p(%s)\n",
-				hook, bridge_channel->dtmf_hook_state.collected, bridge_channel,
-				ast_channel_name(bridge_channel->chan));
-
-			/*
-			 * Clear the collected digits before executing the hook
-			 * in case the hook starts another sequence.
-			 */
-			bridge_channel->dtmf_hook_state.collected[0] = '\0';
-
-			ast_bridge_channel_lock_bridge(bridge_channel);
-			already_suspended = bridge_channel->suspended;
-			if (!already_suspended) {
-				bridge_channel_internal_suspend_nolock(bridge_channel);
-			}
-			ast_bridge_unlock(bridge_channel->bridge);
-			ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-
-			/* Execute the matched hook on this channel. */
-			remove_me = hook->generic.callback(bridge_channel, hook->generic.hook_pvt);
-			if (remove_me) {
-				ast_debug(1, "DTMF hook %p is being removed from %p(%s)\n",
-					hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-				ao2_unlink(features->dtmf_hooks, hook);
-			}
-			testsuite_notify_feature_success(bridge_channel->chan, hook->dtmf.code);
-			ao2_ref(hook, -1);
-
-			ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-			if (!already_suspended) {
-				bridge_channel_unsuspend(bridge_channel);
-			}
-
-			/*
-			 * If we are handing the channel off to an external hook for
-			 * ownership, we are not guaranteed what kind of state it will
-			 * come back in.  If the channel hungup, we need to detect that
-			 * here if the hook did not already change the state.
-			 */
-			if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
-				ast_bridge_channel_kick(bridge_channel, 0);
-			}
-			return;
-		}
-	} else {
-		ast_debug(1, "DTMF feature string collection on %p(%s) timed out\n",
-			bridge_channel, ast_channel_name(bridge_channel->chan));
-	}
-
-	/* Timeout or DTMF digit didn't allow a match with any hooks. */
-	if (features->dtmf_passthrough) {
-		/* Stream the collected DTMF to the other channels. */
-		bridge_channel_write_dtmf_stream(bridge_channel,
-			bridge_channel->dtmf_hook_state.collected);
-	}
-	bridge_channel->dtmf_hook_state.collected[0] = '\0';
-
-	ast_test_suite_event_notify("FEATURE_DETECTION", "Result: fail");
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel DTMF feature timeout expiration.
- * \since 12.8.0
- *
- * \param bridge_channel Channel to check expired interdigit timer on.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_feature_timeout(struct ast_bridge_channel *bridge_channel)
-{
-	if (!bridge_channel->dtmf_hook_state.collected[0]
-		|| 0 < ast_tvdiff_ms(bridge_channel->dtmf_hook_state.interdigit_timeout,
-			ast_tvnow())) {
-		/* Not within a sequence or not timed out. */
-		return;
-	}
-
-	ast_bridge_channel_feature_digit(bridge_channel, 0);
-}
-
-/*!
- * \internal
- * \brief Indicate that a bridge_channel is talking
- */
-static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
-	struct ao2_iterator iter;
-
-	/* Run any talk detection hooks. */
-	iter = ao2_iterator_init(features->other_hooks, 0);
-	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
-		int remove_me;
-		ast_bridge_talking_indicate_callback talk_cb;
-
-		if (hook->type != AST_BRIDGE_HOOK_TYPE_TALK) {
-			continue;
-		}
-		talk_cb = (ast_bridge_talking_indicate_callback) hook->callback;
-		remove_me = talk_cb(bridge_channel, hook->hook_pvt, talking);
-		if (remove_me) {
-			ast_debug(1, "Talk detection hook %p is being removed from %p(%s)\n",
-				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			ao2_unlink(features->other_hooks, hook);
-		}
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-/*! \brief Internal function that plays back DTMF on a bridge channel */
-static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
-{
-	ast_debug(1, "Playing DTMF stream '%s' out to %p(%s)\n",
-		dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
-	ast_dtmf_stream(bridge_channel->chan, NULL, dtmf, 0, 0);
-}
-
-/*! \brief Data specifying where a blind transfer is going to */
-struct blind_transfer_data {
-	char exten[AST_MAX_EXTENSION];
-	char context[AST_MAX_CONTEXT];
-};
-
-/*!
- * \internal
- * \brief Execute after bridge actions on a channel when it leaves a bridge
- */
-static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *data)
-{
-	RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
-	struct ast_party_connected_line connected_target;
-	unsigned char connected_line_data[1024];
-	int payload_size;
-
-	ast_party_connected_line_init(&connected_target);
-
-	ast_channel_lock(chan_target);
-	ast_party_connected_line_copy(&connected_target, ast_channel_connected(chan_target));
-	ast_channel_unlock(chan_target);
-	ast_party_id_reset(&connected_target.priv);
-
-	if (ast_channel_move(chan_target, chan_bridged)) {
-		ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
-		ast_party_connected_line_free(&connected_target);
-		return;
-	}
-
-	if ((payload_size = ast_connected_line_build_data(connected_line_data,
-		sizeof(connected_line_data), &connected_target, NULL)) != -1) {
-		struct ast_control_read_action_payload *frame_payload;
-		int frame_size;
-
-		frame_size = payload_size + sizeof(*frame_payload);
-		frame_payload = ast_alloca(frame_size);
-		frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
-		frame_payload->payload_size = payload_size;
-		memcpy(frame_payload->payload, connected_line_data, payload_size);
-		ast_queue_control_data(chan_target, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
-	}
-
-	ast_party_connected_line_free(&connected_target);
-}
-
-/*!
- * \internal
- * \brief Execute logic to cleanup when after bridge fails
- */
-static void after_bridge_move_channel_fail(enum ast_bridge_after_cb_reason reason, void *data)
-{
-	RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
-
-	ast_log(LOG_WARNING, "Unable to complete transfer: %s\n",
-		ast_bridge_after_cb_reason_string(reason));
-	ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
-}
-
-/*!
- * \internal
- * \brief Perform a blind transfer on a channel in a bridge
- */
-static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_channel,
-		struct blind_transfer_data *blind_data)
-{
-	ast_async_goto(bridge_channel->chan, blind_data->context, blind_data->exten, 1);
-	ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
-}
-
-/*!
- * \internal
- * \brief Perform an attended transfer on a channel in a bridge
- */
-static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_channel,
-		const char *target_chan_name)
-{
-	RAII_VAR(struct ast_channel *, chan_target, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_bridged, NULL, ao2_cleanup);
-
-	chan_target = ast_channel_get_by_name(target_chan_name);
-	if (!chan_target) {
-		/* Dang, it disappeared somehow */
-		ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
-		return;
-	}
-
-	ast_bridge_channel_lock(bridge_channel);
-	chan_bridged = bridge_channel->chan;
-	ast_assert(chan_bridged != NULL);
-	ao2_ref(chan_bridged, +1);
-	ast_bridge_channel_unlock(bridge_channel);
-
-	if (ast_bridge_set_after_callback(chan_bridged, after_bridge_move_channel,
-		after_bridge_move_channel_fail, ast_channel_ref(chan_target))) {
-		ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
-
-		/* Release the ref we tried to pass to ast_bridge_set_after_callback(). */
-		ast_channel_unref(chan_target);
-	}
-	ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel bridge action frame.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to execute the action on.
- * \param action What to do.
- * \param data data from the action.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel,
-	enum bridge_channel_action_type action, void *data)
-{
-	switch (action) {
-	case BRIDGE_CHANNEL_ACTION_DTMF_STREAM:
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_dtmf_stream(bridge_channel, data);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-		break;
-	case BRIDGE_CHANNEL_ACTION_TALKING_START:
-	case BRIDGE_CHANNEL_ACTION_TALKING_STOP:
-		bridge_channel_talking(bridge_channel,
-			action == BRIDGE_CHANNEL_ACTION_TALKING_START);
-		break;
-	case BRIDGE_CHANNEL_ACTION_PLAY_FILE:
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_playfile(bridge_channel, data);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-		break;
-	case BRIDGE_CHANNEL_ACTION_RUN_APP:
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_run_app(bridge_channel, data);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-		break;
-	case BRIDGE_CHANNEL_ACTION_CALLBACK:
-		bridge_channel_do_callback(bridge_channel, data);
-		break;
-	case BRIDGE_CHANNEL_ACTION_PARK:
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_park(bridge_channel, data);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-		break;
-	case BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER:
-		bridge_channel_blind_transfer(bridge_channel, data);
-		break;
-	case BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER:
-		bridge_channel_attended_transfer(bridge_channel, data);
-		break;
-	default:
-		break;
-	}
-}
-
-/*!
- * \internal
- * \brief Check if a bridge should dissolve and do it.
- * \since 12.0.0
- *
- * \param bridge_channel Channel causing the check.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \return Nothing
- */
-static void bridge_channel_dissolve_check(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge *bridge = bridge_channel->bridge;
-
-	if (bridge->dissolved) {
-		return;
-	}
-
-	if (!bridge->num_channels
-		&& ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY)) {
-		/* Last channel leaving the bridge turns off the lights. */
-		bridge_dissolve(bridge, ast_channel_hangupcause(bridge_channel->chan));
-		return;
-	}
-
-	switch (bridge_channel->state) {
-	case BRIDGE_CHANNEL_STATE_END:
-		/* Do we need to dissolve the bridge because this channel hung up? */
-		if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)
-			|| (bridge_channel->features->usable
-				&& ast_test_flag(&bridge_channel->features->feature_flags,
-					AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP))) {
-			bridge_dissolve(bridge, ast_channel_hangupcause(bridge_channel->chan));
-			return;
-		}
-		break;
-	default:
-		break;
-	}
-
-	if (bridge->num_lonely && bridge->num_lonely == bridge->num_channels) {
-		/*
-		 * This will start a chain reaction where each channel leaving
-		 * enters this function and causes the next to leave as long as
-		 * there aren't non-lonely channels in the bridge.
-		 */
-		ast_bridge_channel_leave_bridge(AST_LIST_FIRST(&bridge->channels),
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
-			ast_channel_hangupcause(bridge_channel->chan));
-	}
-}
-
-void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge *bridge = bridge_channel->bridge;
-
-	if (!bridge_channel->in_bridge) {
-		return;
-	}
-	bridge_channel->in_bridge = 0;
-
-	ast_debug(1, "Bridge %s: pulling %p(%s)\n",
-		bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
-
-	ast_verb(3, "Channel %s left '%s' %s-bridge <%s>\n",
-		ast_channel_name(bridge_channel->chan),
-		bridge->technology->name,
-		bridge->v_table->name,
-		bridge->uniqueid);
-
-	if (!bridge_channel->just_joined) {
-		/* Tell the bridge technology we are leaving so they tear us down */
-		ast_debug(1, "Bridge %s: %p(%s) is leaving %s technology\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
-			bridge->technology->name);
-		if (bridge->technology->leave) {
-			bridge->technology->leave(bridge, bridge_channel);
-		}
-	}
-
-	/* Remove channel from the bridge */
-	if (!bridge_channel->suspended) {
-		--bridge->num_active;
-	}
-	if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-		--bridge->num_lonely;
-	}
-	--bridge->num_channels;
-	AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
-
-	bridge_channel_dissolve_check(bridge_channel);
-	bridge->v_table->pull(bridge, bridge_channel);
-
-	ast_bridge_channel_clear_roles(bridge_channel);
-
-	/* If we are not going to be hung up after leaving a bridge, and we were an
-	 * outgoing channel, clear the outgoing flag.
-	 */
-	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING)
-	    && (ast_channel_is_leaving_bridge(bridge_channel->chan)
-	        || bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT)) {
-		ast_debug(2, "Channel %s will survive this bridge; clearing outgoing (dialed) flag\n", ast_channel_name(bridge_channel->chan));
-		ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING);
-	}
-
-	bridge->reconfigured = 1;
-	ast_bridge_publish_leave(bridge, bridge_channel->chan);
-}
-
-int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge *bridge = bridge_channel->bridge;
-	struct ast_bridge_channel *swap;
-
-	ast_assert(!bridge_channel->in_bridge);
-
-	swap = bridge_find_channel(bridge, bridge_channel->swap);
-	bridge_channel->swap = NULL;
-
-	if (swap) {
-		ast_debug(1, "Bridge %s: pushing %p(%s) by swapping with %p(%s)\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
-			swap, ast_channel_name(swap->chan));
-	} else {
-		ast_debug(1, "Bridge %s: pushing %p(%s)\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
-	}
-
-	/* Add channel to the bridge */
-	if (bridge->dissolved
-		|| bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
-		|| (swap && swap->state != BRIDGE_CHANNEL_STATE_WAIT)
-		|| bridge->v_table->push(bridge, bridge_channel, swap)
-		|| ast_bridge_channel_establish_roles(bridge_channel)) {
-		ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n",
-			bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
-		return -1;
-	}
-	bridge_channel->in_bridge = 1;
-	bridge_channel->just_joined = 1;
-	AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, entry);
-	++bridge->num_channels;
-	if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-		++bridge->num_lonely;
-	}
-	if (!bridge_channel->suspended) {
-		++bridge->num_active;
-	}
-
-	ast_verb(3, "Channel %s %s%s%s '%s' %s-bridge <%s>\n",
-		ast_channel_name(bridge_channel->chan),
-		swap ? "swapped with " : "joined",
-		swap ? ast_channel_name(swap->chan) : "",
-		swap ? " into" : "",
-		bridge->technology->name,
-		bridge->v_table->name,
-		bridge->uniqueid);
-
-	ast_bridge_publish_enter(bridge, bridge_channel->chan, swap ? swap->chan : NULL);
-	if (swap) {
-		ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0);
-		bridge_channel_internal_pull(swap);
-	}
-
-	/* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */
-	pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL);
-	pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL);
-
-	/* Wake up the bridge channel thread to reevaluate any interval timers. */
-	ast_queue_frame(bridge_channel->chan, &ast_null_frame);
-
-	bridge->reconfigured = 1;
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel control frame action.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to execute the control frame action on.
- * \param fr Control frame to handle.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
-{
-	struct ast_channel *chan;
-	struct ast_option_header *aoh;
-	int is_caller;
-
-	chan = bridge_channel->chan;
-	switch (fr->subclass.integer) {
-	case AST_CONTROL_REDIRECTING:
-		is_caller = !ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
-		if (ast_channel_redirecting_sub(NULL, chan, fr, 1) &&
-			ast_channel_redirecting_macro(NULL, chan, fr, is_caller, 1)) {
-			ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
-		}
-		break;
-	case AST_CONTROL_CONNECTED_LINE:
-		is_caller = !ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
-		if (ast_channel_connected_line_sub(NULL, chan, fr, 1) &&
-			ast_channel_connected_line_macro(NULL, chan, fr, is_caller, 1)) {
-			ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
-		}
-		break;
-	case AST_CONTROL_OPTION:
-		/*
-		 * Forward option Requests, but only ones we know are safe These
-		 * are ONLY sent by chan_iax2 and I'm not convinced that they
-		 * are useful. I haven't deleted them entirely because I just am
-		 * not sure of the ramifications of removing them.
-		 */
-		aoh = fr->data.ptr;
-		if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
-			switch (ntohs(aoh->option)) {
-			case AST_OPTION_TONE_VERIFY:
-			case AST_OPTION_TDD:
-			case AST_OPTION_RELAXDTMF:
-			case AST_OPTION_AUDIO_MODE:
-			case AST_OPTION_DIGIT_DETECT:
-			case AST_OPTION_FAX_DETECT:
-				ast_channel_setoption(chan, ntohs(aoh->option), aoh->data,
-					fr->datalen - sizeof(*aoh), 0);
-				break;
-			default:
-				break;
-			}
-		}
-		break;
-	case AST_CONTROL_ANSWER:
-		if (ast_channel_state(chan) != AST_STATE_UP) {
-			ast_answer(chan);
-		} else {
-			ast_indicate(chan, -1);
-		}
-		break;
-	case AST_CONTROL_MASQUERADE_NOTIFY:
-		/* Should never happen. */
-		ast_assert(0);
-		break;
-	default:
-		ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
-		break;
-	}
-}
-
-/*!
- * \internal
- * \param bridge_channel Channel to read wr_queue alert pipe.
- *
- * \return Nothing
- */
-static void bridge_channel_read_wr_queue_alert(struct ast_bridge_channel *bridge_channel)
-{
-	char nudge;
-
-	if (read(bridge_channel->alert_pipe[0], &nudge, sizeof(nudge)) < 0) {
-		if (errno != EINTR && errno != EAGAIN) {
-			ast_log(LOG_WARNING, "read() failed for alert pipe on %p(%s): %s\n",
-				bridge_channel, ast_channel_name(bridge_channel->chan),
-				strerror(errno));
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel write frame to channel.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to write outgoing frame.
- *
- * \return Nothing
- */
-static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_frame *fr;
-	struct sync_payload *sync_payload;
-
-	ast_bridge_channel_lock(bridge_channel);
-
-	/* It's not good to have unbalanced frames and alert_pipe alerts. */
-	ast_assert(!AST_LIST_EMPTY(&bridge_channel->wr_queue));
-	if (AST_LIST_EMPTY(&bridge_channel->wr_queue)) {
-		/* No frame, flush the alert pipe of excess alerts. */
-		ast_log(LOG_WARNING, "Weird.  No frame from bridge for %s to process?\n",
-			ast_channel_name(bridge_channel->chan));
-		bridge_channel_read_wr_queue_alert(bridge_channel);
-		ast_bridge_channel_unlock(bridge_channel);
-		return;
-	}
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&bridge_channel->wr_queue, fr, frame_list) {
-		if (bridge_channel->dtmf_hook_state.collected[0]) {
-			switch (fr->frametype) {
-			case AST_FRAME_BRIDGE_ACTION:
-			case AST_FRAME_BRIDGE_ACTION_SYNC:
-				/* Defer processing these frames while DTMF is collected. */
-				continue;
-			default:
-				break;
-			}
-		}
-		bridge_channel_read_wr_queue_alert(bridge_channel);
-		AST_LIST_REMOVE_CURRENT(frame_list);
-		break;
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	ast_bridge_channel_unlock(bridge_channel);
-	if (!fr) {
-		/*
-		 * Wait some to reduce CPU usage from a tight loop
-		 * without any wait because we only have deferred
-		 * frames in the wr_queue.
-		 */
-		usleep(1);
-		return;
-	}
-
-	switch (fr->frametype) {
-	case AST_FRAME_BRIDGE_ACTION:
-		bridge_channel_handle_action(bridge_channel, fr->subclass.integer, fr->data.ptr);
-		break;
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
-		sync_payload = fr->data.ptr;
-		bridge_channel_handle_action(bridge_channel, fr->subclass.integer, sync_payload->data);
-		break;
-	case AST_FRAME_CONTROL:
-		bridge_channel_handle_control(bridge_channel, fr);
-		break;
-	case AST_FRAME_NULL:
-		break;
-	default:
-		/* Write the frame to the channel. */
-		bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE;
-		ast_write(bridge_channel->chan, fr);
-		break;
-	}
-	bridge_frame_free(fr);
-}
-
-/*! \brief Internal function to handle DTMF from a channel */
-static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook_dtmf *hook = NULL;
-	char dtmf[2];
-
-	/*
-	 * See if we are already matching a DTMF feature hook sequence or
-	 * if this DTMF matches the beginning of any DTMF feature hooks.
-	 */
-	dtmf[0] = frame->subclass.integer;
-	dtmf[1] = '\0';
-	if (bridge_channel->dtmf_hook_state.collected[0]
-		|| (hook = ao2_find(features->dtmf_hooks, dtmf, OBJ_SEARCH_PARTIAL_KEY))) {
-		enum ast_frame_type frametype = frame->frametype;
-
-		bridge_frame_free(frame);
-		frame = NULL;
-
-		ao2_cleanup(hook);
-
-		switch (frametype) {
-		case AST_FRAME_DTMF_BEGIN:
-			/* Just eat the frame. */
-			break;
-		case AST_FRAME_DTMF_END:
-			ast_bridge_channel_feature_digit(bridge_channel, dtmf[0]);
-			break;
-		default:
-			/* Unexpected frame type. */
-			ast_assert(0);
-			break;
-		}
-#ifdef TEST_FRAMEWORK
-	} else if (frame->frametype == AST_FRAME_DTMF_END) {
-		/* Only transmit this event on DTMF end or else every DTMF
-		 * press will result in the event being broadcast twice
-		 */
-		ast_test_suite_event_notify("FEATURE_DETECTION", "Result: fail");
-#endif
-	}
-
-	return frame;
-}
-
-
-/*!
- * \internal
- * \brief Feed notification that a frame is waiting on a channel into the bridging core
- *
- * \param bridge_channel Bridge channel the notification was received on
- */
-static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_frame *frame;
-
-	if (bridge_channel->features->mute) {
-		frame = ast_read_noaudio(bridge_channel->chan);
-	} else {
-		frame = ast_read(bridge_channel->chan);
-	}
-
-	if (!frame) {
-		ast_bridge_channel_kick(bridge_channel, 0);
-		return;
-	}
-	switch (frame->frametype) {
-	case AST_FRAME_CONTROL:
-		switch (frame->subclass.integer) {
-		case AST_CONTROL_HANGUP:
-			ast_bridge_channel_kick(bridge_channel, 0);
-			bridge_frame_free(frame);
-			return;
-		default:
-			break;
-		}
-		break;
-	case AST_FRAME_DTMF_BEGIN:
-	case AST_FRAME_DTMF_END:
-		frame = bridge_handle_dtmf(bridge_channel, frame);
-		if (!frame) {
-			return;
-		}
-		if (!bridge_channel->features->dtmf_passthrough) {
-			bridge_frame_free(frame);
-			return;
-		}
-		break;
-	default:
-		break;
-	}
-
-	/* Simply write the frame out to the bridge technology. */
-	bridge_channel_write_frame(bridge_channel, frame);
-	bridge_frame_free(frame);
-}
-
-/*!
- * \internal
- * \brief Determine how long till the next timer interval.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to determine how long can wait.
- *
- * \retval ms Number of milliseconds to wait.
- * \retval -1 to wait forever.
- */
-static int bridge_channel_next_interval(struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_heap *interval_hooks = bridge_channel->features->interval_hooks;
-	struct ast_bridge_hook_timer *hook;
-	int ms;
-
-	ast_heap_wrlock(interval_hooks);
-	hook = ast_heap_peek(interval_hooks, 1);
-	if (hook) {
-		ms = ast_tvdiff_ms(hook->timer.trip_time, ast_tvnow());
-		if (ms < 0) {
-			/* Expire immediately.  An interval hook is ready to run. */
-			ms = 0;
-		}
-	} else {
-		/* No hook so wait forever. */
-		ms = -1;
-	}
-	ast_heap_unlock(interval_hooks);
-
-	return ms;
-}
-
-/*!
- * \internal
- * \brief Determine how long till the DTMF interdigit timeout.
- * \since 12.8.0
- *
- * \param bridge_channel Channel to determine how long can wait.
- *
- * \retval ms Number of milliseconds to wait.
- * \retval -1 to wait forever.
- */
-static int bridge_channel_feature_timeout(struct ast_bridge_channel *bridge_channel)
-{
-	int ms;
-
-	if (bridge_channel->dtmf_hook_state.collected[0]) {
-		ms = ast_tvdiff_ms(bridge_channel->dtmf_hook_state.interdigit_timeout,
-			ast_tvnow());
-		if (ms < 0) {
-			/* Expire immediately. */
-			ms = 0;
-		}
-	} else {
-		/* Timer is not active so wait forever. */
-		ms = -1;
-	}
-
-	return ms;
-}
-
-/*!
- * \internal
- * \brief Determine how long till a timeout.
- * \since 12.8.0
- *
- * \param bridge_channel Channel to determine how long can wait.
- *
- * \retval ms Number of milliseconds to wait.
- * \retval -1 to wait forever.
- */
-static int bridge_channel_next_timeout(struct ast_bridge_channel *bridge_channel)
-{
-	int ms_interval;
-	int ms;
-
-	ms_interval = bridge_channel_next_interval(bridge_channel);
-	ms = bridge_channel_feature_timeout(bridge_channel);
-	if (ms < 0 || (0 <= ms_interval && ms_interval < ms)) {
-		/* Interval hook timeout is next. */
-		ms = ms_interval;
-	}
-
-	return ms;
-}
-
-/*!
- * \internal
- * \brief Wait for something to happen on the bridge channel and handle it.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to wait.
- *
- * \note Each channel does writing/reading in their own thread.
- *
- * \return Nothing
- */
-static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
-{
-	int ms;
-	int outfd;
-	struct ast_channel *chan;
-
-	/* Wait for data to either come from the channel or us to be signaled */
-	ast_bridge_channel_lock(bridge_channel);
-	if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-	} else if (bridge_channel->suspended) {
-/* XXX ASTERISK-21271 the external party use of suspended will go away as will these references because this is the bridge channel thread */
-		ast_debug(1, "Bridge %s: %p(%s) is going into a signal wait\n",
-			bridge_channel->bridge->uniqueid, bridge_channel,
-			ast_channel_name(bridge_channel->chan));
-		ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
-	} else {
-		ast_bridge_channel_unlock(bridge_channel);
-		outfd = -1;
-		ms = bridge_channel_next_timeout(bridge_channel);
-		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1,
-			&bridge_channel->alert_pipe[0], 1, NULL, &outfd, &ms);
-		if (ast_channel_unbridged(bridge_channel->chan)) {
-			ast_channel_set_unbridged(bridge_channel->chan, 0);
-			ast_bridge_channel_lock_bridge(bridge_channel);
-			bridge_channel->bridge->reconfigured = 1;
-			bridge_reconfigured(bridge_channel->bridge, 0);
-			ast_bridge_unlock(bridge_channel->bridge);
-		}
-		ast_bridge_channel_lock(bridge_channel);
-		bridge_channel->activity = BRIDGE_CHANNEL_THREAD_FRAME;
-		ast_bridge_channel_unlock(bridge_channel);
-		if (!bridge_channel->suspended
-			&& bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-			if (chan) {
-				bridge_handle_trip(bridge_channel);
-			} else if (ms == 0) {
-				/* An interdigit timeout or interval expired. */
-				bridge_channel_handle_feature_timeout(bridge_channel);
-				bridge_channel_handle_interval(bridge_channel);
-			} else if (-1 < outfd) {
-				/*
-				 * Must do this after checking timeouts or may have
-				 * an infinite loop due to deferring write queue
-				 * actions while trying to match DTMF feature hooks.
-				 */
-				bridge_channel_handle_write(bridge_channel);
-			}
-		}
-		bridge_channel->activity = BRIDGE_CHANNEL_THREAD_IDLE;
-		return;
-	}
-	ast_bridge_channel_unlock(bridge_channel);
-}
-
-/*!
- * \internal
- * \brief Handle bridge channel join/leave event.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel is involved.
- * \param type Specified join/leave event.
- *
- * \return Nothing
- */
-static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_channel, enum ast_bridge_hook_type type)
-{
-	struct ast_bridge_features *features = bridge_channel->features;
-	struct ast_bridge_hook *hook;
-	struct ao2_iterator iter;
-
-	/* Run the specified hooks. */
-	iter = ao2_iterator_init(features->other_hooks, 0);
-	for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
-		if (hook->type == type) {
-			break;
-		}
-	}
-	if (hook) {
-		/* Found the first specified hook to run. */
-		bridge_channel_suspend(bridge_channel);
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		do {
-			if (hook->type == type) {
-				hook->callback(bridge_channel, hook->hook_pvt);
-				ao2_unlink(features->other_hooks, hook);
-			}
-			ao2_ref(hook, -1);
-		} while ((hook = ao2_iterator_next(&iter)));
-		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
-		bridge_channel_unsuspend(bridge_channel);
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
-int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
-{
-	int res = 0;
-	struct ast_bridge_features *channel_features;
-
-	ast_debug(1, "Bridge %s: %p(%s) is joining\n",
-		bridge_channel->bridge->uniqueid,
-		bridge_channel, ast_channel_name(bridge_channel->chan));
-
-	/*
-	 * Directly locking the bridge is safe here because nobody else
-	 * knows about this bridge_channel yet.
-	 */
-	ast_bridge_lock(bridge_channel->bridge);
-
-	ast_channel_lock(bridge_channel->chan);
-
-	bridge_channel->read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan));
-	bridge_channel->write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan));
-
-	/* Make sure we're still good to be put into a bridge */
-	if (ast_channel_internal_bridge(bridge_channel->chan)
-		|| ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
-		ast_channel_unlock(bridge_channel->chan);
-		ast_bridge_unlock(bridge_channel->bridge);
-		ast_debug(1, "Bridge %s: %p(%s) failed to join Bridge\n",
-			bridge_channel->bridge->uniqueid,
-			bridge_channel,
-			ast_channel_name(bridge_channel->chan));
-		return -1;
-	}
-	ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
-
-	/* Attach features requested by the channel */
-	channel_features = ast_channel_feature_hooks_get(bridge_channel->chan);
-	if (channel_features) {
-		ast_bridge_features_merge(bridge_channel->features, channel_features);
-	}
-	ast_channel_unlock(bridge_channel->chan);
-
-	/* Add the jitterbuffer if the channel requires it */
-	ast_jb_enable_for_channel(bridge_channel->chan);
-
-	if (!bridge_channel->bridge->callid) {
-		bridge_channel->bridge->callid = ast_read_threadstorage_callid();
-	}
-
-	if (bridge_channel_internal_push(bridge_channel)) {
-		int cause = bridge_channel->bridge->cause;
-
-		ast_bridge_unlock(bridge_channel->bridge);
-		ast_bridge_channel_kick(bridge_channel, cause);
-		ast_bridge_channel_lock_bridge(bridge_channel);
-		ast_bridge_features_remove(bridge_channel->features,
-			AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-		bridge_channel_dissolve_check(bridge_channel);
-		res = -1;
-	}
-	bridge_reconfigured(bridge_channel->bridge, !bridge_channel->inhibit_colp);
-
-	if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-		/*
-		 * Indicate a source change since this channel is entering the
-		 * bridge system only if the bridge technology is not MULTIMIX
-		 * capable.  The MULTIMIX technology has already done it.
-		 */
-		if (!(bridge_channel->bridge->technology->capabilities
-			& AST_BRIDGE_CAPABILITY_MULTIMIX)) {
-			ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE);
-		}
-
-		ast_bridge_unlock(bridge_channel->bridge);
-		bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN);
-
-		while (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
-			/* Wait for something to do. */
-			bridge_channel_wait(bridge_channel);
-		}
-
-		/* Force a timeout on any accumulated DTMF hook digits. */
-		ast_bridge_channel_feature_digit(bridge_channel, 0);
-
-		bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_LEAVE);
-		ast_bridge_channel_lock_bridge(bridge_channel);
-	}
-
-	bridge_channel_internal_pull(bridge_channel);
-	bridge_channel_settle_owed_events(bridge_channel->bridge, bridge_channel);
-	bridge_reconfigured(bridge_channel->bridge, 1);
-
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	/* Complete any active hold before exiting the bridge. */
-	if (ast_channel_hold_state(bridge_channel->chan) == AST_CONTROL_HOLD) {
-		ast_debug(1, "Channel %s simulating UNHOLD for bridge end.\n",
-			ast_channel_name(bridge_channel->chan));
-		ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
-	}
-
-	/* Complete any partial DTMF digit before exiting the bridge. */
-	if (ast_channel_sending_dtmf_digit(bridge_channel->chan)) {
-		ast_channel_end_dtmf(bridge_channel->chan,
-			ast_channel_sending_dtmf_digit(bridge_channel->chan),
-			ast_channel_sending_dtmf_tv(bridge_channel->chan), "bridge end");
-	}
-
-	/* Indicate a source change since this channel is leaving the bridge system. */
-	ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE);
-
-	/*
-	 * Wait for any dual redirect to complete.
-	 *
-	 * Must be done while "still in the bridge" for ast_async_goto()
-	 * to work right.
-	 */
-	while (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
-		sched_yield();
-	}
-	ast_channel_lock(bridge_channel->chan);
-	ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
-	ast_channel_unlock(bridge_channel->chan);
-
-	ast_bridge_channel_restore_formats(bridge_channel);
-
-	return res;
-}
-
-int bridge_channel_internal_queue_blind_transfer(struct ast_channel *transferee,
-		const char *exten, const char *context,
-		transfer_channel_cb new_channel_cb, void *user_data)
-{
-	RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup);
-	struct blind_transfer_data blind_data;
-
-	ast_channel_lock(transferee);
-	transferee_bridge_channel = ast_channel_get_bridge_channel(transferee);
-	ast_channel_unlock(transferee);
-
-	if (!transferee_bridge_channel) {
-		return -1;
-	}
-
-	if (new_channel_cb) {
-		new_channel_cb(transferee, user_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
-	}
-
-	ast_copy_string(blind_data.exten, exten, sizeof(blind_data.exten));
-	ast_copy_string(blind_data.context, context, sizeof(blind_data.context));
-
-	return bridge_channel_queue_action_data(transferee_bridge_channel,
-		BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER, &blind_data, sizeof(blind_data));
-}
-
-int bridge_channel_internal_queue_attended_transfer(struct ast_channel *transferee,
-		struct ast_channel *unbridged_chan)
-{
-	RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup);
-	char unbridged_chan_name[AST_CHANNEL_NAME];
-
-	ast_channel_lock(transferee);
-	transferee_bridge_channel = ast_channel_get_bridge_channel(transferee);
-	ast_channel_unlock(transferee);
-
-	if (!transferee_bridge_channel) {
-		return -1;
-	}
-
-	ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan),
-		sizeof(unbridged_chan_name));
-
-	return bridge_channel_queue_action_data(transferee_bridge_channel,
-		BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER, unbridged_chan_name,
-		sizeof(unbridged_chan_name));
-}
-
-int bridge_channel_internal_allows_optimization(struct ast_bridge_channel *bridge_channel)
-{
-	return bridge_channel->in_bridge
-		&& AST_LIST_EMPTY(&bridge_channel->wr_queue);
-}
-
-/*!
- * \internal
- * \brief Close a pipe.
- * \since 12.0.0
- *
- * \param my_pipe What to close.
- *
- * \return Nothing
- */
-static void pipe_close(int *my_pipe)
-{
-	if (my_pipe[0] > -1) {
-		close(my_pipe[0]);
-		my_pipe[0] = -1;
-	}
-	if (my_pipe[1] > -1) {
-		close(my_pipe[1]);
-		my_pipe[1] = -1;
-	}
-}
-
-/*!
- * \internal
- * \brief Initialize a pipe as non-blocking.
- * \since 12.0.0
- *
- * \param my_pipe What to initialize.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int pipe_init_nonblock(int *my_pipe)
-{
-	int flags;
-
-	my_pipe[0] = -1;
-	my_pipe[1] = -1;
-	if (pipe(my_pipe)) {
-		ast_log(LOG_WARNING, "Can't create pipe! Try increasing max file descriptors with ulimit -n\n");
-		return -1;
-	}
-	flags = fcntl(my_pipe[0], F_GETFL);
-	if (fcntl(my_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
-		ast_log(LOG_WARNING, "Unable to set read pipe nonblocking! (%d: %s)\n",
-			errno, strerror(errno));
-		return -1;
-	}
-	flags = fcntl(my_pipe[1], F_GETFL);
-	if (fcntl(my_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
-		ast_log(LOG_WARNING, "Unable to set write pipe nonblocking! (%d: %s)\n",
-			errno, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-/* Destroy elements of the bridge channel structure and the bridge channel structure itself */
-static void bridge_channel_destroy(void *obj)
-{
-	struct ast_bridge_channel *bridge_channel = obj;
-	struct ast_frame *fr;
-
-	if (bridge_channel->callid) {
-		bridge_channel->callid = ast_callid_unref(bridge_channel->callid);
-	}
-
-	if (bridge_channel->bridge) {
-		ao2_ref(bridge_channel->bridge, -1);
-		bridge_channel->bridge = NULL;
-	}
-
-	/* Flush any unhandled wr_queue frames. */
-	while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
-		bridge_frame_free(fr);
-	}
-	pipe_close(bridge_channel->alert_pipe);
-
-	ast_cond_destroy(&bridge_channel->cond);
-
-	ao2_cleanup(bridge_channel->write_format);
-	ao2_cleanup(bridge_channel->read_format);
-}
-
-struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	bridge_channel = ao2_alloc(sizeof(struct ast_bridge_channel), bridge_channel_destroy);
-	if (!bridge_channel) {
-		return NULL;
-	}
-	ast_cond_init(&bridge_channel->cond, NULL);
-	if (pipe_init_nonblock(bridge_channel->alert_pipe)) {
-		ao2_ref(bridge_channel, -1);
-		return NULL;
-	}
-	if (bridge) {
-		bridge_channel->bridge = bridge;
-		ao2_ref(bridge_channel->bridge, +1);
-	}
-
-	return bridge_channel;
-}
diff --git a/main/bridge_roles.c b/main/bridge_roles.c
deleted file mode 100644
index af61dc5..0000000
--- a/main/bridge_roles.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Channel Bridging Roles API
- *
- * \author Jonathan Rose <jrose at digium.com>
- *
- * \ingroup bridges
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396182 $")
-
-#include <signal.h>
-
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/datastore.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_roles.h"
-#include "asterisk/stringfields.h"
-
-struct bridge_role_option {
-	AST_LIST_ENTRY(bridge_role_option) list;
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(option);
-		AST_STRING_FIELD(value);
-	);
-};
-
-struct bridge_role {
-	AST_LIST_ENTRY(bridge_role) list;
-	AST_LIST_HEAD(, bridge_role_option) options;
-	char role[AST_ROLE_LEN];
-};
-
-struct bridge_roles_datastore {
-	AST_LIST_HEAD(, bridge_role) role_list;
-};
-
-/*!
- * \internal
- * \brief Destructor function for a bridge role
- * \since 12.0.0
- *
- * \param role bridge_role being destroyed
- *
- * \return Nothing
- */
-static void bridge_role_destroy(struct bridge_role *role)
-{
-	struct bridge_role_option *role_option;
-	while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
-		ast_string_field_free_memory(role_option);
-		ast_free(role_option);
-	}
-	ast_free(role);
-}
-
-/*!
- * \internal
- * \brief Destructor function for bridge role datastores
- * \since 12.0.0
- *
- * \param data Pointer to the datastore being destroyed
- *
- * \return Nothing
- */
-static void bridge_role_datastore_destroy(void *data)
-{
-	struct bridge_roles_datastore *roles_datastore = data;
-	struct bridge_role *role;
-
-	while ((role = AST_LIST_REMOVE_HEAD(&roles_datastore->role_list, list))) {
-		bridge_role_destroy(role);
-	}
-
-	ast_free(roles_datastore);
-}
-
-static const struct ast_datastore_info bridge_role_info = {
-	.type = "bridge roles",
-	.destroy = bridge_role_datastore_destroy,
-};
-
-/*!
- * \internal
- * \brief Setup a bridge role datastore on a channel
- * \since 12.0.0
- *
- * \param chan Chan the datastore is being setup on
- *
- * \retval NULL if failed
- * \retval pointer to the newly created datastore
- */
-static struct bridge_roles_datastore *setup_bridge_roles_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = NULL;
-	struct bridge_roles_datastore *roles_datastore = NULL;
-
-	if (!(datastore = ast_datastore_alloc(&bridge_role_info, NULL))) {
-		return NULL;
-	}
-
-	if (!(roles_datastore = ast_calloc(1, sizeof(*roles_datastore)))) {
-		ast_datastore_free(datastore);
-		return NULL;
-	}
-
-	datastore->data = roles_datastore;
-	ast_channel_datastore_add(chan, datastore);
-	return roles_datastore;
-}
-
-/*!
- * \internal
- * \brief Get the bridge_roles_datastore from a channel if it exists. Don't create one if it doesn't.
- * \since 12.0.0
- *
- * \param chan Channel we want the bridge_roles_datastore from
- *
- * \retval NULL if we can't find the datastore
- * \retval pointer to the bridge_roles_datastore
- */
-static struct bridge_roles_datastore *fetch_bridge_roles_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = NULL;
-
-	ast_channel_lock(chan);
-	if (!(datastore = ast_channel_datastore_find(chan, &bridge_role_info, NULL))) {
-		ast_channel_unlock(chan);
-		return NULL;
-	}
-	ast_channel_unlock(chan);
-
-	return datastore->data;
-}
-
-/*!
- * \internal
- * \brief Get the bridge_roles_datastore from a channel if it exists. If not, create one.
- * \since 12.0.0
- *
- * \param chan Channel we want the bridge_roles_datastore from
- *
- * \retval NULL If we can't find and can't create the datastore
- * \retval pointer to the bridge_roles_datastore
- */
-static struct bridge_roles_datastore *fetch_or_create_bridge_roles_datastore(struct ast_channel *chan)
-{
-	struct bridge_roles_datastore *roles_datastore;
-
-	ast_channel_lock(chan);
-	roles_datastore = fetch_bridge_roles_datastore(chan);
-	if (!roles_datastore) {
-		roles_datastore = setup_bridge_roles_datastore(chan);
-	}
-	ast_channel_unlock(chan);
-
-	return roles_datastore;
-}
-
-/*!
- * \internal
- * \brief Obtain a role from a bridge_roles_datastore if the datastore has it
- * \since 12.0.0
- *
- * \param roles_datastore The bridge_roles_datastore we are looking for the role of
- * \param role_name Name of the role being sought
- *
- * \retval NULL if the datastore does not have the requested role
- * \retval pointer to the requested role
- */
-static struct bridge_role *get_role_from_datastore(struct bridge_roles_datastore *roles_datastore, const char *role_name)
-{
-	struct bridge_role *role;
-
-	AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
-		if (!strcmp(role->role, role_name)) {
-			return role;
-		}
-	}
-
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Obtain a role from a channel structure if the channel's datastore has it
- * \since 12.0.0
- *
- * \param channel The channel we are checking the role of
- * \param role_name Name of the role sought
- *
- * \retval NULL if the channel's datastore does not have the requested role
- * \retval pointer to the requested role
- */
-static struct bridge_role *get_role_from_channel(struct ast_channel *channel, const char *role_name)
-{
-	struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(channel);
-	return roles_datastore ? get_role_from_datastore(roles_datastore, role_name) : NULL;
-}
-
-/*!
- * \internal
- * \brief Obtain a role option from a bridge role if it exists in the bridge role's option list
- * \since 12.0.0
- *
- * \param role a pointer to the bridge role wea re searching for the option of
- * \param option Name of the option sought
- *
- * \retval NULL if the bridge role doesn't have the requested option
- * \retval pointer to the requested option
- */
-static struct bridge_role_option *get_role_option(struct bridge_role *role, const char *option)
-{
-	struct bridge_role_option *role_option = NULL;
-	AST_LIST_TRAVERSE(&role->options, role_option, list) {
-		if (!strcmp(role_option->option, option)) {
-			return role_option;
-		}
-	}
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Setup a bridge role on an existing bridge role datastore
- * \since 12.0.0
- *
- * \param roles_datastore bridge_roles_datastore receiving the new role
- * \param role_name Name of the role being received
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int setup_bridge_role(struct bridge_roles_datastore *roles_datastore, const char *role_name)
-{
-	struct bridge_role *role;
-	role = ast_calloc(1, sizeof(*role));
-
-	if (!role) {
-		return -1;
-	}
-
-	ast_copy_string(role->role, role_name, sizeof(role->role));
-
-	AST_LIST_INSERT_TAIL(&roles_datastore->role_list, role, list);
-	ast_debug(3, "Set role '%s'\n", role_name);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Setup a bridge role option on an existing bridge role
- * \since 12.0.0
- *
- * \param role The role receiving the option
- * \param option Name of the option
- * \param value the option's value
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int setup_bridge_role_option(struct bridge_role *role, const char *option, const char *value)
-{
-	struct bridge_role_option *role_option;
-
-	if (!value) {
-		value = "";
-	}
-
-	role_option = ast_calloc(1, sizeof(*role_option));
-	if (!role_option) {
-		return -1;
-	}
-
-	if (ast_string_field_init(role_option, 32)) {
-		ast_free(role_option);
-		return -1;
-	}
-
-	ast_string_field_set(role_option, option, option);
-	ast_string_field_set(role_option, value, value);
-
-	AST_LIST_INSERT_TAIL(&role->options, role_option, list);
-
-	return 0;
-}
-
-int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
-{
-	struct bridge_roles_datastore *roles_datastore = fetch_or_create_bridge_roles_datastore(chan);
-
-	if (!roles_datastore) {
-		ast_log(LOG_WARNING, "Unable to set up bridge role datastore on channel %s\n", ast_channel_name(chan));
-		return -1;
-	}
-
-	/* Check to make sure we aren't adding a redundant role */
-	if (get_role_from_datastore(roles_datastore, role_name)) {
-		ast_debug(2, "Bridge role %s is already applied to the channel %s\n", role_name, ast_channel_name(chan));
-		return 0;
-	}
-
-	/* It wasn't already there, so we can just finish setting it up now. */
-	return setup_bridge_role(roles_datastore, role_name);
-}
-
-void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
-{
-	struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
-	struct bridge_role *role;
-
-	if (!roles_datastore) {
-		/* The roles datastore didn't already exist, so there is no need to remove a role */
-		ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
-		return;
-	}
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
-		if (!strcmp(role->role, role_name)) {
-			ast_debug(2, "Removing bridge role %s from channel %s\n", role_name, ast_channel_name(chan));
-			AST_LIST_REMOVE_CURRENT(list);
-			bridge_role_destroy(role);
-			return;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	ast_debug(2, "Role %s did not exist on channel %s\n", role_name, ast_channel_name(chan));
-}
-
-void ast_channel_clear_bridge_roles(struct ast_channel *chan)
-{
-	struct bridge_roles_datastore *roles_datastore = fetch_bridge_roles_datastore(chan);
-	struct bridge_role *role;
-
-	if (!roles_datastore) {
-		/* The roles datastore didn't already exist, so there is no need to remove any roles */
-		ast_debug(2, "Roles did not exist on channel %s\n", ast_channel_name(chan));
-		return;
-	}
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&roles_datastore->role_list, role, list) {
-		ast_debug(2, "Removing bridge role %s from channel %s\n", role->role, ast_channel_name(chan));
-		AST_LIST_REMOVE_CURRENT(list);
-		bridge_role_destroy(role);
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-}
-
-int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
-{
-	struct bridge_role *role = get_role_from_channel(channel, role_name);
-	struct bridge_role_option *role_option;
-
-	if (!role) {
-		return -1;
-	}
-
-	role_option = get_role_option(role, option);
-
-	if (role_option) {
-		ast_string_field_set(role_option, value, value);
-		return 0;
-	}
-
-	return setup_bridge_role_option(role, option, value);
-}
-
-int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
-{
-	return get_role_from_channel(channel, role_name) ? 1 : 0;
-}
-
-const char *ast_channel_get_role_option(struct ast_channel *channel, const char *role_name, const char *option)
-{
-	struct bridge_role *role;
-	struct bridge_role_option *role_option;
-
-	role = get_role_from_channel(channel, role_name);
-	if (!role) {
-		return NULL;
-	}
-
-	role_option = get_role_option(role, option);
-
-	return role_option ? role_option->value : NULL;
-}
-
-int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
-{
-	if (!bridge_channel->bridge_roles) {
-		return 0;
-	}
-
-	return get_role_from_datastore(bridge_channel->bridge_roles, role_name) ? 1 : 0;
-}
-
-const char *ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
-{
-	struct bridge_role *role;
-	struct bridge_role_option *role_option = NULL;
-
-	if (!bridge_channel->bridge_roles) {
-		return NULL;
-	}
-
-	role = get_role_from_datastore(bridge_channel->bridge_roles, role_name);
-
-	if (!role) {
-		return NULL;
-	}
-
-	role_option = get_role_option(role, option);
-
-	return role_option ? role_option->value : NULL;
-}
-
-int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
-{
-	struct bridge_roles_datastore *roles_datastore;
-	struct bridge_role *role = NULL;
-	struct bridge_role_option *role_option;
-
-	if (!bridge_channel->chan) {
-		ast_debug(2, "Attempted to set roles on a bridge channel that has no associated channel. That's a bad idea.\n");
-		return -1;
-	}
-
-	if (bridge_channel->bridge_roles) {
-		ast_debug(2, "Attempted to reset roles while roles were already established. Purge existing roles first.\n");
-		return -1;
-	}
-
-	roles_datastore = fetch_bridge_roles_datastore(bridge_channel->chan);
-	if (!roles_datastore) {
-		/* No roles to establish. */
-		return 0;
-	}
-
-	if (!(bridge_channel->bridge_roles = ast_calloc(1, sizeof(*bridge_channel->bridge_roles)))) {
-		return -1;
-	}
-
-	AST_LIST_TRAVERSE(&roles_datastore->role_list, role, list) {
-		struct bridge_role *this_role_copy;
-
-		if (setup_bridge_role(bridge_channel->bridge_roles, role->role)) {
-			/* We need to abandon the copy because we couldn't setup a role */
-			ast_bridge_channel_clear_roles(bridge_channel);
-			return -1;
-		}
-		this_role_copy = AST_LIST_LAST(&bridge_channel->bridge_roles->role_list);
-
-		AST_LIST_TRAVERSE(&role->options, role_option, list) {
-			if (setup_bridge_role_option(this_role_copy, role_option->option, role_option->value)) {
-				/* We need to abandon the copy because we couldn't setup a role option */
-				ast_bridge_channel_clear_roles(bridge_channel);
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
-{
-	if (bridge_channel->bridge_roles) {
-		bridge_role_datastore_destroy(bridge_channel->bridge_roles);
-		bridge_channel->bridge_roles = NULL;
-	}
-}
diff --git a/main/bridging.c b/main/bridging.c
new file mode 100644
index 0000000..0f8f4e8
--- /dev/null
+++ b/main/bridging.c
@@ -0,0 +1,1692 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2007 - 2009, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Channel Bridging API
+ *
+ * \author Joshua Colp <jcolp at digium.com>
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <signal.h>
+
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/options.h"
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
+#include "asterisk/app.h"
+#include "asterisk/file.h"
+#include "asterisk/module.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/test.h"
+
+static AST_RWLIST_HEAD_STATIC(bridge_technologies, ast_bridge_technology);
+
+/* Initial starting point for the bridge array of channels */
+#define BRIDGE_ARRAY_START 128
+
+/* Grow rate of bridge array of channels */
+#define BRIDGE_ARRAY_GROW 32
+
+static void cleanup_video_mode(struct ast_bridge *bridge);
+
+/*! Default DTMF keys for built in features */
+static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING];
+
+/*! Function handlers for the built in features */
+static void *builtin_features_handlers[AST_BRIDGE_BUILTIN_END];
+
+int __ast_bridge_technology_register(struct ast_bridge_technology *technology, struct ast_module *module)
+{
+	struct ast_bridge_technology *current = NULL;
+
+	/* Perform a sanity check to make sure the bridge technology conforms to our needed requirements */
+	if (ast_strlen_zero(technology->name) || !technology->capabilities || !technology->write) {
+		ast_log(LOG_WARNING, "Bridge technology %s failed registration sanity check.\n", technology->name);
+		return -1;
+	}
+
+	AST_RWLIST_WRLOCK(&bridge_technologies);
+
+	/* Look for duplicate bridge technology already using this name, or already registered */
+	AST_RWLIST_TRAVERSE(&bridge_technologies, current, entry) {
+		if ((!strcasecmp(current->name, technology->name)) || (current == technology)) {
+			ast_log(LOG_WARNING, "A bridge technology of %s already claims to exist in our world.\n", technology->name);
+			AST_RWLIST_UNLOCK(&bridge_technologies);
+			return -1;
+		}
+	}
+
+	/* Copy module pointer so reference counting can keep the module from unloading */
+	technology->mod = module;
+
+	/* Insert our new bridge technology into the list and print out a pretty message */
+	AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
+
+	AST_RWLIST_UNLOCK(&bridge_technologies);
+
+	ast_verb(2, "Registered bridge technology %s\n", technology->name);
+
+	return 0;
+}
+
+int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
+{
+	struct ast_bridge_technology *current = NULL;
+
+	AST_RWLIST_WRLOCK(&bridge_technologies);
+
+	/* Ensure the bridge technology is registered before removing it */
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&bridge_technologies, current, entry) {
+		if (current == technology) {
+			AST_RWLIST_REMOVE_CURRENT(entry);
+			ast_verb(2, "Unregistered bridge technology %s\n", technology->name);
+			break;
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+
+	AST_RWLIST_UNLOCK(&bridge_technologies);
+
+	return current ? 0 : -1;
+}
+
+void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
+{
+	/* Change the state on the bridge channel with some manner of intelligence. */
+	ao2_lock(bridge_channel);
+	switch (bridge_channel->state) {
+	case AST_BRIDGE_CHANNEL_STATE_DEPART:
+		break;
+	case AST_BRIDGE_CHANNEL_STATE_END:
+	case AST_BRIDGE_CHANNEL_STATE_HANGUP:
+		if (new_state != AST_BRIDGE_CHANNEL_STATE_DEPART) {
+			break;
+		}
+		/* Fall through */
+	default:
+		bridge_channel->state = new_state;
+		break;
+	}
+	ao2_unlock(bridge_channel);
+
+	/* Only poke the channel's thread if it is not us */
+	if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
+		pthread_kill(bridge_channel->thread, SIGURG);
+		ao2_lock(bridge_channel);
+		ast_cond_signal(&bridge_channel->cond);
+		ao2_unlock(bridge_channel);
+	}
+}
+
+/*! \brief Helper function to poke the bridge thread */
+static void bridge_poke(struct ast_bridge *bridge)
+{
+	/* Poke the thread just in case */
+	if (bridge->thread != AST_PTHREADT_NULL && bridge->thread != AST_PTHREADT_STOP) {
+		pthread_kill(bridge->thread, SIGURG);
+	}
+
+	return;
+}
+
+/*! \brief Helper function to add a channel to the bridge array
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_array_add(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	/* We have to make sure the bridge thread is not using the bridge array before messing with it */
+	while (bridge->waiting) {
+		bridge_poke(bridge);
+		sched_yield();
+	}
+
+	bridge->array[bridge->array_num++] = chan;
+
+	ast_debug(1, "Added channel %s(%p) to bridge array on %p, new count is %d\n", ast_channel_name(chan), chan, bridge, (int)bridge->array_num);
+
+	/* If the next addition of a channel will exceed our array size grow it out */
+	if (bridge->array_num == bridge->array_size) {
+		struct ast_channel **tmp;
+		ast_debug(1, "Growing bridge array on %p from %d to %d\n", bridge, (int)bridge->array_size, (int)bridge->array_size + BRIDGE_ARRAY_GROW);
+		if (!(tmp = ast_realloc(bridge->array, (bridge->array_size + BRIDGE_ARRAY_GROW) * sizeof(struct ast_channel *)))) {
+			ast_log(LOG_ERROR, "Failed to allocate more space for another channel on bridge '%p', this is not going to end well\n", bridge);
+			return;
+		}
+		bridge->array = tmp;
+		bridge->array_size += BRIDGE_ARRAY_GROW;
+	}
+
+	return;
+}
+
+/*! \brief Helper function to remove a channel from the bridge array
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_array_remove(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	int i;
+
+	/* We have to make sure the bridge thread is not using the bridge array before messing with it */
+	while (bridge->waiting) {
+		bridge_poke(bridge);
+		sched_yield();
+	}
+
+	for (i = 0; i < bridge->array_num; i++) {
+		if (bridge->array[i] == chan) {
+			bridge->array[i] = (bridge->array[(bridge->array_num - 1)] != chan ? bridge->array[(bridge->array_num - 1)] : NULL);
+			bridge->array[(bridge->array_num - 1)] = NULL;
+			bridge->array_num--;
+			ast_debug(1, "Removed channel %p from bridge array on %p, new count is %d\n", chan, bridge, (int)bridge->array_num);
+			break;
+		}
+	}
+
+	return;
+}
+
+/*! \brief Helper function to find a bridge channel given a channel */
+static struct ast_bridge_channel *find_bridge_channel(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+		if (bridge_channel->chan == chan) {
+			break;
+		}
+	}
+
+	return bridge_channel;
+}
+
+/*! \brief Internal function to see whether a bridge should dissolve, and if so do it */
+static void bridge_check_dissolve(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_bridge_channel *bridge_channel2 = NULL;
+
+	if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE) && (!bridge_channel->features || !bridge_channel->features->usable || !ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_FLAG_DISSOLVE))) {
+		return;
+	}
+
+	ast_debug(1, "Dissolving bridge %p\n", bridge);
+
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel2, entry) {
+		if (bridge_channel2->state != AST_BRIDGE_CHANNEL_STATE_END && bridge_channel2->state != AST_BRIDGE_CHANNEL_STATE_DEPART) {
+			ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+		}
+	}
+
+	return;
+}
+
+/*! \brief Internal function to handle DTMF from a channel */
+static struct ast_frame *bridge_handle_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+{
+	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+	struct ast_bridge_features_hook *hook = NULL;
+
+	/* If the features structure we grabbed is not usable immediately return the frame */
+	if (!features->usable) {
+		return frame;
+	}
+
+	/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
+	AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
+		if (hook->dtmf[0] == frame->subclass.integer) {
+			ast_frfree(frame);
+			frame = NULL;
+			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_FEATURE);
+			break;
+		}
+	}
+
+	return frame;
+}
+
+/*! \brief Internal function used to determine whether a control frame should be dropped or not */
+static int bridge_drop_control_frame(int subclass)
+{
+	switch (subclass) {
+	case AST_CONTROL_ANSWER:
+	case -1:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking)
+{
+	if (started_talking) {
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_START_TALKING);
+	} else {
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_STOP_TALKING);
+	}
+}
+
+void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd)
+{
+	/* If no bridge channel has been provided and the actual channel has been provided find it */
+	if (chan && !bridge_channel) {
+		bridge_channel = find_bridge_channel(bridge, chan);
+	}
+
+	/* If a bridge channel with actual channel is present read a frame and handle it */
+	if (chan && bridge_channel) {
+		struct ast_frame *frame = (((bridge->features.mute) || (bridge_channel->features && bridge_channel->features->mute)) ? ast_read_noaudio(chan) : ast_read(chan));
+
+		/* This is pretty simple... see if they hung up */
+		if (!frame || (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_HANGUP)) {
+			/* Signal the thread that is handling the bridged channel that it should be ended */
+			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+		} else if (frame->frametype == AST_FRAME_CONTROL && bridge_drop_control_frame(frame->subclass.integer)) {
+			ast_debug(1, "Dropping control frame from bridge channel %p\n", bridge_channel);
+		} else if (frame->frametype == AST_FRAME_DTMF_BEGIN || frame->frametype == AST_FRAME_DTMF_END) {
+			int dtmf_passthrough = bridge_channel->features ?
+				bridge_channel->features->dtmf_passthrough :
+				bridge->features.dtmf_passthrough;
+
+			if (frame->frametype == AST_FRAME_DTMF_BEGIN) {
+				frame = bridge_handle_dtmf(bridge, bridge_channel, frame);
+			}
+
+			if (frame && dtmf_passthrough) {
+				bridge->technology->write(bridge, bridge_channel, frame);
+			}
+		} else {
+			/* Simply write the frame out to the bridge technology if it still exists */
+			bridge->technology->write(bridge, bridge_channel, frame);
+		}
+
+		if (frame) {
+			ast_frfree(frame);
+		}
+		return;
+	}
+
+	/* If a file descriptor actually tripped pass it off to the bridge technology */
+	if (outfd > -1 && bridge->technology->fd) {
+		bridge->technology->fd(bridge, bridge_channel, outfd);
+		return;
+	}
+
+	/* If all else fails just poke the bridge */
+	if (bridge->technology->poke && bridge_channel) {
+		bridge->technology->poke(bridge, bridge_channel);
+		return;
+	}
+
+	return;
+}
+
+/*! \brief Generic thread loop, TODO: Rethink this/improve it */
+static int generic_thread_loop(struct ast_bridge *bridge)
+{
+	while (!bridge->stop && !bridge->refresh && bridge->array_num) {
+		struct ast_channel *winner = NULL;
+		int to = -1;
+
+		/* Move channels around for priority reasons if we have more than one channel in our array */
+		if (bridge->array_num > 1) {
+			struct ast_channel *first = bridge->array[0];
+			memmove(bridge->array, bridge->array + 1, sizeof(struct ast_channel *) * (bridge->array_num - 1));
+			bridge->array[(bridge->array_num - 1)] = first;
+		}
+
+		/* Wait on the channels */
+		bridge->waiting = 1;
+		ao2_unlock(bridge);
+		winner = ast_waitfor_n(bridge->array, (int)bridge->array_num, &to);
+		bridge->waiting = 0;
+		ao2_lock(bridge);
+
+		/* Process whatever they did */
+		ast_bridge_handle_trip(bridge, NULL, winner, -1);
+	}
+
+	return 0;
+}
+
+/*! \brief Bridge thread function */
+static void *bridge_thread(void *data)
+{
+	struct ast_bridge *bridge = data;
+	int res = 0;
+
+	ao2_lock(bridge);
+
+	if (bridge->callid) {
+		ast_callid_threadassoc_add(bridge->callid);
+	}
+
+	ast_debug(1, "Started bridge thread for %p\n", bridge);
+
+	/* Loop around until we are told to stop */
+	while (!bridge->stop && bridge->array_num && !res) {
+		/* In case the refresh bit was set simply set it back to off */
+		bridge->refresh = 0;
+
+		ast_debug(1, "Launching bridge thread function %p for bridge %p\n", (bridge->technology->thread ? bridge->technology->thread : &generic_thread_loop), bridge);
+
+		/* Execute the appropriate thread function. If the technology does not provide one we use the generic one */
+		res = (bridge->technology->thread ? bridge->technology->thread(bridge) : generic_thread_loop(bridge));
+	}
+
+	ast_debug(1, "Ending bridge thread for %p\n", bridge);
+
+	/* Indicate the bridge thread is no longer active */
+	bridge->thread = AST_PTHREADT_NULL;
+	ao2_unlock(bridge);
+
+	ao2_ref(bridge, -1);
+
+	return NULL;
+}
+
+/*! \brief Helper function used to find the "best" bridge technology given a specified capabilities */
+static struct ast_bridge_technology *find_best_technology(uint32_t capabilities)
+{
+	struct ast_bridge_technology *current = NULL, *best = NULL;
+
+	AST_RWLIST_RDLOCK(&bridge_technologies);
+	AST_RWLIST_TRAVERSE(&bridge_technologies, current, entry) {
+		if (current->suspended) {
+			ast_debug(1, "Bridge technology %s is suspended. Skipping.\n", current->name);
+			continue;
+		}
+		if (!(current->capabilities & capabilities)) {
+			ast_debug(1, "Bridge technology %s does not have the capabilities we need.\n", current->name);
+			continue;
+		}
+		if (best && best->preference < current->preference) {
+			ast_debug(1, "Bridge technology %s has preference %u while %s has preference %u. Skipping.\n", current->name, current->preference, best->name, best->preference);
+			continue;
+		}
+		best = current;
+	}
+
+	if (best) {
+		/* Increment it's module reference count if present so it does not get unloaded while in use */
+		if (best->mod) {
+			ast_module_ref(best->mod);
+		}
+		ast_debug(1, "Chose bridge technology %s\n", best->name);
+	}
+
+	AST_RWLIST_UNLOCK(&bridge_technologies);
+
+	return best;
+}
+
+static void destroy_bridge(void *obj)
+{
+	struct ast_bridge *bridge = obj;
+
+	ast_debug(1, "Actually destroying bridge %p, nobody wants it anymore\n", bridge);
+
+	/* Pass off the bridge to the technology to destroy if needed */
+	if (bridge->technology->destroy) {
+		ast_debug(1, "Giving bridge technology %s the bridge structure %p to destroy\n", bridge->technology->name, bridge);
+		if (bridge->technology->destroy(bridge)) {
+			ast_debug(1, "Bridge technology %s failed to destroy bridge structure %p... trying our best\n", bridge->technology->name, bridge);
+		}
+	}
+
+	/* We are no longer using the bridge technology so decrement the module reference count on it */
+	if (bridge->technology->mod) {
+		ast_module_unref(bridge->technology->mod);
+	}
+
+	/* Last but not least clean up the features configuration */
+	ast_bridge_features_cleanup(&bridge->features);
+
+	/* Drop the array of channels */
+	ast_free(bridge->array);
+
+	cleanup_video_mode(bridge);
+
+	return;
+}
+
+struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags)
+{
+	struct ast_bridge *bridge = NULL;
+	struct ast_bridge_technology *bridge_technology = NULL;
+
+	/* If we need to be a smart bridge see if we can move between 1to1 and multimix bridges */
+	if (flags & AST_BRIDGE_FLAG_SMART) {
+		struct ast_bridge *other_bridge;
+
+		if (!(other_bridge = ast_bridge_new((capabilities & AST_BRIDGE_CAPABILITY_1TO1MIX) ? AST_BRIDGE_CAPABILITY_MULTIMIX : AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
+			return NULL;
+		}
+
+		ast_bridge_destroy(other_bridge);
+	}
+
+	/* If capabilities were provided use our helper function to find the "best" bridge technology, otherwise we can
+	 * just look for the most basic capability needed, single 1to1 mixing. */
+	bridge_technology = (capabilities ? find_best_technology(capabilities) : find_best_technology(AST_BRIDGE_CAPABILITY_1TO1MIX));
+
+	/* If no bridge technology was found we can't possibly do bridging so fail creation of the bridge */
+	if (!bridge_technology) {
+		return NULL;
+	}
+
+	/* We have everything we need to create this bridge... so allocate the memory, link things together, and fire her up! */
+	if (!(bridge = ao2_alloc(sizeof(*bridge), destroy_bridge))) {
+		return NULL;
+	}
+
+	bridge->technology = bridge_technology;
+	bridge->thread = AST_PTHREADT_NULL;
+
+	/* Create an array of pointers for the channels that will be joining us */
+	bridge->array = ast_calloc(BRIDGE_ARRAY_START, sizeof(struct ast_channel*));
+	bridge->array_size = BRIDGE_ARRAY_START;
+
+	ast_set_flag(&bridge->feature_flags, flags);
+
+	/* Pass off the bridge to the technology to manipulate if needed */
+	if (bridge->technology->create) {
+		ast_debug(1, "Giving bridge technology %s the bridge structure %p to setup\n", bridge->technology->name, bridge);
+		if (bridge->technology->create(bridge)) {
+			ast_debug(1, "Bridge technology %s failed to setup bridge structure %p\n", bridge->technology->name, bridge);
+			ao2_ref(bridge, -1);
+			bridge = NULL;
+		}
+	}
+
+	return bridge;
+}
+
+int ast_bridge_check(uint32_t capabilities)
+{
+	struct ast_bridge_technology *bridge_technology = NULL;
+
+	if (!(bridge_technology = find_best_technology(capabilities))) {
+		return 0;
+	}
+
+	ast_module_unref(bridge_technology->mod);
+
+	return 1;
+}
+
+int ast_bridge_destroy(struct ast_bridge *bridge)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+
+	ao2_lock(bridge);
+
+	if (bridge->callid) {
+		bridge->callid = ast_callid_unref(bridge->callid);
+	}
+
+	if (bridge->thread != AST_PTHREADT_NULL) {
+		pthread_t thread = bridge->thread;
+		bridge->stop = 1;
+		bridge_poke(bridge);
+		ao2_unlock(bridge);
+		pthread_join(thread, NULL);
+		ao2_lock(bridge);
+	}
+
+	ast_debug(1, "Telling all channels in bridge %p to end and leave the party\n", bridge);
+
+	/* Drop every bridged channel, the last one will cause the bridge thread (if it exists) to exit */
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+	}
+
+	ao2_unlock(bridge);
+
+	ao2_ref(bridge, -1);
+
+	return 0;
+}
+
+static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_format formats[2];
+	ast_format_copy(&formats[0], ast_channel_readformat(bridge_channel->chan));
+	ast_format_copy(&formats[1], ast_channel_writeformat(bridge_channel->chan));
+
+	/* Are the formats currently in use something ths bridge can handle? */
+	if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, ast_channel_readformat(bridge_channel->chan))) {
+		struct ast_format best_format;
+		ast_best_codec(bridge->technology->format_capabilities, &best_format);
+
+		/* Read format is a no go... */
+		if (option_debug) {
+			char codec_buf[512];
+			ast_debug(1, "Bridge technology %s wants to read any of formats %s but channel has %s\n", bridge->technology->name,
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities),
+				ast_getformatname(&formats[0]));
+		}
+		/* Switch read format to the best one chosen */
+		if (ast_set_read_format(bridge_channel->chan, &best_format)) {
+			ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n", ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format));
+			return -1;
+		}
+		ast_debug(1, "Bridge %p put channel %s into read format %s\n", bridge, ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format));
+	} else {
+		ast_debug(1, "Bridge %p is happy that channel %s already has read format %s\n", bridge, ast_channel_name(bridge_channel->chan), ast_getformatname(&formats[0]));
+	}
+
+	if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, &formats[1])) {
+		struct ast_format best_format;
+		ast_best_codec(bridge->technology->format_capabilities, &best_format);
+
+		/* Write format is a no go... */
+		if (option_debug) {
+			char codec_buf[512];
+			ast_debug(1, "Bridge technology %s wants to write any of formats %s but channel has %s\n", bridge->technology->name,
+				ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities),
+				ast_getformatname(&formats[1]));
+		}
+		/* Switch write format to the best one chosen */
+		if (ast_set_write_format(bridge_channel->chan, &best_format)) {
+			ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n", ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format));
+			return -1;
+		}
+		ast_debug(1, "Bridge %p put channel %s into write format %s\n", bridge, ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format));
+	} else {
+		ast_debug(1, "Bridge %p is happy that channel %s already has write format %s\n", bridge, ast_channel_name(bridge_channel->chan), ast_getformatname(&formats[1]));
+	}
+
+	return 0;
+}
+
+/*! \brief Perform the smart bridge operation. Basically sees if a new bridge technology should be used instead of the current one. */
+static int smart_bridge_operation(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int count)
+{
+	uint32_t new_capabilities = 0;
+	struct ast_bridge_technology *new_technology = NULL, *old_technology = bridge->technology;
+	struct ast_bridge temp_bridge = {
+		.technology = bridge->technology,
+		.bridge_pvt = bridge->bridge_pvt,
+	};
+	struct ast_bridge_channel *bridge_channel2 = NULL;
+
+	/* Based on current feature determine whether we want to change bridge technologies or not */
+	if (bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_1TO1MIX) {
+		if (count <= 2) {
+			ast_debug(1, "Bridge %p channel count (%d) is within limits for bridge technology %s, not performing smart bridge operation.\n", bridge, count, bridge->technology->name);
+			return 0;
+		}
+		new_capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX;
+	} else if (bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
+		if (count > 2) {
+			ast_debug(1, "Bridge %p channel count (%d) is within limits for bridge technology %s, not performing smart bridge operation.\n", bridge, count, bridge->technology->name);
+			return 0;
+		}
+		new_capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX;
+	}
+
+	if (!new_capabilities) {
+		ast_debug(1, "Bridge '%p' has no new capabilities, not performing smart bridge operation.\n", bridge);
+		return 0;
+	}
+
+	/* Attempt to find a new bridge technology to satisfy the capabilities */
+	if (!(new_technology = find_best_technology(new_capabilities))) {
+		return -1;
+	}
+
+	ast_debug(1, "Performing smart bridge operation on bridge %p, moving from bridge technology %s to %s\n", bridge, old_technology->name, new_technology->name);
+
+	/* If a thread is currently executing for the current technology tell it to stop */
+	if (bridge->thread != AST_PTHREADT_NULL) {
+		/* If the new bridge technology also needs a thread simply tell the bridge thread to refresh itself. This has the benefit of not incurring the cost/time of tearing down and bringing up a new thread. */
+		if (new_technology->capabilities & AST_BRIDGE_CAPABILITY_THREAD) {
+			ast_debug(1, "Telling current bridge thread for bridge %p to refresh\n", bridge);
+			bridge->refresh = 1;
+			bridge_poke(bridge);
+		} else {
+			pthread_t bridge_thread = bridge->thread;
+			ast_debug(1, "Telling current bridge thread for bridge %p to stop\n", bridge);
+			bridge->stop = 1;
+			bridge_poke(bridge);
+			ao2_unlock(bridge);
+			pthread_join(bridge_thread, NULL);
+			ao2_lock(bridge);
+		}
+	}
+
+	/* Since we are soon going to pass this bridge to a new technology we need to NULL out the bridge_pvt pointer but don't worry as it still exists in temp_bridge, ditto for the old technology */
+	bridge->bridge_pvt = NULL;
+	bridge->technology = new_technology;
+
+	/* Pass the bridge to the new bridge technology so it can set it up */
+	if (new_technology->create) {
+		ast_debug(1, "Giving bridge technology %s the bridge structure %p to setup\n", new_technology->name, bridge);
+		if (new_technology->create(bridge)) {
+			ast_debug(1, "Bridge technology %s failed to setup bridge structure %p\n", new_technology->name, bridge);
+		}
+	}
+
+	/* Move existing channels over to the new technology, while taking them away from the old one */
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel2, entry) {
+		/* Skip over channel that initiated the smart bridge operation */
+		if (bridge_channel == bridge_channel2) {
+			continue;
+		}
+
+		/* First we part them from the old technology */
+		if (old_technology->leave) {
+			ast_debug(1, "Giving bridge technology %s notification that %p is leaving bridge %p (really %p)\n", old_technology->name, bridge_channel2, &temp_bridge, bridge);
+			if (old_technology->leave(&temp_bridge, bridge_channel2)) {
+				ast_debug(1, "Bridge technology %s failed to allow %p (really %p) to leave bridge %p\n", old_technology->name, bridge_channel2, &temp_bridge, bridge);
+			}
+		}
+
+		/* Second we make them compatible again with the bridge */
+		bridge_make_compatible(bridge, bridge_channel2);
+
+		/* Third we join them to the new technology */
+		if (new_technology->join) {
+			ast_debug(1, "Giving bridge technology %s notification that %p is joining bridge %p\n", new_technology->name, bridge_channel2, bridge);
+			if (new_technology->join(bridge, bridge_channel2)) {
+				ast_debug(1, "Bridge technology %s failed to join %p to bridge %p\n", new_technology->name, bridge_channel2, bridge);
+			}
+		}
+
+		/* Fourth we tell them to wake up so they become aware that they above has happened */
+		pthread_kill(bridge_channel2->thread, SIGURG);
+		ao2_lock(bridge_channel2);
+		ast_cond_signal(&bridge_channel2->cond);
+		ao2_unlock(bridge_channel2);
+	}
+
+	/* Now that all the channels have been moved over we need to get rid of all the information the old technology may have left around */
+	if (old_technology->destroy) {
+		ast_debug(1, "Giving bridge technology %s the bridge structure %p (really %p) to destroy\n", old_technology->name, &temp_bridge, bridge);
+		if (old_technology->destroy(&temp_bridge)) {
+			ast_debug(1, "Bridge technology %s failed to destroy bridge structure %p (really %p)... some memory may have leaked\n", old_technology->name, &temp_bridge, bridge);
+		}
+	}
+
+	/* Finally if the old technology has module referencing remove our reference, we are no longer going to use it */
+	if (old_technology->mod) {
+		ast_module_unref(old_technology->mod);
+	}
+
+	return 0;
+}
+
+/*! \brief Run in a multithreaded model. Each joined channel does writing/reading in their own thread. TODO: Improve */
+static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct ast_bridge_channel *bridge_channel)
+{
+	int fds[4] = { -1, }, nfds = 0, i = 0, outfd = -1, ms = -1;
+	struct ast_channel *chan = NULL;
+
+	/* Add any file descriptors we may want to monitor */
+	if (bridge_channel->bridge->technology->fd) {
+		for (i = 0; i < 4; i ++) {
+			if (bridge_channel->fds[i] >= 0) {
+				fds[nfds++] = bridge_channel->fds[i];
+			}
+		}
+	}
+
+	ao2_unlock(bridge_channel->bridge);
+
+	ao2_lock(bridge_channel);
+	/* Wait for data to either come from the channel or us to be signalled */
+	if (!bridge_channel->suspended) {
+		ao2_unlock(bridge_channel);
+		ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
+	} else {
+		ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+		ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
+		ao2_unlock(bridge_channel);
+	}
+
+	ao2_lock(bridge_channel->bridge);
+
+	if (!bridge_channel->suspended) {
+		ast_bridge_handle_trip(bridge_channel->bridge, bridge_channel, chan, outfd);
+	}
+
+	return bridge_channel->state;
+}
+
+/*! \brief Run in a singlethreaded model. Each joined channel yields itself to the main bridge thread. TODO: Improve */
+static enum ast_bridge_channel_state bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
+{
+	ao2_unlock(bridge_channel->bridge);
+	ao2_lock(bridge_channel);
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		ast_debug(1, "Going into a single threaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+		ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
+	}
+	ao2_unlock(bridge_channel);
+	ao2_lock(bridge_channel->bridge);
+
+	return bridge_channel->state;
+}
+
+/*! \brief Internal function that suspends a channel from a bridge */
+static void bridge_channel_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	ao2_lock(bridge_channel);
+	bridge_channel->suspended = 1;
+	bridge_array_remove(bridge, bridge_channel->chan);
+	ao2_unlock(bridge_channel);
+
+	if (bridge->technology->suspend) {
+		bridge->technology->suspend(bridge, bridge_channel);
+	}
+
+	return;
+}
+
+/*! \brief Internal function that unsuspends a channel from a bridge */
+static void bridge_channel_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	ao2_lock(bridge_channel);
+	bridge_channel->suspended = 0;
+	bridge_array_add(bridge, bridge_channel->chan);
+	ast_cond_signal(&bridge_channel->cond);
+	ao2_unlock(bridge_channel);
+
+	if (bridge->technology->unsuspend) {
+		bridge->technology->unsuspend(bridge, bridge_channel);
+	}
+
+
+
+	return;
+}
+
+/*!
+ * \brief Internal function that executes a feature on a bridge channel
+ * \note Neither the bridge nor the bridge_channel locks should be held when entering
+ * this function.
+ */
+static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+	struct ast_bridge_features_hook *hook = NULL;
+	char dtmf[MAXIMUM_DTMF_FEATURE_STRING] = "";
+	int look_for_dtmf = 1, dtmf_len = 0;
+
+	/* The channel is now under our control and we don't really want any begin frames to do our DTMF matching so disable 'em at the core level */
+	ast_set_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_END_DTMF_ONLY);
+
+	/* Wait for DTMF on the channel and put it into a buffer. If the buffer matches any feature hook execute the hook. */
+	while (look_for_dtmf) {
+		int res = ast_waitfordigit(bridge_channel->chan, 3000);
+
+		/* If the above timed out simply exit */
+		if (!res) {
+			ast_debug(1, "DTMF feature string collection on bridge channel %p timed out\n", bridge_channel);
+			break;
+		} else if (res < 0) {
+			ast_debug(1, "DTMF feature string collection failed on bridge channel %p for some reason\n", bridge_channel);
+			break;
+		}
+
+		/* Add the above DTMF into the DTMF string so we can do our matching */
+		dtmf[dtmf_len++] = res;
+
+		ast_debug(1, "DTMF feature string on bridge channel %p is now '%s'\n", bridge_channel, dtmf);
+
+		/* Assume that we do not want to look for DTMF any longer */
+		look_for_dtmf = 0;
+
+		/* See if a DTMF feature hook matches or can match */
+		AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
+			/* If this hook matches just break out now */
+			if (!strcmp(hook->dtmf, dtmf)) {
+				ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on bridge channel %p\n", hook, dtmf, bridge_channel);
+				look_for_dtmf = 0;
+				break;
+			} else if (!strncmp(hook->dtmf, dtmf, dtmf_len)) {
+				ast_debug(1, "DTMF feature hook %p can match DTMF string '%s', it wants '%s', on bridge channel %p\n", hook, dtmf, hook->dtmf, bridge_channel);
+				look_for_dtmf = 1;
+			} else {
+				ast_debug(1, "DTMF feature hook %p does not match DTMF string '%s', it wants '%s', on bridge channel %p\n", hook, dtmf, hook->dtmf, bridge_channel);
+			}
+		}
+
+		/* If we have reached the maximum length of a DTMF feature string bail out */
+		if (dtmf_len == MAXIMUM_DTMF_FEATURE_STRING) {
+			break;
+		}
+	}
+
+	/* Since we are done bringing DTMF in return to using both begin and end frames */
+	ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_END_DTMF_ONLY);
+
+	/* If a hook was actually matched execute it on this channel, otherwise stream up the DTMF to the other channels */
+	if (hook) {
+		hook->callback(bridge, bridge_channel, hook->hook_pvt);
+		/* If we are handing the channel off to an external hook for ownership,
+		 * we are not guaranteed what kind of state it will come back in.  If
+		 * the channel hungup, we need to detect that here. */
+		if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
+			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+		}
+	} else {
+		ast_bridge_dtmf_stream(bridge, dtmf, bridge_channel->chan);
+	}
+
+	/* if the channel is still in feature state, revert it back to wait state */
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+	}
+
+	return;
+}
+
+static void bridge_channel_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+
+	if (features && features->talker_cb) {
+		features->talker_cb(bridge, bridge_channel, features->talker_pvt_data);
+	}
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+}
+
+/*! \brief Internal function that plays back DTMF on a bridge channel */
+static void bridge_channel_dtmf_stream(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	char dtmf_q[8] = "";
+
+	ast_copy_string(dtmf_q, bridge_channel->dtmf_stream_q, sizeof(dtmf_q));
+	bridge_channel->dtmf_stream_q[0] = '\0';
+
+	ast_debug(1, "Playing DTMF stream '%s' out to bridge channel %p\n", dtmf_q, bridge_channel);
+	ast_dtmf_stream(bridge_channel->chan, NULL, dtmf_q, 250, 0);
+
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+
+	return;
+}
+
+/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
+static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_format formats[2];
+	enum ast_bridge_channel_state state;
+	ast_format_copy(&formats[0], ast_channel_readformat(bridge_channel->chan));
+	ast_format_copy(&formats[1], ast_channel_writeformat(bridge_channel->chan));
+
+	/* Record the thread that will be the owner of us */
+	bridge_channel->thread = pthread_self();
+
+	ast_debug(1, "Joining bridge channel %p to bridge %p\n", bridge_channel, bridge_channel->bridge);
+
+	ao2_lock(bridge_channel->bridge);
+
+	if (!bridge_channel->bridge->callid) {
+		bridge_channel->bridge->callid = ast_read_threadstorage_callid();
+	}
+
+	state = bridge_channel->state;
+
+	/* Add channel into the bridge */
+	AST_LIST_INSERT_TAIL(&bridge_channel->bridge->channels, bridge_channel, entry);
+	bridge_channel->bridge->num++;
+
+	bridge_array_add(bridge_channel->bridge, bridge_channel->chan);
+
+	if (bridge_channel->swap) {
+		struct ast_bridge_channel *bridge_channel2 = NULL;
+
+		/* If we are performing a swap operation we do not need
+		 * to execute the smart bridge operation as the actual number
+		 * of channels involved will not have changed, we just need to
+		 * tell the other channel to leave */
+		if ((bridge_channel2 = find_bridge_channel(bridge_channel->bridge, bridge_channel->swap))) {
+			ast_debug(1, "Swapping bridge channel %p out from bridge %p so bridge channel %p can slip in\n", bridge_channel2, bridge_channel->bridge, bridge_channel);
+			ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+		}
+
+		bridge_channel->swap = NULL;
+	} else if (ast_test_flag(&bridge_channel->bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
+		/* Perform the smart bridge operation, basically see if we need to move around between technologies */
+		smart_bridge_operation(bridge_channel->bridge, bridge_channel, bridge_channel->bridge->num);
+	}
+
+	/* Make the channel compatible with the bridge */
+	bridge_make_compatible(bridge_channel->bridge, bridge_channel);
+
+	/* Tell the bridge technology we are joining so they set us up */
+	if (bridge_channel->bridge->technology->join) {
+		ast_debug(1, "Giving bridge technology %s notification that %p is joining bridge %p\n", bridge_channel->bridge->technology->name, bridge_channel, bridge_channel->bridge);
+		if (bridge_channel->bridge->technology->join(bridge_channel->bridge, bridge_channel)) {
+			ast_debug(1, "Bridge technology %s failed to join %p to bridge %p\n", bridge_channel->bridge->technology->name, bridge_channel, bridge_channel->bridge);
+		}
+	}
+
+	/* Actually execute the respective threading model, and keep our bridge thread alive */
+	while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		/* Update bridge pointer on channel */
+		ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
+		/* If the technology requires a thread and one is not running, start it up */
+		if (bridge_channel->bridge->thread == AST_PTHREADT_NULL && (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_THREAD)) {
+			bridge_channel->bridge->stop = 0;
+			ast_debug(1, "Starting a bridge thread for bridge %p\n", bridge_channel->bridge);
+			ao2_ref(bridge_channel->bridge, +1);
+			if (ast_pthread_create(&bridge_channel->bridge->thread, NULL, bridge_thread, bridge_channel->bridge)) {
+				ast_debug(1, "Failed to create a bridge thread for bridge %p, giving it another go.\n", bridge_channel->bridge);
+				ao2_ref(bridge_channel->bridge, -1);
+				continue;
+			}
+		}
+		/* Execute the threading model */
+		state = (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED ? bridge_channel_join_multithreaded(bridge_channel) : bridge_channel_join_singlethreaded(bridge_channel));
+		/* Depending on the above state see what we need to do */
+		switch (state) {
+		case AST_BRIDGE_CHANNEL_STATE_FEATURE:
+			bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+			ao2_unlock(bridge_channel->bridge);
+			bridge_channel_feature(bridge_channel->bridge, bridge_channel);
+			ao2_lock(bridge_channel->bridge);
+			bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+			break;
+		case AST_BRIDGE_CHANNEL_STATE_DTMF:
+			bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+			bridge_channel_dtmf_stream(bridge_channel->bridge, bridge_channel);
+			bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+			break;
+		case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
+		case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
+			ao2_unlock(bridge_channel->bridge);
+			bridge_channel_talking(bridge_channel->bridge, bridge_channel);
+			ao2_lock(bridge_channel->bridge);
+			break;
+		default:
+			break;
+		}
+	}
+
+	ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
+
+	/* See if we need to dissolve the bridge itself if they hung up */
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_END) {
+		bridge_check_dissolve(bridge_channel->bridge, bridge_channel);
+	}
+
+	/* Tell the bridge technology we are leaving so they tear us down */
+	if (bridge_channel->bridge->technology->leave) {
+		ast_debug(1, "Giving bridge technology %s notification that %p is leaving bridge %p\n", bridge_channel->bridge->technology->name, bridge_channel, bridge_channel->bridge);
+		if (bridge_channel->bridge->technology->leave(bridge_channel->bridge, bridge_channel)) {
+			ast_debug(1, "Bridge technology %s failed to leave %p from bridge %p\n", bridge_channel->bridge->technology->name, bridge_channel, bridge_channel->bridge);
+		}
+	}
+
+	/* Remove channel from the bridge */
+	bridge_channel->bridge->num--;
+	AST_LIST_REMOVE(&bridge_channel->bridge->channels, bridge_channel, entry);
+
+	bridge_array_remove(bridge_channel->bridge, bridge_channel->chan);
+
+	/* Perform the smart bridge operation if needed since a channel has left */
+	if (ast_test_flag(&bridge_channel->bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
+		smart_bridge_operation(bridge_channel->bridge, NULL, bridge_channel->bridge->num);
+	}
+
+	ao2_unlock(bridge_channel->bridge);
+
+	/* Restore original formats of the channel as they came in */
+	if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &formats[0]) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_debug(1, "Bridge is returning %p to read format %s(%u)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
+		if (ast_set_read_format(bridge_channel->chan, &formats[0])) {
+			ast_debug(1, "Bridge failed to return channel %p to read format %s(%u)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
+		}
+	}
+	if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), &formats[1]) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_debug(1, "Bridge is returning %p to write format %s(%u)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
+		if (ast_set_write_format(bridge_channel->chan, &formats[1])) {
+			ast_debug(1, "Bridge failed to return channel %p to write format %s(%u)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
+		}
+	}
+
+	return bridge_channel->state;
+}
+
+static void bridge_channel_destroy(void *obj)
+{
+	struct ast_bridge_channel *bridge_channel = obj;
+
+	if (bridge_channel->callid) {
+		bridge_channel->callid = ast_callid_unref(bridge_channel->callid);
+	}
+
+	if (bridge_channel->bridge) {
+		ao2_ref(bridge_channel->bridge, -1);
+		bridge_channel->bridge = NULL;
+	}
+	/* Destroy elements of the bridge channel structure and the bridge channel structure itself */
+	ast_cond_destroy(&bridge_channel->cond);
+}
+
+static struct ast_bridge_channel *bridge_channel_alloc(struct ast_bridge *bridge)
+{
+	struct ast_bridge_channel *bridge_channel = ao2_alloc(sizeof(struct ast_bridge_channel), bridge_channel_destroy);
+	if (!(bridge_channel)) {
+		return NULL;
+	}
+	ast_cond_init(&bridge_channel->cond, NULL);
+	if (bridge) {
+		bridge_channel->bridge = bridge;
+		ao2_ref(bridge_channel->bridge, +1);
+	}
+	return bridge_channel;
+}
+
+enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+	struct ast_channel *chan,
+	struct ast_channel *swap,
+	struct ast_bridge_features *features,
+	struct ast_bridge_tech_optimizations *tech_args)
+{
+	struct ast_bridge_channel *bridge_channel = bridge_channel_alloc(bridge);
+	enum ast_bridge_channel_state state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
+
+	if (!bridge_channel) {
+		return state;
+	}
+	if (tech_args) {
+		memcpy(&bridge_channel->tech_args, tech_args, sizeof(bridge_channel->tech_args));
+	}
+
+	/* Initialize various other elements of the bridge channel structure that we can't do above */
+	bridge_channel->chan = chan;
+	bridge_channel->swap = swap;
+	bridge_channel->features = features;
+
+	state = bridge_channel_join(bridge_channel);
+
+	/* Cleanup all the data in the bridge channel after it leaves the bridge. */
+	ao2_lock(bridge_channel);
+	bridge_channel->chan = NULL;
+	bridge_channel->swap = NULL;
+	bridge_channel->features = NULL;
+	ao2_unlock(bridge_channel);
+
+	ao2_ref(bridge_channel, -1);
+
+	return state;
+}
+
+/*! \brief Thread responsible for imparted bridged channels */
+static void *bridge_channel_thread(void *data)
+{
+	struct ast_bridge_channel *bridge_channel = data;
+	enum ast_bridge_channel_state state;
+
+	if (bridge_channel->callid) {
+		ast_callid_threadassoc_add(bridge_channel->callid);
+	}
+
+	state = bridge_channel_join(bridge_channel);
+
+	/* If no other thread is going to take the channel then hang it up, or else we would have to service it until something else came along */
+	if (bridge_channel->allow_impart_hangup
+		&& state != AST_BRIDGE_CHANNEL_STATE_DEPART) {
+		ast_hangup(bridge_channel->chan);
+
+		/* nobody is waiting to join me. */
+		pthread_detach(pthread_self());
+	}
+
+	/* cleanup */
+	ao2_lock(bridge_channel);
+	bridge_channel->chan = NULL;
+	bridge_channel->swap = NULL;
+	bridge_channel->features = NULL;
+	ao2_unlock(bridge_channel);
+
+	ao2_ref(bridge_channel, -1);
+
+	return NULL;
+}
+
+int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, int allow_hangup)
+{
+	struct ast_bridge_channel *bridge_channel = bridge_channel_alloc(bridge);
+
+	/* Try to allocate a structure for the bridge channel */
+	if (!(bridge_channel)) {
+		return -1;
+	}
+
+	/* Setup various parameters */
+	bridge_channel->chan = chan;
+	bridge_channel->swap = swap;
+	bridge_channel->features = features;
+	bridge_channel->allow_impart_hangup = allow_hangup;
+	bridge_channel->callid = ast_read_threadstorage_callid();
+
+	/* Actually create the thread that will handle the channel */
+	if (ast_pthread_create(&bridge_channel->thread, NULL, bridge_channel_thread, bridge_channel)) {
+		ao2_ref(bridge_channel, -1);
+		return -1;
+	}
+
+	return 0;
+}
+
+int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+	pthread_t thread;
+
+	ao2_lock(bridge);
+
+	/* Try to find the channel that we want to depart */
+	if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
+		ao2_unlock(bridge);
+		return -1;
+	}
+
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
+	thread = bridge_channel->thread;
+
+	ao2_unlock(bridge);
+
+	pthread_join(thread, NULL);
+
+	return 0;
+}
+
+int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+
+	ao2_lock(bridge);
+
+	/* Try to find the channel that we want to remove */
+	if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
+		ao2_unlock(bridge);
+		return -1;
+	}
+
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+
+	ao2_unlock(bridge);
+
+	return 0;
+}
+
+int ast_bridge_merge(struct ast_bridge *bridge0, struct ast_bridge *bridge1)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+
+	ao2_lock(bridge0);
+	ao2_lock(bridge1);
+
+	/* If the first bridge currently has 2 channels and is not capable of becoming a multimixing bridge we can not merge */
+	if ((bridge0->num + bridge1->num) > 2 && (!(bridge0->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) && !ast_test_flag(&bridge0->feature_flags, AST_BRIDGE_FLAG_SMART))) {
+		ao2_unlock(bridge1);
+		ao2_unlock(bridge0);
+		ast_debug(1, "Can't merge bridge %p into bridge %p, multimix is needed and it could not be acquired.\n", bridge1, bridge0);
+		return -1;
+	}
+
+	ast_debug(1, "Merging channels from bridge %p into bridge %p\n", bridge1, bridge0);
+
+	/* Perform smart bridge operation on bridge we are merging into so it can change bridge technology if needed */
+	if (smart_bridge_operation(bridge0, NULL, bridge0->num + bridge1->num)) {
+		ao2_unlock(bridge1);
+		ao2_unlock(bridge0);
+		ast_debug(1, "Can't merge bridge %p into bridge %p, tried to perform smart bridge operation and failed.\n", bridge1, bridge0);
+		return -1;
+	}
+
+	/* If a thread is currently executing on bridge1 tell it to stop */
+	if (bridge1->thread) {
+		ast_debug(1, "Telling bridge thread on bridge %p to stop as it is being merged into %p\n", bridge1, bridge0);
+		bridge1->thread = AST_PTHREADT_STOP;
+	}
+
+	/* Move channels from bridge1 over to bridge0 */
+	while ((bridge_channel = AST_LIST_REMOVE_HEAD(&bridge1->channels, entry))) {
+		/* Tell the technology handling bridge1 that the bridge channel is leaving */
+		if (bridge1->technology->leave) {
+			ast_debug(1, "Giving bridge technology %s notification that %p is leaving bridge %p\n", bridge1->technology->name, bridge_channel, bridge1);
+			if (bridge1->technology->leave(bridge1, bridge_channel)) {
+				ast_debug(1, "Bridge technology %s failed to allow %p to leave bridge %p\n", bridge1->technology->name, bridge_channel, bridge1);
+			}
+		}
+
+		/* Drop channel count and reference count on the bridge they are leaving */
+		bridge1->num--;
+		ao2_ref(bridge1, -1);
+
+		bridge_array_remove(bridge1, bridge_channel->chan);
+
+		/* Now add them into the bridge they are joining, increase channel count, and bump up reference count */
+		bridge_channel->bridge = bridge0;
+		AST_LIST_INSERT_TAIL(&bridge0->channels, bridge_channel, entry);
+		bridge0->num++;
+		ao2_ref(bridge0, +1);
+
+		bridge_array_add(bridge0, bridge_channel->chan);
+
+		/* Make the channel compatible with the new bridge it is joining or else formats would go amuck */
+		bridge_make_compatible(bridge0, bridge_channel);
+
+		/* Tell the technology handling bridge0 that the bridge channel is joining */
+		if (bridge0->technology->join) {
+			ast_debug(1, "Giving bridge technology %s notification that %p is joining bridge %p\n", bridge0->technology->name, bridge_channel, bridge0);
+			if (bridge0->technology->join(bridge0, bridge_channel)) {
+				ast_debug(1, "Bridge technology %s failed to join %p to bridge %p\n", bridge0->technology->name, bridge_channel, bridge0);
+			}
+		}
+
+		/* Poke the bridge channel, this will cause it to wake up and execute the proper threading model for the new bridge it is in */
+		pthread_kill(bridge_channel->thread, SIGURG);
+		ao2_lock(bridge_channel);
+		ast_cond_signal(&bridge_channel->cond);
+		ao2_unlock(bridge_channel);
+	}
+
+	ast_debug(1, "Merged channels from bridge %p into bridge %p\n", bridge1, bridge0);
+
+	ao2_unlock(bridge1);
+	ao2_unlock(bridge0);
+
+	return 0;
+}
+
+int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel;
+
+	ao2_lock(bridge);
+
+	if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
+		ao2_unlock(bridge);
+		return -1;
+	}
+
+	bridge_channel_suspend(bridge, bridge_channel);
+
+	ao2_unlock(bridge);
+
+	return 0;
+}
+
+int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel;
+
+	ao2_lock(bridge);
+
+	if (!(bridge_channel = find_bridge_channel(bridge, chan))) {
+		ao2_unlock(bridge);
+		return -1;
+	}
+
+	bridge_channel_unsuspend(bridge, bridge_channel);
+
+	ao2_unlock(bridge);
+
+	return 0;
+}
+
+void ast_bridge_technology_suspend(struct ast_bridge_technology *technology)
+{
+	technology->suspended = 1;
+	return;
+}
+
+void ast_bridge_technology_unsuspend(struct ast_bridge_technology *technology)
+{
+	technology->suspended = 0;
+	return;
+}
+
+int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_features_hook_callback callback, const char *dtmf)
+{
+	if (builtin_features_handlers[feature]) {
+		return -1;
+	}
+
+	if (!ast_strlen_zero(dtmf)) {
+		ast_copy_string(builtin_features_dtmf[feature], dtmf, sizeof(builtin_features_dtmf[feature]));
+	}
+
+	builtin_features_handlers[feature] = callback;
+
+	return 0;
+}
+
+int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
+{
+	if (!builtin_features_handlers[feature]) {
+		return -1;
+	}
+
+	builtin_features_handlers[feature] = NULL;
+
+	return 0;
+}
+
+int ast_bridge_features_hook(struct ast_bridge_features *features,
+	const char *dtmf,
+	ast_bridge_features_hook_callback callback,
+	void *hook_pvt,
+	ast_bridge_features_hook_pvt_destructor destructor)
+{
+	struct ast_bridge_features_hook *hook = NULL;
+
+	/* Allocate new memory and setup it's various variables */
+	if (!(hook = ast_calloc(1, sizeof(*hook)))) {
+		return -1;
+	}
+
+	ast_copy_string(hook->dtmf, dtmf, sizeof(hook->dtmf));
+	hook->callback = callback;
+	hook->destructor = destructor;
+	hook->hook_pvt = hook_pvt;
+
+	/* Once done we add it onto the list. Now it will be picked up when DTMF is used */
+	AST_LIST_INSERT_TAIL(&features->hooks, hook, entry);
+
+	features->usable = 1;
+
+	return 0;
+}
+
+int ast_bridge_features_set_talk_detector(struct ast_bridge_features *features,
+	ast_bridge_talking_indicate_callback talker_cb,
+	ast_bridge_talking_indicate_destructor talker_destructor,
+	void *pvt_data)
+{
+	features->talker_cb = talker_cb;
+	features->talker_destructor_cb = talker_destructor;
+	features->talker_pvt_data = pvt_data;
+	return 0;
+}
+
+int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config)
+{
+	/* If no alternate DTMF stream was provided use the default one */
+	if (ast_strlen_zero(dtmf)) {
+		dtmf = builtin_features_dtmf[feature];
+		/* If no DTMF is still available (ie: it has been disabled) then error out now */
+		if (ast_strlen_zero(dtmf)) {
+			ast_debug(1, "Failed to enable built in feature %u on %p, no DTMF string is available for it.\n", feature, features);
+			return -1;
+		}
+	}
+
+	if (!builtin_features_handlers[feature]) {
+		return -1;
+	}
+
+	/* The rest is basically pretty easy. We create another hook using the built in feature's callback and DTMF, easy as pie. */
+	return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config, NULL);
+}
+
+int ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag)
+{
+	ast_set_flag(&features->feature_flags, flag);
+	features->usable = 1;
+	return 0;
+}
+
+int ast_bridge_features_init(struct ast_bridge_features *features)
+{
+	/* Zero out the structure */
+	memset(features, 0, sizeof(*features));
+
+	/* Initialize the hooks list, just in case */
+	AST_LIST_HEAD_INIT_NOLOCK(&features->hooks);
+
+	return 0;
+}
+
+int ast_bridge_features_cleanup(struct ast_bridge_features *features)
+{
+	struct ast_bridge_features_hook *hook = NULL;
+
+	/* This is relatively simple, hooks are kept as a list on the features structure so we just pop them off and free them */
+	while ((hook = AST_LIST_REMOVE_HEAD(&features->hooks, entry))) {
+		if (hook->destructor) {
+			hook->destructor(hook->hook_pvt);
+		}
+		ast_free(hook);
+	}
+	if (features->talker_destructor_cb && features->talker_pvt_data) {
+		features->talker_destructor_cb(features->talker_pvt_data);
+		features->talker_pvt_data = NULL;
+	}
+
+	return 0;
+}
+
+int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel = NULL;
+
+	ao2_lock(bridge);
+
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+		if (bridge_channel->chan == chan) {
+			continue;
+		}
+		ast_copy_string(bridge_channel->dtmf_stream_q, dtmf, sizeof(bridge_channel->dtmf_stream_q));
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DTMF);
+	}
+
+	ao2_unlock(bridge);
+
+	return 0;
+}
+
+void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
+{
+	ao2_lock(bridge);
+	bridge->internal_mixing_interval = mixing_interval;
+	ao2_unlock(bridge);
+}
+
+void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
+{
+
+	ao2_lock(bridge);
+	bridge->internal_sample_rate = sample_rate;
+	ao2_unlock(bridge);
+}
+
+static void cleanup_video_mode(struct ast_bridge *bridge)
+{
+	switch (bridge->video_mode.mode) {
+	case AST_BRIDGE_VIDEO_MODE_NONE:
+		break;
+	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+		if (bridge->video_mode.mode_data.single_src_data.chan_vsrc) {
+			ast_channel_unref(bridge->video_mode.mode_data.single_src_data.chan_vsrc);
+		}
+		break;
+	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+		if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc) {
+			ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_vsrc);
+		}
+		if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) {
+			ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc);
+		}
+	}
+	memset(&bridge->video_mode, 0, sizeof(bridge->video_mode));
+}
+
+void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
+{
+	ao2_lock(bridge);
+	cleanup_video_mode(bridge);
+	bridge->video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
+	bridge->video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
+	ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s", bridge->video_mode.mode, ast_channel_name(video_src_chan));
+	ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
+	ao2_unlock(bridge);
+}
+
+void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
+{
+	ao2_lock(bridge);
+	cleanup_video_mode(bridge);
+	bridge->video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC;
+	ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %u", bridge->video_mode.mode);
+	ao2_unlock(bridge);
+}
+
+void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe)
+{
+	struct ast_bridge_video_talker_src_data *data;
+	/* If the channel doesn't support video, we don't care about it */
+	if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO)) {
+		return;
+	}
+
+	ao2_lock(bridge);
+	data = &bridge->video_mode.mode_data.talker_src_data;
+
+	if (data->chan_vsrc == chan) {
+		data->average_talking_energy = talker_energy;
+	} else if ((data->average_talking_energy < talker_energy) && is_keyframe) {
+		if (data->chan_old_vsrc) {
+			ast_channel_unref(data->chan_old_vsrc);
+		}
+		if (data->chan_vsrc) {
+			data->chan_old_vsrc = data->chan_vsrc;
+			ast_indicate(data->chan_old_vsrc, AST_CONTROL_VIDUPDATE);
+		}
+		data->chan_vsrc = ast_channel_ref(chan);
+		data->average_talking_energy = talker_energy;
+		ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+		ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE);
+	} else if ((data->average_talking_energy < talker_energy) && !is_keyframe) {
+		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+	} else if (!data->chan_vsrc && is_keyframe) {
+		data->chan_vsrc = ast_channel_ref(chan);
+		data->average_talking_energy = talker_energy;
+		ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+	} else if (!data->chan_old_vsrc && is_keyframe) {
+		data->chan_old_vsrc = ast_channel_ref(chan);
+		ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+	}
+	ao2_unlock(bridge);
+}
+
+int ast_bridge_number_video_src(struct ast_bridge *bridge)
+{
+	int res = 0;
+
+	ao2_lock(bridge);
+	switch (bridge->video_mode.mode) {
+	case AST_BRIDGE_VIDEO_MODE_NONE:
+		break;
+	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+		if (bridge->video_mode.mode_data.single_src_data.chan_vsrc) {
+			res = 1;
+		}
+		break;
+	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+		if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc) {
+			res++;
+		}
+		if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) {
+			res++;
+		}
+	}
+	ao2_unlock(bridge);
+	return res;
+}
+
+int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	int res = 0;
+
+	ao2_lock(bridge);
+	switch (bridge->video_mode.mode) {
+	case AST_BRIDGE_VIDEO_MODE_NONE:
+		break;
+	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+		if (bridge->video_mode.mode_data.single_src_data.chan_vsrc == chan) {
+			res = 1;
+		}
+		break;
+	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+		if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc == chan) {
+			res = 1;
+		} else if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) {
+			res = 2;
+		}
+
+	}
+	ao2_unlock(bridge);
+	return res;
+}
+
+void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	ao2_lock(bridge);
+	switch (bridge->video_mode.mode) {
+	case AST_BRIDGE_VIDEO_MODE_NONE:
+		break;
+	case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+		if (bridge->video_mode.mode_data.single_src_data.chan_vsrc == chan) {
+			if (bridge->video_mode.mode_data.single_src_data.chan_vsrc) {
+				ast_channel_unref(bridge->video_mode.mode_data.single_src_data.chan_vsrc);
+			}
+			bridge->video_mode.mode_data.single_src_data.chan_vsrc = NULL;
+		}
+		break;
+	case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+		if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc == chan) {
+			if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc) {
+				ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_vsrc);
+			}
+			bridge->video_mode.mode_data.talker_src_data.chan_vsrc = NULL;
+			bridge->video_mode.mode_data.talker_src_data.average_talking_energy = 0;
+		}
+		if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) {
+			if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) {
+				ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc);
+			}
+			bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL;
+		}
+	}
+	ao2_unlock(bridge);
+}
diff --git a/main/bucket.c b/main/bucket.c
deleted file mode 100644
index 8fb4e65..0000000
--- a/main/bucket.c
+++ /dev/null
@@ -1,965 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Bucket File API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<use type="external">uriparser</use>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-        <configInfo name="core" language="en_US">
-                <synopsis>Bucket file API</synopsis>
-                <configFile name="bucket">
-                        <configObject name="bucket">
-                                <configOption name="scheme">
-                                        <synopsis>Scheme in use for bucket</synopsis>
-                                </configOption>
-                                <configOption name="created">
-                                        <synopsis>Time at which the bucket was created</synopsis>
-                                </configOption>
-                                <configOption name="modified">
-                                        <synopsis>Time at which the bucket was last modified</synopsis>
-                                </configOption>
-                        </configObject>
-                        <configObject name="file">
-                                <configOption name="scheme">
-                                        <synopsis>Scheme in use for file</synopsis>
-                                </configOption>
-                                <configOption name="created">
-                                        <synopsis>Time at which the file was created</synopsis>
-                                </configOption>
-                                <configOption name="modified">
-                                        <synopsis>Time at which the file was last modified</synopsis>
-                                </configOption>
-                        </configObject>
-                </configFile>
-        </configInfo>
-***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
-
-#ifdef HAVE_URIPARSER
-#include <uriparser/Uri.h>
-#endif
-
-#include "asterisk/logger.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/bucket.h"
-#include "asterisk/config_options.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-#include "asterisk/json.h"
-#include "asterisk/file.h"
-#include "asterisk/module.h"
-
-/*! \brief Number of buckets for the container of schemes */
-#define SCHEME_BUCKETS 53
-
-/*! \brief Number of buckets for the container of metadata in a file */
-#define METADATA_BUCKETS 53
-
-/*! \brief Sorcery instance for all bucket operations */
-static struct ast_sorcery *bucket_sorcery;
-
-/*! \brief Container of registered schemes */
-static struct ao2_container *schemes;
-
-/*! \brief Structure for available schemes */
-struct ast_bucket_scheme {
-	/*! \brief Wizard for buckets */
-	struct ast_sorcery_wizard *bucket;
-	/*! \brief Wizard for files */
-	struct ast_sorcery_wizard *file;
-	/*! \brief Pointer to the file snapshot creation callback */
-	bucket_file_create_cb create;
-	/*! \brief Pointer to the file snapshot destruction callback */
-	bucket_file_destroy_cb destroy;
-	/*! \brief Name of the scheme */
-	char name[0];
-};
-
-/*! \brief Callback function for creating a bucket */
-static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	struct ast_bucket *bucket = object;
-
-	return bucket->scheme_impl->bucket->create(sorcery, data, object);
-}
-
-/*! \brief Callback function for retrieving a bucket */
-static void *bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
-	const char *id)
-{
-#ifdef HAVE_URIPARSER
-	UriParserStateA state;
-	UriUriA uri;
-	size_t len;
-#else
-	char *tmp = ast_strdupa(id);
-#endif
-	SCOPED_AO2RDLOCK(lock, schemes);
-	char *uri_scheme;
-	RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
-
-#ifdef HAVE_URIPARSER
-	state.uri = &uri;
-	if (uriParseUriA(&state, id) != URI_SUCCESS ||
-		!uri.scheme.first || !uri.scheme.afterLast) {
-		uriFreeUriMembersA(&uri);
-		return NULL;
-	}
-
-	len = (uri.scheme.afterLast - uri.scheme.first) + 1;
-	uri_scheme = ast_alloca(len);
-	ast_copy_string(uri_scheme, uri.scheme.first, len);
-
-	uriFreeUriMembersA(&uri);
-#else
-	uri_scheme = tmp;
-	if (!(tmp = strchr(uri_scheme, ':'))) {
-		return NULL;
-	}
-	*tmp = '\0';
-#endif
-
-	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
-
-	if (!scheme) {
-		return NULL;
-	}
-
-	return scheme->bucket->retrieve_id(sorcery, data, type, id);
-}
-
-/*! \brief Callback function for deleting a bucket */
-static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	struct ast_bucket *bucket = object;
-
-	return bucket->scheme_impl->bucket->delete(sorcery, data, object);
-}
-
-/*! \brief Intermediary bucket wizard */
-static struct ast_sorcery_wizard bucket_wizard = {
-	.name = "bucket",
-	.create = bucket_wizard_create,
-	.retrieve_id = bucket_wizard_retrieve,
-	.delete = bucket_wizard_delete,
-};
-
-/*! \brief Callback function for creating a bucket file */
-static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	struct ast_bucket_file *file = object;
-
-	return file->scheme_impl->file->create(sorcery, data, object);
-}
-
-/*! \brief Callback function for retrieving a bucket file */
-static void *bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
-	const char *id)
-{
-#ifdef HAVE_URIPARSER
-	UriParserStateA state;
-	UriUriA uri;
-	size_t len;
-#else
-	char *tmp = ast_strdupa(id);
-#endif
-	char *uri_scheme;
-	SCOPED_AO2RDLOCK(lock, schemes);
-	RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
-
-#ifdef HAVE_URIPARSER
-	state.uri = &uri;
-	if (uriParseUriA(&state, id) != URI_SUCCESS ||
-		!uri.scheme.first || !uri.scheme.afterLast) {
-		uriFreeUriMembersA(&uri);
-		return NULL;
-	}
-
-	len = (uri.scheme.afterLast - uri.scheme.first) + 1;
-	uri_scheme = ast_alloca(len);
-	ast_copy_string(uri_scheme, uri.scheme.first, len);
-
-	uriFreeUriMembersA(&uri);
-#else
-	uri_scheme = tmp;
-	if (!(tmp = strchr(uri_scheme, ':'))) {
-		return NULL;
-	}
-	*tmp = '\0';
-#endif
-
-	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
-
-	if (!scheme) {
-		return NULL;
-	}
-
-	return scheme->file->retrieve_id(sorcery, data, type, id);
-}
-
-/*! \brief Callback function for updating a bucket file */
-static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	struct ast_bucket_file *file = object;
-
-	return file->scheme_impl->file->update(sorcery, data, object);
-}
-
-/*! \brief Callback function for deleting a bucket file */
-static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	struct ast_bucket_file *file = object;
-
-	return file->scheme_impl->file->delete(sorcery, data, object);
-}
-
-/*! \brief Intermediary file wizard */
-static struct ast_sorcery_wizard bucket_file_wizard = {
-	.name = "bucket_file",
-	.create = bucket_file_wizard_create,
-	.retrieve_id = bucket_file_wizard_retrieve,
-	.update = bucket_file_wizard_update,
-	.delete = bucket_file_wizard_delete,
-};
-
-int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket,
-	struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb,
-	bucket_file_destroy_cb destroy_cb, struct ast_module *module)
-{
-	SCOPED_AO2WRLOCK(lock, schemes);
-	RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(name) || !bucket || !file ||
-	    !bucket->create || !bucket->delete || !bucket->retrieve_id ||
-	    !create_cb) {
-		return -1;
-	}
-
-	scheme = ao2_find(schemes, name, OBJ_KEY | OBJ_NOLOCK);
-	if (scheme) {
-		return -1;
-	}
-
-	scheme = ao2_alloc(sizeof(*scheme) + strlen(name) + 1, NULL);
-	if (!scheme) {
-		return -1;
-	}
-
-	strcpy(scheme->name, name);
-	scheme->bucket = bucket;
-	scheme->file = file;
-	scheme->create = create_cb;
-	scheme->destroy = destroy_cb;
-
-	ao2_link_flags(schemes, scheme, OBJ_NOLOCK);
-
-	ast_verb(2, "Registered bucket scheme '%s'\n", name);
-
-	ast_module_ref(module);
-
-	return 0;
-}
-
-/*! \brief Allocator for metadata attributes */
-static struct ast_bucket_metadata *bucket_metadata_alloc(const char *name, const char *value)
-{
-	int name_len = strlen(name) + 1, value_len = strlen(value) + 1;
-	struct ast_bucket_metadata *metadata = ao2_alloc(sizeof(*metadata) + name_len + value_len, NULL);
-	char *dst;
-
-	if (!metadata) {
-		return NULL;
-	}
-
-	dst = metadata->data;
-	metadata->name = strcpy(dst, name);
-	dst += name_len;
-	metadata->value = strcpy(dst, value);
-
-	return metadata;
-}
-
-int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
-{
-	RAII_VAR(struct ast_bucket_metadata *, metadata, bucket_metadata_alloc(name, value), ao2_cleanup);
-
-	if (!metadata) {
-		return -1;
-	}
-
-	ao2_find(file->metadata, name, OBJ_NODATA | OBJ_UNLINK | OBJ_KEY);
-	ao2_link(file->metadata, metadata);
-
-	return 0;
-}
-
-int ast_bucket_file_metadata_unset(struct ast_bucket_file *file, const char *name)
-{
-	RAII_VAR(struct ast_bucket_metadata *, metadata, ao2_find(file->metadata, name, OBJ_UNLINK | OBJ_KEY), ao2_cleanup);
-
-	if (!metadata) {
-		return -1;
-	}
-
-	return 0;
-}
-
-struct ast_bucket_metadata *ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
-{
-	return ao2_find(file->metadata, name, OBJ_KEY);
-}
-
-/*! \brief Destructor for buckets */
-static void bucket_destroy(void *obj)
-{
-	struct ast_bucket *bucket = obj;
-
-	ao2_cleanup(bucket->scheme_impl);
-	ast_string_field_free_memory(bucket);
-	ao2_cleanup(bucket->buckets);
-	ao2_cleanup(bucket->files);
-}
-
-/*! \brief Sorting function for red black tree string container */
-static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
-	const char *str_left = obj_left;
-	const char *str_right = obj_right;
-	int cmp = 0;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-	case OBJ_KEY:
-		cmp = strcmp(str_left, str_right);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(str_left, str_right, strlen(str_right));
-		break;
-	}
-	return cmp;
-}
-
-/*! \brief Allocator for buckets */
-static void *bucket_alloc(const char *name)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-
-	bucket = ast_sorcery_generic_alloc(sizeof(*bucket), bucket_destroy);
-	if (!bucket) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(bucket, 128)) {
-		return NULL;
-	}
-
-	bucket->buckets = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, bucket_rbtree_str_sort_cmp, NULL);
-	if (!bucket->buckets) {
-		return NULL;
-	}
-
-	bucket->files = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, bucket_rbtree_str_sort_cmp, NULL);
-	if (!bucket->files) {
-		return NULL;
-	}
-
-	ao2_ref(bucket, +1);
-	return bucket;
-}
-
-struct ast_bucket *ast_bucket_alloc(const char *uri)
-{
-#ifdef HAVE_URIPARSER
-	UriParserStateA state;
-	UriUriA full_uri;
-	size_t len;
-#else
-	char *tmp = ast_strdupa(uri);
-#endif
-	char *uri_scheme;
-	RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
-	struct ast_bucket *bucket;
-
-	if (ast_strlen_zero(uri)) {
-		return NULL;
-	}
-
-#ifdef HAVE_URIPARSER
-	state.uri = &full_uri;
-	if (uriParseUriA(&state, uri) != URI_SUCCESS ||
-		!full_uri.scheme.first || !full_uri.scheme.afterLast ||
-		!full_uri.pathTail) {
-		uriFreeUriMembersA(&full_uri);
-		return NULL;
-	}
-
-	len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
-	uri_scheme = ast_alloca(len);
-	ast_copy_string(uri_scheme, full_uri.scheme.first, len);
-
-	uriFreeUriMembersA(&full_uri);
-#else
-	uri_scheme = tmp;
-	if (!(tmp = strchr(uri_scheme, ':'))) {
-		return NULL;
-	}
-	*tmp = '\0';
-#endif
-
-	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
-	if (!scheme) {
-		return NULL;
-	}
-
-	bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri);
-	if (!bucket) {
-		return NULL;
-	}
-
-	ao2_ref(scheme, +1);
-	bucket->scheme_impl = scheme;
-
-	ast_string_field_set(bucket, scheme, uri_scheme);
-
-	return bucket;
-}
-
-int ast_bucket_create(struct ast_bucket *bucket)
-{
-	return ast_sorcery_create(bucket_sorcery, bucket);
-}
-
-struct ast_bucket *ast_bucket_retrieve(const char *uri)
-{
-	if (ast_strlen_zero(uri)) {
-		return NULL;
-	}
-
-	return ast_sorcery_retrieve_by_id(bucket_sorcery, "bucket", uri);
-}
-
-int ast_bucket_observer_add(const struct ast_sorcery_observer *callbacks)
-{
-	return ast_sorcery_observer_add(bucket_sorcery, "bucket", callbacks);
-}
-
-void ast_bucket_observer_remove(const struct ast_sorcery_observer *callbacks)
-{
-	ast_sorcery_observer_remove(bucket_sorcery, "bucket", callbacks);
-}
-
-int ast_bucket_delete(struct ast_bucket *bucket)
-{
-	return ast_sorcery_delete(bucket_sorcery, bucket);
-}
-
-struct ast_json *ast_bucket_json(const struct ast_bucket *bucket)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json *id, *files, *buckets;
-	struct ao2_iterator i;
-	char *uri;
-	int res = 0;
-
-	json = ast_sorcery_objectset_json_create(bucket_sorcery, bucket);
-	if (!json) {
-		return NULL;
-	}
-
-	id = ast_json_string_create(ast_sorcery_object_get_id(bucket));
-	if (!id) {
-		return NULL;
-	}
-
-	if (ast_json_object_set(json, "id", id)) {
-		return NULL;
-	}
-
-	buckets = ast_json_array_create();
-	if (!buckets) {
-		return NULL;
-	}
-
-	if (ast_json_object_set(json, "buckets", buckets)) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(bucket->buckets, 0);
-	for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
-		struct ast_json *bucket_uri = ast_json_string_create(uri);
-
-		if (!bucket_uri || ast_json_array_append(buckets, bucket_uri)) {
-			res = -1;
-			ao2_ref(uri, -1);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	if (res) {
-		return NULL;
-	}
-
-	files = ast_json_array_create();
-	if (!files) {
-		return NULL;
-	}
-
-	if (ast_json_object_set(json, "files", files)) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(bucket->files, 0);
-	for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
-		struct ast_json *file_uri = ast_json_string_create(uri);
-
-		if (!file_uri || ast_json_array_append(files, file_uri)) {
-			res = -1;
-			ao2_ref(uri, -1);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	if (res) {
-		return NULL;
-	}
-
-	ast_json_ref(json);
-	return json;
-}
-
-/*! \brief Hashing function for file metadata */
-static int bucket_file_metadata_hash(const void *obj, const int flags)
-{
-	const struct ast_bucket_metadata *object;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_POINTER:
-		object = obj;
-		return ast_str_hash(object->name);
-	default:
-		/* Hash can only work on something with a full key */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-/*! \brief Comparison function for file metadata */
-static int bucket_file_metadata_cmp(void *obj, void *arg, int flags)
-{
-	struct ast_bucket_metadata *metadata1 = obj, *metadata2 = arg;
-	const char *name = arg;
-
-	return !strcmp(metadata1->name, flags & OBJ_KEY ? name : metadata2->name) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Destructor for bucket files */
-static void bucket_file_destroy(void *obj)
-{
-	struct ast_bucket_file *file = obj;
-
-	if (file->scheme_impl->destroy) {
-		file->scheme_impl->destroy(file);
-	}
-
-	ao2_cleanup(file->scheme_impl);
-	ao2_cleanup(file->metadata);
-}
-
-/*! \brief Allocator for bucket files */
-static void *bucket_file_alloc(const char *name)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	file = ast_sorcery_generic_alloc(sizeof(*file), bucket_file_destroy);
-	if (!file) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(file, 128)) {
-		return NULL;
-	}
-
-	file->metadata = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, METADATA_BUCKETS,
-		bucket_file_metadata_hash, bucket_file_metadata_cmp);
-	if (!file->metadata) {
-		return NULL;
-	}
-
-	ao2_ref(file, +1);
-	return file;
-}
-
-struct ast_bucket_file *ast_bucket_file_alloc(const char *uri)
-{
-#ifdef HAVE_URIPARSER
-	UriParserStateA state;
-	UriUriA full_uri;
-	size_t len;
-#else
-	char *tmp = ast_strdupa(uri);
-#endif
-	char *uri_scheme;
-	RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
-	struct ast_bucket_file *file;
-
-	if (ast_strlen_zero(uri)) {
-		return NULL;
-	}
-
-#ifdef HAVE_URIPARSER
-	state.uri = &full_uri;
-	if (uriParseUriA(&state, uri) != URI_SUCCESS ||
-		!full_uri.scheme.first || !full_uri.scheme.afterLast ||
-		!full_uri.pathTail) {
-		uriFreeUriMembersA(&full_uri);
-		return NULL;
-	}
-
-	len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
-	uri_scheme = ast_alloca(len);
-	ast_copy_string(uri_scheme, full_uri.scheme.first, len);
-
-	uriFreeUriMembersA(&full_uri);
-#else
-	uri_scheme = tmp;
-	if (!(tmp = strchr(uri_scheme, ':'))) {
-		return NULL;
-	}
-	*tmp = '\0';
-#endif
-
-	scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
-	if (!scheme) {
-		return NULL;
-	}
-
-	file = ast_sorcery_alloc(bucket_sorcery, "file", uri);
-	if (!file) {
-		return NULL;
-	}
-
-	ao2_ref(scheme, +1);
-	file->scheme_impl = scheme;
-
-	ast_string_field_set(file, scheme, uri_scheme);
-
-	if (scheme->create(file)) {
-		ao2_ref(file, -1);
-		return NULL;
-	}
-
-	return file;
-}
-
-int ast_bucket_file_create(struct ast_bucket_file *file)
-{
-	return ast_sorcery_create(bucket_sorcery, file);
-}
-
-/*! \brief Copy a file, shamelessly taken from file.c */
-static int bucket_copy(const char *infile, const char *outfile)
-{
-	int ifd, ofd, len;
-	char buf[4096];	/* XXX make it lerger. */
-
-	if ((ifd = open(infile, O_RDONLY)) < 0) {
-		ast_log(LOG_WARNING, "Unable to open %s in read-only mode, error: %s\n", infile, strerror(errno));
-		return -1;
-	}
-	if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
-		ast_log(LOG_WARNING, "Unable to open %s in write-only mode, error: %s\n", outfile, strerror(errno));
-		close(ifd);
-		return -1;
-	}
-	while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
-		int res;
-		if (len < 0) {
-			ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
-			break;
-		}
-		/* XXX handle partial writes */
-		res = write(ofd, buf, len);
-		if (res != len) {
-			ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
-			len = -1; /* error marker */
-			break;
-		}
-	}
-	close(ifd);
-	close(ofd);
-	if (len < 0) {
-		unlink(outfile);
-		return -1; /* error */
-	}
-	return 0;	/* success */
-}
-
-struct ast_bucket_file *ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri)
-{
-	RAII_VAR(struct ast_bucket_file *, copy, ast_bucket_file_alloc(uri), ao2_cleanup);
-
-	if (!copy) {
-		return NULL;
-	}
-
-	ao2_cleanup(copy->metadata);
-	copy->metadata = ao2_container_clone(file->metadata, 0);
-	if (!copy->metadata ||
-		bucket_copy(file->path, copy->path)) {
-		return NULL;
-	}
-
-	ao2_ref(copy, +1);
-	return copy;
-}
-
-struct ast_bucket_file *ast_bucket_file_retrieve(const char *uri)
-{
-	if (ast_strlen_zero(uri)) {
-		return NULL;
-	}
-
-	return ast_sorcery_retrieve_by_id(bucket_sorcery, "file", uri);
-}
-
-int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks)
-{
-	return ast_sorcery_observer_add(bucket_sorcery, "file", callbacks);
-}
-
-void ast_bucket_file_observer_remove(const struct ast_sorcery_observer *callbacks)
-{
-	ast_sorcery_observer_remove(bucket_sorcery, "file", callbacks);
-}
-
-int ast_bucket_file_update(struct ast_bucket_file *file)
-{
-	return ast_sorcery_update(bucket_sorcery, file);
-}
-
-int ast_bucket_file_delete(struct ast_bucket_file *file)
-{
-	return ast_sorcery_delete(bucket_sorcery, file);
-}
-
-struct ast_json *ast_bucket_file_json(const struct ast_bucket_file *file)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json *id, *metadata;
-	struct ao2_iterator i;
-	struct ast_bucket_metadata *attribute;
-	int res = 0;
-
-	json = ast_sorcery_objectset_json_create(bucket_sorcery, file);
-	if (!json) {
-		return NULL;
-	}
-
-	id = ast_json_string_create(ast_sorcery_object_get_id(file));
-	if (!id) {
-		return NULL;
-	}
-
-	if (ast_json_object_set(json, "id", id)) {
-		return NULL;
-	}
-
-	metadata = ast_json_object_create();
-	if (!metadata) {
-		return NULL;
-	}
-
-	if (ast_json_object_set(json, "metadata", metadata)) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(file->metadata, 0);
-	for (; (attribute = ao2_iterator_next(&i)); ao2_ref(attribute, -1)) {
-		struct ast_json *value = ast_json_string_create(attribute->value);
-
-		if (!value || ast_json_object_set(metadata, attribute->name, value)) {
-			res = -1;
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	if (res) {
-		return NULL;
-	}
-
-	ast_json_ref(json);
-	return json;
-}
-
-int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
-{
-	int fd;
-
-	ast_copy_string(file->path, "/tmp/bucket-XXXXXX", sizeof(file->path));
-
-	fd = mkstemp(file->path);
-	if (fd < 0) {
-		return -1;
-	}
-
-	close(fd);
-	return 0;
-}
-
-void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file)
-{
-	if (!ast_strlen_zero(file->path)) {
-		unlink(file->path);
-	}
-}
-
-/*! \brief Hashing function for scheme container */
-static int bucket_scheme_hash(const void *obj, const int flags)
-{
-	const struct ast_bucket_scheme *object;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_POINTER:
-		object = obj;
-		return ast_str_hash(object->name);
-	default:
-		/* Hash can only work on something with a full key */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-/*! \brief Comparison function for scheme container */
-static int bucket_scheme_cmp(void *obj, void *arg, int flags)
-{
-	struct ast_bucket_scheme *scheme1 = obj, *scheme2 = arg;
-	const char *name = arg;
-
-	return !strcmp(scheme1->name, flags & OBJ_KEY ? name : scheme2->name) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Cleanup function for graceful shutdowns */
-static void bucket_cleanup(void)
-{
-	if (bucket_sorcery) {
-		ast_sorcery_unref(bucket_sorcery);
-	}
-
-	ast_sorcery_wizard_unregister(&bucket_wizard);
-	ast_sorcery_wizard_unregister(&bucket_file_wizard);
-
-	ao2_cleanup(schemes);
-}
-
-/*! \brief Custom handler for translating from a string timeval to actual structure */
-static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct timeval *field = (struct timeval *)(obj + aco_option_get_argument(opt, 0));
-	return ast_get_timeval(var->value, field, ast_tv(0, 0), NULL);
-}
-
-/*! \brief Custom handler for translating from an actual structure timeval to string */
-static int timeval_struct2str(const void *obj, const intptr_t *args, char **buf)
-{
-	struct timeval *field = (struct timeval *)(obj + args[0]);
-	return (ast_asprintf(buf, "%lu.%06lu", (unsigned long)field->tv_sec, (unsigned long)field->tv_usec) < 0) ? -1 : 0;
-}
-
-/*! \brief Initialize bucket support */
-int ast_bucket_init(void)
-{
-	ast_register_cleanup(&bucket_cleanup);
-
-	schemes = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, SCHEME_BUCKETS, bucket_scheme_hash,
-		bucket_scheme_cmp);
-	if (!schemes) {
-		ast_log(LOG_ERROR, "Failed to create container for Bucket schemes\n");
-		return -1;
-	}
-
-	if (__ast_sorcery_wizard_register(&bucket_wizard, NULL)) {
-		ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'bucket' intermediary\n");
-		return -1;
-	}
-
-	if (__ast_sorcery_wizard_register(&bucket_file_wizard, NULL)) {
-		ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'file' intermediary\n");
-		return -1;
-	}
-
-	if (!(bucket_sorcery = ast_sorcery_open())) {
-		ast_log(LOG_ERROR, "Failed to create sorcery instance for Bucket support\n");
-		return -1;
-	}
-
-	if (ast_sorcery_apply_default(bucket_sorcery, "bucket", "bucket", NULL) == AST_SORCERY_APPLY_FAIL) {
-		ast_log(LOG_ERROR, "Failed to apply intermediary for 'bucket' object type in Bucket sorcery\n");
-		return -1;
-	}
-
-	if (ast_sorcery_object_register(bucket_sorcery, "bucket", bucket_alloc, NULL, NULL)) {
-		ast_log(LOG_ERROR, "Failed to register 'bucket' object type in Bucket sorcery\n");
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(bucket_sorcery, "bucket", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket, scheme));
-	ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "created", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket, created));
-	ast_sorcery_object_field_register_custom(bucket_sorcery, "bucket", "modified", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket, modified));
-
-	if (ast_sorcery_apply_default(bucket_sorcery, "file", "bucket_file", NULL) == AST_SORCERY_APPLY_FAIL) {
-		ast_log(LOG_ERROR, "Failed to apply intermediary for 'file' object type in Bucket sorcery\n");
-		return -1;
-	}
-
-	if (ast_sorcery_object_register(bucket_sorcery, "file", bucket_file_alloc, NULL, NULL)) {
-		ast_log(LOG_ERROR, "Failed to register 'file' object type in Bucket sorcery\n");
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(bucket_sorcery, "file", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket_file, scheme));
-	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "created", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket_file, created));
-	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "modified", "", timeval_str2struct, timeval_struct2str, NULL, 0, FLDSET(struct ast_bucket_file, modified));
-
-	return 0;
-}
diff --git a/main/callerid.c b/main/callerid.c
index 2e96c35..c111e44 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425155 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 #include <math.h>
@@ -42,7 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425155 $")
 #include "asterisk/callerid.h"
 #include "asterisk/fskmodem.h"
 #include "asterisk/utils.h"
-#include "asterisk/format_cache.h"
 
 struct callerid_state {
 	fsk_data fskd;
@@ -1239,17 +1238,12 @@ const char *ast_redirecting_reason_describe(int data)
 	return "not-known";
 }
 
-const char *ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data)
+const char *ast_redirecting_reason_name(int data)
 {
 	int index;
 
-	if (!ast_strlen_zero(data->str)) {
-		/* Use this string if it has been set. Otherwise, use the table. */
-		return data->str;
-	}
-
 	for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
-		if (redirecting_reason_types[index].value == data->code) {
+		if (redirecting_reason_types[index].value == data) {
 			return redirecting_reason_types[index].name;
 		}
 	}
diff --git a/main/ccss.c b/main/ccss.c
index 05e8b16..aeb902d 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -21,22 +21,13 @@
  * \author Mark Michelson <mmichelson at digium.com>
  */
 
-/*! \li \ref ccss.c uses the configuration file \ref ccss.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page ccss.conf ccss.conf
- * \verbinclude ccss.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/astobj2.h"
 #include "asterisk/strings.h"
@@ -45,14 +36,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
 #include "asterisk/taskprocessor.h"
+#include "asterisk/event.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
 #include "asterisk/cli.h"
 #include "asterisk/manager.h"
 #include "asterisk/causes.h"
-#include "asterisk/stasis_system.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="CallCompletionRequest" language="en_US">
@@ -575,11 +565,9 @@ static enum ast_device_state cc_state_to_devstate_map[] = {
 };
 
 /*!
- * \internal
+ * \intenral
  * \brief lookup the ast_device_state mapped to cc_state
  *
- * \param state
- *
  * \return the correponding DEVICE STATE from the cc_state_to_devstate_map
  * when passed an internal state.
  */
@@ -825,7 +813,7 @@ int ast_cc_set_param(struct ast_cc_config_params *params, const char * const nam
 		return 0;
 	}
 
-	if (!sscanf(value, "%30u", &value_as_uint) == 1) {
+	if (sscanf(value, "%30u", &value_as_uint) != 1) {
 		return -1;
 	}
 
@@ -1026,143 +1014,6 @@ void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * c
 	}
 }
 
-static int cc_publish(struct stasis_message_type *message_type, int core_id, struct ast_json *extras)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!message_type) {
-		return -1;
-	}
-
-	blob = ast_json_pack("{s: i}",
-		"core_id", core_id);
-	if (!blob) {
-		return -1;
-	}
-
-	if (extras) {
-		ast_json_object_update(blob, extras);
-	}
-
-	if (!(payload = ast_json_payload_create(blob))) {
-		return -1;
-	}
-
-	if (!(message = stasis_message_create(message_type, payload))) {
-		return -1;
-	}
-
-	stasis_publish(ast_system_topic(), message);
-
-	return 0;
-}
-
-static void cc_publish_available(int core_id, const char *callee, const char *service)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s, s: s}",
-		"callee", callee,
-		"service", service);
-
-	cc_publish(ast_cc_available_type(), core_id, extras);
-}
-
-static void cc_publish_offertimerstart(int core_id, const char *caller, unsigned int expires)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s, s: i}",
-		"caller", caller,
-		"expires", expires);
-
-	cc_publish(ast_cc_offertimerstart_type(), core_id, extras);
-}
-
-static void cc_publish_requested(int core_id, const char *caller, const char *callee)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s, s: s}",
-		"caller", caller,
-		"callee", callee);
-
-	cc_publish(ast_cc_requested_type(), core_id, extras);
-}
-
-static void cc_publish_requestacknowledged(int core_id, const char *caller)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"caller", caller);
-
-	cc_publish(ast_cc_requestacknowledged_type(), core_id, extras);
-}
-
-static void cc_publish_callerstopmonitoring(int core_id, const char *caller)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"caller", caller);
-
-	cc_publish(ast_cc_callerstopmonitoring_type(), core_id, extras);
-}
-
-static void cc_publish_callerstartmonitoring(int core_id, const char *caller)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"caller", caller);
-
-	cc_publish(ast_cc_callerstartmonitoring_type(), core_id, extras);
-}
-
-static void cc_publish_callerrecalling(int core_id, const char *caller)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"caller", caller);
-
-	cc_publish(ast_cc_callerrecalling_type(), core_id, extras);
-}
-
-static void cc_publish_recallcomplete(int core_id, const char *caller)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"caller", caller);
-
-	cc_publish(ast_cc_recallcomplete_type(), core_id, extras);
-}
-
-static void cc_publish_failure(int core_id, const char *caller, const char *reason)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s, s: s}",
-		"caller", caller,
-		"reason", reason);
-
-	cc_publish(ast_cc_failure_type(), core_id, extras);
-}
-
-static void cc_publish_monitorfailed(int core_id, const char *callee)
-{
-	RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
-
-	extras = ast_json_pack("{s: s}",
-		"callee", callee);
-
-	cc_publish(ast_cc_monitorfailed_type(), core_id, extras);
-}
-
 struct cc_monitor_backend {
 	AST_LIST_ENTRY(cc_monitor_backend) next;
 	const struct ast_cc_monitor_callbacks *callbacks;
@@ -1347,7 +1198,7 @@ struct generic_monitor_instance_list {
 	 * recalled
 	 */
 	int fit_for_recall;
-	struct stasis_subscription *sub;
+	struct ast_event_sub *sub;
 	AST_LIST_HEAD_NOLOCK(, generic_monitor_instance) list;
 };
 
@@ -1398,20 +1249,19 @@ static void generic_monitor_instance_list_destructor(void *obj)
 	struct generic_monitor_instance_list *generic_list = obj;
 	struct generic_monitor_instance *generic_instance;
 
-	generic_list->sub = stasis_unsubscribe(generic_list->sub);
+	generic_list->sub = ast_event_unsubscribe(generic_list->sub);
 	while ((generic_instance = AST_LIST_REMOVE_HEAD(&generic_list->list, next))) {
 		ast_free(generic_instance);
 	}
 	ast_free((char *)generic_list->device_name);
 }
 
-static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg);
+static void generic_monitor_devstate_cb(const struct ast_event *event, void *userdata);
 static struct generic_monitor_instance_list *create_new_generic_list(struct ast_cc_monitor *monitor)
 {
 	struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
 			generic_monitor_instance_list_destructor, "allocate generic monitor instance list");
 	char * device_name;
-	struct stasis_topic *device_specific_topic;
 
 	if (!generic_list) {
 		return NULL;
@@ -1424,12 +1274,11 @@ static struct generic_monitor_instance_list *create_new_generic_list(struct ast_
 	ast_tech_to_upper(device_name);
 	generic_list->device_name = device_name;
 
-	device_specific_topic = ast_device_state_topic(device_name);
-	if (!device_specific_topic) {
-		return NULL;
-	}
-
-	if (!(generic_list->sub = stasis_subscribe(device_specific_topic, generic_monitor_devstate_cb, NULL))) {
+	if (!(generic_list->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
+		generic_monitor_devstate_cb, "Requesting CC", NULL,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, monitor->interface->device_name,
+		AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
+		AST_EVENT_IE_END))) {
 		cc_unref(generic_list, "Failed to subscribe to device state");
 		return NULL;
 	}
@@ -1438,25 +1287,35 @@ static struct generic_monitor_instance_list *create_new_generic_list(struct ast_
 	return generic_list;
 }
 
+struct generic_tp_cb_data {
+	const char *device_name;
+	enum ast_device_state new_state;
+};
+
 static int generic_monitor_devstate_tp_cb(void *data)
 {
-	RAII_VAR(struct ast_device_state_message *, dev_state, data, ao2_cleanup);
-	enum ast_device_state new_state = dev_state->state;
-	enum ast_device_state previous_state;
+	struct generic_tp_cb_data *gtcd = data;
+	enum ast_device_state new_state = gtcd->new_state;
+	enum ast_device_state previous_state = gtcd->new_state;
+	const char *monitor_name = gtcd->device_name;
 	struct generic_monitor_instance_list *generic_list;
 	struct generic_monitor_instance *generic_instance;
 
-	if (!(generic_list = find_generic_monitor_instance_list(dev_state->device))) {
+	if (!(generic_list = find_generic_monitor_instance_list(monitor_name))) {
 		/* The most likely cause for this is that we destroyed the monitor in the
 		 * time between subscribing to its device state and the time this executes.
 		 * Not really a big deal.
 		 */
+		ast_free((char *) gtcd->device_name);
+		ast_free(gtcd);
 		return 0;
 	}
 
 	if (generic_list->current_state == new_state) {
 		/* The device state hasn't actually changed, so we don't really care */
 		cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
+		ast_free((char *) gtcd->device_name);
+		ast_free(gtcd);
 		return 0;
 	}
 
@@ -1476,31 +1335,33 @@ static int generic_monitor_devstate_tp_cb(void *data)
 		}
 	}
 	cc_unref(generic_list, "Kill reference of generic list in devstate taskprocessor callback");
+	ast_free((char *) gtcd->device_name);
+	ast_free(gtcd);
 	return 0;
 }
 
-static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static void generic_monitor_devstate_cb(const struct ast_event *event, void *userdata)
 {
 	/* Wow, it's cool that we've picked up on a state change, but we really want
 	 * the actual work to be done in the core's taskprocessor execution thread
 	 * so that all monitor operations can be serialized. Locks?! We don't need
 	 * no steenkin' locks!
 	 */
-	struct ast_device_state_message *dev_state;
-	if (ast_device_state_message_type() != stasis_message_type(msg)) {
+	struct generic_tp_cb_data *gtcd = ast_calloc(1, sizeof(*gtcd));
+
+	if (!gtcd) {
 		return;
 	}
 
-	dev_state = stasis_message_data(msg);
-	if (dev_state->eid) {
-		/* ignore non-aggregate states */
+	if (!(gtcd->device_name = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE)))) {
+		ast_free(gtcd);
 		return;
 	}
+	gtcd->new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
 
-	ao2_t_ref(dev_state, +1, "Bumping dev_state ref for cc_core_taskprocessor");
-	if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, dev_state)) {
-		ao2_cleanup(dev_state);
-		return;
+	if (ast_taskprocessor_push(cc_core_taskprocessor, generic_monitor_devstate_tp_cb, gtcd)) {
+		ast_free((char *)gtcd->device_name);
+		ast_free(gtcd);
 	}
 }
 
@@ -1777,7 +1638,7 @@ struct extension_child_dialstring {
 	 *
 	 * \details
 	 * This serves mainly as a key when searching for a particular dialstring.
-	 * For instance, let's say that we have called device SIP/400\@somepeer. This
+	 * For instance, let's say that we have called device SIP/400 at somepeer. This
 	 * device offers call completion, but then due to some unforeseen circumstance,
 	 * this device backs out and makes CC unavailable. When that happens, we need
 	 * to find the dialstring that corresponds to that device, and we use the
@@ -2400,7 +2261,12 @@ void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel
 
 	cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
 
-	cc_publish_available(cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service));
+	manager_event(EVENT_FLAG_CC, "CCAvailable",
+		"CoreID: %d\r\n"
+		"Callee: %s\r\n"
+		"Service: %s\r\n",
+		cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
+	);
 
 	cc_unref(core_instance, "Done with core_instance after handling CC control frame");
 	cc_unref(monitor, "Unref reference from allocating monitor");
@@ -2625,7 +2491,7 @@ struct cc_generic_agent_pvt {
 	 * device state of the caller in order to
 	 * determine when we may move on
 	 */
-	struct stasis_subscription *sub;
+	struct ast_event_sub *sub;
 	/*!
 	 * Scheduler id of offer timer.
 	 */
@@ -2758,33 +2624,34 @@ static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent)
 	return 0;
 }
 
-static void generic_agent_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+static int generic_agent_devstate_unsubscribe(void *data)
 {
-	struct ast_cc_agent *agent = userdata;
-	enum ast_device_state new_state;
-	struct ast_device_state_message *dev_state;
+	struct ast_cc_agent *agent = data;
 	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
 
-	if (stasis_subscription_final_message(sub, msg)) {
-		cc_unref(agent, "Done holding ref for subscription");
-		return;
-	} else if (ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
+	if (generic_pvt->sub != NULL) {
+		generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
 	}
+	cc_unref(agent, "Done unsubscribing from devstate");
+	return 0;
+}
 
-	dev_state = stasis_message_data(msg);
-	if (dev_state->eid) {
-		/* ignore non-aggregate states */
-		return;
-	}
+static void generic_agent_devstate_cb(const struct ast_event *event, void *userdata)
+{
+	struct ast_cc_agent *agent = userdata;
+	enum ast_device_state new_state;
 
-	new_state = dev_state->state;
+	new_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
 	if (!cc_generic_is_device_available(new_state)) {
 		/* Not interested in this new state of the device.  It is still busy. */
 		return;
 	}
 
-	generic_pvt->sub = stasis_unsubscribe(sub);
+	/* We can't unsubscribe from device state events here because it causes a deadlock */
+	if (ast_taskprocessor_push(cc_core_taskprocessor, generic_agent_devstate_unsubscribe,
+			cc_ref(agent, "ref agent for device state unsubscription"))) {
+		cc_unref(agent, "Unref agent unsubscribing from devstate failed");
+	}
 	ast_cc_agent_caller_available(agent->core_id, "%s is no longer busy", agent->device_name);
 }
 
@@ -2792,21 +2659,18 @@ static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
 {
 	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
 	struct ast_str *str = ast_str_alloca(128);
-	struct stasis_topic *device_specific_topic;
 
 	ast_assert(generic_pvt->sub == NULL);
 	ast_str_set(&str, 0, "Agent monitoring %s device state since it is busy\n",
 		agent->device_name);
 
-	device_specific_topic = ast_device_state_topic(agent->device_name);
-	if (!device_specific_topic) {
-		return -1;
-	}
-
-	if (!(generic_pvt->sub = stasis_subscribe(device_specific_topic, generic_agent_devstate_cb, agent))) {
+	if (!(generic_pvt->sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
+		generic_agent_devstate_cb, ast_str_buffer(str), agent,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->device_name,
+		AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_EXISTS,
+		AST_EVENT_IE_END))) {
 		return -1;
 	}
-	cc_ref(agent, "Ref agent for subscription");
 	return 0;
 }
 
@@ -2822,7 +2686,8 @@ static void *generic_recall(void *data)
 	const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
 	const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params);
 	unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
-	struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format tmp_fmt;
+	struct ast_format_cap *tmp_cap = ast_format_cap_alloc_nolock();
 
 	if (!tmp_cap) {
 		return NULL;
@@ -2833,17 +2698,17 @@ static void *generic_recall(void *data)
 		*target++ = '\0';
 	}
 
-	ast_format_cap_append(tmp_cap, ast_format_slin, 0);
-	if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
+	ast_format_cap_add(tmp_cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
+	if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
 		/* Hmm, no channel. Sucks for you, bud.
 		 */
 		ast_log_dynamic_level(cc_logger_level, "Core %u: Failed to call back %s for reason %d\n",
 				agent->core_id, agent->device_name, reason);
 		ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
-		ao2_ref(tmp_cap, -1);
+		ast_format_cap_destroy(tmp_cap);
 		return NULL;
 	}
-	ao2_ref(tmp_cap, -1);
+	ast_format_cap_destroy(tmp_cap);
 	
 	/* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
 	 * This will be a common task for all recall functions. If it were possible, I'd have
@@ -2916,7 +2781,7 @@ static void cc_generic_agent_destructor(struct ast_cc_agent *agent)
 
 	cc_generic_agent_stop_offer_timer(agent);
 	if (agent_pvt->sub) {
-		agent_pvt->sub = stasis_unsubscribe(agent_pvt->sub);
+		agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
 	}
 
 	ast_free(agent_pvt);
@@ -3065,7 +2930,11 @@ static int cc_caller_offered(struct cc_core_instance *core_instance, struct cc_s
 				core_instance->agent->device_name);
 		return -1;
 	}
-	cc_publish_offertimerstart(core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
+	manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
+		"CoreID: %d\r\n"
+		"Caller: %s\r\n"
+		"Expires: %u\r\n",
+		core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
 	ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
 			core_instance->core_id, core_instance->agent->device_name);
 	return 0;
@@ -3114,7 +2983,11 @@ static void request_cc(struct cc_core_instance *core_instance)
 						monitor_iter->interface->device_name, 1);
 				cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
 			} else {
-				cc_publish_requested(core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
+				manager_event(EVENT_FLAG_CC, "CCRequested",
+					"CoreID: %d\r\n"
+					"Caller: %s\r\n"
+					"Callee: %s\r\n",
+					core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
 			}
 		}
 	}
@@ -3172,9 +3045,15 @@ static int cc_active(struct cc_core_instance *core_instance, struct cc_state_cha
 	if (previous_state == CC_CALLER_REQUESTED) {
 		core_instance->agent->callbacks->respond(core_instance->agent,
 			AST_CC_AGENT_RESPONSE_SUCCESS);
-		cc_publish_requestacknowledged(core_instance->core_id, core_instance->agent->device_name);
+		manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
+			"CoreID: %d\r\n"
+			"Caller: %s\r\n",
+			core_instance->core_id, core_instance->agent->device_name);
 	} else if (previous_state == CC_CALLER_BUSY) {
-		cc_publish_callerstopmonitoring(core_instance->core_id, core_instance->agent->device_name);
+		manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
+			"CoreID: %d\r\n"
+			"Caller: %s\r\n",
+			core_instance->core_id, core_instance->agent->device_name);
 		unsuspend(core_instance);
 	}
 	/* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
@@ -3216,7 +3095,10 @@ static int cc_caller_busy(struct cc_core_instance *core_instance, struct cc_stat
 	 */
 	suspend(core_instance);
 	core_instance->agent->callbacks->start_monitoring(core_instance->agent);
-	cc_publish_callerstartmonitoring(core_instance->core_id, core_instance->agent->device_name);
+	manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
+		"CoreID: %d\r\n"
+		"Caller: %s\r\n",
+		core_instance->core_id, core_instance->agent->device_name);
 	return 0;
 }
 
@@ -3247,7 +3129,10 @@ static int cc_recalling(struct cc_core_instance *core_instance, struct cc_state_
 	/* Both caller and callee are available, call agent's recall callback
 	 */
 	cancel_available_timer(core_instance);
-	cc_publish_callerrecalling(core_instance->core_id, core_instance->agent->device_name);
+	manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
+		"CoreID: %d\r\n"
+		"Caller: %s\r\n",
+		core_instance->core_id, core_instance->agent->device_name);
 	return 0;
 }
 
@@ -3255,14 +3140,21 @@ static int cc_complete(struct cc_core_instance *core_instance, struct cc_state_c
 {
 	/* Recall has made progress, call agent and monitor destructor functions
 	 */
-	cc_publish_recallcomplete(core_instance->core_id, core_instance->agent->device_name);
+	manager_event(EVENT_FLAG_CC, "CCRecallComplete",
+		"CoreID: %d\r\n"
+		"Caller: %s\r\n",
+		core_instance->core_id, core_instance->agent->device_name);
 	ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
 	return 0;
 }
 
 static int cc_failed(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
 {
-	cc_publish_failure(core_instance->core_id, core_instance->agent->device_name, args->debug);
+	manager_event(EVENT_FLAG_CC, "CCFailure",
+		"CoreID: %d\r\n"
+		"Caller: %s\r\n"
+		"Reason: %s\r\n",
+		core_instance->core_id, core_instance->agent->device_name, args->debug);
 	ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
 	return 0;
 }
@@ -3916,7 +3808,10 @@ static int cc_monitor_failed(void *data)
 				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id,
 						monitor_iter->interface->device_name, 1);
 				monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
-				cc_publish_monitorfailed(monitor_iter->core_id, monitor_iter->interface->device_name);
+				manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
+					"CoreID: %d\r\n"
+					"Callee: %s\r\n",
+					monitor_iter->core_id, monitor_iter->interface->device_name);
 				cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
 			}
 		}
@@ -4688,7 +4583,7 @@ int ast_cc_init(void)
 	initialize_cc_devstate_map();
 	res |= ast_devstate_prov_add("ccss", ccss_device_state);
 
-	ast_register_atexit(cc_shutdown);
+	ast_register_cleanup(cc_shutdown);
 
 	return res;
 }
diff --git a/main/cdr.c b/main/cdr.c
index 559acde..e608807 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -30,14 +30,6 @@
  * isn't properly generated and posted.
  */
 
-/*! \li \ref cdr.c uses the configuration file \ref cdr.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cdr.conf cdr.conf
- * \verbinclude cdr.conf.sample
- */
 
 /*** MODULEINFO
 	<support_level>core</support_level>
@@ -45,10 +37,9 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427902 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
-#include <inttypes.h>
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
@@ -63,3116 +54,948 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427902 $")
 #include "asterisk/cli.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/data.h"
-#include "asterisk/config_options.h"
-#include "asterisk/json.h"
-#include "asterisk/parking.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/astobj2.h"
 
 /*** DOCUMENTATION
-	<configInfo name="cdr" language="en_US">
-		<synopsis>Call Detail Record configuration</synopsis>
-		<description>
-			<para>CDR is Call Detail Record, which provides logging services via a variety of
-			pluggable backend modules. Detailed call information can be recorded to
-			databases, files, etc. Useful for billing, fraud prevention, compliance with
-			Sarbanes-Oxley aka The Enron Act, QOS evaluations, and more.</para>
-		</description>
-		<configFile name="cdr.conf">
-			<configObject name="general">
-				<synopsis>Global settings applied to the CDR engine.</synopsis>
-				<configOption name="debug">
-					<synopsis>Enable/disable verbose CDR debugging.</synopsis>
-					<description><para>When set to <literal>True</literal>, verbose updates
-					of changes in CDR information will be logged. Note that this is only
-					of use when debugging CDR behavior.</para>
-					</description>
-				</configOption>
-				<configOption name="enable">
-					<synopsis>Enable/disable CDR logging.</synopsis>
-					<description><para>Define whether or not to use CDR logging. Setting this to "no" will override
-					any loading of backend CDR modules.  Default is "yes".</para>
-					</description>
-				</configOption>
-				<configOption name="unanswered">
-					<synopsis>Log calls that are never answered and don't set an outgoing party.</synopsis>
-					<description><para>
-					Define whether or not to log unanswered calls that don't involve an outgoing party. Setting
-					this to "yes" will make calls to extensions that don't answer and don't set a side B channel
-					(such as by using the Dial application) receive CDR log entries. If this option is set to
-					"no", then those log entries will not be created. Unanswered calls which get offered to an
-					outgoing line will always receive log entries regardless of this option, and that is the
-					intended behavior.
-					</para>
-					</description>
-				</configOption>
-				<configOption name="congestion">
-					<synopsis>Log congested calls.</synopsis>
-					<description><para>Define whether or not to log congested calls. Setting this to "yes" will
-					report each call that fails to complete due to congestion conditions.</para>
-					</description>
-				</configOption>
-				<configOption name="endbeforehexten">
-					<synopsis>Don't produce CDRs while executing hangup logic</synopsis>
-					<description>
-						<para>As each CDR for a channel is finished, its end time is updated
-						and the CDR is finalized. When a channel is hung up and hangup
-						logic is present (in the form of a hangup handler or the
-						<literal>h</literal> extension), a new CDR is generated for the
-						channel. Any statistics are gathered from this new CDR. By enabling
-						this option, no new CDR is created for the dialplan logic that is
-						executed in <literal>h</literal> extensions or attached hangup handler
-						subroutines. The default value is <literal>yes</literal>, indicating
-						that a CDR will be generated during hangup logic.</para>
-					</description>
-				</configOption>
-				<configOption name="initiatedseconds">
-					<synopsis>Count microseconds for billsec purposes</synopsis>
-					<description><para>Normally, the <literal>billsec</literal> field logged to the CDR backends
-					is simply the end time (hangup time) minus the answer time in seconds. Internally,
-					asterisk stores the time in terms of microseconds and seconds. By setting
-					initiatedseconds to <literal>yes</literal>, you can force asterisk to report any seconds
-					that were initiated (a sort of round up method). Technically, this is
-					when the microsecond part of the end time is greater than the microsecond
-					part of the answer time, then the billsec time is incremented one second.</para>
-					</description>
-				</configOption>
-				<configOption name="batch">
-					<synopsis>Submit CDRs to the backends for processing in batches</synopsis>
-					<description><para>Define the CDR batch mode, where instead of posting the CDR at the end of
-					every call, the data will be stored in a buffer to help alleviate load on the
-					asterisk server.</para>
-					<warning><para>Use of batch mode may result in data loss after unsafe asterisk termination,
-					i.e., software crash, power failure, kill -9, etc.</para>
-					</warning>
-					</description>
-				</configOption>
-				<configOption name="size">
-					<synopsis>The maximum number of CDRs to accumulate before triggering a batch</synopsis>
-					<description><para>Define the maximum number of CDRs to accumulate in the buffer before posting
-					them to the backend engines. batch must be set to <literal>yes</literal>.</para>
-					</description>
-				</configOption>
-				<configOption name="time">
-					<synopsis>The maximum time to accumulate CDRs before triggering a batch</synopsis>
-					<description><para>Define the maximum time to accumulate CDRs before posting them in a batch to the
-					backend engines. If this time limit is reached, then it will post the records, regardless of the value
-					defined for size. batch must be set to <literal>yes</literal>.</para>
-					<note><para>Time is expressed in seconds.</para></note>
-					</description>
-				</configOption>
-				<configOption name="scheduleronly">
-					<synopsis>Post batched CDRs on their own thread instead of the scheduler</synopsis>
-					<description><para>The CDR engine uses the internal asterisk scheduler to determine when to post
-					records.  Posting can either occur inside the scheduler thread, or a new
-					thread can be spawned for the submission of every batch.  For small batches,
-					it might be acceptable to just use the scheduler thread, so set this to <literal>yes</literal>.
-					For large batches, say anything over size=10, a new thread is recommended, so
-					set this to <literal>no</literal>.</para>
-					</description>
-				</configOption>
-				<configOption name="safeshutdown">
-					<synopsis>Block shutdown of Asterisk until CDRs are submitted</synopsis>
-					<description><para>When shutting down asterisk, you can block until the CDRs are submitted.  If
-					you don't, then data will likely be lost.  You can always check the size of
-					the CDR batch buffer with the CLI <astcli>cdr status</astcli> command.  To enable blocking on
-					submission of CDR data during asterisk shutdown, set this to <literal>yes</literal>.</para>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
  ***/
 
+/*! Default AMA flag for billing records (CDR's) */
+int ast_default_amaflags = AST_CDR_DOCUMENTATION;
+char ast_default_accountcode[AST_MAX_ACCOUNT_CODE];
 
-/* The prime here should be similar in size to the channel container. */
-#ifdef LOW_MEMORY
-#define NUM_CDR_BUCKETS 61
-#else
-#define NUM_CDR_BUCKETS 769
-#endif
-
-#define DEFAULT_ENABLED "1"
-#define DEFAULT_BATCHMODE "0"
-#define DEFAULT_UNANSWERED "0"
-#define DEFAULT_CONGESTION "0"
-#define DEFAULT_END_BEFORE_H_EXTEN "1"
-#define DEFAULT_INITIATED_SECONDS "0"
-
-#define DEFAULT_BATCH_SIZE "100"
-#define MAX_BATCH_SIZE 1000
-#define DEFAULT_BATCH_TIME "300"
-#define MAX_BATCH_TIME 86400
-#define DEFAULT_BATCH_SCHEDULER_ONLY "0"
-#define DEFAULT_BATCH_SAFE_SHUTDOWN "1"
-
-#define CDR_DEBUG(mod_cfg, fmt, ...) \
-	do { \
-		if (ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG)) { \
-			ast_verbose((fmt), ##__VA_ARGS__); \
-		} \
-	} while (0)
-
-static void cdr_detach(struct ast_cdr *cdr);
-static void cdr_submit_batch(int shutdown);
-static int cdr_toggle_runtime_options(void);
-
-/*! \brief The configuration settings for this module */
-struct module_config {
-	struct ast_cdr_config *general;		/*< CDR global settings */
-};
-
-/*! \brief The container for the module configuration */
-static AO2_GLOBAL_OBJ_STATIC(module_configs);
-
-/*! \brief The type definition for general options */
-static struct aco_type general_option = {
-	.type = ACO_GLOBAL,
-	.name = "general",
-	.item_offset = offsetof(struct module_config, general),
-	.category = "^general$",
-	.category_match = ACO_WHITELIST,
-};
-
-static void *module_config_alloc(void);
-static void module_config_destructor(void *obj);
-
-/*! \brief The file definition */
-static struct aco_file module_file_conf = {
-	.filename = "cdr.conf",
-	.skip_category = "(^csv$|^custom$|^manager$|^odbc$|^pgsql$|^radius$|^sqlite$|^tds$|^mysql$)",
-	.types = ACO_TYPES(&general_option),
-};
-
-CONFIG_INFO_CORE("cdr", cfg_info, module_configs, module_config_alloc,
-	.files = ACO_FILES(&module_file_conf),
-);
-
-static struct aco_type *general_options[] = ACO_TYPES(&general_option);
-
-/*! \brief Dispose of a module config object */
-static void module_config_destructor(void *obj)
-{
-	struct module_config *cfg = obj;
-
-	if (!cfg) {
-		return;
-	}
-	ao2_ref(cfg->general, -1);
-}
-
-/*! \brief Create a new module config object */
-static void *module_config_alloc(void)
-{
-	struct module_config *mod_cfg;
-	struct ast_cdr_config *cdr_config;
-
-	mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
-	if (!mod_cfg) {
-		return NULL;
-	}
-
-	cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
-	if (!cdr_config) {
-		ao2_ref(cdr_config, -1);
-		return NULL;
-	}
-	mod_cfg->general = cdr_config;
-
-	return mod_cfg;
-}
-
-/*! \brief Registration object for CDR backends */
-struct cdr_beitem {
+struct ast_cdr_beitem {
 	char name[20];
 	char desc[80];
 	ast_cdrbe be;
-	AST_RWLIST_ENTRY(cdr_beitem) list;
-	int suspended:1;
+	AST_RWLIST_ENTRY(ast_cdr_beitem) list;
 };
 
-/*! \brief List of registered backends */
-static AST_RWLIST_HEAD_STATIC(be_list, cdr_beitem);
+static AST_RWLIST_HEAD_STATIC(be_list, ast_cdr_beitem);
 
-/*! \brief Queued CDR waiting to be batched */
-struct cdr_batch_item {
+struct ast_cdr_batch_item {
 	struct ast_cdr *cdr;
-	struct cdr_batch_item *next;
+	struct ast_cdr_batch_item *next;
 };
 
-/*! \brief The actual batch queue */
-static struct cdr_batch {
+static struct ast_cdr_batch {
 	int size;
-	struct cdr_batch_item *head;
-	struct cdr_batch_item *tail;
+	struct ast_cdr_batch_item *head;
+	struct ast_cdr_batch_item *tail;
 } *batch = NULL;
 
-/*! \brief The global sequence counter used for CDRs */
-static int global_cdr_sequence =  0;
 
-/*! \brief Scheduler items */
+static int cdr_sequence =  0;
+
+static int cdr_seq_inc(struct ast_cdr *cdr);
+
 static struct ast_sched_context *sched;
 static int cdr_sched = -1;
-AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
 static pthread_t cdr_thread = AST_PTHREADT_NULL;
 
-/*! \brief Lock protecting modifications to the batch queue */
-AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
-
-/*! \brief These are used to wake up the CDR thread when there's work to do */
-AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
-static ast_cond_t cdr_pending_cond;
-
-/*! \brief A container of the active CDRs indexed by Party A channel id */
-static struct ao2_container *active_cdrs_by_channel;
-
-/*! \brief Message router for stasis messages regarding channel state */
-static struct stasis_message_router *stasis_router;
-
-/*! \brief Our subscription for bridges */
-static struct stasis_forward *bridge_subscription;
-
-/*! \brief Our subscription for channels */
-static struct stasis_forward *channel_subscription;
-
-/*! \brief Our subscription for parking */
-static struct stasis_forward *parking_subscription;
-
-/*! \brief The parent topic for all topics we want to aggregate for CDRs */
-static struct stasis_topic *cdr_topic;
-
-/*! \brief A message type used to synchronize with the CDR topic */
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type);
-
-struct cdr_object;
-
-/*! \brief Return types for \ref process_bridge_enter functions */
-enum process_bridge_enter_results {
-	/*!
-	 * The CDR was the only party in the bridge.
-	 */
-	BRIDGE_ENTER_ONLY_PARTY,
-	/*!
-	 * The CDR was able to obtain a Party B from some other party already in the bridge
-	 */
-	BRIDGE_ENTER_OBTAINED_PARTY_B,
-	/*!
-	 * The CDR was not able to obtain a Party B
-	 */
-	BRIDGE_ENTER_NO_PARTY_B,
-	/*!
-	 * This CDR can't handle a bridge enter message and a new CDR needs to be created
-	 */
-	BRIDGE_ENTER_NEED_CDR,
-};
+static int enabled;
+static const int ENABLED_DEFAULT = 1;
 
-/*!
- * \brief A virtual table used for \ref cdr_object.
- *
- * Note that all functions are optional - if a subclass does not need an
- * implementation, it is safe to leave it NULL.
- */
-struct cdr_object_fn_table {
-	/*! \brief Name of the subclass */
-	const char *name;
-
-	/*!
-	 * \brief An initialization function. This will be called automatically
-	 * when a \ref cdr_object is switched to this type in
-	 * \ref cdr_object_transition_state
-	 *
-	 * \param cdr The \ref cdr_object that was just transitioned
-	 */
-	void (* const init_function)(struct cdr_object *cdr);
-
-	/*!
-	 * \brief Process a Party A update for the \ref cdr_object
-	 *
-	 * \param cdr The \ref cdr_object to process the update
-	 * \param snapshot The snapshot for the CDR's Party A
-	 * \retval 0 the CDR handled the update or ignored it
-	 * \retval 1 the CDR is finalized and a new one should be made to handle it
-	 */
-	int (* const process_party_a)(struct cdr_object *cdr,
-			struct ast_channel_snapshot *snapshot);
-
-	/*!
-	 * \brief Process a Party B update for the \ref cdr_object
-	 *
-	 * \param cdr The \ref cdr_object to process the update
-	 * \param snapshot The snapshot for the CDR's Party B
-	 */
-	void (* const process_party_b)(struct cdr_object *cdr,
-			struct ast_channel_snapshot *snapshot);
-
-	/*!
-	 * \brief Process the beginning of a dial. A dial message implies one of two
-	 * things:
-	 * The \ref cdr_object's Party A has been originated
-	 * The \ref cdr_object's Party A is dialing its Party B
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param caller The originator of the dial attempt
-	 * \param peer The destination of the dial attempt
-	 *
-	 * \retval 0 if the parties in the dial were handled by this CDR
-	 * \retval 1 if the parties could not be handled by this CDR
-	 */
-	int (* const process_dial_begin)(struct cdr_object *cdr,
-			struct ast_channel_snapshot *caller,
-			struct ast_channel_snapshot *peer);
-
-	/*!
-	 * \brief Process the end of a dial. At the end of a dial, a CDR can be
-	 * transitioned into one of two states - DialedPending
-	 * (\ref dialed_pending_state_fn_table) or Finalized
-	 * (\ref finalized_state_fn_table).
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param caller The originator of the dial attempt
-	 * \param peer the Destination of the dial attempt
-	 * \param dial_status What happened
-	 *
-	 * \retval 0 if the parties in the dial were handled by this CDR
-	 * \retval 1 if the parties could not be handled by this CDR
-	 */
-	int (* const process_dial_end)(struct cdr_object *cdr,
-			struct ast_channel_snapshot *caller,
-			struct ast_channel_snapshot *peer,
-			const char *dial_status);
-
-	/*!
-	 * \brief Process the entering of a bridge by this CDR. The purpose of this
-	 * callback is to have the CDR prepare itself for the bridge and attempt to
-	 * find a valid Party B. The act of creating new CDRs based on the entering
-	 * of this channel into the bridge is handled by the higher level message
-	 * handler.
-	 *
-	 * Note that this handler is for when a channel enters into a "normal"
-	 * bridge, where people actually talk to each other. Parking is its own
-	 * thing.
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param bridge The bridge that the Party A just entered into
-	 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
-	 *
-	 * \retval process_bridge_enter_results Defines whether or not this CDR was able
-	 * to fully handle the bridge enter message.
-	 */
-	enum process_bridge_enter_results (* const process_bridge_enter)(
-			struct cdr_object *cdr,
-			struct ast_bridge_snapshot *bridge,
-			struct ast_channel_snapshot *channel);
-
-	/*!
-	 * \brief Process entering into a parking bridge.
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param bridge The parking bridge that Party A just entered into
-	 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
-	 *
-	 * \retval 0 This CDR successfully transitioned itself into the parked state
-	 * \retval 1 This CDR couldn't handle the parking transition and we need a
-	 *  new CDR.
-	 */
-	int (* const process_parking_bridge_enter)(struct cdr_object *cdr,
-			struct ast_bridge_snapshot *bridge,
-			struct ast_channel_snapshot *channel);
-
-	/*!
-	 * \brief Process the leaving of a bridge by this CDR.
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param bridge The bridge that the Party A just left
-	 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
-	 *
-	 * \retval 0 This CDR left successfully
-	 * \retval 1 Error
-	 */
-	int (* const process_bridge_leave)(struct cdr_object *cdr,
-			struct ast_bridge_snapshot *bridge,
-			struct ast_channel_snapshot *channel);
-
-	/*!
-	 * \brief Process an update informing us that the channel got itself parked
-	 *
-	 * \param cdr The \ref cdr_object
-	 * \param channel The parking information for this CDR's party A
-	 *
-	 * \retval 0 This CDR successfully parked itself
-	 * \retval 1 This CDR couldn't handle the park
-	 */
-	int (* const process_parked_channel)(struct cdr_object *cdr,
-			struct ast_parked_call_payload *parking_info);
-};
+static int batchmode;
+static const int BATCHMODE_DEFAULT = 0;
 
-static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static enum process_bridge_enter_results base_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
-static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
-static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
-static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info);
+static int unanswered;
+static const int UNANSWERED_DEFAULT = 0;
 
-static void single_state_init_function(struct cdr_object *cdr);
-static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
-static enum process_bridge_enter_results single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
-static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+static int congestion;
+static const int CONGESTION_DEFAULT = 0;
 
-/*!
- * \brief The virtual table for the Single state.
- *
- * A \ref cdr_object starts off in this state. This represents a channel that
- * has no Party B information itself.
- *
- * A \ref cdr_object from this state can go into any of the following states:
- * * \ref dial_state_fn_table
- * * \ref bridge_state_fn_table
- * * \ref finalized_state_fn_table
- */
-struct cdr_object_fn_table single_state_fn_table = {
-	.name = "Single",
-	.init_function = single_state_init_function,
-	.process_party_a = base_process_party_a,
-	.process_party_b = single_state_process_party_b,
-	.process_dial_begin = single_state_process_dial_begin,
-	.process_dial_end = base_process_dial_end,
-	.process_bridge_enter = single_state_process_bridge_enter,
-	.process_parking_bridge_enter = single_state_process_parking_bridge_enter,
-	.process_bridge_leave = base_process_bridge_leave,
-	.process_parked_channel = base_process_parked_channel,
-};
+static int batchsize;
+static const int BATCH_SIZE_DEFAULT = 100;
 
-static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
-static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
-static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+static int batchtime;
+static const int BATCH_TIME_DEFAULT = 300;
 
-/*!
- * \brief The virtual table for the Dial state.
- *
- * A \ref cdr_object that has begun a dial operation. This state is entered when
- * the Party A for a CDR is determined to be dialing out to a Party B or when
- * a CDR is for an originated channel (in which case the Party A information is
- * the originated channel, and there is no Party B).
- *
- * A \ref cdr_object from this state can go in any of the following states:
- * * \ref dialed_pending_state_fn_table
- * * \ref bridge_state_fn_table
- * * \ref finalized_state_fn_table
- */
-struct cdr_object_fn_table dial_state_fn_table = {
-	.name = "Dial",
-	.process_party_a = base_process_party_a,
-	.process_party_b = dial_state_process_party_b,
-	.process_dial_begin = dial_state_process_dial_begin,
-	.process_dial_end = dial_state_process_dial_end,
-	.process_bridge_enter = dial_state_process_bridge_enter,
-	.process_bridge_leave = base_process_bridge_leave,
-};
+static int batchscheduleronly;
+static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0;
 
-static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
-static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
-static int dialed_pending_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+static int batchsafeshutdown;
+static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1;
 
-/*!
- * \brief The virtual table for the Dialed Pending state.
- *
- * A \ref cdr_object that has successfully finished a dial operation, but we
- * don't know what they're going to do yet. It's theoretically possible to dial
- * a party and then have that party not be bridged with the caller; likewise,
- * an origination can complete and the channel go off and execute dialplan. The
- * pending state acts as a bridge between either:
- * * Entering a bridge
- * * Getting a new CDR for new dialplan execution
- * * Switching from being originated to executing dialplan
- *
- * A \ref cdr_object from this state can go in any of the following states:
- * * \ref single_state_fn_table
- * * \ref dialed_pending_state_fn_table
- * * \ref bridge_state_fn_table
- * * \ref finalized_state_fn_table
- */
-struct cdr_object_fn_table dialed_pending_state_fn_table = {
-	.name = "DialedPending",
-	.process_party_a = dialed_pending_state_process_party_a,
-	.process_dial_begin = dialed_pending_state_process_dial_begin,
-	.process_bridge_enter = dialed_pending_state_process_bridge_enter,
-	.process_parking_bridge_enter = dialed_pending_state_process_parking_bridge_enter,
-	.process_bridge_leave = base_process_bridge_leave,
-	.process_parked_channel = base_process_parked_channel,
-};
+AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
 
-static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
 
-/*!
- * \brief The virtual table for the Bridged state
- *
- * A \ref cdr_object enters this state when it receives notification that the
- * channel has entered a bridge.
- *
- * A \ref cdr_object from this state can go to:
- * * \ref finalized_state_fn_table
- */
-struct cdr_object_fn_table bridge_state_fn_table = {
-	.name = "Bridged",
-	.process_party_a = base_process_party_a,
-	.process_party_b = bridge_state_process_party_b,
-	.process_bridge_leave = bridge_state_process_bridge_leave,
-	.process_parked_channel = base_process_parked_channel,
-};
+/* these are used to wake up the CDR thread when there's work to do */
+AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
+static ast_cond_t cdr_pending_cond;
 
-static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+int check_cdr_enabled(void)
+{
+	return enabled;
+}
 
 /*!
- * \brief The virtual table for the Parked state
- *
- * Parking is weird. Unlike typical bridges, it has to be treated somewhat
- * uniquely - a channel in a parking bridge (which is a subclass of a holding
- * bridge) has to be handled as if the channel went into an application.
- * However, when the channel comes out, we need a new CDR - unlike the Single
- * state.
+ * \brief Register a CDR driver. Each registered CDR driver generates a CDR
+ * \retval 0 on success.
+ * \retval -1 on error
  */
-struct cdr_object_fn_table parked_state_fn_table = {
-	.name = "Parked",
-	.process_party_a = base_process_party_a,
-	.process_bridge_leave = parked_state_process_bridge_leave,
-	.process_parked_channel = base_process_parked_channel,
-};
+int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
+{
+	struct ast_cdr_beitem *i = NULL;
 
-static void finalized_state_init_function(struct cdr_object *cdr);
-static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+	if (!name)
+		return -1;
 
-/*!
- * \brief The virtual table for the finalized state.
- *
- * Once in the finalized state, the CDR is done. No modifications can be made
- * to the CDR.
- */
-struct cdr_object_fn_table finalized_state_fn_table = {
-	.name = "Finalized",
-	.init_function = finalized_state_init_function,
-	.process_party_a = finalized_state_process_party_a,
-	.process_bridge_enter = base_process_bridge_enter,
-};
+	if (!be) {
+		ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
+		return -1;
+	}
 
-/*! \brief A wrapper object around a snapshot.
- * Fields that are mutable by the CDR engine are replicated here.
- */
-struct cdr_object_snapshot {
-	struct ast_channel_snapshot *snapshot;  /*!< The channel snapshot */
-	char userfield[AST_MAX_USER_FIELD];     /*!< Userfield for the channel */
-	unsigned int flags;                     /*!< Specific flags for this party */
-	struct varshead variables;              /*!< CDR variables for the channel */
-};
+	AST_RWLIST_WRLOCK(&be_list);
+	AST_RWLIST_TRAVERSE(&be_list, i, list) {
+		if (!strcasecmp(name, i->name)) {
+			ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
+			AST_RWLIST_UNLOCK(&be_list);
+			return -1;
+		}
+	}
 
-/*! \brief An in-memory representation of an active CDR */
-struct cdr_object {
-	struct cdr_object_snapshot party_a;     /*!< The Party A information */
-	struct cdr_object_snapshot party_b;     /*!< The Party B information */
-	struct cdr_object_fn_table *fn_table;   /*!< The current virtual table */
-
-	enum ast_cdr_disposition disposition;   /*!< The disposition of the CDR */
-	struct timeval start;                   /*!< When this CDR was created */
-	struct timeval answer;                  /*!< Either when the channel was answered, or when the path between channels was established */
-	struct timeval end;                     /*!< When this CDR was finalized */
-	unsigned int sequence;                  /*!< A monotonically increasing number for each CDR */
-	struct ast_flags flags;                 /*!< Flags on the CDR */
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(linkedid);         /*!< Linked ID. Cached here as it may change out from party A, which must be immutable */
-		AST_STRING_FIELD(uniqueid);			/*!< Unique id of party A. Cached here as it is the primary key of this CDR */
-		AST_STRING_FIELD(name);             /*!< Channel name of party A. Cached here as the party A address may change */
-		AST_STRING_FIELD(bridge);           /*!< The bridge the party A happens to be in. */
-		AST_STRING_FIELD(appl);             /*!< The last accepted application party A was in */
-		AST_STRING_FIELD(data);             /*!< The data for the last accepted application party A was in */
-		AST_STRING_FIELD(context);          /*!< The accepted context for Party A */
-		AST_STRING_FIELD(exten);            /*!< The accepted extension for Party A */
-	);
-	struct cdr_object *next;                /*!< The next CDR object in the chain */
-	struct cdr_object *last;                /*!< The last CDR object in the chain */
-};
+	if (!(i = ast_calloc(1, sizeof(*i))))
+		return -1;
 
-/*!
- * \brief Copy variables from one list to another
- * \param to_list destination
- * \param from_list source
- * \retval The number of copied variables
- */
-static int copy_variables(struct varshead *to_list, struct varshead *from_list)
-{
-	struct ast_var_t *variables;
-	struct ast_var_t *newvariable;
-	const char *var;
-	const char *val;
-	int x = 0;
+	i->be = be;
+	ast_copy_string(i->name, name, sizeof(i->name));
+	ast_copy_string(i->desc, desc, sizeof(i->desc));
 
-	AST_LIST_TRAVERSE(from_list, variables, entries) {
-		var = ast_var_name(variables);
-		if (ast_strlen_zero(var)) {
-			continue;
-		}
-		val = ast_var_value(variables);
-		if (ast_strlen_zero(val)) {
-			continue;
-		}
-		newvariable = ast_var_assign(var, val);
-		if (newvariable) {
-			AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
-			++x;
-		}
-	}
+	AST_RWLIST_INSERT_HEAD(&be_list, i, list);
+	AST_RWLIST_UNLOCK(&be_list);
 
-	return x;
+	return 0;
 }
 
-/*!
- * \brief Delete all variables from a variable list
- * \param headp The head pointer to the variable list to delete
- */
-static void free_variables(struct varshead *headp)
+/*! unregister a CDR driver */
+void ast_cdr_unregister(const char *name)
 {
-	struct ast_var_t *vardata;
+	struct ast_cdr_beitem *i = NULL;
 
-	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
-		ast_var_delete(vardata);
+	AST_RWLIST_WRLOCK(&be_list);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
+		if (!strcasecmp(name, i->name)) {
+			AST_RWLIST_REMOVE_CURRENT(list);
+			break;
+		}
 	}
-}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+	AST_RWLIST_UNLOCK(&be_list);
 
-/*!
- * \brief Copy a snapshot and its details
- * \param dst The destination
- * \param src The source
- */
-static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
-{
-	if (dst->snapshot) {
-		ao2_t_ref(dst->snapshot, -1, "release old snapshot during copy");
+	if (i) {
+		ast_verb(2, "Unregistered '%s' CDR backend\n", name);
+		ast_free(i);
 	}
-	dst->snapshot = src->snapshot;
-	ao2_t_ref(dst->snapshot, +1, "bump new snapshot during copy");
-	strcpy(dst->userfield, src->userfield);
-	dst->flags = src->flags;
-	copy_variables(&dst->variables, &src->variables);
 }
 
-/*!
- * \brief Transition a \ref cdr_object to a new state
- * \param cdr The \ref cdr_object to transition
- * \param fn_table The \ref cdr_object_fn_table state to go to
- */
-static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
+int ast_cdr_isset_unanswered(void)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	CDR_DEBUG(mod_cfg, "%p - Transitioning CDR for %s from state %s to %s\n",
-		cdr, cdr->party_a.snapshot->name,
-		cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
-	cdr->fn_table = fn_table;
-	if (cdr->fn_table->init_function) {
-		cdr->fn_table->init_function(cdr);
-	}
+	return unanswered;
 }
-/*! \internal
- * \brief Hash function for containers of CDRs indexing by Party A uniqueid */
-static int cdr_object_channel_hash_fn(const void *obj, const int flags)
+
+int ast_cdr_isset_congestion(void)
 {
-	const struct cdr_object *cdr;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		break;
-	case OBJ_POINTER:
-		cdr = obj;
-		key = cdr->uniqueid;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_case_hash(key);
+	return congestion;
 }
 
-/*! \internal
- * \brief Comparison function for containers of CDRs indexing by Party A uniqueid
- */
-static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags)
+struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr)
 {
-    struct cdr_object *left = obj;
-    struct cdr_object *right = arg;
-    const char *right_key = arg;
-    int cmp;
-
-    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-    case OBJ_POINTER:
-        right_key = right->uniqueid;
-        /* Fall through */
-    case OBJ_KEY:
-        cmp = strcmp(left->uniqueid, right_key);
-        break;
-    case OBJ_PARTIAL_KEY:
-        /*
-         * We could also use a partial key struct containing a length
-         * so strlen() does not get called for every comparison instead.
-         */
-        cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
-        break;
-    default:
-        /* Sort can only work on something with a full or partial key. */
-        ast_assert(0);
-        cmp = 0;
-        break;
-    }
-    return cmp ? 0 : CMP_MATCH;
+	struct ast_cdr *newcdr = ast_cdr_dup(cdr);
+	if (!newcdr)
+		return NULL;
+
+	cdr_seq_inc(newcdr);
+	return newcdr;
 }
 
-/*!
- * \brief \ref cdr_object Destructor
- */
-static void cdr_object_dtor(void *obj)
+struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr)
 {
-	struct cdr_object *cdr = obj;
-	struct ast_var_t *it_var;
-
-	ao2_cleanup(cdr->party_a.snapshot);
-	ao2_cleanup(cdr->party_b.snapshot);
-	while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
-		ast_var_delete(it_var);
-	}
-	while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
-		ast_var_delete(it_var);
-	}
-	ast_string_field_free_memory(cdr);
+	struct ast_cdr *newcdr = ast_cdr_dup(cdr);
+	if (!newcdr)
+		return NULL;
 
-	ao2_cleanup(cdr->next);
+	cdr_seq_inc(cdr);
+	return newcdr;
 }
 
-/*!
- * \brief \ref cdr_object constructor
- * \param chan The \ref ast_channel_snapshot that is the CDR's Party A
- *
- * This implicitly sets the state of the newly created CDR to the Single state
- * (\ref single_state_fn_table)
- */
-static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
+/*! Duplicate a CDR record
+	\returns Pointer to new CDR record
+*/
+struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_object *cdr;
-
-	ast_assert(chan != NULL);
+	struct ast_cdr *newcdr;
 
-	cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
-	if (!cdr) {
+	if (!cdr) /* don't die if we get a null cdr pointer */
 		return NULL;
-	}
-	cdr->last = cdr;
-	if (ast_string_field_init(cdr, 64)) {
-		ao2_cleanup(cdr);
+	newcdr = ast_cdr_alloc();
+	if (!newcdr)
 		return NULL;
-	}
-	ast_string_field_set(cdr, uniqueid, chan->uniqueid);
-	ast_string_field_set(cdr, name, chan->name);
-	ast_string_field_set(cdr, linkedid, chan->linkedid);
-	cdr->disposition = AST_CDR_NULL;
-	cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
-
-	cdr->party_a.snapshot = chan;
-	ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
 
-	CDR_DEBUG(mod_cfg, "%p - Created CDR for channel %s\n", cdr, chan->name);
-
-	cdr_object_transition_state(cdr, &single_state_fn_table);
+	memcpy(newcdr, cdr, sizeof(*newcdr));
+	/* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
+	memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
+	ast_cdr_copy_vars(newcdr, cdr);
+	newcdr->next = NULL;
 
-	return cdr;
+	return newcdr;
 }
 
-/*!
- * \brief Create a new \ref cdr_object and append it to an existing chain
- * \param cdr The \ref cdr_object to append to
- */
-static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr)
+static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur)
 {
-	struct cdr_object *new_cdr;
-	struct cdr_object *it_cdr;
-	struct cdr_object *cdr_last;
-
-	cdr_last = cdr->last;
-	new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot);
-	if (!new_cdr) {
+	if (ast_strlen_zero(name))
 		return NULL;
+
+	for (; cdr; cdr = recur ? cdr->next : NULL) {
+		struct ast_var_t *variables;
+		struct varshead *headp = &cdr->varshead;
+		AST_LIST_TRAVERSE(headp, variables, entries) {
+			if (!strcasecmp(name, ast_var_name(variables)))
+				return ast_var_value(variables);
+		}
 	}
-	new_cdr->disposition = AST_CDR_NULL;
 
-	/* Copy over the linkedid, as it may have changed */
-	ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
-	ast_string_field_set(new_cdr, appl, cdr_last->appl);
-	ast_string_field_set(new_cdr, data, cdr_last->data);
+	return NULL;
+}
 
-	/* Copy over other Party A information */
-	cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
+static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
+{
+	if (fmt == NULL) {	/* raw mode */
+		snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
+	} else {
+		if (when.tv_sec) {
+			struct ast_tm tm;
 
-	/* Append the CDR to the end of the list */
-	for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
-		it_cdr->last = new_cdr;
+			ast_localtime(&when, &tm, NULL);
+			ast_strftime(buf, bufsize, fmt, &tm);
+		}
 	}
-	it_cdr->last = new_cdr;
-	it_cdr->next = new_cdr;
-
-	return new_cdr;
 }
 
-/*!
- * \brief Return whether or not a channel has changed its state in the dialplan, subject
- * to endbeforehexten logic
- *
- * \param old_snapshot The previous state
- * \param new_snapshot The new state
- *
- * \retval 0 if the state has not changed
- * \retval 1 if the state changed
- */
-static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
+/*! CDR channel variable retrieval */
+void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
 {
-	RAII_VAR(struct module_config *, mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
+	const char *fmt = "%Y-%m-%d %T";
+	const char *varbuf;
 
-	/* If we ignore hangup logic, don't indicate that we're executing anything new */
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)
-		&& ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-		return 0;
-	}
+	if (!cdr)  /* don't die if the cdr is null */
+		return;
 
-	/* When Party A is originated to an application and the application exits, the stack
-	 * will attempt to clear the application and restore the dummy originate application
-	 * of "AppDialX". Ignore application changes to AppDialX as a result.
-	 */
-	if (strcmp(new_snapshot->appl, old_snapshot->appl) && strncasecmp(new_snapshot->appl, "appdial", 7)
-		&& (strcmp(new_snapshot->context, old_snapshot->context)
-		|| strcmp(new_snapshot->exten, old_snapshot->exten)
-		|| new_snapshot->priority != old_snapshot->priority)) {
-		return 1;
-	}
+	*ret = NULL;
+	/* special vars (the ones from the struct ast_cdr when requested by name)
+	   I'd almost say we should convert all the stringed vals to vars */
 
-	return 0;
-}
+	if (!strcasecmp(name, "clid"))
+		ast_copy_string(workspace, cdr->clid, workspacelen);
+	else if (!strcasecmp(name, "src"))
+		ast_copy_string(workspace, cdr->src, workspacelen);
+	else if (!strcasecmp(name, "dst"))
+		ast_copy_string(workspace, cdr->dst, workspacelen);
+	else if (!strcasecmp(name, "dcontext"))
+		ast_copy_string(workspace, cdr->dcontext, workspacelen);
+	else if (!strcasecmp(name, "channel"))
+		ast_copy_string(workspace, cdr->channel, workspacelen);
+	else if (!strcasecmp(name, "dstchannel"))
+		ast_copy_string(workspace, cdr->dstchannel, workspacelen);
+	else if (!strcasecmp(name, "lastapp"))
+		ast_copy_string(workspace, cdr->lastapp, workspacelen);
+	else if (!strcasecmp(name, "lastdata"))
+		ast_copy_string(workspace, cdr->lastdata, workspacelen);
+	else if (!strcasecmp(name, "start"))
+		cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
+	else if (!strcasecmp(name, "answer"))
+		cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
+	else if (!strcasecmp(name, "end"))
+		cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
+	else if (!strcasecmp(name, "duration")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
+	} else if (!strcasecmp(name, "billsec")) {
+		snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);	
+	} else if (!strcasecmp(name, "disposition")) {
+		if (raw) {
+			snprintf(workspace, workspacelen, "%ld", cdr->disposition);
+		} else {
+			ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
+		}
+	} else if (!strcasecmp(name, "amaflags")) {
+		if (raw) {
+			snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
+		} else {
+			ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
+		}
+	} else if (!strcasecmp(name, "accountcode"))
+		ast_copy_string(workspace, cdr->accountcode, workspacelen);
+	else if (!strcasecmp(name, "peeraccount"))
+		ast_copy_string(workspace, cdr->peeraccount, workspacelen);
+	else if (!strcasecmp(name, "uniqueid"))
+		ast_copy_string(workspace, cdr->uniqueid, workspacelen);
+	else if (!strcasecmp(name, "linkedid"))
+		ast_copy_string(workspace, cdr->linkedid, workspacelen);
+	else if (!strcasecmp(name, "userfield"))
+		ast_copy_string(workspace, cdr->userfield, workspacelen);
+	else if (!strcasecmp(name, "sequence"))
+		snprintf(workspace, workspacelen, "%d", cdr->sequence);
+	else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
+		ast_copy_string(workspace, varbuf, workspacelen);
+	else
+		workspace[0] = '\0';
 
-/*!
- * \brief Return whether or not a \ref ast_channel_snapshot is for a channel
- * that was created as the result of a dial operation
- *
- * \retval 0 the channel was not created as the result of a dial
- * \retval 1 the channel was created as the result of a dial
- */
-static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
-{
-	return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
-			&& !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
+	if (!ast_strlen_zero(workspace))
+		*ret = workspace;
 }
 
-/*!
- * \brief Given two CDR snapshots, figure out who should be Party A for the
- * resulting CDR
- * \param left One of the snapshots
- * \param right The other snapshot
- * \retval The snapshot that won
- */
-static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
+/* readonly cdr variables */
+static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
+						  "lastapp", "lastdata", "start", "answer", "end", "duration",
+						  "billsec", "disposition", "amaflags", "accountcode", "uniqueid", "linkedid",
+						  "userfield", "sequence", NULL };
+/*! Set a CDR channel variable
+	\note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
+*/
+int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur)
 {
-	/* Check whether or not the party is dialed. A dialed party is never the
-	 * Party A with a party that was not dialed.
-	 */
-	if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
-		return left;
-	} else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
-		return right;
+	struct ast_var_t *newvariable;
+	struct varshead *headp;
+	int x;
+
+	for (x = 0; cdr_readonly_vars[x]; x++) {
+		if (!strcasecmp(name, cdr_readonly_vars[x])) {
+			ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
+			return -1;
+		}
 	}
 
-	/* Try the Party A flag */
-	if (ast_test_flag(left, AST_CDR_FLAG_PARTY_A) && !ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
-		return left;
-	} else if (!ast_test_flag(right, AST_CDR_FLAG_PARTY_A) && ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
-		return right;
+	if (!cdr) {
+		ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
+		return -1;
 	}
 
-	/* Neither party is dialed and neither has the Party A flag - defer to
-	 * creation time */
-	if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
-		return left;
-	} else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
-		return right;
-	} else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
-		return right;
-	} else {
-		/* Okay, fine, take the left one */
-		return left;
+	for (; cdr; cdr = recur ? cdr->next : NULL) {
+		if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			continue;
+		headp = &cdr->varshead;
+		AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
+			if (!strcasecmp(ast_var_name(newvariable), name)) {
+				/* there is already such a variable, delete it */
+				AST_LIST_REMOVE_CURRENT(entries);
+				ast_var_delete(newvariable);
+				break;
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END;
+
+		if (value && (newvariable = ast_var_assign(name, value))) {
+			AST_LIST_INSERT_HEAD(headp, newvariable, entries);
+		}
 	}
-}
 
-/*!
- * Compute the duration for a \ref cdr_object
- */
-static long cdr_object_get_duration(struct cdr_object *cdr)
-{
-	return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
+	return 0;
 }
 
-/*!
- * \brief Compute the billsec for a \ref cdr_object
- */
-static long cdr_object_get_billsec(struct cdr_object *cdr)
+int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	long int ms;
+	struct ast_var_t *variables, *newvariable = NULL;
+	struct varshead *headpa, *headpb;
+	const char *var, *val;
+	int x = 0;
 
-	if (ast_tvzero(cdr->answer)) {
+	if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
 		return 0;
-	}
-	ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_INITIATED_SECONDS)
-		&& (ms % 1000 >= 500)) {
-		ms = (ms / 1000) + 1;
-	} else {
-		ms = ms / 1000;
-	}
 
-	return ms;
-}
-
-/*!
- * \internal
- * \brief Set a variable on a CDR object
- *
- * \param headp The header pointer to the variable to set
- * \param name The name of the variable
- * \param value The value of the variable
- */
-static void set_variable(struct varshead *headp, const char *name, const char *value)
-{
-	struct ast_var_t *newvariable;
+	headpa = &from_cdr->varshead;
+	headpb = &to_cdr->varshead;
 
-	AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
-		if (!strcasecmp(ast_var_name(newvariable), name)) {
-			AST_LIST_REMOVE_CURRENT(entries);
-			ast_var_delete(newvariable);
-			break;
+	AST_LIST_TRAVERSE(headpa,variables,entries) {
+		if (variables &&
+		    (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
+		    !ast_strlen_zero(var) && !ast_strlen_zero(val) &&
+		    (newvariable = ast_var_assign(var, val))) {
+			AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
+			x++;
 		}
 	}
-	AST_LIST_TRAVERSE_SAFE_END;
 
-	if (value && (newvariable = ast_var_assign(name, value))) {
-		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
-	}
+	return x;
 }
 
-/*!
- * \brief Create a chain of \ref ast_cdr objects from a chain of \ref cdr_object
- * suitable for consumption by the registered CDR backends
- * \param cdr The \ref cdr_object to convert to a public record
- * \retval A chain of \ref ast_cdr objects on success
- * \retval NULL on failure
- */
-static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
+int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
 {
-	struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
-	struct cdr_object *it_cdr;
-	struct ast_var_t *it_var, *it_copy_var;
-	struct ast_channel_snapshot *party_a;
-	struct ast_channel_snapshot *party_b;
-
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		struct ast_cdr *cdr_copy;
-
-		/* Don't create records for CDRs where the party A was a dialed channel */
-		if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
-			ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
-				it_cdr->party_a.snapshot->name);
-			continue;
-		}
+	struct ast_var_t *variables;
+	const char *var;
+	char *tmp;
+	char workspace[256];
+	int total = 0, x = 0, i;
 
-		cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
-		if (!cdr_copy) {
-			ast_free(pub_cdr);
-			return NULL;
-		}
+	ast_str_reset(*buf);
 
-		party_a = it_cdr->party_a.snapshot;
-		party_b = it_cdr->party_b.snapshot;
-
-		/* Party A */
-		ast_assert(party_a != NULL);
-		ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
-		cdr_copy->amaflags = party_a->amaflags;
-		ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
-		ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
-		ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
-		ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
-		ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
-		ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
-		ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
-		ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
-
-		/* Party B */
-		if (party_b) {
-			ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
-			ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
-			if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
-				snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
-			}
-		}
-		if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
-			ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
-		}
+	for (; cdr; cdr = recur ? cdr->next : NULL) {
+		if (++x > 1)
+			ast_str_append(buf, 0, "\n");
 
-		/* Timestamps/durations */
-		cdr_copy->start = it_cdr->start;
-		cdr_copy->answer = it_cdr->answer;
-		cdr_copy->end = it_cdr->end;
-		cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
-		cdr_copy->duration = cdr_object_get_duration(it_cdr);
-
-		/* Flags and IDs */
-		ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
-		ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
-		cdr_copy->disposition = it_cdr->disposition;
-		cdr_copy->sequence = it_cdr->sequence;
-
-		/* Variables */
-		copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
-		AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
-			int found = 0;
-			struct ast_var_t *newvariable;
-			AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
-				if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
-					found = 1;
-					break;
-				}
-			}
-			if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
-				AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
+		AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
+			if (!(var = ast_var_name(variables))) {
+				continue;
 			}
-		}
-
-		if (!pub_cdr) {
-			pub_cdr = cdr_copy;
-			cdr_prev = pub_cdr;
-		} else {
-			cdr_prev->next = cdr_copy;
-			cdr_prev = cdr_copy;
-		}
-	}
-
-	return pub_cdr;
-}
 
-/*!
- * \brief Dispatch a CDR.
- * \param cdr The \ref cdr_object to dispatch
- *
- * This will create a \ref ast_cdr object and publish it to the various backends
- */
-static void cdr_object_dispatch(struct cdr_object *cdr)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct ast_cdr *pub_cdr;
-
-	CDR_DEBUG(mod_cfg, "%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
-			cdr->party_a.snapshot->name,
-			cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<none>");
-	pub_cdr = cdr_object_create_public_records(cdr);
-	cdr_detach(pub_cdr);
-}
+			if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep) < 0) {
+				ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
+				break;
+			}
 
-/*!
- * \brief Set the disposition on a \ref cdr_object based on a hangupcause code
- * \param cdr The \ref cdr_object
- * \param hangupcause The Asterisk hangup cause code
- */
-static void cdr_object_set_disposition(struct cdr_object *cdr, int hangupcause)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	/* Change the disposition based on the hang up cause */
-	switch (hangupcause) {
-	case AST_CAUSE_BUSY:
-		cdr->disposition = AST_CDR_BUSY;
-		break;
-	case AST_CAUSE_CONGESTION:
-		if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) {
-			cdr->disposition = AST_CDR_FAILED;
-		} else {
-			cdr->disposition = AST_CDR_CONGESTION;
+			total++;
 		}
-		break;
-	case AST_CAUSE_NO_ROUTE_DESTINATION:
-	case AST_CAUSE_UNREGISTERED:
-		cdr->disposition = AST_CDR_FAILED;
-		break;
-	case AST_CAUSE_NORMAL_CLEARING:
-	case AST_CAUSE_NO_ANSWER:
-		cdr->disposition = AST_CDR_NOANSWER;
-		break;
-	default:
-		break;
-	}
-}
 
-/*!
- * \brief Finalize a CDR.
- *
- * This function is safe to call multiple times. Note that you can call this
- * explicitly before going to the finalized state if there's a chance the CDR
- * will be re-activated, in which case the \ref cdr_object's end time should be
- * cleared. This function is implicitly called when a CDR transitions to the
- * finalized state and right before it is dispatched
- *
- * \param cdr_object The CDR to finalize
- */
-static void cdr_object_finalize(struct cdr_object *cdr)
-{
-	if (!ast_tvzero(cdr->end)) {
-		return;
-	}
-	cdr->end = ast_tvnow();
+		for (i = 0; cdr_readonly_vars[i]; i++) {
+			workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
+			ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
+			if (!tmp)
+				continue;
 
-	if (cdr->disposition == AST_CDR_NULL) {
-		if (!ast_tvzero(cdr->answer)) {
-			cdr->disposition = AST_CDR_ANSWERED;
-		} else if (cdr->party_a.snapshot->hangupcause) {
-			cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
-		} else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangupcause) {
-			cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangupcause);
-		} else {
-			cdr->disposition = AST_CDR_FAILED;
+			if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
+				ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
+				break;
+			} else
+				total++;
 		}
 	}
 
-	/* tv_usec is suseconds_t, which could be int or long */
-	ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dispo %s\n",
-			cdr->party_a.snapshot->name,
-			cdr->start.tv_sec,
-			(long)cdr->start.tv_usec,
-			cdr->answer.tv_sec,
-			(long)cdr->answer.tv_usec,
-			cdr->end.tv_sec,
-			(long)cdr->end.tv_usec,
-			ast_cdr_disp2str(cdr->disposition));
+	return total;
 }
 
-/*!
- * \brief Check to see if a CDR needs to move to the finalized state because
- * its Party A hungup.
- */
-static void cdr_object_check_party_a_hangup(struct cdr_object *cdr)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)
-		&& ast_test_flag(&cdr->party_a.snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-		cdr_object_finalize(cdr);
-	}
 
-	if (ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_DEAD)
-		&& cdr->fn_table != &finalized_state_fn_table) {
-		cdr_object_transition_state(cdr, &finalized_state_fn_table);
-	}
-}
+void ast_cdr_free_vars(struct ast_cdr *cdr, int recur)
+{
 
-/*!
- * \brief Check to see if a CDR needs to be answered based on its Party A.
- * Note that this is safe to call as much as you want - we won't answer twice
- */
-static void cdr_object_check_party_a_answer(struct cdr_object *cdr) {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
-		cdr->answer = ast_tvnow();
-		/* tv_usec is suseconds_t, which could be int or long */
-		CDR_DEBUG(mod_cfg, "%p - Set answered time to %ld.%06ld\n", cdr,
-			cdr->answer.tv_sec,
-			(long)cdr->answer.tv_usec);
+	/* clear variables */
+	for (; cdr; cdr = recur ? cdr->next : NULL) {
+		struct ast_var_t *vardata;
+		struct varshead *headp = &cdr->varshead;
+		while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
+			ast_var_delete(vardata);
 	}
 }
 
-/* \brief Set Caller ID information on a CDR */
-static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
+/*! \brief  print a warning if cdr already posted */
+static void check_post(struct ast_cdr *cdr)
 {
-	if (!old_snapshot->snapshot) {
-		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
-		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
-		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+	if (!cdr)
 		return;
-	}
-	if (!strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) {
-		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
-	}
-	if (!strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) {
-		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
-	}
-	if (!strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) {
-		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
-	}
+	if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
+		ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
 }
 
-/*!
- * \brief Swap an old \ref cdr_object_snapshot's \ref ast_channel_snapshot for
- * a new \ref ast_channel_snapshot
- * \param old_snapshot The old \ref cdr_object_snapshot
- * \param new_snapshot The new \ref ast_channel_snapshot for old_snapshot
- */
-static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
-		struct ast_channel_snapshot *new_snapshot)
-{
-	cdr_object_update_cid(old_snapshot, new_snapshot);
-	if (old_snapshot->snapshot) {
-		ao2_t_ref(old_snapshot->snapshot, -1, "Drop ref for swap");
-	}
-	ao2_t_ref(new_snapshot, +1, "Bump ref for swap");
-	old_snapshot->snapshot = new_snapshot;
-}
-
-/* BASE METHOD IMPLEMENTATIONS */
-
-static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+void ast_cdr_free(struct ast_cdr *cdr)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
 
-	ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
-
-	/* Ignore any snapshots from a dead or dying channel */
-	if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
-			&& ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
-		cdr_object_check_party_a_hangup(cdr);
-		return 0;
-	}
-
-	/*
-	 * Only record the context and extension if we aren't in a subroutine, or if
-	 * we are executing hangup logic.
-	 */
-	if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
-		|| ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-		ast_string_field_set(cdr, context, snapshot->context);
-		ast_string_field_set(cdr, exten, snapshot->exten);
-	}
+	while (cdr) {
+		struct ast_cdr *next = cdr->next;
 
-	cdr_object_swap_snapshot(&cdr->party_a, snapshot);
-
-	/* When Party A is originated to an application and the application exits, the stack
-	 * will attempt to clear the application and restore the dummy originate application
-	 * of "AppDialX". Prevent that, and any other application changes we might not want
-	 * here.
-	 */
-	if (!ast_strlen_zero(snapshot->appl)
-			&& (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))
-			&& !ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)) {
-		ast_string_field_set(cdr, appl, snapshot->appl);
-		ast_string_field_set(cdr, data, snapshot->data);
-
-		/* Dial (app_dial) is a special case. Because pre-dial handlers, which
-		 * execute before the dial begins, will alter the application/data to
-		 * something people typically don't want to see, if we see a channel enter
-		 * into Dial here, we set the appl/data accordingly and lock it.
-		 */
-		if (!strcmp(snapshot->appl, "Dial")) {
-			ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-		}
+		ast_cdr_free_vars(cdr, 0);
+		ast_free(cdr);
+		cdr = next;
 	}
-
-	ast_string_field_set(cdr, linkedid, snapshot->linkedid);
-	cdr_object_check_party_a_answer(cdr);
-	cdr_object_check_party_a_hangup(cdr);
-
-	return 0;
-}
-
-static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	/* In general, most things shouldn't get a bridge leave */
-	ast_assert(0);
-	return 1;
-}
-
-static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
-{
-	/* In general, most things shouldn't get a dial end. */
-	ast_assert(0);
-	return 0;
-}
-
-static enum process_bridge_enter_results base_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	/* Base process bridge enter simply indicates that we can't handle it */
-	return BRIDGE_ENTER_NEED_CDR;
-}
-
-static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
-{
-	char park_info[128];
-
-	ast_assert(!strcasecmp(parking_info->parkee->name, cdr->party_a.snapshot->name));
-
-	/* Update Party A information regardless */
-	cdr->fn_table->process_party_a(cdr, parking_info->parkee);
-
-	/* Fake out where we're parked */
-	ast_string_field_set(cdr, appl, "Park");
-	snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
-	ast_string_field_set(cdr, data, park_info);
-
-	/* Prevent any further changes to the App/Data fields for this record */
-	ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-
-	return 0;
 }
 
-/* SINGLE STATE */
-
-static void single_state_init_function(struct cdr_object *cdr) {
-	cdr->start = ast_tvnow();
-	cdr_object_check_party_a_answer(cdr);
-}
-
-static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+/*! \brief the same as a cdr_free call, only with no checks; just get rid of it */
+void ast_cdr_discard(struct ast_cdr *cdr)
 {
-	/* This should never happen! */
-	ast_assert(cdr->party_b.snapshot == NULL);
-	ast_assert(0);
-	return;
-}
+	while (cdr) {
+		struct ast_cdr *next = cdr->next;
 
-static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) {
-		base_process_party_a(cdr, caller);
-		CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr,
-				cdr->party_a.snapshot->name);
-		cdr_object_swap_snapshot(&cdr->party_b, peer);
-		CDR_DEBUG(mod_cfg, "%p - Updated Party B %s snapshot\n", cdr,
-				cdr->party_b.snapshot->name);
-
-		/* If we have two parties, lock the application that caused the
-		 * two parties to be associated. This prevents mid-call event
-		 * macros/gosubs from perturbing the CDR application/data
-		 */
-		ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-	} else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) {
-		/* We're the entity being dialed, i.e., outbound origination */
-		base_process_party_a(cdr, peer);
-		CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr,
-				cdr->party_a.snapshot->name);
+		ast_cdr_free_vars(cdr, 0);
+		ast_free(cdr);
+		cdr = next;
 	}
-
-	cdr_object_transition_state(cdr, &dial_state_fn_table);
-	return 0;
 }
 
-/*!
- * \brief Handle a comparison between our \ref cdr_object and a \ref cdr_object
- * already in the bridge while in the Single state. The goal of this is to find
- * a Party B for our CDR.
- *
- * \param cdr Our \ref cdr_object in the Single state
- * \param cand_cdr The \ref cdr_object already in the Bridge state
- *
- * \retval 0 The cand_cdr had a Party A or Party B that we could use as our
- * Party B
- * \retval 1 No party in the cand_cdr could be used as our Party B
- */
-static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
-		struct cdr_object *cand_cdr)
+struct ast_cdr *ast_cdr_alloc(void)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_object_snapshot *party_a;
-
-	/* Don't match on ourselves */
-	if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)) {
-		return 1;
-	}
-
-	/* Try the candidate CDR's Party A first */
-	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
-	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
-		CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
-			cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
-		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
-		if (!cand_cdr->party_b.snapshot) {
-			/* We just stole them - finalize their CDR. Note that this won't
-			 * transition their state, it just sets the end time and the
-			 * disposition - if we need to re-activate them later, we can.
-			 */
-			cdr_object_finalize(cand_cdr);
-		}
-		return 0;
-	}
-
-	/* Try their Party B, unless it's us */
-	if (!cand_cdr->party_b.snapshot
-		|| !strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name)) {
-		return 1;
-	}
-	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
-	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
-		CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
-			cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
-		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
-		return 0;
-	}
-
-	return 1;
+	struct ast_cdr *x;
+	x = ast_calloc(1, sizeof(*x));
+	if (!x)
+		ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
+	return x;
 }
 
-static enum process_bridge_enter_results single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+static void cdr_merge_vars(struct ast_cdr *to, struct ast_cdr *from)
 {
-	struct ao2_iterator it_cdrs;
-	char *channel_id;
-	int success = 0;
-
-	ast_string_field_set(cdr, bridge, bridge->uniqueid);
-
-	if (ao2_container_count(bridge->channels) == 1) {
-		/* No one in the bridge yet but us! */
-		cdr_object_transition_state(cdr, &bridge_state_fn_table);
-		return BRIDGE_ENTER_ONLY_PARTY;
-	}
-
-	for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
-		!success && (channel_id = ao2_iterator_next(&it_cdrs));
-		ao2_ref(channel_id, -1)) {
-		RAII_VAR(struct cdr_object *, cand_cdr_master,
-			ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
-			ao2_cleanup);
-		struct cdr_object *cand_cdr;
-
-		if (!cand_cdr_master) {
-			continue;
-		}
+	struct ast_var_t *variablesfrom,*variablesto;
+	struct varshead *headpfrom = &to->varshead;
+	struct varshead *headpto = &from->varshead;
+	AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
+		/* for every var in from, stick it in to */
+		const char *fromvarname, *fromvarval;
+		const char *tovarname = NULL, *tovarval = NULL;
+		fromvarname = ast_var_name(variablesfrom);
+		fromvarval = ast_var_value(variablesfrom);
+		tovarname = 0;
 
-		ao2_lock(cand_cdr_master);
-		for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
-			/* Skip any records that are not in a bridge or in this bridge.
-			 * I'm not sure how that would happen, but it pays to be careful. */
-			if (cand_cdr->fn_table != &bridge_state_fn_table ||
-					strcmp(cdr->bridge, cand_cdr->bridge)) {
-				continue;
-			}
+		/* now, quick see if that var is in the 'to' cdr already */
+		AST_LIST_TRAVERSE(headpto, variablesto, entries) {
 
-			if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
-				continue;
+			/* now, quick see if that var is in the 'to' cdr already */
+			if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
+				tovarname = ast_var_name(variablesto);
+				tovarval = ast_var_value(variablesto);
+				break;
 			}
-			/* We successfully got a party B - break out */
-			success = 1;
-			break;
 		}
-		ao2_unlock(cand_cdr_master);
-	}
-	ao2_iterator_destroy(&it_cdrs);
-
-	/* We always transition state, even if we didn't get a peer */
-	cdr_object_transition_state(cdr, &bridge_state_fn_table);
+		if (tovarname && strcasecmp(fromvarval,tovarval) != 0) {  /* this message here to see how irritating the userbase finds it */
+			ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
+			continue;
+		} else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
+			continue;
 
-	/* Success implies that we have a Party B */
-	if (success) {
-		return BRIDGE_ENTER_OBTAINED_PARTY_B;
+		/* rip this var out of the from cdr, and stick it in the to cdr */
+		AST_LIST_MOVE_CURRENT(headpto, entries);
 	}
-
-	return BRIDGE_ENTER_NO_PARTY_B;
-}
-
-static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	cdr_object_transition_state(cdr, &parked_state_fn_table);
-	return 0;
+	AST_LIST_TRAVERSE_SAFE_END;
 }
 
-
-/* DIAL STATE */
-
-static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from)
 {
-	ast_assert(snapshot != NULL);
+	struct ast_cdr *zcdr;
+	struct ast_cdr *lto = NULL;
+	struct ast_cdr *lfrom = NULL;
+	int discard_from = 0;
 
-	if (!cdr->party_b.snapshot
-		|| strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
+	if (!to || !from)
 		return;
-	}
-	cdr_object_swap_snapshot(&cdr->party_b, snapshot);
-
-	/* If party B hangs up, finalize this CDR */
-	if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_DEAD)) {
-		cdr_object_transition_state(cdr, &finalized_state_fn_table);
-	}
-}
-
-static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
-{
-	/* Don't process a begin dial here. A party A already in the dial state will
-	 * who receives a dial begin for something else will be handled by the
-	 * message router callback and will add a new CDR for the party A */
-	return 1;
-}
 
-/*!
- * \internal
- * \brief Convert a dial status to a CDR disposition
- */
-static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (!strcmp(dial_status, "ANSWER")) {
-		return AST_CDR_ANSWERED;
-	} else if (!strcmp(dial_status, "BUSY")) {
-		return AST_CDR_BUSY;
-	} else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
-		return AST_CDR_NOANSWER;
-	} else if (!strcmp(dial_status, "CONGESTION")) {
-		if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) {
-			return AST_CDR_FAILED;
-		} else {
-			return AST_CDR_CONGESTION;
+	/* don't merge into locked CDR's -- it's bad business */
+	if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
+		zcdr = to; /* safety valve? */
+		while (to->next) {
+			lto = to;
+			to = to->next;
 		}
-	} else if (!strcmp(dial_status, "FAILED")) {
-		return AST_CDR_FAILED;
-	}
-	return AST_CDR_FAILED;
-}
-
-static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
-{
-	struct ast_channel_snapshot *party_a;
-
-	if (caller) {
-		party_a = caller;
-	} else {
-		party_a = peer;
-	}
-	ast_assert(!strcasecmp(cdr->party_a.snapshot->name, party_a->name));
-	cdr_object_swap_snapshot(&cdr->party_a, party_a);
 
-	if (cdr->party_b.snapshot) {
-		if (strcasecmp(cdr->party_b.snapshot->name, peer->name)) {
-			/* Not the status for this CDR - defer back to the message router */
-			return 1;
+		if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
+			ast_log(LOG_WARNING, "Merging into locked CDR... no choice.\n");
+			to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
+			lto = NULL;
 		}
-		cdr_object_swap_snapshot(&cdr->party_b, peer);
 	}
 
-	/* Set the disposition based on the dial string. */
-	cdr->disposition = dial_status_to_disposition(dial_status);
-	if (cdr->disposition == AST_CDR_ANSWERED) {
-		/* Switch to dial pending to wait and see what the caller does */
-		cdr_object_transition_state(cdr, &dialed_pending_state_fn_table);
-	} else {
-		cdr_object_transition_state(cdr, &finalized_state_fn_table);
-	}
-
-	return 0;
-}
-
-static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	struct ao2_iterator it_cdrs;
-	char *channel_id;
-	int success = 0;
-
-	ast_string_field_set(cdr, bridge, bridge->uniqueid);
-
-	/* Get parties in the bridge */
-	if (ao2_container_count(bridge->channels) == 1) {
-		/* No one in the bridge yet but us! */
-		cdr_object_transition_state(cdr, &bridge_state_fn_table);
-		return BRIDGE_ENTER_ONLY_PARTY;
-	}
-
-	for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
-		!success && (channel_id = ao2_iterator_next(&it_cdrs));
-		ao2_ref(channel_id, -1)) {
-		RAII_VAR(struct cdr_object *, cand_cdr_master,
-			ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
-			ao2_cleanup);
-		struct cdr_object *cand_cdr;
-
-		if (!cand_cdr_master) {
-			continue;
-		}
-
-		ao2_lock(cand_cdr_master);
-		for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
-			/* Skip any records that are not in a bridge or in this bridge.
-			 * I'm not sure how that would happen, but it pays to be careful. */
-			if (cand_cdr->fn_table != &bridge_state_fn_table ||
-					strcmp(cdr->bridge, cand_cdr->bridge)) {
-				continue;
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
+		struct ast_cdr *llfrom = NULL;
+		discard_from = 1;
+		if (lto) {
+			/* insert the from stuff after lto */
+			lto->next = from;
+			lfrom = from;
+			while (lfrom && lfrom->next) {
+				if (!lfrom->next->next)
+					llfrom = lfrom;
+				lfrom = lfrom->next;
 			}
-
-			/* If we don't have a Party B (originated channel), skip it */
-			if (!cdr->party_b.snapshot) {
-				continue;
+			/* rip off the last entry and put a copy of the to at the end */
+			if (llfrom) {
+				llfrom->next = to;
 			}
-
-			/* Skip any records that aren't our Party B */
-			if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
-				continue;
+			from = lfrom;
+		} else {
+			/* save copy of the current *to cdr */
+			struct ast_cdr tcdr;
+			memcpy(&tcdr, to, sizeof(tcdr));
+			/* copy in the locked from cdr */
+			memcpy(to, from, sizeof(*to));
+			lfrom = from;
+			while (lfrom && lfrom->next) {
+				if (!lfrom->next->next)
+					llfrom = lfrom;
+				lfrom = lfrom->next;
 			}
-			cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
-			/* If they have a Party B, they joined up with someone else as their
-			 * Party A. Don't finalize them as they're active. Otherwise, we
-			 * have stolen them so they need to be finalized.
-			 */
-			if (!cand_cdr->party_b.snapshot) {
-				cdr_object_finalize(cand_cdr);
+			from->next = NULL;
+			/* rip off the last entry and put a copy of the to at the end */
+			if (llfrom == from) {
+				to = to->next = ast_cdr_dup(&tcdr);
+			} else if (llfrom) {
+				to = llfrom->next = ast_cdr_dup(&tcdr);
 			}
-			success = 1;
-			break;
+			from = lfrom;
 		}
-		ao2_unlock(cand_cdr_master);
 	}
-	ao2_iterator_destroy(&it_cdrs);
 
-	/* We always transition state, even if we didn't get a peer */
-	cdr_object_transition_state(cdr, &bridge_state_fn_table);
-
-	/* Success implies that we have a Party B */
-	if (success) {
-		return BRIDGE_ENTER_OBTAINED_PARTY_B;
+	if (!ast_tvzero(from->start)) {
+		if (!ast_tvzero(to->start)) {
+			if (ast_tvcmp(to->start, from->start) > 0 ) {
+				to->start = from->start; /* use the earliest time */
+				from->start = ast_tv(0,0); /* we actively "steal" these values */
+			}
+			/* else nothing to do */
+		} else {
+			to->start = from->start;
+			from->start = ast_tv(0,0); /* we actively "steal" these values */
+		}
 	}
-	return BRIDGE_ENTER_NO_PARTY_B;
-}
-
-/* DIALED PENDING STATE */
-
-static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
-{
-	/* If we get a CEP change, we're executing dialplan. If we have a Party B
-	 * that means we need a new CDR; otherwise, switch us over to single.
-	 */
-	if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
-		if (cdr->party_b.snapshot) {
-			cdr_object_transition_state(cdr, &finalized_state_fn_table);
-			cdr->fn_table->process_party_a(cdr, snapshot);
-			return 1;
+	if (!ast_tvzero(from->answer)) {
+		if (!ast_tvzero(to->answer)) {
+			if (ast_tvcmp(to->answer, from->answer) > 0 ) {
+				to->answer = from->answer; /* use the earliest time */
+				from->answer = ast_tv(0,0); /* we actively "steal" these values */
+			}
+			/* we got the earliest answer time, so we'll settle for that? */
 		} else {
-			cdr_object_transition_state(cdr, &single_state_fn_table);
-			cdr->fn_table->process_party_a(cdr, snapshot);
-			return 0;
+			to->answer = from->answer;
+			from->answer = ast_tv(0,0); /* we actively "steal" these values */
 		}
 	}
-	base_process_party_a(cdr, snapshot);
-	return 0;
-}
-
-static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	cdr_object_transition_state(cdr, &dial_state_fn_table);
-	return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
-}
-
-static int dialed_pending_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	if (cdr->party_b.snapshot) {
-		/* We can't handle this as we have a Party B - ask for a new one */
-		return 1;
+	if (!ast_tvzero(from->end)) {
+		if (!ast_tvzero(to->end)) {
+			if (ast_tvcmp(to->end, from->end) < 0 ) {
+				to->end = from->end; /* use the latest time */
+				from->end = ast_tv(0,0); /* we actively "steal" these values */
+				to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
+				to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
+			}
+			/* else, nothing to do */
+		} else {
+			to->end = from->end;
+			from->end = ast_tv(0,0); /* we actively "steal" these values */
+			to->duration = to->end.tv_sec - to->start.tv_sec;
+			to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
+		}
 	}
-	cdr_object_transition_state(cdr, &parked_state_fn_table);
-	return 0;
-}
-
-static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
-{
-	cdr_object_transition_state(cdr, &finalized_state_fn_table);
-
-	/* Ask for a new CDR */
-	return 1;
-}
-
-/* BRIDGE STATE */
-
-static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
-{
-	if (!cdr->party_b.snapshot
-		|| strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
-		return;
+	if (to->disposition < from->disposition) {
+		to->disposition = from->disposition;
+		from->disposition = AST_CDR_NOANSWER;
 	}
-	cdr_object_swap_snapshot(&cdr->party_b, snapshot);
-
-	/* If party B hangs up, finalize this CDR */
-	if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_DEAD)) {
-		cdr_object_transition_state(cdr, &finalized_state_fn_table);
+	if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
+		ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
+		from->lastapp[0] = 0; /* theft */
 	}
-}
-
-static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	if (strcmp(cdr->bridge, bridge->uniqueid)) {
-		return 1;
+	if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
+		ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
+		from->lastdata[0] = 0; /* theft */
 	}
-	if (strcasecmp(cdr->party_a.snapshot->name, channel->name)
-		&& cdr->party_b.snapshot
-		&& strcasecmp(cdr->party_b.snapshot->name, channel->name)) {
-		return 1;
+	if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
+		ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
+		from->dcontext[0] = 0; /* theft */
 	}
-	cdr_object_transition_state(cdr, &finalized_state_fn_table);
-
-	return 0;
-}
-
-/* PARKED STATE */
-
-static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
-{
-	if (strcasecmp(cdr->party_a.snapshot->name, channel->name)) {
-		return 1;
+	if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
+		ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
+		from->dstchannel[0] = 0; /* theft */
 	}
-	cdr_object_transition_state(cdr, &finalized_state_fn_table);
-
-	return 0;
-}
-
-/* FINALIZED STATE */
-
-static void finalized_state_init_function(struct cdr_object *cdr)
-{
-	cdr_object_finalize(cdr);
-}
-
-static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
-			&& ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
-		return 0;
-	}
-
-	/* Indicate that, if possible, we should get a new CDR */
-	return 1;
-}
-
-/*!
- * \internal
- * \brief Filter channel snapshots by technology
- */
-static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
-{
-	return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
-}
-
-/*!
- * \internal
- * \brief Filter a channel cache update
- */
-static int filter_channel_cache_message(struct ast_channel_snapshot *old_snapshot,
-		struct ast_channel_snapshot *new_snapshot)
-{
-	int ret = 0;
-
-	/* Drop cache updates from certain channel technologies */
-	if (old_snapshot) {
-		ret |= filter_channel_snapshot(old_snapshot);
-	}
-	if (new_snapshot) {
-		ret |= filter_channel_snapshot(new_snapshot);
-	}
-
-	return ret;
-}
-
-/* TOPIC ROUTER CALLBACKS */
-
-/*!
- * \brief Handler for Stasis-Core dial messages
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message The message
- */
-static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
-	struct ast_multi_channel_blob *payload = stasis_message_data(message);
-	struct ast_channel_snapshot *caller;
-	struct ast_channel_snapshot *peer;
-	struct cdr_object *it_cdr;
-	struct ast_json *dial_status_blob;
-	const char *dial_status = NULL;
-	int res = 1;
-
-	caller = ast_multi_channel_blob_get_channel(payload, "caller");
-	peer = ast_multi_channel_blob_get_channel(payload, "peer");
-	if (!peer && !caller) {
-		return;
-	}
-	dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
-	if (dial_status_blob) {
-		dial_status = ast_json_string_get(dial_status_blob);
-	}
-
-	CDR_DEBUG(mod_cfg, "Dial %s message for %s, %s: %u.%08u\n",
-			ast_strlen_zero(dial_status) ? "Begin" : "End",
-			caller ? caller->name : "(none)",
-			peer ? peer->name : "(none)",
-			(unsigned int)stasis_message_timestamp(message)->tv_sec,
-			(unsigned int)stasis_message_timestamp(message)->tv_usec);
-
-	if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) {
-		return;
-	}
-
-	/* Figure out who is running this show */
-	if (caller) {
-		cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_KEY);
-	} else {
-		cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_KEY);
-	}
-
-	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
-		ast_assert(0);
-		return;
-	}
-
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (ast_strlen_zero(dial_status)) {
-			if (!it_cdr->fn_table->process_dial_begin) {
-				continue;
-			}
-			CDR_DEBUG(mod_cfg, "%p - Processing Dial Begin message for channel %s, peer %s\n",
-					it_cdr,
-					caller ? caller->name : "(none)",
-					peer ? peer->name : "(none)");
-			res &= it_cdr->fn_table->process_dial_begin(it_cdr,
-					caller,
-					peer);
-		} else {
-			if (!it_cdr->fn_table->process_dial_end) {
-				continue;
-			}
-			CDR_DEBUG(mod_cfg, "%p - Processing Dial End message for channel %s, peer %s\n",
-					it_cdr,
-					caller ? caller->name : "(none)",
-					peer ? peer->name : "(none)");
-			it_cdr->fn_table->process_dial_end(it_cdr,
-					caller,
-					peer,
-					dial_status);
-		}
-	}
-
-	/* If no CDR handled a dial begin message, make a new one */
-	if (res && ast_strlen_zero(dial_status)) {
-		struct cdr_object *new_cdr;
-
-		new_cdr = cdr_object_create_and_append(cdr);
-		if (!new_cdr) {
-			ao2_unlock(cdr);
-			return;
-		}
-		new_cdr->fn_table->process_dial_begin(new_cdr,
-				caller,
-				peer);
-	}
-	ao2_unlock(cdr);
-}
-
-static int cdr_object_finalize_party_b(void *obj, void *arg, int flags)
-{
-	struct cdr_object *cdr = obj;
-	struct ast_channel_snapshot *party_b = arg;
-	struct cdr_object *it_cdr;
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->party_b.snapshot
-			&& !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) {
-			/* Don't transition to the finalized state - let the Party A do
-			 * that when its ready
-			 */
-			cdr_object_finalize(it_cdr);
-		}
-	}
-	return 0;
-}
-
-static int cdr_object_update_party_b(void *obj, void *arg, int flags)
-{
-	struct cdr_object *cdr = obj;
-	struct ast_channel_snapshot *party_b = arg;
-	struct cdr_object *it_cdr;
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (!it_cdr->fn_table->process_party_b) {
-			continue;
-		}
-		if (it_cdr->party_b.snapshot
-			&& !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) {
-			it_cdr->fn_table->process_party_b(it_cdr, party_b);
-		}
-	}
-	return 0;
-}
-
-/*! \brief Determine if we need to add a new CDR based on snapshots */
-static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
-		struct ast_channel_snapshot *new_snapshot)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	/* If we're dead, we don't need a new CDR */
-	if (!new_snapshot
-		|| (ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
-			&& ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN))) {
-		return 0;
-	}
-
-	/* Auto-fall through will increment the priority but have no application */
-	if (ast_strlen_zero(new_snapshot->appl)) {
-		return 0;
-	}
-
-	if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
-		return 0;
-	}
-
-	return 1;
-}
-
-/*!
- * \brief Handler for Stasis-Core channel cache update messages
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message The message
- */
-static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct stasis_cache_update *update = stasis_message_data(message);
-	struct ast_channel_snapshot *old_snapshot;
-	struct ast_channel_snapshot *new_snapshot;
-	const char *uniqueid;
-	const char *name;
-	struct cdr_object *it_cdr;
-
-	ast_assert(update != NULL);
-	ast_assert(ast_channel_snapshot_type() == update->type);
-
-	old_snapshot = stasis_message_data(update->old_snapshot);
-	new_snapshot = stasis_message_data(update->new_snapshot);
-	uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
-	name = new_snapshot ? new_snapshot->name : old_snapshot->name;
-
-	if (filter_channel_cache_message(old_snapshot, new_snapshot)) {
-		return;
-	}
-
-	if (new_snapshot && !old_snapshot) {
-		cdr = cdr_object_alloc(new_snapshot);
-		if (!cdr) {
-			return;
-		}
-		ao2_link(active_cdrs_by_channel, cdr);
-	}
-
-	/* Handle Party A */
-	if (!cdr) {
-		cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_KEY);
-	}
-	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);
-		ast_assert(0);
-	} else {
-		ao2_lock(cdr);
-		if (new_snapshot) {
-			int all_reject = 1;
-			for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-				if (!it_cdr->fn_table->process_party_a) {
-					continue;
-				}
-				all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot);
-			}
-			if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {
-				/* We're not hung up and we have a new snapshot - we need a new CDR */
-				struct cdr_object *new_cdr;
-				new_cdr = cdr_object_create_and_append(cdr);
-				if (new_cdr) {
-					new_cdr->fn_table->process_party_a(new_cdr, new_snapshot);
-				}
-			}
-		} else {
-			CDR_DEBUG(mod_cfg, "%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name);
-			for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-				cdr_object_finalize(it_cdr);
-			}
-			cdr_object_dispatch(cdr);
-			ao2_unlink(active_cdrs_by_channel, cdr);
-		}
-		ao2_unlock(cdr);
-	}
-
-	/* Handle Party B */
-	if (new_snapshot) {
-		ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_update_party_b,
-			new_snapshot);
-	} else {
-		ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_finalize_party_b,
-			old_snapshot);
-	}
-
-}
-
-struct bridge_leave_data {
-	struct ast_bridge_snapshot *bridge;
-	struct ast_channel_snapshot *channel;
-};
-
-/*! \brief Callback used to notify CDRs of a Party B leaving the bridge */
-static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, int flags)
-{
-	struct cdr_object *cdr = obj;
-	struct bridge_leave_data *leave_data = arg;
-	struct cdr_object *it_cdr;
-
-	if (strcmp(cdr->bridge, leave_data->bridge->uniqueid)) {
-		return 0;
-	}
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table != &bridge_state_fn_table) {
-			continue;
-		}
-		if (!it_cdr->party_b.snapshot) {
-			continue;
-		}
-		if (strcasecmp(it_cdr->party_b.snapshot->name, leave_data->channel->name)) {
-			continue;
-		}
-		/* It is our Party B, in our bridge. Set the end time and let the handler
-		 * transition our CDR appropriately when we leave the bridge.
-		 */
-		cdr_object_finalize(it_cdr);
-	}
-	return 0;
-}
-
-/*! \brief Filter bridge messages based on bridge technology */
-static int filter_bridge_messages(struct ast_bridge_snapshot *bridge)
-{
-	/* Ignore holding bridge technology messages. We treat this simply as an application
-	 * that a channel enters into.
-	 */
-	if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
-		return 1;
-	}
-	return 0;
-}
-
-/*!
- * \brief Handler for when a channel leaves a bridge
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message The message - hopefully a bridge one!
- */
-static void handle_bridge_leave_message(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_bridge_blob *update = stasis_message_data(message);
-	struct ast_bridge_snapshot *bridge = update->bridge;
-	struct ast_channel_snapshot *channel = update->channel;
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-	RAII_VAR(struct cdr_object *, cdr,
-			ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
-			ao2_cleanup);
-	struct cdr_object *it_cdr;
-	struct bridge_leave_data leave_data = {
-		.bridge = bridge,
-		.channel = channel,
-	};
-	int left_bridge = 0;
-
-	if (filter_bridge_messages(bridge)) {
-		return;
-	}
-
-	if (filter_channel_snapshot(channel)) {
-		return;
-	}
-
-	CDR_DEBUG(mod_cfg, "Bridge Leave message for %s: %u.%08u\n",
-			channel->name,
-			(unsigned int)stasis_message_timestamp(message)->tv_sec,
-			(unsigned int)stasis_message_timestamp(message)->tv_usec);
-
-	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
-		ast_assert(0);
-		return;
-	}
-
-	/* Party A */
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (!it_cdr->fn_table->process_bridge_leave) {
-			continue;
-		}
-		CDR_DEBUG(mod_cfg, "%p - Processing Bridge Leave for %s\n",
-				it_cdr, channel->name);
-		if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
-			ast_string_field_set(it_cdr, bridge, "");
-			left_bridge = 1;
-		}
-	}
-	ao2_unlock(cdr);
-	if (!left_bridge) {
-		return;
-	}
-
-	if (strcmp(bridge->subclass, "parking")) {
-		/* Party B */
-		ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
-				cdr_object_party_b_left_bridge_cb,
-				&leave_data);
-	}
-}
-
-/*!
- * \internal
- * \brief Create a new CDR, append it to an existing CDR, and update its snapshots
- *
- * \note The new CDR will be automatically transitioned to the bridge state
- */
-static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
-		struct cdr_object_snapshot *party_b)
-{
-	RAII_VAR(struct module_config *,  mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_object *new_cdr;
-
-	new_cdr = cdr_object_create_and_append(cdr);
-	if (!new_cdr) {
-		return;
-	}
-	cdr_object_snapshot_copy(&new_cdr->party_b, party_b);
-	cdr_object_check_party_a_answer(new_cdr);
-	ast_string_field_set(new_cdr, bridge, cdr->bridge);
-	cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
-	CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
-		new_cdr, new_cdr->party_a.snapshot->name,
-		party_b->snapshot->name);
-}
-
-/*!
- * \brief Process a single \ref bridge_candidate
- *
- * When a CDR enters a bridge, it needs to make pairings with everyone else
- * that it is not currently paired with. This function determines, for the
- * CDR for the channel that entered the bridge and the CDR for every other
- * channel currently in the bridge, who is Party A and makes new CDRs.
- *
- * \param cdr The \ref cdr_obj being processed
- * \param cand_cdr The \ref cdr_object that is a candidate
- *
- */
-static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_object_snapshot *party_a;
-	struct cdr_object *cand_cdr;
-
-	SCOPED_AO2LOCK(lock, base_cand_cdr);
-
-	for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
-		/* Skip any records that are not in this bridge */
-		if (strcmp(cand_cdr->bridge, cdr->bridge)) {
-			continue;
-		}
-
-		/* If the candidate is us or someone we've taken on, pass on by */
-		if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)
-			|| (cdr->party_b.snapshot
-				&& !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) {
-			return 0;
-		}
-
-		party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
-		/* We're party A - make a new CDR, append it to us, and set the candidate as
-		 * Party B */
-		if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
-			bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
-			return 0;
-		}
-
-		/* We're Party B. Check if we can add ourselves immediately or if we need
-		 * a new CDR for them (they already have a Party B) */
-		if (cand_cdr->party_b.snapshot
-			&& strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
-			bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
-		} else {
-			CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
-				cand_cdr, cand_cdr->party_a.snapshot->name,
-				cdr->party_a.snapshot->name);
-			cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
-			/* It's possible that this joined at one point and was never chosen
-			 * as party A. Clear their end time, as it would be set in such a
-			 * case.
-			 */
-			memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
-		}
-		return 0;
-	}
-	return 0;
-}
-
-/*!
- * \brief Handle creating bridge pairings for the \ref cdr_object that just
- * entered a bridge
- * \param cdr The \ref cdr_object that just entered the bridge
- * \param bridge The \ref ast_bridge_snapshot representing the bridge it just entered
- */
-static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge)
-{
-	struct ao2_iterator it_channels;
-	char *channel_id;
-
-	it_channels = ao2_iterator_init(bridge->channels, 0);
-	while ((channel_id = ao2_iterator_next(&it_channels))) {
-		RAII_VAR(struct cdr_object *, cand_cdr,
-			ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
-			ao2_cleanup);
-
-		if (!cand_cdr) {
-			ao2_ref(channel_id, -1);
-			continue;
-		}
-
-		bridge_candidate_process(cdr, cand_cdr);
-
-		ao2_ref(channel_id, -1);
-	}
-	ao2_iterator_destroy(&it_channels);
-}
-
-/*! \brief Handle entering into a parking bridge
- * \param cdr The CDR to operate on
- * \param bridge The bridge the channel just entered
- * \param channel The channel snapshot
- */
-static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
-		struct ast_bridge_snapshot *bridge,
-		struct ast_channel_snapshot *channel)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-	int res = 1;
-	struct cdr_object *it_cdr;
-	struct cdr_object *new_cdr;
-
-	ao2_lock(cdr);
-
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table->process_parking_bridge_enter) {
-			res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
-		}
-		if (it_cdr->fn_table->process_party_a) {
-			CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr,
-					channel->name);
-			it_cdr->fn_table->process_party_a(it_cdr, channel);
-		}
-	}
-
-	if (res) {
-		/* No one handled it - we need a new one! */
-		new_cdr = cdr_object_create_and_append(cdr);
-		if (new_cdr) {
-			/* Let the single state transition us to Parked */
-			cdr_object_transition_state(new_cdr, &single_state_fn_table);
-			new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
-		}
-	}
-	ao2_unlock(cdr);
-}
-
-/*! \brief Handle a bridge enter message for a 'normal' bridge
- * \param cdr The CDR to operate on
- * \param bridge The bridge the channel just entered
- * \param channel The channel snapshot
- */
-static void handle_standard_bridge_enter_message(struct cdr_object *cdr,
-		struct ast_bridge_snapshot *bridge,
-		struct ast_channel_snapshot *channel)
-{
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-	enum process_bridge_enter_results result;
-	struct cdr_object *it_cdr;
-	struct cdr_object *new_cdr;
-	struct cdr_object *handled_cdr = NULL;
-
-	ao2_lock(cdr);
-
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table->process_party_a) {
-			CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr,
-					channel->name);
-			it_cdr->fn_table->process_party_a(it_cdr, channel);
-		}
-
-		/* Notify all states that they have entered a bridge */
-		if (it_cdr->fn_table->process_bridge_enter) {
-			CDR_DEBUG(mod_cfg, "%p - Processing bridge enter for %s\n", it_cdr,
-					channel->name);
-			result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
-			switch (result) {
-			case BRIDGE_ENTER_ONLY_PARTY:
-				/* Fall through */
-			case BRIDGE_ENTER_OBTAINED_PARTY_B:
-				if (!handled_cdr) {
-					handled_cdr = it_cdr;
-				}
-				break;
-			case BRIDGE_ENTER_NEED_CDR:
-				/* Pass */
-				break;
-			case BRIDGE_ENTER_NO_PARTY_B:
-				/* We didn't win on any - end this CDR. If someone else comes in later
-				 * that is Party B to this CDR, it can re-activate this CDR.
-				 */
-				if (!handled_cdr) {
-					handled_cdr = it_cdr;
-				}
-				cdr_object_finalize(cdr);
-				break;
-			}
-		}
-	}
-
-	/* Create the new matchings, but only for either:
-	 *  * The first CDR in the chain that handled it. This avoids issues with
-	 *    forked CDRs.
-	 *  * If no one handled it, the last CDR in the chain. This would occur if
-	 *    a CDR joined a bridge and it wasn't Party A for anyone. We still need
-	 *    to make pairings with everyone in the bridge.
-	 */
-	if (handled_cdr) {
-		handle_bridge_pairings(handled_cdr, bridge);
-	} else {
-		/* Nothing handled it - we need a new one! */
-		new_cdr = cdr_object_create_and_append(cdr);
-		if (new_cdr) {
-			/* This is guaranteed to succeed: the new CDR is created in the single state
-			 * and will be able to handle the bridge enter message
-			 */
-			handle_standard_bridge_enter_message(cdr, bridge, channel);
-		}
-	}
-	ao2_unlock(cdr);
-}
-
-/*!
- * \internal
- * \brief Handler for Stasis-Core bridge enter messages
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message The message - hopefully a bridge one!
- */
-static void handle_bridge_enter_message(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_bridge_blob *update = stasis_message_data(message);
-	struct ast_bridge_snapshot *bridge = update->bridge;
-	struct ast_channel_snapshot *channel = update->channel;
-	RAII_VAR(struct cdr_object *, cdr,
-			ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
-			ao2_cleanup);
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (filter_bridge_messages(bridge)) {
-		return;
-	}
-
-	if (filter_channel_snapshot(channel)) {
-		return;
-	}
-
-	CDR_DEBUG(mod_cfg, "Bridge Enter message for channel %s: %u.%08u\n",
-			channel->name,
-			(unsigned int)stasis_message_timestamp(message)->tv_sec,
-			(unsigned int)stasis_message_timestamp(message)->tv_usec);
-
-	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
-		ast_assert(0);
-		return;
-	}
-
-	if (!strcmp(bridge->subclass, "parking")) {
-		handle_parking_bridge_enter_message(cdr, bridge, channel);
-	} else {
-		handle_standard_bridge_enter_message(cdr, bridge, channel);
-	}
-}
-
-/*!
- * \brief Handler for when a channel is parked
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message The message about who got parked
- * */
-static void handle_parked_call_message(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_parked_call_payload *payload = stasis_message_data(message);
-	struct ast_channel_snapshot *channel = payload->parkee;
-	RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
-	RAII_VAR(struct module_config *, mod_cfg,
-			ao2_global_obj_ref(module_configs), ao2_cleanup);
-	int unhandled = 1;
-	struct cdr_object *it_cdr;
-
-	/* Anything other than getting parked will be handled by other updates */
-	if (payload->event_type != PARKED_CALL) {
-		return;
-	}
-
-	/* No one got parked? */
-	if (!channel) {
-		return;
-	}
-
-	if (filter_channel_snapshot(channel)) {
-		return;
-	}
-
-	CDR_DEBUG(mod_cfg, "Parked Call message for channel %s: %u.%08u\n",
-			channel->name,
-			(unsigned int)stasis_message_timestamp(message)->tv_sec,
-			(unsigned int)stasis_message_timestamp(message)->tv_usec);
-
-	cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY);
-	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
-		ast_assert(0);
-		return;
-	}
-
-	ao2_lock(cdr);
-
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table->process_parked_channel) {
-			unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
-		}
-	}
-
-	if (unhandled) {
-		/* Nothing handled the messgae - we need a new one! */
-		struct cdr_object *new_cdr = cdr_object_create_and_append(cdr);
-		if (new_cdr) {
-			/* As the new CDR is created in the single state, it is guaranteed
-			 * to have a function for the parked call message and will handle
-			 * the message */
-			new_cdr->fn_table->process_parked_channel(new_cdr, payload);
-		}
-	}
-
-	ao2_unlock(cdr);
-
-}
-
-/*!
- * \brief Handler for a synchronization message
- * \param data Passed on
- * \param sub The stasis subscription for this message callback
- * \param topic The topic this message was published for
- * \param message A blank ao2 object
- * */
-static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	return;
-}
-
-struct ast_cdr_config *ast_cdr_get_config(void)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	ao2_ref(mod_cfg->general, +1);
-	return mod_cfg->general;
-}
-
-void ast_cdr_set_config(struct ast_cdr_config *config)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	ao2_cleanup(mod_cfg->general);
-	mod_cfg->general = config;
-	ao2_ref(mod_cfg->general, +1);
-
-	cdr_toggle_runtime_options();
-}
-
-int ast_cdr_is_enabled(void)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	return ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED);
-}
-
-int ast_cdr_backend_suspend(const char *name)
-{
-	int success = -1;
-	struct cdr_beitem *i = NULL;
-
-	AST_RWLIST_WRLOCK(&be_list);
-	AST_RWLIST_TRAVERSE(&be_list, i, list) {
-		if (!strcasecmp(name, i->name)) {
-			ast_debug(3, "Suspending CDR backend %s\n", i->name);
-			i->suspended = 1;
-			success = 0;
-		}
+	if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
+		ast_copy_string(to->channel, from->channel, sizeof(to->channel));
+		from->channel[0] = 0; /* theft */
 	}
-	AST_RWLIST_UNLOCK(&be_list);
-
-	return success;
-}
-
-int ast_cdr_backend_unsuspend(const char *name)
-{
-	int success = -1;
-	struct cdr_beitem *i = NULL;
-
-	AST_RWLIST_WRLOCK(&be_list);
-	AST_RWLIST_TRAVERSE(&be_list, i, list) {
-		if (!strcasecmp(name, i->name)) {
-			ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
-			i->suspended = 0;
-			success = 0;
-		}
-	}
-	AST_RWLIST_UNLOCK(&be_list);
-
-	return success;
-}
-
-int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
-{
-	struct cdr_beitem *i = NULL;
-
-	if (!name)
-		return -1;
-
-	if (!be) {
-		ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
-		return -1;
-	}
-
-	AST_RWLIST_WRLOCK(&be_list);
-	AST_RWLIST_TRAVERSE(&be_list, i, list) {
-		if (!strcasecmp(name, i->name)) {
-			ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
-			AST_RWLIST_UNLOCK(&be_list);
-			return -1;
-		}
-	}
-
-	if (!(i = ast_calloc(1, sizeof(*i))))
-		return -1;
-
-	i->be = be;
-	ast_copy_string(i->name, name, sizeof(i->name));
-	ast_copy_string(i->desc, desc, sizeof(i->desc));
-
-	AST_RWLIST_INSERT_HEAD(&be_list, i, list);
-	AST_RWLIST_UNLOCK(&be_list);
-
-	return 0;
-}
-
-int ast_cdr_unregister(const char *name)
-{
-	struct cdr_beitem *match = NULL;
-	int active_count;
-
-	AST_RWLIST_WRLOCK(&be_list);
-	AST_RWLIST_TRAVERSE(&be_list, match, list) {
-		if (!strcasecmp(name, match->name)) {
-			break;
-		}
-	}
-
-	if (!match) {
-		AST_RWLIST_UNLOCK(&be_list);
-		return 0;
-	}
-
-	active_count = ao2_container_count(active_cdrs_by_channel);
-
-	if (!match->suspended && active_count != 0) {
-		AST_RWLIST_UNLOCK(&be_list);
-		ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
-			name, active_count);
-		return -1;
-	}
-
-	AST_RWLIST_REMOVE(&be_list, match, list);
-	AST_RWLIST_UNLOCK(&be_list);
-
-	ast_verb(2, "Unregistered '%s' CDR backend\n", name);
-	ast_free(match);
-
-	return 0;
-}
-
-struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
-{
-	struct ast_cdr *newcdr;
-
-	if (!cdr) {
-		return NULL;
+	if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
+		ast_copy_string(to->src, from->src, sizeof(to->src));
+		from->src[0] = 0; /* theft */
 	}
-	newcdr = ast_cdr_alloc();
-	if (!newcdr) {
-		return NULL;
+	if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
+		ast_copy_string(to->clid, from->clid, sizeof(to->clid));
+		from->clid[0] = 0; /* theft */
+	}
+	if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
+		ast_copy_string(to->dst, from->dst, sizeof(to->dst));
+		from->dst[0] = 0; /* theft */
+	}
+	if (!to->amaflags)
+		to->amaflags = AST_CDR_DOCUMENTATION;
+	if (!from->amaflags)
+		from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
+		to->amaflags = from->amaflags;
 	}
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
+		ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
+	}
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->peeraccount) && !ast_strlen_zero(from->peeraccount))) {
+		ast_copy_string(to->peeraccount, from->peeraccount, sizeof(to->peeraccount));
+	}
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
+		ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
+	}
+	/* flags, varsead, ? */
+	cdr_merge_vars(from, to);
 
-	*newcdr = *cdr;
-	AST_LIST_HEAD_INIT_NOLOCK(&newcdr->varshead);
-	copy_variables(&newcdr->varshead, &cdr->varshead);
-	newcdr->next = NULL;
+	if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
+		ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
+	if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
+		ast_set_flag(to, AST_CDR_FLAG_POSTED);
+	if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
+		ast_set_flag(to, AST_CDR_FLAG_LOCKED);
+	if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
+		ast_set_flag(to, AST_CDR_FLAG_CHILD);
+	if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
+		ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);
 
-	return newcdr;
+	/* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
+	while (from->next) {
+		/* just rip 'em off the 'from' and insert them on the 'to' */
+		zcdr = from->next;
+		from->next = zcdr->next;
+		zcdr->next = NULL;
+		/* zcdr is now ripped from the current list; */
+		ast_cdr_append(to, zcdr);
+	}
+	if (discard_from)
+		ast_cdr_discard(from);
 }
 
-static const char *cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
+void ast_cdr_start(struct ast_cdr *cdr)
 {
-	struct ast_var_t *variables;
-
-	if (ast_strlen_zero(name)) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
-		if (!strcasecmp(name, ast_var_name(variables))) {
-			return ast_var_value(variables);
+	for (; cdr; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			cdr->start = ast_tvnow();
 		}
 	}
-
-	return NULL;
 }
 
-static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
+void ast_cdr_answer(struct ast_cdr *cdr)
 {
-	if (fmt == NULL) {	/* raw mode */
-		snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
-	} else {
-		buf[0] = '\0';/* Ensure the buffer is initialized. */
-		if (when.tv_sec) {
-			struct ast_tm tm;
 
-			ast_localtime(&when, &tm, NULL);
-			ast_strftime(buf, bufsize, fmt, &tm);
-		}
+	for (; cdr; cdr = cdr->next) {
+		if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+			continue;
+		if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			continue;
+		check_post(cdr);
+		if (cdr->disposition < AST_CDR_ANSWERED)
+			cdr->disposition = AST_CDR_ANSWERED;
+		if (ast_tvzero(cdr->answer))
+			cdr->answer = ast_tvnow();
 	}
 }
 
-void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
+void ast_cdr_busy(struct ast_cdr *cdr)
 {
-	const char *fmt = "%Y-%m-%d %T";
-	const char *varbuf;
-
-	if (!cdr) {
-		return;
-	}
-
-	*ret = NULL;
 
-	if (!strcasecmp(name, "clid")) {
-		ast_copy_string(workspace, cdr->clid, workspacelen);
-	} else if (!strcasecmp(name, "src")) {
-		ast_copy_string(workspace, cdr->src, workspacelen);
-	} else if (!strcasecmp(name, "dst")) {
-		ast_copy_string(workspace, cdr->dst, workspacelen);
-	} else if (!strcasecmp(name, "dcontext")) {
-		ast_copy_string(workspace, cdr->dcontext, workspacelen);
-	} else if (!strcasecmp(name, "channel")) {
-		ast_copy_string(workspace, cdr->channel, workspacelen);
-	} else if (!strcasecmp(name, "dstchannel")) {
-		ast_copy_string(workspace, cdr->dstchannel, workspacelen);
-	} else if (!strcasecmp(name, "lastapp")) {
-		ast_copy_string(workspace, cdr->lastapp, workspacelen);
-	} else if (!strcasecmp(name, "lastdata")) {
-		ast_copy_string(workspace, cdr->lastdata, workspacelen);
-	} else if (!strcasecmp(name, "start")) {
-		cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
-	} else if (!strcasecmp(name, "answer")) {
-		cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
-	} else if (!strcasecmp(name, "end")) {
-		cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
-	} else if (!strcasecmp(name, "duration")) {
-		snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
-	} else if (!strcasecmp(name, "billsec")) {
-		snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
-	} else if (!strcasecmp(name, "disposition")) {
-		if (raw) {
-			snprintf(workspace, workspacelen, "%ld", cdr->disposition);
-		} else {
-			ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
-		}
-	} else if (!strcasecmp(name, "amaflags")) {
-		if (raw) {
-			snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
-		} else {
-			ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
+	for (; cdr; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			cdr->disposition = AST_CDR_BUSY;
 		}
-	} else if (!strcasecmp(name, "accountcode")) {
-		ast_copy_string(workspace, cdr->accountcode, workspacelen);
-	} else if (!strcasecmp(name, "peeraccount")) {
-		ast_copy_string(workspace, cdr->peeraccount, workspacelen);
-	} else if (!strcasecmp(name, "uniqueid")) {
-		ast_copy_string(workspace, cdr->uniqueid, workspacelen);
-	} else if (!strcasecmp(name, "linkedid")) {
-		ast_copy_string(workspace, cdr->linkedid, workspacelen);
-	} else if (!strcasecmp(name, "userfield")) {
-		ast_copy_string(workspace, cdr->userfield, workspacelen);
-	} else if (!strcasecmp(name, "sequence")) {
-		snprintf(workspace, workspacelen, "%d", cdr->sequence);
-	} else if ((varbuf = cdr_format_var_internal(cdr, name))) {
-		ast_copy_string(workspace, varbuf, workspacelen);
-	} else {
-		workspace[0] = '\0';
-	}
-
-	if (!ast_strlen_zero(workspace)) {
-		*ret = workspace;
 	}
 }
 
-/*
- * \internal
- * \brief Callback that finds all CDRs that reference a particular channel by name
- */
-static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
+void ast_cdr_failed(struct ast_cdr *cdr)
 {
-	struct cdr_object *cdr = obj;
-	const char *name = arg;
-
-	if (!strcasecmp(cdr->party_a.snapshot->name, name) ||
-			(cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, name))) {
-		return CMP_MATCH;
+	for (; cdr; cdr = cdr->next) {
+		check_post(cdr);
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			if (cdr->disposition < AST_CDR_FAILED)
+				cdr->disposition = AST_CDR_FAILED;
+		}
 	}
-	return 0;
 }
 
-/*
- * \internal
- * \brief Callback that finds a CDR by channel name
- */
-static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
+void ast_cdr_noanswer(struct ast_cdr *cdr)
 {
-	struct cdr_object *cdr = obj;
-	const char *name = arg;
-
-	if (!strcasecmp(cdr->party_a.snapshot->name, name)) {
-		return CMP_MATCH;
+	while (cdr) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			cdr->disposition = AST_CDR_NOANSWER;
+		}
+		cdr = cdr->next;
 	}
-	return 0;
 }
 
-/* Read Only CDR variables */
-static const char * const cdr_readonly_vars[] = {
-	"clid",
-	"src",
-	"dst",
-	"dcontext",
-	"channel",
-	"dstchannel",
-	"lastapp",
-	"lastdata",
-	"start",
-	"answer",
-	"end",
-	"duration",
-	"billsec",
-	"disposition",
-	"amaflags",
-	"accountcode",
-	"uniqueid",
-	"linkedid",
-	"userfield",
-	"sequence",
-	NULL
-};
-
-int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
+void ast_cdr_congestion(struct ast_cdr *cdr)
 {
-	struct cdr_object *cdr;
-	struct cdr_object *it_cdr;
-	struct ao2_iterator *it_cdrs;
-	char *arg = ast_strdupa(channel_name);
-	int x;
-
-	for (x = 0; cdr_readonly_vars[x]; x++) {
-		if (!strcasecmp(name, cdr_readonly_vars[x])) {
-			ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
-			return -1;
-		}
-	}
+	char *chan;
 
-	it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE, cdr_object_select_all_by_name_cb, arg);
-	if (!it_cdrs) {
-		ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
-		return -1;
+	/* if congestion log is disabled, pass the buck to ast_cdr_failed */
+	if (!congestion) {
+		ast_cdr_failed(cdr);
 	}
 
-	for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
-		ao2_lock(cdr);
-		for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-			struct varshead *headp = NULL;
+	while (cdr && congestion) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
 
-			if (it_cdr->fn_table == &finalized_state_fn_table) {
-				continue;
+			if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED)) {
+				ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
 			}
-			if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
-				headp = &it_cdr->party_a.variables;
-			} else if (it_cdr->party_b.snapshot
-				&& !strcasecmp(channel_name, it_cdr->party_b.snapshot->name)) {
-				headp = &it_cdr->party_b.variables;
-			}
-			if (headp) {
-				set_variable(headp, name, value);
+
+			if (cdr->disposition < AST_CDR_CONGESTION) {
+				cdr->disposition = AST_CDR_CONGESTION;
 			}
 		}
+		cdr = cdr->next;
 	}
-	ao2_iterator_destroy(it_cdrs);
-
-	return 0;
 }
 
-/*!
- * \brief Format a variable on a \ref cdr_object
- */
-static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char *value, size_t length)
+/* everywhere ast_cdr_disposition is called, it will call ast_cdr_failed()
+   if ast_cdr_disposition returns a non-zero value */
+
+int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
 {
-	struct ast_var_t *variable;
+	int res = 0;
 
-	AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
-		if (!strcasecmp(name, ast_var_name(variable))) {
-			ast_copy_string(value, ast_var_value(variable), length);
-			return;
+	for (; cdr; cdr = cdr->next) {
+		switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
+							return -1 to set disposition to FAILED */
+		case AST_CAUSE_BUSY:
+			ast_cdr_busy(cdr);
+			break;
+		case AST_CAUSE_NO_ANSWER:
+			ast_cdr_noanswer(cdr);
+			break;
+		case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+			ast_cdr_congestion(cdr);
+			break;
+		case AST_CAUSE_NORMAL:
+			break;
+		default:
+			res = -1;
 		}
 	}
-
-	*value = '\0';
+	return res;
 }
 
-/*!
- * \brief Format one of the standard properties on a \ref cdr_object
- */
-static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
+void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chann)
 {
-	struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
-	struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
-
-	if (!strcasecmp(name, "clid")) {
-		ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
-	} else if (!strcasecmp(name, "src")) {
-		ast_copy_string(value, party_a->caller_number, length);
-	} else if (!strcasecmp(name, "dst")) {
-		ast_copy_string(value, party_a->exten, length);
-	} else if (!strcasecmp(name, "dcontext")) {
-		ast_copy_string(value, party_a->context, length);
-	} else if (!strcasecmp(name, "channel")) {
-		ast_copy_string(value, party_a->name, length);
-	} else if (!strcasecmp(name, "dstchannel")) {
-		if (party_b) {
-			ast_copy_string(value, party_b->name, length);
-		} else {
-			ast_copy_string(value, "", length);
-		}
-	} else if (!strcasecmp(name, "lastapp")) {
-		ast_copy_string(value, party_a->appl, length);
-	} else if (!strcasecmp(name, "lastdata")) {
-		ast_copy_string(value, party_a->data, length);
-	} else if (!strcasecmp(name, "start")) {
-		cdr_get_tv(cdr_obj->start, NULL, value, length);
-	} else if (!strcasecmp(name, "answer")) {
-		cdr_get_tv(cdr_obj->answer, NULL, value, length);
-	} else if (!strcasecmp(name, "end")) {
-		cdr_get_tv(cdr_obj->end, NULL, value, length);
-	} else if (!strcasecmp(name, "duration")) {
-		snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
-	} else if (!strcasecmp(name, "billsec")) {
-		snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
-	} else if (!strcasecmp(name, "disposition")) {
-		snprintf(value, length, "%u", cdr_obj->disposition);
-	} else if (!strcasecmp(name, "amaflags")) {
-		snprintf(value, length, "%d", party_a->amaflags);
-	} else if (!strcasecmp(name, "accountcode")) {
-		ast_copy_string(value, party_a->accountcode, length);
-	} else if (!strcasecmp(name, "peeraccount")) {
-		if (party_b) {
-			ast_copy_string(value, party_b->accountcode, length);
-		} else {
-			ast_copy_string(value, "", length);
+	for (; cdr; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
 		}
-	} else if (!strcasecmp(name, "uniqueid")) {
-		ast_copy_string(value, party_a->uniqueid, length);
-	} else if (!strcasecmp(name, "linkedid")) {
-		ast_copy_string(value, cdr_obj->linkedid, length);
-	} else if (!strcasecmp(name, "userfield")) {
-		ast_copy_string(value, cdr_obj->party_a.userfield, length);
-	} else if (!strcasecmp(name, "sequence")) {
-		snprintf(value, length, "%u", cdr_obj->sequence);
-	} else {
-		return 1;
 	}
-
-	return 0;
 }
 
-/*! \internal
- * \brief Look up and retrieve a CDR object by channel name
- * \param name The name of the channel
- * \retval NULL on error
- * \retval The \ref cdr_object for the channel on success, with the reference
- *	count bumped by one.
- */
-static struct cdr_object *cdr_object_get_by_name(const char *name)
+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
 {
-	char *param;
 
-	if (ast_strlen_zero(name)) {
-		return NULL;
+	for (; cdr; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			check_post(cdr);
+			ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
+			ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
+		}
 	}
-
-	param = ast_strdupa(name);
-	return ao2_callback(active_cdrs_by_channel, 0, cdr_object_get_by_name_cb, param);
 }
 
-int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
+void ast_cdr_setanswer(struct ast_cdr *cdr, struct timeval t)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct cdr_object *cdr_obj;
-
-	if (!cdr) {
-		ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
-		return 1;
-	}
 
-	if (ast_strlen_zero(name)) {
-		return 1;
+	for (; cdr; cdr = cdr->next) {
+		if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+			continue;
+		if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			continue;
+		check_post(cdr);
+		cdr->answer = t;
 	}
+}
 
-	ao2_lock(cdr);
+void ast_cdr_setdisposition(struct ast_cdr *cdr, long int disposition)
+{
 
-	cdr_obj = cdr->last;
-	if (cdr_object_format_property(cdr_obj, name, value, length)) {
-		/* Property failed; attempt variable */
-		cdr_object_format_var_internal(cdr_obj, name, value, length);
+	for (; cdr; cdr = cdr->next) {
+		if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			continue;
+		check_post(cdr);
+		cdr->disposition = disposition;
 	}
-
-	ao2_unlock(cdr);
-
-	return 0;
 }
 
-int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep)
+/* set cid info for one record */
+static void set_one_cid(struct ast_cdr *cdr, struct ast_channel *c)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct cdr_object *it_cdr;
-	struct ast_var_t *variable;
-	const char *var;
-	RAII_VAR(char *, workspace, ast_malloc(256), ast_free);
-	int total = 0, x = 0, i;
-
-	if (!workspace) {
-		return 0;
-	}
+	const char *num;
 
 	if (!cdr) {
-		RAII_VAR(struct module_config *, mod_cfg,
-			 ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-		if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
-			ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
-		}
-
-		return 0;
+		return;
 	}
 
-	ast_str_reset(*buf);
-
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (++x > 1)
-			ast_str_append(buf, 0, "\n");
-
-		AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
-			if (!(var = ast_var_name(variable))) {
-				continue;
-			}
-
-			if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
-				ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
-				break;
-			}
-
-			total++;
-		}
+	/* Grab source from ANI or normal Caller*ID */
+	num = S_COR(ast_channel_caller(c)->ani.number.valid, ast_channel_caller(c)->ani.number.str,
+		S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL));
+	ast_callerid_merge(cdr->clid, sizeof(cdr->clid),
+		S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, NULL), num, "");
+	ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
+	ast_cdr_setvar(cdr, "dnid", S_OR(ast_channel_dialed(c)->number.str, ""), 0);
 
-		for (i = 0; cdr_readonly_vars[i]; i++) {
-			if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
-				/* Unhandled read-only CDR variable. */
-				ast_assert(0);
-				continue;
-			}
+	if (ast_channel_caller(c)->id.subaddress.valid) {
+		ast_cdr_setvar(cdr, "callingsubaddr", S_OR(ast_channel_caller(c)->id.subaddress.str, ""), 0);
+	}
+	if (ast_channel_dialed(c)->subaddress.valid) {
+		ast_cdr_setvar(cdr, "calledsubaddr", S_OR(ast_channel_dialed(c)->subaddress.str, ""), 0);
+	}
+}
 
-			if (!ast_strlen_zero(workspace)
-				&& ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
-				ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
-				break;
-			}
-			total++;
-		}
+int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
+{
+	for (; cdr; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			set_one_cid(cdr, c);
 	}
-	ao2_unlock(cdr);
-	return total;
+	return 0;
 }
 
-void ast_cdr_free(struct ast_cdr *cdr)
+static int cdr_seq_inc(struct ast_cdr *cdr)
 {
-	while (cdr) {
-		struct ast_cdr *next = cdr->next;
+	return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
+}
 
-		free_variables(&cdr->varshead);
-		ast_free(cdr);
-		cdr = next;
+int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
+{
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			ast_copy_string(cdr->channel, ast_channel_name(c), sizeof(cdr->channel));
+			set_one_cid(cdr, c);
+			cdr_seq_inc(cdr);
+
+			cdr->disposition = (ast_channel_state(c) == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
+			cdr->amaflags = ast_channel_amaflags(c) ? ast_channel_amaflags(c) :  ast_default_amaflags;
+			ast_copy_string(cdr->accountcode, ast_channel_accountcode(c), sizeof(cdr->accountcode));
+			ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(c), sizeof(cdr->peeraccount));
+			/* Destination information */
+			ast_copy_string(cdr->dst, S_OR(ast_channel_macroexten(c),ast_channel_exten(c)), sizeof(cdr->dst));
+			ast_copy_string(cdr->dcontext, S_OR(ast_channel_macrocontext(c),ast_channel_context(c)), sizeof(cdr->dcontext));
+			/* Unique call identifier */
+			ast_copy_string(cdr->uniqueid, ast_channel_uniqueid(c), sizeof(cdr->uniqueid));
+			/* Linked call identifier */
+			ast_copy_string(cdr->linkedid, ast_channel_linkedid(c), sizeof(cdr->linkedid));
+		}
 	}
+	return 0;
 }
 
-struct ast_cdr *ast_cdr_alloc(void)
-{
-	struct ast_cdr *x;
+/* Three routines were "fixed" via 10668, and later shown that
+   users were depending on this behavior. ast_cdr_end,
+   ast_cdr_setvar and ast_cdr_answer are the three routines.
+   While most of the other routines would not touch
+   LOCKED cdr's, these three routines were designed to
+   operate on locked CDR's as a matter of course.
+   I now appreciate how this plays with the ForkCDR app,
+   which forms these cdr chains in the first place.
+   cdr_end is pretty key: all cdrs created are closed
+   together. They only vary by start time. Arithmetically,
+   users can calculate the subintervals they wish to track. */
 
-	x = ast_calloc(1, sizeof(*x));
-	return x;
+void ast_cdr_end(struct ast_cdr *cdr)
+{
+	for ( ; cdr ; cdr = cdr->next) {
+		if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			continue;
+		check_post(cdr);
+		if (ast_tvzero(cdr->end))
+			cdr->end = ast_tvnow();
+		if (ast_tvzero(cdr->start)) {
+			ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
+			cdr->disposition = AST_CDR_FAILED;
+		} else
+			cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
+		if (ast_tvzero(cdr->answer)) {
+			if (cdr->disposition == AST_CDR_ANSWERED) {
+				ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
+				cdr->disposition = AST_CDR_FAILED;
+			}
+		} else {
+			cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
+			if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
+				cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
+		}
+	}
 }
 
-const char *ast_cdr_disp2str(int disposition)
+char *ast_cdr_disp2str(int disposition)
 {
 	switch (disposition) {
 	case AST_CDR_NULL:
@@ -3191,253 +1014,269 @@ const char *ast_cdr_disp2str(int disposition)
 	return "UNKNOWN";
 }
 
-struct party_b_userfield_update {
-	const char *channel_name;
-	const char *userfield;
-};
+/*! Converts AMA flag to printable string */
+char *ast_cdr_flags2str(int flag)
+{
+	switch (flag) {
+	case AST_CDR_OMIT:
+		return "OMIT";
+	case AST_CDR_BILLING:
+		return "BILLING";
+	case AST_CDR_DOCUMENTATION:
+		return "DOCUMENTATION";
+	}
+	return "Unknown";
+}
 
-/*! \brief Callback used to update the userfield on Party B on all CDRs */
-static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flags)
+int ast_cdr_setaccount(struct ast_channel *chan, const char *account)
 {
-	struct cdr_object *cdr = obj;
-	struct party_b_userfield_update *info = arg;
-	struct cdr_object *it_cdr;
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table == &finalized_state_fn_table) {
-			continue;
+	struct ast_cdr *cdr = ast_channel_cdr(chan);
+	const char *old_acct = "";
+
+	if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
+		old_acct = ast_strdupa(ast_channel_accountcode(chan));
+	}
+
+	ast_channel_accountcode_set(chan, account);
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			ast_copy_string(cdr->accountcode, ast_channel_accountcode(chan), sizeof(cdr->accountcode));
 		}
-		if (it_cdr->party_b.snapshot
-			&& !strcasecmp(it_cdr->party_b.snapshot->name, info->channel_name)) {
-			strcpy(it_cdr->party_b.userfield, info->userfield);
+	}
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a CDR's AccountCode is changed.</synopsis>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "NewAccountCode",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"AccountCode: %s\r\n"
+			"OldAccountCode: %s\r\n",
+			ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_accountcode(chan), old_acct);
+
+	return 0;
+}
+
+int ast_cdr_setpeeraccount(struct ast_channel *chan, const char *account)
+{
+	struct ast_cdr *cdr = ast_channel_cdr(chan);
+	const char *old_acct = "";
+
+	if (!ast_strlen_zero(ast_channel_peeraccount(chan))) {
+		old_acct = ast_strdupa(ast_channel_peeraccount(chan));
+	}
+
+	ast_channel_peeraccount_set(chan, account);
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(chan), sizeof(cdr->peeraccount));
 		}
 	}
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a CDR's PeerAccount is changed.</synopsis>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "NewPeerAccount",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"PeerAccount: %s\r\n"
+			"OldPeerAccount: %s\r\n",
+			ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_peeraccount(chan), old_acct);
+
 	return 0;
 }
 
-void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
+int ast_cdr_setamaflags(struct ast_channel *chan, const char *flag)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct party_b_userfield_update party_b_info = {
-			.channel_name = channel_name,
-			.userfield = userfield,
-	};
-	struct cdr_object *it_cdr;
-
-	/* Handle Party A */
-	if (cdr) {
-		ao2_lock(cdr);
-		for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-			if (it_cdr->fn_table == &finalized_state_fn_table) {
-				continue;
+	struct ast_cdr *cdr;
+	int newflag = ast_cdr_amaflags2int(flag);
+	if (newflag) {
+		for (cdr = ast_channel_cdr(chan); cdr; cdr = cdr->next) {
+			if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+				cdr->amaflags = newflag;
 			}
-			strcpy(it_cdr->party_a.userfield, userfield);
 		}
-		ao2_unlock(cdr);
 	}
 
-	/* Handle Party B */
-	ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
-			cdr_object_update_party_b_userfield_cb,
-			&party_b_info);
-
+	return 0;
 }
 
-static void post_cdr(struct ast_cdr *cdr)
+int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_beitem *i;
-
-	for (; cdr ; cdr = cdr->next) {
-		/* For people, who don't want to see unanswered single-channel events */
-		if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
-				cdr->disposition < AST_CDR_ANSWERED &&
-				(ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
-			ast_debug(1, "Skipping CDR  for %s since we weren't answered\n", cdr->channel);
-			continue;
-		}
+	struct ast_cdr *cdr = ast_channel_cdr(chan);
 
-		if (ast_test_flag(cdr, AST_CDR_FLAG_DISABLE)) {
-			continue;
-		}
-		AST_RWLIST_RDLOCK(&be_list);
-		AST_RWLIST_TRAVERSE(&be_list, i, list) {
-			if (!i->suspended) {
-				i->be(cdr);
-			}
-		}
-		AST_RWLIST_UNLOCK(&be_list);
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
 	}
+
+	return 0;
 }
 
-int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
+int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct cdr_object *it_cdr;
+	struct ast_cdr *cdr = ast_channel_cdr(chan);
 
-	if (!cdr) {
-		return -1;
+	for ( ; cdr ; cdr = cdr->next) {
+		int len = strlen(cdr->userfield);
+
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+			ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
 	}
 
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table == &finalized_state_fn_table) {
-			continue;
+	return 0;
+}
+
+int ast_cdr_update(struct ast_channel *c)
+{
+	struct ast_cdr *cdr = ast_channel_cdr(c);
+
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			set_one_cid(cdr, c);
+
+			/* Copy account code et-al */
+			ast_copy_string(cdr->accountcode, ast_channel_accountcode(c), sizeof(cdr->accountcode));
+			ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(c), sizeof(cdr->peeraccount));
+			ast_copy_string(cdr->linkedid, ast_channel_linkedid(c), sizeof(cdr->linkedid));
+
+			/* Destination information */ /* XXX privilege macro* ? */
+			ast_copy_string(cdr->dst, S_OR(ast_channel_macroexten(c), ast_channel_exten(c)), sizeof(cdr->dst));
+			ast_copy_string(cdr->dcontext, S_OR(ast_channel_macrocontext(c), ast_channel_context(c)), sizeof(cdr->dcontext));
 		}
-		/* Note: in general, set the flags on both the CDR record as well as the
-		 * Party A. Sometimes all we have is the Party A to look at.
-		 */
-		ast_set_flag(&it_cdr->flags, option);
-		ast_set_flag(&it_cdr->party_a, option);
 	}
-	ao2_unlock(cdr);
 
 	return 0;
 }
 
-int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
+int ast_cdr_amaflags2int(const char *flag)
+{
+	if (!strcasecmp(flag, "default"))
+		return 0;
+	if (!strcasecmp(flag, "omit"))
+		return AST_CDR_OMIT;
+	if (!strcasecmp(flag, "billing"))
+		return AST_CDR_BILLING;
+	if (!strcasecmp(flag, "documentation"))
+		return AST_CDR_DOCUMENTATION;
+	return -1;
+}
+
+static void post_cdr(struct ast_cdr *cdr)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct cdr_object *it_cdr;
+	struct ast_cdr_beitem *i;
 
-	if (!cdr) {
-		return -1;
-	}
+	for ( ; cdr ; cdr = cdr->next) {
+		if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
+			/* For people, who don't want to see unanswered single-channel events */
+			ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
+			continue;
+		}
 
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		if (it_cdr->fn_table == &finalized_state_fn_table) {
+		/* don't post CDRs that are for dialed channels unless those
+		 * channels were originated from asterisk (pbx_spool, manager,
+		 * cli) */
+		if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
+			ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
 			continue;
 		}
-		ast_clear_flag(&it_cdr->flags, option);
-	}
-	ao2_unlock(cdr);
 
-	return 0;
+		check_post(cdr);
+		ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
+		if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
+			continue;
+		AST_RWLIST_RDLOCK(&be_list);
+		AST_RWLIST_TRAVERSE(&be_list, i, list) {
+			i->be(cdr);
+		}
+		AST_RWLIST_UNLOCK(&be_list);
+	}
 }
 
-int ast_cdr_reset(const char *channel_name, int keep_variables)
+void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *_flags)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct ast_var_t *vardata;
-	struct cdr_object *it_cdr;
+	struct ast_cdr *duplicate;
+	struct ast_flags flags = { 0 };
 
-	if (!cdr) {
-		return -1;
-	}
+	if (_flags)
+		ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
 
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		/* clear variables */
-		if (!keep_variables) {
-			while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
-				ast_var_delete(vardata);
-			}
-			if (cdr->party_b.snapshot) {
-				while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
-					ast_var_delete(vardata);
+	for ( ; cdr ; cdr = cdr->next) {
+		/* Detach if post is requested */
+		if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
+			if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
+				ast_cdr_end(cdr);
+				if ((duplicate = ast_cdr_dup_unique_swap(cdr))) {
+					ast_cdr_detach(duplicate);
 				}
+				ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
 			}
-		}
 
-		/* Reset to initial state */
-		memset(&it_cdr->start, 0, sizeof(it_cdr->start));
-		memset(&it_cdr->end, 0, sizeof(it_cdr->end));
-		memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
-		it_cdr->start = ast_tvnow();
-		cdr_object_check_party_a_answer(it_cdr);
-	}
-	ao2_unlock(cdr);
+			/* enable CDR only */
+			if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
+				ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
+				continue;
+			}
 
-	return 0;
+			/* clear variables */
+			if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
+				ast_cdr_free_vars(cdr, 0);
+			}
+
+			/* Reset to initial state */
+			ast_clear_flag(cdr, AST_FLAGS_ALL);
+			memset(&cdr->start, 0, sizeof(cdr->start));
+			memset(&cdr->end, 0, sizeof(cdr->end));
+			memset(&cdr->answer, 0, sizeof(cdr->answer));
+			cdr->billsec = 0;
+			cdr->duration = 0;
+			ast_cdr_start(cdr);
+			cdr->disposition = AST_CDR_NOANSWER;
+		}
+	}
 }
 
-int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
+void ast_cdr_specialized_reset(struct ast_cdr *cdr, struct ast_flags *_flags)
 {
-	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
-	struct cdr_object *new_cdr;
-	struct cdr_object *it_cdr;
-	struct cdr_object *cdr_obj;
-
-	if (!cdr) {
-		return -1;
-	}
+	struct ast_flags flags = { 0 };
 
-	{
-		SCOPED_AO2LOCK(lock, cdr);
+	if (_flags)
+		ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
 
-		cdr_obj = cdr->last;
-		if (cdr_obj->fn_table == &finalized_state_fn_table) {
-			/* If the last CDR in the chain is finalized, don't allow a fork -
-			 * things are already dying at this point
-			 */
-			return -1;
-		}
+	/* Reset to initial state */
+	if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
+		ast_clear_flag(cdr, AST_FLAGS_ALL);
+		ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
+	} else {
+		ast_clear_flag(cdr, AST_FLAGS_ALL);
+	}
 
-		/* Copy over the basic CDR information. The Party A information is
-		 * copied over automatically as part of the append
-		 */
-		ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->name);
-		new_cdr = cdr_object_create_and_append(cdr);
-		if (!new_cdr) {
-			return -1;
-		}
-		new_cdr->fn_table = cdr_obj->fn_table;
-		ast_string_field_set(new_cdr, bridge, cdr->bridge);
-		ast_string_field_set(new_cdr, appl, cdr->appl);
-		ast_string_field_set(new_cdr, data, cdr->data);
-		ast_string_field_set(new_cdr, context, cdr->context);
-		ast_string_field_set(new_cdr, exten, cdr->exten);
-		new_cdr->flags = cdr->flags;
-		/* Explicitly clear the AST_CDR_LOCK_APP flag - we want
-		 * the application to be changed on the new CDR if the
-		 * dialplan demands it
-		 */
-		ast_clear_flag(&new_cdr->flags, AST_CDR_LOCK_APP);
-
-		/* If there's a Party B, copy it over as well */
-		if (cdr_obj->party_b.snapshot) {
-			new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
-			ao2_ref(new_cdr->party_b.snapshot, +1);
-			strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
-			new_cdr->party_b.flags = cdr_obj->party_b.flags;
-			if (ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
-				copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
-			}
-		}
-		new_cdr->start = cdr_obj->start;
-		new_cdr->answer = cdr_obj->answer;
+	memset(&cdr->start, 0, sizeof(cdr->start));
+	memset(&cdr->end, 0, sizeof(cdr->end));
+	memset(&cdr->answer, 0, sizeof(cdr->answer));
+	cdr->billsec = 0;
+	cdr->duration = 0;
+	ast_cdr_start(cdr);
+	cdr->disposition = AST_CDR_NULL;
+}
 
-		/* Modify the times based on the flags passed in */
-		if (ast_test_flag(options, AST_CDR_FLAG_SET_ANSWER)
-				&& new_cdr->party_a.snapshot->state == AST_STATE_UP) {
-			new_cdr->answer = ast_tvnow();
-		}
-		if (ast_test_flag(options, AST_CDR_FLAG_RESET)) {
-			new_cdr->answer = ast_tvnow();
-			new_cdr->start = ast_tvnow();
-		}
+struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr)
+{
+	struct ast_cdr *ret;
 
-		/* Create and append, by default, copies over the variables */
-		if (!ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
-			free_variables(&new_cdr->party_a.variables);
-		}
+	if (cdr) {
+		ret = cdr;
 
-		/* Finalize any current CDRs */
-		if (ast_test_flag(options, AST_CDR_FLAG_FINALIZE)) {
-			for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
-				if (it_cdr->fn_table == &finalized_state_fn_table) {
-					continue;
-				}
-				/* Force finalization on the CDR. This will bypass any checks for
-				 * end before 'h' extension.
-				 */
-				cdr_object_finalize(it_cdr);
-				cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
-			}
-		}
+		while (cdr->next)
+			cdr = cdr->next;
+		cdr->next = newcdr;
+	} else {
+		ret = newcdr;
 	}
 
-	return 0;
+	return ret;
 }
 
 /*! \note Don't call without cdr_batch_lock */
@@ -3462,8 +1301,8 @@ static int init_batch(void)
 
 static void *do_batch_backend_process(void *data)
 {
-	struct cdr_batch_item *processeditem;
-	struct cdr_batch_item *batchitem = data;
+	struct ast_cdr_batch_item *processeditem;
+	struct ast_cdr_batch_item *batchitem = data;
 
 	/* Push each CDR into storage mechanism(s) and free all the memory */
 	while (batchitem) {
@@ -3477,16 +1316,14 @@ static void *do_batch_backend_process(void *data)
 	return NULL;
 }
 
-static void cdr_submit_batch(int do_shutdown)
+void ast_cdr_submit_batch(int do_shutdown)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	struct cdr_batch_item *oldbatchitems = NULL;
+	struct ast_cdr_batch_item *oldbatchitems = NULL;
 	pthread_t batch_post_thread = AST_PTHREADT_NULL;
 
 	/* if there's no batch, or no CDRs in the batch, then there's nothing to do */
-	if (!batch || !batch->head) {
+	if (!batch || !batch->head)
 		return;
-	}
 
 	/* move the old CDRs aside, and prepare a new CDR batch */
 	ast_mutex_lock(&cdr_batch_lock);
@@ -3496,7 +1333,7 @@ static void cdr_submit_batch(int do_shutdown)
 
 	/* if configured, spawn a new thread to post these CDRs,
 	   also try to save as much as possible if we are shutting down safely */
-	if (ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) || do_shutdown) {
+	if (batchscheduleronly || do_shutdown) {
 		ast_debug(1, "CDR single-threaded batch processing begins now\n");
 		do_batch_backend_process(oldbatchitems);
 	} else {
@@ -3511,12 +1348,10 @@ static void cdr_submit_batch(int do_shutdown)
 
 static int submit_scheduled_batch(const void *data)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	cdr_submit_batch(0);
+	ast_cdr_submit_batch(0);
 	/* manually reschedule from this point in time */
-
 	ast_mutex_lock(&cdr_sched_lock);
-	cdr_sched = ast_sched_add(sched, mod_cfg->general->batch_settings.time * 1000, submit_scheduled_batch, NULL);
+	cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
 	ast_mutex_unlock(&cdr_sched_lock);
 	/* returning zero so the scheduler does not automatically reschedule */
 	return 0;
@@ -3539,26 +1374,25 @@ static void submit_unscheduled_batch(void)
 	ast_mutex_unlock(&cdr_pending_lock);
 }
 
-static void cdr_detach(struct ast_cdr *cdr)
+void ast_cdr_detach(struct ast_cdr *cdr)
 {
-	struct cdr_batch_item *newtail;
+	struct ast_cdr_batch_item *newtail;
 	int curr;
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
 	int submit_batch = 0;
 
-	if (!cdr) {
+	if (!cdr)
 		return;
-	}
 
 	/* maybe they disabled CDR stuff completely, so just drop it */
-	if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
+	if (!enabled) {
 		ast_debug(1, "Dropping CDR !\n");
+		ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
 		ast_cdr_free(cdr);
 		return;
 	}
 
 	/* post stuff immediately if we are not in batch mode, this is legacy behaviour */
-	if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
+	if (!batchmode) {
 		post_cdr(cdr);
 		ast_cdr_free(cdr);
 		return;
@@ -3590,7 +1424,7 @@ static void cdr_detach(struct ast_cdr *cdr)
 	curr = batch->size++;
 
 	/* if we have enough stuff to post, then do it */
-	if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
+	if (curr >= (batchsize - 1)) {
 		submit_batch = 1;
 	}
 	ast_mutex_unlock(&cdr_batch_lock);
@@ -3627,220 +1461,11 @@ static void *do_cdr(void *data)
 	return NULL;
 }
 
-static char *handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "cdr set debug [on|off]";
-		e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
-				"that this will dump debug information to the VERBOSE setting\n"
-				"and should only be used when debugging information from the\n"
-				"CDR engine is needed.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!strcasecmp(a->argv[3], "on")
-		&& !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
-		ast_set_flag(&mod_cfg->general->settings, CDR_DEBUG);
-		ast_cli(a->fd, "CDR debugging enabled\n");
-	} else if (!strcasecmp(a->argv[3], "off")
-		&& ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
-		ast_clear_flag(&mod_cfg->general->settings, CDR_DEBUG);
-		ast_cli(a->fd, "CDR debugging disabled\n");
-	}
-
-	return CLI_SUCCESS;
-}
-
-/*! \brief Complete user input for 'cdr show' */
-static char *cli_complete_show(struct ast_cli_args *a)
-{
-	char *result = NULL;
-	int wordlen = strlen(a->word);
-	int which = 0;
-	struct ao2_iterator it_cdrs;
-	struct cdr_object *cdr;
-
-	it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0);
-	while ((cdr = ao2_iterator_next(&it_cdrs))) {
-		if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen) &&
-			(++which > a->n)) {
-			result = ast_strdup(cdr->party_a.snapshot->name);
-			if (result) {
-				ao2_ref(cdr, -1);
-				break;
-			}
-		}
-		ao2_ref(cdr, -1);
-	}
-	ao2_iterator_destroy(&it_cdrs);
-	return result;
-}
-
-static void cli_show_channels(struct ast_cli_args *a)
-{
-	struct ao2_iterator it_cdrs;
-	struct cdr_object *cdr;
-	char start_time_buffer[64];
-	char answer_time_buffer[64];
-	char end_time_buffer[64];
-
-#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
-#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
-
-	ast_cli(a->fd, "\n");
-	ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
-	ast_cli(a->fd, "--------------------------------------------------\n");
-	ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
-
-	it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0);
-	for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
-		struct cdr_object *it_cdr;
-		struct timeval start_time = { 0, };
-		struct timeval answer_time = { 0, };
-		struct timeval end_time = { 0, };
-
-		SCOPED_AO2LOCK(lock, cdr);
-
-		/* Calculate the start, end, answer, billsec, and duration over the
-		 * life of all of the CDR entries
-		 */
-		for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-			if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
-				continue;
-			}
-			if (ast_tvzero(start_time)) {
-				start_time = it_cdr->start;
-			}
-			if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
-				answer_time = it_cdr->answer;
-			}
-		}
-
-		/* If there was no start time, then all CDRs were for a dialed channel; skip */
-		if (ast_tvzero(start_time)) {
-			continue;
-		}
-		it_cdr = cdr->last;
-
-		end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
-		cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
-		cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
-		cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
-		ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->name,
-				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
-				it_cdr->appl,
-				start_time_buffer,
-				answer_time_buffer,
-				end_time_buffer,
-				ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
-				(long)ast_tvdiff_ms(end_time, start_time) / 1000);
-	}
-	ao2_iterator_destroy(&it_cdrs);
-#undef FORMAT_STRING
-#undef TITLE_STRING
-}
-
-static void cli_show_channel(struct ast_cli_args *a)
-{
-	struct cdr_object *it_cdr;
-	char clid[64];
-	char start_time_buffer[64];
-	char answer_time_buffer[64];
-	char end_time_buffer[64];
-	const char *channel_name = a->argv[3];
-	RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
-
-#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
-#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
-
-	cdr = cdr_object_get_by_name(channel_name);
-	if (!cdr) {
-		ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
-		return;
-	}
-
-	ast_cli(a->fd, "\n");
-	ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
-	ast_cli(a->fd, "--------------------------------------------------\n");
-	ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
-
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		struct timeval end;
-		if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
-			continue;
-		}
-		ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller_name, it_cdr->party_a.snapshot->caller_number, "");
-		if (ast_tvzero(it_cdr->end)) {
-			end = ast_tvnow();
-		} else {
-			end = it_cdr->end;
-		}
-		cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
-		cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
-		cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
-		ast_cli(a->fd, FORMAT_STRING,
-				it_cdr->party_a.snapshot->accountcode,
-				clid,
-				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
-				it_cdr->appl,
-				it_cdr->data,
-				start_time_buffer,
-				answer_time_buffer,
-				end_time_buffer,
-				(long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
-				(long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
-	}
-	ao2_unlock(cdr);
-#undef FORMAT_STRING
-#undef TITLE_STRING
-}
-
-static char *handle_cli_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-			e->command = "cdr show active";
-			e->usage =
-				"Usage: cdr show active [channel]\n"
-				"	Displays a summary of all Call Detail Records when [channel]\n"
-				"	is omitted; displays all of the Call Detail Records\n"
-				"	currently in flight for a given [channel] when [channel] is\n"
-				"	specified.\n\n"
-				"	Note that this will not display Call Detail Records that\n"
-				"	have already been dispatched to a backend storage, nor for\n"
-				"	channels that are no longer active.\n";
-			return NULL;
-	case CLI_GENERATE:
-		return cli_complete_show(a);
-	}
-
-	if (a->argc > 4) {
-		return CLI_SHOWUSAGE;
-	} else if (a->argc < 4) {
-		cli_show_channels(a);
-	} else {
-		cli_show_channel(a);
-	}
-
-	return CLI_SUCCESS;
-}
-
 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct cdr_beitem *beitem = NULL;
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	int cnt = 0;
-	long nextbatchtime = 0;
+	struct ast_cdr_beitem *beitem=NULL;
+	int cnt=0;
+	long nextbatchtime=0;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -3853,30 +1478,29 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		return NULL;
 	}
 
-	if (a->argc > 3) {
+	if (a->argc > 3)
 		return CLI_SHOWUSAGE;
-	}
 
 	ast_cli(a->fd, "\n");
 	ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
 	ast_cli(a->fd, "----------------------------------\n");
-	ast_cli(a->fd, "  Logging:                    %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
-	ast_cli(a->fd, "  Mode:                       %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
-		ast_cli(a->fd, "  Log unanswered calls:       %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
-		ast_cli(a->fd, "  Log congestion:             %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
-		if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
+	ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
+	ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
+	if (enabled) {
+		ast_cli(a->fd, "  Log unanswered calls:       %s\n", unanswered ? "Yes" : "No");
+		ast_cli(a->fd, "  Log congestion:             %s\n\n", congestion ? "Yes" : "No");
+		if (batchmode) {
 			ast_cli(a->fd, "* Batch Mode Settings\n");
 			ast_cli(a->fd, "  -------------------\n");
 			if (batch)
 				cnt = batch->size;
 			if (cdr_sched > -1)
 				nextbatchtime = ast_sched_when(sched, cdr_sched);
-			ast_cli(a->fd, "  Safe shutdown:              %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
-			ast_cli(a->fd, "  Threading model:            %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) ? "Scheduler only" : "Scheduler plus separate threads");
+			ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
+			ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
 			ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
-			ast_cli(a->fd, "  Maximum batch size:         %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
-			ast_cli(a->fd, "  Maximum batch time:         %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
+			ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
+			ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
 			ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
 		}
 		ast_cli(a->fd, "* Registered Backends\n");
@@ -3886,7 +1510,7 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
 			ast_cli(a->fd, "    (none)\n");
 		} else {
 			AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
-				ast_cli(a->fd, "    %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
+				ast_cli(a->fd, "    %s\n", beitem->name);
 			}
 		}
 		AST_RWLIST_UNLOCK(&be_list);
@@ -3898,32 +1522,18 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
 
 static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "cdr submit";
 		e->usage =
 			"Usage: cdr submit\n"
-			"Posts all pending batched CDR data to the configured CDR\n"
-			"backend engine modules.\n";
+			"       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
-	if (a->argc > 2) {
+	if (a->argc > 2)
 		return CLI_SHOWUSAGE;
-	}
-
-	if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
-		ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
-		return CLI_SUCCESS;
-	}
-
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
-		ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
-		return CLI_SUCCESS;
-	}
 
 	submit_unscheduled_batch();
 	ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
@@ -3931,338 +1541,221 @@ static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	return CLI_SUCCESS;
 }
 
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data"),
-	AST_CLI_DEFINE(handle_cli_status, "Display the CDR status"),
-	AST_CLI_DEFINE(handle_cli_show, "Display active CDRs for channels"),
-	AST_CLI_DEFINE(handle_cli_debug, "Enable debugging in the CDR engine"),
-};
+static struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data");
+static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status");
 
-/*!
- * \brief This dispatches *all* \ref cdr_objects. It should only be used during
- * shutdown, so that we get billing records for everything that we can.
- */
-static int cdr_object_dispatch_all_cb(void *obj, void *arg, int flags)
+static void do_reload(int reload)
 {
-	struct cdr_object *cdr = obj;
-	struct cdr_object *it_cdr;
-
-	ao2_lock(cdr);
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
-	}
-	cdr_object_dispatch(cdr);
-	ao2_unlock(cdr);
-
-	return 0;
-}
+	struct ast_config *config;
+	struct ast_variable *v;
+	int cfg_size;
+	int cfg_time;
+	int was_enabled;
+	int was_batchmode;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
-static void finalize_batch_mode(void)
-{
-	if (cdr_thread == AST_PTHREADT_NULL) {
+	if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
 		return;
 	}
-	/* wake up the thread so it will exit */
-	pthread_cancel(cdr_thread);
-	pthread_kill(cdr_thread, SIGURG);
-	pthread_join(cdr_thread, NULL);
-	cdr_thread = AST_PTHREADT_NULL;
-	ast_cond_destroy(&cdr_pending_cond);
-	ast_cdr_engine_term();
-}
-
-struct stasis_message_router *ast_cdr_message_router(void)
-{
-	if (!stasis_router) {
-		return NULL;
-	}
 
-	ao2_bump(stasis_router);
-	return stasis_router;
-}
-
-/*!
- * \brief Destroy the active Stasis subscriptions
- */
-static void destroy_subscriptions(void)
-{
-	channel_subscription = stasis_forward_cancel(channel_subscription);
-	bridge_subscription = stasis_forward_cancel(bridge_subscription);
-	parking_subscription = stasis_forward_cancel(parking_subscription);
-}
+	ast_mutex_lock(&cdr_batch_lock);
 
-/*!
- * \brief Create the Stasis subcriptions for CDRs
- */
-static int create_subscriptions(void)
-{
-	if (!cdr_topic) {
-		return -1;
-	}
+	was_enabled = enabled;
+	was_batchmode = batchmode;
 
-	if (channel_subscription || bridge_subscription || parking_subscription) {
-		return 0;
-	}
+	batchsize = BATCH_SIZE_DEFAULT;
+	batchtime = BATCH_TIME_DEFAULT;
+	batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
+	batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
+	enabled = ENABLED_DEFAULT;
+	batchmode = BATCHMODE_DEFAULT;
+	unanswered = UNANSWERED_DEFAULT;
+	congestion = CONGESTION_DEFAULT;
 
-	channel_subscription = stasis_forward_all(ast_channel_topic_all_cached(), cdr_topic);
-	if (!channel_subscription) {
-		return -1;
-	}
-	bridge_subscription = stasis_forward_all(ast_bridge_topic_all_cached(), cdr_topic);
-	if (!bridge_subscription) {
-		return -1;
-	}
-	parking_subscription = stasis_forward_all(ast_parking_topic(), cdr_topic);
-	if (!parking_subscription) {
-		return -1;
+	if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
+		ast_mutex_unlock(&cdr_batch_lock);
+		return;
 	}
 
-	return 0;
-}
-
-static int process_config(int reload)
-{
-	RAII_VAR(struct module_config *, mod_cfg, module_config_alloc(), ao2_cleanup);
+	/* don't run the next scheduled CDR posting while reloading */
+	ast_mutex_lock(&cdr_sched_lock);
+	AST_SCHED_DEL(sched, cdr_sched);
+	ast_mutex_unlock(&cdr_sched_lock);
 
-	if (!reload) {
-		if (aco_info_init(&cfg_info)) {
-			return 1;
+	for (v = ast_variable_browse(config, "general"); v; v = v->next) {
+		if (!strcasecmp(v->name, "enable")) {
+			enabled = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "unanswered")) {
+			unanswered = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "congestion")) {
+			congestion = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "batch")) {
+			batchmode = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "scheduleronly")) {
+			batchscheduleronly = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "safeshutdown")) {
+			batchsafeshutdown = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "size")) {
+			if (sscanf(v->value, "%30d", &cfg_size) < 1) {
+				ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
+			} else if (cfg_size < 0) {
+				ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
+			} else {
+				batchsize = cfg_size;
+			}
+		} else if (!strcasecmp(v->name, "time")) {
+			if (sscanf(v->value, "%30d", &cfg_time) < 1) {
+				ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
+			} else if (cfg_time < 0) {
+				ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
+			} else {
+				batchtime = cfg_time;
+			}
+		} else if (!strcasecmp(v->name, "endbeforehexten")) {
+			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
+		} else if (!strcasecmp(v->name, "initiatedseconds")) {
+			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INITIATED_SECONDS);
 		}
-
-		aco_option_register(&cfg_info, "enable", ACO_EXACT, general_options, DEFAULT_ENABLED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_ENABLED);
-		aco_option_register(&cfg_info, "debug", ACO_EXACT, general_options, 0, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_DEBUG);
-		aco_option_register(&cfg_info, "unanswered", ACO_EXACT, general_options, DEFAULT_UNANSWERED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_UNANSWERED);
-		aco_option_register(&cfg_info, "congestion", ACO_EXACT, general_options, 0, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_CONGESTION);
-		aco_option_register(&cfg_info, "batch", ACO_EXACT, general_options, DEFAULT_BATCHMODE, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_BATCHMODE);
-		aco_option_register(&cfg_info, "endbeforehexten", ACO_EXACT, general_options, DEFAULT_END_BEFORE_H_EXTEN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_END_BEFORE_H_EXTEN);
-		aco_option_register(&cfg_info, "initiatedseconds", ACO_EXACT, general_options, DEFAULT_INITIATED_SECONDS, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_INITIATED_SECONDS);
-		aco_option_register(&cfg_info, "scheduleronly", ACO_EXACT, general_options, DEFAULT_BATCH_SCHEDULER_ONLY, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SCHEDULER_ONLY);
-		aco_option_register(&cfg_info, "safeshutdown", ACO_EXACT, general_options, DEFAULT_BATCH_SAFE_SHUTDOWN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SAFE_SHUTDOWN);
-		aco_option_register(&cfg_info, "size", ACO_EXACT, general_options, DEFAULT_BATCH_SIZE, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.size), 0, MAX_BATCH_SIZE);
-		aco_option_register(&cfg_info, "time", ACO_EXACT, general_options, DEFAULT_BATCH_TIME, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.time), 0, MAX_BATCH_TIME);
 	}
 
-	if (aco_process_config(&cfg_info, reload)) {
-		if (!mod_cfg) {
-			return 1;
-		}
-		/* If we couldn't process the configuration and this wasn't a reload,
-		 * create a default config
-		 */
-		if (!reload && !(aco_set_defaults(&general_option, "general", mod_cfg->general))) {
-			ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
-			ao2_global_obj_replace_unref(module_configs, mod_cfg);
-			return 0;
-		}
-		return 1;
+	if (enabled && !batchmode) {
+		ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
+	} else if (enabled && batchmode) {
+		ast_mutex_lock(&cdr_sched_lock);
+		cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
+		ast_mutex_unlock(&cdr_sched_lock);
+		ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
+	} else {
+		ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
 	}
 
-	return 0;
-}
-
-static void cdr_engine_cleanup(void)
-{
-	destroy_subscriptions();
-}
-
-static void cdr_engine_shutdown(void)
-{
-	stasis_message_router_unsubscribe_and_join(stasis_router);
-	stasis_router = NULL;
-
-	ao2_cleanup(cdr_topic);
-	cdr_topic = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
-
-	ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_dispatch_all_cb,
-		NULL);
-	finalize_batch_mode();
-	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_sched_context_destroy(sched);
-	sched = NULL;
-	ast_free(batch);
-	batch = NULL;
-
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(module_configs);
-
-	ao2_container_unregister("cdrs_by_channel");
-	ao2_ref(active_cdrs_by_channel, -1);
-	active_cdrs_by_channel = NULL;
-}
-
-static void cdr_enable_batch_mode(struct ast_cdr_config *config)
-{
-	SCOPED_LOCK(batch, &cdr_batch_lock, ast_mutex_lock, ast_mutex_unlock);
-
-	/* Only create the thread level portions once */
-	if (cdr_thread == AST_PTHREADT_NULL) {
+	/* if this reload enabled the CDR batch mode, create the background thread
+	   if it does not exist */
+	if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
 		ast_cond_init(&cdr_pending_cond, NULL);
 		if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
 			ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
-			return;
+			ast_mutex_lock(&cdr_sched_lock);
+			AST_SCHED_DEL(sched, cdr_sched);
+			ast_mutex_unlock(&cdr_sched_lock);
+		} else {
+			ast_cli_register(&cli_submit);
+			ast_register_atexit(ast_cdr_engine_term);
+		}
+	/* if this reload disabled the CDR and/or batch mode and there is a background thread,
+	   kill it */
+	} else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
+		/* wake up the thread so it will exit */
+		pthread_cancel(cdr_thread);
+		pthread_kill(cdr_thread, SIGURG);
+		pthread_join(cdr_thread, NULL);
+		cdr_thread = AST_PTHREADT_NULL;
+		ast_cond_destroy(&cdr_pending_cond);
+		ast_cli_unregister(&cli_submit);
+		ast_unregister_atexit(ast_cdr_engine_term);
+		/* if leaving batch mode, then post the CDRs in the batch,
+		   and don't reschedule, since we are stopping CDR logging */
+		if (!batchmode && was_batchmode) {
+			ast_cdr_engine_term();
 		}
 	}
 
-	/* Kill the currently scheduled item */
-	AST_SCHED_DEL(sched, cdr_sched);
-	cdr_sched = ast_sched_add(sched, config->batch_settings.time * 1000, submit_scheduled_batch, NULL);
-	ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
-			config->batch_settings.size, config->batch_settings.time);
-}
-
-/*!
- * \internal
- * \brief Print channel object key (name).
- * \since 12.0.0
- *
- * \param v_obj A pointer to the object we want the key printed.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-static void cdr_container_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
-{
-	struct cdr_object *cdr = v_obj;
-	struct cdr_object *it_cdr;
-	if (!cdr) {
-		return;
-	}
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		prnt(where, "Party A: %s; Party B: %s; Bridge %s\n", it_cdr->party_a.snapshot->name, it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<unknown>",
-				it_cdr->bridge);
-	}
+	ast_mutex_unlock(&cdr_batch_lock);
+	ast_config_destroy(config);
+	manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
 }
 
-/*!
- * \brief Checks if CDRs are enabled and enables/disables the necessary options
- */
-static int cdr_toggle_runtime_options(void)
+static void cdr_engine_shutdown(void)
 {
-	RAII_VAR(struct module_config *, mod_cfg,
-		ao2_global_obj_ref(module_configs), ao2_cleanup);
-
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
-		if (create_subscriptions()) {
-			destroy_subscriptions();
-			ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
-			return -1;
-		}
-		if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
-			cdr_enable_batch_mode(mod_cfg->general);
-		} else {
-			ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
-		}
-	} else {
-		destroy_subscriptions();
-		ast_log(LOG_NOTICE, "CDR logging disabled.\n");
+	if (cdr_thread != AST_PTHREADT_NULL) {
+		/* wake up the thread so it will exit */
+		pthread_cancel(cdr_thread);
+		pthread_kill(cdr_thread, SIGURG);
+		pthread_join(cdr_thread, NULL);
+		cdr_thread = AST_PTHREADT_NULL;
+		ast_cond_destroy(&cdr_pending_cond);
 	}
+	ast_cli_unregister(&cli_submit);
 
-	return 0;
+	ast_cli_unregister(&cli_status);
+	ast_sched_context_destroy(sched);
+	sched = NULL;
+	ast_free(batch);
+	batch = NULL;
 }
 
 int ast_cdr_engine_init(void)
 {
-	if (process_config(0)) {
-		return -1;
-	}
-
-	cdr_topic = stasis_topic_create("cdr_engine");
-	if (!cdr_topic) {
-		return -1;
-	}
-
-	stasis_router = stasis_message_router_create(cdr_topic);
-	if (!stasis_router) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
-		return -1;
-	}
-
-	stasis_message_router_add_cache_update(stasis_router, ast_channel_snapshot_type(), handle_channel_cache_message, NULL);
-	stasis_message_router_add(stasis_router, ast_channel_dial_type(), handle_dial_message, NULL);
-	stasis_message_router_add(stasis_router, ast_channel_entered_bridge_type(), handle_bridge_enter_message, NULL);
-	stasis_message_router_add(stasis_router, ast_channel_left_bridge_type(), handle_bridge_leave_message, NULL);
-	stasis_message_router_add(stasis_router, ast_parked_call_type(), handle_parked_call_message, NULL);
-	stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL);
-
-	active_cdrs_by_channel = ao2_container_alloc(NUM_CDR_BUCKETS,
-		cdr_object_channel_hash_fn, cdr_object_channel_cmp_fn);
-	if (!active_cdrs_by_channel) {
-		return -1;
-	}
-	ao2_container_register("cdrs_by_channel", active_cdrs_by_channel, cdr_container_print_fn);
-
 	sched = ast_sched_context_create();
 	if (!sched) {
 		ast_log(LOG_ERROR, "Unable to create schedule context.\n");
 		return -1;
 	}
 
-	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_register_cleanup(cdr_engine_cleanup);
+	ast_cli_register(&cli_status);
+	do_reload(0);
 	ast_register_atexit(cdr_engine_shutdown);
 
-	return cdr_toggle_runtime_options();
+	return 0;
 }
 
+/* \note This actually gets called a couple of times at shutdown.  Once, before we start
+   hanging up channels, and then again, after the channel hangup timeout expires */
 void ast_cdr_engine_term(void)
 {
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	RAII_VAR(void *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	/* Since this is called explicitly during process shutdown, we might not have ever
-	 * been initialized. If so, the config object will be NULL.
-	 */
-	if (!mod_cfg) {
-		return;
-	}
-
-	if (cdr_sync_message_type()) {
-		/* Make sure we have the needed items */
-		payload = ao2_alloc(sizeof(*payload), NULL);
-		if (!stasis_router || !payload) {
-			return;
-		}
-
-		ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
-
-		message = stasis_message_create(cdr_sync_message_type(), payload);
-		if (message) {
-			stasis_message_router_publish_sync(stasis_router, message);
-		}
-	}
-
-	if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
-		cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
-	}
+	ast_cdr_submit_batch(batchsafeshutdown);
 }
 
 int ast_cdr_engine_reload(void)
 {
-	RAII_VAR(struct module_config *, old_mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-	RAII_VAR(struct module_config *, mod_cfg, NULL, ao2_cleanup);
+	do_reload(1);
+	return 0;
+}
+
+int ast_cdr_data_add_structure(struct ast_data *tree, struct ast_cdr *cdr, int recur)
+{
+	struct ast_cdr *tmpcdr;
+	struct ast_data *level;
+	struct ast_var_t *variables;
+	const char *var, *val;
+	int x = 1, i;
+	char workspace[256];
+	char *tmp;
 
-	if (process_config(1)) {
+	if (!cdr) {
 		return -1;
 	}
 
-	mod_cfg = ao2_global_obj_ref(module_configs);
+	for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
+		level = ast_data_add_node(tree, "level");
+		if (!level) {
+			continue;
+		}
+
+		ast_data_add_int(level, "level_number", x);
+
+		AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
+			if (variables && (var = ast_var_name(variables)) &&
+					(val = ast_var_value(variables)) && !ast_strlen_zero(var)
+					&& !ast_strlen_zero(val)) {
+				ast_data_add_str(level, var, val);
+			} else {
+				break;
+			}
+		}
 
-	if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ||
-			!(ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE))) {
-		/* If batch mode used to be enabled, finalize the batch */
-		if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
-			finalize_batch_mode();
+		for (i = 0; cdr_readonly_vars[i]; i++) {
+			workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
+			ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
+			if (!tmp) {
+				continue;
+			}
+			ast_data_add_str(level, cdr_readonly_vars[i], tmp);
 		}
+
+		x++;
 	}
 
-	return cdr_toggle_runtime_options();
+	return 0;
 }
 
-
diff --git a/main/cel.c b/main/cel.c
index 96547bb..59a5b7f 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -21,15 +21,10 @@
  *
  * \author Steve Murphy <murf at digium.com>
  * \author Russell Bryant <russell at digium.com>
- */
-
-/*! \li \ref cel.c uses the configuration file \ref cel.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cel.conf cel.conf
- * \verbinclude cel.conf.sample
+ *
+ * \todo Do thorough testing of all transfer methods to ensure that BLINDTRANSFER,
+ *       ATTENDEDTRANSFER, BRIDGE_START, and BRIDGE_END events are all reported
+ *       as expected.
  */
 
 /*** MODULEINFO
@@ -38,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427870 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -49,100 +44,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427870 $")
 #include "asterisk/linkedlists.h"
 #include "asterisk/utils.h"
 #include "asterisk/config.h"
-#include "asterisk/config_options.h"
 #include "asterisk/cli.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/bridge.h"
-#include "asterisk/parking.h"
-#include "asterisk/pickup.h"
-#include "asterisk/core_local.h"
-
-/*** DOCUMENTATION
-	<configInfo name="cel" language="en_US">
-		<configFile name="cel.conf">
-			<configObject name="general">
-				<synopsis>Options that apply globally to Channel Event Logging (CEL)</synopsis>
-				<configOption name="enable">
-					<synopsis>Determines whether CEL is enabled</synopsis>
-				</configOption>
-				<configOption name="dateformat">
-					<synopsis>The format to be used for dates when logging</synopsis>
-				</configOption>
-				<configOption name="apps">
-					<synopsis>List of apps for CEL to track</synopsis>
-					<description><para>A case-insensitive, comma-separated list of applications
-					to track when one or both of APP_START and APP_END events are flagged for
-					tracking</para></description>
-				</configOption>
-				<configOption name="events">
-					<synopsis>List of events for CEL to track</synopsis>
-					<description><para>A case-sensitive, comma-separated list of event names
-					to track. These event names do not include the leading <literal>AST_CEL</literal>.
-					</para>
-					<enumlist>
-						<enum name="ALL">
-							<para>Special value which tracks all events.</para>
-						</enum>
-						<enum name="CHAN_START"/>
-						<enum name="CHAN_END"/>
-						<enum name="ANSWER"/>
-						<enum name="HANGUP"/>
-						<enum name="APP_START"/>
-						<enum name="APP_END"/>
-						<enum name="PARK_START"/>
-						<enum name="PARK_END"/>
-						<enum name="USER_DEFINED"/>
-						<enum name="BRIDGE_ENTER"/>
-						<enum name="BRIDGE_EXIT"/>
-						<enum name="BLINDTRANSFER"/>
-						<enum name="ATTENDEDTRANSFER"/>
-						<enum name="PICKUP"/>
-						<enum name="FORWARD"/>
-						<enum name="LINKEDID_END"/>
-						<enum name="LOCAL_OPTIMIZE"/>
-					</enumlist>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-/*! Message router for state that CEL needs to know about */
-static struct stasis_message_router *cel_state_router;
 
-/*! Topic for CEL-specific messages */
-static struct stasis_topic *cel_topic;
+/*! Config file to load for the CEL feature. */
+static const char cel_conf_file[] = "cel.conf";
 
-/*! Aggregation topic for all topics CEL needs to know about */
-static struct stasis_topic *cel_aggregation_topic;
+/*! Is the CEL subsystem enabled ? */
+static unsigned char cel_enabled;
 
-/*! Subscription for forwarding the channel caching topic */
-static struct stasis_forward *cel_channel_forwarder;
+/*! \brief CEL is off by default */
+#define CEL_ENABLED_DEFAULT		0
 
-/*! Subscription for forwarding the channel caching topic */
-static struct stasis_forward *cel_bridge_forwarder;
-
-/*! Subscription for forwarding the parking topic */
-static struct stasis_forward *cel_parking_forwarder;
-
-/*! Subscription for forwarding the CEL-specific topic */
-static struct stasis_forward *cel_cel_forwarder;
-
-struct stasis_message_type *cel_generic_type(void);
-STASIS_MESSAGE_TYPE_DEFN(cel_generic_type);
-
-/*! Container for CEL backend information */
-static AO2_GLOBAL_OBJ_STATIC(cel_backends);
-
-/*! The number of buckets into which backend names will be hashed */
-#define BACKEND_BUCKETS 13
-
-/*! Container for dial end multichannel blobs for holding on to dial statuses */
-static AO2_GLOBAL_OBJ_STATIC(cel_dialstatus_store);
+/*!
+ * \brief which events we want to track
+ *
+ * \note bit field, up to 64 events
+ */
+static int64_t eventset;
 
 /*!
  * \brief Maximum possible CEL event IDs
@@ -151,14 +70,34 @@ static AO2_GLOBAL_OBJ_STATIC(cel_dialstatus_store);
 #define CEL_MAX_EVENT_IDS 64
 
 /*!
+ * \brief Track no events by default.
+ */
+#define CEL_DEFAULT_EVENTS	0
+
+/*!
  * \brief Number of buckets for the appset container
  */
 #define NUM_APP_BUCKETS		97
 
 /*!
- * \brief Number of buckets for the dialstatus container
+ * \brief Lock protecting CEL.
+ *
+ * \note It protects during reloads, shutdown, and accesses to
+ * the appset and linkedids containers.
+ */
+AST_MUTEX_DEFINE_STATIC(reload_lock);
+
+/*!
+ * \brief Container of Asterisk application names
+ *
+ * The apps in this container are the applications that were specified
+ * in the configuration as applications that CEL events should be generated
+ * for when they start and end on a channel.
+ *
+ * \note Accesses to the appset container must be done while
+ * holding the reload_lock.
  */
-#define NUM_DIALSTATUS_BUCKETS	251
+static struct ao2_container *appset;
 
 struct cel_linkedid {
 	/*! Number of channels with this linkedid. */
@@ -167,300 +106,78 @@ struct cel_linkedid {
 	char id[0];
 };
 
-/*! Container of channel references to a linkedid for CEL purposes. */
-static AO2_GLOBAL_OBJ_STATIC(cel_linkedids);
-
-/*! \brief Destructor for cel_config */
-static void cel_general_config_dtor(void *obj)
-{
-	struct ast_cel_general_config *cfg = obj;
-	ast_string_field_free_memory(cfg);
-	ao2_cleanup(cfg->apps);
-	cfg->apps = NULL;
-}
-
-void *ast_cel_general_config_alloc(void)
-{
-	RAII_VAR(struct ast_cel_general_config *, cfg, NULL, ao2_cleanup);
-
-	if (!(cfg = ao2_alloc(sizeof(*cfg), cel_general_config_dtor))) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(cfg, 64)) {
-		return NULL;
-	}
-
-	if (!(cfg->apps = ast_str_container_alloc(NUM_APP_BUCKETS))) {
-		return NULL;
-	}
-
-	ao2_ref(cfg, +1);
-	return cfg;
-}
-
-/*! \brief A container that holds all config-related information */
-struct cel_config {
-	struct ast_cel_general_config *general;
-};
-
-
-static AO2_GLOBAL_OBJ_STATIC(cel_configs);
-
-/*! \brief Destructor for cel_config */
-static void cel_config_dtor(void *obj)
-{
-	struct cel_config *cfg = obj;
-	ao2_cleanup(cfg->general);
-	cfg->general = NULL;
-}
-
-static void *cel_config_alloc(void)
-{
-	RAII_VAR(struct cel_config *, cfg, NULL, ao2_cleanup);
-
-	if (!(cfg = ao2_alloc(sizeof(*cfg), cel_config_dtor))) {
-		return NULL;
-	}
-
-	if (!(cfg->general = ast_cel_general_config_alloc())) {
-		return NULL;
-	}
-
-	ao2_ref(cfg, +1);
-	return cfg;
-}
-
-/*! \brief An aco_type structure to link the "general" category to the ast_cel_general_config type */
-static struct aco_type general_option = {
-	.type = ACO_GLOBAL,
-	.name = "general",
-	.item_offset = offsetof(struct cel_config, general),
-	.category_match = ACO_WHITELIST,
-	.category = "^general$",
-};
-
-/*! \brief The config file to be processed for the module. */
-static struct aco_file cel_conf = {
-	.filename = "cel.conf",                  /*!< The name of the config file */
-	.types = ACO_TYPES(&general_option),     /*!< The mapping object types to be processed */
-	.skip_category = "(^manager$|^radius$)", /*!< Config sections used by existing modules. Do not add to this list. */
-};
-
-static int cel_pre_apply_config(void);
-
-CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,
-	.files = ACO_FILES(&cel_conf),
-	.pre_apply_config = cel_pre_apply_config,
-);
-
-static int cel_pre_apply_config(void)
-{
-	struct cel_config *cfg = aco_pending_config(&cel_cfg_info);
-
-	if (!cfg->general) {
-		return -1;
-	}
-
-	if (!ao2_container_count(cfg->general->apps)) {
-		return 0;
-	}
-
-	if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_START)) {
-		return 0;
-	}
-
-	if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_END)) {
-		return 0;
-	}
-
-	ast_log(LOG_ERROR, "Applications are listed to be tracked, but APP events are not tracked\n");
-	return -1;
-}
+/*!
+ * \brief Container of channel references to a linkedid for CEL purposes.
+ *
+ * \note Accesses to the linkedids container must be done while
+ * holding the reload_lock.
+ */
+static struct ao2_container *linkedids;
 
-static struct aco_type *general_options[] = ACO_TYPES(&general_option);
+/*!
+ * \brief Configured date format for event timestamps
+ */
+static char cel_dateformat[256];
 
 /*!
  * \brief Map of ast_cel_event_type to strings
  */
 static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
-	[0]                        = "ALL",
+	[AST_CEL_ALL]              = "ALL",
 	[AST_CEL_CHANNEL_START]    = "CHAN_START",
 	[AST_CEL_CHANNEL_END]      = "CHAN_END",
 	[AST_CEL_ANSWER]           = "ANSWER",
 	[AST_CEL_HANGUP]           = "HANGUP",
 	[AST_CEL_APP_START]        = "APP_START",
 	[AST_CEL_APP_END]          = "APP_END",
+	[AST_CEL_BRIDGE_START]     = "BRIDGE_START",
+	[AST_CEL_BRIDGE_END]       = "BRIDGE_END",
+	[AST_CEL_BRIDGE_UPDATE]    = "BRIDGE_UPDATE",
+	[AST_CEL_CONF_START]       = "CONF_START",
+	[AST_CEL_CONF_END]         = "CONF_END",
 	[AST_CEL_PARK_START]       = "PARK_START",
 	[AST_CEL_PARK_END]         = "PARK_END",
+	[AST_CEL_TRANSFER]         = "TRANSFER",
 	[AST_CEL_USER_DEFINED]     = "USER_DEFINED",
-	[AST_CEL_BRIDGE_ENTER]     = "BRIDGE_ENTER",
-	[AST_CEL_BRIDGE_EXIT]      = "BRIDGE_EXIT",
+	[AST_CEL_CONF_ENTER]       = "CONF_ENTER",
+	[AST_CEL_CONF_EXIT]        = "CONF_EXIT",
 	[AST_CEL_BLINDTRANSFER]    = "BLINDTRANSFER",
 	[AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
 	[AST_CEL_PICKUP]           = "PICKUP",
 	[AST_CEL_FORWARD]          = "FORWARD",
+	[AST_CEL_3WAY_START]       = "3WAY_START",
+	[AST_CEL_3WAY_END]         = "3WAY_END",
+	[AST_CEL_HOOKFLASH]        = "HOOKFLASH",
 	[AST_CEL_LINKEDID_END]     = "LINKEDID_END",
-	[AST_CEL_LOCAL_OPTIMIZE]   = "LOCAL_OPTIMIZE",
 };
 
-struct cel_backend {
-	ast_cel_backend_cb callback; /*!< Callback for this backend */
-	char name[0];                /*!< Name of this backend */
+/*!
+ * \brief Map of ast_cel_ama_flags to strings
+ */
+static const char * const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] = {
+	[AST_CEL_AMA_FLAG_NONE]          = "NONE",
+	[AST_CEL_AMA_FLAG_OMIT]          = "OMIT",
+	[AST_CEL_AMA_FLAG_BILLING]       = "BILLING",
+	[AST_CEL_AMA_FLAG_DOCUMENTATION] = "DOCUMENTATION",
 };
 
-/*! \brief Hashing function for cel_backend */
-static int cel_backend_hash(const void *obj, int flags)
-{
-	const struct cel_backend *backend;
-	const char *name;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		backend = obj;
-		name = backend->name;
-		break;
-	case OBJ_SEARCH_KEY:
-		name = obj;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-
-	return ast_str_hash(name);
-}
-
-/*! \brief Comparator function for cel_backend */
-static int cel_backend_cmp(void *obj, void *arg, int flags)
-{
-	const struct cel_backend *object_left = obj;
-	const struct cel_backend *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->name, right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-static const char *get_caller_uniqueid(struct ast_multi_channel_blob *blob)
-{
-	struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
-	if (!caller) {
-		return NULL;
-	}
-
-	return caller->uniqueid;
-}
-
-/*! \brief Hashing function for dialstatus container */
-static int dialstatus_hash(const void *obj, int flags)
-{
-	struct ast_multi_channel_blob *blob;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		blob = (void *) obj;
-		key = get_caller_uniqueid(blob);
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! \brief Comparator function for dialstatus container */
-static int dialstatus_cmp(void *obj, void *arg, int flags)
+unsigned int ast_cel_check_enabled(void)
 {
-	struct ast_multi_channel_blob *object_left = obj;
-	struct ast_multi_channel_blob *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = get_caller_uniqueid(object_right);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(get_caller_uniqueid(object_left), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(get_caller_uniqueid(object_left), right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
+	return cel_enabled;
 }
 
-unsigned int ast_cel_check_enabled(void)
+static void print_cel_sub(const struct ast_event *event, void *data)
 {
-	unsigned int enabled;
-	struct cel_config *cfg = ao2_global_obj_ref(cel_configs);
+	struct ast_cli_args *a = data;
 
-	enabled = (!cfg || !cfg->general) ? 0 : cfg->general->enable;
-	ao2_cleanup(cfg);
-	return enabled;
+	ast_cli(a->fd, "CEL Event Subscriber: %s\n",
+			ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
 }
 
 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	unsigned int i;
-	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-	RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), ao2_cleanup);
-	struct ao2_iterator iter;
-	char *app;
+	struct ast_event_sub *sub;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -479,16 +196,16 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		return CLI_SHOWUSAGE;
 	}
 
-	ast_cli(a->fd, "CEL Logging: %s\n", ast_cel_check_enabled() ? "Enabled" : "Disabled");
+	ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
 
-	if (!cfg || !cfg->general || !cfg->general->enable) {
+	if (!cel_enabled) {
 		return CLI_SUCCESS;
 	}
 
-	for (i = 0; i < (sizeof(cfg->general->events) * 8); i++) {
+	for (i = 0; i < (sizeof(eventset) * 8); i++) {
 		const char *name;
 
-		if (!(cfg->general->events & ((int64_t) 1 << i))) {
+		if (!(eventset & ((int64_t) 1 << i))) {
 			continue;
 		}
 
@@ -498,21 +215,36 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		}
 	}
 
-	iter = ao2_iterator_init(cfg->general->apps, 0);
-	for (; (app = ao2_iterator_next(&iter)); ao2_ref(app, -1)) {
-		ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
-	}
-	ao2_iterator_destroy(&iter);
+	/* Accesses to the appset container must be done while holding the reload_lock. */
+	ast_mutex_lock(&reload_lock);
+	if (appset) {
+		struct ao2_iterator iter;
+		char *app;
 
-	if (backends) {
-		struct cel_backend *backend;
+		iter = ao2_iterator_init(appset, 0);
+		for (;;) {
+			app = ao2_iterator_next(&iter);
+			if (!app) {
+				break;
+			}
+			ast_mutex_unlock(&reload_lock);
 
-		iter = ao2_iterator_init(backends, 0);
-		for (; (backend = ao2_iterator_next(&iter)); ao2_ref(backend, -1)) {
-			ast_cli(a->fd, "CEL Event Subscriber: %s\n", backend->name);
+			ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
+
+			ao2_ref(app, -1);
+			ast_mutex_lock(&reload_lock);
 		}
 		ao2_iterator_destroy(&iter);
 	}
+	ast_mutex_unlock(&reload_lock);
+
+	if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
+		return CLI_FAILURE;
+	}
+	ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
+	ast_event_report_subs(sub);
+	ast_event_sub_destroy(sub);
+	sub = NULL;
 
 	return CLI_SUCCESS;
 }
@@ -524,33 +256,23 @@ enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
-		if (!cel_event_types[i]) {
-			continue;
-		}
-
-		if (!strcasecmp(name, cel_event_types[i])) {
+		if (cel_event_types[i] && !strcasecmp(name, cel_event_types[i])) {
 			return i;
 		}
 	}
 
+	ast_log(LOG_ERROR, "Unknown event name '%s'\n", name);
 	return -1;
 }
 
 static int ast_cel_track_event(enum ast_cel_event_type et)
 {
-	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-
-	if (!cfg || !cfg->general) {
-		return 0;
-	}
-
-	return (cfg->general->events & ((int64_t) 1 << et));
+	return (eventset & ((int64_t) 1 << et));
 }
 
-static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+static void parse_events(const char *val)
 {
-	struct ast_cel_general_config *cfg = obj;
-	char *events = ast_strdupa(var->value);
+	char *events = ast_strdupa(val);
 	char *cur_event;
 
 	while ((cur_event = strsep(&events, ","))) {
@@ -563,186 +285,187 @@ static int events_handler(const struct aco_option *opt, struct ast_variable *var
 
 		event_type = ast_cel_str_to_event_type(cur_event);
 
-		if (event_type == 0) {
+		if (event_type == AST_CEL_ALL) {
 			/* All events */
-			cfg->events = (int64_t) -1;
-		} else if (event_type == -1) {
-			ast_log(LOG_ERROR, "Unknown event name '%s'\n", cur_event);
-			return -1;
+			eventset = (int64_t) -1;
+		} else if (event_type == AST_CEL_INVALID_VALUE) {
+			ast_log(LOG_WARNING, "Unknown event name '%s'\n",
+					cur_event);
 		} else {
-			cfg->events |= ((int64_t) 1 << event_type);
+			eventset |= ((int64_t) 1 << event_type);
 		}
 	}
-
-	return 0;
 }
 
-static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+static void parse_apps(const char *val)
 {
-	struct ast_cel_general_config *cfg = obj;
-	char *apps = ast_strdupa(var->value);
+	char *apps = ast_strdupa(val);
 	char *cur_app;
 
+	if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
+		ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
+		return;
+	}
+
 	while ((cur_app = strsep(&apps, ","))) {
+		char *app;
+
 		cur_app = ast_strip(cur_app);
 		if (ast_strlen_zero(cur_app)) {
 			continue;
 		}
 
-		cur_app = ast_str_to_lower(cur_app);
-		ast_str_container_add(cfg->apps, cur_app);
-	}
+		/* The app object is immutable so it doesn't need a lock of its own. */
+		app = ao2_alloc_options(strlen(cur_app) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+		if (!app) {
+			continue;
+		}
+		strcpy(app, cur_app);/* Safe */
 
-	return 0;
+		ao2_link(appset, app);
+		ao2_ref(app, -1);
+		app = NULL;
+	}
 }
 
-const char *ast_cel_get_type_name(enum ast_cel_event_type type)
+static void set_defaults(void)
 {
-	return S_OR(cel_event_types[type], "Unknown");
+	cel_enabled = CEL_ENABLED_DEFAULT;
+	eventset = CEL_DEFAULT_EVENTS;
+	*cel_dateformat = '\0';
+	ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
 }
 
-static int cel_track_app(const char *const_app)
+static int do_reload(int is_reload)
 {
-	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-	RAII_VAR(char *, app, NULL, ao2_cleanup);
-	char *app_lower;
+	struct ast_config *config;
+	const char *enabled_value;
+	const char *val;
+	int res = 0;
+	struct ast_flags config_flags = { 0, };
+	const char *s;
 
-	if (!cfg || !cfg->general) {
-		return 0;
-	}
+	ast_mutex_lock(&reload_lock);
 
-	app_lower = ast_str_to_lower(ast_strdupa(const_app));
-	app = ao2_find(cfg->general->apps, app_lower, OBJ_SEARCH_KEY);
-	if (!app) {
-		return 0;
+	if (!is_reload) {
+		/* Initialize all settings before first configuration load. */
+		set_defaults();
 	}
 
-	return 1;
-}
-
-static int cel_linkedid_ref(const char *linkedid);
-
-struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
-		enum ast_cel_event_type event_type, const char *userdefevname,
-		struct ast_json *extra, const char *peer)
-{
-	struct timeval eventtime = ast_tvnow();
-	RAII_VAR(char *, extra_txt, NULL, ast_json_free);
-	if (extra) {
-		extra_txt = ast_json_dump_string(extra);
+	/*
+	 * Unfortunately we have to always load the config file because
+	 * other modules read the same file.
+	 */
+	config = ast_config_load2(cel_conf_file, "cel", config_flags);
+	if (!config || config == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "Could not load %s\n", cel_conf_file);
+		config = NULL;
+		goto return_cleanup;
+	}
+	if (config == CONFIG_STATUS_FILEUNCHANGED) {
+		/* This should never happen because we always load the config file. */
+		config = NULL;
+		goto return_cleanup;
 	}
-	return ast_event_new(AST_EVENT_CEL,
-		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
-		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
-		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
-		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, S_OR(userdefevname, ""),
-		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_name,
-		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_number,
-		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_ani,
-		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_rdnis,
-		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_dnid,
-		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->exten,
-		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->context,
-		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->name,
-		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->appl,
-		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->data,
-		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, snapshot->amaflags,
-		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->accountcode,
-		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peeraccount,
-		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
-		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
-		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
-		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
-		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer, ""),
-		AST_EVENT_IE_END);
-}
-
-static int cel_backend_send_cb(void *obj, void *arg, int flags)
-{
-	struct cel_backend *backend = obj;
 
-	backend->callback(arg);
-	return 0;
-}
+	if (is_reload) {
+		/* Reset all settings before reloading configuration */
+		set_defaults();
+	}
 
-static int cel_report_event(struct ast_channel_snapshot *snapshot,
-		enum ast_cel_event_type event_type, const char *userdefevname,
-		struct ast_json *extra, const char *peer_str)
-{
-	struct ast_event *ev;
-	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-	RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), ao2_cleanup);
+	if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
+		cel_enabled = ast_true(enabled_value);
+	}
 
-	if (!cfg || !cfg->general || !cfg->general->enable || !backends) {
-		return 0;
+	if (!cel_enabled) {
+		goto return_cleanup;
 	}
 
-	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
-	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
-	if (event_type == AST_CEL_CHANNEL_START
-		&& ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-		if (cel_linkedid_ref(snapshot->linkedid)) {
-			return -1;
-		}
+	/* get the date format for logging */
+	if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
+		ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
 	}
 
-	if (!ast_cel_track_event(event_type)) {
-		return 0;
+	if ((val = ast_variable_retrieve(config, "general", "events"))) {
+		parse_events(val);
 	}
 
-	if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
-		&& !cel_track_app(snapshot->appl)) {
-		return 0;
+	if ((val = ast_variable_retrieve(config, "general", "apps"))) {
+		parse_apps(val);
 	}
 
-	ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra, peer_str);
-	if (!ev) {
-		return -1;
+return_cleanup:
+	ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
+
+	ast_mutex_unlock(&reload_lock);
+
+	if (config) {
+		ast_config_destroy(config);
 	}
 
-	/* Distribute event to backends */
-	ao2_callback(backends, OBJ_MULTIPLE | OBJ_NODATA, cel_backend_send_cb, ev);
-	ast_event_destroy(ev);
+	return res;
+}
 
-	return 0;
+const char *ast_cel_get_type_name(enum ast_cel_event_type type)
+{
+	return S_OR(cel_event_types[type], "Unknown");
+}
+
+const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag)
+{
+	if (flag >= ARRAY_LEN(cel_ama_flags)) {
+		ast_log(LOG_WARNING, "Invalid AMA flag: %u\n", flag);
+		return "Unknown";
+	}
+
+	return S_OR(cel_ama_flags[flag], "Unknown");
 }
 
 /* called whenever a channel is destroyed or a linkedid is changed to
  * potentially emit a CEL_LINKEDID_END event */
-static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
+void ast_cel_check_retire_linkedid(struct ast_channel *chan)
 {
-	RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
+	const char *linkedid = ast_channel_linkedid(chan);
 	struct cel_linkedid *lid;
 
-	if (!linkedids || ast_strlen_zero(snapshot->linkedid)) {
-		/* The CEL module is shutdown.  Abort. */
+	if (ast_strlen_zero(linkedid)) {
 		return;
 	}
 
-	ao2_lock(linkedids);
+	/* Get the lock in case any CEL events are still in flight when we shutdown. */
+	ast_mutex_lock(&reload_lock);
+
+	if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)
+		|| !linkedids) {
+		/*
+		 * CEL is disabled or we are not tracking linkedids
+		 * or the CEL module is shutdown.
+		 */
+		ast_mutex_unlock(&reload_lock);
+		return;
+	}
 
-	lid = ao2_find(linkedids, (void *) snapshot->linkedid, OBJ_SEARCH_KEY);
+	lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
 	if (!lid) {
-		ao2_unlock(linkedids);
+		ast_mutex_unlock(&reload_lock);
 
 		/*
 		 * The user may have done a reload to start tracking linkedids
 		 * when a call was already in progress.  This is an unusual kind
 		 * of change to make after starting Asterisk.
 		 */
-		ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
-			snapshot->linkedid);
+		ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
 		return;
 	}
 
 	if (!--lid->count) {
 		/* No channels use this linkedid anymore. */
 		ao2_unlink(linkedids, lid);
-		ao2_unlock(linkedids);
+		ast_mutex_unlock(&reload_lock);
 
-		cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
+		ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
 	} else {
-		ao2_unlock(linkedids);
+		ast_mutex_unlock(&reload_lock);
 	}
 	ao2_ref(lid, -1);
 }
@@ -767,11 +490,6 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 	};
 	struct ast_datastore *datastore;
 	char *app_data;
-	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-
-	if (!cfg || !cfg->general) {
-		return NULL;
-	}
 
 	/* do not call ast_channel_alloc because this is not really a real channel */
 	if (!(tchan = ast_dummy_channel_alloc())) {
@@ -793,13 +511,13 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 	}
 
-	if (ast_strlen_zero(cfg->general->date_format)) {
+	if (ast_strlen_zero(cel_dateformat)) {
 		snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
 				(long) record.event_time.tv_usec);
 	} else {
 		struct ast_tm tm;
 		ast_localtime(&record.event_time, &tm, NULL);
-		ast_strftime(timebuf, sizeof(timebuf), cfg->general->date_format, &tm);
+		ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
 	}
 
 	if ((newvariable = ast_var_assign("eventtime", timebuf))) {
@@ -829,7 +547,8 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 	ast_channel_exten_set(tchan, record.extension);
 	ast_channel_context_set(tchan, record.context);
 	ast_channel_name_set(tchan, record.channel_name);
-	ast_channel_internal_set_fake_ids(tchan, record.unique_id, record.linked_id);
+	ast_channel_uniqueid_set(tchan, record.unique_id);
+	ast_channel_linkedid_set(tchan, record.linked_id);
 	ast_channel_accountcode_set(tchan, record.account_code);
 	ast_channel_peeraccount_set(tchan, record.peer_account);
 	ast_channel_userfield_set(tchan, record.user_field);
@@ -876,31 +595,39 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 	return tchan;
 }
 
-static int cel_linkedid_ref(const char *linkedid)
+int ast_cel_linkedid_ref(const char *linkedid)
 {
-	RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
 	struct cel_linkedid *lid;
 
 	if (ast_strlen_zero(linkedid)) {
 		ast_log(LOG_ERROR, "The linkedid should never be empty\n");
 		return -1;
 	}
+
+	/* Get the lock in case any CEL events are still in flight when we shutdown. */
+	ast_mutex_lock(&reload_lock);
+
+	if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
+		/* CEL is disabled or we are not tracking linkedids. */
+		ast_mutex_unlock(&reload_lock);
+		return 0;
+	}
 	if (!linkedids) {
 		/* The CEL module is shutdown.  Abort. */
+		ast_mutex_unlock(&reload_lock);
 		return -1;
 	}
 
-	ao2_lock(linkedids);
-	lid = ao2_find(linkedids, (void *) linkedid, OBJ_SEARCH_KEY);
+	lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
 	if (!lid) {
 		/*
 		 * Changes to the lid->count member are protected by the
-		 * container lock so the lid object does not need its own lock.
+		 * reload_lock so the lid object does not need its own lock.
 		 */
 		lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
 			AO2_ALLOC_OPT_LOCK_NOLOCK);
 		if (!lid) {
-			ao2_unlock(linkedids);
+			ast_mutex_unlock(&reload_lock);
 			return -1;
 		}
 		strcpy(lid->id, linkedid);/* Safe */
@@ -908,1001 +635,267 @@ static int cel_linkedid_ref(const char *linkedid)
 		ao2_link(linkedids, lid);
 	}
 	++lid->count;
-	ao2_unlock(linkedids);
+	ast_mutex_unlock(&reload_lock);
 	ao2_ref(lid, -1);
 
 	return 0;
 }
 
-int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
+int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
+		const char *userdefevname, const char *extra, struct ast_channel *peer2)
 {
-	if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
-		ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record.  "
-				"Please ensure all modules were compiled for "
-				"this version of Asterisk.\n");
+	struct timeval eventtime;
+	struct ast_event *ev;
+	const char *peername = "";
+	struct ast_channel *peer;
+	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));
+
+	/* Make sure a reload is not occurring while we're checking to see if this
+	 * is an event that we care about.  We could lose an important event in this
+	 * process otherwise. */
+	ast_mutex_lock(&reload_lock);
+
+	if (!appset) {
+		/* The CEL module is shutdown.  Abort. */
+		ast_mutex_unlock(&reload_lock);
 		return -1;
 	}
 
-	r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
+	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
+	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
+	if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
+		if (ast_cel_linkedid_ref(linkedid)) {
+			ast_mutex_unlock(&reload_lock);
+			return -1;
+		}
+	}
 
-	r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
-	r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
+	if (!cel_enabled || !ast_cel_track_event(event_type)) {
+		ast_mutex_unlock(&reload_lock);
+		return 0;
+	}
 
-	r->event_name = ast_cel_get_type_name(r->event_type);
-	if (r->event_type == AST_CEL_USER_DEFINED) {
-		r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
-	} else {
-		r->user_defined_name = "";
+	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
+		char *app;
+		if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
+			ast_mutex_unlock(&reload_lock);
+			return 0;
+		}
+		ao2_ref(app, -1);
 	}
 
-	r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
-	r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
-	r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
-	r->caller_id_rdnis  = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
-	r->caller_id_dnid   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
-	r->extension        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
-	r->context          = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
-	r->channel_name     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
-	r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
-	r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
-	r->account_code     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
-	r->peer_account     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEERACCT), "");
-	r->unique_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
-	r->linked_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
-	r->amaflag          = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
-	r->user_field       = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
-	r->peer             = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
-	r->extra            = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
-
-	return 0;
-}
+	ast_mutex_unlock(&reload_lock);
 
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef void (*cel_channel_snapshot_monitor)(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot);
-
-static struct ast_multi_channel_blob *get_dialstatus_blob(const char *uniqueid)
-{
-	struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
-	struct ast_multi_channel_blob *blob = NULL;
-
-	if (dial_statuses) {
-		blob = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
-		ao2_ref(dial_statuses, -1);
+	ast_channel_lock(chan);
+	peer = ast_bridged_channel(chan);
+	if (peer) {
+		ast_channel_ref(peer);
 	}
-	return blob;
-}
+	ast_channel_unlock(chan);
 
-static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname)
-{
-	struct ast_json *json = ast_multi_channel_blob_get_json(blob);
-	if (!json) {
-		return NULL;
+	if (peer) {
+		ast_channel_lock(peer);
+		peername = ast_strdupa(ast_channel_name(peer));
+		ast_channel_unlock(peer);
+	} else if (peer2) {
+		ast_channel_lock(peer2);
+		peername = ast_strdupa(ast_channel_name(peer2));
+		ast_channel_unlock(peer2);
 	}
 
-	json = ast_json_object_get(json, varname);
-	if (!json) {
-		return NULL;
+	if (!userdefevname) {
+		userdefevname = "";
 	}
 
-	return ast_json_string_get(json);
-}
-
-/*! \brief Handle channel state changes */
-static void cel_channel_state_change(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	int is_hungup, was_hungup;
-
-	if (!new_snapshot) {
-		cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
-		if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-			check_retire_linkedid(old_snapshot);
-		}
-		return;
+	if (!extra) {
+		extra = "";
 	}
 
-	if (!old_snapshot) {
-		cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
-		return;
-	}
+	eventtime = ast_tvnow();
 
-	was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
-	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
+	ast_channel_lock(chan);
 
-	if (!was_hungup && is_hungup) {
-		struct ast_json *extra;
-		struct ast_multi_channel_blob *blob = get_dialstatus_blob(new_snapshot->uniqueid);
-		const char *dialstatus = "";
+	ev = ast_event_new(AST_EVENT_CEL,
+		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
+		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
+		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
+		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
+		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
+			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
+		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
+			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
+		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
+			S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
+		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
+			S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
+		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
+			S_OR(ast_channel_dialed(chan)->number.str, ""),
+		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
+		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
+		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
+		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
+		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
+		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
+		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
+		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
+		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
+		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
+		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
+		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
+		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
+		AST_EVENT_IE_END);
 
-		if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
-			dialstatus = get_blob_variable(blob, "dialstatus");
-		}
-		extra = ast_json_pack("{s: i, s: s, s: s}",
-			"hangupcause", new_snapshot->hangupcause,
-			"hangupsource", new_snapshot->hangupsource,
-			"dialstatus", dialstatus);
-		cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
-		ast_json_unref(extra);
-		ao2_cleanup(blob);
-		return;
-	}
+	ast_channel_unlock(chan);
 
-	if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
-		cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
-		return;
+	if (peer) {
+		peer = ast_channel_unref(peer);
 	}
-}
 
-static void cel_channel_linkedid_change(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	if (!old_snapshot || !new_snapshot) {
-		return;
+	if (ev && ast_event_queue(ev)) {
+		ast_event_destroy(ev);
+		return -1;
 	}
 
-	ast_assert(!ast_strlen_zero(new_snapshot->linkedid));
-	ast_assert(!ast_strlen_zero(old_snapshot->linkedid));
-
-	if (ast_cel_track_event(AST_CEL_LINKEDID_END)
-		&& strcmp(old_snapshot->linkedid, new_snapshot->linkedid)) {
-		cel_linkedid_ref(new_snapshot->linkedid);
-		check_retire_linkedid(old_snapshot);
-	}
+	return 0;
 }
 
-static void cel_channel_app_change(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
+int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
 {
-	if (new_snapshot && old_snapshot
-		&& !strcmp(old_snapshot->appl, new_snapshot->appl)) {
-		return;
-	}
-
-	/* old snapshot has an application, end it */
-	if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
-		cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
+	if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
+		ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record.  "
+				"Please ensure all modules were compiled for "
+				"this version of Asterisk.\n");
+		return -1;
 	}
 
-	/* new snapshot has an application, start it */
-	if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
-		cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
-	}
-}
+	r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
 
-/* \brief Handlers for channel snapshot changes.
- * \note Order of the handlers matters. Application changes must come before state
- * changes to ensure that hangup notifications occur after application changes.
- * Linkedid checking should always come last.
- */
-cel_channel_snapshot_monitor cel_channel_monitors[] = {
-	cel_channel_app_change,
-	cel_channel_state_change,
-	cel_channel_linkedid_change,
-};
+	r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
+	r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
 
-static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
-{
-	if (!snapshot) {
-		return 0;
+	r->event_name = ast_cel_get_type_name(r->event_type);
+	if (r->event_type == AST_CEL_USER_DEFINED) {
+		r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
+	} else {
+		r->user_defined_name = "";
 	}
-	return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
-}
-
-static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_cache_update *update = stasis_message_data(message);
-	if (ast_channel_snapshot_type() == update->type) {
-		struct ast_channel_snapshot *old_snapshot;
-		struct ast_channel_snapshot *new_snapshot;
-		size_t i;
 
-		old_snapshot = stasis_message_data(update->old_snapshot);
-		new_snapshot = stasis_message_data(update->new_snapshot);
-
-		if (cel_filter_channel_snapshot(old_snapshot) || cel_filter_channel_snapshot(new_snapshot)) {
-			return;
-		}
+	r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
+	r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
+	r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
+	r->caller_id_rdnis  = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
+	r->caller_id_dnid   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
+	r->extension        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
+	r->context          = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
+	r->channel_name     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
+	r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
+	r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
+	r->account_code     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
+	r->peer_account     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
+	r->unique_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
+	r->linked_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
+	r->amaflag          = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
+	r->user_field       = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
+	r->peer             = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
+	r->extra            = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
 
-		for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
-			cel_channel_monitors[i](old_snapshot, new_snapshot);
-		}
-	}
+	return 0;
 }
 
-static struct ast_str *cel_generate_peer_str(
-	struct ast_bridge_snapshot *bridge,
-	struct ast_channel_snapshot *chan)
+static int app_hash(const void *obj, const int flags)
 {
-	struct ast_str *peer_str = ast_str_create(32);
-	struct ao2_iterator i;
-	char *current_chan = NULL;
-
-	if (!peer_str) {
-		return NULL;
-	}
-
-	for (i = ao2_iterator_init(bridge->channels, 0);
-		(current_chan = ao2_iterator_next(&i));
-		ao2_cleanup(current_chan)) {
-		struct ast_channel_snapshot *current_snapshot;
-
-		/* Don't add the channel for which this message is being generated */
-		if (!strcmp(current_chan, chan->uniqueid)) {
-			continue;
-		}
-
-		current_snapshot = ast_channel_snapshot_get_latest(current_chan);
-		if (!current_snapshot) {
-			continue;
-		}
-
-		ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
-		ao2_cleanup(current_snapshot);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Rip off the trailing comma */
-	ast_str_truncate(peer_str, -1);
-
-	return peer_str;
+	return ast_str_case_hash((const char *) obj);
 }
 
-static void cel_bridge_enter_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static int app_cmp(void *obj, void *arg, int flags)
 {
-	struct ast_bridge_blob *blob = stasis_message_data(message);
-	struct ast_bridge_snapshot *snapshot = blob->bridge;
-	struct ast_channel_snapshot *chan_snapshot = blob->channel;
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
-
-	if (cel_filter_channel_snapshot(chan_snapshot)) {
-		return;
-	}
+	const char *app1 = obj;
+	const char *app2 = arg;
 
-	extra = ast_json_pack("{s: s, s: s}",
-		"bridge_id", snapshot->uniqueid,
-		"bridge_technology", snapshot->technology);
-	if (!extra) {
-		return;
-	}
-
-	peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
-	if (!peer_str) {
-		return;
-	}
-
-	cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, NULL, extra, ast_str_buffer(peer_str));
+	return !strcasecmp(app1, app2) ? CMP_MATCH : 0;
 }
 
-static void cel_bridge_leave_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static int lid_hash(const void *obj, const int flags)
 {
-	struct ast_bridge_blob *blob = stasis_message_data(message);
-	struct ast_bridge_snapshot *snapshot = blob->bridge;
-	struct ast_channel_snapshot *chan_snapshot = blob->channel;
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, peer_str, NULL, ast_free);
-
-	if (cel_filter_channel_snapshot(chan_snapshot)) {
-		return;
-	}
+	const struct cel_linkedid *lid = obj;
+	const char *key = obj;
 
-	extra = ast_json_pack("{s: s, s: s}",
-		"bridge_id", snapshot->uniqueid,
-		"bridge_technology", snapshot->technology);
-	if (!extra) {
-		return;
-	}
-
-	peer_str = cel_generate_peer_str(snapshot, chan_snapshot);
-	if (!peer_str) {
-		return;
-	}
-
-	cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str));
-}
-
-static void cel_parking_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
-	const char *reason = NULL;
-
-	switch (parked_payload->event_type) {
-	case PARKED_CALL:
-		extra = ast_json_pack("{s: s, s: s}",
-			"parker_dial_string", parked_payload->parker_dial_string,
-			"parking_lot", parked_payload->parkinglot);
-		if (extra) {
-			cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
-		}
-		return;
-	case PARKED_CALL_TIMEOUT:
-		reason = "ParkedCallTimeOut";
-		break;
-	case PARKED_CALL_GIVEUP:
-		reason = "ParkedCallGiveUp";
-		break;
-	case PARKED_CALL_UNPARKED:
-		reason = "ParkedCallUnparked";
-		break;
-	case PARKED_CALL_FAILED:
-		reason = "ParkedCallFailed";
+	switch (flags & (OBJ_POINTER | OBJ_KEY)) {
+	case OBJ_POINTER:
+	default:
+		key = lid->id;
 		break;
-	case PARKED_CALL_SWAP:
-		reason = "ParkedCallSwap";
+	case OBJ_KEY:
 		break;
 	}
 
-	if (parked_payload->retriever) {
-		extra = ast_json_pack("{s: s, s: s}",
-			"reason", reason,
-			"retriever", parked_payload->retriever->name);
-	} else {
-		extra = ast_json_pack("{s: s}", "reason", reason);
-	}
-
-	if (extra) {
-		cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
-	}
+	return ast_str_case_hash(key);
 }
 
-static void save_dialstatus(struct ast_multi_channel_blob *blob)
-{
-	struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store);
-
-	ast_assert(blob != NULL);
-
-	if (dial_statuses) {
-		ao2_link(dial_statuses, blob);
-		ao2_ref(dial_statuses, -1);
-	}
-}
-
-static int is_valid_dialstatus(struct ast_multi_channel_blob *blob)
-{
-	const char *dialstatus = get_blob_variable(blob, "dialstatus");
-	int res = 0;
-
-	if (ast_strlen_zero(dialstatus)) {
-		res = 0;
-	} else if (!strcasecmp(dialstatus, "CHANUNAVAIL")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "CONGESTION")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "NOANSWER")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "BUSY")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "ANSWER")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "CANCEL")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "DONTCALL")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "TORTURE")) {
-		res = 1;
-	} else if (!strcasecmp(dialstatus, "INVALIDARGS")) {
-		res = 1;
-	}
-	return res;
-}
-
-static void cel_dial_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static int lid_cmp(void *obj, void *arg, int flags)
 {
-	struct ast_multi_channel_blob *blob = stasis_message_data(message);
+	struct cel_linkedid *lid1 = obj;
+	struct cel_linkedid *lid2 = arg;
+	const char *key = arg;
 
-	if (cel_filter_channel_snapshot(ast_multi_channel_blob_get_channel(blob, "caller"))) {
-		return;
-	}
-
-	if (!get_caller_uniqueid(blob)) {
-		return;
-	}
-
-	if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
-		struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
-		struct ast_json *extra;
-
-		if (!caller) {
-			return;
-		}
-
-		extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
-		if (extra) {
-			cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL);
-			ast_json_unref(extra);
-		}
-	}
-
-	if (is_valid_dialstatus(blob)) {
-		save_dialstatus(blob);
-	}
-}
-
-static void cel_generic_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	int event_type = ast_json_integer_get(ast_json_object_get(obj->blob, "event_type"));
-	struct ast_json *event_details = ast_json_object_get(obj->blob, "event_details");
-
-	switch (event_type) {
-	case AST_CEL_USER_DEFINED:
-		{
-			const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
-			struct ast_json *extra = ast_json_object_get(event_details, "extra");
-			cel_report_event(obj->snapshot, event_type, event, extra, NULL);
-			break;
-		}
+	switch (flags & (OBJ_POINTER | OBJ_KEY)) {
+	case OBJ_POINTER:
 	default:
-		ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
-		break;
-	}
-}
-
-static void cel_blind_transfer_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
-	struct ast_channel_snapshot *chan_snapshot = transfer_msg->transferer;
-	struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->bridge;
-	struct ast_json *extra;
-
-	if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
-		return;
-	}
-
-	extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
-		"extension", transfer_msg->exten,
-		"context", transfer_msg->context,
-		"bridge_id", bridge_snapshot->uniqueid,
-		"transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->name : "N/A",
-		"transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->uniqueid  : "N/A");
-	if (extra) {
-		cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
-		ast_json_unref(extra);
-	}
-}
-
-static void cel_attended_transfer_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_attended_transfer_message *xfer = stasis_message_data(message);
-	struct ast_json *extra = NULL;
-	struct ast_bridge_snapshot *bridge1, *bridge2;
-	struct ast_channel_snapshot *channel1, *channel2;
-
-	/* Make sure bridge1 is always non-NULL */
-	if (!xfer->to_transferee.bridge_snapshot) {
-		bridge1 = xfer->to_transfer_target.bridge_snapshot;
-		bridge2 = xfer->to_transferee.bridge_snapshot;
-		channel1 = xfer->to_transfer_target.channel_snapshot;
-		channel2 = xfer->to_transferee.channel_snapshot;
-	} else {
-		bridge1 = xfer->to_transferee.bridge_snapshot;
-		bridge2 = xfer->to_transfer_target.bridge_snapshot;
-		channel1 = xfer->to_transferee.channel_snapshot;
-		channel2 = xfer->to_transfer_target.channel_snapshot;
-	}
-
-	switch (xfer->dest_type) {
-	case AST_ATTENDED_TRANSFER_DEST_FAIL:
-		return;
-		/* handle these three the same */
-	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
-	case AST_ATTENDED_TRANSFER_DEST_LINK:
-	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
-			"bridge1_id", bridge1->uniqueid,
-			"channel2_name", channel2->name,
-			"channel2_uniqueid", channel2->uniqueid,
-			"bridge2_id", bridge2->uniqueid,
-			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
-		if (!extra) {
-			return;
-		}
+		key = lid2->id;
 		break;
-	case AST_ATTENDED_TRANSFER_DEST_APP:
-	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
-		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
-			"bridge1_id", bridge1->uniqueid,
-			"channel2_name", channel2->name,
-			"channel2_uniqueid", channel2->uniqueid,
-			"app", xfer->dest.app,
-			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
-		if (!extra) {
-			return;
-		}
+	case OBJ_KEY:
 		break;
 	}
-	cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
-	ast_json_unref(extra);
-}
-
-static void cel_pickup_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *obj = stasis_message_data(message);
-	struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
-	struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
-	struct ast_json *extra;
-
-	if (!channel || !target) {
-		return;
-	}
-
-	extra = ast_json_pack("{s: s, s: s}",
-		"pickup_channel", channel->name,
-		"pickup_channel_uniqueid", channel->uniqueid);
-	if (!extra) {
-		return;
-	}
 
-	cel_report_event(target, AST_CEL_PICKUP, NULL, extra, NULL);
-	ast_json_unref(extra);
+	return !strcasecmp(lid1->id, key) ? CMP_MATCH : 0;
 }
 
-static void cel_local_cb(
-	void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static void ast_cel_engine_term(void)
 {
-	struct ast_multi_channel_blob *obj = stasis_message_data(message);
-	struct ast_channel_snapshot *localone = ast_multi_channel_blob_get_channel(obj, "1");
-	struct ast_channel_snapshot *localtwo = ast_multi_channel_blob_get_channel(obj, "2");
-	struct ast_json *extra;
-
-	if (!localone || !localtwo) {
-		return;
-	}
-
-	extra = ast_json_pack("{s: s, s: s}",
-		"local_two", localtwo->name,
-		"local_two_uniqueid", localtwo->uniqueid);
-	if (!extra) {
-		return;
-	}
+	/* Get the lock in case any CEL events are still in flight when we shutdown. */
+	ast_mutex_lock(&reload_lock);
 
-	cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
-	ast_json_unref(extra);
-}
+	ao2_cleanup(appset);
+	appset = NULL;
+	ao2_cleanup(linkedids);
+	linkedids = NULL;
 
-static void destroy_routes(void)
-{
-	stasis_message_router_unsubscribe_and_join(cel_state_router);
-	cel_state_router = NULL;
-}
+	ast_mutex_unlock(&reload_lock);
 
-static void destroy_subscriptions(void)
-{
-	ao2_cleanup(cel_aggregation_topic);
-	cel_aggregation_topic = NULL;
-	ao2_cleanup(cel_topic);
-	cel_topic = NULL;
-
-	cel_channel_forwarder = stasis_forward_cancel(cel_channel_forwarder);
-	cel_bridge_forwarder = stasis_forward_cancel(cel_bridge_forwarder);
-	cel_parking_forwarder = stasis_forward_cancel(cel_parking_forwarder);
-	cel_cel_forwarder = stasis_forward_cancel(cel_cel_forwarder);
-}
-
-static void cel_engine_cleanup(void)
-{
-	destroy_routes();
-	destroy_subscriptions();
-	STASIS_MESSAGE_TYPE_CLEANUP(cel_generic_type);
-}
-
-static void cel_engine_atexit(void)
-{
 	ast_cli_unregister(&cli_status);
-	aco_info_destroy(&cel_cfg_info);
-	ao2_global_obj_release(cel_configs);
-	ao2_global_obj_release(cel_dialstatus_store);
-	ao2_global_obj_release(cel_linkedids);
-	ao2_global_obj_release(cel_backends);
 }
 
-static void cel_engine_abort(void)
-{
-	cel_engine_cleanup();
-	cel_engine_atexit();
-}
-
-/*!
- * \brief Create the Stasis subscriptions for CEL
- */
-static int create_subscriptions(void)
-{
-	cel_aggregation_topic = stasis_topic_create("cel_aggregation_topic");
-	if (!cel_aggregation_topic) {
-		return -1;
-	}
-
-	cel_topic = stasis_topic_create("cel_topic");
-	if (!cel_topic) {
-		return -1;
-	}
-
-	cel_channel_forwarder = stasis_forward_all(
-		ast_channel_topic_all_cached(),
-		cel_aggregation_topic);
-	if (!cel_channel_forwarder) {
-		return -1;
-	}
-
-	cel_bridge_forwarder = stasis_forward_all(
-		ast_bridge_topic_all_cached(),
-		cel_aggregation_topic);
-	if (!cel_bridge_forwarder) {
-		return -1;
-	}
-
-	cel_parking_forwarder = stasis_forward_all(
-		ast_parking_topic(),
-		cel_aggregation_topic);
-	if (!cel_parking_forwarder) {
-		return -1;
-	}
-
-	cel_cel_forwarder = stasis_forward_all(
-		ast_cel_topic(),
-		cel_aggregation_topic);
-	if (!cel_cel_forwarder) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Create the Stasis message router and routes for CEL
- */
-static int create_routes(void)
-{
-	int ret = 0;
-
-	cel_state_router = stasis_message_router_create(cel_aggregation_topic);
-	if (!cel_state_router) {
-		return -1;
-	}
-
-	ret |= stasis_message_router_add(cel_state_router,
-		stasis_cache_update_type(),
-		cel_snapshot_update_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_channel_dial_type(),
-		cel_dial_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_channel_entered_bridge_type(),
-		cel_bridge_enter_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_channel_left_bridge_type(),
-		cel_bridge_leave_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_parked_call_type(),
-		cel_parking_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		cel_generic_type(),
-		cel_generic_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_blind_transfer_type(),
-		cel_blind_transfer_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_attended_transfer_type(),
-		cel_attended_transfer_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_call_pickup_type(),
-		cel_pickup_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(cel_state_router,
-		ast_local_optimization_end_type(),
-		cel_local_cb,
-		NULL);
-
-	if (ret) {
-		ast_log(AST_LOG_ERROR, "Failed to register for Stasis messages\n");
-	}
-
-	return ret;
-}
-
-static int lid_hash(const void *obj, const int flags)
-{
-	const struct cel_linkedid *lid;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		lid = obj;
-		key = lid->id;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int lid_cmp(void *obj, void *arg, int flags)
+int ast_cel_engine_init(void)
 {
-	const struct cel_linkedid *object_left = obj;
-	const struct cel_linkedid *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->id, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->id, right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
 	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
+	 * Accesses to the appset and linkedids containers have to be
+	 * protected by the reload_lock so they don't need a lock of
+	 * their own.
 	 */
-	return CMP_MATCH;
-}
-
-int ast_cel_engine_init(void)
-{
-	struct ao2_container *container;
-
-	container = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp);
-	ao2_global_obj_replace_unref(cel_linkedids, container);
-	ao2_cleanup(container);
-	if (!container) {
-		cel_engine_abort();
-		return -1;
-	}
-
-	container = ao2_container_alloc(NUM_DIALSTATUS_BUCKETS,
-		dialstatus_hash, dialstatus_cmp);
-	ao2_global_obj_replace_unref(cel_dialstatus_store, container);
-	ao2_cleanup(container);
-	if (!container) {
-		cel_engine_abort();
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(cel_generic_type)) {
-		cel_engine_abort();
+	appset = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, NUM_APP_BUCKETS,
+		app_hash, app_cmp);
+	if (!appset) {
 		return -1;
 	}
-
-	if (ast_cli_register(&cli_status)) {
-		cel_engine_abort();
-		return -1;
-	}
-
-	container = ao2_container_alloc(BACKEND_BUCKETS, cel_backend_hash, cel_backend_cmp);
-	ao2_global_obj_replace_unref(cel_backends, container);
-	ao2_cleanup(container);
-	if (!container) {
-		cel_engine_abort();
+	linkedids = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, NUM_APP_BUCKETS,
+		lid_hash, lid_cmp);
+	if (!linkedids) {
+		ast_cel_engine_term();
 		return -1;
 	}
 
-	if (aco_info_init(&cel_cfg_info)) {
-		cel_engine_abort();
+	if (do_reload(0) || ast_cli_register(&cli_status)) {
+		ast_cel_engine_term();
 		return -1;
 	}
 
-	aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct ast_cel_general_config, enable));
-	aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_cel_general_config, date_format));
-	aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
-	aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
-
-	if (aco_process_config(&cel_cfg_info, 0)) {
-		struct cel_config *cel_cfg = cel_config_alloc();
-
-		if (!cel_cfg) {
-			cel_engine_abort();
-			return -1;
-		}
-
-		/* We couldn't process the configuration so create a default config. */
-		if (!aco_set_defaults(&general_option, "general", cel_cfg->general)) {
-			ast_log(LOG_NOTICE, "Failed to process CEL configuration; using defaults\n");
-			ao2_global_obj_replace_unref(cel_configs, cel_cfg);
-		}
-		ao2_ref(cel_cfg, -1);
-	}
+	ast_register_cleanup(ast_cel_engine_term);
 
-	if (create_subscriptions()) {
-		cel_engine_abort();
-		return -1;
-	}
-
-	if (ast_cel_check_enabled() && create_routes()) {
-		cel_engine_abort();
-		return -1;
-	}
-
-	ast_register_atexit(cel_engine_atexit);
-	ast_register_cleanup(cel_engine_cleanup);
 	return 0;
 }
 
 int ast_cel_engine_reload(void)
 {
-	unsigned int was_enabled = ast_cel_check_enabled();
-	unsigned int is_enabled;
-
-	if (aco_process_config(&cel_cfg_info, 1) == ACO_PROCESS_ERROR) {
-		return -1;
-	}
-
-	is_enabled = ast_cel_check_enabled();
-
-	if (!was_enabled && is_enabled) {
-		if (create_routes()) {
-			return -1;
-		}
-	} else if (was_enabled && !is_enabled) {
-		destroy_routes();
-	}
-
-	ast_verb(3, "CEL logging %sabled.\n", is_enabled ? "en" : "dis");
-
-	return 0;
-}
-
-void ast_cel_publish_event(struct ast_channel *chan,
-	enum ast_cel_event_type event_type,
-	struct ast_json *blob)
-{
-	struct ast_json *cel_blob;
-	struct stasis_message *message;
-
-	cel_blob = ast_json_pack("{s: i, s: O}",
-		"event_type", event_type,
-		"event_details", blob);
-
-	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), cel_generic_type(), cel_blob);
-	if (message) {
-		stasis_publish(ast_cel_topic(), message);
-	}
-	ao2_cleanup(message);
-	ast_json_unref(cel_blob);
+	return do_reload(1);
 }
 
-struct stasis_topic *ast_cel_topic(void)
-{
-	return cel_topic;
-}
-
-struct ast_cel_general_config *ast_cel_get_config(void)
-{
-	RAII_VAR(struct cel_config *, mod_cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
-
-	if (!mod_cfg || !mod_cfg->general) {
-		return NULL;
-	}
-
-	ao2_ref(mod_cfg->general, +1);
-	return mod_cfg->general;
-}
-
-void ast_cel_set_config(struct ast_cel_general_config *config)
-{
-	int was_enabled;
-	int is_enabled;
-	struct ast_cel_general_config *cleanup_config;
-	struct cel_config *mod_cfg = ao2_global_obj_ref(cel_configs);
-
-	if (mod_cfg) {
-		was_enabled = ast_cel_check_enabled();
-
-		cleanup_config = mod_cfg->general;
-		ao2_bump(config);
-		mod_cfg->general = config;
-		ao2_cleanup(cleanup_config);
-
-		is_enabled = ast_cel_check_enabled();
-		if (!was_enabled && is_enabled) {
-			create_routes();
-		} else if (was_enabled && !is_enabled) {
-			destroy_routes();
-		}
-
-		ao2_ref(mod_cfg, -1);
-	}
-}
-
-int ast_cel_backend_unregister(const char *name)
-{
-	struct ao2_container *backends = ao2_global_obj_ref(cel_backends);
-
-	if (backends) {
-		ao2_find(backends, name, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
-		ao2_ref(backends, -1);
-	}
-
-	return 0;
-}
-
-int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
-{
-	RAII_VAR(struct ao2_container *, backends, ao2_global_obj_ref(cel_backends), ao2_cleanup);
-	struct cel_backend *backend;
-
-	if (!backends || ast_strlen_zero(name) || !backend_callback) {
-		return -1;
-	}
-
-	/* The backend object is immutable so it doesn't need a lock of its own. */
-	backend = ao2_alloc_options(sizeof(*backend) + 1 + strlen(name), NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!backend) {
-		return -1;
-	}
-	strcpy(backend->name, name);/* Safe */
-	backend->callback = backend_callback;
-
-	ao2_link(backends, backend);
-	ao2_ref(backend, -1);
-	return 0;
-}
diff --git a/main/channel.c b/main/channel.c
index 9153491..ef50e94 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
 #include "asterisk/cli.h"
 #include "asterisk/translate.h"
 #include "asterisk/manager.h"
+#include "asterisk/cel.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"
@@ -72,9 +73,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
 #include "asterisk/data.h"
 #include "asterisk/channel_internal.h"
 #include "asterisk/features.h"
-#include "asterisk/bridge.h"
 #include "asterisk/test.h"
-#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
  ***/
@@ -103,6 +102,7 @@ struct ast_epoll_data {
 /*! \brief Prevent new channel allocation if shutting down. */
 static int shutting_down;
 
+static int uniqueint;
 static int chancount;
 
 unsigned long global_fin, global_fout;
@@ -114,8 +114,6 @@ AST_THREADSTORAGE(state2str_threadbuf);
  *  100ms */
 #define AST_DEFAULT_EMULATE_DTMF_DURATION 100
 
-#define DEFAULT_AMA_FLAGS AST_AMA_DOCUMENTATION
-
 /*! Minimum amount of time between the end of the last digit and the beginning
  *  of a new one - 45ms */
 #define AST_MIN_DTMF_GAP 45
@@ -126,6 +124,22 @@ struct chanlist {
 	AST_LIST_ENTRY(chanlist) list;
 };
 
+#ifdef CHANNEL_TRACE
+/*! \brief Structure to hold channel context backtrace data */
+struct ast_chan_trace_data {
+	int enabled;
+	AST_LIST_HEAD_NOLOCK(, ast_chan_trace) trace;
+};
+
+/*! \brief Structure to save contexts where an ast_chan has been into */
+struct ast_chan_trace {
+	char context[AST_MAX_CONTEXT];
+	char exten[AST_MAX_EXTENSION];
+	int priority;
+	AST_LIST_ENTRY(ast_chan_trace) entry;
+};
+#endif
+
 /*! \brief the list of registered channel types */
 static AST_RWLIST_HEAD_STATIC(backends, chanlist);
 
@@ -342,7 +356,7 @@ static char *complete_channeltypes(struct ast_cli_args *a)
 static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct chanlist *cl = NULL;
-	struct ast_str *codec_buf = ast_str_alloca(256);
+	char buf[512];
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -387,7 +401,7 @@ static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd,
 		(cl->tech->devicestate) ? "yes" : "no",
 		(cl->tech->indicate) ? "yes" : "no",
 		(cl->tech->transfer) ? "yes" : "no",
-		ast_format_cap_get_names(cl->tech->capabilities, &codec_buf),
+		ast_getformatname_multiple(buf, sizeof(buf), cl->tech->capabilities),
 		(cl->tech->send_digit_begin) ? "yes" : "no",
 		(cl->tech->send_digit_end) ? "yes" : "no",
 		(cl->tech->send_html) ? "yes" : "no",
@@ -455,6 +469,132 @@ const struct ast_channel_tech ast_kill_tech = {
 	.hangup = kill_hangup,
 };
 
+#ifdef CHANNEL_TRACE
+/*! \brief Destructor for the channel trace datastore */
+static void ast_chan_trace_destroy_cb(void *data)
+{
+	struct ast_chan_trace *trace;
+	struct ast_chan_trace_data *traced = data;
+	while ((trace = AST_LIST_REMOVE_HEAD(&traced->trace, entry))) {
+		ast_free(trace);
+	}
+	ast_free(traced);
+}
+
+/*! \brief Datastore to put the linked list of ast_chan_trace and trace status */
+static const struct ast_datastore_info ast_chan_trace_datastore_info = {
+	.type = "ChanTrace",
+	.destroy = ast_chan_trace_destroy_cb
+};
+
+/*! \brief Put the channel backtrace in a string */
+int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **buf)
+{
+	int total = 0;
+	struct ast_chan_trace *trace;
+	struct ast_chan_trace_data *traced;
+	struct ast_datastore *store;
+
+	ast_channel_lock(chan);
+	store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
+	if (!store) {
+		ast_channel_unlock(chan);
+		return total;
+	}
+	traced = store->data;
+	ast_str_reset(*buf);
+	AST_LIST_TRAVERSE(&traced->trace, trace, entry) {
+		if (ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, trace->context, trace->exten, trace->priority) < 0) {
+			ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
+			total = -1;
+			break;
+		}
+		total++;
+	}
+	ast_channel_unlock(chan);
+	return total;
+}
+
+/* !\brief Whether or not context tracing is enabled */
+int ast_channel_trace_is_enabled(struct ast_channel *chan)
+{
+	struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
+	if (!store)
+		return 0;
+	return ((struct ast_chan_trace_data *)store->data)->enabled;
+}
+
+/*! \brief Update the context backtrace data if tracing is enabled */
+static int ast_channel_trace_data_update(struct ast_channel *chan, struct ast_chan_trace_data *traced)
+{
+	struct ast_chan_trace *trace;
+	if (!traced->enabled)
+		return 0;
+	/* If the last saved context does not match the current one
+	   OR we have not saved any context so far, then save the current context */
+	if ((!AST_LIST_EMPTY(&traced->trace) && strcasecmp(AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan))) ||
+	    (AST_LIST_EMPTY(&traced->trace))) {
+		/* Just do some debug logging */
+		if (AST_LIST_EMPTY(&traced->trace))
+			ast_debug(1, "Setting initial trace context to %s\n", ast_channel_context(chan));
+		else
+			ast_debug(1, "Changing trace context from %s to %s\n", AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan));
+		/* alloc or bail out */
+		trace = ast_malloc(sizeof(*trace));
+		if (!trace)
+			return -1;
+		/* save the current location and store it in the trace list */
+		ast_copy_string(trace->context, ast_channel_context(chan), sizeof(trace->context));
+		ast_copy_string(trace->exten, ast_channel_exten(chan), sizeof(trace->exten));
+		trace->priority = ast_channel_priority(chan);
+		AST_LIST_INSERT_HEAD(&traced->trace, trace, entry);
+	}
+	return 0;
+}
+
+/*! \brief Update the context backtrace if tracing is enabled */
+int ast_channel_trace_update(struct ast_channel *chan)
+{
+	struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
+	if (!store)
+		return 0;
+	return ast_channel_trace_data_update(chan, store->data);
+}
+
+/*! \brief Enable context tracing in the channel */
+int ast_channel_trace_enable(struct ast_channel *chan)
+{
+	struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
+	struct ast_chan_trace_data *traced;
+	if (!store) {
+		store = ast_datastore_alloc(&ast_chan_trace_datastore_info, "ChanTrace");
+		if (!store)
+			return -1;
+		traced = ast_calloc(1, sizeof(*traced));
+		if (!traced) {
+			ast_datastore_free(store);
+			return -1;
+		}
+		store->data = traced;
+		AST_LIST_HEAD_INIT_NOLOCK(&traced->trace);
+		ast_channel_datastore_add(chan, store);
+	}
+	((struct ast_chan_trace_data *)store->data)->enabled = 1;
+	ast_channel_trace_data_update(chan, store->data);
+	return 0;
+}
+
+/*! \brief Disable context tracing in the channel */
+int ast_channel_trace_disable(struct ast_channel *chan)
+{
+	struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
+	if (!store)
+		return 0;
+	((struct ast_chan_trace_data *)store->data)->enabled = 0;
+	return 0;
+}
+#endif /* CHANNEL_TRACE */
+
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
 {
@@ -675,43 +815,8 @@ int ast_str2cause(const char *name)
 	return -1;
 }
 
-static struct stasis_message *create_channel_snapshot_message(struct ast_channel *channel)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (!ast_channel_snapshot_type()) {
-		return NULL;
-	}
-
-	ast_channel_lock(channel);
-	snapshot = ast_channel_snapshot_create(channel);
-	ast_channel_unlock(channel);
-	if (!snapshot) {
-		return NULL;
-	}
-
-	return stasis_message_create(ast_channel_snapshot_type(), snapshot);
-}
-
-static void publish_cache_clear(struct ast_channel *chan)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup);
-
-	clear_msg = create_channel_snapshot_message(chan);
-	if (!clear_msg) {
-		return;
-	}
-
-	message = stasis_cache_clear_create(clear_msg);
-	stasis_publish(ast_channel_topic(chan), message);
-}
-
 /*! \brief Gives the string form of a given channel state.
- *
- * \note This function is not reentrant.
- *
- * \param state
+	\note This function is not reentrant.
  */
 const char *ast_state2str(enum ast_channel_state state)
 {
@@ -738,8 +843,6 @@ const char *ast_state2str(enum ast_channel_state state)
 		return "Dialing Offhook";
 	case AST_STATE_PRERING:
 		return "Pre-ring";
-	case AST_STATE_MUTE:
-		return "Mute";
 	default:
 		if (!(buf = ast_threadstorage_get(&state2str_threadbuf, STATE2STR_BUFSIZE)))
 			return "Unknown";
@@ -769,15 +872,75 @@ char *ast_transfercapability2str(int transfercapability)
 	}
 }
 
-/*! \brief Channel technology used to extract a channel from a running application. The
- * channel created with this technology will be immediately hung up - most external
- * applications won't ever want to see this.
- */
-static const struct ast_channel_tech surrogate_tech = {
-	.type = "Surrogate",
-	.description = "Surrogate channel used to pull channel from an application",
-	.properties = AST_CHAN_TP_INTERNAL,
-};
+/*! \brief Pick the best audio codec */
+struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format *result)
+{
+	/* This just our opinion, expressed in code.  We are asked to choose
+	   the best codec to use, given no information */
+	static const enum ast_format_id prefs[] =
+	{
+		/*! Okay, ulaw is used by all telephony equipment, so start with it */
+		AST_FORMAT_ULAW,
+		/*! Unless of course, you're a silly European, so then prefer ALAW */
+		AST_FORMAT_ALAW,
+		AST_FORMAT_G719,
+		AST_FORMAT_SIREN14,
+		AST_FORMAT_SIREN7,
+		AST_FORMAT_TESTLAW,
+		/*! G.722 is better then all below, but not as common as the above... so give ulaw and alaw priority */
+		AST_FORMAT_G722,
+		/*! Okay, well, signed linear is easy to translate into other stuff */
+		AST_FORMAT_SLINEAR192,
+		AST_FORMAT_SLINEAR96,
+		AST_FORMAT_SLINEAR48,
+		AST_FORMAT_SLINEAR44,
+		AST_FORMAT_SLINEAR32,
+		AST_FORMAT_SLINEAR24,
+		AST_FORMAT_SLINEAR16,
+		AST_FORMAT_SLINEAR12,
+		AST_FORMAT_SLINEAR,
+		/*! G.726 is standard ADPCM, in RFC3551 packing order */
+		AST_FORMAT_G726,
+		/*! G.726 is standard ADPCM, in AAL2 packing order */
+		AST_FORMAT_G726_AAL2,
+		/*! ADPCM has great sound quality and is still pretty easy to translate */
+		AST_FORMAT_ADPCM,
+		/*! Okay, we're down to vocoders now, so pick GSM because it's small and easier to
+		    translate and sounds pretty good */
+		AST_FORMAT_GSM,
+		/*! iLBC is not too bad */
+		AST_FORMAT_ILBC,
+		/*! Speex is free, but computationally more expensive than GSM */
+		AST_FORMAT_SPEEX32,
+		AST_FORMAT_SPEEX16,
+		AST_FORMAT_SPEEX,
+		/*! SILK is pretty awesome. */
+		AST_FORMAT_SILK,
+		/*! CELT supports crazy high sample rates */
+		AST_FORMAT_CELT,
+		/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
+		    to use it */
+		AST_FORMAT_LPC10,
+		/*! G.729a is faster than 723 and slightly less expensive */
+		AST_FORMAT_G729A,
+		/*! Down to G.723.1 which is proprietary but at least designed for voice */
+		AST_FORMAT_G723_1,
+	};
+	char buf[512];
+	int x;
+
+	/* Find the first preferred codec in the format given */
+	for (x = 0; x < ARRAY_LEN(prefs); x++) {
+		if (ast_format_cap_best_byid(cap, prefs[x], result)) {
+			return result;
+		}
+	}
+
+	ast_format_clear(result);
+	ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
+
+	return NULL;
+}
 
 static const struct ast_channel_tech null_tech = {
 	.type = "NULL",
@@ -788,11 +951,10 @@ static void ast_channel_destructor(void *obj);
 static void ast_dummy_channel_destructor(void *obj);
 
 /*! \brief Create a new channel structure */
-static struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 0)))
+static struct ast_channel * attribute_malloc __attribute__((format(printf, 13, 0)))
 __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char *cid_name,
-		       const char *acctcode, const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
-		       const struct ast_channel *requestor, enum ama_flags amaflag, struct ast_endpoint *endpoint,
-		       const char *file, int line,
+		       const char *acctcode, const char *exten, const char *context,
+		       const char *linkedid, const int amaflag, const char *file, int line,
 		       const char *function, const char *name_fmt, va_list ap)
 {
 	struct ast_channel *tmp;
@@ -802,7 +964,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	struct ast_sched_context *schedctx;
 	struct ast_timer *timer;
 	struct timeval now;
-	const struct ast_channel_tech *channel_tech;
 
 	/* If shutting down, don't allocate any new channels */
 	if (ast_shutting_down()) {
@@ -810,25 +971,16 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 		return NULL;
 	}
 
-	if (!(tmp = ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor))) {
+	if (!(tmp = ast_channel_internal_alloc(ast_channel_destructor))) {
 		/* Channel structure allocation failure. */
 		return NULL;
 	}
-
-	ast_channel_stage_snapshot(tmp);
-
-	if (!(nativeformats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(nativeformats = ast_format_cap_alloc())) {
+		ao2_ref(tmp, -1);
 		/* format capabilities structure allocation failure */
-		return ast_channel_unref(tmp);
+		return NULL;
 	}
-	ast_format_cap_append(nativeformats, ast_format_none, 0);
 	ast_channel_nativeformats_set(tmp, nativeformats);
-	ao2_ref(nativeformats, -1);
-
-	ast_channel_set_rawwriteformat(tmp, ast_format_none);
-	ast_channel_set_rawreadformat(tmp, ast_format_none);
-	ast_channel_set_writeformat(tmp, ast_format_none);
-	ast_channel_set_readformat(tmp, ast_format_none);
 
 	/*
 	 * Init file descriptors to unopened state so
@@ -851,7 +1003,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	ast_party_dialed_init(ast_channel_dialed(tmp));
 	ast_party_caller_init(ast_channel_caller(tmp));
 	ast_party_connected_line_init(ast_channel_connected(tmp));
-	ast_party_connected_line_init(ast_channel_connected_indicated(tmp));
 	ast_party_redirecting_init(ast_channel_redirecting(tmp));
 
 	if (cid_name) {
@@ -877,6 +1028,14 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 		ast_channel_timingfd_set(tmp, ast_timer_fd(ast_channel_timer(tmp)));
 	}
 
+	/*
+	 * This is the last place the channel constructor can fail.
+	 *
+	 * The destructor takes advantage of this fact to ensure that the
+	 * AST_CEL_CHANNEL_END is not posted if we have not posted the
+	 * AST_CEL_CHANNEL_START yet.
+	 */
+
 	if (needqueue && ast_channel_internal_alertpipe_init(tmp)) {
 		return ast_channel_unref(tmp);
 	}
@@ -888,7 +1047,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 
 	/* Initial state */
 	ast_channel_state_set(tmp, state);
-	ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
 
 	ast_channel_streamid_set(tmp, -1);
 
@@ -898,7 +1056,19 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	now = ast_tvnow();
 	ast_channel_creationtime_set(tmp, &now);
 
-	ast_channel_internal_setup_topics(tmp);
+	if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
+		ast_channel_uniqueid_build(tmp, "%li.%d", (long) time(NULL),
+			ast_atomic_fetchadd_int(&uniqueint, 1));
+	} else {
+		ast_channel_uniqueid_build(tmp, "%s-%li.%d", ast_config_AST_SYSTEM_NAME,
+			(long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
+	}
+
+	if (!ast_strlen_zero(linkedid)) {
+		ast_channel_linkedid_set(tmp, linkedid);
+	} else {
+		ast_channel_linkedid_set(tmp, ast_channel_uniqueid(tmp));
+	}
 
 	if (!ast_strlen_zero(name_fmt)) {
 		char *slash, *slash2;
@@ -926,66 +1096,90 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 		ast_channel_name_set(tmp, "-**Unknown**");
 	}
 
-	if (amaflag != AST_AMA_NONE) {
+	/* Reminder for the future: under what conditions do we NOT want to track cdrs on channels? */
+
+	/* These 4 variables need to be set up for the cdr_init() to work right */
+	if (amaflag) {
 		ast_channel_amaflags_set(tmp, amaflag);
 	} else {
-		ast_channel_amaflags_set(tmp, DEFAULT_AMA_FLAGS);
+		ast_channel_amaflags_set(tmp, ast_default_amaflags);
 	}
 
-	if (!ast_strlen_zero(acctcode)) {
+	if (!ast_strlen_zero(acctcode))
 		ast_channel_accountcode_set(tmp, acctcode);
-	}
-	ast_channel_language_set(tmp, ast_defaultlanguage);
+	else
+		ast_channel_accountcode_set(tmp, ast_default_accountcode);
 
 	ast_channel_context_set(tmp, S_OR(context, "default"));
 	ast_channel_exten_set(tmp, S_OR(exten, "s"));
 	ast_channel_priority_set(tmp, 1);
 
+	ast_channel_cdr_set(tmp, ast_cdr_alloc());
+	ast_cdr_init(ast_channel_cdr(tmp), tmp);
+	ast_cdr_start(ast_channel_cdr(tmp));
+
+	ast_atomic_fetchadd_int(&chancount, +1);
+	ast_cel_report_event(tmp, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
+
 	headp = ast_channel_varshead(tmp);
 	AST_LIST_HEAD_INIT_NOLOCK(headp);
 
 	ast_pbx_hangup_handler_init(tmp);
 	AST_LIST_HEAD_INIT_NOLOCK(ast_channel_datastores(tmp));
-	AST_LIST_HEAD_INIT_NOLOCK(ast_channel_autochans(tmp));
-
-	channel_tech = ast_get_channel_tech(tech);
-	if (!channel_tech && !ast_strlen_zero(tech2)) {
-		channel_tech = ast_get_channel_tech(tech2);
-	}
-	if (channel_tech) {
-		ast_channel_tech_set(tmp, channel_tech);
-	} else {
-		ast_channel_tech_set(tmp, &null_tech);
-	}
 
-	ast_channel_internal_finalize(tmp);
+	AST_LIST_HEAD_INIT_NOLOCK(ast_channel_autochans(tmp));
 
-	ast_atomic_fetchadd_int(&chancount, +1);
+	ast_channel_language_set(tmp, ast_defaultlanguage);
 
-	/* You might scream "locking inversion" at seeing this but it is actually perfectly fine.
-	 * Since the channel was just created nothing can know about it yet or even acquire it.
-	 */
-	ast_channel_lock(tmp);
+	ast_channel_tech_set(tmp, &null_tech);
 
 	ao2_link(channels, tmp);
 
-	if (endpoint) {
-		ast_endpoint_add_channel(endpoint, tmp);
-	}
-
 	/*
-	 * And now, since the channel structure is built, and has its name, let
-	 * the world know of its existance
+	 * And now, since the channel structure is built, and has its name, let's
+	 * call the manager event generator with this Newchannel event. This is the
+	 * proper and correct place to make this call, but you sure do have to pass
+	 * a lot of data into this func to do it here!
 	 */
-	ast_channel_stage_snapshot_done(tmp);
+	if (ast_get_channel_tech(tech) || (tech2 && ast_get_channel_tech(tech2))) {
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a new channel is created.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newstate']/managerEventInstance/syntax/parameter[@name='ChannelState'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newstate']/managerEventInstance/syntax/parameter[@name='ChannelStateDesc'])" />
+				</syntax>
+			</managerEventInstance>
+		***/
+		ast_manager_event(tmp, EVENT_FLAG_CALL, "Newchannel",
+			"Channel: %s\r\n"
+			"ChannelState: %d\r\n"
+			"ChannelStateDesc: %s\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"AccountCode: %s\r\n"
+			"Exten: %s\r\n"
+			"Context: %s\r\n"
+			"Uniqueid: %s\r\n",
+			ast_channel_name(tmp),
+			state,
+			ast_state2str(state),
+			S_OR(cid_num, ""),
+			S_OR(cid_name, ""),
+			ast_channel_accountcode(tmp),
+			S_OR(exten, ""),
+			S_OR(context, ""),
+			ast_channel_uniqueid(tmp));
+	}
+
+	ast_channel_internal_finalize(tmp);
 	return tmp;
 }
 
 struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *cid_num,
 					const char *cid_name, const char *acctcode,
-					const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
-					const struct ast_channel *requestor, enum ama_flags amaflag,
-					struct ast_endpoint *endpoint,
+					const char *exten, const char *context,
+					const char *linkedid, const int amaflag,
 					const char *file, int line, const char *function,
 					const char *name_fmt, ...)
 {
@@ -994,7 +1188,7 @@ struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *ci
 
 	va_start(ap, name_fmt);
 	result = __ast_channel_alloc_ap(needqueue, state, cid_num, cid_name, acctcode, exten, context,
-					assignedids, requestor, amaflag, endpoint, file, line, function, name_fmt, ap);
+					linkedid, amaflag, file, line, function, name_fmt, ap);
 	va_end(ap);
 
 	return result;
@@ -1011,7 +1205,7 @@ struct ast_channel *ast_dummy_channel_alloc(void)
 	struct ast_channel *tmp;
 	struct varshead *headp;
 
-	if (!(tmp = ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL))) {
+	if (!(tmp = ast_channel_internal_alloc(ast_dummy_channel_destructor))) {
 		/* Dummy channel structure allocation failure. */
 		return NULL;
 	}
@@ -1031,10 +1225,6 @@ struct ast_channel *ast_dummy_channel_alloc(void)
 	ast_channel_epfd_set(tmp, -1);
 #endif
 
-	ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
-
-	ast_channel_internal_setup_topics(tmp);
-
 	headp = ast_channel_varshead(tmp);
 	AST_LIST_HEAD_INIT_NOLOCK(headp);
 
@@ -1177,7 +1367,16 @@ int ast_queue_hangup(struct ast_channel *chan)
 	/* Yeah, let's not change a lock-critical value without locking */
 	ast_channel_lock(chan);
 	ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV);
-	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), NULL);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a hangup is requested with no set cause.</synopsis>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "HangupRequest",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan));
 
 	res = ast_queue_frame(chan, &f);
 	ast_channel_unlock(chan);
@@ -1187,7 +1386,6 @@ int ast_queue_hangup(struct ast_channel *chan)
 /*! \brief Queue a hangup frame for channel */
 int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
 	int res;
 
@@ -1201,48 +1399,27 @@ int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
 	if (cause < 0) {
 		f.data.uint32 = ast_channel_hangupcause(chan);
 	}
-	blob = ast_json_pack("{s: i}",
-			     "cause", cause);
-	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), blob);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a hangup is requested with a specific cause code.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
+				</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "HangupRequest",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Cause: %d\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		cause);
 
 	res = ast_queue_frame(chan, &f);
 	ast_channel_unlock(chan);
 	return res;
 }
 
-int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
-	int res;
-
-	if (!ast_strlen_zero(musicclass)) {
-		f.data.ptr = (void *) musicclass;
-		f.datalen = strlen(musicclass) + 1;
-
-		blob = ast_json_pack("{s: s}",
-				     "musicclass", musicclass);
-	}
-
-	ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);
-
-	res = ast_queue_frame(chan, &f);
-
-	return res;
-}
-
-int ast_queue_unhold(struct ast_channel *chan)
-{
-	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
-	int res;
-
-	ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);
-
-	res = ast_queue_frame(chan, &f);
-
-	return res;
-}
-
 /*! \brief Queue a control frame */
 int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
 {
@@ -1473,8 +1650,6 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
 	 * be queued up or not.
 	 */
 	switch (frame->frametype) {
-	case AST_FRAME_BRIDGE_ACTION:
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
 	case AST_FRAME_CONTROL:
 	case AST_FRAME_TEXT:
 	case AST_FRAME_IMAGE:
@@ -2066,49 +2241,6 @@ void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
 	ast_party_id_free(&doomed->priv);
 }
 
-void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init)
-{
-	init->str = NULL;
-	init->code = AST_REDIRECTING_REASON_UNKNOWN;
-}
-
-void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
-{
-	if (dest == src) {
-		return;
-	}
-
-	ast_free(dest->str);
-	dest->str = ast_strdup(src->str);
-	dest->code = src->code;
-}
-
-void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init, const struct ast_party_redirecting_reason *guide)
-{
-	init->str = NULL;
-	init->code = guide->code;
-}
-
-void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
-{
-	if (dest == src) {
-		return;
-	}
-
-	if (src->str && src->str != dest->str) {
-		ast_free(dest->str);
-		dest->str = ast_strdup(src->str);
-	}
-
-	dest->code = src->code;
-}
-
-void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed)
-{
-	ast_free(doomed->str);
-}
-
-
 void ast_party_redirecting_init(struct ast_party_redirecting *init)
 {
 	ast_party_id_init(&init->orig);
@@ -2117,9 +2249,9 @@ void ast_party_redirecting_init(struct ast_party_redirecting *init)
 	ast_party_id_init(&init->priv_orig);
 	ast_party_id_init(&init->priv_from);
 	ast_party_id_init(&init->priv_to);
-	ast_party_redirecting_reason_init(&init->reason);
-	ast_party_redirecting_reason_init(&init->orig_reason);
 	init->count = 0;
+	init->reason = AST_REDIRECTING_REASON_UNKNOWN;
+	init->orig_reason = AST_REDIRECTING_REASON_UNKNOWN;
 }
 
 void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
@@ -2135,9 +2267,9 @@ void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct
 	ast_party_id_copy(&dest->priv_orig, &src->priv_orig);
 	ast_party_id_copy(&dest->priv_from, &src->priv_from);
 	ast_party_id_copy(&dest->priv_to, &src->priv_to);
-	ast_party_redirecting_reason_copy(&dest->reason, &src->reason);
-	ast_party_redirecting_reason_copy(&dest->orig_reason, &src->orig_reason);
 	dest->count = src->count;
+	dest->reason = src->reason;
+	dest->orig_reason = src->orig_reason;
 }
 
 void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
@@ -2148,9 +2280,9 @@ void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const st
 	ast_party_id_set_init(&init->priv_orig, &guide->priv_orig);
 	ast_party_id_set_init(&init->priv_from, &guide->priv_from);
 	ast_party_id_set_init(&init->priv_to, &guide->priv_to);
-	ast_party_redirecting_reason_set_init(&init->reason, &guide->reason);
-	ast_party_redirecting_reason_set_init(&init->orig_reason, &guide->orig_reason);
 	init->count = guide->count;
+	init->reason = guide->reason;
+	init->orig_reason = guide->orig_reason;
 }
 
 void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src, const struct ast_set_party_redirecting *update)
@@ -2161,9 +2293,9 @@ void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct
 	ast_party_id_set(&dest->priv_orig, &src->priv_orig, update ? &update->priv_orig : NULL);
 	ast_party_id_set(&dest->priv_from, &src->priv_from, update ? &update->priv_from : NULL);
 	ast_party_id_set(&dest->priv_to, &src->priv_to, update ? &update->priv_to : NULL);
-	ast_party_redirecting_reason_set(&dest->reason, &src->reason);
-	ast_party_redirecting_reason_set(&dest->orig_reason, &src->orig_reason);
 	dest->count = src->count;
+	dest->reason = src->reason;
+	dest->orig_reason = src->orig_reason;
 }
 
 void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
@@ -2174,8 +2306,6 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
 	ast_party_id_free(&doomed->priv_orig);
 	ast_party_id_free(&doomed->priv_from);
 	ast_party_id_free(&doomed->priv_to);
-	ast_party_redirecting_reason_free(&doomed->reason);
-	ast_party_redirecting_reason_free(&doomed->orig_reason);
 }
 
 /*! \brief Free a channel structure */
@@ -2192,31 +2322,13 @@ static void ast_channel_destructor(void *obj)
 	char device_name[AST_CHANNEL_NAME];
 	struct ast_callid *callid;
 
-	/* Stop monitoring */
-	if (ast_channel_monitor(chan)) {
-		ast_channel_monitor(chan)->stop(chan, 0);
-	}
-
-	/* If there is native format music-on-hold state, free it */
-	if (ast_channel_music_state(chan)) {
-		ast_moh_cleanup(chan);
+	if (ast_channel_internal_is_finalized(chan)) {
+		ast_cel_report_event(chan, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
+		ast_cel_check_retire_linkedid(chan);
 	}
 
 	ast_pbx_hangup_handler_destroy(chan);
 
-	/* Things that may possibly raise Stasis messages shouldn't occur after this point */
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEAD);
-
-	if (ast_channel_internal_is_finalized(chan)) {
-		/* A channel snapshot should not be in the process of being staged now. */
-		ast_assert(!ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE));
-
-		ast_channel_lock(chan);
-		ast_channel_publish_snapshot(chan);
-		ast_channel_unlock(chan);
-		publish_cache_clear(chan);
-	}
-
 	ast_channel_lock(chan);
 
 	/* Get rid of each of the data stores on the channel */
@@ -2255,6 +2367,14 @@ static void ast_channel_destructor(void *obj)
 		device_name[0] = '\0';
 	}
 
+	/* Stop monitoring */
+	if (ast_channel_monitor(chan))
+		ast_channel_monitor(chan)->stop( chan, 0 );
+
+	/* If there is native format music-on-hold state, free it */
+	if (ast_channel_music_state(chan))
+		ast_moh_cleanup(chan);
+
 	/* Free translators */
 	if (ast_channel_readtrans(chan))
 		ast_translator_free_path(ast_channel_readtrans(chan));
@@ -2263,17 +2383,9 @@ static void ast_channel_destructor(void *obj)
 	if (ast_channel_pbx(chan))
 		ast_log_callid(LOG_WARNING, callid, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan));
 
-	/* Free formats */
-	ast_channel_set_oldwriteformat(chan, NULL);
-	ast_channel_set_rawreadformat(chan, NULL);
-	ast_channel_set_rawwriteformat(chan, NULL);
-	ast_channel_set_readformat(chan, NULL);
-	ast_channel_set_writeformat(chan, NULL);
-
 	ast_party_dialed_free(ast_channel_dialed(chan));
 	ast_party_caller_free(ast_channel_caller(chan));
 	ast_party_connected_line_free(ast_channel_connected(chan));
-	ast_party_connected_line_free(ast_channel_connected_indicated(chan));
 	ast_party_redirecting_free(ast_channel_redirecting(chan));
 
 	/* Close pipes if appropriate */
@@ -2305,7 +2417,7 @@ static void ast_channel_destructor(void *obj)
 	ast_jb_destroy(chan);
 
 	if (ast_channel_cdr(chan)) {
-		ast_cdr_free(ast_channel_cdr(chan));
+		ast_cdr_discard(ast_channel_cdr(chan));
 		ast_channel_cdr_set(chan, NULL);
 	}
 
@@ -2326,7 +2438,7 @@ static void ast_channel_destructor(void *obj)
 		ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
 	}
 
-	ast_channel_nativeformats_set(chan, NULL);
+	ast_channel_nativeformats_set(chan, ast_format_cap_destroy(ast_channel_nativeformats(chan)));
 	if (callid) {
 		ast_callid_unref(callid);
 	}
@@ -2356,7 +2468,6 @@ static void ast_dummy_channel_destructor(void *obj)
 	ast_party_dialed_free(ast_channel_dialed(chan));
 	ast_party_caller_free(ast_channel_caller(chan));
 	ast_party_connected_line_free(ast_channel_connected(chan));
-	ast_party_connected_line_free(ast_channel_connected_indicated(chan));
 	ast_party_redirecting_free(ast_channel_redirecting(chan));
 
 	/* loop over the variables list, freeing all data and deleting list items */
@@ -2366,7 +2477,7 @@ static void ast_dummy_channel_destructor(void *obj)
 		ast_var_delete(vardata);
 
 	if (ast_channel_cdr(chan)) {
-		ast_cdr_free(ast_channel_cdr(chan));
+		ast_cdr_discard(ast_channel_cdr(chan));
 		ast_channel_cdr_set(chan, NULL);
 	}
 
@@ -2547,7 +2658,7 @@ void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
 /*! \brief Softly hangup a channel, don't lock */
 int ast_softhangup_nolock(struct ast_channel *chan, int cause)
 {
-	ast_debug(1, "Soft-Hanging (%#04x) up channel '%s'\n", (unsigned)cause, ast_channel_name(chan));
+	ast_debug(1, "Soft-Hanging up channel '%s'\n", ast_channel_name(chan));
 	/* Inform channel driver that we need to be hung up, if it cares */
 	ast_channel_softhangup_internal_flag_add(chan, cause);
 	ast_queue_frame(chan, &ast_null_frame);
@@ -2560,15 +2671,25 @@ int ast_softhangup_nolock(struct ast_channel *chan, int cause)
 /*! \brief Softly hangup a channel, lock */
 int ast_softhangup(struct ast_channel *chan, int cause)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	int res;
 
 	ast_channel_lock(chan);
 	res = ast_softhangup_nolock(chan, cause);
-	blob = ast_json_pack("{s: i, s: b}",
-			     "cause", cause,
-			     "soft", 1);
-	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), blob);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
+				</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "SoftHangupRequest",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Cause: %d\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		cause);
 	ast_channel_unlock(chan);
 
 	return res;
@@ -2576,24 +2697,35 @@ int ast_softhangup(struct ast_channel *chan, int cause)
 
 static void free_translation(struct ast_channel *clonechan)
 {
-	if (ast_channel_writetrans(clonechan)) {
+	if (ast_channel_writetrans(clonechan))
 		ast_translator_free_path(ast_channel_writetrans(clonechan));
-	}
-	if (ast_channel_readtrans(clonechan)) {
+	if (ast_channel_readtrans(clonechan))
 		ast_translator_free_path(ast_channel_readtrans(clonechan));
-	}
 	ast_channel_writetrans_set(clonechan, NULL);
 	ast_channel_readtrans_set(clonechan, NULL);
+	if (ast_format_cap_is_empty(ast_channel_nativeformats(clonechan))) {
+		ast_format_clear(ast_channel_rawwriteformat(clonechan));
+		ast_format_clear(ast_channel_rawreadformat(clonechan));
+	} else {
+		struct ast_format tmpfmt;
+		ast_best_codec(ast_channel_nativeformats(clonechan), &tmpfmt);
+		ast_format_copy(ast_channel_rawwriteformat(clonechan), &tmpfmt);
+		ast_format_copy(ast_channel_rawreadformat(clonechan), &tmpfmt);
+	}
 }
 
 void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
 {
-	RAII_VAR(struct ast_channel *, bridge, ast_channel_bridge_peer(chan), ast_channel_cleanup);
+	struct ast_channel *bridge;
 
 	ast_channel_lock(chan);
 	if (force || ast_strlen_zero(ast_channel_hangupsource(chan))) {
 		ast_channel_hangupsource_set(chan, source);
 	}
+	bridge = ast_bridged_channel(chan);
+	if (bridge) {
+		ast_channel_ref(bridge);
+	}
 	ast_channel_unlock(chan);
 
 	if (bridge) {
@@ -2602,23 +2734,10 @@ void ast_set_hangupsource(struct ast_channel *chan, const char *source, int forc
 			ast_channel_hangupsource_set(bridge, source);
 		}
 		ast_channel_unlock(bridge);
+		ast_channel_unref(bridge);
 	}
 }
 
-int ast_channel_has_audio_frame_or_monitor(struct ast_channel *chan)
-{
-	return ast_channel_monitor(chan)
-		|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
-		|| !ast_framehook_list_contains_no_active(ast_channel_framehooks(chan));
-}
-
-int ast_channel_has_hook_requiring_audio(struct ast_channel *chan)
-{
-	return ast_channel_monitor(chan)
-		|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
-		|| !ast_framehook_list_contains_no_active_of_type(ast_channel_framehooks(chan), AST_FRAME_VOICE);
-}
-
 static void destroy_hooks(struct ast_channel *chan)
 {
 	if (ast_channel_audiohooks(chan)) {
@@ -2630,19 +2749,38 @@ static void destroy_hooks(struct ast_channel *chan)
 }
 
 /*! \brief Hangup a channel */
-void ast_hangup(struct ast_channel *chan)
+int ast_hangup(struct ast_channel *chan)
 {
-	/* Be NULL safe for RAII_VAR() usage. */
-	if (!chan) {
-		return;
-	}
+	char extra_str[64]; /* used for cel logging below */
 
 	ast_autoservice_stop(chan);
 
 	ast_channel_lock(chan);
 
-	while (ast_channel_masq(chan) || ast_channel_masqr(chan))  {
-		CHANNEL_DEADLOCK_AVOIDANCE(chan);
+	/*
+	 * Do the masquerade if someone is setup to masquerade into us.
+	 *
+	 * NOTE: We must hold the channel lock after testing for a
+	 * pending masquerade and setting the channel as a zombie to
+	 * prevent __ast_channel_masquerade() from setting up a
+	 * masquerade with a dead channel.
+	 */
+	while (ast_channel_masq(chan)) {
+		ast_channel_unlock(chan);
+		ast_do_masquerade(chan);
+		ast_channel_lock(chan);
+	}
+
+	if (ast_channel_masqr(chan)) {
+		/*
+		 * This channel is one which will be masqueraded into something.
+		 * Mark it as a zombie already so ast_do_masquerade() will know
+		 * to free it later.
+		 */
+		ast_set_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE);
+		destroy_hooks(chan);
+		ast_channel_unlock(chan);
+		return 0;
 	}
 
 	/* Mark as a zombie so a masquerade cannot be setup on this channel. */
@@ -2689,6 +2827,9 @@ void ast_hangup(struct ast_channel *chan)
 	ast_channel_generatordata_set(chan, NULL);
 	ast_channel_generator_set(chan, NULL);
 
+	snprintf(extra_str, sizeof(extra_str), "%d,%s,%s", ast_channel_hangupcause(chan), ast_channel_hangupsource(chan), S_OR(pbx_builtin_getvar_helper(chan, "DIALSTATUS"), ""));
+	ast_cel_report_event(chan, AST_CEL_HANGUP, NULL, extra_str, NULL);
+
 	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) {
 		ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
 			"is blocked by thread %ld in procedure %s!  Expect a failure\n",
@@ -2704,14 +2845,58 @@ void ast_hangup(struct ast_channel *chan)
 	ast_channel_unlock(chan);
 
 	ast_cc_offer(chan);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel is hung up.</synopsis>
+				<syntax>
+					<parameter name="Cause">
+						<para>A numeric cause code for why the channel was hung up.</para>
+					</parameter>
+					<parameter name="Cause-txt">
+						<para>A description of why the channel was hung up.</para>
+					</parameter>
+				</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "Hangup",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"AccountCode: %s\r\n"
+		"Cause: %d\r\n"
+		"Cause-txt: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"),
+		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "<unknown>"),
+		ast_channel_accountcode(chan),
+		ast_channel_hangupcause(chan),
+		ast_cause2str(ast_channel_hangupcause(chan))
+		);
+
+	if (ast_channel_cdr(chan) && !ast_test_flag(ast_channel_cdr(chan), AST_CDR_FLAG_BRIDGED) &&
+		!ast_test_flag(ast_channel_cdr(chan), AST_CDR_FLAG_POST_DISABLED) &&
+		(ast_channel_cdr(chan)->disposition != AST_CDR_NULL || ast_test_flag(ast_channel_cdr(chan), AST_CDR_FLAG_DIALED))) {
+		ast_channel_lock(chan);
+		ast_cdr_end(ast_channel_cdr(chan));
+		ast_cdr_detach(ast_channel_cdr(chan));
+		ast_channel_cdr_set(chan, NULL);
+		ast_channel_unlock(chan);
+	}
 
 	ast_channel_unref(chan);
+
+	return 0;
 }
 
-int ast_raw_answer(struct ast_channel *chan)
+int ast_raw_answer(struct ast_channel *chan, int cdr_answer)
 {
 	int res = 0;
-	struct timeval answertime;
 
 	ast_channel_lock(chan);
 
@@ -2727,9 +2912,6 @@ int ast_raw_answer(struct ast_channel *chan)
 		return -1;
 	}
 
-	answertime = ast_tvnow();
-	ast_channel_answertime_set(chan, &answertime);
-
 	ast_channel_unlock(chan);
 
 	switch (ast_channel_state(chan)) {
@@ -2740,9 +2922,20 @@ int ast_raw_answer(struct ast_channel *chan)
 			res = ast_channel_tech(chan)->answer(chan);
 		}
 		ast_setstate(chan, AST_STATE_UP);
+		if (cdr_answer) {
+			ast_cdr_answer(ast_channel_cdr(chan));
+		}
+		ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
 		ast_channel_unlock(chan);
 		break;
 	case AST_STATE_UP:
+		ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
+		/* Calling ast_cdr_answer when it it has previously been called
+		 * is essentially a no-op, so it is safe.
+		 */
+		if (cdr_answer) {
+			ast_cdr_answer(ast_channel_cdr(chan));
+		}
 		break;
 	default:
 		break;
@@ -2753,13 +2946,13 @@ int ast_raw_answer(struct ast_channel *chan)
 	return res;
 }
 
-int __ast_answer(struct ast_channel *chan, unsigned int delay)
+int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer)
 {
 	int res = 0;
 	enum ast_channel_state old_state;
 
 	old_state = ast_channel_state(chan);
-	if ((res = ast_raw_answer(chan))) {
+	if ((res = ast_raw_answer(chan, cdr_answer))) {
 		return res;
 	}
 
@@ -2771,8 +2964,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 		 */
 		do {
 			AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
-			struct ast_frame *cur;
-			struct ast_frame *new_frame;
+			struct ast_frame *cur, *new;
 			int timeout_ms = MAX(delay, 500);
 			unsigned int done = 0;
 			struct timeval start;
@@ -2803,11 +2995,11 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 					break;
 				}
 
-				if ((new_frame = ast_frisolate(cur)) != cur) {
+				if ((new = ast_frisolate(cur)) != cur) {
 					ast_frfree(cur);
 				}
 
-				AST_LIST_INSERT_HEAD(&frames, new_frame, frame_list);
+				AST_LIST_INSERT_HEAD(&frames, new, frame_list);
 
 				/* if a specific delay period was requested, continue
 				 * until that delay has passed. don't stop just because
@@ -2817,7 +3009,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 					continue;
 				}
 
-				switch (new_frame->frametype) {
+				switch (new->frametype) {
 					/* all of these frametypes qualify as 'media' */
 				case AST_FRAME_VOICE:
 				case AST_FRAME_VIDEO:
@@ -2831,8 +3023,6 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 					break;
 				case AST_FRAME_CONTROL:
 				case AST_FRAME_IAX:
-				case AST_FRAME_BRIDGE_ACTION:
-				case AST_FRAME_BRIDGE_ACTION_SYNC:
 				case AST_FRAME_NULL:
 				case AST_FRAME_CNG:
 					break;
@@ -2843,14 +3033,14 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 				}
 			}
 
-			if (res == 0) {
-				ast_channel_lock(chan);
-				while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+			ast_channel_lock(chan);
+			while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+				if (res == 0) {
 					ast_queue_frame_head(chan, cur);
-					ast_frfree(cur);
 				}
-				ast_channel_unlock(chan);
+				ast_frfree(cur);
 			}
+			ast_channel_unlock(chan);
 		} while (0);
 		break;
 	default:
@@ -2862,36 +3052,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
 
 int ast_answer(struct ast_channel *chan)
 {
-	return __ast_answer(chan, 0);
-}
-
-inline int ast_auto_answer(struct ast_channel *chan)
-{
-	if (ast_channel_state(chan) == AST_STATE_UP) {
-		/* Already answered */
-		return 0;
-	}
-	return ast_answer(chan);
-}
-
-int ast_channel_get_duration(struct ast_channel *chan)
-{
-	ast_assert(NULL != chan);
-
-	if (ast_tvzero(ast_channel_creationtime(chan))) {
-		return 0;
-	}
-	return (ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(chan)) / 1000);
-}
-
-int ast_channel_get_up_time(struct ast_channel *chan)
-{
-	ast_assert(NULL != chan);
-
-	if (ast_tvzero(ast_channel_answertime(chan))) {
-		return 0;
-	}
-	return (ast_tvdiff_ms(ast_tvnow(), ast_channel_answertime(chan)) / 1000);
+	return __ast_answer(chan, 0, 1);
 }
 
 static void deactivate_generator_nolock(struct ast_channel *chan)
@@ -2944,11 +3105,10 @@ static int generator_force(const void *data)
 		generate = ast_channel_generator(chan)->generate;
 	ast_channel_unlock(chan);
 
-	if (!tmp || !generate) {
+	if (!tmp || !generate)
 		return 0;
-	}
 
-	res = generate(chan, tmp, 0, ast_format_get_sample_rate(ast_channel_writeformat(chan)) / 50);
+	res = generate(chan, tmp, 0, ast_format_rate(ast_channel_writeformat(chan)) / 50);
 
 	ast_channel_lock(chan);
 	if (ast_channel_generator(chan) && generate == ast_channel_generator(chan)->generate) {
@@ -3038,7 +3198,12 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		return NULL;
 	}
 
+	/* Perform any pending masquerades */
 	for (x = 0; x < n; x++) {
+		while (ast_channel_masq(c[x])) {
+			ast_do_masquerade(c[x]);
+		}
+
 		ast_channel_lock(c[x]);
 		if (!ast_tvzero(*ast_channel_whentohangup(c[x]))) {
 			if (ast_tvzero(whentohangup))
@@ -3178,6 +3343,12 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan,
 	struct ast_channel *winner = NULL;
 	struct ast_epoll_data *aed = NULL;
 
+
+	/* See if this channel needs to be masqueraded */
+	while (ast_channel_masq(chan)) {
+		ast_do_masquerade(chan);
+	}
+
 	ast_channel_lock(chan);
 	/* Figure out their timeout */
 	if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
@@ -3259,6 +3430,10 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i
 	struct ast_channel *winner = NULL;
 
 	for (i = 0; i < n; i++) {
+		while (ast_channel_masq(c[i])) {
+			ast_do_masquerade(c[i]);
+		}
+
 		ast_channel_lock(c[i]);
 		if (!ast_tvzero(*ast_channel_whentohangup(c[i]))) {
 			if (whentohangup == 0) {
@@ -3505,17 +3680,6 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
 					ast_frfree(f);
 					ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
 					return -1;
-				case AST_CONTROL_STREAM_STOP:
-				case AST_CONTROL_STREAM_SUSPEND:
-				case AST_CONTROL_STREAM_RESTART:
-				case AST_CONTROL_STREAM_REVERSE:
-				case AST_CONTROL_STREAM_FORWARD:
-					/* Fall-through and treat as if it were a DTMF signal. Items
-					 * that perform stream control will handle this. */
-					res = f->subclass.integer;
-					ast_frfree(f);
-					ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
-					return res;
 				case AST_CONTROL_PVT_CAUSE_CODE:
 				case AST_CONTROL_RINGING:
 				case AST_CONTROL_ANSWER:
@@ -3554,54 +3718,42 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
 	return 0; /* Time is up */
 }
 
-enum DtmfDirection {
-	DTMF_RECEIVED,
-	DTMF_SENT
-};
-
-static const char *dtmf_direction_to_string(enum DtmfDirection direction)
-{
-	switch (direction) {
-	case DTMF_RECEIVED:
-		return "Received";
-	case DTMF_SENT:
-		return "Sent";
-	}
-
-	return "?";
-}
-
-static void send_dtmf_begin_event(struct ast_channel *chan,
-	enum DtmfDirection direction, const char digit)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	char digit_str[] = { digit, '\0' };
-
-	blob = ast_json_pack("{ s: s, s: s }",
-		"digit", digit_str,
-		"direction", dtmf_direction_to_string(direction));
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_cached_blob(chan, ast_channel_dtmf_begin_type(), blob);
-}
-
-static void send_dtmf_end_event(struct ast_channel *chan,
-	enum DtmfDirection direction, const char digit, long duration_ms)
+static void send_dtmf_event(struct ast_channel *chan, const char *direction, const char digit, const char *begin, const char *end)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	char digit_str[] = { digit, '\0' };
-
-	blob = ast_json_pack("{ s: s, s: s, s: i }",
-		"digit", digit_str,
-		"direction", dtmf_direction_to_string(direction),
-		"duration_ms", duration_ms);
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_cached_blob(chan, ast_channel_dtmf_end_type(), blob);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a DTMF digit has started or ended on a channel.</synopsis>
+				<syntax>
+					<parameter name="Direction">
+						<enumlist>
+							<enum name="Received"/>
+							<enum name="Sent"/>
+						</enumlist>
+					</parameter>
+					<parameter name="Begin">
+						<enumlist>
+							<enum name="Yes"/>
+							<enum name="No"/>
+						</enumlist>
+					</parameter>
+					<parameter name="End">
+						<enumlist>
+							<enum name="Yes"/>
+							<enum name="No"/>
+						</enumlist>
+					</parameter>
+				</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_DTMF,
+			"DTMF",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"Digit: %c\r\n"
+			"Direction: %s\r\n"
+			"Begin: %s\r\n"
+			"End: %s\r\n",
+			ast_channel_name(chan), ast_channel_uniqueid(chan), digit, direction, begin, end);
 }
 
 static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)
@@ -3624,9 +3776,11 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram
 	 * We must generate frames in phase locked mode since
 	 * we have no internal timer available.
 	 */
-	if (ast_format_cmp(f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) {
+
+	if (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) {
 		float factor;
-		factor = ((float) ast_format_get_sample_rate(ast_channel_writeformat(chan))) / ((float) ast_format_get_sample_rate(f->subclass.format));
+
+		factor = ((float) ast_format_rate(ast_channel_writeformat(chan))) / ((float) ast_format_rate(&f->subclass.format));
 		samples = (int) (((float) f->samples) * factor);
 	} else {
 		samples = f->samples;
@@ -3725,6 +3879,13 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 	/* this function is very long so make sure there is only one return
 	 * point at the end (there are only two exceptions to this).
 	 */
+
+	if (ast_channel_masq(chan)) {
+		ast_do_masquerade(chan);
+		return &ast_null_frame;
+	}
+
+	/* if here, no masq has happened, lock the channel and proceed */
 	ast_channel_lock(chan);
 
 	/* Stop if we're a zombie or need a soft hangup */
@@ -3926,12 +4087,15 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 					ast_debug(1, "Ignoring answer on an inbound call!\n");
 					ast_frfree(f);
 					f = &ast_null_frame;
-				} else if (prestate == AST_STATE_UP && ast_channel_is_bridged(chan)) {
+				} else if (prestate == AST_STATE_UP && ast_bridged_channel(chan)) {
 					ast_debug(1, "Dropping duplicate answer!\n");
 					ast_frfree(f);
 					f = &ast_null_frame;
 				} else {
+					/* Answer the CDR */
 					ast_setstate(chan, AST_STATE_UP);
+					/* removed a call to ast_cdr_answer(chan->cdr) from here. */
+					ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
 				}
 			} else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
 				read_action_payload = f->data.ptr;
@@ -3960,7 +4124,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 			}
 			break;
 		case AST_FRAME_DTMF_END:
-			send_dtmf_end_event(chan, DTMF_RECEIVED, f->subclass.integer, f->len);
+			send_dtmf_event(chan, "Received", f->subclass.integer, "No", "Yes");
 			ast_log(LOG_DTMF, "DTMF end '%c' received on %s, duration %ld ms\n", f->subclass.integer, ast_channel_name(chan), f->len);
 			/* Queue it up if DTMF is deferred, or if DTMF emulation is forced. */
 			if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF) || ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF)) {
@@ -4046,7 +4210,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 			}
 			break;
 		case AST_FRAME_DTMF_BEGIN:
-			send_dtmf_begin_event(chan, DTMF_RECEIVED, f->subclass.integer);
+			send_dtmf_event(chan, "Received", f->subclass.integer, "Yes", "No");
 			ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass.integer, ast_channel_name(chan));
 			if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY | AST_FLAG_EMULATE_DTMF) ||
 			    (!ast_tvzero(*ast_channel_dtmf_tv(chan)) &&
@@ -4131,14 +4295,14 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 					ast_frfree(f);
 					f = &ast_null_frame;
 				}
-			} else if ((f->frametype == AST_FRAME_VOICE) && ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+			} else if ((f->frametype == AST_FRAME_VOICE) && !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &f->subclass.format)) {
 				/* This frame is not one of the current native formats -- drop it on the floor */
-				struct ast_str *codec_buf = ast_str_alloca(64);
+				char to[200];
 				ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
-					ast_channel_name(chan), ast_format_get_name(f->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf));
+					ast_channel_name(chan), ast_getformatname(&f->subclass.format), ast_getformatname_multiple(to, sizeof(to), ast_channel_nativeformats(chan)));
 				ast_frfree(f);
 				f = &ast_null_frame;
-			} else if ((f->frametype == AST_FRAME_VOICE)) {
+			} else if (f->frametype == AST_FRAME_VOICE) {
 				/* Send frame to audiohooks if present */
 				if (ast_channel_audiohooks(chan)) {
 					struct ast_frame *old_frame = f;
@@ -4151,9 +4315,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 #ifndef MONITOR_CONSTANT_DELAY
 					int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples;
 					if (jump >= 0) {
-						jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
-						                         ast_format_get_sample_rate(f->subclass.format),
-						                         ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+						jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), ast_format_rate(&f->subclass.format), ast_format_rate(&ast_channel_monitor(chan)->read_stream->fmt->format));
 						if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump, SEEK_FORCECUR) == -1) {
 							ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
 						}
@@ -4162,9 +4324,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 						ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples);
 					}
 #else
-					int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
-					                             ast_format_get_sample_rate(f->subclass.codec),
-					                             ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+					int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), ast_format_rate(f->subclass.codec), ast_format_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
 					if (jump - MONITOR_DELAY >= 0) {
 						if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
 							ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
@@ -4238,6 +4398,11 @@ done:
 	return f;
 }
 
+int ast_internal_timing_enabled(struct ast_channel *chan)
+{
+	return ast_channel_timingfd(chan) > -1;
+}
+
 struct ast_frame *ast_read(struct ast_channel *chan)
 {
 	return __ast_read(chan, 0);
@@ -4285,16 +4450,6 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
 	case AST_CONTROL_MCID:
 	case AST_CONTROL_UPDATE_RTP_PEER:
 	case AST_CONTROL_PVT_CAUSE_CODE:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
-	case AST_CONTROL_STREAM_STOP:
-	case AST_CONTROL_STREAM_SUSPEND:
-	case AST_CONTROL_STREAM_REVERSE:
-	case AST_CONTROL_STREAM_FORWARD:
-	case AST_CONTROL_STREAM_RESTART:
-	case AST_CONTROL_RECORD_CANCEL:
-	case AST_CONTROL_RECORD_STOP:
-	case AST_CONTROL_RECORD_SUSPEND:
-	case AST_CONTROL_RECORD_MUTE:
 		break;
 
 	case AST_CONTROL_INCOMPLETE:
@@ -4328,116 +4483,6 @@ void ast_channel_hangupcause_hash_set(struct ast_channel *chan, const struct ast
 	}
 }
 
-enum ama_flags ast_channel_string2amaflag(const char *flag)
-{
-	if (!strcasecmp(flag, "default"))
-		return DEFAULT_AMA_FLAGS;
-	if (!strcasecmp(flag, "omit"))
-		return AST_AMA_OMIT;
-	if (!strcasecmp(flag, "billing"))
-		return AST_AMA_BILLING;
-	if (!strcasecmp(flag, "documentation"))
-		return AST_AMA_DOCUMENTATION;
-	return AST_AMA_NONE;
-}
-
-const char *ast_channel_amaflags2string(enum ama_flags flag)
-{
-	switch (flag) {
-	case AST_AMA_OMIT:
-		return "OMIT";
-	case AST_AMA_BILLING:
-		return "BILLING";
-	case AST_AMA_DOCUMENTATION:
-		return "DOCUMENTATION";
-	default:
-		return "Unknown";
-	}
-}
-
-/*!
- * \internal
- * \brief Preprocess connected line update.
- * \since 12.0.0
- *
- * \param chan channel to change the indication
- * \param data pointer to payload data
- * \param datalen size of payload data
- *
- * \note This function assumes chan is locked.
- *
- * \retval 0 keep going.
- * \retval -1 quit now.
- */
-static int indicate_connected_line(struct ast_channel *chan, const void *data, size_t datalen)
-{
-	struct ast_party_connected_line *chan_connected = ast_channel_connected(chan);
-	struct ast_party_connected_line *chan_indicated = ast_channel_connected_indicated(chan);
-	struct ast_party_connected_line connected;
-	unsigned char current[1024];
-	unsigned char proposed[1024];
-	int current_size;
-	int proposed_size;
-	int res;
-
-	ast_party_connected_line_set_init(&connected, chan_connected);
-	res = ast_connected_line_parse_data(data, datalen, &connected);
-	if (!res) {
-		ast_channel_set_connected_line(chan, &connected, NULL);
-	}
-	ast_party_connected_line_free(&connected);
-	if (res) {
-		return -1;
-	}
-
-	current_size = ast_connected_line_build_data(current, sizeof(current),
-		chan_indicated, NULL);
-	proposed_size = ast_connected_line_build_data(proposed, sizeof(proposed),
-		chan_connected, NULL);
-	if (current_size == -1 || proposed_size == -1) {
-		return -1;
-	}
-
-	if (current_size == proposed_size && !memcmp(current, proposed, current_size)) {
-		ast_debug(1, "%s: Dropping redundant connected line update \"%s\" <%s>.\n",
-			ast_channel_name(chan),
-			S_COR(chan_connected->id.name.valid, chan_connected->id.name.str, ""),
-			S_COR(chan_connected->id.number.valid, chan_connected->id.number.str, ""));
-		return -1;
-	}
-
-	ast_party_connected_line_copy(chan_indicated, chan_connected);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Preprocess redirecting update.
- * \since 12.0.0
- *
- * \param chan channel to change the indication
- * \param data pointer to payload data
- * \param datalen size of payload data
- *
- * \note This function assumes chan is locked.
- *
- * \retval 0 keep going.
- * \retval -1 quit now.
- */
-static int indicate_redirecting(struct ast_channel *chan, const void *data, size_t datalen)
-{
-	struct ast_party_redirecting redirecting;
-	int res;
-
-	ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(chan));
-	res = ast_redirecting_parse_data(data, datalen, &redirecting);
-	if (!res) {
-		ast_channel_set_redirecting(chan, &redirecting, NULL);
-	}
-	ast_party_redirecting_free(&redirecting);
-	return res ? -1 : 0;
-}
-
 int ast_indicate_data(struct ast_channel *chan, int _condition,
 		const void *data, size_t datalen)
 {
@@ -4452,9 +4497,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 	ast_channel_lock(chan);
 
 	/* Don't bother if the channel is about to go away, anyway. */
-	if ((ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
-			|| ast_check_hangup(chan))
-		&& condition != AST_CONTROL_MASQUERADE_NOTIFY) {
+	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
 		res = -1;
 		goto indicate_cleanup;
 	}
@@ -4474,6 +4517,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 		/* who knows what we will get back! the anticipation is killing me. */
 		if (!(awesome_frame = ast_framehook_list_write_event(ast_channel_framehooks(chan), awesome_frame))
 			|| awesome_frame->frametype != AST_FRAME_CONTROL) {
+
 			res = 0;
 			goto indicate_cleanup;
 		}
@@ -4485,21 +4529,31 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 
 	switch (condition) {
 	case AST_CONTROL_CONNECTED_LINE:
-		if (indicate_connected_line(chan, data, datalen)) {
-			res = 0;
-			goto indicate_cleanup;
+		{
+			struct ast_party_connected_line connected;
+
+			ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
+			res = ast_connected_line_parse_data(data, datalen, &connected);
+			if (!res) {
+				ast_channel_set_connected_line(chan, &connected, NULL);
+			}
+			ast_party_connected_line_free(&connected);
 		}
 		break;
+
 	case AST_CONTROL_REDIRECTING:
-		if (indicate_redirecting(chan, data, datalen)) {
-			res = 0;
-			goto indicate_cleanup;
+		{
+			struct ast_party_redirecting redirecting;
+
+			ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(chan));
+			res = ast_redirecting_parse_data(data, datalen, &redirecting);
+			if (!res) {
+				ast_channel_set_redirecting(chan, &redirecting, NULL);
+			}
+			ast_party_redirecting_free(&redirecting);
 		}
 		break;
-	case AST_CONTROL_HOLD:
-	case AST_CONTROL_UNHOLD:
-		ast_channel_hold_state_set(chan, condition);
-		break;
+
 	default:
 		break;
 	}
@@ -4602,17 +4656,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 	case AST_CONTROL_AOC:
 	case AST_CONTROL_END_OF_Q:
 	case AST_CONTROL_MCID:
-	case AST_CONTROL_MASQUERADE_NOTIFY:
 	case AST_CONTROL_UPDATE_RTP_PEER:
-	case AST_CONTROL_STREAM_STOP:
-	case AST_CONTROL_STREAM_SUSPEND:
-	case AST_CONTROL_STREAM_REVERSE:
-	case AST_CONTROL_STREAM_FORWARD:
-	case AST_CONTROL_STREAM_RESTART:
-	case AST_CONTROL_RECORD_CANCEL:
-	case AST_CONTROL_RECORD_STOP:
-	case AST_CONTROL_RECORD_SUSPEND:
-	case AST_CONTROL_RECORD_MUTE:
 		/* Nothing left to do for these. */
 		res = 0;
 		break;
@@ -4701,7 +4745,7 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
 	}
 
 	CHECK_BLOCKING(chan);
-	if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) {
+	if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_TEXT))) {
 		struct ast_frame f;
 
 		f.frametype = AST_FRAME_TEXT;
@@ -4712,7 +4756,7 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
 		f.offset = 0;
 		f.seqno = 0;
 
-		f.subclass.format = ast_format_t140;
+		ast_format_set(&f.subclass.format, AST_FORMAT_T140, 0);
 		res = ast_channel_tech(chan)->write_text(chan, &f);
 	} else if (ast_channel_tech(chan)->send_text) {
 		res = ast_channel_tech(chan)->send_text(chan, text);
@@ -4809,7 +4853,7 @@ int ast_prod(struct ast_channel *chan)
 	/* Send an empty audio frame to get things moving */
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_debug(1, "Prodding channel '%s'\n", ast_channel_name(chan));
-		a.subclass.format = ast_channel_rawwriteformat(chan);
+		ast_format_copy(&a.subclass.format, ast_channel_rawwriteformat(chan));
 		a.data.ptr = nothing + AST_FRIENDLY_OFFSET;
 		a.src = "ast_prod"; /* this better match check in ast_write */
 		if (ast_write(chan, &a))
@@ -4952,6 +4996,17 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
 		goto done;
 
+	/* Handle any pending masquerades */
+	while (ast_channel_masq(chan)) {
+		ast_channel_unlock(chan);
+		ast_do_masquerade(chan);
+		ast_channel_lock(chan);
+	}
+	if (ast_channel_masqr(chan)) {
+		res = 0;	/* XXX explain, why 0 ? */
+		goto done;
+	}
+
 	/* Perform the framehook write event here. After the frame enters the framehook list
 	 * there is no telling what will happen, how awesome is that!!! */
 	if (!(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
@@ -4997,7 +5052,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 			if (old_frame != fr)
 				f = fr;
 		}
-		send_dtmf_begin_event(chan, DTMF_SENT, fr->subclass.integer);
+		send_dtmf_event(chan, "Sent", fr->subclass.integer, "Yes", "No");
 		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
 		ast_channel_unlock(chan);
 		res = ast_senddigit_begin(chan, fr->subclass.integer);
@@ -5013,7 +5068,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 				ast_frfree(new_frame);
 			}
 		}
-		send_dtmf_end_event(chan, DTMF_SENT, fr->subclass.integer, fr->len);
+		send_dtmf_event(chan, "Sent", fr->subclass.integer, "No", "Yes");
 		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
 		ast_channel_unlock(chan);
 		res = ast_senddigit_end(chan, fr->subclass.integer, fr->len);
@@ -5021,7 +5076,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 		CHECK_BLOCKING(chan);
 		break;
 	case AST_FRAME_TEXT:
-		if (ast_format_cmp(fr->subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) {
+		if (fr->subclass.integer == AST_FORMAT_T140) {
 			res = (ast_channel_tech(chan)->write_text == NULL) ? 0 :
 				ast_channel_tech(chan)->write_text(chan, fr);
 		} else {
@@ -5046,17 +5101,17 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 		if (ast_channel_tech(chan)->write == NULL)
 			break;	/*! \todo XXX should return 0 maybe ? */
 
-		if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+		if (ast_opt_generic_plc && fr->subclass.format.id == AST_FORMAT_SLINEAR) {
 			apply_plc(chan, fr);
 		}
 
 		/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
-		if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) {
+		if (ast_format_cmp(&fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) {
 			f = fr;
 		} else {
-			if ((ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), fr->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) &&
-			    (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) {
-				struct ast_str *codec_buf = ast_str_alloca(64);
+			if ((!ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &fr->subclass.format)) &&
+			    (ast_format_cmp(ast_channel_writeformat(chan), &fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) {
+				char nf[512];
 
 				/*
 				 * XXX Something is not right.  We are not compatible with this
@@ -5068,9 +5123,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 				 * areas.
 				 */
 				ast_log(LOG_WARNING, "Codec mismatch on channel %s setting write format to %s from %s native formats %s\n",
-					ast_channel_name(chan), ast_format_get_name(fr->subclass.format), ast_format_get_name(ast_channel_writeformat(chan)),
-					ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf));
-				ast_set_write_format(chan, fr->subclass.format);
+					ast_channel_name(chan), ast_getformatname(&fr->subclass.format), ast_getformatname(ast_channel_writeformat(chan)),
+					ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(chan)));
+				ast_set_write_format_by_id(chan, fr->subclass.format.id);
 			}
 
 			f = (ast_channel_writetrans(chan)) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr;
@@ -5138,9 +5193,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 #ifndef MONITOR_CONSTANT_DELAY
 				int jump = ast_channel_insmpl(chan) - ast_channel_outsmpl(chan) - 4 * cur->samples;
 				if (jump >= 0) {
-					jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)),
-					                         ast_format_get_sample_rate(f->subclass.format),
-					                         ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+					jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), ast_format_rate(&f->subclass.format), ast_format_rate(&ast_channel_monitor(chan)->read_stream->fmt->format));
 					if (ast_seekstream(ast_channel_monitor(chan)->write_stream, jump, SEEK_FORCECUR) == -1) {
 						ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
 					}
@@ -5149,9 +5202,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 					ast_channel_outsmpl_set(chan, ast_channel_outsmpl(chan) + cur->samples);
 				}
 #else
-				int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)),
-				                             ast_format_get_sample_rate(f->subclass.codec),
-				                             ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+				int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), ast_format_rate(f->subclass.codec), ast_format_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
 				if (jump - MONITOR_DELAY >= 0) {
 					if (ast_seekstream(ast_channel_monitor(chan)->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1) {
 						ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
@@ -5233,111 +5284,70 @@ done:
 	return res;
 }
 
-struct set_format_access {
-	const char *direction;
-	struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan);
-	void (*set_trans)(struct ast_channel *chan, struct ast_trans_pvt *value);
-	struct ast_format *(*get_format)(struct ast_channel *chan);
-	void (*set_format)(struct ast_channel *chan, struct ast_format *format);
-	struct ast_format *(*get_rawformat)(struct ast_channel *chan);
-	void (*set_rawformat)(struct ast_channel *chan, struct ast_format *format);
-	int setoption;
+struct set_format_trans_access {
+	struct ast_trans_pvt *(*get)(const struct ast_channel *chan);
+	void (*set)(struct ast_channel *chan, struct ast_trans_pvt *value);
 };
 
-static const struct set_format_access set_format_access_read = {
-	.direction = "read",
-	.get_trans = ast_channel_readtrans,
-	.set_trans = ast_channel_readtrans_set,
-	.get_format = ast_channel_readformat,
-	.set_format = ast_channel_set_readformat,
-	.get_rawformat = ast_channel_rawreadformat,
-	.set_rawformat = ast_channel_set_rawreadformat,
-	.setoption = AST_OPTION_FORMAT_READ,
+static const struct set_format_trans_access set_format_readtrans = {
+	.get = ast_channel_readtrans,
+	.set = ast_channel_readtrans_set,
 };
 
-static const struct set_format_access set_format_access_write = {
-	.direction = "write",
-	.get_trans = ast_channel_writetrans,
-	.set_trans = ast_channel_writetrans_set,
-	.get_format = ast_channel_writeformat,
-	.set_format = ast_channel_set_writeformat,
-	.get_rawformat = ast_channel_rawwriteformat,
-	.set_rawformat = ast_channel_set_rawwriteformat,
-	.setoption = AST_OPTION_FORMAT_WRITE,
+static const struct set_format_trans_access set_format_writetrans = {
+	.get = ast_channel_writetrans,
+	.set = ast_channel_writetrans_set,
 };
 
-static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, const int direction)
+static int set_format(struct ast_channel *chan,
+	struct ast_format_cap *cap_set,
+	struct ast_format *rawformat,
+	struct ast_format *format,
+	const struct set_format_trans_access *trans,
+	const int direction)
 {
 	struct ast_trans_pvt *trans_pvt;
-	struct ast_format_cap *cap_native;
-	const struct set_format_access *access;
-	struct ast_format *rawformat;
-	struct ast_format *format;
-	RAII_VAR(struct ast_format *, best_set_fmt, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, best_native_fmt, NULL, ao2_cleanup);
+	struct ast_format_cap *cap_native = ast_channel_nativeformats(chan);
+	struct ast_format best_set_fmt;
+	struct ast_format best_native_fmt;
 	int res;
+	char from[200], to[200];
 
-	if (!direction) {
-		/* reading */
-		access = &set_format_access_read;
-	} else {
-		/* writing */
-		access = &set_format_access_write;
+	if (!ast_format_cap_has_type(cap_set, AST_FORMAT_TYPE_AUDIO)) {
+		/*
+		 * Not setting any audio formats?
+		 * Assume a call without any sounds (video, text)
+		 */
+		return 0;
 	}
 
-	best_set_fmt = ast_format_cap_get_format(cap_set, 0);
+	ast_best_codec(cap_set, &best_set_fmt);
 
 	/* See if the underlying channel driver is capable of performing transcoding for us */
-	res = ast_channel_setoption(chan, access->setoption,
-		&best_set_fmt, sizeof(best_set_fmt), 0);
-	if (!res) {
-		ast_debug(1, "Channel driver natively set channel %s to %s format %s\n",
-			ast_channel_name(chan), access->direction, ast_format_get_name(best_set_fmt));
+	if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &best_set_fmt, sizeof(best_set_fmt), 0)) {
+		ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", ast_channel_name(chan),
+			  direction ? "write" : "read", ast_getformatname(&best_set_fmt));
 
 		ast_channel_lock(chan);
-		cap_native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (!cap_native
-			|| ast_format_cap_append(cap_native, best_set_fmt, 0)) {
-			ast_channel_unlock(chan);
-			ao2_cleanup(cap_native);
-			return -1;
-		}
-		ast_channel_nativeformats_set(chan, cap_native);
-		ao2_cleanup(cap_native);
-		access->set_format(chan, best_set_fmt);
-		access->set_rawformat(chan, best_set_fmt);
+		ast_format_copy(format, &best_set_fmt);
+		ast_format_copy(rawformat, &best_set_fmt);
+		ast_format_cap_set(ast_channel_nativeformats(chan), &best_set_fmt);
+		ast_channel_unlock(chan);
 
-		trans_pvt = access->get_trans(chan);
+		trans_pvt = trans->get(chan);
 		if (trans_pvt) {
 			ast_translator_free_path(trans_pvt);
-			access->set_trans(chan, NULL);
+			trans->set(chan, NULL);
 		}
-		ast_channel_unlock(chan);
 
 		/* If there is a generator on the channel, it needs to know about this
 		 * change if it is the write format. */
 		if (direction && ast_channel_generatordata(chan)) {
 			generator_write_format_change(chan);
 		}
-
 		return 0;
 	}
 
-	ast_channel_lock(chan);
-
-	format = access->get_format(chan);
-	rawformat = access->get_rawformat(chan);
-	ast_assert(format != NULL);
-	ast_assert(rawformat != NULL);
-
-	cap_native = ast_channel_nativeformats(chan);
-	if (ast_format_cap_empty(cap_native)) {
-		ast_channel_unlock(chan);
-		ast_log(LOG_ERROR, "Unable to set format because channel %s supports no formats\n",
-				ast_channel_name(chan));
-		return -1;
-	}
-
 	/* Find a translation path from the native format to one of the desired formats */
 	if (!direction) {
 		/* reading */
@@ -5346,37 +5356,38 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set,
 		/* writing */
 		res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt);
 	}
-	if (res < 0) {
-		struct ast_str *codec_from = ast_str_alloca(64);
-		struct ast_str *codec_to = ast_str_alloca(64);
-
-		ast_format_cap_get_names(cap_native, &codec_from);
-		ast_channel_unlock(chan);
-		ast_format_cap_get_names(cap_set, &codec_to);
 
+	if (res < 0) {
 		ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n",
-			ast_str_buffer(codec_from), ast_str_buffer(codec_to));
+			ast_getformatname_multiple(from, sizeof(from), cap_native),
+			ast_getformatname_multiple(to, sizeof(to), cap_set));
 		return -1;
 	}
 
 	/* Now we have a good choice for both. */
-	if ((ast_format_cmp(rawformat, best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
-		(ast_format_cmp(format, best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
-		((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || access->get_trans(chan))) {
+	ast_channel_lock(chan);
+
+	if ((ast_format_cmp(rawformat, &best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
+		(ast_format_cmp(format, &best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
+		((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || trans->get(chan))) {
 		/* the channel is already in these formats, so nothing to do */
 		ast_channel_unlock(chan);
 		return 0;
 	}
 
+	ast_format_copy(rawformat, &best_native_fmt);
+	/* User perspective is fmt */
+	ast_format_copy(format, &best_set_fmt);
+
 	/* Free any translation we have right now */
-	trans_pvt = access->get_trans(chan);
+	trans_pvt = trans->get(chan);
 	if (trans_pvt) {
 		ast_translator_free_path(trans_pvt);
-		access->set_trans(chan, NULL);
+		trans->set(chan, NULL);
 	}
 
 	/* Build a translation path from the raw format to the desired format */
-	if (ast_format_cmp(best_set_fmt, best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) {
+	if (ast_format_cmp(format, rawformat) != AST_FORMAT_CMP_NOT_EQUAL) {
 		/*
 		 * If we were able to swap the native format to the format that
 		 * has been requested, then there is no need to try to build
@@ -5386,80 +5397,133 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set,
 	} else {
 		if (!direction) {
 			/* reading */
-			trans_pvt = ast_translator_build_path(best_set_fmt, best_native_fmt);
+			trans_pvt = ast_translator_build_path(format, rawformat);
 		} else {
 			/* writing */
-			trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt);
+			trans_pvt = ast_translator_build_path(rawformat, format);
 		}
-		access->set_trans(chan, trans_pvt);
+		trans->set(chan, trans_pvt);
 		res = trans_pvt ? 0 : -1;
 	}
-
-	if (!res) {
-		access->set_format(chan, best_set_fmt);
-		access->set_rawformat(chan, best_native_fmt);
-
-		ast_debug(1, "Set channel %s to %s format %s\n",
-			ast_channel_name(chan),
-			access->direction,
-			ast_format_get_name(best_set_fmt));
-	}
-
 	ast_channel_unlock(chan);
 
+	ast_debug(1, "Set channel %s to %s format %s\n",
+		ast_channel_name(chan),
+		direction ? "write" : "read",
+		ast_getformatname(&best_set_fmt));
+
 	/* If there is a generator on the channel, it needs to know about this
 	 * change if it is the write format. */
 	if (direction && ast_channel_generatordata(chan)) {
 		generator_write_format_change(chan);
 	}
-
 	return res;
 }
 
 int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
 {
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
 	int res;
 
-	ast_assert(format != NULL);
+	if (!cap) {
+		return -1;
+	}
+	ast_format_cap_add(cap, format);
+
+	res = set_format(chan,
+		cap,
+		ast_channel_rawreadformat(chan),
+		ast_channel_readformat(chan),
+		&set_format_readtrans,
+		0);
+
+	ast_format_cap_destroy(cap);
+	return res;
+}
+
+int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id)
+{
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	struct ast_format tmp_format;
+	int res;
 
 	if (!cap) {
 		return -1;
 	}
-	ast_format_cap_append(cap, format, 0);
+	ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0));
 
-	res = set_format(chan, cap, 0);
+	res = set_format(chan,
+		cap,
+		ast_channel_rawreadformat(chan),
+		ast_channel_readformat(chan),
+		&set_format_readtrans,
+		0);
 
-	ao2_cleanup(cap);
+	ast_format_cap_destroy(cap);
 	return res;
 }
 
 int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
 {
-	return set_format(chan, cap, 0);
+	return set_format(chan,
+		cap,
+		ast_channel_rawreadformat(chan),
+		ast_channel_readformat(chan),
+		&set_format_readtrans,
+		0);
 }
 
 int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
 {
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
 	int res;
 
-	ast_assert(format != NULL);
+	if (!cap) {
+		return -1;
+	}
+	ast_format_cap_add(cap, format);
+
+	res = set_format(chan,
+		cap,
+		ast_channel_rawwriteformat(chan),
+		ast_channel_writeformat(chan),
+		&set_format_writetrans,
+		1);
+
+	ast_format_cap_destroy(cap);
+	return res;
+}
+
+int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id)
+{
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	struct ast_format tmp_format;
+	int res;
 
 	if (!cap) {
 		return -1;
 	}
-	ast_format_cap_append(cap, format, 0);
+	ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0));
 
-	res = set_format(chan, cap, 1);
+	res = set_format(chan,
+		cap,
+		ast_channel_rawwriteformat(chan),
+		ast_channel_writeformat(chan),
+		&set_format_writetrans,
+		1);
 
-	ao2_cleanup(cap);
+	ast_format_cap_destroy(cap);
 	return res;
 }
 
 int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
 {
-	return set_format(chan, cap, 1);
+	return set_format(chan,
+		cap,
+		ast_channel_rawwriteformat(chan),
+		ast_channel_writeformat(chan),
+		&set_format_writetrans,
+		1);
 }
 
 const char *ast_channel_reason2str(int reason)
@@ -5558,7 +5622,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
 		data = tmpchan;
 		type = "Local";
 	}
-	if (!(new_chan = ast_request(type, cap, NULL, orig, data, &cause))) {
+	if (!(new_chan = ast_request(type, cap, orig, data, &cause))) {
 		ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause);
 		handle_cause(cause, outstate);
 		ast_hangup(orig);
@@ -5568,30 +5632,25 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
 	/* Copy/inherit important information into new channel */
 	if (oh) {
 		if (oh->vars) {
-			ast_channel_lock(new_chan);
 			ast_set_variables(new_chan, oh->vars);
-			ast_channel_unlock(new_chan);
 		}
 		if (oh->parent_channel) {
 			call_forward_inherit(new_chan, oh->parent_channel, orig);
 		}
-		if (!ast_strlen_zero(oh->account)) {
+		if (oh->account) {
 			ast_channel_lock(new_chan);
-			ast_channel_stage_snapshot(new_chan);
-			ast_channel_accountcode_set(new_chan, oh->account);
-			ast_channel_peeraccount_set(new_chan, oh->account);
-			ast_channel_stage_snapshot_done(new_chan);
+			ast_cdr_setaccount(new_chan, oh->account);
 			ast_channel_unlock(new_chan);
 		}
 	} else if (caller) { /* no outgoing helper so use caller if available */
 		call_forward_inherit(new_chan, caller, orig);
 	}
-	ast_set_flag(ast_channel_flags(new_chan), AST_FLAG_ORIGINATED);
 
 	ast_channel_lock_both(orig, new_chan);
+	ast_copy_flags(ast_channel_cdr(new_chan), ast_channel_cdr(orig), AST_CDR_FLAG_ORIGINATED);
+	ast_channel_accountcode_set(new_chan, ast_channel_accountcode(orig));
 	ast_party_connected_line_copy(ast_channel_connected(new_chan), ast_channel_connected(orig));
 	ast_party_redirecting_copy(ast_channel_redirecting(new_chan), ast_channel_redirecting(orig));
-	ast_channel_req_accountcodes(new_chan, orig, AST_CHANNEL_REQUESTOR_REPLACEMENT);
 	ast_channel_unlock(new_chan);
 	ast_channel_unlock(orig);
 
@@ -5611,7 +5670,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
 	return new_chan;
 }
 
-struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
+struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *addr, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
 {
 	int dummy_outstate;
 	int cause = 0;
@@ -5625,7 +5684,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 	else
 		outstate = &dummy_outstate;	/* make outstate always a valid pointer */
 
-	chan = ast_request(type, cap, assignedids, requestor, addr, &cause);
+	chan = ast_request(type, cap, requestor, addr, &cause);
 	if (!chan) {
 		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr);
 		handle_cause(cause, outstate);
@@ -5634,9 +5693,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 
 	if (oh) {
 		if (oh->vars) {
-			ast_channel_lock(chan);
 			ast_set_variables(chan, oh->vars);
-			ast_channel_unlock(chan);
 		}
 		if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) {
 			/*
@@ -5654,12 +5711,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 			ast_channel_unlock(oh->parent_channel);
 			ast_channel_unlock(chan);
 		}
-		if (!ast_strlen_zero(oh->account)) {
+		if (oh->account) {
 			ast_channel_lock(chan);
-			ast_channel_stage_snapshot(chan);
-			ast_channel_accountcode_set(chan, oh->account);
-			ast_channel_peeraccount_set(chan, oh->account);
-			ast_channel_stage_snapshot_done(chan);
+			ast_cdr_setaccount(chan, oh->account);
 			ast_channel_unlock(chan);
 		}
 	}
@@ -5674,7 +5728,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 	 */
 	ast_set_callerid(chan, cid_num, cid_name, cid_num);
 
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
+	ast_set_flag(ast_channel_cdr(chan), AST_CDR_FLAG_ORIGINATED);
 	ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
 	if (cid_num) {
 		connected.id.number.valid = 1;
@@ -5687,12 +5741,6 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 		connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
 	}
 	ast_channel_set_connected_line(chan, &connected, NULL);
-	if (requestor) {
-		ast_channel_lock_both(chan, (struct ast_channel *) requestor);
-		ast_channel_req_accountcodes(chan, requestor, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
-		ast_channel_unlock(chan);
-		ast_channel_unlock((struct ast_channel *) requestor);
-	}
 
 	if (ast_call(chan, addr, 0)) {	/* ast_call failed... */
 		ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr);
@@ -5730,21 +5778,25 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 					break;
 
 				case AST_CONTROL_BUSY:
+					ast_cdr_busy(ast_channel_cdr(chan));
 					*outstate = f->subclass.integer;
 					timeout = 0;
 					break;
 
 				case AST_CONTROL_INCOMPLETE:
+					ast_cdr_failed(ast_channel_cdr(chan));
 					*outstate = AST_CONTROL_CONGESTION;
 					timeout = 0;
 					break;
 
 				case AST_CONTROL_CONGESTION:
+					ast_cdr_failed(ast_channel_cdr(chan));
 					*outstate = f->subclass.integer;
 					timeout = 0;
 					break;
 
 				case AST_CONTROL_ANSWER:
+					ast_cdr_answer(ast_channel_cdr(chan));
 					*outstate = f->subclass.integer;
 					timeout = 0;		/* trick to force exit from the while() */
 					break;
@@ -5795,10 +5847,28 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 		*outstate = AST_CONTROL_ANSWER;
 
 	if (res <= 0) {
+		struct ast_cdr *chancdr;
 		ast_channel_lock(chan);
 		if (AST_CONTROL_RINGING == last_subclass) {
 			ast_channel_hangupcause_set(chan, AST_CAUSE_NO_ANSWER);
 		}
+		if (!ast_channel_cdr(chan) && (chancdr = ast_cdr_alloc())) {
+			ast_channel_cdr_set(chan, chancdr);
+			ast_cdr_init(ast_channel_cdr(chan), chan);
+		}
+		if (ast_channel_cdr(chan)) {
+			char tmp[256];
+
+			snprintf(tmp, sizeof(tmp), "%s/%s", type, addr);
+			ast_cdr_setapp(ast_channel_cdr(chan), "Dial", tmp);
+			ast_cdr_update(chan);
+			ast_cdr_start(ast_channel_cdr(chan));
+			ast_cdr_end(ast_channel_cdr(chan));
+			/* If the cause wasn't handled properly */
+			if (ast_cdr_disposition(ast_channel_cdr(chan), ast_channel_hangupcause(chan))) {
+				ast_cdr_failed(ast_channel_cdr(chan));
+			}
+		}
 		ast_channel_unlock(chan);
 		ast_hangup(chan);
 		chan = NULL;
@@ -5806,9 +5876,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 	return chan;
 }
 
-struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int timeout, int *outstate, const char *cidnum, const char *cidname)
+struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *addr, int timeout, int *outstate, const char *cidnum, const char *cidname)
 {
-	return __ast_request_and_dial(type, cap, assignedids, requestor, addr, timeout, outstate, cidnum, cidname, NULL);
+	return __ast_request_and_dial(type, cap, requestor, addr, timeout, outstate, cidnum, cidname, NULL);
 }
 
 static int set_security_requirements(const struct ast_channel *requestor, struct ast_channel *out)
@@ -5851,7 +5921,7 @@ static int set_security_requirements(const struct ast_channel *requestor, struct
 	return 0;
 }
 
-struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
+struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_channel *requestor, const char *addr, int *cause)
 {
 	struct chanlist *chan;
 	struct ast_channel *c;
@@ -5869,29 +5939,26 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
 
 	AST_RWLIST_TRAVERSE(&backends, chan, list) {
 		struct ast_format_cap *tmp_cap;
-		RAII_VAR(struct ast_format *, tmp_fmt, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_format *, best_audio_fmt, NULL, ao2_cleanup);
+		struct ast_format tmp_fmt;
+		struct ast_format best_audio_fmt;
 		struct ast_format_cap *joint_cap;
 
 		if (strcasecmp(type, chan->tech->type))
 			continue;
 
+		ast_format_clear(&best_audio_fmt);
 		/* find the best audio format to use */
-		tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (tmp_cap) {
-			ast_format_cap_append_from_cap(tmp_cap, request_cap, AST_MEDIA_TYPE_AUDIO);
+		if ((tmp_cap = ast_format_cap_get_type(request_cap, AST_FORMAT_TYPE_AUDIO))) {
 			/* We have audio - is it possible to connect the various calls to each other?
 				(Avoid this check for calls without audio, like text+video calls)
 			*/
 			res = ast_translator_best_choice(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt);
-			ao2_ref(tmp_cap, -1);
+			ast_format_cap_destroy(tmp_cap);
 			if (res < 0) {
-				struct ast_str *tech_codecs = ast_str_alloca(64);
-				struct ast_str *request_codecs = ast_str_alloca(64);
-
+				char tmp1[256], tmp2[256];
 				ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
-					ast_format_cap_get_names(chan->tech->capabilities, &tech_codecs),
-					ast_format_cap_get_names(request_cap, &request_codecs));
+					ast_getformatname_multiple(tmp1, sizeof(tmp1), chan->tech->capabilities),
+					ast_getformatname_multiple(tmp2, sizeof(tmp2), request_cap));
 				*cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
 				AST_RWLIST_UNLOCK(&backends);
 				return NULL;
@@ -5905,36 +5972,27 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
 		 * purposes is used for the request. This needs to be re-evaluated.  It may be
 		 * a better choice to send all the audio formats capable of being translated
 		 * during the request and allow the channel drivers to pick the best one. */
-		joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		if (!joint_cap) {
+		if (!(joint_cap = ast_format_cap_dup(request_cap))) {
 			return NULL;
 		}
-		ast_format_cap_append_from_cap(joint_cap, request_cap, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_remove_by_type(joint_cap, AST_MEDIA_TYPE_AUDIO);
-		ast_format_cap_append(joint_cap, best_audio_fmt, 0);
+		ast_format_cap_remove_bytype(joint_cap, AST_FORMAT_TYPE_AUDIO);
+		ast_format_cap_add(joint_cap, &best_audio_fmt);
 
-		if (!(c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause))) {
-			ao2_ref(joint_cap, -1);
+		if (!(c = chan->tech->requester(type, joint_cap, requestor, addr, cause))) {
+			ast_format_cap_destroy(joint_cap);
 			return NULL;
 		}
 
+		/* Set newly created channel callid to same as the requestor */
 		if (requestor) {
-			struct ast_callid *callid;
-
-			ast_channel_lock_both(c, (struct ast_channel *) requestor);
-
-			/* Set the newly created channel's callid to the same as the requestor. */
-			callid = ast_channel_callid(requestor);
+			struct ast_callid *callid = ast_channel_callid(requestor);
 			if (callid) {
 				ast_channel_callid_set(c, callid);
 				callid = ast_callid_unref(callid);
 			}
-
-			ast_channel_unlock(c);
-			ast_channel_unlock((struct ast_channel *) requestor);
 		}
 
-		ao2_ref(joint_cap, -1);
+		joint_cap = ast_format_cap_destroy(joint_cap);
 
 		if (set_security_requirements(requestor, c)) {
 			ast_log(LOG_WARNING, "Setting security requirements failed\n");
@@ -5954,88 +6012,6 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
 	return NULL;
 }
 
-/*!
- * \internal
- * \brief Setup new channel accountcodes from the requestor channel after ast_request().
- * \since 13.0.0
- *
- * \param chan New channel to get accountcodes setup.
- * \param requestor Requesting channel to get accountcodes from.
- * \param relationship What the new channel was created for.
- * \param precious TRUE if pre-existing accountcodes on chan will not be overwritten.
- *
- * \pre The chan and requestor channels are already locked.
- *
- * \return Nothing
- */
-static void channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship, int precious)
-{
-	/*
-	 * The primary reason for the existence of this function is
-	 * so local channels can propagate accountcodes to the ;2
-	 * channel before ast_call().
-	 *
-	 * The secondary reason is to propagate the CHANNEL(peeraccount)
-	 * value set before Dial, FollowMe, and Queue while maintaining
-	 * the historic straight across accountcode propagation as a
-	 * fallback.
-	 */
-	switch (relationship) {
-	case AST_CHANNEL_REQUESTOR_BRIDGE_PEER:
-		/* Crossover the requestor's accountcode and peeraccount */
-		if (!precious || ast_strlen_zero(ast_channel_accountcode(chan))) {
-			/*
-			 * The newly created channel does not have an accountcode
-			 * or we don't care.
-			 */
-			if (!ast_strlen_zero(ast_channel_peeraccount(requestor))) {
-				/*
-				 * Set it to the requestor's peeraccount.  This allows the
-				 * dialplan to indicate the accountcode to use when dialing
-				 * by setting CHANNEL(peeraccount).
-				 */
-				ast_channel_accountcode_set(chan, ast_channel_peeraccount(requestor));
-			} else if (!precious
-				&& !ast_strlen_zero(ast_channel_accountcode(requestor))) {
-				/*
-				 * Fallback to the historic propagation and set it to the
-				 * requestor's accountcode.
-				 */
-				ast_channel_accountcode_set(chan, ast_channel_accountcode(requestor));
-			}
-		}
-		if (!ast_strlen_zero(ast_channel_accountcode(requestor))) {
-			ast_channel_peeraccount_set(chan, ast_channel_accountcode(requestor));
-		}
-		break;
-	case AST_CHANNEL_REQUESTOR_REPLACEMENT:
-		/* Pass the requestor's accountcode and peeraccount straight. */
-		if (!precious || ast_strlen_zero(ast_channel_accountcode(chan))) {
-			/*
-			 * The newly created channel does not have an accountcode
-			 * or we don't care.
-			 */
-			if (!ast_strlen_zero(ast_channel_accountcode(requestor))) {
-				ast_channel_accountcode_set(chan, ast_channel_accountcode(requestor));
-			}
-		}
-		if (!ast_strlen_zero(ast_channel_peeraccount(requestor))) {
-			ast_channel_peeraccount_set(chan, ast_channel_peeraccount(requestor));
-		}
-		break;
-	}
-}
-
-void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
-{
-	channel_req_accountcodes(chan, requestor, relationship, 0);
-}
-
-void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
-{
-	channel_req_accountcodes(chan, requestor, relationship, 1);
-}
-
 int ast_pre_call(struct ast_channel *chan, const char *sub_args)
 {
 	int (*pre_call)(struct ast_channel *chan, const char *sub_args);
@@ -6062,6 +6038,9 @@ int ast_call(struct ast_channel *chan, const char *addr, int timeout)
 	/* Stop if we're a zombie or need a soft hangup */
 	ast_channel_lock(chan);
 	if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
+		if (ast_channel_cdr(chan)) {
+			ast_set_flag(ast_channel_cdr(chan), AST_CDR_FLAG_DIALED);
+		}
 		if (ast_channel_tech(chan)->call)
 			res = ast_channel_tech(chan)->call(chan, addr, timeout);
 		ast_set_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
@@ -6211,41 +6190,30 @@ int ast_channel_sendurl(struct ast_channel *chan, const char *url)
 /*! \brief Set up translation from one channel to another */
 static int ast_channel_make_compatible_helper(struct ast_channel *from, struct ast_channel *to)
 {
-	struct ast_format_cap *src_cap;
-	struct ast_format_cap *dst_cap;
-	RAII_VAR(struct ast_format *, best_src_fmt, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, best_dst_fmt, NULL, ao2_cleanup);
-	int no_path;
+	struct ast_format_cap *src_cap = ast_channel_nativeformats(from); /* shallow copy, do not destroy */
+	struct ast_format_cap *dst_cap = ast_channel_nativeformats(to);   /* shallow copy, do not destroy */
+	struct ast_format best_src_fmt;
+	struct ast_format best_dst_fmt;
+	int use_slin;
 
-	ast_channel_lock_both(from, to);
+	/* See if the channel driver can natively make these two channels compatible */
+	if (ast_channel_tech(from)->bridge && ast_channel_tech(from)->bridge == ast_channel_tech(to)->bridge &&
+	    !ast_channel_setoption(from, AST_OPTION_MAKE_COMPATIBLE, to, sizeof(struct ast_channel *), 0)) {
+		return 0;
+	}
 
 	if ((ast_format_cmp(ast_channel_readformat(from), ast_channel_writeformat(to)) != AST_FORMAT_CMP_NOT_EQUAL) &&
 		(ast_format_cmp(ast_channel_readformat(to), ast_channel_writeformat(from)) != AST_FORMAT_CMP_NOT_EQUAL)) {
 		/* Already compatible!  Moving on ... */
-		ast_channel_unlock(to);
-		ast_channel_unlock(from);
 		return 0;
 	}
 
-	src_cap = ast_channel_nativeformats(from); /* shallow copy, do not destroy */
-	dst_cap = ast_channel_nativeformats(to);   /* shallow copy, do not destroy */
-
 	/* If there's no audio in this call, don't bother with trying to find a translation path */
-	if (!ast_format_cap_has_type(src_cap, AST_MEDIA_TYPE_AUDIO)
-		|| !ast_format_cap_has_type(dst_cap, AST_MEDIA_TYPE_AUDIO)) {
-		ast_channel_unlock(to);
-		ast_channel_unlock(from);
+	if (!ast_format_cap_has_type(src_cap, AST_FORMAT_TYPE_AUDIO) || !ast_format_cap_has_type(dst_cap, AST_FORMAT_TYPE_AUDIO))
 		return 0;
-	}
-
-	no_path = ast_translator_best_choice(dst_cap, src_cap, &best_dst_fmt, &best_src_fmt);
 
-	ast_channel_unlock(to);
-	ast_channel_unlock(from);
-
-	if (no_path) {
-		ast_log(LOG_WARNING, "No path to translate from %s to %s\n",
-			ast_channel_name(from), ast_channel_name(to));
+	if (ast_translator_best_choice(dst_cap, src_cap, &best_src_fmt, &best_dst_fmt) < 0) {
+		ast_log(LOG_WARNING, "No path to translate from %s to %s\n", ast_channel_name(from), ast_channel_name(to));
 		return -1;
 	}
 
@@ -6255,28 +6223,24 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
 	 * no direct conversion available. If generic PLC is
 	 * desired, then transcoding via SLINEAR is a requirement
 	 */
-	if (ast_format_cmp(best_dst_fmt, best_src_fmt) == AST_FORMAT_CMP_NOT_EQUAL
-		&& (ast_opt_generic_plc || ast_opt_transcode_via_slin)) {
-		int use_slin = (ast_format_cache_is_slinear(best_src_fmt)
-			|| ast_format_cache_is_slinear(best_dst_fmt)) ? 1 : 0;
+	use_slin = ast_format_is_slinear(&best_src_fmt) || ast_format_is_slinear(&best_dst_fmt) ? 1 : 0;
+	if ((ast_format_cmp(&best_src_fmt, &best_dst_fmt) == AST_FORMAT_CMP_NOT_EQUAL) &&
+		(ast_opt_generic_plc || ast_opt_transcode_via_slin) &&
+	    (ast_translate_path_steps(&best_dst_fmt, &best_src_fmt) != 1 || use_slin)) {
 
-		if (use_slin || ast_translate_path_steps(best_dst_fmt, best_src_fmt) != 1) {
-			int best_sample_rate = (ast_format_get_sample_rate(best_src_fmt) > ast_format_get_sample_rate(best_dst_fmt)) ?
-				ast_format_get_sample_rate(best_src_fmt) : ast_format_get_sample_rate(best_dst_fmt);
+		int best_sample_rate = ast_format_rate(&best_src_fmt) > ast_format_rate(&best_dst_fmt) ?
+			ast_format_rate(&best_src_fmt) : ast_format_rate(&best_dst_fmt);
 
-			/* pick the best signed linear format based upon what preserves the sample rate the best. */
-			ao2_replace(best_src_fmt, ast_format_cache_get_slin_by_rate(best_sample_rate));
-		}
+		/* pick the best signed linear format based upon what preserves the sample rate the best. */
+		ast_format_set(&best_dst_fmt, ast_format_slin_by_rate(best_sample_rate), 0);
 	}
 
-	if (ast_set_read_format(from, best_src_fmt)) {
-		ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n",
-			ast_channel_name(from), ast_format_get_name(best_src_fmt));
+	if (ast_set_read_format(from, &best_dst_fmt) < 0) {
+		ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", ast_channel_name(from), ast_getformatname(&best_dst_fmt));
 		return -1;
 	}
-	if (ast_set_write_format(to, best_src_fmt)) {
-		ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n",
-			ast_channel_name(to), ast_format_get_name(best_src_fmt));
+	if (ast_set_write_format(to, &best_dst_fmt) < 0) {
+		ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", ast_channel_name(to), ast_getformatname(&best_dst_fmt));
 		return -1;
 	}
 	return 0;
@@ -6284,23 +6248,254 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
 
 int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
 {
-	/*
-	 * Set up translation from the peer to the chan first in case we
-	 * need to hear any in-band tones and the other direction fails.
-	 */
-	if (ast_channel_make_compatible_helper(peer, chan)) {
-		return -1;
-	}
+	/* Some callers do not check return code, and we must try to set all call legs correctly */
+	int rc = 0;
 
 	/* Set up translation from the chan to the peer */
-	if (ast_channel_make_compatible_helper(chan, peer)) {
-		return -1;
-	}
+	rc = ast_channel_make_compatible_helper(chan, peer);
 
-	return 0;
+	if (rc < 0)
+		return rc;
+
+	/* Set up translation from the peer to the chan */
+	rc = ast_channel_make_compatible_helper(peer, chan);
+
+	return rc;
 }
 
-/*! \brief this function simply changes the name of the channel and issues a manager_event
+static int __ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clonechan, struct ast_datastore *xfer_ds)
+{
+	int res = -1;
+	struct ast_channel *final_orig, *final_clone, *base;
+
+	for (;;) {
+		final_orig = original;
+		final_clone = clonechan;
+
+		ast_channel_lock_both(original, clonechan);
+
+		if (ast_test_flag(ast_channel_flags(original), AST_FLAG_ZOMBIE)
+			|| ast_test_flag(ast_channel_flags(clonechan), AST_FLAG_ZOMBIE)) {
+			/* Zombies! Run! */
+			ast_log(LOG_WARNING,
+				"Can't setup masquerade. One or both channels is dead. (%s <-- %s)\n",
+				ast_channel_name(original), ast_channel_name(clonechan));
+			ast_channel_unlock(clonechan);
+			ast_channel_unlock(original);
+			return -1;
+		}
+
+		/*
+		 * Each of these channels may be sitting behind a channel proxy
+		 * (i.e. chan_agent) and if so, we don't really want to
+		 * masquerade it, but its proxy
+		 */
+		if (ast_channel_internal_bridged_channel(original)
+			&& (ast_channel_internal_bridged_channel(original) != ast_bridged_channel(original))
+			&& (ast_channel_internal_bridged_channel(ast_channel_internal_bridged_channel(original)) != original)) {
+			final_orig = ast_channel_internal_bridged_channel(original);
+		}
+		if (ast_channel_internal_bridged_channel(clonechan)
+			&& (ast_channel_internal_bridged_channel(clonechan) != ast_bridged_channel(clonechan))
+			&& (ast_channel_internal_bridged_channel(ast_channel_internal_bridged_channel(clonechan)) != clonechan)) {
+			final_clone = ast_channel_internal_bridged_channel(clonechan);
+		}
+		if (ast_channel_tech(final_clone)->get_base_channel
+			&& (base = ast_channel_tech(final_clone)->get_base_channel(final_clone))) {
+			final_clone = base;
+		}
+
+		if ((final_orig != original) || (final_clone != clonechan)) {
+			/*
+			 * Lots and lots of deadlock avoidance.  The main one we're
+			 * competing with is ast_write(), which locks channels
+			 * recursively, when working with a proxy channel.
+			 */
+			if (ast_channel_trylock(final_orig)) {
+				ast_channel_unlock(clonechan);
+				ast_channel_unlock(original);
+
+				/* Try again */
+				continue;
+			}
+			if (ast_channel_trylock(final_clone)) {
+				ast_channel_unlock(final_orig);
+				ast_channel_unlock(clonechan);
+				ast_channel_unlock(original);
+
+				/* Try again */
+				continue;
+			}
+			ast_channel_unlock(clonechan);
+			ast_channel_unlock(original);
+			original = final_orig;
+			clonechan = final_clone;
+
+			if (ast_test_flag(ast_channel_flags(original), AST_FLAG_ZOMBIE)
+				|| ast_test_flag(ast_channel_flags(clonechan), AST_FLAG_ZOMBIE)) {
+				/* Zombies! Run! */
+				ast_log(LOG_WARNING,
+					"Can't setup masquerade. One or both channels is dead. (%s <-- %s)\n",
+					ast_channel_name(original), ast_channel_name(clonechan));
+				ast_channel_unlock(clonechan);
+				ast_channel_unlock(original);
+				return -1;
+			}
+		}
+		break;
+	}
+
+	if (original == clonechan) {
+		ast_log(LOG_WARNING, "Can't masquerade channel '%s' into itself!\n", ast_channel_name(original));
+		ast_channel_unlock(clonechan);
+		ast_channel_unlock(original);
+		return -1;
+	}
+
+	ast_debug(1, "Planning to masquerade channel %s into the structure of %s\n",
+		ast_channel_name(clonechan), ast_channel_name(original));
+
+	if (!ast_channel_masqr(original) && !ast_channel_masq(original) && !ast_channel_masq(clonechan) && !ast_channel_masqr(clonechan)) {
+		ast_channel_masq_set(original, clonechan);
+		ast_channel_masqr_set(clonechan, original);
+		if (xfer_ds) {
+			ast_channel_datastore_add(original, xfer_ds);
+		}
+		ast_queue_frame(original, &ast_null_frame);
+		ast_queue_frame(clonechan, &ast_null_frame);
+		ast_debug(1, "Done planning to masquerade channel %s into the structure of %s\n", ast_channel_name(clonechan), ast_channel_name(original));
+		res = 0;
+	} else if (ast_channel_masq(original)) {
+		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
+			ast_channel_name(ast_channel_masq(original)), ast_channel_name(original));
+	} else if (ast_channel_masqr(original)) {
+		/* not yet as a previously planned masq hasn't yet happened */
+		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
+			ast_channel_name(original), ast_channel_name(ast_channel_masqr(original)));
+	} else if (ast_channel_masq(clonechan)) {
+		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
+			ast_channel_name(ast_channel_masq(clonechan)), ast_channel_name(clonechan));
+	} else { /* (clonechan->masqr) */
+		ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
+		ast_channel_name(clonechan), ast_channel_name(ast_channel_masqr(clonechan)));
+	}
+
+	ast_channel_unlock(clonechan);
+	ast_channel_unlock(original);
+
+	return res;
+}
+
+int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
+{
+	return __ast_channel_masquerade(original, clone, NULL);
+}
+
+/*!
+ * \internal
+ * \brief Copy the source connected line information to the destination for a transfer.
+ * \since 1.8
+ *
+ * \param dest Destination connected line
+ * \param src Source connected line
+ *
+ * \return Nothing
+ */
+static void party_connected_line_copy_transfer(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
+{
+	struct ast_party_connected_line connected;
+
+	connected = *((struct ast_party_connected_line *) src);
+	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+
+	/* Make sure empty strings will be erased. */
+	if (!connected.id.name.str) {
+		connected.id.name.str = "";
+	}
+	if (!connected.id.number.str) {
+		connected.id.number.str = "";
+	}
+	if (!connected.id.subaddress.str) {
+		connected.id.subaddress.str = "";
+	}
+	if (!connected.id.tag) {
+		connected.id.tag = "";
+	}
+
+	ast_party_connected_line_copy(dest, &connected);
+}
+
+/*! Transfer masquerade connected line exchange data. */
+struct xfer_masquerade_ds {
+	/*! New ID for the target of the transfer (Masquerade original channel) */
+	struct ast_party_connected_line target_id;
+	/*! New ID for the transferee of the transfer (Masquerade clone channel) */
+	struct ast_party_connected_line transferee_id;
+	/*! TRUE if the target call is held. (Masquerade original channel) */
+	int target_held;
+	/*! TRUE if the transferee call is held. (Masquerade clone channel) */
+	int transferee_held;
+};
+
+/*!
+ * \internal
+ * \brief Destroy the transfer connected line exchange datastore information.
+ * \since 1.8
+ *
+ * \param data The datastore payload to destroy.
+ *
+ * \return Nothing
+ */
+static void xfer_ds_destroy(void *data)
+{
+	struct xfer_masquerade_ds *ds = data;
+
+	ast_party_connected_line_free(&ds->target_id);
+	ast_party_connected_line_free(&ds->transferee_id);
+	ast_free(ds);
+}
+
+static const struct ast_datastore_info xfer_ds_info = {
+	.type = "xfer_colp",
+	.destroy = xfer_ds_destroy,
+};
+
+int ast_channel_transfer_masquerade(
+	struct ast_channel *target_chan,
+	const struct ast_party_connected_line *target_id,
+	int target_held,
+	struct ast_channel *transferee_chan,
+	const struct ast_party_connected_line *transferee_id,
+	int transferee_held)
+{
+	struct ast_datastore *xfer_ds;
+	struct xfer_masquerade_ds *xfer_colp;
+	int res;
+
+	xfer_ds = ast_datastore_alloc(&xfer_ds_info, NULL);
+	if (!xfer_ds) {
+		return -1;
+	}
+
+	xfer_colp = ast_calloc(1, sizeof(*xfer_colp));
+	if (!xfer_colp) {
+		ast_datastore_free(xfer_ds);
+		return -1;
+	}
+	party_connected_line_copy_transfer(&xfer_colp->target_id, target_id);
+	xfer_colp->target_held = target_held;
+	party_connected_line_copy_transfer(&xfer_colp->transferee_id, transferee_id);
+	xfer_colp->transferee_held = transferee_held;
+	xfer_ds->data = xfer_colp;
+
+	res = __ast_channel_masquerade(target_chan, transferee_chan, xfer_ds);
+	if (res) {
+		ast_datastore_free(xfer_ds);
+	}
+	return res;
+}
+
+/*! \brief this function simply changes the name of the channel and issues a manager_event
  *         with out unlinking and linking the channel from the ao2_container.  This should
  *         only be used when the channel has already been unlinked from the ao2_container.
  */
@@ -6311,11 +6506,7 @@ static void __ast_change_name_nolink(struct ast_channel *chan, const char *newna
 			<synopsis>Raised when the name of a channel is changed.</synopsis>
 		</managerEventInstance>
 	***/
-	ast_manager_event(chan, EVENT_FLAG_CALL, "Rename",
-		"Channel: %s\r\n"
-		"Newname: %s\r\n"
-		"Uniqueid: %s\r\n",
-		ast_channel_name(chan), newname, ast_channel_uniqueid(chan));
+	ast_manager_event(chan, EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", ast_channel_name(chan), newname, ast_channel_uniqueid(chan));
 	ast_channel_name_set(chan, newname);
 }
 
@@ -6333,42 +6524,41 @@ void ast_change_name(struct ast_channel *chan, const char *newname)
 
 void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
 {
-	struct ast_var_t *current;
-	struct ast_var_t *newvar;
+	struct ast_var_t *current, *newvar;
 	const char *varname;
-	int vartype;
 
 	AST_LIST_TRAVERSE(ast_channel_varshead((struct ast_channel *) parent), current, entries) {
+		int vartype = 0;
+
 		varname = ast_var_full_name(current);
-		if (!varname) {
+		if (!varname)
 			continue;
-		}
 
-		vartype = 0;
 		if (varname[0] == '_') {
 			vartype = 1;
-			if (varname[1] == '_') {
+			if (varname[1] == '_')
 				vartype = 2;
-			}
 		}
 
 		switch (vartype) {
 		case 1:
 			newvar = ast_var_assign(&varname[1], ast_var_value(current));
+			if (newvar) {
+				AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
+				ast_debug(1, "Inheriting variable %s from %s to %s.\n",
+					ast_var_name(newvar), ast_channel_name(parent), ast_channel_name(child));
+			}
 			break;
 		case 2:
 			newvar = ast_var_assign(varname, ast_var_value(current));
+			if (newvar) {
+				AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
+				ast_debug(1, "Inheriting variable %s from %s to %s.\n",
+					ast_var_name(newvar), ast_channel_name(parent), ast_channel_name(child));
+			}
 			break;
 		default:
-			continue;
-		}
-		if (newvar) {
-			ast_debug(1, "Inheriting variable %s from %s to %s.\n",
-				ast_var_full_name(newvar), ast_channel_name(parent),
-				ast_channel_name(child));
-			AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
-			ast_channel_publish_varset(child, ast_var_full_name(newvar),
-				ast_var_value(newvar));
+			break;
 		}
 	}
 }
@@ -6399,17 +6589,252 @@ static void clone_variables(struct ast_channel *original, struct ast_channel *cl
 }
 
 
-void ast_channel_name_to_dial_string(char *channel_name)
+
+/* return the oldest of two linkedids.  linkedid is derived from
+   uniqueid which is formed like this: [systemname-]ctime.seq
+
+   The systemname, and the dash are optional, followed by the epoch
+   time followed by an integer sequence.  Note that this is not a
+   decimal number, since 1.2 is less than 1.11 in uniqueid land.
+
+   To compare two uniqueids, we parse out the integer values of the
+   time and the sequence numbers and compare them, with time trumping
+   sequence.
+*/
+static const char *oldest_linkedid(const char *a, const char *b)
 {
-	char *dash;
+	const char *satime, *saseq;
+	const char *sbtime, *sbseq;
+	const char *dash;
 
-	/* Truncate after the dash */
-	dash = strrchr(channel_name, '-');
-	if (dash) {
-		*dash = '\0';
+	unsigned int atime, aseq, btime, bseq;
+
+	if (ast_strlen_zero(a))
+		return b;
+
+	if (ast_strlen_zero(b))
+		return a;
+
+	satime = a;
+	sbtime = b;
+
+	/* jump over the system name */
+	if ((dash = strrchr(satime, '-'))) {
+		satime = dash+1;
+	}
+	if ((dash = strrchr(sbtime, '-'))) {
+		sbtime = dash+1;
+	}
+
+	/* the sequence comes after the '.' */
+	saseq = strchr(satime, '.');
+	sbseq = strchr(sbtime, '.');
+	if (!saseq || !sbseq)
+		return NULL;
+	saseq++;
+	sbseq++;
+
+	/* convert it all to integers */
+	atime = atoi(satime); /* note that atoi is ignoring the '.' after the time string */
+	btime = atoi(sbtime); /* note that atoi is ignoring the '.' after the time string */
+	aseq = atoi(saseq);
+	bseq = atoi(sbseq);
+
+	/* and finally compare */
+	if (atime == btime) {
+		return (aseq < bseq) ? a : b;
+	}
+	else {
+		return (atime < btime) ? a : b;
 	}
 }
 
+/*! Set the channel's linkedid to the given string, and also check to
+ *  see if the channel's old linkedid is now being retired */
+static void ast_channel_change_linkedid(struct ast_channel *chan, const char *linkedid)
+{
+	ast_assert(linkedid != NULL);
+	/* if the linkedid for this channel is being changed from something, check... */
+	if (ast_channel_linkedid(chan) && !strcmp(ast_channel_linkedid(chan), linkedid)) {
+		return;
+	}
+
+	ast_cel_check_retire_linkedid(chan);
+	ast_channel_linkedid_set(chan, linkedid);
+	ast_cel_linkedid_ref(linkedid);
+}
+
+/*!
+  \brief Propagate the oldest linkedid between associated channels
+
+*/
+void ast_channel_set_linkgroup(struct ast_channel *chan, struct ast_channel *peer)
+{
+	const char* linkedid=NULL;
+	struct ast_channel *bridged;
+
+	linkedid = oldest_linkedid(ast_channel_linkedid(chan), ast_channel_linkedid(peer));
+	linkedid = oldest_linkedid(linkedid, ast_channel_uniqueid(chan));
+	linkedid = oldest_linkedid(linkedid, ast_channel_uniqueid(peer));
+	if (ast_channel_internal_bridged_channel(chan)) {
+		bridged = ast_bridged_channel(chan);
+		if (bridged && bridged != peer) {
+			linkedid = oldest_linkedid(linkedid, ast_channel_linkedid(bridged));
+			linkedid = oldest_linkedid(linkedid, ast_channel_uniqueid(bridged));
+		}
+	}
+	if (ast_channel_internal_bridged_channel(peer)) {
+		bridged = ast_bridged_channel(peer);
+		if (bridged && bridged != chan) {
+			linkedid = oldest_linkedid(linkedid, ast_channel_linkedid(bridged));
+			linkedid = oldest_linkedid(linkedid, ast_channel_uniqueid(bridged));
+		}
+	}
+
+	/* just in case setting a stringfield to itself causes problems */
+	linkedid = ast_strdupa(linkedid);
+
+	ast_channel_change_linkedid(chan, linkedid);
+	ast_channel_change_linkedid(peer, linkedid);
+	if (ast_channel_internal_bridged_channel(chan)) {
+		bridged = ast_bridged_channel(chan);
+		if (bridged && bridged != peer) {
+			ast_channel_change_linkedid(bridged, linkedid);
+		}
+	}
+	if (ast_channel_internal_bridged_channel(peer)) {
+		bridged = ast_bridged_channel(peer);
+		if (bridged && bridged != chan) {
+			ast_channel_change_linkedid(bridged, linkedid);
+		}
+	}
+}
+
+/* copy accountcode and peeraccount across during a link */
+static void ast_set_owners_and_peers(struct ast_channel *chan1,
+									 struct ast_channel *chan2)
+{
+	if (!ast_strlen_zero(ast_channel_accountcode(chan1)) && ast_strlen_zero(ast_channel_peeraccount(chan2))) {
+		ast_debug(1, "setting peeraccount to %s for %s from data on channel %s\n",
+				ast_channel_accountcode(chan1), ast_channel_name(chan2), ast_channel_name(chan1));
+		ast_channel_peeraccount_set(chan2, ast_channel_accountcode(chan1));
+	}
+	if (!ast_strlen_zero(ast_channel_accountcode(chan2)) && ast_strlen_zero(ast_channel_peeraccount(chan1))) {
+		ast_debug(1, "setting peeraccount to %s for %s from data on channel %s\n",
+				ast_channel_accountcode(chan2), ast_channel_name(chan1), ast_channel_name(chan2));
+		ast_channel_peeraccount_set(chan1, ast_channel_accountcode(chan2));
+	}
+	if (!ast_strlen_zero(ast_channel_peeraccount(chan1)) && ast_strlen_zero(ast_channel_accountcode(chan2))) {
+		ast_debug(1, "setting accountcode to %s for %s from data on channel %s\n",
+				ast_channel_peeraccount(chan1), ast_channel_name(chan2), ast_channel_name(chan1));
+		ast_channel_accountcode_set(chan2, ast_channel_peeraccount(chan1));
+	}
+	if (!ast_strlen_zero(ast_channel_peeraccount(chan2)) && ast_strlen_zero(ast_channel_accountcode(chan1))) {
+		ast_debug(1, "setting accountcode to %s for %s from data on channel %s\n",
+				ast_channel_peeraccount(chan2), ast_channel_name(chan1), ast_channel_name(chan2));
+		ast_channel_accountcode_set(chan1, ast_channel_peeraccount(chan2));
+	}
+	if (0 != strcmp(ast_channel_accountcode(chan1), ast_channel_peeraccount(chan2))) {
+		ast_debug(1, "changing peeraccount from %s to %s on %s to match channel %s\n",
+				ast_channel_peeraccount(chan2), ast_channel_peeraccount(chan1), ast_channel_name(chan2), ast_channel_name(chan1));
+		ast_channel_peeraccount_set(chan2, ast_channel_accountcode(chan1));
+	}
+	if (0 != strcmp(ast_channel_accountcode(chan2), ast_channel_peeraccount(chan1))) {
+		ast_debug(1, "changing peeraccount from %s to %s on %s to match channel %s\n",
+				ast_channel_peeraccount(chan1), ast_channel_peeraccount(chan2), ast_channel_name(chan1), ast_channel_name(chan2));
+		ast_channel_peeraccount_set(chan1, ast_channel_accountcode(chan2));
+	}
+}
+
+/*!
+ * \pre chan is locked
+ */
+static void report_new_callerid(struct ast_channel *chan)
+{
+	int pres;
+
+	pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel receives new Caller ID information.</synopsis>
+			<syntax>
+				<parameter name="CID-CallingPres">
+					<para>A description of the Caller ID presentation.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "NewCallerid",
+		"Channel: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"CID-CallingPres: %d (%s)\r\n",
+		ast_channel_name(chan),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
+		ast_channel_uniqueid(chan),
+		pres,
+		ast_describe_caller_presentation(pres)
+		);
+}
+
+/*!
+ * \internal
+ * \brief Transfer COLP between target and transferee channels.
+ * \since 1.8
+ *
+ * \param transferee Transferee channel to exchange connected line information.
+ * \param colp Connected line information to exchange.
+ *
+ * \return Nothing
+ */
+static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer_masquerade_ds *colp)
+{
+	struct ast_control_read_action_payload *frame_payload;
+	int payload_size;
+	int frame_size;
+	unsigned char connected_line_data[1024];
+
+	/* Release any hold on the target. */
+	if (colp->target_held) {
+		ast_queue_control(transferee, AST_CONTROL_UNHOLD);
+	}
+
+	/*
+	 * Since transferee may not actually be bridged to another channel,
+	 * there is no way for us to queue a frame so that its connected
+	 * line status will be updated.  Instead, we use the somewhat
+	 * hackish approach of using a special control frame type that
+	 * instructs ast_read() to perform a specific action.  In this
+	 * case, the frame we queue tells ast_read() to call the
+	 * connected line interception macro configured for transferee.
+	 */
+
+	/* Reset any earlier private connected id representation */
+	ast_party_id_reset(&colp->target_id.priv);
+	ast_party_id_reset(&colp->transferee_id.priv);
+
+	payload_size = ast_connected_line_build_data(connected_line_data,
+		sizeof(connected_line_data), &colp->target_id, NULL);
+	if (payload_size != -1) {
+		frame_size = payload_size + sizeof(*frame_payload);
+		frame_payload = ast_alloca(frame_size);
+		frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
+		frame_payload->payload_size = payload_size;
+		memcpy(frame_payload->payload, connected_line_data, payload_size);
+		ast_queue_control_data(transferee, AST_CONTROL_READ_ACTION, frame_payload,
+			frame_size);
+	}
+	/*
+	 * In addition to queueing the read action frame so that the
+	 * connected line info on transferee will be updated, we also are
+	 * going to queue a plain old connected line update on transferee to
+	 * update the target.
+	 */
+	ast_channel_queue_connected_line_update(transferee, &colp->transferee_id, NULL);
+}
+
 /*!
  * \brief Masquerade a channel
  *
@@ -6417,15 +6842,15 @@ void ast_channel_name_to_dial_string(char *channel_name)
  *       this function, it invalidates our channel container locking order.  All channels
  *       must be unlocked before it is permissible to lock the channels' ao2 container.
  */
-static void channel_do_masquerade(struct ast_channel *original, struct ast_channel *clonechan)
+int ast_do_masquerade(struct ast_channel *original)
 {
 	int x;
 	int origstate;
 	unsigned int orig_disablestatecache;
 	unsigned int clone_disablestatecache;
 	int visible_indication;
-	int clone_hold_state;
 	int moh_is_playing;
+	int clone_was_zombie = 0;/*!< TRUE if the clonechan was a zombie before the masquerade. */
 	struct ast_frame *current;
 	const struct ast_channel_tech *t;
 	void *t_pvt;
@@ -6436,12 +6861,18 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 		struct ast_party_connected_line connected;
 		struct ast_party_redirecting redirecting;
 	} exchange;
+	struct ast_channel *clonechan, *chans[2];
 	struct ast_channel *bridged;
-	struct ast_format *rformat;
-	struct ast_format *wformat;
-	struct ast_format *tmp_format;
-	struct ast_format_cap *tmp_cap;
-	char tmp_name[AST_CHANNEL_NAME];
+	struct ast_cdr *cdr;
+	struct ast_datastore *xfer_ds;
+	struct xfer_masquerade_ds *xfer_colp;
+	struct ast_format rformat;
+	struct ast_format wformat;
+	struct ast_format tmp_format;
+	char newn[AST_CHANNEL_NAME];
+	char orig[AST_CHANNEL_NAME];
+	char masqn[AST_CHANNEL_NAME];
+	char zombn[AST_CHANNEL_NAME];
 	char clone_sending_dtmf_digit;
 	struct timeval clone_sending_dtmf_tv;
 
@@ -6450,25 +6881,52 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	 * original channel's backend.  While the features are nice, which is the
 	 * reason we're keeping it, it's still awesomely weird. XXX */
 
-	/* Indicate to each channel that a masquerade is about to begin. */
-	x = 1;
-	ast_indicate_data(original, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
-	ast_indicate_data(clonechan, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
-
 	/*
-	 * The container lock is necessary for proper locking order
-	 * because the channels must be unlinked to change their
+	 * The reasoning for the channels ao2_container lock here is
+	 * complex.
+	 *
+	 * There is a race condition that exists for this function.
+	 * Since all pvt and channel locks must be let go before calling
+	 * ast_do_masquerade, it is possible that it could be called
+	 * multiple times for the same channel.  In order to prevent the
+	 * race condition with competing threads to do the masquerade
+	 * and new masquerade attempts, the channels container must be
+	 * locked for the entire masquerade.  The original and clonechan
+	 * need to be unlocked earlier to avoid potential deadlocks with
+	 * the chan_local deadlock avoidance method.
+	 *
+	 * The container lock blocks competing masquerade attempts from
+	 * starting as well as being necessary for proper locking order
+	 * because the channels must to be unlinked to change their
 	 * names.
 	 *
 	 * The original and clonechan locks must be held while the
 	 * channel contents are shuffled around for the masquerade.
 	 *
-	 * The masq and masqr pointers need to be left alone until the masquerade
-	 * has restabilized the channels to hold off ast_hangup() and until
-	 * AST_FLAG_ZOMBIE can be set on the clonechan.
+	 * The masq and masqr pointers need to be left alone until the
+	 * masquerade has restabilized the channels to prevent another
+	 * masquerade request until the AST_FLAG_ZOMBIE can be set on
+	 * the clonechan.
 	 */
 	ao2_lock(channels);
 
+	/*
+	 * Lock the original channel to determine if the masquerade is
+	 * still required.
+	 */
+	ast_channel_lock(original);
+
+	clonechan = ast_channel_masq(original);
+	if (!clonechan) {
+		/*
+		 * The masq is already completed by another thread or never
+		 * needed to be done to begin with.
+		 */
+		ast_channel_unlock(original);
+		ao2_unlock(channels);
+		return 0;
+	}
+
 	/* Bump the refs to ensure that they won't dissapear on us. */
 	ast_channel_ref(original);
 	ast_channel_ref(clonechan);
@@ -6477,57 +6935,95 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	ao2_unlink(channels, original);
 	ao2_unlink(channels, clonechan);
 
-	moh_is_playing = ast_test_flag(ast_channel_flags(original), AST_FLAG_MOH);
-	if (moh_is_playing) {
-		/* Stop MOH on the old original channel. */
-		ast_moh_stop(original);
+	/* Get any transfer masquerade connected line exchange data. */
+	xfer_ds = ast_channel_datastore_find(original, &xfer_ds_info, NULL);
+	if (xfer_ds) {
+		ast_channel_datastore_remove(original, xfer_ds);
+		xfer_colp = xfer_ds->data;
+	} else {
+		xfer_colp = NULL;
 	}
 
+	moh_is_playing = ast_test_flag(ast_channel_flags(original), AST_FLAG_MOH);
+
 	/*
 	 * Stop any visible indication on the original channel so we can
 	 * transfer it to the clonechan taking the original's place.
 	 */
-	ast_channel_lock(original);
 	visible_indication = ast_channel_visible_indication(original);
 	ast_channel_unlock(original);
 	ast_indicate(original, -1);
 
+	/*
+	 * Release any hold on the transferee channel before going any
+	 * further with the masquerade.
+	 */
+	if (xfer_colp && xfer_colp->transferee_held) {
+		ast_indicate(clonechan, AST_CONTROL_UNHOLD);
+	}
+
 	/* Start the masquerade channel contents rearangement. */
 	ast_channel_lock_both(original, clonechan);
 
-	ast_debug(1, "Actually Masquerading %s(%u) into the structure of %s(%u)\n",
-		ast_channel_name(clonechan), ast_channel_state(clonechan),
-		ast_channel_name(original), ast_channel_state(original));
+	ast_debug(4, "Actually Masquerading %s(%u) into the structure of %s(%u)\n",
+		ast_channel_name(clonechan), ast_channel_state(clonechan), ast_channel_name(original), ast_channel_state(original));
+
+	chans[0] = clonechan;
+	chans[1] = original;
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a masquerade occurs between two channels, wherein the Clone channel's internal information replaces the Original channel's information.</synopsis>
+			<syntax>
+				<parameter name="Clone">
+					<para>The name of the channel whose information will be going into the Original channel.</para>
+				</parameter>
+				<parameter name="CloneState">
+					<para>The current state of the clone channel.</para>
+				</parameter>
+				<parameter name="Original">
+					<para>The name of the channel whose information will be replaced by the Clone channel's information.</para>
+				</parameter>
+				<parameter name="OriginalState">
+					<para>The current state of the original channel.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "Masquerade", 2, chans,
+		"Clone: %s\r\n"
+		"CloneState: %s\r\n"
+		"Original: %s\r\n"
+		"OriginalState: %s\r\n",
+		ast_channel_name(clonechan), ast_state2str(ast_channel_state(clonechan)), ast_channel_name(original), ast_state2str(ast_channel_state(original)));
 
 	/*
 	 * Remember the original read/write formats.  We turn off any
 	 * translation on either one
 	 */
-	rformat = ao2_bump(ast_channel_readformat(original));
-	wformat = ao2_bump(ast_channel_writeformat(original));
+	ast_format_copy(&rformat, ast_channel_readformat(original));
+	ast_format_copy(&wformat, ast_channel_writeformat(original));
 	free_translation(clonechan);
 	free_translation(original);
 
-	clone_hold_state = ast_channel_hold_state(clonechan);
-
 	/* Save the current DTMF digit being sent if any. */
 	clone_sending_dtmf_digit = ast_channel_sending_dtmf_digit(clonechan);
 	clone_sending_dtmf_tv = ast_channel_sending_dtmf_tv(clonechan);
 
-	/* Swap uniqueid's of the channels. This needs to happen before channel renames,
-	 * so rename events get the proper id's.
-	 */
-	ast_channel_internal_swap_uniqueid_and_linkedid(clonechan, original);
+	/* Save the original name */
+	ast_copy_string(orig, ast_channel_name(original), sizeof(orig));
+	/* Save the new name */
+	ast_copy_string(newn, ast_channel_name(clonechan), sizeof(newn));
+	/* Create the masq name */
+	snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
 
-	/* Make sure the Stasis topic on the channel is updated appropriately */
-	ast_channel_internal_swap_topics(clonechan, original);
+	/* Mangle the name of the clone channel */
+	__ast_change_name_nolink(clonechan, masqn);
 
-	/* Swap channel names. This uses ast_channel_name_set directly, so we
-	 * don't get any spurious rename events.
-	 */
-	ast_copy_string(tmp_name, ast_channel_name(clonechan), sizeof(tmp_name));
-	ast_channel_name_set(clonechan, ast_channel_name(original));
-	ast_channel_name_set(original, tmp_name);
+	/* Copy the name from the clone channel */
+	__ast_change_name_nolink(original, newn);
+
+	/* share linked id's */
+	ast_channel_set_linkgroup(original, clonechan);
 
 	/* Swap the technologies */
 	t = ast_channel_tech(original);
@@ -6538,6 +7034,11 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	ast_channel_tech_pvt_set(original, ast_channel_tech_pvt(clonechan));
 	ast_channel_tech_pvt_set(clonechan, t_pvt);
 
+	/* Swap the cdrs */
+	cdr = ast_channel_cdr(original);
+	ast_channel_cdr_set(original, ast_channel_cdr(clonechan));
+	ast_channel_cdr_set(clonechan, cdr);
+
 	/* Swap the alertpipes */
 	ast_channel_internal_alertpipe_swap(original, clonechan);
 
@@ -6568,15 +7069,13 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	}
 
 	/* Swap the raw formats */
-	tmp_format = ao2_bump(ast_channel_rawreadformat(original));
-	ast_channel_set_rawreadformat(original, ast_channel_rawreadformat(clonechan));
-	ast_channel_set_rawreadformat(clonechan, tmp_format);
-	ao2_cleanup(tmp_format);
+	ast_format_copy(&tmp_format, ast_channel_rawreadformat(original));
+	ast_format_copy(ast_channel_rawreadformat(original), ast_channel_rawreadformat(clonechan));
+	ast_format_copy(ast_channel_rawreadformat(clonechan), &tmp_format);
 
-	tmp_format = ao2_bump(ast_channel_rawwriteformat(original));
-	ast_channel_set_rawwriteformat(original, ast_channel_rawwriteformat(clonechan));
-	ast_channel_set_rawwriteformat(clonechan, tmp_format);
-	ao2_cleanup(tmp_format);
+	ast_format_copy(&tmp_format, ast_channel_rawwriteformat(original));
+	ast_format_copy(ast_channel_rawwriteformat(original), ast_channel_rawwriteformat(clonechan));
+	ast_format_copy(ast_channel_rawwriteformat(clonechan), &tmp_format);
 
 	ast_channel_softhangup_internal_flag_set(clonechan, AST_SOFTHANGUP_DEV);
 
@@ -6602,6 +7101,10 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 		}
 	}
 
+	/* Mangle the name of the clone channel */
+	snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig); /* quick, hide the brains! */
+	__ast_change_name_nolink(clonechan, zombn);
+
 	/* Update the type. */
 	t_pvt = ast_channel_monitor(original);
 	ast_channel_monitor_set(original, ast_channel_monitor(clonechan));
@@ -6626,45 +7129,20 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	*ast_channel_hangup_handlers(original) = *ast_channel_hangup_handlers(clonechan);
 	*ast_channel_hangup_handlers(clonechan) = exchange.handlers;
 
-	/* Call fixup handlers for the clone chan */
+	/* Move data stores over */
 	if (AST_LIST_FIRST(ast_channel_datastores(clonechan))) {
 		struct ast_datastore *ds;
 		/* We use a safe traversal here because some fixup routines actually
 		 * remove the datastore from the list and free them.
 		 */
 		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_datastores(clonechan), ds, entry) {
-			if (ds->info->chan_fixup) {
+			if (ds->info->chan_fixup)
 				ds->info->chan_fixup(ds->data, clonechan, original);
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-	}
-
-	/* Call breakdown handlers for the original chan */
-	if (AST_LIST_FIRST(ast_channel_datastores(original))) {
-		struct ast_datastore *ds;
-		/* We use a safe traversal here because some breakdown routines may
-		 * remove the datastore from the list and free them.
-		 */
-		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_datastores(original), ds, entry) {
-			if (ds->info->chan_breakdown) {
-				ds->info->chan_breakdown(ds->data, clonechan, original);
-			}
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
-	}
-
-	/* Move data stores over */
-	if (AST_LIST_FIRST(ast_channel_datastores(clonechan))) {
 		AST_LIST_APPEND_LIST(ast_channel_datastores(original), ast_channel_datastores(clonechan), entry);
 	}
 
-	/* Move framehooks over */
-	ast_framehook_list_fixup(clonechan, original);
-
-	/* Move audiohooks over */
-	ast_audiohook_move_all(clonechan, original);
-
 	ast_autochan_new_channel(clonechan, original);
 
 	clone_variables(original, clonechan);
@@ -6717,36 +7195,36 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	ast_channel_redirecting_set(original, ast_channel_redirecting(clonechan));
 	ast_channel_redirecting_set(clonechan, &exchange.redirecting);
 
-	ast_channel_publish_snapshot(original);
+	report_new_callerid(original);
 
 	/* Restore original timing file descriptor */
 	ast_channel_set_fd(original, AST_TIMING_FD, ast_channel_timingfd(original));
 
 	/* Our native formats are different now */
-	tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (tmp_cap) {
-		ast_format_cap_append_from_cap(tmp_cap, ast_channel_nativeformats(clonechan), AST_MEDIA_TYPE_UNKNOWN);
-		ast_channel_nativeformats_set(original, tmp_cap);
-		ao2_ref(tmp_cap, -1);
-	}
+	ast_format_cap_copy(ast_channel_nativeformats(original), ast_channel_nativeformats(clonechan));
 
 	/* Context, extension, priority, app data, jump table,  remain the same */
 	/* pvt switches.  pbx stays the same, as does next */
 
 	/* Set the write format */
-	ast_set_write_format(original, wformat);
+	ast_set_write_format(original, &wformat);
 
 	/* Set the read format */
-	ast_set_read_format(original, rformat);
+	ast_set_read_format(original, &rformat);
 
 	/* Copy the music class */
 	ast_channel_musicclass_set(original, ast_channel_musicclass(clonechan));
 
 	/* copy over accuntcode and set peeraccount across the bridge */
 	ast_channel_accountcode_set(original, S_OR(ast_channel_accountcode(clonechan), ""));
+	if (ast_channel_internal_bridged_channel(original)) {
+		/* XXX - should we try to lock original's bridged channel here? */
+		ast_channel_peeraccount_set(ast_channel_internal_bridged_channel(original), S_OR(ast_channel_accountcode(clonechan), ""));
+		ast_cel_report_event(original, AST_CEL_BRIDGE_UPDATE, NULL, NULL, NULL);
+	}
 
 	ast_debug(1, "Putting channel %s in %s/%s formats\n", ast_channel_name(original),
-		ast_format_get_name(wformat), ast_format_get_name(rformat));
+		ast_getformatname(&wformat), ast_getformatname(&rformat));
 
 	/* Fixup the original clonechan's physical side */
 	if (ast_channel_tech(original)->fixup && ast_channel_tech(original)->fixup(clonechan, original)) {
@@ -6762,204 +7240,911 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 
 	/*
 	 * Now, at this point, the "clone" channel is totally F'd up.
-	 * We mark it as a zombie so nothing tries to touch it.
+	 * We mark it as a zombie so nothing tries to touch it.  If it's
+	 * already been marked as a zombie, then we must free it (since
+	 * it already is considered invalid).
 	 *
 	 * This must be done before we unlock clonechan to prevent
 	 * setting up another masquerade on the clonechan.
 	 */
-	ast_set_flag(ast_channel_flags(clonechan), AST_FLAG_ZOMBIE);
-	ast_queue_frame(clonechan, &ast_null_frame);
+	if (ast_test_flag(ast_channel_flags(clonechan), AST_FLAG_ZOMBIE)) {
+		clone_was_zombie = 1;
+	} else {
+		ast_set_flag(ast_channel_flags(clonechan), AST_FLAG_ZOMBIE);
+		ast_queue_frame(clonechan, &ast_null_frame);
+	}
+
+	/* clear the masquerade channels */
+	ast_channel_masq_set(original, NULL);
+	ast_channel_masqr_set(clonechan, NULL);
+
+	/*
+	 * When we unlock original here, it can be immediately setup to
+	 * masquerade again or hungup.  The new masquerade or hangup
+	 * will not actually happen until we release the channels
+	 * container lock.
+	 */
+	ast_channel_unlock(original);
+	ast_channel_unlock(clonechan);
+
+	if (clone_sending_dtmf_digit) {
+		/*
+		 * The clonechan was sending a DTMF digit that was not completed
+		 * before the masquerade.
+		 */
+		ast_bridge_end_dtmf(original, clone_sending_dtmf_digit, clone_sending_dtmf_tv,
+			"masquerade");
+	}
+
+	/*
+	 * If an indication is currently playing, maintain it on the
+	 * channel that is taking the place of original.
+	 *
+	 * This is needed because the masquerade is swapping out the
+	 * internals of the channel, and the new channel private data
+	 * needs to be made aware of the current visible indication
+	 * (RINGING, CONGESTION, etc.)
+	 */
+	if (visible_indication) {
+		ast_indicate(original, visible_indication);
+	}
+
+	/* if moh is playing on the original channel then it needs to be
+	   maintained on the channel that is replacing it. */
+	if (moh_is_playing) {
+		ast_moh_start(original, NULL, NULL);
+	}
+
+	ast_channel_lock(original);
+
+	/* Signal any blocker */
+	if (ast_test_flag(ast_channel_flags(original), AST_FLAG_BLOCKING)) {
+		pthread_kill(ast_channel_blocker(original), SIGURG);
+	}
+
+	ast_debug(1, "Done Masquerading %s (%u)\n", ast_channel_name(original), ast_channel_state(original));
+
+	if ((bridged = ast_bridged_channel(original))) {
+		ast_channel_ref(bridged);
+		ast_channel_unlock(original);
+		ast_indicate(bridged, AST_CONTROL_SRCCHANGE);
+		ast_channel_unref(bridged);
+	} else {
+		ast_channel_unlock(original);
+	}
+	ast_indicate(original, AST_CONTROL_SRCCHANGE);
+
+	if (xfer_colp) {
+		/*
+		 * After the masquerade, the original channel pointer actually
+		 * points to the new transferee channel and the bridged channel
+		 * is still the intended transfer target party.
+		 */
+		masquerade_colp_transfer(original, xfer_colp);
+	}
+
+	if (xfer_ds) {
+		ast_datastore_free(xfer_ds);
+	}
+
+	if (!clone_was_zombie) {
+		ao2_link(channels, clonechan);
+	}
+	ao2_link(channels, original);
+	ao2_unlock(channels);
+
+	if (clone_was_zombie) {
+		/* Restart the ast_hangup() that was deferred because of this masquerade. */
+		ast_debug(1, "Destroying channel clone '%s'\n", ast_channel_name(clonechan));
+		ast_hangup(clonechan);
+	}
+
+	/* Release our held safety references. */
+	ast_channel_unref(original);
+	ast_channel_unref(clonechan);
+
+	return 0;
+}
+
+void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
+{
+	ast_channel_lock(chan);
+
+	if (cid_num) {
+		ast_channel_caller(chan)->id.number.valid = 1;
+		ast_free(ast_channel_caller(chan)->id.number.str);
+		ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
+	}
+	if (cid_name) {
+		ast_channel_caller(chan)->id.name.valid = 1;
+		ast_free(ast_channel_caller(chan)->id.name.str);
+		ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
+	}
+	if (cid_ani) {
+		ast_channel_caller(chan)->ani.number.valid = 1;
+		ast_free(ast_channel_caller(chan)->ani.number.str);
+		ast_channel_caller(chan)->ani.number.str = ast_strdup(cid_ani);
+	}
+	if (ast_channel_cdr(chan)) {
+		ast_cdr_setcid(ast_channel_cdr(chan), chan);
+	}
+
+	report_new_callerid(chan);
+
+	ast_channel_unlock(chan);
+}
+
+void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
+{
+	if (ast_channel_caller(chan) == caller) {
+		/* Don't set to self */
+		return;
+	}
+
+	ast_channel_lock(chan);
+	ast_party_caller_set(ast_channel_caller(chan), caller, update);
+	ast_channel_unlock(chan);
+}
+
+void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
+{
+	const char *old_number;
+	const char *old_name;
+	const char *new_number;
+	const char *new_name;
+
+	if (ast_channel_caller(chan) == caller) {
+		/* Don't set to self */
+		return;
+	}
+
+	ast_channel_lock(chan);
+	old_number = ast_strdupa(S_COR(ast_channel_caller(chan)->id.number.valid,
+		ast_channel_caller(chan)->id.number.str, ""));
+	old_name = ast_strdupa(S_COR(ast_channel_caller(chan)->id.name.valid,
+		ast_channel_caller(chan)->id.name.str, ""));
+
+	ast_party_caller_set(ast_channel_caller(chan), caller, update);
+
+	new_number = S_COR(ast_channel_caller(chan)->id.number.valid,
+		ast_channel_caller(chan)->id.number.str, "");
+	new_name = S_COR(ast_channel_caller(chan)->id.name.valid,
+		ast_channel_caller(chan)->id.name.str, "");
+
+	if (0 != strcmp(old_number, new_number) || 0 != strcmp(old_name, new_name)) {
+		/* The caller id name or number changed. */
+		report_new_callerid(chan);
+	}
+	if (ast_channel_cdr(chan)) {
+		ast_cdr_setcid(ast_channel_cdr(chan), chan);
+	}
+	ast_channel_unlock(chan);
+}
+
+int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
+{
+	int oldstate = ast_channel_state(chan);
+	char name[AST_CHANNEL_NAME], *dashptr;
+
+	if (oldstate == state)
+		return 0;
+
+	ast_copy_string(name, ast_channel_name(chan), sizeof(name));
+	if ((dashptr = strrchr(name, '-'))) {
+		*dashptr = '\0';
+	}
+
+	ast_channel_state_set(chan, state);
+
+	/* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
+	 * for this channel is using the callback method for device state. If we pass in an actual state here
+	 * we override what they are saying the state is and things go amuck. */
+	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
+
+	/* setstate used to conditionally report Newchannel; this is no more */
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a channel's state changes.</synopsis>
+			<syntax>
+				<parameter name="ChannelState">
+					<para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+				</parameter>
+				<parameter name="ChannelStateDesc">
+					<enumlist>
+						<enum name="Down"/>
+						<enum name="Rsrvd"/>
+						<enum name="OffHook"/>
+						<enum name="Dialing"/>
+						<enum name="Ring"/>
+						<enum name="Ringing"/>
+						<enum name="Up"/>
+						<enum name="Busy"/>
+						<enum name="Dialing Offhook"/>
+						<enum name="Pre-ring"/>
+						<enum name="Unknown"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate",
+		"Channel: %s\r\n"
+		"ChannelState: %u\r\n"
+		"ChannelStateDesc: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"Uniqueid: %s\r\n",
+		ast_channel_name(chan), ast_channel_state(chan), ast_state2str(ast_channel_state(chan)),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
+		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""),
+		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""),
+		ast_channel_uniqueid(chan));
+
+	return 0;
+}
+
+/*! \brief Find bridged channel */
+struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
+{
+	struct ast_channel *bridged;
+	bridged = ast_channel_internal_bridged_channel(chan);
+	if (bridged && ast_channel_tech(bridged)->bridged_channel)
+		bridged = ast_channel_tech(bridged)->bridged_channel(chan, bridged);
+	return bridged;
+}
+
+static void bridge_playfile(struct ast_channel *chan, struct ast_channel *peer, const char *sound, int remain)
+{
+	int min = 0, sec = 0, check;
+
+	check = ast_autoservice_start(peer);
+	if (check)
+		return;
+
+	if (remain > 0) {
+		if (remain / 60 > 1) {
+			min = remain / 60;
+			sec = remain % 60;
+		} else {
+			sec = remain;
+		}
+	}
+
+	if (!strcmp(sound,"timeleft")) {	/* Queue support */
+		ast_stream_and_wait(chan, "vm-youhave", "");
+		if (min) {
+			ast_say_number(chan, min, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
+			ast_stream_and_wait(chan, "queue-minutes", "");
+		}
+		if (sec) {
+			ast_say_number(chan, sec, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
+			ast_stream_and_wait(chan, "queue-seconds", "");
+		}
+	} else {
+		ast_stream_and_wait(chan, sound, "");
+	}
+
+	ast_autoservice_stop(peer);
+}
+
+static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_channel *c1,
+						 struct ast_bridge_config *config, struct ast_frame **fo,
+						 struct ast_channel **rc)
+{
+	/* Copy voice back and forth between the two channels. */
+	struct ast_channel *cs[3];
+	struct ast_frame *f;
+	enum ast_bridge_result res = AST_BRIDGE_COMPLETE;
+	struct ast_format_cap *o0nativeformats;
+	struct ast_format_cap *o1nativeformats;
+	int watch_c0_dtmf;
+	int watch_c1_dtmf;
+	void *pvt0, *pvt1;
+	/* Indicates whether a frame was queued into a jitterbuffer */
+	int frame_put_in_jb = 0;
+	int jb_in_use;
+	int to;
+
+	o0nativeformats = ast_format_cap_dup(ast_channel_nativeformats(c0));
+	o1nativeformats = ast_format_cap_dup(ast_channel_nativeformats(c1));
+
+	if (!o0nativeformats || !o1nativeformats) {
+		ast_format_cap_destroy(o0nativeformats); /* NULL safe */
+		ast_format_cap_destroy(o1nativeformats); /* NULL safe */
+		return AST_BRIDGE_FAILED;
+	}
+
+	cs[0] = c0;
+	cs[1] = c1;
+	pvt0 = ast_channel_tech_pvt(c0);
+	pvt1 = ast_channel_tech_pvt(c1);
+	watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
+	watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;
+
+	/* Check the need of a jitterbuffer for each channel */
+	jb_in_use = ast_jb_do_usecheck(c0, c1);
+	if (jb_in_use)
+		ast_jb_empty_and_reset(c0, c1);
+
+	ast_poll_channel_add(c0, c1);
+
+	if (config->feature_timer > 0 && ast_tvzero(config->nexteventts)) {
+		/* nexteventts is not set when the bridge is not scheduled to
+		 * break, so calculate when the bridge should possibly break
+		 * if a partial feature match timed out */
+		config->nexteventts = ast_tvadd(ast_tvnow(), ast_samp2tv(config->feature_timer, 1000));
+	}
+
+	for (;;) {
+		struct ast_channel *who, *other;
+
+		if ((ast_channel_tech_pvt(c0) != pvt0) || (ast_channel_tech_pvt(c1) != pvt1) ||
+		    (!ast_format_cap_identical(o0nativeformats, ast_channel_nativeformats(c0))) ||
+		    (!ast_format_cap_identical(o1nativeformats, ast_channel_nativeformats(c1)))) {
+			/* Check for Masquerade, codec changes, etc */
+			res = AST_BRIDGE_RETRY;
+			break;
+		}
+		if (config->nexteventts.tv_sec) {
+			to = ast_tvdiff_ms(config->nexteventts, ast_tvnow());
+			if (to <= 0) {
+				if (config->timelimit && !config->feature_timer && !ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
+					res = AST_BRIDGE_RETRY;
+					/* generic bridge ending to play warning */
+					ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
+				} else if (config->feature_timer) {
+					/* feature timer expired - make sure we do not play warning */
+					ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
+					res = AST_BRIDGE_RETRY;
+				} else {
+					res = AST_BRIDGE_COMPLETE;
+				}
+				break;
+			}
+		} else {
+			/* If a feature has been started and the bridge is configured to
+			 * to not break, leave the channel bridge when the feature timer
+			 * time has elapsed so the DTMF will be sent to the other side.
+			 */
+			if (!ast_tvzero(config->nexteventts)) {
+				int diff = ast_tvdiff_ms(config->nexteventts, ast_tvnow());
+				if (diff <= 0) {
+					res = AST_BRIDGE_RETRY;
+					break;
+				}
+			}
+			to = -1;
+		}
+		/* Calculate the appropriate max sleep interval - in general, this is the time,
+		   left to the closest jb delivery moment */
+		if (jb_in_use)
+			to = ast_jb_get_when_to_wakeup(c0, c1, to);
+		who = ast_waitfor_n(cs, 2, &to);
+		if (!who) {
+			/* No frame received within the specified timeout - check if we have to deliver now */
+			if (jb_in_use)
+				ast_jb_get_and_deliver(c0, c1);
+			if ((ast_channel_softhangup_internal_flag(c0) | ast_channel_softhangup_internal_flag(c1)) & AST_SOFTHANGUP_UNBRIDGE) {/* Bit operators are intentional. */
+				if (ast_channel_softhangup_internal_flag(c0) & AST_SOFTHANGUP_UNBRIDGE) {
+					ast_channel_clear_softhangup(c0, AST_SOFTHANGUP_UNBRIDGE);
+				}
+				if (ast_channel_softhangup_internal_flag(c1) & AST_SOFTHANGUP_UNBRIDGE) {
+					ast_channel_clear_softhangup(c1, AST_SOFTHANGUP_UNBRIDGE);
+				}
+				ast_channel_lock_both(c0, c1);
+				ast_channel_internal_bridged_channel_set(c0, c1);
+				ast_channel_internal_bridged_channel_set(c1, c0);
+				ast_channel_unlock(c0);
+				ast_channel_unlock(c1);
+			}
+			continue;
+		}
+		f = ast_read(who);
+		if (!f) {
+			*fo = NULL;
+			*rc = who;
+			ast_debug(1, "Didn't get a frame from channel: %s\n", ast_channel_name(who));
+			break;
+		}
+
+		other = (who == c0) ? c1 : c0; /* the 'other' channel */
+		/* Try add the frame info the who's bridged channel jitterbuff */
+		if (jb_in_use)
+			frame_put_in_jb = !ast_jb_put(other, f);
+
+		if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) {
+			int bridge_exit = 0;
+
+			switch (f->subclass.integer) {
+			case AST_CONTROL_PVT_CAUSE_CODE:
+			case AST_CONTROL_AOC:
+			case AST_CONTROL_MCID:
+				ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				break;
+			case AST_CONTROL_REDIRECTING:
+				if (ast_channel_redirecting_sub(who, other, f, 1) &&
+					ast_channel_redirecting_macro(who, other, f, other == c0, 1)) {
+					ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				}
+				break;
+			case AST_CONTROL_CONNECTED_LINE:
+				if (ast_channel_connected_line_sub(who, other, f, 1) &&
+					ast_channel_connected_line_macro(who, other, f, other == c0, 1)) {
+					ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				}
+				break;
+			case AST_CONTROL_HOLD:
+			case AST_CONTROL_UNHOLD:
+			case AST_CONTROL_VIDUPDATE:
+			case AST_CONTROL_SRCUPDATE:
+			case AST_CONTROL_SRCCHANGE:
+			case AST_CONTROL_T38_PARAMETERS:
+				ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				if (jb_in_use) {
+					ast_jb_empty_and_reset(c0, c1);
+				}
+				break;
+			default:
+				*fo = f;
+				*rc = who;
+				bridge_exit = 1;
+				ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass.integer, ast_channel_name(who));
+				break;
+			}
+			if (bridge_exit)
+				break;
+		}
+		if ((f->frametype == AST_FRAME_VOICE) ||
+		    (f->frametype == AST_FRAME_DTMF_BEGIN) ||
+		    (f->frametype == AST_FRAME_DTMF) ||
+		    (f->frametype == AST_FRAME_VIDEO) ||
+		    (f->frametype == AST_FRAME_IMAGE) ||
+		    (f->frametype == AST_FRAME_HTML) ||
+		    (f->frametype == AST_FRAME_MODEM) ||
+		    (f->frametype == AST_FRAME_TEXT)) {
+			/* monitored dtmf causes exit from bridge */
+			int monitored_source = (who == c0) ? watch_c0_dtmf : watch_c1_dtmf;
+
+			if (monitored_source &&
+				(f->frametype == AST_FRAME_DTMF_END ||
+				f->frametype == AST_FRAME_DTMF_BEGIN)) {
+				*fo = f;
+				*rc = who;
+				ast_debug(1, "Got DTMF %s on channel (%s)\n",
+					f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
+					ast_channel_name(who));
+
+				break;
+			}
+			/* Write immediately frames, not passed through jb */
+			if (!frame_put_in_jb)
+				ast_write(other, f);
+
+			/* Check if we have to deliver now */
+			if (jb_in_use)
+				ast_jb_get_and_deliver(c0, c1);
+		}
+		/* XXX do we want to pass on also frames not matched above ? */
+		ast_frfree(f);
+
+#ifndef HAVE_EPOLL
+		/* Swap who gets priority */
+		cs[2] = cs[0];
+		cs[0] = cs[1];
+		cs[1] = cs[2];
+#endif
+	}
+
+	ast_poll_channel_del(c0, c1);
+
+	ast_format_cap_destroy(o0nativeformats);
+	ast_format_cap_destroy(o1nativeformats);
+
+	return res;
+}
+
+/*! \brief Bridge two channels together (early) */
+int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
+{
+	/* Make sure we can early bridge, if not error out */
+	if (!ast_channel_tech(c0)->early_bridge || (c1 && (!ast_channel_tech(c1)->early_bridge || ast_channel_tech(c0)->early_bridge != ast_channel_tech(c1)->early_bridge)))
+		return -1;
+
+	return ast_channel_tech(c0)->early_bridge(c0, c1);
+}
+
+/*! \brief Send manager event for bridge link and unlink events.
+ * \param onoff Link/Unlinked
+ * \param type 1 for core, 2 for native
+ * \param c0 first channel in bridge
+ * \param c1 second channel in bridge
+*/
+static void manager_bridge_event(int onoff, int type, struct ast_channel *c0, struct ast_channel *c1)
+{
+	struct ast_channel *chans[2] = { c0, c1 };
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a bridge changes between two channels.</synopsis>
+			<syntax>
+				<parameter name="Bridgestate">
+					<enumlist>
+						<enum name="Link"/>
+						<enum name="Unlink"/>
+					</enumlist>
+				</parameter>
+				<parameter name="Bridgetype">
+					<enumlist>
+						<enum name="core"/>
+						<enum name="native"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "Bridge", 2, chans,
+		"Bridgestate: %s\r\n"
+		"Bridgetype: %s\r\n"
+		"Channel1: %s\r\n"
+		"Channel2: %s\r\n"
+		"Uniqueid1: %s\r\n"
+		"Uniqueid2: %s\r\n"
+		"CallerID1: %s\r\n"
+		"CallerID2: %s\r\n",
+		onoff ? "Link" : "Unlink",
+		type == 1 ? "core" : "native",
+		ast_channel_name(c0), ast_channel_name(c1),
+		ast_channel_uniqueid(c0), ast_channel_uniqueid(c1),
+		S_COR(ast_channel_caller(c0)->id.number.valid, ast_channel_caller(c0)->id.number.str, ""),
+		S_COR(ast_channel_caller(c1)->id.number.valid, ast_channel_caller(c1)->id.number.str, ""));
+}
+
+static void update_bridge_vars(struct ast_channel *c0, struct ast_channel *c1)
+{
+	const char *c0_name;
+	const char *c1_name;
+	const char *c0_pvtid = NULL;
+	const char *c1_pvtid = NULL;
+
+	ast_channel_lock(c1);
+	c1_name = ast_strdupa(ast_channel_name(c1));
+	if (ast_channel_tech(c1)->get_pvt_uniqueid) {
+		c1_pvtid = ast_strdupa(ast_channel_tech(c1)->get_pvt_uniqueid(c1));
+	}
+	ast_channel_unlock(c1);
+
+	ast_channel_lock(c0);
+	if (!ast_strlen_zero(pbx_builtin_getvar_helper(c0, "BRIDGEPEER"))) {
+		pbx_builtin_setvar_helper(c0, "BRIDGEPEER", c1_name);
+	}
+	if (c1_pvtid) {
+		pbx_builtin_setvar_helper(c0, "BRIDGEPVTCALLID", c1_pvtid);
+	}
+	c0_name = ast_strdupa(ast_channel_name(c0));
+	if (ast_channel_tech(c0)->get_pvt_uniqueid) {
+		c0_pvtid = ast_strdupa(ast_channel_tech(c0)->get_pvt_uniqueid(c0));
+	}
+	ast_channel_unlock(c0);
+
+	ast_channel_lock(c1);
+	if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER"))) {
+		pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0_name);
+	}
+	if (c0_pvtid) {
+		pbx_builtin_setvar_helper(c1, "BRIDGEPVTCALLID", c0_pvtid);
+	}
+	ast_channel_unlock(c1);
+}
+
+static void bridge_play_sounds(struct ast_channel *c0, struct ast_channel *c1)
+{
+	const char *s, *sound;
+
+	/* See if we need to play an audio file to any side of the bridge */
+
+	ast_channel_lock(c0);
+	if ((s = pbx_builtin_getvar_helper(c0, "BRIDGE_PLAY_SOUND"))) {
+		sound = ast_strdupa(s);
+		ast_channel_unlock(c0);
+		bridge_playfile(c0, c1, sound, 0);
+		pbx_builtin_setvar_helper(c0, "BRIDGE_PLAY_SOUND", NULL);
+	} else {
+		ast_channel_unlock(c0);
+	}
 
-	ast_channel_unlock(original);
-	ast_channel_unlock(clonechan);
+	ast_channel_lock(c1);
+	if ((s = pbx_builtin_getvar_helper(c1, "BRIDGE_PLAY_SOUND"))) {
+		sound = ast_strdupa(s);
+		ast_channel_unlock(c1);
+		bridge_playfile(c1, c0, sound, 0);
+		pbx_builtin_setvar_helper(c1, "BRIDGE_PLAY_SOUND", NULL);
+	} else {
+		ast_channel_unlock(c1);
+	}
+}
 
-	/*
-	 * Indicate to each channel that a masquerade is complete.
-	 *
-	 * We can still do this to clonechan even though it is a
-	 * zombie because ast_indicate_data() will explicitly pass
-	 * this control and ast_hangup() is held off until the
-	 * ast_channel_masq() and ast_channel_masqr() pointers are
-	 * cleared.
-	 */
-	x = 0;
-	ast_indicate_data(original, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
-	ast_indicate_data(clonechan, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
+/*! \brief Bridge two channels together */
+enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1,
+					  struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
+{
+	enum ast_bridge_result res = AST_BRIDGE_COMPLETE;
+	struct ast_format_cap *o0nativeformats;
+	struct ast_format_cap *o1nativeformats;
+	long time_left_ms=0;
+	char caller_warning = 0;
+	char callee_warning = 0;
 
-	ast_bridge_notify_masquerade(original);
+	*fo = NULL;
 
-	if (clone_hold_state == AST_CONTROL_HOLD) {
-		ast_debug(1, "Channel %s simulating UNHOLD for masquerade.\n",
-			ast_channel_name(original));
-		ast_indicate(original, AST_CONTROL_UNHOLD);
+	if (ast_channel_internal_bridged_channel(c0)) {
+		ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
+			ast_channel_name(c0), ast_channel_name(ast_channel_internal_bridged_channel(c0)));
+		return -1;
 	}
-	if (clone_sending_dtmf_digit) {
-		/*
-		 * The clonechan was sending a DTMF digit that was not completed
-		 * before the masquerade.
-		 */
-		ast_channel_end_dtmf(original, clone_sending_dtmf_digit, clone_sending_dtmf_tv,
-			"masquerade");
+	if (ast_channel_internal_bridged_channel(c1)) {
+		ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
+			ast_channel_name(c1), ast_channel_name(ast_channel_internal_bridged_channel(c1)));
+		return -1;
 	}
 
-	/*
-	 * If an indication is currently playing, maintain it on the
-	 * channel that is taking the place of original.
-	 *
-	 * This is needed because the masquerade is swapping out the
-	 * internals of the channel, and the new channel private data
-	 * needs to be made aware of the current visible indication
-	 * (RINGING, CONGESTION, etc.)
-	 */
-	if (visible_indication) {
-		if (visible_indication == AST_CONTROL_HOLD) {
-			const char *latest_musicclass;
-			int len;
+	/* Stop if we're a zombie or need a soft hangup */
+	if (ast_test_flag(ast_channel_flags(c0), AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) ||
+	    ast_test_flag(ast_channel_flags(c1), AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1))
+		return -1;
 
-			ast_channel_lock(original);
-			latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(original));
-			ast_channel_unlock(original);
-			if (ast_strlen_zero(latest_musicclass)) {
-				latest_musicclass = NULL;
-				len = 0;
-			} else {
-				len = strlen(latest_musicclass) + 1;
+	o0nativeformats = ast_format_cap_dup(ast_channel_nativeformats(c0));
+	o1nativeformats = ast_format_cap_dup(ast_channel_nativeformats(c1));
+	if (!o0nativeformats || !o1nativeformats) {
+		ast_format_cap_destroy(o0nativeformats);
+		ast_format_cap_destroy(o1nativeformats);
+		ast_log(LOG_WARNING, "failed to copy native formats\n");
+		return -1;
+	}
+
+	caller_warning = ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING);
+	callee_warning = ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING);
+
+	if (ast_tvzero(config->start_time)) {
+		config->start_time = ast_tvnow();
+		if (config->start_sound) {
+			if (caller_warning) {
+				bridge_playfile(c0, c1, config->start_sound, config->timelimit / 1000);
+			}
+			if (callee_warning) {
+				bridge_playfile(c1, c0, config->start_sound, config->timelimit / 1000);
 			}
-			ast_indicate_data(original, visible_indication, latest_musicclass, len);
-		} else {
-			ast_indicate(original, visible_indication);
 		}
 	}
 
-	/*
-	 * If MOH was playing on the original channel then it needs to be
-	 * maintained on the channel that is replacing it.
-	 */
-	if (moh_is_playing) {
-		/* Start MOH on the new original channel. */
-		ast_moh_start(original, NULL, NULL);
-	}
+	/* Keep track of bridge */
+	ast_channel_lock_both(c0, c1);
+	ast_channel_internal_bridged_channel_set(c0, c1);
+	ast_channel_internal_bridged_channel_set(c1, c0);
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
 
-	ast_channel_lock(original);
+	ast_set_owners_and_peers(c0, c1);
 
-	/* Signal any blocker */
-	if (ast_test_flag(ast_channel_flags(original), AST_FLAG_BLOCKING)) {
-		pthread_kill(ast_channel_blocker(original), SIGURG);
+	if (config->feature_timer && !ast_tvzero(config->nexteventts)) {
+		config->nexteventts = ast_tvadd(config->feature_start_time, ast_samp2tv(config->feature_timer, 1000));
+	} else if (config->timelimit) {
+		time_left_ms = config->timelimit - ast_tvdiff_ms(ast_tvnow(), config->start_time);
+		config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+		if ((caller_warning || callee_warning) && config->play_warning) {
+			long next_warn = config->play_warning;
+			if (time_left_ms < config->play_warning && config->warning_freq > 0) {
+				/* At least one warning was played, which means we are returning after feature */
+				long warns_passed = (config->play_warning - time_left_ms) / config->warning_freq;
+				/* It is 'warns_passed * warning_freq' NOT '(warns_passed + 1) * warning_freq',
+					because nexteventts will be updated once again in the 'if (!to)' block */
+				next_warn = config->play_warning - warns_passed * config->warning_freq;
+			}
+			config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(next_warn, 1000));
+		}
+	} else {
+		config->nexteventts.tv_sec = 0;
+		config->nexteventts.tv_usec = 0;
 	}
 
-	ast_debug(1, "Done Masquerading %s (%u)\n", ast_channel_name(original), ast_channel_state(original));
-	ast_channel_unlock(original);
+	if (!ast_channel_tech(c0)->send_digit_begin)
+		ast_set_flag(ast_channel_flags(c1), AST_FLAG_END_DTMF_ONLY);
+	if (!ast_channel_tech(c1)->send_digit_begin)
+		ast_set_flag(ast_channel_flags(c0), AST_FLAG_END_DTMF_ONLY);
+	manager_bridge_event(1, 1, c0, c1);
 
-	if ((bridged = ast_channel_bridge_peer(original))) {
-		ast_indicate(bridged, AST_CONTROL_SRCCHANGE);
-		ast_channel_unref(bridged);
-	}
-	ast_indicate(original, AST_CONTROL_SRCCHANGE);
+	/* Before we enter in and bridge these two together tell them both the source of audio has changed */
+	ast_indicate(c0, AST_CONTROL_SRCUPDATE);
+	ast_indicate(c1, AST_CONTROL_SRCUPDATE);
 
-	/* Now that the operation is complete, we can clear the masq
-	 * and masqr fields of both channels.
-	 */
-	ast_channel_lock_both(original, clonechan);
-	ast_channel_masq_set(original, NULL);
-	ast_channel_masqr_set(clonechan, NULL);
-	ast_channel_unlock(original);
-	ast_channel_unlock(clonechan);
+	for (/* ever */;;) {
+		struct timeval now = { 0, };
+		int to;
 
-	ao2_link(channels, clonechan);
-	ao2_link(channels, original);
-	ao2_unlock(channels);
+		to = -1;
 
-	/* Release our held safety references. */
-	ast_channel_unref(original);
-	ast_channel_unref(clonechan);
+		if (!ast_tvzero(config->nexteventts)) {
+			now = ast_tvnow();
+			to = ast_tvdiff_ms(config->nexteventts, now);
+			if (to <= 0) {
+				if (!config->timelimit) {
+					res = AST_BRIDGE_COMPLETE;
+					break;
+				}
+				to = 0;
+			}
+		}
 
-	ao2_cleanup(rformat);
-	ao2_cleanup(wformat);
-}
+		if (config->timelimit) {
+			time_left_ms = config->timelimit - ast_tvdiff_ms(now, config->start_time);
+			if (time_left_ms < 0) {
+				time_left_ms = 0;
+			}
 
-void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
-{
-	ast_channel_lock(chan);
+			if (time_left_ms < to) {
+				to = time_left_ms;
+			}
 
-	if (cid_num) {
-		ast_channel_caller(chan)->id.number.valid = 1;
-		ast_free(ast_channel_caller(chan)->id.number.str);
-		ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
-	}
-	if (cid_name) {
-		ast_channel_caller(chan)->id.name.valid = 1;
-		ast_free(ast_channel_caller(chan)->id.name.str);
-		ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
-	}
-	if (cid_ani) {
-		ast_channel_caller(chan)->ani.number.valid = 1;
-		ast_free(ast_channel_caller(chan)->ani.number.str);
-		ast_channel_caller(chan)->ani.number.str = ast_strdup(cid_ani);
-	}
+			if (time_left_ms <= 0) {
+				if (caller_warning && config->end_sound)
+					bridge_playfile(c0, c1, config->end_sound, 0);
+				if (callee_warning && config->end_sound)
+					bridge_playfile(c1, c0, config->end_sound, 0);
+				*fo = NULL;
+				res = AST_BRIDGE_COMPLETE;
+				ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s\r\nChannel2: %s", ast_channel_name(c0), ast_channel_name(c1));
+				break;
+			}
 
-	ast_channel_publish_snapshot(chan);
+			if (!to) {
+				if (time_left_ms >= 5000 && config->warning_sound && config->play_warning && ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
+					int t = (time_left_ms + 500) / 1000; /* round to nearest second */
+					if (caller_warning)
+						bridge_playfile(c0, c1, config->warning_sound, t);
+					if (callee_warning)
+						bridge_playfile(c1, c0, config->warning_sound, t);
+				}
 
-	ast_channel_unlock(chan);
-}
+				if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000))) {
+					config->nexteventts = ast_tvadd(config->nexteventts, ast_samp2tv(config->warning_freq, 1000));
+				} else {
+					config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+				}
+			}
+			ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
+		}
 
-void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
-{
-	if (ast_channel_caller(chan) == caller) {
-		/* Don't set to self */
-		return;
-	}
+		if ((ast_channel_softhangup_internal_flag(c0) | ast_channel_softhangup_internal_flag(c1)) & AST_SOFTHANGUP_UNBRIDGE) {/* Bit operators are intentional. */
+			if (ast_channel_softhangup_internal_flag(c0) & AST_SOFTHANGUP_UNBRIDGE) {
+				ast_channel_clear_softhangup(c0, AST_SOFTHANGUP_UNBRIDGE);
+			}
+			if (ast_channel_softhangup_internal_flag(c1) & AST_SOFTHANGUP_UNBRIDGE) {
+				ast_channel_clear_softhangup(c1, AST_SOFTHANGUP_UNBRIDGE);
+			}
+			ast_channel_lock_both(c0, c1);
+			ast_channel_internal_bridged_channel_set(c0, c1);
+			ast_channel_internal_bridged_channel_set(c1, c0);
+			ast_channel_unlock(c0);
+			ast_channel_unlock(c1);
+			ast_debug(1, "Unbridge signal received. Ending native bridge.\n");
+			continue;
+		}
 
-	ast_channel_lock(chan);
-	ast_party_caller_set(ast_channel_caller(chan), caller, update);
-	ast_channel_unlock(chan);
-}
+		/* Stop if we're a zombie or need a soft hangup */
+		if (ast_test_flag(ast_channel_flags(c0), AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) ||
+		    ast_test_flag(ast_channel_flags(c1), AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) {
+			*fo = NULL;
+			res = AST_BRIDGE_COMPLETE;
+			ast_debug(1, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",
+				ast_channel_name(c0), ast_channel_name(c1),
+				ast_test_flag(ast_channel_flags(c0), AST_FLAG_ZOMBIE) ? "Yes" : "No",
+				ast_check_hangup(c0) ? "Yes" : "No",
+				ast_test_flag(ast_channel_flags(c1), AST_FLAG_ZOMBIE) ? "Yes" : "No",
+				ast_check_hangup(c1) ? "Yes" : "No");
+			break;
+		}
+
+		update_bridge_vars(c0, c1);
+
+		bridge_play_sounds(c0, c1);
+
+		if (ast_channel_tech(c0)->bridge &&
+			/* if < 1 ms remains use generic bridging for accurate timing */
+			(!config->timelimit || to > 1000 || to == -1) &&
+		    (ast_channel_tech(c0)->bridge == ast_channel_tech(c1)->bridge) &&
+		    !ast_channel_monitor(c0) && !ast_channel_monitor(c1) &&
+		    !ast_channel_audiohooks(c0) && !ast_channel_audiohooks(c1) &&
+		    ast_framehook_list_is_empty(ast_channel_framehooks(c0)) && ast_framehook_list_is_empty(ast_channel_framehooks(c1)) &&
+		    !ast_channel_masq(c0) && !ast_channel_masqr(c0) && !ast_channel_masq(c1) && !ast_channel_masqr(c1)) {
+			int timeoutms = to - 1000 > 0 ? to - 1000 : to;
+			/* Looks like they share a bridge method and nothing else is in the way */
+			ast_set_flag(ast_channel_flags(c0), AST_FLAG_NBRIDGE);
+			ast_set_flag(ast_channel_flags(c1), AST_FLAG_NBRIDGE);
+			if ((res = ast_channel_tech(c0)->bridge(c0, c1, config->flags, fo, rc, timeoutms)) == AST_BRIDGE_COMPLETE) {
+				manager_bridge_event(0, 1, c0, c1);
+				ast_debug(1, "Returning from native bridge, channels: %s, %s\n", ast_channel_name(c0), ast_channel_name(c1));
+
+				ast_clear_flag(ast_channel_flags(c0), AST_FLAG_NBRIDGE);
+				ast_clear_flag(ast_channel_flags(c1), AST_FLAG_NBRIDGE);
+
+				if ((ast_channel_softhangup_internal_flag(c0) | ast_channel_softhangup_internal_flag(c1)) & AST_SOFTHANGUP_UNBRIDGE) {/* Bit operators are intentional. */
+					continue;
+				}
 
-void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
-{
-	if (ast_channel_caller(chan) == caller) {
-		/* Don't set to self */
-		return;
-	}
+				ast_channel_lock_both(c0, c1);
+				ast_channel_internal_bridged_channel_set(c0, NULL);
+				ast_channel_internal_bridged_channel_set(c1, NULL);
+				ast_channel_unlock(c0);
+				ast_channel_unlock(c1);
+				ast_format_cap_destroy(o0nativeformats);
+				ast_format_cap_destroy(o1nativeformats);
+				return res;
+			} else {
+				ast_clear_flag(ast_channel_flags(c0), AST_FLAG_NBRIDGE);
+				ast_clear_flag(ast_channel_flags(c1), AST_FLAG_NBRIDGE);
+			}
+			switch (res) {
+			case AST_BRIDGE_RETRY:
+				if (config->play_warning) {
+					ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
+				}
+				continue;
+			default:
+				ast_verb(3, "Native bridging %s and %s ended\n", ast_channel_name(c0), ast_channel_name(c1));
+				/* fallthrough */
+			case AST_BRIDGE_FAILED_NOWARN:
+				break;
+			}
+		}
 
-	ast_channel_lock(chan);
-	ast_party_caller_set(ast_channel_caller(chan), caller, update);
-	ast_channel_publish_snapshot(chan);
-	ast_channel_unlock(chan);
-}
+		if (((ast_format_cmp(ast_channel_readformat(c1), ast_channel_writeformat(c0)) == AST_FORMAT_CMP_NOT_EQUAL) ||
+			(ast_format_cmp(ast_channel_readformat(c0), ast_channel_writeformat(c1)) == AST_FORMAT_CMP_NOT_EQUAL) ||
+		    !ast_format_cap_identical(ast_channel_nativeformats(c0), o0nativeformats) ||
+			!ast_format_cap_identical(ast_channel_nativeformats(c1), o1nativeformats)) &&
+		    !(ast_channel_generator(c0) || ast_channel_generator(c1))) {
+			if (ast_channel_make_compatible(c0, c1)) {
+				ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", ast_channel_name(c0), ast_channel_name(c1));
+				manager_bridge_event(0, 1, c0, c1);
+				ast_format_cap_destroy(o0nativeformats);
+				ast_format_cap_destroy(o1nativeformats);
+				return AST_BRIDGE_FAILED;
+			}
 
-int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
-{
-	int oldstate = ast_channel_state(chan);
-	char name[AST_CHANNEL_NAME], *dashptr;
+			ast_format_cap_copy(o0nativeformats, ast_channel_nativeformats(c0));
+			ast_format_cap_copy(o1nativeformats, ast_channel_nativeformats(c1));
+		}
 
-	if (oldstate == state)
-		return 0;
+		update_bridge_vars(c0, c1);
 
-	ast_copy_string(name, ast_channel_name(chan), sizeof(name));
-	if ((dashptr = strrchr(name, '-'))) {
-		*dashptr = '\0';
+		res = ast_generic_bridge(c0, c1, config, fo, rc);
+		if (res != AST_BRIDGE_RETRY) {
+			break;
+		} else if (config->feature_timer) {
+			/* feature timer expired but has not been updated, sending to ast_bridge_call to do so */
+			break;
+		}
 	}
 
-	ast_channel_state_set(chan, state);
-
-	ast_publish_channel_state(chan);
+	ast_clear_flag(ast_channel_flags(c0), AST_FLAG_END_DTMF_ONLY);
+	ast_clear_flag(ast_channel_flags(c1), AST_FLAG_END_DTMF_ONLY);
 
-	/* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
-	 * for this channel is using the callback method for device state. If we pass in an actual state here
-	 * we override what they are saying the state is and things go amuck. */
-	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
+	/* Now that we have broken the bridge the source will change yet again */
+	ast_indicate(c0, AST_CONTROL_SRCUPDATE);
+	ast_indicate(c1, AST_CONTROL_SRCUPDATE);
 
-	return 0;
-}
+	ast_channel_lock_both(c0, c1);
+	ast_channel_internal_bridged_channel_set(c0, NULL);
+	ast_channel_internal_bridged_channel_set(c1, NULL);
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
 
-/*! \brief Bridge two channels together (early) */
-int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
-{
-	/* Make sure we can early bridge, if not error out */
-	if (!ast_channel_tech(c0)->early_bridge || (c1 && (!ast_channel_tech(c1)->early_bridge || ast_channel_tech(c0)->early_bridge != ast_channel_tech(c1)->early_bridge)))
-		return -1;
+	manager_bridge_event(0, 1, c0, c1);
+	ast_debug(1, "Bridge stops bridging channels %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
 
-	return ast_channel_tech(c0)->early_bridge(c0, c1);
+	ast_format_cap_destroy(o0nativeformats);
+	ast_format_cap_destroy(o1nativeformats);
+	return res;
 }
 
 /*! \brief Sets an option on a channel */
@@ -7019,7 +8204,7 @@ struct tonepair_state {
 	int v1_2;
 	int v2_2;
 	int v3_2;
-	struct ast_format *origwfmt;
+	struct ast_format origwfmt;
 	int pos;
 	int duration;
 	int modulate;
@@ -7032,10 +8217,8 @@ static void tonepair_release(struct ast_channel *chan, void *params)
 {
 	struct tonepair_state *ts = params;
 
-	if (chan) {
-		ast_set_write_format(chan, ts->origwfmt);
-	}
-	ao2_cleanup(ts->origwfmt);
+	if (chan)
+		ast_set_write_format(chan, &ts->origwfmt);
 	ast_free(ts);
 }
 
@@ -7044,12 +8227,10 @@ static void *tonepair_alloc(struct ast_channel *chan, void *params)
 	struct tonepair_state *ts;
 	struct tonepair_def *td = params;
 
-	if (!(ts = ast_calloc(1, sizeof(*ts)))) {
+	if (!(ts = ast_calloc(1, sizeof(*ts))))
 		return NULL;
-	}
-
-	ts->origwfmt = ao2_bump(ast_channel_writeformat(chan));
-	if (ast_set_write_format(chan, ast_format_slin)) {
+	ast_format_copy(&ts->origwfmt, ast_channel_writeformat(chan));
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan));
 		tonepair_release(NULL, ts);
 		ts = NULL;
@@ -7103,7 +8284,7 @@ static int tonepair_generator(struct ast_channel *chan, void *data, int len, int
 			ts->data[x] = ts->v3_1 + ts->v3_2;
 	}
 	ts->f.frametype = AST_FRAME_VOICE;
-	ts->f.subclass.format = ast_format_slin;
+	ast_format_set(&ts->f.subclass.format, AST_FORMAT_SLINEAR, 0);
 	ts->f.datalen = len;
 	ts->f.samples = samples;
 	ts->f.offset = AST_FRIENDLY_OFFSET;
@@ -7307,6 +8488,7 @@ void ast_uninstall_music_functions(void)
 	ast_moh_cleanup_ptr = NULL;
 }
 
+/*! \brief Turn on music on hold on a given channel */
 int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
 {
 	if (ast_moh_start_ptr)
@@ -7317,6 +8499,7 @@ int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *inte
 	return 0;
 }
 
+/*! \brief Turn off music on hold on a given channel */
 void ast_moh_stop(struct ast_channel *chan)
 {
 	if (ast_moh_stop_ptr)
@@ -7428,14 +8611,18 @@ static int data_channeltypes_provider_handler(const struct ast_data_search *sear
 		ast_data_add_bool(data_type, "send_image", cl->tech->send_image ? 1 : 0);
 		ast_data_add_bool(data_type, "send_html", cl->tech->send_html ? 1 : 0);
 		ast_data_add_bool(data_type, "exception", cl->tech->exception ? 1 : 0);
+		ast_data_add_bool(data_type, "bridge", cl->tech->bridge ? 1 : 0);
 		ast_data_add_bool(data_type, "early_bridge", cl->tech->early_bridge ? 1 : 0);
 		ast_data_add_bool(data_type, "fixup", cl->tech->fixup ? 1 : 0);
 		ast_data_add_bool(data_type, "setoption", cl->tech->setoption ? 1 : 0);
 		ast_data_add_bool(data_type, "queryoption", cl->tech->queryoption ? 1 : 0);
 		ast_data_add_bool(data_type, "write_video", cl->tech->write_video ? 1 : 0);
 		ast_data_add_bool(data_type, "write_text", cl->tech->write_text ? 1 : 0);
+		ast_data_add_bool(data_type, "bridged_channel", cl->tech->bridged_channel ? 1 : 0);
 		ast_data_add_bool(data_type, "func_channel_read", cl->tech->func_channel_read ? 1 : 0);
 		ast_data_add_bool(data_type, "func_channel_write", cl->tech->func_channel_write ? 1 : 0);
+		ast_data_add_bool(data_type, "get_base_channel", cl->tech->get_base_channel ? 1 : 0);
+		ast_data_add_bool(data_type, "set_base_channel", cl->tech->set_base_channel ? 1 : 0);
 		ast_data_add_bool(data_type, "get_pvt_uniqueid", cl->tech->get_pvt_uniqueid ? 1 : 0);
 		ast_data_add_bool(data_type, "cc_callback", cl->tech->cc_callback ? 1 : 0);
 
@@ -7468,194 +8655,25 @@ static const struct ast_data_handler channeltypes_provider = {
 	.get = data_channeltypes_provider_handler
 };
 
-static const struct ast_data_entry channel_providers[] = {
-	AST_DATA_ENTRY("/asterisk/core/channels", &channels_provider),
-	AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider),
-};
-
-/*!
- * \internal
- * \brief Print channel object key (name).
- * \since 12.0.0
- *
- * \param v_obj A pointer to the object we want the key printed.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-static void prnt_channel_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
-{
-	struct ast_channel *chan = v_obj;
-
-	if (!chan) {
-		return;
-	}
-	prnt(where, "%s", ast_channel_name(chan));
-}
-
-/*!
- * \brief List of channel variables to append to all channel-related events.
- */
-struct manager_channel_variable {
-	AST_LIST_ENTRY(manager_channel_variable) entry;
-	unsigned int isfunc:1;
-	char name[];
-};
-
-static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
-
-static void free_channelvars(void)
-{
-	struct manager_channel_variable *var;
-	AST_RWLIST_WRLOCK(&channelvars);
-	while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
-		ast_free(var);
-	}
-	AST_RWLIST_UNLOCK(&channelvars);
-}
-
-int ast_channel_has_manager_vars(void)
-{
-	int vars_present;
-
-	AST_RWLIST_RDLOCK(&channelvars);
-	vars_present = !AST_LIST_EMPTY(&channelvars);
-	AST_RWLIST_UNLOCK(&channelvars);
-
-	return vars_present;
-}
-
-void ast_channel_set_manager_vars(size_t varc, char **vars)
-{
-	size_t i;
-
-	free_channelvars();
-	AST_RWLIST_WRLOCK(&channelvars);
-	for (i = 0; i < varc; ++i) {
-		const char *var = vars[i];
-		struct manager_channel_variable *mcv;
-		if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(var) + 1))) {
-			break;
-		}
-		strcpy(mcv->name, var); /* SAFE */
-		if (strchr(var, '(')) {
-			mcv->isfunc = 1;
-		}
-		AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
-	}
-	AST_RWLIST_UNLOCK(&channelvars);
-}
-
-/*!
- * \brief Destructor for lists of variables.
- * \param obj AO2 object.
- */
-static void varshead_dtor(void *obj)
-{
-	struct varshead *head = obj;
-	struct ast_var_t *var;
-
-	while ((var = AST_RWLIST_REMOVE_HEAD(head, entries))) {
-		ast_var_delete(var);
-	}
-}
-
-struct varshead *ast_channel_get_vars(struct ast_channel *chan)
-{
-	RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
-	struct ast_var_t *cv;
-
-	ret = ao2_alloc(sizeof(*ret), varshead_dtor);
-
-	if (!ret) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(ast_channel_varshead(chan), cv, entries) {
-		struct ast_var_t *var = ast_var_assign(ast_var_name(cv), ast_var_value(cv));
-
-		if (!var) {
-			return NULL;
-		}
-
-		AST_LIST_INSERT_TAIL(ret, var, entries);
-	}
-
-	ao2_ref(ret, +1);
-	return ret;
-}
-
-struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
-{
-	RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
-	struct manager_channel_variable *mcv;
-	SCOPED_LOCK(lock, &channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	if (AST_LIST_EMPTY(&channelvars)) {
-		return NULL;
-	}
-
-	ret = ao2_alloc(sizeof(*ret), varshead_dtor);
-	tmp = ast_str_create(16);
-
-	if (!ret || !tmp) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&channelvars, mcv, entry) {
-		const char *val = NULL;
-		struct ast_var_t *var;
-
-		if (mcv->isfunc) {
-			if (ast_func_read2(chan, mcv->name, &tmp, 0) == 0) {
-				val = ast_str_buffer(tmp);
-			} else {
-				ast_log(LOG_ERROR,
-					"Error invoking function %s\n", mcv->name);
-			}
-		} else {
-			val = pbx_builtin_getvar_helper(chan, mcv->name);
-		}
-
-		var = ast_var_assign(mcv->name, val ? val : "");
-		if (!var) {
-			return NULL;
-		}
-
-		AST_RWLIST_INSERT_TAIL(ret, var, entries);
-	}
-
-	ao2_ref(ret, +1);
-	return ret;
-}
+static const struct ast_data_entry channel_providers[] = {
+	AST_DATA_ENTRY("/asterisk/core/channels", &channels_provider),
+	AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider),
+};
 
 static void channels_shutdown(void)
 {
-	free_channelvars();
-
 	ast_data_unregister(NULL);
 	ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
 	if (channels) {
-		ao2_container_unregister("channels");
 		ao2_ref(channels, -1);
 		channels = NULL;
 	}
-	ast_channel_unregister(&surrogate_tech);
 }
 
 void ast_channels_init(void)
 {
 	channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
 			ast_channel_hash_cb, ast_channel_cmp_cb);
-	if (channels) {
-		ao2_container_register("channels", channels, prnt_channel_key);
-	}
-
-	ast_channel_register(&surrogate_tech);
-
-	ast_stasis_channels_init();
 
 	ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
 
@@ -7663,8 +8681,7 @@ void ast_channels_init(void)
 
 	ast_plc_reload();
 
-	ast_register_atexit(channels_shutdown);
-
+	ast_register_cleanup(channels_shutdown);
 }
 
 /*! \brief Print call group and pickup group ---*/
@@ -7756,9 +8773,8 @@ void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
 {
 	struct ast_variable *cur;
 
-	for (cur = vars; cur; cur = cur->next) {
+	for (cur = vars; cur; cur = cur->next)
 		pbx_builtin_setvar_helper(chan, cur->name, cur->value);
-	}
 }
 
 static void *silence_generator_alloc(struct ast_channel *chan, void *data)
@@ -7781,7 +8797,7 @@ static int silence_generator_generate(struct ast_channel *chan, void *data, int
 		.samples = samples,
 		.datalen = sizeof(buf),
 	};
-	frame.subclass.format = ast_format_slin;
+	ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	memset(buf, 0, sizeof(buf));
 
@@ -7798,7 +8814,7 @@ static struct ast_generator silence_generator = {
 };
 
 struct ast_silence_generator {
-	struct ast_format *old_write_format;
+	struct ast_format old_write_format;
 };
 
 struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan)
@@ -7809,9 +8825,9 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha
 		return NULL;
 	}
 
-	state->old_write_format = ao2_bump(ast_channel_writeformat(chan));
+	ast_format_copy(&state->old_write_format, ast_channel_writeformat(chan));
 
-	if (ast_set_write_format(chan, ast_format_slin) < 0) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 		ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n");
 		ast_free(state);
 		return NULL;
@@ -7855,11 +8871,9 @@ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_sil
 
 	if (deactivate_silence_generator(chan)) {
 		ast_debug(1, "Stopped silence generator on '%s'\n", ast_channel_name(chan));
-		if (ast_set_write_format(chan, state->old_write_format) < 0) {
+		if (ast_set_write_format(chan, &state->old_write_format) < 0)
 			ast_log(LOG_ERROR, "Could not return write format to its original state\n");
-		}
 	}
-	ao2_cleanup(state->old_write_format);
 	ast_free(state);
 }
 
@@ -7915,9 +8929,9 @@ int ast_say_digit_str(struct ast_channel *chan, const char *str,
 }
 
 int ast_say_character_str(struct ast_channel *chan, const char *str,
-	const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
+	const char *ints, const char *lang)
 {
-	return ast_say_character_str_full(chan, str, ints, lang, sensitivity, -1, -1);
+	return ast_say_character_str_full(chan, str, ints, lang, -1, -1);
 }
 
 int ast_say_phonetic_str(struct ast_channel *chan, const char *str,
@@ -7960,7 +8974,6 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p
 
 	ast_channel_lock(chan);
 	ast_party_connected_line_set(ast_channel_connected(chan), connected, update);
-	ast_channel_publish_snapshot(chan);
 	ast_channel_unlock(chan);
 }
 
@@ -8786,7 +9799,7 @@ enum {
 	AST_REDIRECTING_TO_NAME,
 	AST_REDIRECTING_TO_NUMBER_PLAN,
 	AST_REDIRECTING_TO_ID_PRESENTATION,/* Combined number and name presentation. */
-	AST_REDIRECTING_REASON_CODE,
+	AST_REDIRECTING_REASON,
 	AST_REDIRECTING_COUNT,
 	AST_REDIRECTING_FROM_SUBADDRESS,
 	AST_REDIRECTING_FROM_SUBADDRESS_TYPE,
@@ -8826,7 +9839,7 @@ enum {
 	AST_REDIRECTING_ORIG_SUBADDRESS_ODD_EVEN,
 	AST_REDIRECTING_ORIG_SUBADDRESS_VALID,
 	AST_REDIRECTING_ORIG_TAG,
-	AST_REDIRECTING_ORIG_REASON_CODE,
+	AST_REDIRECTING_ORIG_REASON,
 	AST_REDIRECTING_PRIV_TO_NUMBER,
 	AST_REDIRECTING_PRIV_TO_NUMBER_PLAN,
 	AST_REDIRECTING_PRIV_TO_NUMBER_VALID,
@@ -8866,48 +9879,8 @@ enum {
 	AST_REDIRECTING_PRIV_ORIG_SUBADDRESS_ODD_EVEN,
 	AST_REDIRECTING_PRIV_ORIG_SUBADDRESS_VALID,
 	AST_REDIRECTING_PRIV_ORIG_TAG,
-	AST_REDIRECTING_REASON_STR,
-	AST_REDIRECTING_ORIG_REASON_STR,
-};
-
-struct ast_party_redirecting_reason_ies {
-	int code;
-	int str;
 };
 
-static int redirecting_reason_build_data(unsigned char *data, size_t datalen,
-		const struct ast_party_redirecting_reason *reason, const char *label,
-		const struct ast_party_redirecting_reason_ies *ies)
-{
-	size_t length;
-	size_t pos = 0;
-	int32_t value;
-
-	if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
-		ast_log(LOG_WARNING, "No space left for %s code\n", label);
-		return -1;
-	}
-	data[pos++] = ies->code;
-	data[pos++] = sizeof(value);
-	value = htonl(reason->code);
-	memcpy(data + pos, &value, sizeof(value));
-	pos += sizeof(value);
-
-	if (reason->str) {
-		length = strlen(reason->str);
-		if (datalen < pos + sizeof(data[0] * 2) + length) {
-			ast_log(LOG_WARNING, "No space left for %s string\n", label);
-			return -1;
-		}
-		data[pos++] = ies->str;
-		data[pos++] = length;
-		memcpy(data + pos, reason->str, length);
-		pos += length;
-	}
-
-	return pos;
-}
-
 int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
 {
 	int32_t value;
@@ -9028,15 +10001,6 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct
 		.tag = AST_REDIRECTING_PRIV_TO_TAG,
 		.combined_presentation = 0,/* Not sent. */
 	};
-	static const struct ast_party_redirecting_reason_ies reason_ies = {
-		.code = AST_REDIRECTING_REASON_CODE,
-		.str = AST_REDIRECTING_REASON_STR,
-	};
-
-	static const struct ast_party_redirecting_reason_ies orig_reason_ies = {
-		.code = AST_REDIRECTING_ORIG_REASON_CODE,
-		.str = AST_REDIRECTING_ORIG_REASON_STR,
-	};
 
 	/* Redirecting frame version */
 	if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
@@ -9090,20 +10054,26 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct
 	pos += res;
 
 	/* Redirecting reason */
-	res = redirecting_reason_build_data(data + pos, datalen - pos, &redirecting->reason,
-			"redirecting-reason", &reason_ies);
-	if (res < 0) {
+	if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+		ast_log(LOG_WARNING, "No space left for redirecting reason\n");
 		return -1;
 	}
-	pos += res;
+	data[pos++] = AST_REDIRECTING_REASON;
+	data[pos++] = sizeof(value);
+	value = htonl(redirecting->reason);
+	memcpy(data + pos, &value, sizeof(value));
+	pos += sizeof(value);
 
 	/* Redirecting original reason */
-	res = redirecting_reason_build_data(data + pos, datalen - pos, &redirecting->orig_reason,
-			"redirecting-orig-reason", &orig_reason_ies);
-	if (res < 0) {
+	if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
+		ast_log(LOG_WARNING, "No space left for redirecting original reason\n");
 		return -1;
 	}
-	pos += res;
+	data[pos++] = AST_REDIRECTING_ORIG_REASON;
+	data[pos++] = sizeof(value);
+	value = htonl(redirecting->orig_reason);
+	memcpy(data + pos, &value, sizeof(value));
+	pos += sizeof(value);
 
 	/* Redirecting count */
 	if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
@@ -9827,43 +10797,25 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct
 				redirecting->priv_to.tag[ie_len] = 0;
 			}
 			break;
-/* Redirecting reason code */
-		case AST_REDIRECTING_REASON_CODE:
+/* Redirecting reason */
+		case AST_REDIRECTING_REASON:
 			if (ie_len != sizeof(value)) {
 				ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n",
 					(unsigned) ie_len);
 				break;
 			}
 			memcpy(&value, data + pos, sizeof(value));
-			redirecting->reason.code = ntohl(value);
-			break;
-/* Redirecting reason string */
-		case AST_REDIRECTING_REASON_STR:
-			ast_free(redirecting->reason.str);
-			redirecting->reason.str = ast_malloc(ie_len + 1);
-			if (redirecting->reason.str) {
-				memcpy(redirecting->reason.str, data + pos, ie_len);
-				redirecting->reason.str[ie_len] = 0;
-			}
+			redirecting->reason = ntohl(value);
 			break;
-/* Redirecting orig-reason code */
-		case AST_REDIRECTING_ORIG_REASON_CODE:
+/* Redirecting orig-reason */
+		case AST_REDIRECTING_ORIG_REASON:
 			if (ie_len != sizeof(value)) {
 				ast_log(LOG_WARNING, "Invalid redirecting original reason (%u)\n",
 					(unsigned) ie_len);
 				break;
 			}
 			memcpy(&value, data + pos, sizeof(value));
-			redirecting->orig_reason.code = ntohl(value);
-			break;
-/* Redirecting orig-reason string */
-		case AST_REDIRECTING_ORIG_REASON_STR:
-			ast_free(redirecting->orig_reason.str);
-			redirecting->orig_reason.str = ast_malloc(ie_len + 1);
-			if (redirecting->orig_reason.str) {
-				memcpy(redirecting->orig_reason.str, data + pos, ie_len);
-				redirecting->orig_reason.str[ie_len] = 0;
-			}
+			redirecting->orig_reason = ntohl(value);
 			break;
 /* Redirecting count */
 		case AST_REDIRECTING_COUNT:
@@ -10237,413 +11189,41 @@ int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, si
 	return 0;
 }
 
-void ast_channel_unlink(struct ast_channel *chan)
-{
-	ao2_unlink(channels, chan);
-}
-
-struct ast_bridge *ast_channel_get_bridge(const struct ast_channel *chan)
-{
-	struct ast_bridge *bridge;
-
-	bridge = ast_channel_internal_bridge(chan);
-	if (bridge) {
-		ao2_ref(bridge, +1);
-	}
-	return bridge;
-}
-
-int ast_channel_is_bridged(const struct ast_channel *chan)
-{
-	return ast_channel_internal_bridge(chan) != NULL;
-}
-
-int ast_channel_is_leaving_bridge(struct ast_channel *chan)
-{
-	int hangup_flags = ast_channel_softhangup_internal_flag(chan);
-	int hangup_test = hangup_flags & AST_SOFTHANGUP_ASYNCGOTO;
-	int unbridge = ast_channel_unbridged(chan);
-
-	/* This function should only return true if either the unbridged flag or
-	 * the ASYNCGOTO soft hangup flag is set and when no other soft hangup
-	 * flags are set. Any other soft hangup flags being set should make it
-	 * return false.
-	 */
-	return ((hangup_test || unbridge) && (hangup_test == hangup_flags));
-}
-
-struct ast_channel *ast_channel_bridge_peer(struct ast_channel *chan)
-{
-	struct ast_channel *peer;
-	struct ast_bridge *bridge;
-
-	/* Get the bridge the channel is in. */
-	ast_channel_lock(chan);
-	bridge = ast_channel_get_bridge(chan);
-	ast_channel_unlock(chan);
-	if (!bridge) {
-		return NULL;
-	}
-
-	peer = ast_bridge_peer(bridge, chan);
-	ao2_ref(bridge, -1);
-	return peer;
-}
-
-struct ast_bridge_channel *ast_channel_get_bridge_channel(struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	bridge_channel = ast_channel_internal_bridge_channel(chan);
-	if (bridge_channel) {
-		ao2_ref(bridge_channel, +1);
-	}
-	return bridge_channel;
-}
-
-struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
-{
-	struct ast_channel *yanked_chan;
-	struct {
-		char *accountcode;
-		char *exten;
-		char *context;
-		char *name;
-		int amaflags;
-		struct ast_format *readformat;
-		struct ast_format *writeformat;
-	} my_vars = { 0, };
-
-	ast_channel_lock(yankee);
-	my_vars.accountcode = ast_strdupa(ast_channel_accountcode(yankee));
-	my_vars.exten = ast_strdupa(ast_channel_exten(yankee));
-	my_vars.context = ast_strdupa(ast_channel_context(yankee));
-	my_vars.name = ast_strdupa(ast_channel_name(yankee));
-	my_vars.amaflags = ast_channel_amaflags(yankee);
-	my_vars.writeformat = ao2_bump(ast_channel_writeformat(yankee));
-	my_vars.readformat = ao2_bump(ast_channel_readformat(yankee));
-	ast_channel_unlock(yankee);
-
-	/* Do not hold any channel locks while calling channel_alloc() since the function
-	 * locks the channel container when linking the new channel in. */
-	if (!(yanked_chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, my_vars.accountcode,
-					my_vars.exten, my_vars.context, NULL, yankee, my_vars.amaflags,
-					"Surrogate/%s", my_vars.name))) {
-		ao2_cleanup(my_vars.writeformat);
-		ao2_cleanup(my_vars.readformat);
-		return NULL;
-	}
-
-	/* Make formats okay */
-	ast_channel_set_readformat(yanked_chan, my_vars.readformat);
-	ast_channel_set_writeformat(yanked_chan, my_vars.writeformat);
-	ao2_cleanup(my_vars.readformat);
-	ao2_cleanup(my_vars.writeformat);
-
-	ast_channel_unlock(yanked_chan);
-
-	if (ast_channel_move(yanked_chan, yankee)) {
-		ast_hangup(yanked_chan);
-		return NULL;
-	}
-
-	return yanked_chan;
-}
-
-/*!
- * Mutex that prevents multiple ast_channel_move() operations
- * from occurring simultaneously. This is necessary since the
- * involved channels have to be locked and unlocked throughout
- * the move operation.
+/* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
+ *
+ * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE
  *
- * The most important data being protected are the masq and masqr
- * data on channels. We don't want them getting criss-crossed due
- * to multiple moves mucking with them.
  */
-AST_MUTEX_DEFINE_STATIC(channel_move_lock);
-
-int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
-{
-	SCOPED_MUTEX(lock, &channel_move_lock);
-
-	if (dest == source) {
-		ast_log(LOG_WARNING, "Can't move channel '%s' into itself!\n",
-			ast_channel_name(dest));
-		return -1;
-	}
-
-	ast_channel_lock_both(dest, source);
-
-	if (ast_test_flag(ast_channel_flags(dest), AST_FLAG_ZOMBIE)
-		|| ast_test_flag(ast_channel_flags(source), AST_FLAG_ZOMBIE)) {
-		/* Zombies! Run! */
-		ast_log(LOG_WARNING,
-			"Can't move channel. One or both is dead (%s <-- %s)\n",
-			ast_channel_name(dest), ast_channel_name(source));
-		ast_channel_unlock(source);
-		ast_channel_unlock(dest);
-		return -1;
-	}
-
-	ast_channel_masq_set(dest, source);
-	ast_channel_masqr_set(source, dest);
-
-	ast_channel_unlock(dest);
-	ast_channel_unlock(source);
-
-	channel_do_masquerade(dest, source);
-	return 0;
-}
-
-static void suppress_datastore_destroy_cb(void *data)
-{
-	ao2_cleanup(data);
-}
-
-static const struct ast_datastore_info suppress_datastore_voice = {
-	.type = "suppressvoice",
-	.destroy = suppress_datastore_destroy_cb
-};
-
-static void suppress_framehook_destroy_cb(void *data)
-{
-	ao2_cleanup(data);
-}
 
-struct suppress_data {
-	enum ast_frame_type frametype;
-	unsigned int direction;
-	int framehook_id;
-};
-
-static void suppress_framehook_fixup_cb(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct suppress_data *suppress = data;
-
-	suppress->framehook_id = framehook_id;
-}
-
-static struct ast_frame *suppress_framehook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
-{
-	struct suppress_data *suppress = data;
-	int suppress_frame = 0;
-
-	if (!frame) {
-		return NULL;
-	}
-
-	if (frame->frametype != suppress->frametype) {
-		return frame;
-	}
-
-	if (event == AST_FRAMEHOOK_EVENT_READ && (suppress->direction & AST_MUTE_DIRECTION_READ)) {
-		suppress_frame = 1;
-	} else if (event == AST_FRAMEHOOK_EVENT_WRITE && (suppress->direction & AST_MUTE_DIRECTION_WRITE)) {
-		suppress_frame = 1;
-	}
-
-	if (suppress_frame) {
-		switch (frame->frametype) {
-		case AST_FRAME_VOICE:
-			frame = &ast_null_frame;
-			break;
-		default:
-			break;
-		}
-	}
-
-	return frame;
-}
-
-static const struct ast_datastore_info *suppress_get_datastore_information(enum ast_frame_type frametype)
-{
-	switch (frametype) {
-	case AST_FRAME_VOICE:
-		return &suppress_datastore_voice;
-	default:
-		return NULL;
-	}
-}
-
-int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype)
-{
-	RAII_VAR(struct suppress_data *, suppress, NULL, ao2_cleanup);
-	const struct ast_datastore_info *datastore_info = NULL;
-	struct ast_datastore *datastore = NULL;
-	struct ast_framehook_interface interface = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = suppress_framehook_event_cb,
-		.destroy_cb = suppress_framehook_destroy_cb,
-		.chan_fixup_cb = suppress_framehook_fixup_cb,
-	};
-	int framehook_id;
-
-	if (!(datastore_info = suppress_get_datastore_information(frametype))) {
-		ast_log(LOG_WARNING, "Attempted to suppress an unsupported frame type (%u).\n", frametype);
-		return -1;
-	}
-
-	if ((datastore = ast_channel_datastore_find(chan, datastore_info, NULL))) {
-		suppress = datastore->data;
-		suppress->direction |= direction;
-		return 0;
-	}
-
-	if (!(suppress = ao2_alloc(sizeof(*suppress), NULL))) {
-		ast_log(LOG_WARNING, "Failed to allocate data while attempting to suppress a stream.\n");
-		return -1;
-	}
-
-	suppress->frametype = frametype;
-	suppress->direction |= direction;
-
-	interface.data = suppress;
-
-	framehook_id = ast_framehook_attach(chan, &interface);
-	if (framehook_id < 0) {
-		/* Hook attach failed.  Get rid of the evidence. */
-		ast_log(LOG_WARNING, "Failed to attach framehook while attempting to suppress a stream.\n");
-		return -1;
-	}
-
-	/* One ref for the framehook */
-	ao2_ref(suppress, +1);
-
-	suppress->framehook_id = framehook_id;
-
-	if (!(datastore = ast_datastore_alloc(datastore_info, NULL))) {
-		ast_log(LOG_WARNING, "Failed to allocate datastore while attempting to suppress a stream.\n");
-		ast_framehook_detach(chan, framehook_id);
-		return -1;
-	}
-
-	/* and another ref for the datastore */
-	ao2_ref(suppress, +1);
-	datastore->data = suppress;
-
-	ast_channel_datastore_add(chan, datastore);
-
-	return 0;
-}
-
-int ast_channel_unsuppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype)
-{
-	const struct ast_datastore_info *datastore_info = NULL;
-	struct ast_datastore *datastore = NULL;
-	struct suppress_data *suppress;
-
-	if (!(datastore_info = suppress_get_datastore_information(frametype))) {
-		ast_log(LOG_WARNING, "Attempted to unsuppress an unsupported frame type (%u).\n", frametype);
-		return -1;
-	}
-
-	if (!(datastore = ast_channel_datastore_find(chan, datastore_info, NULL))) {
-		/* Nothing to do! */
-		return 0;
-	}
-
-	suppress = datastore->data;
-
-	suppress->direction &= ~(direction);
-
-	if (suppress->direction == 0) {
-		/* Nothing left to suppress.  Bye! */
-		ast_framehook_detach(chan, suppress->framehook_id);
-		ast_channel_datastore_remove(chan, datastore);
-		ast_datastore_free(datastore);
-	}
-
-	return 0;
-}
-
-void ast_channel_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why)
-{
-	int dead;
-	long duration;
-
-	ast_channel_lock(chan);
-	dead = ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
-		|| (ast_channel_softhangup_internal_flag(chan)
-			& ~AST_SOFTHANGUP_ASYNCGOTO);
-	ast_channel_unlock(chan);
-	if (dead) {
-		/* Channel is a zombie or a real hangup. */
-		return;
-	}
-
-	duration = ast_tvdiff_ms(ast_tvnow(), start);
-	if (duration < option_dtmfminduration) {
-		duration = option_dtmfminduration;
-	}
-	ast_senddigit_end(chan, digit, duration);
-	ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
-		digit, ast_channel_name(chan), why, duration);
-}
-
-static void features_destroy(void *obj)
-{
-	ast_bridge_features_destroy(obj);
-}
-
-static const struct ast_datastore_info bridge_features_info = {
-	.type = "bridge-features",
-	.destroy = features_destroy,
-};
-
-struct ast_bridge_features *ast_channel_feature_hooks_get(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	datastore = ast_channel_datastore_find(chan, &bridge_features_info, NULL);
-	if (!datastore) {
-		return NULL;
-	}
-	return datastore->data;
-}
-
-static int channel_feature_hooks_set_full(struct ast_channel *chan, struct ast_bridge_features *features, int replace)
+/* Provide binary compatibility for modules that call ast_channel_alloc() directly;
+ * newly compiled modules will call __ast_channel_alloc() via the macros in channel.h
+ */
+#undef ast_channel_alloc
+struct ast_channel __attribute__((format(printf, 10, 11)))
+	*ast_channel_alloc(int needqueue, int state, const char *cid_num,
+			   const char *cid_name, const char *acctcode,
+			   const char *exten, const char *context,
+			   const char *linkedid, const int amaflag,
+			   const char *name_fmt, ...);
+struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num,
+				      const char *cid_name, const char *acctcode,
+				      const char *exten, const char *context,
+				      const char *linkedid, const int amaflag,
+				      const char *name_fmt, ...)
 {
-	struct ast_datastore *datastore;
-	struct ast_bridge_features *ds_features;
-
-	datastore = ast_channel_datastore_find(chan, &bridge_features_info, NULL);
-	if (datastore) {
-		ds_features = datastore->data;
-		if (replace) {
-			ast_bridge_features_cleanup(ds_features);
-			ast_bridge_features_init(ds_features);
-		}
-		if (features) {
-			ast_bridge_features_merge(ds_features, features);
-		}
-		return 0;
-	}
-
-	datastore = ast_datastore_alloc(&bridge_features_info, NULL);
-	if (!datastore) {
-		return -1;
-	}
+	va_list ap;
+	struct ast_channel *result;
 
-	ds_features = ast_bridge_features_new();
-	if (!ds_features) {
-		ast_datastore_free(datastore);
-		return -1;
-	}
 
-	if (features) {
-		ast_bridge_features_merge(ds_features, features);
-	}
-	datastore->data = ds_features;
-	ast_channel_datastore_add(chan, datastore);
-	return 0;
-}
+	va_start(ap, name_fmt);
+	result = __ast_channel_alloc_ap(needqueue, state, cid_num, cid_name, acctcode, exten, context,
+					linkedid, amaflag, __FILE__, __LINE__, __FUNCTION__, name_fmt, ap);
+	va_end(ap);
 
-int ast_channel_feature_hooks_append(struct ast_channel *chan, struct ast_bridge_features *features)
-{
-	return channel_feature_hooks_set_full(chan, features, 0);
+	return result;
 }
 
-int ast_channel_feature_hooks_replace(struct ast_channel *chan, struct ast_bridge_features *features)
+void ast_channel_unlink(struct ast_channel *chan)
 {
-	return channel_feature_hooks_set_full(chan, features, 1);
+	ao2_unlink(channels, chan);
 }
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index d163b5d..30790d0 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -33,34 +33,19 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429062 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "asterisk/paths.h"
 #include "asterisk/channel.h"
-#include "asterisk/channel_internal.h"
+#include "asterisk/stringfields.h"
 #include "asterisk/data.h"
-#include "asterisk/endpoints.h"
 #include "asterisk/indications.h"
-#include "asterisk/stasis_cache_pattern.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stringfields.h"
+#include "asterisk/channel_internal.h"
 #include "asterisk/test.h"
 
 /*!
- * \brief Channel UniqueId structure
- * \note channel creation time used for determining LinkedId Propagation
- */
-struct ast_channel_id {
-	time_t creation_time;				/*!< Creation time */
-	int creation_unique;				/*!< sub-second unique value */
-	char unique_id[AST_MAX_UNIQUEID];	/*!< Unique Identifier */
-};
-
-/*!
  * \brief Main Channel structure associated with a channel.
  *
  * \note When adding fields to this structure, it is important to add the field
@@ -77,6 +62,9 @@ struct ast_channel {
 	void *music_state;				/*!< Music State*/
 	void *generatordata;				/*!< Current generator data if there is any */
 	struct ast_generator *generator;		/*!< Current active data generator */
+	struct ast_channel * bridged_channel;			/*!< Who are we bridged to, if we're bridged.
+							 *   Who is proxying for us, if we are proxied (i.e. chan_agent).
+							 *   Do not access directly, use ast_bridged_channel(chan) */
 	struct ast_channel *masq;			/*!< Channel that will masquerade as us */
 	struct ast_channel *masqr;			/*!< Who we are masquerading as */
 	const char *blockproc;				/*!< Procedure causing blocking */
@@ -106,19 +94,17 @@ struct ast_channel {
 		AST_STRING_FIELD(name);         /*!< ASCII unique channel name */
 		AST_STRING_FIELD(language);     /*!< Language requested for voice prompts */
 		AST_STRING_FIELD(musicclass);   /*!< Default music class */
-		AST_STRING_FIELD(latest_musicclass);   /*!< Latest active music class */
 		AST_STRING_FIELD(accountcode);  /*!< Account code for billing */
 		AST_STRING_FIELD(peeraccount);  /*!< Peer account code for billing */
 		AST_STRING_FIELD(userfield);    /*!< Userfield for CEL billing */
 		AST_STRING_FIELD(call_forward); /*!< Where to forward to if asked to dial on this interface */
+		AST_STRING_FIELD(uniqueid);     /*!< Unique Channel Identifier */
+		AST_STRING_FIELD(linkedid);     /*!< Linked Channel Identifier -- gets propagated by linkage */
 		AST_STRING_FIELD(parkinglot);   /*! Default parking lot, if empty, default parking lot  */
 		AST_STRING_FIELD(hangupsource); /*! Who is responsible for hanging up this channel */
 		AST_STRING_FIELD(dialcontext);  /*!< Dial: Extension context that we were called from */
 	);
 
-	struct ast_channel_id uniqueid;		/*!< Unique Channel Identifier - can be specified on creation */
-	struct ast_channel_id linkedid;		/*!< Linked Channel Identifier - oldest propagated when bridged */
-
 	struct timeval whentohangup; /*!< Non-zero, set to actual time when channel is to be hung up */
 	pthread_t blocker;           /*!< If anyone is blocking, this is them */
 
@@ -143,11 +129,6 @@ struct ast_channel {
 	 */
 	struct ast_party_connected_line connected;
 
-	/*!
-	 * \brief Channel Connected Line ID information that was last indicated.
-	 */
-	struct ast_party_connected_line connected_indicated;
-
 	/*! \brief Redirecting/Diversion information */
 	struct ast_party_redirecting redirecting;
 
@@ -158,7 +139,6 @@ struct ast_channel {
 	struct ast_namedgroups *named_callgroups;	/*!< Named call group for call pickups */
 	struct ast_namedgroups *named_pickupgroups;	/*!< Named pickup group - which call groups can be picked up? */
 	struct timeval creationtime;			/*!< The time of channel creation */
-	struct timeval answertime;				/*!< The time the channel was answered */
 	struct ast_readq_list readq;
 	struct ast_jb jb;				/*!< The jitterbuffer state */
 	struct timeval dtmf_tv;				/*!< The time that an in process digit began, or the last digit ended */
@@ -173,12 +153,10 @@ struct ast_channel {
 							 *   See \arg \ref AstFileDesc */
 	int softhangup;				/*!< Whether or not we have been hung up...  Do not set this value
 							 *   directly, use ast_softhangup() */
-	int unbridged;              /*!< If non-zero, the bridge core needs to re-evaluate the current
-	                                 bridging technology which is in use by this channel's bridge. */
 	int fdno;					/*!< Which fd had an event detected on */
 	int streamid;					/*!< For streaming playback, the schedule ID */
 	int vstreamid;					/*!< For streaming video playback, the schedule ID */
-	struct ast_format *oldwriteformat;  /*!< Original writer format */
+	struct ast_format oldwriteformat;  /*!< Original writer format */
 	int timingfd;					/*!< Timing fd */
 	enum ast_channel_state state;			/*!< State of line -- Don't write directly, use ast_setstate() */
 	int rings;					/*!< Number of rings so far */
@@ -195,21 +173,19 @@ struct ast_channel {
 	struct ast_flags flags;				/*!< channel flags of AST_FLAG_ type */
 	int alertpipe[2];
 	struct ast_format_cap *nativeformats;         /*!< Kinds of data this channel can natively handle */
-	struct ast_format *readformat;            /*!< Requested read format (after translation) */
-	struct ast_format *writeformat;           /*!< Requested write format (before translation) */
-	struct ast_format *rawreadformat;         /*!< Raw read format (before translation) */
-	struct ast_format *rawwriteformat;        /*!< Raw write format (after translation) */
+	struct ast_format readformat;            /*!< Requested read format (after translation) */
+	struct ast_format writeformat;           /*!< Requested write format (after translation) */
+	struct ast_format rawreadformat;         /*!< Raw read format (before translation) */
+	struct ast_format rawwriteformat;        /*!< Raw write format (before translation) */
 	unsigned int emulate_dtmf_duration;		/*!< Number of ms left to emulate DTMF for */
 #ifdef HAVE_EPOLL
 	int epfd;
 #endif
 	int visible_indication;                         /*!< Indication currently playing on the channel */
-	int hold_state;							/*!< Current Hold/Unhold state */
 
 	unsigned short transfercapability;		/*!< ISDN Transfer Capability - AST_FLAG_DIGITAL is not enough */
 
 	struct ast_bridge *bridge;                      /*!< Bridge this channel is participating in */
-	struct ast_bridge_channel *bridge_channel;/*!< The bridge_channel this channel is linked with. */
 	struct ast_timer *timer;			/*!< timer object that provided timingfd */
 
 	char context[AST_MAX_CONTEXT];			/*!< Dialplan: Current extension context */
@@ -219,14 +195,8 @@ struct ast_channel {
 	char dtmf_digit_to_emulate;			/*!< Digit being emulated */
 	char sending_dtmf_digit;			/*!< Digit this channel is currently sending out. (zero if not sending) */
 	struct timeval sending_dtmf_tv;		/*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */
-	struct stasis_cp_single *topics;		/*!< Topic for all channel's events */
-	struct stasis_forward *endpoint_forward;	/*!< Subscription for event forwarding to endpoint's topic */
-	struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */
 };
 
-/*! \brief The monotonically increasing integer counter for channel uniqueids */
-static int uniqueint;
-
 /* AST_DATA definitions, which will probably have to be re-thought since the channel will be opaque */
 
 #if 0	/* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */
@@ -253,6 +223,8 @@ AST_DATA_STRUCTURE(ast_callerid, DATA_EXPORT_CALLERID);
 	MEMBER(ast_channel, peeraccount, AST_DATA_STRING)			\
 	MEMBER(ast_channel, userfield, AST_DATA_STRING)				\
 	MEMBER(ast_channel, call_forward, AST_DATA_STRING)			\
+	MEMBER(ast_channel, uniqueid, AST_DATA_STRING)				\
+	MEMBER(ast_channel, linkedid, AST_DATA_STRING)				\
 	MEMBER(ast_channel, parkinglot, AST_DATA_STRING)			\
 	MEMBER(ast_channel, hangupsource, AST_DATA_STRING)			\
 	MEMBER(ast_channel, dialcontext, AST_DATA_STRING)			\
@@ -281,6 +253,7 @@ static void channel_data_add_flags(struct ast_data *tree,
 	ast_data_add_bool(tree, "EXCEPTION", ast_test_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION));
 	ast_data_add_bool(tree, "MOH", ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH));
 	ast_data_add_bool(tree, "SPYING", ast_test_flag(ast_channel_flags(chan), AST_FLAG_SPYING));
+	ast_data_add_bool(tree, "NBRIDGE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE));
 	ast_data_add_bool(tree, "IN_AUTOLOOP", ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP));
 	ast_data_add_bool(tree, "OUTGOING", ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING));
 	ast_data_add_bool(tree, "IN_DTMF", ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF));
@@ -288,16 +261,15 @@ static void channel_data_add_flags(struct ast_data *tree,
 	ast_data_add_bool(tree, "END_DTMF_ONLY", ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY));
 	ast_data_add_bool(tree, "MASQ_NOSTREAM", ast_test_flag(ast_channel_flags(chan), AST_FLAG_MASQ_NOSTREAM));
 	ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN));
+	ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT));
 	ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS));
 	ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE));
-	ast_data_add_bool(tree, "BRIDGE_DUAL_REDIRECT_WAIT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT));
-	ast_data_add_bool(tree, "ORIGINATED", ast_test_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED));
-	ast_data_add_bool(tree, "DEAD", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEAD));
 }
 
 int ast_channel_data_add_structure(struct ast_data *tree,
 	struct ast_channel *chan, int add_bridged)
 {
+	struct ast_channel *bc;
 	struct ast_data *data_bridged;
 	struct ast_data *data_cdr;
 	struct ast_data *data_flags;
@@ -316,7 +288,7 @@ int ast_channel_data_add_structure(struct ast_data *tree,
 	ast_data_add_structure(ast_channel, tree, chan);
 
 	if (add_bridged) {
-		RAII_VAR(struct ast_channel *, bc, ast_channel_bridge_peer(chan), ast_channel_cleanup);
+		bc = ast_bridged_channel(chan);
 		if (bc) {
 			data_bridged = ast_data_add_node(tree, "bridged");
 			if (!data_bridged) {
@@ -326,9 +298,6 @@ int ast_channel_data_add_structure(struct ast_data *tree,
 		}
 	}
 
-	ast_data_add_str(tree, "uniqueid", ast_channel_uniqueid(chan));
-	ast_data_add_str(tree, "linkedid", ast_channel_linkedid(chan));
-
 	ast_data_add_codec(tree, "oldwriteformat", ast_channel_oldwriteformat(chan));
 	ast_data_add_codec(tree, "readformat", ast_channel_readformat(chan));
 	ast_data_add_codec(tree, "writeformat", ast_channel_writeformat(chan));
@@ -357,7 +326,7 @@ int ast_channel_data_add_structure(struct ast_data *tree,
 	if (!enum_node) {
 		return -1;
 	}
-	ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(ast_channel_amaflags(chan)));
+	ast_data_add_str(enum_node, "text", ast_cdr_flags2str(ast_channel_amaflags(chan)));
 	ast_data_add_int(enum_node, "value", ast_channel_amaflags(chan));
 
 	/* transfercapability */
@@ -379,6 +348,7 @@ int ast_channel_data_add_structure(struct ast_data *tree,
 	ast_data_add_bool(data_softhangup, "timeout", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_TIMEOUT);
 	ast_data_add_bool(data_softhangup, "appunload", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_APPUNLOAD);
 	ast_data_add_bool(data_softhangup, "explicit", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_EXPLICIT);
+	ast_data_add_bool(data_softhangup, "unbridge", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_UNBRIDGE);
 
 	/* channel flags */
 	data_flags = ast_data_add_node(tree, "flags");
@@ -423,6 +393,8 @@ int ast_channel_data_add_structure(struct ast_data *tree,
 		return -1;
 	}
 
+	ast_cdr_data_add_structure(data_cdr, ast_channel_cdr(chan), 1);
+
 	return 0;
 }
 
@@ -434,19 +406,15 @@ int ast_channel_data_cmp_structure(const struct ast_data_search *tree,
 
 /* ACCESSORS */
 
-#define DEFINE_STRINGFIELD_SETTERS_FOR(field, publish, assert_on_null) \
+#define DEFINE_STRINGFIELD_SETTERS_FOR(field) \
 void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
 { \
-	if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
-	if (!strcmp(value, chan->field)) return; \
 	ast_string_field_set(chan, field, value); \
-	if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
   \
 void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
 { \
 	ast_string_field_build_va(chan, field, fmt, ap); \
-	if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
 void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
 { \
@@ -456,17 +424,17 @@ void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...)
 	va_end(ap); \
 }
 
-DEFINE_STRINGFIELD_SETTERS_FOR(name, 0, 1);
-DEFINE_STRINGFIELD_SETTERS_FOR(language, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(accountcode, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(peeraccount, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(userfield, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(hangupsource, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(name);
+DEFINE_STRINGFIELD_SETTERS_FOR(language);
+DEFINE_STRINGFIELD_SETTERS_FOR(musicclass);
+DEFINE_STRINGFIELD_SETTERS_FOR(accountcode);
+DEFINE_STRINGFIELD_SETTERS_FOR(peeraccount);
+DEFINE_STRINGFIELD_SETTERS_FOR(userfield);
+DEFINE_STRINGFIELD_SETTERS_FOR(call_forward);
+DEFINE_STRINGFIELD_SETTERS_FOR(uniqueid);
+DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot);
+DEFINE_STRINGFIELD_SETTERS_FOR(hangupsource);
+DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext);
 
 #define DEFINE_STRINGFIELD_GETTER_FOR(field) const char *ast_channel_##field(const struct ast_channel *chan) \
 { \
@@ -476,25 +444,20 @@ DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0, 0);
 DEFINE_STRINGFIELD_GETTER_FOR(name);
 DEFINE_STRINGFIELD_GETTER_FOR(language);
 DEFINE_STRINGFIELD_GETTER_FOR(musicclass);
-DEFINE_STRINGFIELD_GETTER_FOR(latest_musicclass);
 DEFINE_STRINGFIELD_GETTER_FOR(accountcode);
 DEFINE_STRINGFIELD_GETTER_FOR(peeraccount);
 DEFINE_STRINGFIELD_GETTER_FOR(userfield);
 DEFINE_STRINGFIELD_GETTER_FOR(call_forward);
+DEFINE_STRINGFIELD_GETTER_FOR(uniqueid);
+DEFINE_STRINGFIELD_GETTER_FOR(linkedid);
 DEFINE_STRINGFIELD_GETTER_FOR(parkinglot);
 DEFINE_STRINGFIELD_GETTER_FOR(hangupsource);
 DEFINE_STRINGFIELD_GETTER_FOR(dialcontext);
 
-const char *ast_channel_uniqueid(const struct ast_channel *chan)
-{
-	ast_assert(chan->uniqueid.unique_id[0] != '\0');
-	return chan->uniqueid.unique_id;
-}
-
-const char *ast_channel_linkedid(const struct ast_channel *chan)
+void ast_channel_linkedid_set(struct ast_channel *chan, const char *value)
 {
-	ast_assert(chan->linkedid.unique_id[0] != '\0');
-	return chan->linkedid.unique_id;
+	ast_assert(!ast_strlen_zero(value));
+	ast_string_field_set(chan, linkedid, value);
 }
 
 const char *ast_channel_appl(const struct ast_channel *chan)
@@ -582,20 +545,14 @@ void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval va
 	chan->sending_dtmf_tv = value;
 }
 
-enum ama_flags ast_channel_amaflags(const struct ast_channel *chan)
+int ast_channel_amaflags(const struct ast_channel *chan)
 {
 	return chan->amaflags;
 }
-
-void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
+void ast_channel_amaflags_set(struct ast_channel *chan, int value)
 {
-	if (chan->amaflags == value) {
-		return;
-	}
 	chan->amaflags = value;
-	ast_channel_publish_snapshot(chan);
 }
-
 #ifdef HAVE_EPOLL
 int ast_channel_epfd(const struct ast_channel *chan)
 {
@@ -670,14 +627,6 @@ void ast_channel_visible_indication_set(struct ast_channel *chan, int value)
 {
 	chan->visible_indication = value;
 }
-int ast_channel_hold_state(const struct ast_channel *chan)
-{
-	return chan->hold_state;
-}
-void ast_channel_hold_state_set(struct ast_channel *chan, int value)
-{
-	chan->hold_state = value;
-}
 int ast_channel_vstreamid(const struct ast_channel *chan)
 {
 	return chan->vstreamid;
@@ -828,7 +777,7 @@ struct ast_format_cap *ast_channel_nativeformats(const struct ast_channel *chan)
 }
 void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
 {
-	ao2_replace(chan->nativeformats, value);
+	chan->nativeformats = value;
 }
 struct ast_framehook_list *ast_channel_framehooks(const struct ast_channel *chan)
 {
@@ -945,51 +894,31 @@ void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *callid)
 		ast_channel_name(chan),
 		call_identifier_to,
 		call_identifier_from);
-}
 
+}
 void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state value)
 {
 	chan->state = value;
 }
-void ast_channel_set_oldwriteformat(struct ast_channel *chan, struct ast_format *format)
-{
-	ao2_replace(chan->oldwriteformat, format);
-}
-void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
-{
-	ao2_replace(chan->rawreadformat, format);
-}
-void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
-{
-	ao2_replace(chan->rawwriteformat, format);
-}
-void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
-{
-	ao2_replace(chan->readformat, format);
-}
-void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
-{
-	ao2_replace(chan->writeformat, format);
-}
 struct ast_format *ast_channel_oldwriteformat(struct ast_channel *chan)
 {
-	return chan->oldwriteformat;
+	return &chan->oldwriteformat;
 }
 struct ast_format *ast_channel_rawreadformat(struct ast_channel *chan)
 {
-	return chan->rawreadformat;
+	return &chan->rawreadformat;
 }
 struct ast_format *ast_channel_rawwriteformat(struct ast_channel *chan)
 {
-	return chan->rawwriteformat;
+	return &chan->rawwriteformat;
 }
 struct ast_format *ast_channel_readformat(struct ast_channel *chan)
 {
-	return chan->readformat;
+	return &chan->readformat;
 }
 struct ast_format *ast_channel_writeformat(struct ast_channel *chan)
 {
-	return chan->writeformat;
+	return &chan->writeformat;
 }
 struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan)
 {
@@ -1023,10 +952,6 @@ struct ast_party_connected_line *ast_channel_connected(struct ast_channel *chan)
 {
 	return &chan->connected;
 }
-struct ast_party_connected_line *ast_channel_connected_indicated(struct ast_channel *chan)
-{
-	return &chan->connected_indicated;
-}
 struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
 {
 	return ast_party_id_merge(&chan->connected.id, &chan->connected.priv);
@@ -1108,16 +1033,6 @@ void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *valu
 	chan->creationtime = *value;
 }
 
-struct timeval ast_channel_answertime(struct ast_channel *chan)
-{
-	return chan->answertime;
-}
-
-void ast_channel_answertime_set(struct ast_channel *chan, struct timeval *value)
-{
-	chan->answertime = *value;
-}
-
 /* Evil softhangup accessors */
 int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
 {
@@ -1136,33 +1051,6 @@ void ast_channel_softhangup_internal_flag_clear(struct ast_channel *chan, int va
 	chan ->softhangup &= ~value;
 }
 
-int ast_channel_unbridged_nolock(struct ast_channel *chan)
-{
-	return chan->unbridged;
-}
-
-int ast_channel_unbridged(struct ast_channel *chan)
-{
-	int res;
-	ast_channel_lock(chan);
-	res = ast_channel_unbridged_nolock(chan);
-	ast_channel_unlock(chan);
-	return res;
-}
-
-void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value)
-{
-	chan->unbridged = value;
-	ast_queue_frame(chan, &ast_null_frame);
-}
-
-void ast_channel_set_unbridged(struct ast_channel *chan, int value)
-{
-	ast_channel_lock(chan);
-	ast_channel_set_unbridged_nolock(chan, value);
-	ast_channel_unlock(chan);
-}
-
 void ast_channel_callid_cleanup(struct ast_channel *chan)
 {
 	if (chan->callid) {
@@ -1210,7 +1098,14 @@ void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_nam
 int ast_channel_alert_write(struct ast_channel *chan)
 {
 	char blah = 0x7F;
-	return ast_channel_alert_writable(chan) && write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah);
+
+	if (!ast_channel_alert_writable(chan)) {
+		errno = EBADF;
+		return 0;
+	}
+	/* preset errno in case returned size does not match */
+	errno = EPIPE;
+	return write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah);
 }
 
 ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan)
@@ -1261,9 +1156,11 @@ void ast_channel_internal_alertpipe_close(struct ast_channel *chan)
 {
 	if (ast_channel_internal_alert_readable(chan)) {
 		close(chan->alertpipe[0]);
+		chan->alertpipe[0] = -1;
 	}
 	if (ast_channel_alert_writable(chan)) {
 		close(chan->alertpipe[1]);
+		chan->alertpipe[1] = -1;
 	}
 }
 
@@ -1361,16 +1258,15 @@ struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan)
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
 {
 	chan->bridge = value;
-	ast_channel_publish_snapshot(chan);
 }
 
-struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan)
+struct ast_channel *ast_channel_internal_bridged_channel(const struct ast_channel *chan)
 {
-	return chan->bridge_channel;
+	return chan->bridged_channel;
 }
-void ast_channel_internal_bridge_channel_set(struct ast_channel *chan, struct ast_bridge_channel *value)
+void ast_channel_internal_bridged_channel_set(struct ast_channel *chan, struct ast_channel *value)
 {
-	chan->bridge_channel = value;
+	chan->bridged_channel = value;
 }
 
 struct ast_flags *ast_channel_flags(struct ast_channel *chan)
@@ -1444,7 +1340,7 @@ static int pvt_cause_cmp_fn(void *obj, void *vstr, int flags)
 
 #define DIALED_CAUSES_BUCKETS 37
 
-struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function)
+struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *file, int line, const char *function)
 {
 	struct ast_channel *tmp;
 #if defined(REF_DEBUG)
@@ -1457,98 +1353,21 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
 	tmp = ao2_alloc(sizeof(*tmp), destructor);
 #endif
 
-	if ((ast_string_field_init(tmp, 128))) {
-		return ast_channel_unref(tmp);
+	if (!tmp) {
+		return NULL;
 	}
 
-	if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) {
+	if ((ast_string_field_init(tmp, 128))) {
 		return ast_channel_unref(tmp);
 	}
 
-	/* set the creation time in the uniqueid */
-	tmp->uniqueid.creation_time = time(NULL);
-	tmp->uniqueid.creation_unique = ast_atomic_fetchadd_int(&uniqueint, 1);
-
-	/* use provided id or default to historical {system-}time.# format */
-	if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
-		ast_copy_string(tmp->uniqueid.unique_id, assignedids->uniqueid, sizeof(tmp->uniqueid.unique_id));
-	} else if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
-		snprintf(tmp->uniqueid.unique_id, sizeof(tmp->uniqueid.unique_id), "%li.%d",
-			(long)(tmp->uniqueid.creation_time),
-			tmp->uniqueid.creation_unique);
-	} else {
-		snprintf(tmp->uniqueid.unique_id, sizeof(tmp->uniqueid.unique_id), "%s-%li.%d",
-			ast_config_AST_SYSTEM_NAME,
-			(long)(tmp->uniqueid.creation_time),
-			tmp->uniqueid.creation_unique);
-	}
-
-	/* copy linked id from parent channel if known */
-	if (requestor) {
-		tmp->linkedid = requestor->linkedid;
-	} else {
-		tmp->linkedid = tmp->uniqueid;
+	if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) {
+	        return ast_channel_unref(tmp);
 	}
 
 	return tmp;
 }
 
-struct ast_channel *ast_channel_internal_oldest_linkedid(struct ast_channel *a, struct ast_channel *b)
-{
-	ast_assert(a->linkedid.creation_time != 0);
-	ast_assert(b->linkedid.creation_time != 0);
-
-	if (a->linkedid.creation_time < b->linkedid.creation_time) {
-		return a;
-	}
-	if (b->linkedid.creation_time < a->linkedid.creation_time) {
-		return b;
-	}
-	if (a->linkedid.creation_unique < b->linkedid.creation_unique) {
-		return a;
-	}
-	return b;
-}
-
-void ast_channel_internal_copy_linkedid(struct ast_channel *dest, struct ast_channel *source)
-{
-	if (dest->linkedid.creation_time == source->linkedid.creation_time
-		&& dest->linkedid.creation_unique == source->linkedid.creation_unique
-		&& !strcmp(dest->linkedid.unique_id, source->linkedid.unique_id)) {
-		return;
-	}
-	dest->linkedid = source->linkedid;
-	ast_channel_publish_snapshot(dest);
-}
-
-void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, struct ast_channel *b)
-{
-	struct ast_channel_id temp;
-
-	temp = a->uniqueid;
-	a->uniqueid = b->uniqueid;
-	b->uniqueid = temp;
-
-	temp = a->linkedid;
-	a->linkedid = b->linkedid;
-	b->linkedid = temp;
-}
-
-void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b)
-{
-	struct stasis_cp_single *temp;
-
-	temp = a->topics;
-	a->topics = b->topics;
-	b->topics = temp;
-}
-
-void ast_channel_internal_set_fake_ids(struct ast_channel *chan, const char *uniqueid, const char *linkedid)
-{
-	ast_copy_string(chan->uniqueid.unique_id, uniqueid, sizeof(chan->uniqueid.unique_id));
-	ast_copy_string(chan->linkedid.unique_id, linkedid, sizeof(chan->linkedid.unique_id));
-}
-
 void ast_channel_internal_cleanup(struct ast_channel *chan)
 {
 	if (chan->dialed_causes) {
@@ -1558,12 +1377,6 @@ void ast_channel_internal_cleanup(struct ast_channel *chan)
 	}
 
 	ast_string_field_free_memory(chan);
-
-	chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);
-	chan->endpoint_cache_forward = stasis_forward_cancel(chan->endpoint_cache_forward);
-
-	stasis_cp_single_unsubscribe(chan->topics);
-	chan->topics = NULL;
 }
 
 void ast_channel_internal_finalize(struct ast_channel *chan)
@@ -1575,62 +1388,3 @@ int ast_channel_internal_is_finalized(struct ast_channel *chan)
 {
 	return chan->finalized;
 }
-
-struct stasis_topic *ast_channel_topic(struct ast_channel *chan)
-{
-	if (!chan) {
-		return ast_channel_topic_all();
-	}
-
-	return stasis_cp_single_topic(chan->topics);
-}
-
-struct stasis_topic *ast_channel_topic_cached(struct ast_channel *chan)
-{
-	if (!chan) {
-		return ast_channel_topic_all_cached();
-	}
-
-	return stasis_cp_single_topic_cached(chan->topics);
-}
-
-int ast_channel_forward_endpoint(struct ast_channel *chan,
-	struct ast_endpoint *endpoint)
-{
-	ast_assert(chan != NULL);
-	ast_assert(endpoint != NULL);
-
-	chan->endpoint_forward =
-		stasis_forward_all(ast_channel_topic(chan),
-			ast_endpoint_topic(endpoint));
-	if (!chan->endpoint_forward) {
-		return -1;
-	}
-
-	chan->endpoint_cache_forward = stasis_forward_all(ast_channel_topic_cached(chan),
-		ast_endpoint_topic(endpoint));
-	if (!chan->endpoint_cache_forward) {
-		chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);
-		return -1;
-	}
-
-	return 0;
-}
-
-int ast_channel_internal_setup_topics(struct ast_channel *chan)
-{
-	const char *topic_name = chan->uniqueid.unique_id;
-	ast_assert(chan->topics == NULL);
-
-	if (ast_strlen_zero(topic_name)) {
-		topic_name = "<dummy-channel>";
-	}
-
-	chan->topics = stasis_cp_single_create(
-		ast_channel_cache_all(), topic_name);
-	if (!chan->topics) {
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/chanvars.c b/main/chanvars.c
index 7e271ff..ed71a27 100644
--- a/main/chanvars.c
+++ b/main/chanvars.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424964 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/chanvars.h"
 #include "asterisk/strings.h"
@@ -62,7 +62,8 @@ struct ast_var_t *ast_var_assign(const char *name, const char *value)
 
 void ast_var_delete(struct ast_var_t *var)
 {
-	ast_free(var);
+	if (var)
+		ast_free(var);
 }
 
 const char *ast_var_name(const struct ast_var_t *var)
@@ -90,67 +91,4 @@ const char *ast_var_value(const struct ast_var_t *var)
 	return (var ? var->value : NULL);
 }
 
-char *ast_var_find(const struct varshead *head, const char *name)
-{
-	struct ast_var_t *var;
-
-	AST_LIST_TRAVERSE(head, var, entries) {
-		if (!strcmp(name, var->name)) {
-			return var->value;
-		}
-	}
-	return NULL;
-}
-
-struct varshead *ast_var_list_create(void)
-{
-	struct varshead *head;
-
-	head = ast_calloc(1, sizeof(*head));
-	if (!head) {
-		return NULL;
-	}
-	AST_LIST_HEAD_INIT_NOLOCK(head);
-	return head;
-}
-
-void ast_var_list_destroy(struct varshead *head)
-{
-	struct ast_var_t *var;
-
-	if (!head) {
-		return;
-	}
 
-	while ((var = AST_LIST_REMOVE_HEAD(head, entries))) {
-		ast_var_delete(var);
-	}
-
-	ast_free(head);
-}
-
-struct varshead *ast_var_list_clone(struct varshead *head)
-{
-	struct varshead *clone;
-	struct ast_var_t *var, *newvar;
-
-	if (!head) {
-		return NULL;
-	}
-
-	clone = ast_var_list_create();
-	if (!clone) {
-		return NULL;
-	}
-
-	AST_VAR_LIST_TRAVERSE(head, var) {
-		newvar = ast_var_assign(var->name, var->value);
-		if (!newvar) {
-			ast_var_list_destroy(clone);
-			return NULL;
-		}
-		AST_VAR_LIST_INSERT_TAIL(clone, newvar);
-	}
-
-	return clone;
-}
diff --git a/main/cli.c b/main/cli.c
index 7823689..2d14d40 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -23,22 +23,13 @@
  * \author Mark Spencer <markster at digium.com>
  */
 
-/*! \li \ref cli.c uses the configuration file \ref cli_permissions.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page cli_permissions.conf cli_permissions.conf
- * \verbinclude cli_permissions.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422665 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_MODULE_DIR */
@@ -60,9 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422665 $")
 #include "asterisk/lock.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/translate.h"
-#include "asterisk/bridge.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
 
 /*!
  * \brief List of restrictions per user.
@@ -291,30 +279,14 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		return CLI_SUCCESS;
 	}
 	for (x = e->args; x < a->argc; x++) {
-		enum ast_module_reload_result res = ast_module_reload(a->argv[x]);
+		int res = ast_module_reload(a->argv[x]);
+		/* XXX reload has multiple error returns, including -1 on error and 2 on success */
 		switch (res) {
-		case AST_MODULE_RELOAD_NOT_FOUND:
+		case 0:
 			ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
 			break;
-		case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
-			ast_cli(a->fd, "The module '%s' does not support reloads\n", a->argv[x]);
-			break;
-		case AST_MODULE_RELOAD_QUEUED:
-			ast_cli(a->fd, "Asterisk cannot reload a module yet; request queued\n");
-			break;
-		case AST_MODULE_RELOAD_ERROR:
-			ast_cli(a->fd, "The module '%s' reported a reload failure\n", a->argv[x]);
-			break;
-		case AST_MODULE_RELOAD_IN_PROGRESS:
-			ast_cli(a->fd, "A module reload request is already in progress; please be patient\n");
-			break;
-		case AST_MODULE_RELOAD_UNINITIALIZED:
-			ast_cli(a->fd, "The module '%s' was not properly initialized. Before reloading"
-					" the module, you must run \"module load %s\" and fix whatever is"
-					" preventing the module from being initialized.\n", a->argv[x], a->argv[x]);
-			break;
-		case AST_MODULE_RELOAD_SUCCESS:
-			ast_cli(a->fd, "Module '%s' reloaded successfully.\n", a->argv[x]);
+		case 1:
+			ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
 			break;
 		}
 	}
@@ -487,7 +459,7 @@ static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 				return ast_strdup("atleast");
 			}
 #if !defined(LOW_MEMORY)
-		} else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+		} else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel"))
 			|| (a->pos == 5 && atleast)) {
 			const char *pos = S_OR(a->argv[a->pos], "");
 
@@ -772,20 +744,17 @@ static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 	return CLI_SUCCESS;
 }
 
-#define MODLIST_FORMAT  "%-30s %-40.40s %-10d %-11s %13s\n"
-#define MODLIST_FORMAT2 "%-30s %-40.40s %-10s %-11s %13s\n"
+#define MODLIST_FORMAT  "%-30s %-40.40s %-10d\n"
+#define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
 
 AST_MUTEX_DEFINE_STATIC(climodentrylock);
 static int climodentryfd = -1;
 
-static int modlist_modentry(const char *module, const char *description,
-		int usecnt, const char *status, const char *like,
-		enum ast_module_support_level support_level)
+static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
 {
 	/* Comparing the like with the module */
 	if (strcasestr(module, like) ) {
-		ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt,
-				status, ast_module_support_level_to_string(support_level));
+		ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
 		return 1;
 	}
 	return 0;
@@ -802,7 +771,7 @@ static void print_uptimestr(int fd, struct timeval timeval, const char *prefix,
 #define DAY (HOUR*24)
 #define WEEK (DAY*7)
 #define YEAR (DAY*365)
-#define NEEDCOMMA(x) ((x)? ",": "")	/* define if we need a comma */
+#define NEEDCOMMA(x) ((x) ? ", " : "")	/* define if we need a comma */
 	if (timeval.tv_sec < 0)	/* invalid, nothing to show */
 		return;
 
@@ -814,31 +783,33 @@ static void print_uptimestr(int fd, struct timeval timeval, const char *prefix,
 	if (timeval.tv_sec > YEAR) {
 		x = (timeval.tv_sec / YEAR);
 		timeval.tv_sec -= (x * YEAR);
-		ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
+		ast_str_append(&out, 0, "%d year%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
 	}
 	if (timeval.tv_sec > WEEK) {
 		x = (timeval.tv_sec / WEEK);
 		timeval.tv_sec -= (x * WEEK);
-		ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
+		ast_str_append(&out, 0, "%d week%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
 	}
 	if (timeval.tv_sec > DAY) {
 		x = (timeval.tv_sec / DAY);
 		timeval.tv_sec -= (x * DAY);
-		ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
+		ast_str_append(&out, 0, "%d day%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
 	}
 	if (timeval.tv_sec > HOUR) {
 		x = (timeval.tv_sec / HOUR);
 		timeval.tv_sec -= (x * HOUR);
-		ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
+		ast_str_append(&out, 0, "%d hour%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
 	}
 	if (timeval.tv_sec > MINUTE) {
 		x = (timeval.tv_sec / MINUTE);
 		timeval.tv_sec -= (x * MINUTE);
-		ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
+		ast_str_append(&out, 0, "%d minute%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
 	}
 	x = timeval.tv_sec;
-	if (x > 0 || ast_str_strlen(out) == 0)	/* if there is nothing, print 0 seconds */
-		ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
+	if (x > 0 || ast_str_strlen(out) == 0) {
+		/* if there is nothing, print 0 seconds */
+		ast_str_append(&out, 0, "%d second%s", x, ESS(x));
+	}
 	ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
 }
 
@@ -912,7 +883,7 @@ static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
 	ast_mutex_lock(&climodentrylock);
 	climodentryfd = a->fd; /* global, protected by climodentrylock */
-	ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count", "Status", "Support Level");
+	ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
 	ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
 	climodentryfd = -1;
 	ast_mutex_unlock(&climodentrylock);
@@ -959,10 +930,10 @@ static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	} else
 		return CLI_SHOWUSAGE;
 
-	if (ast_option_maxcalls) {
+	if (option_maxcalls) {
 		ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
-		   ast_active_calls(), ast_option_maxcalls, ESS(ast_active_calls()),
-		   ((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
+		   ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
+		   ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
 	} else {
 		ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
 	}
@@ -984,10 +955,9 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 #define VERBOSE_FORMAT_STRING  "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
 
-	RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
-	struct ao2_iterator it_chans;
-	struct stasis_message *msg;
+	struct ast_channel *c = NULL;
 	int numchans = 0, concise = 0, verbose = 0, count = 0;
+	struct ast_channel_iterator *iter = NULL;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -1019,28 +989,29 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 	} else if (a->argc != e->args - 1)
 		return CLI_SHOWUSAGE;
 
-
-	if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) {
-		ast_cli(a->fd, "Failed to retrieve cached channels\n");
-		return CLI_SUCCESS;
-	}
-
 	if (!count) {
 		if (!concise && !verbose)
 			ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
 		else if (verbose)
 			ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
-				"CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID");
+				"CallerID", "Duration", "Accountcode", "PeerAccount", "BridgedTo");
 	}
 
-	it_chans = ao2_iterator_init(channels, 0);
-	for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
-		struct ast_channel_snapshot *cs = stasis_message_data(msg);
+	if (!count && !(iter = ast_channel_iterator_all_new())) {
+		return CLI_FAILURE;
+	}
+
+	for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
+		struct ast_channel *bc;
 		char durbuf[10] = "-";
 
+		ast_channel_lock(c);
+
+		bc = ast_bridged_channel(c);
+
 		if (!count) {
-			if ((concise || verbose)  && !ast_tvzero(cs->creationtime)) {
-				int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+			if ((concise || verbose)  && ast_channel_cdr(c) && !ast_tvzero(ast_channel_cdr(c)->start)) {
+				int duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_cdr(c)->start) / 1000);
 				if (verbose) {
 					int durh = duration / 3600;
 					int durm = (duration % 3600) / 60;
@@ -1051,46 +1022,50 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 				}
 			}
 			if (concise) {
-				ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-					S_OR(cs->appl, "(None)"),
-					cs->data,
-					cs->caller_number,
-					cs->accountcode,
-					cs->peeraccount,
-					cs->amaflags,
+				ast_cli(a->fd, CONCISE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
+					ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
+					S_OR(ast_channel_data(c), ""),	/* XXX different from verbose ? */
+					S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
+					S_OR(ast_channel_accountcode(c), ""),
+					S_OR(ast_channel_peeraccount(c), ""),
+					ast_channel_amaflags(c),
 					durbuf,
-					cs->bridgeid,
-					cs->uniqueid);
+					bc ? ast_channel_name(bc) : "(None)",
+					ast_channel_uniqueid(c));
 			} else if (verbose) {
-				ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-					S_OR(cs->appl, "(None)"),
-					S_OR(cs->data, "(Empty)"),
-					cs->caller_number,
+				ast_cli(a->fd, VERBOSE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
+					ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
+					ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)" ): "(None)",
+					S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
 					durbuf,
-					cs->accountcode,
-					cs->peeraccount,
-					cs->bridgeid);
+					S_OR(ast_channel_accountcode(c), ""),
+					S_OR(ast_channel_peeraccount(c), ""),
+					bc ? ast_channel_name(bc) : "(None)");
 			} else {
 				char locbuf[40] = "(None)";
 				char appdata[40] = "(None)";
 
-				if (!cs->context && !cs->exten)
-					snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority);
-				if (cs->appl)
-					snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, ""));
-				ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata);
+				if (!ast_strlen_zero(ast_channel_context(c)) && !ast_strlen_zero(ast_channel_exten(c)))
+					snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", ast_channel_exten(c), ast_channel_context(c), ast_channel_priority(c));
+				if (ast_channel_appl(c))
+					snprintf(appdata, sizeof(appdata), "%s(%s)", ast_channel_appl(c), S_OR(ast_channel_data(c), ""));
+				ast_cli(a->fd, FORMAT_STRING, ast_channel_name(c), locbuf, ast_state2str(ast_channel_state(c)), appdata);
 			}
 		}
+		ast_channel_unlock(c);
+	}
+
+	if (iter) {
+		ast_channel_iterator_destroy(iter);
 	}
-	ao2_iterator_destroy(&it_chans);
 
 	if (!concise) {
 		numchans = ast_active_channels();
 		ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
-		if (ast_option_maxcalls)
+		if (option_maxcalls)
 			ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
-				ast_active_calls(), ast_option_maxcalls, ESS(ast_active_calls()),
-				((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
+				ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
+				((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
 		else
 			ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
 
@@ -1516,20 +1491,22 @@ static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, str
 
 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct ast_channel *chan;
+	struct ast_channel *c=NULL;
 	struct timeval now;
 	char cdrtime[256];
-	struct ast_str *obuf;/*!< Buffer for CDR variables. */
+	char nf[256];
+	struct ast_str *write_transpath = ast_str_alloca(256);
+	struct ast_str *read_transpath = ast_str_alloca(256);
+	struct ast_str *obuf;/*!< Buffer for variable, CDR variable, and trace output. */
 	struct ast_str *output;/*!< Accumulation buffer for all output. */
 	long elapsed_seconds=0;
 	int hour=0, min=0, sec=0;
-	struct ast_var_t *var;
-	struct ast_str *write_transpath = ast_str_alloca(256);
-	struct ast_str *read_transpath = ast_str_alloca(256);
-	struct ast_str *codec_buf = ast_str_alloca(64);
-	struct ast_bridge *bridge;
 	struct ast_callid *callid;
-	char callid_buf[32];
+	char call_identifier_str[AST_CALLID_BUFFER_LENGTH] = "";
+	struct ast_party_id effective_connected_id;
+#ifdef CHANNEL_TRACE
+	int trace_enabled;
+#endif
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -1546,27 +1523,26 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		return CLI_SHOWUSAGE;
 	}
 
+	now = ast_tvnow();
+
+	if (!(c = ast_channel_get_by_name(a->argv[3]))) {
+		ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
+		return CLI_SUCCESS;
+	}
+
 	obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
 	if (!obuf) {
 		return CLI_FAILURE;
 	}
-
 	output = ast_str_create(8192);
 	if (!output) {
 		return CLI_FAILURE;
 	}
 
-	chan = ast_channel_get_by_name(a->argv[3]);
-	if (!chan) {
-		ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
-		return CLI_SUCCESS;
-	}
-
-	now = ast_tvnow();
-	ast_channel_lock(chan);
+	ast_channel_lock(c);
 
-	if (!ast_tvzero(ast_channel_creationtime(chan))) {
-		elapsed_seconds = now.tv_sec - ast_channel_creationtime(chan).tv_sec;
+	if (ast_channel_cdr(c)) {
+		elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
 		hour = elapsed_seconds / 3600;
 		min = (elapsed_seconds % 3600) / 60;
 		sec = elapsed_seconds % 60;
@@ -1575,17 +1551,14 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		strcpy(cdrtime, "N/A");
 	}
 
-	ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath);
-	ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath);
-
-	bridge = ast_channel_get_bridge(chan);
-	callid_buf[0] = '\0';
-	callid = ast_channel_callid(chan);
-	if (callid) {
-		ast_callid_strnprint(callid_buf, sizeof(callid_buf), callid);
+	/* Construct the call identifier string based on the status of the channel's call identifier */
+	if ((callid = ast_channel_callid(c))) {
+		ast_callid_strnprint(call_identifier_str, sizeof(call_identifier_str), callid);
 		ast_callid_unref(callid);
 	}
 
+	effective_connected_id = ast_channel_connected_effective_id(c);
+
 	ast_str_append(&output, 0,
 		" -- General --\n"
 		"           Name: %s\n"
@@ -1601,14 +1574,19 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		"    DNID Digits: %s\n"
 		"       Language: %s\n"
 		"          State: %s (%u)\n"
+		"          Rings: %d\n"
 		"  NativeFormats: %s\n"
 		"    WriteFormat: %s\n"
 		"     ReadFormat: %s\n"
 		" WriteTranscode: %s %s\n"
 		"  ReadTranscode: %s %s\n"
+		"1st File Descriptor: %d\n"
+		"      Frames in: %u%s\n"
+		"     Frames out: %u%s\n"
 		" Time to Hangup: %ld\n"
 		"   Elapsed Time: %s\n"
-		"      Bridge ID: %s\n"
+		"  Direct Bridge: %s\n"
+		"Indirect Bridge: %s\n"
 		" --   PBX   --\n"
 		"        Context: %s\n"
 		"      Extension: %s\n"
@@ -1617,65 +1595,57 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		"   Pickup Group: %llu\n"
 		"    Application: %s\n"
 		"           Data: %s\n"
+		"    Blocking in: %s\n"
 		" Call Identifer: %s\n",
-		ast_channel_name(chan),
-		ast_channel_tech(chan)->type,
-		ast_channel_uniqueid(chan),
-		ast_channel_linkedid(chan),
-		S_COR(ast_channel_caller(chan)->id.number.valid,
-		      ast_channel_caller(chan)->id.number.str, "(N/A)"),
-		S_COR(ast_channel_caller(chan)->id.name.valid,
-		      ast_channel_caller(chan)->id.name.str, "(N/A)"),
-		S_COR(ast_channel_connected(chan)->id.number.valid,
-		      ast_channel_connected(chan)->id.number.str, "(N/A)"),
-		S_COR(ast_channel_connected(chan)->id.name.valid,
-		      ast_channel_connected(chan)->id.name.str, "(N/A)"),
-		S_COR(ast_channel_connected_effective_id(chan).number.valid,
-		      ast_channel_connected_effective_id(chan).number.str, "(N/A)"),
-		S_COR(ast_channel_connected_effective_id(chan).name.valid,
-		      ast_channel_connected_effective_id(chan).name.str, "(N/A)"),
-		S_OR(ast_channel_dialed(chan)->number.str, "(N/A)"),
-		ast_channel_language(chan),
-		ast_state2str(ast_channel_state(chan)),
-		ast_channel_state(chan),
-		ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf),
-		ast_format_get_name(ast_channel_writeformat(chan)),
-		ast_format_get_name(ast_channel_readformat(chan)),
-		ast_str_strlen(write_transpath) ? "Yes" : "No",
-		ast_str_buffer(write_transpath),
-		ast_str_strlen(read_transpath) ? "Yes" : "No",
-		ast_str_buffer(read_transpath),
-		ast_channel_whentohangup(chan)->tv_sec,
-		cdrtime,
-		bridge ? bridge->uniqueid : "(Not bridged)",
-		ast_channel_context(chan),
-		ast_channel_exten(chan),
-		ast_channel_priority(chan),
-		ast_channel_callgroup(chan),
-		ast_channel_pickupgroup(chan),
-		S_OR(ast_channel_appl(chan), "(N/A)"),
-		S_OR(ast_channel_data(chan), "(Empty)"),
-		S_OR(callid_buf, "(None)")
-		);
-	ast_str_append(&output, 0, "      Variables:\n");
-
-	AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
-		ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var));
-	}
-
-	if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)
-		&& ast_cdr_serialize_variables(ast_channel_name(chan), &obuf, '=', '\n')) {
+		ast_channel_name(c), ast_channel_tech(c)->type, ast_channel_uniqueid(c), ast_channel_linkedid(c),
+		S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
+		S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
+		S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
+		S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"),
+		S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "(N/A)"),
+		S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "(N/A)"),
+		S_OR(ast_channel_dialed(c)->number.str, "(N/A)"),
+		ast_channel_language(c),
+		ast_state2str(ast_channel_state(c)), ast_channel_state(c), ast_channel_rings(c),
+		ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)),
+		ast_getformatname(ast_channel_writeformat(c)),
+		ast_getformatname(ast_channel_readformat(c)),
+		ast_channel_writetrans(c) ? "Yes" : "No",
+		ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
+		ast_channel_readtrans(c) ? "Yes" : "No",
+		ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath),
+		ast_channel_fd(c, 0),
+		ast_channel_fin(c) & ~DEBUGCHAN_FLAG, (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
+		ast_channel_fout(c) & ~DEBUGCHAN_FLAG, (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
+		(long)ast_channel_whentohangup(c)->tv_sec,
+		cdrtime, ast_channel_internal_bridged_channel(c) ? ast_channel_name(ast_channel_internal_bridged_channel(c)) : "<none>", ast_bridged_channel(c) ? ast_channel_name(ast_bridged_channel(c)) : "<none>",
+		ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_callgroup(c), ast_channel_pickupgroup(c), (ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)" ),
+		(ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)"),
+		(ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"),
+		S_OR(call_identifier_str, "(None)"));
+
+	if (pbx_builtin_serialize_variables(c, &obuf)) {
+		ast_str_append(&output, 0, "      Variables:\n%s\n", ast_str_buffer(obuf));
+	}
+
+	if (ast_channel_cdr(c) && ast_cdr_serialize_variables(ast_channel_cdr(c), &obuf, '=', '\n', 1)) {
 		ast_str_append(&output, 0, "  CDR Variables:\n%s\n", ast_str_buffer(obuf));
 	}
 
-	ast_channel_unlock(chan);
+#ifdef CHANNEL_TRACE
+	trace_enabled = ast_channel_trace_is_enabled(c);
+	ast_str_append(&output, 0, "  Context Trace: %s\n",
+		trace_enabled ? "Enabled" : "Disabled");
+	if (trace_enabled && ast_channel_trace_serialize(c, &obuf)) {
+		ast_str_append(&output, 0, "          Trace:\n%s\n", ast_str_buffer(obuf));
+	}
+#endif
+
+	ast_channel_unlock(c);
+	c = ast_channel_unref(c);
 
 	ast_cli(a->fd, "%s", ast_str_buffer(output));
 	ast_free(output);
-
-	ao2_cleanup(bridge);
-	ast_channel_unref(chan);
-
 	return CLI_SUCCESS;
 }
 
@@ -1697,33 +1667,38 @@ char *ast_cli_complete(const char *word, const char * const choices[], int state
 
 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
 {
-	int wordlen = strlen(word), which = 0;
-	RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup);
-	char *ret = NULL;
-	struct ao2_iterator iter;
-	struct stasis_message *msg;
+	struct ast_channel *c = NULL;
+	int which = 0;
+	char notfound = '\0';
+	char *ret = ¬found; /* so NULL can break the loop */
+	struct ast_channel_iterator *iter;
 
 	if (pos != rpos) {
 		return NULL;
 	}
 
-	if (!(cached_channels = stasis_cache_dump(ast_channel_cache(), ast_channel_snapshot_type()))) {
-		return NULL;
+	if (ast_strlen_zero(word)) {
+		iter = ast_channel_iterator_all_new();
+	} else {
+		iter = ast_channel_iterator_by_name_new(word, strlen(word));
 	}
 
-	iter = ao2_iterator_init(cached_channels, 0);
-	for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
-		struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+	if (!iter) {
+		return NULL;
+	}
 
-		if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {
-			ret = ast_strdup(snapshot->name);
-			ao2_ref(msg, -1);
-			break;
+	while (ret == &notfound && (c = ast_channel_iterator_next(iter))) {
+		if (++which > state) {
+			ast_channel_lock(c);
+			ret = ast_strdup(ast_channel_name(c));
+			ast_channel_unlock(c);
 		}
+		ast_channel_unref(c);
 	}
-	ao2_iterator_destroy(&iter);
 
-	return ret;
+	ast_channel_iterator_destroy(iter);
+
+	return ret == &notfound ? NULL : ret;
 }
 
 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -2027,7 +2002,7 @@ static void cli_shutdown(void)
 void ast_builtins_init(void)
 {
 	ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
-	ast_register_atexit(cli_shutdown);
+	ast_register_cleanup(cli_shutdown);
 }
 
 /*!
@@ -2125,7 +2100,7 @@ static char *is_prefix(const char *word, const char *token,
  * \param cmds
  * \param match_type has 3 possible values:
  *      0       returns if the search key is equal or longer than the entry.
- *			    note that trailing optional arguments are skipped.
+ *		            note that trailing optional arguments are skipped.
  *      -1      true if the mismatch is on the last word XXX not true!
  *      1       true only on complete, exact match.
  *
@@ -2354,8 +2329,7 @@ static char *help1(int fd, const char * const match[], int locked)
 			continue;
 		if (match && strncasecmp(matchstr, e->_full_cmd, len))
 			continue;
-		ast_cli(fd, "%-30s -- %s\n", e->_full_cmd,
-			S_OR(e->summary, "<no description available>"));
+		ast_cli(fd, "%30.30s %s\n", e->_full_cmd, S_OR(e->summary, "<no description available>"));
 		found++;
 	}
 	if (!locked)
diff --git a/main/codec.c b/main/codec.c
deleted file mode 100644
index 0f5f49f..0000000
--- a/main/codec.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Codecs API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/frame.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-#include "asterisk/module.h"
-#include "asterisk/cli.h"
-
-/*! \brief Number of buckets to use for codecs (should be prime for performance reasons) */
-#define CODEC_BUCKETS 53
-
-/*! \brief Current identifier value for newly registered codec */
-static int codec_id = 1;
-
-/*! \brief Registered codecs */
-static struct ao2_container *codecs;
-
-static int codec_hash(const void *obj, int flags)
-{
-	const struct ast_codec *codec;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_SEARCH_OBJECT:
-		codec = obj;
-		return ast_str_hash(codec->name);
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int codec_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_codec *left = obj;
-	const struct ast_codec *right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right->name;
-		cmp = strcmp(left->name, right_key);
-
-		if (right->type != AST_MEDIA_TYPE_UNKNOWN) {
-			cmp |= (right->type != left->type);
-		}
-
-		/* BUGBUG: this will allow a match on a codec by name only.
-		 * This is particularly useful when executed by the CLI; if
-		 * that is not needed in translate.c, this can be removed.
-		 */
-		if (right->sample_rate) {
-			cmp |= (right->sample_rate != left->sample_rate);
-		}
-		break;
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left->name, right_key, strlen(right_key));
-		break;
-	default:
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-
-	return CMP_MATCH;
-}
-
-static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ao2_iterator i;
-	struct ast_codec *codec;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "core show codecs [audio|video|image|text]";
-		e->usage =
-			"Usage: core show codecs [audio|video|image|text]\n"
-			"       Displays codec mapping\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if ((a->argc < 3) || (a->argc > 4)) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!ast_opt_dont_warn) {
-		ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
-				"\tIt does not indicate anything about your configuration.\n");
-	}
-
-	ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
-	ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
-
-	ao2_rdlock(codecs);
-	i = ao2_iterator_init(codecs, AO2_ITERATOR_DONTLOCK);
-
-	for (; (codec = ao2_iterator_next(&i)); ao2_ref(codec, -1)) {
-		if (a->argc == 4) {
-			if (!strcasecmp(a->argv[3], "audio")) {
-				if (codec->type != AST_MEDIA_TYPE_AUDIO) {
-					continue;
-				}
-			} else if (!strcasecmp(a->argv[3], "video")) {
-				if (codec->type != AST_MEDIA_TYPE_VIDEO) {
-					continue;
-				}
-			} else if (!strcasecmp(a->argv[3], "image")) {
-				if (codec->type != AST_MEDIA_TYPE_IMAGE) {
-					continue;
-				}
-			} else if (!strcasecmp(a->argv[3], "text")) {
-				if (codec->type != AST_MEDIA_TYPE_TEXT) {
-					continue;
-				}
-			} else {
-				continue;
-			}
-		}
-
-		ast_cli(a->fd, "%8u %5s %8s (%s)\n",
-			codec->id,
-			ast_codec_media_type2str(codec->type),
-			codec->name,
-			codec->description);
-	}
-
-	ao2_iterator_destroy(&i);
-	ao2_unlock(codecs);
-
-	return CLI_SUCCESS;
-}
-
-/*! \brief Callback function for getting a codec based on unique identifier */
-static int codec_id_cmp(void *obj, void *arg, int flags)
-{
-	struct ast_codec *codec = obj;
-	int *id = arg;
-
-	return (codec->id == *id) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int type_punned_codec;
-	struct ast_codec *codec;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "core show codec";
-		e->usage =
-			"Usage: core show codec <number>\n"
-			"       Displays codec mapping\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
-		return CLI_SHOWUSAGE;
-	}
-
-	codec = ao2_callback(codecs, 0, codec_id_cmp, &type_punned_codec);
-	if (!codec) {
-		ast_cli(a->fd, "Codec %d not found\n", type_punned_codec);
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, "%11u %s\n", (unsigned int) codec->id, codec->description);
-
-	ao2_ref(codec, -1);
-
-	return CLI_SUCCESS;
-}
-
-/* Builtin Asterisk CLI-commands for debugging */
-static struct ast_cli_entry codec_cli[] = {
-	AST_CLI_DEFINE(show_codecs, "Displays a list of registered codecs"),
-	AST_CLI_DEFINE(show_codec, "Shows a specific codec"),
-};
-
-/*! \brief Function called when the process is shutting down */
-static void codec_shutdown(void)
-{
-	ast_cli_unregister_multiple(codec_cli, ARRAY_LEN(codec_cli));
-	ao2_cleanup(codecs);
-	codecs = NULL;
-}
-
-int ast_codec_init(void)
-{
-	codecs = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, CODEC_BUCKETS, codec_hash, codec_cmp);
-	if (!codecs) {
-		return -1;
-	}
-
-	ast_cli_register_multiple(codec_cli, ARRAY_LEN(codec_cli));
-	ast_register_atexit(codec_shutdown);
-
-	return 0;
-}
-
-static void codec_dtor(void *obj)
-{
-	struct ast_codec *codec;
-
-	codec = obj;
-
-	ast_module_unref(codec->mod);
-}
-
-int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod)
-{
-	SCOPED_AO2WRLOCK(lock, codecs);
-	struct ast_codec *codec_new;
-
-	/* Some types have specific requirements */
-	if (codec->type == AST_MEDIA_TYPE_UNKNOWN) {
-		ast_log(LOG_ERROR, "A media type must be specified for codec '%s'\n", codec->name);
-		return -1;
-	} else if (codec->type == AST_MEDIA_TYPE_AUDIO) {
-		if (!codec->sample_rate) {
-			ast_log(LOG_ERROR, "A sample rate must be specified for codec '%s' of type '%s'\n",
-				codec->name, ast_codec_media_type2str(codec->type));
-			return -1;
-		}
-	}
-
-	codec_new = ao2_find(codecs, codec, OBJ_SEARCH_OBJECT | OBJ_NOLOCK);
-	if (codec_new) {
-		ast_log(LOG_ERROR, "A codec with name '%s' of type '%s' and sample rate '%u' is already registered\n",
-			codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate);
-		ao2_ref(codec_new, -1);
-		return -1;
-	}
-
-	codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
-	if (!codec_new) {
-		ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n",
-			codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate);
-		return -1;
-	}
-	*codec_new = *codec;
-	codec_new->id = codec_id++;
-
-	ao2_link_flags(codecs, codec_new, OBJ_NOLOCK);
-
-	/* Once registered a codec can not be unregistered, and the module must persist */
-	ast_module_ref(mod);
-
-	ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n",
-		ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->id);
-
-	ao2_ref(codec_new, -1);
-
-	return 0;
-}
-
-struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate)
-{
-	struct ast_codec codec = {
-		.name = name,
-		.type = type,
-		.sample_rate = sample_rate,
-	};
-
-	return ao2_find(codecs, &codec, OBJ_SEARCH_OBJECT);
-}
-
-struct ast_codec *ast_codec_get_by_id(int id)
-{
-	return ao2_callback(codecs, 0, codec_id_cmp, &id);
-}
-
-int ast_codec_get_max(void)
-{
-	return codec_id;
-}
-
-const char *ast_codec_media_type2str(enum ast_media_type type)
-{
-	switch (type) {
-	case AST_MEDIA_TYPE_AUDIO:
-		return "audio";
-	case AST_MEDIA_TYPE_VIDEO:
-		return "video";
-	case AST_MEDIA_TYPE_IMAGE:
-		return "image";
-	case AST_MEDIA_TYPE_TEXT:
-		return "text";
-	default:
-		return "<unknown>";
-	}
-}
-
-unsigned int ast_codec_samples_count(struct ast_frame *frame)
-{
-	struct ast_codec *codec;
-	unsigned int samples = 0;
-
-	if ((frame->frametype != AST_FRAME_VOICE) &&
-		(frame->frametype != AST_FRAME_VIDEO) &&
-		(frame->frametype != AST_FRAME_IMAGE)) {
-		return 0;
-	}
-
-	/* BUGBUG - why not just get the codec pointer off the format?
-	This is a bit roundabout
-	*/
-	codec = ast_codec_get_by_id(ast_format_get_codec_id(frame->subclass.format));
-
-	if (codec->samples_count) {
-		samples = codec->samples_count(frame);
-	} else {
-		ast_log(LOG_WARNING, "Unable to calculate samples for codec %s\n",
-			ast_format_get_name(frame->subclass.format));
-	}
-
-	ao2_ref(codec, -1);
-	return samples;
-}
-
-unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples)
-{
-	if (!codec->get_length) {
-		return 0;
-	}
-
-	return codec->get_length(samples);
-}
diff --git a/main/codec_builtin.c b/main/codec_builtin.c
deleted file mode 100644
index a77e6b1..0000000
--- a/main/codec_builtin.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Built-in supported codecs
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/frame.h"
-
-enum frame_type {
-	TYPE_HIGH,     /* 0x0 */
-	TYPE_LOW,      /* 0x1 */
-	TYPE_SILENCE,  /* 0x2 */
-	TYPE_DONTSEND  /* 0x3 */
-};
-
-#define TYPE_MASK 0x3
-
-static int g723_len(unsigned char buf)
-{
-	enum frame_type type = buf & TYPE_MASK;
-
-	switch(type) {
-	case TYPE_DONTSEND:
-		return 0;
-		break;
-	case TYPE_SILENCE:
-		return 4;
-		break;
-	case TYPE_HIGH:
-		return 24;
-		break;
-	case TYPE_LOW:
-		return 20;
-		break;
-	default:
-		ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type);
-	}
-	return -1;
-}
-
-static int g723_samples(struct ast_frame *frame)
-{
-	unsigned char *buf = frame->data.ptr;
-	int pos = 0, samples = 0, res;
-
-	while(pos < frame->datalen) {
-		res = g723_len(buf[pos]);
-		if (res <= 0)
-			break;
-		samples += 240;
-		pos += res;
-	}
-
-	return samples;
-}
-
-static int g723_length(unsigned int samples)
-{
-	return (samples / 240) * 20;
-}
-
-static struct ast_codec g723 = {
-	.name = "g723",
-	.description = "G.723.1",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 30,
-	.maximum_ms = 300,
-	.default_ms = 30,
-	.minimum_bytes = 20,
-	.samples_count = g723_samples,
-	.get_length = g723_length,
-};
-
-static int none_samples(struct ast_frame *frame)
-{
-	return frame->datalen;
-}
-
-static int none_length(unsigned int samples) {
-	return samples;
-}
-
-static struct ast_codec none = {
-	.name = "none",
-	.description = "<Null> codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000, /* This must have some sample rate to prevent divide by 0 */
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.minimum_bytes = 20,
-	.samples_count = none_samples,
-	.get_length = none_length,
-};
-
-static int ulaw_samples(struct ast_frame *frame)
-{
-	return frame->datalen;
-}
-
-static int ulaw_length(unsigned int samples)
-{
-	return samples;
-}
-
-static struct ast_codec ulaw = {
-	.name = "ulaw",
-	.description = "G.711 u-law",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.minimum_bytes = 80,
-	.samples_count = ulaw_samples,
-	.get_length = ulaw_length,
-	.smooth = 1,
-};
-
-static struct ast_codec alaw = {
-	.name = "alaw",
-	.description = "G.711 a-law",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.minimum_bytes = 80,
-	.samples_count = ulaw_samples,
-	.get_length = ulaw_length,
-	.smooth = 1,
-};
-
-static int gsm_samples(struct ast_frame *frame)
-{
-	return 160 * (frame->datalen / 33);
-}
-
-static int gsm_length(unsigned int samples)
-{
-	return (samples / 160) * 33;
-}
-
-static struct ast_codec gsm = {
-	.name = "gsm",
-	.description = "GSM",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 20,
-	.maximum_ms = 300,
-	.default_ms = 20,
-	.minimum_bytes = 33,
-	.samples_count = gsm_samples,
-	.get_length = gsm_length,
-	.smooth = 1,
-};
-
-static int g726_samples(struct ast_frame *frame)
-{
-	return frame->datalen * 2;
-}
-
-static int g726_length(unsigned int samples)
-{
-	return samples / 2;
-}
-
-static struct ast_codec g726rfc3551 = {
-	.name = "g726",
-	.description = "G.726 RFC3551",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 300,
-	.default_ms = 20,
-	.minimum_bytes = 40,
-	.samples_count = g726_samples,
-	.get_length = g726_length,
-	.smooth = 1,
-};
-
-static struct ast_codec g726aal2 = {
-	.name = "g726aal2",
-	.description = "G.726 AAL2",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 300,
-	.default_ms = 20,
-	.minimum_bytes = 40,
-	.samples_count = g726_samples,
-	.get_length = g726_length,
-	.smooth = 1,
-};
-
-static struct ast_codec adpcm = {
-	.name = "adpcm",
-	.description = "Dialogic ADPCM",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 300,
-	.default_ms = 20,
-	.minimum_bytes = 40,
-	.samples_count = g726_samples,
-	.get_length = g726_length,
-	.smooth = 1,
-};
-
-static int slin_samples(struct ast_frame *frame)
-{
-	return frame->datalen / 2;
-}
-
-static int slin_length(unsigned int samples)
-{
-	return samples * 2;
-}
-
-static struct ast_codec slin8 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 160,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin12 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (12kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 12000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 240,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin16 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (16kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 16000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 320,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin24 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (24kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 24000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 480,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin32 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (32kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 32000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 640,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin44 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (44kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 44100,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 882,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin48 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (48kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 48000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 960,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin96 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (96kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 96000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 1920,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static struct ast_codec slin192 = {
-	.name = "slin",
-	.description = "16 bit Signed Linear PCM (192kHz)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 192000,
-	.minimum_ms = 10,
-	.maximum_ms = 70,
-	.default_ms = 20,
-	.minimum_bytes = 3840,
-	.samples_count = slin_samples,
-	.get_length = slin_length,
-	.smooth = 1,
-};
-
-static int lpc10_samples(struct ast_frame *frame)
-{
-	int samples = 22 * 8;
-
-	/* assumes that the RTP packet contains one LPC10 frame */
-	samples += (((char *)(frame->data.ptr))[7] & 0x1) * 8;
-
-	return samples;
-}
-
-static struct ast_codec lpc10 = {
-	.name = "lpc10",
-	.description = "LPC10",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 20,
-	.maximum_ms = 20,
-	.default_ms = 20,
-	.minimum_bytes = 7,
-	.samples_count = lpc10_samples,
-	.smooth = 1,
-};
-
-static int g729_samples(struct ast_frame *frame)
-{
-	return frame->datalen * 8;
-}
-
-static int g729_length(unsigned int samples)
-{
-	return samples / 8;
-}
-
-static struct ast_codec g729a = {
-	.name = "g729",
-	.description = "G.729A",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 230,
-	.default_ms = 20,
-	.minimum_bytes = 10,
-	.samples_count = g729_samples,
-	.get_length = g729_length,
-	.smooth = 1,
-};
-
-static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
-{
-	int byte = bit / 8;       /* byte containing first bit */
-	int rem = 8 - (bit % 8);  /* remaining bits in first byte */
-	unsigned char ret = 0;
-
-	if (n <= 0 || n > 8)
-		return 0;
-
-	if (rem < n) {
-		ret = (data[byte] << (n - rem));
-		ret |= (data[byte + 1] >> (8 - n + rem));
-	} else {
-		ret = (data[byte] >> (rem - n));
-	}
-
-	return (ret & (0xff >> (8 - n)));
-}
-
-static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
-{
-	static const int SpeexWBSubModeSz[] = {
-		4, 36, 112, 192,
-		352, 0, 0, 0 };
-	int off = bit;
-	unsigned char c;
-
-	/* skip up to two wideband frames */
-	if (((len * 8 - off) >= 5) &&
-		get_n_bits_at(data, 1, off)) {
-		c = get_n_bits_at(data, 3, off + 1);
-		off += SpeexWBSubModeSz[c];
-
-		if (((len * 8 - off) >= 5) &&
-			get_n_bits_at(data, 1, off)) {
-			c = get_n_bits_at(data, 3, off + 1);
-			off += SpeexWBSubModeSz[c];
-
-			if (((len * 8 - off) >= 5) &&
-				get_n_bits_at(data, 1, off)) {
-				ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
-				return -1;
-			}
-		}
-
-	}
-	return off - bit;
-}
-
-static int speex_samples(unsigned char *data, int len)
-{
-	static const int SpeexSubModeSz[] = {
-		5, 43, 119, 160,
-		220, 300, 364, 492,
-		79, 0, 0, 0,
-		0, 0, 0, 0 };
-	static const int SpeexInBandSz[] = {
-		1, 1, 4, 4,
-		4, 4, 4, 4,
-		8, 8, 16, 16,
-		32, 32, 64, 64 };
-	int bit = 0;
-	int cnt = 0;
-	int off;
-	unsigned char c;
-
-	while ((len * 8 - bit) >= 5) {
-		/* skip wideband frames */
-		off = speex_get_wb_sz_at(data, len, bit);
-		if (off < 0)  {
-			ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
-			break;
-		}
-		bit += off;
-
-		if ((len * 8 - bit) < 5)
-			break;
-
-		/* get control bits */
-		c = get_n_bits_at(data, 5, bit);
-		bit += 5;
-
-		if (c == 15) {
-			/* terminator */
-			break;
-		} else if (c == 14) {
-			/* in-band signal; next 4 bits contain signal id */
-			c = get_n_bits_at(data, 4, bit);
-			bit += 4;
-			bit += SpeexInBandSz[c];
-		} else if (c == 13) {
-			/* user in-band; next 4 bits contain msg len */
-			c = get_n_bits_at(data, 4, bit);
-			bit += 4;
-			/* after which it's 5-bit signal id + c bytes of data */
-			bit += 5 + c * 8;
-		} else if (c > 8) {
-			/* unknown */
-			ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
-			break;
-		} else {
-			/* skip number bits for submode (less the 5 control bits) */
-			bit += SpeexSubModeSz[c] - 5;
-			cnt += 160; /* new frame */
-		}
-	}
-	return cnt;
-}
-
-static int speex8_samples(struct ast_frame *frame)
-{
-	return speex_samples(frame->data.ptr, frame->datalen);
-}
-
-static struct ast_codec speex8 = {
-	.name = "speex",
-	.description = "SpeeX",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 60,
-	.default_ms = 20,
-	.minimum_bytes = 10,
-	.samples_count = speex8_samples,
-};
-
-static int speex16_samples(struct ast_frame *frame)
-{
-	return 2 * speex_samples(frame->data.ptr, frame->datalen);
-}
-
-static struct ast_codec speex16 = {
-	.name = "speex",
-	.description = "SpeeX 16khz",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 16000,
-	.minimum_ms = 10,
-	.maximum_ms = 60,
-	.default_ms = 20,
-	.minimum_bytes = 10,
-	.samples_count = speex16_samples,
-};
-
-static int speex32_samples(struct ast_frame *frame)
-{
-	return 4 * speex_samples(frame->data.ptr, frame->datalen);
-}
-
-static struct ast_codec speex32 = {
-	.name = "speex",
-	.description = "SpeeX 32khz",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 32000,
-	.minimum_ms = 10,
-	.maximum_ms = 60,
-	.default_ms = 20,
-	.minimum_bytes = 10,
-	.samples_count = speex32_samples,
-};
-
-static int ilbc_samples(struct ast_frame *frame)
-{
-	return 240 * (frame->datalen / 50);
-}
-
-static struct ast_codec ilbc = {
-	.name = "ilbc",
-	.description = "iLBC",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 30,
-	.maximum_ms = 30,
-	.default_ms = 30,
-	.minimum_bytes = 50,
-	.samples_count = ilbc_samples,
-	.smooth = 1,
-};
-
-static struct ast_codec g722 = {
-	.name = "g722",
-	.description = "G722",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 16000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.minimum_bytes = 80,
-	.samples_count = g726_samples,
-	.get_length = g726_length,
-	.smooth = 1,
-};
-
-static int siren7_samples(struct ast_frame *frame)
-{
-	return frame->datalen * (16000 / 4000);
-}
-
-static int siren7_length(unsigned int samples)
-{
-	return samples / (16000 / 4000);
-}
-
-static struct ast_codec siren7 = {
-	.name = "siren7",
-	.description = "ITU G.722.1 (Siren7, licensed from Polycom)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 16000,
-	.minimum_ms = 20,
-	.maximum_ms = 80,
-	.default_ms = 20,
-	.minimum_bytes = 80,
-	.samples_count = siren7_samples,
-	.get_length = siren7_length,
-};
-
-static int siren14_samples(struct ast_frame *frame)
-{
-	return (int) frame->datalen * ((float) 32000 / 6000);
-}
-
-static int siren14_length(unsigned int samples)
-{
-	return (int) samples / ((float) 32000 / 6000);;
-}
-
-static struct ast_codec siren14 = {
-	.name = "siren14",
-	.description = "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 32000,
-	.minimum_ms = 20,
-	.maximum_ms = 80,
-	.default_ms = 20,
-	.minimum_bytes = 120,
-	.samples_count = siren14_samples,
-	.get_length = siren14_length,
-};
-
-static struct ast_codec testlaw = {
-	.name = "testlaw",
-	.description = "G.711 test-law",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.minimum_bytes = 80,
-	.samples_count = ulaw_samples,
-	.get_length = ulaw_length,
-	.smooth = 1,
-};
-
-static int g719_samples(struct ast_frame *frame)
-{
-	return (int) frame->datalen * ((float) 48000 / 8000);
-}
-
-static int g719_length(unsigned int samples)
-{
-	return (int) samples / ((float) 48000 / 8000);
-}
-
-static struct ast_codec g719 = {
-	.name = "g719",
-	.description = "ITU G.719",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 48000,
-	.minimum_ms = 20,
-	.maximum_ms = 80,
-	.default_ms = 20,
-	.minimum_bytes = 160,
-	.samples_count = g719_samples,
-	.get_length = g719_length,
-};
-
-static struct ast_codec opus = {
-	.name = "opus",
-	.description = "Opus Codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 48000,
-	.minimum_ms = 20,
-	.maximum_ms = 60,
-	.default_ms = 20,
-	.minimum_bytes = 10,
-};
-
-static struct ast_codec jpeg = {
-	.name = "jpeg",
-	.description = "JPEG image",
-	.type = AST_MEDIA_TYPE_IMAGE,
-};
-
-static struct ast_codec png = {
-	.name = "png",
-	.description = "PNG Image",
-	.type = AST_MEDIA_TYPE_IMAGE,
-};
-
-static struct ast_codec h261 = {
-	.name = "h261",
-	.description = "H.261 video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec h263 = {
-	.name = "h263",
-	.description = "H.263 video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec h263p = {
-	.name = "h263p",
-	.description = "H.263+ video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec h264 = {
-	.name = "h264",
-	.description = "H.264 video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec mpeg4 = {
-	.name = "mpeg4",
-	.description = "MPEG4 video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec vp8 = {
-	.name = "vp8",
-	.description = "VP8 video",
-	.type = AST_MEDIA_TYPE_VIDEO,
-};
-
-static struct ast_codec t140red = {
-	.name = "red",
-	.description = "T.140 Realtime Text with redundancy",
-	.type = AST_MEDIA_TYPE_TEXT,
-};
-
-static struct ast_codec t140 = {
-	.name = "t140",
-	.description = "Passthrough T.140 Realtime Text",
-	.type = AST_MEDIA_TYPE_TEXT,
-};
-
-#define CODEC_REGISTER_AND_CACHE(codec) \
-	({ \
-		int __res_ ## __LINE__ = 0; \
-		struct ast_format *__fmt_ ## __LINE__; \
-		struct ast_codec *__codec_ ## __LINE__; \
-		res |= __ast_codec_register(&(codec), NULL); \
-		__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
-		__fmt_ ## __LINE__ = ast_format_create(__codec_ ## __LINE__); \
-		res |= ast_format_cache_set(__fmt_ ## __LINE__); \
-		ao2_ref(__fmt_ ## __LINE__, -1); \
-		ao2_ref(__codec_ ## __LINE__, -1); \
-		__res_ ## __LINE__; \
-	})
-
-#define CODEC_REGISTER_AND_CACHE_NAMED(format_name, codec) \
-	({ \
-		int __res_ ## __LINE__ = 0; \
-		struct ast_format *__fmt_ ## __LINE__; \
-		struct ast_codec *__codec_ ## __LINE__; \
-		res |= __ast_codec_register(&(codec), NULL); \
-		__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
-		__fmt_ ## __LINE__ = ast_format_create_named((format_name), __codec_ ## __LINE__); \
-		res |= ast_format_cache_set(__fmt_ ## __LINE__); \
-		ao2_ref(__fmt_ ## __LINE__, -1); \
-		ao2_ref(__codec_ ## __LINE__, -1); \
-		__res_ ## __LINE__; \
-	})
-
-int ast_codec_builtin_init(void)
-{
-	int res = 0;
-
-	res |= CODEC_REGISTER_AND_CACHE(g723);
-	res |= CODEC_REGISTER_AND_CACHE(ulaw);
-	res |= CODEC_REGISTER_AND_CACHE(alaw);
-	res |= CODEC_REGISTER_AND_CACHE(gsm);
-	res |= CODEC_REGISTER_AND_CACHE(g726rfc3551);
-	res |= CODEC_REGISTER_AND_CACHE(g726aal2);
-	res |= CODEC_REGISTER_AND_CACHE(adpcm);
-	res |= CODEC_REGISTER_AND_CACHE(slin8);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin12", slin12);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin16", slin16);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin24", slin24);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin32", slin32);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin44", slin44);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin48", slin48);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin96", slin96);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("slin192", slin192);
-	res |= CODEC_REGISTER_AND_CACHE(lpc10);
-	res |= CODEC_REGISTER_AND_CACHE(g729a);
-	res |= CODEC_REGISTER_AND_CACHE(speex8);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("speex16", speex16);
-	res |= CODEC_REGISTER_AND_CACHE_NAMED("speex32", speex32);
-	res |= CODEC_REGISTER_AND_CACHE(ilbc);
-	res |= CODEC_REGISTER_AND_CACHE(g722);
-	res |= CODEC_REGISTER_AND_CACHE(siren7);
-	res |= CODEC_REGISTER_AND_CACHE(siren14);
-	res |= CODEC_REGISTER_AND_CACHE(testlaw);
-	res |= CODEC_REGISTER_AND_CACHE(g719);
-	res |= CODEC_REGISTER_AND_CACHE(opus);
-	res |= CODEC_REGISTER_AND_CACHE(jpeg);
-	res |= CODEC_REGISTER_AND_CACHE(png);
-	res |= CODEC_REGISTER_AND_CACHE(h261);
-	res |= CODEC_REGISTER_AND_CACHE(h263);
-	res |= CODEC_REGISTER_AND_CACHE(h263p);
-	res |= CODEC_REGISTER_AND_CACHE(h264);
-	res |= CODEC_REGISTER_AND_CACHE(mpeg4);
-	res |= CODEC_REGISTER_AND_CACHE(vp8);
-	res |= CODEC_REGISTER_AND_CACHE(t140red);
-	res |= CODEC_REGISTER_AND_CACHE(t140);
-	res |= CODEC_REGISTER_AND_CACHE(none);
-
-	return res;
-}
diff --git a/main/config.c b/main/config.c
index 73f0aa5..c49f82c 100644
--- a/main/config.c
+++ b/main/config.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428734 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_CONFIG_DIR */
 #include "asterisk/network.h"	/* we do some sockaddr manipulation here */
@@ -40,7 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428734 $")
 #include <sys/stat.h>
 
 #include <math.h>	/* HUGE_VAL */
-#include <regex.h>
 
 #define AST_INCLUDE_GLOB 1
 
@@ -71,8 +70,6 @@ static char *extconfig_conf = "extconfig.conf";
 
 static struct ao2_container *cfg_hooks;
 static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg);
-inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2);
-static int does_category_match(struct ast_category *cat, const char *category_name, const char *match);
 
 /*! \brief Structure to keep comments for rewriting configuration files */
 struct ast_comment {
@@ -234,8 +231,6 @@ struct ast_category {
 	struct ast_variable *root;
 	/*! Last category variable in the list. */
 	struct ast_variable *last;
-	/*! Previous node in the list. */
-	struct ast_category *prev;
 	/*! Next node in the list. */
 	struct ast_category *next;
 };
@@ -603,70 +598,21 @@ void ast_variables_destroy(struct ast_variable *v)
 
 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
 {
-	struct ast_category *cat;
+	struct ast_category *cat = NULL;
+
+	if (!category) {
+		return NULL;
+	}
 
 	if (config->last_browse && (config->last_browse->name == category)) {
 		cat = config->last_browse;
 	} else {
-		cat = ast_category_get(config, category, NULL);
+		cat = ast_category_get(config, category);
 	}
 
 	return (cat) ? cat->root : NULL;
 }
 
-inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2)
-{
-    l1->next = l2->next;
-    l2->next = l1;
-    return l2;
-}
-
-struct ast_variable *ast_variable_list_sort(struct ast_variable *start)
-{
-	struct ast_variable *p, *q;
-	struct ast_variable top;
-	int changed = 1;
-	memset(&top, 0, sizeof(top));
-	top.next = start;
-	if (start != NULL && start->next != NULL) {
-		while (changed) {
-			changed = 0;
-			q = ⊤
-			p = top.next;
-			while (p->next != NULL) {
-				if (p->next != NULL && strcmp(p->name, p->next->name) > 0) {
-					q->next = variable_list_switch(p, p->next);
-					changed = 1;
-				}
-				q = p;
-				if (p->next != NULL)
-					p = p->next;
-			}
-		}
-	}
-	return top.next;
-}
-
-struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *newvar)
-{
-	struct ast_variable *curr;
-	ast_assert(head != NULL);
-
-	if (!*head) {
-		*head = newvar;
-	} else {
-		if (search_hint == NULL) {
-			search_hint = *head;
-		}
-		for (curr = search_hint; curr->next; curr = curr->next);
-		curr->next = newvar;
-	}
-
-	for (curr = newvar; curr->next; curr = curr->next);
-
-	return curr;
-}
-
 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
 {
 	const char *tmp;
@@ -677,7 +623,8 @@ const char *ast_config_option(struct ast_config *cfg, const char *cat, const cha
 	return tmp;
 }
 
-const char *ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
+
+const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
 {
 	struct ast_variable *v;
 
@@ -702,39 +649,6 @@ const char *ast_variable_retrieve(struct ast_config *config, const char *categor
 	return NULL;
 }
 
-const char *ast_variable_retrieve_filtered(struct ast_config *config,
-	const char *category, const char *variable, const char *filter)
-{
-	struct ast_category *cat = NULL;
-	const char *value;
-
-	while ((cat = ast_category_browse_filtered(config, category, cat, filter))) {
-		value = ast_variable_find(cat, variable);
-		if (value) {
-			return value;
-		}
-	}
-
-	return NULL;
-}
-
-const char *ast_variable_find(const struct ast_category *category, const char *variable)
-{
-	return ast_variable_find_in_list(category->root, variable);
-}
-
-const char *ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
-{
-	const struct ast_variable *v;
-
-	for (v = list; v; v = v->next) {
-		if (!strcasecmp(variable, v->name)) {
-			return v->value;
-		}
-	}
-	return NULL;
-}
-
 static struct ast_variable *variable_clone(const struct ast_variable *old)
 {
 	struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
@@ -758,99 +672,7 @@ static void move_variables(struct ast_category *old, struct ast_category *new)
 	ast_variable_append(new, var);
 }
 
-/*! \brief Returns true if ALL of the regex expressions and category name match.
- * Both can be NULL (I.E. no predicate) which results in a true return;
- */
-static int does_category_match(struct ast_category *cat, const char *category_name, const char *match)
-{
-	char *dupmatch;
-	char *nvp = NULL;
-	int match_found = 0, match_expressions = 0;
-	int template_ok = 0;
-
-	/* Only match on category name if it's not a NULL or empty string */
-	if (!ast_strlen_zero(category_name) && strcasecmp(cat->name, category_name)) {
-		return 0;
-	}
-
-	/* If match is NULL or empty, automatically match if not a template */
-	if (ast_strlen_zero(match)) {
-		return !cat->ignored;
-	}
-
-	dupmatch = ast_strdupa(match);
-
-	while ((nvp = ast_strsep(&dupmatch, ',', AST_STRSEP_STRIP))) {
-		struct ast_variable *v;
-		char *match_name;
-		char *match_value = NULL;
-		char *regerr;
-		int rc;
-		regex_t r_name, r_value;
-
-		match_expressions++;
-
-		match_name = ast_strsep(&nvp, '=', AST_STRSEP_STRIP);
-		match_value = ast_strsep(&nvp, '=', AST_STRSEP_STRIP);
-
-		/* an empty match value is OK.  A NULL match value (no =) is NOT. */
-		if (match_value == NULL) {
-			break;
-		}
-
-		if (!strcmp("TEMPLATES", match_name)) {
-			if (!strcasecmp("include", match_value)) {
-				if (cat->ignored) {
-					template_ok = 1;
-				}
-				match_found++;
-			} else if (!strcasecmp("restrict", match_value)) {
-				if (cat->ignored) {
-					match_found++;
-					template_ok = 1;
-				} else {
-					break;
-				}
-			}
-			continue;
-		}
-
-		if ((rc = regcomp(&r_name, match_name, REG_EXTENDED | REG_NOSUB))) {
-			regerr = ast_alloca(128);
-			regerror(rc, &r_name, regerr, 128);
-			ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n",
-				match_name, regerr);
-			regfree(&r_name);
-			return 0;
-		}
-		if ((rc = regcomp(&r_value, match_value, REG_EXTENDED | REG_NOSUB))) {
-			regerr = ast_alloca(128);
-			regerror(rc, &r_value, regerr, 128);
-			ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n",
-				match_value, regerr);
-			regfree(&r_name);
-			regfree(&r_value);
-			return 0;
-		}
-
-		for (v = cat->root; v; v = v->next) {
-			if (!regexec(&r_name, v->name, 0, NULL, 0)
-				&& !regexec(&r_value, v->value, 0, NULL, 0)) {
-				match_found++;
-				break;
-			}
-		}
-		regfree(&r_name);
-		regfree(&r_value);
-	}
-	if (match_found == match_expressions && (!cat->ignored || template_ok)) {
-		return 1;
-	}
-	return 0;
-}
-
-
-static struct ast_category *new_category(const char *name, const char *in_file, int lineno, int template)
+struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
 {
 	struct ast_category *category;
 
@@ -865,91 +687,44 @@ static struct ast_category *new_category(const char *name, const char *in_file,
 	}
 	ast_copy_string(category->name, name, sizeof(category->name));
 	category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
-	category->ignored = template;
 	return category;
 }
 
-struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
-{
-	return new_category(name, in_file, lineno, 0);
-}
-
-struct ast_category *ast_category_new_template(const char *name, const char *in_file, int lineno)
-{
-	return new_category(name, in_file, lineno, 1);
-}
-
-struct ast_category *ast_category_get(const struct ast_config *config,
-	const char *category_name, const char *filter)
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
 {
 	struct ast_category *cat;
 
+	/* try exact match first, then case-insensitive match */
 	for (cat = config->root; cat; cat = cat->next) {
-		if (cat->name == category_name && does_category_match(cat, category_name, filter)) {
+		if (cat->name == category_name && (ignored || !cat->ignored))
 			return cat;
-		}
 	}
 
 	for (cat = config->root; cat; cat = cat->next) {
-		if (does_category_match(cat, category_name, filter)) {
+		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
 			return cat;
-		}
 	}
 
 	return NULL;
 }
 
-const char *ast_category_get_name(const struct ast_category *category)
+struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
 {
-	return category->name;
-}
-
-int ast_category_is_template(const struct ast_category *category)
-{
-	return category->ignored;
-}
-
-struct ast_str *ast_category_get_templates(const struct ast_category *category)
-{
-	struct ast_category_template_instance *template;
-	struct ast_str *str;
-	int first = 1;
-
-	if (AST_LIST_EMPTY(&category->template_instances)) {
-		return NULL;
-	}
-
-	str = ast_str_create(128);
-	if (!str) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&category->template_instances, template, next) {
-		ast_str_append(&str, 0, "%s%s", first ? "" : ",", template->name);
-		first = 0;
-	}
-
-	return str;
+	return category_get(config, category_name, 0);
 }
 
-int ast_category_exist(const struct ast_config *config, const char *category_name,
-	const char *filter)
+int ast_category_exist(const struct ast_config *config, const char *category_name)
 {
-	return !!ast_category_get(config, category_name, filter);
+	return !!ast_category_get(config, category_name);
 }
 
 void ast_category_append(struct ast_config *config, struct ast_category *category)
 {
-	if (config->last) {
+	if (config->last)
 		config->last->next = category;
-		category->prev = config->last;
-	} else {
+	else
 		config->root = category;
-		category->prev = NULL;
-	}
-	category->next = NULL;
 	category->include_level = config->include_level;
-
 	config->last = category;
 	config->current = category;
 }
@@ -958,26 +733,19 @@ int ast_category_insert(struct ast_config *config, struct ast_category *cat, con
 {
 	struct ast_category *cur_category;
 
-	if (!config || !config->root || !cat || !match) {
+	if (!config || !cat || !match) {
 		return -1;
 	}
-
 	if (!strcasecmp(config->root->name, match)) {
 		cat->next = config->root;
-		cat->prev = NULL;
-		config->root->prev = cat;
 		config->root = cat;
 		return 0;
 	}
-
-	for (cur_category = config->root->next; cur_category; cur_category = cur_category->next) {
-		if (!strcasecmp(cur_category->name, match)) {
-			cat->prev = cur_category->prev;
-			cat->prev->next = cat;
-
-			cat->next = cur_category;
-			cur_category->prev = cat;
-
+	for (cur_category = config->root; cur_category && cur_category->next;
+		cur_category = cur_category->next) {
+		if (!strcasecmp(cur_category->next->name, match)) {
+			cat->next = cur_category->next;
+			cur_category->next = cat;
 			return 0;
 		}
 	}
@@ -1019,10 +787,9 @@ static void ast_includes_destroy(struct ast_config_include *incls)
 	}
 }
 
-static struct ast_category *next_available_category(struct ast_category *cat,
-	const char *name, const char *filter)
+static struct ast_category *next_available_category(struct ast_category *cat)
 {
-	for (; cat && !does_category_match(cat, name, filter); cat = cat->next);
+	for (; cat && cat->ignored; cat = cat->next);
 
 	return cat;
 }
@@ -1035,7 +802,7 @@ struct ast_variable *ast_category_first(struct ast_category *cat)
 
 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
 {
-	struct ast_category *category = ast_category_get(config, cat, NULL);
+	struct ast_category *category = ast_category_get(config, cat);
 
 	if (category)
 		return category->root;
@@ -1200,28 +967,12 @@ char *ast_category_browse(struct ast_config *config, const char *prev)
 	}
 
 	if (cat)
-		cat = next_available_category(cat, NULL, NULL);
+		cat = next_available_category(cat);
 
 	config->last_browse = cat;
 	return (cat) ? cat->name : NULL;
 }
 
-struct ast_category *ast_category_browse_filtered(struct ast_config *config,
-	const char *category_name, struct ast_category *prev, const char *filter)
-{
-	struct ast_category *cat;
-
-	if (!prev) {
-		prev = config->root;
-	} else {
-		prev = prev->next;
-	}
-
-	cat = next_available_category(prev, category_name, filter);
-
-	return cat;
-}
-
 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
 {
 	struct ast_variable *v;
@@ -1238,7 +989,7 @@ void ast_category_rename(struct ast_category *cat, const char *name)
 	ast_copy_string(cat->name, name, sizeof(cat->name));
 }
 
-void ast_category_inherit(struct ast_category *new, const struct ast_category *base)
+static void inherit_category(struct ast_category *new, const struct ast_category *base)
 {
 	struct ast_variable *var;
 	struct ast_category_template_instance *x;
@@ -1342,49 +1093,65 @@ int ast_variable_update(struct ast_category *category, const char *variable,
 	return -1;
 }
 
-struct ast_category *ast_category_delete(struct ast_config *config,
-	struct ast_category *category)
+int ast_category_delete(struct ast_config *cfg, const char *category)
 {
-	struct ast_category *prev;
+	struct ast_category *prev=NULL, *cat;
 
-	if (!config || !category) {
-		return NULL;
-	}
-
-	if (category->prev) {
-		category->prev->next = category->next;
-	} else {
-		config->root = category->next;
-	}
-
-	if (category->next) {
-		category->next->prev = category->prev;
-	} else {
-		config->last = category->prev;
+	cat = cfg->root;
+	while (cat) {
+		if (cat->name == category) {
+			if (prev) {
+				prev->next = cat->next;
+				if (cat == cfg->last)
+					cfg->last = prev;
+			} else {
+				cfg->root = cat->next;
+				if (cat == cfg->last)
+					cfg->last = NULL;
+			}
+			ast_category_destroy(cat);
+			return 0;
+		}
+		prev = cat;
+		cat = cat->next;
 	}
 
-	prev = category->prev;
-
-	if (config->last_browse == category) {
-		config->last_browse = prev;
+	prev = NULL;
+	cat = cfg->root;
+	while (cat) {
+		if (!strcasecmp(cat->name, category)) {
+			if (prev) {
+				prev->next = cat->next;
+				if (cat == cfg->last)
+					cfg->last = prev;
+			} else {
+				cfg->root = cat->next;
+				if (cat == cfg->last)
+					cfg->last = NULL;
+			}
+			ast_category_destroy(cat);
+			return 0;
+		}
+		prev = cat;
+		cat = cat->next;
 	}
-
-	ast_category_destroy(category);
-
-	return prev;
+	return -1;
 }
 
-int ast_category_empty(struct ast_category *category)
+int ast_category_empty(struct ast_config *cfg, const char *category)
 {
-	if (!category) {
-		return -1;
-	}
+	struct ast_category *cat;
 
-	ast_variables_destroy(category->root);
-	category->root = NULL;
-	category->last = NULL;
+	for (cat = cfg->root; cat; cat = cat->next) {
+		if (strcasecmp(cat->name, category))
+			continue;
+		ast_variables_destroy(cat->root);
+		cat->root = NULL;
+		cat->last = NULL;
+		return 0;
+	}
 
-	return 0;
+	return -1;
 }
 
 void ast_config_destroy(struct ast_config *cfg)
@@ -1668,7 +1435,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
 				if (!strcasecmp(cur, "!")) {
 					(*cat)->ignored = 1;
 				} else if (!strcasecmp(cur, "+")) {
-					*cat = ast_category_get(cfg, catname, NULL);
+					*cat = category_get(cfg, catname, 1);
 					if (!(*cat)) {
 						if (newcat)
 							ast_category_destroy(newcat);
@@ -1683,12 +1450,12 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
 				} else {
 					struct ast_category *base;
 
-					base = ast_category_get(cfg, cur, "TEMPLATES=include");
+					base = category_get(cfg, cur, 1);
 					if (!base) {
 						ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
 						return -1;
 					}
-					ast_category_inherit(*cat, base);
+					inherit_category(*cat, base);
 				}
 			}
 		}
@@ -1894,14 +1661,9 @@ static struct ast_config *config_text_file_load(const char *database, const char
 	/*! Growable string buffer */
 	struct ast_str *comment_buffer = NULL;	/*!< this will be a comment collector.*/
 	struct ast_str *lline_buffer = NULL;	/*!< A buffer for stuff behind the ; */
-#ifdef AST_INCLUDE_GLOB
-	int glob_ret;
-	glob_t globbuf;
-#endif
 
-	if (cfg) {
+	if (cfg)
 		cat = ast_config_get_current_category(cfg);
-	}
 
 	if (filename[0] == '/') {
 		ast_copy_string(fn, filename, sizeof(fn));
@@ -1911,9 +1673,8 @@ static struct ast_config *config_text_file_load(const char *database, const char
 
 	if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
 		comment_buffer = ast_str_create(CB_SIZE);
-		if (comment_buffer) {
+		if (comment_buffer)
 			lline_buffer = ast_str_create(CB_SIZE);
-		}
 		if (!lline_buffer) {
 			ast_free(comment_buffer);
 			ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
@@ -1921,284 +1682,273 @@ static struct ast_config *config_text_file_load(const char *database, const char
 		}
 	}
 #ifdef AST_INCLUDE_GLOB
-	globbuf.gl_offs = 0;	/* initialize it to silence gcc */
-	glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
-	if (glob_ret == GLOB_NOSPACE) {
-		ast_log(LOG_WARNING,
-			"Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
-	} else if (glob_ret  == GLOB_ABORTED) {
-		ast_log(LOG_WARNING,
-			"Glob Expansion of pattern '%s' failed: Read error\n", fn);
-	} else {
-		/* loop over expanded files */
-		int i;
+	{
+		int glob_ret;
+		glob_t globbuf;
 
-		if (!cfg && (globbuf.gl_pathc != 1 || strcmp(fn, globbuf.gl_pathv[0]))) {
-			/*
-			 * We just want a file changed answer and since we cannot
-			 * tell if a file was deleted with wildcard matching we will
-			 * assume that something has always changed.  Also without
-			 * a lot of refactoring we couldn't check more than one file
-			 * for changes in the glob loop anyway.
-			 */
-			globfree(&globbuf);
-			ast_free(comment_buffer);
-			ast_free(lline_buffer);
-			return NULL;
-		}
-		for (i=0; i<globbuf.gl_pathc; i++) {
-			ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
+		globbuf.gl_offs = 0;	/* initialize it to silence gcc */
+		glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
+		if (glob_ret == GLOB_NOSPACE) {
+			ast_log(LOG_WARNING,
+				"Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
+		} else if (glob_ret  == GLOB_ABORTED) {
+			ast_log(LOG_WARNING,
+				"Glob Expansion of pattern '%s' failed: Read error\n", fn);
+		} else {
+			/* loop over expanded files */
+			int i;
+
+			if (!cfg && (globbuf.gl_pathc != 1 || strcmp(fn, globbuf.gl_pathv[0]))) {
+				/*
+				 * We just want a file changed answer and since we cannot
+				 * tell if a file was deleted with wildcard matching we will
+				 * assume that something has always changed.  Also without
+				 * a lot of refactoring we couldn't check more than one file
+				 * for changes in the glob loop anyway.
+				 */
+				globfree(&globbuf);
+				ast_free(comment_buffer);
+				ast_free(lline_buffer);
+				return NULL;
+			}
+			for (i=0; i<globbuf.gl_pathc; i++) {
+				ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
 #endif
-			/*
-			 * The following is not a loop, but just a convenient way to define a block
-			 * (using do { } while(0) ), and be able to exit from it with 'continue'
-			 * or 'break' in case of errors. Nice trick.
-			 */
-			do {
-				if (stat(fn, &statbuf)) {
-					if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
-						config_cache_remove(fn, who_asked);
-					}
-					continue;
-				}
+	/*
+	 * The following is not a loop, but just a convenient way to define a block
+	 * (using do { } while(0) ), and be able to exit from it with 'continue'
+	 * or 'break' in case of errors. Nice trick.
+	 */
+	do {
+		if (stat(fn, &statbuf)) {
+			if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
+				config_cache_remove(fn, who_asked);
+			}
+			continue;
+		}
 
-				if (!S_ISREG(statbuf.st_mode)) {
-					ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
-					if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
-						config_cache_remove(fn, who_asked);
-					}
+		if (!S_ISREG(statbuf.st_mode)) {
+			ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
+			if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
+				config_cache_remove(fn, who_asked);
+			}
+			continue;
+		}
+
+		if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
+			/* Find our cached entry for this configuration file */
+			AST_LIST_LOCK(&cfmtime_head);
+			AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
+				if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
+					break;
+			}
+			if (!cfmtime) {
+				cfmtime = cfmtime_new(fn, who_asked);
+				if (!cfmtime) {
+					AST_LIST_UNLOCK(&cfmtime_head);
 					continue;
 				}
+				/* Note that the file mtime is initialized to 0, i.e. 1970 */
+				AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
+			}
+		}
 
-				if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
-					/* Find our cached entry for this configuration file */
-					AST_LIST_LOCK(&cfmtime_head);
-					AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
-						if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked)) {
-							break;
-						}
-					}
-					if (!cfmtime) {
-						cfmtime = cfmtime_new(fn, who_asked);
-						if (!cfmtime) {
-							AST_LIST_UNLOCK(&cfmtime_head);
-							continue;
-						}
-						/* Note that the file mtime is initialized to 0, i.e. 1970 */
-						AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
-					}
-				}
+		if (cfmtime
+			&& !cfmtime->has_exec
+			&& !cfmstat_cmp(cfmtime, &statbuf)
+			&& ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
+			int unchanged = 1;
 
-				if (cfmtime
-					&& !cfmtime->has_exec
-					&& !cfmstat_cmp(cfmtime, &statbuf)
-					&& ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
-					int unchanged = 1;
-
-					/* File is unchanged, what about the (cached) includes (if any)? */
-					AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
-						if (!config_text_file_load(NULL, NULL, cfinclude->include,
-							NULL, flags, "", who_asked)) {
-							/* One change is enough to short-circuit and reload the whole shebang */
-							unchanged = 0;
-							break;
-						}
-					}
+			/* File is unchanged, what about the (cached) includes (if any)? */
+			AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
+				if (!config_text_file_load(NULL, NULL, cfinclude->include,
+					NULL, flags, "", who_asked)) {
+					/* One change is enough to short-circuit and reload the whole shebang */
+					unchanged = 0;
+					break;
+				}
+			}
 
-					if (unchanged) {
-						AST_LIST_UNLOCK(&cfmtime_head);
+			if (unchanged) {
+				AST_LIST_UNLOCK(&cfmtime_head);
 #ifdef AST_INCLUDE_GLOB
-						globfree(&globbuf);
+				globfree(&globbuf);
 #endif
-						ast_free(comment_buffer);
-						ast_free(lline_buffer);
-						return CONFIG_STATUS_FILEUNCHANGED;
-					}
-				}
+				ast_free(comment_buffer);
+				ast_free(lline_buffer);
+				return CONFIG_STATUS_FILEUNCHANGED;
+			}
+		}
 
-				/* If cfg is NULL, then we just want a file changed answer. */
-				if (cfg == NULL) {
-					if (cfmtime) {
-						AST_LIST_UNLOCK(&cfmtime_head);
+		/* If cfg is NULL, then we just want a file changed answer. */
+		if (cfg == NULL) {
+			if (cfmtime) {
+				AST_LIST_UNLOCK(&cfmtime_head);
+			}
+			continue;
+		}
+
+		if (cfmtime) {
+			/* Forget about what we thought we knew about this file's includes. */
+			cfmtime->has_exec = 0;
+			config_cache_flush_includes(cfmtime);
+
+			cfmstat_save(cfmtime, &statbuf);
+			AST_LIST_UNLOCK(&cfmtime_head);
+		}
+
+		if (!(f = fopen(fn, "r"))) {
+			ast_debug(1, "No file to parse: %s\n", fn);
+			ast_verb(2, "Parsing '%s': Not found (%s)\n", fn, strerror(errno));
+			continue;
+		}
+		count++;
+		/* If we get to this point, then we're loading regardless */
+		ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
+		ast_debug(1, "Parsing %s\n", fn);
+		ast_verb(2, "Parsing '%s': Found\n", fn);
+		while (!feof(f)) {
+			lineno++;
+			if (fgets(buf, sizeof(buf), f)) {
+				/* Skip lines that are too long */
+				if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
+					ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
+					while (fgets(buf, sizeof(buf), f)) {
+						if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
+							break;
+						}
 					}
 					continue;
 				}
 
-				if (cfmtime) {
-					/* Forget about what we thought we knew about this file's includes. */
-					cfmtime->has_exec = 0;
-					config_cache_flush_includes(cfmtime);
-
-					cfmstat_save(cfmtime, &statbuf);
-					AST_LIST_UNLOCK(&cfmtime_head);
+				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
 				}
 
-				if (!(f = fopen(fn, "r"))) {
-					ast_debug(1, "No file to parse: %s\n", fn);
-					ast_verb(2, "Parsing '%s': Not found (%s)\n", fn, strerror(errno));
-					continue;
-				}
-				count++;
-				/* If we get to this point, then we're loading regardless */
-				ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
-				ast_debug(1, "Parsing %s\n", fn);
-				ast_verb(2, "Parsing '%s': Found\n", fn);
-				while (!feof(f)) {
-					lineno++;
-					if (fgets(buf, sizeof(buf), f)) {
-						/* Skip lines that are too long */
-						if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
-							ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
-							while (fgets(buf, sizeof(buf), f)) {
-								if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
-									break;
-								}
-							}
-							continue;
-						}
+				new_buf = buf;
+				if (comment)
+					process_buf = NULL;
+				else
+					process_buf = buf;
 
-						if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)
-							&& lline_buffer
-							&& ast_str_strlen(lline_buffer)) {
-							CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-							ast_str_reset(lline_buffer);        /* erase the lline buffer */
-						}
+				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
+					/* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
+					CB_ADD(&comment_buffer, "\n");       /* add a newline to the comment buffer */
+					continue; /* go get a new line, then */
+				}
 
-						new_buf = buf;
-						if (comment) {
-							process_buf = NULL;
+				while ((comment_p = strchr(new_buf, COMMENT_META))) {
+					if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
+						/* Escaped semicolons aren't comments. */
+						new_buf = comment_p;
+						/* write over the \ and bring the null terminator with us */
+						memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
+					} else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
+						/* Meta-Comment start detected ";--" */
+						if (comment < MAX_NESTED_COMMENTS) {
+							*comment_p = '\0';
+							new_buf = comment_p + 3;
+							comment++;
+							nest[comment-1] = lineno;
 						} else {
-							process_buf = buf;
-						}
-
-						if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)
-							&& comment_buffer
-							&& ast_str_strlen(comment_buffer)
-							&& (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
-							/* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
-							CB_ADD(&comment_buffer, "\n"); /* add a newline to the comment buffer */
-							continue; /* go get a new line, then */
+							ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
 						}
-
-						while ((comment_p = strchr(new_buf, COMMENT_META))) {
-							if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
-								/* Escaped semicolons aren't comments. */
-								new_buf = comment_p;
-								/* write over the \ and bring the null terminator with us */
-								memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
-							} else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
-								/* Meta-Comment start detected ";--" */
-								if (comment < MAX_NESTED_COMMENTS) {
-									*comment_p = '\0';
-									new_buf = comment_p + 3;
-									comment++;
-									nest[comment-1] = lineno;
-								} else {
-									ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
+					} else if ((comment_p >= new_buf + 2) &&
+						   (*(comment_p - 1) == COMMENT_TAG) &&
+						   (*(comment_p - 2) == COMMENT_TAG)) {
+						/* Meta-Comment end detected "--;" */
+						comment--;
+						new_buf = comment_p + 1;
+						if (!comment) {
+							/* Back to non-comment now */
+							if (process_buf) {
+								/* Actually have to move what's left over the top, then continue */
+								char *oldptr;
+								oldptr = process_buf + strlen(process_buf);
+								if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
+									CB_ADD(&comment_buffer, ";");
+									CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
 								}
-							} else if ((comment_p >= new_buf + 2) &&
-								   (*(comment_p - 1) == COMMENT_TAG) &&
-								   (*(comment_p - 2) == COMMENT_TAG)) {
-								/* Meta-Comment end detected "--;" */
-								comment--;
-								new_buf = comment_p + 1;
-								if (!comment) {
-									/* Back to non-comment now */
-									if (process_buf) {
-										/* Actually have to move what's left over the top, then continue */
-										char *oldptr;
-
-										oldptr = process_buf + strlen(process_buf);
-										if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
-											CB_ADD(&comment_buffer, ";");
-											CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
-										}
-
-										memmove(oldptr, new_buf, strlen(new_buf) + 1);
-										new_buf = oldptr;
-									} else {
-										process_buf = new_buf;
-									}
-								}
-							} else {
-								if (!comment) {
-									/* If ; is found, and we are not nested in a comment,
-									   we immediately stop all comment processing */
-									if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
-										CB_ADD(&lline_buffer, comment_p);
-									}
-									*comment_p = '\0';
-									new_buf = comment_p;
-								} else {
-									new_buf = comment_p + 1;
-								}
-							}
-						}
-						if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
-							CB_ADD(&comment_buffer, buf); /* the whole line is a comment, store it */
-						}
 
-						if (process_buf) {
-							char *buffer = ast_strip(process_buf);
-
-							if (!ast_strlen_zero(buffer)) {
-								if (process_text_line(cfg, &cat, buffer, lineno, fn,
-									flags, comment_buffer, lline_buffer,
-									suggested_include_file, &last_cat, &last_var,
-									who_asked)) {
-									cfg = CONFIG_STATUS_FILEINVALID;
-									break;
-								}
-							}
+								memmove(oldptr, new_buf, strlen(new_buf) + 1);
+								new_buf = oldptr;
+							} else
+								process_buf = new_buf;
 						}
+					} else {
+						if (!comment) {
+							/* If ; is found, and we are not nested in a comment,
+							   we immediately stop all comment processing */
+							if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
+								CB_ADD(&lline_buffer, comment_p);
+							}
+							*comment_p = '\0';
+							new_buf = comment_p;
+						} else
+							new_buf = comment_p + 1;
 					}
 				}
-				/* end of file-- anything in a comment buffer? */
-				if (last_cat) {
-					if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-						if (lline_buffer && ast_str_strlen(lline_buffer)) {
-							CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-							ast_str_reset(lline_buffer); /* erase the lline buffer */
-						}
-						last_cat->trailing = ALLOC_COMMENT(comment_buffer);
-					}
-				} else if (last_var) {
-					if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-						if (lline_buffer && ast_str_strlen(lline_buffer)) {
-							CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-							ast_str_reset(lline_buffer); /* erase the lline buffer */
+				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
+					CB_ADD(&comment_buffer, buf);  /* the whole line is a comment, store it */
+				}
+
+				if (process_buf) {
+					char *buffer = ast_strip(process_buf);
+					if (!ast_strlen_zero(buffer)) {
+						if (process_text_line(cfg, &cat, buffer, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
+							cfg = CONFIG_STATUS_FILEINVALID;
+							break;
 						}
-						last_var->trailing = ALLOC_COMMENT(comment_buffer);
-					}
-				} else {
-					if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-						ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
 					}
 				}
-				if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
-					CB_RESET(comment_buffer, lline_buffer);
+			}
+		}
+		/* end of file-- anything in a comment buffer? */
+		if (last_cat) {
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				if (lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
 				}
-
-				fclose(f);
-			} while (0);
-			if (comment) {
-				ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
+				last_cat->trailing = ALLOC_COMMENT(comment_buffer);
 			}
-#ifdef AST_INCLUDE_GLOB
-			if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
-				break;
+		} else if (last_var) {
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				if (lline_buffer && ast_str_strlen(lline_buffer)) {
+					CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
+					ast_str_reset(lline_buffer);        /* erase the lline buffer */
+				}
+				last_var->trailing = ALLOC_COMMENT(comment_buffer);
+			}
+		} else {
+			if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
+				ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
 			}
 		}
-		globfree(&globbuf);
+		if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
+			CB_RESET(comment_buffer, lline_buffer);
+
+		fclose(f);
+	} while (0);
+	if (comment) {
+		ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
 	}
+#ifdef AST_INCLUDE_GLOB
+					if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+						break;
+					}
+				}
+				globfree(&globbuf);
+			}
+		}
 #endif
 
 	ast_free(comment_buffer);
 	ast_free(lline_buffer);
 
-	if (count == 0) {
+	if (count == 0)
 		return NULL;
-	}
 
 	return cfg;
 }
@@ -2653,20 +2403,18 @@ static void clear_config_maps(void)
 {
 	struct ast_config_map *map;
 
-	SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
 	while (config_maps) {
 		map = config_maps;
 		config_maps = config_maps->next;
 		ast_free(map);
 	}
+
+	ast_mutex_unlock(&config_lock);
 }
 
-#ifdef TEST_FRAMEWORK
-int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
-#else
-static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
-#endif
+static int append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
 {
 	struct ast_config_map *map;
 	char *dst;
@@ -2768,13 +2516,13 @@ int read_config_maps(void)
 			continue;
 		if (!strcasecmp(v->name, "sipfriends")) {
 			ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sippeers instead.\n");
-			ast_realtime_append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
+			append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
 		} else if (!strcasecmp(v->name, "iaxfriends")) {
 			ast_log(LOG_WARNING, "The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table.\n");
-			ast_realtime_append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
-			ast_realtime_append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
+			append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
+			append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
 		} else
-			ast_realtime_append_mapping(v->name, driver, database, table, pri);
+			append_mapping(v->name, driver, database, table, pri);
 	}
 
 	ast_config_destroy(config);
@@ -2785,7 +2533,7 @@ int ast_config_engine_register(struct ast_config_engine *new)
 {
 	struct ast_config_engine *ptr;
 
-	SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
 	if (!config_engine_list) {
 		config_engine_list = new;
@@ -2794,6 +2542,9 @@ int ast_config_engine_register(struct ast_config_engine *new)
 		ptr->next = new;
 	}
 
+	ast_mutex_unlock(&config_lock);
+	ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
+
 	return 1;
 }
 
@@ -2801,7 +2552,7 @@ int ast_config_engine_deregister(struct ast_config_engine *del)
 {
 	struct ast_config_engine *ptr, *last=NULL;
 
-	SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
 	for (ptr = config_engine_list; ptr; ptr=ptr->next) {
 		if (ptr == del) {
@@ -2814,20 +2565,25 @@ int ast_config_engine_deregister(struct ast_config_engine *del)
 		last = ptr;
 	}
 
+	ast_mutex_unlock(&config_lock);
+
 	return 0;
 }
 
 int ast_realtime_is_mapping_defined(const char *family)
 {
 	struct ast_config_map *map;
-	SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
 	for (map = config_maps; map; map = map->next) {
 		if (!strcasecmp(family, map->name)) {
+			ast_mutex_unlock(&config_lock);
 			return 1;
 		}
 	}
 
+	ast_mutex_unlock(&config_lock);
+
 	return 0;
 }
 
@@ -2837,7 +2593,7 @@ static struct ast_config_engine *find_engine(const char *family, int priority, c
 	struct ast_config_engine *eng, *ret = NULL;
 	struct ast_config_map *map;
 
-	SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
 	for (map = config_maps; map; map = map->next) {
 		if (!strcasecmp(family, map->name) && (priority == map->priority)) {
@@ -2857,6 +2613,8 @@ static struct ast_config_engine *find_engine(const char *family, int priority, c
 		}
 	}
 
+	ast_mutex_unlock(&config_lock);
+
 	/* if we found a mapping, but the engine is not available, then issue a warning */
 	if (map && !ret)
 		ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
@@ -2960,103 +2718,7 @@ struct ast_config *ast_config_load2(const char *filename, const char *who_asked,
 	return result;
 }
 
-#define realtime_arguments_to_fields(ap, result) realtime_arguments_to_fields2(ap, 0, result)
-
-/*!
- * \internal
- * \brief
- *
- * \param ap list of variable arguments
- * \param skip Skip argument pairs for this number of variables
- * \param result Address of a variables pointer to store the results
- *               May be NULL if no arguments are parsed
- *               Will be NULL on failure.
- *
- * \retval 0 on success or empty ap list
- * \retval -1 on failure
- */
-static int realtime_arguments_to_fields2(va_list ap, int skip, struct ast_variable **result)
-{
-	struct ast_variable *first, *fields = NULL;
-	const char *newparam;
-	const char *newval;
-
-	/*
-	 * Previously we would do:
-	 *
-	 *     va_start(ap, last);
-	 *     x = realtime_arguments_to_fields(ap);
-	 *     y = realtime_arguments_to_fields(ap);
-	 *     va_end(ap);
-	 *
-	 * While this works on generic amd64 machines (2014), it doesn't on the
-	 * raspberry PI. The va_arg() manpage says:
-	 *
-	 *     If ap is passed to a function that uses va_arg(ap,type) then
-	 *     the value of ap is undefined after the return of that function.
-	 *
-	 * On the raspberry, ap seems to get reset after the call: the contents
-	 * of y would be equal to the contents of x.
-	 *
-	 * So, instead we allow the caller to skip past earlier argument sets
-	 * using the skip parameter:
-	 *
-	 *     va_start(ap, last);
-	 *     if (realtime_arguments_to_fields(ap, &x)) {
-	 *         // FAILURE CONDITIONS
-	 *     }
-	 *     va_end(ap);
-	 *     va_start(ap, last);
-	 *     if (realtime_arguments_to_fields2(ap, 1, &y)) {
-	 *         // FAILURE CONDITIONS
-	 *     }
-	 *     va_end(ap);
-	 */
-	while (skip--) {
-		/* There must be at least one argument. */
-		newparam = va_arg(ap, const char *);
-		newval = va_arg(ap, const char *);
-		while ((newparam = va_arg(ap, const char *))) {
-			newval = va_arg(ap, const char *);
-		}
-	}
-
-	/* Load up the first vars. */
-	newparam = va_arg(ap, const char *);
-	if (!newparam) {
-		*result = NULL;
-		return 0;
-	}
-	newval = va_arg(ap, const char *);
-
-	if (!(first = ast_variable_new(newparam, newval, ""))) {
-		*result = NULL;
-		return -1;
-	}
-
-	while ((newparam = va_arg(ap, const char *))) {
-		struct ast_variable *field;
-
-		newval = va_arg(ap, const char *);
-		if (!(field = ast_variable_new(newparam, newval, ""))) {
-			ast_variables_destroy(fields);
-			ast_variables_destroy(first);
-			*result = NULL;
-			return -1;
-		}
-
-		field->next = fields;
-		fields = field;
-	}
-
-	first->next = fields;
-	fields = first;
-
-	*result = fields;
-	return 0;
-}
-
-struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
+static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
 {
 	struct ast_config_engine *eng;
 	char db[256];
@@ -3066,7 +2728,7 @@ struct ast_variable *ast_load_realtime_all_fields(const char *family, const stru
 
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) {
+			if (eng->realtime_func && (res = eng->realtime_func(db, table, ap))) {
 				return res;
 			}
 		} else {
@@ -3079,28 +2741,26 @@ struct ast_variable *ast_load_realtime_all_fields(const char *family, const stru
 
 struct ast_variable *ast_load_realtime_all(const char *family, ...)
 {
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	struct ast_variable *res = NULL;
+	struct ast_variable *res;
 	va_list ap;
 
 	va_start(ap, family);
-	realtime_arguments_to_fields(ap, &fields);
+	res = ast_load_realtime_helper(family, ap);
 	va_end(ap);
 
-	if (fields) {
-		res = ast_load_realtime_all_fields(family, fields);
-	}
-
 	return res;
 }
 
-struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
+struct ast_variable *ast_load_realtime(const char *family, ...)
 {
 	struct ast_variable *res;
 	struct ast_variable *cur;
 	struct ast_variable **prev;
+	va_list ap;
 
-	res = ast_load_realtime_all_fields(family, fields);
+	va_start(ap, family);
+	res = ast_load_realtime_helper(family, ap);
+	va_end(ap);
 
 	/* Filter the list. */
 	prev = &res;
@@ -3129,29 +2789,6 @@ struct ast_variable *ast_load_realtime_fields(const char *family, const struct a
 	return res;
 }
 
-struct ast_variable *ast_load_realtime(const char *family, ...)
-{
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	int field_res = 0;
-	va_list ap;
-
-	va_start(ap, family);
-	if (realtime_arguments_to_fields(ap, &fields)) {
-		field_res = -1;
-	}
-	va_end(ap);
-
-	if (field_res) {
-		return NULL;
-	}
-
-	if (!fields) {
-		return NULL;
-	}
-
-	return ast_load_realtime_fields(family, fields);
-}
-
 /*! \brief Check if realtime engine is configured for family */
 int ast_check_realtime(const char *family)
 {
@@ -3216,17 +2853,19 @@ int ast_unload_realtime(const char *family)
 	return res;
 }
 
-struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
+struct ast_config *ast_load_realtime_multientry(const char *family, ...)
 {
 	struct ast_config_engine *eng;
 	char db[256];
 	char table[256];
 	struct ast_config *res = NULL;
+	va_list ap;
 	int i;
 
+	va_start(ap, family);
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
+			if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, ap))) {
 				/* If we were returned an empty cfg, destroy it and return NULL */
 				if (!res->root) {
 					ast_config_destroy(res);
@@ -3238,181 +2877,103 @@ struct ast_config *ast_load_realtime_multientry_fields(const char *family, const
 			break;
 		}
 	}
-
-	return res;
-}
-
-struct ast_config *ast_load_realtime_multientry(const char *family, ...)
-{
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	va_list ap;
-
-	va_start(ap, family);
-	realtime_arguments_to_fields(ap, &fields);
 	va_end(ap);
 
-	if (!fields) {
-		return NULL;
-	}
-
-	return ast_load_realtime_multientry_fields(family, fields);
+	return res;
 }
 
-int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
 {
 	struct ast_config_engine *eng;
 	int res = -1, i;
 	char db[256];
 	char table[256];
+	va_list ap;
 
+	va_start(ap, lookup);
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			/* If the update succeeds, it returns >= 0. */
-			if (eng->update_func && ((res = eng->update_func(db, table, keyfield, lookup, fields)) >= 0)) {
+			/* If the update succeeds, it returns 0. */
+			if (eng->update_func && !(res = eng->update_func(db, table, keyfield, lookup, ap))) {
 				break;
 			}
 		} else {
 			break;
 		}
 	}
-
-	return res;
-}
-
-int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
-{
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	va_list ap;
-
-	va_start(ap, lookup);
-	realtime_arguments_to_fields(ap, &fields);
 	va_end(ap);
 
-	if (!fields) {
-		return -1;
-	}
-
-	return ast_update_realtime_fields(family, keyfield, lookup, fields);
+	return res;
 }
 
-int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+int ast_update2_realtime(const char *family, ...)
 {
 	struct ast_config_engine *eng;
 	int res = -1, i;
 	char db[256];
 	char table[256];
+	va_list ap;
 
+	va_start(ap, family);
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
+			if (eng->update2_func && !(res = eng->update2_func(db, table, ap))) {
 				break;
 			}
 		} else {
 			break;
 		}
 	}
-
-	return res;
-}
-
-int ast_update2_realtime(const char *family, ...)
-{
-	RAII_VAR(struct ast_variable *, lookup_fields, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, update_fields, NULL, ast_variables_destroy);
-	va_list ap;
-
-	va_start(ap, family);
-	/* XXX: If we wanted to pass no lookup fields (select all), we'd be
-	 * out of luck. realtime_arguments_to_fields expects at least one key
-	 * value pair. */
-	realtime_arguments_to_fields(ap, &lookup_fields);
 	va_end(ap);
 
-	va_start(ap, family);
-	realtime_arguments_to_fields2(ap, 1, &lookup_fields);
-	va_end(ap);
-
-	if (!lookup_fields || !update_fields) {
-		return -1;
-	}
-
-	return ast_update2_realtime_fields(family, lookup_fields, update_fields);
+	return res;
 }
 
-int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
+int ast_store_realtime(const char *family, ...)
 {
 	struct ast_config_engine *eng;
 	int res = -1, i;
 	char db[256];
 	char table[256];
+	va_list ap;
 
+	va_start(ap, family);
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			/* If the store succeeds, it returns >= 0*/
-			if (eng->store_func && ((res = eng->store_func(db, table, fields)) >= 0)) {
+			/* If the store succeeds, it returns 0. */
+			if (eng->store_func && !(res = eng->store_func(db, table, ap))) {
 				break;
 			}
 		} else {
 			break;
 		}
 	}
-
-	return res;
-}
-
-int ast_store_realtime(const char *family, ...)
-{
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	va_list ap;
-
-	va_start(ap, family);
-	realtime_arguments_to_fields(ap, &fields);
 	va_end(ap);
 
-	if (!fields) {
-		return -1;
-	}
-
-	return ast_store_realtime_fields(family, fields);
+	return res;
 }
 
-int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
 {
 	struct ast_config_engine *eng;
 	int res = -1, i;
 	char db[256];
 	char table[256];
+	va_list ap;
 
+	va_start(ap, lookup);
 	for (i = 1; ; i++) {
 		if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
-			if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, fields))) {
+			if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, ap))) {
 				break;
 			}
 		} else {
 			break;
 		}
 	}
-
-	return res;
-}
-
-int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
-{
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-	int res = 0;
-	va_list ap;
-
-	va_start(ap, lookup);
-	if (realtime_arguments_to_fields(ap, &fields)) {
-		res = -1;
-	}
 	va_end(ap);
 
-	if (res) {
-		return -1;
-	}
-
-	return ast_destroy_realtime_fields(family, keyfield, lookup, fields);
+	return res;
 }
 
 char *ast_realtime_decode_chunk(char *chunk)
@@ -3675,24 +3236,24 @@ static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int c
 		return NULL;
 	}
 
-	{
-		SCOPED_MUTEX(lock, &config_lock);
+	ast_mutex_lock(&config_lock);
 
-		if (!config_engine_list) {
-			ast_cli(a->fd, "No config mappings found.\n");
-		} else {
-			for (eng = config_engine_list; eng; eng = eng->next) {
-				ast_cli(a->fd, "Config Engine: %s\n", eng->name);
-				for (map = config_maps; map; map = map->next) {
-					if (!strcasecmp(map->driver, eng->name)) {
-						ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
-								map->table ? map->table : map->name);
-					}
+	if (!config_engine_list) {
+		ast_cli(a->fd, "No config mappings found.\n");
+	} else {
+		for (eng = config_engine_list; eng; eng = eng->next) {
+			ast_cli(a->fd, "Config Engine: %s\n", eng->name);
+			for (map = config_maps; map; map = map->next) {
+				if (!strcasecmp(map->driver, eng->name)) {
+					ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
+							map->table ? map->table : map->name);
 				}
 			}
 		}
 	}
 
+	ast_mutex_unlock(&config_lock);
+
 	return CLI_SUCCESS;
 }
 
@@ -3799,12 +3360,15 @@ static void config_shutdown(void)
 	AST_LIST_UNLOCK(&cfmtime_head);
 
 	ast_cli_unregister_multiple(cli_config, ARRAY_LEN(cli_config));
+
+	ao2_cleanup(cfg_hooks);
+	cfg_hooks = NULL;
 }
 
 int register_config_cli(void)
 {
 	ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));
-	ast_register_atexit(config_shutdown);
+	ast_register_cleanup(config_shutdown);
 	return 0;
 }
 
@@ -3887,5 +3451,6 @@ int ast_config_hook_register(const char *name,
 	hook->module = ast_strdup(module);
 
 	ao2_link(cfg_hooks, hook);
+	ao2_ref(hook, -1);
 	return 0;
 }
diff --git a/main/config_options.c b/main/config_options.c
index 6ca8eae..2e6e824 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -27,20 +27,15 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419342 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <regex.h>
 
-#include "asterisk/_private.h"
 #include "asterisk/config.h"
 #include "asterisk/config_options.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/acl.h"
 #include "asterisk/frame.h"
-#include "asterisk/xmldoc.h"
-#include "asterisk/cli.h"
-#include "asterisk/term.h"
-#include "asterisk/format_cap.h"
 
 #ifdef LOW_MEMORY
 #define CONFIG_OPT_BUCKETS 5
@@ -70,32 +65,11 @@ struct aco_option {
 	enum aco_option_type type;
 	aco_option_handler handler;
 	unsigned int flags;
-	unsigned int no_doc:1;
 	unsigned char deprecated:1;
 	size_t argc;
 	intptr_t args[0];
 };
 
-#ifdef AST_XML_DOCS
-static struct ao2_container *xmldocs;
-#endif /* AST_XML_DOCS */
-
-/*! \brief Value of the aco_option_type enum as strings */
-static char *aco_option_type_string[] = {
-	"ACL",				/* OPT_ACL_T, */
-	"Boolean",			/* OPT_BOOL_T, */
-	"Boolean",			/* OPT_BOOLFLAG_T, */
-	"String",			/* OPT_CHAR_ARRAY_T, */
-	"Codec",			/* OPT_CODEC_T, */
-	"Custom",			/* OPT_CUSTOM_T, */
-	"Double",			/* OPT_DOUBLE_T, */
-	"Integer",			/* OPT_INT_T, */
-	"None",				/* OPT_NOOP_T, */
-	"IP Address",		/* OPT_SOCKADDR_T, */
-	"String",			/* OPT_STRINGFIELD_T, */
-	"Unsigned Integer",	/* OPT_UINT_T, */
-};
-
 void *aco_pending_config(struct aco_info *info)
 {
 	if (!(info && info->internal)) {
@@ -126,11 +100,6 @@ static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *v
 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
 
-#ifdef AST_XML_DOCS
-static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
-static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
-#endif
-
 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
 {
 	switch(type) {
@@ -173,7 +142,7 @@ static regex_t *build_regex(const char *text)
 	return regex;
 }
 
-static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
+static int link_option_to_types(struct aco_type **types, struct aco_option *opt)
 {
 	size_t idx = 0;
 	struct aco_type *type;
@@ -183,15 +152,9 @@ static int link_option_to_types(struct aco_info *info, struct aco_type **types,
 			ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
 			return -1;
 		}
-		if (!ao2_link(type->internal->opts, opt)
-#ifdef AST_XML_DOCS
-				|| (!info->hidden &&
-					!opt->no_doc &&
-					xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type))
-#endif /* AST_XML_DOCS */
-		) {
+		if (!ao2_link(type->internal->opts, opt)) {
 			do {
-				ao2_unlink(types[idx - 1]->internal->opts, opt);
+				ao2_unlink(types[idx]->internal->opts, opt);
 			} while (--idx);
 			return -1;
 		}
@@ -219,7 +182,7 @@ int aco_option_register_deprecated(struct aco_info *info, const char *name, stru
 	opt->deprecated = 1;
 	opt->match_type = ACO_EXACT;
 
-	if (link_option_to_types(info, types, opt)) {
+	if (link_option_to_types(types, opt)) {
 		ao2_ref(opt, -1);
 		return -1;
 	}
@@ -227,66 +190,8 @@ int aco_option_register_deprecated(struct aco_info *info, const char *name, stru
 	return 0;
 }
 
-unsigned int aco_option_get_flags(const struct aco_option *option)
-{
-	return option->flags;
-}
-
-intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
-{
-	return option->args[position];
-}
-
-#ifdef AST_XML_DOCS
-/*! \internal
- * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
- */
-static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
-{
-	struct ast_xml_doc_item *iter = config_info;
-
-	if (!iter) {
-		return NULL;
-	}
-	/* First is just the configInfo, we can skip it */
-	while ((iter = AST_LIST_NEXT(iter, next))) {
-		size_t x;
-		if (strcasecmp(iter->name, name)) {
-			continue;
-		}
-		for (x = 0; types[x]; x++) {
-			/* All we care about is that at least one type has the option */
-			if (!strcasecmp(types[x]->name, iter->ref)) {
-				return iter;
-			}
-		}
-	}
-	return NULL;
-}
-
-/*! \internal
- * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
- */
-static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
-{
-	struct ast_xml_doc_item *iter = config_info;
-	if (!iter) {
-		return NULL;
-	}
-	/* First is just the config Info, skip it */
-	while ((iter = AST_LIST_NEXT(iter, next))) {
-		if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
-			break;
-		}
-	}
-	return iter;
-}
-
-#endif /* AST_XML_DOCS */
-
 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
-	const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
-	unsigned int no_doc, size_t argc, ...)
+	const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, size_t argc, ...)
 {
 	struct aco_option *opt;
 	va_list ap;
@@ -323,7 +228,6 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc
 	opt->handler = handler;
 	opt->flags = flags;
 	opt->argc = argc;
-	opt->no_doc = no_doc;
 
 	if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
 		/* This should never happen */
@@ -332,7 +236,7 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc
 		return -1;
 	};
 
-	if (link_option_to_types(info, types, opt)) {
+	if (link_option_to_types(types, opt)) {
 		ao2_ref(opt, -1);
 		return -1;
 	}
@@ -447,25 +351,12 @@ static int process_category(struct ast_config *cfg, struct aco_info *info, struc
 	 * We do not grab a reference to these objects, as the info already holds references to them. This
 	 * pointer is just a convenience. Do not actually store it somewhere. */
 	void **field;
-	regex_t *regex_skip;
 
 	/* Skip preloaded categories if we aren't preloading */
 	if (!preload && is_preload(file, cat)) {
 		return 0;
 	}
 
-	/* Skip the category if we've been told to ignore it */
-	if (!ast_strlen_zero(file->skip_category)) {
-		regex_skip = build_regex(file->skip_category);
-		if (!regexec(regex_skip, cat, 0, NULL, 0)) {
-			regfree(regex_skip);
-			ast_free(regex_skip);
-			return 0;
-		}
-		regfree(regex_skip);
-		ast_free(regex_skip);
-	}
-
 	/* Find aco_type by category, if not found it is an error */
 	if (!(type = internal_aco_type_find(file, cfg, cat))) {
 		ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
@@ -474,7 +365,7 @@ static int process_category(struct ast_config *cfg, struct aco_info *info, struc
 
 	field = info->internal->pending + type->item_offset;
 	if (!*field) {
-		ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
+		ast_log(LOG_ERROR, "No object to update!\n");
 		return -1;
 	}
 
@@ -589,17 +480,16 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload)
 {
 	struct ast_config *cfg;
 	struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
-	int res = ACO_PROCESS_OK;
-	int file_count = 0;
+	int res = ACO_PROCESS_OK, x = 0;
 	struct aco_file *file;
 
-	if (!info->internal) {
-		ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
+	if (!(info->files[0])) {
+		ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
 		return ACO_PROCESS_ERROR;
 	}
 
-	if (!(info->files[0])) {
-		ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
+	if (!info->internal) {
+		ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
 		return ACO_PROCESS_ERROR;
 	}
 
@@ -608,7 +498,7 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload)
 		return ACO_PROCESS_ERROR;
 	}
 
-	while (res != ACO_PROCESS_ERROR && (file = info->files[file_count++])) {
+	while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
 		const char *filename = file->filename;
 		struct aco_type *match;
 		int i;
@@ -633,8 +523,7 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload)
 		}
 
 try_alias:
-		cfg = ast_config_load(filename, cfg_flags);
-		if (!cfg || cfg == CONFIG_STATUS_FILEMISSING) {
+		if (!(cfg = ast_config_load(filename, cfg_flags))) {
 			if (file->alias && strcmp(file->alias, filename)) {
 				filename = file->alias;
 				goto try_alias;
@@ -647,38 +536,28 @@ try_alias:
 			res = ACO_PROCESS_UNCHANGED;
 			continue;
 		} else if (cfg == CONFIG_STATUS_FILEINVALID) {
-			ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n",
-				file->filename);
+			ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
 			res = ACO_PROCESS_ERROR;
 			break;
-		}
-
-		/* A file got loaded. */
-		if (reload) {
-			/* Must do any subsequent file loads unconditionally. */
-			reload = 0;
-			ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
-
-			if (file_count != 1) {
-				/*
-				 * Must restart loading to load all config files since a file
-				 * after the first one changed.
-				 */
-				file_count = 0;
-			} else {
-				res = internal_process_ast_config(info, file, cfg);
+		} else if (cfg == CONFIG_STATUS_FILEMISSING) {
+			if (file->alias && strcmp(file->alias, filename)) {
+				filename = file->alias;
+				goto try_alias;
 			}
-		} else {
-			res = internal_process_ast_config(info, file, cfg);
+			ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
+			res = ACO_PROCESS_ERROR;
+			break;
 		}
+
+		res = internal_process_ast_config(info, file, cfg);
 		ast_config_destroy(cfg);
 	}
 
 	if (res != ACO_PROCESS_OK) {
-		goto end;
+	   goto end;
 	}
 
-	if (info->pre_apply_config && info->pre_apply_config()) {
+	if (info->pre_apply_config && (info->pre_apply_config()))  {
 		res = ACO_PROCESS_ERROR;
 		goto end;
 	}
@@ -788,28 +667,18 @@ static int internal_type_init(struct aco_type *type)
 
 int aco_info_init(struct aco_info *info)
 {
-	size_t x = 0, y = 0;
-	struct aco_file *file;
-	struct aco_type *type;
+	size_t x, y;
 
 	if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
 		return -1;
 	}
 
-	while ((file = info->files[x++])) {
-		while ((type = file->types[y++])) {
-			if (internal_type_init(type)) {
-				goto error;
-			}
-#ifdef AST_XML_DOCS
-			if (!info->hidden &&
-				!type->hidden &&
-				xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
+	for (x = 0; info->files[x]; x++) {
+		for (y = 0; info->files[x]->types[y]; y++) {
+			if (internal_type_init(info->files[x]->types[y])) {
 				goto error;
 			}
-#endif /* AST_XML_DOCS */
 		}
-		y = 0;
 	}
 
 	return 0;
@@ -864,433 +733,6 @@ int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
 	return 0;
 }
 
-#ifdef AST_XML_DOCS
-
-/*! \internal
- * \brief Complete the name of the module the user is looking for
- */
-static char *complete_config_module(const char *word, int pos, int state)
-{
-	char *c = NULL;
-	size_t wordlen = strlen(word);
-	int which = 0;
-	struct ao2_iterator i;
-	struct ast_xml_doc_item *cur;
-
-	if (pos != 3) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(xmldocs, 0);
-	while ((cur = ao2_iterator_next(&i))) {
-		if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
-			c = ast_strdup(cur->name);
-			ao2_ref(cur, -1);
-			break;
-		}
-		ao2_ref(cur, -1);
-	}
-	ao2_iterator_destroy(&i);
-
-	return c;
-}
-
-/*! \internal
- * \brief Complete the name of the configuration type the user is looking for
- */
-static char *complete_config_type(const char *module, const char *word, int pos, int state)
-{
-	char *c = NULL;
-	size_t wordlen = strlen(word);
-	int which = 0;
-	RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
-	struct ast_xml_doc_item *cur;
-
-	if (pos != 4) {
-		return NULL;
-	}
-
-	if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
-		return NULL;
-	}
-
-	cur = info;
-	while ((cur = AST_LIST_NEXT(cur, next))) {
-		if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
-			c = ast_strdup(cur->name);
-			break;
-		}
-	}
-	return c;
-}
-
-/*! \internal
- * \brief Complete the name of the configuration option the user is looking for
- */
-static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
-{
-	char *c = NULL;
-	size_t wordlen = strlen(word);
-	int which = 0;
-	RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
-	struct ast_xml_doc_item *cur;
-
-	if (pos != 5) {
-		return NULL;
-	}
-
-	if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
-		return NULL;
-	}
-
-	cur = info;
-	while ((cur = AST_LIST_NEXT(cur, next))) {
-		if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
-			c = ast_strdup(cur->name);
-			break;
-		}
-	}
-	return c;
-}
-
-/* Define as 0 if we want to allow configurations to be registered without
- * documentation
- */
-#define XMLDOC_STRICT 1
-
-/*! \internal
- * \brief Update the XML documentation for a config type based on its registration
- */
-static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
-{
-	RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
-	RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
-	struct ast_xml_doc_item *config_type;
-	struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
-
-	/* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
-	 * has updated the docs and then load it again. */
-	if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
-		return 0;
-	}
-
-	if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
-		ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(type = ast_xml_xpath_get_first_result(results))) {
-		ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(syntax = ast_xml_new_child(type, "syntax"))) {
-		ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
-		ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
-		ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	ast_xml_set_text(tmp, category);
-	ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
-
-	if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
-		ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	ast_xml_set_attribute(tmp, "name", matchfield);
-	ast_xml_set_text(tmp, matchvalue);
-
-	if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
-		ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (ast_xmldoc_regenerate_doc_item(config_type)) {
-		ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	return 0;
-}
-
-/*! \internal
- * \brief Update the XML documentation for a config option based on its registration
- */
-static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type)
-{
-	RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
-	RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
-	struct ast_xml_doc_item * config_option;
-	struct ast_xml_node *option;
-
-	ast_assert(ARRAY_LEN(aco_option_type_string) > type);
-
-	if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
-		ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
-		ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	if (!(option = ast_xml_xpath_get_first_result(results))) {
-		ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-	ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
-	ast_xml_set_attribute(option, "default", default_value);
-	ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
-
-	if (ast_xmldoc_regenerate_doc_item(config_option)) {
-		ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
-		return XMLDOC_STRICT ? -1 : 0;
-	}
-
-	return 0;
-}
-
-/*! \internal
- * \brief Show the modules with configuration information
- */
-static void cli_show_modules(struct ast_cli_args *a)
-{
-	struct ast_xml_doc_item *item;
-	struct ao2_iterator it_items;
-
-	ast_assert(a->argc == 3);
-
-	if (ao2_container_count(xmldocs) == 0) {
-		ast_cli(a->fd, "No modules found.\n");
-		return;
-	}
-
-	it_items = ao2_iterator_init(xmldocs, 0);
-	ast_cli(a->fd, "The following modules have configuration information:\n");
-	while ((item = ao2_iterator_next(&it_items))) {
-		ast_cli(a->fd, "\t%s\n", item->name);
-		ao2_ref(item, -1);
-	}
-	ao2_iterator_destroy(&it_items);
-}
-
-/*! \internal
- * \brief Show the configuration types for a module
- */
-static void cli_show_module_types(struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
-	struct ast_xml_doc_item *tmp;
-
-	ast_assert(a->argc == 4);
-
-	if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
-		ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
-		return;
-	}
-
-	if (ast_str_strlen(item->synopsis)) {
-		ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
-	}
-	if (ast_str_strlen(item->description)) {
-		ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
-	}
-
-	tmp = item;
-	ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
-	while ((tmp = AST_LIST_NEXT(tmp, next))) {
-		if (!strcasecmp(tmp->type, "configObject")) {
-			ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
-				ast_str_buffer(tmp->synopsis));
-		}
-	}
-}
-
-/*! \internal
- * \brief Show the information for a configuration type
- */
-static void cli_show_module_type(struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
-	struct ast_xml_doc_item *tmp;
-	char option_type[64];
-	int match = 0;
-
-	ast_assert(a->argc == 5);
-
-	if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
-		ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
-		return;
-	}
-
-	tmp = item;
-	while ((tmp = AST_LIST_NEXT(tmp, next))) {
-		if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
-			match = 1;
-			term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
-			ast_cli(a->fd, "%s", option_type);
-			if (ast_str_strlen(tmp->syntax)) {
-				ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
-			} else {
-				ast_cli(a->fd, "\n\n");
-			}
-			if (ast_str_strlen(tmp->synopsis)) {
-				ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
-			}
-			if (ast_str_strlen(tmp->description)) {
-				ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
-			}
-		}
-	}
-
-	if (!match) {
-		ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
-		return;
-	}
-
-	/* Now iterate over the options for the type */
-	tmp = item;
-	while ((tmp = AST_LIST_NEXT(tmp, next))) {
-		if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
-			ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
-					ast_str_buffer(tmp->synopsis));
-		}
-	}
-}
-
-/*! \internal
- * \brief Show detailed information for an option
- */
-static void cli_show_module_options(struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
-	struct ast_xml_doc_item *tmp;
-	char option_name[64];
-	int match = 0;
-
-	ast_assert(a->argc == 6);
-
-	if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
-		ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
-		return;
-	}
-	tmp = item;
-	while ((tmp = AST_LIST_NEXT(tmp, next))) {
-		if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
-			if (match) {
-				ast_cli(a->fd, "\n");
-			}
-			term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
-			ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
-			if (ast_str_strlen(tmp->syntax)) {
-				ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
-			}
-			ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
-			if (ast_str_strlen(tmp->description)) {
-				ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
-			}
-
-			if (ast_str_strlen(tmp->seealso)) {
-				ast_cli(a->fd, "See Also:\n");
-				ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
-			}
-
-			match = 1;
-		}
-	}
-
-	if (!match) {
-		ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
-	}
-}
-
-static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "config show help";
-		e->usage =
-			"Usage: config show help [<module> [<type> [<option>]]]\n"
-			"   Display detailed information about module configuration.\n"
-			"     * If nothing is specified, the modules that have\n"
-			"       configuration information are listed.\n"
-			"     * If <module> is specified, the configuration types\n"
-			"       for that module will be listed, along with brief\n"
-			"       information about that type.\n"
-			"     * If <module> and <type> are specified, detailed\n"
-			"       information about the type is displayed, as well\n"
-			"       as the available options.\n"
-			"     * If <module>, <type>, and <option> are specified,\n"
-			"       detailed information will be displayed about that\n"
-			"       option.\n"
-			"   NOTE: the help documentation is partially generated at run\n"
-			"     time when a module is loaded. If a module is not loaded,\n"
-			"     configuration help for that module may be incomplete.\n";
-		return NULL;
-	case CLI_GENERATE:
-		switch(a->pos) {
-		case 3: return complete_config_module(a->word, a->pos, a->n);
-		case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
-		case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
-		default: return NULL;
-		}
-	}
-
-	switch (a->argc) {
-	case 3:
-		cli_show_modules(a);
-		break;
-	case 4:
-		cli_show_module_types(a);
-		break;
-	case 5:
-		cli_show_module_type(a);
-		break;
-	case 6:
-		cli_show_module_options(a);
-		break;
-	default:
-		return CLI_SHOWUSAGE;
-	}
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_aco[] = {
-	AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
-};
-
-static void aco_deinit(void)
-{
-	ast_cli_unregister(cli_aco);
-	ao2_cleanup(xmldocs);
-}
-#endif /* AST_XML_DOCS */
-
-int aco_init(void)
-{
-#ifdef AST_XML_DOCS
-	ast_register_atexit(aco_deinit);
-	if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
-		ast_log(LOG_ERROR, "Couldn't build config documentation\n");
-		return -1;
-	}
-	ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
-#endif /* AST_XML_DOCS */
-	return 0;
-}
-
 /* Default config option handlers */
 
 /*! \brief Default option handler for signed integers
@@ -1307,7 +749,7 @@ static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var
 			ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
 		if (res) {
 			if (opt->flags & PARSE_RANGE_DEFAULTS) {
-				ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
+				ast_log(LOG_WARNING, "Failed to set %s=%s. Set to  %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
 				res = 0;
 			} else if (opt->flags & PARSE_DEFAULT) {
 				ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
@@ -1337,7 +779,7 @@ static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *va
 			ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
 		if (res) {
 			if (opt->flags & PARSE_RANGE_DEFAULTS) {
-				ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %u instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
+				ast_log(LOG_WARNING, "Failed to set %s=%s. Set to  %u instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
 				res = 0;
 			} else if (opt->flags & PARSE_DEFAULT) {
 				ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
@@ -1378,8 +820,9 @@ static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var
  * enum aco_option_type in config_options.h
  */
 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
-	struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
-	return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
+	struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
+	struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
+	return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
 }
 
 /*! \brief Default option handler for stringfields
@@ -1391,10 +834,6 @@ static int stringfield_handler_fn(const struct aco_option *opt, struct ast_varia
 	ast_string_field *field = (const char **)(obj + opt->args[0]);
 	struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
 	struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
-
-	if (opt->flags && ast_strlen_zero(var->value)) {
-		return -1;
-	}
 	ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
 	return 0;
 }
@@ -1437,7 +876,7 @@ static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable
 	return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
 }
 
-/*! \brief Default handler for doing nothing
+/*! \brief Default handler for doing noithing
  */
 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
@@ -1453,9 +892,6 @@ static int chararray_handler_fn(const struct aco_option *opt, struct ast_variabl
 	char *field = (char *)(obj + opt->args[0]);
 	size_t len = opt->args[1];
 
-	if (opt->flags && ast_strlen_zero(var->value)) {
-		return -1;
-	}
 	ast_copy_string(field, var->value, len);
 	return 0;
 }
diff --git a/main/core_local.c b/main/core_local.c
deleted file mode 100644
index c79d88e..0000000
--- a/main/core_local.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Local proxy channel driver.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-/* ------------------------------------------------------------------- */
-
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/cli.h"
-#include "asterisk/manager.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/bridge.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/core_local.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/_private.h"
-#include "asterisk/stasis_channels.h"
-
-/*** DOCUMENTATION
-	<manager name="LocalOptimizeAway" language="en_US">
-		<synopsis>
-			Optimize away a local channel when possible.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Channel" required="true">
-				<para>The channel name to optimize away.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>A local channel created with "/n" will not automatically optimize away.
-			Calling this command on the local channel will clear that flag and allow
-			it to optimize away if it's bridged or when it becomes bridged.</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="LocalBridge">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="LocalOne"/>
-				<channel_snapshot prefix="LocalTwo"/>
-				<parameter name="Context">
-					<para>The context in the dialplan that Channel2 starts in.</para>
-				</parameter>
-				<parameter name="Exten">
-					<para>The extension in the dialplan that Channel2 starts in.</para>
-				</parameter>
-				<parameter name="LocalOptimization">
-					<enumlist>
-						<enum name="Yes"/>
-						<enum name="No"/>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="LocalOptimizationBegin">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when two halves of a Local Channel begin to optimize
-			themselves out of the media path.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="LocalOne"/>
-				<channel_snapshot prefix="LocalTwo"/>
-				<channel_snapshot prefix="Source"/>
-				<parameter name="DestUniqueId">
-					<para>The unique ID of the bridge into which the local channel is optimizing.</para>
-				</parameter>
-				<parameter name="Id">
-					<para>Identification for the optimization operation.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">LocalOptimizationEnd</ref>
-				<ref type="manager">LocalOptimizeAway</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="LocalOptimizationEnd">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when two halves of a Local Channel have finished optimizing
-			themselves out of the media path.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="LocalOne"/>
-				<channel_snapshot prefix="LocalTwo"/>
-				<parameter name="Success">
-					<para>Indicates whether the local optimization succeeded.</para>
-				</parameter>
-				<parameter name="Id">
-					<para>Identification for the optimization operation. Matches the <replaceable>Id</replaceable>
-					from a previous <literal>LocalOptimizationBegin</literal></para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">LocalOptimizationBegin</ref>
-				<ref type="manager">LocalOptimizeAway</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
-static const char tdesc[] = "Local Proxy Channel Driver";
-
-static struct ao2_container *locals;
-
-static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
-static int local_call(struct ast_channel *ast, const char *dest, int timeout);
-static int local_hangup(struct ast_channel *ast);
-static int local_devicestate(const char *data);
-static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
-		enum ast_unreal_channel_indicator dest, unsigned int id);
-static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id);
-
-static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *msg);
-
-/*!
- * @{ \brief Define local channel message types.
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type,
-	.to_ami = local_message_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_begin_type,
-	.to_ami = local_message_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_end_type,
-	.to_ami = local_message_to_ami,
-	);
-/*! @} */
-
-/*! \brief Callbacks from the unreal core when channel optimization occurs */
-struct ast_unreal_pvt_callbacks local_unreal_callbacks = {
-	.optimization_started = local_optimization_started_cb,
-	.optimization_finished = local_optimization_finished_cb,
-};
-
-/* PBX interface structure for channel registration */
-static struct ast_channel_tech local_tech = {
-	.type = "Local",
-	.description = tdesc,
-	.requester = local_request,
-	.send_digit_begin = ast_unreal_digit_begin,
-	.send_digit_end = ast_unreal_digit_end,
-	.call = local_call,
-	.hangup = local_hangup,
-	.answer = ast_unreal_answer,
-	.read = ast_unreal_read,
-	.write = ast_unreal_write,
-	.write_video = ast_unreal_write,
-	.exception = ast_unreal_read,
-	.indicate = ast_unreal_indicate,
-	.fixup = ast_unreal_fixup,
-	.send_html = ast_unreal_sendhtml,
-	.send_text = ast_unreal_sendtext,
-	.devicestate = local_devicestate,
-	.queryoption = ast_unreal_queryoption,
-	.setoption = ast_unreal_setoption,
-};
-
-/*! What to do with the ;2 channel when ast_call() happens. */
-enum local_call_action {
-	/* The ast_call() will run dialplan on the ;2 channel. */
-	LOCAL_CALL_ACTION_DIALPLAN,
-	/* The ast_call() will impart the ;2 channel into a bridge. */
-	LOCAL_CALL_ACTION_BRIDGE,
-	/* The ast_call() will masquerade the ;2 channel into a channel. */
-	LOCAL_CALL_ACTION_MASQUERADE,
-};
-
-/*! Join a bridge on ast_call() parameters. */
-struct local_bridge {
-	/*! Bridge to join. */
-	struct ast_bridge *join;
-	/*! Channel to swap with when joining bridge. */
-	struct ast_channel *swap;
-	/*! Features that are specific to this channel when pushed into the bridge. */
-	struct ast_bridge_features *features;
-};
-
-/*!
- * \brief the local pvt structure for all channels
- *
- * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
- *
- * ast_chan owner -> local_pvt -> ast_chan chan
- */
-struct local_pvt {
-	/*! Unreal channel driver base class values. */
-	struct ast_unreal_pvt base;
-	/*! Additional action arguments */
-	union {
-		/*! Make ;2 join a bridge on ast_call(). */
-		struct local_bridge bridge;
-		/*! Make ;2 masquerade into this channel on ast_call(). */
-		struct ast_channel *masq;
-	} action;
-	/*! What to do with the ;2 channel on ast_call(). */
-	enum local_call_action type;
-	/*! Context to call */
-	char context[AST_MAX_CONTEXT];
-	/*! Extension to call */
-	char exten[AST_MAX_EXTENSION];
-};
-
-struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
-	struct local_pvt *found;
-	struct ast_channel *peer;
-
-	if (!p) {
-		return NULL;
-	}
-
-	found = p ? ao2_find(locals, p, 0) : NULL;
-	if (!found) {
-		/* ast is either not a local channel or it has alredy been hungup */
-		return NULL;
-	}
-	ao2_lock(found);
-	if (ast == p->base.owner) {
-		peer = p->base.chan;
-	} else if (ast == p->base.chan) {
-		peer = p->base.owner;
-	} else {
-		peer = NULL;
-	}
-	if (peer) {
-		ast_channel_ref(peer);
-	}
-	ao2_unlock(found);
-	ao2_ref(found, -1);
-	return peer;
-}
-
-/*! \brief Adds devicestate to local channels */
-static int local_devicestate(const char *data)
-{
-	int is_inuse = 0;
-	int res = AST_DEVICE_INVALID;
-	char *exten = ast_strdupa(data);
-	char *context;
-	char *opts;
-	struct local_pvt *lp;
-	struct ao2_iterator it;
-
-	/* Strip options if they exist */
-	opts = strchr(exten, '/');
-	if (opts) {
-		*opts = '\0';
-	}
-
-	context = strchr(exten, '@');
-	if (!context) {
-		ast_log(LOG_WARNING,
-			"Someone used Local/%s somewhere without a @context. This is bad.\n", data);
-		return AST_DEVICE_INVALID;
-	}
-	*context++ = '\0';
-
-	it = ao2_iterator_init(locals, 0);
-	for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
-		ao2_lock(lp);
-		if (!strcmp(exten, lp->exten)
-			&& !strcmp(context, lp->context)) {
-			res = AST_DEVICE_NOT_INUSE;
-			if (lp->base.owner
-				&& ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
-				is_inuse = 1;
-			}
-		}
-		ao2_unlock(lp);
-		if (is_inuse) {
-			res = AST_DEVICE_INUSE;
-			ao2_ref(lp, -1);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&it);
-
-	if (res == AST_DEVICE_INVALID) {
-		ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
-		if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
-			res = AST_DEVICE_NOT_INUSE;
-		}
-	}
-
-	return res;
-}
-
-static struct ast_multi_channel_blob *local_channel_optimization_blob(struct local_pvt *p,
-		struct ast_json *json_object)
-{
-	struct ast_multi_channel_blob *payload;
-	RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
-
-	local_one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.owner));
-	if (!local_one_snapshot) {
-		return NULL;
-	}
-
-	local_two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.chan));
-	if (!local_two_snapshot) {
-		return NULL;
-	}
-
-	payload = ast_multi_channel_blob_create(json_object);
-	if (!payload) {
-		return NULL;
-	}
-	ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
-	ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
-
-	return payload;
-}
-
-/*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_started_cb */
-static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
-		enum ast_unreal_channel_indicator dest, unsigned int id)
-{
-	RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct local_pvt *p = (struct local_pvt *)base;
-
-	if (!ast_local_optimization_begin_type()) {
-		return;
-	}
-
-	json_object = ast_json_pack("{s: i, s: i}",
-			"dest", dest, "id", id);
-
-	if (!json_object) {
-		return;
-	}
-
-	payload = local_channel_optimization_blob(p, json_object);
-	if (!payload) {
-		return;
-	}
-
-	if (source) {
-		RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
-		source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
-		if (!source_snapshot) {
-			return;
-		}
-
-		ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
-	}
-
-	msg = stasis_message_create(ast_local_optimization_begin_type(), payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_channel_topic(p->base.owner), msg);
-}
-
-/*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_finished_cb */
-static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
-{
-	RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct local_pvt *p = (struct local_pvt *)base;
-
-	if (!ast_local_optimization_end_type()) {
-		return;
-	}
-
-	json_object = ast_json_pack("{s: i, s: i}", "success", success, "id", id);
-
-	if (!json_object) {
-		return;
-	}
-
-	payload = local_channel_optimization_blob(p, json_object);
-	if (!payload) {
-		return;
-	}
-
-	msg = stasis_message_create(ast_local_optimization_end_type(), payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_channel_topic(p->base.owner), msg);
-}
-
-static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *obj = stasis_message_data(message);
-	struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
-	struct ast_channel_snapshot *local_snapshot_one;
-	struct ast_channel_snapshot *local_snapshot_two;
-	RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
-	RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
-	const char *event;
-
-	local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
-	local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
-	if (!local_snapshot_one || !local_snapshot_two) {
-		return NULL;
-	}
-
-	event_buffer = ast_str_create(1024);
-	local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
-	local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
-	if (!event_buffer || !local_channel_one || !local_channel_two) {
-		return NULL;
-	}
-
-	if (stasis_message_type(message) == ast_local_optimization_begin_type()) {
-		struct ast_channel_snapshot *source_snapshot;
-		RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
-		const char *dest_uniqueid;
-
-		source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
-		if (source_snapshot) {
-			source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
-			if (!source_str) {
-				return NULL;
-			}
-		}
-
-		dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
-				local_snapshot_one->uniqueid : local_snapshot_two->uniqueid;
-
-		event = "LocalOptimizationBegin";
-		if (source_str) {
-			ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
-		}
-		ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
-		ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
-	} else if (stasis_message_type(message) == ast_local_optimization_end_type()) {
-		event = "LocalOptimizationEnd";
-		ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
-		ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
-	} else if (stasis_message_type(message) == ast_local_bridge_type()) {
-		event = "LocalBridge";
-		ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
-		ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
-		ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
-	} else {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, event,
-		"%s"
-		"%s"
-		"%s",
-		ast_str_buffer(local_channel_one),
-		ast_str_buffer(local_channel_two),
-		ast_str_buffer(event_buffer));
-}
-
-/*!
- * \internal
- * \brief Post the \ref ast_local_bridge_type \ref stasis message
- * \since 12.0.0
- *
- * \param p local_pvt to raise the local bridge message
- *
- * \return Nothing
- */
-static void publish_local_bridge_message(struct local_pvt *p)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
-	struct ast_channel *owner;
-	struct ast_channel *chan;
-
-	if (!ast_local_bridge_type()) {
-		return;
-	}
-
-	ast_unreal_lock_all(&p->base, &chan, &owner);
-
-	blob = ast_json_pack("{s: s, s: s, s: b}",
-		"context", p->context,
-		"exten", p->exten,
-		"can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
-	if (!blob) {
-		goto end;
-	}
-
-	multi_blob = ast_multi_channel_blob_create(blob);
-	if (!multi_blob) {
-		goto end;
-	}
-
-	one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(owner));
-	if (!one_snapshot) {
-		goto end;
-	}
-
-	two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
-	if (!two_snapshot) {
-		goto end;
-	}
-
-	ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
-	ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
-
-	msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
-	if (!msg) {
-		goto end;
-	}
-
-	stasis_publish(ast_channel_topic(owner), msg);
-
-end:
-	ast_channel_unlock(owner);
-	ast_channel_unref(owner);
-
-	ast_channel_unlock(chan);
-	ast_channel_unref(chan);
-
-	ao2_unlock(&p->base);
-}
-
-int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
-{
-	struct local_pvt *p;
-	struct local_pvt *found;
-	int res = -1;
-
-	/* Sanity checks. */
-	if (!ast || !bridge) {
-		ast_bridge_features_destroy(features);
-		return -1;
-	}
-
-	ast_channel_lock(ast);
-	p = ast_channel_tech_pvt(ast);
-	ast_channel_unlock(ast);
-
-	found = p ? ao2_find(locals, p, 0) : NULL;
-	if (found) {
-		ao2_lock(found);
-		if (found->type == LOCAL_CALL_ACTION_DIALPLAN
-			&& found->base.owner
-			&& found->base.chan
-			&& !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
-			ao2_ref(bridge, +1);
-			if (swap) {
-				ast_channel_ref(swap);
-			}
-			found->type = LOCAL_CALL_ACTION_BRIDGE;
-			found->action.bridge.join = bridge;
-			found->action.bridge.swap = swap;
-			found->action.bridge.features = features;
-			res = 0;
-		} else {
-			ast_bridge_features_destroy(features);
-		}
-		ao2_unlock(found);
-		ao2_ref(found, -1);
-	}
-
-	return res;
-}
-
-int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
-{
-	struct local_pvt *p;
-	struct local_pvt *found;
-	int res = -1;
-
-	/* Sanity checks. */
-	if (!ast || !masq) {
-		return -1;
-	}
-
-	ast_channel_lock(ast);
-	p = ast_channel_tech_pvt(ast);
-	ast_channel_unlock(ast);
-
-	found = p ? ao2_find(locals, p, 0) : NULL;
-	if (found) {
-		ao2_lock(found);
-		if (found->type == LOCAL_CALL_ACTION_DIALPLAN
-			&& found->base.owner
-			&& found->base.chan
-			&& !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
-			ast_channel_ref(masq);
-			found->type = LOCAL_CALL_ACTION_MASQUERADE;
-			found->action.masq = masq;
-			res = 0;
-		}
-		ao2_unlock(found);
-		ao2_ref(found, -1);
-	}
-
-	return res;
-}
-
-/*! \brief Initiate new call, part of PBX interface
- *         dest is the dial string */
-static int local_call(struct ast_channel *ast, const char *dest, int timeout)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
-	int pvt_locked = 0;
-
-	struct ast_channel *owner = NULL;
-	struct ast_channel *chan = NULL;
-	int res;
-	char *reduced_dest = ast_strdupa(dest);
-	char *slash;
-	const char *chan_cid;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* since we are letting go of channel locks that were locked coming into
-	 * this function, then we need to give the tech pvt a ref */
-	ao2_ref(p, 1);
-	ast_channel_unlock(ast);
-
-	ast_unreal_lock_all(&p->base, &chan, &owner);
-	pvt_locked = 1;
-
-	if (owner != ast) {
-		res = -1;
-		goto return_cleanup;
-	}
-
-	if (!owner || !chan) {
-		res = -1;
-		goto return_cleanup;
-	}
-
-	ast_unreal_call_setup(owner, chan);
-
-	/*
-	 * If the local channel has /n on the end of it, we need to lop
-	 * that off for our argument to setting up the CC_INTERFACES
-	 * variable.
-	 */
-	if ((slash = strrchr(reduced_dest, '/'))) {
-		*slash = '\0';
-	}
-	ast_set_cc_interfaces_chanvar(chan, reduced_dest);
-
-	ao2_unlock(p);
-	pvt_locked = 0;
-
-	ast_channel_unlock(owner);
-
-	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
-		ast_channel_caller(chan)->id.number.str, NULL);
-	if (chan_cid) {
-		chan_cid = ast_strdupa(chan_cid);
-	}
-	ast_channel_unlock(chan);
-
-	res = -1;
-	switch (p->type) {
-	case LOCAL_CALL_ACTION_DIALPLAN:
-		if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
-			ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
-				p->exten, p->context);
-		} else {
-			publish_local_bridge_message(p);
-
-			/* Start switch on sub channel */
-			res = ast_pbx_start(chan);
-		}
-		break;
-	case LOCAL_CALL_ACTION_BRIDGE:
-		publish_local_bridge_message(p);
-		ast_answer(chan);
-		res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
-			p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
-		ao2_ref(p->action.bridge.join, -1);
-		p->action.bridge.join = NULL;
-		ao2_cleanup(p->action.bridge.swap);
-		p->action.bridge.swap = NULL;
-		p->action.bridge.features = NULL;
-		break;
-	case LOCAL_CALL_ACTION_MASQUERADE:
-		publish_local_bridge_message(p);
-		ast_answer(chan);
-		res = ast_channel_move(p->action.masq, chan);
-		if (!res) {
-			/* Chan is now an orphaned zombie.  Destroy it. */
-			ast_hangup(chan);
-		}
-		p->action.masq = ast_channel_unref(p->action.masq);
-		break;
-	}
-	if (!res) {
-		ao2_lock(p);
-		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
-		ao2_unlock(p);
-	}
-
-	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
-	owner = ast_channel_unref(owner);
-	chan = ast_channel_unref(chan);
-
-return_cleanup:
-	if (p) {
-		if (pvt_locked) {
-			ao2_unlock(p);
-		}
-		ao2_ref(p, -1);
-	}
-	if (chan) {
-		ast_channel_unlock(chan);
-		ast_channel_unref(chan);
-	}
-
-	/*
-	 * owner is supposed to be == to ast, if it is, don't unlock it
-	 * because ast must exit locked
-	 */
-	if (owner) {
-		if (owner != ast) {
-			ast_channel_unlock(owner);
-			ast_channel_lock(ast);
-		}
-		ast_channel_unref(owner);
-	} else {
-		/* we have to exit with ast locked */
-		ast_channel_lock(ast);
-	}
-
-	return res;
-}
-
-/*! \brief Hangup a call through the local proxy channel */
-static int local_hangup(struct ast_channel *ast)
-{
-	struct local_pvt *p = ast_channel_tech_pvt(ast);
-	int res;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* give the pvt a ref to fulfill calling requirements. */
-	ao2_ref(p, +1);
-	res = ast_unreal_hangup(&p->base, ast);
-	if (!res) {
-		int unlink;
-
-		ao2_lock(p);
-		unlink = !p->base.owner && !p->base.chan;
-		ao2_unlock(p);
-		if (unlink) {
-			ao2_unlink(locals, p);
-		}
-	}
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief struct local_pvt destructor.
- *
- * \param vdoomed Object to destroy.
- *
- * \return Nothing
- */
-static void local_pvt_destructor(void *vdoomed)
-{
-	struct local_pvt *doomed = vdoomed;
-
-	switch (doomed->type) {
-	case LOCAL_CALL_ACTION_DIALPLAN:
-		break;
-	case LOCAL_CALL_ACTION_BRIDGE:
-		ao2_cleanup(doomed->action.bridge.join);
-		ao2_cleanup(doomed->action.bridge.swap);
-		ast_bridge_features_destroy(doomed->action.bridge.features);
-		break;
-	case LOCAL_CALL_ACTION_MASQUERADE:
-		ao2_cleanup(doomed->action.masq);
-		break;
-	}
-	ast_unreal_destructor(&doomed->base);
-}
-
-/*! \brief Create a call structure */
-static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
-{
-	struct local_pvt *pvt;
-	char *parse;
-	char *context;
-	char *opts;
-
-	pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);
-	if (!pvt) {
-		return NULL;
-	}
-	pvt->base.callbacks = &local_unreal_callbacks;
-
-	parse = ast_strdupa(data);
-
-	/*
-	 * Local channels intercept MOH by default.
-	 *
-	 * This is a silly default because it represents state held by
-	 * the local channels.  Unless local channel optimization is
-	 * disabled, the state will dissapear when the local channels
-	 * optimize out.
-	 */
-	ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
-
-	/* Look for options */
-	if ((opts = strchr(parse, '/'))) {
-		*opts++ = '\0';
-		if (strchr(opts, 'n')) {
-			ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
-		}
-		if (strchr(opts, 'j')) {
-			if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
-				ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
-			} else {
-				ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
-			}
-		}
-		if (strchr(opts, 'm')) {
-			ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
-		}
-	}
-
-	/* Look for a context */
-	if ((context = strchr(parse, '@'))) {
-		*context++ = '\0';
-	}
-
-	ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
-	ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
-	snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
-
-	return pvt; /* this is returned with a ref */
-}
-
-/*! \brief Part of PBX interface */
-static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	struct local_pvt *p;
-	struct ast_channel *chan;
-	struct ast_callid *callid;
-
-	/* Allocate a new private structure and then Asterisk channels */
-	p = local_alloc(data, cap);
-	if (!p) {
-		return NULL;
-	}
-	callid = ast_read_threadstorage_callid();
-	chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
-		p->exten, p->context, assignedids, requestor, callid);
-	if (chan) {
-		ao2_link(locals, p);
-	}
-	if (callid) {
-		ast_callid_unref(callid);
-	}
-	ao2_ref(p, -1); /* kill the ref from the alloc */
-
-	return chan;
-}
-
-/*! \brief CLI command "local show channels" */
-static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct local_pvt *p;
-	struct ao2_iterator it;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "local show channels";
-		e->usage =
-			"Usage: local show channels\n"
-			"       Provides summary information on active local proxy channels.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (ao2_container_count(locals) == 0) {
-		ast_cli(a->fd, "No local channels in use\n");
-		return RESULT_SUCCESS;
-	}
-
-	it = ao2_iterator_init(locals, 0);
-	while ((p = ao2_iterator_next(&it))) {
-		ao2_lock(p);
-		ast_cli(a->fd, "%s -- %s\n",
-			p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
-			p->base.name);
-		ao2_unlock(p);
-		ao2_ref(p, -1);
-	}
-	ao2_iterator_destroy(&it);
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_local[] = {
-	AST_CLI_DEFINE(locals_show, "List status of local channels"),
-};
-
-static int manager_optimize_away(struct mansession *s, const struct message *m)
-{
-	const char *channel;
-	struct local_pvt *p;
-	struct local_pvt *found;
-	struct ast_channel *chan;
-
-	channel = astman_get_header(m, "Channel");
-	if (ast_strlen_zero(channel)) {
-		astman_send_error(s, m, "'Channel' not specified.");
-		return 0;
-	}
-
-	chan = ast_channel_get_by_name(channel);
-	if (!chan) {
-		astman_send_error(s, m, "Channel does not exist.");
-		return 0;
-	}
-
-	p = ast_channel_tech_pvt(chan);
-	ast_channel_unref(chan);
-
-	found = p ? ao2_find(locals, p, 0) : NULL;
-	if (found) {
-		ao2_lock(found);
-		ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
-		ao2_unlock(found);
-		ao2_ref(found, -1);
-		astman_send_ack(s, m, "Queued channel to be optimized away");
-	} else {
-		astman_send_error(s, m, "Unable to find channel");
-	}
-
-	return 0;
-}
-
-
-static int locals_cmp_cb(void *obj, void *arg, int flags)
-{
-	return (obj == arg) ? CMP_MATCH : 0;
-}
-
-/*!
- * \internal
- * \brief Shutdown the local proxy channel.
- * \since 12.0.0
- *
- * \return Nothing
- */
-static void local_shutdown(void)
-{
-	struct local_pvt *p;
-	struct ao2_iterator it;
-
-	/* First, take us out of the channel loop */
-	ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
-	ast_manager_unregister("LocalOptimizeAway");
-	ast_channel_unregister(&local_tech);
-
-	it = ao2_iterator_init(locals, 0);
-	while ((p = ao2_iterator_next(&it))) {
-		if (p->base.owner) {
-			ast_softhangup(p->base.owner, AST_SOFTHANGUP_APPUNLOAD);
-		}
-		ao2_ref(p, -1);
-	}
-	ao2_iterator_destroy(&it);
-	ao2_ref(locals, -1);
-	locals = NULL;
-
-	ao2_cleanup(local_tech.capabilities);
-	local_tech.capabilities = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_begin_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_end_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_local_bridge_type);
-}
-
-int ast_local_init(void)
-{
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_begin_type)) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_end_type)) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_local_bridge_type)) {
-		return -1;
-	}
-
-	if (!(local_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		return -1;
-	}
-	ast_format_cap_append_by_type(local_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
-
-	locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
-	if (!locals) {
-		ao2_cleanup(local_tech.capabilities);
-		local_tech.capabilities = NULL;
-		return -1;
-	}
-
-	/* Make sure we can register our channel type */
-	if (ast_channel_register(&local_tech)) {
-		ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
-		ao2_ref(locals, -1);
-		ao2_cleanup(local_tech.capabilities);
-		local_tech.capabilities = NULL;
-		return -1;
-	}
-	ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
-	ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
-
-	ast_register_atexit(local_shutdown);
-	return 0;
-}
diff --git a/main/core_unreal.c b/main/core_unreal.c
deleted file mode 100644
index d93cbf0..0000000
--- a/main/core_unreal.c
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013 Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Unreal channel derivatives framework for channel drivers like local channels.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425783 $")
-
-#include "asterisk/causes.h"
-#include "asterisk/channel.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/pbx.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/bridge.h"
-#include "asterisk/core_unreal.h"
-
-static unsigned int name_sequence = 0;
-
-void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
-{
-	struct ast_channel *chan = NULL;
-	struct ast_channel *owner = NULL;
-
-	ao2_lock(p);
-	for (;;) {
-		if (p->chan) {
-			chan = p->chan;
-			ast_channel_ref(chan);
-		}
-		if (p->owner) {
-			owner = p->owner;
-			ast_channel_ref(owner);
-		}
-		ao2_unlock(p);
-
-		/* if we don't have both channels, then this is very easy */
-		if (!owner || !chan) {
-			if (owner) {
-				ast_channel_lock(owner);
-			} else if(chan) {
-				ast_channel_lock(chan);
-			}
-		} else {
-			/* lock both channels first, then get the pvt lock */
-			ast_channel_lock_both(chan, owner);
-		}
-		ao2_lock(p);
-
-		/* Now that we have all the locks, validate that nothing changed */
-		if (p->owner != owner || p->chan != chan) {
-			if (owner) {
-				ast_channel_unlock(owner);
-				owner = ast_channel_unref(owner);
-			}
-			if (chan) {
-				ast_channel_unlock(chan);
-				chan = ast_channel_unref(chan);
-			}
-			continue;
-		}
-
-		break;
-	}
-	*outowner = p->owner;
-	*outchan = p->chan;
-}
-
-/* Called with ast locked */
-int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
-{
-	int res = 0;
-	struct ast_unreal_pvt *p;
-	struct ast_channel *otherchan = NULL;
-	ast_chan_write_info_t *write_info;
-	char *info_data;
-
-	if (option != AST_OPTION_CHANNEL_WRITE) {
-		return -1;
-	}
-
-	write_info = data;
-
-	if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
-		ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
-		return -1;
-	}
-
-	info_data = write_info->data;
-	if (!strcmp(write_info->function, "CHANNEL")) {
-		if (!strncasecmp(info_data, "hangup_handler_", 15)) {
-			/* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
-			return 0;
-		}
-
-		/* Crossover the accountcode and peeraccount to cross the unreal bridge. */
-		if (!strcasecmp(info_data, "accountcode")) {
-			info_data = "peeraccount";
-		} else if (!strcasecmp(info_data, "peeraccount")) {
-			info_data = "accountcode";
-		}
-	}
-
-	/* get the tech pvt */
-	if (!(p = ast_channel_tech_pvt(ast))) {
-		return -1;
-	}
-	ao2_ref(p, 1);
-	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
-
-	/* get the channel we are supposed to write to */
-	ao2_lock(p);
-	otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
-	if (!otherchan || otherchan == write_info->chan) {
-		res = -1;
-		otherchan = NULL;
-		ao2_unlock(p);
-		goto setoption_cleanup;
-	}
-	ast_channel_ref(otherchan);
-
-	/* clear the pvt lock before grabbing the channel */
-	ao2_unlock(p);
-
-	ast_channel_lock(otherchan);
-	res = write_info->write_fn(otherchan, write_info->function, info_data, write_info->value);
-	ast_channel_unlock(otherchan);
-
-setoption_cleanup:
-	ao2_ref(p, -1);
-	if (otherchan) {
-		ast_channel_unref(otherchan);
-	}
-	ast_channel_lock(ast); /* Lock back before we leave */
-	return res;
-}
-
-/* Called with ast locked */
-int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
-{
-	struct ast_unreal_pvt *p;
-	struct ast_channel *peer;
-	struct ast_channel *other;
-	int res = 0;
-
-	if (option != AST_OPTION_T38_STATE) {
-		/* AST_OPTION_T38_STATE is the only supported option at this time */
-		return -1;
-	}
-
-	/* for some reason the channel is not locked in channel.c when this function is called */
-	if (!(p = ast_channel_tech_pvt(ast))) {
-		return -1;
-	}
-
-	ao2_lock(p);
-	other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
-	if (!other) {
-		ao2_unlock(p);
-		return -1;
-	}
-	ast_channel_ref(other);
-	ao2_unlock(p);
-	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
-
-	peer = ast_channel_bridge_peer(other);
-	if (peer) {
-		res = ast_channel_queryoption(peer, option, data, datalen, 0);
-		ast_channel_unref(peer);
-	}
-	ast_channel_unref(other);
-	ast_channel_lock(ast); /* Lock back before we leave */
-
-	return res;
-}
-
-/*!
- * \brief queue a frame onto either the p->owner or p->chan
- *
- * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
- * decremented after this function is called.  This is a side effect of the deadlock
- * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
- * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
- * during deadlock avoidance.
- */
-static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
-	struct ast_channel *us, int us_locked)
-{
-	struct ast_channel *other;
-
-	/* Recalculate outbound channel */
-	other = isoutbound ? p->owner : p->chan;
-	if (!other) {
-		return 0;
-	}
-
-	/* do not queue media frames if a generator is on both unreal channels */
-	if (us
-		&& (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
-		&& ast_channel_generator(us)
-		&& ast_channel_generator(other)) {
-		return 0;
-	}
-
-	/* grab a ref on the channel before unlocking the pvt,
-	 * other can not go away from us now regardless of locking */
-	ast_channel_ref(other);
-	if (us && us_locked) {
-		ast_channel_unlock(us);
-	}
-	ao2_unlock(p);
-
-	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
-		ast_setstate(other, AST_STATE_RINGING);
-	}
-	ast_queue_frame(other, f);
-
-	other = ast_channel_unref(other);
-	if (us && us_locked) {
-		ast_channel_lock(us);
-	}
-	ao2_lock(p);
-
-	return 0;
-}
-
-int ast_unreal_answer(struct ast_channel *ast)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int isoutbound;
-	int res = -1;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1);
-	ao2_lock(p);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	if (isoutbound) {
-		/* Pass along answer since somebody answered us */
-		struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
-
-		res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
-	} else {
-		ast_log(LOG_WARNING, "Huh?  %s is being asked to answer?\n",
-			ast_channel_name(ast));
-	}
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-	return res;
-}
-
-/*!
- * \internal
- * \brief Check and optimize out the unreal channels between bridges.
- * \since 12.0.0
- *
- * \param ast Channel writing a frame into the unreal channels.
- * \param p Unreal channel private.
- *
- * \note It is assumed that ast is locked.
- * \note It is assumed that p is locked.
- *
- * \retval 0 if unreal channels were not optimized out.
- * \retval non-zero if unreal channels were optimized out.
- */
-static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
-{
-	int res = 0;
-
-	/* Do a few conditional checks early on just to see if this optimization is possible */
-	if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
-		return res;
-	}
-
-	if (ast == p->owner) {
-		res = ast_bridge_unreal_optimize_out(p->owner, p->chan, p);
-	} else if (ast == p->chan) {
-		res = ast_bridge_unreal_optimize_out(p->chan, p->owner, p);
-	}
-
-	return res;
-}
-
-struct ast_frame  *ast_unreal_read(struct ast_channel *ast)
-{
-	return &ast_null_frame;
-}
-
-int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = -1;
-
-	if (!p) {
-		return -1;
-	}
-
-	/* Just queue for delivery to the other side */
-	ao2_ref(p, 1);
-	ao2_lock(p);
-	switch (f->frametype) {
-	case AST_FRAME_VOICE:
-	case AST_FRAME_VIDEO:
-		if (got_optimized_out(ast, p)) {
-			break;
-		}
-		/* fall through */
-	default:
-		res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
-		break;
-	}
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
-	struct ast_bridge *bridge_owner;
-	struct ast_bridge *bridge_chan;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_lock(p);
-
-	if ((p->owner != oldchan) && (p->chan != oldchan)) {
-		ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
-		ao2_unlock(p);
-		return -1;
-	}
-	if (p->owner == oldchan) {
-		p->owner = newchan;
-	} else {
-		p->chan = newchan;
-	}
-
-	if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
-		ao2_unlock(p);
-		return 0;
-	}
-
-	/* Do not let a masquerade cause an unreal channel to be bridged to itself! */
-	bridge_owner = ast_channel_internal_bridge(p->owner);
-	bridge_chan = ast_channel_internal_bridge(p->chan);
-	if (bridge_owner && bridge_owner == bridge_chan) {
-		ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
-			ast_channel_name(newchan));
-		ao2_unlock(p);
-		ast_queue_hangup(newchan);
-		return -1;
-	}
-
-	ao2_unlock(p);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Queue up a frame representing the indication as a control frame.
- * \since 12.0.0
- *
- * \param p Unreal private structure.
- * \param ast Channel indicating the condition.
- * \param condition What is being indicated.
- * \param data Extra data.
- * \param datalen Length of extra data.
- *
- * \retval 0 on success.
- * \retval AST_T38_REQUEST_PARMS if successful and condition is AST_CONTROL_T38_PARAMETERS.
- * \retval -1 on error.
- */
-static int unreal_queue_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
-	int res = 0;
-	int isoutbound;
-
-	ao2_lock(p);
-	/*
-	 * Block -1 stop tones events if we are to be optimized out.  We
-	 * don't need a flurry of these events on an unreal channel chain
-	 * when initially connected to slow the optimization process.
-	 */
-	if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
-		struct ast_frame f = {
-			.frametype = AST_FRAME_CONTROL,
-			.subclass.integer = condition,
-			.data.ptr = (void *) data,
-			.datalen = datalen,
-		};
-
-		isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-		res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
-		if (!res
-			&& condition == AST_CONTROL_T38_PARAMETERS
-			&& datalen == sizeof(struct ast_control_t38_parameters)) {
-			const struct ast_control_t38_parameters *parameters = data;
-
-			if (parameters->request_response == AST_T38_REQUEST_PARMS) {
-				res = AST_T38_REQUEST_PARMS;
-			}
-		}
-	} else {
-		ast_debug(4, "Blocked indication %d\n", condition);
-	}
-	ao2_unlock(p);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Handle COLP and redirecting conditions.
- * \since 12.0.0
- *
- * \param p Unreal private structure.
- * \param ast Channel indicating the condition.
- * \param condition What is being indicated.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
-{
-	struct ast_channel *my_chan;
-	struct ast_channel *my_owner;
-	struct ast_channel *this_channel;
-	struct ast_channel *the_other_channel;
-	int isoutbound;
-	int res = 0;
-	unsigned char frame_data[1024];
-	struct ast_frame f = {
-		.frametype = AST_FRAME_CONTROL,
-		.subclass.integer = condition,
-		.data.ptr = frame_data,
-	};
-
-	/*
-	 * A connected line update frame may only contain a partial
-	 * amount of data, such as just a source, or just a ton, and not
-	 * the full amount of information.  However, the collected
-	 * information is all stored in the outgoing channel's
-	 * connectedline structure, so when receiving a connected line
-	 * update on an outgoing unreal channel, we need to transmit the
-	 * collected connected line information instead of whatever
-	 * happens to be in this control frame.  The same applies for
-	 * redirecting information, which is why it is handled here as
-	 * well.
-	 */
-	ast_channel_unlock(ast);
-	ast_unreal_lock_all(p, &my_chan, &my_owner);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	if (isoutbound) {
-		this_channel = p->chan;
-		the_other_channel = p->owner;
-	} else {
-		this_channel = p->owner;
-		the_other_channel = p->chan;
-	}
-	if (the_other_channel) {
-		if (condition == AST_CONTROL_CONNECTED_LINE) {
-			ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel),
-				ast_channel_connected(this_channel));
-			f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
-				ast_channel_connected(this_channel), NULL);
-		} else {
-			f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
-				ast_channel_redirecting(this_channel), NULL);
-		}
-	}
-	if (my_chan) {
-		ast_channel_unlock(my_chan);
-		ast_channel_unref(my_chan);
-	}
-	if (my_owner) {
-		ast_channel_unlock(my_owner);
-		ast_channel_unref(my_owner);
-	}
-	if (the_other_channel) {
-		res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
-	}
-	ao2_unlock(p);
-	ast_channel_lock(ast);
-
-	return res;
-}
-
-int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = 0;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1); /* ref for unreal_queue_frame */
-
-	switch (condition) {
-	case AST_CONTROL_MASQUERADE_NOTIFY:
-		/*
-		 * Always block this because this is the channel being
-		 * masqueraded; not anything down the chain.
-		 */
-		break;
-	case AST_CONTROL_CONNECTED_LINE:
-	case AST_CONTROL_REDIRECTING:
-		res = unreal_colp_redirect_indicate(p, ast, condition);
-		break;
-	case AST_CONTROL_HOLD:
-		if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
-			ast_moh_start(ast, data, NULL);
-			break;
-		}
-		res = unreal_queue_indicate(p, ast, condition, data, datalen);
-		break;
-	case AST_CONTROL_UNHOLD:
-		if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
-			ast_moh_stop(ast);
-			break;
-		}
-		res = unreal_queue_indicate(p, ast, condition, data, datalen);
-		break;
-	default:
-		res = unreal_queue_indicate(p, ast, condition, data, datalen);
-		break;
-	}
-
-	ao2_ref(p, -1);
-	return res;
-}
-
-int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = -1;
-	struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
-	int isoutbound;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1); /* ref for unreal_queue_frame */
-	ao2_lock(p);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	f.subclass.integer = digit;
-	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = -1;
-	struct ast_frame f = { AST_FRAME_DTMF_END, };
-	int isoutbound;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1); /* ref for unreal_queue_frame */
-	ao2_lock(p);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	f.subclass.integer = digit;
-	f.len = duration;
-	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = -1;
-	struct ast_frame f = { AST_FRAME_TEXT, };
-	int isoutbound;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1); /* ref for unreal_queue_frame */
-	ao2_lock(p);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	f.data.ptr = (char *) text;
-	f.datalen = strlen(text) + 1;
-	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-	return res;
-}
-
-int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
-{
-	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
-	int res = -1;
-	struct ast_frame f = { AST_FRAME_HTML, };
-	int isoutbound;
-
-	if (!p) {
-		return -1;
-	}
-
-	ao2_ref(p, 1); /* ref for unreal_queue_frame */
-	ao2_lock(p);
-	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
-	f.subclass.integer = subclass;
-	f.data.ptr = (char *)data;
-	f.datalen = datalen;
-	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
-	ao2_unlock(p);
-	ao2_ref(p, -1);
-
-	return res;
-}
-
-void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
-{
-	struct ast_var_t *varptr;
-	struct ast_var_t *clone_var;
-
-	ast_channel_stage_snapshot(semi2);
-
-	/*
-	 * Note that cid_num and cid_name aren't passed in the
-	 * ast_channel_alloc calls in ast_unreal_new_channels().  It's
-	 * done here instead.
-	 */
-	ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));
-
-	ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
-
-	/* Crossover the CallerID and conected-line to cross the unreal bridge. */
-	ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
-	ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
-
-	ast_channel_language_set(semi2, ast_channel_language(semi1));
-
-	/* Crossover the accountcode and peeraccount to cross the unreal bridge. */
-	ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1));
-	ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1));
-
-	ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
-
-	ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
-
-	/*
-	 * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
-	 * set on the queue/dial call request in the dialplan.
-	 */
-	if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
-		ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
-	}
-
-	/*
-	 * Copy the channel variables from the semi1 channel to the
-	 * outgoing channel.
-	 *
-	 * Note that due to certain assumptions, they MUST be in the
-	 * same order.
-	 */
-	AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
-		clone_var = ast_var_assign(varptr->name, varptr->value);
-		if (clone_var) {
-			AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
-			ast_channel_publish_varset(semi2, ast_var_full_name(clone_var),
-				ast_var_value(clone_var));
-		}
-	}
-	ast_channel_datastore_inherit(semi1, semi2);
-
-	ast_channel_stage_snapshot_done(semi2);
-}
-
-int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
-{
-	struct ast_bridge_features *features;
-	struct ast_channel *chan;
-	struct ast_channel *owner;
-	RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);
-
-	RAII_VAR(struct ast_callid *, bridge_callid, NULL, ast_callid_cleanup);
-
-	ast_bridge_lock(bridge);
-	bridge_callid = bridge->callid ? ast_callid_ref(bridge->callid) : NULL;
-	ast_bridge_unlock(bridge);
-
-	{
-		SCOPED_CHANNELLOCK(lock, ast);
-		p = ast_channel_tech_pvt(ast);
-		if (!p) {
-			return -1;
-		}
-		ao2_ref(p, +1);
-	}
-
-	{
-		SCOPED_AO2LOCK(lock, p);
-		chan = p->chan;
-		if (!chan) {
-			return -1;
-		}
-
-		owner = p->owner;
-		if (!owner) {
-			return -1;
-		}
-
-		ast_channel_ref(chan);
-		ast_channel_ref(owner);
-	}
-
-	if (bridge_callid) {
-		struct ast_callid *chan_callid;
-		struct ast_callid *owner_callid;
-
-		/* chan side call ID setting */
-		ast_channel_lock(chan);
-
-		chan_callid = ast_channel_callid(chan);
-		if (!chan_callid) {
-			ast_channel_callid_set(chan, bridge_callid);
-		}
-		ast_channel_unlock(chan);
-		ast_callid_cleanup(chan_callid);
-
-		/* owner side call ID setting */
-		ast_channel_lock(owner);
-
-		owner_callid = ast_channel_callid(owner);
-		if (!owner_callid) {
-			ast_channel_callid_set(owner, bridge_callid);
-		}
-
-		ast_channel_unlock(owner);
-		ast_callid_cleanup(owner_callid);
-	}
-
-	/* We are done with the owner now that its call ID matches the bridge */
-	ast_channel_unref(owner);
-	owner = NULL;
-
-	features = ast_bridge_features_new();
-	if (!features) {
-		ast_channel_unref(chan);
-		return -1;
-	}
-
-	ast_set_flag(&features->feature_flags, flags);
-
-	/* Impart the semi2 channel into the bridge */
-	if (ast_bridge_impart(bridge, chan, NULL, features,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_bridge_features_destroy(features);
-		ast_channel_unref(chan);
-		return -1;
-	}
-
-	ao2_lock(p);
-	ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
-	ao2_unlock(p);
-	ast_channel_unref(chan);
-
-	return 0;
-}
-
-int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
-{
-	int hangup_chan = 0;
-	int res = 0;
-	int cause;
-	struct ast_channel *owner = NULL;
-	struct ast_channel *chan = NULL;
-
-	/* the pvt isn't going anywhere, it has a ref */
-	ast_channel_unlock(ast);
-
-	/* lock everything */
-	ast_unreal_lock_all(p, &chan, &owner);
-
-	if (ast != chan && ast != owner) {
-		res = -1;
-		goto unreal_hangup_cleanup;
-	}
-
-	cause = ast_channel_hangupcause(ast);
-
-	if (ast == p->chan) {
-		/* Outgoing side is hanging up. */
-		ast_clear_flag(p, AST_UNREAL_CARETAKER_THREAD);
-		p->chan = NULL;
-		if (p->owner) {
-			const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
-
-			if (status) {
-				ast_channel_hangupcause_set(p->owner, cause);
-				pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
-			}
-			ast_queue_hangup_with_cause(p->owner, cause);
-		}
-	} else {
-		/* Owner side is hanging up. */
-		p->owner = NULL;
-		if (p->chan) {
-			if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
-				ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
-				ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
-					ast_channel_name(p->chan));
-			}
-			if (!ast_test_flag(p, AST_UNREAL_CARETAKER_THREAD)) {
-				/*
-				 * Need to actually hangup p->chan since nothing else is taking
-				 * care of it.
-				 */
-				hangup_chan = 1;
-			} else {
-				ast_queue_hangup_with_cause(p->chan, cause);
-			}
-		}
-	}
-
-	/* this is one of our locked channels, doesn't matter which */
-	ast_channel_tech_pvt_set(ast, NULL);
-	ao2_ref(p, -1);
-
-unreal_hangup_cleanup:
-	ao2_unlock(p);
-	if (owner) {
-		ast_channel_unlock(owner);
-		ast_channel_unref(owner);
-	}
-	if (chan) {
-		ast_channel_unlock(chan);
-		if (hangup_chan) {
-			ast_hangup(chan);
-		}
-		ast_channel_unref(chan);
-	}
-
-	/* leave with the channel locked that came in */
-	ast_channel_lock(ast);
-
-	return res;
-}
-
-void ast_unreal_destructor(void *vdoomed)
-{
-	struct ast_unreal_pvt *doomed = vdoomed;
-
-	ao2_cleanup(doomed->reqcap);
-	doomed->reqcap = NULL;
-}
-
-struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
-{
-	struct ast_unreal_pvt *unreal;
-
-	static const struct ast_jb_conf jb_conf = {
-		.flags = 0,
-		.max_size = -1,
-		.resync_threshold = -1,
-		.impl = "",
-		.target_extra = -1,
-	};
-
-	unreal = ao2_alloc(size, destructor);
-	if (!unreal) {
-		return NULL;
-	}
-
-	unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!unreal->reqcap) {
-		ao2_ref(unreal, -1);
-		return NULL;
-	}
-	ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);
-
-	memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
-
-	return unreal;
-}
-
-struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
-	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
-	const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
-	const struct ast_channel *requestor, struct ast_callid *callid)
-{
-	struct ast_channel *owner;
-	struct ast_channel *chan;
-	RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
-	struct ast_assigned_ids id1 = {NULL, NULL};
-	struct ast_assigned_ids id2 = {NULL, NULL};
-	int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
-
-	/* set unique ids for the two channels */
-	if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
-		id1.uniqueid = assignedids->uniqueid;
-		id2.uniqueid = assignedids->uniqueid2;
-	}
-
-	/* if id1 given but not id2, use default of id1;2 */
-	if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
-		char *uniqueid2;
-
-		uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
-		strcpy(uniqueid2, id1.uniqueid);/* Safe */
-		strcat(uniqueid2, ";2");/* Safe */
-		id2.uniqueid = uniqueid2;
-	}
-
-	/*
-	 * Allocate two new Asterisk channels
-	 *
-	 * Make sure that the ;2 channel gets the same linkedid as ;1.
-	 * You can't pass linkedid to both allocations since if linkedid
-	 * isn't set, then each channel will generate its own linkedid.
-	 */
-	owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
-		exten, context, &id1, requestor, 0,
-		"%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
-	if (!owner) {
-		ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
-		return NULL;
-	}
-
-	if (callid) {
-		ast_channel_callid_set(owner, callid);
-	}
-
-	ast_channel_tech_set(owner, tech);
-	ao2_ref(p, +1);
-	ast_channel_tech_pvt_set(owner, p);
-
-	ast_channel_nativeformats_set(owner, p->reqcap);
-
-	/* Determine our read/write format and set it on each channel */
-	fmt = ast_format_cap_get_format(p->reqcap, 0);
-	if (!fmt) {
-		ast_channel_tech_pvt_set(owner, NULL);
-		ao2_ref(p, -1);
-		ast_channel_unlock(owner);
-		ast_channel_release(owner);
-		return NULL;
-	}
-
-	ast_channel_set_writeformat(owner, fmt);
-	ast_channel_set_rawwriteformat(owner, fmt);
-	ast_channel_set_readformat(owner, fmt);
-	ast_channel_set_rawreadformat(owner, fmt);
-
-	ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
-
-	ast_jb_configure(owner, &p->jb_conf);
-
-	if (ast_channel_cc_params_init(owner, requestor
-		? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
-		ast_channel_tech_pvt_set(owner, NULL);
-		ao2_ref(p, -1);
-		ast_channel_tech_pvt_set(owner, NULL);
-		ast_channel_unlock(owner);
-		ast_channel_release(owner);
-		return NULL;
-	}
-
-	p->owner = owner;
-	ast_channel_unlock(owner);
-
-	chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
-		exten, context, &id2, owner, 0,
-		"%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
-	if (!chan) {
-		ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
-		ast_channel_tech_pvt_set(owner, NULL);
-		ao2_ref(p, -1);
-		ast_channel_tech_pvt_set(owner, NULL);
-		ast_channel_release(owner);
-		return NULL;
-	}
-
-	if (callid) {
-		ast_channel_callid_set(chan, callid);
-	}
-
-	ast_channel_tech_set(chan, tech);
-	ao2_ref(p, +1);
-	ast_channel_tech_pvt_set(chan, p);
-
-	ast_channel_nativeformats_set(chan, p->reqcap);
-
-	/* Format was already determined when setting up owner */
-	ast_channel_set_writeformat(chan, fmt);
-	ast_channel_set_rawwriteformat(chan, fmt);
-	ast_channel_set_readformat(chan, fmt);
-	ast_channel_set_rawreadformat(chan, fmt);
-
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
-
-	p->chan = chan;
-	ast_channel_unlock(chan);
-
-	return owner;
-}
diff --git a/main/crypt.c b/main/crypt.c
deleted file mode 100644
index a5c74b9..0000000
--- a/main/crypt.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Asterisk wrapper for crypt(3)
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 393675 $")
-
-#include <unistd.h>
-#if defined(HAVE_CRYPT_R)
-#include <crypt.h>
-#endif
-
-#include "asterisk/utils.h"
-
-/*!
- * \brief Max length of a salt string.
- *
- * $[1,5,6]$[a–zA–Z0–9./]{1,16}$, plus null terminator
- */
-#define MAX_SALT_LEN 21
-
-static char salt_chars[] =
-	"abcdefghijklmnopqrstuvwxyz"
-	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-	"0123456789"
-	"./";
-
-/*! Randomly select a character for a salt string */
-static char gen_salt_char(void)
-{
-	int which = ast_random_double() * 64;
-	return salt_chars[which];
-}
-
-/*!
- * \brief Generates a salt to try with crypt.
- *
- * If given an empty string, will generate a salt for the most secure algorithm
- * to try with crypt(). If given a previously generated salt, the algorithm will
- * be lowered by one level of security.
- *
- * \param[out] current_salt Output string in which to generate the salt.
- *                          This can be an empty string, or the results of a
- *                          prior gen_salt call.
- * \param max_len Length of \a current_salt.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-static int gen_salt(char *current_salt, size_t maxlen)
-{
-	int i;
-
-	if (maxlen < MAX_SALT_LEN || current_salt == NULL) {
-		return -1;
-	}
-
-	switch (current_salt[0]) {
-	case '\0':
-		/* Initial generation; $6$ = SHA-512 */
-		*current_salt++ = '$';
-		*current_salt++ = '6';
-		*current_salt++ = '$';
-		for (i = 0; i < 16; ++i) {
-			*current_salt++ = gen_salt_char();
-		}
-		*current_salt++ = '$';
-		*current_salt++ = '\0';
-		return 0;
-	case '$':
-		switch (current_salt[1]) {
-		case '6':
-			/* Downgrade to SHA-256 */
-			current_salt[1] = '5';
-			return 0;
-		case '5':
-			/* Downgrade to MD5 */
-			current_salt[1] = '1';
-			return 0;
-		case '1':
-			/* Downgrade to traditional crypt */
-			*current_salt++ = gen_salt_char();
-			*current_salt++ = gen_salt_char();
-			*current_salt++ = '\0';
-			return 0;
-		default:
-			/* Unrecognized algorithm */
-			return -1;
-		}
-	default:
-		/* Was already as insecure as it gets */
-		return -1;
-	}
-
-}
-
-#if defined(HAVE_CRYPT_R)
-
-char *ast_crypt(const char *key, const char *salt)
-{
-	struct crypt_data data = {};
-	const char *crypted = crypt_r(key, salt, &data);
-
-	/* Crypt may return success even if it doesn't recognize the salt. But
-	 * in those cases it always mangles the salt in some way.
-	 */
-	if (!crypted || !ast_begins_with(crypted, salt)) {
-		return NULL;
-	}
-
-	return ast_strdup(crypted);
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-	struct crypt_data data = {};
-	return strcmp(expected, crypt_r(key, expected, &data)) == 0;
-}
-
-#elif defined(HAVE_CRYPT)
-
-/* crypt is not reentrant. A global mutex is neither ideal nor perfect, but good
- * enough if crypt_r support is unavailable
- */
-AST_MUTEX_DEFINE_STATIC(crypt_mutex);
-
-char *ast_crypt(const char *key, const char *salt)
-{
-	const char *crypted;
-	SCOPED_MUTEX(lock, &crypt_mutex);
-
-	crypted = crypt(key, salt);
-
-	/* Crypt may return success even if it doesn't recognize the salt. But
-	 * in those cases it always mangles the salt in some way.
-	 */
-	if (!crypted || !ast_begins_with(crypted, salt)) {
-		return NULL;
-	}
-
-	return ast_strdup(crypted);
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-	SCOPED_MUTEX(lock, &crypt_mutex);
-	return strcmp(expected, crypt(key, expected)) == 0;
-}
-
-#else /* No crypt support */
-
-char *ast_crypt(const char *key, const char *salt)
-{
-	ast_log(LOG_WARNING,
-		"crypt() support not available; cannot encrypt password\n");
-	return NULL;
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-	ast_log(LOG_WARNING,
-		"crypt() support not available; cannot validate password\n");
-	return 0;
-}
-
-#endif  /* No crypt support */
-
-char *ast_crypt_encrypt(const char *key)
-{
-	char salt[MAX_SALT_LEN] = {};
-	while (gen_salt(salt, sizeof(salt)) == 0) {
-		char *crypted = ast_crypt(key, salt);
-		if (crypted) {
-			return crypted;
-		}
-	}
-	return NULL;
-}
diff --git a/main/data.c b/main/data.c
index d4e38aa..8b3846b 100644
--- a/main/data.c
+++ b/main/data.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424752 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -45,7 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424752 $")
 #include "asterisk/manager.h"
 #include "asterisk/test.h"
 #include "asterisk/frame.h"
-#include "asterisk/codec.h"
 
 /*** DOCUMENTATION
 	<manager name="DataGet" language="en_US">
@@ -2798,7 +2797,7 @@ static void data_result_print_cli_node(int fd, const struct ast_data *node, uint
 
 	ast_free(tabs);
 
-	ast_term_color_code(&output, 0, 0);
+	ast_term_color_code(&output, COLOR_WHITE, 0);
 
 	ast_cli(fd, "%s", ast_str_buffer(output));
 
@@ -2842,7 +2841,19 @@ static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_
  */
 static void data_result_print_cli(int fd, const struct ast_data *root)
 {
-	ast_cli(fd, COLORIZE_FMT "\n", COLORIZE(data_result_get_color(root->type), 0, root->name));
+	struct ast_str *output;
+
+	/* print the initial node. */
+	output = ast_str_create(30);
+	if (!output) {
+		return;
+	}
+
+	ast_term_color_code(&output, data_result_get_color(root->type), 0);
+	ast_str_append(&output, 0, "%s\n", root->name);
+	ast_term_color_code(&output, COLOR_WHITE, 0);
+	ast_cli(fd, "%s", ast_str_buffer(output));
+	ast_free(output);
 
 	__data_result_print_cli(fd, root, 0);
 
@@ -3098,69 +3109,62 @@ static int manager_data_get(struct mansession *s, const struct message *m)
 	return RESULT_SUCCESS;
 }
 
-static int data_add_codec(struct ast_data *codecs, struct ast_format *format) {
-	struct ast_data *codec;
-	struct ast_codec *tmp;
-
-	tmp = ast_codec_get_by_id(ast_format_get_codec_id(format));
-	if (!tmp) {
-		return -1;
-	}
-
-	codec = ast_data_add_node(codecs, "codec");
-	if (!codec) {
-		ao2_ref(tmp, -1);
-		return -1;
-	}
-
-	ast_data_add_str(codec, "name", tmp->name);
-	ast_data_add_int(codec, "samplespersecond", tmp->sample_rate);
-	ast_data_add_str(codec, "description", tmp->description);
-	ast_data_add_int(codec, "frame_length", tmp->minimum_bytes);
-	ao2_ref(tmp, -1);
-
-	return 0;
-}
-
 int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format)
 {
-	struct ast_data *codecs;
+	struct ast_data *codecs, *codec;
+	size_t fmlist_size;
+	const struct ast_format_list *fmlist;
+	int x;
 
 	codecs = ast_data_add_node(root, node_name);
 	if (!codecs) {
 		return -1;
 	}
+	fmlist = ast_format_list_get(&fmlist_size);
+	for (x = 0; x < fmlist_size; x++) {
+		if (ast_format_cmp(&fmlist[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			codec = ast_data_add_node(codecs, "codec");
+			if (!codec) {
+				ast_format_list_destroy(fmlist);
+				return -1;
+			}
+			ast_data_add_str(codec, "name", fmlist[x].name);
+			ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
+			ast_data_add_str(codec, "description", fmlist[x].desc);
+			ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
+		}
+	}
+	ast_format_list_destroy(fmlist);
 
-	return data_add_codec(codecs, format);
+	return 0;
 }
 
 int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap)
 {
-	struct ast_data *codecs;
-	size_t i;
-	size_t count;
+	struct ast_data *codecs, *codec;
+	size_t fmlist_size;
+	const struct ast_format_list *fmlist;
+	int x;
 
 	codecs = ast_data_add_node(root, node_name);
 	if (!codecs) {
 		return -1;
 	}
-
-	count = ast_format_cap_count(cap);
-	for (i = 0; i < count; ++i) {
-		struct ast_format *fmt;
-
-		fmt = ast_format_cap_get_format(cap, i);
-		if (!fmt) {
-			return -1;
-		}
-
-		if (data_add_codec(codecs, fmt)) {
-			ao2_ref(fmt, -1);
-			return -1;
+	fmlist = ast_format_list_get(&fmlist_size);
+	for (x = 0; x < fmlist_size; x++) {
+		if (ast_format_cap_iscompatible(cap, &fmlist[x].format)) {
+			codec = ast_data_add_node(codecs, "codec");
+			if (!codec) {
+				ast_format_list_destroy(fmlist);
+				return -1;
+			}
+			ast_data_add_str(codec, "name", fmlist[x].name);
+			ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
+			ast_data_add_str(codec, "description", fmlist[x].desc);
+			ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
 		}
-
-		ao2_ref(fmt, -1);
 	}
+	ast_format_list_destroy(fmlist);
 
 	return 0;
 }
@@ -3311,10 +3315,7 @@ AST_TEST_DEFINE(test_data_get)
 
 #endif
 
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void data_shutdown(void)
 {
 	ast_manager_unregister("DataGet");
@@ -3342,7 +3343,7 @@ int ast_data_init(void)
 
 	AST_TEST_REGISTER(test_data_get);
 
-	ast_register_atexit(data_shutdown);
+	ast_register_cleanup(data_shutdown);
 
 	return res;
 }
diff --git a/main/datastore.c b/main/datastore.c
index 4d1de16..d086d67 100644
--- a/main/datastore.c
+++ b/main/datastore.c
@@ -25,7 +25,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 393239 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -83,3 +83,19 @@ int ast_datastore_free(struct ast_datastore *datastore)
 
 	return res;
 }
+
+/* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
+ *
+ * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE
+ *
+ */
+
+/* Provide binary compatibility for modules that call ast_datastore_alloc() directly;
+ * newly compiled modules will call __ast_datastore_alloc() via the macros in datastore.h
+ */
+#undef ast_datastore_alloc
+struct ast_datastore *ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid);
+struct ast_datastore *ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
+{
+	return __ast_datastore_alloc(info, uid, __FILE__, __LINE__, __FUNCTION__);
+}
diff --git a/main/db.c b/main/db.c
index 93f94ed..0b87ee5 100644
--- a/main/db.c
+++ b/main/db.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419504 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_DB */
@@ -983,10 +983,7 @@ static void *db_sync_thread(void *data)
 	return NULL;
 }
 
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void astdb_atexit(void)
 {
 	ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database));
diff --git a/main/devicestate.c b/main/devicestate.c
index e18b2ec..48d2d5c 100644
--- a/main/devicestate.c
+++ b/main/devicestate.c
@@ -117,33 +117,9 @@
 	<support_level>core</support_level>
  ***/
 
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="DeviceStateChange">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a device state changes</synopsis>
-			<syntax>
-				<parameter name="Device">
-					<para>The device whose state has changed</para>
-				</parameter>
-				<parameter name="State">
-					<para>The new state of the device</para>
-				</parameter>
-			</syntax>
-			<description>
-				<para>This differs from the <literal>ExtensionStatus</literal>
-				event because this event is raised for all device state changes,
-				not only for changes that affect dialplan hints.</para>
-			</description>
-			<see-also>
-				<ref type="managerEvent">ExtensionStatus</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422661 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/channel.h"
@@ -153,11 +129,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422661 $")
 #include "asterisk/devicestate.h"
 #include "asterisk/pbx.h"
 #include "asterisk/app.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/devicestate.h"
-
-#define DEVSTATE_TOPIC_BUCKETS 57
+#include "asterisk/event.h"
 
 /*! \brief Device state strings for printing */
 static const char * const devstatestring[][2] = {
@@ -169,7 +141,7 @@ static const char * const devstatestring[][2] = {
 	{ /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", "UNAVAILABLE" }, /*!< Unavailable (not registered) */
 	{ /* 6 AST_DEVICE_RINGING */     "Ringing",     "RINGING"     }, /*!< Ring, ring, ring */
 	{ /* 7 AST_DEVICE_RINGINUSE */   "Ring+Inuse",  "RINGINUSE"   }, /*!< Ring and in use */
-	{ /* 8 AST_DEVICE_ONHOLD */      "On Hold",     "ONHOLD"      }, /*!< On Hold */
+	{ /* 8 AST_DEVICE_ONHOLD */      "On Hold",      "ONHOLD"      }, /*!< On Hold */
 };
 
 /*!\brief Mapping for channel states to device states */
@@ -187,6 +159,7 @@ static const struct chan2dev {
 	{ AST_STATE_BUSY,            AST_DEVICE_BUSY },
 	{ AST_STATE_DIALING_OFFHOOK, AST_DEVICE_INUSE },
 	{ AST_STATE_PRERING,         AST_DEVICE_RINGING },
+	{ -100,                      -100 },
 };
 
 /*! \brief  A device state provider (not a channel) */
@@ -215,21 +188,25 @@ static pthread_t change_thread = AST_PTHREADT_NULL;
 /*! \brief Flag for the queue */
 static ast_cond_t change_pending;
 
-struct stasis_subscription *devstate_message_sub;
-
-static struct stasis_topic *device_state_topic_all;
-static struct stasis_cache *device_state_cache;
-static struct stasis_caching_topic *device_state_topic_cached;
-static struct stasis_topic_pool *device_state_topic_pool;
-
-static struct ast_manager_event_blob *devstate_to_ami(struct stasis_message *msg);
-static struct ast_event *devstate_to_event(struct stasis_message *msg);
-
+struct devstate_change {
+	AST_LIST_ENTRY(devstate_change) entry;
+	uint32_t state;
+	struct ast_eid eid;
+	enum ast_devstate_cache cachable;
+	char device[1];
+};
 
-STASIS_MESSAGE_TYPE_DEFN(ast_device_state_message_type,
-	.to_ami = devstate_to_ami,
-	.to_event = devstate_to_event,
-);
+static struct {
+	pthread_t thread;
+	struct ast_event_sub *event_sub;
+	ast_cond_t cond;
+	ast_mutex_t lock;
+	AST_LIST_HEAD_NOLOCK(, devstate_change) devstate_change_q;
+	unsigned int enabled:1;
+} devstate_collector = {
+	.thread = AST_PTHREADT_NULL,
+	.enabled = 0,
+};
 
 /* Forward declarations */
 static int getproviderstate(const char *provider, const char *address);
@@ -250,7 +227,7 @@ enum ast_device_state ast_state_chan2dev(enum ast_channel_state chanstate)
 {
 	int i;
 	chanstate &= 0xFFFF;
-	for (i = 0; i < ARRAY_LEN(chan2dev); i++) {
+	for (i = 0; chan2dev[i].chan != -100; i++) {
 		if (chan2dev[i].chan == chanstate) {
 			return chan2dev[i].dev;
 		}
@@ -303,42 +280,43 @@ enum ast_device_state ast_parse_device_state(const char *device)
 		return AST_DEVICE_UNKNOWN;
 	}
 
-	if (ast_channel_hold_state(chan) == AST_CONTROL_HOLD) {
-		res = AST_DEVICE_ONHOLD;
-	} else {
-		res = ast_state_chan2dev(ast_channel_state(chan));
-	}
-	ast_channel_unref(chan);
+	res = (ast_channel_state(chan) == AST_STATE_RINGING) ? AST_DEVICE_RINGING : AST_DEVICE_INUSE;
+
+	chan = ast_channel_unref(chan);
 
 	return res;
 }
 
 static enum ast_device_state devstate_cached(const char *device)
 {
-	struct stasis_message *cached_msg;
-	struct ast_device_state_message *device_state;
-	enum ast_device_state state;
+	enum ast_device_state res = AST_DEVICE_UNKNOWN;
+	struct ast_event *event;
 
-	cached_msg = stasis_cache_get_by_eid(ast_device_state_cache(),
-		ast_device_state_message_type(), device, NULL);
-	if (!cached_msg) {
-		return AST_DEVICE_UNKNOWN;
-	}
-	device_state = stasis_message_data(cached_msg);
-	state = device_state->state;
-	ao2_cleanup(cached_msg);
+	event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+		AST_EVENT_IE_END);
+
+	if (!event)
+		return res;
 
-	return state;
+	res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+	ast_event_destroy(event);
+
+	return res;
 }
 
 /*! \brief Check device state through channel specific function or generic function */
 static enum ast_device_state _ast_device_state(const char *device, int check_cache)
 {
+	char *buf;
 	char *number;
 	const struct ast_channel_tech *chan_tech;
 	enum ast_device_state res;
 	/*! \brief Channel driver that provides device state */
 	char *tech;
+	/*! \brief Another provider of device state */
+	char *provider = NULL;
 
 	/* If the last known state is cached, just return that */
 	if (check_cache) {
@@ -348,18 +326,16 @@ static enum ast_device_state _ast_device_state(const char *device, int check_cac
 		}
 	}
 
-	number = ast_strdupa(device);
-	tech = strsep(&number, "/");
-	if (!number) {
-		/*! \brief Another provider of device state */
-		char *provider;
-
+	buf = ast_strdupa(device);
+	tech = strsep(&buf, "/");
+	if (!(number = buf)) {
 		provider = strsep(&tech, ":");
 		if (!tech) {
 			return AST_DEVICE_INVALID;
 		}
 		/* We have a provider */
 		number = tech;
+		tech = NULL;
 
 		ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
 		return getproviderstate(provider, number);
@@ -367,21 +343,18 @@ static enum ast_device_state _ast_device_state(const char *device, int check_cac
 
 	ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
 
-	chan_tech = ast_get_channel_tech(tech);
-	if (!chan_tech) {
+	if (!(chan_tech = ast_get_channel_tech(tech)))
 		return AST_DEVICE_INVALID;
-	}
 
-	/* Does the channel driver support device state notification? */
-	if (!chan_tech->devicestate) {
-		/* No, try the generic function */
-		return ast_parse_device_state(device);
-	}
+	if (!(chan_tech->devicestate)) /* Does the channel driver support device state notification? */
+		return ast_parse_device_state(device); /* No, try the generic function */
 
 	res = chan_tech->devicestate(number);
-	if (res == AST_DEVICE_UNKNOWN) {
-		res = ast_parse_device_state(device);
-	}
+
+	if (res != AST_DEVICE_UNKNOWN)
+		return res;
+
+	res = ast_parse_device_state(device);
 
 	return res;
 }
@@ -397,6 +370,7 @@ enum ast_device_state ast_device_state(const char *device)
 /*! \brief Add device state provider */
 int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
 {
+	struct devstate_prov *devcb;
 	struct devstate_prov *devprov;
 
 	if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
@@ -406,6 +380,14 @@ int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
 	ast_copy_string(devprov->label, label, sizeof(devprov->label));
 
 	AST_RWLIST_WRLOCK(&devstate_provs);
+	AST_RWLIST_TRAVERSE(&devstate_provs, devcb, list) {
+		if (!strcasecmp(devcb->label, label)) {
+			ast_log(LOG_WARNING, "Device state provider '%s' already registered\n", label);
+			ast_free(devprov);
+			AST_RWLIST_UNLOCK(&devstate_provs);
+			return -1;
+		}
+	}
 	AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
 	AST_RWLIST_UNLOCK(&devstate_provs);
 
@@ -453,9 +435,39 @@ static int getproviderstate(const char *provider, const char *address)
 	return res;
 }
 
+static void devstate_event(const char *device, enum ast_device_state state, int cachable)
+{
+	struct ast_event *event;
+	enum ast_event_type event_type;
+
+	if (devstate_collector.enabled) {
+		/* Distributed device state is enabled, so this state change is a change
+		 * for a single server, not the real state. */
+		event_type = AST_EVENT_DEVICE_STATE_CHANGE;
+	} else {
+		event_type = AST_EVENT_DEVICE_STATE;
+	}
+
+	ast_debug(3, "device '%s' state '%u'\n", device, state);
+
+	if (!(event = ast_event_new(event_type,
+				    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+				    AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+				    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
+				    AST_EVENT_IE_END))) {
+		return;
+	}
+
+	if (cachable) {
+		ast_event_queue_and_cache(event);
+	} else {
+		ast_event_queue(event);
+	}
+}
+
 /*! Called by the state change thread to find out what the state is, and then
  *  to queue up the state change event */
-static void do_state_change(const char *device, enum ast_devstate_cache cachable)
+static void do_state_change(const char *device, int cachable)
 {
 	enum ast_device_state state;
 
@@ -463,7 +475,7 @@ static void do_state_change(const char *device, enum ast_devstate_cache cachable
 
 	ast_debug(3, "Changing state for %s - state %u (%s)\n", device, state, ast_devstate2str(state));
 
-	ast_publish_device_state(device, state, cachable);
+	devstate_event(device, state, cachable);
 }
 
 int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
@@ -487,7 +499,7 @@ int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_
 	 */
 
 	if (state != AST_DEVICE_UNKNOWN) {
-		ast_publish_device_state(device, state, cachable);
+		devstate_event(device, state, cachable);
 	} else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
 		/* we could not allocate a change struct, or */
 		/* there is no background thread, so process the change now */
@@ -559,62 +571,185 @@ static void *do_devstate_changes(void *data)
 	return NULL;
 }
 
-static struct ast_device_state_message *device_state_alloc(const char *device, enum ast_device_state state, enum ast_devstate_cache cachable, const struct ast_eid *eid)
+static void destroy_devstate_change(struct devstate_change *sc)
 {
-	struct ast_device_state_message *new_device_state;
-	char *pos;
-	size_t stuff_len;
+	ast_free(sc);
+}
 
-	ast_assert(!ast_strlen_zero(device));
+#define MAX_SERVERS 64
+struct change_collection {
+	struct devstate_change states[MAX_SERVERS];
+	size_t num_states;
+};
 
-	stuff_len = strlen(device) + 1;
-	if (eid) {
-		stuff_len += sizeof(*eid);
+static void devstate_cache_cb(const struct ast_event *event, void *data)
+{
+	struct change_collection *collection = data;
+	int i;
+	const struct ast_eid *eid;
+
+	if (collection->num_states == ARRAY_LEN(collection->states)) {
+		ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
+			MAX_SERVERS);
+		return;
 	}
-	new_device_state = ao2_alloc_options(sizeof(*new_device_state) + stuff_len, NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!new_device_state) {
-		return NULL;
+
+	if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
+		ast_log(LOG_ERROR, "Device state change event with no EID\n");
+		return;
 	}
 
-	if (eid) {
-		/* non-aggregate device state. */
-		new_device_state->stuff[0] = *eid;
-		new_device_state->eid = &new_device_state->stuff[0];
-		pos = (char *) &new_device_state->stuff[1];
-	} else {
-		pos = (char *) &new_device_state->stuff[0];
+	i = collection->num_states;
+
+	collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+	collection->states[i].eid = *eid;
+
+	collection->num_states++;
+}
+
+static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
+{
+	int i;
+	struct ast_devstate_aggregate agg;
+	enum ast_device_state state;
+	struct ast_event *event;
+
+	ast_devstate_aggregate_init(&agg);
+
+	for (i = 0; i < collection->num_states; i++) {
+		ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
+			ast_devstate2str(collection->states[i].state), device);
+		ast_devstate_aggregate_add(&agg, collection->states[i].state);
+	}
+
+	state = ast_devstate_aggregate_result(&agg);
+
+	ast_debug(1, "Aggregate devstate result is '%s' for '%s'\n",
+		ast_devstate2str(state), device);
+
+	event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+		AST_EVENT_IE_END);
+
+	if (event) {
+		enum ast_device_state old_state;
+
+		old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+		ast_event_destroy(event);
+
+		if (state == old_state) {
+			/* No change since last reported device state */
+			ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
+				device, ast_devstate2str(state));
+			return;
+		}
 	}
 
-	strcpy(pos, device);/* Safe */
-	new_device_state->device = pos;
+	ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
+		device, ast_devstate2str(state));
 
-	new_device_state->state = state;
-	new_device_state->cachable = cachable;
+	event = ast_event_new(AST_EVENT_DEVICE_STATE,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+		AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+		AST_EVENT_IE_END);
+
+	if (!event) {
+		return;
+	}
 
-	return new_device_state;
+	if (cachable) {
+		ast_event_queue_and_cache(event);
+	} else {
+		ast_event_queue(event);
+	}
 }
 
-static void devstate_change_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
+static void handle_devstate_change(struct devstate_change *sc)
 {
-	struct ast_device_state_message *device_state;
+	struct ast_event_sub *tmp_sub;
+	struct change_collection collection = {
+		.num_states = 0,
+	};
+
+	ast_debug(1, "Processing device state change for '%s'\n", sc->device);
 
-	if (ast_device_state_message_type() != stasis_message_type(msg)) {
+	if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
+		ast_log(LOG_ERROR, "Failed to create subscription\n");
 		return;
 	}
 
-	device_state = stasis_message_data(msg);
-	if (device_state->cachable == AST_DEVSTATE_CACHABLE || !device_state->eid) {
-		/* Ignore cacheable and aggregate messages. */
+	if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
+		ast_log(LOG_ERROR, "Failed to append device IE\n");
+		ast_event_sub_destroy(tmp_sub);
 		return;
 	}
 
-	/*
-	 * Non-cacheable device state aggregates are just the
-	 * device state republished as the aggregate.
+	/* Populate the collection of device states from the cache */
+	ast_event_dump_cache(tmp_sub);
+
+	process_collection(sc->device, sc->cachable, &collection);
+
+	ast_event_sub_destroy(tmp_sub);
+}
+
+static void *run_devstate_collector(void *data)
+{
+	for (;;) {
+		struct devstate_change *sc;
+
+		ast_mutex_lock(&devstate_collector.lock);
+		while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
+			ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
+		ast_mutex_unlock(&devstate_collector.lock);
+
+		handle_devstate_change(sc);
+
+		destroy_devstate_change(sc);
+	}
+
+	return NULL;
+}
+
+static void devstate_change_collector_cb(const struct ast_event *event, void *data)
+{
+	struct devstate_change *sc;
+	const char *device, *cachable_str;
+	const struct ast_eid *eid;
+	uint32_t state;
+	enum ast_devstate_cache cachable = AST_DEVSTATE_CACHABLE;
+
+	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+	eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
+	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+	if (ast_strlen_zero(device) || !eid) {
+		ast_log(LOG_ERROR, "Invalid device state change event received\n");
+		return;
+	}
+
+	if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
+		return;
+
+	strcpy(sc->device, device);
+	sc->eid = *eid;
+	sc->state = state;
+
+	/* For 'cachable' we cannot use ast_event_get_ie_uint(), it overwrites the default of AST_DEVSTATE_CACHABLE we
+	 * have already setup for 'cachable', if for whatever reason the AST_EVENT_IE_CACHABLE wasn't
+	 * posted in the event ast_event_get_ie_uint() is going will return 0,
+	 * which equates to AST_DEVSTATE_NOT_CACHABLE the first enumeration in 'ast_devstate_cache'.
 	 */
-	ast_publish_device_state_full(device_state->device, device_state->state,
-		device_state->cachable, NULL);
+
+	if ((cachable_str = ast_event_get_ie_str(event, AST_EVENT_IE_CACHABLE))) {
+		sscanf(cachable_str, "%30u", &cachable);
+	}
+	sc->cachable = cachable;
+
+	ast_mutex_lock(&devstate_collector.lock);
+	AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
+	ast_cond_signal(&devstate_collector.cond);
+	ast_mutex_unlock(&devstate_collector.lock);
 }
 
 /*! \brief Initialize the device state engine in separate thread */
@@ -667,304 +802,28 @@ enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregat
 	return agg->state;
 }
 
-struct stasis_topic *ast_device_state_topic_all(void)
-{
-	return device_state_topic_all;
-}
-
-struct stasis_cache *ast_device_state_cache(void)
+int ast_enable_distributed_devstate(void)
 {
-	return device_state_cache;
-}
-
-struct stasis_topic *ast_device_state_topic_cached(void)
-{
-	return stasis_caching_get_topic(device_state_topic_cached);
-}
-
-struct stasis_topic *ast_device_state_topic(const char *device)
-{
-	return stasis_topic_pool_get_topic(device_state_topic_pool, device);
-}
-
-int ast_device_state_clear_cache(const char *device)
-{
-	struct stasis_message *cached_msg;
-	struct stasis_message *msg;
-
-	cached_msg = stasis_cache_get_by_eid(ast_device_state_cache(),
-		ast_device_state_message_type(), device, &ast_eid_default);
-	if (!cached_msg) {
-		/* nothing to clear */
-		return -1;
+	if (devstate_collector.enabled) {
+		return 0;
 	}
 
-	msg = stasis_cache_clear_create(cached_msg);
-	if (msg) {
-		stasis_publish(ast_device_state_topic(device), msg);
-	}
-	ao2_cleanup(msg);
-	ao2_cleanup(cached_msg);
-	return 0;
-}
-
-int ast_publish_device_state_full(
-	const char *device,
-	enum ast_device_state state,
-	enum ast_devstate_cache cachable,
-	struct ast_eid *eid)
-{
-	RAII_VAR(struct ast_device_state_message *, device_state, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct stasis_topic *device_specific_topic;
-
-	ast_assert(!ast_strlen_zero(device));
+	devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
+		devstate_change_collector_cb, "devicestate_engine_enable_distributed", NULL, AST_EVENT_IE_END);
 
-	if (!ast_device_state_message_type()) {
+	if (!devstate_collector.event_sub) {
+		ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
 		return -1;
 	}
 
-	device_state = device_state_alloc(device, state, cachable, eid);
-	if (!device_state) {
+	ast_mutex_init(&devstate_collector.lock);
+	ast_cond_init(&devstate_collector.cond, NULL);
+	if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
+		ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
 		return -1;
 	}
 
-	message = stasis_message_create_full(ast_device_state_message_type(), device_state,
-		eid);
-	if (!message) {
-		return -1;
-	}
-
-	device_specific_topic = ast_device_state_topic(device);
-	if (!device_specific_topic) {
-		return -1;
-	}
+	devstate_collector.enabled = 1;
 
-	stasis_publish(device_specific_topic, message);
 	return 0;
 }
-
-static const char *device_state_get_id(struct stasis_message *message)
-{
-	struct ast_device_state_message *device_state;
-
-	if (ast_device_state_message_type() != stasis_message_type(message)) {
-		return NULL;
-	}
-
-	device_state = stasis_message_data(message);
-	if (device_state->cachable == AST_DEVSTATE_NOT_CACHABLE) {
-		return NULL;
-	}
-
-	return device_state->device;
-}
-
-/*!
- * \internal
- * \brief Callback to publish the aggregate device state cache entry message.
- * \since 12.2.0
- *
- * \param cache_topic Caching topic the aggregate message may be published over.
- * \param aggregate The aggregate shapshot message to publish.
- *
- * \return Nothing
- */
-static void device_state_aggregate_publish(struct stasis_topic *cache_topic, struct stasis_message *aggregate)
-{
-	const char *device;
-	struct stasis_topic *device_specific_topic;
-
-	device = device_state_get_id(aggregate);
-	if (!device) {
-		return;
-	}
-	device_specific_topic = ast_device_state_topic(device);
-	if (!device_specific_topic) {
-		return;
-	}
-
-	stasis_publish(device_specific_topic, aggregate);
-}
-
-/*!
- * \internal
- * \brief Callback to calculate the aggregate device state cache entry.
- * \since 12.2.0
- *
- * \param entry Cache entry to calculate a new aggregate snapshot.
- * \param new_snapshot The shapshot that is being updated.
- *
- * \note Return a ref bumped pointer from stasis_cache_entry_get_aggregate()
- * if a new aggregate could not be calculated because of error.
- *
- * \return New aggregate-snapshot calculated on success.
- * Caller has a reference on return.
- */
-static struct stasis_message *device_state_aggregate_calc(struct stasis_cache_entry *entry, struct stasis_message *new_snapshot)
-{
-	struct stasis_message *aggregate_snapshot;
-	struct stasis_message *snapshot;
-	struct ast_device_state_message *device_state;
-	const char *device = NULL;
-	struct ast_devstate_aggregate aggregate;
-	int idx;
-
-	if (!ast_device_state_message_type()) {
-		return NULL;
-	}
-
-	/* Determine the new aggregate device state. */
-	ast_devstate_aggregate_init(&aggregate);
-	snapshot = stasis_cache_entry_get_local(entry);
-	if (snapshot) {
-		device_state = stasis_message_data(snapshot);
-		device = device_state->device;
-		ast_devstate_aggregate_add(&aggregate, device_state->state);
-	}
-	for (idx = 0; ; ++idx) {
-		snapshot = stasis_cache_entry_get_remote(entry, idx);
-		if (!snapshot) {
-			break;
-		}
-
-		device_state = stasis_message_data(snapshot);
-		device = device_state->device;
-		ast_devstate_aggregate_add(&aggregate, device_state->state);
-	}
-
-	if (!device) {
-		/* There are no device states cached.  Delete the aggregate. */
-		return NULL;
-	}
-
-	snapshot = stasis_cache_entry_get_aggregate(entry);
-	if (snapshot) {
-		device_state = stasis_message_data(snapshot);
-		if (device_state->state == ast_devstate_aggregate_result(&aggregate)) {
-			/* Aggregate device state did not change. */
-			return ao2_bump(snapshot);
-		}
-	}
-
-	device_state = device_state_alloc(device, ast_devstate_aggregate_result(&aggregate),
-		AST_DEVSTATE_CACHABLE, NULL);
-	if (!device_state) {
-		/* Bummer.  We have to keep the old aggregate snapshot. */
-		return ao2_bump(snapshot);
-	}
-	aggregate_snapshot = stasis_message_create_full(ast_device_state_message_type(),
-		device_state, NULL);
-	ao2_cleanup(device_state);
-	if (!aggregate_snapshot) {
-		/* Bummer.  We have to keep the old aggregate snapshot. */
-		return ao2_bump(snapshot);
-	}
-
-	return aggregate_snapshot;
-}
-
-static void devstate_cleanup(void)
-{
-	devstate_message_sub = stasis_unsubscribe_and_join(devstate_message_sub);
-	device_state_topic_cached = stasis_caching_unsubscribe_and_join(device_state_topic_cached);
-
-	ao2_cleanup(device_state_cache);
-	device_state_cache = NULL;
-
-	ao2_cleanup(device_state_topic_pool);
-	device_state_topic_pool = NULL;
-
-	ao2_cleanup(device_state_topic_all);
-	device_state_topic_all = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_device_state_message_type);
-}
-
-int devstate_init(void)
-{
-	ast_register_cleanup(devstate_cleanup);
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_device_state_message_type) != 0) {
-		return -1;
-	}
-	device_state_topic_all = stasis_topic_create("ast_device_state_topic");
-	if (!device_state_topic_all) {
-		devstate_cleanup();
-		return -1;
-	}
-	device_state_topic_pool = stasis_topic_pool_create(ast_device_state_topic_all());
-	if (!device_state_topic_pool) {
-		devstate_cleanup();
-		return -1;
-	}
-	device_state_cache = stasis_cache_create_full(device_state_get_id,
-		device_state_aggregate_calc, device_state_aggregate_publish);
-	if (!device_state_cache) {
-		devstate_cleanup();
-		return -1;
-	}
-	device_state_topic_cached = stasis_caching_topic_create(ast_device_state_topic_all(),
-		device_state_cache);
-	if (!device_state_topic_cached) {
-		devstate_cleanup();
-		return -1;
-	}
-
-	devstate_message_sub = stasis_subscribe(ast_device_state_topic_all(),
-		devstate_change_cb, NULL);
-	if (!devstate_message_sub) {
-		ast_log(LOG_ERROR, "Failed to create subscription creating uncached device state aggregate events.\n");
-		devstate_cleanup();
-		return -1;
-	}
-
-	return 0;
-}
-
-static struct ast_manager_event_blob *devstate_to_ami(struct stasis_message *msg)
-{
-	struct ast_device_state_message *dev_state;
-
-	dev_state = stasis_message_data(msg);
-
-	/* Ignore non-aggregate states */
-	if (dev_state->eid) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DeviceStateChange",
-		"Device: %s\r\n"
-		"State: %s\r\n",
-		dev_state->device, ast_devstate_str(dev_state->state));
-}
-
-/*! \brief Convert a \ref stasis_message to a \ref ast_event */
-static struct ast_event *devstate_to_event(struct stasis_message *message)
-{
-	struct ast_event *event;
-	struct ast_device_state_message *device_state;
-
-	if (!message) {
-		return NULL;
-	}
-
-	device_state = stasis_message_data(message);
-
-	if (device_state->eid) {
-		event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
-					    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device_state->device,
-					    AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, device_state->state,
-					    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, device_state->cachable,
-					    AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, device_state->eid, sizeof(*device_state->eid),
-					    AST_EVENT_IE_END);
-	} else {
-		event = ast_event_new(AST_EVENT_DEVICE_STATE,
-					    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device_state->device,
-					    AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, device_state->state,
-					    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, device_state->cachable,
-					    AST_EVENT_IE_END);
-	}
-
-	return event;
-}
diff --git a/main/dial.c b/main/dial.c
index d867ea8..52a2709 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422684 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -42,8 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422684 $")
 #include "asterisk/pbx.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
-#include "asterisk/causes.h"
-#include "asterisk/stasis_channels.h"
 
 /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
 struct ast_dial {
@@ -69,8 +67,6 @@ struct ast_dial_channel {
 	void *options[AST_DIAL_OPTION_MAX];	/*!< Channel specific options */
 	int cause;				/*!< Cause code in case of failure */
 	unsigned int is_running_app:1;		/*!< Is this running an application? */
-	char *assignedid1;				/*!< UniqueID to assign channel */
-	char *assignedid2;				/*!< UniqueID to assign 2nd channel */
 	struct ast_channel *owner;		/*!< Asterisk channel */
 	AST_LIST_ENTRY(ast_dial_channel) list;	/*!< Linked list information */
 };
@@ -147,22 +143,6 @@ static int music_disable(void *data)
 	return 0;
 }
 
-static void *predial_enable(void *data)
-{
-	return ast_strdup(data);
-}
-
-static int predial_disable(void *data)
-{
-	if (!data) {
-		return -1;
-	}
-
-	ast_free(data);
-
-	return 0;
-}
-
 /*! \brief Application execution function for 'ANSWER_EXEC' option */
 static void answer_exec_run(struct ast_dial *dial, struct ast_dial_channel *dial_channel, char *app, char *args)
 {
@@ -204,8 +184,6 @@ static const struct ast_option_types option_types[] = {
 	{ AST_DIAL_OPTION_ANSWER_EXEC, answer_exec_enable, answer_exec_disable }, /*!< Execute application upon answer in async mode */
 	{ AST_DIAL_OPTION_MUSIC, music_enable, music_disable },                   /*!< Play music to the caller instead of ringing */
 	{ AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, NULL, NULL },                  /*!< Disable call forwarding on channels */
-	{ AST_DIAL_OPTION_PREDIAL, predial_enable, predial_disable },             /*!< Execute a subroutine on the outbound channels prior to dialing */
-	{ AST_DIAL_OPTION_DIAL_REPLACES_SELF, NULL, NULL },                       /*!< The dial operation is a replacement for the requester */
 	{ AST_DIAL_OPTION_MAX, NULL, NULL },                                      /*!< Terminator of list */
 };
 
@@ -250,7 +228,7 @@ struct ast_dial *ast_dial_create(void)
  * \note Appends a channel to a dialing structure
  * \return Returns channel reference number on success, -1 on failure
  */
-int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
+int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device)
 {
 	struct ast_dial_channel *channel = NULL;
 
@@ -266,15 +244,6 @@ int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device,
 	channel->tech = ast_strdup(tech);
 	channel->device = ast_strdup(device);
 
-	/* Store the assigned id */
-	if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
-		channel->assignedid1 = ast_strdup(assignedids->uniqueid);
-
-		if (!ast_strlen_zero(assignedids->uniqueid2)) {
-			channel->assignedid2 = ast_strdup(assignedids->uniqueid2);
-		}
-	}
-
 	/* Grab reference number from dial structure */
 	channel->num = ast_atomic_fetchadd_int(&dial->num, +1);
 
@@ -287,49 +256,35 @@ int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device,
 	return channel->num;
 }
 
-/*! \brief Helper function that requests all channels */
-static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channel *chan, struct ast_format_cap *cap, const char *predial_string)
+/*! \brief Helper function that does the beginning dialing per-appended channel */
+static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan)
 {
 	char numsubst[AST_MAX_EXTENSION];
+	int res = 1;
 	struct ast_format_cap *cap_all_audio = NULL;
 	struct ast_format_cap *cap_request;
-	struct ast_assigned_ids assignedids = {
-		.uniqueid = channel->assignedid1,
-		.uniqueid2 = channel->assignedid2,
-	};
 
 	/* Copy device string over */
 	ast_copy_string(numsubst, channel->device, sizeof(numsubst));
 
-	if (cap && ast_format_cap_count(cap)) {
-		cap_request = cap;
-	} else if (chan) {
+	if (chan) {
 		cap_request = ast_channel_nativeformats(chan);
 	} else {
-		cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		ast_format_cap_append_by_type(cap_all_audio, AST_MEDIA_TYPE_AUDIO);
+		cap_all_audio = ast_format_cap_alloc_nolock();
+		ast_format_cap_add_all_by_type(cap_all_audio, AST_FORMAT_TYPE_AUDIO);
 		cap_request = cap_all_audio;
 	}
 
 	/* If we fail to create our owner channel bail out */
-	if (!(channel->owner = ast_request(channel->tech, cap_request, &assignedids, chan, numsubst, &channel->cause))) {
-		ao2_cleanup(cap_all_audio);
+	if (!(channel->owner = ast_request(channel->tech, cap_request, chan, numsubst, &channel->cause))) {
+		cap_all_audio = ast_format_cap_destroy(cap_all_audio);
 		return -1;
 	}
 	cap_request = NULL;
-	ao2_cleanup(cap_all_audio);
-
-	if (chan) {
-		ast_channel_lock_both(chan, channel->owner);
-	} else {
-		ast_channel_lock(channel->owner);
-	}
-
-	ast_channel_stage_snapshot(channel->owner);
+	cap_all_audio = ast_format_cap_destroy(cap_all_audio);
 
 	ast_channel_appl_set(channel->owner, "AppDial2");
 	ast_channel_data_set(channel->owner, "(Outgoing Line)");
-
 	memset(ast_channel_whentohangup(channel->owner), 0, sizeof(*ast_channel_whentohangup(channel->owner)));
 
 	/* Inherit everything from he who spawned this dial */
@@ -345,81 +300,22 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 		ast_connected_line_copy_from_caller(ast_channel_connected(channel->owner), ast_channel_caller(chan));
 
 		ast_channel_language_set(channel->owner, ast_channel_language(chan));
-		if (channel->options[AST_DIAL_OPTION_DIAL_REPLACES_SELF]) {
-			ast_channel_req_accountcodes(channel->owner, chan, AST_CHANNEL_REQUESTOR_REPLACEMENT);
-		} else {
-			ast_channel_req_accountcodes(channel->owner, chan, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
-		}
+		ast_channel_accountcode_set(channel->owner, ast_channel_accountcode(chan));
 		if (ast_strlen_zero(ast_channel_musicclass(channel->owner)))
 			ast_channel_musicclass_set(channel->owner, ast_channel_musicclass(chan));
 
 		ast_channel_adsicpe_set(channel->owner, ast_channel_adsicpe(chan));
 		ast_channel_transfercapability_set(channel->owner, ast_channel_transfercapability(chan));
-		ast_channel_unlock(chan);
-	}
-
-	ast_channel_stage_snapshot_done(channel->owner);
-	ast_channel_unlock(channel->owner);
-
-	if (!ast_strlen_zero(predial_string)) {
-		const char *predial_callee = ast_app_expand_sub_args(chan, predial_string);
-		if (!predial_callee) {
-			ast_log(LOG_ERROR, "Could not expand subroutine arguments in predial request '%s'\n", predial_string);
-		}
-		ast_autoservice_start(chan);
-		ast_pre_call(channel->owner, predial_callee);
-		ast_autoservice_stop(chan);
-		ast_free((char *) predial_callee);
-	}
-
-	return 0;
-}
-
-int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_format_cap *cap)
-{
-	struct ast_dial_channel *channel;
-	int res = -1;
-	char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL];
-
-	if (!ast_strlen_zero(predial_string)) {
-		ast_replace_subargument_delimiter(predial_string);
-	}
-
-	AST_LIST_LOCK(&dial->channels);
-	AST_LIST_TRAVERSE(&dial->channels, channel, list) {
-		if ((res = begin_dial_prerun(channel, chan, cap, predial_string))) {
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&dial->channels);
-
-	return res;
-}
-
-/*! \brief Helper function that does the beginning dialing per-appended channel */
-static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan, int async, const char *predial_string)
-{
-	char numsubst[AST_MAX_EXTENSION];
-	int res = 1;
-
-	/* If no owner channel exists yet execute pre-run */
-	if (!channel->owner && begin_dial_prerun(channel, chan, NULL, predial_string)) {
-		return 0;
 	}
 
-	/* Copy device string over */
-	ast_copy_string(numsubst, channel->device, sizeof(numsubst));
-
 	/* Attempt to actually call this device */
 	if ((res = ast_call(channel->owner, numsubst, 0))) {
 		res = 0;
 		ast_hangup(channel->owner);
 		channel->owner = NULL;
 	} else {
-		if (chan) {
+		if (chan)
 			ast_poll_channel_add(chan, channel->owner);
-		}
-		ast_channel_publish_dial(async ? NULL : chan, channel->owner, channel->device, NULL);
 		res = 1;
 		ast_verb(3, "Called %s\n", numsubst);
 	}
@@ -428,20 +324,15 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
 }
 
 /*! \brief Helper function that does the beginning dialing per dial structure */
-static int begin_dial(struct ast_dial *dial, struct ast_channel *chan, int async)
+static int begin_dial(struct ast_dial *dial, struct ast_channel *chan)
 {
 	struct ast_dial_channel *channel = NULL;
 	int success = 0;
-	char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL];
-
-	if (!ast_strlen_zero(predial_string)) {
-		ast_replace_subargument_delimiter(predial_string);
-	}
 
 	/* Iterate through channel list, requesting and calling each one */
 	AST_LIST_LOCK(&dial->channels);
 	AST_LIST_TRAVERSE(&dial->channels, channel, list) {
-		success += begin_dial_channel(channel, chan, async, predial_string);
+		success += begin_dial_channel(channel, chan);
 	}
 	AST_LIST_UNLOCK(&dial->channels);
 
@@ -455,11 +346,6 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c
 	struct ast_channel *original = channel->owner;
 	char *tmp = ast_strdupa(ast_channel_call_forward(channel->owner));
 	char *tech = "Local", *device = tmp, *stuff;
-	char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL];
-
-	if (!ast_strlen_zero(predial_string)) {
-		ast_replace_subargument_delimiter(predial_string);
-	}
 
 	/* If call forwarding is disabled just drop the original channel and don't attempt to dial the new one */
 	if (FIND_RELATIVE_OPTION(dial, channel, AST_DIAL_OPTION_DISABLE_CALL_FORWARDING)) {
@@ -473,39 +359,21 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c
 		*stuff++ = '\0';
 		tech = tmp;
 		device = stuff;
-	} else {
-		const char *forward_context;
-		char destination[AST_MAX_CONTEXT + AST_MAX_EXTENSION + 1];
-
-		ast_channel_lock(original);
-		forward_context = pbx_builtin_getvar_helper(original, "FORWARD_CONTEXT");
-		snprintf(destination, sizeof(destination), "%s@%s", tmp, S_OR(forward_context, ast_channel_context(original)));
-		ast_channel_unlock(original);
-		device = ast_strdupa(destination);
 	}
 
 	/* Drop old destination information */
 	ast_free(channel->tech);
 	ast_free(channel->device);
-	ast_free(channel->assignedid1);
-	channel->assignedid1 = NULL;
-	ast_free(channel->assignedid2);
-	channel->assignedid2 = NULL;
 
 	/* Update the dial channel with the new destination information */
 	channel->tech = ast_strdup(tech);
 	channel->device = ast_strdup(device);
 	AST_LIST_UNLOCK(&dial->channels);
 
-	/* Drop the original channel */
-	channel->owner = NULL;
-
 	/* Finally give it a go... send it out into the world */
-	begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string);
-
-	ast_channel_publish_dial_forward(chan, original, channel->owner, NULL, "CANCEL",
-		ast_channel_call_forward(original));
+	begin_dial_channel(channel, chan);
 
+	/* Drop the original channel */
 	ast_hangup(original);
 
 	return 0;
@@ -545,21 +413,16 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
 			AST_LIST_REMOVE(&dial->channels, channel, list);
 			AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
 			AST_LIST_UNLOCK(&dial->channels);
-			ast_channel_publish_dial(chan, channel->owner, channel->device, "ANSWER");
 			set_state(dial, AST_DIAL_RESULT_ANSWERED);
 			break;
 		case AST_CONTROL_BUSY:
 			ast_verb(3, "%s is busy\n", ast_channel_name(channel->owner));
-			ast_channel_publish_dial(chan, channel->owner, channel->device, "BUSY");
 			ast_hangup(channel->owner);
-			channel->cause = AST_CAUSE_USER_BUSY;
 			channel->owner = NULL;
 			break;
 		case AST_CONTROL_CONGESTION:
 			ast_verb(3, "%s is circuit-busy\n", ast_channel_name(channel->owner));
-			ast_channel_publish_dial(chan, channel->owner, channel->device, "CONGESTION");
 			ast_hangup(channel->owner);
-			channel->cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 			channel->owner = NULL;
 			break;
 		case AST_CONTROL_INCOMPLETE:
@@ -606,7 +469,7 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
 			break;
 		case AST_CONTROL_HOLD:
 			ast_verb(3, "Call on %s placed on hold\n", ast_channel_name(chan));
-			ast_indicate_data(chan, AST_CONTROL_HOLD, fr->data.ptr, fr->datalen);
+			ast_indicate(chan, AST_CONTROL_HOLD);
 			break;
 		case AST_CONTROL_UNHOLD:
 			ast_verb(3, "Call on %s left from hold\n", ast_channel_name(chan));
@@ -626,6 +489,8 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
 			break;
 		}
 	}
+
+	return;
 }
 
 /*! \brief Helper function that handles control frames WITHOUT owner */
@@ -642,32 +507,16 @@ static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channe
 		AST_LIST_REMOVE(&dial->channels, channel, list);
 		AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
 		AST_LIST_UNLOCK(&dial->channels);
-		ast_channel_publish_dial(NULL, channel->owner, channel->device, "ANSWER");
 		set_state(dial, AST_DIAL_RESULT_ANSWERED);
 		break;
 	case AST_CONTROL_BUSY:
 		ast_verb(3, "%s is busy\n", ast_channel_name(channel->owner));
-		ast_channel_publish_dial(NULL, channel->owner, channel->device, "BUSY");
 		ast_hangup(channel->owner);
-		channel->cause = AST_CAUSE_USER_BUSY;
 		channel->owner = NULL;
 		break;
 	case AST_CONTROL_CONGESTION:
 		ast_verb(3, "%s is circuit-busy\n", ast_channel_name(channel->owner));
-		ast_channel_publish_dial(NULL, channel->owner, channel->device, "CONGESTION");
 		ast_hangup(channel->owner);
-		channel->cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
-		channel->owner = NULL;
-		break;
-	case AST_CONTROL_INCOMPLETE:
-		/*
-		 * Nothing to do but abort the call since we have no
-		 * controlling channel to ask for more digits.
-		 */
-		ast_verb(3, "%s dialed Incomplete extension %s\n",
-			ast_channel_name(channel->owner), ast_channel_exten(channel->owner));
-		ast_hangup(channel->owner);
-		channel->cause = AST_CAUSE_UNALLOCATED;
 		channel->owner = NULL;
 		break;
 	case AST_CONTROL_RINGING:
@@ -685,6 +534,8 @@ static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channe
 	default:
 		break;
 	}
+
+	return;
 }
 
 /*! \brief Helper function to handle when a timeout occurs on dialing attempt */
@@ -693,11 +544,6 @@ static int handle_timeout_trip(struct ast_dial *dial, struct timeval start)
 	struct ast_dial_channel *channel = NULL;
 	int diff = ast_tvdiff_ms(ast_tvnow(), start), lowest_timeout = -1, new_timeout = -1;
 
-	/* If there is no difference yet return the dial timeout so we can go again, we were likely interrupted */
-	if (!diff) {
-		return dial->timeout;
-	}
-
 	/* If the global dial timeout tripped switch the state to timeout so our channel loop will drop every channel */
 	if (diff >= dial->timeout) {
 		set_state(dial, AST_DIAL_RESULT_TIMEOUT);
@@ -708,7 +554,6 @@ static int handle_timeout_trip(struct ast_dial *dial, struct timeval start)
 	AST_LIST_TRAVERSE(&dial->channels, channel, list) {
 		if (dial->state == AST_DIAL_RESULT_TIMEOUT || diff >= channel->timeout) {
 			ast_hangup(channel->owner);
-			channel->cause = AST_CAUSE_NO_ANSWER;
 			channel->owner = NULL;
 		} else if ((lowest_timeout == -1) || (lowest_timeout > channel->timeout)) {
 			lowest_timeout = channel->timeout;
@@ -722,22 +567,6 @@ static int handle_timeout_trip(struct ast_dial *dial, struct timeval start)
 	return new_timeout;
 }
 
-const char *ast_hangup_cause_to_dial_status(int hangup_cause)
-{
-	switch(hangup_cause) {
-	case AST_CAUSE_BUSY:
-		return "BUSY";
-	case AST_CAUSE_CONGESTION:
-		return "CONGESTION";
-	case AST_CAUSE_NO_ROUTE_DESTINATION:
-	case AST_CAUSE_UNREGISTERED:
-		return "CHANUNAVAIL";
-	case AST_CAUSE_NO_ANSWER:
-	default:
-		return "NOANSWER";
-	}
-}
-
 /*! \brief Helper function that basically keeps tabs on dialing attempts */
 static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_channel *chan)
 {
@@ -802,7 +631,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 		/* Wait for frames from channels */
 		who = ast_waitfor_n(cs, pos, &timeout);
 
-		/* Check to see if our thread is being canceled */
+		/* Check to see if our thread is being cancelled */
 		if (dial->thread == AST_PTHREADT_STOP)
 			break;
 
@@ -831,7 +660,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 			}
 			if (chan)
 				ast_poll_channel_del(chan, channel->owner);
-			ast_channel_publish_dial(chan, who, channel->device, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(who)));
 			ast_hangup(who);
 			channel->owner = NULL;
 			continue;
@@ -856,9 +684,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 				continue;
 			if (chan)
 				ast_poll_channel_del(chan, channel->owner);
-			ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL");
 			ast_hangup(channel->owner);
-			channel->cause = AST_CAUSE_ANSWERED_ELSEWHERE;
 			channel->owner = NULL;
 		}
 		AST_LIST_UNLOCK(&dial->channels);
@@ -881,9 +707,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 				continue;
 			if (chan)
 				ast_poll_channel_del(chan, channel->owner);
-			ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL");
 			ast_hangup(channel->owner);
-			channel->cause = AST_CAUSE_NORMAL_CLEARING;
 			channel->owner = NULL;
 		}
 		AST_LIST_UNLOCK(&dial->channels);
@@ -915,7 +739,7 @@ enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *cha
 	enum ast_dial_result res = AST_DIAL_RESULT_TRYING;
 
 	/* Ensure required arguments are passed */
-	if (!dial) {
+	if (!dial || (!chan && !async)) {
 		ast_debug(1, "invalid #1\n");
 		return AST_DIAL_RESULT_INVALID;
 	}
@@ -927,7 +751,7 @@ enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *cha
 	}
 
 	/* Dial each requested channel */
-	if (!begin_dial(dial, chan, async))
+	if (!begin_dial(dial, chan))
 		return AST_DIAL_RESULT_FAILED;
 
 	/* If we are running async spawn a thread and send it away... otherwise block here */
@@ -1049,8 +873,10 @@ void ast_dial_hangup(struct ast_dial *dial)
 
 	AST_LIST_LOCK(&dial->channels);
 	AST_LIST_TRAVERSE(&dial->channels, channel, list) {
-		ast_hangup(channel->owner);
-		channel->owner = NULL;
+		if (channel->owner) {
+			ast_hangup(channel->owner);
+			channel->owner = NULL;
+		}
 	}
 	AST_LIST_UNLOCK(&dial->channels);
 
@@ -1081,17 +907,14 @@ int ast_dial_destroy(struct ast_dial *dial)
 				option_types[i].disable(channel->options[i]);
 			channel->options[i] = NULL;
 		}
-
 		/* Hang up channel if need be */
-		ast_hangup(channel->owner);
-		channel->owner = NULL;
-
+		if (channel->owner) {
+			ast_hangup(channel->owner);
+			channel->owner = NULL;
+		}
 		/* Free structure */
 		ast_free(channel->tech);
 		ast_free(channel->device);
-		ast_free(channel->assignedid1);
-		ast_free(channel->assignedid2);
-
 		AST_LIST_REMOVE_CURRENT(list);
 		ast_free(channel);
 	}
@@ -1247,28 +1070,6 @@ int ast_dial_option_disable(struct ast_dial *dial, int num, enum ast_dial_option
 	return 0;
 }
 
-int ast_dial_reason(struct ast_dial *dial, int num)
-{
-	struct ast_dial_channel *channel;
-
-	if (!dial || AST_LIST_EMPTY(&dial->channels) || !(channel = find_dial_channel(dial, num))) {
-		return -1;
-	}
-
-	return channel->cause;
-}
-
-struct ast_channel *ast_dial_get_channel(struct ast_dial *dial, int num)
-{
-	struct ast_dial_channel *channel;
-
-	if (!dial || AST_LIST_EMPTY(&dial->channels) || !(channel = find_dial_channel(dial, num))) {
-		return NULL;
-	}
-
-	return channel->owner;
-}
-
 void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
 {
 	dial->state_callback = callback;
diff --git a/main/dns.c b/main/dns.c
index 7092b40..c507d5a 100644
--- a/main/dns.c
+++ b/main/dns.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421678 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/network.h"
 #include <arpa/nameser.h>	/* res_* functions */
@@ -225,7 +225,11 @@ static int dns_parse_answer(void *context,
 		answer += sizeof(struct dn_answer);
 		len -= sizeof(struct dn_answer);
 		if (len < 0) {
-			ast_log(LOG_WARNING, "Length of DNS answer exceeds frame\n");
+			ast_log(LOG_WARNING, "Strange result size\n");
+			return -1;
+		}
+		if (len < 0) {
+			ast_log(LOG_WARNING, "Length exceeds frame\n");
 			return -1;
 		}
 
@@ -296,48 +300,3 @@ int ast_search_dns(void *context,
 
 	return ret;
 }
-
-struct ao2_container *ast_dns_get_nameservers(void)
-{
-#ifdef HAVE_RES_NINIT
-	struct __res_state dnsstate;
-#endif
-	struct __res_state *state;
-	struct ao2_container *nameservers;
-	int i;
-
-	nameservers = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 3);
-	if (!nameservers) {
-		return NULL;
-	}
-
-#ifdef HAVE_RES_NINIT
-	memset(&dnsstate, 0, sizeof(dnsstate));
-	res_ninit(&dnsstate);
-	state = &dnsstate;
-#else
-	ast_mutex_lock(&res_lock);
-	res_init();
-	state = &_res;
-#endif
-
-	for (i = 0; i < state->nscount; i++) {
-		ast_str_container_add(nameservers, ast_inet_ntoa(state->nsaddr_list[i].sin_addr));
-	}
-
-#ifdef HAVE_RES_NINIT
-#ifdef HAVE_RES_NDESTROY
-	res_ndestroy(&dnsstate);
-#else
-	res_nclose(&dnsstate);
-#endif
-#else
-#ifdef HAVE_RES_CLOSE
-	res_close();
-#endif
-	ast_mutex_unlock(&res_lock);
-#endif
-
-	return nameservers;
-}
-
diff --git a/main/dnsmgr.c b/main/dnsmgr.c
index 8404aae..352d638 100644
--- a/main/dnsmgr.c
+++ b/main/dnsmgr.c
@@ -28,24 +28,13 @@
  * thread is in the middle of updating it to the new address.
  */
 
-
-/*! \li \ref dnsmgr.c uses the configuration file \ref dnsmgr.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page dnsmgr.conf dnsmgr.conf
- * \verbinclude dnsmgr.conf.sample
- */
-
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389733 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include <regex.h>
@@ -438,7 +427,7 @@ int dnsmgr_init(void)
 	ast_cli_register(&cli_status);
 	ast_cli_register(&cli_refresh);
 
-	ast_register_atexit(dnsmgr_shutdown);
+	ast_register_cleanup(dnsmgr_shutdown);
 
 	return do_reload(1);
 }
@@ -514,6 +503,7 @@ static int do_reload(int loading)
 	}
 
 	ast_mutex_unlock(&refresh_lock);
+	manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
 
 	return 0;
 }
diff --git a/main/dsp.c b/main/dsp.c
index c2a9c9d..d9ce161 100644
--- a/main/dsp.c
+++ b/main/dsp.c
@@ -27,15 +27,6 @@
  * \author Steve Underwood <steveu at coppice.org>
  */
 
-/*! \li \ref dsp.c uses the configuration file \ref dsp.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page dsp.conf dsp.conf
- * \verbinclude dsp.conf.sample
- */
-
 /* Some routines from tone_detect.c by Steven Underwood as published under the zapata library */
 /*
 	tone_detect.c - General telephony tone detection, and specific
@@ -55,12 +46,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 #include "asterisk/channel.h"
 #include "asterisk/dsp.h"
 #include "asterisk/ulaw.h"
@@ -112,9 +102,11 @@ static struct progalias {
 	{ "uk", PROG_MODE_UK },
 };
 
+#define FREQ_ARRAY_SIZE 7
+
 static struct progress {
 	enum gsamp_size size;
-	int freqs[7];
+	int freqs[FREQ_ARRAY_SIZE];
 } modes[] = {
 	{ GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } },	/*!< North America */
 	{ GSAMP_SIZE_CR, { 425 } },					/*!< Costa Rica, Brazil */
@@ -135,7 +127,7 @@ enum busy_detect {
 	BUSY_PAT_PERCENT = 7,	/*!< The percentage difference between measured and actual pattern */
 	BUSY_THRESHOLD = 100,	/*!< Max number of ms difference between max and min times in busy */
 	BUSY_MIN = 75,		/*!< Busy must be at least 80 ms in half-cadence */
-	BUSY_MAX = 3100		/*!< Busy can't be longer than 3100 ms in half-cadence */
+	BUSY_MAX =3100		/*!< Busy can't be longer than 3100 ms in half-cadence */
 };
 
 /*! Remember last 15 units */
@@ -243,6 +235,7 @@ typedef struct {
 	int v3;
 	int chunky;
 	int fac;
+	int samples;
 } goertzel_state_t;
 
 typedef struct {
@@ -339,16 +332,6 @@ static inline void goertzel_sample(goertzel_state_t *s, short sample)
 	}
 }
 
-static inline void goertzel_update(goertzel_state_t *s, short *samps, int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++) {
-		goertzel_sample(s, samps[i]);
-	}
-}
-
-
 static inline float goertzel_result(goertzel_state_t *s)
 {
 	goertzel_result_t r;
@@ -358,10 +341,11 @@ static inline float goertzel_result(goertzel_state_t *s)
 	return (float)r.value * (float)(1 << r.power);
 }
 
-static inline void goertzel_init(goertzel_state_t *s, float freq, unsigned int sample_rate)
+static inline void goertzel_init(goertzel_state_t *s, float freq, int samples, unsigned int sample_rate)
 {
 	s->v2 = s->v3 = s->chunky = 0.0;
 	s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / sample_rate));
+	s->samples = samples;
 }
 
 static inline void goertzel_reset(goertzel_state_t *s)
@@ -399,7 +383,7 @@ struct ast_dsp {
 	struct ast_dsp_busy_pattern busy_cadence;
 	int historicnoise[DSP_HISTORY];
 	int historicsilence[DSP_HISTORY];
-	goertzel_state_t freqs[7];
+	goertzel_state_t freqs[FREQ_ARRAY_SIZE];
 	int freqcount;
 	int gsamps;
 	enum gsamp_size gsamp_size;
@@ -467,7 +451,7 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration,
 	   and thus no tone will be detected in them */
 	s->hits_required = (duration_samples - (s->block_size - 1)) / s->block_size;
 
-	goertzel_init(&s->tone, freq, sample_rate);
+	goertzel_init(&s->tone, freq, s->block_size, sample_rate);
 
 	s->samples_pending = s->block_size;
 	s->hit_count = 0;
@@ -501,30 +485,29 @@ static void ast_fax_detect_init(struct ast_dsp *s)
 
 }
 
-static void ast_dtmf_detect_init(dtmf_detect_state_t *s, unsigned int sample_rate)
+static void ast_dtmf_detect_init (dtmf_detect_state_t *s, unsigned int sample_rate)
 {
 	int i;
 
-	for (i = 0; i < 4; i++) {
-		goertzel_init(&s->row_out[i], dtmf_row[i], sample_rate);
-		goertzel_init(&s->col_out[i], dtmf_col[i], sample_rate);
-	}
 	s->lasthit = 0;
 	s->current_hit = 0;
-	s->energy = 0.0;
+	for (i = 0;  i < 4;  i++) {
+		goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE, sample_rate);
+		goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE, sample_rate);
+		s->energy = 0.0;
+	}
 	s->current_sample = 0;
 	s->hits = 0;
 	s->misses = 0;
 }
 
-static void ast_mf_detect_init(mf_detect_state_t *s, unsigned int sample_rate)
+static void ast_mf_detect_init (mf_detect_state_t *s, unsigned int sample_rate)
 {
 	int i;
-
-	for (i = 0; i < 6; i++) {
-		goertzel_init(&s->tone_out[i], mf_tones[i], sample_rate);
-	}
 	s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0;
+	for (i = 0;  i < 6;  i++) {
+		goertzel_init (&s->tone_out[i], mf_tones[i], MF_GSIZE, sample_rate);
+	}
 	s->current_sample = 0;
 	s->current_hit = 0;
 }
@@ -560,7 +543,7 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp
 		s->mute_samples -= mute.end;
 	}
 
-	for (start = 0; start < samples; start = end) {
+	for (start = 0;  start < samples;  start = end) {
 		/* Process in blocks. */
 		limit = samples - start;
 		if (limit > s->samples_pending) {
@@ -711,15 +694,15 @@ static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp
 		}
 		/* We are at the end of a DTMF detection block */
 		/* Find the peak row and the peak column */
-		row_energy[0] = goertzel_result(&s->td.dtmf.row_out[0]);
-		col_energy[0] = goertzel_result(&s->td.dtmf.col_out[0]);
+		row_energy[0] = goertzel_result (&s->td.dtmf.row_out[0]);
+		col_energy[0] = goertzel_result (&s->td.dtmf.col_out[0]);
 
-		for (best_row = best_col = 0, i = 1; i < 4; i++) {
-			row_energy[i] = goertzel_result(&s->td.dtmf.row_out[i]);
+		for (best_row = best_col = 0, i = 1;  i < 4;  i++) {
+			row_energy[i] = goertzel_result (&s->td.dtmf.row_out[i]);
 			if (row_energy[i] > row_energy[best_row]) {
 				best_row = i;
 			}
-			col_energy[i] = goertzel_result(&s->td.dtmf.col_out[i]);
+			col_energy[i] = goertzel_result (&s->td.dtmf.col_out[i]);
 			if (col_energy[i] > col_energy[best_col]) {
 				best_col = i;
 			}
@@ -731,7 +714,7 @@ static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp
 		    col_energy[best_col] < row_energy[best_row] * (relax ? relax_dtmf_reverse_twist : dtmf_reverse_twist) &&
 		    row_energy[best_row] < col_energy[best_col] * (relax ? relax_dtmf_normal_twist : dtmf_normal_twist)) {
 			/* Relative peak test */
-			for (i = 0; i < 4; i++) {
+			for (i = 0;  i < 4;  i++) {
 				if ((i != best_col &&
 				    col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
 				    (i != best_row
@@ -884,7 +867,7 @@ static int mf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[]
 	}
 
 	hit = 0;
-	for (sample = 0; sample < samples; sample = limit) {
+	for (sample = 0;  sample < samples;  sample = limit) {
 		/* 80 is optimised to meet the MF specs. */
 		/* XXX So then why is MF_GSIZE defined as 120? */
 		if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample)) {
@@ -894,7 +877,7 @@ static int mf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[]
 		}
 		/* The following unrolled loop takes only 35% (rough estimate) of the
 		   time of a rolled loop on the machine on which it was developed */
-		for (j = sample; j < limit; j++) {
+		for (j = sample;  j < limit;  j++) {
 			/* With GCC 2.95, the following unrolled code seems to take about 35%
 			   (rough estimate) as long as a neat little 0-3 loop */
 			samp = amp[j];
@@ -998,7 +981,7 @@ static int mf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[]
 		}
 
 		/* Reinitialise the detector for the next block */
-		for (i = 0; i < 6; i++) {
+		for (i = 0;  i < 6;  i++) {
 			goertzel_reset(&s->td.mf.tone_out[i]);
 		}
 		s->td.mf.current_sample = 0;
@@ -1040,12 +1023,13 @@ static inline int pair_there(float p1, float p2, float i1, float i2, float e)
 
 static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
 {
-	short samp;
 	int x;
 	int y;
 	int pass;
 	int newstate = DSP_TONE_STATE_SILENCE;
 	int res = 0;
+	int freqcount = dsp->freqcount > FREQ_ARRAY_SIZE ? FREQ_ARRAY_SIZE : dsp->freqcount;
+
 	while (len) {
 		/* Take the lesser of the number of samples we need and what we have */
 		pass = len;
@@ -1053,18 +1037,17 @@ static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
 			pass = dsp->gsamp_size - dsp->gsamps;
 		}
 		for (x = 0; x < pass; x++) {
-			samp = s[x];
-			dsp->genergy += (int32_t) samp * (int32_t) samp;
-			for (y = 0; y < dsp->freqcount; y++) {
-				goertzel_sample(&dsp->freqs[y], samp);
+			for (y = 0; y < freqcount; y++) {
+				goertzel_sample(&dsp->freqs[y], s[x]);
 			}
+			dsp->genergy += s[x] * s[x];
 		}
 		s += pass;
 		dsp->gsamps += pass;
 		len -= pass;
 		if (dsp->gsamps == dsp->gsamp_size) {
-			float hz[7];
-			for (y = 0; y < 7; y++) {
+			float hz[FREQ_ARRAY_SIZE];
+			for (y = 0; y < FREQ_ARRAY_SIZE; y++) {
 				hz[y] = goertzel_result(&dsp->freqs[y]);
 			}
 			switch (dsp->progmode) {
@@ -1184,7 +1167,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf)
 		ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n");
 		return 0;
 	}
-	if (!ast_format_cache_is_slinear(inf->subclass.format)) {
+	if (!ast_format_is_slinear(&inf->subclass.format)) {
 		ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n");
 		return 0;
 	}
@@ -1409,29 +1392,30 @@ static int ast_dsp_silence_noise_with_energy(struct ast_dsp *dsp, struct ast_fra
 		ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n");
 		return 0;
 	}
-
-	if (ast_format_cache_is_slinear(f->subclass.format)) {
-		s = f->data.ptr;
-		len = f->datalen/2;
-	} else {
+	if (!ast_format_is_slinear(&f->subclass.format)) {
 		odata = f->data.ptr;
 		len = f->datalen;
-		if (ast_format_cmp(f->subclass.format, ast_format_ulaw)) {
-			s = ast_alloca(len * 2);
-			for (x = 0; x < len; x++) {
-				s[x] = AST_MULAW(odata[x]);
-			}
-		} else if (ast_format_cmp(f->subclass.format, ast_format_alaw)) {
-			s = ast_alloca(len * 2);
-			for (x = 0; x < len; x++) {
-				s[x] = AST_ALAW(odata[x]);
-			}
-		} else {
-			ast_log(LOG_WARNING, "Can only calculate silence on signed-linear, alaw or ulaw frames :(\n");
+		switch (f->subclass.format.id) {
+			case AST_FORMAT_ULAW:
+				s = ast_alloca(len * 2);
+				for (x = 0;x < len; x++) {
+					s[x] = AST_MULAW(odata[x]);
+				}
+				break;
+			case AST_FORMAT_ALAW:
+				s = ast_alloca(len * 2);
+				for (x = 0;x < len; x++) {
+					s[x] = AST_ALAW(odata[x]);
+				}
+				break;
+			default:
+				ast_log(LOG_WARNING, "Can only calculate silence on signed-linear, alaw or ulaw frames :(\n");
 			return 0;
 		}
+	} else {
+		s = f->data.ptr;
+		len = f->datalen/2;
 	}
-
 	if (noise) {
 		return __ast_dsp_silence_noise(dsp, s, len, NULL, total, frames_energy);
 	} else {
@@ -1476,26 +1460,31 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
 	odata = af->data.ptr;
 	len = af->datalen;
 	/* Make sure we have short data */
-	if (ast_format_cache_is_slinear(af->subclass.format)) {
+	if (ast_format_is_slinear(&af->subclass.format)) {
 		shortdata = af->data.ptr;
 		len = af->datalen / 2;
-	} else if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
-		shortdata = ast_alloca(af->datalen * 2);
-		for (x = 0; x < len; x++) {
-			shortdata[x] = AST_MULAW(odata[x]);
-		}
-	} else if (ast_format_cmp(af->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
-		shortdata = ast_alloca(af->datalen * 2);
-		for (x = 0; x < len; x++) {
-			shortdata[x] = AST_ALAW(odata[x]);
-		}
 	} else {
-		/*Display warning only once. Otherwise you would get hundreds of warnings every second */
-		if (dsp->display_inband_dtmf_warning) {
-			ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_format_get_name(af->subclass.format));
+		switch (af->subclass.format.id) {
+		case AST_FORMAT_ULAW:
+		case AST_FORMAT_TESTLAW:
+			shortdata = ast_alloca(af->datalen * 2);
+			for (x = 0;x < len; x++) {
+				shortdata[x] = AST_MULAW(odata[x]);
+			}
+			break;
+		case AST_FORMAT_ALAW:
+			shortdata = ast_alloca(af->datalen * 2);
+			for (x = 0; x < len; x++) {
+				shortdata[x] = AST_ALAW(odata[x]);
+			}
+			break;
+		default:
+			/*Display warning only once. Otherwise you would get hundreds of warnings every second */
+			if (dsp->display_inband_dtmf_warning)
+				ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format));
+			dsp->display_inband_dtmf_warning = 0;
+			return af;
 		}
-		dsp->display_inband_dtmf_warning = 0;
-		return af;
 	}
 
 	/* Initially we do not want to mute anything */
@@ -1624,14 +1613,19 @@ done:
 		memset(shortdata + dsp->mute_data[x].start, 0, sizeof(int16_t) * (dsp->mute_data[x].end - dsp->mute_data[x].start));
 	}
 
-	if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	switch (af->subclass.format.id) {
+	case AST_FORMAT_ULAW:
 		for (x = 0; x < len; x++) {
 			odata[x] = AST_LIN2MU((unsigned short) shortdata[x]);
 		}
-	} else if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+		break;
+	case AST_FORMAT_ALAW:
 		for (x = 0; x < len; x++) {
 			odata[x] = AST_LIN2A((unsigned short) shortdata[x]);
 		}
+		/* fall through */
+	default:
+		break;
 	}
 
 	if (outf) {
@@ -1652,14 +1646,14 @@ static void ast_dsp_prog_reset(struct ast_dsp *dsp)
 
 	dsp->gsamp_size = modes[dsp->progmode].size;
 	dsp->gsamps = 0;
-	for (x = 0; x < ARRAY_LEN(modes[dsp->progmode].freqs); x++) {
+	for (x = 0; x < FREQ_ARRAY_SIZE; x++) {
 		if (modes[dsp->progmode].freqs[x]) {
-			goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->sample_rate);
+			goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size, dsp->sample_rate);
 			max = x + 1;
 		}
 	}
 	dsp->freqcount = max;
-	dsp->ringtimeout = 0;
+	dsp->ringtimeout= 0;
 }
 
 unsigned int ast_dsp_get_sample_rate(const struct ast_dsp *dsp)
@@ -1678,6 +1672,7 @@ static struct ast_dsp *__ast_dsp_new(unsigned int sample_rate)
 		dsp->digitmode = DSP_DIGITMODE_DTMF;
 		dsp->faxmode = DSP_FAXMODE_DETECT_CNG;
 		dsp->sample_rate = sample_rate;
+		dsp->freqcount = 0;
 		/* Initialize digit detector */
 		ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF, dsp->sample_rate);
 		dsp->display_inband_dtmf_warning = 1;
@@ -1742,21 +1737,19 @@ void ast_dsp_digitreset(struct ast_dsp *dsp)
 	if (dsp->digitmode & DSP_DIGITMODE_MF) {
 		mf_detect_state_t *s = &dsp->digit_state.td.mf;
 		/* Reinitialise the detector for the next block */
-		for (i = 0; i < 6; i++) {
+		for (i = 0;  i < 6;  i++) {
 			goertzel_reset(&s->tone_out[i]);
 		}
-		s->hits[4] = s->hits[3] = s->hits[2] = s->hits[1] = s->hits[0] = 0;
-		s->current_hit = 0;
+		s->hits[4] = s->hits[3] = s->hits[2] = s->hits[1] = s->hits[0] = s->current_hit = 0;
 		s->current_sample = 0;
 	} else {
 		dtmf_detect_state_t *s = &dsp->digit_state.td.dtmf;
 		/* Reinitialise the detector for the next block */
-		for (i = 0; i < 4; i++) {
+		for (i = 0;  i < 4;  i++) {
 			goertzel_reset(&s->row_out[i]);
 			goertzel_reset(&s->col_out[i]);
 		}
-		s->lasthit = 0;
-		s->current_hit = 0;
+		s->lasthit = s->current_hit = 0;
 		s->energy = 0.0;
 		s->current_sample = 0;
 		s->hits = 0;
@@ -1778,7 +1771,7 @@ void ast_dsp_reset(struct ast_dsp *dsp)
 	}
 	memset(dsp->historicsilence, 0, sizeof(dsp->historicsilence));
 	memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise));
-	dsp->ringtimeout = 0;
+	dsp->ringtimeout= 0;
 }
 
 int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
diff --git a/main/editline/.gitignore b/main/editline/.gitignore
new file mode 100644
index 0000000..d3bb06b
--- /dev/null
+++ b/main/editline/.gitignore
@@ -0,0 +1,13 @@
+*.o_a
+Makefile
+common.h
+config.cache
+config.h
+editline.c
+emacs.h
+fcns.c
+fcns.h
+help.c
+help.h
+makelist
+vi.h
diff --git a/main/editline/np/strlcat.c b/main/editline/np/strlcat.c
index 6c9f1e9..d9d0e72 100644
--- a/main/editline/np/strlcat.c
+++ b/main/editline/np/strlcat.c
@@ -26,14 +26,6 @@
  */
 
 #include "config.h"
-#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $";
-#endif /* LIBC_SCCS and not lint */
-#ifndef lint
-static const char rcsid[] =
-  "$FreeBSD: src/lib/libc/string/strlcat.c,v 1.2.4.2 2001/07/09 23:30:06 obrien Exp $";
-#endif
-
 #include <sys/types.h>
 #include <string.h>
 
diff --git a/main/editline/np/strlcpy.c b/main/editline/np/strlcpy.c
index 1f154bc..ecad62b 100644
--- a/main/editline/np/strlcpy.c
+++ b/main/editline/np/strlcpy.c
@@ -28,16 +28,6 @@
  */
 
 #include "config.h"
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
-#endif
-#endif /* LIBC_SCCS and not lint */
-#ifndef lint
-static const char rcsid[] =
-  "$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.2.4.1 2001/07/09 23:30:06 obrien Exp $";
-#endif
-
 #include <sys/types.h>
 #include <string.h>
 
diff --git a/main/endpoints.c b/main/endpoints.c
deleted file mode 100644
index 830bb5c..0000000
--- a/main/endpoints.c
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Asterisk endpoint API.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/_private.h"
-
-/*! Buckets for endpoint->channel mappings. Keep it prime! */
-#define ENDPOINT_CHANNEL_BUCKETS 127
-
-/*! Buckets for endpoint hash. Keep it prime! */
-#define ENDPOINT_BUCKETS 127
-
-/*! Buckets for technology endpoints. */
-#define TECH_ENDPOINT_BUCKETS 11
-
-static struct ao2_container *endpoints;
-
-static struct ao2_container *tech_endpoints;
-
-struct ast_endpoint {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(tech);	/*!< Technology (SIP, IAX2, etc.). */
-		AST_STRING_FIELD(resource);	/*!< Name, unique to the tech. */
-		AST_STRING_FIELD(id);	/*!< tech/resource id */
-		);
-	/*! Endpoint's current state */
-	enum ast_endpoint_state state;
-	/*!
-	 * \brief Max channels for this endpoint. -1 means unlimited or unknown.
-	 *
-	 * Note that this simply documents the limits of an endpoint, and does
-	 * nothing to try to enforce the limit.
-	 */
-	int max_channels;
-	/*! Topic for this endpoint's messages */
-	struct stasis_cp_single *topics;
-	/*! Router for handling this endpoint's messages */
-	struct stasis_message_router *router;
-	/*! ast_str_container of channels associated with this endpoint */
-	struct ao2_container *channel_ids;
-	/*! Forwarding subscription from an endpoint to its tech endpoint */
-	struct stasis_forward *tech_forward;
-};
-
-static int endpoint_hash(const void *obj, int flags)
-{
-	const struct ast_endpoint *endpoint;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_SEARCH_OBJECT:
-		endpoint = obj;
-		return ast_str_hash(endpoint->id);
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int endpoint_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_endpoint *left = obj;
-	const struct ast_endpoint *right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right->id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left->id, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left->id, right_key, strlen(right_key));
-		break;
-	default:
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-
-	return CMP_MATCH;
-}
-
-struct ast_endpoint *ast_endpoint_find_by_id(const char *id)
-{
-	struct ast_endpoint *endpoint = ao2_find(endpoints, id, OBJ_KEY);
-
-	if (!endpoint) {
-		endpoint = ao2_find(tech_endpoints, id, OBJ_KEY);
-	}
-
-	return endpoint;
-}
-
-struct stasis_topic *ast_endpoint_topic(struct ast_endpoint *endpoint)
-{
-	if (!endpoint) {
-		return ast_endpoint_topic_all();
-	}
-	return stasis_cp_single_topic(endpoint->topics);
-}
-
-struct stasis_topic *ast_endpoint_topic_cached(struct ast_endpoint *endpoint)
-{
-	if (!endpoint) {
-		return ast_endpoint_topic_all_cached();
-	}
-	return stasis_cp_single_topic_cached(endpoint->topics);
-}
-
-const char *ast_endpoint_state_to_string(enum ast_endpoint_state state)
-{
-	switch (state) {
-	case AST_ENDPOINT_UNKNOWN:
-		return "unknown";
-	case AST_ENDPOINT_OFFLINE:
-		return "offline";
-	case AST_ENDPOINT_ONLINE:
-		return "online";
-	}
-	return "?";
-}
-
-static void endpoint_publish_snapshot(struct ast_endpoint *endpoint)
-{
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	ast_assert(endpoint != NULL);
-	ast_assert(endpoint->topics != NULL);
-
-	if (!ast_endpoint_snapshot_type()) {
-		return;
-	}
-
-	snapshot = ast_endpoint_snapshot_create(endpoint);
-	if (!snapshot) {
-		return;
-	}
-	message = stasis_message_create(ast_endpoint_snapshot_type(), snapshot);
-	if (!message) {
-		return;
-	}
-	stasis_publish(ast_endpoint_topic(endpoint), message);
-}
-
-static void endpoint_dtor(void *obj)
-{
-	struct ast_endpoint *endpoint = obj;
-
-	/* The router should be shut down already */
-	ast_assert(stasis_message_router_is_done(endpoint->router));
-	ao2_cleanup(endpoint->router);
-	endpoint->router = NULL;
-
-	stasis_cp_single_unsubscribe(endpoint->topics);
-	endpoint->topics = NULL;
-
-	ao2_cleanup(endpoint->channel_ids);
-	endpoint->channel_ids = NULL;
-
-	ast_string_field_free_memory(endpoint);
-}
-
-
-int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
-	struct ast_channel *chan)
-{
-	ast_assert(chan != NULL);
-	ast_assert(endpoint != NULL);
-	ast_assert(!ast_strlen_zero(endpoint->resource));
-
-	ast_channel_forward_endpoint(chan, endpoint);
-
-	ao2_lock(endpoint);
-	ast_str_container_add(endpoint->channel_ids, ast_channel_uniqueid(chan));
-	ao2_unlock(endpoint);
-
-	endpoint_publish_snapshot(endpoint);
-
-	return 0;
-}
-
-/*! \brief Handler for channel snapshot cache clears */
-static void endpoint_cache_clear(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_endpoint *endpoint = data;
-	struct stasis_message *clear_msg = stasis_message_data(message);
-	struct ast_channel_snapshot *clear_snapshot;
-
-	if (stasis_message_type(clear_msg) != ast_channel_snapshot_type()) {
-		return;
-	}
-
-	clear_snapshot = stasis_message_data(clear_msg);
-
-	ast_assert(endpoint != NULL);
-
-	ao2_lock(endpoint);
-	ast_str_container_remove(endpoint->channel_ids, clear_snapshot->uniqueid);
-	ao2_unlock(endpoint);
-	endpoint_publish_snapshot(endpoint);
-}
-
-static void endpoint_default(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_endpoint *endpoint = data;
-
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_cleanup(endpoint);
-	}
-}
-
-static struct ast_endpoint *endpoint_internal_create(const char *tech, const char *resource)
-{
-	RAII_VAR(struct ast_endpoint *, endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_endpoint *, tech_endpoint, NULL, ao2_cleanup);
-	int r = 0;
-
-	/* Get/create the technology endpoint */
-	if (!ast_strlen_zero(resource)) {
-		tech_endpoint = ao2_find(tech_endpoints, tech, OBJ_KEY);
-		if (!tech_endpoint) {
-			tech_endpoint = endpoint_internal_create(tech, NULL);
-			if (!tech_endpoint) {
-				return NULL;
-			}
-		}
-	}
-
-	endpoint = ao2_alloc(sizeof(*endpoint), endpoint_dtor);
-	if (!endpoint) {
-		return NULL;
-	}
-
-	endpoint->max_channels = -1;
-	endpoint->state = AST_ENDPOINT_UNKNOWN;
-
-	if (ast_string_field_init(endpoint, 80) != 0) {
-		return NULL;
-	}
-	ast_string_field_set(endpoint, tech, tech);
-	ast_string_field_set(endpoint, resource, S_OR(resource, ""));
-	ast_string_field_build(endpoint, id, "%s%s%s",
-		tech,
-		!ast_strlen_zero(resource) ? "/" : "",
-		S_OR(resource, ""));
-
-	/* All access to channel_ids should be covered by the endpoint's
-	 * lock; no extra lock needed. */
-	endpoint->channel_ids = ast_str_container_alloc_options(
-		AO2_ALLOC_OPT_LOCK_NOLOCK, ENDPOINT_CHANNEL_BUCKETS);
-	if (!endpoint->channel_ids) {
-		return NULL;
-	}
-
-	endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(),
-		endpoint->id);
-	if (!endpoint->topics) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(resource)) {
-		endpoint->router = stasis_message_router_create_pool(ast_endpoint_topic(endpoint));
-		if (!endpoint->router) {
-			return NULL;
-		}
-		r |= stasis_message_router_add(endpoint->router,
-			stasis_cache_clear_type(), endpoint_cache_clear,
-			endpoint);
-		r |= stasis_message_router_set_default(endpoint->router,
-			endpoint_default, endpoint);
-		if (r) {
-			return NULL;
-		}
-
-		endpoint->tech_forward = stasis_forward_all(stasis_cp_single_topic(endpoint->topics),
-			stasis_cp_single_topic(tech_endpoint->topics));
-		endpoint_publish_snapshot(endpoint);
-		ao2_link(endpoints, endpoint);
-	} else {
-		ao2_link(tech_endpoints, endpoint);
-	}
-
-	ao2_ref(endpoint, +1);
-	return endpoint;
-}
-
-struct ast_endpoint *ast_endpoint_create(const char *tech, const char *resource)
-{
-	if (ast_strlen_zero(tech)) {
-		ast_log(LOG_ERROR, "Endpoint tech cannot be empty\n");
-		return NULL;
-	}
-
-	if (ast_strlen_zero(resource)) {
-		ast_log(LOG_ERROR, "Endpoint resource cannot be empty\n");
-		return NULL;
-	}
-
-	return endpoint_internal_create(tech, resource);
-}
-
-static struct stasis_message *create_endpoint_snapshot_message(struct ast_endpoint *endpoint)
-{
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (!ast_endpoint_snapshot_type()) {
-		return NULL;
-	}
-
-	snapshot = ast_endpoint_snapshot_create(endpoint);
-	if (!snapshot) {
-		return NULL;
-	}
-
-	return stasis_message_create(ast_endpoint_snapshot_type(), snapshot);
-}
-
-void ast_endpoint_shutdown(struct ast_endpoint *endpoint)
-{
-	RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup);
-
-	if (endpoint == NULL) {
-		return;
-	}
-
-	ao2_unlink(endpoints, endpoint);
-	endpoint->tech_forward = stasis_forward_cancel(endpoint->tech_forward);
-
-	clear_msg = create_endpoint_snapshot_message(endpoint);
-	if (clear_msg) {
-		RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-		message = stasis_cache_clear_create(clear_msg);
-		if (message) {
-			stasis_publish(ast_endpoint_topic(endpoint), message);
-		}
-	}
-
-	/* Bump refcount to hold on to the router */
-	ao2_ref(endpoint->router, +1);
-	stasis_message_router_unsubscribe(endpoint->router);
-}
-
-const char *ast_endpoint_get_tech(const struct ast_endpoint *endpoint)
-{
-	if (!endpoint) {
-		return NULL;
-	}
-	return endpoint->tech;
-}
-
-const char *ast_endpoint_get_resource(const struct ast_endpoint *endpoint)
-{
-	if (!endpoint) {
-		return NULL;
-	}
-	return endpoint->resource;
-}
-
-const char *ast_endpoint_get_id(const struct ast_endpoint *endpoint)
-{
-	if (!endpoint) {
-		return NULL;
-	}
-	return endpoint->id;
-}
-
-void ast_endpoint_set_state(struct ast_endpoint *endpoint,
-	enum ast_endpoint_state state)
-{
-	ast_assert(endpoint != NULL);
-	ast_assert(!ast_strlen_zero(endpoint->resource));
-
-	ao2_lock(endpoint);
-	endpoint->state = state;
-	ao2_unlock(endpoint);
-	endpoint_publish_snapshot(endpoint);
-}
-
-void ast_endpoint_set_max_channels(struct ast_endpoint *endpoint,
-	int max_channels)
-{
-	ast_assert(endpoint != NULL);
-	ast_assert(!ast_strlen_zero(endpoint->resource));
-
-	ao2_lock(endpoint);
-	endpoint->max_channels = max_channels;
-	ao2_unlock(endpoint);
-	endpoint_publish_snapshot(endpoint);
-}
-
-static void endpoint_snapshot_dtor(void *obj)
-{
-	struct ast_endpoint_snapshot *snapshot = obj;
-	int channel;
-
-	ast_assert(snapshot != NULL);
-
-	for (channel = 0; channel < snapshot->num_channels; channel++) {
-		ao2_ref(snapshot->channel_ids[channel], -1);
-	}
-
-	ast_string_field_free_memory(snapshot);
-}
-
-struct ast_endpoint_snapshot *ast_endpoint_snapshot_create(
-	struct ast_endpoint *endpoint)
-{
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-	int channel_count;
-	struct ao2_iterator i;
-	void *obj;
-	SCOPED_AO2LOCK(lock, endpoint);
-
-	ast_assert(endpoint != NULL);
-	ast_assert(!ast_strlen_zero(endpoint->resource));
-
-	channel_count = ao2_container_count(endpoint->channel_ids);
-
-	snapshot = ao2_alloc(
-		sizeof(*snapshot) + channel_count * sizeof(char *),
-		endpoint_snapshot_dtor);
-
-	if (ast_string_field_init(snapshot, 80) != 0) {
-		return NULL;
-	}
-
-	ast_string_field_build(snapshot, id, "%s/%s", endpoint->tech,
-		endpoint->resource);
-	ast_string_field_set(snapshot, tech, endpoint->tech);
-	ast_string_field_set(snapshot, resource, endpoint->resource);
-
-	snapshot->state = endpoint->state;
-	snapshot->max_channels = endpoint->max_channels;
-
-	i = ao2_iterator_init(endpoint->channel_ids, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		/* The reference is kept so the channel id does not go away until the snapshot is gone */
-		snapshot->channel_ids[snapshot->num_channels++] = obj;
-	}
-	ao2_iterator_destroy(&i);
-
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-static void endpoint_cleanup(void)
-{
-	ao2_cleanup(endpoints);
-	endpoints = NULL;
-
-	ao2_cleanup(tech_endpoints);
-	tech_endpoints = NULL;
-}
-
-int ast_endpoint_init(void)
-{
-	ast_register_cleanup(endpoint_cleanup);
-
-	endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, endpoint_hash,
-		endpoint_cmp);
-	if (!endpoints) {
-		return -1;
-	}
-
-	tech_endpoints = ao2_container_alloc(TECH_ENDPOINT_BUCKETS, endpoint_hash,
-		endpoint_cmp);
-	if (!tech_endpoints) {
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/enum.c b/main/enum.c
index 9bcdae2..3b49486 100644
--- a/main/enum.c
+++ b/main/enum.c
@@ -45,29 +45,22 @@
  * \todo The service type selection needs to be redone.
  */
 
-/*! \li \ref enum.c uses the configuration file \ref enum.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page enum.conf enum.conf
- * \verbinclude enum.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #ifdef __APPLE__
+#if __APPLE_CC__ >= 1495
 #include <arpa/nameser_compat.h>
 #endif
+#endif
 #include <resolv.h>
 #include <ctype.h>
 #include <regex.h>
@@ -257,7 +250,7 @@ struct ebl_context {
 static int ebl_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 {
 	struct ebl_context *c = context;
-	unsigned int i;
+	int i;
 
 	c->pos = 0;	/* default to empty */
 	c->separator[0] = 0;
@@ -1007,6 +1000,7 @@ static int private_enum_init(int reload)
 		ast_config_destroy(cfg);
 	}
 	ast_mutex_unlock(&enumlock);
+	manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
 	return 0;
 }
 
diff --git a/main/event.c b/main/event.c
index f274837..94365e2 100644
--- a/main/event.c
+++ b/main/event.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417571 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -44,6 +44,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417571 $")
 #include "asterisk/astobj2.h"
 #include "asterisk/cli.h"
 
+static struct ast_taskprocessor *event_dispatcher;
+
 /*!
  * \brief An event information element
  *
@@ -90,6 +92,20 @@ struct ast_event {
 } __attribute__((packed));
 
 
+/*!
+ * \brief A holder for an event
+ *
+ * \details This struct used to have more of a purpose than it does now.
+ * It is used to hold events in the event cache.  It can be completely removed
+ * if one of these two things is done:
+ *  - ast_event gets changed such that it never has to be realloc()d
+ *  - astobj2 is updated so that you can realloc() an astobj2 object
+ */
+struct ast_event_ref {
+	struct ast_event *event;
+	unsigned int cache;
+};
+
 struct ast_event_ie_val {
 	AST_LIST_ENTRY(ast_event_ie_val) entry;
 	enum ast_event_ie_type ie_type;
@@ -105,6 +121,86 @@ struct ast_event_ie_val {
 	size_t raw_datalen;
 };
 
+/*! \brief Event subscription */
+struct ast_event_sub {
+	enum ast_event_type type;
+	ast_event_cb_t cb;
+	char description[64];
+	void *userdata;
+	uint32_t uniqueid;
+	AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
+	AST_RWDLLIST_ENTRY(ast_event_sub) entry;
+};
+
+static uint32_t sub_uniqueid;
+
+/*! \brief Event subscriptions
+ * The event subscribers are indexed by which event they are subscribed to */
+static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
+
+static int ast_event_cmp(void *obj, void *arg, int flags);
+static int ast_event_hash_mwi(const void *obj, const int flags);
+static int ast_event_hash_devstate(const void *obj, const int flags);
+static int ast_event_hash_devstate_change(const void *obj, const int flags);
+static int ast_event_hash_presence_state_change(const void *obj, const int flags);
+
+#ifdef LOW_MEMORY
+#define NUM_CACHE_BUCKETS 17
+#else
+#define NUM_CACHE_BUCKETS 563
+#endif
+
+#define MAX_CACHE_ARGS 8
+
+/*!
+ * \brief Event types that are kept in the cache.
+ */
+static struct {
+	/*!
+	 * \brief Container of cached events
+	 *
+	 * \details This gets allocated in ast_event_init() when Asterisk starts
+	 * for the event types declared as using the cache.
+	 */
+	struct ao2_container *container;
+	/*! \brief Event type specific hash function */
+	ao2_hash_fn *hash_fn;
+	/*!
+	 * \brief Information Elements used for caching
+	 *
+	 * \details This array is the set of information elements that will be unique
+	 * among all events in the cache for this event type.  When a new event gets
+	 * cached, a previous event with the same values for these information elements
+	 * will be replaced.
+	 */
+	enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
+} ast_event_cache[AST_EVENT_TOTAL] = {
+	[AST_EVENT_MWI] = {
+		.hash_fn = ast_event_hash_mwi,
+		.cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
+	},
+	[AST_EVENT_DEVICE_STATE] = {
+		.hash_fn = ast_event_hash_devstate,
+		.cache_args = { AST_EVENT_IE_DEVICE, },
+	},
+	[AST_EVENT_DEVICE_STATE_CHANGE] = {
+		.hash_fn = ast_event_hash_devstate_change,
+		.cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
+	},
+	[AST_EVENT_PRESENCE_STATE] = {
+		.hash_fn = ast_event_hash_presence_state_change,
+		.cache_args = { AST_EVENT_IE_PRESENCE_STATE, },
+	},
+
+};
+
+/*!
+ * \brief Names of cached event types, for CLI tab completion
+ *
+ * \note These names must match what is in the event_names array.
+ */
+static const char * const cached_event_types[] = { "MWI", "DeviceState", "DeviceStateChange", NULL };
+
 /*!
  * \brief Event Names
  */
@@ -144,7 +240,7 @@ static const struct ie_map {
 	[AST_EVENT_IE_CEL_EVENT_TYPE]      = { AST_EVENT_IE_PLTYPE_UINT, "CELEventType" },
 	[AST_EVENT_IE_CEL_EVENT_TIME]      = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTime" },
 	[AST_EVENT_IE_CEL_EVENT_TIME_USEC] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTimeUSec" },
-	[AST_EVENT_IE_CEL_USEREVENT_NAME]  = { AST_EVENT_IE_PLTYPE_STR,  "CELUserEventName" },
+	[AST_EVENT_IE_CEL_USEREVENT_NAME]  = { AST_EVENT_IE_PLTYPE_UINT, "CELUserEventName" },
 	[AST_EVENT_IE_CEL_CIDNAME]         = { AST_EVENT_IE_PLTYPE_STR,  "CELCIDName" },
 	[AST_EVENT_IE_CEL_CIDNUM]          = { AST_EVENT_IE_PLTYPE_STR,  "CELCIDNum" },
 	[AST_EVENT_IE_CEL_EXTEN]           = { AST_EVENT_IE_PLTYPE_STR,  "CELExten" },
@@ -152,8 +248,8 @@ static const struct ie_map {
 	[AST_EVENT_IE_CEL_CHANNAME]        = { AST_EVENT_IE_PLTYPE_STR,  "CELChanName" },
 	[AST_EVENT_IE_CEL_APPNAME]         = { AST_EVENT_IE_PLTYPE_STR,  "CELAppName" },
 	[AST_EVENT_IE_CEL_APPDATA]         = { AST_EVENT_IE_PLTYPE_STR,  "CELAppData" },
-	[AST_EVENT_IE_CEL_AMAFLAGS]        = { AST_EVENT_IE_PLTYPE_UINT, "CELAMAFlags" },
-	[AST_EVENT_IE_CEL_ACCTCODE]        = { AST_EVENT_IE_PLTYPE_STR,  "CELAcctCode" },
+	[AST_EVENT_IE_CEL_AMAFLAGS]        = { AST_EVENT_IE_PLTYPE_STR,  "CELAMAFlags" },
+	[AST_EVENT_IE_CEL_ACCTCODE]        = { AST_EVENT_IE_PLTYPE_UINT, "CELAcctCode" },
 	[AST_EVENT_IE_CEL_UNIQUEID]        = { AST_EVENT_IE_PLTYPE_STR,  "CELUniqueID" },
 	[AST_EVENT_IE_CEL_USERFIELD]       = { AST_EVENT_IE_PLTYPE_STR,  "CELUserField" },
 	[AST_EVENT_IE_CEL_CIDANI]          = { AST_EVENT_IE_PLTYPE_STR,  "CELCIDani" },
@@ -163,7 +259,7 @@ static const struct ie_map {
 	[AST_EVENT_IE_CEL_LINKEDID]        = { AST_EVENT_IE_PLTYPE_STR,  "CELLinkedID" },
 	[AST_EVENT_IE_CEL_PEERACCT]        = { AST_EVENT_IE_PLTYPE_STR,  "CELPeerAcct" },
 	[AST_EVENT_IE_CEL_EXTRA]           = { AST_EVENT_IE_PLTYPE_STR,  "CELExtra" },
-	[AST_EVENT_IE_SECURITY_EVENT]      = { AST_EVENT_IE_PLTYPE_UINT, "SecurityEvent" },
+	[AST_EVENT_IE_SECURITY_EVENT]      = { AST_EVENT_IE_PLTYPE_STR,  "SecurityEvent" },
 	[AST_EVENT_IE_EVENT_VERSION]       = { AST_EVENT_IE_PLTYPE_UINT, "EventVersion" },
 	[AST_EVENT_IE_SERVICE]             = { AST_EVENT_IE_PLTYPE_STR,  "Service" },
 	[AST_EVENT_IE_MODULE]              = { AST_EVENT_IE_PLTYPE_STR,  "Module" },
@@ -199,7 +295,7 @@ const char *ast_event_get_type_name(const struct ast_event *event)
 
 	type = ast_event_get_type(event);
 
-	if (type < 0 || type >= ARRAY_LEN(event_names)) {
+	if ((unsigned int)type >= ARRAY_LEN(event_names)) {
 		ast_log(LOG_ERROR, "Invalid event type - '%u'\n", type);
 		return "";
 	}
@@ -207,6 +303,22 @@ const char *ast_event_get_type_name(const struct ast_event *event)
 	return event_names[type];
 }
 
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_LEN(event_names); i++) {
+		if (ast_strlen_zero(event_names[i]) || strcasecmp(event_names[i], str)) {
+			continue;
+		}
+
+		*event_type = i;
+		return 0;
+	}
+
+	return -1;
+}
+
 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
 {
 	if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
@@ -227,195 +339,150 @@ enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
 	return ie_maps[ie_type].ie_pltype;
 }
 
-size_t ast_event_get_size(const struct ast_event *event)
+int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
 {
-	size_t res;
-
-	res = ntohs(event->event_len);
-
-	return res;
-}
+	int i;
 
-/*! \brief Subscription event check list. */
-struct ast_ev_check_list {
-	AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
-};
-
-int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
-{
-	int res = 0;
+	for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
+		if (strcasecmp(ie_maps[i].name, str)) {
+			continue;
+		}
 
-	iterator->event_len = ast_event_get_size(event);
-	iterator->event = event;
-	if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
-		iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
-	} else {
-		iterator->ie = NULL;
-		res = -1;
+		*ie_type = i;
+		return 0;
 	}
 
-	return res;
-}
-
-int ast_event_iterator_next(struct ast_event_iterator *iterator)
-{
-	iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
-	return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
-}
-
-enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
-{
-	return ntohs(iterator->ie->ie_type);
-}
-
-uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
-{
-	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+	return -1;
 }
 
-const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
+size_t ast_event_get_size(const struct ast_event *event)
 {
-	const struct ast_event_ie_str_payload *str_payload;
-
-	str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
-
-	return str_payload ? str_payload->str : NULL;
-}
+	size_t res;
 
-static void *event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
-{
-	return iterator->ie->ie_payload;
-}
+	res = ntohs(event->event_len);
 
-enum ast_event_type ast_event_get_type(const struct ast_event *event)
-{
-	return ntohs(event->type);
+	return res;
 }
 
-uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
+static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
 {
-	const uint32_t *ie_val;
-
-	ie_val = ast_event_get_ie_raw(event, ie_type);
+	switch (ie_val->ie_pltype) {
+	case AST_EVENT_IE_PLTYPE_STR:
+		ast_free((char *) ie_val->payload.str);
+		break;
+	case AST_EVENT_IE_PLTYPE_RAW:
+		ast_free(ie_val->payload.raw);
+		break;
+	case AST_EVENT_IE_PLTYPE_UINT:
+	case AST_EVENT_IE_PLTYPE_BITFLAGS:
+	case AST_EVENT_IE_PLTYPE_EXISTS:
+	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		break;
+	}
 
-	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+	ast_free(ie_val);
 }
 
-const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
-{
-	const struct ast_event_ie_str_payload *str_payload;
-
-	str_payload = ast_event_get_ie_raw(event, ie_type);
-
-	return str_payload ? str_payload->str : NULL;
-}
+/*! \brief Subscription event check list. */
+struct ast_ev_check_list {
+	AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
+};
 
-const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
+/*!
+ * \internal
+ * \brief Check if a subscription ie_val matches an event.
+ *
+ * \param sub_ie_val Subscripton IE value to check
+ * \param check_ie_vals event list to check against
+ *
+ * \retval 0 not matched
+ * \retval non-zero matched
+ */
+static int match_sub_ie_val_to_event(const struct ast_event_ie_val *sub_ie_val, const struct ast_ev_check_list *check_ie_vals)
 {
-	struct ast_event_iterator iterator;
-	int res;
+	const struct ast_event_ie_val *event_ie_val;
+	int res = 0;
 
-	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
-		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
-			return event_iterator_get_ie_raw(&iterator);
+	AST_LIST_TRAVERSE(&check_ie_vals->ie_vals, event_ie_val, entry) {
+		if (sub_ie_val->ie_type == event_ie_val->ie_type) {
+			break;
 		}
 	}
+	if (!event_ie_val) {
+		/* We did not find the event ie the subscriber cares about. */
+		return 0;
+	}
 
-	return NULL;
-}
-
-static uint16_t event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
-{
-	return ntohs(iterator->ie->ie_payload_len);
-}
-
-uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
-{
-	struct ast_event_iterator iterator;
-	int res;
-
-	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
-		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
-			return event_iterator_get_ie_raw_payload_len(&iterator);
+	if (sub_ie_val->ie_pltype != event_ie_val->ie_pltype) {
+		if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+			/* The subscription only cares that this ie exists. */
+			return 1;
 		}
+		/* Payload types do not match. */
+		return 0;
 	}
 
-	return 0;
-}
-
-
-int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
-	const char *str)
-{
-	struct ast_event_ie_str_payload *str_payload;
-	size_t payload_len;
-
-	payload_len = sizeof(*str_payload) + strlen(str);
-	str_payload = ast_alloca(payload_len);
-
-	strcpy(str_payload->str, str);
-	str_payload->hash = ast_str_hash(str);
-
-	return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
-}
-
-int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
-	uint32_t data)
-{
-	data = htonl(data);
-	return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
-}
-
-int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
-	uint32_t flags)
-{
-	flags = htonl(flags);
-	return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
-}
-
-int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
-	const void *data, size_t data_len)
-{
-	struct ast_event_ie *ie;
-	struct ast_event *old_event;
-	unsigned int extra_len;
-	uint16_t event_len;
-
-	event_len = ntohs((*event)->event_len);
-	extra_len = sizeof(*ie) + data_len;
-
-	old_event = *event;
-	*event = ast_realloc(*event, event_len + extra_len);
-	if (!*event) {
-		ast_free(old_event);
-		return -1;
+	switch (sub_ie_val->ie_pltype) {
+	case AST_EVENT_IE_PLTYPE_UINT:
+		res = (sub_ie_val->payload.uint == event_ie_val->payload.uint);
+		break;
+	case AST_EVENT_IE_PLTYPE_BITFLAGS:
+		/*
+		 * If the subscriber has requested *any* of the bitflags we are providing,
+		 * then it's a match.
+		 */
+		res = (sub_ie_val->payload.uint & event_ie_val->payload.uint);
+		break;
+	case AST_EVENT_IE_PLTYPE_STR:
+	{
+		const char *substr = sub_ie_val->payload.str;
+		const char *estr = event_ie_val->payload.str;
+		if (sub_ie_val->ie_type == AST_EVENT_IE_DEVICE) {
+			substr = ast_tech_to_upper(ast_strdupa(substr));
+			estr = ast_tech_to_upper(ast_strdupa(estr));
+		}
+		res = !strcmp(substr, estr);
+		break;
+	}
+	case AST_EVENT_IE_PLTYPE_RAW:
+		res = (sub_ie_val->raw_datalen == event_ie_val->raw_datalen
+			&& !memcmp(sub_ie_val->payload.raw, event_ie_val->payload.raw,
+				sub_ie_val->raw_datalen));
+		break;
+	case AST_EVENT_IE_PLTYPE_EXISTS:
+		/* Should never get here since check_ie_vals cannot have this type. */
+		break;
+	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		/*
+		 * Should never be in a subscription event ie val list and
+		 * check_ie_vals cannot have this type either.
+		 */
+		break;
 	}
 
-	ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
-	ie->ie_type = htons(ie_type);
-	ie->ie_payload_len = htons(data_len);
-	memcpy(ie->ie_payload, data, data_len);
-
-	(*event)->event_len = htons(event_len + extra_len);
-
-	return 0;
+	return res;
 }
 
-struct ast_event *ast_event_new(enum ast_event_type type, ...)
+enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
 {
 	va_list ap;
-	struct ast_event *event;
 	enum ast_event_ie_type ie_type;
+	enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
 	struct ast_event_ie_val *ie_val;
-	AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
+	struct ast_event_sub *sub;
+	struct ast_ev_check_list check_ie_vals = {
+		.ie_vals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
+	};
+	const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
+	int i;
+	int want_specific_event;/* TRUE if looking for subscribers wanting specific parameters. */
 
-	/* Invalid type */
 	if (type >= AST_EVENT_TOTAL) {
-		ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
-			"type '%u'!\n", type);
-		return NULL;
+		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+		return res;
 	}
 
+	want_specific_event = 0;
 	va_start(ap, type);
 	for (ie_type = va_arg(ap, enum ast_event_ie_type);
 		ie_type != AST_EVENT_IE_END;
@@ -427,7 +494,6 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
 		memset(ie_value, 0, sizeof(*ie_value));
 		ie_value->ie_type = ie_type;
 		ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
-
 		switch (ie_value->ie_pltype) {
 		case AST_EVENT_IE_PLTYPE_UINT:
 			ie_value->payload.uint = va_arg(ap, uint32_t);
@@ -445,6 +511,7 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
 		{
 			void *data = va_arg(ap, void *);
 			size_t datalen = va_arg(ap, size_t);
+
 			ie_value->payload.raw = ast_alloca(datalen);
 			memcpy(ie_value->payload.raw, data, datalen);
 			ie_value->raw_datalen = datalen;
@@ -453,70 +520,1380 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
 		}
 		case AST_EVENT_IE_PLTYPE_UNKNOWN:
 		case AST_EVENT_IE_PLTYPE_EXISTS:
+			/* Unsupported payload type. */
 			break;
 		}
 
 		if (insert) {
-			AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
+			want_specific_event = 1;
+			AST_LIST_INSERT_TAIL(&check_ie_vals.ie_vals, ie_value, entry);
 		} else {
 			ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
 		}
 	}
 	va_end(ap);
 
-	if (!(event = ast_calloc(1, sizeof(*event)))) {
-		return NULL;
+	for (i = 0; i < ARRAY_LEN(event_types); i++) {
+		AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
+		if (want_specific_event) {
+			AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
+				AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+					if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) {
+						/* The current subscription ie did not match an event ie. */
+						break;
+					}
+				}
+				if (!ie_val) {
+					/* Everything matched.  A subscriber is looking for this event. */
+					break;
+				}
+			}
+		} else {
+			/* Just looking to see if there are ANY subscribers to the event type. */
+			sub = AST_RWLIST_FIRST(&ast_event_subs[event_types[i]]);
+		}
+		AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
+		if (sub) {
+			break;
+		}
 	}
 
-	event->type = htons(type);
-	event->event_len = htons(sizeof(*event));
+	return sub ? AST_EVENT_SUB_EXISTS : AST_EVENT_SUB_NONE;
+}
 
-	AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
-		switch (ie_val->ie_pltype) {
-		case AST_EVENT_IE_PLTYPE_STR:
-			ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
-			break;
-		case AST_EVENT_IE_PLTYPE_UINT:
-			ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
-			break;
-		case AST_EVENT_IE_PLTYPE_BITFLAGS:
-			ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
-			break;
-		case AST_EVENT_IE_PLTYPE_RAW:
-			ast_event_append_ie_raw(&event, ie_val->ie_type,
-					ie_val->payload.raw, ie_val->raw_datalen);
-			break;
-		case AST_EVENT_IE_PLTYPE_EXISTS:
-		case AST_EVENT_IE_PLTYPE_UNKNOWN:
-			break;
-		}
+/*!
+ * \internal
+ * \brief Check if an ie_val matches an event
+ *
+ * \param event event to check against
+ * \param ie_val IE value to check
+ * \param event2 optional event, if specified, the value to compare against will be pulled
+ *        from this event instead of from the ie_val structure.  In this case, only the IE
+ *        type and payload type will be pulled from ie_val.
+ *
+ * \retval 0 not matched
+ * \retval non-zero matched
+ */
+static int match_ie_val(const struct ast_event *event,
+		const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
+{
+	switch (ie_val->ie_pltype) {
+	case AST_EVENT_IE_PLTYPE_UINT:
+	{
+		uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
 
-		/* realloc inside one of the append functions failed */
-		if (!event) {
-			return NULL;
-		}
+		return (val == ast_event_get_ie_uint(event, ie_val->ie_type)) ? 1 : 0;
 	}
 
-	if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
-		/* If the event is originating on this server, add the server's
-		 * entity ID to the event. */
-		ast_event_append_eid(&event);
+	case AST_EVENT_IE_PLTYPE_BITFLAGS:
+	{
+		uint32_t flags = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+
+		/*
+		 * If the subscriber has requested *any* of the bitflags that this event provides,
+		 * then it's a match.
+		 */
+		return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0;
 	}
 
-	return event;
-}
+	case AST_EVENT_IE_PLTYPE_STR:
+	{
+		const char *str;
+		uint32_t hash;
 
-int ast_event_append_eid(struct ast_event **event)
-{
-	return ast_event_append_ie_raw(event, AST_EVENT_IE_EID,
-			&ast_eid_default, sizeof(ast_eid_default));
-}
+		hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
+		if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
+			return 0;
+		}
+
+		str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
+		if (str) {
+			const char *e1str, *e2str;
+			e1str = ast_event_get_ie_str(event, ie_val->ie_type);
+			e2str = str;
+
+			if (ie_val->ie_type == AST_EVENT_IE_DEVICE) {
+				e1str = ast_tech_to_upper(ast_strdupa(e1str));
+				e2str = ast_tech_to_upper(ast_strdupa(e2str));
+			}
+
+			if (!strcmp(e1str, e2str)) {
+				return 1;
+			}
+		}
+
+		return 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_RAW:
+	{
+		const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
+		uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
+
+		return (buf
+			&& ie_payload_len == ast_event_get_ie_raw_payload_len(event, ie_val->ie_type)
+			&& !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_EXISTS:
+	{
+		return ast_event_get_ie_raw(event, ie_val->ie_type) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int dump_cache_cb(void *obj, void *arg, int flags)
+{
+	const struct ast_event_ref *event_ref = obj;
+	const struct ast_event *event = event_ref->event;
+	const struct ast_event_sub *event_sub = arg;
+	struct ast_event_ie_val *ie_val = NULL;
+
+	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+		if (!match_ie_val(event, ie_val, NULL)) {
+			break;
+		}
+	}
+
+	if (!ie_val) {
+		/* All parameters were matched on this cache entry, so dump it */
+		event_sub->cb(event, event_sub->userdata);
+	}
+
+	return 0;
+}
+
+/*! \brief Dump the event cache for the subscribed event type */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub)
+{
+	if (!ast_event_cache[event_sub->type].container) {
+		return;
+	}
+
+	ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
+			dump_cache_cb, (void *) event_sub);
+}
+
+static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
+{
+	struct ast_event_ie_val *ie_val;
+	struct ast_event *event;
+
+	event = ast_event_new(AST_EVENT_SUB,
+		AST_EVENT_IE_UNIQUEID,    AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
+		AST_EVENT_IE_EVENTTYPE,   AST_EVENT_IE_PLTYPE_UINT, sub->type,
+		AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
+		AST_EVENT_IE_END);
+	if (!event)
+		return NULL;
+
+	AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+		switch (ie_val->ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+			break;
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
+			break;
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
+			break;
+		case AST_EVENT_IE_PLTYPE_STR:
+			ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+			ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
+			break;
+		}
+		if (!event)
+			break;
+	}
+
+	return event;
+}
+
+/*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
+void ast_event_report_subs(const struct ast_event_sub *event_sub)
+{
+	struct ast_event *event;
+	struct ast_event_sub *sub;
+	enum ast_event_type event_type;
+	int found = 0;
+	struct ast_event_ie_val *ie_val;
+
+	if (event_sub->type != AST_EVENT_SUB)
+		return;
+
+	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+		if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
+			event_type = ie_val->payload.uint;
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		return;
+	}
+
+	AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
+	AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
+		if (event_sub == sub) {
+			continue;
+		}
+
+		event = gen_sub_event(sub);
+		if (!event) {
+			continue;
+		}
+
+		event_sub->cb(event, event_sub->userdata);
+
+		ast_event_destroy(event);
+	}
+	AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
+}
+
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+	ast_event_cb_t cb, void *userdata)
+{
+	struct ast_event_sub *sub;
+
+	if (type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+		return NULL;
+	}
+
+	if (!(sub = ast_calloc(1, sizeof(*sub)))) {
+		return NULL;
+	}
+
+	sub->type = type;
+	sub->cb = cb;
+	sub->userdata = userdata;
+	sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
+
+	return sub;
+}
+
+int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, uint32_t unsigned_int)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->payload.uint = unsigned_int;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
+
+	AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+	return 0;
+}
+
+int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, uint32_t flags)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->payload.uint = flags;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_BITFLAGS;
+
+	AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+	return 0;
+}
+
+int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
+
+	AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+	return 0;
+}
+
+int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, const char *str)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
+
+	if (!(ie_val->payload.str = ast_strdup(str))) {
+		ast_free(ie_val);
+		return -1;
+	}
+
+	if (ie_type == AST_EVENT_IE_DEVICE) {
+		char *uppertech = ast_strdupa(str);
+		ast_tech_to_upper(uppertech);
+		ie_val->payload.hash = ast_str_hash(uppertech);
+	} else {
+		ie_val->payload.hash = ast_str_hash(str);
+	}
+
+	AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+	return 0;
+}
+
+int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
+	ie_val->raw_datalen = raw_datalen;
+
+	if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
+		ast_free(ie_val);
+		return -1;
+	}
+
+	memcpy(ie_val->payload.raw, data, raw_datalen);
+
+	AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+	return 0;
+}
+
+int ast_event_sub_activate(struct ast_event_sub *sub)
+{
+	if (ast_event_check_subscriber(AST_EVENT_SUB,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+		struct ast_event *event;
+
+		event = gen_sub_event(sub);
+		if (event && ast_event_queue(event)) {
+			ast_event_destroy(event);
+		}
+	}
+
+	AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
+	AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
+	AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
+
+	return 0;
+}
+
+struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
+	const char *description, void *userdata, ...)
+{
+	va_list ap;
+	enum ast_event_ie_type ie_type;
+	struct ast_event_sub *sub;
+
+	if (!(sub = ast_event_subscribe_new(type, cb, userdata))) {
+		return NULL;
+	}
+
+	ast_copy_string(sub->description, description, sizeof(sub->description));
+
+	va_start(ap, userdata);
+	for (ie_type = va_arg(ap, enum ast_event_ie_type);
+		ie_type != AST_EVENT_IE_END;
+		ie_type = va_arg(ap, enum ast_event_ie_type))
+	{
+		enum ast_event_ie_pltype ie_pltype;
+
+		ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+
+		switch (ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+			break;
+		case AST_EVENT_IE_PLTYPE_UINT:
+		{
+			uint32_t unsigned_int = va_arg(ap, uint32_t);
+			ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+		{
+			uint32_t unsigned_int = va_arg(ap, uint32_t);
+			ast_event_sub_append_ie_bitflags(sub, ie_type, unsigned_int);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_STR:
+		{
+			const char *str = va_arg(ap, const char *);
+			ast_event_sub_append_ie_str(sub, ie_type, str);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_RAW:
+		{
+			void *data = va_arg(ap, void *);
+			size_t data_len = va_arg(ap, size_t);
+			ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			ast_event_sub_append_ie_exists(sub, ie_type);
+			break;
+		}
+	}
+	va_end(ap);
+
+	ast_event_sub_activate(sub);
+
+	return sub;
+}
+
+void ast_event_sub_destroy(struct ast_event_sub *sub)
+{
+	struct ast_event_ie_val *ie_val;
+
+	while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
+		ast_event_ie_val_destroy(ie_val);
+	}
+
+	ast_free(sub);
+}
+
+const char *ast_event_subscriber_get_description(struct ast_event_sub *sub)
+{
+	return sub ? sub->description : NULL;
+}
+
+struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
+{
+	struct ast_event *event;
+
+	AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
+	AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
+	AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
+
+	if (ast_event_check_subscriber(AST_EVENT_UNSUB,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+
+		event = ast_event_new(AST_EVENT_UNSUB,
+			AST_EVENT_IE_UNIQUEID,    AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
+			AST_EVENT_IE_EVENTTYPE,   AST_EVENT_IE_PLTYPE_UINT, sub->type,
+			AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
+			AST_EVENT_IE_END);
+		if (event && ast_event_queue(event)) {
+			ast_event_destroy(event);
+		}
+	}
+
+	ast_event_sub_destroy(sub);
+
+	return NULL;
+}
+
+int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
+{
+	int res = 0;
+
+	iterator->event_len = ast_event_get_size(event);
+	iterator->event = event;
+	if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
+		iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
+	} else {
+		iterator->ie = NULL;
+		res = -1;
+	}
+
+	return res;
+}
+
+int ast_event_iterator_next(struct ast_event_iterator *iterator)
+{
+	iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
+	return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
+}
+
+enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
+{
+	return ntohs(iterator->ie->ie_type);
+}
+
+uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
+{
+	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+}
+
+uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator)
+{
+	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+}
+
+const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
+
+	return str_payload ? str_payload->str : NULL;
+}
+
+void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
+{
+	return iterator->ie->ie_payload;
+}
+
+uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
+{
+	return ntohs(iterator->ie->ie_payload_len);
+}
+
+enum ast_event_type ast_event_get_type(const struct ast_event *event)
+{
+	return ntohs(event->type);
+}
+
+uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const uint32_t *ie_val;
+
+	ie_val = ast_event_get_ie_raw(event, ie_type);
+
+	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+}
+
+uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const uint32_t *ie_val;
+
+	ie_val = ast_event_get_ie_raw(event, ie_type);
+
+	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+}
+
+uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = ast_event_get_ie_raw(event, ie_type);
+
+	return str_payload ? str_payload->hash : 0;
+}
+
+const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = ast_event_get_ie_raw(event, ie_type);
+
+	return str_payload ? str_payload->str : NULL;
+}
+
+const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	struct ast_event_iterator iterator;
+	int res;
+
+	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+			return ast_event_iterator_get_ie_raw(&iterator);
+		}
+	}
+
+	return NULL;
+}
+
+uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	struct ast_event_iterator iterator;
+	int res;
+
+	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+			return ast_event_iterator_get_ie_raw_payload_len(&iterator);
+		}
+	}
+
+	return 0;
+}
+
+int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const char *str)
+{
+	struct ast_event_ie_str_payload *str_payload;
+	size_t payload_len;
+
+	payload_len = sizeof(*str_payload) + strlen(str);
+	str_payload = ast_alloca(payload_len);
+
+	strcpy(str_payload->str, str);
+	if (ie_type == AST_EVENT_IE_DEVICE) {
+		char *uppertech = ast_strdupa(str);
+		ast_tech_to_upper(uppertech);
+		str_payload->hash = ast_str_hash(uppertech);
+	} else {
+		str_payload->hash = ast_str_hash(str);
+	}
+
+	return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
+}
+
+int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
+	uint32_t data)
+{
+	data = htonl(data);
+	return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
+}
+
+int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
+	uint32_t flags)
+{
+	flags = htonl(flags);
+	return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
+}
+
+int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const void *data, size_t data_len)
+{
+	struct ast_event_ie *ie;
+	struct ast_event *old_event;
+	unsigned int extra_len;
+	uint16_t event_len;
+
+	event_len = ntohs((*event)->event_len);
+	extra_len = sizeof(*ie) + data_len;
+
+	old_event = *event;
+	*event = ast_realloc(*event, event_len + extra_len);
+	if (!*event) {
+		ast_free(old_event);
+		return -1;
+	}
+
+	ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
+	ie->ie_type = htons(ie_type);
+	ie->ie_payload_len = htons(data_len);
+	memcpy(ie->ie_payload, data, data_len);
+
+	(*event)->event_len = htons(event_len + extra_len);
+
+	return 0;
+}
+
+struct ast_event *ast_event_new(enum ast_event_type type, ...)
+{
+	va_list ap;
+	struct ast_event *event;
+	enum ast_event_ie_type ie_type;
+	struct ast_event_ie_val *ie_val;
+	AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
+
+	/* Invalid type */
+	if (type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
+			"type '%u'!\n", type);
+		return NULL;
+	}
+
+	va_start(ap, type);
+	for (ie_type = va_arg(ap, enum ast_event_ie_type);
+		ie_type != AST_EVENT_IE_END;
+		ie_type = va_arg(ap, enum ast_event_ie_type))
+	{
+		struct ast_event_ie_val *ie_value = ast_alloca(sizeof(*ie_value));
+		int insert = 0;
+
+		memset(ie_value, 0, sizeof(*ie_value));
+		ie_value->ie_type = ie_type;
+		ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+		switch (ie_value->ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_STR:
+			ie_value->payload.str = va_arg(ap, const char *);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+		{
+			void *data = va_arg(ap, void *);
+			size_t datalen = va_arg(ap, size_t);
+			ie_value->payload.raw = ast_alloca(datalen);
+			memcpy(ie_value->payload.raw, data, datalen);
+			ie_value->raw_datalen = datalen;
+			insert = 1;
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			break;
+		}
+
+		if (insert) {
+			AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
+		} else {
+			ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
+		}
+	}
+	va_end(ap);
+
+	if (!(event = ast_calloc(1, sizeof(*event)))) {
+		return NULL;
+	}
+
+	event->type = htons(type);
+	event->event_len = htons(sizeof(*event));
+
+	AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
+		switch (ie_val->ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_STR:
+			ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+			break;
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+			ast_event_append_ie_raw(&event, ie_val->ie_type,
+					ie_val->payload.raw, ie_val->raw_datalen);
+			break;
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+			break;
+		}
+
+		/* realloc inside one of the append functions failed */
+		if (!event) {
+			return NULL;
+		}
+	}
+
+	if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
+		/* If the event is originating on this server, add the server's
+		 * entity ID to the event. */
+		ast_event_append_eid(&event);
+	}
+
+	return event;
+}
+
+int ast_event_append_eid(struct ast_event **event)
+{
+	return ast_event_append_ie_raw(event, AST_EVENT_IE_EID,
+			&ast_eid_default, sizeof(ast_eid_default));
+}
 
 void ast_event_destroy(struct ast_event *event)
 {
 	ast_free(event);
 }
 
+static void ast_event_ref_destroy(void *obj)
+{
+	struct ast_event_ref *event_ref = obj;
+
+	ast_event_destroy(event_ref->event);
+}
+
+static struct ast_event *ast_event_dup(const struct ast_event *event)
+{
+	struct ast_event *dup_event;
+	uint16_t event_len;
+
+	event_len = ast_event_get_size(event);
+
+	if (!(dup_event = ast_calloc(1, event_len))) {
+		return NULL;
+	}
+
+	memcpy(dup_event, event, event_len);
+
+	return dup_event;
+}
+
+struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
+{
+	va_list ap;
+	enum ast_event_ie_type ie_type;
+	struct ast_event *dup_event = NULL;
+	struct ast_event_ref *cached_event_ref;
+	struct ast_event *cache_arg_event;
+	struct ast_event_ref tmp_event_ref = {
+		.event = NULL,
+	};
+	struct ao2_container *container = NULL;
+
+	if (type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+		return NULL;
+	}
+
+	if (!(container = ast_event_cache[type].container)) {
+		ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
+		return NULL;
+	}
+
+	if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
+		return NULL;
+	}
+
+	va_start(ap, type);
+	for (ie_type = va_arg(ap, enum ast_event_ie_type);
+		ie_type != AST_EVENT_IE_END;
+		ie_type = va_arg(ap, enum ast_event_ie_type))
+	{
+		enum ast_event_ie_pltype ie_pltype;
+
+		ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+
+		switch (ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ast_event_append_ie_bitflags(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
+			break;
+		case AST_EVENT_IE_PLTYPE_STR:
+			ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+		{
+			void *data = va_arg(ap, void *);
+			size_t datalen = va_arg(ap, size_t);
+			ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
+			break;
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+			break;
+		}
+	}
+	va_end(ap);
+
+	tmp_event_ref.event = cache_arg_event;
+
+	cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
+
+	ast_event_destroy(cache_arg_event);
+	cache_arg_event = NULL;
+
+	if (cached_event_ref) {
+		dup_event = ast_event_dup(cached_event_ref->event);
+		ao2_ref(cached_event_ref, -1);
+		cached_event_ref = NULL;
+	}
+
+	return dup_event;
+}
+
+static struct ast_event_ref *alloc_event_ref(void)
+{
+	return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
+}
+
+/*!
+ * \internal
+ * \brief Update the given event cache with the new event.
+ * \since 1.8
+ *
+ * \param cache Event cache container to update.
+ * \param event New event to put in the cache.
+ *
+ * \return Nothing
+ */
+static void event_update_cache(struct ao2_container *cache, struct ast_event *event)
+{
+	struct ast_event_ref tmp_event_ref = {
+		.event = event,
+	};
+	struct ast_event *dup_event;
+	struct ast_event_ref *event_ref;
+
+	/* Hold the cache container lock while it is updated. */
+	ao2_lock(cache);
+
+	/* Remove matches from the cache. */
+	ao2_callback(cache, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
+		ast_event_cmp, &tmp_event_ref);
+
+	/* Save a copy of the event in the cache. */
+	dup_event = ast_event_dup(event);
+	if (dup_event) {
+		event_ref = alloc_event_ref();
+		if (event_ref) {
+			event_ref->event = dup_event;
+			ao2_link(cache, event_ref);
+			ao2_ref(event_ref, -1);
+		} else {
+			ast_event_destroy(dup_event);
+		}
+	}
+
+	ao2_unlock(cache);
+}
+
+static int handle_event(void *data)
+{
+	struct ast_event_ref *event_ref = data;
+	struct ast_event_sub *sub;
+	const enum ast_event_type event_types[] = {
+		ntohs(event_ref->event->type),
+		AST_EVENT_ALL
+	};
+	int i;
+
+	if (event_ref->cache) {
+		struct ao2_container *container;
+		container = ast_event_cache[ast_event_get_type(event_ref->event)].container;
+		if (!container) {
+			ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
+		} else {
+			event_update_cache(container, event_ref->event);
+		}
+	}
+
+	for (i = 0; i < ARRAY_LEN(event_types); i++) {
+		AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
+		AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
+			struct ast_event_ie_val *ie_val;
+
+			AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+				if (!match_ie_val(event_ref->event, ie_val, NULL)) {
+					/* The current subscription ie did not match an event ie. */
+					break;
+				}
+			}
+			if (ie_val) {
+				/* The event did not match this subscription. */
+				continue;
+			}
+			sub->cb(event_ref->event, sub->userdata);
+		}
+		AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
+	}
+
+	ao2_ref(event_ref, -1);
+
+	return 0;
+}
+
+static int _ast_event_queue(struct ast_event *event, unsigned int cache)
+{
+	struct ast_event_ref *event_ref;
+	uint16_t host_event_type;
+	int res;
+
+	host_event_type = ntohs(event->type);
+
+	/* Invalid type */
+	if (host_event_type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
+			"type '%d'!\n", host_event_type);
+		return -1;
+	}
+
+	/* If nobody has subscribed to this event type, throw it away now */
+	if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
+			== AST_EVENT_SUB_NONE) {
+		ast_event_destroy(event);
+		return 0;
+	}
+
+	if (!(event_ref = alloc_event_ref())) {
+		return -1;
+	}
+
+	event_ref->event = event;
+	event_ref->cache = cache;
+
+	res = ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
+	if (res) {
+		event_ref->event = NULL;
+		ao2_ref(event_ref, -1);
+	}
+	return res;
+}
+
+int ast_event_queue(struct ast_event *event)
+{
+	return _ast_event_queue(event, 0);
+}
+
+int ast_event_queue_and_cache(struct ast_event *event)
+{
+	return _ast_event_queue(event, 1);
+}
+
+static int ast_event_hash_mwi(const void *obj, const int flags)
+{
+	const struct ast_event *event = obj;
+	const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+	const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
+
+	return ast_str_hash_add(context, ast_str_hash(mailbox));
+}
+
+/*!
+ * \internal
+ * \brief Hash function for AST_EVENT_DEVICE_STATE
+ *
+ * \param[in] obj an ast_event
+ * \param[in] flags unused
+ *
+ * \return hash value
+ */
+static int ast_event_hash_devstate(const void *obj, const int flags)
+{
+	const struct ast_event *event = obj;
+
+	return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
+}
+
+/*!
+ * \internal
+ * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
+ *
+ * \param[in] obj an ast_event
+ * \param[in] flags unused
+ *
+ * \return hash value
+ */
+static int ast_event_hash_devstate_change(const void *obj, const int flags)
+{
+	const struct ast_event *event = obj;
+
+	return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
+}
+
+/*!
+ * \internal
+ * \brief Hash function for AST_EVENT_PRESENCE_STATE
+ *
+ * \param[in] obj an ast_event
+ * \param[in] flags unused
+ *
+ * \return hash value
+ */
+static int ast_event_hash_presence_state_change(const void *obj, const int flags)
+{
+	const struct ast_event *event = obj;
+
+	return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER));
+}
+
+static int ast_event_hash(const void *obj, const int flags)
+{
+	const struct ast_event_ref *event_ref;
+	const struct ast_event *event;
+	ao2_hash_fn *hash_fn;
+
+	event_ref = obj;
+	event = event_ref->event;
+
+	if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
+		return 0;
+	}
+
+	return hash_fn(event, flags);
+}
+
+/*!
+ * \internal
+ * \brief Compare two events
+ *
+ * \param[in] obj the first event, as an ast_event_ref
+ * \param[in] arg the second event, as an ast_event_ref
+ * \param[in] flags unused
+ *
+ * \pre Both events must be the same type.
+ * \pre The event type must be declared as a cached event type in ast_event_cache
+ *
+ * \details This function takes two events, and determines if they are considered
+ * equivalent.  The values of information elements specified in the cache arguments
+ * for the event type are used to determine if the events are equivalent.
+ *
+ * \retval 0 No match
+ * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
+ */
+static int ast_event_cmp(void *obj, void *arg, int flags)
+{
+	struct ast_event_ref *event_ref, *event_ref2;
+	struct ast_event *event, *event2;
+	int res = CMP_MATCH;
+	int i;
+	enum ast_event_ie_type *cache_args;
+
+	event_ref = obj;
+	event = event_ref->event;
+
+	event_ref2 = arg;
+	event2 = event_ref2->event;
+
+	cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
+
+	for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
+		struct ast_event_ie_val ie_val = {
+			.ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
+			.ie_type = cache_args[i],
+		};
+
+		if (!match_ie_val(event, &ie_val, event2)) {
+			res = 0;
+			break;
+		}
+	}
+
+	return res;
+}
+
+static void dump_raw_ie(struct ast_event_iterator *i, struct ast_cli_args *a)
+{
+	char eid_buf[32];
+	enum ast_event_ie_type ie_type;
+	const char *ie_type_name;
+
+	ie_type = ast_event_iterator_get_ie_type(i);
+	ie_type_name = ast_event_get_ie_type_name(ie_type);
+
+	switch (ie_type) {
+	case AST_EVENT_IE_EID:
+		ast_eid_to_str(eid_buf, sizeof(eid_buf), ast_event_iterator_get_ie_raw(i));
+		ast_cli(a->fd, "%.30s: %s\n", ie_type_name, eid_buf);
+		break;
+	default:
+		ast_cli(a->fd, "%s\n", ie_type_name);
+		break;
+	}
+}
+
+static int event_dump_cli(void *obj, void *arg, int flags)
+{
+	const struct ast_event_ref *event_ref = obj;
+	const struct ast_event *event = event_ref->event;
+	struct ast_cli_args *a = arg;
+	struct ast_event_iterator i;
+
+	if (ast_event_iterator_init(&i, event)) {
+		ast_cli(a->fd, "Failed to initialize event iterator.  :-(\n");
+		return 0;
+	}
+
+	ast_cli(a->fd, "Event: %s\n", ast_event_get_type_name(event));
+
+	do {
+		enum ast_event_ie_type ie_type;
+		enum ast_event_ie_pltype ie_pltype;
+		const char *ie_type_name;
+
+		ie_type = ast_event_iterator_get_ie_type(&i);
+		ie_type_name = ast_event_get_ie_type_name(ie_type);
+		ie_pltype = ast_event_get_ie_pltype(ie_type);
+
+		switch (ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			ast_cli(a->fd, "%s\n", ie_type_name);
+			break;
+		case AST_EVENT_IE_PLTYPE_STR:
+			ast_cli(a->fd, "%.30s: %s\n", ie_type_name,
+					ast_event_iterator_get_ie_str(&i));
+			break;
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
+					ast_event_iterator_get_ie_uint(&i));
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
+					ast_event_iterator_get_ie_bitflags(&i));
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+			dump_raw_ie(&i, a);
+			break;
+		}
+	} while (!ast_event_iterator_next(&i));
+
+	ast_cli(a->fd, "\n");
+
+	return 0;
+}
+
+static char *event_dump_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	enum ast_event_type event_type;
+	enum ast_event_ie_type *cache_args;
+	int i;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "event dump cache";
+		e->usage =
+			"Usage: event dump cache <event type>\n"
+			"       Dump all of the cached events for the given event type.\n"
+			"       This is primarily intended for debugging.\n";
+		return NULL;
+	case CLI_GENERATE:
+		if (a->pos == 3) {
+			return ast_cli_complete(a->word, cached_event_types, a->n);
+		}
+		return NULL;
+	case CLI_HANDLER:
+		break;
+	}
+
+	if (a->argc != e->args + 1) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ast_event_str_to_event_type(a->argv[e->args], &event_type)) {
+		ast_cli(a->fd, "Invalid cached event type: '%s'\n", a->argv[e->args]);
+		return CLI_SHOWUSAGE;
+	}
+
+	if (!ast_event_cache[event_type].container) {
+		ast_cli(a->fd, "Event type '%s' has no cache.\n", a->argv[e->args]);
+		return CLI_SUCCESS;
+	}
+
+	ast_cli(a->fd, "Event Type: %s\n", a->argv[e->args]);
+	ast_cli(a->fd, "Cache Unique Keys:\n");
+	cache_args = ast_event_cache[event_type].cache_args;
+	for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
+		ast_cli(a->fd, "--> %s\n", ast_event_get_ie_type_name(cache_args[i]));
+	}
+
+	ast_cli(a->fd, "\n--- Begin Cache Dump ---\n\n");
+	ao2_callback(ast_event_cache[event_type].container, OBJ_NODATA, event_dump_cli, a);
+	ast_cli(a->fd, "--- End Cache Dump ---\n\n");
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry event_cli[] = {
+	AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
+};
+
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void event_shutdown(void)
+{
+	struct ast_event_sub *sub;
+	int i;
+
+	ast_cli_unregister_multiple(event_cli, ARRAY_LEN(event_cli));
+
+	if (event_dispatcher) {
+		event_dispatcher = ast_taskprocessor_unreference(event_dispatcher);
+	}
+
+	/* Remove any remaining subscriptions.  Note that we can't just call
+	 * unsubscribe, as it will attempt to lock the subscription list
+	 * as well */
+	for (i = 0; i < AST_EVENT_TOTAL; i++) {
+		AST_RWDLLIST_WRLOCK(&ast_event_subs[i]);
+		while ((sub = AST_RWDLLIST_REMOVE_HEAD(&ast_event_subs[i], entry))) {
+			ast_event_sub_destroy(sub);
+		}
+		AST_RWDLLIST_UNLOCK(&ast_event_subs[i]);
+		AST_RWDLLIST_HEAD_DESTROY(&ast_event_subs[i]);
+	}
+
+	for (i = 0; i < AST_EVENT_TOTAL; i++) {
+		if (!ast_event_cache[i].hash_fn) {
+			continue;
+		}
+		if (ast_event_cache[i].container) {
+			ao2_ref(ast_event_cache[i].container, -1);
+		}
+	}
+}
+
+int ast_event_init(void)
+{
+	int i;
+
+	for (i = 0; i < AST_EVENT_TOTAL; i++) {
+		AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
+	}
+
+	for (i = 0; i < AST_EVENT_TOTAL; i++) {
+		if (!ast_event_cache[i].hash_fn) {
+			/* This event type is not cached. */
+			continue;
+		}
+
+		if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
+				ast_event_hash, ast_event_cmp))) {
+			goto event_init_cleanup;
+		}
+	}
+
+	if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
+		goto event_init_cleanup;
+	}
+
+	ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
+
+	ast_register_cleanup(event_shutdown);
+
+	return 0;
+
+event_init_cleanup:
+	event_shutdown();
+	return -1;
+}
+
 size_t ast_event_minimum_length(void)
 {
 	return sizeof(struct ast_event);
diff --git a/main/features.c b/main/features.c
index ebb79b0..c0f4b8d 100644
--- a/main/features.c
+++ b/main/features.c
@@ -24,22 +24,13 @@
  * \author Mark Spencer <markster at digium.com>
  */
 
-/*! \li \ref features.c uses the configuration file \ref features.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page features.conf features.conf
- * \verbinclude features.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427737 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -70,14 +61,58 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427737 $")
 #include "asterisk/audiohook.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/astobj2.h"
+#include "asterisk/cel.h"
 #include "asterisk/test.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_features.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/features_config.h"
+
+/*
+ * Party A - transferee
+ * Party B - transferer
+ * Party C - target of transfer
+ *
+ * DTMF attended transfer works within the channel bridge.
+ * Unfortunately, when either party A or B in the channel bridge
+ * hangs up, that channel is not completely hung up until the
+ * transfer completes.  This is a real problem depending upon
+ * the channel technology involved.
+ *
+ * For chan_dahdi, the channel is crippled until the hangup is
+ * complete.  Either the channel is not useable (analog) or the
+ * protocol disconnect messages are held up (PRI/BRI/SS7) and
+ * the media is not released.
+ *
+ * For chan_sip, a call limit of one is going to block that
+ * endpoint from any further calls until the hangup is complete.
+ *
+ * For party A this is a minor problem.  The party A channel
+ * will only be in this condition while party B is dialing and
+ * when party B and C are conferring.  The conversation between
+ * party B and C is expected to be a short one.  Party B is
+ * either asking a question of party C or announcing party A.
+ * Also party A does not have much incentive to hangup at this
+ * point.
+ *
+ * For party B this can be a major problem during a blonde
+ * transfer.  (A blonde transfer is our term for an attended
+ * transfer that is converted into a blind transfer. :))  Party
+ * B could be the operator.  When party B hangs up, he assumes
+ * that he is out of the original call entirely.  The party B
+ * channel will be in this condition while party C is ringing,
+ * while attempting to recall party B, and while waiting between
+ * call attempts.
+ *
+ * WARNING:
+ * The ATXFER_NULL_TECH conditional is a hack to fix the
+ * problem.  It will replace the party B channel technology with
+ * a NULL channel driver.  The consequences of this code is that
+ * the 'h' extension will not be able to access any channel
+ * technology specific information like SIP statistics for the
+ * call.
+ *
+ * Uncomment the ATXFER_NULL_TECH define below to replace the
+ * party B channel technology in the channel bridge to complete
+ * hanging up the channel technology.
+ */
+//#define ATXFER_NULL_TECH	1
 
 /*** DOCUMENTATION
 	<application name="Bridge" language="en_US">
@@ -204,6 +239,152 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427737 $")
 			</variablelist>
 		</description>
 	</application>
+	<application name="ParkedCall" language="en_US">
+		<synopsis>
+			Retrieve a parked call.
+		</synopsis>
+		<syntax>
+			<parameter name="exten">
+				<para>Parking space extension to retrieve a parked call.
+				If not provided then the first available parked call in the
+				parking lot will be retrieved.</para>
+			</parameter>
+			<parameter name="parking_lot_name">
+				<para>Specify from which parking lot to retrieve a parked call.</para>
+				<para>The parking lot used is selected in the following order:</para>
+				<para>1) parking_lot_name option</para>
+				<para>2) <variable>PARKINGLOT</variable> variable</para>
+				<para>3) <literal>CHANNEL(parkinglot)</literal> function
+				(Possibly preset by the channel driver.)</para>
+				<para>4) Default parking lot.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Used to retrieve a parked call from a parking lot.</para>
+			<note>
+				<para>Parking lots automatically create and manage dialplan extensions in
+				the parking lot context.  You do not need to explicitly use this
+				application in your dialplan.  Instead, all you should do is include the
+				parking lot context in your dialplan.</para>
+			</note>
+		</description>
+		<see-also>
+			<ref type="application">Park</ref>
+			<ref type="application">ParkAndAnnounce</ref>
+		</see-also>
+	</application>
+	<application name="Park" language="en_US">
+		<synopsis>
+			Park yourself.
+		</synopsis>
+		<syntax>
+			<parameter name="timeout">
+				<para>A custom parking timeout for this parked call. Value in milliseconds.</para>
+			</parameter>
+			<parameter name="return_context">
+				<para>The context to return the call to after it times out.</para>
+			</parameter>
+			<parameter name="return_exten">
+				<para>The extension to return the call to after it times out.</para>
+			</parameter>
+			<parameter name="return_priority">
+				<para>The priority to return the call to after it times out.</para>
+			</parameter>
+			<parameter name="options">
+				<para>A list of options for this parked call.</para>
+				<optionlist>
+					<option name="r">
+						<para>Send ringing instead of MOH to the parked call.</para>
+					</option>
+					<option name="R">
+						<para>Randomize the selection of a parking space.</para>
+					</option>
+					<option name="s">
+						<para>Silence announcement of the parking space number.</para>
+					</option>
+				</optionlist>
+			</parameter>
+			<parameter name="parking_lot_name">
+				<para>Specify in which parking lot to park a call.</para>
+				<para>The parking lot used is selected in the following order:</para>
+				<para>1) parking_lot_name option</para>
+				<para>2) <variable>PARKINGLOT</variable> variable</para>
+				<para>3) <literal>CHANNEL(parkinglot)</literal> function
+				(Possibly preset by the channel driver.)</para>
+				<para>4) Default parking lot.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Used to park yourself (typically in combination with a supervised
+			transfer to know the parking space).</para>
+			<para>If you set the <variable>PARKINGEXTEN</variable> variable to a
+			parking space extension in the parking lot, Park() will attempt to park the call
+			on that extension.  If the extension is already is in use then execution
+			will continue at the next priority.</para>
+			<para>If the <literal>parkeddynamic</literal> option is enabled in <filename>features.conf</filename>
+			the following variables can be used to dynamically create new parking lots.</para>
+			<para>If you set the <variable>PARKINGDYNAMIC</variable> variable and this parking lot
+			exists then it will be used as a template for the newly created dynamic lot.  Otherwise,
+			the default parking lot will be used.</para>
+			<para>If you set the <variable>PARKINGDYNCONTEXT</variable> variable then the newly created dynamic
+			parking lot will use this context.</para>
+			<para>If you set the <variable>PARKINGDYNEXTEN</variable> variable then the newly created dynamic
+			parking lot will use this extension to access the parking lot.</para>
+			<para>If you set the <variable>PARKINGDYNPOS</variable> variable then the newly created dynamic parking lot
+			will use those parking postitions.</para>
+			<note>
+				<para>This application must be used as the first extension priority
+				to be recognized as a parking access extension.  DTMF transfers
+				and some channel drivers need this distinction to operate properly.
+				The parking access extension in this case is treated like a dialplan
+				hint.</para>
+			</note>
+			<note>
+				<para>Parking lots automatically create and manage dialplan extensions in
+				the parking lot context.  You do not need to explicitly use this
+				application in your dialplan.  Instead, all you should do is include the
+				parking lot context in your dialplan.</para>
+			</note>
+		</description>
+		<see-also>
+			<ref type="application">ParkAndAnnounce</ref>
+			<ref type="application">ParkedCall</ref>
+		</see-also>
+	</application>
+	<manager name="ParkedCalls" language="en_US">
+		<synopsis>
+			List parked calls.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+		</syntax>
+		<description>
+			<para>List parked calls.</para>
+		</description>
+	</manager>
+	<manager name="Park" language="en_US">
+		<synopsis>
+			Park a channel.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Channel" required="true">
+				<para>Channel name to park.</para>
+			</parameter>
+			<parameter name="Channel2" required="true">
+				<para>Channel to return to if timeout.</para>
+			</parameter>
+			<parameter name="Timeout">
+				<para>Number of milliseconds to wait before callback.</para>
+			</parameter>
+			<parameter name="Parkinglot">
+				<para>Specify in which parking lot to park the channel.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Park a channel.</para>
+		</description>
+	</manager>
 	<manager name="Bridge" language="en_US">
 		<synopsis>
 			Bridge two channels already in the PBX.
@@ -219,10 +400,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427737 $")
 			<parameter name="Tone">
 				<para>Play courtesy tone to Channel 2.</para>
 				<enumlist>
+					<enum name="yes" />
 					<enum name="no" />
-					<enum name="Channel1" />
-					<enum name="Channel2" />
-					<enum name="Both" />
 				</enumlist>
 			</parameter>
 		</syntax>
@@ -230,14 +409,380 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427737 $")
 			<para>Bridge together two channels already in the PBX.</para>
 		</description>
 	</manager>
+	<manager name="Parkinglots" language="en_US">
+		<synopsis>
+			Get a list of parking lots
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+		</syntax>
+		<description>
+			<para>List all parking lots as a series of AMI events</para>
+		</description>
+	</manager>
+	<function name="FEATURE" language="en_US">
+		<synopsis>
+			Get or set a feature option on a channel.
+		</synopsis>
+		<syntax>
+			<parameter name="option_name" required="true">
+				<para>The allowed values are:</para>
+				<enumlist>
+					<enum name="parkingtime"><para>Specified in seconds.</para></enum>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>When this function is used as a read, it will get the current
+			value of the specified feature option for this channel.  It will be
+			the value of this option configured in features.conf if a channel specific
+			value has not been set.  This function can also be used to set a channel
+			specific value for the supported feature options.</para>
+		</description>
+		<see-also>
+			<ref type="function">FEATUREMAP</ref>
+		</see-also>
+	</function>
+	<function name="FEATUREMAP" language="en_US">
+		<synopsis>
+			Get or set a feature map to a given value on a specific channel.
+		</synopsis>
+		<syntax>
+			<parameter name="feature_name" required="true">
+				<para>The allowed values are:</para>
+				<enumlist>
+					<enum name="atxfer"><para>Attended Transfer</para></enum>
+					<enum name="blindxfer"><para>Blind Transfer</para></enum>
+					<enum name="automon"><para>Auto Monitor</para></enum>
+					<enum name="disconnect"><para>Call Disconnect</para></enum>
+					<enum name="parkcall"><para>Park Call</para></enum>
+					<enum name="automixmon"><para>Auto MixMonitor</para></enum>
+				</enumlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>When this function is used as a read, it will get the current
+			digit sequence mapped to the specified feature for this channel.  This
+			value will be the one configured in features.conf if a channel specific
+			value has not been set.  This function can also be used to set a channel
+			specific value for a feature mapping.</para>
+		</description>
+		<see-also>
+			<ref type="function">FEATURE</ref>
+		</see-also>
+	</function>
+	<managerEvent language="en_US" name="ParkedCallTimeOut">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a parked call times out.</synopsis>
+			<syntax>
+				<parameter name="Exten">
+					<para>The parking lot extension.</para>
+				</parameter>
+				<parameter name="Channel"/>
+				<parameter name="Parkinglot">
+					<para>The name of the parking lot.</para>
+				</parameter>
+				<parameter name="CallerIDNum"/>
+				<parameter name="CallerIDName"/>
+				<parameter name="ConnectedLineNum"/>
+				<parameter name="ConnectedLineName"/>
+				<parameter name="UniqueID"/>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ParkedCall</ref>
+			</see-also>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="ParkedCallGiveUp">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a parked call hangs up while in the parking lot.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Exten'])" />
+				<parameter name="Channel"/>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
+				<parameter name="CallerIDNum"/>
+				<parameter name="CallerIDName"/>
+				<parameter name="ConnectedLineNum"/>
+				<parameter name="ConnectedLineName"/>
+				<parameter name="UniqueID"/>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ParkedCall</ref>
+			</see-also>
+		</managerEventInstance>
+	</managerEvent>
  ***/
 
+#define DEFAULT_PARK_TIME							45000	/*!< ms */
+#define DEFAULT_PARK_EXTENSION						"700"
+#define DEFAULT_TRANSFER_DIGIT_TIMEOUT				3000	/*!< ms */
+#define DEFAULT_FEATURE_DIGIT_TIMEOUT				1000	/*!< ms */
+#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER	15000	/*!< ms */
+#define DEFAULT_ATXFER_DROP_CALL					0		/*!< Do not drop call. */
+#define DEFAULT_ATXFER_LOOP_DELAY					10000	/*!< ms */
+#define DEFAULT_ATXFER_CALLBACK_RETRIES				2
+#define DEFAULT_COMEBACK_CONTEXT					"parkedcallstimeout"
+#define DEFAULT_COMEBACK_TO_ORIGIN					1
+#define DEFAULT_COMEBACK_DIAL_TIME					30
+
+#define AST_MAX_WATCHERS 256
+#define MAX_DIAL_FEATURE_OPTIONS 30
+
+struct feature_group_exten {
+	AST_LIST_ENTRY(feature_group_exten) entry;
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(exten);
+	);
+	struct ast_call_feature *feature;
+};
+
+struct feature_group {
+	AST_LIST_ENTRY(feature_group) entry;
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(gname);
+	);
+	AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
+};
+
+static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
+
 typedef enum {
 	FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
 	FEATURE_INTERPRET_DO,     /* Used by feature_interpret */
 	FEATURE_INTERPRET_CHECK,  /* Used by feature_check */
 } feature_interpret_op;
 
+static const char *parkedcall = "ParkedCall";
+
+static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
+
+/*! Parking lot access ramp dialplan usage entry. */
+struct parking_dp_ramp {
+	/*! Next node in the parking lot spaces dialplan list. */
+	AST_LIST_ENTRY(parking_dp_ramp) node;
+	/*! TRUE if the parking lot access extension is exclusive. */
+	unsigned int exclusive:1;
+	/*! Parking lot access extension */
+	char exten[1];
+};
+
+/*! Parking lot dialplan access ramp map */
+AST_LIST_HEAD_NOLOCK(parking_dp_ramp_map, parking_dp_ramp);
+
+/*! Parking lot spaces dialplan usage entry. */
+struct parking_dp_spaces {
+	/*! Next node in the parking lot spaces dialplan list. */
+	AST_LIST_ENTRY(parking_dp_spaces) node;
+	/*! First parking space */
+	int start;
+	/*! Last parking space */
+	int stop;
+};
+
+/*! Parking lot dialplan context space map */
+AST_LIST_HEAD_NOLOCK(parking_dp_space_map, parking_dp_spaces);
+
+/*! Parking lot context dialplan usage entry. */
+struct parking_dp_context {
+	/*! Next node in the parking lot contexts dialplan list. */
+	AST_LIST_ENTRY(parking_dp_context) node;
+	/*! Parking access extensions defined in this context. */
+	struct parking_dp_ramp_map access_extens;
+	/*! Parking spaces defined in this context. */
+	struct parking_dp_space_map spaces;
+	/*! Parking hints defined in this context. */
+	struct parking_dp_space_map hints;
+	/*! Parking lot context name */
+	char context[1];
+};
+
+/*! Parking lot dialplan usage map. */
+AST_LIST_HEAD_NOLOCK(parking_dp_map, parking_dp_context);
+
+/*!
+ * \brief Description of one parked call, added to a list while active, then removed.
+ * The list belongs to a parkinglot.
+ */
+struct parkeduser {
+	struct ast_channel *chan;                   /*!< Parked channel */
+	struct timeval start;                       /*!< Time the park started */
+	int parkingnum;                             /*!< Parking lot space used */
+	char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
+	char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
+	char exten[AST_MAX_EXTENSION];
+	int priority;
+	unsigned int parkingtime;                   /*!< Maximum length in parking lot before return */
+	/*! Method to entertain the caller when parked: AST_CONTROL_RINGING, AST_CONTROL_HOLD, or 0(none) */
+	enum ast_control_frame_type hold_method;
+	unsigned int notquiteyet:1;
+	unsigned int options_specified:1;
+	char peername[AST_CHANNEL_NAME];
+	unsigned char moh_trys;
+	/*! Parking lot this entry belongs to.  Holds a parking lot reference. */
+	struct ast_parkinglot *parkinglot;
+	AST_LIST_ENTRY(parkeduser) list;
+};
+
+/*! Parking lot configuration options. */
+struct parkinglot_cfg {
+	/*! Music class used for parking */
+	char mohclass[MAX_MUSICCLASS];
+	/*! Extension to park calls in this parking lot. */
+	char parkext[AST_MAX_EXTENSION];
+	/*! Context for which parking is made accessible */
+	char parking_con[AST_MAX_CONTEXT];
+	/*! Context that timed-out parked calls are called back on when comebacktoorigin=no */
+	char comebackcontext[AST_MAX_CONTEXT];
+	/*! First available extension for parking */
+	int parking_start;
+	/*! Last available extension for parking */
+	int parking_stop;
+	/*! Default parking time in ms. */
+	unsigned int parkingtime;
+	/*!
+	 * \brief Enable DTMF based transfers on bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcalltransfers;
+	/*!
+	 * \brief Enable DTMF based parking on bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallreparking;
+	/*!
+	 * \brief Enable DTMF based hangup on a bridge when pickup up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallhangup;
+	/*!
+	 * \brief Enable DTMF based recording on a bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallrecording;
+
+	/*! Time in seconds to dial the device that parked a timedout parked call */
+	unsigned int comebackdialtime;
+	/*! TRUE if findslot is set to next */
+	unsigned int parkfindnext:1;
+	/*! TRUE if the parking lot is exclusively accessed by parkext */
+	unsigned int parkext_exclusive:1;
+	/*! Add parking hints automatically */
+	unsigned int parkaddhints:1;
+	/*! TRUE if configuration is invalid and the parking lot should not be used. */
+	unsigned int is_invalid:1;
+	/*! TRUE if a timed out parked call goes back to the parker */
+	unsigned int comebacktoorigin:1;
+};
+
+/*! \brief Structure for parking lots which are put in a container. */
+struct ast_parkinglot {
+	/*! Name of the parking lot. */
+	char name[AST_MAX_CONTEXT];
+	/*! Parking lot user configuration. */
+	struct parkinglot_cfg cfg;
+
+	/*! Parking space to start next park search. */
+	int next_parking_space;
+
+	/*! That which bears the_mark shall be deleted if parking lot empty! (Used during reloads.) */
+	unsigned int the_mark:1;
+	/*! TRUE if the parking lot is disabled. */
+	unsigned int disabled:1;
+
+	/*! List of active parkings in this parkinglot */
+	AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
+};
+
+/*! \brief The configured parking lots container. Always at least one  - the default parking lot */
+static struct ao2_container *parkinglots;
+
+/*!
+ * \brief Default parking lot.
+ * \note Holds a parkinglot reference.
+ * \note Will not be NULL while running.
+ */
+static struct ast_parkinglot *default_parkinglot;
+
+/*! Force a config reload to reload regardless of config file timestamp. */
+static int force_reload_load;
+
+static int parkedplay = 0;                                 /*!< Who to play courtesytone to when someone picks up a parked call. */
+static int parkeddynamic = 0;                              /*!< Enable creation of parkinglots dynamically */
+static char courtesytone[256];                             /*!< Courtesy tone used to pickup parked calls and on-touch-record */
+static char xfersound[256];                                /*!< Call transfer sound */
+static char xferfailsound[256];                            /*!< Call transfer failure sound */
+static char pickupsound[256];                              /*!< Pickup sound */
+static char pickupfailsound[256];                          /*!< Pickup failure sound */
+
+/*!
+ * \brief Context for parking dialback to parker.
+ * \note The need for the context is a KLUDGE.
+ *
+ * \todo Might be able to eliminate the parking_con_dial context
+ * kludge by running app_dial directly in its own thread to
+ * simulate a PBX.
+ */
+static char parking_con_dial[] = "park-dial";
+
+/*! Ensure that features.conf reloads on one thread at a time. */
+AST_MUTEX_DEFINE_STATIC(features_reload_lock);
+
+static int adsipark;
+
+static int transferdigittimeout;
+static int featuredigittimeout;
+
+static int atxfernoanswertimeout;
+static unsigned int atxferdropcall;
+static unsigned int atxferloopdelay;
+static unsigned int atxfercallbackretries;
+
+static char *registrar = "features";		   /*!< Registrar for operations */
+
+/*! PARK_APP_NAME application arguments */
+AST_DEFINE_APP_ARGS_TYPE(park_app_args,
+	AST_APP_ARG(timeout);		/*!< Time in ms to remain in the parking lot. */
+	AST_APP_ARG(return_con);	/*!< Context to return parked call if timeout. */
+	AST_APP_ARG(return_ext);	/*!< Exten to return parked call if timeout. */
+	AST_APP_ARG(return_pri);	/*!< Priority to return parked call if timeout. */
+	AST_APP_ARG(options);		/*!< Parking option flags. */
+	AST_APP_ARG(pl_name);		/*!< Parking lot name to use if present. */
+	AST_APP_ARG(dummy);			/*!< Place to put any remaining args string. */
+	);
+
+/* module and CLI command definitions */
+static const char *parkcall = "Park";
+
+static struct ast_app *monitor_app = NULL;
+static int monitor_ok = 1;
+
+static struct ast_app *mixmonitor_app = NULL;
+static int mixmonitor_ok = 1;
+
+static struct ast_app *stopmixmonitor_app = NULL;
+static int stopmixmonitor_ok = 1;
+
+static pthread_t parking_thread;
 struct ast_dial_features {
 	/*! Channel's feature flags. */
 	struct ast_flags my_features;
@@ -245,6 +790,81 @@ struct ast_dial_features {
 	struct ast_flags peer_features;
 };
 
+#if defined(ATXFER_NULL_TECH)
+/*!
+ * \internal
+ * \brief Set the channel technology to the kill technology.
+ *
+ * \param chan Channel to change technology.
+ *
+ * \return Nothing
+ */
+static void set_kill_chan_tech(struct ast_channel *chan)
+{
+	int idx;
+
+	ast_channel_lock(chan);
+
+	/* Hangup the channel's physical side */
+	if (ast_channel_tech(chan)->hangup) {
+		ast_channel_tech(chan)->hangup(chan);
+	}
+	if (ast_channel_tech_pvt(chan)) {
+		ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n",
+			ast_channel_name(chan));
+		ast_free(ast_channel_tech_pvt(chan));
+		ast_channel_tech_pvt_set(chan, NULL);
+	}
+
+	/* Install the kill technology and wake up anyone waiting on it. */
+	ast_channel_tech_set(chan, &ast_kill_tech);
+	for (idx = 0; idx < AST_MAX_FDS; ++idx) {
+		switch (idx) {
+		case AST_ALERT_FD:
+		case AST_TIMING_FD:
+		case AST_GENERATOR_FD:
+			/* Don't clear these fd's. */
+			break;
+		default:
+			ast_channel_set_fd(chan, idx, -1);
+			break;
+		}
+	}
+	ast_queue_frame(chan, &ast_null_frame);
+
+	ast_channel_unlock(chan);
+}
+#endif	/* defined(ATXFER_NULL_TECH) */
+
+#if defined(ATXFER_NULL_TECH)
+/*!
+ * \internal
+ * \brief Set the channel name to something unique.
+ *
+ * \param chan Channel to change name.
+ *
+ * \return Nothing
+ */
+static void set_new_chan_name(struct ast_channel *chan)
+{
+	static int seq_num_last;
+	int seq_num;
+	int len;
+	char *chan_name;
+	char dummy[1];
+
+	/* Create the new channel name string. */
+	ast_channel_lock(chan);
+	seq_num = ast_atomic_fetchadd_int(&seq_num_last, +1);
+	len = snprintf(dummy, sizeof(dummy), "%s<XFER_%x>", ast_channel_name(chan), seq_num) + 1;
+	chan_name = ast_alloca(len);
+	snprintf(chan_name, len, "%s<XFER_%x>", ast_channel_name(chan), seq_num);
+	ast_channel_unlock(chan);
+
+	ast_change_name(chan, chan_name);
+}
+#endif	/* defined(ATXFER_NULL_TECH) */
+
 static void *dial_features_duplicate(void *data)
 {
 	struct ast_dial_features *df = data, *df_copy;
@@ -258,9 +878,17 @@ static void *dial_features_duplicate(void *data)
 	return df_copy;
 }
 
+static void dial_features_destroy(void *data)
+{
+	struct ast_dial_features *df = data;
+	if (df) {
+		ast_free(df);
+	}
+}
+
 static const struct ast_datastore_info dial_features_info = {
 	.type = "dial-features",
-	.destroy = ast_free_ptr,
+	.destroy = dial_features_destroy,
 	.duplicate = dial_features_duplicate,
 };
 
@@ -309,6 +937,57 @@ static int add_features_datastore(struct ast_channel *chan, const struct ast_fla
 	return 0;
 }
 
+/* Forward declarations */
+static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
+static void parkinglot_unref(struct ast_parkinglot *parkinglot);
+static struct ast_parkinglot *find_parkinglot(const char *name);
+static struct ast_parkinglot *create_parkinglot(const char *name);
+static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
+static int parkinglot_activate(struct ast_parkinglot *parkinglot);
+static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile);
+
+/*!
+ * \internal
+ * \brief Get the parking extension if it exists.
+ *
+ * \param exten_str Parking extension to see if exists.
+ * \param chan Channel to autoservice while looking for exten.  (Could be NULL)
+ * \param context Parking context to look in for exten.
+ *
+ * \retval exten on success.
+ * \retval NULL on error or exten does not exist.
+ */
+static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
+{
+	struct ast_exten *exten;
+	struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+	const char *app_at_exten;
+
+	ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
+	exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
+		E_MATCH);
+	if (!exten) {
+		return NULL;
+	}
+
+	app_at_exten = ast_get_extension_app(exten);
+	if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
+		return NULL;
+	}
+
+	return exten;
+}
+
+int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
+{
+	return get_parking_exten(exten_str, chan, context) ? 1 : 0;
+}
+
+const char *ast_pickup_ext(void)
+{
+	return pickup_ext;
+}
+
 struct ast_bridge_thread_obj
 {
 	struct ast_bridge_config bconfig;
@@ -318,875 +997,8123 @@ struct ast_bridge_thread_obj
 	unsigned int return_to_pbx:1;
 };
 
-static const struct ast_datastore_info channel_app_data_datastore = {
-	.type = "Channel appdata datastore",
-	.destroy = ast_free_ptr,
-};
-
-static void set_config_flags(struct ast_channel *chan, struct ast_bridge_config *config)
+static int parkinglot_hash_cb(const void *obj, const int flags)
 {
-	ast_clear_flag(config, AST_FLAGS_ALL);
-
-	if (ast_test_flag(&config->features_caller, AST_FEATURE_DTMF_MASK)) {
-		ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
-	}
-	if (ast_test_flag(&config->features_callee, AST_FEATURE_DTMF_MASK)) {
-		ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
-	}
-
-	if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
-		RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
+	const struct ast_parkinglot *parkinglot = obj;
 
-		ast_channel_lock(chan);
-		applicationmap = ast_get_chan_applicationmap(chan);
-		ast_channel_unlock(chan);
+	return ast_str_case_hash(parkinglot->name);
+}
 
-		if (!applicationmap) {
-			return;
-		}
+static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct ast_parkinglot *parkinglot = obj;
+	struct ast_parkinglot *parkinglot2 = arg;
 
-		/* If an applicationmap exists for this channel at all, then the channel needs the DTMF flag set */
-		ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
-	}
+	return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
-void ast_channel_log(char *title, struct ast_channel *chan);
-
-void ast_channel_log(char *title, struct ast_channel *chan) /* for debug, this is handy enough to justify keeping it in the source */
+/*!
+ * \brief store context, extension and priority
+ * \param chan, context, ext, pri
+ */
+static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
 {
-	ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan);
-	ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
-		ast_channel_name(chan), ast_channel_appl(chan), ast_channel_data(chan),
-		ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
-	ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
-		ast_channel_accountcode(chan), ast_channel_dialcontext(chan), ast_channel_amaflags(chan),
-		ast_channel_macrocontext(chan), ast_channel_macroexten(chan), ast_channel_macropriority(chan));
-	ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; uniqueID: %s; linkedID:%s\n",
-		ast_channel_masq(chan), ast_channel_masqr(chan),
-		ast_channel_uniqueid(chan), ast_channel_linkedid(chan));
-	if (ast_channel_masqr(chan)) {
-		ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
-			ast_channel_name(ast_channel_masqr(chan)), ast_channel_cdr(ast_channel_masqr(chan)));
-	}
-
-	ast_log(LOG_NOTICE, "===== done ====\n");
+	ast_channel_context_set(chan, context);
+	ast_channel_exten_set(chan, ext);
+	ast_channel_priority_set(chan, pri);
 }
 
-static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
+/*!
+ * \brief Check goto on transfer
+ * \param chan
+ *
+ * Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit.
+ * When found make sure the types are compatible. Check if channel is valid
+ * if so start the new channel else hangup the call.
+ */
+static void check_goto_on_transfer(struct ast_channel *chan)
 {
-	const char *feature;
+	struct ast_channel *xferchan;
+	const char *val;
+	char *goto_on_transfer;
+	char *x;
 
-	if (ast_strlen_zero(features)) {
+	ast_channel_lock(chan);
+	val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
+	if (ast_strlen_zero(val)) {
+		ast_channel_unlock(chan);
 		return;
 	}
+	goto_on_transfer = ast_strdupa(val);
+	ast_channel_unlock(chan);
 
-	for (feature = features; *feature; feature++) {
-		struct ast_flags *party;
+	ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, ast_channel_name(chan));
 
-		if (isupper(*feature)) {
-			party = &config->features_caller;
-		} else {
-			party = &config->features_callee;
-		}
+	xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(chan), 0,
+		"%s", ast_channel_name(chan));
+	if (!xferchan) {
+		return;
+	}
 
-		switch (tolower(*feature)) {
-		case 't' :
-			ast_set_flag(party, AST_FEATURE_REDIRECT);
-			break;
-		case 'k' :
-			ast_set_flag(party, AST_FEATURE_PARKCALL);
-			break;
-		case 'h' :
-			ast_set_flag(party, AST_FEATURE_DISCONNECT);
-			break;
-		case 'w' :
-			ast_set_flag(party, AST_FEATURE_AUTOMON);
-			break;
-		case 'x' :
-			ast_set_flag(party, AST_FEATURE_AUTOMIXMON);
-			break;
-		default :
-			ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
-			break;
-		}
-	}
-}
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(chan));
+	ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(chan));
 
-static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
-{
-	if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
-		/*
-		 * If we don't return here, then when we do a builtin_atxfer we
-		 * will copy the disconnect flags over from the atxfer to the
-		 * callee (Party C).
-		 */
+	if (ast_channel_masquerade(xferchan, chan)) {
+		/* Failed to setup masquerade. */
+		ast_hangup(xferchan);
 		return;
 	}
 
-	add_features_datastore(callee, &config->features_callee, &config->features_caller);
+	for (x = goto_on_transfer; *x; ++x) {
+		if (*x == '^') {
+			*x = ',';
+		}
+	}
+	ast_parseable_goto(xferchan, goto_on_transfer);
+	ast_channel_state_set(xferchan, AST_STATE_UP);
+	ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL);
+	ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
+
+	ast_do_masquerade(xferchan);
+	if (ast_pbx_start(xferchan)) {
+		/* Failed to start PBX. */
+		ast_hangup(xferchan);
+	}
 }
 
-static void clear_dialed_interfaces(struct ast_channel *chan)
+static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
+	const char *caller_name, struct ast_channel *requestor,
+	struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, const char *addr,
+	int timeout, int *outstate, const char *language);
+
+static const struct ast_datastore_info channel_app_data_datastore = {
+	.type = "Channel appdata datastore",
+	.destroy = ast_free_ptr,
+};
+
+static int set_chan_app_data(struct ast_channel *chan, const char *src_app_data)
 {
-	struct ast_datastore *di_datastore;
+	struct ast_datastore *datastore;
+	char *dst_app_data;
 
-	ast_channel_lock(chan);
-	if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
-		if (option_debug) {
-			ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
-		}
-		if (!ast_channel_datastore_remove(chan, di_datastore)) {
-			ast_datastore_free(di_datastore);
-		}
+	datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL);
+	if (!datastore) {
+		return -1;
 	}
-	ast_channel_unlock(chan);
+
+	dst_app_data = ast_malloc(strlen(src_app_data) + 1);
+	if (!dst_app_data) {
+		ast_datastore_free(datastore);
+		return -1;
+	}
+
+	ast_channel_data_set(chan, strcpy(dst_app_data, src_app_data));
+	datastore->data = dst_app_data;
+	ast_channel_datastore_add(chan, datastore);
+	return 0;
 }
 
-static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
+/*!
+ * \brief bridge the call
+ * \param data thread bridge.
+ *
+ * Set Last Data for respective channels, reset cdr for channels
+ * bridge call, check if we're going back to dialplan
+ * if not hangup both legs of the call
+ */
+static void *bridge_call_thread(void *data)
 {
-	if (config->end_sound) {
-		ast_string_field_set(limits, duration_sound, config->end_sound);
+	struct ast_bridge_thread_obj *tobj = data;
+
+	if (tobj->callid) {
+		ast_callid_threadassoc_add(tobj->callid);
+		/* Need to deref and set to null since ast_bridge_thread_obj has no common destructor */
+		tobj->callid = ast_callid_unref(tobj->callid);
 	}
 
-	if (config->warning_sound) {
-		ast_string_field_set(limits, warning_sound, config->warning_sound);
+	ast_channel_appl_set(tobj->chan, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge");
+	if (set_chan_app_data(tobj->chan, ast_channel_name(tobj->peer))) {
+		ast_channel_data_set(tobj->chan, "(Empty)");
 	}
+	ast_channel_appl_set(tobj->peer, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge");
+	if (set_chan_app_data(tobj->peer, ast_channel_name(tobj->chan))) {
+		ast_channel_data_set(tobj->peer, "(Empty)");
+	}
+
+	ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
 
-	if (config->start_sound) {
-		ast_string_field_set(limits, connect_sound, config->start_sound);
+	if (tobj->return_to_pbx) {
+		if (!ast_check_hangup(tobj->peer)) {
+			ast_verb(0, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer));
+			if (ast_pbx_start(tobj->peer)) {
+				ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer));
+				ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
+			}
+		} else {
+			ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
+		}
+		if (!ast_check_hangup(tobj->chan)) {
+			ast_verb(0, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
+			if (ast_pbx_start(tobj->chan)) {
+				ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan));
+				ast_hangup(tobj->chan);
+			}
+		} else {
+			ast_hangup(tobj->chan);
+		}
+	} else {
+		ast_hangup(tobj->chan);
+		ast_hangup(tobj->peer);
 	}
 
-	limits->frequency = config->warning_freq;
-	limits->warning = config->play_warning;
+	ast_free(tobj);
+
+	return NULL;
 }
 
 /*!
- * \internal brief Setup limit hook structures on calls that need limits
+ * \brief create thread for the parked call
+ * \param data
  *
- * \param config ast_bridge_config which provides the limit data
- * \param caller_limits pointer to an ast_bridge_features_limits struct which will store the caller side limits
- * \param callee_limits pointer to an ast_bridge_features_limits struct which will store the callee side limits
+ * Create thread and attributes, call bridge_call_thread
  */
-static void bridge_config_set_limits(struct ast_bridge_config *config, struct ast_bridge_features_limits *caller_limits, struct ast_bridge_features_limits *callee_limits)
+static void bridge_call_thread_launch(struct ast_bridge_thread_obj *data)
 {
-	if (ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING)) {
-		bridge_config_set_limits_warning_values(config, caller_limits);
+	pthread_t thread;
+	pthread_attr_t attr;
+	struct sched_param sched;
+
+	/* This needs to be unreffed once it has been associated with the new thread. */
+	data->callid = ast_read_threadstorage_callid();
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
+		/* Failed to create thread. Ditch the reference to callid. */
+		ast_callid_unref(data->callid);
+		ast_hangup(data->chan);
+		ast_hangup(data->peer);
+		ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
+		return;
 	}
+	pthread_attr_destroy(&attr);
+	memset(&sched, 0, sizeof(sched));
+	pthread_setschedparam(thread, SCHED_RR, &sched);
+}
 
-	if (ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING)) {
-		bridge_config_set_limits_warning_values(config, callee_limits);
+/*!
+ * \brief Announce call parking by ADSI
+ * \param chan .
+ * \param parkingexten .
+ * Create message to show for ADSI, display message.
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
+{
+	int res;
+	int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
+	char tmp[256];
+	char *message[5] = {NULL, NULL, NULL, NULL, NULL};
+
+	snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
+	message[0] = tmp;
+	res = ast_adsi_load_session(chan, NULL, 0, 1);
+	if (res == -1)
+		return res;
+	return ast_adsi_print(chan, message, justify, 1);
+}
+
+/*!
+ * \brief Find parking lot name from channel
+ * \note Channel needs to be locked while the returned string is in use.
+ */
+static const char *findparkinglotname(struct ast_channel *chan)
+{
+	const char *name;
+
+	/* The channel variable overrides everything */
+	name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+	if (!name && !ast_strlen_zero(ast_channel_parkinglot(chan))) {
+		/* Use the channel's parking lot. */
+		name = ast_channel_parkinglot(chan);
 	}
+	return name;
+}
+
+/*! \brief Notify metermaids that we've changed an extension */
+static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
+{
+	ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
+		exten, context, ast_devstate2str(state));
+
+	ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context);
+}
 
-	caller_limits->duration = config->timelimit;
-	callee_limits->duration = config->timelimit;
+/*! \brief metermaids callback from devicestate.c */
+static enum ast_device_state metermaidstate(const char *data)
+{
+	char *context;
+	char *exten;
+
+	context = ast_strdupa(data);
+
+	exten = strsep(&context, "@");
+	if (!context)
+		return AST_DEVICE_INVALID;
+
+	ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
+
+	if (!ast_exists_extension(NULL, context, exten, 1, NULL))
+		return AST_DEVICE_NOT_INUSE;
+
+	return AST_DEVICE_INUSE;
 }
 
+/*! Options to pass to park_call_full */
+enum ast_park_call_options {
+	/*! Provide ringing to the parked caller instead of music on hold */
+	AST_PARK_OPT_RINGING =   (1 << 0),
+	/*! Randomly choose a parking spot for the caller instead of choosing
+	 *  the first one that is available. */
+	AST_PARK_OPT_RANDOMIZE = (1 << 1),
+	/*! Do not announce the parking number */
+	AST_PARK_OPT_SILENCE = (1 << 2),
+};
+
+/*! Optional additional parking options when parking a call. */
+struct ast_park_call_args {
+	/*! How long to wait in the parking lot before the call gets sent back
+	 *  to the specified return extension (or a best guess at where it came
+	 *  from if not explicitly specified). */
+	int timeout;
+	/*! An output parameter to store the parking space where the parked caller
+	 *  was placed. */
+	int *extout;
+	const char *orig_chan_name;
+	const char *return_con;
+	const char *return_ext;
+	int return_pri;
+	uint32_t flags;
+	/*! Parked user that has already obtained a parking space */
+	struct parkeduser *pu;
+	/*! \brief Parkinglot to be parked in */
+	struct ast_parkinglot *parkinglot;
+};
+
 /*!
  * \internal
- * \brief Check if Monitor needs to be started on a channel.
- * \since 12.0.0
+ * \brief Create a dynamic parking lot.
  *
- * \param chan The bridge considers this channel the caller.
- * \param peer The bridge considers this channel the callee.
+ * \param name Dynamic parking lot name to create.
+ * \param chan Channel to get dynamic parking lot parameters.
  *
- * \return Nothing
+ * \retval parkinglot on success.
+ * \retval NULL on error.
  */
-static void bridge_check_monitor(struct ast_channel *chan, struct ast_channel *peer)
+static struct ast_parkinglot *create_dynamic_parkinglot(const char *name, struct ast_channel *chan)
 {
-	const char *value;
-	const char *monitor_args = NULL;
-	struct ast_channel *monitor_chan = NULL;
+	const char *dyn_context;
+	const char *dyn_exten;
+	const char *dyn_range;
+	const char *template_name;
+	struct ast_parkinglot *template_parkinglot = NULL;
+	struct ast_parkinglot *parkinglot;
+	int dyn_start;
+	int dyn_end;
 
 	ast_channel_lock(chan);
-	value = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR");
-	if (!ast_strlen_zero(value)) {
-		monitor_args = ast_strdupa(value);
-		monitor_chan = chan;
-	}
+	template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
+	dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
+	dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
+	dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
 	ast_channel_unlock(chan);
-	if (!monitor_chan) {
-		ast_channel_lock(peer);
-		value = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR");
-		if (!ast_strlen_zero(value)) {
-			monitor_args = ast_strdupa(value);
-			monitor_chan = peer;
+
+	if (!ast_strlen_zero(template_name)) {
+		template_parkinglot = find_parkinglot(template_name);
+		if (!template_parkinglot) {
+			ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
+				template_name);
+		} else if (template_parkinglot->cfg.is_invalid) {
+			ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
+				template_name);
+			parkinglot_unref(template_parkinglot);
+			template_parkinglot = NULL;
 		}
-		ast_channel_unlock(peer);
 	}
-	if (monitor_chan) {
-		struct ast_app *monitor_app;
+	if (!template_parkinglot) {
+		template_parkinglot = parkinglot_addref(default_parkinglot);
+		ast_debug(1, "Using default parking lot for template\n");
+	}
+
+	parkinglot = copy_parkinglot(name, template_parkinglot);
+	if (!parkinglot) {
+		ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
+	} else {
+		/* Configure the dynamic parking lot. */
+		if (!ast_strlen_zero(dyn_context)) {
+			ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
+				sizeof(parkinglot->cfg.parking_con));
+		}
+		if (!ast_strlen_zero(dyn_exten)) {
+			ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
+				sizeof(parkinglot->cfg.parkext));
+		}
+		if (!ast_strlen_zero(dyn_range)) {
+			if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
+				ast_log(LOG_WARNING,
+					"Format for parking positions is a-b, where a and b are numbers\n");
+			} else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
+				ast_log(LOG_WARNING,
+					"Format for parking positions is a-b, where a <= b\n");
+			} else {
+				parkinglot->cfg.parking_start = dyn_start;
+				parkinglot->cfg.parking_stop = dyn_end;
+			}
+		}
 
-		monitor_app = pbx_findapp("Monitor");
-		if (monitor_app) {
-			pbx_exec(monitor_chan, monitor_app, monitor_args);
+		/*
+		 * Sanity check for dynamic parking lot configuration.
+		 *
+		 * XXX It may be desirable to instead check if the dynamic
+		 * parking lot overlaps any existing lots like what is done for
+		 * a reload.
+		 */
+		if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
+			if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
+				&& parkinglot->cfg.parkext_exclusive) {
+				ast_log(LOG_WARNING,
+					"Parking lot '%s' conflicts with template parking lot '%s'!\n"
+					"Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
+					parkinglot->name, template_parkinglot->name);
+			}
+			if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
+					&& parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
+				|| (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
+					&& parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
+				|| (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
+					&& template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
+				ast_log(LOG_WARNING,
+					"Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
+					"Change PARKINGDYNPOS.\n",
+					parkinglot->name, template_parkinglot->name);
+			}
 		}
+
+		parkinglot_activate(parkinglot);
+		ao2_link(parkinglots, parkinglot);
 	}
+	parkinglot_unref(template_parkinglot);
+
+	return parkinglot;
 }
 
 /*!
  * \internal
- * \brief Send the peer channel on its way on bridge start failure.
- * \since 12.0.0
+ * \brief Abort parking a call that has not completed parking yet.
  *
- * \param chan Chan to put into autoservice.
- * \param peer Chan to send to after bridge goto or run hangup handlers and hangup.
+ * \param pu Parked user item to clean up.
+ *
+ * \note The parking lot parkings list is locked on entry.
  *
  * \return Nothing
  */
-static void bridge_failed_peer_goto(struct ast_channel *chan, struct ast_channel *peer)
+static void park_space_abort(struct parkeduser *pu)
 {
-	if (ast_bridge_setup_after_goto(peer)
-		|| ast_pbx_start(peer)) {
-		ast_autoservice_chan_hangup_peer(chan, peer);
-	}
+	struct ast_parkinglot *parkinglot;
+
+	parkinglot = pu->parkinglot;
+
+	/* Put back the parking space just allocated. */
+	--parkinglot->next_parking_space;
+
+	AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
+
+	AST_LIST_UNLOCK(&parkinglot->parkings);
+	parkinglot_unref(parkinglot);
+	ast_free(pu);
 }
 
-static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config,
-		struct ast_bridge_features *chan_features, struct ast_bridge_features *peer_features)
+/*!
+ * \internal
+ * \brief Reserve a parking space in a parking lot for a call being parked.
+ *
+ * \param park_me Channel being parked.
+ * \param parker Channel parking the call.
+ * \param args Optional additional parking options when parking a call.
+ *
+ * \return Parked call descriptor or NULL if failed.
+ * \note The parking lot list is locked if successful.
+ */
+static struct parkeduser *park_space_reserve(struct ast_channel *park_me, struct ast_channel *parker, struct ast_park_call_args *args)
 {
-	int res;
-
-	set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
-	add_features_datastores(chan, peer, config);
+	struct parkeduser *pu;
+	int i;
+	int parking_space = -1;
+	const char *parkinglotname;
+	const char *parkingexten;
+	struct parkeduser *cur;
+	struct ast_parkinglot *parkinglot = NULL;
+
+	if (args->parkinglot) {
+		parkinglot = parkinglot_addref(args->parkinglot);
+		parkinglotname = parkinglot->name;
+	} else {
+		if (parker) {
+			parkinglotname = findparkinglotname(parker);
+		} else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */
+			parkinglotname = findparkinglotname(park_me);
+		}
+		if (!ast_strlen_zero(parkinglotname)) {
+			parkinglot = find_parkinglot(parkinglotname);
+		} else {
+			/* Parking lot is not specified, so use the default parking lot. */
+			ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
+			parkinglot = parkinglot_addref(default_parkinglot);
+		}
+	}
 
-	/*
-	 * This is an interesting case.  One example is if a ringing
-	 * channel gets redirected to an extension that picks up a
-	 * parked call.  This will make sure that the call taken out of
-	 * parking gets told that the channel it just got bridged to is
-	 * still ringing.
-	 */
-	if (ast_channel_state(chan) == AST_STATE_RINGING
-		&& ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
-		ast_indicate(peer, AST_CONTROL_RINGING);
+	/* Dynamically create parkinglot */
+	if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
+		parkinglot = create_dynamic_parkinglot(parkinglotname, park_me);
 	}
 
-	bridge_check_monitor(chan, peer);
+	if (!parkinglot) {
+		ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", ast_channel_name(park_me));
+		return NULL;
+	}
 
-	set_config_flags(chan, config);
+	ast_debug(1, "Parking lot: %s\n", parkinglot->name);
+	if (parkinglot->disabled || parkinglot->cfg.is_invalid) {
+		ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n",
+			parkinglot->name);
+		parkinglot_unref(parkinglot);
+		return NULL;
+	}
 
-	/* Answer if need be */
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		if (ast_raw_answer(chan)) {
-			return -1;
-		}
+	/* Allocate memory for parking data */
+	if (!(pu = ast_calloc(1, sizeof(*pu)))) {
+		parkinglot_unref(parkinglot);
+		return NULL;
 	}
 
-#ifdef FOR_DEBUG
-	/* show the two channels and cdrs involved in the bridge for debug & devel purposes */
-	ast_channel_log("Pre-bridge CHAN Channel info", chan);
-	ast_channel_log("Pre-bridge PEER Channel info", peer);
-#endif
+	/* Lock parking list */
+	AST_LIST_LOCK(&parkinglot->parkings);
+
+	/* Check for channel variable PARKINGEXTEN */
+	parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), ""));
+	if (!ast_strlen_zero(parkingexten)) {
+		/*!
+		 * \note The API forces us to specify a numeric parking slot, even
+		 * though the architecture would tend to support non-numeric extensions
+		 * (as are possible with SIP, for example).  Hence, we enforce that
+		 * limitation here.  If extout was not numeric, we could permit
+		 * arbitrary non-numeric extensions.
+		 */
+		if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) {
+			ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n",
+				parkingexten);
+			AST_LIST_UNLOCK(&parkinglot->parkings);
+			parkinglot_unref(parkinglot);
+			ast_free(pu);
+			return NULL;
+		}
 
-	/*
-	 * If we are bridging a call, stop worrying about forwarding
-	 * loops.  We presume that if a call is being bridged, that the
-	 * humans in charge know what they're doing.  If they don't,
-	 * well, what can we do about that?
-	 */
-	clear_dialed_interfaces(chan);
-	clear_dialed_interfaces(peer);
+		if (parking_space < parkinglot->cfg.parking_start
+			|| parkinglot->cfg.parking_stop < parking_space) {
+			/*
+			 * Cannot allow park because parking lots are not setup for
+			 * spaces outside of the lot.  (Things like dialplan hints don't
+			 * exist for outside lot space.)
+			 */
+			ast_log(LOG_WARNING, "PARKINGEXTEN=%d is not in %s (%d-%d).\n",
+				parking_space, parkinglot->name, parkinglot->cfg.parking_start,
+				parkinglot->cfg.parking_stop);
+			AST_LIST_UNLOCK(&parkinglot->parkings);
+			parkinglot_unref(parkinglot);
+			ast_free(pu);
+			return NULL;
+		}
 
-	res = 0;
-	ast_channel_lock(chan);
-	res |= ast_bridge_features_ds_append(chan, &config->features_caller);
-	ast_channel_unlock(chan);
-	ast_channel_lock(peer);
-	res |= ast_bridge_features_ds_append(peer, &config->features_callee);
-	ast_channel_unlock(peer);
+		/* Check if requested parking space is in use. */
+		AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
+			if (cur->parkingnum == parking_space) {
+				ast_log(LOG_WARNING, "PARKINGEXTEN=%d is already in use in %s\n",
+					parking_space, parkinglot->name);
+				AST_LIST_UNLOCK(&parkinglot->parkings);
+				parkinglot_unref(parkinglot);
+				ast_free(pu);
+				return NULL;
+			}
+		}
+	} else {
+		/* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */
+		int start; /* The first slot we look in the parkinglot. It can be randomized. */
+		int start_checked = 0; /* flag raised once the first slot is checked */
+
+		/* If using randomize mode, set start to random position on parking range */
+		if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
+			start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
+			start += parkinglot->cfg.parking_start;
+		} else if (parkinglot->cfg.parkfindnext
+			&& parkinglot->cfg.parking_start <= parkinglot->next_parking_space
+			&& parkinglot->next_parking_space <= parkinglot->cfg.parking_stop) {
+			/* Start looking with the next parking space in the lot. */
+			start = parkinglot->next_parking_space;
+		} else {
+			/* Otherwise, just set it to the start position. */
+			start = parkinglot->cfg.parking_start;
+		}
 
-	if (res) {
-		return -1;
+		/* free parking extension linear search: O(n^2) */
+		for (i = start; ; i++) {
+			/* If we are past the end, wrap around to the first parking slot*/
+			if (i == parkinglot->cfg.parking_stop + 1) {
+				i = parkinglot->cfg.parking_start;
+			}
+
+			if (i == start) {
+				/* At this point, if start_checked, we've exhausted all the possible slots. */
+				if (start_checked) {
+					break;
+				} else {
+					start_checked = 1;
+				}
+			}
+
+			/* Search the list of parked calls already in use for i. If we find it, it's in use. */
+			AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
+				if (cur->parkingnum == i) {
+					break;
+				}
+			}
+			if (!cur) {
+				/* We found a parking space. */
+				parking_space = i;
+				break;
+			}
+		}
+		if (parking_space == -1) {
+			/* We did not find a parking space.  Lot is full. */
+			ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name);
+			AST_LIST_UNLOCK(&parkinglot->parkings);
+			parkinglot_unref(parkinglot);
+			ast_free(pu);
+			return NULL;
+		}
 	}
 
-	if (config->timelimit) {
-		struct ast_bridge_features_limits call_duration_limits_chan;
-		struct ast_bridge_features_limits call_duration_limits_peer;
-		int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
+	/* Prepare for next parking space search. */
+	parkinglot->next_parking_space = parking_space + 1;
 
-		if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
-			ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
+	snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
+	pu->notquiteyet = 1;
+	pu->parkingnum = parking_space;
+	pu->parkinglot = parkinglot;
+	AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
 
-			return -1;
-		}
+	return pu;
+}
 
-		if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
-			ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
-			ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+static unsigned int get_parkingtime(struct ast_channel *chan, struct ast_parkinglot *parkinglot);
+
+/* Park a call */
+static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
+{
+	struct parkeduser *pu = args->pu;
+	const char *event_from;		/*!< Channel name that is parking the call. */
+	char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
 
+	if (pu == NULL) {
+		args->pu = pu = park_space_reserve(chan, peer, args);
+		if (pu == NULL) {
 			return -1;
 		}
+	}
 
-		bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
+	ast_channel_appl_set(chan, "Parked Call");
+	ast_channel_data_set(chan, NULL);
 
-		if (ast_bridge_features_set_limits(chan_features, &call_duration_limits_chan, 0)) {
-			abandon_call = 1;
-		}
-		if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
-			abandon_call = 1;
+	pu->chan = chan;
+
+	/* Put the parked channel on hold if we have two different channels */
+	if (chan != peer) {
+		if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
+			pu->hold_method = AST_CONTROL_RINGING;
+			ast_indicate(chan, AST_CONTROL_RINGING);
+		} else {
+			pu->hold_method = AST_CONTROL_HOLD;
+			ast_indicate_data(chan, AST_CONTROL_HOLD,
+				S_OR(pu->parkinglot->cfg.mohclass, NULL),
+				!ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
 		}
+	}
 
-		/* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
-		ast_bridge_features_limits_destroy(&call_duration_limits_chan);
-		ast_bridge_features_limits_destroy(&call_duration_limits_peer);
+	pu->start = ast_tvnow();
+	pu->parkingtime = (args->timeout > 0) ? args->timeout : get_parkingtime(chan, pu->parkinglot);
+	if (args->extout)
+		*(args->extout) = pu->parkingnum;
 
-		if (abandon_call) {
-			ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
-			return -1;
+	if (peer) {
+		event_from = S_OR(args->orig_chan_name, ast_channel_name(peer));
+
+		/*
+		 * This is so ugly that it hurts, but implementing
+		 * get_base_channel() on local channels could have ugly side
+		 * effects.  We could have
+		 * transferer<->local;1<->local;2<->parking and we need the
+		 * callback name to be that of transferer.  Since local;1/2 have
+		 * the same name we can be tricky and just grab the bridged
+		 * channel from the other side of the local.
+		 */
+		if (!strcasecmp(ast_channel_tech(peer)->type, "Local")) {
+			struct ast_channel *tmpchan, *base_peer;
+			char other_side[AST_CHANNEL_NAME];
+			char *c;
+
+			ast_copy_string(other_side, event_from, sizeof(other_side));
+			if ((c = strrchr(other_side, ';'))) {
+				*++c = '1';
+			}
+			if ((tmpchan = ast_channel_get_by_name(other_side))) {
+				ast_channel_lock(tmpchan);
+				if ((base_peer = ast_bridged_channel(tmpchan))) {
+					ast_copy_string(pu->peername, ast_channel_name(base_peer), sizeof(pu->peername));
+				}
+				ast_channel_unlock(tmpchan);
+				tmpchan = ast_channel_unref(tmpchan);
+			}
+		} else {
+			ast_copy_string(pu->peername, event_from, sizeof(pu->peername));
 		}
+	} else {
+		event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"),
+			ast_channel_name(chan));
 	}
 
-	return 0;
-}
+	/*
+	 * Remember what had been dialed, so that if the parking
+	 * expires, we try to come back to the same place
+	 */
+	pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
 
-int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
-{
-	int res;
-	struct ast_bridge *bridge;
-	struct ast_bridge_features chan_features;
-	struct ast_bridge_features *peer_features;
-
-	/* Setup features. */
-	res = ast_bridge_features_init(&chan_features);
-	peer_features = ast_bridge_features_new();
-	if (res || !peer_features) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		bridge_failed_peer_goto(chan, peer);
-		return -1;
+	/*
+	 * If extension has options specified, they override all other
+	 * possibilities such as the returntoorigin flag and transferred
+	 * context.  Information on extension options is lost here, so
+	 * we set a flag
+	 */
+	ast_copy_string(pu->context,
+		S_OR(args->return_con, S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan))),
+		sizeof(pu->context));
+	ast_copy_string(pu->exten,
+		S_OR(args->return_ext, S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan))),
+		sizeof(pu->exten));
+	pu->priority = args->return_pri ? args->return_pri :
+		(ast_channel_macropriority(chan) ? ast_channel_macropriority(chan) : ast_channel_priority(chan));
+
+	/*
+	 * If parking a channel directly, don't quite yet get parking
+	 * running on it.  All parking lot entries are put into the
+	 * parking lot with notquiteyet on.
+	 */
+	if (peer != chan) {
+		pu->notquiteyet = 0;
 	}
 
-	if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		bridge_failed_peer_goto(chan, peer);
-		return -1;
+	/* Wake up the (presumably select()ing) thread */
+	pthread_kill(parking_thread, SIGURG);
+	ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %u seconds\n",
+		ast_channel_name(chan), pu->parkingnum, pu->parkinglot->name,
+		pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
+
+	ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a call has been parked.</synopsis>
+			<syntax>
+				<parameter name="Exten">
+					<para>The parking lot extension.</para>
+				</parameter>
+				<parameter name="Parkinglot">
+					<para>The name of the parking lot.</para>
+				</parameter>
+				<parameter name="From">
+					<para>The name of the channel that parked the call.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="application">Park</ref>
+				<ref type="manager">Park</ref>
+				<ref type="managerEvent">ParkedCallTimeOut</ref>
+				<ref type="managerEvent">ParkedCallGiveUp</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall",
+		"Exten: %s\r\n"
+		"Channel: %s\r\n"
+		"Parkinglot: %s\r\n"
+		"From: %s\r\n"
+		"Timeout: %ld\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"Uniqueid: %s\r\n",
+		pu->parkingexten, ast_channel_name(chan), pu->parkinglot->name, event_from,
+		(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"),
+		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "<unknown>"),
+		ast_channel_uniqueid(chan)
+		);
+	ast_debug(4, "peer: %s\n", peer ? ast_channel_name(peer) : "-No peer-");
+	ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-");
+	ast_debug(4, "pu->peername: %s\n", pu->peername);
+	ast_debug(4, "AMI ParkedCall Channel: %s\n", ast_channel_name(chan));
+	ast_debug(4, "AMI ParkedCall From: %s\n", event_from);
+
+	if (peer && adsipark && ast_adsi_available(peer)) {
+		adsi_announce_park(peer, pu->parkingexten);	/* Only supports parking numbers */
+		ast_adsi_unload_session(peer);
 	}
 
-	/* Create bridge */
-	bridge = ast_bridge_basic_new();
-	if (!bridge) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		bridge_failed_peer_goto(chan, peer);
-		return -1;
+	snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
+		pu->parkinglot->name);
+	if (ast_add_extension(pu->parkinglot->cfg.parking_con, 1, pu->parkingexten, 1,
+		NULL, NULL, parkedcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
+		ast_log(LOG_ERROR, "Could not create parked call exten: %s@%s\n",
+			pu->parkingexten, pu->parkinglot->cfg.parking_con);
+	} else {
+		notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
 	}
 
-	ast_bridge_basic_set_flags(bridge, flags);
+	AST_LIST_UNLOCK(&pu->parkinglot->parkings);
 
-	/* Put peer into the bridge */
-	if (ast_bridge_impart(bridge, peer, NULL, peer_features,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT | AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) {
-		ast_bridge_destroy(bridge, 0);
-		ast_bridge_features_cleanup(&chan_features);
-		bridge_failed_peer_goto(chan, peer);
-		return -1;
+	/* Only say number if it's a number and the channel hasn't been masqueraded away */
+	if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE)
+		&& (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(ast_channel_name(peer), args->orig_chan_name))) {
+		/*
+		 * If a channel is masqueraded into peer while playing back the
+		 * parking space number do not continue playing it back.  This
+		 * is the case if an attended transfer occurs.
+		 */
+		ast_set_flag(ast_channel_flags(peer), AST_FLAG_MASQ_NOSTREAM);
+		/* Tell the peer channel the number of the parking space */
+		ast_say_digits(peer, pu->parkingnum, "", ast_channel_language(peer));
+		ast_clear_flag(ast_channel_flags(peer), AST_FLAG_MASQ_NOSTREAM);
+	}
+	if (peer == chan) { /* pu->notquiteyet = 1 */
+		/* Wake up parking thread if we're really done */
+		if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
+			pu->hold_method = AST_CONTROL_RINGING;
+			ast_indicate(chan, AST_CONTROL_RINGING);
+		} else {
+			pu->hold_method = AST_CONTROL_HOLD;
+			ast_indicate_data(chan, AST_CONTROL_HOLD,
+				S_OR(pu->parkinglot->cfg.mohclass, NULL),
+				!ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
+		}
+		pu->notquiteyet = 0;
+		pthread_kill(parking_thread, SIGURG);
 	}
+	return 0;
+}
 
-	/* Join bridge */
-	ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
-		AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP);
+int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
+{
+	int res;
+	char *parse;
+	const char *app_data;
+	struct ast_exten *exten;
+	struct park_app_args app_args;
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	if (!park_exten || !park_context) {
+		return park_call_full(park_me, parker, &args);
+	}
 
 	/*
-	 * If the bridge was broken for a hangup that isn't real, then
-	 * don't run the h extension, because the channel isn't really
-	 * hung up.  This should really only happen with
-	 * AST_SOFTHANGUP_ASYNCGOTO.
+	 * Determiine if the specified park extension has an exclusive
+	 * parking lot to use.
 	 */
-	res = -1;
-	ast_channel_lock(chan);
-	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
-		res = 0;
+	if (parker && parker != park_me) {
+		ast_autoservice_start(park_me);
 	}
-	ast_channel_unlock(chan);
-
-	ast_bridge_features_cleanup(&chan_features);
-
-	if (res && config->end_bridge_callback) {
-		config->end_bridge_callback(config->end_bridge_callback_data);
+	exten = get_parking_exten(park_exten, parker, park_context);
+	if (exten) {
+		app_data = ast_get_extension_app_data(exten);
+		if (!app_data) {
+			app_data = "";
+		}
+		parse = ast_strdupa(app_data);
+		AST_STANDARD_APP_ARGS(app_args, parse);
+
+		if (!ast_strlen_zero(app_args.pl_name)) {
+			/* Find the specified exclusive parking lot */
+			args.parkinglot = find_parkinglot(app_args.pl_name);
+			if (!args.parkinglot && parkeddynamic) {
+				args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
+			}
+		}
+	}
+	if (parker && parker != park_me) {
+		ast_autoservice_stop(park_me);
 	}
 
+	res = park_call_full(park_me, parker, &args);
+	if (args.parkinglot) {
+		parkinglot_unref(args.parkinglot);
+	}
 	return res;
 }
 
-/*!
- * \brief bridge the call and set CDR
- *
- * \param chan The bridge considers this channel the caller.
- * \param peer The bridge considers this channel the callee.
- * \param config Configuration for this bridge.
- *
- * Set start time, check for two channels,check if monitor on
- * check for feature activation, create new CDR
- * \retval res on success.
- * \retval -1 on failure to bridge.
- */
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout)
 {
-	return ast_bridge_call_with_flags(chan, peer, config, 0);
-}
-
-enum play_tone_action {
-	PLAYTONE_NONE = 0,
-	PLAYTONE_CHANNEL1 = (1 << 0),
-	PLAYTONE_CHANNEL2 = (1 << 1),
-	PLAYTONE_BOTH = PLAYTONE_CHANNEL1 | PLAYTONE_CHANNEL2,
-};
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
 
-static enum play_tone_action parse_playtone(const char *playtone_val)
-{
-	if (ast_strlen_zero(playtone_val) || ast_false(playtone_val)) {
-		return PLAYTONE_NONE;
-	} if (!strcasecmp(playtone_val, "channel1")) {
-		return PLAYTONE_CHANNEL1;
-	} else if (!strcasecmp(playtone_val, "channel2") || ast_true(playtone_val)) {
-		return PLAYTONE_CHANNEL2;
-	} else if (!strcasecmp(playtone_val, "both")) {
-		return PLAYTONE_BOTH;
-	} else {
-		/* Invalid input. Assume none */
-		return PLAYTONE_NONE;
-	}
+	return park_call_full(park_me, parker, &args);
 }
 
 /*!
- * \brief Bridge channels together
- * \param s
- * \param m
+ * \brief Park call via masqueraded channel and announce parking spot on peer channel.
  *
- * Make sure valid channels were specified,
- * send errors if any of the channels could not be found/locked, answer channels if needed,
- * create the placeholder channels and grab the other channels
- * make the channels compatible, send error if we fail doing so
- * setup the bridge thread object and start the bridge.
+ * \param rchan the real channel to be parked
+ * \param peer the channel to have the parking read to.
+ * \param args Additional parking options when parking a call.
  *
- * \retval 0
+ * \retval 0 on success.
+ * \retval -1 on failure.
  */
-static int action_bridge(struct mansession *s, const struct message *m)
+static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
-	const char *channela = astman_get_header(m, "Channel1");
-	const char *channelb = astman_get_header(m, "Channel2");
-	enum play_tone_action playtone = parse_playtone(astman_get_header(m, "Tone"));
-	RAII_VAR(struct ast_channel *, chana, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chanb, NULL, ao2_cleanup);
-	const char *chana_exten;
-	const char *chana_context;
-	int chana_priority;
-	const char *chanb_exten;
-	const char *chanb_context;
-	int chanb_priority;
-	struct ast_bridge *bridge;
-	char buf[256];
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_a, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_b, NULL, ao2_cleanup);
+	struct ast_channel *chan;
 
-	/* make sure valid channels were specified */
-	if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
-		astman_send_error(s, m, "Missing channel parameter in request");
-		return 0;
+	/* Make a new, channel that we'll use to masquerade in the real one */
+	chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, ast_channel_accountcode(rchan), ast_channel_exten(rchan),
+		ast_channel_context(rchan), ast_channel_linkedid(rchan), ast_channel_amaflags(rchan), "Parked/%s", ast_channel_name(rchan));
+	if (!chan) {
+		ast_log(LOG_WARNING, "Unable to create parked channel\n");
+		if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
+			if (peer == rchan) {
+				/* Only have one channel to worry about. */
+				ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+			} else if (peer) {
+				/* Have two different channels to worry about. */
+				play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
+			}
+		}
+		return -1;
+	}
+
+	args->pu = park_space_reserve(rchan, peer, args);
+	if (!args->pu) {
+		ast_hangup(chan);
+		if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
+			if (peer == rchan) {
+				/* Only have one channel to worry about. */
+				ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+			} else if (peer) {
+				/* Have two different channels to worry about. */
+				play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
+			}
+		}
+		return -1;
+	}
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(chan), ast_channel_readformat(rchan));
+	ast_format_copy(ast_channel_writeformat(chan), ast_channel_writeformat(rchan));
+
+	if (ast_channel_masquerade(chan, rchan)) {
+		park_space_abort(args->pu);
+		args->pu = NULL;
+		ast_hangup(chan);
+		if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
+			if (peer == rchan) {
+				/* Only have one channel to worry about. */
+				ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+			} else if (peer) {
+				/* Have two different channels to worry about. */
+				play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
+			}
+		}
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	set_c_e_p(chan, ast_channel_context(rchan), ast_channel_exten(rchan), ast_channel_priority(rchan));
+
+	/* Setup the macro extension and such */
+	ast_channel_macrocontext_set(chan, ast_channel_macrocontext(rchan));
+	ast_channel_macroexten_set(chan, ast_channel_macroexten(rchan));
+	ast_channel_macropriority_set(chan, ast_channel_macropriority(rchan));
+
+	/* Manually do the masquerade to make sure it is complete. */
+	ast_do_masquerade(chan);
+
+	if (peer == rchan) {
+		peer = chan;
+	}
+
+	/* parking space reserved, return code check unnecessary */
+	park_call_full(chan, peer, args);
+
+	return 0;
+}
+
+int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
+{
+	int res;
+	char *parse;
+	const char *app_data;
+	struct ast_exten *exten;
+	struct park_app_args app_args;
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	if (parker) {
+		args.orig_chan_name = ast_strdupa(ast_channel_name(parker));
+	}
+	if (!park_exten || !park_context) {
+		return masq_park_call(park_me, parker, &args);
+	}
+
+	/*
+	 * Determiine if the specified park extension has an exclusive
+	 * parking lot to use.
+	 */
+	if (parker && parker != park_me) {
+		ast_autoservice_start(park_me);
+	}
+	exten = get_parking_exten(park_exten, parker, park_context);
+	if (exten) {
+		app_data = ast_get_extension_app_data(exten);
+		if (!app_data) {
+			app_data = "";
+		}
+		parse = ast_strdupa(app_data);
+		AST_STANDARD_APP_ARGS(app_args, parse);
+
+		if (!ast_strlen_zero(app_args.pl_name)) {
+			/* Find the specified exclusive parking lot */
+			args.parkinglot = find_parkinglot(app_args.pl_name);
+			if (!args.parkinglot && parkeddynamic) {
+				args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
+			}
+		}
+	}
+	if (parker && parker != park_me) {
+		ast_autoservice_stop(park_me);
+	}
+
+	res = masq_park_call(park_me, parker, &args);
+	if (args.parkinglot) {
+		parkinglot_unref(args.parkinglot);
+	}
+	return res;
+}
+
+int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
+{
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	if (peer) {
+		args.orig_chan_name = ast_strdupa(ast_channel_name(peer));
+	}
+	return masq_park_call(rchan, peer, &args);
+}
+
+static int finishup(struct ast_channel *chan)
+{
+	ast_indicate(chan, AST_CONTROL_UNHOLD);
+
+	return ast_autoservice_stop(chan);
+}
+
+/*!
+ * \internal
+ * \brief Builtin transfer park call helper.
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot dialplan access ramp extension.
+ *
+ * \note Assumes park_me is on hold and in autoservice.
+ *
+ * \retval -1 on successful park.
+ * \retval -1 on park_me hangup.
+ * \retval AST_FEATURE_RETURN_SUCCESS on error to keep the bridge connected.
+ */
+static int xfer_park_call_helper(struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten)
+{
+	char *parse;
+	const char *app_data;
+	const char *pl_name;
+	struct ast_park_call_args args = { 0, };
+	struct park_app_args app_args;
+	int res;
+
+	app_data = ast_get_extension_app_data(park_exten);
+	if (!app_data) {
+		app_data = "";
+	}
+	parse = ast_strdupa(app_data);
+	AST_STANDARD_APP_ARGS(app_args, parse);
+
+	/* Find the parking lot */
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(parker);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
+		args.parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		args.parkinglot = find_parkinglot(pl_name);
+		if (!args.parkinglot && parkeddynamic) {
+			args.parkinglot = create_dynamic_parkinglot(pl_name, park_me);
+		}
+	}
+
+	if (args.parkinglot) {
+		/* Park the call */
+		res = finishup(park_me);
+		if (res) {
+			/* park_me hungup on us. */
+			parkinglot_unref(args.parkinglot);
+			return -1;
+		}
+		res = masq_park_call(park_me, parker, &args);
+		parkinglot_unref(args.parkinglot);
+	} else {
+		/* Parking failed because parking lot does not exist. */
+		if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
+			ast_stream_and_wait(parker, "pbx-parkingfailed", "");
+		}
+		finishup(park_me);
+		res = -1;
+	}
+
+	return res ? AST_FEATURE_RETURN_SUCCESS : -1;
+}
+
+/*!
+ * \brief set caller and callee according to the direction
+ * \param caller, callee, peer, chan, sense
+ *
+ * Detect who triggered feature and set callee/caller variables accordingly
+ */
+static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
+	struct ast_channel *peer, struct ast_channel *chan, int sense)
+{
+	if (sense == FEATURE_SENSE_PEER) {
+		*caller = peer;
+		*callee = chan;
+	} else {
+		*callee = peer;
+		*caller = chan;
+	}
+}
+
+/*!
+ * \brief support routing for one touch call parking
+ * \param chan channel parking call
+ * \param peer channel to be parked
+ * \param config unsed
+ * \param code unused
+ * \param sense feature options
+ * \param data unused
+ *
+ * \retval -1 on successful park.
+ * \retval -1 on chan hangup.
+ * \retval AST_FEATURE_RETURN_SUCCESS on error to keep the bridge connected.
+ */
+static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	struct ast_channel *parker;
+	struct ast_channel *parkee;
+	struct ast_park_call_args args = { 0, };
+
+	/*
+	 * We used to set chan's exten and priority to "s" and 1 here,
+	 * but this generates (in some cases) an invalid extension, and
+	 * if "s" exists, could errantly cause execution of extensions
+	 * you don't expect.  It makes more sense to let nature take its
+	 * course when chan finishes, and let the pbx do its thing and
+	 * hang up when the park is over.
+	 */
+
+	/* Answer if call is not up */
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		/*
+		 * XXX Why are we doing this?  Both of the channels should be up
+		 * since you cannot do DTMF features unless you are bridged.
+		 */
+		if (ast_answer(chan)) {
+			return -1;
+		}
+
+		/* Sleep to allow VoIP streams to settle down */
+		if (ast_safe_sleep(chan, 1000)) {
+			return -1;
+		}
+	}
+
+	/* one direction used to call park_call.... */
+	set_peers(&parker, &parkee, peer, chan, sense);
+	return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
+}
+
+/*!
+ * \internal
+ * \brief Play file to specified channel.
+ *
+ * \param play_to Channel to play audiofile to.
+ * \param other Channel to put in autoservice while playing file.
+ * \param msg Descriptive name of message type being played.
+ * \param audiofile Audio file to play.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error. (Couldn't play file, a channel hung up,...)
+ */
+static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile)
+{
+	/* Put other channel in autoservice. */
+	if (ast_autoservice_start(other)) {
+		return -1;
+	}
+	ast_autoservice_ignore(other, AST_FRAME_DTMF_BEGIN);
+	ast_autoservice_ignore(other, AST_FRAME_DTMF_END);
+	if (ast_stream_and_wait(play_to, audiofile, "")) {
+		ast_log(LOG_WARNING, "Failed to play %s '%s'!\n", msg, audiofile);
+		ast_autoservice_stop(other);
+		return -1;
+	}
+	if (ast_autoservice_stop(other)) {
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Play file to specified channels.
+ *
+ * \param left Channel on left to play file.
+ * \param right Channel on right to play file.
+ * \param which Play file on indicated channels: which < 0 play left, which == 0 play both, which > 0 play right
+ * \param msg Descriptive name of message type being played.
+ * \param audiofile Audio file to play to channels.
+ *
+ * \note Plays file to the indicated channels in turn so please
+ * don't use this for very long messages.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error. (Couldn't play file, channel hung up,...)
+ */
+static int play_message_to_chans(struct ast_channel *left, struct ast_channel *right, int which, const char *msg, const char *audiofile)
+{
+	/* First play the file to the left channel if requested. */
+	if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) {
+		return -1;
+	}
+
+	/* Then play the file to the right channel if requested. */
+	if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the
+ * other channel during the message, so please don't use this for very long messages
+ */
+static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
+{
+	return play_message_to_chans(caller_chan, callee_chan, 0, "automon message",
+		audiofile);
+}
+
+/*!
+ * \brief Monitor a channel by DTMF
+ * \param chan channel requesting monitor
+ * \param peer channel to be monitored
+ * \param config
+ * \param code
+ * \param sense feature options
+ *
+ * \param data
+ * Check monitor app enabled, setup channels, both caller/callee chans not null
+ * get TOUCH_MONITOR variable for filename if exists, exec monitor app.
+ * \retval AST_FEATURE_RETURN_SUCCESS on success.
+ * \retval -1 on error.
+ */
+static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
+	int x = 0;
+	size_t len;
+	struct ast_channel *caller_chan, *callee_chan;
+	const char *automon_message_start = NULL;
+	const char *automon_message_stop = NULL;
+	const char *touch_format = NULL;
+	const char *touch_monitor = NULL;
+	const char *touch_monitor_prefix = NULL;
+
+	if (!monitor_ok) {
+		ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
+		return -1;
+	}
+
+	if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
+		monitor_ok = 0;
+		ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
+		return -1;
+	}
+
+	set_peers(&caller_chan, &callee_chan, peer, chan, sense);
+
+	/* Find extra messages */
+	automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
+	automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
+
+	if (!ast_strlen_zero(courtesytone)) {	/* Play courtesy tone if configured */
+		if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
+			return -1;
+		}
+	}
+
+	if (ast_channel_monitor(callee_chan)) {
+		ast_verb(4, "User hit '%s' to stop recording call.\n", code);
+		if (!ast_strlen_zero(automon_message_stop)) {
+			play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
+		}
+		ast_channel_monitor(callee_chan)->stop(callee_chan, 1);
+		return AST_FEATURE_RETURN_SUCCESS;
+	}
+
+	touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
+	touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
+	touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
+
+	if (!touch_format)
+		touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
+
+	if (!touch_monitor)
+		touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
+
+	if (!touch_monitor_prefix)
+		touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
+
+	if (touch_monitor) {
+		len = strlen(touch_monitor) + 50;
+		args = ast_alloca(len);
+		touch_filename = ast_alloca(len);
+		snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
+		snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
+	} else {
+		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid,
+			ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan)));
+		callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid,
+			ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan)));
+		len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
+		args = ast_alloca(len);
+		touch_filename = ast_alloca(len);
+		snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
+		snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
+	}
+
+	for(x = 0; x < strlen(args); x++) {
+		if (args[x] == '/')
+			args[x] = '-';
+	}
+
+	ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
+
+	pbx_exec(callee_chan, monitor_app, args);
+	pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
+	pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
+
+	if (!ast_strlen_zero(automon_message_start)) {	/* Play start message for both channels */
+		play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
+	}
+
+	return AST_FEATURE_RETURN_SUCCESS;
+}
+
+static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
+	int x = 0;
+	size_t len;
+	struct ast_channel *caller_chan, *callee_chan;
+	const char *mixmonitor_spy_type = "MixMonitor";
+	const char *touch_format;
+	const char *touch_monitor;
+	int count = 0;
+
+	if (!mixmonitor_ok) {
+		ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
+		return -1;
+	}
+
+	if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
+		mixmonitor_ok = 0;
+		ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
+		return -1;
+	}
+
+	set_peers(&caller_chan, &callee_chan, peer, chan, sense);
+
+	if (!ast_strlen_zero(courtesytone)) {
+		if (ast_autoservice_start(callee_chan))
+			return -1;
+		ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END);
+		if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
+			ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
+			ast_autoservice_stop(callee_chan);
+			return -1;
+		}
+		if (ast_autoservice_stop(callee_chan))
+			return -1;
+	}
+
+	ast_channel_lock(callee_chan);
+	count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+	ast_channel_unlock(callee_chan);
+
+	/* This means a mixmonitor is attached to the channel, running or not is unknown. */
+	if (count > 0) {
+		ast_verb(3, "User hit '%s' to stop recording call.\n", code);
+
+		/* Make sure they are running */
+		ast_channel_lock(callee_chan);
+		count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+		ast_channel_unlock(callee_chan);
+		if (count > 0) {
+			if (!stopmixmonitor_ok) {
+				ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
+				return -1;
+			}
+			if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
+				stopmixmonitor_ok = 0;
+				ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
+				return -1;
+			} else {
+				pbx_exec(callee_chan, stopmixmonitor_app, "");
+				return AST_FEATURE_RETURN_SUCCESS;
+			}
+		}
+
+		ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");
+	}
+
+	touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
+	touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
+
+	if (!touch_format)
+		touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
+
+	if (!touch_monitor)
+		touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
+
+	if (touch_monitor) {
+		len = strlen(touch_monitor) + 50;
+		args = ast_alloca(len);
+		touch_filename = ast_alloca(len);
+		snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
+		snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
+	} else {
+		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid,
+			ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan)));
+		callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid,
+			ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan)));
+		len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
+		args = ast_alloca(len);
+		touch_filename = ast_alloca(len);
+		snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
+		snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
+	}
+
+	for( x = 0; x < strlen(args); x++) {
+		if (args[x] == '/')
+			args[x] = '-';
+	}
+
+	ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
+
+	pbx_exec(callee_chan, mixmonitor_app, args);
+	pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+	pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+	return AST_FEATURE_RETURN_SUCCESS;
+}
+
+static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	ast_verb(4, "User hit '%s' to disconnect call.\n", code);
+	return AST_FEATURE_RETURN_HANGUP;
+}
+
+/*!
+ * \brief Find the context for the transfer
+ * \param transferer
+ * \param transferee
+ *
+ * Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
+ * \return a context string
+ */
+static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
+{
+	const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
+	if (ast_strlen_zero(s)) {
+		s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
+	}
+	if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
+		s = ast_channel_macrocontext(transferer);
+	}
+	if (ast_strlen_zero(s)) {
+		s = ast_channel_context(transferer);
+	}
+	return s;
+}
+
+/*!
+ * \brief Blind transfer user to another extension
+ * \param chan channel to be transferred
+ * \param peer channel initiated blind transfer
+ * \param config
+ * \param code
+ * \param data
+ * \param sense  feature options
+ *
+ * Place chan on hold, check if transferred to parkinglot extension,
+ * otherwise check extension exists and transfer caller.
+ * \retval AST_FEATURE_RETURN_SUCCESS.
+ * \retval -1 on failure.
+ */
+static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	struct ast_channel *transferer;
+	struct ast_channel *transferee;
+	struct ast_exten *park_exten;
+	const char *transferer_real_context;
+	char xferto[256] = "";
+	int res;
+
+	ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense);
+	set_peers(&transferer, &transferee, peer, chan, sense);
+	transferer_real_context = ast_strdupa(real_ctx(transferer, transferee));
+
+	/* Start autoservice on transferee while we talk to the transferer */
+	ast_autoservice_start(transferee);
+	ast_indicate(transferee, AST_CONTROL_HOLD);
+
+	/* Transfer */
+	res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
+	if (res < 0) {
+		finishup(transferee);
+		return -1; /* error ? */
+	}
+	if (res > 0) { /* If they've typed a digit already, handle it */
+		xferto[0] = (char) res;
+	}
+
+	res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
+	if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
+		finishup(transferee);
+		return -1;
+	}
+	if (res == 0) {
+		if (xferto[0]) {
+			ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
+				xferto, transferer_real_context);
+		} else {
+			/* Does anyone care about this case? */
+			ast_log(LOG_WARNING, "No digits dialed.\n");
+		}
+		ast_stream_and_wait(transferer, "pbx-invalid", "");
+		finishup(transferee);
+		return AST_FEATURE_RETURN_SUCCESS;
+	}
+
+	park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
+	if (park_exten) {
+		/* We are transfering the transferee to a parking lot. */
+		return xfer_park_call_helper(transferee, transferer, park_exten);
+	}
+
+	/* Do blind transfer. */
+	ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
+		ast_channel_name(transferee), xferto, transferer_real_context);
+	ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
+	pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", ast_channel_name(transferee));
+	pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", ast_channel_name(transferer));
+	finishup(transferee);
+	ast_channel_lock(transferer);
+	if (!ast_channel_cdr(transferer)) {
+		/* this code should never get called (in a perfect world) */
+		ast_channel_cdr_set(transferer, ast_cdr_alloc());
+		if (ast_channel_cdr(transferer)) {
+			ast_cdr_init(ast_channel_cdr(transferer), transferer); /* initialize our channel's cdr */
+			ast_cdr_start(ast_channel_cdr(transferer));
+		}
+	}
+	ast_channel_unlock(transferer);
+	if (ast_channel_cdr(transferer)) {
+		struct ast_cdr *swap = ast_channel_cdr(transferer);
+
+		ast_debug(1,
+			"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
+			ast_channel_name(transferer), ast_channel_name(transferee), ast_channel_cdr(transferer)->lastapp,
+			ast_channel_cdr(transferer)->lastdata, ast_channel_cdr(transferer)->channel,
+			ast_channel_cdr(transferer)->dstchannel);
+		ast_debug(1, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
+			ast_channel_cdr(transferee)->lastapp, ast_channel_cdr(transferee)->lastdata, ast_channel_cdr(transferee)->channel,
+			ast_channel_cdr(transferee)->dstchannel);
+		ast_debug(1, "transferer_real_context=%s; xferto=%s\n",
+			transferer_real_context, xferto);
+		/* swap cdrs-- it will save us some time & work */
+		ast_channel_cdr_set(transferer, ast_channel_cdr(transferee));
+		ast_channel_cdr_set(transferee, swap);
+	}
+
+	res = ast_channel_pbx(transferee) ? AST_FEATURE_RETURN_SUCCESSBREAK : -1;
+
+	/* Doh!  Use our handy async_goto functions */
+	if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
+		ast_log(LOG_WARNING, "Async goto failed :-(\n");
+		res = -1;
+	} else if (res == AST_FEATURE_RETURN_SUCCESSBREAK) {
+		/* Don't let the after-bridge code run the h-exten */
+		ast_channel_lock(transferee);
+		ast_set_flag(ast_channel_flags(transferee), AST_FLAG_BRIDGE_HANGUP_DONT);
+		ast_channel_unlock(transferee);
+	}
+	check_goto_on_transfer(transferer);
+	return res;
+}
+
+/*!
+ * \brief make channels compatible
+ * \param c
+ * \param newchan
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
+{
+	if (ast_channel_make_compatible(c, newchan) < 0) {
+		ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
+			ast_channel_name(c), ast_channel_name(newchan));
+		ast_autoservice_chan_hangup_peer(c, newchan);
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Builtin attended transfer failed cleanup.
+ * \since 10.0
+ *
+ * \param transferee Party A in the transfer.
+ * \param transferer Party B in the transfer.
+ * \param connected_line Saved connected line info about party A.
+ *
+ * \note The connected_line data is freed.
+ *
+ * \return Nothing
+ */
+static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line)
+{
+	finishup(transferee);
+
+	/*
+	 * Restore party B connected line info about party A.
+	 *
+	 * Party B was the caller to party C and is the last known mode
+	 * for party B.
+	 */
+	if (ast_channel_connected_line_sub(transferee, transferer, connected_line, 0) &&
+		ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) {
+		ast_channel_update_connected_line(transferer, connected_line, NULL);
+	}
+	ast_party_connected_line_free(connected_line);
+}
+
+/*!
+ * \brief Attended transfer
+ * \param chan transferred user
+ * \param peer person transfering call
+ * \param config
+ * \param code
+ * \param sense feature options
+ *
+ * \param data
+ * Get extension to transfer to, if you cannot generate channel (or find extension)
+ * return to host channel. After called channel answered wait for hangup of transferer,
+ * bridge call between transfer peer (taking them off hold) to attended transfer channel.
+ *
+ * \return -1 on failure
+ */
+static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	struct ast_channel *transferer;/* Party B */
+	struct ast_channel *transferee;/* Party A */
+	struct ast_exten *park_exten;
+	const char *chan1_attended_sound;
+	const char *chan2_attended_sound;
+	const char *transferer_real_context;
+	char xferto[256] = "";
+	int res;
+	int outstate=0;
+	struct ast_channel *newchan;
+	struct ast_channel *xferchan;
+	struct ast_bridge_thread_obj *tobj;
+	struct ast_bridge_config bconfig;
+	int l;
+	struct ast_party_connected_line connected_line;
+	struct ast_datastore *features_datastore;
+	struct ast_dial_features *dialfeatures;
+	char *transferer_tech;
+	char *transferer_name;
+	char *transferer_name_orig;
+	char *dash;
+
+	ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense);
+	set_peers(&transferer, &transferee, peer, chan, sense);
+	transferer_real_context = real_ctx(transferer, transferee);
+
+	/* Start autoservice on transferee while we talk to the transferer */
+	ast_autoservice_start(transferee);
+	ast_indicate(transferee, AST_CONTROL_HOLD);
+
+	/* Transfer */
+	res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
+	if (res < 0) {
+		finishup(transferee);
+		return -1;
+	}
+	if (res > 0) { /* If they've typed a digit already, handle it */
+		xferto[0] = (char) res;
+	}
+
+	/* this is specific of atxfer */
+	res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
+	if (res < 0) {  /* hangup or error, (would be 0 for invalid and 1 for valid) */
+		finishup(transferee);
+		return -1;
+	}
+	l = strlen(xferto);
+	if (res == 0) {
+		if (l) {
+			ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n",
+				xferto, transferer_real_context);
+		} else {
+			/* Does anyone care about this case? */
+			ast_log(LOG_WARNING, "No digits dialed for atxfer.\n");
+		}
+		ast_stream_and_wait(transferer, "pbx-invalid", "");
+		finishup(transferee);
+		return AST_FEATURE_RETURN_SUCCESS;
+	}
+
+	park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
+	if (park_exten) {
+		/* We are transfering the transferee to a parking lot. */
+		return xfer_park_call_helper(transferee, transferer, park_exten);
+	}
+
+	/*
+	 * Append context to dialed transfer number.
+	 *
+	 * NOTE: The local channel needs the /n flag so party C will use
+	 * the feature flags set by the dialplan when calling that
+	 * party.
+	 */
+	snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
+
+	/* If we are performing an attended transfer and we have two channels involved then
+	   copy sound file information to play upon attended transfer completion */
+	chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
+	chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
+	if (!ast_strlen_zero(chan1_attended_sound)) {
+		pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
+	}
+	if (!ast_strlen_zero(chan2_attended_sound)) {
+		pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
+	}
+
+	/* Extract redial transferer information from the channel name. */
+	transferer_name_orig = ast_strdupa(ast_channel_name(transferer));
+	transferer_name = ast_strdupa(transferer_name_orig);
+	transferer_tech = strsep(&transferer_name, "/");
+	dash = strrchr(transferer_name, '-');
+	if (dash) {
+		/* Trim off channel name sequence/serial number. */
+		*dash = '\0';
+	}
+
+	/* Stop autoservice so we can monitor all parties involved in the transfer. */
+	if (ast_autoservice_stop(transferee) < 0) {
+		ast_indicate(transferee, AST_CONTROL_UNHOLD);
+		return -1;
+	}
+
+	/* Save connected line info for party B about party A in case transfer fails. */
+	ast_party_connected_line_init(&connected_line);
+	ast_channel_lock(transferer);
+	ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer));
+	ast_channel_unlock(transferer);
+	connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+
+	/* Dial party C */
+	newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
+		transferee, "Local", ast_channel_nativeformats(transferer), xferto,
+		atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
+	ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
+
+	if (!ast_check_hangup(transferer)) {
+		int hangup_dont = 0;
+
+		/* Transferer (party B) is up */
+		ast_debug(1, "Actually doing an attended transfer.\n");
+
+		/* Start autoservice on transferee while the transferer deals with party C. */
+		ast_autoservice_start(transferee);
+
+		ast_indicate(transferer, -1);
+		if (!newchan) {
+			/* any reason besides user requested cancel and busy triggers the failed sound */
+			switch (outstate) {
+			case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */
+			case AST_CONTROL_BUSY:
+			case AST_CONTROL_CONGESTION:
+				if (ast_stream_and_wait(transferer, xfersound, "")) {
+					ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+				}
+				break;
+			default:
+				if (ast_stream_and_wait(transferer, xferfailsound, "")) {
+					ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
+				}
+				break;
+			}
+			atxfer_fail_cleanup(transferee, transferer, &connected_line);
+			return AST_FEATURE_RETURN_SUCCESS;
+		}
+
+		if (check_compat(transferer, newchan)) {
+			if (ast_stream_and_wait(transferer, xferfailsound, "")) {
+				ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n");
+			}
+			atxfer_fail_cleanup(transferee, transferer, &connected_line);
+			return AST_FEATURE_RETURN_SUCCESS;
+		}
+		memset(&bconfig,0,sizeof(struct ast_bridge_config));
+		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
+		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
+
+		/*
+		 * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we
+		 * don't want that to happen here because the transferer is in
+		 * another bridge already.
+		 */
+		if (ast_test_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT)) {
+			hangup_dont = 1;
+		}
+
+		/*
+		 * Don't let the after-bridge code run the h-exten.  It is the
+		 * wrong bridge to run the h-exten after.
+		 */
+		ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
+
+		/*
+		 * Let party B and C talk as long as they want while party A
+		 * languishes in autoservice listening to MOH.
+		 */
+		ast_bridge_call(transferer, newchan, &bconfig);
+
+		if (hangup_dont) {
+			/* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */
+			ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
+		}
+
+		if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
+			ast_autoservice_chan_hangup_peer(transferer, newchan);
+			if (ast_stream_and_wait(transferer, xfersound, "")) {
+				ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+			}
+			atxfer_fail_cleanup(transferee, transferer, &connected_line);
+			return AST_FEATURE_RETURN_SUCCESS;
+		}
+
+		/* Transferer (party B) is confirmed hung up at this point. */
+		if (check_compat(transferee, newchan)) {
+			finishup(transferee);
+			ast_party_connected_line_free(&connected_line);
+			return -1;
+		}
+
+		ast_indicate(transferee, AST_CONTROL_UNHOLD);
+		if ((ast_autoservice_stop(transferee) < 0)
+			|| (ast_waitfordigit(transferee, 100) < 0)
+			|| (ast_waitfordigit(newchan, 100) < 0)
+			|| ast_check_hangup(transferee)
+			|| ast_check_hangup(newchan)) {
+			ast_hangup(newchan);
+			ast_party_connected_line_free(&connected_line);
+			return -1;
+		}
+	} else if (!ast_check_hangup(transferee)) {
+		/* Transferer (party B) has hung up at this point.  Doing blonde transfer. */
+		ast_debug(1, "Actually doing a blonde transfer.\n");
+
+		if (!newchan && !atxferdropcall) {
+			/* Party C is not available, try to call party B back. */
+			unsigned int tries = 0;
+
+			if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
+				ast_log(LOG_WARNING,
+					"Transferer channel name: '%s' cannot be used for callback.\n",
+					transferer_name_orig);
+				ast_indicate(transferee, AST_CONTROL_UNHOLD);
+				ast_party_connected_line_free(&connected_line);
+				return -1;
+			}
+
+			tries = 0;
+			for (;;) {
+				/* Try to get party B back. */
+				ast_debug(1, "We're trying to callback %s/%s\n",
+					transferer_tech, transferer_name);
+				newchan = feature_request_and_dial(transferer, transferer_name_orig,
+					transferee, transferee, transferer_tech,
+					ast_channel_nativeformats(transferee), transferer_name,
+					atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
+				ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
+					!!newchan, outstate);
+				if (newchan) {
+					/*
+					 * We have recalled party B (newchan).  We need to give this
+					 * call leg the same feature flags as the original party B call
+					 * leg.
+					 */
+					ast_channel_lock(transferer);
+					features_datastore = ast_channel_datastore_find(transferer,
+						&dial_features_info, NULL);
+					if (features_datastore && (dialfeatures = features_datastore->data)) {
+						struct ast_flags my_features = { 0 };
+						struct ast_flags peer_features = { 0 };
+
+						ast_copy_flags(&my_features, &dialfeatures->my_features,
+							AST_FLAGS_ALL);
+						ast_copy_flags(&peer_features, &dialfeatures->peer_features,
+							AST_FLAGS_ALL);
+						ast_channel_unlock(transferer);
+						add_features_datastore(newchan, &my_features, &peer_features);
+					} else {
+						ast_channel_unlock(transferer);
+					}
+					break;
+				}
+				if (ast_check_hangup(transferee)) {
+					break;
+				}
+
+				++tries;
+				if (atxfercallbackretries <= tries) {
+					/* No more callback tries remaining. */
+					break;
+				}
+
+				if (atxferloopdelay) {
+					/* Transfer failed, sleeping */
+					ast_debug(1, "Sleeping for %u ms before retrying atxfer.\n",
+						atxferloopdelay);
+					ast_safe_sleep(transferee, atxferloopdelay);
+					if (ast_check_hangup(transferee)) {
+						ast_party_connected_line_free(&connected_line);
+						return -1;
+					}
+				}
+
+				/* Retry dialing party C. */
+				ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
+				newchan = feature_request_and_dial(transferer, transferer_name_orig,
+					transferer, transferee, "Local",
+					ast_channel_nativeformats(transferee), xferto,
+					atxfernoanswertimeout, &outstate, ast_channel_language(transferer));
+				ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
+					!!newchan, outstate);
+				if (newchan || ast_check_hangup(transferee)) {
+					break;
+				}
+			}
+		}
+		ast_indicate(transferee, AST_CONTROL_UNHOLD);
+		if (!newchan) {
+			/* No party C or could not callback party B. */
+			ast_party_connected_line_free(&connected_line);
+			return -1;
+		}
+
+		/* newchan is up, we should prepare transferee and bridge them */
+		if (ast_check_hangup(newchan)) {
+			ast_autoservice_chan_hangup_peer(transferee, newchan);
+			ast_party_connected_line_free(&connected_line);
+			return -1;
+		}
+		if (check_compat(transferee, newchan)) {
+			ast_party_connected_line_free(&connected_line);
+			return -1;
+		}
+	} else {
+		/*
+		 * Both the transferer and transferee have hungup.  If newchan
+		 * is up, hang it up as it has no one to talk to.
+		 */
+		ast_debug(1, "Everyone is hungup.\n");
+		if (newchan) {
+			ast_hangup(newchan);
+		}
+		ast_party_connected_line_free(&connected_line);
+		return -1;
+	}
+
+	/* Initiate the channel transfer of party A to party C (or recalled party B). */
+	ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
+
+	xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
+	if (!xferchan) {
+		ast_autoservice_chan_hangup_peer(transferee, newchan);
+		ast_party_connected_line_free(&connected_line);
+		return -1;
+	}
+
+	/* Give party A a momentary ringback tone during transfer. */
+	ast_channel_visible_indication_set(xferchan, AST_CONTROL_RINGING);
+
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(transferee));
+	ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(transferee));
+
+	if (ast_channel_masquerade(xferchan, transferee)) {
+		ast_hangup(xferchan);
+		ast_autoservice_chan_hangup_peer(transferee, newchan);
+		ast_party_connected_line_free(&connected_line);
+		return -1;
+	}
+
+	dash = strrchr(xferto, '@');
+	if (dash) {
+		/* Trim off the context. */
+		*dash = '\0';
+	}
+	ast_explicit_goto(xferchan, transferer_real_context, xferto, 1);
+	ast_channel_state_set(xferchan, AST_STATE_UP);
+	ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL);
+
+	/* Do the masquerade manually to make sure that is is completed. */
+	ast_do_masquerade(xferchan);
+
+	ast_channel_state_set(newchan, AST_STATE_UP);
+	ast_clear_flag(ast_channel_flags(newchan), AST_FLAGS_ALL);
+	tobj = ast_calloc(1, sizeof(*tobj));
+	if (!tobj) {
+		ast_hangup(xferchan);
+		ast_hangup(newchan);
+		ast_party_connected_line_free(&connected_line);
+		return -1;
+	}
+
+	tobj->chan = newchan;
+	tobj->peer = xferchan;
+	tobj->bconfig = *config;
+
+	ast_channel_lock(newchan);
+	features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL);
+	if (features_datastore && (dialfeatures = features_datastore->data)) {
+		ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features,
+			AST_FLAGS_ALL);
+	}
+	ast_channel_unlock(newchan);
+
+	ast_channel_lock(xferchan);
+	features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL);
+	if (features_datastore && (dialfeatures = features_datastore->data)) {
+		ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features,
+			AST_FLAGS_ALL);
+	}
+	ast_channel_unlock(xferchan);
+
+	if (tobj->bconfig.end_bridge_callback_data_fixup) {
+		tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
+	}
+
+	/*
+	 * xferchan is transferee, and newchan is the transfer target
+	 * So...in a transfer, who is the caller and who is the callee?
+	 *
+	 * When the call is originally made, it is clear who is caller and callee.
+	 * When a transfer occurs, it is my humble opinion that the transferee becomes
+	 * the caller, and the transfer target is the callee.
+	 *
+	 * The problem is that these macros were set with the intention of the original
+	 * caller and callee taking those roles.  A transfer can totally mess things up,
+	 * to be technical.  What sucks even more is that you can't effectively change
+	 * the macros in the dialplan during the call from the transferer to the transfer
+	 * target because the transferee is stuck with whatever role he originally had.
+	 *
+	 * I think the answer here is just to make sure that it is well documented that
+	 * during a transfer, the transferee is the "caller" and the transfer target
+	 * is the "callee."
+	 *
+	 * This means that if party B calls party A, and party B transfers party A to
+	 * party C, then A has switched roles for the call.  Now party A will have the
+	 * caller macro called on his channel instead of the callee macro.
+	 *
+	 * Luckily, the method by which the party B to party C bridge is
+	 * launched above ensures that the transferee is the "chan" on
+	 * the bridge and the transfer target is the "peer," so my idea
+	 * for the roles post-transfer does not require extensive code
+	 * changes.
+	 */
+
+	/* Transfer party C connected line to party A */
+	ast_channel_lock(transferer);
+	/*
+	 * Due to a limitation regarding when callerID is set on a Local channel,
+	 * we use the transferer's connected line information here.
+	 */
+	ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer));
+	ast_channel_unlock(transferer);
+	connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+	if (ast_channel_connected_line_sub(newchan, xferchan, &connected_line, 0) &&
+		ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
+		ast_channel_update_connected_line(xferchan, &connected_line, NULL);
+	}
+
+	/* Transfer party A connected line to party C */
+	ast_channel_lock(xferchan);
+	ast_connected_line_copy_from_caller(&connected_line, ast_channel_caller(xferchan));
+	ast_channel_unlock(xferchan);
+	connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+	if (ast_channel_connected_line_sub(xferchan, newchan, &connected_line, 0) &&
+		ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
+		ast_channel_update_connected_line(newchan, &connected_line, NULL);
+	}
+
+	if (ast_stream_and_wait(newchan, xfersound, ""))
+		ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+	bridge_call_thread_launch(tobj);
+
+	ast_party_connected_line_free(&connected_line);
+	return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */
+}
+
+/* add atxfer and automon as undefined so you can only use em if you configure them */
+#define FEATURES_COUNT ARRAY_LEN(builtin_features)
+
+AST_RWLOCK_DEFINE_STATIC(features_lock);
+
+static struct ast_call_feature builtin_features[] = {
+	{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+};
+
+
+static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
+
+/*! \brief register new feature into feature_list*/
+void ast_register_feature(struct ast_call_feature *feature)
+{
+	if (!feature) {
+		ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
+		return;
+	}
+
+	AST_RWLIST_WRLOCK(&feature_list);
+	AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
+	AST_RWLIST_UNLOCK(&feature_list);
+
+	ast_verb(2, "Registered Feature '%s'\n",feature->sname);
+}
+
+/*!
+ * \brief Add new feature group
+ * \param fgname feature group name.
+ *
+ * Add new feature group to the feature group list insert at head of list.
+ * \note This function MUST be called while feature_groups is locked.
+ */
+static struct feature_group *register_group(const char *fgname)
+{
+	struct feature_group *fg;
+
+	if (!fgname) {
+		ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
+		return NULL;
+	}
+
+	if (!(fg = ast_calloc_with_stringfields(1, struct feature_group, 128))) {
+		return NULL;
+	}
+
+	ast_string_field_set(fg, gname, fgname);
+
+	AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
+
+	ast_verb(2, "Registered group '%s'\n", fg->gname);
+
+	return fg;
+}
+
+/*!
+ * \brief Add feature to group
+ * \param fg feature group
+ * \param exten
+ * \param feature feature to add.
+ *
+ * Check fg and feature specified, add feature to list
+ * \note This function MUST be called while feature_groups is locked.
+ */
+static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
+{
+	struct feature_group_exten *fge;
+
+	if (!fg) {
+		ast_log(LOG_NOTICE, "You didn't pass a group!\n");
+		return;
+	}
+
+	if (!feature) {
+		ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
+		return;
+	}
+
+	if (!(fge = ast_calloc_with_stringfields(1, struct feature_group_exten, 128))) {
+		return;
+	}
+
+	ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
+
+	fge->feature = feature;
+
+	AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
+
+	ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
+					feature->sname, fg->gname, fge->exten);
+}
+
+void ast_unregister_feature(struct ast_call_feature *feature)
+{
+	if (!feature) {
+		return;
+	}
+
+	AST_RWLIST_WRLOCK(&feature_list);
+	AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
+	AST_RWLIST_UNLOCK(&feature_list);
+
+	ast_free(feature);
+}
+
+/*! \brief Remove all features in the list */
+static void ast_unregister_features(void)
+{
+	struct ast_call_feature *feature;
+
+	AST_RWLIST_WRLOCK(&feature_list);
+	while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
+		ast_free(feature);
+	}
+	AST_RWLIST_UNLOCK(&feature_list);
+}
+
+/*! \brief find a call feature by name */
+static struct ast_call_feature *find_dynamic_feature(const char *name)
+{
+	struct ast_call_feature *tmp;
+
+	AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
+		if (!strcasecmp(tmp->sname, name)) {
+			break;
+		}
+	}
+
+	return tmp;
+}
+
+/*! \brief Remove all feature groups in the list */
+static void ast_unregister_groups(void)
+{
+	struct feature_group *fg;
+	struct feature_group_exten *fge;
+
+	AST_RWLIST_WRLOCK(&feature_groups);
+	while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
+		while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
+			ast_string_field_free_memory(fge);
+			ast_free(fge);
+		}
+
+		ast_string_field_free_memory(fg);
+		ast_free(fg);
+	}
+	AST_RWLIST_UNLOCK(&feature_groups);
+}
+
+/*!
+ * \brief Find a group by name
+ * \param name feature name
+ * \retval feature group on success.
+ * \retval NULL on failure.
+ */
+static struct feature_group *find_group(const char *name)
+{
+	struct feature_group *fg = NULL;
+
+	AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
+		if (!strcasecmp(fg->gname, name))
+			break;
+	}
+
+	return fg;
+}
+
+void ast_rdlock_call_features(void)
+{
+	ast_rwlock_rdlock(&features_lock);
+}
+
+void ast_unlock_call_features(void)
+{
+	ast_rwlock_unlock(&features_lock);
+}
+
+/*!
+ * \internal
+ * \pre Expects feature_lock to be readlocked
+ */
+struct ast_call_feature *ast_find_call_feature(const char *name)
+{
+	int x;
+	for (x = 0; x < FEATURES_COUNT; x++) {
+		if (!strcasecmp(name, builtin_features[x].sname))
+			return &builtin_features[x];
+	}
+
+	return find_dynamic_feature(name);
+}
+
+struct feature_exten {
+	char sname[FEATURE_SNAME_LEN];
+	char exten[FEATURE_MAX_LEN];
+};
+
+struct feature_ds {
+	struct ao2_container *feature_map;
+
+	/*!
+	 * \brief specified in seconds, stored in milliseconds
+	 *
+	 * \todo XXX This isn't pretty.  At some point it would be nice to have all
+	 * of the global / [general] options in a config object that we store here
+	 * instead of handling each one manually.
+	 * */
+	unsigned int parkingtime;
+	unsigned int parkingtime_is_set:1;
+};
+
+static void feature_ds_destroy(void *data)
+{
+	struct feature_ds *feature_ds = data;
+
+	if (feature_ds->feature_map) {
+		ao2_ref(feature_ds->feature_map, -1);
+		feature_ds->feature_map = NULL;
+	}
+
+	ast_free(feature_ds);
+}
+
+static const struct ast_datastore_info feature_ds_info = {
+	.type = "FEATURE",
+	.destroy = feature_ds_destroy,
+};
+
+static int feature_exten_hash(const void *obj, int flags)
+{
+	const struct feature_exten *fe = obj;
+	const char *sname = obj;
+
+	return ast_str_hash(flags & OBJ_KEY ? sname : fe->sname);
+}
+
+static int feature_exten_cmp(void *obj, void *arg, int flags)
+{
+	const struct feature_exten *fe = obj, *fe2 = arg;
+	const char *sname = arg;
+
+	return !strcmp(fe->sname, flags & OBJ_KEY ? sname : fe2->sname) ?
+			CMP_MATCH | CMP_STOP : 0;
+}
+
+/*!
+ * \internal
+ * \brief Find or create feature datastore on a channel
+ *
+ * \pre chan is locked
+ *
+ * \return the data on the FEATURE datastore, or NULL on error
+ */
+static struct feature_ds *get_feature_ds(struct ast_channel *chan)
+{
+	struct feature_ds *feature_ds;
+	struct ast_datastore *ds;
+
+	if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
+		feature_ds = ds->data;
+		return feature_ds;
+	}
+
+	if (!(feature_ds = ast_calloc(1, sizeof(*feature_ds)))) {
+		return NULL;
+	}
+
+	if (!(feature_ds->feature_map = ao2_container_alloc(7, feature_exten_hash, feature_exten_cmp))) {
+		feature_ds_destroy(feature_ds);
+		return NULL;
+	}
+
+	if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
+		feature_ds_destroy(feature_ds);
+		return NULL;
+	}
+
+	ds->data = feature_ds;
+
+	ast_channel_datastore_add(chan, ds);
+
+	return feature_ds;
+}
+
+/*!
+ * \internal
+ * \brief Get the extension for a given builtin feature
+ *
+ * \pre expects feature_lock to be readlocked
+ *
+ * \retval 0 success
+ * \retval non-zero failiure
+ */
+static int builtin_feature_get_exten(struct ast_channel *chan, const char *feature_name,
+		char *buf, size_t len)
+{
+	struct ast_call_feature *feature;
+	struct feature_ds *feature_ds;
+	struct feature_exten *fe = NULL;
+
+	*buf = '\0';
+
+	if (!(feature = ast_find_call_feature(feature_name))) {
+		return -1;
+	}
+
+	ast_copy_string(buf, feature->exten, len);
+
+	ast_unlock_call_features();
+
+	ast_channel_lock(chan);
+	if ((feature_ds = get_feature_ds(chan))) {
+		fe = ao2_find(feature_ds->feature_map, feature_name, OBJ_KEY);
+	}
+	ast_channel_unlock(chan);
+
+	ast_rdlock_call_features();
+
+	if (fe) {
+		ao2_lock(fe);
+		ast_copy_string(buf, fe->exten, len);
+		ao2_unlock(fe);
+		ao2_ref(fe, -1);
+		fe = NULL;
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief exec an app by feature
+ * \param chan,peer,config,code,sense,data
+ *
+ * Find a feature, determine which channel activated
+ * \retval AST_FEATURE_RETURN_NO_HANGUP_PEER
+ * \retval -1 error.
+ * \retval -2 when an application cannot be found.
+ */
+static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+	struct ast_app *app;
+	struct ast_call_feature *feature = data;
+	struct ast_channel *work, *idle;
+	int res;
+
+	if (!feature) { /* shouldn't ever happen! */
+		ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
+		return -1;
+	}
+
+	if (sense == FEATURE_SENSE_CHAN) {
+		if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
+			return AST_FEATURE_RETURN_KEEPTRYING;
+		if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
+			work = chan;
+			idle = peer;
+		} else {
+			work = peer;
+			idle = chan;
+		}
+	} else {
+		if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
+			return AST_FEATURE_RETURN_KEEPTRYING;
+		if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
+			work = peer;
+			idle = chan;
+		} else {
+			work = chan;
+			idle = peer;
+		}
+	}
+
+	if (!(app = pbx_findapp(feature->app))) {
+		ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
+		return -2;
+	}
+
+	ast_autoservice_start(idle);
+	ast_autoservice_ignore(idle, AST_FRAME_DTMF_END);
+
+	pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", ast_channel_name(idle));
+	pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", ast_channel_name(work));
+	pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname);
+	pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname);
+
+	if (!ast_strlen_zero(feature->moh_class))
+		ast_moh_start(idle, feature->moh_class, NULL);
+
+	if (!strcasecmp("Gosub", feature->app)) {
+		res = ast_app_exec_sub(NULL, work, feature->app_args, 0);
+	} else if (!strcasecmp("Macro", feature->app)) {
+		res = ast_app_exec_macro(NULL, work, feature->app_args);
+	} else {
+		res = pbx_exec(work, app, feature->app_args);
+	}
+
+	if (!ast_strlen_zero(feature->moh_class))
+		ast_moh_stop(idle);
+
+	ast_autoservice_stop(idle);
+
+	if (res) {
+		return AST_FEATURE_RETURN_SUCCESSBREAK;
+	}
+	return AST_FEATURE_RETURN_SUCCESS;	/*! \todo XXX should probably return res */
+}
+
+static void unmap_features(void)
+{
+	int x;
+
+	ast_rwlock_wrlock(&features_lock);
+	for (x = 0; x < FEATURES_COUNT; x++)
+		strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
+	ast_rwlock_unlock(&features_lock);
+}
+
+static int remap_feature(const char *name, const char *value)
+{
+	int x, res = -1;
+
+	ast_rwlock_wrlock(&features_lock);
+	for (x = 0; x < FEATURES_COUNT; x++) {
+		if (strcasecmp(builtin_features[x].sname, name))
+			continue;
+
+		ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
+		res = 0;
+		break;
+	}
+	ast_rwlock_unlock(&features_lock);
+
+	return res;
+}
+
+/*!
+ * \brief Helper function for feature_interpret and ast_feature_detect
+ * \param chan,peer,config,code,sense,dynamic_features_buf,features,operation,feature
+ *
+ * Lock features list, browse for code, unlock list
+ * If a feature is found and the operation variable is set, that feature's
+ * operation is executed.  The first feature found is copied to the feature parameter.
+ * \retval res on success.
+ * \retval -1 on failure.
+ */
+static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
+	struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
+	struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
+{
+	int x;
+	struct feature_group *fg = NULL;
+	struct feature_group_exten *fge;
+	struct ast_call_feature *tmpfeature;
+	char *tmp, *tok;
+	int res = AST_FEATURE_RETURN_PASSDIGITS;
+	int feature_detected = 0;
+
+	if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
+		return -1; /* can not run feature operation */
+	}
+
+	ast_rwlock_rdlock(&features_lock);
+	for (x = 0; x < FEATURES_COUNT; x++) {
+		char feature_exten[FEATURE_MAX_LEN] = "";
+
+		if (!ast_test_flag(features, builtin_features[x].feature_mask)) {
+			continue;
+		}
+
+		if (builtin_feature_get_exten(chan, builtin_features[x].sname, feature_exten, sizeof(feature_exten))) {
+			continue;
+		}
+
+		/* Feature is up for consideration */
+
+		if (!strcmp(feature_exten, code)) {
+			ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, feature_exten);
+			if (operation == FEATURE_INTERPRET_CHECK) {
+				res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
+			} else if (operation == FEATURE_INTERPRET_DO) {
+				res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
+				ast_test_suite_event_notify("FEATURE_DETECTION",
+						"Result: success\r\n"
+						"Feature: %s",
+						builtin_features[x].sname);
+			}
+			if (feature) {
+				memcpy(feature, &builtin_features[x], sizeof(*feature));
+			}
+			feature_detected = 1;
+			break;
+		} else if (!strncmp(feature_exten, code, strlen(code))) {
+			if (res == AST_FEATURE_RETURN_PASSDIGITS) {
+				res = AST_FEATURE_RETURN_STOREDIGITS;
+			}
+		}
+	}
+
+	if (operation == FEATURE_INTERPRET_CHECK && x == FEATURES_COUNT) {
+		ast_test_suite_event_notify("FEATURE_DETECTION",
+				"Result: fail");
+	}
+
+	ast_rwlock_unlock(&features_lock);
+
+	if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
+		return res;
+	}
+
+	tmp = dynamic_features_buf;
+
+	while ((tok = strsep(&tmp, "#"))) {
+		AST_RWLIST_RDLOCK(&feature_groups);
+
+		fg = find_group(tok);
+
+		if (fg) {
+			AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+				if (!strcmp(fge->exten, code)) {
+					if (operation) {
+						res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
+					}
+					if (feature) {
+						memcpy(feature, fge->feature, sizeof(*feature));
+					}
+					if (res != AST_FEATURE_RETURN_KEEPTRYING) {
+						AST_RWLIST_UNLOCK(&feature_groups);
+						break;
+					}
+					res = AST_FEATURE_RETURN_PASSDIGITS;
+				} else if (!strncmp(fge->exten, code, strlen(code))) {
+					res = AST_FEATURE_RETURN_STOREDIGITS;
+				}
+			}
+			if (fge) {
+				break;
+			}
+		}
+
+		AST_RWLIST_UNLOCK(&feature_groups);
+
+		AST_RWLIST_RDLOCK(&feature_list);
+
+		if (!(tmpfeature = find_dynamic_feature(tok))) {
+			AST_RWLIST_UNLOCK(&feature_list);
+			continue;
+		}
+
+		/* Feature is up for consideration */
+		if (!strcmp(tmpfeature->exten, code)) {
+			ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
+			if (operation == FEATURE_INTERPRET_CHECK) {
+				res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
+			} else if (operation == FEATURE_INTERPRET_DO) {
+				res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
+			}
+			if (feature) {
+				memcpy(feature, tmpfeature, sizeof(*feature));
+			}
+			if (res != AST_FEATURE_RETURN_KEEPTRYING) {
+				AST_RWLIST_UNLOCK(&feature_list);
+				break;
+			}
+			res = AST_FEATURE_RETURN_PASSDIGITS;
+		} else if (!strncmp(tmpfeature->exten, code, strlen(code)))
+			res = AST_FEATURE_RETURN_STOREDIGITS;
+
+		AST_RWLIST_UNLOCK(&feature_list);
+	}
+
+	return res;
+}
+
+/*!
+ * \brief Check the dynamic features
+ * \param chan,peer,config,code,sense
+ *
+ * \retval res on success.
+ * \retval -1 on failure.
+ */
+static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) {
+
+	char dynamic_features_buf[128];
+	const char *peer_dynamic_features, *chan_dynamic_features;
+	struct ast_flags features;
+	struct ast_call_feature feature;
+	if (sense == FEATURE_SENSE_CHAN) {
+		/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
+		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
+	}
+	else {
+		/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
+		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
+	}
+
+	ast_channel_lock(peer);
+	peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
+	ast_channel_unlock(peer);
+
+	ast_channel_lock(chan);
+	chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
+	ast_channel_unlock(chan);
+
+	snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
+
+	ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%u, dynamic=%s\n", ast_channel_name(chan), ast_channel_name(peer), code, sense, features.flags, dynamic_features_buf);
+
+	return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
+}
+
+
+int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
+
+	return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
+}
+
+/*! \brief Check if a feature exists */
+static int feature_check(struct ast_channel *chan, struct ast_flags *features, char *code) {
+	char *chan_dynamic_features;
+	ast_channel_lock(chan);
+	chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
+	ast_channel_unlock(chan);
+
+	return feature_interpret_helper(chan, NULL, NULL, code, 0, chan_dynamic_features, features, FEATURE_INTERPRET_CHECK, NULL);
+}
+
+static void set_config_flags(struct ast_channel *chan, struct ast_bridge_config *config)
+{
+	int x;
+
+	ast_clear_flag(config, AST_FLAGS_ALL);
+
+	ast_rwlock_rdlock(&features_lock);
+	for (x = 0; x < FEATURES_COUNT; x++) {
+		if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
+			continue;
+
+		if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
+			ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
+
+		if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
+			ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
+	}
+	ast_rwlock_unlock(&features_lock);
+
+	if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
+		const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
+
+		if (dynamic_features) {
+			char *tmp = ast_strdupa(dynamic_features);
+			char *tok;
+			struct ast_call_feature *feature;
+
+			/* while we have a feature */
+			while ((tok = strsep(&tmp, "#"))) {
+				struct feature_group *fg;
+
+				AST_RWLIST_RDLOCK(&feature_groups);
+				AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
+					struct feature_group_exten *fge;
+
+					AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+						if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLER)) {
+							ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
+						}
+						if (ast_test_flag(fge->feature, AST_FEATURE_FLAG_BYCALLEE)) {
+							ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
+						}
+					}
+				}
+				AST_RWLIST_UNLOCK(&feature_groups);
+
+				AST_RWLIST_RDLOCK(&feature_list);
+				if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
+					if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) {
+						ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
+					}
+					if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) {
+						ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
+					}
+				}
+				AST_RWLIST_UNLOCK(&feature_list);
+			}
+		}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Get feature and dial.
+ *
+ * \param caller Channel to represent as the calling channel for the dialed channel.
+ * \param caller_name Original caller channel name.
+ * \param requestor Channel to say is requesting the dial (usually the caller).
+ * \param transferee Channel that the dialed channel will be transferred to.
+ * \param type Channel technology type to dial.
+ * \param format Codec formats for dialed channel.
+ * \param addr destination of the call
+ * \param timeout Time limit for dialed channel to answer in ms. Must be greater than zero.
+ * \param outstate Status of dialed channel if unsuccessful.
+ * \param language Language of the caller.
+ *
+ * \note
+ * outstate can be:
+ * 0, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION,
+ * AST_CONTROL_ANSWER, or AST_CONTROL_UNHOLD.  If
+ * AST_CONTROL_UNHOLD then the caller channel cancelled the
+ * transfer or the dialed channel did not answer before the
+ * timeout.
+ *
+ * \details
+ * Request channel, set channel variables, initiate call,
+ * check if they want to disconnect, go into loop, check if timeout has elapsed,
+ * check if person to be transferred hung up, check for answer break loop,
+ * set cdr return channel.
+ *
+ * \retval Channel Connected channel for transfer.
+ * \retval NULL on failure to get third party connected.
+ *
+ * \note This is similar to __ast_request_and_dial() in channel.c
+ */
+static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
+	const char *caller_name, struct ast_channel *requestor,
+	struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, const char *addr,
+	int timeout, int *outstate, const char *language)
+{
+	int state = 0;
+	int cause = 0;
+	int to;
+	int caller_hungup;
+	int transferee_hungup;
+	struct ast_channel *chan;
+	struct ast_channel *monitor_chans[3];
+	struct ast_channel *active_channel;
+	int res;
+	int ready = 0;
+	struct timeval started;
+	int x, len = 0;
+	char *disconnect_code = NULL, *dialed_code = NULL;
+	struct ast_format_cap *tmp_cap;
+	struct ast_format best_audio_fmt;
+	struct ast_frame *f;
+	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
+
+	tmp_cap = ast_format_cap_alloc_nolock();
+	if (!tmp_cap) {
+		if (outstate) {
+			*outstate = 0;
+		}
+		return NULL;
+	}
+	ast_best_codec(cap, &best_audio_fmt);
+	ast_format_cap_add(tmp_cap, &best_audio_fmt);
+
+	caller_hungup = ast_check_hangup(caller);
+
+	if (!(chan = ast_request(type, tmp_cap, requestor, addr, &cause))) {
+		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr);
+		switch (cause) {
+		case AST_CAUSE_BUSY:
+			state = AST_CONTROL_BUSY;
+			break;
+		case AST_CAUSE_CONGESTION:
+			state = AST_CONTROL_CONGESTION;
+			break;
+		default:
+			state = 0;
+			break;
+		}
+		goto done;
+	}
+
+	ast_channel_language_set(chan, language);
+	ast_channel_inherit_variables(caller, chan);
+	pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name);
+
+	ast_channel_lock(chan);
+	ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(requestor));
+	ast_channel_unlock(chan);
+
+	if (ast_call(chan, addr, timeout)) {
+		ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr);
+		switch (ast_channel_hangupcause(chan)) {
+		case AST_CAUSE_BUSY:
+			state = AST_CONTROL_BUSY;
+			break;
+		case AST_CAUSE_CONGESTION:
+			state = AST_CONTROL_CONGESTION;
+			break;
+		default:
+			state = 0;
+			break;
+		}
+		goto done;
+	}
+
+	/* support dialing of the featuremap disconnect code while performing an attended tranfer */
+	ast_rwlock_rdlock(&features_lock);
+	for (x = 0; x < FEATURES_COUNT; x++) {
+		if (strcasecmp(builtin_features[x].sname, "disconnect"))
+			continue;
+
+		disconnect_code = builtin_features[x].exten;
+		len = strlen(disconnect_code) + 1;
+		dialed_code = ast_alloca(len);
+		memset(dialed_code, 0, len);
+		break;
+	}
+	ast_rwlock_unlock(&features_lock);
+	x = 0;
+	started = ast_tvnow();
+	to = timeout;
+	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
+
+	ast_poll_channel_add(caller, chan);
+
+	transferee_hungup = 0;
+	while (!ast_check_hangup(transferee) && (ast_channel_state(chan) != AST_STATE_UP)) {
+		int num_chans = 0;
+
+		monitor_chans[num_chans++] = transferee;
+		monitor_chans[num_chans++] = chan;
+		if (!caller_hungup) {
+			if (ast_check_hangup(caller)) {
+				caller_hungup = 1;
+
+#if defined(ATXFER_NULL_TECH)
+				/* Change caller's name to ensure that it will remain unique. */
+				set_new_chan_name(caller);
+
+				/*
+				 * Get rid of caller's physical technology so it is free for
+				 * other calls.
+				 */
+				set_kill_chan_tech(caller);
+#endif	/* defined(ATXFER_NULL_TECH) */
+			} else {
+				/* caller is not hungup so monitor it. */
+				monitor_chans[num_chans++] = caller;
+			}
+		}
+
+		/* see if the timeout has been violated */
+		if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
+			state = AST_CONTROL_UNHOLD;
+			ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", ast_channel_name(chan));
+			break; /*doh! timeout*/
+		}
+
+		active_channel = ast_waitfor_n(monitor_chans, num_chans, &to);
+		if (!active_channel)
+			continue;
+
+		f = NULL;
+		if (transferee == active_channel) {
+			struct ast_frame *dup_f;
+
+			f = ast_read(transferee);
+			if (f == NULL) { /*doh! where'd he go?*/
+				transferee_hungup = 1;
+				state = 0;
+				break;
+			}
+			if (ast_is_deferrable_frame(f)) {
+				dup_f = ast_frisolate(f);
+				if (dup_f) {
+					if (dup_f == f) {
+						f = NULL;
+					}
+					AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
+				}
+			}
+		} else if (chan == active_channel) {
+			if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
+				state = 0;
+				ast_autoservice_start(transferee);
+				chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state);
+				ast_autoservice_stop(transferee);
+				if (!chan) {
+					break;
+				}
+				continue;
+			}
+			f = ast_read(chan);
+			if (f == NULL) { /*doh! where'd he go?*/
+				switch (ast_channel_hangupcause(chan)) {
+				case AST_CAUSE_BUSY:
+					state = AST_CONTROL_BUSY;
+					break;
+				case AST_CAUSE_CONGESTION:
+					state = AST_CONTROL_CONGESTION;
+					break;
+				default:
+					state = 0;
+					break;
+				}
+				break;
+			}
+
+			if (f->frametype == AST_FRAME_CONTROL) {
+				if (f->subclass.integer == AST_CONTROL_RINGING) {
+					ast_verb(3, "%s is ringing\n", ast_channel_name(chan));
+					ast_indicate(caller, AST_CONTROL_RINGING);
+				} else if (f->subclass.integer == AST_CONTROL_BUSY) {
+					state = f->subclass.integer;
+					ast_verb(3, "%s is busy\n", ast_channel_name(chan));
+					ast_indicate(caller, AST_CONTROL_BUSY);
+					ast_frfree(f);
+					break;
+				} else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) {
+					ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", ast_channel_name(chan), ast_channel_exten(chan));
+				} else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
+					state = f->subclass.integer;
+					ast_verb(3, "%s is congested\n", ast_channel_name(chan));
+					ast_indicate(caller, AST_CONTROL_CONGESTION);
+					ast_frfree(f);
+					break;
+				} else if (f->subclass.integer == AST_CONTROL_ANSWER) {
+					/* This is what we are hoping for */
+					state = f->subclass.integer;
+					ast_frfree(f);
+					ready=1;
+					break;
+				} else if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+					ast_indicate_data(caller, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen);
+				} else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+					if (caller_hungup) {
+						struct ast_party_connected_line connected;
+
+						/* Just save it for the transfer. */
+						ast_party_connected_line_set_init(&connected, ast_channel_connected(caller));
+						res = ast_connected_line_parse_data(f->data.ptr, f->datalen,
+							&connected);
+						if (!res) {
+							ast_channel_set_connected_line(caller, &connected, NULL);
+						}
+						ast_party_connected_line_free(&connected);
+					} else {
+						ast_autoservice_start(transferee);
+						if (ast_channel_connected_line_sub(chan, caller, f, 1) &&
+							ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
+							ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE,
+								f->data.ptr, f->datalen);
+						}
+						ast_autoservice_stop(transferee);
+					}
+				} else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
+					if (!caller_hungup) {
+						ast_autoservice_start(transferee);
+						if (ast_channel_redirecting_sub(chan, caller, f, 1) &&
+							ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
+							ast_indicate_data(caller, AST_CONTROL_REDIRECTING,
+								f->data.ptr, f->datalen);
+						}
+						ast_autoservice_stop(transferee);
+					}
+				} else if (f->subclass.integer != -1
+					&& f->subclass.integer != AST_CONTROL_PROGRESS
+					&& f->subclass.integer != AST_CONTROL_PROCEEDING) {
+					ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
+				}
+				/* else who cares */
+			} else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
+				ast_write(caller, f);
+			}
+		} else if (caller == active_channel) {
+			f = ast_read(caller);
+			if (f) {
+				if (f->frametype == AST_FRAME_DTMF) {
+					dialed_code[x++] = f->subclass.integer;
+					dialed_code[x] = '\0';
+					if (strlen(dialed_code) == len) {
+						x = 0;
+					} else if (x && strncmp(dialed_code, disconnect_code, x)) {
+						x = 0;
+						dialed_code[x] = '\0';
+					}
+					if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
+						/* Caller Canceled the call */
+						state = AST_CONTROL_UNHOLD;
+						ast_frfree(f);
+						break;
+					}
+				} else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
+					ast_write(chan, f);
+				}
+			}
+		}
+		if (f)
+			ast_frfree(f);
+	} /* end while */
+
+	ast_poll_channel_del(caller, chan);
+
+	/*
+	 * We need to free all the deferred frames, but we only need to
+	 * queue the deferred frames if no hangup was received.
+	 */
+	ast_channel_lock(transferee);
+	transferee_hungup = (transferee_hungup || ast_check_hangup(transferee));
+	while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
+		if (!transferee_hungup) {
+			ast_queue_frame_head(transferee, f);
+		}
+		ast_frfree(f);
+	}
+	ast_channel_unlock(transferee);
+
+done:
+	ast_indicate(caller, -1);
+	if (chan && (ready || ast_channel_state(chan) == AST_STATE_UP)) {
+		state = AST_CONTROL_ANSWER;
+	} else if (chan) {
+		ast_hangup(chan);
+		chan = NULL;
+	}
+
+	tmp_cap = ast_format_cap_destroy(tmp_cap);
+
+	if (outstate)
+		*outstate = state;
+
+	return chan;
+}
+
+void ast_channel_log(char *title, struct ast_channel *chan);
+
+void ast_channel_log(char *title, struct ast_channel *chan) /* for debug, this is handy enough to justify keeping it in the source */
+{
+	ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long) chan);
+	ast_log(LOG_NOTICE, "CHAN: name: %s;  appl: %s; data: %s; contxt: %s;  exten: %s; pri: %d;\n",
+		ast_channel_name(chan), ast_channel_appl(chan), ast_channel_data(chan), ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
+	ast_log(LOG_NOTICE, "CHAN: acctcode: %s;  dialcontext: %s; amaflags: %x; maccontxt: %s;  macexten: %s; macpri: %d;\n",
+		ast_channel_accountcode(chan), ast_channel_dialcontext(chan), (unsigned)ast_channel_amaflags(chan), ast_channel_macrocontext(chan), ast_channel_macroexten(chan), ast_channel_macropriority(chan));
+	ast_log(LOG_NOTICE, "CHAN: masq: %p;  masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n",
+		ast_channel_masq(chan), ast_channel_masqr(chan),
+		ast_channel_internal_bridged_channel(chan), ast_channel_uniqueid(chan), ast_channel_linkedid(chan));
+	if (ast_channel_masqr(chan)) {
+		ast_log(LOG_NOTICE, "CHAN: masquerading as: %s;  cdr: %p;\n",
+			ast_channel_name(ast_channel_masqr(chan)), ast_channel_cdr(ast_channel_masqr(chan)));
+	}
+	if (ast_channel_internal_bridged_channel(chan)) {
+		ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", ast_channel_name(ast_channel_internal_bridged_channel(chan)));
+	}
+
+	ast_log(LOG_NOTICE, "===== done ====\n");
+}
+
+/*!
+ * \brief return the first unlocked cdr in a possible chain
+ */
+static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
+{
+	struct ast_cdr *cdr_orig = cdr;
+	while (cdr) {
+		if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
+			return cdr;
+		cdr = cdr->next;
+	}
+	return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
+}
+
+static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
+{
+	const char *feature;
+
+	if (ast_strlen_zero(features)) {
+		return;
+	}
+
+	for (feature = features; *feature; feature++) {
+		switch (*feature) {
+		case 'T' :
+		case 't' :
+			ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
+			break;
+		case 'K' :
+		case 'k' :
+			ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
+			break;
+		case 'H' :
+		case 'h' :
+			ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
+			break;
+		case 'W' :
+		case 'w' :
+			ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
+			break;
+		default :
+			ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
+		}
+	}
+}
+
+static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
+{
+	if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
+		/*
+		 * If we don't return here, then when we do a builtin_atxfer we
+		 * will copy the disconnect flags over from the atxfer to the
+		 * callee (Party C).
+		 */
+		return;
+	}
+
+	add_features_datastore(callee, &config->features_callee, &config->features_caller);
+}
+
+static void clear_dialed_interfaces(struct ast_channel *chan)
+{
+	struct ast_datastore *di_datastore;
+
+	ast_channel_lock(chan);
+	if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
+		if (option_debug) {
+			ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
+		}
+		if (!ast_channel_datastore_remove(chan, di_datastore)) {
+			ast_datastore_free(di_datastore);
+		}
+	}
+	ast_channel_unlock(chan);
+}
+
+void ast_bridge_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why)
+{
+	int dead;
+	long duration;
+
+	ast_channel_lock(chan);
+	dead = ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
+		|| (ast_channel_softhangup_internal_flag(chan)
+			& ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
+	ast_channel_unlock(chan);
+	if (dead) {
+		/* Channel is a zombie or a real hangup. */
+		return;
+	}
+
+	duration = ast_tvdiff_ms(ast_tvnow(), start);
+	ast_senddigit_end(chan, digit, duration);
+	ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
+		digit, ast_channel_name(chan), why, duration);
+}
+
+/*!
+ * \brief bridge the call and set CDR
+ *
+ * \param chan The bridge considers this channel the caller.
+ * \param peer The bridge considers this channel the callee.
+ * \param config Configuration for this bridge.
+ *
+ * Set start time, check for two channels,check if monitor on
+ * check for feature activation, create new CDR
+ * \retval res on success.
+ * \retval -1 on failure to bridge.
+ */
+int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+{
+	/* Copy voice back and forth between the two channels.  Give the peer
+	   the ability to transfer calls with '#<extension' syntax. */
+	struct ast_frame *f;
+	struct ast_channel *who;
+	char chan_featurecode[FEATURE_MAX_LEN + 1]="";
+	char peer_featurecode[FEATURE_MAX_LEN + 1]="";
+	char orig_channame[AST_CHANNEL_NAME];
+	char orig_peername[AST_CHANNEL_NAME];
+	int res;
+	int diff;
+	int hasfeatures=0;
+	int hadfeatures=0;
+	int sendingdtmfdigit = 0;
+	int we_disabled_peer_cdr = 0;
+	struct ast_option_header *aoh;
+	struct ast_cdr *bridge_cdr = NULL;
+	struct ast_cdr *chan_cdr = ast_channel_cdr(chan); /* the proper chan cdr, if there are forked cdrs */
+	struct ast_cdr *peer_cdr = ast_channel_cdr(peer); /* the proper chan cdr, if there are forked cdrs */
+	struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
+	struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
+	struct ast_silence_generator *silgen = NULL;
+	/*! TRUE if h-exten or hangup handlers run. */
+	int hangup_run = 0;
+
+	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
+	pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
+
+	/* Clear any BLINDTRANSFER since the transfer has completed. */
+	pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
+	pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
+
+	set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
+	add_features_datastores(chan, peer, config);
+
+	/* This is an interesting case.  One example is if a ringing channel gets redirected to
+	 * an extension that picks up a parked call.  This will make sure that the call taken
+	 * out of parking gets told that the channel it just got bridged to is still ringing. */
+	if (ast_channel_state(chan) == AST_STATE_RINGING && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
+		ast_indicate(peer, AST_CONTROL_RINGING);
+	}
+
+	if (monitor_ok) {
+		const char *monitor_exec;
+		struct ast_channel *src = NULL;
+		if (!monitor_app) {
+			if (!(monitor_app = pbx_findapp("Monitor")))
+				monitor_ok=0;
+		}
+		if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
+			src = chan;
+		else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
+			src = peer;
+		if (monitor_app && src) {
+			char *tmp = ast_strdupa(monitor_exec);
+			pbx_exec(src, monitor_app, tmp);
+		}
+	}
+
+	set_config_flags(chan, config);
+
+	/* Answer if need be */
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		if (ast_raw_answer(chan, 1)) {
+			return -1;
+		}
+	}
+
+#ifdef FOR_DEBUG
+	/* show the two channels and cdrs involved in the bridge for debug & devel purposes */
+	ast_channel_log("Pre-bridge CHAN Channel info", chan);
+	ast_channel_log("Pre-bridge PEER Channel info", peer);
+#endif
+	/* two channels are being marked as linked here */
+	ast_channel_set_linkgroup(chan,peer);
+
+	/* copy the userfield from the B-leg to A-leg if applicable */
+	if (ast_channel_cdr(chan) && ast_channel_cdr(peer) && !ast_strlen_zero(ast_channel_cdr(peer)->userfield)) {
+		char tmp[256];
+
+		ast_channel_lock(chan);
+		if (!ast_strlen_zero(ast_channel_cdr(chan)->userfield)) {
+			snprintf(tmp, sizeof(tmp), "%s;%s", ast_channel_cdr(chan)->userfield, ast_channel_cdr(peer)->userfield);
+			ast_cdr_appenduserfield(chan, tmp);
+		} else {
+			ast_cdr_setuserfield(chan, ast_channel_cdr(peer)->userfield);
+		}
+		ast_channel_unlock(chan);
+		/* Don't delete the CDR; just disable it. */
+		ast_set_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED);
+		we_disabled_peer_cdr = 1;
+	}
+	ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame));
+	ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername));
+
+	if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
+		ast_channel_lock_both(chan, peer);
+		if (chan_cdr) {
+			ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
+			ast_cdr_update(chan);
+			bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
+			/* rip any forked CDR's off of the chan_cdr and attach
+			 * them to the bridge_cdr instead */
+			bridge_cdr->next = chan_cdr->next;
+			chan_cdr->next = NULL;
+			ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
+			ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
+			if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
+				ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
+			}
+			ast_cdr_setaccount(peer, ast_channel_accountcode(chan));
+		} else {
+			/* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
+			bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
+			ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel));
+			ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel));
+			ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid));
+			ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
+			ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
+			ast_cdr_setcid(bridge_cdr, chan);
+			bridge_cdr->disposition = (ast_channel_state(chan) == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
+			bridge_cdr->amaflags = ast_channel_amaflags(chan) ? ast_channel_amaflags(chan) :  ast_default_amaflags;
+			ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode));
+			/* Destination information */
+			ast_copy_string(bridge_cdr->dst, ast_channel_exten(chan), sizeof(bridge_cdr->dst));
+			ast_copy_string(bridge_cdr->dcontext, ast_channel_context(chan), sizeof(bridge_cdr->dcontext));
+			if (peer_cdr) {
+				bridge_cdr->start = peer_cdr->start;
+				ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
+			} else {
+				ast_cdr_start(bridge_cdr);
+			}
+		}
+		ast_channel_unlock(chan);
+		ast_channel_unlock(peer);
+
+		ast_debug(4, "bridge answer set, chan answer set\n");
+		/* peer_cdr->answer will be set when a macro runs on the peer;
+		   in that case, the bridge answer will be delayed while the
+		   macro plays on the peer channel. The peer answered the call
+		   before the macro started playing. To the phone system,
+		   this is billable time for the call, even tho the caller
+		   hears nothing but ringing while the macro does its thing. */
+
+		/* Another case where the peer cdr's time will be set, is when
+		   A self-parks by pickup up phone and dialing 700, then B
+		   picks up A by dialing its parking slot; there may be more
+		   practical paths that get the same result, tho... in which
+		   case you get the previous answer time from the Park... which
+		   is before the bridge's start time, so I added in the
+		   tvcmp check to the if below */
+
+		if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
+			ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
+			ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
+			if (chan_cdr) {
+				ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
+				ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
+			}
+		} else {
+			ast_cdr_answer(bridge_cdr);
+			if (chan_cdr) {
+				ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
+			}
+		}
+		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
+			if (chan_cdr) {
+				ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
+			}
+			if (peer_cdr) {
+				ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
+			}
+		}
+		/* the DIALED flag may be set if a dialed channel is transferred
+		 * and then bridged to another channel.  In order for the
+		 * bridge CDR to be written, the DIALED flag must not be
+		 * present. */
+		ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
+	}
+	ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);
+
+	/* If we are bridging a call, stop worrying about forwarding loops. We presume that if
+	 * a call is being bridged, that the humans in charge know what they're doing. If they
+	 * don't, well, what can we do about that? */
+	clear_dialed_interfaces(chan);
+	clear_dialed_interfaces(peer);
+
+	for (;;) {
+		struct ast_channel *other;	/* used later */
+
+		res = ast_channel_bridge(chan, peer, config, &f, &who);
+
+		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
+			|| ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE)) {
+			/* Zombies are present time to leave! */
+			res = -1;
+			if (f) {
+				ast_frfree(f);
+			}
+			goto before_you_go;
+		}
+
+		/* When frame is not set, we are probably involved in a situation
+		   where we've timed out.
+		   When frame is set, we'll come this code twice; once for DTMF_BEGIN
+		   and also for DTMF_END. If we flow into the following 'if' for both, then
+		   our wait times are cut in half, as both will subtract from the
+		   feature_timer. Not good!
+		*/
+		if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
+			/* Update feature timer for next pass */
+			diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
+			if (res == AST_BRIDGE_RETRY) {
+				/* The feature fully timed out but has not been updated. Skip
+				 * the potential round error from the diff calculation and
+				 * explicitly set to expired. */
+				config->feature_timer = -1;
+			} else {
+				config->feature_timer -= diff;
+			}
+
+			if (hasfeatures) {
+				if (config->feature_timer <= 0) {
+					/* Not *really* out of time, just out of time for
+					   digits to come in for features. */
+					ast_debug(1, "Timed out for feature!\n");
+					if (!ast_strlen_zero(peer_featurecode)) {
+						ast_dtmf_stream(chan, peer, peer_featurecode, 0, f ? f->len : 0);
+						memset(peer_featurecode, 0, sizeof(peer_featurecode));
+					}
+					if (!ast_strlen_zero(chan_featurecode)) {
+						ast_dtmf_stream(peer, chan, chan_featurecode, 0, f ? f->len : 0);
+						memset(chan_featurecode, 0, sizeof(chan_featurecode));
+					}
+					if (f)
+						ast_frfree(f);
+					hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
+					if (!hasfeatures) {
+						/* No more digits expected - reset the timer */
+						config->feature_timer = 0;
+					}
+					hadfeatures = hasfeatures;
+					/* Continue as we were */
+					continue;
+				} else if (!f) {
+					/* The bridge returned without a frame and there is a feature in progress.
+					 * However, we don't think the feature has quite yet timed out, so just
+					 * go back into the bridge. */
+					continue;
+				}
+			} else {
+				if (config->feature_timer <=0) {
+					/* We ran out of time */
+					config->feature_timer = 0;
+					who = chan;
+					if (f)
+						ast_frfree(f);
+					f = NULL;
+					res = 0;
+				}
+			}
+		}
+		if (res < 0) {
+			if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) && !ast_test_flag(ast_channel_flags(peer), AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
+				ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", ast_channel_name(chan), ast_channel_name(peer));
+			}
+			goto before_you_go;
+		}
+
+		if (!f || (f->frametype == AST_FRAME_CONTROL &&
+				(f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
+					f->subclass.integer == AST_CONTROL_CONGESTION))) {
+			res = -1;
+			break;
+		}
+		/* many things should be sent to the 'other' channel */
+		other = (who == chan) ? peer : chan;
+		if (f->frametype == AST_FRAME_CONTROL) {
+			switch (f->subclass.integer) {
+			case AST_CONTROL_RINGING:
+			case AST_CONTROL_FLASH:
+			case AST_CONTROL_MCID:
+			case -1:
+				ast_indicate(other, f->subclass.integer);
+				break;
+			case AST_CONTROL_CONNECTED_LINE:
+				if (ast_channel_connected_line_sub(who, other, f, 1) &&
+					ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
+					ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				}
+				break;
+			case AST_CONTROL_REDIRECTING:
+				if (ast_channel_redirecting_sub(who, other, f, 1) &&
+					ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
+					ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				}
+				break;
+			case AST_CONTROL_PVT_CAUSE_CODE:
+			case AST_CONTROL_AOC:
+			case AST_CONTROL_HOLD:
+			case AST_CONTROL_UNHOLD:
+				ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+				break;
+			case AST_CONTROL_OPTION:
+				aoh = f->data.ptr;
+				/* Forward option Requests, but only ones we know are safe
+				 * These are ONLY sent by chan_iax2 and I'm not convinced that
+				 * they are useful. I haven't deleted them entirely because I
+				 * just am not sure of the ramifications of removing them. */
+				if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
+					switch (ntohs(aoh->option)) {
+					case AST_OPTION_TONE_VERIFY:
+					case AST_OPTION_TDD:
+					case AST_OPTION_RELAXDTMF:
+					case AST_OPTION_AUDIO_MODE:
+					case AST_OPTION_DIGIT_DETECT:
+					case AST_OPTION_FAX_DETECT:
+						ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
+							f->datalen - sizeof(struct ast_option_header), 0);
+					}
+				}
+				break;
+			}
+		} else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
+			struct ast_flags *cfg;
+			char dtmfcode[2] = { f->subclass.integer, };
+			size_t featurelen;
+
+			if (who == chan) {
+				featurelen = strlen(chan_featurecode);
+				cfg = &(config->features_caller);
+			} else {
+				featurelen = strlen(peer_featurecode);
+				cfg = &(config->features_callee);
+			}
+			/* Take a peek if this (possibly) matches a feature. If not, just pass this
+			 * DTMF along untouched. If this is not the first digit of a multi-digit code
+			 * then we need to fall through and stream the characters if it matches */
+			if (featurelen == 0
+				&& feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
+				if (option_debug > 3) {
+					ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
+				}
+				ast_write(other, f);
+				sendingdtmfdigit = 1;
+			} else {
+				/* If ast_opt_transmit_silence is set, then we need to make sure we are
+				 * transmitting something while we hold on to the DTMF waiting for a
+				 * feature. */
+				if (!silgen && ast_opt_transmit_silence) {
+					silgen = ast_channel_start_silence_generator(other);
+				}
+				if (option_debug > 3) {
+					ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
+				}
+			}
+		} else if (f->frametype == AST_FRAME_DTMF_END) {
+			char *featurecode;
+			int sense;
+			unsigned int dtmfduration = f->len;
+
+			hadfeatures = hasfeatures;
+			/* This cannot overrun because the longest feature is one shorter than our buffer */
+			if (who == chan) {
+				sense = FEATURE_SENSE_CHAN;
+				featurecode = chan_featurecode;
+			} else  {
+				sense = FEATURE_SENSE_PEER;
+				featurecode = peer_featurecode;
+			}
+
+			if (sendingdtmfdigit == 1) {
+				/* We let the BEGIN go through happily, so let's not bother with the END,
+				 * since we already know it's not something we bother with */
+				ast_write(other, f);
+				sendingdtmfdigit = 0;
+			} else {
+				/*! append the event to featurecode. we rely on the string being zero-filled, and
+				 * not overflowing it.
+				 * \todo XXX how do we guarantee the latter ?
+				 */
+				featurecode[strlen(featurecode)] = f->subclass.integer;
+				/* Get rid of the frame before we start doing "stuff" with the channels */
+				ast_frfree(f);
+				f = NULL;
+				if (silgen) {
+					ast_channel_stop_silence_generator(other, silgen);
+					silgen = NULL;
+				}
+				config->feature_timer = 0;
+				res = feature_interpret(chan, peer, config, featurecode, sense);
+				switch(res) {
+				case AST_FEATURE_RETURN_PASSDIGITS:
+					ast_dtmf_stream(other, who, featurecode, 0, dtmfduration);
+					/* Fall through */
+				case AST_FEATURE_RETURN_SUCCESS:
+					memset(featurecode, 0, sizeof(chan_featurecode));
+					break;
+				}
+				if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
+					res = 0;
+				} else {
+					break;
+				}
+				hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
+				if (hadfeatures && !hasfeatures) {
+					/* Feature completed or timed out */
+					config->feature_timer = 0;
+				} else if (hasfeatures) {
+					if (config->timelimit) {
+						/* No warning next time - we are waiting for feature code */
+						ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
+					}
+					config->feature_start_time = ast_tvnow();
+					config->feature_timer = featuredigittimeout;
+					ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
+				}
+			}
+		}
+		if (f)
+			ast_frfree(f);
+	}
+	ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
+
+before_you_go:
+	if (ast_channel_sending_dtmf_digit(chan)) {
+		ast_bridge_end_dtmf(chan, ast_channel_sending_dtmf_digit(chan),
+			ast_channel_sending_dtmf_tv(chan), "bridge end");
+	}
+	if (ast_channel_sending_dtmf_digit(peer)) {
+		ast_bridge_end_dtmf(peer, ast_channel_sending_dtmf_digit(peer),
+			ast_channel_sending_dtmf_tv(peer), "bridge end");
+	}
+
+	/* Just in case something weird happened and we didn't clean up the silence generator... */
+	if (silgen) {
+		ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
+		silgen = NULL;
+	}
+
+	/* Wait for any dual redirect to complete. */
+	while (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
+		sched_yield();
+	}
+
+	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) {
+		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
+		if (bridge_cdr) {
+			ast_cdr_discard(bridge_cdr);
+			/* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
+		}
+		return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
+	}
+
+	if (config->end_bridge_callback) {
+		config->end_bridge_callback(config->end_bridge_callback_data);
+	}
+
+	/* run the hangup exten on the chan object IFF it was NOT involved in a parking situation
+	 * if it were, then chan belongs to a different thread now, and might have been hung up long
+	 * ago.
+	 */
+	if (!(ast_channel_softhangup_internal_flag(chan) & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE))
+			&& !ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
+		struct ast_cdr *swapper = NULL;
+		char savelastapp[AST_MAX_EXTENSION];
+		char savelastdata[AST_MAX_EXTENSION];
+		char save_context[AST_MAX_CONTEXT];
+		char save_exten[AST_MAX_EXTENSION];
+		int  save_prio;
+
+		ast_channel_lock(chan);
+		if (bridge_cdr) {
+			/*
+			 * Swap the bridge_cdr and the chan cdr for a moment, and let
+			 * the hangup dialplan code operate on it.
+			 */
+			swapper = ast_channel_cdr(chan);
+			ast_channel_cdr_set(chan, bridge_cdr);
+
+			/* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
+			ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
+			ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
+		}
+		ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context));
+		ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten));
+		save_prio = ast_channel_priority(chan);
+		ast_channel_unlock(chan);
+
+		ast_autoservice_start(peer);
+		if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
+			S_COR(ast_channel_caller(chan)->id.number.valid,
+				ast_channel_caller(chan)->id.number.str, NULL))) {
+			ast_pbx_h_exten_run(chan, ast_channel_context(chan));
+			hangup_run = 1;
+		} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
+			&& ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
+				S_COR(ast_channel_caller(chan)->id.number.valid,
+					ast_channel_caller(chan)->id.number.str, NULL))) {
+			ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan));
+			hangup_run = 1;
+		}
+		if (ast_pbx_hangup_handler_run(chan)) {
+			/* Indicate hangup handlers were run. */
+			hangup_run = 1;
+		}
+		ast_autoservice_stop(peer);
+
+		ast_channel_lock(chan);
+
+		/* swap it back */
+		ast_channel_context_set(chan, save_context);
+		ast_channel_exten_set(chan, save_exten);
+		ast_channel_priority_set(chan, save_prio);
+		if (bridge_cdr) {
+			if (ast_channel_cdr(chan) == bridge_cdr) {
+				ast_channel_cdr_set(chan, swapper);
+
+				/* Restore the lastapp/lastdata */
+				ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
+				ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
+			} else {
+				bridge_cdr = NULL;
+			}
+		}
+		ast_channel_unlock(chan);
+	}
+
+	/* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
+	new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */
+
+	/*
+	 * If the channel CDR has been modified during the call, record
+	 * the changes in the bridge cdr, BUT, if hangup_run, the CDR
+	 * got swapped so don't overwrite what was done in the
+	 * h-extension or hangup handlers.  What a mess.  This is why
+	 * you never touch CDR code.
+	 */
+	if (new_chan_cdr && bridge_cdr && !hangup_run) {
+		ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
+		ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
+		bridge_cdr->amaflags = new_chan_cdr->amaflags;
+		ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
+		if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
+			ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
+		}
+	}
+
+	/* we can post the bridge CDR at this point */
+	if (bridge_cdr) {
+		ast_cdr_end(bridge_cdr);
+		ast_cdr_detach(bridge_cdr);
+	}
+
+	/* do a specialized reset on the beginning channel
+	   CDR's, if they still exist, so as not to mess up
+	   issues in future bridges;
+
+	   Here are the rules of the game:
+	   1. The chan and peer channel pointers will not change
+	      during the life of the bridge.
+	   2. But, in transfers, the channel names will change.
+	      between the time the bridge is started, and the
+	      time the channel ends.
+	      Usually, when a channel changes names, it will
+	      also change CDR pointers.
+	   3. Usually, only one of the two channels (chan or peer)
+	      will change names.
+	   4. Usually, if a channel changes names during a bridge,
+	      it is because of a transfer. Usually, in these situations,
+	      it is normal to see 2 bridges running simultaneously, and
+	      it is not unusual to see the two channels that change
+	      swapped between bridges.
+	   5. After a bridge occurs, we have 2 or 3 channels' CDRs
+	      to attend to; if the chan or peer changed names,
+	      we have the before and after attached CDR's.
+	*/
+
+	if (new_chan_cdr) {
+		struct ast_channel *chan_ptr = NULL;
+
+		if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) {
+			/* old channel */
+			if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
+				ast_channel_lock(chan_ptr);
+				if (!ast_bridged_channel(chan_ptr)) {
+					struct ast_cdr *cur;
+					for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) {
+						if (cur == chan_cdr) {
+							break;
+						}
+					}
+					if (cur) {
+						ast_cdr_specialized_reset(chan_cdr, 0);
+					}
+				}
+				ast_channel_unlock(chan_ptr);
+				chan_ptr = ast_channel_unref(chan_ptr);
+			}
+			/* new channel */
+			ast_cdr_specialized_reset(new_chan_cdr, 0);
+		} else {
+			ast_cdr_specialized_reset(ast_channel_cdr(chan), 0); /* nothing changed, reset the chan cdr  */
+		}
+	}
+
+	{
+		struct ast_channel *chan_ptr = NULL;
+		new_peer_cdr = pick_unlocked_cdr(ast_channel_cdr(peer)); /* the proper chan cdr, if there are forked cdrs */
+		if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
+			ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
+		if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) {
+			/* old channel */
+			if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
+				ast_channel_lock(chan_ptr);
+				if (!ast_bridged_channel(chan_ptr)) {
+					struct ast_cdr *cur;
+					for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) {
+						if (cur == peer_cdr) {
+							break;
+						}
+					}
+					if (cur) {
+						ast_cdr_specialized_reset(peer_cdr, 0);
+					}
+				}
+				ast_channel_unlock(chan_ptr);
+				chan_ptr = ast_channel_unref(chan_ptr);
+			}
+			/* new channel */
+			if (new_peer_cdr) {
+				ast_cdr_specialized_reset(new_peer_cdr, 0);
+			}
+		} else {
+			if (we_disabled_peer_cdr) {
+				ast_clear_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED);
+			}
+			ast_cdr_specialized_reset(ast_channel_cdr(peer), 0); /* nothing changed, reset the peer cdr  */
+		}
+	}
+
+	return res;
+}
+
+/*! \brief Output parking event to manager */
+static void post_manager_event(const char *s, struct parkeduser *pu)
+{
+	manager_event(EVENT_FLAG_CALL, s,
+		"Exten: %s\r\n"
+		"Channel: %s\r\n"
+		"Parkinglot: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"ConnectedLineNum: %s\r\n"
+		"ConnectedLineName: %s\r\n"
+		"UniqueID: %s\r\n",
+		pu->parkingexten,
+		ast_channel_name(pu->chan),
+		pu->parkinglot->name,
+		S_COR(ast_channel_caller(pu->chan)->id.number.valid, ast_channel_caller(pu->chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(pu->chan)->id.name.valid, ast_channel_caller(pu->chan)->id.name.str, "<unknown>"),
+		S_COR(ast_channel_connected(pu->chan)->id.number.valid, ast_channel_connected(pu->chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_connected(pu->chan)->id.name.valid, ast_channel_connected(pu->chan)->id.name.str, "<unknown>"),
+		ast_channel_uniqueid(pu->chan)
+		);
+}
+
+static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
+{
+	int i = 0;
+	enum {
+		OPT_CALLEE_REDIRECT   = 't',
+		OPT_CALLER_REDIRECT   = 'T',
+		OPT_CALLEE_AUTOMON    = 'w',
+		OPT_CALLER_AUTOMON    = 'W',
+		OPT_CALLEE_DISCONNECT = 'h',
+		OPT_CALLER_DISCONNECT = 'H',
+		OPT_CALLEE_PARKCALL   = 'k',
+		OPT_CALLER_PARKCALL   = 'K',
+	};
+
+	memset(options, 0, len);
+	if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
+		options[i++] = OPT_CALLER_REDIRECT;
+	}
+	if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
+		options[i++] = OPT_CALLER_AUTOMON;
+	}
+	if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
+		options[i++] = OPT_CALLER_DISCONNECT;
+	}
+	if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
+		options[i++] = OPT_CALLER_PARKCALL;
+	}
+
+	if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
+		options[i++] = OPT_CALLEE_REDIRECT;
+	}
+	if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
+		options[i++] = OPT_CALLEE_AUTOMON;
+	}
+	if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
+		options[i++] = OPT_CALLEE_DISCONNECT;
+	}
+	if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
+		options[i++] = OPT_CALLEE_PARKCALL;
+	}
+
+	return options;
+}
+
+/*!
+ * \internal
+ * \brief Run management on a parked call.
+ *
+ * \note The parkinglot parkings list is locked on entry.
+ *
+ * \retval TRUE if the parking completed.
+ */
+static int manage_parked_call(struct parkeduser *pu, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
+{
+	struct ast_channel *chan = pu->chan;	/* shorthand */
+	int tms;        /* timeout for this item */
+	int x;          /* fd index in channel */
+
+	tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
+	if (tms > pu->parkingtime) {
+		/*
+		 * Call has been parked too long.
+		 * Stop entertaining the caller.
+		 */
+		switch (pu->hold_method) {
+		case AST_CONTROL_HOLD:
+			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
+			break;
+		case AST_CONTROL_RINGING:
+			ast_indicate(pu->chan, -1);
+			break;
+		default:
+			break;
+		}
+		pu->hold_method = 0;
+
+		/* Get chan, exten from derived kludge */
+		if (pu->peername[0]) {
+			char *peername;
+			char *dash;
+			char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
+			int i;
+
+			peername = ast_strdupa(pu->peername);
+			dash = strrchr(peername, '-');
+			if (dash) {
+				*dash = '\0';
+			}
+
+			peername_flat = ast_strdupa(peername);
+			for (i = 0; peername_flat[i]; i++) {
+				if (peername_flat[i] == '/') {
+					peername_flat[i] = '_';
+				}
+			}
+
+			if (!ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar)) {
+				ast_log(LOG_ERROR,
+					"Parking dial context '%s' does not exist and unable to create\n",
+					parking_con_dial);
+			} else {
+				char returnexten[AST_MAX_EXTENSION];
+				char comebackdialtime[AST_MAX_EXTENSION];
+				struct ast_datastore *features_datastore;
+				struct ast_dial_features *dialfeatures;
+
+				if (!strncmp(peername, "Parked/", 7)) {
+					peername += 7;
+				}
+
+				ast_channel_lock(chan);
+				features_datastore = ast_channel_datastore_find(chan, &dial_features_info,
+					NULL);
+				if (features_datastore && (dialfeatures = features_datastore->data)) {
+					char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
+
+					snprintf(returnexten, sizeof(returnexten), "%s,%u,%s", peername,
+						pu->parkinglot->cfg.comebackdialtime,
+						callback_dialoptions(&dialfeatures->peer_features,
+							&dialfeatures->my_features, buf, sizeof(buf)));
+				} else { /* Existing default */
+					ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
+						ast_channel_name(chan));
+					snprintf(returnexten, sizeof(returnexten), "%s,%u,t", peername,
+						pu->parkinglot->cfg.comebackdialtime);
+				}
+				ast_channel_unlock(chan);
+
+				snprintf(comebackdialtime, sizeof(comebackdialtime), "%u",
+						pu->parkinglot->cfg.comebackdialtime);
+				pbx_builtin_setvar_helper(chan, "COMEBACKDIALTIME", comebackdialtime);
+
+				pbx_builtin_setvar_helper(chan, "PARKER", peername);
+
+				if (ast_add_extension(parking_con_dial, 1, peername_flat, 1, NULL, NULL,
+					"Dial", ast_strdup(returnexten), ast_free_ptr, registrar)) {
+					ast_log(LOG_ERROR,
+						"Could not create parking return dial exten: %s@%s\n",
+						peername_flat, parking_con_dial);
+				}
+			}
+			if (pu->options_specified) {
+				/*
+				 * Park() was called with overriding return arguments, respect
+				 * those arguments.
+				 */
+				set_c_e_p(chan, pu->context, pu->exten, pu->priority);
+			} else if (pu->parkinglot->cfg.comebacktoorigin) {
+				set_c_e_p(chan, parking_con_dial, peername_flat, 1);
+			} else {
+				char parkingslot[AST_MAX_EXTENSION];
+
+				snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
+				pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
+				pbx_builtin_setvar_helper(chan, "PARKEDLOT", pu->parkinglot->name);
+
+				/* Handle fallback when extensions don't exist here since that logic was removed from pbx */
+				if (ast_exists_extension(chan, pu->parkinglot->cfg.comebackcontext, peername_flat, 1, NULL)) {
+					set_c_e_p(chan, pu->parkinglot->cfg.comebackcontext, peername_flat, 1);
+				} else if (ast_exists_extension(chan, pu->parkinglot->cfg.comebackcontext, "s", 1, NULL)) {
+					ast_verb(2, "Can not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
+						pu->parkinglot->cfg.comebackcontext, peername_flat, pu->parkinglot->cfg.comebackcontext);
+					set_c_e_p(chan, pu->parkinglot->cfg.comebackcontext, "s", 1);
+				} else {
+					ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's at default'\n",
+						ast_channel_name(chan),
+						pu->parkinglot->cfg.comebackcontext, peername_flat,
+						pu->parkinglot->cfg.comebackcontext);
+					set_c_e_p(chan, "default", "s", 1);
+				}
+			}
+		} else {
+			/*
+			 * They've been waiting too long, send them back to where they
+			 * came.  Theoretically they should have their original
+			 * extensions and such, but we copy to be on the safe side.
+			 */
+			set_c_e_p(chan, pu->context, pu->exten, pu->priority);
+		}
+		post_manager_event("ParkedCallTimeOut", pu);
+		ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
+
+		ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n",
+			ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name, ast_channel_context(pu->chan),
+			ast_channel_exten(pu->chan), ast_channel_priority(pu->chan));
+
+		/* Start up the PBX, or hang them up */
+		if (ast_pbx_start(chan))  {
+			ast_log(LOG_WARNING,
+				"Unable to restart the PBX for user on '%s', hanging them up...\n",
+				ast_channel_name(pu->chan));
+			ast_hangup(chan);
+		}
+
+		/* And take them out of the parking lot */
+		return 1;
+	}
+
+	/* still within parking time, process descriptors */
+	if (pfds) {
+		for (x = 0; x < AST_MAX_FDS; x++) {
+			struct ast_frame *f;
+			int y;
+
+			if (!ast_channel_fd_isset(chan, x)) {
+				continue;	/* nothing on this descriptor */
+			}
+
+			for (y = 0; y < nfds; y++) {
+				if (pfds[y].fd == ast_channel_fd(chan, x)) {
+					/* Found poll record! */
+					break;
+				}
+			}
+			if (y == nfds) {
+				/* Not found */
+				continue;
+			}
+
+			if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) {
+				/* Next x */
+				continue;
+			}
+
+			if (pfds[y].revents & POLLPRI) {
+				ast_set_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
+			} else {
+				ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
+			}
+			ast_channel_fdno_set(chan, x);
+
+			/* See if they need servicing */
+			f = ast_read(pu->chan);
+			/* Hangup? */
+			if (!f || (f->frametype == AST_FRAME_CONTROL
+				&& f->subclass.integer == AST_CONTROL_HANGUP)) {
+				if (f) {
+					ast_frfree(f);
+				}
+				post_manager_event("ParkedCallGiveUp", pu);
+				ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp",
+					NULL);
+
+				/* There's a problem, hang them up */
+				ast_verb(2, "%s got tired of being parked\n", ast_channel_name(chan));
+				ast_hangup(chan);
+
+				/* And take them out of the parking lot */
+				return 1;
+			} else {
+				/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
+				ast_frfree(f);
+				if (pu->hold_method == AST_CONTROL_HOLD
+					&& pu->moh_trys < 3
+					&& !ast_channel_generatordata(chan)) {
+					ast_debug(1,
+						"MOH on parked call stopped by outside source.  Restarting on channel %s.\n",
+						ast_channel_name(chan));
+					ast_indicate_data(chan, AST_CONTROL_HOLD,
+						S_OR(pu->parkinglot->cfg.mohclass, NULL),
+						(!ast_strlen_zero(pu->parkinglot->cfg.mohclass)
+							? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0));
+					pu->moh_trys++;
+				}
+				break;
+			}
+		} /* End for */
+	}
+
+	/* mark fds for next round */
+	for (x = 0; x < AST_MAX_FDS; x++) {
+		if (ast_channel_fd_isset(chan, x)) {
+			void *tmp = ast_realloc(*new_pfds,
+				(*new_nfds + 1) * sizeof(struct pollfd));
+
+			if (!tmp) {
+				continue;
+			}
+			*new_pfds = tmp;
+			(*new_pfds)[*new_nfds].fd = ast_channel_fd(chan, x);
+			(*new_pfds)[*new_nfds].events = POLLIN | POLLERR | POLLPRI;
+			(*new_pfds)[*new_nfds].revents = 0;
+			(*new_nfds)++;
+		}
+	}
+	/* Keep track of our shortest wait */
+	if (tms < *ms || *ms < 0) {
+		*ms = tms;
+	}
+
+	/* Stay in the parking lot. */
+	return 0;
+}
+
+/*! \brief Run management on parkinglots, called once per parkinglot */
+static void manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
+{
+	struct parkeduser *pu;
+	struct ast_context *con;
+
+	/* Lock parkings list */
+	AST_LIST_LOCK(&curlot->parkings);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
+		if (pu->notquiteyet) { /* Pretend this one isn't here yet */
+			continue;
+		}
+		if (manage_parked_call(pu, pfds, nfds, new_pfds, new_nfds, ms)) {
+			/* Parking is complete for this call so remove it from the parking lot. */
+			ast_wrlock_contexts();
+			con = ast_context_find(pu->parkinglot->cfg.parking_con);
+			if (con) {
+				if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
+					ast_log(LOG_WARNING,
+						"Whoa, failed to remove the parking extension %s@%s!\n",
+						pu->parkingexten, pu->parkinglot->cfg.parking_con);
+				}
+			}
+			ast_unlock_contexts();
+			if (con) {
+				notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con,
+					AST_DEVICE_NOT_INUSE);
+			} else {
+				ast_log(LOG_WARNING,
+					"Whoa, parking lot '%s' context '%s' does not exist.\n",
+					pu->parkinglot->name, pu->parkinglot->cfg.parking_con);
+			}
+			AST_LIST_REMOVE_CURRENT(list);
+			parkinglot_unref(pu->parkinglot);
+			ast_free(pu);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&curlot->parkings);
+}
+
+/*!
+ * \brief Take care of parked calls and unpark them if needed
+ * \param ignore unused var.
+ *
+ * Start inf loop, lock parking lot, check if any parked channels have gone above timeout
+ * if so, remove channel from parking lot and return it to the extension that parked it.
+ * Check if parked channel decided to hangup, wait until next FD via select().
+ */
+static void *do_parking_thread(void *ignore)
+{
+	struct pollfd *pfds = NULL, *new_pfds = NULL;
+	int nfds = 0, new_nfds = 0;
+
+	for (;;) {
+		struct ao2_iterator iter;
+		struct ast_parkinglot *curlot;
+		int ms = -1;	/* poll2 timeout, uninitialized */
+
+		iter = ao2_iterator_init(parkinglots, 0);
+		while ((curlot = ao2_iterator_next(&iter))) {
+			manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
+			ao2_ref(curlot, -1);
+		}
+		ao2_iterator_destroy(&iter);
+
+		/* Recycle */
+		ast_free(pfds);
+		pfds = new_pfds;
+		nfds = new_nfds;
+		new_pfds = NULL;
+		new_nfds = 0;
+
+		/* Wait for something to happen */
+		ast_poll(pfds, nfds, ms);
+		pthread_testcancel();
+	}
+	/* If this WERE reached, we'd need to free(pfds) */
+	return NULL;	/* Never reached */
+}
+
+/*! \brief Find parkinglot by name */
+static struct ast_parkinglot *find_parkinglot(const char *name)
+{
+	struct ast_parkinglot *parkinglot;
+
+	if (ast_strlen_zero(name)) {
+		return NULL;
+	}
+
+	parkinglot = ao2_find(parkinglots, (void *) name, 0);
+	if (parkinglot) {
+		ast_debug(1, "Found Parking lot: %s\n", parkinglot->name);
+	}
+
+	return parkinglot;
+}
+
+/*! \brief Copy parkinglot and store it with new name */
+static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot)
+{
+	struct ast_parkinglot *copylot;
+
+	if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
+		ao2_ref(copylot, -1);
+		return NULL;
+	}
+
+	copylot = create_parkinglot(name);
+	if (!copylot) {
+		return NULL;
+	}
+
+	ast_debug(1, "Building parking lot %s\n", name);
+
+	/* Copy the source parking lot configuration. */
+	copylot->cfg = parkinglot->cfg;
+
+	return copylot;
+}
+
+AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
+	AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
+	AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
+	AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
+END_OPTIONS );
+
+/*! \brief Park a call */
+static int park_call_exec(struct ast_channel *chan, const char *data)
+{
+	struct ast_park_call_args args = { 0, };
+	struct ast_flags flags = { 0 };
+	char orig_exten[AST_MAX_EXTENSION];
+	int orig_priority;
+	int res;
+	const char *pl_name;
+	char *parse;
+	struct park_app_args app_args;
+
+	/*
+	 * Cache the original channel name because we are going to
+	 * masquerade the channel.  Prefer the BLINDTRANSFER channel
+	 * name over this channel name.  BLINDTRANSFER could be set if
+	 * the parking access extension did not get detected and we are
+	 * executing the Park application from the dialplan.
+	 *
+	 * The orig_chan_name is used to return the call to the
+	 * originator on parking timeout.
+	 */
+	args.orig_chan_name = ast_strdupa(S_OR(
+		pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ast_channel_name(chan)));
+
+	/* Answer if call is not up */
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		if (ast_answer(chan)) {
+			return -1;
+		}
+
+		/* Sleep to allow VoIP streams to settle down */
+		if (ast_safe_sleep(chan, 1000)) {
+			return -1;
+		}
+	}
+
+	/* Process the dialplan application options. */
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(app_args, parse);
+
+	if (!ast_strlen_zero(app_args.timeout)) {
+		if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
+			ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
+			args.timeout = 0;
+		}
+	}
+	if (!ast_strlen_zero(app_args.return_con)) {
+		args.return_con = app_args.return_con;
+	}
+	if (!ast_strlen_zero(app_args.return_ext)) {
+		args.return_ext = app_args.return_ext;
+	}
+	if (!ast_strlen_zero(app_args.return_pri)) {
+		if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
+			ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
+			args.return_pri = 0;
+		}
+	}
+
+	ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
+	args.flags = flags.flags;
+
+	/*
+	 * Setup the exten/priority to be s/1 since we don't know where
+	 * this call should return.
+	 */
+	ast_copy_string(orig_exten, ast_channel_exten(chan), sizeof(orig_exten));
+	orig_priority = ast_channel_priority(chan);
+	ast_channel_exten_set(chan, "s");
+	ast_channel_priority_set(chan, 1);
+
+	/* Park the call */
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(chan);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
+		args.parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		args.parkinglot = find_parkinglot(pl_name);
+		if (!args.parkinglot && parkeddynamic) {
+			args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
+		}
+	}
+	if (args.parkinglot) {
+		res = masq_park_call(chan, chan, &args);
+		parkinglot_unref(args.parkinglot);
+	} else {
+		/* Parking failed because the parking lot does not exist. */
+		if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
+			ast_stream_and_wait(chan, "pbx-parkingfailed", "");
+		}
+		res = -1;
+	}
+	if (res) {
+		/* Park failed, try to continue in the dialplan. */
+		ast_channel_exten_set(chan, orig_exten);
+		ast_channel_priority_set(chan, orig_priority);
+		res = 0;
+	} else {
+		/* Park succeeded. */
+		res = -1;
+	}
+
+	return res;
+}
+
+/*! \brief Pickup parked call */
+static int parked_call_exec(struct ast_channel *chan, const char *data)
+{
+	int res = 0;
+	struct ast_channel *peer = NULL;
+	struct parkeduser *pu;
+	struct ast_context *con;
+	char *parse;
+	const char *pl_name;
+	unsigned int park = 0;
+	struct ast_bridge_config config;
+	struct ast_parkinglot *parkinglot;
+	AST_DECLARE_APP_ARGS(app_args,
+		AST_APP_ARG(pl_space);	/*!< Parking lot space to retrieve if present. */
+		AST_APP_ARG(pl_name);	/*!< Parking lot name to use if present. */
+		AST_APP_ARG(dummy);		/*!< Place to put any remaining args string. */
+	);
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(app_args, parse);
+
+	if (!ast_strlen_zero(app_args.pl_space)) {
+		if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
+			ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
+				app_args.pl_space);
+			park = -1;
+		}
+	}
+
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(chan);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
+		parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		parkinglot = find_parkinglot(pl_name);
+		if (!parkinglot) {
+			/* It helps to answer the channel if not already up. :) */
+			if (ast_channel_state(chan) != AST_STATE_UP) {
+				ast_answer(chan);
+			}
+			if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
+				ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
+					"pbx-invalidpark", ast_channel_name(chan));
+			}
+			ast_log(LOG_WARNING,
+				"Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
+				ast_channel_name(chan), pl_name);
+			return -1;
+		}
+	}
+
+	AST_LIST_LOCK(&parkinglot->parkings);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
+		if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
+			&& !pu->notquiteyet && !ast_channel_pbx(pu->chan)) {
+			/* The parking space has a call and can be picked up now. */
+			AST_LIST_REMOVE_CURRENT(list);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	if (pu) {
+		struct ast_callid *callid = ast_read_threadstorage_callid();
+
+		/* Found a parked call to pickup. */
+		peer = pu->chan;
+
+		/* We need to map the call id we have from this thread to the channel we found. */
+		if (callid) {
+			ast_channel_callid_set(peer, callid);
+			callid = ast_callid_unref(callid);
+		}
+
+		ast_wrlock_contexts();
+		con = ast_context_find(parkinglot->cfg.parking_con);
+		if (con) {
+			res = ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 1);
+		}
+		ast_unlock_contexts();
+
+		if (con) {
+			if (res) {
+				ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+			} else {
+				notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
+			}
+		} else {
+			ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+		}
+
+		ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a call has been unparked.</synopsis>
+				<syntax>
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Exten'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
+					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='From'])" />
+				</syntax>
+				<see-also>
+					<ref type="application">ParkedCall</ref>
+					<ref type="managerEvent">ParkedCall</ref>
+				</see-also>
+			</managerEventInstance>
+		***/
+		ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
+			"Exten: %s\r\n"
+			"Channel: %s\r\n"
+			"Parkinglot: %s\r\n"
+			"From: %s\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n"
+			"Uniqueid: %s\r\n",
+			pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name,
+			ast_channel_name(chan),
+			S_COR(ast_channel_caller(pu->chan)->id.number.valid, ast_channel_caller(pu->chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_caller(pu->chan)->id.name.valid, ast_channel_caller(pu->chan)->id.name.str, "<unknown>"),
+			S_COR(ast_channel_connected(pu->chan)->id.number.valid, ast_channel_connected(pu->chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_connected(pu->chan)->id.name.valid, ast_channel_connected(pu->chan)->id.name.str, "<unknown>"),
+			ast_channel_uniqueid(pu->chan)
+			);
+
+		/* Stop entertaining the caller. */
+		switch (pu->hold_method) {
+		case AST_CONTROL_HOLD:
+			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
+			break;
+		case AST_CONTROL_RINGING:
+			ast_indicate(pu->chan, -1);
+			break;
+		default:
+			break;
+		}
+		pu->hold_method = 0;
+
+		parkinglot_unref(pu->parkinglot);
+		ast_free(pu);
+	}
+	AST_LIST_UNLOCK(&parkinglot->parkings);
+
+	if (peer) {
+		/* Update connected line between retrieving call and parked call. */
+		struct ast_party_connected_line connected;
+
+		ast_party_connected_line_init(&connected);
+
+		/* Send our caller-id to peer. */
+		ast_channel_lock(chan);
+		ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
+		ast_channel_unlock(chan);
+		connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+		if (ast_channel_connected_line_sub(chan, peer, &connected, 0) &&
+			ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
+			ast_channel_update_connected_line(peer, &connected, NULL);
+		}
+
+		/*
+		 * Get caller-id from peer.
+		 *
+		 * Update the retrieving call before it is answered if possible
+		 * for best results.  Some phones do not support updating the
+		 * connected line information after connection.
+		 */
+		ast_channel_lock(peer);
+		ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer));
+		ast_channel_unlock(peer);
+		connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+		if (ast_channel_connected_line_sub(peer, chan, &connected, 0) &&
+			ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
+			ast_channel_update_connected_line(chan, &connected, NULL);
+		}
+
+		ast_party_connected_line_free(&connected);
+	}
+
+	/* JK02: it helps to answer the channel if not already up */
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		ast_answer(chan);
+	}
+
+	if (peer) {
+		struct ast_datastore *features_datastore;
+		struct ast_dial_features *dialfeatures;
+
+		/* Play a courtesy to the source(s) configured to prefix the bridge connecting */
+		if (!ast_strlen_zero(courtesytone)) {
+			static const char msg[] = "courtesy tone";
+
+			switch (parkedplay) {
+			case 0:/* Courtesy tone to pickup chan */
+				res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
+				break;
+			case 1:/* Courtesy tone to parked chan */
+				res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
+				break;
+			case 2:/* Courtesy tone to both chans */
+				res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
+				break;
+			default:
+				res = 0;
+				break;
+			}
+			if (res) {
+				ast_autoservice_chan_hangup_peer(chan, peer);
+				parkinglot_unref(parkinglot);
+				return -1;
+			}
+		}
+
+		res = ast_channel_make_compatible(chan, peer);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer));
+			ast_autoservice_chan_hangup_peer(chan, peer);
+			parkinglot_unref(parkinglot);
+			return -1;
+		}
+		/* This runs sorta backwards, since we give the incoming channel control, as if it
+		   were the person called. */
+		ast_verb(3, "Channel %s connected to parked call %u\n", ast_channel_name(chan), park);
+
+		pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer));
+		ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
+		memset(&config, 0, sizeof(struct ast_bridge_config));
+
+		/* Get datastore for peer and apply it's features to the callee side of the bridge config */
+		ast_channel_lock(peer);
+		features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
+		if (features_datastore && (dialfeatures = features_datastore->data)) {
+			ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
+				AST_FLAGS_ALL);
+		}
+		ast_channel_unlock(peer);
+
+		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
+		}
+		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
+		}
+		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
+		}
+		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
+		}
+		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
+		}
+		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
+		}
+		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
+		}
+		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+			ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+		}
+
+		res = ast_bridge_call(chan, peer, &config);
+
+		pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer));
+		ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
+
+		/* Simulate the PBX hanging up */
+		ast_autoservice_chan_hangup_peer(chan, peer);
+	} else {
+		if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
+			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
+				ast_channel_name(chan));
+		}
+		ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %u\n",
+			ast_channel_name(chan), park);
+		res = -1;
+	}
+
+	parkinglot_unref(parkinglot);
+	return res;
+}
+
+/*!
+ * \brief Unreference parkinglot object.
+ */
+static void parkinglot_unref(struct ast_parkinglot *parkinglot)
+{
+	ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name,
+		ao2_ref(parkinglot, 0) - 1);
+	ao2_ref(parkinglot, -1);
+}
+
+static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
+{
+	int refcount;
+
+	refcount = ao2_ref(parkinglot, +1);
+	ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
+	return parkinglot;
+}
+
+/*! \brief Destroy a parking lot */
+static void parkinglot_destroy(void *obj)
+{
+	struct ast_parkinglot *doomed = obj;
+
+	/*
+	 * No need to destroy parked calls here because any parked call
+	 * holds a parking lot reference.  Therefore the parkings list
+	 * must be empty.
+	 */
+	ast_assert(AST_LIST_EMPTY(&doomed->parkings));
+	AST_LIST_HEAD_DESTROY(&doomed->parkings);
+}
+
+/*! \brief Allocate parking lot structure */
+static struct ast_parkinglot *create_parkinglot(const char *name)
+{
+	struct ast_parkinglot *newlot;
+
+	if (ast_strlen_zero(name)) { /* No name specified */
+		return NULL;
+	}
+
+	newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
+	if (!newlot)
+		return NULL;
+
+	ast_copy_string(newlot->name, name, sizeof(newlot->name));
+	newlot->cfg.is_invalid = 1;/* No config is set yet. */
+	AST_LIST_HEAD_INIT(&newlot->parkings);
+
+	return newlot;
+}
+
+/*!
+ * \brief Add parking hints for all defined parking spaces.
+ * \param context Dialplan context to add the hints.
+ * \param start Starting space in parkinglot.
+ * \param stop Ending space in parkinglot.
+ */
+static void park_add_hints(const char *context, int start, int stop)
+{
+	int numext;
+	char device[AST_MAX_EXTENSION];
+	char exten[10];
+
+	for (numext = start; numext <= stop; numext++) {
+		snprintf(exten, sizeof(exten), "%d", numext);
+		snprintf(device, sizeof(device), "park:%s@%s", exten, context);
+		ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
+	}
+}
+
+/*! Default configuration for default parking lot. */
+static const struct parkinglot_cfg parkinglot_cfg_default_default = {
+	.mohclass = "default",
+	.parkext = DEFAULT_PARK_EXTENSION,
+	.parking_con = "parkedcalls",
+	.parking_start = 701,
+	.parking_stop = 750,
+	.parkingtime = DEFAULT_PARK_TIME,
+	.comebackdialtime = DEFAULT_COMEBACK_DIAL_TIME,
+	.comebackcontext = DEFAULT_COMEBACK_CONTEXT,
+	.comebacktoorigin = DEFAULT_COMEBACK_TO_ORIGIN,
+};
+
+/*! Default configuration for normal parking lots. */
+static const struct parkinglot_cfg parkinglot_cfg_default = {
+	.parkext = DEFAULT_PARK_EXTENSION,
+	.parkingtime = DEFAULT_PARK_TIME,
+	.comebackdialtime = DEFAULT_COMEBACK_DIAL_TIME,
+	.comebackcontext = DEFAULT_COMEBACK_CONTEXT,
+	.comebacktoorigin = DEFAULT_COMEBACK_TO_ORIGIN,
+};
+
+/*!
+ * \internal
+ * \brief Set parking lot feature flag configuration value.
+ *
+ * \param pl_name Parking lot name for diagnostic messages.
+ * \param param Parameter value to set.
+ * \param var Current configuration variable item.
+ *
+ * \return Nothing
+ */
+static void parkinglot_feature_flag_cfg(const char *pl_name, int *param, struct ast_variable *var)
+{
+	ast_debug(1, "Setting parking lot %s %s to %s\n", pl_name, var->name, var->value);
+	if (!strcasecmp(var->value, "both")) {
+		*param = AST_FEATURE_FLAG_BYBOTH;
+	} else if (!strcasecmp(var->value, "caller")) {
+		*param = AST_FEATURE_FLAG_BYCALLER;
+	} else if (!strcasecmp(var->value, "callee")) {
+		*param = AST_FEATURE_FLAG_BYCALLEE;
+	}
+}
+
+/*!
+ * \internal
+ * \brief Read parking lot configuration.
+ *
+ * \param pl_name Parking lot name for diagnostic messages.
+ * \param cfg Parking lot config to update that is already initialized with defaults.
+ * \param var Config variable list.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int parkinglot_config_read(const char *pl_name, struct parkinglot_cfg *cfg, struct ast_variable *var)
+{
+	int error = 0;
+
+	while (var) {
+		if (!strcasecmp(var->name, "context")) {
+			ast_copy_string(cfg->parking_con, var->value, sizeof(cfg->parking_con));
+		} else if (!strcasecmp(var->name, "parkext")) {
+			ast_copy_string(cfg->parkext, var->value, sizeof(cfg->parkext));
+		} else if (!strcasecmp(var->name, "parkext_exclusive")) {
+			cfg->parkext_exclusive = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "parkinghints")) {
+			cfg->parkaddhints = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "parkedmusicclass")) {
+			ast_copy_string(cfg->mohclass, var->value, sizeof(cfg->mohclass));
+		} else if (!strcasecmp(var->name, "parkingtime")) {
+			unsigned int parkingtime = 0;
+
+			if ((sscanf(var->value, "%30u", &parkingtime) != 1) || parkingtime < 1) {
+				ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
+				error = -1;
+			} else {
+				cfg->parkingtime = parkingtime * 1000;
+			}
+		} else if (!strcasecmp(var->name, "parkpos")) {
+			int start = 0;
+			int end = 0;
+
+			if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
+				ast_log(LOG_WARNING,
+					"Format for parking positions is a-b, where a and b are numbers at line %d of %s\n",
+					var->lineno, var->file);
+				error = -1;
+			} else if (end < start || start <= 0 || end <= 0) {
+				ast_log(LOG_WARNING, "Parking range is invalid. Must be a <= b, at line %d of %s\n",
+					var->lineno, var->file);
+				error = -1;
+			} else {
+				cfg->parking_start = start;
+				cfg->parking_stop = end;
+			}
+		} else if (!strcasecmp(var->name, "findslot")) {
+			cfg->parkfindnext = (!strcasecmp(var->value, "next"));
+		} else if (!strcasecmp(var->name, "parkedcalltransfers")) {
+			parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcalltransfers, var);
+		} else if (!strcasecmp(var->name, "parkedcallreparking")) {
+			parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallreparking, var);
+		} else if (!strcasecmp(var->name, "parkedcallhangup")) {
+			parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallhangup, var);
+		} else if (!strcasecmp(var->name, "parkedcallrecording")) {
+			parkinglot_feature_flag_cfg(pl_name, &cfg->parkedcallrecording, var);
+		} else if (!strcasecmp(var->name, "comebackcontext")) {
+			ast_copy_string(cfg->comebackcontext, var->value, sizeof(cfg->comebackcontext));
+		} else if (!strcasecmp(var->name, "comebacktoorigin")) {
+			cfg->comebacktoorigin = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "comebackdialtime")) {
+			if ((sscanf(var->value, "%30u", &cfg->comebackdialtime) != 1)
+					|| (cfg->comebackdialtime < 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid comebackdialtime\n", var->value);
+				cfg->parkingtime = DEFAULT_COMEBACK_DIAL_TIME;
+			}
+		}
+		var = var->next;
+	}
+
+	/* Check for configuration errors */
+	if (ast_strlen_zero(cfg->parking_con)) {
+		ast_log(LOG_WARNING, "Parking lot %s needs context\n", pl_name);
+		error = -1;
+	}
+	if (ast_strlen_zero(cfg->parkext)) {
+		ast_log(LOG_WARNING, "Parking lot %s needs parkext\n", pl_name);
+		error = -1;
+	}
+	if (!cfg->parking_start) {
+		ast_log(LOG_WARNING, "Parking lot %s needs parkpos\n", pl_name);
+		error = -1;
+	}
+	if (!cfg->comebacktoorigin && ast_strlen_zero(cfg->comebackcontext)) {
+		ast_log(LOG_WARNING, "Parking lot %s has comebacktoorigin set false"
+				"but has no comebackcontext.\n",
+				pl_name);
+		error = -1;
+	}
+	if (error) {
+		cfg->is_invalid = 1;
+	}
+
+	return error;
+}
+
+/*!
+ * \internal
+ * \brief Activate the given parkinglot.
+ *
+ * \param parkinglot Parking lot to activate.
+ *
+ * \details
+ * Insert into the dialplan the context, parking lot access
+ * extension, and optional dialplan hints.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int parkinglot_activate(struct ast_parkinglot *parkinglot)
+{
+	int disabled = 0;
+	char app_data[5 + AST_MAX_CONTEXT];
+
+	/* Create Park option list.  Must match with struct park_app_args options. */
+	if (parkinglot->cfg.parkext_exclusive) {
+		/* Specify the parking lot this parking extension parks calls. */
+		snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
+	} else {
+		/* The dialplan must specify which parking lot to use. */
+		app_data[0] = '\0';
+	}
+
+	/* Create context */
+	if (!ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar)) {
+		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n",
+			parkinglot->cfg.parking_con);
+		disabled = 1;
+
+	/* Add a parking extension into the context */
+	} else if (ast_add_extension(parkinglot->cfg.parking_con, 1, parkinglot->cfg.parkext,
+		1, NULL, NULL, parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
+		ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
+			parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
+		disabled = 1;
+	} else {
+		/* Add parking hints */
+		if (parkinglot->cfg.parkaddhints) {
+			park_add_hints(parkinglot->cfg.parking_con, parkinglot->cfg.parking_start,
+				parkinglot->cfg.parking_stop);
+		}
+
+		/*
+		 * XXX Not sure why we should need to notify the metermaids for
+		 * this exten.  It was originally done for the default parking
+		 * lot entry exten only but should be done for all entry extens
+		 * if we do it for one.
+		 */
+		/* Notify metermaids about parking lot entry exten state. */
+		notify_metermaids(parkinglot->cfg.parkext, parkinglot->cfg.parking_con,
+			AST_DEVICE_INUSE);
+	}
+
+	parkinglot->disabled = disabled;
+	return disabled ? -1 : 0;
+}
+
+/*! \brief Build parkinglot from configuration and chain it in if it doesn't already exist */
+static struct ast_parkinglot *build_parkinglot(const char *pl_name, struct ast_variable *var)
+{
+	struct ast_parkinglot *parkinglot;
+	const struct parkinglot_cfg *cfg_defaults;
+	struct parkinglot_cfg new_cfg;
+	int cfg_error;
+	int oldparkinglot = 0;
+
+	parkinglot = find_parkinglot(pl_name);
+	if (parkinglot) {
+		oldparkinglot = 1;
+	} else {
+		parkinglot = create_parkinglot(pl_name);
+		if (!parkinglot) {
+			return NULL;
+		}
+	}
+	if (!strcmp(parkinglot->name, DEFAULT_PARKINGLOT)) {
+		cfg_defaults = &parkinglot_cfg_default_default;
+	} else {
+		cfg_defaults = &parkinglot_cfg_default;
+	}
+	new_cfg = *cfg_defaults;
+
+	ast_debug(1, "Building parking lot %s\n", parkinglot->name);
+
+	ao2_lock(parkinglot);
+
+	/* Do some config stuff */
+	cfg_error = parkinglot_config_read(parkinglot->name, &new_cfg, var);
+	if (oldparkinglot) {
+		if (cfg_error) {
+			/* Bad configuration read.  Keep using the original config. */
+			ast_log(LOG_WARNING, "Changes to parking lot %s are discarded.\n",
+				parkinglot->name);
+			cfg_error = 0;
+		} else if (!AST_LIST_EMPTY(&parkinglot->parkings)
+			&& memcmp(&new_cfg, &parkinglot->cfg, sizeof(parkinglot->cfg))) {
+			/* Try reloading later when parking lot is empty. */
+			ast_log(LOG_WARNING,
+				"Parking lot %s has parked calls.  Parking lot changes discarded.\n",
+				parkinglot->name);
+			force_reload_load = 1;
+		} else {
+			/* Accept the new config */
+			parkinglot->cfg = new_cfg;
+		}
+	} else {
+		/* Load the initial parking lot config. */
+		parkinglot->cfg = new_cfg;
+	}
+	parkinglot->the_mark = 0;
+
+	ao2_unlock(parkinglot);
+
+	if (cfg_error) {
+		/* Only new parking lots could have config errors here. */
+		ast_log(LOG_WARNING, "New parking lot %s is discarded.\n", parkinglot->name);
+		parkinglot_unref(parkinglot);
+		return NULL;
+	}
+
+	/* Move it into the list, if it wasn't already there */
+	if (!oldparkinglot) {
+		ao2_link(parkinglots, parkinglot);
+	}
+	parkinglot_unref(parkinglot);
+
+	return parkinglot;
+}
+
+/*!
+ * \internal
+ * \brief Process an applicationmap section config line.
+ *
+ * \param var Config variable line.
+ *
+ * \return Nothing
+ */
+static void process_applicationmap_line(struct ast_variable *var)
+{
+	char *tmp_val = ast_strdupa(var->value);
+	char *activateon, *new_syn;
+	struct ast_call_feature *feature;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(exten);
+		AST_APP_ARG(activatedby);
+		AST_APP_ARG(app);
+		AST_APP_ARG(app_args);
+		AST_APP_ARG(moh_class);
+	);
+
+	AST_STANDARD_APP_ARGS(args, tmp_val);
+
+	activateon = strsep(&args.activatedby, "/");
+
+	if (ast_strlen_zero(args.app)
+		|| ast_strlen_zero(args.exten)
+		|| ast_strlen_zero(activateon)
+		|| ast_strlen_zero(var->name)) {
+		ast_log(LOG_NOTICE,
+			"Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
+			args.app, args.exten, activateon, var->name);
+		return;
+	}
+
+	if ((new_syn = strchr(args.app, '('))) {
+		/* New syntax */
+		args.moh_class = args.app_args;
+		args.app_args = new_syn;
+		*args.app_args++ = '\0';
+		if (args.app_args[strlen(args.app_args) - 1] == ')') {
+			args.app_args[strlen(args.app_args) - 1] = '\0';
+		}
+	}
+	
+	AST_RWLIST_RDLOCK(&feature_list);
+	if (find_dynamic_feature(var->name)) {
+		AST_RWLIST_UNLOCK(&feature_list);
+		ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n",
+			var->name);
+		return;
+	}
+	AST_RWLIST_UNLOCK(&feature_list);
+
+	if (!(feature = ast_calloc(1, sizeof(*feature)))) {
+		return;
+	}
+
+	ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
+	ast_copy_string(feature->app, args.app, FEATURE_APP_LEN);
+	ast_copy_string(feature->exten, args.exten, FEATURE_EXTEN_LEN);
+
+	if (args.app_args) {
+		ast_copy_string(feature->app_args, args.app_args, FEATURE_APP_ARGS_LEN);
+	}
+
+	if (args.moh_class) {
+		ast_copy_string(feature->moh_class, args.moh_class, FEATURE_MOH_LEN);
+	}
+
+	ast_copy_string(feature->exten, args.exten, sizeof(feature->exten));
+	feature->operation = feature_exec_app;
+	ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
+
+	/* Allow caller and callee to be specified for backwards compatability */
+	if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
+	} else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
+	} else {
+		ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
+			" must be 'self', or 'peer'\n", var->name);
+		ast_free(feature);
+		return;
+	}
+
+	if (ast_strlen_zero(args.activatedby)) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
+	} else if (!strcasecmp(args.activatedby, "caller")) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
+	} else if (!strcasecmp(args.activatedby, "callee")) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
+	} else if (!strcasecmp(args.activatedby, "both")) {
+		ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
+	} else {
+		ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
+			" must be 'caller', or 'callee', or 'both'\n", var->name);
+		ast_free(feature);
+		return;
+	}
+
+	ast_register_feature(feature);
+
+	ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n",
+		var->name, args.app, args.app_args, args.exten);
+}
+
+static int process_config(struct ast_config *cfg)
+{
+	int i;
+	struct ast_variable *var = NULL;
+	struct feature_group *fg = NULL;
+	char *ctg;
+	static const char * const categories[] = {
+		/* Categories in features.conf that are not
+		 * to be parsed as group categories
+		 */
+		"general",
+		"featuremap",
+		"applicationmap"
+	};
+
+	/* Set general features global defaults. */
+	featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
+
+	/* Set global call pickup defaults. */
+	strcpy(pickup_ext, "*8");
+	pickupsound[0] = '\0';
+	pickupfailsound[0] = '\0';
+
+	/* Set global call transfer defaults. */
+	strcpy(xfersound, "beep");
+	strcpy(xferfailsound, "beeperr");
+	transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
+	atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
+	atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
+	atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
+	atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
+
+	/* Set global call parking defaults. */
+	courtesytone[0] = '\0';
+	parkedplay = 0;
+	adsipark = 0;
+	parkeddynamic = 0;
+
+	var = ast_variable_browse(cfg, "general");
+	build_parkinglot(DEFAULT_PARKINGLOT, var);
+	for (; var; var = var->next) {
+		if (!strcasecmp(var->name, "parkeddynamic")) {
+			parkeddynamic = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "adsipark")) {
+			adsipark = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "transferdigittimeout")) {
+			if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
+				transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
+			} else {
+				transferdigittimeout = transferdigittimeout * 1000;
+			}
+		} else if (!strcasecmp(var->name, "featuredigittimeout")) {
+			if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
+				featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
+			}
+		} else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
+			if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
+				atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
+			} else {
+				atxfernoanswertimeout = atxfernoanswertimeout * 1000;
+			}
+		} else if (!strcasecmp(var->name, "atxferloopdelay")) {
+			if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
+				atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
+			} else {
+				atxferloopdelay *= 1000;
+			}
+		} else if (!strcasecmp(var->name, "atxferdropcall")) {
+			atxferdropcall = ast_true(var->value);
+		} else if (!strcasecmp(var->name, "atxfercallbackretries")) {
+			if ((sscanf(var->value, "%30u", &atxfercallbackretries) != 1)) {
+				ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
+				atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
+			}
+		} else if (!strcasecmp(var->name, "courtesytone")) {
+			ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
+		}  else if (!strcasecmp(var->name, "parkedplay")) {
+			if (!strcasecmp(var->value, "both")) {
+				parkedplay = 2;
+			} else if (!strcasecmp(var->value, "parked")) {
+				parkedplay = 1;
+			} else {
+				parkedplay = 0;
+			}
+		} else if (!strcasecmp(var->name, "xfersound")) {
+			ast_copy_string(xfersound, var->value, sizeof(xfersound));
+		} else if (!strcasecmp(var->name, "xferfailsound")) {
+			ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
+		} else if (!strcasecmp(var->name, "pickupexten")) {
+			ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
+		} else if (!strcasecmp(var->name, "pickupsound")) {
+			ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
+		} else if (!strcasecmp(var->name, "pickupfailsound")) {
+			ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
+		}
+	}
+
+	unmap_features();
+	for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
+		if (remap_feature(var->name, var->value)) {
+			ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
+		}
+	}
+
+	/* Map a key combination to an application */
+	ast_unregister_features();
+	for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
+		process_applicationmap_line(var);
+	}
+
+	ast_unregister_groups();
+	AST_RWLIST_WRLOCK(&feature_groups);
+
+	ctg = NULL;
+	while ((ctg = ast_category_browse(cfg, ctg))) {
+		/* Is this a parkinglot definition ? */
+		if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
+			ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
+			if (!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) {
+				ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
+			} else {
+				ast_debug(1, "Configured parking context %s\n", ctg);
+			}
+			continue;
+		}
+
+		/* No, check if it's a group */
+		for (i = 0; i < ARRAY_LEN(categories); i++) {
+			if (!strcasecmp(categories[i], ctg)) {
+				break;
+			}
+		}
+		if (i < ARRAY_LEN(categories)) {
+			continue;
+		}
+
+		if (!(fg = register_group(ctg))) {
+			continue;
+		}
+
+		for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
+			struct ast_call_feature *feature;
+
+			AST_RWLIST_RDLOCK(&feature_list);
+			if (!(feature = find_dynamic_feature(var->name)) &&
+			    !(feature = ast_find_call_feature(var->name))) {
+				AST_RWLIST_UNLOCK(&feature_list);
+				ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
+				continue;
+			}
+			AST_RWLIST_UNLOCK(&feature_list);
+
+			register_group_feature(fg, var->value, feature);
+		}
+	}
+
+	AST_RWLIST_UNLOCK(&feature_groups);
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Destroy the given dialplan usage context.
+ *
+ * \param doomed Parking lot usage context to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_dialplan_usage_context(struct parking_dp_context *doomed)
+{
+	struct parking_dp_ramp *ramp;
+	struct parking_dp_spaces *spaces;
+
+	while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
+		ast_free(ramp);
+	}
+	while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
+		ast_free(spaces);
+	}
+	while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
+		ast_free(spaces);
+	}
+	ast_free(doomed);
+}
+
+/*!
+ * \internal
+ * \brief Destroy the given dialplan usage map.
+ *
+ * \param doomed Parking lot usage map to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_dialplan_usage_map(struct parking_dp_map *doomed)
+{
+	struct parking_dp_context *item;
+
+	while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
+		destroy_dialplan_usage_context(item);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot ramp dialplan usage node.
+ *
+ * \param exten Parking lot access ramp extension.
+ * \param exclusive TRUE if the parking lot access ramp extension is exclusive.
+ *
+ * \retval New usage ramp node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_ramp *build_dialplan_useage_ramp(const char *exten, int exclusive)
+{
+	struct parking_dp_ramp *ramp_node;
+
+	ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
+	if (!ramp_node) {
+		return NULL;
+	}
+	ramp_node->exclusive = exclusive;
+	strcpy(ramp_node->exten, exten);
+	return ramp_node;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot access ramp to the context ramp usage map.
+ *
+ * \param ramp_map Current parking lot context ramp usage map.
+ * \param exten Parking lot access ramp extension to add.
+ * \param exclusive TRUE if the parking lot access ramp extension is exclusive.
+ * \param lot Parking lot supplying reference data.
+ * \param complain TRUE if to complain of parking lot ramp conflicts.
+ *
+ * \retval 0 on success.  The ramp_map is updated.
+ * \retval -1 on failure.
+ */
+static int usage_context_add_ramp(struct parking_dp_ramp_map *ramp_map, const char *exten, int exclusive, struct ast_parkinglot *lot, int complain)
+{
+	struct parking_dp_ramp *cur_ramp;
+	struct parking_dp_ramp *new_ramp;
+	int cmp;
+
+	/* Make sure that exclusive is only 0 or 1 */
+	if (exclusive) {
+		exclusive = 1;
+	}
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
+		cmp = strcmp(exten, cur_ramp->exten);
+		if (cmp > 0) {
+			/* The parking lot ramp goes after this node. */
+			continue;
+		}
+		if (cmp == 0) {
+			/* The ramp is already in the map. */
+			if (complain && (cur_ramp->exclusive || exclusive)) {
+				ast_log(LOG_WARNING,
+					"Parking lot '%s' parkext %s@%s used by another parking lot.\n",
+					lot->name, exten, lot->cfg.parking_con);
+			}
+			return 0;
+		}
+		/* The new parking lot ramp goes before this node. */
+		new_ramp = build_dialplan_useage_ramp(exten, exclusive);
+		if (!new_ramp) {
+			return -1;
+		}
+		AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
+		return 0;
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	/* New parking lot access ramp goes on the end. */
+	new_ramp = build_dialplan_useage_ramp(exten, exclusive);
+	if (!new_ramp) {
+		return -1;
+	}
+	AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot spaces dialplan usage node.
+ *
+ * \param start First parking lot space to add.
+ * \param stop Last parking lot space to add.
+ *
+ * \retval New usage ramp node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_spaces *build_dialplan_useage_spaces(int start, int stop)
+{
+	struct parking_dp_spaces *spaces_node;
+
+	spaces_node = ast_calloc(1, sizeof(*spaces_node));
+	if (!spaces_node) {
+		return NULL;
+	}
+	spaces_node->start = start;
+	spaces_node->stop = stop;
+	return spaces_node;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot spaces to the context space usage map.
+ *
+ * \param space_map Current parking lot context space usage map.
+ * \param start First parking lot space to add.
+ * \param stop Last parking lot space to add.
+ * \param lot Parking lot supplying reference data.
+ * \param complain TRUE if to complain of parking lot spaces conflicts.
+ *
+ * \retval 0 on success.  The space_map is updated.
+ * \retval -1 on failure.
+ */
+static int usage_context_add_spaces(struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot, int complain)
+{
+	struct parking_dp_spaces *cur_node;
+	struct parking_dp_spaces *expand_node;
+	struct parking_dp_spaces *new_node;
+
+	expand_node = NULL;
+	AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
+		/* NOTE: stop + 1 to combine immediately adjacent nodes into one. */
+		if (expand_node) {
+			/* The previous node is expanding to possibly eat following nodes. */
+			if (expand_node->stop + 1 < cur_node->start) {
+				/* Current node is completely after expanding node. */
+				return 0;
+			}
+
+			if (complain
+				&& ((cur_node->start <= start && start <= cur_node->stop)
+					|| (cur_node->start <= stop && stop <= cur_node->stop)
+					|| (start < cur_node->start && cur_node->stop < stop))) {
+				/* Only complain once per range add. */
+				complain = 0;
+				ast_log(LOG_WARNING,
+					"Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
+					lot->name, start, stop, lot->cfg.parking_con);
+			}
+
+			/* Current node is eaten by the expanding node. */
+			if (expand_node->stop < cur_node->stop) {
+				expand_node->stop = cur_node->stop;
+			}
+			AST_LIST_REMOVE_CURRENT(node);
+			ast_free(cur_node);
+			continue;
+		}
+
+		if (cur_node->stop + 1 < start) {
+			/* New range is completely after current node. */
+			continue;
+		}
+		if (stop + 1 < cur_node->start) {
+			/* New range is completely before current node. */
+			new_node = build_dialplan_useage_spaces(start, stop);
+			if (!new_node) {
+				return -1;
+			}
+			AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
+			return 0;
+		}
+
+		if (complain
+			&& ((cur_node->start <= start && start <= cur_node->stop)
+				|| (cur_node->start <= stop && stop <= cur_node->stop)
+				|| (start < cur_node->start && cur_node->stop < stop))) {
+			/* Only complain once per range add. */
+			complain = 0;
+			ast_log(LOG_WARNING,
+				"Parking lot '%s' parkpos %d-%d@%s overlaps another parking lot.\n",
+				lot->name, start, stop, lot->cfg.parking_con);
+		}
+
+		/* Current node range overlaps or is immediately adjacent to new range. */
+		if (start < cur_node->start) {
+			/* Expand the current node in the front. */
+			cur_node->start = start;
+		}
+		if (stop <= cur_node->stop) {
+			/* Current node is not expanding in the rear. */
+			return 0;
+		}
+		cur_node->stop = stop;
+		expand_node = cur_node;
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	if (expand_node) {
+		/*
+		 * The previous node expanded and either ate all following nodes
+		 * or it was the last node.
+		 */
+		return 0;
+	}
+
+	/* New range goes on the end. */
+	new_node = build_dialplan_useage_spaces(start, stop);
+	if (!new_node) {
+		return -1;
+	}
+	AST_LIST_INSERT_TAIL(space_map, new_node, node);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot spaces to the context dialplan usage node.
+ *
+ * \param ctx_node Usage node to add parking lot spaces.
+ * \param lot Parking lot to add data to ctx_node.
+ * \param complain TRUE if to complain of parking lot ramp and spaces conflicts.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int dialplan_usage_add_parkinglot_data(struct parking_dp_context *ctx_node, struct ast_parkinglot *lot, int complain)
+{
+	if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext,
+		lot->cfg.parkext_exclusive, lot, complain)) {
+		return -1;
+	}
+	if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
+		lot->cfg.parking_stop, lot, complain)) {
+		return -1;
+	}
+	if (lot->cfg.parkaddhints
+		&& usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
+			lot->cfg.parking_stop, lot, 0)) {
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot context dialplan usage node.
+ *
+ * \param lot Parking lot to create a new dialplan usage from.
+ *
+ * \retval New usage context node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_context *build_dialplan_useage_context(struct ast_parkinglot *lot)
+{
+	struct parking_dp_context *ctx_node;
+
+	ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
+	if (!ctx_node) {
+		return NULL;
+	}
+	if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 0)) {
+		destroy_dialplan_usage_context(ctx_node);
+		return NULL;
+	}
+	strcpy(ctx_node->context, lot->cfg.parking_con);
+	return ctx_node;
+}
+
+/*!
+ * \internal
+ * \brief Add the given parking lot dialplan usage to the dialplan usage map.
+ *
+ * \param usage_map Parking lot usage map to add the given parking lot.
+ * \param lot Parking lot to add dialplan usage.
+ * \param complain TRUE if to complain of parking lot ramp and spaces conflicts.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int dialplan_usage_add_parkinglot(struct parking_dp_map *usage_map, struct ast_parkinglot *lot, int complain)
+{
+	struct parking_dp_context *cur_ctx;
+	struct parking_dp_context *new_ctx;
+	int cmp;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
+		cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
+		if (cmp > 0) {
+			/* The parking lot context goes after this node. */
+			continue;
+		}
+		if (cmp == 0) {
+			/* This is the node we will add parking lot spaces to the map. */
+			return dialplan_usage_add_parkinglot_data(cur_ctx, lot, complain);
+		}
+		/* The new parking lot context goes before this node. */
+		new_ctx = build_dialplan_useage_context(lot);
+		if (!new_ctx) {
+			return -1;
+		}
+		AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
+		return 0;
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	/* New parking lot context goes on the end. */
+	new_ctx = build_dialplan_useage_context(lot);
+	if (!new_ctx) {
+		return -1;
+	}
+	AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Build the dialplan usage map of the current parking lot container.
+ *
+ * \param usage_map Parking lot usage map.  Must already be initialized.
+ * \param complain TRUE if to complain of parking lot ramp and spaces conflicts.
+ *
+ * \retval 0 on success.  The usage_map is filled in.
+ * \retval -1 on failure.  Built usage_map is incomplete.
+ */
+static int build_dialplan_useage_map(struct parking_dp_map *usage_map, int complain)
+{
+	int status = 0;
+	struct ao2_iterator iter;
+	struct ast_parkinglot *curlot;
+
+	/* For all parking lots */
+	iter = ao2_iterator_init(parkinglots, 0);
+	for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
+		/* Add the parking lot to the map. */
+		if (dialplan_usage_add_parkinglot(usage_map, curlot, complain)) {
+			ao2_ref(curlot, -1);
+			status = -1;
+			break;
+		}
+	}
+	ao2_iterator_destroy(&iter);
+
+	return status;
+}
+
+/*!
+ * \internal
+ * \brief Remove the given extension if it exists.
+ *
+ * \param context Dialplan database context name.
+ * \param exten Extension to remove.
+ * \param priority Extension priority to remove.
+ *
+ * \return Nothing
+ */
+static void remove_exten_if_exist(const char *context, const char *exten, int priority)
+{
+	struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+
+	if (pbx_find_extension(NULL, NULL, &q, context, exten, priority, NULL, NULL,
+		E_MATCH)) {
+		ast_debug(1, "Removing unneeded parking lot exten: %s@%s priority:%d\n",
+			context, exten, priority);
+		ast_context_remove_extension(context, exten, priority, registrar);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot access ramp items.
+ *
+ * \param context Dialplan database context name.
+ * \param old_ramps Before configuration reload access ramp usage map.
+ * \param new_ramps After configuration reload access ramp usage map.
+ *
+ * \details
+ * Remove access ramp items that were in the old context but not in the
+ * new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_ramp_usage(const char *context, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps)
+{
+	struct parking_dp_ramp *old_ramp;
+	struct parking_dp_ramp *new_ramp;
+	int cmp;
+
+	old_ramp = AST_LIST_FIRST(old_ramps);
+	new_ramp = AST_LIST_FIRST(new_ramps);
+
+	while (new_ramp) {
+		if (!old_ramp) {
+			/* No old ramps left, so no dead ramps can remain. */
+			return;
+		}
+		cmp = strcmp(old_ramp->exten, new_ramp->exten);
+		if (cmp < 0) {
+			/* New map does not have old ramp. */
+			remove_exten_if_exist(context, old_ramp->exten, 1);
+			old_ramp = AST_LIST_NEXT(old_ramp, node);
+			continue;
+		}
+		if (cmp == 0) {
+			/* Old and new map have this ramp. */
+			old_ramp = AST_LIST_NEXT(old_ramp, node);
+		} else {
+			/* Old map does not have new ramp. */
+		}
+		new_ramp = AST_LIST_NEXT(new_ramp, node);
+	}
+
+	/* Any old ramps left must be dead. */
+	for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
+		remove_exten_if_exist(context, old_ramp->exten, 1);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Destroy the given parking space.
+ *
+ * \param context Dialplan database context name.
+ * \param space Parking space.
+ *
+ * \return Nothing
+ */
+static void destroy_space(const char *context, int space)
+{
+	char exten[AST_MAX_EXTENSION];
+
+	/* Destroy priorities of the parking space that we registered. */
+	snprintf(exten, sizeof(exten), "%d", space);
+	remove_exten_if_exist(context, exten, PRIORITY_HINT);
+	remove_exten_if_exist(context, exten, 1);
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot space items.
+ *
+ * \param context Dialplan database context name.
+ * \param old_spaces Before configuration reload parking space usage map.
+ * \param new_spaces After configuration reload parking space usage map.
+ * \param destroy_space Function to destroy parking space item.
+ *
+ * \details
+ * Remove parking space items that were in the old context but
+ * not in the new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_spaces_usage(const char *context,
+	struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces,
+	void (*destroy_space)(const char *context, int space))
+{
+	struct parking_dp_spaces *old_range;
+	struct parking_dp_spaces *new_range;
+	int space;/*!< Current position in the current old range. */
+	int stop;
+
+	old_range = AST_LIST_FIRST(old_spaces);
+	new_range = AST_LIST_FIRST(new_spaces);
+	space = -1;
+
+	while (old_range) {
+		if (space < old_range->start) {
+			space = old_range->start;
+		}
+		if (new_range) {
+			if (space < new_range->start) {
+				/* Current position in old range starts before new range. */
+				if (old_range->stop < new_range->start) {
+					/* Old range ends before new range. */
+					stop = old_range->stop;
+					old_range = AST_LIST_NEXT(old_range, node);
+				} else {
+					/* Tail of old range overlaps new range. */
+					stop = new_range->start - 1;
+				}
+			} else if (/* new_range->start <= space && */ space <= new_range->stop) {
+				/* Current position in old range overlaps new range. */
+				if (old_range->stop <= new_range->stop) {
+					/* Old range ends at or before new range. */
+					old_range = AST_LIST_NEXT(old_range, node);
+				} else {
+					/* Old range extends beyond end of new range. */
+					space = new_range->stop + 1;
+					new_range = AST_LIST_NEXT(new_range, node);
+				}
+				continue;
+			} else /* if (new_range->stop < space) */ {
+				/* Current position in old range starts after new range. */
+				new_range = AST_LIST_NEXT(new_range, node);
+				continue;
+			}
+		} else {
+			/* No more new ranges.  All remaining old spaces are dead. */
+			stop = old_range->stop;
+			old_range = AST_LIST_NEXT(old_range, node);
+		}
+
+		/* Destroy dead parking spaces. */
+		for (; space <= stop; ++space) {
+			destroy_space(context, space);
+		}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot context items.
+ *
+ * \param context Dialplan database context name.
+ * \param old_ctx Before configuration reload context usage map.
+ * \param new_ctx After configuration reload context usage map.
+ *
+ * \details
+ * Remove context usage items that were in the old context but not in the
+ * new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_context_usage(const char *context, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx)
+{
+	remove_dead_ramp_usage(context, &old_ctx->access_extens, &new_ctx->access_extens);
+	remove_dead_spaces_usage(context, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
+#if 0
+	/* I don't think we should destroy hints if the parking space still exists. */
+	remove_dead_spaces_usage(context, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
+#endif
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot dialplan items.
+ *
+ * \param old_map Before configuration reload dialplan usage map.
+ * \param new_map After configuration reload dialplan usage map.
+ *
+ * \details
+ * Remove dialplan items that were in the old map but not in the
+ * new map.
+ *
+ * \return Nothing
+ */
+static void remove_dead_dialplan_useage(struct parking_dp_map *old_map, struct parking_dp_map *new_map)
+{
+	struct parking_dp_context *old_ctx;
+	struct parking_dp_context *new_ctx;
+	int cmp;
+
+	old_ctx = AST_LIST_FIRST(old_map);
+	new_ctx = AST_LIST_FIRST(new_map);
+
+	while (new_ctx) {
+		if (!old_ctx) {
+			/* No old contexts left, so no dead stuff can remain. */
+			return;
+		}
+		cmp = strcmp(old_ctx->context, new_ctx->context);
+		if (cmp < 0) {
+			/* New map does not have old map context. */
+			ast_context_destroy_by_name(old_ctx->context, registrar);
+			old_ctx = AST_LIST_NEXT(old_ctx, node);
+			continue;
+		}
+		if (cmp == 0) {
+			/* Old and new map have this context. */
+			remove_dead_context_usage(old_ctx->context, old_ctx, new_ctx);
+			old_ctx = AST_LIST_NEXT(old_ctx, node);
+		} else {
+			/* Old map does not have new map context. */
+		}
+		new_ctx = AST_LIST_NEXT(new_ctx, node);
+	}
+
+	/* Any old contexts left must be dead. */
+	for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
+		ast_context_destroy_by_name(old_ctx->context, registrar);
+	}
+}
+
+static int parkinglot_markall_cb(void *obj, void *arg, int flags)
+{
+	struct ast_parkinglot *parkinglot = obj;
+
+	parkinglot->the_mark = 1;
+	return 0;
+}
+
+static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
+{
+	struct ast_parkinglot *parkinglot = obj;
+
+	if (parkinglot->the_mark) {
+		if (AST_LIST_EMPTY(&parkinglot->parkings)) {
+			/* This parking lot can actually be deleted. */
+			return CMP_MATCH;
+		}
+		/* Try reloading later when parking lot is empty. */
+		ast_log(LOG_WARNING,
+			"Parking lot %s has parked calls.  Could not remove.\n",
+			parkinglot->name);
+		parkinglot->disabled = 1;
+		force_reload_load = 1;
+	}
+
+	return 0;
+}
+
+static int parkinglot_activate_cb(void *obj, void *arg, int flags)
+{
+	struct ast_parkinglot *parkinglot = obj;
+
+	if (parkinglot->the_mark) {
+		/*
+		 * Don't activate a parking lot that still bears the_mark since
+		 * it is effectively deleted.
+		 */
+		return 0;
+	}
+
+	if (parkinglot_activate(parkinglot)) {
+		/*
+		 * The parking lot failed to activate.  Allow reloading later to
+		 * see if that fixes it.
+		 */
+		force_reload_load = 1;
+		ast_log(LOG_WARNING, "Parking lot %s not open for business.\n", parkinglot->name);
+	} else {
+		ast_debug(1, "Parking lot %s now open for business. (parkpos %d-%d)\n",
+			parkinglot->name, parkinglot->cfg.parking_start,
+			parkinglot->cfg.parking_stop);
+	}
+
+	return 0;
+}
+
+static int load_config(int reload)
+{
+	struct ast_flags config_flags = {
+		reload && !force_reload_load ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	struct ast_config *cfg;
+	struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
+	struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
+
+	/* We are reloading now and have already determined if we will force the reload. */
+	force_reload_load = 0;
+
+	if (!default_parkinglot) {
+		/* Must create the default default parking lot */
+		default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
+		if (!default_parkinglot) {
+			ast_log(LOG_ERROR, "Configuration of default default parking lot failed.\n");
+			return -1;
+		}
+		ast_debug(1, "Configuration of default default parking lot done.\n");
+	}
+
+	cfg = ast_config_load2("features.conf", "features", config_flags);
+	if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+		/* No sense in asking for reload trouble if nothing changed. */
+		ast_debug(1, "features.conf did not change.\n");
+		return 0;
+	}
+	if (cfg == CONFIG_STATUS_FILEMISSING
+		|| cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "Could not load features.conf\n");
+		return 0;
+	}
+
+	/* Save current parking lot dialplan needs. */
+	if (build_dialplan_useage_map(&old_usage_map, 0)) {
+		destroy_dialplan_usage_map(&old_usage_map);
+
+		/* Allow reloading later to see if conditions have improved. */
+		force_reload_load = 1;
+		return -1;
+	}
+
+	ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
+		"callback to mark all parking lots");
+	process_config(cfg);
+	ast_config_destroy(cfg);
+	ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
+		"callback to remove marked parking lots");
+
+	/* Save updated parking lot dialplan needs. */
+	if (build_dialplan_useage_map(&new_usage_map, 1)) {
+		/*
+		 * Yuck, if this failure caused any parking lot dialplan items
+		 * to be lost, they will likely remain lost until Asterisk is
+		 * restarted.
+		 */
+		destroy_dialplan_usage_map(&old_usage_map);
+		destroy_dialplan_usage_map(&new_usage_map);
+		return -1;
+	}
+
+	/* Remove no longer needed parking lot dialplan usage. */
+	remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
+
+	destroy_dialplan_usage_map(&old_usage_map);
+	destroy_dialplan_usage_map(&new_usage_map);
+
+	ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_activate_cb, NULL,
+		"callback to activate all parking lots");
+
+	return 0;
+}
+
+/*!
+ * \brief CLI command to list configured features
+ * \param e
+ * \param cmd
+ * \param a
+ *
+ * \retval CLI_SUCCESS on success.
+ * \retval NULL when tab completion is used.
+ */
+static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int i;
+	struct ast_call_feature *feature;
+	struct ao2_iterator iter;
+	struct ast_parkinglot *curlot;
+#define HFS_FORMAT "%-25s %-7s %-7s\n"
+
+	switch (cmd) {
+
+	case CLI_INIT:
+		e->command = "features show";
+		e->usage =
+			"Usage: features show\n"
+			"       Lists configured features\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
+	ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
+
+	ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
+
+	ast_rwlock_rdlock(&features_lock);
+	for (i = 0; i < FEATURES_COUNT; i++)
+		ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
+	ast_rwlock_unlock(&features_lock);
+
+	ast_cli(a->fd, "\n");
+	ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
+	ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
+	if (AST_RWLIST_EMPTY(&feature_list)) {
+		ast_cli(a->fd, "(none)\n");
+	} else {
+		AST_RWLIST_RDLOCK(&feature_list);
+		AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
+			ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
+		}
+		AST_RWLIST_UNLOCK(&feature_list);
+	}
+
+	ast_cli(a->fd, "\nFeature Groups:\n");
+	ast_cli(a->fd, "---------------\n");
+	if (AST_RWLIST_EMPTY(&feature_groups)) {
+		ast_cli(a->fd, "(none)\n");
+	} else {
+		struct feature_group *fg;
+		struct feature_group_exten *fge;
+
+		AST_RWLIST_RDLOCK(&feature_groups);
+		AST_RWLIST_TRAVERSE(&feature_groups, fg, entry) {
+			ast_cli(a->fd, "===> Group: %s\n", fg->gname);
+			AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+				ast_cli(a->fd, "===> --> %s (%s)\n", fge->feature->sname, fge->exten);
+			}
+		}
+		AST_RWLIST_UNLOCK(&feature_groups);
+	}
+
+	iter = ao2_iterator_init(parkinglots, 0);
+	while ((curlot = ao2_iterator_next(&iter))) {
+		ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
+		ast_cli(a->fd, "------------\n");
+		ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->cfg.parkext);
+		ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->cfg.parking_con);
+		ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions",
+			curlot->cfg.parking_start, curlot->cfg.parking_stop);
+		ast_cli(a->fd,"%-22s:      %u ms\n", "Parkingtime", curlot->cfg.parkingtime);
+		ast_cli(a->fd,"%-22s:      %s\n", "Comeback to origin",
+				(curlot->cfg.comebacktoorigin ? "yes" : "no"));
+		ast_cli(a->fd,"%-22s:      %s%s\n", "Comeback context",
+				curlot->cfg.comebackcontext, (curlot->cfg.comebacktoorigin ?
+					" (comebacktoorigin=yes, not used)" : ""));
+		ast_cli(a->fd,"%-22s:      %u\n", "Comeback dial time",
+				curlot->cfg.comebackdialtime);
+		ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->cfg.mohclass);
+		ast_cli(a->fd,"%-22s:      %s\n", "Enabled", AST_CLI_YESNO(!curlot->disabled));
+		ast_cli(a->fd,"\n");
+		ao2_ref(curlot, -1);
+	}
+	ao2_iterator_destroy(&iter);
+
+	return CLI_SUCCESS;
+}
+
+int ast_features_reload(void)
+{
+	int res;
+
+	ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
+
+	/*
+	 * Always destroy the parking_con_dial context to remove buildup
+	 * of recalled extensions in the context.  At worst, the parked
+	 * call gets hungup attempting to run an invalid extension when
+	 * we are trying to callback the parker or the preset return
+	 * extension.  This is a small window of opportunity on an
+	 * execution chain that is not expected to happen very often.
+	 */
+	ast_context_destroy_by_name(parking_con_dial, registrar);
+
+	res = load_config(1);
+	ast_mutex_unlock(&features_reload_lock);
+
+	return res;
+}
+
+static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "features reload";
+		e->usage =
+			"Usage: features reload\n"
+			"       Reloads configured call features from features.conf\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+	ast_features_reload();
+
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \brief Actual bridge
+ * \param chan
+ * \param tmpchan
+ *
+ * Stop hold music, lock both channels, masq channels,
+ * after bridge return channel to next priority.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
+{
+	const char *context;
+	const char *exten;
+	int priority;
+
+	ast_moh_stop(chan);
+	ast_channel_lock_both(chan, tmpchan);
+	context = ast_strdupa(ast_channel_context(chan));
+	exten = ast_strdupa(ast_channel_exten(chan));
+	priority = ast_channel_priority(chan);
+	ast_setstate(tmpchan, ast_channel_state(chan));
+	ast_format_copy(ast_channel_readformat(tmpchan), ast_channel_readformat(chan));
+	ast_format_copy(ast_channel_writeformat(tmpchan), ast_channel_writeformat(chan));
+	ast_channel_unlock(chan);
+	ast_channel_unlock(tmpchan);
+
+	/* Masquerade setup and execution must be done without any channel locks held */
+	if (ast_channel_masquerade(tmpchan, chan)) {
+		return -1;
+	}
+	ast_do_masquerade(tmpchan);
+
+	/* when returning from bridge, the channel will continue at the next priority */
+	ast_explicit_goto(tmpchan, context, exten, priority + 1);
+
+	return 0;
+}
+
+/*!
+ * \brief Bridge channels together
+ * \param s
+ * \param m
+ *
+ * Make sure valid channels were specified,
+ * send errors if any of the channels could not be found/locked, answer channels if needed,
+ * create the placeholder channels and grab the other channels
+ * make the channels compatible, send error if we fail doing so
+ * setup the bridge thread object and start the bridge.
+ *
+ * \retval 0
+ */
+static int action_bridge(struct mansession *s, const struct message *m)
+{
+	const char *channela = astman_get_header(m, "Channel1");
+	const char *channelb = astman_get_header(m, "Channel2");
+	const char *playtone = astman_get_header(m, "Tone");
+	struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
+	struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
+	struct ast_bridge_thread_obj *tobj = NULL;
+	char buf[256];
+
+	/* make sure valid channels were specified */
+	if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
+		astman_send_error(s, m, "Missing channel parameter in request");
+		return 0;
+	}
+
+	/* Start with chana */
+	chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
+	if (!chana) {
+		snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
+		astman_send_error(s, m, buf);
+		return 0;
+	}
+
+	/* Answer the channels if needed */
+	if (ast_channel_state(chana) != AST_STATE_UP)
+		ast_answer(chana);
+
+	/* create the placeholder channels and grab the other channels */
+	if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+		NULL, NULL, ast_channel_linkedid(chana), 0, "Bridge/%s", ast_channel_name(chana)))) {
+		astman_send_error(s, m, "Unable to create temporary channel!");
+		chana = ast_channel_unref(chana);
+		return 0;
+	}
+
+	if (do_bridge_masquerade(chana, tmpchana)) {
+		snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
+		astman_send_error(s, m, buf);
+		ast_hangup(tmpchana);
+		chana = ast_channel_unref(chana);
+		return 0;
+	}
+
+	chana = ast_channel_unref(chana);
+
+	/* now do chanb */
+	chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
+	if (!chanb) {
+		snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
+		astman_send_error(s, m, buf);
+		ast_hangup(tmpchana);
+		return 0;
+	}
+
+	/* Answer the channels if needed */
+	if (ast_channel_state(chanb) != AST_STATE_UP)
+		ast_answer(chanb);
+
+	/* create the placeholder channels and grab the other channels */
+	if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+		NULL, NULL, ast_channel_linkedid(chanb), 0, "Bridge/%s", ast_channel_name(chanb)))) {
+		astman_send_error(s, m, "Unable to create temporary channels!");
+		ast_hangup(tmpchana);
+		chanb = ast_channel_unref(chanb);
+		return 0;
+	}
+
+	if (do_bridge_masquerade(chanb, tmpchanb)) {
+		snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
+		astman_send_error(s, m, buf);
+		ast_hangup(tmpchana);
+		ast_hangup(tmpchanb);
+		chanb = ast_channel_unref(chanb);
+		return 0;
+	}
+
+	chanb = ast_channel_unref(chanb);
+
+	/* make the channels compatible, send error if we fail doing so */
+	if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
+		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb));
+		astman_send_error(s, m, "Could not make channels compatible for manager bridge");
+		ast_hangup(tmpchana);
+		ast_hangup(tmpchanb);
+		return 0;
+	}
+
+	/* setup the bridge thread object and start the bridge */
+	if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
+		ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb), strerror(errno));
+		astman_send_error(s, m, "Unable to spawn a new bridge thread");
+		ast_hangup(tmpchana);
+		ast_hangup(tmpchanb);
+		return 0;
+	}
+
+	tobj->chan = tmpchana;
+	tobj->peer = tmpchanb;
+	tobj->return_to_pbx = 1;
+
+	if (ast_true(playtone)) {
+		if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, ast_channel_language(tmpchanb))) {
+			if (ast_waitstream(tmpchanb, "") < 0)
+				ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", ast_channel_name(tmpchanb));
+		}
+	}
+
+	chans[0] = tmpchana;
+	chans[1] = tmpchanb;
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a bridge is successfully created due to a manager action.</synopsis>
+			<syntax>
+				<parameter name="Response">
+					<enumlist>
+						<enum name="Success"/>
+						<enum name="Failed"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="manager">Bridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeAction", 2, chans,
+				"Response: Success\r\n"
+				"Channel1: %s\r\n"
+				"Channel2: %s\r\n", ast_channel_name(tmpchana), ast_channel_name(tmpchanb));
+
+	bridge_call_thread_launch(tobj);
+
+	astman_send_ack(s, m, "Launched bridge thread with success");
+
+	return 0;
+}
+
+/*!
+ * \brief CLI command to list parked calls
+ * \param e
+ * \param cmd
+ * \param a
+ *
+ * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
+ * \retval CLI_SUCCESS on success.
+ * \retval CLI_SHOWUSAGE on incorrect number of arguments.
+ * \retval NULL when tab completion is used.
+ */
+static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct parkeduser *cur;
+	int numparked = 0;
+	struct ao2_iterator iter;
+	struct ast_parkinglot *curlot;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "parkedcalls show";
+		e->usage =
+			"Usage: parkedcalls show\n"
+			"       List currently parked calls\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc > e->args)
+		return CLI_SHOWUSAGE;
+
+	ast_cli(a->fd, "%-10s %-25s (%-15s %-12s %4s) %s\n", "Num", "Channel",
+		"Context", "Extension", "Pri", "Timeout");
+
+	iter = ao2_iterator_init(parkinglots, 0);
+	while ((curlot = ao2_iterator_next(&iter))) {
+		int lotparked = 0;
+
+		/* subtract ref for iterator and for configured parking lot */
+		ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name,
+			ao2_ref(curlot, 0) - 2 - (curlot == default_parkinglot));
+
+		AST_LIST_LOCK(&curlot->parkings);
+		AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
+			ast_cli(a->fd, "%-10.10s %-25s (%-15s %-12s %4d) %6lds\n",
+				cur->parkingexten, ast_channel_name(cur->chan), cur->context, cur->exten,
+				cur->priority,
+				(long) (cur->start.tv_sec + (cur->parkingtime / 1000) - time(NULL)));
+			++lotparked;
+		}
+		AST_LIST_UNLOCK(&curlot->parkings);
+		if (lotparked) {
+			numparked += lotparked;
+			ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked,
+				ESS(lotparked), curlot->name);
+		}
+
+		ao2_ref(curlot, -1);
+	}
+	ao2_iterator_destroy(&iter);
+
+	ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_features[] = {
+	AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
+	AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
+	AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
+};
+
+static int manager_parkinglot_list(struct mansession *s, const struct message *m)
+{
+	const char *id = astman_get_header(m, "ActionID");
+	char idText[256] = "";
+	struct ao2_iterator iter;
+	struct ast_parkinglot *curlot;
+
+	if (!ast_strlen_zero(id))
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+
+	astman_send_ack(s, m, "Parking lots will follow");
+
+	iter = ao2_iterator_init(parkinglots, 0);
+	while ((curlot = ao2_iterator_next(&iter))) {
+		astman_append(s, "Event: Parkinglot\r\n"
+			"Name: %s\r\n"
+			"StartExten: %d\r\n"
+			"StopExten: %d\r\n"
+			"Timeout: %u\r\n"
+			"\r\n",
+			curlot->name,
+			curlot->cfg.parking_start,
+			curlot->cfg.parking_stop,
+			curlot->cfg.parkingtime ? curlot->cfg.parkingtime / 1000 : curlot->cfg.parkingtime);
+		ao2_ref(curlot, -1);
+	}
+
+	astman_append(s,
+		"Event: ParkinglotsComplete\r\n"
+		"%s"
+		"\r\n",idText);
+
+	return RESULT_SUCCESS;
+}
+
+/*!
+ * \brief Dump parking lot status
+ * \param s
+ * \param m
+ *
+ * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
+ * \return Always RESULT_SUCCESS
+ */
+static int manager_parking_status(struct mansession *s, const struct message *m)
+{
+	struct parkeduser *cur;
+	const char *id = astman_get_header(m, "ActionID");
+	char idText[256] = "";
+	struct ao2_iterator iter;
+	struct ast_parkinglot *curlot;
+	int numparked = 0;
+	long now = time(NULL);
+
+	if (!ast_strlen_zero(id))
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+
+	astman_send_ack(s, m, "Parked calls will follow");
+
+	iter = ao2_iterator_init(parkinglots, 0);
+	while ((curlot = ao2_iterator_next(&iter))) {
+		AST_LIST_LOCK(&curlot->parkings);
+		AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
+			astman_append(s, "Event: ParkedCall\r\n"
+				"Parkinglot: %s\r\n"
+				"Exten: %d\r\n"
+				"Channel: %s\r\n"
+				"From: %s\r\n"
+				"Timeout: %ld\r\n"
+				"Duration: %ld\r\n"
+				"CallerIDNum: %s\r\n"
+				"CallerIDName: %s\r\n"
+				"ConnectedLineNum: %s\r\n"
+				"ConnectedLineName: %s\r\n"
+				"%s"
+				"\r\n",
+				curlot->name,
+				cur->parkingnum, ast_channel_name(cur->chan), cur->peername,
+				(long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - now,
+				now - (long) cur->start.tv_sec,
+				S_COR(ast_channel_caller(cur->chan)->id.number.valid, ast_channel_caller(cur->chan)->id.number.str, ""),	/* XXX in other places it is <unknown> */
+				S_COR(ast_channel_caller(cur->chan)->id.name.valid, ast_channel_caller(cur->chan)->id.name.str, ""),
+				S_COR(ast_channel_connected(cur->chan)->id.number.valid, ast_channel_connected(cur->chan)->id.number.str, ""),	/* XXX in other places it is <unknown> */
+				S_COR(ast_channel_connected(cur->chan)->id.name.valid, ast_channel_connected(cur->chan)->id.name.str, ""),
+				idText);
+			++numparked;
+		}
+		AST_LIST_UNLOCK(&curlot->parkings);
+		ao2_ref(curlot, -1);
+	}
+	ao2_iterator_destroy(&iter);
+
+	astman_append(s,
+		"Event: ParkedCallsComplete\r\n"
+		"Total: %d\r\n"
+		"%s"
+		"\r\n",
+		numparked, idText);
+
+	return RESULT_SUCCESS;
+}
+
+/*!
+ * \brief Create manager event for parked calls
+ * \param s
+ * \param m
+ *
+ * Get channels involved in park, create event.
+ * \return Always 0
+ *
+ * \note ADSI is not compatible with this AMI action for the
+ * same reason ch2 can no longer announce the parking space.
+ */
+static int manager_park(struct mansession *s, const struct message *m)
+{
+	const char *channel = astman_get_header(m, "Channel");
+	const char *channel2 = astman_get_header(m, "Channel2");
+	const char *timeout = astman_get_header(m, "Timeout");
+	const char *parkinglotname = astman_get_header(m, "Parkinglot");
+	char buf[BUFSIZ];
+	int res = 0;
+	struct ast_channel *ch1, *ch2;
+	struct ast_park_call_args args = {
+			/*
+			 * Don't say anything to ch2 since AMI is a third party parking
+			 * a call and we will likely crash if we do.
+			 *
+			 * XXX When the AMI action was originally implemented, the
+			 * parking space was announced to ch2.  Unfortunately, grabbing
+			 * the ch2 lock and holding it while the announcement is played
+			 * was not really a good thing to do to begin with since it
+			 * could hold up the system.  Also holding the lock is no longer
+			 * possible with a masquerade.
+			 *
+			 * Restoring the announcement to ch2 is not easily doable for
+			 * the following reasons:
+			 *
+			 * 1) The AMI manager is not the thread processing ch2.
+			 *
+			 * 2) ch2 could be the same as ch1, bridged to ch1, or some
+			 * random uninvolved channel.
+			 */
+			.flags = AST_PARK_OPT_SILENCE,
+		};
+
+	if (ast_strlen_zero(channel)) {
+		astman_send_error(s, m, "Channel not specified");
+		return 0;
+	}
+
+	if (ast_strlen_zero(channel2)) {
+		astman_send_error(s, m, "Channel2 not specified");
+		return 0;
+	}
+
+	if (!ast_strlen_zero(timeout)) {
+		if (sscanf(timeout, "%30d", &args.timeout) != 1) {
+			astman_send_error(s, m, "Invalid timeout value.");
+			return 0;
+		}
+	}
+
+	if (!(ch1 = ast_channel_get_by_name(channel))) {
+		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
+		astman_send_error(s, m, buf);
+		return 0;
+	}
+
+	if (!(ch2 = ast_channel_get_by_name(channel2))) {
+		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
+		astman_send_error(s, m, buf);
+		ast_channel_unref(ch1);
+		return 0;
+	}
+
+	if (!ast_strlen_zero(parkinglotname)) {
+		args.parkinglot = find_parkinglot(parkinglotname);
+	}
+
+	res = masq_park_call(ch1, ch2, &args);
+	if (!res) {
+		ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
+		astman_send_ack(s, m, "Park successful");
+	} else {
+		astman_send_error(s, m, "Park failure");
+	}
+
+	if (args.parkinglot) {
+		parkinglot_unref(args.parkinglot);
+	}
+	ch1 = ast_channel_unref(ch1);
+	ch2 = ast_channel_unref(ch2);
+
+	return 0;
+}
+
+/*!
+ * The presence of this datastore on the channel indicates that
+ * someone is attemting to pickup or has picked up the channel.
+ * The purpose is to prevent a race between two channels
+ * attempting to pickup the same channel.
+ */
+static const struct ast_datastore_info pickup_active = {
+	.type = "pickup-active",
+};
+
+int ast_can_pickup(struct ast_channel *chan)
+{
+	if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
+		&& (ast_channel_state(chan) == AST_STATE_RINGING
+			|| ast_channel_state(chan) == AST_STATE_RING
+			/*
+			 * Check the down state as well because some SIP devices do not
+			 * give 180 ringing when they can just give 183 session progress
+			 * instead.  Issue 14005.  (Some ISDN switches as well for that
+			 * matter.)
+			 */
+			|| ast_channel_state(chan) == AST_STATE_DOWN)
+		&& !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
+		return 1;
+	}
+	return 0;
+}
+
+static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
+{
+	struct ast_channel *target = obj;/*!< Potential pickup target */
+	struct ast_channel *chan = arg;/*!< Channel wanting to pickup call */
+
+	if (chan == target) {
+		return 0;
+	}
+
+	ast_channel_lock(target);
+	if (ast_can_pickup(target)) {
+		/* Lock both channels. */
+		while (ast_channel_trylock(chan)) {
+			ast_channel_unlock(target);
+			sched_yield();
+			ast_channel_lock(target);
+		}
+
+		/*
+		 * Both callgroup and namedcallgroup pickup variants are
+		 * matched independently.  Checking for named group match is
+		 * done last since it's a more expensive operation.
+		 */
+		if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
+			|| (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan),
+				ast_channel_named_callgroups(target)))) {
+			struct ao2_container *candidates = data;/*!< Candidate channels found. */
+
+			/* This is a candidate to pickup */
+			ao2_link(candidates, target);
+		}
+		ast_channel_unlock(chan);
+	}
+	ast_channel_unlock(target);
+
+	return 0;
+}
+
+struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan)
+{
+	struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
+	struct ast_channel *target;/*!< Potential pickup target */
+
+	candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
+	if (!candidates) {
+		return NULL;
+	}
+
+	/* Find all candidate targets by group. */
+	ast_channel_callback(find_channel_by_group, chan, candidates, 0);
+
+	/* Find the oldest pickup target candidate */
+	target = NULL;
+	for (;;) {
+		struct ast_channel *candidate;/*!< Potential new older target */
+		struct ao2_iterator iter;
+
+		iter = ao2_iterator_init(candidates, 0);
+		while ((candidate = ao2_iterator_next(&iter))) {
+			if (!target) {
+				/* First target. */
+				target = candidate;
+				continue;
+			}
+			if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
+				/* We have a new target. */
+				ast_channel_unref(target);
+				target = candidate;
+				continue;
+			}
+			ast_channel_unref(candidate);
+		}
+		ao2_iterator_destroy(&iter);
+		if (!target) {
+			/* No candidates found. */
+			break;
+		}
+
+		/* The found channel must be locked and ref'd. */
+		ast_channel_lock(target);
+
+		/* Recheck pickup ability */
+		if (ast_can_pickup(target)) {
+			/* This is the channel to pickup. */
+			break;
+		}
+
+		/* Someone else picked it up or the call went away. */
+		ast_channel_unlock(target);
+		ao2_unlink(candidates, target);
+		target = ast_channel_unref(target);
+	}
+	ao2_ref(candidates, -1);
+
+	return target;
+}
+
+/*!
+ * \brief Pickup a call
+ * \param chan channel that initiated pickup.
+ *
+ * Walk list of channels, checking it is not itself, channel is pbx one,
+ * check that the callgroup for both channels are the same and the channel is ringing.
+ * Answer calling channel, flag channel as answered on queue, masq channels together.
+ */
+int ast_pickup_call(struct ast_channel *chan)
+{
+	struct ast_channel *target;/*!< Potential pickup target */
+	int res = -1;
+
+	ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan));
+
+	/* The found channel is already locked. */
+	target = ast_pickup_find_by_group(chan);
+	if (target) {
+		ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
+
+		res = ast_do_pickup(chan, target);
+		ast_channel_unlock(target);
+		if (!res) {
+			if (!ast_strlen_zero(pickupsound)) {
+				pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickupsound);
+			}
+		} else {
+			ast_log(LOG_WARNING, "pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
+		}
+		target = ast_channel_unref(target);
+	}
+
+	if (res < 0) {
+		ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
+		if (!ast_strlen_zero(pickupfailsound)) {
+			ast_answer(chan);
+			ast_stream_and_wait(chan, pickupfailsound, "");
+		}
+	}
+
+	return res;
+}
+
+int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
+{
+	struct ast_party_connected_line connected_caller;
+	struct ast_channel *chans[2] = { chan, target };
+	struct ast_datastore *ds_pickup;
+	const char *chan_name;/*!< A masquerade changes channel names. */
+	const char *target_name;/*!< A masquerade changes channel names. */
+	int res = -1;
+
+	target_name = ast_strdupa(ast_channel_name(target));
+	ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
+
+	/* Mark the target to block any call pickup race. */
+	ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
+	if (!ds_pickup) {
+		ast_log(LOG_WARNING,
+			"Unable to create channel datastore on '%s' for call pickup\n", target_name);
+		return -1;
+	}
+	ast_channel_datastore_add(target, ds_pickup);
+
+	ast_party_connected_line_init(&connected_caller);
+	ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
+	ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
+	/* Reset any earlier private connected id representation */
+	ast_party_id_reset(&connected_caller.priv);
+
+	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+	if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
+		ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
+		ast_channel_update_connected_line(chan, &connected_caller, NULL);
+	}
+	ast_party_connected_line_free(&connected_caller);
+
+	ast_channel_lock(chan);
+	chan_name = ast_strdupa(ast_channel_name(chan));
+	ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
+	ast_channel_unlock(chan);
+	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+
+	ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
+
+	if (ast_answer(chan)) {
+		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
+		goto pickup_failed;
+	}
+
+	if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
+		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
+		goto pickup_failed;
+	}
+
+	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
+
+	/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
+	ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
+
+	if (ast_channel_masquerade(target, chan)) {
+		ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name,
+			target_name);
+		goto pickup_failed;
+	}
+
+	/* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a call pickup occurs.</synopsis>
+			<syntax>
+				<parameter name="Channel"><para>The name of the channel that initiated the pickup.</para></parameter>
+				<parameter name="TargetChannel"><para>The name of the channel that is being picked up.</para></parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
+		"Channel: %s\r\n"
+		"TargetChannel: %s\r\n",
+		chan_name, target_name);
+
+	/* Do the masquerade manually to make sure that it is completed. */
+	ast_do_masquerade(target);
+	res = 0;
+
+pickup_failed:
+	ast_channel_lock(target);
+	if (!ast_channel_datastore_remove(target, ds_pickup)) {
+		ast_datastore_free(ds_pickup);
+	}
+	ast_party_connected_line_free(&connected_caller);
+
+	return res;
+}
+
+static char *app_bridge = "Bridge";
+
+enum {
+	BRIDGE_OPT_PLAYTONE = (1 << 0),
+	OPT_CALLEE_HANGUP =	(1 << 1),
+	OPT_CALLER_HANGUP =	(1 << 2),
+	OPT_DURATION_LIMIT = (1 << 3),
+	OPT_DURATION_STOP =	(1 << 4),
+	OPT_CALLEE_TRANSFER = (1 << 5),
+	OPT_CALLER_TRANSFER = (1 << 6),
+	OPT_CALLEE_MONITOR = (1 << 7),
+	OPT_CALLER_MONITOR = (1 << 8),
+	OPT_CALLEE_PARK = (1 << 9),
+	OPT_CALLER_PARK = (1 << 10),
+	OPT_CALLEE_KILL = (1 << 11),
+	OPT_CALLEE_GO_ON = (1 << 12),
+};
+
+enum {
+	OPT_ARG_DURATION_LIMIT = 0,
+	OPT_ARG_DURATION_STOP,
+	OPT_ARG_CALLEE_GO_ON,
+	/* note: this entry _MUST_ be the last one in the enum */
+	OPT_ARG_ARRAY_SIZE,
+};
+
+AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
+	AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
+	AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
+	AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
+	AST_APP_OPTION('H', OPT_CALLER_HANGUP),
+	AST_APP_OPTION('k', OPT_CALLEE_PARK),
+	AST_APP_OPTION('K', OPT_CALLER_PARK),
+	AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
+	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
+	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+	AST_APP_OPTION('x', OPT_CALLEE_KILL),
+END_OPTIONS );
+
+int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
+	char *parse, struct timeval *calldurationlimit)
+{
+	char *stringp = ast_strdupa(parse);
+	char *limit_str, *warning_str, *warnfreq_str;
+	const char *var;
+	int play_to_caller = 0, play_to_callee = 0;
+	int delta;
+
+	limit_str = strsep(&stringp, ":");
+	warning_str = strsep(&stringp, ":");
+	warnfreq_str = strsep(&stringp, ":");
+
+	config->timelimit = atol(limit_str);
+	if (warning_str)
+		config->play_warning = atol(warning_str);
+	if (warnfreq_str)
+		config->warning_freq = atol(warnfreq_str);
+
+	if (!config->timelimit) {
+		ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
+		config->timelimit = config->play_warning = config->warning_freq = 0;
+		config->warning_sound = NULL;
+		return -1; /* error */
+	} else if ( (delta = config->play_warning - config->timelimit) > 0) {
+		int w = config->warning_freq;
+
+		/*
+		 * If the first warning is requested _after_ the entire call
+		 * would end, and no warning frequency is requested, then turn
+		 * off the warning. If a warning frequency is requested, reduce
+		 * the 'first warning' time by that frequency until it falls
+		 * within the call's total time limit.
+		 *
+		 * Graphically:
+		 *                timelim->|    delta        |<-playwarning
+		 *      0__________________|_________________|
+		 *                       | w  |    |    |    |
+		 *
+		 * so the number of intervals to cut is 1+(delta-1)/w
+		 */
+		if (w == 0) {
+			config->play_warning = 0;
+		} else {
+			config->play_warning -= w * ( 1 + (delta-1)/w );
+			if (config->play_warning < 1)
+				config->play_warning = config->warning_freq = 0;
+		}
+	}
+
+	ast_channel_lock(chan);
+
+	var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
+	play_to_caller = var ? ast_true(var) : 1;
+
+	var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
+	play_to_callee = var ? ast_true(var) : 0;
+
+	if (!play_to_caller && !play_to_callee)
+		play_to_caller = 1;
+
+	var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
+	config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
+
+	/* The code looking at config wants a NULL, not just "", to decide
+	 * that the message should not be played, so we replace "" with NULL.
+	 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
+	 * not found.
+	 */
+
+	var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
+	config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
+
+	var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
+	config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
+
+	ast_channel_unlock(chan);
+
+	/* undo effect of S(x) in case they are both used */
+	calldurationlimit->tv_sec = 0;
+	calldurationlimit->tv_usec = 0;
+
+	/* more efficient to do it like S(x) does since no advanced opts */
+	if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
+		calldurationlimit->tv_sec = config->timelimit / 1000;
+		calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
+		ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
+			calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
+		config->timelimit = play_to_caller = play_to_callee =
+		config->play_warning = config->warning_freq = 0;
+	} else {
+		ast_verb(4, "Limit Data for this call:\n");
+		ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
+		ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
+		ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
+		ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
+		ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
+		ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
+		ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
+		ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
 	}
+	if (play_to_caller)
+		ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
+	if (play_to_callee)
+		ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
+	return 0;
+}
 
-	ast_debug(1, "Performing Bridge action on %s and %s\n", channela, channelb);
 
-	/* Start with chana */
-	chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
-	if (!chana) {
-		snprintf(buf, sizeof(buf), "Channel1 does not exist: %s", channela);
-		astman_send_error(s, m, buf);
+/*!
+ * \brief Bridge channels
+ * \param chan
+ * \param data channel to bridge with.
+ *
+ * Split data, check we aren't bridging with ourself, check valid channel,
+ * answer call if not already, check compatible channels, setup bridge config
+ * now bridge call, if transferred party hangs up return to PBX extension.
+ */
+static int bridge_exec(struct ast_channel *chan, const char *data)
+{
+	struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
+	char *tmp_data  = NULL;
+	struct ast_flags opts = { 0, };
+	struct ast_bridge_config bconfig = { { 0, }, };
+	char *opt_args[OPT_ARG_ARRAY_SIZE];
+	struct timeval calldurationlimit = { 0, };
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(dest_chan);
+		AST_APP_ARG(options);
+	);
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
+		return -1;
+	}
+
+	tmp_data = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, tmp_data);
+	if (!ast_strlen_zero(args.options))
+		ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
+
+	/* avoid bridge with ourselves */
+	if (!strcmp(ast_channel_name(chan), args.dest_chan)) {
+		ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an error occurs during bridge creation.</synopsis>
+				<see-also>
+					<ref type="application">Bridge</ref>
+				</see-also>
+			</managerEventInstance>
+		***/
+		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+			"Response: Failed\r\n"
+			"Reason: Unable to bridge channel to itself\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n",
+			ast_channel_name(chan), args.dest_chan);
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
 		return 0;
 	}
-	xfer_cfg_a = ast_get_chan_features_xfer_config(chana);
-	ast_channel_lock(chana);
-	chana_exten = ast_strdupa(ast_channel_exten(chana));
-	chana_context = ast_strdupa(ast_channel_context(chana));
-	chana_priority = ast_channel_priority(chana);
-	if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) {
-		chana_priority++;
+
+	/* make sure we have a valid end point */
+	if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
+			strlen(args.dest_chan)))) {
+		ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
+			args.dest_chan);
+		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+			"Response: Failed\r\n"
+			"Reason: Channel2 does not exist\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
+		return 0;
 	}
-	ast_channel_unlock(chana);
 
-	chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
-	if (!chanb) {
-		snprintf(buf, sizeof(buf), "Channel2 does not exist: %s", channelb);
-		astman_send_error(s, m, buf);
+	/* try to allocate a place holder where current_dest_chan will be placed */
+	if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+		NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) {
+		ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
+		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+			"Response: Failed\r\n"
+			"Reason: Cannot create placeholder channel\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+		ast_channel_unref(current_dest_chan);
 		return 0;
 	}
-	xfer_cfg_b = ast_get_chan_features_xfer_config(chanb);
-	ast_channel_lock(chanb);
-	chanb_exten = ast_strdupa(ast_channel_exten(chanb));
-	chanb_context = ast_strdupa(ast_channel_context(chanb));
-	chanb_priority = ast_channel_priority(chanb);
-	if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) {
-		chanb_priority++;
+
+	if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
+		&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
+		&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
+		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+			"Response: Failed\r\n"
+			"Reason: Cannot setup bridge time limit\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
+		ast_hangup(final_dest_chan);
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+		current_dest_chan = ast_channel_unref(current_dest_chan);
+		goto done;
 	}
-	ast_channel_unlock(chanb);
 
-	bridge = ast_bridge_basic_new();
-	if (!bridge) {
-		astman_send_error(s, m, "Unable to create bridge\n");
-		return 0;
+	if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
+		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+			"Response: Failed\r\n"
+			"Reason: Cannot masquerade channels\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
+		ast_hangup(final_dest_chan);
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+		current_dest_chan = ast_channel_unref(current_dest_chan);
+		goto done;
 	}
 
-	ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL);
-	if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) {
-		snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana));
-		astman_send_error(s, m, buf);
-		ast_bridge_destroy(bridge, 0);
-		return 0;
+	/* answer the channel if needed */
+	if (ast_channel_state(final_dest_chan) != AST_STATE_UP) {
+		ast_answer(final_dest_chan);
 	}
 
-	ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL);
-	if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) {
-		snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb));
-		astman_send_error(s, m, buf);
-		ast_bridge_destroy(bridge, 0);
-		return 0;
+	chans[0] = current_dest_chan;
+	chans[1] = final_dest_chan;
+
+	/* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
+	/* try to make compatible, send error if we fail */
+	if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
+		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
+		ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
+			"Response: Failed\r\n"
+			"Reason: Could not make channels compatible for bridge\r\n"
+			"Channel1: %s\r\n"
+			"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
+
+		/* Maybe we should return this channel to the PBX? */
+		ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
+
+		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
+		current_dest_chan = ast_channel_unref(current_dest_chan);
+		goto done;
+	}
+
+	/* Report that the bridge will be successfull */
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when the bridge is created successfully.</synopsis>
+			<see-also>
+				<ref type="application">Bridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
+		"Response: Success\r\n"
+		"Channel1: %s\r\n"
+		"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
+
+	current_dest_chan = ast_channel_unref(current_dest_chan);
+
+	/* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */
+	if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
+		if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) {
+			if (ast_waitstream(final_dest_chan, "") < 0)
+				ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan));
+		}
 	}
 
-	astman_send_ack(s, m, "Channels have been bridged");
-	ao2_cleanup(bridge);
+	if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
+		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
+	if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
+		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
+	if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
+		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
+	if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
+		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
+	if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
+		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
+	if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
+		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
+	if (ast_test_flag(&opts, OPT_CALLEE_PARK))
+		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
+	if (ast_test_flag(&opts, OPT_CALLER_PARK))
+		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
+
+	/*
+	 * Don't let the after-bridge code run the h-exten.  We want to
+	 * continue in the dialplan.
+	 */
+	ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
+	ast_bridge_call(chan, final_dest_chan, &bconfig);
+
+	/* The bridge has ended, set BRIDGERESULT to SUCCESS. */
+	pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
+
+	/* If the other channel has not been hung up, return it to the PBX */
+	if (!ast_check_hangup(final_dest_chan)) {
+		if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
+			char *caller_context;
+			char *caller_extension;
+			int caller_priority;
+			int goto_opt;
+
+			ast_channel_lock(chan);
+			caller_context = ast_strdupa(ast_channel_context(chan));
+			caller_extension = ast_strdupa(ast_channel_exten(chan));
+			caller_priority = ast_channel_priority(chan);
+			ast_channel_unlock(chan);
+
+			if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+				ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+				/* Set current dialplan position to bridger dialplan position */
+				goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority)
+					/* Then perform the goto */
+					|| ast_parseable_goto(final_dest_chan, opt_args[OPT_ARG_CALLEE_GO_ON]);
+			} else { /* F() */
+				goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1);
+			}
+			if (goto_opt || ast_pbx_start(final_dest_chan)) {
+				ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
+			}
+		} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
+			ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
+				ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan),
+				ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan));
+
+			if (ast_pbx_start(final_dest_chan)) {
+				ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
+				ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
+			} else {
+				ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
+			}
+		} else {
+			ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
+		}
+	} else {
+		ast_debug(1, "chan %s was hungup\n", ast_channel_name(final_dest_chan));
+		ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
+	}
+done:
+	ast_free((char *) bconfig.warning_sound);
+	ast_free((char *) bconfig.end_sound);
+	ast_free((char *) bconfig.start_sound);
 
 	return 0;
 }
 
-static char *app_bridge = "Bridge";
+#if defined(TEST_FRAMEWORK)
+/*!
+ * \internal
+ * \brief Convert parking spaces map list to a comma separated string.
+ *
+ * \param str String buffer to fill.
+ * \param spaces Parking spaces map list to convert.
+ *
+ * \return Nothing
+ */
+static void create_spaces_str(struct ast_str **str, struct parking_dp_space_map *spaces)
+{
+	const char *comma;
+	struct parking_dp_spaces *cur;
+
+	ast_str_reset(*str);
+	comma = "";
+	AST_LIST_TRAVERSE(spaces, cur, node) {
+		if (cur->start == cur->stop) {
+			ast_str_append(str, 0, "%s%d", comma, cur->start);
+		} else {
+			ast_str_append(str, 0, "%s%d-%d", comma, cur->start, cur->stop);
+		}
+		comma = ",";
+	}
+}
+#endif	/* defined(TEST_FRAMEWORK) */
 
-enum {
-	BRIDGE_OPT_PLAYTONE = (1 << 0),
-	OPT_CALLEE_HANGUP =	(1 << 1),
-	OPT_CALLER_HANGUP =	(1 << 2),
-	OPT_DURATION_LIMIT = (1 << 3),
-	OPT_DURATION_STOP =	(1 << 4),
-	OPT_CALLEE_TRANSFER = (1 << 5),
-	OPT_CALLER_TRANSFER = (1 << 6),
-	OPT_CALLEE_MONITOR = (1 << 7),
-	OPT_CALLER_MONITOR = (1 << 8),
-	OPT_CALLEE_PARK = (1 << 9),
-	OPT_CALLER_PARK = (1 << 10),
-	OPT_CALLEE_KILL = (1 << 11),
-	OPT_CALLEE_GO_ON = (1 << 12),
+#if defined(TEST_FRAMEWORK)
+/*!
+ * \internal
+ * \brief Compare parking spaces map to what is expected.
+ *
+ * \param test Unit test context.
+ * \param spaces Parking spaces map list to check.
+ * \param expected String to compare with.
+ * \param what What is being compared.
+ *
+ * \retval 0 successful compare.
+ * \retval nonzero if failed to compare.
+ */
+static int check_spaces(struct ast_test *test, struct parking_dp_space_map *spaces, const char *expected, const char *what)
+{
+	int cmp;
+	struct ast_str *str = ast_str_alloca(1024);
+
+	create_spaces_str(&str, spaces);
+	cmp = strcmp(expected, ast_str_buffer(str));
+	if (cmp) {
+		ast_test_status_update(test,
+			"Unexpected parking space map for %s. Expect:'%s' Got:'%s'\n",
+			what, expected, ast_str_buffer(str));
+	}
+	return cmp;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+/*!
+ * \internal
+ * \brief Add a dead space to the dead spaces list.
+ *
+ * \param context Dead spaces list ptr pretending to be a context name ptr.
+ * \param space Dead space to add to the list.
+ *
+ * \return Nothing
+ */
+static void test_add_dead_space(const char *context, int space)
+{
+	struct parking_dp_space_map *dead_spaces = (struct parking_dp_space_map *) context;
+
+	usage_context_add_spaces(dead_spaces, space, space, NULL, 0);
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+struct test_map {
+	const char *ramp;
+	int start;
+	int stop;
+	const char *expect;
 };
 
-enum {
-	OPT_ARG_DURATION_LIMIT = 0,
-	OPT_ARG_DURATION_STOP,
-	OPT_ARG_CALLEE_GO_ON,
-	/* note: this entry _MUST_ be the last one in the enum */
-	OPT_ARG_ARRAY_SIZE,
+/*!
+ * \internal
+ * \brief Build a parking lot dialplan usage test map from a table.
+ *
+ * \param test Unit test context.
+ * \param lot Parking lot to use to build test usage map.
+ * \param table_name Name of passed in table.
+ * \param table Usage information to put in the usage map.
+ * \param num_entries Number of entries in the table.
+ *
+ * \retval Created context node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_context *test_build_maps(struct ast_test *test,
+	struct ast_parkinglot *lot, const char *table_name, const struct test_map *table,
+	size_t num_entries)
+{
+	struct parking_dp_context *ctx_node;
+	int cur_index = 0;
+	char what[40];
+
+	snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
+	ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
+	lot->cfg.parking_start = table->start;
+	lot->cfg.parking_stop = table->stop;
+	ctx_node = build_dialplan_useage_context(lot);
+	if (!ctx_node) {
+		ast_test_status_update(test, "Failed to create parking lot context map for %s\n",
+			what);
+		return NULL;
+	}
+	if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
+		destroy_dialplan_usage_context(ctx_node);
+		return NULL;
+	}
+	while (--num_entries) {
+		++cur_index;
+		++table;
+		snprintf(what, sizeof(what), "%s[%d]", table_name, cur_index);
+		ast_copy_string(lot->cfg.parkext, table->ramp, sizeof(lot->cfg.parkext));
+		lot->cfg.parking_start = table->start;
+		lot->cfg.parking_stop = table->stop;
+		if (dialplan_usage_add_parkinglot_data(ctx_node, lot, 1)) {
+			ast_test_status_update(test, "Failed to add parking lot data for %s\n", what);
+			destroy_dialplan_usage_context(ctx_node);
+			return NULL;
+		}
+		if (check_spaces(test, &ctx_node->spaces, table->expect, what)) {
+			destroy_dialplan_usage_context(ctx_node);
+			return NULL;
+		}
+	}
+	return ctx_node;
+}
+
+static const struct test_map test_old_ctx[] = {
+	/* The following order of building ctx is important to test adding items to the lists. */
+	{ "702", 14, 15, "14-15" },
+	{ "700", 10, 11, "10-11,14-15" },
+	{ "701", 18, 19, "10-11,14-15,18-19" },
+	{ "703", 12, 13, "10-15,18-19" },
+	{ "704", 16, 17, "10-19" },
+
+	/* Parking ramp and space conflicts are intended with these lines. */
+	{ "704", 9, 19, "9-19" },
+	{ "704", 9, 20, "9-20" },
+	{ "704", 8, 21, "8-21" },
+
+	/* Add more spaces to ctx to test removing dead parking spaces. */
+	{ "705", 23, 25, "8-21,23-25" },
+	{ "706", 28, 31, "8-21,23-25,28-31" },
+	{ "707", 33, 34, "8-21,23-25,28-31,33-34" },
+	{ "708", 38, 40, "8-21,23-25,28-31,33-34,38-40" },
+	{ "709", 42, 43, "8-21,23-25,28-31,33-34,38-40,42-43" },
 };
 
-AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
-	AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
-	AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
-	AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
-	AST_APP_OPTION('H', OPT_CALLER_HANGUP),
-	AST_APP_OPTION('k', OPT_CALLEE_PARK),
-	AST_APP_OPTION('K', OPT_CALLER_PARK),
-	AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
-	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
-	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
-	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
-	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
-	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
-	AST_APP_OPTION('x', OPT_CALLEE_KILL),
-END_OPTIONS );
+static const struct test_map test_new_ctx[] = {
+	{ "702", 4, 5, "4-5" },
+	{ "704", 24, 26, "4-5,24-26" },
+	{ "709", 29, 30, "4-5,24-26,29-30" },
+	{ "710", 32, 35, "4-5,24-26,29-30,32-35" },
+	{ "711", 37, 39, "4-5,24-26,29-30,32-35,37-39" },
+};
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+/*!
+ * \internal
+ * \brief Test parking dialplan usage map code.
+ *
+ * \param test Unit test context.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int test_dialplan_usage_map(struct ast_test *test)
+{
+	struct parking_dp_context *old_ctx;
+	struct parking_dp_context *new_ctx;
+	struct ast_parkinglot *lot;
+	struct parking_dp_spaces *spaces;
+	struct parking_dp_space_map dead_spaces = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
+	int res;
+
+	ast_test_status_update(test, "Test parking dialplan usage map code\n");
+
+	lot = create_parkinglot("test_lot");
+	if (!lot) {
+		return -1;
+	}
+	ast_copy_string(lot->cfg.parking_con, "test-ctx", sizeof(lot->cfg.parking_con));
+	lot->cfg.parkext_exclusive = 1;
+
+	ast_test_status_update(test,
+		"Build old_ctx map\n");
+	ast_log(LOG_NOTICE, "6 Ramp and space conflict warnings are expected.\n");
+	old_ctx = test_build_maps(test, lot, "test_old_ctx", test_old_ctx,
+		ARRAY_LEN(test_old_ctx));
+	if (!old_ctx) {
+		ao2_ref(lot, -1);
+		return -1;
+	}
+
+	ast_test_status_update(test, "Build new_ctx map\n");
+	new_ctx = test_build_maps(test, lot, "test_new_ctx", test_new_ctx,
+		ARRAY_LEN(test_new_ctx));
+	if (!new_ctx) {
+		res = -1;
+		goto fail_old_ctx;
+	}
+
+	ast_test_status_update(test, "Test removing dead parking spaces\n");
+	remove_dead_spaces_usage((void *) &dead_spaces, &old_ctx->spaces,
+		&new_ctx->spaces, test_add_dead_space);
+	if (check_spaces(test, &dead_spaces, "8-21,23,28,31,40,42-43", "dead_spaces")) {
+		res = -1;
+		goto fail_dead_spaces;
+	}
+
+	res = 0;
+
+fail_dead_spaces:
+	while ((spaces = AST_LIST_REMOVE_HEAD(&dead_spaces, node))) {
+		ast_free(spaces);
+	}
+	destroy_dialplan_usage_context(new_ctx);
+
+fail_old_ctx:
+	destroy_dialplan_usage_context(old_ctx);
+	ao2_ref(lot, -1);
+	return res;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
+{
+	return 0;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
+{
+	struct ast_channel *test_channel1;
+	struct ast_format tmp_fmt;
+
+	if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+		NULL, NULL, 0, 0, "TestChannel1"))) {
+		ast_log(LOG_WARNING, "Whoa, test channel creation failed.\n");
+		return NULL;
+	}
+
+	/* normally this is done in the channel driver */
+	ast_format_cap_add(ast_channel_nativeformats(test_channel1), ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
+
+	ast_format_set(ast_channel_writeformat(test_channel1), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_rawwriteformat(test_channel1), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_readformat(test_channel1), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_rawreadformat(test_channel1), AST_FORMAT_GSM, 0);
+
+	ast_channel_tech_set(test_channel1, fake_tech);
+
+	return test_channel1;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+static int unpark_test_channel(struct ast_channel *toremove, struct ast_park_call_args *args)
+{
+	struct ast_context *con;
+	struct parkeduser *pu_toremove;
+	int res = 0;
+
+	args->pu->notquiteyet = 1; /* go ahead and stop processing the test parking */
+
+	AST_LIST_LOCK(&args->pu->parkinglot->parkings);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
+		if (pu_toremove == args->pu) {
+			AST_LIST_REMOVE_CURRENT(list);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
+
+	if (!pu_toremove) {
+		ast_log(LOG_WARNING, "Whoa, could not find parking test call!\n");
+		return -1;
+	}
+
+	ast_wrlock_contexts();
+	con = ast_context_find(args->pu->parkinglot->cfg.parking_con);
+	if (con) {
+		res = ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 1);
+	}
+	ast_unlock_contexts();
+
+	if (con) {
+		if (res) {
+			ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+			res = -1;
+		} else {
+			notify_metermaids(args->pu->parkingexten,
+				pu_toremove->parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
+		}
+	} else {
+		ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+		res = -1;
+	}
 
-int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
-	char *parse, struct timeval *calldurationlimit)
+	parkinglot_unref(pu_toremove->parkinglot);
+	ast_free(pu_toremove);
+	args->pu = NULL;
+
+	if (!res && toremove) {
+		ast_hangup(toremove);
+	}
+	return res;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
+
+#if defined(TEST_FRAMEWORK)
+AST_TEST_DEFINE(features_test)
 {
-	char *stringp = ast_strdupa(parse);
-	char *limit_str, *warning_str, *warnfreq_str;
-	const char *var;
-	int play_to_caller = 0, play_to_callee = 0;
-	int delta;
+	struct ast_channel *test_channel1 = NULL;
+	struct ast_channel *parked_chan = NULL;
+	struct ast_parkinglot *dynlot;
+	struct ast_park_call_args args = {
+		.timeout = DEFAULT_PARK_TIME,
+	};
+
+	int res = 0;
+
+	static const struct ast_channel_tech fake_tech = {
+		.fixup = fake_fixup, /* silence warning from masquerade */
+	};
+
+	static const char unique_lot_1[] = "myuniquetestparkinglot314";
+	static const char unique_lot_2[] = "myuniquetestparkinglot3141592654";
+	static const char unique_context_1[] = "myuniquetestcontext314";
+	static const char unique_context_2[] = "myuniquetestcontext3141592654";
+	static const char parkinglot_parkext[] = "750";
+	static const char parkinglot_range[] = "751-760";
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "features_test";
+		info->category = "/main/features/";
+		info->summary = "Features unit test";
+		info->description =
+			"Tests whether parking respects PARKINGLOT settings";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
 
-	limit_str = strsep(&stringp, ":");
-	warning_str = strsep(&stringp, ":");
-	warnfreq_str = strsep(&stringp, ":");
+	if (test_dialplan_usage_map(test)) {
+		res = -1;
+		goto exit_features_test;
+	}
 
-	config->timelimit = atol(limit_str);
-	if (warning_str)
-		config->play_warning = atol(warning_str);
-	if (warnfreq_str)
-		config->warning_freq = atol(warnfreq_str);
+	/* changing a config option is a bad practice, but must be done in this case */
+	parkeddynamic = 1;
 
-	if (!config->timelimit) {
-		ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str);
-		config->timelimit = config->play_warning = config->warning_freq = 0;
-		config->warning_sound = NULL;
-		return -1; /* error */
-	} else if ( (delta = config->play_warning - config->timelimit) > 0) {
-		int w = config->warning_freq;
+	ast_test_status_update(test, "Test parking functionality with defaults\n");
+	if (!(test_channel1 = create_test_channel(&fake_tech))) {
+		res = -1;
+		goto exit_features_test;
+	}
+	if (park_call_full(test_channel1, NULL, &args)) {
+		res = -1;
+		goto exit_features_test;
+	}
+	if (unpark_test_channel(test_channel1, &args)) {
+		res = -1;
+		goto exit_features_test;
+	}
 
-		/*
-		 * If the first warning is requested _after_ the entire call
-		 * would end, and no warning frequency is requested, then turn
-		 * off the warning. If a warning frequency is requested, reduce
-		 * the 'first warning' time by that frequency until it falls
-		 * within the call's total time limit.
-		 *
-		 * Graphically:
-		 *                timelim->|    delta        |<-playwarning
-		 *      0__________________|_________________|
-		 *                       | w  |    |    |    |
-		 *
-		 * so the number of intervals to cut is 1+(delta-1)/w
-		 */
-		if (w == 0) {
-			config->play_warning = 0;
-		} else {
-			config->play_warning -= w * ( 1 + (delta-1)/w );
-			if (config->play_warning < 1)
-				config->play_warning = config->warning_freq = 0;
+
+	ast_test_status_update(test, "Check that certain parking options are respected\n");
+	if (!(test_channel1 = create_test_channel(&fake_tech))) {
+		res = -1;
+		goto exit_features_test;
+	}
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_1);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_1);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
+	if (park_call_full(test_channel1, NULL, &args)) {
+		res = -1;
+		goto exit_features_test;
+	}
+	/* grab newly created parking lot for destruction in the end */
+	dynlot = args.pu->parkinglot;
+	if (args.pu->parkingnum != 751
+		|| strcmp(dynlot->name, unique_lot_1)
+		|| strcmp(dynlot->cfg.parking_con, unique_context_1)
+		|| strcmp(dynlot->cfg.parkext, parkinglot_parkext)
+		|| dynlot->cfg.parking_start != 751
+		|| dynlot->cfg.parking_stop != 760) {
+		ast_test_status_update(test, "Parking settings were not respected\n");
+		ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
+		ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
+		ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
+		ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
+			dynlot->cfg.parking_stop);
+		ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
+		if (!unpark_test_channel(test_channel1, &args)) {
+			test_channel1 = NULL;
 		}
+		res = -1;
+		goto exit_features_test;
+	} else {
+		ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
+	}
+	if (unpark_test_channel(test_channel1, &args)) {
+		res = -1;
+		goto exit_features_test;
 	}
 
-	ast_channel_lock(chan);
 
-	var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
-	play_to_caller = var ? ast_true(var) : 1;
+	ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
+	if (!(test_channel1 = create_test_channel(&fake_tech))) {
+		res = -1;
+		goto exit_features_test;
+	}
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_lot_2);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_2);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
+	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
+	if (masq_park_call(test_channel1, NULL, &args)) {
+		res = -1;
+		goto exit_features_test;
+	}
+	/* hangup zombie channel */
+	ast_hangup(test_channel1);
+	test_channel1 = NULL;
+
+	dynlot = args.pu->parkinglot;
+	if (args.pu->parkingnum != 751
+		|| strcmp(dynlot->name, unique_lot_2)
+		|| strcmp(dynlot->cfg.parking_con, unique_context_2)
+		|| strcmp(dynlot->cfg.parkext, parkinglot_parkext)
+		|| dynlot->cfg.parking_start != 751
+		|| dynlot->cfg.parking_stop != 760) {
+		ast_test_status_update(test, "Parking settings were not respected\n");
+		ast_test_status_update(test, "Dyn-name:%s\n", dynlot->name);
+		ast_test_status_update(test, "Dyn-context:%s\n", dynlot->cfg.parking_con);
+		ast_test_status_update(test, "Dyn-parkext:%s\n", dynlot->cfg.parkext);
+		ast_test_status_update(test, "Dyn-parkpos:%d-%d\n", dynlot->cfg.parking_start,
+			dynlot->cfg.parking_stop);
+		ast_test_status_update(test, "Parked in space:%d\n", args.pu->parkingnum);
+		res = -1;
+	} else {
+		ast_test_status_update(test, "Parking settings for masquerading park verified\n");
+	}
 
-	var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
-	play_to_callee = var ? ast_true(var) : 0;
+	/* find the real channel */
+	parked_chan = ast_channel_get_by_name("TestChannel1");
+	if (unpark_test_channel(parked_chan, &args)) {
+		if (parked_chan) {
+			ast_hangup(parked_chan);
+		}
+		res = -1;
+	}
+	parked_chan = ast_channel_unref(parked_chan);
 
-	if (!play_to_caller && !play_to_callee)
-		play_to_caller = 1;
 
-	var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
-	config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
+exit_features_test:
 
-	/* The code looking at config wants a NULL, not just "", to decide
-	 * that the message should not be played, so we replace "" with NULL.
-	 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
-	 * not found.
-	 */
+	if (test_channel1) {
+		ast_hangup(test_channel1);
+	}
 
-	var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
-	config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
+	force_reload_load = 1;
+	ast_features_reload();
+	return res ? AST_TEST_FAIL : AST_TEST_PASS;
+}
+#endif	/* defined(TEST_FRAMEWORK) */
 
-	var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
-	config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
+/*!
+ * \internal
+ * \brief Get parkingtime for a channel
+ */
+static unsigned int get_parkingtime(struct ast_channel *chan, struct ast_parkinglot *parkinglot)
+{
+	const char *parkinglot_name;
+	struct feature_ds *feature_ds;
+	unsigned int parkingtime;
+
+	ast_channel_lock(chan);
+
+	feature_ds = get_feature_ds(chan);
+	if (feature_ds && feature_ds->parkingtime_is_set) {
+		parkingtime = feature_ds->parkingtime;
+		ast_channel_unlock(chan);
+		return parkingtime;
+	}
+
+	parkinglot_name = ast_strdupa(S_OR(ast_channel_parkinglot(chan), ""));
 
 	ast_channel_unlock(chan);
 
-	/* undo effect of S(x) in case they are both used */
-	calldurationlimit->tv_sec = 0;
-	calldurationlimit->tv_usec = 0;
+	if (!parkinglot) {
+		if (!ast_strlen_zero(parkinglot_name)) {
+			parkinglot = find_parkinglot(parkinglot_name);
+		}
 
-	/* more efficient to do it like S(x) does since no advanced opts */
-	if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
-		calldurationlimit->tv_sec = config->timelimit / 1000;
-		calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
-		ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
-			calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
-		play_to_caller = 0;
-		play_to_callee = 0;
-		config->timelimit = 0;
-		config->play_warning = 0;
-		config->warning_freq = 0;
+		if (!parkinglot) {
+			parkinglot = parkinglot_addref(default_parkinglot);
+		}
 	} else {
-		ast_verb(4, "Limit Data for this call:\n");
-		ast_verb(4, "timelimit      = %ld ms (%.3lf s)\n", config->timelimit, config->timelimit / 1000.0);
-		ast_verb(4, "play_warning   = %ld ms (%.3lf s)\n", config->play_warning, config->play_warning / 1000.0);
-		ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
-		ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
-		ast_verb(4, "warning_freq   = %ld ms (%.3lf s)\n", config->warning_freq, config->warning_freq / 1000.0);
-		ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
-		ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
-		ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
+		/* Just to balance the unref below */
+		parkinglot_addref(parkinglot);
 	}
-	if (play_to_caller)
-		ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
-	if (play_to_callee)
-		ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
-	return 0;
-}
 
+	parkingtime = parkinglot->cfg.parkingtime;
 
-/*!
- * \brief Bridge channels
- * \param chan
- * \param data channel to bridge with.
- *
- * Split data, check we aren't bridging with ourself, check valid channel,
- * answer call if not already, check compatible channels, setup bridge config
- * now bridge call, if transferred party hangs up return to PBX extension.
- */
-static int bridge_exec(struct ast_channel *chan, const char *data)
-{
-	struct ast_channel *current_dest_chan;
-	char *tmp_data  = NULL;
-	struct ast_flags opts = { 0, };
-	struct ast_bridge_config bconfig = { { 0, }, };
-	char *opt_args[OPT_ARG_ARRAY_SIZE];
-	struct timeval calldurationlimit = { 0, };
-	const char *context;
-	const char *extension;
-	int priority;
-	int bridge_add_failed;
-	struct ast_bridge_features chan_features;
-	struct ast_bridge_features *peer_features;
-	struct ast_bridge *bridge;
-	struct ast_features_xfer_config *xfer_cfg;
+	parkinglot_unref(parkinglot);
 
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(dest_chan);
-		AST_APP_ARG(options);
-	);
+	return parkingtime;
+}
 
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
+static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
+	       char *buf, size_t len)
+{
+	int res = 0;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
 		return -1;
 	}
 
-	tmp_data = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, tmp_data);
-	if (!ast_strlen_zero(args.options))
-		ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
+	if (!strcasecmp(data, "parkingtime")) {
+		snprintf(buf, len, "%u", get_parkingtime(chan, NULL) / 1000);
+	} else {
+		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
+		res = -1;
+	}
 
-	/* make sure we have a valid end point */
-	current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
-		strlen(args.dest_chan));
-	if (!current_dest_chan) {
-		ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
-			args.dest_chan);
-		return 0;
+	return res;
+}
+
+static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
+		const char *value)
+{
+	int res = 0;
+	struct feature_ds *feature_ds;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
 	}
 
-	/* avoid bridge with ourselves */
-	if (chan == current_dest_chan) {
-		ast_channel_unref(current_dest_chan);
-		ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
-		return 0;
+	ast_channel_lock(chan);
+
+	if (!(feature_ds = get_feature_ds(chan))) {
+		res = -1;
+		goto return_cleanup;
 	}
 
-	if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
-		&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
-		&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
-		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
-		goto done;
+	if (!strcasecmp(data, "parkingtime")) {
+		feature_ds->parkingtime_is_set = 1;
+		if (sscanf(value, "%30u", &feature_ds->parkingtime) == 1) {
+			feature_ds->parkingtime *= 1000; /* stored in ms */
+		} else {
+			ast_log(LOG_WARNING, "'%s' is not a valid parkingtime\n", value);
+			feature_ds->parkingtime_is_set = 0;
+			res = -1;
+		}
+	} else {
+		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
+		res = -1;
 	}
 
-	if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
-		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
-	if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
-		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
-	if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
-		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
-	if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
-		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
-	if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
-		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
-	if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
-		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
-	if (ast_test_flag(&opts, OPT_CALLEE_PARK))
-		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
-	if (ast_test_flag(&opts, OPT_CALLER_PARK))
-		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
+return_cleanup:
+	ast_channel_unlock(chan);
 
-	/* Setup after bridge goto location. */
-	if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
-		ast_channel_lock(chan);
-		context = ast_strdupa(ast_channel_context(chan));
-		extension = ast_strdupa(ast_channel_exten(chan));
-		priority = ast_channel_priority(chan);
-		ast_channel_unlock(chan);
-		ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority,
-			opt_args[OPT_ARG_CALLEE_GO_ON]);
-	} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
-		ast_channel_lock(current_dest_chan);
-		context = ast_strdupa(ast_channel_context(current_dest_chan));
-		extension = ast_strdupa(ast_channel_exten(current_dest_chan));
-		priority = ast_channel_priority(current_dest_chan);
-		ast_channel_unlock(current_dest_chan);
-		ast_bridge_set_after_goto(current_dest_chan, context, extension, priority);
-	}
-
-	if (ast_bridge_features_init(&chan_features)) {
-		ast_bridge_features_cleanup(&chan_features);
-		goto done;
-	}
+	return res;
+}
 
-	peer_features = ast_bridge_features_new();
-	if (!peer_features) {
-		ast_bridge_features_cleanup(&chan_features);
-		goto done;
+static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
+	       char *buf, size_t len)
+{
+	int res;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
 	}
 
-	if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		goto done;
+	ast_rdlock_call_features();
+
+	if ((res = builtin_feature_get_exten(chan, data, buf, len))) {
+		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
 	}
 
-	bridge = ast_bridge_basic_new();
-	if (!bridge) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		goto done;
+	ast_unlock_call_features();
+
+	return res;
+}
+
+static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
+		const char *value)
+{
+	struct feature_ds *feature_ds;
+	struct feature_exten *fe;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
 	}
 
-	xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan);
-	bridge_add_failed = ast_bridge_add_channel(bridge, current_dest_chan, peer_features,
-		ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE),
-		xfer_cfg ? xfer_cfg->xfersound : NULL);
-	ao2_cleanup(xfer_cfg);
-	if (bridge_add_failed) {
-		ast_bridge_features_destroy(peer_features);
-		ast_bridge_features_cleanup(&chan_features);
-		ast_bridge_destroy(bridge, 0);
-		goto done;
+	if (!ast_find_call_feature(data)) {
+		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
+		return -1;
 	}
 
-	/* Don't keep the channel ref in case it was not already in a bridge. */
-	current_dest_chan = ast_channel_unref(current_dest_chan);
+	ast_channel_lock(chan);
+
+	if (!(feature_ds = get_feature_ds(chan))) {
+		ast_channel_unlock(chan);
+		return -1;
+	}
 
-	ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
-		AST_BRIDGE_JOIN_PASS_REFERENCE);
+	if (!(fe = ao2_find(feature_ds->feature_map, data, OBJ_KEY))) {
+		if (!(fe = ao2_alloc(sizeof(*fe), NULL))) {
+			ast_channel_unlock(chan);
+			return -1;
+		}
+		ast_copy_string(fe->sname, data, sizeof(fe->sname));
+		ao2_link(feature_ds->feature_map, fe);
+	}
 
-	ast_bridge_features_cleanup(&chan_features);
+	ast_channel_unlock(chan);
 
-	/* The bridge has ended, set BRIDGERESULT to SUCCESS. */
-	pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
-done:
-	ast_free((char *) bconfig.warning_sound);
-	ast_free((char *) bconfig.end_sound);
-	ast_free((char *) bconfig.start_sound);
+	ao2_lock(fe);
+	ast_copy_string(fe->exten, value, sizeof(fe->exten));
+	ao2_unlock(fe);
+	ao2_ref(fe, -1);
+	fe = NULL;
 
-	ast_channel_cleanup(current_dest_chan);
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
+static struct ast_custom_function feature_function = {
+	.name = "FEATURE",
+	.read = feature_read,
+	.write = feature_write
+};
+
+static struct ast_custom_function featuremap_function = {
+	.name = "FEATUREMAP",
+	.read = featuremap_read,
+	.write = featuremap_write
+};
+
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void features_shutdown(void)
 {
-	ast_features_config_shutdown();
-
+	ast_cli_unregister_multiple(cli_features, ARRAY_LEN(cli_features));
+	ast_devstate_prov_del("Park");
+	ast_custom_function_unregister(&featuremap_function);
+	ast_custom_function_unregister(&feature_function);
 	ast_manager_unregister("Bridge");
-
+	ast_manager_unregister("Park");
+	ast_manager_unregister("Parkinglots");
+	ast_manager_unregister("ParkedCalls");
+	ast_unregister_application(parkcall);
+	ast_unregister_application(parkedcall);
 	ast_unregister_application(app_bridge);
-
+#if defined(TEST_FRAMEWORK)
+	AST_TEST_UNREGISTER(features_test);
+#endif	/* defined(TEST_FRAMEWORK) */
+
+	pthread_cancel(parking_thread);
+	pthread_kill(parking_thread, SIGURG);
+	pthread_join(parking_thread, NULL);
+	ast_context_destroy(NULL, registrar);
+	ao2_ref(parkinglots, -1);
 }
 
 int ast_features_init(void)
 {
 	int res;
 
-	res = ast_features_config_init();
-	if (res) {
-		return res;
+	parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
+	if (!parkinglots) {
+		return -1;
 	}
-	res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
-	res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
 
+	res = load_config(0);
 	if (res) {
-		features_shutdown();
-	} else {
-		ast_register_atexit(features_shutdown);
+		return res;
+	}
+	ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
+	if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) {
+		return -1;
+	}
+	ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
+	res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
+	if (!res)
+		res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
+	if (!res) {
+		ast_manager_register_xml_core("ParkedCalls", 0, manager_parking_status);
+		ast_manager_register_xml_core("Parkinglots", 0, manager_parkinglot_list);
+		ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
+		ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
 	}
+	res |= __ast_custom_function_register(&feature_function, NULL);
+	res |= __ast_custom_function_register(&featuremap_function, NULL);
+
+	res |= ast_devstate_prov_add("Park", metermaidstate);
+#if defined(TEST_FRAMEWORK)
+	res |= AST_TEST_REGISTER(features_test);
+#endif	/* defined(TEST_FRAMEWORK) */
+
+	ast_register_cleanup(features_shutdown);
 
 	return res;
 }
diff --git a/main/features_config.c b/main/features_config.c
deleted file mode 100644
index 9fed53b..0000000
--- a/main/features_config.c
+++ /dev/null
@@ -1,1980 +0,0 @@
-/*
-* Asterisk -- An open source telephony toolkit.
-*
-* Copyright (C) 2013, Digium, Inc.
-*
-* Mark Michelson <mmichelson at digium.com>
-*
-* See http://www.asterisk.org for more information about
-* the Asterisk project. Please do not directly contact
-* any of the maintainers of this project for assistance;
-* the project provides a web site, mailing lists and IRC
-* channels for your use.
-*
-* This program is free software, distributed under the terms of
-* the GNU General Public License Version 2. See the LICENSE file
-* at the top of the source tree.
-*/
-
-#include "asterisk.h"
-
-#include "asterisk/features_config.h"
-#include "asterisk/config_options.h"
-#include "asterisk/datastore.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/app.h"
-#include "asterisk/cli.h"
-
-/*** DOCUMENTATION
-	<configInfo name="features" language="en_US">
-		<synopsis>Features Configuration</synopsis>
-		<configFile name="features.conf">
-			<configObject name="globals">
-				<synopsis>
-				</synopsis>
-				<configOption name="featuredigittimeout" default="1000">
-					<synopsis>Milliseconds allowed between digit presses when entering a feature code.</synopsis>
-				</configOption>
-				<configOption name="courtesytone">
-					<synopsis>Sound to play when automon or automixmon is activated</synopsis>
-				</configOption>
-				<configOption name="recordingfailsound">
-					<synopsis>Sound to play when automon or automixmon is attempted but fails to start</synopsis>
-				</configOption>
-				<configOption name="transferdigittimeout" default="3">
-					<synopsis>Seconds allowed between digit presses when dialing a transfer destination</synopsis>
-				</configOption>
-				<configOption name="atxfernoanswertimeout" default="15">
-					<synopsis>Seconds to wait for attended transfer destination to answer</synopsis>
-				</configOption>
-				<configOption name="atxferdropcall" default="no">
-					<synopsis>Hang up the call entirely if the attended transfer fails</synopsis>
-					<description>
-						<para>When this option is set to <literal>no</literal>, then Asterisk will attempt to
-						re-call the transferrer if the call to the transfer target fails. If the call to the
-						transferrer fails, then Asterisk will wait <replaceable>atxferloopdelay</replaceable>
-						milliseconds and then attempt to dial the transfer target again. This process will
-						repeat until <replaceable>atxfercallbackretries</replaceable> attempts to re-call
-						the transferrer have occurred.</para>
-						<para>When this option is set to <literal>yes</literal>, then Asterisk will not attempt
-						to re-call the transferrer if the call to the transfer target fails. Asterisk will instead
-						hang up all channels involved in the transfer.</para>
-					</description>
-				</configOption>
-				<configOption name="atxferloopdelay" default="10">
-					<synopsis>Seconds to wait between attempts to re-dial transfer destination</synopsis>
-					<see-also><ref type="configOption">atxferdropcall</ref></see-also>
-				</configOption>
-				<configOption name="atxfercallbackretries" default="2">
-					<synopsis>Number of times to re-attempt dialing a transfer destination</synopsis>
-					<see-also><ref type="configOption">atxferdropcall</ref></see-also>
-				</configOption>
-				<configOption name="xfersound" default="beep">
-					<synopsis>Sound to play to during transfer and transfer-like operations.</synopsis>
-					<description>
-						<para>This sound will play to the transferrer and transfer target channels when
-						an attended transfer completes. This sound is also played to channels when performing
-						an AMI <literal>Bridge</literal> action.</para>
-					</description>
-				</configOption>
-				<configOption name="xferfailsound" default="beeperr">
-					<synopsis>Sound to play to a transferee when a transfer fails</synopsis>
-				</configOption>
-				<configOption name="atxferabort" default="*1">
-					<synopsis>Digits to dial to abort an attended transfer attempt</synopsis>
-					<description>
-						<para>This option is only available to the transferrer during an attended
-						transfer operation. Aborting a transfer results in the transfer being cancelled and
-						the original parties in the call being re-bridged.</para>
-					</description>
-				</configOption>
-				<configOption name="atxfercomplete" default="*2">
-					<synopsis>Digits to dial to complete an attended transfer</synopsis>
-					<description>
-						<para>This option is only available to the transferrer during an attended
-						transfer operation. Completing the transfer with a DTMF sequence is functionally
-						equivalent to hanging up the transferrer channel during an attended transfer. The
-						result is that the transfer target and transferees are bridged.</para>
-					</description>
-				</configOption>
-				<configOption name="atxferthreeway" default="*3">
-					<synopsis>Digits to dial to change an attended transfer into a three-way call</synopsis>
-					<description>
-						<para>This option is only available to the transferrer during an attended
-						transfer operation. Pressing this DTMF sequence will result in the transferrer,
-						the transferees, and the transfer target all being in a single bridge together.</para>
-					</description>
-				</configOption>
-				<configOption name="atxferswap" default="*4">
-					<synopsis>Digits to dial to toggle who the transferrer is currently bridged to during an attended transfer</synopsis>
-					<description>
-						<para>This option is only available to the transferrer during an attended
-						transfer operation. Pressing this DTMF sequence will result in the transferrer swapping
-						which party he is bridged with. For instance, if the transferrer is currently bridged with
-						the transfer target, then pressing this DTMF sequence will cause the transferrer to be
-						bridged with the transferees.</para>
-					</description>
-				</configOption>
-				<configOption name="pickupexten" default="*8">
-					<synopsis>Digits used for picking up ringing calls</synopsis>
-					<description>
-						<para>In order for the pickup attempt to be successful, the party attempting to
-						pick up the call must either have a <replaceable>namedpickupgroup</replaceable> in
-						common with a ringing party's <replaceable>namedcallgroup</replaceable> or must
-						have a <replaceable>pickupgroup</replaceable> in common with a ringing party's
-						<replaceable>callgroup</replaceable>.</para>
-					</description>
-				</configOption>
-				<configOption name="pickupsound">
-					<synopsis>Sound to play to picker when a call is picked up</synopsis>
-				</configOption>
-				<configOption name="pickupfailsound">
-					<synopsis>Sound to play to picker when a call cannot be picked up</synopsis>
-				</configOption>
-				<configOption name="transferdialattempts" default="3">
-					<synopsis>Number of dial attempts allowed when attempting a transfer</synopsis>
-				</configOption>
-				<configOption name="transferretrysound" default="pbx-invalid">
-					<synopsis>Sound that is played when an incorrect extension is dialed and the transferer should try again.</synopsis>
-				</configOption>
-				<configOption name="transferinvalidsound" default="privacy-incorrect">
-					<synopsis>Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining.</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="featuremap">
-				<synopsis>DTMF options that can be triggered during bridged calls</synopsis>
-				<configOption name="atxfer">
-					<synopsis>DTMF sequence to initiate an attended transfer</synopsis>
-					<description>
-						<para>The transferee parties will be placed on hold and the
-						transferrer may dial an extension to reach a transfer target. During an
-						attended transfer, the transferrer may consult with the transfer target
-						before completing the transfer. Once the transferrer has hung up or pressed
-						the <replaceable>atxfercomplete</replaceable> DTMF sequence, then the transferees
-						and transfer target will be bridged.</para>
-					</description>
-				</configOption>
-				<configOption name="blindxfer" default="#">
-					<synopsis>DTMF sequence to initiate a blind transfer</synopsis>
-					<description>
-						<para>The transferee parties will be placed on hold and the
-						transferrer may dial an extension to reach a transfer target. During a
-						blind transfer, as soon as the transfer target is dialed, the transferrer
-						is hung up.</para>
-					</description>
-				</configOption>
-				<configOption name="disconnect" default="*">
-					<synopsis>DTMF sequence to disconnect the current call</synopsis>
-					<description>
-						<para>Entering this DTMF sequence will cause the bridge to end, no
-						matter the number of parties present</para>
-					</description>
-				</configOption>
-				<configOption name="parkcall">
-					<synopsis>DTMF sequence to park a call</synopsis>
-					<description>
-						<para>The parking lot used to park the call is determined by using either the
-						<replaceable>PARKINGLOT</replaceable> channel variable or a configured value on
-						the channel (provided by the channel driver) if the variable is not present. If
-						no configured value on the channel is present, then <literal>"default"</literal>
-						is used. The call is parked in the next available space in the parking lot.</para>
-					</description>
-				</configOption>
-				<configOption name="automon">
-					<synopsis>DTMF sequence to start or stop monitoring a call</synopsis>
-					<description>
-						<para>This will cause the channel that pressed the DTMF sequence
-						to be monitored by the <literal>Monitor</literal> application. The
-						format for the recording is determined by the <replaceable>TOUCH_MONITOR_FORMAT</replaceable>
-						channel variable. If this variable is not specified, then <literal>wav</literal> is the
-						default. The filename is constructed in the following manner:</para>
-
-						<para>    prefix-timestamp-filename</para>
-
-						<para>where prefix is either the value of the <replaceable>TOUCH_MONITOR_PREFIX</replaceable>
-						channel variable or <literal>auto</literal> if the variable is not set. The timestamp
-						is a UNIX timestamp. The filename is either the value of the <replaceable>TOUCH_MONITOR</replaceable>
-						channel variable or the callerID of the channels if the variable is not set.</para>
-					</description>
-				</configOption>
-				<configOption name="automixmon">
-					<synopsis>DTMF sequence to start or stop mixmonitoring a call </synopsis>
-					<description>
-						<para>Operation of the automixmon is similar to the <literal> automon </literal>
-						feature, with the following exceptions:
-							<replaceable>TOUCH_MIXMONITOR</replaceable> is used in place of <replaceable>TOUCH_MONITOR</replaceable>
-							<replaceable>TOUCH_MIXMONITOR_FORMAT</replaceable> is used in place of <replaceable>TOUCH_MIXMONITOR</replaceable>
-							There is no equivalent for <replaceable>TOUCH_MONITOR_PREFIX</replaceable>. <literal>"auto"</literal> is always how the filename begins.</para>
-					</description>
-					<see-also><ref type="configOption">automon</ref></see-also>
-				</configOption>
-			</configObject>
-			<configObject name="applicationmap">
-				<synopsis>Section for defining custom feature invocations during a call</synopsis>
-				<description>
-					<para>The applicationmap is an area where new custom features can be created. Items
-					defined in the applicationmap are not automatically accessible to bridged parties. Access
-					to the individual items is controled using the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
-					The <replaceable>DYNAMIC_FEATURES</replaceable> is a <literal>#</literal> separated list of
-					either applicationmap item names or featuregroup names.</para>
-				</description>
-				<configOption name="^.*$" regex="true">
-					<synopsis>A custom feature to invoke during a bridged call</synopsis>
-					<description>
-						<para>Each item listed here is a comma-separated list of parameters that determine
-						how a feature may be invoked during a call</para>
-						<para>    Example:</para>
-						<para>    eggs = *5,self,Playback(hello-world),default</para>
-						<para>This would create a feature called <literal>eggs</literal> that could be invoked
-						during a call by pressing the <literal>*5</literal>. The party that presses the DTMF
-						sequence would then trigger the <literal>Playback</literal> application to play the
-						<literal>hello-world</literal> file. The application invocation would happen on the
-						party that pressed the DTMF sequence since <literal>self</literal> is specified. The
-						other parties in the bridge would hear the <literal>default</literal> music on hold
-						class during the playback.</para>
-						<para>In addition to the syntax outlined in this documentation, a backwards-compatible alternative
-						is also allowed. The following applicationmap lines are functionally identical:</para>
-						<para>    eggs = *5,self,Playback(hello-world),default</para>
-						<para>    eggs = *5,self,Playback,hello-world,default</para>
-						<para>    eggs = *5,self,Playback,"hello-world",default</para>
-					</description>
-					<syntax argsep=",">
-						<parameter name="dtmf" required="true">
-							<para>The DTMF sequence used to trigger the option</para>
-						</parameter>
-						<parameter name="activate_on" required="true">
-							<para>The party that the feature will be invoked on</para>
-							<optionlist>
-								<option name="self"><para>Feature is invoked on party that presses the DTMF sequence</para></option>
-								<option name="peer"><para>Feature is invoked on other parties in the bridge</para></option>
-							</optionlist>
-						</parameter>
-						<parameter name="app" required="true">
-							<para>The dialplan application to run when the DTMF sequence is pressed</para>
-							<argument name="app_args" required="false">
-								<para>The arguments to the dialplan application to run</para>
-							</argument>
-						</parameter>
-						<parameter name="moh_class" required="false">
-							<para>Music on hold class to play to bridge participants that are not the target of the application invocation</para>
-						</parameter>
-					</syntax>
-				</configOption>
-			</configObject>
-			<configObject name="featuregroup">
-				<synopsis>Groupings of items from the applicationmap</synopsis>
-				<description>
-					<para>Feature groups allow for multiple applicationmap items to be
-					grouped together. Like with individual applicationmap items, feature groups
-					can be part of the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
-					In addition to creating groupings, the feature group section allows for the
-					DTMF sequence used to invoke an applicationmap item to be overridden with
-					a different sequence.</para>
-				</description>
-				<configOption name="^.*$" regex="true">
-					<synopsis>Applicationmap item to place in the feature group</synopsis>
-					<description>
-						<para>Each item here must be a name of an item in the applicationmap. The
-						argument may either be a new DTMF sequence to use for the item or it
-						may be left blank in order to use the DTMF sequence specified in the
-						applicationmap. For example:</para>
-						<para>	eggs => *1</para>
-						<para>	bacon =></para>
-						<para>would result in the applicationmap items <literal>eggs</literal> and
-						<literal>bacon</literal> being in the featuregroup. The former would have its
-						default DTMF trigger overridden with <literal>*1</literal> and the latter would
-						have the DTMF value specified in the applicationmap.</para>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-	<function name="FEATURE" language="en_US">
-		<synopsis>
-			Get or set a feature option on a channel.
-		</synopsis>
-		<syntax>
-			<parameter name="option_name" required="true">
-				<para>The allowed values are:</para>
-				<enumlist>
-					<enum name="inherit"><para>Inherit feature settings made in FEATURE or FEATUREMAP to child channels.</para></enum>
-					<enum name="featuredigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='featuredigittimeout']/synopsis/text())" /></para></enum>
-					<enum name="transferdigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdigittimeout']/synopsis/text())" /></para></enum>
-					<enum name="atxfernoanswertimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfernoanswertimeout']/synopsis/text())" /></para></enum>
-					<enum name="atxferdropcall"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferdropcall']/synopsis/text())" /></para></enum>
-					<enum name="atxferloopdelay"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferloopdelay']/synopsis/text())" /></para></enum>
-					<enum name="atxfercallbackretries"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercallbackretries']/synopsis/text())" /></para></enum>
-					<enum name="xfersound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xfersound']/synopsis/text())" /></para></enum>
-					<enum name="xferfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xferfailsound']/synopsis/text())" /></para></enum>
-					<enum name="atxferabort"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferabort']/synopsis/text())" /></para></enum>
-					<enum name="atxfercomplete"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercomplete']/synopsis/text())" /></para></enum>
-					<enum name="atxferthreeway"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferthreeway']/synopsis/text())" /></para></enum>
-					<enum name="pickupexten"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupexten']/synopsis/text())" /></para></enum>
-					<enum name="pickupsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupsound']/synopsis/text())" /></para></enum>
-					<enum name="pickupfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupfailsound']/synopsis/text())" /></para></enum>
-					<enum name="courtesytone"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='courtesytone']/synopsis/text())" /></para></enum>
-					<enum name="recordingfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='recordingfailsound']/synopsis/text())" /></para></enum>
-					<enum name="transferdialattempts"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdialattempts']/synopsis/text())" /></para></enum>
-					<enum name="transferretrysound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferretrysound']/synopsis/text())" /></para></enum>
-					<enum name="transferinvalidsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferinvalidsound']/synopsis/text())" /></para></enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>When this function is used as a read, it will get the current
-			value of the specified feature option for this channel.  It will be
-			the value of this option configured in features.conf if a channel specific
-			value has not been set.  This function can also be used to set a channel
-			specific value for the supported feature options.</para>
-		</description>
-		<see-also>
-			<ref type="function">FEATUREMAP</ref>
-		</see-also>
-	</function>
-	<function name="FEATUREMAP" language="en_US">
-		<synopsis>
-			Get or set a feature map to a given value on a specific channel.
-		</synopsis>
-		<syntax>
-			<parameter name="feature_name" required="true">
-				<para>The allowed values are:</para>
-				<enumlist>
-					<enum name="atxfer"><para>Attended Transfer</para></enum>
-					<enum name="blindxfer"><para>Blind Transfer</para></enum>
-					<enum name="automon"><para>Auto Monitor</para></enum>
-					<enum name="disconnect"><para>Call Disconnect</para></enum>
-					<enum name="parkcall"><para>Park Call</para></enum>
-					<enum name="automixmon"><para>Auto MixMonitor</para></enum>
-				</enumlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>When this function is used as a read, it will get the current
-			digit sequence mapped to the specified feature for this channel.  This
-			value will be the one configured in features.conf if a channel specific
-			value has not been set.  This function can also be used to set a channel
-			specific value for a feature mapping.</para>
-		</description>
-		<see-also>
-			<ref type="function">FEATURE</ref>
-		</see-also>
-	</function>
- ***/
-/*! Default general options */
-#define DEFAULT_FEATURE_DIGIT_TIMEOUT               1000
-#define DEFAULT_COURTESY_TONE                       ""
-#define DEFAULT_RECORDING_FAIL_SOUND                ""
-
-/*! Default xfer options */
-#define DEFAULT_TRANSFER_DIGIT_TIMEOUT              3
-#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER  15
-#define DEFAULT_ATXFER_DROP_CALL                    0
-#define DEFAULT_ATXFER_LOOP_DELAY                   10
-#define DEFAULT_ATXFER_CALLBACK_RETRIES             2
-#define DEFAULT_XFERSOUND                           "beep"
-#define DEFAULT_XFERFAILSOUND                       "beeperr"
-#define DEFAULT_ATXFER_ABORT                        "*1"
-#define DEFAULT_ATXFER_COMPLETE                     "*2"
-#define DEFAULT_ATXFER_THREEWAY                     "*3"
-#define DEFAULT_ATXFER_SWAP                         "*4"
-#define DEFAULT_TRANSFER_DIAL_ATTEMPTS              1
-#define DEFAULT_TRANSFER_RETRY_SOUND                "pbx-invalid"
-#define DEFAULT_TRANSFER_INVALID_SOUND              "pbx-invalid"
-
-/*! Default pickup options */
-#define DEFAULT_PICKUPEXTEN                         "*8"
-#define DEFAULT_PICKUPSOUND                         ""
-#define DEFAULT_PICKUPFAILSOUND                     ""
-
-/*! Default featuremap options */
-#define DEFAULT_FEATUREMAP_BLINDXFER                "#"
-#define DEFAULT_FEATUREMAP_DISCONNECT               "*"
-#define DEFAULT_FEATUREMAP_AUTOMON                  ""
-#define DEFAULT_FEATUREMAP_ATXFER                   ""
-#define DEFAULT_FEATUREMAP_PARKCALL                 ""
-#define DEFAULT_FEATUREMAP_AUTOMIXMON               ""
-
-/*!
- * \brief Configuration from the "general" section of features.conf
- */
-struct features_global_config {
-	struct ast_features_general_config *general;
-	struct ast_features_xfer_config *xfer;
-	struct ast_features_pickup_config *pickup;
-};
-
-static void ast_applicationmap_item_destructor(void *obj)
-{
-	struct ast_applicationmap_item *item = obj;
-
-	ast_string_field_free_memory(item);
-}
-
-static int applicationmap_sort(const void *obj, const void *arg, int flags)
-{
-	const struct ast_applicationmap_item *item1 = obj;
-	const struct ast_applicationmap_item *item2;
-	const char *key2;
-
-	switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key2 = arg;
-		return strcasecmp(item1->name, key2);
-	case OBJ_PARTIAL_KEY:
-		key2 = arg;
-		return strncasecmp(item1->name, key2, strlen(key2));
-	default:
-	case OBJ_POINTER:
-		item2 = arg;
-		return strcasecmp(item1->name, item2->name);
-	}
-}
-
-/*!
- * \brief Entry in the container of featuregroups
- */
-struct featuregroup_item {
-	AST_DECLARE_STRING_FIELDS(
-		/*! The name of the applicationmap item that we are referring to */
-		AST_STRING_FIELD(appmap_item_name);
-		/*! Custom DTMF override to use instead of the default for the applicationmap item */
-		AST_STRING_FIELD(dtmf_override);
-	);
-	/*! The applicationmap item that is being referred to */
-	struct ast_applicationmap_item *appmap_item;
-};
-
-static void featuregroup_item_destructor(void *obj)
-{
-	struct featuregroup_item *item = obj;
-
-	ast_string_field_free_memory(item);
-	ao2_cleanup(item->appmap_item);
-}
-
-static int group_item_sort(const void *obj, const void *arg, int flags)
-{
-	const struct featuregroup_item *item1 = obj;
-	const struct featuregroup_item *item2;
-	const char *key2;
-
-	switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key2 = arg;
-		return strcasecmp(item1->appmap_item_name, key2);
-	case OBJ_PARTIAL_KEY:
-		key2 = arg;
-		return strncasecmp(item1->appmap_item_name, key2, strlen(key2));
-	case OBJ_POINTER:
-		item2 = arg;
-		return strcasecmp(item1->appmap_item_name, item2->appmap_item_name);
-	default:
-		return CMP_STOP;
-	}
-}
-
-/*!
- * \brief Featuregroup representation
- */
-struct featuregroup {
-	/*! The name of the featuregroup */
-	const char *name;
-	/*! A container of featuregroup_items */
-	struct ao2_container *items;
-};
-
-static int featuregroup_hash(const void *obj, int flags)
-{
-	const struct featuregroup *group;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return ast_str_case_hash(key);
-	case OBJ_PARTIAL_KEY:
-		ast_assert(0);
-		return 0;
-	case OBJ_POINTER:
-	default:
-		group = obj;
-		return ast_str_case_hash(group->name);
-	}
-}
-
-static int featuregroup_cmp(void *obj, void *arg, int flags)
-{
-	struct featuregroup *group1 = obj;
-	struct featuregroup *group2;
-	const char *key2;
-
-	switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key2 = arg;
-		return strcasecmp(group1->name, key2) ? 0 : CMP_MATCH;
-	case OBJ_PARTIAL_KEY:
-		key2 = arg;
-		return strncasecmp(group1->name, key2, strlen(key2)) ? 0 : CMP_MATCH;
-	case OBJ_POINTER:
-		group2 = arg;
-		return strcasecmp(group1->name, group2->name) ? 0 : CMP_MATCH;
-	default:
-		return CMP_STOP;
-	}
-}
-
-static void *featuregroup_find(struct ao2_container *group_container, const char *category)
-{
-	return ao2_find(group_container, category, OBJ_KEY);
-}
-
-static void featuregroup_destructor(void *obj)
-{
-	struct featuregroup *group = obj;
-
-	ast_free((char *) group->name);
-	ao2_cleanup(group->items);
-}
-
-static void *featuregroup_alloc(const char *cat)
-{
-	struct featuregroup *group;
-
-	group = ao2_alloc(sizeof(*group), featuregroup_destructor);
-	if (!group) {
-		return NULL;
-	}
-
-	group->name = ast_strdup(cat);
-	if (!group->name) {
-		ao2_cleanup(group);
-		return NULL;
-	}
-
-	group->items = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, group_item_sort, NULL);
-	if (!group->items) {
-		ao2_cleanup(group);
-		return NULL;
-	}
-
-	return group;
-}
-
-/* Used for deprecated parking configuration */
-struct dummy_config {
-	char dummy;
-};
-
-struct features_config {
-	struct features_global_config *global;
-	struct ast_featuremap_config *featuremap;
-	struct dummy_config *parkinglots;
-	struct ao2_container *applicationmap;
-	struct ao2_container *featuregroups;
-};
-
-static struct aco_type global_option = {
-	.type = ACO_GLOBAL,
-	.name = "globals",
-	.category_match = ACO_WHITELIST,
-	.category = "^general$",
-	.item_offset = offsetof(struct features_config, global),
-};
-
-static struct aco_type featuremap_option = {
-	.type = ACO_GLOBAL,
-	.name = "featuremap",
-	.category_match = ACO_WHITELIST,
-	.category = "^featuremap$",
-	.item_offset = offsetof(struct features_config, featuremap),
-};
-
-static struct aco_type applicationmap_option = {
-	.type = ACO_GLOBAL,
-	.name = "applicationmap",
-	.category_match = ACO_WHITELIST,
-	.category = "^applicationmap$",
-	.item_offset = offsetof(struct features_config, applicationmap),
-};
-
-static struct aco_type featuregroup_option = {
-	.type = ACO_ITEM,
-	.name = "featuregroup",
-	.category_match = ACO_BLACKLIST,
-	.category = "^(general|featuremap|applicationmap|parkinglot_.*)$",
-	.item_offset = offsetof(struct features_config, featuregroups),
-	.item_alloc = featuregroup_alloc,
-	.item_find = featuregroup_find,
-};
-
-static struct aco_type parkinglot_option = {
-	.type = ACO_GLOBAL,
-	.name = "parkinglot",
-	.category_match = ACO_WHITELIST,
-	.category = "^parkinglot_.*$",
-	.item_offset = offsetof(struct features_config, parkinglots),
-	.hidden = 1,
-};
-
-static struct aco_type *global_options[] = ACO_TYPES(&global_option);
-static struct aco_type *featuremap_options[] = ACO_TYPES(&featuremap_option);
-static struct aco_type *applicationmap_options[] = ACO_TYPES(&applicationmap_option);
-static struct aco_type *featuregroup_options[] = ACO_TYPES(&featuregroup_option);
-static struct aco_type *parkinglot_options[] = ACO_TYPES(&parkinglot_option);
-
-static struct aco_file features_conf = {
-	.filename = "features.conf",
-	.types = ACO_TYPES(&global_option, &featuremap_option, &applicationmap_option, &featuregroup_option, &parkinglot_option),
-};
-
-AO2_GLOBAL_OBJ_STATIC(globals);
-
-static void features_config_destructor(void *obj)
-{
-	struct features_config *cfg = obj;
-
-	ao2_cleanup(cfg->global);
-	ao2_cleanup(cfg->featuremap);
-	ao2_cleanup(cfg->parkinglots);
-	ao2_cleanup(cfg->applicationmap);
-	ao2_cleanup(cfg->featuregroups);
-}
-
-static void featuremap_config_destructor(void *obj)
-{
-	struct ast_featuremap_config *cfg = obj;
-
-	ast_string_field_free_memory(cfg);
-}
-
-static void global_config_destructor(void *obj)
-{
-	struct features_global_config *cfg = obj;
-
-	ao2_cleanup(cfg->general);
-	ao2_cleanup(cfg->xfer);
-	ao2_cleanup(cfg->pickup);
-}
-
-static void general_destructor(void *obj)
-{
-	struct ast_features_general_config *cfg = obj;
-
-	ast_string_field_free_memory(cfg);
-}
-
-static void xfer_destructor(void *obj)
-{
-	struct ast_features_xfer_config *cfg = obj;
-
-	ast_string_field_free_memory(cfg);
-}
-
-static void pickup_destructor(void *obj)
-{
-	struct ast_features_pickup_config *cfg = obj;
-
-	ast_string_field_free_memory(cfg);
-}
-
-static struct features_global_config *global_config_alloc(void)
-{
-	RAII_VAR(struct features_global_config *, cfg, NULL, ao2_cleanup);
-
-	cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
-	if (!cfg) {
-		return NULL;
-	}
-
-	cfg->general = ao2_alloc(sizeof(*cfg->general), general_destructor);
-	if (!cfg->general || ast_string_field_init(cfg->general, 32)) {
-		return NULL;
-	}
-
-	cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
-	if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
-		return NULL;
-	}
-
-	cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
-	if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
-		return NULL;
-	}
-
-	ao2_ref(cfg, +1);
-	return cfg;
-}
-
-static struct ao2_container *applicationmap_alloc(int replace_duplicates)
-{
-	return ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		replace_duplicates ? AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE : AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW,
-		applicationmap_sort, NULL);
-}
-
-/*!
- * \internal
- * \brief Allocate the major configuration structure
- *
- * The parameter is used to determine if the applicationmap and featuregroup
- * structures should be allocated. We only want to allocate these structures for
- * the global features_config structure. For the datastores on channels, we don't
- * need to allocate these structures because they are not used.
- *
- * \param allocate_applicationmap See previous explanation
- * \retval NULL Failed to alloate configuration
- * \retval non-NULL Allocated configuration
- */
-static struct features_config *__features_config_alloc(int allocate_applicationmap)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
-	if (!cfg) {
-		return NULL;
-	}
-
-	cfg->global = global_config_alloc();
-	if (!cfg->global) {
-		return NULL;
-	}
-
-	cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
-	if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
-		return NULL;
-	}
-
-	cfg->parkinglots = ao2_alloc(sizeof(*cfg->parkinglots), NULL);
-	if (!cfg->parkinglots) {
-		return NULL;
-	}
-
-	if (allocate_applicationmap) {
-		cfg->applicationmap = applicationmap_alloc(1);
-		if (!cfg->applicationmap) {
-			return NULL;
-		}
-
-		cfg->featuregroups = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 11, featuregroup_hash,
-			featuregroup_cmp);
-		if (!cfg->featuregroups) {
-			return NULL;
-		}
-	}
-
-	ao2_ref(cfg, +1);
-	return cfg;
-
-}
-
-static void *features_config_alloc(void)
-{
-	return __features_config_alloc(1);
-}
-
-static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
-{
-	ast_string_fields_copy(dest, src);
-	dest->featuredigittimeout = src->featuredigittimeout;
-}
-
-static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
-{
-	ast_string_fields_copy(dest, src);
-	dest->transferdigittimeout = src->transferdigittimeout;
-	dest->atxfernoanswertimeout = src->atxfernoanswertimeout;
-	dest->atxferloopdelay = src->atxferloopdelay;
-	dest->atxfercallbackretries = src->atxfercallbackretries;
-	dest->atxferdropcall = src->atxferdropcall;
-	dest->transferdialattempts = src->transferdialattempts;
-}
-
-static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
-{
-	ast_string_fields_copy(dest, src);
-}
-
-static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
-{
-	general_copy(dest->general, src->general);
-	xfer_copy(dest->xfer, src->xfer);
-	pickup_copy(dest->pickup, src->pickup);
-}
-
-static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
-{
-	ast_string_fields_copy(dest, src);
-}
-
-static void features_copy(struct features_config *dest, const struct features_config *src)
-{
-	global_copy(dest->global, src->global);
-	featuremap_copy(dest->featuremap, src->featuremap);
-
-	/* applicationmap and featuregroups are purposely not copied. A channel's applicationmap
-	 * is produced on the fly when ast_get_chan_applicationmap() is called
-	 * NOTE: This does not apply to the global cfg->applicationmap and cfg->featuresgroups
-	 */
-}
-
-static struct features_config *features_config_dup(const struct features_config *orig)
-{
-	struct features_config *dup;
-
-	dup = __features_config_alloc(0);
-	if (!dup) {
-		return NULL;
-	}
-
-	features_copy(dup, orig);
-
-	return dup;
-}
-
-static int general_set(struct ast_features_general_config *general, const char *name,
-		const char *value)
-{
-	int res = 0;
-
-	if (!strcasecmp(name, "featuredigittimeout")) {
-		res = ast_parse_arg(value, PARSE_INT32, &general->featuredigittimeout);
-	} else if (!strcasecmp(name, "courtesytone")) {
-		ast_string_field_set(general, courtesytone, value);
-	} else if (!strcasecmp(name, "recordingfailsound")) {
-		ast_string_field_set(general, recordingfailsound, value);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int general_get(struct ast_features_general_config *general, const char *field,
-		char *buf, size_t len)
-{
-	int res = 0;
-
-	if (!strcasecmp(field, "featuredigittimeout")) {
-		snprintf(buf, len, "%u", general->featuredigittimeout);
-	} else if (!strcasecmp(field, "courtesytone")) {
-		ast_copy_string(buf, general->courtesytone, len);
-	} else if (!strcasecmp(field, "recordingfailsound")) {
-		ast_copy_string(buf, general->recordingfailsound, len);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
-		const char *value)
-{
-	int res = 0;
-
-	if (!strcasecmp(name, "transferdigittimeout")) {
-		res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdigittimeout);
-	} else if (!strcasecmp(name, "atxfernoanswertimeout")) {
-		res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfernoanswertimeout);
-	} else if (!strcasecmp(name, "atxferloopdelay")) {
-		res = ast_parse_arg(value, PARSE_INT32, &xfer->atxferloopdelay);
-	} else if (!strcasecmp(name, "atxfercallbackretries")) {
-		res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfercallbackretries);
-	} else if (!strcasecmp(name, "atxferdropcall")) {
-		xfer->atxferdropcall = ast_true(value);
-	} else if (!strcasecmp(name, "xfersound")) {
-		ast_string_field_set(xfer, xfersound, value);
-	} else if (!strcasecmp(name, "xferfailsound")) {
-		ast_string_field_set(xfer, xferfailsound, value);
-	} else if (!strcasecmp(name, "atxferabort")) {
-		ast_string_field_set(xfer, atxferabort, value);
-	} else if (!strcasecmp(name, "atxfercomplete")) {
-		ast_string_field_set(xfer, atxfercomplete, value);
-	} else if (!strcasecmp(name, "atxferthreeway")) {
-		ast_string_field_set(xfer, atxferthreeway, value);
-	} else if (!strcasecmp(name, "atxferswap")) {
-		ast_string_field_set(xfer, atxferswap, value);
-	} else if (!strcasecmp(name, "transferdialattempts")) {
-		res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdialattempts);
-	} else if (!strcasecmp(name, "transferretrysound")) {
-		ast_string_field_set(xfer, transferretrysound, value);
-	} else if (!strcasecmp(name, "transferinvalidsound")) {
-		ast_string_field_set(xfer, transferinvalidsound, value);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
-		char *buf, size_t len)
-{
-	int res = 0;
-
-	if (!strcasecmp(field, "transferdigittimeout")) {
-		snprintf(buf, len, "%u", xfer->transferdigittimeout);
-	} else if (!strcasecmp(field, "atxfernoanswertimeout")) {
-		snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
-	} else if (!strcasecmp(field, "atxferloopdelay")) {
-		snprintf(buf, len, "%u", xfer->atxferloopdelay);
-	} else if (!strcasecmp(field, "atxfercallbackretries")) {
-		snprintf(buf, len, "%u", xfer->atxfercallbackretries);
-	} else if (!strcasecmp(field, "atxferdropcall")) {
-		snprintf(buf, len, "%u", xfer->atxferdropcall);
-	} else if (!strcasecmp(field, "xfersound")) {
-		ast_copy_string(buf, xfer->xfersound, len);
-	} else if (!strcasecmp(field, "xferfailsound")) {
-		ast_copy_string(buf, xfer->xferfailsound, len);
-	} else if (!strcasecmp(field, "atxferabort")) {
-		ast_copy_string(buf, xfer->atxferabort, len);
-	} else if (!strcasecmp(field, "atxfercomplete")) {
-		ast_copy_string(buf, xfer->atxfercomplete, len);
-	} else if (!strcasecmp(field, "atxferthreeway")) {
-		ast_copy_string(buf, xfer->atxferthreeway, len);
-	} else if (!strcasecmp(field, "atxferswap")) {
-		ast_copy_string(buf, xfer->atxferswap, len);
-	} else if (!strcasecmp(field, "transferdialattempts")) {
-		snprintf(buf, len, "%u", xfer->transferdialattempts);
-	} else if (!strcasecmp(field, "transferretrysound")) {
-		ast_copy_string(buf, xfer->transferretrysound, len);
-	} else if (!strcasecmp(field, "transferinvalidsound")) {
-		ast_copy_string(buf, xfer->transferinvalidsound, len);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
-		const char *value)
-{
-	int res = 0;
-
-	if (!strcasecmp(name, "pickupsound")) {
-		ast_string_field_set(pickup, pickupsound, value);
-	} else if (!strcasecmp(name, "pickupfailsound")) {
-		ast_string_field_set(pickup, pickupfailsound, value);
-	} else if (!strcasecmp(name, "pickupexten")) {
-		ast_string_field_set(pickup, pickupexten, value);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
-		char *buf, size_t len)
-{
-	int res = 0;
-
-	if (!strcasecmp(field, "pickupsound")) {
-		ast_copy_string(buf, pickup->pickupsound, len);
-	} else if (!strcasecmp(field, "pickupfailsound")) {
-		ast_copy_string(buf, pickup->pickupfailsound, len);
-	} else if (!strcasecmp(field, "pickupexten")) {
-		ast_copy_string(buf, pickup->pickupexten, len);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name,
-		const char *value)
-{
-	int res = 0;
-
-	if (!strcasecmp(name, "blindxfer")) {
-		ast_string_field_set(featuremap, blindxfer, value);
-	} else if (!strcasecmp(name, "disconnect")) {
-		ast_string_field_set(featuremap, disconnect, value);
-	} else if (!strcasecmp(name, "automon")) {
-		ast_string_field_set(featuremap, automon, value);
-	} else if (!strcasecmp(name, "atxfer")) {
-		ast_string_field_set(featuremap, atxfer, value);
-	} else if (!strcasecmp(name, "automixmon")) {
-		ast_string_field_set(featuremap, automixmon, value);
-	} else if (!strcasecmp(name, "parkcall")) {
-		ast_string_field_set(featuremap, parkcall, value);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field,
-		char *buf, size_t len)
-{
-	int res = 0;
-
-	if (!strcasecmp(field, "blindxfer")) {
-		ast_copy_string(buf, featuremap->blindxfer, len);
-	} else if (!strcasecmp(field, "disconnect")) {
-		ast_copy_string(buf, featuremap->disconnect, len);
-	} else if (!strcasecmp(field, "automon")) {
-		ast_copy_string(buf, featuremap->automon, len);
-	} else if (!strcasecmp(field, "atxfer")) {
-		ast_copy_string(buf, featuremap->atxfer, len);
-	} else if (!strcasecmp(field, "automixmon")) {
-		ast_copy_string(buf, featuremap->automixmon, len);
-	} else if (!strcasecmp(field, "parkcall")) {
-		ast_copy_string(buf, featuremap->parkcall, len);
-	} else {
-		/* Unrecognized option */
-		res = -1;
-	}
-
-	return res;
-}
-
-static void feature_ds_destroy(void *data)
-{
-	struct features_config *cfg = data;
-	ao2_cleanup(cfg);
-}
-
-static void *feature_ds_duplicate(void *data)
-{
-	struct features_config *old_cfg = data;
-
-	return features_config_dup(old_cfg);
-}
-
-static const struct ast_datastore_info feature_ds_info = {
-	.type = "FEATURE",
-	.destroy = feature_ds_destroy,
-	.duplicate = feature_ds_duplicate,
-};
-
-/*!
- * \internal
- * \brief Find or create feature datastore on a channel
- *
- * \pre chan is locked
- *
- * \return the data on the FEATURE datastore, or NULL on error
- */
-static struct features_config *get_feature_ds(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
-	struct features_config *cfg;
-	struct ast_datastore *ds;
-
-	if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
-		cfg = ds->data;
-		ao2_ref(cfg, +1);
-		return cfg;
-	}
-
-	orig = ao2_global_obj_ref(globals);
-	if (!orig) {
-		return NULL;
-	}
-
-	cfg = features_config_dup(orig);
-	if (!cfg) {
-		return NULL;
-	}
-
-	if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
-		ao2_cleanup(cfg);
-		return NULL;
-	}
-
-	/* Give the datastore a reference to the config */
-	ao2_ref(cfg, +1);
-	ds->data = cfg;
-
-	ast_channel_datastore_add(chan, ds);
-
-	return cfg;
-}
-
-static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
-{
-	struct ast_datastore *ds;
-
-	if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
-		/* Hasn't been created yet.  Trigger creation. */
-		ao2_cleanup(get_feature_ds(chan));
-
-		ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
-	}
-
-	return ds;
-}
-
-struct ast_features_general_config *ast_get_chan_features_general_config(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	if (chan) {
-		cfg = get_feature_ds(chan);
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-	}
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	ast_assert(cfg->global && cfg->global->general);
-
-	ao2_ref(cfg->global->general, +1);
-	return cfg->global->general;
-}
-
-struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	if (chan) {
-		cfg = get_feature_ds(chan);
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-	}
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	ast_assert(cfg->global && cfg->global->xfer);
-
-	ao2_ref(cfg->global->xfer, +1);
-	return cfg->global->xfer;
-}
-
-struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	if (chan) {
-		cfg = get_feature_ds(chan);
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-	}
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	ast_assert(cfg->global && cfg->global->pickup);
-
-	ao2_ref(cfg->global->pickup, +1);
-	return cfg->global->pickup;
-}
-
-struct ast_featuremap_config *ast_get_chan_featuremap_config(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	if (chan) {
-		cfg = get_feature_ds(chan);
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-	}
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	ast_assert(cfg->featuremap != NULL);
-
-	ao2_ref(cfg->featuremap, +1);
-	return cfg->featuremap;
-}
-
-int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	if (chan) {
-		cfg = get_feature_ds(chan);
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-	}
-
-	if (!cfg) {
-		return -1;
-	}
-
-	return featuremap_get(cfg->featuremap, feature, buf, len);
-}
-
-int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
-{
-	RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
-
-	if (!ast_get_builtin_feature(chan, feature, buf, len)) {
-		return 0;
-	}
-
-	/* Dang, must be in the application map */
-	applicationmap = ast_get_chan_applicationmap(chan);
-	if (!applicationmap) {
-		return -1;
-	}
-
-	item = ao2_find(applicationmap, feature, OBJ_KEY);
-	if (!item) {
-		return -1;
-	}
-
-	ast_copy_string(buf, item->dtmf, len);
-	return 0;
-}
-
-static struct ast_applicationmap_item *applicationmap_item_alloc(const char *name,
-		const char *app, const char *app_data, const char *moh_class, const char *dtmf,
-		unsigned int activate_on_self)
-{
-	struct ast_applicationmap_item *item;
-
-	item = ao2_alloc(sizeof(*item), ast_applicationmap_item_destructor);
-
-	if (!item || ast_string_field_init(item, 64)) {
-		return NULL;
-	}
-
-	ast_string_field_set(item, name, name);
-	ast_string_field_set(item, app, app);
-	ast_string_field_set(item, app_data, app_data);
-	ast_string_field_set(item, moh_class, moh_class);
-	ast_copy_string(item->dtmf, dtmf, sizeof(item->dtmf));
-	item->activate_on_self = activate_on_self;
-
-	return item;
-}
-
-static int add_item(void *obj, void *arg, int flags)
-{
-	struct featuregroup_item *fg_item = obj;
-	struct ao2_container *applicationmap = arg;
-	RAII_VAR(struct ast_applicationmap_item *, appmap_item, NULL, ao2_cleanup);
-
-	/* If there's no DTMF override, then we can just link
-	 * the applicationmap item directly. Otherwise, we need
-	 * to create a copy with the DTMF override in place and
-	 * link that instead
-	 */
-	if (ast_strlen_zero(fg_item->dtmf_override)) {
-		ao2_ref(fg_item->appmap_item, +1);
-		appmap_item = fg_item->appmap_item;
-	} else {
-		appmap_item = applicationmap_item_alloc(fg_item->appmap_item_name,
-				fg_item->appmap_item->app, fg_item->appmap_item->app_data,
-				fg_item->appmap_item->moh_class, fg_item->dtmf_override,
-				fg_item->appmap_item->activate_on_self);
-	}
-
-	if (!appmap_item) {
-		return 0;
-	}
-
-	ao2_link(applicationmap, appmap_item);
-	return 0;
-}
-
-struct ao2_container *ast_get_chan_applicationmap(struct ast_channel *chan)
-{
-	RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-	struct ao2_container *applicationmap;
-	char *group_names;
-	char *name;
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	if (!chan) {
-		if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
-			return NULL;
-		}
-		ao2_ref(cfg->applicationmap, +1);
-		return cfg->applicationmap;
-	}
-
-	group_names = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"), ""));
-	if (ast_strlen_zero(group_names)) {
-		return NULL;
-	}
-
-	applicationmap = applicationmap_alloc(0);
-	if (!applicationmap) {
-		return NULL;
-	}
-
-	/* global config must be initialized */
-	ast_assert(cfg->featuregroups != NULL);
-	ast_assert(cfg->applicationmap != NULL);
-	while ((name = strsep(&group_names, "#"))) {
-		RAII_VAR(struct featuregroup *, group, ao2_find(cfg->featuregroups, name, OBJ_KEY), ao2_cleanup);
-
-		if (!group) {
-			RAII_VAR(struct ast_applicationmap_item *, item, ao2_find(cfg->applicationmap, name, OBJ_KEY), ao2_cleanup);
-
-			if (item) {
-				ao2_link(applicationmap, item);
-			} else {
-				ast_log(LOG_WARNING, "Unknown DYNAMIC_FEATURES item '%s' on channel %s.\n",
-					name, ast_channel_name(chan));
-			}
-		} else {
-			ao2_callback(group->items, 0, add_item, applicationmap);
-		}
-	}
-
-	if (ao2_container_count(applicationmap) == 0) {
-		ao2_cleanup(applicationmap);
-		return NULL;
-	}
-
-	return applicationmap;
-}
-
-static int applicationmap_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
-	struct ao2_container *applicationmap = obj;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(dtmf);
-		AST_APP_ARG(activate_on);
-		AST_APP_ARG(app);
-		AST_APP_ARG(app_data);
-		AST_APP_ARG(moh_class);
-	);
-	char *parse = ast_strdupa(var->value);
-	char *slash;
-	char *paren;
-	unsigned int activate_on_self;
-
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.dtmf) ||
-			ast_strlen_zero(args.activate_on) ||
-			ast_strlen_zero(args.app)) {
-		ast_log(LOG_WARNING, "Invalid applicationmap syntax for '%s'. Missing required argument\n", var->name);
-		return -1;
-	}
-
-	/* features.conf used to have an "activated_by" portion
-	 * in addition to activate_on. Get rid of whatever may be
-	 * there
-	 */
-	slash = strchr(args.activate_on, '/');
-	if (slash) {
-		*slash = '\0';
-	}
-
-	/* Some applications do not require arguments. */
-	if (!args.app_data) {
-		args.app_data = "";
-	}
-
-	/* Two syntaxes allowed for applicationmap:
-	 * Old: foo = *1,self,NoOp,Boo!,default
-	 * New: foo = *1,self,NoOp(Boo!),default
-	 *
-	 * We need to handle both
-	 */
-	paren = strchr(args.app, '(');
-	if (paren) {
-		/* New syntax */
-		char *close_paren;
-
-		args.moh_class = args.app_data;
-		*paren++ = '\0';
-		close_paren = strrchr(paren, ')');
-		if (close_paren) {
-			*close_paren = '\0';
-		}
-		args.app_data = paren;
-
-		/* Re-check that the application is not empty */
-		if (ast_strlen_zero(args.app)) {
-			ast_log(LOG_WARNING, "Applicationmap item '%s' does not contain an application name.\n", var->name);
-			return -1;
-		}
-	} else if (strchr(args.app_data, '"')) {
-		args.app_data = ast_strip_quoted(args.app_data, "\"", "\"");
-	}
-
-	/* Allow caller and callee to be specified for backwards compatibility */
-	if (!strcasecmp(args.activate_on, "self") || !strcasecmp(args.activate_on, "caller")) {
-		activate_on_self = 1;
-	} else if (!strcasecmp(args.activate_on, "peer") || !strcasecmp(args.activate_on, "callee")) {
-		activate_on_self = 0;
-	} else {
-		ast_log(LOG_WARNING, "Invalid 'activate_on' value %s for applicationmap item %s\n",
-			args.activate_on, var->name);
-		return -1;
-	}
-
-	ast_debug(1, "Allocating applicationmap item: dtmf = %s, app = %s, app_data = %s, moh_class = %s\n",
-			args.dtmf, args.app, args.app_data, args.moh_class);
-
-	item = applicationmap_item_alloc(var->name, args.app, args.app_data,
-			args.moh_class, args.dtmf, activate_on_self);
-
-	if (!item) {
-		return -1;
-	}
-
-	if (!ao2_link(applicationmap, item)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int featuregroup_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	RAII_VAR(struct featuregroup_item *, item, NULL, ao2_cleanup);
-	struct featuregroup *group = obj;
-
-	item = ao2_alloc(sizeof(*item), featuregroup_item_destructor);
-	if (!item || ast_string_field_init(item, 32)) {
-		return -1;
-	}
-
-	ast_string_field_set(item, appmap_item_name, var->name);
-	ast_string_field_set(item, dtmf_override, var->value);
-
-	if (!ao2_link(group->items, item)) {
-		return -1;
-	}
-
-	/* We wait to look up the application map item in the preapply callback */
-
-	return 0;
-}
-
-static int general_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	struct features_global_config *global = obj;
-	struct ast_features_general_config *general = global->general;
-
-	return general_set(general, var->name, var->value);
-}
-
-static int xfer_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	struct features_global_config *global = obj;
-	struct ast_features_xfer_config *xfer = global->xfer;
-
-	return xfer_set(xfer, var->name, var->value);
-}
-
-static int pickup_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	struct features_global_config *global = obj;
-	struct ast_features_pickup_config *pickup = global->pickup;
-
-	return pickup_set(pickup, var->name, var->value);
-}
-
-static int parking_warning = 0;
-static int unsupported_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	if (!parking_warning) {
-		ast_log(LOG_WARNING, "Parkinglots are no longer configurable in features.conf; "
-			"parking is now handled by res_parking.conf\n");
-		parking_warning = 1;
-	}
-	ast_log(LOG_WARNING, "The option '%s' is no longer configurable in features.conf.\n", var->name);
-	return 0;
-}
-
-static int featuremap_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	struct ast_featuremap_config *featuremap = obj;
-
-	return featuremap_set(featuremap, var->name, var->value);
-}
-
-static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_applicationmap_item *appmap_item;
-	struct featuregroup_item *fg_item = obj;
-	int *err = arg;
-	struct ao2_container *applicationmap = data;
-
-	appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
-	if (!appmap_item) {
-		*err = 1;
-		return CMP_STOP;
-	}
-
-	fg_item->appmap_item = appmap_item;
-
-	return 0;
-}
-
-static int check_featuregroup(void *obj, void *arg, void *data, int flags)
-{
-	struct featuregroup *group = obj;
-	int *err = arg;
-
-	ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
-
-	if (*err) {
-		ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
-				group->name);
-	}
-
-	return *err ? CMP_STOP : 0;
-}
-
-static int features_pre_apply_config(void);
-
-CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
-	.files = ACO_FILES(&features_conf),
-	.pre_apply_config = features_pre_apply_config,
-);
-
-static int features_pre_apply_config(void)
-{
-	struct features_config *cfg = aco_pending_config(&cfg_info);
-	int err = 0;
-
-	/* Now that the entire config has been processed, we can check that the featuregroup
-	 * items refer to actual applicationmap items.
-	 */
-
-	/* global config must be initialized */
-	ast_assert(cfg->featuregroups != NULL);
-	ast_assert(cfg->applicationmap != NULL);
-	ao2_callback_data(cfg->featuregroups, 0, check_featuregroup, &err, cfg->applicationmap);
-
-	return err;
-}
-
-static int internal_feature_read(struct ast_channel *chan, const char *cmd, char *data,
-	       char *buf, size_t len)
-{
-	int res;
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	if (!strcasecmp(data, "inherit")) {
-		struct ast_datastore *ds = get_feature_chan_ds(chan);
-		unsigned int inherit = ds ? ds->inheritance : 0;
-
-		snprintf(buf, len, "%s", inherit ? "yes" : "no");
-		return 0;
-	}
-
-	cfg = get_feature_ds(chan);
-	if (!cfg) {
-		return -1;
-	}
-
-	res = general_get(cfg->global->general, data, buf, len) &&
-		xfer_get(cfg->global->xfer, data, buf, len) &&
-		pickup_get(cfg->global->pickup, data, buf, len);
-
-	if (res) {
-		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
-	}
-
-	return res;
-}
-
-static int internal_feature_write(struct ast_channel *chan, const char *cmd, char *data,
-		const char *value)
-{
-	int res;
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	if (!strcasecmp(data, "inherit")) {
-		struct ast_datastore *ds = get_feature_chan_ds(chan);
-		if (ds) {
-			ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
-		}
-		return 0;
-	}
-
-	if (!(cfg = get_feature_ds(chan))) {
-		return -1;
-	}
-
-	res = general_set(cfg->global->general, data, value) &&
-		xfer_set(cfg->global->xfer, data, value) &&
-		pickup_set(cfg->global->pickup, data, value);
-
-	if (res) {
-		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
-	}
-
-	return res;
-}
-
-static int internal_featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
-	       char *buf, size_t len)
-{
-	int res;
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	res = ast_get_builtin_feature(chan, data, buf, len);
-
-	if (res) {
-		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
-	}
-
-	return res;
-}
-
-static int internal_featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
-		const char *value)
-{
-	int res;
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	if (!(cfg = get_feature_ds(chan))) {
-		return -1;
-	}
-
-	res = featuremap_set(cfg->featuremap, data, value);
-	if (res) {
-		ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
-		char *buf, size_t len)
-{
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	return internal_feature_read(chan, cmd, data, buf, len);
-}
-
-static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
-		const char *value)
-{
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	return internal_feature_write(chan, cmd, data, value);
-}
-
-static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
-		char *buf, size_t len)
-{
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	return internal_featuremap_read(chan, cmd, data, buf, len);
-}
-
-static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
-		const char *value)
-{
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
-		return -1;
-	}
-
-	return internal_featuremap_write(chan, cmd, data, value);
-}
-
-static struct ast_custom_function feature_function = {
-	.name = "FEATURE",
-	.read = feature_read,
-	.write = feature_write
-};
-
-static struct ast_custom_function featuremap_function = {
-	.name = "FEATUREMAP",
-	.read = featuremap_read,
-	.write = featuremap_write
-};
-
-static int load_config(void)
-{
-	if (aco_info_init(&cfg_info)) {
-		ast_log(LOG_ERROR, "Unable to initialize configuration info for features\n");
-		return -1;
-	}
-
-	aco_option_register_custom(&cfg_info, "featuredigittimeout", ACO_EXACT, global_options,
-			__stringify(DEFAULT_FEATURE_DIGIT_TIMEOUT), general_handler, 0);
-	aco_option_register_custom(&cfg_info, "recordingfailsound", ACO_EXACT, global_options,
-			DEFAULT_RECORDING_FAIL_SOUND, general_handler, 0);
-	aco_option_register_custom(&cfg_info, "courtesytone", ACO_EXACT, global_options,
-			DEFAULT_COURTESY_TONE, general_handler, 0);
-
-	aco_option_register_custom(&cfg_info, "transferdigittimeout", ACO_EXACT, global_options,
-			__stringify(DEFAULT_TRANSFER_DIGIT_TIMEOUT), xfer_handler, 0)
-	aco_option_register_custom(&cfg_info, "atxfernoanswertimeout", ACO_EXACT, global_options,
-			__stringify(DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER), xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxferdropcall", ACO_EXACT, global_options,
-			__stringify(DEFAULT_ATXFER_DROP_CALL), xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxferloopdelay", ACO_EXACT, global_options,
-			__stringify(DEFAULT_ATXFER_LOOP_DELAY), xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxfercallbackretries", ACO_EXACT, global_options,
-			__stringify(DEFAULT_ATXFER_CALLBACK_RETRIES), xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "xfersound", ACO_EXACT, global_options,
-			DEFAULT_XFERSOUND, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "xferfailsound", ACO_EXACT, global_options,
-			DEFAULT_XFERFAILSOUND, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxferabort", ACO_EXACT, global_options,
-			DEFAULT_ATXFER_ABORT, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxfercomplete", ACO_EXACT, global_options,
-			DEFAULT_ATXFER_COMPLETE, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxferthreeway", ACO_EXACT, global_options,
-			DEFAULT_ATXFER_THREEWAY, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxferswap", ACO_EXACT, global_options,
-			DEFAULT_ATXFER_SWAP, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "transferdialattempts", ACO_EXACT, global_options,
-			__stringify(DEFAULT_TRANSFER_DIAL_ATTEMPTS), xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "transferretrysound", ACO_EXACT, global_options,
-			DEFAULT_TRANSFER_RETRY_SOUND, xfer_handler, 0);
-	aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options,
-			DEFAULT_TRANSFER_INVALID_SOUND, xfer_handler, 0);
-
-	aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
-			DEFAULT_PICKUPEXTEN, pickup_handler, 0);
-	aco_option_register_custom(&cfg_info, "pickupsound", ACO_EXACT, global_options,
-			DEFAULT_PICKUPSOUND, pickup_handler, 0);
-	aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
-			DEFAULT_PICKUPFAILSOUND, pickup_handler, 0);
-
-	aco_option_register_custom_nodoc(&cfg_info, "context", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkext", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkext_exclusive", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkinghints", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkedmusicclass", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkingtime", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkpos", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "findslot", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkedcalltransfers", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkedcallreparking", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkedcallhangup", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkedcallrecording", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "comebackcontext", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "comebacktoorigin", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "comebackdialtime", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "parkeddynamic", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-	aco_option_register_custom_nodoc(&cfg_info, "adsipark", ACO_EXACT, global_options,
-			"", unsupported_handler, 0);
-
-	aco_option_register_custom(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_BLINDXFER, featuremap_handler, 0);
-	aco_option_register_custom(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_DISCONNECT, featuremap_handler, 0);
-	aco_option_register_custom(&cfg_info, "automon", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_AUTOMON, featuremap_handler, 0);
-	aco_option_register_custom(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_ATXFER, featuremap_handler, 0);
-	aco_option_register_custom(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_PARKCALL, featuremap_handler, 0);
-	aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
-			DEFAULT_FEATUREMAP_AUTOMIXMON, featuremap_handler, 0);
-
-	aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
-			"", applicationmap_handler, 0);
-
-	aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options,
-			"", featuregroup_handler, 0);
-
-	aco_option_register_custom_nodoc(&cfg_info, "^.*$", ACO_REGEX, parkinglot_options,
-			"", unsupported_handler, 0);
-
-	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
-		RAII_VAR(struct features_config *, features_cfg, features_config_alloc(), ao2_cleanup);
-
-		if (aco_set_defaults(&global_option, "general", features_cfg->global) ||
-			aco_set_defaults(&featuremap_option, "featuremap", features_cfg->featuremap)) {
-			ast_log(LOG_ERROR, "Failed to load features.conf and failed to initialize defaults.\n");
-			return -1;
-		}
-
-		ast_log(LOG_NOTICE, "Could not load features config; using defaults\n");
-		ao2_global_obj_replace_unref(globals, features_cfg);
-	}
-
-	return 0;
-}
-
-static int print_featuregroup(void *obj, void *arg, int flags)
-{
-	struct featuregroup_item *item = obj;
-	struct ast_cli_args *a = arg;
-
-	ast_cli(a->fd, "===> --> %s (%s)\n", item->appmap_item_name,
-			S_OR(item->dtmf_override, item->appmap_item->dtmf));
-
-	return 0;
-}
-
-static int print_featuregroups(void *obj, void *arg, int flags)
-{
-	struct featuregroup *group = obj;
-	struct ast_cli_args *a = arg;
-
-	ast_cli(a->fd, "===> Group: %s\n", group->name);
-
-	ao2_callback(group->items, 0, print_featuregroup, a);
-	return 0;
-}
-
-#define HFS_FORMAT "%-25s %-7s %-7s\n"
-
-static int print_applicationmap(void *obj, void *arg, int flags)
-{
-	struct ast_applicationmap_item *item = obj;
-	struct ast_cli_args *a = arg;
-
-	ast_cli(a->fd, HFS_FORMAT, item->name, "no def", item->dtmf);
-	return 0;
-}
-
-/*!
- * \brief CLI command to list configured features
- * \param e
- * \param cmd
- * \param a
- *
- * \retval CLI_SUCCESS on success.
- * \retval NULL when tab completion is used.
- */
-static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
-
-	switch (cmd) {
-
-	case CLI_INIT:
-		e->command = "features show";
-		e->usage =
-			"Usage: features show\n"
-			"       Lists configured features\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	cfg = ao2_global_obj_ref(globals);
-
-	ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
-	ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
-
-	ast_cli(a->fd, HFS_FORMAT, "Pickup", DEFAULT_PICKUPEXTEN, cfg->global->pickup->pickupexten);
-	ast_cli(a->fd, HFS_FORMAT, "Blind Transfer", DEFAULT_FEATUREMAP_BLINDXFER, cfg->featuremap->blindxfer);
-	ast_cli(a->fd, HFS_FORMAT, "Attended Transfer", DEFAULT_FEATUREMAP_ATXFER, cfg->featuremap->atxfer);
-	ast_cli(a->fd, HFS_FORMAT, "One Touch Monitor", DEFAULT_FEATUREMAP_AUTOMON, cfg->featuremap->automon);
-	ast_cli(a->fd, HFS_FORMAT, "Disconnect Call", DEFAULT_FEATUREMAP_DISCONNECT, cfg->featuremap->disconnect);
-	ast_cli(a->fd, HFS_FORMAT, "Park Call", DEFAULT_FEATUREMAP_PARKCALL, cfg->featuremap->parkcall);
-	ast_cli(a->fd, HFS_FORMAT, "One Touch MixMonitor", DEFAULT_FEATUREMAP_AUTOMIXMON, cfg->featuremap->automixmon);
-
-	ast_cli(a->fd, "\n");
-	ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
-	ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
-	if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
-		ast_cli(a->fd, "(none)\n");
-	} else {
-		ao2_callback(cfg->applicationmap, 0, print_applicationmap, a);
-	}
-
-	ast_cli(a->fd, "\nFeature Groups:\n");
-	ast_cli(a->fd, "---------------\n");
-	if (!cfg->featuregroups || ao2_container_count(cfg->featuregroups) == 0) {
-		ast_cli(a->fd, "(none)\n");
-	} else {
-		ao2_callback(cfg->featuregroups, 0, print_featuregroups, a);
-	}
-
-	ast_cli(a->fd, "\n");
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_features_config[] = {
-	AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
-};
-
-void ast_features_config_shutdown(void)
-{
-	ast_custom_function_unregister(&featuremap_function);
-	ast_custom_function_unregister(&feature_function);
-	ast_cli_unregister_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(globals);
-}
-
-int ast_features_config_reload(void)
-{
-	/* Rearm the parking config options have moved warning. */
-	parking_warning = 0;
-
-	if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
-		return -1;
-	}
-	return 0;
-}
-
-int ast_features_config_init(void)
-{
-	int res;
-
-	res = load_config();
-	res |= __ast_custom_function_register(&feature_function, NULL);
-	res |= __ast_custom_function_register(&featuremap_function, NULL);
-	res |= ast_cli_register_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
-
-	if (res) {
-		ast_features_config_shutdown();
-	}
-
-	return res;
-}
diff --git a/main/file.c b/main/file.c
index 7aeb32a..436aae9 100644
--- a/main/file.c
+++ b/main/file.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427466 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <dirent.h>
 #include <sys/stat.h>
@@ -51,9 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427466 $")
 #include "asterisk/module.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/test.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis_system.h"
 
 /*! \brief
  * The following variable controls the layout of localized sound files.
@@ -69,59 +66,6 @@ int ast_language_is_prefix = 1;
 
 static AST_RWLIST_HEAD_STATIC(formats, ast_format_def);
 
-STASIS_MESSAGE_TYPE_DEFN(ast_format_register_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_format_unregister_type);
-
-static struct ast_json *json_array_from_list(const char *list, const char *sep)
-{
-	RAII_VAR(struct ast_json *, array, ast_json_array_create(), ast_json_unref);
-	char *stringp, *ext;
-
-	stringp = ast_strdupa(list);	/* this is in the stack so does not need to be freed */
-	if (!array || !stringp) {
-		return NULL;
-	}
-
-	while ((ext = strsep(&stringp, sep))) {
-		if (ast_json_array_append(array, ast_json_string_create(ext))) {
-			return NULL;
-		}
-	}
-
-	return ast_json_ref(array);
-}
-
-static int publish_format_update(const struct ast_format_def *f, struct stasis_message_type *type)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
-	if (!type) {
-		return -1;
-	}
-
-	json_object = ast_json_pack("{s: s, s: o}",
-		"format", f->name,
-		"extensions", json_array_from_list(f->exts, "|"));
-	if (!json_object) {
-		return -1;
-	}
-
-	json_payload = ast_json_payload_create(json_object);
-	if (!json_payload) {
-		return -1;
-	}
-
-	msg = stasis_message_create(type, json_payload);
-	if (!msg) {
-		return -1;
-	}
-
-	stasis_publish(ast_system_topic(), msg);
-	return 0;
-}
-
 int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod)
 {
 	struct ast_format_def *tmp;
@@ -155,7 +99,6 @@ int __ast_format_def_register(const struct ast_format_def *f, struct ast_module
 	AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
 	AST_RWLIST_UNLOCK(&formats);
 	ast_verb(2, "Registered file format %s, extension(s) %s\n", f->name, f->exts);
-	publish_format_update(f, ast_format_register_type());
 
 	return 0;
 }
@@ -169,7 +112,6 @@ int ast_format_def_unregister(const char *name)
 	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
 		if (!strcasecmp(name, tmp->name)) {
 			AST_RWLIST_REMOVE_CURRENT(list);
-			publish_format_update(tmp, ast_format_unregister_type());
 			ast_free(tmp);
 			res = 0;
 		}
@@ -193,8 +135,8 @@ int ast_stopstream(struct ast_channel *tmp)
 	if (ast_channel_stream(tmp)) {
 		ast_closestream(ast_channel_stream(tmp));
 		ast_channel_stream_set(tmp, NULL);
-		if (ast_channel_oldwriteformat(tmp) && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp)))
-			ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_format_get_name(ast_channel_oldwriteformat(tmp)));
+		if (ast_channel_oldwriteformat(tmp)->id && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp)))
+			ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(ast_channel_oldwriteformat(tmp)));
 	}
 	/* Stop the video stream too */
 	if (ast_channel_vstream(tmp) != NULL) {
@@ -211,10 +153,10 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
 {
 	int res = -1;
 	if (f->frametype == AST_FRAME_VIDEO) {
-		if (ast_format_get_type(fs->fmt->format) == AST_MEDIA_TYPE_AUDIO) {
+		if (AST_FORMAT_GET_TYPE(fs->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
 			/* This is the audio portion.  Call the video one... */
 			if (!fs->vfs && fs->filename) {
-				const char *type = ast_format_get_name(f->subclass.format);
+				const char *type = ast_getformatname(&f->subclass.format);
 				fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
 				ast_debug(1, "Opened video output file\n");
 			}
@@ -227,7 +169,7 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
 		ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
 		return -1;
 	}
-	if (ast_format_cmp(f->subclass.format, fs->fmt->format) != AST_FORMAT_CMP_NOT_EQUAL) {
+	if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) != AST_FORMAT_CMP_NOT_EQUAL) {
 		res =  fs->fmt->write(fs, f);
 		if (res < 0)
 			ast_log(LOG_WARNING, "Natural write failed\n");
@@ -236,19 +178,18 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
 	} else {
 		/* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
 		       the one we've setup a translator for, we do the "wrong thing" XXX */
-		if (fs->trans && (ast_format_cmp(f->subclass.format, fs->lastwriteformat) != AST_FORMAT_CMP_EQUAL)) {
+		if (fs->trans && (ast_format_cmp(&f->subclass.format, &fs->lastwriteformat) != AST_FORMAT_CMP_EQUAL)) {
 			ast_translator_free_path(fs->trans);
 			fs->trans = NULL;
 		}
-		if (!fs->trans) {
-			fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass.format);
-		}
-		if (!fs->trans) {
+		if (!fs->trans)
+			fs->trans = ast_translator_build_path(&fs->fmt->format, &f->subclass.format);
+		if (!fs->trans)
 			ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
-				fs->fmt->name, ast_format_get_name(f->subclass.format));
-		} else {
+				fs->fmt->name, ast_getformatname(&f->subclass.format));
+		else {
 			struct ast_frame *trf;
-			ao2_replace(fs->lastwriteformat, f->subclass.format);
+			ast_format_copy(&fs->lastwriteformat, &f->subclass.format);
 			/* Get the translated frame but don't consume the original in case they're using it on another stream */
 			if ((trf = ast_translate(fs->trans, f, 0))) {
 				struct ast_frame *cur;
@@ -348,13 +289,10 @@ static int exts_compare(const char *exts, const char *type)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Close the file stream by canceling any pending read / write callbacks
- */
+/*! \internal \brief Close the file stream by canceling any pending read / write callbacks */
 static void filestream_close(struct ast_filestream *f)
 {
-	enum ast_media_type format_type = ast_format_get_type(f->fmt->format);
+	enum ast_format_type format_type = AST_FORMAT_GET_TYPE(f->fmt->format.id);
 
 	if (!f->owner) {
 		return;
@@ -363,12 +301,12 @@ static void filestream_close(struct ast_filestream *f)
 	/* Stop a running stream if there is one */
 	switch (format_type)
 	{
-	case AST_MEDIA_TYPE_AUDIO:
+	case AST_FORMAT_TYPE_AUDIO:
 		ast_channel_stream_set(f->owner, NULL);
 		AST_SCHED_DEL_ACCESSOR(ast_channel_sched(f->owner), f->owner, ast_channel_streamid, ast_channel_streamid_set);
 		ast_settimeout(f->owner, 0, NULL, NULL);
 		break;
-	case AST_MEDIA_TYPE_VIDEO:
+	case AST_FORMAT_TYPE_VIDEO:
 		ast_channel_vstream_set(f->owner, NULL);
 		AST_SCHED_DEL_ACCESSOR(ast_channel_sched(f->owner), f->owner, ast_channel_vstreamid, ast_channel_vstreamid_set);
 		break;
@@ -423,8 +361,6 @@ static void filestream_destructor(void *arg)
 	}
 	if (f->orig_chan_name)
 		free((void *) f->orig_chan_name);
-	ao2_cleanup(f->lastwriteformat);
-	ao2_cleanup(f->fr.subclass.format);
 	ast_module_unref(f->fmt->module);
 }
 
@@ -444,15 +380,6 @@ static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *b
 	if (fmt->buf_size)
 		s->buf = (char *)(s + 1);
 	s->fr.src = fmt->name;
-
-	if (ast_format_get_type(fmt->format) == AST_MEDIA_TYPE_AUDIO) {
-		s->fr.frametype = AST_FRAME_VOICE;
-	} else if (ast_format_get_type(fmt->format) == AST_MEDIA_TYPE_VIDEO) {
-		s->fr.frametype = AST_FRAME_VIDEO;
-	}
-	s->fr.mallocd = 0;
-	s->fr.subclass.format = ao2_bump(fmt->format);
-
 	return s;
 }
 
@@ -545,9 +472,9 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c
 				FILE *bfile;
 				struct ast_filestream *s;
 
-				if ((ast_format_cmp(ast_channel_writeformat(chan), f->format) == AST_FORMAT_CMP_NOT_EQUAL) &&
-				     !(((ast_format_get_type(f->format) == AST_MEDIA_TYPE_AUDIO) && fmt) ||
-					  ((ast_format_get_type(f->format) == AST_MEDIA_TYPE_VIDEO) && fmt))) {
+				if ((ast_format_cmp(ast_channel_writeformat(chan), &f->format) == AST_FORMAT_CMP_NOT_EQUAL) &&
+				     !(((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_AUDIO) && fmt) ||
+					  ((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_VIDEO) && fmt))) {
 					ast_free(fn);
 					continue;	/* not a supported format */
 				}
@@ -575,7 +502,7 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c
 				s->fmt = f;
 				s->trans = NULL;
 				s->filename = NULL;
-				if (ast_format_get_type(s->fmt->format) == AST_MEDIA_TYPE_AUDIO) {
+				if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
 					if (ast_channel_stream(chan))
 						ast_closestream(ast_channel_stream(chan));
 					ast_channel_stream_set(chan, s);
@@ -595,7 +522,7 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c
 				/* if arg2 is present, it is a format capabilities structure.
 				 * Add this format to the set of formats this file can be played in */
 				if (arg2) {
-					ast_format_cap_append((struct ast_format_cap *) arg2, f->format, 0);
+					ast_format_cap_add((struct ast_format_cap *) arg2, &f->format);
 				}
 				res = 1; /* file does exist and format it exists in is returned in arg2 */
 				break;
@@ -677,12 +604,12 @@ static int fileexists_test(const char *filename, const char *fmt, const char *la
  * \note The last parameter(s) point to a buffer of sufficient size,
  * which on success is filled with the matching filename.
  *
- * \param filename Name of the file.
- * \param fmt Format to look for the file in. OPTIONAL
- * \param preflang The perfered language
- * \param buf Returns the matching filename
- * \param buflen Size of the buf
- * \param result_cap OPTIONAL format capabilities result structure
+ * \param filename, name of the file.
+ * \param fmt, format to look for the file in. OPTIONAL
+ * \param preflang, the perfered language
+ * \param buf, returns the matching filename
+ * \param buflen, size of the buf
+ * \param result_cap, OPTIONAL format capabilities result structure
  *        returns what formats the file was found in.
  *
  * \retval 1, true. file exists and result format is set
@@ -765,25 +692,23 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
 	buflen = strlen(preflang) + strlen(filename) + 4;
 	buf = ast_alloca(buflen);
 
-	if (!(file_fmt_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(file_fmt_cap = ast_format_cap_alloc_nolock())) {
 		return NULL;
 	}
 	if (!fileexists_core(filename, NULL, preflang, buf, buflen, file_fmt_cap) ||
-		!ast_format_cap_has_type(file_fmt_cap, AST_MEDIA_TYPE_AUDIO)) {
+		!ast_format_cap_has_type(file_fmt_cap, AST_FORMAT_TYPE_AUDIO)) {
 
 		ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
-		ao2_ref(file_fmt_cap, -1);
+		file_fmt_cap = ast_format_cap_destroy(file_fmt_cap);
 		return NULL;
 	}
 
 	/* Set the channel to a format we can work with and save off the previous format. */
-	ast_channel_lock(chan);
-	ast_channel_set_oldwriteformat(chan, ast_channel_writeformat(chan));
+	ast_format_copy(ast_channel_oldwriteformat(chan), ast_channel_writeformat(chan));
 	/* Set the channel to the best format that exists for the file. */
 	res = ast_set_write_format_from_cap(chan, file_fmt_cap);
-	ast_channel_unlock(chan);
 	/* don't need this anymore now that the channel's write format is set. */
-	ao2_ref(file_fmt_cap, -1);
+	file_fmt_cap = ast_format_cap_destroy(file_fmt_cap);
 
 	if (res == -1) {	/* No format available that works with this channel */
 		return NULL;
@@ -799,50 +724,50 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
 	/* As above, but for video. But here we don't have translators
 	 * so we must enforce a format.
 	 */
+	struct ast_format tmp_fmt;
 	struct ast_format_cap *tmp_cap;
 	char *buf;
 	int buflen;
-	int i, fd;
+	const char *fmt;
+	int fd;
 
-	if (preflang == NULL) {
+	if (preflang == NULL)
 		preflang = "";
-	}
 	buflen = strlen(preflang) + strlen(filename) + 4;
 	buf = ast_alloca(buflen);
 
 	/* is the channel capable of video without translation ?*/
-	if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) {
+	if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO)) {
 		return NULL;
 	}
-	if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(tmp_cap = ast_format_cap_alloc_nolock())) {
 		return NULL;
 	}
 	/* Video is supported, so see what video formats exist for this file */
 	if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) {
-		ao2_ref(tmp_cap, -1);
+		tmp_cap = ast_format_cap_destroy(tmp_cap);
 		return NULL;
 	}
 
 	/* iterate over file formats and pick the first one compatible with the channel's native formats */
-	for (i = 0; i < ast_format_cap_count(tmp_cap); ++i) {
-		struct ast_format *format = ast_format_cap_get_format(tmp_cap, i);
-
-		if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) ||
-			!ast_format_cap_iscompatible(ast_channel_nativeformats(chan), tmp_cap)) {
-			ao2_ref(format, -1);
+	ast_format_cap_iter_start(tmp_cap);
+	while (!ast_format_cap_iter_next(tmp_cap, &tmp_fmt)) {
+		fmt = ast_getformatname(&tmp_fmt);
+		if ((AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) ||
+			!ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &tmp_fmt)) {
 			continue;
 		}
 
-		fd = filehelper(buf, chan, ast_format_get_name(format), ACTION_OPEN);
+		fd = filehelper(buf, chan, fmt, ACTION_OPEN);
 		if (fd >= 0) {
-			ao2_ref(format, -1);
-			ao2_ref(tmp_cap, -1);
+			ast_format_cap_iter_end(tmp_cap);
+			tmp_cap = ast_format_cap_destroy(tmp_cap);
 			return ast_channel_vstream(chan);
 		}
 		ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
-		ao2_ref(format, -1);
 	}
-	ao2_ref(tmp_cap, -1);
+	ast_format_cap_iter_end(tmp_cap);
+	tmp_cap = ast_format_cap_destroy(tmp_cap);
 
 	return NULL;
 }
@@ -915,14 +840,14 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
 
 	if (whennext != s->lasttimeout) {
 		if (ast_channel_timingfd(s->owner) > -1) {
-			float samp_rate = (float) ast_format_get_sample_rate(s->fmt->format);
+			float samp_rate = (float) ast_format_rate(&s->fmt->format);
 			unsigned int rate;
 
 			rate = (unsigned int) roundf(samp_rate / ((float) whennext));
 
 			ast_settimeout_full(s->owner, rate, ast_fsread_audio, s, 1);
 		} else {
-			ast_channel_streamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_get_sample_rate(s->fmt->format) / 1000), ast_fsread_audio, s));
+			ast_channel_streamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_audio, s));
 		}
 		s->lasttimeout = whennext;
 		return FSREAD_SUCCESS_NOSCHED;
@@ -972,7 +897,7 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
 	}
 
 	if (whennext != s->lasttimeout) {
-		ast_channel_vstreamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_get_sample_rate(s->fmt->format) / 1000), ast_fsread_video, s));
+		ast_channel_vstreamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_video, s));
 		s->lasttimeout = whennext;
 		return FSREAD_SUCCESS_NOSCHED;
 	}
@@ -1003,7 +928,7 @@ int ast_playstream(struct ast_filestream *s)
 {
 	enum fsread_res res;
 
-	if (ast_format_get_type(s->fmt->format) == AST_MEDIA_TYPE_AUDIO)
+	if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO)
 		res = ast_readaudio_callback(s);
 	else
 		res = ast_readvideo_callback(s);
@@ -1026,11 +951,6 @@ off_t ast_tellstream(struct ast_filestream *fs)
 	return fs->fmt->tell(fs);
 }
 
-int ast_ratestream(struct ast_filestream *fs)
-{
-	return ast_format_get_sample_rate(fs->fmt->format);
-}
-
 int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
 {
 	return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
@@ -1047,9 +967,6 @@ int ast_closestream(struct ast_filestream *f)
 	 * We close the stream in order to quit queuing frames now, because we might
 	 * change the writeformat, which could result in a subsequent write error, if
 	 * the format is different. */
-	if (f == NULL) {
-		return 0;
-	}
 	filestream_close(f);
 	ao2_ref(f, -1);
 	return 0;
@@ -1090,15 +1007,14 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
 {
 	struct ast_filestream *fs;
 	struct ast_filestream *vfs=NULL;
+	char fmt[256];
 	off_t pos;
 	int seekattempt;
 	int res;
 
 	fs = ast_openstream(chan, filename, preflang);
 	if (!fs) {
-		struct ast_str *codec_buf = ast_str_alloca(64);
-		ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n",
-			filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno));
+		ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), ast_channel_nativeformats(chan)), strerror(errno));
 		return -1;
 	}
 
@@ -1120,7 +1036,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
 
 	vfs = ast_openvstream(chan, filename, preflang);
 	if (vfs) {
-		ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_format_get_name(vfs->fmt->format));
+		ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(&vfs->fmt->format));
 	}
 
 	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MASQ_NOSTREAM))
@@ -1133,7 +1049,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
 	res = ast_playstream(fs);
 	if (!res && vfs)
 		res = ast_playstream(vfs);
-	ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default");
+	ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_getformatname(ast_channel_writeformat(chan)), preflang ? preflang : "default");
 
 	return res;
 }
@@ -1328,45 +1244,6 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
 	return fs;
 }
 
-static void waitstream_control(struct ast_channel *c,
-		enum ast_waitstream_fr_cb_values type,
-		ast_waitstream_fr_cb cb,
-		int skip_ms)
-{
-	switch (type)
-	{
-	case AST_WAITSTREAM_CB_FASTFORWARD:
-		{
-			int eoftest;
-			ast_stream_fastforward(ast_channel_stream(c), skip_ms);
-			eoftest = fgetc(ast_channel_stream(c)->f);
-			if (feof(ast_channel_stream(c)->f)) {
-				ast_stream_rewind(ast_channel_stream(c), skip_ms);
-			} else {
-				ungetc(eoftest, ast_channel_stream(c)->f);
-			}
-		}
-		break;
-	case AST_WAITSTREAM_CB_REWIND:
-		ast_stream_rewind(ast_channel_stream(c), skip_ms);
-		break;
-	default:
-		break;
-	}
-
-	if (cb) {
-		long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_get_sample_rate(ast_channel_stream(c)->fmt->format) / 1000);
-		cb(c, ms_len, type);
-	}
-
-	ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-		"Control: %s\r\n"
-		"SkipMs: %d\r\n",
-		ast_channel_name(c),
-		(type == AST_WAITSTREAM_CB_FASTFORWARD) ? "FastForward" : "Rewind",
-		skip_ms);
-}
-
 /*!
  * \brief the core of all waitstream() functions
  */
@@ -1398,7 +1275,7 @@ static int waitstream_core(struct ast_channel *c,
 		orig_chan_name = ast_strdupa(ast_channel_name(c));
 
 	if (ast_channel_stream(c) && cb) {
-		long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_get_sample_rate(ast_channel_stream(c)->fmt->format) / 1000);
+		long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_rate(&ast_channel_stream(c)->fmt->format) / 1000);
 		cb(c, ms_len, AST_WAITSTREAM_CB_START);
 	}
 
@@ -1463,49 +1340,34 @@ static int waitstream_core(struct ast_channel *c,
 						return res;
 					}
 				} else {
+					enum ast_waitstream_fr_cb_values cb_val = 0;
 					res = fr->subclass.integer;
 					if (strchr(forward, res)) {
-						waitstream_control(c, AST_WAITSTREAM_CB_FASTFORWARD, cb, skip_ms);
+						int eoftest;
+						ast_stream_fastforward(ast_channel_stream(c), skip_ms);
+						eoftest = fgetc(ast_channel_stream(c)->f);
+						if (feof(ast_channel_stream(c)->f)) {
+							ast_stream_rewind(ast_channel_stream(c), skip_ms);
+						} else {
+							ungetc(eoftest, ast_channel_stream(c)->f);
+						}
+						cb_val = AST_WAITSTREAM_CB_FASTFORWARD;
 					} else if (strchr(reverse, res)) {
-						waitstream_control(c, AST_WAITSTREAM_CB_REWIND, cb, skip_ms);
+						ast_stream_rewind(ast_channel_stream(c), skip_ms);
+						cb_val = AST_WAITSTREAM_CB_REWIND;
 					} else if (strchr(breakon, res)) {
-						ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-							"Control: %s\r\n",
-							ast_channel_name(c),
-							"Break");
-
 						ast_frfree(fr);
 						ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
 						return res;
 					}
+					if (cb_val && cb) {
+						long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_rate(&ast_channel_stream(c)->fmt->format) / 1000);
+						cb(c, ms_len, cb_val);
+					}
 				}
 				break;
 			case AST_FRAME_CONTROL:
 				switch (fr->subclass.integer) {
-				case AST_CONTROL_STREAM_STOP:
-				case AST_CONTROL_STREAM_SUSPEND:
-				case AST_CONTROL_STREAM_RESTART:
-					/* Fall-through and break out */
-					ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
-						"Control: %s\r\n",
-						ast_channel_name(c),
-						"Break");
-					res = fr->subclass.integer;
-					ast_frfree(fr);
-					ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
-					return res;
-				case AST_CONTROL_STREAM_REVERSE:
-					if (!skip_ms) {
-						skip_ms = 3000;
-					}
-					waitstream_control(c, AST_WAITSTREAM_CB_REWIND, cb, skip_ms);
-					break;
-				case AST_CONTROL_STREAM_FORWARD:
-					if (!skip_ms) {
-						skip_ms = 3000;
-					}
-					waitstream_control(c, AST_WAITSTREAM_CB_FASTFORWARD, cb, skip_ms);
-					break;
 				case AST_CONTROL_HANGUP:
 				case AST_CONTROL_BUSY:
 				case AST_CONTROL_CONGESTION:
@@ -1569,62 +1431,26 @@ int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *fo
 		-1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */, NULL /* no callback */);
 }
 
-/*! \internal
- * \brief Clean up the return value of a waitstream call
- *
- * It's possible for a control frame to come in from an external source and break the
- * playback. From a consumer of most ast_waitstream_* function callers, this should
- * appear like normal playback termination, i.e., return 0 and not the value of the
- * control frame.
- */
-static int sanitize_waitstream_return(int return_value)
-{
-	switch (return_value) {
-	case AST_CONTROL_STREAM_STOP:
-	case AST_CONTROL_STREAM_SUSPEND:
-	case AST_CONTROL_STREAM_RESTART:
-		/* Fall through and set return_value to 0 */
-		return_value = 0;
-		break;
-	default:
-		/* Do nothing */
-		break;
-	}
-
-	return return_value;
-}
-
 int ast_waitstream(struct ast_channel *c, const char *breakon)
 {
-	int res;
-
-	res = waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL, NULL /* no callback */);
-
-	return sanitize_waitstream_return(res);
+	return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL, NULL /* no callback */);
 }
 
 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
 {
-	int res;
-
-	res = waitstream_core(c, breakon, NULL, NULL, 0,
+	return waitstream_core(c, breakon, NULL, NULL, 0,
 		audiofd, cmdfd, NULL /* no context */, NULL /* no callback */);
-
-	return sanitize_waitstream_return(res);
 }
 
 int ast_waitstream_exten(struct ast_channel *c, const char *context)
 {
-	int res;
-
 	/* Waitstream, with return in the case of a valid 1 digit extension */
 	/* in the current or specified context being pressed */
+
 	if (!context)
 		context = ast_channel_context(c);
-	res = waitstream_core(c, NULL, NULL, NULL, 0,
+	return waitstream_core(c, NULL, NULL, NULL, 0,
 		-1, -1, context, NULL /* no callback */);
-
-	return sanitize_waitstream_return(res);
 }
 
 /*
@@ -1746,7 +1572,7 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd,
 
 	AST_RWLIST_RDLOCK(&formats);
 	AST_RWLIST_TRAVERSE(&formats, f, list) {
-		ast_cli(a->fd, FORMAT2, ast_format_get_name(f->format), f->name, f->exts);
+		ast_cli(a->fd, FORMAT2, ast_getformatname(&f->format), f->name, f->exts);
 		count_fmt++;
 	}
 	AST_RWLIST_UNLOCK(&formats);
@@ -1756,19 +1582,6 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd,
 #undef FORMAT2
 }
 
-struct ast_format *ast_get_format_for_file_ext(const char *file_ext)
-{
-	struct ast_format_def *f;
-	SCOPED_RDLOCK(lock, &formats.lock);
-	AST_RWLIST_TRAVERSE(&formats, f, list) {
-		if (exts_compare(f->exts, file_ext)) {
-			return f->format;
-		}
-	}
-
-	return NULL;
-}
-
 static struct ast_cli_entry cli_file[] = {
 	AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
 };
@@ -1776,15 +1589,11 @@ static struct ast_cli_entry cli_file[] = {
 static void file_shutdown(void)
 {
 	ast_cli_unregister_multiple(cli_file, ARRAY_LEN(cli_file));
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_format_register_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_format_unregister_type);
 }
 
 int ast_file_init(void)
 {
-	STASIS_MESSAGE_TYPE_INIT(ast_format_register_type);
-	STASIS_MESSAGE_TYPE_INIT(ast_format_unregister_type);
 	ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
-	ast_register_atexit(file_shutdown);
+	ast_register_cleanup(file_shutdown);
 	return 0;
 }
diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c
index 869c8d3..17cad49 100644
--- a/main/fixedjitterbuf.c
+++ b/main/fixedjitterbuf.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <assert.h>
 
diff --git a/main/format.c b/main/format.c
index 7b4af84..e3c5bc5 100644
--- a/main/format.c
+++ b/main/format.c
@@ -1,9 +1,10 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2014, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
  *
- * Joshua Colp <jcolp at digium.com>
+ * David Vossel <dvossel at digium.com>
+ * Mark Spencer <markster at digium.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -16,11 +17,12 @@
  * at the top of the source tree.
  */
 
-/*! \file
+/*!
+ * \file
+ * \brief Format API
  *
- * \brief Media Format API
- *
- * \author Joshua Colp <jcolp at digium.com>
+ * \author David Vossel <dvossel at digium.com>
+ * \author Mark Spencer <markster at digium.com>
  */
 
 /*** MODULEINFO
@@ -29,351 +31,1415 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420028 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
-#include "asterisk/logger.h"
-#include "asterisk/codec.h"
+#include "asterisk/_private.h"
 #include "asterisk/format.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-
-/*! \brief Number of buckets to use for format interfaces (should be prime for performance reasons) */
-#define FORMAT_INTERFACE_BUCKETS 53
-
-/*! \brief Definition of a media format */
-struct ast_format {
-	/*! Name of the format */
-	const char *name;
-	/*! \brief Pointer to the codec in use for this format */
-	struct ast_codec *codec;
-	/*! \brief Attribute specific data, implementation specific */
-	void *attribute_data;
-	/*! \brief Pointer to the optional format interface */
-	const struct ast_format_interface *interface;
-};
+#include "asterisk/lock.h"
+#include "asterisk/frame.h"
+#include "asterisk/utils.h"
+#include "asterisk/cli.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/config.h"
+
+#define FORMAT_CONFIG "codecs.conf"
+
+/*!
+ * \brief Container for all the format attribute interfaces.
+ * \note This container uses RWLOCKs instead of MUTEX locks.                                                             .
+ * \note An ao2 container was chosen for fast lookup.
+ */
+static struct ao2_container *interfaces;
 
-/*! \brief Structure used when registering a format interface */
-struct format_interface {
-	/*! \brief Pointer to the format interface itself */
-	const struct ast_format_interface *interface;
-	/*! \brief Name of the codec the interface is for */
-	char codec[0];
+/*! a wrapper is used put interfaces into the ao2 container. */
+struct interface_ao2_wrapper {
+	enum ast_format_id id;
+	const struct ast_format_attr_interface *interface;
 };
 
-/*! \brief Container for registered format interfaces */
-static struct ao2_container *interfaces;
+/*! \brief Format List container, This container is never directly accessed outside
+ * of this file, and It only exists for building the format_list_array. */
+static struct ao2_container *format_list;
+/*! \brief Format List array is a read only array protected by a read write lock.
+ * This array may be used outside this file with the use of reference counting to
+ * guarantee safety for access by multiple threads. */
+static struct ast_format_list *format_list_array;
+static size_t format_list_array_len = 0;
+/*! \brief Locks the format list array so a reference can be taken safely. */
+static ast_rwlock_t format_list_array_lock;
+
+static int interface_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct interface_ao2_wrapper *wrapper1 = obj;
+	struct interface_ao2_wrapper *wrapper2 = arg;
+
+	return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static int interface_hash_cb(const void *obj, const int flags)
+{
+	const struct interface_ao2_wrapper *wrapper = obj;
+	return wrapper->id;
+}
 
-static int format_interface_hash(const void *obj, int flags)
+void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
 {
-	const struct format_interface *format_interface;
-	const char *key;
+	*dst = *src;
+}
 
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_SEARCH_OBJECT:
-		format_interface = obj;
-		return ast_str_hash(format_interface->codec);
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
+void ast_format_set_video_mark(struct ast_format *format)
+{
+	format->fattr.rtp_marker_bit = 1;
+}
+
+int ast_format_get_video_mark(const struct ast_format *format)
+{
+	return format->fattr.rtp_marker_bit;
+}
+
+static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
+{
+	struct interface_ao2_wrapper tmp_wrapper = {
+		.id = format->id,
+	};
+
+	return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
+}
+
+static int has_interface(const struct ast_format *format)
+{
+	struct interface_ao2_wrapper *wrapper;
+
+	wrapper = find_interface(format);
+	if (!wrapper) {
 		return 0;
 	}
+	ao2_ref(wrapper, -1);
+	return 1;
 }
 
-static int format_interface_cmp(void *obj, void *arg, int flags)
+int ast_format_sdp_parse(struct ast_format *format, const char *attributes)
 {
-	const struct format_interface *left = obj;
-	const struct format_interface *right = arg;
-	const char *right_key = arg;
-	int cmp;
+	struct interface_ao2_wrapper *wrapper;
+	int res;
 
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		cmp = strcmp(left->codec, right->codec);
-		break;
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left->codec, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left->codec, right_key, strlen(right_key));
-		break;
-	default:
-		ast_assert(0);
-		cmp = 0;
-		break;
+	if (!(wrapper = find_interface(format))) {
+		return 0;
 	}
-	if (cmp) {
+
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface || !wrapper->interface->format_attr_sdp_parse) {
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
 		return 0;
 	}
 
-	return CMP_MATCH;
+	res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes);
+
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
+
+	return res;
 }
 
-/*! \brief Function called when the process is shutting down */
-static void format_shutdown(void)
+void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str)
 {
-	ao2_cleanup(interfaces);
-	interfaces = NULL;
+	struct interface_ao2_wrapper *wrapper;
+
+	if (!(wrapper = find_interface(format))) {
+		return;
+	}
+
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface || !wrapper->interface->format_attr_sdp_generate) {
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
+		return;
+	}
+
+	wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str);
+
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
 }
 
-int ast_format_init(void)
+/*! \internal
+ * \brief set format attributes using an interface
+ */
+static int format_set_helper(struct ast_format *format, va_list ap)
 {
-	interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, FORMAT_INTERFACE_BUCKETS, format_interface_hash,
-		format_interface_cmp);
-	if (!interfaces) {
+	struct interface_ao2_wrapper *wrapper;
+
+	if (!(wrapper = find_interface(format))) {
+		ast_log(LOG_WARNING, "Could not find format interface to set.\n");
 		return -1;
 	}
 
-	ast_register_atexit(format_shutdown);
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface || !wrapper->interface->format_attr_set) {
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
+		return -1;
+	}
+
+	wrapper->interface->format_attr_set(&format->fattr, ap);
+
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
 
 	return 0;
 }
 
-int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod)
+struct ast_format *ast_format_append(struct ast_format *format, ... )
 {
-	SCOPED_AO2WRLOCK(lock, interfaces);
-	struct format_interface *format_interface;
+	va_list ap;
+	va_start(ap, format);
+	format_set_helper(format, ap);
+	va_end(ap);
 
-	if (!interface->format_clone || !interface->format_destroy) {
-		ast_log(LOG_ERROR, "Format interface for codec '%s' does not implement required callbacks\n", codec);
-		return -1;
+	return format;
+}
+
+struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
+{
+	/* initialize the structure before setting it. */
+	ast_format_clear(format);
+
+	format->id = id;
+
+	if (set_attributes) {
+		va_list ap;
+		va_start(ap, set_attributes);
+		format_set_helper(format, ap);
+		va_end(ap);
 	}
 
-	format_interface = ao2_find(interfaces, codec, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-	if (format_interface) {
-		ast_log(LOG_ERROR, "A format interface is already present for codec '%s'\n", codec);
-		ao2_ref(format_interface, -1);
+	return format;
+}
+
+void ast_format_clear(struct ast_format *format)
+{
+	format->id = 0;
+	memset(&format->fattr, 0, sizeof(format->fattr));
+}
+
+/*! \internal
+ * \brief determine if a list of attribute key value pairs are set on a format
+ */
+static int format_isset_helper(const struct ast_format *format, va_list ap)
+{
+	int res;
+	struct interface_ao2_wrapper *wrapper;
+	struct ast_format tmp = {
+		.id = format->id,
+		.fattr = { { 0, }, },
+	};
+
+	if (!(wrapper = find_interface(format))) {
 		return -1;
 	}
 
-	format_interface = ao2_alloc_options(sizeof(*format_interface) + strlen(codec) + 1,
-		NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!format_interface) {
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface ||
+		!wrapper->interface->format_attr_set ||
+		!wrapper->interface->format_attr_cmp) {
+
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
 		return -1;
 	}
-	format_interface->interface = interface;
-	strcpy(format_interface->codec, codec); /* Safe */
 
-	ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK);
-	ao2_ref(format_interface, -1);
+	/* if isset is present, use that function, else just build a new
+	 * format and use the cmp function */
+	if (wrapper->interface->format_attr_isset) {
+		res = wrapper->interface->format_attr_isset(&format->fattr, ap);
+	} else {
+		wrapper->interface->format_attr_set(&tmp.fattr, ap);
+		/* use our tmp structure to tell if the attributes are set or not */
+		res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
+		res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
+	}
 
-	ast_verb(2, "Registered format interface for codec '%s'\n", codec);
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
 
-	return 0;
+	return res;
 }
 
-void *ast_format_get_attribute_data(const struct ast_format *format)
+int ast_format_isset(const struct ast_format *format, ... )
 {
-	return format->attribute_data;
+	va_list ap;
+	int res;
+
+	va_start(ap, format);
+	res = format_isset_helper(format, ap);
+	va_end(ap);
+	return res;
 }
 
-void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
+int ast_format_get_value(const struct ast_format *format, int key, void *value)
 {
-	format->attribute_data = attribute_data;
+	int res = 0;
+	struct interface_ao2_wrapper *wrapper;
+
+	if (!(wrapper = find_interface(format))) {
+		return -1;
+	}
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface ||
+		!wrapper->interface->format_attr_get_val) {
+
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
+		return -1;
+	}
+
+	res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
+
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
+
+	return res;
 }
 
-/*! \brief Destructor for media formats */
-static void format_destroy(void *obj)
+/*! \internal
+ * \brief cmp format attributes using an interface
+ */
+static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
 {
-	struct ast_format *format = obj;
+	enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
+	struct interface_ao2_wrapper *wrapper;
+
+	if (!(wrapper = find_interface(format1))) {
+		return res;
+	}
 
-	if (format->interface) {
-		format->interface->format_destroy(format);
+	ao2_rdlock(wrapper);
+	if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
+		ao2_unlock(wrapper);
+		ao2_ref(wrapper, -1);
+		return res;
 	}
 
-	ao2_cleanup(format->codec);
+	res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
+
+	ao2_unlock(wrapper);
+	ao2_ref(wrapper, -1);
+
+	return res;
 }
 
-struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec)
+enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
 {
-	struct ast_format *format;
-	struct format_interface *format_interface;
+	if (format1->id != format2->id) {
+		return AST_FORMAT_CMP_NOT_EQUAL;
+	}
 
-	format = ao2_t_alloc_options(sizeof(*format), format_destroy,
-		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
-	if (!format) {
-		return NULL;
+	return format_cmp_helper(format1, format2);
+}
+
+/*! \internal
+ * \brief get joint format attributes using an interface
+ */
+static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
+{
+	int res = 0;
+	struct interface_ao2_wrapper *wrapper;
+
+	if (!(wrapper = find_interface(format1))) {
+		/* if no interface is present, we assume formats are joint by id alone */
+		return res;
 	}
-	format->name = format_name;
-	format->codec = ao2_bump(codec);
 
-	format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY);
-	if (format_interface) {
-		format->interface = format_interface->interface;
-		ao2_ref(format_interface, -1);
+	ao2_rdlock(wrapper);
+	if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
+		res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
 	}
+	ao2_unlock(wrapper);
 
-	return format;
+	ao2_ref(wrapper, -1);
+
+	return res;
 }
 
-struct ast_format *ast_format_clone(const struct ast_format *format)
+int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
 {
-	struct ast_format *cloned = ast_format_create_named(format->name, format->codec);
+	if (format1->id != format2->id) {
+		return -1;
+	}
+	result->id = format1->id;
+	return format_joint_helper(format1, format2, result);
+}
 
-	if (!cloned) {
-		return NULL;
+
+uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
+{
+	switch (id) {
+	/*! G.723.1 compression */
+	case AST_FORMAT_G723_1:
+		return (1ULL << 0);
+	/*! GSM compression */
+	case AST_FORMAT_GSM:
+		return (1ULL << 1);
+	/*! Raw mu-law data (G.711) */
+	case AST_FORMAT_ULAW:
+		return (1ULL << 2);
+	/*! Raw A-law data (G.711) */
+	case AST_FORMAT_ALAW:
+		return (1ULL << 3);
+	/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
+	case AST_FORMAT_G726_AAL2:
+		return (1ULL << 4);
+	/*! ADPCM (IMA) */
+	case AST_FORMAT_ADPCM:
+		return (1ULL << 5);
+	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+	case AST_FORMAT_SLINEAR:
+		return (1ULL << 6);
+	/*! LPC10, 180 samples/frame */
+	case AST_FORMAT_LPC10:
+		return (1ULL << 7);
+	/*! G.729A audio */
+	case AST_FORMAT_G729A:
+		return (1ULL << 8);
+	/*! SpeeX Free Compression */
+	case AST_FORMAT_SPEEX:
+		return (1ULL << 9);
+	/*! iLBC Free Compression */
+	case AST_FORMAT_ILBC:
+		return (1ULL << 10);
+	/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
+	case AST_FORMAT_G726:
+		return (1ULL << 11);
+	/*! G.722 */
+	case AST_FORMAT_G722:
+		return (1ULL << 12);
+	/*! G.722.1 (also known as Siren7, 32kbps assumed) */
+	case AST_FORMAT_SIREN7:
+		return (1ULL << 13);
+	/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+	case AST_FORMAT_SIREN14:
+		return (1ULL << 14);
+	/*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+	case AST_FORMAT_SLINEAR16:
+		return (1ULL << 15);
+	/*! G.719 (64 kbps assumed) */
+	case AST_FORMAT_G719:
+		return (1ULL << 32);
+	/*! SpeeX Wideband (16kHz) Free Compression */
+	case AST_FORMAT_SPEEX16:
+		return (1ULL << 33);
+	/*! Raw mu-law data (G.711) */
+	case AST_FORMAT_TESTLAW:
+		return (1ULL << 47);
+
+	/*! H.261 Video */
+	case AST_FORMAT_H261:
+		return (1ULL << 18);
+	/*! H.263 Video */
+	case AST_FORMAT_H263:
+		return (1ULL << 19);
+	/*! H.263+ Video */
+	case AST_FORMAT_H263_PLUS:
+		return (1ULL << 20);
+	/*! H.264 Video */
+	case AST_FORMAT_H264:
+		return (1ULL << 21);
+	/*! MPEG4 Video */
+	case AST_FORMAT_MP4_VIDEO:
+		return (1ULL << 22);
+
+	/*! JPEG Images */
+	case AST_FORMAT_JPEG:
+		return (1ULL << 16);
+	/*! PNG Images */
+	case AST_FORMAT_PNG:
+		return (1ULL << 17);
+
+	/*! T.140 RED Text format RFC 4103 */
+	case AST_FORMAT_T140RED:
+		return (1ULL << 26);
+	/*! T.140 Text format - ITU T.140, RFC 4103 */
+	case AST_FORMAT_T140:
+		return (1ULL << 27);
+	default:
+		return 0; /* not supported by old bitfield. */
 	}
 
-	if (cloned->interface && cloned->interface->format_clone(format, cloned)) {
-		ao2_ref(cloned, -1);
-		return NULL;
+	return 0;
+
+}
+uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
+{
+	return ast_format_id_to_old_bitfield(format->id);
+}
+
+struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
+{
+	switch (src) {
+	/*! G.723.1 compression */
+	case (1ULL << 0):
+		return ast_format_set(dst, AST_FORMAT_G723_1, 0);
+	/*! GSM compression */
+	case (1ULL << 1):
+		return ast_format_set(dst, AST_FORMAT_GSM, 0);
+	/*! Raw mu-law data (G.711) */
+	case (1ULL << 2):
+		return ast_format_set(dst, AST_FORMAT_ULAW, 0);
+	/*! Raw A-law data (G.711) */
+	case (1ULL << 3):
+		return ast_format_set(dst, AST_FORMAT_ALAW, 0);
+	/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
+	case (1ULL << 4):
+		return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
+	/*! ADPCM (IMA) */
+	case (1ULL << 5):
+		return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
+	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+	case (1ULL << 6):
+		return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
+	/*! LPC10, 180 samples/frame */
+	case (1ULL << 7):
+		return ast_format_set(dst, AST_FORMAT_LPC10, 0);
+	/*! G.729A audio */
+	case (1ULL << 8):
+		return ast_format_set(dst, AST_FORMAT_G729A, 0);
+	/*! SpeeX Free Compression */
+	case (1ULL << 9):
+		return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
+	/*! iLBC Free Compression */
+	case (1ULL << 10):
+		return ast_format_set(dst, AST_FORMAT_ILBC, 0);
+	/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
+	case (1ULL << 11):
+		return ast_format_set(dst, AST_FORMAT_G726, 0);
+	/*! G.722 */
+	case (1ULL << 12):
+		return ast_format_set(dst, AST_FORMAT_G722, 0);
+	/*! G.722.1 (also known as Siren7, 32kbps assumed) */
+	case (1ULL << 13):
+		return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
+	/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+	case (1ULL << 14):
+		return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
+	/*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+	case (1ULL << 15):
+		return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
+	/*! G.719 (64 kbps assumed) */
+	case (1ULL << 32):
+		return ast_format_set(dst, AST_FORMAT_G719, 0);
+	/*! SpeeX Wideband (16kHz) Free Compression */
+	case (1ULL << 33):
+		return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
+	/*! Raw mu-law data (G.711) */
+	case (1ULL << 47):
+		return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
+
+	/*! H.261 Video */
+	case (1ULL << 18):
+		return ast_format_set(dst, AST_FORMAT_H261, 0);
+	/*! H.263 Video */
+	case (1ULL << 19):
+		return ast_format_set(dst, AST_FORMAT_H263, 0);
+	/*! H.263+ Video */
+	case (1ULL << 20):
+		return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
+	/*! H.264 Video */
+	case (1ULL << 21):
+		return ast_format_set(dst, AST_FORMAT_H264, 0);
+	/*! MPEG4 Video */
+	case (1ULL << 22):
+		return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
+
+	/*! JPEG Images */
+	case (1ULL << 16):
+		return ast_format_set(dst, AST_FORMAT_JPEG, 0);
+	/*! PNG Images */
+	case (1ULL << 17):
+		return ast_format_set(dst, AST_FORMAT_PNG, 0);
+
+	/*! T.140 RED Text format RFC 4103 */
+	case (1ULL << 26):
+		return ast_format_set(dst, AST_FORMAT_T140RED, 0);
+	/*! T.140 Text format - ITU T.140, RFC 4103 */
+	case (1ULL << 27):
+		return ast_format_set(dst, AST_FORMAT_T140, 0);
 	}
+	ast_format_clear(dst);
+	return NULL;
+}
 
-	return cloned;
+enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
+{
+	struct ast_format dst;
+	if (ast_format_from_old_bitfield(&dst, src)) {
+		return dst.id;
+	}
+	return 0;
 }
 
-struct ast_format *ast_format_create(struct ast_codec *codec)
+int ast_format_is_slinear(const struct ast_format *format)
 {
-	return ast_format_create_named(codec->name, codec);
+	if (format->id == AST_FORMAT_SLINEAR ||
+		format->id == AST_FORMAT_SLINEAR12 ||
+		format->id == AST_FORMAT_SLINEAR16 ||
+		format->id == AST_FORMAT_SLINEAR24 ||
+		format->id == AST_FORMAT_SLINEAR32 ||
+		format->id == AST_FORMAT_SLINEAR44 ||
+		format->id == AST_FORMAT_SLINEAR48 ||
+		format->id == AST_FORMAT_SLINEAR96 ||
+		format->id == AST_FORMAT_SLINEAR192) {
+		return 1;
+	}
+	return 0;
 }
 
-enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
+enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
 {
-	const struct ast_format_interface *interface;
+	if (rate >= 192000) {
+		return AST_FORMAT_SLINEAR192;
+	} else if (rate >= 96000) {
+		return AST_FORMAT_SLINEAR96;
+	} else if (rate >= 48000) {
+		return AST_FORMAT_SLINEAR48;
+	} else if (rate >= 44100) {
+		return AST_FORMAT_SLINEAR44;
+	} else if (rate >= 32000) {
+		return AST_FORMAT_SLINEAR32;
+	} else if (rate >= 24000) {
+		return AST_FORMAT_SLINEAR24;
+	} else if (rate >= 16000) {
+		return AST_FORMAT_SLINEAR16;
+	} else if (rate >= 12000) {
+		return AST_FORMAT_SLINEAR12;
+	}
+	return AST_FORMAT_SLINEAR;
+}
 
-	if (format1 == NULL || format2 == NULL) {
-		return AST_FORMAT_CMP_NOT_EQUAL;
+const char* ast_getformatname(const struct ast_format *format)
+{
+	int x;
+	const char *ret = "unknown";
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			ret = f_list[x].name;
+			break;
+		}
 	}
+	f_list = ast_format_list_destroy(f_list);
+	return ret;
+}
 
-	if (format1 == format2) {
-		return AST_FORMAT_CMP_EQUAL;
+
+char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
+{
+	int x;
+	unsigned len;
+	char *start, *end = buf;
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	if (!size) {
+		f_list = ast_format_list_destroy(f_list);
+		return buf;
 	}
+	snprintf(end, size, "(");
+	len = strlen(end);
+	end += len;
+	size -= len;
+	start = end;
+	for (x = 0; x < f_len; x++) {
+		if (f_list[x].format.id == id) {
+			snprintf(end, size, "%s|", f_list[x].name);
+			len = strlen(end);
+			end += len;
+			size -= len;
+		}
+	}
+	if (start == end) {
+		ast_copy_string(start, "nothing)", size);
+	} else if (size > 1) {
+		*(end - 1) = ')';
+	}
+	f_list = ast_format_list_destroy(f_list);
+	return buf;
+}
 
-	if (format1->codec != format2->codec) {
-		return AST_FORMAT_CMP_NOT_EQUAL;
+static struct ast_codec_alias_table {
+	const char *alias;
+	const char *realname;
+} ast_codec_alias_table[] = {
+	{ "slinear", "slin"},
+	{ "slinear16", "slin16"},
+	{ "g723.1", "g723"},
+	{ "g722.1", "siren7"},
+	{ "g722.1c", "siren14"},
+};
+
+static const char *ast_expand_codec_alias(const char *in)
+{
+	int x;
+
+	for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
+		if (!strcmp(in,ast_codec_alias_table[x].alias))
+			return ast_codec_alias_table[x].realname;
 	}
+	return in;
+}
+
+struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
+{
+	int x;
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
 
-	interface = format1->interface ? format1->interface : format2->interface;
+	for (x = 0; x < f_len; x++) {
+		if (!strcasecmp(f_list[x].name, name) ||
+			 !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
 
-	if (interface && interface->format_cmp) {
-		return interface->format_cmp(format1, format2);
+			ast_format_copy(result, &f_list[x].format);
+			f_list = ast_format_list_destroy(f_list);
+			return result;
+		}
 	}
+	f_list = ast_format_list_destroy(f_list);
 
-	return AST_FORMAT_CMP_EQUAL;
+	return NULL;
 }
 
-struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2)
+const char *ast_codec2str(struct ast_format *format)
 {
-	const struct ast_format_interface *interface;
+	int x;
+	const char *ret = "unknown";
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			ret = f_list[x].desc;
+			break;
+		}
+	}
+	f_list = ast_format_list_destroy(f_list);
+	return ret;
+}
 
-	if (format1->codec != format2->codec) {
+int ast_format_rate(const struct ast_format *format)
+{
+	switch (format->id) {
+	case AST_FORMAT_SLINEAR12:
+		return 12000;
+	case AST_FORMAT_SLINEAR24:
+		return 24000;
+	case AST_FORMAT_SLINEAR32:
+		return 32000;
+	case AST_FORMAT_SLINEAR44:
+		return 44100;
+	case AST_FORMAT_SLINEAR48:
+		return 48000;
+	case AST_FORMAT_SLINEAR96:
+		return 96000;
+	case AST_FORMAT_SLINEAR192:
+		return 192000;
+	case AST_FORMAT_G722:
+	case AST_FORMAT_SLINEAR16:
+	case AST_FORMAT_SIREN7:
+	case AST_FORMAT_SPEEX16:
+		return 16000;
+	case AST_FORMAT_SIREN14:
+	case AST_FORMAT_SPEEX32:
+		return 32000;
+	case AST_FORMAT_G719:
+		return 48000;
+	case AST_FORMAT_SILK:
+		if (!(ast_format_isset(format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_24KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 24000;
+		} else if (!(ast_format_isset(format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 16000;
+		} else if (!(ast_format_isset(format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_12KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 12000;
+		} else {
+			return 8000;
+		}
+	case AST_FORMAT_CELT:
+	{
+		int samplerate;
+		if (!(ast_format_get_value(format,
+			CELT_ATTR_KEY_SAMP_RATE,
+			&samplerate))) {
+			return samplerate;
+		}
+	}
+	default:
+		return 8000;
+	}
+}
+
+static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int x, found=0;
+	size_t f_len;
+	const struct ast_format_list *f_list;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "core show codecs [audio|video|image|text]";
+		e->usage =
+			"Usage: core show codecs [audio|video|image|text]\n"
+			"       Displays codec mapping\n";
+		return NULL;
+	case CLI_GENERATE:
 		return NULL;
 	}
 
-	/* If the two formats are the same structure OR if the codec is the same and no attributes
-	 * exist we can immediately return a format with reference count bumped up, since they are
-	 * the same.
-	 */
-	if ((ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL && !format1->attribute_data && !format2->attribute_data)) {
-		return ao2_bump((struct ast_format*)format1);
+	if ((a->argc < 3) || (a->argc > 4)) {
+		return CLI_SHOWUSAGE;
 	}
 
-	interface = format1->interface ? format1->interface : format2->interface;
+	f_list = ast_format_list_get(&f_len);
+	if (!ast_opt_dont_warn) {
+		ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
+				"\tIt does not indicate anything about your configuration.\n");
+	}
 
-	/* If there is attribute data on either there has to be an interface */
-	return interface->format_get_joint(format1, format2);
+	ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
+	ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
+
+	for (x = 0; x < f_len; x++) {
+		if (a->argc == 4) {
+			if (!strcasecmp(a->argv[3], "audio")) {
+				if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
+					continue;
+				}
+			} else if (!strcasecmp(a->argv[3], "video")) {
+				if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
+					continue;
+				}
+			} else if (!strcasecmp(a->argv[3], "image")) {
+				if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
+					continue;
+				}
+			} else if (!strcasecmp(a->argv[3], "text")) {
+				if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
+					continue;
+				}
+			} else {
+				continue;
+			}
+		}
+
+		ast_cli(a->fd, "%8u %5s %8s (%s)\n",
+			f_list[x].format.id,
+			(AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
+			(AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_IMAGE)  ? "image" :
+			(AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_VIDEO) ? "video" :
+			(AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_TEXT)  ? "text"  :
+			"(unk)",
+			f_list[x].name,
+			f_list[x].desc);
+		found = 1;
+	}
+
+	f_list = ast_format_list_destroy(f_list);
+	if (!found) {
+		return CLI_SHOWUSAGE;
+	} else {
+		return CLI_SUCCESS;
+	}
 }
 
-struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, const char *value)
+static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	const struct ast_format_interface *interface = format->interface;
+	enum ast_format_id format_id;
+	int x, found = 0;
+	int type_punned_codec;
+	size_t f_len;
+	const struct ast_format_list *f_list;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "core show codec";
+		e->usage =
+			"Usage: core show codec <number>\n"
+			"       Displays codec mapping\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
+		return CLI_SHOWUSAGE;
+	}
+	format_id = type_punned_codec;
 
-	if (!interface) {
-		struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
-		if (format_interface) {
-			interface = format_interface->interface;
-			ao2_ref(format_interface, -1);
+	f_list = ast_format_list_get(&f_len);
+	for (x = 0; x < f_len; x++) {
+		if (f_list[x].format.id == format_id) {
+			found = 1;
+			ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
 		}
 	}
 
-	if (!interface || !interface->format_attribute_set) {
-		return ao2_bump((struct ast_format*)format);
+	if (!found) {
+		ast_cli(a->fd, "Codec %u not found\n", format_id);
 	}
 
-	return interface->format_attribute_set(format, name, value);
+	f_list = ast_format_list_destroy(f_list);
+	return CLI_SUCCESS;
 }
 
-struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
+/* Builtin Asterisk CLI-commands for debugging */
+static struct ast_cli_entry my_clis[] = {
+	AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
+	AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
+};
+int init_framer(void)
 {
-	const struct ast_format_interface *interface = format->interface;
+	return 0;
+}
 
-	if (!interface) {
-		struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
-		if (format_interface) {
-			interface = format_interface->interface;
-			ao2_ref(format_interface, -1);
-		}
+static int format_list_add_custom(struct ast_format_list *new)
+{
+	RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
+	if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
+		return -1;
 	}
-
-	if (!interface || !interface->format_parse_sdp_fmtp) {
-		return ao2_bump((struct ast_format*)format);
+	memcpy(entry, new, sizeof(struct ast_format_list));
+	entry->custom_entry = 1;
+	ao2_link(format_list, entry);
+	return 0;
+}
+static int format_list_add_static(
+	const struct ast_format *format,
+	const char *name,
+	int samplespersecond,
+	const char *description,
+	int fr_len,
+	int min_ms,
+	int max_ms,
+	int inc_ms,
+	int def_ms,
+	unsigned int flags,
+	int cur_ms)
+{
+	struct ast_format_list *entry;
+	if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
+		return -1;
 	}
+	ast_format_copy(&entry->format, format);
+	ast_copy_string(entry->name, name, sizeof(entry->name));
+	ast_copy_string(entry->desc, description, sizeof(entry->desc));
+	entry->samplespersecond = samplespersecond;
+	entry->fr_len = fr_len;
+	entry->min_ms = min_ms;
+	entry->max_ms = max_ms;
+	entry->inc_ms = inc_ms;
+	entry->def_ms = def_ms;
+	entry->flags = flags;
+	entry->cur_ms = cur_ms;
+	entry->custom_entry = 0;
+
+	ao2_link(format_list, entry);
+	ao2_ref(entry, -1);
+	return 0;
+}
 
-	return interface->format_parse_sdp_fmtp(format, attributes);
+static int list_all_custom(void *obj, void *arg, int flag)
+{
+	struct ast_format_list *entry = obj;
+	return entry->custom_entry ? CMP_MATCH : 0;
 }
 
-void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+static int list_cmp_cb(void *obj, void *arg, int flags)
 {
-	if (!format->interface || !format->interface->format_generate_sdp_fmtp) {
-		return;
+	struct ast_format_list *entry1 = obj;
+	struct ast_format_list *entry2 = arg;
+
+	return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+const struct ast_format_list *ast_format_list_get(size_t *size)
+{
+	struct ast_format_list *list;
+	ast_rwlock_rdlock(&format_list_array_lock);
+	ao2_ref(format_list_array, 1);
+	list = format_list_array;
+	*size = format_list_array_len;
+	ast_rwlock_unlock(&format_list_array_lock);
+	return list;
+}
+const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
+{
+	ao2_ref((void *) list, -1);
+	return NULL;
+}
+
+static int build_format_list_array(void)
+{
+	struct ast_format_list *tmp;
+	size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
+	int i = 0;
+	struct ao2_iterator it;
+
+	ast_rwlock_wrlock(&format_list_array_lock);
+	tmp = format_list_array;
+	if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
+		format_list_array = tmp;
+		ast_rwlock_unlock(&format_list_array_lock);
+		return -1;
+	}
+	format_list_array_len = ao2_container_count(format_list);
+	if (tmp) {
+		ao2_ref(tmp, -1);
 	}
 
-	format->interface->format_generate_sdp_fmtp(format, payload, str);
+	/* walk through the container adding elements to the static array */
+	it = ao2_iterator_init(format_list, 0);
+	while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
+		memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
+		ao2_ref(tmp, -1);
+		i++;
+	}
+	ao2_iterator_destroy(&it);
+
+	ast_rwlock_unlock(&format_list_array_lock);
+	return 0;
 }
 
-unsigned int ast_format_get_codec_id(const struct ast_format *format)
+static int format_list_init(void)
 {
-	return format->codec->id;
+	struct ast_format tmpfmt;
+	if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) {
+		return -1;
+	}
+	/*
+	 * initiate static entries XXX DO NOT CHANGE THIS ORDER!
+	 *
+	 * Reason:
+	 * The order is requried by chan_iax2 to send out the IAX_IE_CODEC_PREFS
+	 * list over the wire.  The following order is historical to how v1.8
+	 * and earlier listed the formats in format.c:AST_FORMAT_LIST[].  These
+	 * formats have format compatibility bits assigned which makes chan_iax2
+	 * in particular and other legacy modules aware of them.
+	 */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), "g723", 8000, "G.723.1", 20, 30, 300, 30, 30, 0, 0);       /*!< G723.1 */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm",  8000, "GSM", 33, 20, 300, 20, 20, 0, 0);              /*!< codec_gsm.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20, 0, 0);     /*!< codec_ulaw.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20, 0, 0);     /*!< codec_alaw.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0);   /*!< codec_g726.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20, 0, 0);        /*!< codec_adpcm.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0); /*!< Signed linear */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0);           /*!< codec_lpc10.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729, 0);   /*!< Binary commercial distribution */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0);          /*!< codec_speex.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0);   /*!< codec_speex.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0);                 /*!< codec_ilbc.c */ /* inc=30ms - workaround */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0);               /*!< codec_g722.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (16kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0);          /*!< See format_jpeg.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0);             /*!< PNG Image format */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0);         /*!< H.261 Video Passthrough */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0);         /*!< H.263 Passthrough support, see format_h263.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0);  /*!< H.263plus passthrough support See format_h263.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0);         /*!< Passthrough support, see format_h263.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0);   /*!< Passthrough support for MPEG4 */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0);     /*!< Redundant T.140 Realtime Text */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0);      /*!< Passthrough support for T.140 Realtime Text */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20, 0, 0);	/*!< Binary commercial distribution */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_TESTLAW, 0), "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20, 0, 0);    /*!< codec_ulaw.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
+
+	/*
+	 * ORDER MAY CHANGE AFTER THIS POINT IN THE LIST
+	 *
+	 * Reason:
+	 * These formats and any that follow do NOT have format compatibility
+	 * bits assigned so chan_iax2 in particular and other legacy modules
+	 * that use compatibility bits will not be aware of them.
+	 */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0);   /*!< codec_speex.c */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (12kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (24kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0), "slin32", 32000, "16 bit Signed Linear PCM (32kHz)", 640, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (32kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0), "slin44", 44100, "16 bit Signed Linear PCM (44kHz)", 882, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (44.1kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (48kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (96kHz) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (192kHz) */
+
+	return 0;
 }
 
-const char *ast_format_get_name(const struct ast_format *format)
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void format_list_shutdown(void)
 {
-	return format->name;
+	ast_rwlock_destroy(&format_list_array_lock);
+	if (format_list) {
+		ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
+		format_list = NULL;
+	}
+	if (format_list_array) {
+		ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
+		format_list_array = NULL;
+	}
 }
 
-const char *ast_format_get_codec_name(const struct ast_format *format)
+int ast_format_list_init(void)
 {
-	return format->codec->name;
+	if (ast_rwlock_init(&format_list_array_lock)) {
+		return -1;
+	}
+	if (format_list_init()) {
+		goto init_list_cleanup;
+	}
+	if (build_format_list_array()) {
+		goto init_list_cleanup;
+	}
+
+	ast_register_cleanup(format_list_shutdown);
+	return 0;
+init_list_cleanup:
+
+	format_list_shutdown();
+	return -1;
 }
 
-int ast_format_can_be_smoothed(const struct ast_format *format)
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void format_attr_shutdown(void)
 {
-	return format->codec->smooth;
+	ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
+	if (interfaces) {
+		ao2_ref(interfaces, -1);
+		interfaces = NULL;
+	}
 }
 
-enum ast_media_type ast_format_get_type(const struct ast_format *format)
+int ast_format_attr_init(void)
 {
-	return format->codec->type;
+	interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
+		283, interface_hash_cb, interface_cmp_cb);
+	if (!interfaces) {
+		return -1;
+	}
+
+	ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
+	ast_register_cleanup(format_attr_shutdown);
+	return 0;
 }
 
-unsigned int ast_format_get_default_ms(const struct ast_format *format)
+static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
 {
-	return format->codec->default_ms;
+	if (!entry->samplespersecond) {
+		ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
+	}
+	ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
+	if (!has_interface(&entry->format)) {
+		return -1;
+	}
+
+	snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000);
+
+	ast_format_append(&entry->format,
+		CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
+		CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
+		CELT_ATTR_KEY_FRAME_SIZE, framesize,
+		AST_FORMAT_ATTR_END);
+
+	entry->fr_len = 80;
+	entry->min_ms = 20;
+	entry->max_ms = 20;
+	entry->inc_ms = 20;
+	entry->def_ms = 20;
+	return 0;
 }
 
-unsigned int ast_format_get_minimum_ms(const struct ast_format *format)
+static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
 {
-	return format->codec->minimum_ms;
+	if (!entry->samplespersecond) {
+		ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
+	}
+	ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
+
+	if (!has_interface(&entry->format)) {
+		return -1;
+	}
+
+	switch (entry->samplespersecond) {
+	case 8000:
+		ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
+		ast_format_append(&entry->format,
+			SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
+			AST_FORMAT_ATTR_END);
+		break;
+	case 12000:
+		ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
+		ast_format_append(&entry->format,
+			SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
+			AST_FORMAT_ATTR_END);
+		break;
+	case 16000:
+		ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
+		ast_format_append(&entry->format,
+			SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END);
+		break;
+	case 24000:
+		ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
+		ast_format_append(&entry->format,
+			SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
+			AST_FORMAT_ATTR_END);
+		break;
+	default:
+		ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond);
+		return -1;
+	}
+	ast_format_append(&entry->format,
+			SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
+			SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
+			SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
+			SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
+			AST_FORMAT_ATTR_END);
+
+	entry->fr_len = 80;
+	entry->min_ms = 20;
+	entry->max_ms = 20;
+	entry->inc_ms = 20;
+	entry->def_ms = 20;
+	return 0;
 }
 
-unsigned int ast_format_get_maximum_ms(const struct ast_format *format)
+static int conf_process_format_name(const char *name, enum ast_format_id *id)
 {
-	return format->codec->maximum_ms;
+	if (!strcasecmp(name, "silk")) {
+		*id = AST_FORMAT_SILK;
+	} else if (!strcasecmp(name, "celt")) {
+		*id = AST_FORMAT_CELT;
+	} else {
+		*id = 0;
+		return -1;
+	}
+	return 0;
 }
 
-unsigned int ast_format_get_minimum_bytes(const struct ast_format *format)
+static int conf_process_sample_rate(const char *rate, unsigned int *result)
 {
-	return format->codec->minimum_bytes;
+	if (!strcasecmp(rate, "8000")) {
+		*result = 8000;
+	} else if (!strcasecmp(rate, "12000")) {
+		*result = 12000;
+	} else if (!strcasecmp(rate, "16000")) {
+		*result = 16000;
+	} else if (!strcasecmp(rate, "24000")) {
+		*result = 24000;
+	} else if (!strcasecmp(rate, "32000")) {
+		*result = 32000;
+	} else if (!strcasecmp(rate, "44100")) {
+		*result = 44100;
+	} else if (!strcasecmp(rate, "48000")) {
+		*result = 48000;
+	} else if (!strcasecmp(rate, "96000")) {
+		*result = 96000;
+	} else if (!strcasecmp(rate, "192000")) {
+		*result = 192000;
+	} else {
+		*result = 0;
+		return -1;
+	}
+
+	return 0;
 }
+static int load_format_config(void)
+{
+	struct ast_flags config_flags = { 0, };
+	struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
+	struct ast_format_list entry;
+	struct ast_variable *var;
+	char *cat = NULL;
+	int add_it = 0;
+
+	struct {
+		enum ast_format_id id;
+		unsigned int maxbitrate;
+		unsigned int framesize;
+		unsigned int packetloss_percentage;
+		int usefec;
+		int usedtx;
+	} settings;
+
+	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
+		return 0;
+	}
+
+	/* remove all custom formats from the AO2 Container. Note, this has no affect on the
+	 * global format list until the list is rebuild.  That is why this is okay to do while
+	 * reloading the config. */
+	ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
+
+	while ((cat = ast_category_browse(cfg, cat))) {
+		memset(&entry, 0, sizeof(entry));
+		memset(&settings, 0, sizeof(settings));
+		add_it = 0;
 
-unsigned int ast_format_get_sample_rate(const struct ast_format *format)
+		if (!(ast_variable_retrieve(cfg, cat, "type"))) {
+			continue;
+		}
+		ast_copy_string(entry.name, cat, sizeof(entry.name));
+		var = ast_variable_browse(cfg, cat);
+		for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
+			if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
+				ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
+					var->value, var->lineno, FORMAT_CONFIG);
+				continue;
+			} else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
+				ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
+						var->value, var->lineno, FORMAT_CONFIG);
+			} else if (!strcasecmp(var->name, "maxbitrate")) {
+				if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
+					ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
+						var->value, var->lineno, FORMAT_CONFIG);
+				}
+			} else if (!strcasecmp(var->name, "framesize")) {
+				if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
+					ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
+						var->value, var->lineno, FORMAT_CONFIG);
+				}
+			} else if (!strcasecmp(var->name, "dtx")) {
+				settings.usedtx = ast_true(var->value) ? 1 : 0;
+			} else if (!strcasecmp(var->name, "fec")) {
+				settings.usefec = ast_true(var->value) ? 1 : 0;
+			} else if (!strcasecmp(var->name, "packetloss_percentage")) {
+				if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
+					ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
+						var->value, var->lineno, FORMAT_CONFIG);
+				}
+			}
+		}
+
+		switch (settings.id) {
+		case AST_FORMAT_SILK:
+			if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
+				add_it = 1;
+			}
+			break;
+		case AST_FORMAT_CELT:
+			if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
+				add_it = 1;
+			}
+			break;
+		default:
+			ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
+		}
+
+		if (add_it) {
+			format_list_add_custom(&entry);
+		}
+	}
+	ast_config_destroy(cfg);
+	build_format_list_array();
+	return 0;
+}
+
+int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
 {
-	return format->codec->sample_rate;
+	int x;
+	size_t f_len;
+	const struct ast_format_list *f_list;
+	struct interface_ao2_wrapper *wrapper;
+	struct interface_ao2_wrapper tmp_wrapper = {
+		.id = interface->id,
+	};
+
+	/*
+	 * Grab the write lock before checking for duplicates in
+	 * anticipation of adding a new interface and to prevent a
+	 * duplicate from sneaking in between the check and add.
+	 */
+	ao2_wrlock(interfaces);
+
+	/* check for duplicates first*/
+	if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
+		ao2_unlock(interfaces);
+		ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id);
+		ao2_ref(wrapper, -1);
+		return -1;
+	}
+
+	wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
+	if (!wrapper) {
+		ao2_unlock(interfaces);
+		return -1;
+	}
+
+	wrapper->interface = interface;
+	wrapper->id = interface->id;
+
+	/* The write lock is already held. */
+	ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
+	ao2_unlock(interfaces);
+
+	ao2_ref(wrapper, -1);
+
+	/* This will find all custom formats in codecs.conf for this new registered interface */
+	load_format_config();
+
+	/* update the RTP engine to all custom formats created for this interface */
+	f_list = ast_format_list_get(&f_len);
+	for (x = 0; x < f_len; x++) {
+		if (f_list[x].format.id == tmp_wrapper.id) {
+			ast_rtp_engine_load_format(&f_list[x].format);
+		}
+	}
+	f_list = ast_format_list_destroy(f_list);
+	return 0;
 }
 
-unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples)
+int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
 {
-	return ast_codec_determine_length(format->codec, samples);
+	int x;
+	size_t f_len;
+	const struct ast_format_list *f_list;
+	struct interface_ao2_wrapper *wrapper;
+	struct interface_ao2_wrapper tmp_wrapper = {
+		.id = interface->id,
+	};
+
+	if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
+		return -1;
+	}
+
+	ao2_wrlock(wrapper);
+	wrapper->interface = NULL;
+	ao2_unlock(wrapper);
+
+	ao2_ref(wrapper, -1);
+
+	/* update the RTP engine to remove all custom formats created for this interface */
+	f_list = ast_format_list_get(&f_len);
+	for (x = 0; x < f_len; x++) {
+		if (f_list[x].format.id == tmp_wrapper.id) {
+			ast_rtp_engine_unload_format(&f_list[x].format);
+		}
+	}
+
+	/* This will remove all custom formats previously created for this interface */
+	load_format_config();
+	f_list = ast_format_list_destroy(f_list);
+	return 0;
 }
diff --git a/main/format_cache.c b/main/format_cache.c
deleted file mode 100644
index b86ff20..0000000
--- a/main/format_cache.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Media Format Cache API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421678 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-
-/*!
- * \brief Built-in cached signed linear 8kHz format.
- */
-struct ast_format *ast_format_slin;
-
-/*!
- * \brief Built-in cached signed linear 12kHz format.
- */
-struct ast_format *ast_format_slin12;
-
-/*!
- * \brief Built-in cached signed linear 16kHz format.
- */
-struct ast_format *ast_format_slin16;
-
-/*!
- * \brief Built-in cached signed linear 24kHz format.
- */
-struct ast_format *ast_format_slin24;
-
-/*!
- * \brief Built-in cached signed linear 32kHz format.
- */
-struct ast_format *ast_format_slin32;
-
-/*!
- * \brief Built-in cached signed linear 44kHz format.
- */
-struct ast_format *ast_format_slin44;
-
-/*!
- * \brief Built-in cached signed linear 48kHz format.
- */
-struct ast_format *ast_format_slin48;
-
-/*!
- * \brief Built-in cached signed linear 96kHz format.
- */
-struct ast_format *ast_format_slin96;
-
-/*!
- * \brief Built-in cached signed linear 192kHz format.
- */
-struct ast_format *ast_format_slin192;
-
-/*!
- * \brief Built-in cached ulaw format.
- */
-struct ast_format *ast_format_ulaw;
-
-/*!
- * \brief Built-in cached alaw format.
- */
-struct ast_format *ast_format_alaw;
-
-/*!
- * \brief Built-in cached testlaw format.
- */
-struct ast_format *ast_format_testlaw;
-
-/*!
- * \brief Built-in cached gsm format.
- */
-struct ast_format *ast_format_gsm;
-
-/*!
- * \brief Built-in cached adpcm format.
- */
-struct ast_format *ast_format_adpcm;
-
-/*!
- * \brief Built-in cached g722 format.
- */
-struct ast_format *ast_format_g722;
-
-/*!
- * \brief Built-in cached g726 format.
- */
-struct ast_format *ast_format_g726;
-
-/*!
- * \brief Built-in cached g726-aal2 format.
- */
-struct ast_format *ast_format_g726_aal2;
-
-/*!
- * \brief Built-in cached ilbc format.
- */
-struct ast_format *ast_format_ilbc;
-
-/*!
- * \brief Built-in cached ilbc format.
- */
-struct ast_format *ast_format_lpc10;
-
-/*!
- * \brief Built-in cached speex format.
- */
-struct ast_format *ast_format_speex;
-
-/*!
- * \brief Built-in cached speex at 16kHz format.
- */
-struct ast_format *ast_format_speex16;
-
-/*!
- * \brief Built-in cached speex at 32kHz format.
- */
-struct ast_format *ast_format_speex32;
-
-/*!
- * \brief Built-in cached g723.1 format.
- */
-struct ast_format *ast_format_g723;
-
-/*!
- * \brief Built-in cached g729 format.
- */
-struct ast_format *ast_format_g729;
-
-/*!
- * \brief Built-in cached g719 format.
- */
-struct ast_format *ast_format_g719;
-
-/*!
- * \brief Built-in cached h261 format.
- */
-struct ast_format *ast_format_h261;
-
-/*!
- * \brief Built-in cached h263 format.
- */
-struct ast_format *ast_format_h263;
-
-/*!
- * \brief Built-in cached h263 plus format.
- */
-struct ast_format *ast_format_h263p;
-
-/*!
- * \brief Built-in cached h264 format.
- */
-struct ast_format *ast_format_h264;
-
-/*!
- * \brief Built-in cached mp4 format.
- */
-struct ast_format *ast_format_mp4;
-
-/*!
- * \brief Built-in cached vp8 format.
- */
-struct ast_format *ast_format_vp8;
-
-/*!
- * \brief Built-in cached jpeg format.
- */
-struct ast_format *ast_format_jpeg;
-
-/*!
- * \brief Built-in cached png format.
- */
-struct ast_format *ast_format_png;
-
-/*!
- * \brief Built-in cached siren14 format.
- */
-struct ast_format *ast_format_siren14;
-
-/*!
- * \brief Built-in cached siren7 format.
- */
-struct ast_format *ast_format_siren7;
-
-/*!
- * \brief Built-in cached opus format.
- */
-struct ast_format *ast_format_opus;
-
-/*!
- * \brief Built-in cached t140 format.
- */
-struct ast_format *ast_format_t140;
-
-/*!
- * \brief Built-in cached t140 red format.
- */
-struct ast_format *ast_format_t140_red;
-
-/*!
- * \brief Built-in "null" format.
- */
-struct ast_format *ast_format_none;
-
-/*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */
-#define CACHE_BUCKETS 53
-
-/*! \brief Cached formats */
-static struct ao2_container *formats;
-
-static int format_hash_cb(const void *obj, int flags)
-{
-	const struct ast_format *format;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		return ast_str_case_hash(key);
-	case OBJ_SEARCH_OBJECT:
-		format = obj;
-		return ast_str_case_hash(ast_format_get_name(format));
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int format_cmp_cb(void *obj, void *arg, int flags)
-{
-	const struct ast_format *left = obj;
-	const struct ast_format *right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = ast_format_get_name(right);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcasecmp(ast_format_get_name(left), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncasecmp(ast_format_get_name(left), right_key, strlen(right_key));
-		break;
-	default:
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-
-	return CMP_MATCH;
-}
-
-/*! \brief Function called when the process is shutting down */
-static void format_cache_shutdown(void)
-{
-	ao2_cleanup(formats);
-	formats = NULL;
-
-	ao2_replace(ast_format_g723, NULL);
-	ao2_replace(ast_format_ulaw, NULL);
-	ao2_replace(ast_format_alaw, NULL);
-	ao2_replace(ast_format_gsm, NULL);
-	ao2_replace(ast_format_g726, NULL);
-	ao2_replace(ast_format_g726_aal2, NULL);
-	ao2_replace(ast_format_adpcm, NULL);
-	ao2_replace(ast_format_slin, NULL);
-	ao2_replace(ast_format_slin12, NULL);
-	ao2_replace(ast_format_slin16, NULL);
-	ao2_replace(ast_format_slin24, NULL);
-	ao2_replace(ast_format_slin32, NULL);
-	ao2_replace(ast_format_slin44, NULL);
-	ao2_replace(ast_format_slin48, NULL);
-	ao2_replace(ast_format_slin96, NULL);
-	ao2_replace(ast_format_slin192, NULL);
-	ao2_replace(ast_format_lpc10, NULL);
-	ao2_replace(ast_format_g729, NULL);
-	ao2_replace(ast_format_speex, NULL);
-	ao2_replace(ast_format_speex16, NULL);
-	ao2_replace(ast_format_speex32, NULL);
-	ao2_replace(ast_format_ilbc, NULL);
-	ao2_replace(ast_format_g722, NULL);
-	ao2_replace(ast_format_siren7, NULL);
-	ao2_replace(ast_format_siren14, NULL);
-	ao2_replace(ast_format_testlaw, NULL);
-	ao2_replace(ast_format_g719, NULL);
-	ao2_replace(ast_format_opus, NULL);
-	ao2_replace(ast_format_jpeg, NULL);
-	ao2_replace(ast_format_png, NULL);
-	ao2_replace(ast_format_h261, NULL);
-	ao2_replace(ast_format_h263, NULL);
-	ao2_replace(ast_format_h263p, NULL);
-	ao2_replace(ast_format_h264, NULL);
-	ao2_replace(ast_format_mp4, NULL);
-	ao2_replace(ast_format_vp8, NULL);
-	ao2_replace(ast_format_t140_red, NULL);
-	ao2_replace(ast_format_t140, NULL);
-	ao2_replace(ast_format_none, NULL);
-}
-
-int ast_format_cache_init(void)
-{
-	formats = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, CACHE_BUCKETS,
-		format_hash_cb, format_cmp_cb);
-	if (!formats) {
-		return -1;
-	}
-
-	ast_register_atexit(format_cache_shutdown);
-
-	return 0;
-}
-
-static void set_cached_format(const char *name, struct ast_format *format)
-{
-	if (!strcmp(name, "g723")) {
-		ao2_replace(ast_format_g723, format);
-	} else if (!strcmp(name, "ulaw")) {
-		ao2_replace(ast_format_ulaw, format);
-	} else if (!strcmp(name, "alaw")) {
-		ao2_replace(ast_format_alaw, format);
-	} else if (!strcmp(name, "gsm")) {
-		ao2_replace(ast_format_gsm, format);
-	} else if (!strcmp(name, "g726")) {
-		ao2_replace(ast_format_g726, format);
-	} else if (!strcmp(name, "g726aal2")) {
-		ao2_replace(ast_format_g726_aal2, format);
-	} else if (!strcmp(name, "adpcm")) {
-		ao2_replace(ast_format_adpcm, format);
-	} else if (!strcmp(name, "slin")) {
-		ao2_replace(ast_format_slin, format);
-	} else if (!strcmp(name, "slin12")) {
-		ao2_replace(ast_format_slin12, format);
-	} else if (!strcmp(name, "slin16")) {
-		ao2_replace(ast_format_slin16, format);
-	} else if (!strcmp(name, "slin24")) {
-		ao2_replace(ast_format_slin24, format);
-	} else if (!strcmp(name, "slin32")) {
-		ao2_replace(ast_format_slin32, format);
-	} else if (!strcmp(name, "slin44")) {
-		ao2_replace(ast_format_slin44, format);
-	} else if (!strcmp(name, "slin48")) {
-		ao2_replace(ast_format_slin48, format);
-	} else if (!strcmp(name, "slin96")) {
-		ao2_replace(ast_format_slin96, format);
-	} else if (!strcmp(name, "slin192")) {
-		ao2_replace(ast_format_slin192, format);
-	} else if (!strcmp(name, "lpc10")) {
-		ao2_replace(ast_format_lpc10, format);
-	} else if (!strcmp(name, "g729")) {
-		ao2_replace(ast_format_g729, format);
-	} else if (!strcmp(name, "speex")) {
-		ao2_replace(ast_format_speex, format);
-	} else if (!strcmp(name, "speex16")) {
-		ao2_replace(ast_format_speex16, format);
-	} else if (!strcmp(name, "speex32")) {
-		ao2_replace(ast_format_speex32, format);
-	} else if (!strcmp(name, "ilbc")) {
-		ao2_replace(ast_format_ilbc, format);
-	} else if (!strcmp(name, "g722")) {
-		ao2_replace(ast_format_g722, format);
-	} else if (!strcmp(name, "siren7")) {
-		ao2_replace(ast_format_siren7, format);
-	} else if (!strcmp(name, "siren14")) {
-		ao2_replace(ast_format_siren14, format);
-	} else if (!strcmp(name, "testlaw")) {
-		ao2_replace(ast_format_testlaw, format);
-	} else if (!strcmp(name, "g719")) {
-		ao2_replace(ast_format_g719, format);
-	} else if (!strcmp(name, "opus")) {
-		ao2_replace(ast_format_opus, format);
-	} else if (!strcmp(name, "jpeg")) {
-		ao2_replace(ast_format_jpeg, format);
-	} else if (!strcmp(name, "png")) {
-		ao2_replace(ast_format_png, format);
-	} else if (!strcmp(name, "h261")) {
-		ao2_replace(ast_format_h261, format);
-	} else if (!strcmp(name, "h263")) {
-		ao2_replace(ast_format_h263, format);
-	} else if (!strcmp(name, "h263p")) {
-		ao2_replace(ast_format_h263p, format);
-	} else if (!strcmp(name, "h264")) {
-		ao2_replace(ast_format_h264, format);
-	} else if (!strcmp(name, "mpeg4")) {
-		ao2_replace(ast_format_mp4, format);
-	} else if (!strcmp(name, "vp8")) {
-		ao2_replace(ast_format_vp8, format);
-	} else if (!strcmp(name, "red")) {
-		ao2_replace(ast_format_t140_red, format);
-	} else if (!strcmp(name, "t140")) {
-		ao2_replace(ast_format_t140, format);
-	} else if (!strcmp(name, "none")) {
-		ao2_replace(ast_format_none, format);
-	}
-}
-
-int ast_format_cache_set(struct ast_format *format)
-{
-	SCOPED_AO2WRLOCK(lock, formats);
-	struct ast_format *old_format;
-
-	ast_assert(format != NULL);
-
-	if (ast_strlen_zero(ast_format_get_name(format))) {
-		return -1;
-	}
-
-	old_format = ao2_find(formats, ast_format_get_name(format), OBJ_SEARCH_KEY | OBJ_NOLOCK);
-	if (old_format) {
-		ao2_unlink_flags(formats, old_format, OBJ_NOLOCK);
-	}
-	ao2_link_flags(formats, format, OBJ_NOLOCK);
-
-	set_cached_format(ast_format_get_name(format), format);
-
-	ast_verb(2, "%s cached format with name '%s'\n",
-		old_format ? "Updated" : "Created",
-		ast_format_get_name(format));
-
-	ao2_cleanup(old_format);
-
-	return 0;
-}
-
-struct ast_format *__ast_format_cache_get(const char *name)
-{
-	if (ast_strlen_zero(name)) {
-		return NULL;
-	}
-
-	return ao2_find(formats, name, OBJ_SEARCH_KEY);
-}
-
-struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func)
-{
-	if (ast_strlen_zero(name)) {
-		return NULL;
-	}
-
-	return __ao2_find_debug(formats, name, OBJ_SEARCH_KEY, S_OR(tag, "ast_format_cache_get"), file, line, func);
-}
-
-struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate)
-{
-	if (rate >= 192000) {
-		return ast_format_slin192;
-	} else if (rate >= 96000) {
-		return ast_format_slin96;
-	} else if (rate >= 48000) {
-		return ast_format_slin48;
-	} else if (rate >= 44100) {
-		return ast_format_slin44;
-	} else if (rate >= 32000) {
-		return ast_format_slin32;
-	} else if (rate >= 24000) {
-		return ast_format_slin24;
-	} else if (rate >= 16000) {
-		return ast_format_slin16;
-	} else if (rate >= 12000) {
-		return ast_format_slin12;
-	}
-	return ast_format_slin;
-}
-
-int ast_format_cache_is_slinear(struct ast_format *format)
-{
-	if ((ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin16) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin24) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin32) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin44) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin48) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin96) == AST_FORMAT_CMP_EQUAL)
-		|| (ast_format_cmp(format, ast_format_slin192) == AST_FORMAT_CMP_EQUAL)) {
-		return 1;
-	}
-
-	return 0;
-}
-
diff --git a/main/format_cap.c b/main/format_cap.c
index a16b14d..5fc1108 100644
--- a/main/format_cap.c
+++ b/main/format_cap.c
@@ -1,9 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2014, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
  *
- * Joshua Colp <jcolp at digium.com>
+ * David Vossel <dvossel at digium.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -16,11 +16,11 @@
  * at the top of the source tree.
  */
 
-/*! \file
- *
- * \brief Format Capabilities API
+/*!
+ * \file
+ * \brief Format Capability API
  *
- * \author Joshua Colp <jcolp at digium.com>
+ * \author David Vossel <dvossel at digium.com>
  */
 
 /*** MODULEINFO
@@ -29,689 +29,614 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423414 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
-#include "asterisk/logger.h"
+#include "asterisk/_private.h"
 #include "asterisk/format.h"
 #include "asterisk/format_cap.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/codec.h"
+#include "asterisk/frame.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-#include "asterisk/vector.h"
-#include "asterisk/linkedlists.h"
 #include "asterisk/utils.h"
 
-/*! \brief Structure used for capability formats, adds framing */
-struct format_cap_framed {
-	/*! \brief A pointer to the format */
-	struct ast_format *format;
-	/*! \brief The format framing size */
-	unsigned int framing;
-	/*! \brief Linked list information */
-	AST_LIST_ENTRY(format_cap_framed) entry;
-};
 
-/*! \brief Format capabilities structure, holds formats + preference order + etc */
 struct ast_format_cap {
-	/*! \brief Vector of formats, indexed using the codec identifier */
-	AST_VECTOR(, struct format_cap_framed_list) formats;
-	/*! \brief Vector of formats, added in preference order */
-	AST_VECTOR(, struct format_cap_framed *) preference_order;
-	/*! \brief Global framing size, applies to all formats if no framing present on format */
-	unsigned int framing;
+	/* The capabilities structure is just an ao2 container of ast_formats */
+	struct ao2_container *formats;
+	struct ao2_iterator it;
+	/*! TRUE if the formats container created without a lock. */
+	int nolock;
 };
 
-/*! \brief Linked list for formats */
-AST_LIST_HEAD_NOLOCK(format_cap_framed_list, format_cap_framed);
-
-/*! \brief Dummy empty list for when we are inserting a new list */
-static const struct format_cap_framed_list format_cap_framed_list_empty = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
-
-/*! \brief Destructor for format capabilities structure */
-static void format_cap_destroy(void *obj)
+/*! format exists within capabilities structure if it is identical to
+ * another format, or if the format is a proper subset of another format. */
+static int cmp_cb(void *obj, void *arg, int flags)
 {
-	struct ast_format_cap *cap = obj;
-	int idx;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); idx++) {
-		struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
-		struct format_cap_framed *framed;
-
-		while ((framed = AST_LIST_REMOVE_HEAD(list, entry))) {
-			ao2_ref(framed, -1);
-		}
-	}
-	AST_VECTOR_FREE(&cap->formats);
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); idx++) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
-
-		/* This will always be non-null, unlike formats */
-		ao2_ref(framed, -1);
-	}
-	AST_VECTOR_FREE(&cap->preference_order);
+	struct ast_format *format1 = arg;
+	struct ast_format *format2 = obj;
+	enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
+
+	return ((res == AST_FORMAT_CMP_EQUAL) ||
+			(res == AST_FORMAT_CMP_SUBSET)) ?
+				CMP_MATCH | CMP_STOP :
+				0;
 }
 
-static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags)
+static int hash_cb(const void *obj, const int flags)
 {
-	AST_VECTOR_INIT(&cap->formats, 0);
-
-	/* TODO: Look at common usage of this and determine a good starting point */
-	AST_VECTOR_INIT(&cap->preference_order, 5);
-
-	cap->framing = UINT_MAX;
+	const struct ast_format *format = obj;
+	return format->id;
 }
 
-struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags)
+static struct ast_format_cap *cap_alloc_helper(int nolock)
 {
-	struct ast_format_cap *cap;
+	struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
 
-	cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
 	if (!cap) {
 		return NULL;
 	}
-
-	format_cap_init(cap, flags);
+	cap->nolock = nolock;
+	cap->formats = ao2_container_alloc_options(
+		nolock ? AO2_ALLOC_OPT_LOCK_NOLOCK : AO2_ALLOC_OPT_LOCK_MUTEX,
+		283, hash_cb, cmp_cb);
+	if (!cap->formats) {
+		ast_free(cap);
+		return NULL;
+	}
 
 	return cap;
 }
 
-struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func)
+struct ast_format_cap *ast_format_cap_alloc_nolock(void)
+{
+	return cap_alloc_helper(1);
+}
+
+struct ast_format_cap *ast_format_cap_alloc(void)
 {
-	struct ast_format_cap *cap;
+	return cap_alloc_helper(0);
+}
 
-	cap = __ao2_alloc_debug(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(tag, "ast_format_cap_alloc"), file, line, func, 1);
+void *ast_format_cap_destroy(struct ast_format_cap *cap)
+{
 	if (!cap) {
 		return NULL;
 	}
-
-	format_cap_init(cap, flags);
-
-	return cap;
+	ao2_ref(cap->formats, -1);
+	ast_free(cap);
+	return NULL;
 }
 
-void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
+void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
 {
-	cap->framing = framing;
+	struct ast_format *fnew;
+
+	if (!format || !format->id) {
+		return;
+	}
+	if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
+		return;
+	}
+	ast_format_copy(fnew, format);
+	ao2_link(cap->formats, fnew);
+	ao2_ref(fnew, -1);
 }
 
-/*! \brief Destructor for format capabilities framed structure */
-static void format_cap_framed_destroy(void *obj)
+void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
 {
-	struct format_cap_framed *framed = obj;
+	int x;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
 
-	ao2_cleanup(framed->format);
+	for (x = 0; x < f_len; x++) {
+		if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
+			ast_format_cap_add(cap, &f_list[x].format);
+		}
+	}
+	ast_format_list_destroy(f_list);
 }
 
-static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
+void ast_format_cap_add_all(struct ast_format_cap *cap)
 {
-	struct format_cap_framed_list *list;
-
-	framed->framing = framing;
+	int x;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
 
-	if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
-		if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
-			ao2_ref(framed, -1);
-			return -1;
-		}
+	for (x = 0; x < f_len; x++) {
+		ast_format_cap_add(cap, &f_list[x].format);
 	}
-	list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
-
-	/* Order doesn't matter for formats, so insert at the head for performance reasons */
-	ao2_ref(framed, +1);
-	AST_LIST_INSERT_HEAD(list, framed, entry);
+	ast_format_list_destroy(f_list);
+}
 
-	/* This takes the allocation reference */
-	AST_VECTOR_APPEND(&cap->preference_order, framed);
+static int append_cb(void *obj, void *arg, int flag)
+{
+	struct ast_format_cap *result = (struct ast_format_cap *) arg;
+	struct ast_format *format = (struct ast_format *) obj;
 
-	cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format));
+	if (!ast_format_cap_iscompatible(result, format)) {
+		ast_format_cap_add(result, format);
+	}
 
 	return 0;
 }
 
-/*! \internal \brief Determine if \c format is in \c cap */
-static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format)
+void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
 {
-	struct format_cap_framed *framed;
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
-		framed = AST_VECTOR_GET(&cap->preference_order, i);
+	ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
+}
 
-		if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
-			return 1;
-		}
-	}
+static int copy_cb(void *obj, void *arg, int flag)
+{
+	struct ast_format_cap *result = (struct ast_format_cap *) arg;
+	struct ast_format *format = (struct ast_format *) obj;
 
+	ast_format_cap_add(result, format);
 	return 0;
 }
 
-int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
+void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
 {
-	struct format_cap_framed *framed;
-
-	ast_assert(format != NULL);
+	ast_format_cap_remove_all(dst);
+	ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
+}
 
-	if (format_in_format_cap(cap, format)) {
-		return 0;
+struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
+{
+	struct ast_format_cap *dst;
+	if (cap->nolock) {
+		dst = ast_format_cap_alloc_nolock();
+	} else {
+		dst = ast_format_cap_alloc();
 	}
-
-	framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!framed) {
-		return -1;
+	if (!dst) {
+		return NULL;
 	}
-	framed->format = ao2_bump(format);
-
-	return format_cap_framed_init(framed, cap, format, framing);
+	ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
+	return dst;
 }
 
-int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
+int ast_format_cap_is_empty(const struct ast_format_cap *cap)
 {
-	struct format_cap_framed *framed;
-
-	ast_assert(format != NULL);
-
-	if (format_in_format_cap(cap, format)) {
-		return 0;
-	}
-
-	framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!framed) {
-		return -1;
+	if (!cap) {
+		return 1;
 	}
-
-	__ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func);
-	framed->format = format;
-
-	return format_cap_framed_init(framed, cap, format, framing);
+	return ao2_container_count(cap->formats) == 0 ? 1 : 0;
 }
 
-int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
+static int find_exact_cb(void *obj, void *arg, int flag)
 {
-	int id;
-
-	for (id = 1; id < ast_codec_get_max(); ++id) {
-		struct ast_codec *codec = ast_codec_get_by_id(id);
-		struct ast_format *format;
-		int res;
-
-		if (!codec) {
-			continue;
-		}
+	struct ast_format *format1 = (struct ast_format *) arg;
+	struct ast_format *format2 = (struct ast_format *) obj;
 
-		if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
-			ao2_ref(codec, -1);
-			continue;
-		}
-
-		format = ast_format_create(codec);
-		ao2_ref(codec, -1);
-
-		if (!format) {
-			return -1;
-		}
+	return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
+}
 
-		/* Use the global framing or default framing of the codec */
-		res = ast_format_cap_append(cap, format, 0);
-		ao2_ref(format, -1);
+int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
+{
+	struct ast_format *fremove;
 
-		if (res) {
-			return -1;
-		}
+	fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
+	if (fremove) {
+		ao2_ref(fremove, -1);
+		return 0;
 	}
 
-	return 0;
+	return -1;
 }
 
-int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
-	enum ast_media_type type)
-{
-	int idx, res = 0;
+struct multiple_by_id_data {
+	struct ast_format *format;
+	int match_found;
+};
 
-	for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
+static int multiple_by_id_cb(void *obj, void *arg, int flag)
+{
+	struct multiple_by_id_data *data = arg;
+	struct ast_format *format = obj;
+	int res;
 
-		if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
-			res = ast_format_cap_append(dst, framed->format, framed->framing);
-		}
+	res = (format->id == data->format->id) ? CMP_MATCH : 0;
+	if (res) {
+		data->match_found = 1;
 	}
 
 	return res;
 }
 
-static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
+int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
 {
-	struct format_cap_framed *framed;
-	int i;
-
-	ast_assert(format != NULL);
-
-	for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
-		framed = AST_VECTOR_GET(&cap->preference_order, i);
-
-		if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
-			ao2_t_replace(framed->format, format, "replacing with new format");
-			framed->framing = framing;
-			return 0;
-		}
+	struct ast_format format = {
+		.id = id,
+	};
+	struct multiple_by_id_data data = {
+		.format = &format,
+		.match_found = 0,
+	};
+
+	ao2_callback(cap->formats,
+		OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
+		multiple_by_id_cb,
+		&data);
+
+	/* match_found will be set if at least one item was removed */
+	if (data.match_found) {
+		return 0;
 	}
 
 	return -1;
 }
 
-void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
-	enum ast_media_type type)
+static int multiple_by_type_cb(void *obj, void *arg, int flag)
 {
-	int idx;
-
-	for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
-
-		if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
-			format_cap_replace(dst, framed->format, framed->framing);
-		}
-	}
+	int *type = arg;
+	struct ast_format *format = obj;
+	return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
 }
 
-int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
+void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
 {
-	int res = 0, all = 0, iter_allowing;
-	char *parse = NULL, *this = NULL, *psize = NULL;
-
-	parse = ast_strdupa(list);
-	while ((this = strsep(&parse, ","))) {
-		int framems = 0;
-		struct ast_format *format = NULL;
-
-		iter_allowing = allowing;
-		if (*this == '!') {
-			this++;
-			iter_allowing = !allowing;
-		}
-		if ((psize = strrchr(this, ':'))) {
-			*psize++ = '\0';
-			ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
-			if (!sscanf(psize, "%30d", &framems) || (framems < 0)) {
-				framems = 0;
-				res = -1;
-				ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
-				continue;
-			}
-		}
-		all = strcasecmp(this, "all") ? 0 : 1;
-
-		if (!all && !(format = ast_format_cache_get(this))) {
-			ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
-			res = -1;
-			continue;
-		}
-
-		if (cap) {
-			if (iter_allowing) {
-				if (all) {
-					ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
-				} else {
-					ast_format_cap_append(cap, format, framems);
-				}
-			} else {
-				if (all) {
-					ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
-				} else {
-					ast_format_cap_remove(cap, format);
-				}
-			}
-		}
-
-		ao2_cleanup(format);
-	}
-	return res;
+	ao2_callback(cap->formats,
+		OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
+		multiple_by_type_cb,
+		&type);
 }
 
-size_t ast_format_cap_count(const struct ast_format_cap *cap)
+void ast_format_cap_remove_all(struct ast_format_cap *cap)
 {
-	return AST_VECTOR_SIZE(&cap->preference_order);
+	ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
 }
 
-struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
+void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
 {
-	struct format_cap_framed *framed;
+	ast_format_cap_remove_all(cap);
+	ast_format_cap_add(cap, format);
+}
 
-	ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order));
+int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
+{
+	struct ast_format *f;
+	struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
 
-	if (position >= AST_VECTOR_SIZE(&cap->preference_order)) {
-		return NULL;
+	f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
+	if (f) {
+		ast_format_copy(result, f);
+		ao2_ref(f, -1);
+		return 1;
 	}
-
-	framed = AST_VECTOR_GET(&cap->preference_order, position);
-
-	ast_assert(framed->format != ast_format_none);
-	ao2_ref(framed->format, +1);
-	return framed->format;
+	ast_format_clear(result);
+	return 0;
 }
 
-struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
+int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
 {
-	int i;
+	struct ast_format *f;
+	struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
 
-	if (type == AST_MEDIA_TYPE_UNKNOWN) {
-		return ast_format_cap_get_format(cap, 0);
+	if (!tmp_cap) {
+		return 0;
 	}
 
-	for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
-
-		if (ast_format_get_type(framed->format) == type) {
-			ao2_ref(framed->format, +1);
-			ast_assert(framed->format != ast_format_none);
-			return framed->format;
-		}
+	f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
+	if (f) {
+		ao2_ref(f, -1);
+		return 1;
 	}
 
-	return NULL;
-}
-
-unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
-{
-	return (cap->framing != UINT_MAX) ? cap->framing : 0;
+	return 0;
 }
 
-unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
+struct byid_data {
+	struct ast_format *result;
+	enum ast_format_id id;
+};
+static int find_best_byid_cb(void *obj, void *arg, int flag)
 {
-	unsigned int framing;
-	struct format_cap_framed_list *list;
-	struct format_cap_framed *framed, *result = NULL;
+	struct ast_format *format = obj;
+	struct byid_data *data = arg;
 
-	if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
+	if (data->id != format->id) {
 		return 0;
 	}
-
-	framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format);
-	list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
-
-	AST_LIST_TRAVERSE(list, framed, entry) {
-		enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
-
-		if (res == AST_FORMAT_CMP_NOT_EQUAL) {
-			continue;
-		}
-
-		result = framed;
-
-		if (res == AST_FORMAT_CMP_EQUAL) {
-			break;
-		}
-	}
-
-	if (result && result->framing) {
-		framing = result->framing;
+	if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
+		ast_format_copy(data->result, format);
 	}
+	return 0;
+}
 
-	return framing;
+int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
+{
+	struct byid_data data;
+	data.result = result;
+	data.id = id;
+
+	ast_format_clear(result);
+	ao2_callback(cap->formats,
+		OBJ_MULTIPLE | OBJ_NODATA,
+		find_best_byid_cb,
+		&data);
+	return result->id ? 1 : 0;
 }
 
-/*!
- * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED()
- *
- * \param elem Element to compare against
- * \param value Value to compare with the vector element.
- *
- * \return 0 if element does not match.
- * \return Non-zero if element matches.
+/*! \internal
+ * \brief this struct is just used for the ast_format_cap_joint function so we can provide
+ * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
+ * ao2 callback function.
  */
-#define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value))
-
-/*!
- * \brief format_cap_framed vector element cleanup.
- *
- * \param elem Element to cleanup
- *
- * \return Nothing
- */
-#define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem)  ao2_cleanup((elem))
+struct find_joint_data {
+	/*! format to compare to for joint capabilities */
+	struct ast_format *format;
+	/*! if joint formmat exists with above format, add it to the result container */
+	struct ast_format_cap *joint_cap;
+	int joint_found;
+};
 
-int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
+static int find_joint_cb(void *obj, void *arg, int flag)
 {
-	struct format_cap_framed_list *list;
-	struct format_cap_framed *framed;
-
-	ast_assert(format != NULL);
+	struct ast_format *format = obj;
+	struct find_joint_data *data = arg;
 
-	if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
-		return -1;
-	}
-
-	list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
-		if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) {
-			continue;
+	struct ast_format tmp = { 0, };
+	if (!ast_format_joint(format, data->format, &tmp)) {
+		if (data->joint_cap) {
+			ast_format_cap_add(data->joint_cap, &tmp);
 		}
-
-		AST_LIST_REMOVE_CURRENT(entry);
-		FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed);
-		break;
+		data->joint_found++;
 	}
-	AST_LIST_TRAVERSE_SAFE_END;
 
-	return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format,
-		FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
+	return 0;
 }
 
-void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
+int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
 {
-	int idx;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) {
-		struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
-		struct format_cap_framed *framed;
-
-		AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
-			if ((type != AST_MEDIA_TYPE_UNKNOWN) &&
-				ast_format_get_type(framed->format) != type) {
-				continue;
-			}
-
-			AST_LIST_REMOVE_CURRENT(entry);
-			AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format,
-				FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
-			ao2_ref(framed, -1);
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
+	struct ao2_iterator it;
+	struct ast_format *tmp;
+	struct find_joint_data data = {
+		.joint_found = 0,
+		.joint_cap = NULL,
+	};
+
+	it = ao2_iterator_init(cap1->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		data.format = tmp;
+		ao2_callback(cap2->formats,
+			OBJ_MULTIPLE | OBJ_NODATA,
+			find_joint_cb,
+			&data);
+		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
+
+	return data.joint_found ? 1 : 0;
 }
 
-struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
+int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
 {
-	struct format_cap_framed_list *list;
-	struct format_cap_framed *framed;
-	struct ast_format *result = NULL;
-
-	ast_assert(format != NULL);
+	struct ao2_iterator it;
+	struct ast_format *tmp;
 
-	if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
-		return NULL;
+	if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
+		return 0; /* if they are not the same size, they are not identical */
 	}
 
-	list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
-
-	AST_LIST_TRAVERSE(list, framed, entry) {
-		enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
-
-		if (res == AST_FORMAT_CMP_NOT_EQUAL) {
-			continue;
-		}
-
-		/* Replace any current result, this one will also be a subset OR an exact match */
-		ao2_cleanup(result);
-
-		result = ast_format_joint(format, framed->format);
-
-		/* If it's a match we can do no better so return asap */
-		if (res == AST_FORMAT_CMP_EQUAL) {
-			break;
+	it = ao2_iterator_init(cap1->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		if (!ast_format_cap_iscompatible(cap2, tmp)) {
+			ao2_ref(tmp, -1);
+			ao2_iterator_destroy(&it);
+			return 0;
 		}
+		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
 
-	return result;
+	return 1;
 }
 
-enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap,
-	const struct ast_format *format)
+struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
 {
-	enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL;
-	struct format_cap_framed_list *list;
-	struct format_cap_framed *framed;
-
-	ast_assert(format != NULL);
-
-	if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
-		return AST_FORMAT_CMP_NOT_EQUAL;
+	struct ao2_iterator it;
+	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
+	struct ast_format *tmp;
+	struct find_joint_data data = {
+		.joint_found = 0,
+		.joint_cap = result,
+	};
+	if (!result) {
+		return NULL;
 	}
 
-	list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
-
-	AST_LIST_TRAVERSE(list, framed, entry) {
-		enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format);
-
-		if (cmp == AST_FORMAT_CMP_NOT_EQUAL) {
-			continue;
-		}
-
-		res = cmp;
+	it = ao2_iterator_init(cap1->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		data.format = tmp;
+		ao2_callback(cap2->formats,
+			OBJ_MULTIPLE | OBJ_NODATA,
+			find_joint_cb,
+			&data);
+		ao2_ref(tmp, -1);
+	}
+	ao2_iterator_destroy(&it);
 
-		if (res == AST_FORMAT_CMP_EQUAL) {
-			break;
-		}
+	if (ao2_container_count(result->formats)) {
+		return result;
 	}
 
-	return res;
+	result = ast_format_cap_destroy(result);
+	return NULL;
 }
 
-int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
+static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
 {
-	int idx;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
-
-		if (ast_format_get_type(framed->format) == type) {
-			return 1;
-		}
+	struct ao2_iterator it;
+	struct ast_format *tmp;
+	struct find_joint_data data = {
+		.joint_cap = result,
+		.joint_found = 0,
+	};
+	if (!append) {
+		ast_format_cap_remove_all(result);
+	}
+	it = ao2_iterator_init(cap1->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		data.format = tmp;
+		ao2_callback(cap2->formats,
+			OBJ_MULTIPLE | OBJ_NODATA,
+			find_joint_cb,
+			&data);
+		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
 
-	return 0;
+	return ao2_container_count(result->formats) ? 1 : 0;
 }
 
-int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
-	struct ast_format_cap *result)
+int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
 {
-	int idx, res = 0;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
-		struct ast_format *format;
-
-		format = ast_format_cap_get_compatible_format(cap2, framed->format);
-		if (!format) {
-			continue;
-		}
-
-		res = ast_format_cap_append(result, format, framed->framing);
-		ao2_ref(format, -1);
-
-		if (res) {
-			break;
-		}
-	}
+	return joint_copy_helper(cap1, cap2, result, 1);
+}
 
-	return res;
+int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
+{
+	return joint_copy_helper(cap1, cap2, result, 0);
 }
 
-int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
 {
-	int idx;
+	struct ao2_iterator it;
+	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
+	struct ast_format *tmp;
 
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
+	if (!result) {
+		return NULL;
+	}
 
-		if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) {
-			return 1;
+	/* for each format in cap1, see if that format is
+	 * compatible with cap2. If so copy it to the result */
+	it = ao2_iterator_init(cap->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
+			/* copy format */
+			ast_format_cap_add(result, tmp);
 		}
+		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
 
-	return 0;
+	if (ao2_container_count(result->formats)) {
+		return result;
+	}
+	result = ast_format_cap_destroy(result);
+
+	return NULL;
 }
 
-static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+
+int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
 {
-	int idx;
+	struct ao2_iterator it;
 	struct ast_format *tmp;
 
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
-		tmp = ast_format_cap_get_format(cap1, idx);
-
-		if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) {
+	it = ao2_iterator_init(cap->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
 			ao2_ref(tmp, -1);
-			return 0;
+			ao2_iterator_destroy(&it);
+			return 1;
 		}
-
 		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
 
-	return 1;
+	return 0;
 }
 
-int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+void ast_format_cap_iter_start(struct ast_format_cap *cap)
 {
-	if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) {
-		return 0; /* if they are not the same size, they are not identical */
-	}
-
-	if (!internal_format_cap_identical(cap1, cap2)) {
-		return 0;
-	}
-
-	return internal_format_cap_identical(cap2, cap1);
+	/* We can unconditionally lock even if the container has no lock. */
+	ao2_lock(cap->formats);
+	cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
 }
 
-const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf)
+void ast_format_cap_iter_end(struct ast_format_cap *cap)
 {
-	int i;
+	ao2_iterator_destroy(&cap->it);
+	/* We can unconditionally unlock even if the container has no lock. */
+	ao2_unlock(cap->formats);
+}
 
-	ast_str_set(buf, 0, "(");
+int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
+{
+	struct ast_format *tmp = ao2_iterator_next(&cap->it);
 
-	if (!AST_VECTOR_SIZE(&cap->preference_order)) {
-		ast_str_append(buf, 0, "nothing)");
-		return ast_str_buffer(*buf);
+	if (!tmp) {
+		return -1;
 	}
+	ast_format_copy(format, tmp);
+	ao2_ref(tmp, -1);
 
-	for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) {
-		int res;
-		struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
+	return 0;
+}
 
-		res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format),
-			i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : "");
-		if (res < 0) {
-			break;
+char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
+{
+	int x;
+	unsigned len;
+	char *start, *end = buf;
+	struct ast_format tmp_fmt;
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	if (!size) {
+		f_list = ast_format_list_destroy(f_list);
+		return buf;
+	}
+	snprintf(end, size, "(");
+	len = strlen(end);
+	end += len;
+	size -= len;
+	start = end;
+	for (x = 0; x < f_len; x++) {
+		ast_format_copy(&tmp_fmt, &f_list[x].format);
+		if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
+			snprintf(end, size, "%s|", f_list[x].name);
+			len = strlen(end);
+			end += len;
+			size -= len;
 		}
 	}
-	ast_str_append(buf, 0, ")");
-
-	return ast_str_buffer(*buf);
+	if (start == end) {
+		ast_copy_string(start, "nothing)", size);
+	} else if (size > 1) {
+		*(end - 1) = ')';
+	}
+	f_list = ast_format_list_destroy(f_list);
+	return buf;
 }
 
-int ast_format_cap_empty(struct ast_format_cap *cap)
+uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
 {
-	int count = ast_format_cap_count(cap);
+	uint64_t res = 0;
+	struct ao2_iterator it;
+	struct ast_format *tmp;
 
-	if (count > 1) {
-		return 0;
+	it = ao2_iterator_init(cap->formats, 0);
+	while ((tmp = ao2_iterator_next(&it))) {
+		res |= ast_format_to_old_bitfield(tmp);
+		ao2_ref(tmp, -1);
 	}
+	ao2_iterator_destroy(&it);
+	return res;
+}
 
-	if (count == 0 || AST_VECTOR_GET(&cap->preference_order, 0)->format == ast_format_none) {
-		return 1;
+void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
+{
+	uint64_t tmp = 0;
+	int x;
+	struct ast_format tmp_format = { 0, };
+
+	ast_format_cap_remove_all(dst);
+	for (x = 0; x < 64; x++) {
+		tmp = (1ULL << x);
+		if (tmp & src) {
+			ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
+		}
 	}
-
-	return 0;
 }
diff --git a/main/format_compatibility.c b/main/format_compatibility.c
deleted file mode 100644
index 747f3aa..0000000
--- a/main/format_compatibility.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Media Format Bitfield Compatibility API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420364 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/format_compatibility.h"
-#include "asterisk/format_cache.h"
-
-uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format)
-{
-	if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G723;
-	} else if (ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_GSM;
-	} else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_ULAW;
-	} else if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_ALAW;
-	} else if (ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G726_AAL2;
-	} else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_ADPCM;
-	} else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SLIN;
-	} else if (ast_format_cmp(format, ast_format_lpc10) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_LPC10;
-	} else if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G729;
-	} else if (ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SPEEX;
-	} else if (ast_format_cmp(format, ast_format_ilbc) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_ILBC;
-	} else if (ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G726;
-	} else if (ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G722;
-	} else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SIREN7;
-	} else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SIREN14;
-	} else if (ast_format_cmp(format, ast_format_slin16) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SLIN16;
-	} else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_G719;
-	} else if (ast_format_cmp(format, ast_format_speex16) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_SPEEX16;
-	} else if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_OPUS;
-	} else if (ast_format_cmp(format, ast_format_testlaw) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_TESTLAW;
-	} else if (ast_format_cmp(format, ast_format_h261) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_H261;
-	} else if (ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_H263;
-	} else if (ast_format_cmp(format, ast_format_h263p) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_H263P;
-	} else if (ast_format_cmp(format, ast_format_h264) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_H264;
-	} else if (ast_format_cmp(format, ast_format_mp4) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_MP4;
-	} else if (ast_format_cmp(format, ast_format_vp8) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_VP8;
-	} else if (ast_format_cmp(format, ast_format_jpeg) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_JPEG;
-	} else if (ast_format_cmp(format, ast_format_png) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_PNG;
-	} else if (ast_format_cmp(format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_T140_RED;
-	} else if (ast_format_cmp(format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) {
-		return AST_FORMAT_T140;
-	}
-
-	return 0;
-}
-
-uint64_t ast_format_compatibility_codec2bitfield(const struct ast_codec *codec)
-{
-	if (codec->id == ast_format_get_codec_id(ast_format_g723)) {
-		return AST_FORMAT_G723;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_gsm)) {
-		return AST_FORMAT_GSM;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_ulaw)) {
-		return AST_FORMAT_ULAW;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_alaw)) {
-		return AST_FORMAT_ALAW;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_g726_aal2)) {
-		return AST_FORMAT_G726_AAL2;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_adpcm)) {
-		return AST_FORMAT_ADPCM;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_slin)) {
-		return AST_FORMAT_SLIN;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_lpc10)) {
-		return AST_FORMAT_LPC10;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_g729)) {
-		return AST_FORMAT_G729;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_speex)) {
-		return AST_FORMAT_SPEEX;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_ilbc)) {
-		return AST_FORMAT_ILBC;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_g726)) {
-		return AST_FORMAT_G726;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_g722)) {
-		return AST_FORMAT_G722;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_siren7)) {
-		return AST_FORMAT_SIREN7;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_siren14)) {
-		return AST_FORMAT_SIREN14;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_slin16)) {
-		return AST_FORMAT_SLIN16;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_g719)) {
-		return AST_FORMAT_G719;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_speex16)) {
-		return AST_FORMAT_SPEEX16;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_opus)) {
-		return AST_FORMAT_OPUS;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_testlaw)) {
-		return AST_FORMAT_TESTLAW;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_h261)) {
-		return AST_FORMAT_H261;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_h263)) {
-		return AST_FORMAT_H263;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_h263p)) {
-		return AST_FORMAT_H263P;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_h264)) {
-		return AST_FORMAT_H264;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_mp4)) {
-		return AST_FORMAT_MP4;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_vp8)) {
-		return AST_FORMAT_VP8;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_jpeg)) {
-		return AST_FORMAT_JPEG;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_png)) {
-		return AST_FORMAT_PNG;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_t140_red)) {
-		return AST_FORMAT_T140_RED;
-	} else if (codec->id == ast_format_get_codec_id(ast_format_t140)) {
-		return AST_FORMAT_T140;
-	}
-
-	return 0;
-}
-
-struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield)
-{
-	switch (bitfield) {
-	/*! G.723.1 compression */
-	case AST_FORMAT_G723:
-		return ast_format_g723;
-	/*! GSM compression */
-	case AST_FORMAT_GSM:
-		return ast_format_gsm;
-	/*! Raw mu-law data (G.711) */
-	case AST_FORMAT_ULAW:
-		return ast_format_ulaw;
-	/*! Raw A-law data (G.711) */
-	case AST_FORMAT_ALAW:
-		return ast_format_alaw;
-	/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
-	case AST_FORMAT_G726_AAL2:
-		return ast_format_g726_aal2;
-	/*! ADPCM (IMA) */
-	case AST_FORMAT_ADPCM:
-		return ast_format_adpcm;
-	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
-	case AST_FORMAT_SLIN:
-		return ast_format_slin;
-	/*! LPC10, 180 samples/frame */
-	case AST_FORMAT_LPC10:
-		return ast_format_lpc10;
-	/*! G.729A audio */
-	case AST_FORMAT_G729:
-		return ast_format_g729;
-	/*! SpeeX Free Compression */
-	case AST_FORMAT_SPEEX:
-		return ast_format_speex;
-	/*! iLBC Free Compression */
-	case AST_FORMAT_ILBC:
-		return ast_format_ilbc;
-	/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
-	case AST_FORMAT_G726:
-		return ast_format_g726;
-	/*! G.722 */
-	case AST_FORMAT_G722:
-		return ast_format_g722;
-	/*! G.722.1 (also known as Siren7, 32kbps assumed) */
-	case AST_FORMAT_SIREN7:
-		return ast_format_siren7;
-	/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
-	case AST_FORMAT_SIREN14:
-		return ast_format_siren14;
-	/*! Raw 16-bit Signed Linear (16000 Hz) PCM */
-	case AST_FORMAT_SLIN16:
-		return ast_format_slin16;
-	/*! G.719 (64 kbps assumed) */
-	case AST_FORMAT_G719:
-		return ast_format_g719;
-	/*! SpeeX Wideband (16kHz) Free Compression */
-	case AST_FORMAT_SPEEX16:
-		return ast_format_speex16;
-	/*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
-	case AST_FORMAT_OPUS:
-		return ast_format_opus;
-	/*! Raw mu-law data (G.711) */
-	case AST_FORMAT_TESTLAW:
-		return ast_format_testlaw;
-
-	/*! H.261 Video */
-	case AST_FORMAT_H261:
-		return ast_format_h261;
-	/*! H.263 Video */
-	case AST_FORMAT_H263:
-		return ast_format_h263;
-	/*! H.263+ Video */
-	case AST_FORMAT_H263P:
-		return ast_format_h263p;
-	/*! H.264 Video */
-	case AST_FORMAT_H264:
-		return ast_format_h264;
-	/*! MPEG4 Video */
-	case AST_FORMAT_MP4:
-		return ast_format_mp4;
-	/*! VP8 Video */
-	case AST_FORMAT_VP8:
-		return ast_format_vp8;
-
-	/*! JPEG Images */
-	case AST_FORMAT_JPEG:
-		return ast_format_jpeg;
-	/*! PNG Images */
-	case AST_FORMAT_PNG:
-		return ast_format_png;
-
-	/*! T.140 RED Text format RFC 4103 */
-	case AST_FORMAT_T140_RED:
-		return ast_format_t140;
-	/*! T.140 Text format - ITU T.140, RFC 4103 */
-	case AST_FORMAT_T140:
-		return ast_format_t140_red;
-	}
-	return NULL;
-}
-
diff --git a/main/format_pref.c b/main/format_pref.c
new file mode 100644
index 0000000..4ea9f0c
--- /dev/null
+++ b/main/format_pref.c
@@ -0,0 +1,344 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Format Preference API
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include "asterisk/_private.h"
+#include "asterisk/frame.h"
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+
+void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
+{
+	size_t f_len;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+	int x, differential = (int) 'A', mem;
+	char *from, *to;
+
+	/* TODO re-evaluate this function.  It is using the order of the formats specified
+	 * in the global format list in a way that may not be safe. */
+	if (right) {
+		from = pref->order;
+		to = buf;
+		mem = size;
+	} else {
+		to = pref->order;
+		from = buf;
+		mem = AST_CODEC_PREF_SIZE;
+	}
+
+	memset(to, 0, mem);
+	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+		if (!from[x]) {
+			break;
+		}
+		to[x] = right ? (from[x] + differential) : (from[x] - differential);
+		if (!right && to[x] && (to[x] < f_len)) {
+			ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
+		}
+	}
+	ast_format_list_destroy(f_list);
+}
+
+int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
+{
+	int x;
+	struct ast_format format;
+	size_t total_len, slen;
+	const char *formatname;
+
+	memset(buf, 0, size);
+	total_len = size;
+	buf[0] = '(';
+	total_len--;
+	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+		if (total_len <= 0)
+			break;
+		if (!(ast_codec_pref_index(pref, x, &format)))
+			break;
+		if ((formatname = ast_getformatname(&format))) {
+			slen = strlen(formatname);
+			if (slen > total_len)
+				break;
+			strncat(buf, formatname, total_len - 1); /* safe */
+			total_len -= slen;
+		}
+		if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
+			strncat(buf, "|", total_len - 1); /* safe */
+			total_len--;
+		}
+	}
+	if (total_len) {
+		strncat(buf, ")", total_len - 1); /* safe */
+		total_len--;
+	}
+
+	return size - total_len;
+}
+
+struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
+{
+	if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
+		ast_format_copy(result, &pref->formats[idx]);
+	} else {
+		ast_format_clear(result);
+		return NULL;
+	}
+
+	return result;
+}
+
+/*! \brief Remove codec from pref list */
+void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
+{
+	struct ast_codec_pref oldorder;
+	int x, y = 0;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list;
+
+	if (!pref->order[0]) {
+		return;
+	}
+
+	f_list = ast_format_list_get(&f_len);
+	memcpy(&oldorder, pref, sizeof(oldorder));
+	memset(pref, 0, sizeof(*pref));
+
+	for (x = 0; x < f_len; x++) {
+		if (!oldorder.order[x]) {
+			break;
+		}
+		if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
+			pref->order[y] = oldorder.order[x];
+			ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
+			pref->framing[y++] = oldorder.framing[x];
+		}
+	}
+	ast_format_list_destroy(f_list);
+}
+
+/*! \brief Append codec to list */
+int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
+{
+	int x, newindex = 0;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	ast_codec_pref_remove(pref, format);
+
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			newindex = x + 1;
+			break;
+		}
+	}
+
+	if (newindex) {
+		for (x = 0; x < f_len; x++) {
+			if (!pref->order[x]) {
+				pref->order[x] = newindex;
+				ast_format_copy(&pref->formats[x], format);
+				break;
+			}
+		}
+	}
+
+	ast_format_list_destroy(f_list);
+	return x;
+}
+
+/*! \brief Prepend codec to list */
+void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
+{
+	int x, newindex = 0;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	/* First step is to get the codecs "index number" */
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			newindex = x + 1;
+			break;
+		}
+	}
+	/* Done if its unknown */
+	if (!newindex) {
+		ast_format_list_destroy(f_list);
+		return;
+	}
+
+	/* Now find any existing occurrence, or the end */
+	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+		if (!pref->order[x] || pref->order[x] == newindex)
+			break;
+	}
+
+	/* If we failed to find any occurrence, set to the end */
+	if (x == AST_CODEC_PREF_SIZE) {
+		--x;
+	}
+
+	if (only_if_existing && !pref->order[x]) {
+		ast_format_list_destroy(f_list);
+		return;
+	}
+
+	/* Move down to make space to insert - either all the way to the end,
+	   or as far as the existing location (which will be overwritten) */
+	for (; x > 0; x--) {
+		pref->order[x] = pref->order[x - 1];
+		pref->framing[x] = pref->framing[x - 1];
+		ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
+	}
+
+	/* And insert the new entry */
+	pref->order[0] = newindex;
+	pref->framing[0] = 0; /* ? */
+	ast_format_copy(&pref->formats[0], format);
+	ast_format_list_destroy(f_list);
+}
+
+/*! \brief Set packet size for codec */
+int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
+{
+	int x, idx = -1;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			idx = x;
+			break;
+		}
+	}
+
+	if (idx < 0) {
+		ast_format_list_destroy(f_list);
+		return -1;
+	}
+
+	/* size validation */
+	if (!framems)
+		framems = f_list[idx].def_ms;
+
+	if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
+		framems -= framems % f_list[idx].inc_ms;
+
+	if (framems < f_list[idx].min_ms)
+		framems = f_list[idx].min_ms;
+
+	if (framems > f_list[idx].max_ms)
+		framems = f_list[idx].max_ms;
+
+	for (x = 0; x < f_len; x++) {
+		if (pref->order[x] == (idx + 1)) {
+			pref->framing[x] = framems;
+			break;
+		}
+	}
+
+	ast_format_list_destroy(f_list);
+	return x;
+}
+
+/*! \brief Get packet size for codec */
+struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
+{
+	int x, idx = -1, framems = 0;
+	struct ast_format_list fmt = { { 0, }, };
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	for (x = 0; x < f_len; x++) {
+		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			fmt = f_list[x];
+			idx = x;
+			break;
+		}
+	}
+
+	if (idx < 0) {
+		ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
+		ast_format_list_destroy(f_list);
+		return fmt;
+	}
+
+	for (x = 0; x < f_len; x++) {
+		if (pref->order[x] == (idx + 1)) {
+			framems = pref->framing[x];
+			break;
+		}
+	}
+
+	/* size validation */
+	if (!framems)
+		framems = f_list[idx].def_ms;
+
+	if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
+		framems -= framems % f_list[idx].inc_ms;
+
+	if (framems < f_list[idx].min_ms)
+		framems = f_list[idx].min_ms;
+
+	if (framems > f_list[idx].max_ms)
+		framems = f_list[idx].max_ms;
+
+	fmt.cur_ms = framems;
+	ast_format_list_destroy(f_list);
+	return fmt;
+}
+
+/*! \brief Pick a codec */
+struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
+{
+	int x, slot, found = 0;
+	size_t f_len = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_len);
+
+	for (x = 0; x < f_len; x++) {
+		slot = pref->order[x];
+
+		if (!slot)
+			break;
+		if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
+			found = 1; /*format is found and stored in result */
+			break;
+		}
+	}
+	ast_format_list_destroy(f_list);
+	if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) {
+		return result;
+	}
+	ast_format_clear(result);
+	ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
+
+	return find_best ? ast_best_codec(cap, result) : NULL;
+}
+
+
diff --git a/main/frame.c b/main/frame.c
index e3a969c..47b518c 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -29,12 +29,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/lock.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 #include "asterisk/channel.h"
 #include "asterisk/cli.h"
 #include "asterisk/term.h"
@@ -72,8 +71,199 @@ struct ast_frame_cache {
 };
 #endif
 
+#define SMOOTHER_SIZE 8000
+
+enum frame_type {
+	TYPE_HIGH,     /* 0x0 */
+	TYPE_LOW,      /* 0x1 */
+	TYPE_SILENCE,  /* 0x2 */
+	TYPE_DONTSEND  /* 0x3 */
+};
+
+#define TYPE_MASK 0x3
+
+struct ast_smoother {
+	int size;
+	struct ast_format format;
+	int flags;
+	float samplesperbyte;
+	unsigned int opt_needs_swap:1;
+	struct ast_frame f;
+	struct timeval delivery;
+	char data[SMOOTHER_SIZE];
+	char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
+	struct ast_frame *opt;
+	int len;
+};
+
 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
 
+static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
+{
+	if (s->flags & AST_SMOOTHER_FLAG_G729) {
+		if (s->len % 10) {
+			ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
+			return 0;
+		}
+	}
+	if (swap) {
+		ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples);
+	} else {
+		memcpy(s->data + s->len, f->data.ptr, f->datalen);
+	}
+	/* If either side is empty, reset the delivery time */
+	if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) {	/* XXX really ? */
+		s->delivery = f->delivery;
+	}
+	s->len += f->datalen;
+
+	return 0;
+}
+
+void ast_smoother_reset(struct ast_smoother *s, int bytes)
+{
+	memset(s, 0, sizeof(*s));
+	s->size = bytes;
+}
+
+void ast_smoother_reconfigure(struct ast_smoother *s, int bytes)
+{
+	/* if there is no change, then nothing to do */
+	if (s->size == bytes) {
+		return;
+	}
+	/* set the new desired output size */
+	s->size = bytes;
+	/* if there is no 'optimized' frame in the smoother,
+	 *   then there is nothing left to do
+	 */
+	if (!s->opt) {
+		return;
+	}
+	/* there is an 'optimized' frame here at the old size,
+	 * but it must now be put into the buffer so the data
+	 * can be extracted at the new size
+	 */
+	smoother_frame_feed(s, s->opt, s->opt_needs_swap);
+	s->opt = NULL;
+}
+
+struct ast_smoother *ast_smoother_new(int size)
+{
+	struct ast_smoother *s;
+	if (size < 1)
+		return NULL;
+	if ((s = ast_malloc(sizeof(*s))))
+		ast_smoother_reset(s, size);
+	return s;
+}
+
+int ast_smoother_get_flags(struct ast_smoother *s)
+{
+	return s->flags;
+}
+
+void ast_smoother_set_flags(struct ast_smoother *s, int flags)
+{
+	s->flags = flags;
+}
+
+int ast_smoother_test_flag(struct ast_smoother *s, int flag)
+{
+	return (s->flags & flag);
+}
+
+int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
+{
+	if (f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
+		return -1;
+	}
+	if (!s->format.id) {
+		ast_format_copy(&s->format, &f->subclass.format);
+		s->samplesperbyte = (float)f->samples / (float)f->datalen;
+	} else if (ast_format_cmp(&s->format, &f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n",
+			ast_getformatname(&s->format), ast_getformatname(&f->subclass.format));
+		return -1;
+	}
+	if (s->len + f->datalen > SMOOTHER_SIZE) {
+		ast_log(LOG_WARNING, "Out of smoother space\n");
+		return -1;
+	}
+	if (((f->datalen == s->size) ||
+	     ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) &&
+	    !s->opt &&
+	    !s->len &&
+	    (f->offset >= AST_MIN_OFFSET)) {
+		/* Optimize by sending the frame we just got
+		   on the next read, thus eliminating the douple
+		   copy */
+		if (swap)
+			ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples);
+		s->opt = f;
+		s->opt_needs_swap = swap ? 1 : 0;
+		return 0;
+	}
+
+	return smoother_frame_feed(s, f, swap);
+}
+
+struct ast_frame *ast_smoother_read(struct ast_smoother *s)
+{
+	struct ast_frame *opt;
+	int len;
+
+	/* IF we have an optimization frame, send it */
+	if (s->opt) {
+		if (s->opt->offset < AST_FRIENDLY_OFFSET)
+			ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
+							s->opt->offset);
+		opt = s->opt;
+		s->opt = NULL;
+		return opt;
+	}
+
+	/* Make sure we have enough data */
+	if (s->len < s->size) {
+		/* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
+		if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10)))
+			return NULL;
+	}
+	len = s->size;
+	if (len > s->len)
+		len = s->len;
+	/* Make frame */
+	s->f.frametype = AST_FRAME_VOICE;
+	ast_format_copy(&s->f.subclass.format, &s->format);
+	s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET;
+	s->f.offset = AST_FRIENDLY_OFFSET;
+	s->f.datalen = len;
+	/* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
+	s->f.samples = len * s->samplesperbyte;	/* XXX rounding */
+	s->f.delivery = s->delivery;
+	/* Fill Data */
+	memcpy(s->f.data.ptr, s->data, len);
+	s->len -= len;
+	/* Move remaining data to the front if applicable */
+	if (s->len) {
+		/* In principle this should all be fine because if we are sending
+		   G.729 VAD, the next timestamp will take over anyawy */
+		memmove(s->data, s->data + len, s->len);
+		if (!ast_tvzero(s->delivery)) {
+			/* If we have delivery time, increment it, otherwise, leave it at 0 */
+			s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(&s->format)));
+		}
+	}
+	/* Return frame */
+	return &s->f;
+}
+
+void ast_smoother_free(struct ast_smoother *s)
+{
+	ast_free(s);
+}
+
 static struct ast_frame *ast_frame_header_new(void)
 {
 	struct ast_frame *f;
@@ -126,13 +316,9 @@ static void __frame_free(struct ast_frame *fr, int cache)
 		/* Cool, only the header is malloc'd, let's just cache those for now
 		 * to keep things simple... */
 		struct ast_frame_cache *frames;
+
 		if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) &&
 		    (frames->size < FRAME_CACHE_MAX_SIZE)) {
-			if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
-				(fr->frametype == AST_FRAME_IMAGE)) {
-				ao2_cleanup(fr->subclass.format);
-			}
-
 			AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
 			frames->size++;
 			return;
@@ -149,14 +335,7 @@ static void __frame_free(struct ast_frame *fr, int cache)
 			ast_free((void *) fr->src);
 	}
 	if (fr->mallocd & AST_MALLOCD_HDR) {
-		if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
-			(fr->frametype == AST_FRAME_IMAGE)) {
-			ao2_cleanup(fr->subclass.format);
-		}
-
 		ast_free(fr);
-	} else {
-		fr->mallocd = 0;
 	}
 }
 
@@ -172,13 +351,6 @@ void ast_frame_free(struct ast_frame *frame, int cache)
 	}
 }
 
-void ast_frame_dtor(struct ast_frame *f)
-{
-	if (f) {
-		ast_frfree(f);
-	}
-}
-
 /*!
  * \brief 'isolates' a frame by duplicating non-malloc'ed components
  * (header, src, data).
@@ -208,12 +380,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
 			return NULL;
 		}
 		out->frametype = fr->frametype;
-		if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
-			(fr->frametype == AST_FRAME_IMAGE)) {
-			out->subclass.format = ao2_bump(fr->subclass.format);
-		} else {
-			memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass));
-		}
+		ast_format_copy(&out->subclass.format, &fr->subclass.format);
 		out->datalen = fr->datalen;
 		out->samples = fr->samples;
 		out->offset = fr->offset;
@@ -320,12 +487,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
 	}
 
 	out->frametype = f->frametype;
-	if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) ||
-		(f->frametype == AST_FRAME_IMAGE)) {
-		out->subclass.format = ao2_bump(f->subclass.format);
-	} else {
-		memcpy(&out->subclass, &f->subclass, sizeof(out->subclass));
-	}
+	ast_format_copy(&out->subclass.format, &f->subclass.format);
 	out->datalen = f->datalen;
 	out->samples = f->samples;
 	out->delivery = f->delivery;
@@ -466,14 +628,6 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch
 		/* Should never happen */
 		snprintf(subclass, slen, "IAX Frametype %d", f->subclass.integer);
 		break;
-	case AST_FRAME_BRIDGE_ACTION:
-		/* Should never happen */
-		snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
-		break;
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
-		/* Should never happen */
-		snprintf(subclass, slen, "Synchronous Bridge Frametype %d", f->subclass.integer);
-		break;
 	case AST_FRAME_TEXT:
 		ast_copy_string(subclass, "N/A", slen);
 		if (moreinfo) {
@@ -481,7 +635,7 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch
 		}
 		break;
 	case AST_FRAME_IMAGE:
-		snprintf(subclass, slen, "Image format %s\n", ast_format_get_name(f->subclass.format));
+		snprintf(subclass, slen, "Image format %s\n", ast_getformatname(&f->subclass.format));
 		break;
 	case AST_FRAME_HTML:
 		switch (f->subclass.integer) {
@@ -538,7 +692,6 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch
 		break;
 	default:
 		ast_copy_string(subclass, "Unknown Subclass", slen);
-		break;
 	}
 }
 
@@ -561,14 +714,6 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
 		/* Should never happen */
 		ast_copy_string(ftype, "IAX Specific", len);
 		break;
-	case AST_FRAME_BRIDGE_ACTION:
-		/* Should never happen */
-		ast_copy_string(ftype, "Bridge Specific", len);
-		break;
-	case AST_FRAME_BRIDGE_ACTION_SYNC:
-		/* Should never happen */
-		ast_copy_string(ftype, "Bridge Specific", len);
-		break;
 	case AST_FRAME_TEXT:
 		ast_copy_string(ftype, "Text", len);
 		break;
@@ -589,7 +734,6 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
 		break;
 	default:
 		snprintf(ftype, len, "Unknown Frametype '%u'", frame_type);
-		break;
 	}
 }
 
@@ -647,13 +791,367 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
 			    term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
 }
 
+int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing)
+{
+	int errors = 0, framems = 0, all = 0, iter_allowing;
+	char *parse = NULL, *this = NULL, *psize = NULL;
+	struct ast_format format;
+
+	if (!allowing && ast_strlen_zero(list)) {
+		return 0;
+	}
+
+	parse = ast_strdupa(list);
+	while ((this = strsep(&parse, ","))) {
+		iter_allowing = allowing;
+		framems = 0;
+		if (*this == '!') {
+			this++;
+			iter_allowing = !allowing;
+		}
+		if ((psize = strrchr(this, ':'))) {
+			*psize++ = '\0';
+			ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
+			framems = atoi(psize);
+			if (framems < 0) {
+				framems = 0;
+				errors++;
+				ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
+			}
+		}
+		all = strcasecmp(this, "all") ? 0 : 1;
+
+		if (!all && !ast_getformatbyname(this, &format)) {
+			ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
+			errors++;
+			continue;
+		}
+
+		if (cap) {
+			if (iter_allowing) {
+				if (all) {
+					ast_format_cap_add_all(cap);
+				} else {
+					ast_format_cap_add(cap, &format);
+				}
+			} else {
+				if (all) {
+					ast_format_cap_remove_all(cap);
+				} else {
+					ast_format_cap_remove(cap, &format);
+				}
+			}
+		}
+
+		if (pref) {
+			if (!all) {
+				if (iter_allowing) {
+					ast_codec_pref_append(pref, &format);
+					ast_codec_pref_setsize(pref, &format, framems);
+				} else {
+					ast_codec_pref_remove(pref, &format);
+				}
+			} else if (!iter_allowing) {
+				memset(pref, 0, sizeof(*pref));
+			}
+		}
+	}
+	return errors;
+}
+
+static int g723_len(unsigned char buf)
+{
+	enum frame_type type = buf & TYPE_MASK;
+
+	switch(type) {
+	case TYPE_DONTSEND:
+		return 0;
+		break;
+	case TYPE_SILENCE:
+		return 4;
+		break;
+	case TYPE_HIGH:
+		return 24;
+		break;
+	case TYPE_LOW:
+		return 20;
+		break;
+	default:
+		ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type);
+	}
+	return -1;
+}
+
+static int g723_samples(unsigned char *buf, int maxlen)
+{
+	int pos = 0;
+	int samples = 0;
+	int res;
+	while(pos < maxlen) {
+		res = g723_len(buf[pos]);
+		if (res <= 0)
+			break;
+		samples += 240;
+		pos += res;
+	}
+	return samples;
+}
+
+static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
+{
+	int byte = bit / 8;       /* byte containing first bit */
+	int rem = 8 - (bit % 8);  /* remaining bits in first byte */
+	unsigned char ret = 0;
+
+	if (n <= 0 || n > 8)
+		return 0;
+
+	if (rem < n) {
+		ret = (data[byte] << (n - rem));
+		ret |= (data[byte + 1] >> (8 - n + rem));
+	} else {
+		ret = (data[byte] >> (rem - n));
+	}
+
+	return (ret & (0xff >> (8 - n)));
+}
+
+static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+{
+	static const int SpeexWBSubModeSz[] = {
+		4, 36, 112, 192,
+		352, 0, 0, 0 };
+	int off = bit;
+	unsigned char c;
+
+	/* skip up to two wideband frames */
+	if (((len * 8 - off) >= 5) &&
+		get_n_bits_at(data, 1, off)) {
+		c = get_n_bits_at(data, 3, off + 1);
+		off += SpeexWBSubModeSz[c];
+
+		if (((len * 8 - off) >= 5) &&
+			get_n_bits_at(data, 1, off)) {
+			c = get_n_bits_at(data, 3, off + 1);
+			off += SpeexWBSubModeSz[c];
+
+			if (((len * 8 - off) >= 5) &&
+				get_n_bits_at(data, 1, off)) {
+				ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
+				return -1;
+			}
+		}
+
+	}
+	return off - bit;
+}
+
+static int speex_samples(unsigned char *data, int len)
+{
+	static const int SpeexSubModeSz[] = {
+		5, 43, 119, 160,
+		220, 300, 364, 492,
+		79, 0, 0, 0,
+		0, 0, 0, 0 };
+	static const int SpeexInBandSz[] = {
+		1, 1, 4, 4,
+		4, 4, 4, 4,
+		8, 8, 16, 16,
+		32, 32, 64, 64 };
+	int bit = 0;
+	int cnt = 0;
+	int off;
+	unsigned char c;
+
+	while ((len * 8 - bit) >= 5) {
+		/* skip wideband frames */
+		off = speex_get_wb_sz_at(data, len, bit);
+		if (off < 0)  {
+			ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
+			break;
+		}
+		bit += off;
+
+		if ((len * 8 - bit) < 5)
+			break;
+
+		/* get control bits */
+		c = get_n_bits_at(data, 5, bit);
+		bit += 5;
+
+		if (c == 15) {
+			/* terminator */
+			break;
+		} else if (c == 14) {
+			/* in-band signal; next 4 bits contain signal id */
+			c = get_n_bits_at(data, 4, bit);
+			bit += 4;
+			bit += SpeexInBandSz[c];
+		} else if (c == 13) {
+			/* user in-band; next 4 bits contain msg len */
+			c = get_n_bits_at(data, 4, bit);
+			bit += 4;
+			/* after which it's 5-bit signal id + c bytes of data */
+			bit += 5 + c * 8;
+		} else if (c > 8) {
+			/* unknown */
+			ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
+			break;
+		} else {
+			/* skip number bits for submode (less the 5 control bits) */
+			bit += SpeexSubModeSz[c] - 5;
+			cnt += 160; /* new frame */
+		}
+	}
+	return cnt;
+}
+
+int ast_codec_get_samples(struct ast_frame *f)
+{
+	int samples = 0;
+
+	switch (f->subclass.format.id) {
+	case AST_FORMAT_SPEEX:
+		samples = speex_samples(f->data.ptr, f->datalen);
+		break;
+	case AST_FORMAT_SPEEX16:
+		samples = 2 * speex_samples(f->data.ptr, f->datalen);
+		break;
+	case AST_FORMAT_SPEEX32:
+		samples = 4 * speex_samples(f->data.ptr, f->datalen);
+		break;
+	case AST_FORMAT_G723_1:
+		samples = g723_samples(f->data.ptr, f->datalen);
+		break;
+	case AST_FORMAT_ILBC:
+		samples = 240 * (f->datalen / 50);
+		break;
+	case AST_FORMAT_GSM:
+		samples = 160 * (f->datalen / 33);
+		break;
+	case AST_FORMAT_G729A:
+		samples = f->datalen * 8;
+		break;
+	case AST_FORMAT_SLINEAR:
+	case AST_FORMAT_SLINEAR16:
+		samples = f->datalen / 2;
+		break;
+	case AST_FORMAT_LPC10:
+		/* assumes that the RTP packet contains one LPC10 frame */
+		samples = 22 * 8;
+		samples += (((char *)(f->data.ptr))[7] & 0x1) * 8;
+		break;
+	case AST_FORMAT_ULAW:
+	case AST_FORMAT_ALAW:
+	case AST_FORMAT_TESTLAW:
+		samples = f->datalen;
+		break;
+	case AST_FORMAT_G722:
+	case AST_FORMAT_ADPCM:
+	case AST_FORMAT_G726:
+	case AST_FORMAT_G726_AAL2:
+		samples = f->datalen * 2;
+		break;
+	case AST_FORMAT_SIREN7:
+		/* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+		samples = f->datalen * (16000 / 4000);
+		break;
+	case AST_FORMAT_SIREN14:
+		/* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+		samples = (int) f->datalen * ((float) 32000 / 6000);
+		break;
+	case AST_FORMAT_G719:
+		/* 48,000 samples per second at 64kbps is 8,000 bytes per second */
+		samples = (int) f->datalen * ((float) 48000 / 8000);
+		break;
+	case AST_FORMAT_SILK:
+		if (!(ast_format_isset(&f->subclass.format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_24KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 480;
+		} else if (!(ast_format_isset(&f->subclass.format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 320;
+		} else if (!(ast_format_isset(&f->subclass.format,
+			SILK_ATTR_KEY_SAMP_RATE,
+			SILK_ATTR_VAL_SAMP_12KHZ,
+			AST_FORMAT_ATTR_END))) {
+			return 240;
+		} else {
+			return 160;
+		}
+	case AST_FORMAT_CELT:
+		/* TODO The assumes 20ms delivery right now, which is incorrect */
+		samples = ast_format_rate(&f->subclass.format) / 50;
+		break;
+	default:
+		ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
+	}
+	return samples;
+}
+
+int ast_codec_get_len(struct ast_format *format, int samples)
+{
+	int len = 0;
+
+	/* XXX Still need speex, and lpc10 XXX */
+	switch(format->id) {
+	case AST_FORMAT_G723_1:
+		len = (samples / 240) * 20;
+		break;
+	case AST_FORMAT_ILBC:
+		len = (samples / 240) * 50;
+		break;
+	case AST_FORMAT_GSM:
+		len = (samples / 160) * 33;
+		break;
+	case AST_FORMAT_G729A:
+		len = samples / 8;
+		break;
+	case AST_FORMAT_SLINEAR:
+	case AST_FORMAT_SLINEAR16:
+		len = samples * 2;
+		break;
+	case AST_FORMAT_ULAW:
+	case AST_FORMAT_ALAW:
+	case AST_FORMAT_TESTLAW:
+		len = samples;
+		break;
+	case AST_FORMAT_G722:
+	case AST_FORMAT_ADPCM:
+	case AST_FORMAT_G726:
+	case AST_FORMAT_G726_AAL2:
+		len = samples / 2;
+		break;
+	case AST_FORMAT_SIREN7:
+		/* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+		len = samples / (16000 / 4000);
+		break;
+	case AST_FORMAT_SIREN14:
+		/* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+		len = (int) samples / ((float) 32000 / 6000);
+		break;
+	case AST_FORMAT_G719:
+		/* 48,000 samples per second at 64kbps is 8,000 bytes per second */
+		len = (int) samples / ((float) 48000 / 8000);
+		break;
+	default:
+		ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
+	}
+
+	return len;
+}
+
 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
 {
 	int count;
 	short *fdata = f->data.ptr;
 	short adjust_value = abs(adjustment);
 
-	if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_cache_is_slinear(f->subclass.format))) {
+	if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_is_slinear(&f->subclass.format))) {
 		return -1;
 	}
 
@@ -677,10 +1175,10 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
 	int count;
 	short *data1, *data2;
 
-	if ((f1->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f1->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
+	if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass.format.id != AST_FORMAT_SLINEAR))
 		return -1;
 
-	if ((f2->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f2->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL))
+	if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass.format.id != AST_FORMAT_SLINEAR))
 		return -1;
 
 	if (f1->samples != f2->samples)
diff --git a/main/framehook.c b/main/framehook.c
index 54537c5..1338a2f 100644
--- a/main/framehook.c
+++ b/main/framehook.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424507 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/linkedlists.h"
@@ -49,23 +49,11 @@ struct ast_framehook {
 };
 
 struct ast_framehook_list {
-	/*! the number of hooks currently present */
-	unsigned int count;
-	/*! id for next framehook added */
 	unsigned int id_count;
 	AST_LIST_HEAD_NOLOCK(, ast_framehook) list;
 };
 
-enum framehook_detachment_mode
-{
-	/*! Destroy the framehook outright. */
-	FRAMEHOOK_DETACH_DESTROY = 0,
-	/*! Remove the framehook from the channel, but don't destroy the data since
-	 *  it will be used by a replacement framehook on another channel. */
-	FRAMEHOOK_DETACH_PRESERVE,
-};
-
-static void framehook_detach(struct ast_framehook *framehook, enum framehook_detachment_mode mode)
+static void framehook_detach_and_destroy(struct ast_framehook *framehook)
 {
 	struct ast_frame *frame;
 	frame = framehook->i.event_cb(framehook->chan, NULL, AST_FRAMEHOOK_EVENT_DETACHED, framehook->i.data);
@@ -76,7 +64,7 @@ static void framehook_detach(struct ast_framehook *framehook, enum framehook_det
 	}
 	framehook->chan = NULL;
 
-	if (mode == FRAMEHOOK_DETACH_DESTROY && framehook->i.destroy_cb) {
+	if (framehook->i.destroy_cb) {
 		framehook->i.destroy_cb(framehook->i.data);
 	}
 	ast_free(framehook);
@@ -85,49 +73,21 @@ static void framehook_detach(struct ast_framehook *framehook, enum framehook_det
 static struct ast_frame *framehook_list_push_event(struct ast_framehook_list *framehooks, struct ast_frame *frame, enum ast_framehook_event event)
 {
 	struct ast_framehook *framehook;
-	struct ast_frame *original_frame;
-	int *skip;
-	size_t skip_size;
 
 	if (!framehooks) {
 		return frame;
 	}
 
-	skip_size = sizeof(int) * framehooks->count;
-	skip = ast_alloca(skip_size);
-	memset(skip, 0, skip_size);
-
-	do {
-		unsigned int num = 0;
-		original_frame = frame;
-
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&framehooks->list, framehook, list) {
-			if (framehook->detach_and_destroy_me) {
-				/* this guy is signaled for destruction */
-				AST_LIST_REMOVE_CURRENT(list);
-				framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
-				continue;
-			}
-
-			/* If this framehook has been marked as needing to be skipped, do so */
-			if (skip[num]) {
-				num++;
-				continue;
-			}
-
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&framehooks->list, framehook, list) {
+		if (framehook->detach_and_destroy_me) {
+			/* this guy is signaled for destruction */
+			AST_LIST_REMOVE_CURRENT(list);
+			framehook_detach_and_destroy(framehook);
+		} else {
 			frame = framehook->i.event_cb(framehook->chan, frame, event, framehook->i.data);
-
-			if (frame != original_frame) {
-				/* To prevent looping we skip any framehooks that have already provided a modified frame */
-				skip[num] = 1;
-				break;
-			}
-
-			num++;
 		}
-		AST_LIST_TRAVERSE_SAFE_END;
-	} while (frame != original_frame);
-
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
 	return frame;
 }
 
@@ -137,7 +97,7 @@ int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interfac
 	struct ast_framehook_list *fh_list;
 	struct ast_frame *frame;
 	if (i->version != AST_FRAMEHOOK_INTERFACE_VERSION) {
-		ast_log(LOG_ERROR, "Version '%hu' of framehook interface not what we compiled against (%hu)\n",
+		ast_log(LOG_ERROR, "Version '%hu' of framehook interface not what we compiled against (%i)\n",
 			i->version, AST_FRAMEHOOK_INTERFACE_VERSION);
 		return -1;
 	}
@@ -156,7 +116,6 @@ int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interfac
 		ast_channel_framehooks_set(chan, fh_list);
 	}
 
-	ast_channel_framehooks(chan)->count++;
 	framehook->id = ++ast_channel_framehooks(chan)->id_count;
 	AST_LIST_INSERT_TAIL(&ast_channel_framehooks(chan)->list, framehook, list);
 
@@ -169,10 +128,6 @@ int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interfac
 		ast_frfree(frame);
 	}
 
-	if (ast_channel_is_bridged(chan)) {
-		ast_channel_set_unbridged_nolock(chan, 1);
-	}
-
 	return framehook->id;
 }
 
@@ -198,10 +153,6 @@ int ast_framehook_detach(struct ast_channel *chan, int id)
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
 
-	if (!res && ast_channel_is_bridged(chan)) {
-		ast_channel_set_unbridged_nolock(chan, 1);
-	}
-
 	return res;
 }
 
@@ -214,7 +165,7 @@ int ast_framehook_list_destroy(struct ast_channel *chan)
 	}
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&ast_channel_framehooks(chan)->list, framehook, list) {
 		AST_LIST_REMOVE_CURRENT(list);
-		framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
+		framehook_detach_and_destroy(framehook);
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
 	ast_free(ast_channel_framehooks(chan));
@@ -222,57 +173,6 @@ int ast_framehook_list_destroy(struct ast_channel *chan)
 	return 0;
 }
 
-void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct ast_framehook *framehook;
-	int moved_framehook_id;
-
-	if (ast_channel_framehooks(new_chan)) {
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&ast_channel_framehooks(new_chan)->list, framehook, list) {
-			if (framehook->i.disable_inheritance) {
-				ast_framehook_detach(new_chan, framehook->id);
-				continue;
-			}
-
-			if (framehook->i.chan_breakdown_cb) {
-				framehook->i.chan_breakdown_cb(framehook->i.data, framehook->id,
-					old_chan, new_chan);
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-	}
-
-	if (!ast_channel_framehooks(old_chan)) {
-		return;
-	}
-
-	if (!AST_LIST_EMPTY(&ast_channel_framehooks(old_chan)->list)
-		&& ast_channel_is_bridged(old_chan)) {
-		ast_channel_set_unbridged_nolock(old_chan, 1);
-	}
-	while ((framehook = AST_LIST_REMOVE_HEAD(&ast_channel_framehooks(old_chan)->list, list))) {
-		/* If inheritance is not allowed for this framehook, just destroy it. */
-		if (framehook->i.disable_inheritance) {
-			framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
-			continue;
-		}
-
-		/* Otherwise move it to the other channel and perform any fixups set by the framehook interface */
-		moved_framehook_id = ast_framehook_attach(new_chan, &framehook->i);
-		if (moved_framehook_id < 0) {
-			ast_log(LOG_WARNING, "Failed framehook copy during masquerade. Expect loss of features.\n");
-			framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
-		} else {
-			if (framehook->i.chan_fixup_cb) {
-				framehook->i.chan_fixup_cb(framehook->i.data, moved_framehook_id,
-					old_chan, new_chan);
-			}
-
-			framehook_detach(framehook, FRAMEHOOK_DETACH_PRESERVE);
-		}
-	}
-}
-
 int ast_framehook_list_is_empty(struct ast_framehook_list *framehooks)
 {
 	if (!framehooks) {
@@ -281,37 +181,6 @@ int ast_framehook_list_is_empty(struct ast_framehook_list *framehooks)
 	return AST_LIST_EMPTY(&framehooks->list) ? 1 : 0;
 }
 
-int ast_framehook_list_contains_no_active(struct ast_framehook_list *framehooks)
-{
-	return ast_framehook_list_contains_no_active_of_type(framehooks, 0);
-}
-
-int ast_framehook_list_contains_no_active_of_type(struct ast_framehook_list *framehooks,
-	enum ast_frame_type type)
-{
-	struct ast_framehook *cur;
-
-	if (!framehooks) {
-		return 1;
-	}
-
-	if (AST_LIST_EMPTY(&framehooks->list)) {
-		return 1;
-	}
-
-	AST_LIST_TRAVERSE(&framehooks->list, cur, list) {
-		if (cur->detach_and_destroy_me) {
-			continue;
-		}
-		if (type && cur->i.consume_cb && !cur->i.consume_cb(cur->i.data, type)) {
-			continue;
-		}
-		return 0;
-	}
-
-	return 1;
-}
-
 struct ast_frame *ast_framehook_list_write_event(struct ast_framehook_list *framehooks, struct ast_frame *frame)
 {
 	return framehook_list_push_event(framehooks, frame, AST_FRAMEHOOK_EVENT_WRITE);
diff --git a/main/fskmodem_float.c b/main/fskmodem_float.c
index 97ab895..7bddee7 100644
--- a/main/fskmodem_float.c
+++ b/main/fskmodem_float.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 
diff --git a/main/fskmodem_int.c b/main/fskmodem_int.c
index 3a7521a..cc720fe 100644
--- a/main/fskmodem_int.c
+++ b/main/fskmodem_int.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/fskmodem.h"
 
diff --git a/main/global_datastores.c b/main/global_datastores.c
index 93d299c..92c6bb4 100644
--- a/main/global_datastores.c
+++ b/main/global_datastores.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/global_datastores.h"
 #include "asterisk/linkedlists.h"
diff --git a/main/hashtab.c b/main/hashtab.c
index 09166dc..4b76597 100644
--- a/main/hashtab.c
+++ b/main/hashtab.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396850 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 
@@ -43,10 +43,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396850 $")
 #include "asterisk/hashtab.h"
 
 
-#ifndef __AST_DEBUG_MALLOC
-void *_ast_mem_backtrace_buffer[_AST_MEM_BACKTRACE_BUFLEN];
-#endif
-
 #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
 static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func);
 #define ast_hashtab_resize(a)	_ast_hashtab_resize(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
diff --git a/main/heap.c b/main/heap.c
index e441790..c04f7a0 100644
--- a/main/heap.c
+++ b/main/heap.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398760 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/heap.h"
 #include "asterisk/utils.h"
diff --git a/main/http.c b/main/http.c
index 2319448..533397b 100644
--- a/main/http.c
+++ b/main/http.c
@@ -25,26 +25,18 @@
  * This program implements a tiny http server
  * and was inspired by micro-httpd by Jef Poskanzer
  *
- * GMime http://spruce.sourceforge.net/gmime/
+ * \extref GMime http://spruce.sourceforge.net/gmime/
  *
  * \ref AstHTTP - AMI over the http protocol
  */
 
-/*! \li \ref http.c uses the configuration file \ref http.conf
- * \addtogroup configuration_file
- */
-
-/*! \page http.conf http.conf
- * \verbinclude http.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418067 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 #include <sys/time.h>
@@ -65,36 +57,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418067 $")
 #include "asterisk/_private.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/netsock2.h"
-#include "asterisk/json.h"
 
 #define MAX_PREFIX 80
 #define DEFAULT_PORT 8088
 #define DEFAULT_TLS_PORT 8089
 #define DEFAULT_SESSION_LIMIT 100
-/*! (ms) Idle time waiting for data. */
-#define DEFAULT_SESSION_INACTIVITY 30000
-/*! (ms) Min timeout for initial HTTP request to start coming in. */
-#define MIN_INITIAL_REQUEST_TIMEOUT	10000
-/*! (ms) Idle time between HTTP requests */
-#define DEFAULT_SESSION_KEEP_ALIVE 15000
-
-/*! Maximum application/json or application/x-www-form-urlencoded body content length. */
-#if !defined(LOW_MEMORY)
-#define MAX_CONTENT_LENGTH 4096
-#else
-#define MAX_CONTENT_LENGTH 1024
-#endif	/* !defined(LOW_MEMORY) */
+#define DEFAULT_SESSION_INACTIVITY 30000	/* (ms) Idle time waiting for data. */
 
-/*! Maximum line length for HTTP requests. */
-#if !defined(LOW_MEMORY)
-#define MAX_HTTP_LINE_LENGTH 4096
-#else
-#define MAX_HTTP_LINE_LENGTH 1024
-#endif	/* !defined(LOW_MEMORY) */
+/* See http.h for more information about the SSL implementation */
+#if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
+#define	DO_SSL	/* comment in/out if you want to support ssl */
+#endif
 
 static int session_limit = DEFAULT_SESSION_LIMIT;
 static int session_inactivity = DEFAULT_SESSION_INACTIVITY;
-static int session_keep_alive = DEFAULT_SESSION_KEEP_ALIVE;
 static int session_count = 0;
 
 static struct ast_tls_config http_tls_cfg;
@@ -171,8 +147,6 @@ static const struct ast_cfhttp_methods_text {
 	{ AST_HTTP_POST,        "POST" },
 	{ AST_HTTP_HEAD,        "HEAD" },
 	{ AST_HTTP_PUT,         "PUT" },
-	{ AST_HTTP_DELETE,      "DELETE" },
-	{ AST_HTTP_OPTIONS,     "OPTIONS" },
 };
 
 const char *ast_get_http_method(enum ast_http_method method)
@@ -246,7 +220,7 @@ static int static_callback(struct ast_tcptls_session_instance *ser,
 
 	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
 	}
 
 	/* Yuck.  I'm not really sold on this, but if you don't deliver static content it makes your configuration
@@ -315,12 +289,9 @@ static int static_callback(struct ast_tcptls_session_instance *ser,
 		}
 	}
 
-	http_header = ast_str_create(255);
-	if (!http_header) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
+	if ( (http_header = ast_str_create(255)) == NULL) {
 		close(fd);
-		return 0;
+		return -1;
 	}
 
 	ast_str_set(&http_header, 0, "Content-type: %s\r\n"
@@ -341,12 +312,11 @@ static int static_callback(struct ast_tcptls_session_instance *ser,
 
 out404:
 	ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
-	return 0;
+	return -1;
 
 out403:
-	ast_http_request_close_on_completion(ser);
 	ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
-	return 0;
+	return -1;
 }
 
 static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
@@ -359,18 +329,15 @@ static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
 
 	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
 	}
 
-	out = ast_str_create(512);
-	if (!out) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
-		return 0;
+	if ( (out = ast_str_create(512)) == NULL) {
+		return -1;
 	}
 
 	ast_str_append(&out, 0,
-		"<title>Asterisk HTTP Status</title>\r\n"
+		"<html><title>Asterisk HTTP Status</title>\r\n"
 		"<body bgcolor=\"#ffffff\">\r\n"
 		"<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
 		"<h2>  Asterisk™ HTTP Status</h2></td></tr>\r\n");
@@ -396,7 +363,7 @@ static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
 	}
 	ast_variables_destroy(cookies);
 
-	ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
+	ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body></html>\r\n");
 	ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
 	return 0;
 }
@@ -419,63 +386,23 @@ static struct ast_http_uri staticuri = {
 	.key= __FILE__,
 };
 
-enum http_private_flags {
-	/*! TRUE if the HTTP request has a body. */
-	HTTP_FLAG_HAS_BODY = (1 << 0),
-	/*! TRUE if the HTTP request body has been read. */
-	HTTP_FLAG_BODY_READ = (1 << 1),
-	/*! TRUE if the HTTP request must close when completed. */
-	HTTP_FLAG_CLOSE_ON_COMPLETION = (1 << 2),
-};
-
-/*! HTTP tcptls worker_fn private data. */
-struct http_worker_private_data {
-	/*! Body length or -1 if chunked.  Valid if HTTP_FLAG_HAS_BODY is TRUE. */
-	int body_length;
-	/*! HTTP body tracking flags */
-	struct ast_flags flags;
-};
 
+/* send http/1.1 response */
+/* free content variable and close socket*/
 void ast_http_send(struct ast_tcptls_session_instance *ser,
 	enum ast_http_method method, int status_code, const char *status_title,
-	struct ast_str *http_header, struct ast_str *out, int fd,
+	struct ast_str *http_header, struct ast_str *out, const int fd,
 	unsigned int static_content)
 {
 	struct timeval now = ast_tvnow();
 	struct ast_tm tm;
 	char timebuf[80];
 	int content_length = 0;
-	int close_connection;
 
-	if (!ser || !ser->f) {
-		/* The connection is not open. */
-		ast_free(http_header);
-		ast_free(out);
+	if (!ser || 0 == ser->f) {
 		return;
 	}
 
-	/*
-	 * We shouldn't be sending non-final status codes to this
-	 * function because we may close the connection before
-	 * returning.
-	 */
-	ast_assert(200 <= status_code);
-
-	if (session_keep_alive <= 0) {
-		close_connection = 1;
-	} else {
-		struct http_worker_private_data *request;
-
-		request = ser->private_data;
-		if (!request
-			|| ast_test_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION)
-			|| ast_http_body_discard(ser)) {
-			close_connection = 1;
-		} else {
-			close_connection = 0;
-		}
-	}
-
 	ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
 
 	/* calc content length */
@@ -489,22 +416,20 @@ void ast_http_send(struct ast_tcptls_session_instance *ser,
 	}
 
 	/* send http header */
-	fprintf(ser->f,
-		"HTTP/1.1 %d %s\r\n"
+	fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
 		"Server: Asterisk/%s\r\n"
 		"Date: %s\r\n"
-		"%s"
-		"%s"
+		"Connection: close\r\n"
 		"%s"
 		"Content-Length: %d\r\n"
+		"%s"
 		"\r\n",
 		status_code, status_title ? status_title : "OK",
 		ast_get_version(),
 		timebuf,
-		close_connection ? "Connection: close\r\n" : "",
 		static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
-		http_header ? ast_str_buffer(http_header) : "",
-		content_length
+		content_length,
+		http_header ? ast_str_buffer(http_header) : ""
 		);
 
 	/* send content */
@@ -512,35 +437,33 @@ void ast_http_send(struct ast_tcptls_session_instance *ser,
 		if (out && ast_str_strlen(out)) {
 			if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) {
 				ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
-				close_connection = 1;
 			}
 		}
 
 		if (fd) {
 			char buf[256];
 			int len;
-
 			while ((len = read(fd, buf, sizeof(buf))) > 0) {
 				if (fwrite(buf, len, 1, ser->f) != 1) {
 					ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-					close_connection = 1;
 					break;
 				}
 			}
 		}
 	}
 
-	ast_free(http_header);
-	ast_free(out);
-
-	if (close_connection) {
-		ast_debug(1, "HTTP closing session.  status_code:%d\n", status_code);
-		ast_tcptls_close_session_file(ser);
-	} else {
-		ast_debug(1, "HTTP keeping session open.  status_code:%d\n", status_code);
+	if (http_header) {
+		ast_free(http_header);
+	}
+	if (out) {
+		ast_free(out);
 	}
+
+	ast_tcptls_close_session_file(ser);
+	return;
 }
 
+/* Send http "401 Unauthorized" responce and close socket*/
 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
 	const unsigned long nonce, const unsigned long opaque, int stale,
 	const char *text)
@@ -551,10 +474,6 @@ void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
 	if (!http_headers || !out) {
 		ast_free(http_headers);
 		ast_free(out);
-		if (ser && ser->f) {
-			ast_debug(1, "HTTP closing session.  Auth OOM\n");
-			ast_tcptls_close_session_file(ser);
-		}
 		return;
 	}
 
@@ -579,8 +498,10 @@ void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
 		text ? text : "");
 
 	ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
+	return;
 }
 
+/* send http error response and close socket*/
 void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
 {
 	struct ast_str *http_headers = ast_str_create(40);
@@ -589,10 +510,6 @@ void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, co
 	if (!http_headers || !out) {
 		ast_free(http_headers);
 		ast_free(out);
-		if (ser && ser->f) {
-			ast_debug(1, "HTTP closing session.  error OOM\n");
-			ast_tcptls_close_session_file(ser);
-		}
 		return;
 	}
 
@@ -608,13 +525,14 @@ void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, co
 		"<hr />\r\n"
 		"<address>Asterisk Server</address>\r\n"
 		"</body></html>\r\n",
-		status_code, status_title, status_title, text);
+			status_code, status_title, status_title, text);
 
 	ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
+	return;
 }
 
-/*!
- * \brief Link the new uri into the list.
+/*! \brief
+ * Link the new uri into the list.
  *
  * They are sorted by length of
  * the string, not alphabetically. Duplicate entries are not replaced,
@@ -678,787 +596,229 @@ void ast_http_uri_unlink_all_with_key(const char *key)
 	AST_RWLIST_UNLOCK(&uris);
 }
 
-/*!
- * \brief Retrieves the header with the given field name.
- *
- * \param headers Headers to search.
- * \param field_name Name of the header to find.
- * \return Associated header value.
- * \return \c NULL if header is not present.
+#define MAX_POST_CONTENT 1025
+
+/*
+ * get post variables from client Request Entity-Body, if content type is
+ * application/x-www-form-urlencoded
  */
-static const char *get_header(struct ast_variable *headers, const char *field_name)
+struct ast_variable *ast_http_get_post_vars(
+	struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
 {
-	struct ast_variable *v;
+	int content_length = 0;
+	struct ast_variable *v, *post_vars=NULL, *prev = NULL;
+	char *buf, *var, *val;
+	int res;
 
 	for (v = headers; v; v = v->next) {
-		if (!strcasecmp(v->name, field_name)) {
-			return v->value;
+		if (!strcasecmp(v->name, "Content-Type")) {
+			if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
+				return NULL;
+			}
+			break;
 		}
 	}
-	return NULL;
-}
 
-/*!
- * \brief Retrieves the content type specified in the "Content-Type" header.
- *
- * This function only returns the "type/subtype" and any trailing parameter is
- * not included.
- *
- * \note the return value is an allocated string that needs to be freed.
- *
- * \retval the content type/subtype or NULL if the header is not found.
- */
-static char *get_content_type(struct ast_variable *headers)
-{
-	const char *content_type = get_header(headers, "Content-Type");
-	const char *param;
-	size_t size;
+	for (v = headers; v; v = v->next) {
+		if (!strcasecmp(v->name, "Content-Length")) {
+			content_length = atoi(v->value);
+			break;
+		}
+	}
 
-	if (!content_type) {
+	if (content_length <= 0) {
 		return NULL;
 	}
 
-	param = strchr(content_type, ';');
-	size = param ? param - content_type : strlen(content_type);
-
-	return ast_strndup(content_type, size);
-}
-
-/*!
- * \brief Returns the value of the Content-Length header.
- *
- * \param headers HTTP headers.
- *
- * \retval length Value of the Content-Length header.
- * \retval 0 if header is not present.
- * \retval -1 if header is invalid.
- */
-static int get_content_length(struct ast_variable *headers)
-{
-	const char *content_length = get_header(headers, "Content-Length");
-	int length;
-
-	if (!content_length) {
-		/* Missing content length; assume zero */
-		return 0;
+	if (content_length > MAX_POST_CONTENT - 1) {
+		ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
+				content_length, MAX_POST_CONTENT);
+		ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
+		return NULL;
 	}
 
-	length = 0;
-	if (sscanf(content_length, "%30d", &length) != 1) {
-		/* Invalid Content-Length value */
-		length = -1;
+	buf = ast_malloc(content_length + 1);
+	if (!buf) {
+		return NULL;
 	}
-	return length;
-}
-
-/*!
- * \brief Returns the value of the Transfer-Encoding header.
- *
- * \param headers HTTP headers.
- * \retval string Value of the Transfer-Encoding header.
- * \retval NULL if header is not present.
- */
-static const char *get_transfer_encoding(struct ast_variable *headers)
-{
-	return get_header(headers, "Transfer-Encoding");
-}
-
-/*!
- * \internal
- * \brief Determine if the HTTP peer wants the connection closed.
- *
- * \param headers List of HTTP headers
- *
- * \retval 0 keep connection open.
- * \retval -1 close connection.
- */
-static int http_check_connection_close(struct ast_variable *headers)
-{
-	const char *connection = get_header(headers, "Connection");
-	int close_connection = 0;
 
-	if (connection && !strcasecmp(connection, "close")) {
-		close_connection = -1;
+	res = fread(buf, 1, content_length, ser->f);
+	if (res < content_length) {
+		/* Error, distinguishable by ferror() or feof(), but neither
+		 * is good. */
+		goto done;
 	}
-	return close_connection;
-}
+	buf[content_length] = '\0';
 
-void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
-{
-	struct http_worker_private_data *request = ser->private_data;
+	while ((val = strsep(&buf, "&"))) {
+		var = strsep(&val, "=");
+		if (val) {
+			ast_uri_decode(val, ast_uri_http_legacy);
+		} else  {
+			val = "";
+		}
+		ast_uri_decode(var, ast_uri_http_legacy);
+		if ((v = ast_variable_new(var, val, ""))) {
+			if (post_vars) {
+				prev->next = v;
+			} else {
+				post_vars = v;
+			}
+			prev = v;
+		}
+	}
 
-	ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
+done:
+	ast_free(buf);
+	return post_vars;
 }
 
-/*!
- * \internal
- * \brief Initialize the request tracking information in case of early failure.
- * \since 12.4.0
- *
- * \param request Request tracking information.
- *
- * \return Nothing
- */
-static void http_request_tracking_init(struct http_worker_private_data *request)
+static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
+	enum ast_http_method method, struct ast_variable *headers)
 {
-	ast_set_flags_to(&request->flags,
-		HTTP_FLAG_HAS_BODY | HTTP_FLAG_BODY_READ | HTTP_FLAG_CLOSE_ON_COMPLETION,
-		/* Assume close in case request fails early */
-		HTTP_FLAG_CLOSE_ON_COMPLETION);
-}
+	char *c;
+	int res = -1;
+	char *params = uri;
+	struct ast_http_uri *urih = NULL;
+	int l;
+	struct ast_variable *get_vars = NULL, *v, *prev = NULL;
+	struct http_uri_redirect *redirect;
 
-/*!
- * \internal
- * \brief Setup the HTTP request tracking information.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- * \param headers List of HTTP headers.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int http_request_tracking_setup(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
-{
-	struct http_worker_private_data *request = ser->private_data;
-	const char *transfer_encoding;
+	ast_debug(2, "HTTP Request URI is %s \n", uri);
 
-	ast_set_flags_to(&request->flags,
-		HTTP_FLAG_HAS_BODY | HTTP_FLAG_BODY_READ | HTTP_FLAG_CLOSE_ON_COMPLETION,
-		http_check_connection_close(headers) ? HTTP_FLAG_CLOSE_ON_COMPLETION : 0);
+	strsep(&params, "?");
+	/* Extract arguments from the request and store them in variables. */
+	if (params) {
+		char *var, *val;
 
-	transfer_encoding = get_transfer_encoding(headers);
-	if (transfer_encoding && !strcasecmp(transfer_encoding, "chunked")) {
-		request->body_length = -1;
-		ast_set_flag(&request->flags, HTTP_FLAG_HAS_BODY);
-		return 0;
+		while ((val = strsep(&params, "&"))) {
+			var = strsep(&val, "=");
+			if (val) {
+				ast_uri_decode(val, ast_uri_http_legacy);
+			} else  {
+				val = "";
+			}
+			ast_uri_decode(var, ast_uri_http_legacy);
+			if ((v = ast_variable_new(var, val, ""))) {
+				if (get_vars) {
+					prev->next = v;
+				} else {
+					get_vars = v;
+				}
+				prev = v;
+			}
+		}
 	}
+	ast_uri_decode(uri, ast_uri_http_legacy);
 
-	request->body_length = get_content_length(headers);
-	if (0 < request->body_length) {
-		ast_set_flag(&request->flags, HTTP_FLAG_HAS_BODY);
-	} else if (request->body_length < 0) {
-		/* Invalid Content-Length */
-		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-		ast_http_error(ser, 400, "Bad Request", "Invalid Content-Length in request!");
-		return -1;
-	}
-	return 0;
-}
+	AST_RWLIST_RDLOCK(&uri_redirects);
+	AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
+		if (!strcasecmp(uri, redirect->target)) {
+			struct ast_str *http_header = ast_str_create(128);
+			ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
+			ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
 
-void ast_http_body_read_status(struct ast_tcptls_session_instance *ser, int read_success)
-{
-	struct http_worker_private_data *request;
+			break;
+		}
+	}
+	AST_RWLIST_UNLOCK(&uri_redirects);
+	if (redirect) {
+		goto cleanup;
+	}
 
-	request = ser->private_data;
-	if (!ast_test_flag(&request->flags, HTTP_FLAG_HAS_BODY)
-		|| ast_test_flag(&request->flags, HTTP_FLAG_BODY_READ)) {
-		/* No body to read. */
-		return;
+	/* We want requests to start with the (optional) prefix and '/' */
+	l = strlen(prefix);
+	if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
+		uri += l + 1;
+		/* scan registered uris to see if we match one. */
+		AST_RWLIST_RDLOCK(&uris);
+		AST_RWLIST_TRAVERSE(&uris, urih, entry) {
+			ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
+			l = strlen(urih->uri);
+			c = uri + l;	/* candidate */
+			if (strncasecmp(urih->uri, uri, l) /* no match */
+			    || (*c && *c != '/')) { /* substring */
+				continue;
+			}
+			if (*c == '/') {
+				c++;
+			}
+			if (!*c || urih->has_subtree) {
+				uri = c;
+				break;
+			}
+		}
+		AST_RWLIST_UNLOCK(&uris);
 	}
-	ast_set_flag(&request->flags, HTTP_FLAG_BODY_READ);
-	if (!read_success) {
-		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
+	if (urih) {
+		res = urih->callback(ser, urih, uri, method, get_vars, headers);
+	} else {
+		ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
 	}
+
+cleanup:
+	ast_variables_destroy(get_vars);
+	return res;
 }
 
+#ifdef DO_SSL
+#if defined(HAVE_FUNOPEN)
+#define HOOK_T int
+#define LEN_T int
+#else
+#define HOOK_T ssize_t
+#define LEN_T size_t
+#endif
+
 /*!
- * \internal
- * \brief Read the next length bytes from the HTTP body.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- * \param buf Where to put the contents reading.
- * \param length How much contents to read.
- * \param what_getting Name of the contents reading.
- *
- * \retval 0 on success.
- * \retval -1 on error.
+ * replacement read/write functions for SSL support.
+ * We use wrappers rather than SSL_read/SSL_write directly so
+ * we can put in some debugging.
  */
-static int http_body_read_contents(struct ast_tcptls_session_instance *ser, char *buf, int length, const char *what_getting)
+/*static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
 {
-	int res;
+	int i = SSL_read(cookie, buf, len-1);
+#if 0
+	if (i >= 0)
+		buf[i] = '\0';
+	ast_verbose("ssl read size %d returns %d <%s>\n", (int)len, i, buf);
+#endif
+	return i;
+}
 
-	/* Stay in fread until get all the expected data or timeout. */
-	res = fread(buf, length, 1, ser->f);
-	if (res < 1) {
-		ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d)\n",
-			what_getting, length);
-		return -1;
-	}
-	return 0;
+static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
+{
+#if 0
+	char *s = ast_alloca(len+1);
+	strncpy(s, buf, len);
+	s[len] = '\0';
+	ast_verbose("ssl write size %d <%s>\n", (int)len, s);
+#endif
+	return SSL_write(cookie, buf, len);
 }
 
-/*!
- * \internal
- * \brief Read and discard the next length bytes from the HTTP body.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- * \param length How much contents to discard
- * \param what_getting Name of the contents discarding.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int http_body_discard_contents(struct ast_tcptls_session_instance *ser, int length, const char *what_getting)
+static int ssl_close(void *cookie)
 {
-	int res;
-	char buf[MAX_HTTP_LINE_LENGTH];/* Discard buffer */
-
-	/* Stay in fread until get all the expected data or timeout. */
-	while (sizeof(buf) < length) {
-		res = fread(buf, sizeof(buf), 1, ser->f);
-		if (res < 1) {
-			ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %zu of remaining %d)\n",
-				what_getting, sizeof(buf), length);
-			return -1;
-		}
-		length -= sizeof(buf);
-	}
-	res = fread(buf, length, 1, ser->f);
-	if (res < 1) {
-		ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d of remaining %d)\n",
-			what_getting, length, length);
-		return -1;
-	}
+	close(SSL_get_fd(cookie));
+	SSL_shutdown(cookie);
+	SSL_free(cookie);
 	return 0;
-}
+}*/
+#endif	/* DO_SSL */
 
-/*!
- * \internal
- * \brief decode chunked mode hexadecimal value
- *
- * \param s string to decode
- * \param len length of string
- *
- * \retval length on success.
- * \retval -1 on error.
- */
-static int chunked_atoh(const char *s, int len)
+static struct ast_variable *parse_cookies(const char *cookies)
 {
-	int value = 0;
-	char c;
+	char *parse = ast_strdupa(cookies);
+	char *cur;
+	struct ast_variable *vars = NULL, *var;
 
-	if (*s < '0') {
-		/* zero value must be 0\n not just \n */
-		return -1;
-	}
+	while ((cur = strsep(&parse, ";"))) {
+		char *name, *val;
 
-	while (len--) {
-		c = *s++;
-		if (c == '\x0D') {
-			return value;
-		}
-		if (c == ';') {
-			/* We have a chunk-extension that we don't care about. */
-			while (len--) {
-				if (*s++ == '\x0D') {
-					return value;
-				}
-			}
-			break;
-		}
-		value <<= 4;
-		if (c >= '0' && c <= '9') {
-			value += c - '0';
-			continue;
-		}
-		if (c >= 'a' && c <= 'f') {
-			value += 10 + c - 'a';
-			continue;
-		}
-		if (c >= 'A' && c <= 'F') {
-			value += 10 + c - 'A';
-			continue;
-		}
-		/* invalid character */
-		return -1;
-	}
-	/* end of string */
-	return -1;
-}
-
-/*!
- * \internal
- * \brief Read and convert the chunked body header length.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \retval length Size of chunk to expect.
- * \retval -1 on error.
- */
-static int http_body_get_chunk_length(struct ast_tcptls_session_instance *ser)
-{
-	int length;
-	char header_line[MAX_HTTP_LINE_LENGTH];
-
-	/* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */
-	if (!fgets(header_line, sizeof(header_line), ser->f)) {
-		ast_log(LOG_WARNING, "Short HTTP read of chunked header\n");
-		return -1;
-	}
-	length = chunked_atoh(header_line, strlen(header_line));
-	if (length < 0) {
-		ast_log(LOG_WARNING, "Invalid HTTP chunk size\n");
-		return -1;
-	}
-	return length;
-}
-
-/*!
- * \internal
- * \brief Read and check the chunk contents line termination.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int http_body_check_chunk_sync(struct ast_tcptls_session_instance *ser)
-{
-	int res;
-	char chunk_sync[2];
-
-	/* Stay in fread until get the expected CRLF or timeout. */
-	res = fread(chunk_sync, sizeof(chunk_sync), 1, ser->f);
-	if (res < 1) {
-		ast_log(LOG_WARNING, "Short HTTP chunk sync read (Wanted %zu)\n",
-			sizeof(chunk_sync));
-		return -1;
-	}
-	if (chunk_sync[0] != 0x0D || chunk_sync[1] != 0x0A) {
-		ast_log(LOG_WARNING, "HTTP chunk sync bytes wrong (0x%02X, 0x%02X)\n",
-			(unsigned) chunk_sync[0], (unsigned) chunk_sync[1]);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Read and discard any chunked trailer entity-header lines.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int http_body_discard_chunk_trailer_headers(struct ast_tcptls_session_instance *ser)
-{
-	char header_line[MAX_HTTP_LINE_LENGTH];
-
-	for (;;) {
-		if (!fgets(header_line, sizeof(header_line), ser->f)) {
-			ast_log(LOG_WARNING, "Short HTTP read of chunked trailer header\n");
-			return -1;
-		}
-
-		/* Trim trailing whitespace */
-		ast_trim_blanks(header_line);
-		if (ast_strlen_zero(header_line)) {
-			/* A blank line ends the chunked-body */
-			break;
-		}
-	}
-	return 0;
-}
-
-int ast_http_body_discard(struct ast_tcptls_session_instance *ser)
-{
-	struct http_worker_private_data *request;
-
-	request = ser->private_data;
-	if (!ast_test_flag(&request->flags, HTTP_FLAG_HAS_BODY)
-		|| ast_test_flag(&request->flags, HTTP_FLAG_BODY_READ)) {
-		/* No body to read or it has already been read. */
-		return 0;
-	}
-	ast_set_flag(&request->flags, HTTP_FLAG_BODY_READ);
-
-	ast_debug(1, "HTTP discarding unused request body\n");
-
-	ast_assert(request->body_length != 0);
-	if (0 < request->body_length) {
-		if (http_body_discard_contents(ser, request->body_length, "body")) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-		return 0;
-	}
-
-	/* parse chunked-body */
-	for (;;) {
-		int length;
-
-		length = http_body_get_chunk_length(ser);
-		if (length < 0) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-		if (length == 0) {
-			/* parsed last-chunk */
-			break;
-		}
-
-		if (http_body_discard_contents(ser, length, "chunk-data")
-			|| http_body_check_chunk_sync(ser)) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return -1;
-		}
-	}
-
-	/* Read and discard any trailer entity-header lines. */
-	if (http_body_discard_chunk_trailer_headers(ser)) {
-		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-		return -1;
-	}
-	return 0;
-}
-
-/*!
- * \brief Returns the contents (body) of the HTTP request
- *
- * \param return_length ptr to int that returns content length
- * \param ser HTTP TCP/TLS session object
- * \param headers List of HTTP headers
- * \return ptr to content (zero terminated) or NULL on failure
- * \note Since returned ptr is malloc'd, it should be free'd by caller
- */
-static char *ast_http_get_contents(int *return_length,
-	struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
-{
-	struct http_worker_private_data *request;
-	int content_length;
-	int bufsize;
-	char *buf;
-
-	request = ser->private_data;
-	if (!ast_test_flag(&request->flags, HTTP_FLAG_HAS_BODY)) {
-		/* no content - not an error */
-		return NULL;
-	}
-	if (ast_test_flag(&request->flags, HTTP_FLAG_BODY_READ)) {
-		/* Already read the body.  Cannot read again.  Assume no content. */
-		ast_assert(0);
-		return NULL;
-	}
-	ast_set_flag(&request->flags, HTTP_FLAG_BODY_READ);
-
-	ast_debug(2, "HTTP consuming request body\n");
-
-	ast_assert(request->body_length != 0);
-	if (0 < request->body_length) {
-		/* handle regular non-chunked content */
-		content_length = request->body_length;
-		if (content_length > MAX_CONTENT_LENGTH) {
-			ast_log(LOG_WARNING, "Excessively long HTTP content. (%d > %d)\n",
-				content_length, MAX_CONTENT_LENGTH);
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EFBIG;
-			return NULL;
-		}
-		buf = ast_malloc(content_length + 1);
-		if (!buf) {
-			/* Malloc sets ENOMEM */
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			return NULL;
-		}
-
-		if (http_body_read_contents(ser, buf, content_length, "body")) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
-
-		buf[content_length] = 0;
-		*return_length = content_length;
-		return buf;
-	}
-
-	/* pre-allocate buffer */
-	bufsize = 250;
-	buf = ast_malloc(bufsize);
-	if (!buf) {
-		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-		return NULL;
-	}
-
-	/* parse chunked-body */
-	content_length = 0;
-	for (;;) {
-		int chunk_length;
-
-		chunk_length = http_body_get_chunk_length(ser);
-		if (chunk_length < 0) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
-		if (chunk_length == 0) {
-			/* parsed last-chunk */
-			break;
-		}
-		if (content_length + chunk_length > MAX_CONTENT_LENGTH) {
-			ast_log(LOG_WARNING,
-				"Excessively long HTTP accumulated chunked body. (%d + %d > %d)\n",
-				content_length, chunk_length, MAX_CONTENT_LENGTH);
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EFBIG;
-			ast_free(buf);
-			return NULL;
-		}
-
-		/* insure buffer is large enough +1 */
-		if (content_length + chunk_length >= bufsize) {
-			char *new_buf;
-
-			/* Increase bufsize until it can handle the expected data. */
-			do {
-				bufsize *= 2;
-			} while (content_length + chunk_length >= bufsize);
-
-			new_buf = ast_realloc(buf, bufsize);
-			if (!new_buf) {
-				ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-				ast_free(buf);
-				return NULL;
-			}
-			buf = new_buf;
-		}
-
-		if (http_body_read_contents(ser, buf + content_length, chunk_length, "chunk-data")
-			|| http_body_check_chunk_sync(ser)) {
-			ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-			errno = EIO;
-			ast_free(buf);
-			return NULL;
-		}
-		content_length += chunk_length;
-	}
-
-	/*
-	 * Read and discard any trailer entity-header lines
-	 * which we don't care about.
-	 *
-	 * XXX In the future we may need to add the trailer headers
-	 * to the passed in headers list rather than discarding them.
-	 */
-	if (http_body_discard_chunk_trailer_headers(ser)) {
-		ast_set_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION);
-		errno = EIO;
-		ast_free(buf);
-		return NULL;
-	}
-
-	buf[content_length] = 0;
-	*return_length = content_length;
-	return buf;
-}
-
-struct ast_json *ast_http_get_json(
-	struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
-{
-	int content_length = 0;
-	struct ast_json *body;
-	RAII_VAR(char *, buf, NULL, ast_free);
-	RAII_VAR(char *, type, get_content_type(headers), ast_free);
-
-	/* Use errno to distinguish errors from no body */
-	errno = 0;
-
-	if (ast_strlen_zero(type) || strcasecmp(type, "application/json")) {
-		/* Content type is not JSON.  Don't read the body. */
-		return NULL;
-	}
-
-	buf = ast_http_get_contents(&content_length, ser, headers);
-	if (!buf || !content_length) {
-		/*
-		 * errno already set
-		 * or it is not an error to have zero content
-		 */
-		return NULL;
-	}
-
-	body = ast_json_load_buf(buf, content_length, NULL);
-	if (!body) {
-		/* Failed to parse JSON; treat as an I/O error */
-		errno = EIO;
-		return NULL;
-	}
-
-	return body;
-}
-
-/*
- * get post variables from client Request Entity-Body, if content type is
- * application/x-www-form-urlencoded
- */
-struct ast_variable *ast_http_get_post_vars(
-	struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
-{
-	int content_length = 0;
-	struct ast_variable *v, *post_vars=NULL, *prev = NULL;
-	char *var, *val;
-	RAII_VAR(char *, buf, NULL, ast_free);
-	RAII_VAR(char *, type, get_content_type(headers), ast_free);
-
-	/* Use errno to distinguish errors from no params */
-	errno = 0;
-
-	if (ast_strlen_zero(type) ||
-	    strcasecmp(type, "application/x-www-form-urlencoded")) {
-		/* Content type is not form data.  Don't read the body. */
-		return NULL;
-	}
-
-	buf = ast_http_get_contents(&content_length, ser, headers);
-	if (!buf || !content_length) {
-		/*
-		 * errno already set
-		 * or it is not an error to have zero content
-		 */
-		return NULL;
-	}
-
-	while ((val = strsep(&buf, "&"))) {
-		var = strsep(&val, "=");
-		if (val) {
-			ast_uri_decode(val, ast_uri_http_legacy);
-		} else  {
-			val = "";
-		}
-		ast_uri_decode(var, ast_uri_http_legacy);
-		if ((v = ast_variable_new(var, val, ""))) {
-			if (post_vars) {
-				prev->next = v;
-			} else {
-				post_vars = v;
-			}
-			prev = v;
-		}
-	}
-
-	return post_vars;
-}
-
-static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
-	enum ast_http_method method, struct ast_variable *headers)
-{
-	char *c;
-	int res = 0;
-	char *params = uri;
-	struct ast_http_uri *urih = NULL;
-	int l;
-	struct ast_variable *get_vars = NULL, *v, *prev = NULL;
-	struct http_uri_redirect *redirect;
-
-	ast_debug(2, "HTTP Request URI is %s \n", uri);
-
-	strsep(&params, "?");
-	/* Extract arguments from the request and store them in variables. */
-	if (params) {
-		char *var, *val;
-
-		while ((val = strsep(&params, "&"))) {
-			var = strsep(&val, "=");
-			if (val) {
-				ast_uri_decode(val, ast_uri_http_legacy);
-			} else  {
-				val = "";
-			}
-			ast_uri_decode(var, ast_uri_http_legacy);
-			if ((v = ast_variable_new(var, val, ""))) {
-				if (get_vars) {
-					prev->next = v;
-				} else {
-					get_vars = v;
-				}
-				prev = v;
-			}
-		}
-	}
-
-	AST_RWLIST_RDLOCK(&uri_redirects);
-	AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
-		if (!strcasecmp(uri, redirect->target)) {
-			struct ast_str *http_header = ast_str_create(128);
-
-			if (!http_header) {
-				ast_http_request_close_on_completion(ser);
-				ast_http_error(ser, 500, "Server Error", "Out of memory");
-				break;
-			}
-			ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
-			ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&uri_redirects);
-	if (redirect) {
-		goto cleanup;
-	}
-
-	/* We want requests to start with the (optional) prefix and '/' */
-	l = strlen(prefix);
-	if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
-		uri += l + 1;
-		/* scan registered uris to see if we match one. */
-		AST_RWLIST_RDLOCK(&uris);
-		AST_RWLIST_TRAVERSE(&uris, urih, entry) {
-			l = strlen(urih->uri);
-			c = uri + l;	/* candidate */
-			ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
-			if (strncasecmp(urih->uri, uri, l) /* no match */
-			    || (*c && *c != '/')) { /* substring */
-				continue;
-			}
-			if (*c == '/') {
-				c++;
-			}
-			if (!*c || urih->has_subtree) {
-				uri = c;
-				break;
-			}
-		}
-		AST_RWLIST_UNLOCK(&uris);
-	}
-	if (urih) {
-		ast_debug(1, "Match made with [%s]\n", urih->uri);
-		if (!urih->no_decode_uri) {
-			ast_uri_decode(uri, ast_uri_http_legacy);
-		}
-		res = urih->callback(ser, urih, uri, method, get_vars, headers);
-	} else {
-		ast_debug(1, "Requested URI [%s] has no handler\n", uri);
-		ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
-	}
-
-cleanup:
-	ast_variables_destroy(get_vars);
-	return res;
-}
-
-static struct ast_variable *parse_cookies(const char *cookies)
-{
-	char *parse = ast_strdupa(cookies);
-	char *cur;
-	struct ast_variable *vars = NULL, *var;
-
-	while ((cur = strsep(&parse, ";"))) {
-		char *name, *val;
-
-		name = val = cur;
-		strsep(&val, "=");
-
-		if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
+		name = val = cur;
+		strsep(&val, "=");
+
+		if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
 			continue;
 		}
 
@@ -1493,232 +853,94 @@ struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
 	return cookies;
 }
 
-static struct ast_http_auth *auth_create(const char *userid, const char *password)
-{
-	struct ast_http_auth *auth;
-	size_t userid_len;
-	size_t password_len;
-
-	if (!userid || !password) {
-		ast_log(LOG_ERROR, "Invalid userid/password\n");
-		return NULL;
-	}
-
-	userid_len = strlen(userid) + 1;
-	password_len = strlen(password) + 1;
-
-	/* Allocate enough room to store everything in one memory block */
-	auth = ao2_alloc(sizeof(*auth) + userid_len + password_len, NULL);
-	if (!auth) {
-		return NULL;
-	}
-
-	/* Put the userid right after the struct */
-	auth->userid = (char *)(auth + 1);
-	strcpy(auth->userid, userid);
-
-	/* Put the password right after the userid */
-	auth->password = auth->userid + userid_len;
-	strcpy(auth->password, password);
-
-	return auth;
-}
-
-#define BASIC_PREFIX "Basic "
-#define BASIC_LEN 6 /*!< strlen(BASIC_PREFIX) */
-
-struct ast_http_auth *ast_http_get_auth(struct ast_variable *headers)
-{
-	struct ast_variable *v;
-
-	for (v = headers; v; v = v->next) {
-		const char *base64;
-		char decoded[256] = {};
-		char *username;
-		char *password;
-#ifdef AST_DEVMODE
-		int cnt;
-#endif /* AST_DEVMODE */
-
-		if (strcasecmp("Authorization", v->name) != 0) {
-			continue;
-		}
-
-		if (!ast_begins_with(v->value, BASIC_PREFIX)) {
-			ast_log(LOG_DEBUG,
-				"Unsupported Authorization scheme\n");
-			continue;
-		}
-
-		/* Basic auth header parsing. RFC 2617, section 2.
-		 *   credentials = "Basic" basic-credentials
-		 *   basic-credentials = base64-user-pass
-		 *   base64-user-pass  = <base64 encoding of user-pass,
-		 *                        except not limited to 76 char/line>
-		 *   user-pass   = userid ":" password
-		 */
-
-		base64 = v->value + BASIC_LEN;
-
-		/* This will truncate "userid:password" lines to
-		 * sizeof(decoded). The array is long enough that this shouldn't
-		 * be a problem */
-#ifdef AST_DEVMODE
-		cnt =
-#endif /* AST_DEVMODE */
-		ast_base64decode((unsigned char*)decoded, base64,
-			sizeof(decoded) - 1);
-		ast_assert(cnt < sizeof(decoded));
-
-		/* Split the string at the colon */
-		password = decoded;
-		username = strsep(&password, ":");
-		if (!password) {
-			ast_log(LOG_WARNING, "Invalid Authorization header\n");
-			return NULL;
-		}
-
-		return auth_create(username, password);
-	}
-
-	return NULL;
-}
-
-int ast_http_response_status_line(const char *buf, const char *version, int code)
-{
-	int status_code;
-	size_t size = strlen(version);
-
-	if (strncmp(buf, version, size) || buf[size] != ' ') {
-		ast_log(LOG_ERROR, "HTTP version not supported - "
-			"expected %s\n", version);
-		return -1;
-	}
-
-	/* skip to status code (version + space) */
-	buf += size + 1;
-
-	if (sscanf(buf, "%d", &status_code) != 1) {
-		ast_log(LOG_ERROR, "Could not read HTTP status code - "
-			"%s\n", buf);
-		return -1;
-	}
-
-	return status_code;
-}
+/*! Limit the number of request headers in case the sender is being ridiculous. */
+#define MAX_HTTP_REQUEST_HEADERS	100
 
-static void remove_excess_lws(char *s)
+static void *httpd_helper_thread(void *data)
 {
-	char *p, *res = s;
-	char *buf = ast_malloc(strlen(s) + 1);
-	char *buf_end;
+	char buf[4096];
+	char header_line[4096];
+	struct ast_tcptls_session_instance *ser = data;
+	struct ast_variable *headers = NULL;
+	struct ast_variable *tail = headers;
+	char *uri, *method;
+	enum ast_http_method http_method = AST_HTTP_UNKNOWN;
+	int remaining_headers;
+	int flags;
+	struct protoent *p;
 
-	if (!buf) {
-		return;
+	if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
+		goto done;
 	}
 
-	buf_end = buf;
-
-	while (*s && *(s = ast_skip_blanks(s))) {
-		p = s;
-		s = ast_skip_nonblanks(s);
-
-		if (buf_end != buf) {
-			*buf_end++ = ' ';
+	/* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
+	 * This is necessary to prevent delays (caused by buffering) as we
+	 * write to the socket in bits and pieces. */
+	p = getprotobyname("tcp");
+	if (p) {
+		int arg = 1;
+		if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
+			ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno));
+			ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
 		}
-
-		memcpy(buf_end, p, s - p);
-		buf_end += s - p;
-	}
-	*buf_end = '\0';
-	/* safe since buf will always be less than or equal to res */
-	strcpy(res, buf);
-	ast_free(buf);
-}
-
-int ast_http_header_parse(char *buf, char **name, char **value)
-{
-	ast_trim_blanks(buf);
-	if (ast_strlen_zero(buf)) {
-		return -1;
+	} else {
+		ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n");
+		ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
 	}
 
-	*value = buf;
-	*name = strsep(value, ":");
-	if (!*value) {
-		return 1;
-	}
+	/* make sure socket is non-blocking */
+	flags = fcntl(ser->fd, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(ser->fd, F_SETFL, flags);
 
-	*value = ast_skip_blanks(*value);
-	if (ast_strlen_zero(*value) || ast_strlen_zero(*name)) {
-		return 1;
-	}
+	/* We can let the stream wait for data to arrive. */
+	ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1);
 
-	remove_excess_lws(*value);
-	return 0;
-}
+	ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity);
 
-int ast_http_header_match(const char *name, const char *expected_name,
-			  const char *value, const char *expected_value)
-{
-	if (strcasecmp(name, expected_name)) {
-		/* no value to validate if names don't match */
-		return 0;
+	if (!fgets(buf, sizeof(buf), ser->f) || feof(ser->f)) {
+		goto done;
 	}
 
-	if (strcasecmp(value, expected_value)) {
-		ast_log(LOG_ERROR, "Invalid header value - expected %s "
-			"received %s", value, expected_value);
-		return -1;
+	/* Get method */
+	method = ast_skip_blanks(buf);
+	uri = ast_skip_nonblanks(method);
+	if (*uri) {
+		*uri++ = '\0';
 	}
-	return 1;
-}
 
-int ast_http_header_match_in(const char *name, const char *expected_name,
-			     const char *value, const char *expected_value)
-{
-	if (strcasecmp(name, expected_name)) {
-		/* no value to validate if names don't match */
-		return 0;
+	if (!strcasecmp(method,"GET")) {
+		http_method = AST_HTTP_GET;
+	} else if (!strcasecmp(method,"POST")) {
+		http_method = AST_HTTP_POST;
+	} else if (!strcasecmp(method,"HEAD")) {
+		http_method = AST_HTTP_HEAD;
+	} else if (!strcasecmp(method,"PUT")) {
+		http_method = AST_HTTP_PUT;
 	}
 
-	if (!strcasestr(expected_value, value)) {
-		ast_log(LOG_ERROR, "Header '%s' - could not locate '%s' "
-			"in '%s'\n", name, value, expected_value);
-		return -1;
-
-	}
-	return 1;
-}
+	uri = ast_skip_blanks(uri);	/* Skip white space */
 
-/*! Limit the number of request headers in case the sender is being ridiculous. */
-#define MAX_HTTP_REQUEST_HEADERS	100
+	if (*uri) {			/* terminate at the first blank */
+		char *c = ast_skip_nonblanks(uri);
 
-/*!
- * \internal
- * \brief Read the request headers.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- * \param headers Where to put the request headers list pointer.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int http_request_headers_get(struct ast_tcptls_session_instance *ser, struct ast_variable **headers)
-{
-	struct ast_variable *tail = *headers;
-	int remaining_headers;
-	char header_line[MAX_HTTP_LINE_LENGTH];
+		if (*c) {
+			*c = '\0';
+		}
+	} else {
+		ast_http_error(ser, 400, "Bad Request", "Invalid Request");
+		goto done;
+	}
 
+	/* process "Request Headers" lines */
 	remaining_headers = MAX_HTTP_REQUEST_HEADERS;
 	for (;;) {
 		char *name;
 		char *value;
 
-		if (!fgets(header_line, sizeof(header_line), ser->f)) {
+		if (!fgets(header_line, sizeof(header_line), ser->f) || feof(ser->f)) {
 			ast_http_error(ser, 400, "Bad Request", "Timeout");
-			return -1;
+			goto done;
 		}
 
 		/* Trim trailing characters */
@@ -1744,11 +966,11 @@ static int http_request_headers_get(struct ast_tcptls_session_instance *ser, str
 		if (!remaining_headers--) {
 			/* Too many headers. */
 			ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
-			return -1;
+			goto done;
 		}
-		if (!*headers) {
-			*headers = ast_variable_new(name, value, __FILE__);
-			tail = *headers;
+		if (!headers) {
+			headers = ast_variable_new(name, value, __FILE__);
+			tail = headers;
 		} else {
 			tail->next = ast_variable_new(name, value, __FILE__);
 			tail = tail->next;
@@ -1758,209 +980,27 @@ static int http_request_headers_get(struct ast_tcptls_session_instance *ser, str
 			 * Variable allocation failure.
 			 * Try to make some room.
 			 */
-			ast_variables_destroy(*headers);
-			*headers = NULL;
+			ast_variables_destroy(headers);
+			headers = NULL;
 
 			ast_http_error(ser, 500, "Server Error", "Out of memory");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Process a HTTP request.
- * \since 12.4.0
- *
- * \param ser HTTP TCP/TLS session object.
- *
- * \retval 0 Continue and process the next HTTP request.
- * \retval -1 Fatal HTTP connection error.  Force the HTTP connection closed.
- */
-static int httpd_process_request(struct ast_tcptls_session_instance *ser)
-{
-	RAII_VAR(struct ast_variable *, headers, NULL, ast_variables_destroy);
-	char *uri;
-	char *method;
-	const char *transfer_encoding;
-	struct http_worker_private_data *request;
-	enum ast_http_method http_method = AST_HTTP_UNKNOWN;
-	int res;
-	char request_line[MAX_HTTP_LINE_LENGTH];
-
-	if (!fgets(request_line, sizeof(request_line), ser->f)) {
-		return -1;
-	}
-
-	/* Re-initialize the request body tracking data. */
-	request = ser->private_data;
-	http_request_tracking_init(request);
-
-	/* Get method */
-	method = ast_skip_blanks(request_line);
-	uri = ast_skip_nonblanks(method);
-	if (*uri) {
-		*uri++ = '\0';
-	}
-
-	if (!strcasecmp(method,"GET")) {
-		http_method = AST_HTTP_GET;
-	} else if (!strcasecmp(method,"POST")) {
-		http_method = AST_HTTP_POST;
-	} else if (!strcasecmp(method,"HEAD")) {
-		http_method = AST_HTTP_HEAD;
-	} else if (!strcasecmp(method,"PUT")) {
-		http_method = AST_HTTP_PUT;
-	} else if (!strcasecmp(method,"DELETE")) {
-		http_method = AST_HTTP_DELETE;
-	} else if (!strcasecmp(method,"OPTIONS")) {
-		http_method = AST_HTTP_OPTIONS;
-	}
-
-	uri = ast_skip_blanks(uri);	/* Skip white space */
-	if (*uri) {			/* terminate at the first blank */
-		char *c = ast_skip_nonblanks(uri);
-
-		if (*c) {
-			*c = '\0';
-		}
-	} else {
-		ast_http_error(ser, 400, "Bad Request", "Invalid Request");
-		return -1;
-	}
-
-	/* process "Request Headers" lines */
-	if (http_request_headers_get(ser, &headers)) {
-		return -1;
-	}
-
-	transfer_encoding = get_transfer_encoding(headers);
-	/* Transfer encoding defaults to identity */
-	if (!transfer_encoding) {
-		transfer_encoding = "identity";
-	}
-
-	/*
-	 * RFC 2616, section 3.6, we should respond with a 501 for any transfer-
-	 * codings we don't understand.
-	 */
-	if (strcasecmp(transfer_encoding, "identity") != 0 &&
-		strcasecmp(transfer_encoding, "chunked") != 0) {
-		/* Transfer encodings not supported */
-		ast_http_error(ser, 501, "Unimplemented", "Unsupported Transfer-Encoding.");
-		return -1;
-	}
-
-	if (http_request_tracking_setup(ser, headers)
-		|| handle_uri(ser, uri, http_method, headers)
-		|| ast_test_flag(&request->flags, HTTP_FLAG_CLOSE_ON_COMPLETION)) {
-		res = -1;
-	} else {
-		res = 0;
-	}
-	return res;
-}
-
-static void *httpd_helper_thread(void *data)
-{
-	struct ast_tcptls_session_instance *ser = data;
-	struct protoent *p;
-	int flags;
-	int timeout;
-
-	if (!ser || !ser->f) {
-		ao2_cleanup(ser);
-		return NULL;
-	}
-
-	if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
-		ast_log(LOG_WARNING, "HTTP session count exceeded %d sessions.\n",
-			session_limit);
-		goto done;
-	}
-	ast_debug(1, "HTTP opening session.  Top level\n");
-
-	/*
-	 * Here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
-	 * This is necessary to prevent delays (caused by buffering) as we
-	 * write to the socket in bits and pieces.
-	 */
-	p = getprotobyname("tcp");
-	if (p) {
-		int arg = 1;
-
-		if (setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *) &arg, sizeof(arg) ) < 0) {
-			ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno));
-			ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
+			goto done;
 		}
-	} else {
-		ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n");
-		ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
-	}
-
-	/* make sure socket is non-blocking */
-	flags = fcntl(ser->fd, F_GETFL);
-	flags |= O_NONBLOCK;
-	fcntl(ser->fd, F_SETFL, flags);
-
-	/* Setup HTTP worker private data to keep track of request body reading. */
-	ao2_cleanup(ser->private_data);
-	ser->private_data = ao2_alloc_options(sizeof(struct http_worker_private_data), NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!ser->private_data) {
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
-		goto done;
-	}
-	http_request_tracking_init(ser->private_data);
-
-	/* Determine initial HTTP request wait timeout. */
-	timeout = session_keep_alive;
-	if (timeout <= 0) {
-		/* Persistent connections not enabled. */
-		timeout = session_inactivity;
 	}
-	if (timeout < MIN_INITIAL_REQUEST_TIMEOUT) {
-		timeout = MIN_INITIAL_REQUEST_TIMEOUT;
-	}
-
-	/* We can let the stream wait for data to arrive. */
-	ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1);
-
-	for (;;) {
-		int ch;
-
-		/* Wait for next potential HTTP request message. */
-		ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, timeout);
-		ch = fgetc(ser->f);
-		if (ch == EOF || ungetc(ch, ser->f) == EOF) {
-			/* Between request idle timeout */
-			ast_debug(1, "HTTP idle timeout or peer closed connection.\n");
-			break;
-		}
 
-		ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity);
-		if (httpd_process_request(ser) || !ser->f || feof(ser->f)) {
-			/* Break the connection or the connection closed */
-			break;
-		}
-
-		timeout = session_keep_alive;
-		if (timeout <= 0) {
-			/* Persistent connections not enabled. */
-			break;
-		}
-	}
+	handle_uri(ser, uri, http_method, headers);
 
 done:
 	ast_atomic_fetchadd_int(&session_count, -1);
 
+	/* clean up all the header information */
+	ast_variables_destroy(headers);
+
 	if (ser->f) {
-		ast_debug(1, "HTTP closing session.  Top level\n");
 		ast_tcptls_close_session_file(ser);
 	}
 	ao2_ref(ser, -1);
+	ser = NULL;
 	return NULL;
 }
 
@@ -2037,7 +1077,7 @@ static int __ast_http_load(int reload)
 	int http_tls_was_enabled = 0;
 
 	cfg = ast_config_load2("http.conf", "http", config_flags);
-	if (!cfg || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
 		return 0;
 	}
 
@@ -2069,72 +1109,65 @@ static int __ast_http_load(int reload)
 
 	session_limit = DEFAULT_SESSION_LIMIT;
 	session_inactivity = DEFAULT_SESSION_INACTIVITY;
-	session_keep_alive = DEFAULT_SESSION_KEEP_ALIVE;
-
-	v = ast_variable_browse(cfg, "general");
-	for (; v; v = v->next) {
-		/* read tls config options while preventing unsupported options from being set */
-		if (strcasecmp(v->name, "tlscafile")
-			&& strcasecmp(v->name, "tlscapath")
-			&& strcasecmp(v->name, "tlscadir")
-			&& strcasecmp(v->name, "tlsverifyclient")
-			&& strcasecmp(v->name, "tlsdontverifyserver")
-			&& strcasecmp(v->name, "tlsclientmethod")
-			&& strcasecmp(v->name, "sslclientmethod")
-			&& strcasecmp(v->name, "tlscipher")
-			&& strcasecmp(v->name, "sslcipher")
-			&& !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
-			continue;
-		}
 
-		if (!strcasecmp(v->name, "enabled")) {
-			enabled = ast_true(v->value);
-		} else if (!strcasecmp(v->name, "enablestatic")) {
-			newenablestatic = ast_true(v->value);
-		} else if (!strcasecmp(v->name, "bindport")) {
-			if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE | PARSE_DEFAULT,
-				&bindport, DEFAULT_PORT, 0, 65535)) {
-				ast_log(LOG_WARNING, "Invalid port %s specified. Using default port %" PRId32 "\n",
-					v->value, DEFAULT_PORT);
-			}
-		} else if (!strcasecmp(v->name, "bindaddr")) {
-			if (!(num_addrs = ast_sockaddr_resolve(&addrs, v->value, 0, AST_AF_UNSPEC))) {
-				ast_log(LOG_WARNING, "Invalid bind address %s\n", v->value);
+	if (cfg) {
+		v = ast_variable_browse(cfg, "general");
+		for (; v; v = v->next) {
+
+			/* read tls config options while preventing unsupported options from being set */
+			if (strcasecmp(v->name, "tlscafile")
+				&& strcasecmp(v->name, "tlscapath")
+				&& strcasecmp(v->name, "tlscadir")
+				&& strcasecmp(v->name, "tlsverifyclient")
+				&& strcasecmp(v->name, "tlsdontverifyserver")
+				&& strcasecmp(v->name, "tlsclientmethod")
+				&& strcasecmp(v->name, "sslclientmethod")
+				&& strcasecmp(v->name, "tlscipher")
+				&& strcasecmp(v->name, "sslcipher")
+				&& !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
+				continue;
 			}
-		} else if (!strcasecmp(v->name, "prefix")) {
-			if (!ast_strlen_zero(v->value)) {
-				newprefix[0] = '/';
-				ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
+
+			if (!strcasecmp(v->name, "enabled")) {
+				enabled = ast_true(v->value);
+			} else if (!strcasecmp(v->name, "enablestatic")) {
+				newenablestatic = ast_true(v->value);
+			} else if (!strcasecmp(v->name, "bindport")) {
+				if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE | PARSE_DEFAULT, &bindport, DEFAULT_PORT, 0, 65535)) {
+					ast_log(LOG_WARNING, "Invalid port %s specified. Using default port %"PRId32, v->value, DEFAULT_PORT);
+				}
+			} else if (!strcasecmp(v->name, "bindaddr")) {
+				if (!(num_addrs = ast_sockaddr_resolve(&addrs, v->value, 0, AST_AF_UNSPEC))) {
+					ast_log(LOG_WARNING, "Invalid bind address %s\n", v->value);
+				}
+			} else if (!strcasecmp(v->name, "prefix")) {
+				if (!ast_strlen_zero(v->value)) {
+					newprefix[0] = '/';
+					ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
+				} else {
+					newprefix[0] = '\0';
+				}
+			} else if (!strcasecmp(v->name, "redirect")) {
+				add_redirect(v->value);
+			} else if (!strcasecmp(v->name, "sessionlimit")) {
+				if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
+							&session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
+					ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
+							v->name, v->value, v->lineno);
+				}
+			} else if (!strcasecmp(v->name, "session_inactivity")) {
+				if (ast_parse_arg(v->value, PARSE_INT32 |PARSE_DEFAULT | PARSE_IN_RANGE,
+					&session_inactivity, DEFAULT_SESSION_INACTIVITY, 1, INT_MAX)) {
+					ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
+						v->name, v->value, v->lineno);
+				}
 			} else {
-				newprefix[0] = '\0';
-			}
-		} else if (!strcasecmp(v->name, "redirect")) {
-			add_redirect(v->value);
-		} else if (!strcasecmp(v->name, "sessionlimit")) {
-			if (ast_parse_arg(v->value, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE,
-				&session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
-				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
-					v->name, v->value, v->lineno);
-			}
-		} else if (!strcasecmp(v->name, "session_inactivity")) {
-			if (ast_parse_arg(v->value, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE,
-				&session_inactivity, DEFAULT_SESSION_INACTIVITY, 1, INT_MAX)) {
-				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
-					v->name, v->value, v->lineno);
+				ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
 			}
-		} else if (!strcasecmp(v->name, "session_keep_alive")) {
-			if (sscanf(v->value, "%30d", &session_keep_alive) != 1
-				|| session_keep_alive < 0) {
-				session_keep_alive = DEFAULT_SESSION_KEEP_ALIVE;
-				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
-					v->name, v->value, v->lineno);
-			}
-		} else {
-			ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
 		}
-	}
 
-	ast_config_destroy(cfg);
+		ast_config_destroy(cfg);
+	}
 
 	if (strcmp(prefix, newprefix)) {
 		ast_copy_string(prefix, newprefix, sizeof(prefix));
@@ -2279,7 +1312,7 @@ int ast_http_init(void)
 	ast_http_uri_link(&statusuri);
 	ast_http_uri_link(&staticuri);
 	ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
-	ast_register_atexit(http_shutdown);
+	ast_register_cleanup(http_shutdown);
 
 	return __ast_http_load(0);
 }
diff --git a/main/image.c b/main/image.c
index 4493452..9bd47ae 100644
--- a/main/image.c
+++ b/main/image.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <sys/stat.h>
@@ -114,7 +114,7 @@ struct ast_frame *ast_read_image(const char *filename, const char *preflang, str
 	AST_RWLIST_RDLOCK(&imagers);
 	AST_RWLIST_TRAVERSE(&imagers, i, list) {
 		/* if NULL image format, just pick the first one, otherwise match it. */
-		if (!format || (ast_format_cmp(i->format, format) == AST_FORMAT_CMP_EQUAL)) {
+		if (!format || (ast_format_cmp(&i->format, format) == AST_FORMAT_CMP_EQUAL)) {
 			char *stringp=NULL;
 			ast_copy_string(tmp, i->exts, sizeof(tmp));
 			stringp = tmp;
@@ -194,7 +194,7 @@ static char *handle_core_show_image_formats(struct ast_cli_entry *e, int cmd, st
 	ast_cli(a->fd, FORMAT, "----", "----------", "-----------", "------");
 	AST_RWLIST_RDLOCK(&imagers);
 	AST_RWLIST_TRAVERSE(&imagers, i, list) {
-		ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_format_get_name(i->format));
+		ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(&i->format));
 		count_fmt++;
 	}
 	AST_RWLIST_UNLOCK(&imagers);
@@ -214,6 +214,6 @@ static void image_shutdown(void)
 int ast_image_init(void)
 {
 	ast_cli_register_multiple(cli_image, ARRAY_LEN(cli_image));
-	ast_register_atexit(image_shutdown);
+	ast_register_cleanup(image_shutdown);
 	return 0;
 }
diff --git a/main/indications.c b/main/indications.c
index 5977826..a453fea 100644
--- a/main/indications.c
+++ b/main/indications.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
@@ -37,7 +37,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 #include "asterisk/channel.h"
 #include "asterisk/utils.h"
 #include "asterisk/cli.h"
@@ -121,7 +120,7 @@ struct playtones_state {
 	int npos;
 	int oldnpos;
 	int pos;
-	struct ast_format *origwfmt;
+	struct ast_format origwfmt;
 	struct ast_frame f;
 	unsigned char offset[AST_FRIENDLY_OFFSET];
 	short data[4000];
@@ -132,11 +131,13 @@ static void playtones_release(struct ast_channel *chan, void *params)
 	struct playtones_state *ps = params;
 
 	if (chan) {
-		ast_set_write_format(chan, ps->origwfmt);
+		ast_set_write_format(chan, &ps->origwfmt);
 	}
 
-	ao2_cleanup(ps->origwfmt);
-	ast_free(ps->items);
+	if (ps->items) {
+		ast_free(ps->items);
+		ps->items = NULL;
+	}
 
 	ast_free(ps);
 }
@@ -150,9 +151,9 @@ static void *playtones_alloc(struct ast_channel *chan, void *params)
 		return NULL;
 	}
 
-	ps->origwfmt = ao2_bump(ast_channel_writeformat(chan));
+	ast_format_copy(&ps->origwfmt, ast_channel_writeformat(chan));
 
-	if (ast_set_write_format(chan, ast_format_slin)) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan));
 		playtones_release(NULL, ps);
 		ps = NULL;
@@ -226,7 +227,7 @@ static int playtones_generator(struct ast_channel *chan, void *data, int len, in
 	}
 
 	ps->f.frametype = AST_FRAME_VOICE;
-	ps->f.subclass.format = ast_format_slin;
+	ast_format_set(&ps->f.subclass.format, AST_FORMAT_SLINEAR, 0);
 	ps->f.datalen = len;
 	ps->f.samples = samples;
 	ps->f.offset = AST_FRIENDLY_OFFSET;
@@ -359,14 +360,13 @@ int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst,
 
 		if (tone_data.midinote) {
 			/* midi notes must be between 0 and 127 */
-
-			if (tone_data.freq1 >= 0 && tone_data.freq1 <= 127) {
+			if (tone_data.freq1 <= 127) {
 				tone_data.freq1 = midi_tohz[tone_data.freq1];
 			} else {
 				tone_data.freq1 = 0;
 			}
 
-			if (tone_data.freq2 >= 0 && tone_data.freq2 <= 127) {
+			if (tone_data.freq2 <= 127) {
 				tone_data.freq2 = midi_tohz[tone_data.freq2];
 			} else {
 				tone_data.freq2 = 0;
@@ -1154,10 +1154,7 @@ int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void indications_shutdown(void)
 {
 	ast_cli_unregister_multiple(cli_indications, ARRAY_LEN(cli_indications));
@@ -1186,7 +1183,7 @@ int ast_indications_init(void)
 
 	ast_cli_register_multiple(cli_indications, ARRAY_LEN(cli_indications));
 
-	ast_register_atexit(indications_shutdown);
+	ast_register_cleanup(indications_shutdown);
 	return 0;
 }
 
diff --git a/main/io.c b/main/io.c
index 540c0b6..cd35995 100644
--- a/main/io.c
+++ b/main/io.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <termios.h>
 #include <sys/ioctl.h>
diff --git a/main/jitterbuf.c b/main/jitterbuf.c
index e8bf836..1bfe508 100644
--- a/main/jitterbuf.c
+++ b/main/jitterbuf.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 401789 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "jitterbuf.h"
 #include "asterisk/utils.h"
@@ -139,7 +139,7 @@ static int check_resync(jitterbuf *jb, long ts, long now, long ms, const enum jb
 
 	/* check for drastic change in delay */
 	if (jb->info.conf.resync_threshold != -1) {
-		if (abs(*delay - jb->info.last_delay) > threshold) {
+		if (labs(*delay - jb->info.last_delay) > threshold) {
 			jb->info.cnt_delay_discont++;
 			/* resync the jitterbuffer on 3 consecutive discontinuities,
 			 * or immediately if a control frame */
diff --git a/main/json.c b/main/json.c
deleted file mode 100644
index 24bd096..0000000
--- a/main/json.c
+++ /dev/null
@@ -1,913 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief JSON abstraction layer.
- *
- * This is a very thin wrapper around the Jansson API. For more details on it,
- * see its docs at http://www.digip.org/jansson/doc/2.4/apiref.html.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend>jansson</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420098 $")
-
-#include "asterisk/json.h"
-#include "asterisk/localtime.h"
-#include "asterisk/module.h"
-#include "asterisk/utils.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/channel.h"
-#include "asterisk/callerid.h"
-
-#include <jansson.h>
-#include <time.h>
-
-/*! \brief Magic number, for safety checks. */
-#define JSON_MAGIC 0x1541992
-
-/*! \brief Internal structure for allocated memory blocks */
-struct json_mem {
-	/*! Magic number, for safety checks */
-	uint32_t magic;
-	/*! Mutext for locking this memory block */
-	ast_mutex_t mutex;
-	/*! Linked list pointer for the free list */
-	AST_LIST_ENTRY(json_mem) list;
-	/*! Data section of the allocation; void pointer for proper alignment */
-	void *data[];
-};
-
-/*! \brief Free a \ref json_mem block. */
-static void json_mem_free(struct json_mem *mem)
-{
-	mem->magic = 0;
-	ast_mutex_destroy(&mem->mutex);
-	ast_free(mem);
-}
-
-/*!
- * \brief Get the \ref json_mem block for a pointer allocated via
- * ast_json_malloc().
- *
- * This function properly handles Jansson singletons (null, true, false), and
- * \c NULL.
- *
- * \param p Pointer, usually to a \c json_t or \ref ast_json.
- * \return \ref json_mem object with extra allocation info.
- */
-static inline struct json_mem *to_json_mem(void *p)
-{
-	struct json_mem *mem;
-	/* Avoid ref'ing the singleton values */
-	if (p == NULL || p == json_null() || p == json_true() ||
-		p == json_false()) {
-		return NULL;
-	}
-	mem = (struct json_mem *)((char *) (p) - sizeof(*mem));
-	ast_assert(mem->magic == JSON_MAGIC);
-	return mem;
-}
-
-/*!
- * \brief Lock an \ref ast_json instance.
- *
- * If \a json is an immutable singleton (null, true, false), this function
- * safely ignores it and returns \c NULL. Otherwise, \a json must have been
- * allocates using ast_json_malloc().
- *
- * \param json JSON instance to lock.
- * \return \ref Corresponding \ref json_mem block.
- * \return \c NULL if \a json was not allocated.
- */
-static struct json_mem *json_mem_lock(struct ast_json *json)
-{
-	struct json_mem *mem = to_json_mem(json);
-	if (!mem) {
-		return NULL;
-	}
-	ast_mutex_lock(&mem->mutex);
-	return mem;
-}
-
-/*!
- * \brief Unlock a \ref json_mem instance.
- *
- * \param mem \ref json_mem, usually returned from json_mem_lock().
- */
-static void json_mem_unlock(struct json_mem *mem)
-{
-	if (!mem) {
-		return;
-	}
-	ast_mutex_unlock(&mem->mutex);
-}
-
-/*!
- * \brief Scoped lock for a \ref ast_json instance.
- *
- * \param json JSON instance to lock.
- */
-#define SCOPED_JSON_LOCK(json)				\
-	RAII_VAR(struct json_mem *, __mem_ ## __LINE__, \
-		json_mem_lock(json), json_mem_unlock)
-
-void *ast_json_malloc(size_t size)
-{
-	struct json_mem *mem = ast_malloc(size + sizeof(*mem));
-	if (!mem) {
-		return NULL;
-	}
-	mem->magic = JSON_MAGIC;
-	ast_mutex_init(&mem->mutex);
-	return mem->data;
-}
-
-AST_THREADSTORAGE(json_free_list_ts);
-
-/*!
- * \brief Struct for a linked list of \ref json_mem.
- */
-AST_LIST_HEAD_NOLOCK(json_mem_list, json_mem);
-
-/*!
- * \brief Thread local list of \ref json_mem blocks to free at the end of an
- * unref.
- */
-static struct json_mem_list *json_free_list(void)
-{
-	return ast_threadstorage_get(&json_free_list_ts,
-		sizeof(struct json_mem_list));
-}
-
-void ast_json_free(void *p)
-{
-	struct json_mem *mem;
-	struct json_mem_list *free_list;
-	mem = to_json_mem(p);
-
-	if (!mem) {
-		return;
-	}
-
-	/* Since the unref is holding a lock in mem, we can't free it
-	 * immediately. Store it off on a thread local list to be freed by
-	 * ast_json_unref().
-	 */
-	free_list = json_free_list();
-	if (!free_list) {
-		ast_log(LOG_ERROR, "Error allocating free list\n");
-		ast_assert(0);
-		/* It's not ideal to free the memory immediately, but that's the
-		 * best we can do if the threadlocal allocation fails */
-		json_mem_free(mem);
-		return;
-	}
-
-	AST_LIST_INSERT_HEAD(free_list, mem, list);
-}
-
-void ast_json_set_alloc_funcs(void *(*malloc_fn)(size_t), void (*free_fn)(void*))
-{
-	json_set_alloc_funcs(malloc_fn, free_fn);
-}
-
-void ast_json_reset_alloc_funcs(void)
-{
-	json_set_alloc_funcs(ast_json_malloc, ast_json_free);
-}
-
-struct ast_json *ast_json_ref(struct ast_json *json)
-{
-	/* Jansson refcounting is non-atomic; lock it. */
-	SCOPED_JSON_LOCK(json);
-	json_incref((json_t *)json);
-	return json;
-}
-
-void ast_json_unref(struct ast_json *json)
-{
-	struct json_mem_list *free_list;
-	struct json_mem *mem;
-
-	if (!json) {
-		return;
-	}
-
-	/* Jansson refcounting is non-atomic; lock it. */
-	{
-		SCOPED_JSON_LOCK(json);
-
-		json_decref((json_t *) json);
-	}
-
-	/* Now free any objects that were ast_json_free()'s while the lock was
-	 * held */
-	free_list = json_free_list();
-	if (!free_list) {
-		return;
-	}
-
-	while ((mem = AST_LIST_REMOVE_HEAD(free_list, list))) {
-		json_mem_free(mem);
-	}
-}
-
-enum ast_json_type ast_json_typeof(const struct ast_json *json)
-{
-	int r = json_typeof((json_t*)json);
-	switch(r) {
-	case JSON_OBJECT: return AST_JSON_OBJECT;
-	case JSON_ARRAY: return AST_JSON_ARRAY;
-	case JSON_STRING: return AST_JSON_STRING;
-	case JSON_INTEGER: return AST_JSON_INTEGER;
-	case JSON_REAL: return AST_JSON_REAL;
-	case JSON_TRUE: return AST_JSON_TRUE;
-	case JSON_FALSE: return AST_JSON_FALSE;
-	case JSON_NULL: return AST_JSON_NULL;
-	}
-	ast_assert(0); /* Unexpect return from json_typeof */
-	return r;
-}
-
-const char *ast_json_typename(enum ast_json_type type)
-{
-	switch (type) {
-	case AST_JSON_OBJECT: return "object";
-	case AST_JSON_ARRAY: return "array";
-	case AST_JSON_STRING: return "string";
-	case AST_JSON_INTEGER: return "integer";
-	case AST_JSON_REAL: return "real";
-	case AST_JSON_TRUE: return "boolean";
-	case AST_JSON_FALSE: return "boolean";
-	case AST_JSON_NULL: return "null";
-	}
-	ast_assert(0);
-	return "?";
-}
-
-
-struct ast_json *ast_json_true(void)
-{
-	return (struct ast_json *)json_true();
-}
-
-struct ast_json *ast_json_false(void)
-{
-	return (struct ast_json *)json_false();
-}
-
-struct ast_json *ast_json_boolean(int value)
-{
-#if JANSSON_VERSION_HEX >= 0x020400
-	return (struct ast_json *)json_boolean(value);
-#else
-	return value ? ast_json_true() : ast_json_false();
-#endif
-}
-
-struct ast_json *ast_json_null(void)
-{
-	return (struct ast_json *)json_null();
-}
-
-int ast_json_is_true(const struct ast_json *json)
-{
-	return json_is_true((const json_t *)json);
-}
-
-int ast_json_is_false(const struct ast_json *json)
-{
-	return json_is_false((const json_t *)json);
-}
-
-int ast_json_is_null(const struct ast_json *json)
-{
-	return json_is_null((const json_t *)json);
-}
-
-struct ast_json *ast_json_string_create(const char *value)
-{
-	return (struct ast_json *)json_string(value);
-}
-
-const char *ast_json_string_get(const struct ast_json *string)
-{
-	return json_string_value((json_t *)string);
-}
-
-int ast_json_string_set(struct ast_json *string, const char *value)
-{
-	return json_string_set((json_t *)string, value);
-}
-
-struct ast_json *ast_json_stringf(const char *format, ...)
-{
-	struct ast_json *ret;
-	va_list args;
-	va_start(args, format);
-	ret = ast_json_vstringf(format, args);
-	va_end(args);
-	return ret;
-}
-
-struct ast_json *ast_json_vstringf(const char *format, va_list args)
-{
-	char *str = NULL;
-	json_t *ret = NULL;
-
-	if (format) {
-		int err = ast_vasprintf(&str, format, args);
-		if (err > 0) {
-			ret = json_string(str);
-			ast_free(str);
-		}
-	}
-	return (struct ast_json *)ret;
-}
-
-struct ast_json *ast_json_integer_create(intmax_t value)
-{
-	return (struct ast_json *)json_integer(value);
-}
-
-intmax_t ast_json_integer_get(const struct ast_json *integer)
-{
-	return json_integer_value((json_t *)integer);
-}
-
-int ast_json_integer_set(struct ast_json *integer, intmax_t value)
-{
-	return json_integer_set((json_t *)integer, value);
-}
-
-struct ast_json *ast_json_real_create(double value)
-{
-	return (struct ast_json *)json_real(value);
-}
-
-double ast_json_real_get(const struct ast_json *real)
-{
-	return json_real_value((json_t *)real);
-}
-
-int ast_json_real_set(struct ast_json *real, double value)
-{
-	return json_real_set((json_t *)real, value);
-}
-
-int ast_json_equal(const struct ast_json *lhs, const struct ast_json *rhs)
-{
-	return json_equal((json_t *)lhs, (json_t *)rhs);
-}
-
-struct ast_json *ast_json_array_create(void)
-{
-	return (struct ast_json *)json_array();
-}
-size_t ast_json_array_size(const struct ast_json *array)
-{
-	return json_array_size((json_t *)array);
-}
-struct ast_json *ast_json_array_get(const struct ast_json *array, size_t index)
-{
-	return (struct ast_json *)json_array_get((json_t *)array, index);
-}
-int ast_json_array_set(struct ast_json *array, size_t index, struct ast_json *value)
-{
-	return json_array_set_new((json_t *)array, index, (json_t *)value);
-}
-int ast_json_array_append(struct ast_json *array, struct ast_json *value)
-{
-	return json_array_append_new((json_t *)array, (json_t *)value);
-}
-int ast_json_array_insert(struct ast_json *array, size_t index, struct ast_json *value)
-{
-	return json_array_insert_new((json_t *)array, index, (json_t *)value);
-}
-int ast_json_array_remove(struct ast_json *array, size_t index)
-{
-	return json_array_remove((json_t *)array, index);
-}
-int ast_json_array_clear(struct ast_json *array)
-{
-	return json_array_clear((json_t *)array);
-}
-int ast_json_array_extend(struct ast_json *array, struct ast_json *tail)
-{
-	return json_array_extend((json_t *)array, (json_t *)tail);
-}
-
-struct ast_json *ast_json_object_create(void)
-{
-	return (struct ast_json *)json_object();
-}
-size_t ast_json_object_size(struct ast_json *object)
-{
-	return json_object_size((json_t *)object);
-}
-struct ast_json *ast_json_object_get(struct ast_json *object, const char *key)
-{
-	if (!key) {
-		return NULL;
-	}
-	return (struct ast_json *)json_object_get((json_t *)object, key);
-}
-int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
-{
-	return json_object_set_new((json_t *)object, key, (json_t *)value);
-}
-int ast_json_object_del(struct ast_json *object, const char *key)
-{
-	return json_object_del((json_t *)object, key);
-}
-int ast_json_object_clear(struct ast_json *object)
-{
-	return json_object_clear((json_t *)object);
-}
-int ast_json_object_update(struct ast_json *object, struct ast_json *other)
-{
-	return json_object_update((json_t *)object, (json_t *)other);
-}
-int ast_json_object_update_existing(struct ast_json *object, struct ast_json *other)
-{
-#if JANSSON_VERSION_HEX >= 0x020300
-	return json_object_update_existing((json_t *)object, (json_t *)other);
-#else
-	struct ast_json_iter *iter = ast_json_object_iter(other);
-	int ret = 0;
-
-	if (object == NULL || other == NULL) {
-		return -1;
-	}
-
-	while (iter != NULL && ret == 0) {
-		const char *key = ast_json_object_iter_key(iter);
-
-		if (ast_json_object_get(object, key) != NULL) {
-			struct ast_json *value = ast_json_object_iter_value(iter);
-
-			if (!value || ast_json_object_set(object, key, ast_json_ref(value))) {
-				ret = -1;
-			}
-		}
-		iter = ast_json_object_iter_next(other, iter);
-	}
-	return ret;
-#endif
-}
-int ast_json_object_update_missing(struct ast_json *object, struct ast_json *other)
-{
-#if JANSSON_VERSION_HEX >= 0x020300
-	return json_object_update_missing((json_t *)object, (json_t *)other);
-#else
-	struct ast_json_iter *iter = ast_json_object_iter(other);
-	int ret = 0;
-
-	if (object == NULL || other == NULL) {
-		return -1;
-	}
-
-	while (iter != NULL && ret == 0) {
-		const char *key = ast_json_object_iter_key(iter);
-
-		if (ast_json_object_get(object, key) == NULL) {
-			struct ast_json *value = ast_json_object_iter_value(iter);
-
-			if (!value || ast_json_object_set(object, key, ast_json_ref(value))) {
-				ret = -1;
-			}
-		}
-		iter = ast_json_object_iter_next(other, iter);
-	}
-	return ret;
-#endif
-}
-
-struct ast_json_iter *ast_json_object_iter(struct ast_json *object)
-{
-	return json_object_iter((json_t *)object);
-}
-struct ast_json_iter *ast_json_object_iter_at(struct ast_json *object, const char *key)
-{
-	return json_object_iter_at((json_t *)object, key);
-}
-struct ast_json_iter *ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter)
-{
-	return json_object_iter_next((json_t *)object, iter);
-}
-const char *ast_json_object_iter_key(struct ast_json_iter *iter)
-{
-	return json_object_iter_key(iter);
-}
-struct ast_json *ast_json_object_iter_value(struct ast_json_iter *iter)
-{
-	return (struct ast_json *)json_object_iter_value(iter);
-}
-int ast_json_object_iter_set(struct ast_json *object, struct ast_json_iter *iter, struct ast_json *value)
-{
-	return json_object_iter_set_new((json_t *)object, iter, (json_t *)value);
-}
-
-/*!
- * \brief Default flags for JSON encoding.
- */
-static size_t dump_flags(enum ast_json_encoding_format format)
-{
-	return format == AST_JSON_PRETTY ?
-		JSON_INDENT(2) | JSON_PRESERVE_ORDER : JSON_COMPACT;
-}
-
-char *ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
-{
-	/* Jansson's json_dump*, even though it's a read operation, isn't
-	 * thread safe for concurrent reads. Locking is necessary.
-	 * See http://www.digip.org/jansson/doc/2.4/portability.html#thread-safety. */
-	SCOPED_JSON_LOCK(root);
-	return json_dumps((json_t *)root, dump_flags(format));
-}
-
-static int write_to_ast_str(const char *buffer, size_t size, void *data)
-{
-	struct ast_str **dst = data;
-	size_t str_size = ast_str_size(*dst);
-	size_t remaining = str_size - ast_str_strlen(*dst);
-	int ret;
-
-	/* While ast_str_append will grow the ast_str, it won't report
-	 * allocation errors. Fortunately, it's not that hard.
-	 */
-
-	/* Remaining needs to be big enough for buffer, plus null char */
-	while (remaining < size + 1) {
-		/* doubling the size of the buffer gives us 'amortized
-		 * constant' time.
-		 * See http://stackoverflow.com/a/249695/115478 for info.
-		 */
-		str_size *= 2;
-		remaining = str_size - ast_str_strlen(*dst);
-	}
-
-	ret = ast_str_make_space(dst, str_size);
-	if (ret == -1) {
-		/* Could not alloc; fail */
-		return -1;
-	}
-
-	ast_str_append_substr(dst, -1, buffer, size);
-	return 0;
-}
-
-int ast_json_dump_str_format(struct ast_json *root, struct ast_str **dst, enum ast_json_encoding_format format)
-{
-	/* Jansson's json_dump*, even though it's a read operation, isn't
-	 * thread safe for concurrent reads. Locking is necessary.
-	 * See http://www.digip.org/jansson/doc/2.4/portability.html#thread-safety. */
-	SCOPED_JSON_LOCK(root);
-	return json_dump_callback((json_t *)root, write_to_ast_str, dst, dump_flags(format));
-}
-
-
-int ast_json_dump_file_format(struct ast_json *root, FILE *output, enum ast_json_encoding_format format)
-{
-	/* Jansson's json_dump*, even though it's a read operation, isn't
-	 * thread safe for concurrent reads. Locking is necessary.
-	 * See http://www.digip.org/jansson/doc/2.4/portability.html#thread-safety. */
-	SCOPED_JSON_LOCK(root);
-	if (!root || !output) {
-		return -1;
-	}
-	return json_dumpf((json_t *)root, output, dump_flags(format));
-}
-int ast_json_dump_new_file_format(struct ast_json *root, const char *path, enum ast_json_encoding_format format)
-{
-	/* Jansson's json_dump*, even though it's a read operation, isn't
-	 * thread safe for concurrent reads. Locking is necessary.
-	 * See http://www.digip.org/jansson/doc/2.4/portability.html#thread-safety. */
-	SCOPED_JSON_LOCK(root);
-	if (!root || !path) {
-		return -1;
-	}
-	return json_dump_file((json_t *)root, path, dump_flags(format));
-}
-
-/*!
- * \brief Copy Jansson error struct to ours.
- */
-static void copy_error(struct ast_json_error *error, const json_error_t *jansson_error)
-{
-	if (error && jansson_error) {
-		error->line = jansson_error->line;
-		error->column = jansson_error->column;
-		error->position = jansson_error->position;
-		ast_copy_string(error->text, jansson_error->text, sizeof(error->text));
-		ast_copy_string(error->source, jansson_error->source, sizeof(error->source));
-	}
-
-}
-
-static void parse_error(struct ast_json_error *error, const char *text, const char *source)
-{
-	if (error != NULL) {
-		error->line = 0;
-		error->column = 0;
-		error->position = 0;
-		strncpy(error->text, text, sizeof(error->text));
-		strncpy(error->source, source, sizeof(error->text));
-	}
-}
-
-struct ast_json *ast_json_load_string(const char *input, struct ast_json_error *error)
-{
-	json_error_t jansson_error = {};
-	struct ast_json *r = NULL;
-	if (input != NULL) {
-		r = (struct ast_json *)json_loads(input, 0, &jansson_error);
-		copy_error(error, &jansson_error);
-	} else {
-		parse_error(error, "NULL input string", "<null>");
-	}
-	return r;
-}
-
-struct ast_json *ast_json_load_str(const struct ast_str *input, struct ast_json_error *error)
-{
-	return ast_json_load_string(ast_str_buffer(input), error);
-}
-
-struct ast_json *ast_json_load_buf(const char *buffer, size_t buflen, struct ast_json_error *error)
-{
-	json_error_t jansson_error = {};
-	struct ast_json *r = (struct ast_json *)json_loadb(buffer, buflen, 0, &jansson_error);
-	copy_error(error, &jansson_error);
-	return r;
-}
-struct ast_json *ast_json_load_file(FILE *input, struct ast_json_error *error)
-{
-	json_error_t jansson_error = {};
-	struct ast_json *r = NULL;
-	if (input != NULL) {
-		r = (struct ast_json *)json_loadf(input, 0, &jansson_error);
-		copy_error(error, &jansson_error);
-	} else {
-		parse_error(error, "NULL input file", "<null>");
-	}
-	return r;
-}
-struct ast_json *ast_json_load_new_file(const char *path, struct ast_json_error *error)
-{
-	json_error_t jansson_error = {};
-	struct ast_json *r = (struct ast_json *)json_load_file(path, 0, &jansson_error);
-	copy_error(error, &jansson_error);
-	return r;
-}
-
-struct ast_json *ast_json_pack(char const *format, ...)
-{
-	struct ast_json *ret;
-	va_list args;
-	va_start(args, format);
-	ret = ast_json_vpack(format, args);
-	va_end(args);
-	return ret;
-}
-struct ast_json *ast_json_vpack(char const *format, va_list ap)
-{
-	json_error_t error;
-	struct ast_json *r = NULL;
-	if (format) {
-		r = (struct ast_json *)json_vpack_ex(&error, 0, format, ap);
-		if (!r && !ast_strlen_zero(error.text)) {
-			ast_log(LOG_ERROR,
-				"Error building JSON from '%s': %s.\n",
-				format, error.text);
-		}
-	}
-	return r;
-}
-
-struct ast_json *ast_json_copy(const struct ast_json *value)
-{
-	return (struct ast_json *)json_copy((json_t *)value);
-}
-struct ast_json *ast_json_deep_copy(const struct ast_json *value)
-{
-	return (struct ast_json *)json_deep_copy((json_t *)value);
-}
-
-struct ast_json *ast_json_name_number(const char *name, const char *number)
-{
-	return ast_json_pack("{s: s, s: s}",
-			     "name", name,
-			     "number", number);
-}
-
-struct ast_json *ast_json_dialplan_cep(const char *context, const char *exten, int priority)
-{
-	return ast_json_pack("{s: o, s: o, s: o}",
-			     "context", context ? ast_json_string_create(context) : ast_json_null(),
-			     "exten", exten ? ast_json_string_create(exten) : ast_json_null(),
-			     "priority", priority != -1 ? ast_json_integer_create(priority) : ast_json_null());
-}
-
-struct ast_json *ast_json_timeval(const struct timeval tv, const char *zone)
-{
-	char buf[AST_ISO8601_LEN];
-	struct ast_tm tm = {};
-
-	ast_localtime(&tv, &tm, zone);
-
-	ast_strftime(buf, sizeof(buf),AST_ISO8601_FORMAT, &tm);
-
-	return ast_json_string_create(buf);
-}
-
-struct ast_json *ast_json_ipaddr(const struct ast_sockaddr *addr, enum ast_transport transport_type)
-{
-	struct ast_str *string = ast_str_alloca(64);
-
-	if (!string) {
-		return NULL;
-	}
-
-	ast_str_set(&string, 0, (ast_sockaddr_is_ipv4(addr) ||
-		ast_sockaddr_is_ipv4_mapped(addr)) ? "IPV4/" : "IPV6/");
-
-	if (transport_type) {
-		char *transport_string = NULL;
-
-		/* NOTE: None will be applied if multiple transport types are specified in transport_type */
-		switch(transport_type) {
-		case AST_TRANSPORT_UDP:
-			transport_string = "UDP";
-			break;
-		case AST_TRANSPORT_TCP:
-			transport_string = "TCP";
-			break;
-		case AST_TRANSPORT_TLS:
-			transport_string = "TLS";
-			break;
-		case AST_TRANSPORT_WS:
-			transport_string = "WS";
-			break;
-		case AST_TRANSPORT_WSS:
-			transport_string = "WSS";
-			break;
-		}
-
-		if (transport_string) {
-			ast_str_append(&string, 0, "%s/", transport_string);
-		}
-	}
-
-	ast_str_append(&string, 0, "%s", ast_sockaddr_stringify_addr(addr));
-	ast_str_append(&string, 0, "/%s", ast_sockaddr_stringify_port(addr));
-
-	return ast_json_string_create(ast_str_buffer(string));
-}
-
-void ast_json_init(void)
-{
-	/* Setup to use Asterisk custom allocators */
-	ast_json_reset_alloc_funcs();
-}
-
-static void json_payload_destructor(void *obj)
-{
-	struct ast_json_payload *payload = obj;
-	ast_json_unref(payload->json);
-}
-
-struct ast_json_payload *ast_json_payload_create(struct ast_json *json)
-{
-	struct ast_json_payload *payload;
-
-	if (!(payload = ao2_alloc(sizeof(*payload), json_payload_destructor))) {
-		return NULL;
-	}
-
-	ast_json_ref(json);
-	payload->json = json;
-
-	return payload;
-}
-
-static struct ast_json *json_party_number(struct ast_party_number *number)
-{
-	if (!number->valid) {
-		return NULL;
-	}
-	return ast_json_pack("{s: s, s: i, s: i, s: s}",
-		"number", number->str,
-		"plan", number->plan,
-		"presentation", number->presentation,
-		"presentation_txt", ast_describe_caller_presentation(number->presentation));
-}
-
-static struct ast_json *json_party_name(struct ast_party_name *name)
-{
-	if (!name->valid) {
-		return NULL;
-	}
-	return ast_json_pack("{s: s, s: s, s: i, s: s}",
-		"name", name->str,
-		"character_set", ast_party_name_charset_describe(name->char_set),
-		"presentation", name->presentation,
-		"presentation_txt", ast_describe_caller_presentation(name->presentation));
-}
-
-static struct ast_json *json_party_subaddress(struct ast_party_subaddress *subaddress)
-{
-	if (!subaddress->valid) {
-		return NULL;
-	}
-	return ast_json_pack("{s: s, s: i, s: b}",
-		"subaddress", subaddress->str,
-		"type", subaddress->type,
-		"odd", subaddress->odd_even_indicator);
-}
-
-struct ast_json *ast_json_party_id(struct ast_party_id *party)
-{
-	RAII_VAR(struct ast_json *, json_party_id, NULL, ast_json_unref);
-	int pres;
-
-	/* Combined party presentation */
-	pres = ast_party_id_presentation(party);
-	json_party_id = ast_json_pack("{s: i, s: s}",
-		"presentation", pres,
-		"presentation_txt", ast_describe_caller_presentation(pres));
-	if (!json_party_id) {
-		return NULL;
-	}
-
-	/* Party number */
-	if (party->number.valid && ast_json_object_set(json_party_id, "number", json_party_number(&party->number))) {
-		return NULL;
-	}
-
-	/* Party name */
-	if (party->name.valid && ast_json_object_set(json_party_id, "name", json_party_name(&party->name))) {
-		return NULL;
-	}
-
-	/* Party subaddress */
-	if (party->subaddress.valid && ast_json_object_set(json_party_id, "subaddress", json_party_subaddress(&party->subaddress))) {
-		return NULL;
-	}
-
-	return ast_json_ref(json_party_id);
-}
-
-int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
-{
-	struct ast_json_iter *it_json_var;
-
-	*variables = NULL;
-
-	for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
-		 it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
-		struct ast_variable *new_var;
-		const char *key = ast_json_object_iter_key(it_json_var);
-
-		if (ast_strlen_zero(key)) {
-			continue;
-		}
-
-		new_var = ast_variable_new(key,
-		                           ast_json_string_get(ast_json_object_iter_value(it_json_var)),
-		                           "");
-		if (!new_var) {
-			ast_variables_destroy(*variables);
-			*variables = NULL;
-			return -1;
-		}
-
-		ast_variable_list_append(variables, new_var);
-	}
-
-	return 0;
-}
diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c
index bd5913e..b326701 100644
--- a/main/libasteriskssl.c
+++ b/main/libasteriskssl.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 373080 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef HAVE_OPENSSL
 #include <openssl/ssl.h>
@@ -93,33 +93,6 @@ void SSL_load_error_strings(void)
 #endif
 }
 
-void ERR_load_SSL_strings(void)
-{
-#if defined(AST_DEVMODE)
-	if (startup_complete) {
-		ast_debug(1, "Called after startup... ignoring!\n");
-	}
-#endif
-}
-
-void ERR_load_crypto_strings(void)
-{
-#if defined(AST_DEVMODE)
-	if (startup_complete) {
-		ast_debug(1, "Called after startup... ignoring!\n");
-	}
-#endif
-}
-
-void ERR_load_BIO_strings(void)
-{
-#if defined(AST_DEVMODE)
-	if (startup_complete) {
-		ast_debug(1, "Called after startup... ignoring!\n");
-	}
-#endif
-}
-
 void CRYPTO_set_id_callback(unsigned long (*func)(void))
 {
 #if defined(AST_DEVMODE)
@@ -157,8 +130,6 @@ int ast_ssl_init(void)
 	void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void));
 	void (*real_CRYPTO_set_locking_callback)(void (*)(int, int, const char *, int));
 	void (*real_SSL_load_error_strings)(void);
-	void (*real_ERR_load_SSL_strings)(void);
-	void (*real_ERR_load_BIO_strings)(void);
 	const char *errstr;
 
 	/* clear any previous dynamic linker errors */
@@ -216,12 +187,6 @@ int ast_ssl_init(void)
 	get_OpenSSL_function(SSL_load_error_strings);
 	real_SSL_load_error_strings();
 
-	get_OpenSSL_function(ERR_load_SSL_strings);
-	real_ERR_load_SSL_strings();
-
-	get_OpenSSL_function(ERR_load_BIO_strings);
-	real_ERR_load_BIO_strings();
-
 	startup_complete = 1;
 
 #endif /* HAVE_OPENSSL */
diff --git a/main/loader.c b/main/loader.c
index ed5bd9e..b183b4f 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -33,13 +33,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_MODULE_DIR */
 #include <dirent.h>
 
-#include "asterisk/dlinkedlists.h"
+#include "asterisk/linkedlists.h"
 #include "asterisk/module.h"
 #include "asterisk/config.h"
 #include "asterisk/channel.h"
@@ -50,13 +50,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/enum.h"
 #include "asterisk/http.h"
 #include "asterisk/lock.h"
-#include "asterisk/features_config.h"
+#include "asterisk/features.h"
 #include "asterisk/dsp.h"
 #include "asterisk/udptl.h"
 #include "asterisk/heap.h"
 #include "asterisk/app.h"
 #include "asterisk/test.h"
-#include "asterisk/sounds_index.h"
 
 #include <dlfcn.h>
 
@@ -64,30 +63,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/utils.h"
 
 /*** DOCUMENTATION
-	<managerEvent language="en_US" name="Reload">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
-			<syntax>
-				<parameter name="Module">
-					<para>The name of the module that was reloaded, or
-					<literal>All</literal> if all modules were reloaded</para>
-				</parameter>
-				<parameter name="Status">
-					<para>The numeric status code denoting the success or failure
-					of the reload request.</para>
-					<enumlist>
-						<enum name="0"><para>Success</para></enum>
-						<enum name="1"><para>Request queued</para></enum>
-						<enum name="2"><para>Module not found</para></enum>
-						<enum name="3"><para>Error</para></enum>
-						<enum name="4"><para>Reload already in progress</para></enum>
-						<enum name="5"><para>Module uninitialized</para></enum>
-						<enum name="6"><para>Reload not supported</para></enum>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #ifndef RTLD_NOW
@@ -103,7 +78,7 @@ struct ast_module_user {
 	AST_LIST_ENTRY(ast_module_user) entry;
 };
 
-AST_DLLIST_HEAD(module_user_list, ast_module_user);
+AST_LIST_HEAD(module_user_list, ast_module_user);
 
 static const unsigned char expected_key[] =
 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
@@ -117,19 +92,23 @@ static unsigned int embedding = 1; /* we always start out by registering embedde
 
 struct ast_module {
 	const struct ast_module_info *info;
+#ifdef REF_DEBUG
+	/* Used to get module references into REF_DEBUG logs */
+	void *ref_debug;
+#endif
 	void *lib;					/* the shared lib, or NULL if embedded */
 	int usecount;					/* the number of 'users' currently in this module */
 	struct module_user_list users;			/* the list of users in the module */
 	struct {
 		unsigned int running:1;
 		unsigned int declined:1;
+		unsigned int keepuntilshutdown:1;
 	} flags;
-	AST_LIST_ENTRY(ast_module) list_entry;
-	AST_DLLIST_ENTRY(ast_module) entry;
+	AST_LIST_ENTRY(ast_module) entry;
 	char resource[0];
 };
 
-static AST_DLLIST_HEAD_STATIC(module_list, ast_module);
+static AST_LIST_HEAD_STATIC(module_list, ast_module);
 
 const char *ast_module_name(const struct ast_module *mod)
 {
@@ -153,7 +132,7 @@ struct loadupdate {
 	AST_LIST_ENTRY(loadupdate) entry;
 };
 
-static AST_DLLIST_HEAD_STATIC(updaters, loadupdate);
+static AST_LIST_HEAD_STATIC(updaters, loadupdate);
 
 AST_MUTEX_DEFINE_STATIC(reloadlock);
 
@@ -164,7 +143,7 @@ struct reload_queue_item {
 
 static int do_full_reload = 0;
 
-static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item);
+static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
 
 /* when dynamic modules are being loaded, ast_module_register() will
    need to know what filename the module was loaded from while it
@@ -186,9 +165,10 @@ void ast_module_register(const struct ast_module_info *info)
 		mod = resource_being_loaded;
 	}
 
-	ast_debug(5, "Registering module %s\n", info->name);
-
 	mod->info = info;
+#ifdef REF_DEBUG
+	mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
+#endif
 	AST_LIST_HEAD_INIT(&mod->users);
 
 	/* during startup, before the loader has been initialized,
@@ -198,16 +178,16 @@ void ast_module_register(const struct ast_module_info *info)
 	   let's avoid it altogether
 	*/
 	if (embedding) {
-		AST_DLLIST_INSERT_TAIL(&embedded_module_list, mod, entry);
+		AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
 	} else {
-		AST_DLLIST_LOCK(&module_list);
+		AST_LIST_LOCK(&module_list);
 		/* it is paramount that the new entry be placed at the tail of
 		   the list, otherwise the code that uses dlopen() to load
 		   dynamic modules won't be able to find out if the module it
 		   just opened was registered or failed to load
 		*/
-		AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
-		AST_DLLIST_UNLOCK(&module_list);
+		AST_LIST_INSERT_TAIL(&module_list, mod, entry);
+		AST_LIST_UNLOCK(&module_list);
 	}
 
 	/* give the module a copy of its own handle, for later use in registrations and the like */
@@ -222,19 +202,21 @@ void ast_module_unregister(const struct ast_module_info *info)
 	   will already be empty, or we cannot have gotten to this
 	   point
 	*/
-	AST_DLLIST_LOCK(&module_list);
-	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
+	AST_LIST_LOCK(&module_list);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
 		if (mod->info == info) {
-			AST_DLLIST_REMOVE_CURRENT(entry);
+			AST_LIST_REMOVE_CURRENT(entry);
 			break;
 		}
 	}
-	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&module_list);
 
 	if (mod) {
-		ast_debug(5, "Unregistering module %s\n", info->name);
 		AST_LIST_HEAD_DESTROY(&mod->users);
+#ifdef REF_DEBUG
+		ao2_cleanup(mod->ref_debug);
+#endif
 		ast_free(mod);
 	}
 }
@@ -254,6 +236,10 @@ struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast
 	AST_LIST_INSERT_HEAD(&mod->users, u, entry);
 	AST_LIST_UNLOCK(&mod->users);
 
+#ifdef REF_DEBUG
+	ao2_ref(mod->ref_debug, +1);
+#endif
+
 	ast_atomic_fetchadd_int(&mod->usecount, +1);
 
 	ast_update_use_count();
@@ -278,6 +264,10 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
 		return;
 	}
 
+#ifdef REF_DEBUG
+	ao2_ref(mod->ref_debug, -1);
+#endif
+
 	ast_atomic_fetchadd_int(&mod->usecount, -1);
 	ast_free(u);
 
@@ -293,6 +283,11 @@ void __ast_module_user_hangup_all(struct ast_module *mod)
 		if (u->chan) {
 			ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
 		}
+
+#ifdef REF_DEBUG
+		ao2_ref(mod->ref_debug, -1);
+#endif
+
 		ast_atomic_fetchadd_int(&mod->usecount, -1);
 		ast_free(u);
 	}
@@ -310,22 +305,21 @@ static struct reload_classes {
 	const char *name;
 	int (*reload_fn)(void);
 } reload_classes[] = {	/* list in alpha order, longest match first for cli completion */
-	{ "acl",         ast_named_acl_reload },
-	{ "cdr",         ast_cdr_engine_reload },
-	{ "cel",         ast_cel_engine_reload },
-	{ "dnsmgr",      dnsmgr_reload },
-	{ "dsp",         ast_dsp_reload},
-	{ "extconfig",   read_config_maps },
-	{ "enum",        ast_enum_reload },
-	{ "features",    ast_features_config_reload },
-	{ "http",        ast_http_reload },
+	{ "cdr",	ast_cdr_engine_reload },
+	{ "dnsmgr",	dnsmgr_reload },
+	{ "extconfig",	read_config_maps },
+	{ "enum",	ast_enum_reload },
+	{ "acl",	ast_named_acl_reload },
+	{ "manager",	reload_manager },
+	{ "http",	ast_http_reload },
+	{ "logger",	logger_reload },
+	{ "features",	ast_features_reload },
+	{ "dsp",	ast_dsp_reload},
+	{ "udptl",	ast_udptl_reload },
 	{ "indications", ast_indications_reload },
-	{ "logger",      logger_reload },
-	{ "manager",     reload_manager },
-	{ "plc",         ast_plc_reload },
-	{ "sounds",      ast_sounds_reindex },
-	{ "udptl",       ast_udptl_reload },
-	{ NULL,          NULL }
+	{ "cel",        ast_cel_engine_reload },
+	{ "plc",        ast_plc_reload },
+	{ NULL, 	NULL }
 };
 
 static int printdigest(const unsigned char *d)
@@ -334,7 +328,7 @@ static int printdigest(const unsigned char *d)
 	char buf[256]; /* large enough so we don't have to worry */
 
 	for (pos = 0, x = 0; x < 16; x++)
-		pos += sprintf(buf + pos, " %02x", (unsigned)*d++);
+		pos += sprintf(buf + pos, " %02hhx", *d++);
 
 	ast_debug(1, "Unexpected signature:%s\n", buf);
 
@@ -392,28 +386,23 @@ static struct ast_module *find_resource(const char *resource, int do_lock)
 {
 	struct ast_module *cur;
 
-	if (do_lock) {
-		AST_DLLIST_LOCK(&module_list);
-	}
+	if (do_lock)
+		AST_LIST_LOCK(&module_list);
 
-	AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
 		if (!resource_name_match(resource, cur->resource))
 			break;
 	}
 
-	if (do_lock) {
-		AST_DLLIST_UNLOCK(&module_list);
-	}
+	if (do_lock)
+		AST_LIST_UNLOCK(&module_list);
 
 	return cur;
 }
 
 #ifdef LOADABLE_MODULES
 
-/*!
- * \brief dlclose(), with failure logging.
- */
-static void logged_dlclose(const char *name, void *lib)
+static void close_lib(const char *name, void *lib)
 {
 	char *error;
 
@@ -430,62 +419,14 @@ static void logged_dlclose(const char *name, void *lib)
 	}
 }
 
-#if defined(HAVE_RTLD_NOLOAD)
-/*!
- * \brief Check to see if the given resource is loaded.
- *
- * \param resource_name Name of the resource, including .so suffix.
- * \return False (0) if module is not loaded.
- * \return True (non-zero) if module is loaded.
- */
-static int is_module_loaded(const char *resource_name)
-{
-	char fn[PATH_MAX] = "";
-	void *lib;
-
-	snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
-		resource_name);
-
-	lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
-
-	if (lib) {
-		logged_dlclose(resource_name, lib);
-		return 1;
-	}
-
-	return 0;
-}
-#endif
-
 static void unload_dynamic_module(struct ast_module *mod)
 {
-	char *name = ast_strdupa(ast_module_name(mod));
 	void *lib = mod->lib;
 
 	/* WARNING: the structure pointed to by mod is going to
 	   disappear when this operation succeeds, so we can't
 	   dereference it */
-	logged_dlclose(ast_module_name(mod), lib);
-
-	/* There are several situations where the module might still be resident
-	 * in memory.
-	 *
-	 * If somehow there was another dlopen() on the same module (unlikely,
-	 * since that all is supposed to happen in loader.c).
-	 *
-	 * Or the lazy resolution of a global symbol (very likely, since that is
-	 * how we load all of our modules that export global symbols).
-	 *
-	 * Avoid the temptation of repeating the dlclose(). The other code that
-	 * dlopened the module still has its module reference, and should close
-	 * it itself. In other situations, dlclose() will happily return success
-	 * for as many times as you wish to call it.
-	 */
-#if defined(HAVE_RTLD_NOLOAD)
-	if (is_module_loaded(name)) {
-		ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
-	}
-#endif
+	close_lib(ast_module_name(mod), lib);
 }
 
 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
@@ -531,10 +472,10 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
 	   constructor) places the new module at the tail of the
 	   module_list
 	*/
-	if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) {
+	if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
 		ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
 		/* no, it did not, so close it and return */
-		logged_dlclose(resource_in, lib);
+		close_lib(resource_in, lib);
 		/* note that the module's destructor will call ast_module_unregister(),
 		   which will free the structure we allocated in resource_being_loaded */
 		return NULL;
@@ -545,11 +486,32 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
 	/* if we are being asked only to load modules that provide global symbols,
 	   and this one does not, then close it and return */
 	if (global_symbols_only && !wants_global) {
-		logged_dlclose(resource_in, lib);
+		close_lib(resource_in, lib);
 		return NULL;
 	}
 
-	logged_dlclose(resource_in, lib);
+	/* This section is a workaround for a gcc 4.1 bug that has already been
+	 * fixed in later versions.  Unfortunately, some distributions, such as
+	 * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
+	 * with this issue.  This basically ensures that optional_api modules are
+	 * loaded before any module which requires their functionality. */
+#if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
+	if (!ast_strlen_zero(mod->info->nonoptreq)) {
+		/* Force any required dependencies to load */
+		char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
+		while ((each = strsep(&required_resource, ","))) {
+			struct ast_module *dependency;
+			each = ast_strip(each);
+			dependency = find_resource(each, 0);
+			/* Is it already loaded? */
+			if (!dependency) {
+				load_resource(each, global_symbols_only, resource_heap, 1);
+			}
+		}
+	}
+#endif
+
+	close_lib(resource_in, lib);
 	resource_being_loaded = NULL;
 
 	/* start the load process again */
@@ -570,12 +532,11 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
 	   the previous time we did that, we're going to assume it worked this
 	   time too :) */
 
-	AST_DLLIST_LAST(&module_list)->lib = lib;
+	AST_LIST_LAST(&module_list)->lib = lib;
 	resource_being_loaded = NULL;
 
-	return AST_DLLIST_LAST(&module_list);
+	return AST_LIST_LAST(&module_list);
 }
-
 #endif
 
 void ast_module_shutdown(void)
@@ -583,7 +544,7 @@ void ast_module_shutdown(void)
 	struct ast_module *mod;
 	int somethingchanged = 1, final = 0;
 
-	AST_DLLIST_LOCK(&module_list);
+	AST_LIST_LOCK(&module_list);
 
 	/*!\note Some resources, like timers, are started up dynamically, and thus
 	 * may be still in use, even if all channels are dead.  We must therefore
@@ -598,25 +559,34 @@ void ast_module_shutdown(void)
 		/* Reset flag before traversing the list */
 		somethingchanged = 0;
 
-		AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
 			if (!final && mod->usecount) {
-				ast_debug(1, "Passing on %s: its use count is %d\n",
-					mod->resource, mod->usecount);
 				continue;
 			}
-			AST_DLLIST_REMOVE_CURRENT(entry);
+			AST_LIST_REMOVE_CURRENT(entry);
 			if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
-				ast_verb(1, "Unloading %s\n", mod->resource);
 				mod->info->unload();
 			}
 			AST_LIST_HEAD_DESTROY(&mod->users);
+#ifdef REF_DEBUG
+			ao2_cleanup(mod->ref_debug);
+#endif
 			free(mod);
 			somethingchanged = 1;
 		}
-		AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
+		AST_LIST_TRAVERSE_SAFE_END;
+		if (!somethingchanged) {
+			AST_LIST_TRAVERSE(&module_list, mod, entry) {
+				if (mod->flags.keepuntilshutdown) {
+					ast_module_unref(mod);
+					mod->flags.keepuntilshutdown = 0;
+					somethingchanged = 1;
+				}
+			}
+		}
 	} while (somethingchanged && !final);
 
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
 }
 
 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
@@ -625,10 +595,10 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
 	int res = -1;
 	int error = 0;
 
-	AST_DLLIST_LOCK(&module_list);
+	AST_LIST_LOCK(&module_list);
 
 	if (!(mod = find_resource(resource_name, 0))) {
-		AST_DLLIST_UNLOCK(&module_list);
+		AST_LIST_UNLOCK(&module_list);
 		ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
 		return -1;
 	}
@@ -653,7 +623,6 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
 		/* Request any channels attached to the module to hangup. */
 		__ast_module_user_hangup_all(mod);
 
-		ast_verb(1, "Unloading %s\n", mod->resource);
 		res = mod->info->unload();
 		if (res) {
 			ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
@@ -677,7 +646,7 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
 	if (!error)
 		mod->flags.running = mod->flags.declined = 0;
 
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
 
 	if (!error && !mod->lib && mod->info && mod->info->restore_globals)
 		mod->info->restore_globals();
@@ -704,8 +673,8 @@ char *ast_module_helper(const char *line, const char *word, int pos, int state,
 	if (pos != rpos)
 		return NULL;
 
-	AST_DLLIST_LOCK(&module_list);
-	AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
+	AST_LIST_LOCK(&module_list);
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
 		if (!strncasecmp(word, cur->resource, l) &&
 		    (cur->info->reload || !needsreload) &&
 		    ++which > state) {
@@ -713,7 +682,7 @@ char *ast_module_helper(const char *line, const char *word, int pos, int state,
 			break;
 		}
 	}
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
 
 	if (!ret) {
 		for (i=0; !ret && reload_classes[i].name; i++) {
@@ -790,67 +759,22 @@ static void queue_reload_request(const char *module)
 	AST_LIST_UNLOCK(&reload_queue);
 }
 
-/*!
- * \since 12
- * \internal
- * \brief Publish a \ref stasis message regarding the reload result
- */
-static void publish_reload_message(const char *name, enum ast_module_reload_result result)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
-	char res_buffer[8];
-
-	if (!ast_manager_get_generic_type()) {
-		return;
-	}
-
-	snprintf(res_buffer, sizeof(res_buffer), "%u", result);
-	event_object = ast_json_pack("{s: s, s: s}",
-			"Module", S_OR(name, "All"),
-			"Status", res_buffer);
-	json_object = ast_json_pack("{s: s, s: i, s: O}",
-			"type", "Reload",
-			"class_type", EVENT_FLAG_SYSTEM,
-			"event", event_object);
-
-	if (!json_object) {
-		return;
-	}
-
-	payload = ast_json_payload_create(json_object);
-	if (!payload) {
-		return;
-	}
-
-	message = stasis_message_create(ast_manager_get_generic_type(), payload);
-	if (!message) {
-		return;
-	}
-
-	stasis_publish(ast_manager_get_topic(), message);
-}
-
-enum ast_module_reload_result ast_module_reload(const char *name)
+int ast_module_reload(const char *name)
 {
 	struct ast_module *cur;
-	enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND;
+	int res = 0; /* return value. 0 = not found, others, see below */
 	int i;
 
 	/* If we aren't fully booted, we just pretend we reloaded but we queue this
 	   up to run once we are booted up. */
 	if (!ast_fully_booted) {
 		queue_reload_request(name);
-		res = AST_MODULE_RELOAD_QUEUED;
-		goto module_reload_exit;
+		return 0;
 	}
 
 	if (ast_mutex_trylock(&reloadlock)) {
-		ast_verb(3, "The previous reload command didn't finish yet\n");
-		res = AST_MODULE_RELOAD_IN_PROGRESS;
-		goto module_reload_exit;
+		ast_verbose("The previous reload command didn't finish yet\n");
+		return -1;	/* reload already in progress */
 	}
 	ast_lastreloadtime = ast_tvnow();
 
@@ -864,73 +788,69 @@ enum ast_module_reload_result ast_module_reload(const char *name)
 			}
 		}
 		if (res != AST_LOCK_SUCCESS) {
-			ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
+			ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
 			ast_mutex_unlock(&reloadlock);
-			res = AST_MODULE_RELOAD_ERROR;
-			goto module_reload_exit;
+			return -1;
 		}
 	}
 
 	/* Call "predefined" reload here first */
 	for (i = 0; reload_classes[i].name; i++) {
 		if (!name || !strcasecmp(name, reload_classes[i].name)) {
-			if (reload_classes[i].reload_fn() == AST_MODULE_LOAD_SUCCESS) {
-				res = AST_MODULE_RELOAD_SUCCESS;
+			if (!reload_classes[i].reload_fn()) {
+				ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", name);
 			}
+			res = 2;	/* found and reloaded */
 		}
 	}
 
-	if (name && res == AST_MODULE_RELOAD_SUCCESS) {
+	if (name && res) {
 		if (ast_opt_lock_confdir) {
 			ast_unlock_path(ast_config_AST_CONFIG_DIR);
 		}
 		ast_mutex_unlock(&reloadlock);
-		goto module_reload_exit;
+		return res;
 	}
 
-	AST_DLLIST_LOCK(&module_list);
-	AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
+	AST_LIST_LOCK(&module_list);
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
 		const struct ast_module_info *info = cur->info;
 
 		if (name && resource_name_match(name, cur->resource))
 			continue;
 
 		if (!cur->flags.running || cur->flags.declined) {
-			if (res == AST_MODULE_RELOAD_NOT_FOUND) {
-				res = AST_MODULE_RELOAD_UNINITIALIZED;
-			}
-			if (!name) {
+			if (!name)
 				continue;
-			}
+			ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
+				"Before reloading the module, you must run \"module load %s\" "
+				"and fix whatever is preventing the module from being initialized.\n",
+				name, name);
+			res = 2; /* Don't report that the module was not found */
 			break;
 		}
 
 		if (!info->reload) {	/* cannot be reloaded */
-			if (res == AST_MODULE_RELOAD_NOT_FOUND) {
-				res = AST_MODULE_RELOAD_NOT_IMPLEMENTED;
-			}
-			if (!name) {
-				continue;
-			}
-			break;
+			/* Nothing to reload, so reload is successful */
+			ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
+			if (res < 1)	/* store result if possible */
+				res = 1;	/* 1 = no reload() method */
+			continue;
 		}
+
+		res = 2;
 		ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
-		if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
-			res = AST_MODULE_RELOAD_SUCCESS;
-		}
-		if (name) {
-			break;
+		if (!info->reload()) {
+			ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
 		}
 	}
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
 
 	if (ast_opt_lock_confdir) {
 		ast_unlock_path(ast_config_AST_CONFIG_DIR);
 	}
 	ast_mutex_unlock(&reloadlock);
 
-module_reload_exit:
-	publish_reload_message(name, res);
 	return res;
 }
 
@@ -974,15 +894,17 @@ static enum ast_module_load_result start_resource(struct ast_module *mod)
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (!ast_fully_booted) {
-		ast_verb(1, "Loading %s.\n", mod->resource);
-	}
 	res = mod->info->load();
 
 	switch (res) {
 	case AST_MODULE_LOAD_SUCCESS:
 		if (!ast_fully_booted) {
-			ast_verb(2, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
+			ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
+			if (ast_opt_console && !option_verbose) {
+				/* This never looks good on anything but the root console, so
+				 * it's best not to try to funnel it through the logger. */
+				fprintf(stdout, ".");
+			}
 		} else {
 			ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
 		}
@@ -1000,12 +922,6 @@ static enum ast_module_load_result start_resource(struct ast_module *mod)
 		break;
 	}
 
-	/* Make sure the newly started module is at the end of the list */
-	AST_DLLIST_LOCK(&module_list);
-	AST_DLLIST_REMOVE(&module_list, mod, entry);
-	AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
-	AST_DLLIST_UNLOCK(&module_list);
-
 	return res;
 }
 
@@ -1069,18 +985,24 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi
 		res = start_resource(mod);
 	}
 
+	/* Now make sure that the list is sorted */
+	AST_LIST_LOCK(&module_list);
+	AST_LIST_REMOVE(&module_list, mod, entry);
+	AST_LIST_INSERT_SORTALPHA(&module_list, mod, entry, resource);
+	AST_LIST_UNLOCK(&module_list);
+
 	return res;
 }
 
 int ast_load_resource(const char *resource_name)
 {
 	int res;
-	AST_DLLIST_LOCK(&module_list);
+	AST_LIST_LOCK(&module_list);
 	res = load_resource(resource_name, 0, NULL, 0);
 	if (!res) {
 		ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
 	}
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
 
 	return res;
 }
@@ -1120,17 +1042,16 @@ static int mod_load_cmp(void *a, void *b)
 {
 	struct ast_module *a_mod = (struct ast_module *) a;
 	struct ast_module *b_mod = (struct ast_module *) b;
-	/* if load_pri is not set, default is 128.  Lower is better */
-	int a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
-	int b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
-
-	/*
-	 * Returns comparison values for a min-heap
-	 * <0 a_pri > b_pri
-	 * =0 a_pri == b_pri
-	 * >0 a_pri < b_pri
-	 */
-	return b_pri - a_pri;
+	int res = -1;
+	/* if load_pri is not set, default is 128.  Lower is better*/
+	unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
+	unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
+	if (a_pri == b_pri) {
+		res = 0;
+	} else if (a_pri < b_pri) {
+		res = 1;
+	}
+	return res;
 }
 
 /*! loads modules in order by load_pri, updates mod_count
@@ -1222,7 +1143,7 @@ int load_modules(unsigned int preload_only)
 
 	AST_LIST_HEAD_INIT_NOLOCK(&load_order);
 
-	AST_DLLIST_LOCK(&module_list);
+	AST_LIST_LOCK(&module_list);
 
 	if (embedded_module_list.first) {
 		module_list.first = embedded_module_list.first;
@@ -1252,7 +1173,7 @@ int load_modules(unsigned int preload_only)
 	/* check if 'autoload' is on */
 	if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
 		/* if so, first add all the embedded modules that are not already running to the load order */
-		AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
+		AST_LIST_TRAVERSE(&module_list, mod, entry) {
 			/* if it's not embedded, skip it */
 			if (mod->lib)
 				continue;
@@ -1338,7 +1259,26 @@ done:
 		ast_free(order);
 	}
 
-	AST_DLLIST_UNLOCK(&module_list);
+	AST_LIST_UNLOCK(&module_list);
+
+	/* Tell manager clients that are aggressive at logging in that we're done
+	   loading modules. If there's a DNS problem in chan_sip, we might not
+	   even reach this */
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when all dynamic modules have finished their initial loading.</synopsis>
+			<syntax>
+				<parameter name="ModuleSelection">
+					<enumlist>
+						<enum name="Preload"/>
+						<enum name="All"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
+
 	return res;
 }
 
@@ -1354,32 +1294,22 @@ void ast_update_use_count(void)
 	AST_LIST_UNLOCK(&updaters);
 }
 
-int ast_update_module_list(int (*modentry)(const char *module, const char *description,
-                                           int usecnt, const char *status, const char *like,
-										   enum ast_module_support_level support_level),
-                           const char *like)
+int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
+			   const char *like)
 {
 	struct ast_module *cur;
 	int unlock = -1;
 	int total_mod_loaded = 0;
-	AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
 
-	if (AST_DLLIST_TRYLOCK(&module_list)) {
+	if (AST_LIST_TRYLOCK(&module_list))
 		unlock = 0;
-	}
-
-	AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
-		AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource);
-	}
 
-	while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) {
-		total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
-						cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
+		total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
 	}
 
-	if (unlock) {
-		AST_DLLIST_UNLOCK(&module_list);
-	}
+	if (unlock)
+		AST_LIST_UNLOCK(&module_list);
 
 	return total_mod_loaded;
 }
@@ -1430,36 +1360,62 @@ int ast_loader_unregister(int (*v)(void))
 	return cur ? 0 : -1;
 }
 
-struct ast_module *ast_module_ref(struct ast_module *mod)
+struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
 {
 	if (!mod) {
 		return NULL;
 	}
 
+#ifdef REF_DEBUG
+	__ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
+#endif
+
 	ast_atomic_fetchadd_int(&mod->usecount, +1);
 	ast_update_use_count();
 
 	return mod;
 }
 
-void ast_module_unref(struct ast_module *mod)
+void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
+{
+	if (!mod || mod->flags.keepuntilshutdown) {
+		return;
+	}
+
+	__ast_module_ref(mod, file, line, func);
+	mod->flags.keepuntilshutdown = 1;
+}
+
+void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
 {
 	if (!mod) {
 		return;
 	}
 
+#ifdef REF_DEBUG
+	__ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
+#endif
+
 	ast_atomic_fetchadd_int(&mod->usecount, -1);
 	ast_update_use_count();
 }
 
-const char *support_level_map [] = {
-	[AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
-	[AST_MODULE_SUPPORT_CORE] = "core",
-	[AST_MODULE_SUPPORT_EXTENDED] = "extended",
-	[AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
-};
 
-const char *ast_module_support_level_to_string(enum ast_module_support_level support_level)
+
+/* The following exists for ABI compatibility */
+#undef ast_module_ref
+#undef ast_module_unref
+
+struct ast_module *ast_module_ref(struct ast_module *mod);
+void ast_module_unref(struct ast_module *mod);
+
+struct ast_module *ast_module_ref(struct ast_module *mod)
 {
-	return support_level_map[support_level];
+	return __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
 }
+
+void ast_module_unref(struct ast_module *mod)
+{
+	__ast_module_unref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+}
+
diff --git a/main/lock.c b/main/lock.c
index d178194..dd90d7b 100644
--- a/main/lock.c
+++ b/main/lock.c
@@ -27,7 +27,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411087 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/lock.h"
@@ -62,6 +62,66 @@ static void __dump_backtrace(struct ast_bt *bt, int canlog)
 }
 #endif	/* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
 
+#ifdef DEBUG_THREADS
+AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
+
+static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt)
+{
+	pthread_mutexattr_t reentr_attr;
+	struct ast_lock_track *lt;
+
+	/* It's a bit painful to lock a global mutex for every access to the
+	 * reentrancy structure, but it's necessary to ensure that we don't
+	 * double-allocate the structure or double-initialize the reentr_mutex.
+	 *
+	 * If you'd like to replace this with a double-checked lock, be sure to
+	 * properly volatile-ize everything to avoid optimizer bugs.
+	 *
+	 * We also have to use the underlying pthread calls for manipulating
+	 * the mutex, because this is called from the Asterisk mutex code.
+	 */
+	pthread_mutex_lock(&reentrancy_lock.mutex);
+
+	if (*plt) {
+		pthread_mutex_unlock(&reentrancy_lock.mutex);
+		return *plt;
+	}
+
+	lt = *plt = ast_std_calloc(1, sizeof(*lt));
+	if (!lt) {
+		fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__);
+#if defined(DO_CRASH) || defined(THREAD_CRASH)
+		abort();
+#else
+		pthread_mutex_unlock(&reentrancy_lock.mutex);
+		return NULL;
+#endif
+	}
+
+	pthread_mutexattr_init(&reentr_attr);
+	pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
+	pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
+	pthread_mutexattr_destroy(&reentr_attr);
+
+	pthread_mutex_unlock(&reentrancy_lock.mutex);
+	return lt;
+}
+
+static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
+{
+	struct ast_lock_track *lt;
+
+	if (*plt) {
+		lt = *plt;
+		*plt = NULL;
+
+		pthread_mutex_destroy(&lt->reentr_mutex);
+		ast_std_free(lt);
+	}
+}
+
+#endif /* DEBUG_THREADS */
+
 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
 						const char *mutex_name, ast_mutex_t *t)
 {
@@ -69,30 +129,26 @@ int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, con
 	pthread_mutexattr_t  attr;
 
 #ifdef DEBUG_THREADS
-	t->track = NULL;
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-/*
-		int canlog = strcmp(filename, "logger.c") & track;
+		int canlog = tracking && strcmp(filename, "logger.c");
+
 		__ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
 				   filename, lineno, func, mutex_name);
 		DO_THREAD_CRASH;
-*/
-		return 0;
+		return EBUSY;
 	}
-
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if ((t->tracking = tracking)) {
-		ast_reentrancy_init(&t->track);
-	}
+	t->track = NULL;
+	t->tracking = tracking;
 #endif /* DEBUG_THREADS */
 
 	pthread_mutexattr_init(&attr);
 	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
-
 	res = pthread_mutex_init(&t->mutex, &attr);
 	pthread_mutexattr_destroy(&attr);
+
 	return res;
 }
 
@@ -102,28 +158,25 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = t->track;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-		/* Don't try to uninitialize non initialized mutex
-		 * This may no effect on linux
-		 * And always ganerate core on *BSD with
-		 * linked libpthread
-		 * This not error condition if the mutex created on the fly.
+		/* Don't try to uninitialize an uninitialized mutex
+		 * This may have no effect on linux
+		 * but it always generates a core on *BSD when
+		 * linked with libpthread.
+		 * This is not an error condition if the mutex is created on the fly.
 		 */
 		__ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
 				   filename, lineno, func, mutex_name);
-		return 0;
+		DO_THREAD_CRASH;
+		res = EINVAL;
+		goto lt_cleanup;
 	}
 #endif
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
-	}
-	lt = t->track;
-
 	res = pthread_mutex_trylock(&t->mutex);
 	switch (res) {
 	case 0:
@@ -136,7 +189,7 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
 	case EBUSY:
 		__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
 				   filename, lineno, func, mutex_name);
-		if (t->tracking) {
+		if (lt) {
 			ast_reentrancy_lock(lt);
 			__ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
 				    lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
@@ -156,7 +209,10 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
 		__ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
 				   filename, lineno, func, mutex_name, strerror(res));
 	}
-	if (t->tracking) {
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
+lt_cleanup:
+#endif
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		lt->file[0] = filename;
 		lt->lineno[0] = lineno;
@@ -180,33 +236,17 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-		/* Don't warn abount uninitialized mutex.
-		 * Simple try to initialize it.
-		 * May be not needed in linux system.
-		 */
-		res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
-		if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
-					 filename, lineno, func, mutex_name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -216,7 +256,7 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -274,7 +314,7 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-	if (t->tracking && !res) {
+	if (lt && !res) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -287,10 +327,8 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 							   filename, lineno, func, mutex_name);
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 #ifdef HAVE_BKTR
 		if (lt->reentrancy) {
 			ast_reentrancy_lock(lt);
@@ -320,33 +358,17 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-		/* Don't warn abount uninitialized mutex.
-		 * Simple try to initialize it.
-		 * May be not needed in linux system.
-		 */
-		res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
-		if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
-					 filename, lineno, func, mutex_name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -356,7 +378,7 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -372,7 +394,7 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
 	res = pthread_mutex_trylock(&t->mutex);
 
 #ifdef DEBUG_THREADS
-	if (t->tracking && !res) {
+	if (lt && !res) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -385,10 +407,8 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
 					   filename, lineno, func, mutex_name);
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 		ast_mark_lock_failed(t);
 	}
 #endif /* DEBUG_THREADS */
@@ -402,8 +422,8 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
@@ -412,21 +432,16 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
 		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
 				   filename, lineno, func, mutex_name);
-		res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
-		if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
-					 filename, lineno, func, mutex_name);
-		}
-		return res;
+		DO_THREAD_CRASH;
+		return EINVAL;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
 			__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
@@ -505,6 +520,29 @@ int __ast_cond_destroy(const char *filename, int lineno, const char *func,
 	return pthread_cond_destroy(cond);
 }
 
+#ifdef DEBUG_THREADS
+static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
+{
+	ast_reentrancy_lock(lt);
+
+	/*
+	 * The following code must match the struct ast_lock_track
+	 * definition with the explicit exception of the reentr_mutex
+	 * member.
+	 */
+	memcpy(lt->file, lt_saved->file, sizeof(lt->file));
+	memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
+	lt->reentrancy = lt_saved->reentrancy;
+	memcpy(lt->func, lt_saved->func, sizeof(lt->func));
+	memcpy(lt->thread, lt_saved->thread, sizeof(lt->thread));
+#ifdef HAVE_BKTR
+	memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
+#endif
+
+	ast_reentrancy_unlock(lt);
+}
+#endif /* DEBUG_THREADS */
+
 int __ast_cond_wait(const char *filename, int lineno, const char *func,
 				  const char *cond_name, const char *mutex_name,
 				  ast_cond_t *cond, ast_mutex_t *t)
@@ -512,32 +550,27 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
+	struct ast_lock_track *lt = NULL;
 	struct ast_lock_track lt_orig;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
 		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
 				   filename, lineno, func, mutex_name);
-		res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
-		if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
-					 filename, lineno, func, mutex_name);
-		}
-		return res;
+		DO_THREAD_CRASH;
+		return EINVAL;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
-			__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+			__ast_mutex_logger("%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
 					   filename, lineno, func, mutex_name);
 			__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
 					   lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
@@ -546,7 +579,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
 #endif
 			DO_THREAD_CRASH;
 		} else if (lt->reentrancy <= 0) {
-			__ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
+			__ast_mutex_logger("%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
 					   filename, lineno, func, mutex_name);
 			DO_THREAD_CRASH;
 		}
@@ -569,16 +602,8 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
 		__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
 				   filename, lineno, func, strerror(res));
 		DO_THREAD_CRASH;
-	} else if (t->tracking) {
-		pthread_mutex_t reentr_mutex_orig;
-		ast_reentrancy_lock(lt);
-		/* Restore lock tracking to what it was prior to the wait */
-		reentr_mutex_orig = lt->reentr_mutex;
-		*lt = lt_orig;
-		/* un-trash the mutex we just copied over */
-		lt->reentr_mutex = reentr_mutex_orig;
-		ast_reentrancy_unlock(lt);
-
+	} else if (lt) {
+		restore_lock_tracking(lt, &lt_orig);
 		ast_restore_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
@@ -593,32 +618,27 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
+	struct ast_lock_track *lt = NULL;
 	struct ast_lock_track lt_orig;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
 		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
 				   filename, lineno, func, mutex_name);
-		res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
-		if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
-					 filename, lineno, func, mutex_name);
-		}
-		return res;
+		DO_THREAD_CRASH;
+		return EINVAL;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
-			__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+			__ast_mutex_logger("%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
 					   filename, lineno, func, mutex_name);
 			__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
 					   lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
@@ -627,7 +647,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
 #endif
 			DO_THREAD_CRASH;
 		} else if (lt->reentrancy <= 0) {
-			__ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
+			__ast_mutex_logger("%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
 					   filename, lineno, func, mutex_name);
 			DO_THREAD_CRASH;
 		}
@@ -650,17 +670,9 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
 		__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
 				   filename, lineno, func, strerror(res));
 		DO_THREAD_CRASH;
-	} else if (t->tracking) {
-		pthread_mutex_t reentr_mutex_orig;
-		ast_reentrancy_lock(lt);
-		/* Restore lock tracking to what it was prior to the wait */
-		reentr_mutex_orig = lt->reentr_mutex;
-		*lt = lt_orig;
-		/* un-trash the mutex we just copied over */
-		lt->reentr_mutex = reentr_mutex_orig;
-		ast_reentrancy_unlock(lt);
-
-		ast_suspend_lock_info(t);
+	} else if (lt) {
+		restore_lock_tracking(lt, &lt_orig);
+		ast_restore_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
 
@@ -673,30 +685,28 @@ int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char
 	pthread_rwlockattr_t attr;
 
 #ifdef DEBUG_THREADS
-
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
-
 	if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
+		int canlog = tracking && strcmp(filename, "logger.c");
+
 		__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
 				filename, lineno, func, rwlock_name);
-		return 0;
+		DO_THREAD_CRASH;
+		return EBUSY;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if ((t->tracking = tracking)) {
-		ast_reentrancy_init(&t->track);
-	}
+	t->track = NULL;
+	t->tracking = tracking;
 #endif /* DEBUG_THREADS */
 
 	pthread_rwlockattr_init(&attr);
-
 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
 	pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
 #endif
-
 	res = pthread_rwlock_init(&t->lock, &attr);
 	pthread_rwlockattr_destroy(&attr);
+
 	return res;
 }
 
@@ -706,16 +716,17 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con
 
 #ifdef DEBUG_THREADS
 	struct ast_lock_track *lt = t->track;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
 		__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
 				   filename, lineno, func, rwlock_name);
-		return 0;
+		DO_THREAD_CRASH;
+		res = EINVAL;
+		goto lt_cleanup;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
 #endif /* DEBUG_THREADS */
 
 	res = pthread_rwlock_destroy(&t->lock);
@@ -725,7 +736,10 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con
 		__ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
 				filename, lineno, func, rwlock_name, strerror(res));
 	}
-	if (t->tracking && lt) {
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
+lt_cleanup:
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		lt->file[0] = filename;
 		lt->lineno[0] = lineno;
@@ -748,33 +762,27 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 	int lock_found = 0;
 
-
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
 		__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
 				   filename, line, func, name);
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-		}
-		return res;
+		DO_THREAD_CRASH;
+		return EINVAL;
 	}
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy) {
 			int i;
@@ -834,33 +842,17 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -870,7 +862,7 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -894,7 +886,7 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
 				if (wait_time > reported_wait && (wait_time % 5) == 0) {
 					__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
 						filename, line, func, (int)wait_time, name);
-					if (t->tracking) {
+					if (lt) {
 						ast_reentrancy_lock(lt);
 #ifdef HAVE_BKTR
 						__dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
@@ -918,7 +910,7 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -928,10 +920,8 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
 			lt->reentrancy++;
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 #ifdef HAVE_BKTR
 		if (lt->reentrancy) {
 			ast_reentrancy_lock(lt);
@@ -961,33 +951,17 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -997,7 +971,7 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -1021,7 +995,7 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 				if (wait_time > reported_wait && (wait_time % 5) == 0) {
 					__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
 						filename, line, func, (int)wait_time, name);
-					if (t->tracking) {
+					if (lt) {
 						ast_reentrancy_lock(lt);
 #ifdef HAVE_BKTR
 						__dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
@@ -1045,7 +1019,7 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -1055,10 +1029,8 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 			lt->reentrancy++;
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 #ifdef HAVE_BKTR
 		if (lt->reentrancy) {
 			ast_reentrancy_lock(lt);
@@ -1067,13 +1039,9 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
 		} else {
 			bt = NULL;
 		}
-		if (t->tracking) {
-			ast_remove_lock_info(t, bt);
-		}
+		ast_remove_lock_info(t, bt);
 #else
-		if (t->tracking) {
-			ast_remove_lock_info(t);
-		}
+		ast_remove_lock_info(t);
 #endif
 	}
 	if (res) {
@@ -1092,33 +1060,17 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -1128,7 +1080,7 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -1160,7 +1112,7 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a
 #endif
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -1170,10 +1122,8 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a
 			lt->reentrancy++;
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 #ifdef HAVE_BKTR
 		if (lt->reentrancy) {
 			ast_reentrancy_lock(lt);
@@ -1203,33 +1153,17 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
+	struct ast_lock_track *lt = NULL;
+	int canlog = t->tracking && strcmp(filename, "logger.c");
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -1239,7 +1173,7 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -1271,7 +1205,7 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
 #endif
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -1281,10 +1215,8 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
 			lt->reentrancy++;
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 #ifdef HAVE_BKTR
 		if (lt->reentrancy) {
 			ast_reentrancy_lock(lt);
@@ -1293,13 +1225,9 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
 		} else {
 			bt = NULL;
 		}
-		if (t->tracking) {
-			ast_remove_lock_info(t, bt);
-		}
+		ast_remove_lock_info(t, bt);
 #else
-		if (t->tracking) {
-			ast_remove_lock_info(t);
-		}
+		ast_remove_lock_info(t);
 #endif
 	}
 	if (res) {
@@ -1317,33 +1245,16 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
+	struct ast_lock_track *lt = NULL;
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
 
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -1353,7 +1264,7 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -1369,7 +1280,7 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast
 	res = pthread_rwlock_tryrdlock(&t->lock);
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -1379,10 +1290,8 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast
 			lt->reentrancy++;
 		}
 		ast_reentrancy_unlock(lt);
-		if (t->tracking) {
-			ast_mark_lock_acquired(t);
-		}
-	} else if (t->tracking) {
+		ast_mark_lock_acquired(t);
+	} else if (lt) {
 		ast_mark_lock_failed(t);
 	}
 #endif /* DEBUG_THREADS */
@@ -1395,33 +1304,16 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast
 	int res;
 
 #ifdef DEBUG_THREADS
-	struct ast_lock_track *lt;
+	struct ast_lock_track *lt = NULL;
 #ifdef HAVE_BKTR
 	struct ast_bt *bt = NULL;
 #endif
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-	int canlog = strcmp(filename, "logger.c") & t->tracking;
-
-	if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-		 /* Don't warn abount uninitialized lock.
-		  * Simple try to initialize it.
-		  * May be not needed in linux system.
-		  */
-		res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
-		if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
-			__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
-					filename, line, func, name);
-			return res;
-		}
-	}
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-	if (t->tracking && !t->track) {
-		ast_reentrancy_init(&t->track);
+	if (t->tracking) {
+		lt = ast_get_reentrancy(&t->track);
 	}
-	lt = t->track;
 
-	if (t->tracking) {
+	if (lt) {
 #ifdef HAVE_BKTR
 		struct ast_bt tmp;
 
@@ -1431,7 +1323,7 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast
 		ast_bt_get_addresses(&tmp);
 
 		ast_reentrancy_lock(lt);
-		if (lt->reentrancy != AST_MAX_REENTRANCY) {
+		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
@@ -1447,7 +1339,7 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast
 	res = pthread_rwlock_trywrlock(&t->lock);
 
 #ifdef DEBUG_THREADS
-	if (!res && t->tracking) {
+	if (!res && lt) {
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy < AST_MAX_REENTRANCY) {
 			lt->file[lt->reentrancy] = filename;
@@ -1458,7 +1350,7 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast
 		}
 		ast_reentrancy_unlock(lt);
 		ast_mark_lock_acquired(t);
-	} else if (t->tracking) {
+	} else if (lt) {
 		ast_mark_lock_failed(t);
 	}
 #endif /* DEBUG_THREADS */
diff --git a/main/logger.c b/main/logger.c
index 31251ff..795c85d 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -25,30 +25,17 @@
  * \author Mark Spencer <markster at digium.com>
  */
 
-/*! \li \ref logger.c uses the configuration file \ref logger.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page logger.conf logger.conf
- * \verbinclude logger.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420899 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* When we include logger.h again it will trample on some stuff in syslog.h, but
  * nothing we care about in here. */
 #include <syslog.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_LOG_DIR */
@@ -68,7 +55,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420899 $")
 #include "asterisk/syslog.h"
 #include "asterisk/buildinfo.h"
 #include "asterisk/ast_version.h"
-#include "asterisk/backtrace.h"
+
+#include <signal.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_BKTR
+#include <execinfo.h>
+#define MAX_BACKTRACE_FRAMES 20
+#  if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
+#    include <dlfcn.h>
+#    include <bfd.h>
+#  endif
+#endif
 
 /*** DOCUMENTATION
  ***/
@@ -93,7 +92,6 @@ struct ast_callid {
 AST_THREADSTORAGE_CUSTOM(unique_callid, NULL, unique_callid_cleanup);
 
 static enum rotatestrategy {
-	NONE = 0,                /* Do not rotate log files at all, instead rely on external mechanisms */
 	SEQUENTIAL = 1 << 0,     /* Original method - create a new file, in order */
 	ROTATE = 1 << 1,         /* Rotate all files, such that the oldest file has the highest suffix */
 	TIMESTAMP = 1 << 2,      /* Append the epoch timestamp onto the end of the archived file */
@@ -103,10 +101,10 @@ static struct {
 	unsigned int queue_log:1;
 	unsigned int queue_log_to_file:1;
 	unsigned int queue_adaptive_realtime:1;
-	unsigned int queue_log_realtime_use_gmt:1;
 } logfiles = { 1 };
 
 static char hostname[MAXHOSTNAMELEN];
+AST_THREADSTORAGE_RAW(in_safe_log);
 
 enum logtypes {
 	LOGTYPE_SYSLOG,
@@ -133,8 +131,6 @@ struct logchannel {
 	AST_LIST_ENTRY(logchannel) list;
 	/*! Line number from configuration file */
 	int lineno;
-	/*! Whether this log channel was created dynamically */
-	int dynamic;
 	/*! Components (levels) from last config load */
 	char components[0];
 };
@@ -235,14 +231,11 @@ static const int colors[NUMLOGLEVELS] = {
 };
 
 AST_THREADSTORAGE(verbose_buf);
-AST_THREADSTORAGE(verbose_build_buf);
 #define VERBOSE_BUF_INIT_SIZE   256
 
 AST_THREADSTORAGE(log_buf);
 #define LOG_BUF_INIT_SIZE       256
 
-static void logger_queue_init(void);
-
 static void make_components(struct logchannel *chan)
 {
 	char *w;
@@ -287,7 +280,7 @@ static void make_components(struct logchannel *chan)
 	chan->logmask = logmask;
 }
 
-static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
+static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
 {
 	struct logchannel *chan;
 	char *facility;
@@ -300,7 +293,6 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
 
 	strcpy(chan->components, components);
 	chan->lineno = lineno;
-	chan->dynamic = dynamic;
 
 	if (!strcasecmp(channel, "console")) {
 		chan->type = LOGTYPE_CONSOLE;
@@ -324,7 +316,6 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
 
 		chan->type = LOGTYPE_SYSLOG;
 		ast_copy_string(chan->filename, channel, sizeof(chan->filename));
-		openlog("asterisk", LOG_PID, chan->facility);
 	} else {
 		const char *log_dir_prefix = "";
 		const char *log_dir_separator = "";
@@ -369,7 +360,14 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
 	return chan;
 }
 
-static void init_logger_chain(int locked, const char *altconf)
+/* \brief Read config, setup channels.
+ * \param locked The logchannels list is locked and this is a reload
+ * \param altconf Alternate configuration file to read.
+ *
+ * \retval 0 Success
+ * \retval -1 No config found or Failed
+ */
+static int init_logger_chain(int locked, const char *altconf)
 {
 	struct logchannel *chan;
 	struct ast_config *cfg;
@@ -377,16 +375,25 @@ static void init_logger_chain(int locked, const char *altconf)
 	const char *s;
 	struct ast_flags config_flags = { 0 };
 
-	display_callids = 1;
-
 	if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
-		return;
+		cfg = NULL;
 	}
 
-	/* delete our list of log channels */
 	if (!locked) {
 		AST_RWLIST_WRLOCK(&logchannels);
 	}
+
+	/* Set defaults */
+	hostname[0] = '\0';
+	display_callids = 1;
+	memset(&logfiles, 0, sizeof(logfiles));
+	logfiles.queue_log = 1;
+	ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
+	ast_copy_string(queue_log_name, QUEUELOG, sizeof(queue_log_name));
+	exec_after_rotate[0] = '\0';
+	rotatestrategy = SEQUENTIAL;
+
+	/* delete our list of log channels */
 	while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
 		ast_free(chan);
 	}
@@ -401,16 +408,13 @@ static void init_logger_chain(int locked, const char *altconf)
 
 	/* If no config file, we're fine, set default options. */
 	if (!cfg) {
-		if (errno) {
-			fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
-		} else {
-			fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
-		}
 		if (!(chan = ast_calloc(1, sizeof(*chan)))) {
-			return;
+			fprintf(stderr, "Failed to initialize default logging\n");
+			return -1;
 		}
 		chan->type = LOGTYPE_CONSOLE;
 		chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
+
 		if (!locked) {
 			AST_RWLIST_WRLOCK(&logchannels);
 		}
@@ -419,7 +423,8 @@ static void init_logger_chain(int locked, const char *altconf)
 		if (!locked) {
 			AST_RWLIST_UNLOCK(&logchannels);
 		}
-		return;
+
+		return -1;
 	}
 
 	if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
@@ -428,17 +433,14 @@ static void init_logger_chain(int locked, const char *altconf)
 				ast_copy_string(hostname, "unknown", sizeof(hostname));
 				fprintf(stderr, "What box has no hostname???\n");
 			}
-		} else
-			hostname[0] = '\0';
-	} else
-		hostname[0] = '\0';
+		}
+	}
 	if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
 		display_callids = ast_true(s);
 	}
-	if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
+	if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
 		ast_copy_string(dateformat, s, sizeof(dateformat));
-	else
-		ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
+	}
 	if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
 		logfiles.queue_log = ast_true(s);
 	}
@@ -448,9 +450,6 @@ static void init_logger_chain(int locked, const char *altconf)
 	if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
 		ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
 	}
-	if ((s = ast_variable_retrieve(cfg, "general", "queue_log_realtime_use_gmt"))) {
-		logfiles.queue_log_realtime_use_gmt = ast_true(s);
-	}
 	if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
 		ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
 	}
@@ -461,8 +460,6 @@ static void init_logger_chain(int locked, const char *altconf)
 			rotatestrategy = ROTATE;
 		} else if (strcasecmp(s, "sequential") == 0) {
 			rotatestrategy = SEQUENTIAL;
-		} else if (strcasecmp(s, "none") == 0) {
-			rotatestrategy = NONE;
 		} else {
 			fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
 		}
@@ -478,7 +475,7 @@ static void init_logger_chain(int locked, const char *altconf)
 	}
 	var = ast_variable_browse(cfg, "logfiles");
 	for (; var; var = var->next) {
-		if (!(chan = make_logchannel(var->name, var->value, var->lineno, 0))) {
+		if (!(chan = make_logchannel(var->name, var->value, var->lineno))) {
 			/* Print error message directly to the consoles since the lock is held
 			 * and we don't want to unlock with the list partially built */
 			ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
@@ -500,6 +497,8 @@ static void init_logger_chain(int locked, const char *altconf)
 	}
 
 	ast_config_destroy(cfg);
+
+	return 0;
 }
 
 void ast_child_verbose(int level, const char *fmt, ...)
@@ -560,25 +559,13 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent,
 		return;
 	}
 	if (!queuelog_init) {
-		AST_RWLIST_WRLOCK(&logchannels);
-		if (!queuelog_init) {
-			/*
-			 * We have delayed initializing the queue logging system so
-			 * preloaded realtime modules can get up.  We must initialize
-			 * now since someone is trying to log something.
-			 */
-			logger_queue_init();
-			queuelog_init = 1;
-			AST_RWLIST_UNLOCK(&logchannels);
-			ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
-		} else {
-			AST_RWLIST_UNLOCK(&logchannels);
-		}
+		/* We must initialize now since someone is trying to log something. */
+		logger_queue_start();
 	}
 
 	if (ast_check_realtime("queue_log")) {
 		tv = ast_tvnow();
-		ast_localtime(&tv, &tm, logfiles.queue_log_realtime_use_gmt ? "GMT" : NULL);
+		ast_localtime(&tv, &tm, NULL);
 		ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
 		va_start(ap, fmt);
 		vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
@@ -646,9 +633,6 @@ static int rotate_file(const char *filename)
 	char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
 
 	switch (rotatestrategy) {
-	case NONE:
-		/* No rotation */
-		break;
 	case SEQUENTIAL:
 		for (x = 0; ; x++) {
 			snprintf(new, sizeof(new), "%s.%d", filename, x);
@@ -849,7 +833,7 @@ static int reload_logger(int rotate, const char *altconf)
 		}
 		if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
 			int rotate_this = 0;
-			if (rotatestrategy != NONE && ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
+			if (ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
 				/* Be more proactive about rotating massive log files */
 				rotate_this = 1;
 			}
@@ -928,11 +912,6 @@ static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_c
 	return CLI_SUCCESS;
 }
 
-int ast_logger_rotate()
-{
-	return reload_logger(1, NULL);
-}
-
 static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int x;
@@ -1014,117 +993,6 @@ static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struc
 	return CLI_SUCCESS;
 }
 
-static char *handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct logchannel *chan;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "logger add channel";
-		e->usage =
-			"Usage: logger add channel <name> <levels>\n"
-			"       Adds a temporary logger channel. This logger channel\n"
-			"       will exist until removed or until Asterisk is restarted.\n"
-			"       <levels> is a comma-separated list of desired logger\n"
-			"       levels such as: verbose,warning,error\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc < 5) {
-		return CLI_SHOWUSAGE;
-	}
-
-	AST_RWLIST_WRLOCK(&logchannels);
-	AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
-		if (!strcmp(chan->filename, a->argv[3])) {
-			break;
-		}
-	}
-
-	if (chan) {
-		AST_RWLIST_UNLOCK(&logchannels);
-		ast_cli(a->fd, "Logger channel '%s' already exists\n", a->argv[3]);
-		return CLI_SUCCESS;
-	}
-
-	chan = make_logchannel(a->argv[3], a->argv[4], 0, 1);
-	if (chan) {
-		AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
-		global_logmask |= chan->logmask;
-		AST_RWLIST_UNLOCK(&logchannels);
-		return CLI_SUCCESS;
-	}
-
-	AST_RWLIST_UNLOCK(&logchannels);
-	ast_cli(a->fd, "ERROR: Unable to create log channel '%s'\n", a->argv[3]);
-
-	return CLI_FAILURE;
-}
-
-static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct logchannel *chan;
-	int gen_count = 0;
-	char *gen_ret = NULL;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "logger remove channel";
-		e->usage =
-			"Usage: logger remove channel <name>\n"
-			"       Removes a temporary logger channel.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->argc > 4 || (a->argc == 4 && a->pos > 3)) {
-			return NULL;
-		}
-		AST_RWLIST_RDLOCK(&logchannels);
-		AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
-			if (chan->dynamic && (ast_strlen_zero(a->argv[3])
-				|| !strncmp(a->argv[3], chan->filename, strlen(a->argv[3])))) {
-				if (gen_count == a->n) {
-					gen_ret = ast_strdup(chan->filename);
-					break;
-				}
-				gen_count++;
-			}
-		}
-		AST_RWLIST_UNLOCK(&logchannels);
-		return gen_ret;
-	}
-
-	if (a->argc < 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	AST_RWLIST_WRLOCK(&logchannels);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&logchannels, chan, list) {
-		if (chan->dynamic && !strcmp(chan->filename, a->argv[3])) {
-			AST_RWLIST_REMOVE_CURRENT(list);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-	AST_RWLIST_UNLOCK(&logchannels);
-
-	if (!chan) {
-		ast_cli(a->fd, "Unable to find dynamic logger channel '%s'\n", a->argv[3]);
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, "Removed dynamic logger channel '%s'\n", chan->filename);
-	if (chan->fileptr) {
-		fclose(chan->fileptr);
-		chan->fileptr = NULL;
-	}
-	ast_free(chan);
-	chan = NULL;
-
-	return CLI_SUCCESS;
-}
-
 struct verb {
 	void (*verboser)(const char *string);
 	AST_LIST_ENTRY(verb) list;
@@ -1137,8 +1005,6 @@ static struct ast_cli_entry cli_logger[] = {
 	AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
 	AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
 	AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
-	AST_CLI_DEFINE(handle_logger_add_channel, "Adds a new logging channel"),
-	AST_CLI_DEFINE(handle_logger_remove_channel, "Removes a logging channel"),
 };
 
 static void _handle_SIGXFSZ(int sig)
@@ -1152,7 +1018,7 @@ static struct sigaction handle_SIGXFSZ = {
 	.sa_flags = SA_RESTART,
 };
 
-static void ast_log_vsyslog(struct logmsg *msg)
+static void ast_log_vsyslog(struct logmsg *msg, int facility)
 {
 	char buf[BUFSIZ];
 	int syslog_level = ast_syslog_priority_from_loglevel(msg->level);
@@ -1170,6 +1036,8 @@ static void ast_log_vsyslog(struct logmsg *msg)
 		return;
 	}
 
+	syslog_level = LOG_MAKEPRI(facility, syslog_level);
+
 	snprintf(buf, sizeof(buf), "%s[%d]%s: %s:%d in %s: %s",
 		 levels[msg->level], msg->lwp, call_identifier_str, msg->file, msg->line, msg->function, msg->message);
 
@@ -1255,10 +1123,11 @@ static void logger_print_normal(struct logmsg *logmsg)
 
 			/* Check syslog channels */
 			if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) {
-				ast_log_vsyslog(logmsg);
+				ast_log_vsyslog(logmsg, chan->facility);
 			/* Console channels */
 			} else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) {
 				char linestr[128];
+				char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
 
 				/* If the level is verbose, then skip it */
 				if (logmsg->level == __LOG_VERBOSE)
@@ -1267,14 +1136,14 @@ static void logger_print_normal(struct logmsg *logmsg)
 				/* Turn the numerical line number into a string */
 				snprintf(linestr, sizeof(linestr), "%d", logmsg->line);
 				/* Build string to print out */
-				snprintf(buf, sizeof(buf), "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT ":" COLORIZE_FMT " " COLORIZE_FMT ": %s",
+				snprintf(buf, sizeof(buf), "[%s] %s[%d]%s: %s:%s %s: %s",
 					 logmsg->date,
-					 COLORIZE(colors[logmsg->level], 0, logmsg->level_name),
+					 term_color(tmp1, logmsg->level_name, colors[logmsg->level], 0, sizeof(tmp1)),
 					 logmsg->lwp,
 					 call_identifier_str,
-					 COLORIZE(COLOR_BRWHITE, 0, logmsg->file),
-					 COLORIZE(COLOR_BRWHITE, 0, linestr),
-					 COLORIZE(COLOR_BRWHITE, 0, logmsg->function),
+					 term_color(tmp2, logmsg->file, COLOR_BRWHITE, 0, sizeof(tmp2)),
+					 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
+					 term_color(tmp4, logmsg->function, COLOR_BRWHITE, 0, sizeof(tmp4)),
 					 logmsg->message);
 				/* Print out */
 				ast_console_puts_mutable(buf, logmsg->level);
@@ -1397,8 +1266,33 @@ static void logger_queue_init(void)
 	}
 }
 
+/*!
+ * \brief Start the ast_queue_log() logger.
+ *
+ * \note Called when the system is fully booted after startup
+ * so preloaded realtime modules can get up.
+ *
+ * \return Nothing
+ */
+void logger_queue_start(void)
+{
+	/* Must not be called before the logger is initialized. */
+	ast_assert(logger_initialized);
+
+	AST_RWLIST_WRLOCK(&logchannels);
+	if (!queuelog_init) {
+		logger_queue_init();
+		queuelog_init = 1;
+		AST_RWLIST_UNLOCK(&logchannels);
+		ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
+	} else {
+		AST_RWLIST_UNLOCK(&logchannels);
+	}
+}
+
 int init_logger(void)
 {
+	int res;
 	/* auto rotate if sig SIGXFSZ comes a-knockin */
 	sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
 
@@ -1424,9 +1318,12 @@ int init_logger(void)
 	ast_mkdir(ast_config_AST_LOG_DIR, 0777);
 
 	/* create log channels */
-	init_logger_chain(0 /* locked */, NULL);
+	res = init_logger_chain(0 /* locked */, NULL);
 	ast_verb_update();
 	logger_initialized = 1;
+	if (res) {
+		ast_log(LOG_ERROR, "Errors detected in logger.conf.  Default console logging is being used.\n");
+	}
 
 	return 0;
 }
@@ -1580,7 +1477,7 @@ int ast_callid_threadassoc_remove(void)
 		return -1;
 	} else {
 #ifdef TEST_FRAMEWORK
-		ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", (unsigned)(*pointing)->call_identifier);
+		ast_debug(3, "Call_ID [C-%08x] being removed from thread.\n", (unsigned)(*pointing)->call_identifier);
 #endif
 		*pointing = ast_callid_unref(*pointing);
 		return 0;
@@ -1745,6 +1642,36 @@ void ast_log(int level, const char *file, int line, const char *function, const
 	}
 }
 
+void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	va_list ap;
+	void *recursed = ast_threadstorage_get_ptr(&in_safe_log);
+	struct ast_callid *callid;
+
+	if (recursed) {
+		return;
+	}
+
+	if (ast_threadstorage_set_ptr(&in_safe_log, (void*)1)) {
+		/* We've failed to set the flag that protects against
+		 * recursion, so bail. */
+		return;
+	}
+
+	callid = ast_read_threadstorage_callid();
+
+	va_start(ap, fmt);
+	ast_log_full(level, file, line, function, callid, fmt, ap);
+	va_end(ap);
+
+	if (callid) {
+		ast_callid_unref(callid);
+	}
+
+	/* Clear flag so the next allocation failure can be logged. */
+	ast_threadstorage_set_ptr(&in_safe_log, NULL);
+}
+
 void ast_log_callid(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, ...)
 {
 	va_list ap;
@@ -1753,8 +1680,197 @@ void ast_log_callid(int level, const char *file, int line, const char *function,
 	va_end(ap);
 }
 
+#ifdef HAVE_BKTR
+
+struct ast_bt *ast_bt_create(void)
+{
+	struct ast_bt *bt = ast_calloc(1, sizeof(*bt));
+	if (!bt) {
+		ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n");
+		return NULL;
+	}
+
+	bt->alloced = 1;
+
+	ast_bt_get_addresses(bt);
+
+	return bt;
+}
+
+int ast_bt_get_addresses(struct ast_bt *bt)
+{
+	bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
+
+	return 0;
+}
 
-void ast_log_backtrace(void)
+void *ast_bt_destroy(struct ast_bt *bt)
+{
+	if (bt->alloced) {
+		ast_free(bt);
+	}
+
+	return NULL;
+}
+
+char **ast_bt_get_symbols(void **addresses, size_t num_frames)
+{
+	char **strings;
+#if defined(BETTER_BACKTRACES)
+	int stackfr;
+	bfd *bfdobj;           /* bfd.h */
+	Dl_info dli;           /* dlfcn.h */
+	long allocsize;
+	asymbol **syms = NULL; /* bfd.h */
+	bfd_vma offset;        /* bfd.h */
+	const char *lastslash;
+	asection *section;
+	const char *file, *func;
+	unsigned int line;
+	char address_str[128];
+	char msg[1024];
+	size_t strings_size;
+	size_t *eachlen;
+#endif
+
+#if defined(BETTER_BACKTRACES)
+	strings_size = num_frames * sizeof(*strings);
+
+	eachlen = ast_calloc(num_frames, sizeof(*eachlen));
+	strings = ast_std_calloc(num_frames, sizeof(*strings));
+	if (!eachlen || !strings) {
+		ast_free(eachlen);
+		ast_std_free(strings);
+		return NULL;
+	}
+
+	for (stackfr = 0; stackfr < num_frames; stackfr++) {
+		int found = 0, symbolcount;
+
+		msg[0] = '\0';
+
+		if (!dladdr(addresses[stackfr], &dli)) {
+			continue;
+		}
+
+		if (strcmp(dli.dli_fname, "asterisk") == 0) {
+			char asteriskpath[256];
+
+			if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
+				/* This will fail to find symbols */
+				ast_debug(1, "Failed to find asterisk binary for debug symbols.\n");
+				dli.dli_fname = "asterisk";
+			}
+		}
+
+		lastslash = strrchr(dli.dli_fname, '/');
+		if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
+			bfd_check_format(bfdobj, bfd_object) &&
+			(allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
+			(syms = ast_malloc(allocsize)) &&
+			(symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
+
+			if (bfdobj->flags & DYNAMIC) {
+				offset = addresses[stackfr] - dli.dli_fbase;
+			} else {
+				offset = addresses[stackfr] - (void *) 0;
+			}
+
+			for (section = bfdobj->sections; section; section = section->next) {
+				if (!bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
+					section->vma > offset ||
+					section->size + section->vma < offset) {
+					continue;
+				}
+
+				if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
+					continue;
+				}
+
+				/* file can possibly be null even with a success result from bfd_find_nearest_line */
+				file = file ? file : "";
+
+				/* Stack trace output */
+				found++;
+				if ((lastslash = strrchr(file, '/'))) {
+					const char *prevslash;
+
+					for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) {
+					}
+					if (prevslash >= file) {
+						lastslash = prevslash;
+					}
+				}
+				if (dli.dli_saddr == NULL) {
+					address_str[0] = '\0';
+				} else {
+					snprintf(address_str, sizeof(address_str), " (%p+%lX)",
+						dli.dli_saddr,
+						(unsigned long) (addresses[stackfr] - dli.dli_saddr));
+				}
+				snprintf(msg, sizeof(msg), "%s:%u %s()%s",
+					lastslash ? lastslash + 1 : file, line,
+					S_OR(func, "???"),
+					address_str);
+
+				break; /* out of section iteration */
+			}
+		}
+		if (bfdobj) {
+			bfd_close(bfdobj);
+			ast_free(syms);
+		}
+
+		/* Default output, if we cannot find the information within BFD */
+		if (!found) {
+			if (dli.dli_saddr == NULL) {
+				address_str[0] = '\0';
+			} else {
+				snprintf(address_str, sizeof(address_str), " (%p+%lX)",
+					dli.dli_saddr,
+					(unsigned long) (addresses[stackfr] - dli.dli_saddr));
+			}
+			snprintf(msg, sizeof(msg), "%s %s()%s",
+				lastslash ? lastslash + 1 : dli.dli_fname,
+				S_OR(dli.dli_sname, "<unknown>"),
+				address_str);
+		}
+
+		if (!ast_strlen_zero(msg)) {
+			char **tmp;
+
+			eachlen[stackfr] = strlen(msg) + 1;
+			if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) {
+				ast_std_free(strings);
+				strings = NULL;
+				break; /* out of stack frame iteration */
+			}
+			strings = tmp;
+			strings[stackfr] = (char *) strings + strings_size;
+			strcpy(strings[stackfr], msg);/* Safe since we just allocated the room. */
+			strings_size += eachlen[stackfr];
+		}
+	}
+
+	if (strings) {
+		/* Recalculate the offset pointers because of the reallocs. */
+		strings[0] = (char *) strings + num_frames * sizeof(*strings);
+		for (stackfr = 1; stackfr < num_frames; stackfr++) {
+			strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1];
+		}
+	}
+	ast_free(eachlen);
+
+#else /* !defined(BETTER_BACKTRACES) */
+
+	strings = backtrace_symbols(addresses, num_frames);
+#endif /* defined(BETTER_BACKTRACES) */
+	return strings;
+}
+
+#endif /* HAVE_BKTR */
+
+void ast_backtrace(void)
 {
 #ifdef HAVE_BKTR
 	struct ast_bt *bt;
@@ -1767,14 +1883,14 @@ void ast_log_backtrace(void)
 	}
 
 	if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
-		ast_verbose("Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
+		ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
 		for (i = 3; i < bt->num_frames - 2; i++) {
-			ast_verbose("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
+			ast_debug(1, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
 		}
 
 		ast_std_free(strings);
 	} else {
-		ast_verbose("Could not allocate memory for backtrace\n");
+		ast_debug(1, "Could not allocate memory for backtrace\n");
 	}
 	ast_bt_destroy(bt);
 #else
@@ -1785,8 +1901,9 @@ void ast_log_backtrace(void)
 void __ast_verbose_ap(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, va_list ap)
 {
 	const char *p;
-	struct ast_str *prefixed, *buf;
+	struct ast_str *prefixed, *buf = NULL;
 	int res = 0;
+	const char *prefix = level >= 4 ? VERBOSE_PREFIX_4 : level == 3 ? VERBOSE_PREFIX_3 : level == 2 ? VERBOSE_PREFIX_2 : level == 1 ? VERBOSE_PREFIX_1 : "";
 	signed char magic = level > 9 ? -10 : -level - 1; /* 0 => -1, 1 => -2, etc.  Can't pass NUL, as it is EOS-delimiter */
 
 	/* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */
@@ -1805,18 +1922,18 @@ void __ast_verbose_ap(const char *file, int line, const char *func, int level, s
 	}
 
 	if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)) ||
-	    !(buf = ast_str_thread_get(&verbose_build_buf, VERBOSE_BUF_INIT_SIZE))) {
+	    !(buf = ast_str_create(VERBOSE_BUF_INIT_SIZE))) {
 		return;
 	}
 
 	res = ast_str_set_va(&buf, 0, fmt, ap);
 	/* If the build failed then we can drop this allocated message */
 	if (res == AST_DYNSTR_BUILD_FAILED) {
+		ast_free(buf);
 		return;
 	}
 
 	ast_str_reset(prefixed);
-
 	/* for every newline found in the buffer add verbose prefix data */
 	fmt = ast_str_buffer(buf);
 	do {
@@ -1825,12 +1942,22 @@ void __ast_verbose_ap(const char *file, int line, const char *func, int level, s
 		}
 		++p;
 
-		ast_str_append(&prefixed, 0, "%c", (char)magic);
+		if (ast_opt_timestamp) {
+			struct ast_tm tm;
+			char date[40];
+			struct timeval now = ast_tvnow();
+			ast_localtime(&now, &tm, NULL);
+			ast_strftime(date, sizeof(date), dateformat, &tm);
+			ast_str_append(&prefixed, 0, "%c[%s] %s", (char) magic, date, prefix);
+		} else {
+			ast_str_append(&prefixed, 0, "%c%s", (char) magic, prefix);
+		}
 		ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
 		fmt = p;
 	} while (p && *p);
 
 	ast_log_callid(__LOG_VERBOSE, file, line, func, callid, "%s", ast_str_buffer(prefixed));
+	ast_free(buf);
 }
 
 void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
@@ -2149,9 +2276,3 @@ void ast_logger_unregister_level(const char *name)
 		AST_RWLIST_UNLOCK(&logchannels);
 	}
 }
-
-const char *ast_logger_get_dateformat(void)
-{
-	return dateformat;
-}
-
diff --git a/main/manager.c b/main/manager.c
index c6eb56a..d5e3273 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -22,7 +22,7 @@
  *
  * \author Mark Spencer <markster at digium.com>
  *
- * OpenSSL http://www.openssl.org - for AMI/SSL
+ * \extref OpenSSL http://www.openssl.org - for AMI/SSL
  *
  * At the moment this file contains a number of functions, namely:
  *
@@ -36,17 +36,10 @@
  * \ref amiconf
  */
 
-/*! \li \ref manager.c uses the configuration file \ref manager.conf and \ref users.conf
- * \addtogroup configuration_file
- */
-
-/*! \page manager.conf manager.conf
- * \verbinclude manager.conf.sample
- */
-
-/*! \page users.conf users.conf
- * \verbinclude users.conf.sample
- */
+/*! \addtogroup Group_AMI AMI functions
+*/
+/*! @{
+ Doxygen group */
 
 /*** MODULEINFO
 	<support_level>core</support_level>
@@ -54,7 +47,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use various ast_config_AST_* */
@@ -87,20 +80,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 #include "asterisk/astobj2.h"
 #include "asterisk/features.h"
 #include "asterisk/security_events.h"
+#include "asterisk/event.h"
 #include "asterisk/aoc.h"
-#include "asterisk/strings.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/presencestate.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/test.h"
-#include "asterisk/json.h"
-#include "asterisk/bridge.h"
-#include "asterisk/features_config.h"
-#include "asterisk/rtp_engine.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/translate.h"
 
 /*** DOCUMENTATION
 	<manager name="Ping" language="en_US">
@@ -222,82 +205,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<para>Will return the status information of each channel along with the
 			value for the specified channel variables.</para>
 		</description>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
-			</list-elements>
-			<xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
-		</responses>
 	</manager>
-	<managerEvent language="en_US" name="Status">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised in response to a Status command.</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<channel_snapshot/>
-				<parameter name="Type">
-					<para>Type of channel</para>
-				</parameter>
-				<parameter name="DNID">
-					<para>Dialed number identifier</para>
-				</parameter>
-				<parameter name="TimeToHangup">
-					<para>Absolute lifetime of the channel</para>
-				</parameter>
-				<parameter name="BridgeID">
-					<para>Identifier of the bridge the channel is in, may be empty if not in one</para>
-				</parameter>
-				<parameter name="Linkedid">
-				</parameter>
-				<parameter name="Application">
-					<para>Application currently executing on the channel</para>
-				</parameter>
-				<parameter name="Data">
-					<para>Data given to the currently executing channel</para>
-				</parameter>
-				<parameter name="Nativeformats">
-					<para>Media formats the connected party is willing to send or receive</para>
-				</parameter>
-				<parameter name="Readformat">
-					<para>Media formats that frames from the channel are received in</para>
-				</parameter>
-				<parameter name="Readtrans">
-					<para>Translation path for media received in native formats</para>
-				</parameter>
-				<parameter name="Writeformat">
-					<para>Media formats that frames to the channel are accepted in</para>
-				</parameter>
-				<parameter name="Writetrans">
-					<para>Translation path for media sent to the connected party</para>
-				</parameter>
-				<parameter name="Callgroup">
-					<para>Configured call group on the channel</para>
-				</parameter>
-				<parameter name="Pickupgroup">
-					<para>Configured pickup group on the channel</para>
-				</parameter>
-				<parameter name="Seconds">
-					<para>Number of seconds the channel has been active</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">Status</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="StatusComplete">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised in response to a Status command.</synopsis>
-			<syntax>
-				<parameter name="Items">
-					<para>Number of Status events returned</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">Status</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
 	<manager name="Setvar" language="en_US">
 		<synopsis>
 			Sets a channel variable or function value.
@@ -354,24 +262,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<parameter name="Category">
 				<para>Category in configuration file.</para>
 			</parameter>
-			<parameter name="Filter">
-				<para>A comma separated list of
-				<replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
-				expressions which will cause only categories whose variables match all expressions
-				to be considered.  The special variable name <literal>TEMPLATES</literal>
-				can be used to control whether templates are included.  Passing
-				<literal>include</literal> as the value will include templates
-				along with normal categories. Passing
-				<literal>restrict</literal> as the value will restrict the operation to
-				ONLY templates.  Not specifying a <literal>TEMPLATES</literal> expression
-				results in the default behavior which is to not include templates.</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>This action will dump the contents of a configuration
-			file by category and contents or optionally by specified category only.
-			In the case where a category name is non-unique, a filter may be specified
-			to match only categories with matching variable values.</para>
+			file by category and contents or optionally by specified category only.</para>
 		</description>
 	</manager>
 	<manager name="GetConfigJSON" language="en_US">
@@ -383,19 +277,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<parameter name="Filename" required="true">
 				<para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
 			</parameter>
-			<parameter name="Category">
-				<para>Category in configuration file.</para>
-			</parameter>
-			<parameter name="Filter">
-				<xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
-			</parameter>
 		</syntax>
 		<description>
 			<para>This action will dump the contents of a configuration file by category
-			and contents in JSON format or optionally by specified category only.
-			This only makes sense to be used using rawman over the HTTP interface.
-			In the case where a category name is non-unique, a filter may be specified
-			to match only categories with matching variable values.</para>
+			and contents in JSON format. This only makes sense to be used using rawman over
+			the HTTP interface.</para>
 		</description>
 	</manager>
 	<manager name="UpdateConfig" language="en_US">
@@ -413,9 +299,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<parameter name="Reload">
 				<para>Whether or not a reload should take place (or name of specific module).</para>
 			</parameter>
-			<parameter name="Action-000000">
+			<parameter name="Action-XXXXXX">
 				<para>Action to take.</para>
-				<para>0's represent 6 digit number beginning with 000000.</para>
+				<para>X's represent 6 digit number beginning with 000000.</para>
 				<enumlist>
 					<enum name="NewCat" />
 					<enum name="RenameCat" />
@@ -427,58 +313,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 					<enum name="Insert" />
 				</enumlist>
 			</parameter>
-			<parameter name="Cat-000000">
+			<parameter name="Cat-XXXXXX">
 				<para>Category to operate on.</para>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
+				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
 			</parameter>
-			<parameter name="Var-000000">
+			<parameter name="Var-XXXXXX">
 				<para>Variable to work on.</para>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
+				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
 			</parameter>
-			<parameter name="Value-000000">
+			<parameter name="Value-XXXXXX">
 				<para>Value to work on.</para>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
+				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
 			</parameter>
-			<parameter name="Match-000000">
+			<parameter name="Match-XXXXXX">
 				<para>Extra match required to match line.</para>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
+				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
 			</parameter>
-			<parameter name="Line-000000">
+			<parameter name="Line-XXXXXX">
 				<para>Line in category to operate on (used with delete and insert actions).</para>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
-			</parameter>
-			<parameter name="Options-000000">
-				<para>A comma separated list of action-specific options.</para>
-					<enumlist>
-						<enum name="NewCat"><para>One or more of the following... </para>
-							<enumlist>
-								<enum name="allowdups"><para>Allow duplicate category names.</para></enum>
-								<enum name="template"><para>This category is a template.</para></enum>
-								<enum name="inherit="template[,...]""><para>Templates from which to inherit.</para></enum>
-							</enumlist>
-						</enum>
-					</enumlist>
-					<para> </para>
-						<para>The following actions share the same options...</para>
-					<enumlist>
-						<enum name="RenameCat"/>
-						<enum name="DelCat"/>
-						<enum name="EmptyCat"/>
-						<enum name="Update"/>
-						<enum name="Delete"/>
-						<enum name="Append"/>
-						<enum name="Insert"><para> </para>
-							<enumlist>
-								<enum name="catfilter="<expression>[,...]""><para> </para>
-									<xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
-									<para><literal>catfilter</literal> is most useful when a file
-									contains multiple categories with the same name and you wish to
-									operate on specific ones instead of all of them.</para>
-								</enum>
-							</enumlist>
-						</enum>
-					</enumlist>
-				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
+				<xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
 			</parameter>
 		</syntax>
 		<description>
@@ -563,9 +416,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<parameter name="Exten" required="true">
 				<para>Extension to transfer to.</para>
 			</parameter>
-			<parameter name="Context">
+			<parameter name="Context" required="true">
 				<para>Context to transfer to.</para>
 			</parameter>
+			<parameter name="Priority" required="true">
+				<para>Priority to transfer to.</para>
+			</parameter>
 		</syntax>
 		<description>
 			<para>Attended transfer.</para>
@@ -619,12 +475,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<parameter name="Codecs">
 				<para>Comma-separated list of codecs to use for this call.</para>
 			</parameter>
-			<parameter name="ChannelId">
-				<para>Channel UniqueId to be set on the channel.</para>
-			</parameter>
-			<parameter name="OtherChannelId">
-				<para>Channel UniqueId to be set on the second local channel.</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>Generates an outgoing call to a
@@ -867,49 +717,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 			<para>Send a reload event.</para>
 		</description>
 	</manager>
-	<managerEvent language="en_US" name="CoreShowChannel">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised in response to a CoreShowChannels command.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-				<channel_snapshot/>
-				<parameter name="BridgeId">
-					<para>Identifier of the bridge the channel is in, may be empty if not in one</para>
-				</parameter>
-				<parameter name="Application">
-					<para>Application currently executing on the channel</para>
-				</parameter>
-				<parameter name="ApplicationData">
-					<para>Data given to the currently executing application</para>
-				</parameter>
-				<parameter name="Duration">
-					<para>The amount of time the channel has existed</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">CoreShowChannels</ref>
-				<ref type="managerEvent">CoreShowChannelsComplete</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="CoreShowChannelsComplete">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-				<parameter name="EventList">
-					<para>Conveys the status of the command reponse list</para>
-				</parameter>
-				<parameter name="ListItems">
-					<para>The total number of list items produced</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">CoreShowChannels</ref>
-				<ref type="managerEvent">CoreShowChannel</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
 	<manager name="CoreShowChannels" language="en_US">
 		<synopsis>
 			List currently active channels.
@@ -920,23 +727,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
 		<description>
 			<para>List currently defined channels and some information about them.</para>
 		</description>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
-			</list-elements>
-			<xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
-		</responses>
-	</manager>
-	<manager name="LoggerRotate" language="en_US">
-		<synopsis>
-			Reload and rotate the Asterisk logger.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
-		</description>
 	</manager>
 	<manager name="ModuleLoad" language="en_US">
 		<synopsis>
@@ -1168,122 +958,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428946 $")
                         manager.conf will be present upon starting a new session.</para>
 		</description>
 	</manager>
-	<manager name="BlindTransfer" language="en_US">
-		<synopsis>
-			Blind transfer channel(s) to the given destination
-		</synopsis>
-		<syntax>
-			<parameter name="Channel" required="true">
-			</parameter>
-			<parameter name="Context">
-			</parameter>
-			<parameter name="Exten">
-			</parameter>
-		</syntax>
-		<description>
-			<para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
-		</description>
-		<see-also>
-			<ref type="manager">Redirect</ref>
-		</see-also>
-	</manager>
-	<managerEvent name="ExtensionStatus" language="en_US">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a hint changes due to a device state change.</synopsis>
-			<syntax>
-				<parameter name="Exten">
-					<para>Name of the extension.</para>
-				</parameter>
-				<parameter name="Context">
-					<para>Context that owns the extension.</para>
-				</parameter>
-				<parameter name="Hint">
-					<para>Hint set for the extension</para>
-				</parameter>
-				<parameter name="Status">
-					<para>Numerical value of the extension status. Extension
-					status is determined by the combined device state of all items
-					contained in the hint.</para>
-					<enumlist>
-						<enum name="-2">
-							<para>The extension was removed from the dialplan.</para>
-						</enum>
-						<enum name="-1">
-							<para>The extension's hint was removed from the dialplan.</para>
-						</enum>
-						<enum name="0">
-							<para><literal>Idle</literal> - Related device(s) are in an idle
-							state.</para>
-						</enum>
-						<enum name="1">
-							<para><literal>InUse</literal> - Related device(s) are in active
-							calls but may take more calls.</para>
-						</enum>
-						<enum name="2">
-							<para><literal>Busy</literal> - Related device(s) are in active
-							calls and may not take any more calls.</para>
-						</enum>
-						<enum name="4">
-							<para><literal>Unavailable</literal> - Related device(s) are
-							not reachable.</para>
-						</enum>
-						<enum name="8">
-							<para><literal>Ringing</literal> - Related device(s) are
-							currently ringing.</para>
-						</enum>
-						<enum name="9">
-							<para><literal>InUse&Ringing</literal> - Related device(s)
-							are currently ringing and in active calls.</para>
-						</enum>
-						<enum name="16">
-							<para><literal>Hold</literal> - Related device(s) are
-							currently on hold.</para>
-						</enum>
-						<enum name="17">
-							<para><literal>InUse&Hold</literal> - Related device(s)
-							are currently on hold and in active calls.</para>
-						</enum>
-					</enumlist>
-				</parameter>
-				<parameter name="StatusText">
-					<para>Text representation of <literal>Status</literal>.</para>
-					<enumlist>
-						<enum name="Idle" />
-						<enum name="InUse" />
-						<enum name="Busy" />
-						<enum name="Unavailable" />
-						<enum name="Ringing" />
-						<enum name="InUse&Ringing" />
-						<enum name="Hold" />
-						<enum name="InUse&Hold" />
-						<enum name="Unknown">
-							<para>Status does not match any of the above values.</para>
-						</enum>
-					</enumlist>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent name="PresenceStatus" language="en_US">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a hint changes due to a presence state change.</synopsis>
-			<syntax>
-				<parameter name="Exten" />
-				<parameter name="Context" />
-				<parameter name="Hint" />
-				<parameter name="Status" />
-				<parameter name="Subtype" />
-				<parameter name="Message" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
-/*! \addtogroup Group_AMI AMI functions
-*/
-/*! @{
- Doxygen group */
-
 enum error_type {
 	UNKNOWN_ACTION = 1,
 	UNKNOWN_CATEGORY,
@@ -1295,8 +971,7 @@ enum error_type {
 	FAILURE_EMPTYCAT,
 	FAILURE_UPDATE,
 	FAILURE_DELETE,
-	FAILURE_APPEND,
-	FAILURE_TEMPLATE
+	FAILURE_APPEND
 };
 
 enum add_filter_result {
@@ -1341,7 +1016,6 @@ static int timestampevents;
 static int httptimeout = 60;
 static int broken_events_action = 0;
 static int manager_enabled = 0;
-static int subscribed = 0;
 static int webmanager_enabled = 0;
 static int manager_debug = 0;	/*!< enable some debugging code in the manager */
 static int authtimeout;
@@ -1352,28 +1026,7 @@ static char *manager_channelvars;
 static char global_realm[MAXHOSTNAMELEN];	/*!< Default realm */
 
 static int unauth_sessions = 0;
-static struct stasis_subscription *acl_change_sub;
-
-/*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
-static struct stasis_topic *manager_topic;
-
-/*! \brief The \ref stasis_message_router for all \ref stasis messages */
-static struct stasis_message_router *stasis_router;
-
-/*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
-static struct stasis_forward *rtp_topic_forwarder;
-
-/*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
-static struct stasis_forward *security_topic_forwarder;
-
-#ifdef TEST_FRAMEWORK
-/*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
-static struct stasis_forward *test_suite_forwarder;
-#endif
-
-#define MGR_SHOW_TERMINAL_WIDTH 80
-
-#define MAX_VARS 128
+static struct ast_event_sub *acl_change_event_subscription;
 
 /*! \brief Fake event class used to end sessions at shutdown */
 #define EVENT_FLAG_SHUTDOWN -1
@@ -1397,19 +1050,21 @@ static const struct {
 	{{ "restart", "gracefully", NULL }},
 };
 
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
+static void acl_change_event_cb(const struct ast_event *event, void *userdata);
 
-static void acl_change_stasis_subscribe(void)
+static void acl_change_event_subscribe(void)
 {
-	if (!acl_change_sub) {
-		acl_change_sub = stasis_subscribe(ast_security_topic(),
-			acl_change_stasis_cb, NULL);
+	if (!acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_subscribe(AST_EVENT_ACL_CHANGE,
+			acl_change_event_cb, "Manager must react to Named ACL changes", NULL, AST_EVENT_IE_END);
 	}
 }
 
-static void acl_change_stasis_unsubscribe(void)
+static void acl_change_event_unsubscribe(void)
 {
-	acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
+	if (acl_change_event_subscription) {
+		acl_change_event_subscription = ast_event_unsubscribe(acl_change_event_subscription);
+	}
 }
 
 /* In order to understand what the heck is going on with the
@@ -1461,7 +1116,7 @@ struct mansession_session {
 	int authenticated;	/*!< Authentication status */
 	int readperm;		/*!< Authorization for reading */
 	int writeperm;		/*!< Authorization for writing */
-	char inbuf[1025];	/*!< Buffer -  we use the extra byte to add a '\\0' and simplify parsing */
+	char inbuf[1025];	/*!< Buffer -  we use the extra byte to add a '\0' and simplify parsing */
 	int inlen;		/*!< number of buffered bytes */
 	struct ao2_container *whitefilters;	/*!< Manager event filters - white list */
 	struct ao2_container *blackfilters;	/*!< Manager event filters - black list */
@@ -1502,6 +1157,14 @@ struct mansession {
 /*! Active manager connection sessions container. */
 static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
 
+struct manager_channel_variable {
+	AST_LIST_ENTRY(manager_channel_variable) entry;
+	unsigned int isfunc:1;
+	char name[0]; /* allocate off the end the real size. */
+};
+
+static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
+
 /*! \brief user descriptor, as read from the config file.
  *
  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
@@ -1515,7 +1178,6 @@ struct ast_manager_user {
 	int writeperm;			/*!< Authorization for writing */
 	int writetimeout;		/*!< Per user Timeout for ast_carefulwrite() */
 	int displayconnects;		/*!< XXX unused */
-	int allowmultiplelogin; /*!< Per user option*/
 	int keep;			/*!< mark entries created on a reload */
 	struct ao2_container *whitefilters; /*!< Manager event filters - white list */
 	struct ao2_container *blackfilters; /*!< Manager event filters - black list */
@@ -1537,17 +1199,13 @@ static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
 /*! \brief A container of event documentation nodes */
 static AO2_GLOBAL_OBJ_STATIC(event_docs);
 
+static void free_channelvars(void);
+
 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
 
 static int match_filter(struct mansession *s, char *eventdata);
 
 /*!
- * @{ \brief Define AMI message types.
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type);
-/*! @} */
-
-/*!
  * \internal
  * \brief Find a registered action object.
  *
@@ -1571,173 +1229,6 @@ static struct manager_action *action_find(const char *name)
 	return act;
 }
 
-struct stasis_topic *ast_manager_get_topic(void)
-{
-	return manager_topic;
-}
-
-struct stasis_message_router *ast_manager_get_message_router(void)
-{
-	return stasis_router;
-}
-
-static void manager_json_value_str_append(struct ast_json *value, const char *key,
-					  struct ast_str **res)
-{
-	switch (ast_json_typeof(value)) {
-	case AST_JSON_STRING:
-		ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
-		break;
-	case AST_JSON_INTEGER:
-		ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
-		break;
-	case AST_JSON_TRUE:
-		ast_str_append(res, 0, "%s: True\r\n", key);
-		break;
-	case AST_JSON_FALSE:
-		ast_str_append(res, 0, "%s: False\r\n", key);
-		break;
-	default:
-		ast_str_append(res, 0, "%s: \r\n", key);
-		break;
-	}
-}
-
-static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
-				    struct ast_str **res, key_exclusion_cb exclusion_cb);
-
-static void manager_json_array_with_key(struct ast_json *obj, const char* key,
-					size_t index, struct ast_str **res,
-					key_exclusion_cb exclusion_cb)
-{
-	struct ast_str *key_str = ast_str_alloca(64);
-	ast_str_set(&key_str, 0, "%s(%zu)", key, index);
-	manager_json_to_ast_str(obj, ast_str_buffer(key_str),
-				res, exclusion_cb);
-}
-
-static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
-				      const char *parent_key, struct ast_str **res,
-				      key_exclusion_cb exclusion_cb)
-{
-	if (parent_key) {
-		struct ast_str *key_str = ast_str_alloca(64);
-		ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
-		manager_json_to_ast_str(obj, ast_str_buffer(key_str),
-					res, exclusion_cb);
-		return;
-	}
-
-	manager_json_to_ast_str(obj, key, res, exclusion_cb);
-}
-
-void manager_json_to_ast_str(struct ast_json *obj, const char *key,
-			     struct ast_str **res, key_exclusion_cb exclusion_cb)
-{
-	struct ast_json_iter *i;
-
-	if (!obj || (!res && !(*res) && (!(*res = ast_str_create(1024))))) {
-		return;
-	}
-
-	if (exclusion_cb && key && exclusion_cb(key)) {
-		return;
-	}
-
-	if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
-	    ast_json_typeof(obj) != AST_JSON_ARRAY) {
-		manager_json_value_str_append(obj, key, res);
-		return;
-	}
-
-	if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
-		size_t j;
-		for (j = 0; j < ast_json_array_size(obj); ++j) {
-			manager_json_array_with_key(ast_json_array_get(obj, j),
-						    key, j, res, exclusion_cb);
-		}
-		return;
-	}
-
-	for (i = ast_json_object_iter(obj); i;
-	     i = ast_json_object_iter_next(obj, i)) {
-		manager_json_obj_with_key(ast_json_object_iter_value(i),
-					  ast_json_object_iter_key(i),
-					  key, res, exclusion_cb);
-	}
-}
-
-
-struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
-{
-	struct ast_str *res = ast_str_create(1024);
-	manager_json_to_ast_str(blob, NULL, &res, exclusion_cb);
-	return res;
-}
-
-static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);
-
-	ev = stasis_message_to_ami(message);
-
-	if (ev == NULL) {
-		/* Not and AMI message; disregard */
-		return;
-	}
-
-	manager_event(ev->event_flags, ev->manager_event, "%s",
-		ev->extra_fields);
-}
-
-static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
-	const char *type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
-	struct ast_json *event = ast_json_object_get(payload->json, "event");
-	RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
-
-	event_buffer = ast_manager_str_from_json_object(event, NULL);
-	if (!event_buffer) {
-		ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
-		return;
-	}
-	manager_event(class_type, type, "%s", ast_str_buffer(event_buffer));
-}
-
-void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
-{
-	RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!obj || !ast_manager_get_generic_type()) {
-		return;
-	}
-
-	ast_json_ref(obj);
-	event_info = ast_json_pack("{s: s, s: i, s: o}",
-			"type", type,
-			"class_type", class_type,
-			"event", obj);
-	if (!event_info) {
-		return;
-	}
-
-	payload = ast_json_payload_create(event_info);
-	if (!payload) {
-		return;
-	}
-	message = stasis_message_create(ast_manager_get_generic_type(), payload);
-	if (!message) {
-		return;
-	}
-	stasis_publish(ast_manager_get_topic(), message);
-}
-
 /*! \brief Add a custom hook to be called when an event is fired */
 void ast_manager_register_hook(struct manager_custom_hook *hook)
 {
@@ -1841,7 +1332,6 @@ static const struct permalias {
 	{ EVENT_FLAG_CC, "cc" },
 	{ EVENT_FLAG_AOC, "aoc" },
 	{ EVENT_FLAG_TEST, "test" },
-	{ EVENT_FLAG_SECURITY, "security" },
 	{ EVENT_FLAG_MESSAGE, "message" },
 	{ INT_MAX, "all" },
 	{ 0, "none" },
@@ -2142,18 +1632,14 @@ static int manager_displayconnects(struct mansession_session *session)
 	return ret;
 }
 
-static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
-
 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct manager_action *cur;
 	struct ast_str *authority;
 	int num, l, which;
-	const char *auth_str;
 	char *ret = NULL;
 #ifdef AST_XML_DOCS
-	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
-	char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
+	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
 #endif
 
 	switch (cmd) {
@@ -2188,17 +1674,12 @@ static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
 	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
 	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-	term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
-	term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
-	term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
 #endif
 
 	AST_RWLIST_RDLOCK(&actions);
 	AST_RWLIST_TRAVERSE(&actions, cur, list) {
 		for (num = 3; num < a->argc; num++) {
 			if (!strcasecmp(cur->action, a->argv[num])) {
-				auth_str = authority_to_str(cur->authority, &authority);
-
 #ifdef AST_XML_DOCS
 				if (cur->docsrc == AST_XML_DOC) {
 					char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
@@ -2206,41 +1687,23 @@ static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_
 					char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
 					char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
 					char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
-					char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available"), 1);
-					char *responses = ast_xmldoc_printable("None", 1);
-					ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
+					ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
 						syntax_title, syntax,
 						synopsis_title, synopsis,
 						description_title, description,
 						arguments_title, arguments,
-						seealso_title, seealso,
-						privilege_title, privilege,
-						list_responses_title);
-
-					if (!cur->list_responses) {
-						ast_cli(a->fd, "%s\n\n", responses);
-					} else {
-						struct ast_xml_doc_item *temp;
-						for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
-							ast_cli(a->fd, "Event: %s\n", temp->name);
-							print_event_instance(a, temp);
-						}
-					}
-
-					ast_cli(a->fd, "%s", final_response_title);
-
-					if (!cur->final_response) {
-						ast_cli(a->fd, "%s\n\n", responses);
-					} else {
-						ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
-						print_event_instance(a, cur->final_response);
-					}
+						seealso_title, seealso);
+					ast_free(syntax);
+					ast_free(synopsis);
+					ast_free(description);
+					ast_free(arguments);
+					ast_free(seealso);
 				} else
 #endif
 				{
 					ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
 						cur->action, cur->synopsis,
-						auth_str,
+						authority_to_str(cur->authority, &authority),
 						S_OR(cur->description, ""));
 				}
 			}
@@ -2323,21 +1786,19 @@ static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli
 
 	ast_cli(a->fd, "\n");
 	ast_cli(a->fd,
-		"          username: %s\n"
-		"            secret: %s\n"
-		"               ACL: %s\n"
-		"         read perm: %s\n"
-		"        write perm: %s\n"
-		"   displayconnects: %s\n"
-		"allowmultiplelogin: %s\n",
+		"       username: %s\n"
+		"         secret: %s\n"
+		"            ACL: %s\n"
+		"      read perm: %s\n"
+		"     write perm: %s\n"
+		"displayconnects: %s\n",
 		(user->username ? user->username : "(N/A)"),
 		(user->secret ? "<Set>" : "(N/A)"),
 		((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
 		user_authority_to_str(user->readperm, &rauthority),
 		user_authority_to_str(user->writeperm, &wauthority),
-		(user->displayconnects ? "yes" : "no"),
-		(user->allowmultiplelogin ? "yes" : "no"));
-	ast_cli(a->fd, "         Variables: \n");
+		(user->displayconnects ? "yes" : "no"));
+	ast_cli(a->fd, "      Variables: \n");
 		for (v = user->chanvars ; v ; v = v->next) {
 			ast_cli(a->fd, "                 %s = %s\n", v->name, v->value);
 		}
@@ -2393,9 +1854,8 @@ static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cl
 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct manager_action *cur;
-	int name_len = 1;
-	int space_remaining;
-#define HSMC_FORMAT "  %-*.*s  %-.*s\n"
+	struct ast_str *authority;
+#define HSMC_FORMAT "  %-15.15s  %-15.15s  %-55.55s\n"
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "manager show commands";
@@ -2406,25 +1866,13 @@ static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli
 	case CLI_GENERATE:
 		return NULL;
 	}
+	authority = ast_str_alloca(MAX_AUTH_PERM_STRING);
+	ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
+	ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
 
 	AST_RWLIST_RDLOCK(&actions);
 	AST_RWLIST_TRAVERSE(&actions, cur, list) {
-		int incoming_len = strlen(cur->action);
-		if (incoming_len > name_len) {
-			name_len = incoming_len;
-		}
-	}
-
-	space_remaining = MGR_SHOW_TERMINAL_WIDTH - name_len - 4;
-	if (space_remaining < 0) {
-		space_remaining = 0;
-	}
-
-	ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "Action", space_remaining, "Synopsis");
-	ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "------", space_remaining, "--------");
-
-	AST_RWLIST_TRAVERSE(&actions, cur, list) {
-		ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, cur->action, space_remaining, cur->synopsis);
+		ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
 	}
 	AST_RWLIST_UNLOCK(&actions);
 
@@ -2943,10 +2391,10 @@ static int set_eventmask(struct mansession *s, const char *eventmask)
 	return maskint;
 }
 
-static enum ast_transport mansession_get_transport(const struct mansession *s)
+static enum ast_security_event_transport_type mansession_get_transport(const struct mansession *s)
 {
-	return s->tcptls_session->parent->tls_cfg ? AST_TRANSPORT_TLS :
-			AST_TRANSPORT_TCP;
+	return s->tcptls_session->parent->tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS :
+			AST_SECURITY_EVENT_TRANSPORT_TCP;
 }
 
 static void report_invalid_user(const struct mansession *s, const char *username)
@@ -3205,7 +2653,7 @@ static int authenticate(struct mansession *s, const struct message *m)
 			MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
 			MD5Final(digest, &md5);
 			for (x = 0; x < 16; x++)
-				len += sprintf(md5key + len, "%2.2x", (unsigned)digest[x]);
+				len += sprintf(md5key + len, "%02hhx", digest[x]);
 			if (!strcmp(md5key, key)) {
 				error = 0;
 			} else {
@@ -3289,11 +2737,9 @@ static int action_getconfig(struct mansession *s, const struct message *m)
 	struct ast_config *cfg;
 	const char *fn = astman_get_header(m, "Filename");
 	const char *category = astman_get_header(m, "Category");
-	const char *filter = astman_get_header(m, "Filter");
-	const char *category_name;
 	int catcount = 0;
 	int lineno = 0;
-	struct ast_category *cur_category = NULL;
+	char *cur_category = NULL;
 	struct ast_variable *v;
 	struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
 
@@ -3301,7 +2747,6 @@ static int action_getconfig(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "Filename not specified");
 		return 0;
 	}
-
 	cfg = ast_config_load2(fn, "manager", config_flags);
 	if (cfg == CONFIG_STATUS_FILEMISSING) {
 		astman_send_error(s, m, "Config file not found");
@@ -3312,34 +2757,19 @@ static int action_getconfig(struct mansession *s, const struct message *m)
 	}
 
 	astman_start_ack(s, m);
-	while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
-		struct ast_str *templates;
-
-		category_name = ast_category_get_name(cur_category);
-		lineno = 0;
-		astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
-
-		if (ast_category_is_template(cur_category)) {
-			astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
-		}
-
-		if ((templates = ast_category_get_templates(cur_category))
-			&& ast_str_strlen(templates) > 0) {
-			astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
-			ast_free(templates);
-		}
-
-		for (v = ast_category_first(cur_category); v; v = v->next) {
-			astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
+	while ((cur_category = ast_category_browse(cfg, cur_category))) {
+		if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
+			lineno = 0;
+			astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
+			for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
+				astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
+			}
+			catcount++;
 		}
-
-		catcount++;
 	}
-
 	if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
 		astman_append(s, "No categories found\r\n");
 	}
-
 	ast_config_destroy(cfg);
 	astman_append(s, "\r\n");
 
@@ -3350,8 +2780,7 @@ static int action_listcategories(struct mansession *s, const struct message *m)
 {
 	struct ast_config *cfg;
 	const char *fn = astman_get_header(m, "Filename");
-	const char *match = astman_get_header(m, "Match");
-	struct ast_category *category = NULL;
+	char *category = NULL;
 	struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
 	int catcount = 0;
 
@@ -3359,7 +2788,6 @@ static int action_listcategories(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "Filename not specified");
 		return 0;
 	}
-
 	if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
 		astman_send_error(s, m, "Config file not found");
 		return 0;
@@ -3367,23 +2795,23 @@ static int action_listcategories(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "Config file has invalid format");
 		return 0;
 	}
-
 	astman_start_ack(s, m);
-	while ((category = ast_category_browse_filtered(cfg, NULL, category, match))) {
-		astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
+	while ((category = ast_category_browse(cfg, category))) {
+		astman_append(s, "Category-%06d: %s\r\n", catcount, category);
 		catcount++;
 	}
-
 	if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
 		astman_append(s, "Error: no categories found\r\n");
 	}
-
 	ast_config_destroy(cfg);
 	astman_append(s, "\r\n");
 
 	return 0;
 }
 
+
+
+
 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
 static void json_escape(char *out, const char *in)
 {
@@ -3418,10 +2846,7 @@ static int action_getconfigjson(struct mansession *s, const struct message *m)
 {
 	struct ast_config *cfg;
 	const char *fn = astman_get_header(m, "Filename");
-	const char *filter = astman_get_header(m, "Filter");
-	const char *category = astman_get_header(m, "Category");
-	struct ast_category *cur_category = NULL;
-	const char *category_name;
+	char *category = NULL;
 	struct ast_variable *v;
 	int comma1 = 0;
 	struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
@@ -3441,30 +2866,14 @@ static int action_getconfigjson(struct mansession *s, const struct message *m)
 
 	astman_start_ack(s, m);
 	astman_append(s, "JSON: {");
-	while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
+	while ((category = ast_category_browse(cfg, category))) {
 		int comma2 = 0;
-		struct ast_str *templates;
 
-		category_name = ast_category_get_name(cur_category);
 		astman_append(s, "%s\"", comma1 ? "," : "");
-		astman_append_json(s, category_name);
+		astman_append_json(s, category);
 		astman_append(s, "\":[");
 		comma1 = 1;
-
-		if (ast_category_is_template(cur_category)) {
-			astman_append(s, "istemplate:1");
-			comma2 = 1;
-		}
-
-		if ((templates = ast_category_get_templates(cur_category))
-			&& ast_str_strlen(templates) > 0) {
-			astman_append(s, "%s", comma2 ? "," : "");
-			astman_append(s, "templates:\"%s\"", ast_str_buffer(templates));
-			ast_free(templates);
-			comma2 = 1;
-		}
-
-		for (v = ast_category_first(cur_category); v; v = v->next) {
+		for (v = ast_variable_browse(cfg, category); v; v = v->next) {
 			astman_append(s, "%s\"", comma2 ? "," : "");
 			astman_append_json(s, v->name);
 			astman_append(s, "\":\"");
@@ -3472,7 +2881,6 @@ static int action_getconfigjson(struct mansession *s, const struct message *m)
 			astman_append(s, "\"");
 			comma2 = 1;
 		}
-
 		astman_append(s, "]");
 	}
 	astman_append(s, "}\r\n\r\n");
@@ -3487,28 +2895,19 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 {
 	int x;
 	char hdr[40];
-	const char *action, *cat, *var, *value, *match, *line, *options;
+	const char *action, *cat, *var, *value, *match, *line;
+	struct ast_category *category;
 	struct ast_variable *v;
 	struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
 	enum error_type result = 0;
 
 	for (x = 0; x < 100000; x++) {	/* 100000 = the max number of allowed updates + 1 */
 		unsigned int object = 0;
-		char *dupoptions;
-		int allowdups = 0;
-		int istemplate = 0;
-		int ignoreerror = 0;
-		char *inherit = NULL;
-		char *catfilter = NULL;
-		char *token;
-		int foundvar = 0;
-		int foundcat = 0;
-		struct ast_category *category = NULL;
 
 		snprintf(hdr, sizeof(hdr), "Action-%06d", x);
 		action = astman_get_header(m, hdr);
 		if (ast_strlen_zero(action))		/* breaks the for loop if no action header */
-			break;							/* this could cause problems if actions come in misnumbered */
+			break;                      	/* this could cause problems if actions come in misnumbered */
 
 		snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
 		cat = astman_get_header(m, hdr);
@@ -3534,90 +2933,22 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 		snprintf(hdr, sizeof(hdr), "Line-%06d", x);
 		line = astman_get_header(m, hdr);
 
-		snprintf(hdr, sizeof(hdr), "Options-%06d", x);
-		options = astman_get_header(m, hdr);
-		if (!ast_strlen_zero(options)) {
-			dupoptions = ast_strdupa(options);
-			while ((token = ast_strsep(&dupoptions, ',', AST_STRSEP_STRIP))) {
-				if (!strcasecmp("allowdups", token)) {
-					allowdups = 1;
-					continue;
-				}
-				if (!strcasecmp("template", token)) {
-					istemplate = 1;
-					continue;
-				}
-				if (!strcasecmp("ignoreerror", token)) {
-					ignoreerror = 1;
-					continue;
-				}
-				if (ast_begins_with(token, "inherit")) {
-					char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
-					c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
-					if (c) {
-						inherit = ast_strdupa(c);
-					}
-					continue;
-				}
-				if (ast_begins_with(token, "catfilter")) {
-					char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
-					c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
-					if (c) {
-						catfilter = ast_strdupa(c);
-					}
-					continue;
-				}
-			}
-		}
-
 		if (!strcasecmp(action, "newcat")) {
-			struct ast_category *template;
-			char *tmpl_name = NULL;
-
-			if (!allowdups) {
-				if (ast_category_get(cfg, cat, "TEMPLATES=include")) {
-					if (ignoreerror) {
-						continue;
-					} else {
-						result = FAILURE_NEWCAT;	/* already exist */
-						break;
-					}
-				}
-			}
-
-			if (istemplate) {
-				category = ast_category_new_template(cat, dfn, -1);
-			} else {
-				category = ast_category_new(cat, dfn, -1);
+			if (ast_category_get(cfg,cat)) {	/* check to make sure the cat doesn't */
+				result = FAILURE_NEWCAT;	/* already exist */
+				break;
 			}
-
-			if (!category) {
+			if (!(category = ast_category_new(cat, dfn, -1))) {
 				result = FAILURE_ALLOCATION;
 				break;
 			}
-
-			if (inherit) {
-				while ((tmpl_name = ast_strsep(&inherit, ',', AST_STRSEP_STRIP))) {
-					if ((template = ast_category_get(cfg, tmpl_name, "TEMPLATES=restrict"))) {
-						ast_category_inherit(category, template);
-					} else {
-						ast_category_destroy(category);
-						category = NULL;
-						result = FAILURE_TEMPLATE;	/* template not found */
-						break;
-					}
-				}
-			}
-
-			if (category != NULL) {
-				if (ast_strlen_zero(match)) {
-					ast_category_append(cfg, category);
-				} else {
-					if (ast_category_insert(cfg, category, match)) {
-						ast_category_destroy(category);
-						result = FAILURE_NEWCAT;
-						break;
-					}
+			if (ast_strlen_zero(match)) {
+				ast_category_append(cfg, category);
+			} else {
+				if (ast_category_insert(cfg, category, match)) {
+					result = FAILURE_NEWCAT;
+					ast_category_destroy(category);
+					break;
 				}
 			}
 		} else if (!strcasecmp(action, "renamecat")) {
@@ -3625,37 +2956,19 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 				result = UNSPECIFIED_ARGUMENT;
 				break;
 			}
-
-			foundcat = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				ast_category_rename(category, value);
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
+			if (!(category = ast_category_get(cfg, cat))) {
 				result = UNKNOWN_CATEGORY;
 				break;
 			}
+			ast_category_rename(category, value);
 		} else if (!strcasecmp(action, "delcat")) {
-			foundcat = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				category = ast_category_delete(cfg, category);
-				foundcat = 1;
-			}
-
-			if (!foundcat && !ignoreerror) {
-				result = UNKNOWN_CATEGORY;
+			if (ast_category_delete(cfg, cat)) {
+				result = FAILURE_DELCAT;
 				break;
 			}
 		} else if (!strcasecmp(action, "emptycat")) {
-			foundcat = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				ast_category_empty(category);
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
-				result = UNKNOWN_CATEGORY;
+			if (ast_category_empty(cfg, cat)) {
+				result = FAILURE_EMPTYCAT;
 				break;
 			}
 		} else if (!strcasecmp(action, "update")) {
@@ -3663,22 +2976,11 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 				result = UNSPECIFIED_ARGUMENT;
 				break;
 			}
-
-			foundcat = 0;
-			foundvar = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				if (!ast_variable_update(category, var, value, match, object)) {
-					foundvar = 1;
-				}
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
+			if (!(category = ast_category_get(cfg,cat))) {
 				result = UNKNOWN_CATEGORY;
 				break;
 			}
-
-			if (!foundvar) {
+			if (ast_variable_update(category, var, value, match, object)) {
 				result = FAILURE_UPDATE;
 				break;
 			}
@@ -3687,23 +2989,12 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 				result = UNSPECIFIED_ARGUMENT;
 				break;
 			}
-
-			foundcat = 0;
-			foundvar = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				if (!ast_variable_delete(category, var, match, line)) {
-					foundvar = 1;
-				}
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
+			if (!(category = ast_category_get(cfg, cat))) {
 				result = UNKNOWN_CATEGORY;
 				break;
 			}
-
-			if (!foundvar && !ignoreerror) {
-				result = FAILURE_UPDATE;
+			if (ast_variable_delete(category, var, match, line)) {
+				result = FAILURE_DELETE;
 				break;
 			}
 		} else if (!strcasecmp(action, "append")) {
@@ -3711,44 +3002,32 @@ static enum error_type handle_updates(struct mansession *s, const struct message
 				result = UNSPECIFIED_ARGUMENT;
 				break;
 			}
-
-			foundcat = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				if (!(v = ast_variable_new(var, value, dfn))) {
-					result = FAILURE_ALLOCATION;
-					break;
-				}
-				if (object || (match && !strcasecmp(match, "object"))) {
-					v->object = 1;
-				}
-				ast_variable_append(category, v);
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
+			if (!(category = ast_category_get(cfg, cat))) {
 				result = UNKNOWN_CATEGORY;
 				break;
 			}
+			if (!(v = ast_variable_new(var, value, dfn))) {
+				result = FAILURE_ALLOCATION;
+				break;
+			}
+			if (object || (match && !strcasecmp(match, "object"))) {
+				v->object = 1;
+			}
+			ast_variable_append(category, v);
 		} else if (!strcasecmp(action, "insert")) {
 			if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
 				result = UNSPECIFIED_ARGUMENT;
 				break;
 			}
-
-			foundcat = 0;
-			while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
-				if (!(v = ast_variable_new(var, value, dfn))) {
-					result = FAILURE_ALLOCATION;
-					break;
-				}
-				ast_variable_insert(category, v, line);
-				foundcat = 1;
-			}
-
-			if (!foundcat) {
+			if (!(category = ast_category_get(cfg, cat))) {
 				result = UNKNOWN_CATEGORY;
 				break;
 			}
+			if (!(v = ast_variable_new(var, value, dfn))) {
+				result = FAILURE_ALLOCATION;
+				break;
+			}
+			ast_variable_insert(category, v, line);
 		}
 		else {
 			ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
@@ -3834,9 +3113,6 @@ static int action_updateconfig(struct mansession *s, const struct message *m)
 		case FAILURE_APPEND:
 			astman_send_error(s, m, "Append did not complete successfully");
 			break;
-		case FAILURE_TEMPLATE:
-			astman_send_error(s, m, "Template category not found");
-			break;
 		}
 	}
 	return 0;
@@ -4299,179 +3575,161 @@ static int action_getvar(struct mansession *s, const struct message *m)
 static int action_status(struct mansession *s, const struct message *m)
 {
 	const char *name = astman_get_header(m, "Channel");
-	const char *chan_variables = astman_get_header(m, "Variables");
-	const char *id = astman_get_header(m, "ActionID");
-	char *variables = ast_strdupa(S_OR(chan_variables, ""));
-	struct ast_str *variable_str = ast_str_create(1024);
-	struct ast_str *write_transpath = ast_str_alloca(256);
-	struct ast_str *read_transpath = ast_str_alloca(256);
-	struct ast_channel *chan;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	const char *cvariables = astman_get_header(m, "Variables");
+	char *variables = ast_strdupa(S_OR(cvariables, ""));
+	struct ast_channel *c;
+	char bridge[256];
+	struct timeval now = ast_tvnow();
+	long elapsed_seconds = 0;
 	int channels = 0;
 	int all = ast_strlen_zero(name); /* set if we want all channels */
-	char id_text[256];
-	struct ast_channel_iterator *it_chans = NULL;
+	const char *id = astman_get_header(m, "ActionID");
+	char idText[256];
 	AST_DECLARE_APP_ARGS(vars,
 		AST_APP_ARG(name)[100];
 	);
+	struct ast_str *str = ast_str_create(1000);
+	struct ast_channel_iterator *iter = NULL;
 
-	if (!variable_str) {
-		astman_send_error(s, m, "Memory Allocation Failure");
-		return 1;
+	if (!ast_strlen_zero(id)) {
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+	} else {
+		idText[0] = '\0';
 	}
 
 	if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) {
-		ast_free(variable_str);
 		astman_send_error(s, m, "Status Access Forbidden: Variables");
 		return 0;
 	}
 
 	if (all) {
-		if (!(it_chans = ast_channel_iterator_all_new())) {
-			ast_free(variable_str);
+		if (!(iter = ast_channel_iterator_all_new())) {
+			ast_free(str);
 			astman_send_error(s, m, "Memory Allocation Failure");
 			return 1;
 		}
-		chan = ast_channel_iterator_next(it_chans);
+		c = ast_channel_iterator_next(iter);
 	} else {
-		chan = ast_channel_get_by_name(name);
-		if (!chan) {
+		if (!(c = ast_channel_get_by_name(name))) {
 			astman_send_error(s, m, "No such channel");
-			ast_free(variable_str);
+			ast_free(str);
 			return 0;
 		}
 	}
 
 	astman_send_ack(s, m, "Channel status will follow");
 
-	if (!ast_strlen_zero(id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-	} else {
-		id_text[0] = '\0';
-	}
-
-	if (!ast_strlen_zero(chan_variables)) {
+	if (!ast_strlen_zero(cvariables)) {
 		AST_STANDARD_APP_ARGS(vars, variables);
 	}
 
 	/* if we look by name, we break after the first iteration */
-	for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
-		struct timeval now;
-		long elapsed_seconds;
-		struct ast_bridge *bridge;
-
-		ast_channel_lock(chan);
+	for (; c; c = ast_channel_iterator_next(iter)) {
+		ast_channel_lock(c);
 
-		now = ast_tvnow();
-		elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
-
-		if (!ast_strlen_zero(chan_variables)) {
+		if (!ast_strlen_zero(cvariables)) {
 			int i;
-			ast_str_reset(variable_str);
+			ast_str_reset(str);
 			for (i = 0; i < vars.argc; i++) {
 				char valbuf[512], *ret = NULL;
 
 				if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
-					if (ast_func_read(chan, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
+					if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
 						valbuf[0] = '\0';
 					}
 					ret = valbuf;
 				} else {
-					pbx_retrieve_variable(chan, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
+					pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
 				}
 
-				ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
+				ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
 			}
 		}
 
 		channels++;
-
-		bridge = ast_channel_get_bridge(chan);
-
-		astman_append(s,
+		if (ast_channel_internal_bridged_channel(c)) {
+			snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", ast_channel_name(ast_channel_internal_bridged_channel(c)), ast_channel_uniqueid(ast_channel_internal_bridged_channel(c)));
+		} else {
+			bridge[0] = '\0';
+		}
+		if (ast_channel_pbx(c)) {
+			if (ast_channel_cdr(c)) {
+				elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
+			}
+			astman_append(s,
 			"Event: Status\r\n"
 			"Privilege: Call\r\n"
 			"Channel: %s\r\n"
-			"ChannelState: %u\r\n"
-			"ChannelStateDesc: %s\r\n"
 			"CallerIDNum: %s\r\n"
 			"CallerIDName: %s\r\n"
 			"ConnectedLineNum: %s\r\n"
 			"ConnectedLineName: %s\r\n"
 			"Accountcode: %s\r\n"
+			"ChannelState: %u\r\n"
+			"ChannelStateDesc: %s\r\n"
 			"Context: %s\r\n"
-			"Exten: %s\r\n"
+			"Extension: %s\r\n"
 			"Priority: %d\r\n"
-			"Uniqueid: %s\r\n"
-			"Type: %s\r\n"
-			"DNID: %s\r\n"
-			"EffectiveConnectedLineNum: %s\r\n"
-			"EffectiveConnectedLineName: %s\r\n"
-			"TimeToHangup: %ld\r\n"
-			"BridgeID: %s\r\n"
-			"Linkedid: %s\r\n"
-			"Application: %s\r\n"
-			"Data: %s\r\n"
-			"Nativeformats: %s\r\n"
-			"Readformat: %s\r\n"
-			"Readtrans: %s\r\n"
-			"Writeformat: %s\r\n"
-			"Writetrans: %s\r\n"
-			"Callgroup: %llu\r\n"
-			"Pickupgroup: %llu\r\n"
 			"Seconds: %ld\r\n"
 			"%s"
+			"Uniqueid: %s\r\n"
+			"%s"
 			"%s"
 			"\r\n",
-			ast_channel_name(chan),
-			ast_channel_state(chan),
-			ast_state2str(ast_channel_state(chan)),
-			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
-			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"),
-			S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "<unknown>"),
-			S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "<unknown>"),
-			ast_channel_accountcode(chan),
-			ast_channel_context(chan),
-			ast_channel_exten(chan),
-			ast_channel_priority(chan),
-			ast_channel_uniqueid(chan),
-			ast_channel_tech(chan)->type,
-			S_OR(ast_channel_dialed(chan)->number.str, ""),
-			S_COR(ast_channel_connected_effective_id(chan).number.valid, ast_channel_connected_effective_id(chan).number.str, "<unknown>"),
-			S_COR(ast_channel_connected_effective_id(chan).name.valid, ast_channel_connected_effective_id(chan).name.str, "<unknown>"),
-			ast_channel_whentohangup(chan)->tv_sec,
-			bridge ? bridge->uniqueid : "",
-			ast_channel_linkedid(chan),
-			ast_channel_appl(chan),
-			ast_channel_data(chan),
-			ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf),
-			ast_format_get_name(ast_channel_readformat(chan)),
-			ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
-			ast_format_get_name(ast_channel_writeformat(chan)),
-			ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
-			ast_channel_callgroup(chan),
-			ast_channel_pickupgroup(chan),
-			(long)elapsed_seconds,
-			ast_str_buffer(variable_str),
-			id_text);
-
-		ao2_cleanup(bridge);
+			ast_channel_name(c),
+			S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
+			S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
+			ast_channel_accountcode(c),
+			ast_channel_state(c),
+			ast_state2str(ast_channel_state(c)), ast_channel_context(c),
+			ast_channel_exten(c), ast_channel_priority(c), (long)elapsed_seconds, bridge, ast_channel_uniqueid(c), ast_str_buffer(str), idText);
+		} else {
+			astman_append(s,
+				"Event: Status\r\n"
+				"Privilege: Call\r\n"
+				"Channel: %s\r\n"
+				"CallerIDNum: %s\r\n"
+				"CallerIDName: %s\r\n"
+				"ConnectedLineNum: %s\r\n"
+				"ConnectedLineName: %s\r\n"
+				"Account: %s\r\n"
+				"State: %s\r\n"
+				"%s"
+				"Uniqueid: %s\r\n"
+				"%s"
+				"%s"
+				"\r\n",
+				ast_channel_name(c),
+				S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
+				S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
+				S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
+				S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
+				ast_channel_accountcode(c),
+				ast_state2str(ast_channel_state(c)), bridge, ast_channel_uniqueid(c),
+				ast_str_buffer(str), idText);
+		}
+
+		ast_channel_unlock(c);
+		c = ast_channel_unref(c);
 
-		ast_channel_unlock(chan);
-		chan = ast_channel_unref(chan);
+		if (!all) {
+			break;
+		}
 	}
 
-	if (it_chans) {
-		ast_channel_iterator_destroy(it_chans);
+	if (iter) {
+		ast_channel_iterator_destroy(iter);
 	}
 
 	astman_append(s,
 		"Event: StatusComplete\r\n"
 		"%s"
 		"Items: %d\r\n"
-		"\r\n", id_text, channels);
+		"\r\n", idText, channels);
 
-	ast_free(variable_str);
+	ast_free(str);
 
 	return 0;
 }
@@ -4586,6 +3844,12 @@ static int action_redirect(struct mansession *s, const struct message *m)
 
 	if (ast_strlen_zero(name2)) {
 		/* Single channel redirect in progress. */
+		if (ast_channel_pbx(chan)) {
+			ast_channel_lock(chan);
+			/* don't let the after-bridge code run the h-exten */
+			ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
+			ast_channel_unlock(chan);
+		}
 		res = ast_async_goto(chan, context, exten, pi);
 		if (!res) {
 			astman_send_ack(s, m, "Redirect successful");
@@ -4613,12 +3877,16 @@ static int action_redirect(struct mansession *s, const struct message *m)
 	/* Dual channel redirect in progress. */
 	if (ast_channel_pbx(chan)) {
 		ast_channel_lock(chan);
-		ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		/* don't let the after-bridge code run the h-exten */
+		ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT
+			| AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
 		ast_channel_unlock(chan);
 	}
 	if (ast_channel_pbx(chan2)) {
 		ast_channel_lock(chan2);
-		ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		/* don't let the after-bridge code run the h-exten */
+		ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT
+			| AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
 		ast_channel_unlock(chan2);
 	}
 	res = ast_async_goto(chan, context, exten, pi);
@@ -4631,71 +3899,26 @@ static int action_redirect(struct mansession *s, const struct message *m)
 		if (!res) {
 			astman_send_ack(s, m, "Dual Redirect successful");
 		} else {
-			astman_send_error(s, m, "Secondary redirect failed");
-		}
-	} else {
-		astman_send_error(s, m, "Redirect failed");
-	}
-
-	/* Release the bridge wait. */
-	if (ast_channel_pbx(chan)) {
-		ast_channel_lock(chan);
-		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
-		ast_channel_unlock(chan);
-	}
-	if (ast_channel_pbx(chan2)) {
-		ast_channel_lock(chan2);
-		ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
-		ast_channel_unlock(chan2);
-	}
-
-	chan2 = ast_channel_unref(chan2);
-	chan = ast_channel_unref(chan);
-	return 0;
-}
-
-static int action_blind_transfer(struct mansession *s, const struct message *m)
-{
-	const char *name = astman_get_header(m, "Channel");
-	const char *exten = astman_get_header(m, "Exten");
-	const char *context = astman_get_header(m, "Context");
-	RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(name)) {
-		astman_send_error(s, m, "No channel specified");
-		return 0;
-	}
-
-	if (ast_strlen_zero(exten)) {
-		astman_send_error(s, m, "No extension specified");
-		return 0;
-	}
-
-	chan = ast_channel_get_by_name(name);
-	if (!chan) {
-		astman_send_error(s, m, "Channel specified does not exist");
-		return 0;
+			astman_send_error(s, m, "Secondary redirect failed");
+		}
+	} else {
+		astman_send_error(s, m, "Redirect failed");
 	}
 
-	if (ast_strlen_zero(context)) {
-		context = ast_channel_context(chan);
+	/* Release the bridge wait. */
+	if (ast_channel_pbx(chan)) {
+		ast_channel_lock(chan);
+		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		ast_channel_unlock(chan);
 	}
-
-	switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-		astman_send_error(s, m, "Transfer not permitted");
-		break;
-	case AST_BRIDGE_TRANSFER_INVALID:
-		astman_send_error(s, m, "Transfer invalid");
-		break;
-	case AST_BRIDGE_TRANSFER_FAIL:
-		astman_send_error(s, m, "Transfer failed");
-		break;
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		astman_send_ack(s, m, "Transfer succeeded");
-		break;
+	if (ast_channel_pbx(chan2)) {
+		ast_channel_lock(chan2);
+		ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
+		ast_channel_unlock(chan2);
 	}
 
+	chan2 = ast_channel_unref(chan2);
+	chan = ast_channel_unref(chan);
 	return 0;
 }
 
@@ -4705,8 +3928,8 @@ static int action_atxfer(struct mansession *s, const struct message *m)
 	const char *exten = astman_get_header(m, "Exten");
 	const char *context = astman_get_header(m, "Context");
 	struct ast_channel *chan = NULL;
-	char feature_code[AST_FEATURE_MAX_LEN];
-	const char *digit;
+	struct ast_call_feature *atxfer_feature = NULL;
+	char *feature_code = NULL;
 
 	if (ast_strlen_zero(name)) {
 		astman_send_error(s, m, "No channel specified");
@@ -4717,32 +3940,27 @@ static int action_atxfer(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	if (!(chan = ast_channel_get_by_name(name))) {
-		astman_send_error(s, m, "Channel specified does not exist");
+	if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
+		astman_send_error(s, m, "No attended transfer feature found");
 		return 0;
 	}
 
-	ast_channel_lock(chan);
-	if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
-			ast_strlen_zero(feature_code)) {
-		ast_channel_unlock(chan);
-		astman_send_error(s, m, "No attended transfer feature code found");
-		ast_channel_unref(chan);
+	if (!(chan = ast_channel_get_by_name(name))) {
+		astman_send_error(s, m, "Channel specified does not exist");
 		return 0;
 	}
-	ast_channel_unlock(chan);
 
 	if (!ast_strlen_zero(context)) {
 		pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
 	}
 
-	for (digit = feature_code; *digit; ++digit) {
-		struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
+	for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
+		struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
 		ast_queue_frame(chan, &f);
 	}
 
-	for (digit = exten; *digit; ++digit) {
-		struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
+	for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
+		struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
 		ast_queue_frame(chan, &f);
 	}
 
@@ -4756,7 +3974,7 @@ static int action_atxfer(struct mansession *s, const struct message *m)
 static int check_blacklist(const char *cmd)
 {
 	char *cmd_copy, *cur_cmd;
-	char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
+	char *cmd_words[AST_MAX_CMD_LEN] = { NULL, };
 	int i;
 
 	cmd_copy = ast_strdupa(cmd);
@@ -4879,8 +4097,6 @@ struct fast_originate_helper {
 		AST_STRING_FIELD(exten);
 		AST_STRING_FIELD(idtext);
 		AST_STRING_FIELD(account);
-		AST_STRING_FIELD(channelid);
-		AST_STRING_FIELD(otherchannelid);
 	);
 	int priority;
 	struct ast_variable *vars;
@@ -4895,7 +4111,7 @@ struct fast_originate_helper {
  */
 static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
 {
-	ao2_cleanup(doomed->cap);
+	ast_format_cap_destroy(doomed->cap);
 	ast_variables_destroy(doomed->vars);
 	ast_string_field_free_memory(doomed);
 	ast_free(doomed);
@@ -4908,23 +4124,19 @@ static void *fast_originate(void *data)
 	int reason = 0;
 	struct ast_channel *chan = NULL, *chans[1];
 	char requested_channel[AST_CHANNEL_NAME];
-	struct ast_assigned_ids assignedids = {
-		.uniqueid = in->channelid,
-		.uniqueid2 = in->otherchannelid
-	};
 
 	if (!ast_strlen_zero(in->app)) {
 		res = ast_pbx_outgoing_app(in->tech, in->cap, in->data,
 			in->timeout, in->app, in->appdata, &reason, 1,
 			S_OR(in->cid_num, NULL),
 			S_OR(in->cid_name, NULL),
-			in->vars, in->account, &chan, &assignedids);
+			in->vars, in->account, &chan);
 	} else {
 		res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data,
 			in->timeout, in->context, in->exten, in->priority, &reason, 1,
 			S_OR(in->cid_num, NULL),
 			S_OR(in->cid_name, NULL),
-			in->vars, in->account, &chan, in->early_media, &assignedids);
+			in->vars, in->account, &chan, in->early_media);
 	}
 	/* Any vars memory was passed to the ast_pbx_outgoing_xxx() calls. */
 	in->vars = NULL;
@@ -4951,10 +4163,9 @@ static void *fast_originate(void *data)
 		S_OR(in->cid_name, "<unknown>")
 		);
 
-	/* Locked and ref'd by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
+	/* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
 	if (chan) {
 		ast_channel_unlock(chan);
-		ast_channel_unref(chan);
 	}
 	destroy_fast_originate_helper(in);
 	return NULL;
@@ -5205,10 +4416,6 @@ static int action_originate(struct mansession *s, const struct message *m)
 	const char *id = astman_get_header(m, "ActionID");
 	const char *codecs = astman_get_header(m, "Codecs");
 	const char *early_media = astman_get_header(m, "Earlymedia");
-	struct ast_assigned_ids assignedids = {
-		.uniqueid = astman_get_header(m, "ChannelId"),
-		.uniqueid2 = astman_get_header(m, "OtherChannelId"),
-	};
 	struct ast_variable *vars = NULL;
 	char *tech, *data;
 	char *l = NULL, *n = NULL;
@@ -5218,7 +4425,8 @@ static int action_originate(struct mansession *s, const struct message *m)
 	int reason = 0;
 	char tmp[256];
 	char tmp2[256];
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+	struct ast_format tmp_fmt;
 	pthread_t th;
 	int bridge_early = 0;
 
@@ -5226,15 +4434,7 @@ static int action_originate(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "Internal Error. Memory allocation failure.");
 		return 0;
 	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
-		|| (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
-		astman_send_error_va(s, m, "Uniqueid length exceeds maximum of %d\n",
-			AST_MAX_PUBLIC_UNIQUEID);
-		res = 0;
-		goto fast_orig_cleanup;
-	}
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
 
 	if (ast_strlen_zero(name)) {
 		astman_send_error(s, m, "Channel not specified");
@@ -5276,8 +4476,8 @@ static int action_originate(struct mansession *s, const struct message *m)
 		}
 	}
 	if (!ast_strlen_zero(codecs)) {
-		ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_update_by_allow_disallow(cap, codecs, 1);
+		ast_format_cap_remove_all(cap);
+		ast_parse_allow_disallow(NULL, cap, codecs, 1);
 	}
 
 	if (!ast_strlen_zero(app) && s->session) {
@@ -5357,8 +4557,6 @@ static int action_originate(struct mansession *s, const struct message *m)
 			ast_string_field_set(fast, context, context);
 			ast_string_field_set(fast, exten, exten);
 			ast_string_field_set(fast, account, account);
-			ast_string_field_set(fast, channelid, assignedids.uniqueid);
-			ast_string_field_set(fast, otherchannelid, assignedids.uniqueid2);
 			fast->vars = vars;
 			fast->cap = cap;
 			cap = NULL; /* transfered originate helper the capabilities structure.  It is now responsible for freeing it. */
@@ -5373,11 +4571,11 @@ static int action_originate(struct mansession *s, const struct message *m)
 			}
 		}
 	} else if (!ast_strlen_zero(app)) {
-		res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL, assignedids.uniqueid ? &assignedids : NULL);
+		res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
 		/* Any vars memory was passed to ast_pbx_outgoing_app(). */
 	} else {
 		if (exten && context && pi) {
-			res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL, bridge_early, assignedids.uniqueid ? &assignedids : NULL);
+			res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL, bridge_early);
 			/* Any vars memory was passed to ast_pbx_outgoing_exten(). */
 		} else {
 			astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
@@ -5393,7 +4591,7 @@ static int action_originate(struct mansession *s, const struct message *m)
 	}
 
 fast_orig_cleanup:
-	ao2_cleanup(cap);
+	ast_format_cap_destroy(cap);
 	return 0;
 }
 
@@ -5455,10 +4653,8 @@ static int action_extensionstate(struct mansession *s, const struct message *m)
 			   "Exten: %s\r\n"
 			   "Context: %s\r\n"
 			   "Hint: %s\r\n"
-			   "Status: %d\r\n"
-		           "StatusText: %s\r\n\r\n",
-		      exten, context, hint, status,
-		      ast_extension_state2str(status));
+			   "Status: %d\r\n\r\n",
+			   exten, context, hint, status);
 	return 0;
 }
 
@@ -5468,6 +4664,8 @@ static int action_presencestate(struct mansession *s, const struct message *m)
 	enum ast_presence_state state;
 	char *subtype;
 	char *message;
+	char subtype_header[256] = "";
+	char message_header[256] = "";
 
 	if (ast_strlen_zero(provider)) {
 		astman_send_error(s, m, "No provider specified");
@@ -5480,25 +4678,25 @@ static int action_presencestate(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	astman_start_ack(s, m);
-	astman_append(s, "Message: Presence State\r\n"
-	                 "State: %s\r\n", ast_presence_state2str(state));
-
 	if (!ast_strlen_zero(subtype)) {
-		astman_append(s, "Subtype: %s\r\n", subtype);
+		snprintf(subtype_header, sizeof(subtype_header),
+				"Subtype: %s\r\n", subtype);
 	}
 
 	if (!ast_strlen_zero(message)) {
-		/* XXX The Message header here is deprecated as it
-		 * duplicates the action response header 'Message'.
-		 * Remove it in the next major revision of AMI.
-		 */
-		astman_append(s, "Message: %s\r\n"
-		                 "PresenceMessage: %s\r\n",
-		                 message, message);
+		snprintf(message_header, sizeof(message_header),
+				"Message: %s\r\n", message);
 	}
-	astman_append(s, "\r\n");
 
+	astman_start_ack(s, m);
+	astman_append(s, "Message: Presence State\r\n"
+			"State: %s\r\n"
+			"%s"
+			"%s"
+			"\r\n",
+			ast_presence_state2str(state),
+			subtype_header,
+			message_header);
 	return 0;
 }
 
@@ -5635,7 +4833,7 @@ static enum add_filter_result manager_add_filter(const char *filter_pattern, str
 		is_blackfilter = 0;
 	}
 
-	if (regcomp(new_filter, filter_pattern, REG_EXTENDED | REG_NOSUB)) {
+	if (regcomp(new_filter, filter_pattern, 0)) { /* XXX: the only place we use non-REG_EXTENDED */
 		ao2_t_ref(new_filter, -1, "failed to make regex");
 		return FILTER_COMPILE_FAIL;
 	}
@@ -5655,7 +4853,7 @@ static int match_filter(struct mansession *s, char *eventdata)
 {
 	int result = 0;
 
-	ast_debug(3, "Examining AMI event:\n%s\n", eventdata);
+	ast_debug(3, "Examining event:\n%s\n", eventdata);
 	if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
 		return 1; /* no filtering means match all */
 	} else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
@@ -5718,8 +4916,7 @@ static int action_userevent(struct mansession *s, const struct message *m)
 	ast_str_reset(body);
 
 	for (x = 0; x < m->hdrcount; x++) {
-		if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:")) &&
-				strncasecmp("Action:", m->headers[x], strlen("Action:"))) {
+		if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
 			ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
 		}
 	}
@@ -5759,13 +4956,13 @@ static int action_coresettings(struct mansession *s, const struct message *m)
 			AMI_VERSION,
 			ast_get_version(),
 			ast_config_AST_SYSTEM_NAME,
-			ast_option_maxcalls,
-			ast_option_maxload,
+			option_maxcalls,
+			option_maxload,
 			ast_config_AST_RUN_USER,
 			ast_config_AST_RUN_GROUP,
-			ast_option_maxfiles,
+			option_maxfiles,
 			AST_CLI_YESNO(ast_realtime_enabled()),
-			AST_CLI_YESNO(ast_cdr_is_enabled()),
+			AST_CLI_YESNO(check_cdr_enabled()),
 			AST_CLI_YESNO(check_webmanager_enabled())
 			);
 	return 0;
@@ -5815,29 +5012,24 @@ static int action_corestatus(struct mansession *s, const struct message *m)
 static int action_reload(struct mansession *s, const struct message *m)
 {
 	const char *module = astman_get_header(m, "Module");
-	enum ast_module_reload_result res = ast_module_reload(S_OR(module, NULL));
+	int res = ast_module_reload(S_OR(module, NULL));
 
 	switch (res) {
-	case AST_MODULE_RELOAD_NOT_FOUND:
+	case -1:
+		astman_send_error(s, m, "A reload is in progress");
+		break;
+	case 0:
 		astman_send_error(s, m, "No such module");
 		break;
-	case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
+	case 1:
 		astman_send_error(s, m, "Module does not support reload");
 		break;
-	case AST_MODULE_RELOAD_ERROR:
-		astman_send_error(s, m, "An unknown error occurred");
-		break;
-	case AST_MODULE_RELOAD_IN_PROGRESS:
-		astman_send_error(s, m, "A reload is in progress");
-		break;
-	case AST_MODULE_RELOAD_UNINITIALIZED:
-		astman_send_error(s, m, "Module not initialized");
-		break;
-	case AST_MODULE_RELOAD_QUEUED:
-	case AST_MODULE_RELOAD_SUCCESS:
-		/* Treat a queued request as success */
+	case 2:
 		astman_send_ack(s, m, "Module Reloaded");
 		break;
+	default:
+		astman_send_error(s, m, "An unknown error occurred");
+		break;
 	}
 	return 0;
 }
@@ -5848,10 +5040,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 {
 	const char *actionid = astman_get_header(m, "ActionID");
 	char idText[256];
+	struct ast_channel *c = NULL;
 	int numchans = 0;
-	RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
-	struct ao2_iterator it_chans;
-	struct stasis_message *msg;
+	int duration, durh, durm, durs;
+	struct ast_channel_iterator *iter;
 
 	if (!ast_strlen_zero(actionid)) {
 		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
@@ -5859,27 +5051,22 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 		idText[0] = '\0';
 	}
 
-	if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) {
-		astman_send_error(s, m, "Could not get cached channels");
-		return 0;
+	if (!(iter = ast_channel_iterator_all_new())) {
+		astman_send_error(s, m, "Memory Allocation Failure");
+		return 1;
 	}
 
 	astman_send_listack(s, m, "Channels will follow", "start");
 
-	it_chans = ao2_iterator_init(channels, 0);
-	for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
-		struct ast_channel_snapshot *cs = stasis_message_data(msg);
-		struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, "");
+	for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
+		struct ast_channel *bc;
 		char durbuf[10] = "";
 
-		if (!built) {
-			continue;
-		}
+		ast_channel_lock(c);
 
-		if (!ast_tvzero(cs->creationtime)) {
-			int duration, durh, durm, durs;
-
-			duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+		bc = ast_bridged_channel(c);
+		if (ast_channel_cdr(c) && !ast_tvzero(ast_channel_cdr(c)->start)) {
+			duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_cdr(c)->start) / 1000);
 			durh = duration / 3600;
 			durm = (duration % 3600) / 60;
 			durs = duration % 60;
@@ -5889,24 +5076,35 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 		astman_append(s,
 			"Event: CoreShowChannel\r\n"
 			"%s"
-			"%s"
+			"Channel: %s\r\n"
+			"UniqueID: %s\r\n"
+			"Context: %s\r\n"
+			"Extension: %s\r\n"
+			"Priority: %d\r\n"
+			"ChannelState: %u\r\n"
+			"ChannelStateDesc: %s\r\n"
 			"Application: %s\r\n"
 			"ApplicationData: %s\r\n"
+			"CallerIDnum: %s\r\n"
+			"CallerIDname: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n"
 			"Duration: %s\r\n"
-			"BridgeId: %s\r\n"
-			"\r\n",
-			idText,
-			ast_str_buffer(built),
-			cs->appl,
-			cs->data,
-			durbuf,
-			cs->bridgeid);
+			"AccountCode: %s\r\n"
+			"BridgedChannel: %s\r\n"
+			"BridgedUniqueID: %s\r\n"
+			"\r\n", idText, ast_channel_name(c), ast_channel_uniqueid(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_state(c),
+			ast_state2str(ast_channel_state(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "", ast_channel_data(c) ? S_OR(ast_channel_data(c), "") : "",
+			S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
+			S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
+			S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, ""),
+			S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, ""),
+			durbuf, S_OR(ast_channel_accountcode(c), ""), bc ? ast_channel_name(bc) : "", bc ? ast_channel_uniqueid(bc) : "");
+
+		ast_channel_unlock(c);
 
 		numchans++;
-
-		ast_free(built);
 	}
-	ao2_iterator_destroy(&it_chans);
 
 	astman_append(s,
 		"Event: CoreShowChannelsComplete\r\n"
@@ -5915,19 +5113,8 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 		"%s"
 		"\r\n", numchans, idText);
 
-	return 0;
-}
-
-/*! \brief  Manager command "LoggerRotate" - reloads and rotates the logger in
- *          the same manner as the CLI command 'logger rotate'. */
-static int action_loggerrotate(struct mansession *s, const struct message *m)
-{
-	if (ast_logger_rotate()) {
-		astman_send_error(s, m, "Failed to reload the logger and rotate log files");
-		return 0;
-	}
+	ast_channel_iterator_destroy(iter);
 
-	astman_send_ack(s, m, "Reloaded the logger and rotated log files");
 	return 0;
 }
 
@@ -5938,9 +5125,6 @@ static int manager_modulecheck(struct mansession *s, const struct message *m)
 	const char *module = astman_get_header(m, "Module");
 	const char *id = astman_get_header(m, "ActionID");
 	char idText[256];
-#if !defined(LOW_MEMORY)
-	const char *version;
-#endif
 	char filename[PATH_MAX];
 	char *cut;
 
@@ -5957,11 +5141,6 @@ static int manager_modulecheck(struct mansession *s, const struct message *m)
 		astman_send_error(s, m, "Module not loaded");
 		return 0;
 	}
-	snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
-	ast_debug(1, "**** ModuleCheck .c file %s\n", filename);
-#if !defined(LOW_MEMORY)
-	version = ast_file_version_find(filename);
-#endif
 
 	if (!ast_strlen_zero(id)) {
 		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
@@ -5970,7 +5149,7 @@ static int manager_modulecheck(struct mansession *s, const struct message *m)
 	}
 	astman_append(s, "Response: Success\r\n%s", idText);
 #if !defined(LOW_MEMORY)
-	astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
+	astman_append(s, "Version: %s\r\n\r\n", ast_get_version());
 #endif
 	return 0;
 }
@@ -6038,8 +5217,7 @@ static int process_message(struct mansession *s, const struct message *m)
 {
 	int ret = 0;
 	struct manager_action *act_found;
-	struct ast_manager_user *user = NULL;
-	const char *username;
+	const char *user;
 	const char *action;
 
 	action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
@@ -6064,24 +5242,19 @@ static int process_message(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	if (!s->session->authenticated
+	if (!allowmultiplelogin
+		&& !s->session->authenticated
 		&& (!strcasecmp(action, "Login")
 			|| !strcasecmp(action, "Challenge"))) {
-		username = astman_get_header(m, "Username");
-
-		if (!ast_strlen_zero(username) && check_manager_session_inuse(username)) {
-			AST_RWLIST_WRLOCK(&users);
-			user = get_manager_by_name_locked(username);
-			if (user && !user->allowmultiplelogin) {
-				AST_RWLIST_UNLOCK(&users);
-				report_session_limit(s);
-				sleep(1);
-				mansession_lock(s);
-				astman_send_error(s, m, "Login Already In Use");
-				mansession_unlock(s);
-				return -1;
-			}
-			AST_RWLIST_UNLOCK(&users);
+		user = astman_get_header(m, "Username");
+
+		if (!ast_strlen_zero(user) && check_manager_session_inuse(user)) {
+			report_session_limit(s);
+			sleep(1);
+			mansession_lock(s);
+			astman_send_error(s, m, "Login Already In Use");
+			mansession_unlock(s);
+			return -1;
 		}
 	}
 
@@ -6524,20 +5697,30 @@ static int append_event(const char *str, int category)
 	return 0;
 }
 
+AST_THREADSTORAGE(manager_event_funcbuf);
+
 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
 {
-	RAII_VAR(struct varshead *, vars, NULL, ao2_cleanup);
-	struct ast_var_t *var;
+	struct manager_channel_variable *var;
 
-	vars = ast_channel_get_manager_vars(chan);
-
-	if (!vars) {
-		return;
-	}
+	AST_RWLIST_RDLOCK(&channelvars);
+	AST_LIST_TRAVERSE(&channelvars, var, entry) {
+		const char *val;
+		struct ast_str *res;
 
-	AST_LIST_TRAVERSE(vars, var, entries) {
-		ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value);
+		if (var->isfunc) {
+			res = ast_str_thread_get(&manager_event_funcbuf, 16);
+			if (res && ast_func_read2(chan, var->name, &res, 0) == 0) {
+				val = ast_str_buffer(res);
+			} else {
+				val = NULL;
+			}
+		} else {
+			val = pbx_builtin_getvar_helper(chan, var->name);
+		}
+		ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, val ? val : "");
 	}
+	AST_RWLIST_UNLOCK(&channelvars);
 }
 
 /* XXX see if can be moved inside the function */
@@ -6585,11 +5768,6 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount
 		ast_str_append(&buf, 0,
 				"File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
 	}
-	if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
-		ast_str_append(&buf, 0,
-				"SystemName: %s\r\n",
-				 ast_config_AST_SYSTEM_NAME);
-	}
 
 	va_start(ap, fmt);
 	ast_str_append_va(&buf, 0, fmt, ap);
@@ -6677,19 +5855,27 @@ static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info
 
 	switch(info->reason) {
 	case AST_HINT_UPDATE_DEVICE:
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when an extension state has changed.</synopsis>
+			</managerEventInstance>
+		***/
 		manager_event(EVENT_FLAG_CALL, "ExtensionStatus",
 			"Exten: %s\r\n"
 			"Context: %s\r\n"
 			"Hint: %s\r\n"
-			"Status: %d\r\n"
-			"StatusText: %s\r\n",
+			"Status: %d\r\n",
 			exten,
 			context,
 			hint,
-			info->exten_state,
-			ast_extension_state2str(info->exten_state));
+			info->exten_state);
 		break;
 	case AST_HINT_UPDATE_PRESENCE:
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a presence state has changed.</synopsis>
+			</managerEventInstance>
+		***/
 		manager_event(EVENT_FLAG_CALL, "PresenceStatus",
 			"Exten: %s\r\n"
 			"Context: %s\r\n"
@@ -6723,9 +5909,9 @@ static int ast_manager_register_struct(struct manager_action *act)
 			return -1;
 		}
 		if (ret > 0) { /* Insert these alphabetically */
-			prev = cur;
 			break;
 		}
+		prev = cur;
 	}
 
 	ao2_t_ref(act, +1, "action object added to list");
@@ -6759,8 +5945,6 @@ static void action_destroy(void *obj)
 		/* The string fields were initialized. */
 		ast_string_field_free_memory(doomed);
 	}
-	ao2_cleanup(doomed->final_response);
-	ao2_cleanup(doomed->list_responses);
 }
 
 /*! \brief register a new command with manager, including online help. This is
@@ -6769,7 +5953,7 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse
 {
 	struct manager_action *cur;
 
-	cur = ao2_t_alloc(sizeof(*cur), action_destroy, action);
+	cur = ao2_alloc(sizeof(*cur), action_destroy);
 	if (!cur) {
 		return -1;
 	}
@@ -6806,9 +5990,6 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse
 		ast_string_field_set(cur, arguments, tmpxml);
 		ast_free(tmpxml);
 
-		cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL);
-		cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL);
-
 		cur->docsrc = AST_XML_DOC;
 	} else
 #endif
@@ -7306,10 +6487,9 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 {
 	struct mansession s = { .session = NULL, .tcptls_session = ser };
 	struct mansession_session *session = NULL;
-	uint32_t ident;
+	uint32_t ident = 0;
 	int blastaway = 0;
-	struct ast_variable *v;
-	struct ast_variable *params = get_params;
+	struct ast_variable *v, *cookies, *params = get_params;
 	char template[] = "/tmp/ast-http-XXXXXX";	/* template for temporary file */
 	struct ast_str *http_header = NULL, *out = NULL;
 	struct message m = { 0 };
@@ -7318,10 +6498,19 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 
 	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
 	}
 
-	ident = ast_http_manid_from_vars(headers);
+	cookies = ast_http_get_cookies(headers);
+	for (v = cookies; v; v = v->next) {
+		if (!strcasecmp(v->name, "mansession_id")) {
+			sscanf(v->value, "%30x", &ident);
+			break;
+		}
+	}
+	if (cookies) {
+		ast_variables_destroy(cookies);
+	}
 
 	if (!(session = find_session(ident, 1))) {
 
@@ -7330,21 +6519,18 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 		 * While it is not in the list we don't need any locking
 		 */
 		if (!(session = build_mansession(remote_address))) {
-			ast_http_request_close_on_completion(ser);
-			ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
-			return 0;
+			ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
+			return -1;
 		}
 		ao2_lock(session);
 		session->send_events = 0;
 		session->inuse = 1;
-		/*!
-		 * \note There is approximately a 1 in 1.8E19 chance that the following
+		/*!\note There is approximately a 1 in 1.8E19 chance that the following
 		 * calculation will produce 0, which is an invalid ID, but due to the
 		 * properties of the rand() function (and the constantcy of s), that
 		 * won't happen twice in a row.
 		 */
-		while ((session->managerid = ast_random() ^ (unsigned long) session) == 0) {
-		}
+		while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
 		session->last_ev = grab_last();
 		AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
 	}
@@ -7356,8 +6542,7 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 	ast_mutex_init(&s.lock);
 
 	if (http_header == NULL || out == NULL) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
 		goto generic_callback_out;
 	}
 
@@ -7365,36 +6550,19 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 	s.fd = mkstemp(template);	/* create a temporary file for command output */
 	unlink(template);
 	if (s.fd <= -1) {
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
 		goto generic_callback_out;
 	}
 	s.f = fdopen(s.fd, "w+");
 	if (!s.f) {
 		ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
 		close(s.fd);
 		goto generic_callback_out;
 	}
 
 	if (method == AST_HTTP_POST) {
 		params = ast_http_get_post_vars(ser, headers);
-		if (!params) {
-			switch (errno) {
-			case EFBIG:
-				ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
-				close_mansession_file(&s);
-				goto generic_callback_out;
-			case ENOMEM:
-				ast_http_request_close_on_completion(ser);
-				ast_http_error(ser, 500, "Server Error", "Out of memory");
-				close_mansession_file(&s);
-				goto generic_callback_out;
-			case EIO:
-				ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
-				close_mansession_file(&s);
-				goto generic_callback_out;
-			}
-		}
 	}
 
 	for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
@@ -7430,6 +6598,7 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 
 	ast_str_append(&http_header, 0,
 		"Content-type: text/%s\r\n"
+		"Cache-Control: no-cache;\r\n"
 		"Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
 		"Pragma: SuppressEvents\r\n",
 		contenttype[format],
@@ -7494,8 +6663,7 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser,
 	ao2_unlock(session);
 
 	ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
-	http_header = NULL;
-	out = NULL;
+	http_header = out = NULL;
 
 generic_callback_out:
 	ast_mutex_destroy(&s.lock);
@@ -7535,7 +6703,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 	struct ast_variable *v, *params = get_params;
 	char template[] = "/tmp/ast-http-XXXXXX";	/* template for temporary file */
 	struct ast_str *http_header = NULL, *out = NULL;
-	size_t result_size;
+	size_t result_size = 512;
 	struct message m = { 0 };
 	unsigned int idx;
 	size_t hdrlen;
@@ -7555,7 +6723,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 
 	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
 	}
 
 	/* Find "Authorization: " header */
@@ -7571,9 +6739,8 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 
 	/* Digest found - parse */
 	if (ast_string_field_init(&d, 128)) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
-		return 0;
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
+		return -1;
 	}
 
 	if (ast_parse_digest(v->value, &d, 0, 1)) {
@@ -7600,9 +6767,8 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 	if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
 		AST_RWLIST_UNLOCK(&users);
 		ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 403, "Permission denied", "Permission denied");
-		return 0;
+		ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
+		return -1;
 	}
 
 	/* --- We have auth, so check it */
@@ -7651,9 +6817,8 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 		 * While it is not in the list we don't need any locking
 		 */
 		if (!(session = build_mansession(remote_address))) {
-			ast_http_request_close_on_completion(ser);
-			ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
-			return 0;
+			ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
+			return -1;
 		}
 		ao2_lock(session);
 
@@ -7720,36 +6885,19 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 	s.fd = mkstemp(template);	/* create a temporary file for command output */
 	unlink(template);
 	if (s.fd <= -1) {
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
 		goto auth_callback_out;
 	}
 	s.f = fdopen(s.fd, "w+");
 	if (!s.f) {
 		ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
 		close(s.fd);
 		goto auth_callback_out;
 	}
 
 	if (method == AST_HTTP_POST) {
 		params = ast_http_get_post_vars(ser, headers);
-		if (!params) {
-			switch (errno) {
-			case EFBIG:
-				ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
-				close_mansession_file(&s);
-				goto auth_callback_out;
-			case ENOMEM:
-				ast_http_request_close_on_completion(ser);
-				ast_http_error(ser, 500, "Server Error", "Out of memory");
-				close_mansession_file(&s);
-				goto auth_callback_out;
-			case EIO:
-				ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
-				close_mansession_file(&s);
-				goto auth_callback_out;
-			}
-		}
 	}
 
 	for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
@@ -7778,14 +6926,15 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 		m.headers[idx] = NULL;
 	}
 
-	result_size = ftell(s.f); /* Calculate approx. size of result */
+	if (s.f) {
+		result_size = ftell(s.f); /* Calculate approx. size of result */
+	}
 
 	http_header = ast_str_create(80);
 	out = ast_str_create(result_size * 2 + 512);
+
 	if (http_header == NULL || out == NULL) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
-		close_mansession_file(&s);
+		ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
 		goto auth_callback_out;
 	}
 
@@ -7815,8 +6964,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser,
 	}
 
 	ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
-	http_header = NULL;
-	out = NULL;
+	http_header = out = NULL;
 
 auth_callback_out:
 	ast_mutex_destroy(&s.lock);
@@ -8205,43 +7353,6 @@ static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct
 	return CLI_SUCCESS;
 }
 
-static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
-{
-	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
-
-	term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-	term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
-	term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
-	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-
-	if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))) {
-		char *synopsis = ast_xmldoc_printable(ast_str_buffer(instance->synopsis), 1);
-		ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
-		ast_free(synopsis);
-	}
-	if (!ast_strlen_zero(ast_str_buffer(instance->syntax))) {
-		char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
-		ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
-		ast_free(syntax);
-	}
-	if (!ast_strlen_zero(ast_str_buffer(instance->description))) {
-		char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
-		ast_cli(a->fd, "%s%s\n\n", description_title, description);
-		ast_free(description);
-	}
-	if (!ast_strlen_zero(ast_str_buffer(instance->arguments))) {
-		char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
-		ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
-		ast_free(arguments);
-	}
-	if (!ast_strlen_zero(ast_str_buffer(instance->seealso))) {
-		char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
-		ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
-		ast_free(seealso);
-	}
-}
-
 static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup);
@@ -8250,6 +7361,7 @@ static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct
 	int length;
 	int which;
 	char *match = NULL;
+	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
 
 	if (cmd == CLI_INIT) {
 		e->command = "manager show event";
@@ -8290,9 +7402,39 @@ static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct
 		return CLI_SUCCESS;
 	}
 
+	term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
+	term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
+	term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
+	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
+	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
+
 	ast_cli(a->fd, "Event: %s\n", a->argv[3]);
-	for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)) {
-		print_event_instance(a, temp);
+	for (temp = item; temp; temp = temp->next) {
+		if (!ast_strlen_zero(ast_str_buffer(temp->synopsis))) {
+			char *synopsis = ast_xmldoc_printable(ast_str_buffer(temp->synopsis), 1);
+			ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
+			ast_free(synopsis);
+		}
+		if (!ast_strlen_zero(ast_str_buffer(temp->syntax))) {
+			char *syntax = ast_xmldoc_printable(ast_str_buffer(temp->syntax), 1);
+			ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
+			ast_free(syntax);
+		}
+		if (!ast_strlen_zero(ast_str_buffer(temp->description))) {
+			char *description = ast_xmldoc_printable(ast_str_buffer(temp->description), 1);
+			ast_cli(a->fd, "%s%s\n\n", description_title, description);
+			ast_free(description);
+		}
+		if (!ast_strlen_zero(ast_str_buffer(temp->arguments))) {
+			char *arguments = ast_xmldoc_printable(ast_str_buffer(temp->arguments), 1);
+			ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
+			ast_free(arguments);
+		}
+		if (!ast_strlen_zero(ast_str_buffer(temp->seealso))) {
+			char *seealso = ast_xmldoc_printable(ast_str_buffer(temp->seealso), 1);
+			ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
+			ast_free(seealso);
+		}
 	}
 
 	ao2_ref(item, -1);
@@ -8327,25 +7469,34 @@ static struct ast_cli_entry cli_manager[] = {
  */
 static void load_channelvars(struct ast_variable *var)
 {
-        char *parse = NULL;
-        AST_DECLARE_APP_ARGS(args,
-                AST_APP_ARG(vars)[MAX_VARS];
-        );
+	struct manager_channel_variable *mcv;
+	char *remaining = ast_strdupa(var->value);
+	char *next;
 
 	ast_free(manager_channelvars);
 	manager_channelvars = ast_strdup(var->value);
 
-	/* parse the setting */
-	parse = ast_strdupa(manager_channelvars);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	ast_channel_set_manager_vars(args.argc, args.vars);
+	/*
+	 * XXX TODO: To allow dialplan functions to have more than one
+	 * parameter requires eliminating the '|' as a separator so we
+	 * could use AST_STANDARD_APP_ARGS() to separate items.
+	 */
+	free_channelvars();
+	AST_RWLIST_WRLOCK(&channelvars);
+	while ((next = strsep(&remaining, ",|"))) {
+		if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
+			break;
+		}
+		strcpy(mcv->name, next); /* SAFE */
+		if (strchr(next, '(')) {
+			mcv->isfunc = 1;
+		}
+		AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
+	}
+	AST_RWLIST_UNLOCK(&channelvars);
 }
 
-/*!
- * \internal
- * \brief Free a user record.  Should already be removed from the list
- */
+/*! \internal \brief Free a user record.  Should already be removed from the list */
 static void manager_free_user(struct ast_manager_user *user)
 {
 	ast_free(user->a1_hash);
@@ -8361,10 +7512,7 @@ static void manager_free_user(struct ast_manager_user *user)
 	ast_free(user);
 }
 
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void manager_shutdown(void)
 {
 	struct ast_manager_user *user;
@@ -8402,13 +7550,11 @@ static void manager_shutdown(void)
 	ast_manager_unregister("CoreSettings");
 	ast_manager_unregister("CoreStatus");
 	ast_manager_unregister("Reload");
-	ast_manager_unregister("LoggerRotate");
 	ast_manager_unregister("CoreShowChannels");
 	ast_manager_unregister("ModuleLoad");
 	ast_manager_unregister("ModuleCheck");
 	ast_manager_unregister("AOCMessage");
 	ast_manager_unregister("Filter");
-	ast_manager_unregister("BlindTransfer");
 	ast_custom_function_unregister(&managerclient_function);
 	ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
 
@@ -8416,23 +7562,6 @@ static void manager_shutdown(void)
 	ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
 #endif
 
-#ifdef TEST_FRAMEWORK
-	stasis_forward_cancel(test_suite_forwarder);
-	test_suite_forwarder = NULL;
-#endif
-
-	if (stasis_router) {
-		stasis_message_router_unsubscribe_and_join(stasis_router);
-		stasis_router = NULL;
-	}
-	stasis_forward_cancel(rtp_topic_forwarder);
-	rtp_topic_forwarder = NULL;
-	stasis_forward_cancel(security_topic_forwarder);
-	security_topic_forwarder = NULL;
-	ao2_cleanup(manager_topic);
-	manager_topic = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_manager_get_generic_type);
-
 	ast_tcptls_server_stop(&ami_desc);
 	ast_tcptls_server_stop(&amis_desc);
 
@@ -8448,72 +7577,6 @@ static void manager_shutdown(void)
 	while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
 		manager_free_user(user);
 	}
-	acl_change_stasis_unsubscribe();
-}
-
-
-/*! \brief Initialize all \ref stasis topics and routers used by the various
- * sub-components of AMI
- */
-static int manager_subscriptions_init(void)
-{
-	int res = 0;
-
-	rtp_topic_forwarder = stasis_forward_all(ast_rtp_topic(), manager_topic);
-	if (!rtp_topic_forwarder) {
-		return -1;
-	}
-
-	security_topic_forwarder = stasis_forward_all(ast_security_topic(), manager_topic);
-	if (!security_topic_forwarder) {
-		return -1;
-	}
-
-	stasis_router = stasis_message_router_create(manager_topic);
-	if (!stasis_router) {
-		return -1;
-	}
-
-	res |= stasis_message_router_set_default(stasis_router,
-		manager_default_msg_cb, NULL);
-
-	res |= stasis_message_router_add(stasis_router,
-		ast_manager_get_generic_type(), manager_generic_msg_cb, NULL);
-
-	if (res != 0) {
-		return -1;
-	}
-	return 0;
-}
-
-static int subscribe_all(void)
-{
-	if (manager_subscriptions_init()) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize manager subscriptions\n");
-		return -1;
-	}
-	if (manager_system_init()) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize manager system handling\n");
-		return -1;
-	}
-	if (manager_channels_init()) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize manager channel handling\n");
-		return -1;
-	}
-	if (manager_mwi_init()) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize manager MWI handling\n");
-		return -1;
-	}
-	if (manager_bridging_init()) {
-		return -1;
-	}
-	if (manager_endpoints_init()) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize manager endpoints handling\n");
-		return -1;
-	}
-
-	subscribed = 1;
-	return 0;
 }
 
 static void manager_set_defaults(void)
@@ -8538,6 +7601,8 @@ static void manager_set_defaults(void)
 	ami_tls_cfg.pvtfile = ast_strdup("");
 	ast_free(ami_tls_cfg.cipher);
 	ami_tls_cfg.cipher = ast_strdup("");
+
+	free_channelvars();
 }
 
 static int __init_manager(int reload, int by_external_config)
@@ -8561,18 +7626,8 @@ static int __init_manager(int reload, int by_external_config)
 #ifdef AST_XML_DOCS
 		struct ao2_container *temp_event_docs;
 #endif
-		int res;
-
-		ast_register_atexit(manager_shutdown);
 
-		res = STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type);
-		if (res != 0) {
-			return -1;
-		}
-		manager_topic = stasis_topic_create("manager_topic");
-		if (!manager_topic) {
-			return -1;
-		}
+		ast_register_cleanup(manager_shutdown);
 
 		/* Register default actions */
 		ast_manager_register_xml_core("Ping", 0, action_ping);
@@ -8605,17 +7660,11 @@ static int __init_manager(int reload, int by_external_config)
 		ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
 		ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
 		ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
-		ast_manager_register_xml_core("LoggerRotate", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_loggerrotate);
 		ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
 		ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
 		ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
 		ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
 		ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter);
-		ast_manager_register_xml_core("BlindTransfer", EVENT_FLAG_CALL, action_blind_transfer);
-
-#ifdef TEST_FRAMEWORK
-		test_suite_forwarder = stasis_forward_all(ast_test_suite_topic(), manager_topic);
-#endif
 
 		ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
 		__ast_custom_function_register(&managerclient_function, NULL);
@@ -8656,7 +7705,7 @@ static int __init_manager(int reload, int by_external_config)
 
 	/* If this wasn't performed due to a forced reload (because those can be created by ACL change events, we need to unsubscribe to ACL change events. */
 	if (!by_external_config) {
-		acl_change_stasis_unsubscribe();
+		acl_change_event_unsubscribe();
 	}
 
 	if (reload) {
@@ -8744,13 +7793,6 @@ static int __init_manager(int reload, int by_external_config)
 		}
 	}
 
-	if (manager_enabled && !subscribed) {
-		if (subscribe_all() != 0) {
-			ast_log(LOG_ERROR, "Manager subscription error\n");
-			return -1;
-		}
-	}
-
 	ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
 
 	/* if the amis address has not been set, default is the same as non secure ami */
@@ -8791,7 +7833,6 @@ static int __init_manager(int reload, int by_external_config)
 				const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
 				const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
 				const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
-				const char *user_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
 				const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
 
 				/* Look for an existing entry,
@@ -8812,8 +7853,6 @@ static int __init_manager(int reload, int by_external_config)
 					user->writeperm = -1;
 					/* Default displayconnect from [general] */
 					user->displayconnects = displayconnects;
-					/* Default allowmultiplelogin from [general] */
-					user->allowmultiplelogin = allowmultiplelogin;
 					user->writetimeout = 100;
 				}
 
@@ -8829,9 +7868,6 @@ static int __init_manager(int reload, int by_external_config)
 				if (!user_displayconnects) {
 					user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
 				}
-				if (!user_allowmultiplelogin) {
-					user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
-				}
 				if (!user_writetimeout) {
 					user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
 				}
@@ -8850,9 +7886,6 @@ static int __init_manager(int reload, int by_external_config)
 				if (user_displayconnects) {
 					user->displayconnects = ast_true(user_displayconnects);
 				}
-				if (user_allowmultiplelogin) {
-					user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
-				}
 				if (user_writetimeout) {
 					int value = atoi(user_writetimeout);
 					if (value < 100) {
@@ -8888,8 +7921,6 @@ static int __init_manager(int reload, int by_external_config)
 			user->writeperm = 0;
 			/* Default displayconnect from [general] */
 			user->displayconnects = displayconnects;
-			/* Default allowmultiplelogin from [general] */
-			user->allowmultiplelogin = allowmultiplelogin;
 			user->writetimeout = 100;
 			user->whitefilters = ao2_container_alloc(1, NULL, NULL);
 			user->blackfilters = ao2_container_alloc(1, NULL, NULL);
@@ -8926,8 +7957,6 @@ static int __init_manager(int reload, int by_external_config)
 				user->writeperm = get_perm(var->value);
 			}  else if (!strcasecmp(var->name, "displayconnects") ) {
 				user->displayconnects = ast_true(var->value);
-			}  else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
-				user->allowmultiplelogin = ast_true(var->value);
 			} else if (!strcasecmp(var->name, "writetimeout")) {
 				int value = atoi(var->value);
 				if (value < 100) {
@@ -8965,7 +7994,7 @@ static int __init_manager(int reload, int by_external_config)
 
 	/* Check the flag for named ACL event subscription and if we need to, register a subscription. */
 	if (acl_subscription_flag && !by_external_config) {
-		acl_change_stasis_subscribe();
+		acl_change_event_subscribe();
 	}
 
 	/* Perform cleanup - essentially prune out old users that no longer exist */
@@ -9017,6 +8046,12 @@ static int __init_manager(int reload, int by_external_config)
 		httptimeout = newhttptimeout;
 	}
 
+	manager_event(EVENT_FLAG_SYSTEM, "Reload",
+		"Module: Manager\r\n"
+		"Status: %s\r\n"
+		"Message: Manager reload Requested\r\n",
+		manager_enabled ? "Enabled" : "Disabled");
+
 	ast_tcptls_server_start(&ami_desc);
 	if (tls_was_enabled && !ami_tls_cfg.enabled) {
 		ast_tcptls_server_stop(&amis_desc);
@@ -9027,18 +8062,24 @@ static int __init_manager(int reload, int by_external_config)
 	return 0;
 }
 
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
+static void acl_change_event_cb(const struct ast_event *event, void *userdata)
 {
-	if (stasis_message_type(message) != ast_named_acl_change_type()) {
-		return;
-	}
-
 	/* For now, this is going to be performed simply and just execute a forced reload. */
 	ast_log(LOG_NOTICE, "Reloading manager in response to ACL change event.\n");
 	__init_manager(1, 1);
 }
 
+/* clear out every entry in the channelvar list */
+static void free_channelvars(void)
+{
+	struct manager_channel_variable *var;
+	AST_RWLIST_WRLOCK(&channelvars);
+	while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
+		ast_free(var);
+	}
+	AST_RWLIST_UNLOCK(&channelvars);
+}
+
 int init_manager(void)
 {
 	return __init_manager(0, 0);
@@ -9087,64 +8128,3 @@ struct ast_datastore *astman_datastore_find(struct mansession *s, const struct a
 
 	return datastore;
 }
-
-int ast_str_append_event_header(struct ast_str **fields_string,
-					const char *header, const char *value)
-{
-	struct ast_str *working_str = *fields_string;
-
-	if (!working_str) {
-		working_str = ast_str_create(128);
-		if (!working_str) {
-			return -1;
-		}
-		*fields_string = working_str;
-	}
-
-	ast_str_append(&working_str, 0,
-		"%s: %s\r\n",
-		header, value);
-
-	return 0;
-}
-
-static void manager_event_blob_dtor(void *obj)
-{
-	struct ast_manager_event_blob *ev = obj;
-	ast_string_field_free_memory(ev);
-}
-
-struct ast_manager_event_blob *
-__attribute__((format(printf, 3, 4)))
-ast_manager_event_blob_create(
-	int event_flags,
-	const char *manager_event,
-	const char *extra_fields_fmt,
-	...)
-{
-	RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);
-	va_list argp;
-
-	ast_assert(extra_fields_fmt != NULL);
-	ast_assert(manager_event != NULL);
-
-	ev = ao2_alloc(sizeof(*ev), manager_event_blob_dtor);
-	if (!ev) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(ev, 20)) {
-		return NULL;
-	}
-
-	ev->manager_event = manager_event;
-	ev->event_flags = event_flags;
-
-	va_start(argp, extra_fields_fmt);
-	ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
-				      argp);
-	va_end(argp);
-
-	ao2_ref(ev, +1);
-	return ev;
-}
diff --git a/main/manager_bridges.c b/main/manager_bridges.c
deleted file mode 100644
index 29794b5..0000000
--- a/main/manager_bridges.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief The Asterisk Management Interface - AMI (bridge event handling)
- *
- * \author Kinsey Moore <kmoore at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419342 $")
-
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis_message_router.h"
-
-/*! \brief Message router for cached bridge state snapshot updates */
-static struct stasis_message_router *bridge_state_router;
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="BridgeCreate">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a bridge is created.</synopsis>
-			<syntax>
-				<bridge_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="BridgeDestroy">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a bridge is destroyed.</synopsis>
-			<syntax>
-				<bridge_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="BridgeEnter">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel enters a bridge.</synopsis>
-			<syntax>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-				<parameter name="SwapUniqueid">
-					<para>The uniqueid of the channel being swapped out of the bridge</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="BridgeLeave">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel leaves a bridge.</synopsis>
-			<syntax>
-				<bridge_snapshot/>
-				<channel_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="BridgeList" language="en_US">
-		<synopsis>
-			Get a list of bridges in the system.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeType">
-				<para>Optional type for filtering the resulting list of bridges.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Returns a list of bridges, optionally filtering on a bridge type.</para>
-		</description>
-	</manager>
-	<manager name="BridgeInfo" language="en_US">
-		<synopsis>
-			Get information about a bridge.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeUniqueid" required="true">
-				<para>The unique ID of the bridge about which to retreive information.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Returns detailed information about a bridge and the channels in it.</para>
-		</description>
-		<responses>
-			<list-elements>
-				<managerEvent language="en_US" name="BridgeInfoChannel">
-					<managerEventInstance class="EVENT_FLAG_COMMAND">
-						<synopsis>Information about a channel in a bridge.</synopsis>
-						<syntax>
-							<channel_snapshot/>
-						</syntax>
-					</managerEventInstance>
-				</managerEvent>
-			</list-elements>
-			<managerEvent language="en_US" name="BridgeInfoComplete">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>Information about a bridge.</synopsis>
-					<syntax>
-						<bridge_snapshot/>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
-	<manager name="BridgeDestroy" language="en_US">
-		<synopsis>
-			Destroy a bridge.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeUniqueid" required="true">
-				<para>The unique ID of the bridge to destroy.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Deletes the bridge, causing channels to continue or hang up.</para>
-		</description>
-	</manager>
-	<manager name="BridgeKick" language="en_US">
-		<synopsis>
-			Kick a channel from a bridge.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="BridgeUniqueid" required="false">
-				<para>The unique ID of the bridge containing the channel to
-				destroy.  This parameter can be omitted, or supplied to insure
-				that the channel is not removed from the wrong bridge.</para>
-			</parameter>
-			<parameter name="Channel" required="true">
-				<para>The channel to kick out of a bridge.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>The channel is removed from the bridge.</para>
-		</description>
-	</manager>
- ***/
-
-/*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
- * to the manager topic
- */
-static struct stasis_forward *topic_forwarder;
-
-struct ast_str *ast_manager_build_bridge_state_string_prefix(
-	const struct ast_bridge_snapshot *snapshot,
-	const char *prefix)
-{
-	struct ast_str *out = ast_str_create(128);
-	int res;
-
-	if (!out) {
-		return NULL;
-	}
-
-	res = ast_str_set(&out, 0,
-		"%sBridgeUniqueid: %s\r\n"
-		"%sBridgeType: %s\r\n"
-		"%sBridgeTechnology: %s\r\n"
-		"%sBridgeCreator: %s\r\n"
-		"%sBridgeName: %s\r\n"
-		"%sBridgeNumChannels: %u\r\n",
-		prefix, snapshot->uniqueid,
-		prefix, snapshot->subclass,
-		prefix, snapshot->technology,
-		prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
-		prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
-		prefix, snapshot->num_channels);
-	if (!res) {
-		ast_free(out);
-		return NULL;
-	}
-
-	return out;
-}
-
-struct ast_str *ast_manager_build_bridge_state_string(
-	const struct ast_bridge_snapshot *snapshot)
-{
-	return ast_manager_build_bridge_state_string_prefix(snapshot, "");
-}
-
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
-	struct ast_bridge_snapshot *old_snapshot,
-	struct ast_bridge_snapshot *new_snapshot);
-
-/*! \brief Handle bridge creation */
-static struct ast_manager_event_blob *bridge_create(
-	struct ast_bridge_snapshot *old_snapshot,
-	struct ast_bridge_snapshot *new_snapshot)
-{
-	if (!new_snapshot || old_snapshot) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
-}
-
-/*! \brief Handle bridge destruction */
-static struct ast_manager_event_blob *bridge_destroy(
-	struct ast_bridge_snapshot *old_snapshot,
-	struct ast_bridge_snapshot *new_snapshot)
-{
-	if (new_snapshot || !old_snapshot) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
-}
-
-
-bridge_snapshot_monitor bridge_monitors[] = {
-	bridge_create,
-	bridge_destroy,
-};
-
-static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
-	struct stasis_cache_update *update;
-	struct ast_bridge_snapshot *old_snapshot;
-	struct ast_bridge_snapshot *new_snapshot;
-	size_t i;
-
-	update = stasis_message_data(message);
-
-	ast_assert(ast_bridge_snapshot_type() == update->type);
-
-	old_snapshot = stasis_message_data(update->old_snapshot);
-	new_snapshot = stasis_message_data(update->new_snapshot);
-
-	for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
-		RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
-
-		event = bridge_monitors[i](old_snapshot, new_snapshot);
-		if (!event) {
-			continue;
-		}
-
-		/* If we haven't already, build the channel event string */
-		if (!bridge_event_string) {
-			bridge_event_string =
-				ast_manager_build_bridge_state_string(
-					new_snapshot ? new_snapshot : old_snapshot);
-			if (!bridge_event_string) {
-				return;
-			}
-		}
-
-		manager_event(event->event_flags, event->manager_event, "%s%s",
-			ast_str_buffer(bridge_event_string),
-			event->extra_fields);
-	}
-}
-
-static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
-	RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
-
-	ast_assert(merge_msg->to != NULL);
-	ast_assert(merge_msg->from != NULL);
-
-	to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To");
-	from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From");
-	if (!to_text || !from_text) {
-		return;
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when two bridges are merged.</synopsis>
-			<syntax>
-				<bridge_snapshot prefix="To"/>
-				<bridge_snapshot prefix="From"/>
-			</syntax>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_CALL, "BridgeMerge",
-		"%s"
-		"%s",
-		ast_str_buffer(to_text),
-		ast_str_buffer(from_text));
-}
-
-static void channel_enter_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	static const char *swap_name = "SwapUniqueid: ";
-	struct ast_bridge_blob *blob = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
-	const char *swap_id;
-
-	bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
-	channel_text = ast_manager_build_channel_state_string(blob->channel);
-	if (!bridge_text || !channel_text) {
-		return;
-	}
-
-	swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap"));
-
-	manager_event(EVENT_FLAG_CALL, "BridgeEnter",
-		"%s"
-		"%s"
-		"%s%s%s",
-		ast_str_buffer(bridge_text),
-		ast_str_buffer(channel_text),
-		swap_id ? swap_name : "",
-		S_OR(swap_id, ""),
-		swap_id ? "\r\n" : "");
-}
-
-static void channel_leave_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	struct ast_bridge_blob *blob = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
-
-	bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
-	channel_text = ast_manager_build_channel_state_string(blob->channel);
-	if (!bridge_text || !channel_text) {
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, "BridgeLeave",
-		"%s"
-		"%s",
-		ast_str_buffer(bridge_text),
-		ast_str_buffer(channel_text));
-}
-
-static int filter_bridge_type_cb(void *obj, void *arg, int flags)
-{
-	char *bridge_type = arg;
-	struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
-	/* unlink all the snapshots that do not match the bridge type */
-	return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
-}
-
-static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
-	struct mansession *s = arg;
-	char *id_text = data;
-	RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free_ptr);
-
-	if (!bridge_info) {
-		return 0;
-	}
-
-	astman_append(s,
-		"Event: BridgeListItem\r\n"
-		"%s"
-		"%s"
-		"\r\n",
-		ast_str_buffer(bridge_info),
-		id_text);
-	return 0;
-}
-
-static int manager_bridges_list(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	const char *type_filter = astman_get_header(m, "BridgeType");
-	RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
-	RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
-
-	if (!id_text) {
-		astman_send_error(s, m, "Internal error");
-		return -1;
-	}
-
-	if (!ast_strlen_zero(id)) {
-		ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
-	}
-
-	bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
-	if (!bridges) {
-		astman_send_error(s, m, "Internal error");
-		return -1;
-	}
-
-	astman_send_ack(s, m, "Bridge listing will follow");
-
-	if (!ast_strlen_zero(type_filter)) {
-		char *type_filter_dup = ast_strdupa(type_filter);
-		ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, filter_bridge_type_cb, type_filter_dup);
-	}
-
-	ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, ast_str_buffer(id_text));
-
-	astman_append(s,
-		"Event: BridgeListComplete\r\n"
-		"%s"
-		"\r\n",
-		ast_str_buffer(id_text));
-
-	return 0;
-}
-
-static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
-{
-	char *uniqueid = obj;
-	struct mansession *s = arg;
-	char *id_text = data;
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
-	RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
-	msg = stasis_cache_get(ast_channel_cache(),
-		ast_channel_snapshot_type(), uniqueid);
-
-	if (!msg) {
-		return 0;
-	}
-
-	snapshot = stasis_message_data(msg);
-	if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
-		return 0;
-	}
-
-	channel_text = ast_manager_build_channel_state_string(snapshot);
-	if (!channel_text) {
-		return 0;
-	}
-
-	astman_append(s,
-		"Event: BridgeInfoChannel\r\n"
-		"%s"
-		"%s"
-		"\r\n",
-		ast_str_buffer(channel_text),
-		id_text);
-	return 0;
-}
-
-static int manager_bridge_info(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
-	RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
-	struct ast_bridge_snapshot *snapshot;
-
-	if (!id_text) {
-		astman_send_error(s, m, "Internal error");
-		return -1;
-	}
-
-	if (ast_strlen_zero(bridge_uniqueid)) {
-		astman_send_error(s, m, "BridgeUniqueid must be provided");
-		return 0;
-	}
-
-	if (!ast_strlen_zero(id)) {
-		ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
-	}
-
-	msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);
-	if (!msg) {
-		astman_send_error(s, m, "Specified BridgeUniqueid not found");
-		return 0;
-	}
-
-	astman_send_ack(s, m, "Bridge channel listing will follow");
-
-	snapshot = stasis_message_data(msg);
-	bridge_info = ast_manager_build_bridge_state_string(snapshot);
-
-	ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, ast_str_buffer(id_text));
-
-	astman_append(s,
-		"Event: BridgeInfoComplete\r\n"
-		"%s"
-		"%s"
-		"\r\n",
-		S_COR(bridge_info, ast_str_buffer(bridge_info), ""),
-		ast_str_buffer(id_text));
-
-	return 0;
-}
-
-static int manager_bridge_destroy(struct mansession *s, const struct message *m)
-{
-	const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
-	struct ast_bridge *bridge;
-
-	if (ast_strlen_zero(bridge_uniqueid)) {
-		astman_send_error(s, m, "BridgeUniqueid must be provided");
-		return 0;
-	}
-
-	bridge = ast_bridge_find_by_id(bridge_uniqueid);
-	if (!bridge) {
-		astman_send_error(s, m, "Specified BridgeUniqueid not found");
-		return 0;
-	}
-	ast_bridge_destroy(bridge, 0);
-
-	astman_send_ack(s, m, "Bridge has been destroyed");
-
-	return 0;
-}
-
-static int manager_bridge_kick(struct mansession *s, const struct message *m)
-{
-	const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
-	const char *channel_name = astman_get_header(m, "Channel");
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(channel_name)) {
-		astman_send_error(s, m, "Channel must be provided");
-		return 0;
-	}
-
-	channel = ast_channel_get_by_name(channel_name);
-	if (!channel) {
-		astman_send_error(s, m, "Channel does not exist");
-		return 0;
-	}
-
-	if (ast_strlen_zero(bridge_uniqueid)) {
-		/* get the bridge from the channel */
-		ast_channel_lock(channel);
-		bridge = ast_channel_get_bridge(channel);
-		ast_channel_unlock(channel);
-		if (!bridge) {
-			astman_send_error(s, m, "Channel is not in a bridge");
-			return 0;
-		}
-	} else {
-		bridge = ast_bridge_find_by_id(bridge_uniqueid);
-		if (!bridge) {
-			astman_send_error(s, m, "Bridge not found");
-			return 0;
-		}
-	}
-
-	if (ast_bridge_kick(bridge, channel)) {
-		astman_send_error(s, m, "Channel kick from bridge failed");
-		return 0;
-	}
-
-	astman_send_ack(s, m, "Channel has been kicked");
-	return 0;
-}
-
-static void manager_bridging_cleanup(void)
-{
-	stasis_forward_cancel(topic_forwarder);
-	topic_forwarder = NULL;
-}
-
-static void manager_bridging_shutdown(void)
-{
-	ast_manager_unregister("BridgeList");
-	ast_manager_unregister("BridgeInfo");
-	ast_manager_unregister("BridgeDestroy");
-	ast_manager_unregister("BridgeKick");
-}
-
-int manager_bridging_init(void)
-{
-	int ret = 0;
-	struct stasis_topic *manager_topic;
-	struct stasis_topic *bridge_topic;
-
-	if (bridge_state_router) {
-		/* Already initialized */
-		return 0;
-	}
-
-	ast_register_atexit(manager_bridging_shutdown);
-	ast_register_cleanup(manager_bridging_cleanup);
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return -1;
-	}
-
-	bridge_topic = ast_bridge_topic_all_cached();
-	if (!bridge_topic) {
-		return -1;
-	}
-
-	topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
-	if (!topic_forwarder) {
-		return -1;
-	}
-
-	bridge_state_router = ast_manager_get_message_router();
-	if (!bridge_state_router) {
-		return -1;
-	}
-
-	ret |= stasis_message_router_add_cache_update(bridge_state_router,
-		ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);
-
-	ret |= stasis_message_router_add(bridge_state_router,
-		ast_bridge_merge_message_type(), bridge_merge_cb, NULL);
-
-	ret |= stasis_message_router_add(bridge_state_router,
-		ast_channel_entered_bridge_type(), channel_enter_cb, NULL);
-
-	ret |= stasis_message_router_add(bridge_state_router,
-		ast_channel_left_bridge_type(), channel_leave_cb, NULL);
-
-	ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
-	ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
-	ret |= ast_manager_register_xml_core("BridgeDestroy", 0, manager_bridge_destroy);
-	ret |= ast_manager_register_xml_core("BridgeKick", 0, manager_bridge_kick);
-
-	/* If somehow we failed to add any routes, just shut down the whole
-	 * thing and fail it.
-	 */
-	if (ret) {
-		manager_bridging_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/manager_channels.c b/main/manager_channels.c
deleted file mode 100644
index e3c213a..0000000
--- a/main/manager_channels.c
+++ /dev/null
@@ -1,1198 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief The Asterisk Management Interface - AMI (channel event handling)
- *
- * \author David M. Lee, II <dlee at digium.com>
- *
- * AMI generated many per-channel and global-channel events by converting Stasis
- * messages to AMI events. It makes sense to simply put them into a single file.
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
-
-#include "asterisk/callerid.h"
-#include "asterisk/channel.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/pbx.h"
-#include "asterisk/stasis_channels.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="Newchannel">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a new channel is created.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Newstate">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel's state changes.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Hangup">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel is hung up.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Cause">
-					<para>A numeric cause code for why the channel was hung up.</para>
-				</parameter>
-				<parameter name="Cause-txt">
-					<para>A description of why the channel was hung up.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="HangupRequest">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a hangup is requested.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SoftHangupRequest">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="NewExten">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Extension">
-					<para>Deprecated in 12, but kept for
-					backward compatability. Please use
-					'Exten' instead.</para>
-				</parameter>
-				<parameter name="Application">
-					<para>The application about to be executed.</para>
-				</parameter>
-				<parameter name="AppData">
-					<para>The data to be passed to the application.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="NewCallerid">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel receives new Caller ID information.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="CID-CallingPres">
-					<para>A description of the Caller ID presentation.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="NewAccountCode">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a Channel's AccountCode is changed.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="OldAccountCode">
-					<para>The channel's previous account code</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="DialBegin">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a dial action has started.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<parameter name="DialString">
-					<para>The non-technology specific device being dialed.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">Dial</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="DialEnd">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a dial action has completed.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Dest"/>
-				<parameter name="DialStatus">
-					<para>The result of the dial operation.</para>
-					<enumlist>
-						<enum name="ABORT">
-							<para>The call was aborted.</para>
-						</enum>
-						<enum name="ANSWER">
-							<para>The caller answered.</para>
-						</enum>
-						<enum name="BUSY">
-							<para>The caller was busy.</para>
-						</enum>
-						<enum name="CANCEL">
-							<para>The caller cancelled the call.</para>
-						</enum>
-						<enum name="CHANUNAVAIL">
-							<para>The requested channel is unavailable.</para>
-						</enum>
-						<enum name="CONGESTION">
-							<para>The called party is congested.</para>
-						</enum>
-						<enum name="CONTINUE">
-							<para>The dial completed, but the caller elected
-							to continue in the dialplan.</para>
-						</enum>
-						<enum name="GOTO">
-							<para>The dial completed, but the caller jumped to
-							a dialplan location.</para>
-							<para>If known, the location the caller is jumping
-							to will be appended to the result following a
-							":".</para>
-						</enum>
-						<enum name="NOANSWER">
-							<para>The called party failed to answer.</para>
-						</enum>
-					</enumlist>
-				</parameter>
-				<parameter name="Forward" required="false">
-					<para>If the call was forwarded, where the call was
-					forwarded to.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">Dial</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Hold">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel goes on hold.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="MusicClass">
-					<para>The suggested MusicClass, if provided.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="Unhold">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel goes off hold.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChanSpyStart">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when one channel begins spying on another channel.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Spyer"/>
-				<channel_snapshot prefix="Spyee"/>
-			</syntax>
-			<see-also>
-				<ref type="application">ChanSpyStop</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChanSpyStop">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel has stopped spying.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Spyer"/>
-				<channel_snapshot prefix="Spyee"/>
-			</syntax>
-			<see-also>
-				<ref type="application">ChanSpyStart</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="HangupHandlerRun">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>Raised when a hangup handler is about to be called.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Handler">
-					<para>Hangup handler parameter string passed to the Gosub application.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="HangupHandlerPop">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>
-				Raised when a hangup handler is removed from the handler stack
-				by the CHANNEL() function.
-			</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='HangupHandlerRun']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">HangupHandlerPush</ref>
-				<ref type="function">CHANNEL</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="HangupHandlerPush">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>
-				Raised when a hangup handler is added to the handler stack by
-				the CHANNEL() function.
-			</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='HangupHandlerRun']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">HangupHandlerPop</ref>
-				<ref type="function">CHANNEL</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="FAXStatus">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>
-				Raised periodically during a fax transmission.
-			</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Operation">
-					<enumlist>
-						<enum name="gateway"/>
-						<enum name="receive"/>
-						<enum name="send"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Status">
-					<para>A text message describing the current status of the fax</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter[@name='LocalStationID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter[@name='FileName'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ReceiveFAX">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>
-				Raised when a receive fax operation has completed.
-			</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="LocalStationID">
-					<para>The value of the <variable>LOCALSTATIONID</variable> channel variable</para>
-				</parameter>
-				<parameter name="RemoteStationID">
-					<para>The value of the <variable>REMOTESTATIONID</variable> channel variable</para>
-				</parameter>
-				<parameter name="PagesTransferred">
-					<para>The number of pages that have been transferred</para>
-				</parameter>
-				<parameter name="Resolution">
-					<para>The negotiated resolution</para>
-				</parameter>
-				<parameter name="TransferRate">
-					<para>The negotiated transfer rate</para>
-				</parameter>
-				<parameter name="FileName" multiple="yes">
-					<para>The files being affected by the fax operation</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SendFAX">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>
-				Raised when a send fax operation has completed.
-			</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MusicOnHoldStart">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when music on hold has started on a channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Class">
-					<para>The class of music being played on the channel</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MusicOnHoldStop</ref>
-				<ref type="application">MusicOnHold</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MusicOnHoldStop">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when music on hold has stopped on a channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MusicOnHoldStart</ref>
-				<ref type="application">StopMusicOnHold</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MonitorStart">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when monitoring has started on a channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">MonitorStop</ref>
-				<ref type="application">Monitor</ref>
-				<ref type="manager">Monitor</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MonitorStop">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-		<synopsis>Raised when monitoring has stopped on a channel.</synopsis>
-		<syntax>
-			<channel_snapshot/>
-		</syntax>
-		<see-also>
-			<ref type="managerEvent">MonitorStart</ref>
-			<ref type="application">StopMonitor</ref>
-			<ref type="manager">StopMonitor</ref>
-		</see-also>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
-/*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
- * to the manager topic
- */
-static struct stasis_forward *topic_forwarder;
-
-struct ast_str *ast_manager_build_channel_state_string_prefix(
-		const struct ast_channel_snapshot *snapshot,
-		const char *prefix)
-{
-	struct ast_str *out = ast_str_create(1024);
-	int res = 0;
-
-	if (!out) {
-		return NULL;
-	}
-
-	if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
-		ast_free(out);
-		return NULL;
-	}
-
-	res = ast_str_set(&out, 0,
-		"%sChannel: %s\r\n"
-		"%sChannelState: %u\r\n"
-		"%sChannelStateDesc: %s\r\n"
-		"%sCallerIDNum: %s\r\n"
-		"%sCallerIDName: %s\r\n"
-		"%sConnectedLineNum: %s\r\n"
-		"%sConnectedLineName: %s\r\n"
-		"%sAccountCode: %s\r\n"
-		"%sContext: %s\r\n"
-		"%sExten: %s\r\n"
-		"%sPriority: %d\r\n"
-		"%sUniqueid: %s\r\n",
-		prefix, snapshot->name,
-		prefix, snapshot->state,
-		prefix, ast_state2str(snapshot->state),
-		prefix, S_OR(snapshot->caller_number, "<unknown>"),
-		prefix, S_OR(snapshot->caller_name, "<unknown>"),
-		prefix, S_OR(snapshot->connected_number, "<unknown>"),
-		prefix, S_OR(snapshot->connected_name, "<unknown>"),
-		prefix, snapshot->accountcode,
-		prefix, snapshot->context,
-		prefix, snapshot->exten,
-		prefix, snapshot->priority,
-		prefix, snapshot->uniqueid);
-
-	if (!res) {
-		ast_free(out);
-		return NULL;
-	}
-
-	if (snapshot->manager_vars) {
-		struct ast_var_t *var;
-		AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
-			ast_str_append(&out, 0, "%sChanVariable: %s=%s\r\n",
-				       prefix,
-				       var->name, var->value);
-		}
-	}
-
-	return out;
-}
-
-struct ast_str *ast_manager_build_channel_state_string(
-		const struct ast_channel_snapshot *snapshot)
-{
-	return ast_manager_build_channel_state_string_prefix(snapshot, "");
-}
-
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef struct ast_manager_event_blob *(*channel_snapshot_monitor)(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot);
-
-/*! \brief Handle channel state changes */
-static struct ast_manager_event_blob *channel_state_change(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	int is_hungup, was_hungup;
-
-	if (!new_snapshot) {
-		/* Ignore cache clearing events; we'll see the hangup first */
-		return NULL;
-	}
-
-	/* The Newchannel, Newstate and Hangup events are closely related, in
-	 * in that they are mutually exclusive, basically different flavors
-	 * of a new channel state event.
-	 */
-
-	if (!old_snapshot) {
-		return ast_manager_event_blob_create(
-			EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
-	}
-
-	was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
-	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
-
-	if (!was_hungup && is_hungup) {
-		return ast_manager_event_blob_create(
-			EVENT_FLAG_CALL, "Hangup",
-			"Cause: %d\r\n"
-			"Cause-txt: %s\r\n",
-			new_snapshot->hangupcause,
-			ast_cause2str(new_snapshot->hangupcause));
-	}
-
-	if (old_snapshot->state != new_snapshot->state) {
-		return ast_manager_event_blob_create(
-			EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
-	}
-
-	/* No event */
-	return NULL;
-}
-
-static struct ast_manager_event_blob *channel_newexten(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	/* No Newexten event on cache clear */
-	if (!new_snapshot) {
-		return NULL;
-	}
-
-	/* Empty application is not valid for a Newexten event */
-	if (ast_strlen_zero(new_snapshot->appl)) {
-		return NULL;
-	}
-
-	/* Ignore any updates if we're hungup */
-	if (ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD)) {
-		return NULL;
-	}
-
-	/* Ignore updates if the CEP is unchanged */
-	if (old_snapshot && ast_channel_snapshot_cep_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "Newexten",
-		"Extension: %s\r\n"
-		"Application: %s\r\n"
-		"AppData: %s\r\n",
-		new_snapshot->exten,
-		new_snapshot->appl,
-		new_snapshot->data);
-}
-
-static struct ast_manager_event_blob *channel_new_callerid(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	/* No NewCallerid event on cache clear or first event */
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	if (ast_channel_snapshot_caller_id_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "NewCallerid",
-		"CID-CallingPres: %d (%s)\r\n",
-		new_snapshot->caller_pres,
-		ast_describe_caller_presentation(new_snapshot->caller_pres));
-}
-
-static struct ast_manager_event_blob *channel_new_connected_line(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	/* No NewConnectedLine event on cache clear or first event */
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	if (ast_channel_snapshot_connected_line_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "NewConnectedLine", "%s", "");
-}
-
-static struct ast_manager_event_blob *channel_new_accountcode(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot)
-{
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	if (!strcmp(old_snapshot->accountcode, new_snapshot->accountcode)) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(
-		EVENT_FLAG_CALL, "NewAccountCode",
-		"OldAccountCode: %s\r\n", old_snapshot->accountcode);
-}
-
-channel_snapshot_monitor channel_monitors[] = {
-	channel_state_change,
-	channel_newexten,
-	channel_new_callerid,
-	channel_new_accountcode,
-	channel_new_connected_line,
-};
-
-static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	struct stasis_cache_update *update;
-	struct ast_channel_snapshot *old_snapshot;
-	struct ast_channel_snapshot *new_snapshot;
-	size_t i;
-
-	update = stasis_message_data(message);
-
-	ast_assert(ast_channel_snapshot_type() == update->type);
-
-	old_snapshot = stasis_message_data(update->old_snapshot);
-	new_snapshot = stasis_message_data(update->new_snapshot);
-
-	for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {
-		RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);
-		ev = channel_monitors[i](old_snapshot, new_snapshot);
-
-		if (!ev) {
-			continue;
-		}
-
-		/* If we haven't already, build the channel event string */
-		if (!channel_event_string) {
-			channel_event_string =
-				ast_manager_build_channel_state_string(new_snapshot);
-			if (!channel_event_string) {
-				return;
-			}
-		}
-
-		manager_event(ev->event_flags, ev->manager_event, "%s%s",
-			ast_str_buffer(channel_event_string),
-			ev->extra_fields);
-	}
-}
-
-static void publish_basic_channel_event(const char *event, int class, struct ast_channel_snapshot *snapshot)
-{
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	channel_event_string = ast_manager_build_channel_state_string(snapshot);
-	if (!channel_event_string) {
-		return;
-	}
-
-	manager_event(class, event,
-		"%s",
-		ast_str_buffer(channel_event_string));
-}
-
-static void channel_hangup_request_cb(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, extra, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	struct ast_json *cause;
-	int is_soft;
-	char *manager_event = "HangupRequest";
-
-	extra = ast_str_create(20);
-	if (!extra) {
-		return;
-	}
-
-	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-
-	if (!channel_event_string) {
-		return;
-	}
-
-	cause = ast_json_object_get(obj->blob, "cause");
-	if (cause) {
-		ast_str_append(&extra, 0,
-			       "Cause: %jd\r\n",
-			       ast_json_integer_get(cause));
-	}
-
-	is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
-	if (is_soft) {
-		manager_event = "SoftHangupRequest";
-	}
-
-	manager_event(EVENT_FLAG_CALL, manager_event,
-		      "%s%s",
-		      ast_str_buffer(channel_event_string),
-		      ast_str_buffer(extra));
-}
-
-static void channel_chanspy_stop_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, spyer_channel_string, NULL, ast_free);
-	struct ast_channel_snapshot *spyer;
-	struct ast_multi_channel_blob *payload = stasis_message_data(message);
-
-	spyer = ast_multi_channel_blob_get_channel(payload, "spyer_channel");
-	if (!spyer) {
-		ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyer channel!\n");
-		return;
-	}
-
-	spyer_channel_string = ast_manager_build_channel_state_string_prefix(spyer, "Spyer");
-	if (!spyer_channel_string) {
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, "ChanSpyStop",
-		      "%s",
-		      ast_str_buffer(spyer_channel_string));
-}
-
-static void channel_chanspy_start_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, spyer_channel_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, spyee_channel_string, NULL, ast_free);
-	struct ast_channel_snapshot *spyer;
-	struct ast_channel_snapshot *spyee;
-	struct ast_multi_channel_blob *payload = stasis_message_data(message);
-
-	spyer = ast_multi_channel_blob_get_channel(payload, "spyer_channel");
-	if (!spyer) {
-		ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyer channel!\n");
-		return;
-	}
-	spyee = ast_multi_channel_blob_get_channel(payload, "spyee_channel");
-	if (!spyee) {
-		ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyee channel!\n");
-		return;
-	}
-
-	spyer_channel_string = ast_manager_build_channel_state_string_prefix(spyer, "Spyer");
-	if (!spyer_channel_string) {
-		return;
-	}
-	spyee_channel_string = ast_manager_build_channel_state_string_prefix(spyee, "Spyee");
-	if (!spyee_channel_string) {
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
-		      "%s%s",
-		      ast_str_buffer(spyer_channel_string),
-		      ast_str_buffer(spyee_channel_string));
-}
-
-static void channel_dtmf_begin_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	const char *digit =
-		ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
-	const char *direction =
-		ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
-
-	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-
-	if (!channel_event_string) {
-		return;
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when a DTMF digit has started on a channel.</synopsis>
-				<syntax>
-					<channel_snapshot/>
-					<parameter name="Digit">
-						<para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
-					</parameter>
-					<parameter name="Direction">
-						<enumlist>
-							<enum name="Received"/>
-							<enum name="Sent"/>
-						</enumlist>
-					</parameter>
-				</syntax>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_DTMF, "DTMFBegin",
-		"%s"
-		"Digit: %s\r\n"
-		"Direction: %s\r\n",
-		ast_str_buffer(channel_event_string),
-		digit, direction);
-}
-
-static void channel_dtmf_end_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	const char *digit =
-		ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
-	const char *direction =
-		ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
-	long duration_ms =
-		ast_json_integer_get(ast_json_object_get(obj->blob, "duration_ms"));
-
-	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-
-	if (!channel_event_string) {
-		return;
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when a DTMF digit has ended on a channel.</synopsis>
-				<syntax>
-					<channel_snapshot/>
-					<parameter name="Digit">
-						<para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
-					</parameter>
-					<parameter name="DurationMs">
-						<para>Duration (in milliseconds) DTMF was sent/received</para>
-					</parameter>
-					<parameter name="Direction">
-						<enumlist>
-							<enum name="Received"/>
-							<enum name="Sent"/>
-						</enumlist>
-					</parameter>
-				</syntax>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_DTMF, "DTMFEnd",
-		"%s"
-		"Digit: %s\r\n"
-		"DurationMs: %ld\r\n"
-		"Direction: %s\r\n",
-		ast_str_buffer(channel_event_string),
-		digit, duration_ms, direction);
-}
-
-static void channel_hangup_handler_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	struct ast_channel_blob *payload = stasis_message_data(message);
-	const char *action = ast_json_string_get(ast_json_object_get(payload->blob, "type"));
-	const char *handler = ast_json_string_get(ast_json_object_get(payload->blob, "handler"));
-	const char *event;
-
-	channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
-
-	if (!channel_event_string) {
-		return;
-	}
-
-	if (!strcmp(action, "type")) {
-		event = "HangupHandlerRun";
-	} else if (!strcmp(action, "type")) {
-		event = "HangupHandlerPop";
-	} else if (!strcmp(action, "type")) {
-		event = "HangupHandlerPush";
-	} else {
-		return;
-	}
-	manager_event(EVENT_FLAG_DIALPLAN, event,
-		"%s"
-		"Handler: %s\r\n",
-		ast_str_buffer(channel_event_string),
-		handler);
-}
-
-static void channel_fax_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_buffer, ast_str_create(256), ast_free);
-	struct ast_channel_blob *payload = stasis_message_data(message);
-	const char *type = ast_json_string_get(ast_json_object_get(payload->blob, "type"));
-	struct ast_json *operation = ast_json_object_get(payload->blob, "operation");
-	struct ast_json *status = ast_json_object_get(payload->blob, "status");
-	struct ast_json *local_station_id = ast_json_object_get(payload->blob, "local_station_id");
-	struct ast_json *remote_station_id = ast_json_object_get(payload->blob, "remote_station_id");
-	struct ast_json *fax_pages = ast_json_object_get(payload->blob, "fax_pages");
-	struct ast_json *fax_resolution = ast_json_object_get(payload->blob, "fax_resolution");
-	struct ast_json *fax_bitrate = ast_json_object_get(payload->blob, "fax_bitrate");
-	struct ast_json *filenames = ast_json_object_get(payload->blob, "filenames");
-	const char *event;
-	size_t array_len;
-	size_t i;
-
-	if (!event_buffer) {
-		return;
-	}
-
-	channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
-	if (!channel_event_string) {
-		return;
-	}
-
-	if (!strcmp(type, "status")) {
-		event = "FAXStatus";
-	} else if (!strcmp(type, "receive")) {
-		event = "ReceiveFAX";
-	} else if (!strcmp(type, "send")) {
-		event = "SendFAX";
-	} else {
-		return;
-	}
-
-	if (operation) {
-		ast_str_append(&event_buffer, 0, "Operation: %s\r\n", ast_json_string_get(operation));
-	}
-	if (status) {
-		ast_str_append(&event_buffer, 0, "Status: %s\r\n", ast_json_string_get(status));
-	}
-	if (local_station_id) {
-		ast_str_append(&event_buffer, 0, "LocalStationID: %s\r\n", ast_json_string_get(local_station_id));
-	}
-	if (remote_station_id) {
-		ast_str_append(&event_buffer, 0, "RemoteStationID: %s\r\n", ast_json_string_get(remote_station_id));
-	}
-	if (fax_pages) {
-		ast_str_append(&event_buffer, 0, "PagesTransferred: %s\r\n", ast_json_string_get(fax_pages));
-	}
-	if (fax_resolution) {
-		ast_str_append(&event_buffer, 0, "Resolution: %s\r\n", ast_json_string_get(fax_resolution));
-	}
-	if (fax_bitrate) {
-		ast_str_append(&event_buffer, 0, "TransferRate: %s\r\n", ast_json_string_get(fax_bitrate));
-	}
-	if (filenames) {
-		array_len = ast_json_array_size(filenames);
-		for (i = 0; i < array_len; i++) {
-			ast_str_append(&event_buffer, 0, "FileName: %s\r\n", ast_json_string_get(ast_json_array_get(filenames, i)));
-		}
-	}
-
-	manager_event(EVENT_FLAG_CALL, event,
-		"%s"
-		"%s",
-		ast_str_buffer(channel_event_string),
-		ast_str_buffer(event_buffer));
-}
-
-static void channel_moh_start_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_channel_blob *payload = stasis_message_data(message);
-	struct ast_json *blob = payload->blob;
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
-	if (!channel_event_string) {
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, "MusicOnHoldStart",
-		"%s"
-		"Class: %s\r\n",
-		ast_str_buffer(channel_event_string),
-		ast_json_string_get(ast_json_object_get(blob, "class")));
-
-}
-
-static void channel_moh_stop_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_channel_blob *payload = stasis_message_data(message);
-
-	publish_basic_channel_event("MusicOnHoldStop", EVENT_FLAG_CALL, payload->snapshot);
-}
-
-static void channel_monitor_start_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_channel_blob *payload = stasis_message_data(message);
-
-	publish_basic_channel_event("MonitorStart", EVENT_FLAG_CALL, payload->snapshot);
-}
-
-static void channel_monitor_stop_cb(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct ast_channel_blob *payload = stasis_message_data(message);
-
-	publish_basic_channel_event("MonitorStop", EVENT_FLAG_CALL, payload->snapshot);
-}
-
-/*!
- * \brief Callback processing messages for channel dialing
- */
-static void channel_dial_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *obj = stasis_message_data(message);
-	const char *dialstatus;
-	const char *dialstring;
-	const char *forward;
-	struct ast_channel_snapshot *caller;
-	struct ast_channel_snapshot *peer;
-	RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free);
-
-	caller = ast_multi_channel_blob_get_channel(obj, "caller");
-	peer = ast_multi_channel_blob_get_channel(obj, "peer");
-
-	/* Peer is required - otherwise, who are we dialing? */
-	ast_assert(peer != NULL);
-	peer_event_string = ast_manager_build_channel_state_string_prefix(peer, "Dest");
-	if (!peer_event_string) {
-		return;
-	}
-
-	if (caller && !(caller_event_string = ast_manager_build_channel_state_string(caller))) {
-		return;
-	}
-
-	dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus"));
-	dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring"));
-	forward = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "forward"));
-	if (ast_strlen_zero(dialstatus)) {
-		manager_event(EVENT_FLAG_CALL, "DialBegin",
-				"%s"
-				"%s"
-				"DialString: %s\r\n",
-				caller_event_string ? ast_str_buffer(caller_event_string) : "",
-				ast_str_buffer(peer_event_string),
-				S_OR(dialstring, "unknown"));
-	} else {
-		int forwarded = !ast_strlen_zero(forward);
-
-		manager_event(EVENT_FLAG_CALL, "DialEnd",
-				"%s"
-				"%s"
-				"%s%s%s"
-				"DialStatus: %s\r\n",
-				caller_event_string ? ast_str_buffer(caller_event_string) : "",
-				ast_str_buffer(peer_event_string),
-				forwarded ? "Forward: " : "", S_OR(forward, ""), forwarded ? "\r\n" : "",
-				S_OR(dialstatus, "unknown"));
-	}
-
-}
-
-static void channel_hold_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	const char *musicclass;
-	RAII_VAR(struct ast_str *, musicclass_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	if (!(musicclass_string = ast_str_create(32))) {
-		return;
-	}
-
-	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_event_string) {
-		return;
-	}
-
-	if (obj->blob) {
-		musicclass = ast_json_string_get(ast_json_object_get(obj->blob, "musicclass"));
-
-		if (!ast_strlen_zero(musicclass)) {
-			ast_str_set(&musicclass_string, 0, "MusicClass: %s\r\n", musicclass);
-		}
-	}
-
-	manager_event(EVENT_FLAG_CALL, "Hold",
-		"%s"
-		"%s",
-		ast_str_buffer(channel_event_string),
-		ast_str_buffer(musicclass_string));
-}
-
-static void channel_unhold_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_event_string) {
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, "Unhold",
-		"%s",
-		ast_str_buffer(channel_event_string));
-}
-
-static void manager_channels_shutdown(void)
-{
-	stasis_forward_cancel(topic_forwarder);
-	topic_forwarder = NULL;
-}
-
-int manager_channels_init(void)
-{
-	int ret = 0;
-	struct stasis_topic *manager_topic;
-	struct stasis_topic *channel_topic;
-	struct stasis_message_router *message_router;
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return -1;
-	}
-	message_router = ast_manager_get_message_router();
-	if (!message_router) {
-		return -1;
-	}
-	channel_topic = ast_channel_topic_all_cached();
-	if (!channel_topic) {
-		return -1;
-	}
-
-	topic_forwarder = stasis_forward_all(channel_topic, manager_topic);
-	if (!topic_forwarder) {
-		return -1;
-	}
-
-	ast_register_atexit(manager_channels_shutdown);
-
-	ret |= stasis_message_router_add_cache_update(message_router,
-		ast_channel_snapshot_type(), channel_snapshot_update, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_dtmf_begin_type(), channel_dtmf_begin_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_dtmf_end_type(), channel_dtmf_end_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_hangup_request_type(), channel_hangup_request_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_dial_type(), channel_dial_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_hold_type(), channel_hold_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_unhold_type(), channel_unhold_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_fax_type(), channel_fax_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_chanspy_start_type(), channel_chanspy_start_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_chanspy_stop_type(), channel_chanspy_stop_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_hangup_handler_type(), channel_hangup_handler_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_moh_start_type(), channel_moh_start_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_moh_stop_type(), channel_moh_stop_cb, NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_monitor_start_type(), channel_monitor_start_cb,
-		NULL);
-
-	ret |= stasis_message_router_add(message_router,
-		ast_channel_monitor_stop_type(), channel_monitor_stop_cb, NULL);
-
-	/* If somehow we failed to add any routes, just shut down the whole
-	 * thing and fail it.
-	 */
-	if (ret) {
-		manager_channels_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
-
diff --git a/main/manager_endpoints.c b/main/manager_endpoints.c
deleted file mode 100644
index c9cce2a..0000000
--- a/main/manager_endpoints.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief The Asterisk Management Interface - AMI (endpoint handling)
- *
- * \author Joshua Colp <jcolp at digium.com>
- * \author David M. Lee, II <dlee at digium.com>
- *
-  */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400186 $")
-
-#include "asterisk/callerid.h"
-#include "asterisk/channel.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/pbx.h"
-#include "asterisk/stasis_endpoints.h"
-
-static struct stasis_message_router *endpoint_router;
-
-static void manager_endpoints_shutdown(void)
-{
-	stasis_message_router_unsubscribe_and_join(endpoint_router);
-	endpoint_router = NULL;
-}
-
-static void endpoint_state_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	stasis_publish(ast_manager_get_topic(), message);
-}
-
-int manager_endpoints_init(void)
-{
-	struct stasis_topic *endpoint_topic;
-	int ret = 0;
-
-	if (endpoint_router) {
-		/* Already initialized */
-		return 0;
-	}
-
-	ast_register_atexit(manager_endpoints_shutdown);
-
-	endpoint_topic = ast_endpoint_topic_all_cached();
-	if (!endpoint_topic) {
-		return -1;
-	}
-
-	endpoint_router = stasis_message_router_create(endpoint_topic);
-
-	if (!endpoint_router) {
-		return -1;
-	}
-
-	ret |= stasis_message_router_add(endpoint_router, ast_endpoint_state_type(), endpoint_state_cb, NULL);
-
-	/* If somehow we failed to add any routes, just shut down the whole
-	 * thing and fail it.
-	 */
-	if (ret) {
-		manager_endpoints_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
-
diff --git a/main/manager_mwi.c b/main/manager_mwi.c
deleted file mode 100644
index a1dff74..0000000
--- a/main/manager_mwi.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief The Asterisk Management Interface - AMI (MWI event handling)
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400186 $")
-
-#include "asterisk/manager.h"
-#include "asterisk/app.h"
-#include "asterisk/channel.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stasis.h"
-
-struct stasis_message_router *mwi_state_router;
-
-/*** DOCUMENTATION
- ***/
-
-/*! \brief The \ref stasis subscription returned by the forwarding of the MWI topic
- * to the manager topic
- */
-static struct stasis_forward *topic_forwarder;
-
-/*! \brief Callback function used by \ref mwi_app_event_cb to weed out "Event" keys */
-static int exclude_event_cb(const char *key)
-{
-	if (!strcmp(key, "Event")) {
-		return -1;
-	}
-	return 0;
-}
-
-/*! \brief Generic MWI event callback used for one-off events from voicemail modules */
-static void mwi_app_event_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	struct ast_mwi_blob *payload = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
-	struct ast_json *event_json = ast_json_object_get(payload->blob, "Event");
-
-	if (!event_json) {
-		return;
-	}
-
-	if (payload->mwi_state && payload->mwi_state->snapshot) {
-		channel_event_string = ast_manager_build_channel_state_string(payload->mwi_state->snapshot);
-	}
-
-	event_buffer = ast_manager_str_from_json_object(payload->blob, exclude_event_cb);
-	if (!event_buffer) {
-		ast_log(AST_LOG_WARNING, "Failed to create payload for event %s\n", ast_json_string_get(event_json));
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, ast_json_string_get(event_json),
-			"Mailbox: %s\r\n"
-			"%s"
-			"%s",
-			payload->mwi_state ? payload->mwi_state->uniqueid : "Unknown",
-			ast_str_buffer(event_buffer),
-			channel_event_string ? ast_str_buffer(channel_event_string) : "");
-}
-
-static void mwi_update_cb(void *data, struct stasis_subscription *sub,
-				    struct stasis_message *message)
-{
-	struct ast_mwi_state *mwi_state;
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	if (ast_mwi_state_type() != stasis_message_type(message)) {
-		return;
-	}
-
-	mwi_state = stasis_message_data(message);
-	if (!mwi_state) {
-		return;
-	}
-
-	if (mwi_state->snapshot) {
-		channel_event_string = ast_manager_build_channel_state_string(mwi_state->snapshot);
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when the state of messages in a voicemail mailbox
-			has changed or when a channel has finished interacting with a
-			mailbox.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Mailbox">
-					<para>The mailbox with the new message, specified as <literal>mailbox</literal>@<literal>context</literal></para>
-				</parameter>
-				<parameter name="Waiting">
-					<para>Whether or not the mailbox has messages waiting for it.</para>
-				</parameter>
-				<parameter name="New">
-					<para>The number of new messages.</para>
-				</parameter>
-				<parameter name="Old">
-					<para>The number of old messages.</para>
-				</parameter>
-			</syntax>
-			<description>
-				<note><para>The Channel related parameters are only present if a
-				channel was involved in the manipulation of a mailbox. If no
-				channel is involved, the parameters are not included with the
-				event.</para>
-				</note>
-			</description>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_CALL, "MessageWaiting",
-			"%s"
-			"Mailbox: %s\r\n"
-			"Waiting: %d\r\n"
-			"New: %d\r\n"
-			"Old: %d\r\n",
-			AS_OR(channel_event_string, ""),
-			mwi_state->uniqueid,
-			ast_app_has_voicemail(mwi_state->uniqueid, NULL),
-			mwi_state->new_msgs,
-			mwi_state->old_msgs);
-}
-
-static void manager_mwi_shutdown(void)
-{
-	stasis_forward_cancel(topic_forwarder);
-	topic_forwarder = NULL;
-}
-
-int manager_mwi_init(void)
-{
-	int ret = 0;
-	struct stasis_topic *manager_topic;
-	struct stasis_topic *mwi_topic;
-	struct stasis_message_router *message_router;
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return -1;
-	}
-	message_router = ast_manager_get_message_router();
-	if (!message_router) {
-		return -1;
-	}
-	mwi_topic = ast_mwi_topic_all();
-	if (!mwi_topic) {
-		return -1;
-	}
-
-	topic_forwarder = stasis_forward_all(mwi_topic, manager_topic);
-	if (!topic_forwarder) {
-		return -1;
-	}
-
-	ast_register_atexit(manager_mwi_shutdown);
-
-	ret |= stasis_message_router_add(message_router,
-					 ast_mwi_state_type(),
-					 mwi_update_cb,
-					 NULL);
-
-	ret |= stasis_message_router_add(message_router,
-					 ast_mwi_vm_app_type(),
-					 mwi_app_event_cb,
-					 NULL);
-
-	/* If somehow we failed to add any routes, just shut down the whole
-	 * thing and fail it.
-	 */
-	if (ret) {
-		manager_mwi_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/manager_system.c b/main/manager_system.c
deleted file mode 100644
index 1ab7b8b..0000000
--- a/main/manager_system.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jason Parker <jparker at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief System AMI event handling
- *
- * \author Jason Parker <jparker at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400186 $")
-
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stasis_system.h"
-
-/*! \brief The \ref stasis subscription returned by the forwarding of the system topic
- * to the manager topic
- */
-static struct stasis_forward *topic_forwarder;
-
-static void manager_system_shutdown(void)
-{
-	stasis_forward_cancel(topic_forwarder);
-	topic_forwarder = NULL;
-}
-
-int manager_system_init(void)
-{
-	int ret = 0;
-	struct stasis_topic *manager_topic;
-	struct stasis_topic *system_topic;
-	struct stasis_message_router *message_router;
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return -1;
-	}
-	message_router = ast_manager_get_message_router();
-	if (!message_router) {
-		return -1;
-	}
-	system_topic = ast_system_topic();
-	if (!system_topic) {
-		return -1;
-	}
-
-	topic_forwarder = stasis_forward_all(system_topic, manager_topic);
-	if (!topic_forwarder) {
-		return -1;
-	}
-
-	ast_register_atexit(manager_system_shutdown);
-
-	/* If somehow we failed to add any routes, just shut down the whole
-	 * thing and fail it.
-	 */
-	if (ret) {
-		manager_system_shutdown();
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/md5.c b/main/md5.c
index 9342931..5e79729 100644
--- a/main/md5.c
+++ b/main/md5.c
@@ -22,7 +22,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 364462 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/endian.h"
 #include "asterisk/md5.h"
diff --git a/main/media_index.c b/main/media_index.c
deleted file mode 100644
index 3e38245..0000000
--- a/main/media_index.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Sound file format and description indexer.
- */
-
-#include "asterisk.h"
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-#include "asterisk/utils.h"
-#include "asterisk/lock.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/media_index.h"
-#include "asterisk/file.h"
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*! \brief The number of buckets to be used for storing variant-keyed objects */
-#define VARIANT_BUCKETS 7
-
-/*! \brief The number of buckets to be used for storing media filename-keyed objects */
-#define INDEX_BUCKETS 157
-
-/*! \brief Structure to hold a list of the format variations for a media file for a specific variant */
-struct media_variant {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(variant);	/*!< The variant this media is available in */
-		AST_STRING_FIELD(description);	/*!< The description of the media */
-	);
-	struct ast_format_cap *formats;	/*!< The formats this media is available in for this variant */
-};
-
-static void media_variant_destroy(void *obj)
-{
-	struct media_variant *variant = obj;
-
-	ast_string_field_free_memory(variant);
-	ao2_cleanup(variant->formats);
-}
-
-static struct media_variant *media_variant_alloc(const char *variant_str)
-{
-	RAII_VAR(struct media_variant *, variant, ao2_alloc(sizeof(*variant), media_variant_destroy), ao2_cleanup);
-
-	if (!variant || ast_string_field_init(variant, 8)) {
-		return NULL;
-	}
-
-	variant->formats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!variant->formats) {
-		return NULL;
-	}
-
-	ast_string_field_set(variant, variant, variant_str);
-
-	ao2_ref(variant, 1);
-	return variant;
-}
-
-static int media_variant_hash(const void *obj, const int flags)
-{
-	const char *variant = (flags & OBJ_KEY) ? obj : ((struct media_variant*) obj)->variant;
-	return ast_str_case_hash(variant);
-}
-
-static int media_variant_cmp(void *obj, void *arg, int flags)
-{
-	struct media_variant *opt1 = obj, *opt2 = arg;
-	const char *variant = (flags & OBJ_KEY) ? arg : opt2->variant;
-	return strcasecmp(opt1->variant, variant) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-/*! \brief Structure to hold information about a media file */
-struct media_info {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);		/*!< The file name of the media */
-	);
-	struct ao2_container *variants;	/*!< The variants for which this media is available */
-};
-
-static void media_info_destroy(void *obj)
-{
-	struct media_info *info = obj;
-
-	ast_string_field_free_memory(info);
-	ao2_cleanup(info->variants);
-	info->variants = NULL;
-}
-
-static struct media_info *media_info_alloc(const char *name)
-{
-	RAII_VAR(struct media_info *, info, ao2_alloc(sizeof(*info), media_info_destroy), ao2_cleanup);
-
-	if (!info || ast_string_field_init(info, 128)) {
-		return NULL;
-	}
-
-	info->variants = ao2_container_alloc(VARIANT_BUCKETS, media_variant_hash, media_variant_cmp);
-	if (!info->variants) {
-		return NULL;
-	}
-
-	ast_string_field_set(info, name, name);
-
-	ao2_ref(info, 1);
-	return info;
-}
-
-static int media_info_hash(const void *obj, const int flags)
-{
-	const char *name = (flags & OBJ_KEY) ? obj : ((struct media_info*) obj)->name;
-	return ast_str_case_hash(name);
-}
-
-static int media_info_cmp(void *obj, void *arg, int flags)
-{
-	struct media_info *opt1 = obj, *opt2 = arg;
-	const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
-	return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-struct ast_media_index {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(base_dir); /*!< Base directory for indexing */
-	);
-	struct ao2_container *index;            /*!< The index of media that has requested */
-	struct ao2_container *media_list_cache; /*!< Cache of filenames to prevent them from being regenerated so often */
-};
-
-static void media_index_dtor(void *obj)
-{
-	struct ast_media_index *index = obj;
-	ao2_cleanup(index->index);
-	index->index = NULL;
-	ao2_cleanup(index->media_list_cache);
-	index->media_list_cache = NULL;
-	ast_string_field_free_memory(index);
-}
-
-struct ast_media_index *ast_media_index_create(const char *base_dir)
-{
-	RAII_VAR(struct ast_media_index *, index, ao2_alloc(sizeof(*index), media_index_dtor), ao2_cleanup);
-	if (!index || ast_string_field_init(index, 64)) {
-		return NULL;
-	}
-
-	ast_string_field_set(index, base_dir, base_dir);
-
-	index->index = ao2_container_alloc(INDEX_BUCKETS, media_info_hash, media_info_cmp);
-	if (!index->index) {
-		return NULL;
-	}
-
-	ao2_ref(index, +1);
-	return index;
-}
-
-static struct media_variant *find_variant(struct ast_media_index *index, const char *filename, const char *variant)
-{
-	RAII_VAR(struct media_info *, info, NULL, ao2_cleanup);
-
-	info = ao2_find(index->index, filename, OBJ_KEY);
-	if (!info) {
-		return NULL;
-	}
-
-	return ao2_find(info->variants, variant, OBJ_KEY);
-}
-
-/*! \brief create the appropriate media_variant and any necessary structures */
-static struct media_variant *alloc_variant(struct ast_media_index *index, const char *filename, const char *variant_str)
-{
-	RAII_VAR(struct media_info *, info, NULL, ao2_cleanup);
-	RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup);
-
-	info = ao2_find(index->index, filename, OBJ_KEY);
-	if (!info) {
-		/* This is the first time the index has seen this filename,
-		 * allocate and link */
-		info = media_info_alloc(filename);
-		if (!info) {
-			return NULL;
-		}
-
-		ao2_link(index->index, info);
-	}
-
-	variant = ao2_find(info->variants, variant_str, OBJ_KEY);
-	if (!variant) {
-		/* This is the first time the index has seen this variant for
-		 * this filename, allocate and link */
-		variant = media_variant_alloc(variant_str);
-		if (!variant) {
-			return NULL;
-		}
-
-		ao2_link(info->variants, variant);
-	}
-
-	ao2_ref(variant, +1);
-	return variant;
-}
-
-const char *ast_media_get_description(struct ast_media_index *index, const char *filename, const char *variant_str)
-{
-	RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup);
-	if (ast_strlen_zero(filename) || ast_strlen_zero(variant_str)) {
-		return NULL;
-	}
-
-	variant = find_variant(index, filename, variant_str);
-	if (!variant) {
-		return NULL;
-	}
-
-	return variant->description;
-}
-
-struct ast_format_cap *ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant_str)
-{
-	struct ast_format_cap *dupcap;
-	RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup);
-	if (ast_strlen_zero(filename) || ast_strlen_zero(variant_str)) {
-		return NULL;
-	}
-
-	variant = find_variant(index, filename, variant_str);
-	if (!variant) {
-		return NULL;
-	}
-
-	dupcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (dupcap) {
-		ast_format_cap_append_from_cap(dupcap, variant->formats, AST_MEDIA_TYPE_UNKNOWN);
-	}
-	return dupcap;
-}
-
-/*! \brief Add the variant to the list of variants requested */
-static int add_variant_cb(void *obj, void *arg, int flags)
-{
-	struct media_variant *variant = obj;
-	struct ao2_container *variants= arg;
-	ast_str_container_add(variants, variant->variant);
-	return 0;
-}
-
-struct ao2_container *ast_media_get_variants(struct ast_media_index *index, const char *filename)
-{
-	RAII_VAR(struct media_info *, info, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, variants, NULL, ao2_cleanup);
-	if (!filename) {
-		return NULL;
-	}
-
-	variants = ast_str_container_alloc(VARIANT_BUCKETS);
-	if (!variants) {
-		return NULL;
-	}
-
-	info = ao2_find(index->index, filename, OBJ_KEY);
-	if (!info) {
-		return NULL;
-	}
-
-	ao2_callback(info->variants, OBJ_NODATA, add_variant_cb, variants);
-
-	ao2_ref(variants, +1);
-	return variants;
-}
-
-/*! \brief Add the media_info's filename to the container of filenames requested */
-static int add_media_cb(void *obj, void *arg, int flags)
-{
-	struct media_info *info = obj;
-	struct ao2_container *media = arg;
-	ast_str_container_add(media, info->name);
-	return 0;
-}
-
-struct ao2_container *ast_media_get_media(struct ast_media_index *index)
-{
-	RAII_VAR(struct ao2_container *, media, NULL, ao2_cleanup);
-
-	if (!index->media_list_cache) {
-		media = ast_str_container_alloc(INDEX_BUCKETS);
-		if (!media) {
-			return NULL;
-		}
-
-		ao2_callback(index->index, OBJ_NODATA, add_media_cb, media);
-
-		/* Ref to the cache */
-		ao2_ref(media, +1);
-		index->media_list_cache = media;
-	}
-
-	/* Ref to the caller */
-	ao2_ref(index->media_list_cache, +1);
-	return index->media_list_cache;
-}
-
-/*! \brief Update an index with new format/variant information */
-static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, struct ast_format *file_format)
-{
-	RAII_VAR(struct media_variant *, variant, find_variant(index, filename, variant_str), ao2_cleanup);
-	if (!variant) {
-		variant = alloc_variant(index, filename, variant_str);
-		if (!variant) {
-			return -1;
-		}
-	}
-
-	ast_format_cap_append(variant->formats, file_format, 0);
-	return 0;
-}
-
-/*! \brief Process a media file into the index */
-static int process_media_file(struct ast_media_index *index, const char *variant, const char *subdir, const char *filename_stripped, const char *ext)
-{
-	struct ast_format *file_format;
-	const char *file_identifier = filename_stripped;
-	RAII_VAR(struct ast_str *, file_id_str, NULL, ast_free);
-
-	file_format = ast_get_format_for_file_ext(ext);
-	if (!file_format) {
-		/* extension not registered */
-		return 0;
-	}
-
-	/* handle updating the file information */
-	if (subdir) {
-		file_id_str = ast_str_create(64);
-		if (!file_id_str) {
-			return -1;
-		}
-
-		ast_str_set(&file_id_str, 0, "%s/%s", subdir, filename_stripped);
-		file_identifier = ast_str_buffer(file_id_str);
-	}
-
-	if (update_file_format_info(index, file_identifier, variant, file_format)) {
-		return -1;
-	}
-	return 0;
-}
-
-/*!
- * \brief Process a media description text file
- *
- * This currently processes core-sounds-*.txt and extra-sounds-*.txt, but will
- * process others if present.
- */
-static int process_description_file(struct ast_media_index *index,
-	const char *subdir,
-	const char *variant_str,
-	const char *filename)
-{
-	RAII_VAR(struct ast_str *, description_file_path, ast_str_create(64), ast_free);
-	RAII_VAR(struct ast_str *, cumulative_description, ast_str_create(64), ast_free);
-	char *file_id_persist = NULL;
-	int res = 0;
-	FILE *f = NULL;
-#if defined(LOW_MEMORY)
-	char buf[256];
-#else
-	char buf[2048];
-#endif
-
-	if (!description_file_path || !cumulative_description) {
-		return -1;
-	}
-
-	if (ast_strlen_zero(subdir)) {
-		ast_str_set(&description_file_path, 0, "%s/%s/%s", index->base_dir, variant_str, filename);
-	} else {
-		ast_str_set(&description_file_path, 0, "%s/%s/%s/%s", index->base_dir, variant_str, subdir, filename);
-	}
-	f = fopen(ast_str_buffer(description_file_path), "r");
-	if (!f) {
-		ast_log(LOG_WARNING, "Could not open media description file '%s': %s\n", ast_str_buffer(description_file_path), strerror(errno));
-		return -1;
-	}
-
-	while (!feof(f)) {
-		char *file_identifier, *description;
-		if (!fgets(buf, sizeof(buf), f)) {
-			if (ferror(f)) {
-				ast_log(LOG_ERROR, "Error reading from file %s: %s\n", ast_str_buffer(description_file_path), strerror(errno));
-			}
-			continue;
-		}
-
-		/* Skip lines that are too long */
-		if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
-			ast_log(LOG_WARNING, "Line too long, skipping. It begins with: %.32s...\n", buf);
-			while (fgets(buf, sizeof(buf), f)) {
-				if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
-					break;
-				}
-			}
-			if (ferror(f)) {
-				ast_log(LOG_ERROR, "Error reading from file %s: %s\n", ast_str_buffer(description_file_path), strerror(errno));
-			}
-			continue;
-		}
-
-		if (buf[0] == ';') {
-			/* ignore comments */
-			continue;
-		}
-
-		ast_trim_blanks(buf);
-		description = buf;
-		file_identifier = strsep(&description, ":");
-		if (!description) {
-			/* no ':' means this is a continuation */
-			if (file_id_persist) {
-				ast_str_append(&cumulative_description, 0, "\n%s", file_identifier);
-			}
-			continue;
-		} else {
-			/* if there's text in cumulative_description, archive it and start anew */
-			if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
-				RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup);
-
-				variant = find_variant(index, file_id_persist, variant_str);
-				if (!variant) {
-					variant = alloc_variant(index, file_id_persist, variant_str);
-					if (!variant) {
-						res = -1;
-						break;
-					}
-				}
-
-				ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
-
-				ast_str_reset(cumulative_description);
-			}
-
-			ast_free(file_id_persist);
-			file_id_persist = ast_strdup(file_identifier);
-			description = ast_skip_blanks(description);
-			ast_str_set(&cumulative_description, 0, "%s", description);
-		}
-	}
-
-	/* handle the last one */
-	if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
-		RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup);
-
-		variant = find_variant(index, file_id_persist, variant_str);
-		if (!variant) {
-			variant = alloc_variant(index, file_id_persist, variant_str);
-		}
-
-		if (variant) {
-			ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
-		} else {
-			res = -1;
-		}
-	}
-
-	ast_free(file_id_persist);
-	fclose(f);
-	return res;
-}
-
-/*! \brief process an individual file listing */
-static int process_file(struct ast_media_index *index, const char *variant_str, const char *subdir, const char *filename)
-{
-	RAII_VAR(char *, filename_stripped, ast_strdup(filename), ast_free);
-	char *ext;
-
-	if (!filename_stripped) {
-		return -1;
-	}
-
-	ext = strrchr(filename_stripped, '.');
-	if (!ext) {
-		/* file has no extension */
-		return 0;
-	}
-
-	*ext++ = '\0';
-	if (!strcmp(ext, "txt")) {
-		if (process_description_file(index, subdir, variant_str, filename)) {
-			return -1;
-		}
-	} else {
-		if (process_media_file(index, variant_str, subdir, filename_stripped, ext)) {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-/*! \brief internal function for updating the index, recursive */
-static int media_index_update(struct ast_media_index *index,
-	const char *variant,
-	const char *subdir)
-{
-	struct dirent* dent;
-	DIR* srcdir;
-	RAII_VAR(struct ast_str *, index_dir, ast_str_create(64), ast_free);
-	RAII_VAR(struct ast_str *, statfile, ast_str_create(64), ast_free);
-	int res = 0;
-
-	if (!index_dir) {
-		return 0;
-	}
-
-	ast_str_set(&index_dir, 0, "%s", index->base_dir);
-	if (!ast_strlen_zero(variant)) {
-		ast_str_append(&index_dir, 0, "/%s", variant);
-	}
-	if (!ast_strlen_zero(subdir)) {
-		ast_str_append(&index_dir, 0, "/%s", subdir);
-	}
-
-	srcdir = opendir(ast_str_buffer(index_dir));
-	if (srcdir == NULL) {
-		ast_log(LOG_ERROR, "Failed to open %s: %s\n", ast_str_buffer(index_dir), strerror(errno));
-		return -1;
-	}
-
-	while((dent = readdir(srcdir)) != NULL) {
-		struct stat st;
-
-		if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
-			continue;
-		}
-
-		ast_str_reset(statfile);
-		ast_str_set(&statfile, 0, "%s/%s", ast_str_buffer(index_dir), dent->d_name);
-
-		if (stat(ast_str_buffer(statfile), &st) < 0) {
-			ast_log(LOG_WARNING, "Failed to stat %s: %s\n", ast_str_buffer(statfile), strerror(errno));
-			continue;
-		}
-
-		if (S_ISDIR(st.st_mode)) {
-			if (ast_strlen_zero(subdir)) {
-				res = media_index_update(index, variant, dent->d_name);
-			} else {
-				RAII_VAR(struct ast_str *, new_subdir, ast_str_create(64), ast_free);
-				ast_str_set(&new_subdir, 0, "%s/%s", subdir, dent->d_name);
-				res = media_index_update(index, variant, ast_str_buffer(new_subdir));
-			}
-
-			if (res) {
-				break;
-			}
-			continue;
-		}
-
-		if (!S_ISREG(st.st_mode)) {
-			continue;
-		}
-
-		if (process_file(index, variant, subdir, dent->d_name)) {
-			res = -1;
-			break;
-		}
-	}
-
-	closedir(srcdir);
-	return res;
-}
-
-int ast_media_index_update(struct ast_media_index *index,
-	const char *variant)
-{
-	return media_index_update(index, variant, NULL);
-}
-
diff --git a/main/message.c b/main/message.c
index b922fc7..0a43667 100644
--- a/main/message.c
+++ b/main/message.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424692 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -39,7 +39,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424692 $")
 #include "asterisk/manager.h"
 #include "asterisk/strings.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/vector.h"
 #include "asterisk/app.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/message.h"
@@ -123,14 +122,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424692 $")
 		<syntax>
 			<parameter name="to" required="true">
 				<para>A To URI for the message.</para>
-				<xi:include xpointer="xpointer(/docs/info[@name='PJSIPMessageToInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='SIPMessageToInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='XMPPMessageToInfo'])" />
 			</parameter>
 			<parameter name="from" required="false">
 				<para>A From URI for the message if needed for the
 				message technology being used to send this message.</para>
-				<xi:include xpointer="xpointer(/docs/info[@name='PJSIPMessageFromInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='SIPMessageFromInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='XMPPMessageFromInfo'])" />
 			</parameter>
@@ -168,14 +165,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424692 $")
 			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
 			<parameter name="To" required="true">
 				<para>The URI the message is to be sent to.</para>
-				<xi:include xpointer="xpointer(/docs/info[@name='PJSIPMessageToInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='SIPMessageToInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='XMPPMessageToInfo'])" />
 			</parameter>
 			<parameter name="From">
 				<para>A From URI for the message if needed for the
 				message technology being used to send this message.</para>
-				<xi:include xpointer="xpointer(/docs/info[@name='PJSIPMessageFromInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='SIPMessageFromInfo'])" />
 				<xi:include xpointer="xpointer(/docs/info[@name='XMPPMessageFromInfo'])" />
 			</parameter>
@@ -202,46 +197,37 @@ struct msg_data {
 		AST_STRING_FIELD(name);
 		AST_STRING_FIELD(value);
 	);
-	unsigned int send; /* Whether to send out on outbound messages */
+	unsigned int send:1; /* Whether to send out on outbound messages */
 };
 
 AST_LIST_HEAD_NOLOCK(outhead, msg_data);
 
 /*!
  * \brief A message.
+ *
+ * \todo Consider whether stringfields would be an appropriate optimization here.
  */
 struct ast_msg {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Where the message is going */
-		AST_STRING_FIELD(to);
-		/*! Where we "say" the message came from */
-		AST_STRING_FIELD(from);
-		/*! The text to send */
-		AST_STRING_FIELD(body);
-		/*! The dialplan context for the message */
-		AST_STRING_FIELD(context);
-		/*! The dialplan extension for the message */
-		AST_STRING_FIELD(exten);
-		/*! An endpoint associated with this message */
-		AST_STRING_FIELD(endpoint);
-		/*! The technology of the endpoint associated with this message */
-		AST_STRING_FIELD(tech);
-	);
-	/*! Technology/dialplan specific variables associated with the message */
+	struct ast_str *to;
+	struct ast_str *from;
+	struct ast_str *body;
+	struct ast_str *context;
+	struct ast_str *exten;
 	struct ao2_container *vars;
 };
 
-/*! \brief Lock for \c msg_techs vector */
-static ast_rwlock_t msg_techs_lock;
-
-/*! \brief Vector of message technologies */
-AST_VECTOR(, const struct ast_msg_tech *) msg_techs;
-
-/*! \brief Lock for \c msg_handlers vector */
-static ast_rwlock_t msg_handlers_lock;
+struct ast_msg_tech_holder {
+	const struct ast_msg_tech *tech;
+	/*!
+	 * \brief A rwlock for this object
+	 *
+	 * a read/write lock must be used to protect the wrapper instead
+	 * of the ao2 lock. A rdlock must be held to read tech_holder->tech.
+	 */
+	ast_rwlock_t tech_lock;
+};
 
-/*! \brief Vector of received message handlers */
-AST_VECTOR(, const struct ast_msg_handler *) msg_handlers;
+static struct ao2_container *msg_techs;
 
 static struct ast_taskprocessor *msg_q_tp;
 
@@ -397,7 +383,21 @@ static void msg_destructor(void *obj)
 {
 	struct ast_msg *msg = obj;
 
-	ast_string_field_free_memory(msg);
+	ast_free(msg->to);
+	msg->to = NULL;
+
+	ast_free(msg->from);
+	msg->from = NULL;
+
+	ast_free(msg->body);
+	msg->body = NULL;
+
+	ast_free(msg->context);
+	msg->context = NULL;
+
+	ast_free(msg->exten);
+	msg->exten = NULL;
+
 	ao2_ref(msg->vars, -1);
 }
 
@@ -409,7 +409,27 @@ struct ast_msg *ast_msg_alloc(void)
 		return NULL;
 	}
 
-	if (ast_string_field_init(msg, 128)) {
+	if (!(msg->to = ast_str_create(32))) {
+		ao2_ref(msg, -1);
+		return NULL;
+	}
+
+	if (!(msg->from = ast_str_create(32))) {
+		ao2_ref(msg, -1);
+		return NULL;
+	}
+
+	if (!(msg->body = ast_str_create(128))) {
+		ao2_ref(msg, -1);
+		return NULL;
+	}
+
+	if (!(msg->context = ast_str_create(16))) {
+		ao2_ref(msg, -1);
+		return NULL;
+	}
+
+	if (!(msg->exten = ast_str_create(16))) {
 		ao2_ref(msg, -1);
 		return NULL;
 	}
@@ -418,7 +438,8 @@ struct ast_msg *ast_msg_alloc(void)
 		ao2_ref(msg, -1);
 		return NULL;
 	}
-	ast_string_field_set(msg, context, "default");
+
+	ast_str_set(&msg->context, 0, "default");
 
 	return msg;
 }
@@ -432,109 +453,73 @@ struct ast_msg *ast_msg_ref(struct ast_msg *msg)
 struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
 {
 	ao2_ref(msg, -1);
+
 	return NULL;
 }
 
 int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
 {
 	va_list ap;
+	int res;
 
 	va_start(ap, fmt);
-	ast_string_field_build_va(msg, to, fmt, ap);
+	res = ast_str_set_va(&msg->to, 0, fmt, ap);
 	va_end(ap);
 
-	return 0;
+	return res < 0 ? -1 : 0;
 }
 
 int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
 {
 	va_list ap;
+	int res;
 
 	va_start(ap, fmt);
-	ast_string_field_build_va(msg, from, fmt, ap);
+	res = ast_str_set_va(&msg->from, 0, fmt, ap);
 	va_end(ap);
 
-	return 0;
+	return res < 0 ? -1 : 0;
 }
 
 int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
 {
 	va_list ap;
+	int res;
 
 	va_start(ap, fmt);
-	ast_string_field_build_va(msg, body, fmt, ap);
+	res = ast_str_set_va(&msg->body, 0, fmt, ap);
 	va_end(ap);
 
-	return 0;
+	return res < 0 ? -1 : 0;
 }
 
 int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
 {
 	va_list ap;
+	int res;
 
 	va_start(ap, fmt);
-	ast_string_field_build_va(msg, context, fmt, ap);
+	res = ast_str_set_va(&msg->context, 0, fmt, ap);
 	va_end(ap);
 
-	return 0;
+	return res < 0 ? -1 : 0;
 }
 
 int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
 {
 	va_list ap;
+	int res;
 
 	va_start(ap, fmt);
-	ast_string_field_build_va(msg, exten, fmt, ap);
-	va_end(ap);
-
-	return 0;
-}
-
-int ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	ast_string_field_build_va(msg, tech, fmt, ap);
-	va_end(ap);
-
-	return 0;
-}
-
-int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	ast_string_field_build_va(msg, endpoint, fmt, ap);
+	res = ast_str_set_va(&msg->exten, 0, fmt, ap);
 	va_end(ap);
 
-	return 0;
+	return res < 0 ? -1 : 0;
 }
 
 const char *ast_msg_get_body(const struct ast_msg *msg)
 {
-	return msg->body;
-}
-
-const char *ast_msg_get_from(const struct ast_msg *msg)
-{
-	return msg->from;
-}
-
-const char *ast_msg_get_to(const struct ast_msg *msg)
-{
-	return msg->to;
-}
-
-const char *ast_msg_get_tech(const struct ast_msg *msg)
-{
-	return msg->tech;
-}
-
-const char *ast_msg_get_endpoint(const struct ast_msg *msg)
-{
-	return msg->endpoint;
+	return ast_str_buffer(msg->body);
 }
 
 static struct msg_data *msg_data_alloc(void)
@@ -690,17 +675,17 @@ static struct ast_channel *create_msg_q_chan(void)
 
 	chan = ast_channel_alloc(1, AST_STATE_UP,
 			NULL, NULL, NULL,
-			NULL, NULL, NULL, NULL, 0,
+			NULL, NULL, NULL, 0,
 			"%s", "Message/ast_msg_queue");
 
 	if (!chan) {
 		return NULL;
 	}
 
-	ast_channel_tech_set(chan, &msg_chan_tech_hack);
-	ast_channel_unlock(chan);
 	ast_channel_unlink(chan);
 
+	ast_channel_tech_set(chan, &msg_chan_tech_hack);
+
 	if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
 		ast_hangup(chan);
 		return NULL;
@@ -724,7 +709,7 @@ static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
 {
 	struct ast_pbx_args pbx_args;
 
-	ast_explicit_goto(chan, msg->context, S_OR(msg->exten, "s"), 1);
+	ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
 
 	memset(&pbx_args, 0, sizeof(pbx_args));
 	pbx_args.no_hangup_chan = 1,
@@ -743,6 +728,7 @@ static void chan_cleanup(struct ast_channel *chan)
 	struct ast_datastore *msg_ds, *ds;
 	struct varshead *headp;
 	struct ast_var_t *vardata;
+	struct ast_frame *cur;
 
 	ast_channel_lock(chan);
 
@@ -772,6 +758,13 @@ static void chan_cleanup(struct ast_channel *chan)
 	}
 
 	/*
+	 * Remove frames from read queue
+	 */
+	while ((cur = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) {
+		ast_frfree(cur);
+	}
+
+	/*
 	 * Restore msg datastore.
 	 */
 	if (msg_ds) {
@@ -798,9 +791,18 @@ static void destroy_msg_q_chan(void *data)
 
 AST_THREADSTORAGE_CUSTOM(msg_q_chan, NULL, destroy_msg_q_chan);
 
-/*! \internal \brief Handle a message bound for the dialplan */
-static int dialplan_handle_msg_cb(struct ast_msg *msg)
+/*!
+ * \internal
+ * \brief Message queue task processor callback
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note Even though this returns a value, the taskprocessor code ignores the value.
+ */
+static int msg_q_cb(void *data)
 {
+	struct ast_msg *msg = data;
 	struct ast_channel **chan_p, *chan;
 	struct ast_datastore *ds;
 
@@ -826,88 +828,15 @@ static int dialplan_handle_msg_cb(struct ast_msg *msg)
 	msg_route(chan, msg);
 	chan_cleanup(chan);
 
-	return 0;
-}
-
-/*! \internal \brief Determine if a message has a destination in the dialplan */
-static int dialplan_has_destination_cb(const struct ast_msg *msg)
-{
-	if (ast_strlen_zero(msg->context)) {
-		return 0;
-	}
-
-	return ast_exists_extension(NULL, msg->context, S_OR(msg->exten, "s"), 1, NULL);
-}
-
-static struct ast_msg_handler dialplan_msg_handler = {
-	.name = "dialplan",
-	.handle_msg = dialplan_handle_msg_cb,
-	.has_destination = dialplan_has_destination_cb,
-};
-
-/*!
- * \internal
- * \brief Message queue task processor callback
- *
- * \retval 0 success
- * \retval non-zero failure
- *
- * \note Even though this returns a value, the taskprocessor code ignores the value.
- */
-static int msg_q_cb(void *data)
-{
-	struct ast_msg *msg = data;
-	int res = 1;
-	int i;
-
-	ast_rwlock_rdlock(&msg_handlers_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
-		const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
-
-		if (!handler->has_destination(msg)) {
-			ast_debug(5, "Handler %s doesn't want message, moving on\n", handler->name);
-			continue;
-		}
-
-		ast_debug(5, "Dispatching message to %s handler\n", handler->name);
-		res &= handler->handle_msg(msg);
-	}
-	ast_rwlock_unlock(&msg_handlers_lock);
-
-	if (res != 0) {
-		ast_log(LOG_WARNING, "No handler processed message from %s to %s\n",
-			S_OR(msg->from, "<unknown>"), S_OR(msg->to, "<unknown>"));
-	}
-
 	ao2_ref(msg, -1);
 
-	return res;
-}
-
-int ast_msg_has_destination(const struct ast_msg *msg)
-{
-	int i;
-	int result = 0;
-
-	ast_rwlock_rdlock(&msg_handlers_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
-		const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
-
-		ast_debug(5, "Seeing if %s can handle message\n", handler->name);
-		if (handler->has_destination(msg)) {
-			ast_debug(5, "%s can handle message\n", handler->name);
-			result = 1;
-			break;
-		}
-	}
-	ast_rwlock_unlock(&msg_handlers_lock);
-
-	return result;
+	return 0;
 }
 
 int ast_msg_queue(struct ast_msg *msg)
 {
 	int res;
+
 	res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
 	if (res == -1) {
 		ao2_ref(msg, -1);
@@ -974,11 +903,11 @@ static int msg_func_read(struct ast_channel *chan, const char *function,
 	ao2_lock(msg);
 
 	if (!strcasecmp(data, "to")) {
-		ast_copy_string(buf, msg->to, len);
+		ast_copy_string(buf, ast_str_buffer(msg->to), len);
 	} else if (!strcasecmp(data, "from")) {
-		ast_copy_string(buf, msg->from, len);
+		ast_copy_string(buf, ast_str_buffer(msg->from), len);
 	} else if (!strcasecmp(data, "body")) {
-		ast_copy_string(buf, msg->body, len);
+		ast_copy_string(buf, ast_msg_get_body(msg), len);
 	} else {
 		ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
 	}
@@ -1116,57 +1045,57 @@ static int msg_data_func_write(struct ast_channel *chan, const char *function,
 
 	return 0;
 }
-
-/*!
- * \internal \brief Find a \c ast_msg_tech by its technology name
- *
- * \param tech_name The name of the message technology
- *
- * \note \c msg_techs should be locked via \c msg_techs_lock prior to
- *       calling this function
- *
- * \retval NULL if no \c ast_msg_tech has been registered
- * \retval \c ast_msg_tech if registered
- */
-static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
+static int msg_tech_hash(const void *obj, const int flags)
 {
-	const struct ast_msg_tech *current;
-	int i;
+	struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
+	int res = 0;
 
-	for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
-		current = AST_VECTOR_GET(&msg_techs, i);
-		if (!strcmp(current->name, tech_name)) {
-			return current;
-		}
+	ast_rwlock_rdlock(&tech_holder->tech_lock);
+	if (tech_holder->tech) {
+		res = ast_str_case_hash(tech_holder->tech->name);
 	}
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 
-	return NULL;
+	return res;
 }
 
-/*!
- * \internal \brief Find a \c ast_msg_handler by its technology name
- *
- * \param tech_name The name of the message technology
- *
- * \note \c msg_handlers should be locked via \c msg_handlers_lock
- *       prior to calling this function
- *
- * \retval NULL if no \c ast_msg_handler has been registered
- * \retval \c ast_msg_handler if registered
- */
-static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
+static int msg_tech_cmp(void *obj, void *arg, int flags)
 {
-	const struct ast_msg_handler *current;
-	int i;
+	struct ast_msg_tech_holder *tech_holder = obj;
+	const struct ast_msg_tech_holder *tech_holder2 = arg;
+	int res = 1;
 
-	for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
-		current = AST_VECTOR_GET(&msg_handlers, i);
-		if (!strcmp(current->name, tech_name)) {
-			return current;
-		}
+	ast_rwlock_rdlock(&tech_holder->tech_lock);
+	/*
+	 * tech_holder2 is a temporary fake tech_holder.
+	 */
+	if (tech_holder->tech) {
+		res = strcasecmp(tech_holder->tech->name, tech_holder2->tech->name) ? 0 : CMP_MATCH | CMP_STOP;
 	}
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 
-	return NULL;
+	return res;
+}
+
+static struct ast_msg_tech_holder *msg_find_by_tech(const struct ast_msg_tech *msg_tech, int ao2_flags)
+{
+	struct ast_msg_tech_holder *tech_holder;
+	struct ast_msg_tech_holder tmp_tech_holder = {
+		.tech = msg_tech,
+	};
+
+	ast_rwlock_init(&tmp_tech_holder.tech_lock);
+	tech_holder = ao2_find(msg_techs, &tmp_tech_holder, ao2_flags);
+	ast_rwlock_destroy(&tmp_tech_holder.tech_lock);
+	return tech_holder;
+}
+
+static struct ast_msg_tech_holder *msg_find_by_tech_name(const char *tech_name, int ao2_flags)
+{
+	struct ast_msg_tech tmp_msg_tech = {
+		.name = tech_name,
+	};
+	return msg_find_by_tech(&tmp_msg_tech, ao2_flags);
 }
 
 /*!
@@ -1178,7 +1107,7 @@ static int msg_send_exec(struct ast_channel *chan, const char *data)
 	struct ast_datastore *ds;
 	struct ast_msg *msg;
 	char *tech_name;
-	const struct ast_msg_tech *msg_tech;
+	struct ast_msg_tech_holder *tech_holder = NULL;
 	char *parse;
 	int res = -1;
 	AST_DECLARE_APP_ARGS(args,
@@ -1217,10 +1146,9 @@ static int msg_send_exec(struct ast_channel *chan, const char *data)
 	tech_name = ast_strdupa(args.to);
 	tech_name = strsep(&tech_name, ":");
 
-	ast_rwlock_rdlock(&msg_techs_lock);
-	msg_tech = msg_find_by_tech_name(tech_name);
+	tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
 
-	if (!msg_tech) {
+	if (!tech_holder) {
 		ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
 		pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
 		goto exit_cleanup;
@@ -1232,13 +1160,22 @@ static int msg_send_exec(struct ast_channel *chan, const char *data)
 	 * that they could change.
 	 */
 	ao2_lock(msg);
-	res = msg_tech->msg_send(msg, S_OR(args.to, ""), S_OR(args.from, ""));
+	ast_rwlock_rdlock(&tech_holder->tech_lock);
+	if (tech_holder->tech) {
+		res = tech_holder->tech->msg_send(msg, S_OR(args.to, ""),
+							S_OR(args.from, ""));
+	}
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 	ao2_unlock(msg);
 
 	pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
 
 exit_cleanup:
-	ast_rwlock_unlock(&msg_techs_lock);
+	if (tech_holder) {
+		ao2_ref(tech_holder, -1);
+		tech_holder = NULL;
+	}
+
 	ao2_ref(msg, -1);
 
 	return 0;
@@ -1254,7 +1191,7 @@ static int action_messagesend(struct mansession *s, const struct message *m)
 	char *tech_name = NULL;
 	struct ast_variable *vars = NULL;
 	struct ast_variable *data = NULL;
-	const struct ast_msg_tech *msg_tech;
+	struct ast_msg_tech_holder *tech_holder = NULL;
 	struct ast_msg *msg;
 	int res = -1;
 
@@ -1271,32 +1208,34 @@ static int action_messagesend(struct mansession *s, const struct message *m)
 	tech_name = ast_strdupa(to);
 	tech_name = strsep(&tech_name, ":");
 
-	ast_rwlock_rdlock(&msg_techs_lock);
-	msg_tech = msg_find_by_tech_name(tech_name);
-	if (!msg_tech) {
-		ast_rwlock_unlock(&msg_techs_lock);
+	tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
+
+	if (!tech_holder) {
 		astman_send_error(s, m, "Message technology not found.");
 		return 0;
 	}
 
 	if (!(msg = ast_msg_alloc())) {
-		ast_rwlock_unlock(&msg_techs_lock);
+		ao2_ref(tech_holder, -1);
 		astman_send_error(s, m, "Internal failure\n");
 		return 0;
 	}
 
-	data = astman_get_variables_order(m, ORDER_NATURAL);
+	data = astman_get_variables(m);
 	for (vars = data; vars; vars = vars->next) {
 		ast_msg_set_var_outbound(msg, vars->name, vars->value);
 	}
 
 	ast_msg_set_body(msg, "%s", body);
 
-	res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
-
-	ast_rwlock_unlock(&msg_techs_lock);
+	ast_rwlock_rdlock(&tech_holder->tech_lock);
+	if (tech_holder->tech) {
+		res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+	}
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 
 	ast_variables_destroy(vars);
+	ao2_ref(tech_holder, -1);
 	ao2_ref(msg, -1);
 
 	if (res) {
@@ -1310,7 +1249,7 @@ static int action_messagesend(struct mansession *s, const struct message *m)
 int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
 {
 	char *tech_name = NULL;
-	const struct ast_msg_tech *msg_tech;
+	struct ast_msg_tech_holder *tech_holder = NULL;
 	int res = -1;
 
 	if (ast_strlen_zero(to)) {
@@ -1321,19 +1260,20 @@ int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
 	tech_name = ast_strdupa(to);
 	tech_name = strsep(&tech_name, ":");
 
-	ast_rwlock_rdlock(&msg_techs_lock);
-	msg_tech = msg_find_by_tech_name(tech_name);
+	tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
 
-	if (!msg_tech) {
-		ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
-		ast_rwlock_unlock(&msg_techs_lock);
+	if (!tech_holder) {
+		ao2_ref(msg, -1);
 		return -1;
 	}
 
-	res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
-
-	ast_rwlock_unlock(&msg_techs_lock);
+	ast_rwlock_rdlock(&tech_holder->tech_lock);
+	if (tech_holder->tech) {
+		res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+	}
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 
+	ao2_ref(tech_holder, -1);
 	ao2_ref(msg, -1);
 
 	return res;
@@ -1341,111 +1281,52 @@ int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
 
 int ast_msg_tech_register(const struct ast_msg_tech *tech)
 {
-	const struct ast_msg_tech *match;
-
-	ast_rwlock_wrlock(&msg_techs_lock);
+	struct ast_msg_tech_holder *tech_holder;
 
-	match = msg_find_by_tech_name(tech->name);
-	if (match) {
+	if ((tech_holder = msg_find_by_tech(tech, OBJ_POINTER))) {
+		ao2_ref(tech_holder, -1);
 		ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
-		        tech->name);
-		ast_rwlock_unlock(&msg_techs_lock);
+				tech->name);
 		return -1;
 	}
 
-	AST_VECTOR_APPEND(&msg_techs, tech);
-	ast_verb(3, "Message technology '%s' registered.\n", tech->name);
-
-	ast_rwlock_unlock(&msg_techs_lock);
-
-	return 0;
-}
-
-/*!
- * \brief Comparison callback for \c ast_msg_tech vector removal
- *
- * \param vec_elem The element in the vector being compared
- * \param srch The element being looked up
- *
- * \retval non-zero The items are equal
- * \retval 0 The items are not equal
- */
-static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
-{
-	return !strcmp(vec_elem->name, srch->name);
-}
+	if (!(tech_holder = ao2_alloc(sizeof(*tech_holder), NULL))) {
+		return -1;
+	}
 
-int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
-{
-	int match;
+	ast_rwlock_init(&tech_holder->tech_lock);
+	tech_holder->tech = tech;
 
-	ast_rwlock_wrlock(&msg_techs_lock);
-	match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_techs, tech, msg_tech_cmp,
-	                                        AST_VECTOR_ELEM_CLEANUP_NOOP);
-	ast_rwlock_unlock(&msg_techs_lock);
+	ao2_link(msg_techs, tech_holder);
 
-	if (match) {
-		ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
-		return -1;
-	}
+	ao2_ref(tech_holder, -1);
+	tech_holder = NULL;
 
-	ast_verb(2, "Message technology '%s' unregistered.\n", tech->name);
+	ast_verb(3, "Message technology handler '%s' registered.\n", tech->name);
 
 	return 0;
 }
 
-int ast_msg_handler_register(const struct ast_msg_handler *handler)
+int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
 {
-	const struct ast_msg_handler *match;
+	struct ast_msg_tech_holder *tech_holder;
 
-	ast_rwlock_wrlock(&msg_handlers_lock);
+	tech_holder = msg_find_by_tech(tech, OBJ_POINTER | OBJ_UNLINK);
 
-	match = msg_handler_find_by_tech_name(handler->name);
-	if (match) {
-		ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
-		        handler->name);
-		ast_rwlock_unlock(&msg_handlers_lock);
+	if (!tech_holder) {
+		ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
 		return -1;
 	}
 
-	AST_VECTOR_APPEND(&msg_handlers, handler);
-	ast_verb(2, "Message handler '%s' registered.\n", handler->name);
-
-	ast_rwlock_unlock(&msg_handlers_lock);
-
-	return 0;
-
-}
-
-/*!
- * \brief Comparison callback for \c ast_msg_handler vector removal
- *
- * \param vec_elem The element in the vector being compared
- * \param srch The element being looked up
- *
- * \retval non-zero The items are equal
- * \retval 0 The items are not equal
- */
-static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
-{
-	return !strcmp(vec_elem->name, srch->name);
-}
-
-int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
-{
-	int match;
+	ast_rwlock_wrlock(&tech_holder->tech_lock);
+	tech_holder->tech = NULL;
+	ast_rwlock_unlock(&tech_holder->tech_lock);
 
-	ast_rwlock_wrlock(&msg_handlers_lock);
-	match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_handlers, handler, msg_handler_cmp,
-	                                        AST_VECTOR_ELEM_CLEANUP_NOOP);
-	ast_rwlock_unlock(&msg_handlers_lock);
+	ao2_ref(tech_holder, -1);
+	tech_holder = NULL;
 
-	if (match) {
-		ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
-		return -1;
-	}
+	ast_verb(3, "Message technology handler '%s' unregistered.\n", tech->name);
 
-	ast_verb(3, "Message handler '%s' unregistered.\n", handler->name);
 	return 0;
 }
 
@@ -1466,18 +1347,15 @@ void ast_msg_shutdown(void)
  */
 static void message_shutdown(void)
 {
-	ast_msg_handler_unregister(&dialplan_msg_handler);
-
 	ast_custom_function_unregister(&msg_function);
 	ast_custom_function_unregister(&msg_data_function);
 	ast_unregister_application(app_msg_send);
 	ast_manager_unregister("MessageSend");
 
-	AST_VECTOR_FREE(&msg_techs);
-	ast_rwlock_destroy(&msg_techs_lock);
-
-	AST_VECTOR_FREE(&msg_handlers);
-	ast_rwlock_destroy(&msg_handlers_lock);
+	if (msg_techs) {
+		ao2_ref(msg_techs, -1);
+		msg_techs = NULL;
+	}
 }
 
 /*
@@ -1499,24 +1377,17 @@ int ast_msg_init(void)
 		return -1;
 	}
 
-	ast_rwlock_init(&msg_techs_lock);
-	if (AST_VECTOR_INIT(&msg_techs, 8)) {
-		return -1;
-	}
-
-	ast_rwlock_init(&msg_handlers_lock);
-	if (AST_VECTOR_INIT(&msg_handlers, 4)) {
+	msg_techs = ao2_container_alloc(17, msg_tech_hash, msg_tech_cmp);
+	if (!msg_techs) {
 		return -1;
 	}
 
-	res = ast_msg_handler_register(&dialplan_msg_handler);
-
-	res |= __ast_custom_function_register(&msg_function, NULL);
+	res = __ast_custom_function_register(&msg_function, NULL);
 	res |= __ast_custom_function_register(&msg_data_function, NULL);
 	res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
 	res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
 
-	ast_register_atexit(message_shutdown);
+	ast_register_cleanup(message_shutdown);
 
 	return res;
 }
diff --git a/main/mixmonitor.c b/main/mixmonitor.c
deleted file mode 100644
index 290f650..0000000
--- a/main/mixmonitor.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief loadable MixMonitor functionality
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 395686 $")
-
-#include "asterisk/lock.h"
-#include "asterisk/logger.h"
-#include "asterisk/mixmonitor.h"
-#include "asterisk/utils.h"
-#include "asterisk/channel.h"
-
-AST_RWLOCK_DEFINE_STATIC(mixmonitor_lock);
-
-static struct ast_mixmonitor_methods mixmonitor_methods;
-static int table_loaded = 0;
-
-int ast_set_mixmonitor_methods(struct ast_mixmonitor_methods *method_table)
-{
-	SCOPED_WRLOCK(lock, &mixmonitor_lock);
-
-	if (table_loaded) {
-		/* If mixmonitor methods have already been provided, reject the new set */
-		ast_log(LOG_ERROR, "Tried to set mixmonitor methods, but something else has already provided them.\n");
-		return -1;
-	}
-
-	mixmonitor_methods = *method_table;
-
-	table_loaded = 1;
-	return 0;
-}
-
-int ast_clear_mixmonitor_methods(void)
-{
-	SCOPED_WRLOCK(lock, &mixmonitor_lock);
-
-	if (!table_loaded) {
-		ast_log(LOG_ERROR, "Tried to clear mixmonitor methods, but none are currently loaded.\n");
-		return -1;
-	}
-
-	memset(&mixmonitor_methods, 0, sizeof(mixmonitor_methods));
-
-	table_loaded = 0;
-	return 0;
-}
-
-int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
-{
-	SCOPED_RDLOCK(lock, &mixmonitor_lock);
-
-	if (!mixmonitor_methods.start) {
-		ast_log(LOG_ERROR, "No loaded module currently provides MixMonitor starting functionality.\n");
-		return -1;
-	}
-
-	return mixmonitor_methods.start(chan, filename, options);
-}
-
-int ast_stop_mixmonitor(struct ast_channel *chan, const char *mixmon_id)
-{
-	SCOPED_RDLOCK(lock, &mixmonitor_lock);
-
-	if (!mixmonitor_methods.stop) {
-		ast_log(LOG_ERROR, "No loaded module currently provides MixMonitor stopping functionality.\n");
-		return -1;
-	}
-
-	return mixmonitor_methods.stop(chan, mixmon_id);
-}
diff --git a/main/named_acl.c b/main/named_acl.c
index 62aa06d..6f712f7 100644
--- a/main/named_acl.c
+++ b/main/named_acl.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Copyright (C) 2012, Digium, Inc.
  *
@@ -29,38 +29,26 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/config.h"
 #include "asterisk/config_options.h"
+#include "asterisk/event.h"
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/cli.h"
 #include "asterisk/acl.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/paths.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/security_events.h"
 
 #define NACL_CONFIG "acl.conf"
 #define ACL_FAMILY "acls"
 
-/*** DOCUMENTATION
-	<configInfo name="named_acl" language="en_US">
-		<configFile name="named_acl.conf">
-			<configObject name="named_acl">
-				<synopsis>Options for configuring a named ACL</synopsis>
-				<configOption name="permit">
-					<synopsis>An address/subnet from which to allow access</synopsis>
-				</configOption>
-				<configOption name="deny">
-					<synopsis>An address/subnet from which to disallow access</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
+struct named_acl_global_config {
+	AST_DECLARE_STRING_FIELDS(
+		/* Nothing here yet. */
+	);
+};
 
 /*
  * Configuration structure - holds pointers to ao2 containers used for configuration
@@ -68,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
  * time, it's really a config options friendly wrapper for the named ACL container
  */
 struct named_acl_config {
+	struct named_acl_global_config *global;
 	struct ao2_container *named_acl_list;
 };
 
@@ -81,7 +70,6 @@ static void *named_acl_find(struct ao2_container *container, const char *cat);
 /* Config type for named ACL profiles (must not be named general) */
 static struct aco_type named_acl_type = {
 	.type = ACO_ITEM,                  /*!< named_acls are items stored in containers, not individual global objects */
-	.name = "named_acl",
 	.category_match = ACO_BLACKLIST,
 	.category = "^general$",           /*!< Match everything but "general" */
 	.item_alloc = named_acl_alloc,     /*!< A callback to allocate a new named_acl based on category */
@@ -89,16 +77,26 @@ static struct aco_type named_acl_type = {
 	.item_offset = offsetof(struct named_acl_config, named_acl_list), /*!< Could leave this out since 0 */
 };
 
+/* Config type for the general part of the ACL profile (must be named general) */
+static struct aco_type global_option = {
+	.type = ACO_GLOBAL,
+	.item_offset = offsetof(struct named_acl_config, global),
+	.category_match = ACO_WHITELIST,
+	.category = "^general$",
+};
+
 /* This array of aco_type structs is necessary to use aco_option_register */
 struct aco_type *named_acl_types[] = ACO_TYPES(&named_acl_type);
 
+struct aco_type *global_options[] = ACO_TYPES(&global_option);
+
 struct aco_file named_acl_conf = {
 	.filename = "acl.conf",
-	.types = ACO_TYPES(&named_acl_type),
+	.types = ACO_TYPES(&named_acl_type, &global_option),
 };
 
 /* Create a config info struct that describes the config processing for named ACLs. */
-CONFIG_INFO_CORE("named_acl", cfg_info, globals, named_acl_config_alloc,
+CONFIG_INFO_STANDARD(cfg_info, globals, named_acl_config_alloc,
 	.files = ACO_FILES(&named_acl_conf),
 );
 
@@ -126,6 +124,13 @@ static void named_acl_config_destructor(void *obj)
 {
 	struct named_acl_config *cfg = obj;
 	ao2_cleanup(cfg->named_acl_list);
+	ao2_cleanup(cfg->global);
+}
+
+static void named_acl_global_config_destructor(void *obj)
+{
+	struct named_acl_global_config *global = obj;
+	ast_string_field_free_memory(global);
 }
 
 /*! \brief allocator callback for named_acl_config. Notice it returns void * since it is used by
@@ -139,6 +144,14 @@ static void *named_acl_config_alloc(void)
 		return NULL;
 	}
 
+	if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), named_acl_global_config_destructor))) {
+		goto error;
+	}
+
+	if (ast_string_field_init(cfg->global, 128)) {
+		goto error;
+	}
+
 	if (!(cfg->named_acl_list = ao2_container_alloc(37, named_acl_hash_fn, named_acl_cmp_fn))) {
 		goto error;
 	}
@@ -164,7 +177,7 @@ static void destroy_named_acl(void *obj)
  * \retval NULL failure
  *\retval non-NULL successfully allocated named ACL
  */
-static void *named_acl_alloc(const char *cat)
+void *named_acl_alloc(const char *cat)
 {
 	struct named_acl *named_acl;
 
@@ -182,10 +195,10 @@ static void *named_acl_alloc(const char *cat)
  * \brief Find a named ACL in a container by its name
  *
  * \param container ao2container holding the named ACLs
- * \param cat name of the ACL wanted to be found
+ * \param name of the ACL wanted to be found
  * \retval pointer to the named ACL if available. Null if not found.
  */
-static void *named_acl_find(struct ao2_container *container, const char *cat)
+void *named_acl_find(struct ao2_container *container, const char *cat)
 {
 	struct named_acl tmp;
 	ast_copy_string(tmp.name, cat, sizeof(tmp.name));
@@ -296,8 +309,7 @@ static struct named_acl *named_acl_find_realtime(const char *name)
 	return acl;
 }
 
-struct ast_ha *ast_named_acl_find(const char *name, int *is_realtime, int *is_undefined)
-{
+struct ast_ha *ast_named_acl_find(const char *name, int *is_realtime, int *is_undefined) {
 	struct ast_ha *ha = NULL;
 
 	RAII_VAR(struct named_acl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
@@ -357,16 +369,9 @@ struct ast_ha *ast_named_acl_find(const char *name, int *is_realtime, int *is_un
 	return ha;
 }
 
-/*! \brief Message type for named ACL changes */
-STASIS_MESSAGE_TYPE_DEFN(ast_named_acl_change_type);
-
 /*!
  * \internal
- * \brief Sends a stasis message corresponding to a given named ACL that has changed or
- *        that all ACLs have been updated and old copies must be refreshed. Consumers of
- *        named ACLs should subscribe to the ast_security_topic and respond to messages
- *        of the ast_named_acl_change_type stasis message type in order to be able to
- *        accommodate changes to named ACLs.
+ * \brief Sends an update event corresponding to a given named ACL that has changed.
  *
  * \param name Name of the ACL that has changed. May be an empty string (but not NULL)
  *        If name is an empty string, then all ACLs must be refreshed.
@@ -374,38 +379,23 @@ STASIS_MESSAGE_TYPE_DEFN(ast_named_acl_change_type);
  * \retval 0 success
  * \retval 1 failure
  */
-static int publish_acl_change(const char *name)
+static int push_acl_change_event(char *name)
 {
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref);
-
-	if (!json_object || !ast_named_acl_change_type()) {
-		goto publish_failure;
-	}
-
-	if (ast_json_object_set(json_object, "name", ast_json_string_create(name))) {
-		goto publish_failure;
-	}
-
-	if (!(json_payload = ast_json_payload_create(json_object))) {
-		goto publish_failure;
+	struct ast_event *event = ast_event_new(AST_EVENT_ACL_CHANGE,
+							AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, name,
+							AST_EVENT_IE_END);
+	if (!event) {
+		ast_log(LOG_ERROR, "Failed to allocate acl.conf reload event. Some modules will have out of date ACLs.\n");
+		return -1;
 	}
 
-	msg = stasis_message_create(ast_named_acl_change_type(), json_payload);
-
-	if (!msg) {
-		goto publish_failure;
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		ast_log(LOG_ERROR, "Failed to queue acl.conf reload event. Some modules will have out of date ACLs.\n");
+		return -1;
 	}
 
-	stasis_publish(ast_security_topic(), msg);
-
 	return 0;
-
-publish_failure:
-	ast_log(LOG_ERROR, "Failed to to issue ACL change message for %s.\n",
-		ast_strlen_zero(name) ? "all named ACLs" : name);
-	return -1;
 }
 
 /*!
@@ -433,7 +423,7 @@ int ast_named_acl_reload(void)
 	}
 
 	/* We need to push an ACL change event with no ACL name so that all subscribers update with all ACLs */
-	publish_acl_change("");
+	push_acl_change_event("");
 
 	return 0;
 }
@@ -569,7 +559,6 @@ static void named_acl_cleanup(void)
 {
 	ast_cli_unregister_multiple(cli_named_acl, ARRAY_LEN(cli_named_acl));
 
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_named_acl_change_type);
 	aco_info_destroy(&cfg_info);
 	ao2_global_obj_release(globals);
 }
@@ -578,8 +567,6 @@ int ast_named_acl_init()
 {
 	ast_cli_register_multiple(cli_named_acl, ARRAY_LEN(cli_named_acl));
 
-	STASIS_MESSAGE_TYPE_INIT(ast_named_acl_change_type);
-
 	ast_register_cleanup(named_acl_cleanup);
 
 	if (aco_info_init(&cfg_info)) {
@@ -590,10 +577,7 @@ int ast_named_acl_init()
 	aco_option_register(&cfg_info, "permit", ACO_EXACT, named_acl_types, NULL, OPT_ACL_T, 1, FLDSET(struct named_acl, ha));
 	aco_option_register(&cfg_info, "deny", ACO_EXACT, named_acl_types, NULL, OPT_ACL_T, 0, FLDSET(struct named_acl, ha));
 
-	if (aco_process_config(&cfg_info, 0)) {
-		aco_info_destroy(&cfg_info);
-		return 0;
-	}
+	aco_process_config(&cfg_info, 0);
 
 	return 0;
 }
diff --git a/main/netsock.c b/main/netsock.c
index 4918989..3d92f96 100644
--- a/main/netsock.c
+++ b/main/netsock.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417167 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifndef __linux__
 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) || defined(__GLIBC__)
@@ -117,7 +117,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
 	const int reuseFlag = 1;
 
 	/* Make a UDP socket */
-	netsocket = socket(ast_sockaddr_is_ipv6(bindaddr) ? AST_AF_INET6 : AST_AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
 	if (netsocket < 0) {
 		ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
@@ -155,7 +155,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
 	ns->ioc = ioc;
 	ns->sockfd = netsocket;
 	ns->data = data;
-	ast_sockaddr_copy(&ns->bindaddr, bindaddr);
+	memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
 	ASTOBJ_CONTAINER_LINK(list, ns);
 
 	return ns;
@@ -171,6 +171,10 @@ struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_co
 	struct ast_sockaddr addr;
 
 	if (ast_sockaddr_parse(&addr, bindinfo, 0)) {
+		if (!ast_sockaddr_is_ipv4(&addr)) {
+			ast_log(LOG_WARNING, "Only IPv4 addresses are supported at this time.\n");
+			return NULL;
+		}
 
 		if (!ast_sockaddr_port(&addr)) {
 			ast_sockaddr_set_port(&addr, defaultport);
@@ -201,3 +205,106 @@ void ast_netsock_unref(struct ast_netsock *ns)
 {
 	ASTOBJ_UNREF(ns, ast_netsock_destroy);
 }
+
+char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
+{
+	int x;
+	char *os = s;
+	if (maxlen < 18) {
+		if (s && (maxlen > 0))
+			*s = '\0';
+	} else {
+		for (x = 0; x < 5; x++) {
+			sprintf(s, "%02hhx:", eid->eid[x]);
+			s += 3;
+		}
+		sprintf(s, "%02hhx", eid->eid[5]);
+	}
+	return os;
+}
+
+void ast_set_default_eid(struct ast_eid *eid)
+{
+#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
+	int s, x = 0;
+	char eid_str[20];
+	struct ifreq ifr;
+	static const unsigned int MAXIF = 10;
+
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s < 0)
+		return;
+	for (x = 0; x < MAXIF; x++) {
+		static const char *prefixes[] = { "eth", "em" };
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_LEN(prefixes); i++) {
+			memset(&ifr, 0, sizeof(ifr));
+			snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
+			if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
+				break;
+			}
+		}
+
+		if (i == ARRAY_LEN(prefixes)) {
+			/* Try pciX#[1..N] */
+			for (i = 0; i < MAXIF; i++) {
+				memset(&ifr, 0, sizeof(ifr));
+				snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i);
+				if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
+					break;
+				}
+			}
+			if (i == MAXIF) {
+				continue;
+			}
+		}
+
+		memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid));
+		ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr.ifr_name);
+		close(s);
+		return;
+	}
+	close(s);
+#else
+#if defined(ifa_broadaddr) && !defined(SOLARIS)
+	char eid_str[20];
+	struct ifaddrs *ifap;
+
+	if (getifaddrs(&ifap) == 0) {
+		struct ifaddrs *p;
+		for (p = ifap; p; p = p->ifa_next) {
+			if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
+				struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
+				memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
+				ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name);
+				freeifaddrs(ifap);
+				return;
+			}
+		}
+		freeifaddrs(ifap);
+	}
+#endif
+#endif
+	ast_debug(1, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
+}
+
+int ast_str_to_eid(struct ast_eid *eid, const char *s)
+{
+	unsigned int eid_int[6];
+	int x;
+
+	if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
+		 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
+			return -1;
+
+	for (x = 0; x < 6; x++)
+		eid->eid[x] = eid_int[x];
+
+	return 0;
+}
+
+int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
+{
+	return memcmp(eid1, eid2, sizeof(*eid1));
+}
diff --git a/main/netsock2.c b/main/netsock2.c
index 7519379..c53ad06 100644
--- a/main/netsock2.c
+++ b/main/netsock2.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416738 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/config.h"
 #include "asterisk/netsock2.h"
@@ -129,40 +129,6 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
 	return ast_str_buffer(str);
 }
 
-int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa)
-{
-	struct ast_sockaddr sa_ipv4;
-	const struct ast_sockaddr *sa_tmp;
-	int bits = 0;
-	int bytes;
-	int i;
-	int j;
-	char *addr;
-
-	if (ast_sockaddr_isnull(sa)) {
-		return 0;
-	}
-
-	if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) {
-		sa_tmp = &sa_ipv4;
-	} else {
-		sa_tmp = sa;
-	}
-
-	bytes = sa_tmp->len;
-	addr = ((struct sockaddr *)&sa_tmp->ss)->sa_data;
-
-	for (i = 0; i < bytes ; ++i) {
-		for (j = 0; j < 8; ++j) {
-			if ((addr[i] >> j) & 1) {
-				bits++;
-			}
-		}
-	}
-
-	return bits;
-}
-
 int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
 {
 	char *s = str;
@@ -287,11 +253,13 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
 	int	e, i, res_cnt;
 
 	if (!str) {
+		*addrs = NULL;
 		return 0;
 	}
 
 	s = ast_strdupa(str);
 	if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
+		*addrs = NULL;
 		return 0;
 	}
 
@@ -302,6 +270,7 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
 	if ((e = getaddrinfo(host, port, &hints, &res))) {
 		ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
 			host, S_OR(port, "(null)"), gai_strerror(e));
+		*addrs = NULL;
 		return 0;
 	}
 
@@ -311,6 +280,7 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
 	}
 
 	if (res_cnt == 0) {
+		*addrs = NULL;
 		goto cleanup;
 	}
 
@@ -331,37 +301,6 @@ cleanup:
 	return res_cnt;
 }
 
-int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
-		struct ast_sockaddr *result)
-{
-	int res = 0;
-
-	if (ast_sockaddr_is_ipv4(addr)) {
-		struct sockaddr_in result4 = { 0, };
-		struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
-		struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
-		result4.sin_family = AF_INET;
-		result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
-		ast_sockaddr_from_sin(result, &result4);
-	} else if (ast_sockaddr_is_ipv6(addr)) {
-		struct sockaddr_in6 result6 = { 0, };
-		struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
-		struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
-		int i;
-		result6.sin6_family = AF_INET6;
-		for (i = 0; i < 4; ++i) {
-			V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
-		}
-		memcpy(&result->ss, &result6, sizeof(result6));
-		result->len = sizeof(result6);
-	} else {
-		/* Unsupported address scheme */
-		res = -1;
-	}
-
-	return res;
-}
-
 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
 {
 	const struct ast_sockaddr *a_tmp, *b_tmp;
@@ -523,24 +462,6 @@ int ast_sockaddr_hash(const struct ast_sockaddr *addr)
 	}
 }
 
-const char *ast_transport2str(enum ast_transport transport)
-{
-	switch (transport) {
-	case AST_TRANSPORT_TLS:
-		return "TLS";
-	case AST_TRANSPORT_UDP:
-		return "UDP";
-	case AST_TRANSPORT_TCP:
-		return "TCP";
-	case AST_TRANSPORT_WS:
-		return "WS";
-	case AST_TRANSPORT_WSS:
-		return "WSS";
-	}
-
-	return "Undefined";
-}
-
 int ast_accept(int sockfd, struct ast_sockaddr *addr)
 {
 	addr->len = sizeof(addr->ss);
diff --git a/main/optional_api.c b/main/optional_api.c
deleted file mode 100644
index 5af3868..0000000
--- a/main/optional_api.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 414798 $")
-
-#include "asterisk/optional_api.h"
-#include "asterisk/utils.h"
-
-#if defined(OPTIONAL_API)
-
-/*
- * \file Optional API innards.
- *
- * The calls to ast_optional_api_*() happen implicitly from \c __constructor__
- * calls which are defined in header files. This means that some number of them
- * happen before main() is called. This makes calling most Asterisk APIs
- * dangerous, since we could be called before they are initialized. This
- * includes things like AO2, malloc debug, and static mutexes.
- *
- * Another limitation is that most functions are called from the midst of
- * dlopen() or dlclose(), and there is no opportunity to return a failure code.
- * The best we can do is log an error, and call ast_do_crash().
- *
- * Fortunately, there are some constraints that help us out. The \c
- * ast_optional_api_*() are called during module loads, which happens either
- * before main(), or during dlopen() calls. These are already serialized, so we
- * don't have to lock ourselves.
- */
-
-/*! \brief A user of an optional API */
-struct optional_api_user {
-	/*! Pointer to function pointer to link */
-	ast_optional_fn *optional_ref;
-	/*! Stub to use when impl is unavailable */
-	ast_optional_fn stub;
-	/*! Name of the module using the API */
-	char module[];
-};
-
-/*! \brief An optional API */
-struct optional_api {
-	/*! Pointer to the implementation function; could be null */
-	ast_optional_fn impl;
-	/*! Variable length array of users of this API */
-	struct optional_api_user **users;
-	/*! Allocated size of the \a users array */
-	size_t users_maxlen;
-	/*! Number of entries in the \a users array */
-	size_t users_len;
-	/*! Name of the optional API function */
-	char symname[];
-};
-
-/*!
- * \brief Free an \ref optional_api_user.
- *
- * \param user User struct to free.
- */
-static void optional_api_user_destroy(struct optional_api_user *user)
-{
-	*user->optional_ref = user->stub;
-	ast_std_free(user);
-}
-
-/*!
- * \brief Create an \ref optional_api_user.
- *
- * \param optional_ref Pointer-to-function-pointer to link to impl/stub.
- * \param stub Stub function to link to when impl is not available.
- * \param module Name of the module requesting the API.
- *
- * \return New \ref optional_api_user.
- * \return \c NULL on error.
- */
-static struct optional_api_user *optional_api_user_create(
-	ast_optional_fn *optional_ref, ast_optional_fn stub, const char *module)
-{
-	struct optional_api_user *user;
-	size_t size = sizeof(*user) + strlen(module) + 1;
-
-	user = ast_std_calloc(1, size);
-	if (!user) {
-		return NULL;
-	}
-
-	user->optional_ref = optional_ref;
-	user->stub = stub;
-	strcpy(user->module, module); /* SAFE */
-
-	return user;
-}
-
-/*!
- * \brief Free an \ref optional_api.
- *
- * \param api API struct to free.
- */
-static void optional_api_destroy(struct optional_api *api)
-{
-	while (api->users_len--) {
-		optional_api_user_destroy(api->users[api->users_len]);
-	}
-	ast_std_free(api->users);
-	api->users = NULL;
-	api->users_maxlen = 0;
-	ast_std_free(api);
-}
-
-/*!
- * \brief Create an \ref optional_api.
- *
- * \param symname Name of the optional function.
- * \return New \ref optional_api.
- * \return \c NULL on error.
- */
-static struct optional_api *optional_api_create(const char *symname)
-{
-	struct optional_api *api;
-	size_t size;
-
-	size = sizeof(*api) + strlen(symname) + 1;
-	api = ast_std_calloc(1, size);
-	if (!api) {
-		ast_log(LOG_ERROR, "Failed to allocate api\n");
-		return NULL;
-	}
-
-	strcpy(api->symname, symname); /* SAFE */
-
-	return api;
-}
-
-/*! Array of \ref optional_api functions */
-struct {
-	/*! Variable length array of API's */
-	struct optional_api **list;
-	/*! Allocated size of the \a list array */
-	size_t maxlen;
-	/*! Number of entries in the \a list array */
-	size_t len;
-} apis;
-
-/*!
- * \brief Gets (or creates) the \ref optional_api for the given function.
- *
- * \param sysname Name of the function to look up.
- * \return Corresponding \ref optional_api.
- * \return \c NULL on error.
- */
-static struct optional_api *get_api(const char *symname)
-{
-	struct optional_api *api;
-	size_t i;
-
-	/* Find one, if we already have it */
-	if (apis.list) {
-		for (i = 0; i < apis.len; ++i) {
-			if (strcmp(symname, apis.list[i]->symname) == 0) {
-				return apis.list[i];
-			}
-		}
-	}
-
-	/* API not found. Build one */
-	api = optional_api_create(symname);
-	if (!api) {
-		return NULL;
-	}
-
-	/* Grow the list, if needed */
-	if (apis.len + 1 > apis.maxlen) {
-		size_t new_maxlen = apis.maxlen ? 2 * apis.maxlen : 1;
-		struct optional_api **new_list;
-
-		new_list = ast_std_realloc(apis.list, new_maxlen * sizeof(*new_list));
-		if (!new_list) {
-			optional_api_destroy(api);
-			ast_log(LOG_ERROR, "Failed to allocate api list\n");
-			return NULL;
-		}
-
-		apis.maxlen = new_maxlen;
-		apis.list = new_list;
-	}
-
-	apis.list[apis.len++] = api;
-
-	return api;
-}
-
-/*!
- * \brief Re-links a given \a user against its associated \a api.
- *
- * If the \a api has an implementation, the \a user is linked to that
- * implementation. Otherwise, the \a user is linked to its \a stub.
- *
- * \param user \ref optional_api_user to link.
- * \param api \ref optional_api to link.
- */
-static void optional_api_user_relink(struct optional_api_user *user,
-	struct optional_api *api)
-{
-	if (api->impl && *user->optional_ref != api->impl) {
-		*user->optional_ref = api->impl;
-	} else if (!api->impl && *user->optional_ref != user->stub) {
-		*user->optional_ref = user->stub;
-	}
-}
-
-/*!
- * \brief Sets the implementation function pointer for an \a api.
- *
- * \param api API to implement/stub out.
- * \param impl Pointer to implementation function. Can be 0 to remove
- *             implementation.
- */
-static void optional_api_set_impl(struct optional_api *api,
-	ast_optional_fn impl)
-{
-	size_t i;
-
-	api->impl = impl;
-
-	/* re-link all users */
-	for (i = 0; i < api->users_len; ++i) {
-		optional_api_user_relink(api->users[i], api);
-	}
-}
-
-void ast_optional_api_provide(const char *symname, ast_optional_fn impl)
-{
-	struct optional_api *api;
-
-	api = get_api(symname);
-	if (!api) {
-		ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-		ast_do_crash();
-		return;
-	}
-
-	optional_api_set_impl(api, impl);
-}
-
-void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl)
-{
-	struct optional_api *api;
-
-	api = get_api(symname);
-	if (!api) {
-		ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
-		ast_do_crash();
-		return;
-	}
-
-	optional_api_set_impl(api, 0);
-}
-
-void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref,
-	ast_optional_fn stub, const char *module)
-{
-	struct optional_api_user *user;
-	struct optional_api *api;
-
-
-	api = get_api(symname);
-	if (!api) {
-		ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-		ast_do_crash();
-		return;
-	}
-
-	user = optional_api_user_create(optional_ref, stub, module);
-	if (!user) {
-		ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-		ast_do_crash();
-		return;
-	}
-
-	/* Add user to the API */
-	if (api->users_len + 1 > api->users_maxlen) {
-		size_t new_maxlen = api->users_maxlen ? 2 * api->users_maxlen : 1;
-		struct optional_api_user **new_list;
-
-		new_list = ast_std_realloc(api->users, new_maxlen * sizeof(*new_list));
-		if (!new_list) {
-			optional_api_user_destroy(user);
-			ast_log(LOG_ERROR, "Failed to allocate api list\n");
-			ast_do_crash();
-			return;
-		}
-
-		api->users_maxlen = new_maxlen;
-		api->users = new_list;
-	}
-
-	api->users[api->users_len++] = user;
-
-	optional_api_user_relink(user, api);
-}
-
-void ast_optional_api_unuse(const char *symname, ast_optional_fn *optional_ref,
-	const char *module)
-{
-	struct optional_api *api;
-	size_t i;
-
-	api = get_api(symname);
-	if (!api) {
-		ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
-		ast_do_crash();
-		return;
-	}
-
-	for (i = 0; i < api->users_len; ++i) {
-		struct optional_api_user *user = api->users[i];
-
-		if (user->optional_ref == optional_ref) {
-			if (*user->optional_ref != user->stub) {
-				*user->optional_ref = user->stub;
-			}
-
-			/* Remove from the list */
-			api->users[i] = api->users[--api->users_len];
-
-			optional_api_user_destroy(user);
-			return;
-		}
-	}
-
-	ast_log(LOG_ERROR, "%s: Could not find user %s\n", symname, module);
-}
-
-#endif /* defined(OPTIONAL_API) */
diff --git a/main/parking.c b/main/parking.c
deleted file mode 100644
index 61b854d..0000000
--- a/main/parking.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Parking Core
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 414403 $")
-
-#include "asterisk/_private.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/bridge.h"
-#include "asterisk/parking.h"
-#include "asterisk/channel.h"
-#include "asterisk/_private.h"
-#include "asterisk/module.h"
-
-/*! \brief Message type for parked calls */
-STASIS_MESSAGE_TYPE_DEFN(ast_parked_call_type);
-
-/*! \brief Topic for parking lots */
-static struct stasis_topic *parking_topic;
-
-/*! \brief The container for the parking provider */
-static AO2_GLOBAL_OBJ_STATIC(parking_provider);
-
-static void parking_stasis_cleanup(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_parked_call_type);
-	ao2_cleanup(parking_topic);
-	parking_topic = NULL;
-}
-
-int ast_parking_stasis_init(void)
-{
-	if (STASIS_MESSAGE_TYPE_INIT(ast_parked_call_type)) {
-		return -1;
-	}
-
-	parking_topic = stasis_topic_create("ast_parking");
-	if (!parking_topic) {
-		return -1;
-	}
-	ast_register_cleanup(parking_stasis_cleanup);
-	return 0;
-}
-
-struct stasis_topic *ast_parking_topic(void)
-{
-	return parking_topic;
-}
-
-/*! \brief Destructor for parked_call_payload objects */
-static void parked_call_payload_destructor(void *obj)
-{
-	struct ast_parked_call_payload *park_obj = obj;
-
-	ao2_cleanup(park_obj->parkee);
-	ao2_cleanup(park_obj->retriever);
-	ast_string_field_free_memory(park_obj);
-}
-
-struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
-		struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
-		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
-		unsigned int parkingspace, unsigned long int timeout,
-		unsigned long int duration)
-{
-	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
-
-	payload = ao2_alloc(sizeof(*payload), parked_call_payload_destructor);
-	if (!payload) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(payload, 32)) {
-		return NULL;
-	}
-
-	payload->event_type = event_type;
-
-	ao2_ref(parkee_snapshot, +1);
-	payload->parkee = parkee_snapshot;
-
-	if (retriever_snapshot) {
-		ao2_ref(retriever_snapshot, +1);
-		payload->retriever = retriever_snapshot;
-	}
-
-	if (parkinglot) {
-		ast_string_field_set(payload, parkinglot, parkinglot);
-	}
-
-	if (parker_dial_string) {
-		ast_string_field_set(payload, parker_dial_string, parker_dial_string);
-	}
-
-	payload->parkingspace = parkingspace;
-	payload->timeout = timeout;
-	payload->duration = duration;
-
-	/* Bump the ref count by one since RAII_VAR is going to eat one when we leave. */
-	ao2_ref(payload, +1);
-	return payload;
-}
-
-int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (!table || !table->parking_park_bridge_channel) {
-		return -1;
-	}
-
-	if (table->module_info) {
-		SCOPED_MODULE_USE(table->module_info->self);
-		return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
-	}
-
-	return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
-}
-
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
-	const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
-	struct transfer_channel_data *parked_channel_data)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (!table || !table->parking_blind_transfer_park) {
-		return -1;
-	}
-
-	if (table->module_info) {
-		SCOPED_MODULE_USE(table->module_info->self);
-		return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
-	}
-
-	return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
-}
-
-int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (!table || !table->parking_park_call) {
-		return -1;
-	}
-
-	if (table->module_info) {
-		SCOPED_MODULE_USE(table->module_info->self);
-		return table->parking_park_call(parker, exten, length);
-	}
-
-	return table->parking_park_call(parker, exten, length);
-}
-
-int ast_parking_is_exten_park(const char *context, const char *exten)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (!table || !table->parking_is_exten_park) {
-		return -1;
-	}
-
-	if (table->module_info) {
-		SCOPED_MODULE_USE(table->module_info->self);
-		return table->parking_is_exten_park(context, exten);
-	}
-
-	return table->parking_is_exten_park(context, exten);
-}
-
-int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (fn_table->module_version != PARKING_MODULE_VERSION) {
-		ast_log(AST_LOG_WARNING, "Parking module provided incorrect parking module "
-			"version: %u (expected: %d)\n", fn_table->module_version, PARKING_MODULE_VERSION);
-		return -1;
-	}
-
-	if (wrapper) {
-		ast_log(AST_LOG_WARNING, "Parking provider already registered by %s!\n",
-			wrapper->module_name);
-		return -1;
-	}
-
-	wrapper = ao2_alloc(sizeof(*wrapper), NULL);
-	if (!wrapper) {
-		return -1;
-	}
-	*wrapper = *fn_table;
-
-	ao2_global_obj_replace_unref(parking_provider, wrapper);
-	return 0;
-}
-
-int ast_parking_unregister_bridge_features(const char *module_name)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	if (!wrapper) {
-		return -1;
-	}
-
-	if (strcmp(wrapper->module_name, module_name)) {
-		ast_log(AST_LOG_WARNING, "%s has not registered the parking provider\n", module_name);
-		return -1;
-	}
-
-	ao2_global_obj_release(parking_provider);
-	return 0;
-}
-
-int ast_parking_provider_registered(void)
-{
-	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
-		ao2_global_obj_ref(parking_provider), ao2_cleanup);
-
-	return !!table;
-}
diff --git a/main/pbx.c b/main/pbx.c
index d7d1431..0165c88 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_SYSTEM_NAME */
@@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 #include "asterisk/file.h"
 #include "asterisk/callerid.h"
 #include "asterisk/cdr.h"
+#include "asterisk/cel.h"
 #include "asterisk/config.h"
 #include "asterisk/term.h"
 #include "asterisk/time.h"
@@ -64,14 +65,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 #include "asterisk/app.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/presencestate.h"
+#include "asterisk/event.h"
 #include "asterisk/hashtab.h"
 #include "asterisk/module.h"
 #include "asterisk/indications.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/xmldoc.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/dial.h"
+#include "asterisk/vector.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -104,6 +105,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 				<para>Asterisk will wait this number of milliseconds before returning to
 				the dialplan after answering the call.</para>
 			</parameter>
+			<parameter name="nocdr">
+				<para>Asterisk will send an answer signal to the calling phone, but will not
+				set the disposition or answer time in the CDR for this call.</para>
+			</parameter>
 		</syntax>
 		<description>
 			<para>If the call has not been answered, this application will
@@ -464,6 +469,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 			<ref type="function">Exception</ref>
 		</see-also>
 	</application>
+	<application name="ResetCDR" language="en_US">
+		<synopsis>
+			Resets the Call Data Record.
+		</synopsis>
+		<syntax>
+			<parameter name="options">
+				<optionlist>
+					<option name="w">
+						<para>Store the current CDR record before resetting it.</para>
+					</option>
+					<option name="a">
+						<para>Store any stacked records.</para>
+					</option>
+					<option name="v">
+						<para>Save CDR variables.</para>
+					</option>
+					<option name="e">
+						<para>Enable CDR only (negate effects of NoCDR).</para>
+					</option>
+				</optionlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This application causes the Call Data Record to be reset.</para>
+		</description>
+		<see-also>
+			<ref type="application">ForkCDR</ref>
+			<ref type="application">NoCDR</ref>
+		</see-also>
+	</application>
 	<application name="Ringing" language="en_US">
 		<synopsis>
 			Indicate ringing tone.
@@ -487,58 +522,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 			<parameter name="string" required="true" />
 		</syntax>
 		<description>
-			<para>This application will play the sounds that correspond to the letters
-			of the given <replaceable>string</replaceable>. If the channel variable
-			<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
-			then this application will react to DTMF in the	same way as
-			<literal>Background</literal>.</para>
-		</description>
-		<see-also>
-			<ref type="application">SayDigits</ref>
-			<ref type="application">SayNumber</ref>
-			<ref type="application">SayPhonetic</ref>
-			<ref type="function">CHANNEL</ref>
-		</see-also>
-	</application>
-	<application name="SayAlphaCase" language="en_US">
-		<synopsis>
-			Say Alpha.
-		</synopsis>
-		<syntax>
-			<parameter name="casetype" required="true" >
-				<enumlist>
-					<enum name="a">
-						<para>Case sensitive (all) pronunciation.
-						(Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
-					</enum>
-					<enum name="l">
-						<para>Case sensitive (lower) pronunciation.
-						(Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
-					</enum>
-					<enum name="n">
-						<para>Case insensitive pronunciation. Equivalent to SayAlpha.
-						(Ex: SayAlphaCase(n,aBc) - a b c).</para>
-					</enum>
-					<enum name="u">
-						<para>Case sensitive (upper) pronunciation.
-						(Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
-					</enum>
-				</enumlist>
-			</parameter>
-			<parameter name="string" required="true" />
-		</syntax>
-		<description>
 			<para>This application will play the sounds that correspond to the letters of the
-			given <replaceable>string</replaceable>.  Optionally, a <replaceable>casetype</replaceable> may be
-			specified.  This will be used for case-insensitive or case-sensitive pronunciations. If the channel
-			variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-			application will react to DTMF in the same way as <literal>Background</literal>.</para>
+			given <replaceable>string</replaceable>.</para>
 		</description>
 		<see-also>
 			<ref type="application">SayDigits</ref>
 			<ref type="application">SayNumber</ref>
 			<ref type="application">SayPhonetic</ref>
-			<ref type="application">SayAlpha</ref>
 			<ref type="function">CHANNEL</ref>
 		</see-also>
 	</application>
@@ -551,10 +541,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 		</syntax>
 		<description>
 			<para>This application will play the sounds that correspond to the digits of
-			the given number. This will use the language that is currently set for the channel.
-			If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
-			(case insensitive), then this application will react to DTMF in the same way as
-			<literal>Background</literal>.</para>
+			the given number. This will use the language that is currently set for the channel.</para>
 		</description>
 		<see-also>
 			<ref type="application">SayAlpha</ref>
@@ -572,12 +559,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 			<parameter name="gender" />
 		</syntax>
 		<description>
-			<para>This application will play the sounds that correspond to the given
-			<replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
-			specified. This will use the language that is currently set for the channel. See the CHANNEL()
-			function for more information on setting the language for the channel. If the channel variable
-			<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-			application will react to DTMF in the same way as <literal>Background</literal>.</para>
+			<para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>.
+			Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently
+			set for the channel. See the CHANNEL() function for more information on setting the language for the channel.</para>
 		</description>
 		<see-also>
 			<ref type="application">SayAlpha</ref>
@@ -595,9 +579,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 		</syntax>
 		<description>
 			<para>This application will play the sounds from the phonetic alphabet that correspond to the
-			letters in the given <replaceable>string</replaceable>. If the channel variable
-			<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-			application will react to DTMF in the same way as <literal>Background</literal>.</para>
+			letters in the given <replaceable>string</replaceable>.</para>
 		</description>
 		<see-also>
 			<ref type="application">SayAlpha</ref>
@@ -674,11 +656,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 		</syntax>
 		<description>
 			<para>This application will set the channel's AMA Flags for billing purposes.</para>
-			<warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
 		</description>
 		<see-also>
 			<ref type="function">CDR</ref>
-			<ref type="function">CHANNEL</ref>
 		</see-also>
 	</application>
 	<application name="Wait" language="en_US">
@@ -800,45 +780,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427711 $")
 			may take a lot of capacity.</para>
 		</description>
 	</manager>
-	<manager name="ExtensionStateList" language="en_US">
-		<synopsis>
-			List the current known extension states.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>This will list out all known extension states in a
-			sequence of <replaceable>ExtensionStatus</replaceable> events.
-			When finished, a <replaceable>ExtensionStateListComplete</replaceable> event
-			will be emitted.</para>
-		</description>
-		<see-also>
-			<ref type="manager">ExtensionState</ref>
-			<ref type="function">HINT</ref>
-			<ref type="function">EXTENSION_STATE</ref>
-		</see-also>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ExtensionStatus'])" />
-			</list-elements>
-			<managerEvent name="ExtensionStateListComplete" language="en_US">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>
-						Indicates the end of the list the current known extension states.
-					</synopsis>
-					<syntax>
-						<parameter name="EventList">
-							<para>Conveys the status of the event list.</para>
-						</parameter>
-						<parameter name="ListItems">
-							<para>Conveys the number of statuses reported.</para>
-						</parameter>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
  ***/
 
 #ifdef LOW_MEMORY
@@ -878,6 +819,8 @@ AST_APP_OPTIONS(waitexten_opts, {
 struct ast_context;
 struct ast_app;
 
+static struct ast_taskprocessor *extension_state_tps;
+
 AST_THREADSTORAGE(switch_data);
 AST_THREADSTORAGE(extensionstate_buf);
 /*!
@@ -1046,8 +989,9 @@ struct ast_hint {
 
 	char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
 	char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
-};
 
+	AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
+};
 
 #define HINTDEVICE_DATA_LENGTH 16
 AST_THREADSTORAGE(hintdevice_data);
@@ -1077,15 +1021,28 @@ struct ast_hintdevice {
 	char hintdevice[1];
 };
 
-
 /*!
  * \note Using the device for hash
  */
 static int hintdevice_hash_cb(const void *obj, const int flags)
 {
-	const struct ast_hintdevice *ext = obj;
+	const struct ast_hintdevice *ext;
+	const char *key;
+
+	switch (flags & (OBJ_KEY | OBJ_POINTER)) {
+	case OBJ_KEY:
+		key = obj;
+		break;
+	case OBJ_POINTER:
+		ext = obj;
+		key = ext->hintdevice;
+		break;
+	default:
+		ast_assert(0);
+		return 0;
+	}
 
-	return ast_str_case_hash(ext->hintdevice);
+	return ast_str_case_hash(key);
 }
 /*!
  * \note Devices on hints are not unique so no CMP_STOP is returned
@@ -1094,29 +1051,51 @@ static int hintdevice_hash_cb(const void *obj, const int flags)
  */
 static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
 {
-	struct ast_hintdevice *ext = obj, *ext2 = arg;
+	struct ast_hintdevice *left = obj;
+	struct ast_hintdevice *right = arg;
+	const char *right_key = arg;
+	int cmp;
 
-	return !strcasecmp(ext->hintdevice, ext2->hintdevice) ? CMP_MATCH  : 0;
+	switch (flags & (OBJ_POINTER | OBJ_KEY)) {
+	case OBJ_POINTER:
+		right_key = right->hintdevice;
+		/* Fall through */
+	case OBJ_KEY:
+		cmp = strcasecmp(left->hintdevice, right_key);
+		break;
+	default:
+		ast_assert(0);
+		cmp = 0;
+		break;
+	}
+	return cmp ? 0 : CMP_MATCH;
 }
 
-/*
- * \details This is used with ao2_callback to remove old devices
- * when they are linked to the hint
-*/
-static int hintdevice_remove_cb(void *deviceobj, void *arg, int flags)
+/*! \internal \brief \c ao2_callback function to remove hintdevices */
+static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
 {
-	struct ast_hintdevice *device = deviceobj;
-	struct ast_hint *hint = arg;
+	struct ast_hintdevice *candidate = obj;
+	char *device = arg;
+	struct ast_hint *hint = data;
 
-	return (device->hint == hint) ? CMP_MATCH : 0;
+	if (!strcasecmp(candidate->hintdevice, device)
+		&& candidate->hint == hint) {
+		return CMP_MATCH;
+	}
+	return 0;
 }
 
 static int remove_hintdevice(struct ast_hint *hint)
 {
-	/* iterate through all devices and remove the devices which are linked to this hint */
-	ao2_t_callback(hintdevices, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
-		hintdevice_remove_cb, hint,
-		"callback to remove all devices which are linked to a hint");
+	while (AST_VECTOR_SIZE(&hint->devices) > 0) {
+		char *device = AST_VECTOR_GET(&hint->devices, 0);
+
+		ao2_t_callback_data(hintdevices, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA,
+			hintdevice_remove_cb, device, hint, "Remove device from container");
+		AST_VECTOR_REMOVE_UNORDERED(&hint->devices, 0);
+		ast_free(device);
+	}
+
 	return 0;
 }
 
@@ -1159,16 +1138,34 @@ static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
 	ast_str_set(&str, 0, "%s", devicelist);
 	parse = parse_hint_device(str);
 
-	while ((cur = strsep(&parse, "&"))) {
+	/* Spit on '&' and ',' to handle presence hints as well */
+	while ((cur = strsep(&parse, "&,"))) {
+		char *device_name;
+
 		devicelength = strlen(cur);
+		if (!devicelength) {
+			continue;
+		}
+
+		device_name = ast_strdup(cur);
+		if (!device_name) {
+			return -1;
+		}
+
 		device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
 			"allocating a hintdevice structure");
 		if (!device) {
+			ast_free(device_name);
 			return -1;
 		}
 		strcpy(device->hintdevice, cur);
 		ao2_ref(hint, +1);
 		device->hint = hint;
+		if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
+			ast_free(device_name);
+			ao2_ref(device, -1);
+			return -1;
+		}
 		ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
 		ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
 	}
@@ -1191,6 +1188,18 @@ static const struct cfextension_states {
 	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
 };
 
+struct presencechange {
+	char *provider;
+	int state;
+	char *subtype;
+	char *message;
+};
+
+struct statechange {
+	AST_LIST_ENTRY(statechange) entry;
+	char dev[0];
+};
+
 struct pbx_exception {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(context);	/*!< Context associated with this exception */
@@ -1208,6 +1217,7 @@ static int pbx_builtin_background(struct ast_channel *, const char *);
 static int pbx_builtin_wait(struct ast_channel *, const char *);
 static int pbx_builtin_waitexten(struct ast_channel *, const char *);
 static int pbx_builtin_incomplete(struct ast_channel *, const char *);
+static int pbx_builtin_resetcdr(struct ast_channel *, const char *);
 static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
 static int pbx_builtin_ringing(struct ast_channel *, const char *);
 static int pbx_builtin_proceeding(struct ast_channel *, const char *);
@@ -1221,7 +1231,6 @@ static int pbx_builtin_execiftime(struct ast_channel *, const char *);
 static int pbx_builtin_saynumber(struct ast_channel *, const char *);
 static int pbx_builtin_saydigits(struct ast_channel *, const char *);
 static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
-static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *);
 static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
 static int matchcid(const char *cidpattern, const char *callerid);
 #ifdef NEED_DEBUG
@@ -1365,20 +1374,28 @@ static int extenpatternmatchnew = 0;
 static char *overrideswitch = NULL;
 
 /*! \brief Subscription for device state change events */
-static struct stasis_subscription *device_state_sub;
+static struct ast_event_sub *device_state_sub;
 /*! \brief Subscription for presence state change events */
-static struct stasis_subscription *presence_state_sub;
+static struct ast_event_sub *presence_state_sub;
 
 AST_MUTEX_DEFINE_STATIC(maxcalllock);
 static int countcalls;
 static int totalcalls;
 
+static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
+
 /*!
- * \brief Registered functions container.
- *
- * It is sorted by function name.
+ * \brief Extra information for an \ref ast_custom_function holding privilege
+ * escalation information. Kept in a separate structure for ABI compatibility.
  */
-static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
+struct ast_custom_escalating_function {
+	AST_RWLIST_ENTRY(ast_custom_escalating_function) list;
+	const struct ast_custom_function *acf;
+	unsigned int read_escalates:1;
+	unsigned int write_escalates:1;
+};
+
+static AST_RWLIST_HEAD_STATIC(escalation_root, ast_custom_escalating_function);
 
 /*! \brief Declaration of builtin applications */
 static struct pbx_builtin {
@@ -1404,9 +1421,9 @@ static struct pbx_builtin {
 	{ "Proceeding",     pbx_builtin_proceeding },
 	{ "Progress",       pbx_builtin_progress },
 	{ "RaiseException", pbx_builtin_raise_exception },
+	{ "ResetCDR",       pbx_builtin_resetcdr },
 	{ "Ringing",        pbx_builtin_ringing },
 	{ "SayAlpha",       pbx_builtin_saycharacters },
-	{ "SayAlphaCase",   pbx_builtin_saycharacters_case },
 	{ "SayDigits",      pbx_builtin_saydigits },
 	{ "SayNumber",      pbx_builtin_saynumber },
 	{ "SayPhonetic",    pbx_builtin_sayphonetic },
@@ -1433,11 +1450,6 @@ AST_MUTEX_DEFINE_STATIC(conlock);
  */
 AST_MUTEX_DEFINE_STATIC(context_merge_lock);
 
-/*!
- * \brief Registered applications container.
- *
- * It is sorted by application name.
- */
 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
 
 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
@@ -1643,58 +1655,49 @@ int pbx_exec(struct ast_channel *c,	/*!< Channel */
 	const char *saved_c_appl;
 	const char *saved_c_data;
 
+	if (ast_channel_cdr(c) && !ast_check_hangup(c))
+		ast_cdr_setapp(ast_channel_cdr(c), app->name, data);
+
 	/* save channel values */
 	saved_c_appl= ast_channel_appl(c);
 	saved_c_data= ast_channel_data(c);
 
-	ast_channel_lock(c);
 	ast_channel_appl_set(c, app->name);
 	ast_channel_data_set(c, data);
-	ast_channel_publish_snapshot(c);
-	ast_channel_unlock(c);
+	ast_cel_report_event(c, AST_CEL_APP_START, NULL, NULL, NULL);
 
 	if (app->module)
 		u = __ast_module_user_add(app->module, c);
+	if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
+			strchr(data, '|') && !strchr(data, ',') && !ast_opt_dont_warn) {
+		ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
+			"the pipe.  Did you forget to convert your dialplan?  (%s(%s))\n",
+			app->name, (char *) data);
+	}
 	res = app->execute(c, S_OR(data, ""));
 	if (app->module && u)
 		__ast_module_user_remove(app->module, u);
+	ast_cel_report_event(c, AST_CEL_APP_END, NULL, NULL, NULL);
 	/* restore channel values */
 	ast_channel_appl_set(c, saved_c_appl);
 	ast_channel_data_set(c, saved_c_data);
 	return res;
 }
 
-static struct ast_app *pbx_findapp_nolock(const char *name)
-{
-	struct ast_app *cur;
-	int cmp;
-
-	AST_RWLIST_TRAVERSE(&apps, cur, list) {
-		cmp = strcasecmp(name, cur->name);
-		if (cmp > 0) {
-			continue;
-		}
-		if (!cmp) {
-			/* Found it. */
-			break;
-		}
-		/* Not in container. */
-		cur = NULL;
-		break;
-	}
-
-	return cur;
-}
-
+/*! \brief Find application handle in linked list
+ */
 struct ast_app *pbx_findapp(const char *app)
 {
-	struct ast_app *ret;
+	struct ast_app *tmp;
 
 	AST_RWLIST_RDLOCK(&apps);
-	ret = pbx_findapp_nolock(app);
+	AST_RWLIST_TRAVERSE(&apps, tmp, list) {
+		if (!strcasecmp(tmp->name, app))
+			break;
+	}
 	AST_RWLIST_UNLOCK(&apps);
 
-	return ret;
+	return tmp;
 }
 
 static struct ast_switch *pbx_findswitch(const char *sw)
@@ -3708,7 +3711,7 @@ const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, stru
 		if (places[i] == &globals)
 			ast_rwlock_rdlock(&globalslock);
 		AST_LIST_TRAVERSE(places[i], variables, entries) {
-			if (!strcmp(ast_var_name(variables), var)) {
+			if (!strcasecmp(ast_var_name(variables), var)) {
 				s = ast_var_value(variables);
 				break;
 			}
@@ -3859,44 +3862,6 @@ static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_
 	return CLI_SUCCESS;
 }
 
-static char *complete_functions(const char *word, int pos, int state)
-{
-	struct ast_custom_function *cur;
-	char *ret = NULL;
-	int which = 0;
-	int wordlen;
-	int cmp;
-
-	if (pos != 3) {
-		return NULL;
-	}
-
-	wordlen = strlen(word);
-	AST_RWLIST_RDLOCK(&acf_root);
-	AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
-		/*
-		 * Do a case-insensitive search for convenience in this
-		 * 'complete' function.
-		 *
-		 * We must search the entire container because the functions are
-		 * sorted and normally found case sensitively.
-		 */
-		cmp = strncasecmp(word, cur->name, wordlen);
-		if (!cmp) {
-			/* Found match. */
-			if (++which <= state) {
-				/* Not enough matches. */
-				continue;
-			}
-			ret = ast_strdup(cur->name);
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&acf_root);
-
-	return ret;
-}
-
 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_custom_function *acf;
@@ -3905,6 +3870,9 @@ static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_c
 	char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
 	char stxtitle[40], *syntax = NULL, *arguments = NULL;
 	int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
+	char *ret = NULL;
+	int which = 0;
+	int wordlen;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -3914,10 +3882,21 @@ static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_c
 			"       Describe a particular dialplan function.\n";
 		return NULL;
 	case CLI_GENERATE:
-		return complete_functions(a->word, a->pos, a->n);
+		wordlen = strlen(a->word);
+		/* case-insensitive for convenience in this 'complete' function */
+		AST_RWLIST_RDLOCK(&acf_root);
+		AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
+			if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
+				ret = ast_strdup(acf->name);
+				break;
+			}
+		}
+		AST_RWLIST_UNLOCK(&acf_root);
+
+		return ret;
 	}
 
-	if (a->argc != 4) {
+	if (a->argc < 4) {
 		return CLI_SHOWUSAGE;
 	}
 
@@ -3990,34 +3969,15 @@ static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_c
 	return CLI_SUCCESS;
 }
 
-static struct ast_custom_function *ast_custom_function_find_nolock(const char *name)
-{
-	struct ast_custom_function *cur;
-	int cmp;
-
-	AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
-		cmp = strcmp(name, cur->name);
-		if (cmp > 0) {
-			continue;
-		}
-		if (!cmp) {
-			/* Found it. */
-			break;
-		}
-		/* Not in container. */
-		cur = NULL;
-		break;
-	}
-
-	return cur;
-}
-
 struct ast_custom_function *ast_custom_function_find(const char *name)
 {
-	struct ast_custom_function *acf;
+	struct ast_custom_function *acf = NULL;
 
 	AST_RWLIST_RDLOCK(&acf_root);
-	acf = ast_custom_function_find_nolock(name);
+	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
+		if (!strcmp(name, acf->name))
+			break;
+	}
 	AST_RWLIST_UNLOCK(&acf_root);
 
 	return acf;
@@ -4026,6 +3986,7 @@ struct ast_custom_function *ast_custom_function_find(const char *name)
 int ast_custom_function_unregister(struct ast_custom_function *acf)
 {
 	struct ast_custom_function *cur;
+	struct ast_custom_escalating_function *cur_escalation;
 
 	if (!acf) {
 		return -1;
@@ -4042,6 +4003,18 @@ int ast_custom_function_unregister(struct ast_custom_function *acf)
 	}
 	AST_RWLIST_UNLOCK(&acf_root);
 
+	/* Remove from the escalation list */
+	AST_RWLIST_WRLOCK(&escalation_root);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&escalation_root, cur_escalation, list) {
+		if (cur_escalation->acf == acf) {
+			AST_RWLIST_REMOVE_CURRENT(list);
+			ast_free(cur_escalation);
+			break;
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+	AST_RWLIST_UNLOCK(&escalation_root);
+
 	return cur ? 0 : -1;
 }
 
@@ -4053,7 +4026,18 @@ int ast_custom_function_unregister(struct ast_custom_function *acf)
  * \return False (zero) if reads just read.
  */
 static int read_escalates(const struct ast_custom_function *acf) {
-	return acf->read_escalates;
+	int res = 0;
+	struct ast_custom_escalating_function *cur_escalation;
+
+	AST_RWLIST_RDLOCK(&escalation_root);
+	AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
+		if (cur_escalation->acf == acf) {
+			res = cur_escalation->read_escalates;
+			break;
+		}
+	}
+	AST_RWLIST_UNLOCK(&escalation_root);
+	return res;
 }
 
 /*!
@@ -4064,7 +4048,18 @@ static int read_escalates(const struct ast_custom_function *acf) {
  * \return False (zero) if writes just write.
  */
 static int write_escalates(const struct ast_custom_function *acf) {
-	return acf->write_escalates;
+	int res = 0;
+	struct ast_custom_escalating_function *cur_escalation;
+
+	AST_RWLIST_RDLOCK(&escalation_root);
+	AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
+		if (cur_escalation->acf == acf) {
+			res = cur_escalation->write_escalates;
+			break;
+		}
+	}
+	AST_RWLIST_UNLOCK(&escalation_root);
+	return res;
 }
 
 /*! \internal
@@ -4123,6 +4118,7 @@ static int acf_retrieve_docs(struct ast_custom_function *acf)
 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
 {
 	struct ast_custom_function *cur;
+	char tmps[80];
 
 	if (!acf) {
 		return -1;
@@ -4139,34 +4135,37 @@ int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_m
 
 	AST_RWLIST_WRLOCK(&acf_root);
 
-	cur = ast_custom_function_find_nolock(acf->name);
-	if (cur) {
-		ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
-		AST_RWLIST_UNLOCK(&acf_root);
-		return -1;
+	AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
+		if (!strcmp(acf->name, cur->name)) {
+			ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
+			AST_RWLIST_UNLOCK(&acf_root);
+			return -1;
+		}
 	}
 
 	/* Store in alphabetical order */
 	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
-		if (strcmp(acf->name, cur->name) < 0) {
+		if (strcasecmp(acf->name, cur->name) < 0) {
 			AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
 			break;
 		}
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END;
+
 	if (!cur) {
 		AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
 	}
 
 	AST_RWLIST_UNLOCK(&acf_root);
 
-	ast_verb(2, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
+	ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
 
 	return 0;
 }
 
 int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
 {
+	struct ast_custom_escalating_function *acf_escalation = NULL;
 	int res;
 
 	res = __ast_custom_function_register(acf, mod);
@@ -4174,21 +4173,37 @@ int __ast_custom_function_register_escalating(struct ast_custom_function *acf, e
 		return -1;
 	}
 
+	if (escalation == AST_CFE_NONE) {
+		/* No escalations; no need to do anything else */
+		return 0;
+	}
+
+	acf_escalation = ast_calloc(1, sizeof(*acf_escalation));
+	if (!acf_escalation) {
+		ast_custom_function_unregister(acf);
+		return -1;
+	}
+
+	acf_escalation->acf = acf;
 	switch (escalation) {
 	case AST_CFE_NONE:
 		break;
 	case AST_CFE_READ:
-		acf->read_escalates = 1;
+		acf_escalation->read_escalates = 1;
 		break;
 	case AST_CFE_WRITE:
-		acf->write_escalates = 1;
+		acf_escalation->write_escalates = 1;
 		break;
 	case AST_CFE_BOTH:
-		acf->read_escalates = 1;
-		acf->write_escalates = 1;
+		acf_escalation->read_escalates = 1;
+		acf_escalation->write_escalates = 1;
 		break;
 	}
 
+	AST_RWLIST_WRLOCK(&escalation_root);
+	AST_RWLIST_INSERT_TAIL(&escalation_root, acf_escalation, list);
+	AST_RWLIST_UNLOCK(&escalation_root);
+
 	return 0;
 }
 
@@ -4523,12 +4538,12 @@ void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, str
 
 			/* Substitute if necessary */
 			if (needsub) {
-				size_t my_used;
-
+				size_t used;
 				if (!substr2) {
 					substr2 = ast_str_create(16);
 				}
-				ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
+
+				ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
 				finalvars = ast_str_buffer(substr2);
 			} else {
 				finalvars = ast_str_buffer(substr1);
@@ -4599,12 +4614,12 @@ void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, str
 
 			/* Substitute if necessary */
 			if (needsub) {
-				size_t my_used;
-
+				size_t used;
 				if (!substr2) {
 					substr2 = ast_str_create(16);
 				}
-				ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
+
+				ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
 				finalvars = ast_str_buffer(substr2);
 			} else {
 				finalvars = ast_str_buffer(substr1);
@@ -4718,12 +4733,11 @@ void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead
 
 			/* Substitute if necessary */
 			if (needsub) {
-				size_t my_used;
-
-				if (!ltmp) {
+				size_t used;
+				if (!ltmp)
 					ltmp = ast_alloca(VAR_BUF_SIZE);
-				}
-				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
+
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
 				vars = ltmp;
 			} else {
 				vars = var;
@@ -4808,12 +4822,11 @@ void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead
 
 			/* Substitute if necessary */
 			if (needsub) {
-				size_t my_used;
-
-				if (!ltmp) {
+				size_t used;
+				if (!ltmp)
 					ltmp = ast_alloca(VAR_BUF_SIZE);
-				}
-				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
+
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
 				vars = ltmp;
 			} else {
 				vars = var;
@@ -4872,6 +4885,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
 	int res;
 	struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
 	char passdata[EXT_DATA_SIZE];
+
 	int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
 
 	ast_rdlock_contexts();
@@ -4918,15 +4932,41 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
 			if (substitute) {
 				pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
 			}
+#ifdef CHANNEL_TRACE
+			ast_channel_trace_update(c);
+#endif
 			ast_debug(1, "Launching '%s'\n", app->name);
 			if (VERBOSITY_ATLEAST(3)) {
-				ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
+				char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
+				ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
 					exten, context, priority,
-					COLORIZE(COLOR_BRCYAN, 0, app->name),
-					COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(c)),
-					COLORIZE(COLOR_BRMAGENTA, 0, passdata),
+					term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
+					term_color(tmp2, ast_channel_name(c), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
+					term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
 					"in new stack");
 			}
+			/*** DOCUMENTATION
+				<managerEventInstance>
+					<synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
+					<syntax>
+						<parameter name="Application">
+							<para>The application about to be executed.</para>
+						</parameter>
+						<parameter name="AppData">
+							<para>The data to be passed to the application.</para>
+						</parameter>
+					</syntax>
+				</managerEventInstance>
+			***/
+			manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
+					"Channel: %s\r\n"
+					"Context: %s\r\n"
+					"Extension: %s\r\n"
+					"Priority: %d\r\n"
+					"Application: %s\r\n"
+					"AppData: %s\r\n"
+					"Uniqueid: %s\r\n",
+					ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), app->name, passdata, ast_channel_uniqueid(c));
 			return pbx_exec(c, app, passdata);	/* 0 on success, -1 on failure */
 		}
 	} else if (q.swo) {	/* not found here, but in another switch */
@@ -5117,10 +5157,7 @@ const char *ast_extension_state2str(int extension_state)
 	return "Unknown";
 }
 
-/*!
- * \internal
- * \brief Check extension state for an extension by using hint
- */
+/*! \internal \brief Check extension state for an extension by using hint */
 static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
 	struct ao2_container *device_state_info)
 {
@@ -5263,25 +5300,144 @@ static int execute_state_callback(ast_state_cb_type cb,
 	return res;
 }
 
-/*!
- * /internal
- * /brief Identify a channel for every device which is supposedly responsible for the device state.
- *
- * Especially when the device is ringing, the oldest ringing channel is chosen.
- * For all other cases the first encountered channel in the specific state is chosen.
- */
-static void get_device_state_causing_channels(struct ao2_container *c)
+static int handle_presencechange(void *datap)
 {
-	struct ao2_iterator iter;
-	struct ast_device_state_info *info;
-	struct ast_channel *chan;
+	struct ast_hint *hint;
+	struct ast_str *hint_app = NULL;
+	struct presencechange *pc = datap;
+	struct ao2_iterator i;
+	struct ao2_iterator cb_iter;
+	char context_name[AST_MAX_CONTEXT];
+	char exten_name[AST_MAX_EXTENSION];
+	int res = -1;
 
-	if (!c || !ao2_container_count(c)) {
-		return;
+	hint_app = ast_str_create(1024);
+	if (!hint_app) {
+		goto presencechange_cleanup;
 	}
-	iter = ao2_iterator_init(c, 0);
-	for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
-		enum ast_channel_state search_state = 0; /* prevent false uninit warning */
+
+	ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
+	i = ao2_iterator_init(hints, 0);
+	for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
+		struct ast_state_cb *state_cb;
+		const char *app;
+		char *parse;
+
+		ao2_lock(hint);
+
+		if (!hint->exten) {
+			/* The extension has already been destroyed */
+			ao2_unlock(hint);
+			continue;
+		}
+
+		/* Does this hint monitor the device that changed state? */
+		app = ast_get_extension_app(hint->exten);
+		if (ast_strlen_zero(app)) {
+			/* The hint does not monitor presence at all. */
+			ao2_unlock(hint);
+			continue;
+		}
+
+		ast_str_set(&hint_app, 0, "%s", app);
+		parse = parse_hint_presence(hint_app);
+		if (ast_strlen_zero(parse)) {
+			ao2_unlock(hint);
+			continue;
+		}
+		if (strcasecmp(parse, pc->provider)) {
+			/* The hint does not monitor the presence provider. */
+			ao2_unlock(hint);
+			continue;
+		}
+
+		/*
+		 * Save off strings in case the hint extension gets destroyed
+		 * while we are notifying the watchers.
+		 */
+		ast_copy_string(context_name,
+			ast_get_context_name(ast_get_extension_context(hint->exten)),
+			sizeof(context_name));
+		ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
+			sizeof(exten_name));
+		ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
+
+		/* Check to see if update is necessary */
+		if ((hint->last_presence_state == pc->state) &&
+			((hint->last_presence_subtype && pc->subtype && !strcmp(hint->last_presence_subtype, pc->subtype)) || (!hint->last_presence_subtype && !pc->subtype)) &&
+			((hint->last_presence_message && pc->message && !strcmp(hint->last_presence_message, pc->message)) || (!hint->last_presence_message && !pc->message))) {
+
+			/* this update is the same as the last, do nothing */
+			ao2_unlock(hint);
+			continue;
+		}
+
+		/* update new values */
+		ast_free(hint->last_presence_subtype);
+		ast_free(hint->last_presence_message);
+		hint->last_presence_state = pc->state;
+		hint->last_presence_subtype = pc->subtype ? ast_strdup(pc->subtype) : NULL;
+		hint->last_presence_message = pc->message ? ast_strdup(pc->message) : NULL;
+
+		ao2_unlock(hint);
+
+		/* For general callbacks */
+		cb_iter = ao2_iterator_init(statecbs, 0);
+		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+			execute_state_callback(state_cb->change_cb,
+				context_name,
+				exten_name,
+				state_cb->data,
+				AST_HINT_UPDATE_PRESENCE,
+				hint,
+				NULL);
+		}
+		ao2_iterator_destroy(&cb_iter);
+
+		/* For extension callbacks */
+		cb_iter = ao2_iterator_init(hint->callbacks, 0);
+		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+			execute_state_callback(state_cb->change_cb,
+				context_name,
+				exten_name,
+				state_cb->data,
+				AST_HINT_UPDATE_PRESENCE,
+				hint,
+				NULL);
+		}
+		ao2_iterator_destroy(&cb_iter);
+	}
+	ao2_iterator_destroy(&i);
+	ast_mutex_unlock(&context_merge_lock);
+
+	res = 0;
+
+presencechange_cleanup:
+	ast_free(hint_app);
+	ao2_ref(pc, -1);
+
+	return res;
+}
+
+/*!
+ * /internal
+ * /brief Identify a channel for every device which is supposedly responsible for the device state.
+ *
+ * Especially when the device is ringing, the oldest ringing channel is chosen.
+ * For all other cases the first encountered channel in the specific state is chosen.
+ */
+static void get_device_state_causing_channels(struct ao2_container *c)
+{
+	struct ao2_iterator iter;
+	struct ast_device_state_info *info;
+	struct ast_channel *chan;
+
+	if (!c || !ao2_container_count(c)) {
+		return;
+	}
+	iter = ao2_iterator_init(c, 0);
+	for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
+		enum ast_channel_state search_state = 0; /* prevent false uninit warning */
 		char match[AST_CHANNEL_NAME];
 		struct ast_channel_iterator *chan_iter;
 		struct timeval chantime = {0, }; /* prevent false uninit warning */
@@ -5344,40 +5500,32 @@ static void get_device_state_causing_channels(struct ao2_container *c)
 	ao2_iterator_destroy(&iter);
 }
 
-static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
+static int handle_statechange(void *datap)
 {
-	struct ast_device_state_message *dev_state;
 	struct ast_hint *hint;
 	struct ast_str *hint_app;
 	struct ast_hintdevice *device;
 	struct ast_hintdevice *cmpdevice;
+	struct statechange *sc = datap;
 	struct ao2_iterator *dev_iter;
 	struct ao2_iterator cb_iter;
 	char context_name[AST_MAX_CONTEXT];
 	char exten_name[AST_MAX_EXTENSION];
 
-	if (ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	dev_state = stasis_message_data(msg);
-	if (dev_state->eid) {
-		/* ignore non-aggregate states */
-		return;
-	}
-
 	if (ao2_container_count(hintdevices) == 0) {
 		/* There are no hints monitoring devices. */
-		return;
+		ast_free(sc);
+		return 0;
 	}
 
 	hint_app = ast_str_create(1024);
 	if (!hint_app) {
-		return;
+		ast_free(sc);
+		return -1;
 	}
 
-	cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
-	strcpy(cmpdevice->hintdevice, dev_state->device);
+	cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(sc->dev));
+	strcpy(cmpdevice->hintdevice, sc->dev);
 
 	ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
 	dev_iter = ao2_t_callback(hintdevices,
@@ -5388,7 +5536,8 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 	if (!dev_iter) {
 		ast_mutex_unlock(&context_merge_lock);
 		ast_free(hint_app);
-		return;
+		ast_free(sc);
+		return -1;
 	}
 
 	for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
@@ -5457,7 +5606,7 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 		ao2_iterator_destroy(&cb_iter);
 
 		/* For extension callbacks */
-		/* extended callbacks are called when the state changed or when AST_STATE_RINGING is
+		/* extended callbacks are called when the state changed or when AST_EVENT_RINGING is
 		 * included. Normal callbacks are only called when the state changed.
 		 */
 		cb_iter = ao2_iterator_init(hint->callbacks, 0);
@@ -5485,7 +5634,8 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 
 	ao2_iterator_destroy(dev_iter);
 	ast_free(hint_app);
-	return;
+	ast_free(sc);
+	return 0;
 }
 
 /*!
@@ -5505,10 +5655,7 @@ static void destroy_state_cb(void *doomed)
 	}
 }
 
-/*!
- * \internal
- * \brief Add watcher for extension states with destructor
- */
+/*! \internal \brief Add watcher for extension states with destructor */
 static int extension_state_add_destroy(const char *context, const char *exten,
 	ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
 {
@@ -5693,6 +5840,7 @@ static int hint_id_cmp(void *obj, void *arg, int flags)
 static void destroy_hint(void *obj)
 {
 	struct ast_hint *hint = obj;
+	int i;
 
 	if (hint->callbacks) {
 		struct ast_state_cb *state_cb;
@@ -5722,6 +5870,12 @@ static void destroy_hint(void *obj)
 		}
 		ao2_ref(hint->callbacks, -1);
 	}
+
+	for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+		char *device = AST_VECTOR_GET(&hint->devices, i);
+		ast_free(device);
+	}
+	AST_VECTOR_FREE(&hint->devices);
 	ast_free(hint->last_presence_subtype);
 	ast_free(hint->last_presence_message);
 }
@@ -5783,6 +5937,7 @@ static int ast_add_hint(struct ast_exten *e)
 	if (!hint_new) {
 		return -1;
 	}
+	AST_VECTOR_INIT(&hint_new->devices, 8);
 
 	/* Initialize new hint. */
 	hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
@@ -5838,12 +5993,28 @@ static int ast_add_hint(struct ast_exten *e)
 /*! \brief Change hint for an extension */
 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 {
+	struct ast_str *hint_app;
 	struct ast_hint *hint;
+	int previous_device_state;
+	char *previous_message = NULL;
+	char *message = NULL;
+	char *previous_subtype = NULL;
+	char *subtype = NULL;
+	int previous_presence_state;
+	int presence_state;
+	int presence_state_changed = 0;
 
 	if (!oe || !ne) {
 		return -1;
 	}
 
+	hint_app = ast_str_create(1024);
+	if (!hint_app) {
+		return -1;
+	}
+
+	ast_mutex_lock(&context_merge_lock); /* Hold off ast_merge_contexts_and_delete and state changes */
+
 	ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
 
 	/*
@@ -5853,6 +6024,8 @@ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 	hint = ao2_find(hints, oe, OBJ_UNLINK);
 	if (!hint) {
 		ao2_unlock(hints);
+		ast_mutex_unlock(&context_merge_lock);
+		ast_free(hint_app);
 		return -1;
 	}
 
@@ -5861,7 +6034,28 @@ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 	/* Update the hint and put it back in the hints container. */
 	ao2_lock(hint);
 	hint->exten = ne;
+
+	/* Store the previous states so we know whether we need to notify state callbacks */
+	previous_device_state = hint->laststate;
+	previous_presence_state = hint->last_presence_state;
+	previous_message = hint->last_presence_message;
+	previous_subtype = hint->last_presence_subtype;
+
+	/* Update the saved device and presence state with the new extension */
+	hint->laststate = ast_extension_state2(ne, NULL);
+	hint->last_presence_state = AST_PRESENCE_INVALID;
+	hint->last_presence_subtype = NULL;
+	hint->last_presence_message = NULL;
+
+	presence_state = extension_presence_state_helper(ne, &subtype, &message);
+	if (presence_state > 0) {
+		hint->last_presence_state = presence_state;
+		hint->last_presence_subtype = subtype;
+		hint->last_presence_message = message;
+	}
+
 	ao2_unlock(hint);
+
 	ao2_link(hints, hint);
 	if (add_hintdevice(hint, ast_get_extension_app(ne))) {
 		ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
@@ -5870,8 +6064,98 @@ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 	}
 
 	ao2_unlock(hints);
+
+	/* Locking for state callbacks is respected here and only the context_merge_lock lock is
+	 * held during the state callback invocation. This will stop the normal state callback
+	 * thread from being able to handle incoming state changes if they occur.
+	 */
+
+	/* Determine if presence state has changed due to the change of the hint extension */
+	if ((hint->last_presence_state != previous_presence_state) ||
+		strcmp(S_OR(hint->last_presence_subtype, ""), S_OR(previous_subtype, "")) ||
+		strcmp(S_OR(hint->last_presence_message, ""), S_OR(previous_message, ""))) {
+		presence_state_changed = 1;
+	}
+
+	/* Notify any existing state callbacks if the device or presence state has changed */
+	if ((hint->laststate != previous_device_state) || presence_state_changed) {
+		struct ao2_iterator cb_iter;
+		struct ast_state_cb *state_cb;
+		struct ao2_container *device_state_info;
+		int first_extended_cb_call = 1;
+
+		/* For general callbacks */
+		cb_iter = ao2_iterator_init(statecbs, 0);
+		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+			/* Unlike the normal state callbacks since something has explicitly provided us this extension
+			 * it will remain valid and unchanged for the lifetime of this function invocation.
+			 */
+			if (hint->laststate != previous_device_state) {
+				execute_state_callback(state_cb->change_cb,
+					ast_get_context_name(ast_get_extension_context(ne)),
+					ast_get_extension_name(ne),
+					state_cb->data,
+					AST_HINT_UPDATE_DEVICE,
+					hint,
+					NULL);
+			}
+			if (presence_state_changed) {
+				execute_state_callback(state_cb->change_cb,
+					ast_get_context_name(ast_get_extension_context(ne)),
+					ast_get_extension_name(ne),
+					state_cb->data,
+					AST_HINT_UPDATE_PRESENCE,
+					hint,
+					NULL);
+			}
+		}
+		ao2_iterator_destroy(&cb_iter);
+
+		ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(ne));
+
+		device_state_info = alloc_device_state_info();
+		ast_extension_state3(hint_app, device_state_info);
+
+		/* For extension callbacks */
+		cb_iter = ao2_iterator_init(hint->callbacks, 0);
+		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+			if (hint->laststate != previous_device_state) {
+				if (state_cb->extended && first_extended_cb_call) {
+				/* Fill detailed device_state_info now that we know it is used by extd. callback */
+					first_extended_cb_call = 0;
+					get_device_state_causing_channels(device_state_info);
+				}
+				execute_state_callback(state_cb->change_cb,
+					ast_get_context_name(ast_get_extension_context(ne)),
+					ast_get_extension_name(ne),
+					state_cb->data,
+					AST_HINT_UPDATE_DEVICE,
+					hint,
+					state_cb->extended ? device_state_info : NULL);
+			}
+			if (presence_state_changed) {
+				execute_state_callback(state_cb->change_cb,
+					ast_get_context_name(ast_get_extension_context(ne)),
+					ast_get_extension_name(ne),
+					state_cb->data,
+					AST_HINT_UPDATE_PRESENCE,
+					hint,
+					NULL);
+			}
+		}
+		ao2_iterator_destroy(&cb_iter);
+
+		ao2_cleanup(device_state_info);
+	}
+
 	ao2_ref(hint, -1);
 
+	ast_mutex_unlock(&context_merge_lock);
+
+	ast_free(hint_app);
+	ast_free(previous_message);
+	ast_free(previous_subtype);
+
 	return 0;
 }
 
@@ -5953,11 +6237,9 @@ void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
 
 	ast_channel_lock(chan);
 
-	/*
-	 * Make sure that the channel is marked as hungup since we are
-	 * going to run the h exten on it.
-	 */
-	ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);
+	if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
+		ast_cdr_end(ast_channel_cdr(chan));
+	}
 
 	/* Set h exten location */
 	if (context != ast_channel_context(chan)) {
@@ -5966,6 +6248,12 @@ void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
 	ast_channel_exten_set(chan, "h");
 	ast_channel_priority_set(chan, 1);
 
+	/*
+	 * Make sure that the channel is marked as hungup since we are
+	 * going to run the h exten on it.
+	 */
+	ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
+
 	/* Save autoloop flag */
 	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
@@ -6003,24 +6291,6 @@ void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
 	ast_channel_unlock(chan);
 }
 
-/*!
- * \internal
- * \brief Publish a hangup handler related message to \ref stasis
- */
-static void publish_hangup_handler_message(const char *action, struct ast_channel *chan, const char *handler)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	blob = ast_json_pack("{s: s, s: s}",
-			"type", action,
-			"handler", S_OR(handler, ""));
-	if (!blob) {
-		return;
-	}
-
-	ast_channel_publish_blob(chan, ast_channel_hangup_handler_type(), blob);
-}
-
 int ast_pbx_hangup_handler_run(struct ast_channel *chan)
 {
 	struct ast_hangup_handler_list *handlers;
@@ -6033,11 +6303,15 @@ int ast_pbx_hangup_handler_run(struct ast_channel *chan)
 		return 0;
 	}
 
+	if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
+		ast_cdr_end(ast_channel_cdr(chan));
+	}
+
 	/*
 	 * Make sure that the channel is marked as hungup since we are
 	 * going to run the hangup handlers on it.
 	 */
-	ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);
+	ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
 
 	for (;;) {
 		handlers = ast_channel_hangup_handlers(chan);
@@ -6046,7 +6320,23 @@ int ast_pbx_hangup_handler_run(struct ast_channel *chan)
 			break;
 		}
 
-		publish_hangup_handler_message("run", chan, h_handler->args);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a hangup handler is about to be called.</synopsis>
+				<syntax>
+					<parameter name="Handler">
+						<para>Hangup handler parameter string passed to the Gosub application.</para>
+					</parameter>
+				</syntax>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerRun",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"Handler: %s\r\n",
+			ast_channel_name(chan),
+			ast_channel_uniqueid(chan),
+			h_handler->args);
 		ast_channel_unlock(chan);
 
 		ast_app_exec_sub(NULL, chan, h_handler->args, 1);
@@ -6091,7 +6381,30 @@ int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
 	handlers = ast_channel_hangup_handlers(chan);
 	h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
 	if (h_handler) {
-		publish_hangup_handler_message("pop", chan, h_handler->args);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>
+					Raised when a hangup handler is removed from the handler
+					stack by the CHANNEL() function.
+				</synopsis>
+				<syntax>
+					<parameter name="Handler">
+						<para>Hangup handler parameter string passed to the Gosub application.</para>
+					</parameter>
+				</syntax>
+				<see-also>
+					<ref type="managerEvent">HangupHandlerPush</ref>
+					<ref type="function">CHANNEL</ref>
+				</see-also>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPop",
+			"Channel: %s\r\n"
+			"Uniqueid: %s\r\n"
+			"Handler: %s\r\n",
+			ast_channel_name(chan),
+			ast_channel_uniqueid(chan),
+			h_handler->args);
 	}
 	ast_channel_unlock(chan);
 	if (h_handler) {
@@ -6127,7 +6440,32 @@ void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
 
 	handlers = ast_channel_hangup_handlers(chan);
 	AST_LIST_INSERT_HEAD(handlers, h_handler, node);
-	publish_hangup_handler_message("push", chan, h_handler->args);
+
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>
+				Raised when a hangup handler is added to the handler
+				stack by the CHANNEL() function.
+			</synopsis>
+			<syntax>
+				<parameter name="Handler">
+					<para>Hangup handler parameter string passed to the Gosub application.</para>
+				</parameter>
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">HangupHandlerPop</ref>
+				<ref type="function">CHANNEL</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPush",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Handler: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		h_handler->args);
+
 	ast_channel_unlock(chan);
 }
 
@@ -6305,7 +6643,7 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 		ast_free(ast_channel_pbx(c));
 	}
 	if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
-		return AST_PBX_FAILED;
+		return -1;
 	}
 
 	callid = ast_read_threadstorage_callid();
@@ -6318,9 +6656,7 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 		if (!callid) {
 			callid = ast_create_callid();
 			if (callid) {
-				ast_channel_lock(c);
 				ast_channel_callid_set(c, callid);
-				ast_channel_unlock(c);
 			}
 		}
 		ast_callid_threadassoc_add(callid);
@@ -6348,6 +6684,12 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 		set_ext_pri(c, "s", 1);
 	}
 
+	ast_channel_lock(c);
+	if (ast_channel_cdr(c)) {
+		/* allow CDR variables that have been collected after channel was created to be visible during call */
+		ast_cdr_update(c);
+	}
+	ast_channel_unlock(c);
 	for (;;) {
 		char dst_exten[256];	/* buffer to accumulate digits */
 		int pos = 0;		/* XXX should check bounds */
@@ -6362,7 +6704,6 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 		while (!(res = ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
 			S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
 			&found, 1))) {
-
 			if (!ast_check_hangup(c)) {
 				ast_channel_priority_set(c, ast_channel_priority(c) + 1);
 				continue;
@@ -6458,6 +6799,11 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 					}
 					/* Call timed out with no special extension to jump to. */
 				}
+				ast_channel_lock(c);
+				if (ast_channel_cdr(c)) {
+					ast_cdr_update(c);
+				}
+				ast_channel_unlock(c);
 				error = 1;
 				break;
 			}
@@ -6563,6 +6909,12 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 					}
 				}
 			}
+			ast_channel_lock(c);
+			if (ast_channel_cdr(c)) {
+				ast_verb(2, "CDR updated on %s\n",ast_channel_name(c));
+				ast_cdr_update(c);
+			}
+			ast_channel_unlock(c);
 		}
 	}
 
@@ -6590,7 +6942,7 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
 		ast_hangup(c);
 	}
 
-	return AST_PBX_SUCCESS;
+	return 0;
 }
 
 /*!
@@ -6608,16 +6960,16 @@ static int increase_call_count(const struct ast_channel *c)
 #endif
 
 	ast_mutex_lock(&maxcalllock);
-	if (ast_option_maxcalls) {
-		if (countcalls >= ast_option_maxcalls) {
-			ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", ast_option_maxcalls, ast_channel_name(c));
+	if (option_maxcalls) {
+		if (countcalls >= option_maxcalls) {
+			ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, ast_channel_name(c));
 			failed = -1;
 		}
 	}
-	if (ast_option_maxload) {
+	if (option_maxload) {
 		getloadavg(&curloadavg, 1);
-		if (curloadavg >= ast_option_maxload) {
-			ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", ast_option_maxload, ast_channel_name(c), curloadavg);
+		if (curloadavg >= option_maxload) {
+			ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, ast_channel_name(c), curloadavg);
 			failed = -1;
 		}
 	}
@@ -7113,7 +7465,6 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
  * \note This function locks contexts list by &conlist, searches for the right context
  * structure, and locks the macrolock mutex in that context.
  * macrolock is used to limit a macro to be executed by one call at a time.
- * \param context The context
  */
 int ast_context_lockmacro(const char *context)
 {
@@ -7135,7 +7486,6 @@ int ast_context_lockmacro(const char *context)
  * \note This function locks contexts list by &conlist, searches for the right context
  * structure, and unlocks the macrolock mutex in that context.
  * macrolock is used to limit a macro to be executed by one call at a time.
- * \param context The context
  */
 int ast_context_unlockmacro(const char *context)
 {
@@ -7156,19 +7506,21 @@ int ast_context_unlockmacro(const char *context)
 /*! \brief Dynamically register a new dial plan application */
 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
 {
-	struct ast_app *tmp;
-	struct ast_app *cur;
-	int length;
+	struct ast_app *tmp, *cur = NULL;
+	char tmps[80];
+	int length, res;
 #ifdef AST_XML_DOCS
 	char *tmpxml;
 #endif
 
 	AST_RWLIST_WRLOCK(&apps);
-	cur = pbx_findapp_nolock(app);
-	if (cur) {
-		ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
-		AST_RWLIST_UNLOCK(&apps);
-		return -1;
+	AST_RWLIST_TRAVERSE(&apps, tmp, list) {
+		if (!(res = strcasecmp(app, tmp->name))) {
+			ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
+			AST_RWLIST_UNLOCK(&apps);
+			return -1;
+		} else if (res < 0)
+			break;
 	}
 
 	length = sizeof(*tmp) + strlen(app) + 1;
@@ -7236,7 +7588,7 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel
 	if (!cur)
 		AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
 
-	ast_verb(2, "Registered application '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, tmp->name));
+	ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
 
 	AST_RWLIST_UNLOCK(&apps);
 
@@ -7278,67 +7630,74 @@ void ast_unregister_switch(struct ast_switch *sw)
 
 static void print_app_docs(struct ast_app *aa, int fd)
 {
-#ifdef AST_XML_DOCS
-	char *synopsis = NULL, *description = NULL, *arguments = NULL, *seealso = NULL;
-	if (aa->docsrc == AST_XML_DOC) {
-		synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
-		description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
-		arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
-		seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
-		if (!synopsis || !description || !arguments || !seealso) {
-			goto free_docs;
-		}
-		ast_cli(fd, "\n"
-			"%s  -= Info about application '%s' =- %s\n\n"
-			COLORIZE_FMT "\n"
-			"%s\n\n"
-			COLORIZE_FMT "\n"
-			"%s\n\n"
-			COLORIZE_FMT "\n"
-			"%s%s%s\n\n"
-			COLORIZE_FMT "\n"
-			"%s\n\n"
-			COLORIZE_FMT "\n"
-			"%s\n",
-			ast_term_color(COLOR_MAGENTA, 0), aa->name, ast_term_reset(),
-			COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
-			COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
-			COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"),
-				ast_term_color(COLOR_CYAN, 0), S_OR(aa->syntax, "Not available"), ast_term_reset(),
-			COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
-			COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso);
-free_docs:
-		ast_free(synopsis);
-		ast_free(description);
-		ast_free(arguments);
-		ast_free(seealso);
-	} else
+	/* Maximum number of characters added by terminal coloring is 22 */
+	char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
+	char seealsotitle[40];
+	char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
+	char *seealso = NULL;
+	int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
+
+	snprintf(info, sizeof(info), "\n  -= Info about application '%s' =- \n\n", aa->name);
+	term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
+
+	term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
+	term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
+	term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
+	term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
+	term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
+
+#ifdef AST_XML_DOCS
+	if (aa->docsrc == AST_XML_DOC) {
+		description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
+		arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
+		synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
+		seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
+
+		if (!synopsis || !description || !arguments || !seealso) {
+			goto return_cleanup;
+		}
+	} else
 #endif
 	{
-		ast_cli(fd, "\n"
-			"%s  -= Info about application '%s' =- %s\n\n"
-			COLORIZE_FMT "\n"
-			COLORIZE_FMT "\n\n"
-			COLORIZE_FMT "\n"
-			COLORIZE_FMT "\n\n"
-			COLORIZE_FMT "\n"
-			COLORIZE_FMT "\n\n"
-			COLORIZE_FMT "\n"
-			COLORIZE_FMT "\n\n"
-			COLORIZE_FMT "\n"
-			COLORIZE_FMT "\n",
-			ast_term_color(COLOR_MAGENTA, 0), aa->name, ast_term_reset(),
-			COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"),
-			COLORIZE(COLOR_CYAN, 0, S_OR(aa->synopsis, "Not available")),
-			COLORIZE(COLOR_MAGENTA, 0, "[Description]"),
-			COLORIZE(COLOR_CYAN, 0, S_OR(aa->description, "Not available")),
-			COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"),
-			COLORIZE(COLOR_CYAN, 0, S_OR(aa->syntax, "Not available")),
-			COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"),
-			COLORIZE(COLOR_CYAN, 0, S_OR(aa->arguments, "Not available")),
-			COLORIZE(COLOR_MAGENTA, 0, "[See Also]"),
-			COLORIZE(COLOR_CYAN, 0, S_OR(aa->seealso, "Not available")));
+		synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
+		synopsis = ast_malloc(synopsis_size);
+
+		description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
+		description = ast_malloc(description_size);
+
+		arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
+		arguments = ast_malloc(arguments_size);
+
+		seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
+		seealso = ast_malloc(seealso_size);
+
+		if (!synopsis || !description || !arguments || !seealso) {
+			goto return_cleanup;
+		}
+
+		term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
+		term_color(description, S_OR(aa->description, "Not available"),	COLOR_CYAN, 0, description_size);
+		term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
+		term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
+	}
+
+	/* Handle the syntax the same for both XML and raw docs */
+	syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
+	if (!(syntax = ast_malloc(syntax_size))) {
+		goto return_cleanup;
 	}
+	term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
+
+	ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
+			infotitle, syntitle, synopsis, destitle, description,
+			stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
+
+return_cleanup:
+	ast_free(description);
+	ast_free(arguments);
+	ast_free(synopsis);
+	ast_free(seealso);
+	ast_free(syntax);
 }
 
 /*
@@ -7401,7 +7760,6 @@ static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_
 	int num = 0;
 	int watchers;
 	struct ao2_iterator i;
-	char buf[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2];
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -7409,12 +7767,11 @@ static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_
 		e->usage =
 			"Usage: core show hints\n"
 			"       List registered hints.\n"
-			"       Hint details are shown in five columns. In order from left to right, they are:\n"
+			"       Hint details are shown in four columns. In order from left to right, they are:\n"
 			"       1. Hint extension URI.\n"
-			"       2. List of mapped device or presence state identifiers.\n"
+			"       2. Mapped device state identifiers.\n"
 			"       3. Current extension state. The aggregate of mapped device states.\n"
-			"       4. Current presence state for the mapped presence state provider.\n"
-			"       5. Watchers - number of subscriptions and other entities watching this hint.\n";
+			"       4. Watchers - number of subscriptions and other entities watching this hint.\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
@@ -7436,17 +7793,11 @@ static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_
 			continue;
 		}
 		watchers = ao2_container_count(hint->callbacks);
-		sprintf(buf, "%s@%s",
+		ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
 			ast_get_extension_name(hint->exten),
-			ast_get_context_name(ast_get_extension_context(hint->exten)));
-
-		ast_cli(a->fd, "%-20.20s: %-20.20s  State:%-15.15s Presence:%-15.15s Watchers %2d\n",
-			buf,
+			ast_get_context_name(ast_get_extension_context(hint->exten)),
 			ast_get_extension_app(hint->exten),
-			ast_extension_state2str(hint->laststate),
-			ast_presence_state2str(hint->last_presence_state),
-			watchers);
-
+			ast_extension_state2str(hint->laststate), watchers);
 		ao2_unlock(hint);
 		num++;
 	}
@@ -7500,7 +7851,6 @@ static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 	int watchers;
 	int num = 0, extenlen;
 	struct ao2_iterator i;
-	char buf[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2];
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -7508,12 +7858,12 @@ static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		e->usage =
 			"Usage: core show hint <exten>\n"
 			"       List registered hint.\n"
-			"       Hint details are shown in five columns. In order from left to right, they are:\n"
+			"       Hint details are shown in four columns. In order from left to right, they are:\n"
 			"       1. Hint extension URI.\n"
-			"       2. List of mapped device or presence state identifiers.\n"
+			"       2. Mapped device state identifiers.\n"
 			"       3. Current extension state. The aggregate of mapped device states.\n"
-			"       4. Current presence state for the mapped presence state provider.\n"
-			"       5. Watchers - number of subscriptions and other entities watching this hint.\n";
+			"       4. Watchers - number of subscriptions and other entities watching this hint.\n";
+
 		return NULL;
 	case CLI_GENERATE:
 		return complete_core_show_hint(a->line, a->word, a->pos, a->n);
@@ -7538,15 +7888,11 @@ static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 		}
 		if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
 			watchers = ao2_container_count(hint->callbacks);
-			sprintf(buf, "%s@%s",
+			ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
 				ast_get_extension_name(hint->exten),
-				ast_get_context_name(ast_get_extension_context(hint->exten)));
-			ast_cli(a->fd, "%-20.20s: %-20.20s  State:%-15.15s Presence:%-15.15s Watchers %2d\n",
-				buf,
+				ast_get_context_name(ast_get_extension_context(hint->exten)),
 				ast_get_extension_app(hint->exten),
-				ast_extension_state2str(hint->laststate), 
-				ast_presence_state2str(hint->last_presence_state), 
-				watchers);
+				ast_extension_state2str(hint->laststate), watchers);
 			num++;
 		}
 		ao2_unlock(hint);
@@ -7593,81 +7939,6 @@ static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_c
 	return CLI_SUCCESS;
 }
 
-#if 0
-/* This code can be used to test if the system survives running out of memory.
- * It might be an idea to put this in only if ENABLE_AUTODESTRUCT_TESTS is enabled.
- *
- * If you want to test this, these Linux sysctl flags might be appropriate:
- *   vm.overcommit_memory = 2
- *   vm.swappiness = 0
- *
- * <@Corydon76-home> I envision 'core eat disk space' and 'core eat file descriptors' now
- * <@mjordan> egads
- * <@mjordan> it's literally the 'big red' auto-destruct button
- * <@mjordan> if you were wondering who even builds such a thing.... well, now you know
- * ...
- * <@Corydon76-home> What about if they lived only if you defined TEST_FRAMEWORK?  Shouldn't have those on production machines
- * <@mjordan> I think accompanied with an update to one of our README files that "no, really, TEST_FRAMEWORK isn't for you", I'd be fine
- */
-static char *handle_eat_memory(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	void **blocks;
-	int blocks_pos = 0;
-	const int blocks_max = 50000;
-	long long int allocated = 0;
-	int sizes[] = {
-		100 * 1024 * 1024,
-		100 * 1024,
-		2 * 1024,
-		400,
-		0
-	};
-	int i;
-
-	switch (cmd) {
-	case CLI_INIT:
-		/* To do: add method to free memory again? 5 minutes? */
-		e->command = "core eat memory";
-		e->usage =
-			"Usage: core eat memory\n"
-			"       Eats all available memory so you can test if the system survives\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	blocks = ast_malloc(sizeof(void*) * blocks_max);
-	if (!blocks) {
-		ast_log(LOG_ERROR, "Already out of mem?\n");
-		return CLI_SUCCESS;
-	}
-
-	for (i = 0; sizes[i]; ++i) {
-		int alloc_size = sizes[i];
-		ast_log(LOG_WARNING, "Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
-		while (1) {
-			void *block;
-			if (blocks_pos >= blocks_max) {
-				ast_log(LOG_ERROR, "Memory buffer too small? Run me again :)\n");
-				break;
-			}
-
-			block = ast_malloc(alloc_size);
-			if (!block) {
-				break;
-			}
-
-			blocks[blocks_pos++] = block;
-			allocated += alloc_size;
-		}
-	}
-
-	/* No freeing of the mem! */
-	ast_log(LOG_WARNING, "Allocated %lld bytes total!\n", allocated);
-	return CLI_SUCCESS;
-}
-#endif
-
 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_app *aa;
@@ -8403,8 +8674,8 @@ static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, str
 /*! \brief CLI support for listing chanvar's variables in a parseable way */
 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct ast_channel *chan;
-	struct ast_var_t *var;
+	struct ast_channel *chan = NULL;
+	struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -8417,23 +8688,22 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl
 		return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
 	}
 
-	if (a->argc != e->args + 1) {
+	if (a->argc != e->args + 1)
 		return CLI_SHOWUSAGE;
-	}
 
-	chan = ast_channel_get_by_name(a->argv[e->args]);
-	if (!chan) {
+	if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) {
 		ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
 		return CLI_FAILURE;
 	}
 
-	ast_channel_lock(chan);
-	AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
-		ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
+	pbx_builtin_serialize_variables(chan, &vars);
+
+	if (ast_str_strlen(vars)) {
+		ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
 	}
-	ast_channel_unlock(chan);
 
-	ast_channel_unref(chan);
+	chan = ast_channel_unref(chan);
+
 	return CLI_SUCCESS;
 }
 
@@ -8556,9 +8826,6 @@ static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd,
  * CLI entries for upper commands ...
  */
 static struct ast_cli_entry pbx_cli[] = {
-#if 0
-	AST_CLI_DEFINE(handle_eat_memory, "Eats all available memory"),
-#endif
 	AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
 	AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
 	AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
@@ -8602,32 +8869,23 @@ static void unreference_cached_app(struct ast_app *app)
 
 int ast_unregister_application(const char *app)
 {
-	struct ast_app *cur;
-	int cmp;
+	struct ast_app *tmp;
 
 	AST_RWLIST_WRLOCK(&apps);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
-		cmp = strcasecmp(app, cur->name);
-		if (cmp > 0) {
-			continue;
-		}
-		if (!cmp) {
-			/* Found it. */
-			unreference_cached_app(cur);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
+		if (!strcasecmp(app, tmp->name)) {
+			unreference_cached_app(tmp);
 			AST_RWLIST_REMOVE_CURRENT(list);
-			ast_verb(2, "Unregistered application '%s'\n", cur->name);
-			ast_string_field_free_memory(cur);
-			ast_free(cur);
+			ast_verb(2, "Unregistered application '%s'\n", tmp->name);
+			ast_string_field_free_memory(tmp);
+			ast_free(tmp);
 			break;
 		}
-		/* Not in container. */
-		cur = NULL;
-		break;
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END;
 	AST_RWLIST_UNLOCK(&apps);
 
-	return cur ? 0 : -1;
+	return tmp ? 0 : -1;
 }
 
 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
@@ -8655,9 +8913,9 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
 		ast_rdlock_contexts();
 		local_contexts = &contexts;
 		tmp = ast_hashtab_lookup(contexts_table, &search);
-		ast_unlock_contexts();
 		if (tmp) {
 			tmp->refcount++;
+			ast_unlock_contexts();
 			return tmp;
 		}
 	} else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
@@ -8681,15 +8939,18 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
 		tmp->refcount = 1;
 	} else {
 		ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
+		if (!extcontexts) {
+			ast_unlock_contexts();
+		}
 		return NULL;
 	}
 
 	if (!extcontexts) {
-		ast_wrlock_contexts();
 		tmp->next = *local_contexts;
 		*local_contexts = tmp;
 		ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
 		ast_unlock_contexts();
+		ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
 		ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
 	} else {
 		tmp->next = *local_contexts;
@@ -8697,6 +8958,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
 			ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
 
 		*local_contexts = tmp;
+		ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
 		ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
 	}
 	return tmp;
@@ -8810,7 +9072,7 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *
 				dupdstr = ast_strdup(prio_item->data);
 
 				res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
-										  prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
+										  prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar);
 				if (!res1 && new_exten_item && new_prio_item){
 					ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
 							context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
@@ -9007,7 +9269,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
 
 	/*
 	 * Notify watchers of all removed hints with the same lock
-	 * environment as device_state_cb().
+	 * environment as handle_statechange().
 	 */
 	while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
 		/* this hint has been removed, notify the watchers */
@@ -9240,12 +9502,7 @@ static const char * const months[] =
 	"dec",
 	NULL,
 };
-/*! /brief Build timing
- *
- * /param i info
- * /param info_in
- *
- */
+
 int ast_build_timing(struct ast_timing *i, const char *info_in)
 {
 	char *info;
@@ -9584,18 +9841,24 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const
 
 int ast_ignore_pattern(const char *context, const char *pattern)
 {
-	struct ast_context *con = ast_context_find(context);
+	int ret = 0;
+	struct ast_context *con;
 
+	ast_rdlock_contexts();
+	con = ast_context_find(context);
 	if (con) {
 		struct ast_ignorepat *pat;
 
 		for (pat = con->ignorepats; pat; pat = pat->next) {
-			if (ast_extension_match(pat->pattern, pattern))
-				return 1;
+			if (ast_extension_match(pat->pattern, pattern)) {
+				ret = 1;
+				break;
+			}
 		}
 	}
+	ast_unlock_contexts();
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -9666,35 +9929,84 @@ int ast_explicit_goto(struct ast_channel *chan, const char *context, const char
 
 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
 {
-	struct ast_channel *newchan;
+	int res = 0;
+	struct ast_channel *tmpchan;
+	struct {
+		char *accountcode;
+		char *exten;
+		char *context;
+		char *linkedid;
+		char *name;
+		struct ast_cdr *cdr;
+		int amaflags;
+		int state;
+		struct ast_format readformat;
+		struct ast_format writeformat;
+	} tmpvars = { 0, };
 
 	ast_channel_lock(chan);
-	/* Channels in a bridge or running a PBX can be sent directly to the specified destination */
-	if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
-		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
-			priority += 1;
-		}
-		ast_explicit_goto(chan, context, exten, priority);
+	if (ast_channel_pbx(chan)) { /* This channel is currently in the PBX */
+		ast_explicit_goto(chan, context, exten, priority + 1);
 		ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
 		ast_channel_unlock(chan);
-		return 0;
+		return res;
 	}
+
+	/* In order to do it when the channel doesn't really exist within
+	 * the PBX, we have to make a new channel, masquerade, and start the PBX
+	 * at the new location */
+	tmpvars.accountcode = ast_strdupa(ast_channel_accountcode(chan));
+	tmpvars.exten = ast_strdupa(ast_channel_exten(chan));
+	tmpvars.context = ast_strdupa(ast_channel_context(chan));
+	tmpvars.linkedid = ast_strdupa(ast_channel_linkedid(chan));
+	tmpvars.name = ast_strdupa(ast_channel_name(chan));
+	tmpvars.amaflags = ast_channel_amaflags(chan);
+	tmpvars.state = ast_channel_state(chan);
+	ast_format_copy(&tmpvars.writeformat, ast_channel_writeformat(chan));
+	ast_format_copy(&tmpvars.readformat, ast_channel_readformat(chan));
+	tmpvars.cdr = ast_channel_cdr(chan) ? ast_cdr_dup(ast_channel_cdr(chan)) : NULL;
+
 	ast_channel_unlock(chan);
 
-	/* Otherwise, we need to gain control of the channel first */
-	newchan = ast_channel_yank(chan);
-	if (!newchan) {
-		ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
+	/* Do not hold any channel locks while calling channel_alloc() since the function
+	 * locks the channel container when linking the new channel in. */
+	if (!(tmpchan = ast_channel_alloc(0, tmpvars.state, 0, 0, tmpvars.accountcode, tmpvars.exten, tmpvars.context, tmpvars.linkedid, tmpvars.amaflags, "AsyncGoto/%s", tmpvars.name))) {
+		ast_cdr_discard(tmpvars.cdr);
 		return -1;
 	}
-	ast_explicit_goto(newchan, context, exten, priority);
-	if (ast_pbx_start(newchan)) {
-		ast_hangup(newchan);
-		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
-		return -1;
+
+	/* copy the cdr info over */
+	if (tmpvars.cdr) {
+		ast_cdr_discard(ast_channel_cdr(tmpchan));
+		ast_channel_cdr_set(tmpchan, tmpvars.cdr);
+		tmpvars.cdr = NULL;
 	}
 
-	return 0;
+	/* Make formats okay */
+	ast_format_copy(ast_channel_readformat(tmpchan), &tmpvars.readformat);
+	ast_format_copy(ast_channel_writeformat(tmpchan), &tmpvars.writeformat);
+
+	/* Setup proper location. Never hold another channel lock while calling this function. */
+	ast_explicit_goto(tmpchan, S_OR(context, tmpvars.context), S_OR(exten, tmpvars.exten), priority);
+
+	/* Masquerade into tmp channel */
+	if (ast_channel_masquerade(tmpchan, chan)) {
+		/* Failed to set up the masquerade.  It's probably chan_local
+		 * in the middle of optimizing itself out.  Sad. :( */
+		ast_hangup(tmpchan);
+		tmpchan = NULL;
+		res = -1;
+	} else {
+		ast_do_masquerade(tmpchan);
+		/* Start the PBX going on our stolen channel */
+		if (ast_pbx_start(tmpchan)) {
+			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmpchan));
+			ast_hangup(tmpchan);
+			res = -1;
+		}
+	}
+
+	return res;
 }
 
 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
@@ -9939,16 +10251,6 @@ int ast_add_extension2(struct ast_context *con,
 		application, data, datad, registrar, 1);
 }
 
-int ast_add_extension2_nolock(struct ast_context *con,
-	int replace, const char *extension, int priority, const char *label, const char *callerid,
-	const char *application, void *data, void (*datad)(void *),
-	const char *registrar)
-{
-	return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
-		application, data, datad, registrar, 0);
-}
-
-
 /*!
  * \brief Same as ast_add_extension2() but controls the context locking.
  *
@@ -10099,8 +10401,8 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
 			ast_unlock_context(con);
 		}
 		if (res < 0) {
-			errno = EEXIST;
-			return -1;
+			errno = EEXIST;	/* XXX do we care ? */
+			return 0; /* XXX should we return -1 maybe ? */
 		}
 	} else {
 		/*
@@ -10182,408 +10484,475 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
 	return 0;
 }
 
-/*! \brief Structure which contains information about an outgoing dial */
-struct pbx_outgoing {
-	/*! \brief Dialing structure being used */
-	struct ast_dial *dial;
-	/*! \brief Condition for synchronous dialing */
-	ast_cond_t cond;
-	/*! \brief Application to execute */
-	char app[AST_MAX_APP];
-	/*! \brief Application data to pass to application */
-	char *appdata;
-	/*! \brief Dialplan context */
+struct async_stat {
+	pthread_t p;
+	struct ast_channel *chan;
 	char context[AST_MAX_CONTEXT];
-	/*! \brief Dialplan extension */
 	char exten[AST_MAX_EXTENSION];
-	/*! \brief Dialplan priority */
 	int priority;
-	/*! \brief Result of the dial operation when dialed is set */
-	int dial_res;
-	/*! \brief Set when dialing is completed */
-	unsigned int dialed:1;
-	/*! \brief Set when execution is completed */
-	unsigned int executed:1;
+	int timeout;
+	char app[AST_MAX_EXTENSION];
+	char appdata[1024];
+	int early_media;			/* Connect the bridge if early media arrives, don't wait for answer */
 };
 
-/*! \brief Destructor for outgoing structure */
-static void pbx_outgoing_destroy(void *obj)
-{
-	struct pbx_outgoing *outgoing = obj;
-
-	if (outgoing->dial) {
-		ast_dial_destroy(outgoing->dial);
-	}
-
-	ast_cond_destroy(&outgoing->cond);
-
-	ast_free(outgoing->appdata);
-}
-
-/*! \brief Internal function which dials an outgoing leg and sends it to a provided extension or application */
-static void *pbx_outgoing_exec(void *data)
+static void *async_wait(void *data)
 {
-	RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
-	enum ast_dial_result res;
-
-	/* Notify anyone interested that dialing is complete */
-	res = ast_dial_run(outgoing->dial, NULL, 0);
-	ao2_lock(outgoing);
-	outgoing->dial_res = res;
-	outgoing->dialed = 1;
-	ast_cond_signal(&outgoing->cond);
-	ao2_unlock(outgoing);
-
-	/* If the outgoing leg was not answered we can immediately return and go no further */
-	if (res != AST_DIAL_RESULT_ANSWERED) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(outgoing->app)) {
-		struct ast_app *app = pbx_findapp(outgoing->app);
+	struct async_stat *as = data;
+	struct ast_channel *chan = as->chan;
+	int timeout = as->timeout;
+	int res;
+	struct ast_frame *f;
+	struct ast_app *app;
+	int have_early_media = 0;
+	struct timeval start = ast_tvnow();
+	int ms;
 
-		if (app) {
-			ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
-				ast_channel_name(ast_dial_answered(outgoing->dial)));
-			pbx_exec(ast_dial_answered(outgoing->dial), app, outgoing->appdata);
-		} else {
-			ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
+	if (chan) {
+		struct ast_callid *callid = ast_channel_callid(chan);
+		if (callid) {
+			ast_callid_threadassoc_add(callid);
+			ast_callid_unref(callid);
 		}
-	} else {
-		struct ast_channel *answered = ast_dial_answered(outgoing->dial);
+	}
 
-		if (!ast_strlen_zero(outgoing->context)) {
-			ast_channel_context_set(answered, outgoing->context);
-		}
+	while ((ms = ast_remaining_ms(start, timeout)) &&
+			ast_channel_state(chan) != AST_STATE_UP) {
+		res = ast_waitfor(chan, ms);
+		if (res < 1)
+			break;
 
-		if (!ast_strlen_zero(outgoing->exten)) {
-			ast_channel_exten_set(answered, outgoing->exten);
+		f = ast_read(chan);
+		if (!f)
+			break;
+		if (f->frametype == AST_FRAME_CONTROL) {
+			if ((f->subclass.integer == AST_CONTROL_BUSY)  ||
+			    (f->subclass.integer == AST_CONTROL_CONGESTION) ) {
+				ast_frfree(f);
+				break;
+			}
+			if (as->early_media && f->subclass.integer == AST_CONTROL_PROGRESS) {
+				have_early_media = 1;
+				ast_frfree(f);
+				break;
+			}
 		}
-
-		if (outgoing->priority > 0) {
-			ast_channel_priority_set(answered, outgoing->priority);
+		ast_frfree(f);
+	}
+	if (ast_channel_state(chan) == AST_STATE_UP || have_early_media) {
+		if (have_early_media) {
+			ast_debug(2, "Activating pbx since we have early media \n");
 		}
-
-		if (ast_pbx_run(answered)) {
-			ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered));
+		if (!ast_strlen_zero(as->app)) {
+			app = pbx_findapp(as->app);
+			if (app) {
+				ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, ast_channel_name(chan));
+				pbx_exec(chan, app, as->appdata);
+			} else
+				ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
 		} else {
-			/* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
-			ast_dial_answered_steal(outgoing->dial);
+			if (!ast_strlen_zero(as->context))
+				ast_channel_context_set(chan, as->context);
+			if (!ast_strlen_zero(as->exten))
+				ast_channel_exten_set(chan, as->exten);
+			if (as->priority > 0)
+				ast_channel_priority_set(chan, as->priority);
+			/* Run the PBX */
+			if (ast_pbx_run(chan)) {
+				ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
+			} else {
+				/* PBX will have taken care of this */
+				chan = NULL;
+			}
 		}
 	}
-
-	/* Notify anyone else again that may be interested that execution is complete */
-	ao2_lock(outgoing);
-	outgoing->executed = 1;
-	ast_cond_signal(&outgoing->cond);
-	ao2_unlock(outgoing);
-
+	ast_free(as);
+	if (chan)
+		ast_hangup(chan);
 	return NULL;
 }
 
-/*! \brief Internal dialing state callback which causes early media to trigger an answer */
-static void pbx_outgoing_state_callback(struct ast_dial *dial)
+/*!
+ * \brief Function to post an empty cdr after a spool call fails.
+ * \note This function posts an empty cdr for a failed spool call
+*/
+static int ast_pbx_outgoing_cdr_failed(void)
 {
-	struct ast_channel *channel;
+	/* allocate a channel */
+	struct ast_channel *chan = ast_dummy_channel_alloc();
 
-	if (ast_dial_state(dial) != AST_DIAL_RESULT_PROGRESS) {
-		return;
-	}
+	if (!chan)
+		return -1;  /* failure */
 
-	if (!(channel = ast_dial_get_channel(dial, 0))) {
-		return;
+	ast_channel_cdr_set(chan, ast_cdr_alloc());
+	if (!ast_channel_cdr(chan)) {
+		/* allocation of the cdr failed */
+		chan = ast_channel_unref(chan);   /* free the channel */
+		return -1;                /* return failure */
 	}
 
-	ast_verb(4, "Treating progress as answer on '%s' due to early media option\n",
-		ast_channel_name(channel));
+	/* allocation of the cdr was successful */
+	ast_cdr_init(ast_channel_cdr(chan), chan);  /* initialize our channel's cdr */
+	ast_cdr_start(ast_channel_cdr(chan));       /* record the start and stop time */
+	ast_cdr_end(ast_channel_cdr(chan));
+	ast_cdr_failed(ast_channel_cdr(chan));      /* set the status to failed */
+	ast_cdr_detach(ast_channel_cdr(chan));      /* post and free the record */
+	ast_channel_cdr_set(chan, NULL);
+	chan = ast_channel_unref(chan);         /* free the channel */
 
-	ast_queue_control(channel, AST_CONTROL_ANSWER);
+	return 0;  /* success */
 }
 
-/*!
- * \brief Attempt to convert disconnect cause to old originate reason.
- *
- * \todo XXX The old originate reasons need to be trashed and replaced
- * with normal disconnect cause codes if the call was not answered.
- * The internal consumers of the reason values would also need to be
- * updated: app_originate, call files, and AMI OriginateResponse.
- */
-static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
+int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel, int early_media)
 {
-	enum ast_control_frame_type pbx_reason;
-
-	if (dial_result == AST_DIAL_RESULT_ANSWERED) {
-		/* Remote end answered. */
-		pbx_reason = AST_CONTROL_ANSWER;
-	} else if (dial_result == AST_DIAL_RESULT_HANGUP) {
-		/* Caller hungup */
-		pbx_reason = AST_CONTROL_HANGUP;
-	} else {
-		switch (cause) {
-		case AST_CAUSE_USER_BUSY:
-			pbx_reason = AST_CONTROL_BUSY;
-			break;
-		case AST_CAUSE_CALL_REJECTED:
-		case AST_CAUSE_NETWORK_OUT_OF_ORDER:
-		case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
-		case AST_CAUSE_NORMAL_TEMPORARY_FAILURE:
-		case AST_CAUSE_SWITCH_CONGESTION:
-		case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-			pbx_reason = AST_CONTROL_CONGESTION;
-			break;
-		case AST_CAUSE_ANSWERED_ELSEWHERE:
-		case AST_CAUSE_NO_ANSWER:
-			/* Remote end was ringing (but isn't anymore) */
-			pbx_reason = AST_CONTROL_RINGING;
-			break;
-		case AST_CAUSE_UNALLOCATED:
-		default:
-			/* Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?) */
-			pbx_reason = 0;
-			break;
-		}
-	}
+	struct ast_channel *chan;
+	struct async_stat *as;
+	struct ast_callid *callid;
+	int callid_created = 0;
+	int res = -1, cdr_res = -1;
+	struct outgoing_helper oh;
 
-	return pbx_reason;
-}
+	oh.connect_on_early_media = early_media;
 
-static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
-	const char *addr, int timeout, const char *context, const char *exten, int priority,
-	const char *app, const char *appdata, int *reason, int synchronous,
-	const char *cid_num, const char *cid_name, struct ast_variable *vars,
-	const char *account, struct ast_channel **locked_channel, int early_media,
-	const struct ast_assigned_ids *assignedids)
-{
-	RAII_VAR(struct pbx_outgoing *, outgoing, NULL, ao2_cleanup);
-	struct ast_channel *dialed;
-	pthread_t thread;
+	callid_created = ast_callid_threadstorage_auto(&callid);
 
-	outgoing = ao2_alloc(sizeof(*outgoing), pbx_outgoing_destroy);
-	if (!outgoing) {
-		return -1;
-	}
-	ast_cond_init(&outgoing->cond, NULL);
+	if (synchronous) {
+		oh.context = context;
+		oh.exten = exten;
+		oh.priority = priority;
+		oh.cid_num = cid_num;
+		oh.cid_name = cid_name;
+		oh.account = account;
+		oh.vars = vars;
+		oh.parent_channel = NULL;
+
+		chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
+		if (channel) {
+			*channel = chan;
+			if (chan)
+				ast_channel_lock(chan);
+		}
+		if (chan) {
+			/* Bind the callid to the channel if it doesn't already have one on creation */
+			struct ast_callid *channel_callid = ast_channel_callid(chan);
+			if (channel_callid) {
+				ast_callid_unref(channel_callid);
+			} else {
+				if (callid) {
+					ast_channel_callid_set(chan, callid);
+				}
+			}
 
-	if (!ast_strlen_zero(app)) {
-		ast_copy_string(outgoing->app, app, sizeof(outgoing->app));
-		outgoing->appdata = ast_strdup(appdata);
-	} else {
-		ast_copy_string(outgoing->context, context, sizeof(outgoing->context));
-		ast_copy_string(outgoing->exten, exten, sizeof(outgoing->exten));
-		outgoing->priority = priority;
-	}
+			if (ast_channel_state(chan) == AST_STATE_UP || (early_media && *reason == AST_CONTROL_PROGRESS)) {
+					res = 0;
+				ast_verb(4, "Channel %s %s\n", ast_channel_name(chan), ast_channel_state(chan) == AST_STATE_UP ? "was answered" : "got early media");
+
+				if (synchronous > 1) {
+					if (channel)
+						ast_channel_unlock(chan);
+					if (ast_pbx_run(chan)) {
+						ast_log(LOG_ERROR, "Unable to run PBX on %s\n", ast_channel_name(chan));
+						if (channel)
+							*channel = NULL;
+						ast_hangup(chan);
+						chan = NULL;
+						res = -1;
+					}
+				} else {
+					if (ast_pbx_start(chan)) {
+						ast_log(LOG_ERROR, "Unable to start PBX on %s\n", ast_channel_name(chan));
+						if (channel) {
+							*channel = NULL;
+							ast_channel_unlock(chan);
+						}
+						ast_hangup(chan);
+						res = -1;
+					}
+					chan = NULL;
+				}
+			} else {
+				ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(chan));
 
-	if (!(outgoing->dial = ast_dial_create())) {
-		return -1;
-	}
+				if (ast_channel_cdr(chan)) { /* update the cdr */
+					/* here we update the status of the call, which sould be busy.
+					 * if that fails then we set the status to failed */
+					if (ast_cdr_disposition(ast_channel_cdr(chan), ast_channel_hangupcause(chan)))
+						ast_cdr_failed(ast_channel_cdr(chan));
+				}
 
-	if (ast_dial_append(outgoing->dial, type, addr, assignedids)) {
-		return -1;
-	}
+				if (channel) {
+					*channel = NULL;
+					ast_channel_unlock(chan);
+				}
+				ast_hangup(chan);
+				chan = NULL;
+			}
+		}
 
-	ast_dial_set_global_timeout(outgoing->dial, timeout);
+		if (res < 0) { /* the call failed for some reason */
+			if (*reason == 0) { /* if the call failed (not busy or no answer)
+				            * update the cdr with the failed message */
+				cdr_res = ast_pbx_outgoing_cdr_failed();
+				if (cdr_res != 0) {
+					res = cdr_res;
+					goto outgoing_exten_cleanup;
+				}
+			}
 
-	if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
-		if (synchronous && reason) {
-			*reason = pbx_dial_reason(AST_DIAL_RESULT_FAILED,
-				ast_dial_reason(outgoing->dial, 0));
+			/* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
+			/* check if "failed" exists */
+			if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
+				chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", NULL, 0, "OutgoingSpoolFailed");
+				if (chan) {
+					char failed_reason[4] = "";
+					if (!ast_strlen_zero(context))
+						ast_channel_context_set(chan, context);
+					set_ext_pri(chan, "failed", 1);
+					ast_set_variables(chan, vars);
+					snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
+					pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
+					if (account)
+						ast_cdr_setaccount(chan, account);
+					if (ast_pbx_run(chan)) {
+						ast_log(LOG_ERROR, "Unable to run PBX on %s\n", ast_channel_name(chan));
+						ast_hangup(chan);
+					}
+					chan = NULL;
+				}
+			}
+		}
+	} else {
+		struct ast_callid *channel_callid;
+		if (!(as = ast_calloc(1, sizeof(*as)))) {
+			res = -1;
+			goto outgoing_exten_cleanup;
+		}
+		chan = ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name);
+		if (channel) {
+			*channel = chan;
+			if (chan)
+				ast_channel_lock(chan);
+		}
+		if (!chan) {
+			ast_free(as);
+			res = -1;
+			goto outgoing_exten_cleanup;
 		}
-		return -1;
-	}
 
-	dialed = ast_dial_get_channel(outgoing->dial, 0);
-	if (!dialed) {
-		return -1;
+		/* Bind the newly created callid to the channel if it doesn't already have one on creation. */
+		channel_callid = ast_channel_callid(chan);
+		if (channel_callid) {
+			ast_callid_unref(channel_callid);
+		} else {
+			if (callid) {
+				ast_channel_callid_set(chan, callid);
+			}
+		}
+
+		as->chan = chan;
+		ast_copy_string(as->context, context, sizeof(as->context));
+		set_ext_pri(as->chan,  exten, priority);
+		as->timeout = timeout;
+		ast_set_variables(chan, vars);
+		if (account)
+			ast_cdr_setaccount(chan, account);
+		if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
+			ast_log(LOG_WARNING, "Failed to start async wait\n");
+			ast_free(as);
+			if (channel) {
+				*channel = NULL;
+				ast_channel_unlock(chan);
+			}
+			ast_hangup(chan);
+			res = -1;
+			goto outgoing_exten_cleanup;
+		}
+		res = 0;
 	}
 
-	ast_channel_lock(dialed);
-	if (vars) {
-		ast_set_variables(dialed, vars);
-	}
-	if (!ast_strlen_zero(account)) {
-		ast_channel_stage_snapshot(dialed);
-		ast_channel_accountcode_set(dialed, account);
-		ast_channel_peeraccount_set(dialed, account);
-		ast_channel_stage_snapshot_done(dialed);
-	}
-	ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED);
-	ast_channel_unlock(dialed);
+outgoing_exten_cleanup:
+	ast_callid_threadstorage_auto_clean(callid, callid_created);
+	ast_variables_destroy(vars);
+	return res;
+}
 
-	if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
-		struct ast_party_connected_line connected;
+struct app_tmp {
+	struct ast_channel *chan;
+	pthread_t t;
+	AST_DECLARE_STRING_FIELDS (
+		AST_STRING_FIELD(app);
+		AST_STRING_FIELD(data);
+	);
+};
 
-		/*
-		 * It seems strange to set the CallerID on an outgoing call leg
-		 * to whom we are calling, but this function's callers are doing
-		 * various Originate methods.  This call leg goes to the local
-		 * user.  Once the called party answers, the dialplan needs to
-		 * be able to access the CallerID from the CALLERID function as
-		 * if the called party had placed this call.
-		 */
-		ast_set_callerid(dialed, cid_num, cid_name, cid_num);
+/*! \brief run the application and free the descriptor once done */
+static void *ast_pbx_run_app(void *data)
+{
+	struct app_tmp *tmp = data;
+	struct ast_app *app;
+	app = pbx_findapp(tmp->app);
+	if (app) {
+		ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, ast_channel_name(tmp->chan));
+		pbx_exec(tmp->chan, app, tmp->data);
+	} else
+		ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
+	ast_hangup(tmp->chan);
+	ast_string_field_free_memory(tmp);
+	ast_free(tmp);
+	return NULL;
+}
 
-		ast_party_connected_line_set_init(&connected, ast_channel_connected(dialed));
-		if (!ast_strlen_zero(cid_num)) {
-			connected.id.number.valid = 1;
-			connected.id.number.str = (char *) cid_num;
-			connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-		}
-		if (!ast_strlen_zero(cid_name)) {
-			connected.id.name.valid = 1;
-			connected.id.name.str = (char *) cid_name;
-			connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-		}
-		ast_channel_set_connected_line(dialed, &connected, NULL);
-	}
+int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
+{
+	struct ast_channel *chan;
+	struct app_tmp *tmp;
+	struct ast_callid *callid;
+	int callid_created;
+	int res = -1, cdr_res = -1;
+	struct outgoing_helper oh;
 
-	if (early_media) {
-		ast_dial_set_state_callback(outgoing->dial, pbx_outgoing_state_callback);
-	}
+	/* Start by checking for a callid in threadstorage, and if none is found, bind one. */
+	callid_created = ast_callid_threadstorage_auto(&callid);
 
-	if (locked_channel) {
-		/*
-		 * Keep a dialed channel ref since the caller wants
-		 * the channel returned.  We must get the ref before
-		 * spawning off pbx_outgoing_exec().
-		 */
-		ast_channel_ref(dialed);
-		if (!synchronous) {
-			/*
-			 * Lock it now to hold off pbx_outgoing_exec() in case the
-			 * calling function needs the channel state/snapshot before
-			 * dialing actually happens.
-			 */
-			ast_channel_lock(dialed);
-		}
+	memset(&oh, 0, sizeof(oh));
+	oh.vars = vars;
+	oh.account = account;
+
+	if (locked_channel)
+		*locked_channel = NULL;
+	if (ast_strlen_zero(app)) {
+		res = -1;
+		goto outgoing_app_cleanup;
 	}
+	if (synchronous) {
+		chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
+		if (chan) {
+			/* Bind the newly created callid to the channel if it doesn't already have one on creation */
+			struct ast_callid *channel_callid = ast_channel_callid(chan);
+			if (channel_callid) {
+				ast_callid_unref(channel_callid);
+			} else {
+				if (callid) {
+					ast_channel_callid_set(chan, callid);
+				}
+			}
 
-	ao2_ref(outgoing, +1);
-	if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
-		ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
-		ao2_ref(outgoing, -1);
-		if (locked_channel) {
-			if (!synchronous) {
-				ast_channel_unlock(dialed);
+			ast_set_variables(chan, vars);
+			if (account)
+				ast_cdr_setaccount(chan, account);
+			if (ast_channel_state(chan) == AST_STATE_UP) {
+				res = 0;
+				ast_verb(4, "Channel %s was answered.\n", ast_channel_name(chan));
+				tmp = ast_calloc(1, sizeof(*tmp));
+				if (!tmp || ast_string_field_init(tmp, 252)) {
+					if (tmp) {
+						ast_free(tmp);
+					}
+					res = -1;
+				} else {
+					ast_string_field_set(tmp, app, app);
+					ast_string_field_set(tmp, data, appdata);
+					tmp->chan = chan;
+					if (synchronous > 1) {
+						if (locked_channel)
+							ast_channel_unlock(chan);
+						ast_pbx_run_app(tmp);
+					} else {
+						if (locked_channel)
+							ast_channel_lock(chan);
+						if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
+							ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", ast_channel_name(chan), strerror(errno));
+							ast_string_field_free_memory(tmp);
+							ast_free(tmp);
+							if (locked_channel)
+								ast_channel_unlock(chan);
+							ast_hangup(chan);
+							res = -1;
+						} else {
+							if (locked_channel)
+								*locked_channel = chan;
+						}
+					}
+				}
+			} else {
+				ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(chan));
+				if (ast_channel_cdr(chan)) { /* update the cdr */
+					/* here we update the status of the call, which sould be busy.
+					 * if that fails then we set the status to failed */
+					if (ast_cdr_disposition(ast_channel_cdr(chan), ast_channel_hangupcause(chan)))
+						ast_cdr_failed(ast_channel_cdr(chan));
+				}
+				ast_hangup(chan);
 			}
-			ast_channel_unref(dialed);
 		}
-		return -1;
-	}
 
-	if (synchronous) {
-		ao2_lock(outgoing);
-		/* Wait for dialing to complete */
-		while (!outgoing->dialed) {
-			ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
-		}
-		if (1 < synchronous
-			&& outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) {
-			/* Wait for execution to complete */
-			while (!outgoing->executed) {
-				ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
+		if (res < 0) { /* the call failed for some reason */
+			if (*reason == 0) { /* if the call failed (not busy or no answer)
+				            * update the cdr with the failed message */
+				cdr_res = ast_pbx_outgoing_cdr_failed();
+				if (cdr_res != 0) {
+					res = cdr_res;
+					goto outgoing_app_cleanup;
+				}
 			}
 		}
-		ao2_unlock(outgoing);
 
-		/* Determine the outcome of the dialing attempt up to it being answered. */
-		if (reason) {
-			*reason = pbx_dial_reason(outgoing->dial_res,
-				ast_dial_reason(outgoing->dial, 0));
+	} else {
+		struct async_stat *as;
+		struct ast_callid *channel_callid;
+		if (!(as = ast_calloc(1, sizeof(*as)))) {
+			res = -1;
+			goto outgoing_app_cleanup;
+		}
+		chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
+		if (!chan) {
+			ast_free(as);
+			res = -1;
+			goto outgoing_app_cleanup;
 		}
 
-		if (outgoing->dial_res != AST_DIAL_RESULT_ANSWERED) {
-			/* The dial operation failed. */
-			if (locked_channel) {
-				ast_channel_unref(dialed);
+		/* Bind the newly created callid to the channel if it doesn't already have one on creation. */
+		channel_callid = ast_channel_callid(chan);
+		if (channel_callid) {
+			ast_callid_unref(channel_callid);
+		} else {
+			if (callid) {
+				ast_channel_callid_set(chan, callid);
 			}
-			return -1;
-		}
-		if (locked_channel) {
-			ast_channel_lock(dialed);
 		}
-	}
-
-	if (locked_channel) {
-		*locked_channel = dialed;
-	}
-	return 0;
-}
-
-int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
-	int timeout, const char *context, const char *exten, int priority, int *reason,
-	int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
-	const char *account, struct ast_channel **locked_channel, int early_media,
-	const struct ast_assigned_ids *assignedids)
-{
-	int res;
-	int my_reason;
-
-	if (!reason) {
-		reason = &my_reason;
-	}
-	*reason = 0;
-	if (locked_channel) {
-		*locked_channel = NULL;
-	}
-
-	res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
-		NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
-		early_media, assignedids);
 
-	if (res < 0 /* Call failed to get connected for some reason. */
-		&& 1 < synchronous
-		&& ast_exists_extension(NULL, context, "failed", 1, NULL)) {
-		struct ast_channel *failed;
-
-		/* We do not have to worry about a locked_channel if dialing failed. */
-		ast_assert(!locked_channel || !*locked_channel);
-
-		/*!
-		 * \todo XXX Not good.  The channel name is not unique if more than
-		 * one originate fails at a time.
-		 */
-		failed = ast_channel_alloc(0, AST_STATE_DOWN, cid_num, cid_name, account,
-			"failed", context, NULL, NULL, 0, "OutgoingSpoolFailed");
-		if (failed) {
-			char failed_reason[12];
-
-			ast_set_variables(failed, vars);
-			snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
-			pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
-			ast_channel_unlock(failed);
-
-			if (ast_pbx_run(failed)) {
-				ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n",
-					ast_channel_name(failed));
-				ast_hangup(failed);
-			}
+		as->chan = chan;
+		ast_copy_string(as->app, app, sizeof(as->app));
+		if (appdata)
+			ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
+		as->timeout = timeout;
+		ast_set_variables(chan, vars);
+		if (account)
+			ast_cdr_setaccount(chan, account);
+		/* Start a new thread, and get something handling this channel. */
+		if (locked_channel)
+			ast_channel_lock(chan);
+		if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
+			ast_log(LOG_WARNING, "Failed to start async wait\n");
+			ast_free(as);
+			if (locked_channel)
+				ast_channel_unlock(chan);
+			ast_hangup(chan);
+			res = -1;
+			goto outgoing_app_cleanup;
+		} else {
+			if (locked_channel)
+				*locked_channel = chan;
 		}
+		res = 0;
 	}
 
+outgoing_app_cleanup:
+	ast_callid_threadstorage_auto_clean(callid, callid_created);
+	ast_variables_destroy(vars);
 	return res;
 }
 
-int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
-	int timeout, const char *app, const char *appdata, int *reason, int synchronous,
-	const char *cid_num, const char *cid_name, struct ast_variable *vars,
-	const char *account, struct ast_channel **locked_channel,
-	const struct ast_assigned_ids *assignedids)
-{
-	if (reason) {
-		*reason = 0;
-	}
-	if (locked_channel) {
-		*locked_channel = NULL;
-	}
-	if (ast_strlen_zero(app)) {
-		return -1;
-	}
-
-	return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
-		reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
-		assignedids);
-}
-
 /* this is the guts of destroying a context --
    freeing up the structure, traversing and destroying the
    extensions, switches, ignorepats, includes, etc. etc. */
@@ -10717,6 +11086,16 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 				exten_iter = ast_hashtab_start_traversal(tmp->root_table);
 				while ((exten_item=ast_hashtab_next(exten_iter))) {
 					int end_traversal = 1;
+
+					/*
+					 * If the extension could not be removed from the root_table due to
+					 * a loaded PBX app, it can exist here but have its peer_table be
+					 * destroyed due to a previous pass through this function.
+					 */
+					if (!exten_item->peer_table) {
+						continue;
+					}
+
 					prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
 					while ((prio_item=ast_hashtab_next(prio_iter))) {
 						char extension[AST_MAX_EXTENSION];
@@ -10793,6 +11172,22 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 	}
 }
 
+int ast_context_destroy_by_name(const char *context, const char *registrar)
+{
+	struct ast_context *con;
+	int ret = -1;
+
+	ast_wrlock_contexts();
+	con = ast_context_find(context);
+	if (con) {
+		ast_context_destroy(con, registrar);
+		ret = 0;
+	}
+	ast_unlock_contexts();
+
+	return ret;
+}
+
 void ast_context_destroy(struct ast_context *con, const char *registrar)
 {
 	ast_wrlock_contexts();
@@ -10857,12 +11252,10 @@ static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
 	ast_indicate(chan, AST_CONTROL_BUSY);
 	/* Don't change state of an UP channel, just indicate
 	   busy in audio */
-	ast_channel_lock(chan);
 	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
 		ast_setstate(chan, AST_STATE_BUSY);
+		ast_cdr_busy(ast_channel_cdr(chan));
 	}
-	ast_channel_unlock(chan);
 	wait_for_hangup(chan, data);
 	return -1;
 }
@@ -10875,12 +11268,10 @@ static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
 	ast_indicate(chan, AST_CONTROL_CONGESTION);
 	/* Don't change state of an UP channel, just indicate
 	   congestion in audio */
-	ast_channel_lock(chan);
 	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
 		ast_setstate(chan, AST_STATE_BUSY);
+		ast_cdr_congestion(ast_channel_cdr(chan));
 	}
-	ast_channel_unlock(chan);
 	wait_for_hangup(chan, data);
 	return -1;
 }
@@ -10891,6 +11282,7 @@ static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
 static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
 {
 	int delay = 0;
+	int answer_cdr = 1;
 	char *parse;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(delay);
@@ -10898,7 +11290,7 @@ static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
 	);
 
 	if (ast_strlen_zero(data)) {
-		return __ast_answer(chan, 0);
+		return __ast_answer(chan, 0, 1);
 	}
 
 	parse = ast_strdupa(data);
@@ -10913,10 +11305,10 @@ static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
 	}
 
 	if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
-		ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
+		answer_cdr = 0;
 	}
 
-	return __ast_answer(chan, delay);
+	return __ast_answer(chan, delay, answer_cdr);
 }
 
 static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
@@ -10933,7 +11325,7 @@ static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
 	if (ast_check_hangup(chan)) {
 		return -1;
 	} else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
-		__ast_answer(chan, 0);
+		__ast_answer(chan, 0, 1);
 	}
 
 	ast_indicate(chan, AST_CONTROL_INCOMPLETE);
@@ -10941,30 +11333,39 @@ static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
 	return AST_PBX_INCOMPLETE;
 }
 
+AST_APP_OPTIONS(resetcdr_opts, {
+	AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
+	AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
+	AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
+	AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
+});
+
 /*!
  * \ingroup applications
  */
-static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
+static int pbx_builtin_resetcdr(struct ast_channel *chan, const char *data)
 {
-	ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n");
+	char *args;
+	struct ast_flags flags = { 0 };
 
-	if (ast_strlen_zero(data)) {
-		ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n");
-		return 0;
+	if (!ast_strlen_zero(data)) {
+		args = ast_strdupa(data);
+		ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
 	}
+
+	ast_cdr_reset(ast_channel_cdr(chan), &flags);
+
+	return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
+static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
+{
 	/* Copy the AMA Flags as specified */
 	ast_channel_lock(chan);
-	if (isdigit(data[0])) {
-		int amaflags;
-		if (sscanf(data, "%30d", &amaflags) != 1) {
-			ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan));
-			ast_channel_unlock(chan);
-			return 0;
-		}
-		ast_channel_amaflags_set(chan, amaflags);
-	} else {
-		ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data));
-	}
+	ast_cdr_setamaflags(chan, data ? data : "");
 	ast_channel_unlock(chan);
 	return 0;
 }
@@ -11503,11 +11904,21 @@ int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
 	AST_LIST_TRAVERSE_SAFE_END;
 
 	if (value && (newvariable = ast_var_assign(name, value))) {
-		if (headp == &globals) {
+		if (headp == &globals)
 			ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
-		}
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
-		ast_channel_publish_varset(chan, name, value);
+		/*** DOCUMENTATION
+			<managerEventInstance>
+				<synopsis>Raised when a variable is set to a particular value.</synopsis>
+			</managerEventInstance>
+		***/
+		manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
+			"Channel: %s\r\n"
+			"Variable: %s\r\n"
+			"Value: %s\r\n"
+			"Uniqueid: %s\r\n",
+			chan ? ast_channel_name(chan) : "none", name, value,
+			chan ? ast_channel_uniqueid(chan) : "none");
 	}
 
 	if (chan)
@@ -11521,6 +11932,10 @@ int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
 {
 	char *name, *value, *mydata;
 
+	if (ast_compat_app_set) {
+		return pbx_builtin_setvar_multiple(chan, data);
+	}
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
 		return 0;
@@ -11669,18 +12084,7 @@ static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
 {
 	char tmp[256];
 	char *number = tmp;
-	int number_val;
 	char *options;
-	int res;
-	int interrupt = 0;
-	const char *interrupt_string;
-
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		interrupt = 1;
-	}
-	ast_channel_unlock(chan);
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
@@ -11688,12 +12092,6 @@ static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
 	}
 	ast_copy_string(tmp, data, sizeof(tmp));
 	strsep(&number, ",");
-
-	if (sscanf(tmp, "%d", &number_val) != 1) {
-		ast_log(LOG_WARNING, "argument '%s' to SayNumber could not be parsed as a number.\n", tmp);
-		return 0;
-	}
-
 	options = strsep(&number, ",");
 	if (options) {
 		if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
@@ -11703,235 +12101,102 @@ static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
 		}
 	}
 
-	res = ast_say_number(chan, number_val, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), options);
-
-	if (res < 0) {
+	if (ast_say_number(chan, atoi(tmp), "", ast_channel_language(chan), options)) {
 		ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
 	}
 
-	return interrupt ? res : 0;
+	return 0;
 }
 
 static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
-	int interrupt = 0;
-	const char *interrupt_string;
-
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		interrupt = 1;
-	}
-	ast_channel_unlock(chan);
-
-	if (data) {
-		res = ast_say_digit_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
-	}
-
-	return res;
-}
-
-static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data)
-{
-	int res = 0;
-	int sensitivity = 0;
-	char *parse;
-	int interrupt = 0;
-	const char *interrupt_string;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(options);
-		AST_APP_ARG(characters);
-	);
-
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		interrupt = 1;
-	}
-	ast_channel_unlock(chan);
-
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n");
-		return 0;
-	}
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (!args.options || strlen(args.options) != 1) {
-		ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n");
-		return 0;
-	}
-
-	switch (args.options[0]) {
-	case 'a':
-		sensitivity = AST_SAY_CASE_ALL;
-		break;
-	case 'l':
-		sensitivity = AST_SAY_CASE_LOWER;
-		break;
-	case 'n':
-		sensitivity = AST_SAY_CASE_NONE;
-		break;
-	case 'u':
-		sensitivity = AST_SAY_CASE_UPPER;
-		break;
-	default:
-		ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options);
-		return 0;
-	}
-
-	res = ast_say_character_str(chan, args.characters, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), sensitivity);
 
+	if (data)
+		res = ast_say_digit_str(chan, data, "", ast_channel_language(chan));
 	return res;
 }
 
 static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
-	int interrupt = 0;
-	const char *interrupt_string;
-
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		interrupt = 1;
-	}
-	ast_channel_unlock(chan);
-
-	if (data) {
-		res = ast_say_character_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), AST_SAY_CASE_NONE);
-	}
 
+	if (data)
+		res = ast_say_character_str(chan, data, "", ast_channel_language(chan));
 	return res;
 }
 
 static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
-	int interrupt = 0;
-	const char *interrupt_string;
-
-	ast_channel_lock(chan);
-	interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
-	if (ast_true(interrupt_string)) {
-		interrupt = 1;
-	}
-	ast_channel_unlock(chan);
 
 	if (data)
-		res = ast_say_phonetic_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
+		res = ast_say_phonetic_str(chan, data, "", ast_channel_language(chan));
 	return res;
 }
 
-static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
+static void presencechange_destroy(void *data)
 {
-	struct ast_presence_state_message *presence_state = stasis_message_data(msg);
-	struct ast_hint *hint;
-	struct ast_str *hint_app = NULL;
-	struct ao2_iterator hint_iter;
-	struct ao2_iterator cb_iter;
-	char context_name[AST_MAX_CONTEXT];
-	char exten_name[AST_MAX_EXTENSION];
+	struct presencechange *pc = data;
+	ast_free(pc->provider);
+	ast_free(pc->subtype);
+	ast_free(pc->message);
+}
+
+static void presence_state_cb(const struct ast_event *event, void *unused)
+{
+	struct presencechange *pc;
+	const char *tmp;
 
-	if (stasis_message_type(msg) != ast_presence_state_message_type()) {
+	if (!(pc = ao2_alloc(sizeof(*pc), presencechange_destroy))) {
 		return;
 	}
 
-	hint_app = ast_str_create(1024);
-	if (!hint_app) {
+	tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER);
+	if (ast_strlen_zero(tmp)) {
+		ast_log(LOG_ERROR, "Received invalid event that had no presence provider IE\n");
+		ao2_ref(pc, -1);
 		return;
 	}
+	pc->provider = ast_strdup(tmp);
 
-	ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
-	hint_iter = ao2_iterator_init(hints, 0);
-	for (; (hint = ao2_iterator_next(&hint_iter)); ao2_cleanup(hint)) {
-		struct ast_state_cb *state_cb;
-		const char *app;
-		char *parse;
-		SCOPED_AO2LOCK(lock, hint);
-
-		if (!hint->exten) {
-			/* The extension has already been destroyed */
-			continue;
-		}
-
-		/* Does this hint monitor the device that changed state? */
-		app = ast_get_extension_app(hint->exten);
-		if (ast_strlen_zero(app)) {
-			/* The hint does not monitor presence at all. */
-			continue;
-		}
-
-		ast_str_set(&hint_app, 0, "%s", app);
-		parse = parse_hint_presence(hint_app);
-		if (ast_strlen_zero(parse)) {
-			continue;
-		}
-		if (strcasecmp(parse, presence_state->provider)) {
-			/* The hint does not monitor the presence provider. */
-			continue;
-		}
-
-		/*
-		 * Save off strings in case the hint extension gets destroyed
-		 * while we are notifying the watchers.
-		 */
-		ast_copy_string(context_name,
-			ast_get_context_name(ast_get_extension_context(hint->exten)),
-			sizeof(context_name));
-		ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
-			sizeof(exten_name));
-		ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
+	pc->state = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+	if (pc->state < 0) {
+		ao2_ref(pc, -1);
+		return;
+	}
 
-		/* Check to see if update is necessary */
-		if ((hint->last_presence_state == presence_state->state) &&
-			((hint->last_presence_subtype && presence_state->subtype && !strcmp(hint->last_presence_subtype, presence_state->subtype)) || (!hint->last_presence_subtype && !presence_state->subtype)) &&
-			((hint->last_presence_message && presence_state->message && !strcmp(hint->last_presence_message, presence_state->message)) || (!hint->last_presence_message && !presence_state->message))) {
+	if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE))) {
+		pc->subtype = ast_strdup(tmp);
+	}
 
-			/* this update is the same as the last, do nothing */
-			continue;
-		}
+	if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE))) {
+		pc->message = ast_strdup(tmp);
+	}
 
-		/* update new values */
-		ast_free(hint->last_presence_subtype);
-		ast_free(hint->last_presence_message);
-		hint->last_presence_state = presence_state->state;
-		hint->last_presence_subtype = presence_state->subtype ? ast_strdup(presence_state->subtype) : NULL;
-		hint->last_presence_message = presence_state->message ? ast_strdup(presence_state->message) : NULL;
+	/* The task processor thread is taking our reference to the presencechange object. */
+	if (ast_taskprocessor_push(extension_state_tps, handle_presencechange, pc) < 0) {
+		ao2_ref(pc, -1);
+	}
+}
 
-		/* For general callbacks */
-		cb_iter = ao2_iterator_init(statecbs, 0);
-		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
-			execute_state_callback(state_cb->change_cb,
-				context_name,
-				exten_name,
-				state_cb->data,
-				AST_HINT_UPDATE_PRESENCE,
-				hint,
-				NULL);
-		}
-		ao2_iterator_destroy(&cb_iter);
+static void device_state_cb(const struct ast_event *event, void *unused)
+{
+	const char *device;
+	struct statechange *sc;
 
-		/* For extension callbacks */
-		cb_iter = ao2_iterator_init(hint->callbacks, 0);
-		for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
-			execute_state_callback(state_cb->change_cb,
-				context_name,
-				exten_name,
-				state_cb->data,
-				AST_HINT_UPDATE_PRESENCE,
-				hint,
-				NULL);
-		}
-		ao2_iterator_destroy(&cb_iter);
+	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+	if (ast_strlen_zero(device)) {
+		ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
+		return;
 	}
-	ao2_iterator_destroy(&hint_iter);
-	ast_mutex_unlock(&context_merge_lock);
 
-	ast_free(hint_app);
+	if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
+		return;
+	strcpy(sc->dev, device);
+	if (ast_taskprocessor_push(extension_state_tps, handle_statechange, sc) < 0) {
+		ast_free(sc);
+	}
 }
 
 /*!
@@ -11984,104 +12249,46 @@ static const struct ast_data_entry pbx_data_providers[] = {
 	AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
 };
 
-static int action_extensionstatelist(struct mansession *s, const struct message *m)
-{
-	const char *action_id = astman_get_header(m, "ActionID");
-	struct ast_hint *hint;
-	struct ao2_iterator it_hints;
-	int hint_count = 0;
-
-	if (!hints) {
-		astman_send_error(s, m, "No dialplan hints are available");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "Extension Statuses will follow", "start");
-
-	ao2_lock(hints);
-	it_hints = ao2_iterator_init(hints, 0);
-	for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
-
-		ao2_lock(hint);
-
-		/* Ignore pattern matching hints; they are stored in the
-		 * hints container but aren't real from the perspective of
-		 * an AMI user
-		 */
-		if (hint->exten->exten[0] == '_') {
-			ao2_unlock(hint);
-			continue;
-		}
-
-		++hint_count;
-
-		astman_append(s, "Event: ExtensionStatus\r\n");
-		if (!ast_strlen_zero(action_id)) {
-			astman_append(s, "ActionID: %s\r\n", action_id);
-		}
-		astman_append(s,
-		   "Exten: %s\r\n"
-		   "Context: %s\r\n"
-		   "Hint: %s\r\n"
-		   "Status: %d\r\n"
-		   "StatusText: %s\r\n\r\n",
-		   hint->exten->exten,
-		   hint->exten->parent->name,
-		   hint->exten->app,
-		   hint->laststate,
-		   ast_extension_state2str(hint->laststate));
-		ao2_unlock(hint);
-	}
-	astman_append(s, "Event: ExtensionStateListComplete\r\n");
-	if (!ast_strlen_zero(action_id)) {
-		astman_append(s, "ActionID: %s\r\n", action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		"ListItems: %d\r\n\r\n", hint_count);
-
-	ao2_iterator_destroy(&it_hints);
-	ao2_unlock(hints);
-
-	return 0;
-}
-
-
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown.
- *
- * \note Cleans up resources allocated in load_pbx
- */
+/*! \internal \brief Clean up resources on Asterisk shutdown.
+ * \note Cleans up resources allocated in load_pbx */
 static void unload_pbx(void)
 {
 	int x;
 
-	presence_state_sub = stasis_unsubscribe_and_join(presence_state_sub);
-	device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
+	if (presence_state_sub) {
+		presence_state_sub = ast_event_unsubscribe(presence_state_sub);
+	}
+	if (device_state_sub) {
+		device_state_sub = ast_event_unsubscribe(device_state_sub);
+	}
 
 	/* Unregister builtin applications */
 	for (x = 0; x < ARRAY_LEN(builtins); x++) {
 		ast_unregister_application(builtins[x].name);
 	}
 	ast_manager_unregister("ShowDialPlan");
-	ast_manager_unregister("ExtensionStateList");
 	ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
 	ast_custom_function_unregister(&exception_function);
 	ast_custom_function_unregister(&testtime_function);
 	ast_data_unregister(NULL);
+	if (extension_state_tps) {
+		extension_state_tps = ast_taskprocessor_unreference(extension_state_tps);
+	}
 }
 
 int load_pbx(void)
 {
-	int res = 0;
 	int x;
 
-	ast_register_atexit(unload_pbx);
+	ast_register_cleanup(unload_pbx);
 
 	/* Initialize the PBX */
 	ast_verb(1, "Asterisk PBX Core Initializing\n");
+	if (!(extension_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
+		ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
+	}
 
-	ast_verb(2, "Registering builtin applications and functions:\n");
+	ast_verb(1, "Registering builtin applications:\n");
 	ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
 	ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
 	__ast_custom_function_register(&exception_function, NULL);
@@ -12089,6 +12296,7 @@ int load_pbx(void)
 
 	/* Register builtin applications */
 	for (x = 0; x < ARRAY_LEN(builtins); x++) {
+		ast_verb(1, "[%s]\n", builtins[x].name);
 		if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
 			ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
 			return -1;
@@ -12096,18 +12304,15 @@ int load_pbx(void)
 	}
 
 	/* Register manager application */
-	res |= ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
-	res |= ast_manager_register_xml_core("ExtensionStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstatelist);
-
-	if (res) {
-		return -1;
-	}
+	ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
 
-	if (!(device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL))) {
+	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "pbx Device State Change", NULL,
+			AST_EVENT_IE_END))) {
 		return -1;
 	}
 
-	if (!(presence_state_sub = stasis_subscribe(ast_presence_state_topic_all(), presence_state_cb, NULL))) {
+	if (!(presence_state_sub = ast_event_subscribe(AST_EVENT_PRESENCE_STATE, presence_state_cb, "pbx Presence State Change", NULL,
+			AST_EVENT_IE_END))) {
 		return -1;
 	}
 
@@ -12418,29 +12623,17 @@ int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
 
 char *ast_complete_applications(const char *line, const char *word, int state)
 {
-	struct ast_app *app;
+	struct ast_app *app = NULL;
 	int which = 0;
-	int cmp;
 	char *ret = NULL;
 	size_t wordlen = strlen(word);
 
 	AST_RWLIST_RDLOCK(&apps);
 	AST_RWLIST_TRAVERSE(&apps, app, list) {
-		cmp = strncasecmp(word, app->name, wordlen);
-		if (cmp > 0) {
-			continue;
-		}
-		if (!cmp) {
-			/* Found match. */
-			if (++which <= state) {
-				/* Not enough matches. */
-				continue;
-			}
+		if (!strncasecmp(word, app->name, wordlen) && ++which > state) {
 			ret = ast_strdup(app->name);
 			break;
 		}
-		/* Not in container. */
-		break;
 	}
 	AST_RWLIST_UNLOCK(&apps);
 
diff --git a/main/pickup.c b/main/pickup.c
deleted file mode 100644
index cf0e764..0000000
--- a/main/pickup.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2013, Digium, Inc.
- * Copyright (C) 2012, Russell Bryant
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Routines implementing call pickup
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-/*!
- * \li Call pickup uses the configuration file \ref features.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="Pickup">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a call pickup occurs.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<channel_snapshot prefix="Target"/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "asterisk/pickup.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/app.h"
-#include "asterisk/callerid.h"
-#include "asterisk/causes.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/features_config.h"
-
-static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message);
-
-STASIS_MESSAGE_TYPE_DEFN(
-	ast_call_pickup_type,
-	.to_ami = call_pickup_to_ami);
-
-
-/*!
- * The presence of this datastore on the channel indicates that
- * someone is attemting to pickup or has picked up the channel.
- * The purpose is to prevent a race between two channels
- * attempting to pickup the same channel.
- */
-static const struct ast_datastore_info pickup_active = {
-	.type = "pickup-active",
-};
-
-int ast_can_pickup(struct ast_channel *chan)
-{
-	if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
-		&& (ast_channel_state(chan) == AST_STATE_RINGING
-			|| ast_channel_state(chan) == AST_STATE_RING
-			/*
-			 * Check the down state as well because some SIP devices do not
-			 * give 180 ringing when they can just give 183 session progress
-			 * instead.  Issue 14005.  (Some ISDN switches as well for that
-			 * matter.)
-			 */
-			|| ast_channel_state(chan) == AST_STATE_DOWN)
-		&& !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
-		return 1;
-	}
-	return 0;
-}
-
-static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_channel *target = obj; /*!< Potential pickup target */
-	struct ast_channel *chan = arg;   /*!< Channel wanting to pickup call */
-
-	if (chan == target) {
-		return 0;
-	}
-
-	ast_channel_lock(target);
-	if (ast_can_pickup(target)) {
-		/* Lock both channels. */
-		while (ast_channel_trylock(chan)) {
-			ast_channel_unlock(target);
-			sched_yield();
-			ast_channel_lock(target);
-		}
-
-		/*
-		 * Both callgroup and namedcallgroup pickup variants are
-		 * matched independently.  Checking for named group match is
-		 * done last since it's a more expensive operation.
-		 */
-		if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
-			|| (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan),
-				ast_channel_named_callgroups(target)))) {
-			struct ao2_container *candidates = data;/*!< Candidate channels found. */
-
-			/* This is a candidate to pickup */
-			ao2_link(candidates, target);
-		}
-		ast_channel_unlock(chan);
-	}
-	ast_channel_unlock(target);
-
-	return 0;
-}
-
-struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan)
-{
-	struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
-	struct ast_channel *target;/*!< Potential pickup target */
-
-	candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
-	if (!candidates) {
-		return NULL;
-	}
-
-	/* Find all candidate targets by group. */
-	ast_channel_callback(find_channel_by_group, chan, candidates, 0);
-
-	/* Find the oldest pickup target candidate */
-	target = NULL;
-	for (;;) {
-		struct ast_channel *candidate;/*!< Potential new older target */
-		struct ao2_iterator iter;
-
-		iter = ao2_iterator_init(candidates, 0);
-		while ((candidate = ao2_iterator_next(&iter))) {
-			if (!target) {
-				/* First target. */
-				target = candidate;
-				continue;
-			}
-			if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
-				/* We have a new target. */
-				ast_channel_unref(target);
-				target = candidate;
-				continue;
-			}
-			ast_channel_unref(candidate);
-		}
-		ao2_iterator_destroy(&iter);
-		if (!target) {
-			/* No candidates found. */
-			break;
-		}
-
-		/* The found channel must be locked and ref'd. */
-		ast_channel_lock(target);
-
-		/* Recheck pickup ability */
-		if (ast_can_pickup(target)) {
-			/* This is the channel to pickup. */
-			break;
-		}
-
-		/* Someone else picked it up or the call went away. */
-		ast_channel_unlock(target);
-		ao2_unlink(candidates, target);
-		target = ast_channel_unref(target);
-	}
-	ao2_ref(candidates, -1);
-
-	return target;
-}
-
-/*!
- * \brief Pickup a call
- * \param chan channel that initiated pickup.
- *
- * Walk list of channels, checking it is not itself, channel is pbx one,
- * check that the callgroup for both channels are the same and the channel is ringing.
- * Answer calling channel, flag channel as answered on queue, masq channels together.
- */
-int ast_pickup_call(struct ast_channel *chan)
-{
-	struct ast_channel *target;/*!< Potential pickup target */
-	int res = -1;
-	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
-	const char *pickup_sound;
-	const char *fail_sound;
-
-	ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan));
-	ast_channel_lock(chan);
-	pickup_cfg = ast_get_chan_features_pickup_config(chan);
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n");
-	}
-	pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : "");
-	fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : "");
-	ast_channel_unlock(chan);
-
-	/* The found channel is already locked. */
-	target = ast_pickup_find_by_group(chan);
-	if (target) {
-		ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
-
-		res = ast_do_pickup(chan, target);
-		ast_channel_unlock(target);
-		if (!res) {
-			if (!ast_strlen_zero(pickup_sound)) {
-				pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound);
-			}
-		} else {
-			ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
-		}
-		target = ast_channel_unref(target);
-	}
-
-	if (res < 0) {
-		ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
-		if (!ast_strlen_zero(fail_sound)) {
-			ast_answer(chan);
-			ast_stream_and_wait(chan, fail_sound, "");
-		}
-	}
-
-	return res;
-}
-
-static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *contents = stasis_message_data(message);
-	struct ast_channel_snapshot *chan;
-	struct ast_channel_snapshot *target;
-	struct ast_manager_event_blob *res;
-
-	RAII_VAR(struct ast_str *, channel_str, NULL, ast_free);
-	RAII_VAR(struct ast_str *, target_str, NULL, ast_free);
-
-	chan = ast_multi_channel_blob_get_channel(contents, "channel");
-	target = ast_multi_channel_blob_get_channel(contents, "target");
-
-	ast_assert(chan != NULL && target != NULL);
-
-	if (!(channel_str = ast_manager_build_channel_state_string(chan))) {
-		return NULL;
-	}
-
-	if (!(target_str = ast_manager_build_channel_state_string_prefix(target, "Target"))) {
-		return NULL;
-	}
-
-	res = ast_manager_event_blob_create(EVENT_FLAG_CALL, "Pickup",
-		"%s"
-		"%s",
-		ast_str_buffer(channel_str),
-		ast_str_buffer(target_str));
-
-	return res;
-}
-
-static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!ast_call_pickup_type()) {
-		return -1;
-	}
-
-	if (!(pickup_payload = ast_multi_channel_blob_create(ast_json_null()))) {
-		return -1;
-	}
-
-	ast_multi_channel_blob_add_channel(pickup_payload, "channel", chan);
-	ast_multi_channel_blob_add_channel(pickup_payload, "target", target);
-
-	if (!(msg = stasis_message_create(ast_call_pickup_type(), pickup_payload))) {
-		return -1;
-	}
-
-	stasis_publish(ast_channel_topic(picking_up), msg);
-	return 0;
-}
-
-int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
-{
-	struct ast_party_connected_line connected_caller;
-	struct ast_datastore *ds_pickup;
-	const char *chan_name;/*!< A masquerade changes channel names. */
-	const char *target_name;/*!< A masquerade changes channel names. */
-	int res = -1;
-
-	RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);
-
-	target_name = ast_strdupa(ast_channel_name(target));
-	ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
-
-	/* Mark the target to block any call pickup race. */
-	ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
-	if (!ds_pickup) {
-		ast_log(LOG_WARNING,
-			"Unable to create channel datastore on '%s' for call pickup\n", target_name);
-		return -1;
-	}
-	ast_channel_datastore_add(target, ds_pickup);
-
-	ast_party_connected_line_init(&connected_caller);
-	ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
-	ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
-	/* Reset any earlier private connected id representation */
-	ast_party_id_reset(&connected_caller.priv);
-
-	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-	if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
-		ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
-		ast_channel_update_connected_line(chan, &connected_caller, NULL);
-	}
-	ast_party_connected_line_free(&connected_caller);
-
-	ast_channel_lock(chan);
-	chan_name = ast_strdupa(ast_channel_name(chan));
-	ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
-	ast_channel_unlock(chan);
-	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-
-	if (ast_answer(chan)) {
-		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
-		goto pickup_failed;
-	}
-
-	if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
-		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
-		goto pickup_failed;
-	}
-
-	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
-
-	/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
-	ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
-
-	ast_channel_lock(chan);
-	chan_snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (!chan_snapshot) {
-		goto pickup_failed;
-	}
-
-	target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
-	if (!target_snapshot) {
-		goto pickup_failed;
-	}
-
-	if (ast_channel_move(target, chan)) {
-		ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
-			chan_name, target_name);
-		goto pickup_failed;
-	}
-
-	/* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
-	send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);
-
-	res = 0;
-
-pickup_failed:
-	ast_channel_lock(target);
-	if (!ast_channel_datastore_remove(target, ds_pickup)) {
-		ast_datastore_free(ds_pickup);
-	}
-	ast_party_connected_line_free(&connected_caller);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
-static void pickup_shutdown(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_call_pickup_type);
-}
-
-int ast_pickup_init(void)
-{
-	STASIS_MESSAGE_TYPE_INIT(ast_call_pickup_type);
-	ast_register_atexit(pickup_shutdown);
-
-	return 0;
-}
diff --git a/main/plc.c b/main/plc.c
index da8852d..1f02069 100644
--- a/main/plc.c
+++ b/main/plc.c
@@ -36,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
diff --git a/main/poll.c b/main/poll.c
index 6cb13f9..e0f6955 100644
--- a/main/poll.c
+++ b/main/poll.c
@@ -1,5 +1,5 @@
 /*---------------------------------------------------------------------------*\
-  $Id: poll.c 285269 2010-09-07 19:09:08Z tilghman $
+  $Id$
 
   NAME
 
diff --git a/main/presencestate.c b/main/presencestate.c
index 294794f..09a73e6 100644
--- a/main/presencestate.c
+++ b/main/presencestate.c
@@ -25,39 +25,9 @@
 	<support_level>core</support_level>
  ***/
 
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="PresenceStateChange">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a presence state changes</synopsis>
-			<syntax>
-				<parameter name="Presentity">
-					<para>The entity whose presence state has changed</para>
-				</parameter>
-				<parameter name="Status">
-					<para>The new status of the presentity</para>
-				</parameter>
-				<parameter name="Subtype">
-					<para>The new subtype of the presentity</para>
-				</parameter>
-				<parameter name="Message">
-					<para>The new message of the presentity</para>
-				</parameter>
-			</syntax>
-			<description>
-				<para>This differs from the <literal>PresenceStatus</literal>
-				event because this event is raised for all presence state changes,
-				not only for changes that affect dialplan hints.</para>
-			</description>
-			<see-also>
-				<ref type="managerEvent">PresenceStatus</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/utils.h"
@@ -66,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/presencestate.h"
 #include "asterisk/pbx.h"
 #include "asterisk/app.h"
+#include "asterisk/event.h"
 
 /*! \brief Device state strings for printing */
 static const struct {
@@ -82,14 +53,13 @@ static const struct {
 	{ "dnd", AST_PRESENCE_DND},
 };
 
-static struct ast_manager_event_blob *presence_state_to_ami(struct stasis_message *msg);
+/*! \brief Flag for the queue */
+static ast_cond_t change_pending;
 
-STASIS_MESSAGE_TYPE_DEFN(ast_presence_state_message_type,
-	.to_ami = presence_state_to_ami,
-);
-struct stasis_topic *presence_state_topic_all;
-struct stasis_cache *presence_state_cache;
-struct stasis_caching_topic *presence_state_topic_cached;
+struct state_change {
+	AST_LIST_ENTRY(state_change) list;
+	char provider[1];
+};
 
 /*! \brief  A presence state provider */
 struct presence_state_provider {
@@ -101,6 +71,13 @@ struct presence_state_provider {
 /*! \brief A list of providers */
 static AST_RWLIST_HEAD_STATIC(presence_state_providers, presence_state_provider);
 
+/*! \brief The state change queue. State changes are queued
+	for processing by a separate thread */
+static AST_LIST_HEAD_STATIC(state_changes, state_change);
+
+/*! \brief The presence state change notification thread */
+static pthread_t change_thread = AST_PTHREADT_NULL;
+
 const char *ast_presence_state2str(enum ast_presence_state state)
 {
 	int i;
@@ -126,20 +103,25 @@ enum ast_presence_state ast_presence_state_val(const char *val)
 static enum ast_presence_state presence_state_cached(const char *presence_provider, char **subtype, char **message)
 {
 	enum ast_presence_state res = AST_PRESENCE_INVALID;
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_presence_state_message *presence_state;
+	struct ast_event *event;
+	const char *_subtype;
+	const char *_message;
 
-	msg = stasis_cache_get(ast_presence_state_cache(), ast_presence_state_message_type(), presence_provider);
+	event = ast_event_get_cached(AST_EVENT_PRESENCE_STATE,
+		AST_EVENT_IE_PRESENCE_PROVIDER, AST_EVENT_IE_PLTYPE_STR, presence_provider,
+		AST_EVENT_IE_END);
 
-	if (!msg) {
+	if (!event) {
 		return res;
 	}
 
-	presence_state = stasis_message_data(msg);
-	res = presence_state->state;
+	res = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+	_subtype = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE);
+	_message = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE);
 
-	*subtype = !ast_strlen_zero(presence_state->subtype) ? ast_strdup(presence_state->subtype) : NULL;
-	*message = !ast_strlen_zero(presence_state->message) ? ast_strdup(presence_state->message) : NULL;
+	*subtype = !ast_strlen_zero(_subtype) ? ast_strdup(_subtype) : NULL;
+	*message = !ast_strlen_zero(_message) ? ast_strdup(_message) : NULL;
+	ast_event_destroy(event);
 
 	return res;
 }
@@ -231,55 +213,23 @@ int ast_presence_state_prov_del(const char *label)
 	return res;
 }
 
-static void presence_state_dtor(void *obj)
-{
-	struct ast_presence_state_message *presence_state = obj;
-	ast_string_field_free_memory(presence_state);
-}
-
-static struct ast_presence_state_message *presence_state_alloc(const char *provider,
-		enum ast_presence_state state,
-		const char *subtype,
-		const char *message)
-{
-	RAII_VAR(struct ast_presence_state_message *, presence_state, ao2_alloc(sizeof(*presence_state), presence_state_dtor), ao2_cleanup);
-
-	if (!presence_state || ast_string_field_init(presence_state, 256)) {
-		return NULL;
-	}
-
-	presence_state->state = state;
-	ast_string_field_set(presence_state, provider, provider);
-	ast_string_field_set(presence_state, subtype, S_OR(subtype, ""));
-	ast_string_field_set(presence_state, message, S_OR(message, ""));
-
-	ao2_ref(presence_state, +1);
-	return presence_state;
-}
-
 static void presence_state_event(const char *provider,
 		enum ast_presence_state state,
 		const char *subtype,
 		const char *message)
 {
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_presence_state_message *, presence_state, NULL, ao2_cleanup);
-
-	if (!ast_presence_state_message_type()) {
-		return;
-	}
-
-	presence_state = presence_state_alloc(provider, state, subtype, message);
-	if (!presence_state) {
+	struct ast_event *event;
+
+	if (!(event = ast_event_new(AST_EVENT_PRESENCE_STATE,
+			AST_EVENT_IE_PRESENCE_PROVIDER, AST_EVENT_IE_PLTYPE_STR, provider,
+			AST_EVENT_IE_PRESENCE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+			AST_EVENT_IE_PRESENCE_SUBTYPE, AST_EVENT_IE_PLTYPE_STR, S_OR(subtype, ""),
+			AST_EVENT_IE_PRESENCE_MESSAGE, AST_EVENT_IE_PLTYPE_STR, S_OR(message, ""),
+			AST_EVENT_IE_END))) {
 		return;
 	}
 
-	msg = stasis_message_create(ast_presence_state_message_type(), presence_state);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_presence_state_topic_all(), msg);
+	ast_event_queue_and_cache(event);
 }
 
 static void do_presence_state_change(const char *provider)
@@ -290,7 +240,7 @@ static void do_presence_state_change(const char *provider)
 
 	state = ast_presence_state_helper(provider, &subtype, &message, 0);
 
-	if (state < 0) {
+	if (state == AST_PRESENCE_INVALID) {
 		return;
 	}
 
@@ -304,10 +254,19 @@ int ast_presence_state_changed_literal(enum ast_presence_state state,
 		const char *message,
 		const char *presence_provider)
 {
-	if (state == AST_PRESENCE_NOT_SET) {
+	struct state_change *change;
+
+	if (state != AST_PRESENCE_NOT_SET) {
+		presence_state_event(presence_provider, state, subtype, message);
+	} else if ((change_thread == AST_PTHREADT_NULL) ||
+		!(change = ast_calloc(1, sizeof(*change) + strlen(presence_provider)))) {
 		do_presence_state_change(presence_provider);
 	} else {
-		presence_state_event(presence_provider, state, subtype, message);
+		strcpy(change->provider, presence_provider);
+		AST_LIST_LOCK(&state_changes);
+		AST_LIST_INSERT_TAIL(&state_changes, change, list);
+		ast_cond_signal(&change_pending);
+		AST_LIST_UNLOCK(&state_changes);
 	}
 
 	return 0;
@@ -328,79 +287,39 @@ int ast_presence_state_changed(enum ast_presence_state state,
 	return ast_presence_state_changed_literal(state, subtype, message, buf);
 }
 
-struct stasis_topic *ast_presence_state_topic_all(void)
+/*! \brief Go through the presence state change queue and update changes in the presence state thread */
+static void *do_presence_changes(void *data)
 {
-	return presence_state_topic_all;
-}
-
-struct stasis_cache *ast_presence_state_cache(void)
-{
-	return presence_state_cache;
-}
-
-struct stasis_topic *ast_presence_state_topic_cached(void)
-{
-	return stasis_caching_get_topic(presence_state_topic_cached);
-}
-
-static const char *presence_state_get_id(struct stasis_message *msg)
-{
-	struct ast_presence_state_message *presence_state = stasis_message_data(msg);
-
-	if (stasis_message_type(msg) != ast_presence_state_message_type()) {
-		return NULL;
+	struct state_change *next, *current;
+
+	for (;;) {
+		/* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
+		AST_LIST_LOCK(&state_changes);
+		if (AST_LIST_EMPTY(&state_changes))
+			ast_cond_wait(&change_pending, &state_changes.lock);
+		next = AST_LIST_FIRST(&state_changes);
+		AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
+		AST_LIST_UNLOCK(&state_changes);
+
+		/* Process each state change */
+		while ((current = next)) {
+			next = AST_LIST_NEXT(current, list);
+			do_presence_state_change(current->provider);
+			ast_free(current);
+		}
 	}
 
-	return presence_state->provider;
-}
-
-static void presence_state_engine_cleanup(void)
-{
-	ao2_cleanup(presence_state_topic_all);
-	presence_state_topic_all = NULL;
-	ao2_cleanup(presence_state_cache);
-	presence_state_cache = NULL;
-	presence_state_topic_cached = stasis_caching_unsubscribe_and_join(presence_state_topic_cached);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_presence_state_message_type);
+	return NULL;
 }
 
 int ast_presence_state_engine_init(void)
 {
-	ast_register_cleanup(presence_state_engine_cleanup);
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_presence_state_message_type) != 0) {
-		return -1;
-	}
-
-	presence_state_topic_all = stasis_topic_create("ast_presence_state_topic_all");
-	if (!presence_state_topic_all) {
-		return -1;
-	}
-
-	presence_state_cache = stasis_cache_create(presence_state_get_id);
-	if (!presence_state_cache) {
-		return -1;
-	}
-
-	presence_state_topic_cached = stasis_caching_topic_create(presence_state_topic_all, presence_state_cache);
-	if (!presence_state_topic_cached) {
+	ast_cond_init(&change_pending, NULL);
+	if (ast_pthread_create_background(&change_thread, NULL, do_presence_changes, NULL) < 0) {
+		ast_log(LOG_ERROR, "Unable to start presence state change thread.\n");
 		return -1;
 	}
 
 	return 0;
 }
 
-static struct ast_manager_event_blob *presence_state_to_ami(struct stasis_message *msg)
-{
-	struct ast_presence_state_message *presence_state = stasis_message_data(msg);
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "PresenceStateChange",
-		"Presentity: %s\r\n"
-		"Status: %s\r\n"
-		"Subtype: %s\r\n"
-		"Message: %s\r\n",
-		presence_state->provider,
-		ast_presence_state2str(presence_state->state),
-		presence_state->subtype,
-		presence_state->message);
-}
diff --git a/main/privacy.c b/main/privacy.c
index 44641eb..8863f09 100644
--- a/main/privacy.c
+++ b/main/privacy.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index f029e2b..944c477 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -25,119 +25,11 @@
 
 /*** MODULEINFO
 	<support_level>core</support_level>
-***/
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="RTCPSent">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>Raised when an RTCP packet is sent.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="SSRC">
-					<para>The SSRC identifier for our stream</para>
-				</parameter>
-				<parameter name="PT">
-					<para>The type of packet for this RTCP report.</para>
-					<enumlist>
-						<enum name="200(SR)"/>
-						<enum name="201(RR)"/>
-					</enumlist>
-				</parameter>
-				<parameter name="To">
-					<para>The address the report is sent to.</para>
-				</parameter>
-				<parameter name="ReportCount">
-					<para>The number of reports that were sent.</para>
-					<para>The report count determines the number of ReportX headers in
-					the message. The X for each set of report headers will range from 0 to
-					<literal>ReportCount - 1</literal>.</para>
-				</parameter>
-				<parameter name="SentNTP" required="false">
-					<para>The time the sender generated the report. Only valid when
-					PT is <literal>200(SR)</literal>.</para>
-				</parameter>
-				<parameter name="SentRTP" required="false">
-					<para>The sender's last RTP timestamp. Only valid when PT is
-					<literal>200(SR)</literal>.</para>
-				</parameter>
-				<parameter name="SentPackets" required="false">
-					<para>The number of packets the sender has sent. Only valid when PT
-					is <literal>200(SR)</literal>.</para>
-				</parameter>
-				<parameter name="SentOctets" required="false">
-					<para>The number of bytes the sender has sent. Only valid when PT is
-					<literal>200(SR)</literal>.</para>
-				</parameter>
-				<parameter name="ReportXSourceSSRC">
-					<para>The SSRC for the source of this report block.</para>
-				</parameter>
-				<parameter name="ReportXFractionLost">
-					<para>The fraction of RTP data packets from <literal>ReportXSourceSSRC</literal>
-					lost since the previous SR or RR report was sent.</para>
-				</parameter>
-				<parameter name="ReportXCumulativeLost">
-					<para>The total number of RTP data packets from <literal>ReportXSourceSSRC</literal>
-					lost since the beginning of reception.</para>
-				</parameter>
-				<parameter name="ReportXHighestSequence">
-					<para>The highest sequence number received in an RTP data packet from
-					<literal>ReportXSourceSSRC</literal>.</para>
-				</parameter>
-				<parameter name="ReportXSequenceNumberCycles">
-					<para>The number of sequence number cycles seen for the RTP data
-					received from <literal>ReportXSourceSSRC</literal>.</para>
-				</parameter>
-				<parameter name="ReportXIAJitter">
-					<para>An estimate of the statistical variance of the RTP data packet
-					interarrival time, measured in timestamp units.</para>
-				</parameter>
-				<parameter name="ReportXLSR">
-					<para>The last SR timestamp received from <literal>ReportXSourceSSRC</literal>.
-					If no SR has been received from <literal>ReportXSourceSSRC</literal>,
-					then 0.</para>
-				</parameter>
-				<parameter name="ReportXDLSR">
-					<para>The delay, expressed in units of 1/65536 seconds, between
-					receiving the last SR packet from <literal>ReportXSourceSSRC</literal>
-					and sending this report.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="RTCPReceived">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>Raised when an RTCP packet is received.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="SSRC">
-					<para>The SSRC identifier for the remote system</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='PT'])" />
-				<parameter name="From">
-					<para>The address the report was received from.</para>
-				</parameter>
-				<parameter name="RTT">
-					<para>Calculated Round-Trip Time in seconds</para>
-				</parameter>
-				<parameter name="ReportCount">
-					<para>The number of reports that were received.</para>
-					<para>The report count determines the number of ReportX headers in
-					the message. The X for each set of report headers will range from 0 to
-					<literal>ReportCount - 1</literal>.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentNTP'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentRTP'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentPackets'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentOctets'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[contains(@name, 'ReportX')])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427763 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 
@@ -153,9 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427763 $")
 #include "asterisk/netsock2.h"
 #include "asterisk/_private.h"
 #include "asterisk/framehook.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis_channels.h"
 
 struct ast_srtp_res *res_srtp = NULL;
 struct ast_srtp_policy_res *res_srtp_policy = NULL;
@@ -172,6 +61,8 @@ struct ast_rtp_instance {
 	struct ast_sockaddr local_address;
 	/*! Address that we are sending RTP to */
 	struct ast_sockaddr remote_address;
+	/*! Alternate address that we are receiving RTP from */
+	struct ast_sockaddr alt_remote_address;
 	/*! Instance that we are bridged to if doing remote or local bridging */
 	struct ast_rtp_instance *bridged;
 	/*! Payload and packetization information */
@@ -184,10 +75,10 @@ struct ast_rtp_instance {
 	int keepalive;
 	/*! Glue currently in use */
 	struct ast_rtp_glue *glue;
+	/*! Channel associated with the instance */
+	struct ast_channel *chan;
 	/*! SRTP info associated with the instance */
 	struct ast_srtp *srtp;
-	/*! Channel unique ID */
-	char channel_uniqueid[AST_MAX_UNIQUEID];
 };
 
 /*! List of RTP engines that are currently registered */
@@ -196,18 +87,12 @@ static AST_RWLIST_HEAD_STATIC(engines, ast_rtp_engine);
 /*! List of RTP glues */
 static AST_RWLIST_HEAD_STATIC(glues, ast_rtp_glue);
 
-#define MAX_RTP_MIME_TYPES 128
-
 /*! The following array defines the MIME Media type (and subtype) for each
    of our codecs, or RTP-specific data type. */
 static struct ast_rtp_mime_type {
-	/*! \brief A mapping object between the Asterisk codec and this RTP payload */
 	struct ast_rtp_payload_type payload_type;
-	/*! \brief The media type */
-	char type[16];
-	/*! \brief The format type */
-	char subtype[64];
-	/*! \brief Expected sample rate of the /c subtype */
+	char *type;
+	char *subtype;
 	unsigned int sample_rate;
 } ast_rtp_mime_types[128]; /* This will Likely not need to grow any time soon. */
 static ast_rwlock_t mime_types_lock;
@@ -226,27 +111,6 @@ static int mime_types_len = 0;
 static struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT];
 static ast_rwlock_t static_RTP_PT_lock;
 
-/*! \brief \ref stasis topic for RTP related messages */
-static struct stasis_topic *rtp_topic;
-
-
-/*! \internal \brief Destructor for \c ast_rtp_payload_type */
-static void rtp_payload_type_dtor(void *obj)
-{
-	struct ast_rtp_payload_type *payload = obj;
-
-	ao2_cleanup(payload->format);
-}
-
-struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void)
-{
-	struct ast_rtp_payload_type *payload;
-
-	payload = ao2_alloc(sizeof(*payload), rtp_payload_type_dtor);
-
-	return payload;
-}
-
 int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
 {
 	struct ast_rtp_engine *current_engine;
@@ -430,16 +294,6 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
 	return instance;
 }
 
-const char *ast_rtp_instance_get_channel_id(struct ast_rtp_instance *instance)
-{
-	return instance->channel_uniqueid;
-}
-
-void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid)
-{
-	ast_copy_string(instance->channel_uniqueid, uniqueid, sizeof(instance->channel_uniqueid));
-}
-
 void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data)
 {
 	instance->data = data;
@@ -481,6 +335,20 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance,
 	return 0;
 }
 
+int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance,
+		const struct ast_sockaddr *address)
+{
+	ast_sockaddr_copy(&instance->alt_remote_address, address);
+
+	/* oink */
+
+	if (instance->engine->alt_remote_address_set) {
+		instance->engine->alt_remote_address_set(instance, &instance->alt_remote_address);
+	}
+
+	return 0;
+}
+
 int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance,
 		struct ast_sockaddr *address)
 {
@@ -550,30 +418,34 @@ struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *inst
 	return &instance->codecs;
 }
 
-int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
+static int rtp_payload_type_hash(const void *obj, const int flags)
 {
-	int res;
-
-	codecs->framing = 0;
-	ast_rwlock_init(&codecs->codecs_lock);
-	res = AST_VECTOR_INIT(&codecs->payloads, AST_RTP_MAX_PT);
+	const struct ast_rtp_payload_type *type = obj;
+	const int *payload = obj;
 
-	return res;
+	return (flags & OBJ_KEY) ? *payload : type->payload;
 }
 
-void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
+static int rtp_payload_type_cmp(void *obj, void *arg, int flags)
 {
-	int i;
+	struct ast_rtp_payload_type *type1 = obj, *type2 = arg;
+	const int *payload = arg;
 
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
-		struct ast_rtp_payload_type *type;
+	return (type1->payload == (OBJ_KEY ? *payload : type2->payload)) ? CMP_MATCH | CMP_STOP : 0;
+}
 
-		type = AST_VECTOR_GET(&codecs->payloads, i);
-		ao2_t_cleanup(type, "destroying ast_rtp_codec");
+int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
+{
+	if (!(codecs->payloads = ao2_container_alloc(AST_RTP_MAX_PT, rtp_payload_type_hash, rtp_payload_type_cmp))) {
+		return -1;
 	}
-	AST_VECTOR_FREE(&codecs->payloads);
 
-	ast_rwlock_destroy(&codecs->codecs_lock);
+	return 0;
+}
+
+void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
+{
+	ao2_cleanup(codecs->payloads);
 }
 
 void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
@@ -590,69 +462,113 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp
 	ast_rtp_codecs_payloads_initialize(codecs);
 }
 
-void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
 {
 	int i;
 
-	ast_rwlock_rdlock(&src->codecs_lock);
-	ast_rwlock_wrlock(&dest->codecs_lock);
+	ast_rwlock_rdlock(&static_RTP_PT_lock);
+	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		if (static_RTP_PT[i].rtp_code || static_RTP_PT[i].asterisk_format) {
+			struct ast_rtp_payload_type *type;
+
+			if (!(type = ao2_alloc(sizeof(*type), NULL))) {
+				/* Unfortunately if this occurs the payloads container will not contain all possible default payloads
+				 * but we err on the side of doing what we can in the hopes that the extreme memory conditions which
+				 * caused this to occur will go away.
+				 */
+				continue;
+			}
+
+			type->payload = i;
+			type->asterisk_format = static_RTP_PT[i].asterisk_format;
+			type->rtp_code = static_RTP_PT[i].rtp_code;
+			ast_format_copy(&type->format, &static_RTP_PT[i].format);
 
-	for (i = 0; i < AST_VECTOR_SIZE(&src->payloads); i++) {
-		struct ast_rtp_payload_type *type;
+			ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK);
+
+			if (instance && instance->engine && instance->engine->payload_set) {
+				instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code);
+			}
+
+			ao2_ref(type, -1);
+		}
+	}
+	ast_rwlock_unlock(&static_RTP_PT_lock);
+}
+
+void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	int i;
+	struct ast_rtp_payload_type *type;
+
+	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		struct ast_rtp_payload_type *new_type;
+		int payload_alloced = 0;
 
-		type = AST_VECTOR_GET(&src->payloads, i);
-		if (!type) {
+		if (!(type = ao2_find(src->payloads, &i, OBJ_KEY | OBJ_NOLOCK))) {
 			continue;
 		}
-		if (i < AST_VECTOR_SIZE(&dest->payloads)) {
-			ao2_t_cleanup(AST_VECTOR_GET(&dest->payloads, i), "cleaning up vector element about to be replaced");
+
+		new_type = ao2_find(dest->payloads, &i, OBJ_KEY | OBJ_NOLOCK);
+		if (!new_type) {
+			new_type = ao2_alloc(sizeof(*new_type), NULL);
+			if (!new_type) {
+				ao2_ref(type, -1);
+				continue;
+			}
+			payload_alloced = 1;
+		}
+
+		ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
+
+		*new_type = *type;
+
+		if (payload_alloced) {
+			ao2_link_flags(dest->payloads, new_type, OBJ_NOLOCK);
 		}
-		ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest);
-		ao2_bump(type);
-		AST_VECTOR_INSERT(&dest->payloads, i, type);
+
+		ao2_ref(new_type, -1);
 
 		if (instance && instance->engine && instance->engine->payload_set) {
-			instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code);
+			instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code);
 		}
+
+		ao2_ref(type, -1);
 	}
-	dest->framing = src->framing;
-	ast_rwlock_unlock(&dest->codecs_lock);
-	ast_rwlock_unlock(&src->codecs_lock);
 }
 
 void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
 {
-	struct ast_rtp_payload_type *new_type;
-
-	new_type = ast_rtp_engine_alloc_payload_type();
-	if (!new_type) {
-		return;
-	}
+	struct ast_rtp_payload_type *type;
 
 	ast_rwlock_rdlock(&static_RTP_PT_lock);
+
 	if (payload < 0 || payload >= AST_RTP_MAX_PT) {
 		ast_rwlock_unlock(&static_RTP_PT_lock);
 		return;
 	}
 
-	ast_rwlock_wrlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, payload), "cleaning up replaced payload type");
+	if (!(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
+		if (!(type = ao2_alloc(sizeof(*type), NULL))) {
+			ast_rwlock_unlock(&static_RTP_PT_lock);
+			return;
+		}
+		type->payload = payload;
+		ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK);
 	}
 
-	new_type->asterisk_format = static_RTP_PT[payload].asterisk_format;
-	new_type->rtp_code = static_RTP_PT[payload].rtp_code;
-	new_type->payload = payload;
-	new_type->format = ao2_bump(static_RTP_PT[payload].format);
+	type->asterisk_format = static_RTP_PT[payload].asterisk_format;
+	type->rtp_code = static_RTP_PT[payload].rtp_code;
+	ast_format_copy(&type->format, &static_RTP_PT[payload].format);
 
-	ast_debug(1, "Setting payload %d (%p) based on m type on %p\n", payload, new_type, codecs);
-	AST_VECTOR_INSERT(&codecs->payloads, payload, new_type);
+	ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
 
 	if (instance && instance->engine && instance->engine->payload_set) {
-		instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+		instance->engine->payload_set(instance, payload, type->asterisk_format, &type->format, type->rtp_code);
 	}
 
-	ast_rwlock_unlock(&codecs->codecs_lock);
+	ao2_ref(type, -1);
+
 	ast_rwlock_unlock(&static_RTP_PT_lock);
 }
 
@@ -664,16 +580,13 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
 	unsigned int i;
 	int found = 0;
 
-	ast_rwlock_rdlock(&mime_types_lock);
-	if (pt < 0 || pt >= AST_RTP_MAX_PT) {
-		ast_rwlock_unlock(&mime_types_lock);
+	if (pt < 0 || pt >= AST_RTP_MAX_PT)
 		return -1; /* bogus payload type */
-	}
 
-	ast_rwlock_wrlock(&codecs->codecs_lock);
+	ast_rwlock_rdlock(&mime_types_lock);
 	for (i = 0; i < mime_types_len; ++i) {
 		const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
-		struct ast_rtp_payload_type *new_type;
+		struct ast_rtp_payload_type *type;
 
 		if (strcasecmp(mimesubtype, t->subtype)) {
 			continue;
@@ -693,33 +606,29 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
 
 		found = 1;
 
-		new_type = ast_rtp_engine_alloc_payload_type();
-		if (!new_type) {
-			continue;
+		if (!(type = ao2_find(codecs->payloads, &pt, OBJ_KEY | OBJ_NOLOCK))) {
+			if (!(type = ao2_alloc(sizeof(*type), NULL))) {
+				break;
+			}
+			type->payload = pt;
+			ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK);
 		}
 
-		if (pt < AST_VECTOR_SIZE(&codecs->payloads)) {
-			ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, pt), "cleaning up replaced payload type");
-		}
+		*type = t->payload_type;
+		type->payload = pt;
 
-		new_type->payload = pt;
-		new_type->asterisk_format = t->payload_type.asterisk_format;
-		new_type->rtp_code = t->payload_type.rtp_code;
-		if ((ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) &&
-				t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
-			new_type->format = ao2_bump(ast_format_g726_aal2);
-		} else {
-			new_type->format = ao2_bump(t->payload_type.format);
+		if ((t->payload_type.format.id == AST_FORMAT_G726) && t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+			ast_format_set(&type->format, AST_FORMAT_G726_AAL2, 0);
 		}
-		AST_VECTOR_INSERT(&codecs->payloads, pt, new_type);
 
 		if (instance && instance->engine && instance->engine->payload_set) {
-			instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+			instance->engine->payload_set(instance, pt, type->asterisk_format, &type->format, type->rtp_code);
 		}
 
+		ao2_ref(type, -1);
+
 		break;
 	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
 	ast_rwlock_unlock(&mime_types_lock);
 
 	return (found ? 0 : -2);
@@ -732,209 +641,157 @@ int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struc
 
 void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
 {
-	struct ast_rtp_payload_type *type;
-
 	if (payload < 0 || payload >= AST_RTP_MAX_PT) {
 		return;
 	}
 
 	ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs);
 
-	ast_rwlock_wrlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
-		ao2_cleanup(type);
-		AST_VECTOR_INSERT(&codecs->payloads, payload, NULL);
-	}
+	ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK | OBJ_NODATA | OBJ_UNLINK);
 
 	if (instance && instance->engine && instance->engine->payload_set) {
 		instance->engine->payload_set(instance, payload, 0, NULL, 0);
 	}
-
-	ast_rwlock_unlock(&codecs->codecs_lock);
 }
 
-struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload)
+struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload)
 {
-	struct ast_rtp_payload_type *type = NULL;
+	struct ast_rtp_payload_type result = { .asterisk_format = 0, }, *type;
 
 	if (payload < 0 || payload >= AST_RTP_MAX_PT) {
-		return NULL;
+		return result;
 	}
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
-		ao2_bump(type);
+	if ((type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
+		result = *type;
+		ao2_ref(type, -1);
 	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
 
-	if (!type) {
-		type = ast_rtp_engine_alloc_payload_type();
-		if (!type) {
-			return NULL;
-		}
+	if (!result.rtp_code && !result.asterisk_format) {
 		ast_rwlock_rdlock(&static_RTP_PT_lock);
-		type->asterisk_format = static_RTP_PT[payload].asterisk_format;
-		type->rtp_code = static_RTP_PT[payload].rtp_code;
-		type->payload = payload;
-		type->format = ao2_bump(static_RTP_PT[payload].format);
+		result = static_RTP_PT[payload];
 		ast_rwlock_unlock(&static_RTP_PT_lock);
 	}
 
-	return type;
+	return result;
 }
 
-int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format)
-{
-	struct ast_rtp_payload_type *type;
-
-	if (payload < 0 || payload >= AST_RTP_MAX_PT) {
-		return -1;
-	}
-
-	ast_rwlock_wrlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
-		if (type && type->asterisk_format) {
-			ao2_replace(type->format, format);
-		}
-	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
-
-	return 0;
-}
 
 struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload)
 {
 	struct ast_rtp_payload_type *type;
-	struct ast_format *format = NULL;
+	struct ast_format *format;
 
 	if (payload < 0 || payload >= AST_RTP_MAX_PT) {
 		return NULL;
 	}
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
-		if (type && type->asterisk_format) {
-			format = ao2_bump(type->format);
-		}
+	if (!(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
+		return NULL;
 	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
+
+	format = type->asterisk_format ? &type->format : NULL;
+
+	ao2_ref(type, -1);
 
 	return format;
 }
 
-void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing)
+static int rtp_payload_type_add_ast(void *obj, void *arg, int flags)
 {
-	if (!framing) {
-		return;
+	struct ast_rtp_payload_type *type = obj;
+	struct ast_format_cap *astformats = arg;
+
+	if (type->asterisk_format) {
+		ast_format_cap_add(astformats, &type->format);
 	}
 
-	ast_rwlock_wrlock(&codecs->codecs_lock);
-	codecs->framing = framing;
-	ast_rwlock_unlock(&codecs->codecs_lock);
+	return 0;
 }
 
-unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs)
+static int rtp_payload_type_add_nonast(void *obj, void *arg, int flags)
 {
-	unsigned int framing;
+	struct ast_rtp_payload_type *type = obj;
+	int *nonastformats = arg;
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	framing = codecs->framing;
-	ast_rwlock_unlock(&codecs->codecs_lock);
+	if (!type->asterisk_format) {
+		*nonastformats |= type->rtp_code;
+	}
 
-	return framing;
+	return 0;
 }
 
 void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
 {
-	int i;
-
-	ast_format_cap_remove_by_type(astformats, AST_MEDIA_TYPE_UNKNOWN);
+	ast_format_cap_remove_all(astformats);
 	*nonastformats = 0;
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
-		struct ast_rtp_payload_type *type;
+	ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_ast, astformats);
+	ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_nonast, nonastformats);
+}
 
-		type = AST_VECTOR_GET(&codecs->payloads, i);
-		if (!type) {
-			continue;
-		}
+static int rtp_payload_type_find_format(void *obj, void *arg, int flags)
+{
+	struct ast_rtp_payload_type *type = obj;
+	struct ast_format *format = arg;
 
-		if (type->asterisk_format) {
-			ast_format_cap_append(astformats, type->format, 0);
-		} else {
-			*nonastformats |= type->rtp_code;
-		}
-	}
+	return (type->asterisk_format && (ast_format_cmp(&type->format, format) != AST_FORMAT_CMP_NOT_EQUAL)) ? CMP_MATCH | CMP_STOP : 0;
+}
 
-	if (codecs->framing) {
-		ast_format_cap_set_framing(astformats, codecs->framing);
-	}
+static int rtp_payload_type_find_nonast_format(void *obj, void *arg, int flags)
+{
+	struct ast_rtp_payload_type *type = obj;
+	int *rtp_code = arg;
 
-	ast_rwlock_unlock(&codecs->codecs_lock);
+	return ((!type->asterisk_format && (type->rtp_code == *rtp_code)) ? CMP_MATCH | CMP_STOP : 0);
 }
 
 int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
 {
 	struct ast_rtp_payload_type *type;
-	int i;
-	int payload = -1;
-
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
-		type = AST_VECTOR_GET(&codecs->payloads, i);
-		if (!type) {
-			continue;
-		}
+	int i, res = -1;
 
-		if ((asterisk_format && format && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL)
-			|| (!asterisk_format && type->rtp_code == code)) {
-			payload = i;
-			break;
-		}
+	if (asterisk_format && format && (type = ao2_callback(codecs->payloads, OBJ_NOLOCK, rtp_payload_type_find_format, (void*)format))) {
+		res = type->payload;
+		ao2_ref(type, -1);
+		return res;
+	} else if (!asterisk_format && (type = ao2_callback(codecs->payloads, OBJ_NOLOCK, rtp_payload_type_find_nonast_format, (void*)&code))) {
+		res = type->payload;
+		ao2_ref(type, -1);
+		return res;
 	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
 
-	if (payload < 0) {
-		ast_rwlock_rdlock(&static_RTP_PT_lock);
-		for (i = 0; i < AST_RTP_MAX_PT; i++) {
-			if (static_RTP_PT[i].asterisk_format && asterisk_format && format &&
-				(ast_format_cmp(format, static_RTP_PT[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
-				payload = i;
-				break;
-			} else if (!static_RTP_PT[i].asterisk_format && !asterisk_format &&
-				(static_RTP_PT[i].rtp_code == code)) {
-				payload = i;
-				break;
-			}
+	ast_rwlock_rdlock(&static_RTP_PT_lock);
+	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		if (static_RTP_PT[i].asterisk_format && asterisk_format && format &&
+			(ast_format_cmp(format, &static_RTP_PT[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+			res = i;
+			break;
+		} else if (!static_RTP_PT[i].asterisk_format && !asterisk_format &&
+			(static_RTP_PT[i].rtp_code == code)) {
+			res = i;
+			break;
 		}
-		ast_rwlock_unlock(&static_RTP_PT_lock);
 	}
+	ast_rwlock_unlock(&static_RTP_PT_lock);
 
-	return payload;
+	return res;
 }
-
 int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code)
 {
 	struct ast_rtp_payload_type *type;
 	int res = -1;
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (code < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, code);
-		if (type) {
-			res = type->payload;
-		}
+	/* Search the payload type in the codecs passed */
+	if ((type = ao2_find(codecs->payloads, &code, OBJ_NOLOCK | OBJ_KEY)))
+	{
+		res = type->payload;
+		ao2_ref(type, -1);
+		return res;
 	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
 
 	return res;
 }
-
 const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options)
 {
 	int i;
@@ -943,9 +800,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
 	ast_rwlock_rdlock(&mime_types_lock);
 	for (i = 0; i < mime_types_len; i++) {
 		if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format &&
-			(ast_format_cmp(format, ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
-			if ((ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) &&
-					(options & AST_RTP_OPT_G726_NONSTANDARD)) {
+			(ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+			if ((format->id == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
 				res = "G726-32";
 				break;
 			} else {
@@ -972,7 +828,7 @@ unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format
 	ast_rwlock_rdlock(&mime_types_lock);
 	for (i = 0; i < mime_types_len; ++i) {
 		if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format &&
-			(ast_format_cmp(format, ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+			(ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
 			res = ast_rtp_mime_types[i].sample_rate;
 			break;
 		} else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format &&
@@ -996,15 +852,15 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *
 
 
 	if (asterisk_format) {
-		int x;
-		struct ast_format *tmp_fmt;
-		for (x = 0; x < ast_format_cap_count(ast_format_capability); x++) {
-			tmp_fmt = ast_format_cap_get_format(ast_format_capability, x);
-			name = ast_rtp_lookup_mime_subtype2(asterisk_format, tmp_fmt, 0, options);
-			ao2_ref(tmp_fmt, -1);
+		struct ast_format tmp_fmt;
+		ast_format_cap_iter_start(ast_format_capability);
+		while (!ast_format_cap_iter_next(ast_format_capability, &tmp_fmt)) {
+			name = ast_rtp_lookup_mime_subtype2(asterisk_format, &tmp_fmt, 0, options);
 			ast_str_append(&buf, 0, "%s|", name);
 			found = 1;
 		}
+		ast_format_cap_iter_end(ast_format_capability);
+
 	} else {
 		int x;
 		ast_str_append(&buf, 0, "0x%x (", (unsigned int) rtp_capability);
@@ -1022,6 +878,15 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *
 	return ast_str_buffer(buf);
 }
 
+void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs)
+{
+	codecs->pref = *prefs;
+
+	if (instance && instance->engine->packetization_set) {
+		instance->engine->packetization_set(instance, &instance->codecs.pref);
+	}
+}
+
 int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
 {
 	return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1;
@@ -1094,6 +959,505 @@ struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type)
 	return glue;
 }
 
+static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
+{
+	enum ast_bridge_result res = AST_BRIDGE_FAILED;
+	struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
+	struct ast_frame *fr = NULL;
+	struct timeval start;
+
+	/* Start locally bridging both instances */
+	if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) {
+		ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", ast_channel_name(c0), ast_channel_name(c1));
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+	if (instance1->engine->local_bridge && instance1->engine->local_bridge(instance1, instance0)) {
+		ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", ast_channel_name(c1), ast_channel_name(c0));
+		if (instance0->engine->local_bridge) {
+			instance0->engine->local_bridge(instance0, NULL);
+		}
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
+
+	instance0->bridged = instance1;
+	instance1->bridged = instance0;
+
+	ast_poll_channel_add(c0, c1);
+
+	/* Hop into a loop waiting for a frame from either channel */
+	cs[0] = c0;
+	cs[1] = c1;
+	cs[2] = NULL;
+	start = ast_tvnow();
+	for (;;) {
+		int ms;
+		/* If the underlying formats have changed force this bridge to break */
+		if ((ast_format_cmp(ast_channel_rawreadformat(c0), ast_channel_rawwriteformat(c1)) == AST_FORMAT_CMP_NOT_EQUAL) ||
+			(ast_format_cmp(ast_channel_rawreadformat(c1), ast_channel_rawwriteformat(c0)) == AST_FORMAT_CMP_NOT_EQUAL)) {
+			ast_debug(1, "rtp-engine-local-bridge: Oooh, formats changed, backing out\n");
+			res = AST_BRIDGE_FAILED_NOWARN;
+			break;
+		}
+		/* Check if anything changed */
+		if ((ast_channel_tech_pvt(c0) != pvt0) ||
+		    (ast_channel_tech_pvt(c1) != pvt1) ||
+		    (ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1)) ||
+		    (ast_channel_monitor(c0) || ast_channel_audiohooks(c0) || ast_channel_monitor(c1) || ast_channel_audiohooks(c1)) ||
+		    (!ast_framehook_list_is_empty(ast_channel_framehooks(c0)) || !ast_framehook_list_is_empty(ast_channel_framehooks(c1)))) {
+			ast_debug(1, "rtp-engine-local-bridge: Oooh, something is weird, backing out\n");
+			/* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */
+			if ((ast_channel_masq(c0) || ast_channel_masqr(c0)) && (fr = ast_read(c0))) {
+				ast_frfree(fr);
+			}
+			if ((ast_channel_masq(c1) || ast_channel_masqr(c1)) && (fr = ast_read(c1))) {
+				ast_frfree(fr);
+			}
+			res = AST_BRIDGE_RETRY;
+			break;
+		}
+		/* Wait on a channel to feed us a frame */
+		ms = ast_remaining_ms(start, timeoutms);
+		if (!(who = ast_waitfor_n(cs, 2, &ms))) {
+			if (!ms) {
+				res = AST_BRIDGE_RETRY;
+				break;
+			}
+			ast_debug(2, "rtp-engine-local-bridge: Ooh, empty read...\n");
+			if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
+				break;
+			}
+			continue;
+		}
+		/* Read in frame from channel */
+		fr = ast_read(who);
+		other = (who == c0) ? c1 : c0;
+		/* Depending on the frame we may need to break out of our bridge */
+		if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
+			    ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) |
+			    ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)))) {
+			/* Record received frame and who */
+			*fo = fr;
+			*rc = who;
+			ast_debug(1, "rtp-engine-local-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup");
+			res = AST_BRIDGE_COMPLETE;
+			break;
+		} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
+			if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
+			    (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
+			    (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
+			    (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
+			    (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
+				/* If we are going on hold, then break callback mode and P2P bridging */
+				if (fr->subclass.integer == AST_CONTROL_HOLD) {
+					if (instance0->engine->local_bridge) {
+						instance0->engine->local_bridge(instance0, NULL);
+					}
+					if (instance1->engine->local_bridge) {
+						instance1->engine->local_bridge(instance1, NULL);
+					}
+					instance0->bridged = NULL;
+					instance1->bridged = NULL;
+				} else if (fr->subclass.integer == AST_CONTROL_UNHOLD) {
+					if (instance0->engine->local_bridge) {
+						instance0->engine->local_bridge(instance0, instance1);
+					}
+					if (instance1->engine->local_bridge) {
+						instance1->engine->local_bridge(instance1, instance0);
+					}
+					instance0->bridged = instance1;
+					instance1->bridged = instance0;
+				}
+				/* Since UPDATE_BRIDGE_PEER is only used by the bridging code, don't forward it */
+				if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+				if (ast_channel_connected_line_sub(who, other, fr, 1) &&
+					ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+				if (ast_channel_redirecting_sub(who, other, fr, 1) &&
+					ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+				ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen);
+				ast_frfree(fr);
+			} else {
+				*fo = fr;
+				*rc = who;
+				ast_debug(1, "rtp-engine-local-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, ast_channel_name(who));
+				res = AST_BRIDGE_COMPLETE;
+				break;
+			}
+		} else {
+			if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
+			    (fr->frametype == AST_FRAME_DTMF_END) ||
+			    (fr->frametype == AST_FRAME_VOICE) ||
+			    (fr->frametype == AST_FRAME_VIDEO) ||
+			    (fr->frametype == AST_FRAME_IMAGE) ||
+			    (fr->frametype == AST_FRAME_HTML) ||
+			    (fr->frametype == AST_FRAME_MODEM) ||
+			    (fr->frametype == AST_FRAME_TEXT)) {
+				ast_write(other, fr);
+			}
+
+			ast_frfree(fr);
+		}
+		/* Swap priority */
+		cs[2] = cs[0];
+		cs[0] = cs[1];
+		cs[1] = cs[2];
+	}
+
+	/* Stop locally bridging both instances */
+	if (instance0->engine->local_bridge) {
+		instance0->engine->local_bridge(instance0, NULL);
+	}
+	if (instance1->engine->local_bridge) {
+		instance1->engine->local_bridge(instance1, NULL);
+	}
+
+	instance0->bridged = NULL;
+	instance1->bridged = NULL;
+
+	ast_poll_channel_del(c0, c1);
+
+	return res;
+}
+
+static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0,
+	struct ast_channel *c1,
+	struct ast_rtp_instance *instance0,
+	struct ast_rtp_instance *instance1,
+	struct ast_rtp_instance *vinstance0,
+	struct ast_rtp_instance *vinstance1,
+	struct ast_rtp_instance *tinstance0,
+	struct ast_rtp_instance *tinstance1,
+	struct ast_rtp_glue *glue0,
+	struct ast_rtp_glue *glue1,
+	struct ast_format_cap *cap0,
+	struct ast_format_cap *cap1,
+	int timeoutms,
+	int flags,
+	struct ast_frame **fo,
+	struct ast_channel **rc,
+	void *pvt0,
+	void *pvt1)
+{
+	enum ast_bridge_result res = AST_BRIDGE_FAILED;
+	struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
+	struct ast_format_cap *oldcap0 = ast_format_cap_dup(cap0);
+	struct ast_format_cap *oldcap1 = ast_format_cap_dup(cap1);
+	struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}};
+	struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}};
+	struct ast_frame *fr = NULL;
+	struct timeval start;
+
+	if (!oldcap0 || !oldcap1) {
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		goto remote_bridge_cleanup;
+	}
+	/* Test the first channel */
+	if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0))) {
+		ast_rtp_instance_get_remote_address(instance1, &ac1);
+		if (vinstance1) {
+			ast_rtp_instance_get_remote_address(vinstance1, &vac1);
+		}
+		if (tinstance1) {
+			ast_rtp_instance_get_remote_address(tinstance1, &tac1);
+		}
+	} else {
+		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+	}
+
+	/* Test the second channel */
+	if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0))) {
+		ast_rtp_instance_get_remote_address(instance0, &ac0);
+		if (vinstance0) {
+			ast_rtp_instance_get_remote_address(instance0, &vac0);
+		}
+		if (tinstance0) {
+			ast_rtp_instance_get_remote_address(instance0, &tac0);
+		}
+	} else {
+		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c1), ast_channel_name(c0));
+	}
+
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
+
+	instance0->bridged = instance1;
+	instance1->bridged = instance0;
+
+	ast_poll_channel_add(c0, c1);
+
+	/* Go into a loop handling any stray frames that may come in */
+	cs[0] = c0;
+	cs[1] = c1;
+	cs[2] = NULL;
+	start = ast_tvnow();
+	for (;;) {
+		int ms;
+		/* Check if anything changed */
+		if ((ast_channel_tech_pvt(c0) != pvt0) ||
+		    (ast_channel_tech_pvt(c1) != pvt1) ||
+		    (ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1)) ||
+		    (ast_channel_monitor(c0) || ast_channel_audiohooks(c0) || ast_channel_monitor(c1) || ast_channel_audiohooks(c1)) ||
+		    (!ast_framehook_list_is_empty(ast_channel_framehooks(c0)) || !ast_framehook_list_is_empty(ast_channel_framehooks(c1)))) {
+			ast_debug(1, "Oooh, something is weird, backing out\n");
+			res = AST_BRIDGE_RETRY;
+			break;
+		}
+
+		/* Check if they have changed their address */
+		ast_rtp_instance_get_remote_address(instance1, &t1);
+		if (vinstance1) {
+			ast_rtp_instance_get_remote_address(vinstance1, &vt1);
+		}
+		if (tinstance1) {
+			ast_rtp_instance_get_remote_address(tinstance1, &tt1);
+		}
+		ast_channel_lock(c1);
+		if (glue1->get_codec && ast_channel_tech_pvt(c1)) {
+			ast_format_cap_remove_all(cap1);
+			glue1->get_codec(c1, cap1);
+		}
+		ast_channel_unlock(c1);
+
+		ast_rtp_instance_get_remote_address(instance0, &t0);
+		if (vinstance0) {
+			ast_rtp_instance_get_remote_address(vinstance0, &vt0);
+		}
+		if (tinstance0) {
+			ast_rtp_instance_get_remote_address(tinstance0, &tt0);
+		}
+		ast_channel_lock(c0);
+		if (glue0->get_codec && ast_channel_tech_pvt(c0)) {
+			ast_format_cap_remove_all(cap0);
+			glue0->get_codec(c0, cap0);
+		}
+		ast_channel_unlock(c0);
+
+		if ((ast_sockaddr_cmp(&t1, &ac1)) ||
+		    (vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) ||
+		    (tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) ||
+		    (!ast_format_cap_identical(cap1, oldcap1))) {
+			char tmp_buf[512] = { 0, };
+			ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&t1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
+			ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&vt1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
+			ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&tt1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
+			ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&ac1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
+			ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&vac1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
+			ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
+				  ast_channel_name(c1), ast_sockaddr_stringify(&tac1),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
+			if (glue0->update_peer(c0,
+					       ast_sockaddr_isnull(&t1)  ? NULL : instance1,
+					       ast_sockaddr_isnull(&vt1) ? NULL : vinstance1,
+					       ast_sockaddr_isnull(&tt1) ? NULL : tinstance1,
+					       cap1, 0)) {
+				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+			}
+			ast_sockaddr_copy(&ac1, &t1);
+			ast_sockaddr_copy(&vac1, &vt1);
+			ast_sockaddr_copy(&tac1, &tt1);
+			ast_format_cap_copy(oldcap1, cap1);
+		}
+		if ((ast_sockaddr_cmp(&t0, &ac0)) ||
+		    (vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) ||
+		    (tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) ||
+		    (!ast_format_cap_identical(cap0, oldcap0))) {
+			char tmp_buf[512] = { 0, };
+			ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
+				  ast_channel_name(c0), ast_sockaddr_stringify(&t0),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap0));
+			ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
+				  ast_channel_name(c0), ast_sockaddr_stringify(&ac0),
+				  ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap0));
+			if (glue1->update_peer(c1, t0.len ? instance0 : NULL,
+						vt0.len ? vinstance0 : NULL,
+						tt0.len ? tinstance0 : NULL,
+						cap0, 0)) {
+				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", ast_channel_name(c1), ast_channel_name(c0));
+			}
+			ast_sockaddr_copy(&ac0, &t0);
+			ast_sockaddr_copy(&vac0, &vt0);
+			ast_sockaddr_copy(&tac0, &tt0);
+			ast_format_cap_copy(oldcap0, cap0);
+		}
+
+		ms = ast_remaining_ms(start, timeoutms);
+		/* Wait for frame to come in on the channels */
+		if (!(who = ast_waitfor_n(cs, 2, &ms))) {
+			if (!ms) {
+				res = AST_BRIDGE_RETRY;
+				break;
+			}
+			ast_debug(1, "Ooh, empty read...\n");
+			if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
+				break;
+			}
+			continue;
+		}
+		fr = ast_read(who);
+		other = (who == c0) ? c1 : c0;
+		if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
+			    (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
+			     ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
+			/* Break out of bridge */
+			*fo = fr;
+			*rc = who;
+			ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup");
+			res = AST_BRIDGE_COMPLETE;
+			break;
+		} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
+			if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
+			    (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
+			    (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
+			    (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
+				(fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
+				if (fr->subclass.integer == AST_CONTROL_HOLD) {
+					/* If we someone went on hold we want the other side to reinvite back to us */
+					if (who == c0) {
+						glue1->update_peer(c1, NULL, NULL, NULL, NULL, 0);
+					} else {
+						glue0->update_peer(c0, NULL, NULL, NULL, NULL, 0);
+					}
+				} else if (fr->subclass.integer == AST_CONTROL_UNHOLD ||
+					fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER) {
+					/* If they went off hold they should go back to being direct, or if we have
+					 * been told to force a peer update, go ahead and do it. */
+					if (who == c0) {
+						glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0);
+					} else {
+						glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0);
+					}
+				}
+				/* Update local address information */
+				ast_rtp_instance_get_remote_address(instance0, &t0);
+				ast_sockaddr_copy(&ac0, &t0);
+				ast_rtp_instance_get_remote_address(instance1, &t1);
+				ast_sockaddr_copy(&ac1, &t1);
+				/* Update codec information */
+				ast_channel_lock(c0);
+				if (glue0->get_codec && ast_channel_tech_pvt(c0)) {
+					ast_format_cap_remove_all(cap0);
+					ast_format_cap_remove_all(oldcap0);
+					glue0->get_codec(c0, cap0);
+					ast_format_cap_append(oldcap0, cap0);
+
+				}
+				ast_channel_unlock(c0);
+				ast_channel_lock(c1);
+				if (glue1->get_codec && ast_channel_tech_pvt(c1)) {
+					ast_format_cap_remove_all(cap1);
+					ast_format_cap_remove_all(oldcap1);
+					glue1->get_codec(c1, cap1);
+					ast_format_cap_append(oldcap1, cap1);
+				}
+				ast_channel_unlock(c1);
+				/* Since UPDATE_BRIDGE_PEER is only used by the bridging code, don't forward it */
+				if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+				if (ast_channel_connected_line_sub(who, other, fr, 1) &&
+					ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+				if (ast_channel_redirecting_sub(who, other, fr, 1) &&
+					ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+					ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+				}
+				ast_frfree(fr);
+			} else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+				ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen);
+				ast_frfree(fr);
+			} else {
+				*fo = fr;
+				*rc = who;
+				ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, ast_channel_name(who));
+				res = AST_BRIDGE_COMPLETE;
+				break;
+			}
+		} else {
+			if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
+			    (fr->frametype == AST_FRAME_DTMF_END) ||
+			    (fr->frametype == AST_FRAME_VOICE) ||
+			    (fr->frametype == AST_FRAME_VIDEO) ||
+			    (fr->frametype == AST_FRAME_IMAGE) ||
+			    (fr->frametype == AST_FRAME_HTML) ||
+			    (fr->frametype == AST_FRAME_MODEM) ||
+			    (fr->frametype == AST_FRAME_TEXT)) {
+				ast_write(other, fr);
+			}
+			ast_frfree(fr);
+		}
+		/* Swap priority */
+		cs[2] = cs[0];
+		cs[0] = cs[1];
+		cs[1] = cs[2];
+	}
+
+	if (ast_test_flag(ast_channel_flags(c0), AST_FLAG_ZOMBIE)) {
+		ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", ast_channel_name(c0));
+	} else if (ast_channel_tech_pvt(c0) != pvt0) {
+		ast_debug(1, "Channel c0->'%s' pvt changed, in bridge with c1->'%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+	} else if (glue0 != ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) {
+		ast_debug(1, "Channel c0->'%s' technology changed, in bridge with c1->'%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+	} else if (glue0->update_peer(c0, NULL, NULL, NULL, NULL, 0)) {
+		ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", ast_channel_name(c0));
+	}
+	if (ast_test_flag(ast_channel_flags(c1), AST_FLAG_ZOMBIE)) {
+		ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", ast_channel_name(c1));
+	} else if (ast_channel_tech_pvt(c1) != pvt1) {
+		ast_debug(1, "Channel c1->'%s' pvt changed, in bridge with c0->'%s'\n", ast_channel_name(c1), ast_channel_name(c0));
+	} else if (glue1 != ast_rtp_instance_get_glue(ast_channel_tech(c1)->type)) {
+		ast_debug(1, "Channel c1->'%s' technology changed, in bridge with c0->'%s'\n", ast_channel_name(c1), ast_channel_name(c0));
+	} else if (glue1->update_peer(c1, NULL, NULL, NULL, NULL, 0)) {
+		ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", ast_channel_name(c1));
+	}
+
+	instance0->bridged = NULL;
+	instance1->bridged = NULL;
+
+	ast_poll_channel_del(c0, c1);
+
+remote_bridge_cleanup:
+	ast_format_cap_destroy(oldcap0);
+	ast_format_cap_destroy(oldcap1);
+
+	return res;
+}
+
 /*!
  * \brief Conditionally unref an rtp instance
  */
@@ -1105,14 +1469,185 @@ static void unref_instance_cond(struct ast_rtp_instance **instance)
 	}
 }
 
-struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance)
+enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
-	return instance->bridged;
+	struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
+			*vinstance0 = NULL, *vinstance1 = NULL,
+			*tinstance0 = NULL, *tinstance1 = NULL;
+	struct ast_rtp_glue *glue0, *glue1;
+	struct ast_sockaddr addr1 = { {0, }, }, addr2 = { {0, }, };
+	enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
+	enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
+	enum ast_bridge_result res = AST_BRIDGE_FAILED;
+	enum ast_rtp_dtmf_mode dmode;
+	struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock();
+	int unlock_chans = 1;
+	int read_ptime0, read_ptime1, write_ptime0, write_ptime1;
+
+	if (!cap0 || !cap1) {
+		unlock_chans = 0;
+		goto done;
+	}
+
+	/* Lock both channels so we can look for the glue that binds them together */
+	ast_channel_lock(c0);
+	while (ast_channel_trylock(c1)) {
+		ast_channel_unlock(c0);
+		usleep(1);
+		ast_channel_lock(c0);
+	}
+
+	/* Ensure neither channel got hungup during lock avoidance */
+	if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
+		ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+		goto done;
+	}
+
+	/* Grab glue that binds each channel to something using the RTP engine */
+	if (!(glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) || !(glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) {
+		ast_debug(1, "Can't find native functions for channel '%s'\n", glue0 ? ast_channel_name(c1) : ast_channel_name(c0));
+		goto done;
+	}
+
+	audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
+	video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
+
+	audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
+	video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
+
+	/* If the channels are of the same technology, they might have limitations on remote bridging */
+	if (ast_channel_tech(c0) == ast_channel_tech(c1)) {
+		if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
+			if (glue0->allow_rtp_remote && !(glue0->allow_rtp_remote(c0, c1))) {
+				/* If the allow_rtp_remote indicates that remote isn't allowed, revert to local bridge */
+				audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
+			}
+		}
+		if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
+			if (glue0->allow_vrtp_remote && !(glue0->allow_vrtp_remote(c0, c1))) {
+				/* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */
+				video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
+			}
+		}
+	}
+
+	/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
+	if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
+		audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
+	}
+	if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
+		audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
+	}
+
+	/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
+	if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+
+
+	/* If address families differ, force a local bridge */
+	ast_rtp_instance_get_remote_address(instance0, &addr1);
+	ast_rtp_instance_get_remote_address(instance1, &addr2);
+
+	if (addr1.ss.ss_family != addr2.ss.ss_family ||
+	   (ast_sockaddr_is_ipv4_mapped(&addr1) != ast_sockaddr_is_ipv4_mapped(&addr2))) {
+		audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL;
+		audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
+	}
+
+	/* If we need to get DTMF see if we can do it outside of the RTP stream itself */
+	dmode = ast_rtp_instance_dtmf_mode_get(instance0);
+	if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && dmode) {
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+	dmode = ast_rtp_instance_dtmf_mode_get(instance1);
+	if ((flags & AST_BRIDGE_DTMF_CHANNEL_1) && dmode) {
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+
+	/* If we have gotten to a local bridge make sure that both sides have the same local bridge callback and that they are DTMF compatible */
+	if ((audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) && ((instance0->engine->local_bridge != instance1->engine->local_bridge) || (instance0->engine->dtmf_compatible && !instance0->engine->dtmf_compatible(c0, instance0, c1, instance1)))) {
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+
+	/* Make sure that codecs match */
+	if (glue0->get_codec){
+		glue0->get_codec(c0, cap0);
+	}
+	if (glue1->get_codec) {
+		glue1->get_codec(c1, cap1);
+	}
+	if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) {
+		char tmp0[256] = { 0, };
+		char tmp1[256] = { 0, };
+		ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
+			ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0),
+			ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1));
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+
+	read_ptime0 = (ast_codec_pref_getsize(&instance0->codecs.pref, ast_channel_rawreadformat(c0))).cur_ms;
+	read_ptime1 = (ast_codec_pref_getsize(&instance1->codecs.pref, ast_channel_rawreadformat(c1))).cur_ms;
+	write_ptime0 = (ast_codec_pref_getsize(&instance0->codecs.pref, ast_channel_rawwriteformat(c0))).cur_ms;
+	write_ptime1 = (ast_codec_pref_getsize(&instance1->codecs.pref, ast_channel_rawwriteformat(c1))).cur_ms;
+
+	if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
+		ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
+				read_ptime0, write_ptime1, read_ptime1, write_ptime0);
+		res = AST_BRIDGE_FAILED_NOWARN;
+		goto done;
+	}
+
+	instance0->glue = glue0;
+	instance1->glue = glue1;
+	instance0->chan = c0;
+	instance1->chan = c1;
+
+	/* Depending on the end result for bridging either do a local bridge or remote bridge */
+	if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) {
+		ast_verb(3, "Locally bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
+		res = local_bridge_loop(c0, c1, instance0, instance1, timeoutms, flags, fo, rc, ast_channel_tech_pvt(c0), ast_channel_tech_pvt(c1));
+	} else {
+		ast_verb(3, "Remotely bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
+		res = remote_bridge_loop(c0, c1, instance0, instance1, vinstance0, vinstance1,
+				tinstance0, tinstance1, glue0, glue1, cap0, cap1, timeoutms, flags,
+				fo, rc, ast_channel_tech_pvt(c0), ast_channel_tech_pvt(c1));
+	}
+
+	instance0->glue = NULL;
+	instance1->glue = NULL;
+	instance0->chan = NULL;
+	instance1->chan = NULL;
+
+	unlock_chans = 0;
+
+done:
+	if (unlock_chans) {
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+	}
+	ast_format_cap_destroy(cap1);
+	ast_format_cap_destroy(cap0);
+
+	unref_instance_cond(&instance0);
+	unref_instance_cond(&instance1);
+	unref_instance_cond(&vinstance0);
+	unref_instance_cond(&vinstance1);
+	unref_instance_cond(&tinstance0);
+	unref_instance_cond(&tinstance1);
+
+	return res;
 }
 
-void ast_rtp_instance_set_bridged(struct ast_rtp_instance *instance, struct ast_rtp_instance *bridged)
+struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance)
 {
-	instance->bridged = bridged;
+	return instance->bridged;
 }
 
 void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, struct ast_channel *c_src)
@@ -1123,8 +1658,8 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, st
 	struct ast_rtp_glue *glue_dst, *glue_src;
 	enum ast_rtp_glue_result audio_glue_dst_res = AST_RTP_GLUE_RESULT_FORBID, video_glue_dst_res = AST_RTP_GLUE_RESULT_FORBID;
 	enum ast_rtp_glue_result audio_glue_src_res = AST_RTP_GLUE_RESULT_FORBID, video_glue_src_res = AST_RTP_GLUE_RESULT_FORBID;
-	struct ast_format_cap *cap_dst = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	struct ast_format_cap *cap_src = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap_dst = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *cap_src = ast_format_cap_alloc_nolock();
 
 	/* Lock both channels so we can look for the glue that binds them together */
 	ast_channel_lock_both(c_dst, c_src);
@@ -1165,7 +1700,7 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, st
 	}
 
 	/* Make sure we have matching codecs */
-	if (!ast_format_cap_iscompatible(cap_dst, cap_src)) {
+	if (!ast_format_cap_has_joint(cap_dst, cap_src)) {
 		goto done;
 	}
 
@@ -1190,8 +1725,8 @@ done:
 	ast_channel_unlock(c_dst);
 	ast_channel_unlock(c_src);
 
-	ao2_cleanup(cap_dst);
-	ao2_cleanup(cap_src);
+	ast_format_cap_destroy(cap_dst);
+	ast_format_cap_destroy(cap_src);
 
 	unref_instance_cond(&instance_dst);
 	unref_instance_cond(&instance_src);
@@ -1209,18 +1744,28 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
 	struct ast_rtp_glue *glue0, *glue1;
 	enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
 	enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
-	struct ast_format_cap *cap0 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	struct ast_format_cap *cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock();
+	struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock();
+	int res = 0;
 
 	/* If there is no second channel just immediately bail out, we are of no use in that scenario */
-	if (!c1 || !cap1 || !cap0) {
-		ao2_cleanup(cap0);
-		ao2_cleanup(cap1);
+	if (!c1) {
+		ast_format_cap_destroy(cap0);
+		ast_format_cap_destroy(cap1);
 		return -1;
 	}
 
 	/* Lock both channels so we can look for the glue that binds them together */
-	ast_channel_lock_both(c0, c1);
+	ast_channel_lock(c0);
+	while (ast_channel_trylock(c1)) {
+		ast_channel_unlock(c0);
+		usleep(1);
+		ast_channel_lock(c0);
+	}
+
+	if (!cap1 || !cap0) {
+		goto done;
+	}
 
 	/* Grab glue that binds each channel to something using the RTP engine */
 	if (!(glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) || !(glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) {
@@ -1254,7 +1799,7 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
 	}
 
 	/* Make sure we have matching codecs */
-	if (!ast_format_cap_iscompatible(cap0, cap1)) {
+	if (!ast_format_cap_has_joint(cap0, cap1)) {
 		goto done;
 	}
 
@@ -1263,12 +1808,14 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
 		ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", ast_channel_name(c0), c1 ? ast_channel_name(c1) : "<unspecified>");
 	}
 
+	res = 0;
+
 done:
 	ast_channel_unlock(c0);
 	ast_channel_unlock(c1);
 
-	ao2_cleanup(cap0);
-	ao2_cleanup(cap1);
+	ast_format_cap_destroy(cap0);
+	ast_format_cap_destroy(cap1);
 
 	unref_instance_cond(&instance0);
 	unref_instance_cond(&instance1);
@@ -1277,9 +1824,11 @@ done:
 	unref_instance_cond(&tinstance0);
 	unref_instance_cond(&tinstance1);
 
-	ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", ast_channel_name(c0), c1 ? ast_channel_name(c1) : "<unspecified>");
+	if (!res) {
+		ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", ast_channel_name(c0), c1 ? ast_channel_name(c1) : "<unspecified>");
+	}
 
-	return 0;
+	return res;
 }
 
 int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
@@ -1339,64 +1888,36 @@ char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_r
 
 void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance)
 {
-	char quality_buf[AST_MAX_USER_FIELD];
-	char *quality;
-	struct ast_channel *bridge = ast_channel_bridge_peer(chan);
+	char quality_buf[AST_MAX_USER_FIELD], *quality;
+	struct ast_channel *bridge = ast_bridged_channel(chan);
 
-	ast_channel_lock(chan);
-	ast_channel_stage_snapshot(chan);
-	ast_channel_unlock(chan);
-	if (bridge) {
-		ast_channel_lock(bridge);
-		ast_channel_stage_snapshot(bridge);
-		ast_channel_unlock(bridge);
-	}
-
-	quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY,
-		quality_buf, sizeof(quality_buf));
-	if (quality) {
+	if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
 		pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", quality);
 		if (bridge) {
 			pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", quality);
 		}
 	}
 
-	quality = ast_rtp_instance_get_quality(instance,
-		AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf));
-	if (quality) {
+	if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
 		pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", quality);
 		if (bridge) {
 			pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", quality);
 		}
 	}
 
-	quality = ast_rtp_instance_get_quality(instance,
-		AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf));
-	if (quality) {
+	if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
 		pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", quality);
 		if (bridge) {
 			pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", quality);
 		}
 	}
 
-	quality = ast_rtp_instance_get_quality(instance,
-		AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf));
-	if (quality) {
+	if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
 		pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", quality);
 		if (bridge) {
 			pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", quality);
 		}
 	}
-
-	ast_channel_lock(chan);
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
-	if (bridge) {
-		ast_channel_lock(bridge);
-		ast_channel_stage_snapshot_done(bridge);
-		ast_channel_unlock(bridge);
-		ast_channel_unref(bridge);
-	}
 }
 
 int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, struct ast_format *format)
@@ -1453,7 +1974,7 @@ void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struc
 {
 	if (instance->engine->available_formats) {
 		instance->engine->available_formats(instance, to_endpoint, to_asterisk, result);
-		if (ast_format_cap_count(result)) {
+		if (!ast_format_cap_is_empty(result)) {
 			return;
 		}
 	}
@@ -1515,6 +2036,11 @@ struct ast_rtp_glue *ast_rtp_instance_get_active_glue(struct ast_rtp_instance *i
 	return instance->glue;
 }
 
+struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance)
+{
+	return instance->chan;
+}
+
 int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res)
 {
 	if (res_srtp || res_srtp_policy) {
@@ -1643,6 +2169,8 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name,
 
 void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rtp_dtls_cfg *dst_cfg)
 {
+	ast_rtp_dtls_cfg_free(dst_cfg);         /* Prevent a double-call leaking memory via ast_strdup */
+
 	dst_cfg->enabled = src_cfg->enabled;
 	dst_cfg->verify = src_cfg->verify;
 	dst_cfg->rekey = src_cfg->rekey;
@@ -1659,33 +2187,18 @@ void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rt
 void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg)
 {
 	ast_free(dtls_cfg->certfile);
+	dtls_cfg->certfile = NULL;
 	ast_free(dtls_cfg->pvtfile);
+	dtls_cfg->pvtfile = NULL;
 	ast_free(dtls_cfg->cipher);
+	dtls_cfg->cipher = NULL;
 	ast_free(dtls_cfg->cafile);
+	dtls_cfg->cafile = NULL;
 	ast_free(dtls_cfg->capath);
+	dtls_cfg->capath = NULL;
 }
 
-/*! \internal
- * \brief Small helper routine that cleans up entry i in
- * \c static_RTP_PT.
- */
-static void rtp_engine_static_RTP_PT_cleanup(int i)
-{
-	ao2_cleanup(static_RTP_PT[i].format);
-	memset(&static_RTP_PT[i], 0, sizeof(struct ast_rtp_payload_type));
-}
-
-/*! \internal
- * \brief Small helper routine that cleans up entry i in
- * \c ast_rtp_mime_types.
- */
-static void rtp_engine_mime_type_cleanup(int i)
-{
-	ao2_cleanup(ast_rtp_mime_types[i].payload_type.format);
-	memset(&ast_rtp_mime_types[i], 0, sizeof(struct ast_rtp_mime_type));
-}
-
-static void set_next_mime_type(struct ast_format *format, int rtp_code, const char *type, const char *subtype, unsigned int sample_rate)
+static void set_next_mime_type(const struct ast_format *format, int rtp_code, char *type, char *subtype, unsigned int sample_rate)
 {
 	int x = mime_types_len;
 	if (ARRAY_LEN(ast_rtp_mime_types) == mime_types_len) {
@@ -1693,22 +2206,20 @@ static void set_next_mime_type(struct ast_format *format, int rtp_code, const ch
 	}
 
 	ast_rwlock_wrlock(&mime_types_lock);
-	/* Make sure any previous value in ast_rtp_mime_types is cleaned up */
-	memset(&ast_rtp_mime_types[x], 0, sizeof(struct ast_rtp_mime_type));	
 	if (format) {
 		ast_rtp_mime_types[x].payload_type.asterisk_format = 1;
-		ast_rtp_mime_types[x].payload_type.format = ao2_bump(format);
+		ast_format_copy(&ast_rtp_mime_types[x].payload_type.format, format);
 	} else {
 		ast_rtp_mime_types[x].payload_type.rtp_code = rtp_code;
 	}
-	ast_copy_string(ast_rtp_mime_types[x].type, type, sizeof(ast_rtp_mime_types[x].type));
-	ast_copy_string(ast_rtp_mime_types[x].subtype, subtype, sizeof(ast_rtp_mime_types[x].subtype));
+	ast_rtp_mime_types[x].type = type;
+	ast_rtp_mime_types[x].subtype = subtype;
 	ast_rtp_mime_types[x].sample_rate = sample_rate;
 	mime_types_len++;
 	ast_rwlock_unlock(&mime_types_lock);
 }
 
-static void add_static_payload(int map, struct ast_format *format, int rtp_code)
+static void add_static_payload(int map, const struct ast_format *format, int rtp_code)
 {
 	int x;
 	ast_rwlock_wrlock(&static_RTP_PT_lock);
@@ -1723,38 +2234,39 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code)
 	}
 
 	if (map < 0) {
-		ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n",
-			ast_format_get_name(format));
+		ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n" ,ast_getformatname(format));
 		ast_rwlock_unlock(&static_RTP_PT_lock);
 		return;
 	}
 
 	if (format) {
 		static_RTP_PT[map].asterisk_format = 1;
-		static_RTP_PT[map].format = ao2_bump(format);
+		ast_format_copy(&static_RTP_PT[map].format, format);
 	} else {
 		static_RTP_PT[map].rtp_code = rtp_code;
 	}
 	ast_rwlock_unlock(&static_RTP_PT_lock);
 }
 
-int ast_rtp_engine_load_format(struct ast_format *format)
+int ast_rtp_engine_load_format(const struct ast_format *format)
 {
-	char *codec_name = ast_strdupa(ast_format_get_name(format));
-
-	codec_name = ast_str_to_upper(codec_name);
-
-	set_next_mime_type(format,
-		0,
-		ast_codec_media_type2str(ast_format_get_type(format)),
-		codec_name,
-		ast_format_get_sample_rate(format));
-	add_static_payload(-1, format, 0);
+	switch (format->id) {
+	case AST_FORMAT_SILK:
+		set_next_mime_type(format, 0, "audio", "SILK", ast_format_rate(format));
+		add_static_payload(-1, format, 0);
+		break;
+	case AST_FORMAT_CELT:
+		set_next_mime_type(format, 0, "audio", "CELT", ast_format_rate(format));
+		add_static_payload(-1, format, 0);
+		break;
+	default:
+		break;
+	}
 
 	return 0;
 }
 
-int ast_rtp_engine_unload_format(struct ast_format *format)
+int ast_rtp_engine_unload_format(const struct ast_format *format)
 {
 	int x;
 	int y = 0;
@@ -1762,20 +2274,22 @@ int ast_rtp_engine_unload_format(struct ast_format *format)
 	ast_rwlock_wrlock(&static_RTP_PT_lock);
 	/* remove everything pertaining to this format id from the lists */
 	for (x = 0; x < AST_RTP_MAX_PT; x++) {
-		if (ast_format_cmp(static_RTP_PT[x].format, format) == AST_FORMAT_CMP_EQUAL) {
-			rtp_engine_static_RTP_PT_cleanup(x);
+		if (ast_format_cmp(&static_RTP_PT[x].format, format) == AST_FORMAT_CMP_EQUAL) {
+			memset(&static_RTP_PT[x], 0, sizeof(struct ast_rtp_payload_type));
 		}
 	}
 	ast_rwlock_unlock(&static_RTP_PT_lock);
 
+
 	ast_rwlock_wrlock(&mime_types_lock);
 	/* rebuild the list skipping the items matching this id */
 	for (x = 0; x < mime_types_len; x++) {
-		if (ast_format_cmp(ast_rtp_mime_types[x].payload_type.format, format) == AST_FORMAT_CMP_EQUAL) {
-			rtp_engine_mime_type_cleanup(x);
+		if (ast_format_cmp(&ast_rtp_mime_types[x].payload_type.format, format) == AST_FORMAT_CMP_EQUAL) {
 			continue;
 		}
-		ast_rtp_mime_types[y] = ast_rtp_mime_types[x];
+		if (x != y) {
+			ast_rtp_mime_types[y] = ast_rtp_mime_types[x];
+		}
 		y++;
 	}
 	mime_types_len = y;
@@ -1783,386 +2297,92 @@ int ast_rtp_engine_unload_format(struct ast_format *format)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief \ref stasis message payload for RTCP messages
- */
-struct rtcp_message_payload {
-	struct ast_channel_snapshot *snapshot;  /*< The channel snapshot, if available */
-	struct ast_rtp_rtcp_report *report;     /*< The RTCP report */
-	struct ast_json *blob;                  /*< Extra JSON data to publish */
-};
-
-static void rtcp_message_payload_dtor(void *obj)
-{
-	struct rtcp_message_payload *payload = obj;
-
-	ao2_cleanup(payload->report);
-	ao2_cleanup(payload->snapshot);
-	ast_json_unref(payload->blob);
-}
-
-static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *msg)
-{
-	struct rtcp_message_payload *payload = stasis_message_data(msg);
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, packet_string, ast_str_create(512), ast_free);
-	unsigned int ssrc = payload->report->ssrc;
-	unsigned int type = payload->report->type;
-	unsigned int report_count = payload->report->reception_report_count;
-	int i;
-
-	if (!packet_string) {
-		return NULL;
-	}
-
-	if (payload->snapshot) {
-		channel_string = ast_manager_build_channel_state_string(payload->snapshot);
-		if (!channel_string) {
-			return NULL;
-		}
-	}
-
-	if (payload->blob) {
-		/* Optional data */
-		struct ast_json *to = ast_json_object_get(payload->blob, "to");
-		struct ast_json *from = ast_json_object_get(payload->blob, "from");
-		struct ast_json *rtt = ast_json_object_get(payload->blob, "rtt");
-		if (to) {
-			ast_str_append(&packet_string, 0, "To: %s\r\n", ast_json_string_get(to));
-		}
-		if (from) {
-			ast_str_append(&packet_string, 0, "From: %s\r\n", ast_json_string_get(from));
-		}
-		if (rtt) {
-			ast_str_append(&packet_string, 0, "RTT: %4.4f\r\n", ast_json_real_get(rtt));
-		}
-	}
-
-	ast_str_append(&packet_string, 0, "SSRC: 0x%.8x\r\n", ssrc);
-	ast_str_append(&packet_string, 0, "PT: %u(%s)\r\n", type, type== AST_RTP_RTCP_SR ? "SR" : "RR");
-	ast_str_append(&packet_string, 0, "ReportCount: %u\r\n", report_count);
-	if (type == AST_RTP_RTCP_SR) {
-		ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n",
-			(unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec,
-			(unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096);
-		ast_str_append(&packet_string, 0, "SentRTP: %u\r\n",
-				payload->report->sender_information.rtp_timestamp);
-		ast_str_append(&packet_string, 0, "SentPackets: %u\r\n",
-				payload->report->sender_information.packet_count);
-		ast_str_append(&packet_string, 0, "SentOctets: %u\r\n",
-				payload->report->sender_information.octet_count);
-	}
-
-	for (i = 0; i < report_count; i++) {
-		RAII_VAR(struct ast_str *, report_string, NULL, ast_free);
-
-		if (!payload->report->report_block[i]) {
-			break;
-		}
-
-		report_string = ast_str_create(256);
-		if (!report_string) {
-			return NULL;
-		}
-
-		ast_str_append(&report_string, 0, "Report%dSourceSSRC: 0x%.8x\r\n",
-				i, payload->report->report_block[i]->source_ssrc);
-		ast_str_append(&report_string, 0, "Report%dFractionLost: %d\r\n",
-				i, payload->report->report_block[i]->lost_count.fraction);
-		ast_str_append(&report_string, 0, "Report%dCumulativeLost: %u\r\n",
-				i, payload->report->report_block[i]->lost_count.packets);
-		ast_str_append(&report_string, 0, "Report%dHighestSequence: %u\r\n",
-				i, payload->report->report_block[i]->highest_seq_no & 0xffff);
-		ast_str_append(&report_string, 0, "Report%dSequenceNumberCycles: %u\r\n",
-				i, payload->report->report_block[i]->highest_seq_no >> 16);
-		ast_str_append(&report_string, 0, "Report%dIAJitter: %u\r\n",
-				i, payload->report->report_block[i]->ia_jitter);
-		ast_str_append(&report_string, 0, "Report%dLSR: %u\r\n",
-				i, payload->report->report_block[i]->lsr);
-		ast_str_append(&report_string, 0, "Report%dDLSR: %4.4f\r\n",
-				i, ((double)payload->report->report_block[i]->dlsr) / 65536);
-		ast_str_append(&packet_string, 0, "%s", ast_str_buffer(report_string));
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_REPORTING,
-		stasis_message_type(msg) == ast_rtp_rtcp_received_type() ? "RTCPReceived" : "RTCPSent",
-		"%s%s",
-		AS_OR(channel_string, ""),
-		ast_str_buffer(packet_string));
-}
-
-static struct ast_json *rtcp_report_to_json(struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct rtcp_message_payload *payload = stasis_message_data(msg);
-	RAII_VAR(struct ast_json *, json_rtcp_report, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json_rtcp_report_blocks, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json_rtcp_sender_info, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json_channel, NULL, ast_json_unref);
-	int i;
-
-	json_rtcp_report_blocks = ast_json_array_create();
-	if (!json_rtcp_report_blocks) {
-		return NULL;
-	}
-
-	for (i = 0; i < payload->report->reception_report_count && payload->report->report_block[i]; i++) {
-		struct ast_json *json_report_block;
-		char str_lsr[32];
-		snprintf(str_lsr, sizeof(str_lsr), "%u", payload->report->report_block[i]->lsr);
-		json_report_block = ast_json_pack("{s: i, s: i, s: i, s: i, s: i, s: s, s: i}",
-				"source_ssrc", payload->report->report_block[i]->source_ssrc,
-				"fraction_lost", payload->report->report_block[i]->lost_count.fraction,
-				"packets_lost", payload->report->report_block[i]->lost_count.packets,
-				"highest_seq_no", payload->report->report_block[i]->highest_seq_no,
-				"ia_jitter", payload->report->report_block[i]->ia_jitter,
-				"lsr", str_lsr,
-				"dlsr", payload->report->report_block[i]->dlsr);
-		if (!json_report_block) {
-			return NULL;
-		}
-
-		if (ast_json_array_append(json_rtcp_report_blocks, json_report_block)) {
-			return NULL;
-		}
-	}
-
-	if (payload->report->type == AST_RTP_RTCP_SR) {
-		char sec[32];
-		char usec[32];
-		snprintf(sec, sizeof(sec), "%lu", payload->report->sender_information.ntp_timestamp.tv_sec);
-		snprintf(usec, sizeof(usec), "%lu", payload->report->sender_information.ntp_timestamp.tv_usec);
-		json_rtcp_sender_info = ast_json_pack("{s: s, s: s, s: i, s: i, s: i}",
-				"ntp_timestamp_sec", sec,
-				"ntp_timestamp_usec", usec,
-				"rtp_timestamp", payload->report->sender_information.rtp_timestamp,
-				"packets", payload->report->sender_information.packet_count,
-				"octets", payload->report->sender_information.octet_count);
-		if (!json_rtcp_sender_info) {
-			return NULL;
-		}
-	}
-
-	json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: O, s: O}",
-			"ssrc", payload->report->ssrc,
-			"type", payload->report->type,
-			"report_count", payload->report->reception_report_count,
-			"sender_information", json_rtcp_sender_info ? json_rtcp_sender_info : ast_json_null(),
-			"report_blocks", json_rtcp_report_blocks);
-	if (!json_rtcp_report) {
-		return NULL;
-	}
-
-	if (payload->snapshot) {
-		json_channel = ast_channel_snapshot_to_json(payload->snapshot, sanitize);
-		if (!json_channel) {
-			return NULL;
-		}
-	}
-
-	return ast_json_pack("{s: O, s: O, s: O}",
-		"channel", payload->snapshot ? json_channel : ast_json_null(),
-		"rtcp_report", json_rtcp_report,
-		"blob", payload->blob);
-}
-
-static void rtp_rtcp_report_dtor(void *obj)
-{
-	int i;
-	struct ast_rtp_rtcp_report *rtcp_report = obj;
-
-	for (i = 0; i < rtcp_report->reception_report_count; i++) {
-		ast_free(rtcp_report->report_block[i]);
-	}
-}
-
-struct ast_rtp_rtcp_report *ast_rtp_rtcp_report_alloc(unsigned int report_blocks)
-{
-	struct ast_rtp_rtcp_report *rtcp_report;
-
-	/* Size of object is sizeof the report + the number of report_blocks * sizeof pointer */
-	rtcp_report = ao2_alloc((sizeof(*rtcp_report) + report_blocks * sizeof(struct ast_rtp_rtcp_report_block *)),
-		rtp_rtcp_report_dtor);
-
-	return rtcp_report;
-}
-
-void ast_rtp_publish_rtcp_message(struct ast_rtp_instance *rtp,
-		struct stasis_message_type *message_type,
-		struct ast_rtp_rtcp_report *report,
-		struct ast_json *blob)
-{
-	RAII_VAR(struct rtcp_message_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!message_type) {
-		return;
-	}
-
-	payload = ao2_alloc(sizeof(*payload), rtcp_message_payload_dtor);
-	if (!payload || !report) {
-		return;
-	}
-
-	if (!ast_strlen_zero(rtp->channel_uniqueid)) {
-		payload->snapshot = ast_channel_snapshot_get_latest(rtp->channel_uniqueid);
-	}
-	if (blob) {
-		payload->blob = blob;
-		ast_json_ref(blob);
-	}
-	ao2_ref(report, +1);
-	payload->report = report;
-
-	message = stasis_message_create(message_type, payload);
-	if (!message) {
-		return;
-	}
-
-	stasis_publish(ast_rtp_topic(), message);
-}
-
-/*!
- * @{ \brief Define RTCP/RTP message types.
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_rtp_rtcp_sent_type,
-		.to_ami = rtcp_report_to_ami,
-		.to_json = rtcp_report_to_json,);
-STASIS_MESSAGE_TYPE_DEFN(ast_rtp_rtcp_received_type,
-		.to_ami = rtcp_report_to_ami,
-		.to_json = rtcp_report_to_json,);
-/*! @} */
-
-struct stasis_topic *ast_rtp_topic(void)
-{
-	return rtp_topic;
-}
-
-static void rtp_engine_shutdown(void)
-{
-	int x;
-
-	ao2_cleanup(rtp_topic);
-	rtp_topic = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_received_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_sent_type);
-
-	ast_rwlock_wrlock(&static_RTP_PT_lock);
-	for (x = 0; x < AST_RTP_MAX_PT; x++) {
-		if (static_RTP_PT[x].format) {
-			rtp_engine_static_RTP_PT_cleanup(x);
-		}
-	}
-	ast_rwlock_unlock(&static_RTP_PT_lock);
-
-	ast_rwlock_wrlock(&mime_types_lock);
-	for (x = 0; x < mime_types_len; x++) {
-		if (ast_rtp_mime_types[x].payload_type.format) {
-			rtp_engine_mime_type_cleanup(x);
-		}
-	}
-	ast_rwlock_unlock(&mime_types_lock);
-}
-
 int ast_rtp_engine_init()
 {
+	struct ast_format tmpfmt;
+
 	ast_rwlock_init(&mime_types_lock);
 	ast_rwlock_init(&static_RTP_PT_lock);
 
-	rtp_topic = stasis_topic_create("rtp_topic");
-	if (!rtp_topic) {
-		return -1;
-	}
-	STASIS_MESSAGE_TYPE_INIT(ast_rtp_rtcp_sent_type);
-	STASIS_MESSAGE_TYPE_INIT(ast_rtp_rtcp_received_type);
-	ast_register_atexit(rtp_engine_shutdown);
-
 	/* Define all the RTP mime types available */
-	set_next_mime_type(ast_format_g723, 0, "audio", "G723", 8000);
-	set_next_mime_type(ast_format_gsm, 0, "audio", "GSM", 8000);
-	set_next_mime_type(ast_format_ulaw, 0, "audio", "PCMU", 8000);
-	set_next_mime_type(ast_format_ulaw, 0, "audio", "G711U", 8000);
-	set_next_mime_type(ast_format_alaw, 0, "audio", "PCMA", 8000);
-	set_next_mime_type(ast_format_alaw, 0, "audio", "G711A", 8000);
-	set_next_mime_type(ast_format_g726, 0, "audio", "G726-32", 8000);
-	set_next_mime_type(ast_format_adpcm, 0, "audio", "DVI4", 8000);
-	set_next_mime_type(ast_format_slin, 0, "audio", "L16", 8000);
-	set_next_mime_type(ast_format_slin16, 0, "audio", "L16", 16000);
-	set_next_mime_type(ast_format_slin16, 0, "audio", "L16-256", 16000);
-	set_next_mime_type(ast_format_lpc10, 0, "audio", "LPC", 8000);
-	set_next_mime_type(ast_format_g729, 0, "audio", "G729", 8000);
-	set_next_mime_type(ast_format_g729, 0, "audio", "G729A", 8000);
-	set_next_mime_type(ast_format_g729, 0, "audio", "G.729", 8000);
-	set_next_mime_type(ast_format_speex, 0, "audio", "speex", 8000);
-	set_next_mime_type(ast_format_speex16, 0,  "audio", "speex", 16000);
-	set_next_mime_type(ast_format_speex32, 0,  "audio", "speex", 32000);
-	set_next_mime_type(ast_format_ilbc, 0, "audio", "iLBC", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0, "audio", "G723", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0, "audio", "GSM", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "PCMU", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "G711U", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0, "audio", "PCMA", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0, "audio", "G711A", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0, "audio", "G726-32", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0, "audio", "DVI4", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0, "audio", "L16", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0, "audio", "L16", 16000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0, "audio", "L16-256", 16000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), 0, "audio", "LPC", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G729", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G729A", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G.729", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), 0, "audio", "speex", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), 0,  "audio", "speex", 16000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), 0,  "audio", "speex", 32000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0, "audio", "iLBC", 8000);
 	/* this is the sample rate listed in the RTP profile for the G.722 codec, *NOT* the actual sample rate of the media stream */
-	set_next_mime_type(ast_format_g722, 0, "audio", "G722", 8000);
-	set_next_mime_type(ast_format_g726_aal2, 0, "audio", "AAL2-G726-32", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), 0, "audio", "G722", 8000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), 0, "audio", "AAL2-G726-32", 8000);
 	set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 8000);
 	set_next_mime_type(NULL, AST_RTP_CISCO_DTMF, "audio", "cisco-telephone-event", 8000);
 	set_next_mime_type(NULL, AST_RTP_CN, "audio", "CN", 8000);
-	set_next_mime_type(ast_format_jpeg, 0, "video", "JPEG", 90000);
-	set_next_mime_type(ast_format_png, 0, "video", "PNG", 90000);
-	set_next_mime_type(ast_format_h261, 0, "video", "H261", 90000);
-	set_next_mime_type(ast_format_h263, 0, "video", "H263", 90000);
-	set_next_mime_type(ast_format_h263p, 0, "video", "h263-1998", 90000);
-	set_next_mime_type(ast_format_h264, 0, "video", "H264", 90000);
-	set_next_mime_type(ast_format_mp4, 0, "video", "MP4V-ES", 90000);
-	set_next_mime_type(ast_format_t140_red, 0, "text", "RED", 1000);
-	set_next_mime_type(ast_format_t140, 0, "text", "T140", 1000);
-	set_next_mime_type(ast_format_siren7, 0, "audio", "G7221", 16000);
-	set_next_mime_type(ast_format_siren14, 0, "audio", "G7221", 32000);
-	set_next_mime_type(ast_format_g719, 0, "audio", "G719", 48000);
-	/* Opus and VP8 */
-	set_next_mime_type(ast_format_opus, 0,  "audio", "opus", 48000);
-	set_next_mime_type(ast_format_vp8, 0,  "video", "VP8", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), 0, "video", "JPEG", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), 0, "video", "PNG", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), 0, "video", "H261", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0, "video", "H263", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0, "video", "H263-1998", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0, "video", "H264", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), 0, "video", "MP4V-ES", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), 0, "text", "RED", 1000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), 0, "text", "T140", 1000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0, "audio", "G7221", 16000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), 0, "audio", "G7221", 32000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), 0, "audio", "G719", 48000);
 
 	/* Define the static rtp payload mappings */
-	add_static_payload(0, ast_format_ulaw, 0);
+	add_static_payload(0, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0);
 	#ifdef USE_DEPRECATED_G726
-	add_static_payload(2, ast_format_g726, 0);/* Technically this is G.721, but if Cisco can do it, so can we... */
+	add_static_payload(2, ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0);/* Technically this is G.721, but if Cisco can do it, so can we... */
 	#endif
-	add_static_payload(3, ast_format_gsm, 0);
-	add_static_payload(4, ast_format_g723, 0);
-	add_static_payload(5, ast_format_adpcm, 0);/* 8 kHz */
-	add_static_payload(6, ast_format_adpcm, 0); /* 16 kHz */
-	add_static_payload(7, ast_format_lpc10, 0);
-	add_static_payload(8, ast_format_alaw, 0);
-	add_static_payload(9, ast_format_g722, 0);
-	add_static_payload(10, ast_format_slin, 0); /* 2 channels */
-	add_static_payload(11, ast_format_slin, 0); /* 1 channel */
+	add_static_payload(3, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0);
+	add_static_payload(4, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0);
+	add_static_payload(5, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0);/* 8 kHz */
+	add_static_payload(6, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 16 kHz */
+	add_static_payload(7, ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), 0);
+	add_static_payload(8, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0);
+	add_static_payload(9, ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), 0);
+	add_static_payload(10, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0); /* 2 channels */
+	add_static_payload(11, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0); /* 1 channel */
 	add_static_payload(13, NULL, AST_RTP_CN);
-	add_static_payload(16, ast_format_adpcm, 0); /* 11.025 kHz */
-	add_static_payload(17, ast_format_adpcm, 0); /* 22.050 kHz */
-	add_static_payload(18, ast_format_g729, 0);
+	add_static_payload(16, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 11.025 kHz */
+	add_static_payload(17, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 22.050 kHz */
+	add_static_payload(18, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0);
 	add_static_payload(19, NULL, AST_RTP_CN);         /* Also used for CN */
-	add_static_payload(26, ast_format_jpeg, 0);
-	add_static_payload(31, ast_format_h261, 0);
-	add_static_payload(34, ast_format_h263, 0);
-	add_static_payload(97, ast_format_ilbc, 0);
-	add_static_payload(98, ast_format_h263p, 0);
-	add_static_payload(99, ast_format_h264, 0);
+	add_static_payload(26, ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), 0);
+	add_static_payload(31, ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), 0);
+	add_static_payload(34, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0);
+	add_static_payload(97, ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0);
+	add_static_payload(98, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0);
+	add_static_payload(99, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0);
 	add_static_payload(101, NULL, AST_RTP_DTMF);
-	add_static_payload(102, ast_format_siren7, 0);
-	add_static_payload(103, ast_format_h263p, 0);
-	add_static_payload(104, ast_format_mp4, 0);
-	add_static_payload(105, ast_format_t140_red, 0);   /* Real time text chat (with redundancy encoding) */
-	add_static_payload(106, ast_format_t140, 0);     /* Real time text chat */
-	add_static_payload(110, ast_format_speex, 0);
-	add_static_payload(111, ast_format_g726, 0);
-	add_static_payload(112, ast_format_g726_aal2, 0);
-	add_static_payload(115, ast_format_siren14, 0);
-	add_static_payload(116, ast_format_g719, 0);
-	add_static_payload(117, ast_format_speex16, 0);
-	add_static_payload(118, ast_format_slin16, 0); /* 16 Khz signed linear */
-	add_static_payload(119, ast_format_speex32, 0);
+	add_static_payload(102, ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0);
+	add_static_payload(103, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0);
+	add_static_payload(104, ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), 0);
+	add_static_payload(105, ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), 0);   /* Real time text chat (with redundancy encoding) */
+	add_static_payload(106, ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), 0);     /* Real time text chat */
+	add_static_payload(110, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), 0);
+	add_static_payload(111, ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0);
+	add_static_payload(112, ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), 0);
+	add_static_payload(115, ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), 0);
+	add_static_payload(116, ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), 0);
+	add_static_payload(117, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), 0);
+	add_static_payload(118, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0); /* 16 Khz signed linear */
+	add_static_payload(119, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), 0);
 	add_static_payload(121, NULL, AST_RTP_CISCO_DTMF);   /* Must be type 121 */
-	/* Opus and VP8 */
-	add_static_payload(100, ast_format_vp8, 0);
-	add_static_payload(107, ast_format_opus, 0);
 
 	return 0;
 }
diff --git a/main/say.c b/main/say.c
index c6d85b1..0738d01 100644
--- a/main/say.c
+++ b/main/say.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417591 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <netinet/in.h>
 #include <time.h>
@@ -61,15 +61,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417591 $")
 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
 
 
-static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd)
+static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
 {
 	const char *fn;
 	char fnbuf[10], asciibuf[20] = "letters/ascii";
 	char ltr;
 	int num = 0;
 	int res = 0;
-	int upper = 0;
-	int lower = 0;
 
 	while (str[num] && !res) {
 		fn = NULL;
@@ -123,35 +121,9 @@ static int say_character_str_full(struct ast_channel *chan, const char *str, con
 			break;
 		default:
 			ltr = str[num];
-			if ('A' <= ltr && ltr <= 'Z') {
-				ltr += 'a' - 'A';		/* file names are all lower-case */
-				switch (sensitivity) {
-				case AST_SAY_CASE_UPPER:
-				case AST_SAY_CASE_ALL:
-					upper = !upper;
-				case AST_SAY_CASE_LOWER:
-				case AST_SAY_CASE_NONE:
-					break;
-				}
-			} else if ('a' <= ltr && ltr <= 'z') {
-				switch (sensitivity) {
-				case AST_SAY_CASE_LOWER:
-				case AST_SAY_CASE_ALL:
-					lower = !lower;
-				case AST_SAY_CASE_UPPER:
-				case AST_SAY_CASE_NONE:
-					break;
-				}
-			}
-
-			if (upper) {
-				strcpy(fnbuf, "uppercase");
-			} else if (lower) {
-				strcpy(fnbuf, "lowercase");
-			} else {
-				strcpy(fnbuf, "letters/X");
-				fnbuf[8] = ltr;
-			}
+			if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';		/* file names are all lower-case */
+			strcpy(fnbuf, "letters/X");
+			fnbuf[8] = ltr;
 			fn = fnbuf;
 		}
 		if ((fn && ast_fileexists(fn, NULL, lang) > 0) ||
@@ -165,9 +137,6 @@ static int say_character_str_full(struct ast_channel *chan, const char *str, con
 			}
 			ast_stopstream(chan);
 		}
-		if (upper || lower) {
-			continue;
-		}
 		num++;
 	}
 
@@ -381,7 +350,6 @@ static int ast_say_number_full_pt(struct ast_channel *chan, int num, const char
 static int ast_say_number_full_se(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
 static int ast_say_number_full_zh(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
-static int ast_say_number_full_ja(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
 static int ast_say_number_full_ru(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
 static int ast_say_number_full_ka(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
@@ -404,7 +372,6 @@ static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints,
 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
-static int ast_say_date_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_date_ka(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_date_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
@@ -422,7 +389,6 @@ static int ast_say_date_with_format_pl(struct ast_channel *chan, time_t t, const
 static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
 static int ast_say_date_with_format_zh(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
 static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
-static int ast_say_date_with_format_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
 static int ast_say_date_with_format_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
 static int ast_say_date_with_format_vi(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
 
@@ -434,7 +400,6 @@ static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints,
 static int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_time_zh(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
-static int ast_say_time_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_time_ka(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_time_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_time_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
@@ -448,7 +413,6 @@ static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *i
 static int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_datetime_zh(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
-static int ast_say_datetime_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_datetime_ka(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_datetime_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
 static int ast_say_datetime_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
@@ -505,8 +469,6 @@ static int say_number_full(struct ast_channel *chan, int num, const char *ints,
 		return ast_say_number_full_ka(chan, num, ints, language, options, audiofd, ctrlfd);
 	} else if (!strncasecmp(language, "gr", 2)) { /* Greek syntax */
 	   return ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd);
-	} else if (!strncasecmp(language, "ja", 2)) { /* Japanese syntax */
-	   return ast_say_number_full_ja(chan, num, ints, language, audiofd, ctrlfd);
 	} else if (!strncasecmp(language, "he", 2)) { /* Hebrew syntax */
 	   return ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd);
 	} else if (!strncasecmp(language, "hu", 2)) { /* Hungarian syntax */
@@ -1936,31 +1898,31 @@ static void powiedz(struct ast_channel *chan, const char *language, int audiofd,
 	m100 = m1000 % 100;
 	i100 = m1000 / 100;
 
-        if (i100>0)
-                pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
-
-        if (m100 > 0 && m100 <= 9) {
-                if (m1000 > 0)
-                        pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
-                else
-                        pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
-        } else if (m100 % 10 == 0 && m100 != 0) {
-                pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
-        } else if (m100 > 10 && m100 <= 19) {
-                pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
-        } else if (m100 > 20) {
-                if (odm->separator_dziesiatek[0] == ' ') {
-                        pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
-                        pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
-                } else {
-                        char buf[10];
-                        char *b = buf;
-                        b = pl_append(b, odm->dziesiatki[m100 / 10]);
-                        b = pl_append(b, odm->separator_dziesiatek);
-                        pl_append(b, odm->cyfry2[m100 % 10]);
-                        pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
-                }
-        }
+	if (i100>0)
+		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
+
+	if (m100 > 0 && m100 <= 9) {
+		if (m1000 > 0)
+			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
+		else
+			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
+	} else if (m100 % 10 == 0 && m100 != 0) {
+		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
+	} else if (m100 > 10 && m100 <= 19) {
+		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
+	} else if (m100 > 20) {
+		if (odm->separator_dziesiatek[0] == ' ') {
+			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
+			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
+		} else {
+			char buf[10];
+			char *b = buf;
+			b = pl_append(b, odm->dziesiatki[m100 / 10]);
+			b = pl_append(b, odm->separator_dziesiatek);
+			pl_append(b, odm->cyfry2[m100 % 10]);
+			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
+		}
+	}
 
 	if (rzad > 0) {
 		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
@@ -3347,8 +3309,6 @@ static int say_date(struct ast_channel *chan, time_t t, const char *ints, const
 		return ast_say_date_ka(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
 		return ast_say_date_gr(chan, t, ints, lang);
-	} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
-		return ast_say_date_ja(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "he", 2)) { /* Hebrew syntax */
 		return ast_say_date_he(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */
@@ -3698,8 +3658,6 @@ static int say_date_with_format(struct ast_channel *chan, time_t t, const char *
 		return ast_say_date_with_format_fr(chan, t, ints, lang, format, tzone);
 	} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
 		return ast_say_date_with_format_gr(chan, t, ints, lang, format, tzone);
-	} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
-		return ast_say_date_with_format_ja(chan, t, ints, lang, format, tzone);
 	} else if (!strncasecmp(lang, "it", 2)) { /* Italian syntax */
 		return ast_say_date_with_format_it(chan, t, ints, lang, format, tzone);
 	} else if (!strncasecmp(lang, "mx", 2)) { /* deprecated Mexican syntax */
@@ -6332,8 +6290,6 @@ static int say_time(struct ast_channel *chan, time_t t, const char *ints, const
 		return ast_say_time_ka(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
 		return ast_say_time_gr(chan, t, ints, lang);
-	} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
-		return ast_say_time_ja(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "he", 2)) { /* Hebrew syntax */
 		return ast_say_time_he(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */
@@ -6665,8 +6621,6 @@ static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, co
 		return ast_say_datetime_ka(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
 		return ast_say_datetime_gr(chan, t, ints, lang);
-	} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
-		return ast_say_datetime_ja(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "he", 2)) { /* Hebrew syntax */
 		return ast_say_datetime_he(chan, t, ints, lang);
 	} else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */
@@ -7409,71 +7363,6 @@ static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char
 	return res;
 }
 
-/* Japanese syntax */
-static int ast_say_number_full_ja(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
-{
-     int res = 0;
-     int playh = 0;
-     char fn[256] = "";
-     if (!num)
-             return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
-
-     while (!res && (num || playh)) {
-             if (num < 0) {
-                     ast_copy_string(fn, "digits/minus", sizeof(fn));
-                     if ( num > INT_MIN ) {
-                             num = -num;
-                     } else {
-                             num = 0;
-                     }
-             } else if (playh) {
-                     ast_copy_string(fn, "digits/hundred", sizeof(fn));
-                     playh = 0;
-             } else  if (num < 20) {
-                     snprintf(fn, sizeof(fn), "digits/%d", num);
-                     num = 0;
-             } else  if (num < 100) {
-                     snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
-                     num %= 10;
-             } else {
-                     if (num < 1000){
-                             snprintf(fn, sizeof(fn), "digits/%d", (num/100));
-                             playh++;
-                             num %= 100;
-                     } else {
-                             if (num < 1000000) { /* 1,000,000 */
-                                     res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
-                                     if (res)
-                                             return res;
-                                     num %= 1000;
-                                     snprintf(fn, sizeof(fn), "digits/thousand");
-                             } else {
-                                     if (num < 1000000000) { /* 1,000,000,000 */
-                                             res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
-                                             if (res)
-                                                     return res;
-                                             num %= 1000000;
-                                             ast_copy_string(fn, "digits/million", sizeof(fn));
-                                     } else {
-                                             ast_debug(1, "Number '%d' is too big for me\n", num);
-                                             res = -1;
-                                     }
-                             }
-                     }
-             }
-             if (!res) {
-                     if (!ast_streamfile(chan, fn, language)) {
-                             if ((audiofd  > -1) && (ctrlfd > -1))
-                                     res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                             else
-                                     res = ast_waitstream(chan, ints);
-                     }
-                     ast_stopstream(chan);
-             }
-     }
-     return res;
-}
-
 
 /*! \brief Greek support
  *
@@ -7519,39 +7408,6 @@ static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints,
 }
 
 
-/* Japanese syntax */
-int ast_say_date_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
-{
-      struct ast_tm tm;
-      struct timeval tv = { t, 0 };
-      char fn[256];
-      int res = 0;
-      ast_localtime(&tv, &tm, NULL);
-      if (!res)
-              res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
-      if (!res)
-              res = ast_waitstream(chan, ints);
-      if (!res)
-              res = ast_streamfile(chan, "digits/nen", lang);
-      if (!res) {
-              snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
-              res = ast_streamfile(chan, fn, lang);
-              if (!res)
-                      res = ast_waitstream(chan, ints);
-      }
-      if (!res)
-              res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
-      if (!res)
-              res = ast_streamfile(chan, "digits/nichi", lang);
-      if (!res) {
-              snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
-              res = ast_streamfile(chan, fn, lang);
-              if (!res)
-                      res = ast_waitstream(chan, ints);
-      }
-      return res;
-}
-
 
 /*! \brief Greek support
  *
@@ -7609,52 +7465,6 @@ static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints,
 }
 
 
-/* Japanese */
-static int ast_say_time_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
-{
-
-      struct timeval tv = { t, 0 };
-      struct ast_tm tm;
-      int res = 0;
-      int hour, pm=0;
-
-      ast_localtime(&tv, &tm, NULL);
-      hour = tm.tm_hour;
-
-      if (!hour)
-              hour = 12;
-      else if (hour == 12)
-              pm = 1;
-      else if (hour > 12) {
-              hour -= 12;
-              pm = 1;
-      }
-
-      if (pm) {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/p-m", lang);
-      } else {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/a-m", lang);
-      }
-      if (hour == 9 || hour == 21) {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/9_2", lang);
-      } else {
-              if (!res)
-                      res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
-      }
-      if (!res)
-              res = ast_streamfile(chan, "digits/ji", lang);
-      if (!res)
-              res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
-      if (!res)
-              res = ast_streamfile(chan, "digits/fun", lang);
-      if (!res)
-              res = ast_waitstream(chan, ints);
-      return res;
-}
-
 
 /*! \brief Greek support
  */
@@ -7690,72 +7500,6 @@ static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *i
 	return res;
 }
 
-/* Japanese syntax */
-int ast_say_datetime_ja(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
-{
-      struct timeval tv = { t, 0 };
-      struct ast_tm tm;
-      char fn[256];
-      int res = 0;
-      int hour, pm=0;
-
-      ast_localtime(&tv, &tm, NULL);
-
-      if (!res)
-              res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
-      if (!res)
-              res = ast_streamfile(chan, "digits/nen", lang);
-      if (!res) {
-              snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
-              res = ast_streamfile(chan, fn, lang);
-              if (!res)
-                      res = ast_waitstream(chan, ints);
-      }
-      if (!res)
-              res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
-      if (!res)
-              res = ast_streamfile(chan, "digits/nichi", lang);
-      if (!res) {
-              snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
-              res = ast_streamfile(chan, fn, lang);
-      if (!res)
-              res = ast_waitstream(chan, ints);
-      }
-
-      hour = tm.tm_hour;
-      if (!hour)
-              hour = 12;
-      else if (hour == 12)
-              pm = 1;
-      else if (hour > 12) {
-              hour -= 12;
-              pm = 1;
-      }
-      if (pm) {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/p-m", lang);
-      } else {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/a-m", lang);
-      }
-      if (hour == 9 || hour == 21) {
-              if (!res)
-                      res = ast_streamfile(chan, "digits/9_2", lang);
-      } else {
-              if (!res)
-                      res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
-      }
-      if (!res)
-              res = ast_streamfile(chan, "digits/ji", lang);
-      if (!res)
-              res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
-      if (!res)
-              res = ast_streamfile(chan, "digits/fun", lang);
-      if (!res)
-              res = ast_waitstream(chan, ints);
-      return res;
-}
-
 /*! \brief Greek support
  */
 static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
@@ -7929,274 +7673,6 @@ static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const
 	return res;
 }
 
-/* Japanese syntax */
-int ast_say_date_with_format_ja(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone)
-{
-     struct timeval tv = { time, 0 };
-     struct ast_tm tm;
-     int res=0, offset, sndoffset;
-     char sndfile[256], nextmsg[256];
-
-     if (!format)
-           format = "YbdAPIMS";
-
-     ast_localtime(&tv, &tm, timezone);
-
-     for (offset=0 ; format[offset] != '\0' ; offset++) {
-             ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
-             switch (format[offset]) {
-                     /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
-                     case '\'':
-                             /* Literal name of a sound file */
-                             sndoffset=0;
-                             for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
-                                     sndfile[sndoffset] = format[offset];
-                             sndfile[sndoffset] = '\0';
-                             res = wait_file(chan,ints,sndfile,lang);
-                             break;
-                     case 'A':
-                     case 'a':
-                             /* Sunday - Saturday */
-                             snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
-                             res = wait_file(chan,ints,nextmsg,lang);
-                             break;
-                     case 'B':
-                     case 'b':
-                     case 'h':
-                             /* January - December */
-                             snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
-                             res = wait_file(chan,ints,nextmsg,lang);
-                             break;
-                     case 'd':
-                     case 'e':
-                             /* First - Thirtyfirst */
-                             if (tm.tm_mday < 21) {
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d_2", tm.tm_mday);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                             } else if (tm.tm_mday < 30) {
-                                     /* Between 21 and 29 - two sounds */
-                                     res = wait_file(chan,ints, "digits/20",lang);
-                                     if (!res) {
-                                             snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
-                                             res = wait_file(chan,ints,nextmsg,lang);
-                                     }
-                                     res = wait_file(chan,ints, "digits/nichi",lang);
-                             } else if (tm.tm_mday == 30) {
-                                     /* 30 */
-                                     res = wait_file(chan,ints, "digits/h-30_2",lang);
-                             } else {
-                                     /* 31 */
-                                     res = wait_file(chan,ints, "digits/30",lang);
-                                     res = wait_file(chan,ints, "digits/1",lang);
-                                     res = wait_file(chan,ints, "digits/nichi",lang);
-                             }
-                             break;
-                     case 'Y':
-                             /* Year */
-                             if (tm.tm_year > 99) {
-                                     res = wait_file(chan,ints, "digits/2",lang);
-                                     if (!res) {
-                                             res = wait_file(chan,ints, "digits/thousand",lang);
-                                     }
-                                     if (tm.tm_year > 100) {
-                                             if (!res) {
-                                                     /* This works until the end of 2020 */
-                                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
-                                                     res = wait_file(chan,ints,nextmsg,lang);
-                                             }
-                                     }
-                             } else {
-                                     if (tm.tm_year < 1) {
-                                             /* I'm not going to handle 1900 and prior */
-                                             /* We'll just be silent on the year, instead of bombing out. */
-	                                       } else {
-							 res = wait_file(chan,ints, "digits/19",lang);
-                                             if (!res) {
-                                                     if (tm.tm_year <= 9) {
-                                                             /* 1901 - 1909 */
-                                                             res = wait_file(chan,ints, "digits/oh",lang);
-                                                             if (!res) {
-                                                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
-                                                                     res = wait_file(chan,ints,nextmsg,lang);
-                                                             }
-                                                     } else if (tm.tm_year <= 20) {
-                                                             /* 1910 - 1920 */
-                                                             snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
-                                                             res = wait_file(chan,ints,nextmsg,lang);
-                                                     } else {
-                                                             /* 1921 - 1999 */
-                                                             int ten, one;
-                                                             ten = tm.tm_year / 10;
-                                                             one = tm.tm_year % 10;
-                                                             snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
-                                                             res = wait_file(chan,ints,nextmsg,lang);
-                                                             if (!res) {
-                                                                     if (one != 0) {
-                                                                             snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
-                                                                             res = wait_file(chan,ints,nextmsg,lang);
-                                                                     }
-                                                             }
-                                                     }
-                                             }
-                                     }
-                             }
-                             res = wait_file(chan,ints, "digits/nen",lang);
-                             break;
-                     case 'P':
-                     case 'p':
-                             /* AM/PM */
-                             if (tm.tm_hour > 11)
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
-                             else
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
-                             res = wait_file(chan,ints,nextmsg,lang);
-                             break;
-                     case 'I':
-                     case 'l':
-                             /* 12-Hour */
-                             if (tm.tm_hour == 0)
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/12");
-                             else if (tm.tm_hour == 9 || tm.tm_hour == 21)
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/9_2");
-                             else if (tm.tm_hour > 12)
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
-                             else
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
-                             res = wait_file(chan,ints,nextmsg,lang);
-                             if(!res) res = wait_file(chan,ints, "digits/ji",lang);
-                             break;
-                     case 'H':
-                     case 'k':
-                             if (!res) {
-                                     if (tm.tm_hour != 0) {
-                                             int remainder = tm.tm_hour;
-                                             if (tm.tm_hour > 20) {
-                                                     res = wait_file(chan,ints, "digits/20",lang);
-                                                     remainder -= 20;
-                                             }
-                                             if (!res) {
-                                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
-                                                     res = wait_file(chan,ints,nextmsg,lang);
-                                             }
-                                     }
-                             }
-                             res = wait_file(chan,ints, "digits/ji",lang);
-                             break;
-                     case 'M':
-                             /* Minute */
-                             if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                             } else {
-                                     int ten, one;
-                                     ten = (tm.tm_min / 10) * 10;
-                                     one = (tm.tm_min % 10);
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                                     if (!res) {
-                                             /* Fifty, not fifty-zero */
-                                             if (one != 0) {
-                                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
-                                                     res = wait_file(chan,ints,nextmsg,lang);
-                                             }
-                                     }
-                             }
-                             res = wait_file(chan,ints, "digits/fun",lang);
-                             break;
-                     case 'Q':
-                             /* Shorthand for "Today", "Yesterday", or ABdY */
-                             {
-                                     struct timeval now;
-                                     struct ast_tm tmnow;
-                                     time_t beg_today;
-
-                                     gettimeofday(&now,NULL);
-                                     ast_localtime(&now,&tmnow,timezone);
-                                     /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
-                                     /* In any case, it saves not having to do ast_mktime() */
-                                     beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
-                                     if (beg_today < time) {
-                                             /* Today */
-                                             res = wait_file(chan,ints, "digits/today",lang);
-                                     } else if (beg_today - 86400 < time) {
-                                             /* Yesterday */
-                                              res = wait_file(chan,ints, "digits/yesterday",lang);
-                                     } else {
-                                              res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
-                                     }
-                             }
-                             break;
-                     case 'q':
-                             /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
-                             {
-                                     struct timeval now;
-                                     struct ast_tm tmnow;
-                                     time_t beg_today;
-
-                                     gettimeofday(&now,NULL);
-                                     ast_localtime(&now,&tmnow,timezone);
-                                     /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
-                                     /* In any case, it saves not having to do ast_mktime() */
-                                     beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
-                                     if (beg_today < time) {
-                                             /* Today */
-                                     } else if ((beg_today - 86400) < time) {
-                                             /* Yesterday */
-                                             res = wait_file(chan,ints, "digits/yesterday",lang);
-                                     } else if (beg_today - 86400 * 6 < time) {
-                                             /* Within the last week */
-                                             res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
-                                     } else {
-                                             res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
-                                     }
-                             }
-                             break;
-                     case 'R':
-                             res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
-                             break;
-                     case 'S':
-                             /* Seconds */
-                             if (tm.tm_sec == 0) {
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                             } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                             } else {
-                                     int ten, one;
-                                     ten = (tm.tm_sec / 10) * 10;
-                                     one = (tm.tm_sec % 10);
-                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
-                                     res = wait_file(chan,ints,nextmsg,lang);
-                                     if (!res) {
-                                             /* Fifty, not fifty-zero */
-                                             if (one != 0) {
-                                                     snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
-                                                     res = wait_file(chan,ints,nextmsg,lang);
-                                             }
-                                     }
-                             }
-                             res = wait_file(chan,ints, "digits/byou",lang);
-                             break;
-                     case 'T':
-                             res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
-                             break;
-                     case ' ':
-                     case '	':
-                             /* Just ignore spaces and tabs */
-                             break;
-                     default:
-                             /* Unknown character */
-                             ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
-             }
-             /* Jump out on DTMF */
-             if (res) {
-                     break;
-             }
-     }
-     return res;
-}
-
 /*! \brief Vietnamese syntax */
 int ast_say_date_with_format_vi(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
 {
diff --git a/main/sched.c b/main/sched.c
index 3106d6d..f00b152 100644
--- a/main/sched.c
+++ b/main/sched.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425504 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef DEBUG_SCHEDULER
 #define DEBUG(a) do { \
@@ -47,6 +47,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425504 $")
 #include "asterisk/channel.h"
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/dlinkedlists.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/heap.h"
 #include "asterisk/threadstorage.h"
 
@@ -62,22 +65,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425504 $")
 
 AST_THREADSTORAGE(last_del_id);
 
+/*!
+ * \brief Scheduler ID holder
+ *
+ * These form a queue on a scheduler context. When a new
+ * scheduled item is created, a sched_id is popped off the
+ * queue and its id is assigned to the new scheduled item.
+ * When the scheduled task is complete, the sched_id on that
+ * task is then pushed to the back of the queue to be re-used
+ * on some future scheduled item.
+ */
+struct sched_id {
+	/*! Immutable ID number that is copied onto the scheduled task */
+	int id;
+	AST_LIST_ENTRY(sched_id) list;
+};
+
 struct sched {
 	AST_LIST_ENTRY(sched) list;
-	int id;                       /*!< ID number of event */
+	/*! The ID that has been popped off the scheduler context's queue */
+	struct sched_id *sched_id;
 	struct timeval when;          /*!< Absolute time event should take place */
 	int resched;                  /*!< When to reschedule */
 	int variable;                 /*!< Use return value from callback to reschedule */
 	const void *data;             /*!< Data */
 	ast_sched_cb callback;        /*!< Callback */
 	ssize_t __heap_index;
-	/*!
-	 * Used to synchronize between thread running a task and thread
-	 * attempting to delete a task
-	 */
-	ast_cond_t cond;
-	/*! Indication that a running task was deleted. */
-	unsigned int deleted:1;
 };
 
 struct sched_thread {
@@ -89,16 +102,20 @@ struct sched_thread {
 struct ast_sched_context {
 	ast_mutex_t lock;
 	unsigned int eventcnt;                  /*!< Number of events processed */
+	unsigned int schedcnt;                  /*!< Number of outstanding schedule events */
 	unsigned int highwater;					/*!< highest count so far */
+	struct ast_hashtab *schedq_ht;             /*!< hash table for fast searching */
 	struct ast_heap *sched_heap;
 	struct sched_thread *sched_thread;
-	/*! The scheduled task that is currently executing */
-	struct sched *currently_executing;
 
 #ifdef SCHED_MAX_CACHE
 	AST_LIST_HEAD_NOLOCK(, sched) schedc;   /*!< Cache of unused schedule structures and how many */
 	unsigned int schedccnt;
 #endif
+	/*! Queue of scheduler task IDs to assign */
+	AST_LIST_HEAD_NOLOCK(, sched_id) id_queue;
+	/*! The number of IDs in the id_queue */
+	int id_queue_size;
 };
 
 static void *sched_run(void *data)
@@ -192,6 +209,20 @@ int ast_sched_start_thread(struct ast_sched_context *con)
 	return 0;
 }
 
+static int sched_cmp(const void *a, const void *b)
+{
+	const struct sched *as = a;
+	const struct sched *bs = b;
+	return as->sched_id->id != bs->sched_id->id; /* return 0 on a match like strcmp would */
+}
+
+static unsigned int sched_hash(const void *obj)
+{
+	const struct sched *s = obj;
+	unsigned int h = s->sched_id->id;
+	return h;
+}
+
 static int sched_time_cmp(void *a, void *b)
 {
 	return ast_tvcmp(((struct sched *) b)->when, ((struct sched *) a)->when);
@@ -208,6 +239,9 @@ struct ast_sched_context *ast_sched_context_create(void)
 	ast_mutex_init(&tmp->lock);
 	tmp->eventcnt = 1;
 
+	tmp->schedq_ht = ast_hashtab_create(23, sched_cmp, ast_hashtab_resize_java, ast_hashtab_newsize_java, sched_hash, 1);
+	AST_LIST_HEAD_INIT_NOLOCK(&tmp->id_queue);
+
 	if (!(tmp->sched_heap = ast_heap_create(8, sched_time_cmp,
 			offsetof(struct sched, __heap_index)))) {
 		ast_sched_context_destroy(tmp);
@@ -219,13 +253,18 @@ struct ast_sched_context *ast_sched_context_create(void)
 
 static void sched_free(struct sched *task)
 {
-	ast_cond_destroy(&task->cond);
+	/* task->sched_id will be NULL most of the time, but when the
+	 * scheduler context shuts down, it will free all scheduled
+	 * tasks, and in that case, the task->sched_id will be non-NULL
+	 */
+	ast_free(task->sched_id);
 	ast_free(task);
 }
 
 void ast_sched_context_destroy(struct ast_sched_context *con)
 {
 	struct sched *s;
+	struct sched_id *sid;
 
 	sched_thread_destroy(con);
 	con->sched_thread = NULL;
@@ -246,12 +285,86 @@ void ast_sched_context_destroy(struct ast_sched_context *con)
 		con->sched_heap = NULL;
 	}
 
+	ast_hashtab_destroy(con->schedq_ht, NULL);
+	con->schedq_ht = NULL;
+	while ((sid = AST_LIST_REMOVE_HEAD(&con->id_queue, list))) {
+		ast_free(sid);
+	}
+
 	ast_mutex_unlock(&con->lock);
 	ast_mutex_destroy(&con->lock);
 
 	ast_free(con);
 }
 
+#define ID_QUEUE_INCREMENT 16
+
+/*!
+ * \brief Add new scheduler IDs to the queue.
+ *
+ * \retval The number of IDs added to the queue
+ */
+static int add_ids(struct ast_sched_context *con)
+{
+	int new_size;
+	int original_size;
+	int i;
+
+	original_size = con->id_queue_size;
+	/* So we don't go overboard with the mallocs here, we'll just up
+	 * the size of the list by a fixed amount each time instead of
+	 * multiplying the size by any particular factor
+	 */
+	new_size = original_size + ID_QUEUE_INCREMENT;
+	if (new_size < 0) {
+		/* Overflow. Cap it at INT_MAX. */
+		new_size = INT_MAX;
+	}
+	for (i = original_size; i < new_size; ++i) {
+		struct sched_id *new_id;
+
+		new_id = ast_calloc(1, sizeof(*new_id));
+		if (!new_id) {
+			break;
+		}
+		new_id->id = i;
+		AST_LIST_INSERT_TAIL(&con->id_queue, new_id, list);
+		++con->id_queue_size;
+	}
+
+	return con->id_queue_size - original_size;
+}
+
+static int set_sched_id(struct ast_sched_context *con, struct sched *new_sched)
+{
+	if (AST_LIST_EMPTY(&con->id_queue) && (add_ids(con) == 0)) {
+		return -1;
+	}
+
+	new_sched->sched_id = AST_LIST_REMOVE_HEAD(&con->id_queue, list);
+	return 0;
+}
+
+static void sched_release(struct ast_sched_context *con, struct sched *tmp)
+{
+	if (tmp->sched_id) {
+		AST_LIST_INSERT_TAIL(&con->id_queue, tmp->sched_id, list);
+		tmp->sched_id = NULL;
+	}
+
+	/*
+	 * Add to the cache, or just free() if we
+	 * already have too many cache entries
+	 */
+#ifdef SCHED_MAX_CACHE
+	if (con->schedccnt < SCHED_MAX_CACHE) {
+		AST_LIST_INSERT_HEAD(&con->schedc, tmp, list);
+		con->schedccnt++;
+	} else
+#endif
+		ast_free(tmp);
+}
+
 static struct sched *sched_alloc(struct ast_sched_context *con)
 {
 	struct sched *tmp;
@@ -263,30 +376,47 @@ static struct sched *sched_alloc(struct ast_sched_context *con)
 #ifdef SCHED_MAX_CACHE
 	if ((tmp = AST_LIST_REMOVE_HEAD(&con->schedc, list))) {
 		con->schedccnt--;
-	} else 
+	} else
 #endif
 	{
 		tmp = ast_calloc(1, sizeof(*tmp));
-		ast_cond_init(&tmp->cond, NULL);
+		if (!tmp) {
+			return NULL;
+		}
+	}
+
+	if (set_sched_id(con, tmp)) {
+		sched_release(con, tmp);
+		return NULL;
 	}
 
 	return tmp;
 }
 
-static void sched_release(struct ast_sched_context *con, struct sched *tmp)
+void ast_sched_clean_by_callback(struct ast_sched_context *con, ast_sched_cb match, ast_sched_cb cleanup_cb)
 {
-	/*
-	 * Add to the cache, or just free() if we
-	 * already have too many cache entries
-	 */
+	int i = 1;
+	struct sched *current;
 
-#ifdef SCHED_MAX_CACHE
-	if (con->schedccnt < SCHED_MAX_CACHE) {
-		AST_LIST_INSERT_HEAD(&con->schedc, tmp, list);
-		con->schedccnt++;
-	} else
-#endif
-		sched_free(tmp);
+	ast_mutex_lock(&con->lock);
+	while ((current = ast_heap_peek(con->sched_heap, i))) {
+		if (current->callback != match) {
+			i++;
+			continue;
+		}
+
+		ast_heap_remove(con->sched_heap, current);
+		if (!ast_hashtab_remove_this_object(con->schedq_ht, current)) {
+			ast_log(LOG_ERROR,"Sched entry %d was in the schedq list but not in the hashtab???\n",
+				current->sched_id->id);
+		}
+
+		con->schedcnt--;
+
+		cleanup_cb(current->data);
+		sched_release(con, current);
+	}
+	ast_mutex_unlock(&con->lock);
 }
 
 /*! \brief
@@ -324,8 +454,15 @@ static void schedule(struct ast_sched_context *con, struct sched *s)
 {
 	ast_heap_push(con->sched_heap, s);
 
-	if (ast_heap_size(con->sched_heap) > con->highwater) {
-		con->highwater = ast_heap_size(con->sched_heap);
+	if (!ast_hashtab_insert_safe(con->schedq_ht, s)) {
+		ast_log(LOG_WARNING,"Schedule Queue entry %d is already in table!\n",
+			s->sched_id->id);
+	}
+
+	con->schedcnt++;
+
+	if (con->schedcnt > con->highwater) {
+		con->highwater = con->schedcnt;
 	}
 }
 
@@ -368,18 +505,17 @@ int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb
 
 	ast_mutex_lock(&con->lock);
 	if ((tmp = sched_alloc(con))) {
-		tmp->id = con->eventcnt++;
+		con->eventcnt++;
 		tmp->callback = callback;
 		tmp->data = data;
 		tmp->resched = when;
 		tmp->variable = variable;
 		tmp->when = ast_tv(0, 0);
-		tmp->deleted = 0;
 		if (sched_settime(&tmp->when, when)) {
 			sched_release(con, tmp);
 		} else {
 			schedule(con, tmp);
-			res = tmp->id;
+			res = tmp->sched_id->id;
 		}
 	}
 #ifdef DUMP_SCHEDULER
@@ -408,38 +544,16 @@ int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback
 	return ast_sched_add_variable(con, when, callback, data, 0);
 }
 
-static struct sched *sched_find(struct ast_sched_context *con, int id)
-{
-	int x;
-	size_t heap_size;
-
-	heap_size = ast_heap_size(con->sched_heap);
-	for (x = 1; x <= heap_size; x++) {
-		struct sched *cur = ast_heap_peek(con->sched_heap, x);
-
-		if (cur->id == id) {
-			return cur;
-		}
-	}
-
-	return NULL;
-}
-
 const void *ast_sched_find_data(struct ast_sched_context *con, int id)
 {
-	struct sched *s;
-	const void *data = NULL;
-
-	ast_mutex_lock(&con->lock);
-
-	s = sched_find(con, id);
-	if (s) {
-		data = s->data;
-	}
-
-	ast_mutex_unlock(&con->lock);
-
-	return data;
+	struct sched_id tmp_id;
+	struct sched tmp,*res;
+	tmp_id.id = id;
+	tmp.sched_id = &tmp_id;
+	res = ast_hashtab_lookup(con->schedq_ht, &tmp);
+	if (res)
+		return res->data;
+	return NULL;
 }
 
 /*! \brief
@@ -454,7 +568,12 @@ int ast_sched_del(struct ast_sched_context *con, int id)
 int _ast_sched_del(struct ast_sched_context *con, int id, const char *file, int line, const char *function)
 #endif
 {
-	struct sched *s = NULL;
+	struct sched_id tmp_id = {
+		.id = id,
+	};
+	struct sched *s, tmp = {
+		.sched_id = &tmp_id,
+	};
 	int *last_id = ast_threadstorage_get(&last_del_id, sizeof(int));
 
 	DEBUG(ast_debug(1, "ast_sched_del(%d)\n", id));
@@ -464,21 +583,20 @@ int _ast_sched_del(struct ast_sched_context *con, int id, const char *file, int
 	}
 
 	ast_mutex_lock(&con->lock);
-
-	s = sched_find(con, id);
+	s = ast_hashtab_lookup(con->schedq_ht, &tmp);
 	if (s) {
 		if (!ast_heap_remove(con->sched_heap, s)) {
-			ast_log(LOG_WARNING,"sched entry %d not in the sched heap?\n", s->id);
+			ast_log(LOG_WARNING,"sched entry %d not in the sched heap?\n", s->sched_id->id);
+		}
+
+		if (!ast_hashtab_remove_this_object(con->schedq_ht, s)) {
+			ast_log(LOG_WARNING,"Found sched entry %d, then couldn't remove it?\n",
+				s->sched_id->id);
 		}
+
+		con->schedcnt--;
+
 		sched_release(con, s);
-	} else if (con->currently_executing && (id == con->currently_executing->id)) {
-		s = con->currently_executing;
-		s->deleted = 1;
-		/* Wait for executing task to complete so that caller of ast_sched_del() does not
-		 * free memory out from under the task.
-		 */
-		ast_cond_wait(&s->cond, &con->lock);
-		/* Do not sched_release() here because ast_sched_runq() will do it */
 	}
 
 #ifdef DUMP_SCHEDULER
@@ -497,10 +615,9 @@ int _ast_sched_del(struct ast_sched_context *con, int id, const char *file, int
 		ast_assert(s != NULL);
 #else
 		{
-			char buf[100];
-
-			snprintf(buf, sizeof(buf), "s != NULL, id=%d", id);
-			_ast_assert(0, buf, file, line, function);
+		char buf[100];
+		snprintf(buf, sizeof(buf), "s != NULL, id=%d", id);
+		_ast_assert(0, buf, file, line, function);
 		}
 #endif
 		*last_id = id;
@@ -520,7 +637,7 @@ void ast_sched_report(struct ast_sched_context *con, struct ast_str **buf, struc
 	size_t heap_size;
 
 	memset(countlist, 0, sizeof(countlist));
-	ast_str_set(buf, 0, " Highwater = %u\n schedcnt = %zu\n", con->highwater, ast_heap_size(con->sched_heap));
+	ast_str_set(buf, 0, " Highwater = %u\n schedcnt = %u\n", con->highwater, con->schedcnt);
 
 	ast_mutex_lock(&con->lock);
 
@@ -557,9 +674,9 @@ void ast_sched_dump(struct ast_sched_context *con)
 	int x;
 	size_t heap_size;
 #ifdef SCHED_MAX_CACHE
-	ast_debug(1, "Asterisk Schedule Dump (%zu in Q, %u Total, %u Cache, %u high-water)\n", ast_heap_size(con->sched_heap), con->eventcnt - 1, con->schedccnt, con->highwater);
+	ast_debug(1, "Asterisk Schedule Dump (%u in Q, %u Total, %u Cache, %u high-water)\n", con->schedcnt, con->eventcnt - 1, con->schedccnt, con->highwater);
 #else
-	ast_debug(1, "Asterisk Schedule Dump (%zu in Q, %u Total, %u high-water)\n", ast_heap_size(con->sched_heap), con->eventcnt - 1, con->highwater);
+	ast_debug(1, "Asterisk Schedule Dump (%u in Q, %u Total, %u high-water)\n", con->schedcnt, con->eventcnt - 1, con->highwater);
 #endif
 
 	ast_debug(1, "=============================================================\n");
@@ -572,7 +689,7 @@ void ast_sched_dump(struct ast_sched_context *con)
 		q = ast_heap_peek(con->sched_heap, x);
 		delta = ast_tvsub(q->when, when);
 		ast_debug(1, "|%.4d | %-15p | %-15p | %.6ld : %.6ld |\n",
-			q->id,
+			q->sched_id->id,
 			q->callback,
 			q->data,
 			(long)delta.tv_sec,
@@ -609,6 +726,13 @@ int ast_sched_runq(struct ast_sched_context *con)
 
 		current = ast_heap_pop(con->sched_heap);
 
+		if (!ast_hashtab_remove_this_object(con->schedq_ht, current)) {
+			ast_log(LOG_ERROR,"Sched entry %d was in the schedq list but not in the hashtab???\n",
+				current->sched_id->id);
+		}
+
+		con->schedcnt--;
+
 		/*
 		 * At this point, the schedule queue is still intact.  We
 		 * have removed the first event and the rest is still there,
@@ -618,14 +742,11 @@ int ast_sched_runq(struct ast_sched_context *con)
 		 * should return 0.
 		 */
 
-		con->currently_executing = current;
 		ast_mutex_unlock(&con->lock);
 		res = current->callback(current->data);
 		ast_mutex_lock(&con->lock);
-		con->currently_executing = NULL;
-		ast_cond_signal(&current->cond);
 
-		if (res && !current->deleted) {
+		if (res) {
 			/*
 			 * If they return non-zero, we should schedule them to be
 			 * run again.
@@ -648,18 +769,22 @@ int ast_sched_runq(struct ast_sched_context *con)
 
 long ast_sched_when(struct ast_sched_context *con,int id)
 {
-	struct sched *s;
+	struct sched_id tmp_id;
+	struct sched *s, tmp;
 	long secs = -1;
 	DEBUG(ast_debug(1, "ast_sched_when()\n"));
 
 	ast_mutex_lock(&con->lock);
 
-	s = sched_find(con, id);
+	/* these next 3 lines replace a lookup loop */
+	tmp_id.id = id;
+	tmp.sched_id = &tmp_id;
+	s = ast_hashtab_lookup(con->schedq_ht, &tmp);
+
 	if (s) {
 		struct timeval now = ast_tvnow();
 		secs = s->when.tv_sec - now.tv_sec;
 	}
-
 	ast_mutex_unlock(&con->lock);
 
 	return secs;
diff --git a/main/security_events.c b/main/security_events.c
index 2db1ffc..cb89590 100644
--- a/main/security_events.c
+++ b/main/security_events.c
@@ -28,477 +28,17 @@
 	<support_level>core</support_level>
  ***/
 
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="FailedACL">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request violates an ACL check.</synopsis>
-			<syntax>
-				<parameter name="EventTV">
-					<para>The time the event was detected.</para>
-				</parameter>
-				<parameter name="Severity">
-					<para>A relative severity of the security event.</para>
-					<enumlist>
-						<enum name="Informational"/>
-						<enum name="Error"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Service">
-					<para>The Asterisk service that raised the security event.</para>
-				</parameter>
-				<parameter name="EventVersion">
-					<para>The version of this event.</para>
-				</parameter>
-				<parameter name="AccountID">
-					<para>The Service account associated with the security event
-					notification.</para>
-				</parameter>
-				<parameter name="SessionID">
-					<para>A unique identifier for the session in the service
-					that raised the event.</para>
-				</parameter>
-				<parameter name="LocalAddress">
-					<para>The address of the Asterisk service that raised the
-					security event.</para>
-				</parameter>
-				<parameter name="RemoteAddress">
-					<para>The remote address of the entity that caused the
-					security event to be raised.</para>
-				</parameter>
-				<parameter name="Module" required="false">
-					<para>If available, the name of the module that raised the event.</para>
-				</parameter>
-				<parameter name="ACLName" required="false">
-					<para>If available, the name of the ACL that failed.</para>
-				</parameter>
-				<parameter name="SessionTV" required="false">
-					<para>The timestamp reported by the session.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="InvalidAccountID">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request fails an authentication check due to an invalid account ID.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SessionLimit">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request fails due to exceeding the number of allowed concurrent sessions for that service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MemoryLimit">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request fails due to an internal memory allocation failure.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="LoadAverageLimit">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request fails because a configured load average limit has been reached.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="RequestNotSupported">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request fails due to some aspect of the requested item not being supported by the service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="RequestType">
-					<para>The type of request attempted.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="RequestNotAllowed">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request is not allowed by the service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RequestNotSupported']/managerEventInstance/syntax/parameter[@name='RequestType'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-				<parameter name="RequestParams" required="false">
-					<para>Parameters provided to the rejected request.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AuthMethodNotAllowed">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request used an authentication method not allowed by the service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="AuthMethod">
-					<para>The authentication method attempted.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="RequestBadFormat">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request is received with bad formatting.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RequestNotSupported']/managerEventInstance/syntax/parameter[@name='RequestType'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-				<parameter name="AccountID" required="false">
-					<para>The account ID associated with the rejected request.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='RequestNotAllowed']/managerEventInstance/syntax/parameter[@name='RequestParams'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="SuccessfulAuth">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request successfully authenticates with a service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="UsingPassword">
-					<para>Whether or not the authentication attempt included a password.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="UnexpectedAddress">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request has a different source address then what is expected for a session already in progress with a service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="ExpectedAddress">
-					<para>The address that the request was expected to use.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChallengeResponseFailed">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="Challenge">
-					<para>The challenge that was sent.</para>
-				</parameter>
-				<parameter name="Response">
-					<para>The response that was received.</para>
-				</parameter>
-				<parameter name="ExpectedResponse">
-					<para>The expected response to the challenge.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="InvalidPassword">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request provides an invalid password during an authentication attempt.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-				<parameter name="Challenge" required="false">
-					<para>The challenge that was sent.</para>
-				</parameter>
-				<parameter name="ReceivedChallenge" required="false">
-					<para>The challenge that was received.</para>
-				</parameter>
-				<parameter name="RecievedHash" required="false">
-					<para>The hash that was received.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChallengeSent">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when an Asterisk service sends an authentication challenge to a request.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ChallengeResponseFailed']/managerEventInstance/syntax/parameter[@name='Challenge'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="InvalidTransport">
-		<managerEventInstance class="EVENT_FLAG_SECURITY">
-			<synopsis>Raised when a request attempts to use a transport not allowed by the Asterisk service.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventTV'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Severity'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Service'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='EventVersion'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='AccountID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionID'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='LocalAddress'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='RemoteAddress'])" />
-				<parameter name="AttemptedTransport">
-					<para>The transport type that the request attempted to use.</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='Module'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FailedACL']/managerEventInstance/syntax/parameter[@name='SessionTV'])" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/strings.h"
 #include "asterisk/network.h"
-#include "asterisk/event.h"
 #include "asterisk/security_events.h"
 #include "asterisk/netsock2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/astobj2.h"
 
 static const size_t TIMESTAMP_STR_LEN = 32;
-static const size_t SECURITY_EVENT_BUF_INIT_LEN = 256;
-
-/*! \brief Security Topic */
-static struct stasis_topic *security_topic;
-
-struct stasis_topic *ast_security_topic(void)
-{
-	return security_topic;
-}
-
-static int append_event_str_single(struct ast_str **str, struct ast_json *json,
-		const enum ast_event_ie_type ie_type)
-{
-	const char *ie_type_key = ast_event_get_ie_type_name(ie_type);
-	struct ast_json *json_string = ast_json_object_get(json, ie_type_key);
-
-	if (!json_string) {
-		return 0;
-	}
-
-	if (ast_str_append(str, 0, "%s: %s\r\n", ie_type_key, S_OR(ast_json_string_get(json_string), "")) == -1) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int append_event_str_from_json(struct ast_str **str, struct ast_json *json,
-		const struct ast_security_event_ie_type *ies)
-{
-	unsigned int i;
-
-	if (!ies) {
-		return 0;
-	}
-
-	for (i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) {
-		if (append_event_str_single(str, json, ies[i].ie_type)) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static struct ast_manager_event_blob *security_event_to_ami_blob(struct ast_json *json)
-{
-	RAII_VAR(struct ast_str *, str, NULL, ast_free);
-	struct ast_json *event_type_json;
-	enum ast_security_event_type event_type;
-
-	event_type_json = ast_json_object_get(json, "SecurityEvent");
-	event_type = ast_json_integer_get(event_type_json);
-
-	ast_assert(event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
-
-	if (!(str = ast_str_create(SECURITY_EVENT_BUF_INIT_LEN))) {
-		return NULL;
-	}
-
-	if (append_event_str_from_json(&str, json,
-			ast_security_event_get_required_ies(event_type))) {
-		ast_log(AST_LOG_ERROR, "Failed to issue a security event to AMI: "
-			"error occurred when adding required event fields.\n");
-		return NULL;
-	}
-
-	if (append_event_str_from_json(&str, json,
-			ast_security_event_get_optional_ies(event_type))) {
-		ast_log(AST_LOG_ERROR, "Failed to issue a security event to AMI: "
-			"error occurred when adding optional event fields.\n");
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_SECURITY,
-		ast_security_event_get_name(event_type),
-		"%s",
-		ast_str_buffer(str));
-}
-
-static struct ast_manager_event_blob *security_event_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-
-	if (stasis_message_type(message) != ast_security_event_type()) {
-		return NULL;
-	}
-
-	if (!payload) {
-		return NULL;
-	}
-
-	return security_event_to_ami_blob(payload->json);
-}
-
-/*! \brief Message type for security events */
-STASIS_MESSAGE_TYPE_DEFN(ast_security_event_type,
-	.to_ami = security_event_to_ami,
-	);
-
-static void security_stasis_cleanup(void)
-{
-	ao2_cleanup(security_topic);
-	security_topic = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_security_event_type);
-}
-
-int ast_security_stasis_init(void)
-{
-	ast_register_cleanup(security_stasis_cleanup);
-
-	security_topic = stasis_topic_create("ast_security");
-	if (!security_topic) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_security_event_type)) {
-		return -1;
-	}
-
-
-	return 0;
-}
 
 static const struct {
 	const char *name;
@@ -887,7 +427,7 @@ const char *ast_security_event_severity_get_name(
 
 static int check_event_type(const enum ast_security_event_type event_type)
 {
-	if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
+	if ((unsigned int)event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
 		ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type);
 		return -1;
 	}
@@ -924,17 +464,72 @@ const struct ast_security_event_ie_type *ast_security_event_get_optional_ies(
 	return sec_events[event_type].optional_ies;
 }
 
-static int add_ip_json_object(struct ast_json *json, enum ast_event_ie_type ie_type,
+static void encode_timestamp(struct ast_str **str, const struct timeval *tv)
+{
+	ast_str_set(str, 0, "%u-%u",
+			(unsigned int) tv->tv_sec,
+			(unsigned int) tv->tv_usec);
+}
+
+static struct ast_event *alloc_event(const struct ast_security_event_common *sec)
+{
+	struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN);
+	struct timeval tv = ast_tvnow();
+	const char *severity_str;
+
+	if (check_event_type(sec->event_type)) {
+		return NULL;
+	}
+
+	encode_timestamp(&str, &tv);
+
+	severity_str = S_OR(
+		ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
+		"Unknown"
+	);
+
+	return ast_event_new(AST_EVENT_SECURITY,
+		AST_EVENT_IE_SECURITY_EVENT, AST_EVENT_IE_PLTYPE_UINT, sec->event_type,
+		AST_EVENT_IE_EVENT_VERSION, AST_EVENT_IE_PLTYPE_UINT, sec->version,
+		AST_EVENT_IE_EVENT_TV, AST_EVENT_IE_PLTYPE_STR, ast_str_buffer(str),
+		AST_EVENT_IE_SERVICE, AST_EVENT_IE_PLTYPE_STR, sec->service,
+		AST_EVENT_IE_SEVERITY, AST_EVENT_IE_PLTYPE_STR, severity_str,
+		AST_EVENT_IE_END);
+}
+
+static int add_timeval_ie(struct ast_event **event, enum ast_event_ie_type ie_type,
+		const struct timeval *tv)
+{
+	struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN);
+
+	encode_timestamp(&str, tv);
+
+	return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str));
+}
+
+static int add_ip_ie(struct ast_event **event, enum ast_event_ie_type ie_type,
 		const struct ast_security_event_ip_addr *addr)
 {
-	struct ast_json *json_ip;
+	struct ast_str *str = ast_str_alloca(64);
 
-	json_ip = ast_json_ipaddr(addr->addr, addr->transport);
-	if (!json_ip) {
-		return -1;
+	ast_str_set(&str, 0, (ast_sockaddr_is_ipv4(addr->addr) || ast_sockaddr_is_ipv4_mapped(addr->addr)) ? "IPV4/" : "IPV6/");
+
+	switch (addr->transport) {
+	case AST_SECURITY_EVENT_TRANSPORT_UDP:
+		ast_str_append(&str, 0, "UDP/");
+		break;
+	case AST_SECURITY_EVENT_TRANSPORT_TCP:
+		ast_str_append(&str, 0, "TCP/");
+		break;
+	case AST_SECURITY_EVENT_TRANSPORT_TLS:
+		ast_str_append(&str, 0, "TLS/");
+		break;
 	}
 
-	return ast_json_object_set(json, ast_event_get_ie_type_name(ie_type), json_ip);
+	ast_str_append(&str, 0, "%s", ast_sockaddr_stringify_addr(addr->addr));
+	ast_str_append(&str, 0, "/%s", ast_sockaddr_stringify_port(addr->addr));
+
+	return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str));
 }
 
 enum ie_required {
@@ -942,7 +537,7 @@ enum ie_required {
 	REQUIRED
 };
 
-static int add_json_object(struct ast_json *json, const struct ast_security_event_common *sec,
+static int add_ie(struct ast_event **event, const struct ast_security_event_common *sec,
 		const struct ast_security_event_ie_type *ie_type, enum ie_required req)
 {
 	int res = 0;
@@ -964,46 +559,28 @@ static int add_json_object(struct ast_json *json, const struct ast_security_even
 	case AST_EVENT_IE_ATTEMPTED_TRANSPORT:
 	{
 		const char *str;
-		struct ast_json *json_string;
 
 		str = *((const char **)(((const char *) sec) + ie_type->offset));
 
 		if (req && !str) {
-			ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
-					"type '%u' (%s) not present\n", ie_type->ie_type,
-					ast_event_get_ie_type_name(ie_type->ie_type),
-					sec->event_type, ast_security_event_get_name(sec->event_type));
+			ast_log(LOG_WARNING, "Required IE '%d' for security event "
+					"type '%u' not present\n", ie_type->ie_type,
+					sec->event_type);
 			res = -1;
-			break;
-		}
-
-		if (!str) {
-			break;
 		}
 
-		json_string = ast_json_string_create(str);
-		if (!json_string) {
-			res = -1;
-			break;
+		if (str) {
+			res = ast_event_append_ie_str(event, ie_type->ie_type, str);
 		}
 
-		res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
 		break;
 	}
 	case AST_EVENT_IE_EVENT_VERSION:
 	case AST_EVENT_IE_USING_PASSWORD:
 	{
-		struct ast_json *json_string;
 		uint32_t val;
 		val = *((const uint32_t *)(((const char *) sec) + ie_type->offset));
-
-		json_string = ast_json_stringf("%u", val);
-		if (!json_string) {
-			res = -1;
-			break;
-		}
-
-		res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_string);
+		res = ast_event_append_ie_uint(event, ie_type->ie_type, val);
 		break;
 	}
 	case AST_EVENT_IE_LOCAL_ADDR:
@@ -1015,17 +592,15 @@ static int add_json_object(struct ast_json *json, const struct ast_security_even
 		addr = (const struct ast_security_event_ip_addr *)(((const char *) sec) + ie_type->offset);
 
 		if (req && !addr->addr) {
-			ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
-					"type '%u' (%s) not present\n", ie_type->ie_type,
-					ast_event_get_ie_type_name(ie_type->ie_type),
-					sec->event_type, ast_security_event_get_name(sec->event_type));
+			ast_log(LOG_WARNING, "Required IE '%d' for security event "
+					"type '%u' not present\n", ie_type->ie_type,
+					sec->event_type);
 			res = -1;
 		}
 
 		if (addr->addr) {
-			res = add_ip_json_object(json, ie_type->ie_type, addr);
+			res = add_ip_ie(event, ie_type->ie_type, addr);
 		}
-
 		break;
 	}
 	case AST_EVENT_IE_SESSION_TV:
@@ -1035,20 +610,14 @@ static int add_json_object(struct ast_json *json, const struct ast_security_even
 		tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset));
 
 		if (req && !tval) {
-			ast_log(LOG_WARNING, "Required IE '%d' (%s) for security event "
-					"type '%u' (%s) not present\n", ie_type->ie_type,
-					ast_event_get_ie_type_name(ie_type->ie_type),
-					sec->event_type, ast_security_event_get_name(sec->event_type));
+			ast_log(LOG_WARNING, "Required IE '%d' for security event "
+					"type '%u' not present\n", ie_type->ie_type,
+					sec->event_type);
 			res = -1;
 		}
 
 		if (tval) {
-			struct ast_json *json_tval = ast_json_timeval(*tval, NULL);
-			if (!json_tval) {
-				res = -1;
-				break;
-			}
-			res = ast_json_object_set(json, ast_event_get_ie_type_name(ie_type->ie_type), json_tval);
+			add_timeval_ie(event, ie_type->ie_type, tval);
 		}
 
 		break;
@@ -1058,88 +627,28 @@ static int add_json_object(struct ast_json *json, const struct ast_security_even
 		/* Added automatically, nothing to do here. */
 		break;
 	default:
-		ast_log(LOG_WARNING, "Unhandled IE type '%d' (%s), this security event "
-				"will be missing data.\n", ie_type->ie_type,
-				ast_event_get_ie_type_name(ie_type->ie_type));
+		ast_log(LOG_WARNING, "Unhandled IE type '%d', this security event "
+				"will be missing data.\n", ie_type->ie_type);
 		break;
 	}
 
 	return res;
 }
 
-static struct ast_json *alloc_security_event_json_object(const struct ast_security_event_common *sec)
-{
-	struct timeval tv = ast_tvnow();
-	const char *severity_str;
-	struct ast_json *json_temp;
-	RAII_VAR(struct ast_json *, json_object, ast_json_object_create(), ast_json_unref);
-
-	if (!json_object) {
-		return NULL;
-	}
-
-	/* NOTE: Every time ast_json_object_set is used, json_temp becomes a stale pointer since the reference is taken.
-	 *       This is true even if ast_json_object_set fails.
-	 */
-
-	json_temp = ast_json_integer_create(sec->event_type);
-	if (!json_temp || ast_json_object_set(json_object, "SecurityEvent", json_temp)) {
-		return NULL;
-	}
-
-	json_temp = ast_json_stringf("%u", sec->version);
-	if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_VERSION), json_temp)) {
-		return NULL;
-	}
-
-	/* AST_EVENT_IE_EVENT_TV */
-	json_temp  = ast_json_timeval(tv, NULL);
-	if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_EVENT_TV), json_temp)) {
-		return NULL;
-	}
-
-	/* AST_EVENT_IE_SERVICE */
-	json_temp = ast_json_string_create(sec->service);
-	if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SERVICE), json_temp)) {
-		return NULL;
-	}
-
-	/* AST_EVENT_IE_SEVERITY */
-	severity_str = S_OR(
-		ast_security_event_severity_get_name(sec_events[sec->event_type].severity),
-		"Unknown"
-	);
-
-	json_temp = ast_json_string_create(severity_str);
-	if (!json_temp || ast_json_object_set(json_object, ast_event_get_ie_type_name(AST_EVENT_IE_SEVERITY), json_temp)) {
-		return NULL;
-	}
-
-	return ast_json_ref(json_object);
-}
-
 static int handle_security_event(const struct ast_security_event_common *sec)
 {
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
+	struct ast_event *event;
 	const struct ast_security_event_ie_type *ies;
 	unsigned int i;
 
-	if (!ast_security_event_type()) {
-		return -1;
-	}
-
-	json_object = alloc_security_event_json_object(sec);
-	if (!json_object) {
+	if (!(event = alloc_event(sec))) {
 		return -1;
 	}
 
 	for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0;
 			ies[i].ie_type != AST_EVENT_IE_END;
 			i++) {
-		if (add_json_object(json_object, sec, ies + i, REQUIRED)) {
+		if (add_ie(&event, sec, ies + i, REQUIRED)) {
 			goto return_error;
 		}
 	}
@@ -1147,33 +656,31 @@ static int handle_security_event(const struct ast_security_event_common *sec)
 	for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0;
 			ies[i].ie_type != AST_EVENT_IE_END;
 			i++) {
-		if (add_json_object(json_object, sec, ies + i, NOT_REQUIRED)) {
+		if (add_ie(&event, sec, ies + i, NOT_REQUIRED)) {
 			goto return_error;
 		}
 	}
 
-	/* The json blob is ready.  Throw it in the payload and send it out over stasis. */
-	if (!(json_payload = ast_json_payload_create(json_object))) {
-		goto return_error;
-	}
-
-	msg = stasis_message_create(ast_security_event_type(), json_payload);
 
-	if (!msg) {
+	if (ast_event_queue(event)) {
 		goto return_error;
 	}
 
-	stasis_publish(ast_security_topic(), msg);
-
 	return 0;
 
 return_error:
+	if (event) {
+		ast_event_destroy(event);
+	}
+
 	return -1;
 }
 
 int ast_security_event_report(const struct ast_security_event_common *sec)
 {
-	if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
+	int res;
+
+	if ((unsigned int)sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) {
 		ast_log(LOG_ERROR, "Invalid security event type\n");
 		return -1;
 	}
@@ -1190,12 +697,9 @@ int ast_security_event_report(const struct ast_security_event_common *sec)
 		return -1;
 	}
 
-	if (handle_security_event(sec)) {
-		ast_log(LOG_ERROR, "Failed to issue security event of type %s.\n",
-				ast_security_event_get_name(sec->event_type));
-	}
+	res = handle_security_event(sec);
 
-	return 0;
+	return res;
 }
 
 
diff --git a/main/sem.c b/main/sem.c
deleted file mode 100644
index a7e3d6c..0000000
--- a/main/sem.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Asterisk semaphore support.
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400186 $")
-
-#include "asterisk/sem.h"
-#include "asterisk/utils.h"
-
-#ifndef HAS_WORKING_SEMAPHORE
-
-/* DIY semaphores! */
-
-int ast_sem_init(struct ast_sem *sem, int pshared, unsigned int value)
-{
-	if (pshared) {
-		/* Don't need it... yet */
-		errno = ENOSYS;
-		return -1;
-	}
-
-	/* Since value is unsigned, this will also catch attempts to init with
-	 * a negative value */
-	if (value > AST_SEM_VALUE_MAX) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	sem->count = value;
-	sem->waiters = 0;
-	ast_mutex_init(&sem->mutex);
-	ast_cond_init(&sem->cond, NULL);
-	return 0;
-}
-
-int ast_sem_destroy(struct ast_sem *sem)
-{
-	ast_mutex_destroy(&sem->mutex);
-	ast_cond_destroy(&sem->cond);
-	return 0;
-}
-
-int ast_sem_post(struct ast_sem *sem)
-{
-	SCOPED_MUTEX(lock, &sem->mutex);
-
-	ast_assert(sem->count >= 0);
-
-	if (sem->count == AST_SEM_VALUE_MAX) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-
-	/* Give it up! */
-	++sem->count;
-
-	/* Release a waiter, if needed */
-	if (sem->waiters) {
-		ast_cond_signal(&sem->cond);
-	}
-
-	return 0;
-}
-
-int ast_sem_wait(struct ast_sem *sem)
-{
-	SCOPED_MUTEX(lock, &sem->mutex);
-
-	ast_assert(sem->count >= 0);
-
-	/* Wait for a non-zero count */
-	++sem->waiters;
-	while (sem->count == 0) {
-		ast_cond_wait(&sem->cond, &sem->mutex);
-	}
-	--sem->waiters;
-
-	/* Take it! */
-	--sem->count;
-
-	return 0;
-}
-
-int ast_sem_getvalue(struct ast_sem *sem, int *sval)
-{
-	SCOPED_MUTEX(lock, &sem->mutex);
-
-	ast_assert(sem->count >= 0);
-
-	*sval = sem->count;
-
-	return 0;
-}
-
-#endif
diff --git a/main/sha1.c b/main/sha1.c
index 97bd2dd..41ec2f0 100644
--- a/main/sha1.c
+++ b/main/sha1.c
@@ -336,7 +336,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
 /*!
  * \brief This helper function finishes off the digest calculations.
  * \param context [in/out]  The context to pad.
- * \param Pad_Byte [in]  The last byte to add to the message block
+ * \param Pad_byte [in]  The last byte to add to the message block
  *     before the 0-padding and length.  This will contain the last
  *     bits of the message followed by another single bit.  If the
  *     message was an exact multiple of 8-bits long, Pad_Byte will
@@ -359,7 +359,7 @@ static void SHA1Finalize(SHA1Context * context, uint8_t Pad_Byte)
 /*!
  * \brief Pad message to be 512 bits.
  * \param context [in/out]  The context to pad.
- * \param Pad_Byte [in]  Last padding byte.
+ * \param Pad_byte [in]  Last padding byte.
  *
  *  According to the standard, the message must be padded to the next
  *  even multiple of 512 bits.  The first padding bit must be a '1'.
diff --git a/main/slinfactory.c b/main/slinfactory.c
index bf8a4dd..44efc42 100644
--- a/main/slinfactory.c
+++ b/main/slinfactory.c
@@ -30,29 +30,27 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 #include "asterisk/slinfactory.h"
 #include "asterisk/translate.h"
-#include "asterisk/astobj2.h"
 
 void ast_slinfactory_init(struct ast_slinfactory *sf)
 {
 	memset(sf, 0, sizeof(*sf));
 	sf->offset = sf->hold;
-	sf->output_format = ao2_bump(ast_format_slin);
+	ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0);
 }
 
-int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out)
+int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, const struct ast_format *slin_out)
 {
 	memset(sf, 0, sizeof(*sf));
 	sf->offset = sf->hold;
-	if (!ast_format_cache_is_slinear(slin_out)) {
+	if (!ast_format_is_slinear(slin_out)) {
 		return -1;
 	}
-	sf->output_format = ao2_bump(slin_out);
+	ast_format_copy(&sf->output_format, slin_out);
 
 	return 0;
 }
@@ -66,14 +64,8 @@ void ast_slinfactory_destroy(struct ast_slinfactory *sf)
 		sf->trans = NULL;
 	}
 
-	while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) {
+	while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list)))
 		ast_frfree(f);
-	}
-
-	ao2_cleanup(sf->output_format);
-	sf->output_format = NULL;
-	ao2_cleanup(sf->format);
-	sf->format = NULL;
 }
 
 int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
@@ -91,22 +83,22 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
 		return 0;
 	}
 
-	if (ast_format_cmp(f->subclass.format, sf->output_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		if (sf->trans && (ast_format_cmp(f->subclass.format, sf->format) == AST_FORMAT_CMP_NOT_EQUAL)) {
+	if (ast_format_cmp(&f->subclass.format, &sf->output_format) == AST_FORMAT_CMP_NOT_EQUAL) {
+		if (sf->trans && (ast_format_cmp(&f->subclass.format, &sf->format) == AST_FORMAT_CMP_NOT_EQUAL)) {
 			ast_translator_free_path(sf->trans);
 			sf->trans = NULL;
 		}
 
 		if (!sf->trans) {
-			if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass.format))) {
+			if (!(sf->trans = ast_translator_build_path(&sf->output_format, &f->subclass.format))) {
 				ast_log(LOG_WARNING, "Cannot build a path from %s (%u)to %s (%u)\n",
-					ast_format_get_name(f->subclass.format),
-					ast_format_get_codec_id(f->subclass.format),
-					ast_format_get_name(sf->output_format),
-					ast_format_get_codec_id(sf->output_format));
+					ast_getformatname(&f->subclass.format),
+					f->subclass.format.id,
+					ast_getformatname(&sf->output_format),
+					sf->output_format.id);
 				return 0;
 			}
-			ao2_replace(sf->format, f->subclass.format);
+			ast_format_copy(&sf->format, &f->subclass.format);
 		}
 
 		if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
diff --git a/main/smoother.c b/main/smoother.c
deleted file mode 100644
index 4ec5f65..0000000
--- a/main/smoother.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Frame smoother manipulation routines
- *
- * \author Mark Spencer <markster at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/_private.h"
-#include "asterisk/frame.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/time.h"
-#include "asterisk/utils.h"
-#include "asterisk/format.h"
-#include "asterisk/codec.h"
-#include "asterisk/smoother.h"
-
-#define SMOOTHER_SIZE 8000
-
-struct ast_smoother {
-	int size;
-	struct ast_format *format;
-	int flags;
-	float samplesperbyte;
-	unsigned int opt_needs_swap:1;
-	struct ast_frame f;
-	struct timeval delivery;
-	char data[SMOOTHER_SIZE];
-	char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
-	struct ast_frame *opt;
-	int len;
-};
-
-static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
-{
-	if (s->flags & AST_SMOOTHER_FLAG_G729) {
-		if (s->len % 10) {
-			ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
-			return 0;
-		}
-	}
-	if (swap) {
-		ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples);
-	} else {
-		memcpy(s->data + s->len, f->data.ptr, f->datalen);
-	}
-	/* If either side is empty, reset the delivery time */
-	if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) {	/* XXX really ? */
-		s->delivery = f->delivery;
-	}
-	s->len += f->datalen;
-
-	return 0;
-}
-
-void ast_smoother_reset(struct ast_smoother *s, int bytes)
-{
-	ao2_cleanup(s->format);
-	memset(s, 0, sizeof(*s));
-	s->size = bytes;
-}
-
-void ast_smoother_reconfigure(struct ast_smoother *s, int bytes)
-{
-	/* if there is no change, then nothing to do */
-	if (s->size == bytes) {
-		return;
-	}
-	/* set the new desired output size */
-	s->size = bytes;
-	/* if there is no 'optimized' frame in the smoother,
-	 *   then there is nothing left to do
-	 */
-	if (!s->opt) {
-		return;
-	}
-	/* there is an 'optimized' frame here at the old size,
-	 * but it must now be put into the buffer so the data
-	 * can be extracted at the new size
-	 */
-	smoother_frame_feed(s, s->opt, s->opt_needs_swap);
-	s->opt = NULL;
-}
-
-struct ast_smoother *ast_smoother_new(int size)
-{
-	struct ast_smoother *s;
-	if (size < 1)
-		return NULL;
-	if ((s = ast_calloc(1, sizeof(*s))))
-		ast_smoother_reset(s, size);
-	return s;
-}
-
-int ast_smoother_get_flags(struct ast_smoother *s)
-{
-	return s->flags;
-}
-
-void ast_smoother_set_flags(struct ast_smoother *s, int flags)
-{
-	s->flags = flags;
-}
-
-int ast_smoother_test_flag(struct ast_smoother *s, int flag)
-{
-	return (s->flags & flag);
-}
-
-int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
-{
-	if (f->frametype != AST_FRAME_VOICE) {
-		ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
-		return -1;
-	}
-	if (!s->format) {
-		s->format = ao2_bump(f->subclass.format);
-		s->samplesperbyte = (float)f->samples / (float)f->datalen;
-	} else if (ast_format_cmp(s->format, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n",
-			ast_format_get_name(s->format), ast_format_get_name(f->subclass.format));
-		return -1;
-	}
-	if (s->len + f->datalen > SMOOTHER_SIZE) {
-		ast_log(LOG_WARNING, "Out of smoother space\n");
-		return -1;
-	}
-	if (((f->datalen == s->size) ||
-	     ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) &&
-	    !s->opt &&
-	    !s->len &&
-	    (f->offset >= AST_MIN_OFFSET)) {
-		/* Optimize by sending the frame we just got
-		   on the next read, thus eliminating the douple
-		   copy */
-		if (swap)
-			ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples);
-		s->opt = f;
-		s->opt_needs_swap = swap ? 1 : 0;
-		return 0;
-	}
-
-	return smoother_frame_feed(s, f, swap);
-}
-
-struct ast_frame *ast_smoother_read(struct ast_smoother *s)
-{
-	struct ast_frame *opt;
-	int len;
-
-	/* IF we have an optimization frame, send it */
-	if (s->opt) {
-		if (s->opt->offset < AST_FRIENDLY_OFFSET)
-			ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
-							s->opt->offset);
-		opt = s->opt;
-		s->opt = NULL;
-		return opt;
-	}
-
-	/* Make sure we have enough data */
-	if (s->len < s->size) {
-		/* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
-		if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10)))
-			return NULL;
-	}
-	len = s->size;
-	if (len > s->len)
-		len = s->len;
-	/* Make frame */
-	s->f.frametype = AST_FRAME_VOICE;
-	s->f.subclass.format = s->format;
-	s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET;
-	s->f.offset = AST_FRIENDLY_OFFSET;
-	s->f.datalen = len;
-	/* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
-	s->f.samples = len * s->samplesperbyte;	/* XXX rounding */
-	s->f.delivery = s->delivery;
-	/* Fill Data */
-	memcpy(s->f.data.ptr, s->data, len);
-	s->len -= len;
-	/* Move remaining data to the front if applicable */
-	if (s->len) {
-		/* In principle this should all be fine because if we are sending
-		   G.729 VAD, the next timestamp will take over anyawy */
-		memmove(s->data, s->data + len, s->len);
-		if (!ast_tvzero(s->delivery)) {
-			/* If we have delivery time, increment it, otherwise, leave it at 0 */
-			s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples,
-				ast_format_get_sample_rate(s->format)));
-		}
-	}
-	/* Return frame */
-	return &s->f;
-}
-
-void ast_smoother_free(struct ast_smoother *s)
-{
-	ao2_cleanup(s->format);
-	ast_free(s);
-}
-
diff --git a/main/sorcery.c b/main/sorcery.c
deleted file mode 100644
index 041bb48..0000000
--- a/main/sorcery.c
+++ /dev/null
@@ -1,2197 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Sorcery Data Access Layer API
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429000 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/strings.h"
-#include "asterisk/config_options.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/module.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/threadpool.h"
-#include "asterisk/json.h"
-
-/* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
-#undef open
-#undef close
-
-/*! \brief Number of buckets for wizards (should be prime for performance reasons) */
-#define WIZARD_BUCKETS 7
-
-/*! \brief Number of buckets for types (should be prime for performance reasons) */
-#define TYPE_BUCKETS 53
-
-/*! \brief Number of buckets for instances (should be prime for performance reasons) */
-#define INSTANCE_BUCKETS 17
-
-/*! \brief Number of buckets for object fields (should be prime for performance reasons) */
-#define OBJECT_FIELD_BUCKETS 29
-
-#define NOTIFY_GENERIC_OBSERVERS(container, type, callback, ...) ({ \
-	struct ao2_iterator i = ao2_iterator_init(container, 0); \
-	struct type *observer; \
-	ao2_rdlock(container); \
-	while ((observer = ao2_iterator_next(&i))) { \
-		if (observer->callbacks->callback) { \
-			observer->callbacks->callback(__VA_ARGS__); \
-		} \
-		ao2_cleanup(observer); \
-	} \
-	ao2_unlock(container); \
-	ao2_iterator_cleanup(&i); \
-})
-
-#define NOTIFY_GLOBAL_OBSERVERS(container, callback, ...) \
-	NOTIFY_GENERIC_OBSERVERS(container, sorcery_global_observer, callback, __VA_ARGS__)
-
-#define NOTIFY_INSTANCE_OBSERVERS(container, callback, ...) \
-	NOTIFY_GENERIC_OBSERVERS(container, sorcery_instance_observer, callback, __VA_ARGS__)
-
-#define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
-	NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
-
-/*! \brief Thread pool for observers */
-static struct ast_threadpool *threadpool;
-
-/*! \brief Structure for internal sorcery object information */
-struct ast_sorcery_object {
-	/*! \brief Unique identifier of this object */
-	char *id;
-
-	/*! \brief Type of object */
-	char type[MAX_OBJECT_TYPE];
-
-	/*! \brief Optional object destructor */
-	ao2_destructor_fn destructor;
-
-	/*! \brief Extended object fields */
-	struct ast_variable *extended;
-};
-
-/*! \brief Structure for registered object type */
-struct ast_sorcery_object_type {
-	/*! \brief Unique name of the object type */
-	char name[MAX_OBJECT_TYPE];
-
-	/*! \brief Optional transformation callback */
-	sorcery_transform_handler transform;
-
-	/*! \brief Optional object set apply callback */
-	sorcery_apply_handler apply;
-
-	/*! \brief Optional object copy callback */
-	sorcery_copy_handler copy;
-
-	/*! \brief Optional object diff callback */
-	sorcery_diff_handler diff;
-
-	/*! \brief Wizard instances */
-	struct ao2_container *wizards;
-
-	/*! \brief Object fields */
-	struct ao2_container *fields;
-
-	/*! \brief Configuration framework general information */
-	struct aco_info *info;
-
-	/*! \brief Configuration framework file information */
-	struct aco_file *file;
-
-	/*! \brief Type details */
-	struct aco_type type;
-
-	/*! \brief Observers */
-	struct ao2_container *observers;
-
-	/*! \brief Serializer for observers */
-	struct ast_taskprocessor *serializer;
-
-	/*! \brief Specifies if object type is reloadable or not */
-	unsigned int reloadable:1;
-};
-
-/*! \brief Structure for registered object type observer */
-struct ast_sorcery_object_type_observer {
-	/*! \brief Pointer to the observer implementation */
-	const struct ast_sorcery_observer *callbacks;
-};
-
-/*! \brief Structure used for observer invocations */
-struct sorcery_observer_invocation {
-	/*! \brief Pointer to the object type */
-	struct ast_sorcery_object_type *object_type;
-
-	/*! \brief Pointer to the object */
-	void *object;
-};
-
-/*! \brief Structure for registered object field */
-struct ast_sorcery_object_field {
-	/*! \brief Name of the field */
-	char name[MAX_OBJECT_FIELD];
-
-	/*! \brief The compiled name regex if name is a regex */
-	regex_t *name_regex;
-
-	/*! \brief Callback function for translation of a single value */
-	sorcery_field_handler handler;
-
-	/*! \brief Callback function for translation of multiple values */
-	sorcery_fields_handler multiple_handler;
-
-	/*! \brief Position of the field */
-	intptr_t args[];
-};
-
-/*! \brief Structure for an internal wizard instance */
-struct ast_sorcery_internal_wizard {
-	/*! \brief Wizard interface itself */
-	struct ast_sorcery_wizard callbacks;
-
-	/*! \brief Observers */
-	struct ao2_container *observers;
-};
-
-/*! \brief Structure for a wizard instance which operates on objects */
-struct ast_sorcery_object_wizard {
-	/*! \brief Wizard interface itself */
-	struct ast_sorcery_internal_wizard *wizard;
-
-	/*! \brief Unique data for the wizard */
-	void *data;
-
-	/*! \brief Wizard is acting as an object cache */
-	unsigned int caching:1;
-};
-
-/*! \brief Full structure for sorcery */
-struct ast_sorcery {
-	/*! \brief Container for known object types */
-	struct ao2_container *types;
-
-	/*! \brief Observers */
-	struct ao2_container *observers;
-
-	/*! \brief The name of the module owning this sorcery instance */
-	char module_name[0];
-};
-
-/*! \brief Structure for passing load/reload details */
-struct sorcery_load_details {
-	/*! \brief Sorcery structure in use */
-	const struct ast_sorcery *sorcery;
-
-	/*! \brief Type of object being loaded */
-	const char *type;
-
-	/*! \brief Whether this is a reload or not */
-	unsigned int reload:1;
-};
-
-/*! \brief Registered sorcery wizards */
-static struct ao2_container *wizards;
-
-/* The following 3 observer wrappers must name their
- * external observer 'callbacks' and it must be
- * the first member of the structure.  Common macros
- * and container callbacks depend on it.
- */
-
-/*! \brief A global observer wrapper */
-struct sorcery_global_observer {
-	const struct ast_sorcery_global_observer *callbacks;
-};
-
-/*! \brief An instance observer wrapper */
-struct sorcery_instance_observer {
-	const struct ast_sorcery_instance_observer *callbacks;
-};
-
-/*! \brief A wizard observer wrapper */
-struct sorcery_wizard_observer {
-	const struct ast_sorcery_wizard_observer *callbacks;
-};
-
-/*! \brief Registered global observers */
-struct ao2_container *observers;
-
-/*! \brief Registered sorcery instances */
-static struct ao2_container *instances;
-
-static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	int *field = (int *)(obj + args[0]);
-	return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
-}
-
-static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	unsigned int *field = (unsigned int *)(obj + args[0]);
-	return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
-}
-
-static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	double *field = (double *)(obj + args[0]);
-	return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
-}
-
-static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	ast_string_field *field = (const char **)(obj + args[0]);
-	return !(*buf = ast_strdup(*field)) ? -1 : 0;
-}
-
-static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	unsigned int *field = (unsigned int *)(obj + args[0]);
-	return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
-}
-
-static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
-	return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
-}
-
-static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	char *field = (char *)(obj + args[0]);
-	return !(*buf = ast_strdup(field)) ? -1 : 0;
-}
-
-static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
-{
-	struct ast_str *codec_buf = ast_str_alloca(64);
-	struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]);
-	return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf)));
-}
-
-static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
-{
-	switch(type) {
-	case OPT_BOOL_T: return bool_handler_fn;
-	case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
-	case OPT_CODEC_T: return codec_handler_fn;
-	case OPT_DOUBLE_T: return double_handler_fn;
-	case OPT_INT_T: return int_handler_fn;
-	case OPT_SOCKADDR_T: return sockaddr_handler_fn;
-	case OPT_STRINGFIELD_T: return stringfield_handler_fn;
-	case OPT_UINT_T: return uint_handler_fn;
-
-	default:
-	case OPT_CUSTOM_T: return NULL;
-	}
-
-	return NULL;
-}
-
-/*! \brief Hashing function for sorcery wizards */
-static int sorcery_wizard_hash(const void *obj, const int flags)
-{
-	const struct ast_sorcery_internal_wizard *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->callbacks.name;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! \brief Comparator function for sorcery wizards */
-static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_internal_wizard *object_left = obj;
-	const struct ast_sorcery_internal_wizard *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->callbacks.name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->callbacks.name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-/*! \brief Hashing function for sorcery wizards */
-static int object_type_field_hash(const void *obj, const int flags)
-{
-	const struct ast_sorcery_object_field *object_field;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object_field = obj;
-		key = object_field->name;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int object_type_field_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_field *field_left = obj;
-	const struct ast_sorcery_object_field *field_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = field_right->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(field_left->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(field_left->name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-/*! \brief Cleanup function */
-static void sorcery_exit(void)
-{
-	ast_threadpool_shutdown(threadpool);
-	threadpool = NULL;
-}
-
-/*! \brief Cleanup function for graceful shutdowns */
-static void sorcery_cleanup(void)
-{
-	ao2_cleanup(wizards);
-	wizards = NULL;
-	ao2_cleanup(observers);
-	observers = NULL;
-	ao2_cleanup(instances);
-	instances = NULL;
-}
-
-/*! \brief Compare function for sorcery instances */
-static int sorcery_instance_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery *object_left = obj;
-	const struct ast_sorcery *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->module_name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->module_name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-/*! \brief Hashing function for sorcery instances */
-static int sorcery_instance_hash(const void *obj, const int flags)
-{
-	const struct ast_sorcery *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->module_name;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-int ast_sorcery_init(void)
-{
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.auto_increment = 1,
-		.max_size = 0,
-		.idle_timeout = 60,
-		.initial_size = 0,
-	};
-	ast_assert(wizards == NULL);
-
-	if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
-		threadpool = NULL;
-		return -1;
-	}
-
-	if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
-		ast_threadpool_shutdown(threadpool);
-		return -1;
-	}
-
-	observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
-	if (!observers) {
-		sorcery_cleanup();
-		sorcery_exit();
-		return -1;
-	}
-
-	instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
-		sorcery_instance_hash, sorcery_instance_cmp);
-	if (!instances) {
-		sorcery_cleanup();
-		sorcery_exit();
-		return -1;
-	}
-
-	ast_register_cleanup(sorcery_cleanup);
-	ast_register_atexit(sorcery_exit);
-
-	return 0;
-}
-
-static void sorcery_internal_wizard_destructor(void *obj)
-{
-	struct ast_sorcery_internal_wizard *wizard = obj;
-
-	ao2_cleanup(wizard->observers);
-}
-
-int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
-{
-	struct ast_sorcery_internal_wizard *wizard;
-	int res = -1;
-
-	ast_assert(!ast_strlen_zero(interface->name));
-
-	ao2_lock(wizards);
-
-	if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
-		ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
-			interface->name);
-		goto done;
-	}
-
-	if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
-		goto done;
-	}
-
-	wizard->callbacks = *interface;
-	wizard->callbacks.module = module;
-
-	wizard->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
-	if (!wizard->observers) {
-		goto done;
-	}
-
-	ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
-	res = 0;
-
-	ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
-
-	NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
-		interface->name, interface);
-
-done:
-	ao2_cleanup(wizard);
-	ao2_unlock(wizards);
-
-	return res;
-}
-
-int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
-{
-	struct ast_sorcery_internal_wizard *wizard =
-		interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
-
-	if (wizard) {
-		NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
-		ao2_unlink(wizards, wizard);
-		ao2_ref(wizard, -1);
-		ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-/*! \brief Internal callback function for removing a generic observer */
-static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
-{
-	const struct sorcery_global_observer *observer = obj;
-
-	return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
-{
-	struct sorcery_global_observer *cb;
-
-	cb = ao2_alloc(sizeof(*cb), NULL);
-	if (!cb) {
-		return -1;
-	}
-
-	cb->callbacks = callbacks;
-	ao2_link(observers, cb);
-	ao2_ref(cb, -1);
-
-	return 0;
-}
-
-void ast_sorcery_global_observer_remove(
-	const struct ast_sorcery_global_observer *callbacks)
-{
-	ao2_callback(observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
-}
-
-int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
-	const struct ast_sorcery_instance_observer *callbacks)
-{
-	struct sorcery_instance_observer *cb;
-
-	cb = ao2_alloc(sizeof(*cb), NULL);
-	if (!cb) {
-		return -1;
-	}
-
-	cb->callbacks = callbacks;
-	ao2_link(sorcery->observers, cb);
-	ao2_ref(cb, -1);
-
-	return 0;
-}
-
-void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
-	const struct ast_sorcery_instance_observer *callbacks)
-{
-	ao2_callback(sorcery->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
-}
-
-int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface,
-	const struct ast_sorcery_wizard_observer *callbacks)
-{
-	RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
-		interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
-			ao2_cleanup);
-
-	if (wizard) {
-		struct sorcery_wizard_observer *cb;
-
-		cb = ao2_alloc(sizeof(*cb), NULL);
-		if (!cb) {
-			return -1;
-		}
-
-		cb->callbacks = callbacks;
-		ao2_link(wizard->observers, cb);
-		ao2_ref(cb, -1);
-
-		return 0;
-	}
-
-	return -1;
-}
-
-void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface,
-	const struct ast_sorcery_wizard_observer *callbacks)
-{
-	RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
-		interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
-			ao2_cleanup);
-
-	if (wizard) {
-		ao2_callback(wizard->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
-	}
-}
-
-/*! \brief Destructor called when sorcery structure is destroyed */
-static void sorcery_destructor(void *obj)
-{
-	struct ast_sorcery *sorcery = obj;
-
-	if (sorcery->observers) {
-		NOTIFY_GLOBAL_OBSERVERS(observers, instance_destroying, sorcery->module_name, sorcery);
-	}
-	ao2_cleanup(sorcery->observers);
-	ao2_cleanup(sorcery->types);
-}
-
-/*! \brief Hashing function for sorcery types */
-static int sorcery_type_hash(const void *obj, const int flags)
-{
-	const struct ast_sorcery_object_type *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->name;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! \brief Comparator function for sorcery types */
-static int sorcery_type_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type *object_left = obj;
-	const struct ast_sorcery_object_type *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(object_left->name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-struct ast_sorcery *__ast_sorcery_open(const char *module_name)
-{
-	struct ast_sorcery *sorcery;
-
-	ast_assert(module_name != NULL);
-
-	ao2_wrlock(instances);
-	if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
-		goto done;
-	}
-
-	if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
-		goto done;
-	}
-
-	if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
-		ao2_ref(sorcery, -1);
-		sorcery = NULL;
-		goto done;
-	}
-
-	if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
-		ao2_ref(sorcery, -1);
-		sorcery = NULL;
-		goto done;
-	}
-
-	strcpy(sorcery->module_name, module_name); /* Safe */
-
-	if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
-		ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
-		ao2_cleanup(sorcery);
-		sorcery = NULL;
-		goto done;
-	}
-
-	ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
-
-	NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
-
-done:
-	ao2_unlock(instances);
-	return sorcery;
-}
-
-/*! \brief Search function for sorcery instances */
-struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
-{
-	return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
-}
-
-/*! \brief Destructor function for object types */
-static void sorcery_object_type_destructor(void *obj)
-{
-	struct ast_sorcery_object_type *object_type = obj;
-
-	ao2_cleanup(object_type->wizards);
-	ao2_cleanup(object_type->fields);
-	ao2_cleanup(object_type->observers);
-
-	if (object_type->info) {
-		aco_info_destroy(object_type->info);
-		ast_free(object_type->info);
-	}
-
-	ast_free(object_type->file);
-
-	ast_taskprocessor_unreference(object_type->serializer);
-}
-
-/*! \brief Internal function which allocates an object type structure */
-static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
-{
-	struct ast_sorcery_object_type *object_type;
-	char uuid[AST_UUID_STR_LEN];
-
-	if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
-		return NULL;
-	}
-
-	/* Order matters for object wizards */
-	if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, OBJECT_FIELD_BUCKETS,
-					object_type_field_hash, object_type_field_cmp))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
-		ao2_ref(object_type, -1);
-		return NULL;
-	}
-
-	object_type->info->files[0] = object_type->file;
-	object_type->info->files[1] = NULL;
-	object_type->info->module = module;
-
-	ast_copy_string(object_type->name, type, sizeof(object_type->name));
-
-	return object_type;
-}
-
-/*! \brief Object wizard destructor */
-static void sorcery_object_wizard_destructor(void *obj)
-{
-	struct ast_sorcery_object_wizard *object_wizard = obj;
-
-	if (object_wizard->data) {
-		object_wizard->wizard->callbacks.close(object_wizard->data);
-	}
-
-	if (object_wizard->wizard) {
-		ast_module_unref(object_wizard->wizard->callbacks.module);
-	}
-
-	ao2_cleanup(object_wizard->wizard);
-}
-
-/*! \brief Internal function which creates an object type and adds a wizard mapping */
-enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
-		const char *type, const char *module, const char *name, const char *data, unsigned int caching)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
-	int created = 0;
-
-	if (!wizard || !object_wizard) {
-		return AST_SORCERY_APPLY_FAIL;
-	}
-
-	if (!object_type) {
-		if (!(object_type = sorcery_object_type_alloc(type, module))) {
-			return AST_SORCERY_APPLY_FAIL;
-		}
-		created = 1;
-	}
-
-	if (!created) {
-		struct ast_sorcery_wizard *found;
-
-		found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT);
-		if (found) {
-			ast_debug(1, "Wizard %s already applied to object type %s\n",
-					wizard->callbacks.name, object_type->name);
-			ao2_cleanup(found);
-			return AST_SORCERY_APPLY_DUPLICATE;
-		}
-	}
-
-	if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
-		return AST_SORCERY_APPLY_FAIL;
-	}
-
-	ast_module_ref(wizard->callbacks.module);
-
-	object_wizard->wizard = ao2_bump(wizard);
-	object_wizard->caching = caching;
-
-	ao2_link(object_type->wizards, object_wizard);
-
-	if (created) {
-		ao2_link(sorcery->types, object_type);
-	}
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
-		sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
-
-	return AST_SORCERY_APPLY_SUCCESS;
-}
-
-enum ast_sorcery_apply_result  __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
-{
-	struct ast_flags flags = { 0 };
-	struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
-	struct ast_variable *mapping;
-	int res = AST_SORCERY_APPLY_SUCCESS;
-
-	if (!config) {
-		return AST_SORCERY_APPLY_NO_CONFIGURATION;
-	}
-
-	if (config == CONFIG_STATUS_FILEINVALID) {
-		return AST_SORCERY_APPLY_FAIL;
-	}
-
-	for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
-		RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
-		RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
-		char *options = mapping_name;
-		char *type = strsep(&options, "/");
-		char *data = mapping_value;
-		char *wizard = strsep(&data, ",");
-		unsigned int caching = 0;
-
-		/* If no object type or wizard exists just skip, nothing we can do */
-		if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
-			continue;
-		}
-
-		/* If the wizard is configured as a cache treat it as such */
-		if (!ast_strlen_zero(options) && strstr(options, "cache")) {
-			caching = 1;
-		}
-
-		/* Any error immediately causes us to stop */
-		if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
-			res = AST_SORCERY_APPLY_FAIL;
-			break;
-		}
-	}
-
-	ast_config_destroy(config);
-
-	return res;
-}
-
-enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-
-	/* Defaults can not be added if any existing mapping exists */
-	if (object_type) {
-		return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
-	}
-
-	return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
-}
-
-static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	return ast_sorcery_object_set_extended(obj, var->name, var->value);
-}
-
-static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
-{
-	const struct ast_sorcery_object_details *details = obj;
-
-	if (details->object->extended) {
-		*fields = ast_variables_dup(details->object->extended);
-	} else {
-		*fields = NULL;
-	}
-
-	return 0;
-}
-
-int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, unsigned int hidden, unsigned int reloadable, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-
-	if (!object_type || object_type->type.item_alloc) {
-		return -1;
-	}
-
-	object_type->type.name = object_type->name;
-	object_type->type.type = ACO_ITEM;
-	object_type->type.category = ".?";
-	object_type->type.item_alloc = alloc;
-	object_type->type.hidden = hidden;
-
-	object_type->reloadable = reloadable;
-	object_type->transform = transform;
-	object_type->apply = apply;
-	object_type->file->types[0] = &object_type->type;
-	object_type->file->types[1] = NULL;
-
-	if (aco_info_init(object_type->info)) {
-		return -1;
-	}
-
-	if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
-		return -1;
-	}
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
-		sorcery->module_name, sorcery, type);
-
-	return 0;
-}
-
-void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-
-	if (!object_type) {
-		return;
-	}
-
-	object_type->copy = copy;
-}
-
-void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-
-	if (!object_type) {
-		return;
-	}
-
-	object_type->diff = diff;
-}
-
-static void sorcery_object_field_destructor(void *obj)
-{
-	struct ast_sorcery_object_field *object_field = obj;
-
-	if (object_field->name_regex) {
-		regfree(object_field->name_regex);
-	}
-}
-
-int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
-{
-#define MAX_REGEX_ERROR_LEN 128
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
-	int rc;
-
-	if (!object_type || !object_type->type.item_alloc || !config_handler
-		|| !(object_field = ao2_alloc(sizeof(*object_field), sorcery_object_field_destructor))) {
-		return -1;
-	}
-
-	ast_copy_string(object_field->name, regex, sizeof(object_field->name));
-	object_field->multiple_handler = sorcery_handler;
-
-	if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
-		return -1;
-	}
-
-	if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | REG_NOSUB))) {
-		char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
-		regerror(rc, object_field->name_regex, regerr, MAX_REGEX_ERROR_LEN);
-		ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n", regex, regerr);
-		return -1;
-	}
-
-	ao2_link(object_type->fields, object_field);
-	__aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
-
-	return 0;
-}
-
-int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
-					aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, unsigned int alias, size_t argc, ...)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
-	int pos;
-	va_list args;
-
-	if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
-		return -1;
-	}
-
-	if (!sorcery_handler) {
-		sorcery_handler = sorcery_field_default_handler(opt_type);
-	}
-
-	if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
-		return -1;
-	}
-
-	ast_copy_string(object_field->name, name, sizeof(object_field->name));
-	object_field->handler = sorcery_handler;
-	object_field->multiple_handler = multiple_handler;
-
-	va_start(args, argc);
-	for (pos = 0; pos < argc; pos++) {
-		object_field->args[pos] = va_arg(args, size_t);
-	}
-	va_end(args);
-
-	if (!alias) {
-		ao2_link(object_type->fields, object_field);
-	}
-
-	/* TODO: Improve this hack */
-	if (!argc) {
-		__aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
-	} else if (argc == 1) {
-		__aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
-			object_field->args[0]);
-	} else if (argc == 2) {
-		__aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
-			object_field->args[0], object_field->args[1]);
-	} else if (argc == 3) {
-		__aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
-			object_field->args[0], object_field->args[1], object_field->args[2]);
-	} else {
-		ast_assert(0); /* The hack... she does us no good for this */
-	}
-
-	return 0;
-}
-
-/*! \brief Retrieves whether or not the type is reloadable */
-static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type,
-		 ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	return object_type && object_type->reloadable;
-}
-
-static int sorcery_wizard_load(void *obj, void *arg, int flags)
-{
-	struct ast_sorcery_object_wizard *wizard = obj;
-	struct sorcery_load_details *details = arg;
-	void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
-
-	if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
-		ast_log(LOG_NOTICE, "Type '%s' is not reloadable, "
-			"maintaining previous values\n", details->type);
-		return 0;
-	}
-
-	load = !details->reload ? wizard->wizard->callbacks.load : wizard->wizard->callbacks.reload;
-
-	if (load) {
-		NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
-			wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
-
-		load(wizard->data, details->sorcery, details->type);
-
-		NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
-			wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
-	}
-
-	return 0;
-}
-
-/*! \brief Destructor for observer invocation */
-static void sorcery_observer_invocation_destroy(void *obj)
-{
-	struct sorcery_observer_invocation *invocation = obj;
-
-	ao2_cleanup(invocation->object_type);
-	ao2_cleanup(invocation->object);
-}
-
-/*! \brief Allocator function for observer invocation */
-static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
-{
-	struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
-
-	if (!invocation) {
-		return NULL;
-	}
-
-	ao2_ref(object_type, +1);
-	invocation->object_type = object_type;
-
-	if (object) {
-		ao2_ref(object, +1);
-		invocation->object = object;
-	}
-
-	return invocation;
-}
-
-/*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
-static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type_observer *observer = obj;
-
-	if (observer->callbacks->loaded) {
-		observer->callbacks->loaded(arg);
-	}
-
-	return 0;
-}
-
-/*! \brief Internal callback function which notifies observers that an object type has been loaded */
-static int sorcery_observers_notify_loaded(void *data)
-{
-	struct sorcery_observer_invocation *invocation = data;
-
-	ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
-	ao2_cleanup(invocation);
-
-	return 0;
-}
-
-static int sorcery_object_load(void *obj, void *arg, int flags)
-{
-	struct ast_sorcery_object_type *type = obj;
-	struct sorcery_load_details *details = arg;
-
-	details->type = type->name;
-
-	NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
-		details->sorcery->module_name, details->sorcery, type->name, details->reload);
-
-	ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details);
-
-	if (ao2_container_count(type->observers)) {
-		struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(type, NULL);
-
-		if (invocation && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded, invocation)) {
-			ao2_cleanup(invocation);
-		}
-	}
-
-	NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
-		details->sorcery->module_name, details->sorcery, type->name, details->reload);
-
-	return 0;
-}
-
-void ast_sorcery_load(const struct ast_sorcery *sorcery)
-{
-	struct sorcery_load_details details = {
-		.sorcery = sorcery,
-		.reload = 0,
-	};
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
-		sorcery->module_name, sorcery, 0);
-
-	ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
-		sorcery->module_name, sorcery, 0);
-}
-
-void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	struct sorcery_load_details details = {
-		.sorcery = sorcery,
-		.reload = 0,
-	};
-
-	if (!object_type) {
-		return;
-	}
-
-	sorcery_object_load(object_type, &details, 0);
-}
-
-void ast_sorcery_reload(const struct ast_sorcery *sorcery)
-{
-	struct sorcery_load_details details = {
-		.sorcery = sorcery,
-		.reload = 1,
-	};
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
-		sorcery->module_name, sorcery, 1);
-
-	ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
-
-	NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
-		sorcery->module_name, sorcery, 1);
-
-}
-
-void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	struct sorcery_load_details details = {
-		.sorcery = sorcery,
-		.reload = 1,
-	};
-
-	if (!object_type) {
-		return;
-	}
-
-	sorcery_object_load(object_type, &details, 0);
-}
-
-void ast_sorcery_ref(struct ast_sorcery *sorcery)
-{
-	ao2_ref(sorcery, +1);
-}
-
-static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
-{
-	struct ast_variable *tmp = NULL;
-	char *buf = NULL;
-
-	if (!object_field->handler) {
-		return NULL;
-	}
-
-	if (!(object_field->handler(object, object_field->args, &buf))) {
-		tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
-	}
-	ast_free(buf);
-
-	return tmp;
-}
-
-static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
-{
-	struct ast_variable *tmp = NULL;
-
-	if (!object_field->multiple_handler) {
-		return NULL;
-	}
-
-	if (object_field->multiple_handler(object, &tmp)) {
-		ast_variables_destroy(tmp);
-		tmp = NULL;
-	}
-
-	return tmp;
-}
-
-struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
-	const void *object,	enum ast_sorcery_field_handler_flags flags)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	struct ao2_iterator i;
-	struct ast_sorcery_object_field *object_field;
-	struct ast_variable *head = NULL;
-	struct ast_variable *tail = NULL;
-
-	if (!object_type) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(object_type->fields, 0);
-
-	for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
-		struct ast_variable *tmp;
-
-		switch (flags) {
-		case AST_HANDLER_PREFER_LIST:
-			if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
-				(tmp = get_single_field_as_var_list(object, object_field))) {
-				break;
-			}
-			continue;
-		case AST_HANDLER_PREFER_STRING:
-			if ((tmp = get_single_field_as_var_list(object, object_field)) ||
-				(tmp = get_multiple_fields_as_var_list(object, object_field))) {
-				break;
-			}
-			continue;
-		case AST_HANDLER_ONLY_LIST:
-			if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
-				break;
-			}
-			continue;
-		case AST_HANDLER_ONLY_STRING:
-			if ((tmp = get_single_field_as_var_list(object, object_field))) {
-				break;
-			}
-			continue;
-		default:
-			continue;
-		}
-
-		tail = ast_variable_list_append_hint(&head, tail, tmp);
-	}
-
-	ao2_iterator_destroy(&i);
-
-	return head;
-}
-
-struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	struct ao2_iterator i;
-	struct ast_sorcery_object_field *object_field;
-	struct ast_json *json = ast_json_object_create();
-	int res = 0;
-
-	if (!object_type || !json) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(object_type->fields, 0);
-
-	for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
-		if (object_field->multiple_handler) {
-			struct ast_variable *tmp = NULL;
-			struct ast_variable *field;
-
-			if ((res = object_field->multiple_handler(object, &tmp))) {
-				ast_variables_destroy(tmp);
-				ao2_ref(object_field, -1);
-				break;
-			}
-
-			for (field = tmp; field; field = field->next) {
-				struct ast_json *value = ast_json_string_create(field->value);
-
-				if (!value || ast_json_object_set(json, field->name, value)) {
-					res = -1;
-					break;
-				}
-			}
-
-			ast_variables_destroy(tmp);
-		} else if (object_field->handler) {
-			char *buf = NULL;
-			struct ast_json *value = NULL;
-
-			if ((res = object_field->handler(object, object_field->args, &buf))
-				|| !(value = ast_json_string_create(buf))
-				|| ast_json_object_set(json, object_field->name, value)) {
-				res = -1;
-			}
-
-			ast_free(buf);
-		} else {
-			continue;
-		}
-	}
-
-	ao2_iterator_destroy(&i);
-
-	/* If any error occurs we destroy the JSON object so a partial objectset is not returned */
-	if (res) {
-		ast_json_unref(json);
-		json = NULL;
-	}
-
-	return json;
-}
-
-int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
-	struct ast_variable *field;
-	int res = 0;
-
-	if (!object_type) {
-		return -1;
-	}
-
-	if (object_type->transform && (transformed = object_type->transform(objectset))) {
-		field = transformed;
-	} else {
-		field = objectset;
-	}
-
-	for (; field; field = field->next) {
-		if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
-			break;
-		}
-	}
-
-	if (!res && object_type->apply) {
-		res = object_type->apply(sorcery, object);
-	}
-
-	return res;
-}
-
-int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
-{
-	const struct ast_variable *field;
-	int res = 0;
-
-	*changes = NULL;
-
-	/* Unless the ast_variable list changes when examined... it can't differ from itself */
-	if (original == modified) {
-		return 0;
-	}
-
-	for (field = modified; field; field = field->next) {
-		const char *old_value = ast_variable_find_in_list(original, field->name);
-
-		if (!old_value || strcmp(old_value, field->value)) {
-			struct ast_variable *tmp;
-
-			if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
-				res = -1;
-				break;
-			}
-
-			tmp->next = *changes;
-			*changes = tmp;
-		}
-	}
-
-	/* If an error occurred do not return a partial changeset */
-	if (res) {
-		ast_variables_destroy(*changes);
-		*changes = NULL;
-	}
-
-	return res;
-}
-
-static void sorcery_object_destructor(void *object)
-{
-	struct ast_sorcery_object_details *details = object;
-
-	if (details->object->destructor) {
-		details->object->destructor(object);
-	}
-
-	ast_variables_destroy(details->object->extended);
-	ast_free(details->object->id);
-}
-
-void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
-{
-	void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	struct ast_sorcery_object_details *details = object;
-
-	if (!object) {
-		return NULL;
-	}
-
-	details->object = object + size;
-	details->object->destructor = destructor;
-
-	return object;
-}
-
-void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	struct ast_sorcery_object_details *details;
-
-	if (!object_type || !object_type->type.item_alloc ||
-		!(details = object_type->type.item_alloc(id))) {
-		return NULL;
-	}
-
-	if (ast_strlen_zero(id)) {
-		char uuid[AST_UUID_STR_LEN];
-
-		ast_uuid_generate_str(uuid, sizeof(uuid));
-		details->object->id = ast_strdup(uuid);
-	} else {
-		details->object->id = ast_strdup(id);
-	}
-
-	ast_copy_string(details->object->type, type, sizeof(details->object->type));
-
-	if (aco_set_defaults(&object_type->type, id, details)) {
-		ao2_ref(details, -1);
-		return NULL;
-	}
-
-	return details;
-}
-
-void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
-	RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
-	int res = 0;
-
-	if (!copy) {
-		return NULL;
-	} else if (object_type->copy) {
-		res = object_type->copy(object, copy);
-	} else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
-		res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
-	} else {
-		/* No native copy available and could not create an objectset, this copy has failed */
-		res = -1;
-	}
-
-	if (res) {
-		ao2_cleanup(copy);
-		copy = NULL;
-	}
-
-	return copy;
-}
-
-int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
-
-	*changes = NULL;
-
-	if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
-		return -1;
-	}
-
-	if (original == modified) {
-		return 0;
-	} else if (!object_type->diff) {
-		RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
-		RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
-
-		objectset1 = ast_sorcery_objectset_create(sorcery, original);
-		objectset2 = ast_sorcery_objectset_create(sorcery, modified);
-
-		return ast_sorcery_changeset_create(objectset1, objectset2, changes);
-	} else {
-		return object_type->diff(original, modified, changes);
-	}
-}
-
-/*! \brief Structure used when calling create, update, or delete */
-struct sorcery_details {
-	/*! \brief Pointer to the sorcery instance */
-	const struct ast_sorcery *sorcery;
-	/*! \brief Pointer to the object itself */
-	void *obj;
-};
-
-/*! \brief Internal function used to create an object in caching wizards */
-static int sorcery_cache_create(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_wizard *object_wizard = obj;
-	const struct sorcery_details *details = arg;
-
-	if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
-		return 0;
-	}
-
-	object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
-
-	return 0;
-}
-
-void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	void *object = NULL;
-	struct ao2_iterator i;
-	struct ast_sorcery_object_wizard *wizard;
-	unsigned int cached = 0;
-
-	if (!object_type || ast_strlen_zero(id)) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(object_type->wizards, 0);
-	for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
-		if (wizard->wizard->callbacks.retrieve_id &&
-			!(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
-			continue;
-		}
-
-		cached = wizard->caching;
-
-		ao2_ref(wizard, -1);
-		break;
-	}
-	ao2_iterator_destroy(&i);
-
-	if (!cached && object) {
-		ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
-	}
-
-	return object;
-}
-
-void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	void *object = NULL;
-	struct ao2_iterator i;
-	struct ast_sorcery_object_wizard *wizard;
-	unsigned int cached = 0;
-
-	if (!object_type) {
-		return NULL;
-	}
-
-	/* If returning multiple objects create a container to store them in */
-	if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
-		if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
-			return NULL;
-		}
-	}
-
-	/* Inquire with the available wizards for retrieval */
-	i = ao2_iterator_init(object_type->wizards, 0);
-	for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
-		if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
-			if (wizard->wizard->callbacks.retrieve_multiple) {
-				wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
-			}
-		} else if (fields && wizard->wizard->callbacks.retrieve_fields) {
-			if (wizard->wizard->callbacks.retrieve_fields) {
-				object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
-			}
-		}
-
-		if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
-			continue;
-		}
-
-		cached = wizard->caching;
-
-		ao2_ref(wizard, -1);
-		break;
-	}
-	ao2_iterator_destroy(&i);
-
-	/* If we are returning a single object and it came from a non-cache source create it in any caches */
-	if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
-		ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
-	}
-
-	return object;
-}
-
-struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	struct ao2_container *objects;
-	struct ao2_iterator i;
-	struct ast_sorcery_object_wizard *wizard;
-
-	if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(object_type->wizards, 0);
-	for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
-		if (!wizard->wizard->callbacks.retrieve_regex) {
-			continue;
-		}
-
-		wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
-	}
-	ao2_iterator_destroy(&i);
-
-	return objects;
-}
-
-/*! \brief Internal function which returns if the wizard has created the object */
-static int sorcery_wizard_create(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_wizard *object_wizard = obj;
-	const struct sorcery_details *details = arg;
-
-	if (!object_wizard->wizard->callbacks.create) {
-		ast_assert(0);
-		ast_log(LOG_ERROR, "Sorcery wizard '%s' doesn't contain a 'create' virtual function.\n",
-			object_wizard->wizard->callbacks.name);
-		return 0;
-	}
-	return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Internal callback function which notifies an individual observer that an object has been created */
-static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type_observer *observer = obj;
-
-	if (observer->callbacks->created) {
-		observer->callbacks->created(arg);
-	}
-
-	return 0;
-}
-
-/*! \brief Internal callback function which notifies observers that an object has been created */
-static int sorcery_observers_notify_create(void *data)
-{
-	struct sorcery_observer_invocation *invocation = data;
-
-	ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
-	ao2_cleanup(invocation);
-
-	return 0;
-}
-
-int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
-	struct sorcery_details sdetails = {
-		.sorcery = sorcery,
-		.obj = object,
-	};
-
-	if (!object_type) {
-		return -1;
-	}
-
-	if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_create, &sdetails)) &&
-		ao2_container_count(object_type->observers)) {
-		struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
-
-		if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
-			ao2_cleanup(invocation);
-		}
-	}
-
-	return object_wizard ? 0 : -1;
-}
-
-/*! \brief Internal callback function which notifies an individual observer that an object has been updated */
-static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type_observer *observer = obj;
-
-	if (observer->callbacks->updated) {
-		observer->callbacks->updated(arg);
-	}
-
-	return 0;
-}
-
-/*! \brief Internal callback function which notifies observers that an object has been updated */
-static int sorcery_observers_notify_update(void *data)
-{
-	struct sorcery_observer_invocation *invocation = data;
-
-	ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
-	ao2_cleanup(invocation);
-
-	return 0;
-}
-
-/*! \brief Internal function which returns if a wizard has updated the object */
-static int sorcery_wizard_update(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_wizard *object_wizard = obj;
-	const struct sorcery_details *details = arg;
-
-	return (object_wizard->wizard->callbacks.update && !object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) &&
-		!object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
-	struct sorcery_details sdetails = {
-		.sorcery = sorcery,
-		.obj = object,
-	};
-
-	if (!object_type) {
-		return -1;
-	}
-
-	if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_update, &sdetails)) &&
-		ao2_container_count(object_type->observers)) {
-		struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
-
-		if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
-			ao2_cleanup(invocation);
-		}
-	}
-
-	return object_wizard ? 0 : -1;
-}
-
-/*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
-static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type_observer *observer = obj;
-
-	if (observer->callbacks->deleted) {
-		observer->callbacks->deleted(arg);
-	}
-
-	return 0;
-}
-
-/*! \brief Internal callback function which notifies observers that an object has been deleted */
-static int sorcery_observers_notify_delete(void *data)
-{
-	struct sorcery_observer_invocation *invocation = data;
-
-	ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
-	ao2_cleanup(invocation);
-
-	return 0;
-}
-
-/*! \brief Internal function which returns if a wizard has deleted the object */
-static int sorcery_wizard_delete(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_wizard *object_wizard = obj;
-	const struct sorcery_details *details = arg;
-
-	return (object_wizard->wizard->callbacks.delete && !object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) &&
-		!object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
-	struct sorcery_details sdetails = {
-		.sorcery = sorcery,
-		.obj = object,
-	};
-
-	if (!object_type) {
-		return -1;
-	}
-
-	if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_delete, &sdetails)) &&
-		ao2_container_count(object_type->observers)) {
-		struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
-
-		if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
-			ao2_cleanup(invocation);
-		}
-	}
-
-	return object_wizard ? 0 : -1;
-}
-
-void ast_sorcery_unref(struct ast_sorcery *sorcery)
-{
-	if (sorcery) {
-		/* One ref for what we just released, the other for the instances container. */
-		ao2_wrlock(instances);
-		if (ao2_ref(sorcery, -1) == 2) {
-			ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
-		}
-		ao2_unlock(instances);
-	}
-}
-
-const char *ast_sorcery_object_get_id(const void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	return details->object->id;
-}
-
-const char *ast_sorcery_object_get_type(const void *object)
-{
-	const struct ast_sorcery_object_details *details = object;
-	return details->object->type;
-}
-
-const char *ast_sorcery_object_get_extended(const void *object, const char *name)
-{
-	const struct ast_sorcery_object_details *details = object;
-	struct ast_variable *field;
-
-	for (field = details->object->extended; field; field = field->next) {
-		if (!strcmp(field->name + 1, name)) {
-			return field->value;
-		}
-	}
-
-	return NULL;
-}
-
-int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
-{
-	RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
-	struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
-	const struct ast_sorcery_object_details *details = object;
-
-	if (!extended) {
-		return -1;
-	}
-
-	for (field = details->object->extended; field; previous = field, field = field->next) {
-		if (!strcmp(field->name, name)) {
-			if (previous) {
-				previous->next = field->next;
-			} else {
-				details->object->extended = field->next;
-			}
-			field->next = NULL;
-			break;
-		}
-	}
-
-	extended->next = details->object->extended;
-	details->object->extended = extended;
-
-	return 0;
-}
-
-int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
-	struct ast_sorcery_object_type_observer *observer;
-	int res;
-
-	if (!object_type || !callbacks) {
-		return -1;
-	}
-
-	if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
-		return -1;
-	}
-
-	observer->callbacks = callbacks;
-	res = 0;
-	if (!ao2_link(object_type->observers, observer)) {
-		res = -1;
-	}
-	ao2_ref(observer, -1);
-
-	return res;
-}
-
-/*! \brief Internal callback function for removing an observer */
-static int sorcery_observer_remove(void *obj, void *arg, int flags)
-{
-	const struct ast_sorcery_object_type_observer *observer = obj;
-
-	return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
-{
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
-	struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
-
-	if (!sorcery) {
-		return;
-	}
-	object_type = ao2_find(sorcery->types, type, OBJ_KEY);
-	if (!object_type) {
-		return;
-	}
-
-	ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
-		sorcery_observer_remove, cbs);
-}
-
-int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
-{
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = ast_sorcery_object_get_id(arg);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
-{
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = ast_sorcery_object_get_id(arg);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
-			cmp = CMP_MATCH | CMP_STOP;
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
-			cmp = CMP_MATCH;
-		}
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-int ast_sorcery_object_id_hash(const void *obj, int flags) {
-	if (flags & OBJ_SEARCH_OBJECT) {
-		return ast_str_hash(ast_sorcery_object_get_id(obj));
-	} else if (flags & OBJ_SEARCH_KEY) {
-		return ast_str_hash(obj);
-	}
-	return -1;
-}
-
-struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
-		const char *type)
-{
-	return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
-}
-
-static int is_registered_cb(void *obj, void *arg, int flags)
-{
-	struct ast_sorcery_object_field *object_field = obj;
-	char *name = arg;
-	int rc = 0;
-
-	if (object_field->name_regex
-		&& !regexec(object_field->name_regex, name, 0, NULL, 0)) {
-		rc = CMP_MATCH | CMP_STOP;
-	}
-
-	return rc;
-}
-
-int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
-		const char *field_name)
-{
-	struct ast_sorcery_object_field *object_field;
-	int res = 1;
-
-	ast_assert(object_type != NULL);
-
-	object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
-
-	if (!object_field) {
-		object_field = ao2_callback(object_type->fields, 0, is_registered_cb, (char *)field_name);
-	}
-
-	if (!object_field) {
-		res = 0;
-	}
-
-	ao2_cleanup(object_field);
-	return res;
-}
diff --git a/main/sounds_index.c b/main/sounds_index.c
deleted file mode 100644
index 8ca5967..0000000
--- a/main/sounds_index.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Sound file format and description index.
- */
-
-#include "asterisk.h"
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-#include "asterisk/utils.h"
-#include "asterisk/lock.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/paths.h"	/* use ast_config_AST_DATA_DIR */
-#include "asterisk/media_index.h"
-#include "asterisk/sounds_index.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/_private.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/stasis_system.h"
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*! \brief The number of buckets to be used for storing language-keyed objects */
-#define LANGUAGE_BUCKETS 7
-
-static struct ast_media_index *sounds_index;
-
-static struct stasis_message_router *sounds_system_router;
-
-/*! \brief Get the languages in which sound files are available */
-static struct ao2_container *get_languages(void)
-{
-	RAII_VAR(struct ao2_container *, lang_dirs, NULL, ao2_cleanup);
-	struct dirent* dent;
-	DIR* srcdir;
-	RAII_VAR(struct ast_str *, media_dir, ast_str_create(64), ast_free);
-	RAII_VAR(struct ast_str *, variant_dir, ast_str_create(64), ast_free);
-
-	lang_dirs = ast_str_container_alloc(LANGUAGE_BUCKETS);
-	if (!media_dir || !lang_dirs) {
-		return NULL;
-	}
-
-	ast_str_set(&media_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
-
-	srcdir = opendir(ast_str_buffer(media_dir));
-
-	if (srcdir == NULL) {
-		ast_log(LOG_ERROR, "Failed to open %s\n", ast_str_buffer(media_dir));
-		return NULL;
-	}
-
-	while((dent = readdir(srcdir)) != NULL) {
-		struct stat st;
-
-		if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
-			continue;
-		}
-
-		ast_str_reset(variant_dir);
-		ast_str_set(&variant_dir, 0, "%s/%s", ast_str_buffer(media_dir), dent->d_name);
-
-		if (stat(ast_str_buffer(variant_dir), &st) < 0) {
-			ast_log(LOG_ERROR, "Failed to stat %s\n", ast_str_buffer(variant_dir));
-			continue;
-		}
-
-		if (S_ISDIR(st.st_mode)) {
-			ast_str_container_add(lang_dirs, dent->d_name);
-		}
-	}
-
-	closedir(srcdir);
-	ao2_ref(lang_dirs, +1);
-	return lang_dirs;
-}
-
-/*! \brief Callback to process an individual language directory or subdirectory */
-static int update_index_cb(void *obj, void *arg, int flags)
-{
-	char *lang = obj;
-	struct ast_media_index *index = arg;
-
-	if (ast_media_index_update(index, lang)) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-AST_MUTEX_DEFINE_STATIC(reload_lock);
-
-int ast_sounds_reindex(void)
-{
-	RAII_VAR(struct ast_str *, sounds_dir, NULL, ast_free);
-	RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
-	RAII_VAR(char *, failed_index, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_media_index *, new_index, NULL, ao2_cleanup);
-	struct ast_media_index *old_index;
-
-	SCOPED_MUTEX(lock, &reload_lock);
-
-	old_index = sounds_index;
-	languages = get_languages();
-	sounds_dir = ast_str_create(64);
-
-	if (!languages || !sounds_dir) {
-		return -1;
-	}
-
-	ast_str_set(&sounds_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
-	new_index = ast_media_index_create(ast_str_buffer(sounds_dir));
-	if (!new_index) {
-		return -1;
-	}
-
-	failed_index = ao2_callback(languages, 0, update_index_cb, new_index);
-	if (failed_index) {
-		return -1;
-	}
-
-	ao2_ref(new_index, +1);
-	sounds_index = new_index;
-	ao2_cleanup(old_index);
-	return 0;
-}
-
-static int show_sounds_cb(void *obj, void *arg, int flags)
-{
-	char *name = obj;
-	struct ast_cli_args *a = arg;
-	ast_cli(a->fd, "%s\n", name);
-	return 0;
-}
-
-static int show_sound_info_cb(void *obj, void *arg, int flags)
-{
-	char *language = obj;
-	struct ast_cli_args *a = arg;
-	struct ast_format *format;
-	int formats_shown = 0;
-	RAII_VAR(struct ast_media_index *, local_index, ast_sounds_get_index(), ao2_cleanup);
-	struct ast_format_cap *cap;
-	const char *description = ast_media_get_description(local_index, a->argv[3], language);
-
-	ast_cli(a->fd, "  Language %s:\n", language);
-	if (!ast_strlen_zero(description)) {
-		ast_cli(a->fd, "    Description: %s\n", description);
-	}
-
-	cap = ast_media_get_format_cap(local_index, a->argv[3], language);
-	if (cap) {
-		int x;
-		for (x = 0; x < ast_format_cap_count(cap); x++) {
-			format = ast_format_cap_get_format(cap, x);
-			ast_cli(a->fd, "    Format: %s\n", ast_format_get_name(format));
-			ao2_ref(format, -1);
-			formats_shown = 1;
-		}
-		ao2_ref(cap, -1);
-	}
-
-	if (!formats_shown) {
-		ast_cli(a->fd, "    No Formats Available\n");
-	}
-
-	return 0;
-}
-
-/*! \brief Show a list of sounds available on the system */
-static char *handle_cli_sounds_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "core show sounds";
-		e->usage =
-			"Usage: core show sounds\n"
-			"       Shows a listing of sound files available on the system.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc == 3) {
-		RAII_VAR(struct ao2_container *, sound_files, ast_media_get_media(sounds_index), ao2_cleanup);
-		if (!sound_files) {
-			return CLI_FAILURE;
-		}
-
-		ast_cli(a->fd, "Available audio files:\n");
-		ao2_callback(sound_files, OBJ_MULTIPLE | OBJ_NODATA, show_sounds_cb, a);
-		return CLI_SUCCESS;
-	}
-
-	return CLI_SHOWUSAGE;
-}
-
-/*! \brief Show details about a sound available in the system */
-static char *handle_cli_sound_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "core show sound";
-		e->usage =
-			"Usage: core show sound [soundid]\n"
-			"       Shows information about the specified sound.\n";
-		return NULL;
-	case CLI_GENERATE:
-	{
-		int length = strlen(a->word);
-		int which = 0;
-		struct ao2_iterator it_sounds;
-		char *match = NULL;
-		char *filename;
-		RAII_VAR(struct ao2_container *, sound_files, ast_media_get_media(sounds_index), ao2_cleanup);
-		if (!sound_files) {
-			return NULL;
-		}
-
-		it_sounds = ao2_iterator_init(sound_files, 0);
-		while ((filename = ao2_iterator_next(&it_sounds))) {
-			if (!strncasecmp(a->word, filename, length) && ++which > a->n) {
-				match = ast_strdup(filename);
-				ao2_ref(filename, -1);
-				break;
-			}
-			ao2_ref(filename, -1);
-		}
-		ao2_iterator_destroy(&it_sounds);
-		return match;
-	}
-	}
-
-	if (a->argc == 4) {
-		RAII_VAR(struct ao2_container *, variants, ast_media_get_variants(sounds_index, a->argv[3]), ao2_cleanup);
-		if (!variants || !ao2_container_count(variants)) {
-			ast_cli(a->fd, "ERROR: File %s not found in index\n", a->argv[3]);
-			return CLI_FAILURE;
-		}
-
-		ast_cli(a->fd, "Indexed Information for %s:\n", a->argv[3]);
-		ao2_callback(variants, OBJ_MULTIPLE | OBJ_NODATA, show_sound_info_cb, a);
-		return CLI_SUCCESS;
-	}
-
-	return CLI_SHOWUSAGE;
-}
-
-/*! \brief Struct for registering CLI commands */
-static struct ast_cli_entry cli_sounds[] = {
-	AST_CLI_DEFINE(handle_cli_sounds_show, "Shows available sounds"),
-	AST_CLI_DEFINE(handle_cli_sound_show, "Shows details about a specific sound"),
-};
-
-static void sounds_cleanup(void)
-{
-	stasis_message_router_unsubscribe_and_join(sounds_system_router);
-	sounds_system_router = NULL;
-	ast_cli_unregister_multiple(cli_sounds, ARRAY_LEN(cli_sounds));
-	ao2_cleanup(sounds_index);
-	sounds_index = NULL;
-}
-
-static void format_update_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	ast_sounds_reindex();
-}
-
-int ast_sounds_index_init(void)
-{
-	int res = 0;
-	sounds_index = NULL;
-	if (ast_sounds_reindex()) {
-		return -1;
-	}
-	res |= ast_cli_register_multiple(cli_sounds, ARRAY_LEN(cli_sounds));
-
-	sounds_system_router = stasis_message_router_create(ast_system_topic());
-	if (!sounds_system_router) {
-		return -1;
-	}
-
-	if (ast_format_register_type()) {
-		res |= stasis_message_router_add(
-			sounds_system_router,
-			ast_format_register_type(),
-			format_update_cb,
-			NULL);
-	}
-
-	if (ast_format_unregister_type()) {
-		res |= stasis_message_router_add(
-			sounds_system_router,
-			ast_format_unregister_type(),
-			format_update_cb,
-			NULL);
-	}
-
-	if (res) {
-		return -1;
-	}
-
-	ast_register_atexit(sounds_cleanup);
-	return 0;
-}
-
-struct ast_media_index *ast_sounds_get_index(void)
-{
-	ao2_ref(sounds_index, +1);
-	return sounds_index;
-}
diff --git a/main/srv.c b/main/srv.c
index 2bdd72b..b8b2df8 100644
--- a/main/srv.c
+++ b/main/srv.c
@@ -35,13 +35,15 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 388045 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #ifdef __APPLE__
+#if __APPLE_CC__ >= 1495
 #include <arpa/nameser_compat.h>
 #endif
+#endif
 #include <resolv.h>
 
 #include "asterisk/channel.h"
diff --git a/main/stasis.c b/main/stasis.c
deleted file mode 100644
index aa55350..0000000
--- a/main/stasis.c
+++ /dev/null
@@ -1,1635 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Message Bus API.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $");
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis_internal.h"
-#include "asterisk/stasis.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/threadpool.h"
-#include "asterisk/utils.h"
-#include "asterisk/uuid.h"
-#include "asterisk/vector.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/config_options.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="UserEvent">
-		<managerEventInstance class="EVENT_FLAG_USER">
-			<synopsis>A user defined event raised from the dialplan.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="UserEvent">
-					<para>The event name, as specified in the dialplan.</para>
-				</parameter>
-			</syntax>
-			<description>
-				<para>Event may contain additional arbitrary parameters in addition to optional bridge and endpoint snapshots.  Multiple snapshots of the same type are prefixed with a numeric value.</para>
-			</description>
-			<see-also>
-				<ref type="application">UserEvent</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<configInfo name="stasis" language="en_US">
-		<configFile name="stasis.conf">
-			<configObject name="threadpool">
-				<synopsis>Settings that configure the threadpool Stasis uses to deliver some messages.</synopsis>
-				<configOption name="initial_size" default="5">
-					<synopsis>Initial number of threads in the message bus threadpool.</synopsis>
-				</configOption>
-				<configOption name="idle_timeout_sec" default="20">
-					<synopsis>Number of seconds before an idle thread is disposed of.</synopsis>
-				</configOption>
-				<configOption name="max_size" default="50">
-					<synopsis>Maximum number of threads in the threadpool.</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="declined_message_types">
-				<synopsis>Stasis message types for which to decline creation.</synopsis>
-				<configOption name="decline">
-					<synopsis>The message type to decline.</synopsis>
-					<description>
-						<para>This configuration option defines the name of the Stasis
-						message type that Asterisk is forbidden from creating and can be
-						specified as many times as necessary to achieve the desired result.</para>
-						<enumlist>
-							<enum name="stasis_app_recording_snapshot_type" />
-							<enum name="stasis_app_playback_snapshot_type" />
-							<enum name="stasis_test_message_type" />
-							<enum name="confbridge_start_type" />
-							<enum name="confbridge_end_type" />
-							<enum name="confbridge_join_type" />
-							<enum name="confbridge_leave_type" />
-							<enum name="confbridge_start_record_type" />
-							<enum name="confbridge_stop_record_type" />
-							<enum name="confbridge_mute_type" />
-							<enum name="confbridge_unmute_type" />
-							<enum name="confbridge_talking_type" />
-							<enum name="cel_generic_type" />
-							<enum name="ast_bridge_snapshot_type" />
-							<enum name="ast_bridge_merge_message_type" />
-							<enum name="ast_channel_entered_bridge_type" />
-							<enum name="ast_channel_left_bridge_type" />
-							<enum name="ast_blind_transfer_type" />
-							<enum name="ast_attended_transfer_type" />
-							<enum name="ast_endpoint_snapshot_type" />
-							<enum name="ast_endpoint_state_type" />
-							<enum name="ast_device_state_message_type" />
-							<enum name="ast_test_suite_message_type" />
-							<enum name="ast_mwi_state_type" />
-							<enum name="ast_mwi_vm_app_type" />
-							<enum name="ast_format_register_type" />
-							<enum name="ast_format_unregister_type" />
-							<enum name="ast_manager_get_generic_type" />
-							<enum name="ast_parked_call_type" />
-							<enum name="ast_channel_snapshot_type" />
-							<enum name="ast_channel_dial_type" />
-							<enum name="ast_channel_varset_type" />
-							<enum name="ast_channel_hangup_request_type" />
-							<enum name="ast_channel_dtmf_begin_type" />
-							<enum name="ast_channel_dtmf_end_type" />
-							<enum name="ast_channel_hold_type" />
-							<enum name="ast_channel_unhold_type" />
-							<enum name="ast_channel_chanspy_start_type" />
-							<enum name="ast_channel_chanspy_stop_type" />
-							<enum name="ast_channel_fax_type" />
-							<enum name="ast_channel_hangup_handler_type" />
-							<enum name="ast_channel_moh_start_type" />
-							<enum name="ast_channel_moh_stop_type" />
-							<enum name="ast_channel_monitor_start_type" />
-							<enum name="ast_channel_monitor_stop_type" />
-							<enum name="ast_channel_agent_login_type" />
-							<enum name="ast_channel_agent_logoff_type" />
-							<enum name="ast_channel_talking_start" />
-							<enum name="ast_channel_talking_stop" />
-							<enum name="ast_security_event_type" />
-							<enum name="ast_named_acl_change_type" />
-							<enum name="ast_local_bridge_type" />
-							<enum name="ast_local_optimization_begin_type" />
-							<enum name="ast_local_optimization_end_type" />
-							<enum name="stasis_subscription_change_type" />
-							<enum name="ast_multi_user_event_type" />
-							<enum name="stasis_cache_clear_type" />
-							<enum name="stasis_cache_update_type" />
-							<enum name="ast_network_change_type" />
-							<enum name="ast_system_registry_type" />
-							<enum name="ast_cc_available_type" />
-							<enum name="ast_cc_offertimerstart_type" />
-							<enum name="ast_cc_requested_type" />
-							<enum name="ast_cc_requestacknowledged_type" />
-							<enum name="ast_cc_callerstopmonitoring_type" />
-							<enum name="ast_cc_callerstartmonitoring_type" />
-							<enum name="ast_cc_callerrecalling_type" />
-							<enum name="ast_cc_recallcomplete_type" />
-							<enum name="ast_cc_failure_type" />
-							<enum name="ast_cc_monitorfailed_type" />
-							<enum name="ast_presence_state_message_type" />
-							<enum name="ast_rtp_rtcp_sent_type" />
-							<enum name="ast_rtp_rtcp_received_type" />
-							<enum name="ast_call_pickup_type" />
-							<enum name="aoc_s_type" />
-							<enum name="aoc_d_type" />
-							<enum name="aoc_e_type" />
-							<enum name="dahdichannel_type" />
-							<enum name="mcid_type" />
-							<enum name="session_timeout_type" />
-							<enum name="cdr_read_message_type" />
-							<enum name="cdr_write_message_type" />
-							<enum name="cdr_prop_write_message_type" />
-							<enum name="corosync_ping_message_type" />
-							<enum name="agi_exec_start_type" />
-							<enum name="agi_exec_end_type" />
-							<enum name="agi_async_start_type" />
-							<enum name="agi_async_exec_type" />
-							<enum name="agi_async_end_type" />
-							<enum name="queue_caller_join_type" />
-							<enum name="queue_caller_leave_type" />
-							<enum name="queue_caller_abandon_type" />
-							<enum name="queue_member_status_type" />
-							<enum name="queue_member_added_type" />
-							<enum name="queue_member_removed_type" />
-							<enum name="queue_member_pause_type" />
-							<enum name="queue_member_penalty_type" />
-							<enum name="queue_member_ringinuse_type" />
-							<enum name="queue_agent_called_type" />
-							<enum name="queue_agent_connect_type" />
-							<enum name="queue_agent_complete_type" />
-							<enum name="queue_agent_dump_type" />
-							<enum name="queue_agent_ringnoanswer_type" />
-							<enum name="meetme_join_type" />
-							<enum name="meetme_leave_type" />
-							<enum name="meetme_end_type" />
-							<enum name="meetme_mute_type" />
-							<enum name="meetme_talking_type" />
-							<enum name="meetme_talk_request_type" />
-							<enum name="appcdr_message_type" />
-							<enum name="forkcdr_message_type" />
-							<enum name="cdr_sync_message_type" />
-						</enumlist>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
-/*!
- * \page stasis-impl Stasis Implementation Notes
- *
- * \par Reference counting
- *
- * Stasis introduces a number of objects, which are tightly related to one
- * another. Because we rely on ref-counting for memory management, understanding
- * these relationships is important to understanding this code.
- *
- * \code{.txt}
- *
- *   stasis_topic <----> stasis_subscription
- *             ^          ^
- *              \        /
- *               \      /
- *               dispatch
- *                  |
- *                  |
- *                  v
- *            stasis_message
- *                  |
- *                  |
- *                  v
- *          stasis_message_type
- *
- * \endcode
- *
- * The most troubling thing in this chart is the cyclic reference between
- * stasis_topic and stasis_subscription. This is both unfortunate, and
- * necessary. Topics need the subscription in order to dispatch messages;
- * subscriptions need the topics to unsubscribe and check subscription status.
- *
- * The cycle is broken by stasis_unsubscribe(). The unsubscribe will remove the
- * topic's reference to a subscription. When the subcription is destroyed, it
- * will remove its reference to the topic.
- *
- * This means that until a subscription has be explicitly unsubscribed, it will
- * not be destroyed. Neither will a topic be destroyed while it has subscribers.
- * The destructors of both have assertions regarding this to catch ref-counting
- * problems where a subscription or topic has had an extra ao2_cleanup().
- *
- * The \ref dispatch object is a transient object, which is posted to a
- * subscription's taskprocessor to send a message to the subscriber. They have
- * short life cycles, allocated on one thread, destroyed on another.
- *
- * During shutdown, or the deletion of a domain object, there are a flurry of
- * ao2_cleanup()s on subscriptions and topics, as the final in-flight messages
- * are processed. Any one of these cleanups could be the one to actually destroy
- * a given object, so care must be taken to ensure that an object isn't
- * referenced after an ao2_cleanup(). This includes the implicit ao2_unlock()
- * that might happen when a RAII_VAR() goes out of scope.
- *
- * \par Typical life cycles
- *
- *  \li stasis_topic - There are several topics which live for the duration of
- *      the Asterisk process (ast_channel_topic_all(), etc.) but most of these
- *      are actually fed by shorter-lived topics whose lifetime is associated
- *      with some domain object (like ast_channel_topic() for a given
- *      ast_channel).
- *
- *  \li stasis_subscription - Subscriptions have a similar mix of lifetimes as
- *      topics, for similar reasons.
- *
- *  \li dispatch - Very short lived; just long enough to post a message to a
- *      subscriber.
- *
- *  \li stasis_message - Short to intermediate lifetimes, but that is mostly
- *      irrelevant. Messages are strictly data and have no behavior associated
- *      with them, so it doesn't really matter if/when they are destroyed. By
- *      design, a component could hold a ref to a message forever without any
- *      ill consequences (aside from consuming more memory).
- *
- *  \li stasis_message_type - Long life cycles, typically only destroyed on
- *      module unloading or _clean_ process exit.
- *
- * \par Subscriber shutdown sequencing
- *
- * Subscribers are sensitive to shutdown sequencing, specifically in how the
- * reference message types. This is fully detailed on the wiki at
- * https://wiki.asterisk.org/wiki/x/K4BqAQ.
- *
- * In short, the lifetime of the \a data (and \a callback, if in a module) must
- * be held until the stasis_subscription_final_message() has been received.
- * Depending on the structure of the subscriber code, this can be handled by
- * using stasis_subscription_final_message() to free resources on the final
- * message, or using stasis_subscription_join()/stasis_unsubscribe_and_join() to
- * block until the unsubscribe has completed.
- */
-
-/*! Initial size of the subscribers list. */
-#define INITIAL_SUBSCRIBERS_MAX 4
-
-/*! The number of buckets to use for topic pools */
-#define TOPIC_POOL_BUCKETS 57
-
-/*! Thread pool for topics that don't want a dedicated taskprocessor */
-static struct ast_threadpool *pool;
-
-STASIS_MESSAGE_TYPE_DEFN(stasis_subscription_change_type);
-
-/*! \internal */
-struct stasis_topic {
-	char *name;
-	/*! Variable length array of the subscribers */
-	AST_VECTOR(, struct stasis_subscription *) subscribers;
-
-	/*! Topics forwarding into this topic */
-	AST_VECTOR(, struct stasis_topic *) upstream_topics;
-};
-
-/* Forward declarations for the tightly-coupled subscription object */
-static int topic_add_subscription(struct stasis_topic *topic,
-	struct stasis_subscription *sub);
-
-static int topic_remove_subscription(struct stasis_topic *topic, struct stasis_subscription *sub);
-
-/*! \brief Lock two topics. */
-#define topic_lock_both(topic1, topic2) \
-	do { \
-		ao2_lock(topic1); \
-		while (ao2_trylock(topic2)) { \
-			AO2_DEADLOCK_AVOIDANCE(topic1); \
-		} \
-	} while (0)
-
-static void topic_dtor(void *obj)
-{
-	struct stasis_topic *topic = obj;
-
-	/* Subscribers hold a reference to topics, so they should all be
-	 * unsubscribed before we get here. */
-	ast_assert(AST_VECTOR_SIZE(&topic->subscribers) == 0);
-
-	ast_free(topic->name);
-	topic->name = NULL;
-
-	AST_VECTOR_FREE(&topic->subscribers);
-	AST_VECTOR_FREE(&topic->upstream_topics);
-}
-
-struct stasis_topic *stasis_topic_create(const char *name)
-{
-	struct stasis_topic *topic;
-	int res = 0;
-
-	topic = ao2_t_alloc(sizeof(*topic), topic_dtor, name);
-	if (!topic) {
-		return NULL;
-	}
-
-	topic->name = ast_strdup(name);
-	res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX);
-	res |= AST_VECTOR_INIT(&topic->upstream_topics, 0);
-	if (!topic->name || res) {
-		ao2_cleanup(topic);
-		return NULL;
-	}
-
-	return topic;
-}
-
-const char *stasis_topic_name(const struct stasis_topic *topic)
-{
-	return topic->name;
-}
-
-/*! \internal */
-struct stasis_subscription {
-	/*! Unique ID for this subscription */
-	char uniqueid[AST_UUID_STR_LEN];
-	/*! Topic subscribed to. */
-	struct stasis_topic *topic;
-	/*! Mailbox for processing incoming messages. */
-	struct ast_taskprocessor *mailbox;
-	/*! Callback function for incoming message processing. */
-	stasis_subscription_cb callback;
-	/*! Data pointer to be handed to the callback. */
-	void *data;
-
-	/*! Condition for joining with subscription. */
-	ast_cond_t join_cond;
-	/*! Flag set when final message for sub has been received.
-	 *  Be sure join_lock is held before reading/setting. */
-	int final_message_rxed;
-	/*! Flag set when final message for sub has been processed.
-	 *  Be sure join_lock is held before reading/setting. */
-	int final_message_processed;
-};
-
-static void subscription_dtor(void *obj)
-{
-	struct stasis_subscription *sub = obj;
-
-	/* Subscriptions need to be manually unsubscribed before destruction
-	 * b/c there's a cyclic reference between topics and subscriptions */
-	ast_assert(!stasis_subscription_is_subscribed(sub));
-	/* If there are any messages in flight to this subscription; that would
-	 * be bad. */
-	ast_assert(stasis_subscription_is_done(sub));
-
-	ao2_cleanup(sub->topic);
-	sub->topic = NULL;
-	ast_taskprocessor_unreference(sub->mailbox);
-	sub->mailbox = NULL;
-	ast_cond_destroy(&sub->join_cond);
-}
-
-/*!
- * \brief Invoke the subscription's callback.
- * \param sub Subscription to invoke.
- * \param topic Topic message was published to.
- * \param message Message to send.
- */
-static void subscription_invoke(struct stasis_subscription *sub,
-				  struct stasis_message *message)
-{
-	/* Notify that the final message has been received */
-	if (stasis_subscription_final_message(sub, message)) {
-		SCOPED_AO2LOCK(lock, sub);
-
-		sub->final_message_rxed = 1;
-		ast_cond_signal(&sub->join_cond);
-	}
-
-	/* Since sub is mostly immutable, no need to lock sub */
-	sub->callback(sub->data, sub, message);
-
-	/* Notify that the final message has been processed */
-	if (stasis_subscription_final_message(sub, message)) {
-		SCOPED_AO2LOCK(lock, sub);
-
-		sub->final_message_processed = 1;
-		ast_cond_signal(&sub->join_cond);
-	}
-}
-
-static void send_subscription_subscribe(struct stasis_topic *topic, struct stasis_subscription *sub);
-static void send_subscription_unsubscribe(struct stasis_topic *topic, struct stasis_subscription *sub);
-
-struct stasis_subscription *internal_stasis_subscribe(
-	struct stasis_topic *topic,
-	stasis_subscription_cb callback,
-	void *data,
-	int needs_mailbox,
-	int use_thread_pool)
-{
-	RAII_VAR(struct stasis_subscription *, sub, NULL, ao2_cleanup);
-
-	if (!topic) {
-		return NULL;
-	}
-
-	/* The ao2 lock is used for join_cond. */
-	sub = ao2_t_alloc(sizeof(*sub), subscription_dtor, topic->name);
-	if (!sub) {
-		return NULL;
-	}
-	ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid));
-
-	if (needs_mailbox) {
-		/* With a small number of subscribers, a thread-per-sub is
-		 * acceptable. For larger number of subscribers, a thread
-		 * pool should be used.
-		 */
-		if (use_thread_pool) {
-			sub->mailbox = ast_threadpool_serializer(sub->uniqueid, pool);
-		} else {
-			sub->mailbox = ast_taskprocessor_get(sub->uniqueid,
-				TPS_REF_DEFAULT);
-		}
-		if (!sub->mailbox) {
-			return NULL;
-		}
-		ast_taskprocessor_set_local(sub->mailbox, sub);
-		/* Taskprocessor has a reference */
-		ao2_ref(sub, +1);
-	}
-
-	ao2_ref(topic, +1);
-	sub->topic = topic;
-	sub->callback = callback;
-	sub->data = data;
-	ast_cond_init(&sub->join_cond, NULL);
-
-	if (topic_add_subscription(topic, sub) != 0) {
-		return NULL;
-	}
-	send_subscription_subscribe(topic, sub);
-
-	ao2_ref(sub, +1);
-	return sub;
-}
-
-struct stasis_subscription *stasis_subscribe(
-	struct stasis_topic *topic,
-	stasis_subscription_cb callback,
-	void *data)
-{
-	return internal_stasis_subscribe(topic, callback, data, 1, 0);
-}
-
-struct stasis_subscription *stasis_subscribe_pool(
-	struct stasis_topic *topic,
-	stasis_subscription_cb callback,
-	void *data)
-{
-	return internal_stasis_subscribe(topic, callback, data, 1, 1);
-}
-
-static int sub_cleanup(void *data)
-{
-	struct stasis_subscription *sub = data;
-	ao2_cleanup(sub);
-	return 0;
-}
-
-struct stasis_subscription *stasis_unsubscribe(struct stasis_subscription *sub)
-{
-	/* The subscription may be the last ref to this topic. Hold
-	 * the topic ref open until after the unlock. */
-	RAII_VAR(struct stasis_topic *, topic,
-		ao2_bump(sub ? sub->topic : NULL), ao2_cleanup);
-
-	if (!sub) {
-		return NULL;
-	}
-
-	/* We have to remove the subscription first, to ensure the unsubscribe
-	 * is the final message */
-	if (topic_remove_subscription(sub->topic, sub) != 0) {
-		ast_log(LOG_ERROR,
-			"Internal error: subscription has invalid topic\n");
-		return NULL;
-	}
-
-	/* Now let everyone know about the unsubscribe */
-	send_subscription_unsubscribe(topic, sub);
-
-	/* When all that's done, remove the ref the mailbox has on the sub */
-	if (sub->mailbox) {
-		ast_taskprocessor_push(sub->mailbox, sub_cleanup, sub);
-	}
-
-	/* Unsubscribing unrefs the subscription */
-	ao2_cleanup(sub);
-	return NULL;
-}
-
-void stasis_subscription_join(struct stasis_subscription *subscription)
-{
-	if (subscription) {
-		SCOPED_AO2LOCK(lock, subscription);
-
-		/* Wait until the processed flag has been set */
-		while (!subscription->final_message_processed) {
-			ast_cond_wait(&subscription->join_cond,
-				ao2_object_get_lockaddr(subscription));
-		}
-	}
-}
-
-int stasis_subscription_is_done(struct stasis_subscription *subscription)
-{
-	if (subscription) {
-		SCOPED_AO2LOCK(lock, subscription);
-
-		return subscription->final_message_rxed;
-	}
-
-	/* Null subscription is about as done as you can get */
-	return 1;
-}
-
-struct stasis_subscription *stasis_unsubscribe_and_join(
-	struct stasis_subscription *subscription)
-{
-	if (!subscription) {
-		return NULL;
-	}
-
-	/* Bump refcount to hold it past the unsubscribe */
-	ao2_ref(subscription, +1);
-	stasis_unsubscribe(subscription);
-	stasis_subscription_join(subscription);
-	/* Now decrement the refcount back */
-	ao2_cleanup(subscription);
-	return NULL;
-}
-
-int stasis_subscription_is_subscribed(const struct stasis_subscription *sub)
-{
-	if (sub) {
-		size_t i;
-		struct stasis_topic *topic = sub->topic;
-		SCOPED_AO2LOCK(lock_topic, topic);
-
-		for (i = 0; i < AST_VECTOR_SIZE(&topic->subscribers); ++i) {
-			if (AST_VECTOR_GET(&topic->subscribers, i) == sub) {
-				return 1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-const char *stasis_subscription_uniqueid(const struct stasis_subscription *sub)
-{
-	return sub->uniqueid;
-}
-
-int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
-{
-	struct stasis_subscription_change *change;
-
-	if (stasis_message_type(msg) != stasis_subscription_change_type()) {
-		return 0;
-	}
-
-	change = stasis_message_data(msg);
-	if (strcmp("Unsubscribe", change->description)) {
-		return 0;
-	}
-
-	if (strcmp(stasis_subscription_uniqueid(sub), change->uniqueid)) {
-		return 0;
-	}
-
-	return 1;
-}
-
-/*!
- * \brief Add a subscriber to a topic.
- * \param topic Topic
- * \param sub Subscriber
- * \return 0 on success
- * \return Non-zero on error
- */
-static int topic_add_subscription(struct stasis_topic *topic, struct stasis_subscription *sub)
-{
-	size_t idx;
-	SCOPED_AO2LOCK(lock, topic);
-
-	/* The reference from the topic to the subscription is shared with
-	 * the owner of the subscription, which will explicitly unsubscribe
-	 * to release it.
-	 *
-	 * If we bumped the refcount here, the owner would have to unsubscribe
-	 * and cleanup, which is a bit awkward. */
-	AST_VECTOR_APPEND(&topic->subscribers, sub);
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&topic->upstream_topics); ++idx) {
-		topic_add_subscription(
-			AST_VECTOR_GET(&topic->upstream_topics, idx), sub);
-	}
-
-	return 0;
-}
-
-static int topic_remove_subscription(struct stasis_topic *topic, struct stasis_subscription *sub)
-{
-	size_t idx;
-	SCOPED_AO2LOCK(lock_topic, topic);
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&topic->upstream_topics); ++idx) {
-		topic_remove_subscription(
-			AST_VECTOR_GET(&topic->upstream_topics, idx), sub);
-	}
-
-	return AST_VECTOR_REMOVE_ELEM_UNORDERED(&topic->subscribers, sub,
-		AST_VECTOR_ELEM_CLEANUP_NOOP);
-}
-
-/*!
- * \internal \brief Dispatch a message to a subscriber asynchronously
- * \param local \ref ast_taskprocessor_local object
- * \return 0
- */
-static int dispatch_exec_async(struct ast_taskprocessor_local *local)
-{
-	struct stasis_subscription *sub = local->local_data;
-	struct stasis_message *message = local->data;
-
-	subscription_invoke(sub, message);
-	ao2_cleanup(message);
-
-	return 0;
-}
-
-/*!
- * \internal \brief Data passed to \ref dispatch_exec_sync to synchronize
- * a published message to a subscriber
- */
-struct sync_task_data {
-	ast_mutex_t lock;
-	ast_cond_t cond;
-	int complete;
-	void *task_data;
-};
-
-/*!
- * \internal \brief Dispatch a message to a subscriber synchronously
- * \param local \ref ast_taskprocessor_local object
- * \return 0
- */
-static int dispatch_exec_sync(struct ast_taskprocessor_local *local)
-{
-	struct stasis_subscription *sub = local->local_data;
-	struct sync_task_data *std = local->data;
-	struct stasis_message *message = std->task_data;
-
-	subscription_invoke(sub, message);
-	ao2_cleanup(message);
-
-	ast_mutex_lock(&std->lock);
-	std->complete = 1;
-	ast_cond_signal(&std->cond);
-	ast_mutex_unlock(&std->lock);
-
-	return 0;
-}
-
-/*!
- * \internal \brief Dispatch a message to a subscriber
- * \param sub The subscriber to dispatch to
- * \param message The message to send
- * \param synchronous If non-zero, synchronize on the subscriber receiving
- * the message
- */
-static void dispatch_message(struct stasis_subscription *sub,
-	struct stasis_message *message,
-	int synchronous)
-{
-	if (!sub->mailbox) {
-		/* Dispatch directly */
-		subscription_invoke(sub, message);
-		return;
-	}
-
-	/* Bump the message for the taskprocessor push. This will get de-ref'd
-	 * by the task processor callback.
-	 */
-	ao2_bump(message);
-	if (!synchronous) {
-		if (ast_taskprocessor_push_local(sub->mailbox, dispatch_exec_async, message)) {
-			/* Push failed; ugh. */
-			ast_log(LOG_ERROR, "Dropping async dispatch\n");
-			ao2_cleanup(message);
-		}
-	} else {
-		struct sync_task_data std;
-
-		ast_mutex_init(&std.lock);
-		ast_cond_init(&std.cond, NULL);
-		std.complete = 0;
-		std.task_data = message;
-
-		if (ast_taskprocessor_push_local(sub->mailbox, dispatch_exec_sync, &std)) {
-			/* Push failed; ugh. */
-			ast_log(LOG_ERROR, "Dropping sync dispatch\n");
-			ao2_cleanup(message);
-			ast_mutex_destroy(&std.lock);
-			ast_cond_destroy(&std.cond);
-			return;
-		}
-
-		ast_mutex_lock(&std.lock);
-		while (!std.complete) {
-			ast_cond_wait(&std.cond, &std.lock);
-		}
-		ast_mutex_unlock(&std.lock);
-
-		ast_mutex_destroy(&std.lock);
-		ast_cond_destroy(&std.cond);
-	}
-}
-
-/*!
- * \internal \brief Publish a message to a topic's subscribers
- * \brief topic The topic to publish to
- * \brief message The message to publish
- * \brief sync_sub An optional subscriber of the topic to publish synchronously
- * to
- */
-static void publish_msg(struct stasis_topic *topic,
-	struct stasis_message *message, struct stasis_subscription *sync_sub)
-{
-	size_t i;
-
-	ast_assert(topic != NULL);
-	ast_assert(message != NULL);
-
-	/*
-	 * The topic may be unref'ed by the subscription invocation.
-	 * Make sure we hold onto a reference while dispatching.
-	 */
-	ao2_ref(topic, +1);
-	ao2_lock(topic);
-	for (i = 0; i < AST_VECTOR_SIZE(&topic->subscribers); ++i) {
-		struct stasis_subscription *sub = AST_VECTOR_GET(&topic->subscribers, i);
-
-		ast_assert(sub != NULL);
-
-		dispatch_message(sub, message, (sub == sync_sub));
-	}
-	ao2_unlock(topic);
-	ao2_ref(topic, -1);
-}
-
-void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
-{
-	publish_msg(topic, message, NULL);
-}
-
-void stasis_publish_sync(struct stasis_subscription *sub, struct stasis_message *message)
-{
-	ast_assert(sub != NULL);
-
-	publish_msg(sub->topic, message, sub);
-}
-
-/*!
- * \brief Forwarding information
- *
- * Any message posted to \a from_topic is forwarded to \a to_topic.
- *
- * In cases where both the \a from_topic and \a to_topic need to be locked,
- * always lock the \a to_topic first, then the \a from_topic. Lest you deadlock.
- */
-struct stasis_forward {
-	/*! Originating topic */
-	struct stasis_topic *from_topic;
-	/*! Destination topic */
-	struct stasis_topic *to_topic;
-};
-
-static void forward_dtor(void *obj)
-{
-	struct stasis_forward *forward = obj;
-
-	ao2_cleanup(forward->from_topic);
-	forward->from_topic = NULL;
-	ao2_cleanup(forward->to_topic);
-	forward->to_topic = NULL;
-}
-
-struct stasis_forward *stasis_forward_cancel(struct stasis_forward *forward)
-{
-	int idx;
-	struct stasis_topic *from;
-	struct stasis_topic *to;
-
-	if (!forward) {
-		return NULL;
-	}
-
-	from = forward->from_topic;
-	to = forward->to_topic;
-
-	if (from && to) {
-		topic_lock_both(to, from);
-		AST_VECTOR_REMOVE_ELEM_UNORDERED(&to->upstream_topics, from,
-			AST_VECTOR_ELEM_CLEANUP_NOOP);
-
-		for (idx = 0; idx < AST_VECTOR_SIZE(&to->subscribers); ++idx) {
-			topic_remove_subscription(from, AST_VECTOR_GET(&to->subscribers, idx));
-		}
-		ao2_unlock(from);
-		ao2_unlock(to);
-	}
-
-	ao2_cleanup(forward);
-
-	return NULL;
-}
-
-struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic,
-	struct stasis_topic *to_topic)
-{
-	int res;
-	size_t idx;
-	RAII_VAR(struct stasis_forward *, forward, NULL, ao2_cleanup);
-
-	if (!from_topic || !to_topic) {
-		return NULL;
-	}
-
-	forward = ao2_alloc_options(sizeof(*forward), forward_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!forward) {
-		return NULL;
-	}
-
-	/* Forwards to ourselves are implicit. */
-	if (to_topic == from_topic) {
-		return ao2_bump(forward);
-	}
-
-	forward->from_topic = ao2_bump(from_topic);
-	forward->to_topic = ao2_bump(to_topic);
-
-	topic_lock_both(to_topic, from_topic);
-	res = AST_VECTOR_APPEND(&to_topic->upstream_topics, from_topic);
-	if (res != 0) {
-		ao2_unlock(from_topic);
-		ao2_unlock(to_topic);
-		return NULL;
-	}
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&to_topic->subscribers); ++idx) {
-		topic_add_subscription(from_topic, AST_VECTOR_GET(&to_topic->subscribers, idx));
-	}
-	ao2_unlock(from_topic);
-	ao2_unlock(to_topic);
-
-	return ao2_bump(forward);
-}
-
-static void subscription_change_dtor(void *obj)
-{
-	struct stasis_subscription_change *change = obj;
-
-	ast_string_field_free_memory(change);
-	ao2_cleanup(change->topic);
-}
-
-static struct stasis_subscription_change *subscription_change_alloc(struct stasis_topic *topic, const char *uniqueid, const char *description)
-{
-	struct stasis_subscription_change *change;
-
-	change = ao2_alloc(sizeof(struct stasis_subscription_change), subscription_change_dtor);
-	if (!change || ast_string_field_init(change, 128)) {
-		ao2_cleanup(change);
-		return NULL;
-	}
-
-	ast_string_field_set(change, uniqueid, uniqueid);
-	ast_string_field_set(change, description, description);
-	ao2_ref(topic, +1);
-	change->topic = topic;
-
-	return change;
-}
-
-static void send_subscription_subscribe(struct stasis_topic *topic, struct stasis_subscription *sub)
-{
-	struct stasis_subscription_change *change;
-	struct stasis_message *msg;
-
-	/* This assumes that we have already unsubscribed */
-	ast_assert(stasis_subscription_is_subscribed(sub));
-
-	if (!stasis_subscription_change_type()) {
-		return;
-	}
-
-	change = subscription_change_alloc(topic, sub->uniqueid, "Subscribe");
-	if (!change) {
-		return;
-	}
-
-	msg = stasis_message_create(stasis_subscription_change_type(), change);
-	if (!msg) {
-		ao2_cleanup(change);
-		return;
-	}
-
-	stasis_publish(topic, msg);
-	ao2_cleanup(msg);
-	ao2_cleanup(change);
-}
-
-static void send_subscription_unsubscribe(struct stasis_topic *topic,
-	struct stasis_subscription *sub)
-{
-	struct stasis_subscription_change *change;
-	struct stasis_message *msg;
-
-	/* This assumes that we have already unsubscribed */
-	ast_assert(!stasis_subscription_is_subscribed(sub));
-
-	if (!stasis_subscription_change_type()) {
-		return;
-	}
-
-	change = subscription_change_alloc(topic, sub->uniqueid, "Unsubscribe");
-	if (!change) {
-		return;
-	}
-
-	msg = stasis_message_create(stasis_subscription_change_type(), change);
-	if (!msg) {
-		ao2_cleanup(change);
-		return;
-	}
-
-	stasis_publish(topic, msg);
-
-	/* Now we have to dispatch to the subscription itself */
-	dispatch_message(sub, msg, 0);
-
-	ao2_cleanup(msg);
-	ao2_cleanup(change);
-}
-
-struct topic_pool_entry {
-	struct stasis_forward *forward;
-	struct stasis_topic *topic;
-};
-
-static void topic_pool_entry_dtor(void *obj)
-{
-	struct topic_pool_entry *entry = obj;
-
-	entry->forward = stasis_forward_cancel(entry->forward);
-	ao2_cleanup(entry->topic);
-	entry->topic = NULL;
-}
-
-static struct topic_pool_entry *topic_pool_entry_alloc(void)
-{
-	return ao2_alloc_options(sizeof(struct topic_pool_entry), topic_pool_entry_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-}
-
-struct stasis_topic_pool {
-	struct ao2_container *pool_container;
-	struct stasis_topic *pool_topic;
-};
-
-static void topic_pool_dtor(void *obj)
-{
-	struct stasis_topic_pool *pool = obj;
-
-	ao2_cleanup(pool->pool_container);
-	pool->pool_container = NULL;
-	ao2_cleanup(pool->pool_topic);
-	pool->pool_topic = NULL;
-}
-
-static int topic_pool_entry_hash(const void *obj, const int flags)
-{
-	const struct topic_pool_entry *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = stasis_topic_name(object->topic);
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_case_hash(key);
-}
-
-static int topic_pool_entry_cmp(void *obj, void *arg, int flags)
-{
-	const struct topic_pool_entry *object_left = obj;
-	const struct topic_pool_entry *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = stasis_topic_name(object_right->topic);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcasecmp(stasis_topic_name(object_left->topic), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* Not supported by container */
-		ast_assert(0);
-		cmp = -1;
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-struct stasis_topic_pool *stasis_topic_pool_create(struct stasis_topic *pooled_topic)
-{
-	struct stasis_topic_pool *pool;
-
-	pool = ao2_alloc_options(sizeof(*pool), topic_pool_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!pool) {
-		return NULL;
-	}
-
-	pool->pool_container = ao2_container_alloc(TOPIC_POOL_BUCKETS,
-		topic_pool_entry_hash, topic_pool_entry_cmp);
-	if (!pool->pool_container) {
-		ao2_cleanup(pool);
-		return NULL;
-	}
-	ao2_ref(pooled_topic, +1);
-	pool->pool_topic = pooled_topic;
-
-	return pool;
-}
-
-struct stasis_topic *stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name)
-{
-	RAII_VAR(struct topic_pool_entry *, topic_pool_entry, NULL, ao2_cleanup);
-	SCOPED_AO2LOCK(topic_container_lock, pool->pool_container);
-
-	topic_pool_entry = ao2_find(pool->pool_container, topic_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-	if (topic_pool_entry) {
-		return topic_pool_entry->topic;
-	}
-
-	topic_pool_entry = topic_pool_entry_alloc();
-	if (!topic_pool_entry) {
-		return NULL;
-	}
-
-	topic_pool_entry->topic = stasis_topic_create(topic_name);
-	if (!topic_pool_entry->topic) {
-		return NULL;
-	}
-
-	topic_pool_entry->forward = stasis_forward_all(topic_pool_entry->topic, pool->pool_topic);
-	if (!topic_pool_entry->forward) {
-		return NULL;
-	}
-
-	if (!ao2_link_flags(pool->pool_container, topic_pool_entry, OBJ_NOLOCK)) {
-		return NULL;
-	}
-
-	return topic_pool_entry->topic;
-}
-
-void stasis_log_bad_type_access(const char *name)
-{
-#ifdef AST_DEVMODE
-	ast_log(LOG_ERROR, "Use of %s() before init/after destruction\n", name);
-#endif
-}
-
-/*! \brief A multi object blob data structure to carry user event stasis messages */
-struct ast_multi_object_blob {
-	struct ast_json *blob;                             /*< A blob of JSON data */
-	AST_VECTOR(, void *) snapshots[STASIS_UMOS_MAX];   /*< Vector of snapshots for each type */
-};
-
-/*!
- * \internal
- * \brief Destructor for \ref ast_multi_object_blob objects
- */
-static void multi_object_blob_dtor(void *obj)
-{
-	struct ast_multi_object_blob *multi = obj;
-	int type;
-	int i;
-
-	for (type = 0; type < STASIS_UMOS_MAX; ++type) {
-		for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) {
-			ao2_cleanup(AST_VECTOR_GET(&multi->snapshots[type], i));
-		}
-		AST_VECTOR_FREE(&multi->snapshots[type]);
-	}
-	ast_json_unref(multi->blob);
-}
-
-/*! \brief Create a stasis user event multi object blob */
-struct ast_multi_object_blob *ast_multi_object_blob_create(struct ast_json *blob)
-{
-	int type;
-	RAII_VAR(struct ast_multi_object_blob *, multi,
-			ao2_alloc(sizeof(*multi), multi_object_blob_dtor),
-			ao2_cleanup);
-
-	ast_assert(blob != NULL);
-
-	if (!multi) {
-		return NULL;
-	}
-
-	for (type = 0; type < STASIS_UMOS_MAX; ++type) {
-		if (AST_VECTOR_INIT(&multi->snapshots[type], 0)) {
-			return NULL;
-		}
-	}
-
-	multi->blob = ast_json_ref(blob);
-
-	ao2_ref(multi, +1);
-	return multi;
-}
-
-/*! \brief Add an object (snapshot) to the blob */
-void ast_multi_object_blob_add(struct ast_multi_object_blob *multi,
-	enum stasis_user_multi_object_snapshot_type type, void *object)
-{
-	if (!multi || !object) {
-		return;
-	}
-	AST_VECTOR_APPEND(&multi->snapshots[type],object);
-}
-
-/*! \brief Publish single channel user event (for app_userevent compatibility) */
-void ast_multi_object_blob_single_channel_publish(struct ast_channel *chan,
-	struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, channel_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup);
-
-	if (!type) {
-		return;
-	}
-
-	multi = ast_multi_object_blob_create(blob);
-	if (!multi) {
-		return;
-	}
-
-	channel_snapshot = ast_channel_snapshot_create(chan);
-	ao2_ref(channel_snapshot, +1);
-	ast_multi_object_blob_add(multi, STASIS_UMOS_CHANNEL, channel_snapshot);
-
-	message = stasis_message_create(type, multi);
-	if (message) {
-		/* app_userevent still publishes to channel */
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-}
-
-/*! \internal \brief convert multi object blob to ari json */
-static struct ast_json *multi_user_event_to_json(
-	struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
-	struct ast_multi_object_blob *multi = stasis_message_data(message);
-	struct ast_json *blob = multi->blob;
-	const struct timeval *tv = stasis_message_timestamp(message);
-	enum stasis_user_multi_object_snapshot_type type;
-	int i;
-
-	out = ast_json_object_create();
-	if (!out) {
-		return NULL;
-	}
-
-	ast_json_object_set(out, "type", ast_json_string_create("ChannelUserevent"));
-	ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL));
-	ast_json_object_set(out, "eventname", ast_json_ref(ast_json_object_get(blob, "eventname")));
-	ast_json_object_set(out, "userevent", ast_json_ref(blob)); /* eventname gets duplicated, that's ok */
-
-	for (type = 0; type < STASIS_UMOS_MAX; ++type) {
-		for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) {
-			struct ast_json *json_object = NULL;
-			char *name = NULL;
-			void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i);
-
-			switch (type) {
-			case STASIS_UMOS_CHANNEL:
-				json_object = ast_channel_snapshot_to_json(snapshot, sanitize);
-				name = "channel";
-				break;
-			case STASIS_UMOS_BRIDGE:
-				json_object = ast_bridge_snapshot_to_json(snapshot, sanitize);
-				name = "bridge";
-				break;
-			case STASIS_UMOS_ENDPOINT:
-				json_object = ast_endpoint_snapshot_to_json(snapshot, sanitize);
-				name = "endpoint";
-				break;
-			}
-			if (json_object) {
-				ast_json_object_set(out, name, json_object);
-			}
-		}
-	}
-	return ast_json_ref(out);
-}
-
-/*! \internal \brief convert multi object blob to ami string */
-static struct ast_str *multi_object_blob_to_ami(void *obj)
-{
-	struct ast_str *ami_str=ast_str_create(1024);
-	struct ast_str *ami_snapshot;
-	const struct ast_multi_object_blob *multi = obj;
-	enum stasis_user_multi_object_snapshot_type type;
-	int i;
-
-	if (!ami_str) {
-		return NULL;
-	}
-	if (!multi) {
-		ast_free(ami_str);
-		return NULL;
-	}
-
-	for (type = 0; type < STASIS_UMOS_MAX; ++type) {
-		for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) {
-			char *name = "";
-			void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i);
-			ami_snapshot = NULL;
-
-			if (i > 0) {
-				ast_asprintf(&name, "%d", i + 1);
-			}
-
-			switch (type) {
-			case STASIS_UMOS_CHANNEL:
-				ami_snapshot = ast_manager_build_channel_state_string_prefix(snapshot, name);
-				break;
-
-			case STASIS_UMOS_BRIDGE:
-				ami_snapshot = ast_manager_build_bridge_state_string_prefix(snapshot, name);
-				break;
-
-			case STASIS_UMOS_ENDPOINT:
-				/* currently not sending endpoint snapshots to AMI */
-				break;
-			}
-			if (ami_snapshot) {
-				ast_str_append(&ami_str, 0, "%s", ast_str_buffer(ami_snapshot));
-				ast_free(ami_snapshot);
-			}
-		}
-	}
-
-	return ami_str;
-}
-
-/*! \internal \brief Callback to pass only user defined parameters from blob */
-static int userevent_exclusion_cb(const char *key)
-{
-	if (!strcmp("eventname", key)) {
-		return 1;
-	}
-	return 0;
-}
-
-static struct ast_manager_event_blob *multi_user_event_to_ami(
-	struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, object_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, body, NULL, ast_free);
-	struct ast_multi_object_blob *multi = stasis_message_data(message);
-	const char *eventname;
-
-	eventname = ast_json_string_get(ast_json_object_get(multi->blob, "eventname"));
-	body = ast_manager_str_from_json_object(multi->blob, userevent_exclusion_cb);
-	object_string = multi_object_blob_to_ami(multi);
-	if (!object_string || !body) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_USER, "UserEvent",
-		"%s"
-		"UserEvent: %s\r\n"
-		"%s",
-		ast_str_buffer(object_string),
-		eventname,
-		ast_str_buffer(body));
-}
-
-/*! \brief A structure to hold global configuration-related options */
-struct stasis_declined_config {
-	/*! The list of message types to decline */
-	struct ao2_container *declined;
-};
-
-/*! \brief Threadpool configuration options */
-struct stasis_threadpool_conf {
-	/*! Initial size of the thread pool */
-	int initial_size;
-	/*! Time, in seconds, before we expire a thread */
-	int idle_timeout_sec;
-	/*! Maximum number of thread to allow */
-	int max_size;
-};
-
-struct stasis_config {
-	/*! Thread pool configuration options */
-	struct stasis_threadpool_conf *threadpool_options;
-	/*! Declined message types */
-	struct stasis_declined_config *declined_message_types;
-};
-
-static struct aco_type threadpool_option = {
-	.type = ACO_GLOBAL,
-	.name = "threadpool",
-	.item_offset = offsetof(struct stasis_config, threadpool_options),
-	.category = "^threadpool$",
-	.category_match = ACO_WHITELIST,
-};
-
-static struct aco_type *threadpool_options[] = ACO_TYPES(&threadpool_option);
-
-/*! \brief An aco_type structure to link the "declined_message_types" category to the stasis_declined_config type */
-static struct aco_type declined_option = {
-	.type = ACO_GLOBAL,
-	.name = "declined_message_types",
-	.item_offset = offsetof(struct stasis_config, declined_message_types),
-	.category_match = ACO_WHITELIST,
-	.category = "^declined_message_types$",
-};
-
-struct aco_type *declined_options[] = ACO_TYPES(&declined_option);
-
-struct aco_file stasis_conf = {
-        .filename = "stasis.conf",
-	.types = ACO_TYPES(&declined_option, &threadpool_option),
-};
-
-/*! \brief A global object container that will contain the stasis_config that gets swapped out on reloads */
-static AO2_GLOBAL_OBJ_STATIC(globals);
-
-static void *stasis_config_alloc(void);
-
-/*! \brief Register information about the configs being processed by this module */
-CONFIG_INFO_CORE("stasis", cfg_info, globals, stasis_config_alloc,
-        .files = ACO_FILES(&stasis_conf),
-);
-
-static void stasis_declined_config_destructor(void *obj)
-{
-	struct stasis_declined_config *declined = obj;
-
-	ao2_cleanup(declined->declined);
-}
-
-static void stasis_config_destructor(void *obj)
-{
-	struct stasis_config *cfg = obj;
-
-	ao2_cleanup(cfg->declined_message_types);
-	ast_free(cfg->threadpool_options);
-}
-
-static void *stasis_config_alloc(void)
-{
-	struct stasis_config *cfg;
-
-	if (!(cfg = ao2_alloc(sizeof(*cfg), stasis_config_destructor))) {
-		return NULL;
-	}
-
-	cfg->threadpool_options = ast_calloc(1, sizeof(*cfg->threadpool_options));
-	if (!cfg->threadpool_options) {
-		ao2_ref(cfg, -1);
-		return NULL;
-	}
-
-	cfg->declined_message_types = ao2_alloc(sizeof(*cfg->declined_message_types),
-		stasis_declined_config_destructor);
-	if (!cfg->declined_message_types) {
-		ao2_ref(cfg, -1);
-		return NULL;
-	}
-
-	cfg->declined_message_types->declined = ast_str_container_alloc(13);
-	if (!cfg->declined_message_types->declined) {
-		ao2_ref(cfg, -1);
-		return NULL;
-	}
-
-	return cfg;
-}
-
-int stasis_message_type_declined(const char *name)
-{
-	RAII_VAR(struct stasis_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-	char *name_in_declined;
-	int res;
-
-	if (!cfg || !cfg->declined_message_types) {
-		return 0;
-	}
-
-	name_in_declined = ao2_find(cfg->declined_message_types->declined, name, OBJ_SEARCH_KEY);
-	res = name_in_declined ? 1 : 0;
-	ao2_cleanup(name_in_declined);
-	if (res) {
-		ast_log(LOG_NOTICE, "Declining to allocate Stasis message type '%s' due to configuration\n", name);
-	}
-	return res;
-}
-
-static int declined_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct stasis_declined_config *declined = obj;
-
-	if (ast_strlen_zero(var->value)) {
-		return 0;
-	}
-
-	if (ast_str_container_add(declined->declined, var->value)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * @{ \brief Define multi user event message type(s).
- */
-
-STASIS_MESSAGE_TYPE_DEFN(ast_multi_user_event_type,
-	.to_json = multi_user_event_to_json,
-	.to_ami = multi_user_event_to_ami,
-	);
-
-/*! @} */
-
-/*! \brief Shutdown function */
-static void stasis_exit(void)
-{
-	ast_threadpool_shutdown(pool);
-	pool = NULL;
-}
-
-/*! \brief Cleanup function for graceful shutdowns */
-static void stasis_cleanup(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_subscription_change_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_multi_user_event_type);
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(globals);
-}
-
-int stasis_init(void)
-{
-	RAII_VAR(struct stasis_config *, cfg, NULL, ao2_cleanup);
-	int cache_init;
-	struct ast_threadpool_options threadpool_opts = { 0, };
-
-	/* Be sure the types are cleaned up after the message bus */
-	ast_register_cleanup(stasis_cleanup);
-	ast_register_atexit(stasis_exit);
-
-	if (aco_info_init(&cfg_info)) {
-		return -1;
-	}
-
-	aco_option_register_custom(&cfg_info, "decline", ACO_EXACT,
-		declined_options, "", declined_handler, 0);
-	aco_option_register(&cfg_info, "initial_size", ACO_EXACT,
-		threadpool_options, "5", OPT_INT_T, PARSE_IN_RANGE,
-		FLDSET(struct stasis_threadpool_conf, initial_size), 0,
-		INT_MAX);
-	aco_option_register(&cfg_info, "idle_timeout_sec", ACO_EXACT,
-		threadpool_options, "20", OPT_INT_T, PARSE_IN_RANGE,
-		FLDSET(struct stasis_threadpool_conf, idle_timeout_sec), 0,
-		INT_MAX);
-	aco_option_register(&cfg_info, "max_size", ACO_EXACT,
-		threadpool_options, "50", OPT_INT_T, PARSE_IN_RANGE,
-		FLDSET(struct stasis_threadpool_conf, max_size), 0,
-		INT_MAX);
-
-	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
-		struct stasis_config *default_cfg = stasis_config_alloc();
-
-		if (!default_cfg) {
-			return -1;
-		}
-
-		if (aco_set_defaults(&threadpool_option, "threadpool", default_cfg->threadpool_options)) {
-			ast_log(LOG_ERROR, "Failed to initialize defaults on Stasis configuration object\n");
-			ao2_ref(default_cfg, -1);
-			return -1;
-		}
-
-		if (aco_set_defaults(&declined_option, "declined_message_types", default_cfg->declined_message_types)) {
-			ast_log(LOG_ERROR, "Failed to load stasis.conf and failed to initialize defaults.\n");
-			return -1;
-		}
-
-		ast_log(LOG_NOTICE, "Could not load Stasis configuration; using defaults\n");
-		ao2_global_obj_replace_unref(globals, default_cfg);
-		cfg = default_cfg;
-	} else {
-		cfg = ao2_global_obj_ref(globals);
-		if (!cfg) {
-			ast_log(LOG_ERROR, "Failed to obtain Stasis configuration object\n");
-			return -1;
-		}
-	}
-
-	threadpool_opts.version = AST_THREADPOOL_OPTIONS_VERSION;
-	threadpool_opts.initial_size = cfg->threadpool_options->initial_size;
-	threadpool_opts.auto_increment = 1;
-	threadpool_opts.max_size = cfg->threadpool_options->max_size;
-	threadpool_opts.idle_timeout = cfg->threadpool_options->idle_timeout_sec;
-	pool = ast_threadpool_create("stasis-core", NULL, &threadpool_opts);
-	if (!pool) {
-		ast_log(LOG_ERROR, "Failed to create 'stasis-core' threadpool\n");
-		return -1;
-	}
-
-	cache_init = stasis_cache_init();
-	if (cache_init != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(stasis_subscription_change_type) != 0) {
-		return -1;
-	}
-	if (STASIS_MESSAGE_TYPE_INIT(ast_multi_user_event_type) != 0) {
-		return -1;
-	}
-
-	return 0;
-}
-
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
deleted file mode 100644
index 3c60a52..0000000
--- a/main/stasis_bridges.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Messages and Data Types for Bridge Objects
- *
- * \author Kinsey Moore <kmoore at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427870 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_cache_pattern.h"
-#include "asterisk/channel.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_technology.h"
-
-/* The container of channel snapshots in a bridge snapshot should always be
-   equivalent to a linked list; otherwise things (like CDRs) that depend on some
-   consistency in the ordering of channels in a bridge will break. */
-#define SNAPSHOT_CHANNELS_BUCKETS 1
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="BlindTransfer">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a blind transfer is complete.</synopsis>
-			<syntax>
-				<parameter name="Result">
-					<para>Indicates if the transfer was successful or if it failed.</para>
-					<enumlist>
-						<enum name="Fail"><para>An internal error occurred.</para></enum>
-						<enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
-						<enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
-						<enum name="Success"><para>Transfer completed successfully</para></enum>
-					</enumlist>
-					<note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
-					contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
-				</parameter>
-				<channel_snapshot prefix="Transferer"/>
-				<channel_snapshot prefix="Transferee"/>
-				<bridge_snapshot/>
-				<parameter name="IsExternal">
-					<para>Indicates if the transfer was performed outside of Asterisk. For instance,
-					a channel protocol native transfer is external. A DTMF transfer is internal.</para>
-						<enumlist>
-							<enum name="Yes" />
-							<enum name="No" />
-						</enumlist>
-				</parameter>
-				<parameter name="Context">
-					<para>Destination context for the blind transfer.</para>
-				</parameter>
-				<parameter name="Extension">
-					<para>Destination extension for the blind transfer.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AttendedTransfer">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when an attended transfer is complete.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
-				<channel_snapshot prefix="OrigTransferer"/>
-				<bridge_snapshot prefix="Orig"/>
-				<channel_snapshot prefix="SecondTransferer"/>
-				<bridge_snapshot prefix="Second"/>
-				<parameter name="DestType">
-					<para>Indicates the method by which the attended transfer completed.</para>
-					<enumlist>
-						<enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
-						<enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
-						<enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
-						<enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
-						<enum name="Fail"><para>The transfer failed.</para></enum>
-					</enumlist>
-				</parameter>
-				<parameter name="DestBridgeUniqueid">
-					<para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
-					<note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
-				</parameter>
-				<parameter name="DestApp">
-					<para>Indicates the application that is running when the transfer completes</para>
-					<note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
-				</parameter>
-				<channel_snapshot prefix="LocalOne"/>
-				<channel_snapshot prefix="LocalTwo"/>
-				<parameter name="DestTransfererChannel">
-					<para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
-					<note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
-				</parameter>
-				<channel_snapshot prefix="Transferee" />
-			</syntax>
-			<description>
-				<para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
-				and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
-				transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
-				<para>	<replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
-				<para>	<replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
-				<para>	<replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
-				<para>	<replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
-				<para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
-				calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
-				<para>	<replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
-				<para>	<replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
-				<para>	<replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
-				<para>	<replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
-			</description>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
-static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize);
-static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
-static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize);
-static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
-static struct ast_json *ast_channel_entered_bridge_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize);
-static struct ast_json *ast_channel_left_bridge_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize);
-static struct ast_json *ast_bridge_merge_message_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize);
-
-static struct stasis_cp_all *bridge_cache_all;
-
-/*!
- * @{ \brief Define bridge message types.
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type,
-	.to_json = ast_bridge_merge_message_to_json);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type,
-	.to_json = ast_channel_entered_bridge_to_json);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type,
-	.to_json = ast_channel_left_bridge_to_json);
-STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type,
-	.to_json = blind_transfer_to_json,
-	.to_ami = blind_transfer_to_ami);
-STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type,
-	.to_json = attended_transfer_to_json,
-	.to_ami = attended_transfer_to_ami);
-/*! @} */
-
-struct stasis_cache *ast_bridge_cache(void)
-{
-	return stasis_cp_all_cache(bridge_cache_all);
-}
-
-struct stasis_topic *ast_bridge_topic_all(void)
-{
-	return stasis_cp_all_topic(bridge_cache_all);
-}
-
-struct stasis_topic *ast_bridge_topic_all_cached(void)
-{
-	return stasis_cp_all_topic_cached(bridge_cache_all);
-}
-
-int bridge_topics_init(struct ast_bridge *bridge)
-{
-	if (ast_strlen_zero(bridge->uniqueid)) {
-		ast_log(LOG_ERROR, "Bridge id initialization required\n");
-		return -1;
-	}
-	bridge->topics = stasis_cp_single_create(bridge_cache_all,
-		bridge->uniqueid);
-	if (!bridge->topics) {
-		return -1;
-	}
-	return 0;
-}
-
-struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
-{
-	if (!bridge) {
-		return ast_bridge_topic_all();
-	}
-
-	return stasis_cp_single_topic(bridge->topics);
-}
-
-struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)
-{
-	if (!bridge) {
-		return ast_bridge_topic_all_cached();
-	}
-
-	return stasis_cp_single_topic_cached(bridge->topics);
-}
-
-/*! \brief Destructor for bridge snapshots */
-static void bridge_snapshot_dtor(void *obj)
-{
-	struct ast_bridge_snapshot *snapshot = obj;
-	ast_string_field_free_memory(snapshot);
-	ao2_cleanup(snapshot->channels);
-	snapshot->channels = NULL;
-}
-
-struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
-	struct ast_bridge_channel *bridge_channel;
-
-	snapshot = ao2_alloc(sizeof(*snapshot), bridge_snapshot_dtor);
-	if (!snapshot || ast_string_field_init(snapshot, 128)) {
-		return NULL;
-	}
-
-	snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
-	if (!snapshot->channels) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-		if (ast_str_container_add(snapshot->channels,
-				ast_channel_uniqueid(bridge_channel->chan))) {
-			return NULL;
-		}
-	}
-
-	ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
-	ast_string_field_set(snapshot, technology, bridge->technology->name);
-	ast_string_field_set(snapshot, subclass, bridge->v_table->name);
-	ast_string_field_set(snapshot, creator, bridge->creator);
-	ast_string_field_set(snapshot, name, bridge->name);
-
-	snapshot->feature_flags = bridge->feature_flags;
-	snapshot->capabilities = bridge->technology->capabilities;
-	snapshot->num_channels = bridge->num_channels;
-	snapshot->num_active = bridge->num_active;
-
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-void ast_bridge_publish_state(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!ast_bridge_snapshot_type()) {
-		return;
-	}
-
-	ast_assert(bridge != NULL);
-
-	snapshot = ast_bridge_snapshot_create(bridge);
-	if (!snapshot) {
-		return;
-	}
-
-	msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic(bridge), msg);
-}
-
-static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
-	struct ast_bridge_blob *obj)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	ast_assert(obj != NULL);
-
-	msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic(bridge), msg);
-}
-
-/*! \brief Destructor for bridge merge messages */
-static void bridge_merge_message_dtor(void *obj)
-{
-	struct ast_bridge_merge_message *msg = obj;
-
-	ao2_cleanup(msg->to);
-	msg->to = NULL;
-	ao2_cleanup(msg->from);
-	msg->from = NULL;
-}
-
-/*! \brief Bridge merge message creation helper */
-static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
-{
-	RAII_VAR(struct ast_bridge_merge_message *, msg, NULL, ao2_cleanup);
-
-	msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
-	if (!msg) {
-		return NULL;
-	}
-
-	msg->to = ast_bridge_snapshot_create(to);
-	if (!msg->to) {
-		return NULL;
-	}
-
-	msg->from = ast_bridge_snapshot_create(from);
-	if (!msg->from) {
-		return NULL;
-	}
-
-	ao2_ref(msg, +1);
-	return msg;
-}
-
-static struct ast_json *ast_bridge_merge_message_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_bridge_merge_message *merge = stasis_message_data(msg);
-	RAII_VAR(struct ast_json *, json_bridge_to,
-		ast_bridge_snapshot_to_json(merge->to, sanitize), ast_json_unref);
-	RAII_VAR(struct ast_json *, json_bridge_from,
-		ast_bridge_snapshot_to_json(merge->from, sanitize), ast_json_unref);
-
-	if (!json_bridge_to || !json_bridge_from) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: O, s: O}",
-		"type", "BridgeMerged",
-		"timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL),
-		"bridge", json_bridge_to,
-		"bridge_from", json_bridge_from);
-}
-
-void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
-{
-	RAII_VAR(struct ast_bridge_merge_message *, merge_msg, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!ast_bridge_merge_message_type()) {
-		return;
-	}
-
-	ast_assert(to != NULL);
-	ast_assert(from != NULL);
-
-	merge_msg = bridge_merge_message_create(to, from);
-	if (!merge_msg) {
-		return;
-	}
-
-	msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic_all(), msg);
-}
-
-static void bridge_blob_dtor(void *obj)
-{
-	struct ast_bridge_blob *event = obj;
-	ao2_cleanup(event->bridge);
-	event->bridge = NULL;
-	ao2_cleanup(event->channel);
-	event->channel = NULL;
-	ast_json_unref(event->blob);
-	event->blob = NULL;
-}
-
-struct stasis_message *ast_bridge_blob_create(
-	struct stasis_message_type *message_type,
-	struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct ast_json *blob)
-{
-	RAII_VAR(struct ast_bridge_blob *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!message_type) {
-		return NULL;
-	}
-
-	obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
-	if (!obj) {
-		return NULL;
-	}
-
-	if (bridge) {
-		obj->bridge = ast_bridge_snapshot_create(bridge);
-		if (obj->bridge == NULL) {
-			return NULL;
-		}
-	}
-
-	if (chan) {
-		obj->channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
-		if (obj->channel == NULL) {
-			return NULL;
-		}
-	}
-
-	if (blob) {
-		obj->blob = ast_json_ref(blob);
-	}
-
-	msg = stasis_message_create(message_type, obj);
-	if (!msg) {
-		return NULL;
-	}
-
-	ao2_ref(msg, +1);
-	return msg;
-}
-
-void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
-		struct ast_channel *swap)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	if (swap) {
-		blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
-		if (!blob) {
-			return;
-		}
-	}
-
-	msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
-	if (!msg) {
-		return;
-	}
-
-	/* enter blob first, then state */
-	stasis_publish(ast_bridge_topic(bridge), msg);
-	bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
-}
-
-void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
-	if (!msg) {
-		return;
-	}
-
-	/* state first, then leave blob (opposite of enter, preserves nesting of events) */
-	bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
-	stasis_publish(ast_bridge_topic(bridge), msg);
-}
-
-static struct ast_json *simple_bridge_channel_event(
-	const char *type,
-	struct ast_bridge_snapshot *bridge_snapshot,
-	struct ast_channel_snapshot *channel_snapshot,
-	const struct timeval *tv,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, json_bridge,
-		ast_bridge_snapshot_to_json(bridge_snapshot, sanitize), ast_json_unref);
-	RAII_VAR(struct ast_json *, json_channel,
-		ast_channel_snapshot_to_json(channel_snapshot, sanitize), ast_json_unref);
-
-	if (!json_bridge || !json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: O, s: O}",
-		"type", type,
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"bridge", json_bridge,
-		"channel", json_channel);
-}
-
-struct ast_json *ast_channel_entered_bridge_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_bridge_blob *obj = stasis_message_data(msg);
-
-	return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
-		obj->channel, stasis_message_timestamp(msg), sanitize);
-}
-
-struct ast_json *ast_channel_left_bridge_to_json(
-	struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_bridge_blob *obj = stasis_message_data(msg);
-
-	return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
-		obj->channel, stasis_message_timestamp(msg), sanitize);
-}
-
-static struct ast_json *container_to_json_array(struct ao2_container *items,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, json_items, ast_json_array_create(), ast_json_unref);
-	char *item;
-	struct ao2_iterator it;
-	if (!json_items) {
-		return NULL;
-	}
-
-	for (it = ao2_iterator_init(items, 0);
-		(item = ao2_iterator_next(&it)); ao2_cleanup(item)) {
-		if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) {
-			continue;
-		}
-
-		if (ast_json_array_append(json_items, ast_json_string_create(item))) {
-			ao2_cleanup(item);
-			ao2_iterator_destroy(&it);
-			return NULL;
-		}
-	}
-	ao2_iterator_destroy(&it);
-
-	return ast_json_ref(json_items);
-}
-
-static const char *capability2str(uint32_t capabilities)
-{
-	if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
-		return "holding";
-	} else {
-		return "mixing";
-	}
-}
-
-struct ast_json *ast_bridge_snapshot_to_json(
-	const struct ast_bridge_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, json_bridge, NULL, ast_json_unref);
-	struct ast_json *json_channels;
-
-	if (snapshot == NULL) {
-		return NULL;
-	}
-
-	json_channels = container_to_json_array(snapshot->channels, sanitize);
-	if (!json_channels) {
-		return NULL;
-	}
-
-	json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}",
-		"id", snapshot->uniqueid,
-		"technology", snapshot->technology,
-		"bridge_type", capability2str(snapshot->capabilities),
-		"bridge_class", snapshot->subclass,
-		"creator", snapshot->creator,
-		"name", snapshot->name,
-		"channels", json_channels);
-	if (!json_bridge) {
-		return NULL;
-	}
-
-	return ast_json_ref(json_bridge);
-}
-
-/*!
- * \internal
- * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
- *
- * \param pair A bridge and channel to get snapshots of
- * \param[out] snapshot_pair An allocated snapshot pair.
- * \retval 0 Success
- * \retval non-zero Failure
- */
-static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge,
-		struct ast_bridge_channel_snapshot_pair *snapshot_pair)
-{
-	if (bridge) {
-		ast_bridge_lock(bridge);
-		snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(bridge);
-		ast_bridge_unlock(bridge);
-		if (!snapshot_pair->bridge_snapshot) {
-			return -1;
-		}
-	}
-
-	snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(channel));
-	if (!snapshot_pair->channel_snapshot) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
- *
- * \param pair The snapshot pair whose fields are to be cleaned up
- */
-static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
-{
-	ao2_cleanup(pair->bridge_snapshot);
-	ao2_cleanup(pair->channel_snapshot);
-}
-
-static const char *result_strs[] = {
-	[AST_BRIDGE_TRANSFER_FAIL] = "Fail",
-	[AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
-	[AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
-	[AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
-};
-
-static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
-	struct ast_json *json_transferer;
-	struct ast_json *json_transferee = NULL;
-	struct ast_json *out;
-	struct ast_json *json_replace = NULL;
-	const struct timeval *tv = stasis_message_timestamp(msg);
-
-	json_transferer = ast_channel_snapshot_to_json(transfer_msg->transferer, sanitize);
-	if (!json_transferer) {
-		return NULL;
-	}
-
-	if (transfer_msg->transferee) {
-		json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
-		if (!json_transferee) {
-			ast_json_unref(json_transferer);
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->replace_channel) {
-		json_replace = ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize);
-		if (!json_replace) {
-			ast_json_unref(json_transferee);
-			ast_json_unref(json_transferer);
-			return NULL;
-		}
-	}
-
-	out = ast_json_pack("{s: s, s: o, s: o, s: s, s: s, s: s, s: o}",
-		"type", "BridgeBlindTransfer",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"channel", json_transferer,
-		"exten", transfer_msg->exten,
-		"context", transfer_msg->context,
-		"result", result_strs[transfer_msg->result],
-		"is_external", ast_json_boolean(transfer_msg->is_external));
-
-	if (!out) {
-		ast_json_unref(json_transferee);
-		ast_json_unref(json_replace);
-		return NULL;
-	}
-
-	if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
-		ast_json_unref(out);
-		ast_json_unref(json_replace);
-		return NULL;
-	}
-
-	if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
-		ast_json_unref(out);
-		return NULL;
-	}
-
-	if (transfer_msg->bridge) {
-		struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
-				transfer_msg->bridge, sanitize);
-
-		if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
-			ast_json_unref(out);
-			return NULL;
-		}
-	}
-
-	return out;
-}
-
-static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, transferer_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
-	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
-
-	if (!transfer_msg) {
-		return NULL;
-	}
-
-	transferer_state = ast_manager_build_channel_state_string_prefix(
-			transfer_msg->transferer, "Transferer");
-	if (!transferer_state) {
-		return NULL;
-	}
-
-	if (transfer_msg->bridge) {
-		bridge_state = ast_manager_build_bridge_state_string(transfer_msg->bridge);
-		if (!bridge_state) {
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->transferee) {
-		transferee_state = ast_manager_build_channel_state_string_prefix(
-				transfer_msg->transferee, "Transferee");
-		if (!transferee_state) {
-			return NULL;
-		}
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
-			"Result: %s\r\n"
-			"%s"
-			"%s"
-			"%s"
-			"IsExternal: %s\r\n"
-			"Context: %s\r\n"
-			"Extension: %s\r\n",
-			result_strs[transfer_msg->result],
-			ast_str_buffer(transferer_state),
-			transferee_state ? ast_str_buffer(transferee_state) : "",
-			bridge_state ? ast_str_buffer(bridge_state) : "",
-			transfer_msg->is_external ? "Yes" : "No",
-			transfer_msg->context,
-			transfer_msg->exten);
-}
-
-static void blind_transfer_dtor(void *obj)
-{
-	struct ast_blind_transfer_message *msg = obj;
-
-	ao2_cleanup(msg->transferer);
-	ao2_cleanup(msg->bridge);
-	ao2_cleanup(msg->transferee);
-	ao2_cleanup(msg->replace_channel);
-}
-
-struct ast_blind_transfer_message *ast_blind_transfer_message_create(int is_external,
-		struct ast_channel *transferer, const char *exten, const char *context)
-{
-	struct ast_blind_transfer_message *msg;
-
-	msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
-	if (!msg) {
-		return NULL;
-	}
-
-	msg->transferer = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferer));
-	if (!msg->transferer) {
-		ao2_cleanup(msg);
-		return NULL;
-	}
-
-	msg->is_external = is_external;
-	ast_copy_string(msg->context, context, sizeof(msg->context));
-	ast_copy_string(msg->exten, exten, sizeof(msg->exten));
-
-	return msg;
-}
-
-
-void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
-{
-	struct stasis_message *stasis;
-
-	stasis = stasis_message_create(ast_blind_transfer_type(), transfer_message);
-	if (!stasis) {
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic_all(), stasis);
-
-	ao2_cleanup(stasis);
-}
-
-static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
-	RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
-	struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
-	struct ast_json *json_transferee = NULL, *json_target = NULL;
-	const struct timeval *tv = stasis_message_timestamp(msg);
-	int res = 0;
-
-	json_transferer1 = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
-	if (!json_transferer1) {
-		return NULL;
-	}
-
-	json_transferer2 = ast_channel_snapshot_to_json(transfer_msg->to_transfer_target.channel_snapshot, sanitize);
-	if (!json_transferer2) {
-		ast_json_unref(json_transferer1);
-		return NULL;
-	}
-
-	if (transfer_msg->transferee) {
-		json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
-		if (!json_transferee) {
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->target) {
-		json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
-		if (!json_target) {
-			return NULL;
-		}
-	}
-
-	out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: o}",
-		"type", "BridgeAttendedTransfer",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"transferer_first_leg", json_transferer1,
-		"transferer_second_leg", json_transferer2,
-		"result", result_strs[transfer_msg->result],
-		"is_external", ast_json_boolean(transfer_msg->is_external));
-	if (!out) {
-		return NULL;
-	}
-	if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
-		return NULL;
-	}
-	if (json_target && ast_json_object_set(out, "transfer_target", json_target)) {
-		return NULL;
-	}
-
-	if (transfer_msg->to_transferee.bridge_snapshot) {
-		json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transferee.bridge_snapshot, sanitize);
-
-		if (!json_bridge) {
-			return NULL;
-		}
-
-		res |= ast_json_object_set(out, "transferer_first_leg_bridge", json_bridge);
-	}
-
-	if (transfer_msg->to_transfer_target.bridge_snapshot) {
-		json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transfer_target.bridge_snapshot, sanitize);
-
-		if (!json_bridge) {
-			return NULL;
-		}
-
-		res |= ast_json_object_set(out, "transferer_second_leg_bridge", json_bridge);
-	}
-
-	switch (transfer_msg->dest_type) {
-	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
-		res |= ast_json_object_set(out, "destination_type", ast_json_string_create("bridge"));
-		res |= ast_json_object_set(out, "destination_bridge", ast_json_string_create(transfer_msg->dest.bridge));
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
-		res |= ast_json_object_set(out, "replace_channel", ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize));
-		/* fallthrough */
-	case AST_ATTENDED_TRANSFER_DEST_APP:
-		res |= ast_json_object_set(out, "destination_type", ast_json_string_create("application"));
-		res |= ast_json_object_set(out, "destination_application", ast_json_string_create(transfer_msg->dest.app));
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_LINK:
-		res |= ast_json_object_set(out, "destination_type", ast_json_string_create("link"));
-
-		json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[0], sanitize);
-		if (!json_channel) {
-			return NULL;
-		}
-		res |= ast_json_object_set(out, "destination_link_first_leg", json_channel);
-
-		json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[1], sanitize);
-		if (!json_channel) {
-			return NULL;
-		}
-		res |= ast_json_object_set(out, "destination_link_second_leg", json_channel);
-
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-		res |= ast_json_object_set(out, "destination_type", ast_json_string_create("threeway"));
-
-		json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.threeway.channel_snapshot, sanitize);
-		if (!json_channel) {
-			return NULL;
-		}
-		res |= ast_json_object_set(out, "destination_threeway_channel", json_channel);
-
-		json_bridge = ast_bridge_snapshot_to_json(transfer_msg->dest.threeway.bridge_snapshot, sanitize);
-		if (!json_bridge) {
-			return NULL;
-		}
-		res |= ast_json_object_set(out, "destination_threeway_bridge", json_bridge);
-
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_FAIL:
-		res |= ast_json_object_set(out, "destination_type", ast_json_string_create("fail"));
-		break;
-	}
-
-	if (res) {
-		return NULL;
-	}
-
-	return ast_json_ref(out);
-}
-
-static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
-	RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_str *, target_state, NULL, ast_free_ptr);
-	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
-
-	if (!variable_data) {
-		return NULL;
-	}
-
-	transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
-	transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
-	if (!transferer1_state || !transferer2_state) {
-		return NULL;
-	}
-	if (transfer_msg->transferee) {
-		transferee_state = ast_manager_build_channel_state_string_prefix(transfer_msg->transferee, "Transferee");
-		if (!transferee_state) {
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->target) {
-		target_state = ast_manager_build_channel_state_string_prefix(transfer_msg->target, "TransferTarget");
-		if (!target_state) {
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->to_transferee.bridge_snapshot) {
-		bridge1_state = ast_manager_build_bridge_state_string_prefix(
-			transfer_msg->to_transferee.bridge_snapshot, "Orig");
-		if (!bridge1_state) {
-			return NULL;
-		}
-	}
-
-	if (transfer_msg->to_transfer_target.bridge_snapshot) {
-		bridge2_state = ast_manager_build_bridge_state_string_prefix(
-			transfer_msg->to_transfer_target.bridge_snapshot, "Second");
-		if (!bridge2_state) {
-			return NULL;
-		}
-	}
-
-	switch (transfer_msg->dest_type) {
-	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
-		ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
-		ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_APP:
-	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
-		ast_str_append(&variable_data, 0, "DestType: App\r\n");
-		ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_LINK:
-		local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
-		local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
-		if (!local1_state || !local2_state) {
-			return NULL;
-		}
-		ast_str_append(&variable_data, 0, "DestType: Link\r\n");
-		ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
-		ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-		ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
-		ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
-		ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
-		break;
-	case AST_ATTENDED_TRANSFER_DEST_FAIL:
-		ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
-		break;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
-			"Result: %s\r\n"
-			"%s"
-			"%s"
-			"%s"
-			"%s"
-			"%s"
-			"%s"
-			"IsExternal: %s\r\n"
-			"%s",
-			result_strs[transfer_msg->result],
-			ast_str_buffer(transferer1_state),
-			bridge1_state ? ast_str_buffer(bridge1_state) : "",
-			ast_str_buffer(transferer2_state),
-			bridge2_state ? ast_str_buffer(bridge2_state) : "",
-			transferee_state ? ast_str_buffer(transferee_state) : "",
-			target_state ? ast_str_buffer(target_state) : "",
-			transfer_msg->is_external ? "Yes" : "No",
-			ast_str_buffer(variable_data));
-}
-
-static void attended_transfer_dtor(void *obj)
-{
-	struct ast_attended_transfer_message *msg = obj;
-	int i;
-
-	bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
-	bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
-	ao2_cleanup(msg->replace_channel);
-	ao2_cleanup(msg->transferee);
-	ao2_cleanup(msg->target);
-
-	if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
-		return;
-	}
-
-	for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
-		ao2_cleanup(msg->dest.links[i]);
-	}
-}
-
-struct ast_attended_transfer_message *ast_attended_transfer_message_create(int is_external,
-		struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
-		struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
-		struct ast_channel *transferee, struct ast_channel *transfer_target)
-{
-	struct ast_attended_transfer_message *transfer_msg;
-
-	transfer_msg = ao2_alloc(sizeof(*transfer_msg), attended_transfer_dtor);
-	if (!transfer_msg) {
-		return NULL;
-	}
-
-	if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->to_transferee) ||
-			bridge_channel_snapshot_pair_init(to_transfer_target, target_bridge, &transfer_msg->to_transfer_target)) {
-		ao2_cleanup(transfer_msg);
-		return NULL;
-	}
-
-	if (transferee) {
-		transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
-		if (!transfer_msg->transferee) {
-			ao2_cleanup(transfer_msg);
-			return NULL;
-		}
-	} else if (transferee_bridge) {
-		transferee = ast_bridge_peer(transferee_bridge, to_transferee);
-		if (transferee) {
-			transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
-			ao2_cleanup(transferee);
-			if (!transfer_msg->transferee) {
-				ao2_cleanup(transfer_msg);
-				return NULL;
-			}
-		}
-	}
-
-	if (transfer_target) {
-		transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
-		if (!transfer_msg->target) {
-			ao2_cleanup(transfer_msg);
-			return NULL;
-		}
-	} else if (target_bridge) {
-		transfer_target = ast_bridge_peer(target_bridge, to_transfer_target);
-		if (transfer_target) {
-			transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
-			ao2_cleanup(transfer_target);
-			if (!transfer_msg->target) {
-				ao2_cleanup(transfer_msg);
-				return NULL;
-			}
-		}
-	}
-
-	return transfer_msg;
-}
-
-int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_bridge *final_bridge)
-{
-	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
-	ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
-			sizeof(transfer_msg->dest.bridge));
-
-	return 0;
-}
-
-int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
-{
-	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
-
-	if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
-		transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
-	} else {
-		transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
-	}
-
-	if (!strcmp(survivor_bridge->uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
-		transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
-	} else {
-		transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
-	}
-
-	return 0;
-}
-
-int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg,
-		const char *app, struct ast_channel *replace_channel)
-{
-	transfer_msg->dest_type = replace_channel ? AST_ATTENDED_TRANSFER_DEST_LOCAL_APP : AST_ATTENDED_TRANSFER_DEST_APP;
-
-	if (replace_channel) {
-		transfer_msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
-		if (!transfer_msg->replace_channel) {
-			return -1;
-		}
-	}
-
-	ast_copy_string(transfer_msg->dest.app, app, sizeof(transfer_msg->dest.app));
-
-	return 0;
-}
-
-int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg,
-		struct ast_channel *locals[2])
-{
-	int i;
-
-	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
-	for (i = 0; i < 2; ++i) {
-		transfer_msg->dest.links[i] = ast_channel_snapshot_get_latest(ast_channel_uniqueid(locals[i]));
-		if (!transfer_msg->dest.links[i]) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic_all(), msg);
-}
-
-struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct ast_bridge_snapshot *snapshot;
-
-	ast_assert(!ast_strlen_zero(uniqueid));
-
-	message = stasis_cache_get(ast_bridge_cache(),
-			ast_bridge_snapshot_type(),
-			uniqueid);
-	if (!message) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(message);
-	if (!snapshot) {
-		return NULL;
-	}
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-/*! \brief snapshot ID getter for caching topic */
-static const char *bridge_snapshot_get_id(struct stasis_message *msg)
-{
-	struct ast_bridge_snapshot *snapshot;
-	if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
-		return NULL;
-	}
-	snapshot = stasis_message_data(msg);
-	return snapshot->uniqueid;
-}
-
-static void stasis_bridging_cleanup(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
-
-	ao2_cleanup(bridge_cache_all);
-	bridge_cache_all = NULL;
-}
-
-int ast_stasis_bridging_init(void)
-{
-	int res = 0;
-
-	ast_register_cleanup(stasis_bridging_cleanup);
-
-	bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",
-		bridge_snapshot_get_id);
-
-	if (!bridge_cache_all) {
-		return -1;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);
-
-	return res;
-}
diff --git a/main/stasis_cache.c b/main/stasis_cache.c
deleted file mode 100644
index 98e3965..0000000
--- a/main/stasis_cache.c
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Message API.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/hashtab.h"
-#include "asterisk/stasis_internal.h"
-#include "asterisk/stasis.h"
-#include "asterisk/utils.h"
-#include "asterisk/vector.h"
-
-#ifdef LOW_MEMORY
-#define NUM_CACHE_BUCKETS 17
-#else
-#define NUM_CACHE_BUCKETS 563
-#endif
-
-/*! \internal */
-struct stasis_cache {
-	struct ao2_container *entries;
-	snapshot_get_id id_fn;
-	cache_aggregate_calc_fn aggregate_calc_fn;
-	cache_aggregate_publish_fn aggregate_publish_fn;
-};
-
-/*! \internal */
-struct stasis_caching_topic {
-	struct stasis_cache *cache;
-	struct stasis_topic *topic;
-	struct stasis_topic *original_topic;
-	struct stasis_subscription *sub;
-};
-
-static void stasis_caching_topic_dtor(void *obj)
-{
-	struct stasis_caching_topic *caching_topic = obj;
-
-	/* Caching topics contain subscriptions, and must be manually
-	 * unsubscribed. */
-	ast_assert(!stasis_subscription_is_subscribed(caching_topic->sub));
-	/* If there are any messages in flight to this subscription; that would
-	 * be bad. */
-	ast_assert(stasis_subscription_is_done(caching_topic->sub));
-
-	ao2_cleanup(caching_topic->sub);
-	caching_topic->sub = NULL;
-	ao2_cleanup(caching_topic->cache);
-	caching_topic->cache = NULL;
-	ao2_cleanup(caching_topic->topic);
-	caching_topic->topic = NULL;
-	ao2_cleanup(caching_topic->original_topic);
-	caching_topic->original_topic = NULL;
-}
-
-struct stasis_topic *stasis_caching_get_topic(struct stasis_caching_topic *caching_topic)
-{
-	return caching_topic->topic;
-}
-
-struct stasis_caching_topic *stasis_caching_unsubscribe(struct stasis_caching_topic *caching_topic)
-{
-	if (!caching_topic) {
-		return NULL;
-	}
-
-	/*
-	 * The subscription may hold the last reference to this caching
-	 * topic, but we want to make sure the unsubscribe finishes
-	 * before kicking of the caching topic's dtor.
-	 */
-	ao2_ref(caching_topic, +1);
-
-	if (stasis_subscription_is_subscribed(caching_topic->sub)) {
-		/*
-		 * Increment the reference to hold on to it past the
-		 * unsubscribe. Will be cleaned up in dtor.
-		 */
-		ao2_ref(caching_topic->sub, +1);
-		stasis_unsubscribe(caching_topic->sub);
-	} else {
-		ast_log(LOG_ERROR, "stasis_caching_topic unsubscribed multiple times\n");
-	}
-	ao2_cleanup(caching_topic);
-	return NULL;
-}
-
-struct stasis_caching_topic *stasis_caching_unsubscribe_and_join(struct stasis_caching_topic *caching_topic)
-{
-	if (!caching_topic) {
-		return NULL;
-	}
-
-	/* Hold a ref past the unsubscribe */
-	ao2_ref(caching_topic, +1);
-	stasis_caching_unsubscribe(caching_topic);
-	stasis_subscription_join(caching_topic->sub);
-	ao2_cleanup(caching_topic);
-	return NULL;
-}
-
-/*!
- * \brief The key for an entry in the cache
- * \note The items in this struct must be immutable for the item in the cache
- */
-struct cache_entry_key {
-	/*! The message type of the item stored in the cache */
-	struct stasis_message_type *type;
-	/*! The unique ID of the item stored in the cache */
-	const char *id;
-	/*! The hash, computed from \c type and \c id */
-	unsigned int hash;
-};
-
-struct stasis_cache_entry {
-	struct cache_entry_key key;
-	/*! Aggregate snapshot of the stasis cache. */
-	struct stasis_message *aggregate;
-	/*! Local entity snapshot of the stasis event. */
-	struct stasis_message *local;
-	/*! Remote entity snapshots of the stasis event. */
-	AST_VECTOR(, struct stasis_message *) remote;
-};
-
-static void cache_entry_dtor(void *obj)
-{
-	struct stasis_cache_entry *entry = obj;
-	size_t idx;
-
-	ao2_cleanup(entry->key.type);
-	entry->key.type = NULL;
-	ast_free((char *) entry->key.id);
-	entry->key.id = NULL;
-
-	ao2_cleanup(entry->aggregate);
-	entry->aggregate = NULL;
-	ao2_cleanup(entry->local);
-	entry->local = NULL;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&entry->remote); ++idx) {
-		struct stasis_message *remote;
-
-		remote = AST_VECTOR_GET(&entry->remote, idx);
-		ao2_cleanup(remote);
-	}
-	AST_VECTOR_FREE(&entry->remote);
-}
-
-static void cache_entry_compute_hash(struct cache_entry_key *key)
-{
-	key->hash = ast_hashtab_hash_string(stasis_message_type_name(key->type));
-	key->hash += ast_hashtab_hash_string(key->id);
-}
-
-static struct stasis_cache_entry *cache_entry_create(struct stasis_message_type *type, const char *id, struct stasis_message *snapshot)
-{
-	struct stasis_cache_entry *entry;
-	int is_remote;
-
-	ast_assert(id != NULL);
-	ast_assert(snapshot != NULL);
-
-	if (!type) {
-		return NULL;
-	}
-
-	entry = ao2_alloc_options(sizeof(*entry), cache_entry_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!entry) {
-		return NULL;
-	}
-
-	entry->key.id = ast_strdup(id);
-	if (!entry->key.id) {
-		ao2_cleanup(entry);
-		return NULL;
-	}
-	entry->key.type = ao2_bump(type);
-	cache_entry_compute_hash(&entry->key);
-
-	is_remote = ast_eid_cmp(&ast_eid_default, stasis_message_eid(snapshot)) ? 1 : 0;
-	if (AST_VECTOR_INIT(&entry->remote, is_remote)) {
-		ao2_cleanup(entry);
-		return NULL;
-	}
-
-	if (is_remote) {
-		if (AST_VECTOR_APPEND(&entry->remote, snapshot)) {
-			ao2_cleanup(entry);
-			return NULL;
-		}
-	} else {
-		entry->local = snapshot;
-	}
-	ao2_bump(snapshot);
-
-	return entry;
-}
-
-static int cache_entry_hash(const void *obj, int flags)
-{
-	const struct stasis_cache_entry *object;
-	const struct cache_entry_key *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = &object->key;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-
-	return (int)key->hash;
-}
-
-static int cache_entry_cmp(void *obj, void *arg, int flags)
-{
-	const struct stasis_cache_entry *object_left = obj;
-	const struct stasis_cache_entry *object_right = arg;
-	const struct cache_entry_key *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = &object_right->key;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = object_left->key.type != right_key->type
-			|| strcmp(object_left->key.id, right_key->id);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* Not supported by container */
-		ast_assert(0);
-		cmp = -1;
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-static void cache_dtor(void *obj)
-{
-	struct stasis_cache *cache = obj;
-
-	ao2_cleanup(cache->entries);
-	cache->entries = NULL;
-}
-
-struct stasis_cache *stasis_cache_create_full(snapshot_get_id id_fn,
-	cache_aggregate_calc_fn aggregate_calc_fn,
-	cache_aggregate_publish_fn aggregate_publish_fn)
-{
-	struct stasis_cache *cache;
-
-	cache = ao2_alloc_options(sizeof(*cache), cache_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!cache) {
-		return NULL;
-	}
-
-	cache->entries = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0,
-		NUM_CACHE_BUCKETS, cache_entry_hash, NULL, cache_entry_cmp);
-	if (!cache->entries) {
-		ao2_cleanup(cache);
-		return NULL;
-	}
-
-	cache->id_fn = id_fn;
-	cache->aggregate_calc_fn = aggregate_calc_fn;
-	cache->aggregate_publish_fn = aggregate_publish_fn;
-
-	return cache;
-}
-
-struct stasis_cache *stasis_cache_create(snapshot_get_id id_fn)
-{
-	return stasis_cache_create_full(id_fn, NULL, NULL);
-}
-
-struct stasis_message *stasis_cache_entry_get_aggregate(struct stasis_cache_entry *entry)
-{
-	return entry->aggregate;
-}
-
-struct stasis_message *stasis_cache_entry_get_local(struct stasis_cache_entry *entry)
-{
-	return entry->local;
-}
-
-struct stasis_message *stasis_cache_entry_get_remote(struct stasis_cache_entry *entry, int idx)
-{
-	if (idx < AST_VECTOR_SIZE(&entry->remote)) {
-		return AST_VECTOR_GET(&entry->remote, idx);
-	}
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Find the cache entry in the cache entries container.
- *
- * \param entries Container of cached entries.
- * \param type Type of message to retrieve the cache entry.
- * \param id Identity of the snapshot to retrieve the cache entry.
- *
- * \note The entries container is already locked.
- *
- * \retval Cache-entry on success.
- * \retval NULL Not in cache.
- */
-static struct stasis_cache_entry *cache_find(struct ao2_container *entries, struct stasis_message_type *type, const char *id)
-{
-	struct cache_entry_key search_key;
-	struct stasis_cache_entry *entry;
-
-	search_key.type = type;
-	search_key.id = id;
-	cache_entry_compute_hash(&search_key);
-	entry = ao2_find(entries, &search_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-
-	/* Ensure that what we looked for is what we found. */
-	ast_assert(!entry
-		|| (!strcmp(stasis_message_type_name(entry->key.type),
-			stasis_message_type_name(type)) && !strcmp(entry->key.id, id)));
-	return entry;
-}
-
-/*!
- * \internal
- * \brief Remove the stasis snapshot in the cache entry determined by eid.
- *
- * \param entries Container of cached entries.
- * \param cached_entry The entry to remove the snapshot from.
- * \param eid Which snapshot in the cached entry.
- *
- * \note The entries container is already locked.
- *
- * \return Previous stasis entry snapshot.
- */
-static struct stasis_message *cache_remove(struct ao2_container *entries, struct stasis_cache_entry *cached_entry, const struct ast_eid *eid)
-{
-	struct stasis_message *old_snapshot;
-	int is_remote;
-
-	is_remote = ast_eid_cmp(eid, &ast_eid_default);
-	if (!is_remote) {
-		old_snapshot = cached_entry->local;
-		cached_entry->local = NULL;
-	} else {
-		int idx;
-
-		old_snapshot = NULL;
-		for (idx = 0; idx < AST_VECTOR_SIZE(&cached_entry->remote); ++idx) {
-			struct stasis_message *cur;
-
-			cur = AST_VECTOR_GET(&cached_entry->remote, idx);
-			if (!ast_eid_cmp(eid, stasis_message_eid(cur))) {
-				old_snapshot = AST_VECTOR_REMOVE_UNORDERED(&cached_entry->remote, idx);
-				break;
-			}
-		}
-	}
-
-	if (!cached_entry->local && !AST_VECTOR_SIZE(&cached_entry->remote)) {
-		ao2_unlink_flags(entries, cached_entry, OBJ_NOLOCK);
-	}
-
-	return old_snapshot;
-}
-
-/*!
- * \internal
- * \brief Update the stasis snapshot in the cache entry determined by eid.
- *
- * \param cached_entry The entry to remove the snapshot from.
- * \param eid Which snapshot in the cached entry.
- * \param new_snapshot Snapshot to replace the old snapshot.
- *
- * \return Previous stasis entry snapshot.
- */
-static struct stasis_message *cache_udpate(struct stasis_cache_entry *cached_entry, const struct ast_eid *eid, struct stasis_message *new_snapshot)
-{
-	struct stasis_message *old_snapshot;
-	int is_remote;
-	int idx;
-
-	is_remote = ast_eid_cmp(eid, &ast_eid_default);
-	if (!is_remote) {
-		old_snapshot = cached_entry->local;
-		cached_entry->local = ao2_bump(new_snapshot);
-		return old_snapshot;
-	}
-
-	old_snapshot = NULL;
-	for (idx = 0; idx < AST_VECTOR_SIZE(&cached_entry->remote); ++idx) {
-		struct stasis_message *cur;
-
-		cur = AST_VECTOR_GET(&cached_entry->remote, idx);
-		if (!ast_eid_cmp(eid, stasis_message_eid(cur))) {
-			old_snapshot = AST_VECTOR_REMOVE_UNORDERED(&cached_entry->remote, idx);
-			break;
-		}
-	}
-	if (!AST_VECTOR_APPEND(&cached_entry->remote, new_snapshot)) {
-		ao2_bump(new_snapshot);
-	}
-
-	return old_snapshot;
-}
-
-struct cache_put_snapshots {
-	/*! Old cache eid snapshot. */
-	struct stasis_message *old;
-	/*! Old cache aggregate snapshot. */
-	struct stasis_message *aggregate_old;
-	/*! New cache aggregate snapshot. */
-	struct stasis_message *aggregate_new;
-};
-
-static struct cache_put_snapshots cache_put(struct stasis_cache *cache,
-	struct stasis_message_type *type, const char *id, const struct ast_eid *eid,
-	struct stasis_message *new_snapshot)
-{
-	struct stasis_cache_entry *cached_entry;
-	struct cache_put_snapshots snapshots;
-
-	ast_assert(cache->entries != NULL);
-	ast_assert(eid != NULL);/* Aggregate snapshots not allowed to be put directly. */
-	ast_assert(new_snapshot == NULL ||
-		type == stasis_message_type(new_snapshot));
-
-	memset(&snapshots, 0, sizeof(snapshots));
-
-	ao2_wrlock(cache->entries);
-
-	cached_entry = cache_find(cache->entries, type, id);
-
-	/* Update the eid snapshot. */
-	if (!new_snapshot) {
-		/* Remove snapshot from cache */
-		if (cached_entry) {
-			snapshots.old = cache_remove(cache->entries, cached_entry, eid);
-		}
-	} else if (cached_entry) {
-		/* Update snapshot in cache */
-		snapshots.old = cache_udpate(cached_entry, eid, new_snapshot);
-	} else {
-		/* Insert into the cache */
-		cached_entry = cache_entry_create(type, id, new_snapshot);
-		if (cached_entry) {
-			ao2_link_flags(cache->entries, cached_entry, OBJ_NOLOCK);
-		}
-	}
-
-	/* Update the aggregate snapshot. */
-	if (cache->aggregate_calc_fn && cached_entry) {
-		snapshots.aggregate_new = cache->aggregate_calc_fn(cached_entry, new_snapshot);
-		snapshots.aggregate_old = cached_entry->aggregate;
-		cached_entry->aggregate = ao2_bump(snapshots.aggregate_new);
-	}
-
-	ao2_unlock(cache->entries);
-
-	ao2_cleanup(cached_entry);
-	return snapshots;
-}
-
-/*!
- * \internal
- * \brief Dump all entity snapshots in the cache entry into the given container.
- *
- * \param snapshots Container to put all snapshots in the cache entry.
- * \param entry Cache entry to use.
- *
- * \retval 0 on success.
- * \retval non-zero on error.
- */
-static int cache_entry_dump(struct ao2_container *snapshots, const struct stasis_cache_entry *entry)
-{
-	int idx;
-	int err = 0;
-
-	ast_assert(snapshots != NULL);
-	ast_assert(entry != NULL);
-
-	/* The aggregate snapshot is not a snapshot from an entity. */
-
-	if (entry->local) {
-		err |= !ao2_link(snapshots, entry->local);
-	}
-
-	for (idx = 0; !err && idx < AST_VECTOR_SIZE(&entry->remote); ++idx) {
-		struct stasis_message *snapshot;
-
-		snapshot = AST_VECTOR_GET(&entry->remote, idx);
-		err |= !ao2_link(snapshots, snapshot);
-	}
-
-	return err;
-}
-
-struct ao2_container *stasis_cache_get_all(struct stasis_cache *cache, struct stasis_message_type *type, const char *id)
-{
-	struct stasis_cache_entry *cached_entry;
-	struct ao2_container *found;
-
-	ast_assert(cache != NULL);
-	ast_assert(cache->entries != NULL);
-	ast_assert(id != NULL);
-
-	if (!type) {
-		return NULL;
-	}
-
-	found = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
-	if (!found) {
-		return NULL;
-	}
-
-	ao2_rdlock(cache->entries);
-
-	cached_entry = cache_find(cache->entries, type, id);
-	if (cached_entry && cache_entry_dump(found, cached_entry)) {
-		ao2_cleanup(found);
-		found = NULL;
-	}
-
-	ao2_unlock(cache->entries);
-
-	ao2_cleanup(cached_entry);
-	return found;
-}
-
-/*!
- * \internal
- * \brief Retrieve an item from the cache entry for a specific eid.
- *
- * \param entry Cache entry to use.
- * \param eid Specific entity id to retrieve.  NULL for aggregate.
- *
- * \note The returned snapshot has not had its reference bumped.
- *
- * \retval Snapshot from the cache.
- * \retval \c NULL if snapshot is not found.
- */
-static struct stasis_message *cache_entry_by_eid(const struct stasis_cache_entry *entry, const struct ast_eid *eid)
-{
-	int is_remote;
-	int idx;
-
-	if (!eid) {
-		/* Get aggregate. */
-		return entry->aggregate;
-	}
-
-	/* Get snapshot with specific eid. */
-	is_remote = ast_eid_cmp(eid, &ast_eid_default);
-	if (!is_remote) {
-		return entry->local;
-	}
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(&entry->remote); ++idx) {
-		struct stasis_message *cur;
-
-		cur = AST_VECTOR_GET(&entry->remote, idx);
-		if (!ast_eid_cmp(eid, stasis_message_eid(cur))) {
-			return cur;
-		}
-	}
-
-	return NULL;
-}
-
-struct stasis_message *stasis_cache_get_by_eid(struct stasis_cache *cache, struct stasis_message_type *type, const char *id, const struct ast_eid *eid)
-{
-	struct stasis_cache_entry *cached_entry;
-	struct stasis_message *snapshot = NULL;
-
-	ast_assert(cache != NULL);
-	ast_assert(cache->entries != NULL);
-	ast_assert(id != NULL);
-
-	if (!type) {
-		return NULL;
-	}
-
-	ao2_rdlock(cache->entries);
-
-	cached_entry = cache_find(cache->entries, type, id);
-	if (cached_entry) {
-		snapshot = cache_entry_by_eid(cached_entry, eid);
-		ao2_bump(snapshot);
-	}
-
-	ao2_unlock(cache->entries);
-
-	ao2_cleanup(cached_entry);
-	return snapshot;
-}
-
-struct stasis_message *stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id)
-{
-	return stasis_cache_get_by_eid(cache, type, id, &ast_eid_default);
-}
-
-struct cache_dump_data {
-	struct ao2_container *container;
-	struct stasis_message_type *type;
-	const struct ast_eid *eid;
-};
-
-static int cache_dump_by_eid_cb(void *obj, void *arg, int flags)
-{
-	struct cache_dump_data *cache_dump = arg;
-	struct stasis_cache_entry *entry = obj;
-
-	if (!cache_dump->type || entry->key.type == cache_dump->type) {
-		struct stasis_message *snapshot;
-
-		snapshot = cache_entry_by_eid(entry, cache_dump->eid);
-		if (snapshot) {
-			if (!ao2_link(cache_dump->container, snapshot)) {
-				ao2_cleanup(cache_dump->container);
-				cache_dump->container = NULL;
-				return CMP_STOP;
-			}
-		}
-	}
-
-	return 0;
-}
-
-struct ao2_container *stasis_cache_dump_by_eid(struct stasis_cache *cache, struct stasis_message_type *type, const struct ast_eid *eid)
-{
-	struct cache_dump_data cache_dump;
-
-	ast_assert(cache != NULL);
-	ast_assert(cache->entries != NULL);
-
-	cache_dump.eid = eid;
-	cache_dump.type = type;
-	cache_dump.container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
-	if (!cache_dump.container) {
-		return NULL;
-	}
-
-	ao2_callback(cache->entries, OBJ_MULTIPLE | OBJ_NODATA, cache_dump_by_eid_cb, &cache_dump);
-	return cache_dump.container;
-}
-
-struct ao2_container *stasis_cache_dump(struct stasis_cache *cache, struct stasis_message_type *type)
-{
-	return stasis_cache_dump_by_eid(cache, type, &ast_eid_default);
-}
-
-static int cache_dump_all_cb(void *obj, void *arg, int flags)
-{
-	struct cache_dump_data *cache_dump = arg;
-	struct stasis_cache_entry *entry = obj;
-
-	if (!cache_dump->type || entry->key.type == cache_dump->type) {
-		if (cache_entry_dump(cache_dump->container, entry)) {
-			ao2_cleanup(cache_dump->container);
-			cache_dump->container = NULL;
-			return CMP_STOP;
-		}
-	}
-
-	return 0;
-}
-
-struct ao2_container *stasis_cache_dump_all(struct stasis_cache *cache, struct stasis_message_type *type)
-{
-	struct cache_dump_data cache_dump;
-
-	ast_assert(cache != NULL);
-	ast_assert(cache->entries != NULL);
-
-	cache_dump.eid = NULL;
-	cache_dump.type = type;
-	cache_dump.container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
-	if (!cache_dump.container) {
-		return NULL;
-	}
-
-	ao2_callback(cache->entries, OBJ_MULTIPLE | OBJ_NODATA, cache_dump_all_cb, &cache_dump);
-	return cache_dump.container;
-}
-
-STASIS_MESSAGE_TYPE_DEFN(stasis_cache_clear_type);
-STASIS_MESSAGE_TYPE_DEFN(stasis_cache_update_type);
-
-struct stasis_message *stasis_cache_clear_create(struct stasis_message *id_message)
-{
-	return stasis_message_create(stasis_cache_clear_type(), id_message);
-}
-
-static void stasis_cache_update_dtor(void *obj)
-{
-	struct stasis_cache_update *update = obj;
-
-	ao2_cleanup(update->old_snapshot);
-	update->old_snapshot = NULL;
-	ao2_cleanup(update->new_snapshot);
-	update->new_snapshot = NULL;
-	ao2_cleanup(update->type);
-	update->type = NULL;
-}
-
-static struct stasis_message *update_create(struct stasis_message *old_snapshot, struct stasis_message *new_snapshot)
-{
-	struct stasis_cache_update *update;
-	struct stasis_message *msg;
-
-	ast_assert(old_snapshot != NULL || new_snapshot != NULL);
-
-	if (!stasis_cache_update_type()) {
-		return NULL;
-	}
-
-	update = ao2_alloc_options(sizeof(*update), stasis_cache_update_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!update) {
-		return NULL;
-	}
-
-	if (old_snapshot) {
-		ao2_ref(old_snapshot, +1);
-		update->old_snapshot = old_snapshot;
-		if (!new_snapshot) {
-			ao2_ref(stasis_message_type(old_snapshot), +1);
-			update->type = stasis_message_type(old_snapshot);
-		}
-	}
-	if (new_snapshot) {
-		ao2_ref(new_snapshot, +1);
-		update->new_snapshot = new_snapshot;
-		ao2_ref(stasis_message_type(new_snapshot), +1);
-		update->type = stasis_message_type(new_snapshot);
-	}
-
-	msg = stasis_message_create(stasis_cache_update_type(), update);
-
-	ao2_cleanup(update);
-	return msg;
-}
-
-static void caching_topic_exec(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_caching_topic *caching_topic_needs_unref;
-	struct stasis_caching_topic *caching_topic = data;
-	struct stasis_message *msg;
-	struct stasis_message *msg_put;
-	struct stasis_message_type *msg_type;
-	const struct ast_eid *msg_eid;
-	const char *msg_id;
-
-	ast_assert(caching_topic != NULL);
-	ast_assert(caching_topic->topic != NULL);
-	ast_assert(caching_topic->cache != NULL);
-	ast_assert(caching_topic->cache->id_fn != NULL);
-
-	if (stasis_subscription_final_message(sub, message)) {
-		caching_topic_needs_unref = caching_topic;
-	} else {
-		caching_topic_needs_unref = NULL;
-	}
-
-	msg_type = stasis_message_type(message);
-	if (stasis_cache_clear_type() == msg_type) {
-		/* Cache clear event. */
-		msg_put = NULL;
-		msg = stasis_message_data(message);
-		msg_type = stasis_message_type(msg);
-	} else {
-		/* Normal cache update event. */
-		msg_put = message;
-		msg = message;
-	}
-	ast_assert(msg_type != NULL);
-
-	msg_eid = stasis_message_eid(msg);/* msg_eid is NULL for aggregate message. */
-	msg_id = caching_topic->cache->id_fn(msg);
-	if (msg_id && msg_eid) {
-		struct stasis_message *update;
-		struct cache_put_snapshots snapshots;
-
-		/* Update the cache */
-		snapshots = cache_put(caching_topic->cache, msg_type, msg_id, msg_eid, msg_put);
-		if (snapshots.old || msg_put) {
-			update = update_create(snapshots.old, msg_put);
-			if (update) {
-				stasis_publish(caching_topic->topic, update);
-			}
-			ao2_cleanup(update);
-		} else {
-			ast_log(LOG_ERROR,
-				"Attempting to remove an item from the %s cache that isn't there: %s %s\n",
-				stasis_topic_name(caching_topic->topic),
-				stasis_message_type_name(msg_type), msg_id);
-		}
-
-		if (snapshots.aggregate_old != snapshots.aggregate_new) {
-			if (snapshots.aggregate_new && caching_topic->cache->aggregate_publish_fn) {
-				caching_topic->cache->aggregate_publish_fn(caching_topic->original_topic,
-					snapshots.aggregate_new);
-			}
-			update = update_create(snapshots.aggregate_old, snapshots.aggregate_new);
-			if (update) {
-				stasis_publish(caching_topic->topic, update);
-			}
-			ao2_cleanup(update);
-		}
-
-		ao2_cleanup(snapshots.old);
-		ao2_cleanup(snapshots.aggregate_old);
-		ao2_cleanup(snapshots.aggregate_new);
-	}
-
-	ao2_cleanup(caching_topic_needs_unref);
-}
-
-struct stasis_caching_topic *stasis_caching_topic_create(struct stasis_topic *original_topic, struct stasis_cache *cache)
-{
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
-	struct stasis_subscription *sub;
-	RAII_VAR(char *, new_name, NULL, ast_free);
-	int ret;
-
-	ret = ast_asprintf(&new_name, "%s-cached", stasis_topic_name(original_topic));
-	if (ret < 0) {
-		return NULL;
-	}
-
-	caching_topic = ao2_alloc_options(sizeof(*caching_topic),
-		stasis_caching_topic_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (caching_topic == NULL) {
-		return NULL;
-	}
-
-	caching_topic->topic = stasis_topic_create(new_name);
-	if (caching_topic->topic == NULL) {
-		return NULL;
-	}
-
-	ao2_ref(cache, +1);
-	caching_topic->cache = cache;
-
-	sub = internal_stasis_subscribe(original_topic, caching_topic_exec, caching_topic, 0, 0);
-	if (sub == NULL) {
-		return NULL;
-	}
-
-	ao2_ref(original_topic, +1);
-	caching_topic->original_topic = original_topic;
-
-	/* This is for the reference contained in the subscription above */
-	ao2_ref(caching_topic, +1);
-	caching_topic->sub = sub;
-
-	/* The subscription holds the reference, so no additional ref bump. */
-	return caching_topic;
-}
-
-static void stasis_cache_cleanup(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_cache_clear_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_cache_update_type);
-}
-
-int stasis_cache_init(void)
-{
-	ast_register_cleanup(stasis_cache_cleanup);
-
-	if (STASIS_MESSAGE_TYPE_INIT(stasis_cache_clear_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(stasis_cache_update_type) != 0) {
-		return -1;
-	}
-
-	return 0;
-}
-
diff --git a/main/stasis_cache_pattern.c b/main/stasis_cache_pattern.c
deleted file mode 100644
index 54c7b5a..0000000
--- a/main/stasis_cache_pattern.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Typical cache pattern for Stasis topics.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418997 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis_cache_pattern.h"
-
-struct stasis_cp_all {
-	struct stasis_topic *topic;
-	struct stasis_topic *topic_cached;
-	struct stasis_cache *cache;
-
-	struct stasis_forward *forward_all_to_cached;
-};
-
-struct stasis_cp_single {
-	struct stasis_topic *topic;
-	struct stasis_caching_topic *topic_cached;
-
-	struct stasis_forward *forward_topic_to_all;
-	struct stasis_forward *forward_cached_to_all;
-};
-
-static void all_dtor(void *obj)
-{
-	struct stasis_cp_all *all = obj;
-
-	ao2_cleanup(all->topic);
-	all->topic = NULL;
-	ao2_cleanup(all->topic_cached);
-	all->topic_cached = NULL;
-	ao2_cleanup(all->cache);
-	all->cache = NULL;
-	stasis_forward_cancel(all->forward_all_to_cached);
-	all->forward_all_to_cached = NULL;
-}
-
-struct stasis_cp_all *stasis_cp_all_create(const char *name,
-	snapshot_get_id id_fn)
-{
-	RAII_VAR(char *, cached_name, NULL, ast_free);
-	RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup);
-
-	all = ao2_t_alloc(sizeof(*all), all_dtor, name);
-	if (!all) {
-		return NULL;
-	}
-
-	ast_asprintf(&cached_name, "%s-cached", name);
-	if (!cached_name) {
-		return NULL;
-	}
-
-	all->topic = stasis_topic_create(name);
-	all->topic_cached = stasis_topic_create(cached_name);
-	all->cache = stasis_cache_create(id_fn);
-	all->forward_all_to_cached =
-		stasis_forward_all(all->topic, all->topic_cached);
-
-	if (!all->topic || !all->topic_cached || !all->cache ||
-		!all->forward_all_to_cached) {
-		return NULL;
-	}
-
-	ao2_ref(all, +1);
-	return all;
-}
-
-struct stasis_topic *stasis_cp_all_topic(struct stasis_cp_all *all)
-{
-	if (!all) {
-		return NULL;
-	}
-	return all->topic;
-}
-
-struct stasis_topic *stasis_cp_all_topic_cached(
-	struct stasis_cp_all *all)
-{
-	if (!all) {
-		return NULL;
-	}
-	return all->topic_cached;
-}
-
-struct stasis_cache *stasis_cp_all_cache(struct stasis_cp_all *all)
-{
-	if (!all) {
-		return NULL;
-	}
-	return all->cache;
-}
-
-static void one_dtor(void *obj)
-{
-	struct stasis_cp_single *one = obj;
-
-	/* Should already be unsubscribed */
-	ast_assert(one->topic_cached == NULL);
-	ast_assert(one->forward_topic_to_all == NULL);
-	ast_assert(one->forward_cached_to_all == NULL);
-
-	ao2_cleanup(one->topic);
-	one->topic = NULL;
-}
-
-struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
-	const char *name)
-{
-	RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);
-
-	one = ao2_t_alloc(sizeof(*one), one_dtor, name);
-	if (!one) {
-		return NULL;
-	}
-
-	one->topic = stasis_topic_create(name);
-	if (!one->topic) {
-		return NULL;
-	}
-	one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
-	if (!one->topic_cached) {
-		return NULL;
-	}
-
-	one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic);
-	if (!one->forward_topic_to_all) {
-		return NULL;
-	}
-	one->forward_cached_to_all = stasis_forward_all(
-		stasis_caching_get_topic(one->topic_cached), all->topic_cached);
-	if (!one->forward_cached_to_all) {
-		return NULL;
-	}
-
-	ao2_ref(one, +1);
-	return one;
-}
-
-void stasis_cp_single_unsubscribe(struct stasis_cp_single *one)
-{
-	if (!one) {
-		return;
-	}
-
-	stasis_forward_cancel(one->forward_topic_to_all);
-	one->forward_topic_to_all = NULL;
-	stasis_forward_cancel(one->forward_cached_to_all);
-	one->forward_cached_to_all = NULL;
-	stasis_caching_unsubscribe(one->topic_cached);
-	one->topic_cached = NULL;
-
-	ao2_cleanup(one);
-}
-
-struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one)
-{
-	if (!one) {
-		return NULL;
-	}
-	return one->topic;
-}
-
-struct stasis_topic *stasis_cp_single_topic_cached(
-	struct stasis_cp_single *one)
-{
-	if (!one) {
-		return NULL;
-	}
-	return stasis_caching_get_topic(one->topic_cached);
-}
-
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
deleted file mode 100644
index ccb9ee8..0000000
--- a/main/stasis_channels.c
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Messages and Data Types for Channel Objects
- *
- * \author \verbatim Matt Jordan <mjordan at digium.com> \endverbatim
- *
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/json.h"
-#include "asterisk/pbx.h"
-#include "asterisk/bridge.h"
-#include "asterisk/translate.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_cache_pattern.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/dial.h"
-#include "asterisk/linkedlists.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="VarSet">
-		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
-			<synopsis>Raised when a variable is set to a particular value.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Variable">
-					<para>The variable being set.</para>
-				</parameter>
-				<parameter name="Value">
-					<para>The new value of the variable.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentLogin">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when an Agent has logged in.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Agent">
-					<para>Agent ID of the agent.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="application">AgentLogin</ref>
-				<ref type="managerEvent">AgentLogoff</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AgentLogoff">
-		<managerEventInstance class="EVENT_FLAG_AGENT">
-			<synopsis>Raised when an Agent has logged off.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentLogin']/managerEventInstance/syntax/parameter)" />
-				<parameter name="Logintime">
-					<para>The number of seconds the agent was logged in.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="managerEvent">AgentLogin</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChannelTalkingStart">
-		<managerEventInstance class="EVENT_FLAG_CLASS">
-			<synopsis>Raised when talking is detected on a channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-			<see-also>
-				<ref type="function">TALK_DETECT</ref>
-				<ref type="managerEvent">ChannelTalkingStop</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ChannelTalkingStop">
-		<managerEventInstance class="EVENT_FLAG_CLASS">
-			<synopsis>Raised when talking is no longer detected on a channel.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Duration">
-					<para>The length in time, in milliseconds, that talking was
-					detected on the channel.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="function">TALK_DETECT</ref>
-				<ref type="managerEvent">ChannelTalkingStart</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
-#define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
-
-static struct stasis_cp_all *channel_cache_all;
-static struct stasis_cache *channel_cache_by_name;
-static struct stasis_caching_topic *channel_by_name_topic;
-
-struct stasis_cp_all *ast_channel_cache_all(void)
-{
-	return channel_cache_all;
-}
-
-struct stasis_cache *ast_channel_cache(void)
-{
-	return stasis_cp_all_cache(channel_cache_all);
-}
-
-struct stasis_topic *ast_channel_topic_all(void)
-{
-	return stasis_cp_all_topic(channel_cache_all);
-}
-
-struct stasis_topic *ast_channel_topic_all_cached(void)
-{
-	return stasis_cp_all_topic_cached(channel_cache_all);
-}
-
-struct stasis_cache *ast_channel_cache_by_name(void)
-{
-	return channel_cache_by_name;
-}
-
-static const char *channel_snapshot_get_id(struct stasis_message *message)
-{
-	struct ast_channel_snapshot *snapshot;
-	if (ast_channel_snapshot_type() != stasis_message_type(message)) {
-		return NULL;
-	}
-	snapshot = stasis_message_data(message);
-	return snapshot->uniqueid;
-}
-
-static const char *channel_snapshot_get_name(struct stasis_message *message)
-{
-	struct ast_channel_snapshot *snapshot;
-	if (ast_channel_snapshot_type() != stasis_message_type(message)) {
-		return NULL;
-	}
-	snapshot = stasis_message_data(message);
-	return snapshot->name;
-}
-
-/*!
- * \internal
- * \brief Hash function for \ref ast_channel_snapshot objects
- */
-static int channel_snapshot_hash_cb(const void *obj, const int flags)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-	const char *name = (flags & OBJ_KEY) ? obj : snapshot->name;
-	return ast_str_case_hash(name);
-}
-
-/*!
- * \internal
- * \brief Comparison function for \ref ast_channel_snapshot objects
- */
-static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
-{
-	struct ast_channel_snapshot *left = obj;
-	struct ast_channel_snapshot *right = arg;
-	const char *match = (flags & OBJ_KEY) ? arg : right->name;
-	return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-static void channel_snapshot_dtor(void *obj)
-{
-	struct ast_channel_snapshot *snapshot = obj;
-
-	ast_string_field_free_memory(snapshot);
-	ao2_cleanup(snapshot->manager_vars);
-}
-
-struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
-{
-	struct ast_channel_snapshot *snapshot;
-	struct ast_bridge *bridge;
-
-	/* no snapshots for dummy channels */
-	if (!ast_channel_tech(chan)) {
-		return NULL;
-	}
-
-	snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
-	if (!snapshot || ast_string_field_init(snapshot, 1024)) {
-		ao2_cleanup(snapshot);
-		return NULL;
-	}
-
-	ast_string_field_set(snapshot, name, ast_channel_name(chan));
-	ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
-	ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
-	ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
-	ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
-	ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
-	ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
-	ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
-	if (ast_channel_appl(chan)) {
-		ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
-	}
-	if (ast_channel_data(chan)) {
-		ast_string_field_set(snapshot, data, ast_channel_data(chan));
-	}
-	ast_string_field_set(snapshot, context, ast_channel_context(chan));
-	ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
-
-	ast_string_field_set(snapshot, caller_name,
-		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
-	ast_string_field_set(snapshot, caller_number,
-		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
-	ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, ""));
-	ast_string_field_set(snapshot, caller_subaddr,
-		S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
-	ast_string_field_set(snapshot, dialed_subaddr,
-		S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
-	ast_string_field_set(snapshot, caller_ani,
-		S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
-	ast_string_field_set(snapshot, caller_rdnis,
-		S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
-	ast_string_field_set(snapshot, caller_dnid,
-		S_OR(ast_channel_dialed(chan)->number.str, ""));
-
-	ast_string_field_set(snapshot, connected_name,
-		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
-	ast_string_field_set(snapshot, connected_number,
-		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
-	ast_string_field_set(snapshot, language, ast_channel_language(chan));
-
-	if ((bridge = ast_channel_get_bridge(chan))) {
-		ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
-		ao2_cleanup(bridge);
-	}
-
-	snapshot->creationtime = ast_channel_creationtime(chan);
-	snapshot->state = ast_channel_state(chan);
-	snapshot->priority = ast_channel_priority(chan);
-	snapshot->amaflags = ast_channel_amaflags(chan);
-	snapshot->hangupcause = ast_channel_hangupcause(chan);
-	ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
-	snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
-	ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
-
-	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
-	snapshot->tech_properties = ast_channel_tech(chan)->properties;
-
-	return snapshot;
-}
-
-static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
-{
-	if (chan) {
-		stasis_publish(ast_channel_topic(chan), message);
-	} else {
-		stasis_publish(ast_channel_topic_all(), message);
-	}
-}
-
-static void channel_blob_dtor(void *obj)
-{
-	struct ast_channel_blob *event = obj;
-	ao2_cleanup(event->snapshot);
-	ast_json_unref(event->blob);
-}
-
-static void ast_channel_publish_dial_internal(struct ast_channel *caller,
-	struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring,
-	const char *dialstatus, const char *forward)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, peer_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, forwarded_snapshot, NULL, ao2_cleanup);
-
-	if (!ast_channel_dial_type()) {
-		return;
-	}
-
-	ast_assert(peer != NULL);
-	blob = ast_json_pack("{s: s, s: s, s: s}",
-			     "dialstatus", S_OR(dialstatus, ""),
-			     "forward", S_OR(forward, ""),
-			     "dialstring", S_OR(dialstring, ""));
-	if (!blob) {
-		return;
-	}
-	payload = ast_multi_channel_blob_create(blob);
-	if (!payload) {
-		return;
-	}
-
-	if (caller) {
-		ast_channel_lock(caller);
-		if (ast_strlen_zero(dialstatus)) {
-			caller_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(caller));
-		} else {
-			caller_snapshot = ast_channel_snapshot_create(caller);
-		}
-		ast_channel_unlock(caller);
-		if (!caller_snapshot) {
-			return;
-		}
-		ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
-	}
-
-	ast_channel_lock(peer);
-	if (ast_strlen_zero(dialstatus)) {
-		peer_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(peer));
-	} else {
-		peer_snapshot = ast_channel_snapshot_create(peer);
-	}
-	ast_channel_unlock(peer);
-	if (!peer_snapshot) {
-		return;
-	}
-	ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
-
-	if (forwarded) {
-		ast_channel_lock(forwarded);
-		forwarded_snapshot = ast_channel_snapshot_create(forwarded);
-		ast_channel_unlock(forwarded);
-		if (!forwarded_snapshot) {
-			return;
-		}
-		ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
-	}
-
-	msg = stasis_message_create(ast_channel_dial_type(), payload);
-	if (!msg) {
-		return;
-	}
-
-	publish_message_for_channel_topics(msg, caller);
-}
-
-static void remove_dial_masquerade(struct ast_channel *peer);
-static int set_dial_masquerade(struct ast_channel *caller,
-	struct ast_channel *peer, const char *dialstring);
-
-void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer,
-	struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
-	const char *forward)
-{
-	ast_assert(peer != NULL);
-
-	if (caller) {
-		/*
-		 * Lock two or three channels.
-		 *
-		 * We need to hold the locks to hold off a potential masquerade
-		 * messing up the stasis dial event ordering.
-		 */
-		for (;; ast_channel_unlock(caller), sched_yield()) {
-			ast_channel_lock(caller);
-			if (ast_channel_trylock(peer)) {
-				continue;
-			}
-			if (forwarded && ast_channel_trylock(forwarded)) {
-				ast_channel_unlock(peer);
-				continue;
-			}
-			break;
-		}
-
-		if (ast_strlen_zero(dialstatus)) {
-			set_dial_masquerade(caller, peer, dialstring);
-		} else {
-			remove_dial_masquerade(peer);
-		}
-	}
-
-	ast_channel_publish_dial_internal(caller, peer, forwarded, dialstring, dialstatus,
-		forward);
-
-	if (caller) {
-		if (forwarded) {
-			ast_channel_unlock(forwarded);
-		}
-		ast_channel_unlock(peer);
-		ast_channel_unlock(caller);
-	}
-}
-
-void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
-	const char *dialstring, const char *dialstatus)
-{
-	ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
-}
-
-static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
-		struct stasis_message_type *type,
-		struct ast_json *blob)
-{
-	struct stasis_message *msg;
-	struct ast_channel_blob *obj;
-
-	obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
-	if (!obj) {
-		return NULL;
-	}
-
-	if (snapshot) {
-		obj->snapshot = snapshot;
-		ao2_ref(obj->snapshot, +1);
-	}
-	if (!blob) {
-		blob = ast_json_null();
-	}
-	obj->blob = ast_json_ref(blob);
-
-	msg = stasis_message_create(type, obj);
-	ao2_cleanup(obj);
-	return msg;
-}
-
-struct stasis_message *ast_channel_blob_create_from_cache(const char *channel_id,
-					       struct stasis_message_type *type,
-					       struct ast_json *blob)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot,
-			NULL,
-			ao2_cleanup);
-
-	if (!type) {
-		return NULL;
-	}
-
-	snapshot = ast_channel_snapshot_get_latest(channel_id);
-
-	return create_channel_blob_message(snapshot, type, blob);
-}
-
-struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
-	struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (!type) {
-		return NULL;
-	}
-
-	if (chan) {
-		snapshot = ast_channel_snapshot_create(chan);
-	}
-
-	return create_channel_blob_message(snapshot, type, blob);
-}
-
-/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
-struct channel_role_snapshot {
-	struct ast_channel_snapshot *snapshot;	/*!< A channel snapshot */
-	char role[0];							/*!< The role assigned to the channel */
-};
-
-/*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
-struct ast_multi_channel_blob {
-	struct ao2_container *channel_snapshots;	/*!< A container holding the snapshots */
-	struct ast_json *blob;						/*< A blob of JSON data */
-};
-
-/*!
- * \internal
- * \brief Standard comparison function for \ref channel_role_snapshot objects
- */
-static int channel_role_single_cmp_cb(void *obj, void *arg, int flags)
-{
-	struct channel_role_snapshot *left = obj;
-	struct channel_role_snapshot *right = arg;
-	const char *match = (flags & OBJ_KEY) ? arg : right->role;
-	return strcasecmp(left->role, match) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-/*!
- * \internal
- * \brief Multi comparison function for \ref channel_role_snapshot objects
- */
-static int channel_role_multi_cmp_cb(void *obj, void *arg, int flags)
-{
-	struct channel_role_snapshot *left = obj;
-	struct channel_role_snapshot *right = arg;
-	const char *match = (flags & OBJ_KEY) ? arg : right->role;
-	return strcasecmp(left->role, match) ? 0 : (CMP_MATCH);
-}
-
-/*!
- * \internal
- * \brief Hash function for \ref channel_role_snapshot objects
- */
-static int channel_role_hash_cb(const void *obj, const int flags)
-{
-	const struct channel_role_snapshot *snapshot = obj;
-	const char *name = (flags & OBJ_KEY) ? obj : snapshot->role;
-	return ast_str_case_hash(name);
-}
-
-/*!
- * \internal
- * \brief Destructor for \ref ast_multi_channel_blob objects
- */
-static void multi_channel_blob_dtor(void *obj)
-{
-	struct ast_multi_channel_blob *multi_blob = obj;
-
-	ao2_cleanup(multi_blob->channel_snapshots);
-	ast_json_unref(multi_blob->blob);
-}
-
-struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, obj,
-			ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
-			ao2_cleanup);
-
-	ast_assert(blob != NULL);
-
-	if (!obj) {
-		return NULL;
-	}
-
-	obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
-			channel_role_hash_cb, channel_role_single_cmp_cb);
-	if (!obj->channel_snapshots) {
-		return NULL;
-	}
-
-	obj->blob = ast_json_ref(blob);
-
-	ao2_ref(obj, +1);
-	return obj;
-}
-
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
-
-	ast_assert(!ast_strlen_zero(uniqueid));
-
-	message = stasis_cache_get(ast_channel_cache(),
-			ast_channel_snapshot_type(),
-			uniqueid);
-	if (!message) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(message);
-	if (!snapshot) {
-		return NULL;
-	}
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
-
-	ast_assert(!ast_strlen_zero(name));
-
-	message = stasis_cache_get(ast_channel_cache_by_name(),
-			ast_channel_snapshot_type(),
-			name);
-	if (!message) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(message);
-	if (!snapshot) {
-		return NULL;
-	}
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-static void channel_role_snapshot_dtor(void *obj)
-{
-	struct channel_role_snapshot *role_snapshot = obj;
-	ao2_cleanup(role_snapshot->snapshot);
-}
-
-void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
-{
-	RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup);
-	int role_len = strlen(role) + 1;
-
-	if (!obj || ast_strlen_zero(role) || !snapshot) {
-		return;
-	}
-
-	role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor);
-	if (!role_snapshot) {
-		return;
-	}
-	ast_copy_string(role_snapshot->role, role, role_len);
-	role_snapshot->snapshot = snapshot;
-	ao2_ref(role_snapshot->snapshot, +1);
-	ao2_link(obj->channel_snapshots, role_snapshot);
-}
-
-struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
-{
-	struct channel_role_snapshot *role_snapshot;
-
-	if (!obj || ast_strlen_zero(role)) {
-		return NULL;
-	}
-	role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_KEY);
-	/* Note that this function does not increase the ref count on snapshot */
-	if (!role_snapshot) {
-		return NULL;
-	}
-	ao2_ref(role_snapshot, -1);
-	return role_snapshot->snapshot;
-}
-
-struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
-{
-	RAII_VAR(struct ao2_container *, ret_container,
-		ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb),
-		ao2_cleanup);
-	struct ao2_iterator *it_role_snapshots;
-	struct channel_role_snapshot *role_snapshot;
-	char *arg;
-
-	if (!obj || ast_strlen_zero(role) || !ret_container) {
-		return NULL;
-	}
-	arg = ast_strdupa(role);
-
-	it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg);
-	if (!it_role_snapshots) {
-		return NULL;
-	}
-
-	while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
-		ao2_link(ret_container, role_snapshot->snapshot);
-		ao2_ref(role_snapshot, -1);
-	}
-	ao2_iterator_destroy(it_role_snapshots);
-
-	ao2_ref(ret_container, +1);
-	return ret_container;
-}
-
-struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
-{
-	if (!obj) {
-		return NULL;
-	}
-	return obj->blob;
-}
-
-void ast_channel_stage_snapshot(struct ast_channel *chan)
-{
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
-}
-
-void ast_channel_stage_snapshot_done(struct ast_channel *chan)
-{
-	ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
-	ast_channel_publish_snapshot(chan);
-}
-
-void ast_channel_publish_snapshot(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!ast_channel_snapshot_type()) {
-		return;
-	}
-
-	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE)) {
-		return;
-	}
-
-	snapshot = ast_channel_snapshot_create(chan);
-	if (!snapshot) {
-		return;
-	}
-
-	message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
-	if (!message) {
-		return;
-	}
-
-	ast_assert(ast_channel_topic(chan) != NULL);
-	stasis_publish(ast_channel_topic(chan), message);
-}
-
-void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
-{
-	struct stasis_message *message;
-
-	if (!blob) {
-		blob = ast_json_null();
-	}
-
-	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), type, blob);
-	if (message) {
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	ao2_cleanup(message);
-}
-
-void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
-{
-	struct stasis_message *message;
-
-	if (!blob) {
-		blob = ast_json_null();
-	}
-
-	message = ast_channel_blob_create(chan, type, blob);
-	if (message) {
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	ao2_cleanup(message);
-}
-
-void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
-{
-	struct ast_json *blob;
-
-	ast_assert(name != NULL);
-	ast_assert(value != NULL);
-
-	blob = ast_json_pack("{s: s, s: s}",
-			     "variable", name,
-			     "value", value);
-	if (!blob) {
-		ast_log(LOG_ERROR, "Error creating message\n");
-		return;
-	}
-
-	/*! If there are manager variables, force a cache update */
-	if (chan && ast_channel_has_manager_vars()) {
-		ast_channel_publish_snapshot(chan);
-	}
-
-	if (chan) {
-		ast_channel_publish_cached_blob(chan, ast_channel_varset_type(), blob);
-	} else {
-		/* This function is NULL safe for global variables */
-		ast_channel_publish_blob(NULL, ast_channel_varset_type(), blob);
-	}
-
-	ast_json_unref(blob);
-}
-
-static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	const char *variable =
-		ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
-	const char *value =
-		ast_json_string_get(ast_json_object_get(obj->blob, "value"));
-
-	if (obj->snapshot) {
-		channel_event_string =
-			ast_manager_build_channel_state_string(obj->snapshot);
-	} else {
-		channel_event_string = ast_str_create(35);
-		ast_str_set(&channel_event_string, 0,
-			    "Channel: none\r\n"
-			    "Uniqueid: none\r\n");
-	}
-
-	if (!channel_event_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_DIALPLAN, "VarSet",
-		"%s"
-		"Variable: %s\r\n"
-		"Value: %s\r\n",
-		ast_str_buffer(channel_event_string), variable, value);
-}
-
-static struct ast_manager_event_blob *agent_login_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogin",
-		"%s"
-		"Agent: %s\r\n",
-		ast_str_buffer(channel_string), agent);
-}
-
-static struct ast_manager_event_blob *agent_logoff_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
-	long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogoff",
-		"%s"
-		"Agent: %s\r\n"
-		"Logintime: %ld\r\n",
-		ast_str_buffer(channel_string), agent, logintime);
-}
-
-void ast_publish_channel_state(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!ast_channel_snapshot_type()) {
-		return;
-	}
-
-	ast_assert(chan != NULL);
-	if (!chan) {
-		return;
-	}
-
-	snapshot = ast_channel_snapshot_create(chan);
-	if (!snapshot) {
-		return;
-	}
-
-	message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
-	if (!message) {
-		return;
-	}
-
-	ast_assert(ast_channel_topic(chan) != NULL);
-	stasis_publish(ast_channel_topic(chan), message);
-}
-
-struct ast_json *ast_channel_snapshot_to_json(
-	const struct ast_channel_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref);
-
-	if (snapshot == NULL
-		|| (sanitize && sanitize->channel_snapshot
-		&& sanitize->channel_snapshot(snapshot))) {
-		return NULL;
-	}
-
-	json_chan = ast_json_pack(
-		/* Broken up into groups of three for readability */
-		"{ s: s, s: s, s: s,"
-		"  s: o, s: o, s: s,"
-		"  s: o, s: o }",
-		/* First line */
-		"id", snapshot->uniqueid,
-		"name", snapshot->name,
-		"state", ast_state2str(snapshot->state),
-		/* Second line */
-		"caller", ast_json_name_number(
-			snapshot->caller_name, snapshot->caller_number),
-		"connected", ast_json_name_number(
-			snapshot->connected_name, snapshot->connected_number),
-		"accountcode", snapshot->accountcode,
-		/* Third line */
-		"dialplan", ast_json_dialplan_cep(
-			snapshot->context, snapshot->exten, snapshot->priority),
-		"creationtime", ast_json_timeval(snapshot->creationtime, NULL));
-
-	return ast_json_ref(json_chan);
-}
-
-int ast_channel_snapshot_cep_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot)
-{
-	ast_assert(old_snapshot != NULL);
-	ast_assert(new_snapshot != NULL);
-
-	/* We actually get some snapshots with CEP set, but before the
-	 * application is set. Since empty application is invalid, we treat
-	 * setting the application from nothing as a CEP change.
-	 */
-	if (ast_strlen_zero(old_snapshot->appl) &&
-	    !ast_strlen_zero(new_snapshot->appl)) {
-		return 0;
-	}
-
-	return old_snapshot->priority == new_snapshot->priority &&
-		strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
-		strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
-}
-
-int ast_channel_snapshot_caller_id_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot)
-{
-	ast_assert(old_snapshot != NULL);
-	ast_assert(new_snapshot != NULL);
-	return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
-		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
-}
-
-int ast_channel_snapshot_connected_line_equal(
-	const struct ast_channel_snapshot *old_snapshot,
-	const struct ast_channel_snapshot *new_snapshot)
-{
-	ast_assert(old_snapshot != NULL);
-	ast_assert(new_snapshot != NULL);
-	return strcmp(old_snapshot->connected_number, new_snapshot->connected_number) == 0 &&
-		strcmp(old_snapshot->connected_name, new_snapshot->connected_name) == 0;
-}
-
-static struct ast_json *channel_blob_to_json(
-	struct stasis_message *message,
-	const char *type,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
-	struct ast_channel_blob *channel_blob = stasis_message_data(message);
-	struct ast_json *blob = channel_blob->blob;
-	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
-	const struct timeval *tv = stasis_message_timestamp(message);
-	int res = 0;
-
-	if (blob == NULL || ast_json_is_null(blob)) {
-		out = ast_json_object_create();
-	} else {
-		/* blobs are immutable, so shallow copies are fine */
-		out = ast_json_copy(blob);
-	}
-
-	if (!out) {
-		return NULL;
-	}
-
-	res |= ast_json_object_set(out, "type", ast_json_string_create(type));
-	res |= ast_json_object_set(out, "timestamp",
-		ast_json_timeval(*tv, NULL));
-
-	/* For global channel messages, the snapshot is optional */
-	if (snapshot) {
-		struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
-
-		if (!json_channel) {
-			return NULL;
-		}
-
-		res |= ast_json_object_set(out, "channel", json_channel);
-	}
-
-	if (res != 0) {
-		return NULL;
-	}
-
-	return ast_json_ref(out);
-}
-
-static struct ast_json *dtmf_end_to_json(
-	struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_channel_blob *channel_blob = stasis_message_data(message);
-	struct ast_json *blob = channel_blob->blob;
-	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
-	const char *direction =
-		ast_json_string_get(ast_json_object_get(blob, "direction"));
-	const struct timeval *tv = stasis_message_timestamp(message);
-	struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
-
-	/* Only present received DTMF end events as JSON */
-	if (strcasecmp("Received", direction) != 0) {
-		return NULL;
-	}
-
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
-		"type", "ChannelDtmfReceived",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"digit", ast_json_object_get(blob, "digit"),
-		"duration_ms", ast_json_object_get(blob, "duration_ms"),
-		"channel", json_channel);
-}
-
-static struct ast_json *varset_to_json(
-	struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	return channel_blob_to_json(message, "ChannelVarset", sanitize);
-}
-
-static struct ast_json *hangup_request_to_json(
-	struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
-}
-
-static struct ast_json *dial_to_json(
-	struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_multi_channel_blob *payload = stasis_message_data(message);
-	struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
-	struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
-	struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
-	struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
-	struct ast_json *json;
-	const struct timeval *tv = stasis_message_timestamp(message);
-	int res = 0;
-
-	json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}",
-		"type", "Dial",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"dialstatus", ast_json_object_get(blob, "dialstatus"),
-		"forward", ast_json_object_get(blob, "forward"),
-		"dialstring", ast_json_object_get(blob, "dialstring"));
-	if (!json) {
-		ast_json_unref(caller_json);
-		ast_json_unref(peer_json);
-		ast_json_unref(forwarded_json);
-		return NULL;
-	}
-
-	if (caller_json) {
-		res |= ast_json_object_set(json, "caller", caller_json);
-	}
-	if (peer_json) {
-		res |= ast_json_object_set(json, "peer", peer_json);
-	}
-	if (forwarded_json) {
-		res |= ast_json_object_set(json, "forwarded", forwarded_json);
-	}
-
-	if (res) {
-		ast_json_unref(json);
-		return NULL;
-	}
-
-	return json;
-}
-
-static struct ast_manager_event_blob *talking_start_to_ami(struct stasis_message *msg)
-{
-	struct ast_str *channel_string;
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	struct ast_manager_event_blob *blob;
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
-	                                     "%s", ast_str_buffer(channel_string));
-	ast_free(channel_string);
-
-	return blob;
-}
-
-static struct ast_json *talking_start_to_json(struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
-}
-
-static struct ast_manager_event_blob *talking_stop_to_ami(struct stasis_message *msg)
-{
-	struct ast_str *channel_string;
-	struct ast_channel_blob *obj = stasis_message_data(msg);
-	int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
-	struct ast_manager_event_blob *blob;
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	if (!channel_string) {
-		return NULL;
-	}
-
-	blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
-	                                     "%s"
-	                                     "Duration: %d\r\n",
-	                                     ast_str_buffer(channel_string),
-	                                     duration);
-	ast_free(channel_string);
-
-	return blob;
-}
-
-static struct ast_json *talking_stop_to_json(struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
-}
-
-/*!
- * @{ \brief Define channel message types.
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type,
-	.to_json = dial_to_json,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
-	.to_ami = varset_to_ami,
-	.to_json = varset_to_json,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type,
-	.to_json = hangup_request_to_json,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
-	.to_json = dtmf_end_to_json,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_login_type,
-	.to_ami = agent_login_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_logoff_type,
-	.to_ami = agent_logoff_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_talking_start,
-	.to_ami = talking_start_to_ami,
-	.to_json = talking_start_to_json,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_talking_stop,
-	.to_ami = talking_stop_to_ami,
-	.to_json = talking_stop_to_json,
-	);
-
-/*! @} */
-
-static void stasis_channels_cleanup(void)
-{
-	stasis_caching_unsubscribe_and_join(channel_by_name_topic);
-	channel_by_name_topic = NULL;
-	ao2_cleanup(channel_cache_by_name);
-	channel_cache_by_name = NULL;
-	ao2_cleanup(channel_cache_all);
-	channel_cache_all = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_login_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_logoff_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_talking_start);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_talking_stop);
-}
-
-int ast_stasis_channels_init(void)
-{
-	int res = 0;
-
-	ast_register_cleanup(stasis_channels_cleanup);
-
-	channel_cache_all = stasis_cp_all_create("ast_channel_topic_all",
-		channel_snapshot_get_id);
-	if (!channel_cache_all) {
-		return -1;
-	}
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);
-
-	channel_cache_by_name = stasis_cache_create(channel_snapshot_get_name);
-	if (!channel_cache_by_name) {
-		return -1;
-	}
-
-	/* This should be initialized before the caching topic */
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
-
-	channel_by_name_topic = stasis_caching_topic_create(
-		stasis_cp_all_topic(channel_cache_all),
-		channel_cache_by_name);
-	if (!channel_by_name_topic) {
-		return -1;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_talking_start);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_talking_stop);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
- */
-struct dial_target {
-	/*! Called party channel. */
-	struct ast_channel *peer;
-	/*! Dialstring used to call the peer. */
-	char *dialstring;
-	/*! Next entry in the list. */
-	AST_LIST_ENTRY(dial_target) list;
-};
-
-static void dial_target_free(struct dial_target *doomed)
-{
-	if (!doomed) {
-		return;
-	}
-	ast_free(doomed->dialstring);
-	ast_free(doomed);
-}
-
-/*!
- * \internal
- * \brief Datastore used for advancing dial state in the case of a masquerade
- *        against a channel in the process of dialing.
- */
-struct dial_masquerade_datastore {
-	/*! Calling party channel. */
-	struct ast_channel *caller;
-	/*! List of called peers. */
-	AST_LIST_HEAD_NOLOCK(, dial_target) dialed_peers;
-};
-
-static void dial_masquerade_datastore_cleanup(struct dial_masquerade_datastore *masq_data)
-{
-	struct dial_target *cur;
-
-	while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
-		dial_target_free(cur);
-	}
-	masq_data->caller = NULL;
-}
-
-static void dial_masquerade_datastore_remove_chan(struct dial_masquerade_datastore *masq_data, struct ast_channel *chan)
-{
-	struct dial_target *cur;
-
-	ao2_lock(masq_data);
-	if (masq_data->caller == chan) {
-		dial_masquerade_datastore_cleanup(masq_data);
-	} else {
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
-			if (cur->peer == chan) {
-				AST_LIST_REMOVE_CURRENT(list);
-				dial_target_free(cur);
-				break;
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-	}
-	ao2_unlock(masq_data);
-}
-
-static void dial_masquerade_datastore_dtor(void *vdoomed)
-{
-	dial_masquerade_datastore_cleanup(vdoomed);
-}
-
-static struct dial_masquerade_datastore *dial_masquerade_datastore_alloc(void)
-{
-	struct dial_masquerade_datastore *masq_data;
-
-	masq_data = ao2_alloc(sizeof(struct dial_masquerade_datastore),
-		dial_masquerade_datastore_dtor);
-	if (!masq_data) {
-		return NULL;
-	}
-	AST_LIST_HEAD_INIT_NOLOCK(&masq_data->dialed_peers);
-	return masq_data;
-}
-
-/*!
- * \internal
- * \brief Datastore destructor for dial_masquerade_datastore
- */
-static void dial_masquerade_datastore_destroy(void *data)
-{
-	ao2_ref(data, -1);
-}
-
-static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
-
-static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct dial_masquerade_datastore *masq_data = data;
-	struct dial_target *cur;
-	struct ast_datastore *datastore;
-
-	ao2_lock(masq_data);
-	if (!masq_data->caller) {
-		/* Nothing to do but remove the datastore */
-	} else if (masq_data->caller == old_chan) {
-		/* The caller channel is being masqueraded out. */
-		ast_debug(1, "Caller channel %s being masqueraded out to %s (is_empty:%d)\n",
-			ast_channel_name(new_chan), ast_channel_name(old_chan),
-			AST_LIST_EMPTY(&masq_data->dialed_peers));
-		AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
-			ast_channel_publish_dial_internal(new_chan, cur->peer, NULL,
-				cur->dialstring, "NOANSWER", NULL);
-			ast_channel_publish_dial_internal(old_chan, cur->peer, NULL,
-				cur->dialstring, NULL, NULL);
-		}
-		dial_masquerade_datastore_cleanup(masq_data);
-	} else {
-		/* One of the peer channels is being masqueraded out. */
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
-			if (cur->peer == old_chan) {
-				ast_debug(1, "Peer channel %s being masqueraded out to %s\n",
-					ast_channel_name(new_chan), ast_channel_name(old_chan));
-				ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
-					cur->dialstring, "CANCEL", NULL);
-				ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
-					cur->dialstring, NULL, NULL);
-
-				AST_LIST_REMOVE_CURRENT(list);
-				dial_target_free(cur);
-				break;
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-	}
-	ao2_unlock(masq_data);
-
-	/* Remove the datastore from the channel. */
-	datastore = dial_masquerade_datastore_find(old_chan);
-	if (!datastore) {
-		return;
-	}
-	ast_channel_datastore_remove(old_chan, datastore);
-	ast_datastore_free(datastore);
-}
-
-/*!
- * \internal
- * \brief Primary purpose for dial_masquerade_datastore, publishes
- *        the channel dial event needed to set the incoming channel into the
- *        dial state during a masquerade.
- * \param data pointer to the dial_masquerade_datastore
- * \param old_chan Channel being replaced
- * \param new_chan Channel being pushed to dial mode
- */
-static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct dial_masquerade_datastore *masq_data = data;
-	struct dial_target *cur;
-
-	ao2_lock(masq_data);
-
-	if (!masq_data->caller) {
-		ao2_unlock(masq_data);
-		return;
-	}
-
-	if (masq_data->caller == new_chan) {
-		/*
-		 * The caller channel is being masqueraded into.
-		 * The masquerade is likely because of a blonde transfer.
-		 */
-		ast_debug(1, "Caller channel %s being masqueraded into by %s (is_empty:%d)\n",
-			ast_channel_name(old_chan), ast_channel_name(new_chan),
-			AST_LIST_EMPTY(&masq_data->dialed_peers));
-		AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
-			ast_channel_publish_dial_internal(old_chan, cur->peer, NULL,
-				cur->dialstring, "NOANSWER", NULL);
-			ast_channel_publish_dial_internal(new_chan, cur->peer, NULL,
-				cur->dialstring, NULL, NULL);
-		}
-
-		ao2_unlock(masq_data);
-		return;
-	}
-
-	/*
-	 * One of the peer channels is being masqueraded into.
-	 * The masquerade is likely because of a call pickup.
-	 */
-	AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
-		if (cur->peer == new_chan) {
-			ast_debug(1, "Peer channel %s being masqueraded into by %s\n",
-				ast_channel_name(old_chan), ast_channel_name(new_chan));
-			ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
-				cur->dialstring, "CANCEL", NULL);
-			ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
-				cur->dialstring, NULL, NULL);
-			break;
-		}
-	}
-
-	ao2_unlock(masq_data);
-}
-
-static const struct ast_datastore_info dial_masquerade_info = {
-	.type = "stasis-chan-dial-masq",
-	.destroy = dial_masquerade_datastore_destroy,
-	.chan_fixup = dial_masquerade_fixup,
-	.chan_breakdown = dial_masquerade_breakdown,
-};
-
-/*!
- * \internal
- * \brief Find the dial masquerade datastore on the given channel.
- *
- * \param chan Channel a datastore data is wanted from
- *
- * \return A pointer to the datastore if it exists.
- */
-static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan)
-{
-	return ast_channel_datastore_find(chan, &dial_masquerade_info, NULL);
-}
-
-/*!
- * \internal
- * \brief Add the dial masquerade datastore to a channel.
- *
- * \param chan Channel to setup dial masquerade datastore on.
- * \param masq_data NULL to setup caller datastore otherwise steals the ref on success.
- *
- * \retval masq_data given or created on success.
- *         (A ref is not returned but can be obtained before chan is unlocked.)
- * \retval NULL on error.  masq_data ref is not stolen.
- */
-static struct dial_masquerade_datastore *dial_masquerade_datastore_add(
-	struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
-{
-	struct ast_datastore *datastore;
-
-	datastore = ast_datastore_alloc(&dial_masquerade_info, NULL);
-	if (!datastore) {
-		return NULL;
-	}
-
-	if (!masq_data) {
-		masq_data = dial_masquerade_datastore_alloc();
-		if (!masq_data) {
-			ast_datastore_free(datastore);
-			return NULL;
-		}
-		masq_data->caller = chan;
-	}
-
-	datastore->data = masq_data;
-	ast_channel_datastore_add(chan, datastore);
-
-	return masq_data;
-}
-
-static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
-{
-	struct ast_datastore *datastore;
-	struct dial_masquerade_datastore *masq_data;
-	struct dial_target *target;
-
-	/* Find or create caller datastore */
-	datastore = dial_masquerade_datastore_find(caller);
-	if (!datastore) {
-		masq_data = dial_masquerade_datastore_add(caller, NULL);
-	} else {
-		masq_data = datastore->data;
-	}
-	if (!masq_data) {
-		return -1;
-	}
-	ao2_ref(masq_data, +1);
-
-	/*
-	 * Someone likely forgot to do an ast_channel_publish_dial()
-	 * or ast_channel_publish_dial_forward() with a final dial
-	 * status on the channel.
-	 */
-	ast_assert(masq_data->caller == caller);
-
-	/* Create peer target to put into datastore */
-	target = ast_calloc(1, sizeof(*target));
-	if (!target) {
-		ao2_ref(masq_data, -1);
-		return -1;
-	}
-	if (dialstring) {
-		target->dialstring = ast_strdup(dialstring);
-		if (!target->dialstring) {
-			ast_free(target);
-			ao2_ref(masq_data, -1);
-			return -1;
-		}
-	}
-	target->peer = peer;
-
-	/* Put peer target into datastore */
-	ao2_lock(masq_data);
-	dial_masquerade_datastore_remove_chan(masq_data, peer);
-	AST_LIST_INSERT_HEAD(&masq_data->dialed_peers, target, list);
-	ao2_unlock(masq_data);
-
-	datastore = dial_masquerade_datastore_find(peer);
-	if (datastore) {
-		if (datastore->data == masq_data) {
-			/*
-			 * Peer already had the datastore for this dial masquerade.
-			 * This was a redundant peer dial masquerade setup.
-			 */
-			ao2_ref(masq_data, -1);
-			return 0;
-		}
-
-		/* Something is wrong.  Try to fix if the assert doesn't abort. */
-		ast_assert(0);
-
-		/* Remove the stale dial masquerade datastore */
-		dial_masquerade_datastore_remove_chan(datastore->data, peer);
-		ast_channel_datastore_remove(peer, datastore);
-		ast_datastore_free(datastore);
-	}
-
-	/* Create the peer dial masquerade datastore */
-	if (dial_masquerade_datastore_add(peer, masq_data)) {
-		/* Success */
-		return 0;
-	}
-
-	/* Failed to create the peer datastore */
-	dial_masquerade_datastore_remove_chan(masq_data, peer);
-	ao2_ref(masq_data, -1);
-	return -1;
-}
-
-static void remove_dial_masquerade(struct ast_channel *peer)
-{
-	struct ast_datastore *datastore;
-	struct dial_masquerade_datastore *masq_data;
-
-	datastore = dial_masquerade_datastore_find(peer);
-	if (!datastore) {
-		return;
-	}
-
-	masq_data = datastore->data;
-	if (masq_data) {
-		dial_masquerade_datastore_remove_chan(masq_data, peer);
-	}
-
-	ast_channel_datastore_remove(peer, datastore);
-	ast_datastore_free(datastore);
-}
diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c
deleted file mode 100644
index 693f307..0000000
--- a/main/stasis_endpoints.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis endpoint API.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_endpoints.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="PeerStatus">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when the state of a peer changes.</synopsis>
-			<syntax>
-				<parameter name="ChannelType">
-					<para>The channel technology of the peer.</para>
-				</parameter>
-				<parameter name="Peer">
-					<para>The name of the peer (including channel technology).</para>
-				</parameter>
-				<parameter name="PeerStatus">
-					<para>New status of the peer.</para>
-					<enumlist>
-						<enum name="Unknown"/>
-						<enum name="Registered"/>
-						<enum name="Unregistered"/>
-						<enum name="Rejected"/>
-						<enum name="Lagged"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Cause">
-					<para>The reason the status has changed.</para>
-				</parameter>
-				<parameter name="Address">
-					<para>New address of the peer.</para>
-				</parameter>
-				<parameter name="Port">
-					<para>New port for the peer.</para>
-				</parameter>
-				<parameter name="Time">
-					<para>Time it takes to reach the peer and receive a response.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-***/
-
-static struct stasis_cp_all *endpoint_cache_all;
-
-struct stasis_cp_all *ast_endpoint_cache_all(void)
-{
-	return endpoint_cache_all;
-}
-
-struct stasis_cache *ast_endpoint_cache(void)
-{
-	return stasis_cp_all_cache(endpoint_cache_all);
-}
-
-struct stasis_topic *ast_endpoint_topic_all(void)
-{
-	return stasis_cp_all_topic(endpoint_cache_all);
-}
-
-struct stasis_topic *ast_endpoint_topic_all_cached(void)
-{
-	return stasis_cp_all_topic_cached(endpoint_cache_all);
-}
-
-static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg);
-
-STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_snapshot_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_state_type,
-	.to_ami = peerstatus_to_ami,
-);
-
-static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg)
-{
-	struct ast_endpoint_blob *obj = stasis_message_data(msg);
-	RAII_VAR(struct ast_str *, peerstatus_event_string, ast_str_create(64), ast_free);
-	const char *value;
-
-	/* peer_status is the only *required* thing */
-	if (!(value = ast_json_string_get(ast_json_object_get(obj->blob, "peer_status")))) {
-		return NULL;
-	}
-	ast_str_append(&peerstatus_event_string, 0, "PeerStatus: %s\r\n", value);
-
-	if ((value = ast_json_string_get(ast_json_object_get(obj->blob, "cause")))) {
-		ast_str_append(&peerstatus_event_string, 0, "Cause: %s\r\n", value);
-	}
-	if ((value = ast_json_string_get(ast_json_object_get(obj->blob, "address")))) {
-		ast_str_append(&peerstatus_event_string, 0, "Address: %s\r\n", value);
-	}
-	if ((value = ast_json_string_get(ast_json_object_get(obj->blob, "port")))) {
-		ast_str_append(&peerstatus_event_string, 0, "Port: %s\r\n", value);
-	}
-	if ((value = ast_json_string_get(ast_json_object_get(obj->blob, "time")))) {
-		ast_str_append(&peerstatus_event_string, 0, "Time: %s\r\n", value);
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_SYSTEM, "PeerStatus",
-		"ChannelType: %s\r\n"
-		"Peer: %s/%s\r\n"
-		"%s",
-		obj->snapshot->tech,
-		obj->snapshot->tech,
-		obj->snapshot->resource,
-		ast_str_buffer(peerstatus_event_string));
-}
-
-static void endpoint_blob_dtor(void *obj)
-{
-	struct ast_endpoint_blob *event = obj;
-	ao2_cleanup(event->snapshot);
-	ast_json_unref(event->blob);
-}
-
-struct stasis_message *ast_endpoint_blob_create(struct ast_endpoint *endpoint,
-	struct stasis_message_type *type, struct ast_json *blob)
-{
-	RAII_VAR(struct ast_endpoint_blob *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!type) {
-		return NULL;
-	}
-	if (!blob) {
-		blob = ast_json_null();
-	}
-
-	if (!(obj = ao2_alloc(sizeof(*obj), endpoint_blob_dtor))) {
-		return NULL;
-	}
-
-	if (endpoint) {
-		if (!(obj->snapshot = ast_endpoint_snapshot_create(endpoint))) {
-			return NULL;
-		}
-	}
-
-	obj->blob = ast_json_ref(blob);
-
-	if (!(msg = stasis_message_create(type, obj))) {
-		return NULL;
-	}
-
-	ao2_ref(msg, +1);
-	return msg;
-}
-
-void ast_endpoint_blob_publish(struct ast_endpoint *endpoint, struct stasis_message_type *type,
-	struct ast_json *blob)
-{
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	if (blob) {
-		message = ast_endpoint_blob_create(endpoint, type, blob);
-	}
-	if (message) {
-		stasis_publish(ast_endpoint_topic(endpoint), message);
-	}
-}
-
-struct ast_endpoint_snapshot *ast_endpoint_latest_snapshot(const char *tech,
-	const char *name)
-{
-	RAII_VAR(char *, id, NULL, ast_free);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_endpoint_snapshot *snapshot;
-
-	if (ast_strlen_zero(name)) {
-		ast_asprintf(&id, "%s", tech);
-	} else {
-		ast_asprintf(&id, "%s/%s", tech, name);
-	}
-	if (!id) {
-		return NULL;
-	}
-	ast_tech_to_upper(id);
-
-	msg = stasis_cache_get(ast_endpoint_cache(),
-		ast_endpoint_snapshot_type(), id);
-	if (!msg) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(msg);
-	ast_assert(snapshot != NULL);
-
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-/*!
- * \brief Callback extract a unique identity from a snapshot message.
- *
- * This identity is unique to the underlying object of the snapshot, such as the
- * UniqueId field of a channel.
- *
- * \param message Message to extract id from.
- * \return String representing the snapshot's id.
- * \return \c NULL if the message_type of the message isn't a handled snapshot.
- * \since 12
- */
-static const char *endpoint_snapshot_get_id(struct stasis_message *message)
-{
-	struct ast_endpoint_snapshot *snapshot;
-
-	if (ast_endpoint_snapshot_type() != stasis_message_type(message)) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(message);
-
-	return snapshot->id;
-}
-
-
-struct ast_json *ast_endpoint_snapshot_to_json(
-	const struct ast_endpoint_snapshot *snapshot,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json *channel_array;
-	int i;
-
-	json = ast_json_pack("{s: s, s: s, s: s, s: []}",
-		"technology", snapshot->tech,
-		"resource", snapshot->resource,
-		"state", ast_endpoint_state_to_string(snapshot->state),
-		"channel_ids");
-
-	if (json == NULL) {
-		return NULL;
-	}
-
-	if (snapshot->max_channels != -1) {
-		int res = ast_json_object_set(json, "max_channels",
-			ast_json_integer_create(snapshot->max_channels));
-		if (res != 0) {
-			return NULL;
-		}
-	}
-
-	channel_array = ast_json_object_get(json, "channel_ids");
-	ast_assert(channel_array != NULL);
-	for (i = 0; i < snapshot->num_channels; ++i) {
-		int res;
-
-		if (sanitize && sanitize->channel_id
-			&& sanitize->channel_id(snapshot->channel_ids[i])) {
-			continue;
-		}
-
-		res = ast_json_array_append(channel_array,
-			ast_json_string_create(snapshot->channel_ids[i]));
-		if (res != 0) {
-			return NULL;
-		}
-	}
-
-	return ast_json_ref(json);
-}
-
-static void endpoints_stasis_cleanup(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_endpoint_snapshot_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_endpoint_state_type);
-
-	ao2_cleanup(endpoint_cache_all);
-	endpoint_cache_all = NULL;
-}
-
-int ast_endpoint_stasis_init(void)
-{
-	int res = 0;
-	ast_register_cleanup(endpoints_stasis_cleanup);
-
-	endpoint_cache_all = stasis_cp_all_create("endpoint_topic_all",
-		endpoint_snapshot_get_id);
-	if (!endpoint_cache_all) {
-		return -1;
-	}
-
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_endpoint_snapshot_type);
-	res |= STASIS_MESSAGE_TYPE_INIT(ast_endpoint_state_type);
-
-	return res;
-}
diff --git a/main/stasis_message.c b/main/stasis_message.c
deleted file mode 100644
index 75a9e5e..0000000
--- a/main/stasis_message.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Message API.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/utils.h"
-
-/*! \internal */
-struct stasis_message_type {
-	struct stasis_message_vtable *vtable;
-	char *name;
-};
-
-static struct stasis_message_vtable null_vtable = {};
-
-static void message_type_dtor(void *obj)
-{
-	struct stasis_message_type *type = obj;
-	ast_free(type->name);
-	type->name = NULL;
-}
-
-int stasis_message_type_create(const char *name,
-	struct stasis_message_vtable *vtable,
-	struct stasis_message_type **result)
-{
-	struct stasis_message_type *type;
-
-	/* Check for declination */
-	if (name && stasis_message_type_declined(name)) {
-		return STASIS_MESSAGE_TYPE_DECLINED;
-	}
-
-	type = ao2_t_alloc(sizeof(*type), message_type_dtor, name);
-	if (!type) {
-		return STASIS_MESSAGE_TYPE_ERROR;
-	}
-	if (!vtable) {
-		/* Null object pattern, FTW! */
-		vtable = &null_vtable;
-	}
-
-	type->name = ast_strdup(name);
-	if (!type->name) {
-		ao2_cleanup(type);
-		return STASIS_MESSAGE_TYPE_ERROR;
-	}
-	type->vtable = vtable;
-	*result = type;
-
-	return STASIS_MESSAGE_TYPE_SUCCESS;
-}
-
-const char *stasis_message_type_name(const struct stasis_message_type *type)
-{
-	return type->name;
-}
-
-/*! \internal */
-struct stasis_message {
-	/*! Time the message was created */
-	struct timeval timestamp;
-	/*! Type of the message */
-	struct stasis_message_type *type;
-	/*! Where this message originated.  NULL if aggregate message. */
-	const struct ast_eid *eid_ptr;
-	/*! Message content */
-	void *data;
-	/*! Where this message originated. */
-	struct ast_eid eid;
-};
-
-static void stasis_message_dtor(void *obj)
-{
-	struct stasis_message *message = obj;
-	ao2_cleanup(message->type);
-	ao2_cleanup(message->data);
-}
-
-struct stasis_message *stasis_message_create_full(struct stasis_message_type *type, void *data, const struct ast_eid *eid)
-{
-	struct stasis_message *message;
-
-	if (type == NULL || data == NULL) {
-		return NULL;
-	}
-
-	message = ao2_t_alloc(sizeof(*message), stasis_message_dtor, type->name);
-	if (message == NULL) {
-		return NULL;
-	}
-
-	message->timestamp = ast_tvnow();
-	ao2_ref(type, +1);
-	message->type = type;
-	ao2_ref(data, +1);
-	message->data = data;
-	if (eid) {
-		message->eid_ptr = &message->eid;
-		message->eid = *eid;
-	}
-
-	return message;
-}
-
-struct stasis_message *stasis_message_create(struct stasis_message_type *type, void *data)
-{
-	return stasis_message_create_full(type, data, &ast_eid_default);
-}
-
-const struct ast_eid *stasis_message_eid(const struct stasis_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->eid_ptr;
-}
-
-struct stasis_message_type *stasis_message_type(const struct stasis_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->type;
-}
-
-void *stasis_message_data(const struct stasis_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->data;
-}
-
-const struct timeval *stasis_message_timestamp(const struct stasis_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return &msg->timestamp;
-}
-
-#define INVOKE_VIRTUAL(fn, ...)				\
-	({						\
-		if (msg == NULL) {			\
-			return NULL;			\
-		}					\
-		ast_assert(msg->type != NULL);		\
-		ast_assert(msg->type->vtable != NULL);	\
-		if (msg->type->vtable->fn == NULL) {	\
-			return NULL;			\
-		}					\
-		msg->type->vtable->fn(__VA_ARGS__);	\
-	})
-
-struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg)
-{
-	return INVOKE_VIRTUAL(to_ami, msg);
-}
-
-struct ast_json *stasis_message_to_json(
-	struct stasis_message *msg,
-	struct stasis_message_sanitizer *sanitize)
-{
-	return INVOKE_VIRTUAL(to_json, msg, sanitize);
-}
-
-struct ast_event *stasis_message_to_event(struct stasis_message *msg)
-{
-	return INVOKE_VIRTUAL(to_event, msg);
-}
diff --git a/main/stasis_message_router.c b/main/stasis_message_router.c
deleted file mode 100644
index 0692339..0000000
--- a/main/stasis_message_router.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis message router implementation.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/vector.h"
-
-/*! \internal */
-struct stasis_message_route {
-	/*! Message type handle by this route. */
-	struct stasis_message_type *message_type;
-	/*! Callback function for incoming message processing. */
-	stasis_subscription_cb callback;
-	/*! Data pointer to be handed to the callback. */
-	void *data;
-};
-
-AST_VECTOR(route_table, struct stasis_message_route);
-
-static struct stasis_message_route *route_table_find(struct route_table *table,
-	struct stasis_message_type *message_type)
-{
-	size_t idx;
-	struct stasis_message_route *route;
-
-	/* While a linear search for routes may seem very inefficient, most
-	 * route tables have six routes or less. For such small data, it's
-	 * hard to beat a linear search. If we start having larger route
-	 * tables, then we can look into containers with more efficient
-	 * lookups.
-	 */
-	for (idx = 0; idx < AST_VECTOR_SIZE(table); ++idx) {
-		route = AST_VECTOR_GET_ADDR(table, idx);
-		if (route->message_type == message_type) {
-			return route;
-		}
-	}
-
-	return NULL;
-}
-
-/*!
- * \brief route_table comparator for AST_VECTOR_REMOVE_CMP_UNORDERED()
- *
- * \param elem Element to compare against
- * \param value Value to compare with the vector element.
- *
- * \return 0 if element does not match.
- * \return Non-zero if element matches.
- */
-#define ROUTE_TABLE_ELEM_CMP(elem, value) ((elem).message_type == (value))
-
-/*!
- * \brief route_table vector element cleanup.
- *
- * \param elem Element to cleanup
- *
- * \return Nothing
- */
-#define ROUTE_TABLE_ELEM_CLEANUP(elem)  ao2_cleanup((elem).message_type)
-
-static int route_table_remove(struct route_table *table,
-	struct stasis_message_type *message_type)
-{
-	return AST_VECTOR_REMOVE_CMP_UNORDERED(table, message_type, ROUTE_TABLE_ELEM_CMP,
-		ROUTE_TABLE_ELEM_CLEANUP);
-}
-
-static int route_table_add(struct route_table *table,
-	struct stasis_message_type *message_type,
-	stasis_subscription_cb callback, void *data)
-{
-	struct stasis_message_route route;
-	int res;
-
-	ast_assert(callback != NULL);
-	ast_assert(route_table_find(table, message_type) == NULL);
-
-	route.message_type = ao2_bump(message_type);
-	route.callback = callback;
-	route.data = data;
-
-	res = AST_VECTOR_APPEND(table, route);
-	if (res) {
-		ROUTE_TABLE_ELEM_CLEANUP(route);
-	}
-	return res;
-}
-
-static void route_table_dtor(struct route_table *table)
-{
-	size_t idx;
-	struct stasis_message_route *route;
-
-	for (idx = 0; idx < AST_VECTOR_SIZE(table); ++idx) {
-		route = AST_VECTOR_GET_ADDR(table, idx);
-		ROUTE_TABLE_ELEM_CLEANUP(*route);
-	}
-	AST_VECTOR_FREE(table);
-}
-
-/*! \internal */
-struct stasis_message_router {
-	/*! Subscription to the upstream topic */
-	struct stasis_subscription *subscription;
-	/*! Subscribed routes */
-	struct route_table routes;
-	/*! Subscribed routes for \ref stasis_cache_update messages */
-	struct route_table cache_routes;
-	/*! Route of last resort */
-	struct stasis_message_route default_route;
-};
-
-static void router_dtor(void *obj)
-{
-	struct stasis_message_router *router = obj;
-
-	ast_assert(!stasis_subscription_is_subscribed(router->subscription));
-	ast_assert(stasis_subscription_is_done(router->subscription));
-
-	router->subscription = NULL;
-
-	route_table_dtor(&router->routes);
-	route_table_dtor(&router->cache_routes);
-}
-
-static int find_route(
-	struct stasis_message_router *router,
-	struct stasis_message *message,
-	struct stasis_message_route *route_out)
-{
-	struct stasis_message_route *route = NULL;
-	struct stasis_message_type *type = stasis_message_type(message);
-	SCOPED_AO2LOCK(lock, router);
-
-	ast_assert(route_out != NULL);
-
-	if (type == stasis_cache_update_type()) {
-		/* Find a cache route */
-		struct stasis_cache_update *update =
-			stasis_message_data(message);
-		route = route_table_find(&router->cache_routes, update->type);
-	}
-
-	if (route == NULL) {
-		/* Find a regular route */
-		route = route_table_find(&router->routes, type);
-	}
-
-	if (route == NULL && router->default_route.callback) {
-		/* Maybe the default route, then? */
-		route = &router->default_route;
-	}
-
-	if (!route) {
-		return -1;
-	}
-
-	*route_out = *route;
-	return 0;
-}
-
-static void router_dispatch(void *data,
-			    struct stasis_subscription *sub,
-			    struct stasis_message *message)
-{
-	struct stasis_message_router *router = data;
-	struct stasis_message_route route;
-
-	if (find_route(router, message, &route) == 0) {
-		route.callback(route.data, sub, message);
-	}
-
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_cleanup(router);
-	}
-}
-
-static struct stasis_message_router *stasis_message_router_create_internal(
-	struct stasis_topic *topic, int use_thread_pool)
-{
-	int res;
-	RAII_VAR(struct stasis_message_router *, router, NULL, ao2_cleanup);
-
-	router = ao2_t_alloc(sizeof(*router), router_dtor, stasis_topic_name(topic));
-	if (!router) {
-		return NULL;
-	}
-
-	res = 0;
-	res |= AST_VECTOR_INIT(&router->routes, 0);
-	res |= AST_VECTOR_INIT(&router->cache_routes, 0);
-	if (res) {
-		return NULL;
-	}
-
-	if (use_thread_pool) {
-		router->subscription = stasis_subscribe_pool(topic, router_dispatch, router);
-	} else {
-		router->subscription = stasis_subscribe(topic, router_dispatch, router);
-	}
-	if (!router->subscription) {
-		return NULL;
-	}
-
-	ao2_ref(router, +1);
-	return router;
-}
-
-struct stasis_message_router *stasis_message_router_create(
-	struct stasis_topic *topic)
-{
-	return stasis_message_router_create_internal(topic, 0);
-}
-
-struct stasis_message_router *stasis_message_router_create_pool(
-	struct stasis_topic *topic)
-{
-	return stasis_message_router_create_internal(topic, 1);
-}
-
-void stasis_message_router_unsubscribe(struct stasis_message_router *router)
-{
-	if (!router) {
-		return;
-	}
-
-	stasis_unsubscribe(router->subscription);
-}
-
-void stasis_message_router_unsubscribe_and_join(
-	struct stasis_message_router *router)
-{
-	if (!router) {
-		return;
-	}
-	stasis_unsubscribe_and_join(router->subscription);
-}
-
-int stasis_message_router_is_done(struct stasis_message_router *router)
-{
-	if (!router) {
-		/* Null router is about as done as you can get */
-		return 1;
-	}
-
-	return stasis_subscription_is_done(router->subscription);
-}
-
-void stasis_message_router_publish_sync(struct stasis_message_router *router,
-	struct stasis_message *message)
-{
-	ast_assert(router != NULL);
-
-	ao2_bump(router);
-	stasis_publish_sync(router->subscription, message);
-	ao2_cleanup(router);
-}
-
-int stasis_message_router_add(struct stasis_message_router *router,
-	struct stasis_message_type *message_type,
-	stasis_subscription_cb callback, void *data)
-{
-	int res;
-
-	ast_assert(router != NULL);
-
-	if (!message_type) {
-		/* Cannot route to NULL type. */
-		return -1;
-	}
-	ao2_lock(router);
-	res = route_table_add(&router->routes, message_type, callback, data);
-	ao2_unlock(router);
-	return res;
-}
-
-int stasis_message_router_add_cache_update(struct stasis_message_router *router,
-	struct stasis_message_type *message_type,
-	stasis_subscription_cb callback, void *data)
-{
-	int res;
-
-	ast_assert(router != NULL);
-
-	if (!message_type) {
-		/* Cannot cache a route to NULL type. */
-		return -1;
-	}
-	ao2_lock(router);
-	res = route_table_add(&router->cache_routes, message_type, callback, data);
-	ao2_unlock(router);
-	return res;
-}
-
-void stasis_message_router_remove(struct stasis_message_router *router,
-	struct stasis_message_type *message_type)
-{
-	ast_assert(router != NULL);
-
-	if (!message_type) {
-		/* Cannot remove a NULL type. */
-		return;
-	}
-	ao2_lock(router);
-	route_table_remove(&router->routes, message_type);
-	ao2_unlock(router);
-}
-
-void stasis_message_router_remove_cache_update(
-	struct stasis_message_router *router,
-	struct stasis_message_type *message_type)
-{
-	ast_assert(router != NULL);
-
-	if (!message_type) {
-		/* Cannot remove a NULL type. */
-		return;
-	}
-	ao2_lock(router);
-	route_table_remove(&router->cache_routes, message_type);
-	ao2_unlock(router);
-}
-
-int stasis_message_router_set_default(struct stasis_message_router *router,
-	stasis_subscription_cb callback,
-	void *data)
-{
-	ast_assert(router != NULL);
-	ast_assert(callback != NULL);
-
-	ao2_lock(router);
-	router->default_route.callback = callback;
-	router->default_route.data = data;
-	ao2_unlock(router);
-	/* While this implementation can never fail, it used to be able to */
-	return 0;
-}
diff --git a/main/stasis_system.c b/main/stasis_system.c
deleted file mode 100644
index bf7b330..0000000
--- a/main/stasis_system.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jason Parker <jparker at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis Messages and Data Types for System events
- *
- * \author Jason Parker <jparker at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_system.h"
-
-/*** DOCUMENTATION
-	<managerEvent language="en_US" name="Registry">
-		<managerEventInstance class="EVENT_FLAG_SYSTEM">
-			<synopsis>Raised when an outbound registration completes.</synopsis>
-			<syntax>
-				<parameter name="ChannelType">
-					<para>The type of channel that was registered (or not).</para>
-				</parameter>
-				<parameter name="Username">
-					<para>The username portion of the registration.</para>
-				</parameter>
-				<parameter name="Domain">
-					<para>The address portion of the registration.</para>
-				</parameter>
-				<parameter name="Status">
-					<para>The status of the registration request.</para>
-					<enumlist>
-						<enum name="Registered"/>
-						<enum name="Unregistered"/>
-						<enum name="Rejected"/>
-						<enum name="Failed"/>
-					</enumlist>
-				</parameter>
-				<parameter name="Cause">
-					<para>What caused the rejection of the request, if available.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
-/*! \brief The \ref stasis topic for system level changes */
-static struct stasis_topic *system_topic;
-
-static struct ast_manager_event_blob *system_registry_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_available_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_offertimerstart_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_requested_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_requestacknowledged_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_callerstopmonitoring_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_callerstartmonitoring_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_callerrecalling_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_recallcomplete_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_failure_to_ami(struct stasis_message *message);
-static struct ast_manager_event_blob *cc_monitorfailed_to_ami(struct stasis_message *message);
-
-STASIS_MESSAGE_TYPE_DEFN(ast_network_change_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_system_registry_type,
-	.to_ami = system_registry_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_available_type,
-	.to_ami = cc_available_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_offertimerstart_type,
-	.to_ami = cc_offertimerstart_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_requested_type,
-	.to_ami = cc_requested_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_requestacknowledged_type,
-	.to_ami = cc_requestacknowledged_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_callerstopmonitoring_type,
-	.to_ami = cc_callerstopmonitoring_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_callerstartmonitoring_type,
-	.to_ami = cc_callerstartmonitoring_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_callerrecalling_type,
-	.to_ami = cc_callerrecalling_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_recallcomplete_type,
-	.to_ami = cc_recallcomplete_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_failure_type,
-	.to_ami = cc_failure_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN(ast_cc_monitorfailed_type,
-	.to_ami = cc_monitorfailed_to_ami,
-	);
-
-void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause)
-{
-	RAII_VAR(struct ast_json *, registry, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	if (!ast_system_registry_type()) {
-		return;
-	}
-
-	registry = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s}",
-		"type", "registry",
-		"channeltype", channeltype,
-		"username", username,
-		"domain", domain,
-		"status", status,
-		"cause", S_OR(cause, ""));
-
-	if (!(payload = ast_json_payload_create(registry))) {
-		return;
-	}
-
-	if (!(message = stasis_message_create(ast_system_registry_type(), payload))) {
-		return;
-	}
-
-	stasis_publish(ast_system_topic(), message);
-}
-
-static struct ast_manager_event_blob *system_registry_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	const char *channeltype;
-	const char *username;
-	const char *domain;
-	const char *status;
-	const char *cause;
-	RAII_VAR(struct ast_str *, cause_string, ast_str_create(32), ast_free);
-
-	if (!cause_string) {
-		return NULL;
-	}
-
-	channeltype = ast_json_string_get(ast_json_object_get(payload->json, "channeltype"));
-	username = ast_json_string_get(ast_json_object_get(payload->json, "username"));
-	domain = ast_json_string_get(ast_json_object_get(payload->json, "domain"));
-	status = ast_json_string_get(ast_json_object_get(payload->json, "status"));
-	cause = ast_json_string_get(ast_json_object_get(payload->json, "cause"));
-
-	if (!ast_strlen_zero(cause)) {
-		ast_str_set(&cause_string, 0, "Cause: %s\r\n", cause);
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_SYSTEM, "Registry",
-		"ChannelType: %s\r\n"
-		"Username: %s\r\n"
-		"Domain: %s\r\n"
-		"Status: %s\r\n"
-		"%s",
-		channeltype, username, domain, status, ast_str_buffer(cause_string));
-}
-
-static struct ast_manager_event_blob *cc_available_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *callee;
-	const char *service;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	callee = ast_json_string_get(ast_json_object_get(payload->json, "callee"));
-	service = ast_json_string_get(ast_json_object_get(payload->json, "service"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCAvailable",
-		"CoreID: %d\r\n"
-		"Callee: %s\r\n"
-		"Service: %s\r\n",
-		core_id, callee, service);
-}
-
-static struct ast_manager_event_blob *cc_offertimerstart_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-	unsigned int expires;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-	expires = ast_json_integer_get(ast_json_object_get(payload->json, "expires"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCOfferTimerStart",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n"
-		"Expires: %u\r\n",
-		core_id, caller, expires);
-}
-
-static struct ast_manager_event_blob *cc_requested_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-	const char *callee;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-	callee = ast_json_string_get(ast_json_object_get(payload->json, "callee"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCRequested",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n"
-		"Callee: %s\r\n",
-		core_id, caller, callee);
-}
-
-static struct ast_manager_event_blob *cc_requestacknowledged_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCRequestAcknowledged",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n",
-		core_id, caller);
-}
-
-static struct ast_manager_event_blob *cc_callerstopmonitoring_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCCallerStopMonitoring",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n",
-		core_id, caller);
-}
-
-static struct ast_manager_event_blob *cc_callerstartmonitoring_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCCallerStartMonitoring",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n",
-		core_id, caller);
-}
-
-static struct ast_manager_event_blob *cc_callerrecalling_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCCallerRecalling",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n",
-		core_id, caller);
-}
-
-static struct ast_manager_event_blob *cc_recallcomplete_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCRecallComplete",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n",
-		core_id, caller);
-}
-
-static struct ast_manager_event_blob *cc_failure_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *caller;
-	const char *reason;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	caller = ast_json_string_get(ast_json_object_get(payload->json, "caller"));
-	reason = ast_json_string_get(ast_json_object_get(payload->json, "reason"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCFailure",
-		"CoreID: %d\r\n"
-		"Caller: %s\r\n"
-		"Reason: %s\r\n",
-		core_id, caller, reason);
-}
-
-static struct ast_manager_event_blob *cc_monitorfailed_to_ami(struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-	int core_id;
-	const char *callee;
-
-	core_id = ast_json_integer_get(ast_json_object_get(payload->json, "core_id"));
-	callee = ast_json_string_get(ast_json_object_get(payload->json, "callee"));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_CC, "CCMonitorFailed",
-		"CoreID: %d\r\n"
-		"Callee: %s\r\n",
-		core_id, callee);
-}
-
-struct stasis_topic *ast_system_topic(void)
-{
-	return system_topic;
-}
-
-/*! \brief Cleanup the \ref stasis system level items */
-static void stasis_system_cleanup(void)
-{
-	ao2_cleanup(system_topic);
-	system_topic = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_network_change_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_system_registry_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_available_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_offertimerstart_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_requested_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_requestacknowledged_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_callerstopmonitoring_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_callerstartmonitoring_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_callerrecalling_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_recallcomplete_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_failure_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_monitorfailed_type);
-}
-
-/*! \brief Initialize the system level items for \ref stasis */
-int ast_stasis_system_init(void)
-{
-	ast_register_cleanup(stasis_system_cleanup);
-
-	system_topic = stasis_topic_create("ast_system");
-	if (!system_topic) {
-		return 1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_network_change_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_system_registry_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_available_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_offertimerstart_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_requested_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_requestacknowledged_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_callerstopmonitoring_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_callerstartmonitoring_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_callerrecalling_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_recallcomplete_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_failure_type) != 0) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_cc_monitorfailed_type) != 0) {
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c
index aa1cb26..4b00520 100644
--- a/main/stdtime/localtime.c
+++ b/main/stdtime/localtime.c
@@ -50,7 +50,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 #include <sys/stat.h>
@@ -187,6 +187,60 @@ struct state {
 	AST_LIST_ENTRY(state) list;
 };
 
+/* extra initialisation for sstate_alloc() */
+#define SP_STACK_FLAG INT_MIN
+#ifdef HAVE_INOTIFY
+#	define SP_STACK_INIT(sp) do { \
+		(sp).wd[0] = SP_STACK_FLAG; \
+	} while (0)
+#	define SP_STACK_CHECK(sp) ((sp)->wd[0] == SP_STACK_FLAG)
+#	define SP_HEAP_INIT(sp) do { \
+		(sp)->wd[0] = -1; \
+		(sp)->wd[1] = -1; \
+	} while (0)
+#	define SP_HEAP_FREE(sp) do {} while (0)
+
+#elif defined(HAVE_KQUEUE)
+#	define SP_STACK_INIT(sp) do { \
+		(sp).fd = SP_STACK_FLAG; \
+	} while (0)
+#	define SP_STACK_CHECK(sp) ((sp)->fd == SP_STACK_FLAG)
+#ifdef HAVE_O_SYMLINK
+#	define SP_HEAP_INIT(sp) do { \
+		(sp)->fd = -1; \
+		(sp)->fds = -1; \
+	} while (0)
+#	define SP_HEAP_FREE(sp) do { \
+	if ( (sp) ) { \
+		kqueue_daemon_freestate(sp); \
+		if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
+		if ((sp)->fds > -1) { close((sp)->fds); (sp)->fds = -1; } \
+	} \
+	} while (0)
+
+#else  /* HAVE_O_SYMLINK */
+#	define SP_HEAP_INIT(sp) do { \
+		(sp)->fd = -1; \
+		(sp)->dir = NULL; \
+	} while (0)
+#	define SP_HEAP_FREE(sp) do { \
+	if ( (sp) ) { \
+		kqueue_daemon_freestate(sp); \
+		if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
+		if ((sp)->dir != NULL) { closedir((sp)->dir); (sp)->dir = NULL; } \
+	} \
+	} while (0)
+
+#endif /* HAVE_O_SYMLINK */
+
+#else  /* defined(HAVE_KQUEUE) */
+#	define SP_STACK_INIT(sp) do {} while (0)
+#	define SP_STACK_CHECK(sp) (0)
+#	define SP_HEAP_INIT(sp) do {} while (0)
+#	define SP_HEAP_FREE(sp) do {} while (0)
+
+#endif
+
 struct locale_entry {
 	AST_LIST_ENTRY(locale_entry) list;
 	locale_t locale;
@@ -253,6 +307,9 @@ static int		tzload P((const char * name, struct state * sp,
 				int doextend));
 static int		tzparse P((const char * name, struct state * sp,
 				int lastditch));
+/* struct state allocator with additional setup as needed */
+static struct state *	sstate_alloc(void);
+static void		sstate_free(struct state *p);
 
 static AST_LIST_HEAD_STATIC(zonelist, state);
 #ifdef HAVE_NEWLOCALE
@@ -274,7 +331,20 @@ static void common_startup(void) {
 	struct state *sp;
 	AST_LIST_LOCK(&zonelist);
 	AST_LIST_TRAVERSE(&zonelist, sp, list) {
-		add_notify(sp, sp->name);
+		/* ensure sp->name is not relative -- it
+		 * often is -- otherwise add_notify() fails
+		 */
+		char name[FILENAME_MAX + 1];
+
+		if (sp->name[0] == '/') {
+			snprintf(name, sizeof(name), "%s", sp->name);
+		} else if (!strcmp(sp->name, TZDEFAULT)) {
+			snprintf(name, sizeof(name), "/etc/%s", sp->name);
+		} else {
+			snprintf(name, sizeof(name), "%s/%s", TZDIR, sp->name);
+		}
+
+		add_notify(sp, name);
 	}
 	AST_LIST_UNLOCK(&zonelist);
 }
@@ -284,10 +354,9 @@ static int inotify_fd = -1;
 
 static void *inotify_daemon(void *data)
 {
-	struct {
-		struct inotify_event iev;
-		char name[FILENAME_MAX + 1];
-	} buf;
+	/* inotify_event is dynamically sized */
+	struct inotify_event *iev;
+	size_t real_sizeof_iev = sizeof(*iev) + FILENAME_MAX + 1;
 	ssize_t res;
 	struct state *cur;
 
@@ -302,14 +371,15 @@ static void *inotify_daemon(void *data)
 		inotify_thread = AST_PTHREADT_NULL;
 		return NULL;
 	}
+	iev = ast_alloca(real_sizeof_iev);
 
 	common_startup();
 
 	for (;/*ever*/;) {
 		/* This read should block, most of the time. */
-		if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
+		if ((res = read(inotify_fd, iev, real_sizeof_iev)) < sizeof(*iev) && res > 0) {
 			/* This should never happen */
-			ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zu)?!!\n", res, sizeof(buf.iev));
+			ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zu)?!!\n", res, sizeof(*iev));
 			break;
 		} else if (res < 0) {
 			if (errno == EINTR || errno == EAGAIN) {
@@ -325,9 +395,9 @@ static void *inotify_daemon(void *data)
 		}
 		AST_LIST_LOCK(&zonelist);
 		AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
-			if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
+			if (cur->wd[0] == iev->wd || cur->wd[1] == iev->wd) {
 				AST_LIST_REMOVE_CURRENT(list);
-				ast_free(cur);
+				sstate_free(cur);
 				break;
 			}
 		}
@@ -342,6 +412,13 @@ static void *inotify_daemon(void *data)
 
 static void add_notify(struct state *sp, const char *path)
 {
+	/* watch for flag indicating stack automatic sp,
+	 * should not be added to watch
+	 */
+	if (SP_STACK_CHECK(sp)) {
+		return;
+	}
+
 	if (inotify_thread == AST_PTHREADT_NULL) {
 		ast_cond_init(&initialization, NULL);
 		ast_mutex_init(&initialization_lock);
@@ -376,14 +453,35 @@ static void add_notify(struct state *sp, const char *path)
 #elif defined(HAVE_KQUEUE)
 static int queue_fd = -1;
 
+/*
+ * static struct state *psx_sp and associated code will guard againt
+ * add_notify() called repeatedly for /usr/share/zoneinfo/posixrules
+ * without zonelist check as a result of some errors
+ * (any code where tzparse() is called if tzload() fails --
+ * tzparse() re-calls tzload() for /usr/share/zoneinfo/posixrules)
+ * the pointer itself is guarded by the zonelist lock
+ */
+static struct state *psx_sp = NULL;
+
+/* collect EVFILT_VNODE fflags in macro;
+ */
+#ifdef NOTE_TRUNCATE
+#	define EVVN_NOTES_BITS \
+	(NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
+	|NOTE_RENAME|NOTE_LINK|NOTE_TRUNCATE)
+#else
+#	define EVVN_NOTES_BITS \
+	(NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
+	|NOTE_RENAME|NOTE_LINK)
+#endif
+
 static void *kqueue_daemon(void *data)
 {
 	struct kevent kev;
 	struct state *sp;
-	struct timespec no_wait = { 0, 1 };
 
 	ast_mutex_lock(&initialization_lock);
-	if ((queue_fd = kqueue()) < 0) {
+	if (queue_fd < 0 && (queue_fd = kqueue()) < 0) {
 		/* ast_log uses us to format messages, so if we called ast_log, we'd be
 		 * in for a nasty loop (seen already in testing) */
 		fprintf(stderr, "Unable to initialize kqueue(): %s\n", strerror(errno));
@@ -410,55 +508,104 @@ static void *kqueue_daemon(void *data)
 
 		sp = kev.udata;
 
-		/*!\note
-		 * If the file event fired, then the file was removed, so we'll need
-		 * to reparse the entry.  The directory event is a bit more
-		 * interesting.  Unfortunately, the queue doesn't contain information
-		 * about the file that changed (only the directory itself), so unless
-		 * we kept a record of the directory state before, it's not really
-		 * possible to know what change occurred.  But if we act paranoid and
-		 * just purge the associated file, then it will get reparsed, and
-		 * everything works fine.  It may be more work, but it's a vast
-		 * improvement over the alternative implementation, which is to stat
-		 * the file repeatedly in what is essentially a busy loop. */
 		AST_LIST_LOCK(&zonelist);
-		AST_LIST_REMOVE(&zonelist, sp, list);
+		/* see comment near psx_sp in add_notify() */
+		if (sp == psx_sp) {
+			psx_sp = NULL;
+
+			sstate_free(sp);
+
+			while ((sp = AST_LIST_REMOVE_HEAD(&zonelist, list))) {
+				sstate_free(sp);
+			}
+		} else {
+			AST_LIST_REMOVE(&zonelist, sp, list);
+			sstate_free(sp);
+		}
+
+		/* Just in case the signal was sent late */
+		ast_cond_broadcast(&initialization);
 		AST_LIST_UNLOCK(&zonelist);
+	}
+
+	inotify_thread = AST_PTHREADT_NULL;
+	return NULL;
+}
+
+static void kqueue_daemon_freestate(struct state *sp)
+{
+	struct kevent kev;
+	struct timespec no_wait = { 0, 1 };
 
+	/*!\note
+	 * If the file event fired, then the file was removed, so we'll need
+	 * to reparse the entry.  The directory event is a bit more
+	 * interesting.  Unfortunately, the queue doesn't contain information
+	 * about the file that changed (only the directory itself), so unless
+	 * we kept a record of the directory state before, it's not really
+	 * possible to know what change occurred.  But if we act paranoid and
+	 * just purge the associated file, then it will get reparsed, and
+	 * everything works fine.  It may be more work, but it's a vast
+	 * improvement over the alternative implementation, which is to stat
+	 * the file repeatedly in what is essentially a busy loop. */
+
+	if (sp->fd > -1) {
 		/* If the directory event fired, remove the file event */
 		EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
 		kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
-		close(sp->fd);
+	}
 
 #ifdef HAVE_O_SYMLINK
-		if (sp->fds > -1) {
-			/* If the file event fired, remove the symlink event */
-			EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
-			kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
-			close(sp->fds);
-		}
+	if (sp->fds > -1) {
+		/* If the file event fired, remove the symlink event */
+		EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
+		kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
+	}
 #else
-		if (sp->dir) {
-			/* If the file event fired, remove the directory event */
-			EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
-			kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
-			closedir(sp->dir);
-		}
-#endif
-		ast_free(sp);
-
-		/* Just in case the signal was sent late */
-		AST_LIST_LOCK(&zonelist);
-		ast_cond_broadcast(&initialization);
-		AST_LIST_UNLOCK(&zonelist);
+	if (sp->dir) {
+		/* If the file event fired, remove the directory event */
+		EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
+		kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
 	}
+#endif
 }
 
 static void add_notify(struct state *sp, const char *path)
 {
 	struct kevent kev;
 	struct timespec no_wait = { 0, 1 };
-	char watchdir[PATH_MAX + 1] = "";
+	char   watchdir[PATH_MAX + 1] = "";
+
+	/* watch for flag indicating stack automatic sp,
+	 * should not be added to watch
+	 */
+	if (SP_STACK_CHECK(sp) || sp->fd != -1) {
+		return;
+	}
+
+	/* some errors might cause repeated calls to tzload()
+	 * for TZDEFRULES more than once if errors repeat,
+	 * so psx_sp is used to keep just one
+	 */
+	if (!strcmp(path, TZDEFRULES) ||
+	    !strcmp(path, TZDIR "/" TZDEFRULES)) {
+		int lckgot = AST_LIST_TRYLOCK(&zonelist);
+
+		if (lckgot) {
+			return;
+		}
+
+		if (psx_sp != NULL ||
+		   (psx_sp = sstate_alloc()) == NULL) {
+			AST_LIST_UNLOCK(&zonelist);
+			return;
+		}
+
+		ast_copy_string(psx_sp->name, TZDIR "/" TZDEFRULES,
+			sizeof(psx_sp->name));
+		sp = psx_sp;
+		AST_LIST_UNLOCK(&zonelist);
+	}
 
 	if (inotify_thread == AST_PTHREADT_NULL) {
 		ast_cond_init(&initialization, NULL);
@@ -482,7 +629,8 @@ static void add_notify(struct state *sp, const char *path)
 			| O_EVTONLY
 # endif
 			)) >= 0) {
-		EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_WRITE | NOTE_EXTEND | NOTE_DELETE | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
+		EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
+		errno = 0;
 		if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
 			/* According to the API docs, we may get -1 return value, due to the
 			 * NULL space for a returned event, but errno should be 0 unless
@@ -518,7 +666,8 @@ static void add_notify(struct state *sp, const char *path)
 		 * Likewise, there's no potential leak of a descriptor.
 		 */
 		EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
-				NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
+				EVVN_NOTES_BITS, 0, sp);
+		errno = 0;
 		if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
 			fprintf(stderr, "Unable to watch '%s': %s\n", watchdir, strerror(errno));
 			closedir(sp->dir);
@@ -538,7 +687,8 @@ watch_file:
 		return;
 	}
 
-	EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_WRITE | NOTE_EXTEND | NOTE_DELETE | NOTE_REVOKE | NOTE_ATTRIB, 0, sp);
+	EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
+	errno = 0;
 	if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
 		/* According to the API docs, we may get -1 return value, due to the
 		 * NULL space for a returned event, but errno should be 0 unless
@@ -550,6 +700,7 @@ watch_file:
 	}
 }
 #else
+
 static void *notify_daemon(void *data)
 {
 	struct stat st, lst;
@@ -589,7 +740,7 @@ static void *notify_daemon(void *data)
 					ast_log(LOG_NOTICE, "Removing cached TZ entry '%s' because underlying file changed.\n", name);
 				}
 				AST_LIST_REMOVE_CURRENT(list);
-				ast_free(cur);
+				sstate_free(cur);
 				continue;
 			}
 		}
@@ -623,6 +774,26 @@ static void add_notify(struct state *sp, const char *path)
 }
 #endif
 
+/*
+ * struct state allocator with additional setup as needed
+ */
+static struct state *sstate_alloc(void)
+{
+	struct state *p = ast_calloc(1, sizeof(*p));
+
+	if (p != NULL) {
+		SP_HEAP_INIT(p);
+	}
+
+	return p;
+}
+
+static void sstate_free(struct state *p)
+{
+	SP_HEAP_FREE(p);
+	ast_free(p);
+}
+
 void ast_localtime_wakeup_monitor(struct ast_test *info)
 {
 	if (inotify_thread != AST_PTHREADT_NULL) {
@@ -737,7 +908,8 @@ static int tzload(const char *name, struct state * const sp, const int doextend)
 		}
 	}
 	nread = read(fid, u.buf, sizeof u.buf);
-	if (close(fid) < 0 || nread <= 0)
+	/* comp nread < sizeof u.tzhead against unexpected short files */
+	if (close(fid) < 0 || nread < sizeof u.tzhead)
 		return -1;
 	for (stored = 4; stored <= 8; stored *= 2) {
 		int		ttisstdcnt;
@@ -864,6 +1036,11 @@ static int tzload(const char *name, struct state * const sp, const int doextend)
 		nread -= p - u.buf;
 		for (i = 0; i < nread; ++i)
 			u.buf[i] = p[i];
+		/* next loop iter. will assume at least
+		   sizeof(struct tzhead) bytes */
+		if (nread < sizeof(u.tzhead)) {
+			break;
+		}
 		/*
 		** If this is a narrow integer time_t system, we're done.
 		*/
@@ -876,6 +1053,12 @@ static int tzload(const char *name, struct state * const sp, const int doextend)
 			struct state	ts;
 			int	result;
 
+			/* for temporary struct state --
+			 * macro flags the the struct as a stack temp.
+			 * to prevent use within add_notify()
+			 */
+			SP_STACK_INIT(ts);
+
 			u.buf[nread - 1] = '\0';
 			result = tzparse(&u.buf[1], &ts, FALSE);
 			if (result == 0 && ts.typecnt == 2 &&
@@ -1443,7 +1626,7 @@ void clean_time_zones(void)
 
 	AST_LIST_LOCK(&zonelist);
 	while ((sp = AST_LIST_REMOVE_HEAD(&zonelist, list))) {
-		ast_free(sp);
+		sstate_free(sp);
 	}
 	AST_LIST_UNLOCK(&zonelist);
 }
@@ -1470,17 +1653,17 @@ static const struct state *ast_tzset(const char *zone)
 			return sp;
 		}
 	}
-	AST_LIST_UNLOCK(&zonelist);
 
-	if (!(sp = ast_calloc(1, sizeof *sp)))
+	if (!(sp = sstate_alloc())) {
+		AST_LIST_UNLOCK(&zonelist);
 		return NULL;
+	}
 
 	if (tzload(zone, sp, TRUE) != 0) {
 		if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
 			(void) gmtload(sp);
 	}
 	ast_copy_string(sp->name, zone, sizeof(sp->name));
-	AST_LIST_LOCK(&zonelist);
 	AST_LIST_INSERT_TAIL(&zonelist, sp, list);
 	AST_LIST_UNLOCK(&zonelist);
 	return sp;
@@ -1724,8 +1907,10 @@ static struct ast_tm *gmtsub(const struct timeval *timep, const long offset, str
 	}
 
 	if (!sp) {
-		if (!(sp = (struct state *) ast_calloc(1, sizeof *sp)))
+		if (!(sp = sstate_alloc())) {
+			AST_LIST_UNLOCK(&zonelist);
 			return NULL;
+		}
 		gmtload(sp);
 		AST_LIST_INSERT_TAIL(&zonelist, sp, list);
 	}
diff --git a/main/strings.c b/main/strings.c
index 299bf68..e582012 100644
--- a/main/strings.c
+++ b/main/strings.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420384 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/strings.h"
 #include "asterisk/pbx.h"
@@ -70,7 +70,7 @@ int __ast_str_helper(struct ast_str **buf, ssize_t max_len,
 		}
 		/*
 		 * Ask vsnprintf how much space we need. Remember that vsnprintf
-		 * does not count the final <code>'\\0'</code> so we must add 1.
+		 * does not count the final <code>'\0'</code> so we must add 1.
 		 */
 		va_copy(aq, ap);
 		res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
@@ -87,9 +87,6 @@ int __ast_str_helper(struct ast_str **buf, ssize_t max_len,
 			} else if (max_len == 0) {	/* if unbounded, give more room for next time */
 				need += 16 + need / 4;
 			}
-			if (0) {	/* debugging */
-				ast_verbose("extend from %d to %d\n", len, need);
-			}
 			if (
 #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
 					_ast_str_make_space(buf, need, file, lineno, function)
@@ -97,7 +94,7 @@ int __ast_str_helper(struct ast_str **buf, ssize_t max_len,
 					ast_str_make_space(buf, need)
 #endif
 				) {
-				ast_verbose("failed to extend from %d to %d\n", len, need);
+				ast_log_safe(LOG_VERBOSE, "failed to extend from %d to %d\n", len, need);
 				va_end(aq);
 				return AST_DYNSTR_BUILD_FAILED;
 			}
@@ -160,50 +157,3 @@ char *__ast_str_helper2(struct ast_str **buf, ssize_t maxlen, const char *src, s
 	return (*buf)->__AST_STR_STR;
 }
 
-static int str_hash(const void *obj, const int flags)
-{
-	return ast_str_hash(obj);
-}
-
-static int str_cmp(void *lhs, void *rhs, int flags)
-{
-	return strcmp(lhs, rhs) ? 0 : CMP_MATCH;
-}
-
-struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets)
-{
-	return ao2_container_alloc_options(opts, buckets, str_hash, str_cmp);
-}
-
-int ast_str_container_add(struct ao2_container *str_container, const char *add)
-{
-	char *ao2_add;
-
-	/* The ao2_add object is immutable so it doesn't need a lock of its own. */
-	ao2_add = ao2_alloc_options(strlen(add) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!ao2_add) {
-		return -1;
-	}
-	strcpy(ao2_add, add);/* Safe */
-
-	ao2_link(str_container, ao2_add);
-	ao2_ref(ao2_add, -1);
-	return 0;
-}
-
-void ast_str_container_remove(struct ao2_container *str_container, const char *remove)
-{
-	ao2_find(str_container, remove, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
-}
-
-char *ast_generate_random_string(char *buf, size_t size)
-{
-	int i;
-
-	for (i = 0; i < size - 1; ++i) {
-		buf[i] = 'a' + (ast_random() % 26);
-	}
-	buf[i] = '\0';
-
-	return buf;
-}
diff --git a/main/stun.c b/main/stun.c
index ebe6424..f5bdc9a 100644
--- a/main/stun.c
+++ b/main/stun.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427876 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/stun.h"
@@ -516,5 +516,5 @@ static void stun_shutdown(void)
 void ast_stun_init(void)
 {
 	ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
-	ast_register_atexit(stun_shutdown);
+	ast_register_cleanup(stun_shutdown);
 }
diff --git a/main/syslog.c b/main/syslog.c
index 55ada23..51da69a 100644
--- a/main/syslog.c
+++ b/main/syslog.c
@@ -30,7 +30,7 @@
 #include "asterisk/utils.h"
 #include "asterisk/syslog.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <syslog.h>
 
@@ -163,8 +163,16 @@ static const int logger_level_to_syslog_map[] = {
 
 int ast_syslog_priority_from_loglevel(int level)
 {
+	/* First 16 levels are reserved for system use.
+	 * Default to using LOG_NOTICE for dynamic logging.
+	 */
+	if (level >= 16 && level < ASTNUMLOGLEVELS) {
+		return LOG_NOTICE;
+	}
+
 	if (level < 0 || level >= ARRAY_LEN(logger_level_to_syslog_map)) {
 		return -1;
 	}
+
 	return logger_level_to_syslog_map[level];
 }
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index 77f5607..60fc322 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007-2013, Digium, Inc.
+ * Copyright (C) 2007-2008, Digium, Inc.
  *
  * Dwayne M. Hubbard <dhubbard at digium.com>
  *
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/module.h"
@@ -37,7 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
 #include "asterisk/astobj2.h"
 #include "asterisk/cli.h"
 #include "asterisk/taskprocessor.h"
-#include "asterisk/sem.h"
+
 
 /*!
  * \brief tps_task structure is queued to a taskprocessor
@@ -48,15 +48,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424472 $")
  */
 struct tps_task {
 	/*! \brief The execute() task callback function pointer */
-	union {
-		int (*execute)(void *datap);
-		int (*execute_local)(struct ast_taskprocessor_local *local);
-	} callback;
+	int (*execute)(void *datap);
 	/*! \brief The data pointer for the task execute() function */
 	void *datap;
 	/*! \brief AST_LIST_ENTRY overhead */
 	AST_LIST_ENTRY(tps_task) list;
-	unsigned int wants_local:1;
 };
 
 /*! \brief tps_taskprocessor_stats maintain statistics for a taskprocessor. */
@@ -71,39 +67,23 @@ struct tps_taskprocessor_stats {
 struct ast_taskprocessor {
 	/*! \brief Friendly name of the taskprocessor */
 	const char *name;
+	/*! \brief Thread poll condition */
+	ast_cond_t poll_cond;
+	/*! \brief Taskprocessor thread */
+	pthread_t poll_thread;
+	/*! \brief Taskprocessor lock */
+	ast_mutex_t taskprocessor_lock;
+	/*! \brief Taskprocesor thread run flag */
+	unsigned char poll_thread_run;
 	/*! \brief Taskprocessor statistics */
 	struct tps_taskprocessor_stats *stats;
-	void *local_data;
 	/*! \brief Taskprocessor current queue size */
 	long tps_queue_size;
 	/*! \brief Taskprocessor queue */
 	AST_LIST_HEAD_NOLOCK(tps_queue, tps_task) tps_queue;
-	struct ast_taskprocessor_listener *listener;
-	/*! Current thread executing the tasks */
-	pthread_t thread;
-	/*! Indicates if the taskprocessor is currently executing a task */
-	unsigned int executing:1;
-};
-
-/*!
- * \brief A listener for taskprocessors
- *
- * \since 12.0.0
- *
- * When a taskprocessor's state changes, the listener
- * is notified of the change. This allows for tasks
- * to be addressed in whatever way is appropriate for
- * the module using the taskprocessor.
- */
-struct ast_taskprocessor_listener {
-	/*! The callbacks the taskprocessor calls into to notify of state changes */
-	const struct ast_taskprocessor_listener_callbacks *callbacks;
-	/*! The taskprocessor that the listener is listening to */
-	struct ast_taskprocessor *tps;
-	/*! Data private to the listener */
-	void *user_data;
+	/*! \brief Taskprocessor singleton list entry */
+	AST_LIST_ENTRY(ast_taskprocessor) list;
 };
-
 #define TPS_MAX_BUCKETS 7
 /*! \brief tps_singletons is the astobj2 container for taskprocessor singletons */
 static struct ao2_container *tps_singletons;
@@ -119,6 +99,9 @@ static int tps_hash_cb(const void *obj, const int flags);
 /*! \brief The astobj2 compare callback for taskprocessors */
 static int tps_cmp_cb(void *obj, void *arg, int flags);
 
+/*! \brief The task processing function executed by a taskprocessor */
+static void *tps_processing_function(void *data);
+
 /*! \brief Destroy the taskprocessor when its refcount reaches zero */
 static void tps_taskprocessor_destroy(void *tps);
 
@@ -139,122 +122,6 @@ static struct ast_cli_entry taskprocessor_clis[] = {
 	AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),
 };
 
-struct default_taskprocessor_listener_pvt {
-	pthread_t poll_thread;
-	int dead;
-	struct ast_sem sem;
-};
-
-static void default_listener_pvt_destroy(struct default_taskprocessor_listener_pvt *pvt)
-{
-	ast_assert(pvt->dead);
-	ast_sem_destroy(&pvt->sem);
-	ast_free(pvt);
-}
-
-static void default_listener_pvt_dtor(struct ast_taskprocessor_listener *listener)
-{
-	struct default_taskprocessor_listener_pvt *pvt = listener->user_data;
-
-	default_listener_pvt_destroy(pvt);
-
-	listener->user_data = NULL;
-}
-
-/*!
- * \brief Function that processes tasks in the taskprocessor
- * \internal
- */
-static void *default_tps_processing_function(void *data)
-{
-	struct ast_taskprocessor_listener *listener = data;
-	struct ast_taskprocessor *tps = listener->tps;
-	struct default_taskprocessor_listener_pvt *pvt = listener->user_data;
-	int sem_value;
-	int res;
-
-	while (!pvt->dead) {
-		res = ast_sem_wait(&pvt->sem);
-		if (res != 0 && errno != EINTR) {
-			ast_log(LOG_ERROR, "ast_sem_wait(): %s\n",
-				strerror(errno));
-			/* Just give up */
-			break;
-		}
-		ast_taskprocessor_execute(tps);
-	}
-
-	/* No posting to a dead taskprocessor! */
-	res = ast_sem_getvalue(&pvt->sem, &sem_value);
-	ast_assert(res == 0 && sem_value == 0);
-
-	/* Free the shutdown reference (see default_listener_shutdown) */
-	ao2_t_ref(listener->tps, -1, "tps-shutdown");
-
-	return NULL;
-}
-
-static int default_listener_start(struct ast_taskprocessor_listener *listener)
-{
-	struct default_taskprocessor_listener_pvt *pvt = listener->user_data;
-
-	if (ast_pthread_create(&pvt->poll_thread, NULL, default_tps_processing_function, listener)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static void default_task_pushed(struct ast_taskprocessor_listener *listener, int was_empty)
-{
-	struct default_taskprocessor_listener_pvt *pvt = listener->user_data;
-
-	if (ast_sem_post(&pvt->sem) != 0) {
-		ast_log(LOG_ERROR, "Failed to notify of enqueued task: %s\n",
-			strerror(errno));
-	}
-}
-
-static int default_listener_die(void *data)
-{
-	struct default_taskprocessor_listener_pvt *pvt = data;
-	pvt->dead = 1;
-	return 0;
-}
-
-static void default_listener_shutdown(struct ast_taskprocessor_listener *listener)
-{
-	struct default_taskprocessor_listener_pvt *pvt = listener->user_data;
-	int res;
-
-	/* Hold a reference during shutdown */
-	ao2_t_ref(listener->tps, +1, "tps-shutdown");
-
-	ast_taskprocessor_push(listener->tps, default_listener_die, pvt);
-
-	ast_assert(pvt->poll_thread != AST_PTHREADT_NULL);
-
-	if (pthread_equal(pthread_self(), pvt->poll_thread)) {
-		res = pthread_detach(pvt->poll_thread);
-		if (res != 0) {
-			ast_log(LOG_ERROR, "pthread_detach(): %s\n", strerror(errno));
-		}
-	} else {
-		res = pthread_join(pvt->poll_thread, NULL);
-		if (res != 0) {
-			ast_log(LOG_ERROR, "pthread_join(): %s\n", strerror(errno));
-		}
-	}
-	pvt->poll_thread = AST_PTHREADT_NULL;
-}
-
-static const struct ast_taskprocessor_listener_callbacks default_listener_callbacks = {
-	.start = default_listener_start,
-	.task_pushed = default_task_pushed,
-	.shutdown = default_listener_shutdown,
-	.dtor = default_listener_pvt_dtor,
-};
-
 /*!
  * \internal
  * \brief Clean up resources on Asterisk shutdown
@@ -278,7 +145,7 @@ int ast_tps_init(void)
 
 	ast_cli_register_multiple(taskprocessor_clis, ARRAY_LEN(taskprocessor_clis));
 
-	ast_register_atexit(tps_shutdown);
+	ast_register_cleanup(tps_shutdown);
 
 	return 0;
 }
@@ -287,48 +154,19 @@ int ast_tps_init(void)
 static struct tps_task *tps_task_alloc(int (*task_exe)(void *datap), void *datap)
 {
 	struct tps_task *t;
-	if (!task_exe) {
-		ast_log(LOG_ERROR, "task_exe is NULL!\n");
-		return NULL;
+	if ((t = ast_calloc(1, sizeof(*t)))) {
+		t->execute = task_exe;
+		t->datap = datap;
 	}
-
-	t = ast_calloc(1, sizeof(*t));
-	if (!t) {
-		ast_log(LOG_ERROR, "failed to allocate task!\n");
-		return NULL;
-	}
-
-	t->callback.execute = task_exe;
-	t->datap = datap;
-
-	return t;
-}
-
-static struct tps_task *tps_task_alloc_local(int (*task_exe)(struct ast_taskprocessor_local *local), void *datap)
-{
-	struct tps_task *t;
-	if (!task_exe) {
-		ast_log(LOG_ERROR, "task_exe is NULL!\n");
-		return NULL;
-	}
-
-	t = ast_calloc(1, sizeof(*t));
-	if (!t) {
-		ast_log(LOG_ERROR, "failed to allocate task!\n");
-		return NULL;
-	}
-
-	t->callback.execute_local = task_exe;
-	t->datap = datap;
-	t->wants_local = 1;
-
 	return t;
 }
 
 /* release task resources */
 static void *tps_task_free(struct tps_task *task)
 {
-	ast_free(task);
+	if (task) {
+		ast_free(task);
+	}
 	return NULL;
 }
 
@@ -453,46 +291,102 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	return CLI_SUCCESS;
 }
 
+/* this is the task processing worker function */
+static void *tps_processing_function(void *data)
+{
+	struct ast_taskprocessor *i = data;
+	struct tps_task *t;
+	int size;
+
+	if (!i) {
+		ast_log(LOG_ERROR, "cannot start thread_function loop without a ast_taskprocessor structure.\n");
+		return NULL;
+	}
+
+	while (i->poll_thread_run) {
+		ast_mutex_lock(&i->taskprocessor_lock);
+		if (!i->poll_thread_run) {
+			ast_mutex_unlock(&i->taskprocessor_lock);
+			break;
+		}
+		if (!(size = tps_taskprocessor_depth(i))) {
+			ast_cond_wait(&i->poll_cond, &i->taskprocessor_lock);
+			if (!i->poll_thread_run) {
+				ast_mutex_unlock(&i->taskprocessor_lock);
+				break;
+			}
+		}
+		ast_mutex_unlock(&i->taskprocessor_lock);
+		/* stuff is in the queue */
+		if (!(t = tps_taskprocessor_pop(i))) {
+			ast_log(LOG_ERROR, "Wtf?? %d tasks in the queue, but we're popping blanks!\n", size);
+			continue;
+		}
+		if (!t->execute) {
+			ast_log(LOG_WARNING, "Task is missing a function to execute!\n");
+			tps_task_free(t);
+			continue;
+		}
+		t->execute(t->datap);
+
+		ast_mutex_lock(&i->taskprocessor_lock);
+		if (i->stats) {
+			i->stats->_tasks_processed_count++;
+			if (size > i->stats->max_qsize) {
+				i->stats->max_qsize = size;
+			}
+		}
+		ast_mutex_unlock(&i->taskprocessor_lock);
+
+		tps_task_free(t);
+	}
+	while ((t = tps_taskprocessor_pop(i))) {
+		tps_task_free(t);
+	}
+	return NULL;
+}
+
 /* hash callback for astobj2 */
 static int tps_hash_cb(const void *obj, const int flags)
 {
 	const struct ast_taskprocessor *tps = obj;
-	const char *name = flags & OBJ_KEY ? obj : tps->name;
 
-	return ast_str_case_hash(name);
+	return ast_str_case_hash(tps->name);
 }
 
 /* compare callback for astobj2 */
 static int tps_cmp_cb(void *obj, void *arg, int flags)
 {
 	struct ast_taskprocessor *lhs = obj, *rhs = arg;
-	const char *rhsname = flags & OBJ_KEY ? arg : rhs->name;
 
-	return !strcasecmp(lhs->name, rhsname) ? CMP_MATCH | CMP_STOP : 0;
+	return !strcasecmp(lhs->name, rhs->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 /* destroy the taskprocessor */
 static void tps_taskprocessor_destroy(void *tps)
 {
 	struct ast_taskprocessor *t = tps;
-	struct tps_task *task;
 
 	if (!tps) {
 		ast_log(LOG_ERROR, "missing taskprocessor\n");
 		return;
 	}
 	ast_debug(1, "destroying taskprocessor '%s'\n", t->name);
+	/* kill it */
+	ast_mutex_lock(&t->taskprocessor_lock);
+	t->poll_thread_run = 0;
+	ast_cond_signal(&t->poll_cond);
+	ast_mutex_unlock(&t->taskprocessor_lock);
+	pthread_join(t->poll_thread, NULL);
+	t->poll_thread = AST_PTHREADT_NULL;
+	ast_mutex_destroy(&t->taskprocessor_lock);
+	ast_cond_destroy(&t->poll_cond);
 	/* free it */
-	ast_free(t->stats);
-	t->stats = NULL;
-	ast_free((char *) t->name);
-	if (t->listener) {
-		ao2_ref(t->listener, -1);
-		t->listener = NULL;
-	}
-	while ((task = AST_LIST_REMOVE_HEAD(&t->tps_queue, list))) {
-		tps_task_free(task);
+	if (t->stats) {
+		ast_free(t->stats);
+		t->stats = NULL;
 	}
+	ast_free((char *) t->name);
 }
 
 /* pop the front task and return it */
@@ -500,9 +394,15 @@ static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps)
 {
 	struct tps_task *task;
 
+	if (!tps) {
+		ast_log(LOG_ERROR, "missing taskprocessor\n");
+		return NULL;
+	}
+	ast_mutex_lock(&tps->taskprocessor_lock);
 	if ((task = AST_LIST_REMOVE_HEAD(&tps->tps_queue, list))) {
 		tps->tps_queue_size--;
 	}
+	ast_mutex_unlock(&tps->taskprocessor_lock);
 	return task;
 }
 
@@ -521,285 +421,101 @@ const char *ast_taskprocessor_name(struct ast_taskprocessor *tps)
 	return tps->name;
 }
 
-static void listener_shutdown(struct ast_taskprocessor_listener *listener)
-{
-	listener->callbacks->shutdown(listener);
-	ao2_ref(listener->tps, -1);
-}
-
-static void taskprocessor_listener_dtor(void *obj)
-{
-	struct ast_taskprocessor_listener *listener = obj;
-
-	if (listener->callbacks->dtor) {
-		listener->callbacks->dtor(listener);
-	}
-}
-
-struct ast_taskprocessor_listener *ast_taskprocessor_listener_alloc(const struct ast_taskprocessor_listener_callbacks *callbacks, void *user_data)
-{
-	struct ast_taskprocessor_listener *listener;
-
-	listener = ao2_alloc(sizeof(*listener), taskprocessor_listener_dtor);
-	if (!listener) {
-		return NULL;
-	}
-	listener->callbacks = callbacks;
-	listener->user_data = user_data;
-
-	return listener;
-}
-
-struct ast_taskprocessor *ast_taskprocessor_listener_get_tps(const struct ast_taskprocessor_listener *listener)
-{
-	ao2_ref(listener->tps, +1);
-	return listener->tps;
-}
-
-void *ast_taskprocessor_listener_get_user_data(const struct ast_taskprocessor_listener *listener)
-{
-	return listener->user_data;
-}
-
-static void *default_listener_pvt_alloc(void)
-{
-	struct default_taskprocessor_listener_pvt *pvt;
-
-	pvt = ast_calloc(1, sizeof(*pvt));
-	if (!pvt) {
-		return NULL;
-	}
-	pvt->poll_thread = AST_PTHREADT_NULL;
-	if (ast_sem_init(&pvt->sem, 0, 0) != 0) {
-		ast_log(LOG_ERROR, "ast_sem_init(): %s\n", strerror(errno));
-		ast_free(pvt);
-		return NULL;
-	}
-	return pvt;
-}
-
-static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, struct ast_taskprocessor_listener *listener)
-{
-	RAII_VAR(struct ast_taskprocessor *, p,
-			ao2_alloc(sizeof(*p), tps_taskprocessor_destroy), ao2_cleanup);
-
-	if (!p) {
-		ast_log(LOG_WARNING, "failed to create taskprocessor '%s'\n", name);
-		return NULL;
-	}
-
-	if (!(p->stats = ast_calloc(1, sizeof(*p->stats)))) {
-		ast_log(LOG_WARNING, "failed to create taskprocessor stats for '%s'\n", name);
-		return NULL;
-	}
-	if (!(p->name = ast_strdup(name))) {
-		ao2_ref(p, -1);
-		return NULL;
-	}
-
-	ao2_ref(listener, +1);
-	p->listener = listener;
-
-	p->thread = AST_PTHREADT_NULL;
-
-	ao2_ref(p, +1);
-	listener->tps = p;
-
-	if (!(ao2_link(tps_singletons, p))) {
-		ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name);
-		return NULL;
-	}
-
-	if (p->listener->callbacks->start(p->listener)) {
-		ast_log(LOG_ERROR, "Unable to start taskprocessor listener for taskprocessor %s\n", p->name);
-		ast_taskprocessor_unreference(p);
-		return NULL;
-	}
-
-	/* RAII_VAR will decrement the refcount at the end of the function.
-	 * Since we want to pass back a reference to p, we bump the refcount
-	 */
-	ao2_ref(p, +1);
-	return p;
-
-}
-
 /* Provide a reference to a taskprocessor.  Create the taskprocessor if necessary, but don't
  * create the taskprocessor if we were told via ast_tps_options to return a reference only
  * if it already exists */
 struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_options create)
 {
-	struct ast_taskprocessor *p;
-	struct ast_taskprocessor_listener *listener;
-	struct default_taskprocessor_listener_pvt *pvt;
+	struct ast_taskprocessor *p, tmp_tps = {
+		.name = name,
+	};
 
 	if (ast_strlen_zero(name)) {
 		ast_log(LOG_ERROR, "requesting a nameless taskprocessor!!!\n");
 		return NULL;
 	}
-	p = ao2_find(tps_singletons, name, OBJ_KEY);
+	ao2_lock(tps_singletons);
+	p = ao2_find(tps_singletons, &tmp_tps, OBJ_POINTER);
 	if (p) {
+		ao2_unlock(tps_singletons);
 		return p;
 	}
 	if (create & TPS_REF_IF_EXISTS) {
 		/* calling function does not want a new taskprocessor to be created if it doesn't already exist */
+		ao2_unlock(tps_singletons);
 		return NULL;
 	}
-	/* Create a new taskprocessor. Start by creating a default listener */
-	pvt = default_listener_pvt_alloc();
-	if (!pvt) {
+	/* create a new taskprocessor */
+	if (!(p = ao2_alloc(sizeof(*p), tps_taskprocessor_destroy))) {
+		ao2_unlock(tps_singletons);
+		ast_log(LOG_WARNING, "failed to create taskprocessor '%s'\n", name);
+		return NULL;
+	}
+
+	ast_cond_init(&p->poll_cond, NULL);
+	ast_mutex_init(&p->taskprocessor_lock);
+
+	if (!(p->stats = ast_calloc(1, sizeof(*p->stats)))) {
+		ao2_unlock(tps_singletons);
+		ast_log(LOG_WARNING, "failed to create taskprocessor stats for '%s'\n", name);
+		ao2_ref(p, -1);
 		return NULL;
 	}
-	listener = ast_taskprocessor_listener_alloc(&default_listener_callbacks, pvt);
-	if (!listener) {
-		default_listener_pvt_destroy(pvt);
+	if (!(p->name = ast_strdup(name))) {
+		ao2_unlock(tps_singletons);
+		ao2_ref(p, -1);
 		return NULL;
 	}
-
-	p = __allocate_taskprocessor(name, listener);
-	if (!p) {
-		ao2_ref(listener, -1);
+	p->poll_thread_run = 1;
+	p->poll_thread = AST_PTHREADT_NULL;
+	if (ast_pthread_create(&p->poll_thread, NULL, tps_processing_function, p) < 0) {
+		ao2_unlock(tps_singletons);
+		ast_log(LOG_ERROR, "Taskprocessor '%s' failed to create the processing thread.\n", p->name);
+		ao2_ref(p, -1);
 		return NULL;
 	}
-
-	/* Unref listener here since the taskprocessor has gained a reference to the listener */
-	ao2_ref(listener, -1);
-	return p;
-}
-
-struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener)
-{
-	struct ast_taskprocessor *p = ao2_find(tps_singletons, name, OBJ_KEY);
-
-	if (p) {
-		ast_taskprocessor_unreference(p);
+	if (!(ao2_link(tps_singletons, p))) {
+		ao2_unlock(tps_singletons);
+		ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name);
+		ao2_ref(p, -1);
 		return NULL;
 	}
-	return __allocate_taskprocessor(name, listener);
-}
-
-void ast_taskprocessor_set_local(struct ast_taskprocessor *tps,
-	void *local_data)
-{
-	SCOPED_AO2LOCK(lock, tps);
-	tps->local_data = local_data;
+	ao2_unlock(tps_singletons);
+	return p;
 }
 
 /* decrement the taskprocessor reference count and unlink from the container if necessary */
 void *ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
 {
-	if (!tps) {
-		return NULL;
-	}
-
-	if (ao2_ref(tps, -1) > 3) {
-		return NULL;
+	if (tps) {
+		ao2_lock(tps_singletons);
+		ao2_unlink(tps_singletons, tps);
+		if (ao2_ref(tps, -1) > 1) {
+			ao2_link(tps_singletons, tps);
+		}
+		ao2_unlock(tps_singletons);
 	}
-	/* If we're down to 3 references, then those must be:
-	 * 1. The reference we just got rid of
-	 * 2. The container
-	 * 3. The listener
-	 */
-	ao2_unlink(tps_singletons, tps);
-	listener_shutdown(tps->listener);
 	return NULL;
 }
 
 /* push the task into the taskprocessor queue */
-static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t)
+int ast_taskprocessor_push(struct ast_taskprocessor *tps, int (*task_exe)(void *datap), void *datap)
 {
-	int previous_size;
-	int was_empty;
+	struct tps_task *t;
 
-	if (!tps) {
-		ast_log(LOG_ERROR, "tps is NULL!\n");
+	if (!tps || !task_exe) {
+		ast_log(LOG_ERROR, "%s is missing!!\n", (tps) ? "task callback" : "taskprocessor");
 		return -1;
 	}
-
-	if (!t) {
-		ast_log(LOG_ERROR, "t is NULL!\n");
+	if (!(t = tps_task_alloc(task_exe, datap))) {
+		ast_log(LOG_ERROR, "failed to allocate task!  Can't push to '%s'\n", tps->name);
 		return -1;
 	}
-
-	ao2_lock(tps);
+	ast_mutex_lock(&tps->taskprocessor_lock);
 	AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list);
-	previous_size = tps->tps_queue_size++;
-	/* The currently executing task counts as still in queue */
-	was_empty = tps->executing ? 0 : previous_size == 0;
-	ao2_unlock(tps);
-	tps->listener->callbacks->task_pushed(tps->listener, was_empty);
+	tps->tps_queue_size++;
+	ast_cond_signal(&tps->poll_cond);
+	ast_mutex_unlock(&tps->taskprocessor_lock);
 	return 0;
 }
 
-int ast_taskprocessor_push(struct ast_taskprocessor *tps, int (*task_exe)(void *datap), void *datap)
-{
-	return taskprocessor_push(tps, tps_task_alloc(task_exe, datap));
-}
-
-int ast_taskprocessor_push_local(struct ast_taskprocessor *tps, int (*task_exe)(struct ast_taskprocessor_local *datap), void *datap)
-{
-	return taskprocessor_push(tps, tps_task_alloc_local(task_exe, datap));
-}
-
-int ast_taskprocessor_execute(struct ast_taskprocessor *tps)
-{
-	struct ast_taskprocessor_local local;
-	struct tps_task *t;
-	int size;
-
-	ao2_lock(tps);
-	t = tps_taskprocessor_pop(tps);
-	if (!t) {
-		ao2_unlock(tps);
-		return 0;
-	}
-
-	tps->thread = pthread_self();
-	tps->executing = 1;
-
-	if (t->wants_local) {
-		local.local_data = tps->local_data;
-		local.data = t->datap;
-	}
-	ao2_unlock(tps);
-
-	if (t->wants_local) {
-		t->callback.execute_local(&local);
-	} else {
-		t->callback.execute(t->datap);
-	}
-	tps_task_free(t);
-
-	ao2_lock(tps);
-	tps->thread = AST_PTHREADT_NULL;
-	/* We need to check size in the same critical section where we reset the
-	 * executing bit. Avoids a race condition where a task is pushed right
-	 * after we pop an empty stack.
-	 */
-	tps->executing = 0;
-	size = tps_taskprocessor_depth(tps);
-	/* If we executed a task, bump the stats */
-	if (tps->stats) {
-		tps->stats->_tasks_processed_count++;
-		if (size > tps->stats->max_qsize) {
-			tps->stats->max_qsize = size;
-		}
-	}
-	ao2_unlock(tps);
-
-	/* If we executed a task, check for the transition to empty */
-	if (size == 0 && tps->listener->callbacks->emptied) {
-		tps->listener->callbacks->emptied(tps->listener);
-	}
-	return size > 0;
-}
-
-int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
-{
-	int is_task;
-
-	ao2_lock(tps);
-	is_task = pthread_equal(tps->thread, pthread_self());
-	ao2_unlock(tps);
-	return is_task;
-}
diff --git a/main/tcptls.c b/main/tcptls.c
index 6a36aaf..14e4fcd 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425991 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
@@ -400,7 +400,11 @@ static int tcptls_stream_close(void *cookie)
 
 			if (!stream->ssl->server) {
 				/* For client threads, ensure that the error stack is cleared */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+				ERR_remove_thread_state(NULL);
+#else
 				ERR_remove_state(0);
+#endif	/* OPENSSL_VERSION_NUMBER >= 0x10000000L */
 			}
 
 			SSL_free(stream->ssl);
@@ -548,7 +552,6 @@ static void session_instance_destructor(void *obj)
 		i->stream_cookie = NULL;
 	}
 	ast_free(i->overflow_buf);
-	ao2_cleanup(i->private_data);
 }
 
 /*! \brief
@@ -602,7 +605,7 @@ static void *handle_tcptls_connection(void *data)
 	else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
 		SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
 		if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
-			ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
+			ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
 		} else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
 			tcptls_session->ssl, tcptls_session->fd, -1))) {
 			if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
@@ -640,9 +643,15 @@ static void *handle_tcptls_connection(void *data)
 							break;
 						}
 						str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
-						ASN1_STRING_to_UTF8(&str2, str);
+						ret = ASN1_STRING_to_UTF8(&str2, str);
+						if (ret < 0) {
+							continue;
+						}
+
 						if (str2) {
-							if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) {
+							if (strlen((char *) str2) != ret) {
+								ast_log(LOG_WARNING, "Invalid certificate common name length (contains NULL bytes?)\n");
+							} else if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) {
 								found = 1;
 							}
 							ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2);
@@ -674,7 +683,7 @@ static void *handle_tcptls_connection(void *data)
 		ast_log(LOG_WARNING, "FILE * open failed!\n");
 #ifndef DO_SSL
 		if (tcptls_session->parent->tls_cfg) {
-			ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n");
+			ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n");
 		}
 #endif
 		ao2_ref(tcptls_session, -1);
@@ -708,8 +717,9 @@ void *ast_tcptls_server_root(void *data)
 		}
 		fd = ast_accept(desc->accept_fd, &addr);
 		if (fd < 0) {
-			if ((errno != EAGAIN) && (errno != EINTR)) {
-				ast_log(LOG_ERROR, "Accept failed: %s\n", strerror(errno));
+			if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINTR) && (errno != ECONNABORTED)) {
+				ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
+				break;
 			}
 			continue;
 		}
@@ -733,7 +743,7 @@ void *ast_tcptls_server_root(void *data)
 
 		/* This thread is now the only place that controls the single ref to tcptls_session */
 		if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
-			ast_log(LOG_ERROR, "Unable to launch helper thread: %s\n", strerror(errno));
+			ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
 			ast_tcptls_close_session_file(tcptls_session);
 			ao2_ref(tcptls_session, -1);
 		}
@@ -768,10 +778,13 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
 			cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
 		} else
 #endif
+#ifndef OPENSSL_NO_SSL3_METHOD
 		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
 			ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
 			cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
-		} else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
+		} else
+#endif
+		if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
 			cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
 		} else {
 			disable_ssl = 1;
@@ -808,7 +821,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
 		if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
 			if (!client) {
 				/* Clients don't need a certificate, but if its setup we can use it */
-				ast_log(LOG_ERROR, "TLS/SSL error loading cert file. <%s>\n", cfg->certfile);
+				ast_verb(0, "SSL error loading cert file. <%s>\n", cfg->certfile);
 				cfg->enabled = 0;
 				SSL_CTX_free(cfg->ssl_ctx);
 				cfg->ssl_ctx = NULL;
@@ -818,7 +831,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
 		if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
 			if (!client) {
 				/* Clients don't need a private key, but if its setup we can use it */
-				ast_log(LOG_ERROR, "TLS/SSL error loading private key file. <%s>\n", tmpprivate);
+				ast_verb(0, "SSL error loading private key file. <%s>\n", tmpprivate);
 				cfg->enabled = 0;
 				SSL_CTX_free(cfg->ssl_ctx);
 				cfg->ssl_ctx = NULL;
@@ -829,7 +842,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
 	if (!ast_strlen_zero(cfg->cipher)) {
 		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
 			if (!client) {
-				ast_log(LOG_ERROR, "TLS/SSL cipher error <%s>\n", cfg->cipher);
+				ast_verb(0, "SSL cipher error <%s>\n", cfg->cipher);
 				cfg->enabled = 0;
 				SSL_CTX_free(cfg->ssl_ctx);
 				cfg->ssl_ctx = NULL;
@@ -839,47 +852,11 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
 	}
 	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
 		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) {
-			ast_log(LOG_ERROR, "TLS/SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
+			ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
 		}
 	}
 
-#ifdef HAVE_OPENSSL_EC
-
-	if (!ast_strlen_zero(cfg->pvtfile)) {
-		BIO *bio = BIO_new_file(cfg->pvtfile, "r");
-		if (bio != NULL) {
-			DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-			if (dh != NULL) {
-				if (SSL_CTX_set_tmp_dh(cfg->ssl_ctx, dh)) {
-					long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
-					options = SSL_CTX_set_options(cfg->ssl_ctx, options);
-					ast_verb(2, "TLS/SSL DH initialized, PFS cipher-suites enabled\n");
-				}
-				DH_free(dh);
-			}
-			BIO_free(bio);
-		}
-	}
-	#ifndef SSL_CTRL_SET_ECDH_AUTO
-		#define SSL_CTRL_SET_ECDH_AUTO 94
-	#endif
-	/* SSL_CTX_set_ecdh_auto(cfg->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */
-	if (SSL_CTX_ctrl(cfg->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {
-		ast_verb(2, "TLS/SSL ECDH initialized (automatic), faster PFS ciphers enabled\n");
-	} else {
-		/* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
-		EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-		if (ecdh != NULL) {
-			if (SSL_CTX_set_tmp_ecdh(cfg->ssl_ctx, ecdh)) {
-				ast_verb(2, "TLS/SSL ECDH initialized (secp256r1), faster PFS cipher-suites enabled\n");
-			}
-			EC_KEY_free(ecdh);
-		}
-	}
-
-#endif /* #ifdef HAVE_OPENSSL_EC */
-
-	ast_verb(2, "TLS/SSL certificate ok\n");	/* We should log which one that is ok. This message doesn't really make sense in production use */
+	ast_verb(0, "SSL certificate ok\n");
 	return 1;
 #endif
 }
@@ -957,7 +934,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s
 	desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
 				 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
 	if (desc->accept_fd < 0) {
-		ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
+		ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
 			desc->name, strerror(errno));
 		return NULL;
 	}
@@ -1135,7 +1112,7 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_
 		ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER);
 	} else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
 		if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
-			ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
+			ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
 	} else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
 		if (!strcasecmp(value, "tlsv1")) {
 			ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
diff --git a/main/tdd.c b/main/tdd.c
index 8bbeae0..2a8b869 100644
--- a/main/tdd.c
+++ b/main/tdd.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 373330 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 #include <math.h>
@@ -281,9 +281,8 @@ static inline float tdd_getcarrier(float *cr, float *ci, int bit)
 } while(0);
 
 /*! Generate TDD hold tone
- * \param outbuf, buf Result buffer
- * \todo How big should this be?
- */
+ * \param buf Result buffer
+ * \todo How big should this be??? */
 int tdd_gen_holdtone(unsigned char *buf)
 {
 	int bytes = 0;
diff --git a/main/term.c b/main/term.c
index da7c2ef..132b7fa 100644
--- a/main/term.c
+++ b/main/term.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 381448 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include <sys/time.h>
@@ -40,7 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 381448 $")
 #include "asterisk/term.h"
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
-#include "asterisk/threadstorage.h"
 
 static int vt100compat;
 
@@ -55,13 +54,6 @@ static const char * const termpath[] = {
 	NULL
 	};
 
-AST_THREADSTORAGE(commonbuf);
-
-struct commonbuf {
-	short which;
-	char buffer[AST_TERM_MAX_ROTATING_BUFFERS][AST_TERM_MAX_ESCAPE_CHARS];
-};
-
 static int opposite(int color)
 {
 	int lookup[] = {
@@ -225,11 +217,11 @@ char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int
 
 static void check_fgcolor(int *fgcolor, int *attr)
 {
-	*attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
 	if (*fgcolor & 128) {
+		*attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
 		*fgcolor &= ~128;
 	}
-
+	
 	if (ast_opt_light_background) {
 		*fgcolor = opposite(*fgcolor);
 	}
@@ -257,7 +249,7 @@ int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
 
 	check_fgcolor(&fgcolor, &attr);
 	check_bgcolor(&bgcolor);
-
+	
 	if (ast_opt_force_black_background) {
 		ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
 	} else if (bgcolor) {
@@ -292,32 +284,6 @@ char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
 	return outbuf;
 }
 
-const char *ast_term_color(int fgcolor, int bgcolor)
-{
-	struct commonbuf *cb = ast_threadstorage_get(&commonbuf, sizeof(*cb));
-	char *buf;
-
-	if (!cb) {
-		return "";
-	}
-	buf = cb->buffer[cb->which++];
-	if (cb->which == AST_TERM_MAX_ROTATING_BUFFERS) {
-		cb->which = 0;
-	}
-
-	return term_color_code(buf, fgcolor, bgcolor, AST_TERM_MAX_ESCAPE_CHARS);
-}
-
-const char *ast_term_reset(void)
-{
-	if (ast_opt_force_black_background) {
-		static const char reset[] = { ESC, '[', COLOR_BLACK + 10, 'm', 0 };
-		return reset;
-	} else {
-		return quitdata;
-	}
-}
-
 char *term_strip(char *outbuf, const char *inbuf, int maxout)
 {
 	char *outbuf_ptr = outbuf;
@@ -347,22 +313,22 @@ char *term_prompt(char *outbuf, const char *inbuf, int maxout)
 		return outbuf;
 	}
 	if (ast_opt_force_black_background) {
-		snprintf(outbuf, maxout, "%c[%d;%d;%dm%c%c[%d;%dm%s",
-			ESC, ATTR_BRIGHT, COLOR_BLUE, COLOR_BLACK + 10,
+		snprintf(outbuf, maxout, "%c[%d;%dm%c%c[%d;%dm%s",
+			ESC, COLOR_BLUE, COLOR_BLACK + 10,
 			inbuf[0],
 			ESC, COLOR_WHITE, COLOR_BLACK + 10,
 			inbuf + 1);
 	} else if (ast_opt_light_background) {
-		snprintf(outbuf, maxout, "%c[%d;0m%c%c[0m%s",
+		snprintf(outbuf, maxout, "%c[%d;0m%c%c[%d;0m%s",
 			ESC, COLOR_BLUE,
 			inbuf[0],
-			ESC,
+			ESC, COLOR_BLACK,
 			inbuf + 1);
 	} else {
-		snprintf(outbuf, maxout, "%c[%d;%d;0m%c%c[0m%s",
+		snprintf(outbuf, maxout, "%c[%d;%d;0m%c%c[%d;%d;0m%s",
 			ESC, ATTR_BRIGHT, COLOR_BLUE,
 			inbuf[0],
-			ESC,
+			ESC, 0, COLOR_WHITE,
 			inbuf + 1);
 	}
 	return outbuf;
@@ -391,17 +357,17 @@ void term_filter_escapes(char *line)
 	}
 }
 
-const char *term_prep(void)
+char *term_prep(void)
 {
 	return prepdata;
 }
 
-const char *term_end(void)
+char *term_end(void)
 {
 	return enddata;
 }
 
-const char *term_quit(void)
+char *term_quit(void)
 {
 	return quitdata;
 }
diff --git a/main/test.c b/main/test.c
index 7f49aea..e1925f7 100644
--- a/main/test.c
+++ b/main/test.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428973 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/_private.h"
 
@@ -45,16 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428973 $");
 #include "asterisk/ast_version.h"
 #include "asterisk/paths.h"
 #include "asterisk/time.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-
-/*! \since 12
- * \brief The topic for test suite messages
- */
-struct stasis_topic *test_suite_topic;
+#include "asterisk/manager.h"
 
 /*! This array corresponds to the values defined in the ast_test_state enum */
 static const char * const test_result2str[] = {
@@ -77,11 +68,9 @@ struct ast_test {
 	 * CLI in addition to being saved off in status_str.
 	 */
 	struct ast_cli_args *cli;
-	enum ast_test_result_state state;   /*!< current test state */
-	unsigned int time;                  /*!< time in ms test took */
-	ast_test_cb_t *cb;                  /*!< test callback function */
-	ast_test_init_cb_t *init_cb;        /*!< test init function */
-	ast_test_cleanup_cb_t *cleanup_cb;  /*!< test cleanup function */
+	enum ast_test_result_state state; /*!< current test state */
+	unsigned int time;                /*!< time in ms test took */
+	ast_test_cb_t *cb;                /*!< test callback function */
 	AST_LIST_ENTRY(ast_test) entry;
 };
 
@@ -111,28 +100,8 @@ static int test_insert(struct ast_test *test);
 static struct ast_test *test_remove(ast_test_cb_t *cb);
 static int test_cat_cmp(const char *cat1, const char *cat2);
 
-void ast_test_debug(struct ast_test *test, const char *fmt, ...)
-{
-	struct ast_str *buf = NULL;
-	va_list ap;
-
-	buf = ast_str_create(128);
-	if (!buf) {
-		return;
-	}
-
-	va_start(ap, fmt);
-	ast_str_set_va(&buf, 0, fmt, ap);
-	va_end(ap);
-
-	if (test->cli) {
-		ast_cli(test->cli->fd, "%s", ast_str_buffer(buf));
-	}
-
-	ast_free(buf);
-}
-
-int __ast_test_status_update(const char *file, const char *func, int line, struct ast_test *test, const char *fmt, ...)
+int __ast_test_status_update(const char *file, const char *func, int line,
+		struct ast_test *test, const char *fmt, ...)
 {
 	struct ast_str *buf = NULL;
 	va_list ap;
@@ -158,40 +127,6 @@ int __ast_test_status_update(const char *file, const char *func, int line, struc
 	return 0;
 }
 
-int ast_test_register_init(const char *category, ast_test_init_cb_t *cb)
-{
-	struct ast_test *test;
-	int registered = 1;
-
-	AST_LIST_LOCK(&tests);
-	AST_LIST_TRAVERSE(&tests, test, entry) {
-		if (!(test_cat_cmp(test->info.category, category))) {
-			test->init_cb = cb;
-			registered = 0;
-		}
-	}
-	AST_LIST_UNLOCK(&tests);
-
-	return registered;
-}
-
-int ast_test_register_cleanup(const char *category, ast_test_cleanup_cb_t *cb)
-{
-	struct ast_test *test;
-	int registered = 1;
-
-	AST_LIST_LOCK(&tests);
-	AST_LIST_TRAVERSE(&tests, test, entry) {
-		if (!(test_cat_cmp(test->info.category, category))) {
-			test->cleanup_cb = cb;
-			registered = 0;
-		}
-	}
-	AST_LIST_UNLOCK(&tests);
-
-	return registered;
-}
-
 int ast_test_register(ast_test_cb_t *cb)
 {
 	struct ast_test *test;
@@ -236,35 +171,14 @@ int ast_test_unregister(ast_test_cb_t *cb)
 static void test_execute(struct ast_test *test)
 {
 	struct timeval begin;
-	enum ast_test_result_state result;
 
 	ast_str_reset(test->status_str);
 
 	begin = ast_tvnow();
-	if (test->init_cb && test->init_cb(&test->info, test)) {
-		test->state = AST_TEST_FAIL;
-		goto exit;
-	}
-	test->state = AST_TEST_NOT_RUN;
-	result = test->cb(&test->info, TEST_EXECUTE, test);
-	if (test->state != AST_TEST_FAIL) {
-		test->state = result;
-	}
-	if (test->cleanup_cb && test->cleanup_cb(&test->info, test)) {
-		test->state = AST_TEST_FAIL;
-	}
-exit:
+	test->state = test->cb(&test->info, TEST_EXECUTE, test);
 	test->time = ast_tvdiff_ms(ast_tvnow(), begin);
 }
 
-void ast_test_set_result(struct ast_test *test, enum ast_test_result_state state)
-{
-	if (test->state == AST_TEST_FAIL || state == AST_TEST_NOT_RUN) {
-		return;
-	}
-	test->state = state;
-}
-
 static void test_xml_entry(struct ast_test *test, FILE *f)
 {
 	if (!f || !test || test->state == AST_TEST_NOT_RUN) {
@@ -976,156 +890,60 @@ static struct ast_cli_entry test_cli[] = {
 	AST_CLI_DEFINE(test_cli_generate_results,          "generate test results to file"),
 };
 
-struct stasis_topic *ast_test_suite_topic(void)
+int __ast_test_suite_event_notify(const char *file, const char *func, int line,
+		const char *state, const char *fmt, ...)
 {
-	return test_suite_topic;
-}
-
-/*!
- * \since 12
- * \brief A wrapper object that can be ao2 ref counted around an \ref ast_json blob
- */
-struct ast_test_suite_message_payload {
-	struct ast_json *blob; /*!< The actual blob that we want to deliver */
-};
-
-/*! \internal
- * \since 12
- * \brief Destructor for \ref ast_test_suite_message_payload
- */
-static void test_suite_message_payload_dtor(void *obj)
-{
-	struct ast_test_suite_message_payload *payload = obj;
+	struct ast_str *buf = NULL;
+	va_list ap;
 
-	if (payload->blob) {
-		ast_json_unref(payload->blob);
+	if (!(buf = ast_str_create(128))) {
+		return -1;
 	}
-}
 
-struct ast_json *ast_test_suite_get_blob(struct ast_test_suite_message_payload *payload)
-{
-	return payload->blob;
-}
+	va_start(ap, fmt);
+	ast_str_set_va(&buf, 0, fmt, ap);
+	va_end(ap);
 
-static struct ast_manager_event_blob *test_suite_event_to_ami(struct stasis_message *msg)
-{
-	RAII_VAR(struct ast_str *, packet_string, ast_str_create(128), ast_free);
-	struct ast_test_suite_message_payload *payload;
-	struct ast_json *blob;
-	const char *type;
+	manager_event(EVENT_FLAG_TEST, "TestEvent",
+		"Type: StateChange\r\n"
+		"State: %s\r\n"
+		"AppFile: %s\r\n"
+		"AppFunction: %s\r\n"
+		"AppLine: %d\r\n%s\r\n",
+		state, file, func, line, ast_str_buffer(buf));
 
-	payload = stasis_message_data(msg);
-	if (!payload) {
-		return NULL;
-	}
-	blob = ast_test_suite_get_blob(payload);
-	if (!blob) {
-		return NULL;
-	}
-
-	type = ast_json_string_get(ast_json_object_get(blob, "type"));
-	if (ast_strlen_zero(type) || strcmp("testevent", type)) {
-		return NULL;
-	}
+	ast_free(buf);
 
-	ast_str_append(&packet_string, 0, "Type: StateChange\r\n");
-	ast_str_append(&packet_string, 0, "State: %s\r\n",
-		ast_json_string_get(ast_json_object_get(blob, "state")));
-	ast_str_append(&packet_string, 0, "AppFile: %s\r\n",
-		ast_json_string_get(ast_json_object_get(blob, "appfile")));
-	ast_str_append(&packet_string, 0, "AppFunction: %s\r\n",
-		ast_json_string_get(ast_json_object_get(blob, "appfunction")));
-	ast_str_append(&packet_string, 0, "AppLine: %jd\r\n",
-		ast_json_integer_get(ast_json_object_get(blob, "line")));
-	ast_str_append(&packet_string, 0, "%s\r\n",
-		ast_json_string_get(ast_json_object_get(blob, "data")));
-
-	return ast_manager_event_blob_create(EVENT_FLAG_REPORTING,
-		"TestEvent",
-		"%s",
-		ast_str_buffer(packet_string));
+	return 0;
 }
 
-/*! \since 12
- * \brief The message type for test suite messages
- */
-STASIS_MESSAGE_TYPE_DEFN(ast_test_suite_message_type,
-	.to_ami = test_suite_event_to_ami);
-
-void __ast_test_suite_event_notify(const char *file, const char *func, int line, const char *state, const char *fmt, ...)
+int __ast_test_suite_assert_notify(const char *file, const char *func, int line,
+		const char *exp)
 {
-	RAII_VAR(struct ast_test_suite_message_payload *, payload,
-			NULL,
-			ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, buf, NULL, ast_free);
-	va_list ap;
-
-	if (!ast_test_suite_message_type()) {
-		return;
-	}
+	manager_event(EVENT_FLAG_TEST, "TestEvent",
+		"Type: Assert\r\n"
+		"AppFile: %s\r\n"
+		"AppFunction: %s\r\n"
+		"AppLine: %d\r\n"
+		"Expression: %s\r\n",
+		file, func, line, exp);
 
-	buf = ast_str_create(128);
-	if (!buf) {
-		return;
-	}
-
-	payload = ao2_alloc(sizeof(*payload), test_suite_message_payload_dtor);
-	if (!payload) {
-		return;
-	}
-
-	va_start(ap, fmt);
-	ast_str_set_va(&buf, 0, fmt, ap);
-	va_end(ap);
-	payload->blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: i, s: s}",
-			     "type", "testevent",
-			     "state", state,
-			     "appfile", file,
-			     "appfunction", func,
-			     "line", line,
-			     "data", ast_str_buffer(buf));
-	if (!payload->blob) {
-		return;
-	}
-	msg = stasis_message_create(ast_test_suite_message_type(), payload);
-	if (!msg) {
-		return;
-	}
-	stasis_publish(ast_test_suite_topic(), msg);
+	return 0;
 }
 
-#endif /* TEST_FRAMEWORK */
-
-#ifdef TEST_FRAMEWORK
-
-static void test_cleanup(void)
+static void test_shutdown(void)
 {
 	ast_cli_unregister_multiple(test_cli, ARRAY_LEN(test_cli));
-	ao2_cleanup(test_suite_topic);
-	test_suite_topic = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(ast_test_suite_message_type);
 }
 
-#endif
+#endif /* TEST_FRAMEWORK */
 
-int ast_test_init(void)
+int ast_test_init()
 {
 #ifdef TEST_FRAMEWORK
-	ast_register_cleanup(test_cleanup);
-
-	/* Create stasis topic */
-	test_suite_topic = stasis_topic_create("test_suite_topic");
-	if (!test_suite_topic) {
-		return -1;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(ast_test_suite_message_type) != 0) {
-		return -1;
-	}
-
 	/* Register cli commands */
 	ast_cli_register_multiple(test_cli, ARRAY_LEN(test_cli));
+	ast_register_cleanup(test_shutdown);
 #endif
 
 	return 0;
diff --git a/main/threadpool.c b/main/threadpool.c
deleted file mode 100644
index 597e83e..0000000
--- a/main/threadpool.c
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012-2013, Digium, Inc.
- *
- * Mark Michelson <mmmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-
-#include "asterisk.h"
-
-#include "asterisk/threadpool.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/utils.h"
-
-/* Needs to stay prime if increased */
-#define THREAD_BUCKETS 89
-
-/*!
- * \brief An opaque threadpool structure
- *
- * A threadpool is a collection of threads that execute
- * tasks from a common queue.
- */
-struct ast_threadpool {
-	/*! Threadpool listener */
-	struct ast_threadpool_listener *listener;
-	/*!
-	 * \brief The container of active threads.
-	 * Active threads are those that are currently running tasks
-	 */
-	struct ao2_container *active_threads;
-	/*!
-	 * \brief The container of idle threads.
-	 * Idle threads are those that are currenly waiting to run tasks
-	 */
-	struct ao2_container *idle_threads;
-	/*!
-	 * \brief The container of zombie threads.
-	 * Zombie threads may be running tasks, but they are scheduled to die soon
-	 */
-	struct ao2_container *zombie_threads;
-	/*!
-	 * \brief The main taskprocessor
-	 *
-	 * Tasks that are queued in this taskprocessor are
-	 * doled out to the worker threads. Worker threads that
-	 * execute tasks from the threadpool are executing tasks
-	 * in this taskprocessor.
-	 *
-	 * The threadpool itself is actually the private data for
-	 * this taskprocessor's listener. This way, as taskprocessor
-	 * changes occur, the threadpool can alert its listeners
-	 * appropriately.
-	 */
-	struct ast_taskprocessor *tps;
-	/*!
-	 * \brief The control taskprocessor
-	 *
-	 * This is a standard taskprocessor that uses the default
-	 * taskprocessor listener. In other words, all tasks queued to
-	 * this taskprocessor have a single thread that executes the
-	 * tasks.
-	 *
-	 * All tasks that modify the state of the threadpool and all tasks
-	 * that call out to threadpool listeners are pushed to this
-	 * taskprocessor.
-	 *
-	 * For instance, when the threadpool changes sizes, a task is put
-	 * into this taskprocessor to do so. When it comes time to tell the
-	 * threadpool listener that worker threads have changed state,
-	 * the task is placed in this taskprocessor.
-	 *
-	 * This is done for three main reasons
-	 * 1) It ensures that listeners are given an accurate portrayal
-	 * of the threadpool's current state. In other words, when a listener
-	 * gets told a count of active, idle and zombie threads, it does not
-	 * need to worry that internal state of the threadpool might be different
-	 * from what it has been told.
-	 * 2) It minimizes the locking required in both the threadpool and in
-	 * threadpool listener's callbacks.
-	 * 3) It ensures that listener callbacks are called in the same order
-	 * that the threadpool had its state change.
-	 */
-	struct ast_taskprocessor *control_tps;
-	/*! True if the threadpool is in the process of shutting down */
-	int shutting_down;
-	/*! Threadpool-specific options */
-	struct ast_threadpool_options options;
-};
-
-/*!
- * \brief listener for a threadpool
- *
- * The listener is notified of changes in a threadpool. It can
- * react by doing things like increasing the number of threads
- * in the pool
- */
-struct ast_threadpool_listener {
-	/*! Callbacks called by the threadpool */
-	const struct ast_threadpool_listener_callbacks *callbacks;
-	/*! User data for the listener */
-	void *user_data;
-};
-
-/*!
- * \brief states for worker threads
- */
-enum worker_state {
-	/*! The worker is either active or idle */
-	ALIVE,
-	/*!
-	 * The worker has been asked to shut down but
-	 * may still be in the process of executing tasks.
-	 * This transition happens when the threadpool needs
-	 * to shrink and needs to kill active threads in order
-	 * to do so.
-	 */
-	ZOMBIE,
-	/*!
-	 * The worker has been asked to shut down. Typically
-	 * only idle threads go to this state directly, but
-	 * active threads may go straight to this state when
-	 * the threadpool is shut down.
-	 */
-	DEAD,
-};
-
-/*!
- * A thread that executes threadpool tasks
- */
-struct worker_thread {
-	/*! A unique (within a run of Asterisk) ID for the thread. Used for hashing and searching */
-	int id;
-	/*! Condition used in conjunction with state changes */
-	ast_cond_t cond;
-	/*! Lock used alongside the condition for state changes */
-	ast_mutex_t lock;
-	/*! The actual thread that is executing tasks */
-	pthread_t thread;
-	/*! A pointer to the threadpool. Needed to be able to execute tasks */
-	struct ast_threadpool *pool;
-	/*! The current state of the worker thread */
-	enum worker_state state;
-	/*! A boolean used to determine if an idle thread should become active */
-	int wake_up;
-	/*! Options for this threadpool */
-	struct ast_threadpool_options options;
-};
-
-/* Worker thread forward declarations. See definitions for documentation */
-static int worker_thread_hash(const void *obj, int flags);
-static int worker_thread_cmp(void *obj, void *arg, int flags);
-static void worker_thread_destroy(void *obj);
-static void worker_active(struct worker_thread *worker);
-static void *worker_start(void *arg);
-static struct worker_thread *worker_thread_alloc(struct ast_threadpool *pool);
-static int worker_thread_start(struct worker_thread *worker);
-static int worker_idle(struct worker_thread *worker);
-static void worker_set_state(struct worker_thread *worker, enum worker_state state);
-static void worker_shutdown(struct worker_thread *worker);
-
-/*!
- * \brief Notify the threadpool listener that the state has changed.
- *
- * This notifies the threadpool listener via its state_changed callback.
- * \param pool The threadpool whose state has changed
- */
-static void threadpool_send_state_changed(struct ast_threadpool *pool)
-{
-	int active_size = ao2_container_count(pool->active_threads);
-	int idle_size = ao2_container_count(pool->idle_threads);
-
-	if (pool->listener && pool->listener->callbacks->state_changed) {
-		pool->listener->callbacks->state_changed(pool, pool->listener, active_size, idle_size);
-	}
-}
-
-/*!
- * \brief Struct used for queued operations involving worker state changes
- */
-struct thread_worker_pair {
-	/*! Threadpool that contains the worker whose state has changed */
-	struct ast_threadpool *pool;
-	/*! Worker whose state has changed */
-	struct worker_thread *worker;
-};
-
-/*!
- * \brief Destructor for thread_worker_pair
- */
-static void thread_worker_pair_destructor(void *obj)
-{
-	struct thread_worker_pair *pair = obj;
-	ao2_ref(pair->worker, -1);
-}
-
-/*!
- * \brief Allocate and initialize a thread_worker_pair
- * \param pool Threadpool to assign to the thread_worker_pair
- * \param worker Worker thread to assign to the thread_worker_pair
- */
-static struct thread_worker_pair *thread_worker_pair_alloc(struct ast_threadpool *pool,
-		struct worker_thread *worker)
-{
-	struct thread_worker_pair *pair = ao2_alloc(sizeof(*pair), thread_worker_pair_destructor);
-	if (!pair) {
-		return NULL;
-	}
-	pair->pool = pool;
-	ao2_ref(worker, +1);
-	pair->worker = worker;
-	return pair;
-}
-
-/*!
- * \brief Move a worker thread from the active container to the idle container.
- *
- * This function is called from the threadpool's control taskprocessor thread.
- * \param data A thread_worker_pair containing the threadpool and the worker to move.
- * \return 0
- */
-static int queued_active_thread_idle(void *data)
-{
-	struct thread_worker_pair *pair = data;
-
-	ao2_link(pair->pool->idle_threads, pair->worker);
-	ao2_unlink(pair->pool->active_threads, pair->worker);
-
-	threadpool_send_state_changed(pair->pool);
-
-	ao2_ref(pair, -1);
-	return 0;
-}
-
-/*!
- * \brief Queue a task to move a thread from the active list to the idle list
- *
- * This is called by a worker thread when it runs out of tasks to perform and
- * goes idle.
- * \param pool The threadpool to which the worker belongs
- * \param worker The worker thread that has gone idle
- */
-static void threadpool_active_thread_idle(struct ast_threadpool *pool,
-		struct worker_thread *worker)
-{
-	struct thread_worker_pair *pair;
-	SCOPED_AO2LOCK(lock, pool);
-	if (pool->shutting_down) {
-		return;
-	}
-	pair = thread_worker_pair_alloc(pool, worker);
-	if (!pair) {
-		return;
-	}
-	ast_taskprocessor_push(pool->control_tps, queued_active_thread_idle, pair);
-}
-
-/*!
- * \brief Kill a zombie thread
- *
- * This runs from the threadpool's control taskprocessor thread.
- *
- * \param data A thread_worker_pair containing the threadpool and the zombie thread
- * \return 0
- */
-static int queued_zombie_thread_dead(void *data)
-{
-	struct thread_worker_pair *pair = data;
-
-	ao2_unlink(pair->pool->zombie_threads, pair->worker);
-	threadpool_send_state_changed(pair->pool);
-
-	ao2_ref(pair, -1);
-	return 0;
-}
-
-/*!
- * \brief Queue a task to kill a zombie thread
- *
- * This is called by a worker thread when it acknowledges that it is time for
- * it to die.
- */
-static void threadpool_zombie_thread_dead(struct ast_threadpool *pool,
-		struct worker_thread *worker)
-{
-	struct thread_worker_pair *pair;
-	SCOPED_AO2LOCK(lock, pool);
-	if (pool->shutting_down) {
-		return;
-	}
-	pair = thread_worker_pair_alloc(pool, worker);
-	if (!pair) {
-		return;
-	}
-	ast_taskprocessor_push(pool->control_tps, queued_zombie_thread_dead, pair);
-}
-
-static int queued_idle_thread_dead(void *data)
-{
-	struct thread_worker_pair *pair = data;
-
-	ao2_unlink(pair->pool->idle_threads, pair->worker);
-	threadpool_send_state_changed(pair->pool);
-
-	ao2_ref(pair, -1);
-	return 0;
-}
-
-static void threadpool_idle_thread_dead(struct ast_threadpool *pool,
-		struct worker_thread *worker)
-{
-	struct thread_worker_pair *pair;
-	SCOPED_AO2LOCK(lock, pool);
-	if (pool->shutting_down) {
-		return;
-	}
-	pair = thread_worker_pair_alloc(pool, worker);
-	if (!pair) {
-		return;
-	}
-	ast_taskprocessor_push(pool->control_tps, queued_idle_thread_dead, pair);
-}
-
-/*!
- * \brief Execute a task in the threadpool
- *
- * This is the function that worker threads call in order to execute tasks
- * in the threadpool
- *
- * \param pool The pool to which the tasks belong.
- * \retval 0 Either the pool has been shut down or there are no tasks.
- * \retval 1 There are still tasks remaining in the pool.
- */
-static int threadpool_execute(struct ast_threadpool *pool)
-{
-	ao2_lock(pool);
-	if (!pool->shutting_down) {
-		ao2_unlock(pool);
-		return ast_taskprocessor_execute(pool->tps);
-	}
-	ao2_unlock(pool);
-	return 0;
-}
-
-/*!
- * \brief Destroy a threadpool's components.
- *
- * This is the destructor called automatically when the threadpool's
- * reference count reaches zero. This is not to be confused with
- * threadpool_destroy.
- *
- * By the time this actually gets called, most of the cleanup has already
- * been done in the pool. The only thing left to do is to release the
- * final reference to the threadpool listener.
- *
- * \param obj The pool to destroy
- */
-static void threadpool_destructor(void *obj)
-{
-	struct ast_threadpool *pool = obj;
-	ao2_cleanup(pool->listener);
-}
-
-/*
- * \brief Allocate a threadpool
- *
- * This is implemented as a taskprocessor listener's alloc callback. This
- * is because the threadpool exists as the private data on a taskprocessor
- * listener.
- *
- * \param name The name of the threadpool.
- * \param options The options the threadpool uses.
- * \retval NULL Could not initialize threadpool properly
- * \retval non-NULL The newly-allocated threadpool
- */
-static struct ast_threadpool *threadpool_alloc(const char *name, const struct ast_threadpool_options *options)
-{
-	RAII_VAR(struct ast_threadpool *, pool, NULL, ao2_cleanup);
-	struct ast_str *control_tps_name;
-
-	pool = ao2_alloc(sizeof(*pool), threadpool_destructor);
-	control_tps_name = ast_str_create(64);
-	if (!pool || !control_tps_name) {
-		ast_free(control_tps_name);
-		return NULL;
-	}
-
-	ast_str_set(&control_tps_name, 0, "%s-control", name);
-
-	pool->control_tps = ast_taskprocessor_get(ast_str_buffer(control_tps_name), TPS_REF_DEFAULT);
-	ast_free(control_tps_name);
-	if (!pool->control_tps) {
-		return NULL;
-	}
-	pool->active_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
-	if (!pool->active_threads) {
-		return NULL;
-	}
-	pool->idle_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
-	if (!pool->idle_threads) {
-		return NULL;
-	}
-	pool->zombie_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
-	if (!pool->zombie_threads) {
-		return NULL;
-	}
-	pool->options = *options;
-
-	ao2_ref(pool, +1);
-	return pool;
-}
-
-static int threadpool_tps_start(struct ast_taskprocessor_listener *listener)
-{
-	return 0;
-}
-
-/*!
- * \brief helper used for queued task when tasks are pushed
- */
-struct task_pushed_data {
-	/*! Pool into which a task was pushed */
-	struct ast_threadpool *pool;
-	/*! Indicator of whether the pool had no tasks prior to the new task being added */
-	int was_empty;
-};
-
-/*!
- * \brief Allocate and initialize a task_pushed_data
- * \param pool The threadpool to set in the task_pushed_data
- * \param was_empty The was_empty value to set in the task_pushed_data
- * \retval NULL Unable to allocate task_pushed_data
- * \retval non-NULL The newly-allocated task_pushed_data
- */
-static struct task_pushed_data *task_pushed_data_alloc(struct ast_threadpool *pool,
-		int was_empty)
-{
-	struct task_pushed_data *tpd = ao2_alloc(sizeof(*tpd), NULL);
-
-	if (!tpd) {
-		return NULL;
-	}
-	tpd->pool = pool;
-	tpd->was_empty = was_empty;
-	return tpd;
-}
-
-/*!
- * \brief Activate idle threads
- *
- * This function always returns CMP_MATCH because all workers that this
- * function acts on need to be seen as matches so they are unlinked from the
- * list of idle threads.
- *
- * Called as an ao2_callback in the threadpool's control taskprocessor thread.
- * \param obj The worker to activate
- * \param arg The pool where the worker belongs
- * \retval CMP_MATCH
- */
-static int activate_thread(void *obj, void *arg, int flags)
-{
-	struct worker_thread *worker = obj;
-	struct ast_threadpool *pool = arg;
-
-	if (!ao2_link(pool->active_threads, worker)) {
-		/* If we can't link the idle thread into the active container, then
-		 * we'll just leave the thread idle and not wake it up.
-		 */
-		ast_log(LOG_WARNING, "Failed to activate thread %d. Remaining idle\n",
-				worker->id);
-		return 0;
-	}
-	worker_set_state(worker, ALIVE);
-	return CMP_MATCH;
-}
-
-/*!
- * \brief Add threads to the threadpool
- *
- * This function is called from the threadpool's control taskprocessor thread.
- * \param pool The pool that is expanding
- * \delta The number of threads to add to the pool
- */
-static void grow(struct ast_threadpool *pool, int delta)
-{
-	int i;
-
-	int current_size = ao2_container_count(pool->active_threads) +
-		ao2_container_count(pool->idle_threads);
-
-	if (pool->options.max_size && current_size + delta > pool->options.max_size) {
-		delta = pool->options.max_size - current_size;
-	}
-
-	ast_debug(3, "Increasing threadpool %s's size by %d\n",
-			ast_taskprocessor_name(pool->tps), delta);
-
-	for (i = 0; i < delta; ++i) {
-		struct worker_thread *worker = worker_thread_alloc(pool);
-		if (!worker) {
-			return;
-		}
-		if (ao2_link(pool->idle_threads, worker)) {
-			if (worker_thread_start(worker)) {
-				ast_log(LOG_ERROR, "Unable to start worker thread %d. Destroying.\n", worker->id);
-				ao2_unlink(pool->active_threads, worker);
-			}
-		} else {
-			ast_log(LOG_WARNING, "Failed to activate worker thread %d. Destroying.\n", worker->id);
-		}
-		ao2_ref(worker, -1);
-	}
-}
-
-/*!
- * \brief Queued task called when tasks are pushed into the threadpool
- *
- * This function first calls into the threadpool's listener to let it know
- * that a task has been pushed. It then wakes up all idle threads and moves
- * them into the active thread container.
- * \param data A task_pushed_data
- * \return 0
- */
-static int queued_task_pushed(void *data)
-{
-	struct task_pushed_data *tpd = data;
-	struct ast_threadpool *pool = tpd->pool;
-	int was_empty = tpd->was_empty;
-
-	if (pool->listener && pool->listener->callbacks->task_pushed) {
-		pool->listener->callbacks->task_pushed(pool, pool->listener, was_empty);
-	}
-	if (ao2_container_count(pool->idle_threads) == 0) {
-		if (!pool->options.auto_increment) {
-			return 0;
-		}
-		grow(pool, pool->options.auto_increment);
-	}
-
-	ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA,
-			activate_thread, pool);
-
-	threadpool_send_state_changed(pool);
-	ao2_ref(tpd, -1);
-	return 0;
-}
-
-/*!
- * \brief Taskprocessor listener callback called when a task is added
- *
- * The threadpool uses this opportunity to queue a task on its control taskprocessor
- * in order to activate idle threads and notify the threadpool listener that the
- * task has been pushed.
- * \param listener The taskprocessor listener. The threadpool is the listener's private data
- * \param was_empty True if the taskprocessor was empty prior to the task being pushed
- */
-static void threadpool_tps_task_pushed(struct ast_taskprocessor_listener *listener,
-		int was_empty)
-{
-	struct ast_threadpool *pool = ast_taskprocessor_listener_get_user_data(listener);
-	struct task_pushed_data *tpd;
-	SCOPED_AO2LOCK(lock, pool);
-
-	if (pool->shutting_down) {
-		return;
-	}
-	tpd = task_pushed_data_alloc(pool, was_empty);
-	if (!tpd) {
-		return;
-	}
-
-	ast_taskprocessor_push(pool->control_tps, queued_task_pushed, tpd);
-}
-
-/*!
- * \brief Queued task that handles the case where the threadpool's taskprocessor is emptied
- *
- * This simply lets the threadpool's listener know that the threadpool is devoid of tasks
- * \param data The pool that has become empty
- * \return 0
- */
-static int queued_emptied(void *data)
-{
-	struct ast_threadpool *pool = data;
-
-	/* We already checked for existence of this callback when this was queued */
-	pool->listener->callbacks->emptied(pool, pool->listener);
-	return 0;
-}
-
-/*!
- * \brief Taskprocessor listener emptied callback
- *
- * The threadpool queues a task to let the threadpool listener know that
- * the threadpool no longer contains any tasks.
- * \param listener The taskprocessor listener. The threadpool is the listener's private data.
- */
-static void threadpool_tps_emptied(struct ast_taskprocessor_listener *listener)
-{
-	struct ast_threadpool *pool = ast_taskprocessor_listener_get_user_data(listener);
-	SCOPED_AO2LOCK(lock, pool);
-
-	if (pool->shutting_down) {
-		return;
-	}
-
-	if (pool->listener && pool->listener->callbacks->emptied) {
-		ast_taskprocessor_push(pool->control_tps, queued_emptied, pool);
-	}
-}
-
-/*!
- * \brief Taskprocessor listener shutdown callback
- *
- * The threadpool will shut down and destroy all of its worker threads when
- * this is called back. By the time this gets called, the taskprocessor's
- * control taskprocessor has already been destroyed. Therefore there is no risk
- * in outright destroying the worker threads here.
- * \param listener The taskprocessor listener. The threadpool is the listener's private data.
- */
-static void threadpool_tps_shutdown(struct ast_taskprocessor_listener *listener)
-{
-	struct ast_threadpool *pool = ast_taskprocessor_listener_get_user_data(listener);
-
-	if (pool->listener && pool->listener->callbacks->shutdown) {
-		pool->listener->callbacks->shutdown(pool->listener);
-	}
-	ao2_cleanup(pool->active_threads);
-	ao2_cleanup(pool->idle_threads);
-	ao2_cleanup(pool->zombie_threads);
-	ao2_cleanup(pool);
-}
-
-/*!
- * \brief Table of taskprocessor listener callbacks for threadpool's main taskprocessor
- */
-static struct ast_taskprocessor_listener_callbacks threadpool_tps_listener_callbacks = {
-	.start = threadpool_tps_start,
-	.task_pushed = threadpool_tps_task_pushed,
-	.emptied = threadpool_tps_emptied,
-	.shutdown = threadpool_tps_shutdown,
-};
-
-/*!
- * \brief ao2 callback to kill a set number of threads.
- *
- * Threads will be unlinked from the container as long as the
- * counter has not reached zero. The counter is decremented with
- * each thread that is removed.
- * \param obj The worker thread up for possible destruction
- * \param arg The counter
- * \param flags Unused
- * \retval CMP_MATCH The counter has not reached zero, so this flag should be removed.
- * \retval CMP_STOP The counter has reached zero so no more threads should be removed.
- */
-static int kill_threads(void *obj, void *arg, int flags)
-{
-	int *num_to_kill = arg;
-
-	if (*num_to_kill > 0) {
-		--(*num_to_kill);
-		return CMP_MATCH;
-	} else {
-		return CMP_STOP;
-	}
-}
-
-/*!
- * \brief ao2 callback to zombify a set number of threads.
- *
- * Threads will be zombified as long as as the counter has not reached
- * zero. The counter is decremented with each thread that is zombified.
- *
- * Zombifying a thread involves removing it from its current container,
- * adding it to the zombie container, and changing the state of the
- * worker to a zombie
- *
- * This callback is called from the threadpool control taskprocessor thread.
- *
- * \param obj The worker thread that may be zombified
- * \param arg The pool to which the worker belongs
- * \param data The counter
- * \param flags Unused
- * \retval CMP_MATCH The zombified thread should be removed from its current container
- * \retval CMP_STOP Stop attempting to zombify threads
- */
-static int zombify_threads(void *obj, void *arg, void *data, int flags)
-{
-	struct worker_thread *worker = obj;
-	struct ast_threadpool *pool = arg;
-	int *num_to_zombify = data;
-
-	if ((*num_to_zombify)-- > 0) {
-		if (!ao2_link(pool->zombie_threads, worker)) {
-			ast_log(LOG_WARNING, "Failed to zombify active thread %d. Thread will remain active\n", worker->id);
-			return 0;
-		}
-		worker_set_state(worker, ZOMBIE);
-		return CMP_MATCH;
-	} else {
-		return CMP_STOP;
-	}
-}
-
-/*!
- * \brief Remove threads from the threadpool
- *
- * The preference is to kill idle threads. However, if there are
- * more threads to remove than there are idle threads, then active
- * threads will be zombified instead.
- *
- * This function is called from the threadpool control taskprocessor thread.
- *
- * \param pool The threadpool to remove threads from
- * \param delta The number of threads to remove
- */
-static void shrink(struct ast_threadpool *pool, int delta)
-{
-	/*
-	 * Preference is to kill idle threads, but
-	 * we'll move on to deactivating active threads
-	 * if we have to
-	 */
-	int idle_threads = ao2_container_count(pool->idle_threads);
-	int idle_threads_to_kill = MIN(delta, idle_threads);
-	int active_threads_to_zombify = delta - idle_threads_to_kill;
-
-	ast_debug(3, "Destroying %d idle threads in threadpool %s\n", idle_threads_to_kill,
-			ast_taskprocessor_name(pool->tps));
-
-	ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE,
-			kill_threads, &idle_threads_to_kill);
-
-	ast_debug(3, "Destroying %d active threads in threadpool %s\n", active_threads_to_zombify,
-			ast_taskprocessor_name(pool->tps));
-
-	ao2_callback_data(pool->active_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE,
-			zombify_threads, pool, &active_threads_to_zombify);
-}
-
-/*!
- * \brief Helper struct used for queued operations that change the size of the threadpool
- */
-struct set_size_data {
-	/*! The pool whose size is to change */
-	struct ast_threadpool *pool;
-	/*! The requested new size of the pool */
-	unsigned int size;
-};
-
-/*!
- * \brief Allocate and initialize a set_size_data
- * \param pool The pool for the set_size_data
- * \param size The size to store in the set_size_data
- */
-static struct set_size_data *set_size_data_alloc(struct ast_threadpool *pool,
-		unsigned int size)
-{
-	struct set_size_data *ssd = ao2_alloc(sizeof(*ssd), NULL);
-	if (!ssd) {
-		return NULL;
-	}
-
-	ssd->pool = pool;
-	ssd->size = size;
-	return ssd;
-}
-
-/*!
- * \brief Change the size of the threadpool
- *
- * This can either result in shrinking or growing the threadpool depending
- * on the new desired size and the current size.
- *
- * This function is run from the threadpool control taskprocessor thread
- *
- * \param data A set_size_data used for determining how to act
- * \return 0
- */
-static int queued_set_size(void *data)
-{
-	RAII_VAR(struct set_size_data *, ssd, data, ao2_cleanup);
-	struct ast_threadpool *pool = ssd->pool;
-	unsigned int num_threads = ssd->size;
-
-	/* We don't count zombie threads as being "live" when potentially resizing */
-	unsigned int current_size = ao2_container_count(pool->active_threads) +
-		ao2_container_count(pool->idle_threads);
-
-	if (current_size == num_threads) {
-		ast_debug(3, "Not changing threadpool size since new size %u is the same as current %u\n",
-			  num_threads, current_size);
-		return 0;
-	}
-
-	if (current_size < num_threads) {
-		grow(pool, num_threads - current_size);
-		ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE,
-				activate_thread, pool);
-	} else {
-		shrink(pool, current_size - num_threads);
-	}
-
-	threadpool_send_state_changed(pool);
-	return 0;
-}
-
-void ast_threadpool_set_size(struct ast_threadpool *pool, unsigned int size)
-{
-	struct set_size_data *ssd;
-	SCOPED_AO2LOCK(lock, pool);
-	if (pool->shutting_down) {
-		return;
-	}
-
-	ssd = set_size_data_alloc(pool, size);
-	if (!ssd) {
-		return;
-	}
-
-	ast_taskprocessor_push(pool->control_tps, queued_set_size, ssd);
-}
-
-struct ast_threadpool_listener *ast_threadpool_listener_alloc(
-		const struct ast_threadpool_listener_callbacks *callbacks, void *user_data)
-{
-	struct ast_threadpool_listener *listener = ao2_alloc(sizeof(*listener), NULL);
-	if (!listener) {
-		return NULL;
-	}
-	listener->callbacks = callbacks;
-	listener->user_data = user_data;
-	return listener;
-}
-
-void *ast_threadpool_listener_get_user_data(const struct ast_threadpool_listener *listener)
-{
-	return listener->user_data;
-}
-
-struct pool_options_pair {
-	struct ast_threadpool *pool;
-	struct ast_threadpool_options options;
-};
-
-struct ast_threadpool *ast_threadpool_create(const char *name,
-		struct ast_threadpool_listener *listener,
-		const struct ast_threadpool_options *options)
-{
-	struct ast_taskprocessor *tps;
-	RAII_VAR(struct ast_taskprocessor_listener *, tps_listener, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_threadpool *, pool, NULL, ao2_cleanup);
-
-	pool = threadpool_alloc(name, options);
-	if (!pool) {
-		return NULL;
-	}
-
-	tps_listener = ast_taskprocessor_listener_alloc(&threadpool_tps_listener_callbacks, pool);
-	if (!tps_listener) {
-		return NULL;
-	}
-
-	if (options->version != AST_THREADPOOL_OPTIONS_VERSION) {
-		ast_log(LOG_WARNING, "Incompatible version of threadpool options in use.\n");
-		return NULL;
-	}
-
-	tps = ast_taskprocessor_create_with_listener(name, tps_listener);
-	if (!tps) {
-		return NULL;
-	}
-
-	pool->tps = tps;
-	if (listener) {
-		ao2_ref(listener, +1);
-		pool->listener = listener;
-	}
-	ast_threadpool_set_size(pool, pool->options.initial_size);
-	ao2_ref(pool, +1);
-	return pool;
-}
-
-int ast_threadpool_push(struct ast_threadpool *pool, int (*task)(void *data), void *data)
-{
-	SCOPED_AO2LOCK(lock, pool);
-	if (!pool->shutting_down) {
-		return ast_taskprocessor_push(pool->tps, task, data);
-	}
-	return -1;
-}
-
-void ast_threadpool_shutdown(struct ast_threadpool *pool)
-{
-	if (!pool) {
-		return;
-	}
-	/* Shut down the taskprocessors and everything else just
-	 * takes care of itself via the taskprocessor callbacks
-	 */
-	ao2_lock(pool);
-	pool->shutting_down = 1;
-	ao2_unlock(pool);
-	ast_taskprocessor_unreference(pool->control_tps);
-	ast_taskprocessor_unreference(pool->tps);
-}
-
-/*!
- * A monotonically increasing integer used for worker
- * thread identification.
- */
-static int worker_id_counter;
-
-static int worker_thread_hash(const void *obj, int flags)
-{
-	const struct worker_thread *worker = obj;
-
-	return worker->id;
-}
-
-static int worker_thread_cmp(void *obj, void *arg, int flags)
-{
-	struct worker_thread *worker1 = obj;
-	struct worker_thread *worker2 = arg;
-
-	return worker1->id == worker2->id ? CMP_MATCH : 0;
-}
-
-/*!
- * \brief shut a worker thread down
- *
- * Set the worker dead and then wait for its thread
- * to finish executing.
- *
- * \param worker The worker thread to shut down
- */
-static void worker_shutdown(struct worker_thread *worker)
-{
-	worker_set_state(worker, DEAD);
-	if (worker->thread != AST_PTHREADT_NULL) {
-		pthread_join(worker->thread, NULL);
-		worker->thread = AST_PTHREADT_NULL;
-	}
-}
-
-/*!
- * \brief Worker thread destructor
- *
- * Called automatically when refcount reaches 0. Shuts
- * down the worker thread and destroys its component
- * parts
- */
-static void worker_thread_destroy(void *obj)
-{
-	struct worker_thread *worker = obj;
-	ast_debug(3, "Destroying worker thread %d\n", worker->id);
-	worker_shutdown(worker);
-	ast_mutex_destroy(&worker->lock);
-	ast_cond_destroy(&worker->cond);
-}
-
-/*!
- * \brief start point for worker threads
- *
- * Worker threads start in the active state but may
- * immediately go idle if there is no work to be
- * done
- *
- * \param arg The worker thread
- * \retval NULL
- */
-static void *worker_start(void *arg)
-{
-	struct worker_thread *worker = arg;
-
-	if (worker->options.thread_start) {
-		worker->options.thread_start();
-	}
-
-	ast_mutex_lock(&worker->lock);
-	while (worker_idle(worker)) {
-		ast_mutex_unlock(&worker->lock);
-		worker_active(worker);
-		ast_mutex_lock(&worker->lock);
-		if (worker->state != ALIVE) {
-			break;
-		}
-		threadpool_active_thread_idle(worker->pool, worker);
-	}
-	ast_mutex_unlock(&worker->lock);
-
-	/* Reaching this portion means the thread is
-	 * on death's door. It may have been killed while
-	 * it was idle, in which case it can just die
-	 * peacefully. If it's a zombie, though, then
-	 * it needs to let the pool know so
-	 * that the thread can be removed from the
-	 * list of zombie threads.
-	 */
-	if (worker->state == ZOMBIE) {
-		threadpool_zombie_thread_dead(worker->pool, worker);
-	}
-
-	if (worker->options.thread_end) {
-		worker->options.thread_end();
-	}
-	return NULL;
-}
-
-/*!
- * \brief Allocate and initialize a new worker thread
- *
- * This will create, initialize, and start the thread.
- *
- * \param pool The threadpool to which the worker will be added
- * \retval NULL Failed to allocate or start the worker thread
- * \retval non-NULL The newly-created worker thread
- */
-static struct worker_thread *worker_thread_alloc(struct ast_threadpool *pool)
-{
-	struct worker_thread *worker = ao2_alloc(sizeof(*worker), worker_thread_destroy);
-	if (!worker) {
-		return NULL;
-	}
-	worker->id = ast_atomic_fetchadd_int(&worker_id_counter, 1);
-	ast_mutex_init(&worker->lock);
-	ast_cond_init(&worker->cond, NULL);
-	worker->pool = pool;
-	worker->thread = AST_PTHREADT_NULL;
-	worker->state = ALIVE;
-	worker->options = pool->options;
-	return worker;
-}
-
-static int worker_thread_start(struct worker_thread *worker)
-{
-	return ast_pthread_create(&worker->thread, NULL, worker_start, worker);
-}
-
-/*!
- * \brief Active loop for worker threads
- *
- * The worker will stay in this loop for its lifetime,
- * executing tasks as they become available. If there
- * are no tasks currently available, then the thread
- * will go idle.
- *
- * \param worker The worker thread executing tasks.
- */
-static void worker_active(struct worker_thread *worker)
-{
-	int alive;
-
-	/* The following is equivalent to 
-	 *
-	 * while (threadpool_execute(worker->pool));
-	 *
-	 * However, reviewers have suggested in the past
-	 * doing that can cause optimizers to (wrongly)
-	 * optimize the code away.
-	 */
-	do {
-		alive = threadpool_execute(worker->pool);
-	} while (alive);
-}
-
-/*!
- * \brief Idle function for worker threads
- *
- * The worker waits here until it gets told by the threadpool
- * to wake up.
- *
- * worker is locked before entering this function.
- *
- * \param worker The idle worker
- * \retval 0 The thread is being woken up so that it can conclude.
- * \retval non-zero The thread is being woken up to do more work.
- */
-static int worker_idle(struct worker_thread *worker)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + worker->options.idle_timeout,
-		.tv_nsec = start.tv_usec * 1000,
-	};
-	while (!worker->wake_up) {
-		if (worker->options.idle_timeout <= 0) {
-			ast_cond_wait(&worker->cond, &worker->lock);
-		} else if (ast_cond_timedwait(&worker->cond, &worker->lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	if (!worker->wake_up) {
-		ast_debug(1, "Worker thread idle timeout reached. Dying.\n");
-		threadpool_idle_thread_dead(worker->pool, worker);
-		worker->state = DEAD;
-	}
-	worker->wake_up = 0;
-	return worker->state == ALIVE;
-}
-
-/*!
- * \brief Change a worker's state
- *
- * The threadpool calls into this function in order to let a worker know
- * how it should proceed.
- */
-static void worker_set_state(struct worker_thread *worker, enum worker_state state)
-{
-	SCOPED_MUTEX(lock, &worker->lock);
-	worker->state = state;
-	worker->wake_up = 1;
-	ast_cond_signal(&worker->cond);
-}
-
-struct serializer {
-	struct ast_threadpool *pool;
-};
-
-static void serializer_dtor(void *obj)
-{
-	struct serializer *ser = obj;
-	ao2_cleanup(ser->pool);
-	ser->pool = NULL;
-}
-
-static struct serializer *serializer_create(struct ast_threadpool *pool)
-{
-	struct serializer *ser;
-
-	ser = ao2_alloc_options(sizeof(*ser), serializer_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!ser) {
-		return NULL;
-	}
-	ao2_ref(pool, +1);
-	ser->pool = pool;
-	return ser;
-}
-
-static int execute_tasks(void *data)
-{
-	struct ast_taskprocessor *tps = data;
-
-	while (ast_taskprocessor_execute(tps)) {
-		/* No-op */
-	}
-
-	ast_taskprocessor_unreference(tps);
-	return 0;
-}
-
-static void serializer_task_pushed(struct ast_taskprocessor_listener *listener, int was_empty)
-{
-	if (was_empty) {
-		struct serializer *ser = ast_taskprocessor_listener_get_user_data(listener);
-		struct ast_taskprocessor *tps = ast_taskprocessor_listener_get_tps(listener);
-
-		if (ast_threadpool_push(ser->pool, execute_tasks, tps)) {
-			ast_taskprocessor_unreference(tps);
-		}
-	}
-}
-
-static int serializer_start(struct ast_taskprocessor_listener *listener)
-{
-	/* No-op */
-	return 0;
-}
-
-static void serializer_shutdown(struct ast_taskprocessor_listener *listener)
-{
-	struct serializer *ser = ast_taskprocessor_listener_get_user_data(listener);
-	ao2_cleanup(ser);
-}
-
-static struct ast_taskprocessor_listener_callbacks serializer_tps_listener_callbacks = {
-	.task_pushed = serializer_task_pushed,
-	.start = serializer_start,
-	.shutdown = serializer_shutdown,
-};
-
-struct ast_taskprocessor *ast_threadpool_serializer(const char *name, struct ast_threadpool *pool)
-{
-	RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_taskprocessor_listener *, listener, NULL, ao2_cleanup);
-	struct ast_taskprocessor *tps = NULL;
-
-	ser = serializer_create(pool);
-	if (!ser) {
-		return NULL;
-	}
-
-	listener = ast_taskprocessor_listener_alloc(&serializer_tps_listener_callbacks, ser);
-	if (!listener) {
-		return NULL;
-	}
-	ser = NULL; /* ownership transferred to listener */
-
-	tps = ast_taskprocessor_create_with_listener(name, listener);
-	if (!tps) {
-		return NULL;
-	}
-
-	return tps;
-}
diff --git a/main/threadstorage.c b/main/threadstorage.c
index 8515719..4c46a0f 100644
--- a/main/threadstorage.c
+++ b/main/threadstorage.c
@@ -38,7 +38,7 @@ void threadstorage_init(void)
 
 #else /* !defined(DEBUG_THREADLOCALS) */
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397110 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/strings.h"
 #include "asterisk/utils.h"
@@ -258,7 +258,7 @@ void threadstorage_init(void)
 {
 	pthread_mutex_init(&threadstoragelock, NULL);
 	ast_cli_register_multiple(cli, ARRAY_LEN(cli));
-	ast_register_atexit(threadstorage_shutdown);
+	ast_register_cleanup(threadstorage_shutdown);
 }
 
 #endif /* !defined(DEBUG_THREADLOCALS) */
diff --git a/main/timing.c b/main/timing.c
index 67bcd14..335c269 100644
--- a/main/timing.c
+++ b/main/timing.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 407749 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 
@@ -54,7 +54,7 @@ struct timing_holder {
 static struct ast_heap *timing_interfaces;
 
 struct ast_timer {
-	void *data;
+	int fd;
 	struct timing_holder *holder;
 };
 
@@ -84,8 +84,7 @@ void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
 	    !funcs->timer_get_event ||
 	    !funcs->timer_get_max_rate ||
 	    !funcs->timer_enable_continuous ||
-	    !funcs->timer_disable_continuous ||
-	    !funcs->timer_fd) {
+	    !funcs->timer_disable_continuous) {
 		return NULL;
 	}
 
@@ -123,22 +122,22 @@ int ast_unregister_timing_interface(void *handle)
 
 struct ast_timer *ast_timer_open(void)
 {
-	void *data = NULL;
+	int fd = -1;
 	struct timing_holder *h;
 	struct ast_timer *t = NULL;
 
 	ast_heap_rdlock(timing_interfaces);
 
 	if ((h = ast_heap_peek(timing_interfaces, 1))) {
-		data = h->iface->timer_open();
+		fd = h->iface->timer_open();
 		ast_module_ref(h->mod);
 	}
 
-	if (data) {
+	if (fd != -1) {
 		if (!(t = ast_calloc(1, sizeof(*t)))) {
-			h->iface->timer_close(data);
+			h->iface->timer_close(fd);
 		} else {
-			t->data = data;
+			t->fd = fd;
 			t->holder = h;
 		}
 	}
@@ -150,44 +149,69 @@ struct ast_timer *ast_timer_open(void)
 
 void ast_timer_close(struct ast_timer *handle)
 {
-	handle->holder->iface->timer_close(handle->data);
+	handle->holder->iface->timer_close(handle->fd);
+	handle->fd = -1;
 	ast_module_unref(handle->holder->mod);
 	ast_free(handle);
 }
 
 int ast_timer_fd(const struct ast_timer *handle)
 {
-	return handle->holder->iface->timer_fd(handle->data);
+	return handle->fd;
 }
 
 int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
 {
-	return handle->holder->iface->timer_set_rate(handle->data, rate);
+	int res = -1;
+
+	res = handle->holder->iface->timer_set_rate(handle->fd, rate);
+
+	return res;
 }
 
 int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
 {
-	return handle->holder->iface->timer_ack(handle->data, quantity);
+	int res = -1;
+
+	res = handle->holder->iface->timer_ack(handle->fd, quantity);
+
+	return res;
 }
 
 int ast_timer_enable_continuous(const struct ast_timer *handle)
 {
-	return handle->holder->iface->timer_enable_continuous(handle->data);
+	int res = -1;
+
+	res = handle->holder->iface->timer_enable_continuous(handle->fd);
+
+	return res;
 }
 
 int ast_timer_disable_continuous(const struct ast_timer *handle)
 {
-	return handle->holder->iface->timer_disable_continuous(handle->data);
+	int res = -1;
+
+	res = handle->holder->iface->timer_disable_continuous(handle->fd);
+
+	return res;
 }
 
 enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
 {
-	return handle->holder->iface->timer_get_event(handle->data);
+	enum ast_timer_event res = -1;
+
+	res = handle->holder->iface->timer_get_event(handle->fd);
+
+	return res;
 }
 
 unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
 {
-	return handle->holder->iface->timer_get_max_rate(handle->data);
+	unsigned int res = 0;
+
+	res = handle->holder->iface->timer_get_max_rate(handle->fd);
+
+	return res;
 }
 
 const char *ast_timer_get_name(const struct ast_timer *handle)
@@ -289,7 +313,7 @@ int ast_timing_init(void)
 		return -1;
 	}
 
-	ast_register_atexit(timing_shutdown);
+	ast_register_cleanup(timing_shutdown);
 
 	return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
 }
diff --git a/main/translate.c b/main/translate.c
index 520793f..e95e06b 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426079 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -43,7 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426079 $")
 #include "asterisk/sched.h"
 #include "asterisk/cli.h"
 #include "asterisk/term.h"
-#include "asterisk/format.h"
+#include "asterisk/linkedlists.h"
 
 /*! \todo
  * TODO: sample frames for each supported input format.
@@ -77,11 +77,11 @@ struct translator_path {
 static struct translator_path **__matrix;
 
 /*!
- * \brief table for converting index to format values.
+ * \brief table for converting index to format id values.
  *
  * \note this table is protected by the table_lock.
  */
-static unsigned int *__indextable;
+static int *__indextable;
 
 /*! protects the __indextable for resizing */
 static ast_rwlock_t tablelock;
@@ -100,9 +100,9 @@ static void matrix_rebuild(int samples);
 
 /*!
  * \internal
- * \brief converts codec id to index value.
+ * \brief converts format id to index value.
  */
-static int codec_to_index(unsigned int id)
+static int format2index(enum ast_format_id id)
 {
 	int x;
 
@@ -120,34 +120,16 @@ static int codec_to_index(unsigned int id)
 
 /*!
  * \internal
- * \brief converts codec to index value.
- */
-static int codec2index(struct ast_codec *codec)
-{
-	return codec_to_index(codec->id);
-}
-
-/*!
- * \internal
- * \brief converts format to codec index value.
- */
-static int format2index(struct ast_format *format)
-{
-	return codec_to_index(ast_format_get_codec_id(format));
-}
-
-/*!
- * \internal
- * \brief add a new codec to the matrix and index table structures.
+ * \brief add a new format to the matrix and index table structures.
  *
- * \note it is perfectly safe to call this on codecs already indexed.
+ * \note it is perfectly safe to call this on formats already indexed.
  *
  * \retval 0, success
  * \retval -1, matrix and index table need to be resized
  */
-static int add_codec2index(struct ast_codec *codec)
+static int add_format2index(enum ast_format_id id)
 {
-	if (codec2index(codec) != -1) {
+	if (format2index(id) != -1) {
 		/* format is already already indexed */
 		return 0;
 	}
@@ -157,7 +139,7 @@ static int add_codec2index(struct ast_codec *codec)
 		ast_rwlock_unlock(&tablelock);
 		return -1; /* hit max length */
 	}
-	__indextable[cur_max_index] = codec->id;
+	__indextable[cur_max_index] = id;
 	cur_max_index++;
 	ast_rwlock_unlock(&tablelock);
 
@@ -166,20 +148,20 @@ static int add_codec2index(struct ast_codec *codec)
 
 /*!
  * \internal
- * \brief converts index value back to codec
+ * \brief converts index value back to format id
  */
-static struct ast_codec *index2codec(int index)
+static enum ast_format_id index2format(int index)
 {
-	struct ast_codec *codec;
+	enum ast_format_id format_id;
 
 	if (index >= cur_max_index) {
 		return 0;
 	}
 	ast_rwlock_rdlock(&tablelock);
-	codec = ast_codec_get_by_id(__indextable[index]);
+	format_id = __indextable[index];
 	ast_rwlock_unlock(&tablelock);
 
-	return codec;
+	return format_id;
 }
 
 /*!
@@ -195,7 +177,7 @@ static struct ast_codec *index2codec(int index)
 static int matrix_resize(int init)
 {
 	struct translator_path **tmp_matrix = NULL;
-	unsigned int *tmp_table = NULL;
+	int *tmp_table = NULL;
 	int old_index;
 	int x;
 
@@ -221,7 +203,7 @@ static int matrix_resize(int init)
 	}
 
 	/* make new index table */
-	if (!(tmp_table = ast_calloc(1, sizeof(unsigned int) * index_size))) {
+	if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
 		goto resize_cleanup;
 	}
 
@@ -232,7 +214,7 @@ static int matrix_resize(int init)
 		}
 		ast_free(__matrix);
 
-		memcpy(tmp_table, __indextable, sizeof(unsigned int) * old_index);
+		memcpy(tmp_table, __indextable, sizeof(int) * old_index);
 		ast_free(__indextable);
 	}
 
@@ -289,23 +271,11 @@ static struct translator_path *matrix_get(unsigned int x, unsigned int y)
  * wrappers around the translator routines.
  */
 
-static void destroy(struct ast_trans_pvt *pvt)
-{
-	struct ast_translator *t = pvt->t;
-
-	if (t->destroy) {
-		t->destroy(pvt);
-	}
-	ao2_cleanup(pvt->f.subclass.format);
-	ast_free(pvt);
-	ast_module_unref(t->module);
-}
-
 /*!
  * \brief Allocate the descriptor, required outbuf space,
  * and possibly desc.
  */
-static struct ast_trans_pvt *newpvt(struct ast_translator *t)
+static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst)
 {
 	struct ast_trans_pvt *pvt;
 	int len;
@@ -331,49 +301,28 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t)
 	if (t->buf_size) {/* finally buffer and header */
 		pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
 	}
-
-	ast_module_ref(t->module);
-
+	/* if a explicit destination format is provided, set that on the pvt so the
+	 * translator will process it. */
+	if (explicit_dst) {
+		ast_format_copy(&pvt->explicit_dst, explicit_dst);
+	}
 	/* call local init routine, if present */
 	if (t->newpvt && t->newpvt(pvt)) {
 		ast_free(pvt);
-		ast_module_unref(t->module);
 		return NULL;
 	}
+	ast_module_ref(t->module);
+	return pvt;
+}
 
-	/* Setup normal static translation frame. */
-	pvt->f.frametype = AST_FRAME_VOICE;
-	pvt->f.mallocd = 0;
-	pvt->f.offset = AST_FRIENDLY_OFFSET;
-	pvt->f.src = pvt->t->name;
-	pvt->f.data.ptr = pvt->outbuf.c;
-
-	/* if the translator has not provided a format find one in the cache or create one */
-	if (!pvt->f.subclass.format) {
-		if (!ast_strlen_zero(pvt->t->format)) {
-			pvt->f.subclass.format = ast_format_cache_get(pvt->t->format);
-		}
-
-		if (!pvt->f.subclass.format) {
-			struct ast_codec *codec = ast_codec_get(t->dst_codec.name,
-				t->dst_codec.type, t->dst_codec.sample_rate);
-			if (!codec) {
-				ast_log(LOG_ERROR, "Unable to get destination codec\n");
-				destroy(pvt);
-				return NULL;
-			}
-			pvt->f.subclass.format = ast_format_create(codec);
-			ao2_ref(codec, -1);
-		}
-
-		if (!pvt->f.subclass.format) {
-			ast_log(LOG_ERROR, "Unable to create format\n");
-			destroy(pvt);
-			return NULL;
-		}
-	}
+static void destroy(struct ast_trans_pvt *pvt)
+{
+	struct ast_translator *t = pvt->t;
 
-	return pvt;
+	if (t->destroy)
+		t->destroy(pvt);
+	ast_free(pvt);
+	ast_module_unref(t->module);
 }
 
 /*! \brief framein wrapper, deals with bound checks.  */
@@ -426,9 +375,8 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
 	if (samples) {
 		f->samples = samples;
 	} else {
-		if (pvt->samples == 0) {
+		if (pvt->samples == 0)
 			return NULL;
-		}
 		f->samples = pvt->samples;
 		pvt->samples = 0;
 	}
@@ -439,6 +387,13 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
 		pvt->datalen = 0;
 	}
 
+	f->frametype = AST_FRAME_VOICE;
+	ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
+	f->mallocd = 0;
+	f->offset = AST_FRIENDLY_OFFSET;
+	f->src = pvt->t->name;
+	f->data.ptr = pvt->outbuf.c;
+
 	return ast_frisolate(f);
 }
 
@@ -463,12 +418,14 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a
 {
 	struct ast_trans_pvt *head = NULL, *tail = NULL;
 	int src_index, dst_index;
+	struct ast_format tmp_fmt1;
+	struct ast_format tmp_fmt2;
 
-	src_index = format2index(src);
-	dst_index = format2index(dst);
+	src_index = format2index(src->id);
+	dst_index = format2index(dst->id);
 
-	if (src_index < 0 || dst_index < 0) {
-		ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index < 0 ? "starting" : "ending");
+	if (src_index == -1 || dst_index == -1) {
+		ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index == -1 ? "starting" : "ending");
 		return NULL;
 	}
 
@@ -476,16 +433,26 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a
 
 	while (src_index != dst_index) {
 		struct ast_trans_pvt *cur;
+		struct ast_format *explicit_dst = NULL;
 		struct ast_translator *t = matrix_get(src_index, dst_index)->step;
 		if (!t) {
+			int src_id = index2format(src_index);
+			int dst_id = index2format(dst_index);
 			ast_log(LOG_WARNING, "No translator path from %s to %s\n",
-				ast_format_get_name(src), ast_format_get_name(dst));
+				ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
+				ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
 			AST_RWLIST_UNLOCK(&translators);
 			return NULL;
 		}
-		if (!(cur = newpvt(t))) {
+		if (dst_index == t->dst_fmt_index) {
+			explicit_dst = dst;
+		}
+		if (!(cur = newpvt(t, explicit_dst))) {
+			int src_id = index2format(src_index);
+			int dst_id = index2format(dst_index);
 			ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
-				ast_format_get_name(src), ast_format_get_name(dst));
+				ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
+				ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
 			if (head) {
 				ast_translator_free_path(head);
 			}
@@ -542,12 +509,16 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
 			path->nextout = f->delivery;
 		}
 		/* Predict next incoming sample */
-		path->nextin = ast_tvadd(path->nextin, ast_samp2tv(
-			 f->samples, ast_format_get_sample_rate(f->subclass.format)));
+		path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
 	}
 	delivery = f->delivery;
 	for (out = f; out && p ; p = p->next) {
-		framein(p, out);
+		struct ast_frame *current = out;
+
+		do {
+			framein(p, current);
+			current = AST_LIST_NEXT(current, frame_list);
+		} while (current);
 		if (out != f) {
 			ast_frfree(out);
 		}
@@ -556,22 +527,32 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
 	if (out) {
 		/* we have a frame, play with times */
 		if (!ast_tvzero(delivery)) {
-			/* Regenerate prediction after a discontinuity */
-			if (ast_tvzero(path->nextout)) {
-				path->nextout = ast_tvnow();
-			}
+			struct ast_frame *current = out;
 
-			/* Use next predicted outgoing timestamp */
-			out->delivery = path->nextout;
+			do {
+				/* Regenerate prediction after a discontinuity */
+				if (ast_tvzero(path->nextout)) {
+					path->nextout = ast_tvnow();
+				}
 
-			/* Predict next outgoing timestamp from samples in this
-			   frame. */
-			path->nextout = ast_tvadd(path->nextout, ast_samp2tv(
-				 out->samples, ast_format_get_sample_rate(out->subclass.format)));
-			if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) {
-				ast_debug(4, "Sample size different %d vs %d\n", f->samples, out->samples);
-				ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO);
-			}
+				/* Use next predicted outgoing timestamp */
+				current->delivery = path->nextout;
+
+				/* Invalidate prediction if we're entering a silence period */
+				if (out->frametype == AST_FRAME_CNG) {
+					path->nextout = ast_tv(0, 0);
+				/* Predict next outgoing timestamp from samples in this
+				   frame. */
+				} else {
+					path->nextout = ast_tvadd(path->nextout, ast_samp2tv(current->samples, ast_format_rate(&current->subclass.format)));
+				}
+
+				if (f->samples != current->samples && ast_test_flag(current, AST_FRFLAG_HAS_TIMING_INFO)) {
+					ast_debug(4, "Sample size different %d vs %d\n", f->samples, current->samples);
+					ast_clear_flag(current, AST_FRFLAG_HAS_TIMING_INFO);
+				}
+				current = AST_LIST_NEXT(current, frame_list);
+			} while (current);
 		} else {
 			out->delivery = ast_tv(0, 0);
 			ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
@@ -580,10 +561,10 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
 				out->len = len;
 				out->seqno = seqno;
 			}
-		}
-		/* Invalidate prediction if we're entering a silence period */
-		if (out->frametype == AST_FRAME_CNG) {
-			path->nextout = ast_tv(0, 0);
+			/* Invalidate prediction if we're entering a silence period */
+			if (out->frametype == AST_FRAME_CNG) {
+				path->nextout = ast_tv(0, 0);
+			}
 		}
 	}
 	if (consume) {
@@ -608,7 +589,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
 	struct rusage start;
 	struct rusage end;
 	int cost;
-	int out_rate = t->dst_codec.sample_rate;
+	int out_rate = ast_format_rate(&t->dst_format);
 
 	if (!seconds) {
 		seconds = 1;
@@ -621,7 +602,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
 		return;
 	}
 
-	pvt = newpvt(t);
+	pvt = newpvt(t, NULL);
 	if (!pvt) {
 		ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
 		t->comp_cost = 999999;
@@ -679,23 +660,21 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
  * \retval Table Cost value greater than 0.
  * \retval 0 on error.
  */
-static int generate_table_cost(struct ast_codec *src, struct ast_codec *dst)
+static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
 {
-	int src_rate = src->sample_rate;
+	int src_rate = ast_format_rate(src);
 	int src_ll = 0;
-	int dst_rate = dst->sample_rate;
+	int dst_rate = ast_format_rate(dst);
 	int dst_ll = 0;
 
-	if ((src->type != AST_MEDIA_TYPE_AUDIO) ||
-	    (dst->type != AST_MEDIA_TYPE_AUDIO)) {
+	if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
 		/* This method of generating table cost is limited to audio.
 		 * Translators for media other than audio must manually set their
 		 * table cost. */
 		return 0;
 	}
-
-	src_ll = !strcmp(src->name, "slin");
-	dst_ll = !strcmp(dst->name, "slin");
+	src_ll = ast_format_is_slinear(src);
+	dst_ll = ast_format_is_slinear(dst);
 	if (src_ll) {
 		if (dst_ll && (src_rate == dst_rate)) {
 			return AST_TRANS_COST_LL_LL_ORIGSAMP;
@@ -801,25 +780,18 @@ static void matrix_rebuild(int samples)
 					/* if no step already exists between x and z OR the new cost of using the intermediate
 					 * step is cheaper, use this step. */
 					if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
+						struct ast_format tmpx;
+						struct ast_format tmpy;
+						struct ast_format tmpz;
 						matrix_get(x, z)->step = matrix_get(x, y)->step;
 						matrix_get(x, z)->table_cost = newtablecost;
 						matrix_get(x, z)->multistep = 1;
 						changed++;
-
-						if (DEBUG_ATLEAST(10)) {
-							struct ast_codec *x_codec = index2codec(x);
-							struct ast_codec *y_codec = index2codec(y);
-							struct ast_codec *z_codec = index2codec(z);
-
-							ast_log(LOG_DEBUG,
-								"Discovered %u cost path from %s to %s, via %s\n",
-								matrix_get(x, z)->table_cost, x_codec->name,
-								y_codec->name, z_codec->name);
-
-							ao2_ref(x_codec, -1);
-							ao2_ref(y_codec, -1);
-							ao2_ref(z_codec, -1);
-						}
+						ast_debug(10, "Discovered %u cost path from %s to %s, via %s\n",
+							matrix_get(x, z)->table_cost,
+							ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
+							ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
+							ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
 					}
 				}
 			}
@@ -830,27 +802,20 @@ static void matrix_rebuild(int samples)
 	}
 }
 
-static void codec_append_name(const struct ast_codec *codec, struct ast_str **buf)
-{
-	if (codec) {
-		ast_str_append(buf, 0, "(%s@%u)", codec->name, codec->sample_rate);
-	} else {
-		ast_str_append(buf, 0, "(nothing)");
-	}
-}
-
 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
 {
+	struct ast_trans_pvt *pn = p;
+	char tmp[256];
+
 	if (!p || !p->t) {
 		return "";
 	}
 
-	ast_str_reset(*str);
-	codec_append_name(&p->t->src_codec, str);
-	while (p) {
-		ast_str_append(str, 0, "->");
-		codec_append_name(&p->t->dst_codec, str);
-		p = p->next;
+	ast_str_set(str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->src_format.id));
+
+	while ( (p = pn) ) {
+		pn = p->next;
+		ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id));
 	}
 
 	return ast_str_buffer(*str);
@@ -858,24 +823,24 @@ const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **
 
 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
 {
-	int i = 1, which = 0;
+	int which = 0;
 	int wordlen = strlen(word);
-	struct ast_codec *codec;
+	int i;
+	char *ret = NULL;
+	size_t len = 0;
+	const struct ast_format_list *format_list = ast_format_list_get(&len);
 
-	while ((codec = ast_codec_get_by_id(i))) {
-		++i;
-		if (codec->type != AST_MEDIA_TYPE_AUDIO) {
-			ao2_ref(codec, -1);
+	for (i = 0; i < len; i++) {
+		if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
 			continue;
 		}
-		if (!strncasecmp(word, codec->name, wordlen) && ++which > state) {
-			char *res = ast_strdup(codec->name);
-			ao2_ref(codec, -1);
-			return res;
+		if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
+			ret = ast_strdup(format_list[i].name);
+			break;
 		}
-		ao2_ref(codec, -1);
 	}
-	return NULL;
+	ast_format_list_destroy(format_list);
+	return ret;
 }
 
 static void handle_cli_recalc(struct ast_cli_args *a)
@@ -899,61 +864,63 @@ static void handle_cli_recalc(struct ast_cli_args *a)
 
 static char *handle_show_translation_table(struct ast_cli_args *a)
 {
-	int x, y, i, k;
-	int longest = 0, num_codecs = 0, curlen = 0;
+	int x;
+	int y;
+	int i;
+	int k;
+	int curlen = 0;
+	int longest = 0;
+	int f_len;
+	size_t f_size = 0;
+	const struct ast_format_list *f_list = ast_format_list_get(&f_size);
 	struct ast_str *out = ast_str_create(1024);
-	struct ast_codec *codec;
 
-	/* Get the length of the longest (usable?) codec name,
-	   so we know how wide the left side should be */
-	for (i = 1; (codec = ast_codec_get_by_id(i)); ao2_ref(codec, -1), ++i) {
-		++num_codecs;
-		if (codec->type != AST_MEDIA_TYPE_AUDIO) {
+	f_len = f_size;
+	AST_RWLIST_RDLOCK(&translators);
+	ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
+	ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
+
+	/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
+	for (i = 0; i < f_len; i++) {
+		/* translation only applies to audio right now. */
+		if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)
 			continue;
-		}
-		curlen = strlen(codec->name);
+		curlen = strlen(ast_getformatname(&f_list[i].format));
 		if (curlen > longest) {
 			longest = curlen;
 		}
 	}
 
-	AST_RWLIST_RDLOCK(&translators);
-	ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
-	ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
-
-	for (i = 0; i < num_codecs; i++) {
-		struct ast_codec *row = i ? ast_codec_get_by_id(i) : NULL;
-
+	for (i = -1; i < f_len; i++) {
 		x = -1;
-		if ((i > 0) && (row->type != AST_MEDIA_TYPE_AUDIO)) {
-			ao2_ref(row, -1);
+		if ((i >= 0) && ((x = format2index(f_list[i].format.id)) == -1)) {
 			continue;
 		}
-
-		if ((i > 0) && (x = codec2index(row)) == -1) {
-			ao2_ref(row, -1);
+		/* translation only applies to audio right now. */
+		if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) {
+			continue;
+		}
+		/*Go ahead and move to next iteration if dealing with an unknown codec*/
+		if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) {
 			continue;
 		}
-
 		ast_str_set(&out, 0, " ");
-		for (k = 0; k < num_codecs; k++) {
-			struct ast_codec *col = k ? ast_codec_get_by_id(k) : NULL;
-
+		for (k = -1; k < f_len; k++) {
 			y = -1;
-			if ((k > 0) && (col->type != AST_MEDIA_TYPE_AUDIO)) {
-				ao2_ref(col, -1);
+			if ((k >= 0) && ((y = format2index(f_list[k].format.id)) == -1)) {
 				continue;
 			}
-
-			if ((k > 0) && (y = codec2index(col)) == -1) {
-				ao2_ref(col, -1);
+			/* translation only applies to audio right now. */
+			if (k >= 0 && (AST_FORMAT_GET_TYPE(f_list[k].format.id) != AST_FORMAT_TYPE_AUDIO)) {
 				continue;
 			}
-
-			if (k > 0) {
-				curlen = strlen(col->name);
+			/*Go ahead and move to next iteration if dealing with an unknown codec*/
+			if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) {
+				continue;
+			}
+			if (k >= 0) {
+				curlen = strlen(ast_getformatname(&f_list[k].format));
 			}
-
 			if (curlen < 5) {
 				curlen = 5;
 			}
@@ -961,12 +928,12 @@ static char *handle_show_translation_table(struct ast_cli_args *a)
 			if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
 				/* Actual codec output */
 				ast_str_append(&out, 0, "%*u", curlen + 1, (matrix_get(x, y)->table_cost/100));
-			} else if (i == 0 && k > 0) {
+			} else if (i == -1 && k >= 0) {
 				/* Top row - use a dynamic size */
-				ast_str_append(&out, 0, "%*s", curlen + 1, col->name);
-			} else if (k == 0 && i > 0) {
+				ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format));
+			} else if (k == -1 && i >= 0) {
 				/* Left column - use a static size. */
-				ast_str_append(&out, 0, "%*s", longest, row->name);
+				ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format));
 			} else if (x >= 0 && y >= 0) {
 				/* Codec not supported */
 				ast_str_append(&out, 0, "%*s", curlen + 1, "-");
@@ -974,79 +941,74 @@ static char *handle_show_translation_table(struct ast_cli_args *a)
 				/* Upper left hand corner */
 				ast_str_append(&out, 0, "%*s", longest, "");
 			}
-			ao2_cleanup(col);
 		}
 		ast_str_append(&out, 0, "\n");
 		ast_cli(a->fd, "%s", ast_str_buffer(out));
-		ao2_cleanup(row);
 	}
 	ast_free(out);
 	AST_RWLIST_UNLOCK(&translators);
+	ast_format_list_destroy(f_list);
 	return CLI_SUCCESS;
 }
 
-static char *handle_show_translation_path(struct ast_cli_args *a, const char *codec_name, unsigned int sample_rate)
+static char *handle_show_translation_path(struct ast_cli_args *a)
 {
-	int i = 1;
+	struct ast_format input_src_format;
+	size_t len = 0;
+	int i;
+	const struct ast_format_list *format_list = ast_format_list_get(&len);
 	struct ast_str *str = ast_str_alloca(1024);
 	struct ast_translator *step;
-	struct ast_codec *dst_codec;
-	struct ast_codec *src_codec = ast_codec_get(codec_name, AST_MEDIA_TYPE_AUDIO, sample_rate);
+	char tmp[256];
 
-	if (!src_codec) {
-		ast_cli(a->fd, "Source codec \"%s\" is not found.\n", codec_name);
+	ast_format_clear(&input_src_format);
+	for (i = 0; i < len; i++) {
+		if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
+			continue;
+		}
+		if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
+			ast_format_copy(&input_src_format, &format_list[i].format);
+		}
+	}
+
+	if (!input_src_format.id) {
+		ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
+		ast_format_list_destroy(format_list);
 		return CLI_FAILURE;
 	}
 
 	AST_RWLIST_RDLOCK(&translators);
-	ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %u ---\n",
-		codec_name, src_codec->sample_rate);
-
-	while ((dst_codec = ast_codec_get_by_id(i))) {
-		int src, dst;
-		char src_buffer[64];
-		char dst_buffer[64];
-
-		++i;
-		if (src_codec == dst_codec ||
-		    dst_codec->type != AST_MEDIA_TYPE_AUDIO) {
-			ao2_ref(dst_codec, -1);
+	ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
+	for (i = 0; i < len; i++) {
+		int src;
+		int dst;
+		if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) {
 			continue;
 		}
-
-		dst = codec2index(dst_codec);
-		src = codec2index(src_codec);
-
-		if (src < 0 || dst < 0) {
-			ast_str_set(&str, 0, "No Translation Path");
-		} else {
-			step = matrix_get(src, dst)->step;
-
-			if (step) {
-				codec_append_name(&step->src_codec, &str);
-				while (src != dst) {
-					src = step->dst_fmt_index;
-					step = matrix_get(src, dst)->step;
-					if (!step) {
-						ast_str_append(&str, 0, "->");
-						codec_append_name(dst_codec, &str);
-						break;
-					}
-					ast_str_append(&str, 0, "->");
-					codec_append_name(&step->src_codec, &str);
+		dst = format2index(format_list[i].format.id);
+		src = format2index(input_src_format.id);
+		ast_str_reset(str);
+		if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
+			ast_str_append(&str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), matrix_get(src, dst)->step->src_format.id));
+			while (src != dst) {
+				step = matrix_get(src, dst)->step;
+				if (!step) {
+					ast_str_reset(str);
+					break;
 				}
+				ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id));
+				src = step->dst_fmt_index;
 			}
 		}
 
-		snprintf(src_buffer, sizeof(src_buffer), "%s:%u", src_codec->name, src_codec->sample_rate);
-		snprintf(dst_buffer, sizeof(dst_buffer), "%s:%u", dst_codec->name, dst_codec->sample_rate);
-		ast_cli(a->fd, "\t%-16.16s To %-16.16s: %-60.60s\n",
-			src_buffer, dst_buffer, ast_str_buffer(str));
-		ast_str_reset(str);
-		ao2_ref(dst_codec, -1);
+		if (ast_strlen_zero(ast_str_buffer(str))) {
+			ast_str_set(&str, 0, "No Translation Path");
+		}
+		ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
 	}
 	AST_RWLIST_UNLOCK(&translators);
-	ao2_ref(src_codec, -1);
+
+	ast_format_list_destroy(format_list);
 	return CLI_SUCCESS;
 }
 
@@ -1064,10 +1026,8 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
 			"          with each conversion.  If the argument 'recalc' is supplied along\n"
 			"          with optional number of seconds to test a new test will be performed\n"
 			"          as the chart is being displayed.\n"
-			"       2. 'core show translation paths [codec [sample_rate]]'\n"
-			"           This will display all the translation paths associated with a codec.\n"
-			"           If a codec has multiple sample rates, the sample rate must be\n"
-			"           provided as well.\n";
+			"       2. 'core show translation paths [codec]'\n"
+			"           This will display all the translation paths associated with a codec\n";
 		return NULL;
 	case CLI_GENERATE:
 		if (a->pos == 3) {
@@ -1076,22 +1036,14 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
 		if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
 			return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
 		}
-		/* BUGBUG - add tab completion for sample rates */
 		return NULL;
 	}
 
-	if (a->argc > 6)
+	if (a->argc > 5)
 		return CLI_SHOWUSAGE;
 
 	if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */
-		return handle_show_translation_path(a, a->argv[4], 0);
-	} else if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 6) {
-		unsigned int sample_rate;
-		if (sscanf(a->argv[5], "%30u", &sample_rate) != 1) {
-			ast_cli(a->fd, "Invalid sample rate: %s.\n", a->argv[5]);
-			return CLI_FAILURE;
-		}
-		return handle_show_translation_path(a, a->argv[4], sample_rate);
+		return handle_show_translation_path(a);
 	} else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */
 		handle_cli_recalc(a);
 	} else if (a->argc > 3) { /* wrong input */
@@ -1110,29 +1062,14 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
 {
 	struct ast_translator *u;
 	char tmp[80];
-	RAII_VAR(struct ast_codec *, src_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, dst_codec, NULL, ao2_cleanup);
-
-	src_codec = ast_codec_get(t->src_codec.name, t->src_codec.type, t->src_codec.sample_rate);
-	if (!src_codec) {
-		ast_assert(0);
-		ast_log(LOG_WARNING, "Failed to register translator: unknown source codec %s\n", t->src_codec.name);
-		return -1;
-	}
-
-	dst_codec = ast_codec_get(t->dst_codec.name, t->dst_codec.type, t->dst_codec.sample_rate);
-	if (!dst_codec) {
-		ast_log(LOG_WARNING, "Failed to register translator: unknown destination codec %s\n", t->dst_codec.name);
-		return -1;
-	}
 
-	if (add_codec2index(src_codec) || add_codec2index(dst_codec)) {
+	if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
 		if (matrix_resize(0)) {
 			ast_log(LOG_WARNING, "Translator matrix can not represent any more translators.  Out of resources.\n");
 			return -1;
 		}
-		add_codec2index(src_codec);
-		add_codec2index(dst_codec);
+		add_format2index(t->src_format.id);
+		add_format2index(t->dst_format.id);
 	}
 
 	if (!mod) {
@@ -1144,28 +1081,28 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
 		ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
 		return -1;
 	}
-	if (!t->table_cost && !(t->table_cost = generate_table_cost(src_codec, dst_codec))) {
+	if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
 		ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
 			"Please set table_cost variable on translator.\n", t->name);
 		return -1;
 	}
 
 	t->module = mod;
-	t->src_fmt_index = codec2index(src_codec);
-	t->dst_fmt_index = codec2index(dst_codec);
+	t->src_fmt_index = format2index(t->src_format.id);
+	t->dst_fmt_index = format2index(t->dst_format.id);
 	t->active = 1;
 
-	if (t->src_fmt_index < 0 || t->dst_fmt_index < 0) {
-		ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index < 0 ? "starting" : "ending");
+	if (t->src_fmt_index == -1 || t->dst_fmt_index == -1) {
+		ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index == -1 ? "starting" : "ending");
 		return -1;
 	}
 	if (t->src_fmt_index >= cur_max_index) {
-		ast_log(LOG_WARNING, "Source codec %s is larger than cur_max_index\n", t->src_codec.name);
+		ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
 		return -1;
 	}
 
 	if (t->dst_fmt_index >= cur_max_index) {
-		ast_log(LOG_WARNING, "Destination codec %s is larger than cur_max_index\n", t->dst_codec.name);
+		ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
 		return -1;
 	}
 
@@ -1186,9 +1123,9 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
 
 	generate_computational_cost(t, 1);
 
-	ast_verb(2, "Registered translator '%s' from codec %s to %s, table cost, %d, computational cost %d\n",
-		 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
-		 t->src_codec.name, t->dst_codec.name, t->table_cost, t->comp_cost);
+	ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
+			    term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
+			    ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
 
 	AST_RWLIST_WRLOCK(&translators);
 
@@ -1205,7 +1142,7 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END;
 
-	/* if no existing translator was found for this codec combination,
+	/* if no existing translator was found for this format combination,
 	   add it to the beginning of the list */
 	if (t) {
 		AST_RWLIST_INSERT_HEAD(&translators, t, list);
@@ -1229,9 +1166,10 @@ int ast_unregister_translator(struct ast_translator *t)
 	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
 		if (u == t) {
 			AST_RWLIST_REMOVE_CURRENT(list);
-			ast_verb(2, "Unregistered translator '%s' from codec %s to %s\n",
+			ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
 				term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
-				t->src_codec.name, t->dst_codec.name);
+				ast_getformatname(&t->src_format),
+				ast_getformatname(&t->dst_format));
 			found = 1;
 			break;
 		}
@@ -1266,113 +1204,104 @@ void ast_translator_deactivate(struct ast_translator *t)
 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
 int ast_translator_best_choice(struct ast_format_cap *dst_cap,
 	struct ast_format_cap *src_cap,
-	struct ast_format **dst_fmt_out,
-	struct ast_format **src_fmt_out)
+	struct ast_format *dst_fmt_out,
+	struct ast_format *src_fmt_out)
 {
 	unsigned int besttablecost = INT_MAX;
 	unsigned int beststeps = INT_MAX;
-	RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, bestdst, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, joint_cap, NULL, ao2_cleanup);
-	int i;
-	int j;
+	struct ast_format cur_dst;
+	struct ast_format cur_src;
+	struct ast_format best;
+	struct ast_format bestdst;
+	struct ast_format_cap *joint_cap;
 
-	if (ast_format_cap_empty(dst_cap) || ast_format_cap_empty(src_cap)) {
-		ast_log(LOG_ERROR, "Cannot determine best translation path since one capability supports no formats\n");
-		return -1;
-	}
-
-	if (!(joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		return -1;
-	}
-	ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap);
+	ast_format_clear(&best);
 
-	for (i = 0; i < ast_format_cap_count(joint_cap); ++i) {
-		struct ast_format *fmt =
-			ast_format_cap_get_format(joint_cap, i);
+	joint_cap = ast_format_cap_joint(dst_cap, src_cap);
+	if (joint_cap) { /* yes, pick one and return */
+		struct ast_format tmp_fmt;
 
-		if (!fmt) {
-			continue;
-		}
+		ast_format_cap_iter_start(joint_cap);
+		while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
+				continue;
+			}
 
-		if (!best) {
-			/* No ao2_ref operations needed, we're done with fmt */
-			best = fmt;
-			continue;
+			if (!best.id
+				|| ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
+				ast_format_copy(&best, &tmp_fmt);
+			}
 		}
-
-		if (ast_format_get_sample_rate(best) <
-		    ast_format_get_sample_rate(fmt)) {
-			ao2_replace(best, fmt);
+		ast_format_cap_iter_end(joint_cap);
+		ast_format_cap_destroy(joint_cap);
+
+		if (best.id) {
+			/* We are done, this is a common format to both. */
+			ast_format_copy(dst_fmt_out, &best);
+			ast_format_copy(src_fmt_out, &best);
+			return 0;
 		}
-		ao2_ref(fmt, -1);
-	}
-
-	if (best) {
-		ao2_replace(*dst_fmt_out, best);
-		ao2_replace(*src_fmt_out, best);
-		return 0;
 	}
-	/* need to translate */
-	AST_RWLIST_RDLOCK(&translators);
 
-	for (i = 0; i < ast_format_cap_count(dst_cap); ++i) {
-		struct ast_format *dst =
-			ast_format_cap_get_format(dst_cap, i);
+	/* No, we will need to translate */
+	ast_format_clear(&bestdst);
 
-		if (!dst) {
+	AST_RWLIST_RDLOCK(&translators);
+	ast_format_cap_iter_start(dst_cap);
+	while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
+		if (AST_FORMAT_GET_TYPE(cur_dst.id) != AST_FORMAT_TYPE_AUDIO) {
 			continue;
 		}
 
-		for (j = 0; j < ast_format_cap_count(src_cap); ++j) {
-			struct ast_format *src =
-				ast_format_cap_get_format(src_cap, j);
-			int x, y;
+		ast_format_cap_iter_start(src_cap);
+		while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
+			int x;
+			int y;
 
-			if (!src) {
+			if (AST_FORMAT_GET_TYPE(cur_src.id) != AST_FORMAT_TYPE_AUDIO) {
 				continue;
 			}
 
-			x = format2index(src);
-			y = format2index(dst);
+			x = format2index(cur_src.id);
+			y = format2index(cur_dst.id);
 			if (x < 0 || y < 0) {
-				ao2_ref(src, -1);
 				continue;
 			}
 			if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
-				ao2_ref(src, -1);
 				continue;
 			}
-			if (((matrix_get(x, y)->table_cost < besttablecost) ||
-			     (matrix_get(x, y)->multistep < beststeps))) {
+			if (matrix_get(x, y)->table_cost < besttablecost
+				|| matrix_get(x, y)->multistep < beststeps) {
 				/* better than what we have so far */
-				ao2_replace(best, src);
-				ao2_replace(bestdst, dst);
+				ast_format_copy(&best, &cur_src);
+				ast_format_copy(&bestdst, &cur_dst);
 				besttablecost = matrix_get(x, y)->table_cost;
 				beststeps = matrix_get(x, y)->multistep;
 			}
-			ao2_ref(src, -1);
 		}
-		ao2_ref(dst, -1);
+		ast_format_cap_iter_end(src_cap);
 	}
+	ast_format_cap_iter_end(dst_cap);
 	AST_RWLIST_UNLOCK(&translators);
-	if (!best) {
+
+	if (!best.id) {
 		return -1;
 	}
-	ao2_replace(*dst_fmt_out, bestdst);
-	ao2_replace(*src_fmt_out, best);
+	ast_format_copy(dst_fmt_out, &bestdst);
+	ast_format_copy(src_fmt_out, &best);
 	return 0;
 }
 
 unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
 {
 	unsigned int res = -1;
+	int src, dest;
 	/* convert bitwise format numbers into array indices */
-	int src = format2index(src_format);
-	int dest = format2index(dst_format);
+	src = format2index(src_format->id);
+	dest = format2index(dst_format->id);
 
-	if (src < 0 || dest < 0) {
-		ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src < 0 ? "starting" : "ending");
+	if (src == -1 || dest == -1) {
+		ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
 		return -1;
 	}
 	AST_RWLIST_RDLOCK(&translators);
@@ -1386,72 +1315,25 @@ unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_
 	return res;
 }
 
-static void check_translation_path(
-	struct ast_format_cap *dest, struct ast_format_cap *src,
-	struct ast_format_cap *result, struct ast_format *src_fmt,
-	enum ast_media_type type)
-{
-	int index, src_index = format2index(src_fmt);
-	/* For a given source format, traverse the list of
-	   known formats to determine whether there exists
-	   a translation path from the source format to the
-	   destination format. */
-	for (index = 0; (src_index >= 0) && index < cur_max_index; index++) {
-		struct ast_codec *codec = index2codec(index);
-		RAII_VAR(struct ast_format *, fmt, ast_format_create(codec), ao2_cleanup);
-
-		ao2_ref(codec, -1);
-
-		if (ast_format_get_type(fmt) != type) {
-			continue;
-		}
-
-		/* if this is not a desired format, nothing to do */
-		if (ast_format_cap_iscompatible_format(dest, fmt) == AST_FORMAT_CMP_NOT_EQUAL) {
-			continue;
-		}
-
-		/* if the source is supplying this format, then
-		   we can leave it in the result */
-		if (ast_format_cap_iscompatible_format(src, fmt) == AST_FORMAT_CMP_EQUAL) {
-			continue;
-		}
-
-		/* if we don't have a translation path from the src
-		   to this format, remove it from the result */
-		if (!matrix_get(src_index, index)->step) {
-			ast_format_cap_remove(result, fmt);
-			continue;
-		}
-
-		/* now check the opposite direction */
-		if (!matrix_get(index, src_index)->step) {
-			ast_format_cap_remove(result, fmt);
-		}
-	}
-
-}
-
 void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
 {
-	struct ast_format *cur_dest, *cur_src;
+	struct ast_format tmp_fmt;
+	struct ast_format cur_dest, cur_src;
+	int src_audio = 0;
+	int src_video = 0;
 	int index;
 
-	for (index = 0; index < ast_format_cap_count(dest); ++index) {
-		if (!(cur_dest = ast_format_cap_get_format(dest, index))) {
-			continue;
-		}
-
+	ast_format_cap_iter_start(dest);
+	while (!ast_format_cap_iter_next(dest, &cur_dest)) {
 		/* We give preference to a joint format structure if possible */
-		if ((cur_src = ast_format_cap_get_compatible_format(src, cur_dest))) {
-			ast_format_cap_append(result, cur_src, 0);
-			ao2_ref(cur_src, -1);
+		if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) {
+			ast_format_cap_add(result, &tmp_fmt);
 		} else {
 			/* Otherwise we just use the destination format */
-			ast_format_cap_append(result, cur_dest, 0);
+			ast_format_cap_add(result, &cur_dest);
 		}
-		ao2_ref(cur_dest, -1);
 	}
+	ast_format_cap_iter_end(dest);
 
 	/* if we don't have a source format, we just have to try all
 	   possible destination formats */
@@ -1459,19 +1341,91 @@ void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_for
 		return;
 	}
 
-	for (index = 0; index < ast_format_cap_count(src); ++index) {
-		if (!(cur_src = ast_format_cap_get_format(src, index))) {
-			continue;
+	ast_format_cap_iter_start(src);
+	while (!ast_format_cap_iter_next(src, &cur_src)) {
+		/* If we have a source audio format, get its format index */
+		if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
+			src_audio = format2index(cur_src.id);
+		}
+
+		/* If we have a source video format, get its format index */
+		if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
+			src_video = format2index(cur_src.id);
 		}
 
 		AST_RWLIST_RDLOCK(&translators);
-		check_translation_path(dest, src, result,
-				       cur_src, AST_MEDIA_TYPE_AUDIO);
-		check_translation_path(dest, src, result,
-				       cur_src, AST_MEDIA_TYPE_VIDEO);
+
+		/* For a given source audio format, traverse the list of
+		   known audio formats to determine whether there exists
+		   a translation path from the source format to the
+		   destination format. */
+		for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
+			ast_format_set(&tmp_fmt, index2format(index), 0);
+
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
+				continue;
+			}
+
+			/* if this is not a desired format, nothing to do */
+			if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
+				continue;
+			}
+
+			/* if the source is supplying this format, then
+			   we can leave it in the result */
+			if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
+				continue;
+			}
+
+			/* if we don't have a translation path from the src
+			   to this format, remove it from the result */
+			if (!matrix_get(src_audio, index)->step) {
+				ast_format_cap_remove_byid(result, tmp_fmt.id);
+				continue;
+			}
+
+			/* now check the opposite direction */
+			if (!matrix_get(index, src_audio)->step) {
+				ast_format_cap_remove_byid(result, tmp_fmt.id);
+			}
+		}
+
+		/* For a given source video format, traverse the list of
+		   known video formats to determine whether there exists
+		   a translation path from the source format to the
+		   destination format. */
+		for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
+			ast_format_set(&tmp_fmt, index2format(index), 0);
+			if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
+				continue;
+			}
+
+			/* if this is not a desired format, nothing to do */
+			if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
+				continue;
+			}
+
+			/* if the source is supplying this format, then
+			   we can leave it in the result */
+			if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
+				continue;
+			}
+
+			/* if we don't have a translation path from the src
+			   to this format, remove it from the result */
+			if (!matrix_get(src_video, index)->step) {
+				ast_format_cap_remove_byid(result, tmp_fmt.id);
+				continue;
+			}
+
+			/* now check the opposite direction */
+			if (!matrix_get(index, src_video)->step) {
+				ast_format_cap_remove_byid(result, tmp_fmt.id);
+			}
+		}
 		AST_RWLIST_UNLOCK(&translators);
-		ao2_ref(cur_src, -1);
 	}
+	ast_format_cap_iter_end(src);
 }
 
 static void translate_shutdown(void)
@@ -1495,6 +1449,6 @@ int ast_translate_init(void)
 	ast_rwlock_init(&tablelock);
 	res = matrix_resize(1);
 	res |= ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
-	ast_register_atexit(translate_shutdown);
+	ast_register_cleanup(translate_shutdown);
 	return res;
 }
diff --git a/main/udptl.c b/main/udptl.c
index c42e69b..76fc2fb 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * UDPTL support for T.38
  *
@@ -48,22 +48,13 @@
  * - app_fax.c
  */
 
-/*! \li \ref udptl.c uses the configuration file \ref udptl.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page udptl.conf udptl.conf
- * \verbinclude udptl.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417327 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -80,40 +71,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417327 $")
 #include "asterisk/cli.h"
 #include "asterisk/unaligned.h"
 
-/*** DOCUMENTATION
-	<configInfo name="udptl" language="en_US">
-		<configFile name="udptl.conf">
-			<configObject name="global">
-				<synopsis>Global options for configuring UDPTL</synopsis>
-				<configOption name="udptlstart">
-					<synopsis>The start of the UDPTL port range</synopsis>
-				</configOption>
-				<configOption name="udptlend">
-					<synopsis>The end of the UDPTL port range</synopsis>
-				</configOption>
-				<configOption name="udptlchecksums">
-					<synopsis>Whether to enable or disable UDP checksums on UDPTL traffic</synopsis>
-				</configOption>
-				<configOption name="udptlfecentries">
-					<synopsis>The number of error correction entries in a UDPTL packet</synopsis>
-				</configOption>
-				<configOption name="udptlfecspan">
-					<synopsis>The span over which parity is calculated for FEC in a UDPTL packet</synopsis>
-				</configOption>
-				<configOption name="use_even_ports">
-					<synopsis>Whether to only use even-numbered UDPTL ports</synopsis>
-				</configOption>
-				<configOption name="t38faxudpec">
-					<synopsis>Removed</synopsis>
-				</configOption>
-				<configOption name="t38faxmaxdatagram">
-					<synopsis>Removed</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
 #define UDPTL_MTU		1200
 
 #if !defined(FALSE)
@@ -218,6 +175,8 @@ struct ast_udptl {
 	udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
 };
 
+static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
+
 struct udptl_global_options {
 	unsigned int start; /*< The UDPTL start port */
 	unsigned int end;   /*< The UDPTL end port */
@@ -238,7 +197,6 @@ static int udptl_pre_apply_config(void);
 
 static struct aco_type general_option = {
 	.type = ACO_GLOBAL,
-	.name = "global",
 	.category_match = ACO_WHITELIST,
 	.item_offset = offsetof(struct udptl_config, general),
 	.category = "^general$",
@@ -251,7 +209,7 @@ static struct aco_file udptl_conf = {
 	.types = ACO_TYPES(&general_option),
 };
 
-CONFIG_INFO_CORE("udptl", cfg_info, globals, udptl_snapshot_alloc,
+CONFIG_INFO_STANDARD(cfg_info, globals, udptl_snapshot_alloc,
 	.files = ACO_FILES(&udptl_conf),
 	.pre_apply_config = udptl_pre_apply_config,
 );
@@ -362,8 +320,7 @@ static int encode_open_type(const struct ast_udptl *udptl, uint8_t *buf, unsigne
 	}
 	/* Encode the open type */
 	for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) {
-		if ((enclen = encode_length(buf, len, num_octets)) < 0)
-			return -1;
+		enclen = encode_length(buf, len, num_octets);
 		if (enclen + *len > buflen) {
 			ast_log(LOG_ERROR, "UDPTL (%s): Buffer overflow detected (%u + %u > %u)\n",
 				LOG_TAG(udptl), enclen, *len, buflen);
@@ -520,7 +477,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
 #if 0
 			fprintf(stderr, "FEC: ");
 			for (j = 0; j < s->rx[x].fec_len[i]; j++)
-				fprintf(stderr, "%02X ", data[j]);
+				fprintf(stderr, "%02hhX ", data[j]);
 			fprintf(stderr, "\n");
 #endif
 		}
@@ -646,8 +603,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int bu
 		buf[len++] = 0x00;
 		/* The number of entries will always be zero, so it is pointless allowing
 		   for the fragmented case here. */
-		if (encode_length(buf, &len, 0) < 0)
-			return -1;
+		encode_length(buf, &len, 0);
 		break;
 	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
 		/* Encode the error recovery type */
@@ -658,8 +614,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int bu
 			entries = s->tx_seq_no;
 		/* The number of entries will always be small, so it is pointless allowing
 		   for the fragmented case here. */
-		if (encode_length(buf, &len, entries) < 0)
-			return -1;
+		encode_length(buf, &len, entries);
 		/* Encode the elements */
 		for (i = 0; i < entries; i++) {
 			j = (entry - i - 1) & UDPTL_BUF_MASK;
@@ -1190,6 +1145,169 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
 	return 0;
 }
 
+void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto)
+{
+	AST_RWLIST_WRLOCK(&protos);
+	AST_RWLIST_REMOVE(&protos, proto, list);
+	AST_RWLIST_UNLOCK(&protos);
+}
+
+int ast_udptl_proto_register(struct ast_udptl_protocol *proto)
+{
+	struct ast_udptl_protocol *cur;
+
+	AST_RWLIST_WRLOCK(&protos);
+	AST_RWLIST_TRAVERSE(&protos, cur, list) {
+		if (cur->type == proto->type) {
+			ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
+			AST_RWLIST_UNLOCK(&protos);
+			return -1;
+		}
+	}
+	AST_RWLIST_INSERT_TAIL(&protos, proto, list);
+	AST_RWLIST_UNLOCK(&protos);
+	return 0;
+}
+
+static struct ast_udptl_protocol *get_proto(struct ast_channel *chan)
+{
+	struct ast_udptl_protocol *cur = NULL;
+
+	AST_RWLIST_RDLOCK(&protos);
+	AST_RWLIST_TRAVERSE(&protos, cur, list) {
+		if (cur->type == ast_channel_tech(chan)->type)
+			break;
+	}
+	AST_RWLIST_UNLOCK(&protos);
+
+	return cur;
+}
+
+int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
+{
+	struct ast_frame *f;
+	struct ast_channel *who;
+	struct ast_channel *cs[3];
+	struct ast_udptl *p0;
+	struct ast_udptl *p1;
+	struct ast_udptl_protocol *pr0;
+	struct ast_udptl_protocol *pr1;
+	struct ast_sockaddr ac0;
+	struct ast_sockaddr ac1;
+	struct ast_sockaddr t0;
+	struct ast_sockaddr t1;
+	void *pvt0;
+	void *pvt1;
+	int to;
+
+	ast_channel_lock(c0);
+	while (ast_channel_trylock(c1)) {
+		ast_channel_unlock(c0);
+		usleep(1);
+		ast_channel_lock(c0);
+	}
+	pr0 = get_proto(c0);
+	pr1 = get_proto(c1);
+	if (!pr0) {
+		ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", ast_channel_name(c0));
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return -1;
+	}
+	if (!pr1) {
+		ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", ast_channel_name(c1));
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return -1;
+	}
+	pvt0 = ast_channel_tech_pvt(c0);
+	pvt1 = ast_channel_tech_pvt(c1);
+	p0 = pr0->get_udptl_info(c0);
+	p1 = pr1->get_udptl_info(c1);
+	if (!p0 || !p1) {
+		/* Somebody doesn't want to play... */
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return -2;
+	}
+	if (pr0->set_udptl_peer(c0, p1)) {
+		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c0), ast_channel_name(c1));
+		memset(&ac1, 0, sizeof(ac1));
+	} else {
+		/* Store UDPTL peer */
+		ast_udptl_get_peer(p1, &ac1);
+	}
+	if (pr1->set_udptl_peer(c1, p0)) {
+		ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", ast_channel_name(c1), ast_channel_name(c0));
+		memset(&ac0, 0, sizeof(ac0));
+	} else {
+		/* Store UDPTL peer */
+		ast_udptl_get_peer(p0, &ac0);
+	}
+	ast_channel_unlock(c0);
+	ast_channel_unlock(c1);
+	cs[0] = c0;
+	cs[1] = c1;
+	cs[2] = NULL;
+	for (;;) {
+		if ((ast_channel_tech_pvt(c0) != pvt0) ||
+			(ast_channel_tech_pvt(c1) != pvt1) ||
+			(ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1))) {
+				ast_debug(1, "Oooh, something is weird, backing out\n");
+				/* Tell it to try again later */
+				return -3;
+		}
+		to = -1;
+		ast_udptl_get_peer(p1, &t1);
+		ast_udptl_get_peer(p0, &t0);
+		if (ast_sockaddr_cmp(&t1, &ac1)) {
+			ast_debug(1, "Oooh, '%s' changed end address to %s\n",
+				ast_channel_name(c1), ast_sockaddr_stringify(&t1));
+			ast_debug(1, "Oooh, '%s' was %s\n",
+				ast_channel_name(c1), ast_sockaddr_stringify(&ac1));
+			ast_sockaddr_copy(&ac1, &t1);
+		}
+		if (ast_sockaddr_cmp(&t0, &ac0)) {
+			ast_debug(1, "Oooh, '%s' changed end address to %s\n",
+				ast_channel_name(c0), ast_sockaddr_stringify(&t0));
+			ast_debug(1, "Oooh, '%s' was %s\n",
+				ast_channel_name(c0), ast_sockaddr_stringify(&ac0));
+			ast_sockaddr_copy(&ac0, &t0);
+		}
+		who = ast_waitfor_n(cs, 2, &to);
+		if (!who) {
+			ast_debug(1, "Ooh, empty read...\n");
+			/* check for hangup / whentohangup */
+			if (ast_check_hangup(c0) || ast_check_hangup(c1))
+				break;
+			continue;
+		}
+		f = ast_read(who);
+		if (!f) {
+			*fo = f;
+			*rc = who;
+			ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup");
+			/* That's all we needed */
+			return 0;
+		} else {
+			if (f->frametype == AST_FRAME_MODEM) {
+				/* Forward T.38 frames if they happen upon us */
+				if (who == c0) {
+					ast_write(c1, f);
+				} else if (who == c1) {
+					ast_write(c0, f);
+				}
+			}
+			ast_frfree(f);
+		}
+		/* Swap priority. Not that it's a big deal at this point */
+		cs[2] = cs[0];
+		cs[0] = cs[1];
+		cs[1] = cs[2];
+	}
+	return -1;
+}
+
 static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	switch (cmd) {
@@ -1403,5 +1521,5 @@ void ast_udptl_init(void)
 
 	ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
 
-	ast_register_atexit(udptl_shutdown);
+	ast_register_cleanup(udptl_shutdown);
 }
diff --git a/main/ulaw.c b/main/ulaw.c
index abab853..76e4b04 100644
--- a/main/ulaw.c
+++ b/main/ulaw.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/ulaw.h"
 #include "asterisk/logger.h"
diff --git a/main/uri.c b/main/uri.c
deleted file mode 100644
index 0749369..0000000
--- a/main/uri.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include "asterisk/astobj2.h"
-#include "asterisk/strings.h"
-#include "asterisk/uri.h"
-
-#ifdef HAVE_URIPARSER
-#include <uriparser/Uri.h>
-#endif
-
-/*! \brief Stores parsed uri information */
-struct ast_uri {
-	/*! scheme (e.g. http, https, ws, wss, etc...) */
-	char *scheme;
-	/*! username:password */
-	char *user_info;
-	/*! host name or address */
-	char *host;
-	/*! associated port */
-	char *port;
-	/*! path info following host[:port] */
-	char *path;
-	/*! query information */
-	char *query;
-	/*! storage for uri string */
-	char uri[0];
-};
-
-/*!
- * \brief Construct a uri object with the given values.
- *
- * \note The size parameters [should] include room for the string terminator
- *       (strlen(<param>) + 1). For instance, if a scheme of 'http' is given
- *       then the 'scheme_size' should be equal to 5.
- */
-static struct ast_uri *ast_uri_create_(
-	const char *scheme, unsigned int scheme_size,
-	const char *user_info, unsigned int user_info_size,
-	const char *host, unsigned int host_size,
-	const char *port, unsigned int port_size,
-	const char *path, unsigned int path_size,
-	const char *query, unsigned int query_size)
-{
-#define SET_VALUE(param, field, size) \
-	do { if (param) { \
-	     ast_copy_string(p, param, size); \
-	     field = p; \
-	     p += size;	} } while (0)
-
-	char *p;
-	struct ast_uri *res = ao2_alloc(
-		sizeof(*res) + scheme_size + user_info_size + host_size +
-		port_size + path_size + query_size, NULL);
-
-	if (!res) {
-		ast_log(LOG_ERROR, "Unable to create URI object\n");
-		return NULL;
-	}
-
-	p = res->uri;
-	SET_VALUE(scheme, res->scheme, scheme_size);
-	SET_VALUE(user_info, res->user_info, user_info_size);
-	SET_VALUE(host, res->host, host_size);
-	SET_VALUE(port, res->port, port_size);
-	SET_VALUE(path, res->path, path_size);
-	SET_VALUE(query, res->query, query_size);
-	return res;
-}
-
-struct ast_uri *ast_uri_create(const char *scheme, const char *user_info,
-			       const char *host, const char *port,
-			       const char *path, const char *query)
-{
-	return ast_uri_create_(
-		scheme, scheme ? strlen(scheme) + 1 : 0,
-		user_info, user_info ? strlen(user_info) + 1 : 0,
-		host, host ? strlen(host) + 1 : 0,
-		port, port ? strlen(port) + 1 : 0,
-		path, path ? strlen(path) + 1 : 0,
-		query, query ? strlen(query) + 1 : 0);
-}
-
-struct ast_uri *ast_uri_copy_replace(const struct ast_uri *uri, const char *scheme,
-				     const char *user_info, const char *host,
-				     const char *port, const char *path,
-				     const char *query)
-{
-	return ast_uri_create(
-		scheme ? scheme : uri->scheme,
-		user_info ? user_info : uri->user_info,
-		host ? host : uri->host,
-		port ? port : uri->port,
-		path ? path : uri->path,
-		query ? query : uri->query);
-}
-
-const char *ast_uri_scheme(const struct ast_uri *uri)
-{
-	return uri->scheme;
-}
-
-const char *ast_uri_user_info(const struct ast_uri *uri)
-{
-	return uri->user_info;
-}
-
-const char *ast_uri_host(const struct ast_uri *uri)
-{
-	return uri->host;
-}
-
-const char *ast_uri_port(const struct ast_uri *uri)
-{
-	return uri->port;
-}
-
-const char *ast_uri_path(const struct ast_uri *uri)
-{
-	return uri->path;
-}
-
-const char *ast_uri_query(const struct ast_uri *uri)
-{
-	return uri->query;
-}
-
-int ast_uri_is_secure(const struct ast_uri *uri)
-{
-	return ast_strlen_zero(uri->scheme) ? 0 :
-		*(uri->scheme + strlen(uri->scheme) - 1) == 's';
-}
-
-#ifdef HAVE_URIPARSER
-struct ast_uri *ast_uri_parse(const char *uri)
-{
-	UriParserStateA state;
-	UriUriA uria;
-	struct ast_uri *res;
-	unsigned int scheme_size, user_info_size, host_size;
-	unsigned int port_size, path_size, query_size;
-	const char *path_start, *path_end;
-
-	state.uri = &uria;
-	if (uriParseUriA(&state, uri) != URI_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to parse URI %s\n", uri);
-		uriFreeUriMembersA(&uria);
-		return NULL;
-	}
-
-	scheme_size = uria.scheme.first ?
-		uria.scheme.afterLast - uria.scheme.first + 1 : 0;
-	user_info_size = uria.userInfo.first ?
-		uria.userInfo.afterLast - uria.userInfo.first + 1 : 0;
-	host_size = uria.hostText.first ?
-		uria.hostText.afterLast - uria.hostText.first + 1 : 0;
-	port_size = uria.portText.first ?
-		uria.portText.afterLast - uria.portText.first + 1 : 0;
-
-	path_start = uria.pathHead && uria.pathHead->text.first ?
-		uria.pathHead->text.first : NULL;
-	path_end = path_start ? uria.pathTail->text.afterLast : NULL;
-	path_size = path_end ? path_end - path_start + 1 : 0;
-
-	query_size = uria.query.first ?
-		uria.query.afterLast - uria.query.first + 1 : 0;
-
-	res = ast_uri_create_(uria.scheme.first, scheme_size,
-			      uria.userInfo.first, user_info_size,
-			      uria.hostText.first, host_size,
-			      uria.portText.first, port_size,
-			      path_start, path_size,
-			      uria.query.first, query_size);
-	uriFreeUriMembersA(&uria);
-	return res;
-}
-#else
-struct ast_uri *ast_uri_parse(const char *uri)
-{
-#define SET_VALUES(value) \
-	value = uri; \
-	size_##value = p - uri + 1; \
-	uri = p + 1;
-
-	const char *p, *scheme = NULL, *user_info = NULL, *host = NULL;
-	const char *port = NULL, *path = NULL, *query = NULL;
-	unsigned int size_scheme = 0, size_user_info = 0, size_host = 0;
-	unsigned int size_port = 0, size_path = 0, size_query = 0;
-
-	if ((p = strstr(uri, "://"))) {
-		scheme = uri;
-		size_scheme = p - uri + 1;
-		uri = p + 3;
-	}
-
-	if ((p = strchr(uri, '@'))) {
-		SET_VALUES(user_info);
-	}
-
-	if ((p = strchr(uri, ':'))) {
-		SET_VALUES(host);
-	}
-
-	if ((p = strchr(uri, '/'))) {
-		if (!host) {
-			SET_VALUES(host);
-		} else {
-			SET_VALUES(port);
-		}
-	}
-
-	if ((p = strchr(uri, '?'))) {
-		query = p + 1;
-		size_query = strlen(query) + 1;
-	} else {
-		p = uri + strlen(uri);
-	}
-
-	if (!host) {
-		SET_VALUES(host);
-	} else if (*(uri - 1) == ':') {
-		SET_VALUES(port);
-	} else if (*(uri - 1) == '/') {
-		SET_VALUES(path);
-	}
-
-	return ast_uri_create_(scheme, size_scheme,
-			       user_info, size_user_info,
-			       host, size_host,
-			       port, size_port,
-			       path, size_path,
-			       query, size_query);
-}
-#endif
-
-static struct ast_uri *uri_parse_and_default(const char *uri, const char *scheme,
-					     const char *port, const char *secure_port)
-{
-	struct ast_uri *res;
-	int len = strlen(scheme);
-
-	if (!strncmp(uri, scheme, len)) {
-		res = ast_uri_parse(uri);
-	} else {
-		/* make room for <scheme>:// */
-		char *with_scheme = ast_malloc(len + strlen(uri) + 4);
-		if (!with_scheme) {
-			ast_log(LOG_ERROR, "Unable to allocate uri '%s' with "
-				"scheme '%s'", uri, scheme);
-			return NULL;
-		}
-
-		/* safe - 'with_scheme' created with size equal to len of
-		   scheme plus length of uri plus space for extra characters
-		   '://' and terminator */
-		sprintf(with_scheme, "%s://%s", scheme, uri);
-		res = ast_uri_parse(with_scheme);
-		ast_free(with_scheme);
-	}
-
-	if (res && ast_strlen_zero(ast_uri_port(res))) {
-		/* default the port if not given */
-		struct ast_uri *tmp = ast_uri_copy_replace(
-			res, NULL, NULL, NULL,
-			ast_uri_is_secure(res) ? secure_port : port,
-			NULL, NULL);
-		ao2_ref(res, -1);
-		res = tmp;
-	}
-	return res;
-}
-
-struct ast_uri *ast_uri_parse_http(const char *uri)
-{
-	return uri_parse_and_default(uri, "http", "80", "443");
-}
-
-struct ast_uri *ast_uri_parse_websocket(const char *uri)
-{
-	return uri_parse_and_default(uri, "ws", "80", "443");
-}
-
-char *ast_uri_make_host_with_port(const struct ast_uri *uri)
-{
-	int host_size = ast_uri_host(uri) ?
-		strlen(ast_uri_host(uri)) : 0;
-	/* if there is a port +1 for the colon */
-	int port_size = ast_uri_port(uri) ?
-		strlen(ast_uri_port(uri)) + 1 : 0;
-	char *res = ast_malloc(host_size + port_size + 1);
-
-	if (!res) {
-		return NULL;
-	}
-
-	memcpy(res, ast_uri_host(uri), host_size);
-
-	if (ast_uri_port(uri)) {
-		res[host_size] = ':';
-		memcpy(res + host_size + 1,
-		       ast_uri_port(uri), port_size - 1);
-	}
-
-	res[host_size + port_size] = '\0';
-	return res;
-}
diff --git a/main/utils.c b/main/utils.c
index d9b363d..3fa0b76 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -29,11 +29,11 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427384 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
-#include <fcntl.h>
 #include <sys/stat.h>
+
 #include <sys/syscall.h>
 #include <unistd.h>
 #if defined(__APPLE__)
@@ -42,6 +42,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427384 $")
 #include <sys/thr.h>
 #endif
 
+#ifdef HAVE_DEV_URANDOM
+#include <fcntl.h>
+#endif
+
+#include <sys/syscall.h>
+#if defined(__APPLE__)
+#include <mach/mach.h>
+#elif defined(HAVE_SYS_THR_H)
+#include <sys/thr.h>
+#endif
+
 #include "asterisk/network.h"
 #include "asterisk/ast_version.h"
 
@@ -52,7 +63,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427384 $")
 #include "asterisk/sha1.h"
 #include "asterisk/cli.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/astobj2.h"
 
 #define AST_API_MODULE		/* ensure that inlinable API functions will be built in this module if required */
 #include "asterisk/strings.h"
@@ -251,7 +261,7 @@ void ast_md5_hash(char *output, const char *input)
 	MD5Final(digest, &md5);
 	ptr = output;
 	for (x = 0; x < 16; x++)
-		ptr += sprintf(ptr, "%2.2x", (unsigned)digest[x]);
+		ptr += sprintf(ptr, "%02hhx", digest[x]);
 }
 
 /*! \brief Produce 40 char SHA1 hash of value. */
@@ -269,7 +279,7 @@ void ast_sha1_hash(char *output, const char *input)
 	SHA1Result(&sha, Message_Digest);
 	ptr = output;
 	for (x = 0; x < 20; x++)
-		ptr += sprintf(ptr, "%2.2x", (unsigned)Message_Digest[x]);
+		ptr += sprintf(ptr, "%02hhx", Message_Digest[x]);
 }
 
 /*! \brief Produce a 20 byte SHA1 hash of value. */
@@ -420,7 +430,7 @@ char *ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_fl
 			if (out - outbuf >= buflen - 3) {
 				break;
 			}
-			out += sprintf(out, "%%%02X", (unsigned) *ptr);
+			out += sprintf(out, "%%%02hhX", (unsigned char) *ptr);
 		} else {
 			*out = *ptr;	/* Continue copying the string */
 			out++;
@@ -611,7 +621,9 @@ const char *ast_inet_ntoa(struct in_addr ia)
 	return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
 }
 
-static int dev_urandom_fd;
+#ifdef HAVE_DEV_URANDOM
+static int dev_urandom_fd = -1;
+#endif
 
 #ifndef __linux__
 #undef pthread_create /* For ast_pthread_create function only */
@@ -644,11 +656,11 @@ struct thr_lock_info {
 	/*! This is the actual container of info for what locks this thread holds */
 	struct {
 		const char *file;
+		int line_num;
 		const char *func;
 		const char *lock_name;
 		void *lock_addr;
 		int times_locked;
-		int line_num;
 		enum ast_lock_type type;
 		/*! This thread is waiting on this lock */
 		int pending:2;
@@ -662,8 +674,6 @@ struct thr_lock_info {
 	 *  The index (num_locks - 1) has the info on the last one in the
 	 *  locks member */
 	unsigned int num_locks;
-	/*! The LWP id (which GDB prints) */
-	int lwp;
 	/*! Protects the contents of the locks member
 	 * Intentionally not ast_mutex_t */
 	pthread_mutex_t lock;
@@ -713,10 +723,9 @@ static void lock_info_destroy(void *data)
 	}
 
 	pthread_mutex_destroy(&lock_info->lock);
-	if (lock_info->thread_name) {
-		ast_free((void *) lock_info->thread_name);
-	}
-	ast_free(lock_info);
+	if (lock_info->thread_name)
+		free((void *) lock_info->thread_name);
+	free(lock_info);
 }
 
 /*!
@@ -1041,7 +1050,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
 	which will give a stack trace and continue. -- that aught to do the job!
 
 */
-void ast_log_show_lock(void *this_lock_addr)
+void log_show_lock(void *this_lock_addr)
 {
 	struct thr_lock_info *lock_info;
 	struct ast_str *str;
@@ -1072,16 +1081,28 @@ void ast_log_show_lock(void *this_lock_addr)
 }
 
 
-struct ast_str *ast_dump_locks(void)
+static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct thr_lock_info *lock_info;
 	struct ast_str *str;
 
-	if (!(str = ast_str_create(4096))) {
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "core show locks";
+		e->usage =
+			"Usage: core show locks\n"
+			"       This command is for lock debugging.  It prints out which locks\n"
+			"are owned by each active thread.\n";
+		return NULL;
+
+	case CLI_GENERATE:
 		return NULL;
 	}
 
-	ast_str_append(&str, 0, "\n"
+	if (!(str = ast_str_create(4096)))
+		return CLI_FAILURE;
+
+	ast_str_append(&str, 0, "\n" 
 	               "=======================================================================\n"
 	               "=== %s\n"
 	               "=== Currently Held Locks\n"
@@ -1090,9 +1111,8 @@ struct ast_str *ast_dump_locks(void)
 	               "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
 	               "===\n", ast_get_version());
 
-	if (!str) {
-		return NULL;
-	}
+	if (!str)
+		return CLI_FAILURE;
 
 	pthread_mutex_lock(&lock_infos_lock.mutex);
 	AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
@@ -1106,13 +1126,8 @@ struct ast_str *ast_dump_locks(void)
 			}
 
 			if (!header_printed) {
-				if (lock_info->lwp != -1) {
-					ast_str_append(&str, 0, "=== Thread ID: 0x%lx LWP:%d (%s)\n",
-						(long unsigned) lock_info->thread_id, lock_info->lwp, lock_info->thread_name);
-				} else {
-					ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n",
-						(long unsigned) lock_info->thread_id, lock_info->thread_name);
-				}
+				ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
+					lock_info->thread_name);
 				header_printed = 1;
 			}
 
@@ -1132,37 +1147,14 @@ struct ast_str *ast_dump_locks(void)
 	}
 	pthread_mutex_unlock(&lock_infos_lock.mutex);
 
-	if (!str) {
-		return NULL;
-	}
+	if (!str)
+		return CLI_FAILURE;
 
 	ast_str_append(&str, 0, "=======================================================================\n"
 	               "\n");
 
-	return str;
-}
-
-static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ast_str *str;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "core show locks";
-		e->usage =
-			"Usage: core show locks\n"
-			"       This command is for lock debugging.  It prints out which locks\n"
-			"are owned by each active thread.\n";
-		return NULL;
-
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	str = ast_dump_locks();
-	if (!str) {
+	if (!str)
 		return CLI_FAILURE;
-	}
 
 	ast_cli(a->fd, "%s", ast_str_buffer(str));
 
@@ -1207,7 +1199,6 @@ static void *dummy_start(void *data)
 		return NULL;
 
 	lock_info->thread_id = pthread_self();
-	lock_info->lwp = ast_get_tid();
 	lock_info->thread_name = strdup(a.name);
 
 	pthread_mutexattr_init(&mutex_attr);
@@ -1251,8 +1242,8 @@ int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*st
 		pthread_attr_init(attr);
 	}
 
-#ifdef __linux__
-	/* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
+#if defined(__linux__) || defined(__FreeBSD__)
+	/* On Linux and FreeBSD , pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
 	   which is kind of useless. Change this here to
 	   PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
 	   priority will propagate down to new threads by default.
@@ -1504,66 +1495,6 @@ char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
 	return s;
 }
 
-char *ast_strsep(char **iss, const char sep, uint32_t flags)
-{
-	char *st = *iss;
-	char *is;
-	int inquote = 0;
-	int found = 0;
-	char stack[8];
-
-	if (iss == NULL || *iss == '\0') {
-		return NULL;
-	}
-
-	memset(stack, 0, sizeof(stack));
-
-	for(is = st; *is; is++) {
-		if (*is == '\\') {
-			if (*++is != '\0') {
-				is++;
-			} else {
-				break;
-			}
-		}
-
-		if (*is == '\'' || *is == '"') {
-			if (*is == stack[inquote]) {
-				stack[inquote--] = '\0';
-			} else {
-				if (++inquote >= sizeof(stack)) {
-					return NULL;
-				}
-				stack[inquote] = *is;
-			}
-		}
-
-		if (*is == sep && !inquote) {
-			*is = '\0';
-			found = 1;
-			*iss = is + 1;
-			break;
-		}
-	}
-	if (!found) {
-		*iss = NULL;
-	}
-
-	if (flags & AST_STRSEP_STRIP) {
-		st = ast_strip_quoted(st, "'\"", "'\"");
-	}
-
-	if (flags & AST_STRSEP_TRIM) {
-		st = ast_strip(st);
-	}
-
-	if (flags & AST_STRSEP_UNESCAPE) {
-		ast_unescape_quoted(st);
-	}
-
-	return st;
-}
-
 char *ast_unescape_semicolon(char *s)
 {
 	char *e;
@@ -1767,17 +1698,11 @@ int ast_remaining_ms(struct timeval start, int max_ms)
 	return ms;
 }
 
-void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length)
-{
-	int durh, durm, durs;
-	durh = duration / 3600;
-	durm = (duration % 3600) / 60;
-	durs = duration % 60;
-	snprintf(buf, length, "%02d:%02d:%02d", durh, durm, durs);
-}
-
 #undef ONE_MILLION
 
+/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
+ * BSD libc (and others) do not. */
+
 #ifndef linux
 AST_MUTEX_DEFINE_STATIC(randomlock);
 #endif
@@ -1785,7 +1710,7 @@ AST_MUTEX_DEFINE_STATIC(randomlock);
 long int ast_random(void)
 {
 	long int res;
-
+#ifdef HAVE_DEV_URANDOM
 	if (dev_urandom_fd >= 0) {
 		int read_res = read(dev_urandom_fd, &res, sizeof(res));
 		if (read_res > 0) {
@@ -1795,14 +1720,7 @@ long int ast_random(void)
 			return res % rm;
 		}
 	}
-
-	/* XXX - Thread safety really depends on the libc, not the OS.
-	 *
-	 * But... popular Linux libc's (uClibc, glibc, eglibc), all have a
-	 * somewhat thread safe random(3) (results are random, but not
-	 * reproducible). The libc's for other systems (BSD, et al.), not so
-	 * much.
-	 */
+#endif
 #ifdef linux
 	res = random();
 #else
@@ -1848,7 +1766,7 @@ char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
 	return dataPut;
 }
 
-void ast_join_delim(char *s, size_t len, const char * const w[], unsigned int size, char delim)
+void ast_join(char *s, size_t len, const char * const w[])
 {
 	int x, ofs = 0;
 	const char *src;
@@ -1856,9 +1774,9 @@ void ast_join_delim(char *s, size_t len, const char * const w[], unsigned int si
 	/* Join words into a string */
 	if (!s)
 		return;
-	for (x = 0; ofs < len && w[x] && x < size; x++) {
+	for (x = 0; ofs < len && w[x]; x++) {
 		if (x > 0)
-			s[ofs++] = delim;
+			s[ofs++] = ' ';
 		for (src = w[x]; *src && ofs < len; src++)
 			s[ofs++] = *src;
 	}
@@ -1867,25 +1785,6 @@ void ast_join_delim(char *s, size_t len, const char * const w[], unsigned int si
 	s[ofs] = '\0';
 }
 
-char *ast_to_camel_case_delim(const char *s, const char *delim)
-{
-	char *res = ast_strdup(s);
-	char *front, *back, *buf = res;
-	int size;
-
-	front = strtok_r(buf, delim, &back);
-
-	while (front) {
-		size = strlen(front);
-		*front = toupper(*front);
-		ast_copy_string(buf, front, size + 1);
-		buf += size;
-		front = strtok_r(NULL, delim, &back);
-	}
-
-	return res;
-}
-
 /*
  * stringfields support routines.
  */
@@ -2364,104 +2263,12 @@ int ast_mkdir(const char *path, int mode)
 	return 0;
 }
 
-static int safe_mkdir(const char *base_path, char *path, int mode)
-{
-	RAII_VAR(char *, absolute_path, NULL, ast_std_free);
-
-	absolute_path = realpath(path, NULL);
-
-	if (absolute_path) {
-		/* Path exists, but is it in the right place? */
-		if (!ast_begins_with(absolute_path, base_path)) {
-			return EPERM;
-		}
-
-		/* It is in the right place! */
-		return 0;
-	} else {
-		/* Path doesn't exist. */
-
-		/* The slash terminating the subpath we're checking */
-		char *path_term = strchr(path, '/');
-		/* True indicates the parent path is within base_path */
-		int parent_is_safe = 0;
-		int res;
-
-		while (path_term) {
-			RAII_VAR(char *, absolute_subpath, NULL, ast_std_free);
-
-			/* Truncate the path one past the slash */
-			char c = *(path_term + 1);
-			*(path_term + 1) = '\0';
-			absolute_subpath = realpath(path, NULL);
-
-			if (absolute_subpath) {
-				/* Subpath exists, but is it safe? */
-				parent_is_safe = ast_begins_with(
-					absolute_subpath, base_path);
-			} else if (parent_is_safe) {
-				/* Subpath does not exist, but parent is safe
-				 * Create it */
-				res = mkdir(path, mode);
-				if (res != 0) {
-					ast_assert(errno != EEXIST);
-					return errno;
-				}
-			} else {
-				/* Subpath did not exist, parent was not safe
-				 * Fail! */
-				errno = EPERM;
-				return errno;
-			}
-			/* Restore the path */
-			*(path_term + 1) = c;
-			/* Move on to the next slash */
-			path_term = strchr(path_term + 1, '/');
-		}
-
-		/* Now to build the final path, but only if it's safe */
-		if (!parent_is_safe) {
-			errno = EPERM;
-			return errno;
-		}
-
-		res = mkdir(path, mode);
-		if (res != 0 && errno != EEXIST) {
-			return errno;
-		}
-
-		return 0;
-	}
-}
-
-int ast_safe_mkdir(const char *base_path, const char *path, int mode)
-{
-	RAII_VAR(char *, absolute_base_path, NULL, ast_std_free);
-	RAII_VAR(char *, p, NULL, ast_free);
-
-	if (base_path == NULL || path == NULL) {
-		errno = EFAULT;
-		return errno;
-	}
-
-	p = ast_strdup(path);
-	if (p == NULL) {
-		errno = ENOMEM;
-		return errno;
-	}
-
-	absolute_base_path = realpath(base_path, NULL);
-	if (absolute_base_path == NULL) {
-		return errno;
-	}
-
-	return safe_mkdir(absolute_base_path, p, mode);
-}
-
 static void utils_shutdown(void)
 {
+#ifdef HAVE_DEV_URANDOM
 	close(dev_urandom_fd);
 	dev_urandom_fd = -1;
+#endif
 #if defined(DEBUG_THREADS) && !defined(LOW_MEMORY)
 	ast_cli_unregister_multiple(utils_cli, ARRAY_LEN(utils_cli));
 #endif
@@ -2469,14 +2276,16 @@ static void utils_shutdown(void)
 
 int ast_utils_init(void)
 {
+#ifdef HAVE_DEV_URANDOM
 	dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+#endif
 	base64_init();
 #ifdef DEBUG_THREADS
 #if !defined(LOW_MEMORY)
 	ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
 #endif
 #endif
-	ast_register_atexit(utils_shutdown);
+	ast_register_cleanup(utils_shutdown);
 	return 0;
 }
 
@@ -2677,10 +2486,6 @@ void __ast_assert_failed(int condition, const char *condition_str, const char *f
 		condition_str, condition);
 	fprintf(stderr, "FRACK!, Failed assertion %s (%d) at line %d in %s of %s\n",
 		condition_str, condition, line, function, file);
-
-	/* Generate a backtrace for the assert */
-	ast_log_backtrace();
-
 	/*
 	 * Give the logger a chance to get the message out, just in case
 	 * we abort(), or Asterisk crashes due to whatever problem just
@@ -2690,110 +2495,3 @@ void __ast_assert_failed(int condition, const char *condition_str, const char *f
 	ast_do_crash();
 }
 #endif	/* defined(AST_DEVMODE) */
-
-char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
-{
-	int x;
-	char *os = s;
-	if (maxlen < 18) {
-		if (s && (maxlen > 0)) {
-			*s = '\0';
-		}
-	} else {
-		for (x = 0; x < 5; x++) {
-			sprintf(s, "%02x:", (unsigned)eid->eid[x]);
-			s += 3;
-		}
-		sprintf(s, "%02x", (unsigned)eid->eid[5]);
-	}
-	return os;
-}
-
-void ast_set_default_eid(struct ast_eid *eid)
-{
-#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
-	int s, x = 0;
-	char eid_str[20];
-	struct ifreq ifr;
-	static const unsigned int MAXIF = 10;
-
-	s = socket(AF_INET, SOCK_STREAM, 0);
-	if (s < 0) {
-		return;
-	}
-	for (x = 0; x < MAXIF; x++) {
-		static const char *prefixes[] = { "eth", "em" };
-		unsigned int i;
-
-		for (i = 0; i < ARRAY_LEN(prefixes); i++) {
-			memset(&ifr, 0, sizeof(ifr));
-			snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
-			if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-				break;
-			}
-		}
-
-		if (i == ARRAY_LEN(prefixes)) {
-			/* Try pciX#[1..N] */
-			for (i = 0; i < MAXIF; i++) {
-				memset(&ifr, 0, sizeof(ifr));
-				snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i);
-				if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-					break;
-				}
-			}
-			if (i == MAXIF) {
-				continue;
-			}
-		}
-
-		memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid));
-		ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr.ifr_name);
-		close(s);
-		return;
-	}
-	close(s);
-#else
-#if defined(ifa_broadaddr) && !defined(SOLARIS)
-	char eid_str[20];
-	struct ifaddrs *ifap;
-
-	if (getifaddrs(&ifap) == 0) {
-		struct ifaddrs *p;
-		for (p = ifap; p; p = p->ifa_next) {
-			if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
-				struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
-				memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
-				ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name);
-				freeifaddrs(ifap);
-				return;
-			}
-		}
-		freeifaddrs(ifap);
-	}
-#endif
-#endif
-	ast_debug(1, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
-}
-
-int ast_str_to_eid(struct ast_eid *eid, const char *s)
-{
-	unsigned int eid_int[6];
-	int x;
-
-	if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
-		 &eid_int[3], &eid_int[4], &eid_int[5]) != 6) {
-			return -1;
-	}
-
-	for (x = 0; x < 6; x++) {
-		eid->eid[x] = eid_int[x];
-	}
-
-	return 0;
-}
-
-int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
-{
-	return memcmp(eid1, eid2, sizeof(*eid1));
-}
diff --git a/main/uuid.c b/main/uuid.c
deleted file mode 100644
index ba864ac..0000000
--- a/main/uuid.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012, Digium, Inc.
- *
- * Mark Michelson <mmmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Universally unique identifier support
- *
- * \extref Depends on libuuid, a component of the e2fsprogs package - http://e2fsprogs.sourceforge.net/
- */
-
-#include "asterisk.h"
-#include <uuid/uuid.h>
-#include <fcntl.h>
-
-#include "asterisk/uuid.h"
-#include "asterisk/utils.h"
-#include "asterisk/strings.h"
-#include "asterisk/logger.h"
-#include "asterisk/lock.h"
-
-AST_MUTEX_DEFINE_STATIC(uuid_lock);
-
-static int has_dev_urandom;
-
-struct ast_uuid {
-	uuid_t uu;
-};
-
-/*!
- * \internal
- * \brief Generate a UUID.
- * \since 12.0.0
- *
- * \param uuid Fill this with a generated UUID.
- *
- * \return Nothing
- */
-static void generate_uuid(struct ast_uuid *uuid)
-{
-	/* libuuid provides three methods of generating uuids,
-	 * uuid_generate(), uuid_generate_random(), and uuid_generate_time().
-	 *
-	 * uuid_generate_random() creates a UUID based on random numbers. The method
-	 * attempts to use either /dev/urandom or /dev/random to generate random values.
-	 * If these resources are unavailable, then random numbers will be generated
-	 * using C library calls to generate pseudorandom numbers.
-	 * This method of generating UUIDs corresponds to section 4.4 of RFC 4122.
-	 *
-	 * uuid_generate_time() creates a UUID based on the current time plus
-	 * a system identifier (MAC address of the ethernet interface). This
-	 * method of generating UUIDs corresponds to section 4.2 of RFC 4122.
-	 *
-	 * uuid_generate() will check if /dev/urandom or /dev/random is available to
-	 * use. If so, it will use uuid_generate_random(). Otherwise, it will use
-	 * uuid_generate_time(). The idea is that it avoids using pseudorandom
-	 * numbers if necessary.
-	 *
-	 * For our purposes, we do not use the time-based UUID at all. There are
-	 * several reasons for this:
-	 *
-	 * 1) The time-based algorithm makes use of a daemon process (uuidd) in order
-	 * to ensure that any concurrent requests for UUIDs result in unique results.
-	 * Use of this daemon is a bit dodgy for a few reasons
-	 *
-	 *     a) libuuid assumes a hardcoded location for the .pid file of the daemon.
-	 *     However, the daemon could already be running on the system in a different
-	 *     location than expected. If this is the case, then attempting to connect
-	 *     to the daemon will fail, and attempting to launch another instance in
-	 *     the expected location will also fail.
-	 *
-	 *     b) If the daemon is not running, then the first attempt to create a
-	 *     time-based UUID will result in launching the daemon. Because of the hard-
-	 *     coded locations that libuuid assumes for the daemon, Asterisk must be
-	 *     run with permissions that will allow for the daemon to be launched in
-	 *     the expected directories.
-	 *
-	 *     c) Once the daemon is running, concurrent requests for UUIDs are thread-safe.
-	 *     However, the actual launching of the daemon is not thread-safe since libuuid
-	 *     uses no synchronization primitives to ensure that only one thread (or process)
-	 *     launches the daemon.
-	 *
-	 *     d) When libuuid launches the daemon, it sets an inactivity timer.
-	 *     If no UUID generation requests are issued in that time period,
-	 *     then the daemon will exit. If a new request should occur after the daemon
-	 *     exits, then the daemon will be relaunched. Given point c), we cannot
-	 *     necessarily guarantee the thread-safety of time-based UUID generation since
-	 *     we cannot necessarily guarantee the daemon is running as we expect.
-	 *     We could set up a watchdog thread to generate UUIDs at regular intervals to
-	 *     prevent the daemon from exiting, but frankly, that sucks.
-	 *
-	 * 2) Since the MAC address of the Ethernet interface is part of the UUID when
-	 * using the time-based method, there is information leaked.
-	 *
-	 * Given these drawbacks, we stick to only using random UUIDs. The chance of /dev/random
-	 * or /dev/urandom not existing on systems in this age is next to none.
-	 */
-
-	/* XXX Currently, we only protect this call if the user has no /dev/urandon on their system.
-	 * If it turns out that there are issues with UUID generation despite the presence of
-	 * /dev/urandom, then we may need to make the locking/unlocking unconditional.
-	 */
-	if (!has_dev_urandom) {
-		ast_mutex_lock(&uuid_lock);
-	}
-	uuid_generate_random(uuid->uu);
-	if (!has_dev_urandom) {
-		ast_mutex_unlock(&uuid_lock);
-	}
-}
-
-struct ast_uuid *ast_uuid_generate(void)
-{
-	struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
-
-	if (!uuid) {
-		return NULL;
-	}
-	generate_uuid(uuid);
-	return uuid;
-}
-
-char *ast_uuid_to_str(const struct ast_uuid *uuid, char *buf, size_t size)
-{
-	ast_assert(size >= AST_UUID_STR_LEN);
-	uuid_unparse_lower(uuid->uu, buf);
-	return buf;
-}
-
-char *ast_uuid_generate_str(char *buf, size_t size)
-{
-	struct ast_uuid uuid;
-
-	generate_uuid(&uuid);
-	return ast_uuid_to_str(&uuid, buf, size);
-}
-
-struct ast_uuid *ast_str_to_uuid(const char *str)
-{
-	struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
-	int res;
-
-	if (!uuid) {
-		return NULL;
-	}
-	res = uuid_parse(str, uuid->uu);
-	if (res) {
-		ast_log(LOG_WARNING, "Unable to convert string %s into a UUID\n", str);
-		ast_free(uuid);
-		return NULL;
-	}
-	return uuid;
-}
-
-struct ast_uuid *ast_uuid_copy(const struct ast_uuid *src)
-{
-	struct ast_uuid *dst = ast_malloc(sizeof(*dst));
-
-	if (!dst) {
-		return NULL;
-	}
-	uuid_copy(dst->uu, src->uu);
-	return dst;
-}
-
-int ast_uuid_compare(const struct ast_uuid *left, const struct ast_uuid *right)
-{
-	return uuid_compare(left->uu, right->uu);
-}
-
-void ast_uuid_clear(struct ast_uuid *uuid)
-{
-	uuid_clear(uuid->uu);
-}
-
-int ast_uuid_is_nil(const struct ast_uuid *uuid)
-{
-	return uuid_is_null(uuid->uu);
-}
-
-void ast_uuid_init(void)
-{
-	/* This requires some explanation.
-	 *
-	 * libuuid generates UUIDs based on random number generation. This involves
-	 * opening a handle to /dev/urandom or /dev/random in order to get random
-	 * data for the UUIDs.
-	 *
-	 * This is thread-safe, to a point. The problem is that the first attempt
-	 * to generate a UUID will result in opening the random number handle. Once
-	 * the handle is opened, all further generation is thread safe. This
-	 * first generation can be potentially risky if multiple threads attempt
-	 * to generate a UUID at the same time, though, since there is no thread
-	 * synchronization used within libuuid. To get around this potential
-	 * issue, we go ahead and generate a UUID up front so that the underlying
-	 * work is done before we start requesting UUIDs for real.
-	 *
-	 * Think of this along the same lines as initializing a singleton.
-	 */
-	uuid_t uu;
-	int dev_urandom_fd;
-
-	dev_urandom_fd = open("/dev/urandom", O_RDONLY);
-	if (dev_urandom_fd < 0) {
-		ast_log(LOG_WARNING, "It appears your system does not have /dev/urandom on it. This\n"
-				"means that UUID generation will use a pseudorandom number generator. Since\n"
-				"the thread-safety of your system's random number generator cannot\n"
-				"be guaranteed, we have to synchronize UUID generation. This may result\n"
-				"in decreased performance. It is highly recommended that you set up your\n"
-				"system to have /dev/urandom\n");
-	} else {
-		has_dev_urandom = 1;
-		close(dev_urandom_fd);
-	}
-	uuid_generate_random(uu);
-
-	ast_debug(1, "UUID system initiated\n");
-}
diff --git a/main/xml.c b/main/xml.c
index 2a2bd8e..bdf983e 100644
--- a/main/xml.c
+++ b/main/xml.c
@@ -28,21 +28,14 @@
 #include "asterisk.h"
 #include "asterisk/xml.h"
 #include "asterisk/logger.h"
-#include "asterisk/utils.h"
-#include "asterisk/autoconfig.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400385 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #if defined(HAVE_LIBXML2)
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/xinclude.h>
-#include <libxml/xpath.h>
 /* libxml2 ast_xml implementation. */
-#ifdef HAVE_LIBXSLT
-	#include <libxslt/xsltInternals.h>
-	#include <libxslt/transform.h>
-#endif /* HAVE_LIBXSLT */
 
 
 int ast_xml_init(void)
@@ -55,9 +48,6 @@ int ast_xml_init(void)
 int ast_xml_finish(void)
 {
 	xmlCleanupParser();
-#ifdef HAVE_LIBXSLT_CLEANUP
-	xsltCleanupGlobals();
-#endif
 
 	return 0;
 }
@@ -71,32 +61,13 @@ struct ast_xml_doc *ast_xml_open(char *filename)
 	}
 
 	doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
-	if (!doc) {
-		return NULL;
-	}
-
-	/* process xinclude elements. */
-	if (xmlXIncludeProcess(doc) < 0) {
-		xmlFreeDoc(doc);
-		return NULL;
-	}
-
-#ifdef HAVE_LIBXSLT
-	{
-		xsltStylesheetPtr xslt = xsltLoadStylesheetPI(doc);
-		if (xslt) {
-			xmlDocPtr tmpdoc = xsltApplyStylesheet(xslt, doc, NULL);
-			xsltFreeStylesheet(xslt);
+	if (doc) {
+		/* process xinclude elements. */
+		if (xmlXIncludeProcess(doc) < 0) {
 			xmlFreeDoc(doc);
-			if (!tmpdoc) {
-				return NULL;
-			}
-			doc = tmpdoc;
+			return NULL;
 		}
 	}
-#else /* no HAVE_LIBXSLT */
-	ast_log(LOG_NOTICE, "XSLT support not found. XML documentation may be incomplete.\n");
-#endif /* HAVE_LIBXSLT */
 
 	return (struct ast_xml_doc *) doc;
 }
@@ -345,42 +316,5 @@ struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node)
 	return (struct ast_xml_node *) ((xmlNode *) node)->parent;
 }
 
-struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
-{
-	return (struct ast_xml_node *) ((xmlXPathObjectPtr) results)->nodesetval->nodeTab[0];
-}
-
-void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
-{
-	xmlXPathFreeObject((xmlXPathObjectPtr) results);
-}
-
-int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results)
-{
-	return ((xmlXPathObjectPtr) results)->nodesetval->nodeNr;
-}
-
-struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char *xpath_str)
-{
-	xmlXPathContextPtr context;
-	xmlXPathObjectPtr result;
-	if (!(context = xmlXPathNewContext((xmlDoc *) doc))) {
-		ast_log(LOG_ERROR, "Could not create XPath context!\n");
-		return NULL;
-	}
-	result = xmlXPathEvalExpression((xmlChar *) xpath_str, context);
-	xmlXPathFreeContext(context);
-	if (!result) {
-		ast_log(LOG_WARNING, "Error for query: %s\n", xpath_str);
-		return NULL;
-	}
-	if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
-		xmlXPathFreeObject(result);
-		ast_debug(5, "No results for query: %s\n", xpath_str);
-		return NULL;
-	}
-	return (struct ast_xml_xpath_results *) result;
-}
-
 #endif /* defined(HAVE_LIBXML2) */
 
diff --git a/main/xmldoc.c b/main/xmldoc.c
index d589a29..fa471e9 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -20,7 +20,7 @@
  *
  * \author Eliel C. Sardanons (LU1ALY) <eliels at gmail.com>
  *
- * libxml2 http://www.xmlsoft.org/
+ * \extref libxml2 http://www.xmlsoft.org/
  */
 
 /*** MODULEINFO
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419822 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"
@@ -38,24 +38,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419822 $")
 #include "asterisk/term.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/xmldoc.h"
-#include "asterisk/cli.h"
 
 #ifdef AST_XML_DOCS
 
 /*! \brief Default documentation language. */
 static const char default_documentation_language[] = "en_US";
 
-/*!
- * \brief Number of columns to print when showing the XML documentation with a
- *         'core show application/function *' CLI command. Used in text wrapping.
- */
+/*! \brief Number of columns to print when showing the XML documentation with a
+ *         'core show application/function *' CLI command. Used in text wrapping.*/
 static const int xmldoc_text_columns = 74;
 
-/*!
- * \brief This is a value that we will use to let the wrapping mechanism move the cursor
+/*! \brief This is a value that we will use to let the wrapping mechanism move the cursor
  *         backward and forward xmldoc_max_diff positions before cutting the middle of a
- *         word, trying to find a space or a \n.
- */
+ *         word, trying to find a space or a \n. */
 static const int xmldoc_max_diff = 5;
 
 /*! \brief XML documentation language. */
@@ -70,7 +65,6 @@ struct documentation_tree {
 
 static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname);
 static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer);
-static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer);
 static int xmldoc_parse_info(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer);
 static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer);
 static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *tabs, const char *posttabs, struct ast_str **buffer);
@@ -104,9 +98,7 @@ static const struct strcolorized_tags {
 
 	/* Special tags */
 	{ "", "", COLOR_YELLOW, "<note>",   "</note>" },
-	{ "", "", COLOR_RED,   "<warning>", "</warning>" },
-	{ "", "", COLOR_WHITE, "<example>", "</example>" },
-	{ "", "", COLOR_GRAY, "<exampletext>", "</exampletext>"},
+	{ "", "", COLOR_RED,   "<warning>", "</warning>" }
 };
 
 static const struct strspecial_tags {
@@ -115,18 +107,14 @@ static const struct strspecial_tags {
 	const char *end;		/*!< Print this at the end. */
 } special_tags[] = {
 	{ "note",    "<note>NOTE:</note> ",             "" },
-	{ "warning", "<warning>WARNING!!!:</warning> ", "" },
-	{ "example", "<example>Example:</example> ", "" },
+	{ "warning", "<warning>WARNING!!!:</warning> ", "" }
 };
 
-/*!
- * \internal
- * \brief Calculate the space in bytes used by a format string
- *        that will be passed to a sprintf function.
- *
- * \param postbr The format string to use to calculate the length.
- *
- * \retval The postbr length.
+/*! \internal
+ *  \brief Calculate the space in bytes used by a format string
+ *         that will be passed to a sprintf function.
+ *  \param postbr The format string to use to calculate the length.
+ *  \retval The postbr length.
  */
 static int xmldoc_postbrlen(const char *postbr)
 {
@@ -147,14 +135,12 @@ static int xmldoc_postbrlen(const char *postbr)
 	return postbrreallen;
 }
 
-/*!
- * \internal
- * \brief Setup postbr to be used while wrapping the text.
- *        Add to postbr array all the spaces and tabs at the beginning of text.
- *
- * \param postbr output array.
- * \param len text array length.
- * \param text Text with format string before the actual string.
+/*! \internal
+ *  \brief Setup postbr to be used while wrapping the text.
+ *         Add to postbr array all the spaces and tabs at the beginning of text.
+ *  \param postbr output array.
+ *  \param len text array length.
+ *  \param text Text with format string before the actual string.
  */
 static void xmldoc_setpostbr(char *postbr, size_t len, const char *text)
 {
@@ -174,18 +160,15 @@ static void xmldoc_setpostbr(char *postbr, size_t len, const char *text)
 	postbr[postbrlen] = '\0';
 }
 
-/*!
- * \internal
- * \brief Try to find a space or a break in text starting at currentpost
+/*! \internal
+ *  \brief Try to find a space or a break in text starting at currentpost
  *         and moving at most maxdiff positions.
  *         Helper for xmldoc_string_wrap().
- *
- * \param text Input string where it will search.
- * \param currentpos Current position within text.
- * \param maxdiff Not move more than maxdiff inside text.
- *
- * \retval 1 if a space or break is found inside text while moving.
- * \retval 0 if no space or break is found.
+ *  \param text Input string where it will search.
+ *  \param currentpos Current position within text.
+ *  \param maxdiff Not move more than maxdiff inside text.
+ *  \retval 1 if a space or break is found inside text while moving.
+ *  \retval 0 if no space or break is found.
  */
 static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff)
 {
@@ -216,19 +199,16 @@ static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Helper function for xmldoc_string_wrap().
- *    Try to found a space or a break inside text moving backward
- *    not more than maxdiff positions.
- *
- * \param text The input string where to search for a space.
- * \param currentpos The current cursor position.
- * \param maxdiff The max number of positions to move within text.
- *
- * \retval 0 If no space is found (Notice that text[currentpos] is not a space or a break)
- * \retval > 0 If a space or a break is found, and the result is the position relative to
- *  currentpos.
+/*! \internal
+ *  \brief Helper function for xmldoc_string_wrap().
+ *	   Try to found a space or a break inside text moving backward
+ *	   not more than maxdiff positions.
+ *  \param text The input string where to search for a space.
+ *  \param currentpos The current cursor position.
+ *  \param maxdiff The max number of positions to move within text.
+ *  \retval 0 If no space is found (Notice that text[currentpos] is not a space or a break)
+ *  \retval > 0 If a space or a break is found, and the result is the position relative to
+ *		currentpos.
  */
 static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxdiff)
 {
@@ -251,16 +231,13 @@ static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxd
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Justify a text to a number of columns.
- *
- * \param text Input text to be justified.
- * \param columns Number of columns to preserve in the text.
- * \param maxdiff Try to not cut a word when goinf down.
- *
- * \retval NULL on error.
- * \retval The wrapped text.
+/*! \internal
+ *  \brief Justify a text to a number of columns.
+ *  \param text Input text to be justified.
+ *  \param columns Number of columns to preserve in the text.
+ *  \param maxdiff Try to not cut a word when goinf down.
+ *  \retval NULL on error.
+ *  \retval The wrapped text.
  */
 static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff)
 {
@@ -435,7 +412,7 @@ char *ast_xmldoc_printable(const char *bwinput, int withcolors)
 	}
 
 	if (withcolors) {
-		ast_str_append(&colorized, 0, "%s", ast_term_reset());
+		ast_str_append(&colorized, 0, "%s", term_end());
 		if (!colorized) {
 			return NULL;
 		}
@@ -449,16 +426,13 @@ char *ast_xmldoc_printable(const char *bwinput, int withcolors)
 	return wrapped;
 }
 
-/*!
- * \internal
- * \brief Cleanup spaces and tabs after a \n
- *
- * \param text String to be cleaned up.
- * \param output buffer (not already allocated).
- * \param lastspaces Remove last spaces in the string.
- * \param maintain_newlines Preserve new line characters (\n \r) discovered in the string
+/*! \internal
+ *  \brief Cleanup spaces and tabs after a \n
+ *  \param text String to be cleaned up.
+ *  \param output buffer (not already allocated).
+ *  \param lastspaces Remove last spaces in the string.
  */
-static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int lastspaces, int maintain_newlines)
+static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int lastspaces)
 {
 	int i;
 	size_t textlen;
@@ -478,9 +452,6 @@ static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int
 
 	for (i = 0; i < textlen; i++) {
 		if (text[i] == '\n' || text[i] == '\r') {
-			if (maintain_newlines) {
-				ast_str_append(output, 0, "%c", text[i]);
-			}
 			/* remove spaces/tabs/\n after a \n. */
 			while (text[i + 1] == '\t' || text[i + 1] == '\r' || text[i + 1] == '\n') {
 				i++;
@@ -498,14 +469,11 @@ static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int
 	}
 }
 
-/*!
- * \internal
+/*! \internal
  * \brief Check if the given attribute on the given node matches the given value.
- *
  * \param node the node to match
  * \param attr the name of the attribute
  * \param value the expected value of the attribute
- *
  * \retval true if the given attribute contains the given value
  * \retval false if the given attribute does not exist or does not contain the given value
  */
@@ -517,19 +485,16 @@ static int xmldoc_attribute_match(struct ast_xml_node *node, const char *attr, c
 	return match;
 }
 
-/*!
- * \internal
- * \brief Get the application/function node for 'name' application/function with language 'language'
- *        and module 'module' if we don't find any, get the first application
- *        with 'name' no matter which language or module.
- *
- * \param type 'application', 'function', ...
- * \param name Application or Function name.
- * \param module Module item is in.
- * \param language Try to get this language (if not found try with en_US)
- *
- * \retval NULL on error.
- * \retval A node of type ast_xml_node.
+/*! \internal
+ *  \brief Get the application/function node for 'name' application/function with language 'language'
+ *         and module 'module' if we don't find any, get the first application
+ *         with 'name' no matter which language or module.
+ *  \param type 'application', 'function', ...
+ *  \param name Application or Function name.
+ *  \param module Module item is in.
+ *  \param language Try to get this language (if not found try with en_US)
+ *  \retval NULL on error.
+ *  \retval A node of type ast_xml_node.
  */
 static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *module, const char *language)
 {
@@ -602,16 +567,14 @@ static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name,
 	return node;
 }
 
-/*!
- * \internal
- * \brief Helper function used to build the syntax, it allocates the needed buffer (or reallocates it),
- *        and based on the reverse value it makes use of fmt to print the parameter list inside the
- *        realloced buffer (syntax).
- *
- * \param reverse We are going backwards while generating the syntax?
- * \param len Current length of 'syntax' buffer.
- * \param syntax Output buffer for the concatenated values.
- * \param fmt A format string that will be used in a sprintf call.
+/*! \internal
+ *  \brief Helper function used to build the syntax, it allocates the needed buffer (or reallocates it),
+ *         and based on the reverse value it makes use of fmt to print the parameter list inside the
+ *         realloced buffer (syntax).
+ *  \param reverse We are going backwards while generating the syntax?
+ *  \param len Current length of 'syntax' buffer.
+ *  \param syntax Output buffer for the concatenated values.
+ *  \param fmt A format string that will be used in a sprintf call.
  */
 static void __attribute__((format(printf, 4, 5))) xmldoc_reverse_helper(int reverse, int *len, char **syntax, const char *fmt, ...)
 {
@@ -655,15 +618,12 @@ static void __attribute__((format(printf, 4, 5))) xmldoc_reverse_helper(int reve
 	ast_free(tmpfmt);
 }
 
-/*!
- * \internal
- * \brief Check if the passed node has 'what' tags inside it.
- *
- * \param node Root node to search 'what' elements.
- * \param what node name to search inside node.
- *
- * \retval 1 If a 'what' element is found inside 'node'.
- * \retval 0 If no 'what' is found inside 'node'.
+/*! \internal
+ *  \brief Check if the passed node has 'what' tags inside it.
+ *  \param node Root node to search 'what' elements.
+ *  \param what node name to search inside node.
+ *  \retval 1 If a 'what' element is found inside 'node'.
+ *  \retval 0 If no 'what' is found inside 'node'.
  */
 static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
 {
@@ -677,14 +637,11 @@ static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Check if the passed node has at least one node inside it.
- *
- * \param node Root node to search node elements.
- *
- * \retval 1 If a node element is found inside 'node'.
- * \retval 0 If no node is found inside 'node'.
+/*! \internal
+ *  \brief Check if the passed node has at least one node inside it.
+ *  \param node Root node to search node elements.
+ *  \retval 1 If a node element is found inside 'node'.
+ *  \retval 0 If no node is found inside 'node'.
  */
 static int xmldoc_has_nodes(struct ast_xml_node *fixnode)
 {
@@ -698,14 +655,11 @@ static int xmldoc_has_nodes(struct ast_xml_node *fixnode)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Check if the passed node has at least one specialtag.
- *
- * \param node Root node to search "specialtags" elements.
- *
- * \retval 1 If a "specialtag" element is found inside 'node'.
- * \retval 0 If no "specialtag" is found inside 'node'.
+/*! \internal
+ *  \brief Check if the passed node has at least one specialtag.
+ *  \param node Root node to search "specialtags" elements.
+ *  \retval 1 If a "specialtag" element is found inside 'node'.
+ *  \retval 0 If no "specialtag" is found inside 'node'.
  */
 static int xmldoc_has_specialtags(struct ast_xml_node *fixnode)
 {
@@ -722,18 +676,15 @@ static int xmldoc_has_specialtags(struct ast_xml_node *fixnode)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Build the syntax for a specified starting node.
- *
- * \param rootnode A pointer to the ast_xml root node.
- * \param rootname Name of the application, function, option, etc. to build the syntax.
- * \param childname The name of each parameter node.
- * \param printparenthesis Boolean if we must print parenthesis if not parameters are found in the rootnode.
- * \param printrootname Boolean if we must print the rootname before the syntax and parenthesis at the begining/end.
- *
- * \retval NULL on error.
- * \retval An ast_malloc'ed string with the syntax generated.
+/*! \internal
+ *  \brief Build the syntax for a specified starting node.
+ *  \param rootnode A pointer to the ast_xml root node.
+ *  \param rootname Name of the application, function, option, etc. to build the syntax.
+ *  \param childname The name of each parameter node.
+ *  \param printparenthesis Boolean if we must print parenthesis if not parameters are found in the rootnode.
+ *  \param printrootname Boolean if we must print the rootname before the syntax and parenthesis at the begining/end.
+ *  \retval NULL on error.
+ *  \retval An ast_malloc'ed string with the syntax generated.
  */
 static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
 {
@@ -970,14 +921,12 @@ static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *ro
 #undef MP
 }
 
-/*!
- * \internal
- * \brief Parse an enumlist inside a <parameter> to generate a COMMAND syntax.
- *
- * \param fixnode A pointer to the <enumlist> node.
- *
- * \retval {<unknown>} on error.
- * \retval A string inside brackets {} with the enum's separated by pipes |.
+/*! \internal
+ *  \brief Parse an enumlist inside a <parameter> to generate a COMMAND
+ *         syntax.
+ *  \param fixnode A pointer to the <enumlist> node.
+ *  \retval {<unknown>} on error.
+ *  \retval A string inside brackets {} with the enum's separated by pipes |.
  */
 static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
 {
@@ -1018,16 +967,13 @@ static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Generate a syntax of COMMAND type.
- *
- * \param fixnode The <syntax> node pointer.
- * \param name The name of the 'command'.
- * \param printname Print the name of the command before the paramters?
- *
- * \retval On error, return just 'name'.
- * \retval On success return the generated syntax.
+/*! \internal
+ *  \brief Generate a syntax of COMMAND type.
+ *  \param fixnode The <syntax> node pointer.
+ *  \param name The name of the 'command'.
+ *  \param printname Print the name of the command before the paramters?
+ *  \retval On error, return just 'name'.
+ *  \retval On success return the generated syntax.
  */
 static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname)
 {
@@ -1037,10 +983,6 @@ static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *nam
 	const char *paramtype, *attrname, *literal;
 	int required, isenum, first = 1, isliteral;
 
-	if (!fixnode) {
-		return NULL;
-	}
-
 	syntax = ast_str_create(128);
 	if (!syntax) {
 		/* at least try to return something... */
@@ -1124,16 +1066,13 @@ static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *nam
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Generate an AMI action/event syntax.
- *
- * \param fixnode The manager action/event node pointer.
- * \param name The name of the manager action/event.
- * \param manager_type "Action" or "Event"
- *
- * \retval The generated syntax.
- * \retval NULL on error.
+/*! \internal
+ *  \brief Generate an AMI action/event syntax.
+ *  \param fixnode The manager action/event node pointer.
+ *  \param name The name of the manager action/event.
+ *  \param manager_type "Action" or "Event"
+ *  \retval The generated syntax.
+ *  \retval NULL on error.
  */
 static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char *name, const char *manager_type)
 {
@@ -1143,10 +1082,6 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
 	int required;
 	char *ret;
 
-	if (!fixnode) {
-		return NULL;
-	}
-
 	syntax = ast_str_create(128);
 	if (!syntax) {
 		return ast_strdup(name);
@@ -1187,78 +1122,11 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
 	return ret;
 }
 
-static char *xmldoc_get_syntax_config_object(struct ast_xml_node *fixnode, const char *name)
-{
-	struct ast_xml_node *matchinfo, *tmp;
-	int match;
-	const char *attr_value;
-	const char *text;
-	RAII_VAR(struct ast_str *, syntax, ast_str_create(128), ast_free);
-
-	if (!syntax || !fixnode) {
-		return NULL;
-	}
-	if (!(matchinfo = ast_xml_find_element(ast_xml_node_get_children(fixnode), "matchInfo", NULL, NULL))) {
-		return NULL;
-	}
-	if (!(tmp  = ast_xml_find_element(ast_xml_node_get_children(matchinfo), "category", NULL, NULL))) {
-		return NULL;
-	}
-	attr_value = ast_xml_get_attribute(tmp, "match");
-	if (attr_value) {
-		match = ast_true(attr_value);
-		text = ast_xml_get_text(tmp);
-		ast_str_set(&syntax, 0, "category %s /%s/", match ? "=~" : "!~", text);
-		ast_xml_free_attr(attr_value);
-		ast_xml_free_text(text);
-	}
-
-	if ((tmp = ast_xml_find_element(ast_xml_node_get_children(matchinfo), "field", NULL, NULL))) {
-		text = ast_xml_get_text(tmp);
-		attr_value = ast_xml_get_attribute(tmp, "name");
-		ast_str_append(&syntax, 0, " matchfield: %s = %s", S_OR(attr_value, "Unknown"), text);
-		ast_xml_free_attr(attr_value);
-		ast_xml_free_text(text);
-	}
-	return ast_strdup(ast_str_buffer(syntax));
-}
-
-static char *xmldoc_get_syntax_config_option(struct ast_xml_node *fixnode, const char *name)
-{
-	const char *type;
-	const char *default_value;
-	const char *regex;
-	RAII_VAR(struct ast_str *, syntax, ast_str_create(128), ast_free);
-
-	if (!syntax || !fixnode) {
-		return NULL;
-	}
-	type = ast_xml_get_attribute(fixnode, "type");
-	default_value = ast_xml_get_attribute(fixnode, "default");
-
-	regex = ast_xml_get_attribute(fixnode, "regex");
-	ast_str_set(&syntax, 0, "%s = [%s] (Default: %s) (Regex: %s)\n",
-		name,
-		type,
-		default_value ?: "n/a",
-		regex ?: "False");
-
-	ast_xml_free_attr(type);
-	ast_xml_free_attr(default_value);
-	ast_xml_free_attr(regex);
-
-	return ast_strdup(ast_str_buffer(syntax));
-}
-
 /*! \brief Types of syntax that we are able to generate. */
 enum syntaxtype {
 	FUNCTION_SYNTAX,
 	MANAGER_SYNTAX,
 	MANAGER_EVENT_SYNTAX,
-	CONFIG_INFO_SYNTAX,
-	CONFIG_FILE_SYNTAX,
-	CONFIG_OPTION_SYNTAX,
-	CONFIG_OBJECT_SYNTAX,
 	COMMAND_SYNTAX
 };
 
@@ -1267,24 +1135,17 @@ static struct strsyntaxtype {
 	const char *type;
 	enum syntaxtype stxtype;
 } stxtype[] = {
-    { "function",     FUNCTION_SYNTAX      },
-    { "application",  FUNCTION_SYNTAX      },
-    { "manager",      MANAGER_SYNTAX       },
-    { "managerEvent", MANAGER_EVENT_SYNTAX },
-    { "configInfo",   CONFIG_INFO_SYNTAX   },
-    { "configFile",   CONFIG_FILE_SYNTAX   },
-    { "configOption", CONFIG_OPTION_SYNTAX },
-    { "configObject", CONFIG_OBJECT_SYNTAX },
-    { "agi",          COMMAND_SYNTAX       },
+	{ "function",		FUNCTION_SYNTAX			},
+	{ "application",	FUNCTION_SYNTAX			},
+	{ "manager",		MANAGER_SYNTAX			},
+	{ "managerEvent",	MANAGER_EVENT_SYNTAX	},
+	{ "agi",			COMMAND_SYNTAX			}
 };
 
-/*!
- * \internal
- * \brief Get syntax type based on type of node.
- *
- * \param type Type of node.
- *
- * \retval The type of syntax to generate based on the type of node.
+/*! \internal
+ *  \brief Get syntax type based on type of node.
+ *  \param type Type of node.
+ *  \retval The type of syntax to generate based on the type of node.
  */
 static enum syntaxtype xmldoc_get_syntax_type(const char *type)
 {
@@ -1308,15 +1169,14 @@ static enum syntaxtype xmldoc_get_syntax_type(const char *type)
  * \note This method exists for when you already have the node.  This
  * prevents having to lock the documentation tree twice
  *
- * \retval A malloc'd character pointer to the syntax of the item
- * \retval NULL on failure
+ * \returns A malloc'd character pointer to the syntax of the item
+ * \returns NULL on failure
  *
  * \since 11
  */
-static char *_ast_xmldoc_build_syntax(struct ast_xml_node *root_node, const char *type, const char *name)
+static char *_ast_xmldoc_build_syntax(struct ast_xml_node *node, const char *type, const char *name)
 {
 	char *syntax = NULL;
-	struct ast_xml_node *node = root_node;
 
 	for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
 		if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
@@ -1324,6 +1184,10 @@ static char *_ast_xmldoc_build_syntax(struct ast_xml_node *root_node, const char
 		}
 	}
 
+	if (!node) {
+		return syntax;
+	}
+
 	switch (xmldoc_get_syntax_type(type)) {
 	case FUNCTION_SYNTAX:
 		syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
@@ -1337,12 +1201,6 @@ static char *_ast_xmldoc_build_syntax(struct ast_xml_node *root_node, const char
 	case MANAGER_EVENT_SYNTAX:
 		syntax = xmldoc_get_syntax_manager(node, name, "Event");
 		break;
-	case CONFIG_OPTION_SYNTAX:
-		syntax = xmldoc_get_syntax_config_option(root_node, name);
-		break;
-	case CONFIG_OBJECT_SYNTAX:
-		syntax = xmldoc_get_syntax_config_object(node, name);
-		break;
 	default:
 		syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
 	}
@@ -1362,21 +1220,18 @@ char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *mo
 	return _ast_xmldoc_build_syntax(node, type, name);
 }
 
-/*!
- * \internal
- * \brief Parse common internal elements.  This includes paragraphs, special
- *        tags, and information nodes.
- *
- * \param node The element to parse
- * \param tabs Add this string before the content of the parsed element.
- * \param posttabs Add this string after the content of the parsed element.
- * \param buffer This must be an already allocated ast_str. It will be used to
- *               store the result (if something has already been placed in the
- *               buffer, the parsed elements will be appended)
- *
- * \retval 1 if any data was appended to the buffer
- * \retval 2 if the data appended to the buffer contained a text paragraph
- * \retval 0 if no data was appended to the buffer
+/*! \internal
+ *  \brief Parse common internal elements.  This includes paragraphs, special
+ *         tags, and information nodes.
+ *  \param node The element to parse
+ *  \param tabs Add this string before the content of the parsed element.
+ *  \param posttabs Add this string after the content of the parsed element.
+ *  \param buffer This must be an already allocated ast_str. It will be used to
+ *                store the result (if something has already been placed in the
+ *                buffer, the parsed elements will be appended)
+ *  \retval 1 if any data was appended to the buffer
+ *  \retval 2 if the data appended to the buffer contained a text paragraph
+ *  \retval 0 if no data was appended to the buffer
  */
 static int xmldoc_parse_common_elements(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
 {
@@ -1385,20 +1240,17 @@ static int xmldoc_parse_common_elements(struct ast_xml_node *node, const char *t
 		|| xmldoc_parse_info(node, tabs, posttabs, buffer));
 }
 
-/*!
- * \internal
- * \brief Parse a <para> element.
- *
- * \param node The <para> element pointer.
- * \param tabs Added this string before the content of the <para> element.
- * \param posttabs Added this string after the content of the <para> element.
- * \param buffer This must be an already allocated ast_str. It will be used
- *        to store the result (if already has something it will be appended to the current
- *        string).
- *
- * \retval 1 If 'node' is a named 'para'.
- * \retval 2 If data is appended in buffer.
- * \retval 0 on error.
+/*! \internal
+ *  \brief Parse a <para> element.
+ *  \param node The <para> element pointer.
+ *  \param tabs Added this string before the content of the <para> element.
+ *  \param posttabs Added this string after the content of the <para> element.
+ *  \param buffer This must be an already allocated ast_str. It will be used
+ *         to store the result (if already has something it will be appended to the current
+ *         string).
+ *  \retval 1 If 'node' is a named 'para'.
+ *  \retval 2 If data is appended in buffer.
+ *  \retval 0 on error.
  */
 static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
 {
@@ -1424,7 +1276,7 @@ static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const
 		tmptext = ast_xml_get_text(tmp);
 		if (tmptext) {
 			/* Strip \n etc. */
-			xmldoc_string_cleanup(tmptext, &tmpstr, 0, 0);
+			xmldoc_string_cleanup(tmptext, &tmpstr, 0);
 			ast_xml_free_text(tmptext);
 			if (tmpstr) {
 				if (strcasecmp(ast_xml_node_get_name(tmp), "text")) {
@@ -1444,69 +1296,15 @@ static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse an <example> node.
- * \since 13.0.0
- *
- * \param fixnode An ast xml pointer to the <example> node.
- * \param buffer The output buffer.
- *
- * \retval 0 if no example node is parsed.
- * \retval 1 if an example node is parsed.
- */
-static int xmldoc_parse_example(struct ast_xml_node *fixnode, struct ast_str **buffer)
-{
-	struct ast_xml_node *node = fixnode;
-	const char *tmptext;
-	const char *title;
-	struct ast_str *stripped_text;
-	int ret = 0;
-
-	if (!node || !ast_xml_node_get_children(node)) {
-		return ret;
-	}
-
-	if (strcasecmp(ast_xml_node_get_name(node), "example")) {
-		return ret;
-	}
-
-	ret = 1;
-
-	title = ast_xml_get_attribute(node, "title");
-	if (title) {
-		ast_str_append(buffer, 0, "%s", title);
-		ast_xml_free_attr(title);
-	}
-	ast_str_append(buffer, 0, "\n");
-
-	for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-		tmptext = ast_xml_get_text(node);
-		if (tmptext) {
-			xmldoc_string_cleanup(tmptext, &stripped_text, 0, 1);
-			if (stripped_text) {
-				ast_str_append(buffer, 0, "<exampletext>%s</exampletext>\n", ast_str_buffer(stripped_text));
-				ast_xml_free_text(tmptext);
-				ast_free(stripped_text);
-			}
-		}
-	}
-
-	return ret;
-}
-
-/*!
- * \internal
- * \brief Parse special elements defined in 'struct special_tags' special elements must have a <para> element inside them.
- *
- * \param fixnode special tag node pointer.
- * \param tabs put tabs before printing the node content.
- * \param posttabs put posttabs after printing node content.
- * \param buffer Output buffer, the special tags will be appended here.
- *
- * \retval 0 if no special element is parsed.
- * \retval 1 if a special element is parsed (data is appended to buffer).
- * \retval 2 if a special element is parsed and also a <para> element is parsed inside the specialtag.
+/*! \internal
+ *  \brief Parse special elements defined in 'struct special_tags' special elements must have a <para> element inside them.
+ *  \param fixnode special tag node pointer.
+ *  \param tabs put tabs before printing the node content.
+ *  \param posttabs put posttabs after printing node content.
+ *  \param buffer Output buffer, the special tags will be appended here.
+ *  \retval 0 if no special element is parsed.
+ *  \retval 1 if a special element is parsed (data is appended to buffer).
+ *  \retval 2 if a special element is parsed and also a <para> element is parsed inside the specialtag.
  */
 static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *tabs, const char *posttabs, struct ast_str **buffer)
 {
@@ -1530,11 +1328,6 @@ static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *ta
 			ast_str_append(buffer, 0, "%s%s", tabs, special_tags[i].init);
 		}
 
-		if (xmldoc_parse_example(node, buffer)) {
-			ret = 1;
-			break;
-		}
-
 		/* parse <para> elements inside special tags. */
 		for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
 			/* first <para> just print it without tabs at the begining. */
@@ -1554,18 +1347,64 @@ static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *ta
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse an <argument> element from the xml documentation.
- *
- * \param fixnode Pointer to the 'argument' xml node.
- * \param insideparameter If we are parsing an <argument> inside a <parameter>.
- * \param paramtabs pre tabs if we are inside a parameter element.
- * \param tabs What to be printed before the argument name.
- * \param buffer Output buffer to put values found inside the <argument> element.
- *
- * \retval 1 If there is content inside the argument.
- * \retval 0 If the argument element is not parsed, or there is no content inside it.
+/*! \internal
+ *  \brief Parse an 'info' tag inside an element.
+ *  \param node A pointer to the 'info' xml node.
+ *  \param tabs A string to be appended at the beginning of each line being printed
+ *              inside 'buffer'
+ *  \param posttabs Add this string after the content of the <para> element, if one exists
+ *  \param String buffer to put values found inide the info element.
+ *  \ret 2 if the information contained a para element, and it returned a value of 2
+ *  \ret 1 if information was put into the buffer
+ *  \ret 0 if no information was put into the buffer or error
+ */
+static int xmldoc_parse_info(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
+{
+	const char *tech;
+	char *internaltabs;
+	int internal_ret;
+	int ret = 0;
+
+	if (strcasecmp(ast_xml_node_get_name(node), "info")) {
+		return ret;
+	}
+
+	ast_asprintf(&internaltabs, "%s    ", tabs);
+	if (!internaltabs) {
+		return ret;
+	}
+
+	tech = ast_xml_get_attribute(node, "tech");
+	if (tech) {
+		ast_str_append(buffer, 0, "%s<note>Technology: %s</note>\n", internaltabs, tech);
+		ast_xml_free_attr(tech);
+	}
+
+	ret = 1;
+
+	for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+		if (!strcasecmp(ast_xml_node_get_name(node), "enumlist")) {
+			xmldoc_parse_enumlist(node, internaltabs, buffer);
+		} else if ((internal_ret = xmldoc_parse_common_elements(node, internaltabs, posttabs, buffer))) {
+			if (internal_ret > ret) {
+				ret = internal_ret;
+			}
+		}
+	}
+	ast_free(internaltabs);
+
+	return ret;
+}
+
+/*! \internal
+ *  \brief Parse an <argument> element from the xml documentation.
+ *  \param fixnode Pointer to the 'argument' xml node.
+ *  \param insideparameter If we are parsing an <argument> inside a <parameter>.
+ *  \param paramtabs pre tabs if we are inside a parameter element.
+ *  \param tabs What to be printed before the argument name.
+ *  \param buffer Output buffer to put values found inside the <argument> element.
+ *  \retval 1 If there is content inside the argument.
+ *  \retval 0 If the argument element is not parsed, or there is no content inside it.
  */
 static int xmldoc_parse_argument(struct ast_xml_node *fixnode, int insideparameter, const char *paramtabs, const char *tabs, struct ast_str **buffer)
 {
@@ -1600,19 +1439,16 @@ static int xmldoc_parse_argument(struct ast_xml_node *fixnode, int insideparamet
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse a <variable> node inside a <variablelist> node.
- *
- * \param node The variable node to parse.
- * \param tabs A string to be appended at the begining of the output that will be stored
- *        in buffer.
- * \param buffer This must be an already created ast_str. It will be used
- *        to store the result (if already has something it will be appended to the current
- *        string).
- *
- * \retval 0 if no data is appended.
- * \retval 1 if data is appended.
+/*! \internal
+ *  \brief Parse a <variable> node inside a <variablelist> node.
+ *  \param node The variable node to parse.
+ *  \param tabs A string to be appended at the begining of the output that will be stored
+ *         in buffer.
+ *  \param buffer This must be an already created ast_str. It will be used
+ *         to store the result (if already has something it will be appended to the current
+ *         string).
+ *  \retval 0 if no data is appended.
+ *  \retval 1 if data is appended.
  */
 static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
 {
@@ -1648,7 +1484,7 @@ static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, st
 		/* Check inside this node for any explanation about its meaning. */
 		if (tmptext) {
 			/* Cleanup text. */
-			xmldoc_string_cleanup(tmptext, &cleanstr, 1, 0);
+			xmldoc_string_cleanup(tmptext, &cleanstr, 1);
 			ast_xml_free_text(tmptext);
 			if (cleanstr && ast_str_strlen(cleanstr) > 0) {
 				ast_str_append(buffer, 0, ":%s", ast_str_buffer(cleanstr));
@@ -1661,19 +1497,16 @@ static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, st
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse a <variablelist> node and put all the output inside 'buffer'.
- *
- * \param node The variablelist node pointer.
- * \param tabs A string to be appended at the begining of the output that will be stored
- *        in buffer.
- * \param buffer This must be an already created ast_str. It will be used
- *        to store the result (if already has something it will be appended to the current
- *        string).
- *
- * \retval 1 If a <variablelist> element is parsed.
- * \retval 0 On error.
+/*! \internal
+ *  \brief Parse a <variablelist> node and put all the output inside 'buffer'.
+ *  \param node The variablelist node pointer.
+ *  \param tabs A string to be appended at the begining of the output that will be stored
+ *         in buffer.
+ *  \param buffer This must be an already created ast_str. It will be used
+ *         to store the result (if already has something it will be appended to the current
+ *         string).
+ *  \retval 1 If a <variablelist> element is parsed.
+ *  \retval 0 On error.
  */
 static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
 {
@@ -1722,14 +1555,13 @@ static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs
 /*!
  * \internal
  * \brief Build seealso information for an item
- *
  * \param node	The seealso node to parse
  *
  * \note This method exists for when you already have the node.  This
  * prevents having to lock the documentation tree twice
  *
- * \retval A malloc'd character pointer to the seealso information of the item
- * \retval NULL on failure
+ * \returns A malloc'd character pointer to the seealso information of the item
+ * \returns NULL on failure
  *
  * \since 11
  */
@@ -1815,15 +1647,12 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *m
 	return output;
 }
 
-/*!
- * \internal
- * \brief Parse a <enum> node.
- *
- * \param fixnode An ast_xml_node pointer to the <enum> node.
- * \param buffer The output buffer.
- *
- * \retval 0 if content is not found inside the enum element (data is not appended to buffer).
- * \retval 1 if content is found and data is appended to buffer.
+/*! \internal
+ *  \brief Parse a <enum> node.
+ *  \brief fixnode An ast_xml_node pointer to the <enum> node.
+ *  \bried buffer The output buffer.
+ *  \retval 0 if content is not found inside the enum element (data is not appended to buffer).
+ *  \retval 1 if content is found and data is appended to buffer.
  */
 static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
 {
@@ -1841,7 +1670,6 @@ static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, str
 		}
 
 		xmldoc_parse_enumlist(node, optiontabs, buffer);
-		xmldoc_parse_parameter(node, optiontabs, buffer);
 	}
 
 	ast_free(optiontabs);
@@ -1849,15 +1677,12 @@ static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, str
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse a <enumlist> node.
- *
- * \param fixnode As ast_xml pointer to the <enumlist> node.
- * \param buffer The ast_str output buffer.
- *
- * \retval 0 if no <enumlist> node was parsed.
- * \retval 1 if a <enumlist> node was parsed.
+/*! \internal
+ *  \brief Parse a <enumlist> node.
+ *  \param fixnode As ast_xml pointer to the <enumlist> node.
+ *  \param buffer The ast_str output buffer.
+ *  \retval 0 if no <enumlist> node was parsed.
+ *  \retval 1 if a <enumlist> node was parsed.
  */
 static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
 {
@@ -1886,17 +1711,14 @@ static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs,
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse an <option> node.
- *
- * \param fixnode An ast_xml pointer to the <option> node.
- * \param tabs A string to be appended at the begining of each line being added to the
- *             buffer string.
- * \param buffer The output buffer.
- *
- * \retval 0 if no option node is parsed.
- * \retval 1 if an option node is parsed.
+/*! \internal
+ *  \brief Parse an <option> node.
+ *  \param fixnode An ast_xml pointer to the <option> node.
+ *  \param tabs A string to be appended at the begining of each line being added to the
+ *              buffer string.
+ *  \param buffer The output buffer.
+ *  \retval 0 if no option node is parsed.
+ *  \retval 1 if an option node is parsed.
  */
 static int xmldoc_parse_option(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
 {
@@ -1933,14 +1755,12 @@ static int xmldoc_parse_option(struct ast_xml_node *fixnode, const char *tabs, s
 	return ret;
 }
 
-/*!
- * \internal
- * \brief Parse an <optionlist> element from the xml documentation.
- *
- * \param fixnode Pointer to the optionlist xml node.
- * \param tabs A string to be appended at the begining of each line being added to the
- *             buffer string.
- * \param buffer Output buffer to put what is inside the optionlist tag.
+/*! \internal
+ *  \brief Parse an <optionlist> element from the xml documentation.
+ *  \param fixnode Pointer to the optionlist xml node.
+ *  \param tabs A string to be appended at the begining of each line being added to the
+ *              buffer string.
+ *  \param buffer Output buffer to put what is inside the optionlist tag.
  */
 static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
 {
@@ -1986,14 +1806,12 @@ static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *ta
 	}
 }
 
-/*!
- * \internal
- * \brief Parse a 'parameter' tag inside a syntax element.
- *
- * \param fixnode A pointer to the 'parameter' xml node.
- * \param tabs A string to be appended at the beginning of each line being printed inside
- *             'buffer'.
- * \param buffer String buffer to put values found inside the parameter element.
+/*! \internal
+ *  \brief Parse a 'parameter' tag inside a syntax element.
+ *  \param fixnode A pointer to the 'parameter' xml node.
+ *  \param tabs A string to be appended at the beginning of each line being printed inside
+ *              'buffer'.
+ *  \param buffer String buffer to put values found inside the parameter element.
  */
 static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
 {
@@ -2066,69 +1884,14 @@ static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tab
 
 /*!
  * \internal
- * \brief Parse an 'info' tag inside an element.
- *
- * \param node A pointer to the 'info' xml node.
- * \param tabs A string to be appended at the beginning of each line being printed
- *             inside 'buffer'
- * \param posttabs Add this string after the content of the <para> element, if one exists
- * \param String buffer to put values found inide the info element.
- *
- * \retval 2 if the information contained a para element, and it returned a value of 2
- * \retval 1 if information was put into the buffer
- * \retval 0 if no information was put into the buffer or error
- */
-static int xmldoc_parse_info(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
-{
-	const char *tech;
-	char *internaltabs;
-	int internal_ret;
-	int ret = 0;
-
-	if (strcasecmp(ast_xml_node_get_name(node), "info")) {
-		return ret;
-	}
-
-	ast_asprintf(&internaltabs, "%s    ", tabs);
-	if (!internaltabs) {
-		return ret;
-	}
-
-	tech = ast_xml_get_attribute(node, "tech");
-	if (tech) {
-		ast_str_append(buffer, 0, "%s<note>Technology: %s</note>\n", internaltabs, tech);
-		ast_xml_free_attr(tech);
-	}
-
-	ret = 1;
-
-	for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-		if (!strcasecmp(ast_xml_node_get_name(node), "enumlist")) {
-			xmldoc_parse_enumlist(node, internaltabs, buffer);
-		} else if (!strcasecmp(ast_xml_node_get_name(node), "parameter")) {
-			xmldoc_parse_parameter(node, internaltabs, buffer);
-		} else if ((internal_ret = xmldoc_parse_common_elements(node, internaltabs, posttabs, buffer))) {
-			if (internal_ret > ret) {
-				ret = internal_ret;
-			}
-		}
-	}
-	ast_free(internaltabs);
-
-	return ret;
-}
-
-/*!
- * \internal
  * \brief Build the arguments for an item
- *
  * \param node	The arguments node to parse
  *
  * \note This method exists for when you already have the node.  This
  * prevents having to lock the documentation tree twice
  *
- * \retval A malloc'd character pointer to the arguments for the item
- * \retval NULL on failure
+ * \returns A malloc'd character pointer to the arguments for the item
+ * \returns NULL on failure
  *
  * \since 11
  */
@@ -2189,16 +1952,13 @@ char *ast_xmldoc_build_arguments(const char *type, const char *name, const char
 	return _ast_xmldoc_build_arguments(node);
 }
 
-/*!
- * \internal
- * \brief Return the string within a node formatted with <para> and <variablelist> elements.
- *
- * \param node Parent node where content resides.
- * \param raw If set, return the node's content without further processing.
- * \param raw_wrap Wrap raw text.
- *
- * \retval NULL on error
- * \retval Node content on success.
+/*! \internal
+ *  \brief Return the string within a node formatted with <para> and <variablelist> elements.
+ *  \param node Parent node where content resides.
+ *  \param raw If set, return the node's content without further processing.
+ *  \param raw_wrap Wrap raw text.
+ *  \retval NULL on error
+ *  \retval Node content on success.
  */
 static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_output, int raw_wrap)
 {
@@ -2210,24 +1970,21 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
 		/* xmldoc_string_cleanup will allocate the ret object */
 		notcleanret = ast_xml_get_text(node);
 		tmpstr = notcleanret;
-		xmldoc_string_cleanup(ast_skip_blanks(notcleanret), &ret, 0, 0);
+		xmldoc_string_cleanup(ast_skip_blanks(notcleanret), &ret, 0);
 		ast_xml_free_text(tmpstr);
 	} else {
 		ret = ast_str_create(128);
+		if (!ret) {
+			return NULL;
+		}
 		for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
-			/* if found, parse children elements. */
+			/* if found, parse a <para> element. */
 			if (xmldoc_parse_common_elements(tmp, "", "\n", &ret)) {
 				continue;
 			}
-			if (xmldoc_parse_variablelist(tmp, "", &ret)) {
-				continue;
-			}
-			if (xmldoc_parse_enumlist(tmp, "    ", &ret)) {
-				continue;
-			}
-			if (xmldoc_parse_specialtags(tmp, "", "", &ret)) {
-				continue;
-			}
+			/* if found, parse a <variablelist> element. */
+			xmldoc_parse_variablelist(tmp, "", &ret);
+			xmldoc_parse_enumlist(tmp, "    ", &ret);
 		}
 		/* remove last '\n' */
 		/* XXX Don't modify ast_str internals manually */
@@ -2240,16 +1997,13 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
 }
 
 /*!
- * \internal
- * \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree node
- *
- * \param node The node to obtain the information from
- * \param var Name of field to return (synopsis, description, etc).
- * \param raw Field only contains text, no other elements inside it.
- *
- * \retval NULL On error.
- * \retval Field text content on success.
- * \since 11
+ *  \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree node
+ *  \param node The node to obtain the information from
+ *  \param var Name of field to return (synopsis, description, etc).
+ *  \param raw Field only contains text, no other elements inside it.
+ *  \retval NULL On error.
+ *  \retval Field text content on success.
+ *  \since 11
  */
 static char *_xmldoc_build_field(struct ast_xml_node *node, const char *var, int raw)
 {
@@ -2263,7 +2017,7 @@ static char *_xmldoc_build_field(struct ast_xml_node *node, const char *var, int
 	}
 
 	formatted = xmldoc_get_formatted(node, raw, raw);
-	if (ast_str_strlen(formatted) > 0) {
+	if (formatted && ast_str_strlen(formatted) > 0) {
 		ret = ast_strdup(ast_str_buffer(formatted));
 	}
 	ast_free(formatted);
@@ -2272,17 +2026,13 @@ static char *_xmldoc_build_field(struct ast_xml_node *node, const char *var, int
 }
 
 /*!
- * \internal
- * \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree
- *
- * \param type Type of element (application, function, ...).
- * \param name Name of element (Dial, Echo, Playback, ...).
- * \param var Name of field to return (synopsis, description, etc).
- * \param module
- * \param raw Field only contains text, no other elements inside it.
- *
- * \retval NULL On error.
- * \retval Field text content on success.
+ *  \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree
+ *  \param type Type of element (application, function, ...).
+ *  \param name Name of element (Dial, Echo, Playback, ...).
+ *  \param var Name of field to return (synopsis, description, etc).
+ *  \param raw Field only contains text, no other elements inside it.
+ *  \retval NULL On error.
+ *  \retval Field text content on success.
  */
 static char *xmldoc_build_field(const char *type, const char *name, const char *module, const char *var, int raw)
 {
@@ -2303,17 +2053,15 @@ static char *xmldoc_build_field(const char *type, const char *name, const char *
 	return _xmldoc_build_field(node, var, raw);
 }
 
-/*!
- * \internal
+/* \internal
  * \brief Build the synopsis for an item
- *
  * \param node The synopsis node
  *
  * \note This method exists for when you already have the node.  This
  * prevents having to lock the documentation tree twice
  *
- * \retval A malloc'd character pointer to the synopsis information
- * \retval NULL on failure
+ * \returns A malloc'd character pointer to the synopsis information
+ * \returns NULL on failure
  * \since 11
  */
 static char *_ast_xmldoc_build_synopsis(struct ast_xml_node *node)
@@ -2329,14 +2077,13 @@ char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *
 /*!
  * \internal
  * \brief Build the descripton for an item
- *
  * \param node	The description node to parse
  *
  * \note This method exists for when you already have the node.  This
  * prevents having to lock the documentation tree twice
  *
- * \retval A malloc'd character pointer to the arguments for the item
- * \retval NULL on failure
+ * \returns A malloc'd character pointer to the arguments for the item
+ * \returns NULL on failure
  * \since 11
  */
 static char *_ast_xmldoc_build_description(struct ast_xml_node *node)
@@ -2349,9 +2096,7 @@ char *ast_xmldoc_build_description(const char *type, const char *name, const cha
 	return xmldoc_build_field(type, name, module, "description", 0);
 }
 
-/*!
- * \internal
- * \brief ast_xml_doc_item ao2 destructor
+/*! \internal \brief ast_xml_doc_item ao2 destructor
  * \since 11
  */
 static void ast_xml_doc_item_destructor(void *obj)
@@ -2369,16 +2114,14 @@ static void ast_xml_doc_item_destructor(void *obj)
 	ast_free(doc->description);
 	ast_string_field_free_memory(doc);
 
-	if (AST_LIST_NEXT(doc, next)) {
-		ao2_ref(AST_LIST_NEXT(doc, next), -1);
-		AST_LIST_NEXT(doc, next) = NULL;
+	if (doc->next) {
+		ao2_ref(doc->next, -1);
+		doc->next = NULL;
 	}
 }
 
-/*!
- * \internal
+/*! \internal
  * \brief Create an ao2 ref counted ast_xml_doc_item
- *
  * \param name The name of the item
  * \param type The item's source type
  * \since 11
@@ -2415,8 +2158,7 @@ ast_xml_doc_item_failure:
 	return NULL;
 }
 
-/*!
- * \internal
+/*! \internal
  * \brief ao2 item hash function for ast_xml_doc_item
  * \since 11
  */
@@ -2427,8 +2169,7 @@ static int ast_xml_doc_item_hash(const void *obj, const int flags)
 	return ast_str_case_hash(name);
 }
 
-/*!
- * \internal
+/*! \internal
  * \brief ao2 item comparison function for ast_xml_doc_item
  * \since 11
  */
@@ -2440,16 +2181,14 @@ static int ast_xml_doc_item_cmp(void *obj, void *arg, int flags)
 	return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
 }
 
-/*!
- * \internal
+/* \internal
  * \brief Build an XML documentation item
- *
  * \param node The root node for the item
  * \param name The name of the item
  * \param type The item's source type
  *
- * \retval NULL on failure
- * \retval An ao2 ref counted object
+ * \returns NULL on failure
+ * \returns An ao2 ref counted object
  * \since 11
  */
 static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_node *node, const char *name, const char *type)
@@ -2464,7 +2203,6 @@ static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_n
 	if (!(item = ast_xml_doc_item_alloc(name, type))) {
 		return NULL;
 	}
-	item->node = node;
 
 	syntax = _ast_xmldoc_build_syntax(node, type, name);
 	seealso = _ast_xmldoc_build_seealso(node);
@@ -2497,246 +2235,10 @@ static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_n
 	return item;
 }
 
-/*!
- * \internal
- * \brief Build the list responses for an item
- *
- * \param manager_action The action node to parse
- *
- * \note This method exists for when you already have the node.  This
- * prevents having to lock the documentation tree twice
- *
- * \retval A list of ast_xml_doc_items
- * \retval NULL on failure
- *
- * \since 13.0.0
- */
-static struct ast_xml_doc_item *xmldoc_build_list_responses(struct ast_xml_node *manager_action)
-{
-	struct ast_xml_node *event;
-	struct ast_xml_node *responses;
-	struct ast_xml_node *list_elements;
-	struct ast_xml_doc_item_list root;
-
-	AST_LIST_HEAD_INIT(&root);
-
-	responses = ast_xml_find_element(ast_xml_node_get_children(manager_action), "responses", NULL, NULL);
-	if (!responses) {
-		return NULL;
-	}
-
-	list_elements = ast_xml_find_element(ast_xml_node_get_children(responses), "list-elements", NULL, NULL);
-	if (!list_elements) {
-		return NULL;
-	}
-
-	/* Iterate over managerEvent nodes */
-	for (event = ast_xml_node_get_children(list_elements); event; event = ast_xml_node_get_next(event)) {
-		struct ast_xml_node *event_instance;
-		const char *name = ast_xml_get_attribute(event, "name");
-		struct ast_xml_doc_item *new_item;
-
-		if (!name || strcmp(ast_xml_node_get_name(event), "managerEvent")) {
-			continue;
-		}
-
-		event_instance = ast_xml_find_element(ast_xml_node_get_children(event),
-			"managerEventInstance", NULL, NULL);
-		new_item = xmldoc_build_documentation_item(event_instance, name, "managerEvent");
-		if (!new_item) {
-			ao2_cleanup(AST_LIST_FIRST(&root));
-			return NULL;
-		}
-
-		AST_LIST_INSERT_TAIL(&root, new_item, next);
-	}
-
-	return AST_LIST_FIRST(&root);
-}
-
-struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module)
-{
-	struct ast_xml_node *node;
-
-	if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
-		return NULL;
-	}
-
-	node = xmldoc_get_node(type, name, module, documentation_language);
-
-	if (!node || !ast_xml_node_get_children(node)) {
-		return NULL;
-	}
-
-	return xmldoc_build_list_responses(node);
-}
-
-/*!
- * \internal
- * \brief Build the final response for an item
- *
- * \param manager_action The action node to parse
- *
- * \note This method exists for when you already have the node.  This
- * prevents having to lock the documentation tree twice
- *
- * \retval An ast_xml_doc_item
- * \retval NULL on failure
- *
- * \since 13.0.0
- */
-static struct ast_xml_doc_item *xmldoc_build_final_response(struct ast_xml_node *manager_action)
-{
-	struct ast_xml_node *responses;
-	struct ast_xml_node *final_response_event;
-	struct ast_xml_node *event_instance;
-
-	responses = ast_xml_find_element(ast_xml_node_get_children(manager_action),
-		"responses", NULL, NULL);
-	if (!responses) {
-		return NULL;
-	}
-
-	final_response_event = ast_xml_find_element(ast_xml_node_get_children(responses),
-		"managerEvent", NULL, NULL);
-	if (!final_response_event) {
-		return NULL;
-	}
-
-	event_instance = ast_xml_find_element(ast_xml_node_get_children(final_response_event),
-		"managerEventInstance", NULL, NULL);
-	if (!event_instance) {
-		return NULL;
-	}
-
-	return xmldoc_build_documentation_item(event_instance,
-		ast_xml_get_attribute(final_response_event, "name"), "managerEvent");
-}
-
-struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module)
-{
-	struct ast_xml_node *node;
-
-	if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
-		return NULL;
-	}
-
-	node = xmldoc_get_node(type, name, module, documentation_language);
-
-	if (!node || !ast_xml_node_get_children(node)) {
-		return NULL;
-	}
-
-	return xmldoc_build_final_response(node);
-}
-
-struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_query(const char *fmt, ...)
-{
-	struct ast_xml_xpath_results *results = NULL;
-	struct documentation_tree *doctree;
-	RAII_VAR(struct ast_str *, xpath_str, ast_str_create(128), ast_free);
-	va_list ap;
-
-	if (!xpath_str) {
-		return NULL;
-	}
-
-	va_start(ap, fmt);
-	ast_str_set_va(&xpath_str, 0, fmt, ap);
-	va_end(ap);
-
-	AST_RWLIST_RDLOCK(&xmldoc_tree);
-	AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
-		if (!(results = ast_xml_query(doctree->doc, ast_str_buffer(xpath_str)))) {
-			continue;
-		}
-		break;
-	}
-	AST_RWLIST_UNLOCK(&xmldoc_tree);
-
-	return results;
-}
-
-static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item_list *root)
-{
-	struct ast_xml_node *iter;
-	struct ast_xml_doc_item *item;
-
-	for (iter = ast_xml_node_get_children(cur); iter; iter = ast_xml_node_get_next(iter)) {
-		const char *iter_name;
-		if (strncasecmp(ast_xml_node_get_name(iter), "config", 6)) {
-			continue;
-		}
-		iter_name = ast_xml_get_attribute(iter, "name");
-		/* Now add all of the child config-related items to the list */
-		if (!(item = xmldoc_build_documentation_item(iter, iter_name, ast_xml_node_get_name(iter)))) {
-			ast_log(LOG_ERROR, "Could not build documentation for '%s:%s'\n", ast_xml_node_get_name(iter), iter_name);
-			ast_xml_free_attr(iter_name);
-			break;
-		}
-		ast_xml_free_attr(iter_name);
-		if (!strcasecmp(ast_xml_node_get_name(iter), "configOption")) {
-			const char *name = ast_xml_get_attribute(cur, "name");
-			ast_string_field_set(item, ref, name);
-			ast_xml_free_attr(name);
-		}
-		AST_LIST_INSERT_TAIL(root, item, next);
-		build_config_docs(iter, root);
-	}
-}
-
-int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item)
-{
-	const char *name;
-	char *syntax;
-	char *seealso;
-	char *arguments;
-	char *synopsis;
-	char *description;
-
-	if (!item || !item->node) {
-		return -1;
-	}
-
-	name = ast_xml_get_attribute(item->node, "name");
-	if (!name) {
-		return -1;
-	}
-
-	syntax = _ast_xmldoc_build_syntax(item->node, item->type, name);
-	seealso = _ast_xmldoc_build_seealso(item->node);
-	arguments = _ast_xmldoc_build_arguments(item->node);
-	synopsis = _ast_xmldoc_build_synopsis(item->node);
-	description = _ast_xmldoc_build_description(item->node);
-
-	if (syntax) {
-		ast_str_set(&item->syntax, 0, "%s", syntax);
-	}
-	if (seealso) {
-		ast_str_set(&item->seealso, 0, "%s", seealso);
-	}
-	if (arguments) {
-		ast_str_set(&item->arguments, 0, "%s", arguments);
-	}
-	if (synopsis) {
-		ast_str_set(&item->synopsis, 0, "%s", synopsis);
-	}
-	if (description) {
-		ast_str_set(&item->description, 0, "%s", description);
-	}
-
-	ast_free(syntax);
-	ast_free(seealso);
-	ast_free(arguments);
-	ast_free(synopsis);
-	ast_free(description);
-	ast_xml_free_attr(name);
-	return 0;
-}
-
 struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 {
 	struct ao2_container *docs;
+	struct ast_xml_doc_item *item = NULL, *root = NULL;
 	struct ast_xml_node *node = NULL, *instance = NULL;
 	struct documentation_tree *doctree;
 	const char *name;
@@ -2755,8 +2257,6 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 		}
 
 		for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-			struct ast_xml_doc_item *item = NULL;
-
 			/* Ignore empty nodes or nodes that aren't of the type requested */
 			if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), type)) {
 				continue;
@@ -2768,10 +2268,6 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 
 			switch (xmldoc_get_syntax_type(type)) {
 			case MANAGER_EVENT_SYNTAX:
-			{
-				struct ast_xml_doc_item_list root;
-
-				AST_LIST_HEAD_INIT(&root);
 				for (instance = ast_xml_node_get_children(node); instance; instance = ast_xml_node_get_next(instance)) {
 					struct ast_xml_doc_item *temp;
 					if (!ast_xml_node_get_children(instance) || strcasecmp(ast_xml_node_get_name(instance), "managerEventInstance")) {
@@ -2781,29 +2277,16 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 					if (!temp) {
 						break;
 					}
-					AST_LIST_INSERT_TAIL(&root, temp, next);
-				}
-				item = AST_LIST_FIRST(&root);
-				break;
-			}
-			case CONFIG_INFO_SYNTAX:
-			{
-				RAII_VAR(const char *, name, ast_xml_get_attribute(node, "name"), ast_xml_free_attr);
-
-				if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
-					break;
-				}
-
-				item = xmldoc_build_documentation_item(node, name, "configInfo");
-				if (item) {
-					struct ast_xml_doc_item_list root;
-
-					AST_LIST_HEAD_INIT(&root);
-					AST_LIST_INSERT_TAIL(&root, item, next);
-					build_config_docs(node, &root);
+					if (!item) {
+						item = temp;
+						root = item;
+					} else {
+						item->next = temp;
+						item = temp;
+					}
 				}
+				item = root;
 				break;
-			}
 			default:
 				item = xmldoc_build_documentation_item(node, name, type);
 			}
@@ -2812,6 +2295,7 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 			if (item) {
 				ao2_link(docs, item);
 				ao2_t_ref(item, -1, "Dispose of creation ref");
+				item = NULL;
 			}
 		}
 	}
@@ -2820,9 +2304,6 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 	return docs;
 }
 
-int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item);
-
-
 #if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
 static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbuf)
 {
@@ -2866,47 +2347,11 @@ static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbu
 }
 #endif
 
-static char *handle_dump_docs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct documentation_tree *doctree;
-	FILE *f;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "xmldoc dump";
-		e->usage =
-			"Usage: xmldoc dump <filename>\n"
-			"  Dump XML documentation to a file\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-	if (!(f = fopen(a->argv[2], "w"))) {
-		ast_log(LOG_ERROR, "Could not open file '%s': %s\n", a->argv[2], strerror(errno));
-		return CLI_FAILURE;
-	}
-	AST_RWLIST_RDLOCK(&xmldoc_tree);
-	AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
-		ast_xml_doc_dump_file(f, doctree->doc);
-	}
-	AST_RWLIST_UNLOCK(&xmldoc_tree);
-	fclose(f);
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_dump_xmldocs = AST_CLI_DEFINE(handle_dump_docs, "Dump the XML docs to the specified file");
-
 /*! \brief Close and unload XML documentation. */
 static void xmldoc_unload_documentation(void)
 {
 	struct documentation_tree *doctree;
 
-	ast_cli_unregister(&cli_dump_xmldocs);
-
 	AST_RWLIST_WRLOCK(&xmldoc_tree);
 	while ((doctree = AST_RWLIST_REMOVE_HEAD(&xmldoc_tree, entry))) {
 		ast_free(doctree->filename);
@@ -2950,9 +2395,8 @@ int ast_xmldoc_load_documentation(void)
 	/* initialize the XML library. */
 	ast_xml_init();
 
-	ast_cli_register(&cli_dump_xmldocs);
 	/* register function to be run when asterisk finish. */
-	ast_register_atexit(xmldoc_unload_documentation);
+	ast_register_cleanup(xmldoc_unload_documentation);
 
 	globbuf.gl_offs = 0;    /* slots to reserve in gl_pathv */
 
@@ -2969,7 +2413,7 @@ int ast_xmldoc_load_documentation(void)
 	globret = glob(xmlpattern, MY_GLOB_FLAGS, NULL, &globbuf);
 #endif
 
-	ast_debug(3, "gl_pathc %zu\n", globbuf.gl_pathc);
+	ast_debug(3, "gl_pathc %zu\n", (size_t)globbuf.gl_pathc);
 	if (globret == GLOB_NOSPACE) {
 		ast_log(LOG_WARNING, "XML load failure, glob expansion of pattern '%s' failed: Not enough memory\n", xmlpattern);
 		ast_free(xmlpattern);
diff --git a/makeopts.in b/makeopts.in
index a0faaee..6b44011 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -21,7 +21,6 @@ COMPRESS=@COMPRESS@
 BASENAME=@BASENAME@
 SHELL=@SHELL@
 LN=@LN@
-DOXYGEN=@DOXYGEN@
 DOT=@DOT@
 STRIP=@STRIP@
 WGET=@WGET@
@@ -60,7 +59,6 @@ PTHREAD_LIBS=@PTHREAD_LIBS@
 
 CONFIG_CFLAGS=@CONFIG_CFLAGS@
 CONFIG_LDFLAGS=@CONFIG_LDFLAGS@
-CONFIG_SIGNED_CHAR=@CONFIG_SIGNED_CHAR@
 
 GNU_LD=@GNU_LD@
 WEAKREF=@PBX_WEAKREF@
@@ -109,6 +107,9 @@ AST_TRAMPOLINES=@AST_TRAMPOLINES@
 AST_NO_STRICT_OVERFLOW=@AST_NO_STRICT_OVERFLOW@
 AST_SHADOW_WARNINGS=@AST_SHADOW_WARNINGS@
 AST_NESTED_FUNCTIONS=@AST_NESTED_FUNCTIONS@
+AST_CLANG_BLOCKS=@AST_CLANG_BLOCKS@
+AST_CLANG_BLOCKS_LIBS=@AST_CLANG_BLOCKS_LIBS@
+C_COMPILER_FAMILY=@AST_C_COMPILER_FAMILY@
 AST_RPATH=@AST_RPATH@
 AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
 AST_MARCH_NATIVE=@AST_MARCH_NATIVE@
@@ -171,12 +172,6 @@ IODBC_LIB=@IODBC_LIB@
 JACK_INCLUDE=@JACK_INCLUDE@
 JACK_LIB=@JACK_LIB@
 
-JANSSON_INCLUDE=@JANSSON_INCLUDE@
-JANSSON_LIB=@JANSSON_LIB@
-
-URIPARSER_INCLUDE=@URIPARSER_INCLUDE@
-URIPARSER_LIB=@URIPARSER_LIB@
-
 LDAP_INCLUDE=@LDAP_INCLUDE@
 LDAP_LIB=@LDAP_LIB@
 
@@ -211,9 +206,6 @@ NEWT_LIB=@NEWT_LIB@
 OGG_INCLUDE=@OGG_INCLUDE@
 OGG_LIB=@OGG_LIB@
 
-OPUS_INCLUDE=@OPUS_INCLUDE@
-OPUS_LIB=@OPUS_LIB@
-
 OSPTK_INCLUDE=@OSPTK_INCLUDE@
 OSPTK_LIB=@OSPTK_LIB@
 
@@ -225,9 +217,6 @@ OSS_LIB=@OSS_LIB@ @FFMPEG_LIB@ @SDL_LIB@ @SDL_IMAGE_LIB@ @X11_LIB@
 PGSQL_INCLUDE=@PGSQL_INCLUDE@
 PGSQL_LIB=@PGSQL_LIB@
 
-PJPROJECT_INCLUDE=@PJPROJECT_INCLUDE@
-PJPROJECT_LIB=@PJPROJECT_LIB@
-
 POPT_INCLUDE=@POPT_INCLUDE@
 POPT_LIB=@POPT_LIB@
 
@@ -288,9 +277,6 @@ SRTP_INCLUDE=@SRTP_INCLUDE@
 OPENSSL_INCLUDE=@OPENSSL_INCLUDE@
 OPENSSL_LIB=@OPENSSL_LIB@
 
-CRYPT_INCLUDE=@CRYPT_INCLUDE@
-CRYPT_LIB=@CRYPT_LIB@
-
 CRYPTO_INCLUDE=@CRYPTO_INCLUDE@
 CRYPTO_LIB=@CRYPTO_LIB@
 
@@ -309,7 +295,6 @@ VORBIS_LIB=@VORBIS_LIB@
 VPB_INCLUDE=@VPB_INCLUDE@
 VPB_LIB=@VPB_LIB@
 
-HAVE_DAHDI=@PBX_DAHDI@
 DAHDI_INCLUDE=@DAHDI_INCLUDE@
 
 ZLIB_INCLUDE=@ZLIB_INCLUDE@
@@ -337,9 +322,6 @@ TERMCAP_DIR=@TERMCAP_DIR@
 LIBXML2_INCLUDE=@LIBXML2_INCLUDE@
 LIBXML2_LIB=@LIBXML2_LIB@
 
-LIBXSLT_INCLUDE=@LIBXSLT_INCLUDE@
-LIBXSLT_LIB=@LIBXSLT_LIB@
-
 TINFO_INCLUDE=@TINFO_INCLUDE@
 TINFO_LIB=@TINFO_LIB@
 TINFO_DIR=@TINFO_DIR@
diff --git a/menuselect/.gitignore b/menuselect/.gitignore
new file mode 100644
index 0000000..0818d7b
--- /dev/null
+++ b/menuselect/.gitignore
@@ -0,0 +1,7 @@
+autoconfig.h
+cmenuselect
+config.log
+config.status
+menuselect
+nmenuselect
+gmenuselect
diff --git a/menuselect/configure b/menuselect/configure
index 5081371..648091e 100755
--- a/menuselect/configure
+++ b/menuselect/configure
@@ -3227,7 +3227,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -3299,7 +3299,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -3371,7 +3371,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-static void __attribute__((weakref("foo"))) *test(void *muffin, ...) {return (void *) 0;}
+static void __attribute__((weakref("foo"))) *test(void *muffin, ...) ;
 int
 main ()
 {
@@ -3445,7 +3445,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 else
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-static void __attribute__((weakref("foo"))) *test(void *muffin, ...) {return (void *) 0;}
+static void __attribute__((weakref("foo"))) *test(void *muffin, ...) ;
 int
 main ()
 {
diff --git a/menuselect/configure.ac b/menuselect/configure.ac
index df305d5..5989f5c 100644
--- a/menuselect/configure.ac
+++ b/menuselect/configure.ac
@@ -15,7 +15,7 @@ AC_CONFIG_SRCDIR([menuselect.c])
 AC_CONFIG_HEADER(autoconfig.h)
 
 AC_COPYRIGHT("Menuselect")
-AC_REVISION($Revision: 418850 $)
+AC_REVISION($Revision$)
 
 AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
diff --git a/mkinstalldirs b/mkinstalldirs
index 86809c6..6b3b5fc 100755
--- a/mkinstalldirs
+++ b/mkinstalldirs
@@ -4,7 +4,7 @@
 # Created: 1993-05-16
 # Public domain
 
-# $Id: mkinstalldirs 25628 2006-05-08 16:02:42Z kpfleming $
+# $Id$
 
 errstatus=0
 
diff --git a/pbx/Makefile b/pbx/Makefile
index 0afc4bc..d3b560b 100644
--- a/pbx/Makefile
+++ b/pbx/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for PBX modules
 #
@@ -24,7 +24,7 @@ ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
 endif
 
 clean::
-	rm -f ael/*.o ael/*.i
+	rm -f ael/*.o ael/*.i ael/*.gcda ael/*.gcno
 
 dundi-parser.o: dundi-parser.h
 dundi-parser.o: _ASTCFLAGS+=-I.
diff --git a/pbx/dundi-parser.c b/pbx/dundi-parser.c
index d29cbc0..c178fd6 100644
--- a/pbx/dundi-parser.c
+++ b/pbx/dundi-parser.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413589 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -61,7 +61,7 @@ char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
 			*s = '\0';
 	} else {
 		for (x=0;x<6;x++) {
-			sprintf(s, "%02X", (unsigned)eid->eid[x]);
+			sprintf(s, "%02hhX", (unsigned char)eid->eid[x]);
 			s += 2;
 		}
 	}
@@ -320,7 +320,7 @@ static void dump_encrypted(char *output, int maxlen, void *value, int len)
 	if ((len > 16) && !(len % 16)) {
 		/* Build up IV */
 		for (x=0;x<16;x++) {
-			snprintf(iv + (x << 1), 3, "%02x", (unsigned)((unsigned char *)value)[x]);
+			snprintf(iv + (x << 1), 3, "%02hhx", ((unsigned char *)value)[x]);
 		}
 		snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
 	} else
@@ -334,7 +334,7 @@ static void dump_raw(char *output, int maxlen, void *value, int len)
 	output[maxlen - 1] = '\0';
 	strcpy(output, "[ ");
 	for (x=0;x<len;x++) {
-		snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", (unsigned)u[x]);
+		snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02hhx ", u[x]);
 	}
 	strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
 }
@@ -464,7 +464,7 @@ void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int
 	} else {
 		class = commands[(int)(fhi->cmdresp & 0x3f)];
 	}
-	snprintf(subclass2, (int)sizeof(subclass2), "%02x", (unsigned)fhi->cmdflags);
+	snprintf(subclass2, (int)sizeof(subclass2), "%02hhx", (unsigned char)fhi->cmdflags);
 	subclass = subclass2;
 	snprintf(tmp, (int)sizeof(tmp), 
 		"%s-Frame -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c
index 6323947..5c42732 100644
--- a/pbx/pbx_ael.c
+++ b/pbx/pbx_ael.c
@@ -30,7 +30,7 @@
 #include "asterisk.h"
 
 #if !defined(STANDALONE)
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #endif
 
 #include <ctype.h>
@@ -161,7 +161,7 @@ static int pbx_load_module(void)
 	
 	struct pval *parse_tree;
 
-	ast_debug(1, "Starting AEL load process.\n");
+	ast_log(LOG_NOTICE, "Starting AEL load process.\n");
 	if (config[0] == '/')
 		rfilename = (char *)config;
 	else {
@@ -174,25 +174,25 @@ static int pbx_load_module(void)
 	}
 	
 	parse_tree = ael2_parse(rfilename, &errs);
-	ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
+	ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
 	ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
 	if (errs == 0 && sem_err == 0) {
-		ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
+		ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
 		local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
 		if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
 			ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
 			destroy_pval(parse_tree); /* free up the memory */
 			return AST_MODULE_LOAD_DECLINE;
 		}
-		ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
+		ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
 		
 		ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
 		local_table = NULL; /* it's the dialplan global now */
 		local_contexts = NULL;
-		ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
+		ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
 		for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
 			ast_context_verify_includes(con);
-		ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
+		ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
 	} else {
 		ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
 		destroy_pval(parse_tree); /* free up the memory */
@@ -297,7 +297,6 @@ int ael_external_load_module(void)
 #endif
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index 1aceb96..65dabae 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -27,62 +27,9 @@
 	<support_level>core</support_level>
  ***/
 
-/*** DOCUMENTATION
-	<manager name="DialplanExtensionAdd" language="en_US">
-		<synopsis>
-			Add an extension to the dialplan
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Context" required="true">
-				<para>Context where the extension will be created. The context will
-				be created if it does not already exist.</para>
-			</parameter>
-			<parameter name="Extension" required="true">
-				<para>Name of the extension that will be created (may include callerid match by separating
-				with '/')</para>
-			</parameter>
-			<parameter name="Priority" required="true">
-				<para>Priority being added to this extension. Must be either <literal>hint</literal> or a
-				numerical value.</para>
-			</parameter>
-			<parameter name="Application" required="true">
-				<para>The application to use for this extension at the requested priority</para>
-			</parameter>
-			<parameter name="ApplicationData" required="false">
-				<para>Arguments to the application.</para>
-			</parameter>
-			<parameter name="Replace" required="false">
-				<para>If set to 'yes', '1', 'true' or any of the other values we evaluate as true, then
-				if an extension already exists at the requested context, extension, and priority it will
-				be overwritten. Otherwise, the existing extension will remain and the action will fail.
-				</para>
-			</parameter>
-		</syntax>
-	</manager>
-	<manager name="DialplanExtensionRemove" language="en_US">
-		<synopsis>
-			Remove an extension from the dialplan
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Context" required="true">
-				<para>Context of the extension being removed</para>
-			</parameter>
-			<parameter name="Extension" required="true">
-				<para>Name of the extension being removed (may include callerid match by separating with '/')</para>
-			</parameter>
-			<parameter name="Priority" required="false">
-				<para>If provided, only remove this priority from the extension instead of all
-				priorities in the extension.</para>
-			</parameter>
-		</syntax>
-	</manager>
- ***/
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427276 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 
@@ -133,8 +80,6 @@ static char *complete_dialplan_remove_context(struct ast_cli_args *);
 
 static char *handle_cli_dialplan_remove_context(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct ast_context *con;
-
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "dialplan remove context";
@@ -150,16 +95,11 @@ static char *handle_cli_dialplan_remove_context(struct ast_cli_entry *e, int cmd
 		return CLI_SHOWUSAGE;
 	}
 
-	con = ast_context_find(a->argv[3]);
-
-	if (!con) {
-		ast_cli(a->fd, "There is no such context as '%s'\n",
-                        a->argv[3]);
-                return CLI_SUCCESS;
+	if (ast_context_destroy_by_name(a->argv[3], NULL)) {
+		ast_cli(a->fd, "There is no such context as '%s'\n", a->argv[3]);
+		return CLI_SUCCESS;
 	} else {
-		ast_context_destroy(con, registrar);
-		ast_cli(a->fd, "Removing context '%s'\n",
-			a->argv[3]);
+		ast_cli(a->fd, "Removed context '%s'\n", a->argv[3]);
 		return CLI_SUCCESS;
 	}
 }
@@ -485,54 +425,6 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c
 	return ret;
 }
 
-static int manager_dialplan_extension_remove(struct mansession *s, const struct message *m)
-{
-	const char *context = astman_get_header(m, "Context");
-	const char *extension = astman_get_header(m, "Extension");
-	const char *priority = astman_get_header(m, "Priority");
-
-	int ipriority;
-	char *exten;
-	char *cidmatch = NULL;
-
-	if (ast_strlen_zero(context) || ast_strlen_zero(extension)) {
-		astman_send_error(s, m, "Context and Extension must be provided "
-			"for DialplanExtensionRemove");
-		return 0;
-	}
-
-	exten = ast_strdupa(extension);
-
-	if (strchr(exten, '/')) {
-		cidmatch = exten;
-		strsep(&cidmatch, "/");
-	}
-
-	if (ast_strlen_zero(priority)) {
-		ipriority = 0;
-	} else if (!strcmp("hint", priority)) {
-		ipriority = PRIORITY_HINT;
-	} else if ((sscanf(priority, "%30d", &ipriority) != 1) || ipriority <= 0) {
-		astman_send_error(s, m, "The priority specified was invalid.");
-		return 0;
-	}
-
-	if (!ast_context_remove_extension_callerid(context, exten, ipriority,
-			/* Do not substitute S_OR; it is not the same thing */
-			!ast_strlen_zero(cidmatch) ? cidmatch : (ipriority ? "" : NULL),
-			!ast_strlen_zero(cidmatch) ? 1 : 0, registrar)) {
-		if (ipriority) {
-			astman_send_ack(s, m, "Removed the requested priority from the extension");
-		} else {
-			astman_send_ack(s, m, "Removed the requested extension");
-		}
-	} else {
-		astman_send_error(s, m, "Failed to remove requested extension");
-	}
-
-	return 0;
-}
-
 static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
 {
 	char *ret = NULL;
@@ -956,7 +848,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a
 					const char *el = ast_get_extension_label(p);
 					char label[128] = "";
 					char *appdata = ast_get_extension_app_data(p);
-					char *escaped;
+
+					int escaped_len = (!ast_strlen_zero(appdata)) ? 2 * strlen(appdata) + 1 : 1;
+					char escaped[escaped_len];
 
 					if (ast_get_extension_matchcid(p)) {
 						sep = "/";
@@ -970,12 +864,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a
 					}
 
 					if (!ast_strlen_zero(appdata)) {
-						int escaped_len = 2 * strlen(appdata) + 1;
-						char escaped[escaped_len];
-
 						ast_escape_semicolons(appdata, escaped, escaped_len);
 					} else {
-						escaped = "";
+						escaped[0] = '\0';
 					}
 
 					fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
@@ -1173,88 +1064,6 @@ static char *handle_cli_dialplan_add_extension(struct ast_cli_entry *e, int cmd,
 	return CLI_SUCCESS;
 }
 
-static int manager_dialplan_extension_add(struct mansession *s, const struct message *m)
-{
-	const char *context = astman_get_header(m, "Context");
-	const char *extension = astman_get_header(m, "Extension");
-	const char *priority = astman_get_header(m, "Priority");
-	const char *application = astman_get_header(m, "Application");
-	const char *application_data = astman_get_header(m, "ApplicationData");
-	int replace = ast_true(astman_get_header(m, "Replace"));
-	int ipriority;
-	char *exten;
-	char *cidmatch = NULL;
-	struct ast_context *add_context;
-
-	if (ast_strlen_zero(context) || ast_strlen_zero(extension) ||
-			ast_strlen_zero(priority) || ast_strlen_zero(application)) {
-		astman_send_error(s, m, "Context, Extension, Priority, and "
-			"Application must be defined for DialplanExtensionAdd.");
-		return 0;
-	}
-
-	/* Priority conversion/validation */
-	if (!strcmp(priority, "hint")) {
-		ipriority = PRIORITY_HINT;
-	} else if ((sscanf(priority, "%30d", &ipriority) != 1) || (ipriority < 0)) {
-		astman_send_error(s, m, "The priority specified was invalid.");
-		return 0;
-	}
-
-	/* Split extension from cidmatch */
-	exten = ast_strdupa(extension);
-
-	if (strchr(exten, '/')) {
-		cidmatch = exten;
-		strsep(&cidmatch, "/");
-	}
-
-	if (ast_wrlock_contexts()) {
-		astman_send_error(s, m, "Failed to lock contexts list. Try again later.");
-		return 0;
-	}
-
-	add_context = ast_context_find_or_create(NULL, NULL, context, registrar);
-	if (!add_context) {
-		astman_send_error(s, m, "Could not find or create context specified "
-			"for the extension.");
-		ast_unlock_contexts();
-		return 0;
-	}
-
-	if (ast_add_extension2(add_context, replace, exten, ipriority, NULL, cidmatch,
-			application, ast_strdup(application_data), ast_free_ptr, registrar)) {
-		ast_unlock_contexts();
-		switch (errno) {
-		case ENOMEM:
-			astman_send_error(s, m, "Out of Memory");
-			break;
-
-		case EBUSY:
-			astman_send_error(s, m, "Failed to lock context(s) list");
-			break;
-
-		case ENOENT:
-			astman_send_error(s, m, "Context does not exist");
-			break;
-
-		case EEXIST:
-			astman_send_error(s, m, "That extension and priority already exist at that context");
-			break;
-
-		default:
-			astman_send_error(s, m, "Failed to add extension");
-			break;
-		}
-		return 0;
-	}
-	ast_unlock_contexts();
-
-	astman_send_ack(s, m, "Added requested extension");
-
-	return 0;
-}
-
 static char *complete_dialplan_remove_context(struct ast_cli_args *a)
 {
 	struct ast_context *c = NULL;
@@ -1593,9 +1402,6 @@ static struct ast_cli_entry cli_pbx_config[] = {
 static struct ast_cli_entry cli_dialplan_save =
 	AST_CLI_DEFINE(handle_cli_dialplan_save, "Save dialplan");
 
-#define AMI_EXTENSION_ADD "DialplanExtensionAdd"
-#define AMI_EXTENSION_REMOVE "DialplanExtensionRemove"
-
 /*!
  * Standard module functions ...
  */
@@ -1607,8 +1413,6 @@ static int unload_module(void)
 		ast_free(overrideswitch_config);
 	}
 	ast_cli_unregister_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config));
-	ast_manager_unregister(AMI_EXTENSION_ADD);
-	ast_manager_unregister(AMI_EXTENSION_REMOVE);
 	ast_context_destroy(NULL, registrar);
 	return 0;
 }
@@ -2075,22 +1879,10 @@ static int pbx_load_module(void)
 
 static int load_module(void)
 {
-	int res;
-
 	if (static_config && !write_protect_config)
 		ast_cli_register(&cli_dialplan_save);
 	ast_cli_register_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config));
 
-	res = ast_manager_register_xml_core(AMI_EXTENSION_ADD,
-		EVENT_FLAG_SYSTEM, manager_dialplan_extension_add);
-	res |= ast_manager_register_xml_core(AMI_EXTENSION_REMOVE,
-		EVENT_FLAG_SYSTEM, manager_dialplan_extension_remove);
-
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
 	if (pbx_load_module())
 		return AST_MODULE_LOAD_DECLINE;
 
@@ -2105,7 +1897,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index 8807dd0..f2bb06c 100644
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -21,15 +21,6 @@
  * \brief Distributed Universal Number Discovery (DUNDi)
  */
 
-/*! \li \ref pbx_dundi.c uses configuration file \ref dundi.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page dundi.conf dundi.conf
- * \verbinclude dundi.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>zlib</depend>
 	<use type="external">crypto</use>
@@ -38,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/network.h"
 #include <sys/ioctl.h>
@@ -5052,7 +5043,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Number Discovery (DUNDi)",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/pbx/pbx_loopback.c b/pbx/pbx_loopback.c
index cc2140d..bd87b1f 100644
--- a/pbx/pbx_loopback.c
+++ b/pbx/pbx_loopback.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428789 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/logger.h"
diff --git a/pbx/pbx_lua.c b/pbx/pbx_lua.c
index 3ff482f..70dfd81 100644
--- a/pbx/pbx_lua.c
+++ b/pbx/pbx_lua.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420149 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
@@ -422,6 +422,7 @@ static void lua_update_registry(lua_State *L, const char *context, const char *e
  * The value on the top of the stack is popped and used as the name.
  *
  * \param L the lua_State to use
+ * \param name the name of the variable
  */
 static void lua_push_variable_table(lua_State *L)
 {
@@ -1673,7 +1674,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Lua PBX Switch",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c
index 4a9d221..3808483 100644
--- a/pbx/pbx_realtime.c
+++ b/pbx/pbx_realtime.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <signal.h>
 
@@ -52,7 +52,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
 #include "asterisk/astdb.h"
 #include "asterisk/app.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/stasis_channels.h"
 
 #define MODE_MATCH 		0
 #define MODE_MATCHMORE 	1
@@ -206,7 +205,7 @@ static struct ast_variable *realtime_switch_common(const char *table, const char
 					match = ast_extension_match(cat, exten);
 				}
 				if (match) {
-					var = ast_category_detach_variables(ast_category_get(cfg, cat, NULL));
+					var = ast_category_detach_variables(ast_category_get(cfg, cat));
 					break;
 				}
 				cat = ast_category_browse(cfg, cat);
@@ -303,7 +302,7 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
 	struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
 
 	if (var) {
-		char *appdata_tmp = "";
+		char *tmp="";
 		char *app = NULL;
 		struct ast_variable *v;
 
@@ -311,7 +310,31 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
 			if (!strcasecmp(v->name, "app"))
 				app = ast_strdupa(v->value);
 			else if (!strcasecmp(v->name, "appdata")) {
-				appdata_tmp = ast_strdupa(v->value);
+				if (ast_compat_pbx_realtime) {
+					char *ptr;
+					int in = 0;
+					tmp = ast_alloca(strlen(v->value) * 2 + 1);
+					for (ptr = tmp; *v->value; v->value++) {
+						if (*v->value == ',') {
+							*ptr++ = '\\';
+							*ptr++ = ',';
+						} else if (*v->value == '|' && !in) {
+							*ptr++ = ',';
+						} else {
+							*ptr++ = *v->value;
+						}
+
+						/* Don't escape '|', meaning 'or', inside expressions ($[ ]) */
+						if (v->value[0] == '[' && v->value[-1] == '$') {
+							in++;
+						} else if (v->value[0] == ']' && in) {
+							in--;
+						}
+					}
+					*ptr = '\0';
+				} else {
+					tmp = ast_strdupa(v->value);
+				}
 			}
 		}
 		ast_variables_destroy(var);
@@ -322,33 +345,25 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
 				char tmp1[80];
 				char tmp2[80];
 				char tmp3[EXT_DATA_SIZE];
-				RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-				RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 
 				appdata[0] = 0; /* just in case the substitute var func isn't called */
-				if(!ast_strlen_zero(appdata_tmp))
-					pbx_substitute_variables_helper(chan, appdata_tmp, appdata, sizeof(appdata) - 1);
+				if(!ast_strlen_zero(tmp))
+					pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
 				ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
 						ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan),
 						 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
 						 term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
 						 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
-				if (ast_channel_snapshot_type()) {
-					ast_channel_lock(chan);
-					snapshot = ast_channel_snapshot_create(chan);
-					ast_channel_unlock(chan);
-				}
-				if (snapshot) {
-					/* pbx_exec sets application name and data, but we don't want to log
-					 * every exec. Just update the snapshot here instead.
-					 */
-					ast_string_field_set(snapshot, appl, app);
-					ast_string_field_set(snapshot, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
-					msg = stasis_message_create(ast_channel_snapshot_type(), snapshot);
-					if (msg) {
-						stasis_publish(ast_channel_topic(chan), msg);
-					}
-				}
+				manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
+							  "Channel: %s\r\n"
+							  "Context: %s\r\n"
+							  "Extension: %s\r\n"
+							  "Priority: %d\r\n"
+							  "Application: %s\r\n"
+							  "AppData: %s\r\n"
+							  "Uniqueid: %s\r\n",
+							  ast_channel_name(chan), ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", ast_channel_uniqueid(chan));
+				
 				res = pbx_exec(chan, a, appdata);
 			} else
 				ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
@@ -405,5 +420,4 @@ static int load_module(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Realtime Switch");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");
diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c
index b26765f..119a450 100644
--- a/pbx/pbx_spool.c
+++ b/pbx/pbx_spool.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 #include <time.h>
@@ -53,8 +53,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
 #include "asterisk/options.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cache.h"
 
 /*
  * pbx_spool is similar in spirit to qcall, but with substantially enhanced functionality...
@@ -102,6 +100,14 @@ struct outgoing {
 };
 
 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
+struct direntry {
+	AST_LIST_ENTRY(direntry) list;
+	time_t mtime;
+	char name[0];
+};
+
+static AST_LIST_HEAD_STATIC(dirlist, direntry);
+
 static void queue_file(const char *filename, time_t when);
 #endif
 
@@ -110,7 +116,7 @@ static void free_outgoing(struct outgoing *o)
 	if (o->vars) {
 		ast_variables_destroy(o->vars);
 	}
-	ao2_cleanup(o->capabilities);
+	o->capabilities = ast_format_cap_destroy(o->capabilities);
 	ast_string_field_free_memory(o);
 	ast_free(o);
 }
@@ -118,6 +124,7 @@ static void free_outgoing(struct outgoing *o)
 static struct outgoing *new_outgoing(const char *fn)
 {
 	struct outgoing *o;
+	struct ast_format tmpfmt;
 
 	o = ast_calloc(1, sizeof(*o));
 	if (!o) {
@@ -145,12 +152,12 @@ static struct outgoing *new_outgoing(const char *fn)
 		return NULL;
 	}
 
-	o->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	o->capabilities = ast_format_cap_alloc_nolock();
 	if (!o->capabilities) {
 		free_outgoing(o);
 		return NULL;
 	}
-	ast_format_cap_append(o->capabilities, ast_format_slin, 0);
+	ast_format_cap_add(o->capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 
 	return o;
 }
@@ -227,7 +234,7 @@ static int apply_outgoing(struct outgoing *o, FILE *f)
 				o->maxretries = 0;
 			}
 		} else if (!strcasecmp(buf, "codecs")) {
-			ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1);
+			ast_parse_allow_disallow(NULL, o->capabilities, c, 1);
 		} else if (!strcasecmp(buf, "context")) {
 			ast_string_field_set(o, context, c);
 		} else if (!strcasecmp(buf, "extension")) {
@@ -323,6 +330,10 @@ static int remove_from_queue(struct outgoing *o, const char *status)
 	char newfn[256];
 	const char *bname;
 
+#if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
+	struct direntry *cur;
+#endif
+
 	if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) {
 		struct stat current_file_status;
 
@@ -333,6 +344,19 @@ static int remove_from_queue(struct outgoing *o, const char *status)
 		}
 	}
 
+#if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
+	AST_LIST_LOCK(&dirlist);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&dirlist, cur, list) {
+		if (!strcmp(cur->name, o->fn)) {
+			AST_LIST_REMOVE_CURRENT(list);
+			ast_free(cur);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&dirlist);
+#endif
+
 	if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) {
 		unlink(o->fn);
 		return 0;
@@ -376,14 +400,14 @@ static void *attempt_thread(void *data)
 		ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
 		res = ast_pbx_outgoing_app(o->tech, o->capabilities, o->dest, o->waittime * 1000,
 			o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name,
-			o->vars, o->account, NULL, NULL);
+			o->vars, o->account, NULL);
 		o->vars = NULL;
 	} else {
 		ast_verb(3, "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
 		res = ast_pbx_outgoing_exten(o->tech, o->capabilities, o->dest,
 			o->waittime * 1000, o->context, o->exten, o->priority, &reason,
 			2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL,
-			ast_test_flag(&o->options, SPOOL_FLAG_EARLY_MEDIA), NULL);
+			ast_test_flag(&o->options, SPOOL_FLAG_EARLY_MEDIA));
 		o->vars = NULL;
 	}
 	if (res) {
@@ -488,14 +512,6 @@ static int scan_service(const char *fn, time_t now)
 	return 0;
 }
 
-#if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
-struct direntry {
-	AST_LIST_ENTRY(direntry) list;
-	time_t mtime;
-	char name[0];
-};
-
-static AST_LIST_HEAD_STATIC(dirlist, direntry);
 
 #if defined(HAVE_INOTIFY)
 /* Only one thread is accessing this list, so no lock is necessary */
@@ -503,6 +519,8 @@ static AST_LIST_HEAD_NOLOCK_STATIC(createlist, direntry);
 static AST_LIST_HEAD_NOLOCK_STATIC(openlist, direntry);
 #endif
 
+#if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
+
 static void queue_file(const char *filename, time_t when)
 {
 	struct stat st;
diff --git a/res/Makefile b/res/Makefile
index 4038634..c0b4821 100644
--- a/res/Makefile
+++ b/res/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for resource modules
 #
@@ -9,7 +9,7 @@
 # the GNU General Public License
 #
 
--include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps
+-include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps $(ASTTOPDIR)/build_tools/menuselect-deps
 
 MODULE_PREFIX=res
 MENUSELECT_CATEGORY=RES
@@ -33,6 +33,9 @@ ael/ael_lex.o: _ASTCFLAGS+=-I. -Iael -Wno-unused
 
 ael/ael.tab.o: ael/ael.tab.c ael/ael.tab.h ../include/asterisk/ael_structs.h
 ael/ael.tab.o: _ASTCFLAGS+=-I. -Iael -DYYENABLE_NLS=0
+	ifneq ($(AST_CLANG_BLOCKS),)
+		_ASTCFLAGS+=-Wno-parentheses-equality
+	endif
 
 $(if $(filter res_ais,$(EMBEDDED_MODS)),modules.link,res_ais.so): ais/clm.o ais/evt.o
 ais/clm.o ais/evt.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ais)
@@ -43,12 +46,6 @@ snmp/agent.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_snmp)
 $(if $(filter res_ael_share,$(EMBEDDED_MODS)),modules.link,res_ael_share.so): ael/ael_lex.o ael/ael.tab.o ael/pval.o
 ael/ael_lex.o ael/ael.tab.o ael/pval.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ael_share)
 
-$(if $(filter res_pjsip,$(EMBEDDED_MODS)),modules.link,res_pjsip.so): $(subst .c,.o,$(wildcard res_pjsip/*.c))
-$(subst .c,.o,$(wildcard res_pjsip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_pjsip)
-
-$(if $(filter res_stasis,$(EMBEDDED_MODS)),modules.link,res_stasis.so): $(subst .c,.o,$(wildcard stasis/*.c))
-$(subst .c,.o,$(wildcard stasis/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_stasis)
-
 ifneq ($(findstring REBUILD_PARSERS,$(MENUSELECT_CFLAGS)),)
 ael/ael_lex.c: ael/ael.flex
 else
@@ -73,21 +70,31 @@ endif
 ael/pval.o: ael/pval.c
 
 clean::
-	rm -f snmp/*.[oi] ael/*.[oi] ais/*.[oi] ari/*.[oi]
-	rm -f res_pjsip/*.[oi] stasis/*.[oi]
-	rm -f parking/*.o parking/*.i stasis_recording/*.[oi]
+	@if [ -f pjproject/build.mak ]; then $(MAKE) -C pjproject realclean; fi
+	rm -f snmp/*.o snmp/*.i ael/*.o ael/*.i ais/*.o ais/*.i snmp/*.gcda snmp/*.gcno ael/*.gcda ael/*.gcno
+
+dist-clean:: distclean
+distclean::
+	rm -f pjproject/build.mak
 
-$(if $(filter res_parking,$(EMBEDDED_MODS)),modules.link,res_parking.so): $(subst .c,.o,$(wildcard parking/*.c))
-$(subst .c,.o,$(wildcard parking/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_parking)
+pjproject/build.mak: pjproject/aconfigure
+	(cd pjproject && CFLAGS="-fPIC" ./configure --build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM) --disable-floating-point --disable-sound --disable-oss --disable-speex-aec --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-speex-codec --disable-ilbc-codec --disable-g711-codec)
 
-res_ari.so: ari/cli.o ari/config.o ari/ari_websockets.o
-ari/cli.o ari/config.o ari/ari_websockets.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari)
+ifneq ($(findstring $(MAKECMDGOALS),all),)
+-include pjproject/build.mak
+endif
+
+.PHONY: FORCE
+FORCE:
 
-res_ari_model.so: ari/ari_model_validators.o
-ari/ari_model_validators.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_model)
+$(PJ_LIB_FILES): FORCE
+	$(MAKE) -C $(patsubst %/lib/,%,$(dir $@))/build/ ../lib/$(notdir $@)
 
-res_stasis_recording.so: stasis_recording/stored.o
-stasis_recording/stored.o:  _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_stasis_recording)
+ifeq ($(subst 1:0,1,$(UUID)), 1)
+res_rtp_asterisk.o: $(PJ_LIB_FILES)
+res_rtp_asterisk.o: _ASTCFLAGS+=-DUSE_PJPROJECT
+res_rtp_asterisk.o: _ASTCFLAGS+=$(PJ_CFLAGS)
+res_rtp_asterisk.so: _ASTLDFLAGS+=$(PJ_LDFLAGS)
+res_rtp_asterisk.so: LIBS+=$(PJ_LDLIBS)
+endif
 
-# Dependencies for res_ari_*.so are generated, so they're in this file
-include ari.make
diff --git a/res/ael/.gitignore b/res/ael/.gitignore
new file mode 100644
index 0000000..f39b612
--- /dev/null
+++ b/res/ael/.gitignore
@@ -0,0 +1 @@
+ael.output
diff --git a/res/ael/ael.flex b/res/ael/ael.flex
index 0275e16..dab6ac0 100644
--- a/res/ael/ael.flex
+++ b/res/ael/ael.flex
@@ -69,7 +69,7 @@
 
 %{
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410994 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -885,7 +885,7 @@ static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf,
 				ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
 			}			
 			buffer[stats.st_size] = 0;
-			ast_debug(1, "  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
+			ast_log(LOG_NOTICE,"  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
 			fclose(in1);
 			if (include_stack[include_stack_index].fname) {
 			   	free(include_stack[include_stack_index].fname);
diff --git a/res/ael/ael.tab.c b/res/ael/ael.tab.c
index 6594f29..c838d79 100644
--- a/res/ael/ael.tab.c
+++ b/res/ael/ael.tab.c
@@ -101,7 +101,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/res/ael/ael.y b/res/ael/ael.y
index 8eaf8dd..27e04c5 100644
--- a/res/ael/ael.y
+++ b/res/ael/ael.y
@@ -24,7 +24,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 272260 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c
index e91e63f..e255fab 100644
--- a/res/ael/ael_lex.c
+++ b/res/ael/ael_lex.c
@@ -828,7 +828,7 @@ static yyconst flex_int16_t yy_chk[1073] =
  */
 #line 71 "ael.flex"
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410994 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -3458,7 +3458,7 @@ static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf,
 				ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
 			}			
 			buffer[stats.st_size] = 0;
-			ast_debug(1, "  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
+			ast_log(LOG_NOTICE,"  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
 			fclose(in1);
 			if (include_stack[include_stack_index].fname) {
 			   	free(include_stack[include_stack_index].fname);
diff --git a/res/ael/pval.c b/res/ael/pval.c
index 819f9f0..c0da0f0 100644
--- a/res/ael/pval.c
+++ b/res/ael/pval.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418019 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <stdlib.h>
@@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418019 $")
 #endif
 #include "asterisk/utils.h"
 
+extern struct ast_flags ast_compat;
 extern int localized_pbx_load_module(void);
 
 static char expr_output[2096];
@@ -3383,7 +3384,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 					for (first = 1; first >= 0; first--) {
 						switch_set = new_prio();
 						switch_set->type = AEL_APPCALL;
-						switch_set->app = strdup("MSet");
+						if (!ast_compat_app_set) {
+							switch_set->app = strdup("MSet");
+						} else {
+							switch_set->app = strdup("Set");
+						}
 						/* Are we likely inside a gosub subroutine? */
 						if (!strcmp(mother_exten->name, "~~s~~") && first) {
 							/* If we're not actually within a gosub, this will fail, but the
@@ -3408,7 +3413,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 					for (first = 1; first >= 0; first--) {
 						switch_set = new_prio();
 						switch_set->type = AEL_APPCALL;
-						switch_set->app = strdup("MSet");
+						if (!ast_compat_app_set) {
+							switch_set->app = strdup("MSet");
+						} else {
+							switch_set->app = strdup("Set");
+						}
 						/* Are we likely inside a gosub subroutine? */
 						if (!strcmp(exten->name, "~~s~~")) {
 							/* If we're not actually within a gosub, this will fail, but the
@@ -3444,7 +3453,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 			pr = new_prio();
 			pr->type = AEL_APPCALL;
 			snprintf(buf1, BUF_SIZE, "%s=$[%s]", p->u1.str, p->u2.val);
-			pr->app = strdup("MSet");
+			if (!ast_compat_app_set) {
+				pr->app = strdup("MSet");
+			} else {
+				pr->app = strdup("Set");
+			}
 			remove_spaces_before_equals(buf1);
 			pr->appargs = strdup(buf1);
 			pr->origin = p;
@@ -3455,7 +3468,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 			pr = new_prio();
 			pr->type = AEL_APPCALL;
 			snprintf(buf1, BUF_SIZE, "LOCAL(%s)=$[%s]", p->u1.str, p->u2.val);
-			pr->app = strdup("MSet");
+			if (!ast_compat_app_set) {
+				pr->app = strdup("MSet");
+			} else {
+				pr->app = strdup("Set");
+			}
 			remove_spaces_before_equals(buf1);
 			pr->appargs = strdup(buf1);
 			pr->origin = p;
@@ -3518,7 +3535,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 			for_test->goto_false = for_end;
 			for_loop->type = AEL_CONTROL1; /* simple goto */
 			for_end->type = AEL_APPCALL;
-			for_init->app = strdup("MSet");
+			if (!ast_compat_app_set) {
+				for_init->app = strdup("MSet");
+			} else {
+				for_init->app = strdup("Set");
+			}
 			
 			strcpy(buf2,p->u1.for_init);
 			remove_spaces_before_equals(buf2);
@@ -3579,7 +3600,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement,
 				strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
 				strcat(buf2,"]");
 				for_inc->appargs = strdup(buf2);
-				for_inc->app = strdup("MSet");
+				if (!ast_compat_app_set) {
+					for_inc->app = strdup("MSet");
+				} else {
+					for_inc->app = strdup("Set");
+				}
 			} else {
 				strp2 = p->u3.for_inc;
 				while (*strp2 && isspace(*strp2))
@@ -4464,7 +4489,11 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo
 				/* for each arg, set up a "Set" command */
 				struct ael_priority *np2 = new_prio();
 				np2->type = AEL_APPCALL;
-				np2->app = strdup("MSet");
+				if (!ast_compat_app_set) {
+					np2->app = strdup("MSet");
+				} else {
+					np2->app = strdup("Set");
+				}
 				snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
 				remove_spaces_before_equals(buf);
 				np2->appargs = strdup(buf);
diff --git a/res/ari.make b/res/ari.make
deleted file mode 100644
index f9a87d3..0000000
--- a/res/ari.make
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Asterisk -- A telephony toolkit for Linux.
-#
-# Generated Makefile for res_ari dependencies.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License
-#
-
-#
-# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-# !!!!!                               DO NOT EDIT                        !!!!!
-# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-# This file is generated by a template. Please see the original template at
-# rest-api-templates/ari.make.mustache
-#
-
-res_ari_asterisk.so: ari/resource_asterisk.o
-
-ari/resource_asterisk.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_asterisk)
-
-res_ari_endpoints.so: ari/resource_endpoints.o
-
-ari/resource_endpoints.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_endpoints)
-
-res_ari_channels.so: ari/resource_channels.o
-
-ari/resource_channels.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_channels)
-
-res_ari_bridges.so: ari/resource_bridges.o
-
-ari/resource_bridges.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_bridges)
-
-res_ari_recordings.so: ari/resource_recordings.o
-
-ari/resource_recordings.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_recordings)
-
-res_ari_sounds.so: ari/resource_sounds.o
-
-ari/resource_sounds.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_sounds)
-
-res_ari_playbacks.so: ari/resource_playbacks.o
-
-ari/resource_playbacks.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_playbacks)
-
-res_ari_device_states.so: ari/resource_device_states.o
-
-ari/resource_device_states.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_device_states)
-
-res_ari_mailboxes.so: ari/resource_mailboxes.o
-
-ari/resource_mailboxes.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_mailboxes)
-
-res_ari_events.so: ari/resource_events.o
-
-ari/resource_events.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_events)
-
-res_ari_applications.so: ari/resource_applications.o
-
-ari/resource_applications.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_applications)
-
diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c
deleted file mode 100644
index c471eee..0000000
--- a/res/ari/ari_model_validators.c
+++ /dev/null
@@ -1,5198 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - Build validators for ARI model objects.
- */
-
- /*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_model_validators.h.mustache
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "ari_model_validators.h"
-
-int ast_ari_validate_asterisk_info(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("build", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_build_info(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI AsteriskInfo field build failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("config", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_config_info(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI AsteriskInfo field config failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("status", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_status_info(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI AsteriskInfo field status failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("system", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_system_info(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI AsteriskInfo field system failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI AsteriskInfo has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_asterisk_info_fn(void)
-{
-	return ast_ari_validate_asterisk_info;
-}
-
-int ast_ari_validate_build_info(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_date = 0;
-	int has_kernel = 0;
-	int has_machine = 0;
-	int has_options = 0;
-	int has_os = 0;
-	int has_user = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("date", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_date = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field date failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("kernel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_kernel = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field kernel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("machine", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_machine = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field machine failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("options", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_options = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field options failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("os", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_os = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field os failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("user", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_user = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BuildInfo field user failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BuildInfo has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_date) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field date\n");
-		res = 0;
-	}
-
-	if (!has_kernel) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field kernel\n");
-		res = 0;
-	}
-
-	if (!has_machine) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field machine\n");
-		res = 0;
-	}
-
-	if (!has_options) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field options\n");
-		res = 0;
-	}
-
-	if (!has_os) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field os\n");
-		res = 0;
-	}
-
-	if (!has_user) {
-		ast_log(LOG_ERROR, "ARI BuildInfo missing required field user\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_build_info_fn(void)
-{
-	return ast_ari_validate_build_info;
-}
-
-int ast_ari_validate_config_info(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_default_language = 0;
-	int has_name = 0;
-	int has_setid = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("default_language", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_default_language = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field default_language failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("max_channels", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field max_channels failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("max_load", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_double(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field max_load failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("max_open_files", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field max_open_files failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("setid", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_setid = 1;
-			prop_is_valid = ast_ari_validate_set_id(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ConfigInfo field setid failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ConfigInfo has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_default_language) {
-		ast_log(LOG_ERROR, "ARI ConfigInfo missing required field default_language\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI ConfigInfo missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_setid) {
-		ast_log(LOG_ERROR, "ARI ConfigInfo missing required field setid\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_config_info_fn(void)
-{
-	return ast_ari_validate_config_info;
-}
-
-int ast_ari_validate_set_id(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_group = 0;
-	int has_user = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("group", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_group = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI SetId field group failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("user", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_user = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI SetId field user failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI SetId has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_group) {
-		ast_log(LOG_ERROR, "ARI SetId missing required field group\n");
-		res = 0;
-	}
-
-	if (!has_user) {
-		ast_log(LOG_ERROR, "ARI SetId missing required field user\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_set_id_fn(void)
-{
-	return ast_ari_validate_set_id;
-}
-
-int ast_ari_validate_status_info(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_last_reload_time = 0;
-	int has_startup_time = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("last_reload_time", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_last_reload_time = 1;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StatusInfo field last_reload_time failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("startup_time", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_startup_time = 1;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StatusInfo field startup_time failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI StatusInfo has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_last_reload_time) {
-		ast_log(LOG_ERROR, "ARI StatusInfo missing required field last_reload_time\n");
-		res = 0;
-	}
-
-	if (!has_startup_time) {
-		ast_log(LOG_ERROR, "ARI StatusInfo missing required field startup_time\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_status_info_fn(void)
-{
-	return ast_ari_validate_status_info;
-}
-
-int ast_ari_validate_system_info(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_entity_id = 0;
-	int has_version = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("entity_id", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_entity_id = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI SystemInfo field entity_id failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("version", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_version = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI SystemInfo field version failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI SystemInfo has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_entity_id) {
-		ast_log(LOG_ERROR, "ARI SystemInfo missing required field entity_id\n");
-		res = 0;
-	}
-
-	if (!has_version) {
-		ast_log(LOG_ERROR, "ARI SystemInfo missing required field version\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_system_info_fn(void)
-{
-	return ast_ari_validate_system_info;
-}
-
-int ast_ari_validate_variable(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_value = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_value = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Variable field value failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Variable has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_value) {
-		ast_log(LOG_ERROR, "ARI Variable missing required field value\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_variable_fn(void)
-{
-	return ast_ari_validate_variable;
-}
-
-int ast_ari_validate_endpoint(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_channel_ids = 0;
-	int has_resource = 0;
-	int has_technology = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("channel_ids", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel_ids = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Endpoint field channel_ids failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("resource", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_resource = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Endpoint field resource failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Endpoint field state failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_technology = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Endpoint field technology failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Endpoint has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_channel_ids) {
-		ast_log(LOG_ERROR, "ARI Endpoint missing required field channel_ids\n");
-		res = 0;
-	}
-
-	if (!has_resource) {
-		ast_log(LOG_ERROR, "ARI Endpoint missing required field resource\n");
-		res = 0;
-	}
-
-	if (!has_technology) {
-		ast_log(LOG_ERROR, "ARI Endpoint missing required field technology\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_endpoint_fn(void)
-{
-	return ast_ari_validate_endpoint;
-}
-
-int ast_ari_validate_text_message(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_body = 0;
-	int has_from = 0;
-	int has_to = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("body", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_body = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessage field body failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("from", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_from = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessage field from failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("to", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_to = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessage field to failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("variables", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_text_message_variable);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessage field variables failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI TextMessage has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_body) {
-		ast_log(LOG_ERROR, "ARI TextMessage missing required field body\n");
-		res = 0;
-	}
-
-	if (!has_from) {
-		ast_log(LOG_ERROR, "ARI TextMessage missing required field from\n");
-		res = 0;
-	}
-
-	if (!has_to) {
-		ast_log(LOG_ERROR, "ARI TextMessage missing required field to\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_text_message_fn(void)
-{
-	return ast_ari_validate_text_message;
-}
-
-int ast_ari_validate_text_message_variable(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_key = 0;
-	int has_value = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("key", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_key = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageVariable field key failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_value = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageVariable field value failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI TextMessageVariable has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_key) {
-		ast_log(LOG_ERROR, "ARI TextMessageVariable missing required field key\n");
-		res = 0;
-	}
-
-	if (!has_value) {
-		ast_log(LOG_ERROR, "ARI TextMessageVariable missing required field value\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_text_message_variable_fn(void)
-{
-	return ast_ari_validate_text_message_variable;
-}
-
-int ast_ari_validate_caller_id(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_name = 0;
-	int has_number = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI CallerID field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("number", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_number = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI CallerID field number failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI CallerID has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI CallerID missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_number) {
-		ast_log(LOG_ERROR, "ARI CallerID missing required field number\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_caller_id_fn(void)
-{
-	return ast_ari_validate_caller_id;
-}
-
-int ast_ari_validate_channel(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_accountcode = 0;
-	int has_caller = 0;
-	int has_connected = 0;
-	int has_creationtime = 0;
-	int has_dialplan = 0;
-	int has_id = 0;
-	int has_name = 0;
-	int has_state = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("accountcode", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_accountcode = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field accountcode failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("caller", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_caller = 1;
-			prop_is_valid = ast_ari_validate_caller_id(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field caller failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_connected = 1;
-			prop_is_valid = ast_ari_validate_caller_id(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field connected failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("creationtime", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_creationtime = 1;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field creationtime failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("dialplan", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_dialplan = 1;
-			prop_is_valid = ast_ari_validate_dialplan_cep(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field dialplan failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_id = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field id failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_state = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Channel field state failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Channel has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_accountcode) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field accountcode\n");
-		res = 0;
-	}
-
-	if (!has_caller) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field caller\n");
-		res = 0;
-	}
-
-	if (!has_connected) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field connected\n");
-		res = 0;
-	}
-
-	if (!has_creationtime) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field creationtime\n");
-		res = 0;
-	}
-
-	if (!has_dialplan) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field dialplan\n");
-		res = 0;
-	}
-
-	if (!has_id) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field id\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_state) {
-		ast_log(LOG_ERROR, "ARI Channel missing required field state\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_fn(void)
-{
-	return ast_ari_validate_channel;
-}
-
-int ast_ari_validate_dialed(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		{
-			ast_log(LOG_ERROR,
-				"ARI Dialed has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_dialed_fn(void)
-{
-	return ast_ari_validate_dialed;
-}
-
-int ast_ari_validate_dialplan_cep(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_context = 0;
-	int has_exten = 0;
-	int has_priority = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("context", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_context = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DialplanCEP field context failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("exten", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_exten = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DialplanCEP field exten failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("priority", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_priority = 1;
-			prop_is_valid = ast_ari_validate_long(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DialplanCEP field priority failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI DialplanCEP has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_context) {
-		ast_log(LOG_ERROR, "ARI DialplanCEP missing required field context\n");
-		res = 0;
-	}
-
-	if (!has_exten) {
-		ast_log(LOG_ERROR, "ARI DialplanCEP missing required field exten\n");
-		res = 0;
-	}
-
-	if (!has_priority) {
-		ast_log(LOG_ERROR, "ARI DialplanCEP missing required field priority\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_dialplan_cep_fn(void)
-{
-	return ast_ari_validate_dialplan_cep;
-}
-
-int ast_ari_validate_bridge(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_bridge_class = 0;
-	int has_bridge_type = 0;
-	int has_channels = 0;
-	int has_creator = 0;
-	int has_id = 0;
-	int has_name = 0;
-	int has_technology = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("bridge_class", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge_class = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field bridge_class failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge_type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field bridge_type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channels", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channels = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field channels failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("creator", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_creator = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field creator failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_id = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field id failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_technology = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Bridge field technology failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Bridge has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_bridge_class) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_class\n");
-		res = 0;
-	}
-
-	if (!has_bridge_type) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_type\n");
-		res = 0;
-	}
-
-	if (!has_channels) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field channels\n");
-		res = 0;
-	}
-
-	if (!has_creator) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field creator\n");
-		res = 0;
-	}
-
-	if (!has_id) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field id\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_technology) {
-		ast_log(LOG_ERROR, "ARI Bridge missing required field technology\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_fn(void)
-{
-	return ast_ari_validate_bridge;
-}
-
-int ast_ari_validate_live_recording(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_format = 0;
-	int has_name = 0;
-	int has_state = 0;
-	int has_target_uri = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field cause failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("duration", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field duration failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_format = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field format failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("silence_duration", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field silence_duration failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_state = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field state failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("talking_duration", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field talking_duration failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("target_uri", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_target_uri = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI LiveRecording field target_uri failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI LiveRecording has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_format) {
-		ast_log(LOG_ERROR, "ARI LiveRecording missing required field format\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI LiveRecording missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_state) {
-		ast_log(LOG_ERROR, "ARI LiveRecording missing required field state\n");
-		res = 0;
-	}
-
-	if (!has_target_uri) {
-		ast_log(LOG_ERROR, "ARI LiveRecording missing required field target_uri\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_live_recording_fn(void)
-{
-	return ast_ari_validate_live_recording;
-}
-
-int ast_ari_validate_stored_recording(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_format = 0;
-	int has_name = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_format = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StoredRecording field format failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StoredRecording field name failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI StoredRecording has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_format) {
-		ast_log(LOG_ERROR, "ARI StoredRecording missing required field format\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI StoredRecording missing required field name\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_stored_recording_fn(void)
-{
-	return ast_ari_validate_stored_recording;
-}
-
-int ast_ari_validate_format_lang_pair(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_format = 0;
-	int has_language = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_format = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI FormatLangPair field format failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_language = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI FormatLangPair field language failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI FormatLangPair has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_format) {
-		ast_log(LOG_ERROR, "ARI FormatLangPair missing required field format\n");
-		res = 0;
-	}
-
-	if (!has_language) {
-		ast_log(LOG_ERROR, "ARI FormatLangPair missing required field language\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_format_lang_pair_fn(void)
-{
-	return ast_ari_validate_format_lang_pair;
-}
-
-int ast_ari_validate_sound(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_formats = 0;
-	int has_id = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("formats", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_formats = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_format_lang_pair);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Sound field formats failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_id = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Sound field id failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("text", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Sound field text failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Sound has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_formats) {
-		ast_log(LOG_ERROR, "ARI Sound missing required field formats\n");
-		res = 0;
-	}
-
-	if (!has_id) {
-		ast_log(LOG_ERROR, "ARI Sound missing required field id\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_sound_fn(void)
-{
-	return ast_ari_validate_sound;
-}
-
-int ast_ari_validate_playback(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_id = 0;
-	int has_media_uri = 0;
-	int has_state = 0;
-	int has_target_uri = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_id = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Playback field id failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Playback field language failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("media_uri", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_media_uri = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Playback field media_uri failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_state = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Playback field state failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("target_uri", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_target_uri = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Playback field target_uri failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Playback has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_id) {
-		ast_log(LOG_ERROR, "ARI Playback missing required field id\n");
-		res = 0;
-	}
-
-	if (!has_media_uri) {
-		ast_log(LOG_ERROR, "ARI Playback missing required field media_uri\n");
-		res = 0;
-	}
-
-	if (!has_state) {
-		ast_log(LOG_ERROR, "ARI Playback missing required field state\n");
-		res = 0;
-	}
-
-	if (!has_target_uri) {
-		ast_log(LOG_ERROR, "ARI Playback missing required field target_uri\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_playback_fn(void)
-{
-	return ast_ari_validate_playback;
-}
-
-int ast_ari_validate_device_state(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_name = 0;
-	int has_state = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceState field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_state = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceState field state failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI DeviceState has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI DeviceState missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_state) {
-		ast_log(LOG_ERROR, "ARI DeviceState missing required field state\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_device_state_fn(void)
-{
-	return ast_ari_validate_device_state;
-}
-
-int ast_ari_validate_mailbox(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_name = 0;
-	int has_new_messages = 0;
-	int has_old_messages = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Mailbox field name failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("new_messages", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_new_messages = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Mailbox field new_messages failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("old_messages", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_old_messages = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Mailbox field old_messages failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Mailbox has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI Mailbox missing required field name\n");
-		res = 0;
-	}
-
-	if (!has_new_messages) {
-		ast_log(LOG_ERROR, "ARI Mailbox missing required field new_messages\n");
-		res = 0;
-	}
-
-	if (!has_old_messages) {
-		ast_log(LOG_ERROR, "ARI Mailbox missing required field old_messages\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_mailbox_fn(void)
-{
-	return ast_ari_validate_mailbox;
-}
-
-int ast_ari_validate_application_replaced(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ApplicationReplaced field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ApplicationReplaced field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ApplicationReplaced field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ApplicationReplaced has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field application\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_application_replaced_fn(void)
-{
-	return ast_ari_validate_application_replaced;
-}
-
-int ast_ari_validate_bridge_attended_transfer(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_destination_type = 0;
-	int has_is_external = 0;
-	int has_result = 0;
-	int has_transferer_first_leg = 0;
-	int has_transferer_second_leg = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_link_first_leg", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_link_first_leg failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_link_second_leg", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_link_second_leg failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_threeway_bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_threeway_bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_threeway_channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_threeway_channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("destination_type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_destination_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field destination_type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("is_external", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_is_external = 1;
-			prop_is_valid = ast_ari_validate_boolean(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field is_external failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("replace_channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field replace_channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("result", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_result = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field result failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transfer_target", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transfer_target failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferee", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transferee failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferer_first_leg", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_transferer_first_leg = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transferer_first_leg failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferer_first_leg_bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transferer_first_leg_bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferer_second_leg", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_transferer_second_leg = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transferer_second_leg failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferer_second_leg_bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer field transferer_second_leg_bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BridgeAttendedTransfer has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_destination_type) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field destination_type\n");
-		res = 0;
-	}
-
-	if (!has_is_external) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field is_external\n");
-		res = 0;
-	}
-
-	if (!has_result) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field result\n");
-		res = 0;
-	}
-
-	if (!has_transferer_first_leg) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field transferer_first_leg\n");
-		res = 0;
-	}
-
-	if (!has_transferer_second_leg) {
-		ast_log(LOG_ERROR, "ARI BridgeAttendedTransfer missing required field transferer_second_leg\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_attended_transfer_fn(void)
-{
-	return ast_ari_validate_bridge_attended_transfer;
-}
-
-int ast_ari_validate_bridge_blind_transfer(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-	int has_context = 0;
-	int has_exten = 0;
-	int has_is_external = 0;
-	int has_result = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("context", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_context = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field context failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("exten", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_exten = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field exten failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("is_external", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_is_external = 1;
-			prop_is_valid = ast_ari_validate_boolean(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field is_external failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("replace_channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field replace_channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("result", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_result = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field result failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("transferee", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeBlindTransfer field transferee failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BridgeBlindTransfer has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field channel\n");
-		res = 0;
-	}
-
-	if (!has_context) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field context\n");
-		res = 0;
-	}
-
-	if (!has_exten) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field exten\n");
-		res = 0;
-	}
-
-	if (!has_is_external) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field is_external\n");
-		res = 0;
-	}
-
-	if (!has_result) {
-		ast_log(LOG_ERROR, "ARI BridgeBlindTransfer missing required field result\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_blind_transfer_fn(void)
-{
-	return ast_ari_validate_bridge_blind_transfer;
-}
-
-int ast_ari_validate_bridge_created(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_bridge = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeCreated field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeCreated field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeCreated field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeCreated field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BridgeCreated has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI BridgeCreated missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI BridgeCreated missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_bridge) {
-		ast_log(LOG_ERROR, "ARI BridgeCreated missing required field bridge\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_created_fn(void)
-{
-	return ast_ari_validate_bridge_created;
-}
-
-int ast_ari_validate_bridge_destroyed(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_bridge = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeDestroyed field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeDestroyed field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeDestroyed field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeDestroyed field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BridgeDestroyed has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_bridge) {
-		ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field bridge\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_destroyed_fn(void)
-{
-	return ast_ari_validate_bridge_destroyed;
-}
-
-int ast_ari_validate_bridge_merged(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_bridge = 0;
-	int has_bridge_from = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeMerged field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeMerged field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeMerged field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeMerged field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge_from", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge_from = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI BridgeMerged field bridge_from failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI BridgeMerged has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI BridgeMerged missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI BridgeMerged missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_bridge) {
-		ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge\n");
-		res = 0;
-	}
-
-	if (!has_bridge_from) {
-		ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge_from\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_bridge_merged_fn(void)
-{
-	return ast_ari_validate_bridge_merged;
-}
-
-int ast_ari_validate_channel_caller_id(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_caller_presentation = 0;
-	int has_caller_presentation_txt = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("caller_presentation", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_caller_presentation = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("caller_presentation_txt", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_caller_presentation_txt = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation_txt failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCallerId field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelCallerId has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_caller_presentation) {
-		ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation\n");
-		res = 0;
-	}
-
-	if (!has_caller_presentation_txt) {
-		ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation_txt\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_caller_id_fn(void)
-{
-	return ast_ari_validate_channel_caller_id;
-}
-
-int ast_ari_validate_channel_connected_line(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelConnectedLine field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelConnectedLine field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelConnectedLine field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelConnectedLine field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelConnectedLine has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelConnectedLine missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelConnectedLine missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelConnectedLine missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_connected_line_fn(void)
-{
-	return ast_ari_validate_channel_connected_line;
-}
-
-int ast_ari_validate_channel_created(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCreated field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCreated field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCreated field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelCreated field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelCreated has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelCreated missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelCreated missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelCreated missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_created_fn(void)
-{
-	return ast_ari_validate_channel_created;
-}
-
-int ast_ari_validate_channel_destroyed(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_cause = 0;
-	int has_cause_txt = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_cause = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("cause_txt", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_cause_txt = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause_txt failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDestroyed field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelDestroyed has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_cause) {
-		ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause\n");
-		res = 0;
-	}
-
-	if (!has_cause_txt) {
-		ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause_txt\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_destroyed_fn(void)
-{
-	return ast_ari_validate_channel_destroyed;
-}
-
-int ast_ari_validate_channel_dialplan(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-	int has_dialplan_app = 0;
-	int has_dialplan_app_data = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("dialplan_app", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_dialplan_app = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("dialplan_app_data", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_dialplan_app_data = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app_data failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelDialplan has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field channel\n");
-		res = 0;
-	}
-
-	if (!has_dialplan_app) {
-		ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app\n");
-		res = 0;
-	}
-
-	if (!has_dialplan_app_data) {
-		ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app_data\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_dialplan_fn(void)
-{
-	return ast_ari_validate_channel_dialplan;
-}
-
-int ast_ari_validate_channel_dtmf_received(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-	int has_digit = 0;
-	int has_duration_ms = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("digit", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_digit = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field digit failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("duration_ms", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_duration_ms = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field duration_ms failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelDtmfReceived has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field channel\n");
-		res = 0;
-	}
-
-	if (!has_digit) {
-		ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field digit\n");
-		res = 0;
-	}
-
-	if (!has_duration_ms) {
-		ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field duration_ms\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_dtmf_received_fn(void)
-{
-	return ast_ari_validate_channel_dtmf_received;
-}
-
-int ast_ari_validate_channel_entered_bridge(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_bridge = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelEnteredBridge has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_bridge) {
-		ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field bridge\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_entered_bridge_fn(void)
-{
-	return ast_ari_validate_channel_entered_bridge;
-}
-
-int ast_ari_validate_channel_hangup_request(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field cause failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("soft", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_boolean(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelHangupRequest field soft failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelHangupRequest has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_hangup_request_fn(void)
-{
-	return ast_ari_validate_channel_hangup_request;
-}
-
-int ast_ari_validate_channel_left_bridge(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_bridge = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelLeftBridge field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelLeftBridge field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelLeftBridge field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge = 1;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelLeftBridge field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelLeftBridge field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelLeftBridge has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_bridge) {
-		ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field bridge\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_left_bridge_fn(void)
-{
-	return ast_ari_validate_channel_left_bridge;
-}
-
-int ast_ari_validate_channel_state_change(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelStateChange field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelStateChange field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelStateChange field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelStateChange field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelStateChange has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_state_change_fn(void)
-{
-	return ast_ari_validate_channel_state_change;
-}
-
-int ast_ari_validate_channel_talking_finished(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-	int has_duration = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingFinished field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingFinished field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingFinished field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingFinished field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("duration", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_duration = 1;
-			prop_is_valid = ast_ari_validate_int(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingFinished field duration failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelTalkingFinished has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingFinished missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingFinished missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingFinished missing required field channel\n");
-		res = 0;
-	}
-
-	if (!has_duration) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingFinished missing required field duration\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_talking_finished_fn(void)
-{
-	return ast_ari_validate_channel_talking_finished;
-}
-
-int ast_ari_validate_channel_talking_started(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingStarted field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingStarted field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingStarted field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelTalkingStarted field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelTalkingStarted has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingStarted missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingStarted missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI ChannelTalkingStarted missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_talking_started_fn(void)
-{
-	return ast_ari_validate_channel_talking_started;
-}
-
-int ast_ari_validate_channel_userevent(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_eventname = 0;
-	int has_userevent = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_bridge(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field bridge failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_endpoint(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field endpoint failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("eventname", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_eventname = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field eventname failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("userevent", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_userevent = 1;
-			prop_is_valid = ast_ari_validate_object(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelUserevent field userevent failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelUserevent has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_eventname) {
-		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field eventname\n");
-		res = 0;
-	}
-
-	if (!has_userevent) {
-		ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field userevent\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_userevent_fn(void)
-{
-	return ast_ari_validate_channel_userevent;
-}
-
-int ast_ari_validate_channel_varset(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_value = 0;
-	int has_variable = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_value = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field value failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("variable", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_variable = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI ChannelVarset field variable failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI ChannelVarset has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI ChannelVarset missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI ChannelVarset missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_value) {
-		ast_log(LOG_ERROR, "ARI ChannelVarset missing required field value\n");
-		res = 0;
-	}
-
-	if (!has_variable) {
-		ast_log(LOG_ERROR, "ARI ChannelVarset missing required field variable\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_channel_varset_fn(void)
-{
-	return ast_ari_validate_channel_varset;
-}
-
-int ast_ari_validate_device_state_changed(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_device_state = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceStateChanged field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceStateChanged field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceStateChanged field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("device_state", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_device_state = 1;
-			prop_is_valid = ast_ari_validate_device_state(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI DeviceStateChanged field device_state failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI DeviceStateChanged has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI DeviceStateChanged missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI DeviceStateChanged missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_device_state) {
-		ast_log(LOG_ERROR, "ARI DeviceStateChanged missing required field device_state\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_device_state_changed_fn(void)
-{
-	return ast_ari_validate_device_state_changed;
-}
-
-int ast_ari_validate_dial(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_dialstatus = 0;
-	int has_peer = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("caller", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field caller failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("dialstatus", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_dialstatus = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field dialstatus failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("dialstring", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field dialstring failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("forward", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field forward failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("forwarded", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field forwarded failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("peer", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_peer = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Dial field peer failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Dial has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI Dial missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI Dial missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_dialstatus) {
-		ast_log(LOG_ERROR, "ARI Dial missing required field dialstatus\n");
-		res = 0;
-	}
-
-	if (!has_peer) {
-		ast_log(LOG_ERROR, "ARI Dial missing required field peer\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_dial_fn(void)
-{
-	return ast_ari_validate_dial;
-}
-
-int ast_ari_validate_endpoint_state_change(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_endpoint = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI EndpointStateChange field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI EndpointStateChange field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI EndpointStateChange field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_endpoint = 1;
-			prop_is_valid = ast_ari_validate_endpoint(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI EndpointStateChange field endpoint failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI EndpointStateChange has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_endpoint) {
-		ast_log(LOG_ERROR, "ARI EndpointStateChange missing required field endpoint\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_endpoint_state_change_fn(void)
-{
-	return ast_ari_validate_endpoint_state_change;
-}
-
-int ast_ari_validate_event(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	const char *discriminator;
-
-	discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
-	if (!discriminator) {
-		ast_log(LOG_ERROR, "ARI Event missing required field type");
-		return 0;
-	}
-
-	if (strcmp("Event", discriminator) == 0) {
-		/* Self type; fall through */
-	} else
-	if (strcmp("ApplicationReplaced", discriminator) == 0) {
-		return ast_ari_validate_application_replaced(json);
-	} else
-	if (strcmp("BridgeAttendedTransfer", discriminator) == 0) {
-		return ast_ari_validate_bridge_attended_transfer(json);
-	} else
-	if (strcmp("BridgeBlindTransfer", discriminator) == 0) {
-		return ast_ari_validate_bridge_blind_transfer(json);
-	} else
-	if (strcmp("BridgeCreated", discriminator) == 0) {
-		return ast_ari_validate_bridge_created(json);
-	} else
-	if (strcmp("BridgeDestroyed", discriminator) == 0) {
-		return ast_ari_validate_bridge_destroyed(json);
-	} else
-	if (strcmp("BridgeMerged", discriminator) == 0) {
-		return ast_ari_validate_bridge_merged(json);
-	} else
-	if (strcmp("ChannelCallerId", discriminator) == 0) {
-		return ast_ari_validate_channel_caller_id(json);
-	} else
-	if (strcmp("ChannelConnectedLine", discriminator) == 0) {
-		return ast_ari_validate_channel_connected_line(json);
-	} else
-	if (strcmp("ChannelCreated", discriminator) == 0) {
-		return ast_ari_validate_channel_created(json);
-	} else
-	if (strcmp("ChannelDestroyed", discriminator) == 0) {
-		return ast_ari_validate_channel_destroyed(json);
-	} else
-	if (strcmp("ChannelDialplan", discriminator) == 0) {
-		return ast_ari_validate_channel_dialplan(json);
-	} else
-	if (strcmp("ChannelDtmfReceived", discriminator) == 0) {
-		return ast_ari_validate_channel_dtmf_received(json);
-	} else
-	if (strcmp("ChannelEnteredBridge", discriminator) == 0) {
-		return ast_ari_validate_channel_entered_bridge(json);
-	} else
-	if (strcmp("ChannelHangupRequest", discriminator) == 0) {
-		return ast_ari_validate_channel_hangup_request(json);
-	} else
-	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
-		return ast_ari_validate_channel_left_bridge(json);
-	} else
-	if (strcmp("ChannelStateChange", discriminator) == 0) {
-		return ast_ari_validate_channel_state_change(json);
-	} else
-	if (strcmp("ChannelTalkingFinished", discriminator) == 0) {
-		return ast_ari_validate_channel_talking_finished(json);
-	} else
-	if (strcmp("ChannelTalkingStarted", discriminator) == 0) {
-		return ast_ari_validate_channel_talking_started(json);
-	} else
-	if (strcmp("ChannelUserevent", discriminator) == 0) {
-		return ast_ari_validate_channel_userevent(json);
-	} else
-	if (strcmp("ChannelVarset", discriminator) == 0) {
-		return ast_ari_validate_channel_varset(json);
-	} else
-	if (strcmp("DeviceStateChanged", discriminator) == 0) {
-		return ast_ari_validate_device_state_changed(json);
-	} else
-	if (strcmp("Dial", discriminator) == 0) {
-		return ast_ari_validate_dial(json);
-	} else
-	if (strcmp("EndpointStateChange", discriminator) == 0) {
-		return ast_ari_validate_endpoint_state_change(json);
-	} else
-	if (strcmp("PlaybackFinished", discriminator) == 0) {
-		return ast_ari_validate_playback_finished(json);
-	} else
-	if (strcmp("PlaybackStarted", discriminator) == 0) {
-		return ast_ari_validate_playback_started(json);
-	} else
-	if (strcmp("RecordingFailed", discriminator) == 0) {
-		return ast_ari_validate_recording_failed(json);
-	} else
-	if (strcmp("RecordingFinished", discriminator) == 0) {
-		return ast_ari_validate_recording_finished(json);
-	} else
-	if (strcmp("RecordingStarted", discriminator) == 0) {
-		return ast_ari_validate_recording_started(json);
-	} else
-	if (strcmp("StasisEnd", discriminator) == 0) {
-		return ast_ari_validate_stasis_end(json);
-	} else
-	if (strcmp("StasisStart", discriminator) == 0) {
-		return ast_ari_validate_stasis_start(json);
-	} else
-	if (strcmp("TextMessageReceived", discriminator) == 0) {
-		return ast_ari_validate_text_message_received(json);
-	} else
-	{
-		ast_log(LOG_ERROR, "ARI Event has undocumented subtype %s\n",
-			discriminator);
-		res = 0;
-	}
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Event field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Event field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Event field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Event has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI Event missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI Event missing required field application\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_event_fn(void)
-{
-	return ast_ari_validate_event;
-}
-
-int ast_ari_validate_message(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	const char *discriminator;
-
-	discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
-	if (!discriminator) {
-		ast_log(LOG_ERROR, "ARI Message missing required field type");
-		return 0;
-	}
-
-	if (strcmp("Message", discriminator) == 0) {
-		/* Self type; fall through */
-	} else
-	if (strcmp("ApplicationReplaced", discriminator) == 0) {
-		return ast_ari_validate_application_replaced(json);
-	} else
-	if (strcmp("BridgeAttendedTransfer", discriminator) == 0) {
-		return ast_ari_validate_bridge_attended_transfer(json);
-	} else
-	if (strcmp("BridgeBlindTransfer", discriminator) == 0) {
-		return ast_ari_validate_bridge_blind_transfer(json);
-	} else
-	if (strcmp("BridgeCreated", discriminator) == 0) {
-		return ast_ari_validate_bridge_created(json);
-	} else
-	if (strcmp("BridgeDestroyed", discriminator) == 0) {
-		return ast_ari_validate_bridge_destroyed(json);
-	} else
-	if (strcmp("BridgeMerged", discriminator) == 0) {
-		return ast_ari_validate_bridge_merged(json);
-	} else
-	if (strcmp("ChannelCallerId", discriminator) == 0) {
-		return ast_ari_validate_channel_caller_id(json);
-	} else
-	if (strcmp("ChannelConnectedLine", discriminator) == 0) {
-		return ast_ari_validate_channel_connected_line(json);
-	} else
-	if (strcmp("ChannelCreated", discriminator) == 0) {
-		return ast_ari_validate_channel_created(json);
-	} else
-	if (strcmp("ChannelDestroyed", discriminator) == 0) {
-		return ast_ari_validate_channel_destroyed(json);
-	} else
-	if (strcmp("ChannelDialplan", discriminator) == 0) {
-		return ast_ari_validate_channel_dialplan(json);
-	} else
-	if (strcmp("ChannelDtmfReceived", discriminator) == 0) {
-		return ast_ari_validate_channel_dtmf_received(json);
-	} else
-	if (strcmp("ChannelEnteredBridge", discriminator) == 0) {
-		return ast_ari_validate_channel_entered_bridge(json);
-	} else
-	if (strcmp("ChannelHangupRequest", discriminator) == 0) {
-		return ast_ari_validate_channel_hangup_request(json);
-	} else
-	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
-		return ast_ari_validate_channel_left_bridge(json);
-	} else
-	if (strcmp("ChannelStateChange", discriminator) == 0) {
-		return ast_ari_validate_channel_state_change(json);
-	} else
-	if (strcmp("ChannelTalkingFinished", discriminator) == 0) {
-		return ast_ari_validate_channel_talking_finished(json);
-	} else
-	if (strcmp("ChannelTalkingStarted", discriminator) == 0) {
-		return ast_ari_validate_channel_talking_started(json);
-	} else
-	if (strcmp("ChannelUserevent", discriminator) == 0) {
-		return ast_ari_validate_channel_userevent(json);
-	} else
-	if (strcmp("ChannelVarset", discriminator) == 0) {
-		return ast_ari_validate_channel_varset(json);
-	} else
-	if (strcmp("DeviceStateChanged", discriminator) == 0) {
-		return ast_ari_validate_device_state_changed(json);
-	} else
-	if (strcmp("Dial", discriminator) == 0) {
-		return ast_ari_validate_dial(json);
-	} else
-	if (strcmp("EndpointStateChange", discriminator) == 0) {
-		return ast_ari_validate_endpoint_state_change(json);
-	} else
-	if (strcmp("Event", discriminator) == 0) {
-		return ast_ari_validate_event(json);
-	} else
-	if (strcmp("MissingParams", discriminator) == 0) {
-		return ast_ari_validate_missing_params(json);
-	} else
-	if (strcmp("PlaybackFinished", discriminator) == 0) {
-		return ast_ari_validate_playback_finished(json);
-	} else
-	if (strcmp("PlaybackStarted", discriminator) == 0) {
-		return ast_ari_validate_playback_started(json);
-	} else
-	if (strcmp("RecordingFailed", discriminator) == 0) {
-		return ast_ari_validate_recording_failed(json);
-	} else
-	if (strcmp("RecordingFinished", discriminator) == 0) {
-		return ast_ari_validate_recording_finished(json);
-	} else
-	if (strcmp("RecordingStarted", discriminator) == 0) {
-		return ast_ari_validate_recording_started(json);
-	} else
-	if (strcmp("StasisEnd", discriminator) == 0) {
-		return ast_ari_validate_stasis_end(json);
-	} else
-	if (strcmp("StasisStart", discriminator) == 0) {
-		return ast_ari_validate_stasis_start(json);
-	} else
-	if (strcmp("TextMessageReceived", discriminator) == 0) {
-		return ast_ari_validate_text_message_received(json);
-	} else
-	{
-		ast_log(LOG_ERROR, "ARI Message has undocumented subtype %s\n",
-			discriminator);
-		res = 0;
-	}
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Message field type failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Message has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI Message missing required field type\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_message_fn(void)
-{
-	return ast_ari_validate_message;
-}
-
-int ast_ari_validate_missing_params(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_params = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI MissingParams field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("params", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_params = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI MissingParams field params failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI MissingParams has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI MissingParams missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_params) {
-		ast_log(LOG_ERROR, "ARI MissingParams missing required field params\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_missing_params_fn(void)
-{
-	return ast_ari_validate_missing_params;
-}
-
-int ast_ari_validate_playback_finished(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_playback = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackFinished field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackFinished field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackFinished field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_playback = 1;
-			prop_is_valid = ast_ari_validate_playback(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackFinished field playback failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI PlaybackFinished has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_playback) {
-		ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field playback\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_playback_finished_fn(void)
-{
-	return ast_ari_validate_playback_finished;
-}
-
-int ast_ari_validate_playback_started(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_playback = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackStarted field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackStarted field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackStarted field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_playback = 1;
-			prop_is_valid = ast_ari_validate_playback(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI PlaybackStarted field playback failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI PlaybackStarted has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_playback) {
-		ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field playback\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_playback_started_fn(void)
-{
-	return ast_ari_validate_playback_started;
-}
-
-int ast_ari_validate_recording_failed(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_recording = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFailed field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFailed field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFailed field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("recording", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_recording = 1;
-			prop_is_valid = ast_ari_validate_live_recording(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFailed field recording failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI RecordingFailed has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI RecordingFailed missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI RecordingFailed missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_recording) {
-		ast_log(LOG_ERROR, "ARI RecordingFailed missing required field recording\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_recording_failed_fn(void)
-{
-	return ast_ari_validate_recording_failed;
-}
-
-int ast_ari_validate_recording_finished(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_recording = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFinished field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFinished field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFinished field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("recording", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_recording = 1;
-			prop_is_valid = ast_ari_validate_live_recording(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingFinished field recording failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI RecordingFinished has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI RecordingFinished missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI RecordingFinished missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_recording) {
-		ast_log(LOG_ERROR, "ARI RecordingFinished missing required field recording\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_recording_finished_fn(void)
-{
-	return ast_ari_validate_recording_finished;
-}
-
-int ast_ari_validate_recording_started(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_recording = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingStarted field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingStarted field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingStarted field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("recording", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_recording = 1;
-			prop_is_valid = ast_ari_validate_live_recording(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI RecordingStarted field recording failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI RecordingStarted has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI RecordingStarted missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI RecordingStarted missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_recording) {
-		ast_log(LOG_ERROR, "ARI RecordingStarted missing required field recording\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_recording_started_fn(void)
-{
-	return ast_ari_validate_recording_started;
-}
-
-int ast_ari_validate_stasis_end(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisEnd field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisEnd field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisEnd field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisEnd field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI StasisEnd has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI StasisEnd missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI StasisEnd missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI StasisEnd missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_stasis_end_fn(void)
-{
-	return ast_ari_validate_stasis_end;
-}
-
-int ast_ari_validate_stasis_start(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_args = 0;
-	int has_channel = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("args", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_args = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field args failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel = 1;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field channel failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("replace_channel", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_channel(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI StasisStart field replace_channel failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI StasisStart has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI StasisStart missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI StasisStart missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_args) {
-		ast_log(LOG_ERROR, "ARI StasisStart missing required field args\n");
-		res = 0;
-	}
-
-	if (!has_channel) {
-		ast_log(LOG_ERROR, "ARI StasisStart missing required field channel\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_stasis_start_fn(void)
-{
-	return ast_ari_validate_stasis_start;
-}
-
-int ast_ari_validate_text_message_received(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_type = 0;
-	int has_application = 0;
-	int has_message = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_type = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageReceived field type failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_application = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageReceived field application failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_date(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageReceived field timestamp failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			prop_is_valid = ast_ari_validate_endpoint(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageReceived field endpoint failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("message", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_message = 1;
-			prop_is_valid = ast_ari_validate_text_message(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI TextMessageReceived field message failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI TextMessageReceived has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_type) {
-		ast_log(LOG_ERROR, "ARI TextMessageReceived missing required field type\n");
-		res = 0;
-	}
-
-	if (!has_application) {
-		ast_log(LOG_ERROR, "ARI TextMessageReceived missing required field application\n");
-		res = 0;
-	}
-
-	if (!has_message) {
-		ast_log(LOG_ERROR, "ARI TextMessageReceived missing required field message\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_text_message_received_fn(void)
-{
-	return ast_ari_validate_text_message_received;
-}
-
-int ast_ari_validate_application(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-	int has_bridge_ids = 0;
-	int has_channel_ids = 0;
-	int has_device_names = 0;
-	int has_endpoint_ids = 0;
-	int has_name = 0;
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-		if (strcmp("bridge_ids", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_bridge_ids = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Application field bridge_ids failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("channel_ids", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_channel_ids = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Application field channel_ids failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("device_names", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_device_names = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Application field device_names failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("endpoint_ids", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_endpoint_ids = 1;
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_string);
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Application field endpoint_ids failed validation\n");
-				res = 0;
-			}
-		} else
-		if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-			has_name = 1;
-			prop_is_valid = ast_ari_validate_string(
-				ast_json_object_iter_value(iter));
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI Application field name failed validation\n");
-				res = 0;
-			}
-		} else
-		{
-			ast_log(LOG_ERROR,
-				"ARI Application has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-	if (!has_bridge_ids) {
-		ast_log(LOG_ERROR, "ARI Application missing required field bridge_ids\n");
-		res = 0;
-	}
-
-	if (!has_channel_ids) {
-		ast_log(LOG_ERROR, "ARI Application missing required field channel_ids\n");
-		res = 0;
-	}
-
-	if (!has_device_names) {
-		ast_log(LOG_ERROR, "ARI Application missing required field device_names\n");
-		res = 0;
-	}
-
-	if (!has_endpoint_ids) {
-		ast_log(LOG_ERROR, "ARI Application missing required field endpoint_ids\n");
-		res = 0;
-	}
-
-	if (!has_name) {
-		ast_log(LOG_ERROR, "ARI Application missing required field name\n");
-		res = 0;
-	}
-
-	return res;
-}
-
-ari_validator ast_ari_validate_application_fn(void)
-{
-	return ast_ari_validate_application;
-}
diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h
deleted file mode 100644
index de8547c..0000000
--- a/res/ari/ari_model_validators.h
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - Build validators for ARI model objects.
- *
- * In addition to the normal validation functions one would normally expect,
- * each validator has a ast_ari_validate_{id}_fn() companion function that returns
- * the validator's function pointer.
- *
- * The reason for this seamingly useless indirection is the way function
- * pointers interfere with module loading. Asterisk attempts to dlopen() each
- * module using \c RTLD_LAZY in order to read some metadata from the module.
- * Unfortunately, if you take the address of a function, the function has to be
- * resolvable at load time, even if \c RTLD_LAZY is specified. By moving the
- * function-address-taking into this module, we can once again be lazy.
- */
-
- /*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_model_validators.h.mustache
- */
-
-#ifndef _ASTERISK_ARI_MODEL_H
-#define _ASTERISK_ARI_MODEL_H
-
-#include "asterisk/json.h"
-
-/*! @{ */
-
-/*!
- * \brief Validator for native Swagger void.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_void(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger object.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_object(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger byte.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_byte(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger boolean.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_boolean(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger int.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_int(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger long.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_long(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger float.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_float(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger double.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_double(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger string.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_string(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger date.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_date(struct ast_json *json);
-
-/*!
- * \brief Validator for a Swagger List[]/JSON array.
- *
- * \param json JSON object to validate.
- * \param fn Validator to call on every element in the array.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
-
-/*! @} */
-
-/*!
- * \brief Function type for validator functions. Allows for 
- */
-typedef int (*ari_validator)(struct ast_json *json);
-
-/*!
- * \brief Validator for AsteriskInfo.
- *
- * Asterisk system information
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_asterisk_info(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_asterisk_info().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_asterisk_info_fn(void);
-
-/*!
- * \brief Validator for BuildInfo.
- *
- * Info about how Asterisk was built
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_build_info(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_build_info().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_build_info_fn(void);
-
-/*!
- * \brief Validator for ConfigInfo.
- *
- * Info about Asterisk configuration
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_config_info(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_config_info().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_config_info_fn(void);
-
-/*!
- * \brief Validator for SetId.
- *
- * Effective user/group id
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_set_id(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_set_id().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_set_id_fn(void);
-
-/*!
- * \brief Validator for StatusInfo.
- *
- * Info about Asterisk status
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_status_info(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_status_info().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_status_info_fn(void);
-
-/*!
- * \brief Validator for SystemInfo.
- *
- * Info about Asterisk
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_system_info(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_system_info().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_system_info_fn(void);
-
-/*!
- * \brief Validator for Variable.
- *
- * The value of a channel variable
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_variable(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_variable().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_variable_fn(void);
-
-/*!
- * \brief Validator for Endpoint.
- *
- * An external device that may offer/accept calls to/from Asterisk.
- *
- * Unlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_endpoint(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_endpoint().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_endpoint_fn(void);
-
-/*!
- * \brief Validator for TextMessage.
- *
- * A text message.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_text_message(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_text_message().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_text_message_fn(void);
-
-/*!
- * \brief Validator for TextMessageVariable.
- *
- * A key/value pair variable in a text message.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_text_message_variable(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_text_message_variable().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_text_message_variable_fn(void);
-
-/*!
- * \brief Validator for CallerID.
- *
- * Caller identification
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_caller_id(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_caller_id().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_caller_id_fn(void);
-
-/*!
- * \brief Validator for Channel.
- *
- * A specific communication connection between Asterisk and an Endpoint.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_fn(void);
-
-/*!
- * \brief Validator for Dialed.
- *
- * Dialed channel information.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_dialed(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_dialed().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_dialed_fn(void);
-
-/*!
- * \brief Validator for DialplanCEP.
- *
- * Dialplan location (context/extension/priority)
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_dialplan_cep(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_dialplan_cep().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_dialplan_cep_fn(void);
-
-/*!
- * \brief Validator for Bridge.
- *
- * The merging of media from one or more channels.
- *
- * Everyone on the bridge receives the same audio.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_fn(void);
-
-/*!
- * \brief Validator for LiveRecording.
- *
- * A recording that is in progress
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_live_recording(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_live_recording().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_live_recording_fn(void);
-
-/*!
- * \brief Validator for StoredRecording.
- *
- * A past recording that may be played back.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_stored_recording(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_stored_recording().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_stored_recording_fn(void);
-
-/*!
- * \brief Validator for FormatLangPair.
- *
- * Identifies the format and language of a sound file
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_format_lang_pair(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_format_lang_pair().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_format_lang_pair_fn(void);
-
-/*!
- * \brief Validator for Sound.
- *
- * A media file that may be played back.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_sound(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_sound().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_sound_fn(void);
-
-/*!
- * \brief Validator for Playback.
- *
- * Object representing the playback of media to a channel
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_playback(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_playback().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_playback_fn(void);
-
-/*!
- * \brief Validator for DeviceState.
- *
- * Represents the state of a device.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_device_state(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_device_state().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_device_state_fn(void);
-
-/*!
- * \brief Validator for Mailbox.
- *
- * Represents the state of a mailbox.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_mailbox(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_mailbox().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_mailbox_fn(void);
-
-/*!
- * \brief Validator for ApplicationReplaced.
- *
- * Notification that another WebSocket has taken over for an application.
- *
- * An application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_application_replaced(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_application_replaced().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_application_replaced_fn(void);
-
-/*!
- * \brief Validator for BridgeAttendedTransfer.
- *
- * Notification that an attended transfer has occurred.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge_attended_transfer(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge_attended_transfer().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_attended_transfer_fn(void);
-
-/*!
- * \brief Validator for BridgeBlindTransfer.
- *
- * Notification that a blind transfer has occurred.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge_blind_transfer(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge_blind_transfer().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_blind_transfer_fn(void);
-
-/*!
- * \brief Validator for BridgeCreated.
- *
- * Notification that a bridge has been created.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge_created(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge_created().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_created_fn(void);
-
-/*!
- * \brief Validator for BridgeDestroyed.
- *
- * Notification that a bridge has been destroyed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge_destroyed(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge_destroyed().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_destroyed_fn(void);
-
-/*!
- * \brief Validator for BridgeMerged.
- *
- * Notification that one bridge has merged into another.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_bridge_merged(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_bridge_merged().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_bridge_merged_fn(void);
-
-/*!
- * \brief Validator for ChannelCallerId.
- *
- * Channel changed Caller ID.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_caller_id(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_caller_id().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_caller_id_fn(void);
-
-/*!
- * \brief Validator for ChannelConnectedLine.
- *
- * Channel changed Connected Line.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_connected_line(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_connected_line().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_connected_line_fn(void);
-
-/*!
- * \brief Validator for ChannelCreated.
- *
- * Notification that a channel has been created.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_created(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_created().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_created_fn(void);
-
-/*!
- * \brief Validator for ChannelDestroyed.
- *
- * Notification that a channel has been destroyed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_destroyed(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_destroyed().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_destroyed_fn(void);
-
-/*!
- * \brief Validator for ChannelDialplan.
- *
- * Channel changed location in the dialplan.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_dialplan(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_dialplan().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_dialplan_fn(void);
-
-/*!
- * \brief Validator for ChannelDtmfReceived.
- *
- * DTMF received on a channel.
- *
- * This event is sent when the DTMF ends. There is no notification about the start of DTMF
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_dtmf_received(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_dtmf_received().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_dtmf_received_fn(void);
-
-/*!
- * \brief Validator for ChannelEnteredBridge.
- *
- * Notification that a channel has entered a bridge.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_entered_bridge(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_entered_bridge().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_entered_bridge_fn(void);
-
-/*!
- * \brief Validator for ChannelHangupRequest.
- *
- * A hangup was requested on the channel.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_hangup_request(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_hangup_request().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_hangup_request_fn(void);
-
-/*!
- * \brief Validator for ChannelLeftBridge.
- *
- * Notification that a channel has left a bridge.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_left_bridge(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_left_bridge().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_left_bridge_fn(void);
-
-/*!
- * \brief Validator for ChannelStateChange.
- *
- * Notification of a channel's state change.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_state_change(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_state_change().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_state_change_fn(void);
-
-/*!
- * \brief Validator for ChannelTalkingFinished.
- *
- * Talking is no longer detected on the channel.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_talking_finished(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_talking_finished().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_talking_finished_fn(void);
-
-/*!
- * \brief Validator for ChannelTalkingStarted.
- *
- * Talking was detected on the channel.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_talking_started(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_talking_started().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_talking_started_fn(void);
-
-/*!
- * \brief Validator for ChannelUserevent.
- *
- * User-generated event with additional user-defined fields in the object.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_userevent(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_userevent().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_userevent_fn(void);
-
-/*!
- * \brief Validator for ChannelVarset.
- *
- * Channel variable changed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_channel_varset(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_channel_varset().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_channel_varset_fn(void);
-
-/*!
- * \brief Validator for DeviceStateChanged.
- *
- * Notification that a device state has changed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_device_state_changed(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_device_state_changed().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_device_state_changed_fn(void);
-
-/*!
- * \brief Validator for Dial.
- *
- * Dialing state has changed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_dial(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_dial().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_dial_fn(void);
-
-/*!
- * \brief Validator for EndpointStateChange.
- *
- * Endpoint state changed.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_endpoint_state_change(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_endpoint_state_change().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_endpoint_state_change_fn(void);
-
-/*!
- * \brief Validator for Event.
- *
- * Base type for asynchronous events from Asterisk.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_event(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_event().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_event_fn(void);
-
-/*!
- * \brief Validator for Message.
- *
- * Base type for errors and events
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_message(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_message().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_message_fn(void);
-
-/*!
- * \brief Validator for MissingParams.
- *
- * Error event sent when required params are missing.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_missing_params(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_missing_params().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_missing_params_fn(void);
-
-/*!
- * \brief Validator for PlaybackFinished.
- *
- * Event showing the completion of a media playback operation.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_playback_finished(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_playback_finished().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_playback_finished_fn(void);
-
-/*!
- * \brief Validator for PlaybackStarted.
- *
- * Event showing the start of a media playback operation.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_playback_started(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_playback_started().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_playback_started_fn(void);
-
-/*!
- * \brief Validator for RecordingFailed.
- *
- * Event showing failure of a recording operation.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_recording_failed(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_recording_failed().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_recording_failed_fn(void);
-
-/*!
- * \brief Validator for RecordingFinished.
- *
- * Event showing the completion of a recording operation.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_recording_finished(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_recording_finished().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_recording_finished_fn(void);
-
-/*!
- * \brief Validator for RecordingStarted.
- *
- * Event showing the start of a recording operation.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_recording_started(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_recording_started().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_recording_started_fn(void);
-
-/*!
- * \brief Validator for StasisEnd.
- *
- * Notification that a channel has left a Stasis application.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_stasis_end(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_stasis_end().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_stasis_end_fn(void);
-
-/*!
- * \brief Validator for StasisStart.
- *
- * Notification that a channel has entered a Stasis application.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_stasis_start(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_stasis_start().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_stasis_start_fn(void);
-
-/*!
- * \brief Validator for TextMessageReceived.
- *
- * A text message was received from an endpoint.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_text_message_received(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_text_message_received().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_text_message_received_fn(void);
-
-/*!
- * \brief Validator for Application.
- *
- * Details of a Stasis application
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_application(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_application().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_application_fn(void);
-
-/*
- * JSON models
- *
- * AsteriskInfo
- * - build: BuildInfo
- * - config: ConfigInfo
- * - status: StatusInfo
- * - system: SystemInfo
- * BuildInfo
- * - date: string (required)
- * - kernel: string (required)
- * - machine: string (required)
- * - options: string (required)
- * - os: string (required)
- * - user: string (required)
- * ConfigInfo
- * - default_language: string (required)
- * - max_channels: int
- * - max_load: double
- * - max_open_files: int
- * - name: string (required)
- * - setid: SetId (required)
- * SetId
- * - group: string (required)
- * - user: string (required)
- * StatusInfo
- * - last_reload_time: Date (required)
- * - startup_time: Date (required)
- * SystemInfo
- * - entity_id: string (required)
- * - version: string (required)
- * Variable
- * - value: string (required)
- * Endpoint
- * - channel_ids: List[string] (required)
- * - resource: string (required)
- * - state: string
- * - technology: string (required)
- * TextMessage
- * - body: string (required)
- * - from: string (required)
- * - to: string (required)
- * - variables: List[TextMessageVariable]
- * TextMessageVariable
- * - key: string (required)
- * - value: string (required)
- * CallerID
- * - name: string (required)
- * - number: string (required)
- * Channel
- * - accountcode: string (required)
- * - caller: CallerID (required)
- * - connected: CallerID (required)
- * - creationtime: Date (required)
- * - dialplan: DialplanCEP (required)
- * - id: string (required)
- * - name: string (required)
- * - state: string (required)
- * Dialed
- * DialplanCEP
- * - context: string (required)
- * - exten: string (required)
- * - priority: long (required)
- * Bridge
- * - bridge_class: string (required)
- * - bridge_type: string (required)
- * - channels: List[string] (required)
- * - creator: string (required)
- * - id: string (required)
- * - name: string (required)
- * - technology: string (required)
- * LiveRecording
- * - cause: string
- * - duration: int
- * - format: string (required)
- * - name: string (required)
- * - silence_duration: int
- * - state: string (required)
- * - talking_duration: int
- * - target_uri: string (required)
- * StoredRecording
- * - format: string (required)
- * - name: string (required)
- * FormatLangPair
- * - format: string (required)
- * - language: string (required)
- * Sound
- * - formats: List[FormatLangPair] (required)
- * - id: string (required)
- * - text: string
- * Playback
- * - id: string (required)
- * - language: string
- * - media_uri: string (required)
- * - state: string (required)
- * - target_uri: string (required)
- * DeviceState
- * - name: string (required)
- * - state: string (required)
- * Mailbox
- * - name: string (required)
- * - new_messages: int (required)
- * - old_messages: int (required)
- * ApplicationReplaced
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * BridgeAttendedTransfer
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - destination_application: string
- * - destination_bridge: string
- * - destination_link_first_leg: Channel
- * - destination_link_second_leg: Channel
- * - destination_threeway_bridge: Bridge
- * - destination_threeway_channel: Channel
- * - destination_type: string (required)
- * - is_external: boolean (required)
- * - replace_channel: Channel
- * - result: string (required)
- * - transfer_target: Channel
- * - transferee: Channel
- * - transferer_first_leg: Channel (required)
- * - transferer_first_leg_bridge: Bridge
- * - transferer_second_leg: Channel (required)
- * - transferer_second_leg_bridge: Bridge
- * BridgeBlindTransfer
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge
- * - channel: Channel (required)
- * - context: string (required)
- * - exten: string (required)
- * - is_external: boolean (required)
- * - replace_channel: Channel
- * - result: string (required)
- * - transferee: Channel
- * BridgeCreated
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge (required)
- * BridgeDestroyed
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge (required)
- * BridgeMerged
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge (required)
- * - bridge_from: Bridge (required)
- * ChannelCallerId
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - caller_presentation: int (required)
- * - caller_presentation_txt: string (required)
- * - channel: Channel (required)
- * ChannelConnectedLine
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * ChannelCreated
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * ChannelDestroyed
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - cause: int (required)
- * - cause_txt: string (required)
- * - channel: Channel (required)
- * ChannelDialplan
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * - dialplan_app: string (required)
- * - dialplan_app_data: string (required)
- * ChannelDtmfReceived
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * - digit: string (required)
- * - duration_ms: int (required)
- * ChannelEnteredBridge
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge (required)
- * - channel: Channel
- * ChannelHangupRequest
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - cause: int
- * - channel: Channel (required)
- * - soft: boolean
- * ChannelLeftBridge
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge (required)
- * - channel: Channel (required)
- * ChannelStateChange
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * ChannelTalkingFinished
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * - duration: int (required)
- * ChannelTalkingStarted
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * ChannelUserevent
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - bridge: Bridge
- * - channel: Channel
- * - endpoint: Endpoint
- * - eventname: string (required)
- * - userevent: object (required)
- * ChannelVarset
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel
- * - value: string (required)
- * - variable: string (required)
- * DeviceStateChanged
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - device_state: DeviceState (required)
- * Dial
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - caller: Channel
- * - dialstatus: string (required)
- * - dialstring: string
- * - forward: string
- * - forwarded: Channel
- * - peer: Channel (required)
- * EndpointStateChange
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - endpoint: Endpoint (required)
- * Event
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * Message
- * - type: string (required)
- * MissingParams
- * - type: string (required)
- * - params: List[string] (required)
- * PlaybackFinished
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - playback: Playback (required)
- * PlaybackStarted
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - playback: Playback (required)
- * RecordingFailed
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - recording: LiveRecording (required)
- * RecordingFinished
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - recording: LiveRecording (required)
- * RecordingStarted
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - recording: LiveRecording (required)
- * StasisEnd
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - channel: Channel (required)
- * StasisStart
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - args: List[string] (required)
- * - channel: Channel (required)
- * - replace_channel: Channel
- * TextMessageReceived
- * - type: string (required)
- * - application: string (required)
- * - timestamp: Date
- * - endpoint: Endpoint
- * - message: TextMessage (required)
- * Application
- * - bridge_ids: List[string] (required)
- * - channel_ids: List[string] (required)
- * - device_names: List[string] (required)
- * - endpoint_ids: List[string] (required)
- * - name: string (required)
- */
-
-#endif /* _ASTERISK_ARI_MODEL_H */
diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c
deleted file mode 100644
index b0052cb..0000000
--- a/res/ari/ari_websockets.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417317 $")
-
-#include "asterisk/ari.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/http_websocket.h"
-#include "internal.h"
-
-/*! \file
- *
- * \brief WebSocket support for RESTful API's.
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-struct ast_ari_websocket_session {
-	struct ast_websocket *ws_session;
-	int (*validator)(struct ast_json *);
-};
-
-static void websocket_session_dtor(void *obj)
-{
-	struct ast_ari_websocket_session *session = obj;
-
-	ast_websocket_unref(session->ws_session);
-	session->ws_session = NULL;
-}
-
-/*!
- * \brief Validator that always succeeds.
- */
-static int null_validator(struct ast_json *json)
-{
-	return 1;
-}
-
-struct ast_ari_websocket_session *ast_ari_websocket_session_create(
-	struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
-{
-	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_ari_conf *, config, ast_ari_config_get(), ao2_cleanup);
-
-	if (ws_session == NULL) {
-		return NULL;
-	}
-
-	if (config == NULL || config->general == NULL) {
-		return NULL;
-	}
-
-	if (validator == NULL) {
-		validator = null_validator;
-	}
-
-	if (ast_websocket_set_nonblock(ws_session) != 0) {
-		ast_log(LOG_ERROR,
-			"ARI web socket failed to set nonblock; closing: %s\n",
-			strerror(errno));
-		return NULL;
-	}
-
-	if (ast_websocket_set_timeout(ws_session, config->general->write_timeout)) {
-		ast_log(LOG_WARNING, "Failed to set write timeout %d on ARI web socket\n",
-			config->general->write_timeout);
-	}
-
-	session = ao2_alloc(sizeof(*session), websocket_session_dtor);
-	if (!session) {
-		return NULL;
-	}
-
-	ao2_ref(ws_session, +1);
-	session->ws_session = ws_session;
-	session->validator = validator;
-
-	ao2_ref(session, +1);
-	return session;
-}
-
-struct ast_json *ast_ari_websocket_session_read(
-	struct ast_ari_websocket_session *session)
-{
-	RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
-
-	while (!message) {
-		int res;
-		char *payload;
-		uint64_t payload_len;
-		enum ast_websocket_opcode opcode;
-		int fragmented;
-
-		res = ast_wait_for_input(
-			ast_websocket_fd(session->ws_session), -1);
-
-		if (res <= 0) {
-			ast_log(LOG_WARNING, "WebSocket poll error: %s\n",
-				strerror(errno));
-			return NULL;
-		}
-
-		res = ast_websocket_read(session->ws_session, &payload,
-			&payload_len, &opcode, &fragmented);
-
-		if (res != 0) {
-			ast_log(LOG_WARNING, "WebSocket read error: %s\n",
-				strerror(errno));
-			return NULL;
-		}
-
-		switch (opcode) {
-		case AST_WEBSOCKET_OPCODE_CLOSE:
-			ast_debug(1, "WebSocket closed by peer\n");
-			return NULL;
-		case AST_WEBSOCKET_OPCODE_TEXT:
-			message = ast_json_load_buf(payload, payload_len, NULL);
-			if (message == NULL) {
-				ast_log(LOG_WARNING,
-					"WebSocket input failed to parse\n");
-			}
-			break;
-		default:
-			/* Ignore all other message types */
-			break;
-		}
-	}
-
-	return ast_json_ref(message);
-}
-
-#define VALIDATION_FAILED				\
-	"{"						\
-	"  \"error\": \"InvalidMessage\","		\
-	"  \"message\": \"Message validation failed\""	\
-	"}" 
-
-int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
-	struct ast_json *message)
-{
-	RAII_VAR(char *, str, NULL, ast_json_free);
-
-#ifdef AST_DEVMODE
-	if (!session->validator(message)) {
-		ast_log(LOG_ERROR, "Outgoing message failed validation\n");
-		return ast_websocket_write(session->ws_session,
-			AST_WEBSOCKET_OPCODE_TEXT, VALIDATION_FAILED,
-			strlen(VALIDATION_FAILED));
-	}
-#endif
-
-	str = ast_json_dump_string_format(message, ast_ari_json_format());
-
-	if (str == NULL) {
-		ast_log(LOG_ERROR, "Failed to encode JSON object\n");
-		return -1;
-	}
-
-	ast_debug(3, "Examining ARI event: \n%s\n", str);
-	return ast_websocket_write(session->ws_session,
-		AST_WEBSOCKET_OPCODE_TEXT, str,	strlen(str));
-}
-
-void ari_handle_websocket(struct ast_websocket_server *ws_server,
-	struct ast_tcptls_session_instance *ser, const char *uri,
-	enum ast_http_method method, struct ast_variable *get_params,
-	struct ast_variable *headers)
-{
-	struct ast_http_uri fake_urih = {
-		.data = ws_server,
-	};
-	ast_websocket_uri_cb(ser, &fake_urih, uri, method, get_params,
-		headers);
-}
diff --git a/res/ari/cli.c b/res/ari/cli.c
deleted file mode 100644
index d18b1b8..0000000
--- a/res/ari/cli.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Command line for ARI.
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 395603 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/cli.h"
-#include "internal.h"
-
-static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari show status";
-		e->usage =
-			"Usage: ari show status\n"
-			"       Shows all ARI settings\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	default:
-		break;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	conf = ast_ari_config_get();
-
-	if (!conf) {
-		ast_cli(a->fd, "Error getting ARI configuration\n");
-		return CLI_FAILURE;
-	}
-
-	ast_cli(a->fd, "ARI Status:\n");
-	ast_cli(a->fd, "Enabled: %s\n", AST_CLI_YESNO(conf->general->enabled));
-	ast_cli(a->fd, "Output format: ");
-	switch (conf->general->format) {
-	case AST_JSON_COMPACT:
-		ast_cli(a->fd, "compact");
-		break;
-	case AST_JSON_PRETTY:
-		ast_cli(a->fd, "pretty");
-		break;
-	}
-	ast_cli(a->fd, "\n");
-	ast_cli(a->fd, "Auth realm: %s\n", conf->general->auth_realm);
-	ast_cli(a->fd, "Allowed Origins: %s\n", conf->general->allowed_origins);
-	ast_cli(a->fd, "User count: %d\n", ao2_container_count(conf->users));
-	return CLI_SUCCESS;
-}
-
-static int show_users_cb(void *obj, void *arg, int flags)
-{
-	struct ast_ari_conf_user *user = obj;
-	struct ast_cli_args *a = arg;
-
-	ast_cli(a->fd, "%-4s  %s\n",
-		AST_CLI_YESNO(user->read_only),
-		user->username);
-	return 0;
-}
-
-static char *ari_show_users(struct ast_cli_entry *e, int cmd,
-	struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari show users";
-		e->usage =
-			"Usage: ari show users\n"
-			"       Shows all ARI users\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	default:
-		break;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	conf = ast_ari_config_get();
-	if (!conf) {
-		ast_cli(a->fd, "Error getting ARI configuration\n");
-		return CLI_FAILURE;
-	}
-
-	ast_cli(a->fd, "r/o?  Username\n");
-	ast_cli(a->fd, "----  --------\n");
-
-	ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
-
-	return CLI_SUCCESS;
-}
-
-struct user_complete {
-	/*! Nth user to search for */
-	int state;
-	/*! Which user currently on */
-	int which;
-};
-
-static int complete_ari_user_search(void *obj, void *arg, void *data, int flags)
-{
-	struct user_complete *search = data;
-
-	if (++search->which > search->state) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_ari_user(struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
-
-	struct user_complete search = {
-		.state = a->n,
-	};
-
-	conf = ast_ari_config_get();
-	if (!conf) {
-		ast_cli(a->fd, "Error getting ARI configuration\n");
-		return CLI_FAILURE;
-	}
-
-	user = ao2_callback_data(conf->users,
-		ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_ari_user_search, (char*)a->word, &search);
-
-	return user ? ast_strdup(user->username) : NULL;
-}
-
-static char *complete_ari_show_user(struct ast_cli_args *a)
-{
-	if (a->pos == 3) {
-		return complete_ari_user(a);
-	}
-
-	return NULL;
-}
-
-static char *ari_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari show user";
-		e->usage =
-			"Usage: ari show user <username>\n"
-			"       Shows a specific ARI user\n";
-		return NULL;
-	case CLI_GENERATE:
-		return complete_ari_show_user(a);
-	default:
-		break;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	conf = ast_ari_config_get();
-
-	if (!conf) {
-		ast_cli(a->fd, "Error getting ARI configuration\n");
-		return CLI_FAILURE;
-	}
-
-	user = ao2_find(conf->users, a->argv[3], OBJ_KEY);
-	if (!user) {
-		ast_cli(a->fd, "User '%s' not found\n", a->argv[3]);
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, "Username: %s\n", user->username);
-	ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
-
-	return CLI_SUCCESS;
-}
-
-static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(char *, crypted, NULL, ast_free);
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "ari mkpasswd";
-		e->usage =
-			"Usage: ari mkpasswd <password>\n"
-			"       Encrypts a password for use in ari.conf\n"
-			"       Be aware that the password will be shown in the\n"
-			"       command line history. The mkpasswd shell command\n"
-			"       may be preferable.\n"
-			;
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	default:
-		break;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	crypted = ast_crypt_encrypt(a->argv[2]);
-	if (!crypted) {
-		ast_cli(a->fd, "Failed to encrypt password\n");
-		return CLI_FAILURE;
-	}
-
-	ast_cli(a->fd,
-		"; Copy the following two lines into ari.conf\n");
-	ast_cli(a->fd, "password_format = crypt\n");
-	ast_cli(a->fd, "password = %s\n", crypted);
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_ari[] = {
-	AST_CLI_DEFINE(ari_show, "Show ARI settings"),
-	AST_CLI_DEFINE(ari_show_users, "List ARI users"),
-	AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
-	AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
-};
-
-int ast_ari_cli_register(void) {
-	return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
-
-void ast_ari_cli_unregister(void) {
-	ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
diff --git a/res/ari/config.c b/res/ari/config.c
deleted file mode 100644
index e158a93..0000000
--- a/res/ari/config.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Config framework stuffz for ARI.
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 417317 $")
-
-#include "asterisk/config_options.h"
-#include "asterisk/http_websocket.h"
-#include "internal.h"
-
-/*! \brief Locking container for safe configuration access. */
-static AO2_GLOBAL_OBJ_STATIC(confs);
-
-/*! \brief Mapping of the ARI conf struct's globals to the
- *         general context in the config file. */
-static struct aco_type general_option = {
-	.type = ACO_GLOBAL,
-	.name = "general",
-	.item_offset = offsetof(struct ast_ari_conf, general),
-	.category = "^general$",
-	.category_match = ACO_WHITELIST,
-};
-
-static struct aco_type *general_options[] = ACO_TYPES(&general_option);
-
-/*! \brief Encoding format handler converts from boolean to enum. */
-static int encoding_format_handler(const struct aco_option *opt,
-	struct ast_variable *var, void *obj)
-{
-	struct ast_ari_conf_general *general = obj;
-
-	if (!strcasecmp(var->name, "pretty")) {
-		general->format = ast_true(var->value) ?
-			AST_JSON_PRETTY : AST_JSON_COMPACT;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Parses the ast_ari_password_format enum from a config file */
-static int password_format_handler(const struct aco_option *opt,
-	struct ast_variable *var, void *obj)
-{
-	struct ast_ari_conf_user *user = obj;
-
-	if (strcasecmp(var->value, "plain") == 0) {
-		user->password_format = ARI_PASSWORD_FORMAT_PLAIN;
-	} else if (strcasecmp(var->value, "crypt") == 0) {
-		user->password_format = ARI_PASSWORD_FORMAT_CRYPT;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Destructor for \ref ast_ari_conf_user */
-static void user_dtor(void *obj)
-{
-	struct ast_ari_conf_user *user = obj;
-	ast_debug(3, "Disposing of user %s\n", user->username);
-	ast_free(user->username);
-}
-
-/*! \brief Allocate an \ref ast_ari_conf_user for config parsing */
-static void *user_alloc(const char *cat)
-{
-	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
-
-	if (!cat) {
-		return NULL;
-	}
-
-	ast_debug(3, "Allocating user %s\n", cat);
-
-	user = ao2_alloc_options(sizeof(*user), user_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!user) {
-		return NULL;
-	}
-
-	user->username = ast_strdup(cat);
-	if (!user->username) {
-		return NULL;
-	}
-
-	ao2_ref(user, +1);
-	return user;
-}
-
-/*! \brief Sorting function for use with red/black tree */
-static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct ast_ari_conf_user *user_left = obj_left;
-
-	if (flags & OBJ_PARTIAL_KEY) {
-		const char *key_right = obj_right;
-		return strncasecmp(user_left->username, key_right,
-			strlen(key_right));
-	} else if (flags & OBJ_KEY) {
-		const char *key_right = obj_right;
-		return strcasecmp(user_left->username, key_right);
-	} else {
-		const struct ast_ari_conf_user *user_right = obj_right;
-		const char *key_right = user_right->username;
-		return strcasecmp(user_left->username, key_right);
-	}
-}
-
-/*! \brief \ref aco_type item_find function */
-static void *user_find(struct ao2_container *tmp_container, const char *cat)
-{
-	if (!cat) {
-		return NULL;
-	}
-
-	return ao2_find(tmp_container, cat, OBJ_KEY);
-}
-
-static struct aco_type user_option = {
-	.type = ACO_ITEM,
-	.name = "user",
-	.category_match = ACO_BLACKLIST,
-	.category = "^general$",
-	.matchfield = "type",
-	.matchvalue = "user",
-	.item_alloc = user_alloc,
-	.item_find = user_find,
-	.item_offset = offsetof(struct ast_ari_conf, users),
-};
-
-static struct aco_type *user[] = ACO_TYPES(&user_option);
-
-/*! \brief \ref ast_ari_conf destructor. */
-static void conf_destructor(void *obj)
-{
-	struct ast_ari_conf *cfg = obj;
-
-	ast_string_field_free_memory(cfg->general);
-
-	ao2_cleanup(cfg->general);
-	ao2_cleanup(cfg->users);
-}
-
-/*! \brief Allocate an \ref ast_ari_conf for config parsing */
-static void *conf_alloc(void)
-{
-	RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
-
-	cfg = ao2_alloc_options(sizeof(*cfg), conf_destructor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!cfg) {
-		return NULL;
-	}
-
-	cfg->general = ao2_alloc_options(sizeof(*cfg->general), NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!cfg->general) {
-		return NULL;
-	}
-	aco_set_defaults(&general_option, "general", cfg->general);
-
-	if (ast_string_field_init(cfg->general, 64)) {
-		return NULL;
-	}
-
-	cfg->users = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, user_sort_cmp, NULL);
-
-	ao2_ref(cfg, +1);
-	return cfg;
-}
-
-#define CONF_FILENAME "ari.conf"
-
-/*! \brief The conf file that's processed for the module. */
-static struct aco_file conf_file = {
-	/*! The config file name. */
-	.filename = CONF_FILENAME,
-	/*! The mapping object types to be processed. */
-	.types = ACO_TYPES(&general_option, &user_option),
-};
-
-CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
-		     .files = ACO_FILES(&conf_file));
-
-struct ast_ari_conf *ast_ari_config_get(void)
-{
-	struct ast_ari_conf *res = ao2_global_obj_ref(confs);
-	if (!res) {
-		ast_log(LOG_ERROR,
-			"Error obtaining config from " CONF_FILENAME "\n");
-	}
-	return res;
-}
-
-struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
-	const char *password)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
-	int is_valid = 0;
-
-	conf = ast_ari_config_get();
-	if (!conf) {
-		return NULL;
-	}
-
-	user = ao2_find(conf->users, username, OBJ_KEY);
-	if (!user) {
-		return NULL;
-	}
-
-	if (ast_strlen_zero(user->password)) {
-		ast_log(LOG_WARNING,
-			"User '%s' missing password; authentication failed\n",
-			user->username);
-		return NULL;
-	}
-
-	switch (user->password_format) {
-	case ARI_PASSWORD_FORMAT_PLAIN:
-		is_valid = strcmp(password, user->password) == 0;
-		break;
-	case ARI_PASSWORD_FORMAT_CRYPT:
-		is_valid = ast_crypt_validate(password, user->password);
-		break;
-	}
-
-	if (!is_valid) {
-		return NULL;
-	}
-
-	ao2_ref(user, +1);
-	return user;
-}
-
-/*! \brief Callback to validate a user object */
-static int validate_user_cb(void *obj, void *arg, int flags)
-{
-	struct ast_ari_conf_user *user = obj;
-
-	if (ast_strlen_zero(user->password)) {
-		ast_log(LOG_WARNING, "User '%s' missing password\n",
-			user->username);
-	}
-
-	return 0;
-}
-
-/*! \brief Load (or reload) configuration. */
-static int process_config(int reload)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-
-	switch (aco_process_config(&cfg_info, reload)) {
-	case ACO_PROCESS_ERROR:
-		return -1;
-	case ACO_PROCESS_OK:
-	case ACO_PROCESS_UNCHANGED:
-		break;
-	}
-
-	conf = ast_ari_config_get();
-	if (!conf) {
-		ast_assert(0); /* We just configured; it should be there */
-		return -1;
-	}
-
-	if (conf->general->enabled) {
-		if (ao2_container_count(conf->users) == 0) {
-			ast_log(LOG_ERROR, "No configured users for ARI\n");
-		} else {
-			ao2_callback(conf->users, OBJ_NODATA, validate_user_cb, NULL);
-		}
-	}
-
-	return 0;
-}
-
-int ast_ari_config_init(void)
-{
-	if (aco_info_init(&cfg_info)) {
-		aco_info_destroy(&cfg_info);
-		return -1;
-	}
-
-	aco_option_register(&cfg_info, "enabled", ACO_EXACT, general_options,
-		"yes", OPT_BOOL_T, 1,
-		FLDSET(struct ast_ari_conf_general, enabled));
-	aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
-		general_options, "no",  encoding_format_handler, 0);
-	aco_option_register(&cfg_info, "auth_realm", ACO_EXACT, general_options,
-		"Asterisk REST Interface", OPT_CHAR_ARRAY_T, 0,
-		FLDSET(struct ast_ari_conf_general, auth_realm),
-		ARI_AUTH_REALM_LEN);
-	aco_option_register(&cfg_info, "allowed_origins", ACO_EXACT, general_options,
-		"", OPT_STRINGFIELD_T, 0,
-		STRFLDSET(struct ast_ari_conf_general, allowed_origins));
-	aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
-		AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE,
-		FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX);
-
-	aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
-		OPT_NOOP_T, 0, 0);
-	aco_option_register(&cfg_info, "read_only", ACO_EXACT, user,
-		"no", OPT_BOOL_T, 1,
-		FLDSET(struct ast_ari_conf_user, read_only));
-	aco_option_register(&cfg_info, "password", ACO_EXACT, user,
-		"", OPT_CHAR_ARRAY_T, 0,
-		FLDSET(struct ast_ari_conf_user, password), ARI_PASSWORD_LEN);
-	aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
-		user, "plain",  password_format_handler, 0);
-
-	return process_config(0);
-}
-
-int ast_ari_config_reload(void)
-{
-	return process_config(1);
-}
-
-void ast_ari_config_destroy(void)
-{
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(confs);
-}
diff --git a/res/ari/internal.h b/res/ari/internal.h
deleted file mode 100644
index 93ea0b7..0000000
--- a/res/ari/internal.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef ARI_INTERNAL_H_
-#define ARI_INTERNAL_H_
-
-/*! \file
- *
- * \brief Internal API's for res_ari.
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk/http.h"
-#include "asterisk/json.h"
-#include "asterisk/stringfields.h"
-
-/*! @{ */
-
-/*!
- * \brief Register CLI commands for ARI.
- *
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int ast_ari_cli_register(void);
-
-/*!
- * \brief Unregister CLI commands for ARI.
- */
-void ast_ari_cli_unregister(void);
-
-/*! @} */
-
-/*! @{ */
-
-struct ast_ari_conf_general;
-
-/*! \brief All configuration options for ARI. */
-struct ast_ari_conf {
-	/*! The general section configuration options. */
-	struct ast_ari_conf_general *general;
-	/*! Configured users */
-	struct ao2_container *users;
-};
-
-/*! Max length for auth_realm field */
-#define ARI_AUTH_REALM_LEN 80
-
-/*! \brief Global configuration options for ARI. */
-struct ast_ari_conf_general {
-	/*! Enabled by default, disabled if false. */
-	int enabled;
-	/*! Write timeout for websocket connections */
-	int write_timeout;
-	/*! Encoding format used during output (default compact). */
-	enum ast_json_encoding_format format;
-	/*! Authentication realm */
-	char auth_realm[ARI_AUTH_REALM_LEN];
-
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(allowed_origins);
-	);
-};
-
-/*! \brief Password format */
-enum ast_ari_password_format {
-	/*! \brief Plaintext password */
-	ARI_PASSWORD_FORMAT_PLAIN,
-	/*! crypt(3) password */
-	ARI_PASSWORD_FORMAT_CRYPT,
-};
-
-/*!
- * \brief User's password mx length.
- *
- * If 256 seems like a lot, a crypt SHA-512 has over 106 characters.
- */
-#define ARI_PASSWORD_LEN 256
-
-/*! \brief Per-user configuration options */
-struct ast_ari_conf_user {
-	/*! Username for authentication */
-	char *username;
-	/*! User's password. */
-	char password[ARI_PASSWORD_LEN];
-	/*! Format for the password field */
-	enum ast_ari_password_format password_format;
-	/*! If true, user cannot execute change operations */
-	int read_only;
-};
-
-/*!
- * \brief Initialize the ARI configuration
- */
-int ast_ari_config_init(void);
-
-/*!
- * \brief Reload the ARI configuration
- */
-int ast_ari_config_reload(void);
-
-/*!
- * \brief Destroy the ARI configuration
- */
-void ast_ari_config_destroy(void);
-
-/*!
- * \brief Get the current ARI configuration.
- *
- * This is an immutable object, so don't modify it. It is AO2 managed, so
- * ao2_cleanup() when you're done with it.
- *
- * \return ARI configuration object.
- * \return \c NULL on error.
- */
-struct ast_ari_conf *ast_ari_config_get(void);
-
-/*!
- * \brief Validated a user's credentials.
- *
- * \param username Name of the user.
- * \param password User's password.
- * \return User object.
- * \return \c NULL if username or password is invalid.
- */
-struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
-	const char *password);
-
-/*! @} */
-
-/* Forward-declare websocket structs. This avoids including http_websocket.h,
- * which causes optional_api stuff to happen, which makes optional_api more
- * difficult to debug. */
-
-struct ast_websocket_server;
-
-/*!
- * \brief Wrapper for invoking the websocket code for an incoming connection.
- *
- * \param ws_server WebSocket server to invoke.
- * \param ser HTTP session.
- * \param uri Requested URI.
- * \param method Requested HTTP method.
- * \param get_params Parsed query parameters.
- * \param headers Parsed HTTP headers.
- */
-void ari_handle_websocket(struct ast_websocket_server *ws_server,
-	struct ast_tcptls_session_instance *ser, const char *uri,
-	enum ast_http_method method, struct ast_variable *get_params,
-	struct ast_variable *headers);
-
-#endif /* ARI_INTERNAL_H_ */
diff --git a/res/ari/resource_applications.c b/res/ari/resource_applications.c
deleted file mode 100644
index 2cf7ac5..0000000
--- a/res/ari/resource_applications.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/applications.{format} implementation - Stasis application
- * resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405326 $")
-
-#include "asterisk/stasis_app.h"
-#include "resource_applications.h"
-
-static int append_json(void *obj, void *arg, int flags)
-{
-	const char *app = obj;
-	struct ast_json *array = arg;
-
-	ast_json_array_append(array, stasis_app_to_json(app));
-
-	return 0;
-}
-
-void ast_ari_applications_list(struct ast_variable *headers,
-	struct ast_ari_applications_list_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	size_t count;
-
-	apps = stasis_app_get_all();
-	json = ast_json_array_create();
-	if (!apps || !json) {
-		ast_ari_response_error(response, 500, "Internal Server Error",
-			"Allocation failed");
-		return;
-	}
-
-	ao2_lock(apps);
-	count = ao2_container_count(apps);
-	ao2_callback(apps, OBJ_NOLOCK | OBJ_NODATA, append_json, json);
-	ao2_lock(apps);
-
-	if (count != ast_json_array_size(json)) {
-		ast_ari_response_error(response, 500, "Internal Server Error",
-			"Allocation failed");
-		return;
-	}
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_applications_get(struct ast_variable *headers,
-	struct ast_ari_applications_get_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-
-	json = stasis_app_to_json(args->application_name);
-
-	if (!json) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Application not found");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-void ast_ari_applications_subscribe(struct ast_variable *headers,
-	struct ast_ari_applications_subscribe_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	enum stasis_app_subscribe_res res;
-
-	if (args->event_source_count <= 0) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Missing parameter eventSource");
-		return;
-	}
-
-	if (ast_strlen_zero(args->application_name)) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Missing parameter applicationName");
-		return;
-	}
-
-	res = stasis_app_subscribe(args->application_name, args->event_source,
-		args->event_source_count, &json);
-
-	switch (res) {
-	case STASIS_ASR_OK:
-		ast_ari_response_ok(response, ast_json_ref(json));
-		break;
-	case STASIS_ASR_APP_NOT_FOUND:
-		ast_ari_response_error(response, 404, "Not Found",
-			"Application not found");
-		break;
-	case STASIS_ASR_EVENT_SOURCE_NOT_FOUND:
-		ast_ari_response_error(response, 422, "Unprocessable Entity",
-			"Event source does not exist");
-		break;
-	case STASIS_ASR_EVENT_SOURCE_BAD_SCHEME:
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Invalid event source URI scheme");
-		break;
-	case STASIS_ASR_INTERNAL_ERROR:
-		ast_ari_response_error(response, 500, "Internal Server Error",
-			"Error processing request");
-		break;
-	}
-}
-
-void ast_ari_applications_unsubscribe(struct ast_variable *headers,
-	struct ast_ari_applications_unsubscribe_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	enum stasis_app_subscribe_res res;
-
-	if (args->event_source_count == 0) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Missing parameter eventSource");
-		return;
-	}
-
-	res = stasis_app_unsubscribe(args->application_name, args->event_source,
-		args->event_source_count, &json);
-
-	switch (res) {
-	case STASIS_ASR_OK:
-		ast_ari_response_ok(response, ast_json_ref(json));
-		break;
-	case STASIS_ASR_APP_NOT_FOUND:
-		ast_ari_response_error(response, 404, "Not Found",
-			"Application not found");
-		break;
-	case STASIS_ASR_EVENT_SOURCE_NOT_FOUND:
-		ast_ari_response_error(response, 422, "Unprocessable Entity",
-			"Event source was not subscribed to");
-		break;
-	case STASIS_ASR_EVENT_SOURCE_BAD_SCHEME:
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Invalid event source URI scheme");
-		break;
-	case STASIS_ASR_INTERNAL_ERROR:
-		ast_ari_response_error(response, 500, "Internal Server Error",
-			"Error processing request");
-	}
-}
diff --git a/res/ari/resource_applications.h b/res/ari/resource_applications.h
deleted file mode 100644
index be62e9d..0000000
--- a/res/ari/resource_applications.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_applications.c
- *
- * Stasis application resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_APPLICATIONS_H
-#define _ASTERISK_RESOURCE_APPLICATIONS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_applications_list() */
-struct ast_ari_applications_list_args {
-};
-/*!
- * \brief List all applications.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_applications_list(struct ast_variable *headers, struct ast_ari_applications_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_applications_get() */
-struct ast_ari_applications_get_args {
-	/*! Application's name */
-	const char *application_name;
-};
-/*!
- * \brief Get details of an application.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_applications_get(struct ast_variable *headers, struct ast_ari_applications_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_applications_subscribe() */
-struct ast_ari_applications_subscribe_args {
-	/*! Application's name */
-	const char *application_name;
-	/*! Array of URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}[/{resource}], deviceState:{deviceName} */
-	const char **event_source;
-	/*! Length of event_source array. */
-	size_t event_source_count;
-	/*! Parsing context for event_source. */
-	char *event_source_parse;
-};
-/*!
- * \brief Body parsing function for /applications/{applicationName}/subscription.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_applications_subscribe_parse_body(
-	struct ast_json *body,
-	struct ast_ari_applications_subscribe_args *args);
-
-/*!
- * \brief Subscribe an application to a event source.
- *
- * Returns the state of the application after the subscriptions have changed
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_applications_subscribe(struct ast_variable *headers, struct ast_ari_applications_subscribe_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_applications_unsubscribe() */
-struct ast_ari_applications_unsubscribe_args {
-	/*! Application's name */
-	const char *application_name;
-	/*! Array of URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}[/{resource}], deviceState:{deviceName} */
-	const char **event_source;
-	/*! Length of event_source array. */
-	size_t event_source_count;
-	/*! Parsing context for event_source. */
-	char *event_source_parse;
-};
-/*!
- * \brief Body parsing function for /applications/{applicationName}/subscription.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_applications_unsubscribe_parse_body(
-	struct ast_json *body,
-	struct ast_ari_applications_unsubscribe_args *args);
-
-/*!
- * \brief Unsubscribe an application from an event source.
- *
- * Returns the state of the application after the subscriptions have changed
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_applications_unsubscribe(struct ast_variable *headers, struct ast_ari_applications_unsubscribe_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_APPLICATIONS_H */
diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c
deleted file mode 100644
index 0466e64..0000000
--- a/res/ari/resource_asterisk.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/* -*- C -*-
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation for ARI stubs.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 402529 $")
-
-#include "asterisk/ast_version.h"
-#include "asterisk/buildinfo.h"
-#include "asterisk/paths.h"
-#include "asterisk/pbx.h"
-#include "resource_asterisk.h"
-
-void ast_ari_asterisk_get_info(struct ast_variable *headers,
-	struct ast_ari_asterisk_get_info_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	int show_all = args->only_count == 0;
-	int show_build = show_all;
-	int show_system = show_all;
-	int show_config = show_all;
-	int show_status = show_all;
-	size_t i;
-	int res = 0;
-
-	for (i = 0; i < args->only_count; ++i) {
-		if (strcasecmp("build", args->only[i]) == 0) {
-			show_build = 1;
-		} else if (strcasecmp("system", args->only[i]) == 0) {
-			show_system = 1;
-		} else if (strcasecmp("config", args->only[i]) == 0) {
-			show_config = 1;
-		} else if (strcasecmp("status", args->only[i]) == 0) {
-			show_status = 1;
-		} else {
-			ast_log(LOG_WARNING, "Unrecognized info section '%s'\n",
-				args->only[i]);
-		}
-	}
-
-	json = ast_json_object_create();
-
-	if (show_build) {
-		res |= ast_json_object_set(json, "build",
-			ast_json_pack(
-				"{ s: s, s: s, s: s,"
-				"  s: s, s: s, s: s }",
-
-				"os", ast_build_os,
-				"kernel", ast_build_kernel,
-				"machine", ast_build_machine,
-
-				"options", AST_BUILDOPTS,
-				"date", ast_build_date,
-				"user", ast_build_user));
-	}
-
-	if (show_system) {
-		char eid_str[128];
-
-		ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
-
-		res |= ast_json_object_set(json, "system",
-			ast_json_pack("{ s: s, s: s }",
-				"version", ast_get_version(),
-				"entity_id", eid_str));
-	}
-
-	if (show_config) {
-		struct ast_json *config = ast_json_pack(
-			"{ s: s, s: s,"
-			" s: { s: s, s: s } }",
-
-			"name", ast_config_AST_SYSTEM_NAME,
-			"default_language", ast_defaultlanguage,
-
-			"setid",
-			"user", ast_config_AST_RUN_USER,
-			"group", ast_config_AST_RUN_GROUP);
-
-		res |= ast_json_object_set(json, "config", config);
-
-		if (ast_option_maxcalls) {
-			res |= ast_json_object_set(config, "max_channels",
-				ast_json_integer_create(ast_option_maxcalls));
-		}
-
-		if (ast_option_maxfiles) {
-			res |= ast_json_object_set(config, "max_open_files",
-				ast_json_integer_create(ast_option_maxfiles));
-		}
-
-		if (ast_option_maxload) {
-			res |= ast_json_object_set(config, "max_load",
-				ast_json_real_create(ast_option_maxload));
-		}
-	}
-
-	if (show_status) {
-		res |= ast_json_object_set(json, "status",
-			ast_json_pack("{ s: o, s: o }",
-				"startup_time",
-				ast_json_timeval(ast_startuptime, NULL),
-				"last_reload_time",
-				ast_json_timeval(ast_lastreloadtime, NULL)));
-	}
-
-	if (res != 0) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_asterisk_get_global_var(struct ast_variable *headers,
-	struct ast_ari_asterisk_get_global_var_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
-
-	const char *value;
-
-	ast_assert(response != NULL);
-
-	if (ast_strlen_zero(args->variable)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Variable name is required");
-		return;
-	}
-
-	tmp = ast_str_create(32);
-	if (!tmp) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	value = ast_str_retrieve_variable(&tmp, 0, NULL, NULL, args->variable);
-
-	if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_asterisk_set_global_var(struct ast_variable *headers,
-	struct ast_ari_asterisk_set_global_var_args *args,
-	struct ast_ari_response *response)
-{
-	ast_assert(response != NULL);
-
-	if (ast_strlen_zero(args->variable)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Variable name is required");
-		return;
-	}
-
-	pbx_builtin_setvar_helper(NULL, args->variable, args->value);
-
-	ast_ari_response_no_content(response);
-}
diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h
deleted file mode 100644
index dc4b183..0000000
--- a/res/ari/resource_asterisk.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_asterisk.c
- *
- * Asterisk resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_ASTERISK_H
-#define _ASTERISK_RESOURCE_ASTERISK_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_asterisk_get_info() */
-struct ast_ari_asterisk_get_info_args {
-	/*! Array of Filter information returned */
-	const char **only;
-	/*! Length of only array. */
-	size_t only_count;
-	/*! Parsing context for only. */
-	char *only_parse;
-};
-/*!
- * \brief Body parsing function for /asterisk/info.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_asterisk_get_info_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_get_info_args *args);
-
-/*!
- * \brief Gets Asterisk system information.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_asterisk_get_info(struct ast_variable *headers, struct ast_ari_asterisk_get_info_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_asterisk_get_global_var() */
-struct ast_ari_asterisk_get_global_var_args {
-	/*! The variable to get */
-	const char *variable;
-};
-/*!
- * \brief Body parsing function for /asterisk/variable.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_asterisk_get_global_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_get_global_var_args *args);
-
-/*!
- * \brief Get the value of a global variable.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_asterisk_get_global_var(struct ast_variable *headers, struct ast_ari_asterisk_get_global_var_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_asterisk_set_global_var() */
-struct ast_ari_asterisk_set_global_var_args {
-	/*! The variable to set */
-	const char *variable;
-	/*! The value to set the variable to */
-	const char *value;
-};
-/*!
- * \brief Body parsing function for /asterisk/variable.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_asterisk_set_global_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_set_global_var_args *args);
-
-/*!
- * \brief Set the value of a global variable.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_asterisk_set_global_var(struct ast_variable *headers, struct ast_ari_asterisk_set_global_var_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_ASTERISK_H */
diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c
deleted file mode 100644
index 3283dec..0000000
--- a/res/ari/resource_bridges.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation for ARI stubs.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420796 $")
-
-#include "resource_bridges.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/stasis_app_playback.h"
-#include "asterisk/stasis_app_recording.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/channel.h"
-#include "asterisk/bridge.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/file.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/format_cache.h"
-
-/*!
- * \brief Finds a bridge, filling the response with an error, if appropriate.
- *
- * \param[out] response Response to fill with an error if control is not found.
- * \param bridge_id ID of the bridge to lookup.
- *
- * \return Bridget.
- * \return \c NULL if bridge does not exist.
- */
-static struct ast_bridge *find_bridge(
-	struct ast_ari_response *response,
-	const char *bridge_id)
-{
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	bridge = stasis_app_bridge_find_by_id(bridge_id);
-	if (bridge == NULL) {
-		RAII_VAR(struct ast_bridge_snapshot *, snapshot,
-			ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
-		if (!snapshot) {
-			ast_ari_response_error(response, 404, "Not found",
-				"Bridge not found");
-			return NULL;
-		}
-
-		ast_ari_response_error(response, 409, "Conflict",
-			"Bridge not in Stasis application");
-		return NULL;
-	}
-
-	ao2_ref(bridge, +1);
-	return bridge;
-}
-
-/*!
- * \brief Finds the control object for a channel, filling the response with an
- * error, if appropriate.
- * \param[out] response Response to fill with an error if control is not found.
- * \param channel_id ID of the channel to lookup.
- * \return Channel control object.
- * \return \c NULL if control object does not exist.
- */
-static struct stasis_app_control *find_channel_control(
-	struct ast_ari_response *response,
-	const char *channel_id)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	control = stasis_app_control_find_by_channel_id(channel_id);
-	if (control == NULL) {
-		/* Distinguish between 400 and 422 errors */
-		RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL,
-			ao2_cleanup);
-		snapshot = ast_channel_snapshot_get_latest(channel_id);
-		if (snapshot == NULL) {
-			ast_log(LOG_DEBUG, "Couldn't find '%s'\n", channel_id);
-			ast_ari_response_error(response, 400, "Bad Request",
-				"Channel not found");
-			return NULL;
-		}
-
-		ast_log(LOG_DEBUG, "Found non-stasis '%s'\n", channel_id);
-		ast_ari_response_error(response, 422, "Unprocessable Entity",
-			"Channel not in Stasis application");
-		return NULL;
-	}
-
-	ao2_ref(control, +1);
-	return control;
-}
-
-struct control_list {
-	size_t count;
-	struct stasis_app_control *controls[];
-};
-
-static void control_list_dtor(void *obj) {
-	struct control_list *list = obj;
-	size_t i;
-
-	for (i = 0; i < list->count; ++i) {
-		ao2_cleanup(list->controls[i]);
-		list->controls[i] = NULL;
-	}
-}
-
-static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
-	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
-	size_t i;
-
-	if (count == 0 || !channels) {
-		ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
-		return NULL;
-	}
-
-	list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
-	if (!list) {
-		ast_ari_response_alloc_failed(response);
-		return NULL;
-	}
-
-	for (i = 0; i < count; ++i) {
-		if (ast_strlen_zero(channels[i])) {
-			continue;
-		}
-		list->controls[list->count] =
-			find_channel_control(response, channels[i]);
-		if (!list->controls[list->count]) {
-			/* response filled in by find_channel_control() */
-			return NULL;
-		}
-		++list->count;
-	}
-
-	if (list->count == 0) {
-		ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
-		return NULL;
-	}
-
-	ao2_ref(list, +1);
-	return list;
-}
-
-static int check_add_remove_channel(struct ast_ari_response *response,
-				    struct stasis_app_control *control,
-				    enum stasis_app_control_channel_result result)
-{
-	switch (result) {
-	case STASIS_APP_CHANNEL_RECORDING :
-		ast_ari_response_error(
-			response, 409, "Conflict", "Channel %s currently recording",
-			stasis_app_control_get_channel_id(control));
-		return -1;
-	case STASIS_APP_CHANNEL_OKAY:
-		return 0;
-	}
-	return 0;
-}
-
-void ast_ari_bridges_add_channel(struct ast_variable *headers,
-	struct ast_ari_bridges_add_channel_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
-	size_t i;
-	int has_error = 0;
-
-	if (!bridge) {
-		/* Response filled in by find_bridge() */
-		return;
-	}
-
-	list = control_list_create(response, args->channel_count, args->channel);
-	if (!list) {
-		/* Response filled in by control_list_create() */
-		return;
-	}
-
-	for (i = 0; i < list->count; ++i) {
-		stasis_app_control_clear_roles(list->controls[i]);
-		if (!ast_strlen_zero(args->role)) {
-			if (stasis_app_control_add_role(list->controls[i], args->role)) {
-				ast_ari_response_alloc_failed(response);
-				return;
-			}
-		}
-	}
-
-	for (i = 0; i < list->count; ++i) {
-		if ((has_error = check_add_remove_channel(response, list->controls[i],
-			     stasis_app_control_add_channel_to_bridge(
-				    list->controls[i], bridge)))) {
-			break;
-		}
-	}
-
-	if (!has_error) {
-		ast_ari_response_no_content(response);
-	}
-}
-
-void ast_ari_bridges_remove_channel(struct ast_variable *headers,
-	struct ast_ari_bridges_remove_channel_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
-	size_t i;
-
-	if (!bridge) {
-		/* Response filled in by find_bridge() */
-		return;
-	}
-
-	list = control_list_create(response, args->channel_count, args->channel);
-	if (!list) {
-		/* Response filled in by control_list_create() */
-		return;
-	}
-
-	/* Make sure all of the channels are in this bridge */
-	for (i = 0; i < list->count; ++i) {
-		if (stasis_app_get_bridge(list->controls[i]) != bridge) {
-			ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
-				args->channel[i], args->bridge_id);
-			ast_ari_response_error(response, 422,
-				"Unprocessable Entity",
-				"Channel not in this bridge");
-			return;
-		}
-	}
-
-	/* Now actually remove it */
-	for (i = 0; i < list->count; ++i) {
-		stasis_app_control_remove_channel_from_bridge(list->controls[i],
-			bridge);
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-struct bridge_channel_control_thread_data {
-	struct ast_channel *bridge_channel;
-	struct stasis_app_control *control;
-	struct stasis_forward *forward;
-};
-
-static void *bridge_channel_control_thread(void *data)
-{
-	struct bridge_channel_control_thread_data *thread_data = data;
-	struct ast_channel *bridge_channel = thread_data->bridge_channel;
-	struct stasis_app_control *control = thread_data->control;
-	struct stasis_forward *forward = thread_data->forward;
-
-	RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
-
-	if (callid) {
-		ast_callid_threadassoc_add(callid);
-	}
-
-	ast_free(thread_data);
-	thread_data = NULL;
-
-	stasis_app_control_execute_until_exhausted(bridge_channel, control);
-
-	ast_hangup(bridge_channel);
-	ao2_cleanup(control);
-	stasis_forward_cancel(forward);
-	return NULL;
-}
-
-static struct ast_channel *prepare_bridge_media_channel(const char *type)
-{
-	RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
-	struct ast_channel *chan;
-
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!cap) {
-		return NULL;
-	}
-
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
-	if (!chan) {
-		return NULL;
-	}
-
-	if (stasis_app_channel_unreal_set_internal(chan)) {
-		ast_channel_cleanup(chan);
-		return NULL;
-	}
-	return chan;
-}
-
-/*!
- * \brief Performs common setup for a bridge playback operation
- * with both new controls and when existing controls are  found.
- *
- * \param args_media media string split from arguments
- * \param args_lang language string split from arguments
- * \param args_offset_ms milliseconds offset split from arguments
- * \param args_playback_id string to use for playback split from
- *        arguments (null valid)
- * \param response ARI response being built
- * \param bridge Bridge the playback is being peformed on
- * \param control Control being used for the playback channel
- * \param json contents of the response to ARI
- * \param playback_url stores playback URL for use with response
- *
- * \retval -1 operation failed
- * \retval operation was successful
- */
-static int ari_bridges_play_helper(const char *args_media,
-	const char *args_lang,
-	int args_offset_ms,
-	int args_skipms,
-	const char *args_playback_id,
-	struct ast_ari_response *response,
-	struct ast_bridge *bridge,
-	struct stasis_app_control *control,
-	struct ast_json **json,
-	char **playback_url)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-
-	const char *language;
-
-	snapshot = stasis_app_control_get_snapshot(control);
-	if (!snapshot) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Failed to get control snapshot");
-		return -1;
-	}
-
-	language = S_OR(args_lang, snapshot->language);
-
-	playback = stasis_app_control_play_uri(control, args_media, language,
-		bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
-		args_offset_ms, args_playback_id);
-
-	if (!playback) {
-		ast_ari_response_alloc_failed(response);
-		return -1;
-	}
-
-	if (ast_asprintf(playback_url, "/playback/%s",
-			stasis_app_playback_get_id(playback)) == -1) {
-		playback_url = NULL;
-		ast_ari_response_alloc_failed(response);
-		return -1;
-	}
-
-	*json = stasis_app_playback_to_json(playback);
-	if (!*json) {
-		ast_ari_response_alloc_failed(response);
-		return -1;
-	}
-
-	return 0;
-}
-
-static void ari_bridges_play_new(const char *args_media,
-	const char *args_lang,
-	int args_offset_ms,
-	int args_skipms,
-	const char *args_playback_id,
-	struct ast_ari_response *response,
-	struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
-	RAII_VAR(char *, playback_url, NULL, ast_free);
-
-	struct stasis_topic *channel_topic;
-	struct stasis_topic *bridge_topic;
-	struct bridge_channel_control_thread_data *thread_data;
-	pthread_t threadid;
-
-	if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Could not create playback channel");
-		return;
-	}
-	ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
-
-	bridge_topic = ast_bridge_topic(bridge);
-	channel_topic = ast_channel_topic(play_channel);
-
-	/* Forward messages from the playback channel topic to the bridge topic so that anything listening for
-	 * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
-	 * go to this channel will be suppressed since the channel is marked as internal.
-	 */
-	if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
-		return;
-	}
-
-	if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
-		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Failed to put playback channel into the bridge");
-		return;
-	}
-
-	control = stasis_app_control_create(play_channel);
-	if (control == NULL) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ao2_lock(control);
-	if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
-			args_skipms, args_playback_id, response, bridge, control,
-			&json, &playback_url)) {
-		ao2_unlock(control);
-		return;
-	}
-	ao2_unlock(control);
-
-	if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	/* Give play_channel and control reference to the thread data */
-	thread_data = ast_calloc(1, sizeof(*thread_data));
-	if (!thread_data) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	thread_data->bridge_channel = play_channel;
-	thread_data->control = control;
-	thread_data->forward = channel_forward;
-
-	if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
-		ast_ari_response_alloc_failed(response);
-		ast_free(thread_data);
-		return;
-	}
-
-	/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
-	play_channel = NULL;
-	control = NULL;
-	channel_forward = NULL;
-
-	ast_ari_response_created(response, playback_url, ast_json_ref(json));
-}
-
-enum play_found_result {
-	PLAY_FOUND_SUCCESS,
-	PLAY_FOUND_FAILURE,
-	PLAY_FOUND_CHANNEL_UNAVAILABLE,
-};
-
-/*!
- * \brief Performs common setup for a bridge playback operation
- * with both new controls and when existing controls are  found.
- *
- * \param args_media media string split from arguments
- * \param args_lang language string split from arguments
- * \param args_offset_ms milliseconds offset split from arguments
- * \param args_playback_id string to use for playback split from
- *        arguments (null valid)
- * \param response ARI response being built
- * \param bridge Bridge the playback is being peformed on
- * \param found_channel The channel that was found controlling playback
- *
- * \retval PLAY_FOUND_SUCCESS The operation was successful
- * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
- * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
- * the channel requested to playback with is breaking down.
- */
-static enum play_found_result ari_bridges_play_found(const char *args_media,
-	const char *args_lang,
-	int args_offset_ms,
-	int args_skipms,
-	const char *args_playback_id,
-	struct ast_ari_response *response,
-	struct ast_bridge *bridge,
-	struct ast_channel *found_channel)
-{
-	RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(char *, playback_url, NULL, ast_free);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	control = stasis_app_control_find_by_channel(play_channel);
-	if (!control) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Failed to get control snapshot");
-		return PLAY_FOUND_FAILURE;
-	}
-
-	ao2_lock(control);
-	if (stasis_app_control_is_done(control)) {
-		/* We failed to queue the action. Bailout and return that we aren't terminal. */
-		ao2_unlock(control);
-		return PLAY_FOUND_CHANNEL_UNAVAILABLE;
-	}
-
-	if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
-			args_skipms, args_playback_id, response, bridge, control,
-			&json, &playback_url)) {
-		ao2_unlock(control);
-		return PLAY_FOUND_FAILURE;
-	}
-	ao2_unlock(control);
-
-	ast_ari_response_created(response, playback_url, ast_json_ref(json));
-	return PLAY_FOUND_SUCCESS;
-}
-
-static void ari_bridges_handle_play(
-	const char *args_bridge_id,
-	const char *args_media,
-	const char *args_lang,
-	int args_offset_ms,
-	int args_skipms,
-	const char *args_playback_id,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
-	struct ast_channel *play_channel;
-
-	ast_assert(response != NULL);
-
-	if (!bridge) {
-		return;
-	}
-
-	while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
-		/* If ari_bridges_play_found fails because the channel is unavailable for
-		 * playback, The channel will be removed from the playback list soon. We
-		 * can keep trying to get channels from the list until we either get one
-		 * that will work or else there isn't a channel for this bridge anymore,
-		 * in which case we'll revert to ari_bridges_play_new.
-		 */
-		if (ari_bridges_play_found(args_media, args_lang, args_offset_ms,
-				args_skipms, args_playback_id, response,bridge,
-				play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
-			continue;
-		}
-		return;
-	}
-
-	ari_bridges_play_new(args_media, args_lang, args_offset_ms,
-		args_skipms, args_playback_id, response, bridge);
-}
-
-
-void ast_ari_bridges_play(struct ast_variable *headers,
-	struct ast_ari_bridges_play_args *args,
-	struct ast_ari_response *response)
-{
-	ari_bridges_handle_play(args->bridge_id,
-	args->media,
-	args->lang,
-	args->offsetms,
-	args->skipms,
-	args->playback_id,
-	response);
-}
-
-void ast_ari_bridges_play_with_id(struct ast_variable *headers,
-	struct ast_ari_bridges_play_with_id_args *args,
-	struct ast_ari_response *response)
-{
-	ari_bridges_handle_play(args->bridge_id,
-	args->media,
-	args->lang,
-	args->offsetms,
-	args->skipms,
-	args->playback_id,
-	response);
-}
-
-void ast_ari_bridges_record(struct ast_variable *headers,
-	struct ast_ari_bridges_record_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
-	RAII_VAR(char *, recording_url, NULL, ast_free);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
-	RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
-	RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
-
-	struct stasis_topic *channel_topic;
-	struct stasis_topic *bridge_topic;
-	size_t uri_name_maxlen;
-	struct bridge_channel_control_thread_data *thread_data;
-	pthread_t threadid;
-
-	ast_assert(response != NULL);
-
-	if (bridge == NULL) {
-		return;
-	}
-
-	if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error", "Failed to create recording channel");
-		return;
-	}
-
-	bridge_topic = ast_bridge_topic(bridge);
-	channel_topic = ast_channel_topic(record_channel);
-
-	/* Forward messages from the recording channel topic to the bridge topic so that anything listening for
-	 * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
-	 * go to this channel will be suppressed since the channel is marked as internal.
-	 */
-	if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
-		return;
-	}
-
-	if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
-		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-		ast_ari_response_error(
-			response, 500, "Internal Error", "Failed to put recording channel into the bridge");
-		return;
-	}
-
-	control = stasis_app_control_create(record_channel);
-	if (control == NULL) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	options = stasis_app_recording_options_create(args->name, args->format);
-	if (options == NULL) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
-	options->max_silence_seconds = args->max_silence_seconds;
-	options->max_duration_seconds = args->max_duration_seconds;
-	options->terminate_on =
-		stasis_app_recording_termination_parse(args->terminate_on);
-	options->if_exists =
-		stasis_app_recording_if_exists_parse(args->if_exists);
-	options->beep = args->beep;
-
-	if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"terminateOn invalid");
-		return;
-	}
-
-	if (options->if_exists == -1) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"ifExists invalid");
-		return;
-	}
-
-	if (!ast_get_format_for_file_ext(options->format)) {
-		ast_ari_response_error(
-			response, 422, "Unprocessable Entity",
-			"specified format is unknown on this system");
-		return;
-	}
-
-	recording = stasis_app_control_record(control, options);
-	if (recording == NULL) {
-		switch(errno) {
-		case EINVAL:
-			/* While the arguments are invalid, we should have
-			 * caught them prior to calling record.
-			 */
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Error parsing request");
-			break;
-		case EEXIST:
-			ast_ari_response_error(response, 409, "Conflict",
-				"Recording '%s' already exists and can not be overwritten",
-				args->name);
-			break;
-		case ENOMEM:
-			ast_ari_response_alloc_failed(response);
-			break;
-		case EPERM:
-			ast_ari_response_error(
-				response, 400, "Bad Request",
-				"Recording name invalid");
-			break;
-		default:
-			ast_log(LOG_WARNING,
-				"Unrecognized recording error: %s\n",
-				strerror(errno));
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Internal Server Error");
-			break;
-		}
-		return;
-	}
-
-	uri_name_maxlen = strlen(args->name) * 3;
-	uri_encoded_name = ast_malloc(uri_name_maxlen);
-	if (!uri_encoded_name) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-	ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
-
-	if (ast_asprintf(&recording_url, "/recordings/live/%s",
-			uri_encoded_name) == -1) {
-		recording_url = NULL;
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = stasis_app_recording_to_json(recording);
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	thread_data = ast_calloc(1, sizeof(*thread_data));
-	if (!thread_data) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	thread_data->bridge_channel = record_channel;
-	thread_data->control = control;
-	thread_data->forward = channel_forward;
-
-	if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
-		ast_ari_response_alloc_failed(response);
-		ast_free(thread_data);
-		return;
-	}
-
-	/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
-	record_channel = NULL;
-	control = NULL;
-	channel_forward = NULL;
-
-	ast_ari_response_created(response, recording_url, ast_json_ref(json));
-}
-
-void ast_ari_bridges_start_moh(struct ast_variable *headers,
-	struct ast_ari_bridges_start_moh_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	struct ast_channel *moh_channel;
-	const char *moh_class = args->moh_class;
-
-	if (!bridge) {
-		/* The response is provided by find_bridge() */
-		return;
-	}
-
-	moh_channel = stasis_app_bridge_moh_channel(bridge);
-	if (!moh_channel) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_moh_start(moh_channel, moh_class, NULL);
-
-	ast_ari_response_no_content(response);
-
-}
-
-void ast_ari_bridges_stop_moh(struct ast_variable *headers,
-	struct ast_ari_bridges_stop_moh_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-
-	if (!bridge) {
-		/* the response is provided by find_bridge() */
-		return;
-	}
-
-	if (stasis_app_bridge_moh_stop(bridge)) {
-		ast_ari_response_error(
-			response, 409, "Conflict",
-			"Bridge isn't playing music");
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_bridges_get(struct ast_variable *headers,
-	struct ast_ari_bridges_get_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
-	if (!snapshot) {
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Bridge not found");
-		return;
-	}
-
-	ast_ari_response_ok(response,
-		ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
-}
-
-void ast_ari_bridges_destroy(struct ast_variable *headers,
-	struct ast_ari_bridges_destroy_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	if (!bridge) {
-		return;
-	}
-
-	stasis_app_bridge_destroy(args->bridge_id);
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_bridges_list(struct ast_variable *headers,
-	struct ast_ari_bridges_list_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ao2_iterator i;
-	void *obj;
-
-	cache = ast_bridge_cache();
-	if (!cache) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Message bus not initialized");
-		return;
-	}
-	ao2_ref(cache, +1);
-
-	snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
-	if (!snapshots) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = ast_json_array_create();
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	i = ao2_iterator_init(snapshots, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
-		struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
-		struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-
-		if (!json_bridge || ast_json_array_append(json, json_bridge)) {
-			ao2_iterator_destroy(&i);
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_bridges_create(struct ast_variable *headers,
-	struct ast_ari_bridges_create_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (!bridge) {
-		ast_ari_response_error(
-			response, 500, "Internal Error",
-			"Unable to create bridge");
-		return;
-	}
-
-	ast_bridge_lock(bridge);
-	snapshot = ast_bridge_snapshot_create(bridge);
-	ast_bridge_unlock(bridge);
-
-	if (!snapshot) {
-		ast_ari_response_error(
-			response, 500, "Internal Error",
-			"Unable to create snapshot for new bridge");
-		return;
-	}
-
-	ast_ari_response_ok(response,
-		ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
-}
-
-void ast_ari_bridges_create_or_update_with_id(struct ast_variable *headers,
-	struct ast_ari_bridges_create_or_update_with_id_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	if (bridge) {
-		/* update */
-		if (strcmp(args->name, bridge->name)) {
-			ast_ari_response_error(
-				response, 500, "Internal Error",
-				"Changing bridge name is not implemented");
-			return;
-		}
-		if (!ast_strlen_zero(args->type)) {
-			ast_ari_response_error(
-				response, 500, "Internal Error",
-				"Changing bridge type is not implemented");
-			return;
-		}
-		ast_ari_response_ok(response,
-			ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
-		return;
-	}
-
-	bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
-	if (!bridge) {
-		ast_ari_response_error(
-			response, 500, "Internal Error",
-			"Unable to create bridge");
-		return;
-	}
-
-	ast_bridge_lock(bridge);
-	snapshot = ast_bridge_snapshot_create(bridge);
-	ast_bridge_unlock(bridge);
-
-	if (!snapshot) {
-		ast_ari_response_error(
-			response, 500, "Internal Error",
-			"Unable to create snapshot for new bridge");
-		return;
-	}
-
-	ast_ari_response_ok(response,
-		ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
-}
diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h
deleted file mode 100644
index 2b1e787..0000000
--- a/res/ari/resource_bridges.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_bridges.c
- *
- * Bridge resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_BRIDGES_H
-#define _ASTERISK_RESOURCE_BRIDGES_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_bridges_list() */
-struct ast_ari_bridges_list_args {
-};
-/*!
- * \brief List all active bridges in Asterisk.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_create() */
-struct ast_ari_bridges_create_args {
-	/*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media). */
-	const char *type;
-	/*! Unique ID to give to the bridge being created. */
-	const char *bridge_id;
-	/*! Name to give to the bridge being created. */
-	const char *name;
-};
-/*!
- * \brief Body parsing function for /bridges.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_create_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_create_args *args);
-
-/*!
- * \brief Create a new bridge.
- *
- * This bridge persists until it has been shut down, or Asterisk has been shut down.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_create(struct ast_variable *headers, struct ast_ari_bridges_create_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_create_or_update_with_id() */
-struct ast_ari_bridges_create_or_update_with_id_args {
-	/*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media) to set. */
-	const char *type;
-	/*! Unique ID to give to the bridge being created. */
-	const char *bridge_id;
-	/*! Set the name of the bridge. */
-	const char *name;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_create_or_update_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_create_or_update_with_id_args *args);
-
-/*!
- * \brief Create a new bridge or updates an existing one.
- *
- * This bridge persists until it has been shut down, or Asterisk has been shut down.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_create_or_update_with_id(struct ast_variable *headers, struct ast_ari_bridges_create_or_update_with_id_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_get() */
-struct ast_ari_bridges_get_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-};
-/*!
- * \brief Get bridge details.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_get(struct ast_variable *headers, struct ast_ari_bridges_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_destroy() */
-struct ast_ari_bridges_destroy_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-};
-/*!
- * \brief Shut down a bridge.
- *
- * If any channels are in this bridge, they will be removed and resume whatever they were doing beforehand.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_destroy(struct ast_variable *headers, struct ast_ari_bridges_destroy_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_add_channel() */
-struct ast_ari_bridges_add_channel_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Array of Ids of channels to add to bridge */
-	const char **channel;
-	/*! Length of channel array. */
-	size_t channel_count;
-	/*! Parsing context for channel. */
-	char *channel_parse;
-	/*! Channel's role in the bridge */
-	const char *role;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/addChannel.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_add_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_add_channel_args *args);
-
-/*!
- * \brief Add a channel to a bridge.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_add_channel(struct ast_variable *headers, struct ast_ari_bridges_add_channel_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_remove_channel() */
-struct ast_ari_bridges_remove_channel_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Array of Ids of channels to remove from bridge */
-	const char **channel;
-	/*! Length of channel array. */
-	size_t channel_count;
-	/*! Parsing context for channel. */
-	char *channel_parse;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/removeChannel.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_remove_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_remove_channel_args *args);
-
-/*!
- * \brief Remove a channel from a bridge.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_remove_channel(struct ast_variable *headers, struct ast_ari_bridges_remove_channel_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_start_moh() */
-struct ast_ari_bridges_start_moh_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Channel's id */
-	const char *moh_class;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/moh.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_start_moh_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_start_moh_args *args);
-
-/*!
- * \brief Play music on hold to a bridge or change the MOH class that is playing.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_start_moh(struct ast_variable *headers, struct ast_ari_bridges_start_moh_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_stop_moh() */
-struct ast_ari_bridges_stop_moh_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-};
-/*!
- * \brief Stop playing music on hold to a bridge.
- *
- * This will only stop music on hold being played via POST bridges/{bridgeId}/moh.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_stop_moh(struct ast_variable *headers, struct ast_ari_bridges_stop_moh_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_play() */
-struct ast_ari_bridges_play_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Media's URI to play. */
-	const char *media;
-	/*! For sounds, selects language for sound. */
-	const char *lang;
-	/*! Number of media to skip before playing. */
-	int offsetms;
-	/*! Number of milliseconds to skip for forward/reverse operations. */
-	int skipms;
-	/*! Playback Id. */
-	const char *playback_id;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/play.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_play_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_play_args *args);
-
-/*!
- * \brief Start playback of media on a bridge.
- *
- * The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_play(struct ast_variable *headers, struct ast_ari_bridges_play_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_play_with_id() */
-struct ast_ari_bridges_play_with_id_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Playback ID. */
-	const char *playback_id;
-	/*! Media's URI to play. */
-	const char *media;
-	/*! For sounds, selects language for sound. */
-	const char *lang;
-	/*! Number of media to skip before playing. */
-	int offsetms;
-	/*! Number of milliseconds to skip for forward/reverse operations. */
-	int skipms;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/play/{playbackId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_play_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_play_with_id_args *args);
-
-/*!
- * \brief Start playback of media on a bridge.
- *
- * The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_play_with_id(struct ast_variable *headers, struct ast_ari_bridges_play_with_id_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_bridges_record() */
-struct ast_ari_bridges_record_args {
-	/*! Bridge's id */
-	const char *bridge_id;
-	/*! Recording's filename */
-	const char *name;
-	/*! Format to encode audio in */
-	const char *format;
-	/*! Maximum duration of the recording, in seconds. 0 for no limit. */
-	int max_duration_seconds;
-	/*! Maximum duration of silence, in seconds. 0 for no limit. */
-	int max_silence_seconds;
-	/*! Action to take if a recording with the same name already exists. */
-	const char *if_exists;
-	/*! Play beep when recording begins */
-	int beep;
-	/*! DTMF input to terminate recording. */
-	const char *terminate_on;
-};
-/*!
- * \brief Body parsing function for /bridges/{bridgeId}/record.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_bridges_record_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_record_args *args);
-
-/*!
- * \brief Start a recording.
- *
- * This records the mixed audio from all channels participating in this bridge.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_bridges_record(struct ast_variable *headers, struct ast_ari_bridges_record_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_BRIDGES_H */
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
deleted file mode 100644
index 4159e93..0000000
--- a/res/ari/resource_channels.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation for ARI stubs.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis_app_playback</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421312 $")
-
-#include "asterisk/file.h"
-#include "asterisk/pbx.h"
-#include "asterisk/bridge.h"
-#include "asterisk/callerid.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/stasis_app_playback.h"
-#include "asterisk/stasis_app_recording.h"
-#include "asterisk/stasis_app_snoop.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/causes.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/core_local.h"
-#include "resource_channels.h"
-
-#include <limits.h>
-
-/*!
- * \brief Finds the control object for a channel, filling the response with an
- * error, if appropriate.
- * \param[out] response Response to fill with an error if control is not found.
- * \param channel_id ID of the channel to lookup.
- * \return Channel control object.
- * \return \c NULL if control object does not exist.
- */
-static struct stasis_app_control *find_control(
-	struct ast_ari_response *response,
-	const char *channel_id)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	control = stasis_app_control_find_by_channel_id(channel_id);
-	if (control == NULL) {
-		/* Distinguish between 404 and 409 errors */
-		RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
-		chan = ast_channel_get_by_name(channel_id);
-		if (chan == NULL) {
-			ast_ari_response_error(response, 404, "Not Found",
-				   "Channel not found");
-			return NULL;
-		}
-
-		ast_ari_response_error(response, 409, "Conflict",
-			   "Channel not in Stasis application");
-		return NULL;
-	}
-
-	ao2_ref(control, +1);
-	return control;
-}
-
-void ast_ari_channels_continue_in_dialplan(
-	struct ast_variable *headers,
-	struct ast_ari_channels_continue_in_dialplan_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_answer(struct ast_variable *headers,
-	struct ast_ari_channels_answer_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	if (stasis_app_control_answer(control) != 0) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Failed to answer channel");
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_ring(struct ast_variable *headers,
-	struct ast_ari_channels_ring_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	stasis_app_control_ring(control);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_ring_stop(struct ast_variable *headers,
-	struct ast_ari_channels_ring_stop_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	stasis_app_control_ring_stop(control);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_mute(struct ast_variable *headers,
-	struct ast_ari_channels_mute_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	unsigned int direction = 0;
-	enum ast_frame_type frametype = AST_FRAME_VOICE;
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	if (ast_strlen_zero(args->direction)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Direction is required");
-		return;
-	}
-
-	if (!strcmp(args->direction, "in")) {
-		direction = AST_MUTE_DIRECTION_READ;
-	} else if (!strcmp(args->direction, "out")) {
-		direction = AST_MUTE_DIRECTION_WRITE;
-	} else if (!strcmp(args->direction, "both")) {
-		direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
-	} else {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Invalid direction specified");
-		return;
-	}
-
-	stasis_app_control_mute(control, direction, frametype);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_unmute(struct ast_variable *headers,
-	struct ast_ari_channels_unmute_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	unsigned int direction = 0;
-	enum ast_frame_type frametype = AST_FRAME_VOICE;
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	if (ast_strlen_zero(args->direction)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Direction is required");
-		return;
-	}
-
-	if (!strcmp(args->direction, "in")) {
-		direction = AST_MUTE_DIRECTION_READ;
-	} else if (!strcmp(args->direction, "out")) {
-		direction = AST_MUTE_DIRECTION_WRITE;
-	} else if (!strcmp(args->direction, "both")) {
-		direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
-	} else {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Invalid direction specified");
-		return;
-	}
-
-	stasis_app_control_unmute(control, direction, frametype);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_send_dtmf(struct ast_variable *headers,
-	struct ast_ari_channels_send_dtmf_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		return;
-	}
-
-	if (ast_strlen_zero(args->dtmf)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"DTMF is required");
-		return;
-	}
-
-	stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_hold(struct ast_variable *headers,
-	struct ast_ari_channels_hold_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_hold(control);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_unhold(struct ast_variable *headers,
-	struct ast_ari_channels_unhold_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_unhold(control);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_start_moh(struct ast_variable *headers,
-	struct ast_ari_channels_start_moh_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_moh_start(control, args->moh_class);
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_stop_moh(struct ast_variable *headers,
-	struct ast_ari_channels_stop_moh_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_moh_stop(control);
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_start_silence(struct ast_variable *headers,
-	struct ast_ari_channels_start_silence_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_silence_start(control);
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_stop_silence(struct ast_variable *headers,
-	struct ast_ari_channels_stop_silence_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	stasis_app_control_silence_stop(control);
-	ast_ari_response_no_content(response);
-}
-
-static void ari_channels_handle_play(
-	const char *args_channel_id,
-	const char *args_media,
-	const char *args_lang,
-	int args_offsetms,
-	int args_skipms,
-	const char *args_playback_id,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	RAII_VAR(char *, playback_url, NULL, ast_free);
-	struct ast_json *json;
-	const char *language;
-
-	ast_assert(response != NULL);
-
-	control = find_control(response, args_channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	snapshot = stasis_app_control_get_snapshot(control);
-	if (!snapshot) {
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Channel not found");
-		return;
-	}
-
-	if (args_skipms < 0) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"skipms cannot be negative");
-		return;
-	}
-
-	if (args_offsetms < 0) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"offsetms cannot be negative");
-		return;
-	}
-
-	language = S_OR(args_lang, snapshot->language);
-
-	playback = stasis_app_control_play_uri(control, args_media, language,
-		args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
-	if (!playback) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Failed to queue media for playback");
-		return;
-	}
-
-	if (ast_asprintf(&playback_url, "/playback/%s",
-			stasis_app_playback_get_id(playback)) == -1) {
-		playback_url = NULL;
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-		return;
-	}
-
-	json = stasis_app_playback_to_json(playback);
-	if (!json) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-		return;
-	}
-
-	ast_ari_response_created(response, playback_url, json);
-}
-
-void ast_ari_channels_play(struct ast_variable *headers,
-	struct ast_ari_channels_play_args *args,
-	struct ast_ari_response *response)
-{
-	ari_channels_handle_play(
-		args->channel_id,
-		args->media,
-		args->lang,
-		args->offsetms,
-		args->skipms,
-		args->playback_id,
-		response);
-}
-
-void ast_ari_channels_play_with_id(struct ast_variable *headers,
-	struct ast_ari_channels_play_with_id_args *args,
-	struct ast_ari_response *response)
-{
-	ari_channels_handle_play(
-		args->channel_id,
-		args->media,
-		args->lang,
-		args->offsetms,
-		args->skipms,
-		args->playback_id,
-		response);
-}
-
-void ast_ari_channels_record(struct ast_variable *headers,
-	struct ast_ari_channels_record_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
-	RAII_VAR(char *, recording_url, NULL, ast_free);
-	struct ast_json *json;
-	RAII_VAR(struct stasis_app_recording_options *, options, NULL,
-		ao2_cleanup);
-	RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
-	size_t uri_name_maxlen;
-
-	ast_assert(response != NULL);
-
-	if (args->max_duration_seconds < 0) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"max_duration_seconds cannot be negative");
-		return;
-	}
-
-	if (args->max_silence_seconds < 0) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"max_silence_seconds cannot be negative");
-		return;
-	}
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* Response filled in by find_control */
-		return;
-	}
-
-	options = stasis_app_recording_options_create(args->name, args->format);
-	if (options == NULL) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-	}
-	ast_string_field_build(options, target, "channel:%s", args->channel_id);
-	options->max_silence_seconds = args->max_silence_seconds;
-	options->max_duration_seconds = args->max_duration_seconds;
-	options->terminate_on =
-		stasis_app_recording_termination_parse(args->terminate_on);
-	options->if_exists =
-		stasis_app_recording_if_exists_parse(args->if_exists);
-	options->beep = args->beep;
-
-	if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"terminateOn invalid");
-		return;
-	}
-
-	if (options->if_exists == -1) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"ifExists invalid");
-		return;
-	}
-
-	if (!ast_get_format_for_file_ext(options->format)) {
-		ast_ari_response_error(
-			response, 422, "Unprocessable Entity",
-			"specified format is unknown on this system");
-		return;
-	}
-
-	recording = stasis_app_control_record(control, options);
-	if (recording == NULL) {
-		switch(errno) {
-		case EINVAL:
-			/* While the arguments are invalid, we should have
-			 * caught them prior to calling record.
-			 */
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Error parsing request");
-			break;
-		case EEXIST:
-			ast_ari_response_error(response, 409, "Conflict",
-				"Recording '%s' already exists and can not be overwritten",
-				args->name);
-			break;
-		case ENOMEM:
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Out of memory");
-			break;
-		case EPERM:
-			ast_ari_response_error(
-				response, 400, "Bad Request",
-				"Recording name invalid");
-			break;
-		default:
-			ast_log(LOG_WARNING,
-				"Unrecognized recording error: %s\n",
-				strerror(errno));
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Internal Server Error");
-			break;
-		}
-		return;
-	}
-
-	uri_name_maxlen = strlen(args->name) * 3;
-	uri_encoded_name = ast_malloc(uri_name_maxlen);
-	if (!uri_encoded_name) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-		return;
-	}
-	ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
-		ast_uri_http);
-
-	if (ast_asprintf(&recording_url, "/recordings/live/%s",
-			uri_encoded_name) == -1) {
-		recording_url = NULL;
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-		return;
-	}
-
-	json = stasis_app_recording_to_json(recording);
-	if (!json) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Out of memory");
-		return;
-	}
-
-	ast_ari_response_created(response, recording_url, json);
-}
-
-void ast_ari_channels_get(struct ast_variable *headers,
-	struct ast_ari_channels_get_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct stasis_cache *cache;
-	struct ast_channel_snapshot *snapshot;
-
-	cache = ast_channel_cache();
-	if (!cache) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Message bus not initialized");
-		return;
-	}
-
-	msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
-				   args->channel_id);
-	if (!msg) {
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Channel not found");
-		return;
-	}
-
-	snapshot = stasis_message_data(msg);
-	ast_assert(snapshot != NULL);
-
-	ast_ari_response_ok(response,
-				ast_channel_snapshot_to_json(snapshot, NULL));
-}
-
-void ast_ari_channels_hangup(struct ast_variable *headers,
-	struct ast_ari_channels_hangup_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
-	int cause;
-
-	chan = ast_channel_get_by_name(args->channel_id);
-	if (chan == NULL) {
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Channel not found");
-		return;
-	}
-
-	if (ast_strlen_zero(args->reason) || !strcmp(args->reason, "normal")) {
-		cause = AST_CAUSE_NORMAL;
-	} else if (!strcmp(args->reason, "busy")) {
-		cause = AST_CAUSE_BUSY;
-	} else if (!strcmp(args->reason, "congestion")) {
-		cause = AST_CAUSE_CONGESTION;
-	} else {
-		ast_ari_response_error(
-			response, 400, "Invalid Reason",
-			"Invalid reason for hangup provided");
-		return;
-	}
-
-	ast_channel_hangupcause_set(chan, cause);
-	ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_channels_list(struct ast_variable *headers,
-	struct ast_ari_channels_list_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ao2_iterator i;
-	void *obj;
-	struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
-
-	cache = ast_channel_cache();
-	if (!cache) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Message bus not initialized");
-		return;
-	}
-	ao2_ref(cache, +1);
-
-	snapshots = stasis_cache_dump(cache, ast_channel_snapshot_type());
-	if (!snapshots) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = ast_json_array_create();
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	i = ao2_iterator_init(snapshots, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
-		struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
-		int r;
-
-		if (sanitize && sanitize->channel_snapshot
-			&& sanitize->channel_snapshot(snapshot)) {
-			continue;
-		}
-
-		r = ast_json_array_append(
-			json, ast_channel_snapshot_to_json(snapshot, NULL));
-		if (r != 0) {
-			ast_ari_response_alloc_failed(response);
-			ao2_iterator_destroy(&i);
-			return;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-static void ari_channels_handle_originate_with_id(const char *args_endpoint,
-	const char *args_extension,
-	const char *args_context,
-	long args_priority,
-	const char *args_app,
-	const char *args_app_args,
-	const char *args_caller_id,
-	int args_timeout,
-	struct ast_variable *variables,
-	const char *args_channel_id,
-	const char *args_other_channel_id,
-	struct ast_ari_response *response)
-{
-	char *dialtech;
-	char dialdevice[AST_CHANNEL_NAME];
-	char *caller_id = NULL;
-	char *cid_num = NULL;
-	char *cid_name = NULL;
-	int timeout = 30000;
-	RAII_VAR(struct ast_format_cap *, cap,
-		ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
-	char *stuff;
-	struct ast_channel *chan;
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	struct ast_assigned_ids assignedids = {
-		.uniqueid = args_channel_id,
-		.uniqueid2 = args_other_channel_id,
-	};
-
-	if (!cap) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
-		|| (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Uniqueid length exceeds maximum of %d", AST_MAX_PUBLIC_UNIQUEID);
-		return;
-	}
-
-	if (ast_strlen_zero(args_endpoint)) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Endpoint must be specified");
-		return;
-	}
-
-	dialtech = ast_strdupa(args_endpoint);
-	if ((stuff = strchr(dialtech, '/'))) {
-		*stuff++ = '\0';
-		ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
-	}
-
-	if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Invalid endpoint specified");
-		return;
-	}
-
-	if (args_timeout > 0) {
-		timeout = args_timeout * 1000;
-	} else if (args_timeout == -1) {
-		timeout = -1;
-	}
-
-	if (!ast_strlen_zero(args_caller_id)) {
-		caller_id = ast_strdupa(args_caller_id);
-		ast_callerid_parse(caller_id, &cid_name, &cid_num);
-
-		if (ast_is_shrinkable_phonenumber(cid_num)) {
-			ast_shrink_phone_number(cid_num);
-		}
-	}
-
-	if (!ast_strlen_zero(args_app)) {
-		const char *app = "Stasis";
-
-		RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
-
-		if (!appdata) {
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-
-		ast_str_set(&appdata, 0, "%s", args_app);
-		if (!ast_strlen_zero(args_app_args)) {
-			ast_str_append(&appdata, 0, ",%s", args_app_args);
-		}
-
-		/* originate a channel, putting it into an application */
-		if (ast_pbx_outgoing_app(dialtech, cap, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, variables, NULL, &chan, &assignedids)) {
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	} else if (!ast_strlen_zero(args_extension)) {
-		/* originate a channel, sending it to an extension */
-		if (ast_pbx_outgoing_exten(dialtech, cap, dialdevice, timeout, S_OR(args_context, "default"), args_extension, args_priority ? args_priority : 1, NULL, 0, cid_num, cid_name, variables, NULL, &chan, 0, &assignedids)) {
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	} else {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Application or extension must be specified");
-		return;
-	}
-
-	if (!ast_strlen_zero(args_app)) {
-		struct ast_channel *local_peer;
-
-		stasis_app_subscribe_channel(args_app, chan);
-
-		/* Subscribe to the Local channel peer also. */
-		local_peer = ast_local_get_peer(chan);
-		if (local_peer) {
-			stasis_app_subscribe_channel(args_app, local_peer);
-			ast_channel_unref(local_peer);
-		}
-	}
-
-	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
-	ast_channel_unlock(chan);
-
-	ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
-	ast_channel_unref(chan);
-}
-
-void ast_ari_channels_originate_with_id(struct ast_variable *headers,
-	struct ast_ari_channels_originate_with_id_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
-
-	/* Parse any query parameters out of the body parameter */
-	if (args->variables) {
-		struct ast_json *json_variables;
-
-		ast_ari_channels_originate_with_id_parse_body(args->variables, args);
-		json_variables = ast_json_object_get(args->variables, "variables");
-		if (json_variables) {
-			if (ast_json_to_ast_variables(json_variables, &variables)) {
-				ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
-				ast_ari_response_alloc_failed(response);
-				return;
-			}
-		}
-	}
-
-	ari_channels_handle_originate_with_id(
-		args->endpoint,
-		args->extension,
-		args->context,
-		args->priority,
-		args->app,
-		args->app_args,
-		args->caller_id,
-		args->timeout,
-		variables,
-		args->channel_id,
-		args->other_channel_id,
-		response);
-}
-
-void ast_ari_channels_originate(struct ast_variable *headers,
-	struct ast_ari_channels_originate_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
-
-	/* Parse any query parameters out of the body parameter */
-	if (args->variables) {
-		struct ast_json *json_variables;
-
-		ast_ari_channels_originate_parse_body(args->variables, args);
-		json_variables = ast_json_object_get(args->variables, "variables");
-		if (json_variables) {
-			if (ast_json_to_ast_variables(json_variables, &variables)) {
-				ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
-				ast_ari_response_alloc_failed(response);
-				return;
-			}
-		}
-	}
-
-	ari_channels_handle_originate_with_id(
-		args->endpoint,
-		args->extension,
-		args->context,
-		args->priority,
-		args->app,
-		args->app_args,
-		args->caller_id,
-		args->timeout,
-		variables,
-		args->channel_id,
-		args->other_channel_id,
-		response);
-}
-
-void ast_ari_channels_get_channel_var(struct ast_variable *headers,
-	struct ast_ari_channels_get_channel_var_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, value, ast_str_create(32), ast_free);
-	RAII_VAR(struct ast_channel *, channel, NULL, ast_channel_cleanup);
-
-	ast_assert(response != NULL);
-
-	if (ast_strlen_zero(args->variable)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Variable name is required");
-		return;
-	}
-
-	if (ast_strlen_zero(args->channel_id)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Channel ID is required");
-		return;
-	}
-
-	channel = ast_channel_get_by_name(args->channel_id);
-	if (!channel) {
-		ast_ari_response_error(
-			response, 404, "Channel Not Found",
-			"Provided channel was not found");
-		return;
-	}
-
-	/* You may be tempted to lock the channel you're about to read from. You
-	 * would be wrong. Some dialplan functions put the channel into
-	 * autoservice, which deadlocks if the channel is already locked.
-	 * ast_str_retrieve_variable() does its own locking, and the dialplan
-	 * functions need to as well. We should be fine without the lock.
-	 */
-
-	if (args->variable[strlen(args->variable) - 1] == ')') {
-		if (ast_func_read2(channel, args->variable, &value, 0)) {
-			ast_ari_response_error(
-				response, 500, "Error With Function",
-				"Unable to read provided function");
-			return;
-		}
-	} else {
-		if (!ast_str_retrieve_variable(&value, 0, channel, NULL, args->variable)) {
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	}
-
-	if (!(json = ast_json_pack("{s: s}", "value", S_OR(ast_str_buffer(value), "")))) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_channels_set_channel_var(struct ast_variable *headers,
-	struct ast_ari_channels_set_channel_var_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	if (ast_strlen_zero(args->variable)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Variable name is required");
-		return;
-	}
-
-	control = find_control(response, args->channel_id);
-	if (control == NULL) {
-		/* response filled in by find_control */
-		return;
-	}
-
-	if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Failed to execute function");
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-static void ari_channels_handle_snoop_channel(
-	const char *args_channel_id,
-	const char *args_spy,
-	const char *args_whisper,
-	const char *args_app,
-	const char *args_app_args,
-	const char *args_snoop_id,
-	struct ast_ari_response *response)
-{
-	enum stasis_app_snoop_direction spy, whisper;
-	RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_channel *, snoop, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	ast_assert(response != NULL);
-
-	if (ast_strlen_zero(args_spy) || !strcmp(args_spy, "none")) {
-		spy = STASIS_SNOOP_DIRECTION_NONE;
-	} else if (!strcmp(args_spy, "both")) {
-		spy = STASIS_SNOOP_DIRECTION_BOTH;
-	} else if (!strcmp(args_spy, "out")) {
-		spy = STASIS_SNOOP_DIRECTION_OUT;
-	} else if (!strcmp(args_spy, "in")) {
-		spy = STASIS_SNOOP_DIRECTION_IN;
-	} else {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Invalid direction specified for spy");
-		return;
-	}
-
-	if (ast_strlen_zero(args_whisper) || !strcmp(args_whisper, "none")) {
-		whisper = STASIS_SNOOP_DIRECTION_NONE;
-	} else if (!strcmp(args_whisper, "both")) {
-		whisper = STASIS_SNOOP_DIRECTION_BOTH;
-	} else if (!strcmp(args_whisper, "out")) {
-		whisper = STASIS_SNOOP_DIRECTION_OUT;
-	} else if (!strcmp(args_whisper, "in")) {
-		whisper = STASIS_SNOOP_DIRECTION_IN;
-	} else {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Invalid direction specified for whisper");
-		return;
-	}
-
-	if (spy == STASIS_SNOOP_DIRECTION_NONE && whisper == STASIS_SNOOP_DIRECTION_NONE) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Direction must be specified for at least spy or whisper");
-		return;
-	} else if (ast_strlen_zero(args_app)) {
-		ast_ari_response_error(
-			response, 400, "Bad Request",
-			"Application name is required");
-		return;
-	}
-
-	chan = ast_channel_get_by_name(args_channel_id);
-	if (chan == NULL) {
-		ast_ari_response_error(
-			response, 404, "Channel Not Found",
-			"Provided channel was not found");
-		return;
-	}
-
-	snoop = stasis_app_control_snoop(chan, spy, whisper, args_app, args_app_args,
-		args_snoop_id);
-	if (snoop == NULL) {
-		ast_ari_response_error(
-			response, 500, "Internal error",
-			"Snoop channel could not be created");
-		return;
-	}
-
-	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(snoop));
-	ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
-}
-
-void ast_ari_channels_snoop_channel(struct ast_variable *headers,
-	struct ast_ari_channels_snoop_channel_args *args,
-	struct ast_ari_response *response)
-{
-	ari_channels_handle_snoop_channel(
-		args->channel_id,
-		args->spy,
-		args->whisper,
-		args->app,
-		args->app_args,
-		args->snoop_id,
-		response);
-}
-
-void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers,
-	struct ast_ari_channels_snoop_channel_with_id_args *args,
-	struct ast_ari_response *response)
-{
-	ari_channels_handle_snoop_channel(
-		args->channel_id,
-		args->spy,
-		args->whisper,
-		args->app,
-		args->app_args,
-		args->snoop_id,
-		response);
-}
diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h
deleted file mode 100644
index 104e1bd..0000000
--- a/res/ari/resource_channels.h
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_channels.c
- *
- * Channel resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_CHANNELS_H
-#define _ASTERISK_RESOURCE_CHANNELS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_channels_list() */
-struct ast_ari_channels_list_args {
-};
-/*!
- * \brief List all active channels in Asterisk.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_list(struct ast_variable *headers, struct ast_ari_channels_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_originate() */
-struct ast_ari_channels_originate_args {
-	/*! Endpoint to call. */
-	const char *endpoint;
-	/*! The extension to dial after the endpoint answers */
-	const char *extension;
-	/*! The context to dial after the endpoint answers. If omitted, uses 'default' */
-	const char *context;
-	/*! The priority to dial after the endpoint answers. If omitted, uses 1 */
-	long priority;
-	/*! The application that is subscribed to the originated channel, and passed to the Stasis application. */
-	const char *app;
-	/*! The application arguments to pass to the Stasis application. */
-	const char *app_args;
-	/*! CallerID to use when dialing the endpoint or extension. */
-	const char *caller_id;
-	/*! Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
-	int timeout;
-	/*! The "variables" key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { "endpoint": "SIP/Alice", "variables": { "CALLERID(name)": "Alice" } } */
-	struct ast_json *variables;
-	/*! The unique id to assign the channel on creation. */
-	const char *channel_id;
-	/*! The unique id to assign the second channel when using local channels. */
-	const char *other_channel_id;
-};
-/*!
- * \brief Body parsing function for /channels.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_originate_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_originate_args *args);
-
-/*!
- * \brief Create a new channel (originate).
- *
- * The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated channel for further events and updates.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_originate(struct ast_variable *headers, struct ast_ari_channels_originate_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_get() */
-struct ast_ari_channels_get_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Channel details.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_get(struct ast_variable *headers, struct ast_ari_channels_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_originate_with_id() */
-struct ast_ari_channels_originate_with_id_args {
-	/*! The unique id to assign the channel on creation. */
-	const char *channel_id;
-	/*! Endpoint to call. */
-	const char *endpoint;
-	/*! The extension to dial after the endpoint answers */
-	const char *extension;
-	/*! The context to dial after the endpoint answers. If omitted, uses 'default' */
-	const char *context;
-	/*! The priority to dial after the endpoint answers. If omitted, uses 1 */
-	long priority;
-	/*! The application that is subscribed to the originated channel, and passed to the Stasis application. */
-	const char *app;
-	/*! The application arguments to pass to the Stasis application. */
-	const char *app_args;
-	/*! CallerID to use when dialing the endpoint or extension. */
-	const char *caller_id;
-	/*! Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
-	int timeout;
-	/*! The "variables" key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { "endpoint": "SIP/Alice", "variables": { "CALLERID(name)": "Alice" } } */
-	struct ast_json *variables;
-	/*! The unique id to assign the second channel when using local channels. */
-	const char *other_channel_id;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_originate_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_originate_with_id_args *args);
-
-/*!
- * \brief Create a new channel (originate with id).
- *
- * The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated channel for further events and updates.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_originate_with_id(struct ast_variable *headers, struct ast_ari_channels_originate_with_id_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_hangup() */
-struct ast_ari_channels_hangup_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Reason for hanging up the channel */
-	const char *reason;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_hangup_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_hangup_args *args);
-
-/*!
- * \brief Delete (i.e. hangup) a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_hangup(struct ast_variable *headers, struct ast_ari_channels_hangup_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_continue_in_dialplan() */
-struct ast_ari_channels_continue_in_dialplan_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! The context to continue to. */
-	const char *context;
-	/*! The extension to continue to. */
-	const char *extension;
-	/*! The priority to continue to. */
-	int priority;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/continue.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_continue_in_dialplan_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_continue_in_dialplan_args *args);
-
-/*!
- * \brief Exit application; continue execution in the dialplan.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_continue_in_dialplan(struct ast_variable *headers, struct ast_ari_channels_continue_in_dialplan_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_answer() */
-struct ast_ari_channels_answer_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Answer a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_answer(struct ast_variable *headers, struct ast_ari_channels_answer_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_ring() */
-struct ast_ari_channels_ring_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Indicate ringing to a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_ring(struct ast_variable *headers, struct ast_ari_channels_ring_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_ring_stop() */
-struct ast_ari_channels_ring_stop_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Stop ringing indication on a channel if locally generated.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_ring_stop(struct ast_variable *headers, struct ast_ari_channels_ring_stop_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_send_dtmf() */
-struct ast_ari_channels_send_dtmf_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! DTMF To send. */
-	const char *dtmf;
-	/*! Amount of time to wait before DTMF digits (specified in milliseconds) start. */
-	int before;
-	/*! Amount of time in between DTMF digits (specified in milliseconds). */
-	int between;
-	/*! Length of each DTMF digit (specified in milliseconds). */
-	int duration;
-	/*! Amount of time to wait after DTMF digits (specified in milliseconds) end. */
-	int after;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/dtmf.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_send_dtmf_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_send_dtmf_args *args);
-
-/*!
- * \brief Send provided DTMF to a given channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_send_dtmf(struct ast_variable *headers, struct ast_ari_channels_send_dtmf_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_mute() */
-struct ast_ari_channels_mute_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Direction in which to mute audio */
-	const char *direction;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/mute.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_mute_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_mute_args *args);
-
-/*!
- * \brief Mute a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_mute(struct ast_variable *headers, struct ast_ari_channels_mute_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_unmute() */
-struct ast_ari_channels_unmute_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Direction in which to unmute audio */
-	const char *direction;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/mute.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_unmute_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_unmute_args *args);
-
-/*!
- * \brief Unmute a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_unmute(struct ast_variable *headers, struct ast_ari_channels_unmute_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_hold() */
-struct ast_ari_channels_hold_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Hold a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_hold(struct ast_variable *headers, struct ast_ari_channels_hold_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_unhold() */
-struct ast_ari_channels_unhold_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Remove a channel from hold.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_unhold(struct ast_variable *headers, struct ast_ari_channels_unhold_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_start_moh() */
-struct ast_ari_channels_start_moh_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Music on hold class to use */
-	const char *moh_class;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/moh.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_start_moh_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_start_moh_args *args);
-
-/*!
- * \brief Play music on hold to a channel.
- *
- * Using media operations such as /play on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_start_moh(struct ast_variable *headers, struct ast_ari_channels_start_moh_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_stop_moh() */
-struct ast_ari_channels_stop_moh_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Stop playing music on hold to a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_stop_moh(struct ast_variable *headers, struct ast_ari_channels_stop_moh_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_start_silence() */
-struct ast_ari_channels_start_silence_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Play silence to a channel.
- *
- * Using media operations such as /play on a channel playing silence in this manner will suspend silence without resuming automatically.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_start_silence(struct ast_variable *headers, struct ast_ari_channels_start_silence_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_stop_silence() */
-struct ast_ari_channels_stop_silence_args {
-	/*! Channel's id */
-	const char *channel_id;
-};
-/*!
- * \brief Stop playing silence to a channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_stop_silence(struct ast_variable *headers, struct ast_ari_channels_stop_silence_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_play() */
-struct ast_ari_channels_play_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Media's URI to play. */
-	const char *media;
-	/*! For sounds, selects language for sound. */
-	const char *lang;
-	/*! Number of media to skip before playing. */
-	int offsetms;
-	/*! Number of milliseconds to skip for forward/reverse operations. */
-	int skipms;
-	/*! Playback ID. */
-	const char *playback_id;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/play.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_play_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_play_args *args);
-
-/*!
- * \brief Start playback of media.
- *
- * The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_play(struct ast_variable *headers, struct ast_ari_channels_play_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_play_with_id() */
-struct ast_ari_channels_play_with_id_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Playback ID. */
-	const char *playback_id;
-	/*! Media's URI to play. */
-	const char *media;
-	/*! For sounds, selects language for sound. */
-	const char *lang;
-	/*! Number of media to skip before playing. */
-	int offsetms;
-	/*! Number of milliseconds to skip for forward/reverse operations. */
-	int skipms;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/play/{playbackId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_play_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_play_with_id_args *args);
-
-/*!
- * \brief Start playback of media and specify the playbackId.
- *
- * The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_play_with_id(struct ast_variable *headers, struct ast_ari_channels_play_with_id_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_record() */
-struct ast_ari_channels_record_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Recording's filename */
-	const char *name;
-	/*! Format to encode audio in */
-	const char *format;
-	/*! Maximum duration of the recording, in seconds. 0 for no limit */
-	int max_duration_seconds;
-	/*! Maximum duration of silence, in seconds. 0 for no limit */
-	int max_silence_seconds;
-	/*! Action to take if a recording with the same name already exists. */
-	const char *if_exists;
-	/*! Play beep when recording begins */
-	int beep;
-	/*! DTMF input to terminate recording */
-	const char *terminate_on;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/record.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_record_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_record_args *args);
-
-/*!
- * \brief Start a recording.
- *
- * Record audio from a channel. Note that this will not capture audio sent to the channel. The bridge itself has a record feature if that's what you want.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_record(struct ast_variable *headers, struct ast_ari_channels_record_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_get_channel_var() */
-struct ast_ari_channels_get_channel_var_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! The channel variable or function to get */
-	const char *variable;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/variable.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_get_channel_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_get_channel_var_args *args);
-
-/*!
- * \brief Get the value of a channel variable or function.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_get_channel_var(struct ast_variable *headers, struct ast_ari_channels_get_channel_var_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_set_channel_var() */
-struct ast_ari_channels_set_channel_var_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! The channel variable or function to set */
-	const char *variable;
-	/*! The value to set the variable to */
-	const char *value;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/variable.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_set_channel_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_set_channel_var_args *args);
-
-/*!
- * \brief Set the value of a channel variable or function.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_set_channel_var(struct ast_variable *headers, struct ast_ari_channels_set_channel_var_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_snoop_channel() */
-struct ast_ari_channels_snoop_channel_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Direction of audio to spy on */
-	const char *spy;
-	/*! Direction of audio to whisper into */
-	const char *whisper;
-	/*! Application the snooping channel is placed into */
-	const char *app;
-	/*! The application arguments to pass to the Stasis application */
-	const char *app_args;
-	/*! Unique ID to assign to snooping channel */
-	const char *snoop_id;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/snoop.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_snoop_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_snoop_channel_args *args);
-
-/*!
- * \brief Start snooping.
- *
- * Snoop (spy/whisper) on a specific channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_channels_snoop_channel_with_id() */
-struct ast_ari_channels_snoop_channel_with_id_args {
-	/*! Channel's id */
-	const char *channel_id;
-	/*! Unique ID to assign to snooping channel */
-	const char *snoop_id;
-	/*! Direction of audio to spy on */
-	const char *spy;
-	/*! Direction of audio to whisper into */
-	const char *whisper;
-	/*! Application the snooping channel is placed into */
-	const char *app;
-	/*! The application arguments to pass to the Stasis application */
-	const char *app_args;
-};
-/*!
- * \brief Body parsing function for /channels/{channelId}/snoop/{snoopId}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_channels_snoop_channel_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_snoop_channel_with_id_args *args);
-
-/*!
- * \brief Start snooping.
- *
- * Snoop (spy/whisper) on a specific channel.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_with_id_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_CHANNELS_H */
diff --git a/res/ari/resource_device_states.c b/res/ari/resource_device_states.c
deleted file mode 100644
index 959f58e..0000000
--- a/res/ari/resource_device_states.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/deviceStates.{format} implementation- Device state resources
- *
- * \author Kevin Harwell <kharwell at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405326 $")
-
-#include "resource_device_states.h"
-#include "asterisk/stasis_app_device_state.h"
-
-void ast_ari_device_states_list(
-	struct ast_variable *headers,
-	struct ast_ari_device_states_list_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-
-	if (!(json = stasis_app_device_states_to_json())) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-void ast_ari_device_states_get(struct ast_variable *headers,
-	struct ast_ari_device_states_get_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-
-	if (!(json = stasis_app_device_state_to_json(
-		      args->device_name, ast_device_state(args->device_name)))) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-void ast_ari_device_states_update(struct ast_variable *headers,
-	struct ast_ari_device_states_update_args *args,
-	struct ast_ari_response *response)
-{
-	switch (stasis_app_device_state_update(
-			args->device_name, args->device_state)) {
-	case STASIS_DEVICE_STATE_NOT_CONTROLLED:
-		ast_ari_response_error(response, 409,
-			"Conflict", "Uncontrolled device specified");
-		return;
-	case STASIS_DEVICE_STATE_MISSING:
-		ast_ari_response_error(response, 404,
-			"Not Found", "Device name is missing");
-		return;
-	case STASIS_DEVICE_STATE_UNKNOWN:
-		ast_ari_response_error(response, 500, "Internal Server Error",
-				       "Unknown device");
-		return;
-	case STASIS_DEVICE_STATE_OK:
-	case STASIS_DEVICE_STATE_SUBSCRIBERS: /* shouldn't be returned for update */
-		ast_ari_response_no_content(response);
-	}
-}
-
-void ast_ari_device_states_delete(struct ast_variable *headers,
-	struct ast_ari_device_states_delete_args *args,
-	struct ast_ari_response *response)
-{
-	switch (stasis_app_device_state_delete(args->device_name)) {
-	case STASIS_DEVICE_STATE_NOT_CONTROLLED:
-		ast_ari_response_error(response, 409,
-			"Conflict", "Uncontrolled device specified");
-		return;
-	case STASIS_DEVICE_STATE_MISSING:
-		ast_ari_response_error(response, 404,
-			"Not Found", "Device name is missing");
-		return;
-	case STASIS_DEVICE_STATE_SUBSCRIBERS:
-		ast_ari_response_error(response, 500,
-			"Internal Server Error",
-			"Cannot delete device with subscribers");
-		return;
-	case STASIS_DEVICE_STATE_OK:
-	case STASIS_DEVICE_STATE_UNKNOWN:
-		ast_ari_response_no_content(response);
-	}
-}
diff --git a/res/ari/resource_device_states.h b/res/ari/resource_device_states.h
deleted file mode 100644
index e0c4ad3..0000000
--- a/res/ari/resource_device_states.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_deviceStates.c
- *
- * Device state resources
- *
- * \author Kevin Harwell <kharwell at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_DEVICESTATES_H
-#define _ASTERISK_RESOURCE_DEVICESTATES_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_device_states_list() */
-struct ast_ari_device_states_list_args {
-};
-/*!
- * \brief List all ARI controlled device states.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_device_states_list(struct ast_variable *headers, struct ast_ari_device_states_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_device_states_get() */
-struct ast_ari_device_states_get_args {
-	/*! Name of the device */
-	const char *device_name;
-};
-/*!
- * \brief Retrieve the current state of a device.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_device_states_get(struct ast_variable *headers, struct ast_ari_device_states_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_device_states_update() */
-struct ast_ari_device_states_update_args {
-	/*! Name of the device */
-	const char *device_name;
-	/*! Device state value */
-	const char *device_state;
-};
-/*!
- * \brief Body parsing function for /deviceStates/{deviceName}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_device_states_update_parse_body(
-	struct ast_json *body,
-	struct ast_ari_device_states_update_args *args);
-
-/*!
- * \brief Change the state of a device controlled by ARI. (Note - implicitly creates the device state).
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_device_states_update(struct ast_variable *headers, struct ast_ari_device_states_update_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_device_states_delete() */
-struct ast_ari_device_states_delete_args {
-	/*! Name of the device */
-	const char *device_name;
-};
-/*!
- * \brief Destroy a device-state controlled by ARI.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_device_states_delete(struct ast_variable *headers, struct ast_ari_device_states_delete_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_DEVICESTATES_H */
diff --git a/res/ari/resource_endpoints.c b/res/ari/resource_endpoints.c
deleted file mode 100644
index 8d739f4..0000000
--- a/res/ari/resource_endpoints.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/endpoints.{format} implementation- Endpoint resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420098 $")
-
-#include "resource_endpoints.h"
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/channel.h"
-#include "asterisk/message.h"
-
-void ast_ari_endpoints_list(struct ast_variable *headers,
-	struct ast_ari_endpoints_list_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ao2_iterator i;
-	void *obj;
-
-	cache = ast_endpoint_cache();
-	if (!cache) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Message bus not initialized");
-		return;
-	}
-	ao2_ref(cache, +1);
-
-	snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
-	if (!snapshots) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = ast_json_array_create();
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	i = ao2_iterator_init(snapshots, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
-		struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
-		struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-
-		if (!json_endpoint || ast_json_array_append(json, json_endpoint)) {
-			ao2_iterator_destroy(&i);
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_endpoints_list_by_tech(struct ast_variable *headers,
-	struct ast_ari_endpoints_list_by_tech_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_endpoint *tech_endpoint;
-	struct ao2_iterator i;
-	void *obj;
-
-	tech_endpoint = ast_endpoint_find_by_id(args->tech);
-	if (!tech_endpoint) {
-		ast_ari_response_error(response, 404, "Not Found",
-				       "No Endpoints found - invalid tech %s", args->tech);
-		return;
-	}
-	ao2_ref(tech_endpoint, -1);
-
-	cache = ast_endpoint_cache();
-	if (!cache) {
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Message bus not initialized");
-		return;
-	}
-	ao2_ref(cache, +1);
-
-	snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
-	if (!snapshots) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = ast_json_array_create();
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	i = ao2_iterator_init(snapshots, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
-		struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
-		struct ast_json *json_endpoint;
-		int r;
-
-		if (strcasecmp(args->tech, snapshot->tech) != 0) {
-			continue;
-		}
-
-		json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-		if (!json_endpoint) {
-			continue;
-		}
-
-		r = ast_json_array_append(
-			json, json_endpoint);
-		if (r != 0) {
-			ao2_iterator_destroy(&i);
-			ast_ari_response_alloc_failed(response);
-			return;
-		}
-	}
-	ao2_iterator_destroy(&i);
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_endpoints_get(struct ast_variable *headers,
-	struct ast_ari_endpoints_get_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
-	if (!snapshot) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Endpoint not found");
-		return;
-	}
-
-	json = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-static void send_message(const char *to, const char *from, const char *body, struct ast_variable *variables, struct ast_ari_response *response)
-{
-	struct ast_variable *current;
-	struct ast_msg *msg;
-	int res = 0;
-
-	if (ast_strlen_zero(to)) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"To must be specified");
-		return;
-	}
-
-	msg = ast_msg_alloc();
-	if (!msg) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	res |= ast_msg_set_from(msg, "%s", from);
-	res |= ast_msg_set_to(msg, "%s", to);
-
-	if (!ast_strlen_zero(body)) {
-		res |= ast_msg_set_body(msg, "%s", body);
-	}
-
-	for (current = variables; current; current = current->next) {
-		res |= ast_msg_set_var_outbound(msg, current->name, current->value);
-	}
-
-	if (res) {
-		ast_ari_response_alloc_failed(response);
-		ast_msg_destroy(msg);
-		return;
-	}
-
-	if (ast_msg_send(msg, to, from)) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Endpoint not found");
-	}
-
-	response->message = ast_json_null();
-	response->response_code = 202;
-	response->response_text = "Accepted";
-}
-
-void ast_ari_endpoints_send_message(struct ast_variable *headers,
-	struct ast_ari_endpoints_send_message_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
-
-	if (args->variables) {
-		struct ast_json *json_variables;
-
-		ast_ari_endpoints_send_message_parse_body(args->variables, args);
-		json_variables = ast_json_object_get(args->variables, "variables");
-		if (json_variables) {
-			if (ast_json_to_ast_variables(json_variables, &variables)) {
-				ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
-				ast_ari_response_alloc_failed(response);
-				return;
-			}
-		}
-	}
-
-	send_message(args->to, args->from, args->body, variables, response);
-}
-
-void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers,
-	struct ast_ari_endpoints_send_message_to_endpoint_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-	char msg_to[128];
-	char *tech = ast_strdupa(args->tech);
-
-	/* Really, we just want to know if this thing exists */
-	snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
-	if (!snapshot) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Endpoint not found");
-		return;
-	}
-
-	if (args->variables) {
-		struct ast_json *json_variables;
-
-		ast_ari_endpoints_send_message_to_endpoint_parse_body(args->variables, args);
-		json_variables = ast_json_object_get(args->variables, "variables");
-
-		if (json_variables) {
-			if (ast_json_to_ast_variables(json_variables, &variables)) {
-				ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
-				ast_ari_response_alloc_failed(response);
-				return;
-			}
-		}
-	}
-
-	snprintf(msg_to, sizeof(msg_to), "%s:%s", ast_str_to_lower(tech), args->resource);
-
-	send_message(msg_to, args->from, args->body, variables, response);
-}
diff --git a/res/ari/resource_endpoints.h b/res/ari/resource_endpoints.h
deleted file mode 100644
index 4391b36..0000000
--- a/res/ari/resource_endpoints.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_endpoints.c
- *
- * Endpoint resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_ENDPOINTS_H
-#define _ASTERISK_RESOURCE_ENDPOINTS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_endpoints_list() */
-struct ast_ari_endpoints_list_args {
-};
-/*!
- * \brief List all endpoints.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_endpoints_list(struct ast_variable *headers, struct ast_ari_endpoints_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_endpoints_send_message() */
-struct ast_ari_endpoints_send_message_args {
-	/*! The endpoint resource or technology specific URI to send the message to. Valid resources are sip, pjsip, and xmpp. */
-	const char *to;
-	/*! The endpoint resource or technology specific identity to send this message from. Valid resources are sip, pjsip, and xmpp. */
-	const char *from;
-	/*! The body of the message */
-	const char *body;
-	struct ast_json *variables;
-};
-/*!
- * \brief Body parsing function for /endpoints/sendMessage.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_endpoints_send_message_parse_body(
-	struct ast_json *body,
-	struct ast_ari_endpoints_send_message_args *args);
-
-/*!
- * \brief Send a message to some technology URI or endpoint.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_endpoints_send_message(struct ast_variable *headers, struct ast_ari_endpoints_send_message_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_endpoints_list_by_tech() */
-struct ast_ari_endpoints_list_by_tech_args {
-	/*! Technology of the endpoints (sip,iax2,...) */
-	const char *tech;
-};
-/*!
- * \brief List available endoints for a given endpoint technology.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_endpoints_list_by_tech(struct ast_variable *headers, struct ast_ari_endpoints_list_by_tech_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_endpoints_get() */
-struct ast_ari_endpoints_get_args {
-	/*! Technology of the endpoint */
-	const char *tech;
-	/*! ID of the endpoint */
-	const char *resource;
-};
-/*!
- * \brief Details for an endpoint.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_endpoints_get(struct ast_variable *headers, struct ast_ari_endpoints_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_endpoints_send_message_to_endpoint() */
-struct ast_ari_endpoints_send_message_to_endpoint_args {
-	/*! Technology of the endpoint */
-	const char *tech;
-	/*! ID of the endpoint */
-	const char *resource;
-	/*! The endpoint resource or technology specific identity to send this message from. Valid resources are sip, pjsip, and xmpp. */
-	const char *from;
-	/*! The body of the message */
-	const char *body;
-	struct ast_json *variables;
-};
-/*!
- * \brief Body parsing function for /endpoints/{tech}/{resource}/sendMessage.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_endpoints_send_message_to_endpoint_parse_body(
-	struct ast_json *body,
-	struct ast_ari_endpoints_send_message_to_endpoint_args *args);
-
-/*!
- * \brief Send a message to some endpoint in a technology.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers, struct ast_ari_endpoints_send_message_to_endpoint_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_ENDPOINTS_H */
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
deleted file mode 100644
index 1a43816..0000000
--- a/res/ari/resource_events.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/events.{format} implementation- WebSocket resource
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 414406 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/stasis_app.h"
-#include "resource_events.h"
-
-/*! Number of buckets for the Stasis application hash table. Remember to keep it
- *  a prime number!
- */
-#define APPS_NUM_BUCKETS 7
-
-/*! \brief A connection to the event WebSocket */
-struct event_session {
-	struct ast_ari_websocket_session *ws_session;
-	struct ao2_container *websocket_apps;
-};
-
-/*!
- * \brief Explicitly shutdown a session.
- *
- * An explicit shutdown is necessary, since stasis-app has a reference to this
- * session. We also need to be sure to null out the \c ws_session field, since
- * the websocket is about to go away.
- *
- * \param session Session info struct.
- */
-static void session_shutdown(struct event_session *session)
-{
-        struct ao2_iterator i;
-	char *app;
-	SCOPED_AO2LOCK(lock, session);
-
-	i = ao2_iterator_init(session->websocket_apps, 0);
-	while ((app = ao2_iterator_next(&i))) {
-		stasis_app_unregister(app);
-		ao2_cleanup(app);
-	}
-	ao2_iterator_destroy(&i);
-	ao2_cleanup(session->websocket_apps);
-
-	session->websocket_apps = NULL;
-	session->ws_session = NULL;
-}
-
-static void session_dtor(void *obj)
-{
-#ifdef AST_DEVMODE /* Avoid unused variable warning */
-	struct event_session *session = obj;
-#endif
-
-	/* session_shutdown should have been called before */
-	ast_assert(session->ws_session == NULL);
-	ast_assert(session->websocket_apps == NULL);
-}
-
-static void session_cleanup(struct event_session *session)
-{
-	session_shutdown(session);
-	ao2_cleanup(session);
-}
-
-static struct event_session *session_create(
-	struct ast_ari_websocket_session *ws_session)
-{
-	RAII_VAR(struct event_session *, session, NULL, ao2_cleanup);
-
-	session = ao2_alloc(sizeof(*session), session_dtor);
-
-	session->ws_session = ws_session;
-	session->websocket_apps =
-		ast_str_container_alloc(APPS_NUM_BUCKETS);
-
-	if (!session->websocket_apps) {
-		return NULL;
-	}
-
-	ao2_ref(session, +1);
-	return session;
-}
-
-/*!
- * \brief Callback handler for Stasis application messages.
- */
-static void app_handler(void *data, const char *app_name,
-			struct ast_json *message)
-{
-	struct event_session *session = data;
-	int res;
-	const char *msg_type = S_OR(
-		ast_json_string_get(ast_json_object_get(message, "type")),
-		"");
-	const char *msg_application = S_OR(
-		ast_json_string_get(ast_json_object_get(message, "application")),
-		"");
- 
-	/* Determine if we've been replaced */
-	if (strcmp(msg_type, "ApplicationReplaced") == 0 &&
-		strcmp(msg_application, app_name) == 0) {
-		ao2_find(session->websocket_apps, msg_application,
-			OBJ_UNLINK | OBJ_NODATA);
-	}
-
-	res = ast_json_object_set(message, "application",
-				  ast_json_string_create(app_name));
-	if(res != 0) {
-		return;
-	}
-
-	ao2_lock(session);
-	if (session->ws_session) {
-		ast_ari_websocket_session_write(session->ws_session, message);
-	}
-	ao2_unlock(session);
-}
-
-/*!
- * \brief Register for all of the apps given.
- * \param session Session info struct.
- * \param app_name Name of application to register.
- */
-static int session_register_app(struct event_session *session,
-				 const char *app_name)
-{
-	SCOPED_AO2LOCK(lock, session);
-
-	ast_assert(session->ws_session != NULL);
-	ast_assert(session->websocket_apps != NULL);
-
-	if (ast_strlen_zero(app_name)) {
-		return -1;
-	}
-
-	if (ast_str_container_add(session->websocket_apps, app_name)) {
-		ast_ari_websocket_session_write(session->ws_session,
-			ast_ari_oom_json());
-		return -1;
-	}
-
-	stasis_app_register(app_name, app_handler, session);
-
-	return 0;
-}
-
-void ast_ari_websocket_events_event_websocket(struct ast_ari_websocket_session *ws_session,
-	struct ast_variable *headers,
-	struct ast_ari_events_event_websocket_args *args)
-{
-	RAII_VAR(struct event_session *, session, NULL, session_cleanup);
-	struct ast_json *msg;
-	int res;
-	size_t i;
-
-	ast_debug(3, "/events WebSocket connection\n");
-
-	session = session_create(ws_session);
-	if (!session) {
-		ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
-		return;
-	}
-
-	res = 0;
-	for (i = 0; i < args->app_count; ++i) {
-		if (ast_strlen_zero(args->app[i])) {
-			continue;
-		}
-		res |= session_register_app(session, args->app[i]);
-	}
-
-	if (ao2_container_count(session->websocket_apps) == 0) {
-		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
-
-		msg = ast_json_pack("{s: s, s: [s]}",
-			"type", "MissingParams",
-			"params", "app");
-		if (!msg) {
-			msg = ast_json_ref(ast_ari_oom_json());
-		}
-
-		ast_ari_websocket_session_write(session->ws_session, msg);
-		return;
-	}
-
-	if (res != 0) {
-		ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
-		return;
-	}
-
-	/* We don't process any input, but we'll consume it waiting for EOF */
-	while ((msg = ast_ari_websocket_session_read(ws_session))) {
-		ast_json_unref(msg);
-	}
-}
-
-void ast_ari_events_user_event(struct ast_variable *headers,
-	struct ast_ari_events_user_event_args *args,
-	struct ast_ari_response *response)
-{
-	enum stasis_app_user_event_res res;
-	struct ast_json *json_variables = NULL;
-
-	if (args->variables) {
-		ast_ari_events_user_event_parse_body(args->variables, args);
-		json_variables = ast_json_object_get(args->variables, "variables");
-	}
-
-	if (ast_strlen_zero(args->application)) {
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Missing parameter application");
-		return;
-	}
-
-	res = stasis_app_user_event(args->application,
-		args->event_name,
-		args->source, args->source_count,
-		json_variables);
-
-	switch (res) {
-	case STASIS_APP_USER_OK:
-		ast_ari_response_no_content(response);
-		break;
-
-	case STASIS_APP_USER_APP_NOT_FOUND:
-		ast_ari_response_error(response, 404, "Not Found",
-			"Application not found");
-		break;
-
-	case STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND:
-		ast_ari_response_error(response, 422, "Unprocessable Entity",
-			"Event source was not found");
-		break;
-
-	case STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME:
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Invalid event source URI scheme");
-		break;
-
-	case STASIS_APP_USER_USEREVENT_INVALID:
-		ast_ari_response_error(response, 400, "Bad Request",
-			"Invalid userevnet data");
-		break;
-
-	case STASIS_APP_USER_INTERNAL_ERROR:
-	default:
-		ast_ari_response_error(response, 500, "Internal Server Error",
-			"Error processing request");
-	}
-}
-
diff --git a/res/ari/resource_events.h b/res/ari/resource_events.h
deleted file mode 100644
index 646cf9b..0000000
--- a/res/ari/resource_events.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_events.c
- *
- * WebSocket resource
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_EVENTS_H
-#define _ASTERISK_RESOURCE_EVENTS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_events_event_websocket() */
-struct ast_ari_events_event_websocket_args {
-	/*! Array of Applications to subscribe to. */
-	const char **app;
-	/*! Length of app array. */
-	size_t app_count;
-	/*! Parsing context for app. */
-	char *app_parse;
-};
-/*!
- * \brief WebSocket connection for events.
- *
- * \param session ARI WebSocket.
- * \param headers HTTP headers.
- * \param args Swagger parameters.
- */
-void ast_ari_websocket_events_event_websocket(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_events_event_websocket_args *args);
-/*! Argument struct for ast_ari_events_user_event() */
-struct ast_ari_events_user_event_args {
-	/*! Event name */
-	const char *event_name;
-	/*! The name of the application that will receive this event */
-	const char *application;
-	/*! Array of URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}/{resource}, deviceState:{deviceName} */
-	const char **source;
-	/*! Length of source array. */
-	size_t source_count;
-	/*! Parsing context for source. */
-	char *source_parse;
-	/*! The "variables" key in the body object holds custom key/value pairs to add to the user event. Ex. { "variables": { "key": "value" } } */
-	struct ast_json *variables;
-};
-/*!
- * \brief Body parsing function for /events/user/{eventName}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_events_user_event_parse_body(
-	struct ast_json *body,
-	struct ast_ari_events_user_event_args *args);
-
-/*!
- * \brief Generate a user event.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_events_user_event(struct ast_variable *headers, struct ast_ari_events_user_event_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_EVENTS_H */
diff --git a/res/ari/resource_mailboxes.c b/res/ari/resource_mailboxes.c
deleted file mode 100644
index ddeea0a..0000000
--- a/res/ari/resource_mailboxes.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/mailboxes.{format} implementation- Mailboxes resources
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-#include "asterisk/stasis_app_mailbox.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405554 $")
-
-#include "resource_mailboxes.h"
-
-void ast_ari_mailboxes_list(struct ast_variable *headers,
-	struct ast_ari_mailboxes_list_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-
-	if (!(json = stasis_app_mailboxes_to_json())) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-void ast_ari_mailboxes_get(struct ast_variable *headers,
-	struct ast_ari_mailboxes_get_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *json;
-
-	switch (stasis_app_mailbox_to_json(args->mailbox_name, &json)) {
-	case STASIS_MAILBOX_MISSING:
-		ast_ari_response_error(response, 404,
-			"Not Found", "Mailbox is does not exist");
-		return;
-	case STASIS_MAILBOX_ERROR:
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	case STASIS_MAILBOX_OK:
-		ast_ari_response_ok(response, json);
-	}
-}
-void ast_ari_mailboxes_update(struct ast_variable *headers,
-	struct ast_ari_mailboxes_update_args *args,
-	struct ast_ari_response *response)
-{
-	if (stasis_app_mailbox_update(args->mailbox_name, args->old_messages, args->new_messages)) {
-		ast_ari_response_error(response, 500, "Internal Server Error", "Error updating mailbox");
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-void ast_ari_mailboxes_delete(struct ast_variable *headers,
-	struct ast_ari_mailboxes_delete_args *args,
-	struct ast_ari_response *response)
-{
-	switch (stasis_app_mailbox_delete(args->mailbox_name)) {
-	case STASIS_MAILBOX_MISSING:
-		ast_ari_response_error(response, 404,
-			"Not Found", "Mailbox does not exist");
-		return;
-	case STASIS_MAILBOX_ERROR:
-		ast_ari_response_error(response, 500,
-			"INternal Server Error", "Failed to delete the mailbox");
-		return;
-	case STASIS_MAILBOX_OK:
-		ast_ari_response_no_content(response);
-	}
-}
diff --git a/res/ari/resource_mailboxes.h b/res/ari/resource_mailboxes.h
deleted file mode 100644
index bd83777..0000000
--- a/res/ari/resource_mailboxes.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_mailboxes.c
- *
- * Mailboxes resources
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_MAILBOXES_H
-#define _ASTERISK_RESOURCE_MAILBOXES_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_mailboxes_list() */
-struct ast_ari_mailboxes_list_args {
-};
-/*!
- * \brief List all mailboxes.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_mailboxes_list(struct ast_variable *headers, struct ast_ari_mailboxes_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_mailboxes_get() */
-struct ast_ari_mailboxes_get_args {
-	/*! Name of the mailbox */
-	const char *mailbox_name;
-};
-/*!
- * \brief Retrieve the current state of a mailbox.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_mailboxes_get(struct ast_variable *headers, struct ast_ari_mailboxes_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_mailboxes_update() */
-struct ast_ari_mailboxes_update_args {
-	/*! Name of the mailbox */
-	const char *mailbox_name;
-	/*! Count of old messages in the mailbox */
-	int old_messages;
-	/*! Count of new messages in the mailbox */
-	int new_messages;
-};
-/*!
- * \brief Body parsing function for /mailboxes/{mailboxName}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_mailboxes_update_parse_body(
-	struct ast_json *body,
-	struct ast_ari_mailboxes_update_args *args);
-
-/*!
- * \brief Change the state of a mailbox. (Note - implicitly creates the mailbox).
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_mailboxes_update(struct ast_variable *headers, struct ast_ari_mailboxes_update_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_mailboxes_delete() */
-struct ast_ari_mailboxes_delete_args {
-	/*! Name of the mailbox */
-	const char *mailbox_name;
-};
-/*!
- * \brief Destroy a mailbox.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_mailboxes_delete(struct ast_variable *headers, struct ast_ari_mailboxes_delete_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_MAILBOXES_H */
diff --git a/res/ari/resource_playbacks.c b/res/ari/resource_playbacks.c
deleted file mode 100644
index 04abcc3..0000000
--- a/res/ari/resource_playbacks.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/playbacks.{format} implementation- Playback control resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 405326 $")
-
-#include "asterisk/stasis_app_playback.h"
-#include "resource_playbacks.h"
-
-void ast_ari_playbacks_get(struct ast_variable *headers,
-	struct ast_ari_playbacks_get_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	struct ast_json *json;
-
-	playback = stasis_app_playback_find_by_id(args->playback_id);
-	if (playback == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Playback not found");
-		return;
-	}
-
-	json = stasis_app_playback_to_json(playback);
-	if (json == NULL) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-void ast_ari_playbacks_stop(struct ast_variable *headers,
-	struct ast_ari_playbacks_stop_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	enum stasis_playback_oper_results res;
-
-	playback = stasis_app_playback_find_by_id(args->playback_id);
-	if (playback == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Playback not found");
-		return;
-	}
-
-	res = stasis_app_playback_operation(playback, STASIS_PLAYBACK_STOP);
-	switch (res) {
-	case STASIS_PLAYBACK_OPER_OK:
-		ast_ari_response_no_content(response);
-		return;
-	case STASIS_PLAYBACK_OPER_FAILED:
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Could not stop playback");
-		return;
-	case STASIS_PLAYBACK_OPER_NOT_PLAYING:
-		/* Stop operation should be valid even when not playing */
-		ast_assert(0);
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Could not stop playback");
-		return;
-	}
-}
-void ast_ari_playbacks_control(struct ast_variable *headers,
-	struct ast_ari_playbacks_control_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	enum stasis_app_playback_media_operation oper;
-	enum stasis_playback_oper_results res;
-
-	if (!args->operation) {
-		ast_ari_response_error(response, 400,
-			"Bad Request", "Missing operation");
-		return;
-	}
-	if (strcmp(args->operation, "unpause") == 0) {
-		oper = STASIS_PLAYBACK_UNPAUSE;
-	} else if (strcmp(args->operation, "pause") == 0) {
-		oper = STASIS_PLAYBACK_PAUSE;
-	} else if (strcmp(args->operation, "restart") == 0) {
-		oper = STASIS_PLAYBACK_RESTART;
-	} else if (strcmp(args->operation, "reverse") == 0) {
-		oper = STASIS_PLAYBACK_REVERSE;
-	} else if (strcmp(args->operation, "forward") == 0) {
-		oper = STASIS_PLAYBACK_FORWARD;
-	} else {
-		ast_ari_response_error(response, 400,
-			"Bad Request", "Invalid operation %s",
-			args->operation);
-		return;
-	}
-
-	playback = stasis_app_playback_find_by_id(args->playback_id);
-	if (playback == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Playback not found");
-		return;
-	}
-
-	res = stasis_app_playback_operation(playback, oper);
-	switch (res) {
-	case STASIS_PLAYBACK_OPER_OK:
-		ast_ari_response_no_content(response);
-		return;
-	case STASIS_PLAYBACK_OPER_FAILED:
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Could not %s playback",
-			args->operation);
-		return;
-	case STASIS_PLAYBACK_OPER_NOT_PLAYING:
-		ast_ari_response_error(response, 409, "Conflict",
-			"Can only %s while media is playing", args->operation);
-		return;
-	}
-}
diff --git a/res/ari/resource_playbacks.h b/res/ari/resource_playbacks.h
deleted file mode 100644
index 316ee49..0000000
--- a/res/ari/resource_playbacks.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_playbacks.c
- *
- * Playback control resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_PLAYBACKS_H
-#define _ASTERISK_RESOURCE_PLAYBACKS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_playbacks_get() */
-struct ast_ari_playbacks_get_args {
-	/*! Playback's id */
-	const char *playback_id;
-};
-/*!
- * \brief Get a playback's details.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_playbacks_get(struct ast_variable *headers, struct ast_ari_playbacks_get_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_playbacks_stop() */
-struct ast_ari_playbacks_stop_args {
-	/*! Playback's id */
-	const char *playback_id;
-};
-/*!
- * \brief Stop a playback.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_playbacks_stop(struct ast_variable *headers, struct ast_ari_playbacks_stop_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_playbacks_control() */
-struct ast_ari_playbacks_control_args {
-	/*! Playback's id */
-	const char *playback_id;
-	/*! Operation to perform on the playback. */
-	const char *operation;
-};
-/*!
- * \brief Body parsing function for /playbacks/{playbackId}/control.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_playbacks_control_parse_body(
-	struct ast_json *body,
-	struct ast_ari_playbacks_control_args *args);
-
-/*!
- * \brief Control a playback.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_playbacks_control(struct ast_variable *headers, struct ast_ari_playbacks_control_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_PLAYBACKS_H */
diff --git a/res/ari/resource_recordings.c b/res/ari/resource_recordings.c
deleted file mode 100644
index efd6c43..0000000
--- a/res/ari/resource_recordings.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/recordings.{format} implementation- Recording resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419022 $")
-
-#include "asterisk/stasis_app_recording.h"
-#include "resource_recordings.h"
-
-void ast_ari_recordings_list_stored(struct ast_variable *headers,
-	struct ast_ari_recordings_list_stored_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ao2_container *, recordings, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ao2_iterator i;
-	void *obj;
-
-	recordings = stasis_app_stored_recording_find_all();
-
-	if (!recordings) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	json = ast_json_array_create();
-	if (!json) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	i = ao2_iterator_init(recordings, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_app_stored_recording *, recording, obj,
-			ao2_cleanup);
-
-		int r = ast_json_array_append(
-			json, stasis_app_stored_recording_to_json(recording));
-		if (r != 0) {
-			ast_ari_response_alloc_failed(response);
-			ao2_iterator_destroy(&i);
-			return;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	ast_ari_response_ok(response, ast_json_ref(json));
-}
-
-void ast_ari_recordings_get_stored(struct ast_variable *headers,
-	struct ast_ari_recordings_get_stored_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-		ao2_cleanup);
-	struct ast_json *json;
-
-	recording = stasis_app_stored_recording_find_by_name(
-		args->recording_name);
-	if (recording == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Recording not found");
-		return;
-	}
-
-	json = stasis_app_stored_recording_to_json(recording);
-	if (json == NULL) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-void ast_ari_recordings_copy_stored(struct ast_variable *headers,
-	struct ast_ari_recordings_copy_stored_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, src_recording, NULL,
-		ao2_cleanup);
-	RAII_VAR(struct stasis_app_stored_recording *, dst_recording, NULL,
-		ao2_cleanup);
-	struct ast_json *json;
-	int res;
-
-	src_recording = stasis_app_stored_recording_find_by_name(
-		args->recording_name);
-	if (src_recording == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Recording not found");
-		return;
-	}
-
-	dst_recording = stasis_app_stored_recording_find_by_name(
-		args->destination_recording_name);
-	if (dst_recording) {
-		ast_ari_response_error(response, 409, "Conflict",
-			"A recording with the same name already exists on the system");
-		return;
-	}
-
-	/* See if we got our name rejected */
-	switch (errno) {
-	case EINVAL:
-		ast_ari_response_error(response, 400, "Bad request",
-			"Invalid destination recording name");
-		return;
-	case EACCES:
-		ast_ari_response_error(response, 403, "Forbidden",
-			"Destination file path is forbidden");
-		return;
-	default:
-		break;
-	}
-
-	res = stasis_app_stored_recording_copy(src_recording,
-		args->destination_recording_name, &dst_recording);
-	if (res) {
-		switch (errno) {
-		case EACCES:
-		case EPERM:
-			ast_ari_response_error(response, 500,
-				"Internal Server Error",
-				"Copy failed");
-			break;
-		default:
-			ast_log(LOG_WARNING,
-				"Unexpected error copying recording %s to %s: %s\n",
-				args->recording_name, args->destination_recording_name, strerror(errno));
-			ast_ari_response_error(response, 500,
-				"Internal Server Error",
-				"Copy failed");
-			break;
-		}
-		return;
-	}
-
-	json = stasis_app_stored_recording_to_json(dst_recording);
-	if (json == NULL) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-void ast_ari_recordings_delete_stored(struct ast_variable *headers,
-	struct ast_ari_recordings_delete_stored_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-		ao2_cleanup);
-	int res;
-
-	recording = stasis_app_stored_recording_find_by_name(
-		args->recording_name);
-	if (recording == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Recording not found");
-		return;
-	}
-
-	res = stasis_app_stored_recording_delete(recording);
-
-	if (res != 0) {
-		switch (errno) {
-		case EACCES:
-		case EPERM:
-			ast_ari_response_error(response, 500,
-				"Internal Server Error",
-				"Delete failed");
-			break;
-		default:
-			ast_log(LOG_WARNING,
-				"Unexpected error deleting recording %s: %s\n",
-				args->recording_name, strerror(errno));
-			ast_ari_response_error(response, 500,
-				"Internal Server Error",
-				"Delete failed");
-			break;
-		}
-		return;
-	}
-
-	ast_ari_response_no_content(response);
-}
-
-void ast_ari_recordings_get_live(struct ast_variable *headers,
-	struct ast_ari_recordings_get_live_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
-	struct ast_json *json;
-
-	recording = stasis_app_recording_find_by_name(args->recording_name);
-	if (recording == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Recording not found");
-		return;
-	}
-
-	json = stasis_app_recording_to_json(recording);
-	if (json == NULL) {
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Error building response");
-		return;
-	}
-
-	ast_ari_response_ok(response, json);
-}
-
-static void control_recording(const char *name,
-	enum stasis_app_recording_media_operation operation,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
-	enum stasis_app_recording_oper_results res;
-
-	recording = stasis_app_recording_find_by_name(name);
-	if (recording == NULL) {
-		ast_ari_response_error(response, 404, "Not Found",
-			"Recording not found");
-		return;
-	}
-
-	res = stasis_app_recording_operation(recording, operation);
-
-	switch (res) {
-	case STASIS_APP_RECORDING_OPER_OK:
-		ast_ari_response_no_content(response);
-		return;
-	case STASIS_APP_RECORDING_OPER_FAILED:
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Recording operation failed");
-		return;
-	case STASIS_APP_RECORDING_OPER_NOT_RECORDING:
-		ast_ari_response_error(response, 409,
-			"Conflict", "Recording not in session");
-	}
-}
-
-void ast_ari_recordings_cancel(struct ast_variable *headers,
-	struct ast_ari_recordings_cancel_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_CANCEL,
-		response);
-}
-
-void ast_ari_recordings_stop(struct ast_variable *headers,
-	struct ast_ari_recordings_stop_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_STOP,
-		response);
-}
-
-void ast_ari_recordings_pause(struct ast_variable *headers,
-	struct ast_ari_recordings_pause_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_PAUSE,
-		response);
-}
-
-void ast_ari_recordings_unpause(struct ast_variable *headers,
-	struct ast_ari_recordings_unpause_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_UNPAUSE,
-		response);
-}
-
-void ast_ari_recordings_mute(struct ast_variable *headers,
-	struct ast_ari_recordings_mute_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_MUTE,
-		response);
-}
-
-void ast_ari_recordings_unmute(struct ast_variable *headers,
-	struct ast_ari_recordings_unmute_args *args,
-	struct ast_ari_response *response)
-{
-	control_recording(args->recording_name, STASIS_APP_RECORDING_UNMUTE,
-		response);
-}
diff --git a/res/ari/resource_recordings.h b/res/ari/resource_recordings.h
deleted file mode 100644
index 196122f..0000000
--- a/res/ari/resource_recordings.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_recordings.c
- *
- * Recording resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_RECORDINGS_H
-#define _ASTERISK_RESOURCE_RECORDINGS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_recordings_list_stored() */
-struct ast_ari_recordings_list_stored_args {
-};
-/*!
- * \brief List recordings that are complete.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_list_stored(struct ast_variable *headers, struct ast_ari_recordings_list_stored_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_get_stored() */
-struct ast_ari_recordings_get_stored_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Get a stored recording's details.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_get_stored(struct ast_variable *headers, struct ast_ari_recordings_get_stored_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_delete_stored() */
-struct ast_ari_recordings_delete_stored_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Delete a stored recording.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_delete_stored(struct ast_variable *headers, struct ast_ari_recordings_delete_stored_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_copy_stored() */
-struct ast_ari_recordings_copy_stored_args {
-	/*! The name of the recording to copy */
-	const char *recording_name;
-	/*! The destination name of the recording */
-	const char *destination_recording_name;
-};
-/*!
- * \brief Body parsing function for /recordings/stored/{recordingName}/copy.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_recordings_copy_stored_parse_body(
-	struct ast_json *body,
-	struct ast_ari_recordings_copy_stored_args *args);
-
-/*!
- * \brief Copy a stored recording.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_copy_stored(struct ast_variable *headers, struct ast_ari_recordings_copy_stored_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_get_live() */
-struct ast_ari_recordings_get_live_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief List live recordings.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_get_live(struct ast_variable *headers, struct ast_ari_recordings_get_live_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_cancel() */
-struct ast_ari_recordings_cancel_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Stop a live recording and discard it.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_cancel(struct ast_variable *headers, struct ast_ari_recordings_cancel_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_stop() */
-struct ast_ari_recordings_stop_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Stop a live recording and store it.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_stop(struct ast_variable *headers, struct ast_ari_recordings_stop_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_pause() */
-struct ast_ari_recordings_pause_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Pause a live recording.
- *
- * Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused. Paused time is not included in the accounting for maxDurationSeconds.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_pause(struct ast_variable *headers, struct ast_ari_recordings_pause_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_unpause() */
-struct ast_ari_recordings_unpause_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Unpause a live recording.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_unpause(struct ast_variable *headers, struct ast_ari_recordings_unpause_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_mute() */
-struct ast_ari_recordings_mute_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Mute a live recording.
- *
- * Muting a recording suspends silence detection, which will be restarted when the recording is unmuted.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_mute(struct ast_variable *headers, struct ast_ari_recordings_mute_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_recordings_unmute() */
-struct ast_ari_recordings_unmute_args {
-	/*! The name of the recording */
-	const char *recording_name;
-};
-/*!
- * \brief Unmute a live recording.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_recordings_unmute(struct ast_variable *headers, struct ast_ari_recordings_unmute_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_RECORDINGS_H */
diff --git a/res/ari/resource_sounds.c b/res/ari/resource_sounds.c
deleted file mode 100644
index 36bc06c..0000000
--- a/res/ari/resource_sounds.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief /api-docs/sounds.{format} implementation- Sound resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "resource_sounds.h"
-#include "asterisk/media_index.h"
-#include "asterisk/sounds_index.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/json.h"
-
-/*! \brief arguments that are necessary for adding format/lang pairs */
-struct lang_format_info {
-	struct ast_json *format_list;	/*!< The embedded array to which format/lang pairs should be added */
-	const char *filename;		/*!< Name of the file for which to add format/lang pairs */
-	const char *format_filter;	/*!< Format filter provided in the request */
-};
-
-/*! \brief Add format/lang pairs to the array embedded in the sound object */
-static int add_format_information_cb(void *obj, void *arg, int flags)
-{
-	char *language = obj;
-	struct lang_format_info *args = arg;
-	int idx;
-	RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
-
-	if (!sounds_index) {
-		return CMP_STOP;
-	}
-
-	cap = ast_media_get_format_cap(sounds_index, args->filename, language);
-	if (!cap) {
-		return CMP_STOP;
-	}
-
-	for (idx = 0; idx < ast_format_cap_count(cap); idx++) {
-		struct ast_format *format = ast_format_cap_get_format(cap, idx);
-		struct ast_json *lang_format_pair;
-
-		if (!ast_strlen_zero(args->format_filter)
-			&& strcmp(args->format_filter, ast_format_get_name(format))) {
-			ao2_ref(format, -1);
-			continue;
-		}
-
-		lang_format_pair = ast_json_pack("{s: s, s: s}",
-			"language", language,
-			"format", ast_format_get_name(format));
-		if (!lang_format_pair) {
-			ao2_ref(format, -1);
-			return CMP_STOP;
-		}
-
-		ast_json_array_append(args->format_list, lang_format_pair);
-		ao2_ref(format, -1);
-	}
-
-	return 0;
-}
-
-/*! \brief Filter out all languages not matching the specified language */
-static int filter_langs_cb(void *obj, void *arg, int flags)
-{
-	char *lang_filter = arg;
-	char *lang = obj;
-	if (strcmp(lang, lang_filter)) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-/*! \brief Generate a Sound structure as documented in sounds.json for the specified filename */
-static struct ast_json *create_sound_blob(const char *filename,
-	struct ast_ari_sounds_list_args *args)
-{
-	RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref);
-	RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
-	const char *description;
-	struct ast_json *format_lang_list;
-	struct lang_format_info info;
-	RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
-
-	if (!sounds_index) {
-		return NULL;
-	}
-
-	description = ast_media_get_description(sounds_index, filename, "en");
-	if (ast_strlen_zero(description)) {
-		sound = ast_json_pack("{s: s, s: []}",
-			"id", filename,
-			"formats");
-	} else {
-		sound = ast_json_pack("{s: s, s: s, s: []}",
-			"id", filename,
-			"text", description,
-			"formats");
-	}
-	if (!sound) {
-		return NULL;
-	}
-
-	format_lang_list = ast_json_object_get(sound, "formats");
-	if (!format_lang_list) {
-		return NULL;
-	}
-
-	languages = ast_media_get_variants(sounds_index, filename);
-	if (!languages || !ao2_container_count(languages)) {
-		return NULL;
-	}
-
-	/* filter requested languages */
-	if (args && !ast_strlen_zero(args->lang)) {
-		char *lang_filter = ast_strdupa(args->lang);
-		ao2_callback(languages, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, filter_langs_cb, lang_filter);
-		if (!languages || !ao2_container_count(languages)) {
-			return NULL;
-		}
-	}
-
-	info.filename = filename;
-	info.format_list = format_lang_list;
-	info.format_filter = NULL;
-	if (args) {
-		info.format_filter = args->format;
-	}
-	ao2_callback(languages, OBJ_NODATA, add_format_information_cb, &info);
-
-	/* no format/lang pairs for this sound so nothing to return */
-	if (!ast_json_array_size(format_lang_list)) {
-		return NULL;
-	}
-
-	return ast_json_ref(sound);
-}
-
-/*! \brief Generate a Sound structure and append it to the output blob */
-static int append_sound_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_json *sounds_array = arg;
-	char *filename = obj;
-	struct ast_ari_sounds_list_args *args = data;
-	struct ast_json *sound_blob = create_sound_blob(filename, args);
-	if (!sound_blob) {
-		return 0;
-	}
-
-	ast_json_array_append(sounds_array, sound_blob);
-	return 0;
-}
-
-void ast_ari_sounds_list(struct ast_variable *headers,
-	struct ast_ari_sounds_list_args *args,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct ao2_container *, sound_files, NULL, ao2_cleanup);
-	struct ast_json *sounds_blob;
-	RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
-
-	if (!sounds_index) {
-		ast_ari_response_error(response, 500, "Internal Error", "Sounds index not available");
-		return;
-	}
-
-	sound_files = ast_media_get_media(sounds_index);
-	if (!sound_files) {
-		ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
-		return;
-	}
-
-	sounds_blob = ast_json_array_create();
-	if (!sounds_blob) {
-		ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
-		return;
-	}
-
-	ao2_callback_data(sound_files, OBJ_NODATA, append_sound_cb, sounds_blob, args);
-
-	if (!ast_json_array_size(sounds_blob)) {
-		ast_ari_response_error(response, 404, "Not Found", "No sounds found that matched the query");
-		return;
-	}
-
-	ast_ari_response_ok(response, sounds_blob);
-}
-
-void ast_ari_sounds_get(struct ast_variable *headers,
-	struct ast_ari_sounds_get_args *args,
-	struct ast_ari_response *response)
-{
-	struct ast_json *sound_blob;
-
-	sound_blob = create_sound_blob(args->sound_id, NULL);
-	if (!sound_blob) {
-		ast_ari_response_error(response, 404, "Not Found", "Sound not found");
-		return;
-	}
-
-	ast_ari_response_ok(response, sound_blob);
-}
diff --git a/res/ari/resource_sounds.h b/res/ari/resource_sounds.h
deleted file mode 100644
index cdfa17a..0000000
--- a/res/ari/resource_sounds.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_sounds.c
- *
- * Sound resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_SOUNDS_H
-#define _ASTERISK_RESOURCE_SOUNDS_H
-
-#include "asterisk/ari.h"
-
-/*! Argument struct for ast_ari_sounds_list() */
-struct ast_ari_sounds_list_args {
-	/*! Lookup sound for a specific language. */
-	const char *lang;
-	/*! Lookup sound in a specific format. */
-	const char *format;
-};
-/*!
- * \brief Body parsing function for /sounds.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_sounds_list_parse_body(
-	struct ast_json *body,
-	struct ast_ari_sounds_list_args *args);
-
-/*!
- * \brief List all sounds.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_sounds_list(struct ast_variable *headers, struct ast_ari_sounds_list_args *args, struct ast_ari_response *response);
-/*! Argument struct for ast_ari_sounds_get() */
-struct ast_ari_sounds_get_args {
-	/*! Sound's id */
-	const char *sound_id;
-};
-/*!
- * \brief Get a sound's details.
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_sounds_get(struct ast_variable *headers, struct ast_ari_sounds_get_args *args, struct ast_ari_response *response);
-
-#endif /* _ASTERISK_RESOURCE_SOUNDS_H */
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
deleted file mode 100644
index b4a56b2..0000000
--- a/res/parking/parking_applications.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Applications
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "res_parking.h"
-#include "asterisk/config.h"
-#include "asterisk/config_options.h"
-#include "asterisk/utils.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/features.h"
-#include "asterisk/module.h"
-#include "asterisk/app.h"
-#include "asterisk/say.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/format_cache.h"
-
-/*** DOCUMENTATION
-	<application name="Park" language="en_US">
-		<synopsis>
-			Park yourself.
-		</synopsis>
-		<syntax>
-			<parameter name="parking_lot_name">
-				<para>Specify in which parking lot to park a call.</para>
-				<para>The parking lot used is selected in the following order:</para>
-				<para>1) parking_lot_name option to this application</para>
-				<para>2) <variable>PARKINGLOT</variable> variable</para>
-				<para>3) <literal>CHANNEL(parkinglot)</literal> function
-				(Possibly preset by the channel driver.)</para>
-				<para>4) Default parking lot.</para>
-			</parameter>
-			<parameter name="options">
-				<para>A list of options for this parked call.</para>
-				<optionlist>
-					<option name="r">
-						<para>Send ringing instead of MOH to the parked call.</para>
-					</option>
-					<option name="R">
-						<para>Randomize the selection of a parking space.</para>
-					</option>
-					<option name="s">
-						<para>Silence announcement of the parking space number.</para>
-					</option>
-					<option name="c" argsep=",">
-						<argument name="context" required="false" />
-						<argument name="extension" required="false" />
-						<argument name="priority" required="true" />
-						<para>If the parking times out, go to this place in the dialplan
-							instead of where the parking lot defines the call should go.
-						</para>
-					</option>
-					<option name="t">
-						<argument name="duration" required="true" />
-						<para>Use a timeout of <literal>duration</literal> seconds instead
-							of the timeout specified by the parking lot.</para>
-					</option>
-				</optionlist>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Used to park yourself (typically in combination with an attended
-			transfer to know the parking space).</para>
-			<para>If you set the <variable>PARKINGEXTEN</variable> variable to a
-				parking space extension in the parking lot, Park() will attempt to park the
-				call on that extension. If the extension is already in use then execution
-				will continue at the next priority.
-			</para>
-		</description>
-		<see-also>
-			<ref type="application">ParkedCall</ref>
-		</see-also>
-	</application>
-
-	<application name="ParkedCall" language="en_US">
-		<synopsis>
-			Retrieve a parked call.
-		</synopsis>
-		<syntax>
-			<parameter name="parking_lot_name">
-				<para>Specify from which parking lot to retrieve a parked call.</para>
-				<para>The parking lot used is selected in the following order:</para>
-				<para>1) parking_lot_name option</para>
-				<para>2) <variable>PARKINGLOT</variable> variable</para>
-				<para>3) <literal>CHANNEL(parkinglot)</literal> function
-				(Possibly preset by the channel driver.)</para>
-				<para>4) Default parking lot.</para>
-			</parameter>
-			<parameter name="parking_space">
-				<para>Parking space to retrieve a parked call from.
-				If not provided then the first available parked call in the
-				parking lot will be retrieved.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Used to retrieve a parked call from a parking lot.</para>
-			<note>
-				<para>If a parking lot's parkext option is set, then Parking lots
-				will automatically create and manage dialplan extensions in
-				the parking lot context. If that is the case then you will not
-				need to manage parking extensions yourself, just include the
-				parking context of the parking lot.</para>
-			</note>
-		</description>
-		<see-also>
-			<ref type="application">Park</ref>
-		</see-also>
-	</application>
-
-	<application name="ParkAndAnnounce" language="en_US">
-		<synopsis>
-			Park and Announce.
-		</synopsis>
-		<syntax>
-			<parameter name="parking_lot_name">
-				<para>Specify in which parking lot to park a call.</para>
-				<para>The parking lot used is selected in the following order:</para>
-				<para>1) parking_lot_name option to this application</para>
-				<para>2) <variable>PARKINGLOT</variable> variable</para>
-				<para>3) <literal>CHANNEL(parkinglot)</literal> function
-				(Possibly preset by the channel driver.)</para>
-				<para>4) Default parking lot.</para>
-			</parameter>
-			<parameter name="options">
-				<para>A list of options for this parked call.</para>
-				<optionlist>
-					<option name="r">
-						<para>Send ringing instead of MOH to the parked call.</para>
-					</option>
-					<option name="R">
-						<para>Randomize the selection of a parking space.</para>
-					</option>
-					<option name="c" argsep=",">
-						<argument name="context" required="false" />
-						<argument name="extension" required="false" />
-						<argument name="priority" required="true" />
-						<para>If the parking times out, go to this place in the dialplan
-							instead of where the parking lot defines the call should go.
-						</para>
-					</option>
-					<option name="t">
-						<argument name="duration" required="true" />
-						<para>Use a timeout of <literal>duration</literal> seconds instead
-							of the timeout specified by the parking lot.</para>
-					</option>
-				</optionlist>
-			</parameter>
-			<parameter name="announce_template" required="true" argsep=":">
-				<argument name="announce" required="true">
-					<para>Colon-separated list of files to announce. The word
-					<literal>PARKED</literal> will be replaced by a say_digits of the extension in which
-					the call is parked.</para>
-				</argument>
-				<argument name="announce1" multiple="true" />
-			</parameter>
-			<parameter name="dial" required="true">
-				<para>The app_dial style resource to call to make the
-				announcement. Console/dsp calls the console.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Park a call into the parkinglot and announce the call to another channel.</para>
-			<para>The variable <variable>PARKEDAT</variable> will contain the parking extension
-			into which the call was placed.  Use with the Local channel to allow the dialplan to make
-			use of this information.</para>
-		</description>
-		<see-also>
-			<ref type="application">Park</ref>
-			<ref type="application">ParkedCall</ref>
-		</see-also>
-	</application>
- ***/
-
-#define PARK_AND_ANNOUNCE_APPLICATION "ParkAndAnnounce"
-
-/* Park a call */
-
-enum park_args {
-	OPT_ARG_COMEBACK,
-	OPT_ARG_TIMEOUT,
-	OPT_ARG_ARRAY_SIZE /* Always the last element of the enum */
-};
-
-enum park_flags {
-	MUXFLAG_RINGING = (1 << 0),
-	MUXFLAG_RANDOMIZE = (1 << 1),
-	MUXFLAG_NOANNOUNCE = (1 << 2),
-	MUXFLAG_COMEBACK_OVERRIDE = (1 << 3),
-	MUXFLAG_TIMEOUT_OVERRIDE = (1 << 4),
-};
-
-AST_APP_OPTIONS(park_opts, {
-	AST_APP_OPTION('r', MUXFLAG_RINGING),
-	AST_APP_OPTION('R', MUXFLAG_RANDOMIZE),
-	AST_APP_OPTION('s', MUXFLAG_NOANNOUNCE),
-	AST_APP_OPTION_ARG('c', MUXFLAG_COMEBACK_OVERRIDE, OPT_ARG_COMEBACK),
-	AST_APP_OPTION_ARG('t', MUXFLAG_TIMEOUT_OVERRIDE, OPT_ARG_TIMEOUT),
-});
-
-static int apply_option_timeout (int *var, char *timeout_arg)
-{
-	if (ast_strlen_zero(timeout_arg)) {
-		ast_log(LOG_ERROR, "No duration value provided for the timeout ('t') option.\n");
-		return -1;
-	}
-
-	if (sscanf(timeout_arg, "%d", var) != 1 || *var < 0) {
-		ast_log(LOG_ERROR, "Duration value provided for timeout ('t') option must be 0 or greater.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int park_app_parse_data(const char *data, int *disable_announce, int *use_ringing, int *randomize, int *time_limit, char **comeback_override, char **lot_name)
-{
-	char *parse;
-	struct ast_flags flags = { 0 };
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(lot_name);
-		AST_APP_ARG(options);
-		AST_APP_ARG(other);	/* Any remaining unused arguments */
-	);
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (args.options) {
-		char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
-		ast_app_parse_options(park_opts, &flags, opts, args.options);
-		if (ast_test_flag(&flags, MUXFLAG_TIMEOUT_OVERRIDE)) {
-			if (apply_option_timeout(time_limit, opts[OPT_ARG_TIMEOUT])) {
-				return -1;
-			}
-		}
-
-		if (ast_test_flag(&flags, MUXFLAG_COMEBACK_OVERRIDE)) {
-			*comeback_override = ast_strdup(opts[OPT_ARG_COMEBACK]);
-		}
-
-		if (ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
-			if (disable_announce) {
-				*disable_announce = 1;
-			}
-		}
-
-		if (ast_test_flag(&flags, MUXFLAG_RINGING)) {
-			*use_ringing = 1;
-		}
-
-		if (ast_test_flag(&flags, MUXFLAG_RANDOMIZE)) {
-			*randomize = 1;
-		}
-	}
-
-	if (!ast_strlen_zero(args.lot_name)) {
-		*lot_name = ast_strdup(args.lot_name);
-	}
-
-	return 0;
-}
-
-void park_common_datastore_free(struct park_common_datastore *datastore)
-{
-	if (!datastore) {
-		return;
-	}
-
-	ast_free(datastore->parker_uuid);
-	ast_free(datastore->parker_dial_string);
-	ast_free(datastore->comeback_override);
-	ast_free(datastore);
-}
-
-static void park_common_datastore_destroy(void *data)
-{
-	struct park_common_datastore *datastore = data;
-	park_common_datastore_free(datastore);
-}
-
-static const struct ast_datastore_info park_common_info = {
-	.type = "park entry data",
-	.destroy = park_common_datastore_destroy,
-};
-
-static void wipe_park_common_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &park_common_info, NULL);
-	if (datastore) {
-		ast_channel_datastore_remove(chan, datastore);
-		ast_datastore_free(datastore);
-	}
-	ast_channel_unlock(chan);
-}
-
-static int setup_park_common_datastore(struct ast_channel *parkee, const char *parker_uuid, const char *comeback_override, int randomize, int time_limit, int silence_announce)
-{
-	struct ast_datastore *datastore = NULL;
-	struct park_common_datastore *park_datastore;
-	const char *attended_transfer;
-	const char *blind_transfer;
-	char *parker_dial_string = NULL;
-
-	wipe_park_common_datastore(parkee);
-
-	if (!(datastore = ast_datastore_alloc(&park_common_info, NULL))) {
-		return -1;
-	}
-
-	if (!(park_datastore = ast_calloc(1, sizeof(*park_datastore)))) {
-		ast_datastore_free(datastore);
-		return -1;
-	}
-
-	if (parker_uuid) {
-		park_datastore->parker_uuid = ast_strdup(parker_uuid);
-	}
-
-	ast_channel_lock(parkee);
-
-	attended_transfer = pbx_builtin_getvar_helper(parkee, "ATTENDEDTRANSFER");
-	blind_transfer = pbx_builtin_getvar_helper(parkee, "BLINDTRANSFER");
-
-	if (attended_transfer || blind_transfer) {
-		parker_dial_string = ast_strdupa(S_OR(attended_transfer, blind_transfer));
-	}
-
-	ast_channel_unlock(parkee);
-
-	if (!ast_strlen_zero(parker_dial_string)) {
-		ast_channel_name_to_dial_string(parker_dial_string);
-		ast_verb(4, "Setting Parker dial string to %s from %s value", parker_dial_string, attended_transfer ? "ATTENDEDTRANSFER" : "BLINDTRANSFER");
-		park_datastore->parker_dial_string = ast_strdup(parker_dial_string);
-	}
-
-	park_datastore->randomize = randomize;
-	park_datastore->time_limit = time_limit;
-	park_datastore->silence_announce = silence_announce;
-
-	if (comeback_override) {
-		park_datastore->comeback_override = ast_strdup(comeback_override);
-	}
-
-
-	datastore->data = park_datastore;
-	ast_channel_lock(parkee);
-	ast_channel_datastore_add(parkee, datastore);
-	ast_channel_unlock(parkee);
-
-	return 0;
-}
-
-struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee)
-{
-	struct ast_datastore *datastore;
-	struct park_common_datastore *data;
-	struct park_common_datastore *data_copy;
-
-	SCOPED_CHANNELLOCK(lock, parkee);
-	if (!(datastore = ast_channel_datastore_find(parkee, &park_common_info, NULL))) {
-		return NULL;
-	}
-
-	data = datastore->data;
-
-	if (!data) {
-		/* This data should always be populated if this datastore was appended to the channel */
-		ast_assert(0);
-	}
-
-	data_copy = ast_calloc(1, sizeof(*data_copy));
-	if (!data_copy) {
-		return NULL;
-	}
-
-	if (!(data_copy->parker_uuid = ast_strdup(data->parker_uuid))) {
-		park_common_datastore_free(data_copy);
-		return NULL;
-	}
-
-	data_copy->randomize = data->randomize;
-	data_copy->time_limit = data->time_limit;
-	data_copy->silence_announce = data->silence_announce;
-
-	if (data->comeback_override) {
-		data_copy->comeback_override = ast_strdup(data->comeback_override);
-		if (!data_copy->comeback_override) {
-			park_common_datastore_free(data_copy);
-			return NULL;
-		}
-	}
-
-	if (data->parker_dial_string) {
-		data_copy->parker_dial_string = ast_strdup(data->parker_dial_string);
-		if (!data_copy->parker_dial_string) {
-			park_common_datastore_free(data_copy);
-			return NULL;
-		}
-	}
-
-	return data_copy;
-}
-
-struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
-		const char *lot_name, const char *comeback_override,
-		int use_ringing, int randomize, int time_limit, int silence_announcements)
-{
-	struct ast_bridge *parking_bridge;
-	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
-
-	if (!parker) {
-		parker = parkee;
-	}
-
-	/* If the name of the parking lot isn't specified in the arguments, find it based on the channel. */
-	if (ast_strlen_zero(lot_name)) {
-		ast_channel_lock(parker);
-		lot_name = ast_strdupa(find_channel_parking_lot_name(parker));
-		ast_channel_unlock(parker);
-	}
-
-	lot = parking_lot_find_by_name(lot_name);
-	if (!lot) {
-		lot = parking_create_dynamic_lot(lot_name, parkee);
-	}
-
-	if (!lot) {
-		ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
-		return NULL;
-	}
-
-	ao2_lock(lot);
-	parking_bridge = parking_lot_get_bridge(lot);
-	ao2_unlock(lot);
-
-	if (!parking_bridge) {
-		return NULL;
-	}
-
-	/* Apply relevant bridge roles and such to the parking channel */
-	parking_channel_set_roles(parkee, lot, use_ringing);
-	setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
-		silence_announcements);
-	return parking_bridge;
-}
-
-struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data,
-		int *silence_announcements)
-{
-	int use_ringing = 0;
-	int randomize = 0;
-	int time_limit = -1;
-
-	RAII_VAR(char *, comeback_override, NULL, ast_free);
-	RAII_VAR(char *, lot_name_app_arg, NULL, ast_free);
-
-	if (app_data) {
-		park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
-	}
-
-	return park_common_setup(parkee, parker, lot_name_app_arg, comeback_override, use_ringing,
-		randomize, time_limit, silence_announcements ? *silence_announcements : 0);
-
-}
-
-static int park_app_exec(struct ast_channel *chan, const char *data)
-{
-	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-
-	struct ast_bridge_features chan_features;
-	int res;
-	int silence_announcements = 0;
-	const char *transferer;
-
-	/* Answer the channel if needed */
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_answer(chan);
-	}
-
-	ast_channel_lock(chan);
-	if (!(transferer = pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER"))) {
-		transferer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
-	}
-	transferer = ast_strdupa(S_OR(transferer, ""));
-	ast_channel_unlock(chan);
-
-	/* Handle the common parking setup stuff */
-	if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) {
-		if (!silence_announcements && !transferer) {
-			ast_stream_and_wait(chan, "pbx-parkingfailed", "");
-		}
-		publish_parked_call_failure(chan);
-		return 0;
-	}
-
-	/* Initialize bridge features for the channel. */
-	res = ast_bridge_features_init(&chan_features);
-	if (res) {
-		ast_bridge_features_cleanup(&chan_features);
-		publish_parked_call_failure(chan);
-		return -1;
-	}
-
-	/* Now for the fun part... park it! */
-	ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
-
-	/*
-	 * If the bridge was broken for a hangup that isn't real, then
-	 * don't run the h extension, because the channel isn't really
-	 * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
-	 */
-	res = -1;
-
-	ast_channel_lock(chan);
-	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
-		res = 0;
-	}
-	ast_channel_unlock(chan);
-
-	ast_bridge_features_cleanup(&chan_features);
-
-	return res;
-}
-
-/* Retrieve a parked call */
-
-static int parked_call_app_exec(struct ast_channel *chan, const char *data)
-{
-	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
-	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); /* Parked user being retrieved */
-	struct ast_bridge *retrieval_bridge;
-	int res;
-	int target_space = -1;
-	struct ast_bridge_features chan_features;
-	char *parse;
-	char *lot_name;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(lot_name);
-		AST_APP_ARG(parking_space);
-		AST_APP_ARG(other);	/* Any remaining unused arguments */
-	);
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	/* Answer the channel if needed */
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_answer(chan);
-	}
-
-	lot_name = args.lot_name;
-
-	/* If the name of the parking lot isn't in the arguments, find it based on the channel. */
-	if (ast_strlen_zero(lot_name)) {
-		ast_channel_lock(chan);
-		lot_name = ast_strdupa(find_channel_parking_lot_name(chan));
-		ast_channel_unlock(chan);
-	}
-
-	lot = parking_lot_find_by_name(lot_name);
-
-	if (!lot) {
-		ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
-		ast_stream_and_wait(chan, "pbx-invalidpark", "");
-		return -1;
-	}
-
-	if (!ast_strlen_zero(args.parking_space)) {
-		if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
-			ast_stream_and_wait(chan, "pbx-invalidpark", "");
-			ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
-			return -1;
-		}
-	}
-
-	/* Attempt to get the parked user from the parking lot */
-	pu = parking_lot_retrieve_parked_user(lot, target_space);
-	if (!pu) {
-		ast_stream_and_wait(chan, "pbx-invalidpark", "");
-		return -1;
-	}
-
-	/* The parked call needs to know who is retrieving it before we move it out of the parking bridge */
-	pu->retriever = ast_channel_snapshot_create(chan);
-
-	/* Create bridge */
-	retrieval_bridge = ast_bridge_basic_new();
-	if (!retrieval_bridge) {
-		return -1;
-	}
-
-	/* Move the parkee into the new bridge */
-	if (ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
-		ast_bridge_destroy(retrieval_bridge, 0);
-		return -1;
-	}
-
-	/* Initialize our bridge features */
-	res = ast_bridge_features_init(&chan_features);
-	if (res) {
-		ast_bridge_destroy(retrieval_bridge, 0);
-		ast_bridge_features_cleanup(&chan_features);
-		return -1;
-	}
-
-	/* Set the features */
-	parked_call_retrieve_enable_features(chan, lot, AST_FEATURE_FLAG_BYCALLER);
-
-	/* If the parkedplay option is set for the caller to hear, play that tone now. */
-	if (lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLER) {
-		ast_stream_and_wait(chan, lot->cfg->courtesytone, NULL);
-	}
-
-	/* Now we should try to join the new bridge ourselves... */
-	ast_bridge_join(retrieval_bridge, chan, NULL, &chan_features, NULL,
-		AST_BRIDGE_JOIN_PASS_REFERENCE);
-
-	ast_bridge_features_cleanup(&chan_features);
-
-	return 0;
-}
-
-struct park_announce_subscription_data {
-	char *parkee_uuid;
-	char *dial_string;
-	char *announce_string;
-};
-
-static void park_announce_subscription_data_destroy(void *data)
-{
-	struct park_announce_subscription_data *pa_data = data;
-	ast_free(pa_data->parkee_uuid);
-	ast_free(pa_data->dial_string);
-	ast_free(pa_data->announce_string);
-	ast_free(pa_data);
-}
-
-static struct park_announce_subscription_data *park_announce_subscription_data_create(const char *parkee_uuid,
-		const char *dial_string,
-		const char *announce_string)
-{
-	struct park_announce_subscription_data *pa_data;
-
-	if (!(pa_data = ast_calloc(1, sizeof(*pa_data)))) {
-		return NULL;
-	}
-
-	if (!(pa_data->parkee_uuid = ast_strdup(parkee_uuid))
-		|| !(pa_data->dial_string = ast_strdup(dial_string))
-		|| !(pa_data->announce_string = ast_strdup(announce_string))) {
-		park_announce_subscription_data_destroy(pa_data);
-		return NULL;
-	}
-
-	return pa_data;
-}
-
-static void announce_to_dial(char *dial_string, char *announce_string, int parkingspace, struct ast_channel_snapshot *parkee_snapshot)
-{
-	struct ast_channel *dchan;
-	struct outgoing_helper oh = { 0, };
-	int outstate;
-	struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	char buf[13];
-	char *dial_tech;
-	char *cur_announce;
-
-	dial_tech = strsep(&dial_string, "/");
-	ast_verb(3, "Dial Tech,String: (%s,%s)\n", dial_tech, dial_string);
-
-	if (!cap_slin) {
-		ast_log(LOG_WARNING, "PARK: Failed to announce park.\n");
-		goto announce_cleanup;
-	}
-	ast_format_cap_append(cap_slin, ast_format_slin, 0);
-
-	snprintf(buf, sizeof(buf), "%d", parkingspace);
-	oh.vars = ast_variable_new("_PARKEDAT", buf, "");
-	dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, NULL, dial_string, 30000,
-		&outstate,
-		parkee_snapshot->caller_number,
-		parkee_snapshot->caller_name,
-		&oh);
-
-	ast_variables_destroy(oh.vars);
-	if (!dchan) {
-		ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
-		goto announce_cleanup;
-	}
-
-	ast_verb(4, "Announce Template: %s\n", announce_string);
-
-	for (cur_announce = strsep(&announce_string, ":"); cur_announce; cur_announce = strsep(&announce_string, ":")) {
-		ast_verb(4, "Announce:%s\n", cur_announce);
-		if (!strcmp(cur_announce, "PARKED")) {
-			ast_say_digits(dchan, parkingspace, "", ast_channel_language(dchan));
-		} else {
-			int dres = ast_streamfile(dchan, cur_announce, ast_channel_language(dchan));
-			if (!dres) {
-				dres = ast_waitstream(dchan, "");
-			} else {
-				ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", cur_announce, ast_channel_name(dchan));
-			}
-		}
-	}
-
-	ast_stopstream(dchan);
-	ast_hangup(dchan);
-
-announce_cleanup:
-	ao2_cleanup(cap_slin);
-}
-
-static void park_announce_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct park_announce_subscription_data *pa_data = data;
-	char *dial_string = pa_data->dial_string;
-
-	struct ast_parked_call_payload *payload = stasis_message_data(message);
-
-	if (stasis_subscription_final_message(sub, message)) {
-		park_announce_subscription_data_destroy(data);
-		return;
-	}
-
-	if (payload->event_type != PARKED_CALL) {
-		/* We are only concerned with calls parked */
-		return;
-	}
-
-	if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
-		/* We are only concerned with the parkee we are subscribed for. */
-		return;
-	}
-
-	if (!ast_strlen_zero(dial_string)) {
-		announce_to_dial(dial_string, pa_data->announce_string, payload->parkingspace, payload->parkee);
-	}
-
-	*dial_string = '\0'; /* If we observe this dial string on a second pass, we don't want to do anything with it. */
-}
-
-static int park_and_announce_app_exec(struct ast_channel *chan, const char *data)
-{
-	struct ast_bridge_features chan_features;
-	char *parse;
-	int res;
-	int silence_announcements = 1;
-
-	struct stasis_subscription *parking_subscription;
-	struct park_announce_subscription_data *pa_data;
-
-	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(lot_name);
-		AST_APP_ARG(options);
-		AST_APP_ARG(announce_template);
-		AST_APP_ARG(dial);
-		AST_APP_ARG(others);/* Any remaining unused arguments */
-	);
-
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_ERROR, "ParkAndAnnounce has required arguments. No arguments were provided.\n");
-		return -1;
-	}
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.announce_template)) {
-		/* improperly configured arguments for the application */
-		ast_log(LOG_ERROR, "ParkAndAnnounce requires the announce_template argument.\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.dial)) {
-		/* improperly configured arguments */
-		ast_log(LOG_ERROR, "ParkAndAnnounce requires the dial argument.\n");
-		return -1;
-	}
-
-	if (!strchr(args.dial, '/')) {
-		ast_log(LOG_ERROR, "ParkAndAnnounce dial string '%s' is improperly formed.\n", args.dial);
-		return -1;
-	}
-
-	/* Handle the common parking setup stuff */
-	if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) {
-		return 0;
-	}
-
-	/* Initialize bridge features for the channel. */
-	res = ast_bridge_features_init(&chan_features);
-	if (res) {
-		ast_bridge_features_cleanup(&chan_features);
-		return -1;
-	}
-
-	/* subscribe to the parking message so that we can announce once it is parked */
-	pa_data = park_announce_subscription_data_create(ast_channel_uniqueid(chan), args.dial, args.announce_template);
-	if (!pa_data) {
-		return -1;
-	}
-
-	if (!(parking_subscription = stasis_subscribe_pool(ast_parking_topic(), park_announce_update_cb, pa_data))) {
-		/* Failed to create subscription */
-		park_announce_subscription_data_destroy(pa_data);
-		return -1;
-	}
-
-	/* Now for the fun part... park it! */
-	ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
-
-	/* Toss the subscription since we aren't bridged at this point. */
-	stasis_unsubscribe(parking_subscription);
-
-	/*
-	 * If the bridge was broken for a hangup that isn't real, then
-	 * don't run the h extension, because the channel isn't really
-	 * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
-	 */
-	res = -1;
-
-	ast_channel_lock(chan);
-	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
-		res = 0;
-	}
-	ast_channel_unlock(chan);
-
-	ast_bridge_features_cleanup(&chan_features);
-
-	return res;
-}
-
-int load_parking_applications(void)
-{
-	const struct ast_module_info *ast_module_info = parking_get_module_info();
-
-	if (ast_register_application_xml(PARK_APPLICATION, park_app_exec)) {
-		return -1;
-	}
-
-	if (ast_register_application_xml(PARKED_CALL_APPLICATION, parked_call_app_exec)) {
-		return -1;
-	}
-
-	if (ast_register_application_xml(PARK_AND_ANNOUNCE_APPLICATION, park_and_announce_app_exec)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-void unload_parking_applications(void)
-{
-	ast_unregister_application(PARK_APPLICATION);
-	ast_unregister_application(PARKED_CALL_APPLICATION);
-	ast_unregister_application(PARK_AND_ANNOUNCE_APPLICATION);
-}
diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c
deleted file mode 100644
index 4f7198b..0000000
--- a/res/parking/parking_bridge.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Parking Bridge Class
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-#include "res_parking.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/logger.h"
-#include "asterisk/say.h"
-#include "asterisk/term.h"
-#include "asterisk/features.h"
-#include "asterisk/bridge_internal.h"
-
-struct ast_bridge_parking
-{
-	struct ast_bridge base;
-
-	/* private stuff for parking */
-	struct parking_lot *lot;
-};
-
-/*!
- * \internal
- * \brief ast_bridge parking class destructor
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- *
- * \note XXX Stub... and it might go unused.
- *
- * \return Nothing
- */
-static void bridge_parking_destroy(struct ast_bridge_parking *self)
-{
-	ast_bridge_base_v_table.destroy(&self->base);
-}
-
-static void bridge_parking_dissolving(struct ast_bridge_parking *self)
-{
-	self->lot = NULL;
-	ast_bridge_base_v_table.dissolving(&self->base);
-}
-
-static void destroy_parked_user(void *obj)
-{
-	struct parked_user *pu = obj;
-
-	ao2_cleanup(pu->lot);
-	ao2_cleanup(pu->retriever);
-	ast_free(pu->parker_dial_string);
-}
-
-/* Only call this on a parked user that hasn't had its parker_dial_string set already */
-static int parked_user_set_parker_dial_string(struct parked_user *pu, struct ast_channel *parker)
-{
-	char *dial_string = ast_strdupa(ast_channel_name(parker));
-
-	ast_channel_name_to_dial_string(dial_string);
-	pu->parker_dial_string = ast_strdup(dial_string);
-
-	if (!pu->parker_dial_string) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \since 12
- * \brief Construct a parked_user struct assigned to the specified parking lot
- *
- * \param lot The parking lot we are assigning the user to
- * \param parkee The channel being parked
- * \param parker The channel performing the park operation (may be the same channel)
- * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
- * \param use_random_space if true, prioritize using a random parking space instead
- *        of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
- * \param time_limit If using a custom timeout, this should be supplied so that the
- *        parked_user struct can provide this information for manager events. If <0,
- *        use the parking lot limit instead.
- *
- * \retval NULL on failure
- * \retval reference to the parked user
- *
- * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
- */
-static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit)
-{
-	struct parked_user *new_parked_user;
-	int preferred_space = -1; /* Initialize to use parking lot defaults */
-	int parking_space;
-	const char *parkingexten;
-
-	if (lot->mode == PARKINGLOT_DISABLED) {
-		ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
-		return NULL;
-	}
-
-	new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
-	if (!new_parked_user) {
-		return NULL;
-	}
-
-	if (use_random_space) {
-		preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
-		preferred_space += lot->cfg->parking_start;
-	} else {
-		ast_channel_lock(chan);
-		if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
-			parkingexten = ast_strdupa(parkingexten);
-		}
-		ast_channel_unlock(chan);
-
-		if (!ast_strlen_zero(parkingexten)) {
-			if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
-				ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
-				ao2_ref(new_parked_user, -1);
-				return NULL;
-			}
-		}
-	}
-
-	/* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
-	ao2_lock(lot);
-
-	parking_space = parking_lot_get_space(lot, preferred_space);
-	if (parking_space == -1) {
-		ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
-		ao2_ref(new_parked_user, -1);
-		ao2_unlock(lot);
-		return NULL;
-	}
-
-	lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
-	new_parked_user->chan = chan;
-	new_parked_user->parking_space = parking_space;
-
-	/* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
-	new_parked_user->lot = lot;
-	ao2_ref(lot, +1);
-
-	new_parked_user->start = ast_tvnow();
-	new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
-
-	if (parker_dial_string) {
-		new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
-	} else {
-		if (parked_user_set_parker_dial_string(new_parked_user, parker)) {
-			ao2_ref(new_parked_user, -1);
-			ao2_unlock(lot);
-			return NULL;
-		}
-	}
-
-	if (!new_parked_user->parker_dial_string) {
-		ao2_ref(new_parked_user, -1);
-		ao2_unlock(lot);
-		return NULL;
-	}
-
-	/* Insert into the parking lot's parked user list. We can unlock the lot now. */
-	ao2_link(lot->parked_users, new_parked_user);
-	ao2_unlock(lot);
-
-	return new_parked_user;
-}
-
-/* TODO CEL events for parking */
-
-/*!
- * \internal
- * \brief ast_bridge parking push method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon
- * \param bridge_channel Bridge channel to push
- * \param swap Bridge channel to swap places with if not NULL
- *
- * \note On entry, self is already locked
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	struct parked_user *pu;
-	const char *blind_transfer;
-	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); /* XXX replace with ast_channel_cleanup when available */
-	RAII_VAR(struct park_common_datastore *, park_datastore, NULL, park_common_datastore_free);
-
-	ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
-
-	ast_assert(self->lot != NULL);
-
-	/* Answer the channel if needed */
-	if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
-		ast_answer(bridge_channel->chan);
-	}
-
-	if (swap) {
-		int use_ringing = 0;
-
-		ast_bridge_channel_lock(swap);
-		pu = swap->bridge_pvt;
-		if (!pu) {
-			/* This should be impossible since the only way a channel can enter in the first place
-			 * is if it has a parked user associated with it */
-			publish_parked_call_failure(bridge_channel->chan);
-			ast_bridge_channel_unlock(swap);
-			return -1;
-		}
-
-		/* Give the swap channel's parked user reference to the incoming channel */
-		pu->chan = bridge_channel->chan;
-		bridge_channel->bridge_pvt = pu;
-		swap->bridge_pvt = NULL;
-
-		if (ast_bridge_channel_has_role(swap, "holding_participant")) {
-			const char *idle_mode = ast_bridge_channel_get_role_option(swap, "holding_participant", "idle_mode");
-
-			if (!ast_strlen_zero(idle_mode) && !strcmp(idle_mode, "ringing")) {
-				use_ringing = 1;
-			}
-		}
-
-		ast_bridge_channel_unlock(swap);
-
-		parking_set_duration(bridge_channel->features, pu);
-
-		if (parking_channel_set_roles(bridge_channel->chan, self->lot, use_ringing)) {
-			ast_log(LOG_WARNING, "Failed to apply holding bridge roles to %s while joining the parking lot.\n",
-				ast_channel_name(bridge_channel->chan));
-		}
-
-		publish_parked_call(pu, PARKED_CALL_SWAP);
-
-		return 0;
-	}
-
-	if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) {
-		/* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */
-		return -1;
-	}
-	parker = ast_channel_get_by_name(park_datastore->parker_uuid);
-
-	/* If the parker and the parkee are the same channel pointer, then the channel entered using
-	 * the park application. It's possible that the channel that transferred it is still alive (particularly
-	 * when a multichannel bridge is parked), so try to get the real parker if possible. */
-	ast_channel_lock(bridge_channel->chan);
-	blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
-		ast_channel_name(bridge_channel->chan));
-	if (blind_transfer) {
-		blind_transfer = ast_strdupa(blind_transfer);
-	}
-	ast_channel_unlock(bridge_channel->chan);
-
-	if (parker == bridge_channel->chan) {
-		struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
-
-		if (real_parker) {
-			ao2_cleanup(parker);
-			parker = real_parker;
-		}
-	}
-
-	pu = generate_parked_user(self->lot, bridge_channel->chan, parker,
-		park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit);
-	if (!pu) {
-		publish_parked_call_failure(bridge_channel->chan);
-		return -1;
-	}
-
-	/* If a comeback_override was provided, set it for the parked user's comeback string. */
-	if (park_datastore->comeback_override) {
-		ast_copy_string(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback));
-	}
-
-	/* Generate ParkedCall Stasis Message */
-	publish_parked_call(pu, PARKED_CALL);
-
-	/* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
-	if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !park_datastore->silence_announce) {
-		char saynum_buf[16];
-
-		snprintf(saynum_buf, sizeof(saynum_buf), "%d %d", 0, pu->parking_space);
-		ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
-	}
-
-	/* Apply parking duration limits */
-	parking_set_duration(bridge_channel->features, pu);
-
-	/* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
-	bridge_channel->bridge_pvt = pu;
-
-	ast_verb(3, "Parking '" COLORIZE_FMT "' in '" COLORIZE_FMT "' at space %d\n",
-		COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(bridge_channel->chan)),
-		COLORIZE(COLOR_BRMAGENTA, 0, self->lot->name),
-		pu->parking_space);
-
-	parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_INUSE);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief ast_bridge parking pull method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to pull.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
-{
-	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
-
-	ast_bridge_base_v_table.pull(&self->base, bridge_channel);
-
-	/* Take over the bridge channel's pu reference. It will be released when we are done. */
-	pu = bridge_channel->bridge_pvt;
-	bridge_channel->bridge_pvt = NULL;
-
-	/* This should only happen if the exiting channel was swapped out */
-	if (!pu) {
-		return;
-	}
-
-	/* If we got here without the resolution being set, that's because the call was hung up for some reason without
-	 * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
-	 * handled in those cases */
-	ao2_lock(pu);
-	if (pu->resolution == PARK_UNSET) {
-		pu->resolution = PARK_ABANDON;
-	}
-	ao2_unlock(pu);
-
-	/* Pull can still happen after the bridge starts dissolving, so make sure we still have a lot before trying to notify metermaids. */
-	if (self->lot) {
-		parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_NOT_INUSE);
-	}
-
-	switch (pu->resolution) {
-	case PARK_UNSET:
-		/* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
-		   isn't allowed to be changed when it isn't currently PARK_UNSET. */
-		break;
-	case PARK_ABANDON:
-		/* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
-		publish_parked_call(pu, PARKED_CALL_GIVEUP);
-		unpark_parked_user(pu);
-		break;
-	case PARK_FORCED:
-		/* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
-		 * There is currently no event related to forced parked calls either */
-		break;
-	case PARK_ANSWERED:
-		/* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
-		 * the parking lot afterwards. We do need to apply bridge features though and play the courtesy tone if set. */
-		publish_parked_call(pu, PARKED_CALL_UNPARKED);
-		parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
-
-		if (pu->lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLEE) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, pu->lot->cfg->courtesytone, NULL);
-		}
-		break;
-	case PARK_TIMEOUT:
-		/* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
-		 * actually pull the channel. Because of that, unpark should happen in here. */
-		publish_parked_call(pu, PARKED_CALL_TIMEOUT);
-		parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
-		unpark_parked_user(pu);
-		break;
-	}
-}
-
-/*!
- * \internal
- * \brief ast_bridge parking notify_masquerade method.
- * \since 12.0.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel that was masqueraded.
- *
- * \note On entry, self is already locked.
- * \note XXX Stub... and it will probably go unused.
- *
- * \return Nothing
- */
-static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
-{
-	ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
-}
-
-static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
-{
-	ast_bridge_base_v_table.get_merge_priority(&self->base);
-}
-
-struct ast_bridge_methods ast_bridge_parking_v_table = {
-	.name = "parking",
-	.destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
-	.dissolving = (ast_bridge_dissolving_fn) bridge_parking_dissolving,
-	.push = (ast_bridge_push_channel_fn) bridge_parking_push,
-	.pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
-	.notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
-	.get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
-};
-
-static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
-{
-	if (!self) {
-		return NULL;
-	}
-
-	/* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
-	if (!bridge_lot) {
-		ao2_ref(self, -1);
-		return NULL;
-	}
-
-	/* It doesn't need to be a reference since the bridge only lives as long as the parking lot lives. */
-	self->lot = bridge_lot;
-
-	return &self->base;
-}
-
-struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
-{
-	void *bridge;
-
-	bridge = bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
-	bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM,  "Parking", bridge_lot->name, NULL);
-	bridge = ast_bridge_parking_init(bridge, bridge_lot);
-	bridge = bridge_register(bridge);
-	return bridge;
-}
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
deleted file mode 100644
index c6e01c9..0000000
--- a/res/parking/parking_bridge_features.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Parking Bridge DTMF and Interval features
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "res_parking.h"
-#include "asterisk/utils.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/logger.h"
-#include "asterisk/pbx.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/bridge_channel.h"
-#include "asterisk/bridge_features.h"
-#include "asterisk/features.h"
-#include "asterisk/say.h"
-#include "asterisk/datastore.h"
-#include "asterisk/stasis.h"
-#include "asterisk/module.h"
-#include "asterisk/core_local.h"
-#include "asterisk/causes.h"
-
-struct parked_subscription_datastore {
-	struct stasis_subscription *parked_subscription;
-};
-
-struct parked_subscription_data {
-	struct transfer_channel_data *transfer_data;
-	char *parkee_uuid;
-	int hangup_after:1;
-	char parker_uuid[0];
-};
-
-static void parked_subscription_datastore_destroy(void *data)
-{
-	struct parked_subscription_datastore *subscription_datastore = data;
-
-	stasis_unsubscribe(subscription_datastore->parked_subscription);
-	subscription_datastore->parked_subscription = NULL;
-
-	ast_free(subscription_datastore);
-}
-
-static const struct ast_datastore_info parked_subscription_info = {
-	.type = "park subscription",
-	.destroy = parked_subscription_datastore_destroy,
-};
-
-static void wipe_subscription_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	ast_channel_lock(chan);
-
-	datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL);
-	if (datastore) {
-		ast_channel_datastore_remove(chan, datastore);
-		ast_datastore_free(datastore);
-	}
-	ast_channel_unlock(chan);
-}
-
-static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
-	struct stasis_subscription *sub)
-{
-	const char *parkee_to_act_on = data->parkee_uuid;
-	char saynum_buf[16];
-	struct ast_channel_snapshot *parkee_snapshot = message->parkee;
-	RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
-		return;
-	}
-
-	if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
-		/* We only care about these two event types */
-		return;
-	}
-
-	parker = ast_channel_get_by_name(data->parker_uuid);
-	if (!parker) {
-		return;
-	}
-
-	ast_channel_lock(parker);
-	bridge_channel = ast_channel_get_bridge_channel(parker);
-	ast_channel_unlock(parker);
-	if (!bridge_channel) {
-		return;
-	}
-
-	/* This subscription callback will block for the duration of the announcement if
-	 * parked_subscription_data is tracking a transfer_channel_data struct. */
-	if (message->event_type == PARKED_CALL) {
-		/* queue the saynum on the bridge channel and hangup */
-		snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
-		if (!data->transfer_data) {
-			ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
-		} else {
-			ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
-			data->transfer_data->completed = 1;
-		}
-		wipe_subscription_datastore(parker);
-	} else if (message->event_type == PARKED_CALL_FAILED) {
-		if (!data->transfer_data) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
-		} else {
-			ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
-			data->transfer_data->completed = 1;
-		}
-		wipe_subscription_datastore(parker);
-	}
-}
-
-static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	if (stasis_subscription_final_message(sub, message)) {
-		struct parked_subscription_data *ps_data = data;
-		ao2_cleanup(ps_data->transfer_data);
-		ps_data->transfer_data = NULL;
-		ast_free(data);
-		return;
-	}
-
-	if (stasis_message_type(message) == ast_parked_call_type()) {
-		struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
-		parker_parked_call_message_response(parked_call_message, data, sub);
-	}
-}
-
-static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
-	struct transfer_channel_data *parked_channel_data)
-{
-	struct ast_datastore *datastore;
-	struct parked_subscription_datastore *parked_datastore;
-	struct parked_subscription_data *subscription_data;
-
-	char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan));
-	size_t parker_uuid_size = strlen(parker_uuid) + 1;
-
-	/* If there is already a subscription, get rid of it. */
-	wipe_subscription_datastore(chan);
-
-	if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
-		return -1;
-	}
-
-	if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
-		ast_datastore_free(datastore);
-		return -1;
-	}
-
-	if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
-			strlen(parkee_uuid) + 1))) {
-		ast_datastore_free(datastore);
-		ast_free(parked_datastore);
-		return -1;
-	}
-
-	if (parked_channel_data) {
-		subscription_data->transfer_data = parked_channel_data;
-		ao2_ref(parked_channel_data, +1);
-	}
-
-	subscription_data->hangup_after = hangup_after;
-	subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
-	strcpy(subscription_data->parkee_uuid, parkee_uuid);
-	strcpy(subscription_data->parker_uuid, parker_uuid);
-
-	if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
-		return -1;
-	}
-
-	datastore->data = parked_datastore;
-
-	ast_channel_lock(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_channel_unlock(chan);
-
-	return 0;
-}
-
-int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
-{
-	return create_parked_subscription_full(chan, parkee_uuid, hangup_after, NULL);
-}
-
-/*!
- * \internal
- * \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly
- *        identical to the dial_transfer function in bridge_basic.c, however it doesn't swap the
- *        local channel and the channel that instigated the park.
- */
-static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
-{
-	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
-	struct ast_channel *parkee;
-	struct ast_channel *parkee_side_2;
-	int cause;
-
-	/* Fill the variable with the extension and context we want to call */
-	snprintf(destination, sizeof(destination), "%s@%s", exten, context);
-
-	/* Now we request that chan_local prepare to call the destination */
-	parkee = ast_request("Local", ast_channel_nativeformats(parker), NULL, parker, destination,
-		&cause);
-	if (!parkee) {
-		return NULL;
-	}
-
-	/* Before we actually dial out let's inherit appropriate information. */
-	ast_channel_lock_both(parker, parkee);
-	ast_channel_req_accountcodes(parkee, parker, AST_CHANNEL_REQUESTOR_REPLACEMENT);
-	ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker));
-	ast_channel_inherit_variables(parker, parkee);
-	ast_channel_datastore_inherit(parker, parkee);
-	ast_channel_unlock(parker);
-
-	parkee_side_2 = ast_local_get_peer(parkee);
-	ast_assert(parkee_side_2 != NULL);
-	ast_channel_unlock(parkee);
-
-	/* We need to have the parker subscribe to the new local channel before hand. */
-	if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
-		ast_channel_unref(parkee_side_2);
-		ast_hangup(parkee);
-		return NULL;
-	}
-
-	ast_bridge_set_transfer_variables(parkee_side_2, ast_channel_name(parker), 0);
-
-	ast_channel_unref(parkee_side_2);
-
-	/* Since the above worked fine now we actually call it and return the channel */
-	if (ast_call(parkee, destination, 0)) {
-		ast_hangup(parkee);
-		return NULL;
-	}
-
-	return parkee;
-}
-
-/*!
- * \internal
- * \brief Determine if an extension is a parking extension
- */
-static int parking_is_exten_park(const char *context, const char *exten)
-{
-	struct ast_exten *exten_obj;
-	struct pbx_find_info info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-	const char *app_at_exten;
-
-	ast_debug(4, "Checking if %s@%s is a parking exten\n", exten, context);
-	exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH);
-	if (!exten_obj) {
-		return 0;
-	}
-
-	app_at_exten = ast_get_extension_app(exten_obj);
-	if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
-		return 0;
-	}
-
-	return 1;
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Perform a blind transfer to a parking lot
- *
- * In general, most parking features should work to call this function. This will safely
- * park either a channel in the bridge with \ref bridge_channel or will park the entire
- * bridge if more than one channel is in the bridge. It will create the correct data to
- * pass to the \ref AstBridging Bridging API to safely park the channel.
- *
- * \param bridge_channel The bridge_channel representing the channel performing the park
- * \param context The context to blind transfer to
- * \param exten The extension to blind transfer to
- * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
- * \param parked_channel_data Data for the parked_channel_cb
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
-		const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
-		struct transfer_channel_data *parked_channel_data)
-{
-	RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);
-
-	struct ast_exten *e;
-	struct pbx_find_info find_info = { .stacklen = 0 };
-	int peer_count;
-
-	if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
-		return -1;
-	}
-
-	if (!bridge_channel->in_bridge) {
-		return -1;
-	}
-
-	if (!parking_is_exten_park(context, exten)) {
-		return -1;
-	}
-
-	ast_bridge_channel_lock_bridge(bridge_channel);
-	peer_count = bridge_channel->bridge->num_channels;
-	if (peer_count == 2) {
-		other = ast_bridge_channel_peer(bridge_channel);
-		ao2_ref(other, +1);
-		other_chan = other->chan;
-		ast_channel_ref(other_chan);
-	}
-	ast_bridge_unlock(bridge_channel->bridge);
-
-	if (peer_count < 2) {
-		/* There is nothing to do if there is no one to park. */
-		return -1;
-	}
-
-	/* With a multiparty bridge, we need to do a regular blind transfer. We link the
-	 * existing bridge to the parking lot with a Local channel rather than
-	 * transferring others. */
-	if (peer_count > 2) {
-		struct ast_channel *transfer_chan = NULL;
-
-		transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
-		if (!transfer_chan) {
-			return -1;
-		}
-		ast_channel_ref(transfer_chan);
-
-		if (parked_channel_cb) {
-			parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
-		}
-
-		if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
-			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-			ast_hangup(transfer_chan);
-			ast_channel_unref(transfer_chan);
-			return -1;
-		}
-
-		ast_channel_unref(transfer_chan);
-
-		return 0;
-	}
-
-	/* Subscribe to park messages with the other channel entering */
-	if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
-		return -1;
-	}
-
-	if (parked_channel_cb) {
-		parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
-	}
-
-	e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
-
-	/* Write the park frame with the intended recipient and other data out to the bridge. */
-	ast_bridge_channel_write_park(bridge_channel,
-		ast_channel_uniqueid(other_chan),
-		ast_channel_uniqueid(bridge_channel->chan),
-		e ? ast_get_extension_app_data(e) : NULL);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Perform a direct park on a channel in a bridge
- *
- * \note This will be called from within the \ref AstBridging Bridging API
- *
- * \param bridge_channel The bridge_channel representing the channel to be parked
- * \param uuid_parkee The UUID of the channel being parked
- * \param uuid_parker The UUID of the channel performing the park
- * \param app_data Application parseable data to pass to the parking application
- */
-static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
-{
-	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
-
-	if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
-		/* We aren't the parkee, so ignore this action. */
-		return -1;
-	}
-
-	parker = ast_channel_get_by_name(uuid_parker);
-
-	if (!parker) {
-		ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
-		publish_parked_call_failure(bridge_channel->chan);
-		return -1;
-	}
-
-	if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
-		publish_parked_call_failure(bridge_channel->chan);
-		return -1;
-	}
-
-	ast_bridge_set_transfer_variables(bridge_channel->chan, ast_channel_name(parker), 0);
-
-	/* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
-	ao2_lock(bridge_channel);
-
-	original_bridge = bridge_channel->bridge;
-	if (!original_bridge) {
-		ao2_unlock(bridge_channel);
-		publish_parked_call_failure(bridge_channel->chan);
-		return -1;
-	}
-
-	ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */
-
-	ao2_unlock(bridge_channel);
-
-	if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) {
-		ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
-			ast_channel_name(bridge_channel->chan));
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \since 12.0.0
- * \brief Park a call
- *
- * \param parker The bridge_channel parking the call
- * \param exten Optional. The extension where the call was parked.
- * \param length Optional. If \c exten is specified, the length of the buffer.
- *
- * \note This will determine the context and extension to park the channel based on
- * the configuration of the \ref ast_channel associated with \ref parker. It will then
- * park either the channel or the entire bridge.
- *
- * \retval 0 on success
- * \retval -1 on error
- */
-static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
-{
-	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
-	const char *lot_name = NULL;
-
-	ast_channel_lock(parker->chan);
-	lot_name = find_channel_parking_lot_name(parker->chan);
-	if (!ast_strlen_zero(lot_name)) {
-		lot_name = ast_strdupa(lot_name);
-	}
-	ast_channel_unlock(parker->chan);
-
-	if (ast_strlen_zero(lot_name)) {
-		return -1;
-	}
-
-	lot = parking_lot_find_by_name(lot_name);
-	if (!lot) {
-		ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n",
-			ast_channel_name(parker->chan), lot_name);
-		return -1;
-	}
-
-	if (exten) {
-		ast_copy_string(exten, lot->cfg->parkext, length);
-	}
-	return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
-}
-
-static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	SCOPED_MODULE_USE(parking_get_module_info()->self);
-
-	return parking_park_call(bridge_channel, NULL, 0);
-}
-
-/*!
- * \internal
- * \brief Setup the caller features for when that channel is dialed.
- * \since 12.0.0
- *
- * \param chan Parked channel leaving the parking lot.
- * \param cfg Parking lot configuration.
- *
- * \return Nothing
- */
-static void parking_timeout_set_caller_features(struct ast_channel *chan, struct parking_lot_cfg *cfg)
-{
-	char features[5];
-	char *pos;
-
-	/*
-	 * We are setting the callee Dial flag values because in the
-	 * timeout case, the caller is who is being called back.
-	 */
-	pos = features;
-	if (cfg->parkedcalltransfers & AST_FEATURE_FLAG_BYCALLER) {
-		*pos++ = 't';
-	}
-	if (cfg->parkedcallreparking & AST_FEATURE_FLAG_BYCALLER) {
-		*pos++ = 'k';
-	}
-	if (cfg->parkedcallhangup & AST_FEATURE_FLAG_BYCALLER) {
-		*pos++ = 'h';
-	}
-	if (cfg->parkedcallrecording & AST_FEATURE_FLAG_BYCALLER) {
-		*pos++ = 'x';
-	}
-	*pos = '\0';
-
-	pbx_builtin_setvar_helper(chan, "BRIDGE_FEATURES", features);
-}
-
-/*! \internal
- * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
- *
- * \param bridge_channel bridge channel this interval hook is being executed on
- * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
- */
-static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct parked_user *user = hook_pvt;
-	struct ast_channel *chan = user->chan;
-	struct ast_context *park_dial_context;
-	const char *dial_string;
-	char *dial_string_flat;
-	char parking_space[AST_MAX_EXTENSION];
-
-	char returnexten[AST_MAX_EXTENSION];
-	char *duplicate_returnexten;
-	struct ast_exten *existing_exten;
-	struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */
-
-
-	/* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
-	   to deal with this, lock the parked user, check and set resolution. */
-	ao2_lock(user);
-	if (user->resolution != PARK_UNSET) {
-		/* Abandon timeout since something else has resolved the parked user before we got to it. */
-		ao2_unlock(user);
-		return -1;
-	}
-	user->resolution = PARK_TIMEOUT;
-	ao2_unlock(user);
-
-	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
-		AST_CAUSE_NORMAL_CLEARING);
-
-	dial_string = user->parker_dial_string;
-	dial_string_flat = ast_strdupa(dial_string);
-	flatten_dial_string(dial_string_flat);
-
-	/* Set parking timeout channel variables */
-	snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
-	ast_channel_lock(chan);
-	ast_channel_stage_snapshot(chan);
-	pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
-	pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
-	pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
-	pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
-	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
-	parking_timeout_set_caller_features(chan, user->lot->cfg);
-	ast_channel_stage_snapshot_done(chan);
-	ast_channel_unlock(chan);
-
-	/* Dialplan generation for park-dial extensions */
-
-	if (ast_wrlock_contexts()) {
-		ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
-		return -1;
-	}
-
-	if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
-		ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
-		if (ast_unlock_contexts()) {
-			ast_assert(0);
-		}
-		goto abandon_extension_creation;
-	}
-
-	if (ast_wrlock_context(park_dial_context)) {
-		ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
-		if (ast_unlock_contexts()) {
-			ast_assert(0);
-		}
-		goto abandon_extension_creation;
-	}
-
-	if (ast_unlock_contexts()) {
-		ast_assert(0);
-	}
-
-	snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
-		user->lot->cfg->comebackdialtime);
-
-	duplicate_returnexten = ast_strdup(returnexten);
-	if (!duplicate_returnexten) {
-		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
-			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
-	}
-
-	/* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
-	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
-	    (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
-		ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
-			dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
-	} else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
-			"Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
-			ast_free(duplicate_returnexten);
-		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
-			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
-	}
-
-	if (ast_unlock_context(park_dial_context)) {
-		ast_assert(0);
-	}
-
-abandon_extension_creation:
-
-	/* async_goto the proper PBX destination - this should happen when we come out of the bridge */
-	if (!ast_strlen_zero(user->comeback)) {
-		ast_async_parseable_goto(chan, user->comeback);
-	} else {
-		comeback_goto(user, user->lot);
-	}
-
-	return -1;
-}
-
-void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
-{
-	unsigned int numeric_value;
-	unsigned int hangup_after;
-
-	if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
-		/* If say_parking_space is called with a non-numeric string, we have a problem. */
-		ast_assert(0);
-		ast_bridge_channel_leave_bridge(bridge_channel,
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-		return;
-	}
-
-	ast_say_digits(bridge_channel->chan, numeric_value, "",
-		ast_channel_language(bridge_channel->chan));
-
-	if (hangup_after) {
-		ast_bridge_channel_leave_bridge(bridge_channel,
-			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
-	}
-}
-
-void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
-{
-	unsigned int time_limit;
-
-	time_limit = user->time_limit * 1000;
-
-	if (!time_limit) {
-		/* There is no duration limit that we need to apply. */
-		return;
-	}
-
-	/* If the time limit has already been passed, set a really low time limit so we can kick them out immediately. */
-	time_limit = ast_remaining_ms(user->start, time_limit);
-	if (time_limit <= 0) {
-		time_limit = 1;
-	}
-
-	/* The interval hook is going to need a reference to the parked_user */
-	ao2_ref(user, +1);
-
-	if (ast_bridge_interval_hook(features, 0, time_limit,
-		parking_duration_callback, user, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-		ast_log(LOG_ERROR, "Failed to apply duration limit to the parked call.\n");
-		ao2_ref(user, -1);
-	}
-}
-
-struct ast_parking_bridge_feature_fn_table parking_provider = {
-	.module_version = PARKING_MODULE_VERSION,
-	.module_name = __FILE__,
-	.parking_is_exten_park = parking_is_exten_park,
-	.parking_blind_transfer_park = parking_blind_transfer_park,
-	.parking_park_bridge_channel = parking_park_bridge_channel,
-	.parking_park_call = parking_park_call,
-};
-
-void unload_parking_bridge_features(void)
-{
-	ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_PARKCALL);
-	ast_parking_unregister_bridge_features(parking_provider.module_name);
-}
-
-int load_parking_bridge_features(void)
-{
-	parking_provider.module_info = parking_get_module_info();
-
-	if (ast_parking_register_bridge_features(&parking_provider)) {
-		return -1;
-	}
-
-	if (ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park_call, NULL)) {
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/res/parking/parking_controller.c b/res/parking/parking_controller.c
deleted file mode 100644
index 9e9e540..0000000
--- a/res/parking/parking_controller.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Parking Entry, Exit, and other assorted controls.
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-#include "asterisk.h"
-
-#include "asterisk/logger.h"
-#include "res_parking.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/utils.h"
-#include "asterisk/manager.h"
-#include "asterisk/test.h"
-#include "asterisk/features.h"
-#include "asterisk/bridge_basic.h"
-
-struct ast_bridge *parking_lot_get_bridge(struct parking_lot *lot)
-{
-	struct ast_bridge *lot_bridge;
-
-	if (lot->parking_bridge) {
-		ao2_ref(lot->parking_bridge, +1);
-		return lot->parking_bridge;
-	}
-
-	lot_bridge = bridge_parking_new(lot);
-	if (!lot_bridge) {
-		return NULL;
-	}
-
-	/* The parking lot needs a reference to the bridge as well. */
-	lot->parking_bridge = lot_bridge;
-	ao2_ref(lot->parking_bridge, +1);
-
-	return lot_bridge;
-}
-
-int parking_channel_set_roles(struct ast_channel *chan, struct parking_lot *lot, int force_ringing)
-{
-	if (ast_channel_add_bridge_role(chan, "holding_participant")) {
-		return -1;
-	}
-
-	if (force_ringing) {
-		if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing")) {
-			return -1;
-		}
-	} else {
-		if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold")) {
-			return -1;
-		}
-		if (!ast_strlen_zero(lot->cfg->mohclass)) {
-			if (ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", lot->cfg->mohclass)) {
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-struct parking_limits_pvt {
-	struct parked_user *user;
-};
-
-int unpark_parked_user(struct parked_user *pu)
-{
-	if (pu->lot) {
-		ao2_unlink(pu->lot->parked_users, pu);
-		parking_lot_remove_if_unused(pu->lot);
-		return 0;
-	}
-
-	return -1;
-}
-
-int parking_lot_get_space(struct parking_lot *lot, int target_override)
-{
-	int original_target;
-	int current_target;
-	struct ao2_iterator i;
-	struct parked_user *user;
-	int wrap;
-
-	if (lot->cfg->parkfindnext) {
-		/* Use next_space if the lot already has next_space set; otherwise use lot start. */
-		original_target = lot->next_space ? lot->next_space : lot->cfg->parking_start;
-	} else {
-		original_target = lot->cfg->parking_start;
-	}
-
-	if (target_override >= lot->cfg->parking_start && target_override <= lot->cfg->parking_stop) {
-		original_target = target_override;
-	}
-
-	current_target = original_target;
-
-	wrap = lot->cfg->parking_start;
-
-	i = ao2_iterator_init(lot->parked_users, 0);
-	while ((user = ao2_iterator_next(&i))) {
-		/* Increment the wrap on each pass until we find an empty space */
-		if (wrap == user->parking_space) {
-			wrap += 1;
-		}
-
-		if (user->parking_space < current_target) {
-			/* It's lower than the anticipated target, so we haven't reached the target yet. */
-			ao2_ref(user, -1);
-			continue;
-		}
-
-		if (user->parking_space > current_target) {
-			/* The current target is usable because all items below have been read and the next target is higher than the one we want. */
-			ao2_ref(user, -1);
-			break;
-		}
-
-		/* We found one already parked here. */
-		current_target += 1;
-		ao2_ref(user, -1);
-	}
-	ao2_iterator_destroy(&i);
-
-	if (current_target <= lot->cfg->parking_stop) {
-		return current_target;
-	}
-
-	if (wrap <= lot->cfg->parking_stop) {
-		return wrap;
-	}
-
-	return -1;
-}
-
-static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
-{
-	int *target = arg;
-	struct parked_user *user = obj;
-	if (user->parking_space == *target) {
-		return CMP_MATCH;
-	}
-
-	return 0;
-}
-
-struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target)
-{
-	RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
-
-	if (target < 0) {
-		user = ao2_callback(lot->parked_users, 0, NULL, NULL);
-	} else {
-		user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target);
-	}
-
-	if (!user) {
-		return NULL;
-	}
-
-	ao2_lock(user);
-	if (user->resolution != PARK_UNSET) {
-		/* Abandon. Something else has resolved the parked user before we got to it. */
-		ao2_unlock(user);
-		return NULL;
-	}
-
-	ao2_unlink(lot->parked_users, user);
-	user->resolution = PARK_ANSWERED;
-	ao2_unlock(user);
-
-	parking_lot_remove_if_unused(user->lot);
-
-	/* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
-	ao2_ref(user, +1);
-	return user;
-}
-
-void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parking_lot *lot, int recipient_mode)
-{
-	/* Enabling features here should be additive to features that are already on the channel. */
-	struct ast_flags feature_flags = { 0 };
-	struct ast_flags *existing_features;
-
-	ast_channel_lock(chan);
-	existing_features = ast_bridge_features_ds_get(chan);
-	if (existing_features) {
-		feature_flags = *existing_features;
-	}
-
-	if (lot->cfg->parkedcalltransfers & recipient_mode) {
-		ast_set_flag(&feature_flags, AST_FEATURE_REDIRECT);
-	}
-
-	if (lot->cfg->parkedcallreparking & recipient_mode) {
-		ast_set_flag(&feature_flags, AST_FEATURE_PARKCALL);
-	}
-
-	if (lot->cfg->parkedcallhangup & recipient_mode) {
-		ast_set_flag(&feature_flags, AST_FEATURE_DISCONNECT);
-	}
-
-	if (lot->cfg->parkedcallrecording & recipient_mode) {
-		ast_set_flag(&feature_flags, AST_FEATURE_AUTOMIXMON);
-	}
-
-	ast_bridge_features_ds_set(chan, &feature_flags);
-	ast_channel_unlock(chan);
-
-	return;
-}
-
-void flatten_dial_string(char *dialstring)
-{
-	int i;
-
-	for (i = 0; dialstring[i]; i++) {
-		if (dialstring[i] == '/') {
-			/* The underscore is the flattest character of all. */
-			dialstring[i] = '_';
-		}
-	}
-}
-
-int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
-{
-	struct ast_channel *chan = pu->chan;
-	char *peername_flat = ast_strdupa(pu->parker_dial_string);
-
-	/* Flatten the peername so that it can be used for performing the timeout PBX operations */
-	flatten_dial_string(peername_flat);
-
-	if (lot->cfg->comebacktoorigin) {
-		if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) {
-			ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1);
-			return 0;
-		} else {
-			ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
-				ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat);
-			return -1;
-		}
-	}
-
-	if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) {
-		ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1);
-		return 0;
-	}
-
-	if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) {
-		ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
-			lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
-		ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1);
-		return 0;
-	}
-
-	ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's at default'\n",
-		ast_channel_name(chan),
-		lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
-	ast_async_goto(chan, "default", "s", 1);
-
-	return 0;
-}
diff --git a/res/parking/parking_devicestate.c b/res/parking/parking_devicestate.c
deleted file mode 100644
index 3f6d07d..0000000
--- a/res/parking/parking_devicestate.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Device State Management
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-#include "asterisk/logger.h"
-#include "res_parking.h"
-#include "asterisk/devicestate.h"
-
-struct parking_lot_extension_inuse_search {
-	char *context;
-	int exten;
-};
-
-static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
-{
-	int *target = arg;
-	struct parked_user *user = obj;
-	if (user->parking_space == *target) {
-		return CMP_MATCH;
-	}
-
-	return 0;
-}
-
-static int parking_lot_search_context_extension_inuse(void *obj, void *arg, int flags)
-{
-	struct parking_lot *lot = obj;
-	struct parking_lot_extension_inuse_search *search = arg;
-	RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
-
-	if (strcmp(lot->cfg->parking_con, search->context)) {
-		return 0;
-	}
-
-	if ((search->exten < lot->cfg->parking_start) || (search->exten > lot->cfg->parking_stop)) {
-		return 0;
-	}
-
-	user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &search->exten);
-	if (!user) {
-		return 0;
-	}
-
-	ao2_lock(user);
-	if (user->resolution != PARK_UNSET) {
-		/* The parked user isn't in an answerable state. */
-		ao2_unlock(user);
-		return 0;
-	}
-	ao2_unlock(user);
-
-	return CMP_MATCH;
-}
-
-static enum ast_device_state metermaidstate(const char *data)
-{
-	struct ao2_container *global_lots = get_parking_lot_container();
-	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
-	char *context;
-	char *exten;
-	struct parking_lot_extension_inuse_search search = {};
-
-	context = ast_strdupa(data);
-
-	exten = strsep(&context, "@");
-
-	if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
-		return AST_DEVICE_INVALID;
-	}
-
-	search.context = context;
-	if (sscanf(exten, "%d", &search.exten) != 1) {
-		return AST_DEVICE_INVALID;
-	}
-
-	ast_debug(4, "Checking state of exten %d in context %s\n", search.exten, context);
-
-	lot = ao2_callback(global_lots, 0, parking_lot_search_context_extension_inuse, &data);
-	if (!lot) {
-		return AST_DEVICE_NOT_INUSE;
-	}
-
-	return AST_DEVICE_INUSE;
-}
-
-void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state)
-{
-	ast_debug(4, "Notification of state change to metermaids %d@%s\n to state '%s'\n",
-		exten, context, ast_devstate2str(state));
-
-	ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%d@%s", exten, context);
-}
-
-void unload_parking_devstate(void)
-{
-	ast_devstate_prov_del("Park");
-}
-
-int load_parking_devstate(void)
-{
-	return ast_devstate_prov_add("Park", metermaidstate);
-}
diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c
deleted file mode 100644
index df0c4ce..0000000
--- a/res/parking/parking_manager.c
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Manager Actions and Events
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "res_parking.h"
-#include "asterisk/config.h"
-#include "asterisk/config_options.h"
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/features.h"
-#include "asterisk/manager.h"
-#include "asterisk/bridge.h"
-#include "asterisk/module.h"
-
-/*** DOCUMENTATION
-	<manager name="Parkinglots" language="en_US">
-		<synopsis>
-			Get a list of parking lots
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>List all parking lots as a series of AMI events</para>
-		</description>
-	</manager>
-	<manager name="ParkedCalls" language="en_US">
-		<synopsis>
-			List parked calls.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="ParkingLot">
-				<para>If specified, only show parked calls from the parking lot with this name.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>List parked calls.</para>
-		</description>
-	</manager>
-	<manager name="Park" language="en_US">
-		<synopsis>
-			Park a channel.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Channel" required="true">
-				<para>Channel name to park.</para>
-			</parameter>
-			<parameter name="TimeoutChannel" required="false">
-				<para>Channel name to use when constructing the dial string that will be dialed if the parked channel
-				times out. If <literal>TimeoutChannel</literal> is in a two party bridge with
-				<literal>Channel</literal>, then <literal>TimeoutChannel</literal> will receive an announcement and be
-				treated as having parked <literal>Channel</literal> in the same manner as the Park Call DTMF feature.
-				</para>
-			</parameter>
-			<parameter name="AnnounceChannel" required="false">
-				<para>If specified, then this channel will receive an announcement when <literal>Channel</literal>
-				is parked if <literal>AnnounceChannel</literal> is in a state where it can receive announcements
-				(AnnounceChannel must be bridged). <literal>AnnounceChannel</literal> has no bearing on the actual
-				state of the parked call.</para>
-			</parameter>
-			<parameter name="Timeout" required="false">
-				<para>Overrides the timeout of the parking lot for this park action. Specified in milliseconds, but will be converted to
-					seconds. Use a value of 0 to disable the timeout.
-				</para>
-			</parameter>
-			<parameter name="Parkinglot" required="false">
-				<para>The parking lot to use when parking the channel</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Park an arbitrary channel with optional arguments for specifying the parking lot used, how long
-				the channel should remain parked, and what dial string to use as the parker if the call times out.
-			</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="ParkedCall">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel is parked.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Parkee"/>
-				<parameter name="ParkerDialString">
-					<para>Dial String that can be used to call back the parker on ParkingTimeout.</para>
-				</parameter>
-				<parameter name="Parkinglot">
-					<para>Name of the parking lot that the parkee is parked in</para>
-				</parameter>
-				<parameter name="ParkingSpace">
-					<para>Parking Space that the parkee is parked in</para>
-				</parameter>
-				<parameter name="ParkingTimeout">
-				<para>Time remaining until the parkee is forcefully removed from parking in seconds</para>
-				</parameter>
-				<parameter name="ParkingDuration">
-					<para>Time the parkee has been in the parking bridge (in seconds)</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ParkedCallTimeOut">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel leaves a parking lot due to reaching the time limit of being parked.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Parkee"/>
-				<channel_snapshot prefix="Parker"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ParkedCallGiveUp">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel leaves a parking lot because it hung up without being answered.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Parkee"/>
-				<channel_snapshot prefix="Parker"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter)" />
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="UnParkedCall">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when a channel leaves a parking lot because it was retrieved from the parking lot and reconnected.</synopsis>
-			<syntax>
-				<channel_snapshot prefix="Parkee"/>
-				<channel_snapshot prefix="Parker"/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter)" />
-				<channel_snapshot prefix="Retriever"/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
- ***/
-
-/*! \brief subscription to the parking lot topic */
-static struct stasis_subscription *parking_sub;
-
-static struct ast_parked_call_payload *parked_call_payload_from_failure(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	parkee_snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (!parkee_snapshot) {
-		return NULL;
-	}
-
-	return ast_parked_call_payload_create(PARKED_CALL_FAILED, parkee_snapshot, NULL, NULL, NULL, 0, 0, 0);
-}
-
-static struct ast_parked_call_payload *parked_call_payload_from_parked_user(struct parked_user *pu, enum ast_parked_call_event_type event_type)
-{
-	RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup);
-	long int timeout;
-	long int duration;
-	struct timeval now = ast_tvnow();
-	const char *lot_name = pu->lot->name;
-
-	ast_channel_lock(pu->chan);
-	parkee_snapshot = ast_channel_snapshot_create(pu->chan);
-	ast_channel_unlock(pu->chan);
-	if (!parkee_snapshot) {
-		return NULL;
-	}
-
-	timeout = pu->start.tv_sec + (long) pu->time_limit - now.tv_sec;
-	duration = now.tv_sec - pu->start.tv_sec;
-
-	return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker_dial_string, pu->retriever, lot_name, pu->parking_space, timeout, duration);
-
-}
-
-/*! \brief Builds a manager string based on the contents of a parked call payload */
-static struct ast_str *manager_build_parked_call_string(const struct ast_parked_call_payload *payload)
-{
-	struct ast_str *out = ast_str_create(1024);
-	RAII_VAR(struct ast_str *, parkee_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, retriever_string, NULL, ast_free);
-
-	if (!out) {
-		return NULL;
-	}
-
-	parkee_string = ast_manager_build_channel_state_string_prefix(payload->parkee, "Parkee");
-	if (!parkee_string) {
-		return NULL;
-	}
-
-	if (payload->retriever) {
-		retriever_string = ast_manager_build_channel_state_string_prefix(payload->retriever, "Retriever");
-	}
-
-	ast_str_set(&out, 0,
-		"%s" /* parkee channel state */
-		"%s" /* retriever channel state (when available) */
-		"ParkerDialString: %s\r\n"
-		"Parkinglot: %s\r\n"
-		"ParkingSpace: %u\r\n"
-		"ParkingTimeout: %lu\r\n"
-		"ParkingDuration: %lu\r\n",
-
-		ast_str_buffer(parkee_string),
-		retriever_string ? ast_str_buffer(retriever_string) : "",
-		payload->parker_dial_string,
-		payload->parkinglot,
-		payload->parkingspace,
-		payload->timeout,
-		payload->duration);
-
-	return out;
-}
-
-static void manager_parking_status_single_lot(struct mansession *s, const struct message *m, const char *id_text, const char *lot_name)
-{
-	RAII_VAR(struct parking_lot *, curlot, NULL, ao2_cleanup);
-	struct parked_user *curuser;
-	struct ao2_iterator iter_users;
-	int total = 0;
-
-	curlot = parking_lot_find_by_name(lot_name);
-	if (!curlot) {
-		astman_send_error(s, m, "Requested parking lot could not be found.");
-		return;
-	}
-
-	astman_send_ack(s, m, "Parked calls will follow");
-
-	iter_users = ao2_iterator_init(curlot->parked_users, 0);
-	while ((curuser = ao2_iterator_next(&iter_users))) {
-		RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_str *, parked_call_string, NULL, ast_free);
-
-		payload = parked_call_payload_from_parked_user(curuser, PARKED_CALL);
-		if (!payload) {
-			ao2_ref(curuser, -1);
-			ao2_iterator_destroy(&iter_users);
-			astman_send_error(s, m, "Failed to retrieve parking data about a parked user.");
-			return;
-		}
-
-		parked_call_string = manager_build_parked_call_string(payload);
-		if (!parked_call_string) {
-			ao2_ref(curuser, -1);
-			ao2_iterator_destroy(&iter_users);
-			astman_send_error(s, m, "Failed to retrieve parking data about a parked user.");
-			return;
-		}
-
-		total++;
-
-		astman_append(s, "Event: ParkedCall\r\n"
-			"%s" /* The parked call string */
-			"%s" /* The action ID */
-			"\r\n",
-			ast_str_buffer(parked_call_string),
-			id_text);
-
-		ao2_ref(curuser, -1);
-	}
-	ao2_iterator_destroy(&iter_users);
-
-	astman_append(s,
-		"Event: ParkedCallsComplete\r\n"
-		"Total: %d\r\n"
-		"%s"
-		"\r\n",
-		total, id_text);
-}
-
-static void manager_parking_status_all_lots(struct mansession *s, const struct message *m, const char *id_text)
-{
-	struct parked_user *curuser;
-	struct ao2_container *lot_container;
-	struct ao2_iterator iter_lots;
-	struct ao2_iterator iter_users;
-	struct parking_lot *curlot;
-	int total = 0;
-
-	lot_container = get_parking_lot_container();
-	if (!lot_container) {
-		ast_log(LOG_ERROR, "Failed to obtain parking lot list. Action canceled.\n");
-		astman_send_error(s, m, "Could not create parking lot list");
-		return;
-	}
-
-	astman_send_ack(s, m, "Parked calls will follow");
-
-	iter_lots = ao2_iterator_init(lot_container, 0);
-	while ((curlot = ao2_iterator_next(&iter_lots))) {
-		iter_users = ao2_iterator_init(curlot->parked_users, 0);
-		while ((curuser = ao2_iterator_next(&iter_users))) {
-			RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
-			RAII_VAR(struct ast_str *, parked_call_string, NULL, ast_free);
-
-			payload = parked_call_payload_from_parked_user(curuser, PARKED_CALL);
-			if (!payload) {
-				ao2_ref(curuser, -1);
-				ao2_iterator_destroy(&iter_users);
-				ao2_ref(curlot, -1);
-				ao2_iterator_destroy(&iter_lots);
-				return;
-			}
-
-			parked_call_string = manager_build_parked_call_string(payload);
-			if (!parked_call_string) {
-				ao2_ref(curuser, -1);
-				ao2_iterator_destroy(&iter_users);
-				ao2_ref(curlot, -1);
-				ao2_iterator_destroy(&iter_lots);
-				return;
-			}
-
-			total++;
-
-			astman_append(s, "Event: ParkedCall\r\n"
-				"%s" /* The parked call string */
-				"%s" /* The action ID */
-				"\r\n",
-				ast_str_buffer(parked_call_string),
-				id_text);
-
-			ao2_ref(curuser, -1);
-		}
-		ao2_iterator_destroy(&iter_users);
-		ao2_ref(curlot, -1);
-	}
-	ao2_iterator_destroy(&iter_lots);
-
-	astman_append(s,
-		"Event: ParkedCallsComplete\r\n"
-		"Total: %d\r\n"
-		"%s"
-		"\r\n",
-		total, id_text);
-}
-
-static int manager_parking_status(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	const char *lot_name = astman_get_header(m, "ParkingLot");
-	char id_text[256] = "";
-
-	if (!ast_strlen_zero(id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-	}
-
-	if (!ast_strlen_zero(lot_name)) {
-		manager_parking_status_single_lot(s, m, id_text, lot_name);
-	} else {
-		manager_parking_status_all_lots(s, m, id_text);
-	}
-
-	return 0;
-}
-
-static int manager_append_event_parking_lot_data_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct parking_lot *curlot = obj;
-	struct mansession *s = arg;
-	char *id_text = data;
-
-	astman_append(s, "Event: Parkinglot\r\n"
-		"Name: %s\r\n"
-		"StartSpace: %d\r\n"
-		"StopSpace: %d\r\n"
-		"Timeout: %u\r\n"
-		"%s" /* The Action ID */
-		"\r\n",
-		curlot->name,
-		curlot->cfg->parking_start,
-		curlot->cfg->parking_stop,
-		curlot->cfg->parkingtime,
-		id_text);
-
-	return 0;
-}
-
-static int manager_parking_lot_list(struct mansession *s, const struct message *m)
-{
-	const char *id = astman_get_header(m, "ActionID");
-	char id_text[256] = "";
-	struct ao2_container *lot_container;
-
-	if (!ast_strlen_zero(id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-	}
-
-	lot_container = get_parking_lot_container();
-	if (!lot_container) {
-		ast_log(LOG_ERROR, "Failed to obtain parking lot list. Action canceled.\n");
-		astman_send_error(s, m, "Could not create parking lot list");
-		return 0;
-	}
-
-	astman_send_ack(s, m, "Parking lots will follow");
-
-	ao2_callback_data(lot_container, OBJ_MULTIPLE | OBJ_NODATA, manager_append_event_parking_lot_data_cb, s, id_text);
-
-	astman_append(s,
-		"Event: ParkinglotsComplete\r\n"
-		"%s"
-		"\r\n",id_text);
-
-	return 0;
-}
-
-static void manager_park_unbridged(struct mansession *s, const struct message *m,
-		struct ast_channel *chan, const char *parkinglot, int timeout_override)
-{
-	struct ast_bridge *parking_bridge = park_common_setup(chan,
-		chan, parkinglot, NULL, 0, 0, timeout_override, 1);
-
-	if (!parking_bridge) {
-		astman_send_error(s, m, "Park action failed\n");
-		return;
-	}
-
-	if (ast_bridge_add_channel(parking_bridge, chan, NULL, 0, NULL)) {
-		astman_send_error(s, m, "Park action failed\n");
-		ao2_cleanup(parking_bridge);
-		return;
-	}
-
-	astman_send_ack(s, m, "Park successful\n");
-	ao2_cleanup(parking_bridge);
-}
-
-static void manager_park_bridged(struct mansession *s, const struct message *m,
-		struct ast_channel *chan, struct ast_channel *parker_chan,
-		const char *parkinglot, int timeout_override)
-{
-	struct ast_bridge_channel *bridge_channel;
-	char *app_data;
-
-	if (timeout_override != -1) {
-		if (ast_asprintf(&app_data, "%s,t(%d)", parkinglot, timeout_override) == -1) {
-			astman_send_error(s, m, "Park action failed\n");
-			return;
-		}
-	} else {
-		if (ast_asprintf(&app_data, "%s", parkinglot) == -1) {
-			astman_send_error(s, m, "Park action failed\n");
-			return;
-		}
-	}
-
-	ast_channel_lock(parker_chan);
-	bridge_channel = ast_channel_get_bridge_channel(parker_chan);
-	ast_channel_unlock(parker_chan);
-
-	if (!bridge_channel) {
-		ast_free(app_data);
-		astman_send_error(s, m, "Park action failed\n");
-		return;
-	}
-
-	/* Subscribe to park messages for the channel being parked */
-	if (create_parked_subscription(parker_chan, ast_channel_uniqueid(chan), 1)) {
-		ast_free(app_data);
-		astman_send_error(s, m, "Park action failed\n");
-		ao2_cleanup(bridge_channel);
-		return;
-	}
-
-	ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(chan),
-			ast_channel_uniqueid(parker_chan), app_data);
-
-	ast_free(app_data);
-
-	astman_send_ack(s, m, "Park successful\n");
-	ao2_cleanup(bridge_channel);
-}
-
-static int manager_park(struct mansession *s, const struct message *m)
-{
-	const char *channel = astman_get_header(m, "Channel");
-	const char *timeout_channel = S_OR(astman_get_header(m, "TimeoutChannel"), astman_get_header(m, "Channel2"));
-	const char *announce_channel = astman_get_header(m, "AnnounceChannel");
-	const char *timeout = astman_get_header(m, "Timeout");
-	const char *parkinglot = astman_get_header(m, "Parkinglot");
-	char buf[BUFSIZ];
-	int timeout_override = -1;
-
-	RAII_VAR(struct ast_channel *, parker_chan, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(channel)) {
-		astman_send_error(s, m, "Channel not specified");
-		return 0;
-	}
-
-	if (!ast_strlen_zero(timeout)) {
-		if (sscanf(timeout, "%30d", &timeout_override) != 1 || timeout < 0) {
-			astman_send_error(s, m, "Invalid Timeout value.");
-			return 0;
-		}
-
-		if (timeout_override > 0) {
-			/* If greater than zero, convert to seconds for internal use. Must be >= 1 second. */
-			timeout_override = MAX(1, timeout_override / 1000);
-		}
-	}
-
-	if (!(chan = ast_channel_get_by_name(channel))) {
-		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
-		astman_send_error(s, m, buf);
-		return 0;
-	}
-
-	ast_channel_lock(chan);
-	if (!ast_strlen_zero(timeout_channel)) {
-		ast_bridge_set_transfer_variables(chan, timeout_channel, 0);
-	}
-	ast_channel_unlock(chan);
-
-	parker_chan = ast_channel_bridge_peer(chan);
-	if (!parker_chan || strcmp(ast_channel_name(parker_chan), timeout_channel)) {
-		if (!ast_strlen_zero(announce_channel)) {
-			struct ast_channel *announce_chan = ast_channel_get_by_name(announce_channel);
-			if (!announce_channel) {
-				astman_send_error(s, m, "AnnounceChannel does not exist");
-				return 0;
-			}
-
-			create_parked_subscription(announce_chan, ast_channel_uniqueid(chan), 0);
-			ast_channel_cleanup(announce_chan);
-		}
-
-		manager_park_unbridged(s, m, chan, parkinglot, timeout_override);
-		return 0;
-	}
-
-	if (!ast_strlen_zero(announce_channel) && strcmp(announce_channel, timeout_channel)) {
-		/* When using an announce_channel in bridge mode, only add the announce channel if it isn't
-		 * the same as the timeout channel (which will play announcements anyway) */
-		struct ast_channel *announce_chan = ast_channel_get_by_name(announce_channel);
-		if (!announce_channel) {
-			astman_send_error(s, m, "AnnounceChannel does not exist");
-			return 0;
-		}
-
-		create_parked_subscription(announce_chan, ast_channel_uniqueid(chan), 0);
-		ast_channel_cleanup(announce_chan);
-	}
-
-	manager_park_bridged(s, m, chan, parker_chan, parkinglot, timeout_override);
-	return 0;
-}
-
-void publish_parked_call_failure(struct ast_channel *parkee)
-{
-	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!ast_parked_call_type()) {
-		return;
-	}
-
-	payload = parked_call_payload_from_failure(parkee);
-	if (!payload) {
-		return;
-	}
-
-	msg = stasis_message_create(ast_parked_call_type(), payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_parking_topic(), msg);
-}
-
-void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type event_type)
-{
-	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	if (!ast_parked_call_type()) {
-		return;
-	}
-
-	payload = parked_call_payload_from_parked_user(pu, event_type);
-	if (!payload) {
-		return;
-	}
-
-	msg = stasis_message_create(ast_parked_call_type(), payload);
-	if (!msg) {
-		return;
-	}
-
-	stasis_publish(ast_parking_topic(), msg);
-}
-
-static void parked_call_message_response(struct ast_parked_call_payload *parked_call)
-{
-	char *event_type = "";
-	RAII_VAR(struct ast_str *, parked_call_string, NULL, ast_free);
-
-	switch (parked_call->event_type) {
-	case PARKED_CALL:
-		event_type = "ParkedCall";
-		break;
-	case PARKED_CALL_TIMEOUT:
-		event_type = "ParkedCallTimeOut";
-		break;
-	case PARKED_CALL_GIVEUP:
-		event_type = "ParkedCallGiveUp";
-		break;
-	case PARKED_CALL_UNPARKED:
-		event_type = "UnParkedCall";
-		break;
-	case PARKED_CALL_SWAP:
-		event_type = "ParkedCallSwap";
-		break;
-	case PARKED_CALL_FAILED:
-		/* PARKED_CALL_FAILED doesn't currently get a message and is used exclusively for bridging */
-		return;
-	}
-
-	parked_call_string = manager_build_parked_call_string(parked_call);
-	if (!parked_call_string) {
-		ast_log(LOG_ERROR, "Failed to issue an AMI event of '%s' in response to a stasis message.\n", event_type);
-		return;
-	}
-
-	manager_event(EVENT_FLAG_CALL, event_type,
-			"%s",
-			ast_str_buffer(parked_call_string)
-		);
-}
-
-static void parking_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	if (stasis_message_type(message) == ast_parked_call_type()) {
-		struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
-		parked_call_message_response(parked_call_message);
-	}
-}
-
-static void parking_manager_enable_stasis(void)
-{
-	if (!parking_sub) {
-		parking_sub = stasis_subscribe(ast_parking_topic(), parking_event_cb, NULL);
-	}
-}
-
-int load_parking_manager(void)
-{
-	int res;
-	const struct ast_module_info *module = parking_get_module_info();
-
-	res = ast_manager_register2("Parkinglots", EVENT_FLAG_CALL, manager_parking_lot_list, module->self, NULL, NULL);
-	res |= ast_manager_register2("ParkedCalls", EVENT_FLAG_CALL, manager_parking_status, module->self, NULL, NULL);
-	res |= ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, module->self, NULL, NULL);
-	parking_manager_enable_stasis();
-	return res ? -1 : 0;
-}
-
-static void parking_manager_disable_stasis(void)
-{
-	parking_sub = stasis_unsubscribe(parking_sub);
-}
-
-void unload_parking_manager(void)
-{
-	ast_manager_unregister("Parkinglots");
-	ast_manager_unregister("ParkedCalls");
-	ast_manager_unregister("Park");
-	parking_manager_disable_stasis();
-}
diff --git a/res/parking/parking_tests.c b/res/parking/parking_tests.c
deleted file mode 100644
index dd1d554..0000000
--- a/res/parking/parking_tests.c
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Unit Tests
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428169 $")
-
-#include "res_parking.h"
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/test.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/time.h"
-#include "asterisk/causes.h"
-#include "asterisk/pbx.h"
-#include "asterisk/format_cache.h"
-
-#if defined(TEST_FRAMEWORK)
-
-#define TEST_CATEGORY "/res/parking/"
-
-#define CHANNEL_TECH_NAME "ParkingTestChannel"
-
-static const struct ast_party_caller alice_callerid = {
-	.id.name.str = "Alice",
-	.id.name.valid = 1,
-	.id.number.str = "100",
-	.id.number.valid = 1,
-};
-
-static int parking_test_write(struct ast_channel *chan, struct ast_frame *frame)
-{
-	return 0;
-}
-
-static struct ast_frame *parking_test_read(struct ast_channel *chan)
-{
-	return &ast_null_frame;
-}
-
-static const struct ast_channel_tech parking_test_tech = {
-	.type = CHANNEL_TECH_NAME,
-	.description = "Parking unit test technology",
-	.write = parking_test_write,
-	.read = parking_test_read,
-};
-
-/*! \brief Set ulaw format on the channel */
-static int set_test_formats(struct ast_channel *chan)
-{
-	struct ast_format_cap *caps;
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		return -1;
-	}
-
-	ast_format_cap_append(caps, ast_format_ulaw, 0);
-	ast_channel_nativeformats_set(chan, caps);
-	ast_channel_set_writeformat(chan, ast_format_ulaw);
-	ast_channel_set_rawwriteformat(chan, ast_format_ulaw);
-	ast_channel_set_readformat(chan, ast_format_ulaw);
-	ast_channel_set_rawreadformat(chan, ast_format_ulaw);
-	ao2_ref(caps, -1);
-
-	return 0;
-}
-
-/*! \brief Create a \ref test_cdr_chan_tech for Alice */
-static struct ast_channel *create_alice_channel(void)
-{
-	struct ast_channel *alice = ast_channel_alloc(0, AST_STATE_DOWN,
-		"100", "Alice", "100", "100", "default", NULL, NULL, 0,
-		CHANNEL_TECH_NAME "/Alice");
-
-	if (!alice) {
-		return NULL;
-	}
-
-	if (set_test_formats(alice)) {
-		ast_channel_unlock(alice);
-		ast_channel_release(alice);
-		return NULL;
-	}
-
-	ast_channel_tech_set(alice, &parking_test_tech);
-
-	ast_channel_set_caller(alice, &alice_callerid, NULL);
-
-	ast_channel_unlock(alice);
-
-	return alice;
-}
-
-/*! \brief Hang up a test channel safely */
-static struct ast_channel *hangup_channel(struct ast_channel *chan, int hangup_cause)
-{
-	ast_channel_hangupcause_set(chan, hangup_cause);
-	ast_hangup(chan);
-	return NULL;
-}
-
-static void safe_channel_release(struct ast_channel *chan)
-{
-	if (!chan) {
-		return;
-	}
-	ast_channel_release(chan);
-}
-
-static void do_sleep(struct timespec *to_sleep)
-{
-	while ((nanosleep(to_sleep, to_sleep) == -1) && (errno == EINTR)) {
-	}
-}
-
-static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
-{
-	return 0;
-}
-
-static const struct ast_channel_tech fake_tech = {
-	.fixup = fake_fixup, /* silence warning from masquerade... though those shouldn't be happening now */
-};
-
-#define TEST_LOT_NAME "unit_tests_res_parking_test_lot"
-
-static struct parking_lot *generate_test_parking_lot(const char *name, int low_space, int high_space, const char *park_exten, const char *park_context, struct ast_test *test)
-{
-	RAII_VAR(struct parking_lot_cfg *, test_cfg, NULL, ao2_cleanup);
-	struct parking_lot *test_lot;
-
-	test_cfg = parking_lot_cfg_create(name);
-	if (!test_cfg) {
-		return NULL;
-	}
-
-	test_cfg->parking_start = low_space;
-	test_cfg->parking_stop = high_space;
-	test_cfg->parkingtime = 10;
-	test_cfg->comebackdialtime = 10;
-	test_cfg->parkfindnext = 1;
-	test_cfg->parkext_exclusive = 1;
-	ast_string_field_set(test_cfg, parkext, park_exten);
-	ast_string_field_set(test_cfg, parking_con, park_context);
-	ast_string_field_set(test_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
-
-	if (parking_lot_cfg_create_extensions(test_cfg)) {
-		ast_test_status_update(test, "Extensions for parking lot '%s' could not be registered. Extension Creation failed.\n", name);
-		return NULL;
-	}
-
-	test_lot = parking_lot_build_or_update(test_cfg, 1);
-	if (!test_lot) {
-		return NULL;
-	}
-
-	return test_lot;
-}
-
-static int dispose_test_lot(struct parking_lot *test_lot, int expect_destruction)
-{
-	RAII_VAR(struct parking_lot *, found_lot, NULL, ao2_cleanup);
-
-	test_lot->mode = PARKINGLOT_DISABLED;
-	parking_lot_remove_if_unused(test_lot);
-
-	found_lot = parking_lot_find_by_name(test_lot->name);
-
-	if ((expect_destruction && !found_lot) || (!expect_destruction && found_lot)) {
-		return 0;
-	}
-
-	return -1;
-}
-
-AST_TEST_DEFINE(create_lot)
-{
-	RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct parking_lot *, found_copy, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "create_lot";
-		info->category = TEST_CATEGORY;
-		info->summary = "Parking lot creation";
-		info->description =
-			"Creates a parking lot and then disposes of it.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
-
-	test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
-	if (!test_lot) {
-		ast_test_status_update(test, "Failed to create test parking lot. Test Failed\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_status_update(test, "Successfully created parking lot. Retrieving test parking lot from container.\n");
-
-	found_copy = parking_lot_find_by_name(TEST_LOT_NAME);
-	if (!found_copy) {
-		ast_test_status_update(test, "Failed to find parking lot in the parking lot container. Test failed.\n");
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_status_update(test, "Successfully retrieved parking lot. Removing test parking lot from container.\n");
-
-	if (dispose_test_lot(found_copy, 1)) {
-		ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
-	}
-
-	ast_test_status_update(test, "Parking lot was successfully removed from the container. Test complete.\n");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(park_call)
-{
-	RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-
-	struct timespec to_sleep = {1, 0};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "park_channel";
-		info->category = TEST_CATEGORY;
-		info->summary = "Park a Channel";
-		info->description =
-			"Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
-
-	test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
-	if (!test_lot) {
-		ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	chan_alice = create_alice_channel();
-	if (!chan_alice) {
-		ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	ast_channel_state_set(chan_alice, AST_STATE_UP);
-	pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
-
-	parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
-	if (!parking_bridge) {
-		ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
-		AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
-		ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_alice);
-
-	chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
-
-	if (dispose_test_lot(test_lot, 1)) {
-		ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-
-}
-
-static int parked_users_match(const struct parked_user *actual, const struct parked_user *expected, struct ast_test *test)
-{
-	if (expected->parking_space != actual->parking_space) {
-		ast_test_status_update(test, "parking_space expected: %d - got: %d\n", expected->parking_space, actual->parking_space);
-		return 0;
-	}
-
-	if (strcmp(expected->parker_dial_string, actual->parker_dial_string)) {
-		ast_test_status_update(test, "parker_dial_string expected: %s - got: %s\n", expected->parker_dial_string, actual->parker_dial_string);
-		return 0;
-	}
-
-	if (expected->time_limit != actual->time_limit) {
-		ast_test_status_update(test, "time_limit expected: %u - got: %u\n", expected->time_limit, actual->time_limit);
-		return 0;
-	}
-
-	if (expected->resolution != actual->resolution) {
-		ast_test_status_update(test, "resolution expected: %u - got: %u\n", expected->resolution, actual->resolution);
-		return 0;
-	}
-
-	return 1;
-}
-
-static int parking_lot_cfgs_match(const struct parking_lot_cfg *actual, const struct parking_lot_cfg *expected, struct ast_test *test)
-{
-	if (expected->parking_start != actual->parking_start) {
-		ast_test_status_update(test, "parking_start expected: %d - got: %d\n", expected->parking_start, actual->parking_start);
-		return 0;
-	}
-
-	if (expected->parking_stop != actual->parking_stop) {
-		ast_test_status_update(test, "parking_stop expected: %d - got: %d\n", expected->parking_stop, actual->parking_stop);
-		return 0;
-	}
-
-	if (expected->parkingtime != actual->parkingtime) {
-		ast_test_status_update(test, "parkingtime expected: %u - got: %u\n", expected->parkingtime, actual->parkingtime);
-		return 0;
-	}
-
-	if (expected->comebackdialtime != actual->comebackdialtime) {
-		ast_test_status_update(test, "comebackdialtime expected: %u - got: %u\n", expected->comebackdialtime, actual->comebackdialtime);
-		return 0;
-	}
-
-	if (expected->parkfindnext != actual->parkfindnext) {
-		ast_test_status_update(test, "parkfindnext expected: %u - got: %u\n", expected->parkfindnext, actual->parkfindnext);
-		return 0;
-	}
-
-	if (expected->parkext_exclusive != actual->parkext_exclusive) {
-		ast_test_status_update(test, "parkext_exclusive expected: %u - got: %u\n", expected->parkext_exclusive, actual->parkext_exclusive);
-		return 0;
-	}
-
-	if (strcmp(expected->parkext, actual->parkext)) {
-		ast_test_status_update(test, "parkext expected: %s - got: %s\n", expected->parkext, actual->parkext);
-		return 0;
-	}
-
-	if (strcmp(expected->parking_con, actual->parking_con)) {
-		ast_test_status_update(test, "parking_con expected: %s - got: %s\n", expected->parking_con, actual->parking_con);
-		return 0;
-	}
-
-	if (strcmp(expected->comebackcontext, actual->comebackcontext)) {
-		ast_test_status_update(test, "comebackcontext expected: %s - got: %s\n", expected->comebackcontext, actual->comebackcontext);
-		return 0;
-	}
-
-	return 1;
-}
-
-AST_TEST_DEFINE(retrieve_call)
-{
-	RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-	RAII_VAR(struct parked_user *, retrieved_user, NULL, ao2_cleanup);
-
-	struct timespec to_sleep = {1, 0};
-	int failure = 0;
-
-	static const struct parked_user expected_user = {
-		.parking_space = 701,
-		.parker_dial_string = "ParkingTestChannel/Alice",
-		.time_limit = 10,
-		.resolution = PARK_ANSWERED,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "park_retrieve";
-		info->category = TEST_CATEGORY;
-		info->summary = "Retrieve a parked channel";
-		info->description =
-			"Creates a parking lot, parks a channel in it, then removes it from the parking lot bridge.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_status_update(test, "Creating test parking lot '%s'\n", TEST_LOT_NAME);
-
-	test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, NULL, "unit_test_res_parking_create_lot_con", test);
-	if (!test_lot) {
-		ast_test_status_update(test, "Failed to create test parking lot. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	chan_alice = create_alice_channel();
-	if (!chan_alice) {
-		ast_test_status_update(test, "Failed to create test channel to park. Test failed.\n");
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	ast_channel_state_set(chan_alice, AST_STATE_UP);
-	pbx_builtin_setvar_helper(chan_alice, "BLINDTRANSFER", ast_channel_name(chan_alice));
-
-	parking_bridge = park_application_setup(chan_alice, chan_alice, TEST_LOT_NAME, NULL);
-	if (!parking_bridge) {
-		ast_test_status_update(test, "Failed to get the parking bridge for '%s'. Test failed.\n", TEST_LOT_NAME);
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bridge_impart(parking_bridge, chan_alice, NULL, NULL,
-		AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) {
-		ast_test_status_update(test, "Failed to impart alice into parking lot. Test failed.\n");
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	do_sleep(&to_sleep);
-
-	retrieved_user = parking_lot_retrieve_parked_user(test_lot, 701);
-	if (!retrieved_user) {
-		ast_test_status_update(test, "Failed to retrieve the parked user from the expected parking space. Test failed.\n");
-		failure = 1;
-		goto test_cleanup;
-	}
-
-	ast_test_status_update(test, "Successfully retrieved parked user from the parking lot. Validating user data.\n");
-
-	if (!parked_users_match(retrieved_user, &expected_user, test)) {
-		ast_test_status_update(test, "Parked user validation failed\n");
-		failure = 1;
-		goto test_cleanup;
-	}
-
-	if (retrieved_user->chan != chan_alice) {
-		ast_test_status_update(test, "The retrieved parked channel didn't match the expected channel. Test failed.\n");
-		failure = 1;
-		goto test_cleanup;
-	}
-
-test_cleanup:
-	ast_bridge_depart(chan_alice);
-	chan_alice = hangup_channel(chan_alice, AST_CAUSE_NORMAL);
-	if (dispose_test_lot(test_lot, 1)) {
-		ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
-		failure = 1;
-	}
-
-	return failure ? AST_TEST_FAIL : AST_TEST_PASS;
-}
-
-static int check_retrieve_call_extensions(struct ast_test *test, int expected)
-{
-	struct ast_exten *check;
-	struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-	int extens;
-	char search_buffer[4];
-
-	/* Check the parking extensions */
-	check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", "700", 1, NULL, NULL, E_MATCH);
-
-	if (check ? !expected : expected) {
-		/* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
-		ast_test_status_update(test, "An extension '700' was %s when it %s have been. Test failed.\n",
-			expected ? "not present" : "present",
-			expected ? "should" : "should not");
-		return -1;
-	} else if (check && expected) {
-		if (strcmp(ast_get_extension_app(check), "Park")) {
-			ast_test_status_update(test, "An extension '700' has the wrong application associated with it. Got '%s' expected 'Park'.\n",
-				ast_get_extension_app(check));
-			return -1;
-		}
-	}
-
-
-	/* Check the parking space extensions 701-703 */
-	for (extens = 701; extens <= 703; extens++) {
-		sprintf(search_buffer, "%d", extens);
-		find_info.stacklen = 0; /* reset for pbx_find_extension */
-
-		check = pbx_find_extension(NULL, NULL, &find_info, "unit_test_res_parking_create_lot_con", search_buffer, 1, NULL, NULL, E_MATCH);
-
-		if (check ? !expected : expected) {
-			/* extension isn't present when it should be or is present when it shouldn't be. Automatic failure. */
-			ast_test_status_update(test, "An extension '%s' was %s when it %s have been. Test failed.\n",
-				search_buffer,
-				expected ? "not present" : "present",
-				expected ? "should" : "should not");
-			return -1;
-		} else if (check && expected) {
-			if (strcmp(ast_get_extension_app(check), "ParkedCall")) {
-				ast_test_status_update(test, "An extension '%s' has the wrong application associated with it. Got '%s', expected 'ParkedCall'.\n",
-					search_buffer,
-					ast_get_extension_app(check));
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-
-}
-
-AST_TEST_DEFINE(park_extensions)
-{
-	RAII_VAR(struct parking_lot *, test_lot, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "park_extensions";
-		info->category = TEST_CATEGORY;
-		info->summary = "Parking lot extension creation tests";
-		info->description =
-			"Creates parking lots and checks that they registered the expected extensions, then removes them.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	test_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
-	if (!test_lot) {
-		ast_test_status_update(test, "Failed to create test parking lot. Test Failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (check_retrieve_call_extensions(test, 1)) {
-		dispose_test_lot(test_lot, 1);
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_status_update(test, "Extensions for the test parking lot were verified. Cleaning up and verifying their removal.\n");
-
-	if (dispose_test_lot(test_lot, 1)) {
-		ast_test_status_update(test, "Found parking lot in container after attempted removal. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-	ao2_cleanup(test_lot);
-	test_lot = NULL;
-
-	if (check_retrieve_call_extensions(test, 0)) {
-		ast_log(LOG_ERROR, "Test 'park_extensions' failed to clean up after itself properly.\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_status_update(test, "Extensions for the test parking lot verified as removed. Test completed successfully.\n");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(extension_conflicts)
-{
-	RAII_VAR(struct parking_lot *, base_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct parking_lot *, expect_fail1, NULL, ao2_cleanup); /* Failure due to overlapping parkexten */
-	RAII_VAR(struct parking_lot *, expect_fail2, NULL, ao2_cleanup); /* Failure due to overlapping spaces */
-	RAII_VAR(struct parking_lot *, expect_fail3, NULL, ao2_cleanup); /* parkexten overlaps parking spaces */
-	RAII_VAR(struct parking_lot *, expect_fail4, NULL, ao2_cleanup); /* parking spaces overlap parkexten */
-	RAII_VAR(struct parking_lot *, expect_success1, NULL, ao2_cleanup); /* Success due to being in a different context */
-	RAII_VAR(struct parking_lot *, expect_success2, NULL, ao2_cleanup); /* Success due to not having overlapping extensions */
-	RAII_VAR(struct parking_lot *, expect_success3, NULL, ao2_cleanup); /* Range of parking spaces differs by one above */
-	RAII_VAR(struct parking_lot *, expect_success4, NULL, ao2_cleanup); /* Range of parking spaces differs by one below */
-	char *cur_lot_name;
-
-	int failed = 0;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "extension_conflicts";
-		info->category = TEST_CATEGORY;
-		info->summary = "Tests the addition of parking lot extensions to make sure conflicts are detected";
-		info->description =
-			"Creates parking lots with overlapping extensions to test for conflicts";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_status_update(test, "Creating the base lot. This should pass.\n");
-	base_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
-
-	if (!base_lot) {
-		ast_test_status_update(test, "Failed to create the base parking lot. Test failed.\n");
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_fail1";
-	ast_test_status_update(test, "Creating a test lot which will overlap.\n");
-	expect_fail1 = generate_test_parking_lot(cur_lot_name,
-		801, 803, "700", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the parkexten of the base */
-		test);
-
-	if (expect_fail1) {
-		ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_fail2";
-	expect_fail2 = generate_test_parking_lot(cur_lot_name,
-		702, 705, "800", "unit_test_res_parking_create_lot_con", /* The range overlaps the range of the base */
-		test);
-	if (expect_fail2) {
-		ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_fail3";
-	expect_fail3 = generate_test_parking_lot(cur_lot_name,
-		698, 700, "testfail3", "unit_test_res_parking_create_lot_con", /* The range overlaps the parkexten of the base */
-		test);
-	if (expect_fail3) {
-		ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_fail4";
-	expect_fail4 = generate_test_parking_lot(cur_lot_name,
-		704, 706, "703", "unit_test_res_parking_create_lot_con", /* The parkexten overlaps the range of the base */
-		test);
-	if (expect_fail4) {
-		ast_test_status_update(test, "%s was successfully created when it was expected to fail. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_success1";
-	expect_success1 = generate_test_parking_lot(cur_lot_name,
-		701, 703, "700", "unit_test_res_parking_create_lot_con_2", /* no overlap due to different context */
-		test);
-	if (!expect_success1) {
-		ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_success2";
-	expect_success2 = generate_test_parking_lot(cur_lot_name,
-		601, 605, "600", "unit_test_res_parking_create_lot_con", /* no overlap due to different extensions and ranges */
-		test);
-	if (!expect_success2) {
-		ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_success3";
-	expect_success3 = generate_test_parking_lot(cur_lot_name,
-		704, 706, "testsuccess3", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces start 1 above existing ranges */
-		test);
-	if (!expect_success3) {
-		ast_test_status_update(test, "%s failed to be created. Success was expected. Test failed.\n", cur_lot_name);
-		failed = 1;
-		goto cleanup;
-	}
-
-	cur_lot_name = "unit_tests_res_parking_test_lot_success4";
-	expect_success4 = generate_test_parking_lot(cur_lot_name,
-		697, 699, "testsuccess4", "unit_test_res_parking_create_lot_con", /* no overlap because the parking spaces end 1 below existing ranges */
-		test);
-	if (!expect_success4) {
-		failed = 1;
-		goto cleanup;
-	}
-
-cleanup:
-	if (base_lot && dispose_test_lot(base_lot, 1)) {
-		ast_test_status_update(test, "Found base parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	if (expect_fail1) {
-		dispose_test_lot(expect_fail1, 1);
-		failed = 1;
-	}
-
-	if (expect_fail2) {
-		dispose_test_lot(expect_fail2, 1);
-		failed = 1;
-	}
-
-	if (expect_fail3) {
-		dispose_test_lot(expect_fail3, 1);
-		failed = 1;
-	}
-
-	if (expect_fail4) {
-		dispose_test_lot(expect_fail4, 1);
-		failed = 1;
-	}
-
-	if (expect_success1 && dispose_test_lot(expect_success1, 1)) {
-		ast_test_status_update(test, "Found expect_success1 parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	if (expect_success2 && dispose_test_lot(expect_success2, 1)) {
-		ast_test_status_update(test, "Found expect_success2 parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	if (expect_success3 && dispose_test_lot(expect_success3, 1)) {
-		ast_test_status_update(test, "Found expect_success3 parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	if (expect_success4 && dispose_test_lot(expect_success4, 1)) {
-		ast_test_status_update(test, "Found expect_success4 parking lot in container after attempted removal. Test failed.\n");
-	}
-
-	return failed ? AST_TEST_FAIL : AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(dynamic_parking_variables)
-{
-	RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct parking_lot *, dynamic_lot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct parking_lot_cfg *, expected_cfg, NULL, ao2_cleanup);
-
-	int failed = 0;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dynamic_parking_variables";
-		info->category = TEST_CATEGORY;
-		info->summary = "Tests whether dynamic parking lot creation respects channel variables";
-		info->description =
-			"Creates a template parking lot, creates a channel, sets dynamic parking variables, and then creates a parking lot for that channel";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_status_update(test, "Creating expected configuration for dynamic parking lot\n");
-
-	expected_cfg = parking_lot_cfg_create("unit_tests_res_parking_test_lot_dynamic");
-
-	if (!expected_cfg) {
-		ast_test_status_update(test, "Failed to create expected configuration. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	expected_cfg->parking_start = 751;
-	expected_cfg->parking_stop = 760;
-	expected_cfg->parkingtime = 10;
-	expected_cfg->comebackdialtime = 10;
-	expected_cfg->parkfindnext = 1;
-	expected_cfg->parkext_exclusive = 1;
-	ast_string_field_set(expected_cfg, parkext, "750");
-	ast_string_field_set(expected_cfg, parking_con, "unit_test_res_parking_create_lot_dynamic");
-	ast_string_field_set(expected_cfg, comebackcontext, "unit_test_res_parking_create_lot_comeback");
-
-	ast_test_status_update(test, "Creating template lot\n");
-
-	template_lot = generate_test_parking_lot(TEST_LOT_NAME, 701, 703, "700", "unit_test_res_parking_create_lot_con", test);
-
-	if (!template_lot) {
-		ast_test_status_update(test, "Failed to generate template lot. Test failed.\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_status_update(test, "Creating Alice channel to test dynamic parking lot creation.\n");
-
-	chan_alice = create_alice_channel();
-
-	if (!chan_alice) {
-		ast_test_status_update(test, "Failed to create Alice channel. Test failed.\n");
-		failed = 1;
-		goto cleanup;
-	}
-
-	ast_test_status_update(test, "Setting Dynamic Parking channel variables on Alice.\n");
-
-	pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNAMIC", TEST_LOT_NAME);
-	pbx_builtin_setvar_helper(chan_alice, "PARKINGLOT", "unit_test_res_parking_create_lot_dynamic");
-	pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNCONTEXT", "unit_test_res_parking_create_lot_dynamic");
-	pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNEXTEN", "750");
-	pbx_builtin_setvar_helper(chan_alice, "PARKINGDYNPOS", "751-760");
-
-	ast_test_status_update(test, "Generating dynamic parking lot based on Alice's channel variables.\n");
-
-	dynamic_lot = parking_create_dynamic_lot_forced("unit_tests_res_parking_test_lot_dynamic", chan_alice);
-
-	if (!dynamic_lot) {
-		ast_test_status_update(test, "Failed to create dynamic parking lot. Test failed.\n");
-		failed = 1;
-		goto cleanup;
-	}
-
-	/* Check stats */
-	if (!parking_lot_cfgs_match(dynamic_lot->cfg, expected_cfg, test)) {
-		ast_test_status_update(test, "Dynamic parking lot configuration did not match Expectations.\n");
-		failed = 1;
-		goto cleanup;
-	}
-
-	ast_test_status_update(test, "Dynamic parking lot created successfully and matches expectations. Test passed.\n");
-
-cleanup:
-	if (template_lot && dispose_test_lot(template_lot, 1)) {
-		ast_test_status_update(test, "Found template parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	if (dynamic_lot && dispose_test_lot(dynamic_lot, 1)) {
-		ast_test_status_update(test, "Found dynamic parking lot in container after attempted removal. Test failed.\n");
-		failed = 1;
-	}
-
-	return failed ? AST_TEST_FAIL : AST_TEST_PASS;
-}
-
-#endif /* TEST_FRAMEWORK */
-
-
-void unload_parking_tests(void)
-{
-/* NOOP without test framework */
-#if defined(TEST_FRAMEWORK)
-	AST_TEST_UNREGISTER(create_lot);
-	AST_TEST_UNREGISTER(park_call);
-	AST_TEST_UNREGISTER(retrieve_call);
-	AST_TEST_UNREGISTER(park_extensions);
-	AST_TEST_UNREGISTER(extension_conflicts);
-	AST_TEST_UNREGISTER(dynamic_parking_variables);
-#endif
-}
-
-int load_parking_tests(void)
-{
-	int res = 0;
-
-/* NOOP without test framework */
-#if defined(TEST_FRAMEWORK)
-	res |= AST_TEST_REGISTER(create_lot);
-	res |= AST_TEST_REGISTER(park_call);
-	res |= AST_TEST_REGISTER(retrieve_call);
-	res |= AST_TEST_REGISTER(park_extensions);
-	res |= AST_TEST_REGISTER(extension_conflicts);
-	res |= AST_TEST_REGISTER(dynamic_parking_variables);
-#endif
-
-	return res;
-}
diff --git a/res/parking/parking_ui.c b/res/parking/parking_ui.c
deleted file mode 100644
index 46ef769..0000000
--- a/res/parking/parking_ui.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking CLI commands
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396887 $")
-
-#include "res_parking.h"
-#include "asterisk/config.h"
-#include "asterisk/config_options.h"
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/features.h"
-#include "asterisk/manager.h"
-
-static void display_parked_call(struct parked_user *user, int fd)
-{
-	ast_cli(fd, "  Space               :  %d\n", user->parking_space);
-	ast_cli(fd, "  Channel             :  %s\n", ast_channel_name(user->chan));
-	ast_cli(fd, "  Parker Dial String  :  %s\n", user->parker_dial_string);
-	ast_cli(fd, "\n");
-}
-
-static int display_parked_users_cb(void *obj, void *arg, int flags)
-{
-	int *fd = arg;
-	struct parked_user *user = obj;
-	display_parked_call(user, *fd);
-	return 0;
-}
-
-static void display_parking_lot(struct parking_lot *lot, int fd)
-{
-	ast_cli(fd, "Parking Lot: %s\n--------------------------------------------------------------------------\n", lot->name);
-	ast_cli(fd, "Parking Extension   :  %s\n", lot->cfg->parkext);
-	ast_cli(fd, "Parking Context     :  %s\n", lot->cfg->parking_con);
-	ast_cli(fd, "Parking Spaces      :  %d-%d\n", lot->cfg->parking_start, lot->cfg->parking_stop);
-	ast_cli(fd, "Parking Time        :  %u sec\n", lot->cfg->parkingtime);
-	ast_cli(fd, "Comeback to Origin  :  %s\n", lot->cfg->comebacktoorigin ? "yes" : "no");
-	ast_cli(fd, "Comeback Context    :  %s%s\n", lot->cfg->comebackcontext, lot->cfg->comebacktoorigin ? " (comebacktoorigin=yes, not used)" : "");
-	ast_cli(fd, "Comeback Dial Time  :  %u sec\n", lot->cfg->comebackdialtime);
-	ast_cli(fd, "MusicOnHold Class   :  %s\n", lot->cfg->mohclass);
-	ast_cli(fd, "Enabled             :  %s\n", (lot->mode == PARKINGLOT_DISABLED) ? "no" : "yes");
-	ast_cli(fd, "Dynamic             :  %s\n", (lot->mode == PARKINGLOT_DYNAMIC) ? "yes" : "no");
-	ast_cli(fd, "\n");
-}
-
-static int display_parking_lot_cb(void *obj, void *arg, int flags)
-{
-	int *fd = arg;
-	struct parking_lot *lot = obj;
-	display_parking_lot(lot, *fd);
-	return 0;
-}
-
-static void cli_display_parking_lot(int fd, const char *name)
-{
-	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
-	lot = parking_lot_find_by_name(name);
-
-	/* If the parking lot couldn't be found with the search, also abort. */
-	if (!lot) {
-		ast_cli(fd, "Could not find parking lot '%s'\n\n", name);
-		return;
-	}
-
-	display_parking_lot(lot, fd);
-
-	ast_cli(fd, "Parked Calls\n------------\n");
-
-	if (!ao2_container_count(lot->parked_users)) {
-		ast_cli(fd, "  (none)\n");
-		ast_cli(fd, "\n\n");
-		return;
-	}
-
-	ao2_callback(lot->parked_users, OBJ_MULTIPLE | OBJ_NODATA, display_parked_users_cb, &fd);
-	ast_cli(fd, "\n");
-}
-
-static void cli_display_parking_global(int fd)
-{
-	ast_cli(fd, "Parking General Options\n"
-	            "-----------------------\n");
-	ast_cli(fd, "Dynamic Parking     :  %s\n", parking_dynamic_lots_enabled() ? "yes" : "no");
-	ast_cli(fd, "\n");
-}
-
-static void cli_display_parking_lot_list(int fd)
-{
-	struct ao2_container *lot_container;
-
-	lot_container = get_parking_lot_container();
-
-	if (!lot_container) {
-		ast_cli(fd, "Failed to obtain parking lot list.\n\n");
-		return;
-	}
-
-	ao2_callback(lot_container, OBJ_MULTIPLE | OBJ_NODATA, display_parking_lot_cb, &fd);
-	ast_cli(fd, "\n");
-}
-
-struct parking_lot_complete {
-	int seeking;    /*! Nth match to return. */
-	int which;      /*! Which match currently on. */
-};
-
-static int complete_parking_lot_search(void *obj, void *arg, void *data, int flags)
-{
-	struct parking_lot_complete *search = data;
-	if (++search->which > search->seeking) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static char *complete_parking_lot(const char *word, int seeking)
-{
-	char *ret = NULL;
-	struct parking_lot *lot;
-	struct ao2_container *global_lots = get_parking_lot_container();
-	struct parking_lot_complete search = {
-		.seeking = seeking,
-		};
-
-	lot = ao2_callback_data(global_lots, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
-		complete_parking_lot_search, (char *) word, &search);
-
-	if (!lot) {
-		return NULL;
-	}
-
-	ret = ast_strdup(lot->name);
-	ao2_ref(lot, -1);
-	return ret;
-}
-
-/* \brief command parking show <name> */
-static char *handle_show_parking_lot_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "parking show";
-		e->usage =
-			"Usage: parking show [name]\n"
-			"	Shows a list of parking lots or details of a specific parking lot.";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 2) {
-			return complete_parking_lot(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	ast_cli(a->fd, "\n");
-
-	if (a->argc == 2) {
-		cli_display_parking_global(a->fd);
-		cli_display_parking_lot_list(a->fd);
-		return CLI_SUCCESS;
-	}
-
-	if (a->argc == 3) {
-		cli_display_parking_lot(a->fd, a->argv[2]);
-		return CLI_SUCCESS;
-	}
-
-	return CLI_SHOWUSAGE;
-}
-
-static struct ast_cli_entry cli_parking_lot[] = {
-	AST_CLI_DEFINE(handle_show_parking_lot_cmd, "Show a parking lot or a list of all parking lots."),
-};
-
-int load_parking_ui(void)
-{
-	return ast_cli_register_multiple(cli_parking_lot, ARRAY_LEN(cli_parking_lot));
-}
-
-void unload_parking_ui(void)
-{
-	ast_cli_unregister_multiple(cli_parking_lot, ARRAY_LEN(cli_parking_lot));
-}
diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h
deleted file mode 100644
index 3d77e51..0000000
--- a/res/parking/res_parking.h
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Resource Internal API
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-#include "asterisk/pbx.h"
-#include "asterisk/bridge.h"
-#include "asterisk/parking.h"
-#include "asterisk/stasis_channels.h"
-
-#define DEFAULT_PARKING_LOT "default"
-#define DEFAULT_PARKING_EXTEN "700"
-#define BASE_REGISTRAR "res_parking"
-#define PARK_DIAL_CONTEXT "park-dial"
-#define PARKED_CALL_APPLICATION "ParkedCall"
-
-enum park_call_resolution {
-	PARK_UNSET = 0,		/*! Nothing set a resolution. This should never be observed in practice. */
-	PARK_ABANDON,		/*! The channel for the parked call hung up */
-	PARK_TIMEOUT,		/*! The parked call stayed parked until the parking lot timeout was reached and was removed */
-	PARK_FORCED,		/*! The parked call was forcibly terminated by an unusual means in Asterisk */
-	PARK_ANSWERED,		/*! The parked call was retrieved successfully */
-};
-
-enum parked_call_feature_options {
-	OPT_PARKEDPLAY = 0,
-	OPT_PARKEDTRANSFERS,
-	OPT_PARKEDREPARKING,
-	OPT_PARKEDHANGUP,
-	OPT_PARKEDRECORDING,
-};
-
-enum parking_lot_modes {
-	PARKINGLOT_NORMAL = 0,          /*! The parking lot is configured normally and can accept new calls. Disable on reload if the config isn't replaced.
-	                                 *  valid transitions: PARKINGLOT_DISABLED */
-	PARKINGLOT_DYNAMIC,             /*! The parking lot is a dynamically created parking lot. It can be parked to at any time. Disabled on last parked call leaving.
-	                                 *  valid transitions: PARKINGLOT_DISABLED */
-	PARKINGLOT_DISABLED,            /*! The parking lot is no longer linked to a parking lot in configuration. It can no longer be parked to.
-	                                 *  and it can not be parked to. This mode has no transitions. */
-};
-
-struct parking_lot_cfg {
-	int parking_start;                        /*!< First space in the parking lot */
-	int parking_stop;                         /*!< Last space in the parking lot */
-
-	unsigned int parkingtime;                 /*!< Analogous to parkingtime config option */
-	unsigned int comebackdialtime;            /*!< Analogous to comebackdialtime config option */
-	unsigned int parkfindnext;                /*!< Analogous to parkfindnext config option */
-	unsigned int parkext_exclusive;           /*!< Analogous to parkext_exclusive config option */
-	unsigned int parkaddhints;                /*!< Analogous to parkaddhints config option */
-	unsigned int comebacktoorigin;            /*!< Analogous to comebacktoorigin config option */
-	int parkedplay;                           /*!< Analogous to parkedplay config option */
-	int parkedcalltransfers;                  /*!< Analogous to parkedcalltransfers config option */
-	int parkedcallreparking;                  /*!< Analogous to parkedcallreparking config option */
-	int parkedcallhangup;                     /*!< Analogous to parkedcallhangup config option */
-	int parkedcallrecording;                  /*!< Analogous to parkedcallrecording config option */
-
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);               /*!< Name of the parking lot configuration object */
-		AST_STRING_FIELD(registrar);          /*!< Which registrar the lot uses if it isn't the default registrar */
-		AST_STRING_FIELD(mohclass);           /*!< Analogous to mohclass config option */
-		AST_STRING_FIELD(parkext);            /*!< Analogous to parkext config option */
-		AST_STRING_FIELD(parking_con);        /*!< Analogous to context config option */
-		AST_STRING_FIELD(comebackcontext);    /*!< Analogous to comebackcontext config option */
-		AST_STRING_FIELD(courtesytone);       /*!< Analogous to courtesytone config option */
-	);
-};
-
-struct parking_lot {
-	int next_space;                           /*!< When using parkfindnext, which space we should start searching from next time we park */
-	struct ast_bridge *parking_bridge;        /*!< Bridged where parked calls will rest until they are answered or otherwise leave */
-	struct ao2_container *parked_users;       /*!< List of parked users rigidly ordered by their parking space */
-	struct parking_lot_cfg *cfg;              /*!< Reference to configuration object for the parking lot */
-	enum parking_lot_modes mode;              /*!< Whether a parking lot is operational, being reconfigured, primed for deletion, or dynamically created. */
-	int disable_mark;                         /*!< On reload, disable this parking lot if it doesn't receive a new configuration. */
-
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);               /*!< Name of the parking lot object */
-	);
-};
-
-struct parked_user {
-	struct ast_channel *chan;                 /*!< Parked channel */
-	struct ast_channel_snapshot *retriever;   /*!< Snapshot of the channel that retrieves a parked call */
-	struct timeval start;                     /*!< When the call was parked */
-	int parking_space;                        /*!< Which parking space is used */
-	char comeback[AST_MAX_CONTEXT];           /*!< Where to go on parking timeout */
-	char *parker_dial_string;                 /*!< dialstring to call back with comebacktoorigin. Used timeout extension generation and call control */
-	unsigned int time_limit;                  /*!< How long this specific channel may remain in the parking lot before timing out */
-	struct parking_lot *lot;                  /*!< Which parking lot the user is parked to */
-	enum park_call_resolution resolution;     /*!< How did the parking session end? If the call is in a bridge, lock parked_user before checking/setting */
-};
-
-#if defined(TEST_FRAMEWORK)
-/*!
- * \since 12.0.0
- * \brief Create an empty parking lot configuration structure
- *        useful for unit tests.
- *
- * \param cat name given to the parking lot
- *
- * \retval NULL failure
- * \retval non-NULL successfully allocated parking lot
- */
-struct parking_lot_cfg *parking_lot_cfg_create(const char *cat);
-#endif
-
-/*!
- * \since 12.0.0
- * \brief If a parking lot exists in the parking lot list already, update its status to match the provided
- *        configuration and return a reference return a reference to it. Otherwise, create a parking lot
- *        struct based on a parking lot configuration and return a reference to the new one.
- *
- * \param cfg The configuration being used as a reference to build the parking lot from.
- * \param dynamic non-zero if creating a dynamic parking lot with this. Don't replace existing parking lots. Ever.
- *
- * \retval A reference to the new parking lot
- * \retval NULL if it was not found and could not be be allocated
- *
- * \note The parking lot will need to be unreffed if it ever falls out of scope
- * \note The parking lot will automatically be added to the parking lot container if needed as part of this process
- */
-struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *cfg, int dynamic);
-
-/*!
- * \since 12.0.0
- * \brief Remove a parking lot from the usable lists if it is no longer involved in any calls and no configuration currently claims it
- *
- * \param lot Which parking lot is being checked for elimination
- *
- * \retval 0 if the parking lot was removed
- * \retval -1 if the parking lot wasn't removed.
- *
- * \note This should generally be called when something is happening that could cause a parking lot to die such as a call being unparked or
- *       a parking lot no longer existing in configurations.
- */
-int parking_lot_remove_if_unused(struct parking_lot *lot);
-
-/*!
- * \since 12.0.0
- * \brief Create a new parking bridge
- *
- * \param bridge_lot Parking lot which the new bridge should be based on
- *
- * \retval NULL if the bridge can not be created
- * \retval Newly created parking bridge
- */
-struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot);
-
-/*!
- * \since 12.0.0
- * \brief Get a reference to a parking lot's bridge. If it doesn't exist, create it and get a reference.
- *
- * \param lot Which parking lot we need the bridge from. This parking lot must be locked before calling this function.
- *
- * \retval A reference to the ast_bridge associated with the parking lot
- * \retval NULL if it didn't already have a bridge and one couldn't be created
- *
- * \note This bridge will need to be unreffed if it ever falls out of scope.
- */
-struct ast_bridge *parking_lot_get_bridge(struct parking_lot *lot);
-
-/*!
- * \since 12.0.0
- * \brief Get an available parking space within a parking lot.
- *
- * \param lot Which parking lot we are getting a space from
- * \param target_override If there is a specific slot we want, provide it here and we'll start from that position
- *
- * \retval -1 if No slot can be found
- * \retval integer value of parking space selected
- *
- * \note lot should be locked before this is called and unlocked only after a parked_user with the space
- *       returned has been added to the parking lot.
- */
-int parking_lot_get_space(struct parking_lot *lot, int target_override);
-
-/*!
- * \since 12.0.0
- * \brief Determine if there is a parked user in a parking space and pull it from the parking lot if there is.
- *
- * \param lot Parking lot being pulled from
- * \param target If < 0   search for the first occupied space in the parking lot
- *               If >= 0  Only pull from the indicated target
- *
- * \retval NULL if no parked user could be pulled from the requested parking lot at the requested parking space
- * \retval reference to the requested parked user
- *
- * \note The parked user will be removed from parking lot as part of this process
- * \note Remove this reference with ao2_cleanup once it falls out of scope.
- */
-struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target);
-
-/*!
- * \since 12.0.0
- * \brief Apply features based on the parking lot feature options
- *
- * \param chan Which channel's feature set is being modified
- * \param lot parking lot which establishes the features used
- * \param recipient_mode AST_FEATURE_FLAG_BYCALLER if the user is the retriever
- *                       AST_FEATURE_FLAG_BYCALLEE if the user is the parkee
- */
-void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parking_lot *lot, int recipient_mode);
-
-/*!
- * \since 12.0.0
- * \brief Set necessary bridge roles on a channel that is about to enter a parking lot
- *
- * \param chan Entering channel
- * \param lot The parking lot the channel will be entering
- * \param force_ringing Use ringing instead of music on hold
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-int parking_channel_set_roles(struct ast_channel *chan, struct parking_lot *lot, int force_ringing);
-
-/*!
- * \since 12.0.0
- * \brief custom callback function for ast_bridge_channel_queue_playfile which plays a parking space
- *        and optionally hangs up the call afterwards based on the payload in playfile.
- */
-void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload);
-
-/*!
- * \since 12.0.0
- * \brief Setup timeout interval feature on an ast_bridge_features for parking
- *
- * \param features The ast_bridge_features we are establishing the interval hook on
- * \param user The parked_user receiving the timeout duration limits
- */
-void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user);
-
-/*!
- * \since 12.0.0
- * \brief Get a pointer to the parking lot container for purposes such as iteration
- *
- * \retval pointer to the parking lot container.
- */
-struct ao2_container *get_parking_lot_container(void);
-
-/*!
- * \since 12.0.0
- * \brief Find a parking lot based on its name
- *
- * \param lot_name Name of the parking lot sought
- *
- * \retval The parking lot if found
- * \retval NULL if no parking lot with the name specified exists
- *
- * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
- */
-struct parking_lot *parking_lot_find_by_name(const char *lot_name);
-
-/*!
- * \since 12.0.0
- * \brief Create a dynamic parking lot
- *
- * \param name Dynamic parking lot name to create
- * \param chan Channel parkee to get dynamic parking lot parameters from
- *
- * \retval dynamically created parking lot on success
- * \retval NULL on error
- *
- * \note This should be called only after verifying that the named parking lot doesn't already exist in a non-dynamic way.
- */
-struct parking_lot *parking_create_dynamic_lot(const char *name, struct ast_channel *chan);
-
-#if defined(TEST_FRAMEWORK)
-/*!
- * \since 12.0.0
- * \brief Create a dynamic parking lot without respect to whether they are enabled by configuration
- *
- * \param name Dynamic parking lot name to create
- * \param chan Channel parkee to get the dynamic parking lot parameters from
- *
- * \retval dynamically created parking lot on success
- * \retval NULL on error
- *
- * \note This should be called only after verifying that the named parking lot doesn't already exist in a non-dynamic way.
- */
-struct parking_lot *parking_create_dynamic_lot_forced(const char *name, struct ast_channel *chan);
-#endif
-
-/*!
- * \since 12.0.0
- * \brief Find parking lot name from channel
- *
- * \param chan The channel we want the parking lot name for
- *
- * \retval name of the channel's assigned parking lot if it is defined by the channel in some way
- * \retval name of the default parking lot if it is not
- *
- * \note Channel needs to be locked while the returned string is in use.
- */
-const char *find_channel_parking_lot_name(struct ast_channel *chan);
-
-/*!
- * \since 12.0.0
- * \brief Flattens a dial string so that it can be written to/found from PBX extensions
- *
- * \param peername unflattened dial string. This will be flattened in place.
- */
-void flatten_dial_string(char *dialstring);
-
-/*!
- * \since 12.0.0
- * \brief Set a channel's position in the PBX after timeout using the parking lot settings
- *
- * \param pu Parked user who is entering/reentering the PBX
- * \param lot Parking lot the user was removed from.
- *
- * \retval 0 Position set successfully
- * \retval -1 Failed to set the position
- */
-int comeback_goto(struct parked_user *pu, struct parking_lot *lot);
-
-/*!
- * \since 12.0.0
- * \brief Add extensions for a parking lot configuration
- *
- * \param lot_cfg parking lot configuration to generate extensions for
- *
- * \retval 0 on success
- * \retval non-zero on failure
- */
-int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg);
-
-/*!
- * \since 12.0.0
- * \brief Remove extensions belonging to a parking lot configuration
- *
- * \param lot_cfg parking lot configuratin to remove extensions from
- *
- * \note This will not remove extensions registered non-exclusively even
- *       if those extensions were registered by lot_cfg. Those are only
- *       purged on a res_parking module reload.
- */
-void parking_lot_cfg_remove_extensions(struct parking_lot_cfg *lot_cfg);
-
-/*!
- * \since 12.0.0
- * \brief Pull a parked user out of its parking lot. Use this when you don't want to use the parked user afterwards.
- * \param user The parked user being pulled.
- *
- * \retval 0 on success
- * \retval -1 if the user didn't have its parking lot set
- */
-int unpark_parked_user(struct parked_user *user);
-
-/*!
- * \since 12.0.0
- * \brief Publish a stasis parked call message for the channel indicating failure to park.
- *
- * \param parkee channel belonging to the failed parkee
- */
-void publish_parked_call_failure(struct ast_channel *parkee);
-
-/*!
- * \since 12.0.0
- * \brief Publish a stasis parked call message for a given parked user
- *
- * \param pu pointer to a parked_user that we are generating the message for
- * \param event_type What parked call event type is provoking this message
- */
-void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type event_type);
-
-/*!
- * \since 12.3.0
- * \brief Create a parking announcement subscription
- *
- * \param chan Channel that will receive the announcement
- * \param parkee_uuid Unique ID of the channel being parked
- * \param hangup_after if non-zero, have the channel hangup after hearing the announcement
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after);
-
-/*!
- * \since 12.0.0
- * \brief Setup a parked call on a parking bridge without needing to parse appdata
- *
- */
-struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
-		const char *lot_name, const char *comeback_override,
-		int use_ringing, int randomize, int time_limit, int silence_announcements);
-
-/*!
- * \since 12.0.0
- * \brief Function to prepare a channel for parking by determining which parking bridge should
- *        be used, setting up a park common datastore so that the parking bridge will have access
- *        to necessary parking information when joining, and applying various bridge roles to the
- *        channel.
- *
- * \param parkee The channel being preparred for parking
- * \param parker The channel initiating the park; may be the parkee as well. May be NULL.
- * \param app_data arguments supplied to the Park application. May be NULL.
- * \param silence_announcements optional pointer to an integer where we want to store the silence option flag
- *        this value should be initialized to 0 prior to calling park_common_setup.
- *
- * \retval reference to a parking bridge if successful
- * \retval NULL on failure
- *
- * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
- */
-struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker,
-	const char *app_data, int *silence_announcements);
-
-struct park_common_datastore {
-	char *parker_uuid;           /*!< Unique ID of the channel parking the call. */
-	char *parker_dial_string;    /*!< Dial string that we would attempt to call when timing out when comebacktoorigin=yes */
-	char *comeback_override;     /*!< Optional goto string for where to send the call after we are done */
-	int randomize;               /*!< Pick a parking space to enter on at random */
-	int time_limit;              /*!< time limit override. -1 values don't override, 0 for unlimited time, >0 for custom time limit in seconds */
-	int silence_announce;        /*!< Used when a call parks itself to keep it from hearing the parked call announcement */
-};
-
-/*!
- * \since 12.0.0
- * \brief Get a copy of the park_common_datastore from a channel that is being parked
- *
- * \param parkee The channel entering parking with the datastore we are checking
- *
- * \retval Pointer to a copy of the park common datastore for parkee if it could be cloned. This needs to be free'd with park_common_datastore free.
- * \retval NULL if the park_common_datastore could not be copied off of the channel.
- */
-struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee);
-
-/*!
- * \since 12.0.0
- * \brief Free a park common datastore struct
- *
- * \param datastore The park_common_datastore being free'd. (NULL tolerant)
- */
-void park_common_datastore_free(struct park_common_datastore *datastore);
-
-/*!
- * \since 12.0.0
- * \brief Notify metermaids that we've changed an extension
- *
- * \param exten Extension of the call parked/unparked
- * \param context Context of the call parked/unparked
- * \param state new device state
- */
-void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state);
-
-/*!
- * \since 12.0.0
- * \brief Check global configuration to see if dynamic parking is enabled
- *
- * \retval 1 if dynamic parking is enabled
- * \retval 0 if dynamic parking is disabled
- */
-int parking_dynamic_lots_enabled(void);
-
-/*!
- * \since 12.0.0
- * \brief Register parking applications
- *
- * \retval 0 if successful
- * \retval -1 on failure
- */
-int load_parking_applications(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister parking applications
- */
-void unload_parking_applications(void);
-
-/*!
- * \since 12.0.0
- * \brief Register CLI commands
- *
- * \retval 0 if successful
- * \retval -1 on failure
- */
-int load_parking_ui(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister CLI commands
- */
-void unload_parking_ui(void);
-
-/*!
- * \since 12.0.0
- * \brief Register manager actions and setup subscriptions for stasis events
- */
-int load_parking_manager(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister manager actions and remove subscriptions for stasis events
- */
-void unload_parking_manager(void);
-
-/*!
- * \since 12.0.0
- * \brief Register bridge features for parking
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-int load_parking_bridge_features(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister features registered by load_parking_bridge_features
- */
-void unload_parking_bridge_features(void);
-
-/*!
- * \since 12.0.0
- * \brief Register Parking devstate handler
- */
-int load_parking_devstate(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister Parking devstate handler
- */
-void unload_parking_devstate(void);
-
-/*!
- * \since 12.0.0
- * \brief Register parking unit tests
- *
- * \retval 0 on success
- * \retval nonzero on failure
- */
-int load_parking_tests(void);
-
-/*!
- * \since 12.0.0
- * \brief Unregister parking unit tests
- *
- * \return Nothing
- */
-void unload_parking_tests(void);
-
-struct ast_module_info;
-/*!
- * \since 12.0.0
- * \brief Get res_parking's module info
- *
- * \retval res_parking's ast_module
- */
-const struct ast_module_info *parking_get_module_info(void);
diff --git a/res/res_adsi.c b/res/res_adsi.c
index 6287161..92987f0 100644
--- a/res/res_adsi.c
+++ b/res/res_adsi.c
@@ -36,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
 #include <math.h>
@@ -50,7 +50,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/config.h"
 #include "asterisk/file.h"
 #include "asterisk/adsi.h"
-#include "asterisk/format_cache.h"
 
 #define DEFAULT_ADSI_MAX_RETRIES 3
 
@@ -155,14 +154,12 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l
 {
 	/* Sends carefully on a full duplex channel by using reading for
 	   timing */
-	struct ast_frame *inf;
-	struct ast_frame outf = {
-		.frametype = AST_FRAME_VOICE,
-		.subclass.format = ast_format_ulaw,
-		.data.ptr = buf,
-	};
+	struct ast_frame *inf, outf;
 	int amt;
 
+	/* Zero out our outgoing frame */
+	memset(&outf, 0, sizeof(outf));
+
 	if (remain && *remain) {
 		amt = len;
 
@@ -172,7 +169,9 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l
 		} else {
 			*remain = *remain - amt;
 		}
-
+		outf.frametype = AST_FRAME_VOICE;
+		ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0);
+		outf.data.ptr = buf;
 		outf.datalen = amt;
 		outf.samples = amt;
 		if (ast_write(chan, &outf)) {
@@ -202,7 +201,7 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l
 			continue;
 		}
 
-		if (ast_format_cmp(inf->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL) {
+		if (inf->subclass.format.id != AST_FORMAT_ULAW) {
 			ast_log(LOG_WARNING, "Channel not in ulaw?\n");
 			ast_frfree(inf);
 			return -1;
@@ -213,6 +212,9 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l
 		} else if (remain) {
 			*remain = inf->datalen - amt;
 		}
+		outf.frametype = AST_FRAME_VOICE;
+		ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0);
+		outf.data.ptr = buf;
 		outf.datalen = amt;
 		outf.samples = amt;
 		if (ast_write(chan, &outf)) {
@@ -243,9 +245,11 @@ static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **ms
 	}
 
 	while (retries < maxretries) {
+		struct ast_format tmpfmt;
 		if (!(ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE)) {
 			/* Generate CAS (no SAS) */
-			ast_gen_cas(buf, 0, 680, ast_format_ulaw);
+			ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0);
+			ast_gen_cas(buf, 0, 680, &tmpfmt);
 
 			/* Send CAS */
 			if (adsi_careful_send(chan, buf, 680, NULL)) {
@@ -304,7 +308,7 @@ static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **ms
 		def= ast_channel_defer_dtmf(chan);
 #endif
 		while ((x < 6) && msg[x]) {
-			if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], ast_format_ulaw)) < 0) {
+			if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], ast_format_set(&tmpfmt, AST_FORMAT_ULAW,0))) < 0) {
 				ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, ast_channel_name(chan));
 				return -1;
 			}
@@ -391,8 +395,11 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m
 {
 	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
 	int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0;
-	RAII_VAR(struct ast_format *, writeformat, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, readformat, NULL, ao2_cleanup);
+	struct ast_format writeformat;
+	struct ast_format readformat;
+
+	ast_format_copy(&writeformat, ast_channel_writeformat(chan));
+	ast_format_copy(&readformat, ast_channel_readformat(chan));
 
 	for (x = 0; x < msglen; x += (msg[x+1]+2)) {
 		if (msg[x] == ADSI_SWITCH_TO_DATA) {
@@ -419,19 +426,16 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m
 
 	ast_stopstream(chan);
 
-	writeformat = ao2_bump(ast_channel_writeformat(chan));
-	readformat = ao2_bump(ast_channel_readformat(chan));
-
-	if (ast_set_write_format(chan, ast_format_ulaw)) {
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) {
 		ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
 		return -1;
 	}
 
-	if (ast_set_read_format(chan, ast_format_ulaw)) {
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) {
 		ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
-		if (writeformat) {
-			if (ast_set_write_format(chan, writeformat)) {
-				ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_format_get_name(writeformat));
+		if (writeformat.id) {
+			if (ast_set_write_format(chan, &writeformat)) {
+				ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat));
 			}
 		}
 		return -1;
@@ -450,11 +454,11 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m
 		ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode);
 	}
 
-	if (writeformat) {
-		ast_set_write_format(chan, writeformat);
+	if (writeformat.id) {
+		ast_set_write_format(chan, &writeformat);
 	}
-	if (readformat) {
-		ast_set_read_format(chan, readformat);
+	if (readformat.id) {
+		ast_set_read_format(chan, &readformat);
 	}
 
 	if (!res) {
@@ -1210,7 +1214,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ADSI Resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_ael_share.c b/res/res_ael_share.c
index 93c818a..f1ae9f3 100644
--- a/res/res_ael_share.c
+++ b/res/res_ael_share.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -53,7 +53,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "share-able code for AEL",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 				.load = load_module,
 				.unload = unload_module
 	);
diff --git a/res/res_agi.c b/res/res_agi.c
index b0ae0c3..770aaaa 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <math.h>
 #include <signal.h>
@@ -66,9 +66,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
 #include "asterisk/srv.h"
 #include "asterisk/test.h"
 #include "asterisk/netsock2.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/format_cache.h"
 
 #define AST_API_MODULE
 #include "asterisk/agi.h"
@@ -156,37 +153,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
 				<para>Defaults to <literal>*</literal></para>
 			</parameter>
 			<parameter name="pausechr" />
-			<parameter name="offsetms">
-				<para>Offset, in milliseconds, to start the audio playback</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>Send the given file, allowing playback to be controlled by the given
 			digits, if any. Use double quotes for the digits if you wish none to be
-			permitted. If offsetms is provided then the audio will seek to offsetms
-			before play starts. Returns <literal>0</literal> if playback completes without a digit
+			permitted. Returns <literal>0</literal> if playback completes without a digit
 			being pressed, or the ASCII numerical value of the digit if one was pressed,
-			or <literal>-1</literal> on error or if the channel was disconnected. Returns the
-			position where playback was terminated as endpos.</para>
-
-			<para>It sets the following channel variables upon completion:</para>
-			<variablelist>
-				<variable name="CPLAYBACKSTATUS">
-					<para>Contains the status of the attempt as a text string</para>
-					<value name="SUCCESS" />
-					<value name="USERSTOPPED" />
-					<value name="REMOTESTOPPED" />
-					<value name="ERROR" />
-				</variable>
-				<variable name="CPLAYBACKOFFSET">
-					<para>Contains the offset in ms into the file where playback
-					was at when it stopped. <literal>-1</literal> is end of file.</para>
-				</variable>
-				<variable name="CPLAYBACKSTOPKEY">
-					<para>If the playback is stopped by the user this variable contains
-					the key that was pressed.</para>
-				</variable>
-			</variablelist>
+			or <literal>-1</literal> on error or if the channel was disconnected.</para>
 		</description>
 	</agi>
 	<agi name="database del" language="en_US">
@@ -375,9 +348,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
 			</parameter>
 		</syntax>
 		<description>
-			<para>Receives a string of text on a channel. Most channels
+			<para>Receives a string of text on a channel. Most channels 
 			do not support the reception of text. Returns <literal>-1</literal> for failure
-			or <literal>1</literal> for success, and the string in parenthesis.</para>
+			or <literal>1</literal> for success, and the string in parenthesis.</para> 
 		</description>
 	</agi>
 	<agi name="record file" language="en_US">
@@ -679,14 +652,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
 			or <literal>-1</literal> on error or if the channel was disconnected. If
 			musiconhold is playing before calling stream file it will be automatically
 			stopped and will not be restarted after completion.</para>
-			<para>It sets the following channel variables upon completion:</para>
-			<variablelist>
-				<variable name="PLAYBACKSTATUS">
-					<para>The status of the playback attempt as a text string.</para>
-					<value name="SUCCESS"/>
-					<value name="FAILED"/>
-				</variable>
-			</variablelist>
 		</description>
 		<see-also>
 			<ref type="agi">control stream file</ref>
@@ -937,68 +902,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426362 $")
 			<para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
 		</description>
 	</manager>
-	<managerEvent language="en_US" name="AsyncAGIStart">
-		<managerEventInstance class="EVENT_FLAG_AGI">
-			<synopsis>Raised when a channel starts AsyncAGI command processing.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Env">
-					<para>URL encoded string read from the AsyncAGI server.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AsyncAGIEnd">
-		<managerEventInstance class="EVENT_FLAG_AGI">
-			<synopsis>Raised when a channel stops AsyncAGI command processing.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AsyncAGIExec">
-		<managerEventInstance class="EVENT_FLAG_AGI">
-			<synopsis>Raised when AsyncAGI completes an AGI command.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="CommandID" required="false">
-					<para>Optional command ID sent by the AsyncAGI server to identify the command.</para>
-				</parameter>
-				<parameter name="Result">
-					<para>URL encoded result string from the executed AGI command.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AGIExecStart">
-		<managerEventInstance class="EVENT_FLAG_AGI">
-			<synopsis>Raised when a received AGI command starts processing.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<parameter name="Command">
-					<para>The AGI command as received from the external source.</para>
-				</parameter>
-				<parameter name="CommandId">
-					<para>Random identification number assigned to the execution of this command.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AGIExecEnd">
-		<managerEventInstance class="EVENT_FLAG_AGI">
-			<synopsis>Raised when a received AGI command completes processing.</synopsis>
-			<syntax>
-				<channel_snapshot/>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AGIExecStart']/managerEventInstance/syntax/parameter)" />
-				<parameter name="ResultCode">
-					<para>The numeric result code from AGI</para>
-				</parameter>
-				<parameter name="Result">
-					<para>The text result reason from AGI</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
  ***/
 
 #define MAX_ARGS 128
@@ -1034,66 +937,6 @@ enum agi_result {
 	AGI_RESULT_HANGUP,
 };
 
-static struct ast_manager_event_blob *agi_channel_to_ami(const char *type, struct stasis_message *message)
-{
-	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
-
-	channel_string = ast_manager_build_channel_state_string(obj->snapshot);
-	event_string = ast_manager_str_from_json_object(obj->blob, NULL);
-	if (!channel_string || !event_string) {
-		return NULL;
-	}
-
-	return ast_manager_event_blob_create(EVENT_FLAG_AGI, type,
-		"%s"
-		"%s",
-		ast_str_buffer(channel_string),
-		ast_str_buffer(event_string));
-}
-
-static struct ast_manager_event_blob *agi_exec_start_to_ami(struct stasis_message *message)
-{
-	return agi_channel_to_ami("AGIExecStart", message);
-}
-
-static struct ast_manager_event_blob *agi_exec_end_to_ami(struct stasis_message *message)
-{
-	return agi_channel_to_ami("AGIExecEnd", message);
-}
-
-static struct ast_manager_event_blob *agi_async_start_to_ami(struct stasis_message *message)
-{
-	return agi_channel_to_ami("AsyncAGIStart", message);
-}
-
-static struct ast_manager_event_blob *agi_async_exec_to_ami(struct stasis_message *message)
-{
-	return agi_channel_to_ami("AsyncAGIExec", message);
-}
-
-static struct ast_manager_event_blob *agi_async_end_to_ami(struct stasis_message *message)
-{
-	return agi_channel_to_ami("AsyncAGIEnd", message);
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type,
-	.to_ami = agi_exec_start_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_end_type,
-	.to_ami = agi_exec_end_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_start_type,
-	.to_ami = agi_async_start_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_exec_type,
-	.to_ami = agi_async_exec_to_ami,
-	);
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_end_type,
-	.to_ami = agi_async_end_to_ami,
-	);
-
 static agi_command *find_command(const char * const cmds[], int exact);
 
 AST_THREADSTORAGE(agi_buf);
@@ -1162,18 +1005,10 @@ static const struct ast_datastore_info agi_commands_datastore_info = {
 	.destroy = agi_destroy_commands_cb
 };
 
-/*!
- * \brief Retrieve the list head to the requested channel's AGI datastore
- * \param chan Channel datastore is requested for
- * \param cmd Pointer to the struct pointer which will reference the head of the agi command list.
- *
- * \retval 0 if the datastore was valid and the list head was retrieved appropriately (even if it's
- *           NULL and the list is empty)
- * \retval -1 if the datastore could not be retrieved causing an error
-*/
-static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
+static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
 {
 	struct ast_datastore *store;
+	struct agi_cmd *cmd;
 	AST_LIST_HEAD(, agi_cmd) *agi_commands;
 
 	ast_channel_lock(chan);
@@ -1182,14 +1017,13 @@ static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
 	if (!store) {
 		ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
 			ast_channel_name(chan));
-		*cmd = NULL;
-		return -1;
+		return NULL;
 	}
 	agi_commands = store->data;
 	AST_LIST_LOCK(agi_commands);
-	*cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
+	cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
 	AST_LIST_UNLOCK(agi_commands);
-	return 0;
+	return cmd;
 }
 
 /* channel is locked when calling this one either from the CLI or manager thread */
@@ -1400,7 +1234,7 @@ static enum agi_result async_agi_read_frame(struct ast_channel *chan)
 	return AGI_RESULT_SUCCESS;
 }
 
-static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
+static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
 {
 /* This buffer sizes might cause truncation if the AGI command writes more data
    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
@@ -1431,7 +1265,6 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 	char ami_buffer[AMI_BUF_SIZE];
 	enum agi_result returnstatus = AGI_RESULT_SUCCESS;
 	AGI async_agi;
-	RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
 
 	if (efd) {
 		ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
@@ -1467,7 +1300,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 
 	/* notify possible manager users of a new channel ready to
 	   receive commands */
-	setup_env(chan, "async", fds[1], 0, argc, argv);
+	setup_env(chan, "async", fds[1], 0, 0, NULL);
 	/* read the environment */
 	res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
 	if (res <= 0) {
@@ -1481,28 +1314,17 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 	   care of AGI commands on this channel can decide which AGI commands
 	   to execute based on the setup info */
 	ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
-	startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
-
-	ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
-
-	hungup = ast_check_hangup_locked(chan);
-
+	manager_event(EVENT_FLAG_AGI, "AsyncAGI",
+		"SubEvent: Start\r\n"
+		"Channel: %s\r\n"
+		"Env: %s\r\n", ast_channel_name(chan), ami_buffer);
+	hungup = ast_check_hangup(chan);
 	for (;;) {
 		/*
 		 * Process as many commands as we can.  Commands are added via
 		 * the manager or the cli threads.
 		 */
-		while (!hungup) {
-			RAII_VAR(struct ast_json *, execblob, NULL, ast_json_unref);
-			res = get_agi_cmd(chan, &cmd);
-
-			if (res) {
-				returnstatus = AGI_RESULT_FAILURE;
-				goto async_agi_done;
-			} else if (!cmd) {
-				break;
-			}
-
+		while (!hungup && (cmd = get_agi_cmd(chan))) {
 			/* OK, we have a command, let's call the command handler. */
 			cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
 
@@ -1525,13 +1347,18 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 			 */
 			agi_buffer[res] = '\0';
 			ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
-
-			execblob = ast_json_pack("{s: s}", "Result", ami_buffer);
-			if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
-				ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
+			if (ast_strlen_zero(cmd->cmd_id)) {
+				manager_event(EVENT_FLAG_AGI, "AsyncAGI",
+					"SubEvent: Exec\r\n"
+					"Channel: %s\r\n"
+					"Result: %s\r\n", ast_channel_name(chan), ami_buffer);
+			} else {
+				manager_event(EVENT_FLAG_AGI, "AsyncAGI",
+					"SubEvent: Exec\r\n"
+					"Channel: %s\r\n"
+					"CommandID: %s\r\n"
+					"Result: %s\r\n", ast_channel_name(chan), cmd->cmd_id, ami_buffer);
 			}
-			ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
-
 			free_agi_cmd(cmd);
 
 			/*
@@ -1589,8 +1416,11 @@ async_agi_done:
 	if (async_agi.speech) {
 		ast_speech_destroy(async_agi.speech);
 	}
-	/* notify manager users this channel cannot be controlled anymore by Async AGI */
-	ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
+	/* notify manager users this channel cannot be
+	   controlled anymore by Async AGI */
+	manager_event(EVENT_FLAG_AGI, "AsyncAGI",
+		"SubEvent: End\r\n"
+		"Channel: %s\r\n", ast_channel_name(chan));
 
 async_agi_abort:
 	/* close the pipe */
@@ -1825,7 +1655,7 @@ static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
 	return AGI_RESULT_FAILURE;
 }
 
-static enum agi_result launch_script(struct ast_channel *chan, char *script, int argc, char *argv[], int *fds, int *efd, int *opid)
+static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
 {
 	char tmp[256];
 	int pid, toast[2], fromast[2], audio[2], res;
@@ -1838,7 +1668,7 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, int
 		return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
 	}
 	if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
-		return launch_asyncagi(chan, argc, argv, efd);
+		return launch_asyncagi(chan, argv, efd);
 	}
 
 	if (script[0] != '/') {
@@ -2125,11 +1955,8 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
 {
 	int res = 0, skipms = 3000;
 	const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL;	/* Default values */
-	char stopkeybuf[2];
-	long offsetms = 0;
-	char offsetbuf[20];
 
-	if (argc < 5 || argc > 10) {
+	if (argc < 5 || argc > 9) {
 		return RESULT_SHOWUSAGE;
 	}
 
@@ -2153,32 +1980,9 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
 		suspend = argv[8];
 	}
 
-	if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
-		return RESULT_SHOWUSAGE;
-	}
-
-	res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
+	res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
 
-	/* If we stopped on one of our stop keys, return 0  */
-	if (res > 0 && stop && strchr(stop, res)) {
-		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
-		snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
-		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
-	} else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
-		pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
-		res = 0;
-	} else {
-		if (res < 0) {
-			pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
-		} else {
-			pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
-		}
-	}
-
-	snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
-	pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
-
-	ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
+	ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
 
 	return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -2210,8 +2014,9 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const
 	if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
 		ast_debug(1, "Ooh, found a video stream, too\n");
 	}
-
-	ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
+	ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
+		ast_channel_name(chan), argv[2], ast_getformatname(ast_channel_writeformat(chan)),
+		edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
 
 	ast_seekstream(fs, 0, SEEK_END);
 	max_length = ast_tellstream(fs);
@@ -2235,8 +2040,6 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const
 		return RESULT_SUCCESS;
 	}
 	ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
-	pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
-
 	return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
 }
 
@@ -2344,37 +2147,11 @@ static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const
 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
 	int res;
-	int sensitivity = AST_SAY_CASE_NONE;
 
-	if (argc < 4 || argc > 5) {
+	if (argc != 4)
 		return RESULT_SHOWUSAGE;
-	}
 
-	if (argc > 4) {
-		switch (argv[4][0]) {
-		case 'a':
-		case 'A':
-			sensitivity = AST_SAY_CASE_ALL;
-			break;
-		case 'l':
-		case 'L':
-			sensitivity = AST_SAY_CASE_LOWER;
-			break;
-		case 'n':
-		case 'N':
-			sensitivity = AST_SAY_CASE_NONE;
-			break;
-		case 'u':
-		case 'U':
-			sensitivity = AST_SAY_CASE_UPPER;
-			break;
-		case '\0':
-			break;
-		default:
-			return RESULT_SHOWUSAGE;
-		}
-	}
-	res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
+	res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
 	if (res == 1) /* New command */
 		return RESULT_SUCCESS;
 	ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
@@ -2539,7 +2316,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
 	int silence = 0;                /* amount of silence to allow */
 	int gotsilence = 0;             /* did we timeout for silence? */
 	char *silencestr = NULL;
-	RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
+	struct ast_format rfmt;
+	ast_format_clear(&rfmt);
 
 	/* XXX EAGI FIXME XXX */
 
@@ -2569,8 +2347,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
 	}
 
 	if (silence > 0) {
-		rfmt = ao2_bump(ast_channel_readformat(chan));
-		res = ast_set_read_format(chan, ast_format_slin);
+		ast_format_copy(&rfmt, ast_channel_readformat(chan));
+		res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
 			ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
@@ -2584,7 +2362,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
 		}
 		ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
 	}
-
+	
 	/* backward compatibility, if no offset given, arg[6] would have been
 	 * caught below and taken to be a beep, else if it is a digit then it is a
 	 * offset */
@@ -2694,7 +2472,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const
 	}
 
 	if (silence > 0) {
-		res = ast_set_read_format(chan, rfmt);
+		res = ast_set_read_format(chan, &rfmt);
 		if (res)
 			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
 		ast_dsp_free(sildet);
@@ -2718,9 +2496,7 @@ static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const
 		whentohangup.tv_sec = timeout;
 		whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
 	}
-	ast_channel_lock(chan);
 	ast_channel_setwhentohangup_tv(chan, whentohangup);
-	ast_channel_unlock(chan);
 	ast_agi_send(agi->fd, chan, "200 result=0\n");
 	return RESULT_SUCCESS;
 }
@@ -2767,7 +2543,24 @@ static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char
 		if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
 			ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS);
 		}
-		res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
+		if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
+			char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
+			const char *vptr;
+			for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
+				if (*vptr == ',') {
+					*cptr++ = '\\';
+					*cptr++ = ',';
+				} else if (*vptr == '|') {
+					*cptr++ = ',';
+				} else {
+					*cptr++ = *vptr;
+				}
+			}
+			*cptr = '\0';
+			res = pbx_exec(chan, app_to_exec, compat);
+		} else {
+			res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
+		}
 		if (!workaround) {
 			ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS);
 		}
@@ -2804,18 +2597,16 @@ static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, cons
 
 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
+	struct ast_channel *c;
 	if (argc == 2) {
 		/* no argument: supply info on the current channel */
 		ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
 		return RESULT_SUCCESS;
 	} else if (argc == 3) {
-		RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
 		/* one argument: look for info on the specified channel */
-		if ((msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), argv[2]))) {
-			struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
-
-			ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
+		if ((c = ast_channel_get_by_name(argv[2]))) {
+			ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(c));
+			c = ast_channel_unref(c);
 			return RESULT_SUCCESS;
 		}
 		/* if we get this far no channel name matched the argument given */
@@ -2932,7 +2723,7 @@ static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char
 			break;
 		}
 	} while (1);
-
+	
 	if (res)
 		ast_agi_send(agi->fd, chan, "200 result=0\n");
 	else
@@ -3032,6 +2823,7 @@ static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const c
 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
 	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
 
 	/* If a structure already exists, return an error */
 	if (agi->speech) {
@@ -3039,16 +2831,16 @@ static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, con
 		return RESULT_SUCCESS;
 	}
 
-	if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(cap = ast_format_cap_alloc_nolock())) {
 		return RESULT_FAILURE;
 	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
 	if ((agi->speech = ast_speech_new(argv[2], cap))) {
 		ast_agi_send(agi->fd, chan, "200 result=1\n");
 	} else {
 		ast_agi_send(agi->fd, chan, "200 result=0\n");
 	}
-	ao2_ref(cap, -1);
+	cap = ast_format_cap_destroy(cap);
 
 	return RESULT_SUCCESS;
 }
@@ -3181,6 +2973,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
 	const char *prompt;
 	char dtmf = 0, tmp[4096] = "", *buf = tmp;
 	int timeout = 0, offset = 0, res = 0, i = 0;
+	struct ast_format old_read_format;
 	long current_offset = 0;
 	const char *reason = NULL;
 	struct ast_frame *fr = NULL;
@@ -3204,7 +2997,8 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
 		offset = atoi(argv[4]);
 
 	/* We want frames coming in signed linear */
-	if (ast_set_read_format(chan, ast_format_slin)) {
+	ast_format_copy(&old_read_format, ast_channel_readformat(chan));
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_agi_send(agi->fd, chan, "200 result=0\n");
 		return RESULT_SUCCESS;
 	}
@@ -3342,15 +3136,15 @@ static struct agi_command commands[] = {
 	{ { "noop", NULL }, handle_noop, NULL, NULL, 1 },
 	{ { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
 	{ { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
-	{ { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
+	{ { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 }, 
 	{ { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
 	{ { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
 	{ { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
-	{ { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
-	{ { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
-	{ { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
+	{ { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0}, 
+	{ { "say", "date", NULL }, handle_saydate, NULL, NULL, 0}, 
+	{ { "say", "time", NULL }, handle_saytime, NULL, NULL, 0}, 
 	{ { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
-	{ { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
+	{ { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0}, 
 	{ { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
 	{ { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
 	{ { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
@@ -3480,9 +3274,10 @@ int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_comman
 	}
 	AST_RWLIST_TRAVERSE_SAFE_END;
 	AST_RWLIST_UNLOCK(&agi_commands);
-	if (unregistered) {
+	if (unregistered)
 		ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
-	}
+	else
+		ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
 	return unregistered;
 }
 
@@ -3633,34 +3428,22 @@ normal:
 	return 0;
 }
 
-static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
-			     "CommandId", command_id,
-			     "Command", command,
-			     "ResultCode", result_code,
-			     "Result", result);
-	ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
-}
-
 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
 {
 	const char *argv[MAX_ARGS];
 	int argc = MAX_ARGS;
 	int res;
 	agi_command *c;
-	char *ami_cmd = ast_strdupa(buf);
 	const char *ami_res;
+	char *ami_cmd = ast_strdupa(buf);
 	int command_id = ast_random();
-	int resultcode = 0;
-	RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
-
-	startblob = ast_json_pack("{s: i, s: s}",
-			     "CommandId", command_id,
-			     "Command", ami_cmd);
-	ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
+	int resultcode;
 
+	manager_event(EVENT_FLAG_AGI, "AGIExec",
+			"SubEvent: Start\r\n"
+			"Channel: %s\r\n"
+			"CommandId: %d\r\n"
+			"Command: %s\r\n", ast_channel_name(chan), command_id, ami_cmd);
 	parse_args(buf, &argc, argv);
 	c = find_command(argv, 0);
 	if (c && (!dead || (dead && c->dead))) {
@@ -3668,6 +3451,11 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
 		the module we are using */
 		if (c->mod != ast_module_info->self)
 			ast_module_ref(c->mod);
+		/* If the AGI command being executed is an actual application (using agi exec)
+		the app field will be updated in pbx_exec via handle_exec */
+		if (ast_channel_cdr(chan) && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
+			ast_cdr_setapp(ast_channel_cdr(chan), "AGI", buf);
+
 		res = c->handler(chan, agi, argc, argv);
 		if (c->mod != ast_module_info->self)
 			ast_module_unref(c->mod);
@@ -3675,64 +3463,65 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
 		case RESULT_SHOWUSAGE:
 			ami_res = "Usage";
 			resultcode = 520;
-
-			publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
-
-			if (ast_strlen_zero(c->usage)) {
-				ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
-			} else {
-				ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
-				ast_agi_send(agi->fd, chan, "%s", c->usage);
-				ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
-			}
-
 			break;
 		case RESULT_FAILURE:
 			ami_res = "Failure";
 			resultcode = -1;
-
-			publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
-
-			/* The RESULT_FAILURE code is usually because the channel hungup. */
-			return AGI_RESULT_FAILURE;
+			break;
 		case ASYNC_AGI_BREAK:
-			ami_res = "Success";
-			resultcode = 200;
-
-			publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
-
-			return AGI_RESULT_SUCCESS_ASYNC;
 		case RESULT_SUCCESS:
 			ami_res = "Success";
 			resultcode = 200;
-
-			publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
-
 			break;
 		default:
 			ami_res = "Unknown Result";
 			resultcode = 200;
-
-			publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
-
+			break;
+		}
+		manager_event(EVENT_FLAG_AGI, "AGIExec",
+				"SubEvent: End\r\n"
+				"Channel: %s\r\n"
+				"CommandId: %d\r\n"
+				"Command: %s\r\n"
+				"ResultCode: %d\r\n"
+				"Result: %s\r\n", ast_channel_name(chan), command_id, ami_cmd, resultcode, ami_res);
+		switch (res) {
+		case RESULT_SHOWUSAGE:
+			if (ast_strlen_zero(c->usage)) {
+				ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
+			} else {
+				ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
+				ast_agi_send(agi->fd, chan, "%s", c->usage);
+				ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
+			}
+			break;
+		case ASYNC_AGI_BREAK:
+			return AGI_RESULT_SUCCESS_ASYNC;
+		case RESULT_FAILURE:
+			/* The RESULT_FAILURE code is usually because the channel hungup. */
+			return AGI_RESULT_FAILURE;
+		default:
 			break;
 		}
 	} else if (c) {
-		ami_res = "Command Not Permitted on a dead channel";
-		resultcode = 511;
-
-		ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
-
-		publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
+		ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
+		manager_event(EVENT_FLAG_AGI, "AGIExec",
+				"SubEvent: End\r\n"
+				"Channel: %s\r\n"
+				"CommandId: %d\r\n"
+				"Command: %s\r\n"
+				"ResultCode: 511\r\n"
+				"Result: Command not permitted on a dead channel\r\n", ast_channel_name(chan), command_id, ami_cmd);
 	} else {
-		ami_res = "Invalid or unknown command";
-		resultcode = 510;
-
-		ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
-
-		publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
+		ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
+		manager_event(EVENT_FLAG_AGI, "AGIExec",
+				"SubEvent: End\r\n"
+				"Channel: %s\r\n"
+				"CommandId: %d\r\n"
+				"Command: %s\r\n"
+				"ResultCode: 510\r\n"
+				"Result: Invalid or unknown command\r\n", ast_channel_name(chan), command_id, ami_cmd);
 	}
-
 	return AGI_RESULT_SUCCESS;
 }
 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
@@ -3753,7 +3542,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
 	const char *sighup_str;
 	const char *exit_on_hangup_str;
 	int exit_on_hangup;
-
+	
 	ast_channel_lock(chan);
 	sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
 	send_sighup = !ast_false(sighup_str);
@@ -3768,7 +3557,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
 		close(agi->ctrl);
 		return AGI_RESULT_FAILURE;
 	}
-
+	
 	setlinebuf(readf);
 	setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
 	for (;;) {
@@ -4141,7 +3930,7 @@ static int agi_exec_full(struct ast_channel *chan, const char *data, int enhance
 			return -1;
 	}
 #endif
-	res = launch_script(chan, args.argv[0], args.argc, args.argv, fds, enhanced ? &efd : NULL, &pid);
+	res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
 	/* Async AGI do not require run_agi(), so just proceed if normal AGI
 	   or Fast AGI are setup with success. */
 	if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
@@ -4192,26 +3981,23 @@ static int agi_exec(struct ast_channel *chan, const char *data)
 static int eagi_exec(struct ast_channel *chan, const char *data)
 {
 	int res;
-	struct ast_format *readformat;
+	struct ast_format readformat;
 
 	if (ast_check_hangup(chan)) {
 		ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
 		return 0;
 	}
-	readformat = ao2_bump(ast_channel_readformat(chan));
-	if (ast_set_read_format(chan, ast_format_slin)) {
+	ast_format_copy(&readformat, ast_channel_readformat(chan));
+	if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
 		ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
-		ao2_ref(readformat, -1);
 		return -1;
 	}
 	res = agi_exec_full(chan, data, 1, 0);
 	if (!res) {
-		if (ast_set_read_format(chan, readformat)) {
-			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
-				ast_format_get_name(readformat));
+		if (ast_set_read_format(chan, &readformat)) {
+			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan), ast_getformatname(&readformat));
 		}
 	}
-	ao2_ref(readformat, -1);
 	return res;
 }
 
@@ -4270,50 +4056,33 @@ AST_TEST_DEFINE(test_agi_null_docs)
 
 static int unload_module(void)
 {
-	STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
-
 	ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
-	ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
+	/* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
+	   we know that these commands were registered by this module and are still registered
+	*/
+	(void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
 	ast_unregister_application(eapp);
 	ast_unregister_application(deadapp);
 	ast_manager_unregister("AGI");
-	ast_unregister_application(app);
 	AST_TEST_UNREGISTER(test_agi_null_docs);
-	return 0;
+	return ast_unregister_application(app);
 }
 
 static int load_module(void)
 {
-	int err = 0;
-
-	err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
-	err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
-
-	err |= ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
-	err |= ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
-	err |= ast_register_application_xml(deadapp, deadagi_exec);
-	err |= ast_register_application_xml(eapp, eagi_exec);
-	err |= ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
-	err |= ast_register_application_xml(app, agi_exec);
-
+	ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
+	/* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
+	   no other commands have been registered yet
+	*/
+	(void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
+	ast_register_application_xml(deadapp, deadagi_exec);
+	ast_register_application_xml(eapp, eagi_exec);
+	ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
 	AST_TEST_REGISTER(test_agi_null_docs);
-
-	if (err) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
+	return ast_register_application_xml(app, agi_exec);
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Gateway Interface (AGI)",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_APP_DEPEND,
diff --git a/res/res_ari.c b/res/res_ari.c
deleted file mode 100644
index b6c5284..0000000
--- a/res/res_ari.c
+++ /dev/null
@@ -1,1109 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief HTTP binding for the Stasis API
- * \author David M. Lee, II <dlee at digium.com>
- *
- * The API itself is documented using <a
- * href="https://developers.helloreverb.com/swagger/">Swagger</a>, a lightweight
- * mechanism for documenting RESTful API's using JSON. This allows us to use <a
- * href="https://github.com/wordnik/swagger-ui">swagger-ui</a> to provide
- * executable documentation for the API, generate client bindings in different
- * <a href="https://github.com/asterisk/asterisk_rest_libraries">languages</a>,
- * and generate a lot of the boilerplate code for implementing the RESTful
- * bindings. The API docs live in the \c rest-api/ directory.
- *
- * The RESTful bindings are generated from the Swagger API docs using a set of
- * <a href="http://mustache.github.io/mustache.5.html">Mustache</a> templates.
- * The code generator is written in Python, and uses the Python implementation
- * <a href="https://github.com/defunkt/pystache">pystache</a>. Pystache has no
- * dependencies, and be installed easily using \c pip. Code generation code
- * lives in \c rest-api-templates/.
- *
- * The generated code reduces a lot of boilerplate when it comes to handling
- * HTTP requests. It also helps us have greater consistency in the REST API.
- *
- * The structure of the generated code is:
- *
- *  - res/ari/resource_{resource}.h
- *    - For each operation in the resouce, a generated argument structure
- *      (holding the parsed arguments from the request) and function
- *      declarations (to implement in res/ari/resource_{resource}.c)
- *  - res_ari_{resource}.c
- *    - A set of \ref stasis_rest_callback functions, which glue the two
- *      together. They parse out path variables and request parameters to
- *      populate a specific \c *_args which is passed to the specific request
- *      handler (in res/ari/resource_{resource}.c)
- *    - A tree of \ref stasis_rest_handlers for routing requests to its
- *      \ref stasis_rest_callback
- *
- * The basic flow of an HTTP request is:
- *
- *  - ast_ari_callback()
- *    1. Initial request validation
- *    2. Routes as either a doc request (ast_ari_get_docs) or API
- *       request (ast_ari_invoke)
- *       - ast_ari_invoke()
- *         1. Further request validation
- *         2. Routes the request through the tree of generated
- *            \ref stasis_rest_handlers.
- *         3. Dispatch to the generated callback
- *            - \c ast_ari_*_cb
- *              1. Populate \c *_args struct with path and get params
- *              2. Invoke the request handler
- *    3. Validates and sends response
- */
-
-/*** MODULEINFO
-	<depend type="module">res_http_websocket</depend>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_ari" language="en_US">
-		<synopsis>HTTP binding for the Stasis API</synopsis>
-		<configFile name="ari.conf">
-			<configObject name="general">
-				<synopsis>General configuration settings</synopsis>
-				<configOption name="enabled">
-					<synopsis>Enable/disable the ARI module</synopsis>
-					<description>
-						<para>This option enables or disables the ARI module.</para>
-						<note>
-							<para>ARI uses Asterisk's HTTP server, which must also be enabled in <filename>http.conf</filename>.</para>
-						</note>
-					</description>
-					<see-also>
-						<ref type="filename">http.conf</ref>
-						<ref type="link">https://wiki.asterisk.org/wiki/display/AST/Asterisk+Builtin+mini-HTTP+Server</ref>
-					</see-also>
-				</configOption>
-				<configOption name="websocket_write_timeout">
-					<synopsis>The timeout (in milliseconds) to set on WebSocket connections.</synopsis>
-					<description>
-						<para>If a websocket connection accepts input slowly, the timeout
-						for writes to it can be increased to keep it from being disconnected.
-						Value is in milliseconds; default is 100 ms.</para>
-					</description>
-				</configOption>
-				<configOption name="pretty">
-					<synopsis>Responses from ARI are formatted to be human readable</synopsis>
-				</configOption>
-				<configOption name="auth_realm">
-					<synopsis>Realm to use for authentication. Defaults to Asterisk REST Interface.</synopsis>
-				</configOption>
-				<configOption name="allowed_origins">
-					<synopsis>Comma separated list of allowed origins, for Cross-Origin Resource Sharing. May be set to * to allow all origins.</synopsis>
-				</configOption>
-			</configObject>
-
-			<configObject name="user">
-				<synopsis>Per-user configuration settings</synopsis>
-				<configOption name="type">
-					<synopsis>Define this configuration section as a user.</synopsis>
-					<description>
-						<enumlist>
-							<enum name="user"><para>Configure this section as a <replaceable>user</replaceable></para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="read_only">
-					<synopsis>When set to yes, user is only authorized for read-only requests</synopsis>
-				</configOption>
-				<configOption name="password">
-					<synopsis>Crypted or plaintext password (see password_format)</synopsis>
-				</configOption>
-				<configOption name="password_format">
-					<synopsis>password_format may be set to plain (the default) or crypt. When set to crypt, crypt(3) is used to validate the password. A crypted password can be generated using mkpasswd -m sha-512. When set to plain, the password is in plaintext</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "ari/internal.h"
-#include "asterisk/ari.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/paths.h"
-
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/*! \brief Helper function to check if module is enabled. */
-static int is_enabled(void)
-{
-	RAII_VAR(struct ast_ari_conf *, cfg, ast_ari_config_get(), ao2_cleanup);
-	return cfg && cfg->general && cfg->general->enabled;
-}
-
-/*! Lock for \ref root_handler */
-static ast_mutex_t root_handler_lock;
-
-/*! Handler for root RESTful resource. */
-static struct stasis_rest_handlers *root_handler;
-
-/*! Pre-defined message for allocation failures. */
-static struct ast_json *oom_json;
-
-struct ast_json *ast_ari_oom_json(void)
-{
-	return oom_json;
-}
-
-int ast_ari_add_handler(struct stasis_rest_handlers *handler)
-{
-	RAII_VAR(struct stasis_rest_handlers *, new_handler, NULL, ao2_cleanup);
-	size_t old_size, new_size;
-
-	SCOPED_MUTEX(lock, &root_handler_lock);
-
-	old_size = sizeof(*new_handler) +
-		root_handler->num_children * sizeof(handler);
-	new_size = old_size + sizeof(handler);
-
-	new_handler = ao2_alloc(new_size, NULL);
-	if (!new_handler) {
-		return -1;
-	}
-	memcpy(new_handler, root_handler, old_size);
-	new_handler->children[new_handler->num_children++] = handler;
-
-	ao2_cleanup(root_handler);
-	ao2_ref(new_handler, +1);
-	root_handler = new_handler;
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
-{
-	RAII_VAR(struct stasis_rest_handlers *, new_handler, NULL, ao2_cleanup);
-	size_t size, i, j;
-
-	ast_assert(root_handler != NULL);
-
-	ast_mutex_lock(&root_handler_lock);
-	size = sizeof(*new_handler) +
-		root_handler->num_children * sizeof(handler);
-
-	new_handler = ao2_alloc(size, NULL);
-	if (!new_handler) {
-		return -1;
-	}
-	memcpy(new_handler, root_handler, sizeof(*new_handler));
-
-	for (i = 0, j = 0; i < root_handler->num_children; ++i) {
-		if (root_handler->children[i] == handler) {
-			ast_module_unref(ast_module_info->self);
-			continue;
-		}
-		new_handler->children[j++] = root_handler->children[i];
-	}
-	new_handler->num_children = j;
-
-	ao2_cleanup(root_handler);
-	ao2_ref(new_handler, +1);
-	root_handler = new_handler;
-	ast_mutex_unlock(&root_handler_lock);
-	return 0;
-}
-
-static struct stasis_rest_handlers *get_root_handler(void)
-{
-	SCOPED_MUTEX(lock, &root_handler_lock);
-	ao2_ref(root_handler, +1);
-	return root_handler;
-}
-
-static struct stasis_rest_handlers *root_handler_create(void)
-{
-	RAII_VAR(struct stasis_rest_handlers *, handler, NULL, ao2_cleanup);
-
-	handler = ao2_alloc(sizeof(*handler), NULL);
-	if (!handler) {
-		return NULL;
-	}
-	handler->path_segment = "ari";
-
-	ao2_ref(handler, +1);
-	return handler;
-}
-
-void ast_ari_response_error(struct ast_ari_response *response,
-				int response_code,
-				const char *response_text,
-				const char *message_fmt, ...)
-{
-	RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
-	va_list ap;
-
-	va_start(ap, message_fmt);
-	message = ast_json_vstringf(message_fmt, ap);
-	va_end(ap);
-	response->message = ast_json_pack("{s: o}",
-					  "message", ast_json_ref(message));
-	response->response_code = response_code;
-	response->response_text = response_text;
-}
-
-void ast_ari_response_ok(struct ast_ari_response *response,
-			     struct ast_json *message)
-{
-	response->message = message;
-	response->response_code = 200;
-	response->response_text = "OK";
-}
-
-void ast_ari_response_no_content(struct ast_ari_response *response)
-{
-	response->message = ast_json_null();
-	response->response_code = 204;
-	response->response_text = "No Content";
-}
-
-void ast_ari_response_alloc_failed(struct ast_ari_response *response)
-{
-	response->message = ast_json_ref(oom_json);
-	response->response_code = 500;
-	response->response_text = "Internal Server Error";
-}
-
-void ast_ari_response_created(struct ast_ari_response *response,
-	const char *url, struct ast_json *message)
-{
-	response->message = message;
-	response->response_code = 201;
-	response->response_text = "Created";
-	ast_str_append(&response->headers, 0, "Location: %s\r\n", url);
-}
-
-static void add_allow_header(struct stasis_rest_handlers *handler,
-			     struct ast_ari_response *response)
-{
-	enum ast_http_method m;
-	ast_str_append(&response->headers, 0,
-		       "Allow: OPTIONS");
-	for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
-		if (handler->callbacks[m] != NULL) {
-			ast_str_append(&response->headers, 0,
-				       ",%s", ast_get_http_method(m));
-		}
-	}
-	ast_str_append(&response->headers, 0, "\r\n");
-}
-
-static int origin_allowed(const char *origin)
-{
-	RAII_VAR(struct ast_ari_conf *, cfg, ast_ari_config_get(), ao2_cleanup);
-
-	char *allowed = ast_strdupa(cfg->general->allowed_origins);
-	char *current;
-
-	while ((current = strsep(&allowed, ","))) {
-		if (!strcmp(current, "*")) {
-			return 1;
-		}
-
-		if (!strcmp(current, origin)) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-#define ACR_METHOD "Access-Control-Request-Method"
-#define ACR_HEADERS "Access-Control-Request-Headers"
-#define ACA_METHODS "Access-Control-Allow-Methods"
-#define ACA_HEADERS "Access-Control-Allow-Headers"
-
-/*!
- * \brief Handle OPTIONS request, mainly for CORS preflight requests.
- *
- * Some browsers will send this prior to non-simple methods (i.e. DELETE).
- * See http://www.w3.org/TR/cors/ for the spec. Especially section 6.2.
- */
-static void handle_options(struct stasis_rest_handlers *handler,
-			   struct ast_variable *headers,
-			   struct ast_ari_response *response)
-{
-	struct ast_variable *header;
-	char const *acr_method = NULL;
-	char const *acr_headers = NULL;
-	char const *origin = NULL;
-
-	RAII_VAR(struct ast_str *, allow, NULL, ast_free);
-	enum ast_http_method m;
-	int allowed = 0;
-
-	/* Regular OPTIONS response */
-	add_allow_header(handler, response);
-	ast_ari_response_no_content(response);
-
-	/* Parse CORS headers */
-	for (header = headers; header != NULL; header = header->next) {
-		if (strcmp(ACR_METHOD, header->name) == 0) {
-			acr_method = header->value;
-		} else if (strcmp(ACR_HEADERS, header->name) == 0) {
-			acr_headers = header->value;
-		} else if (strcmp("Origin", header->name) == 0) {
-			origin = header->value;
-		}
-	}
-
-	/* CORS 6.2, #1 - "If the Origin header is not present terminate this
-	 * set of steps."
-	 */
-	if (origin == NULL) {
-		return;
-	}
-
-	/* CORS 6.2, #2 - "If the value of the Origin header is not a
-	 * case-sensitive match for any of the values in list of origins do not
-	 * set any additional headers and terminate this set of steps.
-	 *
-	 * Always matching is acceptable since the list of origins can be
-	 * unbounded.
-	 *
-	 * The Origin header can only contain a single origin as the user agent
-	 * will not follow redirects."
-	 */
-	if (!origin_allowed(origin)) {
-		ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
-		return;
-	}
-
-	/* CORS 6.2, #3 - "If there is no Access-Control-Request-Method header
-	 * or if parsing failed, do not set any additional headers and terminate
-	 * this set of steps."
-	 */
-	if (acr_method == NULL) {
-		return;
-	}
-
-	/* CORS 6.2, #4 - "If there are no Access-Control-Request-Headers
-	 * headers let header field-names be the empty list."
-	 */
-	if (acr_headers == NULL) {
-		acr_headers = "";
-	}
-
-	/* CORS 6.2, #5 - "If method is not a case-sensitive match for any of
-	 * the values in list of methods do not set any additional headers and
-	 * terminate this set of steps."
-	 */
-	allow = ast_str_create(20);
-
-	if (!allow) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	/* Go ahead and build the ACA_METHODS header at the same time */
-	for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
-		if (handler->callbacks[m] != NULL) {
-			char const *m_str = ast_get_http_method(m);
-			if (strcmp(m_str, acr_method) == 0) {
-				allowed = 1;
-			}
-			ast_str_append(&allow, 0, ",%s", m_str);
-		}
-	}
-
-	if (!allowed) {
-		return;
-	}
-
-	/* CORS 6.2 #6 - "If any of the header field-names is not a ASCII
-	 * case-insensitive match for any of the values in list of headers do
-	 * not set any additional headers and terminate this set of steps.
-	 *
-	 * Note: Always matching is acceptable since the list of headers can be
-	 * unbounded."
-	 */
-
-	/* CORS 6.2 #7 - "If the resource supports credentials add a single
-	 * Access-Control-Allow-Origin header, with the value of the Origin
-	 * header as value, and add a single Access-Control-Allow-Credentials
-	 * header with the case-sensitive string "true" as value."
-	 *
-	 * Added by process_cors_request() earlier in the request.
-	 */
-
-	/* CORS 6.2 #8 - "Optionally add a single Access-Control-Max-Age
-	 * header..."
-	 */
-
-	/* CORS 6.2 #9 - "Add one or more Access-Control-Allow-Methods headers
-	 * consisting of (a subset of) the list of methods."
-	 */
-	ast_str_append(&response->headers, 0, "%s: OPTIONS%s\r\n",
-		       ACA_METHODS, ast_str_buffer(allow));
-
-
-	/* CORS 6.2, #10 - "Add one or more Access-Control-Allow-Headers headers
-	 * consisting of (a subset of) the list of headers.
-	 *
-	 * Since the list of headers can be unbounded simply returning headers
-	 * can be enough."
-	 */
-	if (!ast_strlen_zero(acr_headers)) {
-		ast_str_append(&response->headers, 0, "%s: %s\r\n",
-			       ACA_HEADERS, acr_headers);
-	}
-}
-
-void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
-	const char *uri, enum ast_http_method method,
-	struct ast_variable *get_params, struct ast_variable *headers,
-	struct ast_ari_response *response)
-{
-	RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
-	struct stasis_rest_handlers *handler;
-	RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
-	char *path = ast_strdupa(uri);
-	char *path_segment;
-	stasis_rest_callback callback;
-
-	root = handler = get_root_handler();
-	ast_assert(root != NULL);
-
-	while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
-		struct stasis_rest_handlers *found_handler = NULL;
-		int i;
-		ast_uri_decode(path_segment, ast_uri_http_legacy);
-		ast_debug(3, "Finding handler for %s\n", path_segment);
-		for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
-			struct stasis_rest_handlers *child = handler->children[i];
-
-			ast_debug(3, "  Checking %s\n", child->path_segment);
-			if (child->is_wildcard) {
-				/* Record the path variable */
-				struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
-				path_var->next = path_vars;
-				path_vars = path_var;
-				found_handler = child;
-			} else if (strcmp(child->path_segment, path_segment) == 0) {
-				found_handler = child;
-			}
-		}
-
-		if (found_handler == NULL) {
-			/* resource not found */
-			ast_debug(3, "  Handler not found\n");
-			ast_ari_response_error(
-				response, 404, "Not Found",
-				"Resource not found");
-			return;
-		} else {
-			ast_debug(3, "  Got it!\n");
-			handler = found_handler;
-		}
-	}
-
-	ast_assert(handler != NULL);
-	if (method == AST_HTTP_OPTIONS) {
-		handle_options(handler, headers, response);
-		return;
-	}
-
-	if (method < 0 || method >= AST_HTTP_MAX_METHOD) {
-		add_allow_header(handler, response);
-		ast_ari_response_error(
-			response, 405, "Method Not Allowed",
-			"Invalid method");
-		return;
-	}
-
-	if (handler->ws_server && method == AST_HTTP_GET) {
-		/* WebSocket! */
-		ari_handle_websocket(handler->ws_server, ser, uri, method,
-			get_params, headers);
-		/* Since the WebSocket code handles the connection, we shouldn't
-		 * do anything else; setting no_response */
-		response->no_response = 1;
-		return;
-	}
-
-	callback = handler->callbacks[method];
-	if (callback == NULL) {
-		add_allow_header(handler, response);
-		ast_ari_response_error(
-			response, 405, "Method Not Allowed",
-			"Invalid method");
-		return;
-	}
-
-	callback(ser, get_params, path_vars, headers, response);
-	if (response->message == NULL && response->response_code == 0) {
-		/* Really should not happen */
-		ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
-			ast_get_http_method(method), uri);
-		ast_ari_response_error(
-			response, 501, "Not Implemented",
-			"Method not implemented");
-	}
-}
-
-void ast_ari_get_docs(const char *uri, struct ast_variable *headers,
-			  struct ast_ari_response *response)
-{
-	RAII_VAR(struct ast_str *, absolute_path_builder, NULL, ast_free);
-	RAII_VAR(char *, absolute_api_dirname, NULL, ast_std_free);
-	RAII_VAR(char *, absolute_filename, NULL, ast_std_free);
-	struct ast_json *obj = NULL;
-	struct ast_variable *host = NULL;
-	struct ast_json_error error = {};
-	struct stat file_stat;
-
-	ast_debug(3, "%s(%s)\n", __func__, uri);
-
-	absolute_path_builder = ast_str_create(80);
-	if (absolute_path_builder == NULL) {
-		ast_ari_response_alloc_failed(response);
-		return;
-	}
-
-	/* absolute path to the rest-api directory */
-	ast_str_append(&absolute_path_builder, 0, "%s", ast_config_AST_DATA_DIR);
-	ast_str_append(&absolute_path_builder, 0, "/rest-api/");
-	absolute_api_dirname = realpath(ast_str_buffer(absolute_path_builder), NULL);
-	if (absolute_api_dirname == NULL) {
-		ast_log(LOG_ERROR, "Error determining real directory for rest-api\n");
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Cannot find rest-api directory");
-		return;
-	}
-
-	/* absolute path to the requested file */
-	ast_str_append(&absolute_path_builder, 0, "%s", uri);
-	absolute_filename = realpath(ast_str_buffer(absolute_path_builder), NULL);
-	if (absolute_filename == NULL) {
-		switch (errno) {
-		case ENAMETOOLONG:
-		case ENOENT:
-		case ENOTDIR:
-			ast_ari_response_error(
-				response, 404, "Not Found",
-				"Resource not found");
-			break;
-		case EACCES:
-			ast_ari_response_error(
-				response, 403, "Forbidden",
-				"Permission denied");
-			break;
-		default:
-			ast_log(LOG_ERROR,
-				"Error determining real path for uri '%s': %s\n",
-				uri, strerror(errno));
-			ast_ari_response_error(
-				response, 500, "Internal Server Error",
-				"Cannot find file");
-			break;
-		}
-		return;
-	}
-
-	if (!ast_begins_with(absolute_filename, absolute_api_dirname)) {
-		/* HACKERZ! */
-		ast_log(LOG_ERROR,
-			"Invalid attempt to access '%s' (not in %s)\n",
-			absolute_filename, absolute_api_dirname);
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Resource not found");
-		return;
-	}
-
-	if (stat(absolute_filename, &file_stat) == 0) {
-		if (!(file_stat.st_mode & S_IFREG)) {
-			/* Not a file */
-			ast_ari_response_error(
-				response, 403, "Forbidden",
-				"Invalid access");
-			return;
-		}
-	} else {
-		/* Does not exist */
-		ast_ari_response_error(
-			response, 404, "Not Found",
-			"Resource not found");
-		return;
-	}
-
-	/* Load resource object from file */
-	obj = ast_json_load_new_file(absolute_filename, &error);
-	if (obj == NULL) {
-		ast_log(LOG_ERROR, "Error parsing resource file: %s:%d(%d) %s\n",
-			error.source, error.line, error.column, error.text);
-		ast_ari_response_error(
-			response, 500, "Internal Server Error",
-			"Yikes! Cannot parse resource");
-		return;
-	}
-
-	/* Update the basePath properly */
-	if (ast_json_object_get(obj, "basePath") != NULL) {
-		for (host = headers; host; host = host->next) {
-			if (strcasecmp(host->name, "Host") == 0) {
-				break;
-			}
-		}
-		if (host != NULL) {
-			ast_json_object_set(
-				obj, "basePath",
-				ast_json_stringf("http://%s/ari", host->value));
-		} else {
-			/* Without the host, we don't have the basePath */
-			ast_json_object_del(obj, "basePath");
-		}
-	}
-
-	ast_ari_response_ok(response, obj);
-}
-
-static void remove_trailing_slash(const char *uri,
-				  struct ast_ari_response *response)
-{
-	char *slashless = ast_strdupa(uri);
-	slashless[strlen(slashless) - 1] = '\0';
-
-	/* While it's tempting to redirect the client to the slashless URL,
-	 * that is problematic. A 302 Found is the most appropriate response,
-	 * but most clients issue a GET on the location you give them,
-	 * regardless of the method of the original request.
-	 *
-	 * While there are some ways around this, it gets into a lot of client
-	 * specific behavior and corner cases in the HTTP standard. There's also
-	 * very little practical benefit of redirecting; only GET and HEAD can
-	 * be redirected automagically; all other requests "MUST NOT
-	 * automatically redirect the request unless it can be confirmed by the
-	 * user, since this might change the conditions under which the request
-	 * was issued."
-	 *
-	 * Given all of that, a 404 with a nice message telling them what to do
-	 * is probably our best bet.
-	 */
-	ast_ari_response_error(response, 404, "Not Found",
-		"ARI URLs do not end with a slash. Try /ari/%s", slashless);
-}
-
-/*!
- * \brief Handle CORS headers for simple requests.
- *
- * See http://www.w3.org/TR/cors/ for the spec. Especially section 6.1.
- */
-static void process_cors_request(struct ast_variable *headers,
-				 struct ast_ari_response *response)
-{
-	char const *origin = NULL;
-	struct ast_variable *header;
-
-	/* Parse CORS headers */
-	for (header = headers; header != NULL; header = header->next) {
-		if (strcmp("Origin", header->name) == 0) {
-			origin = header->value;
-		}
-	}
-
-	/* CORS 6.1, #1 - "If the Origin header is not present terminate this
-	 * set of steps."
-	 */
-	if (origin == NULL) {
-		return;
-	}
-
-	/* CORS 6.1, #2 - "If the value of the Origin header is not a
-	 * case-sensitive match for any of the values in list of origins, do not
-	 * set any additional headers and terminate this set of steps.
-	 *
-	 * Note: Always matching is acceptable since the list of origins can be
-	 * unbounded."
-	 */
-	if (!origin_allowed(origin)) {
-		ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
-		return;
-	}
-
-	/* CORS 6.1, #3 - "If the resource supports credentials add a single
-	 * Access-Control-Allow-Origin header, with the value of the Origin
-	 * header as value, and add a single Access-Control-Allow-Credentials
-	 * header with the case-sensitive string "true" as value.
-	 *
-	 * Otherwise, add a single Access-Control-Allow-Origin header, with
-	 * either the value of the Origin header or the string "*" as value."
-	 */
-	ast_str_append(&response->headers, 0,
-		       "Access-Control-Allow-Origin: %s\r\n", origin);
-	ast_str_append(&response->headers, 0,
-		       "Access-Control-Allow-Credentials: true\r\n");
-
-	/* CORS 6.1, #4 - "If the list of exposed headers is not empty add one
-	 * or more Access-Control-Expose-Headers headers, with as values the
-	 * header field names given in the list of exposed headers."
-	 *
-	 * No exposed headers; skipping
-	 */
-}
-
-enum ast_json_encoding_format ast_ari_json_format(void)
-{
-	RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
-	cfg = ast_ari_config_get();
-	return cfg->general->format;
-}
-
-/*!
- * \brief Authenticate a <code>?api_key=userid:password</code>
- *
- * \param api_key API key query parameter
- * \return User object for the authenticated user.
- * \return \c NULL if authentication failed.
- */
-static struct ast_ari_conf_user *authenticate_api_key(const char *api_key)
-{
-	RAII_VAR(char *, copy, NULL, ast_free);
-	char *username;
-	char *password;
-
-	password = copy = ast_strdup(api_key);
-	if (!copy) {
-		return NULL;
-	}
-
-	username = strsep(&password, ":");
-	if (!password) {
-		ast_log(LOG_WARNING, "Invalid api_key\n");
-		return NULL;
-	}
-
-	return ast_ari_config_validate_user(username, password);
-}
-
-/*!
- * \brief Authenticate an HTTP request.
- *
- * \param get_params GET parameters of the request.
- * \param header HTTP headers.
- * \return User object for the authenticated user.
- * \return \c NULL if authentication failed.
- */
-static struct ast_ari_conf_user *authenticate_user(struct ast_variable *get_params,
-	struct ast_variable *headers)
-{
-	RAII_VAR(struct ast_http_auth *, http_auth, NULL, ao2_cleanup);
-	struct ast_variable *v;
-
-	/* HTTP Basic authentication */
-	http_auth = ast_http_get_auth(headers);
-	if (http_auth) {
-		return ast_ari_config_validate_user(http_auth->userid,
-			http_auth->password);
-	}
-
-	/* ?api_key authentication */
-	for (v = get_params; v; v = v->next) {
-		if (strcasecmp("api_key", v->name) == 0) {
-			return authenticate_api_key(v->value);
-		}
-	}
-
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief ARI HTTP handler.
- *
- * This handler takes the HTTP request and turns it into the appropriate
- * RESTful request (conversion to JSON, routing, etc.)
- *
- * \param ser TCP session.
- * \param urih URI handler.
- * \param uri URI requested.
- * \param method HTTP method.
- * \param get_params HTTP \c GET params.
- * \param headers HTTP headers.
- */
-static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
-				const struct ast_http_uri *urih,
-				const char *uri,
-				enum ast_http_method method,
-				struct ast_variable *get_params,
-				struct ast_variable *headers)
-{
-	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
-	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
-	struct ast_ari_response response = {};
-	RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
-
-	if (!response_body) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
-		return 0;
-	}
-
-	response.headers = ast_str_create(40);
-	if (!response.headers) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
-		return 0;
-	}
-
-	conf = ast_ari_config_get();
-	if (!conf || !conf->general) {
-		ast_free(response.headers);
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "URI handler config missing");
-		return 0;
-	}
-
-	process_cors_request(headers, &response);
-
-	/* Process form data from a POST. It could be mixed with query
-	 * parameters, which seems a bit odd. But it's allowed, so that's okay
-	 * with us.
-	 */
-	post_vars = ast_http_get_post_vars(ser, headers);
-	if (!post_vars) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(&response, 413,
-				"Request Entity Too Large",
-				"Request body too large");
-			goto request_failed;
-		case ENOMEM:
-			ast_http_request_close_on_completion(ser);
-			ast_ari_response_error(&response, 500,
-				"Internal Server Error",
-				"Out of memory");
-			goto request_failed;
-		case EIO:
-			ast_ari_response_error(&response, 400,
-				"Bad Request", "Error parsing request body");
-			goto request_failed;
-		}
-	}
-	if (get_params == NULL) {
-		get_params = post_vars;
-	} else if (get_params && post_vars) {
-		/* Has both post_vars and get_params */
-		struct ast_variable *last_var = post_vars;
-		while (last_var->next) {
-			last_var = last_var->next;
-		}
-		/* The duped get_params will get freed when post_vars gets
-		 * ast_variables_destroyed.
-		 */
-		last_var->next = ast_variables_dup(get_params);
-		get_params = post_vars;
-	}
-
-	user = authenticate_user(get_params, headers);
-	if (response.response_code > 0) {
-		/* POST parameter processing error. Do nothing. */
-	} else if (!user) {
-		/* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
-		 * message is used by an origin server to challenge the
-		 * authorization of a user agent. This response MUST include a
-		 * WWW-Authenticate header field containing at least one
-		 * challenge applicable to the requested resource.
-		 */
-		ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required");
-
-		/* Section 1.2:
-		 *   realm       = "realm" "=" realm-value
-		 *   realm-value = quoted-string
-		 * Section 2:
-		 *   challenge   = "Basic" realm
-		 */
-		ast_str_append(&response.headers, 0,
-			"WWW-Authenticate: Basic realm=\"%s\"\r\n",
-			conf->general->auth_realm);
-	} else if (!ast_fully_booted) {
-		ast_http_request_close_on_completion(ser);
-		ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted");
-	} else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
-		ast_ari_response_error(&response, 403, "Forbidden", "Write access denied");
-	} else if (ast_ends_with(uri, "/")) {
-		remove_trailing_slash(uri, &response);
-	} else if (ast_begins_with(uri, "api-docs/")) {
-		/* Serving up API docs */
-		if (method != AST_HTTP_GET) {
-			ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method");
-		} else {
-			/* Skip the api-docs prefix */
-			ast_ari_get_docs(strchr(uri, '/') + 1, headers, &response);
-		}
-	} else {
-		/* Other RESTful resources */
-		ast_ari_invoke(ser, uri, method, get_params, headers,
-			&response);
-	}
-
-	if (response.no_response) {
-		/* The handler indicates no further response is necessary.
-		 * Probably because it already handled it */
-		ast_free(response.headers);
-		return 0;
-	}
-
-request_failed:
-	/* If you explicitly want to have no content, set message to
-	 * ast_json_null().
-	 */
-	ast_assert(response.message != NULL);
-	ast_assert(response.response_code > 0);
-
-	/* response.message could be NULL, in which case the empty response_body
-	 * is correct
-	 */
-	if (response.message && !ast_json_is_null(response.message)) {
-		ast_str_append(&response.headers, 0,
-			       "Content-type: application/json\r\n");
-		if (ast_json_dump_str_format(response.message, &response_body,
-				conf->general->format) != 0) {
-			/* Error encoding response */
-			response.response_code = 500;
-			response.response_text = "Internal Server Error";
-			ast_str_set(&response_body, 0, "%s", "");
-			ast_str_set(&response.headers, 0, "%s", "");
-		}
-	}
-
-	ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code,
-		response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body));
-	ast_http_send(ser, method, response.response_code,
-		      response.response_text, response.headers, response_body,
-		      0, 0);
-	/* ast_http_send takes ownership, so we don't have to free them */
-	response_body = NULL;
-
-	ast_json_unref(response.message);
-	return 0;
-}
-
-static struct ast_http_uri http_uri = {
-	.callback = ast_ari_callback,
-	.description = "Asterisk RESTful API",
-	.uri = "ari",
-
-	.has_subtree = 1,
-	.data = NULL,
-	.key = __FILE__,
-	.no_decode_uri = 1,
-};
-
-static int load_module(void)
-{
-	ast_mutex_init(&root_handler_lock);
-
-	/* root_handler may have been built during a declined load */
-	if (!root_handler) {
-		root_handler = root_handler_create();
-	}
-	if (!root_handler) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	/* oom_json may have been built during a declined load */
-	if (!oom_json) {
-		oom_json = ast_json_pack(
-			"{s: s}", "error", "Allocation failed");
-	}
-	if (!oom_json) {
-		/* Ironic */
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (ast_ari_config_init() != 0) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (is_enabled()) {
-		ast_debug(3, "ARI enabled\n");
-		ast_http_uri_link(&http_uri);
-	} else {
-		ast_debug(3, "ARI disabled\n");
-	}
-
-	if (ast_ari_cli_register() != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_ari_cli_unregister();
-
-	if (is_enabled()) {
-		ast_debug(3, "Disabling ARI\n");
-		ast_http_uri_unlink(&http_uri);
-	}
-
-	ast_ari_config_destroy();
-
-	ao2_cleanup(root_handler);
-	root_handler = NULL;
-	ast_mutex_destroy(&root_handler_lock);
-
-	ast_json_unref(oom_json);
-	oom_json = NULL;
-
-	return 0;
-}
-
-static int reload_module(void)
-{
-	char was_enabled = is_enabled();
-
-	if (ast_ari_config_reload() != 0) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (was_enabled && !is_enabled()) {
-		ast_debug(3, "Disabling ARI\n");
-		ast_http_uri_unlink(&http_uri);
-	} else if (!was_enabled && is_enabled()) {
-		ast_debug(3, "Enabling ARI\n");
-		ast_http_uri_link(&http_uri);
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk RESTful Interface",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.reload = reload_module,
-	.nonoptreq = "res_http_websocket",
-	.load_pri = AST_MODPRI_APP_DEPEND,
-	);
diff --git a/res/res_ari.exports.in b/res/res_ari.exports.in
deleted file mode 100644
index f143ef3..0000000
--- a/res/res_ari.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_ari_*;
-	local:
-		*;
-};
diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c
deleted file mode 100644
index 882b618..0000000
--- a/res/res_ari_applications.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Stasis application resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_applications.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /applications.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_applications_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_applications_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_applications_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_application_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /applications\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /applications\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /applications/{applicationName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_applications_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_applications_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "applicationName") == 0) {
-			args.application_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_applications_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Application does not exist. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_application(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_applications_subscribe_parse_body(
-	struct ast_json *body,
-	struct ast_ari_applications_subscribe_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "eventSource");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->event_source);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->event_source_count = ast_json_array_size(field);
-			args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
-
-			if (!args->event_source) {
-				return -1;
-			}
-
-			for (i = 0; i < args->event_source_count; ++i) {
-				args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->event_source_count = 1;
-			args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
-			if (!args->event_source) {
-				return -1;
-			}
-			args->event_source[0] = ast_json_string_get(field);
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_applications_subscribe_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_applications_subscribe_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "eventSource") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.event_source_parse = ast_strdup(i->value);
-			if (!args.event_source_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.event_source_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.event_source_count = 1;
-				vals[0] = args.event_source_parse;
-			} else {
-				args.event_source_count = ast_app_separate_args(
-					args.event_source_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.event_source_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.event_source_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for event_source");
-				goto fin;
-			}
-
-			args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
-			if (!args.event_source) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.event_source_count; ++j) {
-				args.event_source[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "applicationName") == 0) {
-			args.application_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_applications_subscribe_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_applications_subscribe(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing parameter. */
-	case 404: /* Application does not exist. */
-	case 422: /* Event source does not exist. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_application(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.event_source_parse);
-	ast_free(args.event_source);
-	return;
-}
-int ast_ari_applications_unsubscribe_parse_body(
-	struct ast_json *body,
-	struct ast_ari_applications_unsubscribe_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "eventSource");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->event_source);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->event_source_count = ast_json_array_size(field);
-			args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
-
-			if (!args->event_source) {
-				return -1;
-			}
-
-			for (i = 0; i < args->event_source_count; ++i) {
-				args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->event_source_count = 1;
-			args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
-			if (!args->event_source) {
-				return -1;
-			}
-			args->event_source[0] = ast_json_string_get(field);
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_applications_unsubscribe_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_applications_unsubscribe_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "eventSource") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.event_source_parse = ast_strdup(i->value);
-			if (!args.event_source_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.event_source_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.event_source_count = 1;
-				vals[0] = args.event_source_parse;
-			} else {
-				args.event_source_count = ast_app_separate_args(
-					args.event_source_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.event_source_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.event_source_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for event_source");
-				goto fin;
-			}
-
-			args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
-			if (!args.event_source) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.event_source_count; ++j) {
-				args.event_source[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "applicationName") == 0) {
-			args.application_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_applications_unsubscribe_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_applications_unsubscribe(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing parameter; event source scheme not recognized. */
-	case 404: /* Application does not exist. */
-	case 409: /* Application not subscribed to event source. */
-	case 422: /* Event source does not exist. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_application(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.event_source_parse);
-	ast_free(args.event_source);
-	return;
-}
-
-/*! \brief REST handler for /api-docs/applications.{format} */
-static struct stasis_rest_handlers applications_applicationName_subscription = {
-	.path_segment = "subscription",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_applications_subscribe_cb,
-		[AST_HTTP_DELETE] = ast_ari_applications_unsubscribe_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/applications.{format} */
-static struct stasis_rest_handlers applications_applicationName = {
-	.path_segment = "applicationName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_applications_get_cb,
-	},
-	.num_children = 1,
-	.children = { &applications_applicationName_subscription, }
-};
-/*! \brief REST handler for /api-docs/applications.{format} */
-static struct stasis_rest_handlers applications = {
-	.path_segment = "applications",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_applications_list_cb,
-	},
-	.num_children = 1,
-	.children = { &applications_applicationName, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&applications);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&applications);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Stasis application resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c
deleted file mode 100644
index 05f6567..0000000
--- a/res/res_ari_asterisk.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Asterisk resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_asterisk.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-int ast_ari_asterisk_get_info_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_get_info_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "only");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->only);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->only_count = ast_json_array_size(field);
-			args->only = ast_malloc(sizeof(*args->only) * args->only_count);
-
-			if (!args->only) {
-				return -1;
-			}
-
-			for (i = 0; i < args->only_count; ++i) {
-				args->only[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->only_count = 1;
-			args->only = ast_malloc(sizeof(*args->only) * args->only_count);
-			if (!args->only) {
-				return -1;
-			}
-			args->only[0] = ast_json_string_get(field);
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /asterisk/info.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_asterisk_get_info_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_asterisk_get_info_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "only") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.only_parse = ast_strdup(i->value);
-			if (!args.only_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.only_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.only_count = 1;
-				vals[0] = args.only_parse;
-			} else {
-				args.only_count = ast_app_separate_args(
-					args.only_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.only_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.only_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for only");
-				goto fin;
-			}
-
-			args.only = ast_malloc(sizeof(*args.only) * args.only_count);
-			if (!args.only) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.only_count; ++j) {
-				args.only[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_asterisk_get_info_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_asterisk_get_info(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_asterisk_info(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/info\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /asterisk/info\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.only_parse);
-	ast_free(args.only);
-	return;
-}
-int ast_ari_asterisk_get_global_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_get_global_var_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "variable");
-	if (field) {
-		args->variable = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /asterisk/variable.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_asterisk_get_global_var_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_asterisk_get_global_var_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "variable") == 0) {
-			args.variable = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_asterisk_get_global_var(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing variable parameter. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_variable(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_asterisk_set_global_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_asterisk_set_global_var_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "variable");
-	if (field) {
-		args->variable = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "value");
-	if (field) {
-		args->value = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /asterisk/variable.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_asterisk_set_global_var_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_asterisk_set_global_var_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "variable") == 0) {
-			args.variable = (i->value);
-		} else
-		if (strcmp(i->name, "value") == 0) {
-			args.value = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_asterisk_set_global_var(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing variable parameter. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /asterisk/variable\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /asterisk/variable\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/asterisk.{format} */
-static struct stasis_rest_handlers asterisk_info = {
-	.path_segment = "info",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_asterisk_get_info_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/asterisk.{format} */
-static struct stasis_rest_handlers asterisk_variable = {
-	.path_segment = "variable",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_asterisk_get_global_var_cb,
-		[AST_HTTP_POST] = ast_ari_asterisk_set_global_var_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/asterisk.{format} */
-static struct stasis_rest_handlers asterisk = {
-	.path_segment = "asterisk",
-	.callbacks = {
-	},
-	.num_children = 2,
-	.children = { &asterisk_info,&asterisk_variable, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&asterisk);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&asterisk);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c
deleted file mode 100644
index 72d33c6..0000000
--- a/res/res_ari_bridges.c
+++ /dev/null
@@ -1,1419 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Bridge resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_bridges.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /bridges.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_bridges_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_bridge_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_create_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_create_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "type");
-	if (field) {
-		args->type = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "bridgeId");
-	if (field) {
-		args->bridge_id = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "name");
-	if (field) {
-		args->name = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_create_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_create_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "type") == 0) {
-			args.type = (i->value);
-		} else
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		if (strcmp(i->name, "name") == 0) {
-			args.name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_create_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_create(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_bridge(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_create_or_update_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_create_or_update_with_id_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "type");
-	if (field) {
-		args->type = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "name");
-	if (field) {
-		args->name = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_create_or_update_with_id_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_create_or_update_with_id_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "type") == 0) {
-			args.type = (i->value);
-		} else
-		if (strcmp(i->name, "name") == 0) {
-			args.name = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_create_or_update_with_id_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_create_or_update_with_id(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_bridge(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_bridges_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_bridge(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_destroy_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_destroy_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_bridges_destroy(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_add_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_add_channel_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "channel");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->channel);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->channel_count = ast_json_array_size(field);
-			args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
-
-			if (!args->channel) {
-				return -1;
-			}
-
-			for (i = 0; i < args->channel_count; ++i) {
-				args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->channel_count = 1;
-			args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
-			if (!args->channel) {
-				return -1;
-			}
-			args->channel[0] = ast_json_string_get(field);
-		}
-	}
-	field = ast_json_object_get(body, "role");
-	if (field) {
-		args->role = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_add_channel_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_add_channel_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "channel") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.channel_parse = ast_strdup(i->value);
-			if (!args.channel_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.channel_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.channel_count = 1;
-				vals[0] = args.channel_parse;
-			} else {
-				args.channel_count = ast_app_separate_args(
-					args.channel_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.channel_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.channel_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for channel");
-				goto fin;
-			}
-
-			args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
-			if (!args.channel) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.channel_count; ++j) {
-				args.channel[j] = (vals[j]);
-			}
-		} else
-		if (strcmp(i->name, "role") == 0) {
-			args.role = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_add_channel_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_add_channel(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Channel not found */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in Stasis application; Channel currently recording */
-	case 422: /* Channel not in Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/addChannel\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/addChannel\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.channel_parse);
-	ast_free(args.channel);
-	return;
-}
-int ast_ari_bridges_remove_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_remove_channel_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "channel");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->channel);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->channel_count = ast_json_array_size(field);
-			args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
-
-			if (!args->channel) {
-				return -1;
-			}
-
-			for (i = 0; i < args->channel_count; ++i) {
-				args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->channel_count = 1;
-			args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
-			if (!args->channel) {
-				return -1;
-			}
-			args->channel[0] = ast_json_string_get(field);
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_remove_channel_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_remove_channel_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "channel") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.channel_parse = ast_strdup(i->value);
-			if (!args.channel_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.channel_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.channel_count = 1;
-				vals[0] = args.channel_parse;
-			} else {
-				args.channel_count = ast_app_separate_args(
-					args.channel_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.channel_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.channel_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for channel");
-				goto fin;
-			}
-
-			args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
-			if (!args.channel) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.channel_count; ++j) {
-				args.channel[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_remove_channel_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_remove_channel(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Channel not found */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in Stasis application */
-	case 422: /* Channel not in this bridge */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/removeChannel\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/removeChannel\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.channel_parse);
-	ast_free(args.channel);
-	return;
-}
-int ast_ari_bridges_start_moh_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_start_moh_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "mohClass");
-	if (field) {
-		args->moh_class = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_start_moh_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_start_moh_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "mohClass") == 0) {
-			args.moh_class = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_start_moh_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_start_moh(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_stop_moh_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_stop_moh_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_bridges_stop_moh(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_play_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_play_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "media");
-	if (field) {
-		args->media = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "lang");
-	if (field) {
-		args->lang = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "offsetms");
-	if (field) {
-		args->offsetms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "skipms");
-	if (field) {
-		args->skipms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "playbackId");
-	if (field) {
-		args->playback_id = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/play.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_play_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_play_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "media") == 0) {
-			args.media = (i->value);
-		} else
-		if (strcmp(i->name, "lang") == 0) {
-			args.lang = (i->value);
-		} else
-		if (strcmp(i->name, "offsetms") == 0) {
-			args.offsetms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "skipms") == 0) {
-			args.skipms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_play_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_play(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_playback(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/play\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/play\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_play_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_play_with_id_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "media");
-	if (field) {
-		args->media = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "lang");
-	if (field) {
-		args->lang = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "offsetms");
-	if (field) {
-		args->offsetms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "skipms");
-	if (field) {
-		args->skipms = ast_json_integer_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/play/{playbackId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_play_with_id_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_play_with_id_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "media") == 0) {
-			args.media = (i->value);
-		} else
-		if (strcmp(i->name, "lang") == 0) {
-			args.lang = (i->value);
-		} else
-		if (strcmp(i->name, "offsetms") == 0) {
-			args.offsetms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "skipms") == 0) {
-			args.skipms = atoi(i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_play_with_id_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_play_with_id(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_playback(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/play/{playbackId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/play/{playbackId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_bridges_record_parse_body(
-	struct ast_json *body,
-	struct ast_ari_bridges_record_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "name");
-	if (field) {
-		args->name = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "format");
-	if (field) {
-		args->format = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "maxDurationSeconds");
-	if (field) {
-		args->max_duration_seconds = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "maxSilenceSeconds");
-	if (field) {
-		args->max_silence_seconds = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "ifExists");
-	if (field) {
-		args->if_exists = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "beep");
-	if (field) {
-		args->beep = ast_json_is_true(field);
-	}
-	field = ast_json_object_get(body, "terminateOn");
-	if (field) {
-		args->terminate_on = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /bridges/{bridgeId}/record.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_bridges_record_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_bridges_record_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "name") == 0) {
-			args.name = (i->value);
-		} else
-		if (strcmp(i->name, "format") == 0) {
-			args.format = (i->value);
-		} else
-		if (strcmp(i->name, "maxDurationSeconds") == 0) {
-			args.max_duration_seconds = atoi(i->value);
-		} else
-		if (strcmp(i->name, "maxSilenceSeconds") == 0) {
-			args.max_silence_seconds = atoi(i->value);
-		} else
-		if (strcmp(i->name, "ifExists") == 0) {
-			args.if_exists = (i->value);
-		} else
-		if (strcmp(i->name, "beep") == 0) {
-			args.beep = ast_true(i->value);
-		} else
-		if (strcmp(i->name, "terminateOn") == 0) {
-			args.terminate_on = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "bridgeId") == 0) {
-			args.bridge_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_bridges_record_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_bridges_record(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters */
-	case 404: /* Bridge not found */
-	case 409: /* Bridge is not in a Stasis application; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail */
-	case 422: /* The format specified is unknown on this system */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_live_recording(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/record\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/record\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_addChannel = {
-	.path_segment = "addChannel",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_add_channel_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_removeChannel = {
-	.path_segment = "removeChannel",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_remove_channel_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_moh = {
-	.path_segment = "moh",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_start_moh_cb,
-		[AST_HTTP_DELETE] = ast_ari_bridges_stop_moh_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_play_playbackId = {
-	.path_segment = "playbackId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_play_with_id_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_play = {
-	.path_segment = "play",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_play_cb,
-	},
-	.num_children = 1,
-	.children = { &bridges_bridgeId_play_playbackId, }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId_record = {
-	.path_segment = "record",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_record_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges_bridgeId = {
-	.path_segment = "bridgeId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_bridges_create_or_update_with_id_cb,
-		[AST_HTTP_GET] = ast_ari_bridges_get_cb,
-		[AST_HTTP_DELETE] = ast_ari_bridges_destroy_cb,
-	},
-	.num_children = 5,
-	.children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, }
-};
-/*! \brief REST handler for /api-docs/bridges.{format} */
-static struct stasis_rest_handlers bridges = {
-	.path_segment = "bridges",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_bridges_list_cb,
-		[AST_HTTP_POST] = ast_ari_bridges_create_cb,
-	},
-	.num_children = 1,
-	.children = { &bridges_bridgeId, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&bridges);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&bridges);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Bridge resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
deleted file mode 100644
index 17538e5..0000000
--- a/res/res_ari_channels.c
+++ /dev/null
@@ -1,2597 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Channel resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_channels.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /channels.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_channels_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_channel_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_originate_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_originate_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "endpoint");
-	if (field) {
-		args->endpoint = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "extension");
-	if (field) {
-		args->extension = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "context");
-	if (field) {
-		args->context = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "priority");
-	if (field) {
-		args->priority = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "app");
-	if (field) {
-		args->app = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "appArgs");
-	if (field) {
-		args->app_args = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "callerId");
-	if (field) {
-		args->caller_id = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "timeout");
-	if (field) {
-		args->timeout = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "channelId");
-	if (field) {
-		args->channel_id = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "otherChannelId");
-	if (field) {
-		args->other_channel_id = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_originate_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_originate_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "endpoint") == 0) {
-			args.endpoint = (i->value);
-		} else
-		if (strcmp(i->name, "extension") == 0) {
-			args.extension = (i->value);
-		} else
-		if (strcmp(i->name, "context") == 0) {
-			args.context = (i->value);
-		} else
-		if (strcmp(i->name, "priority") == 0) {
-			args.priority = atol(i->value);
-		} else
-		if (strcmp(i->name, "app") == 0) {
-			args.app = (i->value);
-		} else
-		if (strcmp(i->name, "appArgs") == 0) {
-			args.app_args = (i->value);
-		} else
-		if (strcmp(i->name, "callerId") == 0) {
-			args.caller_id = (i->value);
-		} else
-		if (strcmp(i->name, "timeout") == 0) {
-			args.timeout = atoi(i->value);
-		} else
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		if (strcmp(i->name, "otherChannelId") == 0) {
-			args.other_channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	args.variables = ast_json_ref(body);
-	ast_ari_channels_originate(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters for originating a channel. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_channel(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_channel(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_originate_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_originate_with_id_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "endpoint");
-	if (field) {
-		args->endpoint = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "extension");
-	if (field) {
-		args->extension = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "context");
-	if (field) {
-		args->context = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "priority");
-	if (field) {
-		args->priority = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "app");
-	if (field) {
-		args->app = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "appArgs");
-	if (field) {
-		args->app_args = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "callerId");
-	if (field) {
-		args->caller_id = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "timeout");
-	if (field) {
-		args->timeout = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "otherChannelId");
-	if (field) {
-		args->other_channel_id = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_originate_with_id_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_originate_with_id_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "endpoint") == 0) {
-			args.endpoint = (i->value);
-		} else
-		if (strcmp(i->name, "extension") == 0) {
-			args.extension = (i->value);
-		} else
-		if (strcmp(i->name, "context") == 0) {
-			args.context = (i->value);
-		} else
-		if (strcmp(i->name, "priority") == 0) {
-			args.priority = atol(i->value);
-		} else
-		if (strcmp(i->name, "app") == 0) {
-			args.app = (i->value);
-		} else
-		if (strcmp(i->name, "appArgs") == 0) {
-			args.app_args = (i->value);
-		} else
-		if (strcmp(i->name, "callerId") == 0) {
-			args.caller_id = (i->value);
-		} else
-		if (strcmp(i->name, "timeout") == 0) {
-			args.timeout = atoi(i->value);
-		} else
-		if (strcmp(i->name, "otherChannelId") == 0) {
-			args.other_channel_id = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	args.variables = ast_json_ref(body);
-	ast_ari_channels_originate_with_id(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters for originating a channel. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_channel(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_hangup_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_hangup_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "reason");
-	if (field) {
-		args->reason = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_hangup_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_hangup_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "reason") == 0) {
-			args.reason = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_hangup_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_hangup(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid reason for hangup provided */
-	case 404: /* Channel not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_continue_in_dialplan_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_continue_in_dialplan_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "context");
-	if (field) {
-		args->context = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "extension");
-	if (field) {
-		args->extension = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "priority");
-	if (field) {
-		args->priority = ast_json_integer_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/continue.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_continue_in_dialplan_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_continue_in_dialplan_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "context") == 0) {
-			args.context = (i->value);
-		} else
-		if (strcmp(i->name, "extension") == 0) {
-			args.extension = (i->value);
-		} else
-		if (strcmp(i->name, "priority") == 0) {
-			args.priority = atoi(i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_continue_in_dialplan_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_continue_in_dialplan(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/continue\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/continue\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/answer.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_answer_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_answer_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_answer(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/answer\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/answer\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/ring.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_ring_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_ring_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_ring(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/ring.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_ring_stop_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_ring_stop_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_ring_stop(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_send_dtmf_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_send_dtmf_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "dtmf");
-	if (field) {
-		args->dtmf = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "before");
-	if (field) {
-		args->before = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "between");
-	if (field) {
-		args->between = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "duration");
-	if (field) {
-		args->duration = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "after");
-	if (field) {
-		args->after = ast_json_integer_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/dtmf.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_send_dtmf_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_send_dtmf_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "dtmf") == 0) {
-			args.dtmf = (i->value);
-		} else
-		if (strcmp(i->name, "before") == 0) {
-			args.before = atoi(i->value);
-		} else
-		if (strcmp(i->name, "between") == 0) {
-			args.between = atoi(i->value);
-		} else
-		if (strcmp(i->name, "duration") == 0) {
-			args.duration = atoi(i->value);
-		} else
-		if (strcmp(i->name, "after") == 0) {
-			args.after = atoi(i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_send_dtmf_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_send_dtmf(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* DTMF is required */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dtmf\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dtmf\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_mute_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_mute_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "direction");
-	if (field) {
-		args->direction = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/mute.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_mute_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_mute_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "direction") == 0) {
-			args.direction = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_mute_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_mute(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_unmute_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_unmute_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "direction");
-	if (field) {
-		args->direction = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/mute.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_unmute_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_unmute_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "direction") == 0) {
-			args.direction = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_unmute_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_unmute(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/hold.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_hold_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_hold_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_hold(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/hold.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_unhold_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_unhold_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_unhold(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_start_moh_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_start_moh_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "mohClass");
-	if (field) {
-		args->moh_class = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/moh.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_start_moh_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_start_moh_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "mohClass") == 0) {
-			args.moh_class = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_start_moh_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_start_moh(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/moh.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_stop_moh_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_stop_moh_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_stop_moh(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/silence.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_start_silence_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_start_silence_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_start_silence(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/silence.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_stop_silence_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_stop_silence_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_channels_stop_silence(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_play_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_play_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "media");
-	if (field) {
-		args->media = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "lang");
-	if (field) {
-		args->lang = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "offsetms");
-	if (field) {
-		args->offsetms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "skipms");
-	if (field) {
-		args->skipms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "playbackId");
-	if (field) {
-		args->playback_id = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/play.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_play_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_play_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "media") == 0) {
-			args.media = (i->value);
-		} else
-		if (strcmp(i->name, "lang") == 0) {
-			args.lang = (i->value);
-		} else
-		if (strcmp(i->name, "offsetms") == 0) {
-			args.offsetms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "skipms") == 0) {
-			args.skipms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_play_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_play(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_playback(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_play_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_play_with_id_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "media");
-	if (field) {
-		args->media = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "lang");
-	if (field) {
-		args->lang = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "offsetms");
-	if (field) {
-		args->offsetms = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "skipms");
-	if (field) {
-		args->skipms = ast_json_integer_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/play/{playbackId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_play_with_id_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_play_with_id_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "media") == 0) {
-			args.media = (i->value);
-		} else
-		if (strcmp(i->name, "lang") == 0) {
-			args.lang = (i->value);
-		} else
-		if (strcmp(i->name, "offsetms") == 0) {
-			args.offsetms = atoi(i->value);
-		} else
-		if (strcmp(i->name, "skipms") == 0) {
-			args.skipms = atoi(i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_play_with_id_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_play_with_id(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_playback(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play/{playbackId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play/{playbackId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_record_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_record_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "name");
-	if (field) {
-		args->name = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "format");
-	if (field) {
-		args->format = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "maxDurationSeconds");
-	if (field) {
-		args->max_duration_seconds = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "maxSilenceSeconds");
-	if (field) {
-		args->max_silence_seconds = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "ifExists");
-	if (field) {
-		args->if_exists = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "beep");
-	if (field) {
-		args->beep = ast_json_is_true(field);
-	}
-	field = ast_json_object_get(body, "terminateOn");
-	if (field) {
-		args->terminate_on = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/record.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_record_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_record_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "name") == 0) {
-			args.name = (i->value);
-		} else
-		if (strcmp(i->name, "format") == 0) {
-			args.format = (i->value);
-		} else
-		if (strcmp(i->name, "maxDurationSeconds") == 0) {
-			args.max_duration_seconds = atoi(i->value);
-		} else
-		if (strcmp(i->name, "maxSilenceSeconds") == 0) {
-			args.max_silence_seconds = atoi(i->value);
-		} else
-		if (strcmp(i->name, "ifExists") == 0) {
-			args.if_exists = (i->value);
-		} else
-		if (strcmp(i->name, "beep") == 0) {
-			args.beep = ast_true(i->value);
-		} else
-		if (strcmp(i->name, "terminateOn") == 0) {
-			args.terminate_on = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_record_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_record(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters */
-	case 404: /* Channel not found */
-	case 409: /* Channel is not in a Stasis application; the channel is currently bridged with other hcannels; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail */
-	case 422: /* The format specified is unknown on this system */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_live_recording(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/record\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/record\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_get_channel_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_get_channel_var_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "variable");
-	if (field) {
-		args->variable = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/variable.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_get_channel_var_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_get_channel_var_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "variable") == 0) {
-			args.variable = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_get_channel_var_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_get_channel_var(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing variable parameter. */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_variable(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_set_channel_var_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_set_channel_var_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "variable");
-	if (field) {
-		args->variable = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "value");
-	if (field) {
-		args->value = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/variable.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_set_channel_var_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_set_channel_var_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "variable") == 0) {
-			args.variable = (i->value);
-		} else
-		if (strcmp(i->name, "value") == 0) {
-			args.value = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_set_channel_var_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_set_channel_var(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Missing variable parameter. */
-	case 404: /* Channel not found */
-	case 409: /* Channel not in a Stasis application */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_snoop_channel_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_snoop_channel_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "spy");
-	if (field) {
-		args->spy = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "whisper");
-	if (field) {
-		args->whisper = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "app");
-	if (field) {
-		args->app = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "appArgs");
-	if (field) {
-		args->app_args = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "snoopId");
-	if (field) {
-		args->snoop_id = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/snoop.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_snoop_channel_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_snoop_channel_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "spy") == 0) {
-			args.spy = (i->value);
-		} else
-		if (strcmp(i->name, "whisper") == 0) {
-			args.whisper = (i->value);
-		} else
-		if (strcmp(i->name, "app") == 0) {
-			args.app = (i->value);
-		} else
-		if (strcmp(i->name, "appArgs") == 0) {
-			args.app_args = (i->value);
-		} else
-		if (strcmp(i->name, "snoopId") == 0) {
-			args.snoop_id = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_snoop_channel_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_snoop_channel(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters */
-	case 404: /* Channel not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_channel(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_channels_snoop_channel_with_id_parse_body(
-	struct ast_json *body,
-	struct ast_ari_channels_snoop_channel_with_id_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "spy");
-	if (field) {
-		args->spy = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "whisper");
-	if (field) {
-		args->whisper = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "app");
-	if (field) {
-		args->app = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "appArgs");
-	if (field) {
-		args->app_args = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /channels/{channelId}/snoop/{snoopId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_channels_snoop_channel_with_id_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_channels_snoop_channel_with_id_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "spy") == 0) {
-			args.spy = (i->value);
-		} else
-		if (strcmp(i->name, "whisper") == 0) {
-			args.whisper = (i->value);
-		} else
-		if (strcmp(i->name, "app") == 0) {
-			args.app = (i->value);
-		} else
-		if (strcmp(i->name, "appArgs") == 0) {
-			args.app_args = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "channelId") == 0) {
-			args.channel_id = (i->value);
-		} else
-		if (strcmp(i->name, "snoopId") == 0) {
-			args.snoop_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_channels_snoop_channel_with_id(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters */
-	case 404: /* Channel not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_channel(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop/{snoopId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop/{snoopId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_continue = {
-	.path_segment = "continue",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_continue_in_dialplan_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_answer = {
-	.path_segment = "answer",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_answer_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_ring = {
-	.path_segment = "ring",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_ring_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_ring_stop_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_dtmf = {
-	.path_segment = "dtmf",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_send_dtmf_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_mute = {
-	.path_segment = "mute",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_mute_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_unmute_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_hold = {
-	.path_segment = "hold",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_hold_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_unhold_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_moh = {
-	.path_segment = "moh",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_start_moh_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_stop_moh_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_silence = {
-	.path_segment = "silence",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_start_silence_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_stop_silence_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_play_playbackId = {
-	.path_segment = "playbackId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_play_with_id_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_play = {
-	.path_segment = "play",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_play_cb,
-	},
-	.num_children = 1,
-	.children = { &channels_channelId_play_playbackId, }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_record = {
-	.path_segment = "record",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_record_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_variable = {
-	.path_segment = "variable",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_channels_get_channel_var_cb,
-		[AST_HTTP_POST] = ast_ari_channels_set_channel_var_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_snoop_snoopId = {
-	.path_segment = "snoopId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_snoop_channel_with_id_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId_snoop = {
-	.path_segment = "snoop",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_channels_snoop_channel_cb,
-	},
-	.num_children = 1,
-	.children = { &channels_channelId_snoop_snoopId, }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels_channelId = {
-	.path_segment = "channelId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_channels_get_cb,
-		[AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb,
-		[AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
-	},
-	.num_children = 12,
-	.children = { &channels_channelId_continue,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop, }
-};
-/*! \brief REST handler for /api-docs/channels.{format} */
-static struct stasis_rest_handlers channels = {
-	.path_segment = "channels",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_channels_list_cb,
-		[AST_HTTP_POST] = ast_ari_channels_originate_cb,
-	},
-	.num_children = 1,
-	.children = { &channels_channelId, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&channels);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&channels);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Channel resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c
deleted file mode 100644
index 1447525..0000000
--- a/res/res_ari_device_states.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Device state resources
- *
- * \author Kevin Harwell <kharwell at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_device_states.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /deviceStates.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_device_states_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_device_states_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_device_states_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_device_state_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /deviceStates\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /deviceStates\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /deviceStates/{deviceName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_device_states_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_device_states_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "deviceName") == 0) {
-			args.device_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_device_states_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_device_state(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /deviceStates/{deviceName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /deviceStates/{deviceName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_device_states_update_parse_body(
-	struct ast_json *body,
-	struct ast_ari_device_states_update_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "deviceState");
-	if (field) {
-		args->device_state = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /deviceStates/{deviceName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_device_states_update_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_device_states_update_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "deviceState") == 0) {
-			args.device_state = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "deviceName") == 0) {
-			args.device_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_device_states_update_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_device_states_update(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Device name is missing */
-	case 409: /* Uncontrolled device specified */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /deviceStates/{deviceName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /deviceStates/{deviceName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /deviceStates/{deviceName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_device_states_delete_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_device_states_delete_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "deviceName") == 0) {
-			args.device_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_device_states_delete(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Device name is missing */
-	case 409: /* Uncontrolled device specified */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /deviceStates/{deviceName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /deviceStates/{deviceName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/deviceStates.{format} */
-static struct stasis_rest_handlers deviceStates_deviceName = {
-	.path_segment = "deviceName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_device_states_get_cb,
-		[AST_HTTP_PUT] = ast_ari_device_states_update_cb,
-		[AST_HTTP_DELETE] = ast_ari_device_states_delete_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/deviceStates.{format} */
-static struct stasis_rest_handlers deviceStates = {
-	.path_segment = "deviceStates",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_device_states_list_cb,
-	},
-	.num_children = 1,
-	.children = { &deviceStates_deviceName, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&deviceStates);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&deviceStates);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Device state resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c
deleted file mode 100644
index ed3c14d..0000000
--- a/res/res_ari_endpoints.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Endpoint resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420098 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_endpoints.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /endpoints.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_endpoints_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_endpoints_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_endpoints_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_endpoint_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /endpoints\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /endpoints\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_endpoints_send_message_parse_body(
-	struct ast_json *body,
-	struct ast_ari_endpoints_send_message_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "to");
-	if (field) {
-		args->to = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "from");
-	if (field) {
-		args->from = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "body");
-	if (field) {
-		args->body = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /endpoints/sendMessage.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_endpoints_send_message_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_endpoints_send_message_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "to") == 0) {
-			args.to = (i->value);
-		} else
-		if (strcmp(i->name, "from") == 0) {
-			args.from = (i->value);
-		} else
-		if (strcmp(i->name, "body") == 0) {
-			args.body = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	args.variables = ast_json_ref(body);
-	ast_ari_endpoints_send_message(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Endpoint not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/sendMessage\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /endpoints/sendMessage\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /endpoints/{tech}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_endpoints_list_by_tech_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_endpoints_list_by_tech_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "tech") == 0) {
-			args.tech = (i->value);
-		} else
-		{}
-	}
-	ast_ari_endpoints_list_by_tech(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Endpoints not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_endpoint_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /endpoints/{tech}/{resource}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_endpoints_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_endpoints_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "tech") == 0) {
-			args.tech = (i->value);
-		} else
-		if (strcmp(i->name, "resource") == 0) {
-			args.resource = (i->value);
-		} else
-		{}
-	}
-	ast_ari_endpoints_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters for sending a message. */
-	case 404: /* Endpoints not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_endpoint(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}/{resource}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}/{resource}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_endpoints_send_message_to_endpoint_parse_body(
-	struct ast_json *body,
-	struct ast_ari_endpoints_send_message_to_endpoint_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "from");
-	if (field) {
-		args->from = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "body");
-	if (field) {
-		args->body = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /endpoints/{tech}/{resource}/sendMessage.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_endpoints_send_message_to_endpoint_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_endpoints_send_message_to_endpoint_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "from") == 0) {
-			args.from = (i->value);
-		} else
-		if (strcmp(i->name, "body") == 0) {
-			args.body = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "tech") == 0) {
-			args.tech = (i->value);
-		} else
-		if (strcmp(i->name, "resource") == 0) {
-			args.resource = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	args.variables = ast_json_ref(body);
-	ast_ari_endpoints_send_message_to_endpoint(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* Invalid parameters for sending a message. */
-	case 404: /* Endpoint not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /endpoints/{tech}/{resource}/sendMessage\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /endpoints/{tech}/{resource}/sendMessage\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/endpoints.{format} */
-static struct stasis_rest_handlers endpoints_sendMessage = {
-	.path_segment = "sendMessage",
-	.callbacks = {
-		[AST_HTTP_PUT] = ast_ari_endpoints_send_message_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/endpoints.{format} */
-static struct stasis_rest_handlers endpoints_tech_resource_sendMessage = {
-	.path_segment = "sendMessage",
-	.callbacks = {
-		[AST_HTTP_PUT] = ast_ari_endpoints_send_message_to_endpoint_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/endpoints.{format} */
-static struct stasis_rest_handlers endpoints_tech_resource = {
-	.path_segment = "resource",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_endpoints_get_cb,
-	},
-	.num_children = 1,
-	.children = { &endpoints_tech_resource_sendMessage, }
-};
-/*! \brief REST handler for /api-docs/endpoints.{format} */
-static struct stasis_rest_handlers endpoints_tech = {
-	.path_segment = "tech",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_endpoints_list_by_tech_cb,
-	},
-	.num_children = 1,
-	.children = { &endpoints_tech_resource, }
-};
-/*! \brief REST handler for /api-docs/endpoints.{format} */
-static struct stasis_rest_handlers endpoints = {
-	.path_segment = "endpoints",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_endpoints_list_cb,
-	},
-	.num_children = 2,
-	.children = { &endpoints_sendMessage,&endpoints_tech, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&endpoints);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&endpoints);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Endpoint resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_events.c b/res/res_ari_events.c
deleted file mode 100644
index c1b3434..0000000
--- a/res/res_ari_events.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief WebSocket resource
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_events.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-#include "asterisk/http_websocket.h"
-
-#define MAX_VALS 128
-
-static void ast_ari_events_event_websocket_ws_cb(struct ast_websocket *ws_session,
-	struct ast_variable *get_params, struct ast_variable *headers)
-{
-	struct ast_ari_events_event_websocket_args args = {};
-	RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
-	struct ast_variable *i;
-	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
-	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
-
-	response = ast_calloc(1, sizeof(*response));
-	if (!response) {
-		ast_log(LOG_ERROR, "Failed to create response.\n");
-		goto fin;
-	}
-
-#if defined(AST_DEVMODE)
-	session = ast_ari_websocket_session_create(ws_session,
-		ast_ari_validate_message_fn());
-#else
-	session = ast_ari_websocket_session_create(ws_session, NULL);
-#endif
-	if (!session) {
-		ast_log(LOG_ERROR, "Failed to create ARI session\n");
-		goto fin;
-	}
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "app") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.app_parse = ast_strdup(i->value);
-			if (!args.app_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.app_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.app_count = 1;
-				vals[0] = args.app_parse;
-			} else {
-				args.app_count = ast_app_separate_args(
-					args.app_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.app_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.app_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for app");
-				goto fin;
-			}
-
-			args.app = ast_malloc(sizeof(*args.app) * args.app_count);
-			if (!args.app) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.app_count; ++j) {
-				args.app[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-
-	ast_ari_websocket_events_event_websocket(session, headers, &args);
-
-fin: __attribute__((unused))
-	if (response && response->response_code != 0) {
-		/* Param parsing failure */
-		/* TODO - ideally, this would return the error code to the
-		 * HTTP client; but we've already done the WebSocket
-		 * negotiation. Param parsing should happen earlier, but we
-		 * need a way to pass it through the WebSocket code to the
-		 * callback */
-		RAII_VAR(char *, msg, NULL, ast_json_free);
-		if (response->message) {
-			msg = ast_json_dump_string(response->message);
-		} else {
-			ast_log(LOG_ERROR, "Missing response message\n");
-		}
-		if (msg) {
-			ast_websocket_write(ws_session,
-				AST_WEBSOCKET_OPCODE_TEXT, msg,	strlen(msg));
-		}
-	}
-	ast_free(args.app_parse);
-	ast_free(args.app);
-}
-int ast_ari_events_user_event_parse_body(
-	struct ast_json *body,
-	struct ast_ari_events_user_event_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "application");
-	if (field) {
-		args->application = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "source");
-	if (field) {
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->source);
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->source_count = ast_json_array_size(field);
-			args->source = ast_malloc(sizeof(*args->source) * args->source_count);
-
-			if (!args->source) {
-				return -1;
-			}
-
-			for (i = 0; i < args->source_count; ++i) {
-				args->source[i] = ast_json_string_get(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->source_count = 1;
-			args->source = ast_malloc(sizeof(*args->source) * args->source_count);
-			if (!args->source) {
-				return -1;
-			}
-			args->source[0] = ast_json_string_get(field);
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /events/user/{eventName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_events_user_event_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_events_user_event_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "application") == 0) {
-			args.application = (i->value);
-		} else
-		if (strcmp(i->name, "source") == 0) {
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.source_parse = ast_strdup(i->value);
-			if (!args.source_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.source_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.source_count = 1;
-				vals[0] = args.source_parse;
-			} else {
-				args.source_count = ast_app_separate_args(
-					args.source_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.source_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.source_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for source");
-				goto fin;
-			}
-
-			args.source = ast_malloc(sizeof(*args.source) * args.source_count);
-			if (!args.source) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.source_count; ++j) {
-				args.source[j] = (vals[j]);
-			}
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "eventName") == 0) {
-			args.event_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	args.variables = ast_json_ref(body);
-	ast_ari_events_user_event(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Application does not exist. */
-	case 422: /* Event source not found. */
-	case 400: /* Invalid even tsource URI or userevent data. */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /events/user/{eventName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /events/user/{eventName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	ast_free(args.source_parse);
-	ast_free(args.source);
-	return;
-}
-
-/*! \brief REST handler for /api-docs/events.{format} */
-static struct stasis_rest_handlers events_user_eventName = {
-	.path_segment = "eventName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_events_user_event_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/events.{format} */
-static struct stasis_rest_handlers events_user = {
-	.path_segment = "user",
-	.callbacks = {
-	},
-	.num_children = 1,
-	.children = { &events_user_eventName, }
-};
-/*! \brief REST handler for /api-docs/events.{format} */
-static struct stasis_rest_handlers events = {
-	.path_segment = "events",
-	.callbacks = {
-	},
-	.num_children = 1,
-	.children = { &events_user, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	events.ws_server = ast_websocket_server_create();
-	if (!events.ws_server) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	res |= ast_websocket_server_add_protocol(events.ws_server,
-		"ari", ast_ari_events_event_websocket_ws_cb);
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&events);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&events);
-	ao2_cleanup(events.ws_server);
-	events.ws_server = NULL;
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - WebSocket resource",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c
deleted file mode 100644
index 590088d..0000000
--- a/res/res_ari_mailboxes.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Mailboxes resources
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_mailboxes.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /mailboxes.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_mailboxes_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_mailboxes_list_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_mailboxes_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_mailbox_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /mailboxes\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /mailboxes\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /mailboxes/{mailboxName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_mailboxes_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_mailboxes_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "mailboxName") == 0) {
-			args.mailbox_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_mailboxes_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Mailbox not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_mailbox(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /mailboxes/{mailboxName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /mailboxes/{mailboxName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_mailboxes_update_parse_body(
-	struct ast_json *body,
-	struct ast_ari_mailboxes_update_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "oldMessages");
-	if (field) {
-		args->old_messages = ast_json_integer_get(field);
-	}
-	field = ast_json_object_get(body, "newMessages");
-	if (field) {
-		args->new_messages = ast_json_integer_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /mailboxes/{mailboxName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_mailboxes_update_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_mailboxes_update_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "oldMessages") == 0) {
-			args.old_messages = atoi(i->value);
-		} else
-		if (strcmp(i->name, "newMessages") == 0) {
-			args.new_messages = atoi(i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "mailboxName") == 0) {
-			args.mailbox_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_mailboxes_update_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_mailboxes_update(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Mailbox not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /mailboxes/{mailboxName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /mailboxes/{mailboxName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /mailboxes/{mailboxName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_mailboxes_delete_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_mailboxes_delete_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "mailboxName") == 0) {
-			args.mailbox_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_mailboxes_delete(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Mailbox not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /mailboxes/{mailboxName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /mailboxes/{mailboxName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/mailboxes.{format} */
-static struct stasis_rest_handlers mailboxes_mailboxName = {
-	.path_segment = "mailboxName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_mailboxes_get_cb,
-		[AST_HTTP_PUT] = ast_ari_mailboxes_update_cb,
-		[AST_HTTP_DELETE] = ast_ari_mailboxes_delete_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/mailboxes.{format} */
-static struct stasis_rest_handlers mailboxes = {
-	.path_segment = "mailboxes",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_mailboxes_list_cb,
-	},
-	.num_children = 1,
-	.children = { &mailboxes_mailboxName, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&mailboxes);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&mailboxes);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Mailboxes resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_model.c b/res/res_ari_model.c
deleted file mode 100644
index ff4fe5d..0000000
--- a/res/res_ari_model.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation Swagger validators.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "ari/ari_model_validators.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/utils.h"
-
-#include <regex.h>
-
-/* Regex to match date strings */
-static regex_t date_regex;
-
-/* Regex for YYYY-MM-DD */
-#define REGEX_YMD "[0-9]{4}-[01][0-9]-[0-3][0-9]"
-
-/* Regex for hh:mm(:ss(.s)); seconds and subseconds optional
- * Handles the probably impossible case of a leap second, too */
-#define REGEX_HMS "[0-2][0-9]:[0-5][0-9](:[0-6][0-9](.[0-9]+)?)?"
-
-/* Regex for timezone: (+|-)hh(:mm), with optional colon. */
-#define REGEX_TZ "(Z|[-+][0-2][0-9](:?[0-5][0-9])?)"
-
-/* REGEX for ISO 8601, the time specifier optional */
-#define ISO8601_PATTERN "^" REGEX_YMD "(T" REGEX_HMS REGEX_TZ ")?$"
-
-static int check_type(struct ast_json *json, enum ast_json_type expected)
-{
-	enum ast_json_type actual;
-
-	if (!json) {
-		ast_log(LOG_ERROR, "Expected type %s, was NULL\n",
-			ast_json_typename(expected));
-		return 0;
-	}
-
-	actual = ast_json_typeof(json);
-	if (expected != actual) {
-		ast_log(LOG_ERROR, "Expected type %s, was %s\n",
-			ast_json_typename(expected), ast_json_typename(actual));
-		return 0;
-	}
-	return 1;
-}
-
-static int check_range(intmax_t minval, intmax_t maxval, struct ast_json *json)
-{
-	intmax_t v;
-
-	if (!check_type(json, AST_JSON_INTEGER)) {
-		return 0;
-	}
-
-	v = ast_json_integer_get(json);
-
-	if (v < minval || maxval < v) {
-		ast_log(LOG_ERROR, "Value out of range. Expected %jd <= %jd <= %jd\n", minval, v, maxval);
-		return 0;
-	}
-	return 1;
-}
-
-int ast_ari_validate_void(struct ast_json *json)
-{
-	return check_type(json, AST_JSON_NULL);
-}
-
-int ast_ari_validate_object(struct ast_json *json)
-{
-	return check_type(json, AST_JSON_OBJECT);
-}
-
-int ast_ari_validate_byte(struct ast_json *json)
-{
-	/* Java bytes are signed, which accounts for great fun for all */
-	return check_range(-128, 255, json);
-}
-
-int ast_ari_validate_boolean(struct ast_json *json)
-{
-	enum ast_json_type actual = ast_json_typeof(json);
-	switch (actual) {
-	case AST_JSON_TRUE:
-	case AST_JSON_FALSE:
-		return 1;
-	default:
-		ast_log(LOG_ERROR, "Expected type boolean, was %s\n",
-			ast_json_typename(actual));
-		return 0;
-	}
-}
-
-int ast_ari_validate_int(struct ast_json *json)
-{
-	/* Swagger int's are 32-bit */
-	return check_range(-2147483648LL, 2147483647LL, json);
-}
-
-int ast_ari_validate_long(struct ast_json *json)
-{
-	/* All integral values are valid longs. No need for range check. */
-	return check_type(json, AST_JSON_INTEGER);
-}
-
-int ast_ari_validate_float(struct ast_json *json)
-{
-	return check_type(json, AST_JSON_REAL);
-}
-
-int ast_ari_validate_double(struct ast_json *json)
-{
-	return check_type(json, AST_JSON_REAL);
-}
-
-int ast_ari_validate_string(struct ast_json *json)
-{
-	return check_type(json, AST_JSON_STRING);
-}
-
-int ast_ari_validate_date(struct ast_json *json)
-{
-	/* Dates are ISO-8601 strings */
-	const char *str;
-	if (!check_type(json, AST_JSON_STRING)) {
-		return 0;
-	}
-	str = ast_json_string_get(json);
-	ast_assert(str != NULL);
-	if (regexec(&date_regex, str, 0, NULL, 0) != 0) {
-		ast_log(LOG_ERROR, "Date field is malformed: '%s'\n", str);
-		return 0;
-	}
-	return 1;
-}
-
-int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *))
-{
-	int res = 1;
-	size_t i;
-
-	if (!check_type(json, AST_JSON_ARRAY)) {
-		return 0;
-	}
-
-	for (i = 0; i < ast_json_array_size(json); ++i) {
-		int member_res;
-		member_res = fn(ast_json_array_get(json, i));
-		if (!member_res) {
-			ast_log(LOG_ERROR,
-				"Array member %zu failed validation\n", i);
-			res = 0;
-		}
-	}
-
-	return res;
-}
-
-static int load_module(void)
-{
-	int res;
-	res = regcomp(&date_regex, ISO8601_PATTERN,
-		REG_EXTENDED | REG_ICASE | REG_NOSUB);
-
-	if (res != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	regfree(&date_regex);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER | AST_MODFLAG_GLOBAL_SYMBOLS, "ARI Model validators",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_APP_DEPEND,
-        );
diff --git a/res/res_ari_model.exports.in b/res/res_ari_model.exports.in
deleted file mode 100644
index f143ef3..0000000
--- a/res/res_ari_model.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_ari_*;
-	local:
-		*;
-};
diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c
deleted file mode 100644
index 94662f2..0000000
--- a/res/res_ari_playbacks.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Playback control resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_playbacks.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /playbacks/{playbackId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_playbacks_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_playbacks_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_playbacks_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* The playback cannot be found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_playback(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /playbacks/{playbackId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /playbacks/{playbackId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /playbacks/{playbackId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_playbacks_stop_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_playbacks_stop_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_playbacks_stop(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* The playback cannot be found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /playbacks/{playbackId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /playbacks/{playbackId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_playbacks_control_parse_body(
-	struct ast_json *body,
-	struct ast_ari_playbacks_control_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "operation");
-	if (field) {
-		args->operation = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /playbacks/{playbackId}/control.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_playbacks_control_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_playbacks_control_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "operation") == 0) {
-			args.operation = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "playbackId") == 0) {
-			args.playback_id = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_playbacks_control_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_playbacks_control(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 400: /* The provided operation parameter was invalid */
-	case 404: /* The playback cannot be found */
-	case 409: /* The operation cannot be performed in the playback's current state */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /playbacks/{playbackId}/control\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /playbacks/{playbackId}/control\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/playbacks.{format} */
-static struct stasis_rest_handlers playbacks_playbackId_control = {
-	.path_segment = "control",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_playbacks_control_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/playbacks.{format} */
-static struct stasis_rest_handlers playbacks_playbackId = {
-	.path_segment = "playbackId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_playbacks_get_cb,
-		[AST_HTTP_DELETE] = ast_ari_playbacks_stop_cb,
-	},
-	.num_children = 1,
-	.children = { &playbacks_playbackId_control, }
-};
-/*! \brief REST handler for /api-docs/playbacks.{format} */
-static struct stasis_rest_handlers playbacks = {
-	.path_segment = "playbacks",
-	.callbacks = {
-	},
-	.num_children = 1,
-	.children = { &playbacks_playbackId, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&playbacks);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&playbacks);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Playback control resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
deleted file mode 100644
index a94d31a..0000000
--- a/res/res_ari_recordings.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Recording resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_recordings.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-/*!
- * \brief Parameter parsing callback for /recordings/stored.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_list_stored_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_list_stored_args args = {};
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	ast_ari_recordings_list_stored(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_stored_recording_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/stored\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_get_stored_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_get_stored_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_get_stored(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_stored_recording(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_delete_stored_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_delete_stored_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_delete_stored(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-int ast_ari_recordings_copy_stored_parse_body(
-	struct ast_json *body,
-	struct ast_ari_recordings_copy_stored_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "destinationRecordingName");
-	if (field) {
-		args->destination_recording_name = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /recordings/stored/{recordingName}/copy.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_copy_stored_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_copy_stored_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "destinationRecordingName") == 0) {
-			args.destination_recording_name = (i->value);
-		} else
-		{}
-	}
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_recordings_copy_stored_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_recordings_copy_stored(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-	case 409: /* A recording with the same name already exists on the system */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_stored_recording(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}/copy\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}/copy\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_get_live_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_get_live_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_get_live(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_live_recording(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_cancel_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_cancel_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_cancel(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}/stop.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_stop_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_stop_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_stop(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/stop\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/stop\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}/pause.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_pause_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_pause_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_pause(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-	case 409: /* Recording not in session */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/pause\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/pause\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}/pause.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_unpause_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_unpause_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_unpause(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-	case 409: /* Recording not in session */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/pause\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/pause\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}/mute.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_mute_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_mute_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_mute(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-	case 409: /* Recording not in session */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/mute\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/mute\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingName}/mute.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_recordings_unmute_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_recordings_unmute_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "recordingName") == 0) {
-			args.recording_name = (i->value);
-		} else
-		{}
-	}
-	ast_ari_recordings_unmute(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-	case 404: /* Recording not found */
-	case 409: /* Recording not in session */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_void(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/mute\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/mute\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_stored_recordingName_copy = {
-	.path_segment = "copy",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_recordings_copy_stored_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_stored_recordingName = {
-	.path_segment = "recordingName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_recordings_get_stored_cb,
-		[AST_HTTP_DELETE] = ast_ari_recordings_delete_stored_cb,
-	},
-	.num_children = 1,
-	.children = { &recordings_stored_recordingName_copy, }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_stored = {
-	.path_segment = "stored",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_recordings_list_stored_cb,
-	},
-	.num_children = 1,
-	.children = { &recordings_stored_recordingName, }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingName_stop = {
-	.path_segment = "stop",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_recordings_stop_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingName_pause = {
-	.path_segment = "pause",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_recordings_pause_cb,
-		[AST_HTTP_DELETE] = ast_ari_recordings_unpause_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingName_mute = {
-	.path_segment = "mute",
-	.callbacks = {
-		[AST_HTTP_POST] = ast_ari_recordings_mute_cb,
-		[AST_HTTP_DELETE] = ast_ari_recordings_unmute_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingName = {
-	.path_segment = "recordingName",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_recordings_get_live_cb,
-		[AST_HTTP_DELETE] = ast_ari_recordings_cancel_cb,
-	},
-	.num_children = 3,
-	.children = { &recordings_live_recordingName_stop,&recordings_live_recordingName_pause,&recordings_live_recordingName_mute, }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live = {
-	.path_segment = "live",
-	.callbacks = {
-	},
-	.num_children = 1,
-	.children = { &recordings_live_recordingName, }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings = {
-	.path_segment = "recordings",
-	.callbacks = {
-	},
-	.num_children = 2,
-	.children = { &recordings_stored,&recordings_live, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&recordings);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&recordings);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Recording resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c
deleted file mode 100644
index e27286a..0000000
--- a/res/res_ari_sounds.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief Sound resources
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_sounds.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-
-#define MAX_VALS 128
-
-int ast_ari_sounds_list_parse_body(
-	struct ast_json *body,
-	struct ast_ari_sounds_list_args *args)
-{
-	struct ast_json *field;
-	/* Parse query parameters out of it */
-	field = ast_json_object_get(body, "lang");
-	if (field) {
-		args->lang = ast_json_string_get(field);
-	}
-	field = ast_json_object_get(body, "format");
-	if (field) {
-		args->format = ast_json_string_get(field);
-	}
-	return 0;
-}
-
-/*!
- * \brief Parameter parsing callback for /sounds.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_sounds_list_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_sounds_list_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "lang") == 0) {
-			args.lang = (i->value);
-		} else
-		if (strcmp(i->name, "format") == 0) {
-			args.format = (i->value);
-		} else
-		{}
-	}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-	if (ast_ari_sounds_list_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-	ast_ari_sounds_list(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_sound_fn());
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /sounds\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /sounds\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-/*!
- * \brief Parameter parsing callback for /sounds/{soundId}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_sounds_get_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_sounds_get_args args = {};
-	struct ast_variable *i;
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-	for (i = path_vars; i; i = i->next) {
-		if (strcmp(i->name, "soundId") == 0) {
-			args.sound_id = (i->value);
-		} else
-		{}
-	}
-	ast_ari_sounds_get(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-			is_valid = ast_ari_validate_sound(
-				response->message);
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for /sounds/{soundId}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for /sounds/{soundId}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-	return;
-}
-
-/*! \brief REST handler for /api-docs/sounds.{format} */
-static struct stasis_rest_handlers sounds_soundId = {
-	.path_segment = "soundId",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_sounds_get_cb,
-	},
-	.num_children = 0,
-	.children = {  }
-};
-/*! \brief REST handler for /api-docs/sounds.{format} */
-static struct stasis_rest_handlers sounds = {
-	.path_segment = "sounds",
-	.callbacks = {
-		[AST_HTTP_GET] = ast_ari_sounds_list_cb,
-	},
-	.num_children = 1,
-	.children = { &sounds_soundId, }
-};
-
-static int load_module(void)
-{
-	int res = 0;
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&sounds);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&sounds);
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Sound resources",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
diff --git a/res/res_calendar.c b/res/res_calendar.c
index 834b655..e418425 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -23,25 +23,15 @@
  * \todo Support writing attendees
  */
 
-/*! \li \ref res_calendar.c uses the configuration file \ref calendar.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page calendar.conf calendar.conf
- * \verbinclude calendar.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428246 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/_private.h"
-#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/utils.h"
 #include "asterisk/astobj2.h"
@@ -55,7 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428246 $")
 #include "asterisk/cli.h"
 #include "asterisk/pbx.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<function name="CALENDAR_BUSY" language="en_US">
@@ -538,11 +527,6 @@ int ast_calendar_register(struct ast_calendar_tech *tech)
 {
 	struct ast_calendar_tech *iter;
 
-	if (!calendar_config) {
-		ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
-		return -1;
-	}
-
 	AST_LIST_LOCK(&techs);
 	AST_LIST_TRAVERSE(&techs, iter, list) {
 		if(!strcasecmp(tech->type, iter->type)) {
@@ -736,7 +720,6 @@ static void *do_notify(void *data)
 	struct ast_variable *itervar;
 	char *tech, *dest;
 	char buf[8];
-	struct ast_format_cap *caps;
 
 	tech = ast_strdupa(event->owner->notify_channel);
 
@@ -753,7 +736,7 @@ static void *do_notify(void *data)
 		goto notify_cleanup;
 	}
 
-	if (ast_dial_append(dial, tech, dest, NULL) < 0) {
+	if (ast_dial_append(dial, tech, dest) < 0) {
 		ast_log(LOG_ERROR, "Could not append channel\n");
 		goto notify_cleanup;
 	}
@@ -761,27 +744,18 @@ static void *do_notify(void *data)
 	ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
 	generate_random_string(buf, sizeof(buf));
 
-	if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, NULL, NULL, 0, "Calendar/%s-%s", event->owner->name, buf))) {
+	if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
 		ast_log(LOG_ERROR, "Could not allocate notification channel\n");
 		goto notify_cleanup;
 	}
 
 	ast_channel_tech_set(chan, &null_tech);
-	ast_channel_set_writeformat(chan, ast_format_slin);
-	ast_channel_set_readformat(chan, ast_format_slin);
-	ast_channel_set_rawwriteformat(chan, ast_format_slin);
-	ast_channel_set_rawreadformat(chan, ast_format_slin);
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_log(LOG_ERROR, "Could not allocate capabilities, notification not being sent!\n");
-		goto notify_cleanup;
-	}
-	ast_format_cap_append(caps, ast_format_slin, 0);
-	ast_channel_nativeformats_set(chan, caps);
-	ao2_ref(caps, -1);
-
-	ast_channel_unlock(chan);
+	ast_format_set(ast_channel_writeformat(chan), AST_FORMAT_SLINEAR, 0);
+	ast_format_set(ast_channel_readformat(chan), AST_FORMAT_SLINEAR, 0);
+	ast_format_set(ast_channel_rawwriteformat(chan), AST_FORMAT_SLINEAR, 0);
+	ast_format_set(ast_channel_rawreadformat(chan), AST_FORMAT_SLINEAR, 0);
+	/* clear native formats and set to slinear. write format is signlear so just use that to set it */
+	ast_format_cap_set(ast_channel_nativeformats(chan), ast_channel_writeformat(chan));
 
 	if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
 		ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
@@ -1106,8 +1080,8 @@ static struct ast_custom_function calendar_busy_function = {
 static int add_event_to_list(struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
 {
 	struct evententry *entry, *iter;
-	int event_startdiff = abs(start - event->start);
-	int event_enddiff = abs(end - event->end);
+	long event_startdiff = labs(start - event->start);
+	long event_enddiff = labs(end - event->end);
 	int i = 0;
 
 	if (!(entry = ast_calloc(1, sizeof(*entry)))) {
@@ -1120,16 +1094,16 @@ static int add_event_to_list(struct eventlist *events, struct ast_calendar_event
 
 	if (start == end) {
 		AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
-			int startdiff = abs(iter->event->start - start);
+			long startdiff = labs(iter->event->start - start);
 
-			ast_debug(10, "Comparing %s with startdiff %d to %s with startdiff %d\n", event->summary, event_startdiff, iter->event->summary, startdiff);
+			ast_debug(10, "Comparing %s with startdiff %ld to %s with startdiff %ld\n", event->summary, event_startdiff, iter->event->summary, startdiff);
 			++i;
 			if (startdiff > event_startdiff) {
 				AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
 				return i;
 			}
 			if (startdiff == event_startdiff) {
-				int enddiff = abs(iter->event->end - end);
+				long enddiff = labs(iter->event->end - end);
 
 				if (enddiff > event_enddiff) {
 					AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
@@ -1866,16 +1840,6 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
@@ -1913,7 +1877,6 @@ static int load_module(void)
 	return AST_MODULE_LOAD_SUCCESS;
 }
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Calendar integration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c
index 59fb03c..39c76f1 100644
--- a/res/res_calendar_caldav.c
+++ b/res/res_calendar_caldav.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libical/ical.h>
 #include <ne_session.h>
@@ -41,7 +41,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include <libxml/parser.h>
 
 #include "asterisk/module.h"
-#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/lock.h"
 #include "asterisk/config.h"
@@ -725,7 +724,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk CalDAV Calendar Integration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c
index 3d7f862..00e6e37 100644
--- a/res/res_calendar_ews.c
+++ b/res/res_calendar_ews.c
@@ -27,7 +27,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425289 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ne_request.h>
 #include <ne_session.h>
@@ -40,7 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425289 $")
 #include <ne_redirect.h>
 
 #include "asterisk/module.h"
-#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/lock.h"
 #include "asterisk/config.h"
@@ -938,7 +937,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk MS Exchange Web Service Calendar Integration",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
diff --git a/res/res_calendar_exchange.c b/res/res_calendar_exchange.c
index 9777efc..6b5a72b 100644
--- a/res/res_calendar_exchange.c
+++ b/res/res_calendar_exchange.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libical/ical.h>
 #include <ne_session.h>
@@ -40,12 +40,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include <iksemel.h>
 
 #include "asterisk/module.h"
-#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/lock.h"
 #include "asterisk/config.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/uuid.h"
 
 static void *exchangecal_load_calendar(void *data);
 static void *unref_exchangecal(void *obj);
@@ -243,23 +241,38 @@ static void *unref_exchangecal(void *obj)
 /* It is very important to use the return value of this function as a realloc could occur */
 static struct ast_str *generate_exchange_uuid(struct ast_str *uid)
 {
-	char buffer[AST_UUID_STR_LEN];
+	unsigned short val[8];
+	int x;
+
+	for (x = 0; x < 8; x++) {
+		val[x] = ast_random();
+	}
+	ast_str_set(&uid, 0, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", (unsigned)val[0],
+		(unsigned)val[1], (unsigned)val[2], (unsigned)val[3], (unsigned)val[4],
+		(unsigned)val[5], (unsigned)val[6], (unsigned)val[7]);
 
-	ast_uuid_generate_str(buffer, sizeof(buffer));
-	ast_str_set(&uid, 0, "%s", buffer);
 	return uid;
 }
 
 static int is_valid_uuid(struct ast_str *uid)
 {
-	struct ast_uuid *uuid = ast_str_to_uuid(ast_str_buffer(uid));
+	int i;
 
-	if (uuid) {
-		ast_free(uuid);
-		return 1;
+	if (ast_str_strlen(uid) != 36) {
+		return 0;
 	}
 
-	return 0;
+	for (i = 0; i < ast_str_strlen(uid); i++) {
+		if (i == 8 || i == 13 || i == 18 || i == 23) {
+			if (ast_str_buffer(uid)[i] != '-') {
+				return 0;
+			}
+		} else if (!((ast_str_buffer(uid)[i] > 47 && ast_str_buffer(uid)[i] < 58) || (ast_str_buffer(uid)[i] > 96 && ast_str_buffer(uid)[i] < 103))) {
+			return 0;
+		}
+	}
+
+	return 1;
 }
 
 static struct ast_str *xml_encode_str(struct ast_str *dst, const char *src)
@@ -407,17 +420,9 @@ static struct ast_str *exchangecal_request(struct exchangecal_pvt *pvt, const ch
 
 static int exchangecal_write_event(struct ast_calendar_event *event)
 {
-	struct ast_str *body = NULL;
-	struct ast_str *response = NULL;
-	struct ast_str *subdir = NULL;
-	struct ast_str *uid = NULL;
-	struct ast_str *summary = NULL;
-	struct ast_str *description = NULL;
-	struct ast_str *organizer = NULL;
-	struct ast_str *location = NULL;
-	struct ast_str *start = NULL;
-	struct ast_str *end = NULL;
-	struct ast_str *busystate = NULL;
+	struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
+	struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL,
+	               *location = NULL, *start = NULL, *end = NULL, *busystate = NULL;
 	int ret = -1;
 
 	if (!event) {
@@ -435,7 +440,7 @@ static int exchangecal_write_event(struct ast_calendar_event *event)
 		goto write_cleanup;
 	}
 
-	if (!(uid = ast_str_create(AST_UUID_STR_LEN)) ||
+	if (!(uid = ast_str_create(32)) ||
 		!(summary = ast_str_create(32)) ||
 		!(description = ast_str_create(32)) ||
 		!(organizer = ast_str_create(32)) ||
@@ -450,7 +455,7 @@ static int exchangecal_write_event(struct ast_calendar_event *event)
 	if (ast_strlen_zero(event->uid)) {
 		uid = generate_exchange_uuid(uid);
 	} else {
-		ast_str_set(&uid, AST_UUID_STR_LEN, "%s", event->uid);
+		ast_str_set(&uid, 36, "%s", event->uid);
 	}
 
 	if (!is_valid_uuid(uid)) {
@@ -497,14 +502,7 @@ static int exchangecal_write_event(struct ast_calendar_event *event)
 		"      </a:prop>\n"
 		"    </a:set>\n"
 		"</a:propertyupdate>\n",
-		ast_str_buffer(uid),
-		ast_str_buffer(summary),
-		ast_str_buffer(description),
-		ast_str_buffer(organizer),
-		ast_str_buffer(location),
-		ast_str_buffer(start),
-		ast_str_buffer(end),
-		ast_str_buffer(busystate));
+		ast_str_buffer(uid), ast_str_buffer(summary), ast_str_buffer(description), ast_str_buffer(organizer), ast_str_buffer(location), ast_str_buffer(start), ast_str_buffer(end), ast_str_buffer(busystate));
 	ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body));
 	ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid));
 
@@ -513,17 +511,39 @@ static int exchangecal_write_event(struct ast_calendar_event *event)
 	}
 
 write_cleanup:
-	ast_free(uid);
-	ast_free(summary);
-	ast_free(description);
-	ast_free(organizer);
-	ast_free(location);
-	ast_free(start);
-	ast_free(end);
-	ast_free(busystate);
-	ast_free(body);
-	ast_free(response);
-	ast_free(subdir);
+	if (uid) {
+		ast_free(uid);
+	}
+	if (summary) {
+		ast_free(summary);
+	}
+	if (description) {
+		ast_free(description);
+	}
+	if (organizer) {
+		ast_free(organizer);
+	}
+	if (location) {
+		ast_free(location);
+	}
+	if (start) {
+		ast_free(start);
+	}
+	if (end) {
+		ast_free(end);
+	}
+	if (busystate) {
+		ast_free(busystate);
+	}
+	if (body) {
+		ast_free(body);
+	}
+	if (response) {
+		ast_free(response);
+	}
+	if (subdir) {
+		ast_free(subdir);
+	}
 
 	return ret;
 }
@@ -741,7 +761,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk MS Exchange Calendar Integration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c
index 823fc83..df3c621 100644
--- a/res/res_calendar_icalendar.c
+++ b/res/res_calendar_icalendar.c
@@ -28,7 +28,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libical/ical.h>
 #include <ne_session.h>
@@ -38,7 +38,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include <ne_redirect.h>
 
 #include "asterisk/module.h"
-#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/lock.h"
 #include "asterisk/config.h"
@@ -504,7 +503,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk iCalendar .ics file integration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c
deleted file mode 100644
index 50a5fd8..0000000
--- a/res/res_chan_stats.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \brief Statsd channel stats. Exmaple of how to subscribe to Stasis events.
- *
- * This module subscribes to the channel caching topic and issues statsd stats
- * based on the received messages.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-/*** MODULEINFO
-	<depend>res_statsd</depend>
-	<defaultenabled>no</defaultenabled>
-	<support_level>extended</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/module.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/statsd.h"
-#include "asterisk/time.h"
-
-/*! Regular Stasis subscription */
-static struct stasis_subscription *sub;
-/*! Stasis message router */
-static struct stasis_message_router *router;
-
-/*!
- * \brief Subscription callback for all channel messages.
- * \param data Data pointer given when creating the subscription.
- * \param sub This subscription.
- * \param topic The topic the message was posted to. This is not necessarily the
- *              topic you subscribed to, since messages may be forwarded between
- *              topics.
- * \param message The message itself.
- */
-static void statsmaker(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	RAII_VAR(struct ast_str *, metric, NULL, ast_free);
-
-	if (stasis_subscription_final_message(sub, message)) {
-		/* Normally, data points to an object that must be cleaned up.
-		 * The final message is an unsubscribe notification that's
-		 * guaranteed to be the last message this subscription receives.
-		 * This would be a safe place to kick off any needed cleanup.
-		 */
-		return;
-	}
-
-	/* For no good reason, count message types */
-	metric = ast_str_create(80);
-	if (metric) {
-		ast_str_set(&metric, 0, "stasis.message.%s",
-			stasis_message_type_name(stasis_message_type(message)));
-		ast_statsd_log(ast_str_buffer(metric), AST_STATSD_METER, 1);
-	}
-}
-
-/*!
- * \brief Router callback for \ref stasis_cache_update messages.
- * \param data Data pointer given when added to router.
- * \param sub This subscription.
- * \param topic The topic the message was posted to. This is not necessarily the
- *              topic you subscribed to, since messages may be forwarded between
- *              topics.
- * \param message The message itself.
- */
-static void updates(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	/* Since this came from a message router, we know the type of the
-	 * message. We can cast the data without checking its type.
-	 */
-	struct stasis_cache_update *update = stasis_message_data(message);
-
-	/* We're only interested in channel snapshots, so check the type
-	 * of the underlying message.
-	 */
-	if (ast_channel_snapshot_type() != update->type) {
-		return;
-	}
-
-	/* There are three types of cache updates.
-	 * !old && new -> Initial cache entry
-	 * old && new -> Updated cache entry
-	 * old && !new -> Cache entry removed.
-	 */
-
-	if (!update->old_snapshot && update->new_snapshot) {
-		/* Initial cache entry; count a channel creation */
-		ast_statsd_log("channels.count", AST_STATSD_COUNTER, 1);
-	} else if (update->old_snapshot && !update->new_snapshot) {
-		/* Cache entry removed. Compute the age of the channel and post
-		 * that, as well as decrementing the channel count.
-		 */
-		struct ast_channel_snapshot *last;
-		int64_t age;
-
-		last = stasis_message_data(update->old_snapshot);
-		age = ast_tvdiff_ms(*stasis_message_timestamp(message),
-			last->creationtime);
-		ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);
-
-		/* And decrement the channel count */
-		ast_statsd_log("channels.count", AST_STATSD_COUNTER, -1);
-	}
-}
-
-/*!
- * \brief Router callback for any message that doesn't otherwise have a route.
- * \param data Data pointer given when added to router.
- * \param sub This subscription.
- * \param topic The topic the message was posted to. This is not necessarily the
- *              topic you subscribed to, since messages may be forwarded between
- *              topics.
- * \param message The message itself.
- */
-static void default_route(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	if (stasis_subscription_final_message(sub, message)) {
-		/* Much like with the regular subscription, you may need to
-		 * perform some cleanup when done with a message router. You
-		 * can look for the final message in the default route.
-		 */
-		return;
-	}
-}
-
-static int load_module(void)
-{
-	/* You can create a message router to route messages by type */
-	router = stasis_message_router_create(
-		ast_channel_topic_all_cached());
-	if (!router) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	stasis_message_router_add(router, stasis_cache_update_type(),
-		updates, NULL);
-	stasis_message_router_set_default(router, default_route, NULL);
-
-	/* Or a subscription to receive all of the messages from a topic */
-	sub = stasis_subscribe(ast_channel_topic_all(), statsmaker, NULL);
-	if (!sub) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	stasis_unsubscribe_and_join(sub);
-	sub = NULL;
-	stasis_message_router_unsubscribe_and_join(router);
-	router = NULL;
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Example of how to use Stasis",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_statsd"
-	);
diff --git a/res/res_clialiases.c b/res/res_clialiases.c
index 4f67158..0fa355a 100644
--- a/res/res_clialiases.c
+++ b/res/res_clialiases.c
@@ -26,22 +26,13 @@
  * CLI commands.
  */
 
-/*! \li \ref res_clialiases.c uses the configuration file \ref cli_aliases.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page cli_aliases.conf cli_aliases.conf
- * \verbinclude cli_aliases.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/config.h"
@@ -276,16 +267,7 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief Function called to load the module */
 static int load_module(void)
 {
 	if (!(cli_aliases = ao2_container_alloc(MAX_ALIAS_BUCKETS, alias_hash_cb, alias_cmp_cb))) {
@@ -300,7 +282,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "CLI Aliases",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c
index 7e17fd4..42030d7 100644
--- a/res/res_clioriginate.c
+++ b/res/res_clioriginate.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
@@ -38,7 +38,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $");
 #include "asterisk/cli.h"
 #include "asterisk/utils.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 
 /*! The timeout for originated calls, in seconds */
 #define TIMEOUT 30
@@ -58,6 +57,7 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app
 	char *chandata;
 	int reason = 0;
 	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
 
 	if (ast_strlen_zero(app))
 		return CLI_SHOWUSAGE;
@@ -70,12 +70,12 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app
 		return CLI_SHOWUSAGE;
 	}
 
-	if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(cap = ast_format_cap_alloc_nolock())) {
 		return CLI_FAILURE;
 	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
-	ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL);
-	ao2_ref(cap, -1);
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+	cap = ast_format_cap_destroy(cap);
 
 	return CLI_SUCCESS;
 }
@@ -96,6 +96,7 @@ static char *orig_exten(int fd, const char *chan, const char *data)
 	char *context = NULL;
 	int reason = 0;
 	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
 
 	chandata = ast_strdupa(chan);
 
@@ -114,12 +115,12 @@ static char *orig_exten(int fd, const char *chan, const char *data)
 		exten = "s";
 	if (ast_strlen_zero(context))
 		context = "default";
-	if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(cap = ast_format_cap_alloc_nolock())) {
 		return CLI_FAILURE;
 	}
-	ast_format_cap_append(cap, ast_format_slin, 0);
-	ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL);
-	ao2_ref(cap, -1);
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+	ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0);
+	cap = ast_format_cap_destroy(cap);
 
 	return CLI_SUCCESS;
 }
diff --git a/res/res_config_curl.c b/res/res_config_curl.c
index 44d3f1a..c50885e 100644
--- a/res/res_config_curl.c
+++ b/res/res_config_curl.c
@@ -22,7 +22,7 @@
  *
  * \author Tilghman Lesher <res_config_curl_v1 at the-tilghman.com>
  *
- * Depends on the CURL library - http://curl.haxx.se/
+ * \extref Depends on the CURL library  - http://curl.haxx.se/
  * 
  */
 
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <curl/curl.h>
 
@@ -53,18 +53,18 @@ AST_THREADSTORAGE(result_buf);
  * \brief Execute a curl query and return ast_variable list
  * \param url The base URL from which to retrieve data
  * \param unused Not currently used
- * \param fields list containing one or more field/operator/value set.
+ * \param ap list containing one or more field/operator/value set.
  *
  * \retval var on success
  * \retval NULL on failure
 */
-static struct ast_variable *realtime_curl(const char *url, const char *unused, const struct ast_variable *fields)
+static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[256], buf2[256];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp, *pair, *key;
-	unsigned int start = 1;
+	int i;
 	struct ast_variable *var = NULL, *prev = NULL;
 
 	if (!ast_custom_function_find("CURL")) {
@@ -82,11 +82,11 @@ static struct ast_variable *realtime_curl(const char *url, const char *unused, c
 
 	ast_str_set(&query, 0, "${CURL(%s/single,", url);
 
-	for (field = fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
-		start = 0;
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -124,18 +124,18 @@ static struct ast_variable *realtime_curl(const char *url, const char *unused, c
  * \brief Excute an Select query and return ast_config list
  * \param url
  * \param unused
- * \param fields list containing one or more field/operator/value set.
+ * \param ap list containing one or more field/operator/value set.
  *
  * \retval struct ast_config pointer on success
  * \retval NULL on failure
 */
-static struct ast_config *realtime_multi_curl(const char *url, const char *unused, const struct ast_variable *fields)
+static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[256], buf2[256];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp, *line, *pair, *key, *initfield = NULL;
-	int start = 1;
+	int i;
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
@@ -155,17 +155,17 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
 
 	ast_str_set(&query, 0, "${CURL(%s/multi,", url);
 
-	for (field = fields; field; field = field->next) {
-		if (start) {
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		if (i == 0) {
 			char *op;
-			initfield = ast_strdupa(field->name);
+			initfield = ast_strdupa(newparam);
 			if ((op = strchr(initfield, ' ')))
 				*op = '\0';
 		}
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
-		start = 0;
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -216,7 +216,7 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
  * \param unused
  * \param keyfield where clause field
  * \param lookup value of field for where clause
- * \param fields list containing one or more field/value set(s).
+ * \param ap list containing one or more field/value set(s).
  *
  * Update a database table, prepare the sql statement using keyfield and lookup
  * control the number of records to change. All values to be changed are stored in ap list.
@@ -225,13 +225,13 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[256], buf2[256];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp;
-	int start = 1, rowcount = -1;
+	int i, rowcount = -1;
 
 	if (!ast_custom_function_find("CURL")) {
 		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
@@ -250,11 +250,11 @@ static int update_curl(const char *url, const char *unused, const char *keyfield
 	ast_uri_encode(lookup, buf2, sizeof(buf2), ast_uri_http);
 	ast_str_set(&query, 0, "${CURL(%s/update?%s=%s,", url, buf1, buf2);
 
-	for (field = fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
-		start = 0;
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -274,14 +274,13 @@ static int update_curl(const char *url, const char *unused, const char *keyfield
 	return -1;
 }
 
-static int update2_curl(const char *url, const char *unused, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int update2_curl(const char *url, const char *unused, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[200], buf2[200];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp;
-	unsigned int start = 1;
-	int rowcount = -1;
+	int rowcount = -1, lookup = 1, first = 1;
 
 	if (!ast_custom_function_find("CURL")) {
 		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
@@ -297,20 +296,23 @@ static int update2_curl(const char *url, const char *unused, const struct ast_va
 
 	ast_str_set(&query, 0, "${CURL(%s/update?", url);
 
-	for (field = lookup_fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "" : "&", buf1, buf2);
-		start = 0;
-	}
-	ast_str_append(&query, 0, ",");
-	start = 1;
-
-	for (field = update_fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "" : "&", buf1, buf2);
-		start = 0;
+	for (;;) {
+		if ((newparam = va_arg(ap, const char *)) == SENTINEL) {
+			if (lookup) {
+				lookup = 0;
+				ast_str_append(&query, 0, ",");
+				/* Back to the first parameter; we don't need a starting '&' */
+				first = 1;
+				continue;
+			} else {
+				break;
+			}
+		}
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", first ? "" : "&", buf1, buf2);
+		first = 0;
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -338,7 +340,7 @@ static int update2_curl(const char *url, const char *unused, const struct ast_va
  * \brief Execute an INSERT query
  * \param url
  * \param unused
- * \param fields list containing one or more field/value set(s)
+ * \param ap list containing one or more field/value set(s)
  *
  * Insert a new record into database table, prepare the sql statement.
  * All values to be changed are stored in ap list.
@@ -347,13 +349,13 @@ static int update2_curl(const char *url, const char *unused, const struct ast_va
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int store_curl(const char *url, const char *unused, const struct ast_variable *fields)
+static int store_curl(const char *url, const char *unused, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[256], buf2[256];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp;
-	int start = 1, rowcount = -1;
+	int i, rowcount = -1;
 
 	if (!ast_custom_function_find("CURL")) {
 		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
@@ -370,11 +372,11 @@ static int store_curl(const char *url, const char *unused, const struct ast_vari
 
 	ast_str_set(&query, 0, "${CURL(%s/store,", url);
 
-	for (field = fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
-		start = 0;
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -399,7 +401,7 @@ static int store_curl(const char *url, const char *unused, const struct ast_vari
  * \param unused
  * \param keyfield where clause field
  * \param lookup value of field for where clause
- * \param fields list containing one or more field/value set(s)
+ * \param ap list containing one or more field/value set(s)
  *
  * Delete a row from a database table, prepare the sql statement using keyfield and lookup
  * control the number of records to change. Additional params to match rows are stored in ap list.
@@ -408,13 +410,13 @@ static int store_curl(const char *url, const char *unused, const struct ast_vari
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct ast_str *query, *buffer;
 	char buf1[200], buf2[200];
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char *stringp;
-	int start = 1, rowcount = -1;
+	int i, rowcount = -1;
 
 	if (!ast_custom_function_find("CURL")) {
 		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
@@ -433,11 +435,11 @@ static int destroy_curl(const char *url, const char *unused, const char *keyfiel
 	ast_uri_encode(lookup, buf2, sizeof(buf2), ast_uri_http);
 	ast_str_set(&query, 0, "${CURL(%s/destroy,%s=%s&", url, buf1, buf2);
 
-	for (field = fields; field; field = field->next) {
-		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
-		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
-		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
-		start = 0;
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
+		ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
 	}
 
 	ast_str_append(&query, 0, ")}");
@@ -630,7 +632,7 @@ static int reload_module(void)
 static int unload_module(void)
 {
 	ast_config_engine_deregister(&curl_engine);
-
+	ast_verb(1, "res_config_curl unloaded.\n");
 	return 0;
 }
 
@@ -653,12 +655,11 @@ static int load_module(void)
 	reload_module();
 
 	ast_config_engine_register(&curl_engine);
-
+	ast_verb(1, "res_config_curl loaded.\n");
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime Curl configuration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c
index d2b8b4a..0e50de3 100644
--- a/res/res_config_ldap.c
+++ b/res/res_config_ldap.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Copyright (C) 2005, Oxymium sarl
  * Manuel Guesdon <mguesdon at oxymium.net> - LDAP RealTime Driver Author/Adaptor
@@ -21,23 +21,14 @@
 
 /*! \file
  *
- * \brief LDAP plugin for portable configuration engine (ARA)
+ * \brief ldap plugin for portable configuration engine (ARA)
  *
  * \author Mark Spencer <markster at digium.com>
  * \author Manuel Guesdon
  * \author Carl-Einar Thorner <cthorner at voicerd.com>
  * \author Russell Bryant <russell at digium.com>
  *
- * OpenLDAP http://www.openldap.org
- */
-
-/*! \li \ref res_config_ldap.c uses the configuration file \ref res_ldap.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page res_ldap.conf res_ldap.conf
- * \verbinclude res_ldap.conf.sample
+ * \extref OpenLDAP http://www.openldap.org
  */
 
 /*** MODULEINFO
@@ -53,7 +44,7 @@
 #include <stdio.h>
 #include <ldap.h>
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/logger.h"
@@ -92,8 +83,7 @@ struct category_and_metric {
 	int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */
 };
 
-/*! \brief Table configuration 
- */
+/*! \brief Table configuration */
 struct ldap_table_config {
 	char *table_name;		 /*!< table name */
 	char *additional_filter;	  /*!< additional filter	*/
@@ -103,8 +93,7 @@ struct ldap_table_config {
 	/* TODO: Make proxies work */
 };
 
-/*! \brief Should be locked before using it 
- */
+/*! \brief Should be locked before using it */
 static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
 static struct ldap_table_config *base_table_config;
 static struct ldap_table_config *static_table_config;
@@ -113,8 +102,7 @@ static struct ast_cli_entry ldap_cli[] = {
 	AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
 };
 
-/*! \brief Create a new table_config
- */
+/*! \brief Create a new table_config */
 static struct ldap_table_config *table_config_new(const char *table_name)
 {
 	struct ldap_table_config *p;
@@ -132,12 +120,8 @@ static struct ldap_table_config *table_config_new(const char *table_name)
 	return p;
 }
 
-/*! \brief Find a table_config
- *
- * Should be locked before using it 
- *
- *  \note This function assumes ldap_lock to be locked.
- */
+/*! \brief Find a table_config - Should be locked before using it 
+ *  \note This function assumes ldap_lock to be locked. */
 static struct ldap_table_config *table_config_for_table_name(const char *table_name)
 {
 	struct ldap_table_config *c = NULL;
@@ -150,8 +134,7 @@ static struct ldap_table_config *table_config_for_table_name(const char *table_n
 	return c;
 }
 
-/*! \brief Find variable by name
- */
+/*! \brief Find variable by name */
 static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
 {
 	for (; var; var = var->next) {
@@ -162,10 +145,10 @@ static struct ast_variable *variable_named(struct ast_variable *var, const char
 	return var;
 }
 
-/*! \brief Count  semicolons in string
- * \param somestr - pointer to a string
- *
- * \return number of occurances of the delimiter(semicolon)
+/*! \brief for the semicolon delimiter
+	\param somestr - pointer to a string
+
+	\return number of occurances of the delimiter(semicolon)
  */
 static int semicolon_count_str(const char *somestr)
 {
@@ -179,9 +162,7 @@ static int semicolon_count_str(const char *somestr)
 	return count;
 }
 
-/* \brief Count semicolons in variables
- *  
- * takes a linked list of \a ast_variable variables, finds the one with the name variable_value
+/* takes a linked list of \a ast_variable variables, finds the one with the name variable_value
  * and returns the number of semicolons in the value for that \a ast_variable
  */
 static int semicolon_count_var(struct ast_variable *var)
@@ -197,10 +178,7 @@ static int semicolon_count_var(struct ast_variable *var)
 	return semicolon_count_str(var_value->value);
 }
 
-/*! \brief add attribute to table config
- *
- * Should be locked before using it
- */
+/*! \brief add attribute to table config - Should be locked before using it */
 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
 	const char *attribute_name, const char *attribute_value)
 {
@@ -220,10 +198,8 @@ static void ldap_table_config_add_attribute(struct ldap_table_config *table_conf
 	table_config->attributes = var;
 }
 
-/*! \brief Free table_config
- *
- * \note assumes ldap_lock to be locked
- */
+/*! \brief Free table_config 
+ *  \note assumes ldap_lock to be locked */
 static void table_configs_free(void)
 {
 	struct ldap_table_config *c;
@@ -245,10 +221,7 @@ static void table_configs_free(void)
 	static_table_config = NULL;
 }
 
-/*! \brief Convert variable name to ldap attribute name
- *
- * \note Should be locked before using it
- */
+/*! \brief Convert variable name to ldap attribute name - Should be locked before using it */
 static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
 	const char *attribute_name)
 {
@@ -274,9 +247,7 @@ static const char *convert_attribute_name_to_ldap(struct ldap_table_config *tabl
 }
 
 /*! \brief Convert ldap attribute name to variable name 
- *
- * \note Should be locked before using it
- */
+	\note Should be locked before using it */
 static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
 						    const char *attribute_name)
 {
@@ -302,8 +273,8 @@ static const char *convert_attribute_name_from_ldap(struct ldap_table_config *ta
 }
 
 /*! \brief Get variables from ldap entry attributes 
- * \note Should be locked before using it
- * \return a linked list of ast_variable variables.
+	\note Should be locked before using it
+ 	\return a linked list of ast_variable variables.
  */
 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
 	LDAPMessage *ldap_entry)
@@ -386,7 +357,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config
  * The results are freed outside this function so is the \a vars array.
  *	
  * \return \a vars - an array of ast_variable variables terminated with a null.
- */
+ **/
 static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
 	LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
 {
@@ -403,8 +374,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
 	int delim_tot_count = 0;
 	int delim_count = 0;
 
-	/* \breif First find the total count
-	 */
+	/* First find the total count */
 	ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
 
 	for (tot_count = 0; ldap_entry; tot_count++) { 
@@ -418,20 +388,18 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
 		*entries_count_ptr = tot_count;
 	}
 
-	/*! \note Now that we have the total count we allocate space and create the variables
+	/* Now that we have the total count we allocate space and create the variables
 	 * Remember that each element in vars is a linked list that points to realtime variable.
 	 * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
 	 * value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element.
-	 * This memory must be freed outside of this function.
-	 */
+	 * This memory must be freed outside of this function. */
 	vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
 
 	ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
 
 	i = 0;
 
-	/* \brief For each static realtime variable we may create several entries in the \a vars array if it's delimited
-	 */
+	/* For each static realtime variable we may create several entries in the \a vars array if it's delimited */
 	for (entry_index = 0; ldap_entry; ) {
 		int pos = 0;
 		delim_value = NULL;
@@ -573,19 +541,14 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
 }
 
 
-/*! \brief Check if we have a connection error
- */
+/*! \brief Check if we have a connection error */
 static int is_ldap_connect_error(int err)
 {
 	return (err == LDAP_SERVER_DOWN || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
 }
 
-/*! \brief Get LDAP entry by dn and return attributes as variables
- *
- * Should be locked before using it 
- *
- * This is used for setting the default values of an object
- * i.e., with accountBaseDN
+/*! \brief Get LDAP entry by dn and return attributes as variables  - Should be locked before using it 
+	This is used for setting the default values of an object(i.e., with accountBaseDN)
 */
 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
 					   const char *dn)
@@ -661,8 +624,7 @@ static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_confi
 	}
 }
 
-/*! \note caller should free returned pointer
- */
+/*! \note caller should free returned pointer */
 static char *substituted(struct ast_channel *channel, const char *string)
 {
 #define MAXRESULT	2048
@@ -676,8 +638,7 @@ static char *substituted(struct ast_channel *channel, const char *string)
 	return ret_string;
 }
 
-/*! \note caller should free returned pointer
- */
+/*! \note caller should free returned pointer */
 static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
 {
 	char *cbasedn = NULL;
@@ -705,8 +666,7 @@ static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
 }
 
 /*! \brief Replace \<search\> by \<by\> in string. 
- * \note No check is done on string allocated size !
- */
+	\note No check is done on string allocated size ! */
 static int replace_string_in_string(char *string, const char *search, const char *by)
 {
 	int search_len = strlen(search);
@@ -729,8 +689,7 @@ static int replace_string_in_string(char *string, const char *search, const char
 	return replaced;
 }
 
-/*! \brief Append a name=value filter string. The filter string can grow. 
- */
+/*! \brief Append a name=value filter string. The filter string can grow. */
 static void append_var_and_value_to_filter(struct ast_str **filter,
 	struct ldap_table_config *table_config,
 	const char *name, const char *value)
@@ -762,13 +721,14 @@ static void append_var_and_value_to_filter(struct ast_str **filter,
  * \param entries_count_ptr is a pointer to found entries count (can be NULL)
  * \param basedn is the base DN
  * \param table_name is the table_name (used dor attribute convertion and additional filter)
- * \param fields contains list of pairs name/value
+ * \param ap contains null terminated list of pairs name/value
 */
 static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
-	const char *basedn, const char *table_name, const struct ast_variable *fields)
+	const char *basedn, const char *table_name, va_list ap)
 {
 	struct ast_variable **vars = NULL;
-	const struct ast_variable *field = fields;
+	const char *newparam = NULL;
+	const char *newval = NULL;
 	struct ldap_table_config *table_config = NULL;
 	char *clean_basedn = cleaned_basedn(NULL, basedn);
 	struct ast_str *filter = NULL;
@@ -788,7 +748,11 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 		return NULL;
 	}
 
-	if (!field) {
+	/* Get the first parameter and first value in our list of passed paramater/value pairs  */
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+
+	if (!newparam || !newval) {
 		ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
 			" and 1 value to search on.\n");
 		ast_free(filter);
@@ -825,13 +789,13 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 		ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
 	}
 
-	/* Create the first part of the query using the first parameter/value pairs we just extracted.
-	 * If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat
-	 */
+	/* Create the first part of the query using the first parameter/value pairs we just extracted */
+	/*   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
-	while ((field = field->next)) {
-		append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
+	append_var_and_value_to_filter(&filter, table_config, newparam, newval);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		append_var_and_value_to_filter(&filter, table_config, newparam, newval);
 	}
 	ast_str_append(&filter, 0, ")");
 
@@ -870,8 +834,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 
 		ldap_msgfree(ldap_result_msg);
 
-		/*! \TODO get the default variables from the accountBaseDN, not implemented with delimited values
-		 */
+		/* TODO: get the default variables from the accountBaseDN, not implemented with delimited values */
 		if (vars) {
 			struct ast_variable **p = vars;
 			while (*p) {
@@ -941,53 +904,28 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
 	return vars;
 }
 
-static struct ast_variable *realtime_arguments_to_fields(va_list ap)
-{
-	struct ast_variable *fields = NULL;
-	const char *newparam, *newval;
-
-	while ((newparam = va_arg(ap, const char *))) {
-		struct ast_variable *field;
-
-		newval = va_arg(ap, const char *);
-		if (!(field = ast_variable_new(newparam, newval, ""))) {
-			ast_variables_destroy(fields);
-			return NULL;
-		}
-
-		field->next = fields;
-		fields = field;
-	}
-
-	return fields;
-}
-
-/*! \brief same as realtime_ldap_base_ap but take variable arguments count list
- */
+/*! \brief same as realtime_ldap_base_ap but take variable arguments count list */
 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
 	const char *basedn, const char *table_name, ...)
 {
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
 	struct ast_variable **vars = NULL;
 	va_list ap;
 
 	va_start(ap, table_name);
-	fields = realtime_arguments_to_fields(ap);
+	vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
 	va_end(ap);
 
-	vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, fields);
-
 	return vars;
 }
 
 /*! \brief See Asterisk doc
- *
- * For Realtime Dynamic(i.e., switch, queues, and directory)
- */
+*
+* For Realtime Dynamic(i.e., switch, queues, and directory) -- I think
+*/
 static struct ast_variable *realtime_ldap(const char *basedn,
-					  const char *table_name, const struct ast_variable *fields)
+					  const char *table_name, va_list ap)
 {
-	struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, fields);
+	struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
 	struct ast_variable *var = NULL;
 
 	if (vars) {
@@ -1013,26 +951,29 @@ static struct ast_variable *realtime_ldap(const char *basedn,
 }
 
 /*! \brief See Asterisk doc
- *
- * this function will be called for the switch statment if no match is found with the realtime_ldap function(i.e. it is a failover);
- * however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
- * this is an area of asterisk that could do with a lot of modification
- * I think this function returns Realtime dynamic objects
- */
+*
+* this function will be called for the switch statment if no match is found with the realtime_ldap function(i.e. it is a failover);
+* however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
+* this is an area of asterisk that could do with a lot of modification
+* I think this function returns Realtime dynamic objects
+*/
 static struct ast_config *realtime_multi_ldap(const char *basedn,
-      const char *table_name, const struct ast_variable *fields)
+      const char *table_name, va_list ap)
 {
 	char *op;
 	const char *initfield = NULL;
+	const char *newparam, *newval;
 	struct ast_variable **vars =
-		realtime_ldap_base_ap(NULL, basedn, table_name, fields);
+		realtime_ldap_base_ap(NULL, basedn, table_name, ap);
 	struct ast_config *cfg = NULL;
 
-	if (!fields) {
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 	    ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
 	    return NULL;
 	}
-	initfield = ast_strdupa(fields->name);
+	initfield = ast_strdupa(newparam);
 	if ((op = strchr(initfield, ' '))) {
 		*op = '\0';
 	}
@@ -1072,7 +1013,8 @@ static struct ast_config *realtime_multi_ldap(const char *basedn,
 
 }
 
-/*! \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
+/*! 
+ * \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
  * \param a pointer to category_and_metric struct
  * \param b pointer to category_and_metric struct
  *
@@ -1102,13 +1044,13 @@ static int compare_categories(const void *a, const void *b)
 	return 0;
 }
 
-/*! \brief See Asterisk Realtime Documentation
+/*! \brief See Asterisk doc
  *
- * This is for Static Realtime
- *	
- * load the configuration stuff for the .conf files
- * called on a reload
- */
+*	This is for Static Realtime (again: I think...)
+*	
+*	load the configuration stuff for the .conf files
+*	called on a reload
+*/
 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
 	const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
 {
@@ -1134,7 +1076,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
 		return NULL;
 	}
 
-	/*! \note Since the items come back in random order, they need to be sorted
+	/*!\note Since the items come back in random order, they need to be sorted
 	 * first, and since the data could easily exceed stack size, this is
 	 * allocated from the heap.
 	 */
@@ -1220,15 +1162,15 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
 }
 
 /* \brief Function to update a set of values in ldap static mode
- */
+*/
 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
-	const char *lookup, const struct ast_variable *fields)
+	const char *lookup, va_list ap)
 {
 	int error = 0;
 	LDAPMessage *ldap_entry = NULL;
 	LDAPMod **ldap_mods;
-	const char *newparam;
-	const struct ast_variable *field = fields;
+	const char *newparam = NULL;
+	const char *newval = NULL;
 	char *dn;
 	int num_entries = 0;
 	int i = 0;
@@ -1285,8 +1227,10 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 	/* Create the modification array with the parameter/value pairs we were given, 
 	 * if there are several parameters with the same name, we collect them into 
 	 * one parameter/value pair and delimit them with a semicolon */
-	newparam = convert_attribute_name_to_ldap(table_config, field->name);
-	if (!newparam) {
+	newparam = va_arg(ap, const char *);
+	newparam = convert_attribute_name_to_ldap(table_config, newparam);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
 		return -1;
 	}
@@ -1299,18 +1243,19 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 	ldap_mods[0]->mod_type = ldap_strdup(newparam);
 
 	ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
-	ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
+	ldap_mods[0]->mod_values[0] = ldap_strdup(newval);
 
-	while ((field = field->next)) {
-		newparam = convert_attribute_name_to_ldap(table_config, field->name);
+	while ((newparam = va_arg(ap, const char *))) {
+		newparam = convert_attribute_name_to_ldap(table_config, newparam);
+		newval = va_arg(ap, const char *);
 		mod_exists = 0;
 
 		for (i = 0; i < mods_size - 1; i++) {
 			if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
 				/* We have the parameter allready, adding the value as a semicolon delimited value */
-				ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
+				ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
 				strcat(ldap_mods[i]->mod_values[0], ";");
-				strcat(ldap_mods[i]->mod_values[0], field->value);
+				strcat(ldap_mods[i]->mod_values[0], newval);
 				mod_exists = 1;	
 				break;
 			}
@@ -1327,14 +1272,14 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 			ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
 			strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
 
-			if (strlen(field->value) == 0) {
+			if (strlen(newval) == 0) {
 				ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
 			} else {
 				ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
 
 				ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
-				ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(field->value) + 1);
-				strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
+				ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(newval) + 1);
+				strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
 			}
 		}
 	}
@@ -1402,13 +1347,13 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 	return num_entries;
 }
 
-static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
 {
 	int error = 0;
 	LDAPMessage *ldap_entry = NULL;
 	LDAPMod **ldap_mods;
-	const char *newparam;
-	const struct ast_variable *field;
+	const char *newparam = NULL;
+	const char *newval = NULL;
 	char *dn;
 	int num_entries = 0;
 	int i = 0;
@@ -1460,17 +1405,19 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
 	}
 
 	/* Get multiple lookup keyfields and values */
-	for (field = lookup_fields; field; field = field->next) {
-		append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		append_var_and_value_to_filter(&filter, table_config, newparam, newval);
 	}
 	ast_str_append(&filter, 0, ")");
 
 	/* Create the modification array with the parameter/value pairs we were given, 
 	 * if there are several parameters with the same name, we collect them into 
 	 * one parameter/value pair and delimit them with a semicolon */
-	field = update_fields;
-	newparam = convert_attribute_name_to_ldap(table_config, field->name);
-	if (!newparam) {
+	newparam = va_arg(ap, const char *);
+	newparam = convert_attribute_name_to_ldap(table_config, newparam);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
 		ast_free(filter);
 		ast_free(clean_basedn);
@@ -1486,19 +1433,20 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
 	strcpy(ldap_mods[0]->mod_type, newparam);
 
 	ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
-	ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
-	strcpy(ldap_mods[0]->mod_values[0], field->value);
+	ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
+	strcpy(ldap_mods[0]->mod_values[0], newval);
 
-	while ((field = field->next)) {
-		newparam = convert_attribute_name_to_ldap(table_config, field->name);
+	while ((newparam = va_arg(ap, const char *))) {
+		newparam = convert_attribute_name_to_ldap(table_config, newparam);
+		newval = va_arg(ap, const char *);
 		mod_exists = 0;
 
 		for (i = 0; i < mods_size - 1; i++) {
 			if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
 				/* We have the parameter allready, adding the value as a semicolon delimited value */
-				ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
+				ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
 				strcat(ldap_mods[i]->mod_values[0], ";");
-				strcat(ldap_mods[i]->mod_values[0], field->value);
+				strcat(ldap_mods[i]->mod_values[0], newval);
 				mod_exists = 1;	
 				break;
 			}
@@ -1517,8 +1465,8 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
 			strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
 
 			ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
-			ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
-			strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
+			ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
+			strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
 		}
 	}
 	/* freeing ldap_mods further down */
@@ -1594,19 +1542,6 @@ static struct ast_config_engine ldap_engine = {
 	.update2_func = update2_ldap,
 };
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- *
- * \todo Don't error or warn on a default install. If the config is
- * default we should not attempt to connect to a server. -lathama
- */
 static int load_module(void)
 {
 	if (parse_config() < 0) {
@@ -1629,9 +1564,6 @@ static int load_module(void)
 	return 0;
 }
 
-/*! \brief Unload Module
- *
- */
 static int unload_module(void)
 {
 	/* Aquire control before doing anything to the module itself. */
@@ -1653,8 +1585,6 @@ static int unload_module(void)
 	return 0;
 }
 
-/*! \breif Relod Module
- */
 static int reload(void)
 {
 	/* Aquire control before doing anything to the module itself. */
@@ -1683,8 +1613,7 @@ static int reload(void)
 	return 0;
 }
 
-/*! \brief parse the configuration file
- */
+/*! \brief parse the configuration file */
 static int parse_config(void)
 {
 	struct ast_config *config;
@@ -1832,9 +1761,6 @@ static int ldap_reconnect(void)
 	}
 }
 
-/*! \brief Realtime Status
- *
- */
 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	char status[256], credentials[100] = "";
@@ -1883,11 +1809,7 @@ static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_c
 	return CLI_SUCCESS;
 }
 
-/*! \brief Module Information
- *
- */
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interface",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index fe89b55..3f8a0e6 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -56,7 +56,7 @@ struct custom_prepare_struct {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(encoding)[256];
 	);
-	const struct ast_variable *fields;
+	va_list ap;
 	unsigned long long skip;
 };
 
@@ -100,9 +100,10 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
 {
 	int res, x = 1, count = 0;
 	struct custom_prepare_struct *cps = data;
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	char encodebuf[1024];
 	SQLHSTMT stmt;
+	va_list ap;
 
 	res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@@ -119,14 +120,14 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
 		return NULL;
 	}
 
-	for (field = cps->fields; field; field = field->next) {
-		const char *newval = field->value;
-
+	va_copy(ap, cps->ap);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
 		if ((1LL << count++) & cps->skip) {
-			ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", field->name, newval, 1ULL << (count - 1), cps->skip);
+			ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1ULL << (count - 1), cps->skip);
 			continue;
 		}
-		ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, field->name, newval);
+		ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
 		if (strchr(newval, ';') || strchr(newval, '^')) {
 			ENCODE_CHUNK(encodebuf, newval);
 			ast_string_field_set(cps, encoding[x], encodebuf);
@@ -134,6 +135,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
 		}
 		SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
 	}
+	va_end(ap);
 
 	if (!ast_strlen_zero(cps->extra)) {
 		const char *newval = cps->extra;
@@ -161,7 +163,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
  * \retval var on success
  * \retval NULL on failure
 */
-static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
@@ -169,7 +171,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
 	char coltitle[256];
 	struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
 	char *op;
-	const struct ast_variable *field = fields;
+	const char *newparam;
 	char *stringp;
 	char *chunk;
 	SQLSMALLINT collen;
@@ -182,10 +184,11 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
 	SQLSMALLINT decimaldigits;
 	SQLSMALLINT nullable;
 	SQLLEN indicator;
-	struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
+	va_list aq;
+	struct custom_prepare_struct cps = { .sql = sql };
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-	if (!table || !field) {
+	if (!table) {
 		return NULL;
 	}
 
@@ -196,20 +199,32 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
 		return NULL;
 	}
 
-	op = !strchr(field->name, ' ') ? " =" : "";
-	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
-		strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
-	while ((field = field->next)) {
-		op = !strchr(field->name, ' ') ? " =" : "";
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
-			strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
+	va_copy(aq, ap);
+	newparam = va_arg(aq, const char *);
+	if (!newparam) {
+		va_end(aq);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
+	va_arg(aq, const char *);
+	op = !strchr(newparam, ' ') ? " =" : "";
+	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
+		strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
+	while((newparam = va_arg(aq, const char *))) {
+		op = !strchr(newparam, ' ') ? " =" : "";
+		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
+			strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
+		va_arg(aq, const char *);
 	}
+	va_end(aq);
 
 	if (ast_string_field_init(&cps, 256)) {
 		ast_odbc_release_obj(obj);
 		return NULL;
 	}
+	va_copy(cps.ap, ap);
 	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
+	va_end(cps.ap);
 	ast_string_field_free_memory(&cps);
 
 	if (!stmt) {
@@ -317,7 +332,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
  * \retval var on success
  * \retval NULL on failure
 */
-static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
@@ -326,7 +341,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
 	struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
 	const char *initfield;
 	char *op;
-	const struct ast_variable *field = fields;
+	const char *newparam;
 	char *stringp;
 	char *chunk;
 	SQLSMALLINT collen;
@@ -342,9 +357,10 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
 	SQLSMALLINT decimaldigits;
 	SQLSMALLINT nullable;
 	SQLLEN indicator;
-	struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
+	struct custom_prepare_struct cps = { .sql = sql };
+	va_list aq;
 
-	if (!table || !field) {
+	if (!table) {
 		return NULL;
 	}
 
@@ -353,19 +369,30 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
 		return NULL;
 	}
 
-	initfield = ast_strdupa(field->name);
+	va_copy(aq, ap);
+	newparam = va_arg(aq, const char *);
+	if (!newparam)  {
+		va_end(aq);
+		ast_odbc_release_obj(obj);
+		return NULL;
+	}
+
+	initfield = ast_strdupa(newparam);
 	if ((op = strchr(initfield, ' '))) {
 		*op = '\0';
 	}
 
-	op = !strchr(field->name, ' ') ? " =" : "";
-	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
-		strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
-	while ((field = field->next)) {
-		op = !strchr(field->name, ' ') ? " =" : "";
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
-			strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
+	va_arg(aq, const char *);
+	op = !strchr(newparam, ' ') ? " =" : "";
+	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
+		strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
+	while((newparam = va_arg(aq, const char *))) {
+		op = !strchr(newparam, ' ') ? " =" : "";
+		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
+			strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
+		va_arg(aq, const char *);
 	}
+	va_end(aq);
 
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
 
@@ -373,7 +400,9 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
 		ast_odbc_release_obj(obj);
 		return NULL;
 	}
+	va_copy(cps.ap, ap);
 	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
+	va_end(cps.ap);
 	ast_string_field_free_memory(&cps);
 
 	if (!stmt) {
@@ -482,20 +511,21 @@ next_sql_fetch:;
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
 	char sql[256];
 	SQLLEN rowcount=0;
-	const struct ast_variable *field = fields;
+	const char *newparam, *newval;
 	int res, count = 0, paramcount = 0;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
+	va_list aq;
+	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
 	struct odbc_cache_tables *tableptr;
 	struct odbc_cache_columns *column = NULL;
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-	if (!table || !field || !keyfield) {
+	if (!table || !keyfield) {
 		return -1;
 	}
 
@@ -509,26 +539,29 @@ static int update_odbc(const char *database, const char *table, const char *keyf
 		ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", keyfield, table, database);
 	}
 
+	va_copy(aq, ap);
+
 	snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
-	while (field) {
-		if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
+	while((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
+		if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count >= 64) {
 			if (paramcount++) {
 				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
 			}
 			/* NULL test for non-text columns */
-			if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", field->name);
+			if (count < 64 && ast_strlen_zero(newval) && column->nullable && !is_text(column) && !ast_odbc_allow_empty_string_in_nontext(obj)) {
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", newparam);
 				cps.skip |= (1LL << count);
 			} else {
-				/* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", field->name);
+				/* Value is not an empty string, or column accepts empty strings, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", newparam);
 			}
 		} else { /* the column does not exist in the table */
 			cps.skip |= (1LL << count);
 		}
 		++count;
-		field = field->next;
 	}
+	va_end(aq);
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
 	ast_odbc_release_table(tableptr);
 
@@ -536,7 +569,9 @@ static int update_odbc(const char *database, const char *table, const char *keyf
 		ast_odbc_release_obj(obj);
 		return -1;
 	}
+	va_copy(cps.ap, ap);
 	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
+	va_end(cps.ap);
 	ast_string_field_free_memory(&cps);
 
 	if (!stmt) {
@@ -563,17 +598,17 @@ static int update_odbc(const char *database, const char *table, const char *keyf
 struct update2_prepare_struct {
 	const char *database;
 	const char *table;
-	const struct ast_variable *lookup_fields;
-	const struct ast_variable *update_fields;
+	va_list ap;
 };
 
 static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
 {
 	int res, x = 1, first = 1;
 	struct update2_prepare_struct *ups = data;
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
 	SQLHSTMT stmt;
+	va_list ap;
 	struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
 
 	if (!sql) {
@@ -597,30 +632,45 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
 
 	ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
 
-	for (field = ups->update_fields; field; field = field->next) {
-		if (ast_odbc_find_column(tableptr, field->name)) {
-			ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
-			SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
+	/* Start by finding the second set of parameters */
+	va_copy(ap, ups->ap);
+
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+	}
+
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		if (ast_odbc_find_column(tableptr, newparam)) {
+			ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
+			SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
 			first = 0;
 		} else {
-			ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
+			ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
 		}
 	}
+	va_end(ap);
 
 	ast_str_append(&sql, 0, "WHERE");
 	first = 1;
 
-	for (field = ups->lookup_fields; field; field = field->next) {
-		if (!ast_odbc_find_column(tableptr, field->name)) {
-			ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", field->name, ups->table, ups->database);
+	/* Restart search, because we need to add the search parameters */
+	va_copy(ap, ups->ap);
+
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		if (!ast_odbc_find_column(tableptr, newparam)) {
+			va_end(ap);
+			ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->table, ups->database);
 			ast_odbc_release_table(tableptr);
 			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 			return NULL;
 		}
-		ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
-		SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
+		ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
+		SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
 		first = 0;
 	}
+	va_end(ap);
 
 	/* Done with the table metadata */
 	ast_odbc_release_table(tableptr);
@@ -649,11 +699,11 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int update2_odbc(const char *database, const char *table, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
-	struct update2_prepare_struct ups = { .database = database, .table = table, .lookup_fields = lookup_fields, .update_fields = update_fields, };
+	struct update2_prepare_struct ups = { .database = database, .table = table, };
 	struct ast_str *sql;
 	int res;
 	SQLLEN rowcount = 0;
@@ -662,10 +712,13 @@ static int update2_odbc(const char *database, const char *table, const struct as
 		return -1;
 	}
 
+	va_copy(ups.ap, ap);
 	if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
+		va_end(ups.ap);
 		ast_odbc_release_obj(obj);
 		return -1;
 	}
+	va_end(ups.ap);
 
 	res = SQLRowCount(stmt, &rowcount);
 	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
@@ -698,7 +751,7 @@ static int update2_odbc(const char *database, const char *table, const struct as
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
+static int store_odbc(const char *database, const char *table, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
@@ -706,12 +759,13 @@ static int store_odbc(const char *database, const char *table, const struct ast_
 	char keys[256];
 	char vals[256];
 	SQLLEN rowcount=0;
-	const struct ast_variable *field = fields;
+	const char *newparam;
 	int res;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = NULL, .fields = fields, };
+	va_list aq;
+	struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-	if (!table || !field) {
+	if (!table) {
 		return -1;
 	}
 
@@ -720,19 +774,32 @@ static int store_odbc(const char *database, const char *table, const struct ast_
 		return -1;
 	}
 
-	snprintf(keys, sizeof(keys), "%s", field->name);
+	va_copy(aq, ap);
+
+	newparam = va_arg(aq, const char *);
+	if (!newparam)  {
+		va_end(aq);
+		ast_odbc_release_obj(obj);
+		return -1;
+	}
+	va_arg(aq, const char *);
+	snprintf(keys, sizeof(keys), "%s", newparam);
 	ast_copy_string(vals, "?", sizeof(vals));
-	while ((field = field->next)) {
-		snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", field->name);
+	while ((newparam = va_arg(aq, const char *))) {
+		snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
 		snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
+		va_arg(aq, const char *);
 	}
+	va_end(aq);
 	snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
 
 	if (ast_string_field_init(&cps, 256)) {
 		ast_odbc_release_obj(obj);
 		return -1;
 	}
+	va_copy(cps.ap, ap);
 	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
+	va_end(cps.ap);
 	ast_string_field_free_memory(&cps);
 
 	if (!stmt) {
@@ -770,15 +837,16 @@ static int store_odbc(const char *database, const char *table, const struct ast_
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
 	struct odbc_obj *obj;
 	SQLHSTMT stmt;
 	char sql[256];
 	SQLLEN rowcount=0;
-	const struct ast_variable *field;
+	const char *newparam;
 	int res;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
+	va_list aq;
+	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
 	if (!table) {
@@ -792,16 +860,21 @@ static int destroy_odbc(const char *database, const char *table, const char *key
 
 	snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
 
-	for (field = fields; field; field = field->next) {
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", field->name);
+	va_copy(aq, ap);
+	while((newparam = va_arg(aq, const char *))) {
+		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
+		va_arg(aq, const char *);
 	}
+	va_end(aq);
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
 
 	if (ast_string_field_init(&cps, 256)) {
 		ast_odbc_release_obj(obj);
 		return -1;
 	}
+	va_copy(cps.ap, ap);
 	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
+	va_end(cps.ap);
 	ast_string_field_free_memory(&cps);
 
 	if (!stmt) {
@@ -1205,13 +1278,14 @@ static int unload_module (void)
 {
 	ast_config_engine_deregister(&odbc_engine);
 
+	ast_verb(1, "res_config_odbc unloaded.\n");
 	return 0;
 }
 
 static int load_module (void)
 {
 	ast_config_engine_register(&odbc_engine);
-
+	ast_verb(1, "res_config_odbc loaded.\n");
 	return 0;
 }
 
@@ -1221,7 +1295,6 @@ static int reload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime ODBC configuration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index c836749..be2d4ed 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Copyright (C) 1999-2010, Digium, Inc.
  *
@@ -19,7 +19,7 @@
  * \author Mark Spencer <markster at digium.com>
  * \author Manuel Guesdon <mguesdon at oxymium.net> - PostgreSQL RealTime Driver Author/Adaptor
  *
- * PostgreSQL http://www.postgresql.org
+ * \extref PostgreSQL http://www.postgresql.org
  */
 
 /*** MODULEINFO
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libpq-fe.h>			/* PostgreSQL */
 
@@ -79,7 +79,6 @@ static char dbhost[MAX_DB_OPTION_SIZE] = "";
 static char dbuser[MAX_DB_OPTION_SIZE] = "";
 static char dbpass[MAX_DB_OPTION_SIZE] = "";
 static char dbname[MAX_DB_OPTION_SIZE] = "";
-static char dbappname[MAX_DB_OPTION_SIZE] = "";
 static char dbsock[MAX_DB_OPTION_SIZE] = "";
 static int dbport = 5432;
 static time_t connect_time = 0;
@@ -140,7 +139,7 @@ static void destroy_table(struct tables *table)
  *  \return -2 on query failure that resulted in disconnection
  *  \return 0 on success
  *
- *  \note see pgsql_exec for full example
+ *  \example see pgsql_exec for full example
  */
 static int _pgsql_exec(const char *database, const char *tablename, const char *sql, PGresult **result)
 {
@@ -415,7 +414,7 @@ static struct columns *find_column(struct tables *t, const char *colname)
 	return NULL;
 }
 
-static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
+static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int num_rows = 0, pgresult;
@@ -424,7 +423,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 	char *stringp;
 	char *chunk;
 	char *op;
-	const struct ast_variable *field = fields;
+	const char *newparam, *newval;
 	struct ast_variable *var = NULL, *prev = NULL;
 
 	/*
@@ -439,7 +438,9 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
 		if (pgsqlConn) {
@@ -451,28 +452,29 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	op = strchr(field->name, ' ') ? "" : " =";
+	op = strchr(newparam, ' ') ? "" : " =";
 
-	ESCAPE_STRING(escapebuf, field->value);
+	ESCAPE_STRING(escapebuf, newval);
 	if (pgresult) {
-		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf));
-	while ((field = field->next)) {
-		if (!strchr(field->name, ' '))
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		if (!strchr(newparam, ' '))
 			op = " =";
 		else
 			op = "";
 
-		ESCAPE_STRING(escapebuf, field->value);
+		ESCAPE_STRING(escapebuf, newval);
 		if (pgresult) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
 	}
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
@@ -527,17 +529,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 	return var;
 }
 
-static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int num_rows = 0, pgresult;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
 	struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
-	const struct ast_variable *field = fields;
 	const char *initfield = NULL;
 	char *stringp;
 	char *chunk;
 	char *op;
+	const char *newparam, *newval;
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
@@ -557,7 +559,9 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		return NULL;
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
 		if (pgsqlConn) {
@@ -568,7 +572,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		return NULL;
 	}
 
-	initfield = ast_strdupa(field->name);
+	initfield = ast_strdupa(newparam);
 	if ((op = strchr(initfield, ' '))) {
 		*op = '\0';
 	}
@@ -576,33 +580,34 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' '))
+	if (!strchr(newparam, ' '))
 		op = " =";
 	else
 		op = "";
 
-	ESCAPE_STRING(escapebuf, field->value);
+	ESCAPE_STRING(escapebuf, newval);
 	if (pgresult) {
-		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 		ast_config_destroy(cfg);
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf));
-	while ((field = field->next)) {
-		if (!strchr(field->name, ' '))
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		if (!strchr(newparam, ' '))
 			op = " =";
 		else
 			op = "";
 
-		ESCAPE_STRING(escapebuf, field->value);
+		ESCAPE_STRING(escapebuf, newval);
 		if (pgresult) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 			ast_config_destroy(cfg);
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
 	}
 
 	if (initfield) {
@@ -681,11 +686,11 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 }
 
 static int update_pgsql(const char *database, const char *tablename, const char *keyfield,
-						const char *lookup, const struct ast_variable *fields)
+						const char *lookup, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int numrows = 0, pgresult;
-	const struct ast_variable *field = fields;
+	const char *newparam, *newval;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
 	struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
 	struct tables *table;
@@ -708,7 +713,9 @@ static int update_pgsql(const char *database, const char *tablename, const char
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
 		if (pgsqlConn) {
@@ -721,13 +728,13 @@ static int update_pgsql(const char *database, const char *tablename, const char
 
 	/* Check that the column exists in the table */
 	AST_LIST_TRAVERSE(&table->columns, column, list) {
-		if (strcmp(column->name, field->name) == 0) {
+		if (strcmp(column->name, newparam) == 0) {
 			break;
 		}
 	}
 
 	if (!column) {
-		ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", field->name, tablename);
+		ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
 		release_table(table);
 		return -1;
 	}
@@ -735,28 +742,30 @@ static int update_pgsql(const char *database, const char *tablename, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	ESCAPE_STRING(escapebuf, field->value);
+	ESCAPE_STRING(escapebuf, newval);
 	if (pgresult) {
-		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+		ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 		release_table(table);
 		return -1;
 	}
-	ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, field->name, ast_str_buffer(escapebuf));
+	ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
 
-	while ((field = field->next)) {
-		if (!find_column(table, field->name)) {
-			ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+
+		if (!find_column(table, newparam)) {
+			ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
 			continue;
 		}
 
-		ESCAPE_STRING(escapebuf, field->value);
+		ESCAPE_STRING(escapebuf, newval);
 		if (pgresult) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 			release_table(table);
 			return -1;
 		}
 
-		ast_str_append(&sql, 0, ", %s = '%s'", field->name, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
 	}
 	release_table(table);
 
@@ -808,12 +817,12 @@ static int update_pgsql(const char *database, const char *tablename, const char
 	return -1;
 }
 
-static int update2_pgsql(const char *database, const char *tablename, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int update2_pgsql(const char *database, const char *tablename, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int numrows = 0, pgresult, first = 1;
 	struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
 	struct ast_str *where = ast_str_thread_get(&where_buf, 100);
 	struct tables *table;
@@ -842,20 +851,21 @@ static int update2_pgsql(const char *database, const char *tablename, const stru
 	ast_str_set(&sql, 0, "UPDATE %s SET", tablename);
 	ast_str_set(&where, 0, " WHERE");
 
-	for (field = lookup_fields; field; field = field->next) {
-		if (!find_column(table, field->name)) {
-			ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", field->name, tablename, database);
+	while ((newparam = va_arg(ap, const char *))) {
+		if (!find_column(table, newparam)) {
+			ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
 			release_table(table);
 			return -1;
 		}
 
-		ESCAPE_STRING(escapebuf, field->value);
+		newval = va_arg(ap, const char *);
+		ESCAPE_STRING(escapebuf, newval);
 		if (pgresult) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 			release_table(table);
 			return -1;
 		}
-		ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", field->name, ast_str_buffer(escapebuf));
+		ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
 		first = 0;
 	}
 
@@ -872,21 +882,23 @@ static int update2_pgsql(const char *database, const char *tablename, const stru
 
 	/* Now retrieve the columns to update */
 	first = 1;
-	for (field = update_fields; field; field = field->next) {
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+
 		/* If the column is not within the table, then skip it */
-		if (!find_column(table, field->name)) {
-			ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", field->name, tablename, database);
+		if (!find_column(table, newparam)) {
+			ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
 			continue;
 		}
 
-		ESCAPE_STRING(escapebuf, field->value);
+		ESCAPE_STRING(escapebuf, newval);
 		if (pgresult) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
+			ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
 			release_table(table);
 			return -1;
 		}
 
-		ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", field->name, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
 		first = 0;
 	}
 	release_table(table);
@@ -919,7 +931,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru
 	return -1;
 }
 
-static int store_pgsql(const char *database, const char *table, const struct ast_variable *fields)
+static int store_pgsql(const char *database, const char *table, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int numrows;
@@ -927,7 +939,7 @@ static int store_pgsql(const char *database, const char *table, const struct ast
 	struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
 	struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
 	int pgresult;
-	const struct ast_variable *field = fields;
+	const char *newparam, *newval;
 
 	/*
 	 * Ignore database from the extconfig.conf since it was
@@ -941,7 +953,9 @@ static int store_pgsql(const char *database, const char *table, const struct ast
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!field) {
+	newparam = va_arg(ap, const char *);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
 		ast_log(LOG_WARNING,
 				"PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
 		if (pgsqlConn) {
@@ -960,14 +974,15 @@ static int store_pgsql(const char *database, const char *table, const struct ast
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	ESCAPE_STRING(buf, field->name);
+	ESCAPE_STRING(buf, newparam);
 	ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
-	ESCAPE_STRING(buf, field->value);
+	ESCAPE_STRING(buf, newval);
 	ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
-	while ((field = field->next)) {
-		ESCAPE_STRING(buf, field->name);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		ESCAPE_STRING(buf, newparam);
 		ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
-		ESCAPE_STRING(buf, field->value);
+		ESCAPE_STRING(buf, newval);
 		ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
 	}
 	ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
@@ -997,14 +1012,14 @@ static int store_pgsql(const char *database, const char *table, const struct ast
 	return -1;
 }
 
-static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
+static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
 	int numrows = 0;
 	int pgresult;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
 	struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
-	const struct ast_variable *field;
+	const char *newparam, *newval;
 
 	/*
 	 * Ignore database from the extconfig.conf since it was
@@ -1045,9 +1060,10 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
 	ESCAPE_STRING(buf1, keyfield);
 	ESCAPE_STRING(buf2, lookup);
 	ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
-	for (field = fields; field; field = field->next) {
-		ESCAPE_STRING(buf1, field->name);
-		ESCAPE_STRING(buf2, field->value);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		ESCAPE_STRING(buf1, newparam);
+		ESCAPE_STRING(buf2, newval);
 		ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
 	}
 
@@ -1335,7 +1351,7 @@ static int load_module(void)
 		return AST_MODULE_LOAD_DECLINE;
 
 	ast_config_engine_register(&pgsql_engine);
-
+	ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
 	ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
 
 	return 0;
@@ -1353,6 +1369,7 @@ static int unload_module(void)
 	}
 	ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
 	ast_config_engine_deregister(&pgsql_engine);
+	ast_verb(1, "PostgreSQL RealTime unloaded.\n");
 
 	/* Destroy cached table info */
 	AST_LIST_LOCK(&psql_tables);
@@ -1437,12 +1454,6 @@ static int parse_config(int is_reload)
 		dbport = atoi(s);
 	}
 
-	if (!(s = ast_variable_retrieve(config, "general", "dbappname"))) {
-		dbappname[0] = '\0';
-	} else {
-		ast_copy_string(dbappname, s, sizeof(dbappname));
-	}
-
 	if (!ast_strlen_zero(dbhost)) {
 		/* No socket needed */
 	} else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) {
@@ -1506,27 +1517,18 @@ static int pgsql_reconnect(const char *database)
 
 	/* DB password can legitimately be 0-length */
 	if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) {
-		struct ast_str *conn_info = ast_str_create(128);
-
-		if (!conn_info) {
-			ast_log(LOG_ERROR, "PostgreSQL RealTime: Failed to allocate memory for connection string.\n");
-			return 0;
-		}
+		struct ast_str *connInfo = ast_str_create(128);
 
-		ast_str_set(&conn_info, 0, "host=%s port=%d dbname=%s user=%s",
+		ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s",
 			S_OR(dbhost, dbsock), dbport, my_database, dbuser);
+		if (!ast_strlen_zero(dbpass))
+			ast_str_append(&connInfo, 0, " password=%s", dbpass);
 
-		if (!ast_strlen_zero(dbappname)) {
-			ast_str_append(&conn_info, 0, " application_name=%s", dbappname);
-		}
-
-		if (!ast_strlen_zero(dbpass)) {
-			ast_str_append(&conn_info, 0, " password=%s", dbpass);
-		}
-
-		pgsqlConn = PQconnectdb(ast_str_buffer(conn_info));
-		ast_free(conn_info);
-		conn_info = NULL;
+		ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
+		pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
+		ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
+		ast_free(connInfo);
+		connInfo = NULL;
 
 		ast_debug(1, "pgsqlConn=%p\n", pgsqlConn);
 		if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
@@ -1655,7 +1657,6 @@ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd,
 
 /* needs usecount semantics defined */
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PostgreSQL RealTime Configuration Driver",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c
index 324a9a2..4177586 100644
--- a/res/res_config_sqlite.c
+++ b/res/res_config_sqlite.c
@@ -36,7 +36,7 @@
  *
  * \section conf_sec Configuration
  *
- * The main configuration file is res_config_sqlite.conf.sample It must be readable or
+ * The main configuration file is res_config_sqlite.conf. It must be readable or
  * res_config_sqlite will fail to start. It is suggested to use the sample file
  * in this package as a starting point. The file has only one section
  * named <code>general</code>. Here are the supported parameters :
@@ -71,22 +71,13 @@
  * \brief res_config_sqlite module.
  */
 
-/*! \li \ref res_config_sqlite.c uses the configuration file \ref res_config_sqlite.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page res_config_sqlite.conf res_config_sqlite.conf
- * \verbinclude res_config_sqlite.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>sqlite</depend>
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sqlite.h>
 
@@ -291,6 +282,32 @@ static struct ast_config * config_handler(const char *database, const char *tabl
 	struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl, const char *who_asked);
 
 /*!
+ * \brief Helper function to parse a va_list object into 2 dynamic arrays of
+ * strings, parameters and values.
+ *
+ * ap must have the following format : param1 val1 param2 val2 param3 val3 ...
+ * arguments will be extracted to create 2 arrays:
+ *
+ * <ul>
+ *	<li>params : param1 param2 param3 ...</li>
+ *	<li>vals : val1 val2 val3 ...</li>
+ * </ul>
+ *
+ * The address of these arrays are stored in params_ptr and vals_ptr. It
+ * is the responsibility of the caller to release the memory of these arrays.
+ * It is considered an error that va_list has a null or odd number of strings.
+ *
+ * \param ap the va_list object to parse
+ * \param params_ptr where the address of the params array is stored
+ * \param vals_ptr where the address of the vals array is stored
+ * \param warn
+ * \retval the number of elements in the arrays (which have the same size).
+ * \retval 0 if an error occurred.
+ */
+static size_t get_params(va_list ap, const char ***params_ptr,
+	const char ***vals_ptr, int warn);
+
+/*!
  * \brief SQLite callback function for RealTime configuration.
  *
  * This function is passed to the SQLite engine as a callback function to
@@ -319,14 +336,14 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv,
  *
  * \param database the database to use (ignored)
  * \param table the table to use
- * \param fields list of parameters and values to match
+ * \param ap list of parameters and values to match
  *
  * \retval a linked list of struct ast_variable objects
  * \retval NULL if an error occurred
  * \see add_rt_cfg_entry()
  */
 static struct ast_variable * realtime_handler(const char *database,
-	const char *table, const struct ast_variable *fields);
+	const char *table, va_list ap);
 
 /*!
  * \brief SQLite callback function for RealTime configuration.
@@ -356,14 +373,14 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv,
  *
  * \param database the database to use (ignored)
  * \param table the table to use
- * \param fields list of parameters and values to match
+ * \param ap list of parameters and values to match
  * \retval a struct ast_config object storing categories and variables.
  * \retval NULL if an error occurred.
  *
  * \see add_rt_multi_cfg_entry()
  */
 static struct ast_config * realtime_multi_handler(const char *database,
-	const char *table, const struct ast_variable *fields);
+	const char *table, va_list ap);
 
 /*!
  * \brief Asterisk callback function for RealTime configuration (variable
@@ -379,14 +396,14 @@ static struct ast_config * realtime_multi_handler(const char *database,
  * \param table the table to use
  * \param keyfield the column of the matching cell
  * \param entity the value of the matching cell
- * \param fields list of parameters and new values to update in the database
+ * \param ap list of parameters and new values to update in the database
  * \retval the number of affected rows.
  * \retval -1 if an error occurred.
  */
 static int realtime_update_handler(const char *database, const char *table,
-	const char *keyfield, const char *entity, const struct ast_variable *fields);
+	const char *keyfield, const char *entity, va_list ap);
 static int realtime_update2_handler(const char *database, const char *table,
-	const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
+	va_list ap);
 
 /*!
  * \brief Asterisk callback function for RealTime configuration (variable
@@ -399,12 +416,12 @@ static int realtime_update2_handler(const char *database, const char *table,
  *
  * \param database the database to use (ignored)
  * \param table the table to use
- * \param fields list of parameters and new values to insert into the database
+ * \param ap list of parameters and new values to insert into the database
  * \retval the rowid of inserted row.
  * \retval -1 if an error occurred.
  */
 static int realtime_store_handler(const char *database, const char *table,
-	const struct ast_variable *fields);
+	va_list ap);
 
 /*!
  * \brief Asterisk callback function for RealTime configuration (destroys
@@ -420,12 +437,12 @@ static int realtime_store_handler(const char *database, const char *table,
  * \param table the table to use
  * \param keyfield the column of the matching cell
  * \param entity the value of the matching cell
- * \param fields list of additional parameters for cell matching
+ * \param ap list of additional parameters for cell matching
  * \retval the number of affected rows.
  * \retval -1 if an error occurred.
  */
 static int realtime_destroy_handler(const char *database, const char *table,
-	const char *keyfield, const char *entity, const struct ast_variable *fields);
+	const char *keyfield, const char *entity, va_list ap);
 
 /*!
  * \brief Asterisk callback function for the CLI status command.
@@ -791,7 +808,7 @@ static int cdr_handler(struct ast_cdr *cdr)
 
 	AST_RWLIST_TRAVERSE(&(tbl->columns), col, list) {
 		if (col->isint) {
-			ast_cdr_format_var(cdr, col->name, &tmp, workspace, sizeof(workspace), 1);
+			ast_cdr_getvar(cdr, col->name, &tmp, workspace, sizeof(workspace), 0, 1);
 			if (!tmp) {
 				continue;
 			}
@@ -800,7 +817,7 @@ static int cdr_handler(struct ast_cdr *cdr)
 				ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", scannum);
 			}
 		} else {
-			ast_cdr_format_var(cdr, col->name, &tmp, workspace, sizeof(workspace), 0);
+			ast_cdr_getvar(cdr, col->name, &tmp, workspace, sizeof(workspace), 0, 0);
 			if (!tmp) {
 				continue;
 			}
@@ -947,6 +964,45 @@ static struct ast_config *config_handler(const char *database,	const char *table
 	return cfg;
 }
 
+static size_t get_params(va_list ap, const char ***params_ptr, const char ***vals_ptr, int warn)
+{
+	const char **tmp, *param, *val, **params, **vals;
+	size_t params_count;
+
+	params = NULL;
+	vals = NULL;
+	params_count = 0;
+
+	while ((param = va_arg(ap, const char *)) && (val = va_arg(ap, const char *))) {
+		if (!(tmp = ast_realloc(params, (params_count + 1) * sizeof(char *)))) {
+			ast_free(params);
+			ast_free(vals);
+			return 0;
+		}
+		params = tmp;
+
+		if (!(tmp = ast_realloc(vals, (params_count + 1) * sizeof(char *)))) {
+			ast_free(params);
+			ast_free(vals);
+			return 0;
+		}
+		vals = tmp;
+
+		params[params_count] = param;
+		vals[params_count] = val;
+		params_count++;
+	}
+
+	if (params_count > 0) {
+		*params_ptr = params;
+		*vals_ptr = vals;
+	} else if (warn) {
+		ast_log(LOG_WARNING, "1 parameter and 1 value at least required\n");
+	}
+
+	return params_count;
+}
+
 static int add_rt_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
 {
 	struct rt_cfg_entry_args *args;
@@ -976,11 +1032,12 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv, char **columnNames
 	return 0;
 }
 
-static struct ast_variable * realtime_handler(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_variable * realtime_handler(const char *database, const char *table, va_list ap)
 {
 	char *query, *errormsg = NULL, *op, *tmp_str;
 	struct rt_cfg_entry_args args;
-	const struct ast_variable *field = fields;
+	const char **params, **vals;
+	size_t params_count;
 	int error;
 
 	if (!table) {
@@ -988,37 +1045,49 @@ static struct ast_variable * realtime_handler(const char *database, const char *
 		return NULL;
 	}
 
-	if (!fields) {
+	params_count = get_params(ap, &params, &vals, 1);
+
+	if (params_count == 0)
 		return NULL;
-	}
 
-	op = (strchr(field->name, ' ') == NULL) ? " =" : "";
+	op = (strchr(params[0], ' ') == NULL) ? " =" : "";
 
 /* \cond DOXYGEN_CAN_PARSE_THIS */
 #undef QUERY
 #define QUERY "SELECT * FROM '%q' WHERE%s %q%s '%q'"
 /* \endcond */
 
-	query = sqlite_mprintf(QUERY, table, (config_table && !strcmp(config_table, table)) ? " commented = 0 AND" : "", field->name, op, field->value);
+	query = sqlite_mprintf(QUERY, table, (config_table && !strcmp(config_table, table)) ? " commented = 0 AND" : "", params[0], op, vals[0]);
 
 	if (!query) {
 		ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
+		ast_free(params);
+		ast_free(vals);
 		return NULL;
 	}
 
-	while ((field = field->next)) {
-		op = (strchr(field->name, ' ') == NULL) ? " =" : "";
-		tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, field->name, op, field->value);
-		sqlite_freemem(query);
+	if (params_count > 1) {
+		size_t i;
 
-		if (!tmp_str) {
-			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
-			return NULL;
-		}
+		for (i = 1; i < params_count; i++) {
+			op = (strchr(params[i], ' ') == NULL) ? " =" : "";
+			tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
+			sqlite_freemem(query);
 
-		query = tmp_str;
+			if (!tmp_str) {
+				ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
+				ast_free(params);
+				ast_free(vals);
+				return NULL;
+			}
+
+			query = tmp_str;
+		}
 	}
 
+	ast_free(params);
+	ast_free(vals);
+
 	tmp_str = sqlite_mprintf("%s LIMIT 1;", query);
 	sqlite_freemem(query);
 
@@ -1103,12 +1172,13 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
 }
 
 static struct ast_config *realtime_multi_handler(const char *database,
-	const char *table, const struct ast_variable *fields)
+	const char *table, va_list ap)
 {
 	char *query, *errormsg = NULL, *op, *tmp_str, *initfield;
 	struct rt_multi_cfg_entry_args args;
-	const struct ast_variable *field = fields;
+	const char **params, **vals;
 	struct ast_config *cfg;
+	size_t params_count;
 	int error;
 
 	if (!table) {
@@ -1116,17 +1186,20 @@ static struct ast_config *realtime_multi_handler(const char *database,
 		return NULL;
 	}
 
-	if (!fields) {
+	if (!(cfg = ast_config_new())) {
+		ast_log(LOG_WARNING, "Unable to allocate configuration structure\n");
 		return NULL;
 	}
 
-	if (!(cfg = ast_config_new())) {
-		ast_log(LOG_WARNING, "Unable to allocate configuration structure\n");
+	if (!(params_count = get_params(ap, &params, &vals, 1))) {
+		ast_config_destroy(cfg);
 		return NULL;
 	}
 
-	if (!(initfield = ast_strdup(field->name))) {
+	if (!(initfield = ast_strdup(params[0]))) {
 		ast_config_destroy(cfg);
+		ast_free(params);
+		ast_free(vals);
 		return NULL;
 	}
 
@@ -1135,41 +1208,52 @@ static struct ast_config *realtime_multi_handler(const char *database,
 	if (tmp_str)
 		*tmp_str = '\0';
 
-	op = (!strchr(field->name, ' ')) ? " =" : "";
+	op = (!strchr(params[0], ' ')) ? " =" : "";
 
 	/*
 	 * Asterisk sends us an already escaped string when searching for
 	 * "exten LIKE" (uh!). Handle it separately.
 	 */
-	tmp_str = (!strcmp(field->value, "\\_%")) ? "_%" : (char *)field->value;
+	tmp_str = (!strcmp(vals[0], "\\_%")) ? "_%" : (char *)vals[0];
 
 /* \cond DOXYGEN_CAN_PARSE_THIS */
 #undef QUERY
 #define QUERY "SELECT * FROM '%q' WHERE%s %q%s '%q'"
 /* \endcond */
 
-	if (!(query = sqlite_mprintf(QUERY, table, (config_table && !strcmp(config_table, table)) ? " commented = 0 AND" : "", field->name, op, tmp_str))) {
+	if (!(query = sqlite_mprintf(QUERY, table, (config_table && !strcmp(config_table, table)) ? " commented = 0 AND" : "", params[0], op, tmp_str))) {
 		ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
 		ast_config_destroy(cfg);
+		ast_free(params);
+		ast_free(vals);
 		ast_free(initfield);
 		return NULL;
 	}
 
-	while ((field = field->next)) {
-		op = (!strchr(field->name, ' ')) ? " =" : "";
-		tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, field->name, op, field->value);
-		sqlite_freemem(query);
+	if (params_count > 1) {
+		size_t i;
 
-		if (!tmp_str) {
-			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
-			ast_config_destroy(cfg);
-			ast_free(initfield);
-			return NULL;
-		}
+		for (i = 1; i < params_count; i++) {
+			op = (!strchr(params[i], ' ')) ? " =" : "";
+			tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
+			sqlite_freemem(query);
 
-		query = tmp_str;
+			if (!tmp_str) {
+				ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
+				ast_config_destroy(cfg);
+				ast_free(params);
+				ast_free(vals);
+				ast_free(initfield);
+				return NULL;
+			}
+
+			query = tmp_str;
+		}
 	}
 
+	ast_free(params);
+	ast_free(vals);
+
 	if (!(tmp_str = sqlite_mprintf("%s ORDER BY %q;", query, initfield))) {
 		ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
 		sqlite_freemem(query);
@@ -1207,10 +1291,11 @@ static struct ast_config *realtime_multi_handler(const char *database,
 }
 
 static int realtime_update_handler(const char *database, const char *table,
-	const char *keyfield, const char *entity, const struct ast_variable *fields)
+	const char *keyfield, const char *entity, va_list ap)
 {
 	char *query, *errormsg = NULL, *tmp_str;
-	const struct ast_variable *field = fields;
+	const char **params, **vals;
+	size_t params_count;
 	int error, rows_num;
 
 	if (!table) {
@@ -1218,32 +1303,42 @@ static int realtime_update_handler(const char *database, const char *table,
 		return -1;
 	}
 
-	if (!field) {
+	if (!(params_count = get_params(ap, &params, &vals, 1)))
 		return -1;
-	}
 
 /* \cond DOXYGEN_CAN_PARSE_THIS */
 #undef QUERY
 #define QUERY "UPDATE '%q' SET %q = '%q'"
 /* \endcond */
 
-	if (!(query = sqlite_mprintf(QUERY, table, field->name, field->value))) {
+	if (!(query = sqlite_mprintf(QUERY, table, params[0], vals[0]))) {
 		ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
+		ast_free(params);
+		ast_free(vals);
 		return -1;
 	}
 
-	while ((field = field->next)) {
-		tmp_str = sqlite_mprintf("%s, %q = '%q'", query, field->name, field->value);
-		sqlite_freemem(query);
+	if (params_count > 1) {
+		size_t i;
 
-		if (!tmp_str) {
-			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
-			return -1;
-		}
+		for (i = 1; i < params_count; i++) {
+			tmp_str = sqlite_mprintf("%s, %q = '%q'", query, params[i], vals[i]);
+			sqlite_freemem(query);
 
-		query = tmp_str;
+			if (!tmp_str) {
+				ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
+				ast_free(params);
+				ast_free(vals);
+				return -1;
+			}
+
+			query = tmp_str;
+		}
 	}
 
+	ast_free(params);
+	ast_free(vals);
+
 	if (!(tmp_str = sqlite_mprintf("%s WHERE %q = '%q';", query, keyfield, entity))) {
 		ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
 		sqlite_freemem(query);
@@ -1278,13 +1373,13 @@ static int realtime_update_handler(const char *database, const char *table,
 }
 
 static int realtime_update2_handler(const char *database, const char *table,
-	const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+	va_list ap)
 {
 	char *errormsg = NULL, *tmp1, *tmp2;
 	int error, rows_num, first = 1;
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
 	struct ast_str *where = ast_str_thread_get(&where_buf, 100);
-	const struct ast_variable *field;
+	const char *param, *value;
 
 	if (!table) {
 		ast_log(LOG_WARNING, "Table name unspecified\n");
@@ -1298,11 +1393,12 @@ static int realtime_update2_handler(const char *database, const char *table,
 	ast_str_set(&sql, 0, "UPDATE %s SET", table);
 	ast_str_set(&where, 0, " WHERE");
 
-	for (field = lookup_fields; field; field = field->next) {
+	while ((param = va_arg(ap, const char *))) {
+		value = va_arg(ap, const char *);
 		ast_str_append(&where, 0, "%s %s = %s",
 			first ? "" : " AND",
-			tmp1 = sqlite_mprintf("%q", field->name),
-			tmp2 = sqlite_mprintf("%Q", field->value));
+			tmp1 = sqlite_mprintf("%q", param),
+			tmp2 = sqlite_mprintf("%Q", value));
 		sqlite_freemem(tmp1);
 		sqlite_freemem(tmp2);
 		first = 0;
@@ -1314,11 +1410,12 @@ static int realtime_update2_handler(const char *database, const char *table,
 	}
 
 	first = 1;
-	for (field = update_fields; field; field = field->next) {
+	while ((param = va_arg(ap, const char *))) {
+		value = va_arg(ap, const char *);
 		ast_str_append(&sql, 0, "%s %s = %s",
 			first ? "" : ",",
-			tmp1 = sqlite_mprintf("%q", field->name),
-			tmp2 = sqlite_mprintf("%Q", field->value));
+			tmp1 = sqlite_mprintf("%q", param),
+			tmp2 = sqlite_mprintf("%Q", value));
 		sqlite_freemem(tmp1);
 		sqlite_freemem(tmp2);
 		first = 0;
@@ -1349,55 +1446,63 @@ static int realtime_update2_handler(const char *database, const char *table,
 	return rows_num;
 }
 
-static int realtime_store_handler(const char *database, const char *table, const struct ast_variable *fields)
+static int realtime_store_handler(const char *database, const char *table, va_list ap)
 {
 	char *errormsg = NULL, *tmp_str, *tmp_keys = NULL, *tmp_keys2 = NULL, *tmp_vals = NULL, *tmp_vals2 = NULL;
-	const struct ast_variable *field = fields;
+	const char **params, **vals;
+	size_t params_count;
 	int error, rows_id;
+	size_t i;
 
 	if (!table) {
 		ast_log(LOG_WARNING, "Table name unspecified\n");
 		return -1;
 	}
 
-	if (!fields) {
+	if (!(params_count = get_params(ap, &params, &vals, 1)))
 		return -1;
-	}
 
 /* \cond DOXYGEN_CAN_PARSE_THIS */
 #undef QUERY
 #define QUERY "INSERT into '%q' (%s) VALUES (%s);"
 /* \endcond */
 
-	do {
+	for (i = 0; i < params_count; i++) {
 		if ( tmp_keys2 ) {
-			tmp_keys = sqlite_mprintf("%s, %q", tmp_keys2, field->name);
+			tmp_keys = sqlite_mprintf("%s, %q", tmp_keys2, params[i]);
 			sqlite_freemem(tmp_keys2);
 		} else {
-			tmp_keys = sqlite_mprintf("%q", field->name);
+			tmp_keys = sqlite_mprintf("%q", params[i]);
 		}
 		if (!tmp_keys) {
 			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
 			sqlite_freemem(tmp_vals);
+			ast_free(params);
+			ast_free(vals);
 			return -1;
 		}
 
 		if ( tmp_vals2 ) {
-			tmp_vals = sqlite_mprintf("%s, '%q'", tmp_vals2, field->value);
+			tmp_vals = sqlite_mprintf("%s, '%q'", tmp_vals2, vals[i]);
 			sqlite_freemem(tmp_vals2);
 		} else {
-			tmp_vals = sqlite_mprintf("'%q'", field->value);
+			tmp_vals = sqlite_mprintf("'%q'", vals[i]);
 		}
 		if (!tmp_vals) {
 			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
 			sqlite_freemem(tmp_keys);
+			ast_free(params);
+			ast_free(vals);
 			return -1;
 		}
 
 
 		tmp_keys2 = tmp_keys;
 		tmp_vals2 = tmp_vals;
-	} while ((field = field->next));
+	}
+
+	ast_free(params);
+	ast_free(vals);
 
 	if (!(tmp_str = sqlite_mprintf(QUERY, table, tmp_keys, tmp_vals))) {
 		ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
@@ -1436,17 +1541,21 @@ static int realtime_store_handler(const char *database, const char *table, const
 }
 
 static int realtime_destroy_handler(const char *database, const char *table,
-	const char *keyfield, const char *entity, const struct ast_variable *fields)
+	const char *keyfield, const char *entity, va_list ap)
 {
 	char *query, *errormsg = NULL, *tmp_str;
-	const struct ast_variable *field;
+	const char **params = NULL, **vals = NULL;
+	size_t params_count;
 	int error, rows_num;
+	size_t i;
 
 	if (!table) {
 		ast_log(LOG_WARNING, "Table name unspecified\n");
 		return -1;
 	}
 
+	params_count = get_params(ap, &params, &vals, 0);
+
 /* \cond DOXYGEN_CAN_PARSE_THIS */
 #undef QUERY
 #define QUERY "DELETE FROM '%q' WHERE"
@@ -1454,21 +1563,27 @@ static int realtime_destroy_handler(const char *database, const char *table,
 
 	if (!(query = sqlite_mprintf(QUERY, table))) {
 		ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
+		ast_free(params);
+		ast_free(vals);
 		return -1;
 	}
 
-	for (field = fields; field; field = field->next) {
-		tmp_str = sqlite_mprintf("%s %q = '%q' AND", query, field->name, field->value);
+	for (i = 0; i < params_count; i++) {
+		tmp_str = sqlite_mprintf("%s %q = '%q' AND", query, params[i], vals[i]);
 		sqlite_freemem(query);
 
 		if (!tmp_str) {
 			ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
+			ast_free(params);
+			ast_free(vals);
 			return -1;
 		}
 
 		query = tmp_str;
 	}
 
+	ast_free(params);
+	ast_free(vals);
 	if (!(tmp_str = sqlite_mprintf("%s %q = '%q';", query, keyfield, entity))) {
 		ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
 		sqlite_freemem(query);
@@ -1627,13 +1742,11 @@ static char *handle_cli_sqlite_show_tables(struct ast_cli_entry *e, int cmd, str
 
 static int unload_module(void)
 {
-	if (cdr_registered && ast_cdr_unregister(RES_CONFIG_SQLITE_NAME)) {
-		return -1;
-	}
-
-	if (cli_status_registered) {
+	if (cli_status_registered)
 		ast_cli_unregister_multiple(cli_status, ARRAY_LEN(cli_status));
-	}
+
+	if (cdr_registered)
+		ast_cdr_unregister(RES_CONFIG_SQLITE_NAME);
 
 	ast_config_engine_deregister(&sqlite_engine);
 
@@ -1645,16 +1758,6 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	char *errormsg = NULL;
@@ -1768,7 +1871,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime SQLite configuration",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_REALTIME_DRIVER,
diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c
index f3e0435..075830d 100644
--- a/res/res_config_sqlite3.c
+++ b/res/res_config_sqlite3.c
@@ -29,15 +29,6 @@
  * \ingroup resources
  */
 
-/*! \li \ref res_config_sqlite3.c uses the configuration file \ref res_config_sqlite3.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page res_config_sqlite3.conf res_config_sqlite3.conf
- * \verbinclude res_config_sqlite3.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>sqlite3</depend>
 	<support_level>core</support_level>
@@ -45,7 +36,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sqlite3.h>
 
@@ -61,12 +52,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
  ***/
 
 static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
-static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
-static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
-static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
-static int realtime_sqlite3_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
-static int realtime_sqlite3_store(const char *database, const char *table, const struct ast_variable *fields);
-static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
+static struct ast_variable *realtime_sqlite3(const char *database, const char *table, va_list ap);
+static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, va_list ap);
+static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
+static int realtime_sqlite3_update2(const char *database, const char *table, va_list ap);
+static int realtime_sqlite3_store(const char *database, const char *table, va_list ap);
+static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
 static int realtime_sqlite3_require(const char *database, const char *table, va_list ap);
 static int realtime_sqlite3_unload(const char *database, const char *table);
 
@@ -649,10 +640,10 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
 }
 
 /*! \brief Helper function for single and multi-row realtime load functions */
-static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
+static int realtime_sqlite3_helper(const char *database, const char *table, va_list ap, int is_multi, void *arg)
 {
 	struct ast_str *sql;
-	const struct ast_variable *field;
+	const char *param, *value;
 	int first = 1;
 
 	if (ast_strlen_zero(table)) {
@@ -664,14 +655,14 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons
 		return -1;
 	}
 
-	for (field = fields; field; field = field->next) {
+	while ((param = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
 			ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s %s", sqlite3_escape_table(table),
-				    sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
+					sqlite3_escape_column_op(param), sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
-					sqlite3_escape_value(field->value));
+			ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(param),
+					sqlite3_escape_value(value));
 		}
 	}
 
@@ -692,11 +683,11 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons
 /*! \brief Realtime callback for a single row query
  * \return ast_variable list for single result on success, NULL on empty/failure
  */
-static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_variable *realtime_sqlite3(const char *database, const char *table, va_list ap)
 {
 	struct ast_variable *result_row = NULL;
 
-	realtime_sqlite3_helper(database, table, fields, 0, &result_row);
+	realtime_sqlite3_helper(database, table, ap, 0, &result_row);
 
 	return result_row;
 }
@@ -704,7 +695,7 @@ static struct ast_variable *realtime_sqlite3(const char *database, const char *t
 /*! \brief Realtime callback for a multi-row query
  * \return ast_config containing possibly many results on success, NULL on empty/failure
  */
-static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields)
+static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, va_list ap)
 {
 	struct ast_config *cfg;
 
@@ -712,7 +703,7 @@ static struct ast_config *realtime_sqlite3_multi(const char *database, const cha
 		return NULL;
 	}
 
-	if (realtime_sqlite3_helper(database, table, fields, 1, cfg)) {
+	if (realtime_sqlite3_helper(database, table, ap, 1, cfg)) {
 		ast_config_destroy(cfg);
 		return NULL;
 	}
@@ -723,10 +714,10 @@ static struct ast_config *realtime_sqlite3_multi(const char *database, const cha
 /*! \brief Realtime callback for updating a row based on a single criteria
  * \return Number of rows affected or -1 on error
  */
-static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
+static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap)
 {
 	struct ast_str *sql;
-	const struct ast_variable *field;
+	const char *key, *value;
 	int first = 1, res;
 
 	if (ast_strlen_zero(table)) {
@@ -738,13 +729,13 @@ static int realtime_sqlite3_update(const char *database, const char *table, cons
 		return -1;
 	}
 
-	for (field = fields; field; field = field->next) {
+	while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
 			ast_str_set(&sql, 0, "UPDATE %s SET %s = %s",
-					sqlite3_escape_table(table), sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
+					sqlite3_escape_table(table), sqlite3_escape_column(key), sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
+			ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(key), sqlite3_escape_value(value));
 		}
 	}
 
@@ -759,11 +750,11 @@ static int realtime_sqlite3_update(const char *database, const char *table, cons
 /*! \brief Realtime callback for updating a row based on multiple criteria
  * \return Number of rows affected or -1 on error
  */
-static int realtime_sqlite3_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
+static int realtime_sqlite3_update2(const char *database, const char *table, va_list ap)
 {
 	struct ast_str *sql;
 	struct ast_str *where_clause;
-	const struct ast_variable *field;
+	const char *key, *value;
 	int first = 1, res;
 
 	if (ast_strlen_zero(table)) {
@@ -780,22 +771,22 @@ static int realtime_sqlite3_update2(const char *database, const char *table, con
 		return -1;
 	}
 
-	for (field = lookup_fields; field; field = field->next) {
+	while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
-			ast_str_set(&where_clause, 0, " WHERE %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
+			ast_str_set(&where_clause, 0, " WHERE %s %s", sqlite3_escape_column_op(key), sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&where_clause, 0, " AND %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
+			ast_str_append(&where_clause, 0, " AND %s %s", sqlite3_escape_column_op(key), sqlite3_escape_value(value));
 		}
 	}
 
 	first = 1;
-	for (field = update_fields; field; field = field->next) {
+	while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
-			ast_str_set(&sql, 0, "UPDATE %s SET %s = %s", sqlite3_escape_table(table), sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
+			ast_str_set(&sql, 0, "UPDATE %s SET %s = %s", sqlite3_escape_table(table), sqlite3_escape_column(key), sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
+			ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(key), sqlite3_escape_value(value));
 		}
 	}
 
@@ -812,10 +803,10 @@ static int realtime_sqlite3_update2(const char *database, const char *table, con
 /*! \brief Realtime callback for inserting a row
  * \return Number of rows affected or -1 on error
  */
-static int realtime_sqlite3_store(const char *database, const char *table, const struct ast_variable *fields)
+static int realtime_sqlite3_store(const char *database, const char *table, va_list ap)
 {
 	struct ast_str *sql, *values;
-	const struct ast_variable *field;
+	const char *column, *value;
 	int first = 1, res;
 
 	if (ast_strlen_zero(table)) {
@@ -832,14 +823,14 @@ static int realtime_sqlite3_store(const char *database, const char *table, const
 		return -1;
 	}
 
-	for (field = fields; field; field = field->next) {
+	while ((column = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
-			ast_str_set(&sql, 0, "INSERT INTO %s (%s", sqlite3_escape_table(table), sqlite3_escape_column(field->name));
-			ast_str_set(&values, 0, ") VALUES (%s", sqlite3_escape_value(field->value));
+			ast_str_set(&sql, 0, "INSERT INTO %s (%s", sqlite3_escape_table(table), sqlite3_escape_column(column));
+			ast_str_set(&values, 0, ") VALUES (%s", sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&sql, 0, ", %s", sqlite3_escape_column(field->name));
-			ast_str_append(&values, 0, ", %s", sqlite3_escape_value(field->value));
+			ast_str_append(&sql, 0, ", %s", sqlite3_escape_column(column));
+			ast_str_append(&values, 0, ", %s", sqlite3_escape_value(value));
 		}
 	}
 
@@ -856,10 +847,10 @@ static int realtime_sqlite3_store(const char *database, const char *table, const
 /*! \brief Realtime callback for deleting a row
  * \return Number of rows affected or -1 on error
  */
-static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
+static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap)
 {
 	struct ast_str *sql;
-	const struct ast_variable *field;
+	const char *param, *value;
 	int first = 1, res;
 
 	if (ast_strlen_zero(table)) {
@@ -871,13 +862,13 @@ static int realtime_sqlite3_destroy(const char *database, const char *table, con
 		return -1;
 	}
 
-	for (field = fields; field; field = field->next) {
+	while ((param = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
 		if (first) {
 			ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s %s", sqlite3_escape_table(table),
-					sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
+					sqlite3_escape_column_op(param), sqlite3_escape_value(value));
 			first = 0;
 		} else {
-			ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
+			ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(param), sqlite3_escape_value(value));
 		}
 	}
 
@@ -1172,16 +1163,6 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
@@ -1203,7 +1184,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite 3 realtime config engine",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/res/res_convert.c b/res/res_convert.c
index 83342ce..c2966a8 100644
--- a/res/res_convert.c
+++ b/res/res_convert.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
diff --git a/res/res_corosync.c b/res/res_corosync.c
index 0b6a06f..4b32055 100644
--- a/res/res_corosync.c
+++ b/res/res_corosync.c
@@ -26,13 +26,12 @@
 
 /*** MODULEINFO
 	<depend>corosync</depend>
-	<defaultenabled>no</defaultenabled>
 	<support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include <corosync/cpg.h>
 #include <corosync/cfg.h>
@@ -44,129 +43,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $");
 #include "asterisk/event.h"
 #include "asterisk/cli.h"
 #include "asterisk/devicestate.h"
-#include "asterisk/app.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
 
 AST_RWLOCK_DEFINE_STATIC(event_types_lock);
 
-static void publish_mwi_to_stasis(struct ast_event *event);
-static void publish_device_state_to_stasis(struct ast_event *event);
-
-/*! \brief The internal topic used for message forwarding and pings */
-static struct stasis_topic *corosync_aggregate_topic;
-
-/*! \brief Our \ref stasis message router */
-static struct stasis_message_router *stasis_router;
-
-/*! \brief Internal accessor for our topic */
-static struct stasis_topic *corosync_topic(void)
-{
-	return corosync_aggregate_topic;
-}
-
-/*! \brief A payload wrapper around a corosync ping event */
-struct corosync_ping_payload {
-	/*! The corosync ping event being passed over \ref stasis */
-	struct ast_event *event;
-};
-
-/*! \brief Destructor for the \ref corosync_ping_payload wrapper object */
-static void corosync_ping_payload_dtor(void *obj)
-{
-	struct corosync_ping_payload *payload = obj;
-
-	ast_free(payload->event);
-}
-
-/*! \brief Convert a Corosync PING to a \ref ast_event */
-static struct ast_event *corosync_ping_to_event(struct stasis_message *message)
-{
-	struct corosync_ping_payload *payload;
-	struct ast_event *event;
-	struct ast_eid *event_eid;
-
-	if (!message) {
-		return NULL;
-	}
-
-	payload = stasis_message_data(message);
-
-	if (!payload->event) {
-		return NULL;
-	}
-
-	event_eid = (struct ast_eid *)ast_event_get_ie_raw(payload->event, AST_EVENT_IE_EID);
-
-	event = ast_event_new(AST_EVENT_PING,
-				AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, event_eid, sizeof(*event_eid),
-				AST_EVENT_IE_END);
-
-	return event;
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(corosync_ping_message_type,
-	.to_event = corosync_ping_to_event, );
-
-/*! \brief Publish a Corosync ping to \ref stasis */
-static void publish_corosync_ping_to_stasis(struct ast_event *event)
-{
-	struct corosync_ping_payload *payload;
-	struct stasis_message *message;
-
-	ast_assert(ast_event_get_type(event) == AST_EVENT_PING);
-	ast_assert(event != NULL);
-
-	if (!corosync_ping_message_type()) {
-		return;
-	}
-
-	payload = ao2_t_alloc(sizeof(*payload), corosync_ping_payload_dtor, "Create ping payload");
-	if (!payload) {
-		return;
-	}
-	payload->event = event;
-
-	message = stasis_message_create(corosync_ping_message_type(), payload);
-	if (!message) {
-		ao2_t_ref(payload, -1, "Destroy payload on off nominal");
-		return;
-	}
-
-	stasis_publish(corosync_topic(), message);
-
-	ao2_t_ref(payload, -1, "Hand ref to stasis");
-	ao2_t_ref(message, -1, "Hand ref to stasis");
-}
-
 static struct {
 	const char *name;
-	struct stasis_forward *sub;
+	struct ast_event_sub *sub;
 	unsigned char publish;
 	unsigned char publish_default;
 	unsigned char subscribe;
 	unsigned char subscribe_default;
-	struct stasis_topic *(* topic_fn)(void);
-	struct stasis_cache *(* cache_fn)(void);
-	struct stasis_message_type *(* message_type_fn)(void);
-	void (* publish_to_stasis)(struct ast_event *);
 } event_types[] = {
-	[AST_EVENT_MWI] = { .name = "mwi",
-	                    .topic_fn = ast_mwi_topic_all,
-	                    .cache_fn = ast_mwi_state_cache,
-	                    .message_type_fn = ast_mwi_state_type,
-	                    .publish_to_stasis = publish_mwi_to_stasis, },
-	[AST_EVENT_DEVICE_STATE_CHANGE] = { .name = "device_state",
-	                                    .topic_fn = ast_device_state_topic_all,
-	                                    .cache_fn = ast_device_state_cache,
-	                                    .message_type_fn = ast_device_state_message_type,
-	                                    .publish_to_stasis = publish_device_state_to_stasis, },
-	[AST_EVENT_PING] = { .name = "ping",
-	                     .publish_default = 1,
-	                     .subscribe_default = 1,
-	                     .topic_fn = corosync_topic,
-	                     .message_type_fn = corosync_ping_message_type,
-	                     .publish_to_stasis = publish_corosync_ping_to_stasis, },
+	[AST_EVENT_MWI] = { .name = "mwi", },
+	[AST_EVENT_DEVICE_STATE_CHANGE] = { .name = "device_state", },
+	[AST_EVENT_PING] = { .name = "ping", .publish_default = 1, .subscribe_default = 1 },
 };
 
 static struct {
@@ -197,71 +87,6 @@ static corosync_cfg_callbacks_t cfg_callbacks = {
 	.corosync_cfg_shutdown_callback = cfg_shutdown_cb,
 };
 
-/*! \brief Publish a received MWI \ref ast_event to \ref stasis */
-static void publish_mwi_to_stasis(struct ast_event *event)
-{
-	const char *mailbox;
-	const char *context;
-	unsigned int new_msgs;
-	unsigned int old_msgs;
-	struct ast_eid *event_eid;
-
-	ast_assert(ast_event_get_type(event) == AST_EVENT_MWI);
-
-	mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
-	context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
-	new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
-	old_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
-	event_eid = (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
-
-	if (ast_strlen_zero(mailbox) || ast_strlen_zero(context)) {
-		return;
-	}
-
-	if (new_msgs > INT_MAX) {
-		new_msgs = INT_MAX;
-	}
-
-	if (old_msgs > INT_MAX) {
-		old_msgs = INT_MAX;
-	}
-
-	if (ast_publish_mwi_state_full(mailbox, context, (int)new_msgs,
-	                               (int)old_msgs, NULL, event_eid)) {
-		char eid[16];
-		ast_eid_to_str(eid, sizeof(eid), event_eid);
-		ast_log(LOG_WARNING, "Failed to publish MWI message for %s@%s from %s\n",
-			mailbox, context, eid);
-	}
-}
-
-/*! \brief Publish a received device state \ref ast_event to \ref stasis */
-static void publish_device_state_to_stasis(struct ast_event *event)
-{
-	const char *device;
-	enum ast_device_state state;
-	unsigned int cachable;
-	struct ast_eid *event_eid;
-
-	ast_assert(ast_event_get_type(event) == AST_EVENT_DEVICE_STATE_CHANGE);
-
-	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
-	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
-	cachable = ast_event_get_ie_uint(event, AST_EVENT_IE_CACHABLE);
-	event_eid = (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
-
-	if (ast_strlen_zero(device)) {
-		return;
-	}
-
-	if (ast_publish_device_state_full(device, state, cachable, event_eid)) {
-		char eid[16];
-		ast_eid_to_str(eid, sizeof(eid), event_eid);
-		ast_log(LOG_WARNING, "Failed to publish device state message for %s from %s\n",
-			device, eid);
-	}
-}
-
 static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_name,
 		uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len);
 
@@ -275,6 +100,8 @@ static cpg_callbacks_t cpg_callbacks = {
 	.cpg_confchg_fn = cpg_confchg_cb,
 };
 
+static void ast_event_cb(const struct ast_event *event, void *data);
+
 #ifdef HAVE_COROSYNC_CFG_STATE_TRACK
 static void cfg_state_track_cb(
 		corosync_cfg_state_notification_buffer_t *notification_buffer,
@@ -292,8 +119,6 @@ static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_nam
 		uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 {
 	struct ast_event *event;
-	void (*publish_handler)(struct ast_event *) = NULL;
-	enum ast_event_type event_type;
 
 	if (msg_len < ast_event_minimum_length()) {
 		ast_debug(1, "Ignoring event that's too small. %u < %u\n",
@@ -307,17 +132,9 @@ static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_nam
 		return;
 	}
 
-	event_type = ast_event_get_type(msg);
-	if (event_type > AST_EVENT_TOTAL) {
-		/* Egads, we don't support this */
-		return;
-	}
-
 	ast_rwlock_rdlock(&event_types_lock);
-	publish_handler = event_types[event_type].publish_to_stasis;
-	if (!event_types[event_type].subscribe || !publish_handler) {
-		/* We are not configured to subscribe to these events or
-		   we have no way to publish it internally. */
+	if (!event_types[ast_event_get_type(msg)].subscribe) {
+		/* We are not configured to subscribe to these events. */
 		ast_rwlock_unlock(&event_types_lock);
 		return;
 	}
@@ -329,80 +146,20 @@ static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_nam
 
 	memcpy(event, msg, msg_len);
 
-	if (event_type == AST_EVENT_PING) {
-		const struct ast_eid *eid;
-		char buf[128] = "";
-
-		eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
-		ast_eid_to_str(buf, sizeof(buf), (struct ast_eid *) eid);
-		ast_log(LOG_NOTICE, "Got event PING from server with EID: '%s'\n", buf);
-	}
-	ast_debug(5, "Publishing event %s (%u) to stasis\n",
-		ast_event_get_type_name(event), event_type);
-	publish_handler(event);
-}
-
-static void publish_to_corosync(struct stasis_message *message)
-{
-	cs_error_t cs_err;
-	struct iovec iov;
-	struct ast_event *event;
-
-	event = stasis_message_to_event(message);
-	if (!event) {
-		return;
-	}
-
-	if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
-		/* If the event didn't originate from this server, don't send it back out. */
-		ast_event_destroy(event);
-		return;
-	}
-
 	if (ast_event_get_type(event) == AST_EVENT_PING) {
 		const struct ast_eid *eid;
 		char buf[128] = "";
 
 		eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
 		ast_eid_to_str(buf, sizeof(buf), (struct ast_eid *) eid);
-		ast_log(LOG_NOTICE, "Sending event PING from this server with EID: '%s'\n", buf);
-	}
+		ast_log(LOG_NOTICE, "(cpg_deliver_cb) Got event PING from server with EID: '%s'\n", buf);
 
-	iov.iov_base = (void *)event;
-	iov.iov_len = ast_event_get_size(event);
-
-	ast_debug(5, "Publishing event %s (%u) to corosync\n",
-		ast_event_get_type_name(event), ast_event_get_type(event));
-
-	/* The stasis subscription will only exist if we are configured to publish
-	 * these events, so just send away. */
-	if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) {
-		ast_log(LOG_WARNING, "CPG mcast failed (%u)\n", cs_err);
+		ast_event_queue(event);
+	} else {
+		ast_event_queue_and_cache(event);
 	}
 }
 
-static void stasis_message_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	if (!message) {
-		return;
-	}
-
-	publish_to_corosync(message);
-}
-
-static int dump_cache_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_message *message = obj;
-
-	if (!message) {
-		return 0;
-	}
-
-	publish_to_corosync(message);
-
-	return 0;
-}
-
 static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_name,
 		const struct cpg_address *member_list, size_t member_list_entries,
 		const struct cpg_address *left_list, size_t left_list_entries,
@@ -418,27 +175,20 @@ static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_nam
 	}
 
 	for (i = 0; i < ARRAY_LEN(event_types); i++) {
-		struct ao2_container *messages;
+		struct ast_event_sub *event_sub;
 
 		ast_rwlock_rdlock(&event_types_lock);
 		if (!event_types[i].publish) {
 			ast_rwlock_unlock(&event_types_lock);
 			continue;
 		}
-
-		if (!event_types[i].cache_fn || !event_types[i].message_type_fn) {
-			ast_rwlock_unlock(&event_types_lock);
-			continue;
-		}
-
-		messages = stasis_cache_dump_by_eid(event_types[i].cache_fn(),
-			event_types[i].message_type_fn(),
-			&ast_eid_default);
 		ast_rwlock_unlock(&event_types_lock);
 
-		ao2_callback(messages, OBJ_NODATA, dump_cache_cb, NULL);
-
-		ao2_t_ref(messages, -1, "Dispose of dumped cache");
+		event_sub = ast_event_subscribe_new(i, ast_event_cb, NULL);
+		ast_event_sub_append_ie_raw(event_sub, AST_EVENT_IE_EID,
+					&ast_eid_default, sizeof(ast_eid_default));
+		ast_event_dump_cache(event_sub);
+		ast_event_sub_destroy(event_sub);
 	}
 }
 
@@ -536,6 +286,37 @@ static void *dispatch_thread_handler(void *data)
 	return NULL;
 }
 
+static void ast_event_cb(const struct ast_event *event, void *data)
+{
+	cs_error_t cs_err;
+	struct iovec iov = {
+		.iov_base = (void *) event,
+		.iov_len = ast_event_get_size(event),
+	};
+
+	if (ast_event_get_type(event) == AST_EVENT_PING) {
+		const struct ast_eid *eid;
+		char buf[128] = "";
+
+		eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
+		ast_eid_to_str(buf, sizeof(buf), (struct ast_eid *) eid);
+		ast_log(LOG_NOTICE, "(ast_event_cb) Got event PING from server with EID: '%s'\n", buf);
+	}
+
+	if (ast_eid_cmp(&ast_eid_default,
+			ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
+		/* If the event didn't originate from this server, don't send it back out. */
+		return;
+	}
+
+	/* The ast_event subscription will only exist if we are configured to publish
+	 * these events, so just send away. */
+
+	if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) {
+		ast_log(LOG_WARNING, "CPG mcast failed (%u)\n", cs_err);
+	}
+}
+
 static char *corosync_show_members(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	cs_error_t cs_err;
@@ -639,9 +420,7 @@ static char *corosync_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		return CLI_FAILURE;
 	}
 
-	ast_rwlock_rdlock(&event_types_lock);
-	event_types[AST_EVENT_PING].publish_to_stasis(event);
-	ast_rwlock_unlock(&event_types_lock);
+	ast_event_queue(event);
 
 	return CLI_SUCCESS;
 }
@@ -752,16 +531,11 @@ static int load_general_config(struct ast_config *cfg)
 
 	for (i = 0; i < ARRAY_LEN(event_types); i++) {
 		if (event_types[i].publish && !event_types[i].sub) {
-			event_types[i].sub = stasis_forward_all(event_types[i].topic_fn(),
-													corosync_topic());
-			stasis_message_router_add(stasis_router,
-			                          event_types[i].message_type_fn(),
-			                          stasis_message_cb,
-			                          NULL);
+			event_types[i].sub = ast_event_subscribe(i,
+						ast_event_cb, "Corosync", NULL,
+						AST_EVENT_IE_END);
 		} else if (!event_types[i].publish && event_types[i].sub) {
-			event_types[i].sub = stasis_forward_cancel(event_types[i].sub);
-			stasis_message_router_remove(stasis_router,
-			                             event_types[i].message_type_fn());
+			event_types[i].sub = ast_event_unsubscribe(event_types[i].sub);
 		}
 	}
 
@@ -802,32 +576,14 @@ static void cleanup_module(void)
 	cs_error_t cs_err;
 	unsigned int i;
 
-	if (stasis_router) {
-
-		/* Unsubscribe all topic forwards and cancel all message routes */
-		ast_rwlock_wrlock(&event_types_lock);
-		for (i = 0; i < ARRAY_LEN(event_types); i++) {
-			if (event_types[i].sub) {
-				event_types[i].sub = stasis_forward_cancel(event_types[i].sub);
-				stasis_message_router_remove(stasis_router,
-				                             event_types[i].message_type_fn());
-			}
-			event_types[i].publish = 0;
-			event_types[i].subscribe = 0;
+	for (i = 0; i < ARRAY_LEN(event_types); i++) {
+		if (event_types[i].sub) {
+			event_types[i].sub = ast_event_unsubscribe(event_types[i].sub);
 		}
-		ast_rwlock_unlock(&event_types_lock);
-
-		stasis_message_router_unsubscribe_and_join(stasis_router);
-		stasis_router = NULL;
+		event_types[i].publish = 0;
+		event_types[i].subscribe = 0;
 	}
 
-	if (corosync_aggregate_topic) {
-		ao2_t_ref(corosync_aggregate_topic, -1, "Dispose of topic on cleanup");
-		corosync_aggregate_topic = NULL;
-	}
-
-	STASIS_MESSAGE_TYPE_CLEANUP(corosync_ping_message_type);
-
 	if (dispatch_thread.id != AST_PTHREADT_NULL) {
 		char meepmeep = 'x';
 		dispatch_thread.stop = 1;
@@ -866,30 +622,13 @@ static int load_module(void)
 	enum ast_module_load_result res = AST_MODULE_LOAD_FAILURE;
 	struct cpg_name name;
 
-	corosync_aggregate_topic = stasis_topic_create("corosync_aggregate_topic");
-	if (!corosync_aggregate_topic) {
-		ast_log(AST_LOG_ERROR, "Failed to create stasis topic for corosync\n");
-		goto failed;
-	}
-
-	stasis_router = stasis_message_router_create(corosync_aggregate_topic);
-	if (!stasis_router) {
-		ast_log(AST_LOG_ERROR, "Failed to create message router for corosync topic\n");
-		goto failed;
-	}
-
-	if (STASIS_MESSAGE_TYPE_INIT(corosync_ping_message_type) != 0) {
-		ast_log(AST_LOG_ERROR, "Failed to initialize corosync ping message type\n");
-		goto failed;
-	}
-
 	if ((cs_err = corosync_cfg_initialize(&cfg_handle, &cfg_callbacks)) != CS_OK) {
-		ast_log(LOG_ERROR, "Failed to initialize cfg: (%d)\n", (int) cs_err);
-		goto failed;
+		ast_log(LOG_ERROR, "Failed to initialize cfg (%d)\n", (int) cs_err);
+		return AST_MODULE_LOAD_DECLINE;
 	}
 
 	if ((cs_err = cpg_initialize(&cpg_handle, &cpg_callbacks)) != CS_OK) {
-		ast_log(LOG_ERROR, "Failed to initialize cpg: (%d)\n", (int) cs_err);
+		ast_log(LOG_ERROR, "Failed to initialize cpg (%d)\n", (int) cs_err);
 		goto failed;
 	}
 
@@ -897,7 +636,7 @@ static int load_module(void)
 	name.length = strlen(name.value);
 
 	if ((cs_err = cpg_join(cpg_handle, &name)) != CS_OK) {
-		ast_log(LOG_ERROR, "Failed to join: (%d)\n", (int) cs_err);
+		ast_log(LOG_ERROR, "Failed to join (%d)\n", (int) cs_err);
 		goto failed;
 	}
 
@@ -921,6 +660,8 @@ static int load_module(void)
 
 	ast_cli_register_multiple(corosync_cli, ARRAY_LEN(corosync_cli));
 
+	ast_enable_distributed_devstate();
+
 	return AST_MODULE_LOAD_SUCCESS;
 
 failed:
@@ -938,5 +679,4 @@ static int unload_module(void)
 	return 0;
 }
 
-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Corosync");
-
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Corosync");
diff --git a/res/res_crypto.c b/res/res_crypto.c
index 71634d0..2f0c676 100644
--- a/res/res_crypto.c
+++ b/res/res_crypto.c
@@ -22,7 +22,7 @@
  *
  * \author Mark Spencer <markster at digium.com>
  *
- * Uses the OpenSSL library, available at
+ * \extref Uses the OpenSSL library, available at
  *	http://www.openssl.org/
  */
 
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* use ast_config_AST_KEY_DIR */
 #include <openssl/ssl.h>
@@ -532,7 +532,7 @@ static void md52sum(char *sum, unsigned char *md5)
 {
 	int x;
 	for (x = 0; x < 16; x++) {
-		sum += sprintf(sum, "%02x", (unsigned)*(md5++));
+		sum += sprintf(sum, "%02hhx", *(md5++));
 	}
 }
 
@@ -663,7 +663,6 @@ static int unload_module(void)
 
 /* needs usecount semantics defined */
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Cryptographic Digital Signatures",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_curl.c b/res/res_curl.c
index da35c98..08e6aa1 100644
--- a/res/res_curl.c
+++ b/res/res_curl.c
@@ -22,19 +22,10 @@
  *
  * \author Tilghman Lesher <res_curl_v1 at the-tilghman.com>
  *
- * Depends on the CURL library  - http://curl.haxx.se/
+ * \extref Depends on the CURL library  - http://curl.haxx.se/
  * 
  */
 
-/*! \li \ref res_curl.c uses the configuration file \ref res_curl.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page res_curl.conf res_curl.conf
- * \verbinclude res_curl.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>curl</depend>
 	<support_level>core</support_level>
@@ -42,54 +33,38 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <curl/curl.h>
 
 #include "asterisk/module.h"
 
-static const char *dependents[] = {
-	"func_curl.so",
-	"res_config_curl.so",
-};
-
 static int unload_module(void)
 {
 	int res = 0;
-	size_t i;
 
 	/* If the dependent modules are still in memory, forbid unload */
-	for (i = 0; i < ARRAY_LEN(dependents); i++) {
-		if (ast_module_check(dependents[i])) {
-			ast_log(LOG_ERROR, "%s (dependent module) is still loaded.  Cannot unload res_curl.so\n", dependents[i]);
-			res = -1;
-		}
+	if (ast_module_check("func_curl.so")) {
+		ast_log(LOG_ERROR, "func_curl.so (dependent module) is still loaded.  Cannot unload res_curl.so\n");
+		return -1;
 	}
 
-	if (res)
+	if (ast_module_check("res_config_curl.so")) {
+		ast_log(LOG_ERROR, "res_config_curl.so (dependent module) is still loaded.  Cannot unload res_curl.so\n");
 		return -1;
+	}
 
 	curl_global_cleanup();
 
 	return res;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res = 0;
 
 	if (curl_global_init(CURL_GLOBAL_ALL)) {
-		ast_log(LOG_ERROR, "Unable to initialize the cURL library. Cannot load res_curl.so\n");
+		ast_log(LOG_ERROR, "Unable to initialize the CURL library. Cannot load res_curl\n");
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -97,7 +72,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "cURL Resource Module",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_REALTIME_DEPEND,
diff --git a/res/res_fax.c b/res/res_fax.c
index 46fe99e..16a3d58 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -54,18 +54,9 @@
  * \ingroup applications
  */
 
-/*! \li \ref res_fax.c uses the configuration file \ref res_fax.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page res_fax.conf res_fax.conf
- * \verbinclude res_fax.conf.sample
- */
-
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426529 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/io.h"
 #include "asterisk/file.h"
@@ -83,14 +74,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426529 $")
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
+#include "asterisk/manager.h"
 #include "asterisk/dsp.h"
 #include "asterisk/indications.h"
 #include "asterisk/ast_version.h"
 #include "asterisk/translate.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/smoother.h"
-#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
 	<application name="ReceiveFAX" language="en_US" module="res_fax">
@@ -225,200 +213,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426529 $")
 					<enum name="statusstr">
 						<para>R/O Verbose Result Status of the FAX transmission.</para>
 					</enum>
+					<enum name="t38timeout">
+						<para>R/W The timeout used for T.38 negotiation.</para>
+					</enum>
 				</enumlist>
 			</parameter>
 		</syntax>
 		<description>
 			<para>FAXOPT can be used to override the settings for a FAX session listed in <filename>res_fax.conf</filename>,
-		   	it can also be used to retreive information about a FAX session that has finished eg. pages/status.</para>
+		   	it can also be used to retrieve information about a FAX session that has finished eg. pages/status.</para>
 		</description>
 		<see-also>
 			<ref type="application">ReceiveFax</ref>
 			<ref type="application">SendFax</ref>
 		</see-also>
 	</function>
-	<manager name="FAXSessions" language="en_US">
-		<synopsis>
-			Lists active FAX sessions
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>Will generate a series of FAXSession events with information about each FAXSession. Closes with
-			a FAXSessionsComplete event which includes a count of the included FAX sessions. This action works in
-			the same manner as the CLI command 'fax show sessions'</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="FAXSessionsEntry">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>A single list item for the FAXSessions AMI command</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="Channel">
-					<para>Name of the channel responsible for the FAX session</para>
-				</parameter>
-				<parameter name="Technology">
-					<para>The FAX technology that the FAX session is using</para>
-				</parameter>
-				<parameter name="SessionNumber">
-					<para>The numerical identifier for this particular session</para>
-				</parameter>
-				<parameter name="SessionType">
-					<para>FAX session passthru/relay type</para>
-					<enumlist>
-						<enum name="G.711" />
-						<enum name="T.38" />
-					</enumlist>
-				</parameter>
-				<parameter name="Operation">
-					<para>FAX session operation type</para>
-					<enumlist>
-						<enum name="gateway" />
-						<enum name="V.21" />
-						<enum name="send" />
-						<enum name="receive" />
-						<enum name="none" />
-					</enumlist>
-				</parameter>
-				<parameter name="State">
-					<para>Current state of the FAX session</para>
-					<enumlist>
-						<enum name="Uninitialized" />
-						<enum name="Initialized" />
-						<enum name="Open" />
-						<enum name="Active" />
-						<enum name="Complete" />
-						<enum name="Reserved" />
-						<enum name="Inactive" />
-						<enum name="Unknown" />
-					</enumlist>
-				</parameter>
-				<parameter name="Files">
-					<para>File or list of files associated with this FAX session</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="FAXSessionsComplete">
-		<managerEventInstance class="EVENT_FLAG_CALL">
-			<synopsis>Raised when all FAXSession events are completed for a FAXSessions command</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="Total">
-					<para>Count of FAXSession events sent in response to FAXSessions action</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="FAXSession" language="en_US">
-		<synopsis>
-			Responds with a detailed description of a single FAX session
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="SessionNumber" required="true">
-				<para>The session ID of the fax the user is interested in.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Provides details about a specific FAX session. The response will include a common subset of
-			the output from the CLI command 'fax show session <session_number>' for each technology. If the
-			FAX technolgy used by this session does not include a handler for FAXSession, then this action
-			will fail.</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="FAXSession">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>Raised in response to FAXSession manager command</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="SessionNumber">
-					<para>The numerical identifier for this particular session</para>
-				</parameter>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FAXSessionsEntry']/managerEventInstance/syntax/parameter[@name='Operation'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='FAXSessionsEntry']/managerEventInstance/syntax/parameter[@name='State'])" />
-				<parameter name="ErrorCorrectionMode" required="false">
-					<para>Whether error correcting mode is enabled for the FAX session. This field is not
-					included when operation is 'V.21 Detect' or if operation is 'gateway' and state is
-					'Uninitialized'
-					</para>
-					<enumlist>
-						<enum name="yes" />
-						<enum name="no" />
-					</enumlist>
-				</parameter>
-				<parameter name="DataRate" required="false">
-					<para>Bit rate of the FAX. This field is not included when operation is 'V.21 Detect' or
-					if operation is 'gateway' and state is 'Uninitialized'.</para>
-				</parameter>
-				<parameter name="ImageResolution" required="false">
-					<para>Resolution of each page of the FAX. Will be in the format of X_RESxY_RES. This field
-					is not included if the operation is anything other than Receive/Transmit.</para>
-				</parameter>
-				<parameter name="PageNumber" required="false">
-					<para>Current number of pages transferred during this FAX session. May change as the FAX
-					progresses. This field is not included when operation is 'V.21 Detect' or if operation is
-					'gateway' and state is 'Uninitialized'.</para>
-				</parameter>
-				<parameter name="FileName" required="false">
-					<para>Filename of the image being sent/recieved for this FAX session. This field is not
-					included if Operation isn't 'send' or 'receive'.</para>
-				</parameter>
-				<parameter name="PagesTransmitted" required="false">
-					<para>Total number of pages sent during this session. This field is not included if
-					Operation isn't 'send' or 'receive'. Will always be 0 for 'receive'.</para>
-				</parameter>
-				<parameter name="PagesReceived" required="false">
-					<para>Total number of pages received during this session. This field is not included if
-					Operation is not 'send' or 'receive'. Will be 0 for 'send'.</para>
-				</parameter>
-				<parameter name="TotalBadLines" required="false">
-					<para>Total number of bad lines sent/recieved during this session. This field is not
-					included if Operation is not 'send' or 'received'.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="FAXStats" language="en_US">
-		<synopsis>
-			Responds with fax statistics
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>Provides FAX statistics including the number of active sessions, reserved sessions, completed
-			sessions, failed sessions, and the number of receive/transmit attempts. This command provides all
-			of the non-technology specific information provided by the CLI command 'fax show stats'</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="FAXStats">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>Raised in response to FAXStats manager command</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="CurrentSessions" required="true">
-					<para>Number of active FAX sessions</para>
-				</parameter>
-				<parameter name="ReservedSessions" required="true">
-					<para>Number of reserved FAX sessions</para>
-				</parameter>
-				<parameter name="TransmitAttempts" required="true">
-					<para>Total FAX sessions for which Asterisk is/was the transmitter</para>
-				</parameter>
-				<parameter name="ReceiveAttempts" required="true">
-					<para>Total FAX sessions for which Asterisk is/was the recipient</para>
-				</parameter>
-				<parameter name="CompletedFAXes" required="true">
-					<para>Total FAX sessions which have been completed successfully</para>
-				</parameter>
-				<parameter name="FailedFAXes" required="true">
-					<para>Total FAX sessions which failed to complete successfully</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
 ***/
 
 static const char app_receivefax[] = "ReceiveFAX";
@@ -455,10 +264,10 @@ struct fax_gateway {
 	/*! \brief a flag to track the state of our negotiation */
 	enum ast_t38_state t38_state;
 	/*! \brief original audio formats */
-	struct ast_format *chan_read_format;
-	struct ast_format *chan_write_format;
-	struct ast_format *peer_read_format;
-	struct ast_format *peer_write_format;
+	struct ast_format chan_read_format;
+	struct ast_format chan_write_format;
+	struct ast_format peer_read_format;
+	struct ast_format peer_write_format;
 };
 
 /*! \brief used for fax detect framehook */
@@ -470,7 +279,7 @@ struct fax_detect {
 	/*! \brief DSP Processor */
 	struct ast_dsp *dsp;
 	/*! \brief original audio formats */
-	struct ast_format *orig_format;
+	struct ast_format orig_format;
 	/*! \brief fax session details */
 	struct ast_fax_session_details *details;
 	/*! \brief mode */
@@ -520,7 +329,8 @@ static AST_RWLIST_HEAD_STATIC(faxmodules, fax_module);
 #define RES_FAX_MINRATE 4800
 #define RES_FAX_MAXRATE 14400
 #define RES_FAX_STATUSEVENTS 0
-#define RES_FAX_MODEM (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)
+#define RES_FAX_MODEM (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27TER | AST_FAX_MODEM_V29)
+#define RES_FAX_T38TIMEOUT 5000
 
 struct fax_options {
 	enum ast_fax_modems modems;
@@ -528,6 +338,7 @@ struct fax_options {
 	uint32_t ecm:1;
 	unsigned int minrate;
 	unsigned int maxrate;
+	unsigned int t38timeout;
 };
 
 static struct fax_options general_options;
@@ -538,6 +349,7 @@ static const struct fax_options default_options = {
 	.statusevents = RES_FAX_STATUSEVENTS,
 	.modems = RES_FAX_MODEM,
 	.ecm = AST_FAX_OPTFLAG_TRUE,
+	.t38timeout = RES_FAX_T38TIMEOUT,
 };
 
 AST_RWLOCK_DEFINE_STATIC(options_lock);
@@ -569,6 +381,12 @@ AST_APP_OPTIONS(fax_exec_options, BEGIN_OPTIONS
 	AST_APP_OPTION('z', OPT_REQUEST_T38),
 END_OPTIONS);
 
+struct manager_event_info {
+	char context[AST_MAX_CONTEXT];
+	char exten[AST_MAX_EXTENSION];
+	char cid[128];
+};
+
 static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned int c2s, struct ast_frame *frame)
 {
 	struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
@@ -591,7 +409,7 @@ static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned in
 		history->consec_ms = 0;
 
 		if ((last_consec_frames != 0)) {
-			ast_verb(0, "Channel '%s' fax session '%u', [ %.3ld.%.6ld ], %s sent %u frames (%u ms) of %s.\n",
+			ast_verb(6, "Channel '%s' fax session '%u', [ %.3ld.%.6ld ], %s sent %u frames (%u ms) of %s.\n",
 				 s->channame, s->id, (long) diff.tv_sec, (long int) diff.tv_usec,
 				 (c2s) ? "channel" : "stack", last_consec_frames, last_consec_ms,
 				 (wassil) ? "silence" : "energy");
@@ -609,47 +427,11 @@ static void destroy_callback(void *data)
 	}
 }
 
-static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
-
 static const struct ast_datastore_info fax_datastore = {
 	.type = "res_fax",
 	.destroy = destroy_callback,
-	.chan_fixup = fixup_callback,
 };
 
-static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details);
-static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags);
-static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan);
-
-/*! \brief Copies fax detection and gateway framehooks during masquerades
- *
- * \note must be called with both old_chan and new_chan locked. Since this
- *       is only called by do_masquerade, that shouldn't be an issue.
- */
-static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct ast_fax_session_details *old_details = data;
-	struct ast_datastore *datastore = ast_channel_datastore_find(old_chan, &fax_datastore, NULL);
-
-	if (old_details->gateway_id >= 0) {
-		struct ast_fax_session_details *new_details = find_or_create_details(new_chan);
-
-		ast_framehook_detach(old_chan, old_details->gateway_id);
-		fax_gateway_attach(new_chan, new_details);
-		ao2_cleanup(new_details);
-	}
-
-	if (old_details->faxdetect_id >= 0) {
-		ast_framehook_detach(old_chan, old_details->faxdetect_id);
-		fax_detect_attach(new_chan, old_details->faxdetect_timeout, old_details->faxdetect_flags);
-	}
-
-	if (datastore) {
-		ast_channel_datastore_remove(old_chan, datastore);
-		ast_datastore_free(datastore);
-	}
-}
-
 /*! \brief returns a reference counted pointer to a fax datastore, if it exists */
 static struct ast_fax_session_details *find_details(struct ast_channel *chan)
 {
@@ -713,6 +495,7 @@ static struct ast_fax_session_details *session_details_new(void)
 	d->modems = options.modems;
 	d->minrate = options.minrate;
 	d->maxrate = options.maxrate;
+	d->t38timeout = options.t38timeout;
 	d->gateway_id = -1;
 	d->faxdetect_id = -1;
 	d->gateway_timeout = 0;
@@ -821,7 +604,7 @@ static int update_modem_bits(enum ast_fax_modems *bits, const char *value)
 		if (!strcasecmp(m[j], "v17")) {
 			*bits |= AST_FAX_MODEM_V17;
 		} else if (!strcasecmp(m[j], "v27")) {
-			*bits |= AST_FAX_MODEM_V27;
+			*bits |= AST_FAX_MODEM_V27TER;
 		} else if (!strcasecmp(m[j], "v29")) {
 			*bits |= AST_FAX_MODEM_V29;
 		} else if (!strcasecmp(m[j], "v34")) {
@@ -899,7 +682,7 @@ static int ast_fax_modem_to_str(enum ast_fax_modems bits, char *tbuf, size_t buf
 		strcat(tbuf, "V17");
 		count++;
 	}
-	if (bits & AST_FAX_MODEM_V27) {
+	if (bits & AST_FAX_MODEM_V27TER) {
 		if (count) {
 			strcat(tbuf, ",");
 		}
@@ -928,22 +711,14 @@ static int check_modem_rate(enum ast_fax_modems modems, unsigned int rate)
 {
 	switch (rate) {
 	case 2400:
-		if (!(modems & (AST_FAX_MODEM_V34))) {
-			return 1;
-		}
-		break;
 	case 4800:
-		if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
+		if (!(modems & (AST_FAX_MODEM_V27TER | AST_FAX_MODEM_V34))) {
 			return 1;
 		}
 		break;
 	case 7200:
-		if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
-			return 1;
-		}
-		break;
 	case 9600:
-		if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
+		if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
 			return 1;
 		}
 		break;
@@ -1315,40 +1090,14 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
 	return s;
 }
 
-/*!
- * \internal
- * \brief Convert the filenames in a fax session into a JSON array
- * \retval NULL on error
- * \retval A \ref ast_json array on success
- */
-static struct ast_json *generate_filenames_json(struct ast_fax_session_details *details)
+static void get_manager_event_info(struct ast_channel *chan, struct manager_event_info *info)
 {
-	RAII_VAR(struct ast_json *, json_array, ast_json_array_create(), ast_json_unref);
-	struct ast_fax_document *doc;
-
-	if (!details || !json_array) {
-		return NULL;
-	}
-
-	/* don't process empty lists */
-	if (AST_LIST_EMPTY(&details->documents)) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(&details->documents, doc, next) {
-		struct ast_json *entry = ast_json_string_create(doc->filename);
-		if (!entry) {
-			return NULL;
-		}
-		if (ast_json_array_append(json_array, entry)) {
-			return NULL;
-		}
-	}
-
-	ast_json_ref(json_array);
-	return json_array;
+	pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
+	pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
+	pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
 }
 
+
 /* \brief Generate a string of filenames using the given prefix and separator.
  * \param details the fax session details
  * \param prefix the prefix to each filename
@@ -1369,7 +1118,7 @@ static char *generate_filenames_string(struct ast_fax_session_details *details,
 
 	/* don't process empty lists */
 	if (AST_LIST_EMPTY(&details->documents)) {
-		return ast_strdup("");
+		return NULL;
 	}
 
 	/* Calculate the total length of all of the file names */
@@ -1399,38 +1148,39 @@ static char *generate_filenames_string(struct ast_fax_session_details *details,
 /*! \brief send a FAX status manager event */
 static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
 {
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct ast_json *json_filenames = NULL;
+	char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
 
-	if (!details->option.statusevents) {
-		return 0;
-	}
-
-	json_filenames = generate_filenames_json(details);
-	if (!json_filenames) {
-		return -1;
+	ast_channel_lock(chan);
+	if (details->option.statusevents) {
+		struct manager_event_info info;
+
+		get_manager_event_info(chan, &info);
+		manager_event(EVENT_FLAG_CALL,
+			      "FAXStatus",
+			      "Operation: %s\r\n"
+			      "Status: %s\r\n"
+			      "Channel: %s\r\n"
+			      "Context: %s\r\n"
+			      "Exten: %s\r\n"
+			      "CallerID: %s\r\n"
+			      "LocalStationID: %s\r\n"
+			      "%s%s",
+			      (details->caps & AST_FAX_TECH_GATEWAY) ? "gateway" : (details->caps & AST_FAX_TECH_RECEIVE) ? "receive" : "send",
+			      status,
+			      ast_channel_name(chan),
+			      info.context,
+			      info.exten,
+			      info.cid,
+			      details->localstationid,
+			      S_OR(filenames, ""),
+			      filenames ? "\r\n" : "");
 	}
+	ast_channel_unlock(chan);
 
-	json_object = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
-			"type", "status",
-			"operation", (details->caps & AST_FAX_TECH_GATEWAY) ? "gateway" : (details->caps & AST_FAX_TECH_RECEIVE) ? "receive" : "send",
-			"status", status,
-			"local_station_id", details->localstationid,
-			"filenames", json_filenames);
-	if (!json_object) {
-		return -1;
+	if (filenames) {
+		ast_free(filenames);
 	}
 
-	{
-		SCOPED_CHANNELLOCK(lock, chan);
-
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), ast_channel_fax_type(), json_object);
-		if (!message) {
-			return -1;
-		}
-		stasis_publish(ast_channel_topic(chan), message);
-	}
 	return 0;
 }
 
@@ -1577,18 +1327,20 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 	int timeout = RES_FAX_TIMEOUT;
 	int chancount;
 	unsigned int expected_frametype = -1;
-	struct ast_frame_subclass expected_framesubclass = { .integer = 0, };
+	union ast_frame_subclass expected_framesubclass = { .integer = -1 };
 	unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
 	struct ast_control_t38_parameters t38_parameters;
 	const char *tempvar;
 	struct ast_fax_session *fax = NULL;
 	struct ast_frame *frame = NULL;
 	struct ast_channel *c = chan;
-	RAII_VAR(struct ast_format *, orig_write_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, orig_read_format, NULL, ao2_cleanup);
+	struct ast_format orig_write_format;
+	struct ast_format orig_read_format;
 	int remaining_time;
 	struct timeval start;
 
+	ast_format_clear(&orig_write_format);
+	ast_format_clear(&orig_read_format);
 	chancount = 1;
 
 	/* create the FAX session */
@@ -1612,10 +1364,10 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 	report_fax_status(chan, details, "Allocating Resources");
 
 	if (details->caps & AST_FAX_TECH_AUDIO) {
-		expected_frametype = AST_FRAME_VOICE;
-		expected_framesubclass.format = ast_format_slin;
-		orig_write_format = ao2_bump(ast_channel_writeformat(chan));
-		if (ast_set_write_format(chan, ast_format_slin) < 0) {
+		expected_frametype = AST_FRAME_VOICE;;
+		ast_format_set(&expected_framesubclass.format, AST_FORMAT_SLINEAR, 0);
+		ast_format_copy(&orig_write_format, ast_channel_writeformat(chan));
+		if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 			ast_log(LOG_ERROR, "channel '%s' failed to set write format to signed linear'.\n", ast_channel_name(chan));
  			ao2_lock(faxregistry.container);
  			ao2_unlink(faxregistry.container, fax);
@@ -1624,8 +1376,8 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 			ast_channel_unlock(chan);
 			return -1;
 		}
-		orig_read_format = ao2_bump(ast_channel_readformat(chan));
-		if (ast_set_read_format(chan, ast_format_slin) < 0) {
+		ast_format_copy(&orig_read_format, ast_channel_readformat(chan));
+		if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
 			ast_log(LOG_ERROR, "channel '%s' failed to set read format to signed linear.\n", ast_channel_name(chan));
  			ao2_lock(faxregistry.container);
  			ao2_unlink(faxregistry.container, fax);
@@ -1716,7 +1468,10 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 					break;
 				}
 				if (t38negotiated && !was_t38) {
-					fax->tech->switch_to_t38(fax);
+					if (fax->tech->switch_to_t38(fax)) {
+						GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "T.38 switch failed");
+						break;
+					}
 					details->caps &= ~AST_FAX_TECH_AUDIO;
 					expected_frametype = AST_FRAME_MODEM;
 					expected_framesubclass.integer = AST_MODEM_T38;
@@ -1729,10 +1484,8 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 
 					ast_verb(3, "Channel '%s' switched to T.38 FAX session '%u'.\n", ast_channel_name(chan), fax->id);
 				}
-			} else if ((frame->frametype == expected_frametype) && (expected_framesubclass.integer == frame->subclass.integer) &&
-				((!frame->subclass.format && !expected_framesubclass.format) ||
-				(frame->subclass.format && expected_framesubclass.format &&
-					(ast_format_cmp(frame->subclass.format, expected_framesubclass.format) != AST_FORMAT_CMP_NOT_EQUAL)))) {
+			} else if ((frame->frametype == expected_frametype) &&
+				   (!memcmp(&frame->subclass, &expected_framesubclass, sizeof(frame->subclass)))) {
 				struct ast_frame *f;
 
 				if (fax->smoother) {
@@ -1816,11 +1569,11 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
 	 * restore them now
 	 */
 	if (chancount) {
-		if (orig_read_format) {
-			ast_set_read_format(chan, orig_read_format);
+		if (orig_read_format.id) {
+			ast_set_read_format(chan, &orig_read_format);
 		}
-		if (orig_write_format) {
-			ast_set_write_format(chan, orig_write_format);
+		if (orig_write_format.id) {
+			ast_set_write_format(chan, &orig_write_format);
 		}
 	}
 
@@ -1904,8 +1657,8 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
 	/* request T.38 */
 	ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(chan));
 
-	/* wait up to five seconds for negotiation to complete */
-	timeout_ms = 5000;
+	/* wait for negotiation to complete */
+	timeout_ms = details->t38timeout;
 
 	/* set parameters based on the session's parameters */
 	t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
@@ -1987,79 +1740,13 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
 	return 0;
 }
 
-/*! \brief Report on the final state of a receive fax operation
- * \note This will lock the \ref ast_channel
- */
-static int report_receive_fax_status(struct ast_channel *chan, const char *filename)
-{
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json_array, ast_json_array_create(), ast_json_unref);
-	struct ast_json *json_filename = ast_json_string_create(filename);
-
-	if (!json_array || !json_filename) {
-		ast_json_unref(json_filename);
-		return -1;
-	}
-	ast_json_array_append(json_array, json_filename);
-
-	{
-		const char *remote_station_id;
-		const char *local_station_id;
-		const char *fax_pages;
-		const char *fax_resolution;
-		const char *fax_bitrate;
-		SCOPED_CHANNELLOCK(lock, chan);
-
-		remote_station_id = S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), "");
-		if (!ast_strlen_zero(remote_station_id)) {
-			remote_station_id = ast_strdupa(remote_station_id);
-		}
-		local_station_id = S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), "");
-		if (!ast_strlen_zero(local_station_id)) {
-			local_station_id = ast_strdupa(local_station_id);
-		}
-		fax_pages = S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), "");
-		if (!ast_strlen_zero(fax_pages)) {
-			fax_pages = ast_strdupa(fax_pages);
-		}
-		fax_resolution = S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), "");
-		if (!ast_strlen_zero(fax_resolution)) {
-			fax_resolution = ast_strdupa(fax_resolution);
-		}
-		fax_bitrate = S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), "");
-		if (!ast_strlen_zero(fax_bitrate)) {
-			fax_bitrate = ast_strdupa(fax_bitrate);
-		}
-
-		json_object = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: O}",
-				"type", "receive",
-				"remote_station_id", S_OR(remote_station_id, ""),
-				"local_station_id", S_OR(local_station_id, ""),
-				"fax_pages", S_OR(fax_pages, ""),
-				"fax_resolution", S_OR(fax_resolution, ""),
-				"fax_bitrate", S_OR(fax_bitrate, ""),
-				"filenames", json_array);
-		if (!json_object) {
-			return -1;
-		}
-
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), ast_channel_fax_type(), json_object);
-		if (!message) {
-			return -1;
-		}
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	return 0;
-}
-
 /*! \brief initiate a receive FAX session */
 static int receivefax_exec(struct ast_channel *chan, const char *data)
 {
 	char *parse, modems[128] = "";
 	int channel_alive;
-	RAII_VAR(struct ast_fax_session *, s, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
+	struct ast_fax_session_details *details;
+	struct ast_fax_session *s;
 	struct ast_fax_tech_token *token = NULL;
 	struct ast_fax_document *doc;
 	AST_DECLARE_APP_ARGS(args,
@@ -2067,6 +1754,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(options);
 	);
 	struct ast_flags opts = { 0, };
+	struct manager_event_info info;
 	enum ast_t38_state t38state;
 
 	/* initialize output channel variables */
@@ -2094,6 +1782,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "can't receive a fax on a channel with a T.38 gateway");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "executing ReceiveFAX on a channel with a T.38 Gateway is not supported\n");
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2102,6 +1791,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "maxrate is less than minrate");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "maxrate %u is less than minrate %u\n", details->maxrate, details->minrate);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2111,6 +1801,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2120,6 +1811,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2128,6 +1820,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 	parse = ast_strdupa(data);
@@ -2138,6 +1831,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 	if (ast_strlen_zero(args.filename)) {
@@ -2145,6 +1839,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2154,6 +1849,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s does not support polling\n", app_receivefax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2167,6 +1863,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "error allocating memory");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2199,6 +1896,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "error reserving fax session");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2209,6 +1907,8 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 			set_channel_variables(chan, details);
 			ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", ast_channel_name(chan));
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			return -1;
 		}
 	}
@@ -2219,6 +1919,8 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error negotiating T.38");
 			set_channel_variables(chan, details);
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			return -1;
 		}
 	} else {
@@ -2231,6 +1933,8 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error negotiating T.38");
 			set_channel_variables(chan, details);
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", ast_channel_name(chan));
 			return -1;
 		}
@@ -2246,9 +1950,36 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
 		}
 	}
 
-	if (report_receive_fax_status(chan, args.filename)) {
-		ast_log(AST_LOG_ERROR, "Error publishing ReceiveFax status message\n");
-	}
+	/* send out the AMI completion event */
+	ast_channel_lock(chan);
+
+	get_manager_event_info(chan, &info);
+	manager_event(EVENT_FLAG_CALL,
+		      "ReceiveFAX",
+		      "Channel: %s\r\n"
+		      "Context: %s\r\n"
+		      "Exten: %s\r\n"
+		      "CallerID: %s\r\n"
+		      "RemoteStationID: %s\r\n"
+		      "LocalStationID: %s\r\n"
+		      "PagesTransferred: %s\r\n"
+		      "Resolution: %s\r\n"
+		      "TransferRate: %s\r\n"
+		      "FileName: %s\r\n",
+		      ast_channel_name(chan),
+		      info.context,
+		      info.exten,
+		      info.cid,
+		      S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
+		      args.filename);
+	ast_channel_unlock(chan);
+
+	ao2_ref(s, -1);
+	ao2_ref(details, -1);
 
 	/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
 	return (!channel_alive) ? -1 : 0;
@@ -2494,79 +2225,14 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
 	return 0;
 }
 
-/*!
- * \brief Report on the status of a completed fax send attempt
- * \note This will lock the \ref ast_channel
- */
-static int report_send_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details)
-{
-	RAII_VAR(struct ast_json *, json_obj, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct ast_json *json_filenames;
-
-	json_filenames = generate_filenames_json(details);
-	if (!json_filenames) {
-		return -1;
-	}
-
-	{
-		const char *remote_station_id;
-		const char *local_station_id;
-		const char *fax_pages;
-		const char *fax_resolution;
-		const char *fax_bitrate;
-		SCOPED_CHANNELLOCK(lock, chan);
-
-		remote_station_id = S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), "");
-		if (!ast_strlen_zero(remote_station_id)) {
-			remote_station_id = ast_strdupa(remote_station_id);
-		}
-		local_station_id = S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), "");
-		if (!ast_strlen_zero(local_station_id)) {
-			local_station_id = ast_strdupa(local_station_id);
-		}
-		fax_pages = S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), "");
-		if (!ast_strlen_zero(fax_pages)) {
-			fax_pages = ast_strdupa(fax_pages);
-		}
-		fax_resolution = S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), "");
-		if (!ast_strlen_zero(fax_resolution)) {
-			fax_resolution = ast_strdupa(fax_resolution);
-		}
-		fax_bitrate = S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), "");
-		if (!ast_strlen_zero(fax_bitrate)) {
-			fax_bitrate = ast_strdupa(fax_bitrate);
-		}
-		json_obj = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}",
-				"type", "send",
-				"remote_station_id", S_OR(remote_station_id, ""),
-				"local_station_id", S_OR(local_station_id, ""),
-				"fax_pages", S_OR(fax_pages, ""),
-				"fax_resolution", S_OR(fax_resolution, ""),
-				"fax_bitrate", S_OR(fax_bitrate, ""),
-				"filenames", json_filenames);
-		if (!json_obj) {
-			return -1;
-		}
-
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), ast_channel_fax_type(), json_obj);
-		if (!message) {
-			return -1;
-		}
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	return 0;
-}
-
-
 
 /*! \brief initiate a send FAX session */
 static int sendfax_exec(struct ast_channel *chan, const char *data)
 {
 	char *parse, *filenames, *c, modems[128] = "";
 	int channel_alive, file_count;
-	RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_fax_session *, s, NULL, ao2_cleanup);
+	struct ast_fax_session_details *details;
+	struct ast_fax_session *s;
 	struct ast_fax_tech_token *token = NULL;
 	struct ast_fax_document *doc;
 	AST_DECLARE_APP_ARGS(args,
@@ -2574,6 +2240,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(options);
 	);
 	struct ast_flags opts = { 0, };
+	struct manager_event_info info;
 	enum ast_t38_state t38state;
 
 	/* initialize output channel variables */
@@ -2601,6 +2268,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "can't send a fax on a channel with a T.38 gateway");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "executing SendFAX on a channel with a T.38 Gateway is not supported\n");
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2609,6 +2277,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "maxrate is less than minrate");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "maxrate %u is less than minrate %u\n", details->maxrate, details->minrate);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2618,6 +2287,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2627,6 +2297,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2635,6 +2306,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 	parse = ast_strdupa(data);
@@ -2642,10 +2314,11 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 
 
 	if (!ast_strlen_zero(args.options) &&
-		ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
+	    ast_app_parse_options(fax_exec_options, &opts, NULL, args.options)) {
 		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
+		ao2_ref(details, -1);
 		return -1;
 	}
 	if (ast_strlen_zero(args.filenames)) {
@@ -2653,6 +2326,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2662,6 +2336,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "invalid arguments");
 		set_channel_variables(chan, details);
 		ast_log(LOG_WARNING, "%s does not support polling\n", app_sendfax);
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2675,6 +2350,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error reading file");
 			set_channel_variables(chan, details);
 			ast_log(LOG_ERROR, "access failure.  Verify '%s' exists and check permissions.\n", args.filenames);
+			ao2_ref(details, -1);
 			return -1;
 		}
 
@@ -2683,6 +2359,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error allocating memory");
 			set_channel_variables(chan, details);
 			ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
+			ao2_ref(details, -1);
 			return -1;
 		}
 
@@ -2727,6 +2404,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 		ast_string_field_set(details, resultstr, "error reserving fax session");
 		set_channel_variables(chan, details);
 		ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
+		ao2_ref(details, -1);
 		return -1;
 	}
 
@@ -2737,6 +2415,8 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 			set_channel_variables(chan, details);
 			ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", ast_channel_name(chan));
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			return -1;
 		}
 	}
@@ -2747,6 +2427,8 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error negotiating T.38");
 			set_channel_variables(chan, details);
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			return -1;
 		}
 	} else {
@@ -2759,6 +2441,8 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 			ast_string_field_set(details, resultstr, "error negotiating T.38");
 			set_channel_variables(chan, details);
 			fax_session_release(s, token);
+			ao2_ref(s, -1);
+			ao2_ref(details, -1);
 			ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", ast_channel_name(chan));
 			return -1;
 		}
@@ -2778,13 +2462,42 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
 
 	if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
 		ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
+		ao2_ref(s, -1);
+		ao2_ref(details, -1);
 		return (!channel_alive) ? -1 : 0;
 	}
 
 	/* send out the AMI completion event */
-	if (report_send_fax_status(chan, details)) {
-		ast_log(AST_LOG_ERROR, "Error publishing SendFAX status message\n");
-	}
+	ast_channel_lock(chan);
+	get_manager_event_info(chan, &info);
+	manager_event(EVENT_FLAG_CALL,
+		      "SendFAX",
+		      "Channel: %s\r\n"
+		      "Context: %s\r\n"
+		      "Exten: %s\r\n"
+		      "CallerID: %s\r\n"
+		      "RemoteStationID: %s\r\n"
+		      "LocalStationID: %s\r\n"
+		      "PagesTransferred: %s\r\n"
+		      "Resolution: %s\r\n"
+		      "TransferRate: %s\r\n"
+		      "%s\r\n",
+		      ast_channel_name(chan),
+		      info.context,
+		      info.exten,
+		      info.cid,
+		      S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
+		      S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
+		      filenames);
+	ast_channel_unlock(chan);
+
+	ast_free(filenames);
+
+	ao2_ref(s, -1);
+	ao2_ref(details, -1);
 
 	/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
 	return (!channel_alive) ? -1 : 0;
@@ -2830,11 +2543,6 @@ static void destroy_gateway(void *data)
 		ao2_ref(gateway->s, -1);
 		gateway->s = NULL;
 	}
-
-	ao2_cleanup(gateway->chan_read_format);
-	ao2_cleanup(gateway->chan_write_format);
-	ao2_cleanup(gateway->peer_read_format);
-	ao2_cleanup(gateway->peer_write_format);
 }
 
 /*! \brief Create a new fax gateway object.
@@ -3262,13 +2970,8 @@ static void fax_gateway_framehook_destroy(void *data) {
  */
 static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) {
 	struct fax_gateway *gateway = data;
-	struct ast_channel *active;
-	RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_ref, chan, ao2_cleanup);
-
-	/* Ref bump channel for when we have to unlock it */
-	ao2_ref(chan_ref, 1);
+	struct ast_channel *peer, *active;
+	struct ast_fax_session_details *details;
 
 	if (gateway->s) {
 		details = gateway->s->details;
@@ -3286,39 +2989,38 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 		set_channel_variables(chan, details);
 
 		if (gateway->bridged) {
-			ast_set_read_format(chan, gateway->chan_read_format);
-			ast_set_read_format(chan, gateway->chan_write_format);
+			ast_set_read_format(chan, &gateway->chan_read_format);
+			ast_set_read_format(chan, &gateway->chan_write_format);
 
-			ast_channel_unlock(chan);
-			peer = ast_channel_bridge_peer(chan);
-			if (peer) {
-				ast_set_read_format(peer, gateway->peer_read_format);
-				ast_set_read_format(peer, gateway->peer_write_format);
+			if ((peer = ast_bridged_channel(chan))) {
+				ast_set_read_format(peer, &gateway->peer_read_format);
+				ast_set_read_format(peer, &gateway->peer_write_format);
 				ast_channel_make_compatible(chan, peer);
 			}
-			ast_channel_lock(chan);
 		}
+
+		ao2_ref(details, -1);
 		return NULL;
 	}
 
 	if (!f || (event == AST_FRAMEHOOK_EVENT_ATTACHED)) {
+		ao2_ref(details, -1);
 		return NULL;
 	};
 
 	/* this frame was generated by the fax gateway, pass it on */
 	if (ast_test_flag(f, AST_FAX_FRFLAG_GATEWAY)) {
+		ao2_ref(details, -1);
 		return f;
 	}
 
-	/* If we aren't bridged or we don't have a peer, don't do anything */
-	ast_channel_unlock(chan);
-	peer = ast_channel_bridge_peer(chan);
-	ast_channel_lock(chan);
-	if (!peer) {
+	if (!(peer = ast_bridged_channel(chan))) {
+		/* not bridged, don't do anything */
+		ao2_ref(details, -1);
 		return f;
 	}
 
-	if (!gateway->bridged) {
+	if (!gateway->bridged && peer) {
 		/* don't start a gateway if neither channel can handle T.38 */
 		if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) {
 			ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", ast_channel_name(chan), ast_channel_name(peer));
@@ -3329,6 +3031,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 			ast_string_field_set(details, resultstr, "neither channel supports T.38");
 			ast_string_field_set(details, error, "T38_NEG_ERROR");
 			set_channel_variables(chan, details);
+			ao2_ref(details, -1);
 			return f;
 		}
 
@@ -3338,21 +3041,19 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 
 		/* we are bridged, change r/w formats to SLIN for v21 preamble
 		 * detection and T.30 */
-		ao2_replace(gateway->chan_read_format, ast_channel_readformat(chan));
-		ao2_replace(gateway->chan_write_format, ast_channel_readformat(chan));
+		ast_format_copy(&gateway->chan_read_format, ast_channel_readformat(chan));
+		ast_format_copy(&gateway->chan_write_format, ast_channel_readformat(chan));
 
-		ao2_replace(gateway->peer_read_format, ast_channel_readformat(peer));
-		ao2_replace(gateway->peer_write_format, ast_channel_readformat(peer));
+		ast_format_copy(&gateway->peer_read_format, ast_channel_readformat(peer));
+		ast_format_copy(&gateway->peer_write_format, ast_channel_readformat(peer));
 
-		ast_set_read_format(chan, ast_format_slin);
-		ast_set_write_format(chan, ast_format_slin);
+		ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
+		ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
 
-		ast_channel_unlock(chan);
-		ast_set_read_format(peer, ast_format_slin);
-		ast_set_write_format(peer, ast_format_slin);
+		ast_set_read_format_by_id(peer, AST_FORMAT_SLINEAR);
+		ast_set_write_format_by_id(peer, AST_FORMAT_SLINEAR);
 
 		ast_channel_make_compatible(chan, peer);
-		ast_channel_lock(chan);
 		gateway->bridged = 1;
 	}
 
@@ -3366,6 +3067,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 			ast_string_field_build(details, resultstr, "no fax activity after %d ms", details->gateway_timeout);
 			ast_string_field_set(details, error, "TIMEOUT");
 			set_channel_variables(chan, details);
+			ao2_ref(details, -1);
 			return f;
 		}
 	}
@@ -3373,9 +3075,13 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 	/* only handle VOICE, MODEM, and CONTROL frames*/
 	switch (f->frametype) {
 	case AST_FRAME_VOICE:
-		if ((ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(f->subclass.format, ast_format_alaw) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(f->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) {
+		switch (f->subclass.format.id) {
+		case AST_FORMAT_SLINEAR:
+		case AST_FORMAT_ALAW:
+		case AST_FORMAT_ULAW:
+			break;
+		default:
+			ao2_ref(details, -1);
 			return f;
 		}
 		break;
@@ -3383,13 +3089,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 		if (f->subclass.integer == AST_MODEM_T38) {
 			break;
 		}
+		ao2_ref(details, -1);
 		return f;
 	case AST_FRAME_CONTROL:
 		if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
 			break;
 		}
+		ao2_ref(details, -1);
 		return f;
 	default:
+		ao2_ref(details, -1);
 		return f;
 	}
 
@@ -3403,17 +3112,20 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 		break;
 	default:
 		ast_log(LOG_WARNING, "unhandled framehook event %u\n", event);
+		ao2_ref(details, -1);
 		return f;
 	}
 
 	/* handle control frames */
 	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
+		ao2_ref(details, -1);
 		return fax_gateway_detect_t38(gateway, chan, peer, active, f);
 	}
 
 	if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) {
 		/* not in gateway mode and have not detected v21 yet, listen
 		 * for v21 */
+		ao2_ref(details, -1);
 		return fax_gateway_detect_v21(gateway, chan, peer, active, f);
 	}
 
@@ -3422,10 +3134,11 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 		struct ast_trans_pvt *readtrans;
 		/* framehooks are called in __ast_read() before frame format
 		 * translation is done, so we need to translate here */
-		if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL)
+		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id != AST_FORMAT_SLINEAR)
 			&& (readtrans = ast_channel_readtrans(active))) {
 			if ((f = ast_translate(readtrans, f, 1)) == NULL) {
 				f = &ast_null_frame;
+				ao2_ref(details, -1);
 				return f;
 			}
 			/* XXX we ignore the return value here, perhaps we should
@@ -3439,28 +3152,32 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
 		}
 
 		f = &ast_null_frame;
+		ao2_ref(details, -1);
 		return f;
 	}
 
 	/* force silence on the line if T.38 negotiation might be taking place */
 	if (gateway->t38_state != T38_STATE_UNAVAILABLE && gateway->t38_state != T38_STATE_REJECTED) {
-		if (f->frametype == AST_FRAME_VOICE &&
-			(ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+		if (f->frametype == AST_FRAME_VOICE && f->subclass.format.id == AST_FORMAT_SLINEAR) {
 			short silence_buf[f->samples];
 			struct ast_frame silence_frame = {
 				.frametype = AST_FRAME_VOICE,
-				.subclass.format = ast_format_slin,
 				.data.ptr = silence_buf,
 				.samples = f->samples,
 				.datalen = sizeof(silence_buf),
 			};
+			ast_format_set(&silence_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
 			memset(silence_buf, 0, sizeof(silence_buf));
+
+			ao2_ref(details, -1);
 			return ast_frisolate(&silence_frame);
 		} else {
+			ao2_ref(details, -1);
 			return &ast_null_frame;
 		}
 	}
 
+	ao2_ref(details, -1);
 	return f;
 }
 
@@ -3477,7 +3194,6 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d
 		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
 		.event_cb = fax_gateway_framehook,
 		.destroy_cb = fax_gateway_framehook_destroy,
-		.disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */
 	};
 
 	ast_string_field_set(details, result, "SUCCESS");
@@ -3523,7 +3239,6 @@ static void destroy_faxdetect(void *data)
 		faxdetect->dsp = NULL;
 	}
 	ao2_ref(faxdetect->details, -1);
-	ao2_cleanup(faxdetect->orig_format);
 }
 
 /*! \brief Create a new fax detect object.
@@ -3586,40 +3301,34 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a
 	struct fax_detect *faxdetect = data;
 	struct ast_fax_session_details *details;
 	struct ast_control_t38_parameters *control_params;
-	RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan_ref, chan, ao2_cleanup);
+	struct ast_channel *peer;
 	int result = 0;
 
-	/* Ref bump the channel for when we have to unlock it */
-	ao2_ref(chan, 1);
-
 	details = faxdetect->details;
 
 	switch (event) {
 	case AST_FRAMEHOOK_EVENT_ATTACHED:
 		/* Setup format for DSP on ATTACH*/
-		ao2_replace(faxdetect->orig_format, ast_channel_readformat(chan));
-
-		if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_slin) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) {
-			if (ast_set_read_format(chan, ast_format_slin)) {
-				ast_framehook_detach(chan, details->faxdetect_id);
-				details->faxdetect_id = -1;
-				return f;
-			}
+		ast_format_copy(&faxdetect->orig_format, ast_channel_readformat(chan));
+		switch (ast_channel_readformat(chan)->id) {
+			case AST_FORMAT_SLINEAR:
+			case AST_FORMAT_ALAW:
+			case AST_FORMAT_ULAW:
+				break;
+			default:
+				if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+					ast_framehook_detach(chan, details->faxdetect_id);
+					details->faxdetect_id = -1;
+					return f;
+				}
 		}
-
 		return NULL;
 	case AST_FRAMEHOOK_EVENT_DETACHED:
 		/* restore audio formats when we are detached */
-		ast_set_read_format(chan, faxdetect->orig_format);
-		ast_channel_unlock(chan);
-		peer = ast_channel_bridge_peer(chan);
-		if (peer) {
+		ast_set_read_format(chan, &faxdetect->orig_format);
+		if ((peer = ast_bridged_channel(chan))) {
 			ast_channel_make_compatible(chan, peer);
 		}
-		ast_channel_lock(chan);
 		return NULL;
 	case AST_FRAMEHOOK_EVENT_READ:
 		if (f) {
@@ -3648,10 +3357,13 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a
 			return f;
 		}
 		/* We can only process some formats*/
-		if ((ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(f->subclass.format, ast_format_alaw) != AST_FORMAT_CMP_EQUAL) &&
-			(ast_format_cmp(f->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) {
-			return f;
+		switch (f->subclass.format.id) {
+			case AST_FORMAT_SLINEAR:
+			case AST_FORMAT_ALAW:
+			case AST_FORMAT_ULAW:
+				break;
+			default:
+				return f;
 		}
 		break;
 	case AST_FRAME_CONTROL:
@@ -3744,8 +3456,6 @@ static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags)
 	faxdetect->details = details;
 	ast_channel_lock(chan);
 	details->faxdetect_id = ast_framehook_attach(chan, &fr_hook);
-	details->faxdetect_timeout = timeout;
-	details->faxdetect_flags = flags;
 	ast_channel_unlock(chan);
 
 	if (details->faxdetect_id < 0) {
@@ -3923,6 +3633,7 @@ static char *cli_fax_show_settings(struct ast_cli_entry *e, int cmd, struct ast_
 	ast_cli(a->fd, "\tMaximum Bit Rate: %u\n", options.maxrate);
 	ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
 	ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
+	ast_cli(a->fd, "\tT.38 Negotiation Timeout: %u\n", options.t38timeout);
 	ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
 	AST_RWLIST_RDLOCK(&faxmodules);
 	AST_RWLIST_TRAVERSE(&faxmodules, fax, list) {
@@ -3970,43 +3681,6 @@ static char *cli_fax_show_session(struct ast_cli_entry *e, int cmd, struct ast_c
 	return CLI_SUCCESS;
 }
 
-static int manager_fax_session(struct mansession *s, const struct message *m)
-{
-	const char *action_id = astman_get_header(m, "ActionID");
-	const char *session_number = astman_get_header(m, "SessionNumber");
-	char id_text[256] = "";
-	struct ast_fax_session *session;
-	struct ast_fax_session find_session;
-
-	if (sscanf(session_number, "%30u", &find_session.id) != 1) {
-		astman_send_error(s, m, "Invalid session ID");
-		return 0;
-	}
-
-	session = ao2_find(faxregistry.container, &find_session, OBJ_POINTER);
-	if (!session) {
-		astman_send_error(s, m, "Session not found");
-		return 0;
-	}
-
-	if (!session->tech->manager_fax_session) {
-		astman_send_error(s, m, "Fax technology doesn't provide a handler for FAXSession");
-		ao2_ref(session, -1);
-		return 0;
-	}
-
-	if (!ast_strlen_zero(action_id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", action_id);
-	}
-
-	astman_send_ack(s, m, "FAXSession event will follow");
-
-	session->tech->manager_fax_session(s, id_text, session);
-	ao2_ref(session, -1);
-
-	return 0;
-}
-
 /*! \brief display fax stats */
 static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -4040,36 +3714,7 @@ static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli
 	return CLI_SUCCESS;
 }
 
-static int manager_fax_stats(struct mansession *s, const struct message *m)
-{
-	const char *action_id = astman_get_header(m, "ActionID");
-
-	char id_text[256] = "";
-
-	astman_send_ack(s, m, "FAXStats event will follow");
-
-	if (!ast_strlen_zero(action_id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", action_id);
-	}
-
-	astman_append(s, "Event: FAXStats\r\n"
-		"%s"
-		"CurrentSessions: %d\r\n"
-		"ReservedSessions: %d\r\n"
-		"TransmitAttempts: %d\r\n"
-		"ReceiveAttempts: %d\r\n"
-		"CompletedFAXes: %d\r\n"
-		"FailedFAXes: %d\r\n"
-		"\r\n",
-		id_text,
-		faxregistry.active_sessions, faxregistry.reserved_sessions,
-		faxregistry.fax_tx_attempts, faxregistry.fax_rx_attempts,
-		faxregistry.fax_complete, faxregistry.fax_failures);
-
-	return 0;
-}
-
-static const char *fax_session_type(struct ast_fax_session *s)
+static const char *cli_session_type(struct ast_fax_session *s)
 {
 	if (s->details->caps & AST_FAX_TECH_AUDIO) {
 		return "G.711";
@@ -4081,7 +3726,7 @@ static const char *fax_session_type(struct ast_fax_session *s)
 	return "none";
 }
 
-const char *ast_fax_session_operation_str(struct ast_fax_session *s)
+static const char *cli_session_operation(struct ast_fax_session *s)
 {
 	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
 		return "gateway";
@@ -4129,8 +3774,8 @@ static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_
 
 		ast_cli(a->fd, "%-20.20s %-10.10s %-10u %-5.5s %-10.10s %-15.15s %-30s\n",
 			s->channame, s->tech->type, s->id,
-			fax_session_type(s),
-			ast_fax_session_operation_str(s),
+			cli_session_type(s),
+			cli_session_operation(s),
 			ast_fax_state_to_str(s->state), S_OR(filenames, ""));
 
 		ast_free(filenames);
@@ -4144,72 +3789,6 @@ static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_
 	return CLI_SUCCESS;
 }
 
-static int manager_fax_sessions_entry(struct mansession *s,
-	struct ast_fax_session *session, const char *id_text)
-{
-	char *filenames;
-
-	ao2_lock(session);
-	filenames = generate_filenames_string(session->details, "", ",");
-
-	if (!filenames) {
-		ast_log(LOG_ERROR, "Error generating Files string");
-		ao2_unlock(session);
-		return -1;
-	}
-
-	astman_append(s, "Event: FAXSessionsEntry\r\n"
-		"%s" /* ActionID if present */
-		"Channel: %s\r\n" /* Channel name */
-		"Technology: %s\r\n" /* Fax session technology */
-		"SessionNumber: %u\r\n" /* Session ID */
-		"SessionType: %s\r\n" /* G711 or T38 */
-		"Operation: %s\r\n"
-		"State: %s\r\n"
-		"Files: %s\r\n"
-		"\r\n",
-		id_text, session->channame, session->tech->type, session->id,
-		fax_session_type(session), ast_fax_session_operation_str(session),
-		ast_fax_state_to_str(session->state), S_OR(filenames, ""));
-	ast_free(filenames);
-	ao2_unlock(session);
-	return 0;
-}
-
-static int manager_fax_sessions(struct mansession *s, const struct message *m)
-{
-	const char *action_id = astman_get_header(m, "ActionID");
-	char id_text[256] = "";
-	struct ast_fax_session *session;
-	struct ao2_iterator iter;
-	int session_count = 0;
-
-	astman_send_listack(s, m, "FAXSessionsEntry event list will follow", "Start");
-
-	if (!ast_strlen_zero(action_id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", action_id);
-	}
-
-	iter = ao2_iterator_init(faxregistry.container, 0);
-	while ((session = ao2_iterator_next(&iter))) {
-		if (!manager_fax_sessions_entry(s, session, id_text)) {
-			session_count++;
-		}
-		ao2_ref(session, -1);
-	}
-	ao2_iterator_destroy(&iter);
-
-	astman_append(s, "Event: FAXSessionsComplete\r\n"
-		"%s"
-		"EventList: Complete\r\n"
-		"Total: %d\r\n"
-		"\r\n",
-		id_text,
-		session_count);
-
-	return 0;
-}
-
 static struct ast_cli_entry fax_cli[] = {
 	AST_CLI_DEFINE(cli_fax_show_version, "Show versions of FAX For Asterisk components"),
 	AST_CLI_DEFINE(cli_fax_set_debug, "Enable/Disable FAX debugging on new FAX sessions"),
@@ -4234,6 +3813,23 @@ static void get_general_options(struct fax_options *options)
 	ast_rwlock_unlock(&options_lock);
 }
 
+static int set_t38timeout(const char *value, unsigned int *t38timeout)
+{
+	unsigned int timeout;
+
+	if (sscanf(value, "%u", &timeout) != 1) {
+		ast_log(LOG_ERROR, "Unable to get timeout from '%s'\n", value);
+		return -1;
+	} else if (timeout) {
+		*t38timeout = timeout;
+	} else {
+		ast_log(LOG_ERROR, "T.38 negotiation timeout must be non-zero\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*! \brief configure res_fax */
 static int set_config(int reload)
 {
@@ -4303,6 +3899,11 @@ static int set_config(int reload)
 		} else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
 			options.modems = 0;
 			update_modem_bits(&options.modems, v->value);
+		} else if (!strcasecmp(v->name, "t38timeout")) {
+			if (set_t38timeout(v->value, &options.t38timeout)) {
+				res = -1;
+				goto end;
+			}
 		}
 	}
 
@@ -4395,6 +3996,8 @@ static int acf_faxopt_read(struct ast_channel *chan, const char *cmd, char *data
 		ast_copy_string(buf, details->resultstr, len);
 	} else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
 		ast_fax_modem_to_str(details->modems, buf, len);
+	} else if (!strcasecmp(data, "t38timeout")) {
+		snprintf(buf, len, "%u", details->t38timeout);
 	} else {
 		ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", ast_channel_name(chan), data);
 		res = -1;
@@ -4521,6 +4124,10 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat
 		if (!details->minrate) {
 			details->minrate = ast_fax_minrate();
 		}
+	} else if (!strcasecmp(data, "t38timeout")) {
+		if (set_t38timeout(value, &details->t38timeout)) {
+			res = -1;
+		}
 	} else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) {
 		update_modem_bits(&details->modems, value);
 	} else {
@@ -4557,10 +4164,6 @@ static int unload_module(void)
 		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
 	}
 
-	ast_manager_unregister("FAXSessions");
-	ast_manager_unregister("FAXSession");
-	ast_manager_unregister("FAXStats");
-
 	if (fax_logger_level != -1) {
 		ast_logger_unregister_level("FAX");
 	}
@@ -4570,16 +4173,7 @@ static int unload_module(void)
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
+/*! \brief load res_fax */
 static int load_module(void)
 {
 	int res;
@@ -4610,33 +4204,6 @@ static int load_module(void)
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	if (ast_manager_register_xml("FAXSessions", EVENT_FLAG_CALL, manager_fax_sessions)) {
-		ast_log(LOG_WARNING, "failed to register 'FAXSessions' AMI command.\n");
-		ast_unregister_application(app_receivefax);
-		ast_unregister_application(app_sendfax);
-		ao2_ref(faxregistry.container, -1);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_manager_register_xml("FAXSession", EVENT_FLAG_CALL, manager_fax_session)) {
-		ast_log(LOG_WARNING, "failed to register 'FAXSession' AMI command.\n");
-		ast_manager_unregister("FAXSession");
-		ast_unregister_application(app_receivefax);
-		ast_unregister_application(app_sendfax);
-		ao2_ref(faxregistry.container, -1);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_manager_register_xml("FAXStats", EVENT_FLAG_REPORTING, manager_fax_stats)) {
-		ast_log(LOG_WARNING, "failed to register 'FAXStats' AMI command.\n");
-		ast_manager_unregister("FAXSession");
-		ast_manager_unregister("FAXSessions");
-		ast_unregister_application(app_receivefax);
-		ast_unregister_application(app_sendfax);
-		ao2_ref(faxregistry.container, -1);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
 	ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
 	res = ast_custom_function_register(&acf_faxopt);
 	fax_logger_level = ast_logger_register_level("FAX");
@@ -4652,7 +4219,6 @@ static int reload_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic FAX Applications",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_fax.exports.in b/res/res_fax.exports.in
index e2f3a7d..1b0e364 100644
--- a/res/res_fax.exports.in
+++ b/res/res_fax.exports.in
@@ -6,7 +6,6 @@
 		LINKER_SYMBOL_PREFIXast_fax_minrate;
 		LINKER_SYMBOL_PREFIXast_fax_maxrate;
 		LINKER_SYMBOL_PREFIXast_fax_state_to_str;
-		LINKER_SYMBOL_PREFIXast_fax_session_operation_str;
 		LINKER_SYMBOL_PREFIXast_fax_log;
 	local:
 		*;
diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c
index c6bd09b..30525ee 100644
--- a/res/res_fax_spandsp.c
+++ b/res/res_fax_spandsp.c
@@ -50,7 +50,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423372 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
 #include <spandsp.h>
@@ -65,7 +65,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423372 $")
 #include "asterisk/astobj2.h"
 #include "asterisk/res_fax.h"
 #include "asterisk/channel.h"
-#include "asterisk/format_cache.h"
 
 #define SPANDSP_FAX_SAMPLES 160
 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES	/* 50 ticks per second, 20ms, 160 samples per second */
@@ -87,8 +86,6 @@ static void spandsp_v21_tone(void *data, int code, int level, int delay);
 
 static char *spandsp_fax_cli_show_capabilities(int fd);
 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
-static void spandsp_manager_fax_session(struct mansession *s,
-	const char *id_text, struct ast_fax_session *session);
 static char *spandsp_fax_cli_show_stats(int fd);
 static char *spandsp_fax_cli_show_settings(int fd);
 
@@ -116,7 +113,6 @@ static struct ast_fax_tech spandsp_fax_tech = {
 	.switch_to_t38 = spandsp_fax_switch_to_t38,
 	.cli_show_capabilities = spandsp_fax_cli_show_capabilities,
 	.cli_show_session = spandsp_fax_cli_show_session,
-	.manager_fax_session = spandsp_manager_fax_session,
 	.cli_show_stats = spandsp_fax_cli_show_stats,
 	.cli_show_settings = spandsp_fax_cli_show_settings,
 };
@@ -502,7 +498,7 @@ static int spandsp_modems(struct ast_fax_session_details *details)
 	if (AST_FAX_MODEM_V17 & details->modems) {
 		modems |= T30_SUPPORT_V17;
 	}
-	if (AST_FAX_MODEM_V27 & details->modems) {
+	if (AST_FAX_MODEM_V27TER & details->modems) {
 		modems |= T30_SUPPORT_V27TER;
 	}
 	if (AST_FAX_MODEM_V29 & details->modems) {
@@ -627,9 +623,9 @@ static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
 	struct ast_frame fax_frame = {
 		.frametype = AST_FRAME_VOICE,
 		.src = "res_fax_spandsp_g711",
-		.subclass.format = ast_format_slin,
 	};
 	struct ast_frame *f = &fax_frame;
+	ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	if (ast_timer_ack(p->timer, 1) < 0) {
 		ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id);
@@ -682,21 +678,20 @@ static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame
 		return -1;
 	}
 
-	ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format=%s  }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, ast_format_get_name(f->subclass.format));
+	ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format.id=%u  }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, f->subclass.format.id);
 
 	/* slinear frame can be passed to spandsp */
-	if (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
+	if (f->subclass.format.id == AST_FORMAT_SLINEAR) {
 		modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
 
 	/* alaw/ulaw frame must be converted to slinear before passing to spandsp */
-	} else if (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ||
-	           ast_format_cmp(f->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
+	} else if (f->subclass.format.id == AST_FORMAT_ALAW || f->subclass.format.id == AST_FORMAT_ULAW) {
 		if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) {
 			return -1;
 		}
-		decoder = g711_init(NULL, (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ? G711_ALAW : G711_ULAW));
+		decoder = g711_init(NULL, (f->subclass.format.id == AST_FORMAT_ALAW ? G711_ALAW : G711_ULAW));
 		g711_decode(decoder, slndata, f->data.ptr, f->samples);
-		ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", ast_format_get_name(f->subclass.format));
+		ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", (f->subclass.format.id == AST_FORMAT_ALAW ? "G711_ALAW" : "G711_ULAW"));
 		modem_connect_tones_rx(p->tone_state, slndata, f->samples);
 		g711_release(decoder);
 #if SPANDSP_RELEASE_DATE >= 20090220
@@ -706,7 +701,7 @@ static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame
 
 	/* frame in other formats cannot be passed to spandsp, it could cause segfault */
 	} else {
-		ast_log(LOG_WARNING, "Frame format %s not supported, v.21 detection skipped\n", ast_format_get_name(f->subclass.format));
+		ast_log(LOG_WARNING, "Unknown frame format %u, v.21 detection skipped\n", f->subclass.format.id);
 		return -1;
 	}
 
@@ -768,7 +763,6 @@ static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len,
 	struct ast_frame *f;
 	struct ast_frame t30_frame = {
 		.frametype = AST_FRAME_VOICE,
-		.subclass.format = ast_format_slin,
 		.src = "res_fax_spandsp_g711",
 		.samples = samples,
 		.flags = AST_FAX_FRFLAG_GATEWAY,
@@ -776,6 +770,7 @@ static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len,
 
 	AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
 
+	ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
 	if (!(f = ast_frisolate(&t30_frame))) {
 		return p->isdone ? -1 : res;
 	}
@@ -809,7 +804,7 @@ static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
 	struct spandsp_pvt *p = s->tech_pvt;
 	struct ast_fax_t38_parameters *t38_param;
 	int i;
-	RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
+	struct ast_channel *peer;
 	static struct ast_generator t30_gen = {
 		.alloc = spandsp_fax_gw_gen_alloc,
 		.release = spandsp_fax_gw_gen_release,
@@ -830,7 +825,7 @@ static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
 
 	p->ist38 = 1;
 	p->ast_t38_state = ast_channel_get_t38_state(s->chan);
-	if (!(peer = ast_channel_bridge_peer(s->chan))) {
+	if (!(peer = ast_bridged_channel(s->chan))) {
 		ast_channel_unlock(s->chan);
 		return -1;
 	}
@@ -897,8 +892,7 @@ static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct a
 	/* Process a IFP packet */
 	if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
 		return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
-	} else if ((f->frametype == AST_FRAME_VOICE) &&
-		(ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
+	} else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
 		return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
 	}
 
@@ -1096,97 +1090,6 @@ static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
 	return CLI_SUCCESS;
 }
 
-static void spandsp_manager_fax_session(struct mansession *s,
-	const char *id_text, struct ast_fax_session *session)
-{
-	struct ast_str *message_string;
-	struct spandsp_pvt *span_pvt = session->tech_pvt;
-	int res;
-
-	message_string = ast_str_create(128);
-
-	if (!message_string) {
-		return;
-	}
-
-	ao2_lock(session);
-	res = ast_str_append(&message_string, 0, "SessionNumber: %u\r\n", session->id);
-	res |= ast_str_append(&message_string, 0, "Operation: %s\r\n", ast_fax_session_operation_str(session));
-	res |= ast_str_append(&message_string, 0, "State: %s\r\n", ast_fax_state_to_str(session->state));
-
-	if (session->details->caps & AST_FAX_TECH_GATEWAY) {
-		t38_stats_t stats;
-
-		if (session->state == AST_FAX_STATE_UNINITIALIZED) {
-			goto skip_cap_additions;
-		}
-
-		t38_gateway_get_transfer_statistics(&span_pvt->t38_gw_state, &stats);
-		res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
-			stats.error_correcting_mode ? "yes" : "no");
-		res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
-			stats.bit_rate);
-		res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
-			stats.pages_transferred + 1);
-	} else if (!(session->details->caps & AST_FAX_TECH_V21_DETECT)) { /* caps is SEND/RECEIVE */
-		t30_stats_t stats;
-
-		if (session->state == AST_FAX_STATE_UNINITIALIZED) {
-			goto skip_cap_additions;
-		}
-
-		t30_get_transfer_statistics(span_pvt->t30_state, &stats);
-		res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
-			stats.error_correcting_mode ? "Yes" : "No");
-		res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
-			stats.bit_rate);
-		res |= ast_str_append(&message_string, 0, "ImageResolution: %dx%d\r\n",
-			stats.x_resolution, stats.y_resolution);
-#if SPANDSP_RELEASE_DATE >= 20090220
-		res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
-			((session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
-#else
-		res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
-			stats.pages_transferred + 1);
-#endif
-		res |= ast_str_append(&message_string, 0, "FileName: %s\r\n",
-			session->details->caps & AST_FAX_TECH_RECEIVE ? span_pvt->t30_state->rx_file :
-			span_pvt->t30_state->tx_file);
-#if SPANDSP_RELEASE_DATE >= 20090220
-		res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
-			stats.pages_tx);
-		res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
-			stats.pages_rx);
-#else
-		res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
-			(session->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
-		res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
-			(session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
-#endif
-		res |= ast_str_append(&message_string, 0, "TotalBadLines: %d\r\n",
-			stats.bad_rows);
-	}
-
-skip_cap_additions:
-
-	ao2_unlock(session);
-
-	if (res < 0) {
-		/* One or more of the ast_str_append attempts failed, cancel the message */
-		ast_free(message_string);
-		return;
-	}
-
-	astman_append(s, "Event: FAXSession\r\n"
-		"%s"
-		"%s"
-		"\r\n",
-		id_text,
-		ast_str_buffer(message_string));
-
-	ast_free(message_string);
-}
-
 /*! \brief */
 static char *spandsp_fax_cli_show_stats(int fd)
 {
@@ -1257,7 +1160,6 @@ static int load_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 	       );
diff --git a/res/res_format_attr_celt.c b/res/res_format_attr_celt.c
index 6e3191b..1249f04 100644
--- a/res/res_format_attr_celt.c
+++ b/res/res_format_attr_celt.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/format.h"
@@ -45,148 +45,152 @@ struct celt_attr {
 	unsigned int framesize;
 };
 
-static void celt_destroy(struct ast_format *format)
+static int celt_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
 {
-	struct celt_attr *attr = ast_format_get_attribute_data(format);
-
-	ast_free(attr);
-}
-
-static int celt_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct celt_attr *original = ast_format_get_attribute_data(src);
-	struct celt_attr *attr = ast_calloc(1, sizeof(*attr));
-
-	if (!attr) {
-		return -1;
-	}
-
-	if (original) {
-		*attr = *original;
-	}
-
-	ast_format_set_attribute_data(dst, attr);
-
-	return 0;
-}
-
-static struct ast_format *celt_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
-{
-	struct ast_format *cloned;
-	struct celt_attr *attr;
+	struct celt_attr *attr = (struct celt_attr *) format_attr;
 	unsigned int val;
 
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
 	if (sscanf(attributes, "framesize=%30u", &val) == 1) {
 		attr->framesize = val;
 	}
 
-	return cloned;
+	return 0;
 }
 
-static void celt_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+static void celt_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
 {
-	struct celt_attr *attr = ast_format_get_attribute_data(format);
+	struct celt_attr *attr = (struct celt_attr *) format_attr;
 
-	if (!attr || !attr->framesize) {
+	if (!attr->framesize) {
 		return;
 	}
 
 	ast_str_append(str, 0, "a=fmtp:%u framesize=%u\r\n", payload, attr->framesize);
 }
 
-static enum ast_format_cmp_res celt_cmp(const struct ast_format *format1, const struct ast_format *format2)
+static enum ast_format_cmp_res celt_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
 {
-	struct celt_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct celt_attr *attr2 = ast_format_get_attribute_data(format2);
+	struct celt_attr *attr1 = (struct celt_attr *) fattr1;
+	struct celt_attr *attr2 = (struct celt_attr *) fattr2;
 
-	if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) ||
-		(attr1->samplerate == attr2->samplerate)) {
+	if (attr1->samplerate == attr2->samplerate) {
 		return AST_FORMAT_CMP_EQUAL;
 	}
-
 	return AST_FORMAT_CMP_NOT_EQUAL;
 }
 
-static struct ast_format *celt_getjoint(const struct ast_format *format1, const struct ast_format *format2)
+static int celt_get_val(const struct ast_format_attr *fattr, int key, void *result)
 {
-	struct celt_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct celt_attr *attr2 = ast_format_get_attribute_data(format2);
-	struct ast_format *jointformat;
-	struct celt_attr *jointattr;
-
-	if (attr1 && attr2 && (attr1->samplerate != attr2->samplerate)) {
-		return NULL;
+	const struct celt_attr *attr = (struct celt_attr *) fattr;
+	int *val = result;
+
+	switch (key) {
+	case CELT_ATTR_KEY_SAMP_RATE:
+		*val = attr->samplerate;
+		break;
+	case CELT_ATTR_KEY_MAX_BITRATE:
+		*val = attr->maxbitrate;
+		break;
+	case CELT_ATTR_KEY_FRAME_SIZE:
+		*val = attr->framesize;
+		break;
+	default:
+		ast_log(LOG_WARNING, "unknown attribute type %d\n", key);
+		return -1;
 	}
+	return 0;
+}
 
-	jointformat = ast_format_clone(format1);
-	if (!jointformat) {
-		return NULL;
+static int celt_isset(const struct ast_format_attr *fattr, va_list ap)
+{
+	enum celt_attr_keys key;
+	const struct celt_attr *attr = (struct celt_attr *) fattr;
+
+	for (key = va_arg(ap, int);
+		key != AST_FORMAT_ATTR_END;
+		key = va_arg(ap, int))
+	{
+		switch (key) {
+		case CELT_ATTR_KEY_SAMP_RATE:
+			if (attr->samplerate != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case CELT_ATTR_KEY_MAX_BITRATE:
+			if (attr->maxbitrate != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case CELT_ATTR_KEY_FRAME_SIZE:
+			if (attr->framesize != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		default:
+			ast_log(LOG_WARNING, "unknown attribute type %u\n", key);
+			return -1;
+		}
 	}
-	jointattr = ast_format_get_attribute_data(jointformat);
+	return 0;
+}
+static int celt_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
+{
+	struct celt_attr *attr1 = (struct celt_attr *) fattr1;
+	struct celt_attr *attr2 = (struct celt_attr *) fattr2;
+	struct celt_attr *attr_res = (struct celt_attr *) result;
 
+	/* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */
+	if (attr1->samplerate != attr2->samplerate) {
+		return -1;
+	}
 	/* either would work, they are guaranteed the same at this point. */
-	jointattr->samplerate = attr1->samplerate;
+	attr_res->samplerate = attr1->samplerate;
 	/* Take the lowest max bitrate */
-	jointattr->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
-
-	jointattr->framesize = attr2->framesize; /* TODO figure out what joint framesize means */
+	attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
 
-	return jointformat;
+	attr_res->framesize = attr2->framesize; /* TODO figure out what joint framesize means */
+	return 0;
 }
 
-static struct ast_format *celt_set(const struct ast_format *format, const char *name, const char *value)
+static void celt_set(struct ast_format_attr *fattr, va_list ap)
 {
-	struct ast_format *cloned;
-	struct celt_attr *attr;
-	unsigned int val;
-
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	if (sscanf(value, "%30u", &val) != 1) {
-		ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
-			value, name);
-		ao2_ref(cloned, -1);
-		return NULL;
+	enum celt_attr_keys key;
+	struct celt_attr *attr = (struct celt_attr *) fattr;
+
+	for (key = va_arg(ap, int);
+		key != AST_FORMAT_ATTR_END;
+		key = va_arg(ap, int))
+	{
+		switch (key) {
+		case CELT_ATTR_KEY_SAMP_RATE:
+			attr->samplerate = (va_arg(ap, int));
+			break;
+		case CELT_ATTR_KEY_MAX_BITRATE:
+			attr->maxbitrate = (va_arg(ap, int));
+			break;
+		case CELT_ATTR_KEY_FRAME_SIZE:
+			attr->framesize = (va_arg(ap, int));
+			break;
+		default:
+			ast_log(LOG_WARNING, "unknown attribute type %u\n", key);
+		}
 	}
-
-	if (!strcasecmp(name, "sample_rate")) {
-		attr->samplerate = val;
-	} else if (!strcasecmp(name, "max_bitrate")) {
-		attr->maxbitrate = val;
-	} else if (!strcasecmp(name, "frame_size")) {
-		attr->framesize = val;
-	} else {
-		ast_log(LOG_WARNING, "Unknown attribute type '%s'\n", name);
-		ao2_ref(cloned, -1);
-		return NULL;
-	}
-
-	return cloned;
 }
 
-static struct ast_format_interface celt_interface = {
-	.format_destroy = celt_destroy,
-	.format_clone = celt_clone,
-	.format_cmp = celt_cmp,
-	.format_get_joint = celt_getjoint,
-	.format_attribute_set = celt_set,
-	.format_parse_sdp_fmtp = celt_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = celt_generate_sdp_fmtp,
+static struct ast_format_attr_interface celt_interface = {
+	.id = AST_FORMAT_CELT,
+	.format_attr_cmp = celt_cmp,
+	.format_attr_get_joint = celt_getjoint,
+	.format_attr_set = celt_set,
+	.format_attr_isset = celt_isset,
+	.format_attr_get_val = celt_get_val,
+	.format_attr_sdp_parse = celt_sdp_parse,
+	.format_attr_sdp_generate = celt_sdp_generate,
 };
 
 static int load_module(void)
 {
-	if (ast_format_interface_register("celt", &celt_interface)) {
+	if (ast_format_attr_reg_interface(&celt_interface)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -195,11 +199,11 @@ static int load_module(void)
 
 static int unload_module(void)
 {
+	ast_format_attr_unreg_interface(&celt_interface);
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "CELT Format Attribute Module",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_format_attr_h263.c b/res/res_format_attr_h263.c
index 88bb379..8ec28aa 100644
--- a/res/res_format_attr_h263.c
+++ b/res/res_format_attr_h263.c
@@ -33,236 +33,255 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/format.h"
 
-struct h263_attr {
-	unsigned int SQCIF;       /*!< Minimum picture interval for SQCIF resolution */
-	unsigned int QCIF;        /*!< Minimum picture interval for QCIF resolution */
-	unsigned int CIF;         /*!< Minimum picture interval for CIF resolution */
-	unsigned int CIF4;        /*!< Minimum picture interval for CIF4 resolution */
-	unsigned int CIF16;       /*!< Minimum picture interval for CIF16 resolution */
-	unsigned int VGA;         /*!< Minimum picture interval for VGA resolution */
-	unsigned int CUSTOM_XMAX; /*!< Custom resolution (Xmax) */
-	unsigned int CUSTOM_YMAX; /*!< Custom resolution (Ymax) */
-	unsigned int CUSTOM_MPI;  /*!< Custom resolution (MPI) */
-	unsigned int F;           /*!< F annex support */
-	unsigned int I;           /*!< I annex support */
-	unsigned int J;           /*!< J annex support */
-	unsigned int T;           /*!< T annex support */
-	unsigned int K;           /*!< K annex support */
-	unsigned int N;           /*!< N annex support */
-	unsigned int P_SUB1;      /*!< Reference picture resampling (sub mode 1) */
-	unsigned int P_SUB2;      /*!< Reference picture resampling (sub mode 2) */
-	unsigned int P_SUB3;      /*!< Reference picture resampling (sub mode 3) */
-	unsigned int P_SUB4;      /*!< Reference picture resampling (sub mode 4) */
-	unsigned int PAR_WIDTH;   /*!< Pixel aspect ratio (width) */
-	unsigned int PAR_HEIGHT;  /*!< Pixel aspect ratio (height) */
-	unsigned int BPP;         /*!< Bits per picture maximum */
-	unsigned int HRD;         /*!< Hypothetical reference decoder status */
+enum h263_attr_keys {
+	H263_ATTR_KEY_SQCIF,       /*!< Minimum picture interval for SQCIF resolution */
+	H263_ATTR_KEY_QCIF,        /*!< Minimum picture interval for QCIF resolution */
+	H263_ATTR_KEY_CIF,         /*!< Minimum picture interval for CIF resolution */
+	H263_ATTR_KEY_CIF4,        /*!< Minimum picture interval for CIF4 resolution */
+	H263_ATTR_KEY_CIF16,       /*!< Minimum picture interval for CIF16 resolution */
+	H263_ATTR_KEY_VGA,         /*!< Minimum picture interval for VGA resolution */
+	H263_ATTR_KEY_CUSTOM_XMAX, /*!< Custom resolution (Xmax) */
+	H263_ATTR_KEY_CUSTOM_YMAX, /*!< Custom resolution (Ymax) */
+	H263_ATTR_KEY_CUSTOM_MPI,  /*!< Custom resolution (MPI) */
+	H263_ATTR_KEY_F,           /*!< F annex support */
+	H263_ATTR_KEY_I,           /*!< I annex support */
+	H263_ATTR_KEY_J,           /*!< J annex support */
+	H263_ATTR_KEY_T,           /*!< T annex support */
+	H263_ATTR_KEY_K,           /*!< K annex support */
+	H263_ATTR_KEY_N,           /*!< N annex support */
+	H263_ATTR_KEY_P_SUB1,      /*!< Reference picture resampling (sub mode 1) */
+	H263_ATTR_KEY_P_SUB2,      /*!< Reference picture resampling (sub mode 2) */
+	H263_ATTR_KEY_P_SUB3,      /*!< Reference picture resampling (sub mode 3) */
+	H263_ATTR_KEY_P_SUB4,      /*!< Reference picture resampling (sub mode 4) */
+	H263_ATTR_KEY_PAR_WIDTH,   /*!< Pixel aspect ratio (width) */
+	H263_ATTR_KEY_PAR_HEIGHT,  /*!< Pixel aspect ratio (height) */
+	H263_ATTR_KEY_BPP,         /*!< Bits per picture maximum */
+	H263_ATTR_KEY_HRD,         /*!< Hypothetical reference decoder status */
+	H263_ATTR_KEY_END,         /*!< End terminator for list */
 };
 
-static void h263_destroy(struct ast_format *format)
+static int h263_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
 {
-	struct h263_attr *attr = ast_format_get_attribute_data(format);
+	int i;
 
-	ast_free(attr);
-}
-
-static int h263_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct h263_attr *original = ast_format_get_attribute_data(src);
-	struct h263_attr *attr = ast_calloc(1, sizeof(*attr));
-
-	if (!attr) {
-		return -1;
-	}
-
-	if (original) {
-		*attr = *original;
+	/* These are all receiver options so we just copy over what they sent */
+	for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
+		result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i];
 	}
 
-	ast_format_set_attribute_data(dst, attr);
-
 	return 0;
 }
 
-static enum ast_format_cmp_res h263_cmp(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct h263_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct h263_attr *attr2 = ast_format_get_attribute_data(format2);
-
-	if (!attr1 || !attr2 || (attr1 && attr2 && !memcmp(attr1, attr2, sizeof(*attr1)))) {
-		return AST_FORMAT_CMP_EQUAL;
-	}
-	return AST_FORMAT_CMP_NOT_EQUAL;
-}
-
-#define DETERMINE_JOINT(joint, attr1, attr2, field) (joint->field = (attr1 && attr1->field) ? attr1->field : (attr2 && attr2->field) ? attr2->field : 0)
-
-static struct ast_format *h263_getjoint(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct ast_format *cloned;
-	struct h263_attr *attr, *attr1, *attr2;
-
-	cloned = ast_format_clone(format1);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	attr1 = ast_format_get_attribute_data(format1);
-	attr2 = ast_format_get_attribute_data(format2);
-
-	DETERMINE_JOINT(attr, attr1, attr2, SQCIF);
-	DETERMINE_JOINT(attr, attr1, attr2, QCIF);
-	DETERMINE_JOINT(attr, attr1, attr2, CIF);
-	DETERMINE_JOINT(attr, attr1, attr2, CIF4);
-	DETERMINE_JOINT(attr, attr1, attr2, CIF16);
-	DETERMINE_JOINT(attr, attr1, attr2, VGA);
-	DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_XMAX);
-	DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_YMAX);
-	DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_MPI);
-	DETERMINE_JOINT(attr, attr1, attr2, F);
-	DETERMINE_JOINT(attr, attr1, attr2, I);
-	DETERMINE_JOINT(attr, attr1, attr2, J);
-	DETERMINE_JOINT(attr, attr1, attr2, T);
-	DETERMINE_JOINT(attr, attr1, attr2, K);
-	DETERMINE_JOINT(attr, attr1, attr2, N);
-	DETERMINE_JOINT(attr, attr1, attr2, P_SUB1);
-	DETERMINE_JOINT(attr, attr1, attr2, P_SUB2);
-	DETERMINE_JOINT(attr, attr1, attr2, P_SUB3);
-	DETERMINE_JOINT(attr, attr1, attr2, P_SUB4);
-	DETERMINE_JOINT(attr, attr1, attr2, PAR_WIDTH);
-	DETERMINE_JOINT(attr, attr1, attr2, PAR_HEIGHT);
-	DETERMINE_JOINT(attr, attr1, attr2, BPP);
-	DETERMINE_JOINT(attr, attr1, attr2, HRD);
-
-	return cloned;
-}
-
-static struct ast_format *h263_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
+static int h263_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
 {
 	char *attribs = ast_strdupa(attributes), *attrib;
-	struct ast_format *cloned;
-	struct h263_attr *attr;
-
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
 
 	while ((attrib = strsep(&attribs, ";"))) {
 		unsigned int val, val2 = 0, val3 = 0, val4 = 0;
 
 		if (sscanf(attrib, "SQCIF=%30u", &val) == 1) {
-			attr->SQCIF = val;
+			format_attr->format_attr[H263_ATTR_KEY_SQCIF] = val;
 		} else if (sscanf(attrib, "QCIF=%30u", &val) == 1) {
-			attr->QCIF = val;
+			format_attr->format_attr[H263_ATTR_KEY_QCIF] = val;
 		} else if (sscanf(attrib, "CIF=%30u", &val) == 1) {
-			attr->CIF = val;
+			format_attr->format_attr[H263_ATTR_KEY_CIF] = val;
 		} else if (sscanf(attrib, "CIF4=%30u", &val) == 1) {
-			attr->CIF4 = val;
+			format_attr->format_attr[H263_ATTR_KEY_CIF4] = val;
 		} else if (sscanf(attrib, "CIF16=%30u", &val) == 1) {
-			attr->CIF16 = val;
+			format_attr->format_attr[H263_ATTR_KEY_CIF16] = val;
 		} else if (sscanf(attrib, "VGA=%30u", &val) == 1) {
-			attr->VGA = val;
+			format_attr->format_attr[H263_ATTR_KEY_VGA] = val;
 		} else if (sscanf(attrib, "CUSTOM=%30u,%30u,%30u", &val, &val2, &val3) == 3) {
-			attr->CUSTOM_XMAX = val;
-			attr->CUSTOM_YMAX = val2;
-			attr->CUSTOM_MPI = val3;
+			format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] = val;
+			format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] = val2;
+			format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI] = val3;
 		} else if (sscanf(attrib, "F=%30u", &val) == 1) {
-			attr->F = val;
+			format_attr->format_attr[H263_ATTR_KEY_F] = val;
 		} else if (sscanf(attrib, "I=%30u", &val) == 1) {
-			attr->I = val;
+			format_attr->format_attr[H263_ATTR_KEY_I] = val;
 		} else if (sscanf(attrib, "J=%30u", &val) == 1) {
-			attr->J = val;
+			format_attr->format_attr[H263_ATTR_KEY_J] = val;
 		} else if (sscanf(attrib, "T=%30u", &val) == 1) {
-			attr->T = val;
+			format_attr->format_attr[H263_ATTR_KEY_T] = val;
 		} else if (sscanf(attrib, "K=%30u", &val) == 1) {
-			attr->K = val;
+			format_attr->format_attr[H263_ATTR_KEY_K] = val;
 		} else if (sscanf(attrib, "N=%30u", &val) == 1) {
-			attr->N = val;
+			format_attr->format_attr[H263_ATTR_KEY_N] = val;
 		} else if (sscanf(attrib, "PAR=%30u:%30u", &val, &val2) == 2) {
-			attr->PAR_WIDTH = val;
-			attr->PAR_HEIGHT = val2;
+			format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] = val;
+			format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT] = val2;
 		} else if (sscanf(attrib, "BPP=%30u", &val) == 1) {
-			attr->BPP = val;
+			format_attr->format_attr[H263_ATTR_KEY_BPP] = val;
 		} else if (sscanf(attrib, "HRD=%30u", &val) == 1) {
-			attr->HRD = val;
+			format_attr->format_attr[H263_ATTR_KEY_HRD] = val;
 		} else if (sscanf(attrib, "P=%30u,%30u,%30u,%30u", &val, &val2, &val3, &val4) > 0) {
-			attr->P_SUB1 = val;
-			attr->P_SUB2 = val2;
-			attr->P_SUB3 = val3;
-			attr->P_SUB4 = val4;
+			format_attr->format_attr[H263_ATTR_KEY_P_SUB1] = val;
+			format_attr->format_attr[H263_ATTR_KEY_P_SUB2] = val2;
+			format_attr->format_attr[H263_ATTR_KEY_P_SUB3] = val3;
+			format_attr->format_attr[H263_ATTR_KEY_P_SUB4] = val4;
 		}
 	}
 
-	return cloned;
+	return 0;
 }
 
-static void h263_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+/*! \brief Helper function which converts a key enum into a string value for SDP */
+static const char *h263_attr_key_to_str(enum h263_attr_keys key, const struct ast_format_attr *format_attr)
 {
-	struct h263_attr *attr = ast_format_get_attribute_data(format);
-
-	if (!attr) {
-		return;
-	}
-
-	ast_str_append(str, 0, "a=fmtp:%u SQCIF=%u;QCIF=%u;CIF=%u;CIF4=%u;CIF16=%u;VGA=%u;F=%u;I=%u;J=%u;T=%u;K=%u;N=%u;BPP=%u;HRD=%u",
-		payload, attr->SQCIF, attr->QCIF, attr->CIF, attr->CIF4, attr->CIF16, attr->VGA, attr->F, attr->I, attr->J,
-		attr->T, attr->K, attr->N, attr->BPP, attr->HRD);
-
-	if (attr->CUSTOM_XMAX && attr->CUSTOM_YMAX && attr->CUSTOM_MPI) {
-		ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", attr->CUSTOM_XMAX, attr->CUSTOM_YMAX, attr->CUSTOM_MPI);
+	switch (key) {
+	case H263_ATTR_KEY_SQCIF:
+		return format_attr->format_attr[key] ? "SQCIF" : NULL;
+	case H263_ATTR_KEY_QCIF:
+		return format_attr->format_attr[key] ? "QCIF" : NULL;
+	case H263_ATTR_KEY_CIF:
+		return format_attr->format_attr[key] ? "CIF" : NULL;
+	case H263_ATTR_KEY_CIF4:
+		return format_attr->format_attr[key] ? "CIF4" : NULL;
+	case H263_ATTR_KEY_CIF16:
+		return format_attr->format_attr[key] ? "CIF16" : NULL;
+	case H263_ATTR_KEY_VGA:
+		return format_attr->format_attr[key] ? "VGA" : NULL;
+	case H263_ATTR_KEY_F:
+		return "F";
+	case H263_ATTR_KEY_I:
+		return "I";
+	case H263_ATTR_KEY_J:
+		return "J";
+	case H263_ATTR_KEY_T:
+		return "T";
+	case H263_ATTR_KEY_K:
+		return "K";
+	case H263_ATTR_KEY_N:
+		return "N";
+	case H263_ATTR_KEY_BPP:
+		return "BPP";
+	case H263_ATTR_KEY_HRD:
+		return "HRD";
+	case H263_ATTR_KEY_CUSTOM_XMAX:
+	case H263_ATTR_KEY_CUSTOM_YMAX:
+	case H263_ATTR_KEY_CUSTOM_MPI:
+	case H263_ATTR_KEY_P_SUB1:
+	case H263_ATTR_KEY_P_SUB2:
+	case H263_ATTR_KEY_P_SUB3:
+	case H263_ATTR_KEY_P_SUB4:
+	case H263_ATTR_KEY_PAR_WIDTH:
+	case H263_ATTR_KEY_PAR_HEIGHT:
+	case H263_ATTR_KEY_END:
+	default:
+		return NULL;
 	}
 
-	if (attr->PAR_WIDTH && attr->PAR_HEIGHT) {
-		ast_str_append(str, 0, ";PAR=%u:%u", attr->PAR_WIDTH, attr->PAR_HEIGHT);
-	}
+	return NULL;
+}
 
-	if (attr->P_SUB1) {
-		ast_str_append(str, 0, ";P=%u", attr->P_SUB1);
-		if (attr->P_SUB2) {
-			ast_str_append(str, 0, ",%u", attr->P_SUB2);
-		}
-		if (attr->P_SUB3) {
-			ast_str_append(str, 0, ",%u", attr->P_SUB3);
-		}
-		if (attr->P_SUB4) {
-			ast_str_append(str, 0, ",%u", attr->P_SUB4);
+static void h263_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
+{
+	int i, added = 0;
+
+	for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
+		const char *name;
+
+		if (i == H263_ATTR_KEY_CUSTOM_XMAX) {
+			if (!format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] || !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] ||
+			    !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]) {
+				continue;
+			}
+
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u CUSTOM=%u,%u,%u", payload, format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
+					       format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
+					       format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
+			}
+		} else if (i == H263_ATTR_KEY_PAR_WIDTH) {
+			if (!format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] || !format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]) {
+				continue;
+			}
+
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u PAR=%u:%u", payload, format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
+					       format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";PAR=%u:%u", format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
+					       format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
+			}
+		} else if (i == H263_ATTR_KEY_P_SUB1) {
+			if (!format_attr->format_attr[H263_ATTR_KEY_P_SUB1]) {
+				continue;
+			}
+
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u P=%u", payload, format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";P=%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
+			}
+
+			if (format_attr->format_attr[H263_ATTR_KEY_P_SUB2]) {
+				ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB2]);
+			}
+                        if (format_attr->format_attr[H263_ATTR_KEY_P_SUB3]) {
+                                ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB3]);
+                        }
+                        if (format_attr->format_attr[H263_ATTR_KEY_P_SUB4]) {
+                                ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB4]);
+                        }
+
+		} else if ((name = h263_attr_key_to_str(i, format_attr))) {
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u %s=%u", payload, name, format_attr->format_attr[i]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]);
+			}
 		}
 	}
 
-	ast_str_append(str, 0, "\r\n");
+	if (added) {
+		ast_str_append(str, 0, "\r\n");
+	}
 
 	return;
 }
 
-static struct ast_format_interface h263_interface = {
-	.format_destroy = h263_destroy,
-	.format_clone = h263_clone,
-	.format_cmp = h263_cmp,
-	.format_get_joint = h263_getjoint,
-	.format_parse_sdp_fmtp = h263_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = h263_generate_sdp_fmtp,
+static struct ast_format_attr_interface h263_format_attr_interface = {
+	.id = AST_FORMAT_H263,
+	.format_attr_get_joint = h263_format_attr_get_joint,
+	.format_attr_sdp_parse = h263_format_attr_sdp_parse,
+	.format_attr_sdp_generate = h263_format_attr_sdp_generate,
+};
+
+static struct ast_format_attr_interface h263p_format_attr_interface = {
+        .id = AST_FORMAT_H263_PLUS,
+	.format_attr_get_joint = h263_format_attr_get_joint,
+        .format_attr_sdp_parse = h263_format_attr_sdp_parse,
+        .format_attr_sdp_generate = h263_format_attr_sdp_generate,
 };
 
 static int unload_module(void)
 {
+	ast_format_attr_unreg_interface(&h263_format_attr_interface);
+	ast_format_attr_unreg_interface(&h263p_format_attr_interface);
+
 	return 0;
 }
 
 static int load_module(void)
 {
-	if (ast_format_interface_register("h263", &h263_interface)) {
+	if (ast_format_attr_reg_interface(&h263_format_attr_interface)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	if (ast_format_interface_register("h263p", &h263_interface)) {
+	if (ast_format_attr_reg_interface(&h263p_format_attr_interface)) {
+		ast_format_attr_unreg_interface(&h263_format_attr_interface);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -270,7 +289,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "H.263 Format Attribute Module",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_DEFAULT,
diff --git a/res/res_format_attr_h264.c b/res/res_format_attr_h264.c
index 37637fa..2bd47e0 100644
--- a/res/res_format_attr_h264.c
+++ b/res/res_format_attr_h264.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/format.h"
@@ -50,284 +50,266 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
  *   H264_MAX_SPS_PPS_SIZE */
 #define H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "15"
 
-struct h264_attr {
-	unsigned int PROFILE_IDC;
-	unsigned int PROFILE_IOP;
-	unsigned int LEVEL;
-	unsigned int MAX_MBPS;
-	unsigned int MAX_FS;
-	unsigned int MAX_CPB;
-	unsigned int MAX_DPB;
-	unsigned int MAX_BR;
-	unsigned int MAX_SMBPS;
-	unsigned int MAX_FPS;
-	unsigned int REDUNDANT_PIC_CAP;
-	unsigned int PARAMETER_ADD;
-	unsigned int PACKETIZATION_MODE;
-	unsigned int SPROP_INTERLEAVING_DEPTH;
-	unsigned int SPROP_DEINT_BUF_REQ;
-	unsigned int DEINT_BUF_CAP;
-	unsigned int SPROP_INIT_BUF_TIME;
-	unsigned int SPROP_MAX_DON_DIFF;
-	unsigned int MAX_RCMD_NALU_SIZE;
-	unsigned int LEVEL_ASYMMETRY_ALLOWED;
-	char SPS[H264_MAX_SPS_PPS_SIZE];
-	char PPS[H264_MAX_SPS_PPS_SIZE];
+enum h264_attr_keys {
+	H264_ATTR_KEY_PROFILE_IDC,
+	H264_ATTR_KEY_PROFILE_IOP,
+	H264_ATTR_KEY_LEVEL,
+	H264_ATTR_KEY_MAX_MBPS,
+	H264_ATTR_KEY_MAX_FS,
+	H264_ATTR_KEY_MAX_CPB,
+	H264_ATTR_KEY_MAX_DPB,
+	H264_ATTR_KEY_MAX_BR,
+	H264_ATTR_KEY_MAX_SMBPS,
+	H264_ATTR_KEY_MAX_FPS,
+	H264_ATTR_KEY_REDUNDANT_PIC_CAP,
+	H264_ATTR_KEY_PARAMETER_ADD,
+	H264_ATTR_KEY_PACKETIZATION_MODE,
+	H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH,
+	H264_ATTR_KEY_SPROP_DEINT_BUF_REQ,
+	H264_ATTR_KEY_DEINT_BUF_CAP,
+	H264_ATTR_KEY_SPROP_INIT_BUF_TIME,
+	H264_ATTR_KEY_SPROP_MAX_DON_DIFF,
+	H264_ATTR_KEY_MAX_RCMD_NALU_SIZE,
+	H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED,
+	H264_ATTR_KEY_SPS_LEN,
+	H264_ATTR_KEY_PPS_LEN,
+	H264_ATTR_KEY_SPS,
+	H264_ATTR_KEY_PPS = H264_ATTR_KEY_SPS + H264_MAX_SPS_PPS_SIZE,
+	H264_ATTR_KEY_END = H264_ATTR_KEY_PPS + H264_MAX_SPS_PPS_SIZE,
 };
 
-static void h264_destroy(struct ast_format *format)
+static enum ast_format_cmp_res h264_format_attr_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
 {
-	struct h264_attr *attr = ast_format_get_attribute_data(format);
-
-	ast_free(attr);
-}
-
-static int h264_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct h264_attr *original = ast_format_get_attribute_data(src);
-	struct h264_attr *attr = ast_calloc(1, sizeof(*attr));
-
-	if (!attr) {
-		return -1;
-	}
-
-	if (original) {
-		*attr = *original;
-	}
-
-	ast_format_set_attribute_data(dst, attr);
-
-	return 0;
-}
-
-static enum ast_format_cmp_res h264_cmp(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct h264_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct h264_attr *attr2 = ast_format_get_attribute_data(format2);
-
-	if (!attr1 || !attr1->PROFILE_IDC || !attr2 || !attr2->PROFILE_IDC ||
-		(attr1->PROFILE_IDC == attr2->PROFILE_IDC)) {
+	if (!fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] || !fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC] ||
+	    (fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] == fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC])) {
 		return AST_FORMAT_CMP_EQUAL;
 	}
 
 	return AST_FORMAT_CMP_NOT_EQUAL;
 }
 
-#define DETERMINE_JOINT(joint, attr1, attr2, field) (joint->field = (attr1 && attr1->field) ? attr1->field : (attr2 && attr2->field) ? attr2->field : 0)
-
-static struct ast_format *h264_getjoint(const struct ast_format *format1, const struct ast_format *format2)
+static int h264_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
 {
-	struct ast_format *cloned;
-	struct h264_attr *attr, *attr1, *attr2;
-
-	cloned = ast_format_clone(format1);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	attr1 = ast_format_get_attribute_data(format1);
-	attr2 = ast_format_get_attribute_data(format2);
-
-	DETERMINE_JOINT(attr, attr1, attr2, PROFILE_IDC);
-	DETERMINE_JOINT(attr, attr1, attr2, PROFILE_IOP);
-	DETERMINE_JOINT(attr, attr1, attr2, LEVEL);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_MBPS);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_FS);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_CPB);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_DPB);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_BR);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_SMBPS);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_FPS);
-	DETERMINE_JOINT(attr, attr1, attr2, REDUNDANT_PIC_CAP);
-	DETERMINE_JOINT(attr, attr1, attr2, PARAMETER_ADD);
-	DETERMINE_JOINT(attr, attr1, attr2, SPROP_INTERLEAVING_DEPTH);
-	DETERMINE_JOINT(attr, attr1, attr2, SPROP_DEINT_BUF_REQ);
-	DETERMINE_JOINT(attr, attr1, attr2, DEINT_BUF_CAP);
-	DETERMINE_JOINT(attr, attr1, attr2, SPROP_INIT_BUF_TIME);
-	DETERMINE_JOINT(attr, attr1, attr2, SPROP_MAX_DON_DIFF);
-	DETERMINE_JOINT(attr, attr1, attr2, MAX_RCMD_NALU_SIZE);
-	DETERMINE_JOINT(attr, attr1, attr2, LEVEL_ASYMMETRY_ALLOWED);
-	DETERMINE_JOINT(attr, attr1, attr2, PACKETIZATION_MODE);
-
-	if (attr1 && !ast_strlen_zero(attr1->SPS)) {
-		ast_copy_string(attr->SPS, attr1->SPS, sizeof(attr->SPS));
-	} else if (attr2 && !ast_strlen_zero(attr2->SPS)) {
-		ast_copy_string(attr->SPS, attr1->SPS, sizeof(attr->SPS));
-	}
+	int i;
 
-	if (attr1 && !ast_strlen_zero(attr1->PPS)) {
-		ast_copy_string(attr->PPS, attr1->PPS, sizeof(attr->PPS));
-	} else if (attr2 && !ast_strlen_zero(attr2->PPS)) {
-		ast_copy_string(attr->PPS, attr1->PPS, sizeof(attr->PPS));
+	for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) {
+		result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i];
 	}
 
-	return cloned;
+	return 0;
 }
 
-static struct ast_format *h264_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
+static int h264_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
 {
 	char *attribs = ast_strdupa(attributes), *attrib;
-	struct ast_format *cloned;
-	struct h264_attr *attr;
 
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	attr->REDUNDANT_PIC_CAP = H264_ATTR_KEY_UNSET;
-	attr->PARAMETER_ADD = H264_ATTR_KEY_UNSET;
-	attr->PACKETIZATION_MODE = H264_ATTR_KEY_UNSET;
-	attr->LEVEL_ASYMMETRY_ALLOWED = H264_ATTR_KEY_UNSET;
+	format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = H264_ATTR_KEY_UNSET;
+	format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = H264_ATTR_KEY_UNSET;
+	format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = H264_ATTR_KEY_UNSET;
+	format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = H264_ATTR_KEY_UNSET;
 
 	while ((attrib = strsep(&attribs, ";"))) {
 		unsigned int val;
 		unsigned long int val2;
+		char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE];
 
 		if (sscanf(attrib, "profile-level-id=%lx", &val2) == 1) {
-			attr->PROFILE_IDC = ((val2 >> 16) & 0xFF);
-			attr->PROFILE_IOP = ((val2 >> 8) & 0xFF);
-			attr->LEVEL = (val2 & 0xFF);
-		} else if (sscanf(attrib, "sprop-parameter-sets=%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "[^','],%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "s", attr->SPS, attr->PPS) == 2) {
+			format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] = ((val2 >> 16) & 0xFF);
+			format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] = ((val2 >> 8) & 0xFF);
+			format_attr->format_attr[H264_ATTR_KEY_LEVEL] = (val2 & 0xFF);
+		} else if (sscanf(attrib, "sprop-parameter-sets=%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "[^','],%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "s", sps, pps) == 2) {
 			/* XXX sprop-parameter-sets can actually be of unlimited length. This may need to be addressed later. */
+			unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, };
+			int i;
+
+			ast_base64decode(spsdecoded, sps, sizeof(spsdecoded));
+			ast_base64decode(ppsdecoded, pps, sizeof(ppsdecoded));
+
+			format_attr->format_attr[H264_ATTR_KEY_SPS_LEN] = 0;
+			format_attr->format_attr[H264_ATTR_KEY_PPS_LEN] = 0;
+
+			for (i = 0; i < H264_MAX_SPS_PPS_SIZE; i++) {
+				if (spsdecoded[i]) {
+					format_attr->format_attr[H264_ATTR_KEY_SPS + i] = spsdecoded[i];
+					format_attr->format_attr[H264_ATTR_KEY_SPS_LEN]++;
+				}
+				if (ppsdecoded[i]) {
+					format_attr->format_attr[H264_ATTR_KEY_PPS + i] = ppsdecoded[i];
+					format_attr->format_attr[H264_ATTR_KEY_PPS_LEN]++;
+				}
+			}
 		} else if (sscanf(attrib, "max-mbps=%30u", &val) == 1) {
-			attr->MAX_MBPS = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_MBPS] = val;
 		} else if (sscanf(attrib, "max-fs=%30u", &val) == 1) {
-			attr->MAX_FS = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_FS] = val;
 		} else if (sscanf(attrib, "max-cpb=%30u", &val) == 1) {
-			attr->MAX_CPB = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_CPB] = val;
 		} else if (sscanf(attrib, "max-dpb=%30u", &val) == 1) {
-			attr->MAX_DPB = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_DPB] = val;
 		} else if (sscanf(attrib, "max-br=%30u", &val) == 1) {
-			attr->MAX_BR = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_BR] = val;
 		} else if (sscanf(attrib, "max-smbps=%30u", &val) == 1) {
-			attr->MAX_SMBPS = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_SMBPS] = val;
 		} else if (sscanf(attrib, "max-fps=%30u", &val) == 1) {
-			attr->MAX_FPS = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_FPS] = val;
 		} else if (sscanf(attrib, "redundant-pic-cap=%30u", &val) == 1) {
-			attr->REDUNDANT_PIC_CAP = val;
+			format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = val;
 		} else if (sscanf(attrib, "parameter-add=%30u", &val) == 1) {
-			attr->PARAMETER_ADD = val;
+			format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = val;
 		} else if (sscanf(attrib, "packetization-mode=%30u", &val) == 1) {
-			attr->PACKETIZATION_MODE = val;
+			format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = val;
 		} else if (sscanf(attrib, "sprop-interleaving-depth=%30u", &val) == 1) {
-			attr->SPROP_INTERLEAVING_DEPTH = val;
+			format_attr->format_attr[H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH] = val;
 		} else if (sscanf(attrib, "sprop-deint-buf-req=%30u", &val) == 1) {
-			attr->SPROP_DEINT_BUF_REQ = val;
+			format_attr->format_attr[H264_ATTR_KEY_SPROP_DEINT_BUF_REQ] = val;
 		} else if (sscanf(attrib, "deint-buf-cap=%30u", &val) == 1) {
-			attr->DEINT_BUF_CAP = val;
+			format_attr->format_attr[H264_ATTR_KEY_DEINT_BUF_CAP] = val;
 		} else if (sscanf(attrib, "sprop-init-buf-time=%30u", &val) == 1) {
-			attr->SPROP_INIT_BUF_TIME = val;
+			format_attr->format_attr[H264_ATTR_KEY_SPROP_INIT_BUF_TIME] = val;
 		} else if (sscanf(attrib, "sprop-max-don-diff=%30u", &val) == 1) {
-			attr->SPROP_MAX_DON_DIFF = val;
+			format_attr->format_attr[H264_ATTR_KEY_SPROP_MAX_DON_DIFF] = val;
 		} else if (sscanf(attrib, "max-rcmd-nalu-size=%30u", &val) == 1) {
-			attr->MAX_RCMD_NALU_SIZE = val;
+			format_attr->format_attr[H264_ATTR_KEY_MAX_RCMD_NALU_SIZE] = val;
 		} else if (sscanf(attrib, "level-asymmetry-allowed=%30u", &val) == 1) {
-			attr->LEVEL_ASYMMETRY_ALLOWED = val;
+			format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = val;
 		}
 	}
 
-	return cloned;
+	return 0;
 }
 
-#define APPEND_IF_NOT_H264_UNSET(field, str, name) do {		\
-	if (field != H264_ATTR_KEY_UNSET) {	\
-		if (added) {	\
-			ast_str_append(str, 0, ";");	\
-		} else {	\
-			added = 1;	\
-		}	\
-		ast_str_append(str, 0, "%s=%u", name, field);	\
-	}	\
-} while (0)
-
-#define APPEND_IF_NONZERO(field, str, name) do {		\
-	if (field) {	\
-		if (added) {	\
-			ast_str_append(str, 0, ";");	\
-		} else {	\
-			added = 1;	\
-		}	\
-		ast_str_append(str, 0, "%s=%u", name, field);	\
-	}	\
-} while (0)
-
-static void h264_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+/*! \brief Helper function which converts a key enum into a string value for SDP */
+static const char *h264_attr_key_to_str(enum h264_attr_keys key)
 {
-	struct h264_attr *attr = ast_format_get_attribute_data(format);
-	int added = 0;
-
-	if (!attr) {
-		return;
+	switch (key) {
+	case H264_ATTR_KEY_MAX_MBPS:
+		return "max-mbps";
+	case H264_ATTR_KEY_MAX_FS:
+		return "max-fs";
+	case H264_ATTR_KEY_MAX_CPB:
+		return "max-cpb";
+	case H264_ATTR_KEY_MAX_DPB:
+		return "max-dpb";
+	case H264_ATTR_KEY_MAX_BR:
+		return "max-br";
+	case H264_ATTR_KEY_MAX_SMBPS:
+		return "max-smbps";
+	case H264_ATTR_KEY_MAX_FPS:
+		return "max-fps";
+	case H264_ATTR_KEY_REDUNDANT_PIC_CAP:
+		return "redundant-pic-cap";
+	case H264_ATTR_KEY_PARAMETER_ADD:
+		return "parameter-add";
+	case H264_ATTR_KEY_PACKETIZATION_MODE:
+		return "packetization-mode";
+	case H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH:
+		return "sprop-interleaving-depth";
+	case H264_ATTR_KEY_SPROP_DEINT_BUF_REQ:
+		return "sprop-deint-buf-req";
+	case H264_ATTR_KEY_DEINT_BUF_CAP:
+		return "deint-buf-cap";
+	case H264_ATTR_KEY_SPROP_INIT_BUF_TIME:
+		return "sprop-init-buf-time";
+	case H264_ATTR_KEY_SPROP_MAX_DON_DIFF:
+		return "sprop-max-don-diff";
+	case H264_ATTR_KEY_MAX_RCMD_NALU_SIZE:
+		return "max-rcmd-nalu-size";
+	case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED:
+		return "level-asymmetry-allowed";
+	default:
+		return NULL;
 	}
 
-	ast_str_append(str, 0, "a=fmtp:%u ", payload);
-
-	APPEND_IF_NONZERO(attr->MAX_MBPS, str, "max-mbps");
-	APPEND_IF_NONZERO(attr->MAX_FS, str, "max-fs");
-	APPEND_IF_NONZERO(attr->MAX_CPB, str, "max-cpb");
-	APPEND_IF_NONZERO(attr->MAX_DPB, str, "max-dpb");
-	APPEND_IF_NONZERO(attr->MAX_BR, str, "max-br");
-	APPEND_IF_NONZERO(attr->MAX_SMBPS, str, "max-smbps");
-	APPEND_IF_NONZERO(attr->MAX_FPS, str, "max-fps");
-	APPEND_IF_NONZERO(attr->SPROP_INTERLEAVING_DEPTH, str, "sprop-interleaving-depth");
-	APPEND_IF_NONZERO(attr->SPROP_DEINT_BUF_REQ, str, "sprop-deint-buf-req");
-	APPEND_IF_NONZERO(attr->DEINT_BUF_CAP, str, "deint-buf-cap");
-	APPEND_IF_NONZERO(attr->SPROP_INIT_BUF_TIME, str, "sprop-init-buf-time");
-	APPEND_IF_NONZERO(attr->SPROP_MAX_DON_DIFF, str, "sprop-max-don-diff");
-	APPEND_IF_NONZERO(attr->MAX_RCMD_NALU_SIZE, str, "max-rcmd-nalu-size");
-
-	APPEND_IF_NOT_H264_UNSET(attr->REDUNDANT_PIC_CAP, str, "redundant-pic-cap");
-	APPEND_IF_NOT_H264_UNSET(attr->PARAMETER_ADD, str, "parameter-add");
-	APPEND_IF_NOT_H264_UNSET(attr->PACKETIZATION_MODE, str, "packetization-mode");
-	APPEND_IF_NOT_H264_UNSET(attr->LEVEL_ASYMMETRY_ALLOWED, str, "level-asymmetry-allowed");
-
-	if (attr->PROFILE_IDC && attr->PROFILE_IOP && attr->LEVEL) {
-		if (added) {
-			ast_str_append(str, 0, ";");
-		} else {
-			added = 1;
-		}
-		ast_str_append(str, 0, "profile-level-id=%02X%02X%02X", attr->PROFILE_IDC, attr->PROFILE_IOP, attr->LEVEL);
+	return NULL;
+}
+
+/*! \brief Helper function which determines if the value of an attribute can be placed into the SDP */
+static int h264_attr_key_addable(const struct ast_format_attr *format_attr, enum h264_attr_keys key)
+{
+	switch (key) {
+	case H264_ATTR_KEY_REDUNDANT_PIC_CAP:
+	case H264_ATTR_KEY_PARAMETER_ADD:
+	case H264_ATTR_KEY_PACKETIZATION_MODE:
+	case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED:
+		return (format_attr->format_attr[key] != H264_ATTR_KEY_UNSET) ? 1 : 0;
+	default:
+		return format_attr->format_attr[key] ? 1 : 0;
 	}
 
-	if (!ast_strlen_zero(attr->SPS) && !ast_strlen_zero(attr->PPS)) {
-		if (added) {
-			ast_str_append(str, 0, ";");
-		} else {
-			added = 1;
+	return 1;
+}
+
+static void h264_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
+{
+	int i, added = 0;
+
+        for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) {
+                const char *name;
+
+		if (i == H264_ATTR_KEY_SPS && format_attr->format_attr[H264_ATTR_KEY_SPS] && format_attr->format_attr[H264_ATTR_KEY_PPS]) {
+			unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, };
+			int pos;
+			char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE];
+
+			for (pos = 0; pos < H264_MAX_SPS_PPS_SIZE; pos++) {
+				spsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_SPS + pos];
+				ppsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_PPS + pos];
+			}
+
+			ast_base64encode(sps, spsdecoded, format_attr->format_attr[H264_ATTR_KEY_SPS_LEN], H264_MAX_SPS_PPS_SIZE);
+			ast_base64encode(pps, ppsdecoded, format_attr->format_attr[H264_ATTR_KEY_PPS_LEN], H264_MAX_SPS_PPS_SIZE);
+
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u sprop-parameter-sets=%s,%s", payload, sps, pps);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", sps, pps);
+			}
+		} else if (i == H264_ATTR_KEY_PROFILE_IDC && format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] &&
+		    format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] && format_attr->format_attr[H264_ATTR_KEY_LEVEL]) {
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u profile-level-id=%02X%02X%02X", payload, format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC],
+					       format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";profile-level-id=%02X%02X%02X", format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC],
+					       format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]);
+			}
+		} else if ((name = h264_attr_key_to_str(i)) && h264_attr_key_addable(format_attr, i)) {
+			if (!added) {
+				ast_str_append(str, 0, "a=fmtp:%u %s=%u", payload, name, format_attr->format_attr[i]);
+				added = 1;
+			} else {
+				ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]);
+			}
 		}
-		ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", attr->SPS, attr->PPS);
 	}
-
-	if (!added) {
-		ast_str_reset(*str);
-	} else {
+	
+	if (added) {
 		ast_str_append(str, 0, "\r\n");
 	}
 
 	return;
 }
 
-static struct ast_format_interface h264_interface = {
-	.format_destroy = h264_destroy,
-	.format_clone = h264_clone,
-	.format_cmp = h264_cmp,
-	.format_get_joint = h264_getjoint,
-	.format_parse_sdp_fmtp = h264_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = h264_generate_sdp_fmtp,
+static struct ast_format_attr_interface h264_format_attr_interface = {
+	.id = AST_FORMAT_H264,
+	.format_attr_cmp = h264_format_attr_cmp,
+	.format_attr_get_joint = h264_format_attr_get_joint,
+	.format_attr_sdp_parse = h264_format_attr_sdp_parse,
+	.format_attr_sdp_generate = h264_format_attr_sdp_generate,
 };
 
 static int unload_module(void)
 {
+	ast_format_attr_unreg_interface(&h264_format_attr_interface);
+
 	return 0;
 }
 
 static int load_module(void)
 {
-	if (ast_format_interface_register("h264", &h264_interface)) {
+	if (ast_format_attr_reg_interface(&h264_format_attr_interface)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -335,7 +317,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "H.264 Format Attribute Module",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_DEFAULT,
diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c
deleted file mode 100644
index 65d83e0..0000000
--- a/res/res_format_attr_opus.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Lorenzo Miniero <lorenzo at meetecho.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Opus format attribute interface
- *
- * \author Lorenzo Miniero <lorenzo at meetecho.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/module.h"
-#include "asterisk/format.h"
-
-/*!
- * \brief Opus attribute structure.
- *
- * \note http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-00.
- */
-struct opus_attr {
-	unsigned int maxbitrate;	        /* Default 64-128 kb/s for FB stereo music */
-	unsigned int maxplayrate	        /* Default 48000 */;
-	unsigned int minptime;	            /* Default 3, but it's 10 in format.c */
-	unsigned int stereo;	            /* Default 0 */
-	unsigned int cbr;	                /* Default 0 */
-	unsigned int fec;	                /* Default 0 */
-	unsigned int dtx;	                /* Default 0 */
-	unsigned int spropmaxcapturerate;	/* Default 48000 */
-	unsigned int spropstereo;	        /* Default 0 */
-};
-
-static void opus_destroy(struct ast_format *format)
-{
-	struct opus_attr *attr = ast_format_get_attribute_data(format);
-
-	ast_free(attr);
-}
-
-static int opus_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct opus_attr *original = ast_format_get_attribute_data(src);
-	struct opus_attr *attr = ast_calloc(1, sizeof(*attr));
-
-	if (!attr) {
-		return -1;
-	}
-
-	if (original) {
-		*attr = *original;
-	}
-
-	ast_format_set_attribute_data(dst, attr);
-
-	return 0;
-}
-
-static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
-{
-	struct ast_format *cloned;
-	struct opus_attr *attr;
-	const char *kvp;
-	unsigned int val;
-
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) {
-		attr->maxplayrate = val;
-	}
-	if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) {
-		attr->spropmaxcapturerate = val;
-	}
-	if ((kvp = strstr(attributes, "minptime")) && sscanf(kvp, "minptime=%30u", &val) == 1) {
-		attr->minptime = val;
-	}
-	if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) {
-		attr->maxbitrate = val;
-	}
-	if ((kvp = strstr(attributes, " stereo")) && sscanf(kvp, " stereo=%30u", &val) == 1) {
-		attr->stereo = val;
-	}
-	if ((kvp = strstr(attributes, ";stereo")) && sscanf(kvp, ";stereo=%30u", &val) == 1) {
-		attr->stereo = val;
-	}
-	if ((kvp = strstr(attributes, "sprop-stereo")) && sscanf(kvp, "sprop-stereo=%30u", &val) == 1) {
-		attr->spropstereo = val;
-	}
-	if ((kvp = strstr(attributes, "cbr")) && sscanf(kvp, "cbr=%30u", &val) == 1) {
-		attr->cbr = val;
-	}
-	if ((kvp = strstr(attributes, "useinbandfec")) && sscanf(kvp, "useinbandfec=%30u", &val) == 1) {
-		attr->fec = val;
-	}
-	if ((kvp = strstr(attributes, "usedtx")) && sscanf(kvp, "usedtx=%30u", &val) == 1) {
-		attr->dtx = val;
-	}
-
-	return 0;
-}
-
-static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
-{
-	struct opus_attr *attr = ast_format_get_attribute_data(format);
-
-	if (!attr) {
-		return;
-	}
-
-	/* FIXME should we only generate attributes that were explicitly set? */
-	ast_str_append(str, 0,
-				"a=fmtp:%u "
-					"maxplaybackrate=%u;"
-					"sprop-maxcapturerate=%u;"
-					"minptime=%u;"
-					"maxaveragebitrate=%u;"
-					"stereo=%d;"
-					"sprop-stereo=%d;"
-					"cbr=%d;"
-					"useinbandfec=%d;"
-					"usedtx=%d\r\n",
-			payload,
-			attr->maxplayrate ? attr->maxplayrate : 48000,	/* maxplaybackrate */
-			attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000,	/* sprop-maxcapturerate */
-			attr->minptime > 10 ? attr->minptime : 10,	/* minptime */
-			attr->maxbitrate ? attr->maxbitrate : 20000,	/* maxaveragebitrate */
-			attr->stereo ? 1 : 0,		/* stereo */
-			attr->spropstereo ? 1 : 0,		/* sprop-stereo */
-			attr->cbr ? 1 : 0,		/* cbr */
-			attr->fec ? 1 : 0,		/* useinbandfec */
-			attr->dtx ? 1 : 0		/* usedtx */
-	);
-}
-
-static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
-	struct ast_format *jointformat;
-	struct opus_attr *attr_res;
-
-	jointformat = ast_format_clone(format1);
-	if (!jointformat) {
-		return NULL;
-	}
-	attr_res = ast_format_get_attribute_data(jointformat);
-
-	/* Only do dtx if both sides want it. DTX is a trade off between
-	 * computational complexity and bandwidth. */
-	attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
-
-	/* Only do FEC if both sides want it.  If a peer specifically requests not
-	 * to receive with FEC, it may be a waste of bandwidth. */
-	attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
-
-	/* Only do stereo if both sides want it.  If a peer specifically requests not
-	 * to receive stereo signals, it may be a waste of bandwidth. */
-	attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
-
-	/* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */
-
-	return jointformat;
-}
-
-static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value)
-{
-	struct ast_format *cloned;
-	struct opus_attr *attr;
-	unsigned int val;
-
-	if (sscanf(value, "%30u", &val) != 1) {
-		ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
-			value, name);
-		return NULL;
-	}
-
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	if (!strcasecmp(name, "max_bitrate")) {
-		attr->maxbitrate = val;
-	} else if (!strcasecmp(name, "max_playrate")) {
-		attr->maxplayrate = val;
-	} else if (!strcasecmp(name, "minptime")) {
-		attr->minptime = val;
-	} else if (!strcasecmp(name, "stereo")) {
-		attr->stereo = val;
-	} else if (!strcasecmp(name, "cbr")) {
-		attr->cbr = val;
-	} else if (!strcasecmp(name, "fec")) {
-		attr->fec = val;
-	} else if (!strcasecmp(name, "dtx")) {
-		attr->dtx = val;
-	} else if (!strcasecmp(name, "sprop_capture_rate")) {
-		attr->spropmaxcapturerate = val;
-	} else if (!strcasecmp(name, "sprop_stereo")) {
-		attr->spropstereo = val;
-	} else {
-		ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
-	}
-
-	return cloned;
-}
-
-static struct ast_format_interface opus_interface = {
-	.format_destroy = opus_destroy,
-	.format_clone = opus_clone,
-	.format_get_joint = opus_getjoint,
-	.format_attribute_set = opus_set,
-	.format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
-};
-
-static int load_module(void)
-{
-	if (ast_format_interface_register("opus", &opus_interface)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c
index 766439a..075570f 100644
--- a/res/res_format_attr_silk.c
+++ b/res/res_format_attr_silk.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/format.h"
@@ -47,43 +47,11 @@ struct silk_attr {
 	unsigned int packetloss_percentage;
 };
 
-static void silk_destroy(struct ast_format *format)
+static int silk_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
 {
-	struct silk_attr *attr = ast_format_get_attribute_data(format);
-
-	ast_free(attr);
-}
-
-static int silk_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct silk_attr *original = ast_format_get_attribute_data(src);
-	struct silk_attr *attr = ast_calloc(1, sizeof(*attr));
-
-	if (!attr) {
-		return -1;
-	}
-
-	if (original) {
-		*attr = *original;
-	}
-
-	ast_format_set_attribute_data(dst, attr);
-
-	return 0;
-}
-
-static struct ast_format *silk_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
-{
-	struct ast_format *cloned;
-	struct silk_attr *attr;
+	struct silk_attr *attr = (struct silk_attr *) format_attr;
 	unsigned int val;
 
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
 	if (sscanf(attributes, "maxaveragebitrate=%30u", &val) == 1) {
 		attr->maxbitrate = val;
 	}
@@ -97,13 +65,9 @@ static struct ast_format *silk_parse_sdp_fmtp(const struct ast_format *format, c
 	return 0;
 }
 
-static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+static void silk_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
 {
-	struct silk_attr *attr = ast_format_get_attribute_data(format);
-
-	if (!attr) {
-		return;
-	}
+	struct silk_attr *attr = (struct silk_attr *) format_attr;
 
 	if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { 
 		ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate);
@@ -113,40 +77,99 @@ static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int
 	ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec);
 }
 
-static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2)
+static enum ast_format_cmp_res silk_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
 {
-	struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
+	struct silk_attr *attr1 = (struct silk_attr *) fattr1;
+	struct silk_attr *attr2 = (struct silk_attr *) fattr2;
 
-	if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) ||
-		(attr1->samplerate == attr2->samplerate)) {
+	if (attr1->samplerate == attr2->samplerate) {
 		return AST_FORMAT_CMP_EQUAL;
 	}
-
 	return AST_FORMAT_CMP_NOT_EQUAL;
 }
 
-static struct ast_format *silk_getjoint(const struct ast_format *format1, const struct ast_format *format2)
+static int silk_get_val(const struct ast_format_attr *fattr, int key, void *result)
 {
-	struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
-	struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
-	unsigned int samplerate;
-	struct ast_format *jointformat;
-	struct silk_attr *attr_res;
-
-	samplerate = attr1->samplerate & attr2->samplerate;
-	/* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */
-	if (samplerate) {
-		return NULL;
+	const struct silk_attr *attr = (struct silk_attr *) fattr;
+	int *val = result;
+
+	switch (key) {
+	case SILK_ATTR_KEY_SAMP_RATE:
+		*val = attr->samplerate;
+		break;
+	case SILK_ATTR_KEY_MAX_BITRATE:
+		*val = attr->maxbitrate;
+		break;
+	case SILK_ATTR_KEY_DTX:
+		*val = attr->dtx;
+		break;
+	case SILK_ATTR_KEY_FEC:
+		*val = attr->fec;
+		break;
+	case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+		*val = attr->packetloss_percentage;
+		break;
+	default:
+		ast_log(LOG_WARNING, "unknown attribute type %d\n", key);
+		return -1;
 	}
+	return 0;
+}
 
-	jointformat = ast_format_clone(format1);
-	if (!jointformat) {
-		return NULL;
+static int silk_isset(const struct ast_format_attr *fattr, va_list ap)
+{
+	enum silk_attr_keys key;
+	const struct silk_attr *attr = (struct silk_attr *) fattr;
+
+	for (key = va_arg(ap, int);
+		key != AST_FORMAT_ATTR_END;
+		key = va_arg(ap, int))
+	{
+		switch (key) {
+		case SILK_ATTR_KEY_SAMP_RATE:
+			if (attr->samplerate != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case SILK_ATTR_KEY_MAX_BITRATE:
+			if (attr->maxbitrate != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case SILK_ATTR_KEY_DTX:
+			if (attr->dtx != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case SILK_ATTR_KEY_FEC:
+			if (attr->fec != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+			if (attr->packetloss_percentage != (va_arg(ap, int))) {
+				return -1;
+			}
+			break;
+		default:
+			ast_log(LOG_WARNING, "unknown attribute type %u\n", key);
+			return -1;
+		}
 	}
-	attr_res = ast_format_get_attribute_data(jointformat);
-	attr_res->samplerate = samplerate;
+	return 0;
+}
+static int silk_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
+{
+	struct silk_attr *attr1 = (struct silk_attr *) fattr1;
+	struct silk_attr *attr2 = (struct silk_attr *) fattr2;
+	struct silk_attr *attr_res = (struct silk_attr *) result;
+	int joint = -1;
 
+	attr_res->samplerate = attr1->samplerate & attr2->samplerate;
+	/* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */
+	if (attr_res->samplerate) {
+		joint = 0;
+	}
 	/* Take the lowest max bitrate */
 	attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
 
@@ -161,58 +184,54 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const
 	/* Use the maximum packetloss percentage between the two attributes. This affects how
 	 * much redundancy is used in the FEC. */
 	attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage);
-
-	return jointformat;
+	return joint;
 }
 
-static struct ast_format *silk_set(const struct ast_format *format, const char *name, const char *value)
+static void silk_set(struct ast_format_attr *fattr, va_list ap)
 {
-	struct ast_format *cloned;
-	struct silk_attr *attr;
-	unsigned int val;
-
-	if (sscanf(value, "%30u", &val) != 1) {
-		ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
-			value, name);
-		return NULL;
-	}
-
-	cloned = ast_format_clone(format);
-	if (!cloned) {
-		return NULL;
-	}
-	attr = ast_format_get_attribute_data(cloned);
-
-	if (!strcasecmp(name, "sample_rate")) {
-		attr->samplerate = val;
-	} else if (!strcasecmp(name, "max_bitrate")) {
-		attr->maxbitrate = val;
-	} else if (!strcasecmp(name, "dtx")) {
-		attr->dtx = val;
-	} else if (!strcasecmp(name, "fec")) {
-		attr->fec = val;
-	} else if (!strcasecmp(name, "packetloss_percentage")) {
-		attr->packetloss_percentage = val;
-	} else {
-		ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
+	enum silk_attr_keys key;
+	struct silk_attr *attr = (struct silk_attr *) fattr;
+
+	for (key = va_arg(ap, int);
+		key != AST_FORMAT_ATTR_END;
+		key = va_arg(ap, int))
+	{
+		switch (key) {
+		case SILK_ATTR_KEY_SAMP_RATE:
+			attr->samplerate = (va_arg(ap, int));
+			break;
+		case SILK_ATTR_KEY_MAX_BITRATE:
+			attr->maxbitrate = (va_arg(ap, int));
+			break;
+		case SILK_ATTR_KEY_DTX:
+			attr->dtx = (va_arg(ap, int));
+			break;
+		case SILK_ATTR_KEY_FEC:
+			attr->fec = (va_arg(ap, int));
+			break;
+		case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+			attr->packetloss_percentage = (va_arg(ap, int));
+			break;
+		default:
+			ast_log(LOG_WARNING, "unknown attribute type %u\n", key);
+		}
 	}
-
-	return cloned;
 }
 
-static struct ast_format_interface silk_interface = {
-	.format_destroy = silk_destroy,
-	.format_clone = silk_clone,
-	.format_cmp = silk_cmp,
-	.format_get_joint = silk_getjoint,
-	.format_attribute_set = silk_set,
-	.format_parse_sdp_fmtp = silk_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = silk_generate_sdp_fmtp,
+static struct ast_format_attr_interface silk_interface = {
+	.id = AST_FORMAT_SILK,
+	.format_attr_cmp = silk_cmp,
+	.format_attr_get_joint = silk_getjoint,
+	.format_attr_set = silk_set,
+	.format_attr_isset = silk_isset,
+	.format_attr_get_val = silk_get_val,
+	.format_attr_sdp_parse = silk_sdp_parse,
+	.format_attr_sdp_generate = silk_sdp_generate,
 };
 
 static int load_module(void)
 {
-	if (ast_format_interface_register("silk", &silk_interface)) {
+	if (ast_format_attr_reg_interface(&silk_interface)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -221,11 +240,11 @@ static int load_module(void)
 
 static int unload_module(void)
 {
+	ast_format_attr_unreg_interface(&silk_interface);
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SILK Format Attribute Module",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_hep.c b/res/res_hep.c
deleted file mode 100644
index 273da5b..0000000
--- a/res/res_hep.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2014, Digium, Inc.
- *
- * Alexandr Dubovikov <alexandr.dubovikov at sipcapture.org>
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Routines for integration with Homer using HEPv3
- *
- * \author Alexandr Dubovikov <alexandr.dubovikov at sipcapture.org>
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-/*!
- * \li \ref res_hep.c uses the configuration file \ref hep.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page hep.conf hep.conf
- * \verbinclude hep.conf.sample
- */
-
-/*** MODULEINFO
-	<support_level>extended</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_hep" language="en_US">
-		<synopsis>Resource for integration with Homer using HEPv3</synopsis>
-		<configFile name="hep.conf">
-			<configObject name="general">
-				<synopsis>General settings.</synopsis>
-				<description><para>
-					The <emphasis>general</emphasis> settings section contains information
-					to configure Asterisk as a Homer capture agent.
-					</para>
-				</description>
-				<configOption name="enabled" default="yes">
-					<synopsis>Enable or disable packet capturing.</synopsis>
-					<description>
-						<enumlist>
-							<enum name="no" />
-							<enum name="yes" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="capture_address" default="192.168.1.1:9061">
-					<synopsis>The address and port of the Homer server to send packets to.</synopsis>
-				</configOption>
-				<configOption name="capture_password">
-					<synopsis>If set, the authentication password to send to Homer.</synopsis>
-				</configOption>
-				<configOption name="capture_id" default="0">
-					<synopsis>The ID for this capture agent.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427405 $")
-
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/config_options.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/res_hep.h"
-
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-#include <netinet/ip6.h>
-
-#define DEFAULT_HEP_SERVER ""
-
-/*! Generic vendor ID. Used for HEPv3 standard packets */
-#define GENERIC_VENDOR_ID 0x0000
-
-/*! Asterisk vendor ID. Used for custom data to send to a capture node */
-#define ASTERISK_VENDOR_ID 0x0004
-
-/*! Chunk types from the HEPv3 Spec */
-enum hepv3_chunk_types {
-
-	/*! THE IP PROTOCOL FAMILY */
-	CHUNK_TYPE_IP_PROTOCOL_FAMILY = 0X0001,
-
-	/*! THE IP PROTOCOL ID (UDP, TCP, ETC.) */
-	CHUNK_TYPE_IP_PROTOCOL_ID = 0X0002,
-
-	/*! IF IPV4, THE SOURCE ADDRESS */
-	CHUNK_TYPE_IPV4_SRC_ADDR = 0X0003,
-
-	/*! IF IPV4, THE DESTINATION ADDRESS */
-	CHUNK_TYPE_IPV4_DST_ADDR = 0X0004,
-
-	/*! IF IPV6, THE SOURCE ADDRESS */
-	CHUNK_TYPE_IPV6_SRC_ADDR = 0X0005,
-
-	/*! IF IPV6, THE DESTINATION ADDRESS */
-	CHUNK_TYPE_IPV6_DST_ADDR = 0X0006,
-
-	/*! THE SOURCE PORT */
-	CHUNK_TYPE_SRC_PORT = 0X0007,
-
-	/*! THE DESTINATION PORT */
-	CHUNK_TYPE_DST_PORT = 0X0008,
-
-	/*! THE CAPTURE TIME (SECONDS) */
-	CHUNK_TYPE_TIMESTAMP_SEC = 0X0009,
-
-	/*! THE CAPTURE TIME (MICROSECONDS) */
-	CHUNK_TYPE_TIMESTAMP_USEC = 0X000A,
-
-	/*! THE PROTOCOL PACKET TYPE. SEE /REF HEPV3_CAPTURE_TYPE */
-	CHUNK_TYPE_PROTOCOL_TYPE = 0X000B,
-
-	/*! OUR CAPTURE AGENT ID */
-	CHUNK_TYPE_CAPTURE_AGENT_ID = 0X000C,
-
-	/*! A KEEP ALIVE TIMER */
-	CHUNK_TYPE_KEEP_ALIVE_TIMER = 0X000D,
-
-	/*! THE \REF CAPTURE_PASSWORD IF DEFINED */
-	CHUNK_TYPE_AUTH_KEY = 0X000E,
-
-	/*! THE ONE AND ONLY PAYLOAD */
-	CHUNK_TYPE_PAYLOAD = 0X000F,
-
-	/*! THE ONE AND ONLY (ZIPPED) PAYLOAD */
-	CHUNK_TYPE_PAYLOAD_ZIP = 0X0010,
-
-	/*! THE UUID FOR THIS PACKET */
-	CHUNK_TYPE_UUID = 0X0011,
-};
-
-#define INITIALIZE_GENERIC_HEP_IDS(hep_chunk, type) do { \
-	(hep_chunk)->vendor_id = htons(GENERIC_VENDOR_ID); \
-	(hep_chunk)->type_id = htons((type)); \
-	} while (0)
-
-#define INITIALIZE_GENERIC_HEP_IDS_VAR(hep_chunk, type, len) do { \
-	INITIALIZE_GENERIC_HEP_IDS((hep_chunk), (type)); \
-	(hep_chunk)->length = htons(sizeof(*(hep_chunk)) + len); \
-	} while (0)
-
-#define INITIALIZE_GENERIC_HEP_CHUNK(hep_item, type) do { \
-	INITIALIZE_GENERIC_HEP_IDS(&(hep_item)->chunk, (type)); \
-	(hep_item)->chunk.length = htons(sizeof(*(hep_item))); \
-	} while (0)
-
-#define INITIALIZE_GENERIC_HEP_CHUNK_DATA(hep_item, type, value) do { \
-	INITIALIZE_GENERIC_HEP_CHUNK((hep_item), (type)); \
-	(hep_item)->data = (value); \
-	} while (0)
-
-/*
- * HEPv3 Types.
- * Note that the content in these is stored in network byte order.
- */
-
-struct hep_chunk {
-	u_int16_t vendor_id;
-	u_int16_t type_id;
-	u_int16_t length;
-} __attribute__((packed));
-
-struct hep_chunk_uint8 {
-	struct hep_chunk chunk;
-	u_int8_t data;
-} __attribute__((packed));
-
-struct hep_chunk_uint16 {
-	struct hep_chunk chunk;
-	u_int16_t data;
-} __attribute__((packed));
-
-struct hep_chunk_uint32 {
-	struct hep_chunk chunk;
-	u_int32_t data;
-} __attribute__((packed));
-
-struct hep_chunk_ip4 {
-	struct hep_chunk chunk;
-	struct in_addr data;
-} __attribute__((packed));
-
-struct hep_chunk_ip6 {
-	struct hep_chunk chunk;
-	struct in6_addr data;
-} __attribute__((packed));
-
-struct hep_ctrl {
-	char id[4];
-	u_int16_t length;
-} __attribute__((packed));
-
-/* HEP structures */
-
-struct hep_generic {
-	struct hep_ctrl         header;
-	struct hep_chunk_uint8  ip_family;
-	struct hep_chunk_uint8  ip_proto;
-	struct hep_chunk_uint16 src_port;
-	struct hep_chunk_uint16 dst_port;
-	struct hep_chunk_uint32 time_sec;
-	struct hep_chunk_uint32 time_usec;
-	struct hep_chunk_uint8  proto_t;
-	struct hep_chunk_uint32 capt_id;
-} __attribute__((packed));
-
-/*! \brief Global configuration for the module */
-struct hepv3_global_config {
-	unsigned int enabled;                    /*!< Whether or not sending is enabled */
-	unsigned int capture_id;                 /*!< Capture ID for this agent */
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(capture_address);   /*!< Address to send to */
-		AST_STRING_FIELD(capture_password);  /*!< Password for Homer server */
-	);
-};
-
-/*! \brief The actual module config */
-struct module_config {
-	struct hepv3_global_config *general; /*!< The general config settings */
-};
-
-/*! \brief Run-time data derived from \ref hepv3_global_config */
-struct hepv3_runtime_data {
-	struct ast_sockaddr remote_addr;  /*!< The address to send to */
-	int sockfd;                       /*!< The socket file descriptor */
-};
-
-static struct aco_type global_option = {
-	.type = ACO_GLOBAL,
-	.name = "general",
-	.item_offset = offsetof(struct module_config, general),
-	.category_match = ACO_WHITELIST,
-	.category = "^general$",
-};
-
-struct aco_type *global_options[] = ACO_TYPES(&global_option);
-
-struct aco_file hepv3_conf = {
-	.filename = "hep.conf",
-	.types = ACO_TYPES(&global_option),
-};
-
-/*! \brief The module configuration container */
-static AO2_GLOBAL_OBJ_STATIC(global_config);
-
-/*! \brief Current module data */
-static AO2_GLOBAL_OBJ_STATIC(global_data);
-
-static struct ast_taskprocessor *hep_queue_tp;
-
-static void *module_config_alloc(void);
-static void hepv3_config_post_apply(void);
-
-/*! \brief Register information about the configs being processed by this module */
-CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc,
-	.files = ACO_FILES(&hepv3_conf),
-	.post_apply_config = hepv3_config_post_apply,
-);
-
-static void hepv3_config_dtor(void *obj)
-{
-	struct hepv3_global_config *config = obj;
-
-	ast_string_field_free_memory(config);
-}
-
-/*! \brief HEPv3 configuration object allocation */
-static void *hepv3_config_alloc(void)
-{
-	struct hepv3_global_config *config;
-
-	config = ao2_alloc(sizeof(*config), hepv3_config_dtor);
-	if (!config || ast_string_field_init(config, 32)) {
-		return NULL;
-	}
-
-	return config;
-}
-
-/*! \brief Configuration object destructor */
-static void module_config_dtor(void *obj)
-{
-	struct module_config *config = obj;
-
-	if (config->general) {
-		ao2_ref(config->general, -1);
-	}
-}
-
-/*! \brief Module config constructor */
-static void *module_config_alloc(void)
-{
-	struct module_config *config;
-
-	config = ao2_alloc(sizeof(*config), module_config_dtor);
-	if (!config) {
-		return NULL;
-	}
-
-	config->general = hepv3_config_alloc();
-	if (!config->general) {
-		ao2_ref(config, -1);
-		config = NULL;
-	}
-
-	return config;
-}
-
-/*! \brief HEPv3 run-time data destructor */
-static void hepv3_data_dtor(void *obj)
-{
-	struct hepv3_runtime_data *data = obj;
-
-	if (data->sockfd > -1) {
-		close(data->sockfd);
-		data->sockfd = -1;
-	}
-}
-
-/*! \brief Allocate the HEPv3 run-time data */
-static struct hepv3_runtime_data *hepv3_data_alloc(struct hepv3_global_config *config)
-{
-	struct hepv3_runtime_data *data;
-
-	data = ao2_alloc(sizeof(*data), hepv3_data_dtor);
-	if (!data) {
-		return NULL;
-	}
-
-	if (!ast_sockaddr_parse(&data->remote_addr, config->capture_address, PARSE_PORT_REQUIRE)) {
-		ast_log(AST_LOG_WARNING, "Failed to create address from %s\n", config->capture_address);
-		ao2_ref(data, -1);
-		return NULL;
-	}
-
-	data->sockfd = socket(ast_sockaddr_is_ipv6(&data->remote_addr) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
-	if (data->sockfd < 0) {
-		ast_log(AST_LOG_WARNING, "Failed to create socket for address %s: %s\n",
-				config->capture_address, strerror(errno));
-		ao2_ref(data, -1);
-		return NULL;
-	}
-
-	return data;
-}
-
-/*! \brief Destructor for a \ref hepv3_capture_info object */
-static void capture_info_dtor(void *obj)
-{
-	struct hepv3_capture_info *info = obj;
-
-	ast_free(info->uuid);
-	ast_free(info->payload);
-}
-
-struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
-{
-	struct hepv3_capture_info *info;
-
-	info = ao2_alloc(sizeof(*info), capture_info_dtor);
-	if (!info) {
-		return NULL;
-	}
-
-	info->payload = ast_malloc(len);
-	if (!info->payload) {
-		ao2_ref(info, -1);
-		return NULL;
-	}
-	memcpy(info->payload, payload, len);
-	info->len = len;
-
-	return info;
-}
-
-/*! \brief Callback function for the \ref hep_queue_tp taskprocessor */
-static int hep_queue_cb(void *data)
-{
-	RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
-	RAII_VAR(struct hepv3_runtime_data *, hepv3_data, ao2_global_obj_ref(global_data), ao2_cleanup);
-	RAII_VAR(struct hepv3_capture_info *, capture_info, data, ao2_cleanup);
-	struct hep_generic hg_pkt;
-	unsigned int packet_len = 0, sock_buffer_len;
-	struct hep_chunk_ip4 ipv4_src, ipv4_dst;
-	struct hep_chunk_ip6 ipv6_src, ipv6_dst;
-	struct hep_chunk auth_key, payload, uuid;
-	void *sock_buffer;
-	int res;
-
-	if (!capture_info || !config || !hepv3_data) {
-		return 0;
-	}
-
-	if (ast_sockaddr_is_ipv4(&capture_info->src_addr) != ast_sockaddr_is_ipv4(&capture_info->dst_addr)) {
-		ast_log(AST_LOG_NOTICE, "Unable to send packet: Address Family mismatch between source/destination\n");
-		return -1;
-	}
-
-	packet_len = sizeof(hg_pkt);
-
-	/* Build HEPv3 header, capture info, and calculate the total packet size */
-	memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4);
-
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, 0x11);
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr)));
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr)));
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec));
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_usec, CHUNK_TYPE_TIMESTAMP_USEC, htonl(capture_info->capture_time.tv_usec));
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.proto_t, CHUNK_TYPE_PROTOCOL_TYPE, capture_info->capture_type);
-	INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.capt_id, CHUNK_TYPE_CAPTURE_AGENT_ID, htonl(config->general->capture_id));
-
-	if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
-		INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
-			CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET);
-
-		INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_src, CHUNK_TYPE_IPV4_SRC_ADDR);
-		inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv4_src.data);
-
-		INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_dst, CHUNK_TYPE_IPV4_DST_ADDR);
-		inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv4_dst.data);
-
-		packet_len += (sizeof(ipv4_src) + sizeof(ipv4_dst));
-	} else {
-		INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
-			CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET6);
-
-		INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_src, CHUNK_TYPE_IPV6_SRC_ADDR);
-		inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv6_src.data);
-
-		INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_dst, CHUNK_TYPE_IPV6_DST_ADDR);
-		inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv6_dst.data);
-
-		packet_len += (sizeof(ipv6_src) + sizeof(ipv6_dst));
-	}
-
-	if (!ast_strlen_zero(config->general->capture_password))  {
-		INITIALIZE_GENERIC_HEP_IDS_VAR(&auth_key, CHUNK_TYPE_AUTH_KEY, strlen(config->general->capture_password));
-		packet_len += (sizeof(auth_key) + strlen(config->general->capture_password));
-	}
-	INITIALIZE_GENERIC_HEP_IDS_VAR(&uuid, CHUNK_TYPE_UUID, strlen(capture_info->uuid));
-	packet_len += (sizeof(uuid) + strlen(capture_info->uuid));
-	INITIALIZE_GENERIC_HEP_IDS_VAR(&payload,
-		capture_info->zipped ? CHUNK_TYPE_PAYLOAD_ZIP : CHUNK_TYPE_PAYLOAD, capture_info->len);
-	packet_len += (sizeof(payload) + capture_info->len);
-	hg_pkt.header.length = htons(packet_len);
-
-	/* Build the buffer to send */
-	sock_buffer = ast_malloc(packet_len);
-	if (!sock_buffer) {
-		return -1;
-	}
-
-	/* Copy in the header */
-	memcpy(sock_buffer, &hg_pkt, sizeof(hg_pkt));
-	sock_buffer_len = sizeof(hg_pkt);
-
-	/* Addresses */
-	if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
-		memcpy(sock_buffer + sock_buffer_len, &ipv4_src, sizeof(ipv4_src));
-		sock_buffer_len += sizeof(ipv4_src);
-		memcpy(sock_buffer + sock_buffer_len, &ipv4_dst, sizeof(ipv4_dst));
-		sock_buffer_len += sizeof(ipv4_dst);
-	} else {
-		memcpy(sock_buffer + sock_buffer_len, &ipv6_src, sizeof(ipv6_src));
-		sock_buffer_len += sizeof(ipv6_src);
-		memcpy(sock_buffer + sock_buffer_len, &ipv6_dst, sizeof(ipv6_dst));
-		sock_buffer_len += sizeof(ipv6_dst);
-	}
-
-	/* Auth Key */
-	if (!ast_strlen_zero(config->general->capture_password)) {
-		memcpy(sock_buffer + sock_buffer_len, &auth_key, sizeof(auth_key));
-		sock_buffer_len += sizeof(auth_key);
-		memcpy(sock_buffer + sock_buffer_len, config->general->capture_password, strlen(config->general->capture_password));
-		sock_buffer_len += strlen(config->general->capture_password);
-	}
-
-	/* UUID */
-	memcpy(sock_buffer + sock_buffer_len, &uuid, sizeof(uuid));
-	sock_buffer_len += sizeof(uuid);
-	memcpy(sock_buffer + sock_buffer_len, capture_info->uuid, strlen(capture_info->uuid));
-	sock_buffer_len += strlen(capture_info->uuid);
-
-	/* Packet! */
-	memcpy(sock_buffer + sock_buffer_len, &payload, sizeof(payload));
-	sock_buffer_len += sizeof(payload);
-	memcpy(sock_buffer + sock_buffer_len, capture_info->payload, capture_info->len);
-	sock_buffer_len += capture_info->len;
-
-	ast_assert(sock_buffer_len == packet_len);
-
-	res = ast_sendto(hepv3_data->sockfd, sock_buffer, sock_buffer_len, 0, &hepv3_data->remote_addr);
-	if (res < 0) {
-		ast_log(AST_LOG_ERROR, "Error [%d] while sending packet to HEPv3 server: %s\n",
-			errno, strerror(errno));
-	} else if (res != sock_buffer_len) {
-		ast_log(AST_LOG_WARNING, "Failed to send complete packet to HEPv3 server: %d of %u sent\n",
-			res, sock_buffer_len);
-		res = -1;
-	}
-
-	ast_free(sock_buffer);
-	return res;
-}
-
-int hepv3_send_packet(struct hepv3_capture_info *capture_info)
-{
-	RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
-	int res;
-
-	if (!config || !config->general->enabled) {
-		ao2_ref(capture_info, -1);
-		return 0;
-	}
-
-	res = ast_taskprocessor_push(hep_queue_tp, hep_queue_cb, capture_info);
-	if (res == -1) {
-		ao2_ref(capture_info, -1);
-	}
-
-	return res;
-}
-
-/*!
- * \brief Post-apply callback for the config framework.
- *
- * This will create the run-time information from the supplied
- * configuration.
-*/
-static void hepv3_config_post_apply(void)
-{
-	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(global_config), ao2_cleanup);
-	struct hepv3_runtime_data *data;
-
-	data = hepv3_data_alloc(mod_cfg->general);
-	if (!data) {
-		return;
-	}
-
-	ao2_global_obj_replace_unref(global_data, data);
-	ao2_ref(data, -1);
-}
-
-/*!
- * \brief Reload the module
- */
-static int reload_module(void)
-{
-	if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
-		return -1;
-	}
-	return 0;
-}
-
-/*!
- * \brief Unload the module
- */
-static int unload_module(void)
-{
-	hep_queue_tp = ast_taskprocessor_unreference(hep_queue_tp);
-
-	ao2_global_obj_release(global_config);
-	ao2_global_obj_release(global_data);
-	aco_info_destroy(&cfg_info);
-
-	return 0;
-}
-
-/*!
- * \brief Load the module
- */
-static int load_module(void)
-{
-	if (aco_info_init(&cfg_info)) {
-		goto error;
-	}
-
-	hep_queue_tp = ast_taskprocessor_get("hep_queue_tp", TPS_REF_DEFAULT);
-	if (!hep_queue_tp) {
-		goto error;
-	}
-
-	aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct hepv3_global_config, enabled));
-	aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address));
-	aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password));
-	aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id));
-
-	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
-		goto error;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-
-error:
-	aco_info_destroy(&cfg_info);
-	return AST_MODULE_LOAD_DECLINE;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HEPv3 API",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
-	.load = load_module,
-	.unload = unload_module,
-	.reload = reload_module,
-	.load_pri = AST_MODPRI_APP_DEPEND,
-	);
diff --git a/res/res_hep.exports.in b/res/res_hep.exports.in
deleted file mode 100644
index d09d3f4..0000000
--- a/res/res_hep.exports.in
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIX*hepv3_send_packet;
-		LINKER_SYMBOL_PREFIX*hepv3_create_capture_info;
-	local:
-		*;
-};
diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c
deleted file mode 100644
index 0127377..0000000
--- a/res/res_hep_pjsip.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief PJSIP logging with Homer
- *
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<depend>res_hep</depend>
-	<support_level>extended</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425691 $")
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/res_hep.h"
-#include "asterisk/module.h"
-#include "asterisk/netsock2.h"
-
-static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, const pj_str_t *remote_tag)
-{
-	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-	pjsip_dialog *dlg;
-	char *uuid = NULL;
-
-	if ((dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE))
-	    && (session = ast_sip_dialog_get_session(dlg))
-	    && (session->channel)) {
-
-		uuid = ast_strdup(ast_channel_name(session->channel));
-	} else {
-
-		uuid = ast_malloc(pj_strlen(call_id) + 1);
-		if (uuid) {
-			ast_copy_pj_str(uuid, call_id, pj_strlen(call_id) + 1);
-		}
-	}
-
-	return uuid;
-}
-
-static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
-{
-	char local_buf[256];
-	char remote_buf[256];
-	char *uuid;
-	struct hepv3_capture_info *capture_info;
-	pjsip_cid_hdr *cid_hdr;
-	pjsip_from_hdr *from_hdr;
-	pjsip_to_hdr *to_hdr;
-
-	capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));
-	if (!capture_info) {
-		return PJ_SUCCESS;
-	}
-
-	pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
-	pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);
-
-	cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);
-	from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg);
-	to_hdr = PJSIP_MSG_TO_HDR(tdata->msg);
-
-	uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag);
-	if (!uuid) {
-		ao2_ref(capture_info, -1);
-		return PJ_SUCCESS;
-	}
-
-	ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE);
-	ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE);
-
-	capture_info->capture_time = ast_tvnow();
-	capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
-	capture_info->uuid = uuid;
-	capture_info->zipped = 0;
-
-	hepv3_send_packet(capture_info);
-
-	return PJ_SUCCESS;
-}
-
-static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
-{
-	char local_buf[256];
-	char remote_buf[256];
-	char *uuid;
-	struct hepv3_capture_info *capture_info;
-
-	capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len);
-	if (!capture_info) {
-		return PJ_SUCCESS;
-	}
-
-	if (rdata->tp_info.transport->addr_len) {
-		pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
-	}
-	if (rdata->pkt_info.src_addr_len) {
-		pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3);
-	}
-
-	uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag);
-	if (!uuid) {
-		ao2_ref(capture_info, -1);
-		return PJ_SUCCESS;
-	}
-
-	ast_sockaddr_parse(&capture_info->src_addr, remote_buf, PARSE_PORT_REQUIRE);
-	ast_sockaddr_parse(&capture_info->dst_addr, local_buf, PARSE_PORT_REQUIRE);
-	capture_info->capture_time.tv_sec = rdata->pkt_info.timestamp.sec;
-	capture_info->capture_time.tv_usec = rdata->pkt_info.timestamp.msec * 1000;
-	capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
-	capture_info->uuid = uuid;
-	capture_info->zipped = 0;
-
-	hepv3_send_packet(capture_info);
-
-	return PJ_FALSE;
-}
-
-static pjsip_module logging_module = {
-	.name = { "HEPv3 Logging Module", 20 },
-	.priority = 0,
-	.on_rx_request = logging_on_rx_msg,
-	.on_rx_response = logging_on_rx_msg,
-	.on_tx_request = logging_on_tx_msg,
-	.on_tx_response = logging_on_tx_msg,
-};
-
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sip_register_service(&logging_module);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_service(&logging_module);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP HEPv3 Logger",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_DEFAULT,
-	       );
diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c
deleted file mode 100644
index f254b66..0000000
--- a/res/res_hep_rtcp.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief RTCP logging with Homer
- *
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>res_hep</depend>
-	<support_level>extended</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421065 $")
-
-#include "asterisk/res_hep.h"
-#include "asterisk/module.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/stasis.h"
-#include "asterisk/rtp_engine.h"
-#include "asterisk/json.h"
-#include "asterisk/config.h"
-
-static struct stasis_subscription *stasis_rtp_subscription;
-
-static void rtcp_message_handler(struct stasis_message *message)
-{
-
-	RAII_VAR(struct ast_json *, json_payload, NULL, ast_json_unref);
-	RAII_VAR(char *,  payload, NULL, ast_json_free);
-	struct ast_json *json_blob;
-	struct ast_json *json_channel;
-	struct ast_json *json_rtcp;
-	struct hepv3_capture_info *capture_info;
-	struct ast_json *from;
-	struct ast_json *to;
-	struct timeval current_time = ast_tvnow();
-
-	json_payload = stasis_message_to_json(message, NULL);
-	if (!json_payload) {
-		return;
-	}
-
-	json_blob = ast_json_object_get(json_payload, "blob");
-	if (!json_blob) {
-		return;
-	}
-
-	json_channel = ast_json_object_get(json_payload, "channel");
-	if (!json_channel) {
-		return;
-	}
-
-	json_rtcp = ast_json_object_get(json_payload, "rtcp_report");
-	if (!json_rtcp) {
-		return;
-	}
-
-	from = ast_json_object_get(json_blob, "from");
-	to = ast_json_object_get(json_blob, "to");
-	if (!from || !to) {
-		return;
-	}
-
-	payload = ast_json_dump_string(json_rtcp);
-	if (ast_strlen_zero(payload)) {
-		return;
-	}
-
-	capture_info = hepv3_create_capture_info(payload, strlen(payload));
-	if (!capture_info) {
-		return;
-	}
-	ast_sockaddr_parse(&capture_info->src_addr, ast_json_string_get(from), PARSE_PORT_REQUIRE);
-	ast_sockaddr_parse(&capture_info->dst_addr, ast_json_string_get(to), PARSE_PORT_REQUIRE);
-
-	capture_info->uuid = ast_strdup(ast_json_string_get(ast_json_object_get(json_channel, "name")));
-	if (!capture_info->uuid) {
-		ao2_ref(capture_info, -1);
-		return;
-	}
-	capture_info->capture_time = current_time;
-	capture_info->capture_type = HEPV3_CAPTURE_TYPE_RTCP;
-	capture_info->zipped = 0;
-
-	hepv3_send_packet(capture_info);
-}
-
-static void rtp_topic_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct stasis_message_type *message_type = stasis_message_type(message);
-
-	if ((message_type == ast_rtp_rtcp_sent_type()) ||
-		(message_type == ast_rtp_rtcp_received_type())) {
-		rtcp_message_handler(message);
-	}
-}
-
-static int load_module(void)
-{
-
-	stasis_rtp_subscription = stasis_subscribe(ast_rtp_topic(),
-		rtp_topic_handler, NULL);
-	if (!stasis_rtp_subscription) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	if (stasis_rtp_subscription) {
-		stasis_rtp_subscription = stasis_unsubscribe(stasis_rtp_subscription);
-	}
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RTCP HEPv3 Logger",
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_DEFAULT,
-	);
diff --git a/res/res_http_post.c b/res/res_http_post.c
index 4f1fb13..c05c228 100644
--- a/res/res_http_post.c
+++ b/res/res_http_post.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -213,7 +213,7 @@ static int find_sequence(char * inbuf, int inlen, char * matchbuf, int matchlen)
 * This function has two modes.  The first to find a boundary marker.  The
 * second is to find the filename immediately after the boundary.
 */
-static int readmimefile(FILE *fin, FILE *fout, char *boundary, int contentlen)
+static int readmimefile(FILE * fin, FILE * fout, char * boundary, int contentlen)
 {
 	int find_filename = 0;
 	char buf[4096];
@@ -313,41 +313,53 @@ static int readmimefile(FILE *fin, FILE *fout, char *boundary, int contentlen)
 
 static int http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
 {
-	struct ast_variable *var;
-	uint32_t ident;
+	struct ast_variable *var, *cookies;
+	unsigned long ident = 0;
 	FILE *f;
 	int content_len = 0;
 	struct ast_str *post_dir;
 	GMimeMessage *message;
-	char *boundary_marker = NULL;
+	char * boundary_marker = NULL;
 
 	if (method != AST_HTTP_POST) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
+	}
+
+	if (!astman_is_authed(ast_http_manid_from_vars(headers))) {
+		ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave.");
+		return -1;
 	}
 
 	if (!urih) {
 		ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request");
-		return 0;
+	        return -1;
 	}
 
-	ident = ast_http_manid_from_vars(headers);
-	if (!ident || !astman_is_authed(ident)) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave.");
-		return 0;
+	cookies = ast_http_get_cookies(headers);
+	for (var = cookies; var; var = var->next) {
+		if (!strcasecmp(var->name, "mansession_id")) {
+			sscanf(var->value, "%30lx", &ident);
+			break;
+		}
+	}
+	if (cookies) {
+		ast_variables_destroy(cookies);
 	}
 
+	if (ident == 0) {
+		ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request.");
+		return -1;
+	}
 	if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
-		ast_http_request_close_on_completion(ser);
 		ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request.");
-		return 0;
+		return -1;
 	}
 
 	if (!(f = tmpfile())) {
 		ast_log(LOG_ERROR, "Could not create temp file.\n");
 		ast_http_error(ser, 500, "Internal server error", "Could not create temp file.");
-		return 0;
+		return -1;
 	}
 
 	for (var = headers; var; var = var->next) {
@@ -357,9 +369,8 @@ static int http_post_callback(struct ast_tcptls_session_instance *ser, const str
 			if ((sscanf(var->value, "%30u", &content_len)) != 1) {
 				ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n");
 				fclose(f);
-				ast_http_request_close_on_completion(ser);
-				ast_http_error(ser, 400, "Bad Request", "Invalid Content-Length in POST request!");
-				return 0;
+				ast_http_error(ser, 500, "Internal server error", "Invalid Content-Length in POST request!");
+				return -1;
 			}
 			ast_debug(1, "Got a Content-Length of %d\n", content_len);
 		} else if (!strcasecmp(var->name, "Content-Type")) {
@@ -369,50 +380,42 @@ static int http_post_callback(struct ast_tcptls_session_instance *ser, const str
 			}
 		}
 	}
-	fprintf(f, "\r\n");
 
-	/*
-	 * Always mark the body read as failed.
-	 *
-	 * XXX Should change readmimefile() to always be sure to read
-	 * the entire body so we can update the read status and
-	 * potentially keep the connection open.
-	 */
-	ast_http_body_read_status(ser, 0);
+	fprintf(f, "\r\n");
 
 	if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) {
 		ast_debug(1, "Cannot find boundary marker in POST request.\n");
 		fclose(f);
-		ast_http_error(ser, 400, "Bad Request", "Cannot find boundary marker in POST request.");
-		return 0;
+
+		return -1;
 	}
 
 	if (fseek(f, SEEK_SET, 0)) {
 		ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n");
 		fclose(f);
 		ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning.");
-		return 0;
+		return -1;
 	}
 
 	post_dir = urih->data;
 
 	message = parse_message(f); /* Takes ownership and will close f */
+
 	if (!message) {
 		ast_log(LOG_ERROR, "Error parsing MIME data\n");
 
-		ast_http_error(ser, 400, "Bad Request", "There was an error parsing the request.");
-		return 0;
+		ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request.");
+		return -1;
 	}
 
 	if (!process_message(message, ast_str_buffer(post_dir))) {
 		ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
 		g_object_unref(message);
-		ast_http_error(ser, 400, "Bad Request", "There was an error parsing the request.");
-		return 0;
+		ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request.");
+		return -1;
 	}
 	g_object_unref(message);
 
-	/* XXX Passing 200 to the error response routine? */
 	ast_http_error(ser, 200, "OK", "File successfully uploaded.");
 	return 0;
 }
@@ -424,7 +427,7 @@ static int __ast_http_post_load(int reload)
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
 	cfg = ast_config_load2("http.conf", "http", config_flags);
-	if (!cfg || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
 		return 0;
 	}
 
@@ -432,43 +435,45 @@ static int __ast_http_post_load(int reload)
 		ast_http_uri_unlink_all_with_key(__FILE__);
 	}
 
-	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
-		if (!strcasecmp(v->name, "prefix")) {
-			ast_copy_string(prefix, v->value, sizeof(prefix));
-			if (prefix[strlen(prefix)] == '/') {
-				prefix[strlen(prefix)] = '\0';
+	if (cfg) {
+		for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+			if (!strcasecmp(v->name, "prefix")) {
+				ast_copy_string(prefix, v->value, sizeof(prefix));
+				if (prefix[strlen(prefix)] == '/') {
+					prefix[strlen(prefix)] = '\0';
+				}
 			}
 		}
-	}
 
-	for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
-		struct ast_http_uri *urih;
-		struct ast_str *ds;
+		for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
+			struct ast_http_uri *urih;
+			struct ast_str *ds;
 
-		if (!(urih = ast_calloc(sizeof(*urih), 1))) {
-			ast_config_destroy(cfg);
-			return -1;
-		}
+			if (!(urih = ast_calloc(sizeof(*urih), 1))) {
+				ast_config_destroy(cfg);
+				return -1;
+			}
 
-		if (!(ds = ast_str_create(32))) {
-			ast_free(urih);
-			ast_config_destroy(cfg);
-			return -1;
-		}
+			if (!(ds = ast_str_create(32))) {
+				ast_free(urih);
+				ast_config_destroy(cfg);
+				return -1;
+			}
 
-		urih->description = ast_strdup("HTTP POST mapping");
-		urih->uri = ast_strdup(v->name);
-		ast_str_set(&ds, 0, "%s", v->value);
-		urih->data = ds;
-		urih->has_subtree = 0;
-		urih->callback = http_post_callback;
-		urih->key = __FILE__;
-		urih->mallocd = urih->dmallocd = 1;
+			urih->description = ast_strdup("HTTP POST mapping");
+			urih->uri = ast_strdup(v->name);
+			ast_str_set(&ds, 0, "%s", v->value);
+			urih->data = ds;
+			urih->has_subtree = 0;
+			urih->callback = http_post_callback;
+			urih->key = __FILE__;
+			urih->mallocd = urih->dmallocd = 1;
 
-		ast_http_uri_link(urih);
-	}
+			ast_http_uri_link(urih);
+		}
 
-	ast_config_destroy(cfg);
+		ast_config_destroy(cfg);
+	}
 	return 0;
 }
 
@@ -496,7 +501,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP POST support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index dac32a2..47c1557 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/http.h"
@@ -37,7 +37,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 #include "asterisk/strings.h"
 #include "asterisk/file.h"
 #include "asterisk/unaligned.h"
-#include "asterisk/uri.h"
 
 #define AST_API_MODULE
 #include "asterisk/http_websocket.h"
@@ -45,14 +44,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429317 $")
 /*! \brief GUID used to compute the accept key, defined in the specifications */
 #define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
 
-/*! \brief Length of a websocket's client key */
-#define CLIENT_KEY_SIZE 16
-
 /*! \brief Number of buckets for registered protocols */
 #define MAX_PROTOCOL_BUCKETS 7
 
 /*! \brief Size of the pre-determined buffer for WebSocket frames */
-#define MAXIMUM_FRAME_SIZE 8192
+#define MAXIMUM_FRAME_SIZE 16384
 
 /*! \brief Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will start a
  *         payload.
@@ -85,7 +81,6 @@ struct ast_websocket {
 	unsigned int secure:1;            /*!< Bit to indicate that the transport is secure */
 	unsigned int closing:1;           /*!< Bit to indicate that the session is in the process of being closed */
 	unsigned int close_sent:1;        /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
-	struct websocket_client *client;  /*!< Client object when connected as a client websocket */
 };
 
 /*! \brief Structure definition for protocols */
@@ -94,6 +89,9 @@ struct websocket_protocol {
 	ast_websocket_callback callback; /*!< Callback called when a new session is established */
 };
 
+/*! \brief Container for registered protocols */
+static struct ao2_container *protocols;
+
 /*! \brief Hashing function for protocols */
 static int protocol_hash_fn(const void *obj, const int flags)
 {
@@ -119,101 +117,49 @@ static void protocol_destroy_fn(void *obj)
 	ast_free(protocol->name);
 }
 
-/*! \brief Structure for a WebSocket server */
-struct ast_websocket_server {
-	struct ao2_container *protocols; /*!< Container for registered protocols */
-};
-
-static void websocket_server_internal_dtor(void *obj)
-{
-	struct ast_websocket_server *server = obj;
-	ao2_cleanup(server->protocols);
-	server->protocols = NULL;
-}
-
-static void websocket_server_dtor(void *obj)
-{
-	websocket_server_internal_dtor(obj);
-	ast_module_unref(ast_module_info->self);
-}
-
-static struct ast_websocket_server *websocket_server_create_impl(void (*dtor)(void *))
-{
-	RAII_VAR(struct ast_websocket_server *, server, NULL, ao2_cleanup);
-
-	server = ao2_alloc(sizeof(*server), dtor);
-	if (!server) {
-		return NULL;
-	}
-
-	server->protocols = ao2_container_alloc(MAX_PROTOCOL_BUCKETS, protocol_hash_fn, protocol_cmp_fn);
-	if (!server->protocols) {
-		return NULL;
-	}
-
-	ao2_ref(server, +1);
-	return server;
-}
-
-static struct ast_websocket_server *websocket_server_internal_create(void)
-{
-	return websocket_server_create_impl(websocket_server_internal_dtor);
-}
-
-struct ast_websocket_server *AST_OPTIONAL_API_NAME(ast_websocket_server_create)(void)
-{
-	ast_module_ref(ast_module_info->self);
-	return websocket_server_create_impl(websocket_server_dtor);
-}
-
 /*! \brief Destructor function for sessions */
 static void session_destroy_fn(void *obj)
 {
 	struct ast_websocket *session = obj;
 
+	ast_websocket_close(session, 0);
+
 	if (session->f) {
-		ast_websocket_close(session, 0);
 		fclose(session->f);
-		ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from",
-			ast_sockaddr_stringify(&session->address));
+		ast_verb(2, "WebSocket connection from '%s' closed\n", ast_sockaddr_stringify(&session->address));
 	}
 
-	ao2_cleanup(session->client);
 	ast_free(session->payload);
 }
 
-int AST_OPTIONAL_API_NAME(ast_websocket_server_add_protocol)(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
+int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback)
 {
 	struct websocket_protocol *protocol;
 
-	if (!server->protocols) {
-		return -1;
-	}
-
-	ao2_lock(server->protocols);
+	ao2_lock(protocols);
 
 	/* Ensure a second protocol handler is not registered for the same protocol */
-	if ((protocol = ao2_find(server->protocols, name, OBJ_KEY | OBJ_NOLOCK))) {
+	if ((protocol = ao2_find(protocols, name, OBJ_KEY | OBJ_NOLOCK))) {
 		ao2_ref(protocol, -1);
-		ao2_unlock(server->protocols);
+		ao2_unlock(protocols);
 		return -1;
 	}
 
 	if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) {
-		ao2_unlock(server->protocols);
+		ao2_unlock(protocols);
 		return -1;
 	}
 
 	if (!(protocol->name = ast_strdup(name))) {
 		ao2_ref(protocol, -1);
-		ao2_unlock(server->protocols);
+		ao2_unlock(protocols);
 		return -1;
 	}
 
 	protocol->callback = callback;
 
-	ao2_link_flags(server->protocols, protocol, OBJ_NOLOCK);
-	ao2_unlock(server->protocols);
+	ao2_link_flags(protocols, protocol, OBJ_NOLOCK);
+	ao2_unlock(protocols);
 	ao2_ref(protocol, -1);
 
 	ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name);
@@ -221,11 +167,11 @@ int AST_OPTIONAL_API_NAME(ast_websocket_server_add_protocol)(struct ast_websocke
 	return 0;
 }
 
-int AST_OPTIONAL_API_NAME(ast_websocket_server_remove_protocol)(struct ast_websocket_server *server, const char *name, ast_websocket_callback callback)
+int AST_OPTIONAL_API_NAME(ast_websocket_remove_protocol)(const char *name, ast_websocket_callback callback)
 {
 	struct websocket_protocol *protocol;
 
-	if (!(protocol = ao2_find(server->protocols, name, OBJ_KEY))) {
+	if (!(protocol = ao2_find(protocols, name, OBJ_KEY))) {
 		return -1;
 	}
 
@@ -234,7 +180,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_server_remove_protocol)(struct ast_webso
 		return -1;
 	}
 
-	ao2_unlink(server->protocols, protocol);
+	ao2_unlink(protocols, protocol);
 	ao2_ref(protocol, -1);
 
 	ast_verb(2, "WebSocket unregistered sub-protocol '%s'\n", name);
@@ -263,7 +209,19 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui
 
 	ao2_lock(session);
 	res = ast_careful_fwrite(session->f, session->fd, frame, 4, session->timeout);
+
+	/* If an error occurred when trying to close this connection explicitly terminate it now.
+	 * Doing so will cause the thread polling on it to wake up and terminate.
+	 */
+	if (res) {
+		fclose(session->f);
+		session->f = NULL;
+		ast_verb(2, "WebSocket connection from '%s' forcefully closed due to fatal write error\n",
+			ast_sockaddr_stringify(&session->address));
+	}
+
 	ao2_unlock(session);
+
 	return res;
 }
 
@@ -273,7 +231,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
 {
 	size_t header_size = 2; /* The minimum size of a websocket frame is 2 bytes */
 	char *frame;
-	uint64_t length = 0;
+	uint64_t length;
 
 	if (actual_length < 126) {
 		length = actual_length;
@@ -288,7 +246,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
 	}
 
 	frame = ast_alloca(header_size);
-	memset(frame, 0, sizeof(*frame));
+	memset(frame, 0, header_size);
 
 	frame[0] = opcode | 0x80;
 	frame[1] = length;
@@ -297,7 +255,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
 	if (length == 126) {
 		put_unaligned_uint16(&frame[2], htons(actual_length));
 	} else if (length == 127) {
-		put_unaligned_uint64(&frame[2], htonl(actual_length));
+		put_unaligned_uint64(&frame[2], htonll(actual_length));
 	}
 
 	ao2_lock(session);
@@ -305,13 +263,18 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
 		ao2_unlock(session);
 		return -1;
 	}
+
 	if (ast_careful_fwrite(session->f, session->fd, frame, header_size, session->timeout)) {
 		ao2_unlock(session);
+		/* 1011 - server terminating connection due to not being able to fulfill the request */
+		ast_websocket_close(session, 1011);
 		return -1;
 	}
 
 	if (ast_careful_fwrite(session->f, session->fd, payload, actual_length, session->timeout)) {
 		ao2_unlock(session);
+		/* 1011 - server terminating connection due to not being able to fulfill the request */
+		ast_websocket_close(session, 1011);
 		return -1;
 	}
 	fflush(session->f);
@@ -337,7 +300,7 @@ void AST_OPTIONAL_API_NAME(ast_websocket_ref)(struct ast_websocket *session)
 
 void AST_OPTIONAL_API_NAME(ast_websocket_unref)(struct ast_websocket *session)
 {
-	ao2_cleanup(session);
+	ao2_ref(session, -1);
 }
 
 int AST_OPTIONAL_API_NAME(ast_websocket_fd)(struct ast_websocket *session)
@@ -409,18 +372,45 @@ int AST_OPTIONAL_API_NAME(ast_websocket_set_timeout)(struct ast_websocket *sessi
  */
 static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len, enum ast_websocket_opcode *opcode)
 {
-	int sanity;
 	size_t rlen;
 	int xlen = len;
 	char *rbuf = buf;
-	for (sanity = 10; sanity; sanity--) {
+	int sanity = 10;
+
+	ao2_lock(session);
+	if (!session->f) {
+		ao2_unlock(session);
+		errno = ECONNABORTED;
+		return -1;
+	}
+
+	for (;;) {
 		clearerr(session->f);
 		rlen = fread(rbuf, 1, xlen, session->f);
-		if (!rlen && ferror(session->f) && errno != EAGAIN) {
-			ast_log(LOG_ERROR, "Error reading from web socket: %s\n", strerror(errno));
-			*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
-			session->closing = 1;
-			return -1;
+		if (!rlen) {
+			if (feof(session->f)) {
+				ast_log(LOG_WARNING, "Web socket closed abruptly\n");
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				ao2_unlock(session);
+				return -1;
+			}
+
+			if (ferror(session->f) && errno != EAGAIN) {
+				ast_log(LOG_ERROR, "Error reading from web socket: %s\n", strerror(errno));
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				ao2_unlock(session);
+				return -1;
+			}
+
+			if (!--sanity) {
+				ast_log(LOG_WARNING, "Websocket seems unresponsive, disconnecting ...\n");
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				ao2_unlock(session);
+				return -1;
+			}
 		}
 		xlen = xlen - rlen;
 		rbuf = rbuf + rlen;
@@ -431,15 +421,12 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len
 			ast_log(LOG_ERROR, "ast_wait_for_input returned err: %s\n", strerror(errno));
 			*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
 			session->closing = 1;
+			ao2_unlock(session);
 			return -1;
 		}
 	}
-	if (!sanity) {
-		ast_log(LOG_WARNING, "Websocket seems unresponsive, disconnecting ...\n");
-		*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
-		session->closing = 1;
-		return -1;
-	}
+
+	ao2_unlock(session);
 	return 0;
 }
 
@@ -456,7 +443,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 	*fragmented = 0;
 
 	if (ws_safe_read(session, &buf[0], MIN_WS_HDR_SZ, opcode)) {
-		return 0;
+		return -1;
 	}
 	frame_size += MIN_WS_HDR_SZ;
 
@@ -474,7 +461,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 		if (options_len) {
 			/* read the rest of the header options */
 			if (ws_safe_read(session, &buf[frame_size], options_len, opcode)) {
-				return 0;
+				return -1;
 			}
 			frame_size += options_len;
 		}
@@ -503,8 +490,9 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 		}
 
 		if (ws_safe_read(session, *payload, *payload_len, opcode)) {
-			return 0;
+			return -1;
 		}
+
 		/* If a mask is present unmask the payload */
 		if (mask_present) {
 			unsigned int pos;
@@ -526,7 +514,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 					session->payload, session->payload_len, *payload_len);
 				*payload_len = 0;
 				ast_websocket_close(session, 1009);
-				return 0;
+				return -1;
 			}
 
 			session->payload = new_payload;
@@ -563,7 +551,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 		/* Make the payload available so the user can look at the reason code if they so desire */
 		if ((*payload_len) && (new_payload = ast_realloc(session->payload, *payload_len))) {
 			if (ws_safe_read(session, &buf[frame_size], (*payload_len), opcode)) {
-				return 0;
+				return -1;
 			}
 			session->payload = new_payload;
 			memcpy(session->payload, &buf[frame_size], *payload_len);
@@ -582,66 +570,21 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
 	return 0;
 }
 
-/*!
- * \brief If the server has exactly one configured protocol, return it.
- */
-static struct websocket_protocol *one_protocol(
-	struct ast_websocket_server *server)
-{
-	SCOPED_AO2LOCK(lock, server->protocols);
-
-	if (ao2_container_count(server->protocols) != 1) {
-		return NULL;
-	}
-
-	return ao2_callback(server->protocols, OBJ_NOLOCK, NULL, NULL);
-}
-
-static char *websocket_combine_key(const char *key, char *res, int res_size)
-{
-	char *combined;
-	unsigned combined_length = strlen(key) + strlen(WEBSOCKET_GUID) + 1;
-	uint8_t sha[20];
-
-	combined = ast_alloca(combined_length);
-	snprintf(combined, combined_length, "%s%s", key, WEBSOCKET_GUID);
-	ast_sha1_hash_uint(sha, combined);
-	ast_base64encode(res, (const unsigned char*)sha, 20, res_size);
-	return res;
-}
-
-static void websocket_bad_request(struct ast_tcptls_session_instance *ser)
-{
-	struct ast_str *http_header = ast_str_create(64);
-
-	if (!http_header) {
-		ast_http_request_close_on_completion(ser);
-		ast_http_error(ser, 500, "Server Error", "Out of memory");
-		return;
-	}
-	ast_str_set(&http_header, 0, "Sec-WebSocket-Version: 7, 8, 13\r\n");
-	ast_http_send(ser, AST_HTTP_UNKNOWN, 400, "Bad Request", http_header, NULL, 0, 0);
-}
-
-int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
+/*! \brief Callback that is executed everytime an HTTP request is received by this module */
+static int websocket_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
 {
 	struct ast_variable *v;
 	char *upgrade = NULL, *key = NULL, *key1 = NULL, *key2 = NULL, *protos = NULL, *requested_protocols = NULL, *protocol = NULL;
 	int version = 0, flags = 1;
 	struct websocket_protocol *protocol_handler = NULL;
 	struct ast_websocket *session;
-	struct ast_websocket_server *server;
-
-	SCOPED_MODULE_USE(ast_module_info->self);
 
 	/* Upgrade requests are only permitted on GET methods */
 	if (method != AST_HTTP_GET) {
 		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+		return -1;
 	}
 
-	server = urih->data;
-
 	/* Get the minimum headers required to satisfy our needs */
 	for (v = headers; v; v = v->next) {
 		if (!strcasecmp(v->name, "Upgrade")) {
@@ -667,53 +610,52 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
 		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - did not request WebSocket\n",
 			ast_sockaddr_stringify(&ser->remote_address));
 		ast_http_error(ser, 426, "Upgrade Required", NULL);
-		return 0;
+		return -1;
 	} else if (ast_strlen_zero(requested_protocols)) {
-		/* If there's only a single protocol registered, and the
-		 * client doesn't specify what protocol it's using, go ahead
-		 * and accept the connection */
-		protocol_handler = one_protocol(server);
-		if (!protocol_handler) {
-			/* Multiple registered subprotocols; client must specify */
-			ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - no protocols requested\n",
-				ast_sockaddr_stringify(&ser->remote_address));
-			websocket_bad_request(ser);
-			return 0;
-		}
+		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - no protocols requested\n",
+			ast_sockaddr_stringify(&ser->remote_address));
+		fputs("HTTP/1.1 400 Bad Request\r\n"
+		      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
+		return -1;
 	} else if (key1 && key2) {
 		/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 and
 		 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00 -- not currently supported*/
 		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - unsupported version '00/76' chosen\n",
 			ast_sockaddr_stringify(&ser->remote_address));
-		websocket_bad_request(ser);
+		fputs("HTTP/1.1 400 Bad Request\r\n"
+		      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 		return 0;
 	}
 
 	/* Iterate through the requested protocols trying to find one that we have a handler for */
-	while (!protocol_handler && (protocol = strsep(&requested_protocols, ","))) {
-		protocol_handler = ao2_find(server->protocols, ast_strip(protocol), OBJ_KEY);
+	while ((protocol = strsep(&requested_protocols, ","))) {
+		if ((protocol_handler = ao2_find(protocols, ast_strip(protocol), OBJ_KEY))) {
+			break;
+		}
 	}
 
 	/* If no protocol handler exists bump this back to the requester */
 	if (!protocol_handler) {
 		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - no protocols out of '%s' supported\n",
 			ast_sockaddr_stringify(&ser->remote_address), protos);
-		websocket_bad_request(ser);
+		fputs("HTTP/1.1 400 Bad Request\r\n"
+		      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 		return 0;
 	}
 
 	/* Determine how to respond depending on the version */
 	if (version == 7 || version == 8 || version == 13) {
-		char base64[64];
-
-		if (!key || strlen(key) + strlen(WEBSOCKET_GUID) + 1 > 8192) { /* no stack overflows please */
-			websocket_bad_request(ser);
-			ao2_ref(protocol_handler, -1);
-			return 0;
-		}
-
-		if (ast_http_body_discard(ser)) {
-			websocket_bad_request(ser);
+		/* Version 7 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07 */
+		/* Version 8 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10 */
+		/* Version 13 defined in specification http://tools.ietf.org/html/rfc6455 */
+		char *combined, base64[64];
+		unsigned combined_length;
+		uint8_t sha[20];
+
+		combined_length = (key ? strlen(key) : 0) + strlen(WEBSOCKET_GUID) + 1;
+		if (!key || combined_length > 8192) { /* no stack overflows please */
+			fputs("HTTP/1.1 400 Bad Request\r\n"
+			      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 			ao2_ref(protocol_handler, -1);
 			return 0;
 		}
@@ -721,41 +663,34 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
 		if (!(session = ao2_alloc(sizeof(*session), session_destroy_fn))) {
 			ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted\n",
 				ast_sockaddr_stringify(&ser->remote_address));
-			websocket_bad_request(ser);
+			fputs("HTTP/1.1 400 Bad Request\r\n"
+			      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 			ao2_ref(protocol_handler, -1);
 			return 0;
 		}
-		session->timeout =  AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
+		session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
+
+		combined = ast_alloca(combined_length);
+		snprintf(combined, combined_length, "%s%s", key, WEBSOCKET_GUID);
+		ast_sha1_hash_uint(sha, combined);
+		ast_base64encode(base64, (const unsigned char*)sha, 20, sizeof(base64));
 
 		fprintf(ser->f, "HTTP/1.1 101 Switching Protocols\r\n"
 			"Upgrade: %s\r\n"
 			"Connection: Upgrade\r\n"
-			"Sec-WebSocket-Accept: %s\r\n",
+			"Sec-WebSocket-Accept: %s\r\n"
+			"Sec-WebSocket-Protocol: %s\r\n\r\n",
 			upgrade,
-			websocket_combine_key(key, base64, sizeof(base64)));
-
-		/* RFC 6455, Section 4.1:
-		 *
-		 * 6. If the response includes a |Sec-WebSocket-Protocol| header
-		 *    field and this header field indicates the use of a
-		 *    subprotocol that was not present in the client's handshake
-		 *    (the server has indicated a subprotocol not requested by
-		 *    the client), the client MUST _Fail the WebSocket
-		 *    Connection_.
-		 */
-		if (protocol) {
-			fprintf(ser->f, "Sec-WebSocket-Protocol: %s\r\n",
-				protocol);
-		}
-
-		fprintf(ser->f, "\r\n");
+			base64,
+			protocol);
 		fflush(ser->f);
 	} else {
 
 		/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 or completely unknown */
 		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - unsupported version '%d' chosen\n",
 			ast_sockaddr_stringify(&ser->remote_address), version ? version : 75);
-		websocket_bad_request(ser);
+		fputs("HTTP/1.1 400 Bad Request\r\n"
+		      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 		ao2_ref(protocol_handler, -1);
 		return 0;
 	}
@@ -764,13 +699,14 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
 	if (setsockopt(ser->fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) {
 		ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to enable keepalive\n",
 			ast_sockaddr_stringify(&ser->remote_address));
-		websocket_bad_request(ser);
+		fputs("HTTP/1.1 400 Bad Request\r\n"
+		      "Sec-WebSocket-Version: 7, 8, 13\r\n\r\n", ser->f);
 		ao2_ref(session, -1);
 		ao2_ref(protocol_handler, -1);
 		return 0;
 	}
 
-	ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version);
+	ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol, version);
 
 	/* Populate the session with all the needed details */
 	session->f = ser->f;
@@ -781,7 +717,6 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
 	session->secure = ser->ssl ? 1 : 0;
 
 	/* Give up ownership of the socket and pass it to the protocol handler */
-	ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0);
 	protocol_handler->callback(session, get_vars, headers);
 	ao2_ref(protocol_handler, -1);
 
@@ -797,7 +732,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
 }
 
 static struct ast_http_uri websocketuri = {
-	.callback = AST_OPTIONAL_API_NAME(ast_websocket_uri_cb),
+	.callback = websocket_callback,
 	.description = "Asterisk HTTP WebSocket",
 	.uri = "ws",
 	.has_subtree = 0,
@@ -848,465 +783,25 @@ end:
 	ast_websocket_unref(session);
 }
 
-static int websocket_add_protocol_internal(const char *name, ast_websocket_callback callback)
-{
-	struct ast_websocket_server *ws_server = websocketuri.data;
-	if (!ws_server) {
-		return -1;
-	}
-	return ast_websocket_server_add_protocol(ws_server, name, callback);
-}
-
-int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback)
-{
-	int res = websocket_add_protocol_internal(name, callback);
-	if (res == 0) {
-		ast_module_ref(ast_module_info->self);
-	}
-	return res;
-}
-
-static int websocket_remove_protocol_internal(const char *name, ast_websocket_callback callback)
-{
-	struct ast_websocket_server *ws_server = websocketuri.data;
-	if (!ws_server) {
-		return -1;
-	}
-	return ast_websocket_server_remove_protocol(ws_server, name, callback);
-}
-
-int AST_OPTIONAL_API_NAME(ast_websocket_remove_protocol)(const char *name, ast_websocket_callback callback)
-{
-	int res = websocket_remove_protocol_internal(name, callback);
-	if (res == 0) {
-		ast_module_unref(ast_module_info->self);
-	}
-	return res;
-}
-
-/*! \brief Parse the given uri into a path and remote address.
- *
- * Expected uri form: [ws[s]]://<host>[:port][/<path>]
- *
- * The returned host will contain the address and optional port while
- * path will contain everything after the address/port if included.
- */
-static int websocket_client_parse_uri(const char *uri, char **host, struct ast_str **path)
-{
-	struct ast_uri *parsed_uri = ast_uri_parse_websocket(uri);
-
-	if (!parsed_uri) {
-		return -1;
-	}
-
-	*host = ast_uri_make_host_with_port(parsed_uri);
-
-	if (ast_uri_path(parsed_uri) || ast_uri_query(parsed_uri)) {
-		*path = ast_str_create(64);
-		if (!*path) {
-			ao2_ref(parsed_uri, -1);
-			return -1;
-		}
-
-		if (ast_uri_path(parsed_uri)) {
-			ast_str_set(path, 0, "%s", ast_uri_path(parsed_uri));
-		}
-
-		if (ast_uri_query(parsed_uri)) {
-			ast_str_append(path, 0, "?%s", ast_uri_query(parsed_uri));
-		}
-	}
-
-	ao2_ref(parsed_uri, -1);
-	return 0;
-}
-
-static void websocket_client_args_destroy(void *obj)
-{
-	struct ast_tcptls_session_args *args = obj;
-
-	if (args->tls_cfg) {
-		ast_free(args->tls_cfg->certfile);
-		ast_free(args->tls_cfg->pvtfile);
-		ast_free(args->tls_cfg->cipher);
-		ast_free(args->tls_cfg->cafile);
-		ast_free(args->tls_cfg->capath);
-
-		ast_ssl_teardown(args->tls_cfg);
-	}
-	ast_free(args->tls_cfg);
-}
-
-static struct ast_tcptls_session_args *websocket_client_args_create(
-	const char *host, struct ast_tls_config *tls_cfg,
-	enum ast_websocket_result *result)
-{
-	struct ast_sockaddr *addr;
-	struct ast_tcptls_session_args *args = ao2_alloc(
-		sizeof(*args), websocket_client_args_destroy);
-
-	if (!args) {
-		*result = WS_ALLOCATE_ERROR;
-		return NULL;
-	}
-
-	args->accept_fd = -1;
-	args->tls_cfg = tls_cfg;
-	args->name = "websocket client";
-
-	if (!ast_sockaddr_resolve(&addr, host, 0, 0)) {
-		ast_log(LOG_ERROR, "Unable to resolve address %s\n",
-			host);
-		ao2_ref(args, -1);
-		*result = WS_URI_RESOLVE_ERROR;
-		return NULL;
-	}
-	ast_sockaddr_copy(&args->remote_address, addr);
-	ast_free(addr);
-	return args;
-}
-
-static char *websocket_client_create_key(void)
-{
-	static int encoded_size = CLIENT_KEY_SIZE * 2 * sizeof(char) + 1;
-	/* key is randomly selected 16-byte base64 encoded value */
-	unsigned char key[CLIENT_KEY_SIZE + sizeof(long) - 1];
-	char *encoded = ast_malloc(encoded_size);
-	long i = 0;
-
-	if (!encoded) {
-		ast_log(LOG_ERROR, "Unable to allocate client websocket key\n");
-		return NULL;
-	}
-
-	while (i < CLIENT_KEY_SIZE) {
-		long num = ast_random();
-		memcpy(key + i, &num, sizeof(long));
-		i += sizeof(long);
-	}
-
-	ast_base64encode(encoded, key, CLIENT_KEY_SIZE, encoded_size);
-	return encoded;
-}
-
-struct websocket_client {
-	/*! host portion of client uri */
-	char *host;
-	/*! path for logical websocket connection */
-	struct ast_str *resource_name;
-	/*! unique key used during server handshaking */
-	char *key;
-	/*! container for registered protocols */
-	char *protocols;
-	/*! the protocol accepted by the server */
-	char *accept_protocol;
-	/*! websocket protocol version */
-	int version;
-	/*! tcptls connection arguments */
-	struct ast_tcptls_session_args *args;
-	/*! tcptls connection instance */
-	struct ast_tcptls_session_instance *ser;
-};
-
-static void websocket_client_destroy(void *obj)
-{
-	struct websocket_client *client = obj;
-
-	ao2_cleanup(client->ser);
-	ao2_cleanup(client->args);
-
-	ast_free(client->accept_protocol);
-	ast_free(client->protocols);
-	ast_free(client->key);
-	ast_free(client->resource_name);
-	ast_free(client->host);
-}
-
-static struct ast_websocket * websocket_client_create(
-	const char *uri, const char *protocols,	struct ast_tls_config *tls_cfg,
-	enum ast_websocket_result *result)
-{
-	struct ast_websocket *ws = ao2_alloc(sizeof(*ws), session_destroy_fn);
-
-	if (!ws) {
-		ast_log(LOG_ERROR, "Unable to allocate websocket\n");
-		*result = WS_ALLOCATE_ERROR;
-		return NULL;
-	}
-
-	if (!(ws->client = ao2_alloc(
-		      sizeof(*ws->client), websocket_client_destroy))) {
-		ast_log(LOG_ERROR, "Unable to allocate websocket client\n");
-		*result = WS_ALLOCATE_ERROR;
-		return NULL;
-	}
-
-	if (!(ws->client->key = websocket_client_create_key())) {
-		ao2_ref(ws, -1);
-		*result = WS_KEY_ERROR;
-		return NULL;
-	}
-
-	if (websocket_client_parse_uri(
-		    uri, &ws->client->host, &ws->client->resource_name)) {
-		ao2_ref(ws, -1);
-		*result = WS_URI_PARSE_ERROR;
-		return NULL;
-	}
-
-	if (!(ws->client->args = websocket_client_args_create(
-		      ws->client->host, tls_cfg, result))) {
-		ao2_ref(ws, -1);
-		return NULL;
-	}
-	ws->client->protocols = ast_strdup(protocols);
-
-	ws->client->version = 13;
-	ws->opcode = -1;
-	ws->reconstruct = DEFAULT_RECONSTRUCTION_CEILING;
-	return ws;
-}
-
-const char * AST_OPTIONAL_API_NAME(
-	ast_websocket_client_accept_protocol)(struct ast_websocket *ws)
-{
-	return ws->client->accept_protocol;
-}
-
-static enum ast_websocket_result websocket_client_handle_response_code(
-	struct websocket_client *client, int response_code)
-{
-	if (response_code <= 0) {
-		return WS_INVALID_RESPONSE;
-	}
-
-	switch (response_code) {
-	case 101:
-		return 0;
-	case 400:
-		ast_log(LOG_ERROR, "Received response 400 - Bad Request "
-			"- from %s\n", client->host);
-		return WS_BAD_REQUEST;
-	case 404:
-		ast_log(LOG_ERROR, "Received response 404 - Request URL not "
-			"found - from %s\n", client->host);
-		return WS_URL_NOT_FOUND;
-	}
-
-	ast_log(LOG_ERROR, "Invalid HTTP response code %d from %s\n",
-		response_code, client->host);
-	return WS_INVALID_RESPONSE;
-}
-
-static enum ast_websocket_result websocket_client_handshake_get_response(
-	struct websocket_client *client)
-{
-	enum ast_websocket_result res;
-	char buf[4096];
-	char base64[64];
-	int has_upgrade = 0;
-	int has_connection = 0;
-	int has_accept = 0;
-	int has_protocol = 0;
-
-	if (!fgets(buf, sizeof(buf), client->ser->f)) {
-		ast_log(LOG_ERROR, "Unable to retrieve HTTP status line.");
-		return WS_BAD_STATUS;
-	}
-
-	if ((res = websocket_client_handle_response_code(client,
-		    ast_http_response_status_line(
-			    buf, "HTTP/1.1", 101))) != WS_OK) {
-		return res;
-	}
-
-	/* Ignoring line folding - assuming header field values are contained
-	   within a single line */
-	while (fgets(buf, sizeof(buf), client->ser->f)) {
-		char *name, *value;
-		int parsed = ast_http_header_parse(buf, &name, &value);
-
-		if (parsed < 0) {
-			break;
-		}
-
-		if (parsed > 0) {
-			continue;
-		}
-
-		if (!has_upgrade &&
-		    (has_upgrade = ast_http_header_match(
-			    name, "upgrade", value, "websocket")) < 0) {
-			return WS_HEADER_MISMATCH;
-		} else if (!has_connection &&
-			   (has_connection = ast_http_header_match(
-				   name, "connection", value, "upgrade")) < 0) {
-			return WS_HEADER_MISMATCH;
-		} else if (!has_accept &&
-			   (has_accept = ast_http_header_match(
-				   name, "sec-websocket-accept", value,
-			    websocket_combine_key(
-				    client->key, base64, sizeof(base64)))) < 0) {
-			return WS_HEADER_MISMATCH;
-		} else if (!has_protocol &&
-			   (has_protocol = ast_http_header_match_in(
-				   name, "sec-websocket-protocol", value, client->protocols))) {
-			if (has_protocol < 0) {
-				return WS_HEADER_MISMATCH;
-			}
-			client->accept_protocol = ast_strdup(value);
-		} else if (!strcasecmp(name, "sec-websocket-extensions")) {
-			ast_log(LOG_ERROR, "Extensions received, but not "
-				"supported by client\n");
-			return WS_NOT_SUPPORTED;
-		}
-	}
-	return has_upgrade && has_connection && has_accept ?
-		WS_OK : WS_HEADER_MISSING;
-}
-
-static enum ast_websocket_result websocket_client_handshake(
-	struct websocket_client *client)
-{
-	char protocols[100] = "";
-
-	if (!ast_strlen_zero(client->protocols)) {
-		sprintf(protocols, "Sec-WebSocket-Protocol: %s\r\n",
-			client->protocols);
-	}
-
-	if (fprintf(client->ser->f,
-		    "GET /%s HTTP/1.1\r\n"
-		    "Sec-WebSocket-Version: %d\r\n"
-		    "Upgrade: websocket\r\n"
-		    "Connection: Upgrade\r\n"
-		    "Host: %s\r\n"
-		    "Sec-WebSocket-Key: %s\r\n"
-		    "%s\r\n",
-		    client->resource_name ? ast_str_buffer(client->resource_name) : "",
-		    client->version,
-		    client->host,
-		    client->key,
-		    protocols) < 0) {
-		ast_log(LOG_ERROR, "Failed to send handshake.\n");
-		return WS_WRITE_ERROR;
-	}
-	/* wait for a response before doing anything else */
-	return websocket_client_handshake_get_response(client);
-}
-
-static enum ast_websocket_result websocket_client_connect(struct ast_websocket *ws)
-{
-	enum ast_websocket_result res;
-	/* create and connect the client - note client_start
-	   releases the session instance on failure */
-	if (!(ws->client->ser = ast_tcptls_client_start(
-		      ast_tcptls_client_create(ws->client->args)))) {
-		return WS_CLIENT_START_ERROR;
-	}
-
-	if ((res = websocket_client_handshake(ws->client)) != WS_OK) {
-		ao2_ref(ws->client->ser, -1);
-		ws->client->ser = NULL;
-		return res;
-	}
-
-	ws->f = ws->client->ser->f;
-	ws->fd = ws->client->ser->fd;
-	ws->secure = ws->client->ser->ssl ? 1 : 0;
-	ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address);
-	return WS_OK;
-}
-
-struct ast_websocket *AST_OPTIONAL_API_NAME(ast_websocket_client_create)
-	(const char *uri, const char *protocols, struct ast_tls_config *tls_cfg,
-	 enum ast_websocket_result *result)
-{
-	struct ast_websocket *ws = websocket_client_create(
-		uri, protocols, tls_cfg, result);
-
-	if (!ws) {
-		return NULL;
-	}
-
-	if ((*result = websocket_client_connect(ws)) != WS_OK) {
-		ao2_ref(ws, -1);
-		return NULL;
-	}
-
-	return ws;
-}
-
-int AST_OPTIONAL_API_NAME(ast_websocket_read_string)
-	(struct ast_websocket *ws, char **buf)
-{
-	char *payload;
-	uint64_t payload_len;
-	enum ast_websocket_opcode opcode;
-	int fragmented = 1;
-
-	while (fragmented) {
-		if (ast_websocket_read(ws, &payload, &payload_len,
-				       &opcode, &fragmented)) {
-			ast_log(LOG_ERROR, "Client WebSocket string read - "
-				"error reading string data\n");
-			return -1;
-		}
-
-		if (opcode == AST_WEBSOCKET_OPCODE_CONTINUATION) {
-			continue;
-		}
-
-		if (opcode == AST_WEBSOCKET_OPCODE_CLOSE) {
-			return -1;
-		}
-
-		if (opcode != AST_WEBSOCKET_OPCODE_TEXT) {
-			ast_log(LOG_ERROR, "Client WebSocket string read - "
-				"non string data received\n");
-			return -1;
-		}
-	}
-
-	if (!(*buf = ast_malloc(payload_len + 1))) {
-		return -1;
-	}
-
-	ast_copy_string(*buf, payload, payload_len + 1);
-	return payload_len + 1;
-}
-
-int AST_OPTIONAL_API_NAME(ast_websocket_write_string)
-	(struct ast_websocket *ws, const char *buf)
-{
-	return ast_websocket_write(ws, AST_WEBSOCKET_OPCODE_TEXT,
-				   (char *)buf, strlen(buf));
-}
-
 static int load_module(void)
 {
-	websocketuri.data = websocket_server_internal_create();
-	if (!websocketuri.data) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
+	protocols = ao2_container_alloc(MAX_PROTOCOL_BUCKETS, protocol_hash_fn, protocol_cmp_fn);
 	ast_http_uri_link(&websocketuri);
-	websocket_add_protocol_internal("echo", websocket_echo_callback);
+	ast_websocket_add_protocol("echo", websocket_echo_callback);
 
 	return 0;
 }
 
 static int unload_module(void)
 {
-	websocket_remove_protocol_internal("echo", websocket_echo_callback);
+	ast_websocket_remove_protocol("echo", websocket_echo_callback);
 	ast_http_uri_unlink(&websocketuri);
-	ao2_ref(websocketuri.data, -1);
-	websocketuri.data = NULL;
+	ao2_ref(protocols, -1);
 
 	return 0;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HTTP WebSocket Support",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_http_websocket.exports.in b/res/res_http_websocket.exports.in
index 3774aeb..273192f 100644
--- a/res/res_http_websocket.exports.in
+++ b/res/res_http_websocket.exports.in
@@ -1,6 +1,18 @@
 {
 	global:
-		LINKER_SYMBOL_PREFIX*ast_websocket_*;
+		LINKER_SYMBOL_PREFIX*ast_websocket_add_protocol;
+		LINKER_SYMBOL_PREFIX*ast_websocket_remove_protocol;
+		LINKER_SYMBOL_PREFIX*ast_websocket_read;
+		LINKER_SYMBOL_PREFIX*ast_websocket_write;
+		LINKER_SYMBOL_PREFIX*ast_websocket_close;
+		LINKER_SYMBOL_PREFIX*ast_websocket_reconstruct_enable;
+		LINKER_SYMBOL_PREFIX*ast_websocket_reconstruct_disable;
+		LINKER_SYMBOL_PREFIX*ast_websocket_ref;
+		LINKER_SYMBOL_PREFIX*ast_websocket_unref;
+		LINKER_SYMBOL_PREFIX*ast_websocket_fd;
+		LINKER_SYMBOL_PREFIX*ast_websocket_remote_address;
+		LINKER_SYMBOL_PREFIX*ast_websocket_is_secure;
+		LINKER_SYMBOL_PREFIX*ast_websocket_set_nonblock;
 		LINKER_SYMBOL_PREFIX*ast_websocket_set_timeout;
 	local:
 		*;
diff --git a/res/res_jabber.c b/res/res_jabber.c
new file mode 100644
index 0000000..5ee7698
--- /dev/null
+++ b/res/res_jabber.c
@@ -0,0 +1,4830 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2010, Digium, Inc.
+ *
+ * Matt O'Gorman <mogorman at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief A resource for interfacing Asterisk directly as a client
+ * or a component to a XMPP/Jabber compliant server.
+ *
+ * References:
+ * - http://www.xmpp.org - The XMPP standards foundation
+ *
+ * \extref Iksemel http://code.google.com/p/iksemel/
+ *
+ * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
+ * \todo Dialplan applications need RETURN variable, like JABBERSENDSTATUS
+ *
+ */
+
+/*** MODULEINFO
+        <defaultenabled>no</defaultenabled>
+	<depend>iksemel</depend>
+	<use type="external">openssl</use>
+	<support_level>deprecated</support_level>
+	<replacement>res_xmpp</replacement>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <ctype.h>
+#include <iksemel.h>
+
+#include "asterisk/channel.h"
+#include "asterisk/jabber.h"
+#include "asterisk/file.h"
+#include "asterisk/config.h"
+#include "asterisk/callerid.h"
+#include "asterisk/lock.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/pbx.h"
+#include "asterisk/md5.h"
+#include "asterisk/acl.h"
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/astobj.h"
+#include "asterisk/astdb.h"
+#include "asterisk/manager.h"
+#include "asterisk/event.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/message.h"
+
+/*** DOCUMENTATION
+	<application name="JabberSend" language="en_US" module="res_jabber">
+		<synopsis>
+			Sends an XMPP message to a buddy.
+		</synopsis>
+		<syntax>
+			<parameter name="account" required="true">
+				<para>The local named account to listen on (specified in
+				jabber.conf)</para>
+			</parameter>
+			<parameter name="jid" required="true">
+				<para>Jabber ID of the buddy to send the message to. It can be a
+				bare JID (username at domain) or a full JID (username at domain/resource).</para>
+			</parameter>
+			<parameter name="message" required="true">
+				<para>The message to send.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Sends the content of <replaceable>message</replaceable> as text message
+			from the given <replaceable>account</replaceable> to the buddy identified by
+			<replaceable>jid</replaceable></para>
+			<para>Example: JabberSend(asterisk,bob at domain.com,Hello world) sends "Hello world"
+			to <replaceable>bob at domain.com</replaceable> as an XMPP message from the account
+			<replaceable>asterisk</replaceable>, configured in jabber.conf.</para>
+		</description>
+		<see-also>
+			<ref type="function" module="res_jabber">JABBER_STATUS</ref>
+			<ref type="function" module="res_jabber">JABBER_RECEIVE</ref>
+		</see-also>
+	</application>
+	<function name="JABBER_RECEIVE" language="en_US" module="res_jabber">
+		<synopsis>
+			Reads XMPP messages.
+		</synopsis>
+		<syntax>
+			<parameter name="account" required="true">
+				<para>The local named account to listen on (specified in
+				jabber.conf)</para>
+			</parameter>
+			<parameter name="jid" required="true">
+				<para>Jabber ID of the buddy to receive message from. It can be a
+				bare JID (username at domain) or a full JID (username at domain/resource).</para>
+			</parameter>
+			<parameter name="timeout">
+				<para>In seconds, defaults to <literal>20</literal>.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Receives a text message on the given <replaceable>account</replaceable>
+			from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
+			<para>Example: ${JABBER_RECEIVE(asterisk,bob at domain.com)} returns an XMPP message
+			sent from <replaceable>bob at domain.com</replaceable> (or nothing in case of a time out), to
+			the <replaceable>asterisk</replaceable> XMPP account configured in jabber.conf.</para>
+		</description>
+		<see-also>
+			<ref type="function" module="res_jabber">JABBER_STATUS</ref>
+			<ref type="application" module="res_jabber">JabberSend</ref>
+		</see-also>
+	</function>
+	<function name="JABBER_STATUS" language="en_US" module="res_jabber">
+		<synopsis>
+			Retrieves a buddy's status.
+		</synopsis>
+		<syntax>
+			<parameter name="account" required="true">
+				<para>The local named account to listen on (specified in
+				jabber.conf)</para>
+			</parameter>
+			<parameter name="jid" required="true">
+				<para>Jabber ID of the buddy to receive message from. It can be a
+				bare JID (username at domain) or a full JID (username at domain/resource).</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Retrieves the numeric status associated with the buddy identified
+			by <replaceable>jid</replaceable>.
+			If the buddy does not exist in the buddylist, returns 7.</para>
+			<para>Status will be 1-7.</para>
+			<para>1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline</para>
+			<para>If not in roster variable will be set to 7.</para>
+			<para>Example: ${JABBER_STATUS(asterisk,bob at domain.com)} returns 1 if
+			<replaceable>bob at domain.com</replaceable> is online. <replaceable>asterisk</replaceable> is
+			the associated XMPP account configured in jabber.conf.</para>
+		</description>
+		<see-also>
+			<ref type="function" module="res_jabber">JABBER_RECEIVE</ref>
+			<ref type="application" module="res_jabber">JabberSend</ref>
+		</see-also>
+	</function>
+	<application name="JabberSendGroup" language="en_US" module="res_jabber">
+		<synopsis>
+			Send a Jabber Message to a specified chat room
+		</synopsis>
+		<syntax>
+			<parameter name="Jabber" required="true">
+				<para>Client or transport Asterisk uses to connect to Jabber.</para>
+			</parameter>
+			<parameter name="RoomJID" required="true">
+				<para>XMPP/Jabber JID (Name) of chat room.</para>
+			</parameter>
+			<parameter name="Message" required="true">
+				<para>Message to be sent to the chat room.</para>
+			</parameter>
+			<parameter name="Nickname" required="false">
+				<para>The nickname Asterisk uses in the chat room.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Allows user to send a message to a chat room via XMPP.</para>
+			<note><para>To be able to send messages to a chat room, a user must have previously joined it. Use the <replaceable>JabberJoin</replaceable> function to do so.</para></note>
+		</description>
+	</application>
+	<application name="JabberJoin" language="en_US" module="res_jabber">
+		<synopsis>
+			Join a chat room
+		</synopsis>
+		<syntax>
+			<parameter name="Jabber" required="true">
+				<para>Client or transport Asterisk uses to connect to Jabber.</para>
+			</parameter>
+			<parameter name="RoomJID" required="true">
+				<para>XMPP/Jabber JID (Name) of chat room.</para>
+			</parameter>
+			<parameter name="Nickname" required="false">
+				<para>The nickname Asterisk will use in the chat room.</para>
+				<note><para>If a different nickname is supplied to an already joined room, the old nick will be changed to the new one.</para></note>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Allows Asterisk to join a chat room.</para>
+		</description>
+	</application>
+	<application name="JabberLeave" language="en_US" module="res_jabber">
+		<synopsis>
+			Leave a chat room
+		</synopsis>
+		<syntax>
+			<parameter name="Jabber" required="true">
+				<para>Client or transport Asterisk uses to connect to Jabber.</para>
+			</parameter>
+			<parameter name="RoomJID" required="true">
+				<para>XMPP/Jabber JID (Name) of chat room.</para>
+			</parameter>
+			<parameter name="Nickname" required="false">
+				<para>The nickname Asterisk uses in the chat room.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Allows Asterisk to leave a chat room.</para>
+		</description>
+	</application>
+	<application name="JabberStatus" language="en_US" module="res_jabber">
+		<synopsis>
+			Retrieve the status of a jabber list member
+		</synopsis>
+		<syntax>
+			<parameter name="Jabber" required="true">
+				<para>Client or transport Asterisk users to connect to Jabber.</para>
+			</parameter>
+			<parameter name="JID" required="true">
+				<para>XMPP/Jabber JID (Name) of recipient.</para>
+			</parameter>
+			<parameter name="Variable" required="true">
+				<para>Variable to store the status of requested user.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
+			<para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
+			The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
+			<enumlist>
+				<enum name="1">
+					<para>Online.</para>
+				</enum>
+				<enum name="2">
+					<para>Chatty.</para>
+				</enum>
+				<enum name="3">
+					<para>Away.</para>
+				</enum>
+				<enum name="4">
+					<para>Extended Away.</para>
+				</enum>
+				<enum name="5">
+					<para>Do Not Disturb.</para>
+				</enum>
+				<enum name="6">
+					<para>Offline.</para>
+				</enum>
+				<enum name="7">
+					<para>Not In Roster.</para>
+				</enum>
+			</enumlist>
+		</description>
+	</application>
+	<manager name="JabberSend" language="en_US" module="res_jabber">
+		<synopsis>
+			Sends a message to a Jabber Client.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Jabber" required="true">
+				<para>Client or transport Asterisk uses to connect to JABBER.</para>
+			</parameter>
+			<parameter name="JID" required="true">
+				<para>XMPP/Jabber JID (Name) of recipient.</para>
+			</parameter>
+			<parameter name="Message" required="true">
+				<para>Message to be sent to the buddy.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Sends a message to a Jabber Client.</para>
+		</description>
+	</manager>
+ ***/
+
+/*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we
+ * need to read both files */
+#define JABBER_CONFIG "jabber.conf"
+
+/*-- Forward declarations */
+static void aji_message_destroy(struct aji_message *obj);
+static int aji_is_secure(struct aji_client *client);
+#ifdef HAVE_OPENSSL
+static int aji_start_tls(struct aji_client *client);
+static int aji_tls_handshake(struct aji_client *client);
+#endif
+static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
+static int aji_recv(struct aji_client *client, int timeout);
+static int aji_send_header(struct aji_client *client, const char *to);
+static int aji_send_raw(struct aji_client *client, const char *xmlstr);
+static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
+static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
+static int aji_act_hook(void *data, int type, iks *node);
+static void aji_handle_iq(struct aji_client *client, iks *node);
+static void aji_handle_message(struct aji_client *client, ikspak *pak);
+static void aji_handle_presence(struct aji_client *client, ikspak *pak);
+static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
+static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message);
+static void *aji_recv_loop(void *data);
+static int aji_initialize(struct aji_client *client);
+static int aji_client_connect(void *data, ikspak *pak);
+static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
+static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc);
+static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static int aji_create_client(char *label, struct ast_variable *var, int debug);
+static int aji_create_buddy(char *label, struct aji_client *client);
+static int aji_reload(int reload);
+static int aji_load_config(int reload);
+static void aji_pruneregister(struct aji_client *client);
+static int aji_filter_roster(void *data, ikspak *pak);
+static int aji_get_roster(struct aji_client *client);
+static int aji_client_info_handler(void *data, ikspak *pak);
+static int aji_dinfo_handler(void *data, ikspak *pak);
+static int aji_ditems_handler(void *data, ikspak *pak);
+static int aji_register_query_handler(void *data, ikspak *pak);
+static int aji_register_approve_handler(void *data, ikspak *pak);
+static int aji_reconnect(struct aji_client *client);
+static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
+	ast_cli_args *a);
+static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
+		ast_cli_args *a);
+static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
+static int aji_receive_node_list(void *data, ikspak* pak);
+static void aji_init_event_distribution(struct aji_client *client);
+static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type,
+	const char *name, const char *collection_name);
+static iks* aji_build_node_config(iks *pubsub, const char *node_type,
+	const char *collection_name);
+static void aji_create_pubsub_collection(struct aji_client *client,
+	const char *collection_name);
+static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
+   const char *leaf_name);
+static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static void aji_create_affiliations(struct aji_client *client, const char *node);
+static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
+static void aji_publish_device_state(struct aji_client *client, const char * device,
+				     const char *device_state, unsigned int cachable);
+static int aji_handle_pubsub_error(void *data, ikspak *pak);
+static int aji_handle_pubsub_event(void *data, ikspak *pak);
+static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
+static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name);
+static iks* aji_build_node_request(struct aji_client *client, const char *collection);
+static int aji_delete_node_list(void *data, ikspak* pak);
+static void aji_pubsub_purge_nodes(struct aji_client *client,
+	const char* collection_name);
+static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
+	const char *context, const char *oldmsgs, const char *newmsgs);
+static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
+static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
+static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
+				       const char *event_type, unsigned int cachable);
+/* No transports in this version */
+/*
+static int aji_create_transport(char *label, struct aji_client *client);
+static int aji_register_transport(void *data, ikspak *pak);
+static int aji_register_transport2(void *data, ikspak *pak);
+*/
+
+static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from);
+
+static const struct ast_msg_tech msg_tech = {
+	.name = "xmpp",
+	.msg_send = msg_send_cb,
+};
+
+static struct ast_cli_entry aji_cli[] = {
+	AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
+	AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
+	AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
+	AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
+	AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."),
+	AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"),
+	AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"),
+	AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"),
+	AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
+};
+
+static char *app_ajisend = "JabberSend";
+static char *app_ajisendgroup = "JabberSendGroup";
+static char *app_ajistatus = "JabberStatus";
+static char *app_ajijoin = "JabberJoin";
+static char *app_ajileave = "JabberLeave";
+
+static struct aji_client_container clients;
+static struct aji_capabilities *capabilities = NULL;
+static struct ast_event_sub *mwi_sub = NULL;
+static struct ast_event_sub *device_state_sub = NULL;
+static ast_cond_t message_received_condition;
+static ast_mutex_t messagelock;
+
+/*! \brief Global flags, initialized to default values */
+static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT };
+
+/*! \brief PubSub flags, initialized to default values */
+static struct ast_flags pubsubflags = { 0 };
+/*!
+ * \internal
+ * \brief Deletes the aji_client data structure.
+ * \param obj aji_client The structure we will delete.
+ * \return void.
+ */
+void ast_aji_client_destroy(struct aji_client *obj)
+{
+	struct aji_message *tmp;
+	ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
+	iks_filter_delete(obj->f);
+	iks_parser_delete(obj->p);
+	iks_stack_delete(obj->stack);
+	AST_LIST_LOCK(&obj->messages);
+	while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
+		aji_message_destroy(tmp);
+	}
+	AST_LIST_HEAD_DESTROY(&obj->messages);
+	ast_free(obj);
+}
+
+/*!
+ * \internal
+ * \brief Deletes the aji_buddy data structure.
+ * \param obj aji_buddy The structure we will delete.
+ * \return void.
+ */
+void ast_aji_buddy_destroy(struct aji_buddy *obj)
+{
+	struct aji_resource *tmp;
+
+	while ((tmp = obj->resources)) {
+		obj->resources = obj->resources->next;
+		ast_free(tmp->description);
+		ast_free(tmp);
+	}
+
+	ast_free(obj);
+}
+
+/*!
+ * \internal
+ * \brief Deletes the aji_message data structure.
+ * \param obj aji_message The structure we will delete.
+ * \return void.
+ */
+static void aji_message_destroy(struct aji_message *obj)
+{
+	if (obj->from) {
+		ast_free(obj->from);
+	}
+	if (obj->message) {
+		ast_free(obj->message);
+	}
+	ast_free(obj);
+}
+
+/*!
+ * \internal
+ * \brief Find version in XML stream and populate our capabilities list
+ * \param node the node attribute in the caps element we'll look for or add to
+ * our list
+ * \param version the version attribute in the caps element we'll look for or
+ * add to our list
+ * \param pak struct The XML stanza we're processing
+ * \return a pointer to the added or found aji_version structure
+ */
+static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
+{
+	struct aji_capabilities *list = NULL;
+	struct aji_version *res = NULL;
+
+	list = capabilities;
+
+	if (!node) {
+		node = pak->from->full;
+	}
+	if (!version) {
+		version = "none supplied.";
+	}
+	while (list) {
+		if (!strcasecmp(list->node, node)) {
+			res = list->versions;
+			while(res) {
+				if (!strcasecmp(res->version, version)) {
+					return res;
+				}
+				res = res->next;
+			}
+			/* Specified version not found. Let's add it to
+			   this node in our capabilities list */
+			if (!res) {
+				res = ast_malloc(sizeof(*res));
+				if (!res) {
+					ast_log(LOG_ERROR, "Out of memory!\n");
+					return NULL;
+				}
+				res->jingle = 0;
+				res->parent = list;
+				ast_copy_string(res->version, version, sizeof(res->version));
+				res->next = list->versions;
+				list->versions = res;
+				return res;
+			}
+		}
+		list = list->next;
+	}
+	/* Specified node not found. Let's add it our capabilities list */
+	if (!list) {
+		list = ast_malloc(sizeof(*list));
+		if (!list) {
+			ast_log(LOG_ERROR, "Out of memory!\n");
+			return NULL;
+		}
+		res = ast_malloc(sizeof(*res));
+		if (!res) {
+			ast_log(LOG_ERROR, "Out of memory!\n");
+			ast_free(list);
+			return NULL;
+		}
+		ast_copy_string(list->node, node, sizeof(list->node));
+		ast_copy_string(res->version, version, sizeof(res->version));
+		res->jingle = 0;
+		res->parent = list;
+		res->next = NULL;
+		list->versions = res;
+		list->next = capabilities;
+		capabilities = list;
+	}
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Find the aji_resource we want
+ * \param buddy aji_buddy A buddy
+ * \param name
+ * \return aji_resource object
+*/
+static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
+{
+	struct aji_resource *res = NULL;
+	if (!buddy || !name) {
+		return res;
+	}
+	res = buddy->resources;
+	while (res) {
+		if (!strcasecmp(res->resource, name)) {
+			break;
+		}
+		res = res->next;
+	}
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Jabber GTalk function
+ * \param node iks
+ * \return 1 on success, 0 on failure.
+*/
+static int gtalk_yuck(iks *node)
+{
+	if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
+		ast_debug(1, "Found resource with Googletalk voice capabilities\n");
+		return 1;
+	} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
+		ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
+		return 1;
+	} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
+		ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Setup the authentication struct
+ * \param id iksid 
+ * \param pass password
+ * \param sid
+ * \return x iks
+*/
+static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
+{
+	iks *x, *y;
+	x = iks_new("iq");
+	iks_insert_attrib(x, "type", "set");
+	y = iks_insert(x, "query");
+	iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
+	iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
+	iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
+	if (sid) {
+		char buf[41];
+		char sidpass[100];
+		snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
+		ast_sha1_hash(buf, sidpass);
+		iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
+	} else {
+		iks_insert_cdata(iks_insert(y, "password"), pass, 0);
+	}
+	return x;
+}
+
+/*!
+ * \internal
+ * \brief Dial plan function status(). puts the status of watched user 
+ * into a channel variable.
+ * \param chan ast_channel
+ * \param data
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int aji_status_exec(struct ast_channel *chan, const char *data)
+{
+	struct aji_client *client = NULL;
+	struct aji_buddy *buddy = NULL;
+	struct aji_resource *r = NULL;
+	char *s = NULL;
+	int stat = 7;
+	char status[2];
+	static int deprecation_warning = 0;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(jid);
+		AST_APP_ARG(variable);
+	);
+	AST_DECLARE_APP_ARGS(jid,
+		AST_APP_ARG(screenname);
+		AST_APP_ARG(resource);
+	);
+
+	if (deprecation_warning++ % 10 == 0) {
+		ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
+	}
+
+	if (!data) {
+		ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
+		return 0;
+	}
+	s = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, s);
+
+	if (args.argc != 3) {
+		ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
+		return -1;
+	}
+
+	AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
+	if (jid.argc < 1 || jid.argc > 2) {
+		ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
+	if (!buddy) {
+		ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return -1;
+	}
+	r = aji_find_resource(buddy, jid.resource);
+	if (!r && buddy->resources) {
+		r = buddy->resources;
+	}
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	if (!r) {
+		ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
+	} else {
+		stat = r->status;
+	}
+	snprintf(status, sizeof(status), "%d", stat);
+	pbx_builtin_setvar_helper(chan, args.variable, status);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Dial plan funtcion to retrieve the status of a buddy.
+ * \param channel The associated ast_channel, if there is one
+ * \param data The account, buddy JID, and optional timeout
+ * timeout.
+ * \retval 0 success
+ * \retval -1 failure
+ */
+static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
+{
+	struct aji_client *client = NULL;
+	struct aji_buddy *buddy = NULL;
+	struct aji_resource *r = NULL;
+	int stat = 7;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(jid);
+	);
+	AST_DECLARE_APP_ARGS(jid,
+		AST_APP_ARG(screenname);
+		AST_APP_ARG(resource);
+	);
+
+	if (!data) {
+		ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
+		return 0;
+	}
+	AST_STANDARD_APP_ARGS(args, data);
+
+	if (args.argc != 2) {
+		ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
+		return -1;
+	}
+
+	AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
+	if (jid.argc < 1 || jid.argc > 2) {
+		ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
+	if (!buddy) {
+		ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return -1;
+	}
+	r = aji_find_resource(buddy, jid.resource);
+	if (!r && buddy->resources) {
+		r = buddy->resources;
+	}
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	if (!r) {
+		ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
+	} else {
+		stat = r->status;
+	}
+	snprintf(buf, buflen, "%d", stat);
+	return 0;
+}
+
+static struct ast_custom_function jabberstatus_function = {
+	.name = "JABBER_STATUS",
+	.read = acf_jabberstatus_read,
+};
+
+/*!
+ * \internal
+ * \brief Dial plan function to receive a message.
+ * \param channel The associated ast_channel, if there is one
+ * \param data The account, JID, and optional timeout
+ * timeout.
+ * \retval 0 success
+ * \retval -1 failure
+ */
+static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
+{
+	char *parse = NULL;
+	int timeout;
+	int jidlen, resourcelen;
+	struct timeval start;
+	long diff = 0;
+	struct aji_client *client = NULL;
+	int found = 0;
+	struct aji_message *tmp = NULL;
+	AST_DECLARE_APP_ARGS(args,
+			AST_APP_ARG(account);
+			AST_APP_ARG(jid);
+			AST_APP_ARG(timeout);
+			);
+	AST_DECLARE_APP_ARGS(jid,
+			AST_APP_ARG(screenname);
+			AST_APP_ARG(resource);
+	);
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (args.argc < 2 || args.argc > 3) {
+		ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
+		return -1;
+	}
+
+	parse = ast_strdupa(args.jid);
+	AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
+	if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
+		ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
+		return -1;
+	}
+
+	if (ast_strlen_zero(args.timeout)) {
+		timeout = 20;
+	} else {
+		sscanf(args.timeout, "%d", &timeout);
+		if (timeout <= 0) {
+			ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
+			return -1;
+		}
+	}
+
+	jidlen = strlen(jid.screenname);
+	resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
+
+	client = ast_aji_get_client(args.account);
+	if (!client) {
+		ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
+		return -1;
+	}
+
+	ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
+
+	start = ast_tvnow();
+
+	if (chan && ast_autoservice_start(chan) < 0) {
+		ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return -1;
+	}
+
+	/* search the messages list, grab the first message that matches with
+	 * the from JID we're expecting, and remove it from the messages list */
+	while (diff < timeout) {
+		struct timespec ts = { 0, };
+		struct timeval wait;
+		int res;
+
+		wait = ast_tvadd(start, ast_tv(timeout, 0));
+		ts.tv_sec = wait.tv_sec;
+		ts.tv_nsec = wait.tv_usec * 1000;
+
+		/* wait up to timeout seconds for an incoming message */
+		ast_mutex_lock(&messagelock);
+		res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
+		ast_mutex_unlock(&messagelock);
+		if (res == ETIMEDOUT) {
+			ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
+			break;
+		}
+
+		AST_LIST_LOCK(&client->messages);
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
+			if (jid.argc == 1) {
+				/* no resource provided, compare bare JIDs */
+				if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
+					continue;
+				}
+			} else {
+				/* resource appended, compare bare JIDs and resources */
+				char *resource = strchr(tmp->from, '/');
+				if (!resource || strlen(resource) == 0) {
+					ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
+					if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
+						continue;
+					}
+				} else {
+					resource ++;
+					if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
+						continue;
+					}
+				}
+			}
+			/* check if the message is not too old */
+			if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
+				ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
+				AST_LIST_REMOVE_CURRENT(list);
+				aji_message_destroy(tmp);
+				continue;
+			}
+			found = 1;
+			ast_copy_string(buf, tmp->message, buflen);
+			AST_LIST_REMOVE_CURRENT(list);
+			aji_message_destroy(tmp);
+			break;
+		}
+		AST_LIST_TRAVERSE_SAFE_END;
+		AST_LIST_UNLOCK(&client->messages);
+		if (found) {
+			break;
+		}
+
+		/* check timeout */
+		diff = ast_tvdiff_ms(ast_tvnow(), start);
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	if (chan && ast_autoservice_stop(chan) < 0) {
+		ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
+	}
+
+	/* return if we timed out */
+	if (!found) {
+		ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct ast_custom_function jabberreceive_function = {
+	.name = "JABBER_RECEIVE",
+	.read = acf_jabberreceive_read,
+};
+
+/*!
+ * \internal
+ * \brief Delete old messages from a given JID
+ * Messages stored during more than client->message_timeout are deleted
+ * \param client Asterisk's XMPP client
+ * \param from the JID we received messages from
+ * \retval the number of deleted messages
+ * \retval -1 failure
+ */
+static int delete_old_messages(struct aji_client *client, char *from)
+{
+	int deleted = 0;
+	int isold = 0;
+	struct aji_message *tmp = NULL;
+	if (!client) {
+		ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
+		return -1;
+	}
+
+	/* remove old messages */
+	AST_LIST_LOCK(&client->messages);
+	if (AST_LIST_EMPTY(&client->messages)) {
+		AST_LIST_UNLOCK(&client->messages);
+		return 0;
+	}
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
+		if (isold) {
+			if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
+				AST_LIST_REMOVE_CURRENT(list);
+				aji_message_destroy(tmp);
+				deleted ++;
+			}
+		} else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
+			isold = 1;
+			if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
+				AST_LIST_REMOVE_CURRENT(list);
+				aji_message_destroy(tmp);
+				deleted ++;
+			}
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&client->messages);
+
+	return deleted;
+}
+
+/*!
+ * \internal
+ * \brief Delete old messages
+ * Messages stored during more than client->message_timeout are deleted
+ * \param client Asterisk's XMPP client
+ * \retval the number of deleted messages
+ * \retval -1 failure
+ */
+static int delete_old_messages_all(struct aji_client *client)
+{
+	return delete_old_messages(client, NULL);
+}
+
+/*!
+* \brief Application to join a chat room
+* \param chan ast_channel
+* \param data  Data is sender|jid|nickname.
+* \retval 0 success
+* \retval -1 error
+*/
+static int aji_join_exec(struct ast_channel *chan, const char *data)
+{
+	struct aji_client *client = NULL;
+	char *s;
+	char nick[AJI_MAX_RESJIDLEN];
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(jid);
+		AST_APP_ARG(nick);
+	);
+
+	if (!data) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
+		return -1;
+	}
+	s = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, s);
+	if (args.argc < 2 || args.argc > 3) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
+		return -1;
+	}
+
+	if (strchr(args.jid, '/')) {
+		ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+
+	if (!ast_strlen_zero(args.nick)) {
+		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
+	} else {
+		if (client->component) {
+			sprintf(nick, "asterisk");
+		} else {
+			snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
+		}
+	}
+
+	if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
+		ast_aji_join_chat(client, args.jid, nick);
+	} else {
+		ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return 0;
+}
+
+/*!
+* \brief Application to leave a chat room
+* \param chan ast_channel
+* \param data  Data is sender|jid|nickname.
+* \retval 0 success
+* \retval -1 error
+*/
+static int aji_leave_exec(struct ast_channel *chan, const char *data)
+{
+	struct aji_client *client = NULL;
+	char *s;
+	char nick[AJI_MAX_RESJIDLEN];
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(jid);
+		AST_APP_ARG(nick);
+	);
+
+	if (!data) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
+		return -1;
+	}
+	s = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, s);
+	if (args.argc < 2 || args.argc > 3) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
+		return -1;
+	}
+
+	if (strchr(args.jid, '/')) {
+		ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+
+	if (!ast_strlen_zero(args.nick)) {
+		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
+	} else {
+		if (client->component) {
+			sprintf(nick, "asterisk");
+		} else {
+			snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
+		}
+	}
+
+	if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
+		ast_aji_leave_chat(client, args.jid, nick);
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Dial plan function to send a message.
+ * \param chan ast_channel
+ * \param data  Data is account,jid,message.
+ * \retval 0 success
+ * \retval -1 failure
+ */
+static int aji_send_exec(struct ast_channel *chan, const char *data)
+{
+	struct aji_client *client = NULL;
+	char *s;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(recipient);
+		AST_APP_ARG(message);
+	);
+
+	if (!data) {
+		ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
+		return -1;
+	}
+	s = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, s);
+	if (args.argc < 3) {
+		ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+	if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
+		ast_aji_send_chat(client, args.recipient, args.message);
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return 0;
+}
+
+static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from)
+{
+	struct aji_client *client;
+	char *sender;
+	char *dest;
+	int res;
+
+	sender = ast_strdupa(from);
+	strsep(&sender, ":");
+	dest = ast_strdupa(to);
+	strsep(&dest, ":");
+
+	if (ast_strlen_zero(sender)) {
+		ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for xmpp\n", from);
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(sender))) {
+		ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
+		return -1;
+	}
+
+	ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name);
+
+	res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg));
+	if (res != IKS_OK) {
+		ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res);
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return res == IKS_OK ? 0 : -1;
+}
+
+/*!
+* \brief Application to send a message to a groupchat.
+* \param chan ast_channel
+* \param data  Data is sender|groupchat|message.
+* \retval 0 success
+* \retval -1 error
+*/
+static int aji_sendgroup_exec(struct ast_channel *chan, const char *data)
+{
+	struct aji_client *client = NULL;
+	char *s;
+	char nick[AJI_MAX_RESJIDLEN];
+	int res = 0;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(sender);
+		AST_APP_ARG(groupchat);
+		AST_APP_ARG(message);
+		AST_APP_ARG(nick);
+	);
+
+	if (!data) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
+		return -1;
+	}
+	s = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, s);
+	if (args.argc < 3 || args.argc > 4) {
+		ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
+		return -1;
+	}
+
+	if (!(client = ast_aji_get_client(args.sender))) {
+		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
+		return -1;
+	}
+
+	if (ast_strlen_zero(args.nick) || args.argc == 3) {
+		if (client->component) {
+			sprintf(nick, "asterisk");
+		} else {
+			snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
+		}
+	} else {
+		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
+	}
+
+	if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
+		res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	if (res != IKS_OK) {
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Tests whether the connection is secured or not
+ * \return 0 if the connection is not secured
+ */
+static int aji_is_secure(struct aji_client *client)
+{
+#ifdef HAVE_OPENSSL
+	return client->stream_flags & SECURE;
+#else
+	return 0;
+#endif
+}
+
+#ifdef HAVE_OPENSSL
+/*!
+ * \internal
+ * \brief Starts the TLS procedure
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL
+ * if OpenSSL is not installed
+ */
+static int aji_start_tls(struct aji_client *client)
+{
+	int ret;
+
+	/* This is sent not encrypted */
+	if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
+		return ret;
+	}
+
+	client->stream_flags |= TRY_SECURE;
+	return IKS_OK;
+}
+
+/*!
+ * \internal
+ * \brief TLS handshake, OpenSSL initialization
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return IKS_OK on success, IKS_NET_TLSFAIL on failure
+ */
+static int aji_tls_handshake(struct aji_client *client)
+{
+	int sock;
+	long ssl_opts;
+
+	ast_debug(1, "Starting TLS handshake\n");
+
+	/* Choose an SSL/TLS protocol version, create SSL_CTX */
+	client->ssl_method = SSLv23_method();
+	if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
+		return IKS_NET_TLSFAIL;
+	}
+	ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+	SSL_CTX_set_options(client->ssl_context, ssl_opts);
+
+	/* Create new SSL session */
+	if (!(client->ssl_session = SSL_new(client->ssl_context))) {
+		return IKS_NET_TLSFAIL;
+	}
+
+	/* Enforce TLS on our XMPP connection */
+	sock = iks_fd(client->p);
+	if (!SSL_set_fd(client->ssl_session, sock)) {
+		return IKS_NET_TLSFAIL;
+	}
+
+	/* Perform SSL handshake */
+	if (!SSL_connect(client->ssl_session)) {
+		return IKS_NET_TLSFAIL;
+	}
+
+	client->stream_flags &= (~TRY_SECURE);
+	client->stream_flags |= SECURE;
+
+	/* Sent over the established TLS connection */
+	if (aji_send_header(client, client->jid->server) != IKS_OK) {
+		return IKS_NET_TLSFAIL;
+	}
+
+	ast_debug(1, "TLS started with server\n");
+
+	return IKS_OK;
+}
+#endif /* HAVE_OPENSSL */
+
+/*!
+ * \internal
+ * \brief Secured or unsecured IO socket receiving function
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param buffer the reception buffer
+ * \param buf_len the size of the buffer
+ * \param timeout the select timer
+ * \retval the number of read bytes
+ * \retval 0 timeout expiration
+ * \retval -1 error
+ */
+static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
+{
+	struct pollfd pfd = { .events = POLLIN };
+	int len, res;
+
+#ifdef HAVE_OPENSSL
+	if (aji_is_secure(client)) {
+		pfd.fd = SSL_get_fd(client->ssl_session);
+		if (pfd.fd < 0) {
+			return -1;
+		}
+	} else
+#endif /* HAVE_OPENSSL */
+		pfd.fd = iks_fd(client->p);
+
+	res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
+	if (res > 0) {
+#ifdef HAVE_OPENSSL
+		if (aji_is_secure(client)) {
+			len = SSL_read(client->ssl_session, buffer, buf_len);
+		} else
+#endif /* HAVE_OPENSSL */
+			len = recv(pfd.fd, buffer, buf_len, 0);
+
+		if (len > 0) {
+			return len;
+		} else if (len <= 0) {
+			return -1;
+		}
+	}
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Tries to receive data from the Jabber server
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param timeout the timeout value
+ * This function receives (encrypted or unencrypted) data from the XMPP server,
+ * and passes it to the parser.
+ * \retval IKS_OK success
+ * \retval IKS_NET_RWERR IO error
+ * \retval IKS_NET_NOCONN no connection available
+ * \retval IKS_NET_EXPIRED timeout expiration
+ */
+static int aji_recv (struct aji_client *client, int timeout)
+{
+	int len, ret;
+	char buf[NET_IO_BUF_SIZE - 1];
+	char newbuf[NET_IO_BUF_SIZE - 1];
+	int pos = 0;
+	int newbufpos = 0;
+	unsigned char c;
+
+	memset(buf, 0, sizeof(buf));
+	memset(newbuf, 0, sizeof(newbuf));
+
+	while (1) {
+		len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
+		if (len < 0) return IKS_NET_RWERR;
+		if (len == 0) return IKS_NET_EXPIRED;
+		buf[len] = '\0';
+
+		/* our iksemel parser won't work as expected if we feed
+		   it with XML packets that contain multiple whitespace
+		   characters between tags */
+		while (pos < len) {
+			c = buf[pos];
+			/* if we stumble on the ending tag character,
+			   we skip any whitespace that follows it*/
+			if (c == '>') {
+				while (isspace(buf[pos+1])) {
+					pos++;
+				}
+			}
+			newbuf[newbufpos] = c;
+			newbufpos ++;
+			pos++;
+		}
+		pos = 0;
+		newbufpos = 0;
+
+		/* Log the message here, because iksemel's logHook is
+		   unaccessible */
+		aji_log_hook(client, buf, len, 1);
+
+		/* let iksemel deal with the string length,
+		   and reset our buffer */
+		ret = iks_parse(client->p, newbuf, 0, 0);
+		memset(newbuf, 0, sizeof(newbuf));
+
+		switch (ret) {
+		case IKS_NOMEM:
+			ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
+			break;
+		case IKS_BADXML:
+			ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
+			break;
+		case IKS_HOOK:
+			ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
+			break;
+		}
+		if (ret != IKS_OK) {
+			return ret;
+		}
+		ast_debug(3, "XML parsing successful\n");
+	}
+	return IKS_OK;
+}
+
+/*!
+ * \internal
+ * \brief Sends XMPP header to the server
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param to the target XMPP server
+ * \return IKS_OK on success, any other value on failure
+ */
+static int aji_send_header(struct aji_client *client, const char *to)
+{
+	char *msg;
+	int len, err;
+
+	len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
+	msg = iks_malloc(len);
+	if (!msg)
+		return IKS_NOMEM;
+	sprintf(msg, "<?xml version='1.0'?>"
+		"<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
+		"%s' to='%s' version='1.0'>", client->name_space, to);
+	err = aji_send_raw(client, msg);
+	iks_free(msg);
+	if (err != IKS_OK)
+		return err;
+
+	return IKS_OK;
+}
+
+/*!
+ * \brief Wraps raw sending
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param x the XMPP packet to send
+ * \return IKS_OK on success, any other value on failure
+ */
+int ast_aji_send(struct aji_client *client, iks *x)
+{
+	return aji_send_raw(client, iks_string(iks_stack(x), x));
+}
+
+/*!
+ * \internal
+ * \brief Sends an XML string over an XMPP connection
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param xmlstr the XML string to send
+ * The XML data is sent whether the connection is secured or not. In the
+ * latter case, we just call iks_send_raw().
+ * \return IKS_OK on success, any other value on failure
+ */
+static int aji_send_raw(struct aji_client *client, const char *xmlstr)
+{
+	int ret;
+#ifdef HAVE_OPENSSL
+	int len = strlen(xmlstr);
+
+	if (aji_is_secure(client)) {
+		ret = SSL_write(client->ssl_session, xmlstr, len);
+		if (ret) {
+			/* Log the message here, because iksemel's logHook is
+			   unaccessible */
+			aji_log_hook(client, xmlstr, len, 0);
+			return IKS_OK;
+		}
+	}
+#endif
+	/* If needed, data will be sent unencrypted, and logHook will
+	   be called inside iks_send_raw */
+	ret = iks_send_raw(client->p, xmlstr);
+	if (ret != IKS_OK) {
+		return ret;
+	}
+
+	return IKS_OK;
+}
+
+/*!
+ * \internal
+ * \brief the debug loop.
+ * \param data void
+ * \param xmpp xml data as string
+ * \param size size of string
+ * \param is_incoming direction of packet 1 for inbound 0 for outbound.
+ */
+static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+
+	if (!ast_strlen_zero(xmpp)) {
+		manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
+	}
+
+	if (client->debug) {
+		if (is_incoming) {
+			ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
+		} else {
+			if (strlen(xmpp) == 1) {
+				if (option_debug > 2  && xmpp[0] == ' ') {
+					ast_verbose("\nJABBER: Keep alive packet\n");
+				}
+			} else {
+				ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
+			}
+		}
+
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+}
+
+/*!
+ * \internal
+ * \brief A wrapper function for iks_start_sasl
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param type the SASL authentication type. Supported types are PLAIN and MD5
+ * \param username
+ * \param pass password.
+ *
+ * \return IKS_OK on success, IKSNET_NOTSUPP on failure.
+ */
+static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
+{
+	iks *x = NULL;
+	int len;
+	char *s;
+	char *base64;
+
+	/* trigger SASL DIGEST-MD5 only over an unsecured connection.
+	   iks_start_sasl is an iksemel API function and relies on GnuTLS,
+	   whereas we use OpenSSL */
+	if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
+		return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
+	if (!(type & IKS_STREAM_SASL_PLAIN)) {
+		ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
+		return IKS_NET_NOTSUPP;
+	}
+
+	x = iks_new("auth"); 
+	if (!x) {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+		return IKS_NET_NOTSUPP;
+	}
+
+	iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
+	len = strlen(username) + strlen(pass) + 3;
+	s = ast_alloca(len);
+	base64 = ast_alloca((len + 2) * 4 / 3);
+	iks_insert_attrib(x, "mechanism", "PLAIN");
+	snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
+
+	/* exclude the NULL training byte from the base64 encoding operation
+	   as some XMPP servers will refuse it.
+	   The format for authentication is [authzid]\0authcid\0password
+	   not [authzid]\0authcid\0password\0 */
+	ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
+	iks_insert_cdata(x, base64, 0);
+	ast_aji_send(client, x);
+	iks_delete(x);
+
+	return IKS_OK;
+}
+
+/*!
+ * \internal
+ * \brief The action hook parses the inbound packets, constantly running.
+ * \param data aji client structure 
+ * \param type type of packet 
+ * \param node the actual packet.
+ * \return IKS_OK or IKS_HOOK .
+ */
+static int aji_act_hook(void *data, int type, iks *node)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	ikspak *pak = NULL;
+	iks *auth = NULL;
+	int features = 0;
+
+	if (!node) {
+		ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_HOOK;
+	}
+
+	if (client->state == AJI_DISCONNECTING) {
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_HOOK;
+	}
+
+	pak = iks_packet(node);
+
+	/* work around iksemel's impossibility to recognize node names
+	 * containing a semicolon. Set the namespace of the corresponding
+	 * node accordingly. */
+	if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
+		char *node_ns = NULL;
+		char attr[AJI_MAX_ATTRLEN];
+		char *node_name = iks_name(iks_child(node));
+		char *aux = strchr(node_name, ':') + 1;
+		snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
+		node_ns = iks_find_attrib(iks_child(node), attr);
+		if (node_ns) {
+			pak->ns = node_ns;
+			pak->query = iks_child(node);
+		}
+	}
+
+
+	if (!client->component) { /*client */
+		switch (type) {
+		case IKS_NODE_START:
+			if (client->usetls && !aji_is_secure(client)) {
+#ifndef HAVE_OPENSSL
+				ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n");
+				ASTOBJ_UNREF(client, ast_aji_client_destroy);
+				return IKS_HOOK;
+#else
+				if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
+					ast_log(LOG_ERROR, "Could not start TLS\n");
+					ASTOBJ_UNREF(client, ast_aji_client_destroy);
+					return IKS_HOOK;
+				}
+				break;
+#endif
+			}
+			if (!client->usesasl) {
+				iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
+				auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
+				if (auth) {
+					iks_insert_attrib(auth, "id", client->mid);
+					iks_insert_attrib(auth, "to", client->jid->server);
+					ast_aji_increment_mid(client->mid);
+					ast_aji_send(client, auth);
+					iks_delete(auth);
+				} else {
+					ast_log(LOG_ERROR, "Out of memory.\n");
+				}
+			}
+			break;
+
+		case IKS_NODE_NORMAL:
+#ifdef HAVE_OPENSSL
+			if (client->stream_flags & TRY_SECURE) {
+				if (!strcmp("proceed", iks_name(node))) {
+					return aji_tls_handshake(client);
+				}
+			}
+#endif
+			if (!strcmp("stream:features", iks_name(node))) {
+				features = iks_stream_features(node);
+				if (client->usesasl) {
+					if (client->usetls && !aji_is_secure(client)) {
+						break;
+					}
+					if (client->authorized) {
+						if (features & IKS_STREAM_BIND) {
+							iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
+							auth = iks_make_resource_bind(client->jid);
+							if (auth) {
+								iks_insert_attrib(auth, "id", client->mid);
+								ast_aji_increment_mid(client->mid);
+								ast_aji_send(client, auth);
+								iks_delete(auth);
+							} else {
+								ast_log(LOG_ERROR, "Out of memory.\n");
+								break;
+							}
+						}
+						if (features & IKS_STREAM_SESSION) {
+							iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
+							auth = iks_make_session();
+							if (auth) {
+								iks_insert_attrib(auth, "id", "auth");
+								ast_aji_increment_mid(client->mid);
+								ast_aji_send(client, auth);
+								iks_delete(auth);
+							} else {
+								ast_log(LOG_ERROR, "Out of memory.\n");
+							}
+						}
+					} else {
+						int ret;
+						if (!client->jid->user) {
+							ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
+							break;
+						}
+
+						ret = aji_start_sasl(client, features, client->jid->user, client->password);
+						if (ret != IKS_OK) {
+							ASTOBJ_UNREF(client, ast_aji_client_destroy);
+							return IKS_HOOK;
+						}
+						break;
+					}
+				}
+			} else if (!strcmp("failure", iks_name(node))) {
+				ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
+			} else if (!strcmp("success", iks_name(node))) {
+				client->authorized = 1;
+				aji_send_header(client, client->jid->server);
+			}
+			break;
+		case IKS_NODE_ERROR:
+			ast_log(LOG_ERROR, "JABBER: Node Error\n");
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_HOOK;
+			break;
+		case IKS_NODE_STOP:
+			ast_log(LOG_WARNING, "JABBER: Disconnected\n");
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_HOOK;
+			break;
+		}
+	} else if (client->state != AJI_CONNECTED && client->component) {
+		switch (type) {
+		case IKS_NODE_START:
+			if (client->state == AJI_DISCONNECTED) {
+				char secret[160], shasum[320], *handshake;
+
+				sprintf(secret, "%s%s", pak->id, client->password);
+				ast_sha1_hash(shasum, secret);
+				if (ast_asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
+					aji_send_raw(client, handshake);
+					ast_free(handshake);
+				}
+				client->state = AJI_CONNECTING;
+				if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
+					client->state = AJI_CONNECTED;
+				else
+					ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
+				break;
+			}
+			break;
+
+		case IKS_NODE_NORMAL:
+			break;
+
+		case IKS_NODE_ERROR:
+			ast_log(LOG_ERROR, "JABBER: Node Error\n");
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_HOOK;
+
+		case IKS_NODE_STOP:
+			ast_log(LOG_WARNING, "JABBER: Disconnected\n");
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_HOOK;
+		}
+	}
+
+	switch (pak->type) {
+	case IKS_PAK_NONE:
+		ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
+		break;
+	case IKS_PAK_MESSAGE:
+		aji_handle_message(client, pak);
+		ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
+		break;
+	case IKS_PAK_PRESENCE:
+		aji_handle_presence(client, pak);
+		ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
+		break;
+	case IKS_PAK_S10N:
+		aji_handle_subscribe(client, pak);
+		ast_debug(1, "JABBER: Handling paktype S10N\n");
+		break;
+	case IKS_PAK_IQ:
+		ast_debug(1, "JABBER: Handling paktype IQ\n");
+		aji_handle_iq(client, node);
+		break;
+	default:
+		ast_debug(1, "JABBER: I don't know anything about paktype '%u'\n", pak->type);
+		break;
+	}
+
+	iks_filter_packet(client->f, pak);
+
+	if (node)
+		iks_delete(node);
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_OK;
+}
+/*!
+ * \internal
+ * \brief Unknown
+ * \param data void
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT.
+*/
+static int aji_register_approve_handler(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	iks *iq = NULL, *presence = NULL, *x = NULL;
+
+	iq = iks_new("iq");
+	presence = iks_new("presence");
+	x = iks_new("x");
+	if (client && iq && presence && x) {
+		if (!iks_find(pak->query, "remove")) {
+			iks_insert_attrib(iq, "from", client->jid->full);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			ast_aji_send(client, iq);
+
+			iks_insert_attrib(presence, "from", client->jid->full);
+			iks_insert_attrib(presence, "to", pak->from->partial);
+			iks_insert_attrib(presence, "id", client->mid);
+			ast_aji_increment_mid(client->mid);
+			iks_insert_attrib(presence, "type", "subscribe");
+			iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
+			iks_insert_node(presence, x);
+			ast_aji_send(client, presence);
+		}
+	} else {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	}
+
+	iks_delete(iq);
+	iks_delete(presence);
+	iks_delete(x);
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+/*!
+ * \internal
+ * \brief register handler for incoming querys (IQ's)
+ * \param data incoming aji_client request
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT.
+*/
+static int aji_register_query_handler(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	struct aji_buddy *buddy = NULL;
+	iks *iq = NULL, *query = NULL;
+
+	client = (struct aji_client *) data;
+
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+	if (!buddy) {
+		iks  *error = NULL, *notacceptable = NULL;
+
+		ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
+		iq = iks_new("iq");
+		query = iks_new("query");
+		error = iks_new("error");
+		notacceptable = iks_new("not-acceptable");
+		if (iq && query && error && notacceptable) {
+			iks_insert_attrib(iq, "type", "error");
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(query, "xmlns", "jabber:iq:register");
+			iks_insert_attrib(error, "code" , "406");
+			iks_insert_attrib(error, "type", "modify");
+			iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
+			iks_insert_node(iq, query);
+			iks_insert_node(iq, error);
+			iks_insert_node(error, notacceptable);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(error);
+		iks_delete(notacceptable);
+	} else if (!iks_find_attrib(pak->query, "node")) {
+		iks *instructions = NULL;
+		char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
+		iq = iks_new("iq");
+		query = iks_new("query");
+		instructions = iks_new("instructions");
+		if (iq && query && instructions && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "jabber:iq:register");
+			iks_insert_cdata(instructions, explain, 0);
+			iks_insert_node(iq, query);
+			iks_insert_node(query, instructions);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(instructions);
+	}
+	iks_delete(iq);
+	iks_delete(query);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \internal
+ * \brief Handles stuff
+ * \param data void
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT.
+*/
+static int aji_ditems_handler(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	char *node = NULL;
+
+	if (!(node = iks_find_attrib(pak->query, "node"))) {
+		iks *iq = NULL, *query = NULL, *item = NULL;
+		iq = iks_new("iq");
+		query = iks_new("query");
+		item = iks_new("item");
+
+		if (iq && query && item) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
+			iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
+			iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
+			iks_insert_attrib(item, "jid", client->user);
+
+			iks_insert_node(iq, query);
+			iks_insert_node(query, item);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(item);
+
+	} else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
+		iks *iq, *query, *confirm;
+		iq = iks_new("iq");
+		query = iks_new("query");
+		confirm = iks_new("item");
+		if (iq && query && confirm && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
+			iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
+			iks_insert_attrib(confirm, "node", "confirmaccount");
+			iks_insert_attrib(confirm, "name", "Confirm AIM account");
+			iks_insert_attrib(confirm, "jid", "blog.astjab.org");
+
+			iks_insert_node(iq, query);
+			iks_insert_node(query, confirm);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(confirm);
+
+	} else if (!strcasecmp(node, "confirmaccount")) {
+		iks *iq = NULL, *query = NULL, *feature = NULL;
+
+		iq = iks_new("iq");
+		query = iks_new("query");
+		feature = iks_new("feature");
+
+		if (iq && query && feature && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
+			iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
+			iks_insert_node(iq, query);
+			iks_insert_node(query, feature);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(feature);
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+
+}
+
+/*!
+ * \internal
+ * \brief Handle add extra info
+ * \param data void
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT
+*/
+static int aji_client_info_handler(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	struct aji_resource *resource = NULL;
+	struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+
+	if (!buddy) {
+		ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_FILTER_EAT;
+	}
+
+	resource = aji_find_resource(buddy, pak->from->resource);
+	if (pak->subtype == IKS_TYPE_RESULT) {
+		if (!resource) {
+			ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_FILTER_EAT;
+		}
+		if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
+			resource->cap->jingle = 1;
+		} else {
+			resource->cap->jingle = 0;
+		}
+	} else if (pak->subtype == IKS_TYPE_GET) {
+		iks *iq, *disco, *ident, *google, *query;
+		iq = iks_new("iq");
+		query = iks_new("query");
+		ident = iks_new("identity");
+		disco = iks_new("feature");
+		google = iks_new("feature");
+		if (iq && ident && disco && google) {
+			iks_insert_attrib(iq, "from", client->jid->full);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
+			iks_insert_attrib(ident, "category", "client");
+			iks_insert_attrib(ident, "type", "pc");
+			iks_insert_attrib(ident, "name", "asterisk");
+			iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
+			iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
+			iks_insert_node(iq, query);
+			iks_insert_node(query, ident);
+			iks_insert_node(query, google);
+			iks_insert_node(query, disco);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of Memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(ident);
+		iks_delete(google);
+		iks_delete(disco);
+	} else if (pak->subtype == IKS_TYPE_ERROR) {
+		ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
+	}
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \internal
+ * \brief Handler of the return info packet
+ * \param data aji_client
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT
+*/
+static int aji_dinfo_handler(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	char *node = NULL;
+	struct aji_resource *resource = NULL;
+	struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+
+	if (!buddy) {
+		ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_FILTER_EAT;
+	}
+
+	if (pak->subtype == IKS_TYPE_ERROR) {
+		ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_FILTER_EAT;
+	}
+	resource = aji_find_resource(buddy, pak->from->resource);
+	if (pak->subtype == IKS_TYPE_RESULT) {
+		if (!resource) {
+			ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
+			return IKS_FILTER_EAT;
+		}
+		if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
+			resource->cap->jingle = 1;
+		} else {
+			resource->cap->jingle = 0;
+		}
+	} else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
+		iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
+
+		iq = iks_new("iq");
+		query = iks_new("query");
+		identity = iks_new("identity");
+		disco = iks_new("feature");
+		reg = iks_new("feature");
+		commands = iks_new("feature");
+		gateway = iks_new("feature");
+		version = iks_new("feature");
+		vcard = iks_new("feature");
+		search = iks_new("feature");
+		if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
+			iks_insert_attrib(identity, "category", "gateway");
+			iks_insert_attrib(identity, "type", "pstn");
+			iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
+			iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
+			iks_insert_attrib(reg, "var", "jabber:iq:register");
+			iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
+			iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
+			iks_insert_attrib(version, "var", "jabber:iq:version");
+			iks_insert_attrib(vcard, "var", "vcard-temp");
+			iks_insert_attrib(search, "var", "jabber:iq:search");
+
+			iks_insert_node(iq, query);
+			iks_insert_node(query, identity);
+			iks_insert_node(query, disco);
+			iks_insert_node(query, reg);
+			iks_insert_node(query, commands);
+			iks_insert_node(query, gateway);
+			iks_insert_node(query, version);
+			iks_insert_node(query, vcard);
+			iks_insert_node(query, search);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(identity);
+		iks_delete(disco);
+		iks_delete(reg);
+		iks_delete(commands);
+		iks_delete(gateway);
+		iks_delete(version);
+		iks_delete(vcard);
+		iks_delete(search);
+	} else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
+		iks *iq, *query, *confirm;
+		iq = iks_new("iq");
+		query = iks_new("query");
+		confirm = iks_new("item");
+
+		if (iq && query && confirm && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
+			iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
+			iks_insert_attrib(confirm, "node", "confirmaccount");
+			iks_insert_attrib(confirm, "name", "Confirm AIM account");
+			iks_insert_attrib(confirm, "jid", client->user);
+			iks_insert_node(iq, query);
+			iks_insert_node(query, confirm);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(confirm);
+
+	} else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
+		iks *iq, *query, *feature;
+
+		iq = iks_new("iq");
+		query = iks_new("query");
+		feature = iks_new("feature");
+
+		if (iq && query && feature && client) {
+			iks_insert_attrib(iq, "from", client->user);
+			iks_insert_attrib(iq, "to", pak->from->full);
+			iks_insert_attrib(iq, "id", pak->id);
+			iks_insert_attrib(iq, "type", "result");
+			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
+			iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
+			iks_insert_node(iq, query);
+			iks_insert_node(query, feature);
+			ast_aji_send(client, iq);
+		} else {
+			ast_log(LOG_ERROR, "Out of memory.\n");
+		}
+
+		iks_delete(iq);
+		iks_delete(query);
+		iks_delete(feature);
+	}
+
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \internal
+ * \brief Handles \verbatim <iq> \endverbatim stanzas.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node iks
+ * \return void.
+ */
+static void aji_handle_iq(struct aji_client *client, iks *node)
+{
+	/*Nothing to see here */
+}
+
+/*!
+ * \internal
+ * \brief Handles \verbatim <message>\endverbatim stanzas.
+ * Adds the incoming message to the client's message list.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param pak ikspak the node
+ */
+static void aji_handle_message(struct aji_client *client, ikspak *pak)
+{
+	struct aji_message *insert;
+	int deleted = 0;
+	struct ast_msg *msg;
+
+	ast_debug(3, "client %s received a message\n", client->name);
+
+	if (!(insert = ast_calloc(1, sizeof(*insert)))) {
+		return;
+	}
+
+	insert->arrived = ast_tvnow();
+
+	/* wake up threads waiting for messages */
+	ast_mutex_lock(&messagelock);
+	ast_cond_broadcast(&message_received_condition);
+	ast_mutex_unlock(&messagelock);
+
+	if (iks_find_cdata(pak->x, "body")) {
+		insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
+	}
+	if (pak->id) {
+		ast_copy_string(insert->id, pak->id, sizeof(insert->id));
+	}
+	if (pak->from){
+		/* insert will furtherly be added to message list */
+		insert->from = ast_strdup(pak->from->full);
+		if (!insert->from) {
+			ast_free(insert);
+			ast_log(LOG_ERROR, "Memory allocation failure\n");
+			return;
+		}
+		ast_debug(3, "message comes from %s\n", insert->from);
+	}
+
+	if (client->send_to_dialplan) {
+		if ((msg = ast_msg_alloc())) {
+			int res;
+
+			res = ast_msg_set_to(msg, "xmpp:%s", client->user);
+			res |= ast_msg_set_from(msg, "xmpp:%s", insert->from);
+			res |= ast_msg_set_body(msg, "%s", insert->message);
+			res |= ast_msg_set_context(msg, "%s", client->context);
+
+			if (res) {
+				ast_msg_destroy(msg);
+			} else {
+				ast_msg_queue(msg);
+			}
+
+			msg = NULL;
+		}
+	}
+
+	/* remove old messages received from this JID
+	 * and insert received message */
+	deleted = delete_old_messages(client, pak->from->partial);
+	ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
+	AST_LIST_LOCK(&client->messages);
+	AST_LIST_INSERT_HEAD(&client->messages, insert, list);
+	AST_LIST_UNLOCK(&client->messages);
+}
+
+/*!
+ * \internal
+ * \brief handles \verbatim <presence>\endverbatim stanzas.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param pak ikspak
+ */
+static void aji_handle_presence(struct aji_client *client, ikspak *pak)
+{
+	int status, priority;
+	struct aji_buddy *buddy;
+	struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
+	char *ver, *node, *descrip, *type;
+
+	if (client->state != AJI_CONNECTED)
+		aji_create_buddy(pak->from->partial, client);
+
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+	if (!buddy && pak->from->partial) {
+		/* allow our jid to be used to log in with another resource */
+		if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
+			aji_create_buddy(pak->from->partial, client);
+		else
+			ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
+		return;
+	}
+	type = iks_find_attrib(pak->x, "type");
+	if (client->component && type &&!strcasecmp("probe", type)) {
+		aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
+		ast_verbose("what i was looking for \n");
+	}
+	ASTOBJ_WRLOCK(buddy);
+	status = (pak->show) ? pak->show : 6;
+	priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
+	tmp = buddy->resources;
+	descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
+
+	while (tmp && pak->from->resource) {
+		if (!strcasecmp(tmp->resource, pak->from->resource)) {
+			tmp->status = status;
+			if (tmp->description) {
+				ast_free(tmp->description);
+			}
+			tmp->description = descrip;
+			found = tmp;
+			if (status == 6) {	/* Sign off Destroy resource */
+				if (last && found->next) {
+					last->next = found->next;
+				} else if (!last) {
+					if (found->next) {
+						buddy->resources = found->next;
+					} else {
+						buddy->resources = NULL;
+					}
+				} else if (!found->next) {
+					if (last) {
+						last->next = NULL;
+					} else {
+						buddy->resources = NULL;
+					}
+				}
+				ast_free(found);
+				found = NULL;
+				break;
+			}
+			/* resource list is sorted by descending priority */
+			if (tmp->priority != priority) {
+				found->priority = priority;
+				if (!last && !found->next) {
+					/* resource was found to be unique,
+					   leave loop */
+					break;
+				}
+				/* search for resource in our list
+				   and take it out for the moment */
+				if (last) {
+					last->next = found->next;
+				} else {
+					buddy->resources = found->next;
+				}
+
+				last = NULL;
+				tmp = buddy->resources;
+				if (!buddy->resources) {
+					buddy->resources = found;
+				}
+				/* priority processing */
+				while (tmp) {
+					/* insert resource back according to
+					   its priority value */
+					if (found->priority > tmp->priority) {
+						if (last) {
+							/* insert within list */
+							last->next = found;
+						}
+						found->next = tmp;
+						if (!last) {
+							/* insert on top */
+							buddy->resources = found;
+						}
+						break;
+					}
+					if (!tmp->next) {
+						/* insert at the end of the list */
+						tmp->next = found;
+						found->next = NULL;
+						break;
+					}
+					last = tmp;
+					tmp = tmp->next;
+				}
+			}
+			break;
+		}
+		last = tmp;
+		tmp = tmp->next;
+	}
+
+	/* resource not found in our list, create it */
+	if (!found && status != 6 && pak->from->resource) {
+		found = ast_calloc(1, sizeof(*found));
+
+		if (!found) {
+			ast_log(LOG_ERROR, "Out of memory!\n");
+			ASTOBJ_UNLOCK(buddy);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			return;
+		}
+		ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
+		found->status = status;
+		found->description = descrip;
+		found->priority = priority;
+		found->next = NULL;
+		last = NULL;
+		tmp = buddy->resources;
+		while (tmp) {
+			if (found->priority > tmp->priority) {
+				if (last) {
+					last->next = found;
+				}
+				found->next = tmp;
+				if (!last) {
+					buddy->resources = found;
+				}
+				break;
+			}
+			if (!tmp->next) {
+				tmp->next = found;
+				break;
+			}
+			last = tmp;
+			tmp = tmp->next;
+		}
+		if (!tmp) {
+			buddy->resources = found;
+		}
+	}
+
+	ASTOBJ_UNLOCK(buddy);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+
+	node = iks_find_attrib(iks_find(pak->x, "c"), "node");
+	ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
+
+	/* handle gmail client's special caps:c tag */
+	if (!node && !ver) {
+		node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
+		ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
+	}
+
+	/* retrieve capabilites of the new resource */
+	if (status != 6 && found && !found->cap) {
+		found->cap = aji_find_version(node, ver, pak);
+		if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
+			found->cap->jingle = 1;
+		}
+		if (found->cap->jingle) {
+			ast_debug(1, "Special case for google till they support discover.\n");
+		} else {
+			iks *iq, *query;
+			iq = iks_new("iq");
+			query = iks_new("query");
+			if (query && iq) {
+				iks_insert_attrib(iq, "type", "get");
+				iks_insert_attrib(iq, "to", pak->from->full);
+				iks_insert_attrib(iq, "from", client->jid->full);
+				iks_insert_attrib(iq, "id", client->mid);
+				ast_aji_increment_mid(client->mid);
+				iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
+				iks_insert_node(iq, query);
+				ast_aji_send(client, iq);
+			} else {
+				ast_log(LOG_ERROR, "Out of memory.\n");
+			}
+			iks_delete(query);
+			iks_delete(iq);
+		}
+	}
+	switch (pak->subtype) {
+	case IKS_TYPE_AVAILABLE:
+		ast_debug(3, "JABBER: I am available ^_* %u\n", pak->subtype);
+		break;
+	case IKS_TYPE_UNAVAILABLE:
+		ast_debug(3, "JABBER: I am unavailable ^_* %u\n", pak->subtype);
+		break;
+	default:
+		ast_debug(3, "JABBER: Ohh sexy and the wrong type: %u\n", pak->subtype);
+	}
+	switch (pak->show) {
+	case IKS_SHOW_UNAVAILABLE:
+		ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
+		break;
+	case IKS_SHOW_AVAILABLE:
+		ast_debug(3, "JABBER: type is available\n");
+		break;
+	case IKS_SHOW_CHAT:
+		ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
+		break;
+	case IKS_SHOW_AWAY:
+		ast_debug(3, "JABBER: type is away\n");
+		break;
+	case IKS_SHOW_XA:
+		ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
+		break;
+	case IKS_SHOW_DND:
+		ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
+		break;
+	default:
+		ast_debug(3, "JABBER: Kinky! how did that happen %u\n", pak->show);
+	}
+
+	if (found) {
+		manager_event(EVENT_FLAG_USER, "JabberStatus",
+			"Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
+			"\r\nDescription: %s\r\n",
+			client->name, pak->from->partial, found->resource, found->status,
+			found->priority, S_OR(found->description, ""));
+	} else {
+		manager_event(EVENT_FLAG_USER, "JabberStatus",
+			"Account: %s\r\nJID: %s\r\nStatus: %u\r\n",
+			client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
+	}
+}
+
+/*!
+ * \internal
+ * \brief handles subscription requests.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param pak ikspak iksemel packet.
+ * \return void.
+ */
+static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
+{
+	iks *presence = NULL, *status = NULL;
+	struct aji_buddy* buddy = NULL;
+
+	switch (pak->subtype) {
+	case IKS_TYPE_SUBSCRIBE:
+		if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
+			presence = iks_new("presence");
+			status = iks_new("status");
+			if (presence && status) {
+				iks_insert_attrib(presence, "type", "subscribed");
+				iks_insert_attrib(presence, "to", pak->from->full);
+				iks_insert_attrib(presence, "from", client->jid->full);
+				if (pak->id)
+					iks_insert_attrib(presence, "id", pak->id);
+				iks_insert_cdata(status, "Asterisk has approved subscription", 0);
+				iks_insert_node(presence, status);
+				ast_aji_send(client, presence);
+			} else {
+				ast_log(LOG_ERROR, "Unable to allocate nodes\n");
+			}
+
+			iks_delete(presence);
+			iks_delete(status);
+		}
+
+		if (client->component)
+			aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
+	case IKS_TYPE_SUBSCRIBED:
+		buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+		if (!buddy && pak->from->partial) {
+			aji_create_buddy(pak->from->partial, client);
+		} else if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+		}
+	default:
+		ast_verb(5, "JABBER: This is a subcription of type %u\n", pak->subtype);
+	}
+}
+
+/*!
+ * \brief sends messages.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param address
+ * \param message
+ * \retval IKS_OK success
+ * \retval -1 failure
+ */
+int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
+{
+	return aji_send_raw_chat(client, 0, NULL, address, message);
+}
+
+/*!
+* \brief sends message to a groupchat
+* Prior to sending messages to a groupchat, one must be connected to it.
+* \param client the configured XMPP client we use to connect to a XMPP server
+* \param nick the nickname we use in the chatroom
+* \param address the user the messages must be sent to
+* \param message the message to send
+* \return IKS_OK on success, any other value on failure
+*/
+int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) {
+	return aji_send_raw_chat(client, 1, nick, address, message);
+}
+
+/*!
+* \brief sends messages.
+* \param client the configured XMPP client we use to connect to a XMPP server
+* \param groupchat 
+* \param nick the nickname we use in chatrooms
+* \param address
+* \param message
+* \return IKS_OK on success, any other value on failure
+*/
+static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message)
+{
+	int res = 0;
+	iks *message_packet = NULL;
+	char from[AJI_MAX_JIDLEN];
+	/* the nickname is used only in component mode */
+	if (nick && client->component) {
+		snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
+	} else {
+		snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
+	}
+
+	if (client->state != AJI_CONNECTED) {
+		ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
+		return -1;
+	}
+
+	message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
+	if (!message_packet) {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+		return -1;
+	}
+	iks_insert_attrib(message_packet, "from", from);
+	res = ast_aji_send(client, message_packet);
+	iks_delete(message_packet);
+
+	return res;
+}
+
+/*!
+ * \brief create a chatroom.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param room name of room
+ * \param server name of server
+ * \param topic topic for the room.
+ * \return 0.
+ */
+int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
+{
+	int res = 0;
+	iks *iq = NULL;
+	iq = iks_new("iq");
+
+	if (iq && client) {
+		iks_insert_attrib(iq, "type", "get");
+		iks_insert_attrib(iq, "to", server);
+		iks_insert_attrib(iq, "id", client->mid);
+		ast_aji_increment_mid(client->mid);
+		ast_aji_send(client, iq);
+	} else {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	}
+
+	iks_delete(iq);
+
+	return res;
+}
+
+/*!
+ * \brief join a chatroom.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param room room to join
+ * \param nick the nickname to use in this room
+ * \return IKS_OK on success, any other value on failure.
+ */
+int ast_aji_join_chat(struct aji_client *client, char *room, char *nick)
+{
+	return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
+}
+
+/*!
+ * \brief leave a chatroom.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param room room to leave
+ * \param nick the nickname used in this room
+ * \return IKS_OK on success, any other value on failure.
+ */
+int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick)
+{
+	return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
+}
+/*!
+ * \brief invite to a chatroom.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param user
+ * \param room
+ * \param message
+ * \return res.
+ */
+int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
+{
+	int res = 0;
+	iks *invite, *body, *namespace;
+
+	invite = iks_new("message");
+	body = iks_new("body");
+	namespace = iks_new("x");
+	if (client && invite && body && namespace) {
+		iks_insert_attrib(invite, "to", user);
+		iks_insert_attrib(invite, "id", client->mid);
+		ast_aji_increment_mid(client->mid);
+		iks_insert_cdata(body, message, 0);
+		iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
+		iks_insert_attrib(namespace, "jid", room);
+		iks_insert_node(invite, body);
+		iks_insert_node(invite, namespace);
+		res = ast_aji_send(client, invite);
+	} else {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	}
+
+	iks_delete(body);
+	iks_delete(namespace);
+	iks_delete(invite);
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief receive message loop.
+ * \param data void
+ * \return void.
+ */
+static void *aji_recv_loop(void *data)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	int res = IKS_HOOK;
+
+	while (res != IKS_OK) {
+		ast_debug(3, "JABBER: Connecting.\n");
+		res = aji_reconnect(client);
+		sleep(4);
+	}
+
+	do {
+		if (res == IKS_NET_RWERR || client->timeout == 0) {
+			while (res != IKS_OK) {
+				ast_debug(3, "JABBER: reconnecting.\n");
+				res = aji_reconnect(client);
+				sleep(4);
+			}
+		}
+
+		res = aji_recv(client, 1);
+
+		if (client->state == AJI_DISCONNECTING) {
+			ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
+			pthread_exit(NULL);
+		}
+
+		/* Decrease timeout if no data received, and delete
+		 * old messages globally */
+		if (res == IKS_NET_EXPIRED) {
+			client->timeout--;
+			delete_old_messages_all(client);
+		}
+		if (res == IKS_HOOK) {
+			ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
+		} else if (res == IKS_NET_TLSFAIL) {
+			ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
+		} else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
+			res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
+			if (res == IKS_OK) {
+				client->timeout = 50;
+			} else {
+				ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
+			}
+		} else if (res == IKS_NET_RWERR) {
+			ast_log(LOG_WARNING, "JABBER: socket read error\n");
+		}
+	} while (client);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return 0;
+}
+
+/*!
+ * \brief increments the mid field for messages and other events.
+ * \param mid char.
+ * \return void.
+ */
+void ast_aji_increment_mid(char *mid)
+{
+	int i = 0;
+
+	for (i = strlen(mid) - 1; i >= 0; i--) {
+		if (mid[i] != 'z') {
+			mid[i] = mid[i] + 1;
+			i = 0;
+		} else
+			mid[i] = 'a';
+	}
+}
+
+#if 0
+/*!
+ * \brief attempts to register to a transport.
+ * \param aji_client struct, and xml packet.
+ * \return IKS_FILTER_EAT.
+ */
+/*allows for registering to transport , was too sketch and is out for now. */
+static int aji_register_transport(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	int res = 0;
+	struct aji_buddy *buddy = NULL;
+	iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
+
+	if (client && send) {
+		ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+			ASTOBJ_RDLOCK(iterator); 
+			if (iterator->btype == AJI_TRANS) {
+				  buddy = iterator;
+			}
+			ASTOBJ_UNLOCK(iterator);
+		});
+		iks_filter_remove_hook(client->f, aji_register_transport);
+		iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE);
+		iks_insert_attrib(send, "to", buddy->host);
+		iks_insert_attrib(send, "id", client->mid);
+		ast_aji_increment_mid(client->mid);
+		iks_insert_attrib(send, "from", client->user);
+		res = ast_aji_send(client, send);
+	} else 
+		ast_log(LOG_ERROR, "Out of memory.\n");
+
+	if (send)
+		iks_delete(send);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+
+}
+/*!
+ * \brief attempts to register to a transport step 2.
+ * \param aji_client struct, and xml packet.
+ * \return IKS_FILTER_EAT.
+ */
+/* more of the same blob of code, too wonky for now*/
+static int aji_register_transport2(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	int res = 0;
+	struct aji_buddy *buddy = NULL;
+
+	iks *regiq = iks_new("iq");
+	iks *regquery = iks_new("query");
+	iks *reguser = iks_new("username");
+	iks *regpass = iks_new("password");
+
+	if (client && regquery && reguser && regpass && regiq) {
+		ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			if (iterator->btype == AJI_TRANS)
+				buddy = iterator; ASTOBJ_UNLOCK(iterator);
+		});
+		iks_filter_remove_hook(client->f, aji_register_transport2);
+		iks_insert_attrib(regiq, "to", buddy->host);
+		iks_insert_attrib(regiq, "type", "set");
+		iks_insert_attrib(regiq, "id", client->mid);
+		ast_aji_increment_mid(client->mid);
+		iks_insert_attrib(regiq, "from", client->user);
+		iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
+		iks_insert_cdata(reguser, buddy->user, 0);
+		iks_insert_cdata(regpass, buddy->pass, 0);
+		iks_insert_node(regiq, regquery);
+		iks_insert_node(regquery, reguser);
+		iks_insert_node(regquery, regpass);
+		res = ast_aji_send(client, regiq);
+	} else
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	if (regiq)
+		iks_delete(regiq);
+	if (regquery)
+		iks_delete(regquery);
+	if (reguser)
+		iks_delete(reguser);
+	if (regpass)
+		iks_delete(regpass);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+#endif
+
+/*!
+ * \internal
+ * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return void.
+ * \note The messages here should be configurable.
+ */
+static void aji_pruneregister(struct aji_client *client)
+{
+	iks *removeiq = iks_new("iq");
+	iks *removequery = iks_new("query");
+	iks *removeitem = iks_new("item");
+	iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
+	if (!client || !removeiq || !removequery || !removeitem || !send) {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+		goto safeout;
+	}
+
+	iks_insert_node(removeiq, removequery);
+	iks_insert_node(removequery, removeitem);
+	ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		/* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
+		 * be called at the same time */
+		if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
+			ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
+								 "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
+								 " so I am no longer subscribing to your presence.\n"));
+			ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
+								 "GoodBye.  You are no longer in the Asterisk config file so I am removing"
+								 " your access to my presence.\n"));
+			iks_insert_attrib(removeiq, "from", client->jid->full);
+			iks_insert_attrib(removeiq, "type", "set");
+			iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
+			iks_insert_attrib(removeitem, "jid", iterator->name);
+			iks_insert_attrib(removeitem, "subscription", "remove");
+			ast_aji_send(client, removeiq);
+		} else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
+			ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
+								 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
+			ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
+		}
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+ safeout:
+	iks_delete(removeiq);
+	iks_delete(removequery);
+	iks_delete(removeitem);
+	iks_delete(send);
+
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
+}
+
+/*!
+ * \internal
+ * \brief filters the roster packet we get back from server.
+ * \param data void
+ * \param pak ikspak iksemel packet.
+ * \return IKS_FILTER_EAT.
+ */
+static int aji_filter_roster(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	int flag = 0;
+	iks *x = NULL;
+	struct aji_buddy *buddy;
+
+	client->state = AJI_CONNECTED;
+	ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		x = iks_child(pak->query);
+		flag = 0;
+		while (x) {
+			if (!iks_strcmp(iks_name(x), "item")) {
+				if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
+					flag = 1;
+					ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
+				}
+			}
+			x = iks_next(x);
+		}
+		if (!flag) {
+			ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
+		}
+		iks_delete(x);
+
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+	x = iks_child(pak->query);
+	while (x) {
+		flag = 0;
+		if (iks_strcmp(iks_name(x), "item") == 0) {
+			ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+				ASTOBJ_RDLOCK(iterator);
+				if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
+					flag = 1;
+				ASTOBJ_UNLOCK(iterator);
+			});
+
+			if (flag) {
+				/* found buddy, don't create a new one */
+				x = iks_next(x);
+				continue;
+			}
+
+			buddy = ast_calloc(1, sizeof(*buddy));
+			if (!buddy) {
+				ast_log(LOG_WARNING, "Out of memory\n");
+				ASTOBJ_UNREF(client, ast_aji_client_destroy);
+				return 0;
+			}
+			ASTOBJ_INIT(buddy);
+			ASTOBJ_WRLOCK(buddy);
+			ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
+			ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
+			if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
+				ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
+				ASTOBJ_MARK(buddy);
+			} else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
+				if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
+					/* subscribe to buddy's presence only
+					   if we really need to */
+					ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
+				}
+			}
+			ASTOBJ_UNLOCK(buddy);
+			if (buddy) {
+				ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			}
+		}
+		x = iks_next(x);
+	}
+
+	iks_delete(x);
+	aji_pruneregister(client);
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \internal
+ * \brief reconnect to jabber server
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return res.
+*/
+static int aji_reconnect(struct aji_client *client)
+{
+	int res = 0;
+
+	if (client->state) {
+		client->state = AJI_DISCONNECTED;
+	}
+	client->timeout = 50;
+	if (client->p) {
+		iks_parser_reset(client->p);
+	}
+	if (client->authorized) {
+		client->authorized = 0;
+	}
+
+	res = aji_initialize(client);
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Get the roster of jabber users
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return 1.
+*/
+static int aji_get_roster(struct aji_client *client)
+{
+	iks *roster = NULL;
+	roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
+
+	if (roster) {
+		iks_insert_attrib(roster, "id", "roster");
+		aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
+		ast_aji_send(client, roster);
+	}
+
+	iks_delete(roster);
+
+	return 1;
+}
+
+/*!
+ * \internal
+ * \brief connects as a client to jabber server.
+ * \param data void
+ * \param pak ikspak iksemel packet
+ * \return res.
+ */
+static int aji_client_connect(void *data, ikspak *pak)
+{
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	int res = IKS_FILTER_PASS;
+
+	if (client) {
+		if (client->state == AJI_DISCONNECTED) {
+			iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
+			client->state = AJI_CONNECTING;
+			client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
+			if (!client->component) { /*client*/
+				aji_get_roster(client);
+			}
+			if (client->distribute_events) {
+				aji_init_event_distribution(client);
+			}
+
+			iks_filter_remove_hook(client->f, aji_client_connect);
+			/* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
+			res = IKS_FILTER_EAT;
+		}
+	} else {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	}
+
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief prepares client for connect.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return 1.
+ */
+static int aji_initialize(struct aji_client *client)
+{
+	int connected = IKS_NET_NOCONN;
+
+#ifdef HAVE_OPENSSL
+	/* reset stream flags */
+	client->stream_flags = 0;
+#endif
+	/* If it's a component, connect to user, otherwise, connect to server */
+	connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
+
+	if (connected == IKS_NET_NOCONN) {
+		ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
+		return IKS_HOOK;
+	} else if (connected == IKS_NET_NODNS) {
+		ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name,
+			S_OR(client->serverhost, client->jid->server));
+		return IKS_HOOK;
+	}
+
+	return IKS_OK;
+}
+
+/*!
+ * \brief disconnect from jabber server.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return 1.
+ */
+int ast_aji_disconnect(struct aji_client *client)
+{
+	if (client) {
+		ast_verb(4, "JABBER: Disconnecting\n");
+#ifdef HAVE_OPENSSL
+		if (client->stream_flags & SECURE) {
+			SSL_shutdown(client->ssl_session);
+			SSL_CTX_free(client->ssl_context);
+			SSL_free(client->ssl_session);
+		}
+#endif
+		iks_disconnect(client->p);
+		iks_parser_delete(client->p);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	}
+
+	return 1;
+}
+
+/*!
+ * \brief Callback function for MWI events
+ * \param ast_event
+ * \param data void pointer to ast_client structure
+ * \return void
+ */
+static void aji_mwi_cb(const struct ast_event *ast_event, void *data)
+{
+	const char *mailbox;
+	const char *context;
+	char oldmsgs[10];
+	char newmsgs[10];
+	struct aji_client *client;
+	if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
+	{
+		/* If the event didn't originate from this server, don't send it back out. */
+		ast_debug(1, "Returning here\n");
+		return;
+	}
+
+	client = ASTOBJ_REF((struct aji_client *) data);
+	mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
+	context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
+	snprintf(oldmsgs, sizeof(oldmsgs), "%u",
+		ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
+	snprintf(newmsgs, sizeof(newmsgs), "%u",
+		ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
+	aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+
+}
+/*!
+ * \brief Callback function for device state events
+ * \param ast_event
+ * \param data void pointer to ast_client structure
+ * \return void
+ */
+static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
+{
+	const char *device;
+	const char *device_state;
+	unsigned int cachable;
+	struct aji_client *client;
+	if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
+	{
+		/* If the event didn't originate from this server, don't send it back out. */
+		ast_debug(1, "Returning here\n");
+		return;
+	}
+
+	client = ASTOBJ_REF((struct aji_client *) data);
+	device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
+	device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
+	cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
+	aji_publish_device_state(client, device, device_state, cachable);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+}
+
+/*!
+ * \brief Initialize collections for event distribution
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \return void
+ */
+static void aji_init_event_distribution(struct aji_client *client)
+{
+	if (!mwi_sub) {
+		mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
+			client, AST_EVENT_IE_END);
+	}
+	if (!device_state_sub) {
+		if (ast_enable_distributed_devstate()) {
+			return;
+		}
+		device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
+			aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
+		ast_event_dump_cache(device_state_sub);
+	}
+
+	aji_pubsub_subscribe(client, "device_state");
+	aji_pubsub_subscribe(client, "message_waiting");
+	iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
+		IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
+	iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
+		IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
+
+}
+
+/*!
+ * \brief Callback for handling PubSub events
+ * \param data void pointer to aji_client structure
+ * \return IKS_FILTER_EAT
+ */
+static int aji_handle_pubsub_event(void *data, ikspak *pak)
+{
+	char *item_id, *device_state, *mailbox, *cachable_str;
+	int oldmsgs, newmsgs;
+	iks *item, *item_content;
+	struct ast_eid pubsub_eid;
+	struct ast_event *event;
+	unsigned int cachable = AST_DEVSTATE_CACHABLE;
+
+	item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
+	if (!item) {
+		ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
+		return IKS_FILTER_EAT;
+	}
+	item_id = iks_find_attrib(item, "id");
+	item_content = iks_child(item);
+	ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
+	if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
+		ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
+		return IKS_FILTER_EAT;
+	}
+	if (!strcasecmp(iks_name(item_content), "state")) {
+		if ((cachable_str = iks_find_attrib(item_content, "cachable"))) {
+			sscanf(cachable_str, "%30u", &cachable);
+		}
+		device_state = iks_find_cdata(item, "state");
+		if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
+					    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
+					    AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
+					    AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+					    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
+					    AST_EVENT_IE_END))) {
+			return IKS_FILTER_EAT;
+		}
+	} else if (!strcasecmp(iks_name(item_content), "mailbox")) {
+		mailbox = strsep(&item_id, "@");
+		sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
+		sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
+		if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, item_id,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, oldmsgs,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, newmsgs,
+			AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+			AST_EVENT_IE_END))) {
+			return IKS_FILTER_EAT;
+		}
+	} else {
+		ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
+			iks_name(item_content));
+		return IKS_FILTER_EAT;
+	}
+
+	if (cachable == AST_DEVSTATE_CACHABLE) {
+		ast_event_queue_and_cache(event);
+	} else {
+		ast_event_queue(event);
+	}
+
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \brief Add Owner affiliations for pubsub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node the name of the node to which to add affiliations
+ * \return void
+ */
+static void aji_create_affiliations(struct aji_client *client, const char *node)
+{
+	iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
+	iks *pubsub, *affiliations, *affiliate;
+	pubsub = iks_insert(modify_affiliates, "pubsub");
+	iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
+	affiliations = iks_insert(pubsub, "affiliations");
+	iks_insert_attrib(affiliations, "node", node);
+	ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		affiliate = iks_insert(affiliations, "affiliation");
+		iks_insert_attrib(affiliate, "jid", iterator->name);
+		iks_insert_attrib(affiliate, "affiliation", "owner");
+		ASTOBJ_UNLOCK(iterator);
+	});
+	ast_aji_send(client, modify_affiliates);
+	iks_delete(modify_affiliates);
+}
+
+/*!
+ * \brief Subscribe to a PubSub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node the name of the node to which to subscribe
+ * \return void
+ */
+static void aji_pubsub_subscribe(struct aji_client *client, const char *node)
+{
+	iks *request = aji_pubsub_iq_create(client, "set");
+	iks *pubsub, *subscribe;
+
+	pubsub = iks_insert(request, "pubsub");
+	iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
+	subscribe = iks_insert(pubsub, "subscribe");
+	iks_insert_attrib(subscribe, "jid", client->jid->partial);
+	iks_insert_attrib(subscribe, "node", node);
+	if (ast_test_flag(&globalflags, AJI_XEP0248)) {
+		iks *options, *x, *sub_options, *sub_type, *sub_depth;
+		options = iks_insert(pubsub, "options");
+		x = iks_insert(options, "x");
+		iks_insert_attrib(x, "xmlns", "jabber:x:data");
+		iks_insert_attrib(x, "type", "submit");
+		sub_options = iks_insert(x, "field");
+		iks_insert_attrib(sub_options, "var", "FORM_TYPE");
+		iks_insert_attrib(sub_options, "type", "hidden");
+		iks_insert_cdata(iks_insert(sub_options, "value"),
+			"http://jabber.org/protocol/pubsub#subscribe_options", 51);
+		sub_type = iks_insert(x, "field");
+		iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
+		iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
+		sub_depth = iks_insert(x, "field");
+		iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
+		iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
+	}
+	ast_aji_send(client, request);
+	iks_delete(request);
+}
+
+/*!
+ * \brief Build the skeleton of a publish
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node Name of the node that will be published to
+ * \param event_type
+ * \return iks *
+ */
+static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
+				       const char *event_type, unsigned int cachable)
+{
+	iks *request = aji_pubsub_iq_create(client, "set");
+	iks *pubsub, *publish, *item;
+	pubsub = iks_insert(request, "pubsub");
+	iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
+	publish = iks_insert(pubsub, "publish");
+	if (ast_test_flag(&globalflags, AJI_XEP0248)) {
+		iks_insert_attrib(publish, "node", node);
+	} else {
+		iks_insert_attrib(publish, "node", event_type);
+	}
+	item = iks_insert(publish, "item");
+	iks_insert_attrib(item, "id", node);
+
+	if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
+		iks *options, *x, *field_form_type, *field_persist;
+
+		options = iks_insert(pubsub, "publish-options");
+		x = iks_insert(options, "x");
+		iks_insert_attrib(x, "xmlns", "jabber:x:data");
+		iks_insert_attrib(x, "type", "submit");
+		field_form_type = iks_insert(x, "field");
+		iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
+		iks_insert_attrib(field_form_type, "type", "hidden");
+		iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
+		field_persist = iks_insert(x, "field");
+		iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
+		iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
+	}
+
+	return item;
+}
+
+/*!
+ * \brief Publish device state to a PubSub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param device the name of the device whose state to publish
+ * \param device_state the state to publish
+ * \return void
+ */
+static void aji_publish_device_state(struct aji_client *client, const char *device,
+				     const char *device_state, unsigned int cachable)
+{
+	iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable);
+	iks *state;
+	char eid_str[20], cachable_str[2];
+	if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
+		if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
+			aji_create_pubsub_node(client, "leaf", device, "device_state");
+		} else {
+			aji_create_pubsub_node(client, NULL, device, NULL);
+		}
+	}
+	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
+	state = iks_insert(request, "state");
+	iks_insert_attrib(state, "xmlns", "http://asterisk.org");
+	iks_insert_attrib(state, "eid", eid_str);
+	snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
+	iks_insert_attrib(state, "cachable", cachable_str);
+	iks_insert_cdata(state, device_state, strlen(device_state));
+	ast_aji_send(client, iks_root(request));
+	iks_delete(request);
+}
+
+/*!
+ * \brief Publish MWI to a PubSub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param device the name of the device whose state to publish
+ * \param device_state the state to publish
+ * \return void
+ */
+static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
+	const char *context, const char *oldmsgs, const char *newmsgs)
+{
+	char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
+	char eid_str[20];
+	iks *mailbox_node, *request;
+	snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
+	request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting", 1);
+	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
+	mailbox_node = iks_insert(request, "mailbox");
+	iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
+	iks_insert_attrib(mailbox_node, "eid", eid_str);
+	iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
+	iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
+	ast_aji_send(client, iks_root(request));
+	iks_delete(request);
+}
+
+/*!
+ * \brief Create an IQ packet
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param type the type of IQ packet to create
+ * \return iks*
+ */
+static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type)
+{
+	iks *request = iks_new("iq");
+
+	iks_insert_attrib(request, "to", client->pubsub_node);
+	iks_insert_attrib(request, "from", client->jid->full);
+	iks_insert_attrib(request, "type", type);
+	ast_aji_increment_mid(client->mid);
+	iks_insert_attrib(request, "id", client->mid);
+	return request;
+}
+
+static int aji_handle_pubsub_error(void *data, ikspak *pak)
+{
+	char *node_name;
+	char *error;
+	int error_num;
+	iks *orig_request;
+	iks *orig_pubsub = iks_find(pak->x, "pubsub");
+	struct aji_client *client;
+	if (!orig_pubsub) {
+		ast_debug(1, "Error isn't a PubSub error, why are we here?\n");
+		return IKS_FILTER_EAT;
+	}
+	orig_request = iks_child(orig_pubsub);
+	error = iks_find_attrib(iks_find(pak->x, "error"), "code");
+	node_name = iks_find_attrib(orig_request, "node");
+	if (!sscanf(error, "%30d", &error_num)) {
+		return IKS_FILTER_EAT;
+	}
+	if (error_num > 399 && error_num < 500 && error_num != 404) {
+		ast_log(LOG_ERROR,
+			"Error performing operation on PubSub node %s, %s.\n", node_name, error);
+		return IKS_FILTER_EAT;
+	} else if (error_num > 499 && error_num < 600) {
+		ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
+		return IKS_FILTER_EAT;
+	}
+
+	client = ASTOBJ_REF((struct aji_client *) data);
+
+	if (!strcasecmp(iks_name(orig_request), "publish")) {
+		iks *request;
+		if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
+			if (iks_find(iks_find(orig_request, "item"), "state")) {
+				aji_create_pubsub_leaf(client, "device_state", node_name);
+			} else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
+				aji_create_pubsub_leaf(client, "message_waiting", node_name);
+			}
+		} else {
+			aji_create_pubsub_node(client, NULL, node_name, NULL);
+		}
+		request = aji_pubsub_iq_create(client, "set");
+		iks_insert_node(request, orig_pubsub);
+		ast_aji_send(client, request);
+		iks_delete(request);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return IKS_FILTER_EAT;
+	} else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
+		if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
+			aji_create_pubsub_collection(client, node_name);
+		} else {
+			aji_create_pubsub_node(client, NULL, node_name, NULL);
+		}
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+/*!
+ * \brief Request item list from pubsub
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param collection name of the collection for request
+ * \return void
+ */
+static void aji_request_pubsub_nodes(struct aji_client *client, const char *collection)
+{
+	iks *request = aji_build_node_request(client, collection);
+
+	iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
+		IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
+		IKS_RULE_DONE);
+	ast_aji_send(client, request);
+	iks_delete(request);
+
+}
+
+/*!
+ * \brief Build the a node request
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param collection name of the collection for request
+ * \return iks*
+ */
+static iks* aji_build_node_request(struct aji_client *client, const char *collection)
+{
+	iks *request = aji_pubsub_iq_create(client, "get");
+	iks *query;
+	query = iks_insert(request, "query");
+	iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
+	if (collection) {
+		iks_insert_attrib(query, "node", collection);
+	}
+	return request;
+}
+
+/*!
+ * \brief Receive pubsub item lists
+ * \param data pointer to aji_client structure
+ * \param pak response from pubsub diso#items query
+ * \return IKS_FILTER_EAT
+ */
+static int aji_receive_node_list(void *data, ikspak* pak)
+{
+
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	iks *item = NULL;
+	if (iks_has_children(pak->query)) {
+		item = iks_first_tag(pak->query);
+		ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
+			iks_find_attrib(item, "node"));
+		while ((item = iks_next_tag(item))) {
+			ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
+		}
+	}
+	if (item) {
+		iks_delete(item);
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return IKS_FILTER_EAT;
+}
+
+
+/*!
+ * \brief Method to expose PubSub node list via CLI.
+ * \param e pointer to ast_cli_entry structure
+ * \param cmd
+ * \param a pointer to ast_cli_args structure
+ * \return char *
+ */
+static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
+ast_cli_args *a)
+{
+		struct aji_client *client;
+		const char *name = NULL;
+		const char *collection = NULL;
+
+		switch (cmd) {
+		case CLI_INIT:
+				e->command = "jabber list nodes";
+				e->usage =
+					"Usage: jabber list nodes <connection> [collection]\n"
+					"       Lists the user's nodes on the respective connection\n"
+					"       ([connection] as configured in jabber.conf.)\n";
+			return NULL;
+		case CLI_GENERATE:
+			return NULL;
+		}
+
+		if (a->argc > 5 || a->argc < 4) {
+			return CLI_SHOWUSAGE;
+		} else if (a->argc == 4 || a->argc == 5) {
+			name = a->argv[3];
+		}
+		if (a->argc == 5) {
+			collection = a->argv[4];
+		}
+		if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+			ast_cli(a->fd, "Unable to find client '%s'!\n", name);
+			return CLI_FAILURE;
+		}
+
+		ast_cli(a->fd, "Listing pubsub nodes.\n");
+		aji_request_pubsub_nodes(client, collection);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return CLI_SUCCESS;
+}
+
+/*!
+ * \brief Method to purge PubSub nodes via CLI.
+ * \param e pointer to ast_cli_entry structure
+ * \param cmd
+ * \param a pointer to ast_cli_args structure
+ * \return char *
+ */
+static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
+	ast_cli_args *a)
+{
+	struct aji_client *client;
+	const char *name;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "jabber purge nodes";
+			e->usage =
+					"Usage: jabber purge nodes <connection> <node>\n"
+					"       Purges nodes on PubSub server\n"
+					"       as configured in jabber.conf.\n";
+			return NULL;
+		case CLI_GENERATE:
+			return NULL;
+	}
+
+	if (a->argc != 5) {
+		return CLI_SHOWUSAGE;
+	}
+	name = a->argv[3];
+
+	if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+		ast_cli(a->fd, "Unable to find client '%s'!\n", name);
+		return CLI_FAILURE;
+	}
+	if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
+		aji_pubsub_purge_nodes(client, a->argv[4]);
+	} else {
+		aji_delete_pubsub_node(client, a->argv[4]);
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return CLI_SUCCESS;
+}
+
+static void aji_pubsub_purge_nodes(struct aji_client *client, const char* collection_name)
+{
+	iks *request = aji_build_node_request(client, collection_name);
+	ast_aji_send(client, request);
+	iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
+		IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
+		IKS_RULE_DONE);
+	ast_aji_send(client, request);
+	iks_delete(request);
+}
+
+/*!
+ * \brief Delete pubsub item lists
+ * \param data pointer to aji_client structure
+ * \param pak response from pubsub diso#items query
+ * \return IKS_FILTER_EAT
+ */
+static int aji_delete_node_list(void *data, ikspak* pak)
+{
+
+	struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+	iks *item = NULL;
+	if (iks_has_children(pak->query)) {
+		item = iks_first_tag(pak->query);
+		ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
+				iks_find_attrib(item, "node"));
+		while ((item = iks_next_tag(item))) {
+			aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
+		}
+	}
+	if (item) {
+		iks_delete(item);
+	}
+	return IKS_FILTER_EAT;
+}
+
+
+/*!
+ * \brief Method to expose PubSub node deletion via CLI.
+ * \param e pointer to ast_cli_entry structure
+ * \param cmd
+ * \param a pointer to ast_cli_args structure
+ * \return char *
+ */
+static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
+	ast_cli_args *a)
+{
+	struct aji_client *client;
+	const char *name;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "jabber delete node";
+			e->usage =
+					"Usage: jabber delete node <connection> <node>\n"
+					"       Deletes a node on PubSub server\n"
+					"       as configured in jabber.conf.\n";
+			return NULL;
+		case CLI_GENERATE:
+			return NULL;
+	}
+
+	if (a->argc != 5) {
+		return CLI_SHOWUSAGE;
+	}
+	name = a->argv[3];
+
+	if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+		ast_cli(a->fd, "Unable to find client '%s'!\n", name);
+		return CLI_FAILURE;
+	}
+	aji_delete_pubsub_node(client, a->argv[4]);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \brief Delete a PubSub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node_name the name of the node to delete
+ * return void
+ */
+static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name)
+{
+	iks *request = aji_pubsub_iq_create(client, "set");
+	iks *pubsub, *delete;
+	pubsub = iks_insert(request, "pubsub");
+	iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
+	delete = iks_insert(pubsub, "delete");
+	iks_insert_attrib(delete, "node", node_name);
+	ast_aji_send(client, request);
+}
+
+/*!
+ * \brief Create a PubSub collection node.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param collection_name The name to use for this collection
+ * \return void.
+ */
+static void aji_create_pubsub_collection(struct aji_client *client, const char
+*collection_name)
+{
+	aji_create_pubsub_node(client, "collection", collection_name, NULL);
+}
+
+
+/*!
+ * \brief Create a PubSub leaf node.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param leaf_name The name to use for this collection
+ * \return void.
+ */
+static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
+const char *leaf_name)
+{
+	aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
+}
+
+/*!
+ * \brief Create a pubsub node
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param node_type the type of node to create
+ * \param name the name of the node to create
+ * \return iks*
+ */
+static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type, const
+		char *name, const char *collection_name)
+{
+	iks *node = aji_pubsub_iq_create(client, "set");
+	iks *pubsub, *create;
+	pubsub = iks_insert(node, "pubsub");
+	iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
+	create = iks_insert(pubsub, "create");
+	iks_insert_attrib(create, "node", name);
+	aji_build_node_config(pubsub, node_type, collection_name);
+	ast_aji_send(client, node);
+	aji_create_affiliations(client, name);
+	iks_delete(node);
+	return 0;
+}
+
+
+
+static iks* aji_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
+{
+	iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
+		*field_deliver_payload, *field_persist_items, *field_access_model,
+		*field_pubsub_collection;
+	configure = iks_insert(pubsub, "configure");
+	x = iks_insert(configure, "x");
+	iks_insert_attrib(x, "xmlns", "jabber:x:data");
+	iks_insert_attrib(x, "type", "submit");
+	field_owner = iks_insert(x, "field");
+	iks_insert_attrib(field_owner, "var", "FORM_TYPE");
+	iks_insert_attrib(field_owner, "type", "hidden");
+	iks_insert_cdata(iks_insert(field_owner, "value"),
+		"http://jabber.org/protocol/pubsub#owner", 39);
+	if (node_type) {
+		field_node_type = iks_insert(x, "field");
+		iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
+		iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
+	}
+	field_node_config = iks_insert(x, "field");
+	iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
+	iks_insert_attrib(field_node_config, "type", "hidden");
+	iks_insert_cdata(iks_insert(field_node_config, "value"),
+		"http://jabber.org/protocol/pubsub#node_config", 45);
+	field_deliver_payload = iks_insert(x, "field");
+	iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
+	iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
+	field_persist_items = iks_insert(x, "field");
+	iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
+	iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
+	field_access_model = iks_insert(x, "field");
+	iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
+	iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
+	if (node_type && !strcasecmp(node_type, "leaf")) {
+		field_pubsub_collection = iks_insert(x, "field");
+		iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
+		iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
+			strlen(collection_name));
+	}
+	return configure;
+}
+
+
+
+/*!
+ * \brief Method to expose PubSub collection node creation via CLI.
+ * \return char *.
+ */
+static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+		struct aji_client *client;
+		const char *name;
+		const char *collection_name;
+
+		switch (cmd) {
+		case CLI_INIT:
+				e->command = "jabber create collection";
+				e->usage =
+					"Usage: jabber create collection <connection> <collection>\n"
+					"       Creates a PubSub collection node using the account\n"
+					"       as configured in jabber.conf.\n";
+			return NULL;
+		case CLI_GENERATE:
+			return NULL;
+		}
+
+		if (a->argc != 5) {
+			return CLI_SHOWUSAGE;
+		}
+		name = a->argv[3];
+		collection_name = a->argv[4];
+
+		if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+			ast_cli(a->fd, "Unable to find client '%s'!\n", name);
+			return CLI_FAILURE;
+		}
+
+		ast_cli(a->fd, "Creating test PubSub node collection.\n");
+		aji_create_pubsub_collection(client, collection_name);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return CLI_SUCCESS;
+}
+
+/*!
+ * \brief Method to expose PubSub leaf node creation via CLI.
+ * \return char *.
+ */
+static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct aji_client *client;
+	const char *name;
+	const char *collection_name;
+	const char *leaf_name;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "jabber create leaf";
+			e->usage =
+					"Usage: jabber create leaf <connection> <collection> <leaf>\n"
+					"       Creates a PubSub leaf node using the account\n"
+					"       as configured in jabber.conf.\n";
+			return NULL;
+		case CLI_GENERATE:
+			return NULL;
+	}
+
+	if (a->argc != 6) {
+		return CLI_SHOWUSAGE;
+	}
+	name = a->argv[3];
+	collection_name = a->argv[4];
+	leaf_name = a->argv[5];
+
+	if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+		ast_cli(a->fd, "Unable to find client '%s'!\n", name);
+		return CLI_FAILURE;
+	}
+
+	ast_cli(a->fd, "Creating test PubSub node collection.\n");
+	aji_create_pubsub_leaf(client, collection_name, leaf_name);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	return CLI_SUCCESS;
+}
+
+
+
+/*!
+ * \internal
+ * \brief set presence of client.
+ * \param client the configured XMPP client we use to connect to a XMPP server
+ * \param to user send it to
+ * \param from user it came from
+ * \param level
+ * \param desc
+ * \return void.
+ */
+static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
+{
+	iks *presence = iks_make_pres(level, desc);
+	iks *cnode = iks_new("c");
+	iks *priority = iks_new("priority");
+	char priorityS[10];
+
+	if (presence && cnode && client && priority) {
+		if (to) {
+			iks_insert_attrib(presence, "to", to);
+		}
+		if (from) {
+			iks_insert_attrib(presence, "from", from);
+		}
+		snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
+		iks_insert_cdata(priority, priorityS, strlen(priorityS));
+		iks_insert_node(presence, priority);
+		iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
+		iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
+		iks_insert_attrib(cnode, "ext", "voice-v1");
+		iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
+		iks_insert_node(presence, cnode);
+		ast_aji_send(client, presence);
+	} else {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+	}
+
+	iks_delete(cnode);
+	iks_delete(presence);
+	iks_delete(priority);
+}
+
+/*
+* \brief set the presence of the client in a groupchat context.
+* \param client the configured XMPP client we use to connect to a XMPP server
+* \param room the groupchat identifier in the from roomname at service
+* \param from user it came from
+* \param level the type of action, i.e. join or leave the chatroom
+* \param nick the nickname to use in the chatroom
+* \param desc a text that details the action to be taken
+* \return res.
+*/
+static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc)
+{
+	int res = 0;
+	iks *presence = NULL, *x = NULL;
+	char from[AJI_MAX_JIDLEN];
+	char roomid[AJI_MAX_JIDLEN];
+
+	presence = iks_make_pres(level, NULL);
+	x = iks_new("x");
+
+	if (client->component) {
+		snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
+		snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
+	} else {
+		snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
+		snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
+	}
+
+	if (!presence || !x || !client) {
+		ast_log(LOG_ERROR, "Out of memory.\n");
+		res = -1;
+		goto safeout;
+	} else {
+		iks_insert_attrib(presence, "to", roomid);
+		iks_insert_attrib(presence, "from", from);
+		iks_insert_attrib(x, "xmlns", MUC_NS);
+		iks_insert_node(presence, x);
+		res = ast_aji_send(client, presence);
+	}
+
+safeout:
+	iks_delete(presence);
+	iks_delete(x);
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Turn on/off console debugging.
+ * \return CLI_SUCCESS.
+ */
+static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jabber set debug {on|off}";
+		e->usage =
+			"Usage: jabber set debug {on|off}\n"
+			"       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != e->args) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
+		ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			iterator->debug = 1;
+			ASTOBJ_UNLOCK(iterator);
+		});
+		ast_cli(a->fd, "Jabber Debugging Enabled.\n");
+		return CLI_SUCCESS;
+	} else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
+		ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			iterator->debug = 0;
+			ASTOBJ_UNLOCK(iterator);
+		});
+		ast_cli(a->fd, "Jabber Debugging Disabled.\n");
+		return CLI_SUCCESS;
+	}
+	return CLI_SHOWUSAGE; /* defaults to invalid */
+}
+
+/*!
+ * \internal
+ * \brief Reload jabber module.
+ * \return CLI_SUCCESS.
+ */
+static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jabber reload";
+		e->usage =
+			"Usage: jabber reload\n"
+			"       Reloads the Jabber module.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	aji_reload(1);
+	ast_cli(a->fd, "Jabber Reloaded.\n");
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \internal
+ * \brief Show client status.
+ * \return CLI_SUCCESS.
+ */
+static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	char *status;
+	int count = 0;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jabber show connections";
+		e->usage =
+			"Usage: jabber show connections\n"
+			"       Shows state of client and component connections\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_cli(a->fd, "Jabber Users and their status:\n");
+	ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		count++;
+		switch (iterator->state) {
+		case AJI_DISCONNECTED:
+			status = "Disconnected";
+			break;
+		case AJI_CONNECTING:
+			status = "Connecting";
+			break;
+		case AJI_CONNECTED:
+			status = "Connected";
+			break;
+		default:
+			status = "Unknown";
+		}
+		ast_cli(a->fd, "       [%s] %s     - %s\n", iterator->name, iterator->user, status);
+		ASTOBJ_UNLOCK(iterator);
+	});
+	ast_cli(a->fd, "----\n");
+	ast_cli(a->fd, "   Number of users: %d\n", count);
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \internal
+ * \brief Show buddy lists
+ * \return CLI_SUCCESS.
+ */
+static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct aji_resource *resource;
+	struct aji_client *client;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "jabber show buddies";
+		e->usage =
+			"Usage: jabber show buddies\n"
+			"       Shows buddy lists of our clients\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_cli(a->fd, "Jabber buddy lists\n");
+	ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+		ast_cli(a->fd, "Client: %s\n", iterator->user);
+		client = iterator;
+		ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
+			ASTOBJ_RDLOCK(iterator);
+			ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
+			if (!iterator->resources)
+				ast_cli(a->fd, "\t\tResource: None\n");
+			for (resource = iterator->resources; resource; resource = resource->next) {
+				ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
+				if (resource->cap) {
+					ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
+					ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
+					ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
+				}
+				ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
+				ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
+			}
+			ASTOBJ_UNLOCK(iterator);
+		});
+		iterator = client;
+	});
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \internal
+ * \brief creates aji_client structure.
+ * \param label
+ * \param var ast_variable
+ * \param debug
+ * \return 0.
+ */
+static int aji_create_client(char *label, struct ast_variable *var, int debug)
+{
+	char *resource;
+	struct aji_client *client = NULL;
+	int flag = 0;
+
+	client = ASTOBJ_CONTAINER_FIND(&clients, label);
+	if (!client) {
+		flag = 1;
+		client = ast_calloc(1, sizeof(*client));
+		if (!client) {
+			ast_log(LOG_ERROR, "Out of memory!\n");
+			return 0;
+		}
+		ASTOBJ_INIT(client);
+		ASTOBJ_WRLOCK(client);
+		ASTOBJ_CONTAINER_INIT(&client->buddies);
+	} else {
+		ASTOBJ_WRLOCK(client);
+		ASTOBJ_UNMARK(client);
+	}
+	ASTOBJ_CONTAINER_MARKALL(&client->buddies);
+	ast_copy_string(client->name, label, sizeof(client->name));
+	ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
+	ast_copy_string(client->context, "default", sizeof(client->context));
+
+	/* Set default values for the client object */
+	client->debug = debug;
+	ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
+	client->port = 5222;
+	client->usetls = 1;
+	client->usesasl = 1;
+	client->forcessl = 0;
+	client->keepalive = 1;
+	client->timeout = 50;
+	client->message_timeout = 5;
+	client->distribute_events = 0;
+	AST_LIST_HEAD_INIT(&client->messages);
+	client->component = 0;
+	ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
+	client->priority = 0;
+	client->status = IKS_SHOW_AVAILABLE;
+	client->send_to_dialplan = 0;
+
+	if (flag) {
+		client->authorized = 0;
+		client->state = AJI_DISCONNECTED;
+	}
+	while (var) {
+		if (!strcasecmp(var->name, "username")) {
+			ast_copy_string(client->user, var->value, sizeof(client->user));
+		} else if (!strcasecmp(var->name, "serverhost")) {
+			ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
+		} else if (!strcasecmp(var->name, "secret")) {
+			ast_copy_string(client->password, var->value, sizeof(client->password));
+		} else if (!strcasecmp(var->name, "statusmessage")) {
+			ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
+		} else if (!strcasecmp(var->name, "port")) {
+			client->port = atoi(var->value);
+		} else if (!strcasecmp(var->name, "timeout")) {
+			client->message_timeout = atoi(var->value);
+		} else if (!strcasecmp(var->name, "debug")) {
+			client->debug = (ast_false(var->value)) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "type")) {
+			if (!strcasecmp(var->value, "component")) {
+				client->component = 1;
+				if (client->distribute_events) {
+					ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
+					client->distribute_events = 0;
+				}
+			}
+		} else if (!strcasecmp(var->name, "distribute_events")) {
+			if (ast_true(var->value)) {
+				if (client->component) {
+					ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
+				} else {
+					if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
+						ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
+					} else {
+						ast_set_flag(&pubsubflags, AJI_PUBSUB);
+						client->distribute_events = 1;
+					}
+				}
+			}
+		} else if (!strcasecmp(var->name, "pubsub_node")) {
+			ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
+		} else if (!strcasecmp(var->name, "usetls")) {
+			client->usetls = (ast_false(var->value)) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "usesasl")) {
+			client->usesasl = (ast_false(var->value)) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "forceoldssl")) {
+			client->forcessl = (ast_false(var->value)) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "keepalive")) {
+			client->keepalive = (ast_false(var->value)) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "autoprune")) {
+			ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
+		} else if (!strcasecmp(var->name, "autoregister")) {
+			ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
+		} else if (!strcasecmp(var->name, "auth_policy")) {
+			if (!strcasecmp(var->value, "accept")) {
+				ast_set_flag(&client->flags, AJI_AUTOACCEPT);
+			} else {
+				ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
+			}
+		} else if (!strcasecmp(var->name, "buddy")) {
+			aji_create_buddy((char *)var->value, client);
+		} else if (!strcasecmp(var->name, "priority")) {
+			client->priority = atoi(var->value);
+		} else if (!strcasecmp(var->name, "status")) {
+			if (!strcasecmp(var->value, "unavailable")) {
+				client->status = IKS_SHOW_UNAVAILABLE;
+			} else if (!strcasecmp(var->value, "available")
+			 || !strcasecmp(var->value, "online")) {
+				client->status = IKS_SHOW_AVAILABLE;
+			} else if (!strcasecmp(var->value, "chat")
+			 || !strcasecmp(var->value, "chatty")) {
+				client->status = IKS_SHOW_CHAT;
+			} else if (!strcasecmp(var->value, "away")) {
+				client->status = IKS_SHOW_AWAY;
+			} else if (!strcasecmp(var->value, "xa")
+			 || !strcasecmp(var->value, "xaway")) {
+				client->status = IKS_SHOW_XA;
+			} else if (!strcasecmp(var->value, "dnd")) {
+				client->status = IKS_SHOW_DND;
+			} else if (!strcasecmp(var->value, "invisible")) {
+			#ifdef IKS_SHOW_INVISIBLE
+				client->status = IKS_SHOW_INVISIBLE;
+			#else
+				ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
+				client->status = IKS_SHOW_DND;
+			#endif
+			} else {
+				ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
+			}
+		} else if (!strcasecmp(var->name, "context")) {
+			ast_copy_string(client->context, var->value, sizeof(client->context));
+		} else if (!strcasecmp(var->name, "sendtodialplan")) {
+			client->send_to_dialplan = ast_true(var->value) ? 1 : 0;
+		}
+	/* no transport support in this version */
+	/*	else if (!strcasecmp(var->name, "transport"))
+				aji_create_transport(var->value, client);
+	*/
+		var = var->next;
+	}
+	if (!flag) {
+		ASTOBJ_UNLOCK(client);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
+		return 1;
+	}
+
+	ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
+	client->p = iks_stream_new(client->name_space, client, aji_act_hook);
+	if (!client->p) {
+		ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
+		return 0;
+	}
+	client->stack = iks_stack_new(8192, 8192);
+	if (!client->stack) {
+		ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
+		return 0;
+	}
+	client->f = iks_filter_new();
+	if (!client->f) {
+		ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
+		return 0;
+	}
+	if (!strchr(client->user, '/') && !client->component) { /*client */
+		if (ast_asprintf(&resource, "%s/asterisk", client->user) >= 0) {
+			client->jid = iks_id_new(client->stack, resource);
+			ast_free(resource);
+		}
+	} else {
+		client->jid = iks_id_new(client->stack, client->user);
+	}
+	if (client->component) {
+		iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
+		iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
+		iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
+		iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
+	} else {
+		iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
+	}
+
+	iks_set_log_hook(client->p, aji_log_hook);
+	ASTOBJ_UNLOCK(client);
+	ASTOBJ_CONTAINER_LINK(&clients, client);
+	return 1;
+}
+
+
+
+#if 0
+/*!
+ * \brief creates transport.
+ * \param label, buddy to dump it into. 
+ * \return 0.
+ */
+/* no connecting to transports today */
+static int aji_create_transport(char *label, struct aji_client *client)
+{
+	char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
+	struct aji_buddy *buddy = NULL;
+	int needs_unref = 1;
+
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
+	if (!buddy) {
+		needs_unref = 0;
+		buddy = ast_calloc(1, sizeof(*buddy));
+		if (!buddy) {
+			ast_log(LOG_WARNING, "Out of memory\n");
+			return 0;
+		}
+		ASTOBJ_INIT(buddy);
+	}
+	ASTOBJ_WRLOCK(buddy);
+	server = label;
+	if ((buddyname = strchr(label, ','))) {
+		*buddyname = '\0';
+		buddyname++;
+		if (buddyname && buddyname[0] != '\0') {
+			if ((user = strchr(buddyname, ','))) {
+				*user = '\0';
+				user++;
+				if (user && user[0] != '\0') {
+					if ((pass = strchr(user, ','))) {
+						*pass = '\0';
+						pass++;
+						ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
+						ast_copy_string(buddy->user, user, sizeof(buddy->user));
+						ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
+						ast_copy_string(buddy->server, server, sizeof(buddy->server));
+						if (needs_unref) {
+							ASTOBJ_UNMARK(buddy);
+							ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+						}
+						return 1;
+					}
+				}
+			}
+		}
+	}
+	ASTOBJ_UNLOCK(buddy);
+	if (needs_unref) {
+		ASTOBJ_UNMARK(buddy);
+		ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	} else {
+		ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
+	}
+	return 0;
+}
+#endif
+
+/*!
+ * \internal
+ * \brief creates buddy.
+ * \param label char.
+ * \param client the configured XMPP client we use to connect to a XMPP server 
+ * \return 1 on success, 0 on failure.
+ */
+static int aji_create_buddy(char *label, struct aji_client *client)
+{
+	struct aji_buddy *buddy = NULL;
+	int needs_unref = 1;
+	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, label);
+	if (!buddy) {
+		needs_unref = 0;
+		buddy = ast_calloc(1, sizeof(*buddy));
+		if (!buddy) {
+			ast_log(LOG_WARNING, "Out of memory\n");
+			return 0;
+		}
+		ASTOBJ_INIT(buddy);
+	}
+	ASTOBJ_WRLOCK(buddy);
+	ast_copy_string(buddy->name, label, sizeof(buddy->name));
+	ASTOBJ_UNLOCK(buddy);
+	if (needs_unref) {
+		ASTOBJ_UNMARK(buddy);
+		ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	} else {
+		ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
+	}
+	return 1;
+}
+
+/*!< load config file. \return 1. */
+static int aji_load_config(int reload)
+{
+	char *cat = NULL;
+	int debug = 0;
+	struct ast_config *cfg = NULL;
+	struct ast_variable *var = NULL;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+	if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
+		return -1;
+	}
+
+	/* Reset flags to default value */
+	ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
+
+	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
+		return 0;
+	}
+
+	cat = ast_category_browse(cfg, NULL);
+	for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+		if (!strcasecmp(var->name, "debug")) {
+			debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
+		} else if (!strcasecmp(var->name, "autoprune")) {
+			ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
+		} else if (!strcasecmp(var->name, "autoregister")) {
+			ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
+		} else if (!strcasecmp(var->name, "collection_nodes")) {
+			ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
+		} else if (!strcasecmp(var->name, "pubsub_autocreate")) {
+			ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
+		} else if (!strcasecmp(var->name, "auth_policy")) {
+			if (!strcasecmp(var->value, "accept")) {
+				ast_set_flag(&globalflags, AJI_AUTOACCEPT);
+			} else {
+				ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
+			}
+		}
+	}
+
+	while (cat) {
+		if (strcasecmp(cat, "general")) {
+			var = ast_variable_browse(cfg, cat);
+			aji_create_client(cat, var, debug);
+		}
+		cat = ast_category_browse(cfg, cat);
+	}
+	ast_config_destroy(cfg); /* or leak memory */
+	return 1;
+}
+
+/*!
+ * \brief grab a aji_client structure by label name or JID. Bumps the refcount.
+ * (without the resource string)
+ * \param name label or JID
+ * \return aji_client.
+ */
+struct aji_client *ast_aji_get_client(const char *name)
+{
+	struct aji_client *client = NULL;
+	char *aux = NULL;
+
+	client = ASTOBJ_CONTAINER_FIND(&clients, name);
+	if (!client && strchr(name, '@')) {
+		ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+			aux = ast_strdupa(iterator->user);
+			if (strchr(aux, '/')) {
+				/* strip resource for comparison */
+				aux = strsep(&aux, "/");
+			}
+			if (!strncasecmp(aux, name, strlen(aux))) {
+				client = ASTOBJ_REF(iterator);
+			}
+		});
+	}
+
+	return client;
+}
+
+struct aji_client_container *ast_aji_get_clients(void)
+{
+	return &clients;
+}
+
+/*!
+ * \internal
+ * \brief  Send a Jabber Message via call from the Manager
+ * \param s mansession Manager session
+ * \param m message Message to send
+ * \return  0
+*/
+static int manager_jabber_send(struct mansession *s, const struct message *m)
+{
+	struct aji_client *client = NULL;
+	const char *id = astman_get_header(m, "ActionID");
+	const char *jabber = astman_get_header(m, "Jabber");
+	const char *screenname = astman_get_header(m, "ScreenName");
+	const char *message = astman_get_header(m, "Message");
+
+	if (ast_strlen_zero(jabber)) {
+		astman_send_error(s, m, "No transport specified");
+		return 0;
+	}
+	if (ast_strlen_zero(screenname)) {
+		astman_send_error(s, m, "No ScreenName specified");
+		return 0;
+	}
+	if (ast_strlen_zero(message)) {
+		astman_send_error(s, m, "No Message specified");
+		return 0;
+	}
+
+	astman_send_ack(s, m, "Attempting to send Jabber Message");
+	client = ast_aji_get_client(jabber);
+	if (!client) {
+		astman_send_error(s, m, "Could not find Sender");
+		return 0;
+	}
+	if (strchr(screenname, '@') && message) {
+		ast_aji_send_chat(client, screenname, message);
+		astman_append(s, "Response: Success\r\n");
+	} else {
+		astman_append(s, "Response: Error\r\n");
+	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
+	if (!ast_strlen_zero(id)) {
+		astman_append(s, "ActionID: %s\r\n", id);
+	}
+	astman_append(s, "\r\n");
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Reload the jabber module
+ */
+static int aji_reload(int reload)
+{
+	int res;
+
+	ASTOBJ_CONTAINER_MARKALL(&clients);
+	if (!(res = aji_load_config(reload))) {
+		ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
+		return 0;
+	} else if (res == -1)
+		return 1;
+
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
+	ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		if (iterator->state == AJI_DISCONNECTED) {
+			if (!iterator->thread)
+				ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
+		} else if (iterator->state == AJI_CONNECTING) {
+			aji_get_roster(iterator);
+			if (iterator->distribute_events) {
+				aji_init_event_distribution(iterator);
+			}
+		}
+
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+	return 1;
+}
+
+/*!
+ * \internal
+ * \brief Unload the jabber module
+ */
+static int unload_module(void)
+{
+	ast_msg_tech_unregister(&msg_tech);
+	ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
+	ast_unregister_application(app_ajisend);
+	ast_unregister_application(app_ajisendgroup);
+	ast_unregister_application(app_ajistatus);
+	ast_unregister_application(app_ajijoin);
+	ast_unregister_application(app_ajileave);
+	ast_manager_unregister("JabberSend");
+	ast_custom_function_unregister(&jabberstatus_function);
+	if (mwi_sub) {
+		ast_event_unsubscribe(mwi_sub);
+	}
+	if (device_state_sub) {
+		ast_event_unsubscribe(device_state_sub);
+	}
+	ast_custom_function_unregister(&jabberreceive_function);
+
+	ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+		ASTOBJ_WRLOCK(iterator);
+		ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
+		iterator->state = AJI_DISCONNECTING;
+		ASTOBJ_UNLOCK(iterator);
+		pthread_join(iterator->thread, NULL);
+		ast_aji_disconnect(iterator);
+	});
+
+	ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&clients);
+
+	ast_cond_destroy(&message_received_condition);
+	ast_mutex_destroy(&messagelock);
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Unload the jabber module
+ */
+static int load_module(void)
+{
+	ASTOBJ_CONTAINER_INIT(&clients);
+	if (!aji_reload(0))
+		return AST_MODULE_LOAD_DECLINE;
+	ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
+	ast_register_application_xml(app_ajisend, aji_send_exec);
+	ast_register_application_xml(app_ajisendgroup, aji_sendgroup_exec);
+	ast_register_application_xml(app_ajistatus, aji_status_exec);
+	ast_register_application_xml(app_ajijoin, aji_join_exec);
+	ast_register_application_xml(app_ajileave, aji_leave_exec);
+	ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
+	ast_custom_function_register(&jabberstatus_function);
+	ast_custom_function_register(&jabberreceive_function);
+	ast_msg_tech_register(&msg_tech);
+
+	ast_mutex_init(&messagelock);
+	ast_cond_init(&message_received_condition, NULL);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Wrapper for aji_reload
+ */
+static int reload(void)
+{
+	aji_reload(1);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "AJI - Asterisk Jabber Interface",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
+	       );
diff --git a/res/res_limit.c b/res/res_limit.c
index d3f7445..dc07a4c 100644
--- a/res/res_limit.c
+++ b/res/res_limit.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Resource limits
  * 
@@ -24,7 +24,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 375003 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <sys/time.h>
diff --git a/res/res_manager_devicestate.c b/res/res_manager_devicestate.c
deleted file mode 100644
index 25eae87..0000000
--- a/res/res_manager_devicestate.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<manager name="DeviceStateList" language="en_US">
-		<synopsis>
-			List the current known device states.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>This will list out all known device states in a
-			sequence of <replaceable>DeviceStateChange</replaceable> events.
-			When finished, a <replaceable>DeviceStateListComplete</replaceable> event
-			will be emitted.</para>
-		</description>
-		<see-also>
-			<ref type="managerEvent">DeviceStateChange</ref>
-			<ref type="function">DEVICE_STATE</ref>
-		</see-also>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='DeviceStateChange'])" />
-			</list-elements>
-			<managerEvent name="DeviceStateListComplete" language="en_US">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>
-						Indicates the end of the list the current known extension states.
-					</synopsis>
-					<syntax>
-						<parameter name="EventList">
-							<para>Conveys the status of the event list.</para>
-						</parameter>
-						<parameter name="ListItems">
-							<para>Conveys the number of statuses reported.</para>
-						</parameter>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
- ***/
-
-
-#include "asterisk.h"
-#include "asterisk/module.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis.h"
-#include "asterisk/devicestate.h"
-
-static struct stasis_forward *topic_forwarder;
-
-static int action_devicestatelist(struct mansession *s, const struct message *m)
-{
-	RAII_VAR(struct ao2_container *, device_states, NULL, ao2_cleanup);
-	const char *action_id = astman_get_header(m, "ActionID");
-	struct stasis_message *msg;
-	struct ao2_iterator it_states;
-	int count = 0;
-
-	device_states = stasis_cache_dump_by_eid(ast_device_state_cache(),
-		ast_device_state_message_type(), NULL);
-	if (!device_states) {
-		astman_send_error(s, m, "Memory Allocation Failure");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "Device State Changes will follow", "start");
-
-	it_states = ao2_iterator_init(device_states, 0);
-	for (; (msg = ao2_iterator_next(&it_states)); ao2_ref(msg, -1)) {
-		struct ast_manager_event_blob *blob = stasis_message_to_ami(msg);
-
-		if (!blob) {
-			continue;
-		}
-
-		count++;
-
-		astman_append(s, "Event: %s\r\n", blob->manager_event);
-		if (!ast_strlen_zero(action_id)) {
-			astman_append(s, "ActionID: %s\r\n", action_id);
-		}
-		astman_append(s, "%s\r\n", blob->extra_fields);
-		ao2_ref(blob, -1);
-	}
-	ao2_iterator_destroy(&it_states);
-
-	astman_append(s, "Event: DeviceStateListComplete\r\n");
-	if (!ast_strlen_zero(action_id)) {
-		astman_append(s, "ActionID: %s\r\n", action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		"ListItems: %d\r\n\r\n", count);
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	topic_forwarder = stasis_forward_cancel(topic_forwarder);
-	ast_manager_unregister("DeviceStateList");
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	struct stasis_topic *manager_topic;
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	topic_forwarder = stasis_forward_all(ast_device_state_topic_all(), manager_topic);
-	if (!topic_forwarder) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_manager_register_xml("DeviceStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING,
-		                         action_devicestatelist)) {
-		topic_forwarder = stasis_forward_cancel(topic_forwarder);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Manager Device State Topic Forwarder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
-	);
diff --git a/res/res_manager_presencestate.c b/res/res_manager_presencestate.c
deleted file mode 100644
index e2cfca5..0000000
--- a/res/res_manager_presencestate.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<manager name="PresenceStateList" language="en_US">
-		<synopsis>
-			List the current known presence states.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-		</syntax>
-		<description>
-			<para>This will list out all known presence states in a
-			sequence of <replaceable>PresenceStateChange</replaceable> events.
-			When finished, a <replaceable>PresenceStateListComplete</replaceable> event
-			will be emitted.</para>
-		</description>
-		<see-also>
-			<ref type="manager">PresenceState</ref>
-			<ref type="managerEvent">PresenceStatus</ref>
-			<ref type="function">PRESENCE_STATE</ref>
-		</see-also>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='PresenceStateChange'])" />
-			</list-elements>
-			<managerEvent name="PresenceStateListComplete" language="en_US">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>
-						Indicates the end of the list the current known extension states.
-					</synopsis>
-					<syntax>
-						<parameter name="EventList">
-							<para>Conveys the status of the event list.</para>
-						</parameter>
-						<parameter name="ListItems">
-							<para>Conveys the number of statuses reported.</para>
-						</parameter>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
- ***/
-
-#include "asterisk.h"
-#include "asterisk/module.h"
-#include "asterisk/manager.h"
-#include "asterisk/stasis.h"
-#include "asterisk/presencestate.h"
-
-static struct stasis_forward *topic_forwarder;
-
-static int action_presencestatelist(struct mansession *s, const struct message *m)
-{
-	RAII_VAR(struct ao2_container *, presence_states, NULL, ao2_cleanup);
-	const char *action_id = astman_get_header(m, "ActionID");
-	struct stasis_message *msg;
-	struct ao2_iterator it_states;
-	int count = 0;
-
-	presence_states = stasis_cache_dump(ast_presence_state_cache(),
-		ast_presence_state_message_type());
-	if (!presence_states) {
-		astman_send_error(s, m, "Memory Allocation Failure");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "Presence State Changes will follow", "start");
-
-	it_states = ao2_iterator_init(presence_states, 0);
-	for (; (msg = ao2_iterator_next(&it_states)); ao2_ref(msg, -1)) {
-		struct ast_manager_event_blob *blob = stasis_message_to_ami(msg);
-
-		if (!blob) {
-			continue;
-		}
-
-		count++;
-
-		astman_append(s, "Event: %s\r\n", blob->manager_event);
-		if (!ast_strlen_zero(action_id)) {
-			astman_append(s, "ActionID: %s\r\n", action_id);
-		}
-		astman_append(s, "%s\r\n", blob->extra_fields);
-		ao2_ref(blob, -1);
-	}
-	ao2_iterator_destroy(&it_states);
-
-	astman_append(s, "Event: PresenceStateListComplete\r\n");
-	if (!ast_strlen_zero(action_id)) {
-		astman_append(s, "ActionID: %s\r\n", action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		"ListItems: %d\r\n\r\n", count);
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_manager_unregister("PresenceStateList");
-	topic_forwarder = stasis_forward_cancel(topic_forwarder);
-	return 0;
-}
-
-static int load_module(void)
-{
-	struct stasis_topic *manager_topic;
-
-	manager_topic = ast_manager_get_topic();
-	if (!manager_topic) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	topic_forwarder = stasis_forward_all(ast_presence_state_topic_all(), manager_topic);
-	if (!topic_forwarder) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_manager_register_xml("PresenceStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING,
-		                         action_presencestatelist)) {
-		topic_forwarder = stasis_forward_cancel(topic_forwarder);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Manager Presence State Topic Forwarder",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
-	);
diff --git a/res/res_monitor.c b/res/res_monitor.c
index 98c17f9..76c43e1 100644
--- a/res/res_monitor.c
+++ b/res/res_monitor.c
@@ -29,7 +29,7 @@
  
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429033 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 #include <libgen.h>
@@ -40,18 +40,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429033 $")
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
-#include "asterisk/cli.h"
 #include "asterisk/manager.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
+#include "asterisk/cli.h"
 #define AST_API_MODULE
 #include "asterisk/monitor.h"
-#undef AST_API_MODULE
 #include "asterisk/app.h"
 #include "asterisk/utils.h"
 #include "asterisk/config.h"
 #include "asterisk/options.h"
-#include "asterisk/beep.h"
 
 /*** DOCUMENTATION
 	<application name="Monitor" language="en_US">
@@ -86,10 +82,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429033 $")
 					<option name="b">
 						<para>Don't begin recording unless a call is bridged to another channel.</para>
 					</option>
-					<option name="B">
-						<para>Play a periodic beep while this call is being recorded.</para>
-						<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
-					</option>
 					<option name="i">
 						<para>Skip recording of input stream (disables <literal>m</literal> option).</para>
 					</option>
@@ -296,11 +288,9 @@ static int ast_monitor_set_state(struct ast_channel *chan, int state)
  * \retval -1 on failure
  */
 int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
-					     const char *fname_base, int need_lock, int stream_action,
-					     const char *beep_id)
+					     const char *fname_base, int need_lock, int stream_action)
 {
 	int res = 0;
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
 
 	LOCK_IF_NEEDED(chan, need_lock);
 
@@ -316,10 +306,6 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha
 			return -1;
 		}
 
-		if (!ast_strlen_zero(beep_id)) {
-			ast_copy_string(monitor->beep_id, beep_id, sizeof(monitor->beep_id));
-		}
-
 		/* Determine file names */
 		if (!ast_strlen_zero(fname_base)) {
 			int directory = strchr(fname_base, '/') ? 1 : 0;
@@ -409,12 +395,11 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha
 		/* so we know this call has been monitored in case we need to bill for it or something */
 		pbx_builtin_setvar_helper(chan, "__MONITORED","true");
 
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
-				ast_channel_monitor_start_type(),
-				NULL);
-		if (message) {
-			stasis_publish(ast_channel_topic(chan), message);
-		}
+		ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
+			                "Channel: %s\r\n"
+					        "Uniqueid: %s\r\n",
+	                        ast_channel_name(chan),
+			                ast_channel_uniqueid(chan));
 	} else {
 		ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
 		res = -1;
@@ -454,7 +439,6 @@ static const char *get_soxmix_format(const char *format)
 int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
 {
 	int delfiles = 0;
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
 
 	LOCK_IF_NEEDED(chan, need_lock);
 
@@ -469,24 +453,28 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l
 		}
 
 		if (ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
-			if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) {
-				snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base);
-				if (ast_fileexists(filename, NULL, NULL) > 0) {
-					ast_filedelete(filename, NULL);
+			if (ast_channel_monitor(chan)->read_stream) {
+				if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) {
+					snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base);
+					if (ast_fileexists(filename, NULL, NULL) > 0) {
+						ast_filedelete(filename, NULL);
+					}
+					ast_filerename(ast_channel_monitor(chan)->read_filename, filename, ast_channel_monitor(chan)->format);
+				} else {
+					ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename);
 				}
-				ast_filerename(ast_channel_monitor(chan)->read_filename, filename, ast_channel_monitor(chan)->format);
-			} else {
-				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename);
 			}
 
-			if (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
-				snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base);
-				if (ast_fileexists(filename, NULL, NULL) > 0) {
-					ast_filedelete(filename, NULL);
+			if (ast_channel_monitor(chan)->write_stream) {
+				if (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
+					snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base);
+					if (ast_fileexists(filename, NULL, NULL) > 0) {
+						ast_filedelete(filename, NULL);
+					}
+					ast_filerename(ast_channel_monitor(chan)->write_filename, filename, ast_channel_monitor(chan)->format);
+				} else {
+					ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename);
 				}
-				ast_filerename(ast_channel_monitor(chan)->write_filename, filename, ast_channel_monitor(chan)->format);
-			} else {
-				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename);
 			}
 		}
 
@@ -524,21 +512,17 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l
 			if (ast_safe_system(tmp) == -1)
 				ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
 		}
-
-		if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
-			ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
-		}
-
+		
 		ast_free(ast_channel_monitor(chan)->format);
 		ast_free(ast_channel_monitor(chan));
 		ast_channel_monitor_set(chan, NULL);
 
-		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
-				ast_channel_monitor_stop_type(),
-				NULL);
-		if (message) {
-			stasis_publish(ast_channel_topic(chan), message);
-		}
+		ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop",
+			                "Channel: %s\r\n"
+	                        "Uniqueid: %s\r\n",
+	                        ast_channel_name(chan),
+	                        ast_channel_uniqueid(chan)
+	                        );
 		pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
 	}
 	pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
@@ -656,27 +640,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, co
 	return 0;
 }
 
-enum {
-	MON_FLAG_BRIDGED =  (1 << 0),
-	MON_FLAG_MIX =      (1 << 1),
-	MON_FLAG_DROP_IN =  (1 << 2),
-	MON_FLAG_DROP_OUT = (1 << 3),
-	MON_FLAG_BEEP =     (1 << 4),
-};
-
-enum {
-	OPT_ARG_BEEP_INTERVAL,
-	OPT_ARG_ARRAY_SIZE,	/* Always last element of the enum */
-};
-
-AST_APP_OPTIONS(monitor_opts, {
-	AST_APP_OPTION('b', MON_FLAG_BRIDGED),
-	AST_APP_OPTION('m', MON_FLAG_MIX),
-	AST_APP_OPTION('i', MON_FLAG_DROP_IN),
-	AST_APP_OPTION('o', MON_FLAG_DROP_OUT),
-	AST_APP_OPTION_ARG('B', MON_FLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
-});
-
+ 
 /*!
  * \brief Start monitor
  * \param chan
@@ -693,11 +657,9 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
 	char tmp[256];
 	int stream_action = X_REC_IN | X_REC_OUT;
 	int joinfiles = 0;
+	int waitforbridge = 0;
 	int res = 0;
 	char *parse;
-	struct ast_flags flags = { 0 };
-	char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
-	char beep_id[64] = "";
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(format);
 		AST_APP_ARG(fname_base);
@@ -714,31 +676,14 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (!ast_strlen_zero(args.options)) {
-		ast_app_parse_options(monitor_opts, &flags, opts, args.options);
-
-		if (ast_test_flag(&flags, MON_FLAG_MIX)) {
+		if (strchr(args.options, 'm'))
 			stream_action |= X_JOIN;
-		}
-		if (ast_test_flag(&flags, MON_FLAG_DROP_IN)) {
+		if (strchr(args.options, 'b'))
+			waitforbridge = 1;
+		if (strchr(args.options, 'i'))
 			stream_action &= ~X_REC_IN;
-		}
-		if (ast_test_flag(&flags, MON_FLAG_DROP_OUT)) {
+		if (strchr(args.options, 'o'))
 			stream_action &= ~X_REC_OUT;
-		}
-		if (ast_test_flag(&flags, MON_FLAG_BEEP)) {
-			const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
-			unsigned int interval = 15;
-
-			if (sscanf(interval_str, "%30u", &interval) != 1) {
-				ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
-						interval_str, interval);
-			}
-
-			if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
-				ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
-				return -1;
-			}
-		}
 	}
 
 	arg = strchr(args.format, ':');
@@ -748,13 +693,21 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
 	}
 
 	if (!ast_strlen_zero(urlprefix) && !ast_strlen_zero(args.fname_base)) {
+		struct ast_cdr *chan_cdr;
 		snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
 			((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
 		ast_channel_lock(chan);
-		ast_cdr_setuserfield(ast_channel_name(chan), tmp);
+		if (!ast_channel_cdr(chan)) {
+			if (!(chan_cdr = ast_cdr_alloc())) {
+				ast_channel_unlock(chan);
+				return -1;
+			}
+			ast_channel_cdr_set(chan, chan_cdr);
+		}
+		ast_cdr_setuserfield(chan, tmp);
 		ast_channel_unlock(chan);
 	}
-	if (ast_test_flag(&flags, MON_FLAG_BRIDGED)) {
+	if (waitforbridge) {
 		/* We must remove the "b" option if listed.  In principle none of
 		   the following could give NULL results, but we check just to
 		   be pedantic. Reconstructing with checks for 'm' option does not
@@ -771,7 +724,7 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
 		return 0;
 	}
 
-	res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action, beep_id);
+	res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action);
 	if (res < 0)
 		res = ast_monitor_change_fname(chan, args.fname_base, 1);
 
@@ -830,7 +783,7 @@ static int start_monitor_action(struct mansession *s, const struct message *m)
 		}
 	}
 
-	if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT, NULL)) {
+	if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
 		if (ast_monitor_change_fname(c, fname, 1)) {
 			astman_send_error(s, m, "Could not start monitoring channel");
 			c = ast_channel_unref(c);
@@ -1001,7 +954,6 @@ static int unload_module(void)
 
 /* usecount semantics need to be defined */
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Call Monitoring Resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index d0c1b2d..9172473 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -19,19 +19,12 @@
 /*! \file
  *
  * \brief Routines implementing music on hold
+ *
+ * \arg See also \ref Config_moh
  * 
  * \author Mark Spencer <markster at digium.com>
  */
 
-/*! \li \ref res_musiconhold.c uses the configuration file \ref musiconhold.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page musiconhold.conf musiconhold.conf
- * \verbinclude musiconhold.conf.sample
- */
-
 /*** MODULEINFO
 	<conflict>win32</conflict>
 	<support_level>core</support_level>
@@ -39,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422037 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <signal.h>
@@ -67,8 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422037 $")
 #include "asterisk/cli.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_channels.h"
+#include "asterisk/manager.h"
 #include "asterisk/paths.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/timing.h"
@@ -98,6 +90,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422037 $")
 			an application such as Answer() or Progress().</para>
 		</description>
 	</application>
+	<application name="WaitMusicOnHold" language="en_US">
+		<synopsis>
+			Wait, playing Music On Hold.
+		</synopsis>
+		<syntax>
+			<parameter name="delay" required="true" />
+		</syntax>
+		<description>
+			<para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
+			<para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
+			or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
+			with no sound.</para>
+			<para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
+		</description>
+	</application>
+	<application name="SetMusicOnHold" language="en_US">
+		<synopsis>
+			Set default Music On Hold class.
+		</synopsis>
+		<syntax>
+			<parameter name="class" required="yes" />
+		</syntax>
+		<description>
+			<para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
+			<para>Sets the default class for music on hold for a given channel.
+			When music on hold is activated, this class will be used to select which
+			music is played.</para>
+			<para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
+		</description>
+	</application>
 	<application name="StartMusicOnHold" language="en_US">
 		<synopsis>
 			Play Music On Hold.
@@ -123,6 +145,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422037 $")
  ***/
 
 static const char play_moh[] = "MusicOnHold";
+static const char wait_moh[] = "WaitMusicOnHold";
+static const char set_moh[] = "SetMusicOnHold";
 static const char start_moh[] = "StartMusicOnHold";
 static const char stop_moh[] = "StopMusicOnHold";
 
@@ -131,8 +155,8 @@ static int respawn_time = 20;
 struct moh_files_state {
 	/*! Holds a reference to the MOH class. */
 	struct mohclass *class;
-	struct ast_format *origwfmt;
-	struct ast_format *mohwfmt;
+	struct ast_format origwfmt;
+	struct ast_format mohwfmt;
 	int announcement;
 	int samples;
 	int sample_queue;
@@ -172,7 +196,7 @@ struct mohclass {
 	int total_files;
 	unsigned int flags;
 	/*! The format from the MOH source, not applicable to "files" mode */
-	struct ast_format *format;
+	struct ast_format format;
 	/*! The pid of the external application delivering MOH */
 	int pid;
 	time_t start;
@@ -190,7 +214,7 @@ struct mohclass {
 
 struct mohdata {
 	int pipe[2];
-	struct ast_format *origwfmt;
+	struct ast_format origwfmt;
 	struct mohclass *parent;
 	struct ast_frame f;
 	AST_LIST_ENTRY(mohdata) list;
@@ -228,48 +252,6 @@ static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag,
 }
 #endif
 
-static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
-{
-	struct stasis_message *message;
-	struct ast_json *json_object;
-
-	ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n",
-		moh_class_name, ast_channel_name(chan));
-
-	json_object = ast_json_pack("{s: s}", "class", moh_class_name);
-	if (!json_object) {
-		return;
-	}
-
-	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
-		ast_channel_moh_start_type(), json_object);
-	if (message) {
-		/* A channel snapshot must have been in the cache. */
-		ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
-
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	ao2_cleanup(message);
-	ast_json_unref(json_object);
-}
-
-static void moh_post_stop(struct ast_channel *chan)
-{
-	struct stasis_message *message;
-
-	ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
-
-	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
-		ast_channel_moh_stop_type(), NULL);
-	if (message) {
-		/* A channel snapshot must have been in the cache. */
-		ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
-
-		stasis_publish(ast_channel_topic(chan), message);
-	}
-	ao2_cleanup(message);
-}
-
 static void moh_files_release(struct ast_channel *chan, void *data)
 {
 	struct moh_files_state *state;
@@ -284,17 +266,13 @@ static void moh_files_release(struct ast_channel *chan, void *data)
 		ast_closestream(ast_channel_stream(chan));
 		ast_channel_stream_set(chan, NULL);
 	}
+	
+	ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
 
-	moh_post_stop(chan);
-
-	ao2_ref(state->mohwfmt, -1);
-	state->mohwfmt = NULL; /* make sure to clear this format before restoring the original format */
-	if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
-		ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan),
-			ast_format_get_name(state->origwfmt));
+	ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */
+	if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) {
+		ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt));
 	}
-	ao2_cleanup(state->origwfmt);
-	state->origwfmt = NULL;
 
 	state->save_pos = state->pos;
 	state->announcement = 0;
@@ -407,15 +385,15 @@ static void moh_files_write_format_change(struct ast_channel *chan, void *data)
 	/* In order to prevent a recursive call to this function as a result
 	 * of setting the moh write format back on the channel. Clear
 	 * the moh write format before setting the write format on the channel.*/
-	if (state->origwfmt) {
-		struct ast_format *tmp;
+	if (&state->origwfmt.id) {
+		struct ast_format tmp;
 
-		tmp = ao2_bump(ast_channel_writeformat(chan));
-		ao2_replace(state->origwfmt, NULL);
-		if (state->mohwfmt) {
-			ast_set_write_format(chan, state->mohwfmt);
+		ast_format_copy(&tmp, ast_channel_writeformat(chan));
+		if (state->mohwfmt.id) {
+			ast_format_clear(&state->origwfmt);
+			ast_set_write_format(chan, &state->mohwfmt);
 		}
-		state->origwfmt = tmp;
+		ast_format_copy(&state->origwfmt, &tmp);
 	}
 }
 
@@ -444,8 +422,8 @@ static int moh_files_generator(struct ast_channel *chan, void *data, int len, in
 
 		state->samples += f->samples;
 		state->sample_queue -= f->samples;
-		if (ast_format_cmp(f->subclass.format, state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
-			ao2_replace(state->mohwfmt, f->subclass.format);
+		if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
+			ast_format_copy(&state->mohwfmt, &f->subclass.format);
 		}
 		res = ast_write(chan, f);
 		ast_frfree(f);
@@ -462,11 +440,11 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
 	struct moh_files_state *state;
 	struct mohclass *class = params;
 
-	state = ast_channel_music_state(chan);
-	if (!state && (state = ast_calloc(1, sizeof(*state)))) {
+	if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
 		ast_channel_music_state_set(chan, state);
 		ast_module_ref(ast_module_info->self);
 	} else {
+		state = ast_channel_music_state(chan);
 		if (!state) {
 			return NULL;
 		}
@@ -479,8 +457,6 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
 	/* Resume MOH from where we left off last time or start from scratch? */
 	if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
 		/* Start MOH from scratch. */
-		ao2_cleanup(state->origwfmt);
-		ao2_cleanup(state->mohwfmt);
 		memset(state, 0, sizeof(*state));
 		if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
 			state->pos = ast_random() % class->total_files;
@@ -488,16 +464,16 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
 	}
 
 	state->class = mohclass_ref(class, "Reffing music class for channel");
-	/* it's possible state is not a new allocation, don't leak old refs */
-	ao2_replace(state->origwfmt, ast_channel_writeformat(chan));
-	ao2_replace(state->mohwfmt, ast_channel_writeformat(chan));
+	ast_format_copy(&state->origwfmt, ast_channel_writeformat(chan));
+	ast_format_copy(&state->mohwfmt, ast_channel_writeformat(chan));
 	/* For comparison on restart of MOH (see above) */
 	ast_copy_string(state->name, class->name, sizeof(state->name));
 	state->save_total = class->total_files;
 
-	moh_post_start(chan, class->name);
 
-	return state;
+	ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, ast_channel_name(chan));
+	
+	return ast_channel_music_state(chan);
 }
 
 static int moh_digit_match(void *obj, void *arg, int flags)
@@ -528,7 +504,8 @@ static void moh_handle_digit(struct ast_channel *chan, char digit)
 	}
 }
 
-static struct ast_generator moh_file_stream = {
+static struct ast_generator moh_file_stream = 
+{
 	.alloc    = moh_files_alloc,
 	.release  = moh_files_release,
 	.generate = moh_files_generator,
@@ -713,8 +690,7 @@ static void *monmp3thread(void *data)
 					ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
 					return NULL;
 				}
-				/* 25 samples per second => 40ms framerate => 320 samples */
-				res = 320; /* 320/40 = 8 samples/ms */
+				res = 320;
 			} else {
 				ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
 				res = 0;
@@ -735,16 +711,12 @@ static void *monmp3thread(void *data)
 				ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
 				deadline = tv_tmp;
 			}
-			/* 10 samples per second (MOH_MS_INTERVAL) => 100ms framerate => 800 samples */
-			res = 8 * MOH_MS_INTERVAL; /* 800/100 = 8 samples/ms */
+			res = 8 * MOH_MS_INTERVAL;	/* 8 samples per millisecond */
 		}
-		/* For non-8000Hz formats, we need to alter the resolution */
-		res = res * ast_format_get_sample_rate(class->format) / 8000;
-
 		if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
 			continue;
 		/* Read mp3 audio */
-		len = ast_format_determine_length(class->format, res);
+		len = ast_codec_get_len(&class->format, res);
 
 		if ((res2 = read(class->srcfd, sbuf, len)) != len) {
 			if (!res2) {
@@ -836,6 +808,46 @@ static int play_moh_exec(struct ast_channel *chan, const char *data)
 	return res;
 }
 
+static int wait_moh_exec(struct ast_channel *chan, const char *data)
+{
+	static int deprecation_warning = 0;
+	int res;
+
+	if (!deprecation_warning) {
+		deprecation_warning = 1;
+		ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
+	}
+
+	if (!data || !atoi(data)) {
+		ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
+		return -1;
+	}
+	if (ast_moh_start(chan, NULL, NULL)) {
+		ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan));
+		return 0;
+	}
+	res = ast_safe_sleep(chan, atoi(data) * 1000);
+	ast_moh_stop(chan);
+	return res;
+}
+
+static int set_moh_exec(struct ast_channel *chan, const char *data)
+{
+	static int deprecation_warning = 0;
+
+	if (!deprecation_warning) {
+		deprecation_warning = 1;
+		ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
+	}
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
+		return -1;
+	}
+	ast_channel_musicclass_set(chan, data);
+	return 0;
+}
+
 static int start_moh_exec(struct ast_channel *chan, const char *data)
 {
 	char *parse;
@@ -881,7 +893,7 @@ static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, co
 #endif
 
 	if (!moh && warn) {
-		ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
+		ast_log(LOG_WARNING, "Music on Hold class '%s' not found in memory. Verify your configuration.\n", name);
 	}
 
 	return moh;
@@ -908,7 +920,7 @@ static struct mohdata *mohalloc(struct mohclass *cl)
 	fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
 
 	moh->f.frametype = AST_FRAME_VOICE;
-	moh->f.subclass.format = cl->format;
+	ast_format_copy(&moh->f.subclass.format, &cl->format);
 	moh->f.offset = AST_FRIENDLY_OFFSET;
 
 	moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
@@ -924,7 +936,7 @@ static void moh_release(struct ast_channel *chan, void *data)
 {
 	struct mohdata *moh = data;
 	struct mohclass *class = moh->parent;
-	struct ast_format *oldwfmt;
+	struct ast_format oldwfmt;
 
 	ao2_lock(class);
 	AST_LIST_REMOVE(&moh->parent->members, moh, list);	
@@ -933,7 +945,7 @@ static void moh_release(struct ast_channel *chan, void *data)
 	close(moh->pipe[0]);
 	close(moh->pipe[1]);
 
-	oldwfmt = moh->origwfmt;
+	ast_format_copy(&oldwfmt, &moh->origwfmt);
 
 	moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
 
@@ -946,15 +958,13 @@ static void moh_release(struct ast_channel *chan, void *data)
 		if (state && state->class) {
 			state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
 		}
-		if (oldwfmt && ast_set_write_format(chan, oldwfmt)) {
+		if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) {
 			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
-					ast_channel_name(chan), ast_format_get_name(oldwfmt));
+					ast_channel_name(chan), ast_getformatname(&oldwfmt));
 		}
 
-		moh_post_stop(chan);
+		ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
 	}
-
-	ao2_cleanup(oldwfmt);
 }
 
 static void *moh_alloc(struct ast_channel *chan, void *params)
@@ -964,11 +974,11 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
 	struct moh_files_state *state;
 
 	/* Initiating music_state for current channel. Channel should know name of moh class */
-	state = ast_channel_music_state(chan);
-	if (!state && (state = ast_calloc(1, sizeof(*state)))) {
+	if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
 		ast_channel_music_state_set(chan, state);
 		ast_module_ref(ast_module_info->self);
 	} else {
+		state = ast_channel_music_state(chan);
 		if (!state) {
 			return NULL;
 		}
@@ -976,22 +986,19 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
 			mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
 			ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
 		}
-		ao2_cleanup(state->origwfmt);
-		ao2_cleanup(state->mohwfmt);
 		memset(state, 0, sizeof(*state));
 	}
 
 	if ((res = mohalloc(class))) {
-		res->origwfmt = ao2_bump(ast_channel_writeformat(chan));
-		if (ast_set_write_format(chan, class->format)) {
-			ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan),
-				ast_format_get_name(class->format));
+		ast_format_copy(&res->origwfmt, ast_channel_writeformat(chan));
+		if (ast_set_write_format(chan, &class->format)) {
+			ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format));
 			moh_release(NULL, res);
 			res = NULL;
 		} else {
 			state->class = mohclass_ref(class, "Placing reference into state container");
-			moh_post_start(chan, class->name);
 		}
+		ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, ast_channel_name(chan));
 	}
 	return res;
 }
@@ -1002,7 +1009,7 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
 	short buf[1280 + AST_FRIENDLY_OFFSET / 2];
 	int res;
 
-	len = ast_format_determine_length(moh->parent->format, samples);
+	len = ast_codec_get_len(&moh->parent->format, samples);
 
 	if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
 		ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
@@ -1014,7 +1021,7 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
 
 	moh->f.datalen = res;
 	moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
-	moh->f.samples = ast_codec_samples_count(&moh->f);
+	moh->f.samples = ast_codec_get_samples(&moh->f);
 
 	if (ast_write(chan, &moh->f) < 0) {
 		ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
@@ -1248,7 +1255,7 @@ static int init_app_class(struct mohclass *class)
 /*!
  * \note This function owns the reference it gets to moh if unref is true
  */
-#define moh_register(moh, reload, unref) _moh_register(moh, reload, unref, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define moh_register(a,b,c)	_moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
 static int _moh_register(struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
 {
 	struct mohclass *mohclass = NULL;
@@ -1308,16 +1315,14 @@ static void local_ast_moh_cleanup(struct ast_channel *chan)
 	struct moh_files_state *state = ast_channel_music_state(chan);
 
 	if (state) {
-		ast_channel_music_state_set(chan, NULL);
 		if (state->class) {
 			/* This should never happen.  We likely just leaked some resource. */
 			state->class =
 				mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
 			ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
 		}
-		ao2_cleanup(state->origwfmt);
-		ao2_cleanup(state->mohwfmt);
-		ast_free(state);
+		ast_free(ast_channel_music_state(chan));
+		ast_channel_music_state_set(chan, NULL);
 		/* Only held a module reference if we had a music state */
 		ast_module_unref(ast_module_info->self);
 	}
@@ -1342,7 +1347,7 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char
 			ao2_alloc(sizeof(*class), moh_class_destructor)
 #endif
 		)) {
-		class->format = ao2_bump(ast_format_slin);
+		ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
 		class->srcfd = -1;
 	}
 
@@ -1420,10 +1425,10 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
 				else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
 					ast_set_flag(mohclass, MOH_SORTALPHA);
 				else if (!strcasecmp(tmp->name, "format")) {
-					mohclass->format = ast_format_cache_get(tmp->value);
-					if (!mohclass->format) {
+					ast_getformatbyname(tmp->value, &mohclass->format);
+					if (!mohclass->format.id) {
 						ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
-						mohclass->format = ao2_bump(ast_format_slin);
+						ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
 					}
 				}
 			}
@@ -1542,6 +1547,16 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
 		}
 	}
 
+	ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
+		"State: Start\r\n"
+		"Channel: %s\r\n"
+		"UniqueID: %s\r\n"
+		"Class: %s\r\n",
+		ast_channel_name(chan), ast_channel_uniqueid(chan),
+		mohclass->name);
+
+	ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
+
 	if (!state || !state->class || strcmp(mohclass->name, state->class->name)) {
 		if (mohclass->total_files) {
 			res = ast_activate_generator(chan, &moh_file_stream, mohclass);
@@ -1549,10 +1564,6 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
 			res = ast_activate_generator(chan, &mohgen, mohclass);
 		}
 	}
-	if (!res) {
-		ast_channel_latest_musicclass_set(chan, mohclass->name);
-		ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
-	}
 
 	mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
 
@@ -1571,6 +1582,12 @@ static void local_ast_moh_stop(struct ast_channel *chan)
 			ast_channel_stream_set(chan, NULL);
 		}
 	}
+
+	ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
+		"State: Stop\r\n"
+		"Channel: %s\r\n"
+		"UniqueID: %s\r\n",
+		ast_channel_name(chan), ast_channel_uniqueid(chan));
 	ast_channel_unlock(chan);
 }
 
@@ -1656,8 +1673,6 @@ static void moh_class_destructor(void *obj)
 		class->timer = NULL;
 	}
 
-	ao2_cleanup(class->format);
-
 	/* Finally, collect the exit status of the monitor thread */
 	if (tid > 0) {
 		pthread_join(tid, NULL);
@@ -1752,10 +1767,10 @@ static int load_moh_classes(int reload)
 			} else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
 				ast_set_flag(class, MOH_SORTALPHA);
 			} else if (!strcasecmp(var->name, "format")) {
-				class->format = ast_format_cache_get(var->value);
-				if (!class->format) {
+				ast_getformatbyname(var->value, &class->format);
+				if (!class->format.id) {
 					ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
-					class->format = ao2_bump(ast_format_slin);
+					ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
 				}
 			}
 		}
@@ -1892,7 +1907,7 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc
 			ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
 		}
 		if (strcasecmp(class->mode, "files")) {
-			ast_cli(a->fd, "\tFormat: %s\n", ast_format_get_name(class->format));
+			ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
 		}
 	}
 	ao2_iterator_destroy(&i);
@@ -1922,16 +1937,6 @@ static int moh_class_cmp(void *obj, void *arg, int flags)
 		CMP_MATCH | CMP_STOP;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res;
@@ -1952,6 +1957,10 @@ static int load_module(void)
 	ast_register_atexit(ast_moh_destroy);
 	ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
 	if (!res)
+		res = ast_register_application_xml(wait_moh, wait_moh_exec);
+	if (!res)
+		res = ast_register_application_xml(set_moh, set_moh_exec);
+	if (!res)
 		res = ast_register_application_xml(start_moh, start_moh_exec);
 	if (!res)
 		res = ast_register_application_xml(stop_moh, stop_moh_exec);
@@ -1997,6 +2006,8 @@ static int unload_module(void)
 
 	ast_moh_destroy();
 	res = ast_unregister_application(play_moh);
+	res |= ast_unregister_application(wait_moh);
+	res |= ast_unregister_application(set_moh);
 	res |= ast_unregister_application(start_moh);
 	res |= ast_unregister_application(stop_moh);
 	ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
@@ -2006,7 +2017,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.reload = reload,
diff --git a/res/res_mutestream.c b/res/res_mutestream.c
index 3327b54..2fc8a49 100644
--- a/res/res_mutestream.c
+++ b/res/res_mutestream.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/options.h"
 #include "asterisk/logger.h"
@@ -123,44 +123,154 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
  ***/
 
 
-static int mute_channel(struct ast_channel *chan, const char *direction, int mute)
+/*! Our own datastore */
+struct mute_information {
+	struct ast_audiohook audiohook;
+	int mute_write;
+	int mute_read;
+};
+
+
+/*! Datastore destroy audiohook callback */
+static void destroy_callback(void *data)
 {
-	unsigned int mute_direction = 0;
-	enum ast_frame_type frametype = AST_FRAME_VOICE;
-	int ret = 0;
-
-	if (!strcmp(direction, "in")) {
-		mute_direction = AST_MUTE_DIRECTION_READ;
-	} else if (!strcmp(direction, "out")) {
-		mute_direction = AST_MUTE_DIRECTION_WRITE;
-	} else if (!strcmp(direction, "all")) {
-		mute_direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
-	} else {
-		return -1;
+	struct mute_information *mute = data;
+
+	/* Destroy the audiohook, and destroy ourselves */
+	ast_audiohook_destroy(&mute->audiohook);
+	ast_free(mute);
+	ast_module_unref(ast_module_info->self);
+}
+
+/*! \brief Static structure for datastore information */
+static const struct ast_datastore_info mute_datastore = {
+	.type = "mute",
+	.destroy = destroy_callback
+};
+
+/*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */
+static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
+{
+	struct ast_datastore *datastore = NULL;
+	struct mute_information *mute = NULL;
+
+
+	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
+	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
+		return 0;
 	}
 
 	ast_channel_lock(chan);
-
-	if (mute) {
-		ret = ast_channel_suppress(chan, mute_direction, frametype);
-	} else {
-		ret = ast_channel_unsuppress(chan, mute_direction, frametype);
+	/* Grab datastore which contains our mute information */
+	if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
+		ast_channel_unlock(chan);
+		ast_debug(2, "Can't find any datastore to use. Bad. \n");
+		return 0;
 	}
 
+	mute = datastore->data;
+
+
+	/* If this is audio then allow them to increase/decrease the gains */
+	if (frame->frametype == AST_FRAME_VOICE) {
+		ast_debug(2, "Audio frame - direction %s  mute READ %s WRITE %s\n", direction == AST_AUDIOHOOK_DIRECTION_READ ? "read" : "write", mute->mute_read ? "on" : "off", mute->mute_write ? "on" : "off");
+
+		/* Based on direction of frame grab the gain, and confirm it is applicable */
+		if ((direction == AST_AUDIOHOOK_DIRECTION_READ && mute->mute_read) || (direction == AST_AUDIOHOOK_DIRECTION_WRITE && mute->mute_write)) {
+			/* Ok, we just want to reset all audio in this frame. Keep NOTHING, thanks. */
+			ast_frame_clear(frame);
+		}
+	}
 	ast_channel_unlock(chan);
 
-	return ret;
+	return 0;
+}
+
+/*! \brief Initialize mute hook on channel, but don't activate it
+	\pre Assumes that the channel is locked
+*/
+static struct ast_datastore *initialize_mutehook(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+	struct mute_information *mute = NULL;
+
+	ast_debug(2, "Initializing new Mute Audiohook \n");
+
+	/* Allocate a new datastore to hold the reference to this mute_datastore and audiohook information */
+	if (!(datastore = ast_datastore_alloc(&mute_datastore, NULL))) {
+		return NULL;
+	}
+
+	if (!(mute = ast_calloc(1, sizeof(*mute)))) {
+		ast_datastore_free(datastore);
+		return NULL;
+	}
+	ast_audiohook_init(&mute->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Mute", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
+	mute->audiohook.manipulate_callback = mute_callback;
+	datastore->data = mute;
+	return datastore;
+}
+
+/*! \brief Add or activate mute audiohook on channel
+	Assumes channel is locked
+*/
+static int mute_add_audiohook(struct ast_channel *chan, struct mute_information *mute, struct ast_datastore *datastore)
+{
+	/* Activate the settings */
+	ast_channel_datastore_add(chan, datastore);
+	if (ast_audiohook_attach(chan, &mute->audiohook)) {
+		ast_log(LOG_ERROR, "Failed to attach audiohook for muting channel %s\n", ast_channel_name(chan));
+		return -1;
+	}
+	ast_module_ref(ast_module_info->self);
+	ast_debug(2, "Initialized audiohook on channel %s\n", ast_channel_name(chan));
+	return 0;
 }
 
 /*! \brief Mute dialplan function */
 static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
+	struct ast_datastore *datastore = NULL;
+	struct mute_information *mute = NULL;
+	int is_new = 0;
+	int turnon;
+
 	if (!chan) {
 		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
 		return -1;
 	}
 
-	return mute_channel(chan, data, ast_true(value));
+	ast_channel_lock(chan);
+	if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
+		if (!(datastore = initialize_mutehook(chan))) {
+			ast_channel_unlock(chan);
+			return 0;
+		}
+		is_new = 1;
+	}
+	mute = datastore->data;
+
+	turnon = ast_true(value);
+	if (!strcasecmp(data, "out")) {
+		mute->mute_write = turnon;
+		ast_debug(1, "%s channel - outbound \n", turnon ? "Muting" : "Unmuting");
+	} else if (!strcasecmp(data, "in")) {
+		mute->mute_read = turnon;
+		ast_debug(1, "%s channel - inbound  \n", turnon ? "Muting" : "Unmuting");
+	} else if (!strcasecmp(data,"all")) {
+		mute->mute_write = mute->mute_read = turnon;
+	}
+
+	if (is_new) {
+		if (mute_add_audiohook(chan, mute, datastore)) {
+			/* Can't add audiohook - already printed error message */
+			ast_datastore_free(datastore);
+			ast_free(mute);
+		}
+	}
+	ast_channel_unlock(chan);
+
+	return 0;
 }
 
 /* Function for debugging - might be useful */
@@ -177,6 +287,10 @@ static int manager_mutestream(struct mansession *s, const struct message *m)
 	const char *direction = astman_get_header(m,"Direction");
 	char id_text[256];
 	struct ast_channel *c = NULL;
+	struct ast_datastore *datastore = NULL;
+	struct mute_information *mute = NULL;
+	int is_new = 0;
+	int turnon;
 
 	if (ast_strlen_zero(channel)) {
 		astman_send_error(s, m, "Channel not specified");
@@ -198,12 +312,40 @@ static int manager_mutestream(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	if (mute_channel(c, direction, ast_true(state))) {
-		astman_send_error(s, m, "Failed to mute/unmute stream");
-		ast_channel_unref(c);
-		return 0;
+	ast_channel_lock(c);
+
+	if (!(datastore = ast_channel_datastore_find(c, &mute_datastore, NULL))) {
+		if (!(datastore = initialize_mutehook(c))) {
+			ast_channel_unlock(c);
+			ast_channel_unref(c);
+			astman_send_error(s, m, "Memory allocation failure");
+			return 0;
+		}
+		is_new = 1;
 	}
+	mute = datastore->data;
 
+	turnon = ast_true(state);
+	if (!strcasecmp(direction, "in")) {
+		mute->mute_read = turnon;
+	} else if (!strcasecmp(direction, "out")) {
+		mute->mute_write = turnon;
+	} else if (!strcasecmp(direction, "all")) {
+		mute->mute_read = mute->mute_write = turnon;
+	}
+
+	if (is_new) {
+		if (mute_add_audiohook(c, mute, datastore)) {
+			/* Can't add audiohook */
+			ast_datastore_free(datastore);
+			ast_free(mute);
+			ast_channel_unlock(c);
+			ast_channel_unref(c);
+			astman_send_error(s, m, "Couldn't add mute audiohook");
+			return 0;
+		}
+	}
+	ast_channel_unlock(c);
 	ast_channel_unref(c);
 
 	if (!ast_strlen_zero(id)) {
diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c
deleted file mode 100644
index 820a53f..0000000
--- a/res/res_mwi_external.c
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Core external MWI support.
- *
- * \details
- * The module manages the persistent message counts cache and supplies
- * an API to allow the protocol specific modules to control the counts
- * or a subset.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<defaultenabled>no</defaultenabled>
-	<conflict>app_voicemail</conflict>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_mwi_external" language="en_US">
-		<synopsis>Core external MWI support</synopsis>
-		<configFile name="sorcery.conf">
-			<configObject name="mailboxes">
-				<synopsis>Persistent cache of external MWI Mailboxs.</synopsis>
-				<description>
-					<para>Allows the alteration of sorcery backend mapping for
-					the persistent cache of external MWI mailboxes.</para>
-				</description>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/res_mwi_external.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/cli.h"
-
-/* ------------------------------------------------------------------- */
-
-/*!
- * Define to include CLI commands to manipulate the external MWI mailboxes.
- * Useful for testing the module functionality.
- */
-//#define MWI_DEBUG_CLI		1
-
-#define MWI_ASTDB_PREFIX	"mwi_external"
-#define MWI_MAILBOX_TYPE	"mailboxes"
-
-struct ast_mwi_mailbox_object {
-	SORCERY_OBJECT(details);
-	/*! Number of new messages in mailbox. */
-	unsigned int msgs_new;
-	/*! Number of old messages in mailbox. */
-	unsigned int msgs_old;
-};
-
-static struct ast_sorcery *mwi_sorcery;
-
-void ast_mwi_external_ref(void)
-{
-	ast_module_ref(ast_module_info->self);
-}
-
-void ast_mwi_external_unref(void)
-{
-	ast_module_unref(ast_module_info->self);
-}
-
-/*!
- * \internal
- * \brief Post an update event to the MWI counts.
- * \since 12.1.0
- *
- * \return Nothing
- */
-static void mwi_post_event(const struct ast_mwi_mailbox_object *mailbox)
-{
-	ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL,
-		mailbox->msgs_new, mailbox->msgs_old);
-}
-
-static void mwi_observe_update(const void *obj)
-{
-	mwi_post_event(obj);
-}
-
-/*!
- * \internal
- * \brief Post a count clearing event to the MWI counts.
- * \since 12.1.0
- *
- * \return Nothing
- */
-static void mwi_observe_delete(const void *obj)
-{
-	const struct ast_mwi_mailbox_object *mailbox = obj;
-
-	if (mailbox->msgs_new || mailbox->msgs_old) {
-		/* Post a count clearing event. */
-		ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0);
-	}
-
-	/* Post a cache remove event. */
-	ast_delete_mwi_state(ast_sorcery_object_get_id(mailbox), NULL);
-}
-
-static const struct ast_sorcery_observer mwi_observers = {
-	.created = mwi_observe_update,
-	.updated = mwi_observe_update,
-	.deleted = mwi_observe_delete,
-};
-
-/*! \brief Internal function to allocate a mwi object */
-static void *mwi_sorcery_object_alloc(const char *id)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct ast_mwi_mailbox_object), NULL);
-}
-
-/*!
- * \internal
- * \brief Initialize sorcery for external MWI.
- * \since 12.1.0
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int mwi_sorcery_init(void)
-{
-	int res;
-
-	mwi_sorcery = ast_sorcery_open();
-	if (!mwi_sorcery) {
-		ast_log(LOG_ERROR, "MWI external: Sorcery failed to open.\n");
-		return -1;
-	}
-
-	/* Map the external MWI wizards. */
-	if (ast_sorcery_apply_default(mwi_sorcery, MWI_MAILBOX_TYPE, "astdb",
-			MWI_ASTDB_PREFIX) == AST_SORCERY_APPLY_FAIL) {
-		ast_log(LOG_ERROR, "MWI external: Sorcery could not setup wizards.\n");
-		return -1;
-	}
-
-	res = ast_sorcery_object_register(mwi_sorcery, MWI_MAILBOX_TYPE,
-		mwi_sorcery_object_alloc, NULL, NULL);
-	if (res) {
-		ast_log(LOG_ERROR, "MWI external: Sorcery could not register object type '%s'.\n",
-			MWI_MAILBOX_TYPE);
-		return -1;
-	}
-
-	/* Define the MWI_MAILBOX_TYPE object fields. */
-	res |= ast_sorcery_object_field_register_nodoc(mwi_sorcery, MWI_MAILBOX_TYPE,
-		"msgs_new", "0", OPT_UINT_T, 0, FLDSET(struct ast_mwi_mailbox_object, msgs_new));
-	res |= ast_sorcery_object_field_register_nodoc(mwi_sorcery, MWI_MAILBOX_TYPE,
-		"msgs_old", "0", OPT_UINT_T, 0, FLDSET(struct ast_mwi_mailbox_object, msgs_old));
-	return res ? -1 : 0;
-}
-
-struct ao2_container *ast_mwi_mailbox_get_all(void)
-{
-	return ast_sorcery_retrieve_by_fields(mwi_sorcery, MWI_MAILBOX_TYPE,
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-}
-
-struct ao2_container *ast_mwi_mailbox_get_by_regex(const char *regex)
-{
-	return ast_sorcery_retrieve_by_regex(mwi_sorcery, MWI_MAILBOX_TYPE, regex ?: "");
-}
-
-const struct ast_mwi_mailbox_object *ast_mwi_mailbox_get(const char *mailbox_id)
-{
-	if (ast_strlen_zero(mailbox_id)) {
-		return NULL;
-	}
-
-	return ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
-}
-
-struct ast_mwi_mailbox_object *ast_mwi_mailbox_alloc(const char *mailbox_id)
-{
-	if (ast_strlen_zero(mailbox_id)) {
-		return NULL;
-	}
-
-	return ast_sorcery_alloc(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
-}
-
-struct ast_mwi_mailbox_object *ast_mwi_mailbox_copy(const struct ast_mwi_mailbox_object *mailbox)
-{
-	return ast_sorcery_copy(mwi_sorcery, mailbox);
-}
-
-const char *ast_mwi_mailbox_get_id(const struct ast_mwi_mailbox_object *mailbox)
-{
-	return ast_sorcery_object_get_id(mailbox);
-}
-
-unsigned int ast_mwi_mailbox_get_msgs_new(const struct ast_mwi_mailbox_object *mailbox)
-{
-	return mailbox->msgs_new;
-}
-
-unsigned int ast_mwi_mailbox_get_msgs_old(const struct ast_mwi_mailbox_object *mailbox)
-{
-	return mailbox->msgs_old;
-}
-
-void ast_mwi_mailbox_set_msgs_new(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs)
-{
-	mailbox->msgs_new = num_msgs;
-}
-
-void ast_mwi_mailbox_set_msgs_old(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs)
-{
-	mailbox->msgs_old = num_msgs;
-}
-
-int ast_mwi_mailbox_update(struct ast_mwi_mailbox_object *mailbox)
-{
-	const struct ast_mwi_mailbox_object *exists;
-	int res;
-
-	exists = ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE,
-		ast_sorcery_object_get_id(mailbox));
-	if (exists) {
-		res = ast_sorcery_update(mwi_sorcery, mailbox);
-		ast_mwi_mailbox_unref(exists);
-	} else {
-		res = ast_sorcery_create(mwi_sorcery, mailbox);
-	}
-	return res;
-}
-
-/*!
- * \internal
- * \brief Delete a mailbox.
- * \since 12.1.0
- *
- * \param mailbox Mailbox object to delete from sorcery.
- *
- * \return Nothing
- */
-static void mwi_mailbox_delete(struct ast_mwi_mailbox_object *mailbox)
-{
-	ast_sorcery_delete(mwi_sorcery, mailbox);
-}
-
-/*!
- * \internal
- * \brief Delete all mailboxes in container.
- * \since 12.1.0
- *
- * \param mailboxes Mailbox objects to delete from sorcery.
- *
- * \return Nothing
- */
-static void mwi_mailbox_delete_all(struct ao2_container *mailboxes)
-{
-	struct ast_mwi_mailbox_object *mailbox;
-	struct ao2_iterator iter;
-
-	iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		mwi_mailbox_delete(mailbox);
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-int ast_mwi_mailbox_delete_all(void)
-{
-	struct ao2_container *mailboxes;
-
-	mailboxes = ast_mwi_mailbox_get_all();
-	if (mailboxes) {
-		mwi_mailbox_delete_all(mailboxes);
-		ao2_ref(mailboxes, -1);
-	}
-	return 0;
-}
-
-int ast_mwi_mailbox_delete_by_regex(const char *regex)
-{
-	struct ao2_container *mailboxes;
-
-	mailboxes = ast_mwi_mailbox_get_by_regex(regex);
-	if (mailboxes) {
-		mwi_mailbox_delete_all(mailboxes);
-		ao2_ref(mailboxes, -1);
-	}
-	return 0;
-}
-
-int ast_mwi_mailbox_delete(const char *mailbox_id)
-{
-	const struct ast_mwi_mailbox_object *mailbox;
-
-	if (ast_strlen_zero(mailbox_id)) {
-		return -1;
-	}
-
-	mailbox = ast_mwi_mailbox_get(mailbox_id);
-	if (mailbox) {
-		mwi_mailbox_delete((struct ast_mwi_mailbox_object *) mailbox);
-		ast_mwi_mailbox_unref(mailbox);
-	}
-	return 0;
-}
-
-enum folder_map {
-	FOLDER_INVALID = 0,
-	FOLDER_INBOX = 1,
-	FOLDER_OLD = 2,
-};
-
-/*!
- * \internal
- * \brief Determine if the requested folder is valid for external MWI support.
- * \since 12.1.0
- *
- * \param folder Folder name to check (NULL is valid).
- *
- * \return Enum of the supported folder.
- */
-static enum folder_map mwi_folder_map(const char *folder)
-{
-	enum folder_map which_folder;
-
-	if (ast_strlen_zero(folder) || !strcasecmp(folder, "INBOX")) {
-		which_folder = FOLDER_INBOX;
-	} else if (!strcasecmp(folder, "Old")) {
-		which_folder = FOLDER_OLD;
-	} else {
-		which_folder = FOLDER_INVALID;
-	}
-	return which_folder;
-}
-
-/*!
- * \internal
- * \brief Gets the number of messages that exist in a mailbox folder.
- * \since 12.1.0
- *
- * \param mailbox_id The mailbox name.
- * \param folder The folder to look in.  Default is INBOX if not provided.
- *
- * \return The number of messages in the mailbox folder (zero or more).
- */
-static int mwi_messagecount(const char *mailbox_id, const char *folder)
-{
-	const struct ast_mwi_mailbox_object *mailbox;
-	int num_msgs;
-	enum folder_map which_folder;
-
-	which_folder = mwi_folder_map(folder);
-	if (which_folder == FOLDER_INVALID) {
-		return 0;
-	}
-
-	mailbox = ast_mwi_mailbox_get(mailbox_id);
-	if (!mailbox) {
-		return 0;
-	}
-	num_msgs = 0;
-	switch (which_folder) {
-	case FOLDER_INVALID:
-		break;
-	case FOLDER_INBOX:
-		num_msgs = mailbox->msgs_new;
-		break;
-	case FOLDER_OLD:
-		num_msgs = mailbox->msgs_old;
-		break;
-	}
-	ast_mwi_mailbox_unref(mailbox);
-
-	return num_msgs;
-}
-
-/*!
- * \internal
- * \brief Determines if the given folder has messages.
- * \since 12.1.0
- *
- * \param mailboxes Comma or & delimited list of mailboxes.
- * \param folder The folder to look in.  Default is INBOX if not provided.
- *
- * \retval 1 if the folder has one or more messages.
- * \retval 0 otherwise.
- */
-static int mwi_has_voicemail(const char *mailboxes, const char *folder)
-{
-	char *parse;
-	char *mailbox_id;
-	enum folder_map which_folder;
-
-	which_folder = mwi_folder_map(folder);
-	if (which_folder == FOLDER_INVALID) {
-		return 0;
-	}
-
-	/* For each mailbox in the list. */
-	parse = ast_strdupa(mailboxes);
-	while ((mailbox_id = strsep(&parse, ",&"))) {
-		const struct ast_mwi_mailbox_object *mailbox;
-		int num_msgs;
-
-		/* Get the specified mailbox. */
-		mailbox = ast_mwi_mailbox_get(mailbox_id);
-		if (!mailbox) {
-			continue;
-		}
-
-		/* Done if the found mailbox has any messages. */
-		num_msgs = 0;
-		switch (which_folder) {
-		case FOLDER_INVALID:
-			break;
-		case FOLDER_INBOX:
-			num_msgs = mailbox->msgs_new;
-			break;
-		case FOLDER_OLD:
-			num_msgs = mailbox->msgs_old;
-			break;
-		}
-		ast_mwi_mailbox_unref(mailbox);
-		if (num_msgs) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Gets the number of messages that exist for the mailbox list.
- * \since 12.1.0
- *
- * \param mailboxes Comma or space delimited list of mailboxes.
- * \param newmsgs Where to put the count of new messages. (Can be NULL)
- * \param oldmsgs Where to put the count of old messages. (Can be NULL)
- *
- * \details
- * Simultaneously determines the count of new and old
- * messages.  The total messages would then be the sum of these.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int mwi_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
-{
-	char *parse;
-	char *mailbox_id;
-
-	if (!newmsgs && !oldmsgs) {
-		/* Nowhere to accumulate counts */
-		return 0;
-	}
-
-	/* For each mailbox in the list. */
-	parse = ast_strdupa(mailboxes);
-	while ((mailbox_id = strsep(&parse, ", "))) {
-		const struct ast_mwi_mailbox_object *mailbox;
-
-		/* Get the specified mailbox. */
-		mailbox = ast_mwi_mailbox_get(mailbox_id);
-		if (!mailbox) {
-			continue;
-		}
-
-		/* Accumulate the counts. */
-		if (newmsgs) {
-			*newmsgs += mailbox->msgs_new;
-		}
-		if (oldmsgs) {
-			*oldmsgs += mailbox->msgs_old;
-		}
-
-		ast_mwi_mailbox_unref(mailbox);
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Gets the number of messages that exist for the mailbox list.
- * \since 12.1.0
- *
- * \param mailboxes Comma or space delimited list of mailboxes.
- * \param urgentmsgs Where to put the count of urgent messages. (Can be NULL)
- * \param newmsgs Where to put the count of new messages. (Can be NULL)
- * \param oldmsgs Where to put the count of old messages. (Can be NULL)
- *
- * \details
- * Simultaneously determines the count of new, old, and urgent
- * messages.  The total messages would then be the sum of these
- * three.
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int mwi_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
-{
-	/*
-	 * This module does not support urgentmsgs.  Just ignore them.
-	 * The global API call has already set the count to zero.
-	 */
-	return mwi_inboxcount(mailboxes, newmsgs, oldmsgs);
-}
-
-static const struct ast_vm_functions vm_table = {
-	.module_version = VM_MODULE_VERSION,
-	.module_name = AST_MODULE,
-
-	.has_voicemail = mwi_has_voicemail,
-	.inboxcount = mwi_inboxcount,
-	.inboxcount2 = mwi_inboxcount2,
-	.messagecount = mwi_messagecount,
-};
-
-#if defined(MWI_DEBUG_CLI)
-static char *complete_mailbox(const char *word, int state)
-{
-	struct ao2_iterator iter;
-	int wordlen = strlen(word);
-	int which = 0;
-	char *ret = NULL;
-	char *regex;
-	const struct ast_mwi_mailbox_object *mailbox;
-	RAII_VAR(struct ao2_container *, mailboxes, NULL, ao2_cleanup);
-
-	regex = ast_alloca(2 + wordlen);
-	sprintf(regex, "^%s", word);/* Safe */
-
-	mailboxes = ast_mwi_mailbox_get_by_regex(regex);
-	if (!mailboxes) {
-		return NULL;
-	}
-
-	iter = ao2_iterator_init(mailboxes, 0);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		if (++which > state) {
-			ret = ast_strdup(ast_sorcery_object_get_id(mailbox));
-			ast_mwi_mailbox_unref(mailbox);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	return ret;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_delete_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi delete all";
-		e->usage =
-			"Usage: mwi delete all\n"
-			"       Delete all external MWI mailboxes.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	ast_mwi_mailbox_delete_all();
-	ast_cli(a->fd, "Deleted all external MWI mailboxes.\n");
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_delete_like(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *regex;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi delete like";
-		e->usage =
-			"Usage: mwi delete like <pattern>\n"
-			"       Delete external MWI mailboxes matching a regular expression.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-	regex = a->argv[3];
-
-	ast_mwi_mailbox_delete_by_regex(regex);
-	ast_cli(a->fd, "Deleted external MWI mailboxes matching '%s'.\n", regex);
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_delete_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *mailbox_id;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi delete mailbox";
-		e->usage =
-			"Usage: mwi delete mailbox <mailbox_id>\n"
-			"       Delete a specific external MWI mailbox.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 3) {
-			return complete_mailbox(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-	mailbox_id = a->argv[3];
-
-	ast_mwi_mailbox_delete(mailbox_id);
-	ast_cli(a->fd, "Deleted external MWI mailbox '%s'.\n", mailbox_id);
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#define FORMAT_MAILBOX_HDR "%6s %6s %s\n"
-#define FORMAT_MAILBOX_ROW "%6u %6u %s\n"
-
-#if defined(MWI_DEBUG_CLI)
-/*!
- * \internal
- * \brief Print a mailbox list line to CLI.
- * \since 12.1.0
- *
- * \param cli_fd File descriptor for CLI output.
- * \param mailbox What to list.
- *
- * \return Nothing
- */
-static void mwi_cli_print_mailbox(int cli_fd, const struct ast_mwi_mailbox_object *mailbox)
-{
-	ast_cli(cli_fd, FORMAT_MAILBOX_ROW, mailbox->msgs_new, mailbox->msgs_old,
-		ast_sorcery_object_get_id(mailbox));
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-/*!
- * \internal
- * \brief List all mailboxes in the given container.
- * \since 12.1.0
- *
- * \param cli_fd File descriptor for CLI output.
- * \param mailboxes What to list.
- *
- * \return Nothing
- */
-static void mwi_cli_list_mailboxes(int cli_fd, struct ao2_container *mailboxes)
-{
-	struct ao2_iterator iter;
-	const struct ast_mwi_mailbox_object *mailbox;
-
-	ast_cli(cli_fd, FORMAT_MAILBOX_HDR, "New", "Old", "Mailbox");
-
-	iter = ao2_iterator_init(mailboxes, 0);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		mwi_cli_print_mailbox(cli_fd, mailbox);
-	}
-	ao2_iterator_destroy(&iter);
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#undef FORMAT_MAILBOX_HDR
-#undef FORMAT_MAILBOX_ROW
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_list_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ao2_container *mailboxes;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi list all";
-		e->usage =
-			"Usage: mwi list all\n"
-			"       List all external MWI mailboxes.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	mailboxes = ast_mwi_mailbox_get_all();
-	if (!mailboxes) {
-		ast_cli(a->fd, "Failed to retrieve external MWI mailboxes.\n");
-		return CLI_SUCCESS;
-	}
-	mwi_cli_list_mailboxes(a->fd, mailboxes);
-	ao2_ref(mailboxes, -1);
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_list_like(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ao2_container *mailboxes;
-	const char *regex;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi list like";
-		e->usage =
-			"Usage: mwi list like <pattern>\n"
-			"       List external MWI mailboxes matching a regular expression.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-	regex = a->argv[3];
-
-	mailboxes = ast_mwi_mailbox_get_by_regex(regex);
-	if (!mailboxes) {
-		ast_cli(a->fd, "Failed to retrieve external MWI mailboxes.\n");
-		return CLI_SUCCESS;
-	}
-	mwi_cli_list_mailboxes(a->fd, mailboxes);
-	ao2_ref(mailboxes, -1);
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_show_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const struct ast_mwi_mailbox_object *mailbox;
-	const char *mailbox_id;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi show mailbox";
-		e->usage =
-			"Usage: mwi show mailbox <mailbox_id>\n"
-			"       Show a specific external MWI mailbox.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 3) {
-			return complete_mailbox(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-	mailbox_id = a->argv[3];
-
-	mailbox = ast_mwi_mailbox_get(mailbox_id);
-	if (mailbox) {
-		ast_cli(a->fd,
-			"Mailbox: %s\n"
-			"NewMessages: %u\n"
-			"OldMessages: %u\n",
-			ast_sorcery_object_get_id(mailbox),
-			mailbox->msgs_new,
-			mailbox->msgs_old);
-
-		ast_mwi_mailbox_unref(mailbox);
-	} else {
-		ast_cli(a->fd, "External MWI mailbox '%s' not found.\n", mailbox_id);
-	}
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static char *handle_mwi_update_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct ast_mwi_mailbox_object *mailbox;
-	const char *mailbox_id;
-	unsigned int num_new;
-	unsigned int num_old;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "mwi update mailbox";
-		e->usage =
-			"Usage: mwi update mailbox <mailbox_id> [<new> [<old>]]\n"
-			"       Update a specific external MWI mailbox.\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->pos == 3) {
-			return complete_mailbox(a->word, a->n);
-		}
-		return NULL;
-	}
-
-	if (a->argc < 4 || 6 < a->argc) {
-		return CLI_SHOWUSAGE;
-	}
-	mailbox_id = a->argv[3];
-
-	num_new = 0;
-	if (4 < a->argc) {
-		const char *count_new = a->argv[4];
-
-		if (sscanf(count_new, "%u", &num_new) != 1) {
-			ast_cli(a->fd, "Invalid NewMessages: '%s'.\n", count_new);
-			return CLI_SHOWUSAGE;
-		}
-	}
-
-	num_old = 0;
-	if (5 < a->argc) {
-		const char *count_old = a->argv[5];
-
-		if (sscanf(count_old, "%u", &num_old) != 1) {
-			ast_cli(a->fd, "Invalid OldMessages: '%s'.\n", count_old);
-			return CLI_SHOWUSAGE;
-		}
-	}
-
-	mailbox = ast_mwi_mailbox_alloc(mailbox_id);
-	if (mailbox) {
-		ast_mwi_mailbox_set_msgs_new(mailbox, num_new);
-		ast_mwi_mailbox_set_msgs_old(mailbox, num_old);
-		if (ast_mwi_mailbox_update(mailbox)) {
-			ast_cli(a->fd, "Could not update mailbox %s.\n",
-				ast_sorcery_object_get_id(mailbox));
-		} else {
-			ast_cli(a->fd, "Updated mailbox %s.\n", ast_sorcery_object_get_id(mailbox));
-		}
-
-		ast_mwi_mailbox_unref(mailbox);
-	}
-
-	return CLI_SUCCESS;
-}
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-#if defined(MWI_DEBUG_CLI)
-static struct ast_cli_entry mwi_cli[] = {
-	AST_CLI_DEFINE(handle_mwi_delete_all, "Delete all external MWI mailboxes"),
-	AST_CLI_DEFINE(handle_mwi_delete_like, "Delete external MWI mailboxes matching regex"),
-	AST_CLI_DEFINE(handle_mwi_delete_mailbox, "Delete a specific external MWI mailbox"),
-	AST_CLI_DEFINE(handle_mwi_list_all, "List all external MWI mailboxes"),
-	AST_CLI_DEFINE(handle_mwi_list_like, "List external MWI mailboxes matching regex"),
-	AST_CLI_DEFINE(handle_mwi_show_mailbox, "Show a specific external MWI mailbox"),
-	AST_CLI_DEFINE(handle_mwi_update_mailbox, "Update a specific external MWI mailbox"),
-};
-#endif	/* defined(MWI_DEBUG_CLI) */
-
-/*!
- * \internal
- * \brief Post initial MWI count events.
- * \since 12.1.0
- *
- * \return Nothing
- */
-static void mwi_initial_events(void)
-{
-	struct ao2_container *mailboxes;
-	const struct ast_mwi_mailbox_object *mailbox;
-	struct ao2_iterator iter;
-
-	/* Get all mailbox counts. */
-	mailboxes = ast_mwi_mailbox_get_all();
-	if (!mailboxes) {
-		return;
-	}
-
-	/* Post all mailbox counts. */
-	iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		mwi_post_event(mailbox);
-	}
-	ao2_iterator_destroy(&iter);
-
-	ao2_ref(mailboxes, -1);
-}
-
-static int unload_module(void)
-{
-	ast_vm_unregister(vm_table.module_name);
-#if defined(MWI_DEBUG_CLI)
-	ast_cli_unregister_multiple(mwi_cli, ARRAY_LEN(mwi_cli));
-#endif	/* defined(MWI_DEBUG_CLI) */
-	ast_sorcery_observer_remove(mwi_sorcery, MWI_MAILBOX_TYPE, &mwi_observers);
-
-	ast_sorcery_unref(mwi_sorcery);
-	mwi_sorcery = NULL;
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	if (mwi_sorcery_init()
-		|| ast_sorcery_observer_add(mwi_sorcery, MWI_MAILBOX_TYPE, &mwi_observers)
-#if defined(MWI_DEBUG_CLI)
-		|| ast_cli_register_multiple(mwi_cli, ARRAY_LEN(mwi_cli))
-#endif	/* defined(MWI_DEBUG_CLI) */
-		|| ast_vm_register(&vm_table)) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	/* Post initial MWI count events. */
-	mwi_initial_events();
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Core external MWI resource",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
-);
diff --git a/res/res_mwi_external.exports.in b/res/res_mwi_external.exports.in
deleted file mode 100644
index c823197..0000000
--- a/res/res_mwi_external.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_*;
-	local:
-		*;
-};
diff --git a/res/res_mwi_external_ami.c b/res/res_mwi_external_ami.c
deleted file mode 100644
index ea6604f..0000000
--- a/res/res_mwi_external_ami.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief AMI wrapper for external MWI.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-/*** MODULEINFO
-	<depend>res_mwi_external</depend>
-	<support_level>core</support_level>
- ***/
-
-
-/*** DOCUMENTATION
-	<manager name="MWIGet" language="en_US">
-		<synopsis>
-			Get selected mailboxes with message counts.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Mailbox" required="true">
-				<para>Mailbox ID in the form of
-				/<replaceable>regex</replaceable>/ for all mailboxes matching the regular
-				expression.  Otherwise it is for a specific mailbox.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Get a list of mailboxes with their message counts.</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="MWIGet">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>
-				Raised in response to a MWIGet command.
-			</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="Mailbox">
-					<para>Specific mailbox ID.</para>
-				</parameter>
-				<parameter name="OldMessages">
-					<para>The number of old messages in the mailbox.</para>
-				</parameter>
-				<parameter name="NewMessages">
-					<para>The number of new messages in the mailbox.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">MWIGet</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="MWIGetComplete">
-		<managerEventInstance class="EVENT_FLAG_REPORTING">
-			<synopsis>
-				Raised in response to a MWIGet command.
-			</synopsis>
-			<syntax>
-				<parameter name="ActionID" required="false"/>
-				<parameter name="EventList" />
-				<parameter name="ListItems">
-					<para>The number of mailboxes reported.</para>
-				</parameter>
-			</syntax>
-			<see-also>
-				<ref type="manager">MWIGet</ref>
-			</see-also>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="MWIDelete" language="en_US">
-		<synopsis>
-			Delete selected mailboxes.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<xi:include xpointer="xpointer(/docs/manager[@name='MWIGet']/syntax/parameter[@name='Mailbox'])" />
-		</syntax>
-		<description>
-			<para>Delete the specified mailboxes.</para>
-		</description>
-	</manager>
-	<manager name="MWIUpdate" language="en_US">
-		<synopsis>
-			Update the mailbox message counts.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Mailbox" required="true">
-				<para>Specific mailbox ID.</para>
-			</parameter>
-			<parameter name="OldMessages">
-				<para>The number of old messages in the mailbox.  Defaults
-				to zero if missing.</para>
-			</parameter>
-			<parameter name="NewMessages">
-				<para>The number of new messages in the mailbox.  Defaults
-				to zero if missing.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Update the mailbox message counts.</para>
-		</description>
-	</manager>
- ***/
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/module.h"
-#include "asterisk/res_mwi_external.h"
-#include "asterisk/manager.h"
-
-/* ------------------------------------------------------------------- */
-
-/*!
- * \internal
- * \brief Get the requested mailboxes.
- * \since 12.1.0
- *
- * \param s AMI session.
- * \param m AMI message.
- *
- * \retval 0 to keep AMI connection.
- * \retval -1 to disconnect AMI connection.
- */
-static int mwi_mailbox_get(struct mansession *s, const struct message *m)
-{
-	char id_text[256];
-	const char *id;
-	const char *mailbox_id = astman_get_header(m, "Mailbox");
-	const struct ast_mwi_mailbox_object *mailbox;
-	struct ao2_container *mailboxes;
-	unsigned count;
-	struct ao2_iterator iter;
-
-	if (ast_strlen_zero(mailbox_id)) {
-		astman_send_error(s, m, "Missing mailbox parameter in request");
-		return 0;
-	}
-
-	if (*mailbox_id == '/') {
-		struct ast_str *regex_string;
-
-		regex_string = ast_str_create(strlen(mailbox_id) + 1);
-		if (!regex_string) {
-			astman_send_error(s, m, "Memory Allocation Failure");
-			return 0;
-		}
-
-		/* Make "/regex/" into "regex" */
-		if (ast_regex_string_to_regex_pattern(mailbox_id, &regex_string) != 0) {
-			astman_send_error_va(s, m, "Mailbox regex format invalid in: %s", mailbox_id);
-			ast_free(regex_string);
-			return 0;
-		}
-
-		mailboxes = ast_mwi_mailbox_get_by_regex(ast_str_buffer(regex_string));
-		ast_free(regex_string);
-	} else {
-		mailboxes = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
-		if (mailboxes) {
-			mailbox = ast_mwi_mailbox_get(mailbox_id);
-			if (mailbox) {
-				if (!ao2_link(mailboxes, (void *) mailbox)) {
-					ao2_ref(mailboxes, -1);
-					mailboxes = NULL;
-				}
-				ast_mwi_mailbox_unref(mailbox);
-			}
-		}
-	}
-	if (!mailboxes) {
-		astman_send_error(s, m, "Mailbox container creation failure");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "Mailboxes will follow", "start");
-
-	id = astman_get_header(m, "ActionID");
-	if (!ast_strlen_zero(id)) {
-		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
-	} else {
-		id_text[0] = '\0';
-	}
-
-	/* Output mailbox list. */
-	count = 0;
-	iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		++count;
-		astman_append(s,
-			"Event: MWIGet\r\n"
-			"Mailbox: %s\r\n"
-			"OldMessages: %u\r\n"
-			"NewMessages: %u\r\n"
-			"%s"
-			"\r\n",
-			ast_mwi_mailbox_get_id(mailbox),
-			ast_mwi_mailbox_get_msgs_old(mailbox),
-			ast_mwi_mailbox_get_msgs_new(mailbox),
-			id_text);
-	}
-	ao2_iterator_destroy(&iter);
-	ao2_ref(mailboxes, -1);
-
-	astman_append(s,
-		"Event: MWIGetComplete\r\n"
-		"EventList: Complete\r\n"
-		"ListItems: %u\r\n"
-		"%s"
-		"\r\n", count, id_text);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Delete the requested mailboxes.
- * \since 12.1.0
- *
- * \param s AMI session.
- * \param m AMI message.
- *
- * \retval 0 to keep AMI connection.
- * \retval -1 to disconnect AMI connection.
- */
-static int mwi_mailbox_delete(struct mansession *s, const struct message *m)
-{
-	const char *mailbox_id = astman_get_header(m, "Mailbox");
-
-	if (ast_strlen_zero(mailbox_id)) {
-		astman_send_error(s, m, "Missing mailbox parameter in request");
-		return 0;
-	}
-
-	if (*mailbox_id == '/') {
-		struct ast_str *regex_string;
-
-		regex_string = ast_str_create(strlen(mailbox_id) + 1);
-		if (!regex_string) {
-			astman_send_error(s, m, "Memory Allocation Failure");
-			return 0;
-		}
-
-		/* Make "/regex/" into "regex" */
-		if (ast_regex_string_to_regex_pattern(mailbox_id, &regex_string) != 0) {
-			astman_send_error_va(s, m, "Mailbox regex format invalid in: %s", mailbox_id);
-			ast_free(regex_string);
-			return 0;
-		}
-
-		ast_mwi_mailbox_delete_by_regex(ast_str_buffer(regex_string));
-		ast_free(regex_string);
-	} else {
-		ast_mwi_mailbox_delete(mailbox_id);
-	}
-
-	astman_send_ack(s, m, NULL);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Update the specified mailbox.
- * \since 12.1.0
- *
- * \param s AMI session.
- * \param m AMI message.
- *
- * \retval 0 to keep AMI connection.
- * \retval -1 to disconnect AMI connection.
- */
-static int mwi_mailbox_update(struct mansession *s, const struct message *m)
-{
-	const char *mailbox_id = astman_get_header(m, "Mailbox");
-	const char *msgs_old = astman_get_header(m, "OldMessages");
-	const char *msgs_new = astman_get_header(m, "NewMessages");
-	struct ast_mwi_mailbox_object *mailbox;
-	unsigned int num_old;
-	unsigned int num_new;
-
-	if (ast_strlen_zero(mailbox_id)) {
-		astman_send_error(s, m, "Missing mailbox parameter in request");
-		return 0;
-	}
-
-	num_old = 0;
-	if (!ast_strlen_zero(msgs_old)) {
-		if (sscanf(msgs_old, "%u", &num_old) != 1) {
-			astman_send_error_va(s, m, "Invalid OldMessages: %s", msgs_old);
-			return 0;
-		}
-	}
-
-	num_new = 0;
-	if (!ast_strlen_zero(msgs_new)) {
-		if (sscanf(msgs_new, "%u", &num_new) != 1) {
-			astman_send_error_va(s, m, "Invalid NewMessages: %s", msgs_new);
-			return 0;
-		}
-	}
-
-	mailbox = ast_mwi_mailbox_alloc(mailbox_id);
-	if (!mailbox) {
-		astman_send_error(s, m, "Mailbox object creation failure");
-		return 0;
-	}
-
-	/* Update external mailbox. */
-	ast_mwi_mailbox_set_msgs_old(mailbox, num_old);
-	ast_mwi_mailbox_set_msgs_new(mailbox, num_new);
-	if (ast_mwi_mailbox_update(mailbox)) {
-		astman_send_error(s, m, "Update attempt failed");
-	} else {
-		astman_send_ack(s, m, NULL);
-	}
-	ast_mwi_mailbox_unref(mailbox);
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_manager_unregister("MWIGet");
-	ast_manager_unregister("MWIDelete");
-	ast_manager_unregister("MWIUpdate");
-
-	/* Must be done last */
-	ast_mwi_external_unref();
-	return 0;
-}
-
-static int load_module(void)
-{
-	int res;
-
-	/* Must be done first */
-	ast_mwi_external_ref();
-
-	res = 0;
-	res |= ast_manager_register_xml_core("MWIGet", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, mwi_mailbox_get);
-	res |= ast_manager_register_xml_core("MWIDelete", EVENT_FLAG_CALL, mwi_mailbox_delete);
-	res |= ast_manager_register_xml_core("MWIUpdate", EVENT_FLAG_CALL, mwi_mailbox_update);
-	if (res) {
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "AMI support for external MWI",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-);
-
diff --git a/res/res_odbc.c b/res/res_odbc.c
index d539f79..3595cde 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -30,15 +30,6 @@
  * \arg See also: \ref cdr_odbc
  */
 
-/*! \li \ref res_odbc.c uses the configuration file \ref res_odbc.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page res_odbc.conf res_odbc.conf
- * \verbinclude res_odbc.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>generic_odbc</depend>
 	<depend>ltdl</depend>
@@ -47,7 +38,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -137,6 +128,7 @@ struct odbc_class
 	unsigned int delme:1;                /*!< Purge the class */
 	unsigned int backslash_is_escape:1;  /*!< On this database, the backslash is a native escape sequence */
 	unsigned int forcecommit:1;          /*!< Should uncommitted transactions be auto-committed on handle release? */
+	unsigned int allow_empty_strings:1;  /*!< Implicit conversion from an empty string to a number is valid for this database */
 	unsigned int isolation;              /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
 	unsigned int limit;                  /*!< Maximum number of database handles we will allow */
 	int count;                           /*!< Running count of pooled connections */
@@ -461,7 +453,7 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *
 	SQLLEN sqlptr;
 	SQLHSTMT stmt = NULL;
 	int res = 0, error = 0, try = 0;
-	struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
+	struct odbc_obj *obj;
 
 	AST_RWLIST_RDLOCK(&odbc_tables);
 	AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
@@ -472,13 +464,10 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *
 	if (tableptr) {
 		AST_RWLIST_RDLOCK(&tableptr->columns);
 		AST_RWLIST_UNLOCK(&odbc_tables);
-		if (obj) {
-			ast_odbc_release_obj(obj);
-		}
 		return tableptr;
 	}
 
-	if (!obj) {
+	if (!(obj = ast_odbc_request_obj(database, 0))) {
 		ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
 		AST_RWLIST_UNLOCK(&odbc_tables);
 		return NULL;
@@ -546,7 +535,7 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *
 				entry->octetlen = entry->size;
 			}
 
-			ast_debug(3, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
+			ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
 			/* Insert column info into column list */
 			AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
 		}
@@ -564,9 +553,7 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *
 		destroy_table_cache(tableptr);
 		tableptr = NULL;
 	}
-	if (obj) {
-		ast_odbc_release_obj(obj);
-	}
+	ast_odbc_release_obj(obj);
 	return tableptr;
 }
 
@@ -781,7 +768,7 @@ static int load_odbc_config(void)
 	struct ast_variable *v;
 	char *cat;
 	const char *dsn, *username, *password, *sanitysql;
-	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation;
+	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation, allow_empty_strings;
 	struct timeval ncache = { 0, 0 };
 	unsigned int idlecheck;
 	int preconnect = 0, res = 0;
@@ -810,6 +797,7 @@ static int load_odbc_config(void)
 			bse = 1;
 			conntimeout = 10;
 			forcecommit = 0;
+			allow_empty_strings = 1;
 			isolation = SQL_TXN_READ_COMMITTED;
 			for (v = ast_variable_browse(config, cat); v; v = v->next) {
 				if (!strcasecmp(v->name, "pooling")) {
@@ -845,6 +833,8 @@ static int load_odbc_config(void)
 					sanitysql = v->value;
 				} else if (!strcasecmp(v->name, "backslash_is_escape")) {
 					bse = ast_true(v->value);
+				} else if (!strcasecmp(v->name, "allow_empty_string_in_nontext")) {
+					allow_empty_strings = ast_true(v->value);
 				} else if (!strcasecmp(v->name, "connect_timeout")) {
 					if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
 						ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
@@ -906,6 +896,7 @@ static int load_odbc_config(void)
 				new->idlecheck = idlecheck;
 				new->conntimeout = conntimeout;
 				new->negative_connection_cache = ncache;
+				new->allow_empty_strings = allow_empty_strings ? 1 : 0;
 
 				if (cat)
 					ast_copy_string(new->name, cat, sizeof(new->name));
@@ -1123,6 +1114,11 @@ int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
 	return obj->parent->backslash_is_escape;
 }
 
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj)
+{
+	return obj->parent->allow_empty_strings;
+}
+
 static int commit_exec(struct ast_channel *chan, const char *data)
 {
 	struct odbc_txn_frame *tx;
@@ -1258,8 +1254,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
 		if (obj) {
 			ast_assert(ao2_ref(obj, 0) > 1);
 		}
-		if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
-				(time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
+		if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit)) {
 			obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
 			if (!obj) {
 				class->count--;
@@ -1417,10 +1412,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
 	}
 
 	if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
-		/* Check if this connection qualifies for reconnection, with negative connection cache time */
-		if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) {
-			odbc_obj_connect(obj);
-		}
+		odbc_obj_connect(obj);
 	} else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
 		ast_odbc_sanity_check(obj);
 	} else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
@@ -1527,6 +1519,7 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
 	char *tracefile = "/tmp/odbc.trace";
 #endif
 	SQLHDBC con;
+	long int negative_cache_expiration;
 
 	if (obj->up) {
 		odbc_obj_disconnect(obj);
@@ -1536,6 +1529,13 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
 		ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
 	}
 
+	/* Dont connect while server is marked as unreachable via negative_connection_cache */
+	negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
+	if (time(NULL) < negative_cache_expiration) {
+		ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
+		return ODBC_FAIL;
+	}
+
 	res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@@ -1884,16 +1884,6 @@ static int unload_module(void)
 	return -1;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr)))
@@ -1910,7 +1900,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ODBC resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_odbc.exports.in b/res/res_odbc.exports.in
index ad674be..991dacc 100644
--- a/res/res_odbc.exports.in
+++ b/res/res_odbc.exports.in
@@ -2,6 +2,7 @@
 	global:
 		LINKER_SYMBOL_PREFIXast_odbc_ast_str_SQLGetData;
 		LINKER_SYMBOL_PREFIXast_odbc_backslash_is_escape;
+		LINKER_SYMBOL_PREFIXast_odbc_allow_empty_string_in_nontext;
 		LINKER_SYMBOL_PREFIXast_odbc_clear_cache;
 		LINKER_SYMBOL_PREFIXast_odbc_direct_execute;
 		LINKER_SYMBOL_PREFIXast_odbc_find_column;
diff --git a/res/res_parking.c b/res/res_parking.c
deleted file mode 100644
index cbe880d..0000000
--- a/res/res_parking.c
+++ /dev/null
@@ -1,1271 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Call Parking Resource
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*** MODULEINFO
-	<depend>bridge_holding</depend>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_parking" language="en_US">
-		<configFile name="res_parking.conf">
-			<configObject name="globals">
-				<synopsis>Options that apply to every parking lot</synopsis>
-				<configOption name="parkeddynamic">
-					<synopsis>Enables dynamically created parkinglots.</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="parking_lot">
-				<synopsis>Defined parking lots for res_parking to use to park calls on</synopsis>
-				<configOption name="context" default="parkedcalls">
-					<synopsis>The name of the context where calls are parked and picked up from.</synopsis>
-					<description><para>This option is only used if parkext is set.</para></description>
-				</configOption>
-				<configOption name="parkext">
-					<synopsis>Extension to park calls to this parking lot.</synopsis>
-					<description><para>If this option is used, this extension will automatically be created to place calls into
-                        parking lots. In addition, if parkext_exclusive is set for this parking lot, the name of the parking lot
-                        will be included in the application's arguments so that it only parks to this parking lot. The extension
-                        will be created in <literal>context</literal>. Using this option also creates extensions for retrieving
-                        parked calls from the parking spaces in the same context.</para></description>
-				</configOption>
-				<configOption name="parkext_exclusive" default="no">
-					<synopsis>If yes, the extension registered as parkext will park exclusively to this parking lot.</synopsis>
-				</configOption>
-				<configOption name="parkpos" default="701-750">
-					<synopsis>Numerical range of parking spaces which can be used to retrieve parked calls.</synopsis>
-					<description><para>If parkext is set, these extensions will automatically be mapped in <literal>context</literal>
-						in order to pick up calls parked to these parking spaces.</para></description>
-				</configOption>
-				<configOption name="parkinghints" default="no">
-					<synopsis>If yes, this parking lot will add hints automatically for parking spaces.</synopsis>
-				</configOption>
-				<configOption name="parkingtime" default="45">
-					<synopsis>Amount of time a call will remain parked before giving up (in seconds).</synopsis>
-				</configOption>
-				<configOption name="parkedmusicclass">
-					<synopsis>Which music class to use for parked calls. They will use the default if unspecified.</synopsis>
-				</configOption>
-				<configOption name="comebacktoorigin" default="yes">
-					<synopsis>Determines what should be done with the parked channel if no one picks it up before it times out.</synopsis>
-					<description><para>Valid Options:</para>
-						<enumlist>
-							<enum name="yes">
-								<para>Automatically have the parked channel dial the device that parked the call with dial
-									timeout set by the <literal>parkingtime</literal> option. When the call times out an extension
-									to dial the PARKER will automatically be created in the <literal>park-dial</literal> context with
-									an extension of the flattened parker device name. If the call is not answered, the parked channel
-									that is timing out will continue in the dial plan at that point if there are more priorities in
-									the extension (which won't be the case unless the dialplan deliberately includes such priorities
-									in the <literal>park-dial</literal> context through pattern matching or deliberately written
-									flattened peer extensions).</para>
-							</enum>
-							<enum name="no">
-								<para>Place the call into the PBX at <literal>comebackcontext</literal> instead. The extension will
-									still be set as the flattened peer name. If an extension the flattened peer name isn't available
-									then it will fall back to the <literal>s</literal> extension. If that also is unavailable it will
-									attempt to fall back to <literal>s at default</literal>. The normal dial extension will still be
-									created in the <literal>park-dial</literal> context with the extension also being the flattened
-									peer name.</para>
-							</enum>
-						</enumlist>
-						<note><para>Flattened Peer Names - Extensions can not include slash characters since those are used for pattern
-							matching. When a peer name is flattened, slashes become underscores. For example if the parker of a call
-							is called <literal>SIP/0004F2040001</literal> then flattened peer name and therefor the extensions created
-							and used on timeouts will be <literal>SIP_0004F204001</literal>.</para></note>
-						<note><para>When parking times out and the channel returns to the dial plan, the following variables are set:
-						</para></note>
-						<variablelist>
-							<variable name="PARKING_SPACE">
-								<para>extension that the call was parked in prior to timing out.</para>
-							</variable>
-							<variable name="PARKINGSLOT">
-								<para>Deprecated.  Use <variable>PARKING_SPACE</variable> instead.</para>
-							</variable>
-							<variable name="PARKEDLOT">
-								<para>name of the lot that the call was parked in prior to timing out.</para>
-							</variable>
-							<variable name="PARKER">
-								<para>The device that parked the call</para>
-							</variable>
-							<variable name="PARKER_FLAT">
-								<para>The flat version of <variable>PARKER</variable></para>
-							</variable>
-						</variablelist>
-					</description>
-				</configOption>
-				<configOption name="comebackdialtime" default="30">
-					<synopsis>Timeout for the Dial extension created to call back the parker when a parked call times out.</synopsis>
-				</configOption>
-				<configOption name="comebackcontext" default="parkedcallstimeout">
-					<synopsis>Context where parked calls will enter the PBX on timeout when comebacktoorigin=no</synopsis>
-					<description><para>The extension the call enters will prioritize the flattened peer name in this context.
-						If the flattened peer name extension is unavailable, then the 's' extension in this context will be
-						used. If that also is unavailable, the 's' extension in the 'default' context will be used.</para>
-					</description>
-				</configOption>
-				<configOption name="courtesytone">
-					<synopsis>If the name of a sound file is provided, use this as the courtesy tone</synopsis>
-					<description><para>By default, this tone is only played to the caller of a parked call. Who receives the tone
-						can be changed using the <literal>parkedplay</literal> option.</para>
-					</description>
-				</configOption>
-				<configOption name="parkedplay" default="caller">
-					<synopsis>Who we should play the courtesytone to on the pickup of a parked call from this lot</synopsis>
-					<description>
-						<enumlist>
-							<enum name="no"><para>Apply to neither side.</para></enum>
-							<enum name="caller"><para>Apply only to the call connecting with the call coming out of the parking lot.</para></enum>
-							<enum name="callee"><para>Apply only to the call coming out of the parking lot.</para></enum>
-							<enum name="both"><para>Apply to both sides.</para></enum>
-						</enumlist>
-						<note><para>If courtesy tone is not specified then this option will be ignored.</para></note>
-					</description>
-				</configOption>
-				<configOption name="parkedcalltransfers" default="no">
-					<synopsis>Who to apply the DTMF transfer features to when parked calls are picked up or timeout.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
-					</description>
-				</configOption>
-				<configOption name="parkedcallreparking" default="no">
-					<synopsis>Who to apply the DTMF parking feature to when parked calls are picked up or timeout.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
-					</description>
-				</configOption>
-				<configOption name="parkedcallhangup" default="no">
-					<synopsis>Who to apply the DTMF hangup feature to when parked calls are picked up or timeout.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
-					</description>
-				</configOption>
-				<configOption name="parkedcallrecording" default="no">
-					<synopsis>Who to apply the DTMF MixMonitor recording feature to when parked calls are picked up or timeout.</synopsis>
-					<description>
-						<xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
-					</description>
-				</configOption>
-				<configOption name="findslot" default="first">
-					<synopsis>Rule to use when trying to figure out which parking space a call should be parked with.</synopsis>
-					<description>
-						<enumlist>
-							<enum name="first"><para>Always try to place in the lowest available space in the parking lot</para></enum>
-							<enum name="next"><para>Track the last parking space used and always attempt to use the one immediately after.
-							</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="courtesytone">
-					<synopsis>If set, the sound set will be played to whomever is set by parkedplay</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "parking/res_parking.h"
-#include "asterisk/config.h"
-#include "asterisk/config_options.h"
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/features.h"
-#include "asterisk/manager.h"
-#include "asterisk/pbx.h"
-
-static int parking_lot_sort_fn(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct parking_lot *left = obj_left;
-	const struct parking_lot *right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	default:
-	case OBJ_POINTER:
-		right_key = right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(left->name, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		cmp = strncmp(left->name, right_key, strlen(right_key));
-	}
-	return cmp;
-}
-
-/*! All parking lots that are currently alive in some fashion can be obtained from here */
-static struct ao2_container *parking_lot_container;
-
-static void *parking_config_alloc(void);
-
-static void *parking_lot_cfg_alloc(const char *cat);
-static void *named_item_find(struct ao2_container *container, const char *name); /* XXX This is really just a generic string find. Move to astobj2.c? */
-
-static int config_parking_preapply(void);
-static void link_configured_disable_marked_lots(void);
-
-struct parking_global_config {
-	int parkeddynamic;
-};
-
-struct parking_config {
-	struct parking_global_config *global;
-	struct ao2_container *parking_lots;
-};
-
-static struct aco_type global_option = {
-	.type = ACO_GLOBAL,
-	.name = "globals",
-	.item_offset = offsetof(struct parking_config, global),
-	.category_match = ACO_WHITELIST,
-	.category = "^general$",
-};
-
-struct aco_type *global_options[] = ACO_TYPES(&global_option);
-
-static struct aco_type parking_lot_type = {
-	.type = ACO_ITEM,
-	.name = "parking_lot",
-	.category_match = ACO_BLACKLIST,
-	.category = "^(general)$",
-	.item_alloc = parking_lot_cfg_alloc,
-	.item_find = named_item_find,
-	.item_offset = offsetof(struct parking_config, parking_lots),
-};
-
-struct aco_type *parking_lot_types[] = ACO_TYPES(&parking_lot_type);
-
-struct aco_file parking_lot_conf = {
-	.filename = "res_parking.conf",
-	.types = ACO_TYPES(&global_option, &parking_lot_type),
-};
-
-static AO2_GLOBAL_OBJ_STATIC(globals);
-
-CONFIG_INFO_STANDARD(cfg_info, globals, parking_config_alloc,
-	.files = ACO_FILES(&parking_lot_conf),
-	.pre_apply_config = config_parking_preapply,
-	.post_apply_config = link_configured_disable_marked_lots,
-);
-
-static int parking_lot_cfg_hash_fn(const void *obj, const int flags)
-{
-	const struct parking_lot_cfg *entry;
-	const char *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_PARTIAL_KEY:
-		ast_assert(0);
-		return 0;
-	default:
-		entry = obj;
-		return ast_str_hash(entry->name);
-	}
-}
-
-static int parking_lot_cfg_cmp_fn(void *obj, void *arg, const int flags)
-{
-	struct parking_lot_cfg *entry1 = obj;
-
-	char *key;
-	size_t key_size;
-	struct parking_lot_cfg *entry2;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = arg;
-		return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
-	case OBJ_PARTIAL_KEY:
-		key = arg;
-		key_size = strlen(key);
-		return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
-	case OBJ_POINTER:
-		entry2 = arg;
-		return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
-	default:
-		return CMP_STOP;
-	}
-}
-
-/*! \brief destructor for parking_config */
-static void parking_config_destructor(void *obj)
-{
-	struct parking_config *cfg = obj;
-	ao2_cleanup(cfg->parking_lots);
-	ao2_cleanup(cfg->global);
-}
-
-/*! \brief destructor for parking_global_config */
-static void parking_global_config_destructor(void *obj)
-{
-	/* For now, do nothing. */
-}
-
-/*! \brief allocator callback for parking_config. Notice it returns void * since it is only used by the backend config code */
-static void *parking_config_alloc(void)
-{
-	RAII_VAR(struct parking_config *, cfg, NULL, ao2_cleanup);
-
-	if (!(cfg = ao2_alloc(sizeof(*cfg), parking_config_destructor))) {
-		return NULL;
-	}
-
-	if (!(cfg->parking_lots = ao2_container_alloc(37, parking_lot_cfg_hash_fn, parking_lot_cfg_cmp_fn))) {
-		return NULL;
-	}
-
-	if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), parking_global_config_destructor))) {
-		return NULL;
-	}
-
-	/* Bump the ref count since RAII_VAR is going to eat one */
-	ao2_ref(cfg, +1);
-	return cfg;
-}
-
-int parking_lot_remove_if_unused(struct parking_lot *lot)
-{
-	if (lot->mode != PARKINGLOT_DISABLED) {
-		return -1;
-	}
-
-	if (!ao2_container_count(lot->parked_users)) {
-		ao2_unlink(parking_lot_container, lot);
-		return 0;
-	}
-
-	return -1;
-}
-
-static void parking_lot_disable(struct parking_lot *lot)
-{
-	/* If a dynamic lot wasn't removed, we need to restore it to full functionality afterwards. */
-	int was_dynamic = (lot->mode == PARKINGLOT_DYNAMIC);
-
-	lot->mode = PARKINGLOT_DISABLED;
-	if (parking_lot_remove_if_unused(lot) && was_dynamic) {
-		lot->mode = PARKINGLOT_DYNAMIC;
-		lot->disable_mark = 0;
-	}
-}
-
-/*! \brief Destroy a parking lot cfg object */
-static void parking_lot_cfg_destructor(void *obj)
-{
-	struct parking_lot_cfg *lot_cfg = obj;
-	parking_lot_cfg_remove_extensions(lot_cfg);
-	ast_string_field_free_memory(lot_cfg);
-}
-
-/* The arg just needs to have the parking space with it */
-static int parked_user_cmp_fn(void *obj, void *arg, int flags)
-{
-	int *search_space = arg;
-	struct parked_user *user = obj;
-	int object_space = user->parking_space;
-
-	if (*search_space == object_space) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-static int parked_user_sort_fn(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct parked_user *left = obj_left;
-	const struct parked_user *right = obj_right;
-
-	return left->parking_space - right->parking_space;
-}
-
-/*!
- * \brief create a parking lot structure
- * \param cat name given to the parking lot
- * \retval NULL failure
- * \retval non-NULL successfully allocated parking lot
- */
-static void *parking_lot_cfg_alloc(const char *cat)
-{
-	struct parking_lot_cfg *lot_cfg;
-
-	lot_cfg = ao2_alloc(sizeof(*lot_cfg), parking_lot_cfg_destructor);
-	if (!lot_cfg) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(lot_cfg, 32)) {
-		ao2_cleanup(lot_cfg);
-		return NULL;
-	}
-
-	ast_string_field_set(lot_cfg, name, cat);
-
-	return lot_cfg;
-}
-
-#if defined(TEST_FRAMEWORK)
-struct parking_lot_cfg *parking_lot_cfg_create(const char *cat)
-{
-	return parking_lot_cfg_alloc(cat);
-}
-#endif
-
-/*!
- * XXX This is actually incredibly generic and might be better placed in something like astobj2 if there isn't already an equivalent
- * \brief find an item in a container by its name
- *
- * \param container ao2container where we want the item from
- * \param key name of the item wanted to be found
- *
- * \retval pointer to the parking lot if available. NULL if not found.
- */
-static void *named_item_find(struct ao2_container *container, const char *name)
-{
-	return ao2_find(container, name, OBJ_KEY);
-}
-
-/*!
- * \brief Custom field handler for parking positions
- */
-static int option_handler_parkpos(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct parking_lot_cfg *lot_cfg = obj;
-	int low;
-	int high;
-
-	if (sscanf(var->value, "%30d-%30d", &low, &high) != 2) {
-		ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
-	} else if (high < low || low <= 0 || high <= 0) {
-		ast_log(LOG_WARNING, "Format for parking positions is a-b, where a <= b\n");
-	} else {
-		lot_cfg->parking_start = low;
-		lot_cfg->parking_stop = high;
-		return 0;
-	}
-	return -1;
-}
-
-/*!
- * \brief Custom field handler for the findslot option
- */
-static int option_handler_findslot(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct parking_lot_cfg *lot_cfg = obj;
-
-	if (!strcmp(var->value, "first")) {
-		lot_cfg->parkfindnext = 0;
-	} else if (!strcmp(var->value, "next")) {
-		lot_cfg->parkfindnext = 1;
-	} else {
-		ast_log(LOG_WARNING, "value '%s' is not valid for findslot option.\n", var->value);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Maps string values for option_handler_parkedfeature to their ENUM values
- */
-static int parking_feature_flag_cfg(int *param, const char *var)
-{
-	if (ast_false(var)) {
-		*param = 0;
-	} else if (!strcasecmp(var, "both")) {
-		*param = AST_FEATURE_FLAG_BYBOTH;
-	} else if (!strcasecmp(var, "caller")) {
-		*param = AST_FEATURE_FLAG_BYCALLER;
-	} else if (!strcasecmp(var, "callee")) {
-		*param = AST_FEATURE_FLAG_BYCALLEE;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Custom field handler for feature mapping on parked call pickup options
- */
-static int option_handler_parkedfeature(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct parking_lot_cfg *cfg = obj;
-	enum parked_call_feature_options option = aco_option_get_flags(opt);
-	int *parameter = NULL;
-
-	switch (option) {
-	case OPT_PARKEDPLAY:
-		parameter = &cfg->parkedplay;
-		break;
-	case OPT_PARKEDTRANSFERS:
-		parameter = &cfg->parkedcalltransfers;
-		break;
-	case OPT_PARKEDREPARKING:
-		parameter = &cfg->parkedcallreparking;
-		break;
-	case OPT_PARKEDHANGUP:
-		parameter = &cfg->parkedcallhangup;
-		break;
-	case OPT_PARKEDRECORDING:
-		parameter = &cfg->parkedcallrecording;
-		break;
-	}
-
-	ast_assert(parameter != NULL);
-	if (!parameter || parking_feature_flag_cfg(parameter, var->value)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-struct ao2_container *get_parking_lot_container(void)
-{
-	return parking_lot_container;
-}
-
-struct parking_lot *parking_lot_find_by_name(const char *lot_name)
-{
-	struct parking_lot *lot = named_item_find(parking_lot_container, lot_name);
-	return lot;
-}
-
-const char *find_channel_parking_lot_name(struct ast_channel *chan)
-{
-	const char *name;
-
-	/* The channel variable overrides everything */
-	name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
-	if (ast_strlen_zero(name) && !ast_strlen_zero(ast_channel_parkinglot(chan))) {
-		/* Use the channel's parking lot. */
-		name = ast_channel_parkinglot(chan);
-	}
-
-	/* If the name couldn't be pulled from that either, use the default parking lot name. */
-	if (ast_strlen_zero(name)) {
-		name = DEFAULT_PARKING_LOT;
-	}
-
-	return name;
-}
-
-static void parking_lot_destructor(void *obj)
-{
-	struct parking_lot *lot = obj;
-
-	if (lot->parking_bridge) {
-		ast_bridge_destroy(lot->parking_bridge, 0);
-	}
-	ao2_cleanup(lot->parked_users);
-	ao2_cleanup(lot->cfg);
-	ast_string_field_free_memory(lot);
-}
-
-static struct parking_lot *alloc_new_parking_lot(struct parking_lot_cfg *lot_cfg)
-{
-	struct parking_lot *lot;
-	if (!(lot = ao2_alloc(sizeof(*lot), parking_lot_destructor))) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(lot, 32)) {
-		return NULL;
-	}
-
-	/* Create parked user ordered list */
-	lot->parked_users = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-		parked_user_sort_fn,
-		parked_user_cmp_fn);
-
-	if (!lot->parked_users) {
-		ao2_cleanup(lot);
-		return NULL;
-	}
-
-	ast_string_field_set(lot, name, lot_cfg->name);
-	return lot;
-}
-
-void parking_lot_cfg_remove_extensions(struct parking_lot_cfg *lot_cfg)
-{
-	if (!ast_strlen_zero(lot_cfg->registrar)) {
-		/* Although the function is called ast_context_destroy, the use of this funtion is
-		 * intended only to remove extensions, hints, etc registered by the parking lot's registrar.
-		 * It won't actually destroy the context unless that context is empty afterwards and it is
-		 * unreferenced.
-		 */
-		ast_context_destroy(NULL, lot_cfg->registrar);
-	}
-
-	/* If we come back for a second pass, someone else has this registrar now. */
-	ast_string_field_set(lot_cfg, registrar, "");
-}
-
-static void remove_all_configured_parking_lot_extensions(void)
-{
-	RAII_VAR(struct parking_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-	struct parking_lot_cfg *lot_cfg;
-	struct ao2_iterator iter;
-
-	if (!cfg) {
-		return;
-	}
-
-	for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
-		parking_lot_cfg_remove_extensions(lot_cfg);
-	}
-
-	ast_context_destroy(NULL, BASE_REGISTRAR);
-
-	ao2_iterator_destroy(&iter);
-}
-
-/*!
- * \internal
- * \since 12
- * \brief Create an extension using ast_add_extension2_nolock. This function automatically allocates a duplicate
- *        of the data string so that whatever calls it doesn't have to deal with freeing it if the ast_add_extension2_nolock
- *        fails.
- *
- * \param context a write locked ast_context. Make certain it is write locked prior to calling this function
- * \param replace whether the extension should replace existing extensions
- * \param extension name of the extension desired
- * \param priority priority of the extension we are registering
- * \param application name of the application being used for the extension
- * \param data application arguments
- * \param registrar name of the registrar you should use for the extension.
- *        Make sure this string doesn't go anywhere while there are still extensions using it.
- */
-static int parking_add_extension(struct ast_context *context, int replace, const char *extension,
-	int priority, const char *application, const char *data, const char *registrar)
-{
-	char *data_duplicate = ast_strdup(data);
-
-	if (!data_duplicate) {
-		return -1;
-	}
-
-	if (ast_add_extension2_nolock(context, replace, extension, priority, NULL, NULL,
-			application, data_duplicate, ast_free_ptr, registrar)) {
-		ast_free(data_duplicate);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int extension_is_compatible(struct parking_lot_cfg *lot_cfg, const char *app_type, struct ast_exten *extension)
-{
-	const char *extension_registrar = ast_get_extension_registrar(extension);
-	const char *extension_context = ast_get_context_name(ast_get_extension_context(extension));
-	const char *extension_name = ast_get_extension_name(extension);
-	const char *extension_application = ast_get_extension_app(extension);
-
-	ast_assert(extension_registrar && extension_context && extension_name && extension_application);
-
-	if (strcmp(extension_registrar, BASE_REGISTRAR)) {
-		ast_log(LOG_ERROR, "Parking lot '%s' -- Needs an extension '%s@%s', but that extension is already owned by %s.\n",
-		        lot_cfg->name, extension_name, extension_context, extension_registrar);
-		return 0;
-	}
-
-	if (strcmp(extension_application, app_type)) {
-		ast_log(LOG_ERROR, "Parking lot '%s' -- Needs an extension '%s@%s' with a non-exclusive %s application, "
-		        "but a/an %s application is already registered to that extension by %s.\n",
-		        lot_cfg->name, extension_name, extension_context, app_type,
-		        extension_application, BASE_REGISTRAR);
-		return 0;
-	}
-
-	ast_debug(3, "Parking lot '%s' -- extension '%s@%s' with application %s is compatible.\n",
-	          lot_cfg->name, extension_name, extension_context, app_type);
-	return 1;
-}
-
-int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
-{
-	int parkingspace;
-	struct ast_exten *existing_exten;
-	struct ast_context *lot_context;
-	struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-	const char *parkext_registrar_pointer; /* Used for park extension */
-	const char *parkedcall_registrar_pointer; /* Used for parkedcall extensions/hints */
-
-	if (ast_strlen_zero(lot_cfg->parkext)) {
-		return 0;
-	}
-
-	ast_string_field_build(lot_cfg, registrar, "%s/%s", BASE_REGISTRAR, lot_cfg->name);
-	parkedcall_registrar_pointer = lot_cfg->registrar;
-
-	if (lot_cfg->parkext_exclusive) {
-		parkext_registrar_pointer = lot_cfg->registrar;
-	} else {
-		parkext_registrar_pointer = BASE_REGISTRAR;
-	}
-
-	/* We need the contexts list locked to safely be able to both read and lock the specific context within */
-	if (ast_wrlock_contexts()) {
-		ast_log(LOG_ERROR, "Failed to lock the contexts list.\n");
-		return -1;
-	}
-
-	if (!(lot_context = ast_context_find_or_create(NULL, NULL, lot_cfg->parking_con, parkext_registrar_pointer))) {
-		ast_log(LOG_ERROR, "Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n",
-			lot_cfg->name, lot_cfg->parking_con);
-		if (ast_unlock_contexts()) {
-			ast_assert(0);
-		}
-		return -1;
-	}
-
-	/* Once we know what context we will be modifying, we need to write lock it because we will be reading extensions
-	 * and we don't want something else to destroy them while we are looking at them.
-	 */
-	if (ast_wrlock_context(lot_context)) {
-		ast_log(LOG_ERROR, "failed to obtain write lock on context\n");
-		return -1;
-	}
-
-	if (ast_unlock_contexts()) {
-		ast_assert(0);
-	}
-
-	/* Handle generation/confirmation for the Park extension */
-	if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, lot_cfg->parkext, 1, NULL, NULL, E_MATCH))) {
-		if (lot_cfg->parkext_exclusive || !extension_is_compatible(lot_cfg, PARK_APPLICATION, existing_exten)) {
-			ast_unlock_context(lot_context);
-			return -1;
-		}
-	} else if (parking_add_extension(lot_context, 0, lot_cfg->parkext, 1, PARK_APPLICATION,
-	           lot_cfg->parkext_exclusive ? lot_cfg->name : "", parkext_registrar_pointer)) {
-		ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
-		        lot_cfg->name, PARK_APPLICATION, lot_cfg->parkext, lot_cfg->parking_con);
-		ast_unlock_context(lot_context);
-		return -1;
-	}
-
-	/* Handle generation/confirmation for the ParkedCall extensions and hints */
-	for (parkingspace = lot_cfg->parking_start; parkingspace <= lot_cfg->parking_stop; parkingspace++) {
-		char space[AST_MAX_EXTENSION];
-		RAII_VAR(struct ast_str *, arguments_string, NULL, ast_free);
-		find_info.stacklen = 0; /* reset for pbx_find_exten */
-
-		snprintf(space, sizeof(space), "%d", parkingspace);
-
-		/* Unlike the Park extensions, ParkedCall extensions and their hints may never be shared for any reason. */
-		if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, space, 1, NULL, NULL, E_MATCH))) {
-			ast_unlock_context(lot_context);
-			return -1;
-		}
-
-		arguments_string = ast_str_create(32);
-		if (!arguments_string) {
-			ast_unlock_context(lot_context);
-			return -1;
-		}
-
-		ast_str_set(&arguments_string, 0, "%s,%s", lot_cfg->name, space);
-		if (parking_add_extension(lot_context, 0, space, 1, PARKED_CALL_APPLICATION,
-		    ast_str_buffer(arguments_string), parkedcall_registrar_pointer)) {
-			ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
-			        lot_cfg->name, PARKED_CALL_APPLICATION, space, lot_cfg->parking_con);
-			ast_unlock_context(lot_context);
-			return -1;
-		}
-
-		find_info.stacklen = 0; /* reset for pbx_find_exten */
-
-		if (lot_cfg->parkaddhints) {
-			char hint_device[AST_MAX_EXTENSION];
-
-			snprintf(hint_device, sizeof(hint_device), "park:%s@%s", space, lot_cfg->parking_con);
-
-			if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, space, PRIORITY_HINT, NULL, NULL, E_MATCH))) {
-				ast_log(LOG_ERROR, "Parking lot '%s' -- Needs to add a hint '%s' at '%s@%s' but one already exists owned by %s\n",
-			        lot_cfg->name, hint_device, space, lot_cfg->parking_con, ast_get_extension_registrar(existing_exten));
-					ast_unlock_context(lot_context);
-					return -1;
-			}
-
-			if (parking_add_extension(lot_context, 0, space, PRIORITY_HINT, hint_device, "", parkedcall_registrar_pointer)) {
-				ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add hint '%s@%s' to the PBX.\n",
-				        lot_cfg->name, space, lot_cfg->parking_con);
-				ast_unlock_context(lot_context);
-				return -1;
-			}
-		}
-	}
-
-	if (ast_unlock_context(lot_context)) {
-		ast_assert(0);
-	}
-
-	return 0;
-}
-
-struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg, int dynamic)
-{
-	struct parking_lot *lot;
-	struct parking_lot_cfg *replaced_cfg = NULL;
-	int found = 0;
-
-	/* Start by trying to find it. If that works we can skip the rest. */
-	lot = named_item_find(parking_lot_container, lot_cfg->name);
-	if (!lot) {
-		lot = alloc_new_parking_lot(lot_cfg);
-
-		/* If we still don't have a lot, we failed to alloc one. */
-		if (!lot) {
-			return NULL;
-		}
-	} else {
-		found = 1;
-
-		if (dynamic) {
-			ast_log(LOG_ERROR, "Tried to create dynamic parking lot with name '%s' but a lot with that name already exists.\n", lot_cfg->name);
-			ao2_cleanup(lot);
-			return NULL;
-		}
-	}
-
-	/* Set the configuration reference. Unref the one currently in the lot if it's there. */
-	if (lot->cfg) {
-		replaced_cfg = lot->cfg;
-	}
-
-	ao2_ref(lot_cfg, +1);
-	lot->cfg = lot_cfg;
-
-	ao2_cleanup(replaced_cfg);
-
-	/* Set the operating mode to normal since the parking lot has a configuration. */
-	lot->disable_mark = 0;
-	lot->mode = dynamic ? PARKINGLOT_DYNAMIC : PARKINGLOT_NORMAL;
-
-	if (!found) {
-		/* Link after configuration is set since a lot without configuration will cause all kinds of trouble. */
-		ao2_link(parking_lot_container, lot);
-	};
-
-	return lot;
-}
-
-static void generate_or_link_lots_to_configs(void)
-{
-	RAII_VAR(struct parking_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-	struct parking_lot_cfg *lot_cfg;
-	struct ao2_iterator iter;
-
-	iter = ao2_iterator_init(cfg->parking_lots, 0);
-	for (; (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
-		ao2_cleanup(parking_lot_build_or_update(lot_cfg, 0));
-	}
-	ao2_iterator_destroy(&iter);
-}
-
-int parking_dynamic_lots_enabled(void)
-{
-	RAII_VAR(struct parking_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
-
-	if (!cfg) {
-		return 0;
-	}
-
-	return cfg->global->parkeddynamic;
-}
-
-static struct parking_lot_cfg *clone_parkinglot_cfg(struct parking_lot_cfg *source, const char *name)
-{
-	struct parking_lot_cfg *cfg = parking_lot_cfg_alloc(name);
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	ast_string_fields_copy(cfg, source);
-
-	/* Needs to be reset after being copied */
-	ast_string_field_set(cfg, name, name);
-
-	/* Stuff that should be cloned that isn't hit by string field copy */
-	cfg->parking_start = source->parking_start;
-	cfg->parking_stop = source->parking_stop;
-	cfg->parkingtime = source->parkingtime;
-	cfg->comebackdialtime = source->comebackdialtime;
-	cfg->parkfindnext = source->parkfindnext;
-	cfg->parkext_exclusive = source->parkext_exclusive;
-	cfg->parkaddhints = source->parkaddhints;
-	cfg->comebacktoorigin = source->comebacktoorigin;
-	cfg->parkedplay = source->parkedplay;
-	cfg->parkedcalltransfers = source->parkedcalltransfers;
-	cfg->parkedcallreparking = source->parkedcallreparking;
-	cfg->parkedcallhangup = source->parkedcallhangup;
-	cfg->parkedcallrecording = source->parkedcallrecording;
-
-	return cfg;
-}
-
-static struct parking_lot *create_dynamic_lot_full(const char *name, struct ast_channel *chan, int forced)
-{
-	RAII_VAR(struct parking_lot_cfg *, cfg, NULL, ao2_cleanup);
-	RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
-
-	struct parking_lot *lot;
-	const char *dyn_context;
-	const char *dyn_exten;
-	const char *dyn_range;
-	const char *template_name;
-	const char *chan_template_name;
-	int dyn_start;
-	int dyn_end;
-
-	if (!forced && !parking_dynamic_lots_enabled()) {
-		return NULL;
-	}
-
-	ast_channel_lock(chan);
-	chan_template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
-	dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
-	dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
-	dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
-	ast_channel_unlock(chan);
-
-	template_name = S_OR(chan_template_name, DEFAULT_PARKING_LOT);
-
-	template_lot = parking_lot_find_by_name(template_name);
-	if (!template_lot) {
-		ast_log(LOG_ERROR, "Lot %s does not exist. Can not use it as a dynamic parking lot template.\n",
-			template_name);
-		return NULL;
-	}
-
-	cfg = clone_parkinglot_cfg(template_lot->cfg, name);
-
-	if (!cfg) {
-		ast_log(LOG_ERROR, "Failed to allocate dynamic parking lot configuration.\n");
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(dyn_exten)) {
-		ast_string_field_set(cfg, parkext, dyn_exten);
-	}
-
-	if (!ast_strlen_zero(dyn_context)) {
-		ast_string_field_set(cfg, parking_con, dyn_context);
-	}
-
-	if (!ast_strlen_zero(dyn_range)) {
-		if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
-			ast_log(LOG_ERROR,
-				"Invalid parking range %s specified in PARKINGDYNPOS: could not parse minimum/maximum parking space range\n", dyn_range);
-				return NULL;
-		}
-		if (dyn_end < dyn_start || dyn_start < 0) {
-			ast_log(LOG_ERROR,
-				"Invalid parking range %s specified for PARKINGDYNPOS: end parking space must be greater than starting parking space.\n", dyn_range);
-				return NULL;
-		}
-
-		cfg->parking_start = dyn_start;
-		cfg->parking_stop = dyn_end;
-	}
-
-	if (parking_lot_cfg_create_extensions(cfg)) {
-		ast_log(LOG_ERROR, "Extensions for dynamic parking lot '%s' could not be registered. Dynamic lot creation failed.\n", name);
-		return NULL;
-	}
-
-	ao2_lock(parking_lot_container);
-
-	if ((lot = parking_lot_find_by_name(name))) {
-		ao2_unlock(parking_lot_container);
-		ast_log(LOG_ERROR, "Started creating dynamic parking lot '%s', but a parking lot with that name already exists.\n", name);
-		ao2_ref(lot, -1);
-		return NULL;
-	}
-
-	lot = parking_lot_build_or_update(cfg, 1);
-	ao2_unlock(parking_lot_container);
-
-	if (!lot) {
-		ast_log(LOG_NOTICE, "Failed to build dynamic parking lot '%s'\n", name);
-	}
-
-	return lot;
-}
-
-struct parking_lot *parking_create_dynamic_lot(const char *name, struct ast_channel *chan){
-	return create_dynamic_lot_full(name, chan, 0);
-}
-
-#if defined(TEST_FRAMEWORK)
-struct parking_lot *parking_create_dynamic_lot_forced(const char *name, struct ast_channel *chan) {
-	return create_dynamic_lot_full(name, chan, 1);
-}
-#endif
-
-/* Preapply */
-
-static int verify_default_parking_lot(void)
-{
-	struct parking_config *cfg = aco_pending_config(&cfg_info);
-	RAII_VAR(struct parking_lot_cfg *, lot_cfg, NULL, ao2_cleanup);
-
-	if (!cfg) {
-		return 0;
-	}
-
-	lot_cfg = ao2_find(cfg->parking_lots, DEFAULT_PARKING_LOT, OBJ_KEY);
-	if (!lot_cfg) {
-		lot_cfg = parking_lot_cfg_alloc(DEFAULT_PARKING_LOT);
-		if (!lot_cfg) {
-			return -1;
-		}
-		ast_log(AST_LOG_NOTICE, "Adding %s profile to res_parking\n", DEFAULT_PARKING_LOT);
-		aco_set_defaults(&parking_lot_type, DEFAULT_PARKING_LOT, lot_cfg);
-		ast_string_field_set(lot_cfg, parkext, DEFAULT_PARKING_EXTEN);
-		ao2_link(cfg->parking_lots, lot_cfg);
-	}
-
-	return 0;
-}
-
-static void remove_pending_parking_lot_extensions(struct parking_config *cfg_pending)
-{
-	struct parking_lot_cfg *lot_cfg;
-	struct ao2_iterator iter;
-
-	for (iter = ao2_iterator_init(cfg_pending->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
-		parking_lot_cfg_remove_extensions(lot_cfg);
-	}
-
-	ao2_iterator_destroy(&iter);
-
-	ast_context_destroy(NULL, BASE_REGISTRAR);
-
-}
-
-static int configure_parking_extensions(void)
-{
-	struct parking_config *cfg = aco_pending_config(&cfg_info);
-	struct ao2_iterator iter;
-	RAII_VAR(struct parking_lot_cfg *, lot_cfg, NULL, ao2_cleanup);
-	int res = 0;
-
-	if (!cfg) {
-		return 0;
-	}
-
-	/* Clear existing extensions */
-	remove_all_configured_parking_lot_extensions();
-
-	/* Attempt to build new extensions for each lot */
-	for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
-		if (parking_lot_cfg_create_extensions(lot_cfg)) {
-			ao2_cleanup(lot_cfg);
-			lot_cfg = NULL;
-			res = -1;
-			break;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	if (res) {
-		remove_pending_parking_lot_extensions(cfg);
-		ast_log(LOG_ERROR, "Extension registration failed. Previously configured lot extensions were removed and can not be safely restored.\n");
-	}
-
-	return res;
-}
-
-static void mark_lots_as_disabled(void)
-{
-	struct ao2_iterator iter;
-	struct parking_lot *lot;
-
-	for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
-		lot->disable_mark = 1;
-	}
-
-	ao2_iterator_destroy(&iter);
-}
-
-static int config_parking_preapply(void)
-{
-	mark_lots_as_disabled();
-
-	if (verify_default_parking_lot()) {
-		return -1;
-	}
-
-	if (configure_parking_extensions()) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static void disable_marked_lots(void)
-{
-	struct ao2_iterator iter;
-	struct parking_lot *lot;
-
-	for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
-		if (lot->disable_mark) {
-			parking_lot_disable(lot);
-		}
-	}
-
-	ao2_iterator_destroy(&iter);
-}
-
-static void link_configured_disable_marked_lots(void)
-{
-	generate_or_link_lots_to_configs();
-	disable_marked_lots();
-}
-
-const struct ast_module_info *parking_get_module_info(void)
-{
-	return ast_module_info;
-}
-
-static int unload_module(void)
-{
-	unload_parking_bridge_features();
-	remove_all_configured_parking_lot_extensions();
-	unload_parking_applications();
-	unload_parking_manager();
-	unload_parking_ui();
-	unload_parking_devstate();
-	unload_parking_tests();
-	ao2_cleanup(parking_lot_container);
-	parking_lot_container = NULL;
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(globals);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	parking_lot_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-		parking_lot_sort_fn,
-		NULL);
-	if (!parking_lot_container) {
-		goto error;
-	}
-
-	if (aco_info_init(&cfg_info)) {
-		goto error;
-	}
-
-	/* Global options */
-	aco_option_register(&cfg_info, "parkeddynamic", ACO_EXACT, global_options, "no", OPT_BOOL_T, 1, FLDSET(struct parking_global_config, parkeddynamic));
-
-	/* Register the per parking lot options. */
-	aco_option_register(&cfg_info, "parkext", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parkext));
-	aco_option_register(&cfg_info, "context", ACO_EXACT, parking_lot_types, "parkedcalls", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parking_con));
-	aco_option_register(&cfg_info, "parkingtime", ACO_EXACT, parking_lot_types, "45", OPT_UINT_T, 0, FLDSET(struct parking_lot_cfg, parkingtime));
-	aco_option_register(&cfg_info, "comebacktoorigin", ACO_EXACT, parking_lot_types, "yes", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, comebacktoorigin));
-	aco_option_register(&cfg_info, "comebackcontext", ACO_EXACT, parking_lot_types, "parkedcallstimeout", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, comebackcontext));
-	aco_option_register(&cfg_info, "comebackdialtime", ACO_EXACT, parking_lot_types, "30", OPT_UINT_T, 0, FLDSET(struct parking_lot_cfg, comebackdialtime));
-	aco_option_register(&cfg_info, "parkedmusicclass", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, mohclass));
-	aco_option_register(&cfg_info, "parkext_exclusive", ACO_EXACT, parking_lot_types, "no", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, parkext_exclusive));
-	aco_option_register(&cfg_info, "parkinghints", ACO_EXACT, parking_lot_types, "no", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, parkaddhints));
-	aco_option_register(&cfg_info, "courtesytone", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, courtesytone));
-
-	/* More complicated parking lot options that require special handling */
-	aco_option_register_custom(&cfg_info, "parkpos", ACO_EXACT, parking_lot_types, "701-750", option_handler_parkpos, 0);
-	aco_option_register_custom(&cfg_info, "findslot", ACO_EXACT, parking_lot_types, "first", option_handler_findslot, 0);
-	aco_option_register_custom(&cfg_info, "parkedplay", ACO_EXACT, parking_lot_types, "caller", option_handler_parkedfeature, OPT_PARKEDPLAY);
-	aco_option_register_custom(&cfg_info, "parkedcalltransfers", ACO_EXACT, parking_lot_types, "no", option_handler_parkedfeature, OPT_PARKEDTRANSFERS);
-	aco_option_register_custom(&cfg_info, "parkedcallreparking", ACO_EXACT, parking_lot_types, "no", option_handler_parkedfeature, OPT_PARKEDREPARKING);
-	aco_option_register_custom(&cfg_info, "parkedcallhangup", ACO_EXACT, parking_lot_types, "no", option_handler_parkedfeature, OPT_PARKEDHANGUP);
-	aco_option_register_custom(&cfg_info, "parkedcallrecording", ACO_EXACT, parking_lot_types, "no", option_handler_parkedfeature, OPT_PARKEDRECORDING);
-
-	if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
-		goto error;
-	}
-
-	if (load_parking_applications()) {
-		goto error;
-	}
-
-	if (load_parking_ui()) {
-		goto error;
-	}
-
-	if (load_parking_manager()) {
-		goto error;
-	}
-
-	if (load_parking_bridge_features()) {
-		goto error;
-	}
-
-	if (load_parking_devstate()) {
-		goto error;
-	}
-
-	if (load_parking_tests()) {
-		goto error;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-
-error:
-	unload_module();
-	return AST_MODULE_LOAD_DECLINE;
-}
-
-static int reload_module(void)
-{
-	if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Call Parking Resource",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.reload = reload_module,
-);
diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c
index b9c3dbd..4ae7efe 100644
--- a/res/res_phoneprov.c
+++ b/res/res_phoneprov.c
@@ -2,12 +2,10 @@
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 1999 - 2008, Digium, Inc.
- * Copyright (C) 2014, Fairview 5 Engineering, LLC
  *
  * Mark Spencer <markster at digium.com>
  * Matthew Brooks <mbrooks at digium.com>
  * Terry Wilson <twilson at digium.com>
- * George Joseph <george.joseph at fairview5.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -26,24 +24,12 @@
  *
  * \author Matthew Brooks <mbrooks at digium.com>
  * \author Terry Wilson <twilson at digium.com>
- * \author George Joseph <george.joseph at fairview5.com>
-  */
-
-/*! \li \ref res_phoneprov.c uses the configuration file \ref phoneprov.conf and \ref users.conf and \ref sip.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*! 
- * \page phoneprov.conf phoneprov.conf
- * \verbinclude phoneprov.conf.sample
  */
 
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
 
-#define AST_API_MODULE
-
 #include "asterisk.h"
 
 #include <sys/ioctl.h>
@@ -52,7 +38,7 @@
 #ifdef SOLARIS
 #include <sys/sockio.h>
 #endif
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426176 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/file.h"
@@ -70,15 +56,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426176 $")
 #include "asterisk/acl.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/ast_version.h"
-#include "asterisk/phoneprov.h"
 
 #ifdef LOW_MEMORY
-#define MAX_PROVIDER_BUCKETS 1
 #define MAX_PROFILE_BUCKETS 1
 #define MAX_ROUTE_BUCKETS 1
 #define MAX_USER_BUCKETS 1
 #else
-#define MAX_PROVIDER_BUCKETS 17
 #define MAX_PROFILE_BUCKETS 17
 #define MAX_ROUTE_BUCKETS 563
 #define MAX_USER_BUCKETS 563
@@ -93,7 +76,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426176 $")
 		</synopsis>
 		<syntax>
 			<parameter name="mac" required="true" />
-			<parameter name="template_file" required="true" />
+			<parameter name="template" required="true" />
 		</syntax>
 		<description>
 			<para>Output the specified template for each extension associated with the specified MAC address.</para>
@@ -117,162 +100,41 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426176 $")
 	</function>
  ***/
 
-/*!
- * \brief Creates a hash function for a structure string field.
- * \param fname The name to use for the function
- * \param stype The structure type
- * \param field The field in the structure to hash
- *
- * SIMPLE_HASH_FN(mystruct, myfield) will produce a function
- * named mystruct_hash_fn which hashes mystruct->myfield.
- */
-#define SIMPLE_HASH_FN(fname, stype, field) \
-static int fname(const void *obj, const int flags) \
-{ \
-	const struct stype *provider = obj; \
-	const char *key; \
-	switch (flags & OBJ_SEARCH_MASK) { \
-	case OBJ_SEARCH_KEY: \
-		key = obj; \
-		break; \
-	case OBJ_SEARCH_OBJECT: \
-		provider = obj; \
-		key = provider->field; \
-		break; \
-	default: \
-		ast_assert(0); \
-		return 0; \
-	} \
-	return ast_str_hash(key); \
-}
-
-/*!
- * \brief Creates a compare function for a structure string field.
- * \param fname The name to use for the function
- * \param stype The structure type
- * \param field The field in the structure to compare
- *
- * SIMPLE_CMP_FN(mystruct, myfield) will produce a function
- * named mystruct_cmp_fn which compares mystruct->myfield.
- */
-#define SIMPLE_CMP_FN(fname, stype, field) \
-static int fname(void *obj, void *arg, int flags) \
-{ \
-	const struct stype *object_left = obj, *object_right = arg; \
-	const char *right_key = arg; \
-	int cmp; \
-	switch (flags & OBJ_SEARCH_MASK) { \
-	case OBJ_SEARCH_OBJECT: \
-		right_key = object_right->field; \
-	case OBJ_SEARCH_KEY: \
-		cmp = strcmp(object_left->field, right_key); \
-		break; \
-	case OBJ_SEARCH_PARTIAL_KEY: \
-		cmp = strncmp(object_left->field, right_key, strlen(right_key)); \
-		break; \
-	default: \
-		cmp = 0; \
-		break; \
-	} \
-	if (cmp) { \
-		return 0; \
-	} \
-	return CMP_MATCH; \
-}
-
-static const char *variable_lookup[] = {
-	[AST_PHONEPROV_STD_MAC] = "MAC",
-	[AST_PHONEPROV_STD_PROFILE] = "PROFILE",
-	[AST_PHONEPROV_STD_USERNAME] = "USERNAME",
-	[AST_PHONEPROV_STD_DISPLAY_NAME] = "DISPLAY_NAME",
-	[AST_PHONEPROV_STD_SECRET] = "SECRET",
-	[AST_PHONEPROV_STD_LABEL] = "LABEL",
-	[AST_PHONEPROV_STD_CALLERID] = "CALLERID",
-	[AST_PHONEPROV_STD_TIMEZONE] = "TIMEZONE",
-	[AST_PHONEPROV_STD_LINENUMBER] = "LINE",
-	[AST_PHONEPROV_STD_LINEKEYS] = "LINEKEYS",
-	[AST_PHONEPROV_STD_SERVER] = "SERVER",
-	[AST_PHONEPROV_STD_SERVER_PORT] = "SERVER_PORT",
-	[AST_PHONEPROV_STD_SERVER_IFACE] = "SERVER_IFACE",
-	[AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = "VOICEMAIL_EXTEN",
-	[AST_PHONEPROV_STD_EXTENSION_LENGTH] = "EXTENSION_LENGTH",
-	[AST_PHONEPROV_STD_TZOFFSET] = "TZOFFSET",
-	[AST_PHONEPROV_STD_DST_ENABLE] = "DST_ENABLE",
-	[AST_PHONEPROV_STD_DST_START_MONTH] = "DST_START_MONTH",
-	[AST_PHONEPROV_STD_DST_START_MDAY] = "DST_START_MDAY",
-	[AST_PHONEPROV_STD_DST_START_HOUR] = "DST_START_HOUR",
-	[AST_PHONEPROV_STD_DST_END_MONTH] = "DST_END_MONTH",
-	[AST_PHONEPROV_STD_DST_END_MDAY] = "DST_END_MDAY",
-	[AST_PHONEPROV_STD_DST_END_HOUR] = "DST_END_HOUR",
-};
-
-/* Translate the standard variables to their users.conf equivalents. */
-static const char *pp_user_lookup[] = {
-	[AST_PHONEPROV_STD_MAC] = "macaddress",
-	[AST_PHONEPROV_STD_PROFILE] = "profile",
-	[AST_PHONEPROV_STD_USERNAME] = "username",
-	[AST_PHONEPROV_STD_DISPLAY_NAME] = "fullname",
-	[AST_PHONEPROV_STD_SECRET] = "secret",
-	[AST_PHONEPROV_STD_LABEL] = "label",
-	[AST_PHONEPROV_STD_CALLERID] = "cid_number",
-	[AST_PHONEPROV_STD_TIMEZONE] = "timezone",
-	[AST_PHONEPROV_STD_LINENUMBER] = "linenumber",
-	[AST_PHONEPROV_STD_LINEKEYS] = "linekeys",
-	[AST_PHONEPROV_STD_SERVER] = NULL,
-	[AST_PHONEPROV_STD_SERVER_PORT] = NULL,
-	[AST_PHONEPROV_STD_SERVER_IFACE] = NULL,
-	[AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = "vmexten",
-	[AST_PHONEPROV_STD_EXTENSION_LENGTH] = "localextenlength",
-	[AST_PHONEPROV_STD_TZOFFSET] = NULL,
-	[AST_PHONEPROV_STD_DST_ENABLE] = NULL,
-	[AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
-	[AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
-	[AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
-	[AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
-	[AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
-	[AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
-};
-
-/* Translate the standard variables to their phoneprov.conf [general] equivalents. */
-static const char *pp_general_lookup[] = {
-	[AST_PHONEPROV_STD_MAC] = NULL,
-	[AST_PHONEPROV_STD_PROFILE] = "default_profile",
-	[AST_PHONEPROV_STD_USERNAME] = NULL,
-	[AST_PHONEPROV_STD_DISPLAY_NAME] = NULL,
-	[AST_PHONEPROV_STD_SECRET] = NULL,
-	[AST_PHONEPROV_STD_LABEL] = NULL,
-	[AST_PHONEPROV_STD_CALLERID] = NULL,
-	[AST_PHONEPROV_STD_TIMEZONE] = NULL,
-	[AST_PHONEPROV_STD_LINENUMBER] = NULL,
-	[AST_PHONEPROV_STD_LINEKEYS] = NULL,
-	[AST_PHONEPROV_STD_SERVER] = "serveraddr",
-	[AST_PHONEPROV_STD_SERVER_PORT] = "serverport",
-	[AST_PHONEPROV_STD_SERVER_IFACE] = "serveriface",
-	[AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = NULL,
-	[AST_PHONEPROV_STD_EXTENSION_LENGTH] = NULL,
-	[AST_PHONEPROV_STD_TZOFFSET] = NULL,
-	[AST_PHONEPROV_STD_DST_ENABLE] = NULL,
-	[AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
-	[AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
-	[AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
-	[AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
-	[AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
-	[AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
-};
-
 /*! \brief for use in lookup_iface */
 static struct in_addr __ourip = { .s_addr = 0x00000000, };
 
-/*! \brief structure to hold config providers */
-struct phoneprov_provider {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(provider_name);
-	);
-	ast_phoneprov_load_users_cb load_users;
+/* \note This enum and the pp_variable_list must be in the same order or
+ * bad things happen! */
+enum pp_variables {
+	PP_MACADDRESS,
+	PP_USERNAME,
+	PP_FULLNAME,
+	PP_SECRET,
+	PP_LABEL,
+	PP_CALLERID,
+	PP_TIMEZONE,
+	PP_LINENUMBER,
+	PP_LINEKEYS,
+	PP_VAR_LIST_LENGTH,	/* This entry must always be the last in the list */
+};
+
+/*! \brief Lookup table to translate between users.conf property names and
+ * variables for use in phoneprov templates */
+static const struct pp_variable_lookup {
+	enum pp_variables id;
+	const char * const user_var;
+	const char * const template_var;
+} pp_variable_list[] = {
+	{ PP_MACADDRESS, "macaddress", "MAC" },
+	{ PP_USERNAME, "username", "USERNAME" },
+	{ PP_FULLNAME, "fullname", "DISPLAY_NAME" },
+	{ PP_SECRET, "secret", "SECRET" },
+	{ PP_LABEL, "label", "LABEL" },
+	{ PP_CALLERID, "cid_number", "CALLERID" },
+	{ PP_TIMEZONE, "timezone", "TIMEZONE" },
+	{ PP_LINENUMBER, "linenumber", "LINE" },
+ 	{ PP_LINEKEYS, "linekeys", "LINEKEYS" },
 };
-struct ao2_container *providers;
-SIMPLE_HASH_FN(phoneprov_provider_hash_fn, phoneprov_provider, provider_name)
-SIMPLE_CMP_FN(phoneprov_provider_cmp_fn, phoneprov_provider, provider_name)
 
 /*! \brief structure to hold file data */
 struct phoneprov_file {
@@ -284,16 +146,6 @@ struct phoneprov_file {
 	AST_LIST_ENTRY(phoneprov_file) entry;
 };
 
-/*! \brief structure to hold extensions */
-struct extension {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);
-	);
-	int index;
-	struct varshead *headp;	/*!< List of variables to substitute into templates */
-	AST_LIST_ENTRY(extension) entry;
-};
-
 /*! \brief structure to hold phone profiles read from phoneprov.conf */
 struct phone_profile {
 	AST_DECLARE_STRING_FIELDS(
@@ -305,22 +157,24 @@ struct phone_profile {
 	AST_LIST_HEAD_NOLOCK(, phoneprov_file) static_files;	/*!< List of static files */
 	AST_LIST_HEAD_NOLOCK(, phoneprov_file) dynamic_files;	/*!< List of dynamic files */
 };
-struct ao2_container *profiles;
-SIMPLE_HASH_FN(phone_profile_hash_fn, phone_profile, name)
-SIMPLE_CMP_FN(phone_profile_cmp_fn, phone_profile, name)
+
+struct extension {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(name);
+	);
+	int index;
+	struct varshead *headp;	/*!< List of variables to substitute into templates */
+	AST_LIST_ENTRY(extension) entry;
+};
 
 /*! \brief structure to hold users read from users.conf */
 struct user {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(macaddress);	/*!< Mac address of user's phone */
-		AST_STRING_FIELD(provider_name);	/*!< Name of the provider who registered this mac */
 	);
 	struct phone_profile *profile;	/*!< Profile the phone belongs to */
 	AST_LIST_HEAD_NOLOCK(, extension) extensions;
 };
-struct ao2_container *users;
-SIMPLE_HASH_FN(user_hash_fn, user, macaddress)
-SIMPLE_CMP_FN(user_cmp_fn, user, macaddress)
 
 /*! \brief structure to hold http routes (valid URIs, and the files they link to) */
 struct http_route {
@@ -330,13 +184,19 @@ struct http_route {
 	struct phoneprov_file *file;	/*!< The file that links to the URI */
 	struct user *user;	/*!< The user that has variables to substitute into the file
 						 * NULL in the case of a static route */
-	struct phone_profile *profile;
 };
-struct ao2_container *http_routes;
-SIMPLE_HASH_FN(http_route_hash_fn, http_route, uri)
-SIMPLE_CMP_FN(http_route_cmp_fn, http_route, uri)
 
-#define SIPUSERS_PROVIDER_NAME "sipusers"
+static struct ao2_container *profiles;
+static struct ao2_container *http_routes;
+static struct ao2_container *users;
+
+static char global_server[80] = "";	/*!< Server to substitute into templates */
+static char global_serverport[6] = "";	/*!< Server port to substitute into templates */
+static char global_default_profile[80] = "";	/*!< Default profile to use if one isn't specified */
+
+/*! \brief List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH */
+static struct varshead global_variables;
+static ast_mutex_t globals_lock;
 
 /* iface is the interface (e.g. eth0); address is the return value */
 static int lookup_iface(const char *iface, struct in_addr *address)
@@ -369,25 +229,35 @@ static int lookup_iface(const char *iface, struct in_addr *address)
 	}
 }
 
-static struct phoneprov_provider *find_provider(char *name)
+static struct phone_profile *unref_profile(struct phone_profile *prof)
+{
+	ao2_ref(prof, -1);
+
+	return NULL;
+}
+
+/*! \brief Return a phone profile looked up by name */
+static struct phone_profile *find_profile(const char *name)
 {
-	return ao2_find(providers, name, OBJ_SEARCH_KEY);
+	struct phone_profile tmp = {
+		.name = name,
+	};
+
+	return ao2_find(profiles, &tmp, OBJ_POINTER);
 }
 
-/*! \brief Delete all providers */
-static void delete_providers(void)
+static int profile_hash_fn(const void *obj, const int flags)
 {
-	if (!providers) {
-		return;
-	}
+	const struct phone_profile *profile = obj;
 
-	ao2_callback(providers, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+	return ast_str_case_hash(profile->name);
 }
 
-static void provider_destructor(void *obj)
+static int profile_cmp_fn(void *obj, void *arg, int flags)
 {
-	struct phoneprov_provider *provider = obj;
-	ast_string_field_free_memory(provider);
+	const struct phone_profile *profile1 = obj, *profile2 = arg;
+
+	return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static void delete_file(struct phoneprov_file *file)
@@ -396,6 +266,53 @@ static void delete_file(struct phoneprov_file *file)
 	free(file);
 }
 
+static void profile_destructor(void *obj)
+{
+	struct phone_profile *profile = obj;
+	struct phoneprov_file *file;
+	struct ast_var_t *var;
+
+	while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry)))
+		delete_file(file);
+
+	while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry)))
+		delete_file(file);
+
+	while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries)))
+		ast_var_delete(var);
+
+	ast_free(profile->headp);
+	ast_string_field_free_memory(profile);
+}
+
+static struct http_route *unref_route(struct http_route *route)
+{
+	ao2_ref(route, -1);
+
+	return NULL;
+}
+
+static int routes_hash_fn(const void *obj, const int flags)
+{
+	const struct http_route *route = obj;
+
+	return ast_str_case_hash(route->uri);
+}
+
+static int routes_cmp_fn(void *obj, void *arg, int flags)
+{
+	const struct http_route *route1 = obj, *route2 = arg;
+
+	return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static void route_destructor(void *obj)
+{
+	struct http_route *route = obj;
+
+	ast_string_field_free_memory(route);
+}
+
 /*! \brief Read a TEXT file into a string and return the length */
 static int load_file(const char *filename, char **ret)
 {
@@ -439,66 +356,189 @@ static void set_timezone_variables(struct varshead *headp, const char *zone)
 	struct ast_tm tm_info;
 	int tzoffset;
 	char buffer[21];
+	struct ast_var_t *var;
 	struct timeval when;
 
 	time(&utc_time);
 	ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone);
 	snprintf(buffer, sizeof(buffer), "%d", tzoffset);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("TZOFFSET", buffer));
+	var = ast_var_assign("TZOFFSET", buffer);
+	if (var)
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
-	if (!dstenable) {
+	if (!dstenable)
 		return;
-	}
 
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_ENABLE", "1"));
+	if ((var = ast_var_assign("DST_ENABLE", "1")))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	when.tv_sec = dststart;
 	ast_localtime(&when, &tm_info, zone);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_MONTH", buffer));
+	if ((var = ast_var_assign("DST_START_MONTH", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_MDAY", buffer));
+	if ((var = ast_var_assign("DST_START_MDAY", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_START_HOUR", buffer));
+	if ((var = ast_var_assign("DST_START_HOUR", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	when.tv_sec = dstend;
 	ast_localtime(&when, &tm_info, zone);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_MONTH", buffer));
+	if ((var = ast_var_assign("DST_END_MONTH", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_MDAY", buffer));
+	if ((var = ast_var_assign("DST_END_MDAY", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 
 	snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
-	AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign("DST_END_HOUR", buffer));
+	if ((var = ast_var_assign("DST_END_HOUR", buffer)))
+		AST_LIST_INSERT_TAIL(headp, var, entries);
 }
 
-static struct http_route *unref_route(struct http_route *route)
+/*! \brief Callback that is executed everytime an http request is received by this module */
+static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
 {
-	ao2_cleanup(route);
+	struct http_route *route;
+	struct http_route search_route = {
+		.uri = uri,
+	};
+	struct ast_str *result;
+	char path[PATH_MAX];
+	char *file = NULL;
+	int len;
+	int fd;
+	struct ast_str *http_header;
 
-	return NULL;
-}
+	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
+		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
+		return -1;
+	}
 
-static void route_destructor(void *obj)
-{
-	struct http_route *route = obj;
+	if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
+		goto out404;
+	}
 
-	ast_string_field_free_memory(route);
-}
+	snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template);
 
-/*! \brief Delete all http routes, freeing their memory */
-static void delete_routes(void)
-{
-	if (!http_routes) {
-		return;
+	if (!route->user) { /* Static file */
+
+		fd = open(path, O_RDONLY);
+		if (fd < 0) {
+			goto out500;
+		}
+
+		len = lseek(fd, 0, SEEK_END);
+		lseek(fd, 0, SEEK_SET);
+		if (len < 0) {
+			ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
+			close(fd);
+			goto out500;
+		}
+
+		http_header = ast_str_create(80);
+		ast_str_set(&http_header, 0, "Content-type: %s\r\n",
+			route->file->mime_type);
+
+		ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0);
+
+		close(fd);
+		route = unref_route(route);
+		return 0;
+	} else { /* Dynamic file */
+		struct ast_str *tmp;
+
+		len = load_file(path, &file);
+		if (len < 0) {
+			ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
+			if (file) {
+				ast_free(file);
+			}
+
+			goto out500;
+		}
+
+		if (!file) {
+			goto out500;
+		}
+
+		if (!(tmp = ast_str_create(len))) {
+			if (file) {
+				ast_free(file);
+			}
+
+			goto out500;
+		}
+
+		/* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to
+		 * the IP address we are listening on that the phone contacted for this config file */
+		if (ast_strlen_zero(global_server)) {
+			union {
+				struct sockaddr sa;
+				struct sockaddr_in sa_in;
+			} name;
+			socklen_t namelen = sizeof(name.sa);
+			int res;
+
+			if ((res = getsockname(ser->fd, &name.sa, &namelen))) {
+				ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n");
+			} else {
+				struct ast_var_t *var;
+				struct extension *exten_iter;
+
+				if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) {
+					AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) {
+						AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries);
+					}
+				}
+			}
+		}
+
+		ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file);
+
+		if (file) {
+			ast_free(file);
+		}
+
+		http_header = ast_str_create(80);
+		ast_str_set(&http_header, 0, "Content-type: %s\r\n",
+			route->file->mime_type);
+
+		if (!(result = ast_str_create(512))) {
+			ast_log(LOG_ERROR, "Could not create result string!\n");
+			if (tmp) {
+				ast_free(tmp);
+			}
+			ast_free(http_header);
+			goto out500;
+		}
+		ast_str_append(&result, 0, "%s", ast_str_buffer(tmp)); 
+
+		ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0);
+		if (tmp) {
+			ast_free(tmp);
+		}
+
+		route = unref_route(route);
+
+		return 0;
 	}
 
-	ao2_callback(http_routes, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+out404:
+	ast_http_error(ser, 404, "Not Found", "Nothing to see here.  Move along.");
+	return -1;
+
+out500:
+	route = unref_route(route);
+	ast_http_error(ser, 500, "Internal Error", "An internal error has occured.");
+	return -1;
 }
 
 /*! \brief Build a route structure and add it to the list of available http routes
@@ -506,7 +546,7 @@ static void delete_routes(void)
 	\param user User to link to the route (NULL means static route)
 	\param uri URI of the route
 */
-static void build_route(struct phoneprov_file *pp_file, struct phone_profile *profile, struct user *user, char *uri)
+static void build_route(struct phoneprov_file *pp_file, struct user *user, char *uri)
 {
 	struct http_route *route;
 
@@ -523,88 +563,44 @@ static void build_route(struct phoneprov_file *pp_file, struct phone_profile *pr
 	ast_string_field_set(route, uri, S_OR(uri, pp_file->format));
 	route->user = user;
 	route->file = pp_file;
-	route->profile = profile;
 
 	ao2_link(http_routes, route);
 
 	route = unref_route(route);
 }
 
-static struct phone_profile *unref_profile(struct phone_profile *prof)
-{
-	ao2_cleanup(prof);
-
-	return NULL;
-}
-
-/*! \brief Return a phone profile looked up by name */
-static struct phone_profile *find_profile(const char *name)
-{
-	return ao2_find(profiles, name, OBJ_SEARCH_KEY);
-}
-
-static void profile_destructor(void *obj)
+/*! \brief Build a phone profile and add it to the list of phone profiles
+	\param name the name of the profile
+	\param v ast_variable from parsing phoneprov.conf
+*/
+static void build_profile(const char *name, struct ast_variable *v)
 {
-	struct phone_profile *profile = obj;
-	struct phoneprov_file *file;
+	struct phone_profile *profile;
 	struct ast_var_t *var;
 
-	while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry))) {
-		delete_file(file);
+	if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) {
+		return;
 	}
 
-	while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry))) {
-		delete_file(file);
+	if (ast_string_field_init(profile, 32)) {
+		profile = unref_profile(profile);
+		return;
 	}
 
-	while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries))) {
-		ast_var_delete(var);
+	if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) {
+		profile = unref_profile(profile);
+		return;
 	}
 
-	ast_free(profile->headp);
-	ast_string_field_free_memory(profile);
-}
-
-/*! \brief Delete all phone profiles, freeing their memory */
-static void delete_profiles(void)
-{
-	if (!profiles) {
-		return;
-	}
-
-	ao2_callback(profiles, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-}
-
-/*! \brief Build a phone profile and add it to the list of phone profiles
-	\param name the name of the profile
-	\param v ast_variable from parsing phoneprov.conf
-*/
-static void build_profile(const char *name, struct ast_variable *v)
-{
-	struct phone_profile *profile;
-
-	if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) {
-		return;
-	}
-
-	if (ast_string_field_init(profile, 32)) {
-		profile = unref_profile(profile);
-		return;
-	}
-
-	if (!(profile->headp = ast_var_list_create())) {
-		profile = unref_profile(profile);
-		return;
-	}
-
-	AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files);
-	AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files);
+	AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files);
+	AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files);
 
 	ast_string_field_set(profile, name, name);
 	for (; v; v = v->next) {
 		if (!strcasecmp(v->name, "mime_type")) {
 			ast_string_field_set(profile, default_mime_type, v->value);
 		} else if (!strcasecmp(v->name, "setvar")) {
+			struct ast_var_t *variable;
 			char *value_copy = ast_strdupa(v->value);
 
 			AST_DECLARE_APP_ARGS(args,
@@ -620,7 +616,8 @@ static void build_profile(const char *name, struct ast_variable *v)
 				args.varval = ast_strip(args.varval);
 				if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
 					break;
-				AST_VAR_LIST_INSERT_TAIL(profile->headp, ast_var_assign(args.varname, args.varval));
+				if ((variable = ast_var_assign(args.varname, args.varval)))
+					AST_LIST_INSERT_TAIL(profile->headp, variable, entries);
 			} while (0);
 		} else if (!strcasecmp(v->name, "staticdir")) {
 			ast_string_field_set(profile, staticdir, v->value);
@@ -658,7 +655,7 @@ static void build_profile(const char *name, struct ast_variable *v)
 				ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename);
 				AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry);
 				/* Add a route for the static files, as their filenames won't change per-user */
-				build_route(pp_file, profile, NULL, NULL);
+				build_route(pp_file, NULL, NULL);
 			} else {
 				ast_string_field_set(pp_file, format, v->name);
 				ast_string_field_set(pp_file, template, args.filename);
@@ -667,6 +664,18 @@ static void build_profile(const char *name, struct ast_variable *v)
 		}
 	}
 
+	/* Append the global variables to the variables list for this profile.
+	 * This is for convenience later, when we need to provide a single
+	 * variable list for use in substitution. */
+	ast_mutex_lock(&globals_lock);
+	AST_LIST_TRAVERSE(&global_variables, var, entries) {
+		struct ast_var_t *new_var;
+		if ((new_var = ast_var_assign(var->name, var->value))) {
+			AST_LIST_INSERT_TAIL(profile->headp, new_var, entries);
+		}
+	}
+	ast_mutex_unlock(&globals_lock);
+
 	ao2_link(profiles, profile);
 
 	profile = unref_profile(profile);
@@ -674,17 +683,24 @@ static void build_profile(const char *name, struct ast_variable *v)
 
 static struct extension *delete_extension(struct extension *exten)
 {
-	ast_var_list_destroy(exten->headp);
+	struct ast_var_t *var;
+	while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) {
+		ast_var_delete(var);
+	}
+	ast_free(exten->headp);
 	ast_string_field_free_memory(exten);
+
 	ast_free(exten);
 
 	return NULL;
 }
 
-static struct extension *build_extension(const char *name, struct varshead *vars)
+static struct extension *build_extension(struct ast_config *cfg, const char *name)
 {
 	struct extension *exten;
+	struct ast_var_t *var;
 	const char *tmp;
+	int i;
 
 	if (!(exten = ast_calloc_with_stringfields(1, struct extension, 32))) {
 		return NULL;
@@ -692,36 +708,56 @@ static struct extension *build_extension(const char *name, struct varshead *vars
 
 	ast_string_field_set(exten, name, name);
 
-	exten->headp = ast_var_list_clone(vars);
-	if (!exten->headp) {
-		ast_log(LOG_ERROR, "Unable to clone variables for extension '%s'\n", name);
-		delete_extension(exten);
+	if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) {
+		ast_free(exten);
+		exten = NULL;
 		return NULL;
 	}
 
-	tmp = ast_var_find(exten->headp, variable_lookup[AST_PHONEPROV_STD_LINENUMBER]);
-	if (!tmp) {
-		AST_VAR_LIST_INSERT_TAIL(exten->headp,
-			ast_var_assign(variable_lookup[AST_PHONEPROV_STD_LINENUMBER], "1"));
-		exten->index = 1;
-	} else {
-		sscanf(tmp, "%d", &exten->index);
+	for (i = 0; i < PP_VAR_LIST_LENGTH; i++) {
+		tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var);
+
+		/* If we didn't get a USERNAME variable, set it to the user->name */
+		if (i == PP_USERNAME && !tmp) {
+			if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) {
+				AST_LIST_INSERT_TAIL(exten->headp, var, entries);
+			}
+			continue;
+		} else if (i == PP_TIMEZONE) {
+			/* perfectly ok if tmp is NULL, will set variables based on server's time zone */
+			set_timezone_variables(exten->headp, tmp);
+		} else if (i == PP_LINENUMBER) {
+			if (!tmp) {
+				tmp = "1";
+			}
+			exten->index = atoi(tmp);
+		} else if (i == PP_LINEKEYS) {
+			if (!tmp) {
+				tmp = "1";
+			}
+		}
+
+		if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) {
+			AST_LIST_INSERT_TAIL(exten->headp, var, entries);
+		}
 	}
 
-	if (!ast_var_find(exten->headp, variable_lookup[AST_PHONEPROV_STD_LINEKEYS])) {
-		AST_VAR_LIST_INSERT_TAIL(exten->headp,
-			ast_var_assign(variable_lookup[AST_PHONEPROV_STD_LINEKEYS], "1"));
+	if (!ast_strlen_zero(global_server)) {
+		if ((var = ast_var_assign("SERVER", global_server)))
+			AST_LIST_INSERT_TAIL(exten->headp, var, entries);
 	}
 
-	set_timezone_variables(exten->headp,
-		ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_TIMEZONE]));
+	if (!ast_strlen_zero(global_serverport)) {
+		if ((var = ast_var_assign("SERVER_PORT", global_serverport)))
+			AST_LIST_INSERT_TAIL(exten->headp, var, entries);
+	}
 
 	return exten;
 }
 
 static struct user *unref_user(struct user *user)
 {
-	ao2_cleanup(user);
+	ao2_ref(user, -1);
 
 	return NULL;
 }
@@ -729,19 +765,25 @@ static struct user *unref_user(struct user *user)
 /*! \brief Return a user looked up by name */
 static struct user *find_user(const char *macaddress)
 {
-	return ao2_find(users, macaddress, OBJ_SEARCH_KEY);
+	struct user tmp = {
+		.macaddress = macaddress,
+	};
+
+	return ao2_find(users, &tmp, OBJ_POINTER);
 }
 
-static int routes_delete_cb(void *obj, void *arg, int flags)
+static int users_hash_fn(const void *obj, const int flags)
 {
-	struct http_route *route = obj;
-	struct user *user = route->user;
-	char *macaddress = arg;
+	const struct user *user = obj;
 
-	if (user && !strcmp(user->macaddress, macaddress)) {
-		return CMP_MATCH;
-	}
-	return 0;
+	return ast_str_case_hash(user->macaddress);
+}
+
+static int users_cmp_fn(void *obj, void *arg, int flags)
+{
+	const struct user *user1 = obj, *user2 = arg;
+
+	return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 /*! \brief Free all memory associated with a user */
@@ -758,41 +800,41 @@ static void user_destructor(void *obj)
 		user->profile = unref_profile(user->profile);
 	}
 
-	if (http_routes) {
-		ao2_callback(http_routes, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, routes_delete_cb, (void *)user->macaddress);
-	}
-
 	ast_string_field_free_memory(user);
 }
 
 /*! \brief Delete all users */
 static void delete_users(void)
 {
-	if (!users) {
-		return;
-	}
+	struct ao2_iterator i;
+	struct user *user;
 
-	ao2_callback(users, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+	i = ao2_iterator_init(users, 0);
+	while ((user = ao2_iterator_next(&i))) {
+		ao2_unlink(users, user);
+		user = unref_user(user);
+	}
+	ao2_iterator_destroy(&i);
 }
 
 /*! \brief Build and return a user structure based on gathered config data */
-static struct user *build_user(const char *mac, struct phone_profile *profile, char *provider_name)
+static struct user *build_user(const char *mac, struct phone_profile *profile)
 {
 	struct user *user;
 
 	if (!(user = ao2_alloc(sizeof(*user), user_destructor))) {
+		profile = unref_profile(profile);
 		return NULL;
 	}
 
-	if (ast_string_field_init(user, 64)) {
+	if (ast_string_field_init(user, 32)) {
+		profile = unref_profile(profile);
 		user = unref_user(user);
 		return NULL;
 	}
 
 	ast_string_field_set(user, macaddress, mac);
-	ast_string_field_set(user, provider_name, provider_name);
-	user->profile = profile;
-	ao2_ref(profile, 1);
+	user->profile = profile; /* already ref counted by find_profile */
 
 	return user;
 }
@@ -800,7 +842,7 @@ static struct user *build_user(const char *mac, struct phone_profile *profile, c
 /*! \brief Add an extension to a user ordered by index/linenumber */
 static int add_user_extension(struct user *user, struct extension *exten)
 {
-	struct ast_var_t *pvar, *var2;
+	struct ast_var_t *var;
 	struct ast_str *str = ast_str_create(16);
 
 	if (!str) {
@@ -809,16 +851,15 @@ static int add_user_extension(struct user *user, struct extension *exten)
 
 	/* Append profile variables here, and substitute variables on profile
 	 * setvars, so that we can use user specific variables in them */
-	AST_VAR_LIST_TRAVERSE(user->profile->headp, pvar) {
-		if (ast_var_find(exten->headp, pvar->name)) {
-			continue;
-		}
+	AST_LIST_TRAVERSE(user->profile->headp, var, entries) {
+		struct ast_var_t *var2;
 
-		ast_str_substitute_variables_varshead(&str, 0, exten->headp, pvar->value);
-		if ((var2 = ast_var_assign(pvar->name, ast_str_buffer(str)))) {
-			AST_VAR_LIST_INSERT_TAIL(exten->headp, var2);
+		ast_str_substitute_variables_varshead(&str, 0, exten->headp, var->value);
+		if ((var2 = ast_var_assign(var->name, ast_str_buffer(str)))) {
+			AST_LIST_INSERT_TAIL(exten->headp, var2, entries);
 		}
 	}
+
 	ast_free(str);
 
 	if (AST_LIST_EMPTY(&user->extensions)) {
@@ -854,146 +895,187 @@ static int build_user_routes(struct user *user)
 
 	AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) {
 		ast_str_substitute_variables_varshead(&str, 0, AST_LIST_FIRST(&user->extensions)->headp, pp_file->format);
-		build_route(pp_file, user->profile, user, ast_str_buffer(str));
+		build_route(pp_file, user, ast_str_buffer(str));
 	}
 
 	ast_free(str);
 	return 0;
 }
 
-/*! \brief Callback that is executed everytime an http request is received by this module */
-static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
+/* \brief Parse config files and create appropriate structures */
+static int set_config(void)
 {
-	struct http_route *route;
-	struct ast_str *result;
-	char path[PATH_MAX];
-	char *file = NULL;
-	char *server;
-	int len;
-	int fd;
-	struct ast_str *http_header;
+	struct ast_config *cfg, *phoneprov_cfg;
+	char *cat;
+	struct ast_variable *v;
+	struct ast_flags config_flags = { 0 };
+	struct ast_var_t *var;
 
-	if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
-		ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
-		return 0;
+	/* Try to grab the port from sip.conf.  If we don't get it here, we'll set it
+	 * to whatever is set in phoneprov.conf or default to 5060 */
+	if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
+		ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport));
+		ast_config_destroy(cfg);
 	}
 
-	if (!(route = ao2_find(http_routes, uri, OBJ_SEARCH_KEY))) {
-		goto out404;
+	if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "Unable to load users.conf\n");
+		return 0;
 	}
 
-	snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template);
-
-	if (!route->user) { /* Static file */
-
-		fd = open(path, O_RDONLY);
-		if (fd < 0) {
-			goto out500;
+	/* Go ahead and load global variables from users.conf so we can append to profiles */
+	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+		if (!strcasecmp(v->name, "vmexten")) {
+			if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) {
+				ast_mutex_lock(&globals_lock);
+				AST_LIST_INSERT_TAIL(&global_variables, var, entries);
+				ast_mutex_unlock(&globals_lock);
+			}
 		}
-
-		len = lseek(fd, 0, SEEK_END);
-		lseek(fd, 0, SEEK_SET);
-		if (len < 0) {
-			ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
-			close(fd);
-			goto out500;
+		if (!strcasecmp(v->name, "localextenlength")) {
+			if ((var = ast_var_assign("EXTENSION_LENGTH", v->value)))
+				ast_mutex_lock(&globals_lock);
+				AST_LIST_INSERT_TAIL(&global_variables, var, entries);
+				ast_mutex_unlock(&globals_lock);
 		}
+	}
 
-		http_header = ast_str_create(80);
-		ast_str_set(&http_header, 0, "Content-type: %s\r\n",
-			route->file->mime_type);
+	if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
+		ast_config_destroy(cfg);
+		return -1;
+	}
 
-		ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0);
+	cat = NULL;
+	while ((cat = ast_category_browse(phoneprov_cfg, cat))) {
+		if (!strcasecmp(cat, "general")) {
+			for (v = ast_variable_browse(phoneprov_cfg, cat); v; v = v->next) {
+				if (!strcasecmp(v->name, "serveraddr"))
+					ast_copy_string(global_server, v->value, sizeof(global_server));
+				else if (!strcasecmp(v->name, "serveriface")) {
+					struct in_addr addr;
+					lookup_iface(v->value, &addr);
+					ast_copy_string(global_server, ast_inet_ntoa(addr), sizeof(global_server));
+				} else if (!strcasecmp(v->name, "serverport"))
+					ast_copy_string(global_serverport, v->value, sizeof(global_serverport));
+				else if (!strcasecmp(v->name, "default_profile"))
+					ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile));
+			}
+		} else
+			build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
+	}
 
-		close(fd);
-		route = unref_route(route);
-		return 0;
-	} else { /* Dynamic file */
-		struct ast_str *tmp;
+	ast_config_destroy(phoneprov_cfg);
 
-		len = load_file(path, &file);
-		if (len < 0) {
-			ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
-			if (file) {
-				ast_free(file);
-			}
+	cat = NULL;
+	while ((cat = ast_category_browse(cfg, cat))) {
+		const char *tmp, *mac;
+		struct user *user;
+		struct phone_profile *profile;
+		struct extension *exten;
 
-			goto out500;
+		if (!strcasecmp(cat, "general")) {
+			continue;
 		}
 
-		if (!file) {
-			goto out500;
-		}
+		if (!strcasecmp(cat, "authentication"))
+			continue;
 
-		if (!(tmp = ast_str_create(len))) {
-			if (file) {
-				ast_free(file);
-			}
+		if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp)))
+			continue;
 
-			goto out500;
+		if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) {
+			ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat);
+			continue;
 		}
 
-		/* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to
-		 * the IP address we are listening on that the phone contacted for this config file */
-
-		server = ast_var_find(AST_LIST_FIRST(&route->user->extensions)->headp,
-			variable_lookup[AST_PHONEPROV_STD_SERVER]);
+		tmp = S_OR(ast_variable_retrieve(cfg, cat, "profile"), global_default_profile);
+		if (ast_strlen_zero(tmp)) {
+			ast_log(LOG_WARNING, "No profile for user [%s] with mac '%s' - skipping\n", cat, mac);
+			continue;
+		}
 
-		if (!server) {
-			union {
-				struct sockaddr sa;
-				struct sockaddr_in sa_in;
-			} name;
-			socklen_t namelen = sizeof(name.sa);
-			int res;
+		if (!(user = find_user(mac))) {
+			if (!(profile = find_profile(tmp))) {
+				ast_log(LOG_WARNING, "Could not look up profile '%s' - skipping.\n", tmp);
+				continue;
+			}
 
-			if ((res = getsockname(ser->fd, &name.sa, &namelen))) {
-				ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n");
-			} else {
-				struct extension *exten_iter;
-				const char *newserver = ast_inet_ntoa(name.sa_in.sin_addr);
+			if (!(user = build_user(mac, profile))) {
+				ast_log(LOG_WARNING, "Could not create user for '%s' - skipping\n", mac);
+				continue;
+			}
 
-				AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) {
-					AST_VAR_LIST_INSERT_TAIL(exten_iter->headp,
-						ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER], newserver));
-				}
+			if (!(exten = build_extension(cfg, cat))) {
+				ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
+				user = unref_user(user);
+				continue;
 			}
-		}
 
-		ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file);
+			if (add_user_extension(user, exten)) {
+				ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
+				user = unref_user(user);
+				exten = delete_extension(exten);
+				continue;
+			}
 
-		ast_free(file);
+			if (build_user_routes(user)) {
+				ast_log(LOG_WARNING, "Could not create http routes for %s - skipping\n", user->macaddress);
+				user = unref_user(user);
+				continue;
+			}
 
-		http_header = ast_str_create(80);
-		ast_str_set(&http_header, 0, "Content-type: %s\r\n",
-			route->file->mime_type);
+			ao2_link(users, user);
+			user = unref_user(user);
+		} else {
+			if (!(exten = build_extension(cfg, cat))) {
+				ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
+				user = unref_user(user);
+				continue;
+			}
 
-		if (!(result = ast_str_create(512))) {
-			ast_log(LOG_ERROR, "Could not create result string!\n");
-			if (tmp) {
-				ast_free(tmp);
+			if (add_user_extension(user, exten)) {
+				ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
+				user = unref_user(user);
+				exten = delete_extension(exten);
+				continue;
 			}
-			ast_free(http_header);
-			goto out500;
+
+			user = unref_user(user);
 		}
-		ast_str_append(&result, 0, "%s", ast_str_buffer(tmp));
+	}
 
-		ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0);
-		ast_free(tmp);
+	ast_config_destroy(cfg);
 
-		route = unref_route(route);
+	return 0;
+}
 
-		return 0;
+/*! \brief Delete all http routes, freeing their memory */
+static void delete_routes(void)
+{
+	struct ao2_iterator i;
+	struct http_route *route;
+
+	i = ao2_iterator_init(http_routes, 0);
+	while ((route = ao2_iterator_next(&i))) {
+		ao2_unlink(http_routes, route);
+		route = unref_route(route);
 	}
+	ao2_iterator_destroy(&i);
+}
 
-out404:
-	ast_http_error(ser, 404, "Not Found", uri);
-	return 0;
+/*! \brief Delete all phone profiles, freeing their memory */
+static void delete_profiles(void)
+{
+	struct ao2_iterator i;
+	struct phone_profile *profile;
 
-out500:
-	route = unref_route(route);
-	ast_http_error(ser, 500, "Internal Error", "An internal error has occured.");
-	return 0;
+	i = ao2_iterator_init(profiles, 0);
+	while ((profile = ao2_iterator_next(&i))) {
+		ao2_unlink(profiles, profile);
+		profile = unref_profile(profile);
+	}
+	ao2_iterator_destroy(&i);
 }
 
 /*! \brief A dialplan function that can be used to print a string for each phoneprov user */
@@ -1131,27 +1213,13 @@ static struct ast_custom_function pp_each_extension_function = {
 	.read2 = pp_each_extension_read2,
 };
 
-#define FORMATS "%-20.20s %-40.40s  %-30.30s\n"
-#define FORMATD "%-20.20s %-20.20s %-40.40s  %-30.30s\n"
-static int route_list_cb(void *obj, void *arg, void *data, int flags)
-{
-	int fd = *(int *)arg;
-	struct http_route *route = obj;
-
-	if (data && route->user) {
-		ast_cli(fd, FORMATD, route->user->provider_name, route->profile->name, route->uri, route->file->template);
-	}
-	if (!data && !route->user) {
-		ast_cli(fd, FORMATS, route->profile->name, route->uri, route->file->template);
-	}
-
-	return CMP_MATCH;
-}
-
 /*! \brief CLI command to list static and dynamic routes */
 static char *handle_show_routes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	int fd = a->fd;
+#define FORMAT "%-40.40s  %-30.30s\n"
+	struct ao2_iterator i;
+	struct http_route *route;
+
 	switch(cmd) {
 	case CLI_INIT:
 		e->command = "phoneprov show routes";
@@ -1166,14 +1234,25 @@ static char *handle_show_routes(struct ast_cli_entry *e, int cmd, struct ast_cli
 	/* This currently iterates over routes twice, but it is the only place I've needed
 	 * to really separate static an dynamic routes, so I've just left it this way. */
 	ast_cli(a->fd, "Static routes\n\n");
-	ast_cli(a->fd, FORMATS, "Profile", "Relative URI", "Physical location");
-
-	ao2_callback_data(http_routes, OBJ_NODATA | OBJ_MULTIPLE, route_list_cb, &fd, NULL);
+	ast_cli(a->fd, FORMAT, "Relative URI", "Physical location");
+	i = ao2_iterator_init(http_routes, 0);
+	while ((route = ao2_iterator_next(&i))) {
+		if (!route->user)
+			ast_cli(a->fd, FORMAT, route->uri, route->file->template);
+		route = unref_route(route);
+	}
+	ao2_iterator_destroy(&i);
 
 	ast_cli(a->fd, "\nDynamic routes\n\n");
-	ast_cli(a->fd, FORMATD, "Provider", "Profile", "Relative URI", "Template");
+	ast_cli(a->fd, FORMAT, "Relative URI", "Template");
 
-	ao2_callback_data(http_routes, OBJ_NODATA | OBJ_MULTIPLE, route_list_cb, &fd, (void *)1);
+	i = ao2_iterator_init(http_routes, 0);
+	while ((route = ao2_iterator_next(&i))) {
+		if (route->user)
+			ast_cli(a->fd, FORMAT, route->uri, route->file->template);
+		route = unref_route(route);
+	}
+	ao2_iterator_destroy(&i);
 
 	return CLI_SUCCESS;
 }
@@ -1191,507 +1270,75 @@ static struct ast_http_uri phoneprovuri = {
 	.key = __FILE__,
 };
 
-static struct varshead *get_defaults(void)
-{
-	struct ast_config *phoneprov_cfg;
-	struct ast_config *cfg;
-	const char *value;
-	struct ast_variable *v;
-	struct ast_var_t *var;
-	struct ast_flags config_flags = { 0 };
-	struct varshead *defaults = ast_var_list_create();
-
-	if (!defaults) {
-		ast_log(LOG_ERROR, "Unable to create default var list.\n");
-		return NULL;
-	}
-
-	if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags))
-		|| phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
-		ast_var_list_destroy(defaults);
-		return NULL;
-	}
-
-	value = ast_variable_retrieve(phoneprov_cfg, "general", pp_general_lookup[AST_PHONEPROV_STD_SERVER]);
-	if (!value) {
-		struct in_addr addr;
-		value = ast_variable_retrieve(phoneprov_cfg, "general", pp_general_lookup[AST_PHONEPROV_STD_SERVER_IFACE]);
-		if (value) {
-			lookup_iface(value, &addr);
-			value = ast_inet_ntoa(addr);
-		}
-	}
-	if (value) {
-		var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER], value);
-		AST_VAR_LIST_INSERT_TAIL(defaults, var);
-	} else {
-		ast_log(LOG_WARNING, "Unable to find a valid server address or name.\n");
-	}
-
-	value = ast_variable_retrieve(phoneprov_cfg, "general", pp_general_lookup[AST_PHONEPROV_STD_SERVER_PORT]);
-	if (!value) {
-		if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
-			value = ast_variable_retrieve(cfg, "general", "bindport");
-			ast_config_destroy(cfg);
-		}
-	}
-	var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER_PORT], S_OR(value, "5060"));
-	AST_VAR_LIST_INSERT_TAIL(defaults, var);
-
-	value = ast_variable_retrieve(phoneprov_cfg, "general", pp_general_lookup[AST_PHONEPROV_STD_PROFILE]);
-	if (!value) {
-		ast_log(LOG_ERROR, "Unable to load default profile.\n");
-		ast_config_destroy(phoneprov_cfg);
-		ast_var_list_destroy(defaults);
-		return NULL;
-	}
-	var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_PROFILE], value);
-	AST_VAR_LIST_INSERT_TAIL(defaults, var);
-	ast_config_destroy(phoneprov_cfg);
-
-	if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Unable to load users.conf\n");
-		ast_var_list_destroy(defaults);
-		return NULL;
-	}
-
-	/* Go ahead and load global variables from users.conf so we can append to profiles */
-	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
-		if (!strcasecmp(v->name, pp_user_lookup[AST_PHONEPROV_STD_VOICEMAIL_EXTEN])) {
-			var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_VOICEMAIL_EXTEN], v->value);
-			AST_VAR_LIST_INSERT_TAIL(defaults, var);
-		}
-		if (!strcasecmp(v->name, pp_user_lookup[AST_PHONEPROV_STD_EXTENSION_LENGTH])) {
-			var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_EXTENSION_LENGTH], v->value);
-			AST_VAR_LIST_INSERT_TAIL(defaults, var);
-		}
-	}
-	ast_config_destroy(cfg);
-
-	return defaults;
-}
-
-static int load_users(void)
+static int load_module(void)
 {
-	struct ast_config *cfg;
-	char *cat;
-	const char *value;
-	struct ast_flags config_flags = { 0 };
-	struct varshead *defaults = get_defaults();
-
-	if (!defaults) {
-		ast_log(LOG_WARNING, "Unable to load default variables.\n");
-		return -1;
-	}
-
-	if (!(cfg = ast_config_load("users.conf", config_flags))
-		|| cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_WARNING, "Unable to load users.conf\n");
-		return -1;
-	}
-
-	cat = NULL;
-	while ((cat = ast_category_browse(cfg, cat))) {
-		const char *tmp;
-		int i;
-		struct ast_var_t *varx;
-		struct ast_var_t *vard;
-
-		if (strcasecmp(cat, "general") && strcasecmp(cat, "authentication")) {
-			struct varshead *variables = ast_var_list_create();
+	profiles = ao2_container_alloc(MAX_PROFILE_BUCKETS, profile_hash_fn, profile_cmp_fn);
 
-			if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp))) {
-				ast_var_list_destroy(variables);
-				continue;
-			}
+	http_routes = ao2_container_alloc(MAX_ROUTE_BUCKETS, routes_hash_fn, routes_cmp_fn);
 
-			/* Transfer the standard variables */
-			for (i = 0; i < AST_PHONEPROV_STD_VAR_LIST_LENGTH; i++) {
-				if (pp_user_lookup[i]) {
-					value = ast_variable_retrieve(cfg, cat, pp_user_lookup[i]);
-					if (value) {
-						varx = ast_var_assign(variable_lookup[i],
-							value);
-						AST_VAR_LIST_INSERT_TAIL(variables, varx);
-					}
-				}
-			}
+	users = ao2_container_alloc(MAX_USER_BUCKETS, users_hash_fn, users_cmp_fn);
 
-			if (!ast_var_find(variables, variable_lookup[AST_PHONEPROV_STD_MAC])) {
-				ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat);
-				ast_var_list_destroy(variables);
-				continue;
-			}
+	AST_LIST_HEAD_INIT_NOLOCK(&global_variables);
+	ast_mutex_init(&globals_lock);
 
-			/* Apply defaults */
-			AST_VAR_LIST_TRAVERSE(defaults, vard) {
-				if (ast_var_find(variables, vard->name)) {
-					continue;
-				}
-				varx = ast_var_assign(vard->name, vard->value);
-				AST_VAR_LIST_INSERT_TAIL(variables, varx);
-			}
-
-			ast_phoneprov_add_extension(SIPUSERS_PROVIDER_NAME, variables);
-		}
-	}
-	ast_config_destroy(cfg);
-	return 0;
-}
-
-static int load_common(void)
-{
-	struct ast_config *phoneprov_cfg;
-	struct ast_flags config_flags = { 0 };
-	char *cat;
-
-	if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags))
-		|| phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
-		return -1;
-	}
-
-	cat = NULL;
-	while ((cat = ast_category_browse(phoneprov_cfg, cat))) {
-		if (!strcasecmp(cat, "general")) {
-			continue;
-		}
-		build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
-	}
-	ast_config_destroy(phoneprov_cfg);
+	ast_custom_function_register(&pp_each_user_function);
+	ast_custom_function_register(&pp_each_extension_function);
+	ast_cli_register_multiple(pp_cli, ARRAY_LEN(pp_cli));
 
-	if (!ao2_container_count(profiles)) {
-		ast_log(LOG_ERROR, "There are no provisioning profiles in phoneprov.conf.\n");
-		return -1;
-	}
+	set_config();
+	ast_http_uri_link(&phoneprovuri);
 
 	return 0;
 }
 
 static int unload_module(void)
 {
+	struct ast_var_t *var;
+
 	ast_http_uri_unlink(&phoneprovuri);
 	ast_custom_function_unregister(&pp_each_user_function);
 	ast_custom_function_unregister(&pp_each_extension_function);
 	ast_cli_unregister_multiple(pp_cli, ARRAY_LEN(pp_cli));
 
-	/* This cleans up the sip.conf/users.conf provider (called specifically for clarity) */
-	ast_phoneprov_provider_unregister(SIPUSERS_PROVIDER_NAME);
-
-	/* This cleans up the framework which also cleans up the providers. */
-	delete_profiles();
-	ao2_cleanup(profiles);
-	profiles = NULL;
 	delete_routes();
 	delete_users();
-	ao2_cleanup(http_routes);
-	http_routes = NULL;
-	ao2_cleanup(users);
-	users = NULL;
-	delete_providers();
-	ao2_cleanup(providers);
-	providers = NULL;
-
-	return 0;
-}
-
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
-static int load_module(void)
-{
-	profiles = ao2_container_alloc(MAX_PROFILE_BUCKETS, phone_profile_hash_fn, phone_profile_cmp_fn);
-	if (!profiles) {
-		ast_log(LOG_ERROR, "Unable to allocate profiles container.\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	http_routes = ao2_container_alloc(MAX_ROUTE_BUCKETS, http_route_hash_fn, http_route_cmp_fn);
-	if (!http_routes) {
-		ast_log(LOG_ERROR, "Unable to allocate routes container.\n");
-		goto error;
-	}
-
-	if (load_common()) {
-		ast_log(LOG_ERROR, "Unable to load provisioning profiles.\n");
-		goto error;
-	}
-
-	users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_fn, user_cmp_fn);
-	if (!users) {
-		ast_log(LOG_ERROR, "Unable to allocate users container.\n");
-		goto error;
-	}
-
-	providers = ao2_container_alloc(MAX_PROVIDER_BUCKETS, phoneprov_provider_hash_fn, phoneprov_provider_cmp_fn);
-	if (!providers) {
-		ast_log(LOG_ERROR, "Unable to allocate providers container.\n");
-		goto error;
-	}
+	delete_profiles();
+	ao2_ref(profiles, -1);
+	ao2_ref(http_routes, -1);
+	ao2_ref(users, -1);
 
-	/* Register ourselves as the provider for sip.conf/users.conf */
-	if (ast_phoneprov_provider_register(SIPUSERS_PROVIDER_NAME, load_users)) {
-		ast_log(LOG_WARNING, "Unable register sip/users config provider.  Others may succeed.\n");
+	ast_mutex_lock(&globals_lock);
+	while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) {
+		ast_var_delete(var);
 	}
+	ast_mutex_unlock(&globals_lock);
 
-	ast_http_uri_link(&phoneprovuri);
-
-	ast_custom_function_register(&pp_each_user_function);
-	ast_custom_function_register(&pp_each_extension_function);
-	ast_cli_register_multiple(pp_cli, ARRAY_LEN(pp_cli));
-
-	return AST_MODULE_LOAD_SUCCESS;
+	ast_mutex_destroy(&globals_lock);
 
-error:
-	unload_module();
-	return AST_MODULE_LOAD_DECLINE;
+	return 0;
 }
 
 static int reload(void)
 {
-	struct ao2_iterator i;
-	struct phoneprov_provider *provider;
+	struct ast_var_t *var;
 
-	/* Clean everything except the providers */
 	delete_routes();
 	delete_users();
 	delete_profiles();
 
-	/* Reload the profiles */
-	if (load_common()) {
-		ast_log(LOG_ERROR, "Unable to reload provisioning profiles.\n");
-		unload_module();
-		return AST_MODULE_LOAD_DECLINE;
+	ast_mutex_lock(&globals_lock);
+	while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) {
+		ast_var_delete(var);
 	}
+	ast_mutex_unlock(&globals_lock);
 
-	/* For each provider, reload the users */
-	ao2_lock(providers);
-	i = ao2_iterator_init(providers, 0);
-	for(; (provider = ao2_iterator_next(&i)); ao2_ref(provider, -1)) {
-		ast_log(LOG_VERBOSE, "Reloading provider '%s' users.\n", provider->provider_name);
-		if (provider->load_users()) {
-			ast_log(LOG_ERROR, "Unable to load provider '%s' users. Reload aborted.\n", provider->provider_name);
-			continue;
-		}
-	}
-	ao2_iterator_destroy(&i);
-	ao2_unlock(providers);
+	set_config();
 
-	return AST_MODULE_LOAD_SUCCESS;
+	return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP Phone Provisioning",
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
 	);
-
-/****  Public API for register/unregister, set defaults, and add extension. ****/
-
-const char *ast_phoneprov_std_variable_lookup(enum ast_phoneprov_std_variables var)
-{
-	if (var >= AST_PHONEPROV_STD_VAR_LIST_LENGTH) {
-		return NULL;
-	}
-
-	return variable_lookup[var];
-}
-
-int ast_phoneprov_provider_register(char *provider_name,
-	ast_phoneprov_load_users_cb load_users)
-{
-	struct phoneprov_provider *provider;
-
-	if (ast_strlen_zero(provider_name)) {
-		ast_log(LOG_ERROR, "Provider name can't be empty.\n");
-		return -1;
-	}
-
-	if (!providers) {
-		ast_log(LOG_WARNING, "Provider '%s' cannot be registered: res_phoneprov not loaded.\n", provider_name);
-		return -1;
-	}
-
-	provider = find_provider(provider_name);
-	if (provider) {
-		ast_log(LOG_ERROR, "There is already a provider registered named '%s'.\n", provider_name);
-		ao2_ref(provider, -1);
-		return -1;
-	}
-
-	provider = ao2_alloc(sizeof(struct phoneprov_provider), provider_destructor);
-	if (!provider) {
-		ast_log(LOG_ERROR, "Unable to allocate sufficient memory for provider '%s'.\n", provider_name);
-		return -1;
-	}
-
-	if (ast_string_field_init(provider, 32)) {
-		ao2_ref(provider, -1);
-		ast_log(LOG_ERROR, "Unable to allocate sufficient memory for provider '%s' stringfields.\n", provider_name);
-		return -1;
-	}
-
-	ast_string_field_set(provider, provider_name, provider_name);
-	provider->load_users = load_users;
-
-	ao2_link(providers, provider);
-	ao2_ref(provider, -1);
-
-	if (provider->load_users()) {
-		ast_log(LOG_ERROR, "Unable to load provider '%s' users. Register aborted.\n", provider_name);
-		ast_phoneprov_provider_unregister(provider_name);
-		return -1;
-	}
-
-	ast_log(LOG_VERBOSE, "Registered phoneprov provider '%s'.\n", provider_name);
-	return 0;
-}
-
-static int extensions_delete_cb(void *obj, void *arg, int flags)
-{
-	char *provider_name = arg;
-	struct user *user = obj;
-	if (strcmp(user->provider_name, provider_name)) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-static int extension_delete_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct user *user = obj;
-	char *provider_name = data;
-	char *macaddress = arg;
-
-	if (!strcmp(user->provider_name, provider_name) && !strcasecmp(user->macaddress, macaddress)) {
-		return CMP_MATCH;
-	}
-	return 0;
-}
-
-void ast_phoneprov_delete_extension(char *provider_name, char *macaddress)
-{
-	ao2_callback_data(users, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-		extension_delete_cb, macaddress, provider_name);
-}
-
-void ast_phoneprov_delete_extensions(char *provider_name)
-{
-	ao2_callback(users, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, extensions_delete_cb, provider_name);
-}
-
-void ast_phoneprov_provider_unregister(char *provider_name)
-{
-	if (!providers) {
-		return;
-	}
-
-	ast_phoneprov_delete_extensions(provider_name);
-	ao2_find(providers, provider_name, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK);
-	ast_log(LOG_VERBOSE, "Unegistered phoneprov provider '%s'.\n", provider_name);
-}
-
-int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars)
-{
-	RAII_VAR(struct phoneprov_provider *, provider, NULL, ao2_cleanup);
-	RAII_VAR(struct user *, user, NULL, ao2_cleanup);
-	RAII_VAR(struct phone_profile *, profile, NULL, ao2_cleanup);
-	struct extension *exten;
-	char *profile_name;
-	char *mac;
-	char *username;
-
-	if (ast_strlen_zero(provider_name)) {
-		ast_log(LOG_ERROR, "Provider name can't be empty.\n");
-		return -1;
-	}
-	if (!vars) {
-		ast_log(LOG_ERROR, "Variable list can't be empty.\n");
-		return -1;
-	}
-
-	username = ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_USERNAME]);
-	if (!username) {
-		ast_log(LOG_ERROR, "Extension name can't be empty.\n");
-		return -1;
-	}
-
-	mac = ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_MAC]);
-	if (!mac) {
-		ast_log(LOG_ERROR, "MAC Address can't be empty.\n");
-		return -1;
-	}
-
-	provider = find_provider(provider_name);
-	if (!provider) {
-		ast_log(LOG_ERROR, "Provider '%s' wasn't found in the registry.\n", provider_name);
-		return -1;
-	}
-
-	profile_name = ast_var_find(vars,
-		variable_lookup[AST_PHONEPROV_STD_PROFILE]);
-	if (!profile_name) {
-		ast_log(LOG_ERROR, "No profile could be found for user '%s' - skipping.\n", username);
-		return -1;
-	}
-	if (!(profile = find_profile(profile_name))) {
-		ast_log(LOG_ERROR, "Could not look up profile '%s' - skipping.\n", profile_name);
-		return -1;
-	}
-
-	if (!(user = find_user(mac))) {
-
-		if (!(user = build_user(mac, profile, provider_name))) {
-			ast_log(LOG_ERROR, "Could not create user for '%s' - skipping\n", mac);
-			return -1;
-		}
-
-		if (!(exten = build_extension(username, vars))) {
-			ast_log(LOG_ERROR, "Could not create extension for '%s' - skipping\n", user->macaddress);
-			return -1;
-		}
-
-		if (add_user_extension(user, exten)) {
-			ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
-			exten = delete_extension(exten);
-			return -1;
-		}
-
-		if (build_user_routes(user)) {
-			ast_log(LOG_WARNING, "Could not create http routes for '%s' - skipping\n", user->macaddress);
-			return -1;
-		}
-		ast_log(LOG_VERBOSE, "Created %s/%s for provider '%s'.\n", username, mac, provider_name);
-		ao2_link(users, user);
-
-	} else {
-		if (strcmp(provider_name, user->provider_name)) {
-			ast_log(LOG_ERROR, "MAC address '%s' was already added by provider '%s' - skipping\n", user->macaddress, user->provider_name);
-			return -1;
-		}
-
-		if (!(exten = build_extension(username, vars))) {
-			ast_log(LOG_ERROR, "Could not create extension for '%s' - skipping\n", user->macaddress);
-			return -1;
-		}
-
-		if (add_user_extension(user, exten)) {
-			ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
-			exten = delete_extension(exten);
-			return -1;
-		}
-		ast_log(LOG_VERBOSE, "Added %s/%s for provider '%s'.\n", username, mac, provider_name);
-	}
-
-	return 0;
-}
diff --git a/res/res_phoneprov.exports.in b/res/res_phoneprov.exports.in
deleted file mode 100644
index 8356147..0000000
--- a/res/res_phoneprov.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_phoneprov_*;
-	local:
-		*;
-};
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
deleted file mode 100644
index f597f27..0000000
--- a/res/res_pjsip.c
+++ /dev/null
@@ -1,3209 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/logger.h"
-#include "asterisk/lock.h"
-#include "asterisk/utils.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/threadpool.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/uuid.h"
-#include "asterisk/sorcery.h"
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_sorcery_config</depend>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip" language="en_US">
-		<synopsis>SIP Resource using PJProject</synopsis>
-		<configFile name="pjsip.conf">
-			<configObject name="endpoint">
-				<synopsis>Endpoint</synopsis>
-				<description><para>
-					The <emphasis>Endpoint</emphasis> is the primary configuration object.
-					It contains the core SIP related options only, endpoints are <emphasis>NOT</emphasis>
-					dialable entries of their own. Communication with another SIP device is
-					accomplished via Addresses of Record (AoRs) which have one or more
-					contacts assicated with them. Endpoints <emphasis>NOT</emphasis> configured to
-					use a <literal>transport</literal> will default to first transport found
-					in <filename>pjsip.conf</filename> that matches its type.
-					</para>
-					<para>Example: An Endpoint has been configured with no transport.
-					When it comes time to call an AoR, PJSIP will find the
-					first transport that matches the type. A SIP URI of <literal>sip:5000@[11::33]</literal>
-					will use the first IPv6 transport and try to send the request.
-					</para>
-					<para>If the anonymous endpoint identifier is in use an endpoint with the name
-					"anonymous at domain" will be searched for as a last resort. If this is not found
-					it will fall back to searching for "anonymous". If neither endpoints are found
-					the anonymous endpoint identifier will not return an endpoint and anonymous
-					calling will not be possible.
-					</para>
-				</description>
-				<configOption name="100rel" default="yes">
-					<synopsis>Allow support for RFC3262 provisional ACK tags</synopsis>
-					<description>
-						<enumlist>
-							<enum name="no" />
-							<enum name="required" />
-							<enum name="yes" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="aggregate_mwi" default="yes">
-					<synopsis>Condense MWI notifications into a single NOTIFY.</synopsis>
-					<description><para>When enabled, <replaceable>aggregate_mwi</replaceable> condenses message
-					waiting notifications from multiple mailboxes into a single NOTIFY. If it is disabled,
-					individual NOTIFYs are sent for each mailbox.</para></description>
-				</configOption>
-				<configOption name="allow">
-					<synopsis>Media Codec(s) to allow</synopsis>
-				</configOption>
-				<configOption name="aors">
-					<synopsis>AoR(s) to be used with the endpoint</synopsis>
-					<description><para>
-						List of comma separated AoRs that the endpoint should be associated with.
-					</para></description>
-				</configOption>
-				<configOption name="auth">
-					<synopsis>Authentication Object(s) associated with the endpoint</synopsis>
-					<description><para>
-						This is a comma-delimited list of <replaceable>auth</replaceable> sections defined
-						in <filename>pjsip.conf</filename> to be used to verify inbound connection attempts.
-						</para><para>
-						Endpoints without an <literal>authentication</literal> object
-						configured will allow connections without vertification.
-					</para></description>
-				</configOption>
-				<configOption name="callerid">
-					<synopsis>CallerID information for the endpoint</synopsis>
-					<description><para>
-						Must be in the format <literal>Name <Number></literal>,
-						or only <literal><Number></literal>.
-					</para></description>
-				</configOption>
-				<configOption name="callerid_privacy">
-					<synopsis>Default privacy level</synopsis>
-					<description>
-						<enumlist>
-							<enum name="allowed_not_screened" />
-							<enum name="allowed_passed_screen" />
-							<enum name="allowed_failed_screen" />
-							<enum name="allowed" />
-							<enum name="prohib_not_screened" />
-							<enum name="prohib_passed_screen" />
-							<enum name="prohib_failed_screen" />
-							<enum name="prohib" />
-							<enum name="unavailable" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="callerid_tag">
-					<synopsis>Internal id_tag for the endpoint</synopsis>
-				</configOption>
-				<configOption name="context">
-					<synopsis>Dialplan context for inbound sessions</synopsis>
-				</configOption>
-				<configOption name="direct_media_glare_mitigation" default="none">
-					<synopsis>Mitigation of direct media (re)INVITE glare</synopsis>
-					<description>
-						<para>
-						This setting attempts to avoid creating INVITE glare scenarios
-						by disabling direct media reINVITEs in one direction thereby allowing
-						designated servers (according to this option) to initiate direct
-						media reINVITEs without contention and significantly reducing call
-						setup time.
-						</para>
-						<para>
-						A more detailed description of how this option functions can be found on
-						the Asterisk wiki https://wiki.asterisk.org/wiki/display/AST/SIP+Direct+Media+Reinvite+Glare+Avoidance
-						</para>
-						<enumlist>
-							<enum name="none" />
-							<enum name="outgoing" />
-							<enum name="incoming" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="direct_media_method" default="invite">
-					<synopsis>Direct Media method type</synopsis>
-					<description>
-						<para>Method for setting up Direct Media between endpoints.</para>
-						<enumlist>
-							<enum name="invite" />
-							<enum name="reinvite">
-								<para>Alias for the <literal>invite</literal> value.</para>
-							</enum>
-							<enum name="update" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="connected_line_method" default="invite">
-					<synopsis>Connected line method type</synopsis>
-					<description>
-						<para>Method used when updating connected line information.</para>
-						<enumlist>
-							<enum name="invite" />
-							<enum name="reinvite">
-								<para>Alias for the <literal>invite</literal> value.</para>
-							</enum>
-							<enum name="update" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="direct_media" default="yes">
-					<synopsis>Determines whether media may flow directly between endpoints.</synopsis>
-				</configOption>
-				<configOption name="disable_direct_media_on_nat" default="no">
-					<synopsis>Disable direct media session refreshes when NAT obstructs the media session</synopsis>
-				</configOption>
-				<configOption name="disallow">
-					<synopsis>Media Codec(s) to disallow</synopsis>
-				</configOption>
-				<configOption name="dtmf_mode" default="rfc4733">
-					<synopsis>DTMF mode</synopsis>
-					<description>
-						<para>This setting allows to choose the DTMF mode for endpoint communication.</para>
-						<enumlist>
-							<enum name="rfc4733">
-								<para>DTMF is sent out of band of the main audio stream.This
-								supercedes the older <emphasis>RFC-2833</emphasis> used within
-								the older <literal>chan_sip</literal>.</para>
-							</enum>
-							<enum name="inband">
-								<para>DTMF is sent as part of audio stream.</para>
-							</enum>
-							<enum name="info">
-								<para>DTMF is sent as SIP INFO packets.</para>
-							</enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="media_address">
-					<synopsis>IP address used in SDP for media handling</synopsis>
-					<description><para>
-						At the time of SDP creation, the IP address defined here will be used as
-						the media address for individual streams in the SDP.
-					</para>
-					<note><para>
-						Be aware that the <literal>external_media_address</literal> option, set in Transport
-						configuration, can also affect the final media address used in the SDP.
-					</para></note>
-					</description>
-				</configOption>
-				<configOption name="force_rport" default="yes">
-					<synopsis>Force use of return port</synopsis>
-				</configOption>
-				<configOption name="ice_support" default="no">
-					<synopsis>Enable the ICE mechanism to help traverse NAT</synopsis>
-				</configOption>
-				<configOption name="identify_by" default="username,location">
-					<synopsis>Way(s) for Endpoint to be identified</synopsis>
-					<description><para>
-						An endpoint can be identified in multiple ways. Currently, the only supported
-						option is <literal>username</literal>, which matches the endpoint based on the
-						username in the From header.
-						</para>
-						<note><para>Endpoints can also be identified by IP address; however, that method
-						of identification is not handled by this configuration option. See the documentation
-						for the <literal>identify</literal> configuration section for more details on that
-						method of endpoint identification. If this option is set to <literal>username</literal>
-						and an <literal>identify</literal> configuration section exists for the endpoint, then
-						the endpoint can be identified in multiple ways.</para></note>
-						<enumlist>
-							<enum name="username" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="redirect_method">
-					<synopsis>How redirects received from an endpoint are handled</synopsis>
-					<description><para>
-						When a redirect is received from an endpoint there are multiple ways it can be handled.
-						If this option is set to <literal>user</literal> the user portion of the redirect target
-						is treated as an extension within the dialplan and dialed using a Local channel. If this option
-						is set to <literal>uri_core</literal> the target URI is returned to the dialing application
-						which dials it using the PJSIP channel driver and endpoint originally used. If this option is
-						set to <literal>uri_pjsip</literal> the redirect occurs within chan_pjsip itself and is not exposed
-						to the core at all. The <literal>uri_pjsip</literal> option has the benefit of being more efficient
-						and also supporting multiple potential redirect targets. The con is that since redirection occurs
-						within chan_pjsip redirecting information is not forwarded and redirection can not be
-						prevented.
-						</para>
-						<enumlist>
-							<enum name="user" />
-							<enum name="uri_core" />
-							<enum name="uri_pjsip" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="mailboxes">
-					<synopsis>NOTIFY the endpoint when state changes for any of the specified mailboxes</synopsis>
-					<description><para>
-						Asterisk will send unsolicited MWI NOTIFY messages to the endpoint when state
-						changes happen for any of the specified mailboxes. More than one mailbox can be
-						specified with a comma-delimited string. app_voicemail mailboxes must be specified
-						as mailbox at context; for example: mailboxes=6001 at default. For mailboxes provided by
-						external sources, such as through the res_external_mwi module, you must specify
-						strings supported by the external system.
-					</para><para>
-						For endpoints that SUBSCRIBE for MWI, use the <literal>mailboxes</literal> option in your AOR
-						configuration.
-					</para></description>
-				</configOption>
-				<configOption name="moh_suggest" default="default">
-					<synopsis>Default Music On Hold class</synopsis>
-				</configOption>
-				<configOption name="outbound_auth">
-					<synopsis>Authentication object used for outbound requests</synopsis>
-				</configOption>
-				<configOption name="outbound_proxy">
-					<synopsis>Proxy through which to send requests, a full SIP URI must be provided</synopsis>
-				</configOption>
-				<configOption name="rewrite_contact">
-					<synopsis>Allow Contact header to be rewritten with the source IP address-port</synopsis>
-					<description><para>
-						On inbound SIP messages from this endpoint, the Contact header will be changed to have the
-						source IP address and port. This option does not affect outbound messages send to this
-						endpoint.
-					</para></description>
-				</configOption>
-				<configOption name="rtp_ipv6" default="no">
-					<synopsis>Allow use of IPv6 for RTP traffic</synopsis>
-				</configOption>
-				<configOption name="rtp_symmetric" default="no">
-					<synopsis>Enforce that RTP must be symmetric</synopsis>
-				</configOption>
-				<configOption name="send_diversion" default="yes">
-					<synopsis>Send the Diversion header, conveying the diversion
-					information to the called user agent</synopsis>
-				</configOption>
-				<configOption name="send_pai" default="no">
-					<synopsis>Send the P-Asserted-Identity header</synopsis>
-				</configOption>
-				<configOption name="send_rpid" default="no">
-					<synopsis>Send the Remote-Party-ID header</synopsis>
-				</configOption>
-				<configOption name="timers_min_se" default="90">
-					<synopsis>Minimum session timers expiration period</synopsis>
-					<description><para>
-						Minimium session timer expiration period. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="timers" default="yes">
-					<synopsis>Session timers for SIP packets</synopsis>
-					<description>
-						<enumlist>
-							<enum name="forced" />
-							<enum name="no" />
-							<enum name="required" />
-							<enum name="yes" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="timers_sess_expires" default="1800">
-					<synopsis>Maximum session timer expiration period</synopsis>
-					<description><para>
-						Maximium session timer expiration period. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="transport">
-					<synopsis>Desired transport configuration</synopsis>
-					<description><para>
-						This will set the desired transport configuration to send SIP data through.
-						</para>
-						<warning><para>Not specifying a transport will <emphasis>DEFAULT</emphasis>
-						to the first configured transport in <filename>pjsip.conf</filename> which is
-						valid for the URI we are trying to contact.
-						</para></warning>
-						<warning><para>Transport configuration is not affected by reloads. In order to
-						change transports, a full Asterisk restart is required</para></warning>
-					</description>
-				</configOption>
-				<configOption name="trust_id_inbound" default="no">
-					<synopsis>Accept identification information received from this endpoint</synopsis>
-					<description><para>This option determines whether Asterisk will accept
-					identification from the endpoint from headers such as P-Asserted-Identity
-					or Remote-Party-ID header. This option applies both to calls originating from the
-					endpoint and calls originating from Asterisk. If <literal>no</literal>, the
-					configured Caller-ID from pjsip.conf will always be used as the identity for
-					the endpoint.</para></description>
-				</configOption>
-				<configOption name="trust_id_outbound" default="no">
-					<synopsis>Send private identification details to the endpoint.</synopsis>
-					<description><para>This option determines whether res_pjsip will send private
-					identification information to the endpoint. If <literal>no</literal>,
-					private Caller-ID information will not be forwarded to the endpoint.
-					"Private" in this case refers to any method of restricting identification.
-					Example: setting <replaceable>callerid_privacy</replaceable> to any
-					<literal>prohib</literal> variation.
-					Example: If <replaceable>trust_id_inbound</replaceable> is set to
-					<literal>yes</literal>, the presence of a <literal>Privacy: id</literal>
-					header in a SIP request or response would indicate the identification
-					provided in the request is private.</para></description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'endpoint'.</synopsis>
-				</configOption>
-				<configOption name="use_ptime" default="no">
-					<synopsis>Use Endpoint's requested packetisation interval</synopsis>
-				</configOption>
-				<configOption name="use_avpf" default="no">
-					<synopsis>Determines whether res_pjsip will use and enforce usage of AVPF for this
-					endpoint.</synopsis>
-					<description><para>
-						If set to <literal>yes</literal>, res_pjsip will use the AVPF or SAVPF RTP
-						profile for all media offers on outbound calls and media updates and will
-						decline media offers not using the AVPF or SAVPF profile.
-					</para><para>
-						If set to <literal>no</literal>, res_pjsip will use the AVP or SAVP RTP
-						profile for all media offers on outbound calls and media updates, and will
-						decline media offers not using the AVP or SAVP profile.
-					</para></description>
-				</configOption>
-				<configOption name="force_avp" default="no">
-					<synopsis>Determines whether res_pjsip will use and enforce usage of AVP,
-					regardless of the RTP profile in use for this endpoint.</synopsis>
-					<description><para>
-						If set to <literal>yes</literal>, res_pjsip will use the AVP, AVPF, SAVP, or
-						SAVPF RTP profile for all media offers on outbound calls and media updates including
-						those for DTLS-SRTP streams.
-					</para><para>
-						If set to <literal>no</literal>, res_pjsip will use the respective RTP profile
-						depending on configuration.
-					</para></description>
-				</configOption>
-				<configOption name="media_use_received_transport" default="no">
-					<synopsis>Determines whether res_pjsip will use the media transport received in the
-					offer SDP in the corresponding answer SDP.</synopsis>
-					<description><para>
-						If set to <literal>yes</literal>, res_pjsip will use the received media transport.
-					</para><para>
-						If set to <literal>no</literal>, res_pjsip will use the respective RTP profile
-						depending on configuration.
-					</para></description>
-				</configOption>
-				<configOption name="media_encryption" default="no">
-					<synopsis>Determines whether res_pjsip will use and enforce usage of media encryption
-					for this endpoint.</synopsis>
-					<description>
-						<enumlist>
-							<enum name="no"><para>
-								res_pjsip will offer no encryption and allow no encryption to be setup.
-							</para></enum>
-							<enum name="sdes"><para>
-								res_pjsip will offer standard SRTP setup via in-SDP keys. Encrypted SIP
-								transport should be used in conjunction with this option to prevent
-								exposure of media encryption keys.
-							</para></enum>
-							<enum name="dtls"><para>
-								res_pjsip will offer DTLS-SRTP setup.
-							</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="media_encryption_optimistic" default="no">
-					<synopsis>Determines whether encryption should be used if possible but does not terminate the
-					session if not achieved.</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>sdes</literal> or <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="inband_progress" default="no">
-					<synopsis>Determines whether chan_pjsip will indicate ringing using inband
-					    progress.</synopsis>
-					<description><para>
-						If set to <literal>yes</literal>, chan_pjsip will send a 183 Session Progress
-						when told to indicate ringing and will immediately start sending ringing
-						as audio.
-					</para><para>
-						If set to <literal>no</literal>, chan_pjsip will send a 180 Ringing when told
-						to indicate ringing and will NOT send it as audio.
-					</para></description>
-				</configOption>
-				<configOption name="call_group">
-					<synopsis>The numeric pickup groups for a channel.</synopsis>
-					<description><para>
-						Can be set to a comma separated list of numbers or ranges between the values
-						of 0-63 (maximum of 64 groups).
-					</para></description>
-				</configOption>
-				<configOption name="pickup_group">
-					<synopsis>The numeric pickup groups that a channel can pickup.</synopsis>
-					<description><para>
-						Can be set to a comma separated list of numbers or ranges between the values
-						of 0-63 (maximum of 64 groups).
-					</para></description>
-				</configOption>
-				<configOption name="named_call_group">
-					<synopsis>The named pickup groups for a channel.</synopsis>
-					<description><para>
-						Can be set to a comma separated list of case sensitive strings limited by
-						supported line length.
-					</para></description>
-				</configOption>
-				<configOption name="named_pickup_group">
-					<synopsis>The named pickup groups that a channel can pickup.</synopsis>
-					<description><para>
-						Can be set to a comma separated list of case sensitive strings limited by
-						supported line length.
-					</para></description>
-				</configOption>
-				<configOption name="device_state_busy_at" default="0">
-					<synopsis>The number of in-use channels which will cause busy to be returned as device state</synopsis>
-					<description><para>
-						When the number of in-use channels for the endpoint matches the devicestate_busy_at setting the
-						PJSIP channel driver will return busy as the device state instead of in use.
-					</para></description>
-				</configOption>
-				<configOption name="t38_udptl" default="no">
-					<synopsis>Whether T.38 UDPTL support is enabled or not</synopsis>
-					<description><para>
-						If set to yes T.38 UDPTL support will be enabled, and T.38 negotiation requests will be accepted
-						and relayed.
-					</para></description>
-				</configOption>
-				<configOption name="t38_udptl_ec" default="none">
-					<synopsis>T.38 UDPTL error correction method</synopsis>
-					<description>
-						<enumlist>
-							<enum name="none"><para>
-								No error correction should be used.
-							</para></enum>
-							<enum name="fec"><para>
-								Forward error correction should be used.
-							</para></enum>
-							<enum name="redundancy"><para>
-								Redundacy error correction should be used.
-							</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="t38_udptl_maxdatagram" default="0">
-					<synopsis>T.38 UDPTL maximum datagram size</synopsis>
-					<description><para>
-						This option can be set to override the maximum datagram of a remote endpoint for broken
-						endpoints.
-					</para></description>
-				</configOption>
-				<configOption name="fax_detect" default="no">
-					<synopsis>Whether CNG tone detection is enabled</synopsis>
-					<description><para>
-						This option can be set to send the session to the fax extension when a CNG tone is
-						detected.
-					</para></description>
-				</configOption>
-				<configOption name="t38_udptl_nat" default="no">
-					<synopsis>Whether NAT support is enabled on UDPTL sessions</synopsis>
-					<description><para>
-						When enabled the UDPTL stack will send UDPTL packets to the source address of
-						received packets.
-					</para></description>
-				</configOption>
-				<configOption name="t38_udptl_ipv6" default="no">
-					<synopsis>Whether IPv6 is used for UDPTL Sessions</synopsis>
-					<description><para>
-						When enabled the UDPTL stack will use IPv6.
-					</para></description>
-				</configOption>
-				<configOption name="tone_zone">
-					<synopsis>Set which country's indications to use for channels created for this endpoint.</synopsis>
-				</configOption>
-				<configOption name="language">
-					<synopsis>Set the default language to use for channels created for this endpoint.</synopsis>
-				</configOption>
-				<configOption name="one_touch_recording" default="no">
-					<synopsis>Determines whether one-touch recording is allowed for this endpoint.</synopsis>
-					<see-also>
-						<ref type="configOption">record_on_feature</ref>
-						<ref type="configOption">record_off_feature</ref>
-					</see-also>
-				</configOption>
-				<configOption name="record_on_feature" default="automixmon">
-					<synopsis>The feature to enact when one-touch recording is turned on.</synopsis>
-					<description>
-						<para>When an INFO request for one-touch recording arrives with a Record header set to "on", this
-						feature will be enabled for the channel. The feature designated here can be any built-in
-						or dynamic feature defined in features.conf.</para>
-						<note><para>This setting has no effect if the endpoint's one_touch_recording option is disabled</para></note>
-					</description>
-					<see-also>
-						<ref type="configOption">one_touch_recording</ref>
-						<ref type="configOption">record_off_feature</ref>
-					</see-also>
-				</configOption>
-				<configOption name="record_off_feature" default="automixmon">
-					<synopsis>The feature to enact when one-touch recording is turned off.</synopsis>
-					<description>
-						<para>When an INFO request for one-touch recording arrives with a Record header set to "off", this
-						feature will be enabled for the channel. The feature designated here can be any built-in
-						or dynamic feature defined in features.conf.</para>
-						<note><para>This setting has no effect if the endpoint's one_touch_recording option is disabled</para></note>
-					</description>
-					<see-also>
-						<ref type="configOption">one_touch_recording</ref>
-						<ref type="configOption">record_on_feature</ref>
-					</see-also>
-				</configOption>
-				<configOption name="rtp_engine" default="asterisk">
-					<synopsis>Name of the RTP engine to use for channels created for this endpoint</synopsis>
-				</configOption>
-				<configOption name="allow_transfer" default="yes">
-					<synopsis>Determines whether SIP REFER transfers are allowed for this endpoint</synopsis>
-				</configOption>
-				<configOption name="sdp_owner" default="-">
-					<synopsis>String placed as the username portion of an SDP origin (o=) line.</synopsis>
-				</configOption>
-				<configOption name="sdp_session" default="Asterisk">
-					<synopsis>String used for the SDP session (s=) line.</synopsis>
-				</configOption>
-				<configOption name="tos_audio">
-					<synopsis>DSCP TOS bits for audio streams</synopsis>
-					<description><para>
-						See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
-					</para></description>
-				</configOption>
-				<configOption name="tos_video">
-					<synopsis>DSCP TOS bits for video streams</synopsis>
-					<description><para>
-						See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
-					</para></description>
-				</configOption>
-				<configOption name="cos_audio">
-					<synopsis>Priority for audio streams</synopsis>
-					<description><para>
-						See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
-					</para></description>
-				</configOption>
-				<configOption name="cos_video">
-					<synopsis>Priority for video streams</synopsis>
-					<description><para>
-						See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
-					</para></description>
-				</configOption>
-				<configOption name="allow_subscribe" default="yes">
-					<synopsis>Determines if endpoint is allowed to initiate subscriptions with Asterisk.</synopsis>
-				</configOption>
-				<configOption name="sub_min_expiry" default="60">
-					<synopsis>The minimum allowed expiry time for subscriptions initiated by the endpoint.</synopsis>
-				</configOption>
-				<configOption name="from_user">
-					<synopsis>Username to use in From header for requests to this endpoint.</synopsis>
-				</configOption>
-				<configOption name="mwi_from_user">
-					<synopsis>Username to use in From header for unsolicited MWI NOTIFYs to this endpoint.</synopsis>
-				</configOption>
-				<configOption name="from_domain">
-					<synopsis>Domain to user in From header for requests to this endpoint.</synopsis>
-				</configOption>
-				<configOption name="dtls_verify">
-					<synopsis>Verify that the provided peer certificate is valid</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_rekey">
-					<synopsis>Interval at which to renegotiate the TLS session and rekey the SRTP session</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para><para>
-						If this is not set or the value provided is 0 rekeying will be disabled.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_cert_file">
-					<synopsis>Path to certificate file to present to peer</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_private_key">
-					<synopsis>Path to private key for certificate file</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_cipher">
-					<synopsis>Cipher to use for DTLS negotiation</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para>
-					<para>Many options for acceptable ciphers. See link for more:</para>
-					<para>http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
-					</para></description>
-				</configOption>
-				<configOption name="dtls_ca_file">
-					<synopsis>Path to certificate authority certificate</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_ca_path">
-					<synopsis>Path to a directory containing certificate authority certificates</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="dtls_setup">
-					<synopsis>Whether we are willing to accept connections, connect to the other party, or both.</synopsis>
-					<description>
-						<para>
-							This option only applies if <replaceable>media_encryption</replaceable> is
-							set to <literal>dtls</literal>.
-						</para>
-						<enumlist>
-							<enum name="active"><para>
-								res_pjsip will make a connection to the peer.
-							</para></enum>
-							<enum name="passive"><para>
-								res_pjsip will accept connections from the peer.
-							</para></enum>
-							<enum name="actpass"><para>
-								res_pjsip will offer and accept connections from the peer.
-							</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="dtls_fingerprint">
-					<synopsis>Type of hash to use for the DTLS fingerprint in the SDP.</synopsis>
-					<description>
-						<para>
-							This option only applies if <replaceable>media_encryption</replaceable> is
-							set to <literal>dtls</literal>.
-						</para>
-						<enumlist>
-							<enum name="SHA-256"></enum>
-							<enum name="SHA-1"></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="srtp_tag_32">
-					<synopsis>Determines whether 32 byte tags should be used instead of 80 byte tags.</synopsis>
-					<description><para>
-						This option only applies if <replaceable>media_encryption</replaceable> is
-						set to <literal>sdes</literal> or <literal>dtls</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="set_var">
-					<synopsis>Variable set on a channel involving the endpoint.</synopsis>
-					<description><para>
-					        When a new channel is created using the endpoint set the specified
-						variable(s) on that channel. For multiple channel variables specify
-						multiple 'set_var'(s).
-					</para></description>
-				</configOption>
-				<configOption name="message_context">
-					<synopsis>Context to route incoming MESSAGE requests to.</synopsis>
-					<description><para>
-						If specified, incoming MESSAGE requests will be routed to the indicated
-						dialplan context. If no <replaceable>message_context</replaceable> is
-						specified, then the <replaceable>context</replaceable> setting is used.
-					</para></description>
-				</configOption>
-				<configOption name="accountcode">
-					<synopsis>An accountcode to set automatically on any channels created for this endpoint.</synopsis>
-					<description><para>
-						If specified, any channel created for this endpoint will automatically
-						have this accountcode set on it.
-					</para></description>
-				</configOption>
-			</configObject>
-			<configObject name="auth">
-				<synopsis>Authentication type</synopsis>
-				<description><para>
-					Authentication objects hold the authentication information for use
-					by other objects such as <literal>endpoints</literal> or <literal>registrations</literal>.
-					This also allows for multiple objects to use a single auth object. See
-					the <literal>auth_type</literal> config option for password style choices.
-				</para></description>
-				<configOption name="auth_type" default="userpass">
-					<synopsis>Authentication type</synopsis>
-					<description><para>
-						This option specifies which of the password style config options should be read
-						when trying to authenticate an endpoint inbound request. If set to <literal>userpass</literal>
-						then we'll read from the 'password' option. For <literal>md5</literal> we'll read
-						from 'md5_cred'.
-						</para>
-						<enumlist>
-							<enum name="md5"/>
-							<enum name="userpass"/>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="nonce_lifetime" default="32">
-					<synopsis>Lifetime of a nonce associated with this authentication config.</synopsis>
-				</configOption>
-				<configOption name="md5_cred">
-					<synopsis>MD5 Hash used for authentication.</synopsis>
-					<description><para>Only used when auth_type is <literal>md5</literal>.</para></description>
-				</configOption>
-				<configOption name="password">
-					<synopsis>PlainText password used for authentication.</synopsis>
-					<description><para>Only used when auth_type is <literal>userpass</literal>.</para></description>
-				</configOption>
-				<configOption name="realm" default="asterisk">
-					<synopsis>SIP realm for endpoint</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be 'auth'</synopsis>
-				</configOption>
-				<configOption name="username">
-					<synopsis>Username to use for account</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="domain_alias">
-				<synopsis>Domain Alias</synopsis>
-				<description><para>
-					Signifies that a domain is an alias. If the domain on a session is
-					not found to match an AoR then this object is used to see if we have
-					an alias for the AoR to which the endpoint is binding. This objects
-					name as defined in configuration should be the domain alias and a
-					config option is provided to specify the domain to be aliased.
-				</para></description>
-				<configOption name="type">
-					<synopsis>Must be of type 'domain_alias'.</synopsis>
-				</configOption>
-				<configOption name="domain">
-					<synopsis>Domain to be aliased</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="transport">
-				<synopsis>SIP Transport</synopsis>
-				<description><para>
-					<emphasis>Transports</emphasis>
-					</para>
-					<para>There are different transports and protocol derivatives
-						supported by <literal>res_pjsip</literal>. They are in order of
-						preference: UDP, TCP, and WebSocket (WS).</para>
-					<note><para>Changes to transport configuration in pjsip.conf will only be
-						effected on a complete restart of Asterisk. A module reload
-						will not suffice.</para></note>
-				</description>
-				<configOption name="async_operations" default="1">
-					<synopsis>Number of simultaneous Asynchronous Operations</synopsis>
-				</configOption>
-				<configOption name="bind">
-					<synopsis>IP Address and optional port to bind to for this transport</synopsis>
-				</configOption>
-				<configOption name="ca_list_file">
-					<synopsis>File containing a list of certificates to read (TLS ONLY)</synopsis>
-				</configOption>
-				<configOption name="cert_file">
-					<synopsis>Certificate file for endpoint (TLS ONLY)</synopsis>
-					<description><para>
-						A path to a .crt or .pem file can be provided.  However, only
-						the certificate is read from the file, not the private key.
-						The <literal>priv_key_file</literal> option must supply a
-						matching key file.
-					</para></description>
-				</configOption>
-				<configOption name="cipher">
-					<synopsis>Preferred cryptography cipher names (TLS ONLY)</synopsis>
-					<description>
-					<para>Comma separated list of cipher names or numeric equivalents.
-						Numeric equivalents can be either decimal or hexadecimal (0xX).
-					</para>
-					<para>There are many cipher names.  Use the CLI command
-						<literal>pjsip list ciphers</literal> to see a list of cipher
-						names available for your installation.  See link for more:</para>
-					<para>http://www.openssl.org/docs/apps/ciphers.html#CIPHER_SUITE_NAMES
-					</para>
-					</description>
-				</configOption>
-				<configOption name="domain">
-					<synopsis>Domain the transport comes from</synopsis>
-				</configOption>
-				<configOption name="external_media_address">
-					<synopsis>External IP address to use in RTP handling</synopsis>
-					<description><para>
-						When a request or response is sent out, if the destination of the
-						message is outside the IP network defined in the option <literal>localnet</literal>,
-						and the media address in the SDP is within the localnet network, then the
-						media address in the SDP will be rewritten to the value defined for
-						<literal>external_media_address</literal>.
-					</para></description>
-				</configOption>
-				<configOption name="external_signaling_address">
-					<synopsis>External address for SIP signalling</synopsis>
-				</configOption>
-				<configOption name="external_signaling_port" default="0">
-					<synopsis>External port for SIP signalling</synopsis>
-				</configOption>
-				<configOption name="method">
-					<synopsis>Method of SSL transport (TLS ONLY)</synopsis>
-					<description>
-						<enumlist>
-							<enum name="default" />
-							<enum name="unspecified" />
-							<enum name="tlsv1" />
-							<enum name="sslv2" />
-							<enum name="sslv3" />
-							<enum name="sslv23" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="local_net">
-					<synopsis>Network to consider local (used for NAT purposes).</synopsis>
-					<description><para>This must be in CIDR or dotted decimal format with the IP
-					and mask separated with a slash ('/').</para></description>
-				</configOption>
-				<configOption name="password">
-					<synopsis>Password required for transport</synopsis>
-				</configOption>
-				<configOption name="priv_key_file">
-					<synopsis>Private key file (TLS ONLY)</synopsis>
-				</configOption>
-				<configOption name="protocol" default="udp">
-					<synopsis>Protocol to use for SIP traffic</synopsis>
-					<description>
-						<enumlist>
-							<enum name="udp" />
-							<enum name="tcp" />
-							<enum name="tls" />
-							<enum name="ws" />
-							<enum name="wss" />
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="require_client_cert" default="false">
-					<synopsis>Require client certificate (TLS ONLY)</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'transport'.</synopsis>
-				</configOption>
-				<configOption name="verify_client" default="false">
-					<synopsis>Require verification of client certificate (TLS ONLY)</synopsis>
-				</configOption>
-				<configOption name="verify_server" default="false">
-					<synopsis>Require verification of server certificate (TLS ONLY)</synopsis>
-				</configOption>
-				<configOption name="tos" default="false">
-					<synopsis>Enable TOS for the signalling sent over this transport</synopsis>
-					<description>
-					<para>See <literal>https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service</literal>
-					for more information on this parameter.</para>
-					<note><para>This option does not apply to the <replaceable>ws</replaceable>
-					or the <replaceable>wss</replaceable> protocols.</para></note>
-					</description>
-				</configOption>
-				<configOption name="cos" default="false">
-					<synopsis>Enable COS for the signalling sent over this transport</synopsis>
-					<description>
-					<para>See <literal>https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service</literal>
-					for more information on this parameter.</para>
-					<note><para>This option does not apply to the <replaceable>ws</replaceable>
-					or the <replaceable>wss</replaceable> protocols.</para></note>
-					</description>
-				</configOption>
-				<configOption name="websocket_write_timeout">
-					<synopsis>The timeout (in milliseconds) to set on WebSocket connections.</synopsis>
-					<description>
-						<para>If a websocket connection accepts input slowly, the timeout
-						for writes to it can be increased to keep it from being disconnected.
-						Value is in milliseconds; default is 100 ms.</para>
-					</description>
-				</configOption>
-			</configObject>
-			<configObject name="contact">
-				<synopsis>A way of creating an aliased name to a SIP URI</synopsis>
-				<description><para>
-					Contacts are a way to hide SIP URIs from the dialplan directly.
-					They are also used to make a group of contactable parties when
-					in use with <literal>AoR</literal> lists.
-				</para></description>
-				<configOption name="type">
-					<synopsis>Must be of type 'contact'.</synopsis>
-				</configOption>
-				<configOption name="uri">
-					<synopsis>SIP URI to contact peer</synopsis>
-				</configOption>
-				<configOption name="expiration_time">
-					<synopsis>Time to keep alive a contact</synopsis>
-					<description><para>
-						Time to keep alive a contact. String style specification.
-					</para></description>
-				</configOption>
-				<configOption name="qualify_frequency" default="0">
-					<synopsis>Interval at which to qualify a contact</synopsis>
-					<description><para>
-						Interval between attempts to qualify the contact for reachability.
-						If <literal>0</literal> never qualify. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="outbound_proxy">
-					<synopsis>Outbound proxy used when sending OPTIONS request</synopsis>
-					<description><para>
-						If set the provided URI will be used as the outbound proxy when an
-						OPTIONS request is sent to a contact for qualify purposes.
-					</para></description>
-				</configOption>
-				<configOption name="path">
-					<synopsis>Stored Path vector for use in Route headers on outgoing requests.</synopsis>
-				</configOption>
-				<configOption name="user_agent">
-					<synopsis>User-Agent header from registration.</synopsis>
-					<description><para>
-						The User-Agent is automatically stored based on data present in incoming SIP
-						REGISTER requests and is not intended to be configured manually.
-					</para></description>
-				</configOption>
-			</configObject>
-			<configObject name="aor">
-				<synopsis>The configuration for a location of an endpoint</synopsis>
-				<description><para>
-					An AoR is what allows Asterisk to contact an endpoint via res_pjsip. If no
-					AoRs are specified, an endpoint will not be reachable by Asterisk.
-					Beyond that, an AoR has other uses within Asterisk, such as inbound
-					registration.
-					</para><para>
-					An <literal>AoR</literal> is a way to allow dialing a group
-					of <literal>Contacts</literal> that all use the same
-					<literal>endpoint</literal> for calls.
-					</para><para>
-					This can be used as another way of grouping a list of contacts to dial
-					rather than specifing them each directly when dialing via the dialplan.
-					This must be used in conjuction with the <literal>PJSIP_DIAL_CONTACTS</literal>.
-					</para><para>
-					Registrations: For Asterisk to match an inbound registration to an endpoint,
-					the AoR object name must match the user portion of the SIP URI in the "To:"
-					header of the inbound SIP registration. That will usually be equivalent
-					to the "user name" set in your hard or soft phones configuration.
-				</para></description>
-				<configOption name="contact">
-					<synopsis>Permanent contacts assigned to AoR</synopsis>
-					<description><para>
-						Contacts specified will be called whenever referenced
-						by <literal>chan_pjsip</literal>.
-						</para><para>
-						Use a separate "contact=" entry for each contact required. Contacts
-						are specified using a SIP URI.
-					</para></description>
-				</configOption>
-				<configOption name="default_expiration" default="3600">
-					<synopsis>Default expiration time in seconds for contacts that are dynamically bound to an AoR.</synopsis>
-				</configOption>
-				<configOption name="mailboxes">
-					<synopsis>Allow subscriptions for the specified mailbox(es)</synopsis>
-					<description><para>This option applies when an external entity subscribes to an AoR
-						for Message Waiting Indications. The mailboxes specified will be subscribed to.
-						More than one mailbox can be specified with a comma-delimited string.
-						app_voicemail mailboxes must be specified as mailbox at context;
-						for example: mailboxes=6001 at default. For mailboxes provided by external sources,
-						such as through the res_external_mwi module, you must specify strings supported by
-						the external system.
-					</para><para>
-						For endpoints that cannot SUBSCRIBE for MWI, you can set the <literal>mailboxes</literal> option in your
-						endpoint configuration section to enable unsolicited MWI NOTIFYs to the endpoint.
-					</para></description>
-				</configOption>
-				<configOption name="maximum_expiration" default="7200">
-					<synopsis>Maximum time to keep an AoR</synopsis>
-					<description><para>
-						Maximium time to keep a peer with explicit expiration. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="max_contacts" default="0">
-					<synopsis>Maximum number of contacts that can bind to an AoR</synopsis>
-					<description><para>
-						Maximum number of contacts that can associate with this AoR. This value does
-						not affect the number of contacts that can be added with the "contact" option.
-						It only limits contacts added through external interaction, such as
-						registration.
-						</para>
-						<note><para>This should be set to <literal>1</literal> and
-						<replaceable>remove_existing</replaceable> set to <literal>yes</literal> if you
-						wish to stick with the older <literal>chan_sip</literal> behaviour.
-						</para></note>
-					</description>
-				</configOption>
-				<configOption name="minimum_expiration" default="60">
-					<synopsis>Minimum keep alive time for an AoR</synopsis>
-					<description><para>
-						Minimum time to keep a peer with an explict expiration. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="remove_existing" default="no">
-					<synopsis>Determines whether new contacts replace existing ones.</synopsis>
-					<description><para>
-						On receiving a new registration to the AoR should it remove
-						the existing contact that was registered against it?
-						</para>
-						<note><para>This should be set to <literal>yes</literal> and
-						<replaceable>max_contacts</replaceable> set to <literal>1</literal> if you
-						wish to stick with the older <literal>chan_sip</literal> behaviour.
-						</para></note>
-					</description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'aor'.</synopsis>
-				</configOption>
-				<configOption name="qualify_frequency" default="0">
-					<synopsis>Interval at which to qualify an AoR</synopsis>
-					<description><para>
-						Interval between attempts to qualify the AoR for reachability.
-						If <literal>0</literal> never qualify. Time in seconds.
-					</para></description>
-				</configOption>
-				<configOption name="authenticate_qualify" default="no">
-					<synopsis>Authenticates a qualify request if needed</synopsis>
-					<description><para>
-						If true and a qualify request receives a challenge or authenticate response
-						authentication is attempted before declaring the contact available.
-					</para></description>
-				</configOption>
-				<configOption name="outbound_proxy">
-					<synopsis>Outbound proxy used when sending OPTIONS request</synopsis>
-					<description><para>
-						If set the provided URI will be used as the outbound proxy when an
-						OPTIONS request is sent to a contact for qualify purposes.
-					</para></description>
-				</configOption>
-				<configOption name="support_path">
-					<synopsis>Enables Path support for REGISTER requests and Route support for other requests.</synopsis>
-					<description><para>
-						When this option is enabled, the Path headers in register requests will be saved
-						and its contents will be used in Route headers for outbound out-of-dialog requests
-						and in Path headers for outbound 200 responses. Path support will also be indicated
-						in the Supported header.
-					</para></description>
-				</configOption>
-			</configObject>
-			<configObject name="system">
-				<synopsis>Options that apply to the SIP stack as well as other system-wide settings</synopsis>
-				<description><para>
-					The settings in this section are global. In addition to being global, the values will
-					not be re-evaluated when a reload is performed. This is because the values must be set
-					before the SIP stack is initialized. The only way to reset these values is to either
-					restart Asterisk, or unload res_pjsip.so and then load it again.
-				</para></description>
-				<configOption name="timer_t1" default="500">
-					<synopsis>Set transaction timer T1 value (milliseconds).</synopsis>
-					<description><para>
-						Timer T1 is the base for determining how long to wait before retransmitting
-						requests that receive no response when using an unreliable transport (e.g. UDP).
-						For more information on this timer, see RFC 3261, Section 17.1.1.1.
-					</para></description>
-				</configOption>
-				<configOption name="timer_b" default="32000">
-					<synopsis>Set transaction timer B value (milliseconds).</synopsis>
-					<description><para>
-						Timer B determines the maximum amount of time to wait after sending an INVITE
-						request before terminating the transaction. It is recommended that this be set
-						to 64 * Timer T1, but it may be set higher if desired. For more information on
-						this timer, see RFC 3261, Section 17.1.1.1.
-					</para></description>
-				</configOption>
-				<configOption name="compact_headers" default="no">
-					<synopsis>Use the short forms of common SIP header names.</synopsis>
-				</configOption>
-				<configOption name="threadpool_initial_size" default="0">
-					<synopsis>Initial number of threads in the res_pjsip threadpool.</synopsis>
-				</configOption>
-				<configOption name="threadpool_auto_increment" default="5">
-					<synopsis>The amount by which the number of threads is incremented when necessary.</synopsis>
-				</configOption>
-				<configOption name="threadpool_idle_timeout" default="60">
-					<synopsis>Number of seconds before an idle thread should be disposed of.</synopsis>
-				</configOption>
-				<configOption name="threadpool_max_size" default="0">
-					<synopsis>Maximum number of threads in the res_pjsip threadpool.
-					A value of 0 indicates no maximum.</synopsis>
-				</configOption>
-				<configOption name="disable_tcp_switch" default="yes">
-					<synopsis>Disable automatic switching from UDP to TCP transports.</synopsis>
-					<description><para>
-						Disable automatic switching from UDP to TCP transports if outgoing
-						request is too large.  See RFC 3261 section 18.1.1.
-					</para></description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'system'.</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="global">
-				<synopsis>Options that apply globally to all SIP communications</synopsis>
-				<description><para>
-					The settings in this section are global. Unlike options in the <literal>system</literal>
-					section, these options can be refreshed by performing a reload.
-				</para></description>
-				<configOption name="max_forwards" default="70">
-					<synopsis>Value used in Max-Forwards header for SIP requests.</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'global'.</synopsis>
-				</configOption>
-				<configOption name="user_agent" default="Asterisk <Asterisk Version>">
-					<synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis>
-				</configOption>
-				<configOption name="default_outbound_endpoint" default="default_outbound_endpoint">
-					<synopsis>Endpoint to use when sending an outbound request to a URI without a specified endpoint.</synopsis>
-				</configOption>
-				<configOption name="debug" default="no">
-					<synopsis>Enable/Disable SIP debug logging.  Valid options include yes|no or
-                                        a host address</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-	<manager name="PJSIPQualify" language="en_US">
-		<synopsis>
-			Qualify a chan_pjsip endpoint.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Endpoint" required="true">
-				<para>The endpoint you want to qualify.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Qualify a chan_pjsip endpoint.</para>
-		</description>
-	</manager>
-	<managerEvent language="en_US" name="IdentifyDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about an identify section.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'identify'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="Endpoint">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='endpoint']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Match">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='match']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="EndpointName">
-					<para>The name of the endpoint associated with this information.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AorDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about an Address of Record (AoR) section.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'aor'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="MinimumExpiration">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='minimum_expiration']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MaximumExpiration">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='maximum_expiration']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DefaultExpiration">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='default_expiration']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="QualifyFrequency">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='qualify_frequency']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AuthenticateQualify">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='authenticate_qualify']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MaxContacts">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='max_contacts']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RemoveExisting">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Mailboxes">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="OutboundProxy">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='outbound_proxy']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SupportPath">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='support_path']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TotalContacts">
-					<para>The total number of contacts associated with this AoR.</para>
-				</parameter>
-				<parameter name="ContactsRegistered">
-					<para>The number of non-permanent contacts associated with this AoR.</para>
-				</parameter>
-				<parameter name="EndpointName">
-					<para>The name of the endpoint associated with this information.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="AuthDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about an authentication section.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'auth'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="Username">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='username']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Password">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='username']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Md5Cred">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='md5_cred']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Realm">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='realm']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="NonceLifetime">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='nonce_lifetime']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AuthType">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='auth_type']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="EndpointName">
-					<para>The name of the endpoint associated with this information.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="TransportDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about an authentication section.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'transport'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="Protocol">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='protocol']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Bind">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='bind']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AsycOperations">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='async_operations']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CaListFile">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='ca_list_file']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CertFile">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='cert_file']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="PrivKeyFile">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='priv_key_file']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Password">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='password']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ExternalSignalingAddress">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='external_signaling_address']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ExternalSignalingPort">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='external_signaling_port']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ExternalMediaAddress">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='external_media_address']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Domain">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='domain']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="VerifyServer">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='verify_server']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="VerifyClient">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='verify_client']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RequireClientCert">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='require_client_cert']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Method">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='method']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Cipher">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='cipher']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="LocalNet">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='local_net']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Tos">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='tos']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Cos">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='cos']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="WebsocketWriteTimeout">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='transport']/configOption[@name='websocket_write_timeout']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="EndpointName">
-					<para>The name of the endpoint associated with this information.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="EndpointDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about an endpoint section.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'endpoint'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="Context">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='context']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Disallow">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='disallow']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Allow">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='allow']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtmfMode">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtmf_mode']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RtpIpv6">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='rtp_ipv6']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RtpSymmetric">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='rtp_symmetric']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="IceSupport">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='ice_support']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="UsePtime">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='use_ptime']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ForceRport">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='force_rport']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RewriteContact">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='rewrite_contact']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Transport">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='transport']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="OutboundProxy">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='outbound_proxy']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MohSuggest">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='moh_suggest']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="100rel">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='100rel']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Timers">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='timers']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TimersMinSe">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='timers_min_se']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TimersSessExpires">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='timers_sess_expires']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Auth">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='auth']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="OutboundAuth">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='outbound_auth']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Aors">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='aors']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MediaAddress">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='media_address']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="IdentifyBy">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='identify_by']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DirectMedia">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='direct_media']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DirectMediaMethod">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='direct_media_method']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ConnectedLineMethod">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='connected_line_method']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DirectMediaGlareMitigation">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='direct_media_glare_mitigation']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DisableDirectMediaOnNat">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='disable_direct_media_on_nat']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Callerid">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='callerid']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CalleridPrivacy">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='callerid_privacy']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CalleridTag">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='callerid_tag']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TrustIdInbound">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='trust_id_inbound']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TrustIdOutbound">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='trust_id_outbound']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SendPai">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='send_pai']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SendRpid">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='send_rpid']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SendDiversion">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='send_diversion']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Mailboxes">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='mailboxes']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AggregateMwi">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='aggregate_mwi']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MediaEncryption">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='media_encryption']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MediaEncryptionOptimistic">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='media_encryption_optimistic']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="UseAvpf">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='use_avpf']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ForceAvp">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='force_avp']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MediaUseReceivedTransport">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='media_use_received_transport']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="OneTouchRecording">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='one_touch_recording']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="InbandProgress">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='inband_progress']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CallGroup">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='call_group']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="PickupGroup">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='pickup_group']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="NamedCallGroup">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='named_call_group']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="NamedPickupGroup">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='named_pickup_group']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DeviceStateBusyAt">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='device_state_busy_at']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="T38Udptl">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="T38UdptlEc">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl_ec']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="T38UdptlMaxdatagram">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl_maxdatagram']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="FaxDetect">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='fax_detect']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="T38UdptlNat">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl_nat']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="T38UdptlIpv6">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl_ipv6']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="ToneZone">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='tone_zone']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Language">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='language']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RecordOnFeature">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='record_on_feature']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RecordOffFeature">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='record_off_feature']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AllowTransfer">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='allow_transfer']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SdpOwner">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='sdp_owner']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SdpSession">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='sdp_session']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TosAudio">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='tos_audio']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="TosVideo">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='tos_video']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CosAudio">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='cos_audio']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="CosVideo">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='cos_video']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="AllowSubscribe">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='allow_subscribe']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SubMinExpiry">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='sub_min_expiry']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="FromUser">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='from_user']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="FromDomain">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='from_domain']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MwiFromUser">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='mwi_from_user']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RtpEngine">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='rtp_engine']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsVerify">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_verify']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsRekey">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_rekey']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsCertFile">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_cert_file']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsPrivateKey">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_private_key']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsCipher">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_cipher']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsCaFile">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_ca_file']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsCaPath">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_ca_path']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DtlsSetup">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='dtls_setup']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SrtpTag32">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='srtp_tag_32']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="RedirectMethod">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='redirect_method']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="SetVar">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='set_var']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="MessageContext">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='message_context']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="Accountcode">
-					<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='accountcode']/synopsis/node())"/></para>
-				</parameter>
-				<parameter name="DeviceState">
-					<para>The aggregate device state for this endpoint.</para>
-				</parameter>
-				<parameter name="ActiveChannels">
-					<para>The number of active channels associated with this endpoint.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="ContactStatusDetail">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about a contact's status.</synopsis>
-			<syntax>
-				<parameter name="AOR">
-					<para>The AoR that owns this contact.</para>
-				</parameter>
-				<parameter name="URI">
-					<para>This contact's URI.</para>
-				</parameter>
-				<parameter name="Status">
-					<para>This contact's status.</para>
-					<enumlist>
-						<enum name="Reachable"/>
-						<enum name="Unreachable"/>
-					</enumlist>
-				</parameter>
-				<parameter name="RoundtripUsec">
-					<para>The round trip time in microseconds.</para>
-				</parameter>
-				<parameter name="EndpointName">
-					<para>The name of the endpoint associated with this information.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<managerEvent language="en_US" name="EndpointList">
-		<managerEventInstance class="EVENT_FLAG_COMMAND">
-			<synopsis>Provide details about a contact's status.</synopsis>
-			<syntax>
-				<parameter name="ObjectType">
-					<para>The object's type. This will always be 'endpoint'.</para>
-				</parameter>
-				<parameter name="ObjectName">
-					<para>The name of this object.</para>
-				</parameter>
-				<parameter name="Transport">
-					<para>The transport configurations associated with this endpoint.</para>
-				</parameter>
-				<parameter name="Aor">
-					<para>The aor configurations associated with this endpoint.</para>
-				</parameter>
-				<parameter name="Auths">
-					<para>The inbound authentication configurations associated with this endpoint.</para>
-				</parameter>
-				<parameter name="OutboundAuths">
-					<para>The outbound authentication configurations associated with this endpoint.</para>
-				</parameter>
-				<parameter name="DeviceState">
-					<para>The aggregate device state for this endpoint.</para>
-				</parameter>
-				<parameter name="ActiveChannels">
-					<para>The number of active channels associated with this endpoint.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	</managerEvent>
-	<manager name="PJSIPShowEndpoints" language="en_US">
-		<synopsis>
-			Lists PJSIP endpoints.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			Provides a listing of all endpoints.  For each endpoint an <literal>EndpointList</literal> event
-			is raised that contains relevant attributes and status information.  Once all
-			endpoints have been listed an <literal>EndpointListComplete</literal> event is issued.
-                        </para>
-		</description>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='EndpointList'])" />
-			</list-elements>
-			<managerEvent language="en_US" name="EndpointListComplete">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>Provide final information about an endpoint list.</synopsis>
-					<syntax>
-						<parameter name="EventList"/>
-						<parameter name="ListItems"/>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
-	<manager name="PJSIPShowEndpoint" language="en_US">
-		<synopsis>
-			Detail listing of an endpoint and its objects.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Endpoint" required="true">
-				<para>The endpoint to list.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>
-			Provides a detailed listing of options for a given endpoint.  Events are issued
-			showing the configuration and status of the endpoint and associated objects.  These
-			events include <literal>EndpointDetail</literal>, <literal>AorDetail</literal>,
-			<literal>AuthDetail</literal>, <literal>TransportDetail</literal>, and
-			<literal>IdentifyDetail</literal>.  Some events may be listed multiple times if multiple objects are
-			associated (for instance AoRs).  Once all detail events have been raised a final
-			<literal>EndpointDetailComplete</literal> event is issued.
-                        </para>
-		</description>
-		<responses>
-			<list-elements>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='EndpointDetail'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='IdentifyDetail'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ContactStatusDetail'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AuthDetail'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='TransportDetail'])" />
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='AorDetail'])" />
-			</list-elements>
-			<managerEvent language="en_US" name="EndpointDetailComplete">
-				<managerEventInstance class="EVENT_FLAG_COMMAND">
-					<synopsis>Provide final information about endpoint details.</synopsis>
-					<syntax>
-						<parameter name="EventList"/>
-						<parameter name="ListItems"/>
-					</syntax>
-				</managerEventInstance>
-			</managerEvent>
-		</responses>
-	</manager>
- ***/
-
-#define MOD_DATA_CONTACT "contact"
-
-static pjsip_endpoint *ast_pjsip_endpoint;
-
-static struct ast_threadpool *sip_threadpool;
-
-static int register_service(void *data)
-{
-	pjsip_module **module = data;
-	if (!ast_pjsip_endpoint) {
-		ast_log(LOG_ERROR, "There is no PJSIP endpoint. Unable to register services\n");
-		return -1;
-	}
-	if (pjsip_endpt_register_module(ast_pjsip_endpoint, *module) != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to register module %.*s\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
-		return -1;
-	}
-	ast_debug(1, "Registered SIP service %.*s (%p)\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name), *module);
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-int ast_sip_register_service(pjsip_module *module)
-{
-	return ast_sip_push_task_synchronous(NULL, register_service, &module);
-}
-
-static int unregister_service(void *data)
-{
-	pjsip_module **module = data;
-	ast_module_unref(ast_module_info->self);
-	if (!ast_pjsip_endpoint) {
-		return -1;
-	}
-	pjsip_endpt_unregister_module(ast_pjsip_endpoint, *module);
-	ast_debug(1, "Unregistered SIP service %.*s\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
-	return 0;
-}
-
-void ast_sip_unregister_service(pjsip_module *module)
-{
-	ast_sip_push_task_synchronous(NULL, unregister_service, &module);
-}
-
-static struct ast_sip_authenticator *registered_authenticator;
-
-int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
-{
-	if (registered_authenticator) {
-		ast_log(LOG_WARNING, "Authenticator %p is already registered. Cannot register a new one\n", registered_authenticator);
-		return -1;
-	}
-	registered_authenticator = auth;
-	ast_debug(1, "Registered SIP authenticator module %p\n", auth);
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
-{
-	if (registered_authenticator != auth) {
-		ast_log(LOG_WARNING, "Trying to unregister authenticator %p but authenticator %p registered\n",
-				auth, registered_authenticator);
-		return;
-	}
-	registered_authenticator = NULL;
-	ast_debug(1, "Unregistered SIP authenticator %p\n", auth);
-	ast_module_unref(ast_module_info->self);
-}
-
-int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	if (!registered_authenticator) {
-		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is not required\n");
-		return 0;
-	}
-
-	return registered_authenticator->requires_authentication(endpoint, rdata);
-}
-
-enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
-		pjsip_rx_data *rdata, pjsip_tx_data *tdata)
-{
-	if (!registered_authenticator) {
-		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is successful\n");
-		return 0;
-	}
-	return registered_authenticator->check_authentication(endpoint, rdata, tdata);
-}
-
-static struct ast_sip_outbound_authenticator *registered_outbound_authenticator;
-
-int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
-{
-	if (registered_outbound_authenticator) {
-		ast_log(LOG_WARNING, "Outbound authenticator %p is already registered. Cannot register a new one\n", registered_outbound_authenticator);
-		return -1;
-	}
-	registered_outbound_authenticator = auth;
-	ast_debug(1, "Registered SIP outbound authenticator module %p\n", auth);
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
-{
-	if (registered_outbound_authenticator != auth) {
-		ast_log(LOG_WARNING, "Trying to unregister outbound authenticator %p but outbound authenticator %p registered\n",
-				auth, registered_outbound_authenticator);
-		return;
-	}
-	registered_outbound_authenticator = NULL;
-	ast_debug(1, "Unregistered SIP outbound authenticator %p\n", auth);
-	ast_module_unref(ast_module_info->self);
-}
-
-int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge,
-		pjsip_transaction *tsx, pjsip_tx_data **new_request)
-{
-	if (!registered_outbound_authenticator) {
-		ast_log(LOG_WARNING, "No SIP outbound authenticator registered. Cannot respond to authentication challenge\n");
-		return -1;
-	}
-	return registered_outbound_authenticator->create_request_with_auth(auths, challenge, tsx, new_request);
-}
-
-struct endpoint_identifier_list {
-	struct ast_sip_endpoint_identifier *identifier;
-	AST_RWLIST_ENTRY(endpoint_identifier_list) list;
-};
-
-static AST_RWLIST_HEAD_STATIC(endpoint_identifiers, endpoint_identifier_list);
-
-int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
-{
-	struct endpoint_identifier_list *id_list_item;
-	SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	id_list_item = ast_calloc(1, sizeof(*id_list_item));
-	if (!id_list_item) {
-		ast_log(LOG_ERROR, "Unabled to add endpoint identifier. Out of memory.\n");
-		return -1;
-	}
-	id_list_item->identifier = identifier;
-
-	AST_RWLIST_INSERT_TAIL(&endpoint_identifiers, id_list_item, list);
-	ast_debug(1, "Registered endpoint identifier %p\n", identifier);
-
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
-{
-	struct endpoint_identifier_list *iter;
-	SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&endpoint_identifiers, iter, list) {
-		if (iter->identifier == identifier) {
-			AST_RWLIST_REMOVE_CURRENT(list);
-			ast_free(iter);
-			ast_debug(1, "Unregistered endpoint identifier %p\n", identifier);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata)
-{
-	struct endpoint_identifier_list *iter;
-	struct ast_sip_endpoint *endpoint = NULL;
-	SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE(&endpoint_identifiers, iter, list) {
-		ast_assert(iter->identifier->identify_endpoint != NULL);
-		endpoint = iter->identifier->identify_endpoint(rdata);
-		if (endpoint) {
-			break;
-		}
-	}
-	return endpoint;
-}
-
-AST_RWLIST_HEAD_STATIC(endpoint_formatters, ast_sip_endpoint_formatter);
-
-int ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
-{
-	SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_INSERT_TAIL(&endpoint_formatters, obj, next);
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
-{
-	struct ast_sip_endpoint_formatter *i;
-	SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&endpoint_formatters, i, next) {
-		if (i == obj) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint,
-				struct ast_sip_ami *ami, int *count)
-{
-	int res = 0;
-	struct ast_sip_endpoint_formatter *i;
-	SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	*count = 0;
-	AST_RWLIST_TRAVERSE(&endpoint_formatters, i, next) {
-		if (i->format_ami && ((res = i->format_ami(endpoint, ami)) < 0)) {
-			return res;
-		}
-
-		if (!res) {
-			(*count)++;
-		}
-	}
-	return 0;
-}
-
-pjsip_endpoint *ast_sip_get_pjsip_endpoint(void)
-{
-	return ast_pjsip_endpoint;
-}
-
-static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const char *domain, const pj_str_t *target, pjsip_tpselector *selector)
-{
-	pj_str_t tmp, local_addr;
-	pjsip_uri *uri;
-	pjsip_sip_uri *sip_uri;
-	pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
-	int local_port;
-	char uuid_str[AST_UUID_STR_LEN];
-
-	if (ast_strlen_zero(user)) {
-		user = ast_uuid_generate_str(uuid_str, sizeof(uuid_str));
-	}
-
-	/* Parse the provided target URI so we can determine what transport it will end up using */
-	pj_strdup_with_null(pool, &tmp, target);
-
-	if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
-	    (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
-		return -1;
-	}
-
-	sip_uri = pjsip_uri_get_uri(uri);
-
-	/* Determine the transport type to use */
-	if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
-		type = PJSIP_TRANSPORT_TLS;
-	} else if (!sip_uri->transport_param.slen) {
-		type = PJSIP_TRANSPORT_UDP;
-	} else {
-		type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
-	}
-
-	if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
-		return -1;
-	}
-
-	/* If the host is IPv6 turn the transport into an IPv6 version */
-	if (pj_strchr(&sip_uri->host, ':') && type < PJSIP_TRANSPORT_START_OTHER) {
-		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
-	}
-
-	if (!ast_strlen_zero(domain)) {
-		from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-		from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
-				"<sip:%s@%s%s%s>",
-				user,
-				domain,
-				(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
-				(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
-		return 0;
-	}
-
-	/* Get the local bound address for the transport that will be used when communicating with the provided URI */
-	if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
-							      &local_addr, &local_port) != PJ_SUCCESS) {
-
-		/* If no local address can be retrieved using the transport manager use the host one */
-		pj_strdup(pool, &local_addr, pj_gethostname());
-		local_port = pjsip_transport_get_default_port_for_type(PJSIP_TRANSPORT_UDP);
-	}
-
-	/* If IPv6 was specified in the transport, set the proper type */
-	if (pj_strchr(&local_addr, ':') && type < PJSIP_TRANSPORT_START_OTHER) {
-		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
-	}
-
-	from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-	from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
-				      "<sip:%s@%s%.*s%s:%d%s%s>",
-				      user,
-				      (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
-				      (int)local_addr.slen,
-				      local_addr.ptr,
-				      (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
-				      local_port,
-				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
-				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
-
-	return 0;
-}
-
-static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector)
-{
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-	const char *transport_name = endpoint->transport;
-
-	if (ast_strlen_zero(transport_name)) {
-		return 0;
-	}
-
-	transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name);
-
-	if (!transport || !transport->state) {
-		ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' for endpoint '%s'\n",
-			transport_name, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-
-	if (transport->state->transport) {
-		selector->type = PJSIP_TPSELECTOR_TRANSPORT;
-		selector->u.transport = transport->state->transport;
-	} else if (transport->state->factory) {
-		selector->type = PJSIP_TPSELECTOR_LISTENER;
-		selector->u.listener = transport->state->factory;
-	} else if (transport->type == AST_TRANSPORT_WS || transport->type == AST_TRANSPORT_WSS) {
-		/* The WebSocket transport has no factory as it can not create outgoing connections, so
-		 * even if an endpoint is locked to a WebSocket transport we let the PJSIP logic
-		 * find the existing connection if available and use it.
-		 */
-		return 0;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user)
-{
-	char enclosed_uri[PJSIP_MAX_URL_SIZE];
-	pj_str_t local_uri = { "sip:temp at temp", 13 }, remote_uri, target_uri;
-	pjsip_dialog *dlg = NULL;
-	const char *outbound_proxy = endpoint->outbound_proxy;
-	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
-	static const pj_str_t HCONTACT = { "Contact", 7 };
-
-	snprintf(enclosed_uri, sizeof(enclosed_uri), "<%s>", uri);
-	pj_cstr(&remote_uri, enclosed_uri);
-
-	pj_cstr(&target_uri, uri);
-
-	if (pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, &remote_uri, &target_uri, &dlg) != PJ_SUCCESS) {
-		return NULL;
-	}
-
-	if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
-		pjsip_dlg_terminate(dlg);
-		return NULL;
-	}
-
-	if (sip_dialog_create_from(dlg->pool, &local_uri, endpoint->fromuser, endpoint->fromdomain, &remote_uri, &selector)) {
-		pjsip_dlg_terminate(dlg);
-		return NULL;
-	}
-
-	/* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */
-	pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri);
-	dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0);
-	dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL);
-
-	/* If a request user has been specified and we are permitted to change it, do so */
-	if (!ast_strlen_zero(request_user)) {
-		pjsip_sip_uri *sip_uri;
-
-		if (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target)) {
-			sip_uri = pjsip_uri_get_uri(dlg->target);
-			pj_strdup2(dlg->pool, &sip_uri->user, request_user);
-		}
-		if (PJSIP_URI_SCHEME_IS_SIP(dlg->remote.info->uri) || PJSIP_URI_SCHEME_IS_SIPS(dlg->remote.info->uri)) {
-			sip_uri = pjsip_uri_get_uri(dlg->remote.info->uri);
-			pj_strdup2(dlg->pool, &sip_uri->user, request_user);
-		}
-	}
-
-	/* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */
-	dlg->sess_count++;
-
-	pjsip_dlg_set_transport(dlg, &selector);
-
-	if (!ast_strlen_zero(outbound_proxy)) {
-		pjsip_route_hdr route_set, *route;
-		static const pj_str_t ROUTE_HNAME = { "Route", 5 };
-		pj_str_t tmp;
-
-		pj_list_init(&route_set);
-
-		pj_strdup2_with_null(dlg->pool, &tmp, outbound_proxy);
-		if (!(route = pjsip_parse_hdr(dlg->pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
-			dlg->sess_count--;
-			pjsip_dlg_terminate(dlg);
-			return NULL;
-		}
-		pj_list_insert_nodes_before(&route_set, route);
-
-		pjsip_dlg_set_route_set(dlg, &route_set);
-	}
-
-	dlg->sess_count--;
-
-	return dlg;
-}
-
-pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
-{
-	pjsip_dialog *dlg;
-	pj_str_t contact;
-	pjsip_transport_type_e type = rdata->tp_info.transport->key.type;
-
-	ast_assert(status != NULL);
-
-	contact.ptr = pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE);
-	contact.slen = pj_ansi_snprintf(contact.ptr, PJSIP_MAX_URL_SIZE,
-			"<sip:%s%.*s%s:%d%s%s>",
-			(type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
-			(int)rdata->tp_info.transport->local_name.host.slen,
-			rdata->tp_info.transport->local_name.host.ptr,
-			(type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
-			rdata->tp_info.transport->local_name.port,
-			(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
-			(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
-
-	*status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
-	if (*status != PJ_SUCCESS) {
-		char err[PJ_ERR_MSG_SIZE];
-
-		pj_strerror(*status, err, sizeof(err));
-		ast_log(LOG_ERROR, "Could not create dialog with endpoint %s. %s\n",
-				ast_sorcery_object_get_id(endpoint), err);
-		return NULL;
-	}
-
-	return dlg;
-}
-
-int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
-	char *transport_type, const char *local_name, int local_port)
-{
-	pj_str_t tmp;
-
-	rdata->tp_info.transport = PJ_POOL_ZALLOC_T(rdata->tp_info.pool, pjsip_transport);
-	if (!rdata->tp_info.transport) {
-		return -1;
-	}
-
-	ast_copy_string(rdata->pkt_info.packet, packet, sizeof(rdata->pkt_info.packet));
-	ast_copy_string(rdata->pkt_info.src_name, src_name, sizeof(rdata->pkt_info.src_name));
-	rdata->pkt_info.src_port = src_port;
-
-	pjsip_parse_rdata(packet, strlen(packet), rdata);
-	if (!rdata->msg_info.msg) {
-		return -1;
-	}
-
-	pj_strdup2(rdata->tp_info.pool, &rdata->msg_info.via->recvd_param, rdata->pkt_info.src_name);
-	rdata->msg_info.via->rport_param = -1;
-
-	rdata->tp_info.transport->key.type = pjsip_transport_get_type_from_name(pj_cstr(&tmp, transport_type));
-	rdata->tp_info.transport->type_name = transport_type;
-	pj_strdup2(rdata->tp_info.pool, &rdata->tp_info.transport->local_name.host, local_name);
-	rdata->tp_info.transport->local_name.port = local_port;
-
-	return 0;
-}
-
-/* PJSIP doesn't know about the INFO method, so we have to define it ourselves */
-static const pjsip_method info_method = {PJSIP_OTHER_METHOD, {"INFO", 4} };
-static const pjsip_method message_method = {PJSIP_OTHER_METHOD, {"MESSAGE", 7} };
-
-static struct {
-	const char *method;
-	const pjsip_method *pmethod;
-} methods [] = {
-	{ "INVITE", &pjsip_invite_method },
-	{ "CANCEL", &pjsip_cancel_method },
-	{ "ACK", &pjsip_ack_method },
-	{ "BYE", &pjsip_bye_method },
-	{ "REGISTER", &pjsip_register_method },
-	{ "OPTIONS", &pjsip_options_method },
-	{ "SUBSCRIBE", &pjsip_subscribe_method },
-	{ "NOTIFY", &pjsip_notify_method },
-	{ "PUBLISH", &pjsip_publish_method },
-	{ "INFO", &info_method },
-	{ "MESSAGE", &message_method },
-};
-
-static const pjsip_method *get_pjsip_method(const char *method)
-{
-	int i;
-	for (i = 0; i < ARRAY_LEN(methods); ++i) {
-		if (!strcmp(method, methods[i].method)) {
-			return methods[i].pmethod;
-		}
-	}
-	return NULL;
-}
-
-static int create_in_dialog_request(const pjsip_method *method, struct pjsip_dialog *dlg, pjsip_tx_data **tdata)
-{
-	if (pjsip_dlg_create_request(dlg, method, -1, tdata) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to create in-dialog request.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata);
-static pjsip_module supplement_module = {
-	.name = { "Out of dialog supplement hook", 29 },
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION - 1,
-	.on_rx_request = supplement_on_rx_request,
-};
-
-static int create_out_of_dialog_request(const pjsip_method *method, struct ast_sip_endpoint *endpoint,
-		const char *uri, struct ast_sip_contact *provided_contact, pjsip_tx_data **tdata)
-{
-	RAII_VAR(struct ast_sip_contact *, contact, ao2_bump(provided_contact), ao2_cleanup);
-	pj_str_t remote_uri;
-	pj_str_t from;
-	pj_pool_t *pool;
-	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
-
-	if (ast_strlen_zero(uri)) {
-		if (!endpoint && (!contact || ast_strlen_zero(contact->uri))) {
-			ast_log(LOG_ERROR, "An endpoint and/or uri must be specified\n");
-			return -1;
-		}
-
-		if (!contact) {
-			contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
-		}
-		if (!contact || ast_strlen_zero(contact->uri)) {
-			ast_log(LOG_ERROR, "Unable to retrieve contact for endpoint %s\n",
-					ast_sorcery_object_get_id(endpoint));
-			return -1;
-		}
-
-		pj_cstr(&remote_uri, contact->uri);
-	} else {
-		pj_cstr(&remote_uri, uri);
-	}
-
-	if (endpoint) {
-		if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
-			ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport selector for endpoint %s\n",
-				ast_sorcery_object_get_id(endpoint));
-			return -1;
-		}
-	}
-
-	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound request", 256, 256);
-
-	if (!pool) {
-		ast_log(LOG_ERROR, "Unable to create PJLIB memory pool\n");
-		return -1;
-	}
-
-	if (sip_dialog_create_from(pool, &from, endpoint ? endpoint->fromuser : NULL,
-				endpoint ? endpoint->fromdomain : NULL, &remote_uri, &selector)) {
-		ast_log(LOG_ERROR, "Unable to create From header for %.*s request to endpoint %s\n",
-				(int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	if (pjsip_endpt_create_request(ast_sip_get_pjsip_endpoint(), method, &remote_uri,
-			&from, &remote_uri, &from, NULL, -1, NULL, tdata) != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to create outbound %.*s request to endpoint %s\n",
-				(int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	/* If an outbound proxy is specified on the endpoint apply it to this request */
-	if (endpoint && !ast_strlen_zero(endpoint->outbound_proxy) &&
-		ast_sip_set_outbound_proxy((*tdata), endpoint->outbound_proxy)) {
-		ast_log(LOG_ERROR, "Unable to apply outbound proxy on request %.*s to endpoint %s\n",
-			(int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	ast_sip_mod_data_set((*tdata)->pool, (*tdata)->mod_data, supplement_module.id, MOD_DATA_CONTACT, ao2_bump(contact));
-
-	/* We can release this pool since request creation copied all the necessary
-	 * data into the outbound request's pool
-	 */
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-	return 0;
-}
-
-int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
-		struct ast_sip_endpoint *endpoint, const char *uri,
-		struct ast_sip_contact *contact, pjsip_tx_data **tdata)
-{
-	const pjsip_method *pmethod = get_pjsip_method(method);
-
-	if (!pmethod) {
-		ast_log(LOG_WARNING, "Unknown method '%s'. Cannot send request\n", method);
-		return -1;
-	}
-
-	if (dlg) {
-		return create_in_dialog_request(pmethod, dlg, tdata);
-	} else {
-		return create_out_of_dialog_request(pmethod, endpoint, uri, contact, tdata);
-	}
-}
-
-AST_RWLIST_HEAD_STATIC(supplements, ast_sip_supplement);
-
-int ast_sip_register_supplement(struct ast_sip_supplement *supplement)
-{
-	struct ast_sip_supplement *iter;
-	int inserted = 0;
-	SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) {
-		if (iter->priority > supplement->priority) {
-			AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
-			inserted = 1;
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-
-	if (!inserted) {
-		AST_RWLIST_INSERT_TAIL(&supplements, supplement, next);
-	}
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
-{
-	struct ast_sip_supplement *iter;
-	SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) {
-		if (supplement == iter) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg)
-{
-	if (pjsip_dlg_send_request(dlg, tdata, -1, NULL) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to send in-dialog request.\n");
-		return -1;
-	}
-	return 0;
-}
-
-static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
-{
-	pj_str_t method;
-
-	if (ast_strlen_zero(supplement_method)) {
-		return PJ_TRUE;
-	}
-
-	pj_cstr(&method, supplement_method);
-
-	return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
-}
-
-/*! Maximum number of challenges before assuming that we are in a loop */
-#define MAX_RX_CHALLENGES	10
-
-/*! \brief Structure to hold information about an outbound request */
-struct send_request_data {
-	/*! The endpoint associated with this request */
-	struct ast_sip_endpoint *endpoint;
-	/*! Information to be provided to the callback upon receipt of a response */
-	void *token;
-	/*! The callback to be called upon receipt of a response */
-	void (*callback)(void *token, pjsip_event *e);
-	/*! Number of challenges received. */
-	unsigned int challenge_count;
-};
-
-static void send_request_data_destroy(void *obj)
-{
-	struct send_request_data *req_data = obj;
-
-	ao2_cleanup(req_data->endpoint);
-}
-
-static struct send_request_data *send_request_data_alloc(struct ast_sip_endpoint *endpoint,
-	void *token, void (*callback)(void *token, pjsip_event *e))
-{
-	struct send_request_data *req_data;
-
-	req_data = ao2_alloc_options(sizeof(*req_data), send_request_data_destroy,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!req_data) {
-		return NULL;
-	}
-
-	req_data->endpoint = ao2_bump(endpoint);
-	req_data->token = token;
-	req_data->callback = callback;
-
-	return req_data;
-}
-
-struct send_request_wrapper {
-	/*! Information to be provided to the callback upon receipt of a response */
-	void *token;
-	/*! The callback to be called upon receipt of a response */
-	void (*callback)(void *token, pjsip_event *e);
-	/*! Non-zero when the callback is called. */
-	unsigned int cb_called;
-};
-
-static void endpt_send_request_wrapper(void *token, pjsip_event *e)
-{
-	struct send_request_wrapper *req_wrapper = token;
-
-	req_wrapper->cb_called = 1;
-	if (req_wrapper->callback) {
-		req_wrapper->callback(req_wrapper->token, e);
-	}
-	ao2_ref(req_wrapper, -1);
-}
-
-static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
-	pjsip_tx_data *tdata, pj_int32_t timeout, void *token, pjsip_endpt_send_callback cb)
-{
-	struct send_request_wrapper *req_wrapper;
-	pj_status_t ret_val;
-
-	/* Create wrapper to detect if the callback was actually called on an error. */
-	req_wrapper = ao2_alloc_options(sizeof(*req_wrapper), NULL,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!req_wrapper) {
-		pjsip_tx_data_dec_ref(tdata);
-		return PJ_ENOMEM;
-	}
-	req_wrapper->token = token;
-	req_wrapper->callback = cb;
-
-	ao2_ref(req_wrapper, +1);
-	ret_val = pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, timeout,
-		req_wrapper, endpt_send_request_wrapper);
-	if (ret_val != PJ_SUCCESS) {
-		char errmsg[PJ_ERR_MSG_SIZE];
-
-		/* Complain of failure to send the request. */
-		pj_strerror(ret_val, errmsg, sizeof(errmsg));
-		ast_log(LOG_ERROR, "Error %d '%s' sending %.*s request to endpoint %s\n",
-			(int) ret_val, errmsg, (int) pj_strlen(&tdata->msg->line.req.method.name),
-			pj_strbuf(&tdata->msg->line.req.method.name),
-			endpoint ? ast_sorcery_object_get_id(endpoint) : "<unknown>");
-
-		/* Was the callback called? */
-		if (req_wrapper->cb_called) {
-			/*
-			 * Yes so we cannot report any error.  The callback
-			 * has already freed any resources associated with
-			 * token.
-			 */
-			ret_val = PJ_SUCCESS;
-		} else {
-			/* No and it is not expected to ever be called. */
-			ao2_ref(req_wrapper, -1);
-		}
-	}
-	ao2_ref(req_wrapper, -1);
-	return ret_val;
-}
-
-static void send_request_cb(void *token, pjsip_event *e)
-{
-	struct send_request_data *req_data = token;
-	pjsip_transaction *tsx;
-	pjsip_rx_data *challenge;
-	pjsip_tx_data *tdata;
-	struct ast_sip_supplement *supplement;
-	struct ast_sip_endpoint *endpoint;
-	int res;
-
-	switch(e->body.tsx_state.type) {
-	case PJSIP_EVENT_TRANSPORT_ERROR:
-	case PJSIP_EVENT_TIMER:
-		break;
-	case PJSIP_EVENT_RX_MSG:
-		challenge = e->body.tsx_state.src.rdata;
-
-		/*
-		 * Call any supplements that want to know about a response
-		 * with any received data.
-		 */
-		AST_RWLIST_RDLOCK(&supplements);
-		AST_LIST_TRAVERSE(&supplements, supplement, next) {
-			if (supplement->incoming_response
-				&& does_method_match(&challenge->msg_info.cseq->method.name,
-					supplement->method)) {
-				supplement->incoming_response(req_data->endpoint, challenge);
-			}
-		}
-		AST_RWLIST_UNLOCK(&supplements);
-
-		/* Resend the request with a challenge response if we are challenged. */
-		tsx = e->body.tsx_state.tsx;
-		endpoint = ao2_bump(req_data->endpoint);
-		res = (tsx->status_code == 401 || tsx->status_code == 407)
-			&& endpoint
-			&& ++req_data->challenge_count < MAX_RX_CHALLENGES /* Not in a challenge loop */
-			&& !ast_sip_create_request_with_auth(&endpoint->outbound_auths,
-				challenge, tsx, &tdata)
-			&& endpt_send_request(endpoint, tdata, -1, req_data, send_request_cb)
-				== PJ_SUCCESS;
-		ao2_cleanup(endpoint);
-		if (res) {
-			/*
-			 * Request with challenge response sent.
-			 * Passed our req_data ref to the new request.
-			 */
-			return;
-		}
-		break;
-	default:
-		ast_log(LOG_ERROR, "Unexpected PJSIP event %d\n", e->body.tsx_state.type);
-		break;
-	}
-
-	if (req_data->callback) {
-		req_data->callback(req_data->token, e);
-	}
-	ao2_ref(req_data, -1);
-}
-
-static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint,
-	void *token, void (*callback)(void *token, pjsip_event *e))
-{
-	struct ast_sip_supplement *supplement;
-	struct send_request_data *req_data;
-	struct ast_sip_contact *contact;
-
-	req_data = send_request_data_alloc(endpoint, token, callback);
-	if (!req_data) {
-		pjsip_tx_data_dec_ref(tdata);
-		return -1;
-	}
-
-	contact = ast_sip_mod_data_get(tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT);
-
-	AST_RWLIST_RDLOCK(&supplements);
-	AST_LIST_TRAVERSE(&supplements, supplement, next) {
-		if (supplement->outgoing_request
-			&& does_method_match(&tdata->msg->line.req.method.name, supplement->method)) {
-			supplement->outgoing_request(endpoint, contact, tdata);
-		}
-	}
-	AST_RWLIST_UNLOCK(&supplements);
-
-	ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
-	ao2_cleanup(contact);
-
-	if (endpt_send_request(endpoint, tdata, -1, req_data, send_request_cb)
-		!= PJ_SUCCESS) {
-		ao2_cleanup(req_data);
-		return -1;
-	}
-
-	return 0;
-}
-
-int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
-	struct ast_sip_endpoint *endpoint, void *token,
-	void (*callback)(void *token, pjsip_event *e))
-{
-	ast_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
-
-	if (dlg) {
-		return send_in_dialog_request(tdata, dlg);
-	} else {
-		return send_out_of_dialog_request(tdata, endpoint, token, callback);
-	}
-}
-
-int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
-{
-	pjsip_route_hdr *route;
-	static const pj_str_t ROUTE_HNAME = { "Route", 5 };
-	pj_str_t tmp;
-
-	pj_strdup2_with_null(tdata->pool, &tmp, proxy);
-	if (!(route = pjsip_parse_hdr(tdata->pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
-		return -1;
-	}
-
-	pj_list_insert_nodes_before(&tdata->msg->hdr, (pjsip_hdr*)route);
-
-	return 0;
-}
-
-int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
-{
-	pj_str_t hdr_name;
-	pj_str_t hdr_value;
-	pjsip_generic_string_hdr *hdr;
-
-	pj_cstr(&hdr_name, name);
-	pj_cstr(&hdr_value, value);
-
-	hdr = pjsip_generic_string_hdr_create(tdata->pool, &hdr_name, &hdr_value);
-
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
-	return 0;
-}
-
-static pjsip_msg_body *ast_body_to_pjsip_body(pj_pool_t *pool, const struct ast_sip_body *body)
-{
-	pj_str_t type;
-	pj_str_t subtype;
-	pj_str_t body_text;
-
-	pj_cstr(&type, body->type);
-	pj_cstr(&subtype, body->subtype);
-	pj_cstr(&body_text, body->body_text);
-
-	return pjsip_msg_body_create(pool, &type, &subtype, &body_text);
-}
-
-int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
-{
-	pjsip_msg_body *pjsip_body = ast_body_to_pjsip_body(tdata->pool, body);
-	tdata->msg->body = pjsip_body;
-	return 0;
-}
-
-int ast_sip_add_body_multipart(pjsip_tx_data *tdata, const struct ast_sip_body *bodies[], int num_bodies)
-{
-	int i;
-	/* NULL for type and subtype automatically creates "multipart/mixed" */
-	pjsip_msg_body *body = pjsip_multipart_create(tdata->pool, NULL, NULL);
-
-	for (i = 0; i < num_bodies; ++i) {
-		pjsip_multipart_part *part = pjsip_multipart_create_part(tdata->pool);
-		part->body = ast_body_to_pjsip_body(tdata->pool, bodies[i]);
-		pjsip_multipart_add_part(tdata->pool, body, part);
-	}
-
-	tdata->msg->body = body;
-	return 0;
-}
-
-int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text)
-{
-	size_t combined_size = strlen(body_text) + tdata->msg->body->len;
-	struct ast_str *body_buffer = ast_str_alloca(combined_size);
-
-	ast_str_set(&body_buffer, 0, "%.*s%s", (int) tdata->msg->body->len, (char *) tdata->msg->body->data, body_text);
-
-	tdata->msg->body->data = pj_pool_alloc(tdata->pool, combined_size);
-	pj_memcpy(tdata->msg->body->data, ast_str_buffer(body_buffer), combined_size);
-	tdata->msg->body->len = combined_size;
-
-	return 0;
-}
-
-struct ast_taskprocessor *ast_sip_create_serializer(void)
-{
-	struct ast_taskprocessor *serializer;
-	char name[AST_UUID_STR_LEN];
-
-	ast_uuid_generate_str(name, sizeof(name));
-
-	serializer = ast_threadpool_serializer(name, sip_threadpool);
-	if (!serializer) {
-		return NULL;
-	}
-	return serializer;
-}
-
-int ast_sip_push_task(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data)
-{
-	if (serializer) {
-		return ast_taskprocessor_push(serializer, sip_task, task_data);
-	} else {
-		return ast_threadpool_push(sip_threadpool, sip_task, task_data);
-	}
-}
-
-struct sync_task_data {
-	ast_mutex_t lock;
-	ast_cond_t cond;
-	int complete;
-	int fail;
-	int (*task)(void *);
-	void *task_data;
-};
-
-static int sync_task(void *data)
-{
-	struct sync_task_data *std = data;
-	std->fail = std->task(std->task_data);
-
-	ast_mutex_lock(&std->lock);
-	std->complete = 1;
-	ast_cond_signal(&std->cond);
-	ast_mutex_unlock(&std->lock);
-	return std->fail;
-}
-
-int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data)
-{
-	/* This method is an onion */
-	struct sync_task_data std;
-
-	if (ast_sip_thread_is_servant()) {
-		return sip_task(task_data);
-	}
-
-	memset(&std, 0, sizeof(std));
-	ast_mutex_init(&std.lock);
-	ast_cond_init(&std.cond, NULL);
-	std.task = sip_task;
-	std.task_data = task_data;
-
-	if (serializer) {
-		if (ast_taskprocessor_push(serializer, sync_task, &std)) {
-			ast_mutex_destroy(&std.lock);
-			ast_cond_destroy(&std.cond);
-			return -1;
-		}
-	} else {
-		if (ast_threadpool_push(sip_threadpool, sync_task, &std)) {
-			ast_mutex_destroy(&std.lock);
-			ast_cond_destroy(&std.cond);
-			return -1;
-		}
-	}
-
-	ast_mutex_lock(&std.lock);
-	while (!std.complete) {
-		ast_cond_wait(&std.cond, &std.lock);
-	}
-	ast_mutex_unlock(&std.lock);
-
-	ast_mutex_destroy(&std.lock);
-	ast_cond_destroy(&std.cond);
-	return std.fail;
-}
-
-void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
-{
-	size_t chars_to_copy = MIN(size - 1, pj_strlen(src));
-	memcpy(dest, pj_strbuf(src), chars_to_copy);
-	dest[chars_to_copy] = '\0';
-}
-
-int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
-{
-	pjsip_media_type compare;
-
-	if (!content_type) {
-		return 0;
-	}
-
-	pjsip_media_type_init2(&compare, type, subtype);
-
-	return pjsip_media_type_cmp(content_type, &compare, 0) ? 0 : -1;
-}
-
-pj_caching_pool caching_pool;
-pj_pool_t *memory_pool;
-pj_thread_t *monitor_thread;
-static int monitor_continue;
-
-static void *monitor_thread_exec(void *endpt)
-{
-	while (monitor_continue) {
-		const pj_time_val delay = {0, 10};
-		pjsip_endpt_handle_events(ast_pjsip_endpoint, &delay);
-	}
-	return NULL;
-}
-
-static void stop_monitor_thread(void)
-{
-	monitor_continue = 0;
-	pj_thread_join(monitor_thread);
-}
-
-AST_THREADSTORAGE(pj_thread_storage);
-AST_THREADSTORAGE(servant_id_storage);
-#define SIP_SERVANT_ID 0x5E2F1D
-
-static void sip_thread_start(void)
-{
-	pj_thread_desc *desc;
-	pj_thread_t *thread;
-	uint32_t *servant_id;
-
-	servant_id = ast_threadstorage_get(&servant_id_storage, sizeof(*servant_id));
-	if (!servant_id) {
-		ast_log(LOG_ERROR, "Could not set SIP servant ID in thread-local storage.\n");
-		return;
-	}
-	*servant_id = SIP_SERVANT_ID;
-
-	desc = ast_threadstorage_get(&pj_thread_storage, sizeof(pj_thread_desc));
-	if (!desc) {
-		ast_log(LOG_ERROR, "Could not get thread desc from thread-local storage. Expect awful things to occur\n");
-		return;
-	}
-	pj_bzero(*desc, sizeof(*desc));
-
-	if (pj_thread_register("Asterisk Thread", *desc, &thread) != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Couldn't register thread with PJLIB.\n");
-	}
-}
-
-int ast_sip_thread_is_servant(void)
-{
-	uint32_t *servant_id;
-
-	if (monitor_thread &&
-			pthread_self() == *(pthread_t *)pj_thread_get_os_handle(monitor_thread)) {
-		return 1;
-	}
-
-	servant_id = ast_threadstorage_get(&servant_id_storage, sizeof(*servant_id));
-	if (!servant_id) {
-		return 0;
-	}
-
-	return *servant_id == SIP_SERVANT_ID;
-}
-
-void *ast_sip_dict_get(void *ht, const char *key)
-{
-	unsigned int hval = 0;
-
-	if (!ht) {
-		return NULL;
-	}
-
-	return pj_hash_get(ht, key, PJ_HASH_KEY_STRING, &hval);
-}
-
-void *ast_sip_dict_set(pj_pool_t* pool, void *ht,
-		       const char *key, void *val)
-{
-	if (!ht) {
-		ht = pj_hash_create(pool, 11);
-	}
-
-	pj_hash_set(pool, ht, key, PJ_HASH_KEY_STRING, 0, val);
-
-	return ht;
-}
-
-static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata)
-{
-	struct ast_sip_supplement *supplement;
-
-	if (pjsip_rdata_get_dlg(rdata)) {
-		return PJ_FALSE;
-	}
-
-	AST_RWLIST_RDLOCK(&supplements);
-	AST_LIST_TRAVERSE(&supplements, supplement, next) {
-		if (supplement->incoming_request && does_method_match(&rdata->msg_info.msg->line.req.method.name, supplement->method)) {
-			supplement->incoming_request(ast_pjsip_rdata_get_endpoint(rdata), rdata);
-		}
-	}
-	AST_RWLIST_UNLOCK(&supplements);
-
-	return PJ_FALSE;
-}
-
-int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
-{
-	struct ast_sip_supplement *supplement;
-	pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	struct ast_sip_contact *contact = ast_sip_mod_data_get(tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT);
-
-	AST_RWLIST_RDLOCK(&supplements);
-	AST_LIST_TRAVERSE(&supplements, supplement, next) {
-		if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
-			supplement->outgoing_response(sip_endpoint, contact, tdata);
-		}
-	}
-	AST_RWLIST_UNLOCK(&supplements);
-
-	ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
-	ao2_cleanup(contact);
-
-	return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL);
-}
-
-int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
-	struct ast_sip_contact *contact, pjsip_tx_data **tdata)
-{
-	int res = pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, st_code, NULL, tdata);
-
-	if (!res) {
-		ast_sip_mod_data_set((*tdata)->pool, (*tdata)->mod_data, supplement_module.id, MOD_DATA_CONTACT, ao2_bump(contact));
-	}
-
-	return res;
-}
-
-static void remove_request_headers(pjsip_endpoint *endpt)
-{
-	const pjsip_hdr *request_headers = pjsip_endpt_get_request_headers(endpt);
-	pjsip_hdr *iter = request_headers->next;
-
-	while (iter != request_headers) {
-		pjsip_hdr *to_erase = iter;
-		iter = iter->next;
-		pj_list_erase(to_erase);
-	}
-}
-
-/*!
- * \internal
- * \brief Reload configuration within a PJSIP thread
- */
-static int reload_configuration_task(void *obj)
-{
-	ast_res_pjsip_reload_configuration();
-	ast_res_pjsip_init_options_handling(1);
-	ast_sip_initialize_dns();
-	return 0;
-}
-
-static int load_module(void)
-{
-	/* The third parameter is just copied from
-	 * example code from PJLIB. This can be adjusted
-	 * if necessary.
-	 */
-	pj_status_t status;
-	struct ast_threadpool_options options;
-
-	if (pj_init() != PJ_SUCCESS) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (pjlib_util_init() != PJ_SUCCESS) {
-		pj_shutdown();
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024);
-	if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n");
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	/* PJSIP will automatically try to add a Max-Forwards header. Since we want to control that,
-	 * we need to stop PJSIP from doing it automatically
-	 */
-	remove_request_headers(ast_pjsip_endpoint);
-
-	memory_pool = pj_pool_create(&caching_pool.factory, "SIP", 1024, 1024, NULL);
-	if (!memory_pool) {
-		ast_log(LOG_ERROR, "Failed to create memory pool for SIP. Aborting load\n");
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_initialize_system()) {
-		ast_log(LOG_ERROR, "Failed to initialize SIP 'system' configuration section. Aborting load\n");
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	sip_get_threadpool_options(&options);
-	options.thread_start = sip_thread_start;
-	sip_threadpool = ast_threadpool_create("SIP", NULL, &options);
-	if (!sip_threadpool) {
-		ast_log(LOG_ERROR, "Failed to create SIP threadpool. Aborting load\n");
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sip_initialize_dns();
-
-	pjsip_tsx_layer_init_module(ast_pjsip_endpoint);
-	pjsip_ua_init_module(ast_pjsip_endpoint, NULL);
-
-	monitor_continue = 1;
-	status = pj_thread_create(memory_pool, "SIP", (pj_thread_proc *) &monitor_thread_exec,
-			NULL, PJ_THREAD_DEFAULT_STACK_SIZE * 2, 0, &monitor_thread);
-	if (status != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Failed to start SIP monitor thread. Aborting load\n");
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sip_initialize_global_headers();
-
-	if (ast_res_pjsip_initialize_configuration(ast_module_info)) {
-		ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n");
-		ast_sip_destroy_global_headers();
-		stop_monitor_thread();
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_initialize_distributor()) {
-		ast_log(LOG_ERROR, "Failed to register distributor module. Aborting load\n");
-		ast_res_pjsip_destroy_configuration();
-		ast_sip_destroy_global_headers();
-		stop_monitor_thread();
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_register_service(&supplement_module)) {
-		ast_log(LOG_ERROR, "Failed to initialize supplement hooks. Aborting load\n");
-		ast_sip_destroy_distributor();
-		ast_res_pjsip_destroy_configuration();
-		ast_sip_destroy_global_headers();
-		stop_monitor_thread();
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_initialize_outbound_authentication()) {
-		ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n");
-		ast_sip_unregister_service(&supplement_module);
-		ast_sip_destroy_distributor();
-		ast_res_pjsip_destroy_configuration();
-		ast_sip_destroy_global_headers();
-		stop_monitor_thread();
-		ast_sip_destroy_system();
-		pj_pool_release(memory_pool);
-		memory_pool = NULL;
-		pjsip_endpt_destroy(ast_pjsip_endpoint);
-		ast_pjsip_endpoint = NULL;
-		pj_caching_pool_destroy(&caching_pool);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_res_pjsip_init_options_handling(0);
-
-	ast_module_ref(ast_module_info->self);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	if (ast_sip_push_task(NULL, reload_configuration_task, NULL)) {
-		ast_log(LOG_WARNING, "Failed to reload PJSIP\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	/* This will never get called as this module can't be unloaded */
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Basic SIP resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.reload = reload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
-);
diff --git a/res/res_pjsip.exports.in b/res/res_pjsip.exports.in
deleted file mode 100644
index 8b62abb..0000000
--- a/res/res_pjsip.exports.in
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_sip_*;
-		LINKER_SYMBOL_PREFIXast_copy_pj_str;
-		LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
-	local:
-		*;
-};
diff --git a/res/res_pjsip/config_auth.c b/res/res_pjsip/config_auth.c
deleted file mode 100644
index fcab6a8..0000000
--- a/res/res_pjsip/config_auth.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-#include "asterisk/res_pjsip.h"
-#include "asterisk/logger.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/cli.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/res_pjsip_cli.h"
-
-static void auth_destroy(void *obj)
-{
-	struct ast_sip_auth *auth = obj;
-	ast_string_field_free_memory(auth);
-}
-
-static void *auth_alloc(const char *name)
-{
-	struct ast_sip_auth *auth = ast_sorcery_generic_alloc(sizeof(*auth), auth_destroy);
-
-	if (!auth) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(auth, 64)) {
-		ao2_cleanup(auth);
-		return NULL;
-	}
-
-	return auth;
-}
-
-static int auth_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_auth *auth = obj;
-	if (!strcasecmp(var->value, "userpass")) {
-		auth->type = AST_SIP_AUTH_TYPE_USER_PASS;
-	} else if (!strcasecmp(var->value, "md5")) {
-		auth->type = AST_SIP_AUTH_TYPE_MD5;
-	} else {
-		ast_log(LOG_WARNING, "Unknown authentication storage type '%s' specified for %s\n",
-				var->value, var->name);
-		return -1;
-	}
-	return 0;
-}
-
-static const char *auth_types_map[] = {
-	[AST_SIP_AUTH_TYPE_USER_PASS] = "userpass",
-	[AST_SIP_AUTH_TYPE_MD5] = "md5"
-};
-
-const char *ast_sip_auth_type_to_str(enum ast_sip_auth_type type)
-{
-	return ARRAY_IN_BOUNDS(type, auth_types_map) ?
-		auth_types_map[type] : "";
-}
-
-static int auth_type_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_auth *auth = obj;
-	*buf = ast_strdup(ast_sip_auth_type_to_str(auth->type));
-	return 0;
-}
-
-static int auth_apply(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct ast_sip_auth *auth = obj;
-	int res = 0;
-
-	if (ast_strlen_zero(auth->auth_user)) {
-		ast_log(LOG_ERROR, "No authentication username for auth '%s'\n",
-				ast_sorcery_object_get_id(auth));
-		return -1;
-	}
-
-	switch (auth->type) {
-	case AST_SIP_AUTH_TYPE_MD5:
-		if (ast_strlen_zero(auth->md5_creds)) {
-			ast_log(LOG_ERROR, "'md5' authentication specified but no md5_cred "
-					"specified for auth '%s'\n", ast_sorcery_object_get_id(auth));
-			res = -1;
-		} else if (strlen(auth->md5_creds) != PJSIP_MD5STRLEN) {
-			ast_log(LOG_ERROR, "'md5' authentication requires digest of size '%d', but "
-				"digest is '%d' in size for auth '%s'\n", PJSIP_MD5STRLEN, (int)strlen(auth->md5_creds),
-				ast_sorcery_object_get_id(auth));
-			res = -1;
-		}
-		break;
-	case AST_SIP_AUTH_TYPE_USER_PASS:
-	case AST_SIP_AUTH_TYPE_ARTIFICIAL:
-		break;
-	}
-
-	return res;
-}
-
-int ast_sip_for_each_auth(const struct ast_sip_auth_vector *vector,
-			  ao2_callback_fn on_auth, void *arg)
-{
-	int i;
-
-	if (!vector || !AST_VECTOR_SIZE(vector)) {
-		return 0;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(vector); ++i) {
-		/* AST_VECTOR_GET is safe to use since the vector is immutable */
-		RAII_VAR(struct ast_sip_auth *, auth, ast_sorcery_retrieve_by_id(
-				 ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE,
-				 AST_VECTOR_GET(vector,i)), ao2_cleanup);
-
-		if (!auth) {
-			continue;
-		}
-
-		if (on_auth(auth, arg, 0)) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int sip_auth_to_ami(const struct ast_sip_auth *auth,
-			   struct ast_str **buf)
-{
-	return ast_sip_sorcery_object_to_ami(auth, buf);
-}
-
-static int format_ami_auth_handler(void *obj, void *arg, int flags)
-{
-	const struct ast_sip_auth *auth = obj;
-	struct ast_sip_ami *ami = arg;
-	const struct ast_sip_endpoint *endpoint = ami->arg;
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("AuthDetail", ami), ast_free);
-
-	if (!buf) {
-		return -1;
-	}
-
-	if (sip_auth_to_ami(auth, &buf)) {
-		return -1;
-	}
-
-	if (endpoint) {
-		ast_str_append(&buf, 0, "EndpointName: %s\r\n",
-		       ast_sorcery_object_get_id(endpoint));
-	}
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	ami->count++;
-
-	return 0;
-}
-
-int ast_sip_format_auths_ami(const struct ast_sip_auth_vector *auths,
-			     struct ast_sip_ami *ami)
-{
-	return ast_sip_for_each_auth(auths, format_ami_auth_handler, ami);
-}
-
-static int format_ami_endpoint_auth(const struct ast_sip_endpoint *endpoint,
-				    struct ast_sip_ami *ami)
-{
-	ami->arg = (void *)endpoint;
-	if (ast_sip_format_auths_ami(&endpoint->inbound_auths, ami)) {
-		return -1;
-	}
-
-	return ast_sip_format_auths_ami(&endpoint->outbound_auths, ami);
-}
-
-static struct ast_sip_endpoint_formatter endpoint_auth_formatter = {
-	.format_ami = format_ami_endpoint_auth
-};
-
-static struct ao2_container *cli_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
-	struct ao2_container *s_container;
-
-	container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "auth",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!container) {
-		return NULL;
-	}
-
-	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!s_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_container, container, 0)) {
-		ao2_ref(s_container, -1);
-		return NULL;
-	}
-
-	return s_container;
-}
-
-static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
-{
-	return ast_sip_for_each_auth(container, callback, args);
-}
-
-static void *cli_retrieve_by_id(const char *id)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, id);
-}
-
-static int cli_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_MAX_WIDTH - indent - 20;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <AuthId/UserName%*.*s>\n", indent, "I/OAuth", filler, filler,
-		CLI_HEADER_FILLER);
-
-	return 0;
-}
-
-static int cli_print_body(void *obj, void *arg, int flags)
-{
-	struct ast_sip_auth *auth = obj;
-	struct ast_sip_cli_context *context = arg;
-	char title[32];
-
-	ast_assert(context->output_buffer != NULL);
-
-	snprintf(title, sizeof(title), "%sAuth",
-		context->auth_direction ? context->auth_direction : "");
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %s/%s\n",
-		CLI_INDENT_TO_SPACES(context->indent_level), title,
-		ast_sorcery_object_get_id(auth), auth->auth_user);
-
-	if (context->show_details
-		|| (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(auth, context, 0);
-	}
-
-	return 0;
-}
-
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Auths",
-		.command = "pjsip list auths",
-		.usage = "Usage: pjsip list auths\n"
-				 "       List the configured PJSIP Auths\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Auths",
-		.command = "pjsip show auths",
-		.usage = "Usage: pjsip show auths\n"
-				 "       Show the configured PJSIP Auths\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Auth",
-		.command = "pjsip show auth",
-		.usage = "Usage: pjsip show auth <id>\n"
-				 "       Show the configured PJSIP Auth\n"),
-};
-
-static struct ast_sip_cli_formatter_entry *cli_formatter;
-
-/*! \brief Initialize sorcery with auth support */
-int ast_sip_initialize_sorcery_auth(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-
-	ast_sorcery_apply_default(sorcery, SIP_SORCERY_AUTH_TYPE, "config", "pjsip.conf,criteria=type=auth");
-
-	if (ast_sorcery_object_register(sorcery, SIP_SORCERY_AUTH_TYPE, auth_alloc, NULL, auth_apply)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "type", "",
-			OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "username",
-			"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_user));
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "password",
-			"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_pass));
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "md5_cred",
-			"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, md5_creds));
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "realm",
-			"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, realm));
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime",
-			"32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime));
-	ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type",
-			"userpass", auth_type_handler, auth_type_to_str, NULL, 0, 0);
-
-	ast_sip_register_endpoint_formatter(&endpoint_auth_formatter);
-
-	cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!cli_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
-		return -1;
-	}
-	cli_formatter->name = SIP_SORCERY_AUTH_TYPE;
-	cli_formatter->print_header = cli_print_header;
-	cli_formatter->print_body = cli_print_body;
-	cli_formatter->get_container = cli_get_container;
-	cli_formatter->iterate = cli_iterator;
-	cli_formatter->get_id = ast_sorcery_object_get_id;
-	cli_formatter->retrieve_by_id = cli_retrieve_by_id;
-
-	ast_sip_register_cli_formatter(cli_formatter);
-	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
-
-	return 0;
-}
-
-int ast_sip_destroy_sorcery_auth(void)
-{
-	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_sip_unregister_cli_formatter(cli_formatter);
-
-	return 0;
-}
diff --git a/res/res_pjsip/config_domain_aliases.c b/res/res_pjsip/config_domain_aliases.c
deleted file mode 100644
index 232adac..0000000
--- a/res/res_pjsip/config_domain_aliases.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include "pjsip.h"
-#include "pjlib.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/logger.h"
-#include "asterisk/sorcery.h"
-
-static void domain_alias_destroy(void *obj)
-{
-	struct ast_sip_domain_alias *alias = obj;
-
-	ast_string_field_free_memory(alias);
-}
-
-static void *domain_alias_alloc(const char *name)
-{
-        struct ast_sip_domain_alias *alias = ast_sorcery_generic_alloc(sizeof(*alias), domain_alias_destroy);
-
-	if (!alias) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(alias, 256)) {
-		ao2_cleanup(alias);
-		return NULL;
-	}
-
-	return alias;
-}
-
-/*! \brief Initialize sorcery with domain alias support */
-int ast_sip_initialize_sorcery_domain_alias(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-
-	ast_sorcery_apply_default(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "config", "pjsip.conf,criteria=type=domain_alias");
-
-	if (ast_sorcery_object_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, domain_alias_alloc, NULL, NULL)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "type", "",
-			OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "domain",
-			"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_domain_alias, domain));
-
-	return 0;
-}
diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c
deleted file mode 100644
index 8e2cb2a..0000000
--- a/res/res_pjsip/config_global.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/ast_version.h"
-
-#define DEFAULT_MAX_FORWARDS 70
-#define DEFAULT_USERAGENT_PREFIX "Asterisk PBX"
-#define DEFAULT_OUTBOUND_ENDPOINT "default_outbound_endpoint"
-
-static char default_useragent[128];
-
-struct global_config {
-	SORCERY_OBJECT(details);
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(useragent);
-		AST_STRING_FIELD(default_outbound_endpoint);
-		/*! Debug logging yes|no|host */
-		AST_STRING_FIELD(debug);
-	);
-	/* Value to put in Max-Forwards header */
-	unsigned int max_forwards;
-};
-
-static void global_destructor(void *obj)
-{
-	struct global_config *cfg = obj;
-
-	ast_string_field_free_memory(cfg);
-}
-
-static void *global_alloc(const char *name)
-{
-	struct global_config *cfg = ast_sorcery_generic_alloc(sizeof(*cfg), global_destructor);
-
-	if (!cfg || ast_string_field_init(cfg, 80)) {
-		return NULL;
-	}
-
-	return cfg;
-}
-
-static int global_apply(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct global_config *cfg = obj;
-	char max_forwards[10];
-
-	snprintf(max_forwards, sizeof(max_forwards), "%u", cfg->max_forwards);
-
-	ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1);
-	ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1);
-	ast_sip_add_global_response_header("Server", cfg->useragent, 1);
-	return 0;
-}
-
-static struct global_config *get_global_cfg(void)
-{
-	RAII_VAR(struct ao2_container *, globals, ast_sorcery_retrieve_by_fields(
-			 ast_sip_get_sorcery(), "global", AST_RETRIEVE_FLAG_MULTIPLE,
-			 NULL), ao2_cleanup);
-
-	if (!globals) {
-		return NULL;
-	}
-
-	return ao2_find(globals, NULL, 0);
-}
-
-char *ast_sip_global_default_outbound_endpoint(void)
-{
-	RAII_VAR(struct global_config *, cfg, get_global_cfg(), ao2_cleanup);
-
-	if (!cfg) {
-		return NULL;
-	}
-
-	return ast_strdup(cfg->default_outbound_endpoint);
-}
-
-char *ast_sip_get_debug(void)
-{
-	char *res;
-	struct global_config *cfg = get_global_cfg();
-
-	if (!cfg) {
-		return ast_strdup("no");
-	}
-
-	res = ast_strdup(cfg->debug);
-	ao2_ref(cfg, -1);
-
-	return res;
-}
-
-int ast_sip_initialize_sorcery_global(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-
-	snprintf(default_useragent, sizeof(default_useragent), "%s %s", DEFAULT_USERAGENT_PREFIX, ast_get_version());
-
-	ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global");
-
-	if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, "global", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "global", "max_forwards", __stringify(DEFAULT_MAX_FORWARDS),
-			OPT_UINT_T, 0, FLDSET(struct global_config, max_forwards));
-	ast_sorcery_object_field_register(sorcery, "global", "user_agent", default_useragent,
-			OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, useragent));
-	ast_sorcery_object_field_register(sorcery, "global", "default_outbound_endpoint", DEFAULT_OUTBOUND_ENDPOINT,
-			OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_outbound_endpoint));
-	ast_sorcery_object_field_register(sorcery, "global", "debug", "no",
-			OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, debug));
-
-	return 0;
-}
diff --git a/res/res_pjsip/config_system.c b/res/res_pjsip/config_system.c
deleted file mode 100644
index a41af90..0000000
--- a/res/res_pjsip/config_system.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/sorcery.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/threadpool.h"
-#include "asterisk/dns.h"
-
-#define TIMER_T1_MIN 100
-#define DEFAULT_TIMER_T1 500
-#define DEFAULT_TIMER_B 32000
-
-struct system_config {
-	SORCERY_OBJECT(details);
-	/*! Transaction Timer T1 value */
-	unsigned int timert1;
-	/*! Transaction Timer B value */
-	unsigned int timerb;
-	/*! Should we use short forms for headers? */
-	unsigned int compactheaders;
-	struct {
-		/*! Initial number of threads in the threadpool */
-		int initial_size;
-		/*! The amount by which the number of threads is incremented when necessary */
-		int auto_increment;
-		/*! Thread idle timeout in seconds */
-		int idle_timeout;
-		/*! Maxumum number of threads in the threadpool */
-		int max_size;
-	} threadpool;
-	/*! Nonzero to disable switching from UDP to TCP transport */
-	unsigned int disable_tcp_switch;
-};
-
-static struct ast_threadpool_options sip_threadpool_options = {
-	.version = AST_THREADPOOL_OPTIONS_VERSION,
-};
-
-void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options)
-{
-	*threadpool_options = sip_threadpool_options;
-}
-
-static struct ast_sorcery *system_sorcery;
-
-static void *system_alloc(const char *name)
-{
-	struct system_config *system = ast_sorcery_generic_alloc(sizeof(*system), NULL);
-
-	if (!system) {
-		return NULL;
-	}
-
-	return system;
-}
-
-static int system_apply(const struct ast_sorcery *system_sorcery, void *obj)
-{
-	struct system_config *system = obj;
-	int min_timerb;
-
-	if (system->timert1 < TIMER_T1_MIN) {
-		ast_log(LOG_WARNING, "Timer T1 setting is too low. Setting to %d\n", TIMER_T1_MIN);
-		system->timert1 = TIMER_T1_MIN;
-	}
-
-	min_timerb = 64 * system->timert1;
-
-	if (system->timerb < min_timerb) {
-		ast_log(LOG_WARNING, "Timer B setting is too low. Setting to %d\n", min_timerb);
-		system->timerb = min_timerb;
-	}
-
-	pjsip_cfg()->tsx.t1 = system->timert1;
-	pjsip_cfg()->tsx.td = system->timerb;
-
-	if (system->compactheaders) {
-		extern pj_bool_t pjsip_use_compact_form;
-
-		pjsip_use_compact_form = PJ_TRUE;
-	}
-
-	sip_threadpool_options.initial_size = system->threadpool.initial_size;
-	sip_threadpool_options.auto_increment = system->threadpool.auto_increment;
-	sip_threadpool_options.idle_timeout = system->threadpool.idle_timeout;
-	sip_threadpool_options.max_size = system->threadpool.max_size;
-
-	pjsip_cfg()->endpt.disable_tcp_switch =
-		system->disable_tcp_switch ? PJ_TRUE : PJ_FALSE;
-
-	return 0;
-}
-
-int ast_sip_initialize_system(void)
-{
-	RAII_VAR(struct ao2_container *, system_configs, NULL, ao2_cleanup);
-	RAII_VAR(struct system_config *, system, NULL, ao2_cleanup);
-
-	system_sorcery = ast_sorcery_open();
-	if (!system_sorcery) {
-		ast_log(LOG_ERROR, "Failed to open SIP system sorcery\n");
-		return -1;
-	}
-
-	ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
-
-	if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
-		ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");
-		ast_sorcery_unref(system_sorcery);
-		system_sorcery = NULL;
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(system_sorcery, "system", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(system_sorcery, "system", "timer_t1", __stringify(DEFAULT_TIMER_T1),
-			OPT_UINT_T, 0, FLDSET(struct system_config, timert1));
-	ast_sorcery_object_field_register(system_sorcery, "system", "timer_b", __stringify(DEFAULT_TIMER_B),
-			OPT_UINT_T, 0, FLDSET(struct system_config, timerb));
-	ast_sorcery_object_field_register(system_sorcery, "system", "compact_headers", "no",
-			OPT_BOOL_T, 1, FLDSET(struct system_config, compactheaders));
-	ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_initial_size", "0",
-			OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.initial_size));
-	ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_auto_increment", "5",
-			OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.auto_increment));
-	ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_idle_timeout", "60",
-			OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.idle_timeout));
-	ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_max_size", "0",
-			OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.max_size));
-	ast_sorcery_object_field_register(system_sorcery, "system", "disable_tcp_switch", "yes",
-			OPT_BOOL_T, 1, FLDSET(struct system_config, disable_tcp_switch));
-
-	ast_sorcery_load(system_sorcery);
-
-	system_configs = ast_sorcery_retrieve_by_fields(system_sorcery, "system",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-
-	if (ao2_container_count(system_configs)) {
-		return 0;
-	}
-
-	/* No config present, allocate one and apply defaults */
-	system = ast_sorcery_alloc(system_sorcery, "system", NULL);
-	if (!system) {
-		ast_log(LOG_ERROR, "Unable to allocate default system config.\n");
-		ast_sorcery_unref(system_sorcery);
-		return -1;
-	}
-
-	if (system_apply(system_sorcery, system)) {
-		ast_log(LOG_ERROR, "Failed to apply default system config.\n");
-		ast_sorcery_unref(system_sorcery);
-		return -1;
-	}
-
-	return 0;
-}
-
-void ast_sip_destroy_system(void)
-{
-	ast_sorcery_unref(system_sorcery);
-}
-
-static int system_create_resolver_and_set_nameservers(void *data)
-{
-	struct ao2_container *discovered_nameservers;
-	struct ao2_iterator it_nameservers;
-	char *nameserver;
-	pj_status_t status;
-	pj_dns_resolver *resolver;
-	pj_str_t nameservers[PJ_DNS_RESOLVER_MAX_NS];
-	unsigned int count = 0;
-
-	discovered_nameservers = ast_dns_get_nameservers();
-	if (!discovered_nameservers) {
-		ast_log(LOG_ERROR, "Could not retrieve local system nameservers, resorting to system resolution\n");
-		return 0;
-	}
-
-	if (!ao2_container_count(discovered_nameservers)) {
-		ast_log(LOG_ERROR, "There are no local system nameservers configured, resorting to system resolution\n");
-		ao2_ref(discovered_nameservers, -1);
-		return -1;
-	}
-
-	if (!(resolver = pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint()))) {
-		status = pjsip_endpt_create_resolver(ast_sip_get_pjsip_endpoint(), &resolver);
-		if (status != PJ_SUCCESS) {
-			ast_log(LOG_ERROR, "Could not create DNS resolver(%d), resorting to system resolution\n", status);
-			ao2_ref(discovered_nameservers, -1);
-			return 0;
-		}
-	}
-
-	it_nameservers = ao2_iterator_init(discovered_nameservers, 0);
-	while ((nameserver = ao2_iterator_next(&it_nameservers))) {
-		pj_strset2(&nameservers[count++], nameserver);
-		ao2_ref(nameserver, -1);
-
-		if (count == (PJ_DNS_RESOLVER_MAX_NS - 1)) {
-			break;
-		}
-	}
-	ao2_iterator_destroy(&it_nameservers);
-
-	status = pj_dns_resolver_set_ns(resolver, count, nameservers, NULL);
-
-	/* Since we no longer need the nameservers we can drop the list of them */
-	ao2_ref(discovered_nameservers, -1);
-
-	if (status != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Could not set nameservers on DNS resolver in PJSIP(%d), resorting to system resolution\n",
-			status);
-		return 0;
-	}
-
-	if (!pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint())) {
-		status = pjsip_endpt_set_resolver(ast_sip_get_pjsip_endpoint(), resolver);
-		if (status != PJ_SUCCESS) {
-			ast_log(LOG_ERROR, "Could not set DNS resolver in PJSIP(%d), resorting to system resolution\n", status);
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-void ast_sip_initialize_dns(void)
-{
-	ast_sip_push_task_synchronous(NULL, system_create_resolver_and_set_nameservers, NULL);
-}
diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c
deleted file mode 100644
index fe7612f..0000000
--- a/res/res_pjsip/config_transport.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_cli.h"
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/acl.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/http_websocket.h"
-
-static int sip_transport_to_ami(const struct ast_sip_transport *transport,
-				struct ast_str **buf)
-{
-	return ast_sip_sorcery_object_to_ami(transport, buf);
-}
-
-static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint,
-					 struct ast_sip_ami *ami)
-{
-	RAII_VAR(struct ast_str *, buf, NULL, ast_free);
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(endpoint->transport)) {
-		return 0;
-	}
-
-	buf = ast_sip_create_ami_event("TransportDetail", ami);
-	if (!buf) {
-		return -1;
-	}
-
-	transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
-		endpoint->transport);
-	if (!transport) {
-		astman_send_error_va(ami->s, ami->m, "Unable to retrieve "
-				     "transport %s\n", endpoint->transport);
-		return -1;
-	}
-
-	sip_transport_to_ami(transport, &buf);
-
-	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
-		       ast_sorcery_object_get_id(endpoint));
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	ami->count++;
-
-	return 0;
-}
-
-struct ast_sip_endpoint_formatter endpoint_transport_formatter = {
-	.format_ami = format_ami_endpoint_transport
-};
-
-static int destroy_transport_state(void *data)
-{
-	pjsip_transport *transport = data;
-	pjsip_transport_shutdown(transport);
-	return 0;
-}
-
-/*! \brief Destructor for transport state information */
-static void transport_state_destroy(void *obj)
-{
-	struct ast_sip_transport_state *state = obj;
-
-	if (state->transport) {
-		ast_sip_push_task_synchronous(NULL, destroy_transport_state, state->transport);
-	}
-}
-
-/*! \brief Destructor for transport */
-static void transport_destroy(void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-
-	ast_string_field_free_memory(transport);
-	ast_free_ha(transport->localnet);
-
-	if (transport->external_address_refresher) {
-		ast_dnsmgr_release(transport->external_address_refresher);
-	}
-
-	ao2_cleanup(transport->state);
-}
-
-/*! \brief Allocator for transport */
-static void *transport_alloc(const char *name)
-{
-	struct ast_sip_transport *transport = ast_sorcery_generic_alloc(sizeof(*transport), transport_destroy);
-
-	if (!transport) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(transport, 256)) {
-		ao2_cleanup(transport);
-		return NULL;
-	}
-
-	pjsip_tls_setting_default(&transport->tls);
-	transport->tls.ciphers = transport->ciphers;
-
-	return transport;
-}
-
-static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos)
-{
-	int tos_as_dscp = transport->tos >> 2;
-
-	if (transport->tos) {
-		qos->flags |= PJ_QOS_PARAM_HAS_DSCP;
-		qos->dscp_val = tos_as_dscp;
-	}
-	if (transport->cos) {
-		qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO;
-		qos->so_prio = transport->cos;
-	}
-}
-
-/*! \brief Apply handler for transports */
-static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-	RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup);
-	pj_status_t res = -1;
-
-	if (!existing || !existing->state) {
-		if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) {
-			ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj));
-			return -1;
-		}
-	} else {
-		transport->state = existing->state;
-		ao2_ref(transport->state, +1);
-	}
-
-	/* Once active a transport can not be reconfigured */
-	if (transport->state->transport || transport->state->factory) {
-		return -1;
-	}
-
-	if (transport->host.addr.sa_family != PJ_AF_INET && transport->host.addr.sa_family != PJ_AF_INET6) {
-		ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", ast_sorcery_object_get_id(obj));
-		return -1;
-	}
-
-	/* Set default port if not present */
-	if (!pj_sockaddr_get_port(&transport->host)) {
-		pj_sockaddr_set_port(&transport->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060);
-	}
-
-	/* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
-	if (!ast_strlen_zero(transport->external_signaling_address)) {
-		if (transport->host.addr.sa_family == pj_AF_INET()) {
-			transport->external_address.ss.ss_family = AF_INET;
-		} else if (transport->host.addr.sa_family == pj_AF_INET6()) {
-			transport->external_address.ss.ss_family = AF_INET6;
-		} else {
-			ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
-					ast_sorcery_object_get_id(obj));
-			return -1;
-		}
-
-		if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) {
-			ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj));
-			return -1;
-		}
-	}
-
-	if (transport->type == AST_TRANSPORT_UDP) {
-		if (transport->host.addr.sa_family == pj_AF_INET()) {
-			res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport);
-		} else if (transport->host.addr.sa_family == pj_AF_INET6()) {
-			res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport);
-		}
-
-		if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
-			pj_sock_t sock;
-			pj_qos_params qos_params;
-
-			sock = pjsip_udp_transport_get_socket(transport->state->transport);
-			pj_sock_get_qos_params(sock, &qos_params);
-			set_qos(transport, &qos_params);
-			pj_sock_set_qos_params(sock, &qos_params);
-		}
-	} else if (transport->type == AST_TRANSPORT_TCP) {
-		pjsip_tcp_transport_cfg cfg;
-
-		pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family);
-		cfg.bind_addr = transport->host;
-		cfg.async_cnt = transport->async_operations;
-		set_qos(transport, &cfg.qos_params);
-
-		res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory);
-	} else if (transport->type == AST_TRANSPORT_TLS) {
-		transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file);
-		transport->tls.cert_file = pj_str((char*)transport->cert_file);
-		transport->tls.privkey_file = pj_str((char*)transport->privkey_file);
-		transport->tls.password = pj_str((char*)transport->password);
-		set_qos(transport, &transport->tls.qos_params);
-
-		res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory);
-	} else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
-		if (transport->cos || transport->tos) {
-			ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
-		}
-		res = PJ_SUCCESS;
-	}
-
-	if (res != PJ_SUCCESS) {
-		char msg[PJ_ERR_MSG_SIZE];
-
-		pj_strerror(res, msg, sizeof(msg));
-		ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
-		return -1;
-	}
-	return 0;
-}
-
-/*! \brief Custom handler for turning a string protocol into an enum */
-static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-
-	if (!strcasecmp(var->value, "udp")) {
-		transport->type = AST_TRANSPORT_UDP;
-	} else if (!strcasecmp(var->value, "tcp")) {
-		transport->type = AST_TRANSPORT_TCP;
-	} else if (!strcasecmp(var->value, "tls")) {
-		transport->type = AST_TRANSPORT_TLS;
-	} else if (!strcasecmp(var->value, "ws")) {
-		transport->type = AST_TRANSPORT_WS;
-	} else if (!strcasecmp(var->value, "wss")) {
-		transport->type = AST_TRANSPORT_WSS;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static const char *transport_types[] = {
-	[AST_TRANSPORT_UDP] = "udp",
-	[AST_TRANSPORT_TCP] = "tcp",
-	[AST_TRANSPORT_TLS] = "tls",
-	[AST_TRANSPORT_WS] = "ws",
-	[AST_TRANSPORT_WSS] = "wss"
-};
-
-static int transport_protocol_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-
-	if (ARRAY_IN_BOUNDS(transport->type, transport_types)) {
-		*buf = ast_strdup(transport_types[transport->type]);
-	}
-
-	return 0;
-}
-
-/*! \brief Custom handler for turning a string bind into a pj_sockaddr */
-static int transport_bind_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-	pj_str_t buf;
-	int rc = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &transport->host);
-
-	return rc != PJ_SUCCESS ? -1 : 0;
-}
-
-static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-
-	if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
-		return -1;
-	}
-
-	/* include port as well as brackets if IPv6 */
-	pj_sockaddr_print(&transport->host, *buf, MAX_OBJECT_FIELD, 1 | 2);
-
-	return 0;
-}
-
-/*! \brief Custom handler for TLS boolean settings */
-static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-
-	if (!strcasecmp(var->name, "verify_server")) {
-		transport->tls.verify_server = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
-	} else if (!strcasecmp(var->name, "verify_client")) {
-		transport->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
-	} else if (!strcasecmp(var->name, "require_client_cert")) {
-		transport->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-	*buf = ast_strdup(AST_YESNO(transport->tls.verify_server));
-	return 0;
-}
-
-static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-	*buf = ast_strdup(AST_YESNO(transport->tls.verify_client));
-	return 0;
-}
-
-static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-	*buf = ast_strdup(AST_YESNO(transport->tls.require_client_cert));
-	return 0;
-}
-
-/*! \brief Custom handler for TLS method setting */
-static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-
-	if (ast_strlen_zero(var->value) || !strcasecmp(var->value, "default")) {
-		transport->tls.method = PJSIP_SSL_DEFAULT_METHOD;
-	} else if (!strcasecmp(var->value, "unspecified")) {
-		transport->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD;
-	} else if (!strcasecmp(var->value, "tlsv1")) {
-		transport->tls.method = PJSIP_TLSV1_METHOD;
-	} else if (!strcasecmp(var->value, "sslv2")) {
-		transport->tls.method = PJSIP_SSLV2_METHOD;
-	} else if (!strcasecmp(var->value, "sslv3")) {
-		transport->tls.method = PJSIP_SSLV3_METHOD;
-	} else if (!strcasecmp(var->value, "sslv23")) {
-		transport->tls.method = PJSIP_SSLV23_METHOD;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static const char *tls_method_map[] = {
-	[PJSIP_SSL_DEFAULT_METHOD] = "default",
-	[PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified",
-	[PJSIP_TLSV1_METHOD] = "tlsv1",
-	[PJSIP_SSLV2_METHOD] = "sslv2",
-	[PJSIP_SSLV3_METHOD] = "sslv3",
-	[PJSIP_SSLV23_METHOD] = "sslv23",
-};
-
-static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-	if (ARRAY_IN_BOUNDS(transport->tls.method, tls_method_map)) {
-		*buf = ast_strdup(tls_method_map[transport->tls.method]);
-	}
-	return 0;
-}
-
-/*! \brief Helper function which turns a cipher name into an identifier */
-static pj_ssl_cipher cipher_name_to_id(const char *name)
-{
-	pj_ssl_cipher ciphers[100];
-	pj_ssl_cipher id = 0;
-	unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
-	int pos;
-	const char *pos_name;
-
-	if (pj_ssl_cipher_get_availables(ciphers, &cipher_num)) {
-		return 0;
-	}
-
-	for (pos = 0; pos < cipher_num; ++pos) {
-		pos_name = pj_ssl_cipher_name(ciphers[pos]);
-		if (!pos_name || strcmp(pos_name, name)) {
-			continue;
-		}
-
-		id = ciphers[pos];
-		break;
-	}
-
-	return id;
-}
-
-/*!
- * \internal
- * \brief Add a new cipher to the transport's cipher list array.
- *
- * \param transport Which transport to add the cipher to.
- * \param name Cipher identifier name.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int transport_cipher_add(struct ast_sip_transport *transport, const char *name)
-{
-	pj_ssl_cipher cipher;
-	int idx;
-
-	cipher = cipher_name_to_id(name);
-	if (!cipher) {
-		/* TODO: Check this over/tweak - it's taken from pjsua for now */
-		if (!strnicmp(name, "0x", 2)) {
-			pj_str_t cipher_st = pj_str((char *) name + 2);
-			cipher = pj_strtoul2(&cipher_st, NULL, 16);
-		} else {
-			cipher = atoi(name);
-		}
-	}
-
-	if (pj_ssl_cipher_is_supported(cipher)) {
-		for (idx = transport->tls.ciphers_num; idx--;) {
-			if (transport->ciphers[idx] == cipher) {
-				/* The cipher is already in the list. */
-				return 0;
-			}
-		}
-		transport->ciphers[transport->tls.ciphers_num++] = cipher;
-		return 0;
-	} else {
-		ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", name);
-		return -1;
-	}
-}
-
-/*! \brief Custom handler for TLS cipher setting */
-static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-	char *parse;
-	char *name;
-	int res = 0;
-
-	parse = ast_strdupa(S_OR(var->value, ""));
-	while ((name = strsep(&parse, ","))) {
-		name = ast_strip(name);
-		if (ast_strlen_zero(name)) {
-			continue;
-		}
-		if (ARRAY_LEN(transport->ciphers) <= transport->tls.ciphers_num) {
-			ast_log(LOG_ERROR, "Too many ciphers specified\n");
-			res = -1;
-			break;
-		}
-		res |= transport_cipher_add(transport, name);
-	}
-	return res ? -1 : 0;
-}
-
-static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int cipher_num)
-{
-	struct ast_str *str;
-	int idx;
-
-	str = ast_str_create(128);
-	if (!str) {
-		*buf = NULL;
-		return;
-	}
-
-	for (idx = 0; idx < cipher_num; ++idx) {
-		ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(ciphers[idx]));
-		if (idx < cipher_num - 1) {
-			ast_str_append(&str, 0, ", ");
-		}
-	}
-
-	*buf = ast_strdup(ast_str_buffer(str));
-	ast_free(str);
-}
-
-static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-
-	cipher_to_str(buf, transport->ciphers, transport->tls.ciphers_num);
-	return *buf ? 0 : -1;
-}
-
-static char *handle_pjsip_list_ciphers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	pj_ssl_cipher ciphers[100];
-	unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
-	char *buf;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip list ciphers";
-		e->usage = "Usage: pjsip list ciphers\n"
-			"       List available OpenSSL cipher names.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (pj_ssl_cipher_get_availables(ciphers, &cipher_num) || !cipher_num) {
-		buf = NULL;
-	} else {
-		cipher_to_str(&buf, ciphers, cipher_num);
-	}
-
-	if (!ast_strlen_zero(buf)) {
-		ast_cli(a->fd, "Available ciphers: '%s'\n", buf);
-	} else {
-		ast_cli(a->fd, "No available ciphers\n");
-	}
-	ast_free(buf);
-	return CLI_SUCCESS;
-}
-
-/*! \brief Custom handler for localnet setting */
-static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-	int error = 0;
-
-	if (ast_strlen_zero(var->value)) {
-		ast_free_ha(transport->localnet);
-		transport->localnet = NULL;
-		return 0;
-	}
-
-	if (!(transport->localnet = ast_append_ha("d", var->value, transport->localnet, &error))) {
-		return -1;
-	}
-
-	return error;
-}
-
-static int localnet_to_vl(const void *obj, struct ast_variable **fields)
-{
-	const struct ast_sip_transport *transport = obj;
-
-	char str[MAX_OBJECT_FIELD];
-	struct ast_variable *head = NULL;
-	struct ast_ha *ha = transport->localnet;
-
-	for (; ha; ha = ha->next) {
-		const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
-		snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
-			addr, ast_sockaddr_stringify_addr(&ha->netmask));
-
-		ast_variable_list_append(&head, ast_variable_new("local_net", str, ""));
-	}
-
-	if (head) {
-		*fields = head;
-	}
-
-	return 0;
-}
-
-static int localnet_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-	const struct ast_sip_transport *transport = obj;
-
-	ast_ha_join(transport->localnet, &str);
-	*buf = ast_strdup(ast_str_buffer(str));
-	return 0;
-}
-
-/*! \brief Custom handler for TOS setting */
-static int transport_tos_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_transport *transport = obj;
-	unsigned int value;
-
-	if (ast_str2tos(var->value, &value)) {
-		ast_log(LOG_ERROR, "Error configuring transport '%s' - Could not "
-			"interpret 'tos' value '%s'\n",
-			ast_sorcery_object_get_id(transport), var->value);
-		return -1;
-	}
-
-	if (value % 4) {
-		value = value >> 2;
-		value = value << 2;
-		ast_log(LOG_WARNING,
-			"transport '%s' - 'tos' value '%s' uses bits that are "
-			"discarded when converted to DSCP. Using equivalent %u instead.\n",
-			ast_sorcery_object_get_id(transport), var->value, value);
-	}
-
-	transport->tos = value;
-	return 0;
-}
-
-static int tos_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_transport *transport = obj;
-
-	if (ast_asprintf(buf, "%u", transport->tos) == -1) {
-		return -1;
-	}
-	return 0;
-}
-
-static struct ao2_container *cli_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
-	struct ao2_container *s_container;
-
-	container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!container) {
-		return NULL;
-	}
-
-	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!s_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_container, container, 0)) {
-		ao2_ref(s_container, -1);
-		return NULL;
-	}
-
-	return s_container;
-}
-
-static int cli_iterate(void *container, ao2_callback_fn callback, void *args)
-{
-	const struct ast_sip_endpoint *endpoint = container;
-	struct ast_sip_transport *transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
-		"transport", endpoint->transport);
-
-	if (!transport) {
-		return -1;
-	}
-
-	return callback(transport, args, 0);
-}
-
-static void *cli_retrieve_by_id(const char *id)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", id);
-}
-
-static int cli_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_MAX_WIDTH - indent - 61;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <TransportId........>  <Type>  <cos>  <tos>  <BindAddress%*.*s>\n",
-		indent, "Transport", filler, filler, CLI_HEADER_FILLER);
-
-	return 0;
-}
-
-static int cli_print_body(void *obj, void *arg, int flags)
-{
-	struct ast_sip_transport *transport = obj;
-	struct ast_sip_cli_context *context = arg;
-	char hoststr[PJ_INET6_ADDRSTRLEN];
-
-	ast_assert(context->output_buffer != NULL);
-
-	pj_sockaddr_print(&transport->host, hoststr, sizeof(hoststr), 3);
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %-21s  %6s  %5u  %5u  %s\n",
-		CLI_INDENT_TO_SPACES(context->indent_level), "Transport",
-		ast_sorcery_object_get_id(transport),
-		ARRAY_IN_BOUNDS(transport->type, transport_types) ? transport_types[transport->type] : "Unknown",
-		transport->cos, transport->tos, hoststr);
-
-	if (context->show_details
-		|| (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(transport, context, 0);
-	}
-
-	return 0;
-}
-
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
-		.command = "pjsip list transports",
-		.usage = "Usage: pjsip list transports\n"
-				 "       List the configured PJSIP Transports\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transports",
-		.command = "pjsip show transports",
-		.usage = "Usage: pjsip show transports\n"
-				 "       Show the configured PJSIP Transport\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transport",
-		.command = "pjsip show transport",
-		.usage = "Usage: pjsip show transport <id>\n"
-				 "       Show the configured PJSIP Transport\n"),
-};
-
-static struct ast_sip_cli_formatter_entry *cli_formatter;
-
-/*! \brief Initialize sorcery with transport support */
-int ast_sip_initialize_sorcery_transport(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-
-	ast_sorcery_apply_default(sorcery, "transport", "config", "pjsip.conf,criteria=type=transport");
-
-	if (ast_sorcery_object_register_no_reload(sorcery, "transport", transport_alloc, NULL, transport_apply)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
-	ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file));
-	ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file));
-	ast_sorcery_object_field_register(sorcery, "transport", "priv_key_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file));
-	ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
-	ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
-	ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
-	ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
-	ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain));
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
-	ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX);
-
-	ast_sip_register_endpoint_formatter(&endpoint_transport_formatter);
-
-	cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!cli_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
-		return -1;
-	}
-	cli_formatter->name = "transport";
-	cli_formatter->print_header = cli_print_header;
-	cli_formatter->print_body = cli_print_body;
-	cli_formatter->get_container = cli_get_container;
-	cli_formatter->iterate = cli_iterate;
-	cli_formatter->get_id = ast_sorcery_object_get_id;
-	cli_formatter->retrieve_by_id = cli_retrieve_by_id;
-
-	ast_sip_register_cli_formatter(cli_formatter);
-	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
-
-	return 0;
-}
-
-int ast_sip_destroy_sorcery_transport(void)
-{
-	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_sip_unregister_cli_formatter(cli_formatter);
-
-	return 0;
-}
diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h
deleted file mode 100644
index fa37c8c..0000000
--- a/res/res_pjsip/include/res_pjsip_private.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * res_pjsip.h
- *
- *  Created on: Jan 25, 2013
- *      Author: mjordan
- */
-
-#ifndef RES_PJSIP_PRIVATE_H_
-#define RES_PJSIP_PRIVATE_H_
-
-#include "asterisk/module.h"
-#include "asterisk/compat.h"
-
-struct ao2_container;
-struct ast_threadpool_options;
-
-/*!
- * \brief Initialize the configuration for res_pjsip
- */
-int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info);
-
-/*!
- * \brief Annihilate the configuration objects
- */
-void ast_res_pjsip_destroy_configuration(void);
-
-/*!
- * \brief Reload the configuration
- */
-int ast_res_pjsip_reload_configuration(void);
-
-/*!
- * \brief Initialize OPTIONS request handling.
- *
- * XXX This currently includes qualifying peers. It shouldn't.
- * That should go into a registrar. When that occurs, we won't
- * need the reload stuff.
- *
- * \param reload Reload options handling
- *
- * \retval 0 on success
- * \retval other on failure
- */
-int ast_res_pjsip_init_options_handling(int reload);
-
-/*!
- * \brief Initialize transport storage for contacts.
- *
- * \retval 0 on success
- * \retval other on failure
- */
-int ast_res_pjsip_init_contact_transports(void);
-
-/*!
- * \brief Initialize outbound authentication support
- *
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_initialize_outbound_authentication(void);
-
-/*!
- * \brief Initialize system configuration
- *
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_initialize_system(void);
-
-/*!
- * \brief Destroy system configuration
- */
-void ast_sip_destroy_system(void);
-
-/*!
- * \brief Initialize nameserver configuration
- */
-void ast_sip_initialize_dns(void);
-
-/*!
- * \brief Initialize global configuration
- *
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_initialize_global(void);
-
-/*!
- * \brief Clean up res_pjsip options handling
- */
-void ast_res_pjsip_cleanup_options_handling(void);
-
-/*!
- * \brief Get threadpool options
- */
-void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options);
-
-/*!
- * \brief Retrieve the name of the default outbound endpoint.
- *
- * \note This returns a memory allocated copy of the name that
- *       needs to be freed by the caller.
- *
- * \retval The name of the default outbound endpoint.
- * \retval NULL if configuration not found.
- */
-char *ast_sip_global_default_outbound_endpoint(void);
-
-/*!
- * \brief Functions for initializing and destroying the CLI.
- */
-int ast_sip_initialize_cli(void);
-void ast_sip_destroy_cli(void);
-
-#endif /* RES_PJSIP_PRIVATE_H_ */
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
deleted file mode 100644
index d036ffa..0000000
--- a/res/res_pjsip/location.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-#include "pjsip.h"
-#include "pjlib.h"
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/sorcery.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/res_pjsip_cli.h"
-
-/*! \brief Destructor for AOR */
-static void aor_destroy(void *obj)
-{
-	struct ast_sip_aor *aor = obj;
-
-	ao2_cleanup(aor->permanent_contacts);
-	ast_string_field_free_memory(aor);
-}
-
-/*! \brief Allocator for AOR */
-static void *aor_alloc(const char *name)
-{
-	struct ast_sip_aor *aor = ast_sorcery_generic_alloc(sizeof(struct ast_sip_aor), aor_destroy);
-	if (!aor) {
-		return NULL;
-	}
-	ast_string_field_init(aor, 128);
-	return aor;
-}
-
-/*! \brief Destructor for contact */
-static void contact_destroy(void *obj)
-{
-	struct ast_sip_contact *contact = obj;
-
-	ast_string_field_free_memory(contact);
-}
-
-/*! \brief Allocator for contact */
-static void *contact_alloc(const char *name)
-{
-	struct ast_sip_contact *contact = ast_sorcery_generic_alloc(sizeof(*contact), contact_destroy);
-
-	if (!contact) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(contact, 256)) {
-		ao2_cleanup(contact);
-		return NULL;
-	}
-
-	return contact;
-}
-
-struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
-}
-
-/*! \brief Internal callback function which deletes and unlinks any expired contacts */
-static int contact_expire(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-
-	/* If the contact has not yet expired it is valid */
-	if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) {
-		return 0;
-	}
-
-	ast_sip_location_delete_contact(contact);
-
-	return CMP_MATCH;
-}
-
-/*! \brief Internal callback function which links static contacts into another container */
-static int contact_link_static(void *obj, void *arg, int flags)
-{
-	struct ao2_container *dest = arg;
-
-	ao2_link(dest, obj);
-	return 0;
-}
-
-/*! \brief Simple callback function which returns immediately, used to grab the first contact of an AOR */
-static int contact_find_first(void *obj, void *arg, int flags)
-{
-	return CMP_MATCH | CMP_STOP;
-}
-
-struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor)
-{
-	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-	struct ast_sip_contact *contact;
-
-	contacts = ast_sip_location_retrieve_aor_contacts(aor);
-	if (!contacts || (ao2_container_count(contacts) == 0)) {
-		return NULL;
-	}
-
-	contact = ao2_callback(contacts, 0, contact_find_first, NULL);
-	return contact;
-}
-
-struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
-{
-	/* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
-	char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
-	struct ao2_container *contacts;
-
-	snprintf(regex, sizeof(regex), "^%s;@", ast_sorcery_object_get_id(aor));
-
-	if (!(contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex))) {
-		return NULL;
-	}
-
-	/* Prune any expired contacts and delete them, we do this first because static contacts can never expire */
-	ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL);
-
-	/* Add any permanent contacts from the AOR */
-	if (aor->permanent_contacts) {
-		ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts);
-	}
-
-	return contacts;
-}
-
-struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
-{
-	char *aor_name;
-	char *rest;
-	struct ast_sip_contact *contact = NULL;
-
-	/* If the location is still empty we have nowhere to go */
-	if (ast_strlen_zero(aor_list) || !(rest = ast_strdupa(aor_list))) {
-		ast_log(LOG_WARNING, "Unable to determine contacts from empty aor list\n");
-		return NULL;
-	}
-
-	while ((aor_name = strsep(&rest, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-
-		if (!aor) {
-			continue;
-		}
-		contact = ast_sip_location_retrieve_first_aor_contact(aor);
-		/* If a valid contact is available use its URI for dialing */
-		if (contact) {
-			break;
-		}
-	}
-
-	return contact;
-}
-
-struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
-}
-
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
-		struct timeval expiration_time, const char *path_info, const char *user_agent)
-{
-	char name[MAX_OBJECT_FIELD * 2 + 3];
-	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
-
-	snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri);
-
-	if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) {
-		return -1;
-	}
-
-	ast_string_field_set(contact, uri, uri);
-	contact->expiration_time = expiration_time;
-	contact->qualify_frequency = aor->qualify_frequency;
-	contact->authenticate_qualify = aor->authenticate_qualify;
-	if (path_info && aor->support_path) {
-		ast_string_field_set(contact, path, path_info);
-	}
-
-	if (!ast_strlen_zero(aor->outbound_proxy)) {
-		ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
-	}
-
-	if (!ast_strlen_zero(user_agent)) {
-		ast_string_field_set(contact, user_agent, user_agent);
-	}
-
-	return ast_sorcery_create(ast_sip_get_sorcery(), contact);
-}
-
-int ast_sip_location_update_contact(struct ast_sip_contact *contact)
-{
-	return ast_sorcery_update(ast_sip_get_sorcery(), contact);
-}
-
-int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
-{
-	return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
-}
-
-/*! \brief Custom handler for translating from a string timeval to actual structure */
-static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_contact *contact = obj;
-	return ast_get_timeval(var->value, &contact->expiration_time, ast_tv(0, 0), NULL);
-}
-
-/*! \brief Custom handler for translating from an actual structure timeval to string */
-static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_contact *contact = obj;
-	return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
-}
-
-/*! \brief Helper function which validates a permanent contact */
-static int permanent_contact_validate(void *data)
-{
-	const char *value = data;
-	pj_pool_t *pool;
-	pj_str_t contact_uri;
-	static const pj_str_t HCONTACT = { "Contact", 7 };
-
-	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Permanent Contact Validation", 256, 256);
-	if (!pool) {
-		return -1;
-	}
-
-	pj_strdup2_with_null(pool, &contact_uri, value);
-	if (!pjsip_parse_hdr(pool, &HCONTACT, contact_uri.ptr, contact_uri.slen, NULL)) {
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-	return 0;
-}
-
-static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct ast_sip_contact *object_left = obj_left;
-	const struct ast_sip_contact *object_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = ast_sorcery_object_get_id(object_right);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(ast_sorcery_object_get_id(object_left), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(ast_sorcery_object_get_id(object_left), right_key, strlen(right_key));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-/*! \brief Custom handler for permanent URIs */
-static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_aor *aor = obj;
-	const char *aor_id = ast_sorcery_object_get_id(aor);
-	char *contacts;
-	char *contact_uri;
-
-	if (ast_strlen_zero(var->value)) {
-		return 0;
-	}
-
-	contacts = ast_strdupa(var->value);
-	while ((contact_uri = strsep(&contacts, ","))) {
-		struct ast_sip_contact *contact;
-		char contact_id[strlen(aor_id) + strlen(contact_uri) + 2 + 1];
-
-		if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, contact_uri)) {
-			ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n",
-				ast_sorcery_object_get_id(aor), contact_uri);
-			return -1;
-		}
-
-		if (!aor->permanent_contacts) {
-			aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
-				AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
-			if (!aor->permanent_contacts) {
-				return -1;
-			}
-		}
-
-		snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, contact_uri);
-		contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
-		if (!contact) {
-			return -1;
-		}
-
-		ast_string_field_set(contact, uri, contact_uri);
-		ao2_link(aor->permanent_contacts, contact);
-		ao2_ref(contact, -1);
-	}
-
-	return 0;
-}
-
-static int contact_to_var_list(void *object, void *arg, int flags)
-{
-	struct ast_sip_contact_wrapper *wrapper = object;
-	struct ast_variable **var = arg;
-
-	ast_variable_list_append(&*var, ast_variable_new("contact", wrapper->contact->uri, ""));
-
-	return 0;
-}
-
-static int contacts_to_var_list(const void *obj, struct ast_variable **fields)
-{
-	const struct ast_sip_aor *aor = obj;
-
-	ast_sip_for_each_contact(aor, contact_to_var_list, fields);
-
-	return 0;
-}
-
-int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
-{
-	char *copy, *name;
-
-	if (!on_aor || ast_strlen_zero(aors)) {
-		return 0;
-	}
-
-	copy = ast_strdupa(aors);
-	while ((name = strsep(&copy, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor,
-			 ast_sip_location_retrieve_aor(name), ao2_cleanup);
-
-		if (!aor) {
-			continue;
-		}
-
-		if (on_aor(aor, arg, 0)) {
-			return -1;
-		}
-	}
-	ast_free(copy);
-	return 0;
-}
-
-static void contact_wrapper_destroy(void *obj)
-{
-	struct ast_sip_contact_wrapper *wrapper = obj;
-	ast_free(wrapper->aor_id);
-	ast_free(wrapper->contact_id);
-	ao2_ref(wrapper->contact, -1);
-}
-
-int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
-		ao2_callback_fn on_contact, void *arg)
-{
-	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-	struct ao2_iterator i;
-	int res = 0;
-	void *object = NULL;
-
-	if (!on_contact ||
-	    !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
-		return 0;
-	}
-
-	i = ao2_iterator_init(contacts, 0);
-	while ((object = ao2_iterator_next(&i))) {
-		RAII_VAR(struct ast_sip_contact *, contact, object, ao2_cleanup);
-		RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
-		const char *aor_id = ast_sorcery_object_get_id(aor);
-
-		wrapper = ao2_alloc(sizeof(struct ast_sip_contact_wrapper), contact_wrapper_destroy);
-		if (!wrapper) {
-			res = -1;
-			break;
-		}
-		wrapper->contact_id = ast_malloc(strlen(aor_id) + strlen(contact->uri) + 2);
-		if (!wrapper->contact_id) {
-			res = -1;
-			break;
-		}
-		sprintf(wrapper->contact_id, "%s/%s", aor_id, contact->uri);
-		wrapper->aor_id = ast_strdup(aor_id);
-		if (!wrapper->aor_id) {
-			res = -1;
-			break;
-		}
-		wrapper->contact = contact;
-		ao2_bump(wrapper->contact);
-
-		if ((res = on_contact(wrapper, arg, 0))) {
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-	return res;
-}
-
-int ast_sip_contact_to_str(void *object, void *arg, int flags)
-{
-	struct ast_sip_contact_wrapper *wrapper = object;
-	struct ast_str **buf = arg;
-
-	ast_str_append(buf, 0, "%s,", wrapper->contact_id);
-
-	return 0;
-}
-
-static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf)
-{
-	RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
-			 ast_sip_get_sorcery(), aor, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
-	struct ast_variable *i;
-
-	if (!objset) {
-		return -1;
-	}
-
-	ast_str_append(buf, 0, "ObjectType: %s\r\n",
-		       ast_sorcery_object_get_type(aor));
-	ast_str_append(buf, 0, "ObjectName: %s\r\n",
-		       ast_sorcery_object_get_id(aor));
-
-	for (i = objset; i; i = i->next) {
-		char *camel = ast_to_camel_case(i->name);
-		if (strcmp(camel, "Contact") == 0) {
-			ast_free(camel);
-			camel = NULL;
-		}
-		ast_str_append(buf, 0, "%s: %s\r\n", S_OR(camel, "Contacts"), i->value);
-		ast_free(camel);
-	}
-
-	return 0;
-}
-
-static int contacts_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_aor *aor = obj;
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-
-	ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &str);
-	ast_str_truncate(str, -1);
-
-	*buf = ast_strdup(ast_str_buffer(str));
-	if (!*buf) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int format_ami_aor_handler(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct ast_sip_ami *ami = arg;
-	const struct ast_sip_endpoint *endpoint = ami->arg;
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("AorDetail", ami), ast_free);
-
-	int total_contacts;
-	int num_permanent;
-	RAII_VAR(struct ao2_container *, contacts,
-		 ast_sip_location_retrieve_aor_contacts(aor), ao2_cleanup);
-
-	if (!buf) {
-		return -1;
-	}
-
-	sip_aor_to_ami(aor, &buf);
-	total_contacts = ao2_container_count(contacts);
-	num_permanent = aor->permanent_contacts ?
-		ao2_container_count(aor->permanent_contacts) : 0;
-
-	ast_str_append(&buf, 0, "TotalContacts: %d\r\n", total_contacts);
-	ast_str_append(&buf, 0, "ContactsRegistered: %d\r\n",
-		       total_contacts - num_permanent);
-	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
-		       ast_sorcery_object_get_id(endpoint));
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	ami->count++;
-
-	return 0;
-}
-
-static int format_ami_endpoint_aor(const struct ast_sip_endpoint *endpoint,
-				   struct ast_sip_ami *ami)
-{
-	ami->arg = (void *)endpoint;
-	return ast_sip_for_each_aor(endpoint->aors,
-				    format_ami_aor_handler, ami);
-}
-
-struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
-	.format_ami = format_ami_endpoint_aor
-};
-
-static struct ao2_container *cli_aor_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
-	struct ao2_container *s_container;
-
-	container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!container) {
-		return NULL;
-	}
-
-	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!s_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_container, container, 0)) {
-		ao2_ref(s_container, -1);
-		return NULL;
-	}
-
-	return s_container;
-}
-
-static int cli_contact_populate_container(void *obj, void *arg, int flags)
-{
-	ao2_link(arg, obj);
-
-	return 0;
-}
-
-static int cli_aor_gather_contacts(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-
-	return ast_sip_for_each_contact(aor, cli_contact_populate_container, arg);
-}
-
-static const char *cli_contact_get_id(const void *obj)
-{
-	const struct ast_sip_contact_wrapper *wrapper = obj;
-	return wrapper->contact_id;
-}
-
-static int cli_contact_sort(const void *obj, const void *arg, int flags)
-{
-	const struct ast_sip_contact_wrapper *left_wrapper = obj;
-	const struct ast_sip_contact_wrapper *right_wrapper = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_wrapper->contact_id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_wrapper->contact_id, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_wrapper->contact_id, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_contact_compare(void *obj, void *arg, int flags)
-{
-	const struct ast_sip_contact_wrapper *left_wrapper = obj;
-	const struct ast_sip_contact_wrapper *right_wrapper = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_wrapper->contact_id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		if (strcmp(left_wrapper->contact_id, right_key) == 0) {;
-			cmp = CMP_MATCH | CMP_STOP;
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_wrapper->contact_id, right_key, strlen(right_key)) == 0) {
-			cmp = CMP_MATCH;
-		}
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_contact_hash(const void *obj, int flags)
-{
-	const struct ast_sip_contact_wrapper *wrapper = obj;
-	if (flags & OBJ_SEARCH_OBJECT) {
-		return ast_str_hash(wrapper->contact_id);
-	} else if (flags & OBJ_SEARCH_KEY) {
-		return ast_str_hash(obj);
-	}
-
-	return -1;
-}
-
-static int cli_contact_iterate(void *container, ao2_callback_fn callback, void *args)
-{
-	return ast_sip_for_each_contact(container, callback, args);
-}
-
-static struct ao2_container *cli_contact_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-	struct ao2_container *child_container;
-
-	parent_container =  cli_aor_get_container();
-	if (!parent_container) {
-		return NULL;
-	}
-
-	child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
-		cli_contact_hash, cli_contact_sort, cli_contact_compare);
-	if (!child_container) {
-		return NULL;
-	}
-
-	ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);
-
-	return child_container;
-}
-
-static void *cli_contact_retrieve_by_id(const char *id)
-{
-	return ao2_find(cli_contact_get_container(), id, OBJ_KEY | OBJ_NOLOCK);
-}
-
-static int cli_contact_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_LAST_TABSTOP - indent - 18;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <Aor/ContactUri%*.*s>  <Status....>  <RTT(ms)..>\n",
-		indent, "Contact", filler, filler, CLI_HEADER_FILLER);
-
-	return 0;
-}
-
-static int cli_contact_print_body(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact_wrapper *wrapper = obj;
-	struct ast_sip_contact *contact = wrapper->contact;
-	struct ast_sip_cli_context *context = arg;
-	int indent;
-	int flexwidth;
-
-	RAII_VAR(struct ast_sip_contact_status *, status,
-		ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)),
-		ao2_cleanup);
-
-	ast_assert(contact->uri != NULL);
-	ast_assert(context->output_buffer != NULL);
-
-	indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	flexwidth = CLI_LAST_TABSTOP - indent - 2;
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %-*.*s  %-12.12s  %11.3f\n",
-		indent,
-		"Contact",
-		flexwidth, flexwidth,
-		wrapper->contact_id,
-		(status ? (status->status == AVAILABLE ? "Avail" : "Unavail") : "Unknown"),
-		(status ? ((long long) status->rtt) / 1000.0 : NAN));
-
-	return 0;
-}
-
-static int cli_aor_iterate(void *container, ao2_callback_fn callback, void *args)
-{
-	const char *aor_list = container;
-
-	return ast_sip_for_each_aor(aor_list, callback, args);
-}
-
-static void *cli_aor_retrieve_by_id(const char *id)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id);
-}
-
-static const char *cli_aor_get_id(const void *obj)
-{
-	return ast_sorcery_object_get_id(obj);
-}
-
-static int cli_aor_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
-
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_LAST_TABSTOP - indent - 7;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <Aor%*.*s>  <MaxContact>\n",
-		indent, "Aor", filler, filler, CLI_HEADER_FILLER);
-
-	if (context->recurse) {
-		context->indent_level++;
-		formatter_entry = ast_sip_lookup_cli_formatter("contact");
-		if (formatter_entry) {
-			formatter_entry->print_header(NULL, context, 0);
-		}
-		context->indent_level--;
-	}
-
-	return 0;
-}
-
-static int cli_aor_print_body(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct ast_sip_cli_context *context = arg;
-	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
-	int indent;
-	int flexwidth;
-
-	ast_assert(context->output_buffer != NULL);
-
-//	context->current_aor = aor;
-
-	indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	flexwidth = CLI_LAST_TABSTOP - indent - 12;
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %-*.*s %12u\n",
-		indent,
-		"Aor",
-		flexwidth, flexwidth,
-		ast_sorcery_object_get_id(aor), aor->max_contacts);
-
-	if (context->recurse) {
-		context->indent_level++;
-
-		formatter_entry = ast_sip_lookup_cli_formatter("contact");
-		if (formatter_entry) {
-			formatter_entry->iterate(aor, formatter_entry->print_body, context);
-		}
-
-		context->indent_level--;
-
-		if (context->indent_level == 0) {
-			ast_str_append(&context->output_buffer, 0, "\n");
-		}
-	}
-
-	if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(aor, context, 0);
-	}
-
-	return 0;
-}
-
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors",
-		.command = "pjsip list aors",
-		.usage = "Usage: pjsip list aors\n"
-				 "       List the configured PJSIP Aors\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aors",
-		.command = "pjsip show aors",
-		.usage = "Usage: pjsip show aors\n"
-				 "       Show the configured PJSIP Aors\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aor",
-		.command = "pjsip show aor",
-		.usage = "Usage: pjsip show aor <id>\n"
-				 "       Show the configured PJSIP Aor\n"),
-
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Contacts",
-		.command = "pjsip list contacts",
-		.usage = "Usage: pjsip list contacts\n"
-				 "       List the configured PJSIP contacts\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contacts",
-		.command = "pjsip show contacts",
-		.usage = "Usage: pjsip show contacts\n"
-				 "       Show the configured PJSIP contacts\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contact",
-		.command = "pjsip show contact",
-		.usage = "Usage: pjsip show contact\n"
-				 "       Show the configured PJSIP contact\n"),
-};
-
-struct ast_sip_cli_formatter_entry *contact_formatter;
-struct ast_sip_cli_formatter_entry *aor_formatter;
-
-/*! \brief Initialize sorcery with location support */
-int ast_sip_initialize_sorcery_location(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-	ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar");
-	ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor");
-
-	if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, NULL) ||
-		ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
-	ast_sorcery_object_field_register(sorcery, "contact", "path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, path));
-	ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
-					  PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
-	ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
-	ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent));
-
-	ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));
-	ast_sorcery_object_field_register(sorcery, "aor", "maximum_expiration", "7200", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, maximum_expiration));
-	ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
-	ast_sorcery_object_field_register(sorcery, "aor", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_aor, qualify_frequency), 0, 86400);
-	ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
-	ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
-	ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
-	ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
-	ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
-	ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
-
-	ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
-
-	contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!contact_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for contact_formatter\n");
-		return -1;
-	}
-	contact_formatter->name = "contact";
-	contact_formatter->print_header = cli_contact_print_header;
-	contact_formatter->print_body = cli_contact_print_body;
-	contact_formatter->get_container = cli_contact_get_container;
-	contact_formatter->iterate = cli_contact_iterate;
-	contact_formatter->get_id = cli_contact_get_id;
-	contact_formatter->retrieve_by_id = cli_contact_retrieve_by_id;
-
-	aor_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!aor_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for aor_formatter\n");
-		return -1;
-	}
-	aor_formatter->name = "aor";
-	aor_formatter->print_header = cli_aor_print_header;
-	aor_formatter->print_body = cli_aor_print_body;
-	aor_formatter->get_container = cli_aor_get_container;
-	aor_formatter->iterate = cli_aor_iterate;
-	aor_formatter->get_id = cli_aor_get_id;
-	aor_formatter->retrieve_by_id = cli_aor_retrieve_by_id;
-
-	ast_sip_register_cli_formatter(contact_formatter);
-	ast_sip_register_cli_formatter(aor_formatter);
-	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
-
-	return 0;
-}
-
-int ast_sip_destroy_sorcery_location(void)
-{
-	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_sip_unregister_cli_formatter(contact_formatter);
-	ast_sip_unregister_cli_formatter(aor_formatter);
-
-	return 0;
-}
-
diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c
deleted file mode 100644
index e15e75d..0000000
--- a/res/res_pjsip/pjsip_cli.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/res_pjsip_cli.h"
-#include "asterisk/acl.h"
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/hashtab.h"
-#include "asterisk/utils.h"
-#include "asterisk/sorcery.h"
-
-static struct ao2_container *formatter_registry;
-
-int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	struct ast_variable *i;
-	int max_name_width = 13;
-	int max_value_width = 14;
-	int width;
-	char *separator;
-	struct ast_variable *objset;
-
-	if (!context->output_buffer) {
-		return -1;
-	}
-
-	objset = ast_sorcery_objectset_create(ast_sip_get_sorcery(),obj);
-	if (!objset) {
-		return -1;
-	}
-
-	for (i = objset; i; i = i->next) {
-		if (i->name) {
-			width = strlen(i->name);
-			max_name_width = width > max_name_width ? width : max_name_width;
-		}
-		if (i->value) {
-			width = strlen(i->value);
-			max_value_width = width > max_value_width ? width : max_value_width;
-		}
-	}
-
-	separator = ast_alloca(max_name_width + max_value_width + 8);
-
-	memset(separator, '=', max_name_width + max_value_width + 3);
-	separator[max_name_width + max_value_width + 3] = 0;
-
-	ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, "ParameterName", "ParameterValue");
-	ast_str_append(&context->output_buffer, 0, " %s\n", separator);
-
-	objset = ast_variable_list_sort(objset);
-
-	for (i = objset; i; i = i->next) {
-		ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, i->name, i->value);
-	}
-
-	ast_variables_destroy(objset);
-
-	return 0;
-}
-
-static char *complete_show_sorcery_object(struct ao2_container *container,
-	struct ast_sip_cli_formatter_entry *formatter_entry,
-	const char *word, int state)
-{
-	char *result = NULL;
-	int wordlen = strlen(word);
-	int which = 0;
-
-	struct ao2_iterator i = ao2_iterator_init(container, 0);
-	void *object;
-
-	while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) {
-		const char *id = formatter_entry->get_id(object);
-		if (!strncasecmp(word, id, wordlen)
-			&& ++which > state) {
-			result = ast_strdup(id);
-		}
-		ao2_t_ref(object, -1, "toss iterator endpoint ptr before break");
-		if (result) {
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	return result;
-}
-
-static void dump_str_and_free(int fd, struct ast_str *buf)
-{
-	ast_cli(fd, "%s", ast_str_buffer(buf));
-	ast_free(buf);
-}
-
-char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
-	RAII_VAR(void *, object, NULL, ao2_cleanup);
-	int is_container = 0;
-	const char *cmd1;
-	const char *cmd2;
-	const char *object_id;
-	char formatter_type[64];
-
-	struct ast_sip_cli_context context = {
-		.indent_level = 0,
-		.show_details = 0,
-		.show_details_only_level_0 = 0,
-		.recurse = 0,
-	};
-
-	if (cmd == CLI_INIT) {
-		return NULL;
-	}
-
-	cmd1 = e->cmda[1];
-	cmd2 = e->cmda[2];
-	object_id = a->argv[3];
-
-	if (!ast_ends_with(cmd2, "s")) {
-		ast_copy_string(formatter_type, cmd2, sizeof(formatter_type));
-		is_container = 0;
-	} else if (ast_ends_with(cmd2, "ies")) {
-		/* Take the plural "ies" off of the object name and re[place with "y". */
-		int l = strlen(cmd2);
-		snprintf(formatter_type, 64, "%*.*sy", l - 3, l - 3, cmd2);
-		is_container = 1;
-	} else {
-		/* Take the plural "s" off of the object name. */
-		ast_copy_string(formatter_type, cmd2, strlen(cmd2));
-		is_container = 1;
-	}
-
-	if (!strcmp(cmd1, "show")) {
-		context.show_details_only_level_0 = !is_container;
-		context.recurse = 1;
-	} else {
-		is_container = 1;
-	}
-
-	if (cmd == CLI_GENERATE
-		&& (is_container
-			|| a->argc > 4
-			|| (a->argc == 4 && ast_strlen_zero(a->word)))) {
-		return CLI_SUCCESS;
-	}
-
-	context.output_buffer = ast_str_create(256);
-	if (!context.output_buffer) {
-		return CLI_FAILURE;
-	}
-
-	formatter_entry = ast_sip_lookup_cli_formatter(formatter_type);
-	if (!formatter_entry) {
-		ast_log(LOG_ERROR, "No formatter registered for object type %s.\n",
-			formatter_type);
-		ast_free(context.output_buffer);
-		return CLI_FAILURE;
-	}
-	ast_str_append(&context.output_buffer, 0, "\n");
-	formatter_entry->print_header(NULL, &context, 0);
-	ast_str_append(&context.output_buffer, 0,
-		" =========================================================================================\n\n");
-
-	if (is_container || cmd == CLI_GENERATE) {
-		container = formatter_entry->get_container();
-		if (!container) {
-			ast_cli(a->fd, "No container returned for object type %s.\n",
-				formatter_type);
-			ast_free(context.output_buffer);
-			return CLI_FAILURE;
-		}
-	}
-
-	if (cmd == CLI_GENERATE) {
-		ast_free(context.output_buffer);
-		return complete_show_sorcery_object(container, formatter_entry, a->word, a->n);
-	}
-
-	if (is_container) {
-		if (!ao2_container_count(container)) {
-			ast_free(context.output_buffer);
-			ast_cli(a->fd, "No objects found.\n\n");
-			return CLI_SUCCESS;
-		}
-		ao2_callback(container, OBJ_NODATA, formatter_entry->print_body, &context);
-	} else {
-		if (ast_strlen_zero(object_id)) {
-			ast_free(context.output_buffer);
-			ast_cli(a->fd, "No object specified.\n");
-			return CLI_FAILURE;
-		}
-
-		object = formatter_entry->retrieve_by_id(object_id);
-		if (!object) {
-			ast_free(context.output_buffer);
-			ast_cli(a->fd, "Unable to find object %s.\n\n", object_id);
-			return CLI_SUCCESS;
-		}
-		formatter_entry->print_body(object, &context, 0);
-	}
-
-	ast_str_append(&context.output_buffer, 0, "\n");
-	dump_str_and_free(a->fd, context.output_buffer);
-	return CLI_SUCCESS;
-}
-
-static int formatter_sort(const void *obj, const void *arg, int flags)
-{
-	const struct ast_sip_cli_formatter_entry *left_obj = obj;
-	const struct ast_sip_cli_formatter_entry *right_obj = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_obj->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int formatter_compare(void *obj, void *arg, int flags)
-{
-	const struct ast_sip_cli_formatter_entry *left_obj = obj;
-	const struct ast_sip_cli_formatter_entry *right_obj = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		if (strcmp(left_obj->name, right_key) == 0) {;
-			cmp = CMP_MATCH | CMP_STOP;
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
-			cmp = CMP_MATCH;
-		}
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int formatter_hash(const void *obj, int flags)
-{
-	const struct ast_sip_cli_formatter_entry *left_obj = obj;
-	if (flags & OBJ_SEARCH_OBJECT) {
-		return ast_str_hash(left_obj->name);
-	} else if (flags & OBJ_SEARCH_KEY) {
-		return ast_str_hash(obj);
-	}
-
-	return -1;
-}
-
-struct ast_sip_cli_formatter_entry *ast_sip_lookup_cli_formatter(const char *name)
-{
-	return ao2_find(formatter_registry, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-}
-
-int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
-{
-	ast_assert(formatter != NULL);
-	ast_assert(formatter->name != NULL);
-	ast_assert(formatter->print_body != NULL);
-	ast_assert(formatter->print_header != NULL);
-	ast_assert(formatter->get_container != NULL);
-	ast_assert(formatter->iterate != NULL);
-	ast_assert(formatter->get_id != NULL);
-	ast_assert(formatter->retrieve_by_id != NULL);
-
-	ao2_link(formatter_registry, formatter);
-
-	return 0;
-}
-
-int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
-{
-	if (formatter) {
-		ao2_wrlock(formatter_registry);
-		if (ao2_ref(formatter, -1) == 2) {
-			ao2_unlink_flags(formatter_registry, formatter, OBJ_NOLOCK);
-		}
-		ao2_unlock(formatter_registry);
-	}
-	return 0;
-}
-
-int ast_sip_initialize_cli(void)
-{
-	formatter_registry = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
-		formatter_hash, formatter_sort, formatter_compare);
-
-	if (!formatter_registry) {
-		ast_log(LOG_ERROR, "Unable to create formatter_registry.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-void ast_sip_destroy_cli(void)
-{
-	ao2_ref(formatter_registry, -1);
-}
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
deleted file mode 100644
index 63e63fb..0000000
--- a/res/res_pjsip/pjsip_configuration.c
+++ /dev/null
@@ -1,1992 +0,0 @@
-/*
- * sip_cli_commands.c
- *
- *  Created on: Jan 25, 2013
- *      Author: mjordan
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "include/res_pjsip_private.h"
-#include "asterisk/res_pjsip_cli.h"
-#include "asterisk/acl.h"
-#include "asterisk/manager.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/utils.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/callerid.h"
-
-/*! \brief Number of buckets for persistent endpoint information */
-#define PERSISTENT_BUCKETS 53
-
-/*! \brief Persistent endpoint information */
-struct sip_persistent_endpoint {
-	/*! \brief Asterisk endpoint itself */
-	struct ast_endpoint *endpoint;
-	/*! \brief AORs that we should react to */
-	char *aors;
-};
-
-/*! \brief Container for persistent endpoint information */
-static struct ao2_container *persistent_endpoints;
-
-static struct ast_sorcery *sip_sorcery;
-
-/*! \brief Hashing function for persistent endpoint information */
-static int persistent_endpoint_hash(const void *obj, const int flags)
-{
-	const struct sip_persistent_endpoint *persistent = obj;
-	const char *id = (flags & OBJ_KEY ? obj : ast_endpoint_get_resource(persistent->endpoint));
-
-	return ast_str_hash(id);
-}
-
-/*! \brief Comparison function for persistent endpoint information */
-static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
-{
-	const struct sip_persistent_endpoint *persistent1 = obj;
-	const struct sip_persistent_endpoint *persistent2 = arg;
-	const char *id = (flags & OBJ_KEY ? arg : ast_endpoint_get_resource(persistent2->endpoint));
-
-	return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Callback function for changing the state of an endpoint */
-static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
-{
-	struct sip_persistent_endpoint *persistent = obj;
-	char *aor = arg;
-	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-
-	if (!ast_strlen_zero(aor) && !strstr(persistent->aors, aor)) {
-		return 0;
-	}
-
-	if ((contact = ast_sip_location_retrieve_contact_from_aor_list(persistent->aors))) {
-		ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_ONLINE);
-		blob = ast_json_pack("{s: s}", "peer_status", "Reachable");
-	} else {
-		ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_OFFLINE);
-		blob = ast_json_pack("{s: s}", "peer_status", "Unreachable");
-	}
-
-	ast_endpoint_blob_publish(persistent->endpoint, ast_endpoint_state_type(), blob);
-
-	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(persistent->endpoint));
-
-	return 0;
-}
-
-/*! \brief Function called when stuff relating to a contact happens (created/deleted) */
-static void persistent_endpoint_contact_observer(const void *object)
-{
-	char *id = ast_strdupa(ast_sorcery_object_get_id(object)), *aor = NULL;
-
-	aor = strsep(&id, ";@");
-
-	ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor);
-}
-
-/*! \brief Observer for contacts so state can be updated on respective endpoints */
-static const struct ast_sorcery_observer state_contact_observer = {
-	.created = persistent_endpoint_contact_observer,
-	.deleted = persistent_endpoint_contact_observer,
-};
-
-
-static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "rfc4733")) {
-		endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
-	} else if (!strcasecmp(var->value, "inband")) {
-		endpoint->dtmf = AST_SIP_DTMF_INBAND;
-	} else if (!strcasecmp(var->value, "info")) {
-		endpoint->dtmf = AST_SIP_DTMF_INFO;
-	} else if (!strcasecmp(var->value, "none")) {
-		endpoint->dtmf = AST_SIP_DTMF_NONE;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	switch (endpoint->dtmf) {
-	case AST_SIP_DTMF_RFC_4733 :
-		*buf = "rfc4733"; break;
-	case AST_SIP_DTMF_INBAND :
-		*buf = "inband"; break;
-	case AST_SIP_DTMF_INFO :
-		*buf = "info"; break;
-	default:
-		*buf = "none";
-	}
-
-	*buf = ast_strdup(*buf);
-	return 0;
-}
-
-static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (ast_true(var->value)) {
-		endpoint->extensions.flags |= PJSIP_INV_SUPPORT_100REL;
-	} else if (ast_false(var->value)) {
-		endpoint->extensions.flags &= PJSIP_INV_SUPPORT_100REL;
-	} else if (!strcasecmp(var->value, "required")) {
-		endpoint->extensions.flags |= PJSIP_INV_REQUIRE_100REL;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int prack_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_100REL) {
-		*buf = "required";
-	} else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_100REL) {
-		*buf = "yes";
-	} else {
-		*buf = "no";
-	}
-
-	*buf = ast_strdup(*buf);
-	return 0;
-}
-
-static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (ast_true(var->value)) {
-		endpoint->extensions.flags |= PJSIP_INV_SUPPORT_TIMER;
-	} else if (ast_false(var->value)) {
-		endpoint->extensions.flags &= PJSIP_INV_SUPPORT_TIMER;
-	} else if (!strcasecmp(var->value, "required")) {
-		endpoint->extensions.flags |= PJSIP_INV_REQUIRE_TIMER;
-	} else if (!strcasecmp(var->value, "always")) {
-		endpoint->extensions.flags |= PJSIP_INV_ALWAYS_USE_TIMER;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int timers_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (endpoint->extensions.flags & PJSIP_INV_ALWAYS_USE_TIMER) {
-		*buf = "always";
-	} else if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_TIMER) {
-		*buf = "required";
-	} else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_TIMER) {
-		*buf = "yes";
-	} else {
-		*buf = "no";
-	}
-
-	*buf = ast_strdup(*buf);
-	return 0;
-}
-
-void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *auths)
-{
-	int i;
-	size_t size;
-
-	if (!auths) {
-		return;
-	}
-
-	size = AST_VECTOR_SIZE(auths);
-
-	for (i = 0; i < size; ++i) {
-		const char *name = AST_VECTOR_REMOVE_UNORDERED(auths, 0);
-		ast_free((char *) name);
-	}
-	AST_VECTOR_FREE(auths);
-}
-
-int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *value)
-{
-	char *auth_names = ast_strdupa(value);
-	char *val;
-
-	ast_assert(auths != NULL);
-
-	if (AST_VECTOR_SIZE(auths)) {
-		ast_sip_auth_vector_destroy(auths);
-	}
-	if (AST_VECTOR_INIT(auths, 1)) {
-		return -1;
-	}
-
-	while ((val = strsep(&auth_names, ","))) {
-		val = ast_strdup(val);
-		if (!val) {
-			goto failure;
-		}
-		if (AST_VECTOR_APPEND(auths, val)) {
-			goto failure;
-		}
-	}
-	return 0;
-
-failure:
-	ast_sip_auth_vector_destroy(auths);
-	return -1;
-}
-
-static int inbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	return ast_sip_auth_vector_init(&endpoint->inbound_auths, var->value);
-}
-
-static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	return ast_sip_auth_vector_init(&endpoint->outbound_auths, var->value);
-}
-
-int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
-{
-	if (!auths || !AST_VECTOR_SIZE(auths)) {
-		return 0;
-	}
-
-	if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
-		return -1;
-	}
-
-	/* I feel like accessing the vector's elem array directly is cheating...*/
-	ast_join_delim(*buf, MAX_OBJECT_FIELD, auths->elems, AST_VECTOR_SIZE(auths), ',');
-	return 0;
-}
-
-static int inbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	return ast_sip_auths_to_str(&endpoint->inbound_auths, buf);
-}
-
-static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	return ast_sip_auths_to_str(&endpoint->outbound_auths, buf);
-}
-
-static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	char *idents = ast_strdupa(var->value);
-	char *val;
-
-	while ((val = strsep(&idents, ","))) {
-		if (!strcasecmp(val, "username")) {
-			endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME;
-		} else {
-			ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n",
-					val, ast_sorcery_object_get_id(endpoint));
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int ident_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	switch (endpoint->ident_method) {
-	case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME :
-		*buf = "username"; break;
-	default:
-		return 0;
-	}
-
-	*buf = ast_strdup(*buf);
-	return 0;
-}
-
-static int redirect_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "user")) {
-		endpoint->redirect_method = AST_SIP_REDIRECT_USER;
-	} else if (!strcasecmp(var->value, "uri_core")) {
-		endpoint->redirect_method = AST_SIP_REDIRECT_URI_CORE;
-	} else if (!strcasecmp(var->value, "uri_pjsip")) {
-		endpoint->redirect_method = AST_SIP_REDIRECT_URI_PJSIP;
-	} else {
-		ast_log(LOG_ERROR, "Unrecognized redirect method %s specified for endpoint %s\n",
-			var->value, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
-		endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
-	} else if (!strcasecmp(var->value, "update")) {
-		endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
-	} else {
-		ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
-				var->value, var->name, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-	return 0;
-}
-
-static const char *id_configuration_refresh_methods[] = {
-	[AST_SIP_SESSION_REFRESH_METHOD_INVITE] = "invite",
-	[AST_SIP_SESSION_REFRESH_METHOD_UPDATE] = "update"
-};
-
-static int direct_media_method_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->id.refresh_method, id_configuration_refresh_methods)) {
-		*buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
-	}
-	return 0;
-}
-
-static int connected_line_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
-		endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
-	} else if (!strcasecmp(var->value, "update")) {
-		endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
-	} else {
-		ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
-				var->value, var->name, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-	return 0;
-}
-
-static int connected_line_method_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
-	return 0;
-}
-
-static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "none")) {
-		endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE;
-	} else if (!strcasecmp(var->value, "outgoing")) {
-		endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING;
-	} else if (!strcasecmp(var->value, "incoming")) {
-		endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING;
-	} else {
-		ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
-				var->value, var->name, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-
-	return 0;
-}
-
-static const char *direct_media_glare_mitigation_map[] = {
-	[AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE] = "none",
-	[AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING] = "outgoing",
-	[AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING] = "incoming"
-};
-
-static int direct_media_glare_mitigation_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->media.direct_media.glare_mitigation, direct_media_glare_mitigation_map)) {
-		*buf = ast_strdup(direct_media_glare_mitigation_map[endpoint->media.direct_media.glare_mitigation]);
-	}
-
-	return 0;
-}
-
-static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	char cid_name[80] = { '\0' };
-	char cid_num[80] = { '\0' };
-
-	ast_callerid_split(var->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
-	if (!ast_strlen_zero(cid_name)) {
-		endpoint->id.self.name.str = ast_strdup(cid_name);
-		if (!endpoint->id.self.name.str) {
-			return -1;
-		}
-		endpoint->id.self.name.valid = 1;
-	}
-	if (!ast_strlen_zero(cid_num)) {
-		endpoint->id.self.number.str = ast_strdup(cid_num);
-		if (!endpoint->id.self.number.str) {
-			return -1;
-		}
-		endpoint->id.self.number.valid = 1;
-	}
-	return 0;
-}
-
-static int caller_id_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	const char *name = S_COR(endpoint->id.self.name.valid,
-				 endpoint->id.self.name.str, NULL);
-	const char *number = S_COR(endpoint->id.self.number.valid,
-				   endpoint->id.self.number.str, NULL);
-
-	/* make sure size is at least 10 - that should cover the "<unknown>"
-	   case as well as any additional formatting characters added in
-	   the name and/or number case. */
-	int size = 10;
-	size += name ? strlen(name) : 0;
-	size += number ? strlen(number) : 0;
-
-	if (!(*buf = ast_calloc(size + 1, sizeof(char)))) {
-		return -1;
-	}
-
-	ast_callerid_merge(*buf, size + 1, name, number, NULL);
-	return 0;
-}
-
-static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	int callingpres = ast_parse_caller_presentation(var->value);
-	if (callingpres == -1 && sscanf(var->value, "%d", &callingpres) != 1) {
-		return -1;
-	}
-	endpoint->id.self.number.presentation = callingpres;
-	endpoint->id.self.name.presentation = callingpres;
-	return 0;
-}
-
-static int caller_id_privacy_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	const char *presentation = ast_named_caller_presentation(
-		endpoint->id.self.name.presentation);
-
-	*buf = ast_strdup(presentation);
-	return 0;
-}
-
-static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	endpoint->id.self.tag = ast_strdup(var->value);
-	return endpoint->id.self.tag ? 0 : -1;
-}
-
-static int caller_id_tag_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->id.self.tag);
-	return 0;
-}
-
-static int media_encryption_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp("no", var->value)) {
-		endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
-	} else if (!strcasecmp("sdes", var->value)) {
-		endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES;
-	} else if (!strcasecmp("dtls", var->value)) {
-		endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
-		ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes");
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static const char *media_encryption_map[] = {
-	[AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid",
-	[AST_SIP_MEDIA_ENCRYPT_NONE] = "none",
-	[AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes",
-	[AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls",
-};
-
-static int media_encryption_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->media.rtp.encryption, media_encryption_map)) {
-		*buf = ast_strdup(media_encryption_map[
-					  endpoint->media.rtp.encryption]);
-	}
-	return 0;
-}
-
-static int group_handler(const struct aco_option *opt,
-			 struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strncmp(var->name, "call_group", 10)) {
-		endpoint->pickup.callgroup = ast_get_group(var->value);
-	} else if (!strncmp(var->name, "pickup_group", 12)) {
-		endpoint->pickup.pickupgroup = ast_get_group(var->value);
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int callgroup_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
-		return -1;
-	}
-
-	ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.callgroup);
-	return 0;
-}
-
-static int pickupgroup_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
-		return -1;
-	}
-
-	ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.pickupgroup);
-	return 0;
-}
-
-static int named_groups_handler(const struct aco_option *opt,
-				struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strncmp(var->name, "named_call_group", 16)) {
-		if (ast_strlen_zero(var->value)) {
-			endpoint->pickup.named_callgroups =
-				ast_unref_namedgroups(endpoint->pickup.named_callgroups);
-		} else if (!(endpoint->pickup.named_callgroups =
-		      ast_get_namedgroups(var->value))) {
-			return -1;
-		}
-	} else if (!strncmp(var->name, "named_pickup_group", 18)) {
-		if (ast_strlen_zero(var->value)) {
-			endpoint->pickup.named_pickupgroups =
-				ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
-		} else if (!(endpoint->pickup.named_pickupgroups =
-		      ast_get_namedgroups(var->value))) {
-			return -1;
-		}
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int named_callgroups_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-
-	ast_print_namedgroups(&str, endpoint->pickup.named_callgroups);
-	*buf = ast_strdup(ast_str_buffer(str));
-	return 0;
-}
-
-static int named_pickupgroups_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-
-	ast_print_namedgroups(&str, endpoint->pickup.named_pickupgroups);
-	*buf = ast_strdup(ast_str_buffer(str));
-	return 0;
-}
-
-static int dtls_handler(const struct aco_option *opt,
-			 struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	char *name = ast_strdupa(var->name);
-	char *front, *buf = name;
-
-	/* strip out underscores in the name */
-	front = strtok(buf, "_");
-	while (front) {
-		int size = strlen(front);
-		ast_copy_string(buf, front, size + 1);
-		buf += size;
-		front = strtok(NULL, "_");
-	}
-
-	return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, name, var->value);
-}
-
-static int dtlsverify_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.verify));
-	return 0;
-}
-
-static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	return ast_asprintf(
-		buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;
-}
-
-static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certfile);
-	return 0;
-}
-
-static int dtlsprivatekey_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->media.rtp.dtls_cfg.pvtfile);
-	return 0;
-}
-
-static int dtlscipher_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cipher);
-	return 0;
-}
-
-static int dtlscafile_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cafile);
-	return 0;
-}
-
-static int dtlscapath_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	*buf = ast_strdup(endpoint->media.rtp.dtls_cfg.capath);
-	return 0;
-}
-
-static const char *ast_rtp_dtls_setup_map[] = {
-	[AST_RTP_DTLS_SETUP_ACTIVE] = "active",
-	[AST_RTP_DTLS_SETUP_PASSIVE] = "passive",
-	[AST_RTP_DTLS_SETUP_ACTPASS] = "actpass",
-	[AST_RTP_DTLS_SETUP_HOLDCONN] = "holdconn",
-};
-
-static int dtlssetup_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.default_setup, ast_rtp_dtls_setup_map)) {
-		*buf = ast_strdup(ast_rtp_dtls_setup_map[endpoint->media.rtp.dtls_cfg.default_setup]);
-	}
-	return 0;
-}
-
-static const char *ast_rtp_dtls_fingerprint_map[] = {
-	[AST_RTP_DTLS_HASH_SHA256] = "SHA-256",
-	[AST_RTP_DTLS_HASH_SHA1] = "SHA-1",
-};
-
-static int dtlsfingerprint_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.hash, ast_rtp_dtls_fingerprint_map)) {
-		*buf = ast_strdup(ast_rtp_dtls_fingerprint_map[endpoint->media.rtp.dtls_cfg.hash]);
-	}
-	return 0;
-}
-
-static int t38udptl_ec_handler(const struct aco_option *opt,
-	struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcmp(var->value, "none")) {
-		endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_NONE;
-	} else if (!strcmp(var->value, "fec")) {
-		endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_FEC;
-	} else if (!strcmp(var->value, "redundancy")) {
-		endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_REDUNDANCY;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static const char *ast_t38_ec_modes_map[] = {
-	[UDPTL_ERROR_CORRECTION_NONE] = "none",
-	[UDPTL_ERROR_CORRECTION_FEC] = "fec",
-	[UDPTL_ERROR_CORRECTION_REDUNDANCY] = "redundancy"
-};
-
-static int t38udptl_ec_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (ARRAY_IN_BOUNDS(endpoint->media.t38.error_correction, ast_t38_ec_modes_map)) {
-		*buf = ast_strdup(ast_t38_ec_modes_map[
-					  endpoint->media.t38.error_correction]);
-	}
-	return 0;
-}
-
-static int tos_handler(const struct aco_option *opt,
-	struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	unsigned int value;
-
-	if (ast_str2tos(var->value, &value)) {
-		ast_log(LOG_ERROR, "Error configuring endpoint '%s' - Could not "
-			"interpret '%s' value '%s'\n",
-			ast_sorcery_object_get_id(endpoint), var->name, var->value);
-		return -1;
-	}
-
-	if (!strcmp(var->name, "tos_audio")) {
-		endpoint->media.tos_audio = value;
-	} else if (!strcmp(var->name, "tos_video")) {
-		endpoint->media.tos_video = value;
-	} else {
-		/* If we reach this point, someone called the tos_handler when they shouldn't have. */
-		ast_assert(0);
-		return -1;
-	}
-	return 0;
-}
-
-static int tos_audio_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (ast_asprintf(buf, "%u", endpoint->media.tos_audio) == -1) {
-		return -1;
-	}
-	return 0;
-}
-
-static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-
-	if (ast_asprintf(buf, "%u", endpoint->media.tos_video) == -1) {
-		return -1;
-	}
-	return 0;
-}
-
-static int set_var_handler(const struct aco_option *opt,
-	struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ast_variable *new_var;
-	char *name;
-	char *val;
-
-	if (ast_strlen_zero(var->value)) {
-		return 0;
-	}
-
-	name = ast_strdupa(var->value);
-	val = strchr(name, '=');
-
-	if (!val) {
-		return -1;
-	}
-
-	*val++ = '\0';
-
-	if (!(new_var = ast_variable_new(name, val, ""))) {
-		return -1;
-	}
-
-	ast_variable_list_append(&endpoint->channel_vars, new_var);
-
-	return 0;
-}
-
-static int set_var_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	struct ast_str *str = ast_str_create(MAX_OBJECT_FIELD);
-	const struct ast_sip_endpoint *endpoint = obj;
-	struct ast_variable *var;
-
-	for (var = endpoint->channel_vars; var; var = var->next) {
-		ast_str_append(&str, 0, "%s=%s,", var->name, var->value);
-	}
-
-	*buf = ast_strdup(ast_str_truncate(str, -1));
-	ast_free(str);
-	return 0;
-}
-
-static int set_var_to_vl(const void *obj, struct ast_variable **fields)
-{
-	const struct ast_sip_endpoint *endpoint = obj;
-	if (endpoint->channel_vars) {
-		*fields = ast_variables_dup(endpoint->channel_vars);
-	}
-	return 0;
-}
-
-
-static void *sip_nat_hook_alloc(const char *name)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
-}
-
-/*! \brief Destructor function for persistent endpoint information */
-static void persistent_endpoint_destroy(void *obj)
-{
-	struct sip_persistent_endpoint *persistent = obj;
-
-	ast_endpoint_shutdown(persistent->endpoint);
-	ast_free(persistent->aors);
-}
-
-/*! \brief Internal function which finds (or creates) persistent endpoint information */
-static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_sip_endpoint *endpoint)
-{
-	RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup);
-	SCOPED_AO2LOCK(lock, persistent_endpoints);
-
-	if (!(persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint), OBJ_KEY | OBJ_NOLOCK))) {
-		if (!(persistent = ao2_alloc(sizeof(*persistent), persistent_endpoint_destroy))) {
-			return NULL;
-		}
-
-		if (!(persistent->endpoint = ast_endpoint_create("PJSIP", ast_sorcery_object_get_id(endpoint)))) {
-			return NULL;
-		}
-
-		persistent->aors = ast_strdup(endpoint->aors);
-
-		if (ast_strlen_zero(persistent->aors)) {
-			ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
-		} else {
-			persistent_endpoint_update_state(persistent, NULL, 0);
-		}
-
-		ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
-	}
-
-	ao2_ref(persistent->endpoint, +1);
-	return persistent->endpoint;
-}
-
-/*! \brief Helper function which validates an outbound proxy */
-static int outbound_proxy_validate(void *data)
-{
-	const char *proxy = data;
-	pj_pool_t *pool;
-	pj_str_t tmp;
-	static const pj_str_t ROUTE_HNAME = { "Route", 5 };
-
-	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound Proxy Validation", 256, 256);
-	if (!pool) {
-		return -1;
-	}
-
-	pj_strdup2_with_null(pool, &tmp, proxy);
-	if (!pjsip_parse_hdr(pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL)) {
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-	return 0;
-}
-
-/*! \brief Callback function for when an object is finalized */
-static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!(endpoint->persistent = persistent_endpoint_find_or_create(endpoint))) {
-		return -1;
-	}
-
-	if (!ast_strlen_zero(endpoint->outbound_proxy) &&
-		ast_sip_push_task_synchronous(NULL, outbound_proxy_validate, (char*)endpoint->outbound_proxy)) {
-		ast_log(LOG_ERROR, "Invalid outbound proxy '%s' specified on endpoint '%s'\n",
-			endpoint->outbound_proxy, ast_sorcery_object_get_id(endpoint));
-		return -1;
-	} else if (endpoint->extensions.timer.min_se < 90) {
-		ast_log(LOG_ERROR, "Session timer minimum expires time must be 90 or greater on endpoint '%s'\n",
-			ast_sorcery_object_get_id(endpoint));
-		return -1;
-	} else if (endpoint->extensions.timer.sess_expires < endpoint->extensions.timer.min_se) {
-		ast_log(LOG_ERROR, "Session timer expires must be greater than minimum session expires time on endpoint '%s'\n",
-			ast_sorcery_object_get_id(endpoint));
-		return -1;
-	}
-
-	return 0;
-}
-
-const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint)
-{
-	char device[MAX_OBJECT_FIELD];
-
-	snprintf(device, MAX_OBJECT_FIELD, "PJSIP/%s", ast_sorcery_object_get_id(endpoint));
-	return ast_devstate2str(ast_device_state(device));
-}
-
-struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
-	const struct ast_sip_endpoint *endpoint)
-{
-	return ast_endpoint_latest_snapshot(
-		ast_endpoint_get_tech(endpoint->persistent),
-		ast_endpoint_get_resource(endpoint->persistent));
-}
-
-int ast_sip_for_each_channel_snapshot(
-	const struct ast_endpoint_snapshot *endpoint_snapshot,
-	ao2_callback_fn on_channel_snapshot, void *arg)
-{
-	int num, num_channels = endpoint_snapshot->num_channels;
-
-	if (!on_channel_snapshot || !num_channels) {
-		return 0;
-	}
-
-	for (num = 0; num < num_channels; ++num) {
-		RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-		int res;
-
-		snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
-		if (!snapshot) {
-			continue;
-		}
-
-		res = on_channel_snapshot(snapshot, arg, 0);
-		if (res) {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-int ast_sip_for_each_channel(
-	const struct ast_sip_endpoint *endpoint,
-	ao2_callback_fn on_channel_snapshot, void *arg)
-{
-	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
-	return ast_sip_for_each_channel_snapshot(endpoint_snapshot, on_channel_snapshot, arg);
-}
-
-static int active_channels_to_str_cb(void *object, void *arg, int flags)
-{
-	const struct ast_channel_snapshot *snapshot = object;
-	struct ast_str **buf = arg;
-	ast_str_append(buf, 0, "%s,", snapshot->name);
-	return 0;
-}
-
-static void active_channels_to_str(const struct ast_sip_endpoint *endpoint,
-				   struct ast_str **str)
-{
-
-	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot,
-		 ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
-
-	if (endpoint_snapshot) {
-		return;
-	}
-
-	ast_sip_for_each_channel_snapshot(endpoint_snapshot,
-					  active_channels_to_str_cb, str);
-	ast_str_truncate(*str, -1);
-}
-
-#define AMI_DEFAULT_STR_SIZE 512
-
-struct ast_str *ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
-{
-	struct ast_str *buf = ast_str_create(AMI_DEFAULT_STR_SIZE);
-
-	if (!(buf)) {
-		astman_send_error_va(ami->s, ami->m, "Unable create event "
-				     "for %s\n", event);
-		return NULL;
-	}
-
-	ast_str_set(&buf, 0, "Event: %s\r\n", event);
-	if (!ast_strlen_zero(ami->action_id)) {
-		ast_str_append(&buf, 0, "ActionID: %s\r\n", ami->action_id);
-	}
-	return buf;
-}
-
-static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str **buf)
-{
-	ast_str_append(buf, 0, "ObjectType: %s\r\n",
-		       ast_sorcery_object_get_type(obj));
-	ast_str_append(buf, 0, "ObjectName: %s\r\n",
-		       ast_sorcery_object_get_id(obj));
-}
-
-int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
-{
-	RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
-			 ast_sip_get_sorcery(), obj, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
-	struct ast_variable *i;
-
-	if (!objset) {
-		return -1;
-	}
-
-	sip_sorcery_object_ami_set_type_name(obj, buf);
-
-	for (i = objset; i; i = i->next) {
-		RAII_VAR(char *, camel, ast_to_camel_case(i->name), ast_free);
-		ast_str_append(buf, 0, "%s: %s\r\n", camel, i->value);
-	}
-
-	return 0;
-}
-
-static int sip_endpoints_aors_ami(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct ast_str **buf = arg;
-
-	ast_str_append(buf, 0, "Contacts: ");
-	ast_sip_for_each_contact(aor, ast_sip_contact_to_str, arg);
-	ast_str_append(buf, 0, "\r\n");
-
-	return 0;
-}
-
-static int sip_endpoint_to_ami(const struct ast_sip_endpoint *endpoint,
-			       struct ast_str **buf)
-{
-	if (ast_sip_sorcery_object_to_ami(endpoint, buf)) {
-		return -1;
-	}
-
-	ast_str_append(buf, 0, "DeviceState: %s\r\n",
-		       ast_sip_get_device_state(endpoint));
-
-	ast_str_append(buf, 0, "ActiveChannels: ");
-	active_channels_to_str(endpoint, buf);
-	ast_str_append(buf, 0, "\r\n");
-
-	return 0;
-}
-
-static int format_ami_endpoint(const struct ast_sip_endpoint *endpoint,
-			       struct ast_sip_ami *ami)
-{
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("EndpointDetail", ami), ast_free);
-
-	if (!buf) {
-		return -1;
-	}
-
-	sip_endpoint_to_ami(endpoint, &buf);
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	return 0;
-}
-
-#define AMI_SHOW_ENDPOINTS "PJSIPShowEndpoints"
-#define AMI_SHOW_ENDPOINT "PJSIPShowEndpoint"
-
-static int ami_show_endpoint(struct mansession *s, const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"),
-		.count = 0, };
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	const char *endpoint_name = astman_get_header(m, "Endpoint");
-	int count = 0;
-
-	if (ast_strlen_zero(endpoint_name)) {
-		astman_send_error_va(s, m, "%s requires an endpoint name\n",
-			AMI_SHOW_ENDPOINT);
-		return 0;
-	}
-
-	if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
-		endpoint_name += 6;
-	}
-
-	if (!(endpoint = ast_sorcery_retrieve_by_id(
-		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
-		astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n",
-			endpoint_name);
-		return -1;
-	}
-
-	astman_send_listack(s, m, "Following are Events for each object "
-			    "associated with the the Endpoint", "start");
-
-	/* the endpoint detail needs to always come first so apply as such */
-	if (format_ami_endpoint(endpoint, &ami) ||
-	    ast_sip_format_endpoint_ami(endpoint, &ami, &count)) {
-		astman_send_error_va(s, m, "Unable to format endpoint %s\n",
-			endpoint_name);
-	}
-
-	astman_append(s, "Event: EndpointDetailComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", ami.count + 1);
-
-	return 0;
-}
-
-static int format_str_append_auth(const struct ast_sip_auth_vector *auths,
-				  struct ast_str **buf)
-{
-	char *str = NULL;
-	if (ast_sip_auths_to_str(auths, &str)) {
-		return -1;
-	}
-	ast_str_append(buf, 0, "%s", str ? str : "");
-	ast_free(str);
-	return 0;
-}
-
-static int format_ami_endpoints(void *obj, void *arg, int flags)
-{
-
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ast_sip_ami *ami = arg;
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("EndpointList", ami), ast_free);
-
-	if (!buf) {
-		return -1;
-	}
-
-	sip_sorcery_object_ami_set_type_name(endpoint, &buf);
-	ast_str_append(&buf, 0, "Transport: %s\r\n",
-		       endpoint->transport);
-	ast_str_append(&buf, 0, "Aor: %s\r\n",
-		       endpoint->aors);
-
-	ast_str_append(&buf, 0, "Auths: ");
-	format_str_append_auth(&endpoint->inbound_auths, &buf);
-	ast_str_append(&buf, 0, "\r\n");
-
-	ast_str_append(&buf, 0, "OutboundAuths: ");
-	format_str_append_auth(&endpoint->outbound_auths, &buf);
-	ast_str_append(&buf, 0, "\r\n");
-
-	ast_sip_for_each_aor(endpoint->aors,
-			     sip_endpoints_aors_ami, &buf);
-
-	ast_str_append(&buf, 0, "DeviceState: %s\r\n",
-		       ast_sip_get_device_state(endpoint));
-
-	ast_str_append(&buf, 0, "ActiveChannels: ");
-	active_channels_to_str(endpoint, &buf);
-	ast_str_append(&buf, 0, "\r\n");
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	return 0;
-}
-
-static int ami_show_endpoints(struct mansession *s, const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
-	RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
-	int num;
-
-	endpoints = ast_sip_get_endpoints();
-	if (!endpoints) {
-		return -1;
-	}
-
-	if (!(num = ao2_container_count(endpoints))) {
-		astman_send_error(s, m, "No endpoints found\n");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "A listing of Endpoints follows, "
-			    "presented as EndpointList events", "start");
-
-	ao2_callback(endpoints, OBJ_NODATA, format_ami_endpoints, &ami);
-
-	astman_append(s, "Event: EndpointListComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", num);
-	return 0;
-}
-
-static struct ao2_container *cli_endpoint_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
-	struct ao2_container *s_container;
-
-	container = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!container) {
-		return NULL;
-	}
-
-	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		(void *)ast_sorcery_object_id_sort, (void *)ast_sorcery_object_id_compare);
-	if (!s_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_container, container, 0)) {
-		ao2_ref(s_container, -1);
-		return NULL;
-	}
-
-	return s_container;
-}
-
-static int cli_channel_populate_container(void *obj, void *arg, int flags)
-{
-	struct ast_channel_snapshot *snapshot = obj;
-
-	ao2_link(arg, snapshot);
-
-	return 0;
-}
-
-static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args)
-{
-	const struct ast_sip_endpoint *endpoint = container;
-
-	ast_sip_for_each_channel(endpoint, callback, args);
-
-	return 0;
-}
-
-static int cli_channel_sort(const void *obj, const void *arg, int flags)
-{
-	const struct ast_channel_snapshot *left_obj = obj;
-	const struct ast_channel_snapshot *right_obj = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_obj->name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_channel_compare(void *obj, void *arg, int flags)
-{
-	const struct ast_channel_snapshot *left_obj = obj;
-	const struct ast_channel_snapshot *right_obj = arg;
-	const char *right_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		if (strcmp(left_obj->name, right_key) == 0) {
-			cmp = CMP_MATCH | CMP_STOP;
-		}
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
-			cmp = CMP_MATCH;
-		}
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp;
-}
-
-static int cli_channel_hash(const void *obj, int flags)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-
-	if (flags & OBJ_SEARCH_OBJECT) {
-		return ast_str_hash(snapshot->name);
-	} else if (flags & OBJ_SEARCH_KEY) {
-		return ast_str_hash(obj);
-	}
-
-	return -1;
-}
-
-static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ao2_container *channels = arg;
-
-	ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels);
-
-	return 0;
-}
-
-static struct ao2_container *cli_channel_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-	struct ao2_container *child_container;
-
-	parent_container = cli_endpoint_get_container();
-	if (!parent_container) {
-		return NULL;
-	}
-	child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
-		cli_channel_hash, cli_channel_sort, cli_channel_compare);
-	if (!child_container) {
-		return NULL;
-	}
-
-	ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
-
-	return child_container;
-}
-
-static const char *cli_channel_get_id(const void *obj)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-
-	return snapshot->name;
-}
-
-static void *cli_channel_retrieve_by_id(const char *id)
-{
-	RAII_VAR(struct ao2_container *, container, cli_channel_get_container(), ao2_cleanup);
-
-	return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
-}
-
-static int cli_channel_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_LAST_TABSTOP - indent - 13;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <ChannelId%*.*s>  <State.....>  <Time(sec)>\n",
-		indent, "Channel", filler, filler, CLI_HEADER_FILLER);
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-		filler = CLI_LAST_TABSTOP - indent - 38;
-		ast_str_append(&context->output_buffer, 0,
-			"%*s: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
-			indent, "Exten", filler, filler, CLI_HEADER_FILLER);
-		context->indent_level--;
-	}
-
-	return 0;
-}
-
-static int cli_channel_print_body(void *obj, void *arg, int flags)
-{
-	const struct ast_channel_snapshot *snapshot = obj;
-	struct ast_sip_cli_context *context = arg;
-	struct timeval current_time;
-	char *print_name = NULL;
-	int print_name_len;
-	int indent;
-	int flexwidth;
-
-	ast_assert(context->output_buffer != NULL);
-
-	gettimeofday(&current_time, NULL);
-
-	print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
-	if (!(print_name = alloca(print_name_len))) {
-		return -1;
-	}
-
-	snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
-
-	indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	flexwidth = CLI_LAST_TABSTOP - indent;
-
-	ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %11ld\n",
-		CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
-		flexwidth, flexwidth,
-		print_name,
-		ast_state2str(snapshot->state),
-		current_time.tv_sec - snapshot->creationtime.tv_sec);
-
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-		flexwidth = CLI_LAST_TABSTOP - indent - 25;
-
-		ast_str_append(&context->output_buffer, 0,
-			"%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
-			indent, "Exten",
-			flexwidth, flexwidth,
-			snapshot->exten,
-			snapshot->connected_name,
-			snapshot->connected_number
-			);
-		context->indent_level--;
-		if (context->indent_level == 0) {
-			ast_str_append(&context->output_buffer, 0, "\n");
-		}
-	}
-
-	return 0;
-}
-
-static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
-{
-	ao2_callback(obj, OBJ_NODATA, callback, args);
-
-	return 0;
-}
-
-static void *cli_endpoint_retrieve_by_id(const char *id)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
-}
-
-static void cli_endpoint_print_child_header(char *type, struct ast_sip_cli_context *context)
-{
-	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
-
-	formatter_entry = ast_sip_lookup_cli_formatter(type);
-	if (formatter_entry) {
-		formatter_entry->print_header(NULL, context, 0);
-	}
-}
-
-static int cli_endpoint_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-			" Endpoint:  <Endpoint/CID.....................................>  <State.....>  <Channels.>\n");
-
-	if (context->recurse) {
-		context->indent_level++;
-		cli_endpoint_print_child_header("auth", context);
-		cli_endpoint_print_child_header("aor", context);
-		cli_endpoint_print_child_header("transport", context);
-		cli_endpoint_print_child_header("identify", context);
-		cli_endpoint_print_child_header("channel", context);
-		context->indent_level--;
-	}
-
-	return 0;
-}
-
-static void cli_endpoint_print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
-{
-	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
-
-	formatter_entry = ast_sip_lookup_cli_formatter(type);
-	if (formatter_entry) {
-		formatter_entry->iterate((void *)obj, formatter_entry->print_body, context);
-	}
-}
-
-static int cli_endpoint_print_body(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
-	struct ast_sip_cli_context *context = arg;
-	const char *id = ast_sorcery_object_get_id(endpoint);
-	char *print_name = NULL;
-	int print_name_len;
-	char *number = S_COR(endpoint->id.self.number.valid,
-		endpoint->id.self.number.str, NULL);
-	int indent;
-	int flexwidth;
-
-	ast_assert(context->output_buffer != NULL);
-
-	if (number) {
-		print_name_len = strlen(id) + strlen(number) + 2;
-		if (!(print_name = alloca(print_name_len))) {
-			return -1;
-		}
-		snprintf(print_name, print_name_len, "%s/%s", id, number);
-	}
-
-	indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	flexwidth = CLI_LAST_TABSTOP - indent - 2;
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %-*.*s  %-12.12s  %d of %.0f\n",
-		indent, "Endpoint",
-		flexwidth, flexwidth, print_name ? print_name : id,
-		ast_sip_get_device_state(endpoint),
-		endpoint_snapshot->num_channels,
-		(double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
-														INFINITY
-														);
-
-	if (context->recurse) {
-		context->indent_level++;
-
-		context->auth_direction = "Out";
-		cli_endpoint_print_child_body("auth", &endpoint->outbound_auths, context);
-		context->auth_direction = "In";
-		cli_endpoint_print_child_body("auth", &endpoint->inbound_auths, context);
-
-		cli_endpoint_print_child_body("aor", endpoint->aors, context);
-		cli_endpoint_print_child_body("transport", endpoint, context);
-		cli_endpoint_print_child_body("identify", endpoint, context);
-		cli_endpoint_print_child_body("channel", endpoint, context);
-
-		context->indent_level--;
-
-		if (context->indent_level == 0) {
-			ast_str_append(&context->output_buffer, 0, "\n");
-		}
-	}
-
-	if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(endpoint, context, 0);
-	}
-
-	return 0;
-}
-
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
-		.command = "pjsip list channels",
-		.usage = "Usage: pjsip list channels\n"
-				 "       List the active PJSIP channels\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
-		.command = "pjsip show channels",
-		.usage = "Usage: pjsip show channels\n"
-				 "       List(detailed) the active PJSIP channels\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
-		.command = "pjsip show channel",
-		.usage = "Usage: pjsip show channel\n"
-				 "       List(detailed) the active PJSIP channel\n"),
-
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
-		.command = "pjsip list endpoints",
-		.usage = "Usage: pjsip list endpoints\n"
-				 "       List the configured PJSIP endpoints\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
-		.command = "pjsip show endpoints",
-		.usage = "Usage: pjsip show endpoints\n"
-				 "       List(detailed) the configured PJSIP endpoints\n"),
-	AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
-		.command = "pjsip show endpoint",
-		.usage = "Usage: pjsip show endpoint <id>\n"
-				 "       Show the configured PJSIP endpoint\n"),
-};
-
-struct ast_sip_cli_formatter_entry *channel_formatter;
-struct ast_sip_cli_formatter_entry *endpoint_formatter;
-
-int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info)
-{
-	if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
-	    ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
-		return -1;
-	}
-
-	if (!(persistent_endpoints = ao2_container_alloc(PERSISTENT_BUCKETS, persistent_endpoint_hash, persistent_endpoint_cmp))) {
-		return -1;
-	}
-
-	if (!(sip_sorcery = ast_sorcery_open())) {
-		ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
-		return -1;
-	}
-
-	ast_sip_initialize_cli();
-
-	if (ast_sip_initialize_sorcery_auth()) {
-		ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "pjsip.conf,criteria=type=endpoint");
-	ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
-
-	if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, sip_endpoint_apply_handler)) {
-		ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL);
-
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
-	ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.codecs));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.codecs));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_ptime));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_rport", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.force_rport));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.rewrite_contact));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.min_se));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.sess_expires));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, connected_line_method_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, direct_media_glare_mitigation_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disable_direct_media_on_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.disable_on_nat));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "allowed_not_screened", caller_id_privacy_handler, caller_id_privacy_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_rpid));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "device_state_busy_at", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, devicestate_busy_at));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_on_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.onfeature));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_off_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.offfeature));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_transfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_owner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpowner));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_fingerprint", "", dtls_handler, dtlsfingerprint_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.srtp_tag_32));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_encryption_optimistic", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.encryption_optimistic));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, message_context));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, accountcode));
-
-	if (ast_sip_initialize_sorcery_transport()) {
-		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	if (ast_sip_initialize_sorcery_location()) {
-		ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	if (ast_sip_initialize_sorcery_qualify()) {
-		ast_log(LOG_ERROR, "Failed to register SIP qualify support with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	ast_sorcery_observer_add(sip_sorcery, "contact", &state_contact_observer);
-
-	if (ast_sip_initialize_sorcery_domain_alias()) {
-		ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	if (ast_sip_initialize_sorcery_global()) {
-		ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!channel_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-	channel_formatter->name = "channel";
-	channel_formatter->print_header = cli_channel_print_header;
-	channel_formatter->print_body = cli_channel_print_body;
-	channel_formatter->get_container = cli_channel_get_container;
-	channel_formatter->iterate = cli_channel_iterate;
-	channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
-	channel_formatter->get_id = cli_channel_get_id;
-
-	endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!endpoint_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-	endpoint_formatter->name = "endpoint";
-	endpoint_formatter->print_header = cli_endpoint_print_header;
-	endpoint_formatter->print_body = cli_endpoint_print_body;
-	endpoint_formatter->get_container = cli_endpoint_get_container;
-	endpoint_formatter->iterate = cli_endpoint_iterate;
-	endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
-	endpoint_formatter->get_id = ast_sorcery_object_get_id;
-
-	ast_sip_register_cli_formatter(channel_formatter);
-	ast_sip_register_cli_formatter(endpoint_formatter);
-	ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
-
-	ast_sorcery_load(sip_sorcery);
-
-	return 0;
-}
-
-void ast_res_pjsip_destroy_configuration(void)
-{
-	ast_sip_destroy_sorcery_location();
-	ast_sip_destroy_sorcery_auth();
-	ast_sip_destroy_sorcery_transport();
-	ast_manager_unregister(AMI_SHOW_ENDPOINT);
-	ast_manager_unregister(AMI_SHOW_ENDPOINTS);
-	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
-	ast_sip_unregister_cli_formatter(endpoint_formatter);
-	ast_sip_unregister_cli_formatter(channel_formatter);
-	ast_sorcery_unref(sip_sorcery);
-}
-
-int ast_res_pjsip_reload_configuration(void)
-{
-	if (sip_sorcery) {
-		ast_sorcery_reload(sip_sorcery);
-	}
-	return 0;
-}
-
-static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
-{
-	ast_string_field_free_memory(&subscription->mwi);
-}
-
-static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info)
-{
-	ast_string_field_free_memory(&info->recording);
-}
-
-static void media_configuration_destroy(struct ast_sip_endpoint_media_configuration *media)
-{
-	ast_string_field_free_memory(&media->rtp);
-	ast_string_field_free_memory(media);
-}
-
-static void endpoint_destructor(void* obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	ast_string_field_free_memory(endpoint);
-
-	ao2_ref(endpoint->media.codecs, -1);
-	subscription_configuration_destroy(&endpoint->subscription);
-	info_configuration_destroy(&endpoint->info);
-	media_configuration_destroy(&endpoint->media);
-	ast_sip_auth_vector_destroy(&endpoint->inbound_auths);
-	ast_sip_auth_vector_destroy(&endpoint->outbound_auths);
-	ast_party_id_free(&endpoint->id.self);
-	endpoint->pickup.named_callgroups = ast_unref_namedgroups(endpoint->pickup.named_callgroups);
-	endpoint->pickup.named_pickupgroups = ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
-	ao2_cleanup(endpoint->persistent);
-	ast_variables_destroy(endpoint->channel_vars);
-}
-
-static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
-{
-	return ast_string_field_init(&subscription->mwi, 64);
-}
-
-static int init_info_configuration(struct ast_sip_endpoint_info_configuration *info)
-{
-	return ast_string_field_init(&info->recording, 32);
-}
-
-static int init_media_configuration(struct ast_sip_endpoint_media_configuration *media)
-{
-	return ast_string_field_init(media, 64) || ast_string_field_init(&media->rtp, 32);
-}
-
-void *ast_sip_endpoint_alloc(const char *name)
-{
-	struct ast_sip_endpoint *endpoint = ast_sorcery_generic_alloc(sizeof(*endpoint), endpoint_destructor);
-	if (!endpoint) {
-		return NULL;
-	}
-	if (ast_string_field_init(endpoint, 64)) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	if (init_subscription_configuration(&endpoint->subscription)) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	if (init_info_configuration(&endpoint->info)) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	if (init_media_configuration(&endpoint->media)) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	ast_party_id_init(&endpoint->id.self);
-	return endpoint;
-}
-
-struct ao2_container *ast_sip_get_endpoints(void)
-{
-	struct ao2_container *endpoints;
-
-	endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-
-	return endpoints;
-}
-
-struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void)
-{
-	RAII_VAR(char *, name, ast_sip_global_default_outbound_endpoint(), ast_free);
-	return ast_strlen_zero(name) ? NULL : ast_sorcery_retrieve_by_id(
-		sip_sorcery, "endpoint", name);
-}
-
-int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(auths); ++i) {
-		/* Using AST_VECTOR_GET is safe since the vector is immutable */
-		const char *name = AST_VECTOR_GET(auths, i);
-		out[i] = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, name);
-		if (!out[i]) {
-			ast_log(LOG_NOTICE, "Couldn't find auth '%s'. Cannot authenticate\n", name);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
-{
-	int i;
-	for (i = 0; i < num_auths; ++i) {
-		ao2_cleanup(auths[i]);
-	}
-}
-
-struct ast_sorcery *ast_sip_get_sorcery(void)
-{
-	return sip_sorcery;
-}
diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c
deleted file mode 100644
index 90744fd..0000000
--- a/res/res_pjsip/pjsip_distributor.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-
-static int distribute(void *data);
-static pj_bool_t distributor(pjsip_rx_data *rdata);
-
-static pjsip_module distributor_mod = {
-	.name = {"Request Distributor", 19},
-	.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 6,
-	.on_rx_request = distributor,
-	.on_rx_response = distributor,
-};
-
-/*! Dialog-specific information the distributor uses */
-struct distributor_dialog_data {
-	/* Serializer to distribute tasks to for this dialog */
-	struct ast_taskprocessor *serializer;
-	/* Endpoint associated with this dialog */
-	struct ast_sip_endpoint *endpoint;
-};
-
-/*!
- * \internal
- *
- * \note Call this with the dialog locked
- */
-static struct distributor_dialog_data *distributor_dialog_data_alloc(pjsip_dialog *dlg)
-{
-	struct distributor_dialog_data *dist;
-
-	dist = PJ_POOL_ZALLOC_T(dlg->pool, struct distributor_dialog_data);
-	pjsip_dlg_set_mod_data(dlg, distributor_mod.id, dist);
-
-	return dist;
-}
-
-void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
-{
-	struct distributor_dialog_data *dist;
-	SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
-
-	dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
-	if (!dist) {
-		dist = distributor_dialog_data_alloc(dlg);
-	}
-	dist->serializer = serializer;
-}
-
-void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
-{
-	struct distributor_dialog_data *dist;
-	SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
-
-	dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
-	if (!dist) {
-		dist = distributor_dialog_data_alloc(dlg);
-	}
-	dist->endpoint = endpoint;
-}
-
-struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
-{
-	struct distributor_dialog_data *dist;
-	SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
-
-	dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
-	if (!dist || !dist->endpoint) {
-		return NULL;
-	}
-	ao2_ref(dist->endpoint, +1);
-	return dist->endpoint;
-}
-
-static pjsip_dialog *find_dialog(pjsip_rx_data *rdata)
-{
-	pj_str_t tsx_key;
-	pjsip_transaction *tsx;
-	pjsip_dialog *dlg;
-	pj_str_t *local_tag;
-	pj_str_t *remote_tag;
-
-	if (!rdata->msg_info.msg) {
-		return NULL;
-	}
-
-	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
-		local_tag = &rdata->msg_info.to->tag;
-		remote_tag = &rdata->msg_info.from->tag;
-	} else {
-		local_tag = &rdata->msg_info.from->tag;
-		remote_tag = &rdata->msg_info.to->tag;
-	}
-
-	/* We can only call the convenient method for
-	 *  1) responses
-	 *  2) non-CANCEL requests
-	 *  3) CANCEL requests with a to-tag
-	 */
-	if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG ||
-			pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) ||
-			rdata->msg_info.to->tag.slen != 0) {
-		return pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag,
-				remote_tag, PJ_TRUE);
-	}
-
-	/* Incoming CANCEL without a to-tag can't use same method for finding the
-	 * dialog. Instead, we have to find the matching INVITE transaction and
-	 * then get the dialog from the transaction
-	 */
-	pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS,
-			pjsip_get_invite_method(), rdata);
-
-	tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
-	if (!tsx) {
-		ast_log(LOG_ERROR, "Could not find matching INVITE transaction for CANCEL request\n");
-		return NULL;
-	}
-
-	dlg = pjsip_tsx_get_dlg(tsx);
-
-#ifdef HAVE_PJ_TRANSACTION_GRP_LOCK
-	pj_grp_lock_release(tsx->grp_lock);
-#else
-	pj_mutex_unlock(tsx->mutex);
-#endif
-
-	if (!dlg) {
-		return NULL;
-	}
-
-	pjsip_dlg_inc_lock(dlg);
-	return dlg;
-}
-
-static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata);
-
-static pjsip_module endpoint_mod = {
-	.name = {"Endpoint Identifier", 19},
-	.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 3,
-	.on_rx_request = endpoint_lookup,
-};
-
-static pj_bool_t distributor(pjsip_rx_data *rdata)
-{
-	pjsip_dialog *dlg = find_dialog(rdata);
-	struct distributor_dialog_data *dist = NULL;
-	struct ast_taskprocessor *serializer = NULL;
-	pjsip_rx_data *clone;
-
-	if (dlg) {
-		dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
-		if (dist) {
-			serializer = dist->serializer;
-		}
-	}
-
-	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG && (
-		!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || 
-		!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) &&
-		!serializer) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 481, NULL, NULL, NULL);
-		goto end;
-	}
-
-	pjsip_rx_data_clone(rdata, 0, &clone);
-
-	if (dist) {
-		clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint);
-	}
-
-	ast_sip_push_task(serializer, distribute, clone);
-
-end:
-	if (dlg) {
-		pjsip_dlg_dec_lock(dlg);
-	}
-
-	return PJ_TRUE;
-}
-
-static struct ast_sip_auth *artificial_auth;
-
-static int create_artificial_auth(void)
-{
-	if (!(artificial_auth = ast_sorcery_alloc(
-		      ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, "artificial"))) {
-		ast_log(LOG_ERROR, "Unable to create artificial auth\n");
-		return -1;
-	}
-
-	ast_string_field_set(artificial_auth, realm, "asterisk");
-	ast_string_field_set(artificial_auth, auth_user, "");
-	ast_string_field_set(artificial_auth, auth_pass, "");
-	artificial_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL;
-	return 0;
-}
-
-struct ast_sip_auth *ast_sip_get_artificial_auth(void)
-{
-	ao2_ref(artificial_auth, +1);
-	return artificial_auth;
-}
-
-static struct ast_sip_endpoint *artificial_endpoint;
-
-static int create_artificial_endpoint(void)
-{
-	if (!(artificial_endpoint = ast_sorcery_alloc(
-		      ast_sip_get_sorcery(), "endpoint", NULL))) {
-		return -1;
-	}
-
-	AST_VECTOR_INIT(&artificial_endpoint->inbound_auths, 1);
-	/* Pushing a bogus value into the vector will ensure that
-	 * the proper size of the vector is returned. This value is
-	 * not actually used anywhere
-	 */
-	AST_VECTOR_APPEND(&artificial_endpoint->inbound_auths, "artificial-auth");
-	return 0;
-}
-
-struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void)
-{
-	ao2_ref(artificial_endpoint, +1);
-	return artificial_endpoint;
-}
-
-static void log_unidentified_request(pjsip_rx_data *rdata)
-{
-	char from_buf[PJSIP_MAX_URL_SIZE];
-	char callid_buf[PJSIP_MAX_URL_SIZE];
-	pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, from_buf, PJSIP_MAX_URL_SIZE);
-	ast_copy_pj_str(callid_buf, &rdata->msg_info.cid->id, PJSIP_MAX_URL_SIZE);
-	ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found\n",
-		from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf);
-}
-
-static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata)
-{
-	struct ast_sip_endpoint *endpoint;
-	int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD;
-
-	endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
-	if (endpoint) {
-		return PJ_FALSE;
-	}
-
-	endpoint = ast_sip_identify_endpoint(rdata);
-
-	if (!endpoint && !is_ack) {
-		char name[AST_UUID_STR_LEN] = "";
-		pjsip_uri *from = rdata->msg_info.from->uri;
-
-		/* always use an artificial endpoint - per discussion no reason
-		   to have "alwaysauthreject" as an option.  It is felt using it
-		   was a bug fix and it is not needed since we are not worried about
-		   breaking old stuff and we really don't want to enable the discovery
-		   of SIP accounts */
-		endpoint = ast_sip_get_artificial_endpoint();
-
-		if (PJSIP_URI_SCHEME_IS_SIP(from) || PJSIP_URI_SCHEME_IS_SIPS(from)) {
-			pjsip_sip_uri *sip_from = pjsip_uri_get_uri(from);
-			ast_copy_pj_str(name, &sip_from->user, sizeof(name));
-		}
-
-		log_unidentified_request(rdata);
-		ast_sip_report_invalid_endpoint(name, rdata);
-	}
-	rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint;
-	return PJ_FALSE;
-}
-
-static pj_bool_t authenticate(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
-	int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD;
-
-	ast_assert(endpoint != NULL);
-
-	if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) {
-		pjsip_tx_data *tdata;
-		pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 401, NULL, &tdata);
-		switch (ast_sip_check_authentication(endpoint, rdata, tdata)) {
-		case AST_SIP_AUTHENTICATION_CHALLENGE:
-			/* Send the 401 we created for them */
-			ast_sip_report_auth_challenge_sent(endpoint, rdata, tdata);
-			pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
-			return PJ_TRUE;
-		case AST_SIP_AUTHENTICATION_SUCCESS:
-			ast_sip_report_auth_success(endpoint, rdata);
-			pjsip_tx_data_dec_ref(tdata);
-			return PJ_FALSE;
-		case AST_SIP_AUTHENTICATION_FAILED:
-			ast_sip_report_auth_failed_challenge_response(endpoint, rdata);
-			pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
-			return PJ_TRUE;
-		case AST_SIP_AUTHENTICATION_ERROR:
-			ast_sip_report_auth_failed_challenge_response(endpoint, rdata);
-			pjsip_tx_data_dec_ref(tdata);
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-			return PJ_TRUE;
-		}
-	}
-
-	return PJ_FALSE;
-}
-
-static pjsip_module auth_mod = {
-	.name = {"Request Authenticator", 21},
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION - 2,
-	.on_rx_request = authenticate,
-};
-
-static int distribute(void *data)
-{
-	static pjsip_process_rdata_param param = {
-		.start_mod = &distributor_mod,
-		.idx_after_start = 1,
-	};
-	pj_bool_t handled;
-	pjsip_rx_data *rdata = data;
-	int is_request = rdata->msg_info.msg->type == PJSIP_REQUEST_MSG;
-	int is_ack = is_request ? rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD : 0;
-	struct ast_sip_endpoint *endpoint;
-
-	pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), rdata, &param, &handled);
-	if (!handled && is_request && !is_ack) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 501, NULL, NULL, NULL);
-	}
-
-	/* The endpoint_mod stores an endpoint reference in the mod_data of rdata. This
-	 * is the only appropriate spot to actually decrement the reference.
-	 */
-	endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
-	ao2_cleanup(endpoint);
-	pjsip_rx_data_free_cloned(rdata);
-	return 0;
-}
-
-struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
-{
-	struct ast_sip_endpoint *endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
-	if (endpoint) {
-		ao2_ref(endpoint, +1);
-	}
-	return endpoint;
-}
-
-int ast_sip_initialize_distributor(void)
-{
-	if (create_artificial_endpoint() || create_artificial_auth()) {
-		return -1;
-	}
-
-	if (ast_sip_register_service(&distributor_mod)) {
-		return -1;
-	}
-	if (ast_sip_register_service(&endpoint_mod)) {
-		return -1;
-	}
-	if (ast_sip_register_service(&auth_mod)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-void ast_sip_destroy_distributor(void)
-{
-	ast_sip_unregister_service(&distributor_mod);
-	ast_sip_unregister_service(&endpoint_mod);
-	ast_sip_unregister_service(&auth_mod);
-
-	ao2_cleanup(artificial_auth);
-	ao2_cleanup(artificial_endpoint);
-}
diff --git a/res/res_pjsip/pjsip_global_headers.c b/res/res_pjsip/pjsip_global_headers.c
deleted file mode 100644
index eff8703..0000000
--- a/res/res_pjsip/pjsip_global_headers.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/linkedlists.h"
-
-static pj_status_t add_request_headers(pjsip_tx_data *tdata);
-static pj_status_t add_response_headers(pjsip_tx_data *tdata);
-
-/*!
- * \brief Indicator we've already handled a specific request/response
- *
- * PJSIP tends to reuse requests and responses. If we already have added
- * headers to a request or response, we mark the message with this value
- * so that we know not to re-add the headers again.
- */
-static unsigned int handled_id = 0xCA115785;
-
-static pjsip_module global_header_mod = {
-	.name = {"Global headers", 13},
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.on_tx_request = add_request_headers,
-	.on_tx_response = add_response_headers,
-};
-
-struct header {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);
-		AST_STRING_FIELD(value);
-	);
-	AST_LIST_ENTRY(header) next;
-};
-
-static struct header *alloc_header(const char *name, const char *value)
-{
-	struct header *alloc;
-	
-	alloc = ast_calloc_with_stringfields(1, struct header, 32);
-
-	if (!alloc) {
-		return NULL;
-	}
-
-	ast_string_field_set(alloc, name, name);
-	ast_string_field_set(alloc, value, value);
-
-	return alloc;
-}
-
-static void destroy_header(struct header *to_destroy)
-{
-	ast_string_field_free_memory(to_destroy);
-	ast_free(to_destroy);
-}
-
-AST_RWLIST_HEAD(header_list, header);
-
-static struct header_list request_headers;
-static struct header_list response_headers;
-
-static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *tdata)
-{
-	struct header *iter;
-	SCOPED_LOCK(lock, headers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	if (tdata->mod_data[global_header_mod.id] == &handled_id) {
-		return;
-	}
-	AST_LIST_TRAVERSE(headers, iter, next) {
-		ast_sip_add_header(tdata, iter->name, iter->value);
-	};
-	tdata->mod_data[global_header_mod.id] = &handled_id;
-}
-
-static pj_status_t add_request_headers(pjsip_tx_data *tdata)
-{
-	add_headers_to_message(&request_headers, tdata);
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t add_response_headers(pjsip_tx_data *tdata)
-{
-	add_headers_to_message(&response_headers, tdata);
-
-	return PJ_SUCCESS;
-}
-
-static void remove_header(struct header_list *headers, const char *to_remove)
-{
-	struct header *iter;
-	AST_LIST_TRAVERSE_SAFE_BEGIN(headers, iter, next) {
-		if (!strcasecmp(iter->name, to_remove)) {
-			AST_LIST_REMOVE_CURRENT(next);
-			break;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-}
-
-static int add_header(struct header_list *headers, const char *name, const char *value, int replace)
-{
-	struct header *to_add;
-
-	to_add = alloc_header(name, value);
-	if (!to_add) {
-		return -1;
-	}
-
-	AST_RWLIST_WRLOCK(headers);
-	if (replace) { 
-		remove_header(headers, name);
-	}
-	AST_LIST_INSERT_TAIL(headers, to_add, next);
-	AST_RWLIST_UNLOCK(headers);
-
-	return 0;
-}
-
-int ast_sip_add_global_request_header(const char *name, const char *value, int replace)
-{
-	return add_header(&request_headers, name, value, replace);
-}
-
-int ast_sip_add_global_response_header(const char *name, const char *value, int replace)
-{
-	return add_header(&response_headers, name, value, replace);
-}
-
-void ast_sip_initialize_global_headers(void)
-{
-	AST_RWLIST_HEAD_INIT(&request_headers);
-	AST_RWLIST_HEAD_INIT(&response_headers);
-
-	ast_sip_register_service(&global_header_mod);
-}
-
-static void destroy_headers(struct header_list *headers)
-{
-	struct header *iter;
-
-	while ((iter = AST_RWLIST_REMOVE_HEAD(headers, next))) {
-		destroy_header(iter);
-	}
-	AST_RWLIST_HEAD_DESTROY(headers);
-}
-
-void ast_sip_destroy_global_headers(void)
-{
-	destroy_headers(&request_headers);
-	destroy_headers(&response_headers);
-}
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
deleted file mode 100644
index 300f851..0000000
--- a/res/res_pjsip/pjsip_options.c
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/cli.h"
-#include "asterisk/time.h"
-#include "include/res_pjsip_private.h"
-
-#define DEFAULT_LANGUAGE "en"
-#define DEFAULT_ENCODING "text/plain"
-#define QUALIFIED_BUCKETS 211
-
-/*!
- * \internal
- * \brief Create a ast_sip_contact_status object.
- */
-static void *contact_status_alloc(const char *name)
-{
-	struct ast_sip_contact_status *status = ast_sorcery_generic_alloc(sizeof(*status), NULL);
-
-	if (!status) {
-		ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status\n");
-		return NULL;
-	}
-
-	status->status = UNAVAILABLE;
-
-	return status;
-}
-
-/*!
- * \internal
- * \brief Retrieve a ast_sip_contact_status object from sorcery creating
- *        one if not found.
- */
-static struct ast_sip_contact_status *find_or_create_contact_status(const struct ast_sip_contact *contact)
-{
-	struct ast_sip_contact_status *status;
-
-	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(contact));
-	if (status) {
-		return status;
-	}
-
-	status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(contact));
-	if (!status) {
-		ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s\n",
-			contact->uri);
-		return NULL;
-	}
-
-	if (ast_sorcery_create(ast_sip_get_sorcery(), status)) {
-		ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n",
-			contact->uri);
-		ao2_ref(status, -1);
-		return NULL;
-	}
-
-	return status;
-}
-
-static void delete_contact_status(const struct ast_sip_contact *contact)
-{
-	struct ast_sip_contact_status *status = ast_sorcery_retrieve_by_id(
-		ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact));
-
-	if (!status) {
-		return;
-	}
-
-	ast_sorcery_delete(ast_sip_get_sorcery(), status);
-	ao2_ref(status, -1);
-}
-
-/*!
- * \internal
- * \brief Update an ast_sip_contact_status's elements.
- */
-static void update_contact_status(const struct ast_sip_contact *contact,
-	enum ast_sip_contact_status_type value)
-{
-	struct ast_sip_contact_status *status;
-	struct ast_sip_contact_status *update;
-
-	status = find_or_create_contact_status(contact);
-	if (!status) {
-		return;
-	}
-
-	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(status));
-	if (!update) {
-		ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n",
-			contact->uri);
-		ao2_ref(status, -1);
-		return;
-	}
-
-	update->status = value;
-
-	/* if the contact is available calculate the rtt as
-	   the diff between the last start time and "now" */
-	update->rtt = update->status == AVAILABLE ?
-		ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;
-
-	update->rtt_start = ast_tv(0, 0);
-
-	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
-		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
-			contact->uri);
-	}
-
-	ao2_ref(update, -1);
-	ao2_ref(status, -1);
-}
-
-/*!
- * \internal
- * \brief Initialize the start time on a contact status so the round
- *        trip time can be calculated upon a valid response.
- */
-static void init_start_time(const struct ast_sip_contact *contact)
-{
-	struct ast_sip_contact_status *status;
-	struct ast_sip_contact_status *update;
-
-	status = find_or_create_contact_status(contact);
-	if (!status) {
-		return;
-	}
-
-	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(status));
-	if (!update) {
-		ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n",
-			contact->uri);
-		ao2_ref(status, -1);
-		return;
-	}
-
-	update->rtt_start = ast_tvnow();
-
-	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
-		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
-			contact->uri);
-	}
-
-	ao2_ref(update, -1);
-	ao2_ref(status, -1);
-}
-
-/*!
- * \internal
- * \brief Match a container contact object with the contact sorcery id looking for.
- *
- * \param obj pointer to the (user-defined part) of an object.
- * \param arg callback argument from ao2_callback()
- * \param flags flags from ao2_callback()
- *
- * \return Values are a combination of enum _cb_results.
- */
-static int match_contact_id(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	const char *looking_for = arg;
-
-	return strcmp(ast_sorcery_object_get_id(contact), looking_for) ? 0 : CMP_MATCH;
-}
-
-/*!
- * \internal
- * \brief For an endpoint try to match the given contact sorcery id.
- */
-static int on_endpoint(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ast_sip_contact *contact;
-	char *looking_for = arg;
-	char *aor_name;
-	char *aors;
-
-	if (!arg || ast_strlen_zero(endpoint->aors)) {
-		return 0;
-	}
-
-	aors = ast_strdupa(endpoint->aors);
-	while ((aor_name = strsep(&aors, ","))) {
-		struct ast_sip_aor *aor;
-		struct ao2_container *contacts;
-
-		aor = ast_sip_location_retrieve_aor(aor_name);
-		if (!aor) {
-			continue;
-		}
-
-		contacts = ast_sip_location_retrieve_aor_contacts(aor);
-		ao2_ref(aor, -1);
-		if (!contacts) {
-			continue;
-		}
-
-		contact = ao2_callback(contacts, 0, match_contact_id, looking_for);
-		ao2_ref(contacts, -1);
-		if (contact) {
-			ao2_ref(contact, -1);
-			return CMP_MATCH;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Find an endpoint associated with the given contact.
- */
-static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact)
-{
-	char *looking_for = (char *) ast_sorcery_object_get_id(contact);
-	struct ao2_container *endpoints = ast_sip_get_endpoints();
-	struct ast_sip_endpoint *endpoint;
-
-	endpoint = ao2_callback(endpoints, 0, on_endpoint, looking_for);
-	ao2_ref(endpoints, -1);
-	return endpoint;
-}
-
-/*!
- * \internal
- * \brief Receive a response to the qualify contact request.
- */
-static void qualify_contact_cb(void *token, pjsip_event *e)
-{
-	struct ast_sip_contact *contact = token;
-
-	switch(e->body.tsx_state.type) {
-	default:
-		ast_log(LOG_ERROR, "Unexpected PJSIP event %d\n", e->body.tsx_state.type);
-		/* Fall through */
-	case PJSIP_EVENT_TRANSPORT_ERROR:
-	case PJSIP_EVENT_TIMER:
-		update_contact_status(contact, UNAVAILABLE);
-		break;
-	case PJSIP_EVENT_RX_MSG:
-		update_contact_status(contact, AVAILABLE);
-		break;
-	}
-	ao2_cleanup(contact);
-}
-
-/*!
- * \internal
- * \brief Attempt to qualify the contact
- *
- * \details Sends a SIP OPTIONS request to the given contact in order to make
- *         sure that contact is available.
- */
-static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact)
-{
-	pjsip_tx_data *tdata;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup);
-
-	if (contact->authenticate_qualify) {
-		endpoint_local = ao2_bump(endpoint);
-		if (!endpoint_local) {
-			/*
-			 * Find the "first" endpoint to completely qualify the contact - any
-			 * endpoint that is associated with the contact should do.
-			 */
-			endpoint_local = find_an_endpoint(contact);
-			if (!endpoint_local) {
-				ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n",
-					contact->uri);
-				return -1;
-			}
-		}
-	}
-
-	if (ast_sip_create_request("OPTIONS", NULL, NULL, NULL, contact, &tdata)) {
-		ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n",
-			contact->uri);
-		return -1;
-	}
-
-	/* If an outbound proxy is specified set it on this request */
-	if (!ast_strlen_zero(contact->outbound_proxy) &&
-		ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
-		pjsip_tx_data_dec_ref(tdata);
-		ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
-			contact->uri);
-		return -1;
-	}
-
-	init_start_time(contact);
-
-	ao2_ref(contact, +1);
-	if (ast_sip_send_request(tdata, NULL, endpoint_local, contact, qualify_contact_cb)
-		!= PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
-			contact->uri);
-		update_contact_status(contact, UNAVAILABLE);
-		ao2_ref(contact, -1);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Scheduling context for sending QUALIFY request at specified intervals.
- */
-static struct ast_sched_context *sched;
-
-/*!
- * \internal
- * \brief Container to hold all actively scheduled qualifies.
- */
-static struct ao2_container *sched_qualifies;
-
-/*!
- * \internal
- * \brief Structure to hold qualify contact scheduling information.
- */
-struct sched_data {
-	/*! The scheduling id */
-	int id;
-	/*! The the contact being checked */
-	struct ast_sip_contact *contact;
-};
-
-/*!
- * \internal
- * \brief Destroy the scheduled data and remove from scheduler.
- */
-static void sched_data_destructor(void *obj)
-{
-	struct sched_data *data = obj;
-
-	ao2_cleanup(data->contact);
-}
-/*!
- * \internal
- * \brief Create the scheduling data object.
- */
-static struct sched_data *sched_data_create(struct ast_sip_contact *contact)
-{
-	struct sched_data *data;
-
-	data = ao2_t_alloc(sizeof(*data), sched_data_destructor, contact->uri);
-	if (!data) {
-		ast_log(LOG_ERROR, "Unable to create schedule qualify data for contact %s\n",
-			contact->uri);
-		return NULL;
-	}
-
-	data->contact = contact;
-	ao2_ref(data->contact, +1);
-
-	return data;
-}
-
-/*!
- * \internal
- * \brief Send a qualify contact request within a threaded task.
- */
-static int qualify_contact_task(void *obj)
-{
-	struct ast_sip_contact *contact = obj;
-	int res;
-
-	res = qualify_contact(NULL, contact);
-	ao2_ref(contact, -1);
-	return res;
-}
-
-/*!
- * \internal
- * \brief Send a scheduled qualify contact request.
- */
-static int qualify_contact_sched(const void *obj)
-{
-	struct sched_data *data = (struct sched_data *) obj;
-
-	ao2_ref(data->contact, +1);
-	if (ast_sip_push_task(NULL, qualify_contact_task, data->contact)) {
-		ao2_ref(data->contact, -1);
-	}
-
-	/*
-	 * Always reschedule rather than have a potential race cleaning
-	 * up the data object ref between self deletion and an external
-	 * deletion.
-	 */
-	return 1;
-}
-
-/*!
- * \internal
- * \brief Set up a scheduled qualify contact check.
- */
-static void schedule_qualify(struct ast_sip_contact *contact)
-{
-	struct sched_data *data;
-
-	data = sched_data_create(contact);
-	if (!data) {
-		return;
-	}
-
-	ast_assert(contact->qualify_frequency != 0);
-
-	ao2_t_ref(data, +1, "Ref for qualify_contact_sched() scheduler entry");
-	data->id = ast_sched_add_variable(sched, contact->qualify_frequency * 1000,
-		qualify_contact_sched, data, 0);
-	if (data->id < 0) {
-		ao2_t_ref(data, -1, "Cleanup failed scheduler add");
-		ast_log(LOG_ERROR, "Unable to schedule qualify for contact %s\n",
-			contact->uri);
-	} else if (!ao2_link(sched_qualifies, data)) {
-		AST_SCHED_DEL_UNREF(sched, data->id,
-			ao2_t_ref(data, -1, "Cleanup scheduler for failed ao2_link"));
-	}
-	ao2_t_ref(data, -1, "Done setting up scheduler entry");
-}
-
-/*!
- * \internal
- * \brief Remove the contact from the scheduler.
- */
-static void unschedule_qualify(struct ast_sip_contact *contact)
-{
-	struct sched_data *data;
-
-	data = ao2_find(sched_qualifies, contact, OBJ_UNLINK | OBJ_SEARCH_KEY);
-	if (!data) {
-		return;
-	}
-
-	AST_SCHED_DEL_UNREF(sched, data->id,
-		ao2_t_ref(data, -1, "Delete scheduler entry ref"));
-	ao2_t_ref(data, -1, "Done with ao2_find ref");
-}
-
-/*!
- * \internal
- * \brief Qualify the given contact and set up scheduling if configured.
- */
-static void qualify_and_schedule(struct ast_sip_contact *contact)
-{
-	unschedule_qualify(contact);
-
-	if (contact->qualify_frequency) {
-		ao2_ref(contact, +1);
-		if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
-			ao2_ref(contact, -1);
-		}
-
-		schedule_qualify(contact);
-	} else {
-		delete_contact_status(contact);
-	}
-}
-
-/*!
- * \internal
- * \brief A new contact has been created make sure it is available.
- */
-static void contact_created(const void *obj)
-{
-	qualify_and_schedule((struct ast_sip_contact *) obj);
-}
-
-/*!
- * \internal
- * \brief A contact has been deleted remove status tracking.
- */
-static void contact_deleted(const void *obj)
-{
-	struct ast_sip_contact *contact = (struct ast_sip_contact *) obj;
-	struct ast_sip_contact_status *status;
-
-	unschedule_qualify(contact);
-
-	status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(contact));
-	if (!status) {
-		return;
-	}
-
-	if (ast_sorcery_delete(ast_sip_get_sorcery(), status)) {
-		ast_log(LOG_ERROR, "Unable to delete ast_sip_contact_status for contact %s\n",
-			contact->uri);
-	}
-	ao2_ref(status, -1);
-}
-
-static const struct ast_sorcery_observer contact_observer = {
-	.created = contact_created,
-	.deleted = contact_deleted
-};
-
-static pj_bool_t options_start(void)
-{
-	sched = ast_sched_context_create();
-	if (!sched) {
-		return -1;
-	}
-	if (ast_sched_start_thread(sched)) {
-		ast_sched_context_destroy(sched);
-		sched = NULL;
-		return -1;
-	}
-
-	if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &contact_observer)) {
-		ast_log(LOG_WARNING, "Unable to add contact observer\n");
-		ast_sched_context_destroy(sched);
-		sched = NULL;
-		return -1;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static int sched_qualifies_empty(void *obj, void *arg, int flags)
-{
-	ao2_t_ref(obj, -1, "Release ref held by destroyed scheduler context.");
-	return CMP_MATCH;
-}
-
-static pj_bool_t options_stop(void)
-{
-	ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &contact_observer);
-
-	if (sched) {
-		ast_sched_context_destroy(sched);
-		sched = NULL;
-	}
-
-	/* Empty the container of scheduling data refs. */
-	ao2_callback(sched_qualifies, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
-		sched_qualifies_empty, NULL);
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
-{
-	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
-	pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
-	pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
-	pjsip_tx_data *tdata;
-	const pjsip_hdr *hdr;
-	pjsip_response_addr res_addr;
-	pj_status_t status;
-
-	/* Make the response object */
-	if ((status = ast_sip_create_response(rdata, code, NULL, &tdata) != PJ_SUCCESS)) {
-		ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
-		return status;
-	}
-
-	/* Add appropriate headers */
-	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
-	}
-	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
-	}
-	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
-	}
-
-	/*
-	 * XXX TODO: pjsip doesn't care a lot about either of these headers -
-	 * while it provides specific methods to create them, they are defined
-	 * to be the standard string header creation. We never did add them
-	 * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
-	 */
-	ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
-	ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
-
-	if (dlg && trans) {
-		status = pjsip_dlg_send_response(dlg, trans, tdata);
-	} else {
-		/* Get where to send request. */
-		if ((status = pjsip_get_response_addr(
-			     tdata->pool, rdata, &res_addr)) != PJ_SUCCESS) {
-			ast_log(LOG_ERROR, "Unable to get response address (%d)\n",
-				status);
-
-			pjsip_tx_data_dec_ref(tdata);
-			return status;
-		}
-		status = ast_sip_send_response(&res_addr, tdata,
-						   ast_pjsip_rdata_get_endpoint(rdata));
-	}
-
-	if (status != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
-	}
-
-	return status;
-}
-
-static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	pjsip_uri *ruri;
-	pjsip_sip_uri *sip_ruri;
-	char exten[AST_MAX_EXTENSION];
-
-	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
-			     &pjsip_options_method)) {
-		return PJ_FALSE;
-	}
-
-	if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
-		return PJ_FALSE;
-	}
-
-	ruri = rdata->msg_info.msg->line.req.uri;
-	if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
-		send_options_response(rdata, 416);
-		return -1;
-	}
-
-	sip_ruri = pjsip_uri_get_uri(ruri);
-	ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten));
-
-	if (ast_shutting_down()) {
-		send_options_response(rdata, 503);
-	} else if (!ast_strlen_zero(exten) && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
-		send_options_response(rdata, 404);
-	} else {
-		send_options_response(rdata, 200);
-	}
-	return PJ_TRUE;
-}
-
-static pjsip_module options_module = {
-	.name = {"Options Module", 14},
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.start = options_start,
-	.stop = options_stop,
-	.on_rx_request = options_on_rx_request,
-};
-
-/*!
- * \internal
- * \brief Send qualify request to the given contact.
- */
-static int cli_on_contact(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	struct ast_sip_endpoint *endpoint = data;
-	int *cli_fd = arg;
-
-	ast_cli(*cli_fd, " contact %s\n", contact->uri);
-	qualify_contact(endpoint, contact);
-	return 0;
-}
-
-/*!
- * \brief Data pushed to threadpool to qualify endpoints from the CLI
- */
-struct qualify_data {
-	/*! Endpoint that is being qualified */
-	struct ast_sip_endpoint *endpoint;
-	/*! CLI File descriptor for printing messages */
-	int cli_fd;
-};
-
-static struct qualify_data *qualify_data_alloc(struct ast_sip_endpoint *endpoint, int cli_fd)
-{
-	struct qualify_data *qual_data;
-
-	qual_data = ast_malloc(sizeof(*qual_data));
-	if (!qual_data) {
-		return NULL;
-	}
-
-	qual_data->endpoint = ao2_bump(endpoint);
-	qual_data->cli_fd = cli_fd;
-	return qual_data;
-}
-
-static void qualify_data_destroy(struct qualify_data *qual_data)
-{
-	ao2_cleanup(qual_data->endpoint);
-	ast_free(qual_data);
-}
-
-/*!
- * \internal
- * \brief For an endpoint iterate over and qualify all aors/contacts
- */
-static int cli_qualify_contacts(void *data)
-{
-	char *aors;
-	char *aor_name;
-	RAII_VAR(struct qualify_data *, qual_data, data, qualify_data_destroy);
-	struct ast_sip_endpoint *endpoint = qual_data->endpoint;
-	int cli_fd = qual_data->cli_fd;
-	const char *endpoint_name = ast_sorcery_object_get_id(endpoint);
-
-	if (ast_strlen_zero(endpoint->aors)) {
-		ast_cli(cli_fd, "Endpoint %s has no AoR's configured\n",
-			endpoint_name);
-		return 0;
-	}
-
-	aors = ast_strdupa(endpoint->aors);
-	while ((aor_name = strsep(&aors, ","))) {
-		struct ast_sip_aor *aor;
-		struct ao2_container *contacts;
-
-		aor = ast_sip_location_retrieve_aor(aor_name);
-		if (!aor) {
-			continue;
-		}
-
-		contacts = ast_sip_location_retrieve_aor_contacts(aor);
-		if (contacts) {
-			ast_cli(cli_fd, "Sending qualify to endpoint %s\n", endpoint_name);
-			ao2_callback_data(contacts, OBJ_NODATA, cli_on_contact, &cli_fd, endpoint);
-			ao2_ref(contacts, -1);
-		}
-
-		ao2_ref(aor, -1);
-	}
-	return 0;
-}
-
-static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	const char *endpoint_name;
-	struct qualify_data *qual_data;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip qualify";
-		e->usage =
-			"Usage: pjsip qualify <endpoint>\n"
-			"       Send a SIP OPTIONS request to all contacts on the endpoint.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 3) {
-		return CLI_SHOWUSAGE;
-	}
-
-	endpoint_name = a->argv[2];
-
-	if (!(endpoint = ast_sorcery_retrieve_by_id(
-		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
-		ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
-		return CLI_FAILURE;
-	}
-
-	qual_data = qualify_data_alloc(endpoint, a->fd);
-	if (!qual_data) {
-		return CLI_FAILURE;
-	}
-
-	if (ast_sip_push_task(NULL, cli_qualify_contacts, qual_data)) {
-		qualify_data_destroy(qual_data);
-		return CLI_FAILURE;
-	}
-
-	return CLI_SUCCESS;
-}
-
-/*!
- * \internal
- * \brief Send qualify request to the given contact.
- */
-static int ami_contact_cb(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-
-	ao2_ref(contact, +1);
-	if (ast_sip_push_task(NULL, qualify_contact_task, contact)) {
-		ao2_ref(contact, -1);
-	}
-	return 0;
-}
-
-static int ami_sip_qualify(struct mansession *s, const struct message *m)
-{
-	const char *endpoint_name = astman_get_header(m, "Endpoint");
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	char *aors;
-	char *aor_name;
-
-	if (ast_strlen_zero(endpoint_name)) {
-		astman_send_error(s, m, "Endpoint parameter missing.");
-		return 0;
-	}
-
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
-		endpoint_name);
-	if (!endpoint) {
-		astman_send_error(s, m, "Unable to retrieve endpoint\n");
-		return 0;
-	}
-
-	/* send a qualify for all contacts registered with the endpoint */
-	if (ast_strlen_zero(endpoint->aors)) {
-		astman_send_error(s, m, "No AoRs configured for endpoint\n");
-		return 0;
-	}
-
-	aors = ast_strdupa(endpoint->aors);
-	while ((aor_name = strsep(&aors, ","))) {
-		struct ast_sip_aor *aor;
-		struct ao2_container *contacts;
-
-		aor = ast_sip_location_retrieve_aor(aor_name);
-		if (!aor) {
-			continue;
-		}
-
-		contacts = ast_sip_location_retrieve_aor_contacts(aor);
-		if (contacts) {
-			ao2_callback(contacts, OBJ_NODATA, ami_contact_cb, NULL);
-			ao2_ref(contacts, -1);
-		}
-
-		ao2_ref(aor, -1);
-	}
-
-	astman_send_ack(s, m, "Endpoint found, will qualify");
-	return 0;
-}
-
-static struct ast_cli_entry cli_options[] = {
-	AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint")
-};
-
-static int sched_qualifies_hash_fn(const void *obj, int flags)
-{
-	const struct sched_data *object;
-	const struct ast_sip_contact *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->contact;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(ast_sorcery_object_get_id(key));
-}
-
-static int sched_qualifies_cmp_fn(void *obj, void *arg, int flags)
-{
-	const struct sched_data *object_left = obj;
-	const struct sched_data *object_right = arg;
-	struct ast_sip_contact *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->contact;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(ast_sorcery_object_get_id(object_left->contact),
-			ast_sorcery_object_get_id(right_key));
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* Not supported by container. */
-		ast_assert(0);
-		return 0;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-int ast_sip_initialize_sorcery_qualify(void)
-{
-	struct ast_sorcery *sorcery = ast_sip_get_sorcery();
-
-	/* initialize sorcery ast_sip_contact_status resource */
-	ast_sorcery_apply_default(sorcery, CONTACT_STATUS, "memory", NULL);
-
-	if (ast_sorcery_internal_object_register(sorcery, CONTACT_STATUS,
-					contact_status_alloc, NULL, NULL)) {
-		ast_log(LOG_ERROR, "Unable to register ast_sip_contact_status in sorcery\n");
-		return -1;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", "0", OPT_UINT_T,
-					  1, FLDSET(struct ast_sip_contact_status, status));
-	ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", "0", OPT_UINT_T,
-					  1, FLDSET(struct ast_sip_contact_status, rtt));
-
-	return 0;
-}
-
-static int qualify_and_schedule_cb(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	struct ast_sip_aor *aor = arg;
-
-	contact->qualify_frequency = aor->qualify_frequency;
-	contact->authenticate_qualify = aor->authenticate_qualify;
-
-	qualify_and_schedule(contact);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Qualify and schedule an endpoint's contacts
- *
- * \details For the given endpoint retrieve its list of aors, qualify all
- *         contacts, and schedule for checks if configured.
- */
-static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	char *aors;
-	char *aor_name;
-
-	if (ast_strlen_zero(endpoint->aors)) {
-		return 0;
-	}
-
-	aors = ast_strdupa(endpoint->aors);
-	while ((aor_name = strsep(&aors, ","))) {
-		struct ast_sip_aor *aor;
-		struct ao2_container *contacts;
-
-		aor = ast_sip_location_retrieve_aor(aor_name);
-		if (!aor) {
-			continue;
-		}
-
-		contacts = ast_sip_location_retrieve_aor_contacts(aor);
-		if (contacts) {
-			ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor);
-			ao2_ref(contacts, -1);
-		}
-
-		ao2_ref(aor, -1);
-	}
-
-	return 0;
-}
-
-static void qualify_and_schedule_all(void)
-{
-	struct ao2_container *endpoints = ast_sip_get_endpoints();
-
-	if (!endpoints) {
-		return;
-	}
-
-	ao2_callback(endpoints, OBJ_NODATA, qualify_and_schedule_all_cb, NULL);
-	ao2_ref(endpoints, -1);
-}
-
-static const char *status_map [] = {
-	[UNAVAILABLE] = "Unreachable",
-	[AVAILABLE] = "Reachable",
-};
-
-static int format_contact_status(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact_wrapper *wrapper = obj;
-	struct ast_sip_contact *contact = wrapper->contact;
-	struct ast_sip_ami *ami = arg;
-	struct ast_sip_contact_status *status;
-	struct ast_str *buf;
-	const struct ast_sip_endpoint *endpoint = ami->arg;
-
-	buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
-	if (!buf) {
-		return -1;
-	}
-
-	status = ast_sorcery_retrieve_by_id(
-		ast_sip_get_sorcery(), CONTACT_STATUS,
-		ast_sorcery_object_get_id(contact));
-
-	ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
-	ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
-	if (status) {
-		ast_str_append(&buf, 0, "Status: %s\r\n", status_map[status->status]);
-		ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
-	} else {
-		ast_str_append(&buf, 0, "Status: Unknown\r\n");
-		ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
-	}
-	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
-			ast_sorcery_object_get_id(endpoint));
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	ami->count++;
-	
-	ast_free(buf);
-	ao2_cleanup(status);
-	return 0;
-}
-
-static int format_contact_status_for_aor(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-
-	return ast_sip_for_each_contact(aor, format_contact_status, arg);
-}
-
-static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
-		struct ast_sip_ami *ami)
-{
-	ami->arg = (void *)endpoint;
-	return ast_sip_for_each_aor(endpoint->aors, format_contact_status_for_aor, ami);
-}
-
-static struct ast_sip_endpoint_formatter contact_status_formatter = {
-	.format_ami = format_ami_contact_status
-};
-
-int ast_res_pjsip_init_options_handling(int reload)
-{
-	static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
-
-	if (reload) {
-		qualify_and_schedule_all();
-		return 0;
-	}
-
-	sched_qualifies = ao2_t_container_alloc(QUALIFIED_BUCKETS,
-		sched_qualifies_hash_fn, sched_qualifies_cmp_fn,
-		"Create container for scheduled qualifies");
-	if (!sched_qualifies) {
-		return -1;
-	}
-
-	if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module) != PJ_SUCCESS) {
-		ao2_cleanup(sched_qualifies);
-		sched_qualifies = NULL;
-		return -1;
-	}
-
-	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
-		NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
-		pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
-		ao2_cleanup(sched_qualifies);
-		sched_qualifies = NULL;
-		return -1;
-	}
-
-	ast_sip_register_endpoint_formatter(&contact_status_formatter);
-	ast_manager_register2("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify, NULL, NULL, NULL);
-	ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
-
-	qualify_and_schedule_all();
-
-	return 0;
-}
-
-void ast_res_pjsip_cleanup_options_handling(void)
-{
-	ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options));
-	ast_manager_unregister("PJSIPQualify");
-	ast_sip_unregister_endpoint_formatter(&contact_status_formatter);
-
-	pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
-	ao2_cleanup(sched_qualifies);
-	sched_qualifies = NULL;
-}
diff --git a/res/res_pjsip/pjsip_outbound_auth.c b/res/res_pjsip/pjsip_outbound_auth.c
deleted file mode 100644
index 28ca3ec..0000000
--- a/res/res_pjsip/pjsip_outbound_auth.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-#undef bzero
-#define bzero bzero
-#include "pjsip.h"
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "include/res_pjsip_private.h"
-
-static pj_bool_t outbound_auth(pjsip_rx_data *rdata);
-
-static pjsip_module outbound_auth_mod = {
-	.name = {"Outbound Authentication", 19},
-	.priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
-	.on_rx_response = outbound_auth,
-};
-
-struct outbound_auth_cb_data {
-	ast_sip_dialog_outbound_auth_cb cb;
-	void *user_data;
-};
-
-static pj_bool_t outbound_auth(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	pjsip_transaction *tsx;
-	pjsip_dialog *dlg;
-	struct outbound_auth_cb_data *cb_data;
-	pjsip_tx_data *tdata;
-
-	if (rdata->msg_info.msg->line.status.code != 401 &&
-			rdata->msg_info.msg->line.status.code != 407) {
-		/* Doesn't pertain to us. Move on */
-		return PJ_FALSE;
-	}
-
-	tsx = pjsip_rdata_get_tsx(rdata);
-	dlg = pjsip_rdata_get_dlg(rdata);
-	if (!dlg || !tsx) {
-		return PJ_FALSE;
-	}
-
-	endpoint = ast_sip_dialog_get_endpoint(dlg);
-	if (!endpoint) {
-		return PJ_FALSE;
-	}
-
-	if (ast_sip_create_request_with_auth(&endpoint->outbound_auths, rdata, tsx, &tdata)) {
-		return PJ_FALSE;
-	}
-
-	cb_data = dlg->mod_data[outbound_auth_mod.id];
-	if (cb_data) {
-		cb_data->cb(dlg, tdata, cb_data->user_data);
-		return PJ_TRUE;
-	}
-
-	pjsip_dlg_send_request(dlg, tdata, -1, NULL);
-	return PJ_TRUE;
-}
-
-int ast_sip_dialog_setup_outbound_authentication(pjsip_dialog *dlg, const struct ast_sip_endpoint *endpoint,
-		ast_sip_dialog_outbound_auth_cb cb, void *user_data)
-{
-	struct outbound_auth_cb_data *cb_data = PJ_POOL_ZALLOC_T(dlg->pool, struct outbound_auth_cb_data);
-	cb_data->cb = cb;
-	cb_data->user_data = user_data;
-
-	dlg->sess_count++;
-	pjsip_dlg_add_usage(dlg, &outbound_auth_mod, cb_data);
-	dlg->sess_count--;
-
-	return 0;
-}
-
-int ast_sip_initialize_outbound_authentication(void) {
-	return ast_sip_register_service(&outbound_auth_mod);
-}
diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c
deleted file mode 100644
index 2fe6bdc..0000000
--- a/res/res_pjsip/presence_xml.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<depend>res_pjsip_exten_state</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
-{
-	char *copy = ast_strdupa(input);
-	char *break_point;
-
-	output[0] = '\0';
-
-	while ((break_point = strpbrk(copy, "<>\"&'\n\r"))) {
-		char to_escape = *break_point;
-
-		*break_point = '\0';
-		strncat(output, copy, len);
-
-		switch (to_escape) {
-		case '<':
-			strncat(output, "<", len);
-			break;
-		case '>':
-			strncat(output, ">", len);
-			break;
-		case '"':
-			strncat(output, """, len);
-			break;
-		case '&':
-			strncat(output, "&", len);
-			break;
-		case '\'':
-			strncat(output, "'", len);
-			break;
-		case '\r':
-			strncat(output, "
", len);
-			break;
-		case '\n':
-			strncat(output, "
", len);
-			break;
-		};
-
-		copy = break_point + 1;
-	}
-
-	/* Be sure to copy everything after the final bracket */
-	if (*copy) {
-		strncat(output, copy, len);
-	}
-}
-
-void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **pidfstate,
-			       char **pidfnote, enum ast_sip_pidf_state *local_state)
-{
-	switch (state) {
-	case AST_EXTENSION_RINGING:
-		*statestring = "early";
-		*local_state = NOTIFY_INUSE;
-		*pidfstate = "busy";
-		*pidfnote = "Ringing";
-		break;
-	case AST_EXTENSION_INUSE:
-		*statestring = "confirmed";
-		*local_state = NOTIFY_INUSE;
-		*pidfstate = "busy";
-		*pidfnote = "On the phone";
-		break;
-	case AST_EXTENSION_BUSY:
-		*statestring = "confirmed";
-		*local_state = NOTIFY_CLOSED;
-		*pidfstate = "busy";
-		*pidfnote = "On the phone";
-		break;
-	case AST_EXTENSION_UNAVAILABLE:
-		*statestring = "terminated";
-		*local_state = NOTIFY_CLOSED;
-		*pidfstate = "away";
-		*pidfnote = "Unavailable";
-		break;
-	case AST_EXTENSION_ONHOLD:
-		*statestring = "confirmed";
-		*local_state = NOTIFY_CLOSED;
-		*pidfstate = "busy";
-		*pidfnote = "On hold";
-		break;
-	case AST_EXTENSION_NOT_INUSE:
-	default:
-		/* Default setting */
-		*statestring = "terminated";
-		*local_state = NOTIFY_OPEN;
-		*pidfstate = "--";
-		*pidfnote ="Ready";
-		break;
-	}
-}
-
-pj_xml_attr *ast_sip_presence_xml_create_attr(pj_pool_t *pool,
-		pj_xml_node *node, const char *name, const char *value)
-{
-	pj_xml_attr *attr = PJ_POOL_ALLOC_T(pool, pj_xml_attr);
-
-	pj_strdup2(pool, &attr->name, name);
-	pj_strdup2(pool, &attr->value, value);
-
-	pj_xml_add_attr(node, attr);
-	return attr;
-}
-
-pj_xml_node *ast_sip_presence_xml_create_node(pj_pool_t *pool,
-		pj_xml_node *parent, const char* name)
-{
-	pj_xml_node *node = PJ_POOL_ALLOC_T(pool, pj_xml_node);
-
-	pj_list_init(&node->attr_head);
-	pj_list_init(&node->node_head);
-
-	pj_strdup2(pool, &node->name, name);
-
-	node->content.ptr = NULL;
-	node->content.slen = 0;
-
-	if (parent) {
-		pj_xml_add_node(parent, node);
-	}
-
-	return node;
-}
-
-void ast_sip_presence_xml_find_node_attr(pj_pool_t* pool,
-		pj_xml_node *parent, const char *node_name, const char *attr_name,
-		pj_xml_node **node, pj_xml_attr **attr)
-{
-	pj_str_t name;
-
-	if (!(*node = pj_xml_find_node(parent, pj_cstr(&name, node_name)))) {
-		*node = ast_sip_presence_xml_create_node(pool, parent, node_name);
-	}
-
-	if (!(*attr = pj_xml_find_attr(*node, pj_cstr(&name, attr_name), NULL))) {
-		*attr = ast_sip_presence_xml_create_attr(pool, *node, attr_name, "");
-	}
-}
diff --git a/res/res_pjsip/security_events.c b/res/res_pjsip/security_events.c
deleted file mode 100644
index d19e5ba..0000000
--- a/res/res_pjsip/security_events.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Generate security events in the PJSIP channel
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 412400 $")
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/security_events.h"
-
-static enum ast_transport security_event_get_transport(pjsip_rx_data *rdata)
-{
-	if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
-		rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
-		return AST_TRANSPORT_UDP;
-	} else if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP ||
-		rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP6) {
-		return AST_TRANSPORT_TCP;
-	} else if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS ||
-		rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS6) {
-		return AST_TRANSPORT_TLS;
-	} else if (!strcmp(rdata->tp_info.transport->type_name, "WS")) {
-		return AST_TRANSPORT_WS;
-	} else if (!strcmp(rdata->tp_info.transport->type_name, "WSS")) {
-		return AST_TRANSPORT_WSS;
-	} else {
-		return 0;
-	}
-}
-
-static void security_event_populate(pjsip_rx_data *rdata, char *call_id, size_t call_id_size, struct ast_sockaddr *local, struct ast_sockaddr *remote)
-{
-	char host[NI_MAXHOST];
-
-	ast_copy_pj_str(call_id, &rdata->msg_info.cid->id, call_id_size);
-
-	ast_copy_pj_str(host, &rdata->tp_info.transport->local_name.host, sizeof(host));
-	ast_sockaddr_parse(local, host, PARSE_PORT_FORBID);
-	ast_sockaddr_set_port(local, rdata->tp_info.transport->local_name.port);
-
-	ast_sockaddr_parse(remote, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
-	ast_sockaddr_set_port(remote, rdata->pkt_info.src_port);
-}
-
-static const char *get_account_id(struct ast_sip_endpoint *endpoint)
-{
-	RAII_VAR(struct ast_sip_endpoint *, artificial, ast_sip_get_artificial_endpoint(), ao2_cleanup);
-
-	return endpoint == artificial ? "<unknown>" : ast_sorcery_object_get_id(endpoint);
-}
-
-void ast_sip_report_invalid_endpoint(const char *name, pjsip_rx_data *rdata)
-{
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_inval_acct_id inval_acct_id = {
-		.common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
-		.common.version    = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
-		.common.service    = "PJSIP",
-		.common.account_id = name,
-		.common.local_addr = {
-			.addr      = &local,
-			.transport = transport,
-		},
-		.common.remote_addr = {
-			.addr       = &remote,
-			.transport = transport,
-		},
-		.common.session_id = call_id,
-	};
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
-}
-
-void ast_sip_report_failed_acl(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *name)
-{
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_failed_acl failed_acl_event = {
-			.common.event_type  = AST_SECURITY_EVENT_FAILED_ACL,
-			.common.version     = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
-			.common.service     = "PJSIP",
-			.common.account_id  = get_account_id(endpoint),
-			.common.local_addr  = {
-					.addr       = &local,
-					.transport  = transport,
-			},
-			.common.remote_addr = {
-					.addr       = &remote,
-					.transport  = transport,
-			},
-			.common.session_id  = call_id,
-			.acl_name           = name,
-	};
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
-}
-
-void ast_sip_report_auth_failed_challenge_response(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	pjsip_authorization_hdr *auth = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	char nonce[64] = "", response[256] = "";
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_chal_resp_failed chal_resp_failed = {
-				.common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
-				.common.version    = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
-				.common.service    = "PJSIP",
-				.common.account_id = get_account_id(endpoint),
-				.common.local_addr = {
-						.addr      = &local,
-						.transport = transport,
-				},
-				.common.remote_addr = {
-						.addr      = &remote,
-						.transport = transport,
-				},
-				.common.session_id = call_id,
-
-				.challenge         = nonce,
-				.response          = response,
-				.expected_response = "",
-	};
-
-	if (auth && !pj_strcmp2(&auth->scheme, "Digest")) {
-		ast_copy_pj_str(nonce, &auth->credential.digest.nonce, sizeof(nonce));
-		ast_copy_pj_str(response, &auth->credential.digest.response, sizeof(response));
-	}
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
-}
-
-void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	pjsip_authorization_hdr *auth = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_successful_auth successful_auth = {
-			.common.event_type  = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
-			.common.version     = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
-			.common.service     = "PJSIP",
-			.common.account_id  = get_account_id(endpoint),
-			.common.local_addr  = {
-					.addr       = &local,
-					.transport  = transport,
-			},
-			.common.remote_addr = {
-					.addr       = &remote,
-					.transport  = transport,
-			},
-			.common.session_id  = call_id,
-			.using_password     = auth ? (uint32_t *)1 : (uint32_t *)0,
-	};
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&successful_auth));
-}
-
-void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
-{
-	pjsip_www_authenticate_hdr *auth = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_WWW_AUTHENTICATE, NULL);
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char nonce[64] = "", call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_chal_sent chal_sent = {
-			.common.event_type = AST_SECURITY_EVENT_CHAL_SENT,
-			.common.version    = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
-			.common.service    = "PJSIP",
-			.common.account_id = get_account_id(endpoint),
-			.common.local_addr = {
-					.addr      = &local,
-					.transport = transport,
-			},
-			.common.remote_addr = {
-					.addr      = &remote,
-					.transport = transport,
-			},
-			.common.session_id = call_id,
-			.challenge         = nonce,
-	};
-
-	if (auth && !pj_strcmp2(&auth->scheme, "digest")) {
-		ast_copy_pj_str(nonce, &auth->challenge.digest.nonce, sizeof(nonce));
-	}
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&chal_sent));
-}
-
-void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
-				   const char* req_type)
-{
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_req_no_support req_no_support_event = {
-		.common.event_type  = AST_SECURITY_EVENT_REQ_NO_SUPPORT,
-		.common.version     = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
-		.common.service     = "PJSIP",
-		.common.account_id  = get_account_id(endpoint),
-		.common.local_addr  = {
-			.addr       = &local,
-			.transport  = transport,
-		},
-		.common.remote_addr = {
-			.addr       = &remote,
-			.transport  = transport,
-		},
-		.common.session_id  = call_id,
-		.request_type       = req_type
-	};
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&req_no_support_event));
-}
-
-void ast_sip_report_mem_limit(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	enum ast_transport transport = security_event_get_transport(rdata);
-	char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
-	struct ast_sockaddr local, remote;
-
-	struct ast_security_event_mem_limit mem_limit_event = {
-		.common.event_type  = AST_SECURITY_EVENT_MEM_LIMIT,
-		.common.version     = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
-		.common.service     = "PJSIP",
-		.common.account_id  = get_account_id(endpoint),
-		.common.local_addr  = {
-			.addr       = &local,
-			.transport  = transport,
-		},
-		.common.remote_addr = {
-			.addr       = &remote,
-			.transport  = transport,
-		},
-		.common.session_id  = call_id
-	};
-
-	security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
-
-	ast_security_event_report(AST_SEC_EVT(&mem_limit_event));
-}
diff --git a/res/res_pjsip_acl.c b/res/res_pjsip_acl.c
deleted file mode 100644
index 115d1b8..0000000
--- a/res/res_pjsip_acl.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/acl.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_acl" language="en_US">
-		<synopsis>SIP ACL module</synopsis>
-		<description><para>
-			<emphasis>ACL</emphasis>
-			</para><para>
-			The ACL module used by <literal>res_pjsip</literal>. This module is
-			independent of <literal>endpoints</literal> and operates on all inbound
-			SIP communication using res_pjsip.
-			</para><para>
-			There are two main ways of defining your ACL with the options
-			provided. You can use the <literal>permit</literal> and <literal>deny</literal> options
-			which act on <emphasis>IP</emphasis> addresses, or the <literal>contactpermit</literal>
-			and <literal>contactdeny</literal> options which act on <emphasis>Contact header</emphasis>
-			addresses in incoming REGISTER requests. You can combine the various options to
-			create a mixed ACL.
-			</para><para>
-			Additionally, instead of defining an ACL with options, you can reference IP or
-			Contact header ACLs from the file <filename>acl.conf</filename> by using the <literal>acl</literal>
-			or <literal>contactacl</literal> options.
-		</para></description>
-		<configFile name="pjsip.conf">
-			<configObject name="acl">
-				<synopsis>Access Control List</synopsis>
-				<configOption name="acl">
-					<synopsis>List of IP ACL section names in acl.conf</synopsis>
-					<description><para>
-						This matches sections configured in <literal>acl.conf</literal>. The value is
-						defined as a list of comma-delimited section names.
-					</para></description>
-				</configOption>
-				<configOption name="contact_acl">
-					<synopsis>List of Contact ACL section names in acl.conf</synopsis>
-					<description><para>
-						This matches sections configured in <literal>acl.conf</literal>. The value is
-						defined as a list of comma-delimited section names.
-					</para></description>
-				</configOption>
-				<configOption name="contact_deny">
-					<synopsis>List of Contact header addresses to deny</synopsis>
-					<description><para>
-						The value is a comma-delimited list of IP addresses. IP addresses may
-						have a subnet mask appended. The subnet mask may be written in either
-						CIDR or dotted-decimal notation. Separate the IP address and subnet
-						mask with a slash ('/')
-					</para></description>
-				</configOption>
-				<configOption name="contact_permit">
-					<synopsis>List of Contact header addresses to permit</synopsis>
-					<description><para>
-						The value is a comma-delimited list of IP addresses. IP addresses may
-						have a subnet mask appended. The subnet mask may be written in either
-						CIDR or dotted-decimal notation. Separate the IP address and subnet
-						mask with a slash ('/')
-					</para></description>
-				</configOption>
-				<configOption name="deny">
-					<synopsis>List of IP addresses to deny access from</synopsis>
-					<description><para>
-						The value is a comma-delimited list of IP addresses. IP addresses may
-						have a subnet mask appended. The subnet mask may be written in either
-						CIDR or dotted-decimal notation. Separate the IP address and subnet
-						mask with a slash ('/')
-					</para></description>
-				</configOption>
-				<configOption name="permit">
-					<synopsis>List of IP addresses to permit access from</synopsis>
-					<description><para>
-						The value is a comma-delimited list of IP addresses. IP addresses may
-						have a subnet mask appended. The subnet mask may be written in either
-						CIDR or dotted-decimal notation. Separate the IP address and subnet
-						mask with a slash ('/')
-					</para></description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'acl'.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
-{
-	struct ast_sockaddr addr;
-
-	if (ast_acl_list_is_empty(acl)) {
-		return 0;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
-	ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
-
-	if (ast_apply_acl(acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
-		ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&addr));
-		return 1;
-	}
-	return 0;
-}
-
-static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
-{
-	pjsip_sip_uri *sip_uri;
-	char host[256];
-
-	if (!contact || contact->star) {
-		return 0;
-	}
-	if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
-		return 0;
-	}
-	sip_uri = pjsip_uri_get_uri(contact->uri);
-	ast_copy_pj_str(host, &sip_uri->host, sizeof(host));
-	return ast_sockaddr_resolve(addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC);
-}
-
-static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
-{
-	int num_contact_addrs;
-	int forbidden = 0;
-	struct ast_sockaddr *contact_addrs;
-	int i;
-	pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
-
-	if (ast_acl_list_is_empty(contact_acl)) {
-		return 0;
-	}
-
-	while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
-		num_contact_addrs = extract_contact_addr(contact, &contact_addrs);
-		if (num_contact_addrs <= 0) {
-			continue;
-		}
-		for (i = 0; i < num_contact_addrs; ++i) {
-			if (ast_apply_acl(contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) {
-				ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&contact_addrs[i]));
-				forbidden = 1;
-				break;
-			}
-		}
-		ast_free(contact_addrs);
-		if (forbidden) {
-			/* No use checking other contacts if we already have failed ACL check */
-			break;
-		}
-	}
-
-	return forbidden;
-}
-
-#define SIP_SORCERY_ACL_TYPE "acl"
-
-/*!
- * \brief SIP ACL details and configuration.
- */
-struct ast_sip_acl {
-	SORCERY_OBJECT(details);
-	struct ast_acl_list *acl;
-	struct ast_acl_list *contact_acl;
-};
-
-static int check_acls(void *obj, void *arg, int flags)
-{
-	struct ast_sip_acl *sip_acl = obj;
-	pjsip_rx_data *rdata = arg;
-
-	if (apply_acl(rdata, sip_acl->acl) ||
-	    apply_contact_acl(rdata, sip_acl->contact_acl)) {
-		return CMP_MATCH | CMP_STOP;
-	}
-	return 0;
-}
-
-static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ao2_container *, acls, ast_sorcery_retrieve_by_fields(
-			 ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE,
-			 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
-	RAII_VAR(struct ast_sip_acl *, matched_acl, NULL, ao2_cleanup);
-
-	if (!acls) {
-		ast_log(LOG_ERROR, "Unable to retrieve ACL sorcery data\n");
-		return PJ_FALSE;
-	}
-
-	if ((matched_acl = ao2_callback(acls, 0, check_acls, rdata))) {
-		if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		}
-		return PJ_TRUE;
-	}
-
-	return PJ_FALSE;
-}
-
-static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_acl *sip_acl = obj;
-	int error = 0;
-	int ignore;
-
-	if (!strncmp(var->name, "contact_", 8)) {
-		ast_append_acl(var->name + 8, var->value, &sip_acl->contact_acl, &error, &ignore);
-	} else {
-		ast_append_acl(var->name, var->value, &sip_acl->acl, &error, &ignore);
-	}
-
-	return error;
-}
-
-static pjsip_module acl_module = {
-	.name = { "ACL Module", 14 },
-	/* This should run after a logger but before anything else */
-	.priority = 1,
-	.on_rx_request = acl_on_rx_msg,
-};
-
-static void acl_destroy(void *obj)
-{
-	struct ast_sip_acl *sip_acl = obj;
-	sip_acl->acl = ast_free_acl_list(sip_acl->acl);
-	sip_acl->contact_acl = ast_free_acl_list(sip_acl->contact_acl);
-}
-
-static void *acl_alloc(const char *name)
-{
-	struct ast_sip_acl *sip_acl =
-		ast_sorcery_generic_alloc(sizeof(*sip_acl), acl_destroy);
-
-	return sip_acl;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sorcery_apply_default(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE,
-				  "config", "pjsip.conf,criteria=type=acl");
-
-	if (ast_sorcery_object_register(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE,
-					acl_alloc, NULL, NULL)) {
-
-		ast_log(LOG_ERROR, "Failed to register SIP %s object with sorcery\n",
-			SIP_SORCERY_ACL_TYPE);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "permit", "", acl_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "deny", "", acl_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "acl", "", acl_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_permit", "", acl_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_deny", "", acl_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "contact_acl", "", acl_handler, NULL, NULL, 0, 0);
-
-	ast_sorcery_load_object(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE);
-
-	ast_sip_register_service(&acl_module);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_service(&acl_module);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP ACL Resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c
deleted file mode 100644
index 8a78125..0000000
--- a/res/res_pjsip_authenticator_digest.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/strings.h"
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-AO2_GLOBAL_OBJ_STATIC(entity_id);
-
-/*!
- * \brief Determine if authentication is required
- *
- * Authentication is required if the endpoint has at least one auth
- * section specified
- */
-static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, artificial, ast_sip_get_artificial_endpoint(), ao2_cleanup);
-
-	return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
-}
-
-static void auth_store_cleanup(void *data)
-{
-	struct ast_sip_auth **auth = data;
-
-	ao2_cleanup(*auth);
-	ast_free(data);
-}
-
-/*!
- * \brief Thread-local storage for \ref ast_sip_auth
- *
- * The PJSIP authentication API is a bit annoying. When you set
- * up an authentication server, you specify a lookup callback to
- * call into when verifying incoming credentials. The problem
- * with this callback is that it only gives you the realm and
- * authentication username. In 2.0.5, there is a new version of
- * the callback you can use that gives the pjsip_rx_data in
- * addition.
- *
- * Unfortunately, the data we actually \b need is the
- * \ref ast_sip_auth we are currently observing. So we have two
- * choices:
- * 1) Use the current PJSIP API and use thread-local storage
- * to temporarily store our SIP authentication information. Then
- * in the callback, we can retrieve the authentication info and
- * use as needed. Given our threading model, this is safe.
- * 2) Use the 2.0.5 API and temporarily store the authentication
- * information in the rdata's endpoint_info. Then in the callback,
- * we can retrieve the authentication info from the rdata.
- *
- * I've chosen option 1 since it does not require backporting
- * any APIs from future versions of PJSIP, plus I feel the
- * thread-local option is a bit cleaner.
- */
-AST_THREADSTORAGE_CUSTOM(auth_store, NULL, auth_store_cleanup);
-
-/*!
- * \brief Store authentication information in thread-local storage
- */
-static int store_auth(struct ast_sip_auth *auth)
-{
-	struct ast_sip_auth **pointing;
-	pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
-	if (!pointing || *pointing) {
-		return -1;
-	}
-
-	ao2_ref(auth, +1);
-	*pointing = auth;
-	return 0;
-}
-
-/*!
- * \brief Remove authentication information from thread-local storage
- */
-static int remove_auth(void)
-{
-	struct ast_sip_auth **pointing;
-	pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
-	if (!pointing) {
-		return -1;
-	}
-
-	ao2_cleanup(*pointing);
-	*pointing = NULL;
-	return 0;
-}
-
-/*!
- * \brief Retrieve authentication information from thread-local storage
- */
-static struct ast_sip_auth *get_auth(void)
-{
-	struct ast_sip_auth **auth;
-	auth = ast_threadstorage_get(&auth_store, sizeof(auth));
-	if (auth && *auth) {
-		ao2_ref(*auth, +1);
-		return *auth;
-	}
-	return NULL;
-}
-
-/*!
- * \brief Lookup callback for authentication verification
- *
- * This function is called when we call pjsip_auth_srv_verify(). It
- * expects us to verify that the realm and account name from the
- * Authorization header is correct. We are then supposed to supply
- * a password or MD5 sum of credentials.
- *
- * \param pool A memory pool we can use for allocations
- * \param realm The realm from the Authorization header
- * \param acc_name the user from the Authorization header
- * \param[out] info The credentials we need to fill in
- * \retval PJ_SUCCESS Successful authentication
- * \retval other Unsuccessful
- */
-static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm,
-		const pj_str_t *acc_name, pjsip_cred_info *info)
-{
-	RAII_VAR(struct ast_sip_auth *, auth, get_auth(), ao2_cleanup);
-	if (!auth) {
-		return PJSIP_SC_FORBIDDEN;
-	}
-
-	if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
-		return PJSIP_SC_FORBIDDEN;
-	}
-
-	if (pj_strcmp2(realm, auth->realm)) {
-		return PJSIP_SC_FORBIDDEN;
-	}
-	if (pj_strcmp2(acc_name, auth->auth_user)) {
-		return PJSIP_SC_FORBIDDEN;
-	}
-
-	pj_strdup2(pool, &info->realm, auth->realm);
-	pj_strdup2(pool, &info->username, auth->auth_user);
-
-	switch (auth->type) {
-	case AST_SIP_AUTH_TYPE_USER_PASS:
-		pj_strdup2(pool, &info->data, auth->auth_pass);
-		info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
-		break;
-	case AST_SIP_AUTH_TYPE_MD5:
-		pj_strdup2(pool, &info->data, auth->md5_creds);
-		info->data_type = PJSIP_CRED_DATA_DIGEST;
-		break;
-	default:
-		return PJSIP_SC_FORBIDDEN;
-	}
-	return PJ_SUCCESS;
-}
-
-/*!
- * \brief Calculate a nonce
- *
- * We use this in order to create authentication challenges. We also use this in order
- * to verify that an incoming request with credentials could be in response to one
- * of our challenges.
- *
- * The nonce is calculated from a timestamp, the source IP address, the source port, a
- * unique ID for us, and the realm. This helps to ensure that the incoming request
- * is from the same source that the nonce was calculated for. Including the realm
- * ensures that multiple challenges to the same request have different nonces.
- *
- * \param A UNIX timestamp expressed as a string
- * \param rdata The incoming request
- * \param realm The realm for which authentication should occur
- */
-static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
-{
-	struct ast_str *str = ast_str_alloca(256);
-	RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
-	char hash[33];
-
-	ast_str_append(&str, 0, "%s", timestamp);
-	ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
-	ast_str_append(&str, 0, ":%d", rdata->pkt_info.src_port);
-	ast_str_append(&str, 0, ":%s", eid);
-	ast_str_append(&str, 0, ":%s", realm);
-	ast_md5_hash(hash, ast_str_buffer(str));
-
-	ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
-	return 0;
-}
-
-/*!
- * \brief Ensure that a nonce on an incoming request is sane.
- *
- * The nonce in an incoming Authorization header needs to pass some scrutiny in order
- * for us to consider accepting it. What we do is re-build a nonce based on request
- * data and a realm and see if it matches the nonce they sent us.
- * \param candidate The nonce on an incoming request
- * \param rdata The incoming request
- * \param auth The auth credentials we are trying to match against.
- * \retval 0 Nonce does not pass validity checks
- * \retval 1 Nonce passes validity check
- */
-static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
-{
-	char *copy = ast_strdupa(candidate);
-	char *timestamp = strsep(&copy, "/");
-	int timestamp_int;
-	time_t now = time(NULL);
-	struct ast_str *calculated = ast_str_alloca(64);
-
-	if (!copy) {
-		/* Clearly a bad nonce! */
-		return 0;
-	}
-
-	if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
-		return 0;
-	}
-
-	if ((int) now - timestamp_int > auth->nonce_lifetime) {
-		return 0;
-	}
-
-	build_nonce(&calculated, timestamp, rdata, auth->realm);
-	ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
-	if (strcmp(ast_str_buffer(calculated), candidate)) {
-		return 0;
-	}
-	return 1;
-}
-
-static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
-{
-	struct pjsip_authorization_hdr *auth_hdr = (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
-	int challenge_found = 0;
-	char nonce[64];
-
-	while ((auth_hdr = (pjsip_authorization_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, auth_hdr->next))) {
-		ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
-		if (check_nonce(nonce, rdata, auth) && !pj_strcmp2(&auth_hdr->credential.digest.realm, auth->realm)) {
-			challenge_found = 1;
-			break;
-		}
-	}
-
-	return challenge_found;
-}
-
-/*!
- * \brief Common code for initializing a pjsip_auth_srv
- */
-static void setup_auth_srv(pj_pool_t *pool, pjsip_auth_srv *auth_server, const char *realm)
-{
-	pj_str_t realm_str;
-	pj_cstr(&realm_str, realm);
-
-	pjsip_auth_srv_init(pool, auth_server, &realm_str, digest_lookup, 0);
-}
-
-/*!
- * \brief Result of digest verification
- */
-enum digest_verify_result {
-	/*! Authentication credentials incorrect */
-	AUTH_FAIL,
-	/*! Authentication credentials correct */
-	AUTH_SUCCESS,
-	/*! Authentication credentials correct but nonce mismatch */
-	AUTH_STALE,
-	/*! Authentication credentials were not provided */
-	AUTH_NOAUTH,
-};
-
-/*!
- * \brief astobj2 callback for verifying incoming credentials
- *
- * \param auth The ast_sip_auth to check against
- * \param rdata The incoming request
- * \param pool A pool to use for the auth server
- * \return CMP_MATCH on successful authentication
- * \return 0 on failed authentication
- */
-static int verify(struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
-{
-	pj_status_t authed;
-	int response_code;
-	pjsip_auth_srv auth_server;
-	int stale = 0;
-
-	if (!find_challenge(rdata, auth)) {
-		/* Couldn't find a challenge with a sane nonce.
-		 * Nonce mismatch may just be due to staleness.
-		 */
-		stale = 1;
-	}
-
-	setup_auth_srv(pool, &auth_server, auth->realm);
-
-	store_auth(auth);
-
-	authed = pjsip_auth_srv_verify(&auth_server, rdata, &response_code);
-
-	remove_auth();
-
-	if (authed == PJ_SUCCESS) {
-		if (stale) {
-			return AUTH_STALE;
-		} else {
-			return AUTH_SUCCESS;
-		}
-	}
-
-	if (authed == PJSIP_EAUTHNOAUTH) {
-		return AUTH_NOAUTH;
-	}
-
-	return AUTH_FAIL;
-}
-
-/*!
- * \brief astobj2 callback for adding digest challenges to responses
- *
- * \param realm An auth's realm to build a challenge from
- * \param tdata The response to add the challenge to
- * \param rdata The request the challenge is in response to
- * \param is_stale Indicates whether nonce on incoming request was stale
- */
-static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
-{
-	pj_str_t qop;
-	pj_str_t pj_nonce;
-	pjsip_auth_srv auth_server;
-	struct ast_str *nonce = ast_str_alloca(256);
-	char time_buf[32];
-	time_t timestamp = time(NULL);
-	snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
-
-	build_nonce(&nonce, time_buf, rdata, realm);
-
-	setup_auth_srv(tdata->pool, &auth_server, realm);
-
-	pj_cstr(&pj_nonce, ast_str_buffer(nonce));
-	pj_cstr(&qop, "auth");
-	pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
-}
-
-/*!
- * \brief Check authentication using Digest scheme
- *
- * This function will check an incoming message against configured authentication
- * options. If \b any of the incoming Authorization headers result in successful
- * authentication, then authentication is considered successful.
- *
- * \see ast_sip_check_authentication
- */
-static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint,
-		pjsip_rx_data *rdata, pjsip_tx_data *tdata)
-{
-	struct ast_sip_auth **auths;
-	enum digest_verify_result *verify_res;
-	enum ast_sip_check_auth_result res;
-	int i;
-	int failures = 0;
-	size_t auth_size;
-
-	RAII_VAR(struct ast_sip_endpoint *, artificial_endpoint,
-		 ast_sip_get_artificial_endpoint(), ao2_cleanup);
-
-	auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
-
-	auths = ast_alloca(auth_size * sizeof(*auths));
-	verify_res = ast_alloca(auth_size * sizeof(*verify_res));
-
-	if (!auths) {
-		return AST_SIP_AUTHENTICATION_ERROR;
-	}
-
-	if (endpoint == artificial_endpoint) {
-		auths[0] = ast_sip_get_artificial_auth();
-	} else if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
-		res = AST_SIP_AUTHENTICATION_ERROR;
-		goto cleanup;
-	}
-
-	for (i = 0; i < auth_size; ++i) {
-		if (ast_strlen_zero(auths[i]->realm)) {
-			ast_string_field_set(auths[i], realm, "asterisk");
-		}
-		verify_res[i] = verify(auths[i], rdata, tdata->pool);
-		if (verify_res[i] == AUTH_SUCCESS) {
-			res = AST_SIP_AUTHENTICATION_SUCCESS;
-			goto cleanup;
-		}
-		if (verify_res[i] == AUTH_FAIL) {
-			failures++;
-		}
-	}
-
-	for (i = 0; i < auth_size; ++i) {
-		challenge(auths[i]->realm, tdata, rdata, verify_res[i] == AUTH_STALE);
-	}
-
-	if (failures == auth_size) {
-		res = AST_SIP_AUTHENTICATION_FAILED;
-	} else {
-		res = AST_SIP_AUTHENTICATION_CHALLENGE;
-	}
-
-cleanup:
-	ast_sip_cleanup_auths(auths, auth_size);
-	return res;
-}
-
-static struct ast_sip_authenticator digest_authenticator = {
-	.requires_authentication = digest_requires_authentication,
-	.check_authentication = digest_check_auth,
-};
-
-static int build_entity_id(void)
-{
-	char *eid;
-
-	eid = ao2_alloc(AST_UUID_STR_LEN, NULL);
-	if (!eid) {
-		return -1;
-	}
-
-	ast_uuid_generate_str(eid, AST_UUID_STR_LEN);
-	ao2_global_obj_replace_unref(entity_id, eid);
-	ao2_ref(eid, -1);
-	return 0;
-}
-
-static int reload_module(void)
-{
-	if (build_entity_id()) {
-		return -1;
-	}
-	return 0;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (build_entity_id()) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (ast_sip_register_authenticator(&digest_authenticator)) {
-		ao2_global_obj_release(entity_id);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_authenticator(&digest_authenticator);
-	ao2_global_obj_release(entity_id);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.reload = reload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c
deleted file mode 100644
index e22ce6a..0000000
--- a/res/res_pjsip_caller_id.c
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/channel.h"
-#include "asterisk/module.h"
-#include "asterisk/callerid.h"
-
-/*!
- * \internal
- * \brief Set an ast_party_id name and number based on an identity header.
- * \param hdr From, P-Asserted-Identity, or Remote-Party-ID header on incoming message
- * \param[out] id The ID to set data on
- */
-static void set_id_from_hdr(pjsip_fromto_hdr *hdr, struct ast_party_id *id)
-{
-	char cid_name[AST_CHANNEL_NAME];
-	char cid_num[AST_CHANNEL_NAME];
-	pjsip_sip_uri *uri;
-	pjsip_name_addr *id_name_addr = (pjsip_name_addr *) hdr->uri;
-
-	uri = pjsip_uri_get_uri(id_name_addr);
-	ast_copy_pj_str(cid_name, &id_name_addr->display, sizeof(cid_name));
-	ast_copy_pj_str(cid_num, &uri->user, sizeof(cid_num));
-
-	ast_free(id->name.str);
-	id->name.str = ast_strdup(cid_name);
-	if (!ast_strlen_zero(cid_name)) {
-		id->name.valid = 1;
-	}
-	ast_free(id->number.str);
-	id->number.str = ast_strdup(cid_num);
-	if (!ast_strlen_zero(cid_num)) {
-		id->number.valid = 1;
-	}
-}
-
-/*!
- * \internal
- * \brief Get a P-Asserted-Identity or Remote-Party-ID header from an incoming message
- *
- * This function will parse the header as if it were a From header. This allows for us
- * to easily manipulate the URI, as well as add, modify, or remove parameters from the
- * header
- *
- * \param rdata The incoming message
- * \param header_name The name of the ID header to find
- * \retval NULL No ID header present or unable to parse ID header
- * \retval non-NULL The parsed ID header
- */
-static pjsip_fromto_hdr *get_id_header(pjsip_rx_data *rdata, const pj_str_t *header_name)
-{
-	static const pj_str_t from = { "From", 4 };
-	pj_str_t header_content;
-	pjsip_fromto_hdr *parsed_hdr;
-	pjsip_generic_string_hdr *ident = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
-			header_name, NULL);
-	int parsed_len;
-
-	if (!ident) {
-		return NULL;
-	}
-
-	pj_strdup_with_null(rdata->tp_info.pool, &header_content, &ident->hvalue);
-
-	parsed_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from, header_content.ptr,
-			pj_strlen(&header_content), &parsed_len);
-
-	if (!parsed_hdr) {
-		return NULL;
-	}
-
-	return parsed_hdr;
-}
-
-/*!
- * \internal
- * \brief Set an ast_party_id structure based on data in a P-Asserted-Identity header
- *
- * This makes use of \ref set_id_from_hdr for setting name and number. It uses
- * the contents of a Privacy header in order to set presentation information.
- *
- * \param rdata The incoming message
- * \param[out] id The ID to set
- * \retval 0 Successfully set the party ID
- * \retval non-zero Could not set the party ID
- */
-static int set_id_from_pai(pjsip_rx_data *rdata, struct ast_party_id *id)
-{
-	static const pj_str_t pai_str = { "P-Asserted-Identity", 19 };
-	static const pj_str_t privacy_str = { "Privacy", 7 };
-	pjsip_fromto_hdr *pai_hdr = get_id_header(rdata, &pai_str);
-	pjsip_generic_string_hdr *privacy;
-
-	if (!pai_hdr) {
-		return -1;
-	}
-
-	set_id_from_hdr(pai_hdr, id);
-
-	if (!id->number.valid) {
-		return -1;
-	}
-
-	privacy = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &privacy_str, NULL);
-	if (!privacy) {
-		return 0;
-	}
-	if (!pj_stricmp2(&privacy->hvalue, "id")) {
-		id->number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-		id->name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Set an ast_party_id structure based on data in a Remote-Party-ID header
- *
- * This makes use of \ref set_id_from_hdr for setting name and number. It uses
- * the privacy and screen parameters in order to set presentation information.
- *
- * \param rdata The incoming message
- * \param[out] id The ID to set
- * \retval 0 Succesfully set the party ID
- * \retval non-zero Could not set the party ID
- */
-static int set_id_from_rpid(pjsip_rx_data *rdata, struct ast_party_id *id)
-{
-	static const pj_str_t rpid_str = { "Remote-Party-ID", 15 };
-	static const pj_str_t privacy_str = { "privacy", 7 };
-	static const pj_str_t screen_str = { "screen", 6 };
-	pjsip_fromto_hdr *rpid_hdr = get_id_header(rdata, &rpid_str);
-	pjsip_param *screen;
-	pjsip_param *privacy;
-
-	if (!rpid_hdr) {
-		return -1;
-	}
-
-	set_id_from_hdr(rpid_hdr, id);
-
-	if (!id->number.valid) {
-		return -1;
-	}
-
-	privacy = pjsip_param_find(&rpid_hdr->other_param, &privacy_str);
-	screen = pjsip_param_find(&rpid_hdr->other_param, &screen_str);
-	if (privacy && !pj_stricmp2(&privacy->value, "full")) {
-		id->number.presentation |= AST_PRES_RESTRICTED;
-		id->name.presentation |= AST_PRES_RESTRICTED;
-	}
-	if (screen && !pj_stricmp2(&screen->value, "yes")) {
-		id->number.presentation |= AST_PRES_USER_NUMBER_PASSED_SCREEN;
-		id->name.presentation |= AST_PRES_USER_NUMBER_PASSED_SCREEN;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Set an ast_party_id structure based on data in a From
- *
- * This makes use of \ref set_id_from_hdr for setting name and number. It uses
- * no information from the message in order to set privacy. It relies on endpoint
- * configuration for privacy information.
- *
- * \param rdata The incoming message
- * \param[out] id The ID to set
- * \retval 0 Succesfully set the party ID
- * \retval non-zero Could not set the party ID
- */
-static int set_id_from_from(struct pjsip_rx_data *rdata, struct ast_party_id *id)
-{
-	pjsip_fromto_hdr *from = pjsip_msg_find_hdr(rdata->msg_info.msg,
-			PJSIP_H_FROM, rdata->msg_info.msg->hdr.next);
-
-	if (!from) {
-		/* This had better not happen */
-		return -1;
-	}
-
-	set_id_from_hdr(from, id);
-
-	if (!id->number.valid) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Determine if a connected line update should be queued
- *
- * This uses information about the session and the ID that would be queued
- * in the connected line update in order to determine if we should queue
- * a connected line update.
- *
- * \param session The session whose channel we wish to queue the connected line update on
- * \param id The identification information that would be queued on the connected line update
- * \retval 0 We should not queue a connected line update
- * \retval non-zero We should queue a connected line update
- */
-static int should_queue_connected_line_update(const struct ast_sip_session *session, const struct ast_party_id *id)
-{
-	/* Invalid number means no update */
-	if (!id->number.valid) {
-		return 0;
-	}
-
-	/* If the session has never communicated an update or if the
-	 * new ID has a different number than the session, then we
-	 * should queue an update
-	 */
-	if (ast_strlen_zero(session->id.number.str) ||
-			strcmp(session->id.number.str, id->number.str)) {
-		return 1;
-	}
-
-	/* By making it to this point, it means the number is not enough
-	 * to determine if an update should be sent. Now we look at
-	 * the name
-	 */
-
-	/* If the number couldn't warrant an update and the name is
-	 * invalid, then no update
-	 */
-	if (!id->name.valid) {
-		return 0;
-	}
-
-	/* If the name has changed or we don't have a name set for the
-	 * session, then we should send an update
-	 */
-	if (ast_strlen_zero(session->id.name.str) ||
-			strcmp(session->id.name.str, id->name.str)) {
-		return 1;
-	}
-
-	/* Neither the name nor the number have changed. No update */
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Queue a connected line update on a session's channel.
- * \param session The session whose channel should have the connected line update queued upon.
- * \param id The identification information to place in the connected line update
- */
-static void queue_connected_line_update(struct ast_sip_session *session, const struct ast_party_id *id)
-{
-	struct ast_party_connected_line connected;
-	struct ast_party_caller caller;
-
-	/* Fill connected line information */
-	ast_party_connected_line_init(&connected);
-	connected.id = *id;
-	connected.id.tag = session->endpoint->id.self.tag;
-	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-
-	/* Save to channel driver copy */
-	ast_party_id_copy(&session->id, &connected.id);
-
-	/* Update our channel CALLERID() */
-	ast_party_caller_init(&caller);
-	caller.id = connected.id;
-	caller.ani = connected.id;
-	caller.ani2 = ast_channel_caller(session->channel)->ani2;
-	ast_channel_set_caller_event(session->channel, &caller, NULL);
-
-	/* Tell peer about the new connected line information. */
-	ast_channel_queue_connected_line_update(session->channel, &connected, NULL);
-}
-
-/*!
- * \internal
- * \brief Make updates to connected line information based on an incoming request.
- *
- * This will get identity information from an incoming request. Once the identification is
- * retrieved, we will check if the new information warrants a connected line update and queue
- * a connected line update if so.
- *
- * \param session The session on which we received an incoming request
- * \param rdata The incoming request
- */
-static void update_incoming_connected_line(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	struct ast_party_id id;
-
-	if (!session->endpoint->id.trust_inbound) {
-		return;
-	}
-
-	ast_party_id_init(&id);
-	if (!set_id_from_pai(rdata, &id) || !set_id_from_rpid(rdata, &id)) {
-		if (should_queue_connected_line_update(session, &id)) {
-			queue_connected_line_update(session, &id);
-		}
-	}
-	ast_party_id_free(&id);
-}
-
-/*!
- * \internal
- * \brief Session supplement callback on an incoming INVITE request
- *
- * If we are receiving an initial INVITE, then we will set the session's identity
- * based on the INVITE or configured endpoint values. If we are receiving a reinvite,
- * then we will potentially queue a connected line update via the \ref update_incoming_connected_line
- * function
- *
- * \param session The session that has received an INVITE
- * \param rdata The incoming INVITE
- */
-static int caller_id_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED) {
-		/*
-		 * Initial inbound INVITE.  Set the session ID directly
-		 * because the channel has not been created yet.
-		 */
-		if (session->endpoint->id.trust_inbound
-			&& (!set_id_from_pai(rdata, &session->id)
-				|| !set_id_from_rpid(rdata, &session->id))) {
-			ast_free(session->id.tag);
-			session->id.tag = ast_strdup(session->endpoint->id.self.tag);
-			return 0;
-		}
-		ast_party_id_copy(&session->id, &session->endpoint->id.self);
-		if (!session->endpoint->id.self.number.valid) {
-			set_id_from_from(rdata, &session->id);
-		}
-	} else {
-		/* Reinvite. Check for changes to the ID and queue a connected line
-		 * update if necessary
-		 */
-		update_incoming_connected_line(session, rdata);
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Session supplement callback on INVITE response
- *
- * INVITE responses could result in queuing connected line updates.
- *
- * \param session The session on which communication is happening
- * \param rdata The incoming INVITE response
- */
-static void caller_id_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	if (!session->channel) {
-		return;
-	}
-
-	update_incoming_connected_line(session, rdata);
-}
-
-/*!
- * \internal
- * \brief Set name and number information on an identity header.
- * \param pool Memory pool to use for string duplication
- * \param id_hdr A From, P-Asserted-Identity, or Remote-Party-ID header to modify
- * \param id The identity information to apply to the header
- */
-static void modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id)
-{
-	pjsip_name_addr *id_name_addr;
-	pjsip_sip_uri *id_uri;
-
-	id_name_addr = (pjsip_name_addr *) id_hdr->uri;
-	id_uri = pjsip_uri_get_uri(id_name_addr->uri);
-
-	if (id->name.valid) {
-		int name_buf_len = strlen(id->name.str) * 2 + 1;
-		char *name_buf = ast_alloca(name_buf_len);
-
-		ast_escape_quoted(id->name.str, name_buf, name_buf_len);
-		pj_strdup2(pool, &id_name_addr->display, name_buf);
-	}
-
-	if (id->number.valid) {
-		pj_strdup2(pool, &id_uri->user, id->number.str);
-	}
-}
-
-/*!
- * \internal
- * \brief Create an identity header for an outgoing message
- * \param hdr_name The name of the header to create
- * \param tdata The message to place the header on
- * \param id The identification information for the new header
- * \return newly-created header
- */
-static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_tx_data *tdata, const struct ast_party_id *id)
-{
-	pjsip_fromto_hdr *id_hdr;
-	pjsip_fromto_hdr *base;
-	pjsip_name_addr *id_name_addr;
-	pjsip_sip_uri *id_uri;
-
-	base = tdata->msg->type == PJSIP_REQUEST_MSG ? PJSIP_MSG_FROM_HDR(tdata->msg) :
-		PJSIP_MSG_TO_HDR(tdata->msg);
-	id_hdr = pjsip_from_hdr_create(tdata->pool);
-	id_hdr->type = PJSIP_H_OTHER;
-	pj_strdup(tdata->pool, &id_hdr->name, hdr_name);
-	id_hdr->sname.slen = 0;
-
-	id_name_addr = pjsip_uri_clone(tdata->pool, base->uri);
-	id_uri = pjsip_uri_get_uri(id_name_addr->uri);
-
-	if (id->name.valid) {
-		int name_buf_len = strlen(id->name.str) * 2 + 1;
-		char *name_buf = ast_alloca(name_buf_len);
-
-		ast_escape_quoted(id->name.str, name_buf, name_buf_len);
-		pj_strdup2(tdata->pool, &id_name_addr->display, name_buf);
-	}
-
-	pj_strdup2(tdata->pool, &id_uri->user, id->number.str);
-
-	id_hdr->uri = (pjsip_uri *) id_name_addr;
-	return id_hdr;
-}
-
-/*!
- * \internal
- * \brief Add a Privacy header to an outbound message
- *
- * When sending a P-Asserted-Identity header, if privacy is requested, then we
- * will need to indicate such by adding a Privacy header. Similarly, if no
- * privacy is requested, and a Privacy header already exists on the message,
- * then the old Privacy header should be removed.
- *
- * \param tdata The outbound message to add the Privacy header to
- * \param id The id information used to determine privacy
- */
-static void add_privacy_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
-{
-	static const pj_str_t pj_privacy_name = { "Privacy", 7 };
-	static const pj_str_t pj_privacy_value = { "id", 2 };
-	pjsip_hdr *old_privacy;
-
-	old_privacy = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_privacy_name, NULL);
-
-	if ((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
-			(id->number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-		if (old_privacy) {
-			pj_list_erase(old_privacy);
-		}
-	} else if (!old_privacy) {
-		pjsip_generic_string_hdr *privacy_hdr = pjsip_generic_string_hdr_create(
-				tdata->pool, &pj_privacy_name, &pj_privacy_value);
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)privacy_hdr);
-	}
-}
-
-/*!
- * \internal
- * \brief Add a P-Asserted-Identity header to an outbound message
- * \param tdata The message to add the header to
- * \param id The identification information used to populate the header
- */
-static void add_pai_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
-{
-	static const pj_str_t pj_pai_name = { "P-Asserted-Identity", 19 };
-	pjsip_fromto_hdr *pai_hdr;
-	pjsip_fromto_hdr *old_pai;
-
-	if (!id->number.valid) {
-		return;
-	}
-
-	/* Since inv_session reuses responses, we have to make sure there's not already
-	 * a P-Asserted-Identity present. If there is, we just modify the old one.
-	 */
-	old_pai = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_pai_name, NULL);
-	if (old_pai) {
-		modify_id_header(tdata->pool, old_pai, id);
-		add_privacy_header(tdata, id);
-		return;
-	}
-
-	pai_hdr = create_new_id_hdr(&pj_pai_name, tdata, id);
-	if (!pai_hdr) {
-		return;
-	}
-	add_privacy_header(tdata, id);
-
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)pai_hdr);
-}
-
-/*!
- * \internal
- * \brief Add privacy and screen parameters to a Remote-Party-ID header.
- *
- * If privacy is requested, then the privacy and screen parameters need to
- * reflect this. Similarly, if no privacy or screening is to be communicated,
- * we need to make sure that any previously set values are updated.
- *
- * \param tdata The message where the Remote-Party-ID header is
- * \param hdr The header on which the parameters are being added
- * \param id The identification information used to determine privacy
- */
-static void add_privacy_params(pjsip_tx_data *tdata, pjsip_fromto_hdr *hdr, const struct ast_party_id *id)
-{
-	static const pj_str_t privacy_str = { "privacy", 7 };
-	static const pj_str_t screen_str = { "screen", 6 };
-	static const pj_str_t privacy_full_str = { "full", 4 };
-	static const pj_str_t privacy_off_str = { "off", 3 };
-	static const pj_str_t screen_yes_str = { "yes", 3 };
-	static const pj_str_t screen_no_str = { "no", 2 };
-	pjsip_param *old_privacy;
-	pjsip_param *old_screen;
-	pjsip_param *privacy;
-	pjsip_param *screen;
-
-	old_privacy = pjsip_param_find(&hdr->other_param, &privacy_str);
-	old_screen = pjsip_param_find(&hdr->other_param, &screen_str);
-
-	if (!old_privacy) {
-		privacy = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
-		privacy->name = privacy_str;
-		pj_list_insert_before(&hdr->other_param, privacy);
-	} else {
-		privacy = old_privacy;
-	}
-
-	if (!old_screen) {
-		screen = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
-		screen->name = screen_str;
-		pj_list_insert_before(&hdr->other_param, screen);
-	} else {
-		screen = old_screen;
-	}
-
-	if ((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
-			(id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
-		privacy->value = privacy_off_str;
-	} else {
-		privacy->value = privacy_full_str;
-	}
-
-	if ((id->name.presentation & AST_PRES_NUMBER_TYPE) == AST_PRES_USER_NUMBER_PASSED_SCREEN &&
-			(id->number.presentation & AST_PRES_NUMBER_TYPE) == AST_PRES_USER_NUMBER_PASSED_SCREEN) {
-		screen->value = screen_yes_str;
-	} else {
-		screen->value = screen_no_str;
-	}
-}
-
-/*!
- * \internal
- * \brief Add a Remote-Party-ID header to an outbound message
- * \param tdata The message to add the header to
- * \param id The identification information used to populate the header
- */
-static void add_rpid_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
-{
-	static const pj_str_t pj_rpid_name = { "Remote-Party-ID", 15 };
-	pjsip_fromto_hdr *rpid_hdr;
-	pjsip_fromto_hdr *old_rpid;
-
-	if (!id->number.valid) {
-		return;
-	}
-
-	/* Since inv_session reuses responses, we have to make sure there's not already
-	 * a P-Asserted-Identity present. If there is, we just modify the old one.
-	 */
-	old_rpid = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_rpid_name, NULL);
-	if (old_rpid) {
-		modify_id_header(tdata->pool, old_rpid, id);
-		add_privacy_params(tdata, old_rpid, id);
-		return;
-	}
-
-	rpid_hdr = create_new_id_hdr(&pj_rpid_name, tdata, id);
-	if (!rpid_hdr) {
-		return;
-	}
-	add_privacy_params(tdata, rpid_hdr, id);
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)rpid_hdr);
-}
-
-/*!
- * \internal
- * \brief Add any appropriate identification headers to an outbound SIP message
- *
- * This will determine if an outbound message should have identification headers and
- * will add the appropriately configured headers
- *
- * \param session The session on which we will be sending the message
- * \param tdata The outbound message
- * \param The identity information to place on the message
- */
-static void add_id_headers(const struct ast_sip_session *session, pjsip_tx_data *tdata, const struct ast_party_id *id)
-{
-	if (((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED ||
-			(id->number.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) &&
-			!session->endpoint->id.trust_outbound) {
-		return;
-	}
-	if (session->endpoint->id.send_pai) {
-		add_pai_header(tdata, id);
-	}
-	if (session->endpoint->id.send_rpid) {
-		add_rpid_header(tdata, id);
-	}
-}
-
-/*!
- * \internal
- * \brief Session supplement callback for outgoing INVITE requests
- *
- * For an initial INVITE request, we may change the From header to appropriately
- * reflect the identity information. On all INVITEs (initial and reinvite) we may
- * add other identity headers such as P-Asserted-Identity and Remote-Party-ID based
- * on configuration and privacy settings
- *
- * \param session The session on which the INVITE will be sent
- * \param tdata The outbound INVITE request
- */
-static void caller_id_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct ast_party_id effective_id;
-	struct ast_party_id connected_id;
-
-	if (!session->channel) {
-		return;
-	}
-
-	/* Must do a deep copy unless we hold the channel lock the entire time. */
-	ast_party_id_init(&connected_id);
-	ast_channel_lock(session->channel);
-	effective_id = ast_channel_connected_effective_id(session->channel);
-	ast_party_id_copy(&connected_id, &effective_id);
-	ast_channel_unlock(session->channel);
-
-	if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED &&
-			ast_strlen_zero(session->endpoint->fromuser) &&
-			(session->endpoint->id.trust_outbound ||
-			((connected_id.name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
-			(connected_id.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED))) {
-		/* Only change the From header on the initial outbound INVITE. Switching it
-		 * mid-call might confuse some UAs.
-		 */
-		pjsip_fromto_hdr *from;
-		pjsip_dialog *dlg;
-
-		from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next);
-		dlg = session->inv_session->dlg;
-
-		modify_id_header(tdata->pool, from, &connected_id);
-		modify_id_header(dlg->pool, dlg->local.info, &connected_id);
-	}
-	add_id_headers(session, tdata, &connected_id);
-	ast_party_id_free(&connected_id);
-}
-
-/*!
- * \internal
- * \brief Session supplement for outgoing INVITE response
- *
- * This will add P-Asserted-Identity and Remote-Party-ID headers if necessary
- *
- * \param session The session on which the INVITE response is to be sent
- * \param tdata The outbound INVITE response
- */
-static void caller_id_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct ast_party_id effective_id;
-	struct ast_party_id connected_id;
-
-	if (!session->channel) {
-		return;
-	}
-
-	/* Must do a deep copy unless we hold the channel lock the entire time. */
-	ast_party_id_init(&connected_id);
-	ast_channel_lock(session->channel);
-	effective_id = ast_channel_connected_effective_id(session->channel);
-	ast_party_id_copy(&connected_id, &effective_id);
-	ast_channel_unlock(session->channel);
-
-	add_id_headers(session, tdata, &connected_id);
-	ast_party_id_free(&connected_id);
-}
-
-static struct ast_sip_session_supplement caller_id_supplement = {
-	.method = "INVITE,UPDATE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
-	.incoming_request = caller_id_incoming_request,
-	.incoming_response = caller_id_incoming_response,
-	.outgoing_request = caller_id_outgoing_request,
-	.outgoing_response = caller_id_outgoing_response,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sip_session_register_supplement(&caller_id_supplement);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&caller_id_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Caller ID Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c
deleted file mode 100644
index d9725f4..0000000
--- a/res/res_pjsip_dialog_info_body_generator.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<depend>res_pjsip_exten_state</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-/*! \brief Structure which contains dialog-info+xml state information */
-struct dialog_info_xml_state {
-	/*! \brief Version to place into the next NOTIFY */
-	unsigned int version;
-};
-
-/*! \brief Destructor for dialog-info+xml information */
-static void dialog_info_xml_state_destroy(void *obj)
-{
-	ast_free(obj);
-}
-
-/*! \brief Datastore for attaching dialog-info+xml state information */
-static const struct ast_datastore_info dialog_info_xml_datastore = {
-	.type = "dialog-info+xml",
-	.destroy = dialog_info_xml_state_destroy,
-};
-
-static void *dialog_info_allocate_body(void *data)
-{
-	struct ast_sip_exten_state_data *state_data = data;
-
-	return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info");
-}
-
-static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ast_sip_subscription *sub)
-{
-	struct ast_datastore *datastore = ast_sip_subscription_get_datastore(sub, "dialog-info+xml");
-
-	if (datastore) {
-		return datastore;
-	}
-
-	datastore = ast_sip_subscription_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");
-	if (!datastore) {
-		return NULL;
-	}
-	datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));
-	if (!datastore->data || ast_sip_subscription_add_datastore(sub, datastore)) {
-		ao2_ref(datastore, -1);
-		return NULL;
-	}
-
-	return datastore;
-}
-
-static unsigned int dialog_info_xml_get_version(struct ast_sip_subscription *sub, unsigned int *version)
-{
-	struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(sub);
-	struct dialog_info_xml_state *state;
-
-	if (!datastore) {
-		return -1;
-	}
-
-	state = datastore->data;
-	*version = state->version++;
-	ao2_ref(datastore, -1);
-
-	return 0;
-}
-
-static int dialog_info_generate_body_content(void *body, void *data)
-{
-	pj_xml_node *dialog_info = body, *dialog, *state;
-	struct ast_sip_exten_state_data *state_data = data;
-	char *local = ast_strdupa(state_data->local), *stripped, *statestring = NULL;
-	char *pidfstate = NULL, *pidfnote = NULL;
-	enum ast_sip_pidf_state local_state;
-	unsigned int version;
-	char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
-
-	if (!local || !state_data->sub) {
-		return -1;
-	}
-
-	if (dialog_info_xml_get_version(state_data->sub, &version)) {
-		ast_log(LOG_WARNING, "dialog-info+xml version could not be retrieved from datastore\n");
-		return -1;
-	}
-
-	stripped = ast_strip_quoted(local, "<", ">");
-	ast_sip_sanitize_xml(stripped, sanitized, sizeof(sanitized));
-
-	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
-
-	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info");
-
-	snprintf(version_str, sizeof(version_str), "%u", version);
-	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "version", version_str);
-
-	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "state", "full");
-	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "entity", sanitized);
-
-	dialog = ast_sip_presence_xml_create_node(state_data->pool, dialog_info, "dialog");
-	ast_sip_presence_xml_create_attr(state_data->pool, dialog, "id", state_data->exten);
-
-	state = ast_sip_presence_xml_create_node(state_data->pool, dialog, "state");
-	pj_strdup2(state_data->pool, &state->content, statestring);
-
-	if (state_data->exten_state == AST_EXTENSION_ONHOLD) {
-		pj_xml_node *local_node, *target, *param;
-
-		local_node = ast_sip_presence_xml_create_node(state_data->pool, dialog, "local");
-		target = ast_sip_presence_xml_create_node(state_data->pool, local_node, "target");
-		ast_sip_presence_xml_create_attr(state_data->pool, target, "uri", sanitized);
-		param = ast_sip_presence_xml_create_node(state_data->pool, target, "param");
-		ast_sip_presence_xml_create_attr(state_data->pool, param, "pname", "+sip.rendering");
-		ast_sip_presence_xml_create_attr(state_data->pool, param, "pvalue", "no");
-	}
-
-	return 0;
-}
-
-/* The maximum number of times the ast_str() for the body text can grow before we declare an XML body
- * too large to send.
- */
-#define MAX_STRING_GROWTHS 3
-
-static void dialog_info_to_string(void *body, struct ast_str **str)
-{
-	pj_xml_node *dialog_info = body;
-	int growths = 0;
-	int size;
-
-	do {
-		size = pj_xml_print(dialog_info, ast_str_buffer(*str), ast_str_size(*str), PJ_TRUE);
-		if (size == AST_PJSIP_XML_PROLOG_LEN) {
-			ast_str_make_space(str, ast_str_size(*str) * 2);
-			++growths;
-		}
-	} while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS);
-
-	if (size == AST_PJSIP_XML_PROLOG_LEN) {
-		ast_log(LOG_WARNING, "dialog-info+xml body text too large\n");
-		return;
-	}
-
-	*(ast_str_buffer(*str) + size) = '\0';
-	ast_str_update(*str);
-}
-
-static struct ast_sip_pubsub_body_generator dialog_info_body_generator = {
-	.type = "application",
-	.subtype = "dialog-info+xml",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.allocate_body = dialog_info_allocate_body,
-	.generate_body_content = dialog_info_generate_body_content,
-	.to_string = dialog_info_to_string,
-	/* No need for a destroy_body callback since we use a pool */
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_generator(&dialog_info_body_generator)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_pubsub_unregister_body_generator(&dialog_info_body_generator);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State Dialog Info+XML Provider",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c
deleted file mode 100644
index a4ac157..0000000
--- a/res/res_pjsip_diversion.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/callerid.h"
-#include "asterisk/channel.h"
-#include "asterisk/module.h"
-#include "asterisk/strings.h"
-
-static const pj_str_t diversion_name = { "Diversion", 9 };
-
-/*! \brief Diversion header reasons
- *
- * The core defines a bunch of constants used to define
- * redirecting reasons. This provides a translation table
- * between those and the strings which may be present in
- * a SIP Diversion header
- */
-static const struct reasons {
-	enum AST_REDIRECTING_REASON code;
-	char *const text;
-} reason_table[] = {
-	{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
-	{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
-	{ AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
-	{ AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
-	{ AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
-	{ AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
-	{ AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
-	{ AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
-	{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
-	{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
-	{ AST_REDIRECTING_REASON_AWAY, "away" },
-	{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"},
-	{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"},
-};
-
-static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
-{
-	int code = reason->code;
-
-	/* use specific string if given */
-	if (!ast_strlen_zero(reason->str)) {
-		return reason->str;
-	}
-
-	if (code >= 0 && code < ARRAY_LEN(reason_table)) {
-		return reason_table[code].text;
-	}
-
-	return "unknown";
-}
-
-static enum AST_REDIRECTING_REASON reason_str_to_code(const char *text)
-{
-	enum AST_REDIRECTING_REASON code = AST_REDIRECTING_REASON_UNKNOWN;
-	int i;
-
-	for (i = 0; i < ARRAY_LEN(reason_table); ++i) {
-		if (!strcasecmp(text, reason_table[i].text)) {
-			code = reason_table[i].code;
-			break;
-		}
-	}
-
-	return code;
-}
-
-static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
-{
-	static const pj_str_t from_name = { "From", 4 };
-
-	pjsip_generic_string_hdr *hdr;
-	pj_str_t value;
-	int size;
-
-	if (!(hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &diversion_name, NULL))) {
-		return NULL;
-	}
-
-	pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
-
-	/* parse as a fromto header */
-	return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
-			       pj_strlen(&value), &size);
-}
-
-static void set_redirecting_value(char **dst, const pj_str_t *src)
-{
-	ast_free(*dst);
-	*dst = ast_malloc(pj_strlen(src) + 1);
-	ast_copy_pj_str(*dst, src, pj_strlen(src) + 1);
-}
-
-static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data,
-			       struct ast_set_party_id *update)
-{
-	pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri);
-
-	if (pj_strlen(&uri->user)) {
-		update->number = 1;
-		data->number.valid = 1;
-		set_redirecting_value(&data->number.str, &uri->user);
-	}
-
-	if (pj_strlen(&name_addr->display)) {
-		update->name = 1;
-		data->name.valid = 1;
-		set_redirecting_value(&data->name.str, &name_addr->display);
-	}
-}
-
-static void copy_redirecting_id(struct ast_party_id *dst, const struct ast_party_id *src,
-				struct ast_set_party_id *update)
-{
-	ast_party_id_copy(dst, src);
-
-	if (dst->number.valid) {
-		update->number = 1;
-	}
-
-	if (dst->name.valid) {
-		update->name = 1;
-	}
-}
-
-static void set_redirecting_reason(pjsip_fromto_hdr *hdr,
-				   struct ast_party_redirecting_reason *data)
-{
-	static const pj_str_t reason_name = { "reason", 6 };
-	pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name);
-
-	if (!reason) {
-		return;
-	}
-
-	set_redirecting_value(&data->str, &reason->value);
-	data->code = reason_str_to_code(data->str);
-}
-
-static void set_redirecting(struct ast_sip_session *session,
-			    pjsip_fromto_hdr *from_info,
-			    pjsip_name_addr *to_info)
-{
-	struct ast_party_redirecting data;
-	struct ast_set_party_redirecting update;
-
-	if (!session->channel) {
-		return;
-	}
-
-	ast_party_redirecting_init(&data);
-	memset(&update, 0, sizeof(update));
-
-	if (from_info) {
-		set_redirecting_id((pjsip_name_addr*)from_info->uri,
-			&data.from, &update.from);
-		set_redirecting_reason(from_info, &data.reason);
-	} else {
-		copy_redirecting_id(&data.from, &session->id, &update.from);
-	}
-
-	set_redirecting_id(to_info, &data.to, &update.to);
-
-	ast_set_party_id_all(&update.priv_orig);
-	ast_set_party_id_all(&update.priv_from);
-	ast_set_party_id_all(&update.priv_to);
-	++data.count;
-
-	ast_channel_set_redirecting(session->channel, &data, &update);
-	ast_party_redirecting_free(&data);
-}
-
-static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
-
-	if (hdr) {
-		set_redirecting(session, hdr, (pjsip_name_addr*)
-				PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
-	}
-
-	return 0;
-}
-
-static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	static const pj_str_t contact_name = { "Contact", 7 };
-
-	pjsip_status_line status = rdata->msg_info.msg->line.status;
-	pjsip_fromto_hdr *div_hdr;
-	pjsip_contact_hdr *contact_hdr;
-
-	if ((status.code != 302) && (status.code != 181)) {
-		return;
-	}
-
-	/* use the diversion header info if there is one. if not one then use the
-           session caller id info. if that doesn't exist use info from the To hdr*/
-	if (!(div_hdr = get_diversion_header(rdata)) && !session->id.number.valid) {
-		div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
-	}
-
-	contact_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &contact_name, NULL);
-
-	set_redirecting(session, div_hdr, contact_hdr ?	(pjsip_name_addr*)contact_hdr->uri :
-			(pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
-}
-
-/*!
- * \internal
- * \brief Adds diversion header information to an outbound SIP message
- *
- * \param tdata The outbound message
- * \param data The redirecting data used to fill parts of the diversion header
- */
-static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
-{
-	pjsip_fromto_hdr *hdr;
-	pjsip_name_addr *name_addr;
-	pjsip_sip_uri *uri;
-	pjsip_param *param;
-
-	struct ast_party_id *id = &data->from;
-	pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
-
-	if (!id->number.valid || ast_strlen_zero(id->number.str)) {
-		return;
-	}
-
-	hdr = pjsip_from_hdr_create(tdata->pool);
-	hdr->type = PJSIP_H_OTHER;
-	pj_strdup(tdata->pool, &hdr->name, &diversion_name);
-	hdr->sname.slen = 0;
-
-	name_addr = pjsip_uri_clone(tdata->pool, base);
-	uri = pjsip_uri_get_uri(name_addr->uri);
-
-	pj_strdup2(tdata->pool, &name_addr->display, id->name.str);
-	pj_strdup2(tdata->pool, &uri->user, id->number.str);
-
-	param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
-	param->name = pj_str("reason");
-	param->value = pj_str((char*)reason_code_to_str(&data->reason));
-	pj_list_insert_before(&hdr->other_param, param);
-
-	hdr->uri = (pjsip_uri *) name_addr;
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
-}
-
-static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct ast_party_redirecting *data;
-
-	if (session->channel && session->endpoint->id.send_diversion &&
-	    (data = ast_channel_redirecting(session->channel))->count) {
-		add_diversion_header(tdata, data);
-	}
-}
-
-/*!
- * \internal
- * \brief Adds a diversion header to an outgoing INVITE request if
- *  redirecting information is available.
- *
- * \param session The session on which the INVITE request is to be sent
- * \param tdata The outbound INVITE request
- */
-static void diversion_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	get_redirecting_add_diversion(session, tdata);
-}
-
-/*!
- * \internal
- * \brief Adds a diversion header to an outgoing 3XX response
- *
- * \param session The session on which the INVITE response is to be sent
- * \param tdata The outbound INVITE response
- */
-static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct pjsip_status_line status = tdata->msg->line.status;
-
-	/* add to 302 and 181 */
-	if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
-		get_redirecting_add_diversion(session, tdata);
-	}
-}
-
-static struct ast_sip_session_supplement diversion_supplement = {
-	.method = "INVITE",
-	/* this supplement needs to be called after caller id
-           and after the channel has been created */
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
-	.incoming_request = diversion_incoming_request,
-	.incoming_response = diversion_incoming_response,
-	.outgoing_request = diversion_outgoing_request,
-	.outgoing_response = diversion_outgoing_response,
-	.response_priority = AST_SIP_SESSION_BEFORE_REDIRECTING,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sip_session_register_supplement(&diversion_supplement);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&diversion_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Add Diversion Header Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c
deleted file mode 100644
index b0a6649..0000000
--- a/res/res_pjsip_dtmf_info.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jason Parker <jparker at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-
-static int is_media_type(pjsip_rx_data *rdata, char *subtype)
-{
-	return rdata->msg_info.ctype
-		&& !pj_strcmp2(&rdata->msg_info.ctype->media.type, "application")
-		&& !pj_strcmp2(&rdata->msg_info.ctype->media.subtype, subtype);
-}
-
-static void send_response(struct ast_sip_session *session,
-			  struct pjsip_rx_data *rdata, int code)
-{
-	pjsip_tx_data *tdata;
-	pjsip_dialog *dlg = session->inv_session->dlg;
-
-	if (pjsip_dlg_create_response(dlg, rdata, code,
-				      NULL, &tdata) == PJ_SUCCESS) {
-		struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-		pjsip_dlg_send_response(dlg, tsx, tdata);
-	}
-}
-
-static char get_event(const char *c)
-{
-	unsigned int event;
-
-	if (*c == '!' || *c == '*' || *c == '#' ||
-	    ('A' <= *c && *c <= 'D') ||
-	    ('a' <= *c && *c <= 'd')) {
-		return *c;
-	}
-
-	if ((sscanf(c, "%30u", &event) != 1) || event > 16) {
-		return '\0';
-	}
-
-	if (event < 10) {
-		return *c;
-	}
-
-	switch (event) {
-	case 10: return '*';
-	case 11: return '#';
-	case 16: return '!';
-	}
-
-	return 'A' + (event - 12);
-}
-
-static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	pjsip_msg_body *body = rdata->msg_info.msg->body;
-	char buf[body ? body->len : 0];
-	char *cur = buf;
-	char *line;
-
-	char event = '\0';
-	unsigned int duration = 100;
-
-	char is_dtmf = is_media_type(rdata, "dtmf");
-
-	if (!is_dtmf && !is_media_type(rdata, "dtmf-relay")) {
-		return 0;
-	}
-
-	if (!body || !body->len) {
-		/* need to return 200 OK on empty body */
-		send_response(session, rdata, 200);
-		return 0;
-	}
-
-	body->print_body(body, buf, body->len);
-
-	if (is_dtmf) {
-		/* directly use what is in the message body */
-		event = get_event(cur);
-	} else { /* content type = application/dtmf-relay */
-		while ((line = strsep(&cur, "\r\n"))) {
-			char *c;
-
-			if (!(c = strchr(line, '='))) {
-				continue;
-			}
-
-			*c++ = '\0';
-			c = ast_skip_blanks(c);
-
-			if (!strcasecmp(line, "signal")) {
-				if (!(event = get_event(c))) {
-					break;
-				}
-			} else if (!strcasecmp(line, "duration")) {
-				sscanf(c, "%30u", &duration);
-			}
-		}
-	}
-
-	if (event == '!') {
-		struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } };
-		ast_queue_frame(session->channel, &f);
-	} else if (event != '\0') {
-		struct ast_frame f = { AST_FRAME_DTMF, };
-		f.len = duration;
-		f.subclass.integer = event;
-		ast_queue_frame(session->channel, &f);
-	} else {
-		ast_log(LOG_ERROR, "Invalid DTMF event signal in INFO message.\n");
-	}
-
-	send_response(session, rdata, event ? 200 : 500);
-	return event ? 0 : -1;
-}
-
-static struct ast_sip_session_supplement dtmf_info_supplement = {
-	.method = "INFO",
-	.incoming_request = dtmf_info_incoming_request,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sip_session_register_supplement(&dtmf_info_supplement);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&dtmf_info_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP DTMF INFO Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_endpoint_identifier_anonymous.c b/res/res_pjsip_endpoint_identifier_anonymous.c
deleted file mode 100644
index a7956b5..0000000
--- a/res/res_pjsip_endpoint_identifier_anonymous.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-
-static int get_endpoint_details(pjsip_rx_data *rdata, char *domain, size_t domain_size)
-{
-	pjsip_uri *from = rdata->msg_info.from->uri;
-	pjsip_sip_uri *sip_from;
-	if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) {
-		return -1;
-	}
-	sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
-	ast_copy_pj_str(domain, &sip_from->host, domain_size);
-	return 0;
-}
-
-static int find_transport_in_use(void *obj, void *arg, int flags)
-{
-	struct ast_sip_transport *transport = obj;
-	pjsip_rx_data *rdata = arg;
-
-	if ((transport->state->transport == rdata->tp_info.transport) ||
-		(transport->state->factory && !pj_strcmp(&transport->state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) &&
-			transport->state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) {
-		return CMP_MATCH | CMP_STOP;
-	}
-
-	return 0;
-}
-
-static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata)
-{
-	char domain_name[64], id[AST_UUID_STR_LEN];
-	struct ast_sip_endpoint *endpoint;
-	RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-
-	if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) {
-		return NULL;
-	}
-
-	/* Attempt to find the endpoint given the name and domain provided */
-	snprintf(id, sizeof(id), "anonymous@%s", domain_name);
-	if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-		goto done;
-	}
-
-	/* See if an alias exists for the domain provided */
-	if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
-		snprintf(id, sizeof(id), "anonymous@%s", alias->domain);
-		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-			goto done;
-		}
-	}
-
-	/* See if the transport this came in on has a provided domain */
-	if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) &&
-		(transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) &&
-		!ast_strlen_zero(transport->domain)) {
-		snprintf(id, sizeof(id), "anonymous@%s", transport->domain);
-		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-			goto done;
-		}
-	}
-
-	/* Fall back to no domain */
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous");
-
-done:
-	if (endpoint) {
-		ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint));
-	}
-	return endpoint;
-}
-
-static struct ast_sip_endpoint_identifier anonymous_identifier = {
-	.identify_endpoint = anonymous_identify,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sip_register_endpoint_identifier(&anonymous_identifier);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_endpoint_identifier(&anonymous_identifier);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Anonymous endpoint identifier",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_DEFAULT,
-	       );
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
deleted file mode 100644
index 4bd4f12..0000000
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_cli.h"
-#include "asterisk/module.h"
-#include "asterisk/acl.h"
-#include "asterisk/manager.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_endpoint_identifier_ip" language="en_US">
-		<synopsis>Module that identifies endpoints via source IP address</synopsis>
-		<configFile name="pjsip.conf">
-			<configObject name="identify">
-				<synopsis>Identifies endpoints via source IP address</synopsis>
-				<configOption name="endpoint">
-					<synopsis>Name of Endpoint</synopsis>
-				</configOption>
-				<configOption name="match">
-					<synopsis>IP addresses or networks to match against</synopsis>
-					<description><para>
-						The value is a comma-delimited list of IP addresses. IP addresses may
-						have a subnet mask appended. The subnet mask may be written in either
-						CIDR or dot-decimal notation. Separate the IP address and subnet
-						mask with a slash ('/')
-					</para></description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'identify'.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-/*! \brief Structure for an IP identification matching object */
-struct ip_identify_match {
-	/*! \brief Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! The name of the endpoint */
-		AST_STRING_FIELD(endpoint_name);
-	);
-	/*! \brief Networks or addresses that should match this */
-	struct ast_ha *matches;
-};
-
-/*! \brief Destructor function for a matching object */
-static void ip_identify_destroy(void *obj)
-{
-	struct ip_identify_match *identify = obj;
-
-	ast_string_field_free_memory(identify);
-	ast_free_ha(identify->matches);
-}
-
-/*! \brief Allocator function for a matching object */
-static void *ip_identify_alloc(const char *name)
-{
-	struct ip_identify_match *identify = ast_sorcery_generic_alloc(sizeof(*identify), ip_identify_destroy);
-
-	if (!identify || ast_string_field_init(identify, 256)) {
-		ao2_cleanup(identify);
-		return NULL;
-	}
-
-	return identify;
-}
-
-/*! \brief Comparator function for a matching object */
-static int ip_identify_match_check(void *obj, void *arg, int flags)
-{
-	struct ip_identify_match *identify = obj;
-	struct ast_sockaddr *addr = arg;
-	int sense;
-
-	sense = ast_apply_ha(identify->matches, addr);
-	if (sense != AST_SENSE_ALLOW) {
-		ast_debug(3, "Source address %s matches identify '%s'\n",
-				ast_sockaddr_stringify(addr),
-				ast_sorcery_object_get_id(identify));
-		return CMP_MATCH | CMP_STOP;
-	} else {
-		ast_debug(3, "Source address %s does not match identify '%s'\n",
-				ast_sockaddr_stringify(addr),
-				ast_sorcery_object_get_id(identify));
-		return 0;
-	}
-}
-
-static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)
-{
-	struct ast_sockaddr addr = { { 0, } };
-	RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup);
-	RAII_VAR(struct ip_identify_match *, match, NULL, ao2_cleanup);
-	struct ast_sip_endpoint *endpoint;
-
-	/* If no possibilities exist return early to save some time */
-	if (!(candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
-		!ao2_container_count(candidates)) {
-		ast_debug(3, "No identify sections to match against\n");
-		return NULL;
-	}
-
-	ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
-	ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
-
-	if (!(match = ao2_callback(candidates, 0, ip_identify_match_check, &addr))) {
-		ast_debug(3, "'%s' did not match any identify section rules\n",
-				ast_sockaddr_stringify(&addr));
-		return NULL;
-	}
-
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name);
-	if (endpoint) {
-		ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));
-	} else {
-		ast_log(LOG_WARNING, "Identify section '%s' points to endpoint '%s' but endpoint could not be looked up\n",
-				ast_sorcery_object_get_id(match), match->endpoint_name);
-	}
-
-	return endpoint;
-}
-
-static struct ast_sip_endpoint_identifier ip_identifier = {
-	.identify_endpoint = ip_identify,
-};
-
-/*! \brief Custom handler for match field */
-static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ip_identify_match *identify = obj;
-	char *input_string = ast_strdupa(var->value);
-	char *current_string;
-
-	if (ast_strlen_zero(var->value)) {
-		return 0;
-	}
-
-	while ((current_string = strsep(&input_string, ","))) {
-		struct ast_sockaddr *addrs;
-		int num_addrs = 0, error = 0, i;
-		char *mask = strrchr(current_string, '/');
-
-		if (mask) {
-			identify->matches = ast_append_ha("d", current_string, identify->matches, &error);
-
-			if (!identify->matches || error) {
-				ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
-					current_string, ast_sorcery_object_get_id(obj));
-				return -1;
-			}
-
-			continue;
-		}
-
-		num_addrs = ast_sockaddr_resolve(&addrs, current_string, PARSE_PORT_FORBID, AST_AF_UNSPEC);
-		if (!num_addrs) {
-			ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n",
-				var->value, ast_sorcery_object_get_id(obj));
-			return -1;
-		}
-
-		for (i = 0; i < num_addrs; ++i) {
-			/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
-			identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
-
-			if (!identify->matches || error) {
-				ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
-					ast_sockaddr_stringify_addr(&addrs[i]), ast_sorcery_object_get_id(obj));
-				error = -1;
-				break;
-			}
-		}
-
-		ast_free(addrs);
-
-		if (error) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static int match_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-	const struct ip_identify_match *identify = obj;
-
-	ast_ha_join(identify->matches, &str);
-	*buf = ast_strdup(ast_str_buffer(str));
-	return 0;
-}
-
-static int match_to_var_list(const void *obj, struct ast_variable **fields)
-{
-	char str[MAX_OBJECT_FIELD];
-	const struct ip_identify_match *identify = obj;
-	struct ast_variable *head = NULL;
-	struct ast_ha *ha = identify->matches;
-
-	for (; ha; ha = ha->next) {
-		const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
-		snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
-			addr, ast_sockaddr_stringify_addr(&ha->netmask));
-
-		ast_variable_list_append(&head, ast_variable_new("match", str, ""));
-
-	}
-
-	if (head) {
-		*fields = head;
-	}
-
-	return 0;
-}
-
-static int sip_identify_to_ami(const struct ip_identify_match *identify,
-			       struct ast_str **buf)
-{
-	return ast_sip_sorcery_object_to_ami(identify, buf);
-}
-
-static int find_identify_by_endpoint(void *obj, void *arg, int flags)
-{
-	struct ip_identify_match *identify = obj;
-	const char *endpoint_name = arg;
-
-	return strcmp(identify->endpoint_name, endpoint_name) ? 0 : CMP_MATCH;
-}
-
-static int format_ami_endpoint_identify(const struct ast_sip_endpoint *endpoint,
-					struct ast_sip_ami *ami)
-{
-	RAII_VAR(struct ao2_container *, identifies, NULL, ao2_cleanup);
-	RAII_VAR(struct ip_identify_match *, identify, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, buf, NULL, ast_free);
-
-	identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!identifies) {
-		return -1;
-	}
-
-	identify = ao2_callback(identifies, 0, find_identify_by_endpoint,
-		(void *) ast_sorcery_object_get_id(endpoint));
-	if (!identify) {
-		return 1;
-	}
-
-	if (!(buf = ast_sip_create_ami_event("IdentifyDetail", ami))) {
-		return -1;
-	}
-
-	if (sip_identify_to_ami(identify, &buf)) {
-		return -1;
-	}
-
-	ast_str_append(&buf, 0, "EndpointName: %s\r\n",
-		ast_sorcery_object_get_id(endpoint));
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	ami->count++;
-
-	return 0;
-}
-
-struct ast_sip_endpoint_formatter endpoint_identify_formatter = {
-	.format_ami = format_ami_endpoint_identify
-};
-
-static int cli_populate_container(void *obj, void *arg, int flags)
-{
-	ao2_link(arg, obj);
-
-	return 0;
-}
-
-static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
-{
-	const struct ast_sip_endpoint *endpoint = container;
-	struct ao2_container *identifies;
-
-	struct ast_variable fields = {
-		.name = "endpoint",
-		.value = ast_sorcery_object_get_id(endpoint),
-		.next = NULL,
-	};
-
-	identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
-		AST_RETRIEVE_FLAG_MULTIPLE, &fields);
-	if (!identifies) {
-		return -1;
-	}
-
-	ao2_callback(identifies, OBJ_NODATA, callback, args);
-	ao2_cleanup(identifies);
-
-	return 0;
-}
-
-static int cli_endpoint_gather_identifies(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ao2_container *container = arg;
-
-	cli_iterator(endpoint, cli_populate_container, container);
-
-	return 0;
-}
-
-static struct ao2_container *cli_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, s_parent_container, NULL, ao2_cleanup);
-	struct ao2_container *child_container;
-
-	parent_container =  ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!parent_container) {
-		return NULL;
-	}
-
-	s_parent_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!s_parent_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_parent_container, parent_container, 0)) {
-		return NULL;
-	}
-
-	child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!child_container) {
-		return NULL;
-	}
-
-	ao2_callback(s_parent_container, OBJ_NODATA, cli_endpoint_gather_identifies, child_container);
-
-	return child_container;
-}
-
-static void *cli_retrieve_by_id(const char *id)
-{
-	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "identify", id);
-}
-
-static int cli_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-	int indent = CLI_INDENT_TO_SPACES(context->indent_level);
-	int filler = CLI_MAX_WIDTH - indent - 22;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		"%*s:  <Identify/Endpoint%*.*s>\n",
-		indent, "Identify", filler, filler, CLI_HEADER_FILLER);
-
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-		filler = CLI_LAST_TABSTOP - indent - 24;
-
-		ast_str_append(&context->output_buffer, 0,
-			"%*s:  <ip/cidr%*.*s>\n",
-			indent, "Match", filler, filler, CLI_HEADER_FILLER);
-
-		context->indent_level--;
-	}
-
-	return 0;
-}
-
-static int cli_print_body(void *obj, void *arg, int flags)
-{
-	RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
-	struct ip_identify_match *ident = obj;
-	struct ast_sip_cli_context *context = arg;
-	struct ast_ha *match;
-	int indent;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0, "%*s:  %s/%s\n",
-		CLI_INDENT_TO_SPACES(context->indent_level), "Identify",
-		ast_sorcery_object_get_id(ident), ident->endpoint_name);
-
-	if (context->recurse) {
-		context->indent_level++;
-		indent = CLI_INDENT_TO_SPACES(context->indent_level);
-
-		for (match = ident->matches; match; match = match->next) {
-			const char *addr = ast_sockaddr_stringify_addr(&match->addr);
-
-			ast_str_append(&context->output_buffer, 0, "%*s: %s%s/%d\n",
-				indent,
-				"Match",
-				match->sense == AST_SENSE_ALLOW ? "!" : "",
-				addr, ast_sockaddr_cidr_bits(&match->netmask));
-		}
-
-		context->indent_level--;
-
-		if (context->indent_level == 0) {
-			ast_str_append(&context->output_buffer, 0, "\n");
-		}
-	}
-
-	if (context->show_details
-		|| (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(ident, context, 0);
-	}
-
-	return 0;
-}
-
-/*
- * A function pointer to callback needs to be within the
- * module in order to avoid problems with an undefined
- * symbol when the module is loaded.
- */
-static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd,
-	struct ast_cli_args *a)
-{
-	return ast_sip_cli_traverse_objects(e, cmd, a);
-}
-
-static struct ast_cli_entry cli_identify[] = {
-AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Identifies",
-	.command = "pjsip list identifies",
-	.usage = "Usage: pjsip list identifies\n"
-	"       List the configured PJSIP Identifies\n"),
-AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identifies",
-	.command = "pjsip show identifies",
-	.usage = "Usage: pjsip show identifies\n"
-	"       Show the configured PJSIP Identifies\n"),
-AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identify",
-	.command = "pjsip show identify",
-	.usage = "Usage: pjsip show identify <id>\n"
-	"       Show the configured PJSIP Identify\n"),
-};
-
-static struct ast_sip_cli_formatter_entry *cli_formatter;
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip");
-	ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify");
-
-	if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, NULL)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0);
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
-
-	ast_sip_register_endpoint_identifier(&ip_identifier);
-	ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
-
-	cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!cli_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	cli_formatter->name = "identify";
-	cli_formatter->print_header = cli_print_header;
-	cli_formatter->print_body = cli_print_body;
-	cli_formatter->get_container = cli_get_container;
-	cli_formatter->iterate = cli_iterator;
-	cli_formatter->get_id = ast_sorcery_object_get_id;
-	cli_formatter->retrieve_by_id = cli_retrieve_by_id;
-
-	ast_sip_register_cli_formatter(cli_formatter);
-	ast_cli_register_multiple(cli_identify, ARRAY_LEN(cli_identify));
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_cli_unregister_multiple(cli_identify, ARRAY_LEN(cli_identify));
-	ast_sip_unregister_cli_formatter(cli_formatter);
-	ast_sip_unregister_endpoint_formatter(&endpoint_identify_formatter);
-	ast_sip_unregister_endpoint_identifier(&ip_identifier);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint identifier",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c
deleted file mode 100644
index beae1cd..0000000
--- a/res/res_pjsip_endpoint_identifier_user.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-
-static int get_endpoint_details(pjsip_rx_data *rdata, char *endpoint, size_t endpoint_size, char *domain, size_t domain_size)
-{
-	pjsip_uri *from = rdata->msg_info.from->uri;
-	pjsip_sip_uri *sip_from;
-	if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) {
-		return -1;
-	}
-	sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
-	ast_copy_pj_str(endpoint, &sip_from->user, endpoint_size);
-	ast_copy_pj_str(domain, &sip_from->host, domain_size);
-	return 0;
-}
-
-static int find_transport_in_use(void *obj, void *arg, int flags)
-{
-	struct ast_sip_transport *transport = obj;
-	pjsip_rx_data *rdata = arg;
-
-	if ((transport->state->transport == rdata->tp_info.transport) ||
-		(transport->state->factory && !pj_strcmp(&transport->state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) &&
-			transport->state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) {
-		return CMP_MATCH | CMP_STOP;
-	}
-
-	return 0;
-}
-
-static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata)
-{
-	char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN];
-	struct ast_sip_endpoint *endpoint;
-	RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-
-	if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) {
-		return NULL;
-	}
-
-	/* Attempt to find the endpoint given the name and domain provided */
-	snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name);
-	if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-		goto done;
-	}
-
-	/* See if an alias exists for the domain provided */
-	if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
-		snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain);
-		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-			goto done;
-		}
-	}
-
-	/* See if the transport this came in on has a provided domain */
-	if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) &&
-		(transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) &&
-		!ast_strlen_zero(transport->domain)) {
-		snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain);
-		if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
-			goto done;
-		}
-	}
-
-	/* Fall back to no domain */
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
-
-done:
-	if (endpoint) {
-		if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) {
-			ao2_ref(endpoint, -1);
-			return NULL;
-		}
-		ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));
-	} else {
-		ast_debug(3, "Could not identify endpoint by username '%s'\n", endpoint_name);
-	}
-	return endpoint;
-}
-
-static struct ast_sip_endpoint_identifier username_identifier = {
-	.identify_endpoint = username_identify,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sip_register_endpoint_identifier(&username_identifier);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_endpoint_identifier(&username_identifier);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP username endpoint identifier",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c
deleted file mode 100644
index 332f45b..0000000
--- a/res/res_pjsip_exten_state.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/app.h"
-
-#define BODY_SIZE 1024
-#define EVENT_TYPE_SIZE 50
-
-/*!
- * \brief A subscription for extension state
- *
- * This structure acts as the owner for the underlying SIP subscription. It
- * also keeps a pointer to an associated "provider" so when a state changes
- * a notify data creator is quickly accessible.
- */
-struct exten_state_subscription {
-	/*! Watcher id when registering for extension state changes */
-	int id;
-	/*! The SIP subscription */
-	struct ast_sip_subscription *sip_sub;
-	/*! Context in which subscription looks for updates */
-	char context[AST_MAX_CONTEXT];
-	/*! Extension within the context to receive updates from */
-	char exten[AST_MAX_EXTENSION];
-	/*! The subscription's user agent */
-	char *user_agent;
-	/*! The last known extension state */
-	enum ast_extension_states last_exten_state;
-	/*! The last known presence state */
-	enum ast_presence_state last_presence_state;
-};
-
-#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
-#define DEFAULT_DIALOG_BODY "application/dialog-info+xml"
-
-static void subscription_shutdown(struct ast_sip_subscription *sub);
-static int new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource);
-static int subscription_established(struct ast_sip_subscription *sub);
-static void *get_notify_data(struct ast_sip_subscription *sub);
-static void to_ami(struct ast_sip_subscription *sub,
-		   struct ast_str **buf);
-
-struct ast_sip_notifier presence_notifier = {
-	.default_accept = DEFAULT_PRESENCE_BODY,
-	.new_subscribe = new_subscribe,
-	.subscription_established = subscription_established,
-	.get_notify_data = get_notify_data,
-};
-
-struct ast_sip_notifier dialog_notifier = {
-	.default_accept = DEFAULT_DIALOG_BODY,
-	.new_subscribe = new_subscribe,
-	.subscription_established = subscription_established,
-	.get_notify_data = get_notify_data,
-};
-
-struct ast_sip_subscription_handler presence_handler = {
-	.event_name = "presence",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.accept = { DEFAULT_PRESENCE_BODY, },
-	.subscription_shutdown = subscription_shutdown,
-	.to_ami = to_ami,
-	.notifier = &presence_notifier,
-};
-
-struct ast_sip_subscription_handler dialog_handler = {
-	.event_name = "dialog",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.accept = { DEFAULT_DIALOG_BODY, },
-	.subscription_shutdown = subscription_shutdown,
-	.to_ami = to_ami,
-	.notifier = &dialog_notifier,
-};
-
-static void exten_state_subscription_destructor(void *obj)
-{
-	struct exten_state_subscription *sub = obj;
-
-	ast_free(sub->user_agent);
-	ao2_cleanup(sub->sip_sub);
-}
-
-static char *get_user_agent(const struct ast_sip_subscription *sip_sub)
-{
-	size_t size;
-	char *user_agent = NULL;
-	pjsip_user_agent_hdr *user_agent_hdr = ast_sip_subscription_get_header(
-			sip_sub, "User-Agent");
-
-	if (!user_agent_hdr) {
-		return NULL;
-	}
-
-	size = pj_strlen(&user_agent_hdr->hvalue) + 1;
-	user_agent = ast_malloc(size);
-	ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, size);
-	return ast_str_to_lower(user_agent);
-}
-
-/*!
- * \internal
- * \brief Initialize the last extension state to something outside
- * its usual states.
- */
-#define INITIAL_LAST_EXTEN_STATE -3
-
-/*!
- * \internal
- * \brief Allocates an exten_state_subscription object.
- *
- * Creates the underlying SIP subscription for the given request. First makes
- * sure that there are registered handler and provider objects available.
- */
-static struct exten_state_subscription *exten_state_subscription_alloc(
-		struct ast_sip_subscription *sip_sub, struct ast_sip_endpoint *endpoint)
-{
-	struct exten_state_subscription * exten_state_sub;
-
-	exten_state_sub = ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor);
-	if (!exten_state_sub) {
-		return NULL;
-	}
-
-	exten_state_sub->sip_sub = ao2_bump(sip_sub);
-	exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
-	exten_state_sub->last_presence_state = AST_PRESENCE_NOT_SET;
-	exten_state_sub->user_agent = get_user_agent(sip_sub);
-	return exten_state_sub;
-}
-
-struct notify_task_data {
-	struct ast_sip_exten_state_data exten_state_data;
-	struct exten_state_subscription *exten_state_sub;
-	int terminate;
-};
-
-static void notify_task_data_destructor(void *obj)
-{
-	struct notify_task_data *task_data = obj;
-
-	ao2_ref(task_data->exten_state_sub, -1);
-	ao2_cleanup(task_data->exten_state_data.device_state_info);
-	ast_free(task_data->exten_state_data.presence_subtype);
-	ast_free(task_data->exten_state_data.presence_message);
-	ast_free(task_data->exten_state_data.user_agent);
-}
-
-static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
-						       struct ast_state_cb_info *info)
-{
-	struct notify_task_data *task_data =
-		ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
-
-	if (!task_data) {
-		ast_log(LOG_WARNING, "Unable to create notify task data\n");
-		return NULL;
-	}
-
-	task_data->exten_state_sub = exten_state_sub;
-	task_data->exten_state_sub->last_exten_state = info->exten_state;
-	task_data->exten_state_sub->last_presence_state = info->presence_state;
-	ao2_ref(task_data->exten_state_sub, +1);
-
-	task_data->exten_state_data.exten = exten_state_sub->exten;
-	task_data->exten_state_data.exten_state = info->exten_state;
-	task_data->exten_state_data.presence_state = info->presence_state;
-	task_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype);
-	task_data->exten_state_data.presence_message = ast_strdup(info->presence_message);
-	task_data->exten_state_data.user_agent = ast_strdup(exten_state_sub->user_agent);
-	task_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info);
-	task_data->exten_state_data.sub = exten_state_sub->sip_sub;
-
-	ast_sip_subscription_get_local_uri(exten_state_sub->sip_sub,
-			task_data->exten_state_data.local, sizeof(task_data->exten_state_data.local));
-	ast_sip_subscription_get_remote_uri(exten_state_sub->sip_sub,
-			task_data->exten_state_data.remote, sizeof(task_data->exten_state_data.remote));
-
-	if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
-	    (info->exten_state == AST_EXTENSION_REMOVED)) {
-		ast_log(LOG_WARNING, "Watcher for hint %s %s\n", exten, info->exten_state
-			 == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
-		task_data->terminate = 1;
-	}
-
-	return task_data;
-}
-
-static int notify_task(void *obj)
-{
-	RAII_VAR(struct notify_task_data *, task_data, obj, ao2_cleanup);
-	struct ast_sip_body_data data = {
-		.body_type = AST_SIP_EXTEN_STATE_DATA,
-		.body_data = &task_data->exten_state_data,
-	};
-
-	/* Pool allocation has to happen here so that we allocate within a PJLIB thread */
-	task_data->exten_state_data.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
-			"exten_state", 1024, 1024);
-	if (!task_data->exten_state_data.pool) {
-		return -1;
-	}
-
-	task_data->exten_state_data.sub = task_data->exten_state_sub->sip_sub;
-
-	ast_sip_subscription_notify(task_data->exten_state_sub->sip_sub, &data,
-			task_data->terminate);
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(),
-			task_data->exten_state_data.pool);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Callback for exten/device state changes.
- *
- * Upon state change, send the appropriate notification to the subscriber.
- */
-static int state_changed(char *context, char *exten,
-			 struct ast_state_cb_info *info, void *data)
-{
-	struct notify_task_data *task_data;
-	struct exten_state_subscription *exten_state_sub = data;
-
-	if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
-		return -1;
-	}
-
-	/* safe to push this async since we copy the data from info and
-	   add a ref for the device state info */
-	if (ast_sip_push_task(ast_sip_subscription_get_serializer(task_data->exten_state_sub->sip_sub),
-			      notify_task, task_data)) {
-		ao2_cleanup(task_data);
-		return -1;
-	}
-	return 0;
-}
-
-static void state_changed_destroy(int id, void *data)
-{
-	struct exten_state_subscription *exten_state_sub = data;
-	ao2_cleanup(exten_state_sub);
-}
-
-static struct ast_datastore_info ds_info = { };
-static const char ds_name[] = "exten state datastore";
-
-/*!
- * \internal
- * \brief Add a datastore for exten exten_state_subscription.
- *
- * Adds the exten_state_subscription wrapper object to a datastore so it can be retrieved
- * later based upon its association with the ast_sip_subscription.
- */
-static int add_datastore(struct exten_state_subscription *exten_state_sub)
-{
-	RAII_VAR(struct ast_datastore *, datastore,
-		 ast_sip_subscription_alloc_datastore(&ds_info, ds_name), ao2_cleanup);
-
-	if (!datastore) {
-		return -1;
-	}
-
-	datastore->data = exten_state_sub;
-	ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
-	ao2_ref(exten_state_sub, +1);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Get the exten_state_subscription object associated with the given
- * ast_sip_subscription in the datastore.
- */
-static struct exten_state_subscription *get_exten_state_sub(
-	struct ast_sip_subscription *sub)
-{
-	RAII_VAR(struct ast_datastore *, datastore,
-		 ast_sip_subscription_get_datastore(sub, ds_name), ao2_cleanup);
-
-	return datastore ? datastore->data : NULL;
-}
-
-static void subscription_shutdown(struct ast_sip_subscription *sub)
-{
-	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	ast_extension_state_del(exten_state_sub->id, state_changed);
-	ast_sip_subscription_remove_datastore(exten_state_sub->sip_sub, ds_name);
-	/* remove data store reference */
-	ao2_cleanup(exten_state_sub);
-}
-
-static int new_subscribe(struct ast_sip_endpoint *endpoint,
-		const char *resource)
-{
-	if (!ast_exists_extension(NULL, endpoint->context, resource, PRIORITY_HINT, NULL)) {
-		ast_log(LOG_WARNING, "Extension %s does not exist or has no associated hint\n", resource);
-		return 404;
-	}
-
-	return 200;
-}
-
-static int subscription_established(struct ast_sip_subscription *sip_sub)
-{
-	struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sip_sub);
-	const char *resource = ast_sip_subscription_get_resource_name(sip_sub);
-	struct exten_state_subscription *exten_state_sub;
-
-	if (!(exten_state_sub = exten_state_subscription_alloc(sip_sub, endpoint))) {
-		ao2_cleanup(endpoint);
-		return -1;
-	}
-
-	ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
-	ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten));
-
-	if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
-		     exten_state_sub->context, exten_state_sub->exten,
-		     state_changed, state_changed_destroy, exten_state_sub)) < 0) {
-		ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
-			ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
-			exten_state_sub->context);
-		ao2_cleanup(endpoint);
-		ao2_cleanup(exten_state_sub);
-		return -1;
-	}
-
-	/* Go ahead and cleanup the endpoint since we don't need it anymore */
-	ao2_cleanup(endpoint);
-
-	/* bump the ref since ast_extension_state_add holds a reference */
-	ao2_ref(exten_state_sub, +1);
-
-	if (add_datastore(exten_state_sub)) {
-		ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
-		ao2_cleanup(exten_state_sub);
-		return -1;
-	}
-
-	ao2_cleanup(exten_state_sub);
-	return 0;
-}
-
-static void exten_state_data_destructor(void *obj)
-{
-	struct ast_sip_exten_state_data *exten_state_data = obj;
-
-	ao2_cleanup(exten_state_data->device_state_info);
-	ast_free(exten_state_data->presence_subtype);
-	ast_free(exten_state_data->presence_message);
-	if (exten_state_data->pool) {
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), exten_state_data->pool);
-	}
-}
-
-static struct ast_sip_exten_state_data *exten_state_data_alloc(struct ast_sip_subscription *sip_sub,
-		struct exten_state_subscription *exten_state_sub)
-{
-	struct ast_sip_exten_state_data *exten_state_data;
-	char *subtype = NULL;
-	char *message = NULL;
-
-	exten_state_data = ao2_alloc(sizeof(*exten_state_data), exten_state_data_destructor);
-	if (!exten_state_data) {
-		return NULL;
-	}
-
-	exten_state_data->exten = exten_state_sub->exten;
-	if ((exten_state_data->presence_state = ast_hint_presence_state(NULL, exten_state_sub->context,
-			exten_state_sub->exten, &subtype, &message)) == -1) {
-		ao2_cleanup(exten_state_data);
-		return NULL;
-	}
-	exten_state_data->presence_subtype = subtype;
-	exten_state_data->presence_message = message;
-	exten_state_data->user_agent = exten_state_sub->user_agent;
-	ast_sip_subscription_get_local_uri(sip_sub, exten_state_data->local,
-			sizeof(exten_state_data->local));
-	ast_sip_subscription_get_remote_uri(sip_sub, exten_state_data->remote,
-			sizeof(exten_state_data->remote));
-	exten_state_data->sub = sip_sub;
-
-	exten_state_data->exten_state = ast_extension_state_extended(
-			NULL, exten_state_sub->context, exten_state_sub->exten,
-			&exten_state_data->device_state_info);
-	if (exten_state_data->exten_state < 0) {
-		ao2_cleanup(exten_state_data);
-		return NULL;
-	}
-
-	exten_state_data->pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
-			"exten_state", 1024, 1024);
-	if (!exten_state_data->pool) {
-		ao2_cleanup(exten_state_data);
-		return NULL;
-	}
-
-	return exten_state_data;
-}
-
-static void *get_notify_data(struct ast_sip_subscription *sub)
-{
-	struct exten_state_subscription *exten_state_sub;
-
-	exten_state_sub = get_exten_state_sub(sub);
-	if (!exten_state_sub) {
-		return NULL;
-	}
-
-	return exten_state_data_alloc(sub, exten_state_sub);
-}
-
-static void to_ami(struct ast_sip_subscription *sub,
-		   struct ast_str **buf)
-{
-	struct exten_state_subscription *exten_state_sub =
-		get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
-		       "Extension: %s\r\nExtensionStates: %s\r\n",
-		       exten_state_sub->exten, ast_extension_state2str(
-			       exten_state_sub->last_exten_state));
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (ast_sip_register_subscription_handler(&presence_handler)) {
-		ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
-			presence_handler.event_name);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_register_subscription_handler(&dialog_handler)) {
-		ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
-			dialog_handler.event_name);
-		ast_sip_unregister_subscription_handler(&presence_handler);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_subscription_handler(&dialog_handler);
-	ast_sip_unregister_subscription_handler(&presence_handler);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State Notifications",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_exten_state.exports.in b/res/res_pjsip_exten_state.exports.in
deleted file mode 100644
index 0cce6f6..0000000
--- a/res/res_pjsip_exten_state.exports.in
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_sip_register_exten_state_provider;
-		LINKER_SYMBOL_PREFIXast_sip_unregister_exten_state_provider;
-	local:
-		*;
-};
diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c
deleted file mode 100644
index 4ab3fb1..0000000
--- a/res/res_pjsip_header_funcs.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/utils.h"
-
-/*** DOCUMENTATION
-	<function name="PJSIP_HEADER" language="en_US">
-		<synopsis>
-			Gets, adds, updates or removes the specified SIP header from a PJSIP session.
-		</synopsis>
-		<syntax>
-			<parameter name="action" required="true">
-				<enumlist>
-					<enum name="read"><para>Returns instance <replaceable>number</replaceable>
-					of header <replaceable>name</replaceable>.</para></enum>
-
-					<enum name="add"><para>Adds a new header <replaceable>name</replaceable>
-					to this session.</para></enum>
-
-					<enum name="update"><para>Updates instance <replaceable>number</replaceable>
-					of header <replaceable>name</replaceable> to a new value.
-					The header must already exist.</para></enum>
-
-					<enum name="remove"><para>Removes all instances of previously added headers
-					whose names match <replaceable>name</replaceable>. A <literal>*</literal>
-					may be appended to <replaceable>name</replaceable> to remove all headers
-					<emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
-					<replaceable>name</replaceable> may be set to a single <literal>*</literal>
-					to clear <emphasis>all</emphasis> previously added headers. In all cases,
-					the number of headers actually removed is returned.</para></enum>
-				</enumlist>
-			</parameter>
-
-			<parameter name="name" required="true"><para>The name of the header.</para></parameter>
-
-			<parameter name="number" required="false">
-				<para>If there's more than 1 header with the same name, this specifies which header
-				to read or update.  If not specified, defaults to <literal>1</literal> meaning
-				the first matching header.  Not valid for <literal>add</literal> or
-				<literal>remove</literal>.</para>
-			</parameter>
-
-		</syntax>
-		<description>
-			<para>Examples:</para>
-			<para>;</para>
-			<para>; Set 'somevar' to the value of the 'From' header.</para>
-			<para>exten => 1,1,Set(somevar=${PJSIP_HEADER(read,From)})</para>
-			<para>;</para>
-			<para>; Set 'via2' to the value of the 2nd 'Via' header.</para>
-			<para>exten => 1,1,Set(via2=${PJSIP_HEADER(read,Via,2)})</para>
-			<para>;</para>
-			<para>; Add an 'X-Myheader' header with the value of 'myvalue'.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>
-			<para>;</para>
-			<para>; Add an 'X-Myheader' header with an empty value.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=)</para>
-			<para>;</para>
-			<para>; Update the value of the header named 'X-Myheader' to 'newvalue'.</para>
-			<para>; 'X-Myheader' must already exist or the call will fail.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(update,X-MyHeader)=newvalue)</para>
-			<para>;</para>
-			<para>; Remove all headers whose names exactly match 'X-MyHeader'.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)</para>
-			<para>;</para>
-			<para>; Remove all headers that begin with 'X-My'.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(remove,X-My*)=)</para>
-			<para>;</para>
-			<para>; Remove all previously added headers.</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(remove,*)=)</para>
-			<para>;</para>
-
-			<note><para>The <literal>remove</literal> action can be called by reading
-			<emphasis>or</emphasis> writing PJSIP_HEADER.</para>
-			<para>;</para>
-			<para>; Display the number of headers removed</para>
-			<para>exten => 1,1,Verbose( Removed ${PJSIP_HEADER(remove,X-MyHeader)} headers)</para>
-			<para>;</para>
-			<para>; Set a variable to the number of headers removed</para>
-			<para>exten => 1,1,Set(count=${PJSIP_HEADER(remove,X-MyHeader)})</para>
-			<para>;</para>
-			<para>; Just remove them ignoring any count</para>
-			<para>exten => 1,1,Set(=${PJSIP_HEADER(remove,X-MyHeader)})</para>
-			<para>exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)</para>
-			<para>;</para>
-			</note>
-
-			<note><para>If you call PJSIP_HEADER in a normal dialplan context you'll be
-			operating on the <emphasis>caller's (incoming)</emphasis> channel which
-			may not be what you want.  To operate on the <emphasis>callee's (outgoing)</emphasis>
-			channel call PJSIP_HEADER in a pre-dial handler. </para>
-			<para>Example:</para>
-			<para>;</para>
-			<para>[handler]</para>
-			<para>exten => addheader,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>
-			<para>exten => addheader,2,Set(PJSIP_HEADER(add,X-MyHeader2)=myvalue2)</para>
-			<para>;</para>
-			<para>[somecontext]</para>
-			<para>exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))</para>
-			<para>;</para>
-			</note>
-		</description>
-	</function>
- ***/
-
-/*! \brief Linked list for accumulating headers */
-struct hdr_list_entry {
-	pjsip_hdr *hdr;
-	AST_LIST_ENTRY(hdr_list_entry) nextptr;
-};
-AST_LIST_HEAD(hdr_list, hdr_list_entry);
-
-/*! \brief Destructor for hdr_list */
-static void hdr_list_destroy(void *obj)
-{
-	AST_LIST_HEAD_DESTROY((struct hdr_list *) obj);
-}
-
-/*! \brief Datastore for saving headers */
-static const struct ast_datastore_info header_datastore = {
-	.type = "header_datastore",
-	.destroy = hdr_list_destroy,
-};
-
-/*! \brief Data structure used for ast_sip_push_task_synchronous  */
-struct header_data {
-	struct ast_sip_channel_pvt *channel;
-	char *header_name;
-	const char *header_value;
-	char *buf;
-	int header_number;
-	size_t len;
-};
-
-/*!
- * \internal
- * \brief Insert the header pointers into the linked list.
- *
- * For each header in the message, allocate a list entry,
- * clone the header, then insert the entry.
- */
-static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
-{
-	pjsip_hdr *hdr = msg->hdr.next;
-	struct hdr_list_entry *le;
-
-	while (hdr && hdr != &msg->hdr) {
-		le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
-		le->hdr = pjsip_hdr_clone(pool, hdr);
-		AST_LIST_INSERT_TAIL(list, le, nextptr);
-		hdr = hdr->next;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Session supplement callback on an incoming INVITE request
- *
- * Retrieve the header_datastore from the session or create one if it doesn't exist.
- * Create and initialize the list if needed.
- * Insert the headers.
- */
-static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)
-{
-	pj_pool_t *pool = session->inv_session->dlg->pool;
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
-
-	if (!datastore) {
-		if (!(datastore =
-			  ast_sip_session_alloc_datastore(&header_datastore, header_datastore.type))
-			||
-			!(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
-			ast_sip_session_add_datastore(session, datastore)) {
-			ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
-			return 0;
-		}
-		AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data);
-	}
-	insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Search list for nth occurrence of specific header.
- */
-static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,
-							  int header_number)
-{
-	struct hdr_list_entry *le;
-	pjsip_hdr *hdr = NULL;
-	int i = 1;
-
-	if (!list || ast_strlen_zero(header_name) || header_number < 1) {
-		return NULL;
-	}
-
-	AST_LIST_TRAVERSE(list, le, nextptr) {
-		if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {
-			hdr = le->hdr;
-			break;
-		}
-	}
-
-	return hdr;
-}
-
-
-/*!
- * \internal
- * \brief Implements PJSIP_HEADER 'read' by searching the for the requested header.
- *
- * Retrieve the header_datastore.
- * Search for the nth matching header.
- * Validate the pjsip_hdr found.
- * Parse pjsip_hdr into a name and value.
- * Return the value.
- */
-static int read_header(void *obj)
-{
-	struct header_data *data = obj;
-	pjsip_hdr *hdr = NULL;
-	char *pj_hdr_string;
-	size_t pj_hdr_string_len;
-	char *p;
-	size_t plen;
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
-			 ao2_cleanup);
-
-	if (!datastore || !datastore->data) {
-		ast_debug(1, "There was no datastore from which to read headers.\n");
-		return -1;
-	}
-
-	hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
-					  data->header_number);
-
-	if (!hdr) {
-		ast_debug(1, "There was no header named %s.\n", data->header_name);
-		return -1;
-	}
-
-	pj_hdr_string = ast_alloca(data->len);
-	pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len);
-	pj_hdr_string[pj_hdr_string_len] = '\0';
-
-	p = strchr(pj_hdr_string, ':');
-	if (!p) {
-		ast_log(AST_LOG_ERROR,
-				"A malformed header was returned from pjsip_hdr_print_on.\n");
-		return -1;
-	}
-
-	++p;
-	p = ast_strip(p);
-	plen = strlen(p);
-	if (plen + 1 > data->len) {
-		ast_log(AST_LOG_ERROR,
-				"Buffer isn't big enough to hold header value.  %zu > %zu\n", plen + 1,
-				data->len);
-		return -1;
-	}
-
-	ast_copy_string(data->buf, p, data->len);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into thge list.
- *
- * Retrieve the header_datastore from the session or create one if it doesn't exist.
- * Create and initialize the list if needed.
- * Create the pj_strs for name and value.
- * Create pjsip_msg and hdr_list_entry.
- * Add the entry to the list.
- */
-static int add_header(void *obj)
-{
-	struct header_data *data = obj;
-	struct ast_sip_session *session = data->channel->session;
-	pj_pool_t *pool = session->inv_session->dlg->pool;
-	pj_str_t pj_header_name;
-	pj_str_t pj_header_value;
-	struct hdr_list_entry *le;
-	struct hdr_list *list;
-
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
-
-	if (!datastore) {
-		if (!(datastore = ast_sip_session_alloc_datastore(&header_datastore,
-														  header_datastore.type))
-			|| !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list)))
-			|| ast_sip_session_add_datastore(session, datastore)) {
-			ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
-			return -1;
-		}
-		AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data);
-	}
-
-	ast_debug(1, "Adding header %s with value %s\n", data->header_name,
-			  data->header_value);
-
-	pj_cstr(&pj_header_name, data->header_name);
-	pj_cstr(&pj_header_value, data->header_value);
-	le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
-	le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
-															&pj_header_value);
-	list = datastore->data;
-
-	AST_LIST_INSERT_TAIL(list, le, nextptr);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.
- *
- * Retrieve the header_datastore from the session or create one if it doesn't exist.
- * Create and initialize the list if needed.
- * Create the pj_strs for name and value.
- * Create pjsip_msg and hdr_list_entry.
- * Add the entry to the list.
- */
-static int update_header(void *obj)
-{
-	struct header_data *data = obj;
-	pjsip_hdr *hdr = NULL;
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
-			 ao2_cleanup);
-
-	if (!datastore || !datastore->data) {
-		ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
-		return -1;
-	}
-
-	hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
-					  data->header_number);
-
-	if (!hdr) {
-		ast_log(AST_LOG_ERROR, "There was no header named %s.\n", data->header_name);
-		return -1;
-	}
-
-	pj_strcpy2(&((pjsip_generic_string_hdr *) hdr)->hvalue, data->header_value);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.
- *
- * Retrieve the header_datastore from the session.  Fail if it doesn't exist.
- * If the header_name is exactly '*', the entire list is simply destroyed.
- * Otherwise search the list for the matching header name which may be a partial name.
- */
-static int remove_header(void *obj)
-{
-	struct header_data *data = obj;
-	size_t len = strlen(data->header_name);
-	struct hdr_list *list;
-	struct hdr_list_entry *le;
-	int removed_count = 0;
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
-			 ao2_cleanup);
-
-	if (!datastore || !datastore->data) {
-		ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
-		return -1;
-	}
-
-	list = datastore->data;
-	AST_LIST_TRAVERSE_SAFE_BEGIN(list, le, nextptr) {
-		if (data->header_name[len - 1] == '*') {
-			if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0) {
-				AST_LIST_REMOVE_CURRENT(nextptr);
-				removed_count++;
-			}
-		} else {
-			if (pj_stricmp2(&le->hdr->name, data->header_name) == 0) {
-				AST_LIST_REMOVE_CURRENT(nextptr);
-				removed_count++;
-			}
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	if (data->buf && data->len) {
-		snprintf(data->buf, data->len, "%d", removed_count);
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Implements function 'read' callback.
- *
- * Valid actions are 'read' and 'remove'.
- */
-static int func_read_header(struct ast_channel *chan, const char *function, char *data,
-							char *buf, size_t len)
-{
-	struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
-	struct header_data header_data;
-	int number;
-	AST_DECLARE_APP_ARGS(args,
-						 AST_APP_ARG(action);
-						 AST_APP_ARG(header_name); AST_APP_ARG(header_number););
-	AST_STANDARD_APP_ARGS(args, data);
-
-	if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
-		ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.action)) {
-		ast_log(AST_LOG_ERROR, "This function requires an action.\n");
-		return -1;
-	}
-	if (ast_strlen_zero(args.header_name)) {
-		ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
-		return -1;
-	}
-	if (!args.header_number) {
-		number = 1;
-	} else {
-		sscanf(args.header_number, "%30d", &number);
-		if (number < 1) {
-			number = 1;
-		}
-	}
-
-	header_data.channel = channel;
-	header_data.header_name = args.header_name;
-	header_data.header_number = number;
-	header_data.header_value = NULL;
-	header_data.buf = buf;
-	header_data.len = len;
-
-	if (stricmp(args.action, "read") == 0) {
-		return ast_sip_push_task_synchronous(channel->session->serializer, read_header,
-											 &header_data);
-	} else if (stricmp(args.action, "remove") == 0) {
-		return ast_sip_push_task_synchronous(channel->session->serializer, remove_header,
-											 &header_data);
-	} else {
-		ast_log(AST_LOG_ERROR,
-				"Unknown action \'%s\' is not valid,  Must be \'read\' or \'remove\'.\n",
-				args.action);
-		return -1;
-	}
-}
-
-/*!
- * \brief Implements function 'write' callback.
- *
- * Valid actions are 'add', 'update' and 'remove'.
- */
-static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,
-							 const char *value)
-{
-	struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
-	struct header_data header_data;
-	int header_number;
-	AST_DECLARE_APP_ARGS(args,
-						 AST_APP_ARG(action);
-						 AST_APP_ARG(header_name); AST_APP_ARG(header_number););
-	AST_STANDARD_APP_ARGS(args, data);
-
-	if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
-		ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(args.action)) {
-		ast_log(AST_LOG_ERROR, "This function requires an action.\n");
-		return -1;
-	}
-	if (ast_strlen_zero(args.header_name)) {
-		ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
-		return -1;
-	}
-	if (!args.header_number) {
-		header_number = 1;
-	} else {
-		sscanf(args.header_number, "%30d", &header_number);
-		if (header_number < 1) {
-			header_number = 1;
-		}
-	}
-
-	header_data.channel = channel;
-	header_data.header_name = args.header_name;
-	header_data.header_number = header_number;
-	header_data.header_value = value;
-	header_data.buf = NULL;
-	header_data.len = 0;
-
-	if (stricmp(args.action, "add") == 0) {
-		return ast_sip_push_task_synchronous(channel->session->serializer, add_header,
-											 &header_data);
-	} else if (stricmp(args.action, "update") == 0) {
-		return ast_sip_push_task_synchronous(channel->session->serializer, update_header,
-											 &header_data);
-	} else if (stricmp(args.action, "remove") == 0) {
-		return ast_sip_push_task_synchronous(channel->session->serializer, remove_header,
-											 &header_data);
-	} else {
-		ast_log(AST_LOG_ERROR,
-				"Unknown action \'%s\' is not valid,  Must be \'add\', \'update\', or \'remove\'.\n",
-				args.action);
-		return -1;
-	}
-}
-
-static struct ast_custom_function pjsip_header_function = {
-	.name = "PJSIP_HEADER",
-	.read = func_read_header,
-	.write = func_write_header,
-};
-
-/*!
- * \internal
- * \brief Session supplement callback for outgoing INVITE requests
- *
- * Retrieve the header_datastore from the session.
- * Add each header in the list to the outgoing message.
- *
- * These pjsip_hdr structures will have been created by add_header.
- * Because outgoing_request may be called more than once with the same header
- * list (as in the case of an authentication exchange), each pjsip_hdr structure
- * MUST be newly cloned for each outgoing message.
- */
-static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)
-{
-	pj_pool_t *pool = session->inv_session->dlg->pool;
-	struct hdr_list *list;
-	struct hdr_list_entry *le;
-	RAII_VAR(struct ast_datastore *, datastore,
-			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
-
-	if (!datastore || !datastore->data ||
-		(session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED)) {
-		return;
-	}
-
-	list = datastore->data;
-	AST_LIST_TRAVERSE(list, le, nextptr) {
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(pool, le->hdr));
-	}
-	ast_sip_session_remove_datastore(session, datastore->uid);
-}
-
-static struct ast_sip_session_supplement header_funcs_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
-	.incoming_request = incoming_request,
-	.outgoing_request = outgoing_request,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sip_session_register_supplement(&header_funcs_supplement);
-	ast_custom_function_register(&pjsip_header_function);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_custom_function_unregister(&pjsip_header_function);
-	ast_sip_session_unregister_supplement(&header_funcs_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Header Functions",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,);
diff --git a/res/res_pjsip_log_forwarder.c b/res/res_pjsip_log_forwarder.c
deleted file mode 100644
index 64e47b4..0000000
--- a/res/res_pjsip_log_forwarder.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Bridge PJSIP logging to Asterisk logging.
- * \author David M. Lee, II <dlee at digium.com>
- *
- * PJSIP logging doesn't exactly match Asterisk logging, but mapping the two is
- * not too bad. PJSIP log levels are identified by a single int. Limits are
- * not specified by PJSIP, but their implementation used 1 through 6.
- *
- * The mapping is as follows:
- *  - 0: LOG_ERROR
- *  - 1: LOG_ERROR
- *  - 2: LOG_WARNING
- *  - 3 and above: equivalent to ast_debug(level, ...) for res_pjsip.so
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include <pjsip.h>
-#include <pj/log.h>
-
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-
-static pj_log_func *log_cb_orig;
-static unsigned decor_orig;
-
-static void log_cb(int level, const char *data, int len)
-{
-	int ast_level;
-	/* PJSIP doesn't provide much in the way of source info */
-	const char * log_source = "pjsip";
-	int log_line = 0;
-	const char *log_func = "<?>";
-	int mod_level;
-
-	/* Lower number indicates higher importance */
-	switch (level) {
-	case 0: /* level zero indicates fatal error, according to docs */
-	case 1: /* 1 seems to be used for errors */
-		ast_level = __LOG_ERROR;
-		break;
-	case 2: /* 2 seems to be used for warnings and errors */
-		ast_level = __LOG_WARNING;
-		break;
-	default:
-		ast_level = __LOG_DEBUG;
-
-		/* For levels 3 and up, obey the debug level for res_pjsip */
-		mod_level = ast_opt_dbg_module ?
-			ast_debug_get_by_module("res_pjsip") : 0;
-		if (option_debug < level && mod_level < level) {
-			return;
-		}
-		break;
-	}
-
-	/* PJSIP uses indention to indicate function call depth. We'll prepend
-	 * log statements with a tab so they'll have a better shot at lining
-	 * up */
-	ast_log(ast_level, log_source, log_line, log_func, "\t%s\n", data);
-}
-
-static int load_module(void)
-{
-	pj_init();
-
-	decor_orig = pj_log_get_decor();
-	log_cb_orig = pj_log_get_log_func();
-
-	ast_debug(3, "Forwarding PJSIP logger to Asterisk logger\n");
-	/* SENDER prepends the source to the log message. This could be a
-	 * filename, object reference, or simply a string
-	 *
-	 * INDENT is assumed to be on by most log statements in PJSIP itself.
-	 */
-	pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT);
-	pj_log_set_log_func(log_cb);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	pj_log_set_log_func(log_cb_orig);
-	pj_log_set_decor(decor_orig);
-
-	pj_shutdown();
-
-	return 0;
-}
-
-/* While we don't really export global symbols, we want to load before other
- * modules that do */
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Log Forwarder",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_CHANNEL_DEPEND - 6,
-	);
diff --git a/res/res_pjsip_logger.c b/res/res_pjsip_logger.c
deleted file mode 100644
index dab9832..0000000
--- a/res/res_pjsip_logger.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<defaultenabled>yes</defaultenabled>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425691 $")
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/cli.h"
-#include "asterisk/netsock2.h"
-
-enum pjsip_logging_mode {
-	LOGGING_MODE_DISABLED,    /* No logging is enabled */
-	LOGGING_MODE_ENABLED,     /* Logging is enabled */
-};
-
-static enum pjsip_logging_mode logging_mode;
-static struct ast_sockaddr log_addr;
-
-/*! \brief  Return the first entry from ast_sockaddr_resolve filtered by address family
- *
- * \warning Using this function probably means you have a faulty design.
- * \note This function was taken from the function of the same name in chan_sip.c
- */
-static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
-				      const char* name, int flag, int family)
-{
-	struct ast_sockaddr *addrs;
-	int addrs_cnt;
-
-	addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family);
-	if (addrs_cnt <= 0) {
-		return 1;
-	}
-	if (addrs_cnt > 1) {
-		ast_debug(1, "Multiple addresses, using the first one only\n");
-	}
-
-	ast_sockaddr_copy(addr, &addrs[0]);
-
-	ast_free(addrs);
-	return 0;
-}
-
-/*! \brief See if we pass debug IP filter */
-static inline int pjsip_log_test_addr(const char *address, int port)
-{
-	struct ast_sockaddr test_addr;
-	if (logging_mode == LOGGING_MODE_DISABLED) {
-		return 0;
-	}
-
-	/* A null logging address means we'll debug any address */
-	if (ast_sockaddr_isnull(&log_addr)) {
-		return 1;
-	}
-
-	/* A null address was passed in. Just reject it. */
-	if (ast_strlen_zero(address)) {
-		return 0;
-	}
-
-	ast_sockaddr_parse(&test_addr, address, PARSE_PORT_IGNORE);
-	ast_sockaddr_set_port(&test_addr, port);
-
-	/* If no port was specified for a debug address, just compare the
-	 * addresses, otherwise compare the address and port
-	 */
-	if (ast_sockaddr_port(&log_addr)) {
-		return !ast_sockaddr_cmp(&log_addr, &test_addr);
-	} else {
-		return !ast_sockaddr_cmp_addr(&log_addr, &test_addr);
-	}
-}
-
-static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
-{
-	if (!pjsip_log_test_addr(tdata->tp_info.dst_name, tdata->tp_info.dst_port)) {
-		return PJ_SUCCESS;
-	}
-
-	ast_verbose("<--- Transmitting SIP %s (%d bytes) to %s:%s:%d --->\n%.*s\n",
-		    tdata->msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
-		    (int) (tdata->buf.cur - tdata->buf.start),
-		    tdata->tp_info.transport->type_name,
-		    tdata->tp_info.dst_name,
-		    tdata->tp_info.dst_port,
-		    (int) (tdata->buf.end - tdata->buf.start), tdata->buf.start);
-	return PJ_SUCCESS;
-}
-
-static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
-{
-	if (!pjsip_log_test_addr(rdata->pkt_info.src_name, rdata->pkt_info.src_port)) {
-		return PJ_FALSE;
-	}
-
-	if (!rdata->msg_info.msg) {
-		return PJ_FALSE;
-	}
-
-	ast_verbose("<--- Received SIP %s (%d bytes) from %s:%s:%d --->\n%s\n",
-		    rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
-		    rdata->msg_info.len,
-		    rdata->tp_info.transport->type_name,
-		    rdata->pkt_info.src_name,
-		    rdata->pkt_info.src_port,
-		    rdata->pkt_info.packet);
-	return PJ_FALSE;
-}
-
-static pjsip_module logging_module = {
-	.name = { "Logging Module", 14 },
-	.priority = 0,
-	.on_rx_request = logging_on_rx_msg,
-	.on_rx_response = logging_on_rx_msg,
-	.on_tx_request = logging_on_tx_msg,
-	.on_tx_response = logging_on_tx_msg,
-};
-
-static char *pjsip_enable_logger_host(int fd, const char *arg)
-{
-	if (ast_sockaddr_resolve_first_af(&log_addr, arg, 0, AST_AF_UNSPEC)) {
-		return CLI_SHOWUSAGE;
-	}
-
-	ast_cli(fd, "PJSIP Logging Enabled for host: %s\n", ast_sockaddr_stringify_addr(&log_addr));
-	logging_mode = LOGGING_MODE_ENABLED;
-
-	return CLI_SUCCESS;
-}
-
-static char *pjsip_set_logger(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	const char *what;
-
-	if (cmd == CLI_INIT) {
-		e->command = "pjsip set logger {on|off|host}";
-		e->usage =
-			"Usage: pjsip set logger {on|off|host <name>}\n"
-			"       Enables or disabling logging of SIP packets\n"
-			"       read on ports bound to PJSIP transports either\n"
-			"       globally or enables logging for an individual\n"
-			"       host.\n";
-		return NULL;
-	} else if (cmd == CLI_GENERATE) {
-		return NULL;
-	}
-
-	what = a->argv[e->args - 1];     /* Guaranteed to exist */
-
-	if (a->argc == e->args) {        /* on/off */
-		if (!strcasecmp(what, "on")) {
-			logging_mode = LOGGING_MODE_ENABLED;
-			ast_cli(a->fd, "PJSIP Logging enabled\n");
-			ast_sockaddr_setnull(&log_addr);
-			return CLI_SUCCESS;
-		} else if (!strcasecmp(what, "off")) {
-			logging_mode = LOGGING_MODE_DISABLED;
-			ast_cli(a->fd, "PJSIP Logging disabled\n");
-			return CLI_SUCCESS;
-		}
-	} else if (a->argc == e->args + 1) {
-		if (!strcasecmp(what, "host")) {
-			return pjsip_enable_logger_host(a->fd, a->argv[e->args]);
-		}
-	}
-
-	return CLI_SHOWUSAGE;
-}
-
-static struct ast_cli_entry cli_pjsip[] = {
-	AST_CLI_DEFINE(pjsip_set_logger, "Enable/Disable PJSIP Logger Output")
-};
-
-static void check_debug(void)
-{
-	RAII_VAR(char *, debug, ast_sip_get_debug(), ast_free);
-
-	if (ast_false(debug)) {
-		logging_mode = LOGGING_MODE_DISABLED;
-		return;
-	}
-
-	logging_mode = LOGGING_MODE_ENABLED;
-
-	if (ast_true(debug)) {
-		ast_sockaddr_setnull(&log_addr);
-		return;
-	}
-
-	/* assume host */
-	if (ast_sockaddr_resolve_first_af(&log_addr, debug, 0, AST_AF_UNSPEC)) {
-		ast_log(LOG_WARNING, "Could not resolve host %s for debug "
-			"logging\n", debug);
-	}
-}
-
-static void global_reloaded(const char *object_type)
-{
-	check_debug();
-}
-
-static const struct ast_sorcery_observer global_observer = {
-	.loaded = global_reloaded
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer)) {
-		ast_log(LOG_WARNING, "Unable to add global observer\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	check_debug();
-
-	ast_sip_register_service(&logging_module);
-	ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
-	ast_sip_unregister_service(&logging_module);
-
-	ast_sorcery_observer_remove(
-		ast_sip_get_sorcery(), "global", &global_observer);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Packet Logger",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
deleted file mode 100644
index 0433299..0000000
--- a/res/res_pjsip_messaging.c
+++ /dev/null
@@ -1,762 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<info name="PJSIPMessageFromInfo" language="en_US" tech="PJSIP">
-		<para>The <literal>from</literal> parameter can be a configured endpoint
-		or in the form of "display-name" <URI>.</para>
-	</info>
-	<info name="PJSIPMessageToInfo" language="en_US" tech="PJSIP">
-		<para>Specifying a prefix of <literal>pjsip:</literal> will send the
-		message as a SIP MESSAGE request.</para>
-	</info>
- ***/
-#include "asterisk.h"
-
-#include "pjsua-lib/pjsua.h"
-
-#include "asterisk/message.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-
-const pjsip_method pjsip_message_method = {PJSIP_OTHER_METHOD, {"MESSAGE", 7} };
-
-#define MAX_HDR_SIZE 512
-#define MAX_BODY_SIZE 1024
-#define MAX_USER_SIZE 128
-
-/*!
- * \internal
- * \brief Checks to make sure the request has the correct content type.
- *
- * \details This module supports the following media types: "text/plain".
- * Return unsupported otherwise.
- *
- * \param rdata The SIP request
- */
-static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata)
-{
-	int res;
-	if (rdata->msg_info.msg->body && rdata->msg_info.msg->body->len) {
-		res = ast_sip_is_content_type(
-			&rdata->msg_info.msg->body->content_type, "text", "plain");
-	} else {
-		res = rdata->msg_info.ctype &&
-			!pj_strcmp2(&rdata->msg_info.ctype->media.type, "text") &&
-			!pj_strcmp2(&rdata->msg_info.ctype->media.subtype, "plain");
-	}
-
-	return res ? PJSIP_SC_OK : PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
-}
-
-/*!
- * \internal
- * \brief Puts pointer past 'sip[s]:' string that should be at the
- * front of the given 'fromto' parameter
- *
- * \param fromto 'From' or 'To' field containing 'sip:'
- */
-static const char *skip_sip(const char *fromto)
-{
-	const char *p;
-
-	/* need to be one past 'sip:' or 'sips:' */
-	if (!(p = strstr(fromto, "sip"))) {
-		return fromto;
-	}
-
-	p += 3;
-	if (*p == 's') {
-		++p;
-	}
-
-	return ++p;
-}
-
-/*!
- * \internal
- * \brief Retrieves an endpoint if specified in the given 'to'
- *
- * Expects the given 'to' to be in one of the following formats:
- *      sip[s]:endpoint[/aor]
- *      sip[s]:endpoint[/uri]
- *      sip[s]:uri <-- will use default outbound endpoint
- *
- * If an optional aor is given it will try to find an associated uri
- * to return.  If an optional uri is given then that will be returned,
- * otherwise uri will be NULL.
- *
- * \param to 'From' or 'To' field with possible endpoint
- * \param uri Optional uri to return
- */
-static struct ast_sip_endpoint* get_outbound_endpoint(
-	const char *to, char **uri)
-{
-	char *name, *aor_uri;
-	struct ast_sip_endpoint* endpoint;
-	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
-
-	name = ast_strdupa(skip_sip(to));
-
-	/* attempt to extract the endpoint name */
-	if ((aor_uri = strchr(name, '/'))) {
-		/* format was 'endpoint/' */
-		*aor_uri++ = '\0';
-	} else if ((aor_uri = strchr(name, '@'))) {
-		/* format was 'endpoint@' - don't use the rest */
-		*aor_uri = '\0';
-	}
-
-	/* at this point, if name is not empty then it
-	   might be an endpoint, so try to retrieve it */
-	if (ast_strlen_zero(name) || !(endpoint = ast_sorcery_retrieve_by_id(
-		      ast_sip_get_sorcery(), "endpoint", name))) {
-		/* an endpoint was not found, so assume sending directly
-		   to a uri and use the default outbound endpoint */
-		*uri = ast_strdup(to);
-		return ast_sip_default_outbound_endpoint();
-	}
-
-	*uri = aor_uri;
-	if (*uri) {
-		char *end = strchr(*uri, '>');
-		if (end) {
-			*end++ = '\0';
-		}
-
-		/* if what's in 'uri' is a retrievable aor use the uri on it
-		   instead, otherwise assume what's there is already a uri*/
-		if ((aor = ast_sip_location_retrieve_aor(*uri)) &&
-			(contact = ast_sip_location_retrieve_first_aor_contact(aor))) {
-			*uri = (char*)contact->uri;
-		}
-		/* need to copy because underlying uri goes away */
-		*uri = ast_strdup(*uri);
-	}
-
-	return endpoint;
-}
-
-/*!
- * \internal
- * \brief Overwrite fields in the outbound 'To' header
- *
- * Updates display name in an outgoing To header.
- *
- * \param tdata the outbound message data structure
- * \param to info to copy into the header
- */
-static void update_to(pjsip_tx_data *tdata, char *to)
-{
-	pjsip_name_addr *name_addr = (pjsip_name_addr *)
-		PJSIP_MSG_TO_HDR(tdata->msg)->uri;
-	pjsip_uri *parsed;
-
-	if ((parsed = pjsip_parse_uri(tdata->pool, to, strlen(to),
-				      PJSIP_PARSE_URI_AS_NAMEADDR))) {
-		pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed;
-		if (pj_strlen(&parsed_name_addr->display)) {
-			pj_strdup(tdata->pool, &name_addr->display,
-				  &parsed_name_addr->display);
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Overwrite fields in the outbound 'From' header
- *
- * The outbound 'From' header is created/added in ast_sip_create_request with
- * default data.  If available that data may be info specified in the 'from_user'
- * and 'from_domain' options found on the endpoint.  That information will be
- * overwritten with data in the given 'from' parameter.
- *
- * \param tdata the outbound message data structure
- * \param from info to copy into the header
- */
-static void update_from(pjsip_tx_data *tdata, char *from)
-{
-	pjsip_name_addr *name_addr = (pjsip_name_addr *)
-		PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
-	pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr);
-	pjsip_uri *parsed;
-
-	if (ast_strlen_zero(from)) {
-		return;
-	}
-
-	if ((parsed = pjsip_parse_uri(tdata->pool, from, strlen(from),
-				      PJSIP_PARSE_URI_AS_NAMEADDR))) {
-		pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed;
-		pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
-		if (pj_strlen(&parsed_name_addr->display)) {
-			pj_strdup(tdata->pool, &name_addr->display,
-				  &parsed_name_addr->display);
-		}
-
-		pj_strdup(tdata->pool, &uri->user, &parsed_uri->user);
-		pj_strdup(tdata->pool, &uri->host, &parsed_uri->host);
-		uri->port = parsed_uri->port;
-	} else {
-		/* assume it is 'user[@domain]' format */
-		char *domain = strchr(from, '@');
-		if (domain) {
-			*domain++ = '\0';
-			pj_strdup2(tdata->pool, &uri->host, domain);
-		}
-		pj_strdup2(tdata->pool, &uri->user, from);
-	}
-}
-
-/*!
- * \internal
- * \brief Checks if the given msg var name should be blocked.
- *
- * \details Some headers are not allowed to be overriden by the user.
- *  Determine if the given var header name from the user is blocked for
- *  an outgoing MESSAGE.
- *
- * \param name name of header to see if it is blocked.
- *
- * \retval TRUE if the given header is blocked.
- */
-static int is_msg_var_blocked(const char *name)
-{
-	int i;
-
-	/*
-	 * Don't block Content-Type or Max-Forwards headers because the
-	 * user can override them.
-	 */
-	static const char *hdr[] = {
-		"To",
-		"From",
-		"Via",
-		"Route",
-		"Contact",
-		"Call-ID",
-		"CSeq",
-		"Allow",
-		"Content-Length",
-		"Request-URI",
-	};
-
-	for (i = 0; i < ARRAY_LEN(hdr); ++i) {
-		if (!strcasecmp(name, hdr[i])) {
-			/* Block addition of this header. */
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Copies any other msg vars over to the request headers.
- *
- * \param msg The msg structure to copy headers from
- * \param tdata The SIP transmission data
- */
-static enum pjsip_status_code vars_to_headers(const struct ast_msg *msg, pjsip_tx_data *tdata)
-{
-	const char *name;
-	const char *value;
-	int max_forwards;
-	struct ast_msg_var_iterator *iter;
-
-	for (iter = ast_msg_var_iterator_init(msg);
-		ast_msg_var_iterator_next(msg, iter, &name, &value);
-		ast_msg_var_unref_current(iter)) {
-		if (!strcasecmp(name, "Max-Forwards")) {
-			/* Decrement Max-Forwards for SIP loop prevention. */
-			if (sscanf(value, "%30d", &max_forwards) != 1 || --max_forwards == 0) {
-				ast_msg_var_iterator_destroy(iter);
-				ast_log(LOG_NOTICE, "MESSAGE(Max-Forwards) reached zero.  MESSAGE not sent.\n");
-				return -1;
-			}
-			sprintf((char *) value, "%d", max_forwards);
-			ast_sip_add_header(tdata, name, value);
-		} else if (!is_msg_var_blocked(name)) {
-			ast_sip_add_header(tdata, name, value);
-		}
-	}
-	ast_msg_var_iterator_destroy(iter);
-
-	return PJSIP_SC_OK;
-}
-
-/*!
- * \internal
- * \brief Copies any other request header data over to ast_msg structure.
- *
- * \param rdata The SIP request
- * \param msg The msg structure to copy headers into
- */
-static int headers_to_vars(const pjsip_rx_data *rdata, struct ast_msg *msg)
-{
-	char *c;
-	char name[MAX_HDR_SIZE];
-	char buf[MAX_HDR_SIZE];
-	int res = 0;
-	pjsip_hdr *h = rdata->msg_info.msg->hdr.next;
-	pjsip_hdr *end= &rdata->msg_info.msg->hdr;
-
-	while (h != end) {
-		if ((res = pjsip_hdr_print_on(h, buf, sizeof(buf)-1)) > 0) {
-			buf[res] = '\0';
-			if ((c = strchr(buf, ':'))) {
-				ast_copy_string(buf, ast_skip_blanks(c + 1), sizeof(buf));
-			}
-
-			ast_copy_pj_str(name, &h->name, sizeof(name));
-			if ((res = ast_msg_set_var(msg, name, buf)) != 0) {
-				break;
-			}
-		}
-		h = h->next;
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Prints the message body into the given char buffer.
- *
- * \details Copies body content from the received data into the given
- * character buffer removing any extra carriage return/line feeds.
- *
- * \param rdata The SIP request
- * \param buf Buffer to fill
- * \param len The length of the buffer
- */
-static int print_body(pjsip_rx_data *rdata, char *buf, int len)
-{
-	int res;
-
-	if (!rdata->msg_info.msg->body || !rdata->msg_info.msg->body->len) {
-		return 0;
-	}
-
-	if ((res = rdata->msg_info.msg->body->print_body(
-		     rdata->msg_info.msg->body, buf, len)) < 0) {
-		return res;
-	}
-
-	/* remove any trailing carriage return/line feeds */
-	while (res > 0 && ((buf[--res] == '\r') || (buf[res] == '\n')));
-
-	buf[++res] = '\0';
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Converts a 'sip:' uri to a 'pjsip:' so it can be found by
- * the message tech.
- *
- * \param buf uri to insert 'pjsip' into
- * \param size length of the uri in buf
- * \param capacity total size of buf
- */
-static char *sip_to_pjsip(char *buf, int size, int capacity)
-{
-	int count;
-	const char *scheme;
-	char *res = buf;
-
-	/* remove any wrapping brackets */
-	if (*buf == '<') {
-		++buf;
-		--size;
-	}
-
-	scheme = strncmp(buf, "sip", 3) ? "pjsip:" : "pj";
-	count = strlen(scheme);
-	if (count + size >= capacity) {
-		ast_log(LOG_WARNING, "Unable to handle MESSAGE- incoming uri "
-			"too large for given buffer\n");
-		return NULL;
-	}
-
-	memmove(res + count, buf, size);
-	memcpy(res, scheme, count);
-
-	buf += size - 1;
-	if (*buf == '>') {
-		*buf = '\0';
-	}
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Converts a pjsip_rx_data structure to an ast_msg structure.
- *
- * \details Attempts to fill in as much information as possible into the given
- * msg structure copied from the given request data.
- *
- * \param rdata The SIP request
- * \param msg The asterisk message structure to fill in.
- */
-static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct ast_msg *msg)
-{
-	struct ast_sip_endpoint *endpt = ast_pjsip_rdata_get_endpoint(rdata);
-	pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
-	pjsip_sip_uri *sip_ruri;
-	pjsip_name_addr *name_addr;
-	char buf[MAX_BODY_SIZE];
-	const char *field;
-	const char *context = S_OR(endpt->message_context, endpt->context);
-	char exten[AST_MAX_EXTENSION];
-	int res = 0;
-	int size;
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
-		return PJSIP_SC_UNSUPPORTED_URI_SCHEME;
-	}
-
-	sip_ruri = pjsip_uri_get_uri(ruri);
-	ast_copy_pj_str(exten, &sip_ruri->user, AST_MAX_EXTENSION);
-
-	res |= ast_msg_set_context(msg, "%s", context);
-	res |= ast_msg_set_exten(msg, "%s", exten);
-
-	/* to header */
-	name_addr = (pjsip_name_addr *)rdata->msg_info.to->uri;
-	size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf) - 1);
-	if (size <= 0) {
-		return PJSIP_SC_INTERNAL_SERVER_ERROR;
-	}
-	buf[size] = '\0';
-	res |= ast_msg_set_to(msg, "%s", sip_to_pjsip(buf, ++size, sizeof(buf) - 1));
-
-	/* from header */
-	name_addr = (pjsip_name_addr *)rdata->msg_info.from->uri;
-	size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf) - 1);
-	if (size <= 0) {
-		return PJSIP_SC_INTERNAL_SERVER_ERROR;
-	}
-	buf[size] = '\0';
-	res |= ast_msg_set_from(msg, "%s", buf);
-
-	field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf) - 1, 1);
-	res |= ast_msg_set_var(msg, "PJSIP_RECVADDR", field);
-
-	if (print_body(rdata, buf, sizeof(buf) - 1) > 0) {
-		res |= ast_msg_set_body(msg, "%s", buf);
-	}
-
-	/* endpoint name */
-	res |= ast_msg_set_tech(msg, "%s", "PJSIP");
-	res |= ast_msg_set_endpoint(msg, "%s", ast_sorcery_object_get_id(endpt));
-	if (endpt->id.self.name.valid) {
-		res |= ast_msg_set_var(msg, "PJSIP_ENDPOINT", endpt->id.self.name.str);
-	}
-
-	res |= headers_to_vars(rdata, msg);
-
-	return !res ? PJSIP_SC_OK : PJSIP_SC_INTERNAL_SERVER_ERROR;
-}
-
-struct msg_data {
-	struct ast_msg *msg;
-        char *to;
-	char *from;
-};
-
-static void msg_data_destroy(void *obj)
-{
-	struct msg_data *mdata = obj;
-
-	ast_free(mdata->from);
-	ast_free(mdata->to);
-
-	ast_msg_destroy(mdata->msg);
-}
-
-static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *to, const char *from)
-{
-	char *tag;
-	struct msg_data *mdata = ao2_alloc(sizeof(*mdata), msg_data_destroy);
-
-	if (!mdata) {
-		return NULL;
-	}
-
-	/* typecast to suppress const warning */
-	mdata->msg = ast_msg_ref((struct ast_msg*)msg);
-
-	/* starts with 'pjsip:' the 'pj' needs to be removed and maybe even
-	   the entire string. */
-	if (!(to = strchr(to, ':'))) {
-		ao2_ref(mdata, -1);
-		return NULL;
-	}
-
-	/* Make sure we start with sip: */
-	mdata->to = ast_begins_with(to, "sip:") ? ast_strdup(++to) : ast_strdup(to - 3);
-	mdata->from = ast_strdup(from);
-
-	/* sometimes from can still contain the tag at this point, so remove it */
-	if ((tag = strchr(mdata->from, ';'))) {
-		*tag = '\0';
-	}
-	return mdata;
-}
-
-static int msg_send(void *data)
-{
-	RAII_VAR(struct msg_data *, mdata, data, ao2_cleanup);
-
-	const struct ast_sip_body body = {
-		.type = "text",
-		.subtype = "plain",
-		.body_text = ast_msg_get_body(mdata->msg)
-	};
-
-	pjsip_tx_data *tdata;
-	RAII_VAR(char *, uri, NULL, ast_free);
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint(
-			 mdata->to, &uri), ao2_cleanup);
-
-	if (!endpoint) {
-		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint '%s' and "
-			"no default outbound endpoint configured\n", mdata->to);
-		return -1;
-	}
-
-	if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) {
-		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n");
-		return -1;
-	}
-
-	update_to(tdata, mdata->to);
-	update_from(tdata, mdata->from);
-
-	if (ast_sip_add_body(tdata, &body)) {
-		pjsip_tx_data_dec_ref(tdata);
-		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n");
-		return -1;
-	}
-
-	vars_to_headers(mdata->msg, tdata);
-
-	ast_debug(1, "Sending message to '%s' (via endpoint %s) from '%s'\n",
-		mdata->to, ast_sorcery_object_get_id(endpoint), mdata->from);
-
-	if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
-		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
-		return -1;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from)
-{
-	struct msg_data *mdata;
-
-	if (ast_strlen_zero(to)) {
-		ast_log(LOG_ERROR, "SIP MESSAGE - a 'To' URI  must be specified\n");
-		return -1;
-	}
-
-	if (!(mdata = msg_data_create(msg, to, from)) ||
-	    ast_sip_push_task(NULL, msg_send, mdata)) {
-		ao2_ref(mdata, -1);
-		return -1;
-	}
-	return 0;
-}
-
-static const struct ast_msg_tech msg_tech = {
-	.name = "pjsip",
-	.msg_send = sip_msg_send,
-};
-
-static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code,
-				 pjsip_dialog *dlg, pjsip_transaction *tsx)
-{
-	pjsip_tx_data *tdata;
-	pj_status_t status;
-	pjsip_response_addr res_addr;
-
-	status = ast_sip_create_response(rdata, code, NULL, &tdata);
-	if (status != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
-		return status;
-	}
-
-	if (dlg && tsx) {
-		status = pjsip_dlg_send_response(dlg, tsx, tdata);
-	} else {
-		/* Get where to send request. */
-		status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
-		if (status != PJ_SUCCESS) {
-			ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status);
-			return status;
-		}
-		status = ast_sip_send_response(&res_addr, tdata, ast_pjsip_rdata_get_endpoint(rdata));
-	}
-
-	if (status != PJ_SUCCESS) {
-		ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
-	}
-
-	return status;
-}
-
-static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
-{
-	enum pjsip_status_code code;
-	struct ast_msg *msg;
-
-	/* if not a MESSAGE, don't handle */
-	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_message_method)) {
-		return PJ_FALSE;
-	}
-
-	code = check_content_type(rdata);
-	if (code != PJSIP_SC_OK) {
-		send_response(rdata, code, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	msg = ast_msg_alloc();
-	if (!msg) {
-		send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	code = rx_data_to_ast_msg(rdata, msg);
-	if (code != PJSIP_SC_OK) {
-		send_response(rdata, code, NULL, NULL);
-		ast_msg_destroy(msg);
-		return PJ_TRUE;
-	}
-
-	if (!ast_msg_has_destination(msg)) {
-		ast_debug(1, "MESSAGE request received, but no handler wanted it\n");
-		send_response(rdata, PJSIP_SC_NOT_FOUND, NULL, NULL);
-		ast_msg_destroy(msg);
-		return PJ_TRUE;
-	}
-
-	/* send it to the messaging core */
-	ast_msg_queue(msg);
-	send_response(rdata, PJSIP_SC_ACCEPTED, NULL, NULL);
-
-	return PJ_TRUE;
-}
-
-static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	char buf[MAX_BODY_SIZE];
-	enum pjsip_status_code code;
-	struct ast_frame f;
-
-	pjsip_dialog *dlg = session->inv_session->dlg;
-	pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-
-	if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
-		send_response(rdata, code, dlg, tsx);
-		return 0;
-	}
-
-	if (print_body(rdata, buf, sizeof(buf)-1) < 1) {
-		/* invalid body size */
-		return 0;
-	}
-
-	ast_debug(3, "Received in dialog SIP message\n");
-
-	memset(&f, 0, sizeof(f));
-	f.frametype = AST_FRAME_TEXT;
-	f.subclass.integer = 0;
-	f.offset = 0;
-	f.data.ptr = buf;
-	f.datalen = strlen(buf) + 1;
-	ast_queue_frame(session->channel, &f);
-
-	send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx);
-	return 0;
-}
-
-static struct ast_sip_session_supplement messaging_supplement = {
-	.method = "MESSAGE",
-	.incoming_request = incoming_in_dialog_request
-};
-
-static pjsip_module messaging_module = {
-	.name = {"Messaging Module", 16},
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.on_rx_request = module_on_rx_request,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (ast_sip_register_service(&messaging_module) != PJ_SUCCESS) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(),
-				       NULL, PJSIP_H_ALLOW, NULL, 1,
-				       &pjsip_message_method.name) != PJ_SUCCESS) {
-
-		ast_sip_unregister_service(&messaging_module);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_msg_tech_register(&msg_tech)) {
-		ast_sip_unregister_service(&messaging_module);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sip_session_register_supplement(&messaging_supplement);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&messaging_supplement);
-	ast_msg_tech_unregister(&msg_tech);
-	ast_sip_unregister_service(&messaging_module);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Messaging Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_multihomed.c b/res/res_pjsip_multihomed.c
deleted file mode 100644
index e0ee53e..0000000
--- a/res/res_pjsip_multihomed.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-
-/*! \brief Local host address for IPv4 */
-static char host_ipv4[PJ_INET_ADDRSTRLEN + 2];
-
-/*! \brief Local host address for IPv6 */
-static char host_ipv6[PJ_INET6_ADDRSTRLEN + 2];
-
-/*! \brief Helper function which returns a UDP transport bound to the given address and port */
-static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port)
-{
-	struct ao2_container *transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	struct ast_sip_transport *transport;
-	struct ao2_iterator iter;
-	pjsip_transport *sip_transport = NULL;
-
-	if (!transports) {
-		return NULL;
-	}
-
-	for (iter = ao2_iterator_init(transports, 0); (transport = ao2_iterator_next(&iter)); ao2_ref(transport, -1)) {
-		if ((transport->type != AST_TRANSPORT_UDP) ||
-			(pj_strcmp(&transport->state->transport->local_name.host, address)) ||
-			(transport->state->transport->local_name.port != port)) {
-			continue;
-		}
-
-		sip_transport = transport->state->transport;
-		ao2_ref(transport, -1);
-		break;
-	}
-	ao2_iterator_destroy(&iter);
-
-	ao2_ref(transports, -1);
-
-	return sip_transport;
-}
-
-/*! \brief Helper function which determines if the address within SDP should be rewritten */
-static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
-{
-	if (!sdp->conn) {
-		return 0;
-	}
-
-	/* If the host address is used in the SDP replace it with the address of what this is going out on */
-	if ((!pj_strcmp2(&sdp->conn->addr_type, "IP4") && !pj_strcmp2(&sdp->conn->addr, host_ipv4)) ||
-		(!pj_strcmp2(&sdp->conn->addr_type, "IP6") && !pj_strcmp2(&sdp->conn->addr, host_ipv6))) {
-		return 1;
-	}
-
-	return 0;
-}
-
-/*! \brief Helper function which determines if the existing address has priority over new one */
-static int multihomed_rewrite_header(pj_str_t *source, pjsip_transport *transport)
-{
-	pj_uint32_t loop6[4] = {0, 0, 0, 0};
-
-	/* If the transport is bound to any it should always rewrite */
-	if ((transport->local_addr.addr.sa_family == pj_AF_INET() &&
-		transport->local_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) ||
-		(transport->local_addr.addr.sa_family == pj_AF_INET6() &&
-		!pj_memcmp(&transport->local_addr.ipv6.sin6_addr, loop6, sizeof(loop6)))) {
-		return 1;
-	}
-
-	/* If the transport is explicitly bound but the determined source differs favor the transport */
-	if (!pj_strcmp(source, &transport->local_name.host)) {
-		return 1;
-	}
-
-	return 0;
-}
-
-static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
-{
-	pjsip_tpmgr_fla2_param prm;
-	pjsip_transport *transport = NULL;
-	pjsip_cseq_hdr *cseq;
-	pjsip_via_hdr *via;
-
-	/* Use the destination information to determine what local interface this message will go out on */
-	pjsip_tpmgr_fla2_param_default(&prm);
-	prm.tp_type = tdata->tp_info.transport->key.type;
-	pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
-	prm.local_if = PJ_TRUE;
-
-	/* If we can't get the local address use best effort and let it pass */
-	if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {
-		return PJ_SUCCESS;
-	}
-
-	/* If the transport it is going out on is different reflect it in the message */
-	if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
-		tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
-		transport = multihomed_get_udp_transport(&prm.ret_addr, prm.ret_port);
-	}
-
-	/* If no new transport use the one provided by the message */
-	if (!transport) {
-		transport = tdata->tp_info.transport;
-	}
-
-	/* If the message should not be rewritten then abort early */
-	if (!multihomed_rewrite_header(&prm.ret_addr, transport)) {
-		return PJ_SUCCESS;
-	}
-
-	/* Update the transport in case it has changed - we do this now in case we don't want to touch the message above */
-	tdata->tp_info.transport = transport;
-
-	/* If the message needs to be updated with new address do so */
-	if (tdata->msg->type == PJSIP_REQUEST_MSG || !(cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL)) ||
-		pj_strcmp2(&cseq->method.name, "REGISTER")) {
-		pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
-		if (contact && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
-			pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
-
-			/* prm.ret_addr is allocated from the tdata pool so it is perfectly fine to just do an assignment like this */
-			pj_strassign(&uri->host, &prm.ret_addr);
-			uri->port = prm.ret_port;
-
-			pjsip_tx_data_invalidate_msg(tdata);
-		}
-	}
-
-	if (tdata->msg->type == PJSIP_REQUEST_MSG && (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
-		pj_strassign(&via->sent_by.host, &prm.ret_addr);
-		via->sent_by.port = prm.ret_port;
-
-		pjsip_tx_data_invalidate_msg(tdata);
-	}
-
-	/* Update the SDP if it is present */
-	if (tdata->msg->body && ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") &&
-		multihomed_rewrite_sdp(tdata->msg->body->data)) {
-		struct pjmedia_sdp_session *sdp = tdata->msg->body->data;
-		int stream;
-
-		pj_strassign(&sdp->conn->addr, &prm.ret_addr);
-
-		for (stream = 0; stream < sdp->media_count; ++stream) {
-			if (sdp->media[stream]->conn) {
-				pj_strassign(&sdp->media[stream]->conn->addr, &prm.ret_addr);
-			}
-		}
-
-		pjsip_tx_data_invalidate_msg(tdata);
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pjsip_module multihomed_module = {
-	.name = { "Multihomed Routing", 18 },
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
-	.on_tx_request = multihomed_on_tx_message,
-	.on_tx_response = multihomed_on_tx_message,
-};
-
-static int unload_module(void)
-{
-	ast_sip_unregister_service(&multihomed_module);
-	return 0;
-}
-
-static int load_module(void)
-{
-	char hostname[MAXHOSTNAMELEN] = "";
-	pj_sockaddr addr;
-
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (!gethostname(hostname, sizeof(hostname) - 1)) {
-		ast_verb(2, "Performing DNS resolution of local hostname '%s' to get local IPv4 and IPv6 address\n",
-			hostname);
-	}
-
-	if (!pj_gethostip(pj_AF_INET(), &addr)) {
-		pj_sockaddr_print(&addr, host_ipv4, sizeof(host_ipv4), 2);
-		ast_verb(3, "Local IPv4 address determined to be: %s\n", host_ipv4);
-	}
-
-	if (!pj_gethostip(pj_AF_INET6(), &addr)) {
-		pj_sockaddr_print(&addr, host_ipv6, sizeof(host_ipv6), 2);
-		ast_verb(3, "Local IPv6 address determined to be: %s\n", host_ipv6);
-	}
-
-	if (ast_sip_register_service(&multihomed_module)) {
-		ast_log(LOG_ERROR, "Could not register multihomed module for incoming and outgoing requests\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Multihomed Routing Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
deleted file mode 100644
index bf0925d..0000000
--- a/res/res_pjsip_mwi.c
+++ /dev/null
@@ -1,924 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/stasis.h"
-#include "asterisk/app.h"
-
-struct mwi_subscription;
-AO2_GLOBAL_OBJ_STATIC(unsolicited_mwi);
-
-#define STASIS_BUCKETS 13
-#define MWI_BUCKETS 53
-
-#define MWI_TYPE "application"
-#define MWI_SUBTYPE "simple-message-summary"
-
-#define MWI_DATASTORE "MWI datastore"
-
-static void mwi_subscription_shutdown(struct ast_sip_subscription *sub);
-static void mwi_to_ami(struct ast_sip_subscription *sub, struct ast_str **buf);
-static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
-		const char *resource);
-static int mwi_subscription_established(struct ast_sip_subscription *sub);
-static void *mwi_get_notify_data(struct ast_sip_subscription *sub);
-
-static struct ast_sip_notifier mwi_notifier = {
-	.default_accept = MWI_TYPE"/"MWI_SUBTYPE,
-	.new_subscribe = mwi_new_subscribe,
-	.subscription_established = mwi_subscription_established,
-	.get_notify_data = mwi_get_notify_data,
-};
-
-static struct ast_sip_subscription_handler mwi_handler = {
-	.event_name = "message-summary",
-	.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
-	.accept = { MWI_TYPE"/"MWI_SUBTYPE, },
-	.subscription_shutdown = mwi_subscription_shutdown,
-	.to_ami = mwi_to_ami,
-	.notifier = &mwi_notifier,
-};
-
-/*!
- * \brief Wrapper for stasis subscription
- *
- * An MWI subscription has a container of these. This
- * represents a stasis subscription for MWI state.
- */
-struct mwi_stasis_subscription {
-	/*! The MWI stasis subscription */
-	struct stasis_subscription *stasis_sub;
-	/*! The mailbox corresponding with the MWI subscription. Used as a hash key */
-	char mailbox[1];
-};
-
-/*!
- * \brief A subscription for MWI
- *
- * This subscription is the basis for MWI for an endpoint. Each
- * endpoint that uses MWI will have a corresponding mwi_subscription.
- *
- * This structure acts as the owner for the underlying SIP subscription.
- * When the mwi_subscription is destroyed, the SIP subscription dies, too.
- * The mwi_subscription's lifetime is governed by its underlying stasis
- * subscriptions. When all stasis subscriptions are destroyed, the
- * mwi_subscription is destroyed as well.
- */
-struct mwi_subscription {
-	/*! Container of \ref mwi_stasis_subscription structures.
-	 * A single MWI subscription may be fore multiple mailboxes, thus
-	 * requiring multiple stasis subscriptions
-	 */
-	struct ao2_container *stasis_subs;
-	/*! The SIP subscription. Unsolicited MWI does not use this */
-	struct ast_sip_subscription *sip_sub;
-	/*! Is the MWI solicited (i.e. Initiated with an external SUBSCRIBE) ? */
-	unsigned int is_solicited;
-	/*! Identifier for the subscription.
-	 * The identifier is the same as the corresponding endpoint's stasis ID.
-	 * Used as a hash key
-	 */
-	char id[1];
-};
-
-static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg);
-
-static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char *mailbox, struct mwi_subscription *mwi_sub)
-{
-	struct mwi_stasis_subscription *mwi_stasis_sub;
-	struct stasis_topic *topic;
-
-	if (!mwi_sub) {
-		return NULL;
-	}
-
-	mwi_stasis_sub = ao2_alloc(sizeof(*mwi_stasis_sub) + strlen(mailbox), NULL);
-	if (!mwi_stasis_sub) {
-		return NULL;
-	}
-
-	topic = ast_mwi_topic(mailbox);
-
-	/* Safe strcpy */
-	strcpy(mwi_stasis_sub->mailbox, mailbox);
-	ao2_ref(mwi_sub, +1);
-	ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n", mailbox, mwi_sub->id);
-	mwi_stasis_sub->stasis_sub = stasis_subscribe_pool(topic, mwi_stasis_cb, mwi_sub);
-	return mwi_stasis_sub;
-}
-
-static int stasis_sub_hash(const void *obj, const int flags)
-{
-	const struct mwi_stasis_subscription *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->mailbox;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int stasis_sub_cmp(void *obj, void *arg, int flags)
-{
-	const struct mwi_stasis_subscription *sub_left = obj;
-	const struct mwi_stasis_subscription *sub_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = sub_right->mailbox;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(sub_left->mailbox, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(sub_left->mailbox, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-static void mwi_subscription_destructor(void *obj)
-{
-	struct mwi_subscription *sub = obj;
-
-	ast_debug(3, "Destroying MWI subscription for endpoint %s\n", sub->id);
-	ao2_cleanup(sub->sip_sub);
-	ao2_cleanup(sub->stasis_subs);
-}
-
-static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *endpoint,
-		unsigned int is_solicited, struct ast_sip_subscription *sip_sub)
-{
-	struct mwi_subscription *sub;
-	const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
-
-	sub = ao2_alloc(sizeof(*sub) + strlen(endpoint_id),
-			mwi_subscription_destructor);
-
-	if (!sub) {
-		return NULL;
-	}
-
-	/* Safe strcpy */
-	strcpy(sub->id, endpoint_id);
-
-	/* Unsolicited MWI doesn't actually result in a SIP subscription being
-	 * created. This is because a SIP subscription associates with a dialog.
-	 * Most devices expect unsolicited MWI NOTIFYs to appear out of dialog. If
-	 * they receive an in-dialog MWI NOTIFY (i.e. with a to-tag), then they
-	 * will reject the NOTIFY with a 481, thus resulting in message-waiting
-	 * state not being updated on the device
-	 */
-	if (is_solicited) {
-		sub->sip_sub = ao2_bump(sip_sub);
-	}
-
-	sub->stasis_subs = ao2_container_alloc(STASIS_BUCKETS, stasis_sub_hash, stasis_sub_cmp);
-	if (!sub->stasis_subs) {
-		ao2_cleanup(sub);
-		return NULL;
-	}
-	sub->is_solicited = is_solicited;
-
-	ast_debug(3, "Created %s MWI subscription for endpoint %s\n", is_solicited ? "solicited" : "unsolicited", sub->id);
-
-	return sub;
-}
-
-static int mwi_sub_hash(const void *obj, const int flags)
-{
-	const struct mwi_subscription *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = object->id;
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int mwi_sub_cmp(void *obj, void *arg, int flags)
-{
-	const struct mwi_subscription *sub_left = obj;
-	const struct mwi_subscription *sub_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = sub_right->id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(sub_left->id, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(sub_left->id, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-static int get_message_count(void *obj, void *arg, int flags)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct mwi_stasis_subscription *mwi_stasis = obj;
-	struct ast_sip_message_accumulator *counter = arg;
-	struct ast_mwi_state *mwi_state;
-
-	msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), mwi_stasis->mailbox);
-	if (!msg) {
-		return 0;
-	}
-
-	mwi_state = stasis_message_data(msg);
-	counter->old_msgs += mwi_state->old_msgs;
-	counter->new_msgs += mwi_state->new_msgs;
-	return 0;
-}
-
-struct unsolicited_mwi_data {
-	struct mwi_subscription *sub;
-	struct ast_sip_endpoint *endpoint;
-	pjsip_evsub_state state;
-	const struct ast_sip_body *body;
-};
-
-static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags)
-{
-	struct unsolicited_mwi_data *mwi_data = arg;
-	struct mwi_subscription *sub = mwi_data->sub;
-	struct ast_sip_endpoint *endpoint = mwi_data->endpoint;
-	pjsip_evsub_state state = mwi_data->state;
-	const struct ast_sip_body *body = mwi_data->body;
-	struct ast_sip_contact *contact = obj;
-	const char *state_name;
-	pjsip_tx_data *tdata;
-	pjsip_sub_state_hdr *sub_state;
-	pjsip_event_hdr *event;
-	const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL);
-
-	if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, contact, &tdata)) {
-		ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri);
-		return 0;
-	}
-
-	if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) {
-		pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
-		pjsip_name_addr *from_name_addr = (pjsip_name_addr *) from->uri;
-		pjsip_sip_uri *from_uri = pjsip_uri_get_uri(from_name_addr->uri);
-
-		pj_strdup2(tdata->pool, &from_uri->user, endpoint->subscription.mwi.fromuser);
-	}
-
-	switch (state) {
-	case PJSIP_EVSUB_STATE_ACTIVE:
-		state_name = "active";
-		break;
-	case PJSIP_EVSUB_STATE_TERMINATED:
-	default:
-		state_name = "terminated";
-		break;
-	}
-
-	sub_state = pjsip_sub_state_hdr_create(tdata->pool);
-	pj_cstr(&sub_state->sub_state, state_name);
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) sub_state);
-
-	event = pjsip_event_hdr_create(tdata->pool);
-	pj_cstr(&event->event_type, "message-summary");
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
-
-	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events));
-	ast_sip_add_body(tdata, body);
-	ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL);
-
-	return 0;
-}
-
-static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
-		struct ast_sip_message_accumulator *counter)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
-				"endpoint", sub->id), ao2_cleanup);
-	char *endpoint_aors;
-	char *aor_name;
-	struct ast_sip_body body;
-	struct ast_str *body_text;
-	struct ast_sip_body_data body_data = {
-		.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
-		.body_data = counter,
-	};
-
-	if (!endpoint) {
-		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
-				sub->id);
-		return;
-	}
-	if (ast_strlen_zero(endpoint->aors)) {
-		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because the endpoint has no"
-				" configured AORs\n", sub->id);
-		return;
-	}
-
-	body.type = MWI_TYPE;
-	body.subtype = MWI_SUBTYPE;
-
-	body_text = ast_str_create(64);
-
-	if (!body_text) {
-		return;
-	}
-
-	if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) {
-		ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n");
-		ast_free(body_text);
-		return;
-	}
-
-	body.body_text = ast_str_buffer(body_text);
-
-	endpoint_aors = ast_strdupa(endpoint->aors);
-
-	ast_debug(5, "Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
-			sub->id, counter->new_msgs, counter->old_msgs);
-
-	while ((aor_name = strsep(&endpoint_aors, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-		struct unsolicited_mwi_data mwi_data = {
-			.sub = sub,
-			.endpoint = endpoint,
-			.body = &body,
-		};
-
-		if (!aor) {
-			ast_log(LOG_WARNING, "Unable to locate AOR %s for unsolicited MWI\n", aor_name);
-			continue;
-		}
-
-		contacts = ast_sip_location_retrieve_aor_contacts(aor);
-		if (!contacts || (ao2_container_count(contacts) == 0)) {
-			ast_log(LOG_WARNING, "No contacts bound to AOR %s. Cannot send unsolicited MWI.\n", aor_name);
-			continue;
-		}
-
-		ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data);
-	}
-
-	ast_free(body_text);
-}
-
-static void send_mwi_notify(struct mwi_subscription *sub)
-{
-	struct ast_sip_message_accumulator counter = {
-		.old_msgs = 0,
-		.new_msgs = 0,
-	};
-	struct ast_sip_body_data data = {
-		.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
-		.body_data = &counter,
-	};
-
-	ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter);
-
-	if (sub->is_solicited) {
-		ast_sip_subscription_notify(sub->sip_sub, &data, 0);
-		return;
-	}
-
-	send_unsolicited_mwi_notify(sub, &counter);
-}
-
-static int unsubscribe_stasis(void *obj, void *arg, int flags)
-{
-	struct mwi_stasis_subscription *mwi_stasis = obj;
-	if (mwi_stasis->stasis_sub) {
-		ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);
-		mwi_stasis->stasis_sub = stasis_unsubscribe(mwi_stasis->stasis_sub);
-	}
-	return CMP_MATCH;
-}
-
-static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
-{
-	struct mwi_subscription *mwi_sub;
-	RAII_VAR(struct ast_datastore *, mwi_datastore,
-			ast_sip_subscription_get_datastore(sub, MWI_DATASTORE), ao2_cleanup);
-
-	if (!mwi_datastore) {
-		return;
-	}
-
-	mwi_sub = mwi_datastore->data;
-	ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
-}
-
-static struct ast_datastore_info mwi_ds_info = { };
-
-static int add_mwi_datastore(struct mwi_subscription *sub)
-{
-	RAII_VAR(struct ast_datastore *, mwi_datastore, NULL, ao2_cleanup);
-
-	mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
-	if (!mwi_datastore) {
-		return -1;
-	}
-	mwi_datastore->data = sub;
-
-	ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
-	return 0;
-}
-
-/*!
- * \brief Determines if an endpoint is receiving unsolicited MWI for a particular mailbox.
- *
- * \param endpoint The endpoint to check
- * \param mailbox The candidate mailbox
- * \retval 0 The endpoint does not receive unsolicited MWI for this mailbox
- * \retval 1 The endpoint receives unsolicited MWI for this mailbox
- */
-static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,
-		const char *mailbox)
-{
-	struct ao2_container *unsolicited = ao2_global_obj_ref(unsolicited_mwi);
-	struct ao2_iterator *mwi_subs;
-	struct mwi_subscription *mwi_sub;
-	const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
-	int ret = 0;
-
-	if (!unsolicited) {
-		return 0;
-	}
-
-	mwi_subs = ao2_find(unsolicited, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
-	ao2_cleanup(unsolicited);
-
-	if (!mwi_subs) {
-		return 0;
-	}
-
-	for (; (mwi_sub = ao2_iterator_next(mwi_subs)) && !ret; ao2_cleanup(mwi_sub)) {
-		struct mwi_stasis_subscription *mwi_stasis;
-
-		mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);
-		if (mwi_stasis) {
-			ret = 1;
-			ao2_cleanup(mwi_stasis);
-		}
-	}
-
-	ao2_iterator_destroy(mwi_subs);
-	return ret;
-}
-
-/*!
- * \brief Determine if an endpoint is a candidate to be able to subscribe for MWI
- *
- * Currently, this just makes sure that the endpoint is not already receiving unsolicted
- * MWI for any of an AOR's configured mailboxes.
- *
- * \param obj The AOR to which the endpoint is subscribing.
- * \param arg The endpoint that is attempting to subscribe.
- * \param flags Unused.
- * \retval 0 Endpoint is a candidate to subscribe to MWI on the AOR.
- * \retval -1 The endpoint cannot subscribe to MWI on the AOR.
- */
-static int mwi_validate_for_aor(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct ast_sip_endpoint *endpoint = arg;
-	char *mailboxes;
-	char *mailbox;
-
-	if (ast_strlen_zero(aor->mailboxes)) {
-		return 0;
-	}
-
-	mailboxes = ast_strdupa(aor->mailboxes);
-	while ((mailbox = strsep(&mailboxes, ","))) {
-		if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) {
-			ast_log(LOG_NOTICE, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
-					"Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox,
-					ast_sorcery_object_get_id(aor));
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int mwi_on_aor(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct mwi_subscription *sub = arg;
-	char *mailboxes;
-	char *mailbox;
-
-	if (ast_strlen_zero(aor->mailboxes)) {
-		return 0;
-	}
-
-	mailboxes = ast_strdupa(aor->mailboxes);
-	while ((mailbox = strsep(&mailboxes, ","))) {
-		RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
-				mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
-		if (mwi_stasis_sub) {
-			ao2_link(sub->stasis_subs, mwi_stasis_sub);
-		}
-	}
-
-	return 0;
-}
-
-static struct mwi_subscription *mwi_create_subscription(
-	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
-{
-	struct mwi_subscription *sub = mwi_subscription_alloc(endpoint, 1, sip_sub);
-
-	if (!sub) {
-		return NULL;
-	}
-
-	if (add_mwi_datastore(sub)) {
-		ast_log(LOG_WARNING, "Unable to allocate datastore on MWI "
-			"subscription from %s\n", sub->id);
-		ao2_ref(sub, -1);
-		return NULL;
-	}
-
-	return sub;
-}
-
-static struct mwi_subscription *mwi_subscribe_single(
-	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
-{
-	RAII_VAR(struct ast_sip_aor *, aor,
-		 ast_sip_location_retrieve_aor(name), ao2_cleanup);
-	struct mwi_subscription *sub;
-
-	if (!aor) {
-		/*! I suppose it's possible for the AOR to disappear on us
-		 * between accepting the subscription and sending the first
-		 * NOTIFY...
-		 */
-		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI "
-			"subscription failed.\n", name);
-		return NULL;
-	}
-
-	if (!(sub = mwi_create_subscription(endpoint, sip_sub))) {
-		return NULL;
-	}
-
-	mwi_on_aor(aor, sub, 0);
-	return sub;
-}
-
-static struct mwi_subscription *mwi_subscribe_all(
-	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
-{
-	struct mwi_subscription *sub;
-
-	sub = mwi_create_subscription(endpoint, sip_sub);
-
-	if (!sub) {
-		return NULL;
-	}
-
-	ast_sip_for_each_aor(endpoint->aors, mwi_on_aor, sub);
-	return sub;
-}
-
-static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
-		const char *resource)
-{
-	struct ast_sip_aor *aor;
-
-	if (ast_strlen_zero(resource)) {
-		if (ast_sip_for_each_aor(endpoint->aors, mwi_validate_for_aor, endpoint)) {
-			return 500;
-		}
-		return 200;
-	}
-
-	aor = ast_sip_location_retrieve_aor(resource);
-
-	if (!aor) {
-		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI "
-			"subscription failed.\n", resource);
-		return 404;
-	}
-
-	if (ast_strlen_zero(aor->mailboxes)) {
-		ast_log(LOG_WARNING, "AOR %s has no configured mailboxes. "
-			"MWI subscription failed\n", resource);
-		return 404;
-	}
-
-	if (mwi_validate_for_aor(aor, endpoint, 0)) {
-		return 500;
-	}
-
-	return 200;
-}
-
-static int mwi_subscription_established(struct ast_sip_subscription *sip_sub)
-{
-	const char *resource = ast_sip_subscription_get_resource_name(sip_sub);
-	struct mwi_subscription *sub;
-	struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sip_sub);
-
-	/* no aor in uri? subscribe to all on endpoint */
-	if (ast_strlen_zero(resource)) {
-		sub = mwi_subscribe_all(endpoint, sip_sub);
-	} else {
-		sub = mwi_subscribe_single(endpoint, sip_sub, resource);
-	}
-
-	if (!sub) {
-		ao2_cleanup(endpoint);
-		return -1;
-	}
-
-	ao2_cleanup(sub);
-	ao2_cleanup(endpoint);
-	return 0;
-}
-
-static void *mwi_get_notify_data(struct ast_sip_subscription *sub)
-{
-	struct ast_sip_message_accumulator *counter;
-	struct mwi_subscription *mwi_sub;
-	struct ast_datastore *mwi_datastore;
-
-	mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
-	if (!mwi_datastore) {
-		return NULL;
-	}
-	mwi_sub = mwi_datastore->data;
-
-	counter = ao2_alloc(sizeof(*counter), NULL);
-	if (!counter) {
-		ao2_cleanup(mwi_datastore);
-		return NULL;
-	}
-
-	ao2_callback(mwi_sub->stasis_subs, OBJ_NODATA, get_message_count, counter);
-	ao2_cleanup(mwi_datastore);
-	return counter;
-}
-
-static void mwi_subscription_mailboxes_str(struct ao2_container *stasis_subs,
-					   struct ast_str **str)
-{
-	int num = ao2_container_count(stasis_subs);
-
-	struct mwi_stasis_subscription *node;
-	struct ao2_iterator i = ao2_iterator_init(stasis_subs, 0);
-
-	while ((node = ao2_iterator_next(&i))) {
-		if (--num) {
-			ast_str_append(str, 0, "%s,", node->mailbox);
-		} else {
-			ast_str_append(str, 0, "%s", node->mailbox);
-		}
-		ao2_ref(node, -1);
-	}
-	ao2_iterator_destroy(&i);
-}
-
-static void mwi_to_ami(struct ast_sip_subscription *sub,
-		       struct ast_str **buf)
-{
-	struct mwi_subscription *mwi_sub;
-	RAII_VAR(struct ast_datastore *, mwi_datastore,
-			ast_sip_subscription_get_datastore(sub, MWI_DATASTORE), ao2_cleanup);
-
-	if (!mwi_datastore) {
-		return;
-	}
-
-	mwi_sub = mwi_datastore->data;
-
-	ast_str_append(buf, 0, "SubscriptionType: mwi\r\n");
-	ast_str_append(buf, 0, "Mailboxes: ");
-	mwi_subscription_mailboxes_str(mwi_sub->stasis_subs, buf);
-	ast_str_append(buf, 0, "\r\n");
-}
-
-static int serialized_notify(void *userdata)
-{
-	struct mwi_subscription *mwi_sub = userdata;
-
-	send_mwi_notify(mwi_sub);
-	ao2_ref(mwi_sub, -1);
-	return 0;
-}
-
-static int serialized_cleanup(void *userdata)
-{
-	struct mwi_subscription *mwi_sub = userdata;
-
-	/* This is getting rid of the reference that was added
-	 * just before this serialized task was pushed.
-	 */
-	ao2_cleanup(mwi_sub);
-	/* This is getting rid of the reference held by the
-	 * stasis subscription
-	 */
-	ao2_cleanup(mwi_sub);
-	return 0;
-}
-
-static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
-		struct stasis_message *msg)
-{
-	struct mwi_subscription *mwi_sub = userdata;
-
-	if (stasis_subscription_final_message(sub, msg)) {
-		ao2_ref(mwi_sub, +1);
-		ast_sip_push_task(NULL, serialized_cleanup, mwi_sub);
-		return;
-	}
-
-	if (ast_mwi_state_type() == stasis_message_type(msg)) {
-		struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
-		ao2_ref(mwi_sub, +1);
-		ast_sip_push_task(serializer, serialized_notify, mwi_sub);
-	}
-}
-
-static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)
-{
-	RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);
-	struct ast_sip_endpoint *endpoint = obj;
-	struct ao2_container *mwi_subscriptions = arg;
-	char *mailboxes;
-	char *mailbox;
-
-	if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) {
-		return 0;
-	}
-
-	if (endpoint->subscription.mwi.aggregate) {
-		aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);
-		if (!aggregate_sub) {
-			return 0;
-		}
-	}
-
-	mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes);
-	while ((mailbox = strsep(&mailboxes, ","))) {
-		struct mwi_subscription *sub = aggregate_sub ?:
-			mwi_subscription_alloc(endpoint, 0, NULL);
-		RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
-				mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
-		if (mwi_stasis_sub) {
-			ao2_link(sub->stasis_subs, mwi_stasis_sub);
-		}
-		if (!aggregate_sub) {
-			ao2_link(mwi_subscriptions, sub);
-			ao2_cleanup(sub);
-		}
-	}
-	if (aggregate_sub) {
-		ao2_link(mwi_subscriptions, aggregate_sub);
-	}
-	return 0;
-}
-
-static int unsubscribe(void *obj, void *arg, int flags)
-{
-	struct mwi_subscription *mwi_sub = obj;
-
-	ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
-	return CMP_MATCH;
-}
-
-static void create_mwi_subscriptions(void)
-{
-	struct ao2_container *mwi_subscriptions = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
-	RAII_VAR(struct ao2_container *, old_mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
-	RAII_VAR(struct ao2_container *, endpoints, ast_sorcery_retrieve_by_fields(
-				ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL),
-			ao2_cleanup);
-
-	if (!mwi_subscriptions) {
-		return;
-	}
-
-	/* We remove all the old stasis subscriptions first before applying the new configuration. This
-	 * prevents a situation where there might be multiple overlapping stasis subscriptions for an
-	 * endpoint for mailboxes. Though there may be mailbox changes during the gap between unsubscribing
-	 * and resubscribing, up-to-date mailbox state will be sent out to the endpoint when the
-	 * new stasis subscription is established
-	 */
-	if (old_mwi_subscriptions) {
-		ao2_callback(old_mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
-	}
-	ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, mwi_subscriptions);
-	ao2_global_obj_replace_unref(unsolicited_mwi, mwi_subscriptions);
-	ao2_ref(mwi_subscriptions, -1);
-}
-
-static int reload(void)
-{
-	create_mwi_subscriptions();
-	return 0;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (ast_sip_register_subscription_handler(&mwi_handler)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	create_mwi_subscriptions();
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	RAII_VAR(struct ao2_container *, mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
-	if (mwi_subscriptions) {
-		ao2_callback(mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
-		ao2_global_obj_release(unsolicited_mwi);
-	}
-	ast_sip_unregister_subscription_handler(&mwi_handler);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP MWI resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.reload = reload,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c
deleted file mode 100644
index cc558ac..0000000
--- a/res/res_pjsip_mwi_body_generator.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-#include "asterisk/module.h"
-#include "asterisk/strings.h"
-
-#define MWI_TYPE "application"
-#define MWI_SUBTYPE "simple-message-summary"
-
-static void *mwi_allocate_body(void *data)
-{
-	struct ast_str **mwi_str;
-
-	mwi_str = ast_malloc(sizeof(*mwi_str));
-	if (!mwi_str) {
-		return NULL;
-	}
-	*mwi_str = ast_str_create(64);
-	if (!*mwi_str) {
-		ast_free(mwi_str);
-		return NULL;
-	}
-	return mwi_str;
-}
-
-static int mwi_generate_body_content(void *body, void *data)
-{
-	struct ast_str **mwi = body;
-	struct ast_sip_message_accumulator *counter = data;
-
-	ast_str_append(mwi, 0, "Messages-Waiting: %s\r\n",
-			counter->new_msgs ? "yes" : "no");
-	ast_str_append(mwi, 0, "Voice-Message: %d/%d (0/0)\r\n",
-			counter->new_msgs, counter->old_msgs);
-
-	return 0;
-}
-
-static void mwi_to_string(void *body, struct ast_str **str)
-{
-	struct ast_str **mwi = body;
-
-	ast_str_set(str, 0, "%s", ast_str_buffer(*mwi));
-}
-
-static void mwi_destroy_body(void *body)
-{
-	struct ast_str **mwi = body;
-
-	ast_free(*mwi);
-	ast_free(mwi);
-}
-
-static struct ast_sip_pubsub_body_generator mwi_generator = {
-	.type = MWI_TYPE,
-	.subtype = MWI_SUBTYPE,
-	.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
-	.allocate_body = mwi_allocate_body,
-	.generate_body_content = mwi_generate_body_content,
-	.to_string = mwi_to_string,
-	.destroy_body = mwi_destroy_body,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_generator(&mwi_generator)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_pubsub_unregister_body_generator(&mwi_generator);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP MWI resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c
deleted file mode 100644
index 5887343..0000000
--- a/res/res_pjsip_nat.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-#include "asterisk/acl.h"
-
-static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	pjsip_contact_hdr *contact;
-
-	if (!endpoint) {
-		return PJ_FALSE;
-	}
-
-	if (endpoint->nat.rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
-		!contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
-		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
-		pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
-
-		pj_cstr(&uri->host, rdata->pkt_info.src_name);
-		if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
-			uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
-		} else {
-			uri->transport_param.slen = 0;
-		}
-		uri->port = rdata->pkt_info.src_port;
-
-		/* rewrite the session target since it may have already been pulled from the contact header */
-		if (dlg && (!dlg->remote.contact
-			|| pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
-			dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
-			dlg->target = dlg->remote.contact->uri;
-		}
-	}
-
-	if (endpoint->nat.force_rport) {
-		rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
-	}
-
-	return PJ_FALSE;
-}
-
-static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
-	return handle_rx_message(endpoint, rdata);
-}
-
-/*! \brief Structure which contains information about a transport */
-struct request_transport_details {
-	/*! \brief Type of transport */
-	enum ast_transport type;
-	/*! \brief Potential pointer to the transport itself, if UDP */
-	pjsip_transport *transport;
-	/*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
-	pjsip_tpfactory *factory;
-	/*! \brief Local address for transport */
-	pj_str_t local_address;
-	/*! \brief Local port for transport */
-	int local_port;
-};
-
-/*! \brief Callback function for finding the transport the request is going out on */
-static int find_transport_in_use(void *obj, void *arg, int flags)
-{
-	struct ast_sip_transport *transport = obj;
-	struct request_transport_details *details = arg;
-
-	/* If an explicit transport or factory matches then this is what is in use, if we are unavailable
-	 * to compare based on that we make sure that the type is the same and the source IP address/port are the same
-	 */
-	if ((details->transport && details->transport == transport->state->transport) ||
-		(details->factory && details->factory == transport->state->factory) ||
-		((details->type == transport->type) && (transport->state->factory) &&
-			!pj_strcmp(&transport->state->factory->addr_name.host, &details->local_address) &&
-			transport->state->factory->addr_name.port == details->local_port)) {
-		return CMP_MATCH | CMP_STOP;
-	}
-
-	return 0;
-}
-
-/*! \brief Helper function which returns the SIP URI of a Contact header */
-static pjsip_sip_uri *nat_get_contact_sip_uri(pjsip_tx_data *tdata)
-{
-	pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
-
-	if (!contact || (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
-		return NULL;
-	}
-
-	return pjsip_uri_get_uri(contact->uri);
-}
-
-/*! \brief Structure which contains hook details */
-struct nat_hook_details {
-	/*! \brief Outgoing message itself */
-	pjsip_tx_data *tdata;
-	/*! \brief Chosen transport */
-	struct ast_sip_transport *transport;
-};
-
-/*! \brief Callback function for invoking hooks */
-static int nat_invoke_hook(void *obj, void *arg, int flags)
-{
-	struct ast_sip_nat_hook *hook = obj;
-	struct nat_hook_details *details = arg;
-
-	if (hook->outgoing_external_message) {
-		hook->outgoing_external_message(details->tdata, details->transport);
-	}
-
-	return 0;
-}
-
-static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
-{
-	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-	struct request_transport_details details = { 0, };
-	pjsip_via_hdr *via = NULL;
-	struct ast_sockaddr addr = { { 0, } };
-	pjsip_sip_uri *uri = NULL;
-	RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
-
-	/* If a transport selector is in use we know the transport or factory, so explicitly find it */
-	if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
-		details.transport = tdata->tp_sel.u.transport;
-	} else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
-		details.factory = tdata->tp_sel.u.listener;
-	} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
-		/* Connectionless uses the same transport for all requests */
-		details.type = AST_TRANSPORT_UDP;
-		details.transport = tdata->tp_info.transport;
-	} else {
-		if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
-			details.type = AST_TRANSPORT_TCP;
-		} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
-			details.type = AST_TRANSPORT_TLS;
-		} else {
-			/* Unknown transport type, we can't map and thus can't apply NAT changes */
-			return PJ_SUCCESS;
-		}
-
-		if ((uri = nat_get_contact_sip_uri(tdata))) {
-			details.local_address = uri->host;
-			details.local_port = uri->port;
-		} else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
-			(via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
-			details.local_address = via->sent_by.host;
-			details.local_port = via->sent_by.port;
-		} else {
-			return PJ_SUCCESS;
-		}
-
-		if (!details.local_port) {
-			details.local_port = (details.type == AST_TRANSPORT_TLS) ? 5061 : 5060;
-		}
-	}
-
-	if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
-		!(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
-		ast_sockaddr_isnull(&transport->external_address)) {
-		return PJ_SUCCESS;
-	}
-
-	ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
-	ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
-
-	/* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
-	if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
-		return PJ_SUCCESS;
-	}
-
-	/* Update the contact header with the external address */
-	if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
-		pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
-		if (transport->external_signaling_port) {
-			uri->port = transport->external_signaling_port;
-		}
-	}
-
-	/* Update the via header if relevant */
-	if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
-		pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address));
-		if (transport->external_signaling_port) {
-			via->sent_by.port = transport->external_signaling_port;
-		}
-	}
-
-	/* Invoke any additional hooks that may be registered */
-	if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		struct nat_hook_details hook_details = {
-			.tdata = tdata,
-			.transport = transport,
-		};
-		ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pjsip_module nat_module = {
-	.name = { "NAT", 3 },
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
-	.on_rx_request = nat_on_rx_message,
-	.on_rx_response = nat_on_rx_message,
-	.on_tx_request = nat_on_tx_message,
-	.on_tx_response = nat_on_tx_message,
-};
-
-/*! \brief Function called when an INVITE goes out */
-static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
-		pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
-	}
-
-	return 0;
-}
-
-/*! \brief Function called when an INVITE response comes in */
-static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	handle_rx_message(session->endpoint, rdata);
-}
-
-/*! \brief Function called when an INVITE comes in */
-static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
-		pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
-	}
-}
-
-/*! \brief Supplement for adding NAT functionality to dialog */
-static struct ast_sip_session_supplement nat_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
-	.incoming_request = nat_incoming_invite_request,
-	.outgoing_request = nat_outgoing_invite_request,
-	.incoming_response = nat_incoming_invite_response,
-};
-
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&nat_supplement);
-	ast_sip_unregister_service(&nat_module);
-	return 0;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (ast_sip_register_service(&nat_module)) {
-		ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (ast_sip_session_register_supplement(&nat_supplement)) {
-		ast_log(LOG_ERROR, "Could not register NAT session supplement for incoming and outgoing INVITE requests\n");
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP NAT Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c
deleted file mode 100644
index d7e3d80..0000000
--- a/res/res_pjsip_notify.c
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/cli.h"
-#include "asterisk/config.h"
-#include "asterisk/manager.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/sorcery.h"
-
-/*** DOCUMENTATION
-	<manager name="PJSIPNotify" language="en_US">
-		<synopsis>
-			Send a NOTIFY to either an endpoint or an arbitrary URI.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Endpoint" required="false">
-				<para>The endpoint to which to send the NOTIFY.</para>
-			</parameter>
-			<parameter name="URI" required="false">
-				<para>Abritrary URI to which to send the NOTIFY.</para>
-			</parameter>
-			<parameter name="Variable" required="true">
-				<para>Appends variables as headers/content to the NOTIFY. If the variable is
-				named <literal>Content</literal>, then the value will compose the body
-				of the message if another variable sets <literal>Content-Type</literal>.
-				<replaceable>name</replaceable>=<replaceable>value</replaceable></para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Sends a NOTIFY to an endpoint or an arbitrary URI.</para>
-			<para>All parameters for this event must be specified in the body of this
-			request	via multiple <literal>Variable: name=value</literal> sequences.</para>
-			<note><para>One (and only one) of <literal>Endpoint</literal> or
-			<literal>URI</literal> must be specified. If <literal>URI</literal> is used,
-			the	default outbound endpoint will be used to send the message. If the default
-			outbound endpoint isn't configured, this command can not send to an arbitrary
-			URI.</para></note>
-		</description>
-	</manager>
-	<configInfo name="res_pjsip_notify" language="en_US">
-		<synopsis>Module that supports sending NOTIFY requests to endpoints from external sources</synopsis>
-		<configFile name="pjsip_notify.conf">
-			<configObject name="general">
-				<synopsis>Unused, but reserved.</synopsis>
-			</configObject>
-			<configObject name="notify">
-				<synopsis>Configuration of a NOTIFY request.</synopsis>
-				<description>
-					<para>Each key-value pair in a <literal>notify</literal>
-					configuration section defines either a SIP header to send
-					in the request or a line of content in the request message
-					body. A key of <literal>Content</literal> is treated
-					as part of the message body and is appended in sequential
-					order; any other header is treated as part of the SIP
-					request.</para>
-				</description>
-				<configOption name="^.*$">
-					<synopsis>A key/value pair to add to a NOTIFY request.</synopsis>
-					<description>
-						<para>If the key is <literal>Content</literal>,
-						it will be treated as part of the message body. Otherwise,
-						it will be added as a header in the NOTIFY request.</para>
-						<para>The following headers are reserved and cannot be
-						specified:</para>
-						<enumlist>
-							<enum name="Call-ID" />
-							<enum name="Contact" />
-							<enum name="CSeq" />
-							<enum name="To" />
-							<enum name="From" />
-							<enum name="Record-Route" />
-							<enum name="Route" />
-							<enum name="Via" />
-						</enumlist>
-					</description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-#define CONTENT_TYPE_SIZE 64
-#define CONTENT_SIZE 512
-
-/*!
- * \internal
- * \brief The configuration file containing NOTIFY payload types to send.
- */
-static const char notify_config[] = "pjsip_notify.conf";
-
-struct notify_option_item {
-	const char *name;
-	const char *value;
-	char buf[0];
-};
-
-struct notify_option {
-	/*! Contains header and/or content information */
-	struct ao2_container *items;
-	/*! The name of the notify option */
-	char name[0];
-};
-
-static int notify_option_hash(const void *obj, int flags)
-{
-	const struct notify_option *option = obj;
-	return ast_str_case_hash(flags & OBJ_KEY ? obj : option->name);
-}
-
-static int notify_option_cmp(void *obj, void *arg, int flags)
-{
-	struct notify_option *option1 = obj;
-	struct notify_option *option2 = arg;
-	const char *key = flags & OBJ_KEY ? arg : option2->name;
-
-	return strcasecmp(option1->name, key) ? 0 : CMP_MATCH;
-}
-
-static void notify_option_destroy(void *obj)
-{
-	struct notify_option *option = obj;
-	ao2_cleanup(option->items);
-}
-
-static void *notify_option_alloc(const char *category)
-{
-	int category_size = strlen(category) + 1;
-
-	struct notify_option *option = ao2_alloc(
-		sizeof(*option) + category_size, notify_option_destroy);
-
-	if (!option) {
-		return NULL;
-	}
-
-	ast_copy_string(option->name, category, category_size);
-
-	if (!(option->items = ao2_container_alloc_list(
-		      AO2_ALLOC_OPT_LOCK_NOLOCK,
-		      AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW, NULL, NULL))) {
-		ao2_cleanup(option);
-		return NULL;
-	}
-
-	return option;
-}
-
-static void *notify_option_find(struct ao2_container *container, const char *category)
-{
-	return ao2_find(container, category, OBJ_KEY);
-}
-
-static int notify_option_handler(const struct aco_option *opt,
-				 struct ast_variable *var, void *obj)
-{
-	struct notify_option *option = obj;
-
-	int name_size = strlen(var->name) + 1;
-	int value_size = strlen(var->value) + 1;
-
-	RAII_VAR(struct notify_option_item *, item,
-		 ao2_alloc(sizeof(*item) + name_size + value_size,
-			   NULL), ao2_cleanup);
-
-	item->name = item->buf;
-	item->value = item->buf + name_size;
-
-	ast_copy_string(item->buf, var->name, name_size);
-	ast_copy_string(item->buf + name_size, var->value, value_size);
-
-	if (!ao2_link(option->items, item)) {
-		return -1;
-	}
-
-	return 0;
-}
-
-struct notify_cfg {
-	struct ao2_container *notify_options;
-};
-
-static void notify_cfg_destroy(void *obj)
-{
-	struct notify_cfg *cfg = obj;
-	ao2_cleanup(cfg->notify_options);
-}
-
-static void *notify_cfg_alloc(void)
-{
-	struct notify_cfg *cfg;
-
-	if (!(cfg = ao2_alloc(sizeof(*cfg), notify_cfg_destroy))) {
-		return NULL;
-	}
-
-	if (!(cfg->notify_options = ao2_container_alloc_options(
-		      AO2_ALLOC_OPT_LOCK_NOLOCK, 20, notify_option_hash,
-		      notify_option_cmp))) {
-		ao2_cleanup(cfg);
-		return NULL;
-	}
-
-	return cfg;
-}
-
-static struct aco_type notify_option = {
-	.type = ACO_ITEM,
-	.name = "notify",
-	.category_match = ACO_BLACKLIST,
-	.category = "^general$",
-	.item_offset = offsetof(struct notify_cfg, notify_options),
-	.item_alloc = notify_option_alloc,
-	.item_find = notify_option_find
-};
-
-static struct aco_type *notify_options[] = ACO_TYPES(&notify_option);
-
-static struct aco_file module_conf = {
-	.filename = notify_config,
-	.types = ACO_TYPES(&notify_option),
-};
-
-AO2_GLOBAL_OBJ_STATIC(globals);
-
-CONFIG_INFO_STANDARD(notify_cfg, globals, notify_cfg_alloc,
-	.files = ACO_FILES(&module_conf)
-);
-
-/*!
- * \internal
- * \brief Structure to hold task data for notifications.
- */
-struct notify_data {
-	/*! The endpoint being notified */
-	struct ast_sip_endpoint *endpoint;
-	/*! The info of headers, types and content */
-	void *info;
-	/*! Function to help build notify request */
-	void (*build_notify)(pjsip_tx_data *, void *);
-};
-
-/*!
- * \internal
- * \brief Destroy the notify CLI data releasing any resources.
- */
-static void notify_cli_data_destroy(void *obj)
-{
-	struct notify_data *data = obj;
-
-	ao2_cleanup(data->endpoint);
-	ao2_cleanup(data->info);
-}
-
-/*!
- * \internal
- * \brief Structure to hold task data for notifications (URI variant)
- */
-struct notify_uri_data {
-	char *uri;
-	void *info;
-	void (*build_notify)(pjsip_tx_data *, void *);
-};
-
-static void notify_cli_uri_data_destroy(void *obj)
-{
-	struct notify_uri_data *data = obj;
-
-	ast_free(data->uri);
-	ao2_cleanup(data->info);
-}
-
-/*!
- * \internal
- * \brief Destroy the notify CLI data releasing any resources (URI variant)
- */
-static void build_cli_notify(pjsip_tx_data *tdata, void *info);
-
-/*!
- * \internal
- * \brief Construct a notify data object for CLI.
- */
-static struct notify_data* notify_cli_data_create(
-	struct ast_sip_endpoint *endpoint, void *info)
-{
-	struct notify_data *data = ao2_alloc(sizeof(*data),
-					     notify_cli_data_destroy);
-	if (!data) {
-		return NULL;
-	}
-
-	data->endpoint = endpoint;
-	ao2_ref(data->endpoint, +1);
-
-	data->info = info;
-	ao2_ref(data->info, +1);
-
-	data->build_notify = build_cli_notify;
-
-	return data;
-}
-
-/*!
- * \internal
- * \brief Construct a notify URI data object for CLI.
- */
-static struct notify_uri_data* notify_cli_uri_data_create(
-	const char *uri, void *info)
-{
-	struct notify_uri_data *data = ao2_alloc(sizeof(*data),
-		notify_cli_uri_data_destroy);
-
-	if (!data) {
-		return NULL;
-	}
-
-	data->uri = ast_strdup(uri);
-	if (!data->uri) {
-		ao2_ref(data, -1);
-		return NULL;
-	}
-
-	data->info = info;
-	ao2_ref(data->info, +1);
-
-	data->build_notify = build_cli_notify;
-
-	return data;
-}
-
-/*!
- * \internal
- * \brief Destroy the notify AMI data releasing any resources.
- */
-static void notify_ami_data_destroy(void *obj)
-{
-	struct notify_data *data = obj;
-	struct ast_variable *info = data->info;
-
-	ao2_cleanup(data->endpoint);
-	ast_variables_destroy(info);
-}
-
-/*!
- * \internal
- * \brief Destroy the notify AMI URI data releasing any resources.
- */
-static void notify_ami_uri_data_destroy(void *obj)
-{
-	struct notify_uri_data *data = obj;
-	struct ast_variable *info = data->info;
-
-	ast_free(data->uri);
-	ast_variables_destroy(info);
-}
-
-static void build_ami_notify(pjsip_tx_data *tdata, void *info);
-
-/*!
- * \internal
- * \brief Construct a notify data object for AMI.
- */
-static struct notify_data* notify_ami_data_create(
-	struct ast_sip_endpoint *endpoint, void *info)
-{
-	struct notify_data *data = ao2_alloc(sizeof(*data),
-					     notify_ami_data_destroy);
-	if (!data) {
-		return NULL;
-	}
-
-	data->endpoint = endpoint;
-	ao2_ref(data->endpoint, +1);
-
-	data->info = info;
-	data->build_notify = build_ami_notify;
-
-	return data;
-}
-
-/*!
- * \internal
- * \brief Construct a notify URI data object for AMI.
- */
-static struct notify_uri_data* notify_ami_uri_data_create(
-	const char *uri, void *info)
-{
-	struct notify_uri_data *data = ao2_alloc(sizeof(*data),
-							notify_ami_uri_data_destroy);
-	if (!data) {
-		return NULL;
-	}
-
-	data->uri = ast_strdup(uri);
-	if (!data->uri) {
-		ao2_ref(data, -1);
-		return NULL;
-	}
-
-	data->info = info;
-	data->build_notify = build_ami_notify;
-
-	return data;
-}
-
-/*!
- * \internal
- * \brief Checks if the given header name is not allowed.
- *
- * \details Some headers are not allowed to be set by the user within the
- *          scope of a NOTIFY request.  If the given var header name is
- *          found in the "not allowed" list then return true.
- */
-static int not_allowed(const char *name)
-{
-	int i;
-	static const char *names[] = {
-		"Call-ID",
-		"Contact",
-		"CSeq",
-		"To",
-		"From",
-		"Record-Route",
-		"Route",
-		"Request-URI",
-		"Via",
-	};
-
-	for (i = 0; i < ARRAY_LEN(names); ++i) {
-		if (!strcasecmp(name, names[i])) {
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief If a content type was specified add it and the content body to the
- *        NOTIFY request.
- */
-static void build_notify_body(pjsip_tx_data *tdata, struct ast_str *content_type,
-			      struct ast_str *content)
-{
-	if (content_type) {
-		char *p;
-		struct ast_sip_body body;
-
-		if (content) {
-			body.body_text = ast_str_buffer(content);
-		}
-
-		body.type = ast_str_buffer(content_type);
-		if ((p = strchr(body.type, '/'))) {
-			*p++ = '\0';
-			body.subtype = p;
-		}
-		ast_sip_add_body(tdata, &body);
-	}
-}
-
-/*!
- * \internal
- * \brief Build the NOTIFY request adding content or header info.
- */
-static void build_notify(pjsip_tx_data *tdata, const char *name, const char *value,
-			 struct ast_str **content_type, struct ast_str **content)
-{
-	if (not_allowed(name)) {
-		ast_log(LOG_WARNING, "Cannot specify %s header, "
-			"ignoring\n", name);
-		return;
-	}
-
-	if (!strcasecmp(name, "Content-type")) {
-		if (!(*content_type)) {
-			*content_type = ast_str_create(CONTENT_TYPE_SIZE);
-		}
-		ast_str_set(content_type, 0,"%s", value);
-	} else if (!strcasecmp(name, "Content")) {
-		if (!(*content)) {
-			*content = ast_str_create(CONTENT_SIZE);
-		}
-
-		if (ast_str_strlen(*content)) {
-			ast_str_append(content, 0, "\r\n");
-		}
-		ast_str_append(content, 0, "%s", value);
-	} else {
-		ast_sip_add_header(tdata, name, value);
-	}
-}
-
-/*!
- * \internal
- * \brief Build the NOTIFY request from CLI info adding header and content
- *        when specified.
- */
-static void build_cli_notify(pjsip_tx_data *tdata, void *info)
-{
-	struct notify_option *option = info;
-	RAII_VAR(struct ast_str *, content_type, NULL, ast_free);
-	RAII_VAR(struct ast_str *, content, NULL, ast_free);
-
-	struct notify_option_item *item;
-	struct ao2_iterator i = ao2_iterator_init(option->items, 0);
-
-	while ((item = ao2_iterator_next(&i))) {
-		build_notify(tdata, item->name, item->value,
-			     &content_type, &content);
-		ao2_cleanup(item);
-	}
-	ao2_iterator_destroy(&i);
-
-	build_notify_body(tdata, content_type, content);
-}
-
-/*!
- * \internal
- * \brief Build the NOTIFY request from AMI info adding header and content
- *        when specified.
- */
-static void build_ami_notify(pjsip_tx_data *tdata, void *info)
-{
-	struct ast_variable *vars = info;
-	RAII_VAR(struct ast_str *, content_type, NULL, ast_free);
-	RAII_VAR(struct ast_str *, content, NULL, ast_free);
-	struct ast_variable *i;
-
-	for (i = vars; i; i = i->next) {
-		if (!strcasecmp(i->name, "Content-Length")) {
-			ast_log(LOG_NOTICE, "It is not necessary to specify Content-Length, ignoring.\n");
-			continue;
-		}
-		build_notify(tdata, i->name, i->value,
-			     &content_type, &content);
-	}
-
-	build_notify_body(tdata, content_type, content);
-}
-
-/*!
- * \internal
- * \brief Build and send a NOTIFY request to a contact.
- */
-static int notify_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	struct notify_data *data = arg;
-	pjsip_tx_data *tdata;
-
-	if (ast_sip_create_request("NOTIFY", NULL, data->endpoint,
-				   NULL, contact, &tdata)) {
-		ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
-			"contact %s\n",	contact->uri);
-		return -1;
-	}
-
-	ast_sip_add_header(tdata, "Subscription-State", "terminated");
-	data->build_notify(tdata, data->info);
-
-	if (ast_sip_send_request(tdata, NULL, data->endpoint, NULL, NULL)) {
-		ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
-			"contact %s\n",	contact->uri);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Send a NOTIFY request to the endpoint.
- *
- * \detail Iterates over an endpoint's AORs sending a NOTIFY request
- *         with the appropriate payload information to each contact.
- */
-static int notify_endpoint(void *obj)
-{
-	RAII_VAR(struct notify_data *, data, obj, ao2_cleanup);
-	char *aor_name, *aors;
-
-	if (ast_strlen_zero(data->endpoint->aors)) {
-		ast_log(LOG_WARNING, "Unable to NOTIFY - "
-			"endpoint has no configured AORs\n");
-		return -1;
-	}
-
-	aors = ast_strdupa(data->endpoint->aors);
-
-	while ((aor_name = strsep(&aors, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor,
-			 ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
-		if (!aor || !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
-			continue;
-		}
-
-		ao2_callback(contacts, OBJ_NODATA, notify_contact, data);
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Send a notify request to the URI.
- */
-static int notify_uri(void *obj)
-{
-	RAII_VAR(struct notify_uri_data *, data, obj, ao2_cleanup);
-	RAII_VAR(struct ast_sip_endpoint *, endpoint,
-		ast_sip_default_outbound_endpoint(), ao2_cleanup);
-	pjsip_tx_data *tdata;
-
-	if (!endpoint) {
-		ast_log(LOG_WARNING, "No default outbound endpoint set, can not send "
-			"NOTIFY requests to arbitrary URIs.\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(data->uri)) {
-		ast_log(LOG_WARNING, "Unable to NOTIFY - URI is blank.\n");
-		return -1;
-	}
-
-	if (ast_sip_create_request("NOTIFY", NULL, endpoint,
-				   data->uri, NULL, &tdata)) {
-		ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
-			"uri %s\n",	data->uri);
-		return -1;
-	}
-
-	ast_sip_add_header(tdata, "Subscription-State", "terminated");
-
-	data->build_notify(tdata, data->info);
-
-	if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
-		ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
-			"uri %s\n",	data->uri);
-		return -1;
-	}
-
-	return 0;
-}
-
-enum notify_result {
-	SUCCESS,
-	INVALID_ENDPOINT,
-	ALLOC_ERROR,
-	TASK_PUSH_ERROR
-};
-
-typedef struct notify_data *(*task_data_create)(
-	struct ast_sip_endpoint *, void *info);
-
-typedef struct notify_uri_data *(*task_uri_data_create)(
-	const char *uri, void *info);
-/*!
- * \internal
- * \brief Send a NOTIFY request to the endpoint within a threaded task.
- */
-static enum notify_result push_notify(const char *endpoint_name, void *info,
-				      task_data_create data_create)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	struct notify_data *data;
-
-	if (!(endpoint = ast_sorcery_retrieve_by_id(
-		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
-		return INVALID_ENDPOINT;
-	}
-
-	if (!(data = data_create(endpoint, info))) {
-		return ALLOC_ERROR;
-	}
-
-	if (ast_sip_push_task(NULL, notify_endpoint, data)) {
-		ao2_cleanup(data);
-		return TASK_PUSH_ERROR;
-	}
-
-	return SUCCESS;
-}
-
-/*!
- * \internal
- * \brief Send a NOTIFY request to the URI within an threaded task.
- */
-static enum notify_result push_notify_uri(const char *uri, void *info,
-	task_uri_data_create data_create)
-{
-	struct notify_uri_data *data;
-
-	if (!(data = data_create(uri, info))) {
-		return ALLOC_ERROR;
-	}
-
-	if (ast_sip_push_task(NULL, notify_uri, data)) {
-		ao2_cleanup(data);
-		return TASK_PUSH_ERROR;
-	}
-
-	return SUCCESS;
-}
-
-/*!
- * \internal
- * \brief Do completion on the endpoint.
- */
-static char *cli_complete_endpoint(const char *word, int state)
-{
-	char *result = NULL;
-	int wordlen = strlen(word);
-	int which = 0;
-
-	struct ast_sip_endpoint *endpoint;
-	RAII_VAR(struct ao2_container *, endpoints,
-		 ast_sip_get_endpoints(), ao2_cleanup);
-
-	struct ao2_iterator i = ao2_iterator_init(endpoints, 0);
-	while ((endpoint = ao2_iterator_next(&i))) {
-		const char *name = ast_sorcery_object_get_id(endpoint);
-		if (!strncasecmp(word, name, wordlen) && ++which > state) {
-			result = ast_strdup(name);
-		}
-
-		ao2_cleanup(endpoint);
-		if (result) {
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-	return result;
-}
-
-/*!
- * \internal
- * \brief Do completion on the notify CLI command.
- */
-static char *cli_complete_notify(const char *line, const char *word,
-				 int pos, int state, int using_uri)
-{
-	char *c = NULL;
-
-	if (pos == 3) {
-		int which = 0;
-		int wordlen = strlen(word);
-
-		RAII_VAR(struct notify_cfg *, cfg,
-			 ao2_global_obj_ref(globals), ao2_cleanup);
-		struct notify_option *option;
-
-		/* do completion for notify type */
-		struct ao2_iterator i = ao2_iterator_init(cfg->notify_options, 0);
-		while ((option = ao2_iterator_next(&i))) {
-			if (!strncasecmp(word, option->name, wordlen) && ++which > state) {
-				c = ast_strdup(option->name);
-			}
-
-			ao2_cleanup(option);
-			if (c) {
-				break;
-			}
-		}
-		ao2_iterator_destroy(&i);
-		return c;
-	}
-
-	if (pos == 4) {
-		int wordlen = strlen(word);
-
-		if (ast_strlen_zero(word)) {
-		    if (state == 0) {
-		        c = ast_strdup("endpoint");
-		    } else if (state == 1) {
-		        c = ast_strdup("uri");
-		    }
-		} else if (state == 0) {
-		    if (!strncasecmp(word, "endpoint", wordlen)) {
-		        c = ast_strdup("endpoint");
-		    } else if (!strncasecmp(word, "uri", wordlen)) {
-		        c = ast_strdup("uri");
-		    }
-		}
-
-		return c;
-	}
-
-	return pos > 4 && !using_uri ? cli_complete_endpoint(word, state) : NULL;
-}
-
-/*!
- * \internal
- * \brief CLI command to send a SIP notify to an endpoint.
- *
- * \details Attempts to match the "type" given in the CLI command to a
- *          configured one.  If found, sends a NOTIFY to the endpoint
- *          with the associated payload.
- */
-static char *cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup);
-	RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup);
-
-	int i;
-	int using_uri = 0;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip send notify";
-		e->usage =
-			"Usage: pjsip send notify <type> {endpoint|uri} <peer> [<peer>...]\n"
-			"       Send a NOTIFY request to an endpoint\n"
-			"       Message types are defined in sip_notify.conf\n";
-		return NULL;
-	case CLI_GENERATE:
-		if (a->argc > 4 && (!strcasecmp(a->argv[4], "uri"))) {
-			using_uri = 1;
-		}
-
-		return cli_complete_notify(a->line, a->word, a->pos, a->n, using_uri);
-	}
-
-	if (a->argc < 6) {
-		return CLI_SHOWUSAGE;
-	}
-
-	if (!strcasecmp(a->argv[4], "uri")) {
-		using_uri = 1;
-	} else if (strcasecmp(a->argv[4], "endpoint")) {
-		return CLI_SHOWUSAGE;
-	}
-
-	cfg = ao2_global_obj_ref(globals);
-
-	if (!(option = notify_option_find(cfg->notify_options, a->argv[3])))
-	{
-		ast_cli(a->fd, "Unable to find notify type '%s'\n",
-			a->argv[3]);
-		return CLI_FAILURE;
-	}
-
-	for (i = 5; i < a->argc; ++i) {
-		ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n",
-			a->argv[3], a->argv[i]);
-
-		switch (using_uri ? push_notify_uri(a->argv[i], option, notify_cli_uri_data_create) :
-		                    push_notify(a->argv[i], option, notify_cli_data_create)) {
-		case INVALID_ENDPOINT:
-			ast_cli(a->fd, "Unable to retrieve endpoint %s\n",
-				a->argv[i]);
-			break;
-		case ALLOC_ERROR:
-			ast_cli(a->fd, "Unable to allocate NOTIFY task data\n");
-			return CLI_FAILURE;
-		case TASK_PUSH_ERROR:
-			ast_cli(a->fd, "Unable to push NOTIFY task\n");
-			return CLI_FAILURE;
-		default:
-			break;
-		}
-	}
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_options[] = {
-	AST_CLI_DEFINE(cli_notify, "Send a NOTIFY request to a SIP endpoint")
-};
-
-/*!
- * \interanl
- * \brief Completes SIPNotify AMI command in Endpoint mode.
- */
-static void manager_notify_endpoint(struct mansession *s,
-	const struct message *m, const char *endpoint_name)
-{
-	struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL);
-
-	if (!strncasecmp(endpoint_name, "sip/", 4)) {
-		endpoint_name += 4;
-	}
-
-	if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
-		endpoint_name += 6;
-	}
-
-	switch (push_notify(endpoint_name, vars, notify_ami_data_create)) {
-	case INVALID_ENDPOINT:
-		ast_variables_destroy(vars);
-		astman_send_error_va(s, m, "Unable to retrieve endpoint %s",
-			endpoint_name);
-		break;
-	case ALLOC_ERROR:
-		ast_variables_destroy(vars);
-		astman_send_error(s, m, "Unable to allocate NOTIFY task data");
-		break;
-	case TASK_PUSH_ERROR:
-		/* Don't need to destroy vars since it is handled by cleanup in push_notify */
-		astman_send_error(s, m, "Unable to push NOTIFY task");
-		break;
-	case SUCCESS:
-		astman_send_ack(s, m, "NOTIFY sent");
-		break;
-	}
-}
-
-/*!
- * \internal
- * \brief Completes SIPNotify AMI command in URI mode.
- */
-static void manager_notify_uri(struct mansession *s,
-	const struct message *m, const char *uri)
-{
-	struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL);
-
-	switch (push_notify_uri(uri, vars, notify_ami_uri_data_create)) {
-	case INVALID_ENDPOINT:
-		/* Shouldn't be possible. */
-		ast_assert(0);
-		break;
-	case ALLOC_ERROR:
-		ast_variables_destroy(vars);
-		astman_send_error(s, m, "Unable to allocate NOTIFY task data");
-		break;
-	case TASK_PUSH_ERROR:
-		/* Don't need to destroy vars since it is handled by cleanup in push_notify_uri */
-		astman_send_error(s, m, "Unable to push Notify task");
-		break;
-	case SUCCESS:
-		astman_send_ack(s, m, "NOTIFY sent");
-		break;
-	}
-}
-
-/*!
- * \internal
- * \brief AMI entry point to send a SIP notify to an endpoint.
- */
-static int manager_notify(struct mansession *s, const struct message *m)
-{
-	const char *endpoint_name = astman_get_header(m, "Endpoint");
-	const char *uri = astman_get_header(m, "URI");
-
-	if (!ast_strlen_zero(endpoint_name) && !ast_strlen_zero(uri)) {
-		astman_send_error(s, m, "PJSIPNotify action can not handle a request specifying "
-			"both 'URI' and 'Endpoint'. You must use only one of the two.\n");
-	} else if (!ast_strlen_zero(endpoint_name)) {
-		manager_notify_endpoint(s, m, endpoint_name);
-	} else if (!ast_strlen_zero(uri)) {
-		manager_notify_uri(s, m, uri);
-	} else {
-		astman_send_error(s, m, "PJSIPNotify requires either an endpoint name or a SIP URI.");
-	}
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (aco_info_init(&notify_cfg)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	aco_option_register_custom(&notify_cfg, "^.*$", ACO_REGEX, notify_options,
-				   "", notify_option_handler, 0);
-
-	if (aco_process_config(&notify_cfg, 0)) {
-		aco_info_destroy(&notify_cfg);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
-	ast_manager_register_xml("PJSIPNotify", EVENT_FLAG_SYSTEM, manager_notify);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	if (aco_process_config(&notify_cfg, 1) == ACO_PROCESS_ERROR) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_manager_unregister("PJSIPNotify");
-	ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options));
-	aco_info_destroy(&notify_cfg);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "CLI/AMI PJSIP NOTIFY Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c
deleted file mode 100644
index 8b1ff9d..0000000
--- a/res/res_pjsip_one_touch_record_info.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, malleable, llc.
- *
- * Sean Bright <sean at malleable.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	 <depend>pjproject</depend>
-	 <depend>res_pjsip</depend>
-	 <depend>res_pjsip_session</depend>
-	 <support_level>core</support_level>
-***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/features.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-#include "asterisk/features_config.h"
-
-static void send_response(struct ast_sip_session *session, int code, struct pjsip_rx_data *rdata)
-{
-	pjsip_tx_data *tdata;
-
-	if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) {
-		struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-
-		pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
-	}
-}
-
-static int handle_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	static const pj_str_t rec_str = { "Record", 6 };
-	pjsip_generic_string_hdr *record;
-	int feature_res;
-	char feature_code[AST_FEATURE_MAX_LEN];
-	const char *feature;
-	char *digit;
-
-	record = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &rec_str, NULL);
-
-	/* If we don't have Record header, we have nothing to do */
-	if (!record) {
-		return 0;
-	}
-
-	if (!pj_stricmp2(&record->hvalue, "on")) {
-		feature = session->endpoint->info.recording.onfeature;
-	} else if (!pj_stricmp2(&record->hvalue, "off")) {
-		feature = session->endpoint->info.recording.offfeature;
-	} else {
-		/* Don't send response because another module may handle this */
-		return 0;
-	}
-
-	if (!session->channel) {
-		send_response(session, 481, rdata);
-		return 0;
-	}
-
-	/* Is this endpoint configured with One Touch Recording? */
-	if (!session->endpoint->info.recording.enabled || ast_strlen_zero(feature)) {
-		send_response(session, 403, rdata);
-		return 0;
-	}
-
-	ast_channel_lock(session->channel);
-	feature_res = ast_get_feature(session->channel, feature, feature_code, sizeof(feature_code));
-	ast_channel_unlock(session->channel);
-
-	if (feature_res || ast_strlen_zero(feature_code)) {
-		send_response(session, 403, rdata);
-		return 0;
-	}
-
-	for (digit = feature_code; *digit; ++digit) {
-		struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit, .len = 100 };
-		ast_queue_frame(session->channel, &f);
-	}
-
-	send_response(session, 200, rdata);
-
-	return 0;
-}
-
-static struct ast_sip_session_supplement info_supplement = {
-	.method = "INFO",
-	.incoming_request = handle_incoming_request,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (ast_sip_session_register_supplement(&info_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register One Touch Recording supplement\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&info_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP INFO One Touch Recording Support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_APP_DEPEND,
-	);
diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c
deleted file mode 100644
index 64238a8..0000000
--- a/res/res_pjsip_outbound_authenticator_digest.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/strings.h"
-
-static pjsip_www_authenticate_hdr *get_auth_header(pjsip_rx_data *challenge) {
-	pjsip_hdr_e search_type;
-
-	if (challenge->msg_info.msg->line.status.code == PJSIP_SC_UNAUTHORIZED) {
-		search_type = PJSIP_H_WWW_AUTHENTICATE;
-	} else if (challenge->msg_info.msg->line.status.code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) {
-		search_type = PJSIP_H_PROXY_AUTHENTICATE;
-	} else {
-		ast_log(LOG_ERROR,
-				"Status code %d was received when it should have been 401 or 407.\n",
-				challenge->msg_info.msg->line.status.code);
-		return NULL ;
-	}
-
-	return pjsip_msg_find_hdr(challenge->msg_info.msg, search_type, NULL);
-
-}
-
-static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess,
-		const struct ast_sip_auth_vector *auth_vector, pjsip_rx_data *challenge)
-{
-	size_t auth_size = AST_VECTOR_SIZE(auth_vector);
-	struct ast_sip_auth **auths = ast_alloca(auth_size * sizeof(*auths));
-	pjsip_cred_info *auth_creds = ast_alloca(auth_size * sizeof(*auth_creds));
-	pjsip_www_authenticate_hdr *auth_hdr = NULL;
-	int res = 0;
-	int i;
-
-	if (ast_sip_retrieve_auths(auth_vector, auths)) {
-		res = -1;
-		goto cleanup;
-	}
-
-	auth_hdr = get_auth_header(challenge);
-	if (auth_hdr == NULL) {
-		res = -1;
-		ast_log(LOG_ERROR, "Unable to find authenticate header in challenge.\n");
-		goto cleanup;
-	}
-
-	for (i = 0; i < auth_size; ++i) {
-		if (ast_strlen_zero(auths[i]->realm)) {
-			auth_creds[i].realm = auth_hdr->challenge.common.realm;
-		} else {
-			pj_cstr(&auth_creds[i].realm, auths[i]->realm);
-		}
-		pj_cstr(&auth_creds[i].username, auths[i]->auth_user);
-		pj_cstr(&auth_creds[i].scheme, "digest");
-		switch (auths[i]->type) {
-		case AST_SIP_AUTH_TYPE_USER_PASS:
-			pj_cstr(&auth_creds[i].data, auths[i]->auth_pass);
-			auth_creds[i].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
-			break;
-		case AST_SIP_AUTH_TYPE_MD5:
-			pj_cstr(&auth_creds[i].data, auths[i]->md5_creds);
-			auth_creds[i].data_type = PJSIP_CRED_DATA_DIGEST;
-			break;
-		case AST_SIP_AUTH_TYPE_ARTIFICIAL:
-			ast_log(LOG_ERROR, "Trying to set artificial outbound auth credentials shouldn't happen.\n");
-			break;
-		}
-	}
-
-	pjsip_auth_clt_set_credentials(auth_sess, auth_size, auth_creds);
-
-cleanup:
-	ast_sip_cleanup_auths(auths, auth_size);
-	return res;
-}
-
-static int digest_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge,
-		pjsip_transaction *tsx, pjsip_tx_data **new_request)
-{
-	pjsip_auth_clt_sess auth_sess;
-
-	if (pjsip_auth_clt_init(&auth_sess, ast_sip_get_pjsip_endpoint(),
-				tsx->pool, 0) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Failed to initialize client authentication session\n");
-		return -1;
-	}
-
-	if (set_outbound_authentication_credentials(&auth_sess, auths, challenge)) {
-		ast_log(LOG_WARNING, "Failed to set authentication credentials\n");
-		return -1;
-	}
-
-	switch (pjsip_auth_clt_reinit_req(&auth_sess, challenge,
-				tsx->last_tx, new_request)) {
-	case PJ_SUCCESS:
-		return 0;
-	case PJSIP_ENOCREDENTIAL:
-		ast_log(LOG_WARNING, "Unable to create request with auth."
-				"No auth credentials for any realms in challenge.\n");
-		break;
-	case PJSIP_EAUTHSTALECOUNT:
-		ast_log(LOG_WARNING, "Unable to create request with auth."
-				"Number of stale retries exceeded\n");
-		break;
-	case PJSIP_EFAILEDCREDENTIAL:
-		ast_log(LOG_WARNING, "Authentication credentials not accepted by server\n");
-		break;
-	default:
-		ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure\n");
-		break;
-	}
-
-	return -1;
-}
-
-static struct ast_sip_outbound_authenticator digest_authenticator = {
-	.create_request_with_auth = digest_create_request_with_auth,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (ast_sip_register_outbound_authenticator(&digest_authenticator)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_outbound_authenticator(&digest_authenticator);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c
deleted file mode 100644
index 8bf329a..0000000
--- a/res/res_pjsip_outbound_publish.c
+++ /dev/null
@@ -1,1015 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_outbound_publish.h"
-#include "asterisk/module.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/datastore.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_outbound_publish" language="en_US">
-		<synopsis>SIP resource for outbound publish</synopsis>
-		<description><para>
-			<emphasis>Outbound Publish</emphasis>
-			</para>
-			<para>This module allows <literal>res_pjsip</literal> to publish to other SIP servers.</para>
-		</description>
-		<configFile name="pjsip.conf">
-			<configObject name="outbound-publish">
-				<synopsis>The configuration for outbound publish</synopsis>
-				<description><para>
-					Publish is <emphasis>COMPLETELY</emphasis> separate from the rest of
-					<literal>pjsip.conf</literal>. A minimal configuration consists of
-					setting a <literal>server_uri</literal> and <literal>event</literal>.
-				</para></description>
-				<configOption name="expiration" default="3600">
-					<synopsis>Expiration time for publications in seconds</synopsis>
-				</configOption>
-				<configOption name="outbound_auth" default="">
-					<synopsis>Authentication object to be used for outbound publishes.</synopsis>
-				</configOption>
-				<configOption name="outbound_proxy" default="">
-					<synopsis>SIP URI of the outbound proxy used to send publishes</synopsis>
-				</configOption>
-				<configOption name="server_uri">
-					<synopsis>SIP URI of the server and entity to publish to</synopsis>
-					<description><para>
-						This is the URI at which to find the entity and server to send the outbound PUBLISH to.
-						This URI is used as the request URI of the outbound PUBLISH request from Asterisk.
-					</para></description>
-				</configOption>
-				<configOption name="from_uri">
-					<synopsis>SIP URI to use in the From header</synopsis>
-					<description><para>
-						This is the URI that will be placed into the From header of outgoing PUBLISH
-						messages. If no URI is specified then the URI provided in <literal>server_uri</literal>
-						will be used.
-					</para></description>
-				</configOption>
-				<configOption name="to_uri">
-					<synopsis>SIP URI to use in the To header</synopsis>
-					<description><para>
-						This is the URI that will be placed into the To header of outgoing PUBLISH
-						messages. If no URI is specified then the URI provided in <literal>server_uri</literal>
-						will be used.
-					</para></description>
-				</configOption>
-				<configOption name="event" default="">
-					<synopsis>Event type of the PUBLISH.</synopsis>
-				</configOption>
-				<configOption name="max_auth_attempts" default="5">
-					<synopsis>Maximum number of authentication attempts before stopping the publication.</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'outbound-publish'.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-/*! \brief Queued outbound publish message */
-struct sip_outbound_publish_message {
-	/*! \brief Optional body */
-	struct ast_sip_body body;
-	/*! \brief Linked list information */
-	AST_LIST_ENTRY(sip_outbound_publish_message) entry;
-	/*! \brief Extra space for body contents */
-	char body_contents[0];
-};
-
-/*! \brief Outbound publish client state information (persists for lifetime that publish should exist) */
-struct ast_sip_outbound_publish_client {
-	/*! \brief Underlying publish client */
-	pjsip_publishc *client;
-	/*! \brief Timer entry for refreshing publish */
-	pj_timer_entry timer;
-	/*! \brief Publisher datastores set up by handlers */
-	struct ao2_container *datastores;
-	/*! \brief The number of auth attempts done */
-	unsigned int auth_attempts;
-	/*! \brief Queue of outgoing publish messages to send*/
-	AST_LIST_HEAD_NOLOCK(, sip_outbound_publish_message) queue;
-	/*! \brief The message currently being sent */
-	struct sip_outbound_publish_message *sending;
-	/*! \brief Publish client has been fully started and event type informed */
-	unsigned int started;
-	/*! \brief Publish client should be destroyed */
-	unsigned int destroy;
-};
-
-/*! \brief Outbound publish information */
-struct ast_sip_outbound_publish {
-	/*! \brief Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! \brief URI for the entity and server */
-		AST_STRING_FIELD(server_uri);
-		/*! \brief URI for the From header */
-		AST_STRING_FIELD(from_uri);
-		/*! \brief URI for the To header */
-		AST_STRING_FIELD(to_uri);
-		/*! \brief Outbound proxy to use */
-		AST_STRING_FIELD(outbound_proxy);
-		/*! \brief The event type to publish */
-		AST_STRING_FIELD(event);
-	);
-	/*! \brief Requested expiration time */
-	unsigned int expiration;
-	/*! \brief Maximum number of auth attempts before stopping the publish client */
-	unsigned int max_auth_attempts;
-	/*! \brief Configured authentication credentials */
-	struct ast_sip_auth_vector outbound_auths;
-	/*! \brief Outbound publish state */
-	struct ast_sip_outbound_publish_client *state;
-};
-
-AST_RWLIST_HEAD_STATIC(publisher_handlers, ast_sip_event_publisher_handler);
-
-/*! \brief Container of currently active publish clients */
-static AO2_GLOBAL_OBJ_STATIC(active);
-
-static void sub_add_handler(struct ast_sip_event_publisher_handler *handler)
-{
-	AST_RWLIST_INSERT_TAIL(&publisher_handlers, handler, next);
-	ast_module_ref(ast_module_info->self);
-}
-
-static struct ast_sip_event_publisher_handler *find_publisher_handler_for_event_name(const char *event_name)
-{
-	struct ast_sip_event_publisher_handler *iter;
-
-	AST_RWLIST_TRAVERSE(&publisher_handlers, iter, next) {
-		if (!strcmp(iter->event_name, event_name)) {
-			break;
-		}
-	}
-	return iter;
-}
-
-/*! \brief Helper function which cancels the refresh timer on a client */
-static void cancel_publish_refresh(struct ast_sip_outbound_publish_client *client)
-{
-	if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client->timer)) {
-		/* The timer was successfully cancelled, drop the refcount of the client */
-		ao2_ref(client, -1);
-	}
-}
-
-/*! \brief Helper function which sets up the timer to send publication */
-static void schedule_publish_refresh(struct ast_sip_outbound_publish *publish, pjsip_rx_data *rdata)
-{
-	pj_time_val delay = { .sec = 0, };
-	pjsip_expires_hdr *expires;
-
-	cancel_publish_refresh(publish->state);
-
-	/* Determine when we should refresh - we favor the Expires header if possible */
-	expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
-	if (expires) {
-		delay.sec = expires->ivalue - PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH;
-	}
-	if (publish->expiration && ((delay.sec > publish->expiration) || !delay.sec)) {
-		delay.sec = publish->expiration;
-	}
-	if (delay.sec < PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH) {
-		delay.sec = PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH;
-	}
-
-	ao2_ref(publish->state, +1);
-	if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &publish->state->timer, &delay) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Failed to pass timed publish refresh to scheduler\n");
-		ao2_ref(publish->state, -1);
-	}
-}
-
-/*! \brief Publish client timer callback function */
-static void sip_outbound_publish_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
-{
-	struct ast_sip_outbound_publish_client *client = entry->user_data;
-
-	ao2_lock(client);
-	if (AST_LIST_EMPTY(&client->queue)) {
-		/* If there are no outstanding messages send an empty PUBLISH message so our publication doesn't expire */
-		ast_sip_publish_client_send(client, NULL);
-	}
-	ao2_unlock(client);
-
-	ao2_ref(client, -1);
-}
-
-/*! \brief Task for cancelling a refresh timer */
-static int cancel_refresh_timer_task(void *data)
-{
-	struct ast_sip_outbound_publish_client *state = data;
-
-	cancel_publish_refresh(state);
-	ao2_ref(state, -1);
-
-	return 0;
-}
-
-/*! \brief Task for sending an unpublish */
-static int send_unpublish_task(void *data)
-{
-	struct ast_sip_outbound_publish_client *state = data;
-	pjsip_tx_data *tdata;
-
-	if (pjsip_publishc_unpublish(state->client, &tdata) == PJ_SUCCESS) {
-		pjsip_publishc_send(state->client, tdata);
-	}
-
-	ao2_ref(state, -1);
-
-	return 0;
-}
-
-/*! \brief Helper function which starts or stops publish clients when applicable */
-static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_handler *removed)
-{
-	RAII_VAR(struct ao2_container *, publishes, ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "outbound-publish", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
-	struct ao2_iterator i;
-	struct ast_sip_outbound_publish *publish;
-
-	if (!publishes) {
-		return;
-	}
-
-	i = ao2_iterator_init(publishes, 0);
-	while ((publish = ao2_iterator_next(&i))) {
-		struct ast_sip_event_publisher_handler *handler = find_publisher_handler_for_event_name(publish->event);
-
-		if (!publish->state->started) {
-			/* If the publisher client has not yet been started try to start it */
-			if (!handler) {
-				ast_debug(2, "Could not find handler for event '%s' for outbound publish client '%s'\n",
-					publish->event, ast_sorcery_object_get_id(publish));
-			} else if (handler->start_publishing(publish, publish->state)) {
-				ast_log(LOG_ERROR, "Failed to start outbound publish with event '%s' for client '%s'\n",
-					publish->event, ast_sorcery_object_get_id(publish));
-			} else {
-				publish->state->started = 1;
-			}
-		} else if (publish->state->started && !handler && removed && !strcmp(publish->event, removed->event_name)) {
-			/* If the publisher client has been started but it is going away stop it */
-			removed->stop_publishing(publish->state);
-			publish->state->started = 0;
-			if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(publish->state))) {
-				ast_log(LOG_WARNING, "Could not stop refresh timer on client '%s'\n",
-					ast_sorcery_object_get_id(publish));
-				ao2_ref(publish->state, -1);
-			}
-		}
-		ao2_ref(publish, -1);
-	}
-	ao2_iterator_destroy(&i);
-}
-
-struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name)
-{
-	RAII_VAR(struct ast_sip_outbound_publish *, publish, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "outbound-publish", name), ao2_cleanup);
-
-	if (!publish) {
-		return NULL;
-	}
-
-	return ao2_bump(publish->state);
-}
-
-int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler)
-{
-	struct ast_sip_event_publisher_handler *existing;
-	SCOPED_LOCK(lock, &publisher_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	if (!handler->start_publishing || !handler->stop_publishing) {
-		ast_log(LOG_ERROR, "Handler does not implement required callbacks. Cannot register\n");
-		return -1;
-	} else if (ast_strlen_zero(handler->event_name)) {
-		ast_log(LOG_ERROR, "No event package specified for event publisher handler. Cannot register\n");
-		return -1;
-	}
-
-	existing = find_publisher_handler_for_event_name(handler->event_name);
-	if (existing) {
-		ast_log(LOG_ERROR, "Unable to register event publisher handler for event %s. "
-				"A handler is already registered\n", handler->event_name);
-		return -1;
-	}
-
-	sub_add_handler(handler);
-
-	sip_outbound_publish_synchronize(NULL);
-
-	return 0;
-}
-
-void ast_sip_unregister_event_publisher_handler(struct ast_sip_event_publisher_handler *handler)
-{
-	struct ast_sip_event_publisher_handler *iter;
-	SCOPED_LOCK(lock, &publisher_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publisher_handlers, iter, next) {
-		if (handler == iter) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-
-	sip_outbound_publish_synchronize(handler);
-}
-
-/*! \brief Destructor function for publish information */
-static void sip_outbound_publish_destroy(void *obj)
-{
-	struct ast_sip_outbound_publish *publish = obj;
-	SCOPED_LOCK(lock, &publisher_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	struct ast_sip_event_publisher_handler *handler = find_publisher_handler_for_event_name(publish->event);
-
-	if (handler) {
-		handler->stop_publishing(publish->state);
-	}
-	if (publish->state) {
-		cancel_publish_refresh(publish->state);
-		ao2_ref(publish->state, -1);
-	}
-	ast_sip_auth_vector_destroy(&publish->outbound_auths);
-
-	ast_string_field_free_memory(publish);
-}
-
-/*! \brief Allocator function for publish information */
-static void *sip_outbound_publish_alloc(const char *name)
-{
-	struct ast_sip_outbound_publish *publish = ast_sorcery_generic_alloc(sizeof(*publish),
-		sip_outbound_publish_destroy);
-
-	if (!publish || ast_string_field_init(publish, 256)) {
-		ao2_cleanup(publish);
-		return NULL;
-	}
-
-	return publish;
-}
-
-static void sip_outbound_publish_datastore_destroy(void *obj)
-{
-	struct ast_datastore *datastore = obj;
-
-	/* Using the destroy function (if present) destroy the data */
-	if (datastore->info->destroy != NULL && datastore->data != NULL) {
-		datastore->info->destroy(datastore->data);
-		datastore->data = NULL;
-	}
-
-	ast_free((void *) datastore->uid);
-	datastore->uid = NULL;
-}
-
-struct ast_datastore *ast_sip_publish_client_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	const char *uid_ptr = uid;
-	char uuid_buf[AST_UUID_STR_LEN];
-
-	if (!info) {
-		return NULL;
-	}
-
-	datastore = ao2_alloc(sizeof(*datastore), sip_outbound_publish_datastore_destroy);
-	if (!datastore) {
-		return NULL;
-	}
-
-	datastore->info = info;
-	if (ast_strlen_zero(uid)) {
-		/* They didn't provide an ID so we'll provide one ourself */
-		uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
-	}
-
-	datastore->uid = ast_strdup(uid_ptr);
-	if (!datastore->uid) {
-		return NULL;
-	}
-
-	ao2_ref(datastore, +1);
-	return datastore;
-}
-
-int ast_sip_publish_client_add_datastore(struct ast_sip_outbound_publish_client *client,
-	struct ast_datastore *datastore)
-{
-	ast_assert(datastore != NULL);
-	ast_assert(datastore->info != NULL);
-	ast_assert(!ast_strlen_zero(datastore->uid));
-
-	if (!ao2_link(client->datastores, datastore)) {
-		return -1;
-	}
-	return 0;
-}
-
-struct ast_datastore *ast_sip_publish_client_get_datastore(struct ast_sip_outbound_publish_client *client,
-	const char *name)
-{
-	return ao2_find(client->datastores, name, OBJ_SEARCH_KEY);
-}
-
-void ast_sip_publish_client_remove_datastore(struct ast_sip_outbound_publish_client *client,
-	const char *name)
-{
-	ao2_find(client->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-}
-
-static int sip_publish_client_service_queue(void *data)
-{
-	RAII_VAR(struct ast_sip_outbound_publish_client *, client, data, ao2_cleanup);
-	SCOPED_AO2LOCK(lock, client);
-	struct sip_outbound_publish_message *message;
-	pjsip_tx_data *tdata;
-	pj_status_t status;
-
-	if (client->destroy || client->sending || !(message = AST_LIST_FIRST(&client->queue))) {
-		return 0;
-	}
-
-	if (pjsip_publishc_publish(client->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
-		goto fatal;
-	}
-
-	if (!ast_strlen_zero(message->body.type) && !ast_strlen_zero(message->body.subtype) &&
-		ast_sip_add_body(tdata, &message->body)) {
-		pjsip_tx_data_dec_ref(tdata);
-		goto fatal;
-	}
-
-	status = pjsip_publishc_send(client->client, tdata);
-	if (status == PJ_EBUSY) {
-		/* We attempted to send the message but something else got there first */
-		goto service;
-	} else if (status != PJ_SUCCESS) {
-		goto fatal;
-	}
-
-	client->sending = message;
-
-	return 0;
-
-fatal:
-	AST_LIST_REMOVE_HEAD(&client->queue, entry);
-	ast_free(message);
-
-service:
-	if (ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(client))) {
-		ao2_ref(client, -1);
-	}
-	return -1;
-}
-
-int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client,
-	const struct ast_sip_body *body)
-{
-	SCOPED_AO2LOCK(lock, client);
-	struct sip_outbound_publish_message *message;
-	size_t type_len = 0, subtype_len = 0, body_text_len = 0;
-	int res;
-
-	if (!client->client) {
-		return -1;
-	}
-
-	/* If a body is present we need more space for the contents of it */
-	if (body) {
-		type_len = strlen(body->type) + 1;
-		subtype_len = strlen(body->subtype) + 1;
-		body_text_len = strlen(body->body_text) + 1;
-	}
-
-	message = ast_calloc(1, sizeof(*message) + type_len + subtype_len + body_text_len);
-	if (!message) {
-		return -1;
-	}
-
-	if (body) {
-		char *dst = message->body_contents;
-
-		message->body.type = strcpy(dst, body->type);
-		dst += type_len;
-		message->body.subtype = strcpy(dst, body->subtype);
-		dst += subtype_len;
-		message->body.body_text = strcpy(dst, body->body_text);
-	}
-
-	AST_LIST_INSERT_TAIL(&client->queue, message, entry);
-
-	res = ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(client));
-	if (res) {
-		ao2_ref(client, -1);
-	}
-
-	return res;
-}
-
-/*! \brief Destructor function for publish state */
-static void sip_outbound_publish_client_destroy(void *obj)
-{
-	struct ast_sip_outbound_publish_client *state = obj;
-	struct sip_outbound_publish_message *message;
-
-	/* You might be tempted to think "the publish client isn't being destroyed" but it actually is - just elsewhere */
-
-	while ((message = AST_LIST_REMOVE_HEAD(&state->queue, entry))) {
-		ast_free(message);
-	}
-
-	ao2_cleanup(state->datastores);
-}
-
-/*!
- * \internal
- * \brief Check if a publish can be reused
- *
- * This checks if the existing outbound publish's configuration differs from a newly-applied
- * outbound publish.
- *
- * \param existing The pre-existing outbound publish
- * \param applied The newly-created publish
- */
-static int can_reuse_publish(struct ast_sip_outbound_publish *existing, struct ast_sip_outbound_publish *applied)
-{
-	int i;
-
-	if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->from_uri, applied->from_uri) ||
-		strcmp(existing->to_uri, applied->to_uri) || strcmp(existing->outbound_proxy, applied->outbound_proxy) ||
-		strcmp(existing->event, applied->event) ||
-		AST_VECTOR_SIZE(&existing->outbound_auths) != AST_VECTOR_SIZE(&applied->outbound_auths)) {
-		return 0;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(&existing->outbound_auths); ++i) {
-		if (strcmp(AST_VECTOR_GET(&existing->outbound_auths, i), AST_VECTOR_GET(&applied->outbound_auths, i))) {
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param);
-
-/*! \brief Helper function that allocates a pjsip publish client and configures it */
-static int sip_outbound_publish_client_alloc(void *data)
-{
-	struct ast_sip_outbound_publish *publish = data;
-	pjsip_publishc_opt opt = {
-		.queue_request = PJ_FALSE,
-	};
-	pj_str_t event, server_uri, to_uri, from_uri;
-	pj_status_t status;
-
-	if (publish->state->client) {
-		return 0;
-	} else if (pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt, ao2_bump(publish), sip_outbound_publish_callback,
-		&publish->state->client) != PJ_SUCCESS) {
-		ao2_ref(publish, -1);
-		return -1;
-	}
-
-	if (!ast_strlen_zero(publish->outbound_proxy)) {
-		pjsip_route_hdr route_set, *route;
-		static const pj_str_t ROUTE_HNAME = { "Route", 5 };
-
-		pj_list_init(&route_set);
-
-		if (!(route = pjsip_parse_hdr(pjsip_publishc_get_pool(publish->state->client), &ROUTE_HNAME,
-			(char*)publish->outbound_proxy, strlen(publish->outbound_proxy), NULL))) {
-			pjsip_publishc_destroy(publish->state->client);
-			return -1;
-		}
-		pj_list_insert_nodes_before(&route_set, route);
-
-		pjsip_publishc_set_route_set(publish->state->client, &route_set);
-	}
-
-	pj_cstr(&event, publish->event);
-	pj_cstr(&server_uri, publish->server_uri);
-	pj_cstr(&to_uri, S_OR(publish->to_uri, publish->server_uri));
-	pj_cstr(&from_uri, S_OR(publish->from_uri, publish->server_uri));
-
-	status = pjsip_publishc_init(publish->state->client, &event, &server_uri, &from_uri, &to_uri,
-		publish->expiration);
-	if (status == PJSIP_EINVALIDURI) {
-		pj_pool_t *pool;
-		pj_str_t tmp;
-		pjsip_uri *uri;
-
-		pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
-		if (!pool) {
-			ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound publish '%s'\n",
-				ast_sorcery_object_get_id(publish));
-			pjsip_publishc_destroy(publish->state->client);
-			return -1;
-		}
-
-		pj_strdup2_with_null(pool, &tmp, publish->server_uri);
-		uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
-		if (!uri) {
-			ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound publish '%s'\n",
-				publish->server_uri, ast_sorcery_object_get_id(publish));
-		}
-
-		if (!ast_strlen_zero(publish->to_uri)) {
-			pj_strdup2_with_null(pool, &tmp, publish->to_uri);
-			uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
-			if (!uri) {
-				ast_log(LOG_ERROR, "Invalid to URI '%s' specified on outbound publish '%s'\n",
-					publish->to_uri, ast_sorcery_object_get_id(publish));
-			}
-		}
-
-		if (!ast_strlen_zero(publish->from_uri)) {
-			pj_strdup2_with_null(pool, &tmp, publish->from_uri);
-			uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
-			if (!uri) {
-				ast_log(LOG_ERROR, "Invalid from URI '%s' specified on outbound publish '%s'\n",
-					publish->from_uri, ast_sorcery_object_get_id(publish));
-			}
-		}
-
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		pjsip_publishc_destroy(publish->state->client);
-		return -1;
-	} else if (status != PJ_SUCCESS) {
-		pjsip_publishc_destroy(publish->state->client);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Callback function for publish client responses */
-static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param)
-{
-	RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(param->token), ao2_cleanup);
-	SCOPED_AO2LOCK(lock, publish->state);
-	pjsip_tx_data *tdata;
-
-	if (publish->state->destroy) {
-		if (publish->state->sending) {
-			publish->state->sending = NULL;
-			if (!ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(publish->state))) {
-				return;
-			}
-			ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n",
-				ast_sorcery_object_get_id(publish));
-			ao2_ref(publish->state, -1);
-		}
-		/* Once the destroy is called this callback will not get called any longer, so drop the publish ref */
-		pjsip_publishc_destroy(publish->state->client);
-		ao2_ref(publish, -1);
-		return;
-	}
-
-	if (param->code == 401 || param->code == 407) {
-		if (!ast_sip_create_request_with_auth(&publish->outbound_auths,
-				param->rdata, pjsip_rdata_get_tsx(param->rdata), &tdata)) {
-			pjsip_publishc_send(publish->state->client, tdata);
-		}
-		publish->state->auth_attempts++;
-
-		if (publish->state->auth_attempts == publish->max_auth_attempts) {
-			pjsip_publishc_destroy(publish->state->client);
-			publish->state->client = NULL;
-
-			ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n",
-				ast_sorcery_object_get_id(publish));
-
-			goto end;
-		}
-
-		return;
-	}
-
-	publish->state->auth_attempts = 0;
-
-	if (param->code == 412) {
-		pjsip_publishc_destroy(publish->state->client);
-		publish->state->client = NULL;
-
-		if (sip_outbound_publish_client_alloc(publish)) {
-			ast_log(LOG_ERROR, "Failed to create a new outbound publish client for '%s' on 412 response\n",
-				ast_sorcery_object_get_id(publish));
-			goto end;
-		}
-
-		/* Setting this to NULL will cause a new PUBLISH to get created and sent for the same underlying body */
-		publish->state->sending = NULL;
-	} else if (param->code == 423) {
-		/* Update the expiration with the new expiration time if available */
-		pjsip_expires_hdr *expires;
-
-		expires = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_MIN_EXPIRES, NULL);
-		if (!expires || !expires->ivalue) {
-			ast_log(LOG_ERROR, "Received 423 response on outbound publish '%s' without a Min-Expires header\n",
-				ast_sorcery_object_get_id(publish));
-			pjsip_publishc_destroy(publish->state->client);
-			publish->state->client = NULL;
-			goto end;
-		}
-
-		pjsip_publishc_update_expires(publish->state->client, expires->ivalue);
-		publish->state->sending = NULL;
-	} else if (publish->state->sending) {
-		/* Remove the message currently being sent so that when the queue is serviced another will get sent */
-		AST_LIST_REMOVE_HEAD(&publish->state->queue, entry);
-		ast_free(publish->state->sending);
-		publish->state->sending = NULL;
-	}
-
-	if (AST_LIST_EMPTY(&publish->state->queue)) {
-		schedule_publish_refresh(publish, param->rdata);
-	}
-
-end:
-	if (!publish->state->client) {
-		struct sip_outbound_publish_message *message;
-
-		while ((message = AST_LIST_REMOVE_HEAD(&publish->state->queue, entry))) {
-			ast_free(message);
-		}
-	} else {
-		if (ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(publish->state))) {
-			ao2_ref(publish->state, -1);
-		}
-	}
-}
-
-#define DATASTORE_BUCKETS 53
-
-static int datastore_hash(const void *obj, int flags)
-{
-	const struct ast_datastore *datastore;
-	const char *uid;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		uid = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		datastore = obj;
-		uid = datastore->uid;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-
-	return ast_str_hash(uid);
-}
-
-static int datastore_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_datastore *object_left = obj;
-	const struct ast_datastore *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->uid;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->uid, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-        cmp = strncmp(object_left->uid, right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-/*! \brief Allocator function for publish client state */
-static struct ast_sip_outbound_publish_client *sip_outbound_publish_state_alloc(void)
-{
-	struct ast_sip_outbound_publish_client *state = ao2_alloc(sizeof(*state), sip_outbound_publish_client_destroy);
-
-	if (!state) {
-		return NULL;
-	}
-
-	state->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
-	if (!state->datastores) {
-		ao2_ref(state, -1);
-		return NULL;
-	}
-
-	state->timer.user_data = state;
-	state->timer.cb = sip_outbound_publish_timer_cb;
-
-	return state;
-}
-
-/*! \brief Apply function which finds or allocates a state structure */
-static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *obj)
-{
-	RAII_VAR(struct ast_sip_outbound_publish *, existing, ast_sorcery_retrieve_by_id(sorcery, "outbound-publish", ast_sorcery_object_get_id(obj)), ao2_cleanup);
-	struct ast_sip_outbound_publish *applied = obj;
-
-	if (ast_strlen_zero(applied->server_uri)) {
-		ast_log(LOG_ERROR, "No server URI specified on outbound publish '%s'\n",
-			ast_sorcery_object_get_id(applied));
-		return -1;
-	} else if (ast_strlen_zero(applied->event)) {
-		ast_log(LOG_ERROR, "No event type specified for outbound publish '%s'\n",
-			ast_sorcery_object_get_id(applied));
-		return -1;
-	}
-
-	if (!existing) {
-		/* If no existing publish exists we can just start fresh easily */
-		applied->state = sip_outbound_publish_state_alloc();
-	} else {
-		/* If there is an existing publish things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
-		if (can_reuse_publish(existing, applied)) {
-			applied->state = existing->state;
-			ao2_ref(applied->state, +1);
-		} else {
-			applied->state = sip_outbound_publish_state_alloc();
-		}
-	}
-
-	if (!applied->state) {
-		return -1;
-	}
-
-	return ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, applied);
-}
-
-static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_outbound_publish *publish = obj;
-
-	return ast_sip_auth_vector_init(&publish->outbound_auths, var->value);
-}
-
-/*! \brief Helper function which prunes old publish clients */
-static void prune_publish_clients(const char *object_type)
-{
-	struct ao2_container *old, *current;
-
-	old = ao2_global_obj_ref(active);
-	if (old) {
-		struct ao2_iterator i;
-		struct ast_sip_outbound_publish *existing;
-
-		i = ao2_iterator_init(old, 0);
-		for (; (existing = ao2_iterator_next(&i)); ao2_ref(existing, -1)) {
-			struct ast_sip_outbound_publish *created;
-
-			created = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "outbound-publish",
-				ast_sorcery_object_get_id(existing));
-			if (created) {
-				if (created->state == existing->state) {
-					ao2_ref(created, -1);
-					continue;
-				}
-				ao2_ref(created, -1);
-			}
-
-			ao2_lock(existing->state);
-
-			/* If this publish client is currently publishing stop and terminate any refresh timer */
-			if (existing->state->started) {
-				struct ast_sip_event_publisher_handler *handler = find_publisher_handler_for_event_name(existing->event);
-
-				if (handler) {
-					handler->stop_publishing(existing->state);
-				}
-
-				if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(existing->state))) {
-					ast_log(LOG_WARNING, "Could not stop refresh timer on outbound publish '%s'\n",
-						ast_sorcery_object_get_id(existing));
-					ao2_ref(existing->state, -1);
-				}
-			}
-
-			/* If nothing is being sent right now send the unpublish - the destroy will happen in the subsequent callback */
-			if (!existing->state->sending) {
-				if (ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(existing->state))) {
-					ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n",
-						ast_sorcery_object_get_id(existing));
-					ao2_ref(existing->state, -1);
-				}
-			}
-
-			existing->state->destroy = 1;
-			ao2_unlock(existing->state);
-		}
-		ao2_iterator_destroy(&i);
-
-		ao2_ref(old, -1);
-	}
-
-	current = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "outbound-publish", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	ao2_global_obj_replace_unref(active, current);
-}
-
-static struct ast_sorcery_observer outbound_publish_observer = {
-	.loaded = prune_publish_clients,
-};
-
-static int load_module(void)
-{
-	ast_sorcery_apply_default(ast_sip_get_sorcery(), "outbound-publish", "config", "pjsip.conf,criteria=type=outbound-publish");
-
-	if (ast_sorcery_object_register(ast_sip_get_sorcery(), "outbound-publish", sip_outbound_publish_alloc, NULL,
-		sip_outbound_publish_apply)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_observer_add(ast_sip_get_sorcery(), "outbound-publish", &outbound_publish_observer);
-
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, server_uri));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "from_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, from_uri));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "event", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, event));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "to_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, to_uri));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, outbound_proxy));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, expiration));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "max_auth_attempts", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, max_auth_attempts));
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "outbound-publish", "outbound_auth", "", outbound_auth_handler, NULL, NULL, 0, 0);
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish");
-
-	AST_RWLIST_RDLOCK(&publisher_handlers);
-	sip_outbound_publish_synchronize(NULL);
-	AST_RWLIST_UNLOCK(&publisher_handlers);
-
-	pjsip_publishc_init_module(ast_sip_get_pjsip_endpoint());
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish");
-
-	AST_RWLIST_RDLOCK(&publisher_handlers);
-	sip_outbound_publish_synchronize(NULL);
-	AST_RWLIST_UNLOCK(&publisher_handlers);
-	return 0;
-}
-
-static int unload_module(void)
-{
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Publish Support",
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-	       );
diff --git a/res/res_pjsip_outbound_publish.exports.in b/res/res_pjsip_outbound_publish.exports.in
deleted file mode 100644
index a75103b..0000000
--- a/res/res_pjsip_outbound_publish.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_sip_*;
-	local:
-		*;
-};
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
deleted file mode 100644
index 552d61e..0000000
--- a/res/res_pjsip_outbound_registration.c
+++ /dev/null
@@ -1,1448 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_cli.h"
-#include "asterisk/module.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/cli.h"
-#include "asterisk/stasis_system.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_outbound_registration" language="en_US">
-		<synopsis>SIP resource for outbound registrations</synopsis>
-		<description><para>
-			<emphasis>Outbound Registration</emphasis>
-			</para>
-			<para>This module allows <literal>res_pjsip</literal> to register to other SIP servers.</para>
-		</description>
-		<configFile name="pjsip.conf">
-			<configObject name="registration">
-				<synopsis>The configuration for outbound registration</synopsis>
-				<description><para>
-					Registration is <emphasis>COMPLETELY</emphasis> separate from the rest of
-					<literal>pjsip.conf</literal>. A minimal configuration consists of
-					setting a <literal>server_uri</literal>	and a <literal>client_uri</literal>.
-				</para></description>
-				<configOption name="auth_rejection_permanent" default="yes">
-					<synopsis>Determines whether failed authentication challenges are treated
-					as permanent failures.</synopsis>
-					<description><para>If this option is enabled and an authentication challenge fails,
-					registration will not be attempted again until the configuration is reloaded.</para></description>
-				</configOption>
-				<configOption name="client_uri">
-					<synopsis>Client SIP URI used when attemping outbound registration</synopsis>
-					<description><para>
-						This is the address-of-record for the outbound registration (i.e. the URI in
-						the To header of the REGISTER).</para>
-						<para>For registration with an ITSP, the client SIP URI may need to consist of
-						an account name or number and the provider's hostname for their registrar, e.g.
-						client_uri=1234567890 at example.com. This may differ between providers.</para>
-						<para>For registration to generic registrars, the client SIP URI will depend
-						on networking specifics and configuration of the registrar.
-					</para></description>
-				</configOption>
-				<configOption name="contact_user">
-					<synopsis>Contact User to use in request</synopsis>
-				</configOption>
-				<configOption name="expiration" default="3600">
-					<synopsis>Expiration time for registrations in seconds</synopsis>
-				</configOption>
-				<configOption name="max_retries" default="10">
-					<synopsis>Maximum number of registration attempts.</synopsis>
-				</configOption>
-				<configOption name="outbound_auth" default="">
-					<synopsis>Authentication object to be used for outbound registrations.</synopsis>
-				</configOption>
-				<configOption name="outbound_proxy" default="">
-					<synopsis>Outbound Proxy used to send registrations</synopsis>
-				</configOption>
-				<configOption name="retry_interval" default="60">
-					<synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
-				</configOption>
-				<configOption name="forbidden_retry_interval" default="0">
-					<synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
-					<description><para>
-						If a 403 Forbidden is received, chan_pjsip will wait
-						<replaceable>forbidden_retry_interval</replaceable> seconds before
-						attempting registration again. If 0 is specified, chan_pjsip will not
-						retry after receiving a 403 Forbidden response. Setting this to a non-zero
-						value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
-						buggy registrars.
-					</para></description>
-				</configOption>
-				<configOption name="server_uri">
-					<synopsis>SIP URI of the server to register against</synopsis>
-					<description><para>
-						This is the URI at which to find the registrar to send the outbound REGISTER. This URI
-						is used as the request URI of the outbound REGISTER request from Asterisk.</para>
-						<para>For registration with an ITSP, the setting may often be just the domain of
-						the registrar, e.g. sip:sip.example.com.
-					</para></description>
-				</configOption>
-				<configOption name="transport">
-					<synopsis>Transport used for outbound authentication</synopsis>
-					<description>
-						<note><para>A <replaceable>transport</replaceable> configured in
-						<literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note>
-					</description>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'registration'.</synopsis>
-				</configOption>
-				<configOption name="support_path">
-					<synopsis>Enables Path support for outbound REGISTER requests.</synopsis>
-					<description><para>
-						When this option is enabled, outbound REGISTER requests will advertise
-						support for Path headers so that intervening proxies can add to the Path
-						header as necessary.
-					</para></description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-	<manager name="PJSIPUnregister" language="en_US">
-		<synopsis>
-			Unregister an outbound registration.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Registration" required="true">
-				<para>The outbound registration to unregister.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>
-			Send a SIP REGISTER request to the specified outbound registration with an expiration of 0.
-			This will cause the contact added by this registration to be removed on the remote system.
-			Note: The specified outbound registration will attempt to re-register according to it's last
-			registration expiration.
-                        </para>
-		</description>
-	</manager>
-	<manager name="PJSIPShowRegistrationsOutbound" language="en_US">
-		<synopsis>
-			Lists PJSIP outbound registrations.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			In response <literal>OutboundRegistrationDetail</literal> events showing configuration and status
-			information are raised for each outbound registration object. <literal>AuthDetail</literal>
-			events are raised for each associated auth object as well.  Once all events are completed an
-			<literal>OutboundRegistrationDetailComplete</literal> is issued.
-                        </para>
-		</description>
-	</manager>
- ***/
-
-/*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
-#define REREGISTER_BUFFER_TIME 10
-
-/*! \brief Size of the buffer for creating a unique string for the line */
-#define LINE_PARAMETER_SIZE 8
-
-/*! \brief Various states that an outbound registration may be in */
-enum sip_outbound_registration_status {
-	/*! \brief Currently unregistered */
-	SIP_REGISTRATION_UNREGISTERED = 0,
-	/*! \brief Registered, yay! */
-	SIP_REGISTRATION_REGISTERED,
-	/*! \brief Registration was rejected, but response was temporal */
-	SIP_REGISTRATION_REJECTED_TEMPORARY,
-	/*! \brief Registration was rejected, permanently */
-	SIP_REGISTRATION_REJECTED_PERMANENT,
-	/*! \brief Registration has been stopped */
-	SIP_REGISTRATION_STOPPED,
-};
-
-static const char *sip_outbound_registration_status_str[] = {
-	[SIP_REGISTRATION_UNREGISTERED] = "Unregistered",
-	[SIP_REGISTRATION_REGISTERED] = "Registered",
-	[SIP_REGISTRATION_REJECTED_TEMPORARY] = "Rejected",
-	[SIP_REGISTRATION_REJECTED_PERMANENT] = "Rejected",
-	[SIP_REGISTRATION_STOPPED] = "Stopped",
-};
-
-/*! \brief Outbound registration information */
-struct sip_outbound_registration {
-	/*! \brief Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! \brief URI for the registrar */
-		AST_STRING_FIELD(server_uri);
-		/*! \brief URI for the AOR */
-		AST_STRING_FIELD(client_uri);
-		/*! \brief Optional user for contact header */
-		AST_STRING_FIELD(contact_user);
-		/*! \brief Explicit transport to use for registration */
-		AST_STRING_FIELD(transport);
-		/*! \brief Outbound proxy to use */
-		AST_STRING_FIELD(outbound_proxy);
-		/*! \brief Endpoint to use for related incoming calls */
-		AST_STRING_FIELD(endpoint);
-	);
-	/*! \brief Requested expiration time */
-	unsigned int expiration;
-	/*! \brief Interval at which retries should occur for temporal responses */
-	unsigned int retry_interval;
-	/*! \brief Interval at which retries should occur for permanent responses */
-	unsigned int forbidden_retry_interval;
-	/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
-	unsigned int auth_rejection_permanent;
-	/*! \brief Maximum number of retries permitted */
-	unsigned int max_retries;
-	/*! \brief Whether to add a line parameter to the outbound Contact or not */
-	unsigned int line;
-	/*! \brief Configured authentication credentials */
-	struct ast_sip_auth_vector outbound_auths;
-	/*! \brief Whether Path support is enabled */
-	unsigned int support_path;
-};
-
-/*! \brief Outbound registration client state information (persists for lifetime of regc) */
-struct sip_outbound_registration_client_state {
-	/*! \brief Current status of this registration */
-	enum sip_outbound_registration_status status;
-	/*! \brief Outbound registration client */
-	pjsip_regc *client;
-	/*! \brief Timer entry for retrying on temporal responses */
-	pj_timer_entry timer;
-	/*! \brief Optional line parameter placed into Contact */
-	char line[LINE_PARAMETER_SIZE];
-	/*! \brief Current number of retries */
-	unsigned int retries;
-	/*! \brief Maximum number of retries permitted */
-	unsigned int max_retries;
-	/*! \brief Interval at which retries should occur for temporal responses */
-	unsigned int retry_interval;
-	/*! \brief Interval at which retries should occur for permanent responses */
-	unsigned int forbidden_retry_interval;
-	/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
-	unsigned int auth_rejection_permanent;
-	/*! \brief Determines whether SIP Path support should be advertised */
-	unsigned int support_path;
-	/*! \brief Serializer for stuff and things */
-	struct ast_taskprocessor *serializer;
-	/*! \brief Configured authentication credentials */
-	struct ast_sip_auth_vector outbound_auths;
-	/*! \brief Registration should be destroyed after completion of transaction */
-	unsigned int destroy:1;
-};
-
-/*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
-struct sip_outbound_registration_state {
-	/*! \brief Outbound registration configuration object */
-	struct sip_outbound_registration *registration;
-	/*! \brief Client state information */
-	struct sip_outbound_registration_client_state *client_state;
-};
-
-/*! \brief Default number of state container buckets */
-#define DEFAULT_STATE_BUCKETS 53
-static AO2_GLOBAL_OBJ_STATIC(current_states);
-
-/*! \brief hashing function for state objects */
-static int registration_state_hash(const void *obj, const int flags)
-{
-	const struct sip_outbound_registration_state *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		key = ast_sorcery_object_get_id(object->registration);
-		break;
-	default:
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! \brief comparator function for state objects */
-static int registration_state_cmp(void *obj, void *arg, int flags)
-{
-	const struct sip_outbound_registration_state *object_left = obj;
-	const struct sip_outbound_registration_state *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = ast_sorcery_object_get_id(object_right->registration);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/* Not supported by container. */
-		ast_assert(0);
-		return 0;
-	default:
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	return CMP_MATCH;
-}
-
-static struct sip_outbound_registration_state *get_state(const char *id)
-{
-	RAII_VAR(struct ao2_container *, states,
-		 ao2_global_obj_ref(current_states), ao2_cleanup);
-	return states ? ao2_find(states, id, OBJ_SEARCH_KEY) : NULL;
-}
-
-static int registration_state_add(void *obj, void *arg, int flags)
-{
-	struct sip_outbound_registration_state *state =
-		get_state(ast_sorcery_object_get_id(obj));
-
-	if (state) {
-		ao2_link(arg, state);
-		ao2_ref(state, -1);
-	}
-
-	return 0;
-}
-
-static struct ao2_container *get_registrations(void)
-{
-	RAII_VAR(struct ao2_container *, new_states, NULL, ao2_cleanup);
-	struct ao2_container *registrations = ast_sorcery_retrieve_by_fields(
-		ast_sip_get_sorcery(), "registration",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-
-	if (!(new_states = ao2_container_alloc(DEFAULT_STATE_BUCKETS,
-		      registration_state_hash, registration_state_cmp))) {
-		ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
-		return NULL;
-	}
-
-	if (registrations && ao2_container_count(registrations)) {
-		ao2_callback(registrations, OBJ_NODATA, registration_state_add, new_states);
-	}
-
-	ao2_global_obj_replace_unref(current_states, new_states);
-	return registrations;
-}
-
-/*! \brief Helper function which cancels the timer on a client */
-static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
-{
-	if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
-		/* The timer was successfully cancelled, drop the refcount of client_state */
-		ao2_ref(client_state, -1);
-	}
-}
-
-static pj_str_t PATH_NAME = { "path", 4 };
-
-/*! \brief Callback function for registering */
-static int handle_client_registration(void *data)
-{
-	RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
-	pjsip_tx_data *tdata;
-	pjsip_regc_info info;
-	char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
-
-	cancel_registration(client_state);
-
-	if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
-		(pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
-		return 0;
-	}
-
-	pjsip_regc_get_info(client_state->client, &info);
-	ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
-	ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
-	ast_debug(3, "REGISTER attempt %u to '%s' with client '%s'\n",
-		  client_state->retries + 1, server_uri, client_uri);
-
-	if (client_state->support_path) {
-		pjsip_supported_hdr *hdr;
-
-		hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
-		if (!hdr) {
-			/* insert a new Supported header */
-			hdr = pjsip_supported_hdr_create(tdata->pool);
-			if (!hdr) {
-				return -1;
-			}
-
-			pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
-		}
-
-		/* add on to the existing Supported header */
-		pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
-	}
-
-	/* Due to the registration the callback may now get called, so bump the ref count */
-	ao2_ref(client_state, +1);
-	if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
-		ao2_ref(client_state, -1);
-	}
-
-	return 0;
-}
-
-/*! \brief Timer callback function, used just for registrations */
-static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
-{
-	struct sip_outbound_registration_client_state *client_state = entry->user_data;
-
-	ao2_ref(client_state, +1);
-	if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
-		ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
-		ao2_ref(client_state, -1);
-	}
-
-	entry->id = 0;
-}
-
-/*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
-static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
-{
-	pj_time_val delay = { .sec = seconds, };
-
-	cancel_registration(client_state);
-
-	ao2_ref(client_state, +1);
-	if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
-		ao2_ref(client_state, -1);
-	}
-}
-
-/*! \brief Callback function for unregistering (potentially) and destroying state */
-static int handle_client_state_destruction(void *data)
-{
-	RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
-
-	cancel_registration(client_state);
-
-	if (client_state->client) {
-		pjsip_regc_info info;
-
-		pjsip_regc_get_info(client_state->client, &info);
-
-		if (info.is_busy == PJ_TRUE) {
-			/* If a client transaction is in progress we defer until it is complete */
-			client_state->destroy = 1;
-			return 0;
-		}
-
-		if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
-			pjsip_tx_data *tdata;
-
-			if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
-				pjsip_regc_send(client_state->client, tdata);
-			}
-		}
-
-		pjsip_regc_destroy(client_state->client);
-	}
-
-	client_state->status = SIP_REGISTRATION_STOPPED;
-	ast_sip_auth_vector_destroy(&client_state->outbound_auths);
-
-	return 0;
-}
-
-/*! \brief Structure for registration response */
-struct registration_response {
-	/*! \brief Response code for the registration attempt */
-	int code;
-	/*! \brief Expiration time for registration */
-	int expiration;
-	/*! \brief Retry-After value */
-	int retry_after;
-	/*! \brief Outbound registration client state */
-	struct sip_outbound_registration_client_state *client_state;
-	/*! \brief The response message */
-	pjsip_rx_data *rdata;
-	/*! \brief The response transaction */
-	pjsip_transaction *tsx;
-};
-
-/*! \brief Registration response structure destructor */
-static void registration_response_destroy(void *obj)
-{
-	struct registration_response *response = obj;
-
-	if (response->rdata) {
-		pjsip_rx_data_free_cloned(response->rdata);
-	}
-
-	ao2_cleanup(response->client_state);
-}
-
-/* \brief Helper funtion which determines if a response code is temporal or not */
-static int sip_outbound_registration_is_temporal(unsigned int code,
-		struct sip_outbound_registration_client_state *client_state)
-{
-	/* Shamelessly taken from pjsua */
-	if (code == PJSIP_SC_REQUEST_TIMEOUT ||
-		code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
-		code == PJSIP_SC_BAD_GATEWAY ||
-		code == PJSIP_SC_SERVICE_UNAVAILABLE ||
-		code == PJSIP_SC_SERVER_TIMEOUT ||
-		((code == PJSIP_SC_UNAUTHORIZED ||
-		  code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
-		 !client_state->auth_rejection_permanent) ||
-		PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-static void schedule_retry(struct registration_response *response, unsigned int interval,
-			   const char *server_uri, const char *client_uri)
-{
-	response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
-	schedule_registration(response->client_state, interval);
-
-	if (response->rdata) {
-		ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
-			"registration attempt to '%s', retrying in '%u'\n",
-			response->code, server_uri, client_uri, interval);
-	} else {
-		ast_log(LOG_WARNING, "No response received from '%s' on "
-			"registration attempt to '%s', retrying in '%u'\n",
-			server_uri, client_uri, interval);
-	}
-}
-
-/*! \brief Callback function for handling a response to a registration attempt */
-static int handle_registration_response(void *data)
-{
-	RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
-	pjsip_regc_info info;
-	char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
-
-	if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
-		return 0;
-	}
-
-	pjsip_regc_get_info(response->client_state->client, &info);
-	ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
-	ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
-
-	if (response->code == 401 || response->code == 407) {
-		pjsip_tx_data *tdata;
-		if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
-				response->rdata, response->tsx, &tdata)) {
-			ao2_ref(response->client_state, +1);
-			if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
-				ao2_cleanup(response->client_state);
-			}
-			return 0;
-		}
-		/* Otherwise, fall through so the failure is processed appropriately */
-	}
-
-	if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
-		/* Check if this is in regards to registering or unregistering */
-		if (response->expiration) {
-			/* If the registration went fine simply reschedule registration for the future */
-			ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
-			response->client_state->status = SIP_REGISTRATION_REGISTERED;
-			response->client_state->retries = 0;
-			schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
-		} else {
-			ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
-			response->client_state->status = SIP_REGISTRATION_UNREGISTERED;
-		}
-	} else if (response->retry_after) {
-		/* If we have been instructed to retry after a period of time, schedule it as such */
-		schedule_retry(response, response->retry_after, server_uri, client_uri);
-	} else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
-		if (response->client_state->retries == response->client_state->max_retries) {
-			/* If we received enough temporal responses to exceed our maximum give up permanently */
-			response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
-			ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
-				server_uri, client_uri);
-		} else {
-			/* On the other hand if we can still try some more do so */
-			response->client_state->retries++;
-			schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
-		}
-	} else {
-		if (response->code == 403
-			&& response->client_state->forbidden_retry_interval
-			&& response->client_state->retries < response->client_state->max_retries) {
-			/* A forbidden response retry interval is configured and there are retries remaining */
-			response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
-			response->client_state->retries++;
-			schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
-			ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
-				server_uri, client_uri, response->client_state->forbidden_retry_interval);
-		} else {
-			/* Finally if there's no hope of registering give up */
-			response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
-			if (response->rdata) {
-				ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
-					response->code, server_uri, client_uri);
-			} else {
-				ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
-			}
-		}
-	}
-
-	ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
-
-	/* If deferred destruction is in use see if we need to destroy now */
-	if (response->client_state->destroy) {
-		handle_client_state_destruction(response->client_state);
-	}
-
-	return 0;
-}
-
-/*! \brief Callback function for outbound registration client */
-static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
-{
-	RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
-	struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
-
-	response->code = param->code;
-	response->expiration = param->expiration;
-	response->client_state = client_state;
-	ao2_ref(response->client_state, +1);
-
-	if (param->rdata) {
-		struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
-
-		response->retry_after = retry_after ? retry_after->ivalue : 0;
-		response->tsx = pjsip_rdata_get_tsx(param->rdata);
-		pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
-	}
-
-	if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
-		ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
-		ao2_cleanup(response);
-	}
-}
-
-/*! \brief Destructor function for registration state */
-static void sip_outbound_registration_state_destroy(void *obj)
-{
-	struct sip_outbound_registration_state *state = obj;
-
-	ao2_cleanup(state->registration);
-
-	if (!state->client_state) {
-		return;
-	}
-
-	if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
-		ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
-		ao2_ref(state->client_state, -1);
-	}
-}
-
-/*! \brief Destructor function for client registration state */
-static void sip_outbound_registration_client_state_destroy(void *obj)
-{
-	struct sip_outbound_registration_client_state *client_state = obj;
-
-	ast_taskprocessor_unreference(client_state->serializer);
-}
-
-/*! \brief Allocator function for registration state */
-static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
-{
-	struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
-
-	if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
-		ao2_cleanup(state);
-		return NULL;
-	}
-
-	if (!(state->client_state->serializer = ast_sip_create_serializer())) {
-		ao2_cleanup(state->client_state);
-		ao2_cleanup(state);
-		return NULL;
-	}
-
-	state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
-	state->client_state->timer.user_data = state->client_state;
-	state->client_state->timer.cb = sip_outbound_registration_timer_cb;
-
-	state->registration = ao2_bump(registration);
-	return state;
-}
-
-/*! \brief Destructor function for registration information */
-static void sip_outbound_registration_destroy(void *obj)
-{
-	struct sip_outbound_registration *registration = obj;
-
-	ast_sip_auth_vector_destroy(&registration->outbound_auths);
-
-	ast_string_field_free_memory(registration);
-}
-
-/*! \brief Allocator function for registration information */
-static void *sip_outbound_registration_alloc(const char *name)
-{
-	struct sip_outbound_registration *registration = ast_sorcery_generic_alloc(sizeof(*registration), sip_outbound_registration_destroy);
-	if (!registration || ast_string_field_init(registration, 256)) {
-		ao2_cleanup(registration);
-		return NULL;
-	}
-
-	return registration;
-}
-
-/*! \brief Helper function which populates a pj_str_t with a contact header */
-static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
-{
-	pj_str_t tmp, local_addr;
-	pjsip_uri *uri;
-	pjsip_sip_uri *sip_uri;
-	pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
-	int local_port;
-
-	pj_strdup_with_null(pool, &tmp, target);
-
-	if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
-	    (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
-		return -1;
-	}
-
-	sip_uri = pjsip_uri_get_uri(uri);
-
-	if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
-		type = PJSIP_TRANSPORT_TLS;
-	} else if (!sip_uri->transport_param.slen) {
-		type = PJSIP_TRANSPORT_UDP;
-	} else {
-		type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
-	}
-
-	if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
-		return -1;
-	}
-
-	if (pj_strchr(&sip_uri->host, ':')) {
-		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
-	}
-
-	if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
-							      &local_addr, &local_port) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
-		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
-	}
-
-	contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-	contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
-				      "<%s:%s@%s%.*s%s:%d%s%s>",
-				      (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
-				      user,
-				      (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
-				      (int)local_addr.slen,
-				      local_addr.ptr,
-				      (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
-				      local_port,
-				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
-				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Check if a registration can be reused
- *
- * This checks if the existing outbound registration's configuration differs from a newly-applied
- * outbound registration to see if the applied one.
- *
- * \param existing The pre-existing outbound registration
- * \param applied The newly-created registration
- */
-static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
-{
-	int i;
-
-	if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
-		strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
-		strcmp(existing->outbound_proxy, applied->outbound_proxy) ||
-		AST_VECTOR_SIZE(&existing->outbound_auths) != AST_VECTOR_SIZE(&applied->outbound_auths) ||
-		existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
-		return 0;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(&existing->outbound_auths); ++i) {
-		if (strcmp(AST_VECTOR_GET(&existing->outbound_auths, i), AST_VECTOR_GET(&applied->outbound_auths, i))) {
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-/*! \brief Helper function that allocates a pjsip registration client and configures it */
-static int sip_outbound_registration_regc_alloc(void *data)
-{
-	struct sip_outbound_registration_state *state = data;
-	RAII_VAR(struct sip_outbound_registration *, registration,
-		 ao2_bump(state->registration), ao2_cleanup);
-	pj_pool_t *pool;
-	pj_str_t tmp;
-	pjsip_uri *uri;
-	pj_str_t server_uri, client_uri, contact_uri;
-	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
-
-	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
-	if (!pool) {
-		ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
-			ast_sorcery_object_get_id(registration));
-		return -1;
-	}
-
-	pj_strdup2_with_null(pool, &tmp, registration->server_uri);
-	uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
-	if (!uri) {
-		ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
-			registration->server_uri, ast_sorcery_object_get_id(registration));
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	pj_strdup2_with_null(pool, &tmp, registration->client_uri);
-	uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
-	if (!uri) {
-		ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
-			registration->client_uri, ast_sorcery_object_get_id(registration));
-		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-		return -1;
-	}
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-
-	if (!ast_strlen_zero(registration->transport)) {
-		RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup);
-
-		if (!transport || !transport->state) {
-			ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' "
-				" for outbound registration", registration->transport);
-			return -1;
-		}
-
-		if (transport->state->transport) {
-			selector.type = PJSIP_TPSELECTOR_TRANSPORT;
-			selector.u.transport = transport->state->transport;
-		} else if (transport->state->factory) {
-			selector.type = PJSIP_TPSELECTOR_LISTENER;
-			selector.u.listener = transport->state->factory;
-		} else {
-			return -1;
-		}
-	}
-
-	if (!state->client_state->client &&
-		pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state, sip_outbound_registration_response_cb,
-		&state->client_state->client) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	pjsip_regc_set_transport(state->client_state->client, &selector);
-
-	if (!ast_strlen_zero(registration->outbound_proxy)) {
-		pjsip_route_hdr route_set, *route;
-		static const pj_str_t ROUTE_HNAME = { "Route", 5 };
-		pj_str_t tmp;
-
-		pj_list_init(&route_set);
-
-		pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp, registration->outbound_proxy);
-		if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
-			return -1;
-		}
-		pj_list_insert_nodes_before(&route_set, route);
-
-		pjsip_regc_set_route_set(state->client_state->client, &route_set);
-	}
-
-	pj_cstr(&server_uri, registration->server_uri);
-
-	if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector)) {
-		return -1;
-	}
-
-	pj_cstr(&client_uri, registration->client_uri);
-	if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	return 0;
-}
-
-/*! \brief Helper function which performs a single registration */
-static int sip_outbound_registration_perform(void *data)
-{
-	RAII_VAR(struct sip_outbound_registration_state *, state, data, ao2_cleanup);
-	RAII_VAR(struct sip_outbound_registration *, registration, ao2_bump(state->registration), ao2_cleanup);
-	size_t i;
-
-	/* Just in case the client state is being reused for this registration, free the auth information */
-	ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
-
-	AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
-	for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
-		const char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
-		AST_VECTOR_APPEND(&state->client_state->outbound_auths, name);
-	}
-	state->client_state->retry_interval = registration->retry_interval;
-	state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
-	state->client_state->max_retries = registration->max_retries;
-	state->client_state->retries = 0;
-	state->client_state->support_path = registration->support_path;
-	state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
-
-	pjsip_regc_update_expires(state->client_state->client, registration->expiration);
-
-	schedule_registration(state->client_state, (ast_random() % 10) + 1);
-
-	return 0;
-}
-
-/*! \brief Apply function which finds or allocates a state structure */
-static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
-{
-	RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
-	RAII_VAR(struct sip_outbound_registration_state *, state,
-		 ao2_find(states, ast_sorcery_object_get_id(obj), OBJ_SEARCH_KEY), ao2_cleanup);
-	RAII_VAR(struct sip_outbound_registration_state *, new_state, NULL, ao2_cleanup);
-	struct sip_outbound_registration *applied = obj;
-
-	if (ast_strlen_zero(applied->server_uri)) {
-		ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'",
-			ast_sorcery_object_get_id(applied));
-		return -1;
-	} else if (ast_strlen_zero(applied->client_uri)) {
-		ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
-			ast_sorcery_object_get_id(applied));
-		return -1;
-	}
-
-	if (state && can_reuse_registration(state->registration, applied)) {
-		ao2_replace(state->registration, applied);
-		return 0;
-	}
-
-	if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
-		return -1;
-	}
-
-	if (ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, new_state)) {
-		return -1;
-	}
-
-	if (ast_sip_push_task(new_state->client_state->serializer,
-			      sip_outbound_registration_perform, ao2_bump(new_state))) {
-		ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
-			ast_sorcery_object_get_id(new_state->registration));
-		ao2_ref(new_state, -1);
-		return -1;
-	}
-
-	ao2_lock(states);
-
-	if (state) {
-		ao2_unlink(states, state);
-	}
-
-	ao2_link(states, new_state);
-	ao2_unlock(states);
-
-	return 0;
-}
-
-static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct sip_outbound_registration *registration = obj;
-
-	return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
-}
-
-static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct sip_outbound_registration *registration = obj;
-
-	return ast_sip_auths_to_str(&registration->outbound_auths, buf);
-}
-
-static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
-{
-	const struct sip_outbound_registration *registration = obj;
-	int i;
-	struct ast_variable *head = NULL;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
-		ast_variable_list_append(&head, ast_variable_new("outbound_auth",
-			AST_VECTOR_GET(&registration->outbound_auths, i), ""));
-	}
-
-	if (head) {
-		*fields = head;
-	}
-
-	return 0;
-}
-
-static int unregister_task(void *obj)
-{
-	RAII_VAR(struct sip_outbound_registration_state*, state, obj, ao2_cleanup);
-	struct pjsip_regc *client = state->client_state->client;
-	pjsip_tx_data *tdata;
-
-	if (pjsip_regc_unregister(client, &tdata) != PJ_SUCCESS) {
-		return 0;
-	}
-
-	ao2_ref(state->client_state, +1);
-	if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
-		ao2_cleanup(state->client_state);
-	}
-
-	return 0;
-}
-
-static int queue_unregister(struct sip_outbound_registration_state *state)
-{
-	ao2_ref(state, +1);
-	if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
-		ao2_ref(state, -1);
-		return -1;
-	}
-	return 0;
-}
-
-static char *cli_complete_registration(const char *line, const char *word,
-				       int pos, int state)
-{
-	char *result = NULL;
-	int wordlen;
-	int which = 0;
-	struct sip_outbound_registration *registration;
-	RAII_VAR(struct ao2_container *, registrations, NULL, ao2_cleanup);
-	struct ao2_iterator i;
-
-	if (pos != 3) {
-		return NULL;
-	}
-
-	wordlen = strlen(word);
-	registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
-		AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	if (!registrations) {
-		return NULL;
-	}
-
-	i = ao2_iterator_init(registrations, 0);
-	while ((registration = ao2_iterator_next(&i))) {
-		const char *name = ast_sorcery_object_get_id(registration);
-		if (!strncasecmp(word, name, wordlen) && ++which > state) {
-			result = ast_strdup(name);
-		}
-
-		ao2_cleanup(registration);
-		if (result) {
-			break;
-		}
-	}
-	ao2_iterator_destroy(&i);
-	return result;
-}
-
-static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
-	const char *registration_name;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip send unregister";
-		e->usage =
-			"Usage: pjsip send unregister <registration>\n"
-			"       Send a SIP REGISTER request to the specified outbound "
-			"registration with an expiration of 0. This will cause the contact "
-			"added by this registration to be removed on the remote system. Note: "
-			"The specified outbound registration will attempt to re-register "
-			"according to its last registration expiration.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return cli_complete_registration(a->line, a->word, a->pos, a->n);
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	registration_name = a->argv[3];
-
-	state = get_state(registration_name);
-	if (!state) {
-		ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
-		return CLI_FAILURE;
-	}
-
-	if (queue_unregister(state)) {
-		ast_cli(a->fd, "Failed to queue unregistration");
-		return 0;
-	}
-
-	return CLI_SUCCESS;
-}
-
-static int ami_unregister(struct mansession *s, const struct message *m)
-{
-	const char *registration_name = astman_get_header(m, "Registration");
-	RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
-
-	if (ast_strlen_zero(registration_name)) {
-		astman_send_error(s, m, "Registration parameter missing.");
-		return 0;
-	}
-
-	state = get_state(registration_name);
-	if (!state) {
-		astman_send_error(s, m, "Unable to retrieve registration entry\n");
-		return 0;
-	}
-
-	if (queue_unregister(state)) {
-		astman_send_ack(s, m, "Failed to queue unregistration");
-		return 0;
-	}
-
-	astman_send_ack(s, m, "Unregistration sent");
-	return 0;
-}
-
-struct sip_ami_outbound {
-	struct ast_sip_ami *ami;
-	int registered;
-	int not_registered;
-	struct sip_outbound_registration *registration;
-};
-
-static int ami_outbound_registration_task(void *obj)
-{
-	struct sip_ami_outbound *ami = obj;
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami), ast_free);
-	struct sip_outbound_registration_state *state;
-
-	if (!buf) {
-		return -1;
-	}
-
-	ast_sip_sorcery_object_to_ami(ami->registration, &buf);
-
-	if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
-		pjsip_regc_info info;
-		if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
-			++ami->registered;
-		} else {
-			++ami->not_registered;
-		}
-
-		ast_str_append(&buf, 0, "Status: %s%s",
-			       sip_outbound_registration_status_str[
-				       state->client_state->status], "\r\n");
-
-		pjsip_regc_get_info(state->client_state->client, &info);
-		ast_str_append(&buf, 0, "NextReg: %d%s", info.next_reg, "\r\n");
-		ao2_ref(state, -1);
-	}
-
-	astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
-	return ast_sip_format_auths_ami(&ami->registration->outbound_auths, ami->ami);
-}
-
-static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
-{
-	struct sip_ami_outbound *ami = arg;
-
-	ami->registration = obj;
-	return ast_sip_push_task_synchronous(
-		NULL, ami_outbound_registration_task, ami);
-}
-
-static int ami_show_outbound_registrations(struct mansession *s,
-					   const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
-	struct sip_ami_outbound ami_outbound = { .ami = &ami };
-	RAII_VAR(struct ao2_container *, regs, get_registrations(), ao2_cleanup);
-
-	if (!regs) {
-		astman_send_error(s, m, "Unable to retreive "
-				  "outbound registrations\n");
-		return -1;
-	}
-
-	astman_send_listack(s, m, "Following are Events for each Outbound "
-			    "registration", "start");
-
-	ao2_callback(regs, OBJ_NODATA, ami_outbound_registration_detail, &ami_outbound);
-
-	astman_append(s, "Event: OutboundRegistrationDetailComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "Registered: %d\r\n"
-		      "NotRegistered: %d\r\n\r\n",
-		      ami_outbound.registered,
-		      ami_outbound.not_registered);
-	return 0;
-}
-
-static struct ao2_container *cli_get_container(void)
-{
-	RAII_VAR(struct ao2_container *, container, get_registrations(), ao2_cleanup);
-	struct ao2_container *s_container;
-
-	if (!container) {
-		return NULL;
-	}
-
-	s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-		ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-	if (!s_container) {
-		return NULL;
-	}
-
-	if (ao2_container_dup(s_container, container, 0)) {
-		ao2_ref(s_container, -1);
-		return NULL;
-	}
-
-	return s_container;
-}
-
-static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
-{
-	ao2_callback(container, OBJ_NODATA, callback, args);
-
-	return 0;
-}
-
-static void *cli_retrieve_by_id(const char *id)
-{
-	struct ao2_container *states;
-	void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
-
-	if (!obj) {
-		/* if the object no longer exists then remove its state  */
-		ao2_find((states = ao2_global_obj_ref(current_states)),
-			 id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-		ao2_ref(states, -1);
-	}
-
-	return obj;
-}
-
-static int cli_print_header(void *obj, void *arg, int flags)
-{
-	struct ast_sip_cli_context *context = arg;
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0,
-		" <Registration/ServerURI..............................>  <Auth..........>  <Status.......>\n");
-
-	return 0;
-}
-
-static int cli_print_body(void *obj, void *arg, int flags)
-{
-	struct sip_outbound_registration *registration = obj;
-	struct ast_sip_cli_context *context = arg;
-	const char *id = ast_sorcery_object_get_id(registration);
-	struct sip_outbound_registration_state *state = get_state(id);
-#define REGISTRATION_URI_FIELD_LEN	53
-
-	ast_assert(context->output_buffer != NULL);
-
-	ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s  %-16s  %-16s\n",
-		id,
-		(int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
-		(int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
-		registration->server_uri,
-		AST_VECTOR_SIZE(&registration->outbound_auths)
-			? AST_VECTOR_GET(&registration->outbound_auths, 0)
-			: "n/a",
-		sip_outbound_registration_status_str[state->client_state->status]);
-	ao2_ref(state, -1);
-
-	if (context->show_details
-		|| (context->show_details_only_level_0 && context->indent_level == 0)) {
-		ast_str_append(&context->output_buffer, 0, "\n");
-		ast_sip_cli_print_sorcery_objectset(registration, context, 0);
-	}
-
-	return 0;
-}
-
-/*
- * A function pointer to callback needs to be within the
- * module in order to avoid problems with an undefined
- * symbol when the module is loaded.
- */
-static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	return ast_sip_cli_traverse_objects(e, cmd, a);
-}
-
-static struct ast_cli_entry cli_outbound_registration[] = {
-	AST_CLI_DEFINE(cli_unregister, "Send a REGISTER request to an outbound registration target with a expiration of 0"),
-	AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
-		.command = "pjsip list registrations",
-		.usage = "Usage: pjsip list registrations\n"
-				 "       List the configured PJSIP Registrations\n"),
-	AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
-		.command = "pjsip show registrations",
-		.usage = "Usage: pjsip show registrations\n"
-				 "       Show the configured PJSIP Registrations\n"),
-	AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
-		.command = "pjsip show registration",
-		.usage = "Usage: pjsip show registration <id>\n"
-				 "       Show the configured PJSIP Registration\n"),
-};
-
-static struct ast_sip_cli_formatter_entry *cli_formatter;
-
-static int unload_module(void)
-{
-	ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
-	ast_sip_unregister_cli_formatter(cli_formatter);
-	ast_manager_unregister("PJSIPShowRegistrationsOutbound");
-	ast_manager_unregister("PJSIPUnregister");
-
-	ao2_global_obj_release(current_states);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	struct ao2_container *registrations, *new_states;
-	CHECK_PJSIP_MODULE_LOADED();
-
-	ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
-	ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
-
-	if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
-
-	ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
-	ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
-
-	cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
-	if (!cli_formatter) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
-		unload_module();
-		return -1;
-	}
-	cli_formatter->name = "registration";
-	cli_formatter->print_header = cli_print_header;
-	cli_formatter->print_body = cli_print_body;
-	cli_formatter->get_container = cli_get_container;
-	cli_formatter->iterate = cli_iterator;
-	cli_formatter->get_id = ast_sorcery_object_get_id;
-	cli_formatter->retrieve_by_id = cli_retrieve_by_id;
-
-	ast_sip_register_cli_formatter(cli_formatter);
-	ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
-
-	if (!(new_states = ao2_container_alloc(
-		      DEFAULT_STATE_BUCKETS, registration_state_hash, registration_state_cmp))) {
-		ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	ao2_global_obj_replace_unref(current_states, new_states);
-	ao2_ref(new_states, -1);
-
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
-	if (!(registrations = get_registrations())) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	ao2_ref(registrations, -1);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
-	ao2_cleanup(get_registrations());
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Registration Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c
deleted file mode 100644
index d0ee5a4..0000000
--- a/res/res_pjsip_path.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-#include "asterisk/strings.h"
-
-static const pj_str_t PATH_NAME = { "Path", 4 };
-static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
-
-static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
-{
-	char *configured_aors, *aor_name;
-	pjsip_sip_uri *sip_uri;
-	char *domain_name;
-	RAII_VAR(struct ast_str *, id, NULL, ast_free);
-
-	if (ast_strlen_zero(endpoint->aors)) {
-		return NULL;
-	}
-
-	sip_uri = pjsip_uri_get_uri(uri);
-	domain_name = ast_alloca(sip_uri->host.slen + 1);
-	ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);
-
-	configured_aors = ast_strdupa(endpoint->aors);
-
-	/* Iterate the configured AORs to see if the user or the user+domain match */
-	while ((aor_name = strsep(&configured_aors, ","))) {
-		struct ast_sip_domain_alias *alias = NULL;
-
-		if (!pj_strcmp2(&sip_uri->user, aor_name)) {
-			break;
-		}
-
-		if (!id && !(id = ast_str_create(sip_uri->user.slen + sip_uri->host.slen + 2))) {
-			return NULL;
-		}
-
-		ast_str_set(&id, 0, "%.*s@", (int)sip_uri->user.slen, sip_uri->user.ptr);
-		if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
-			ast_str_append(&id, 0, "%s", alias->domain);
-			ao2_cleanup(alias);
-		} else {
-			ast_str_append(&id, 0, "%s", domain_name);
-		}
-
-		if (!strcmp(aor_name, ast_str_buffer(id))) {
-			ast_free(id);
-			break;
-		}
-	}
-
-	if (ast_strlen_zero(aor_name)) {
-		return NULL;
-	}
-
-	return ast_sip_location_retrieve_aor(aor_name);
-}
-
-/*!
- * \brief Get the path string associated with this contact and tdata
- *
- * \param endpoint The endpoint from which to pull associated path data
- * \param contact_uri The URI identifying the associated contact
- * \param path_str The place to store the retrieved path information
- *
- * \retval zero on success
- * \retval non-zero on failure or no available path information
- */
-static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
-{
-	if (!contact || ast_strlen_zero(contact->path)) {
-		return -1;
-	}
-
-	*path_str = pj_strdup3(pool, contact->path);
-	return 0;
-}
-
-static int add_supported(pjsip_tx_data *tdata)
-{
-	pjsip_supported_hdr *hdr;
-
-	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
-	if (!hdr) {
-		/* insert a new Supported header */
-		hdr = pjsip_supported_hdr_create(tdata->pool);
-		if (!hdr) {
-			return -1;
-		}
-
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
-	}
-
-	/* add on to the existing Supported header */
-	pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Adds a Route header to an outgoing request if
- * path information is available.
- *
- * \param endpoint The endpoint with which this request is associated
- * \param contact The contact to which this request is being sent
- * \param tdata The outbound request
- */
-static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
-{
-	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
-
-	if (!endpoint) {
-		return;
-	}
-
-	aor = find_aor(endpoint, tdata->msg->line.req.uri);
-	if (!aor || !aor->support_path) {
-		return;
-	}
-
-	if (add_supported(tdata)) {
-		return;
-	}
-
-	if (contact && !ast_strlen_zero(contact->path)) {
-		ast_sip_set_outbound_proxy(tdata, contact->path);
-	}
-}
-
-static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	path_outgoing_request(session->endpoint, session->contact, tdata);
-}
-
-/*!
- * \internal
- * \brief Adds a path header to an outgoing 2XX response
- *
- * \param endpoint The endpoint to which the INVITE response is to be sent
- * \param contact The contact to which the INVITE response is to be sent
- * \param tdata The outbound INVITE response
- */
-static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
-{
-	struct pjsip_status_line status = tdata->msg->line.status;
-	pj_str_t path_dup;
-	pjsip_generic_string_hdr *path_hdr;
-	pjsip_contact_hdr *contact_hdr;
-	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
-	pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
-
-	if (!endpoint
-		|| !pj_stristr(&REGISTER_METHOD, &cseq->method.name)
-		|| !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
-		return;
-	}
-
-	contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
-	if (!contact_hdr) {
-		return;
-	}
-
-	aor = find_aor(endpoint, contact_hdr->uri);
-	if (!aor || !aor->support_path || add_supported(tdata)
-		|| path_get_string(tdata->pool, contact, &path_dup)) {
-		return;
-	}
-
-	path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
-	if (!path_hdr) {
-		return;
-	}
-
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
-}
-
-static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	path_outgoing_response(session->endpoint, session->contact, tdata);
-}
-
-static struct ast_sip_supplement path_supplement = {
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
-	.outgoing_request = path_outgoing_request,
-	.outgoing_response = path_outgoing_response,
-};
-
-static struct ast_sip_session_supplement path_session_supplement = {
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
-	.outgoing_request = path_session_outgoing_request,
-	.outgoing_response = path_session_outgoing_response,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (ast_sip_register_supplement(&path_supplement)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_session_register_supplement(&path_session_supplement)) {
-		ast_sip_unregister_supplement(&path_supplement);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_supplement(&path_supplement);
-	ast_sip_session_unregister_supplement(&path_session_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-);
diff --git a/res/res_pjsip_phoneprov_provider.c b/res/res_pjsip_phoneprov_provider.c
deleted file mode 100644
index 61b026f..0000000
--- a/res/res_pjsip_phoneprov_provider.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Fairview 5 Engineering, LLC
- *
- * George Joseph <george.joseph at fairview5.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief PJSIP Phoneprov Configuration Provider
- *
- * \author George Joseph <george.joseph at fairview5.com>
-  */
-
-/*! \li \ref res_pjsip_phoneprov_provider.c uses the configuration file \ref pjsip.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page pjsip.conf pjsip.conf
- * \verbinclude pjsip.conf.sample
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_phoneprov</depend>
-	<support_level>extended</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/phoneprov.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_phoneprov_provider" language="en_US">
-		<synopsis>Module that integrates res_pjsip with res_phoneprov.</synopsis>
-		<description><para>
-			<emphasis>PJSIP Phoneprov Provider</emphasis>
-			</para>
-			<para>This module creates the integration between <literal>res_pjsip</literal> and
-			<literal>res_phoneprov</literal>.
-			</para>
-			<para>Each user to be integrated requires a <literal>phoneprov</literal>
-			section defined in <filename>pjsip.conf</filename>.  Each section identifies
-			the endpoint associated with the user and any other name/value pairs to be passed
-			on to res_phoneprov's template substitution.  Only <literal>MAC</literal> and
-			<literal>PROFILE</literal> variables are required.  Any other variables
-			supplied will be passed through.</para>
-			<para> </para>
-			<para>Example:</para>
-			<para>[1000]</para>
-			<para>type = phoneprovr</para>
-			<para>endpoint = ep1000</para>
-			<para>MAC = deadbeef4dad</para>
-			<para>PROFILE = grandstream2</para>
-			<para>LINEKEYS = 2</para>
-			<para>LINE = 1</para>
-			<para>OTHERVAR = othervalue</para>
-			<para> </para>
-			<para>The following variables are automatically defined if an endpoint
-			is defined for the user:</para>
-			<enumlist>
-				<enum name="USERNAME"><para>Source: The user_name defined in the first auth reference
-				in the endpoint.</para></enum>
-				<enum name="SECRET"><para>Source: The user_pass defined in the first auth reference
-				in the endpoint.</para></enum>
-				<enum name="CALLERID"><para>Source: The number part of the callerid defined in
-				the endpoint.</para></enum>
-				<enum name="DISPLAY_NAME"><para>Source: The name part of the callerid defined in
-				the endpoint.</para></enum>
-				<enum name="LABEL"><para>Source: The id of the phoneprov section.</para></enum>
-			</enumlist>
-			<para> </para>
-			<para>In addition to the standard variables, the following are also automatically defined:</para>
-			<enumlist>
-				<enum name="ENDPOINT_ID"><para>Source: The id of the endpoint.</para></enum>
-				<enum name="TRANSPORT_ID"><para>Source: The id of the transport used by the endpoint.</para></enum>
-				<enum name="AUTH_ID"><para>Source: The id of the auth used by the endpoint.</para></enum>
-			</enumlist>
-			<para> </para>
-			<para>All other template substitution variables must be explicitly defined in the
-			phoneprov_default or phoneprov sections.</para>
-		</description>
-
-		<configFile name="pjsip.conf">
-			<configObject name="phoneprov">
-				<synopsis>Provides variables for each user.</synopsis>
-				<configOption name="type">
-					<synopsis>Must be of type 'phoneprov'.</synopsis>
-				</configOption>
-				<configOption name="endpoint">
-					<synopsis>The endpoint from which variables will be retrieved.</synopsis>
-				</configOption>
-				<configOption name="MAC">
-					<synopsis>The mac address for this user. (required)</synopsis>
-				</configOption>
-				<configOption name="PROFILE">
-					<synopsis>The phoneprov profile to use for this user. (required)</synopsis>
-				</configOption>
-				<configOption name="*">
-					<synopsis>Other name/value pairs to be passed through for use in templates.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-static struct ast_sorcery *sorcery;
-
-/*! \brief Structure for a phoneprov object */
-struct phoneprov {
-	SORCERY_OBJECT(details);
-	struct varshead *vars;
-};
-
-/*! \brief Destructor function for phoneprov */
-static void phoneprov_destroy(void *obj)
-{
-	struct phoneprov *pp = obj;
-
-	ast_var_list_destroy(pp->vars);
-}
-
-/*! \brief Allocator for phoneprov */
-static void *phoneprov_alloc(const char *name)
-{
-	struct phoneprov *pp = ast_sorcery_generic_alloc(sizeof(*pp), phoneprov_destroy);
-
-	if (!pp || !(pp->vars = ast_var_list_create())) {
-		ast_log(LOG_ERROR, "Unable to allocate memory for phoneprov structure %s\n",
-			name);
-		ao2_cleanup(pp);
-		return NULL;
-	}
-
-	return pp;
-}
-
-/*! \brief Helper that creates an ast_var_t and inserts it into the list */
-static int assign_and_insert(const char *name, const char *value, struct varshead *vars)
-{
-	struct ast_var_t *var;
-
-	if (ast_strlen_zero(name) || !vars) {
-		return -1;
-	}
-
-	/* Just ignore if the value is NULL or empty */
-	if (ast_strlen_zero(value)) {
-		return 0;
-	}
-
-	var = ast_var_assign(name, value);
-	if (!var) {
-		ast_log(LOG_ERROR, "Could not allocate variable memory for variable.\n");
-		return -1;
-	}
-	AST_VAR_LIST_INSERT_TAIL(vars, var);
-
-	return 0;
-}
-
-/*! \brief Adds a config name/value pair to the phoneprov object */
-static int aco_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct phoneprov *pp = obj;
-
-	return assign_and_insert(var->name, var->value, pp->vars);
-}
-
-/*! \brief Converts the phoneprov varlist to an ast_variable list */
-static int fields_handler(const void *obj, struct ast_variable **fields)
-{
-	const struct phoneprov *pp = obj;
-	struct ast_var_t *pvar;
-	struct ast_variable *head = NULL;
-	struct ast_variable *tail = NULL;
-	struct ast_variable *var;
-
-	AST_VAR_LIST_TRAVERSE(pp->vars, pvar) {
-		var = ast_variable_new(pvar->name, pvar->value, NULL);
-		if (!var) {
-			ast_variables_destroy(head);
-			return -1;
-		}
-		if (!head) {
-			head = var;
-			tail = var;
-			continue;
-		}
-		tail->next = var;
-		tail = var;
-	}
-
-	*fields = head;
-
-	return 0;
-}
-
-static int load_endpoint(const char *id, const char *endpoint_name, struct varshead *vars,
-	char *port_string)
-{
-	struct ast_sip_auth *auth;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
-	const char *auth_name;
-
-	*port_string = '\0';
-
-	/* We need to use res_pjsip's sorcery instance instead of our own to
-	 * get endpoint and auth.
-	 */
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
-		endpoint_name);
-	if (!endpoint) {
-		ast_log(LOG_ERROR, "phoneprov %s contained invalid endpoint %s.\n", id,
-			endpoint_name);
-		return -1;
-	}
-
-	assign_and_insert("ENDPOINT_ID", endpoint_name, vars);
-	assign_and_insert("TRANSPORT_ID", endpoint->transport, vars);
-
-	if (endpoint->id.self.number.valid && !ast_strlen_zero(endpoint->id.self.number.str)) {
-		assign_and_insert(ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_CALLERID),
-			endpoint->id.self.number.str, vars);
-	}
-
-	if (endpoint->id.self.name.valid && !ast_strlen_zero(endpoint->id.self.name.str)) {
-		assign_and_insert(
-			ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_DISPLAY_NAME),
-			endpoint->id.self.name.str, vars);
-	}
-
-	transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
-		endpoint->transport);
-	if (!transport) {
-		ast_log(LOG_ERROR, "Endpoint %s contained invalid transport %s.\n", endpoint_name,
-			endpoint->transport);
-		return -1;
-	}
-	snprintf(port_string, 6, "%d", pj_sockaddr_get_port(&transport->host));
-
-	if (!AST_VECTOR_SIZE(&endpoint->inbound_auths)) {
-		return 0;
-	}
-	auth_name = AST_VECTOR_GET(&endpoint->inbound_auths, 0);
-
-	auth = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "auth", auth_name);
-	if (!auth) {
-		ast_log(LOG_ERROR, "phoneprov %s contained invalid auth %s.\n", id, auth_name);
-		return -1;
-	}
-
-	assign_and_insert("AUTH_ID", auth_name, vars);
-	assign_and_insert(ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_USERNAME),
-		auth->auth_user, vars);
-	assign_and_insert(ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_SECRET),
-		auth->auth_pass, vars);
-	ao2_ref(auth, -1);
-
-	return 0;
-}
-
-/*! \brief Callback that loads the users from phoneprov sections */
-static int load_users(void)
-{
-	struct phoneprov *pp;
-	struct ao2_container *c;
-	struct ao2_iterator i;
-	int user_count = 0;
-	char port_string[6];
-
-	c = ast_sorcery_retrieve_by_fields(sorcery, "phoneprov", AST_RETRIEVE_FLAG_MULTIPLE, NULL);
-	if (!c) {
-		ast_log(LOG_ERROR, "Retrieve by regex failed to allocate a container.\n");
-		return -1;
-	}
-	if (ao2_container_count(c) == 0) {
-		ast_log(LOG_ERROR, "Unable to find any phoneprov users.\n");
-		ao2_cleanup(c);
-		return -1;
-	}
-
-	i = ao2_iterator_init(c, 0);
-	while ((pp = ao2_iterator_next(&i))) {
-		const char *endpoint_name;
-		const char *id = ast_sorcery_object_get_id(pp);
-
-		endpoint_name = ast_var_find(pp->vars, "endpoint");
-		if (endpoint_name) {
-			if (load_endpoint(id, endpoint_name, pp->vars, port_string)) {
-				goto cleanup;
-			}
-		}
-
-		if (!ast_var_find(pp->vars,
-			ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_USERNAME))) {
-			assign_and_insert(
-				ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_USERNAME), id,
-				pp->vars);
-		}
-
-		if (!ast_var_find(pp->vars,
-			ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_LABEL))) {
-			assign_and_insert(ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_LABEL),
-				id, pp->vars);
-		}
-
-		if (!ast_var_find(pp->vars,
-			ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_SERVER_PORT))) {
-			assign_and_insert("SERVER_PORT", S_OR(port_string, "5060"), pp->vars);
-		}
-
-		if (!ast_var_find(pp->vars,
-			ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_PROFILE))) {
-			ast_log(LOG_ERROR, "phoneprov %s didn't contain a PROFILE entry.\n", id);
-		} else if (!ast_phoneprov_add_extension(AST_MODULE, pp->vars)) {
-			user_count++;
-		}
-		ao2_ref(pp, -1);
-	}
-
-cleanup:
-	ao2_iterator_destroy(&i);
-	ao2_cleanup(pp);
-	ao2_cleanup(c);
-
-	return user_count > 0 ? 0 : -1;
-}
-
-/*! \brief Callback that validates the phoneprov object */
-static int users_apply_handler(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct phoneprov *pp = obj;
-	const char *id = ast_sorcery_object_get_id(pp);
-
-	if (!ast_var_find(pp->vars,
-		ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_MAC))) {
-		ast_log(LOG_ERROR, "phoneprov %s must contain a MAC entry.\n", id);
-		return -1;
-	}
-
-	if (!ast_var_find(pp->vars,
-		ast_phoneprov_std_variable_lookup(AST_PHONEPROV_STD_PROFILE))) {
-		ast_log(LOG_ERROR, "phoneprov %s must contain a PROFILE entry.\n", id);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_log(LOG_ERROR, "Unable to open a sorcery instance.\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_apply_default(sorcery, "phoneprov", "config", "pjsip.conf,criteria=type=phoneprov");
-
-	ast_sorcery_object_register(sorcery, "phoneprov", phoneprov_alloc, NULL,
-		users_apply_handler);
-	ast_sorcery_object_field_register(sorcery, "phoneprov", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_fields_register(sorcery, "phoneprov", "^", aco_handler,
-		fields_handler);
-	ast_sorcery_reload_object(sorcery, "phoneprov");
-
-	if (ast_phoneprov_provider_register(AST_MODULE, load_users)) {
-		ast_log(LOG_ERROR, "Unable to register pjsip phoneprov provider.\n");
-		ast_sorcery_unref(sorcery);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_phoneprov_provider_unregister(AST_MODULE);
-	ast_sorcery_unref(sorcery);
-
-	return 0;
-}
-
-static int reload_module(void)
-{
-	unload_module();
-	load_module();
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Phoneprov Provider",
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-		);
diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c
deleted file mode 100644
index ef0cce5..0000000
--- a/res/res_pjsip_pidf_body_generator.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-static void *pidf_allocate_body(void *data)
-{
-	struct ast_sip_exten_state_data *state_data = data;
-	char *local = ast_strdupa(state_data->local);
-	pjpidf_pres *pres;
-	pj_str_t entity;
-
-	pres = pjpidf_create(state_data->pool, pj_cstr(&entity, ast_strip_quoted(local, "<", ">")));
-
-	return pres;
-}
-
-static int pidf_generate_body_content(void *body, void *data)
-{
-	pjpidf_tuple *tuple;
-	pj_str_t note, id, contact, priority;
-	char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
-	enum ast_sip_pidf_state local_state;
-	char sanitized[PJSIP_MAX_URL_SIZE];
-	pjpidf_pres *pres = body;
-	struct ast_sip_exten_state_data *state_data = data;
-
-	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
-
-	if (!pjpidf_pres_add_note(state_data->pool, pres, pj_cstr(&note, pidfnote))) {
-		ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n");
-		return -1;
-	}
-
-	if (!(tuple = pjpidf_pres_add_tuple(state_data->pool, pres,
-					pj_cstr(&id, state_data->exten)))) {
-		ast_log(LOG_WARNING, "Unable to create PIDF tuple\n");
-		return -1;
-	}
-
-	ast_sip_sanitize_xml(state_data->remote, sanitized, sizeof(sanitized));
-	pjpidf_tuple_set_contact(state_data->pool, tuple, pj_cstr(&contact, sanitized));
-	pjpidf_tuple_set_contact_prio(state_data->pool, tuple, pj_cstr(&priority, "1"));
-	pjpidf_status_set_basic_open(pjpidf_tuple_get_status(tuple),
-			local_state == NOTIFY_OPEN);
-
-	return 0;
-}
-
-#define MAX_STRING_GROWTHS 5
-
-static void pidf_to_string(void *body, struct ast_str **str)
-{
-	int size;
-	int growths = 0;
-	pjpidf_pres *pres = body;
-
-	do {
-		size = pjpidf_print(pres, ast_str_buffer(*str), ast_str_size(*str) - 1);
-		if (size == AST_PJSIP_XML_PROLOG_LEN) {
-			ast_str_make_space(str, ast_str_size(*str) * 2);
-			++growths;
-		}
-	} while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS);
-
-	if (size == AST_PJSIP_XML_PROLOG_LEN) {
-		ast_log(LOG_WARNING, "PIDF body text too large\n");
-		return;
-	}
-
-	*(ast_str_buffer(*str) + size) = '\0';
-	ast_str_update(*str);
-}
-
-static struct ast_sip_pubsub_body_generator pidf_body_generator = {
-	.type = "application",
-	.subtype = "pidf+xml",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.allocate_body = pidf_allocate_body,
-	.generate_body_content = pidf_generate_body_content,
-	.to_string = pidf_to_string,
-	/* No need for a destroy_body callback since we use a pool */
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_generator(&pidf_body_generator)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_pubsub_unregister_body_generator(&pidf_body_generator);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State PIDF Provider",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_pidf_digium_body_supplement.c b/res/res_pjsip_pidf_digium_body_supplement.c
deleted file mode 100644
index 86e673a..0000000
--- a/res/res_pjsip_pidf_digium_body_supplement.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/presencestate.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-static int pidf_supplement_body(void *body, void *data)
-{
-	struct ast_sip_exten_state_data *state_data = data;
-	pj_xml_node *node;
-	char sanitized[256];
-
-	if (ast_strlen_zero(state_data->user_agent) ||
-	    !strstr(state_data->user_agent, "digium")) {
-		/* not a digium phone */
-		return 0;
-	}
-
-	if (!(node = ast_sip_presence_xml_create_node(
-		      state_data->pool, body, "tuple"))) {
-		ast_log(LOG_WARNING, "Unable to create PIDF tuple\n");
-		return -1;
-	}
-
-	ast_sip_presence_xml_create_attr(
-		state_data->pool, node, "id", "digium-presence");
-
-	if (!(node = ast_sip_presence_xml_create_node(
-		      state_data->pool, node, "status"))) {
-		ast_log(LOG_WARNING, "Unable to create PIDF tuple status\n");
-		return -1;
-	}
-
-	if (!(node = ast_sip_presence_xml_create_node(
-		      state_data->pool, node, "digium_presence"))) {
-		ast_log(LOG_WARNING, "Unable to create digium presence\n");
-		return -1;
-	}
-
-	if (!ast_strlen_zero(state_data->presence_message)) {
-		ast_sip_sanitize_xml(state_data->presence_message, sanitized, sizeof(sanitized));
-		pj_strdup2(state_data->pool, &node->content, sanitized);
-	}
-
-	ast_sip_presence_xml_create_attr(
-		state_data->pool, node, "type", ast_presence_state2str(
-			state_data->presence_state));
-
-	if (!ast_strlen_zero(state_data->presence_subtype)) {
-		ast_sip_sanitize_xml(state_data->presence_subtype, sanitized, sizeof(sanitized));
-		ast_sip_presence_xml_create_attr(
-			state_data->pool, node, "subtype", sanitized);
-	}
-
-	return 0;
-}
-
-static struct ast_sip_pubsub_body_supplement pidf_supplement = {
-	.type = "application",
-	.subtype = "pidf+xml",
-	.supplement_body = pidf_supplement_body,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_supplement(&pidf_supplement)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_pubsub_unregister_body_supplement(&pidf_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Digium presence supplement",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c
deleted file mode 100644
index cd590c3..0000000
--- a/res/res_pjsip_pidf_eyebeam_body_supplement.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-/*!
- * \internal
- * \brief Adds non standard elements to the xml body
- *
- * This is some code that was part of the original chan_sip implementation
- * that is not part of the RFC 3863 definition, but we are keeping available
- * for backward compatability. The original comment stated that Eyebeam
- * supports this format.
- */
-static void add_eyebeam(pj_pool_t *pool, pj_xml_node *node, const char *pidfstate)
-{
-	static const char *XMLNS_PP = "xmlns:pp";
-	static const char *XMLNS_PERSON = "urn:ietf:params:xml:ns:pidf:person";
-
-	static const char *XMLNS_ES = "xmlns:es";
-	static const char *XMLNS_RPID_STATUS = "urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status";
-
-	static const char *XMLNS_EP = "xmlns:ep";
-	static const char *XMLNS_RPID_PERSON = "urn:ietf:params:xml:ns:pidf:rpid:rpid-person";
-
-	pj_xml_node *person = ast_sip_presence_xml_create_node(pool, node, "pp:person");
-	pj_xml_node *status = ast_sip_presence_xml_create_node(pool, person, "status");
-
-	if (pidfstate[0] != '-') {
-		pj_xml_node *activities = ast_sip_presence_xml_create_node(pool, status, "ep:activities");
-		size_t str_size = sizeof("ep:") + strlen(pidfstate);
-
-		activities->content.ptr = pj_pool_alloc(pool, str_size);
-		activities->content.slen = pj_ansi_snprintf(activities->content.ptr, str_size,
-				"ep:%s", pidfstate);
-	}
-
-	ast_sip_presence_xml_create_attr(pool, node, XMLNS_PP, XMLNS_PERSON);
-	ast_sip_presence_xml_create_attr(pool, node, XMLNS_ES, XMLNS_RPID_STATUS);
-	ast_sip_presence_xml_create_attr(pool, node, XMLNS_EP, XMLNS_RPID_PERSON);
-}
-
-static int pidf_supplement_body(void *body, void *data)
-{
-	pjpidf_pres *pres = body;
-	struct ast_sip_exten_state_data *state_data = data;
-	char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
-	enum ast_sip_pidf_state local_state;
-
-	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
-
-	add_eyebeam(state_data->pool, pres, pidfstate);
-	return 0;
-}
-
-static struct ast_sip_pubsub_body_supplement pidf_supplement = {
-	.type = "application",
-	.subtype = "pidf+xml",
-	.supplement_body = pidf_supplement_body,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_supplement(&pidf_supplement)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_pubsub_unregister_body_supplement(&pidf_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Eyebeam supplement",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c
deleted file mode 100644
index e1b095e..0000000
--- a/res/res_pjsip_publish_asterisk.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_outbound_publish</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <regex.h>
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_outbound_publish.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/app.h"
-
-/*** DOCUMENTATION
-	<configInfo name="res_pjsip_publish_asterisk" language="en_US">
-		<synopsis>SIP resource for inbound and outbound Asterisk event publications</synopsis>
-		<description><para>
-			<emphasis>Inbound and outbound Asterisk event publication</emphasis>
-			</para>
-			<para>This module allows <literal>res_pjsip</literal> to send and receive Asterisk event publications.</para>
-		</description>
-		<configFile name="pjsip.conf">
-			<configObject name="asterisk-publication">
-				<synopsis>The configuration for inbound Asterisk event publication</synopsis>
-				<description><para>
-					Publish is <emphasis>COMPLETELY</emphasis> separate from the rest of
-					<literal>pjsip.conf</literal>.
-				</para></description>
-				<configOption name="devicestate_publish">
-					<synopsis>Optional name of a publish item that can be used to publish a request for full device state information.</synopsis>
-				</configOption>
-				<configOption name="mailboxstate_publish">
-					<synopsis>Optional name of a publish item that can be used to publish a request for full mailbox state information.</synopsis>
-				</configOption>
-				<configOption name="device_state" default="no">
-					<synopsis>Whether we should permit incoming device state events.</synopsis>
-				</configOption>
-				<configOption name="device_state_filter">
-					<synopsis>Optional regular expression used to filter what devices we accept events for.</synopsis>
-				</configOption>
-				<configOption name="mailbox_state" default="no">
-					<synopsis>Whether we should permit incoming mailbox state events.</synopsis>
-				</configOption>
-				<configOption name="mailbox_state_filter">
-					<synopsis>Optional regular expression used to filter what mailboxes we accept events for.</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'asterisk-publication'.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-/*! \brief Structure which contains Asterisk device state publisher state information */
-struct asterisk_devicestate_publisher_state {
-	/*! \brief The publish client to send PUBLISH messages on */
-	struct ast_sip_outbound_publish_client *client;
-	/*! \brief Device state subscription */
-	struct stasis_subscription *device_state_subscription;
-	/*! \brief Regex used for filtering outbound device state */
-	regex_t device_state_regex;
-	/*! \brief Device state should be filtered */
-	unsigned int device_state_filter;
-};
-
-/*! \brief Structure which contains Asterisk mailbox publisher state information */
-struct asterisk_mwi_publisher_state {
-	/*! \brief The publish client to send PUBLISH messages on */
-	struct ast_sip_outbound_publish_client *client;
-	/*! \brief Mailbox state subscription */
-	struct stasis_subscription *mailbox_state_subscription;
-	/*! \brief Regex used for filtering outbound mailbox state */
-	regex_t mailbox_state_regex;
-	/*! \brief Mailbox state should be filtered */
-	unsigned int mailbox_state_filter;
-};
-
-/*! \brief Structure which contains Asterisk publication information */
-struct asterisk_publication_config {
-	/*! \brief Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! \brief Stringfields */
-	AST_DECLARE_STRING_FIELDS(
-		/*! \brief Optional name of a device state publish item, used to request the remote side update us */
-		AST_STRING_FIELD(devicestate_publish);
-		/*! \brief Optional name of a mailbox state publish item, used to request the remote side update us */
-		AST_STRING_FIELD(mailboxstate_publish);
-	);
-	/*! \brief Accept inbound device state events */
-	unsigned int device_state;
-	/*! \brief Regex used for filtering inbound device state */
-	regex_t device_state_regex;
-	/*! \brief Device state should be filtered */
-	unsigned int device_state_filter;
-	/*! \brief Accept inbound mailbox state events */
-	unsigned int mailbox_state;
-	/*! \brief Regex used for filtering inbound mailbox state */
-	regex_t mailbox_state_regex;
-	/*! \brief Mailbox state should be filtered */
-	unsigned int mailbox_state_filter;
-};
-
-/*! \brief Destroy callback for Asterisk devicestate publisher state information from datastore */
-static void asterisk_devicestate_publisher_state_destroy(void *obj)
-{
-	struct asterisk_devicestate_publisher_state *publisher_state = obj;
-
-	ao2_cleanup(publisher_state->client);
-
-	if (publisher_state->device_state_filter) {
-		regfree(&publisher_state->device_state_regex);
-	}
-}
-
-/*! \brief Datastore for attaching devicestate publisher state information */
-static const struct ast_datastore_info asterisk_devicestate_publisher_state_datastore = {
-	.type = "asterisk-devicestate-publisher",
-	.destroy = asterisk_devicestate_publisher_state_destroy,
-};
-
-/*! \brief Destroy callback for Asterisk mwi publisher state information from datastore */
-static void asterisk_mwi_publisher_state_destroy(void *obj)
-{
-	struct asterisk_mwi_publisher_state *publisher_state = obj;
-
-	ao2_cleanup(publisher_state->client);
-
-	if (publisher_state->mailbox_state_filter) {
-		regfree(&publisher_state->mailbox_state_regex);
-	}
-}
-
-/*! \brief Datastore for attaching devicestate publisher state information */
-static const struct ast_datastore_info asterisk_mwi_publisher_state_datastore = {
-	.type = "asterisk-mwi-publisher",
-	.destroy = asterisk_mwi_publisher_state_destroy,
-};
-
-/*!
- * \brief Callback function for device state events
- * \param ast_event
- * \param data void pointer to ast_client structure
- * \return void
- */
-static void asterisk_publisher_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
-{
-	struct ast_datastore *datastore = data;
-	struct asterisk_devicestate_publisher_state *publisher_state = datastore->data;
-	struct ast_device_state_message *dev_state;
-	char eid_str[20];
-	struct ast_json *json;
-	char *text;
-	struct ast_sip_body body = {
-		.type = "application",
-		.subtype = "json",
-	};
-
-	if (!stasis_subscription_is_subscribed(sub) || ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	dev_state = stasis_message_data(msg);
-	if (!dev_state->eid || ast_eid_cmp(&ast_eid_default, dev_state->eid)) {
-		/* If the event is aggregate or didn't originate from this server, don't send it out. */
-		return;
-	}
-
-	if (publisher_state->device_state_filter && regexec(&publisher_state->device_state_regex, dev_state->device, 0, NULL, 0)) {
-		/* Outgoing device state has been filtered and the device name does not match */
-		return;
-	}
-
-	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
-	json = ast_json_pack(
-		"{ s: s, s: s, s: s, s: i, s:s }",
-		"type", "devicestate",
-		"device", dev_state->device,
-		"state", ast_devstate_str(dev_state->state),
-		"cachable", dev_state->cachable,
-		"eid", eid_str);
-	if (!json) {
-		return;
-	}
-
-	text = ast_json_dump_string(json);
-	if (!text) {
-		ast_json_unref(json);
-		return;
-	}
-	body.body_text = text;
-
-	ast_sip_publish_client_send(publisher_state->client, &body);
-
-	ast_json_free(text);
-	ast_json_unref(json);
-}
-
-/*!
- * \brief Callback function for mailbox state events
- * \param ast_event
- * \param data void pointer to ast_client structure
- * \return void
- */
-static void asterisk_publisher_mwistate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
-{
-	struct ast_datastore *datastore = data;
-	struct asterisk_mwi_publisher_state *publisher_state = datastore->data;
-	struct ast_mwi_state *mwi_state;
-	char eid_str[20];
-	struct ast_json *json;
-	char *text;
-	struct ast_sip_body body = {
-		.type = "application",
-		.subtype = "json",
-	};
-
-	if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	mwi_state = stasis_message_data(msg);
-	if (ast_eid_cmp(&ast_eid_default, &mwi_state->eid)) {
-		/* If the event is aggregate or didn't originate from this server, don't send it out. */
-		return;
-	}
-
-	if (publisher_state->mailbox_state_filter && regexec(&publisher_state->mailbox_state_regex, mwi_state->uniqueid, 0, NULL, 0)) {
-		/* Outgoing mailbox state has been filtered and the uniqueid does not match */
-		return;
-	}
-
-	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
-	json = ast_json_pack(
-		"{ s: s, s: s, s: i, s: i, s:s }",
-		"type", "mailboxstate",
-		"uniqueid", mwi_state->uniqueid,
-		"old", mwi_state->old_msgs,
-		"new", mwi_state->new_msgs,
-		"eid", eid_str);
-	if (!json) {
-		return;
-	}
-
-	text = ast_json_dump_string(json);
-	if (!text) {
-		ast_json_unref(json);
-		return;
-	}
-	body.body_text = text;
-
-	ast_sip_publish_client_send(publisher_state->client, &body);
-
-	ast_json_free(text);
-	ast_json_unref(json);
-}
-
-static int cached_devstate_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_message *msg = obj;
-	struct ast_datastore *datastore = arg;
-	struct asterisk_devicestate_publisher_state *publisher_state = datastore->data;
-
-	asterisk_publisher_devstate_cb(arg, publisher_state->device_state_subscription, msg);
-
-	return 0;
-}
-
-static int cached_mwistate_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_message *msg = obj;
-	struct ast_datastore *datastore = arg;
-	struct asterisk_mwi_publisher_state *publisher_state = datastore->data;
-
-	asterisk_publisher_mwistate_cb(arg, publisher_state->mailbox_state_subscription, msg);
-
-	return 0;
-}
-
-static int build_regex(regex_t *regex, const char *text)
-{
-	int res;
-
-	if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
-		size_t len = regerror(res, regex, NULL, 0);
-		char buf[len];
-		regerror(res, regex, buf, len);
-		ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int asterisk_start_devicestate_publishing(struct ast_sip_outbound_publish *configuration,
-	struct ast_sip_outbound_publish_client *client)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	struct asterisk_devicestate_publisher_state *publisher_state;
-	const char *value;
-	struct ao2_container *cached;
-
-	datastore = ast_sip_publish_client_alloc_datastore(&asterisk_devicestate_publisher_state_datastore,
-		"asterisk-devicestate-publisher");
-	if (!datastore) {
-		return -1;
-	}
-
-	publisher_state = ast_calloc(1, sizeof(struct asterisk_devicestate_publisher_state));
-	if (!publisher_state) {
-		return -1;
-	}
-	datastore->data = publisher_state;
-
-	value = ast_sorcery_object_get_extended(configuration, "device_state_filter");
-	if (!ast_strlen_zero(value)) {
-		if (build_regex(&publisher_state->device_state_regex, value)) {
-			return -1;
-		}
-		publisher_state->device_state_filter = 1;
-	}
-
-	publisher_state->client = ao2_bump(client);
-
-	if (ast_sip_publish_client_add_datastore(client, datastore)) {
-		return -1;
-	}
-
-	publisher_state->device_state_subscription = stasis_subscribe(ast_device_state_topic_all(),
-		asterisk_publisher_devstate_cb, ao2_bump(datastore));
-	if (!publisher_state->device_state_subscription) {
-		ast_sip_publish_client_remove_datastore(client, "asterisk-devicestate-publisher");
-		ao2_ref(datastore, -1);
-		return -1;
-	}
-
-	cached = stasis_cache_dump(ast_device_state_cache(), NULL);
-	ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, datastore);
-	ao2_ref(cached, -1);
-
-	return 0;
-}
-
-static int asterisk_stop_devicestate_publishing(struct ast_sip_outbound_publish_client *client)
-{
-	RAII_VAR(struct ast_datastore *, datastore, ast_sip_publish_client_get_datastore(client, "asterisk-devicestate-publisher"),
-		ao2_cleanup);
-	struct asterisk_devicestate_publisher_state *publisher_state;
-
-	if (!datastore) {
-		return 0;
-	}
-
-	publisher_state = datastore->data;
-	if (publisher_state->device_state_subscription) {
-		stasis_unsubscribe_and_join(publisher_state->device_state_subscription);
-		ao2_ref(datastore, -1);
-	}
-
-	ast_sip_publish_client_remove_datastore(client, "asterisk-devicestate-publisher");
-
-	return 0;
-}
-
-struct ast_sip_event_publisher_handler asterisk_devicestate_publisher_handler = {
-	.event_name = "asterisk-devicestate",
-	.start_publishing = asterisk_start_devicestate_publishing,
-	.stop_publishing = asterisk_stop_devicestate_publishing,
-};
-
-static int asterisk_start_mwi_publishing(struct ast_sip_outbound_publish *configuration,
-	struct ast_sip_outbound_publish_client *client)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	struct asterisk_mwi_publisher_state *publisher_state;
-	const char *value;
-	struct ao2_container *cached;
-
-	datastore = ast_sip_publish_client_alloc_datastore(&asterisk_mwi_publisher_state_datastore, "asterisk-mwi-publisher");
-	if (!datastore) {
-		return -1;
-	}
-
-	publisher_state = ast_calloc(1, sizeof(struct asterisk_mwi_publisher_state));
-	if (!publisher_state) {
-		return -1;
-	}
-	datastore->data = publisher_state;
-
-	value = ast_sorcery_object_get_extended(configuration, "mailbox_state_filter");
-	if (!ast_strlen_zero(value)) {
-		if (build_regex(&publisher_state->mailbox_state_regex, value)) {
-			return -1;
-		}
-		publisher_state->mailbox_state_filter = 1;
-	}
-
-	publisher_state->client = ao2_bump(client);
-
-	if (ast_sip_publish_client_add_datastore(client, datastore)) {
-		return -1;
-	}
-
-	publisher_state->mailbox_state_subscription = stasis_subscribe(ast_mwi_topic_all(),
-		asterisk_publisher_mwistate_cb, ao2_bump(datastore));
-	if (!publisher_state->mailbox_state_subscription) {
-		ast_sip_publish_client_remove_datastore(client, "asterisk-mwi-publisher");
-		ao2_ref(datastore, -1);
-		return -1;
-	}
-
-	cached = stasis_cache_dump(ast_mwi_state_cache(), NULL);
-	ao2_callback(cached, OBJ_NODATA, cached_mwistate_cb, datastore);
-	ao2_ref(cached, -1);
-
-	return 0;
-}
-
-static int asterisk_stop_mwi_publishing(struct ast_sip_outbound_publish_client *client)
-{
-	RAII_VAR(struct ast_datastore *, datastore, ast_sip_publish_client_get_datastore(client, "asterisk-mwi-publisher"),
-		ao2_cleanup);
-	struct asterisk_mwi_publisher_state *publisher_state;
-
-	if (!datastore) {
-		return 0;
-	}
-
-	publisher_state = datastore->data;
-	if (publisher_state->mailbox_state_subscription) {
-		stasis_unsubscribe_and_join(publisher_state->mailbox_state_subscription);
-		ao2_ref(datastore, -1);
-	}
-
-	ast_sip_publish_client_remove_datastore(client, "asterisk-mwi-publisher");
-
-	return 0;
-}
-
-struct ast_sip_event_publisher_handler asterisk_mwi_publisher_handler = {
-	.event_name = "asterisk-mwi",
-	.start_publishing = asterisk_start_mwi_publishing,
-	.stop_publishing = asterisk_stop_mwi_publishing,
-};
-
-static int asterisk_publication_new(struct ast_sip_endpoint *endpoint, const char *resource, const char *event_configuration)
-{
-	RAII_VAR(struct asterisk_publication_config *, config, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "asterisk-publication",
-		event_configuration), ao2_cleanup);
-
-	/* If no inbound Asterisk publication configuration exists reject the PUBLISH */
-	if (!config) {
-		return 404;
-	}
-
-	return 200;
-}
-
-static int asterisk_publication_devicestate(struct ast_sip_publication *pub, struct asterisk_publication_config *config,
-	struct ast_eid *pubsub_eid, struct ast_json *json)
-{
-	const char *device = ast_json_string_get(ast_json_object_get(json, "device"));
-	const char *state = ast_json_string_get(ast_json_object_get(json, "state"));
-	int cachable = ast_json_integer_get(ast_json_object_get(json, "cachable"));
-
-	if (!config->device_state) {
-		ast_debug(2, "Received device state event for resource '%s' but it is not configured to accept them\n",
-			ast_sorcery_object_get_id(config));
-		return 0;
-	}
-
-	if (ast_strlen_zero(device) || ast_strlen_zero(state)) {
-		ast_debug(1, "Received incomplete device state event for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	if (config->device_state_filter && regexec(&config->device_state_regex, device, 0, NULL, 0)) {
-		ast_debug(2, "Received device state on resource '%s' for device '%s' but it has been filtered out\n",
-			ast_sorcery_object_get_id(config), device);
-		return 0;
-	}
-
-	ast_publish_device_state_full(device, ast_devstate_val(state),
-		cachable == AST_DEVSTATE_CACHABLE ? AST_DEVSTATE_CACHABLE : AST_DEVSTATE_NOT_CACHABLE,
-		pubsub_eid);
-
-	return 0;
-}
-
-static int asterisk_publication_mailboxstate(struct ast_sip_publication *pub, struct asterisk_publication_config *config,
-	struct ast_eid *pubsub_eid, struct ast_json *json)
-{
-	const char *uniqueid = ast_json_string_get(ast_json_object_get(json, "uniqueid"));
-	int old_msgs = ast_json_integer_get(ast_json_object_get(json, "old"));
-	int new_msgs = ast_json_integer_get(ast_json_object_get(json, "new"));
-	char *item_id;
-	const char *mailbox;
-
-	if (!config->mailbox_state) {
-		ast_debug(2, "Received mailbox state event for resource '%s' but it is not configured to accept them\n",
-			ast_sorcery_object_get_id(config));
-		return 0;
-	}
-
-	if (ast_strlen_zero(uniqueid)) {
-		ast_debug(1, "Received incomplete mailbox state event for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	if (config->mailbox_state_filter && regexec(&config->mailbox_state_regex, uniqueid, 0, NULL, 0)) {
-		ast_debug(2, "Received mailbox state on resource '%s' for uniqueid '%s' but it has been filtered out\n",
-			ast_sorcery_object_get_id(config), uniqueid);
-		return 0;
-	}
-
-	item_id = ast_strdupa(uniqueid);
-	mailbox = strsep(&item_id, "@");
-
-	ast_publish_mwi_state_full(mailbox, item_id, new_msgs, old_msgs, NULL, pubsub_eid);
-
-	return 0;
-}
-
-static int asterisk_publication_devicestate_refresh(struct ast_sip_publication *pub,
-	struct asterisk_publication_config *config, struct ast_eid *pubsub_eid, struct ast_json *json)
-{
-	struct ast_sip_outbound_publish_client *client;
-	struct ast_datastore *datastore;
-	struct ao2_container *cached;
-
-	if (ast_strlen_zero(config->devicestate_publish)) {
-		return 0;
-	}
-
-	client = ast_sip_publish_client_get(config->devicestate_publish);
-	if (!client) {
-		ast_log(LOG_ERROR, "Received refresh request for devicestate on publication '%s' but publish '%s' is not available\n",
-			ast_sorcery_object_get_id(config), config->devicestate_publish);
-		return 0;
-	}
-
-	datastore = ast_sip_publish_client_get_datastore(client, "asterisk-devicestate-publisher");
-	if (!datastore) {
-		ao2_ref(client, -1);
-		return 0;
-	}
-
-	cached = stasis_cache_dump(ast_device_state_cache(), NULL);
-	if (cached) {
-		ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, datastore);
-		ao2_ref(cached, -1);
-	}
-	ao2_ref(client, -1);
-	ao2_ref(datastore, -1);
-
-	return 0;
-}
-
-static int asterisk_publication_devicestate_state_change(struct ast_sip_publication *pub, pjsip_msg_body *body,
-			enum ast_sip_publish_state state)
-{
-	RAII_VAR(struct asterisk_publication_config *, config, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "asterisk-publication",
-		ast_sip_publication_get_event_configuration(pub)), ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	const char *eid, *type;
-	struct ast_eid pubsub_eid;
-	int res = -1;
-
-	/* If no configuration exists for this publication it has most likely been removed, so drop this immediately */
-	if (!config) {
-		return -1;
-	}
-
-	/* If no body exists this is a refresh and can be ignored */
-	if (!body) {
-		return 0;
-	}
-
-	/* We only accept JSON for content */
-	if (pj_strcmp2(&body->content_type.type, "application") ||
-		pj_strcmp2(&body->content_type.subtype, "json")) {
-		ast_debug(2, "Received unsupported content type for Asterisk event on resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	json = ast_json_load_buf(body->data, body->len, NULL);
-	if (!json) {
-		ast_debug(1, "Received unparseable JSON event for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	eid = ast_json_string_get(ast_json_object_get(json, "eid"));
-	if (!eid) {
-		ast_debug(1, "Received event without eid for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-	ast_str_to_eid(&pubsub_eid, eid);
-
-	type = ast_json_string_get(ast_json_object_get(json, "type"));
-	if (!type) {
-		ast_debug(1, "Received event without type for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	} else if (!strcmp(type, "devicestate")) {
-		res = asterisk_publication_devicestate(pub, config, &pubsub_eid, json);
-	} else if (!strcmp(type, "refresh")) {
-		res = asterisk_publication_devicestate_refresh(pub, config, &pubsub_eid, json);
-	}
-
-	return res;
-}
-
-static int asterisk_publication_mwi_refresh(struct ast_sip_publication *pub,
-	struct asterisk_publication_config *config, struct ast_eid *pubsub_eid, struct ast_json *json)
-{
-	struct ast_sip_outbound_publish_client *client;
-	struct ast_datastore *datastore;
-	struct ao2_container *cached;
-
-	if (ast_strlen_zero(config->mailboxstate_publish)) {
-		return 0;
-	}
-
-	client = ast_sip_publish_client_get(config->mailboxstate_publish);
-	if (!client) {
-		ast_log(LOG_ERROR, "Received refresh request for mwi state on publication '%s' but publish '%s' is not available\n",
-			ast_sorcery_object_get_id(config), config->mailboxstate_publish);
-		return 0;
-	}
-
-	datastore = ast_sip_publish_client_get_datastore(client, "asterisk-mwi-publisher");
-	if (!datastore) {
-		ao2_ref(client, -1);
-		return 0;
-	}
-
-	cached = stasis_cache_dump(ast_mwi_state_cache(), NULL);
-	if (cached) {
-		ao2_callback(cached, OBJ_NODATA, cached_mwistate_cb, datastore);
-		ao2_ref(cached, -1);
-	}
-	ao2_ref(client, -1);
-	ao2_ref(datastore, -1);
-
-	return 0;
-}
-
-static int asterisk_publication_mwi_state_change(struct ast_sip_publication *pub, pjsip_msg_body *body,
-			enum ast_sip_publish_state state)
-{
-	RAII_VAR(struct asterisk_publication_config *, config, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "asterisk-publication",
-		ast_sip_publication_get_event_configuration(pub)), ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	const char *eid, *type;
-	struct ast_eid pubsub_eid;
-	int res = -1;
-
-	/* If no configuration exists for this publication it has most likely been removed, so drop this immediately */
-	if (!config) {
-		return -1;
-	}
-
-	/* If no body exists this is a refresh and can be ignored */
-	if (!body) {
-		return 0;
-	}
-
-	/* We only accept JSON for content */
-	if (pj_strcmp2(&body->content_type.type, "application") ||
-		pj_strcmp2(&body->content_type.subtype, "json")) {
-		ast_debug(2, "Received unsupported content type for Asterisk event on resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	json = ast_json_load_buf(body->data, body->len, NULL);
-	if (!json) {
-		ast_debug(1, "Received unparseable JSON event for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-
-	eid = ast_json_string_get(ast_json_object_get(json, "eid"));
-	if (!eid) {
-		ast_debug(1, "Received event without eid for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	}
-	ast_str_to_eid(&pubsub_eid, eid);
-
-	type = ast_json_string_get(ast_json_object_get(json, "type"));
-	if (!type) {
-		ast_debug(1, "Received event without type for resource '%s'\n",
-			ast_sorcery_object_get_id(config));
-		return -1;
-	} else if (!strcmp(type, "mailboxstate")) {
-		res = asterisk_publication_mailboxstate(pub, config, &pubsub_eid, json);
-	} else if (!strcmp(type, "refresh")) {
-		res = asterisk_publication_mwi_refresh(pub, config, &pubsub_eid, json);
-	}
-
-	return res;
-}
-
-static int send_refresh_cb(void *obj, void *arg, int flags)
-{
-	struct asterisk_publication_config *config = obj;
-	struct ast_sip_outbound_publish_client *client;
-
-	if (!ast_strlen_zero(config->devicestate_publish)) {
-		client = ast_sip_publish_client_get(config->devicestate_publish);
-		if (client) {
-			ast_sip_publish_client_send(client, arg);
-			ao2_ref(client, -1);
-		}
-	}
-
-	if (!ast_strlen_zero(config->mailboxstate_publish)) {
-		client = ast_sip_publish_client_get(config->mailboxstate_publish);
-		if (client) {
-			ast_sip_publish_client_send(client, arg);
-			ao2_ref(client, -1);
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Internal function to send refresh requests to all publications */
-static void asterisk_publication_send_refresh(void)
-{
-	struct ao2_container *publications = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "asterisk-publication", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	char eid_str[20];
-	struct ast_json *json;
-	char *text;
-	struct ast_sip_body body = {
-		.type = "application",
-		.subtype = "json",
-	};
-
-	if (!publications) {
-		return;
-	}
-
-	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
-	json = ast_json_pack(
-		"{ s: s, s: s }",
-		"type", "refresh",
-		"eid", eid_str);
-	if (!json) {
-		ao2_ref(publications, -1);
-		return;
-	}
-
-	text = ast_json_dump_string(json);
-	if (!text) {
-		ast_json_unref(json);
-		ao2_ref(publications, -1);
-		return;
-	}
-	body.body_text = text;
-
-	ao2_callback(publications, OBJ_NODATA, send_refresh_cb, &body);
-
-	ast_json_free(text);
-	ast_json_unref(json);
-	ao2_ref(publications, -1);
-}
-
-struct ast_sip_publish_handler asterisk_devicestate_publication_handler = {
-	.event_name = "asterisk-devicestate",
-	.new_publication = asterisk_publication_new,
-	.publication_state_change = asterisk_publication_devicestate_state_change,
-};
-
-struct ast_sip_publish_handler asterisk_mwi_publication_handler = {
-	.event_name = "asterisk-mwi",
-	.new_publication = asterisk_publication_new,
-	.publication_state_change = asterisk_publication_mwi_state_change,
-};
-
-/*! \brief Destructor function for Asterisk publication configuration */
-static void asterisk_publication_config_destroy(void *obj)
-{
-	struct asterisk_publication_config *config = obj;
-
-	ast_string_field_free_memory(config);
-}
-
-/*! \brief Allocator function for Asterisk publication configuration */
-static void *asterisk_publication_config_alloc(const char *name)
-{
-	struct asterisk_publication_config *config = ast_sorcery_generic_alloc(sizeof(*config),
-		asterisk_publication_config_destroy);
-
-	if (!config || ast_string_field_init(config, 256)) {
-		ao2_cleanup(config);
-		return NULL;
-	}
-
-	return config;
-}
-
-static int regex_filter_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct asterisk_publication_config *config = obj;
-	int res = -1;
-
-	if (ast_strlen_zero(var->value)) {
-		return 0;
-	}
-
-	if (!strcmp(var->name, "device_state_filter")) {
-		if (!(res = build_regex(&config->device_state_regex, var->value))) {
-			config->device_state_filter = 1;
-		}
-	} else if (!strcmp(var->name, "mailbox_state_filter")) {
-		if (!(res = build_regex(&config->mailbox_state_regex, var->value))) {
-			config->mailbox_state_filter = 1;
-		}
-	}
-
-	return res;
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	ast_sorcery_apply_default(ast_sip_get_sorcery(), "asterisk-publication", "config", "pjsip.conf,criteria=type=asterisk-publication");
-
-	if (ast_sorcery_object_register(ast_sip_get_sorcery(), "asterisk-publication", asterisk_publication_config_alloc, NULL, NULL)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "asterisk-publication", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "asterisk-publication", "devicestate_publish", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct asterisk_publication_config, devicestate_publish));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "asterisk-publication", "mailboxstate_publish", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct asterisk_publication_config, mailboxstate_publish));
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "asterisk-publication", "device_state", "no", OPT_BOOL_T, 1, FLDSET(struct asterisk_publication_config, device_state));
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "asterisk-publication", "device_state_filter", "", regex_filter_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "asterisk-publication", "mailbox_state", "no", OPT_BOOL_T, 1, FLDSET(struct asterisk_publication_config, mailbox_state));
-	ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "asterisk-publication", "mailbox_state_filter", "", regex_filter_handler, NULL, NULL, 0, 0);
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "asterisk-publication");
-
-	if (ast_sip_register_publish_handler(&asterisk_devicestate_publication_handler)) {
-		ast_log(LOG_WARNING, "Unable to register event publication handler %s\n",
-			asterisk_devicestate_publication_handler.event_name);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (ast_sip_register_publish_handler(&asterisk_mwi_publication_handler)) {
-		ast_log(LOG_WARNING, "Unable to register event publication handler %s\n",
-			asterisk_mwi_publication_handler.event_name);
-		ast_sip_unregister_publish_handler(&asterisk_devicestate_publication_handler);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (ast_sip_register_event_publisher_handler(&asterisk_devicestate_publisher_handler)) {
-		ast_log(LOG_WARNING, "Unable to register event publisher handler %s\n",
-			asterisk_devicestate_publisher_handler.event_name);
-		ast_sip_unregister_publish_handler(&asterisk_devicestate_publication_handler);
-		ast_sip_unregister_publish_handler(&asterisk_mwi_publication_handler);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (ast_sip_register_event_publisher_handler(&asterisk_mwi_publisher_handler)) {
-		ast_log(LOG_WARNING, "Unable to register event publisher handler %s\n",
-			asterisk_mwi_publisher_handler.event_name);
-		ast_sip_unregister_event_publisher_handler(&asterisk_mwi_publisher_handler);
-		ast_sip_unregister_publish_handler(&asterisk_devicestate_publication_handler);
-		ast_sip_unregister_publish_handler(&asterisk_mwi_publication_handler);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	asterisk_publication_send_refresh();
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int reload_module(void)
-{
-	ast_sorcery_reload_object(ast_sip_get_sorcery(), "asterisk-publication");
-	asterisk_publication_send_refresh();
-	return 0;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_publish_handler(&asterisk_devicestate_publication_handler);
-	ast_sip_unregister_publish_handler(&asterisk_mwi_publication_handler);
-	ast_sip_unregister_event_publisher_handler(&asterisk_devicestate_publisher_handler);
-	ast_sip_unregister_event_publisher_handler(&asterisk_mwi_publisher_handler);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Asterisk Event PUBLISH Support",
-		.load = load_module,
-		.reload = reload_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
deleted file mode 100644
index 02deeb6..0000000
--- a/res/res_pjsip_pubsub.c
+++ /dev/null
@@ -1,4307 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-/*!
- * \brief Opaque structure representing an RFC 3265 SIP subscription
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/module.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/datastore.h"
-#include "asterisk/uuid.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/sched.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/callerid.h"
-#include "asterisk/manager.h"
-#include "asterisk/test.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-
-/*** DOCUMENTATION
-	<manager name="PJSIPShowSubscriptionsInbound" language="en_US">
-		<synopsis>
-			Lists subscriptions.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			Provides a listing of all inbound subscriptions.  An event <literal>InboundSubscriptionDetail</literal>
-			is issued for each subscription object.  Once all detail events are completed an
-			<literal>InboundSubscriptionDetailComplete</literal> event is issued.
-                        </para>
-		</description>
-	</manager>
-	<manager name="PJSIPShowSubscriptionsOutbound" language="en_US">
-		<synopsis>
-			Lists subscriptions.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			Provides a listing of all outbound subscriptions.  An event <literal>OutboundSubscriptionDetail</literal>
-			is issued for each subscription object.  Once all detail events are completed an
-			<literal>OutboundSubscriptionDetailComplete</literal> event is issued.
-                        </para>
-		</description>
-	</manager>
-	<manager name="PJSIPShowResourceLists" language="en_US">
-		<synopsis>
-			Displays settings for configured resource lists.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			Provides a listing of all resource lists.  An event <literal>ResourceListDetail</literal>
-			is issued for each resource list object.  Once all detail events are completed a
-			<literal>ResourceListDetailComplete</literal> event is issued.
-                        </para>
-		</description>
-	</manager>
-
-	<configInfo name="res_pjsip_pubsub" language="en_US">
-		<synopsis>Module that implements publish and subscribe support.</synopsis>
-		<configFile name="pjsip.conf">
-			<configObject name="subscription_persistence">
-				<synopsis>Persists SIP subscriptions so they survive restarts.</synopsis>
-				<configOption name="packet">
-					<synopsis>Entire SIP SUBSCRIBE packet that created the subscription</synopsis>
-				</configOption>
-				<configOption name="src_name">
-					<synopsis>The source address of the subscription</synopsis>
-				</configOption>
-				<configOption name="src_port">
-					<synopsis>The source port of the subscription</synopsis>
-				</configOption>
-				<configOption name="transport_key">
-					<synopsis>The type of transport the subscription was received on</synopsis>
-				</configOption>
-				<configOption name="local_name">
-					<synopsis>The local address the subscription was received on</synopsis>
-				</configOption>
-				<configOption name="local_port">
-					<synopsis>The local port the subscription was received on</synopsis>
-				</configOption>
-				<configOption name="cseq">
-					<synopsis>The sequence number of the next NOTIFY to be sent</synopsis>
-				</configOption>
-				<configOption name="tag">
-					<synopsis>The local tag of the dialog for the subscription</synopsis>
-				</configOption>
-				<configOption name="endpoint">
-					<synopsis>The name of the endpoint that subscribed</synopsis>
-				</configOption>
-				<configOption name="expires">
-					<synopsis>The time at which the subscription expires</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="resource_list">
-				<synopsis>Resource list configuration parameters.</synopsis>
-				<description>
-					<para>This configuration object allows for RFC 4662 resource list subscriptions
-					to be specified. This can be useful to decrease the amount of subscription traffic
-					that a server has to process.</para>
-					<note>
-						<para>Current limitations limit the size of SIP NOTIFY requests that Asterisk sends
-						to 64000 bytes. If your resource list notifications are larger than this maximum, you
-						will need to make adjustments.</para>
-					</note>
-				</description>
-				<configOption name="type">
-					<synopsis>Must be of type 'resource_list'</synopsis>
-				</configOption>
-				<configOption name="event">
-					<synopsis>The SIP event package that the list resource belong to.</synopsis>
-					<description><para>
-						The SIP event package describes the types of resources that Asterisk reports
-						the state of.
-					</para>
-						<enumlist>
-							<enum name="presence"><para>
-								Device state and presence reporting.
-							</para></enum>
-							<enum name="message-summary"><para>
-								Message-waiting indication (MWI) reporting.
-							</para></enum>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="list_item">
-					<synopsis>The name of a resource to report state on</synopsis>
-					<description>
-						<para>In general Asterisk looks up list items in the following way:</para>
-						<para>1. Check if the list item refers to another configured resource list.</para>
-						<para>2. Pass the name of the resource off to event-package-specific handlers
-						   to find the specified resource.</para>
-						<para>The second part means that the way the list item is specified depends
-						on what type of list this is. For instance, if you have the <replaceable>event</replaceable>
-						set to <literal>presence</literal>, then list items should be in the form of
-						dialplan_extension at dialplan_context. For <literal>message-summary</literal> mailbox
-						names should be listed.</para>
-					</description>
-				</configOption>
-				<configOption name="full_state" default="no">
-					<synopsis>Indicates if the entire list's state should be sent out.</synopsis>
-					<description>
-						<para>If this option is enabled, and a resource changes state, then Asterisk will construct
-						a notification that contains the state of all resources in the list. If the option is
-						disabled, Asterisk will construct a notification that only contains the states of
-						resources that have changed.</para>
-						<note>
-							<para>Even with this option disabled, there are certain situations where Asterisk is forced
-							to send a notification with the states of all resources in the list. When a subscriber
-							renews or terminates its subscription to the list, Asterisk MUST send a full state
-							notification.</para>
-						</note>
-					</description>
-				</configOption>
-				<configOption name="notification_batch_interval" default="0">
-					<synopsis>Time Asterisk should wait, in milliseconds, before sending notifications.</synopsis>
-					<description>
-						<para>When a resource's state changes, it may be desired to wait a certain amount before Asterisk
-						sends a notification to subscribers. This allows for other state changes to accumulate, so that
-						Asterisk can communicate multiple state changes in a single notification instead of rapidly sending
-						many notifications.</para>
-					</description>
-				</configOption>
-			</configObject>
-			<configObject name="inbound-publication">
-				<synopsis>The configuration for inbound publications</synopsis>
-				<configOption name="endpoint" default="">
-					<synopsis>Optional name of an endpoint that is only allowed to publish to this resource</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Must be of type 'inbound-publication'.</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
- ***/
-
-static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata);
-
-static struct pjsip_module pubsub_module = {
-	.name = { "PubSub Module", 13 },
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.on_rx_request = pubsub_on_rx_request,
-};
-
-#define MOD_DATA_PERSISTENCE "sub_persistence"
-#define MOD_DATA_MSG "sub_msg"
-
-static const pj_str_t str_event_name = { "Event", 5 };
-
-/*! \brief Scheduler used for automatically expiring publications */
-static struct ast_sched_context *sched;
-
-/*! \brief Number of buckets for publications (on a per handler) */
-#define PUBLICATIONS_BUCKETS 37
-
-/*! \brief Default expiration time for PUBLISH if one is not specified */
-#define DEFAULT_PUBLISH_EXPIRES 3600
-
-/*! \brief Number of buckets for subscription datastore */
-#define DATASTORE_BUCKETS 53
-
-/*! \brief Default expiration for subscriptions */
-#define DEFAULT_EXPIRES 3600
-
-/*! \brief Defined method for PUBLISH */
-const pjsip_method pjsip_publish_method =
-{
-	PJSIP_OTHER_METHOD,
-	{ "PUBLISH", 7 }
-};
-
-/*!
- * \brief The types of PUBLISH messages defined in RFC 3903
- */
-enum sip_publish_type {
-	/*!
-	 * \brief Unknown
-	 *
-	 * \details
-	 * This actually is not defined in RFC 3903. We use this as a constant
-	 * to indicate that an incoming PUBLISH does not fit into any of the
-	 * other categories and is thus invalid.
-	 */
-	SIP_PUBLISH_UNKNOWN,
-
-	/*!
-	 * \brief Initial
-	 *
-	 * \details
-	 * The first PUBLISH sent. This will contain a non-zero Expires header
-	 * as well as a body that indicates the current state of the endpoint
-	 * that has sent the message. The initial PUBLISH is the only type
-	 * of PUBLISH to not contain a Sip-If-Match header in it.
-	 */
-	SIP_PUBLISH_INITIAL,
-
-	/*!
-	 * \brief Refresh
-	 *
-	 * \details
-	 * Used to keep a published state from expiring. This will contain a
-	 * non-zero Expires header but no body since its purpose is not to
-	 * update state.
-	 */
-	SIP_PUBLISH_REFRESH,
-
-	/*!
-	 * \brief Modify
-	 *
-	 * \details
-	 * Used to change state from its previous value. This will contain
-	 * a body updating the published state. May or may not contain an
-	 * Expires header.
-	 */
-	SIP_PUBLISH_MODIFY,
-
-	/*!
-	 * \brief Remove
-	 *
-	 * \details
-	 * Used to remove published state from an ESC. This will contain
-	 * an Expires header set to 0 and likely no body.
-	 */
-	SIP_PUBLISH_REMOVE,
-};
-
-/*!
- * \brief A vector of strings commonly used throughout this module
- */
-AST_VECTOR(resources, const char *);
-
-/*!
- * \brief Resource list configuration item
- */
-struct resource_list {
-	SORCERY_OBJECT(details);
-	/*! SIP event package the list uses. */
-	char event[32];
-	/*! Strings representing resources in the list. */
-	struct resources items;
-	/*! Indicates if Asterisk sends full or partial state on notifications. */
-	unsigned int full_state;
-	/*! Time, in milliseconds Asterisk waits before sending a batched notification.*/
-	unsigned int notification_batch_interval;
-};
-
-/*!
- * Used to create new entity IDs by ESCs.
- */
-static int esc_etag_counter;
-
-/*!
- * \brief Structure representing a SIP publication
- */
-struct ast_sip_publication {
-	/*! Publication datastores set up by handlers */
-	struct ao2_container *datastores;
-	/*! \brief Entity tag for the publication */
-	int entity_tag;
-	/*! \brief Handler for this publication */
-	struct ast_sip_publish_handler *handler;
-	/*! \brief The endpoint with which the subscription is communicating */
-	struct ast_sip_endpoint *endpoint;
-	/*! \brief Expiration time of the publication */
-	int expires;
-	/*! \brief Scheduled item for expiration of publication */
-	int sched_id;
-	/*! \brief The resource the publication is to */
-	char *resource;
-	/*! \brief The name of the event type configuration */
-	char *event_configuration_name;
-	/*! \brief Data containing the above */
-	char data[0];
-};
-
-
-/*!
- * \brief Structure used for persisting an inbound subscription
- */
-struct subscription_persistence {
-	/*! Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! The name of the endpoint involved in the subscrption */
-	char *endpoint;
-	/*! SIP message that creates the subscription */
-	char packet[PJSIP_MAX_PKT_LEN];
-	/*! Source address of the message */
-	char src_name[PJ_INET6_ADDRSTRLEN];
-	/*! Source port of the message */
-	int src_port;
-	/*! Local transport key type */
-	char transport_key[32];
-	/*! Local transport address */
-	char local_name[PJ_INET6_ADDRSTRLEN];
-	/*! Local transport port */
-	int local_port;
-	/*! Next CSeq to use for message */
-	unsigned int cseq;
-	/*! Local tag of the dialog */
-	char *tag;
-	/*! When this subscription expires */
-	struct timeval expires;
-};
-
-/*!
- * \brief A tree of SIP subscriptions
- *
- * Because of the ability to subscribe to resource lists, a SIP
- * subscription can result in a tree of subscriptions being created.
- * This structure represents the information relevant to the subscription
- * as a whole, to include the underlying PJSIP structure for the
- * subscription.
- */
-struct sip_subscription_tree {
-	/*! The endpoint with which the subscription is communicating */
-	struct ast_sip_endpoint *endpoint;
-	/*! Serializer on which to place operations for this subscription */
-	struct ast_taskprocessor *serializer;
-	/*! The role for this subscription */
-	enum ast_sip_subscription_role role;
-	/*! Persistence information */
-	struct subscription_persistence *persistence;
-	/*! The underlying PJSIP event subscription structure */
-	pjsip_evsub *evsub;
-	/*! The underlying PJSIP dialog */
-	pjsip_dialog *dlg;
-	/*! Interval to use for batching notifications */
-	unsigned int notification_batch_interval;
-	/*! Scheduler ID for batched notification */
-	int notify_sched_id;
-	/*! Indicator if scheduled batched notification should be sent */
-	unsigned int send_scheduled_notify;
-	/*! The root of the subscription tree */
-	struct ast_sip_subscription *root;
-	/*! Is this subscription to a list? */
-	int is_list;
-	/*! Next item in the list */
-	AST_LIST_ENTRY(sip_subscription_tree) next;
-};
-
-/*!
- * \brief Structure representing a "virtual" SIP subscription.
- *
- * This structure serves a dual purpose. Structurally, it is
- * the constructed tree of subscriptions based on the resources
- * being subscribed to. API-wise, this serves as the handle that
- * subscription handlers use in order to interact with the pubsub API.
- */
-struct ast_sip_subscription {
-	/*! Subscription datastores set up by handlers */
-	struct ao2_container *datastores;
-	/*! The handler for this subscription */
-	const struct ast_sip_subscription_handler *handler;
-	/*! Pointer to the base of the tree */
-	struct sip_subscription_tree *tree;
-	/*! Body generaator for NOTIFYs */
-	struct ast_sip_pubsub_body_generator *body_generator;
-	/*! Vector of child subscriptions */
-	AST_VECTOR(, struct ast_sip_subscription *) children;
-	/*! Saved NOTIFY body text for this subscription */
-	struct ast_str *body_text;
-	/*! Indicator that the body text has changed since the last notification */
-	int body_changed;
-	/*! The current state of the subscription */
-	pjsip_evsub_state subscription_state;
-	/*! For lists, the current version to place in the RLMI body */
-	unsigned int version;
-	/*! For lists, indicates if full state should always be communicated. */
-	unsigned int full_state;
-	/*! URI associated with the subscription */
-	pjsip_sip_uri *uri;
-	/*! Name of resource being subscribed to */
-	char resource[0];
-};
-
-/*!
- * \brief Structure representing a publication resource
- */
-struct ast_sip_publication_resource {
-	/*! \brief Sorcery object details */
-	SORCERY_OBJECT(details);
-	/*! \brief Optional name of an endpoint that is only allowed to publish to this resource */
-	char *endpoint;
-	/*! \brief Mapping for event types to configuration */
-	struct ast_variable *events;
-};
-
-static const char *sip_subscription_roles_map[] = {
-	[AST_SIP_SUBSCRIBER] = "Subscriber",
-	[AST_SIP_NOTIFIER] = "Notifier"
-};
-
-AST_RWLIST_HEAD_STATIC(subscriptions, sip_subscription_tree);
-
-AST_RWLIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator);
-AST_RWLIST_HEAD_STATIC(body_supplements, ast_sip_pubsub_body_supplement);
-
-static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
-static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
-		int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
-static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
-		pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
-static void pubsub_on_client_refresh(pjsip_evsub *sub);
-static void pubsub_on_server_timeout(pjsip_evsub *sub);
- 
-static pjsip_evsub_user pubsub_cb = {
-	.on_evsub_state = pubsub_on_evsub_state,
-	.on_rx_refresh = pubsub_on_rx_refresh,
-	.on_rx_notify = pubsub_on_rx_notify,
-	.on_client_refresh = pubsub_on_client_refresh,
-	.on_server_timeout = pubsub_on_server_timeout,
-};
-
-/*! \brief Destructor for publication resource */
-static void publication_resource_destroy(void *obj)
-{
-	struct ast_sip_publication_resource *resource = obj;
-
-	ast_free(resource->endpoint);
-	ast_variables_destroy(resource->events);
-}
-
-/*! \brief Allocator for publication resource */
-static void *publication_resource_alloc(const char *name)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct ast_sip_publication_resource), publication_resource_destroy);
-}
-
-/*! \brief Destructor for subscription persistence */
-static void subscription_persistence_destroy(void *obj)
-{
-	struct subscription_persistence *persistence = obj;
-
-	ast_free(persistence->endpoint);
-	ast_free(persistence->tag);
-}
-
-/*! \brief Allocator for subscription persistence */
-static void *subscription_persistence_alloc(const char *name)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct subscription_persistence), subscription_persistence_destroy);
-}
-
-/*! \brief Function which creates initial persistence information of a subscription in sorcery */
-static struct subscription_persistence *subscription_persistence_create(struct sip_subscription_tree *sub_tree)
-{
-	char tag[PJ_GUID_STRING_LENGTH + 1];
-
-	/* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
-	 * look it up by id at all.
-	 */
-	struct subscription_persistence *persistence = ast_sorcery_alloc(ast_sip_get_sorcery(),
-		"subscription_persistence", NULL);
-
-	pjsip_dialog *dlg = sub_tree->dlg;
-
-	if (!persistence) {
-		return NULL;
-	}
-
-	persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
-	ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
-	persistence->tag = ast_strdup(tag);
-
-	ast_sorcery_create(ast_sip_get_sorcery(), persistence);
-	return persistence;
-}
-
-/*! \brief Function which updates persistence information of a subscription in sorcery */
-static void subscription_persistence_update(struct sip_subscription_tree *sub_tree,
-	pjsip_rx_data *rdata)
-{
-	pjsip_dialog *dlg;
-
-	if (!sub_tree->persistence) {
-		return;
-	}
-
-	dlg = sub_tree->dlg;
-	sub_tree->persistence->cseq = dlg->local.cseq;
-
-	if (rdata) {
-		int expires;
-		pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
-
-		expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
-		sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
-
-		ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
-				sizeof(sub_tree->persistence->packet));
-		ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
-				sizeof(sub_tree->persistence->src_name));
-		sub_tree->persistence->src_port = rdata->pkt_info.src_port;
-		ast_copy_string(sub_tree->persistence->transport_key, rdata->tp_info.transport->type_name,
-			sizeof(sub_tree->persistence->transport_key));
-		ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
-			sizeof(sub_tree->persistence->local_name));
-		sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
-	}
-
-	ast_sorcery_update(ast_sip_get_sorcery(), sub_tree->persistence);
-}
-
-/*! \brief Function which removes persistence of a subscription from sorcery */
-static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
-{
-	if (!sub_tree->persistence) {
-		return;
-	}
-
-	ast_sorcery_delete(ast_sip_get_sorcery(), sub_tree->persistence);
-	ao2_ref(sub_tree->persistence, -1);
-}
-
-
-static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name);
-static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
-		size_t num_accept, const char *body_type);
-
-/*! \brief Retrieve a handler using the Event header of an rdata message */
-static struct ast_sip_subscription_handler *subscription_get_handler_from_rdata(pjsip_rx_data *rdata)
-{
-	pjsip_event_hdr *event_header;
-	char event[32];
-	struct ast_sip_subscription_handler *handler;
-
-	event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
-	if (!event_header) {
-		ast_log(LOG_WARNING, "Incoming SUBSCRIBE request with no Event header\n");
-		return NULL;
-	}
-	ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
-
-	handler = find_sub_handler_for_event_name(event);
-	if (!handler) {
-		ast_log(LOG_WARNING, "No registered subscribe handler for event %s\n", event);
-	}
-
-	return handler;
-}
-
-/*!
- * \brief Accept headers that are exceptions to the rule
- *
- * Typically, when a SUBSCRIBE arrives, we attempt to find a
- * body generator that matches one of the Accept headers in
- * the request. When subscribing to a single resource, this works
- * great. However, when subscribing to a list, things work
- * differently. Most Accept header values are fine, but there
- * are a couple that are endemic to resource lists that need
- * to be ignored when searching for a body generator to use
- * for the individual resources of the subscription.
- */
-const char *accept_exceptions[] =  {
-	"multipart/related",
-	"application/rlmi+xml",
-};
-
-/*!
- * \brief Is the Accept header from the SUBSCRIBE in the list of exceptions?
- *
- * \retval 1 This Accept header value is an exception to the rule.
- * \retval 0 This Accept header is not an exception to the rule.
- */
-static int exceptional_accept(const pj_str_t *accept)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
-		if (!pj_strcmp2(accept, accept_exceptions[i])) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Retrieve a body generator using the Accept header of an rdata message */
-static struct ast_sip_pubsub_body_generator *subscription_get_generator_from_rdata(pjsip_rx_data *rdata,
-	const struct ast_sip_subscription_handler *handler)
-{
-	pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
-	char accept[AST_SIP_MAX_ACCEPT][64];
-	size_t num_accept_headers = 0;
-
-	while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next))) {
-		int i;
-
-		for (i = 0; i < accept_header->count; ++i) {
-			if (!exceptional_accept(&accept_header->values[i])) {
-				ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
-				++num_accept_headers;
-			}
-		}
-	}
-
-	if (num_accept_headers == 0) {
-		/* If a SUBSCRIBE contains no Accept headers, then we must assume that
-		 * the default accept type for the event package is to be used.
-		 */
-		ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
-		num_accept_headers = 1;
-	}
-
-	return find_body_generator(accept, num_accept_headers, handler->body_type);
-}
-
-/*! \brief Check if the rdata has a Supported header containing 'eventlist'
- *
- *  \retval 1 rdata has an eventlist containing supported header
- *  \retval 0 rdata doesn't have an eventlist containing supported header
- */
-static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
-{
-	pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
-
-	while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
-		int i;
-
-		for (i = 0; i < supported_header->count; i++) {
-			if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
-				return 1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-struct resource_tree;
-
-/*!
- * \brief A node for a resource tree.
- */
-struct tree_node {
-	AST_VECTOR(, struct tree_node *) children;
-	unsigned int full_state;
-	char resource[0];
-};
-
-/*!
- * \brief Helper function for retrieving a resource list for a given event.
- *
- * This will retrieve a resource list that corresponds to the resource and event provided.
- *
- * \param resource The name of the resource list to retrieve
- * \param event The expected event name on the resource list
- */
-static struct resource_list *retrieve_resource_list(const char *resource, const char *event)
-{
-	struct resource_list *list;
-
-	list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
-	if (!list) {
-		return NULL;
-	}
-
-	if (strcmp(list->event, event)) {
-		ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
-				resource, list->event, event);
-		ao2_cleanup(list);
-		return NULL;
-	}
-
-	return list;
-}
-
-/*!
- * \brief Allocate a tree node
- *
- * In addition to allocating and initializing the tree node, the node is also added
- * to the vector of visited resources. See \ref build_resource_tree for more information
- * on the visited resources.
- *
- * \param resource The name of the resource for this tree node.
- * \param visited The vector of resources that have been visited.
- * \param if allocating a list, indicate whether full state is requested in notifications.
- * \retval NULL Allocation failure.
- * \retval non-NULL The newly-allocated tree_node
- */
-static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state)
-{
-	struct tree_node *node;
-
-	node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
-	if (!node) {
-		return NULL;
-	}
-
-	strcpy(node->resource, resource);
-	if (AST_VECTOR_INIT(&node->children, 4)) {
-		ast_free(node);
-		return NULL;
-	}
-	node->full_state = full_state;
-
-	if (visited) {
-		AST_VECTOR_APPEND(visited, resource);
-	}
-	return node;
-}
-
-/*!
- * \brief Destructor for a tree node
- *
- * This function calls recursively in order to destroy
- * all nodes lower in the tree from the given node in
- * addition to the node itself.
- *
- * \param node The node to destroy.
- */
-static void tree_node_destroy(struct tree_node *node)
-{
-	int i;
-	if (!node) {
-		return;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
-		tree_node_destroy(AST_VECTOR_GET(&node->children, i));
-	}
-	AST_VECTOR_FREE(&node->children);
-	ast_free(node);
-}
-
-/*!
- * \brief Determine if this resource has been visited already
- *
- * See \ref build_resource_tree for more information
- *
- * \param resource The resource currently being visited
- * \param visited The resources that have previously been visited
- */
-static int have_visited(const char *resource, struct resources *visited)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
-		if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Build child nodes for a given parent.
- *
- * This iterates through the items on a resource list and creates tree nodes for each one. The
- * tree nodes created are children of the supplied parent node. If an item in the resource
- * list is itself a list, then this function is called recursively to provide children for
- * the the new node.
- *
- * If an item in a resource list is not a list, then the supplied subscription handler is
- * called into as if a new SUBSCRIBE for the list item were presented. The handler's response
- * is used to determine if the node can be added to the tree or not.
- *
- * If a parent node ends up having no child nodes added under it, then the parent node is
- * pruned from the tree.
- *
- * \param endpoint The endpoint that sent the inbound SUBSCRIBE.
- * \param handler The subscription handler for leaf nodes in the tree.
- * \param list The configured resource list from which the child node is being built.
- * \param parent The parent node for these children.
- * \param visited The resources that have already been visited.
- */
-static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
-		struct resource_list *list, struct tree_node *parent, struct resources *visited)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
-		struct tree_node *current;
-		struct resource_list *child_list;
-		const char *resource = AST_VECTOR_GET(&list->items, i);
-
-		if (have_visited(resource, visited)) {
-			ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
-			continue;
-		}
-
-		child_list = retrieve_resource_list(resource, list->event);
-		if (!child_list) {
-			int resp = handler->notifier->new_subscribe(endpoint, resource);
-			if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
-				current = tree_node_alloc(resource, visited, 0);
-				if (!current) {
-					ast_debug(1, "Subscription to leaf resource %s was successful, but encountered"
-							"allocation error afterwards\n", resource);
-					continue;
-				}
-				ast_debug(1, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
-						resource, parent->resource);
-				AST_VECTOR_APPEND(&parent->children, current);
-			} else {
-				ast_debug(1, "Subscription to leaf resource %s resulted in error response %d\n",
-						resource, resp);
-			}
-		} else {
-			ast_debug(1, "Resource %s (child of %s) is a list\n", resource, parent->resource);
-			current = tree_node_alloc(resource, visited, child_list->full_state);
-			if (!current) {
-				ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
-				continue;
-			}
-			build_node_children(endpoint, handler, child_list, current, visited);
-			if (AST_VECTOR_SIZE(&current->children) > 0) {
-				ast_debug(1, "List %s had no successful children.\n", resource);
-				AST_VECTOR_APPEND(&parent->children, current);
-			} else {
-				ast_debug(1, "List %s had successful children. Adding to parent %s\n",
-						resource, parent->resource);
-				tree_node_destroy(current);
-			}
-			ao2_cleanup(child_list);
-		}
-	}
-}
-
-/*!
- * \brief A resource tree
- *
- * When an inbound SUBSCRIBE arrives, the resource being subscribed to may
- * be a resource list. If this is the case, the resource list may contain resources
- * that are themselves lists. The structure needed to hold the resources is
- * a tree.
- *
- * Upon receipt of the SUBSCRIBE, the tree is built by determining if subscriptions
- * to the individual resources in the tree would be successful or not. Any successful
- * subscriptions result in a node in the tree being created. Any unsuccessful subscriptions
- * result in no node being created.
- *
- * This tree can be seen as a bare-bones analog of the tree of ast_sip_subscriptions that
- * will end up being created to actually carry out the duties of a SIP SUBSCRIBE dialog.
- */
-struct resource_tree {
-	struct tree_node *root;
-	unsigned int notification_batch_interval;
-};
-
-/*!
- * \brief Destroy a resource tree.
- *
- * This function makes no assumptions about how the tree itself was
- * allocated and does not attempt to free the tree itself. Callers
- * of this function are responsible for freeing the tree.
- *
- * \param tree The tree to destroy.
- */
-static void resource_tree_destroy(struct resource_tree *tree)
-{
-	if (tree) {
-		tree_node_destroy(tree->root);
-	}
-}
-
-/*!
- * \brief Build a resource tree
- *
- * This function builds a resource tree based on the requested resource in a SUBSCRIBE request.
- *
- * This function also creates a container that has all resources that have been visited during
- * creation of the tree, whether those resources resulted in a tree node being created or not.
- * Keeping this container of visited resources allows for misconfigurations such as loops in
- * the tree or duplicated resources to be detected.
- *
- * \param endpoint The endpoint that sent the SUBSCRIBE request.
- * \param handler The subscription handler for leaf nodes in the tree.
- * \param resource The resource requested in the SUBSCRIBE request.
- * \param tree The tree that is to be built.
- * \param has_eventlist_support
- *
- * \retval 200-299 Successfully subscribed to at least one resource.
- * \retval 300-699 Failure to subscribe to requested resource.
- */
-static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
-		const char *resource, struct resource_tree *tree, int has_eventlist_support)
-{
-	struct resource_list *list;
-	struct resources visited;
-
-	if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
-		ast_debug(1, "Subscription to resource %s is not to a list\n", resource);
-		tree->root = tree_node_alloc(resource, NULL, 0);
-		if (!tree->root) {
-			return 500;
-		}
-		return handler->notifier->new_subscribe(endpoint, resource);
-	}
-
-	ast_debug(1, "Subscription to resource %s is a list\n", resource);
-	if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
-		return 500;
-	}
-
-	tree->root = tree_node_alloc(resource, &visited, list->full_state);
-	if (!tree->root) {
-		return 500;
-	}
-
-	tree->notification_batch_interval = list->notification_batch_interval;
-
-	build_node_children(endpoint, handler, list, tree->root, &visited);
-	AST_VECTOR_FREE(&visited);
-	ao2_cleanup(list);
-
-	if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
-		return 200;
-	} else {
-		return 500;
-	}
-}
-
-static int datastore_hash(const void *obj, int flags)
-{
-	const struct ast_datastore *datastore = obj;
-	const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
-
-	ast_assert(uid != NULL);
-
-	return ast_str_hash(uid);
-}
-
-static int datastore_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_datastore *datastore1 = obj;
-	const struct ast_datastore *datastore2 = arg;
-	const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
-
-	ast_assert(datastore1->uid != NULL);
-	ast_assert(uid2 != NULL);
-
-	return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-static int subscription_remove_serializer(void *obj)
-{
-	struct sip_subscription_tree *sub_tree = obj;
-
-	/* This is why we keep the dialog on the subscription. When the subscription
-	 * is destroyed, there is no guarantee that the underlying dialog is ready
-	 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
-	 * either. The dialog could be destroyed before our subscription is. We fix
-	 * this problem by keeping a reference to the dialog until it is time to
-	 * destroy the subscription. We need to have the dialog available when the
-	 * subscription is destroyed so that we can guarantee that our attempt to
-	 * remove the serializer will be successful.
-	 */
-	ast_sip_dialog_set_serializer(sub_tree->dlg, NULL);
-	pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
-
-	return 0;
-}
-
-static void add_subscription(struct sip_subscription_tree *obj)
-{
-	SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_INSERT_TAIL(&subscriptions, obj, next);
-}
-
-static void remove_subscription(struct sip_subscription_tree *obj)
-{
-	struct sip_subscription_tree *i;
-	SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscriptions, i, next) {
-		if (i == obj) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			if (i->root) {
-				ast_debug(1, "Removing subscription to resource %s from list of subscriptions\n",
-						ast_sip_subscription_get_resource_name(i->root));
-			}
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-static void subscription_destructor(void *obj)
-{
-	struct ast_sip_subscription *sub = obj;
-
-	ast_debug(3, "Destroying SIP subscription to resource %s\n", sub->resource);
-	ast_free(sub->body_text);
-
-	ao2_cleanup(sub->datastores);
-}
-
-static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_subscription_handler *handler,
-		const char *resource, struct sip_subscription_tree *tree)
-{
-	struct ast_sip_subscription *sub;
-	pjsip_sip_uri *contact_uri;
-
-	sub = ao2_alloc(sizeof(*sub) + strlen(resource) + 1, subscription_destructor);
-	if (!sub) {
-		return NULL;
-	}
-	strcpy(sub->resource, resource); /* Safe */
-
-	sub->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
-	if (!sub->datastores) {
-		ao2_ref(sub, -1);
-		return NULL;
-	}
-
-	sub->body_text = ast_str_create(128);
-	if (!sub->body_text) {
-		ao2_ref(sub, -1);
-		return NULL;
-	}
-
-	sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
-	contact_uri = pjsip_uri_get_uri(tree->dlg->local.contact->uri);
-	pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
-	pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
-
-	sub->handler = handler;
-	sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
-	sub->tree = tree;
-
-	return sub;
-}
-
-/*!
- * \brief Create a tree of virtual subscriptions based on a resource tree node.
- *
- * \param handler The handler to supply to leaf subscriptions.
- * \param resource The requested resource for this subscription.
- * \param generator Body generator to use for leaf subscriptions.
- * \param tree The root of the subscription tree.
- * \param current The tree node that corresponds to the subscription being created.
- */
-static struct ast_sip_subscription *create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler,
-		const char *resource, struct ast_sip_pubsub_body_generator *generator,
-		struct sip_subscription_tree *tree, struct tree_node *current)
-{
-	int i;
-	struct ast_sip_subscription *sub;
-
-	sub = allocate_subscription(handler, resource, tree);
-	if (!sub) {
-		return NULL;
-	}
-
-	sub->full_state = current->full_state;
-	sub->body_generator = generator;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
-		struct ast_sip_subscription *child;
-		struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
-
-		child = create_virtual_subscriptions(handler, child_node->resource, generator,
-				tree, child_node);
-
-		if (!child) {
-			ast_debug(1, "Child subscription to resource %s could not be created\n",
-					child_node->resource);
-			continue;
-		}
-
-		if (AST_VECTOR_APPEND(&sub->children, child)) {
-			ast_debug(1, "Child subscription to resource %s could not be appended\n",
-					child_node->resource);
-		}
-	}
-
-	return sub;
-}
-
-static void shutdown_subscriptions(struct ast_sip_subscription *sub)
-{
-	int i;
-
-	if (!sub) {
-		return;
-	}
-
-	if (AST_VECTOR_SIZE(&sub->children) > 0) {
-		for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
-			shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
-			ao2_cleanup(AST_VECTOR_GET(&sub->children, i));
-		}
-		return;
-	}
-
-	if (sub->handler->subscription_shutdown) {
-		sub->handler->subscription_shutdown(sub);
-	}
-}
-
-static void subscription_tree_destructor(void *obj)
-{
-	struct sip_subscription_tree *sub_tree = obj;
-
-	remove_subscription(sub_tree);
-
-	subscription_persistence_remove(sub_tree);
-	ao2_cleanup(sub_tree->endpoint);
-
-	if (sub_tree->dlg) {
-		ast_sip_push_task_synchronous(NULL, subscription_remove_serializer, sub_tree);
-	}
-
-	shutdown_subscriptions(sub_tree->root);
-	ao2_cleanup(sub_tree->root);
-
-	ast_taskprocessor_unreference(sub_tree->serializer);
-	ast_module_unref(ast_module_info->self);
-}
-
-static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
-{
-	/* We keep a reference to the dialog until our subscription is destroyed. See
-	 * the subscription_destructor for more details
-	 */
-	pjsip_dlg_inc_session(dlg, &pubsub_module);
-	sub_tree->dlg = dlg;
-	ast_sip_dialog_set_serializer(dlg, sub_tree->serializer);
-	pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
-}
-
-static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint)
-{
-	struct sip_subscription_tree *sub_tree;
-
-	sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
-	if (!sub_tree) {
-		return NULL;
-	}
-
-	ast_module_ref(ast_module_info->self);
-
-	sub_tree->serializer = ast_sip_create_serializer();
-	if (!sub_tree->serializer) {
-		ao2_ref(sub_tree, -1);
-		return NULL;
-	}
-
-	sub_tree->endpoint = ao2_bump(endpoint);
-	sub_tree->notify_sched_id = -1;
-
-	add_subscription(sub_tree);
-	return sub_tree;
-}
-
-/*!
- * \brief Create a subscription tree based on a resource tree.
- *
- * Using the previously-determined valid resources in the provided resource tree,
- * a corresponding tree of ast_sip_subscriptions are created. The root of the
- * subscription tree is a real subscription, and the rest in the tree are
- * virtual subscriptions.
- *
- * \param handler The handler to use for leaf subscriptions
- * \param endpoint The endpoint that sent the SUBSCRIBE request
- * \param rdata The SUBSCRIBE content
- * \param resource The requested resource in the SUBSCRIBE request
- * \param generator The body generator to use in leaf subscriptions
- * \param tree The resource tree on which the subscription tree is based
- * \param dlg_status[out] The result of attempting to create a dialog.
- *
- * \retval NULL Could not create the subscription tree
- * \retval non-NULL The root of the created subscription tree
- */
-
-static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
-		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
-		struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
-		pj_status_t *dlg_status)
-{
-	struct sip_subscription_tree *sub_tree;
-	pjsip_dialog *dlg;
-	struct subscription_persistence *persistence;
-
-	sub_tree = allocate_subscription_tree(endpoint);
-	if (!sub_tree) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		return NULL;
-	}
-	sub_tree->role = AST_SIP_NOTIFIER;
-
-	dlg = ast_sip_create_dialog_uas(endpoint, rdata, dlg_status);
-	if (!dlg) {
-		if (*dlg_status != PJ_EEXISTS) {
-			ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
-		}
-		ao2_ref(sub_tree, -1);
-		return NULL;
-	}
-
-	persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
-			pubsub_module.id, MOD_DATA_PERSISTENCE);
-	if (persistence) {
-		/* Update the created dialog with the persisted information */
-		pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
-		pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
-		dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
-		pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
-		dlg->local.cseq = persistence->cseq;
-		dlg->remote.cseq = persistence->cseq;
-	}
-
-	pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
-	subscription_setup_dialog(sub_tree, dlg);
-
-	ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG,
-			pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
-
-	sub_tree->notification_batch_interval = tree->notification_batch_interval;
-
-	sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
-	if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
-		sub_tree->is_list = 1;
-	}
-
-	return sub_tree;
-}
-
-/*! \brief Callback function to perform the actual recreation of a subscription */
-static int subscription_persistence_recreate(void *obj, void *arg, int flags)
-{
-	struct subscription_persistence *persistence = obj;
-	pj_pool_t *pool = arg;
-	pjsip_rx_data rdata = { { 0, }, };
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	struct sip_subscription_tree *sub_tree;
-	struct ast_sip_pubsub_body_generator *generator;
-	int resp;
-	char *resource;
-	size_t resource_size;
-	pjsip_sip_uri *request_uri;
-	struct resource_tree tree;
-	pjsip_expires_hdr *expires_header;
-	struct ast_sip_subscription_handler *handler;
-
-	/* If this subscription has already expired remove it */
-	if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-		return 0;
-	}
-
-	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", persistence->endpoint);
-	if (!endpoint) {
-		ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the endpoint was not found\n",
-			persistence->endpoint);
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-		return 0;
-	}
-
-	pj_pool_reset(pool);
-	rdata.tp_info.pool = pool;
-
-	if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port,
-		persistence->transport_key, persistence->local_name, persistence->local_port)) {
-		ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the message could not be parsed\n",
-			persistence->endpoint);
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-		return 0;
-	}
-
-	request_uri = pjsip_uri_get_uri(rdata.msg_info.msg->line.req.uri);
-	resource_size = pj_strlen(&request_uri->user) + 1;
-	resource = alloca(resource_size);
-	ast_copy_pj_str(resource, &request_uri->user, resource_size);
-
-	/* Update the expiration header with the new expiration */
-	expires_header = pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, rdata.msg_info.msg->hdr.next);
-	if (!expires_header) {
-		expires_header = pjsip_expires_hdr_create(pool, 0);
-		if (!expires_header) {
-			ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-			return 0;
-		}
-		pjsip_msg_add_hdr(rdata.msg_info.msg, (pjsip_hdr*)expires_header);
-	}
-	expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
-
-	handler = subscription_get_handler_from_rdata(&rdata);
-	if (!handler || !handler->notifier) {
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-		return 0;
-	}
-
-	generator = subscription_get_generator_from_rdata(&rdata, handler);
-	if (!generator) {
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-		return 0;
-	}
-
-	ast_sip_mod_data_set(rdata.tp_info.pool, rdata.endpt_info.mod_data,
-			pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
-
-	memset(&tree, 0, sizeof(tree));
-	resp = build_resource_tree(endpoint, handler, resource, &tree,
-		ast_sip_pubsub_has_eventlist_support(&rdata));
-	if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
-		pj_status_t dlg_status;
-
-		sub_tree = create_subscription_tree(handler, endpoint, &rdata, resource, generator, &tree, &dlg_status);
-		if (!sub_tree) {
-			ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-			ast_log(LOG_WARNING, "Failed to re-create subscription for %s\n", persistence->endpoint);
-			return 0;
-		}
-		sub_tree->persistence = ao2_bump(persistence);
-		subscription_persistence_update(sub_tree, &rdata);
-	} else {
-		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
-	}
-	resource_tree_destroy(&tree);
-
-	return 0;
-}
-
-/*! \brief Function which loads and recreates persisted subscriptions upon startup when the system is fully booted */
-static int subscription_persistence_load(void *data)
-{
-	struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
-		"subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-	pj_pool_t *pool;
-
-	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
-		PJSIP_POOL_RDATA_INC);
-	if (!pool) {
-		ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
-		return 0;
-	}
-
-	ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
-
-	ao2_ref(persisted_subscriptions, -1);
-	return 0;
-}
-
-/*! \brief Event callback which fires subscription persistence recreation when the system is fully booted */
-static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct ast_json_payload *payload;
-	const char *type;
-
-	if (stasis_message_type(message) != ast_manager_get_generic_type()) {
-		return;
-	}
-
-	payload = stasis_message_data(message);
-	type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
-
-	/* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
-	 * recreate SIP subscriptions.
-	 */
-	if (strcmp(type, "FullyBooted")) {
-		return;
-	}
-
-	/* This has to be here so the subscription is recreated when the body generator is available */
-	ast_sip_push_task(NULL, subscription_persistence_load, NULL);
-
-	/* Once the system is fully booted we don't care anymore */
-	stasis_unsubscribe(sub);
-}
-
-typedef int (*on_subscription_t)(struct sip_subscription_tree *sub, void *arg);
-
-static int for_each_subscription(on_subscription_t on_subscription, void *arg)
-{
-	int num = 0;
-	struct sip_subscription_tree *i;
-	SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	if (!on_subscription) {
-		return num;
-	}
-
-	AST_RWLIST_TRAVERSE(&subscriptions, i, next) {
-		if (on_subscription(i, arg)) {
-			break;
-		}
-		++num;
-	}
-	return num;
-}
-
-static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree,
-				    struct ast_str **buf)
-{
-	char str[256];
-	struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
-
-	ast_str_append(buf, 0, "Role: %s\r\n",
-		       sip_subscription_roles_map[sub_tree->role]);
-	ast_str_append(buf, 0, "Endpoint: %s\r\n",
-		       ast_sorcery_object_get_id(sub_tree->endpoint));
-
-	ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
-	ast_str_append(buf, 0, "Callid: %s\r\n", str);
-
-	ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
-
-	ast_callerid_merge(str, sizeof(str),
-			   S_COR(id->self.name.valid, id->self.name.str, NULL),
-			   S_COR(id->self.number.valid, id->self.number.str, NULL),
-			   "Unknown");
-
-	ast_str_append(buf, 0, "Callerid: %s\r\n", str);
-
-	/* XXX This needs to be done recursively for lists */
-	if (sub_tree->root->handler->to_ami) {
-		sub_tree->root->handler->to_ami(sub_tree->root, buf);
-	}
-}
-
-
-void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
-{
-	pjsip_dialog *dlg = sub->tree->dlg;
-	pjsip_msg *msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
-	pj_str_t name;
-
-	pj_cstr(&name, header);
-
-	return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
-}
-
-struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
-		struct ast_sip_endpoint *endpoint, const char *resource)
-{
-	struct ast_sip_subscription *sub;
-	pjsip_dialog *dlg;
-	struct ast_sip_contact *contact;
-	pj_str_t event;
-	pjsip_tx_data *tdata;
-	pjsip_evsub *evsub;
-	struct sip_subscription_tree *sub_tree = NULL;
-
-	sub_tree = allocate_subscription_tree(endpoint);
-	if (!sub_tree) {
-		return NULL;
-	}
-
-	sub = allocate_subscription(handler, resource, sub_tree);
-	if (!sub) {
-		ao2_cleanup(sub_tree);
-		return NULL;
-	}
-
-	contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
-	if (!contact || ast_strlen_zero(contact->uri)) {
-		ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
-				ast_sorcery_object_get_id(endpoint));
-		ao2_ref(sub_tree, -1);
-		ao2_cleanup(contact);
-		return NULL;
-	}
-
-	dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
-	ao2_cleanup(contact);
-	if (!dlg) {
-		ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
-		ao2_ref(sub_tree, -1);
-		return NULL;
-	}
-
-	pj_cstr(&event, handler->event_name);
-	pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
-	subscription_setup_dialog(sub_tree, dlg);
-
-	evsub = sub_tree->evsub;
-
-	if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
-		pjsip_evsub_send_request(evsub, tdata);
-	} else {
-		/* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
-		 * being called and terminating the subscription. Therefore, we don't
-		 * need to decrease the reference count of sub here.
-		 */
-		pjsip_evsub_terminate(evsub, PJ_TRUE);
-		ao2_ref(sub_tree, -1);
-		return NULL;
-	}
-
-	return sub;
-}
-
-struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
-{
-	ast_assert(sub->tree->endpoint != NULL);
-	return ao2_bump(sub->tree->endpoint);
-}
-
-struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
-{
-	ast_assert(sub->tree->serializer != NULL);
-	return sub->tree->serializer;
-}
-
-/*!
- * \brief Pre-allocate a buffer for the transmission
- *
- * Typically, we let PJSIP do this step for us when we send a request. PJSIP's buffer
- * allocation algorithm is to allocate a buffer of PJSIP_MAX_PKT_LEN bytes and attempt
- * to write the packet to the allocated buffer. If the buffer is too small to hold the
- * packet, then we get told the message is too long to be sent.
- *
- * When dealing with SIP NOTIFY, especially with RLS, it is possible to exceed
- * PJSIP_MAX_PKT_LEN. Rather than accepting the limitation imposed on us by default,
- * we instead take the strategy of pre-allocating the buffer, testing for ourselves
- * if the message will fit, and resizing the buffer as required.
- *
- * RFC 3261 says that a SIP UDP request can be up to 65535 bytes long. We're capping
- * it at 64000 for a couple of reasons:
- * 1) Allocating more than 64K at a time is hard to justify
- * 2) If the message goes through proxies, those proxies will want to add Via and
- *    Record-Route headers, making the message even larger. Giving some space for
- *    those headers is a nice thing to do.
- *
- * RFC 3261 does not place an upper limit on the size of TCP requests, but we are
- * going to impose the same 64K limit as a memory savings.
- *
- * \param tdata The tdata onto which to allocate a buffer
- * \retval 0 Success
- * \retval -1 The message is too large
- */
-static int allocate_tdata_buffer(pjsip_tx_data *tdata)
-{
-	int buf_size;
-	int size = -1;
-	char *buf;
-
-	for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < 64000; buf_size *= 2) {
-		buf = pj_pool_alloc(tdata->pool, buf_size);
-		size = pjsip_msg_print(tdata->msg, buf, buf_size);
-	}
-
-	if (size == -1) {
-		return -1;
-	}
-
-	tdata->buf.start = buf;
-	tdata->buf.cur = tdata->buf.start;
-	tdata->buf.end = tdata->buf.start + buf_size;
-
-	return 0;
-}
-
-static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
-{
-#ifdef TEST_FRAMEWORK
-	struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
-#endif
-	int res;
-
-	if (allocate_tdata_buffer(tdata)) {
-		ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
-		return -1;
-	}
-
-	res = pjsip_evsub_send_request(sub_tree->evsub, tdata) == PJ_SUCCESS ? 0 : -1;
-	subscription_persistence_update(sub_tree, NULL);
-
-	ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
-		"StateText: %s\r\n"
-		"Endpoint: %s\r\n",
-		pjsip_evsub_get_state_name(sub_tree->evsub),
-		ast_sorcery_object_get_id(endpoint));
-
-	return res;
-}
-
-/*!
- * \brief Add a resource XML element to an RLMI body
- *
- * Each resource element represents a subscribed resource in the list. This function currently
- * will unconditionally add an instance element to each created resource element. Instance
- * elements refer to later parts in the multipart body.
- *
- * \param pool PJLIB allocation pool
- * \param cid Content-ID header of the resource
- * \param resource_name Name of the resource
- * \param resource_uri URI of the resource
- * \param state State of the subscribed resource
- */
-static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
-		const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
-{
-	static pj_str_t cid_name = { "cid", 3 };
-	pj_xml_node *resource;
-	pj_xml_node *name;
-	pj_xml_node *instance;
-	pj_xml_attr *cid_attr;
-	char id[6];
-	char uri[PJSIP_MAX_URL_SIZE];
-
-	/* This creates a string representing the Content-ID without the enclosing < > */
-	const pj_str_t cid_stripped = {
-		.ptr = cid->hvalue.ptr + 1,
-		.slen = cid->hvalue.slen - 2,
-	};
-
-	resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
-	name = ast_sip_presence_xml_create_node(pool, resource, "name");
-	instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
-
-	pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
-	ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
-
-	pj_strdup2(pool, &name->content, resource_name);
-
-	ast_generate_random_string(id, sizeof(id));
-
-	ast_sip_presence_xml_create_attr(pool, instance, "id", id);
-	ast_sip_presence_xml_create_attr(pool, instance, "state",
-			state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
-
-	/* Use the PJLIB-util XML library directly here since we are using a
-	 * pj_str_t
-	 */
-
-	cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
-	pj_xml_add_attr(instance, cid_attr);
-}
-
-/*!
- * \brief A multipart body part and meta-information
- *
- * When creating a multipart body part, the end result (the
- * pjsip_multipart_part) is hard to inspect without undoing
- * a lot of what was done to create it. Therefore, we use this
- * structure to store meta-information about the body part.
- *
- * The main consumer of this is the creator of the RLMI body
- * part of a multipart resource list body.
- */
-struct body_part {
-	/*! Content-ID header for the body part */
-	pjsip_generic_string_hdr *cid;
-	/*! Subscribed resource represented in the body part */
-	const char *resource;
-	/*! URI for the subscribed body part */
-	pjsip_sip_uri *uri;
-	/*! Subscription state of the resource represented in the body part */
-	pjsip_evsub_state state;
-	/*! The actual body part that will be present in the multipart body */
-	pjsip_multipart_part *part;
-};
-
-/*!
- * \brief Type declaration for container of body part structures
- */
-AST_VECTOR(body_part_list, struct body_part *);
-
-/*!
- * \brief Create a Content-ID header
- *
- * Content-ID headers are required by RFC2387 for multipart/related
- * bodies. They serve as identifiers for each part of the multipart body.
- *
- * \param pool PJLIB allocation pool
- * \param sub Subscription to a resource
- */
-static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
-		const struct ast_sip_subscription *sub)
-{
-	static const pj_str_t cid_name = { "Content-ID", 10 };
-	pjsip_generic_string_hdr *cid;
-	char id[6];
-	size_t alloc_size;
-	pj_str_t cid_value;
-
-	/* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
-	alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
-	cid_value.ptr = pj_pool_alloc(pool, alloc_size);
-	cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
-			ast_generate_random_string(id, sizeof(id)),
-			(int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
-	cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
-
-	return cid;
-}
-
-static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
-{
-	int num_printed;
-	pj_xml_node *rlmi = msg_body->data;
-
-	num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
-	if (num_printed == AST_PJSIP_XML_PROLOG_LEN) {
-		return -1;
-	}
-
-	return num_printed;
-}
-
-static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
-{
-	const pj_xml_node *rlmi = data;
-
-	return pj_xml_clone(pool, rlmi);
-}
-
-/*!
- * \brief Create an RLMI body part for a multipart resource list body
- *
- * RLMI (Resource list meta information) is a special body type that lists
- * the subscribed resources and tells subscribers the number of subscribed
- * resources and what other body parts are in the multipart body. The
- * RLMI body also has a version number that a subscriber can use to ensure
- * that the locally-stored state corresponds to server state.
- *
- * \param pool The allocation pool
- * \param sub The subscription representing the subscribed resource list
- * \param body_parts A container of body parts that RLMI will refer to
- * \param full_state Indicates whether this is a full or partial state notification
- * \return The multipart part representing the RLMI body
- */
-static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
-		struct body_part_list *body_parts, unsigned int full_state)
-{
-	static const pj_str_t rlmi_type = { "application", 11 };
-	static const pj_str_t rlmi_subtype = { "rlmi+xml", 8 };
-	pj_xml_node *rlmi;
-	pj_xml_node *name;
-	pjsip_multipart_part *rlmi_part;
-	char version_str[32];
-	char uri[PJSIP_MAX_URL_SIZE];
-	pjsip_generic_string_hdr *cid;
-	int i;
-
-	rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
-	ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
-
-	ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
-	ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
-
-	snprintf(version_str, sizeof(version_str), "%u", sub->version++);
-	ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
-	ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
-
-	name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
-	pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
-
-	for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
-		const struct body_part *part = AST_VECTOR_GET(body_parts, i);
-
-		add_rlmi_resource(pool, rlmi, part->cid, part->resource, part->uri, part->state);
-	}
-
-	rlmi_part = pjsip_multipart_create_part(pool);
-
-	rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
-	pj_strdup(pool, &rlmi_part->body->content_type.type, &rlmi_type);
-	pj_strdup(pool, &rlmi_part->body->content_type.subtype, &rlmi_subtype);
-	pj_list_init(&rlmi_part->body->content_type.param);
-
-	rlmi_part->body->data = pj_xml_clone(pool, rlmi);
-	rlmi_part->body->clone_data = rlmi_clone_data;
-	rlmi_part->body->print_body = rlmi_print_body;
-
-	cid = generate_content_id_hdr(pool, sub);
-	pj_list_insert_before(&rlmi_part->hdr, cid);
-
-	return rlmi_part;
-}
-
-static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
-		unsigned int force_full_state);
-
-/*!
- * \brief Destroy a list of body parts
- *
- * \param parts The container of parts to destroy
- */
-static void free_body_parts(struct body_part_list *parts)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
-		struct body_part *part = AST_VECTOR_GET(parts, i);
-		ast_free(part);
-	}
-
-	AST_VECTOR_FREE(parts);
-}
-
-/*!
- * \brief Allocate and initialize a body part structure
- *
- * \param pool PJLIB allocation pool
- * \param sub Subscription representing a subscribed resource
- */
-static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
-{
-	struct body_part *bp;
-
-	bp = ast_calloc(1, sizeof(*bp));
-	if (!bp) {
-		return NULL;
-	}
-
-	bp->cid = generate_content_id_hdr(pool, sub);
-	bp->resource = sub->resource;
-	bp->state = sub->subscription_state;
-	bp->uri = sub->uri;
-
-	return bp;
-}
-
-/*!
- * \brief Create a multipart body part for a subscribed resource
- *
- * \param pool PJLIB allocation pool
- * \param sub The subscription representing a subscribed resource
- * \param parts A vector of parts to append the created part to.
- * \param use_full_state Unused locally, but may be passed to other functions
- */
-static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
-		struct body_part_list *parts, unsigned int use_full_state)
-{
-	struct body_part *bp;
-	pjsip_msg_body *body;
-
-	bp = allocate_body_part(pool, sub);
-	if (!bp) {
-		return;
-	}
-
-	body = generate_notify_body(pool, sub, use_full_state);
-	if (!body) {
-		/* Partial state was requested and the resource has not changed state */
-		ast_free(bp);
-		return;
-	}
-
-	bp->part = pjsip_multipart_create_part(pool);
-	bp->part->body = body;
-	pj_list_insert_before(&bp->part->hdr, bp->cid);
-
-	AST_VECTOR_APPEND(parts, bp);
-}
-
-/*!
- * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
- *
- * \param pool
- * \return The multipart message body
- */
-static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
-{
-	pjsip_media_type media_type;
-	pjsip_param *media_type_param;
-	char boundary[6];
-	pj_str_t pj_boundary;
-
-	pjsip_media_type_init2(&media_type, "multipart", "related");
-
-	media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
-	pj_list_init(media_type_param);
-
-	pj_strdup2(pool, &media_type_param->name, "type");
-	pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
-
-	pj_list_insert_before(&media_type.param, media_type_param);
-
-	pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
-	return pjsip_multipart_create(pool, &media_type, &pj_boundary);
-}
-
-/*!
- * \brief Create a resource list body for NOTIFY requests
- *
- * Resource list bodies are multipart/related bodies. The first part of the multipart body
- * is an RLMI body that describes the rest of the parts to come. The other parts of the body
- * convey state of individual subscribed resources.
- *
- * \param pool PJLIB allocation pool
- * \param sub Subscription details from which to generate body
- * \param force_full_state If true, ignore resource list settings and send a full state notification
- * \return The generated multipart/related body
- */
-static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
-		unsigned int force_full_state)
-{
-	int i;
-	pjsip_multipart_part *rlmi_part;
-	pjsip_msg_body *multipart;
-	struct body_part_list body_parts;
-	unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
-
-	if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
-		return NULL;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
-		build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
-	}
-
-	/* This can happen if issuing partial state and no children of the list have changed state */
-	if (AST_VECTOR_SIZE(&body_parts) == 0) {
-		return NULL;
-	}
-
-	multipart = create_multipart_body(pool);
-
-	rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
-	if (!rlmi_part) {
-		return NULL;
-	}
-	pjsip_multipart_add_part(pool, multipart, rlmi_part);
-
-	for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
-		pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
-	}
-
-	free_body_parts(&body_parts);
-	return multipart;
-}
-
-/*!
- * \brief Create the body for a NOTIFY request.
- *
- * \param pool The pool used for allocations
- * \param root The root of the subscription tree
- * \param force_full_state If true, ignore resource list settings and send a full state notification
- */
-static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
-		unsigned int force_full_state)
-{
-	pjsip_msg_body *body;
-
-	if (AST_VECTOR_SIZE(&root->children) == 0) {
-		if (force_full_state || root->body_changed) {
-			/* Not a list. We've already generated the body and saved it on the subscription.
-			 * Use that directly.
-			 */
-			pj_str_t type;
-			pj_str_t subtype;
-			pj_str_t text;
-
-			pj_cstr(&type, ast_sip_subscription_get_body_type(root));
-			pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
-			pj_cstr(&text, ast_str_buffer(root->body_text));
-
-			body = pjsip_msg_body_create(pool, &type, &subtype, &text);
-			root->body_changed = 0;
-		} else {
-			body = NULL;
-		}
-	} else {
-		body = generate_list_body(pool, root, force_full_state);
-	}
-
-	return body;
-}
-
-/*!
- * \brief Shortcut method to create a Require: eventlist header
- */
-static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
-{
-	pjsip_require_hdr *require;
-
-	require = pjsip_require_hdr_create(pool);
-	pj_strdup2(pool, &require->values[0], "eventlist");
-	require->count = 1;
-
-	return require;
-}
-
-/*!
- * \brief Send a NOTIFY request to a subscriber
- *
- * \param sub_tree The subscription tree representing the subscription
- * \param force_full_state If true, ignore resource list settings and send full resource list state.
- * \retval 0 Success
- * \retval non-zero Failure
- */
-static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
-{
-	pjsip_evsub *evsub = sub_tree->evsub;
-	pjsip_tx_data *tdata;
-
-	if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
-				NULL, NULL, &tdata) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
-	if (!tdata->msg->body) {
-		pjsip_tx_data_dec_ref(tdata);
-		return -1;
-	}
-
-	if (sub_tree->is_list) {
-		pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
-	}
-
-	if (sip_subscription_send_request(sub_tree, tdata)) {
-		return -1;
-	}
-
-	sub_tree->send_scheduled_notify = 0;
-
-	return 0;
-}
-
-static int serialized_send_notify(void *userdata)
-{
-	struct sip_subscription_tree *sub_tree = userdata;
-
-	/* It's possible that between when the notification was scheduled
-	 * and now, that a new SUBSCRIBE arrived, requiring full state to be
-	 * sent out in an immediate NOTIFY. If that has happened, we need to
-	 * bail out here instead of sending the batched NOTIFY.
-	 */
-	if (!sub_tree->send_scheduled_notify) {
-		ao2_cleanup(sub_tree);
-		return 0;
-	}
-
-	send_notify(sub_tree, 0);
-	ast_test_suite_event_notify("SUBSCRIPTION_STATE_CHANGED",
-			"Resource: %s",
-			sub_tree->root->resource);
-	sub_tree->notify_sched_id = -1;
-	ao2_cleanup(sub_tree);
-	return 0;
-}
-
-static int sched_cb(const void *data)
-{
-	struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
-
-	/* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
-	ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree);
-	return 0;
-}
-
-static int schedule_notification(struct sip_subscription_tree *sub_tree)
-{
-	/* There's already a notification scheduled */
-	if (sub_tree->notify_sched_id > -1) {
-		return 0;
-	}
-
-	sub_tree->notify_sched_id = ast_sched_add(sched, sub_tree->notification_batch_interval, sched_cb, ao2_bump(sub_tree));
-	if (sub_tree->notify_sched_id < 0) {
-		return -1;
-	}
-
-	sub_tree->send_scheduled_notify = 1;
-	return 0;
-}
-
-int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data,
-		int terminate)
-{
-	if (ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
-				ast_sip_subscription_get_body_subtype(sub), notify_data, &sub->body_text)) {
-		return -1;
-	}
-
-	sub->body_changed = 1;
-	if (terminate) {
-		sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
-	}
-
-	if (sub->tree->notification_batch_interval) {
-		return schedule_notification(sub->tree);
-	} else {
-		int res;
-		/* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
-		ao2_ref(sub->tree, +1);
-		res = send_notify(sub->tree, 0);
-		ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
-				"Resource: %s",
-				sub->tree->root->resource);
-		ao2_ref(sub->tree, -1);
-
-		return res;
-	}
-}
-
-void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
-{
-	pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
-}
-
-void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
-{
-	pjsip_dialog *dlg = sub->tree->dlg;
-	ast_copy_pj_str(buf, &dlg->remote.info_str, size);
-}
-
-const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
-{
-	return sub->resource;
-}
-
-static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
-{
-	pjsip_hdr res_hdr;
-
-	/* If this is a persistence recreation the subscription has already been accepted */
-	if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
-		return 0;
-	}
-
-	pj_list_init(&res_hdr);
-	if (sub_tree->is_list) {
-		/* If subscribing to a list, our response has to have a Require: eventlist header in it */
-		pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
-	}
-
-	return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
-}
-
-static void subscription_datastore_destroy(void *obj)
-{
-	struct ast_datastore *datastore = obj;
-
-	/* Using the destroy function (if present) destroy the data */
-	if (datastore->info->destroy != NULL && datastore->data != NULL) {
-		datastore->info->destroy(datastore->data);
-		datastore->data = NULL;
-	}
-
-	ast_free((void *) datastore->uid);
-	datastore->uid = NULL;
-}
-
-struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	char uuid_buf[AST_UUID_STR_LEN];
-	const char *uid_ptr = uid;
-
-	if (!info) {
-		return NULL;
-	}
-
-	datastore = ao2_alloc(sizeof(*datastore), subscription_datastore_destroy);
-	if (!datastore) {
-		return NULL;
-	}
-
-	datastore->info = info;
-	if (ast_strlen_zero(uid)) {
-		/* They didn't provide an ID so we'll provide one ourself */
-		uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
-	}
-
-	datastore->uid = ast_strdup(uid_ptr);
-	if (!datastore->uid) {
-		return NULL;
-	}
-
-	ao2_ref(datastore, +1);
-	return datastore;
-}
-
-int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
-{
-	ast_assert(datastore != NULL);
-	ast_assert(datastore->info != NULL);
-	ast_assert(!ast_strlen_zero(datastore->uid));
-
-	if (!ao2_link(subscription->datastores, datastore)) {
-		return -1;
-	}
-	return 0;
-}
-
-struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
-{
-	return ao2_find(subscription->datastores, name, OBJ_KEY);
-}
-
-void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
-{
-	ao2_find(subscription->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-}
-
-int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
-{
-	ast_assert(datastore != NULL);
-	ast_assert(datastore->info != NULL);
-	ast_assert(!ast_strlen_zero(datastore->uid));
-
-	if (!ao2_link(publication->datastores, datastore)) {
-		return -1;
-	}
-	return 0;
-}
-
-struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name)
-{
-	return ao2_find(publication->datastores, name, OBJ_KEY);
-}
-
-void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
-{
-	ao2_callback(publication->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
-}
-
-AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler);
-
-static int publication_hash_fn(const void *obj, const int flags)
-{
-	const struct ast_sip_publication *publication = obj;
-	const int *entity_tag = obj;
-
-	return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
-}
-
-static int publication_cmp_fn(void *obj, void *arg, int flags)
-{
-	const struct ast_sip_publication *publication1 = obj;
-	const struct ast_sip_publication *publication2 = arg;
-	const int *entity_tag = arg;
-
-	return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
-		CMP_MATCH | CMP_STOP : 0);
-}
-
-static void publish_add_handler(struct ast_sip_publish_handler *handler)
-{
-	SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next);
-}
-
-int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
-{
-	if (ast_strlen_zero(handler->event_name)) {
-		ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
-		return -1;
-	}
-
-	if (!(handler->publications = ao2_container_alloc(PUBLICATIONS_BUCKETS,
-		publication_hash_fn, publication_cmp_fn))) {
-		ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
-			handler->event_name);
-		return -1;
-	}
-
-	publish_add_handler(handler);
-
-	ast_module_ref(ast_module_info->self);
-
-	return 0;
-}
-
-void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
-{
-	struct ast_sip_publish_handler *iter;
-	SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publish_handlers, iter, next) {
-		if (handler == iter) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ao2_cleanup(handler->publications);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-AST_RWLIST_HEAD_STATIC(subscription_handlers, ast_sip_subscription_handler);
-
-static void sub_add_handler(struct ast_sip_subscription_handler *handler)
-{
-	SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next);
-	ast_module_ref(ast_module_info->self);
-}
-
-static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name)
-{
-	struct ast_sip_subscription_handler *iter;
-	SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
-		if (!strcmp(iter->event_name, event_name)) {
-			break;
-		}
-	}
-	return iter;
-}
-
-int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
-{
-	pj_str_t event;
-	pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
-	struct ast_sip_subscription_handler *existing;
-	int i = 0;
-
-	if (ast_strlen_zero(handler->event_name)) {
-		ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
-		return -1;
-	}
-
-	existing = find_sub_handler_for_event_name(handler->event_name);
-	if (existing) {
-		ast_log(LOG_ERROR, "Unable to register subscription handler for event %s."
-				"A handler is already registered\n", handler->event_name);
-		return -1;
-	}
-
-	for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
-		pj_cstr(&accept[i], handler->accept[i]);
-	}
-
-	pj_cstr(&event, handler->event_name);
-
-	pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
-
-	sub_add_handler(handler);
-
-	return 0;
-}
-
-void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
-{
-	struct ast_sip_subscription_handler *iter;
-	SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) {
-		if (handler == iter) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype(const char *content_type,
-		const char *content_subtype)
-{
-	struct ast_sip_pubsub_body_generator *iter;
-	SCOPED_LOCK(lock, &body_generators, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	AST_LIST_TRAVERSE(&body_generators, iter, list) {
-		if (!strcmp(iter->type, content_type) &&
-				!strcmp(iter->subtype, content_subtype)) {
-			break;
-		}
-	};
-
-	return iter;
-}
-
-static struct ast_sip_pubsub_body_generator *find_body_generator_accept(const char *accept)
-{
-	char *accept_copy = ast_strdupa(accept);
-	char *subtype = accept_copy;
-	char *type = strsep(&subtype, "/");
-
-	if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
-		return NULL;
-	}
-
-	return find_body_generator_type_subtype(type, subtype);
-}
-
-static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
-		size_t num_accept, const char *body_type)
-{
-	int i;
-	struct ast_sip_pubsub_body_generator *generator = NULL;
-
-	for (i = 0; i < num_accept; ++i) {
-		generator = find_body_generator_accept(accept[i]);
-		if (generator) {
-			ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
-			if (strcmp(generator->body_type, body_type)) {
-				ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
-						generator->type, generator->subtype, generator);
-				generator = NULL;
-				continue;
-			}
-			break;
-		} else {
-			ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
-		}
-	}
-
-	return generator;
-}
-
-static int generate_initial_notify(struct ast_sip_subscription *sub)
-{
-	void *notify_data;
-	int res;
-	struct ast_sip_body_data data = {
-		.body_type = sub->handler->body_type,
-	};
-
-	if (AST_VECTOR_SIZE(&sub->children) > 0) {
-		int i;
-
-		for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
-			if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
-				return -1;
-			}
-		}
-
-		return 0;
-	}
-
-	if (sub->handler->notifier->subscription_established(sub)) {
-		return -1;
-	}
-
-	notify_data = sub->handler->notifier->get_notify_data(sub);
-	if (!notify_data) {
-		return -1;
-	}
-
-	data.body_data = notify_data;
-
-	res = ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
-			ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
-
-	ao2_cleanup(notify_data);
-
-	return res;
-}
-
-static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
-{
-	pjsip_expires_hdr *expires_header;
-	struct ast_sip_subscription_handler *handler;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	struct sip_subscription_tree *sub_tree;
-	struct ast_sip_pubsub_body_generator *generator;
-	char *resource;
-	pjsip_uri *request_uri;
-	pjsip_sip_uri *request_uri_sip;
-	size_t resource_size;
-	int resp;
-	struct resource_tree tree;
-	pj_status_t dlg_status;
-
-	endpoint = ast_pjsip_rdata_get_endpoint(rdata);
-	ast_assert(endpoint != NULL);
-
-	if (!endpoint->subscription.allow) {
-		ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	request_uri = rdata->msg_info.msg->line.req.uri;
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
-		char uri_str[PJSIP_MAX_URL_SIZE];
-
-		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
-		ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	request_uri_sip = pjsip_uri_get_uri(request_uri);
-	resource_size = pj_strlen(&request_uri_sip->user) + 1;
-	resource = alloca(resource_size);
-	ast_copy_pj_str(resource, &request_uri_sip->user, resource_size);
-
-	expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
-
-	if (expires_header) {
-		if (expires_header->ivalue == 0) {
-			ast_log(LOG_WARNING, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
-				ast_sorcery_object_get_id(endpoint));
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
-				return PJ_TRUE;
-		}
-		if (expires_header->ivalue < endpoint->subscription.minexpiry) {
-			ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
-				expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
-			return PJ_TRUE;
-		}
-	}
-
-	handler = subscription_get_handler_from_rdata(rdata);
-	if (!handler) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	generator = subscription_get_generator_from_rdata(rdata, handler);
-	if (!generator) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	memset(&tree, 0, sizeof(tree));
-	resp = build_resource_tree(endpoint, handler, resource, &tree,
-		ast_sip_pubsub_has_eventlist_support(rdata));
-	if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
-		resource_tree_destroy(&tree);
-		return PJ_TRUE;
-	}
-
-	sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status);
-	if (!sub_tree) {
-		if (dlg_status != PJ_EEXISTS) {
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		}
-	} else {
-		sub_tree->persistence = subscription_persistence_create(sub_tree);
-		subscription_persistence_update(sub_tree, rdata);
-		sip_subscription_accept(sub_tree, rdata, resp);
-		if (generate_initial_notify(sub_tree->root)) {
-			pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
-		}
-		send_notify(sub_tree, 1);
-		ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
-				"Resource: %s",
-				sub_tree->root->resource);
-	}
-
-	resource_tree_destroy(&tree);
-	return PJ_TRUE;
-}
-
-static struct ast_sip_publish_handler *find_pub_handler(const char *event)
-{
-	struct ast_sip_publish_handler *iter = NULL;
-	SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE(&publish_handlers, iter, next) {
-		if (strcmp(event, iter->event_name)) {
-			ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
-			continue;
-		}
-		ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
-		break;
-	}
-
-	return iter;
-}
-
-static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata,
-	pjsip_generic_string_hdr *etag_hdr, int *expires, int *entity_id)
-{
-	pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
-
-	if (etag_hdr) {
-		char etag[pj_strlen(&etag_hdr->hvalue) + 1];
-
-		ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
-
-		if (sscanf(etag, "%30d", entity_id) != 1) {
-			return SIP_PUBLISH_UNKNOWN;
-		}
-	}
-
-	*expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
-
-	if (!(*expires)) {
-		return SIP_PUBLISH_REMOVE;
-	} else if (!etag_hdr && rdata->msg_info.msg->body) {
-		return SIP_PUBLISH_INITIAL;
-	} else if (etag_hdr && !rdata->msg_info.msg->body) {
-		return SIP_PUBLISH_REFRESH;
-	} else if (etag_hdr && rdata->msg_info.msg->body) {
-		return SIP_PUBLISH_MODIFY;
-	}
-
-	return SIP_PUBLISH_UNKNOWN;
-}
-
-/*! \brief Internal destructor for publications */
-static void publication_destroy_fn(void *obj)
-{
-	struct ast_sip_publication *publication = obj;
-
-	ast_debug(3, "Destroying SIP publication\n");
-
-	ao2_cleanup(publication->datastores);
-	ao2_cleanup(publication->endpoint);
-}
-
-static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
-	const char *resource, const char *event_configuration_name)
-{
-	struct ast_sip_publication *publication;
-	pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
-	size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
-	char *dst;
-
-	ast_assert(endpoint != NULL);
-
-	if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
-		return NULL;
-	}
-
-	if (!(publication->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp))) {
-		ao2_ref(publication, -1);
-		return NULL;
-	}
-
-	publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
-	ao2_ref(endpoint, +1);
-	publication->endpoint = endpoint;
-	publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
-	publication->sched_id = -1;
-	dst = publication->data;
-	publication->resource = strcpy(dst, resource);
-	dst += resource_len;
-	publication->event_configuration_name = strcpy(dst, event_configuration_name);
-
-	return publication;
-}
-
-static int sip_publication_respond(struct ast_sip_publication *pub, int status_code,
-		pjsip_rx_data *rdata)
-{
-	pj_status_t status;
-	pjsip_tx_data *tdata;
-	pjsip_transaction *tsx;
-
-	if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
-		RAII_VAR(char *, entity_tag, NULL, ast_free_ptr);
-		RAII_VAR(char *, expires, NULL, ast_free_ptr);
-
-		if ((ast_asprintf(&entity_tag, "%d", pub->entity_tag) < 0) ||
-			(ast_asprintf(&expires, "%d", pub->expires) < 0)) {
-			pjsip_tx_data_dec_ref(tdata);
-			return -1;
-		}
-
-		ast_sip_add_header(tdata, "SIP-ETag", entity_tag);
-		ast_sip_add_header(tdata, "Expires", expires);
-	}
-
-	if ((status = pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx)) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	pjsip_tsx_recv_msg(tsx, rdata);
-
-	if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
-		return -1;
-	}
-
-	return 0;
-}
-
-static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
-	struct ast_sip_publish_handler *handler)
-{
-	struct ast_sip_publication *publication;
-	char *resource_name;
-	size_t resource_size;
-	RAII_VAR(struct ast_sip_publication_resource *, resource, NULL, ao2_cleanup);
-	struct ast_variable *event_configuration_name = NULL;
-	pjsip_uri *request_uri;
-	pjsip_sip_uri *request_uri_sip;
-	int resp;
-
-	request_uri = rdata->msg_info.msg->line.req.uri;
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
-		char uri_str[PJSIP_MAX_URL_SIZE];
-
-		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
-		ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	request_uri_sip = pjsip_uri_get_uri(request_uri);
-	resource_size = pj_strlen(&request_uri_sip->user) + 1;
-	resource_name = alloca(resource_size);
-	ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
-
-	resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
-	if (!resource) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
-		if (!strcmp(event_configuration_name->name, handler->event_name)) {
-			break;
-		}
-	}
-
-	if (!event_configuration_name) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
-
-	if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
-
-	if (!publication) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
-		return NULL;
-	}
-
-	publication->handler = handler;
-	if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
-			AST_SIP_PUBLISH_STATE_INITIALIZED)) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		ao2_cleanup(publication);
-		return NULL;
-	}
-
-	sip_publication_respond(publication, resp, rdata);
-
-	return publication;
-}
-
-static int publish_expire_callback(void *data)
-{
-	RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
-
-	if (publication->handler->publish_expire) {
-		publication->handler->publish_expire(publication);
-	}
-
-	return 0;
-}
-
-static int publish_expire(const void *data)
-{
-	struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
-
-	ao2_unlink(publication->handler->publications, publication);
-	publication->sched_id = -1;
-
-	if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
-		ao2_cleanup(publication);
-	}
-
-	return 0;
-}
-
-static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
-{
-	pjsip_event_hdr *event_header;
-	struct ast_sip_publish_handler *handler;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	char event[32];
-	static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
-	pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
-	enum sip_publish_type publish_type;
-	RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
-	int expires = 0, entity_id, response = 0;
-
-	endpoint = ast_pjsip_rdata_get_endpoint(rdata);
-	ast_assert(endpoint != NULL);
-
-	event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
-	if (!event_header) {
-		ast_log(LOG_WARNING, "Incoming PUBLISH request with no Event header\n");
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-	ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
-
-	handler = find_pub_handler(event);
-	if (!handler) {
-		ast_log(LOG_WARNING, "No registered publish handler for event %s\n", event);
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
-
-	/* If this is not an initial publish ensure that a publication is present */
-	if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
-		if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
-			static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
-
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
-				NULL, NULL);
-			return PJ_TRUE;
-		}
-
-		/* Per the RFC every response has to have a new entity tag */
-		publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
-
-		/* Update the expires here so that the created responses will contain the correct value */
-		publication->expires = expires;
-	}
-
-	switch (publish_type) {
-		case SIP_PUBLISH_INITIAL:
-			publication = publish_request_initial(endpoint, rdata, handler);
-			break;
-		case SIP_PUBLISH_REFRESH:
-		case SIP_PUBLISH_MODIFY:
-			if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
-						AST_SIP_PUBLISH_STATE_ACTIVE)) {
-				/* If an error occurs we want to terminate the publication */
-				expires = 0;
-			}
-			response = 200;
-			break;
-		case SIP_PUBLISH_REMOVE:
-			handler->publication_state_change(publication, rdata->msg_info.msg->body,
-					AST_SIP_PUBLISH_STATE_TERMINATED);
-			response = 200;
-			break;
-		case SIP_PUBLISH_UNKNOWN:
-		default:
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
-			break;
-	}
-
-	if (publication) {
-		if (expires) {
-			ao2_link(handler->publications, publication);
-
-			AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
-						ao2_ref(publication, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
-		} else {
-			AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
-		}
-	}
-
-	if (response) {
-		sip_publication_respond(publication, response, rdata);
-	}
-
-	return PJ_TRUE;
-}
-
-struct ast_sip_endpoint *ast_sip_publication_get_endpoint(struct ast_sip_publication *pub)
-{
-	return pub->endpoint;
-}
-
-const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
-{
-	return pub->resource;
-}
-
-const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
-{
-	return pub->event_configuration_name;
-}
-
-int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
-{
-	struct ast_sip_pubsub_body_generator *existing;
-	pj_str_t accept;
-	pj_size_t accept_len;
-
-	existing = find_body_generator_type_subtype(generator->type, generator->subtype);
-	if (existing) {
-		ast_log(LOG_WARNING, "Cannot register body generator of %s/%s."
-				"One is already registered.\n", generator->type, generator->subtype);
-		return -1;
-	}
-
-	AST_RWLIST_WRLOCK(&body_generators);
-	AST_LIST_INSERT_HEAD(&body_generators, generator, list);
-	AST_RWLIST_UNLOCK(&body_generators);
-
-	/* Lengths of type and subtype plus space for a slash. pj_str_t is not
-	 * null-terminated, so there is no need to allocate for the extra null
-	 * byte
-	 */
-	accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
-
-	accept.ptr = alloca(accept_len);
-	accept.slen = accept_len;
-	/* Safe use of sprintf */
-	sprintf(accept.ptr, "%s/%s", generator->type, generator->subtype);
-	pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
-			PJSIP_H_ACCEPT, NULL, 1, &accept);
-
-	return 0;
-}
-
-void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
-{
-	struct ast_sip_pubsub_body_generator *iter;
-	SCOPED_LOCK(lock, &body_generators, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) {
-		if (iter == generator) {
-			AST_LIST_REMOVE_CURRENT(list);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
-{
-	AST_RWLIST_WRLOCK(&body_supplements);
-	AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
-	AST_RWLIST_UNLOCK(&body_supplements);
-
-	return 0;
-}
-
-void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
-{
-	struct ast_sip_pubsub_body_supplement *iter;
-	SCOPED_LOCK(lock, &body_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_supplements, iter, list) {
-		if (iter == supplement) {
-			AST_LIST_REMOVE_CURRENT(list);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
-{
-	return sub->body_generator->type;
-}
-
-const char *ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
-{
-	return sub->body_generator->subtype;
-}
-
-int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype,
-		struct ast_sip_body_data *data, struct ast_str **str)
-{
-	struct ast_sip_pubsub_body_supplement *supplement;
-	struct ast_sip_pubsub_body_generator *generator;
-	int res = 0;
-	void *body;
-
-	generator = find_body_generator_type_subtype(type, subtype);
-	if (!generator) {
-		ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
-				type, subtype);
-		return -1;
-	}
-
-	if (strcmp(data->body_type, generator->body_type)) {
-		ast_log(LOG_WARNING, "Body generator does not accept the type of data provided\n");
-		return -1;
-	}
-
-	body = generator->allocate_body(data->body_data);
-	if (!body) {
-		ast_log(LOG_WARNING, "Unable to allocate a NOTIFY body of type %s/%s\n",
-				type, subtype);
-		return -1;
-	}
-
-	if (generator->generate_body_content(body, data->body_data)) {
-		res = -1;
-		goto end;
-	}
-
-	AST_RWLIST_RDLOCK(&body_supplements);
-	AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
-		if (!strcmp(generator->type, supplement->type) &&
-				!strcmp(generator->subtype, supplement->subtype)) {
-			res = supplement->supplement_body(body, data->body_data);
-			if (res) {
-				break;
-			}
-		}
-	}
-	AST_RWLIST_UNLOCK(&body_supplements);
-
-	if (!res) {
-		generator->to_string(body, str);
-	}
-
-end:
-	if (generator->destroy_body) {
-		generator->destroy_body(body);
-	}
-
-	return res;
-}
-
-static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
-{
-	if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
-		return pubsub_on_rx_subscribe_request(rdata);
-	} else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
-		return pubsub_on_rx_publish_request(rdata);
-	}
-
-	return PJ_FALSE;
-}
-
-static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
-{
-	struct sip_subscription_tree *sub_tree;
-
-	if (pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
-		return;
-	}
-
-	sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-	if (!sub_tree) {
-		return;
-	}
-
-	ao2_cleanup(sub_tree);
-
-	pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
-}
-
-static void set_state_terminated(struct ast_sip_subscription *sub)
-{
-	int i;
-
-	sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
-	for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
-		set_state_terminated(AST_VECTOR_GET(&sub->children, i));
-	}
-}
-
-static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
-		int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
-{
-	struct sip_subscription_tree *sub_tree;
-
-	sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-	if (!sub_tree) {
-		return;
-	}
-
-	/* If sending a NOTIFY to terminate a subscription, then pubsub_on_evsub_state()
-	 * will be called when we send the NOTIFY, and that will result in dropping the
-	 * refcount of sub_tree by one, and possibly destroying the sub_tree. We need to
-	 * hold a reference to the sub_tree until this function returns so that we don't
-	 * try to read from or write to freed memory by accident
-	 */
-	ao2_ref(sub_tree, +1);
-
-	if (pjsip_evsub_get_state(evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
-		set_state_terminated(sub_tree->root);
-	}
-
-	if (send_notify(sub_tree, 1)) {
-		*p_st_code = 500;
-	}
-
-	ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
-			"SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
-			"Resource: %s", sub_tree->root->resource);
-
-	if (sub_tree->is_list) {
-		pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
-	}
-
-	ao2_ref(sub_tree, -1);
-}
-
-static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
-		pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
-{
-	struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-
-	if (!sub) {
-		return;
-	}
-
-	sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
-			pjsip_evsub_get_state(evsub));
-}
-
-static int serialized_pubsub_on_client_refresh(void *userdata)
-{
-	struct sip_subscription_tree *sub_tree = userdata;
-	pjsip_tx_data *tdata;
-
-	if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
-		pjsip_evsub_send_request(sub_tree->evsub, tdata);
-	} else {
-		pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
-		return 0;
-	}
-	ao2_cleanup(sub_tree);
-	return 0;
-}
-
-static void pubsub_on_client_refresh(pjsip_evsub *evsub)
-{
-	struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-
-	ao2_ref(sub_tree, +1);
-	ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_client_refresh, sub_tree);
-}
-
-static int serialized_pubsub_on_server_timeout(void *userdata)
-{
-	struct sip_subscription_tree *sub_tree = userdata;
-
-	set_state_terminated(sub_tree->root);
-	send_notify(sub_tree, 1);
-	ast_test_suite_event_notify("SUBSCRIPTION_TERMINATED",
-			"Resource: %s",
-			sub_tree->root->resource);
-
-	ao2_cleanup(sub_tree);
-	return 0;
-}
-
-static void pubsub_on_server_timeout(pjsip_evsub *evsub)
-{
-	struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-
-	if (!sub_tree) {
-		/* if a subscription has been terminated and the subscription
-		   timeout/expires is less than the time it takes for all pending
-		   transactions to end then the subscription timer will not have
-		   been canceled yet and sub will be null, so do nothing since
-		   the subscription has already been terminated. */
-		return;
-	}
-
-	ao2_ref(sub_tree, +1);
-	ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_server_timeout, sub_tree);
-}
-
-static int ami_subscription_detail(struct sip_subscription_tree *sub_tree,
-				   struct ast_sip_ami *ami,
-				   const char *event)
-{
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event(event, ami), ast_free);
-
-	if (!buf) {
-		return -1;
-	}
-
-	sip_subscription_to_ami(sub_tree, &buf);
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	return 0;
-}
-
-static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
-{
-	return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
-		sub_tree, arg, "InboundSubscriptionDetail") : 0;
-}
-
-static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
-{
-	return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
-		sub_tree, arg, "OutboundSubscriptionDetail") : 0;
-}
-
-static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
-	int num;
-
-	astman_send_listack(s, m, "Following are Events for "
-			    "each inbound Subscription", "start");
-
-	num = for_each_subscription(ami_subscription_detail_inbound, &ami);
-
-	astman_append(s, "Event: InboundSubscriptionDetailComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", num);
-	return 0;
-}
-
-static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
-	int num;
-
-	astman_send_listack(s, m, "Following are Events for "
-			    "each outbound Subscription", "start");
-
-	num = for_each_subscription(ami_subscription_detail_outbound, &ami);
-
-	astman_append(s, "Event: OutboundSubscriptionDetailComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", num);
-	return 0;
-}
-
-static int format_ami_resource_lists(void *obj, void *arg, int flags)
-{
-	struct resource_list *list = obj;
-	struct ast_sip_ami *ami = arg;
-	struct ast_str *buf;
-
-	buf = ast_sip_create_ami_event("ResourceListDetail", ami);
-	if (!buf) {
-		return CMP_STOP;
-	}
-
-	if (ast_sip_sorcery_object_to_ami(list, &buf)) {
-		ast_free(buf);
-		return CMP_STOP;
-	}
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-
-	ast_free(buf);
-	return 0;
-}
-
-static int ami_show_resource_lists(struct mansession *s, const struct message *m)
-{
-	struct ast_sip_ami ami = { .s = s, .m = m };
-	int num;
-	struct ao2_container *lists;
-
-	lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
-			AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-
-	if (!lists || !(num = ao2_container_count(lists))) {
-		astman_send_error(s, m, "No resource lists found\n");
-		return 0;
-	}
-
-	astman_send_listack(s, m, "A listing of resource lists follows, "
-			    "presented as ResourceListDetail events", "start");
-
-	ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami);
-
-	astman_append(s,
-		      "Event: ResourceListDetailComplete\r\n"
-		      "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", num);
-	return 0;
-}
-
-#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
-#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
-
-static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct subscription_persistence *persistence = obj;
-
-	persistence->endpoint = ast_strdup(var->value);
-	return 0;
-}
-
-static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct subscription_persistence *persistence = obj;
-
-	*buf = ast_strdup(persistence->endpoint);
-	return 0;
-}
-
-static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct subscription_persistence *persistence = obj;
-
-	persistence->tag = ast_strdup(var->value);
-	return 0;
-}
-
-static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct subscription_persistence *persistence = obj;
-
-	*buf = ast_strdup(persistence->tag);
-	return 0;
-}
-
-static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct subscription_persistence *persistence = obj;
-	return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
-}
-
-static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct subscription_persistence *persistence = obj;
-	return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
-}
-
-#define RESOURCE_LIST_INIT_SIZE 4
-
-static void resource_list_destructor(void *obj)
-{
-	struct resource_list *list = obj;
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
-		ast_free((char *) AST_VECTOR_GET(&list->items, i));
-	}
-
-	AST_VECTOR_FREE(&list->items);
-}
-
-static void *resource_list_alloc(const char *name)
-{
-	struct resource_list *list;
-
-	list = ast_sorcery_generic_alloc(sizeof(*list), resource_list_destructor);
-	if (!list) {
-		return NULL;
-	}
-
-	if (AST_VECTOR_INIT(&list->items, RESOURCE_LIST_INIT_SIZE)) {
-		ao2_cleanup(list);
-		return NULL;
-	}
-
-	return list;
-}
-
-static int item_in_vector(const struct resource_list *list, const char *item)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
-		if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static int list_item_handler(const struct aco_option *opt,
-		struct ast_variable *var, void *obj)
-{
-	struct resource_list *list = obj;
-	char *items = ast_strdupa(var->value);
-	char *item;
-
-	while ((item = strsep(&items, ","))) {
-		if (item_in_vector(list, item)) {
-			ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
-			continue;
-		}
-		if (AST_VECTOR_APPEND(&list->items, ast_strdup(item))) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct resource_list *list = obj;
-	int i;
-	struct ast_str *str = ast_str_create(32);
-
-	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
-		ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
-	}
-
-	/* Chop off trailing comma */
-	ast_str_truncate(str, -1);
-	*buf = ast_strdup(ast_str_buffer(str));
-	ast_free(str);
-	return 0;
-}
-
-static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
-{
-	struct resource_list *list = obj;
-
-	if (ast_strlen_zero(list->event)) {
-		ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
-				ast_sorcery_object_get_id(list));
-		return -1;
-	}
-
-	if (AST_VECTOR_SIZE(&list->items) == 0) {
-		ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
-				ast_sorcery_object_get_id(list));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int apply_list_configuration(struct ast_sorcery *sorcery)
-{
-	ast_sorcery_apply_default(sorcery, "resource_list", "config",
-			"pjsip.conf,criteria=type=resource_list");
-	if (ast_sorcery_object_register(sorcery, "resource_list", resource_list_alloc,
-				NULL, resource_list_apply_handler)) {
-		return -1;
-	}
-
-	ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
-			OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
-			OPT_CHAR_ARRAY_T, 1, CHARFLDSET(struct resource_list, event));
-	ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
-			OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
-	ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
-			"0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
-	ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
-			"", list_item_handler, list_item_to_str, NULL, 0, 0);
-
-	ast_sorcery_reload_object(sorcery, "resource_list");
-
-	return 0;
-}
-
-#ifdef TEST_FRAMEWORK
-
-/*!
- * \brief "bad" resources
- *
- * These are resources that the test handler will reject subscriptions to.
- */
-const char *bad_resources[] = {
-	"coconut",
-	"cilantro",
-	"olive",
-	"cheese",
-};
-
-/*!
- * \brief new_subscribe callback for unit tests
- *
- * Will give a 200 OK response to any resource except the "bad" ones.
- */
-static int test_new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_LEN(bad_resources); ++i) {
-		if (!strcmp(resource, bad_resources[i])) {
-			return 400;
-		}
-	}
-
-	return 200;
-}
-
-/*!
- * \brief Subscription notifier for unit tests.
- *
- * Since unit tests are only concerned with building a resource tree,
- * only the new_subscribe callback needs to be defined.
- */
-struct ast_sip_notifier test_notifier = {
-	.new_subscribe = test_new_subscribe,
-};
-
-/*!
- * \brief Subscription handler for unit tests.
- */
-struct ast_sip_subscription_handler test_handler = {
-	.event_name = "test",
-	.notifier = &test_notifier,
-};
-
-/*!
- * \brief Set properties on an allocated resource list
- *
- * \param list The list to set details on.
- * \param event The list's event.
- * \param resources Array of resources to add to the list.
- * \param num_resources Number of resources in the array.
- * \retval 0 Success
- * \retval non-zero Failure
- */
-static int populate_list(struct resource_list *list, const char *event, const char **resources, size_t num_resources)
-{
-	int i;
-
-	ast_copy_string(list->event, event, sizeof(list->event));
-
-	for (i = 0; i < num_resources; ++i) {
-		if (AST_VECTOR_APPEND(&list->items, ast_strdup(resources[i]))) {
-			return -1;
-		}
-	}
-	return 0;
-}
-
-/*!
- * \brief RAII callback to destroy a resource list
- */
-static void cleanup_resource_list(struct resource_list *list)
-{
-	if (!list) {
-		return;
-	}
-
-	ast_sorcery_delete(ast_sip_get_sorcery(), list);
-	ao2_cleanup(list);
-}
-
-/*!
- * \brief allocate a resource list, store it in sorcery, and set its details
- *
- * \param test The unit test. Used for logging status messages.
- * \param list_name The name of the list to create.
- * \param event The event the list services
- * \param resources Array of resources to apply to the list
- * \param num_resources The number of resources in the array
- * \retval NULL Failed to allocate or populate list
- * \retval non-NULL The created list
- */
-static struct resource_list *create_resource_list(struct ast_test *test,
-		const char *list_name, const char *event, const char **resources, size_t num_resources)
-{
-	struct resource_list *list;
-
-	list = ast_sorcery_alloc(ast_sip_get_sorcery(), "resource_list", list_name);
-	if (!list) {
-		ast_test_status_update(test, "Could not allocate resource list in sorcery\n");
-		return NULL;
-	}
-
-	if (ast_sorcery_create(ast_sip_get_sorcery(), list)) {
-		ast_test_status_update(test, "Could not store the resource list in sorcery\n");
-		ao2_cleanup(list);
-		return NULL;
-	}
-
-	if (populate_list(list, event, resources, num_resources)) {
-		ast_test_status_update(test, "Could not add resources to the resource list\n");
-		cleanup_resource_list(list);
-		return NULL;
-	}
-
-	return list;
-}
-
-/*!
- * \brief Check the integrity of a tree node against a set of resources.
- *
- * The tree node's resources must be in the same order as the resources in
- * the supplied resources array. Because of this constraint, tests can misrepresent
- * the size of the resources array as being smaller than it really is if resources
- * at the end of the array should not be present in the tree node.
- *
- * \param test The unit test. Used for printing status messages.
- * \param node The constructed tree node whose integrity is under question.
- * \param resources Array of expected resource values
- * \param num_resources The number of resources to check in the array.
- */
-static int check_node(struct ast_test *test, struct tree_node *node,
-		const char **resources, size_t num_resources)
-{
-	int i;
-
-	if (AST_VECTOR_SIZE(&node->children) != num_resources) {
-		ast_test_status_update(test, "Unexpected number of resources in tree. Expected %zu, got %zu\n",
-				num_resources, AST_VECTOR_SIZE(&node->children));
-		return -1;
-	}
-
-	for (i = 0; i < num_resources; ++i) {
-		if (strcmp(resources[i], AST_VECTOR_GET(&node->children, i)->resource)) {
-			ast_test_status_update(test, "Mismatched resources. Expected '%s' but got '%s'\n",
-					resources[i], AST_VECTOR_GET(&node->children, i)->resource);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \brief RAII_VAR callback to destroy an allocated resource tree
- */
-static void test_resource_tree_destroy(struct resource_tree *tree)
-{
-	resource_tree_destroy(tree);
-	ast_free(tree);
-}
-
-static int ineligible_configuration(void)
-{
-	struct ast_config *config;
-	struct ast_flags flags = {0,};
-	const char *value;
-
-	config = ast_config_load("sorcery.conf", flags);
-	if (!config) {
-		return 1;
-	}
-
-	value = ast_variable_retrieve(config, "res_pjsip_pubsub", "resource_list");
-	if (ast_strlen_zero(value)) {
-		ast_config_destroy(config);
-		return 1;
-	}
-
-	if (strcasecmp(value, "memory") && strcasecmp(value, "astdb")) {
-		ast_config_destroy(config);
-		return 1;
-	}
-
-	return 0;
-}
-
-AST_TEST_DEFINE(resource_tree)
-{
-	RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources[] = {
-		"huey",
-		"dewey",
-		"louie",
-	};
-	int resp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "resource_tree";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Basic resource tree integrity check";
-		info->description =
-			"Create a resource list and ensure that our attempt to build a tree works as expected.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
-	if (!list) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (check_node(test, tree->root, resources, ARRAY_LEN(resources))) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(complex_resource_tree)
-{
-	RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources_1[] = {
-		"huey",
-		"dewey",
-		"louie",
-		"dwarves",
-	};
-	const char *resources_2[] = {
-		"happy",
-		"grumpy",
-		"doc",
-		"bashful",
-		"dopey",
-		"sneezy",
-		"sleepy",
-	};
-	int resp;
-	struct tree_node *node;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "complex_resource_tree";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Complex resource tree integrity check";
-		info->description =
-			"Create a complex resource list and ensure that our attempt to build a tree works as expected.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
-	if (!list_1) {
-		return AST_TEST_FAIL;
-	}
-
-	list_2 = create_resource_list(test, "dwarves", "test", resources_2, ARRAY_LEN(resources_2));
-	if (!list_2) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	node = tree->root;
-	if (check_node(test, node, resources_1, ARRAY_LEN(resources_1))) {
-		return AST_TEST_FAIL;
-	}
-
-	/* The embedded list is at index 3 in the root node's children */
-	node = AST_VECTOR_GET(&node->children, 3);
-	if (check_node(test, node, resources_2, ARRAY_LEN(resources_2))) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bad_resource)
-{
-	RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources[] = {
-		"huey",
-		"dewey",
-		"louie",
-		"coconut", /* A "bad" resource */
-	};
-	int resp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bad_resource";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Ensure bad resources do not end up in the tree";
-		info->description =
-			"Create a resource list with a single bad resource. Ensure the bad resource does not end up in the tree.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
-	if (!list) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* We check against all but the final resource since we expect it not to be in the tree */
-	if (check_node(test, tree->root, resources, ARRAY_LEN(resources) - 1)) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-
-}
-
-AST_TEST_DEFINE(bad_branch)
-{
-	RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources_1[] = {
-		"huey",
-		"dewey",
-		"louie",
-		"gross",
-	};
-	/* This list has nothing but bad resources */
-	const char *resources_2[] = {
-		"coconut",
-		"cilantro",
-		"olive",
-		"cheese",
-	};
-	int resp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bad_branch";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Ensure bad branches are pruned from the tree";
-		info->description =
-			"Create a resource list that makes a tree with an entire branch of bad resources.\n"
-			"Ensure the bad branch is pruned from the tree.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
-	if (!list_1) {
-		return AST_TEST_FAIL;
-	}
-	list_2 = create_resource_list(test, "gross", "test", resources_2, ARRAY_LEN(resources_2));
-	if (!list_2) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* We check against all but the final resource of the list since the entire branch should
-	 * be pruned from the tree
-	 */
-	if (check_node(test, tree->root, resources_1, ARRAY_LEN(resources_1) - 1)) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-
-}
-
-AST_TEST_DEFINE(duplicate_resource)
-{
-	RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources_1[] = {
-		"huey",
-		"ducks",
-		"dewey",
-		"louie",
-	};
-	const char *resources_2[] = {
-		"donald",
-		"daisy",
-		"scrooge",
-		"dewey",
-		"louie",
-		"huey",
-	};
-	int resp;
-	struct tree_node *node;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "duplicate_resource";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Ensure duplicated resources do not end up in the tree";
-		info->description =
-			"Create a resource list with a single duplicated resource. Ensure the duplicated resource does not end up in the tree.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
-	if (!list_1) {
-		return AST_TEST_FAIL;
-	}
-
-	list_2 = create_resource_list(test, "ducks", "test", resources_2, ARRAY_LEN(resources_2));
-	if (!list_2) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	node = tree->root;
-	/* This node should have "huey" and "ducks". "dewey" and "louie" should not
-	 * be present since they were found in the "ducks" list.
-	 */
-	if (check_node(test, node, resources_1, ARRAY_LEN(resources_1) - 2)) {
-		return AST_TEST_FAIL;
-	}
-
-	/* This node should have "donald", "daisy", "scrooge", "dewey", and "louie".
-	 * "huey" is not here since that was already encountered in the parent list
-	 */
-	node = AST_VECTOR_GET(&node->children, 1);
-	if (check_node(test, node, resources_2, ARRAY_LEN(resources_2) - 1)) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(loop)
-{
-	RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources_1[] = {
-		"derp",
-	};
-	const char *resources_2[] = {
-		"herp",
-	};
-	int resp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "loop";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Test that loops are properly detected.";
-		info->description =
-			"Create two resource lists that refer to each other. Ensure that attempting to build a tree\n"
-			"results in an empty tree.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list_1 = create_resource_list(test, "herp", "test", resources_1, ARRAY_LEN(resources_1));
-	if (!list_1) {
-		return AST_TEST_FAIL;
-	}
-	list_2 = create_resource_list(test, "derp", "test", resources_2, ARRAY_LEN(resources_2));
-	if (!list_2) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	resp = build_resource_tree(NULL, &test_handler, "herp", tree, 1);
-	if (resp == 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bad_event)
-{
-	RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
-	RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
-	const char *resources[] = {
-		"huey",
-		"dewey",
-		"louie",
-	};
-	int resp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bad_event";
-		info->category = "/res/res_pjsip_pubsub/";
-		info->summary = "Ensure that list with wrong event specified is not retrieved";
-		info->description =
-			"Create a simple resource list for event 'tsetse'. Ensure that trying to retrieve the list for event 'test' fails.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ineligible_configuration()) {
-		ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
-				"'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	list = create_resource_list(test, "foo", "tsetse", resources, ARRAY_LEN(resources));
-	if (!list) {
-		return AST_TEST_FAIL;
-	}
-
-	tree = ast_calloc(1, sizeof(*tree));
-	/* Since the test_handler is for event "test", this should not build a list, but
-	 * instead result in a single resource being created, called "foo"
-	 */
-	resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
-	if (resp != 200) {
-		ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
-		return AST_TEST_FAIL;
-	}
-
-	if (!tree->root) {
-		ast_test_status_update(test, "Resource tree has no root\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(tree->root->resource, "foo")) {
-		ast_test_status_update(test, "Unexpected resource %s found in tree\n", tree->root->resource);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-#endif
-
-static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_publication_resource *resource = obj;
-
-	ast_free(resource->endpoint);
-	resource->endpoint = ast_strdup(var->value);
-
-	return 0;
-}
-
-static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_publication_resource *resource = obj;
-	/* The event configuration name starts with 'event_' so skip past it to get the real name */
-	const char *event = var->name + 6;
-	struct ast_variable *item;
-
-	if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
-		return -1;
-	}
-
-	item = ast_variable_new(event, var->value, "");
-	if (!item) {
-		return -1;
-	}
-
-	if (resource->events) {
-		item->next = resource->events;
-	}
-	resource->events = item;
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
-	struct ast_sorcery *sorcery;
-
-	CHECK_PJSIP_MODULE_LOADED();
-
-	sorcery = ast_sip_get_sorcery();
-
-	pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint());
-
-	if (!(sched = ast_sched_context_create())) {
-		ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (ast_sched_start_thread(sched)) {
-		ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
-		ast_sched_context_destroy(sched);
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH);
-
-	if (ast_sip_register_service(&pubsub_module)) {
-		ast_log(LOG_ERROR, "Could not register pubsub service\n");
-		ast_sched_context_destroy(sched);
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
-	ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
-	if (ast_sorcery_object_register(sorcery, "subscription_persistence", subscription_persistence_alloc,
-		NULL, NULL)) {
-		ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
-		ast_sip_unregister_service(&pubsub_module);
-		ast_sched_context_destroy(sched);
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
-		CHARFLDSET(struct subscription_persistence, packet));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
-		CHARFLDSET(struct subscription_persistence, src_name));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
-		FLDSET(struct subscription_persistence, src_port));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
-		CHARFLDSET(struct subscription_persistence, transport_key));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
-		CHARFLDSET(struct subscription_persistence, local_name));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
-		FLDSET(struct subscription_persistence, local_port));
-	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
-		FLDSET(struct subscription_persistence, cseq));
-	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
-		persistence_endpoint_str2struct, persistence_endpoint_struct2str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
-		persistence_tag_str2struct, persistence_tag_struct2str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
-		persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0);
-
-	if (apply_list_configuration(sorcery)) {
-		ast_sip_unregister_service(&pubsub_module);
-		ast_sched_context_destroy(sched);
-	}
-
-	ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
-	if (ast_sorcery_object_register(sorcery, "inbound-publication", publication_resource_alloc,
-		NULL, NULL)) {
-		ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
-		ast_sip_unregister_service(&pubsub_module);
-		ast_sched_context_destroy(sched);
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
-		resource_endpoint_handler, NULL, NULL, 0, 0);
-	ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
-	ast_sorcery_reload_object(sorcery, "inbound-publication");
-
-	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
-		ast_sip_push_task(NULL, subscription_persistence_load, NULL);
-	} else {
-		stasis_subscribe_pool(ast_manager_get_topic(), subscription_persistence_event_cb, NULL);
-	}
-
-	ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_INBOUND, EVENT_FLAG_SYSTEM,
-				 ami_show_subscriptions_inbound);
-	ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, EVENT_FLAG_SYSTEM,
-				 ami_show_subscriptions_outbound);
-	ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
-			ami_show_resource_lists);
-
-	AST_TEST_REGISTER(resource_tree);
-	AST_TEST_REGISTER(complex_resource_tree);
-	AST_TEST_REGISTER(bad_resource);
-	AST_TEST_REGISTER(bad_branch);
-	AST_TEST_REGISTER(duplicate_resource);
-	AST_TEST_REGISTER(loop);
-	AST_TEST_REGISTER(bad_event);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
-	ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
-	ast_manager_unregister("PJSIPShowResourceLists");
-
-	if (sched) {
-		ast_sched_context_destroy(sched);
-	}
-
-	AST_TEST_UNREGISTER(resource_tree);
-	AST_TEST_UNREGISTER(complex_resource_tree);
-	AST_TEST_UNREGISTER(bad_resource);
-	AST_TEST_UNREGISTER(bad_branch);
-	AST_TEST_UNREGISTER(duplicate_resource);
-	AST_TEST_UNREGISTER(loop);
-	AST_TEST_UNREGISTER(bad_event);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP event resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pjsip_pubsub.exports.in b/res/res_pjsip_pubsub.exports.in
deleted file mode 100644
index 2a6b75f..0000000
--- a/res/res_pjsip_pubsub.exports.in
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_sip_create_subscription;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_endpoint;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_serializer;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_evsub;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_dlg;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_accept;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_send_request;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_alloc_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_add_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_remove_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_register_subscription_handler;
-		LINKER_SYMBOL_PREFIXast_sip_unregister_subscription_handler;
-		LINKER_SYMBOL_PREFIXast_sip_create_publication;
-		LINKER_SYMBOL_PREFIXast_sip_publication_get_endpoint;
-		LINKER_SYMBOL_PREFIXast_sip_publication_get_resource;
-		LINKER_SYMBOL_PREFIXast_sip_publication_get_event_configuration;
-		LINKER_SYMBOL_PREFIXast_sip_publication_create_response;
-		LINKER_SYMBOL_PREFIXast_sip_publication_send_response;
-		LINKER_SYMBOL_PREFIXast_sip_register_publish_handler;
-		LINKER_SYMBOL_PREFIXast_sip_unregister_publish_handler;
-		LINKER_SYMBOL_PREFIXast_sip_publication_add_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_publication_get_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_generator;
-		LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_generator;
-		LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_supplement;
-		LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_supplement;
-		LINKER_SYMBOL_PREFIXast_sip_pubsub_generate_body_content;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_type;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_subtype;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_resource_name;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_notify;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_local_uri;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_remote_uri;
-		LINKER_SYMBOL_PREFIXast_sip_subscription_get_header;
-	local:
-		*;
-};
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
deleted file mode 100644
index 1cbbbc0..0000000
--- a/res/res_pjsip_refer.c
+++ /dev/null
@@ -1,1043 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/bridge.h"
-#include "asterisk/framehook.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-
-/*! \brief REFER Progress structure */
-struct refer_progress {
-	/*! \brief Subscription to provide updates on */
-	pjsip_evsub *sub;
-	/*! \brief Dialog for subscription */
-	pjsip_dialog *dlg;
-	/*! \brief Received packet, used to construct final response in case no subscription exists */
-	pjsip_rx_data *rdata;
-	/*! \brief Frame hook for monitoring REFER progress */
-	int framehook;
-	/*! \brief Last received subclass in frame hook */
-	int subclass;
-	/*! \brief Serializer for notifications */
-	struct ast_taskprocessor *serializer;
-	/*! \brief Stasis subscription for bridge events */
-	struct stasis_subscription *bridge_sub;
-	/*! \brief Reference to transfer_channel_data related to the refer */
-	struct transfer_channel_data *transfer_data;
-	/*! \brief Uniqueid of transferee channel */
-	char *transferee;
-};
-
-/*! \brief REFER Progress notification structure */
-struct refer_progress_notification {
-	/*! \brief Refer progress structure to send notification on */
-	struct refer_progress *progress;
-	/*! \brief SIP response code to send */
-	int response;
-	/*! \brief Subscription state */
-	pjsip_evsub_state state;
-};
-
-/*! \brief REFER Progress module, used to attach REFER progress structure to subscriptions */
-static pjsip_module refer_progress_module = {
-	.name = { "REFER Progress", 14 },
-	.id = -1,
-};
-
-/*! \brief Destructor for REFER Progress notification structure */
-static void refer_progress_notification_destroy(void *obj)
-{
-	struct refer_progress_notification *notification = obj;
-
-	ao2_cleanup(notification->progress);
-}
-
-/*! \brief Allocator for REFER Progress notification structure */
-static struct refer_progress_notification *refer_progress_notification_alloc(struct refer_progress *progress, int response,
-	pjsip_evsub_state state)
-{
-	struct refer_progress_notification *notification = ao2_alloc(sizeof(*notification), refer_progress_notification_destroy);
-
-	if (!notification) {
-		return NULL;
-	}
-
-	ao2_ref(progress, +1);
-	notification->progress = progress;
-	notification->response = response;
-	notification->state = state;
-
-	return notification;
-}
-
-/*! \brief Serialized callback for subscription notification */
-static int refer_progress_notify(void *data)
-{
-	RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
-	pjsip_evsub *sub;
-	pjsip_tx_data *tdata;
-
-	/* If the subscription has already been terminated we can't send a notification */
-	if (!(sub = notification->progress->sub)) {
-		ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
-			notification->response, notification->state, notification->progress);
-		return 0;
-	}
-
-	/* If the subscription is being terminated we want to actually remove the progress structure here to
-	 * stop a deadlock from occurring - basically terminated changes the state which queues a synchronous task
-	 * but we are already running a task... thus it would deadlock */
-	if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
-		ast_debug(3, "Subscription '%p' is being terminated as a result of a NOTIFY, removing REFER progress structure early on progress monitor '%p'\n",
-			notification->progress->sub, notification->progress);
-		pjsip_dlg_inc_lock(notification->progress->dlg);
-		pjsip_evsub_set_mod_data(notification->progress->sub, refer_progress_module.id, NULL);
-		pjsip_dlg_dec_lock(notification->progress->dlg);
-
-		/* This is for dropping the reference on the subscription */
-		ao2_cleanup(notification->progress);
-
-		notification->progress->sub = NULL;
-	}
-
-	ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n",
-		notification->response, notification->state, sub, notification->progress);
-
-	/* Actually send the notification */
-	if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
-		pjsip_xfer_send_request(sub, tdata);
-	}
-
-	return 0;
-}
-
-static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
-		struct stasis_message *message)
-{
-	struct refer_progress *progress = data;
-	struct ast_bridge_blob *enter_blob;
-	struct refer_progress_notification *notification;
-	struct ast_channel *chan;
-
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_ref(progress, -1);
-		return;
-	}
-
-	if (ast_channel_entered_bridge_type() != stasis_message_type(message)) {
-		/* Don't care */
-		return;
-	}
-
-	enter_blob = stasis_message_data(message);
-	if (strcmp(enter_blob->channel->uniqueid, progress->transferee)) {
-		/* Don't care */
-		return;
-	}
-
-	if (!progress->transfer_data->completed) {
-		/* We can't act on this message because the transfer_channel_data doesn't show that
-		 * the transfer is ready to progress */
-		return;
-	}
-
-	/* OMG the transferee is joining a bridge. His call got answered! */
-	notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
-	if (notification) {
-		if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
-			ao2_cleanup(notification);
-		}
-		progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
-	}
-
-	chan = ast_channel_get_by_name(progress->transferee);
-	if (!chan) {
-		/* The channel is already gone */
-		return;
-	}
-
-	ast_channel_lock(chan);
-	ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as it has joined a bridge\n",
-		ast_channel_name(chan));
-	ast_framehook_detach(chan, progress->framehook);
-	ast_channel_unlock(chan);
-
-	ast_channel_unref(chan);
-}
-
-/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
-static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
-{
-	struct refer_progress *progress = data;
-	struct refer_progress_notification *notification = NULL;
-
-	/* We only care about frames *to* the channel */
-	if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
-		return f;
-	}
-
-	/* If the completed flag hasn't been raised, skip this pass. */
-	if (!progress->transfer_data->completed) {
-		return f;
-	}
-
-	/* Determine the state of the REFER based on the control frames (or voice frames) passing */
-	if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
-		/* Media is passing without progress, this means the call has been answered */
-		notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
-	} else if (f->frametype == AST_FRAME_CONTROL) {
-		/* Based on the control frame being written we can send a NOTIFY advising of the progress */
-		if ((f->subclass.integer == AST_CONTROL_RING) || (f->subclass.integer == AST_CONTROL_RINGING)) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 180, PJSIP_EVSUB_STATE_ACTIVE);
-		} else if (f->subclass.integer == AST_CONTROL_BUSY) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 486, PJSIP_EVSUB_STATE_TERMINATED);
-		} else if (f->subclass.integer == AST_CONTROL_CONGESTION) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
-		} else if (f->subclass.integer == AST_CONTROL_PROGRESS) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 183, PJSIP_EVSUB_STATE_ACTIVE);
-		} else if (f->subclass.integer == AST_CONTROL_PROCEEDING) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 100, PJSIP_EVSUB_STATE_ACTIVE);
-		} else if (f->subclass.integer == AST_CONTROL_ANSWER) {
-			progress->subclass = f->subclass.integer;
-			notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
-		}
-	}
-
-	/* If a notification is due to be sent push it to the thread pool */
-	if (notification) {
-		if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
-			ao2_cleanup(notification);
-		}
-
-		/* If the subscription is being terminated we don't need the frame hook any longer */
-		if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
-			ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
-				ast_channel_name(chan));
-			ast_framehook_detach(chan, progress->framehook);
-		}
-	}
-
-	return f;
-}
-
-/*! \brief Destroy callback for monitoring framehook */
-static void refer_progress_framehook_destroy(void *data)
-{
-	struct refer_progress *progress = data;
-	struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
-
-	if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
-		ao2_cleanup(notification);
-	}
-
-	if (progress->bridge_sub) {
-		progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
-	}
-
-	ao2_cleanup(progress);
-}
-
-/*! \brief Serialized callback for subscription termination */
-static int refer_progress_terminate(void *data)
-{
-	struct refer_progress *progress = data;
-
-	/* The subscription is no longer valid */
-	progress->sub = NULL;
-
-	return 0;
-}
-
-/*! \brief Callback for REFER subscription state changes */
-static void refer_progress_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
-{
-	struct refer_progress *progress = pjsip_evsub_get_mod_data(sub, refer_progress_module.id);
-
-	/* If being destroyed queue it up to the serializer */
-	if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
-		/* To prevent a deadlock race condition we unlock the dialog so other serialized tasks can execute */
-		ast_debug(3, "Subscription '%p' has been remotely terminated, waiting for other tasks to complete on progress monitor '%p'\n",
-			sub, progress);
-
-		/* It's possible that a task is waiting to remove us already, so bump the refcount of progress so it doesn't get destroyed */
-		ao2_ref(progress, +1);
-		pjsip_dlg_dec_lock(progress->dlg);
-		ast_sip_push_task_synchronous(progress->serializer, refer_progress_terminate, progress);
-		pjsip_dlg_inc_lock(progress->dlg);
-		ao2_ref(progress, -1);
-
-		ast_debug(3, "Subscription '%p' removed from progress monitor '%p'\n", sub, progress);
-
-		/* Since it was unlocked it is possible for this to have been removed already, so check again */
-		if (pjsip_evsub_get_mod_data(sub, refer_progress_module.id)) {
-			pjsip_evsub_set_mod_data(sub, refer_progress_module.id, NULL);
-			ao2_cleanup(progress);
-		}
-	}
-}
-
-/*! \brief Callback structure for subscription */
-static pjsip_evsub_user refer_progress_evsub_cb = {
-	.on_evsub_state = refer_progress_on_evsub_state,
-};
-
-/*! \brief Destructor for REFER progress sutrcture */
-static void refer_progress_destroy(void *obj)
-{
-	struct refer_progress *progress = obj;
-
-	if (progress->bridge_sub) {
-		progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
-	}
-
-	ao2_cleanup(progress->transfer_data);
-
-	ast_free(progress->transferee);
-	ast_taskprocessor_unreference(progress->serializer);
-}
-
-/*! \brief Internal helper function which sets up a refer progress structure if needed */
-static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata, struct refer_progress **progress)
-{
-	const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
-	pjsip_generic_string_hdr *refer_sub = NULL;
-	const pj_str_t str_true = { "true", 4 };
-	pjsip_tx_data *tdata;
-	pjsip_hdr hdr_list;
-
-	*progress = NULL;
-
-	/* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
-	refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
-	if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
-		return 0;
-	}
-
-	if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
-		return -1;
-	}
-
-	ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
-		progress, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-
-	(*progress)->framehook = -1;
-
-	/* To prevent a potential deadlock we need the dialog so we can lock/unlock */
-	(*progress)->dlg = session->inv_session->dlg;
-
-	if (!((*progress)->serializer = ast_sip_create_serializer())) {
-		goto error;
-	}
-
-	/* Create the implicit subscription for monitoring of this transfer */
-	if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
-		goto error;
-	}
-
-	/* Associate the REFER progress structure with the subscription */
-	ao2_ref(*progress, +1);
-	pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
-
-	pj_list_init(&hdr_list);
-	if (refer_sub) {
-		pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
-
-		pj_list_push_back(&hdr_list, hdr);
-	}
-
-	/* Accept the REFER request */
-	ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
-	pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
-
-	/* Send initial NOTIFY Request */
-	ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n", *progress);
-	if (pjsip_xfer_notify((*progress)->sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
-		pjsip_xfer_send_request((*progress)->sub, tdata);
-	}
-
-	return 0;
-
-error:
-	ao2_cleanup(*progress);
-	*progress = NULL;
-	return -1;
-}
-
-/*! \brief Structure for attended transfer task */
-struct refer_attended {
-	/*! \brief Transferer session */
-	struct ast_sip_session *transferer;
-	/*! \brief Transferer channel */
-	struct ast_channel *transferer_chan;
-	/*! \brief Second transferer session */
-	struct ast_sip_session *transferer_second	;
-	/*! \brief Optional refer progress structure */
-	struct refer_progress *progress;
-};
-
-/*! \brief Destructor for attended transfer task */
-static void refer_attended_destroy(void *obj)
-{
-	struct refer_attended *attended = obj;
-
-	ao2_cleanup(attended->transferer);
-	ast_channel_unref(attended->transferer_chan);
-	ao2_cleanup(attended->transferer_second);
-}
-
-/*! \brief Allocator for attended transfer task */
-static struct refer_attended *refer_attended_alloc(struct ast_sip_session *transferer, struct ast_sip_session *transferer_second,
-	struct refer_progress *progress)
-{
-	struct refer_attended *attended = ao2_alloc(sizeof(*attended), refer_attended_destroy);
-
-	if (!attended) {
-		return NULL;
-	}
-
-	ao2_ref(transferer, +1);
-	attended->transferer = transferer;
-	ast_channel_ref(transferer->channel);
-	attended->transferer_chan = transferer->channel;
-	ao2_ref(transferer_second, +1);
-	attended->transferer_second = transferer_second;
-
-	if (progress) {
-		ao2_ref(progress, +1);
-		attended->progress = progress;
-	}
-
-	return attended;
-}
-
-/*! \brief Task for attended transfer */
-static int refer_attended(void *data)
-{
-	RAII_VAR(struct refer_attended *, attended, data, ao2_cleanup);
-	int response = 0;
-
-	if (!attended->transferer_second->channel) {
-		return -1;
-	}
-
-	ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
-		ast_channel_name(attended->transferer_chan), ast_channel_name(attended->transferer_second->channel));
-
-	switch (ast_bridge_transfer_attended(attended->transferer_chan, attended->transferer_second->channel)) {
-	case AST_BRIDGE_TRANSFER_INVALID:
-		response = 400;
-		break;
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-		response = 403;
-		break;
-	case AST_BRIDGE_TRANSFER_FAIL:
-		response = 500;
-		break;
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		response = 200;
-		ast_sip_session_defer_termination(attended->transferer);
-		break;
-	}
-
-	ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
-		ast_channel_name(attended->transferer_chan), ast_channel_name(attended->transferer_second->channel), response);
-
-	if (attended->progress && response) {
-		struct refer_progress_notification *notification = refer_progress_notification_alloc(attended->progress, response, PJSIP_EVSUB_STATE_TERMINATED);
-
-		if (notification) {
-			refer_progress_notify(notification);
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Structure for blind transfer callback details */
-struct refer_blind {
-	/*! \brief Context being used for transfer */
-	const char *context;
-	/*! \brief Optional progress structure */
-	struct refer_progress *progress;
-	/*! \brief REFER message */
-	pjsip_rx_data *rdata;
-	/*! \brief Optional Replaces header */
-	pjsip_replaces_hdr *replaces;
-	/*! \brief Optional Refer-To header */
-	pjsip_sip_uri *refer_to;
-};
-
-/*! \brief Blind transfer callback function */
-static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
-	enum ast_transfer_type transfer_type)
-{
-	struct refer_blind *refer = user_data_wrapper->data;
-	pjsip_generic_string_hdr *referred_by;
-
-	static const pj_str_t str_referred_by = { "Referred-By", 11 };
-
-	pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
-
-	/* If progress monitoring is being done attach a frame hook so we can monitor it */
-	if (refer->progress) {
-		struct ast_framehook_interface hook = {
-			.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-			.event_cb = refer_progress_framehook,
-			.destroy_cb = refer_progress_framehook_destroy,
-			.data = refer->progress,
-			.disable_inheritance = 1,
-		};
-
-		refer->progress->transferee = ast_strdup(ast_channel_uniqueid(chan));
-		if (!refer->progress->transferee) {
-			struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
-				PJSIP_EVSUB_STATE_TERMINATED);
-
-			ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
-				ast_channel_name(chan));
-
-			if (notification) {
-				refer_progress_notify(notification);
-			}
-		}
-
-		/* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
-		ao2_ref(user_data_wrapper, +1);
-		refer->progress->transfer_data = user_data_wrapper;
-
-		/* We need to bump the reference count up on the progress structure since it is in the frame hook now */
-		ao2_ref(refer->progress, +1);
-
-		/* If we can't attach a frame hook for whatever reason send a notification of success immediately */
-		if ((refer->progress->framehook = ast_framehook_attach(chan, &hook)) < 0) {
-			struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
-				PJSIP_EVSUB_STATE_TERMINATED);
-
-			ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
-				ast_channel_name(chan));
-
-			if (notification) {
-				refer_progress_notify(notification);
-			}
-
-			ao2_cleanup(refer->progress);
-		}
-
-		/* We need to bump the reference count for the stasis subscription */
-		ao2_ref(refer->progress, +1);
-		/* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
-		 * detect if the transfer target has answered the call
-		 */
-		refer->progress->bridge_sub = stasis_subscribe_pool(ast_bridge_topic_all(), refer_progress_bridge, refer->progress);
-		if (!refer->progress->bridge_sub) {
-			struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
-				PJSIP_EVSUB_STATE_TERMINATED);
-
-			ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
-					ast_channel_name(chan));
-
-			if (notification) {
-				refer_progress_notify(notification);
-			}
-
-			ast_framehook_detach(chan, refer->progress->framehook);
-
-			ao2_cleanup(refer->progress);
-		}
-	}
-
-	pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
-
-	referred_by = pjsip_msg_find_hdr_by_name(refer->rdata->msg_info.msg,
-		&str_referred_by, NULL);
-	if (referred_by) {
-		size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
-		char *uri = ast_alloca(uri_size);
-
-		ast_copy_pj_str(uri, &referred_by->hvalue, uri_size);
-		pbx_builtin_setvar_helper(chan, "__SIPREFERREDBYHDR", S_OR(uri, NULL));
-	} else {
-		pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", NULL);
-	}
-
-	if (refer->replaces) {
-		char replaces[512];
-
-		pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces));
-		pbx_builtin_setvar_helper(chan, "__SIPREPLACESHDR", S_OR(replaces, NULL));
-	} else {
-		pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", NULL);
-	}
-
-	if (refer->refer_to) {
-		char refer_to[PJSIP_MAX_URL_SIZE];
-
-		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
-		pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", S_OR(refer_to, NULL));
-	} else {
-		pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", NULL);
-	}
-}
-
-static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
-	pjsip_param *replaces_param, struct refer_progress *progress)
-{
-	const pj_str_t str_replaces = { "Replaces", 8 };
-	pj_str_t replaces_content;
-	pjsip_replaces_hdr *replaces;
-	int parsed_len;
-	pjsip_dialog *dlg;
-
-	pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
-
-	/* Parsing the parameter as a Replaces header easily grabs the needed information */
-	if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
-		pj_strlen(&replaces_content), &parsed_len))) {
-		ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-		return 400;
-	}
-
-	/* See if the dialog is local, or remote */
-	if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
-		RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
-		struct refer_attended *attended;
-
-		pjsip_dlg_dec_lock(dlg);
-
-		if (!other_session) {
-			ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
-				ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-			return 603;
-		}
-
-		/* We defer actually doing the attended transfer to the other session so no deadlock can occur */
-		if (!(attended = refer_attended_alloc(session, other_session, progress))) {
-			ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not allocate structure to complete, rejecting\n",
-				ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-			return 500;
-		}
-
-		/* Push it to the other session, which will have both channels with minimal locking */
-		if (ast_sip_push_task(other_session->serializer, refer_attended, attended)) {
-			ao2_cleanup(attended);
-			return 500;
-		}
-
-		ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
-			ast_channel_name(session->channel));
-
-		return 200;
-	} else {
-		const char *context = (session->channel ? pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT") : "");
-		struct refer_blind refer = { 0, };
-
-		if (ast_strlen_zero(context)) {
-			context = session->endpoint->context;
-		}
-
-		if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
-			ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but 'external_replaces' context does not exist for handling\n",
-				ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-			return 404;
-		}
-
-		refer.context = context;
-		refer.progress = progress;
-		refer.rdata = rdata;
-		refer.replaces = replaces;
-		refer.refer_to = target_uri;
-
-		switch (ast_bridge_transfer_blind(1, session->channel, "external_replaces", context, refer_blind_callback, &refer)) {
-		case AST_BRIDGE_TRANSFER_INVALID:
-			return 400;
-		case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-			return 403;
-		case AST_BRIDGE_TRANSFER_FAIL:
-			return 500;
-		case AST_BRIDGE_TRANSFER_SUCCESS:
-			ast_sip_session_defer_termination(session);
-			return 200;
-		}
-
-		return 503;
-	}
-
-	return 0;
-}
-
-static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
-	struct refer_progress *progress)
-{
-	const char *context;
-	char exten[AST_MAX_EXTENSION];
-	struct refer_blind refer = { 0, };
-
-	if (!session->channel) {
-		return 404;
-	}
-
-	/* If no explicit transfer context has been provided use their configured context */
-	context = pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT");
-	if (ast_strlen_zero(context)) {
-		context = session->endpoint->context;
-	}
-
-	/* Using the user portion of the target URI see if it exists as a valid extension in their context */
-	ast_copy_pj_str(exten, &target->user, sizeof(exten));
-	if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
-		ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
-		return 404;
-	}
-
-	refer.context = context;
-	refer.progress = progress;
-	refer.rdata = rdata;
-	refer.refer_to = target;
-
-	switch (ast_bridge_transfer_blind(1, session->channel, exten, context, refer_blind_callback, &refer)) {
-	case AST_BRIDGE_TRANSFER_INVALID:
-		return 400;
-	case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
-		return 403;
-	case AST_BRIDGE_TRANSFER_FAIL:
-		return 500;
-	case AST_BRIDGE_TRANSFER_SUCCESS:
-		ast_sip_session_defer_termination(session);
-		return 200;
-	}
-
-	return 503;
-}
-
-/*! \brief Structure used to retrieve channel from another session */
-struct invite_replaces {
-	/*! \brief Session we want the channel from */
-	struct ast_sip_session *session;
-	/*! \brief Channel from the session (with reference) */
-	struct ast_channel *channel;
-	/*! \brief Bridge the channel is in */
-	struct ast_bridge *bridge;
-};
-
-/*! \brief Task for invite replaces */
-static int invite_replaces(void *data)
-{
-	struct invite_replaces *invite = data;
-
-	if (!invite->session->channel) {
-		return -1;
-	}
-
-	ast_channel_ref(invite->session->channel);
-	invite->channel = invite->session->channel;
-
-	ast_channel_lock(invite->channel);
-	invite->bridge = ast_channel_get_bridge(invite->channel);
-	ast_channel_unlock(invite->channel);
-
-	return 0;
-}
-
-static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	pjsip_dialog *other_dlg = NULL;
-	pjsip_tx_data *packet;
-	int response = 0;
-	RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup);
-	struct invite_replaces invite;
-
-	/* If a Replaces header is present make sure it is valid */
-	if (pjsip_replaces_verify_request(rdata, &other_dlg, PJ_TRUE, &packet) != PJ_SUCCESS) {
-		response = packet->msg->line.status.code;
-		pjsip_tx_data_dec_ref(packet);
-		goto end;
-	}
-
-	/* If no other dialog exists then this INVITE request does not have a Replaces header */
-	if (!other_dlg) {
-		return 0;
-	}
-
-	other_session = ast_sip_dialog_get_session(other_dlg);
-	pjsip_dlg_dec_lock(other_dlg);
-
-	/* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */
-	if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
-		response = 488;
-		goto end;
-	}
-
-	if (!other_session) {
-		response = 481;
-		ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-		goto end;
-	}
-
-	invite.session = other_session;
-
-	if (ast_sip_push_task_synchronous(other_session->serializer, invite_replaces, &invite)) {
-		response = 481;
-		goto end;
-	}
-
-	ast_channel_lock(session->channel);
-	ast_setstate(session->channel, AST_STATE_RING);
-	ast_channel_unlock(session->channel);
-	ast_raw_answer(session->channel);
-
-	if (!invite.bridge) {
-		struct ast_channel *chan = session->channel;
-
-		/* This will use a synchronous task but we aren't operating in the serializer at this point in time, so it
-		 * won't deadlock */
-		if (!ast_channel_move(invite.channel, session->channel)) {
-			ast_hangup(chan);
-		} else {
-			response = 500;
-		}
-	} else {
-		if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL,
-			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-			response = 500;
-		}
-	}
-
-	if (!response) {
-		ast_debug(3, "INVITE with Replaces successfully completed on channels '%s' and '%s'\n",
-			ast_channel_name(session->channel), ast_channel_name(invite.channel));
-	}
-
-	ast_channel_unref(invite.channel);
-	ao2_cleanup(invite.bridge);
-
-end:
-	if (response) {
-		if (session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
-			ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
-				ast_channel_name(session->channel), response);
-			session->defer_terminate = 1;
-			ast_hangup(session->channel);
-			session->channel = NULL;
-
-			if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS) {
-				ast_sip_session_send_response(session, packet);
-			}
-		} else {
-			ast_debug(3, "INVITE with Replaces in-dialog on channel '%s', hanging up\n",
-				ast_channel_name(session->channel));
-			ast_queue_hangup(session->channel);
-		}
-	}
-
-	return 1;
-}
-
-static int refer_incoming_refer_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	pjsip_generic_string_hdr *refer_to;
-	char *uri;
-	pjsip_uri *target;
-	pjsip_sip_uri *target_uri;
-	RAII_VAR(struct refer_progress *, progress, NULL, ao2_cleanup);
-	pjsip_param *replaces;
-	int response;
-
-	static const pj_str_t str_refer_to = { "Refer-To", 8 };
-	static const pj_str_t str_replaces = { "Replaces", 8 };
-
-	if (!session->endpoint->allowtransfer) {
-		pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
-		ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
-				ast_sorcery_object_get_id(session->endpoint));
-		return 0;
-	}
-
-	/* A Refer-To header is required */
-	refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
-	if (!refer_to) {
-		pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
-		ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-		return 0;
-	}
-
-	/* This is done on purpose (and is safe) - it's done so that the value passed to
-	 * pjsip_parse_uri is NULL terminated as required
-	 */
-	uri = refer_to->hvalue.ptr;
-	uri[refer_to->hvalue.slen] = '\0';
-
-	target = pjsip_parse_uri(rdata->tp_info.pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0);
-	if (!target
-		|| (!PJSIP_URI_SCHEME_IS_SIP(target)
-			&& !PJSIP_URI_SCHEME_IS_SIPS(target))) {
-		size_t uri_size = pj_strlen(&refer_to->hvalue) + 1;
-		char *uri = ast_alloca(uri_size);
-
-		ast_copy_pj_str(uri, &refer_to->hvalue, uri_size);
-
-		pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
-		ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
-			uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-		return 0;
-	}
-	target_uri = pjsip_uri_get_uri(target);
-
-	/* Set up REFER progress subscription if requested/possible */
-	if (refer_progress_alloc(session, rdata, &progress)) {
-		pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
-		ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
-		return 0;
-	}
-
-	/* Determine if this is an attended or blind transfer */
-	if ((replaces = pjsip_param_find(&target_uri->header_param, &str_replaces)) ||
-		(replaces = pjsip_param_find(&target_uri->other_param, &str_replaces))) {
-		response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
-	} else {
-		response = refer_incoming_blind_request(session, rdata, target_uri, progress);
-	}
-
-	if (!progress) {
-		/* The transferer has requested no subscription, so send a final response immediately */
-		pjsip_tx_data *tdata;
-		const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
-		const pj_str_t str_false = { "false", 5 };
-		pjsip_hdr *hdr;
-
-		ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
-			ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
-
-		if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
-			pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
-			return 0;
-		}
-
-		hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
-		pjsip_msg_add_hdr(tdata->msg, hdr);
-
-		pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
-	} else if (response != 200) {
-		/* Since this failed we can send a final NOTIFY now and terminate the subscription */
-		struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
-
-		if (notification) {
-			/* The refer_progress_notify function will call ao2_cleanup on this for us */
-			refer_progress_notify(notification);
-		}
-	}
-
-	return 0;
-}
-
-static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
-		return refer_incoming_refer_request(session, rdata);
-	} else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_invite_method)) {
-		return refer_incoming_invite_request(session, rdata);
-	} else {
-		return 0;
-	}
-}
-
-static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	const char *hdr;
-
-	if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method)
-		|| !session->channel
-		|| session->inv_session->state != PJSIP_INV_STATE_NULL) {
-		return;
-	}
-
-	ast_channel_lock(session->channel);
-	hdr = pbx_builtin_getvar_helper(session->channel, "SIPREPLACESHDR");
-	if (!ast_strlen_zero(hdr)) {
-		ast_sip_add_header(tdata, "Replaces", hdr);
-	}
-
-	hdr = pbx_builtin_getvar_helper(session->channel, "SIPREFERREDBYHDR");
-	if (!ast_strlen_zero(hdr)) {
-		ast_sip_add_header(tdata, "Referred-By", hdr);
-	}
-	ast_channel_unlock(session->channel);
-}
-
-static struct ast_sip_session_supplement refer_supplement = {
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
-	.incoming_request = refer_incoming_request,
-	.outgoing_request = refer_outgoing_request,
-};
-
-static int load_module(void)
-{
-	const pj_str_t str_norefersub = { "norefersub", 10 };
-
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint());
-	pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint());
-	pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub);
-
-	ast_sip_register_service(&refer_progress_module);
-	ast_sip_session_register_supplement(&refer_supplement);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&refer_supplement);
-	ast_sip_unregister_service(&refer_progress_module);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Attended Transfer Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-		   );
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
deleted file mode 100644
index aad3dd4..0000000
--- a/res/res_pjsip_registrar.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/manager.h"
-#include "res_pjsip/include/res_pjsip_private.h"
-
-/*** DOCUMENTATION
-	<manager name="PJSIPShowRegistrationsInbound" language="en_US">
-		<synopsis>
-			Lists PJSIP inbound registrations.
-		</synopsis>
-		<syntax />
-		<description>
-			<para>
-			In response <literal>InboundRegistrationDetail</literal> events showing configuration and status
-			information are raised for each inbound registration object.  As well as <literal>AuthDetail</literal>
-			events for each associated auth object.  Once all events are completed an
-			<literal>InboundRegistrationDetailComplete</literal> is issued.
-                        </para>
-		</description>
-	</manager>
- ***/
-
-/*! \brief Internal function which returns the expiration time for a contact */
-static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
-{
-	pjsip_expires_hdr *expires;
-	int expiration = aor->default_expiration;
-
-	if (contact->expires != -1) {
-		/* Expiration was provided with the contact itself */
-		expiration = contact->expires;
-	} else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
-		/* Expiration was provided using the Expires header */
-		expiration = expires->ivalue;
-	}
-
-	/* If the value has explicitly been set to 0, do not enforce */
-	if (!expiration) {
-		return expiration;
-	}
-
-	/* Enforce the range that we will allow for expiration */
-	if (expiration < aor->minimum_expiration) {
-		expiration = aor->minimum_expiration;
-	} else if (expiration > aor->maximum_expiration) {
-		expiration = aor->maximum_expiration;
-	}
-
-	return expiration;
-}
-
-/*! \brief Structure used for finding contact */
-struct registrar_contact_details {
-	/*! \brief Pool used for parsing URI */
-	pj_pool_t *pool;
-	/*! \brief URI being looked for */
-	pjsip_uri *uri;
-};
-
-/*! \brief Callback function for finding a contact */
-static int registrar_find_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	const struct registrar_contact_details *details = arg;
-	pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
-
-	return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
-static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
-{
-	pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
-	struct registrar_contact_details details = {
-		.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
-	};
-
-	if (!details.pool) {
-		return -1;
-	}
-
-	while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
-		int expiration = registrar_get_expiration(aor, contact, rdata);
-		RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
-
-		if (contact->star) {
-			/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
-			if ((expiration != 0) || previous) {
-				pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
-				return -1;
-			}
-			continue;
-		} else if (previous && previous->star) {
-			/* If there is a previous contact and it is a '*' this is a deal breaker */
-			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
-			return -1;
-		}
-		previous = contact;
-
-		if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
-			continue;
-		}
-
-		details.uri = pjsip_uri_get_uri(contact->uri);
-
-		/* Determine if this is an add, update, or delete for policy enforcement purposes */
-		if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
-			if (expiration) {
-				(*added)++;
-			}
-		} else if (expiration) {
-			(*updated)++;
-		} else {
-			(*deleted)++;
-		}
-	}
-
-	/* The provided contacts are acceptable, huzzah! */
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
-	return 0;
-}
-
-/*! \brief Callback function which prunes static contacts */
-static int registrar_prune_static(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-
-	return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
-}
-
-/*! \brief Internal function used to delete a contact from an AOR */
-static int registrar_delete_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	const char *aor_name = arg;
-
-	ast_sip_location_delete_contact(contact);
-	if (!ast_strlen_zero(aor_name)) {
-		ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
-		ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
-				"Contact: %s\r\n"
-				"AOR: %s\r\n"
-				"UserAgent: %s",
-				contact->uri,
-				aor_name,
-				contact->user_agent);
-	}
-
-	return 0;
-}
-
-/*! \brief Internal function which adds a contact to a response */
-static int registrar_add_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	pjsip_tx_data *tdata = arg;
-	pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
-	pj_str_t uri;
-
-	pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
-	hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
-	hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
-
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
-
-	return 0;
-}
-
-/*! \brief Helper function which adds a Date header to a response */
-static void registrar_add_date_header(pjsip_tx_data *tdata)
-{
-	char date[256];
-	struct tm tm;
-	time_t t = time(NULL);
-
-	gmtime_r(&t, &tm);
-	strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
-
-	ast_sip_add_header(tdata, "Date", date);
-}
-
-#define SERIALIZER_BUCKETS 59
-
-static struct ao2_container *serializers;
-
-/*! \brief Serializer with associated aor key */
-struct serializer {
-	/* Serializer to distribute tasks to */
-	struct ast_taskprocessor *serializer;
-	/* The name of the aor to associate with the serializer */
-	char aor_name[0];
-};
-
-static void serializer_destroy(void *obj)
-{
-	struct serializer *ser = obj;
-
-	ast_taskprocessor_unreference(ser->serializer);
-}
-
-static struct serializer *serializer_create(const char *aor_name)
-{
-	size_t size = strlen(aor_name) + 1;
-	struct serializer *ser = ao2_alloc(
-		sizeof(*ser) + size, serializer_destroy);
-
-	if (!ser) {
-		return NULL;
-	}
-
-	if (!(ser->serializer = ast_sip_create_serializer())) {
-		ao2_ref(ser, -1);
-		return NULL;
-	}
-
-	strcpy(ser->aor_name, aor_name);
-	return ser;
-}
-
-static struct serializer *serializer_find_or_create(const char *aor_name)
-{
-	struct serializer *ser = ao2_find(serializers, aor_name, OBJ_SEARCH_KEY);
-
-	if (ser) {
-		return ser;
-	}
-
-	if (!(ser = serializer_create(aor_name))) {
-		return NULL;
-	}
-
-	ao2_link(serializers, ser);
-	return ser;
-}
-
-static int serializer_hash(const void *obj, const int flags)
-{
-	const struct serializer *object;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		return ast_str_hash(key);
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		return ast_str_hash(object->aor_name);
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int serializer_cmp(void *obj_left, void *obj_right, int flags)
-{
-	const struct serializer *object_left = obj_left;
-	const struct serializer *object_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->aor_name;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->aor_name, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->aor_name, right_key, strlen(right_key));
-		break;
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp ? 0 : CMP_MATCH;
-}
-
-struct rx_task_data {
-	pjsip_rx_data *rdata;
-	struct ast_sip_endpoint *endpoint;
-	struct ast_sip_aor *aor;
-};
-
-static void rx_task_data_destroy(void *obj)
-{
-	struct rx_task_data *task_data = obj;
-
-	pjsip_rx_data_free_cloned(task_data->rdata);
-	ao2_cleanup(task_data->endpoint);
-	ao2_cleanup(task_data->aor);
-}
-
-static struct rx_task_data *rx_task_data_create(pjsip_rx_data *rdata,
-						struct ast_sip_endpoint *endpoint,
-						struct ast_sip_aor *aor)
-{
-	struct rx_task_data *task_data = ao2_alloc(
-		sizeof(*task_data), rx_task_data_destroy);
-
-	if (!task_data) {
-		return NULL;
-	}
-
-	pjsip_rx_data_clone(rdata, 0, &task_data->rdata);
-
-	task_data->endpoint = endpoint;
-	ao2_ref(task_data->endpoint, +1);
-
-	task_data->aor = aor;
-	ao2_ref(task_data->aor, +1);
-
-	return task_data;
-}
-
-static const pj_str_t path_hdr_name = { "Path", 4 };
-
-static int build_path_data(struct rx_task_data *task_data, struct ast_str **path_str)
-{
-	pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, NULL);
-
-	if (!path_hdr) {
-		return 0;
-	}
-
-	*path_str = ast_str_create(64);
-	if (!path_str) {
-		return -1;
-	}
-
-	ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
-
-	while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
-		ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
-	}
-
-	return 0;
-}
-
-static int registrar_validate_path(struct rx_task_data *task_data, struct ast_str **path_str)
-{
-	const pj_str_t path_supported_name = { "path", 4 };
-	pjsip_supported_hdr *supported_hdr;
-	int i;
-
-	if (!task_data->aor->support_path) {
-		return 0;
-	}
-
-	if (build_path_data(task_data, path_str)) {
-		return -1;
-	}
-
-	if (!*path_str) {
-		return 0;
-	}
-
-	supported_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
-	if (!supported_hdr) {
-		return -1;
-	}
-
-	/* Find advertised path support */
-	for (i = 0; i < supported_hdr->count; i++) {
-		if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
-			return 0;
-		}
-	}
-
-	/* Path header present, but support not advertised */
-	return -1;
-}
-
-static int rx_task(void *data)
-{
-	static const pj_str_t USER_AGENT = { "User-Agent", 10 };
-
-	RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
-	int added = 0, updated = 0, deleted = 0;
-	pjsip_contact_hdr *contact_hdr = NULL;
-	struct registrar_contact_details details = { 0, };
-	pjsip_tx_data *tdata;
-	pjsip_response_addr addr;
-	const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
-	RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
-	struct ast_sip_contact *response_contact;
-	char *user_agent = NULL;
-	pjsip_user_agent_hdr *user_agent_hdr;
-
-	/* Retrieve the current contacts, we'll need to know whether to update or not */
-	contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
-
-	/* So we don't count static contacts against max_contacts we prune them out from the container */
-	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
-
-	if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) {
-		/* The provided Contact headers do not conform to the specification */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL);
-		ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided");
-		ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
-				ast_sorcery_object_get_id(task_data->endpoint));
-		return PJ_TRUE;
-	}
-
-	if (registrar_validate_path(task_data, &path_str)) {
-		/* Ensure that intervening proxies did not make invalid modifications to the request */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 420, NULL, NULL, NULL);
-		ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
-				ast_sorcery_object_get_id(task_data->endpoint));
-		return PJ_TRUE;
-	}
-
-	if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) {
-		/* Enforce the maximum number of contacts */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
-		ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
-				ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts);
-		return PJ_TRUE;
-	}
-
-	if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL);
-		return PJ_TRUE;
-	}
-
-	user_agent_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &USER_AGENT, NULL);
-	if (user_agent_hdr) {
-		size_t alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
-		user_agent = ast_alloca(alloc_size);
-		ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
-	}
-
-	/* Iterate each provided Contact header and add, update, or delete */
-	while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
-		int expiration;
-		char contact_uri[PJSIP_MAX_URL_SIZE];
-		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
-
-		if (contact_hdr->star) {
-			/* A star means to unregister everything, so do so for the possible contacts */
-			ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
-			break;
-		}
-
-		if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
-			/* This registrar only currently supports sip: and sips: URI schemes */
-			continue;
-		}
-
-		expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata);
-		details.uri = pjsip_uri_get_uri(contact_hdr->uri);
-		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
-
-		if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
-			/* If they are actually trying to delete a contact that does not exist... be forgiving */
-			if (!expiration) {
-				ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
-					contact_uri, aor_name);
-				continue;
-			}
-
-			if (ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
-				ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
-					user_agent)) {
-				ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
-						contact_uri, aor_name);
-				continue;
-			}
-
-			ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
-				contact_uri, aor_name, expiration);
-			ast_test_suite_event_notify("AOR_CONTACT_ADDED",
-					"Contact: %s\r\n"
-					"AOR: %s\r\n"
-					"Expiration: %d\r\n"
-					"UserAgent: %s",
-					contact_uri,
-					aor_name,
-					expiration,
-					user_agent);
-		} else if (expiration) {
-			struct ast_sip_contact *contact_update;
-
-			contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
-			if (!contact_update) {
-				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
-					contact->uri, expiration);
-				continue;
-			}
-
-			contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
-			contact_update->qualify_frequency = task_data->aor->qualify_frequency;
-			contact_update->authenticate_qualify = task_data->aor->authenticate_qualify;
-			if (path_str) {
-				ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
-			}
-			if (user_agent) {
-				ast_string_field_set(contact_update, user_agent, user_agent);
-			}
-
-			if (ast_sip_location_update_contact(contact_update)) {
-				ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
-					contact->uri, expiration);
-				ast_sorcery_delete(ast_sip_get_sorcery(), contact);
-				continue;
-			}
-			ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
-				contact_uri, aor_name, expiration);
-			ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
-					"Contact: %s\r\n"
-					"AOR: %s\r\n"
-					"Expiration: %d\r\n"
-					"UserAgent: %s",
-					contact_uri,
-					aor_name,
-					expiration,
-					contact_update->user_agent);
-			ao2_cleanup(contact_update);
-		} else {
-			/* We want to report the user agent that was actually in the removed contact */
-			user_agent = ast_strdupa(contact->user_agent);
-			ast_sip_location_delete_contact(contact);
-			ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
-			ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
-					"Contact: %s\r\n"
-					"AOR: %s\r\n"
-					"UserAgent: %s",
-					contact_uri,
-					aor_name,
-					user_agent);
-		}
-	}
-
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
-
-	/* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
-	 * do so
-	 */
-	if (task_data->aor->remove_existing) {
-		ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
-	}
-
-	/* Update the contacts as things will probably have changed */
-	ao2_cleanup(contacts);
-
-	contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
-	response_contact = ao2_callback(contacts, 0, NULL, NULL);
-
-	/* Send a response containing all of the contacts (including static) that are present on this AOR */
-	if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
-		ao2_cleanup(response_contact);
-		return PJ_TRUE;
-	}
-	ao2_cleanup(response_contact);
-
-	/* Add the date header to the response, some UAs use this to set their date and time */
-	registrar_add_date_header(tdata);
-
-	ao2_callback(contacts, 0, registrar_add_contact, tdata);
-
-	if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
-		ast_sip_send_response(&addr, tdata, task_data->endpoint);
-	} else {
-		pjsip_tx_data_dec_ref(tdata);
-	}
-
-	return PJ_TRUE;
-}
-
-static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
-	struct rx_task_data *task_data;
-
-	RAII_VAR(struct ast_sip_endpoint *, endpoint,
-		 ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
-	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
-	pjsip_sip_uri *uri;
-	char *domain_name;
-	char *configured_aors, *aor_name;
-	RAII_VAR(struct ast_str *, id, NULL, ast_free);
-
-	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
-		return PJ_FALSE;
-	}
-
-	if (ast_strlen_zero(endpoint->aors)) {
-		/* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
-		ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
-		return PJ_TRUE;
-	}
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
-		ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
-		ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
-		return PJ_TRUE;
-	}
-
-	uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
-	domain_name = ast_alloca(uri->host.slen + 1);
-	ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1);
-
-	configured_aors = ast_strdupa(endpoint->aors);
-
-	/* Iterate the configured AORs to see if the user or the user+domain match */
-	while ((aor_name = strsep(&configured_aors, ","))) {
-		struct ast_sip_domain_alias *alias = NULL;
-
-		if (!pj_strcmp2(&uri->user, aor_name)) {
-			break;
-		}
-
-		if (!id && !(id = ast_str_create(uri->user.slen + uri->host.slen + 2))) {
-			return PJ_TRUE;
-		}
-
-		ast_str_set(&id, 0, "%.*s@", (int)uri->user.slen, uri->user.ptr);
-		if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
-			ast_str_append(&id, 0, "%s", alias->domain);
-			ao2_cleanup(alias);
-		} else {
-			ast_str_append(&id, 0, "%s", domain_name);
-		}
-
-		if (!strcmp(aor_name, ast_str_buffer(id))) {
-			ast_free(id);
-			break;
-		}
-	}
-
-	if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
-		/* The provided AOR name was not found (be it within the configuration or sorcery itself) */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
-		ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
-		ast_log(LOG_WARNING, "AOR '%.*s' not found for endpoint '%s'\n", (int)uri->user.slen, uri->user.ptr, ast_sorcery_object_get_id(endpoint));
-		return PJ_TRUE;
-	}
-
-	if (!aor->max_contacts) {
-		/* Registration is not permitted for this AOR */
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
-		ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
-				ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint));
-		return PJ_TRUE;
-	}
-
-	if (!(ser = serializer_find_or_create(aor_name))) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_mem_limit(endpoint, rdata);
-		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n",
-			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
-		return PJ_TRUE;
-	}
-
-	if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_mem_limit(endpoint, rdata);
-		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n",
-			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
-		return PJ_TRUE;
-	}
-
-	if (ast_sip_push_task(ser->serializer, rx_task, task_data)) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
-		ast_sip_report_mem_limit(endpoint, rdata);
-		ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n",
-			ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
-		ao2_ref(task_data, -1);
-	}
-	return PJ_TRUE;
-}
-
-/* function pointer to callback needs to be within the module
-   in order to avoid problems with an undefined symbol */
-static int sip_contact_to_str(void *acp, void *arg, int flags)
-{
-	return ast_sip_contact_to_str(acp, arg, flags);
-}
-
-static int ami_registrations_aor(void *obj, void *arg, int flags)
-{
-	struct ast_sip_aor *aor = obj;
-	struct ast_sip_ami *ami = arg;
-	int *count = ami->arg;
-	RAII_VAR(struct ast_str *, buf,
-		 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
-
-	if (!buf) {
-		return -1;
-	}
-
-	ast_sip_sorcery_object_to_ami(aor, &buf);
-	ast_str_append(&buf, 0, "Contacts: ");
-	ast_sip_for_each_contact(aor, sip_contact_to_str, &buf);
-	ast_str_append(&buf, 0, "\r\n");
-
-	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-	(*count)++;
-	return 0;
-}
-
-static int ami_registrations_endpoint(void *obj, void *arg, int flags)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-	return ast_sip_for_each_aor(
-		endpoint->aors, ami_registrations_aor, arg);
-}
-
-static int ami_registrations_endpoints(void *arg)
-{
-	RAII_VAR(struct ao2_container *, endpoints,
-		 ast_sip_get_endpoints(), ao2_cleanup);
-
-	if (!endpoints) {
-		return 0;
-	}
-
-	ao2_callback(endpoints, OBJ_NODATA, ami_registrations_endpoint, arg);
-	return 0;
-}
-
-static int ami_show_registrations(struct mansession *s, const struct message *m)
-{
-	int count = 0;
-	struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
-	astman_send_listack(s, m, "Following are Events for each Inbound "
-			    "registration", "start");
-
-	ami_registrations_endpoints(&ami);
-
-	astman_append(s, "Event: InboundRegistrationDetailComplete\r\n");
-	if (!ast_strlen_zero(ami.action_id)) {
-		astman_append(s, "ActionID: %s\r\n", ami.action_id);
-	}
-	astman_append(s, "EventList: Complete\r\n"
-		      "ListItems: %d\r\n\r\n", count);
-	return 0;
-}
-
-#define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
-
-static pjsip_module registrar_module = {
-	.name = { "Registrar", 9 },
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.on_rx_request = registrar_on_rx_request,
-};
-
-static int load_module(void)
-{
-	const pj_str_t STR_REGISTER = { "REGISTER", 8 };
-
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (!(serializers = ao2_container_alloc(
-		      SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_register_service(&registrar_module)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
-		ast_sip_unregister_service(&registrar_module);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM,
-				 ami_show_registrations);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
-	ast_sip_unregister_service(&registrar_module);
-
-	ao2_cleanup(serializers);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c
deleted file mode 100644
index 256ed9e..0000000
--- a/res/res_pjsip_registrar_expire.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/module.h"
-#include "asterisk/sched.h"
-
-#define CONTACT_AUTOEXPIRE_BUCKETS 977
-
-static struct ao2_container *contact_autoexpire;
-
-/*! \brief Scheduler used for automatically expiring contacts */
-static struct ast_sched_context *sched;
-
-/*! \brief Structure used for contact auto-expiration */
-struct contact_expiration {
-	/*! \brief Contact that is being auto-expired */
-	struct ast_sip_contact *contact;
-
-	/*! \brief Scheduled item for performing expiration */
-	int sched;
-};
-
-/*! \brief Destructor function for contact auto-expiration */
-static void contact_expiration_destroy(void *obj)
-{
-	struct contact_expiration *expiration = obj;
-
-	ao2_cleanup(expiration->contact);
-}
-
-/*! \brief Hashing function for contact auto-expiration */
-static int contact_expiration_hash(const void *obj, const int flags)
-{
-	const struct contact_expiration *expiration = obj;
-	const char *id = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? id : ast_sorcery_object_get_id(expiration->contact));
-}
-
-/*! \brief Comparison function for contact auto-expiration */
-static int contact_expiration_cmp(void *obj, void *arg, int flags)
-{
-	struct contact_expiration *expiration1 = obj, *expiration2 = arg;
-	const char *id = arg;
-
-	return !strcmp(ast_sorcery_object_get_id(expiration1->contact), flags & OBJ_KEY ? id :
-		       ast_sorcery_object_get_id(expiration2->contact)) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Scheduler function which deletes a contact */
-static int contact_expiration_expire(const void *data)
-{
-	RAII_VAR(struct contact_expiration *, expiration, (void*)data, ao2_cleanup);
-
-	expiration->sched = -1;
-
-	/* This will end up invoking the deleted observer callback, which will perform the unlinking and such */
-	ast_sorcery_delete(ast_sip_get_sorcery(), expiration->contact);
-
-	return 0;
-}
-
-/*! \brief Observer callback for when a contact is created */
-static void contact_expiration_observer_created(const void *object)
-{
-	const struct ast_sip_contact *contact = object;
-	RAII_VAR(struct contact_expiration *, expiration, NULL, ao2_cleanup);
-	int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow()));
-
-	if (ast_tvzero(contact->expiration_time)) {
-		return;
-	}
-
-	if (!(expiration = ao2_alloc_options(sizeof(*expiration), contact_expiration_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
-		return;
-	}
-
-	expiration->contact = (struct ast_sip_contact*)contact;
-	ao2_ref(expiration->contact, +1);
-
-	ao2_ref(expiration, +1);
-	if ((expiration->sched = ast_sched_add(sched, expires, contact_expiration_expire, expiration)) < 0) {
-		ao2_cleanup(expiration);
-		ast_log(LOG_ERROR, "Scheduled expiration for contact '%s' could not be performed, contact may persist past life\n",
-			ast_sorcery_object_get_id(contact));
-		return;
-	}
-
-	ao2_link(contact_autoexpire, expiration);
-}
-
-/*! \brief Observer callback for when a contact is updated */
-static void contact_expiration_observer_updated(const void *object)
-{
-	const struct ast_sip_contact *contact = object;
-	RAII_VAR(struct contact_expiration *, expiration, ao2_find(contact_autoexpire, ast_sorcery_object_get_id(contact), OBJ_KEY), ao2_cleanup);
-	int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow()));
-
-	if (!expiration) {
-		return;
-	}
-
-	AST_SCHED_REPLACE_UNREF(expiration->sched, sched, expires, contact_expiration_expire, expiration, ao2_cleanup(expiration), ao2_cleanup(expiration), ao2_ref(expiration, +1));
-}
-
-/*! \brief Observer callback for when a contact is deleted */
-static void contact_expiration_observer_deleted(const void *object)
-{
-	RAII_VAR(struct contact_expiration *, expiration, ao2_find(contact_autoexpire, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
-
-	if (!expiration) {
-		return;
-	}
-
-	AST_SCHED_DEL_UNREF(sched, expiration->sched, ao2_cleanup(expiration));
-}
-
-/*! \brief Observer callbacks for autoexpiring contacts */
-static const struct ast_sorcery_observer contact_expiration_observer = {
-	.created = contact_expiration_observer_created,
-	.updated = contact_expiration_observer_updated,
-	.deleted = contact_expiration_observer_deleted,
-};
-
-/*! \brief Callback function which deletes a contact if it has expired or sets up auto-expiry */
-static int contact_expiration_setup(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow()));
-
-	if (!expires) {
-		ast_sorcery_delete(ast_sip_get_sorcery(), contact);
-	} else {
-		contact_expiration_observer_created(contact);
-	}
-
-	return 0;
-}
-
-/*! \brief Initialize auto-expiration of any existing contacts */
-static void contact_expiration_initialize_existing(void)
-{
-	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
-	if (!(contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		return;
-	}
-
-	ao2_callback(contacts, OBJ_NODATA, contact_expiration_setup, NULL);
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (!(contact_autoexpire = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, CONTACT_AUTOEXPIRE_BUCKETS,
-		contact_expiration_hash, contact_expiration_cmp))) {
-		ast_log(LOG_ERROR, "Could not create container for contact auto-expiration\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (!(sched = ast_sched_context_create())) {
-		ast_log(LOG_ERROR, "Could not create scheduler for contact auto-expiration\n");
-		goto error;
-	}
-
-	if (ast_sched_start_thread(sched)) {
-		ast_log(LOG_ERROR, "Could not start scheduler thread for contact auto-expiration\n");
-		goto error;
-	}
-
-	contact_expiration_initialize_existing();
-
-	if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &contact_expiration_observer)) {
-		ast_log(LOG_ERROR, "Could not add observer for notifications about contacts for contact auto-expiration\n");
-		goto error;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-
-error:
-	if (sched) {
-		ast_sched_context_destroy(sched);
-	}
-
-	ao2_cleanup(contact_autoexpire);
-	return AST_MODULE_LOAD_FAILURE;
-}
-
-static int unload_module(void)
-{
-	ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &contact_expiration_observer);
-	ast_sched_context_destroy(sched);
-	ao2_cleanup(contact_autoexpire);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Contact Auto-Expiration",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_rfc3326.c b/res/res_pjsip_rfc3326.c
deleted file mode 100644
index 3ed8de6..0000000
--- a/res/res_pjsip_rfc3326.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-#include "asterisk/causes.h"
-
-static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	const pj_str_t str_reason = { "Reason", 6 };
-	pjsip_generic_string_hdr *header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL);
-	char buf[20], *cause, *text;
-	int code;
-
-	if (!header) {
-		return;
-	}
-
-	ast_copy_pj_str(buf, &header->hvalue, sizeof(buf));
-	cause = ast_skip_blanks(buf);
-
-	if (strncasecmp(cause, "Q.850", 5) || !(cause = strstr(cause, "cause="))) {
-		return;
-	}
-
-	/* If text is present get rid of it */
-	if ((text = strstr(cause, ";"))) {
-		*text = '\0';
-	}
-
-	if (sscanf(cause, "cause=%30d", &code) != 1) {
-		return;
-	}
-
-	ast_channel_hangupcause_set(session->channel, code & 0x7f);
-}
-
-static int rfc3326_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	if ((pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method) &&
-	     pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method)) ||
-	    !session->channel) {
-		return 0;
-	}
-
-	rfc3326_use_reason_header(session, rdata);
-
-	return 0;
-}
-
-static void rfc3326_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	struct pjsip_status_line status = rdata->msg_info.msg->line.status;
-
-	if ((status.code < 300) || !session->channel) {
-		return;
-	}
-
-	rfc3326_use_reason_header(session, rdata);
-}
-
-static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	char buf[20];
-
-	snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f);
-	ast_sip_add_header(tdata, "Reason", buf);
-
-	if (ast_channel_hangupcause(session->channel) == AST_CAUSE_ANSWERED_ELSEWHERE) {
-		ast_sip_add_header(tdata, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
-	}
-}
-
-static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	if ((pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_bye_method) &&
-	     pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method)) ||
-	    !session->channel) {
-		return;
-	}
-
-	rfc3326_add_reason_header(session, tdata);
-}
-
-static void rfc3326_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	struct pjsip_status_line status = tdata->msg->line.status;
-
-	if ((status.code < 300) || !session->channel) {
-		return;
-	}
-
-	rfc3326_add_reason_header(session, tdata);
-}
-
-static struct ast_sip_session_supplement rfc3326_supplement = {
-	.incoming_request = rfc3326_incoming_request,
-	.incoming_response = rfc3326_incoming_response,
-	.outgoing_request = rfc3326_outgoing_request,
-	.outgoing_response = rfc3326_outgoing_response,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sip_session_register_supplement(&rfc3326_supplement);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&rfc3326_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP RFC3326 Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
deleted file mode 100644
index 036a645..0000000
--- a/res/res_pjsip_sdp_rtp.c
+++ /dev/null
@@ -1,1353 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- * \brief SIP SDP media stream handling
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjmedia.h>
-#include <pjlib.h>
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431327 $")
-
-#include "asterisk/module.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-#include "asterisk/rtp_engine.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/channel.h"
-#include "asterisk/causes.h"
-#include "asterisk/sched.h"
-#include "asterisk/acl.h"
-#include "asterisk/sdp_srtp.h"
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-
-/*! \brief Scheduler for RTCP purposes */
-static struct ast_sched_context *sched;
-
-/*! \brief Address for IPv4 RTP */
-static struct ast_sockaddr address_ipv4;
-
-/*! \brief Address for IPv6 RTP */
-static struct ast_sockaddr address_ipv6;
-
-static const char STR_AUDIO[] = "audio";
-static const int FD_AUDIO = 0;
-
-static const char STR_VIDEO[] = "video";
-static const int FD_VIDEO = 2;
-
-/*! \brief Retrieves an ast_format_type based on the given stream_type */
-static enum ast_media_type stream_to_media_type(const char *stream_type)
-{
-	if (!strcasecmp(stream_type, STR_AUDIO)) {
-		return AST_MEDIA_TYPE_AUDIO;
-	} else if (!strcasecmp(stream_type, STR_VIDEO)) {
-		return AST_MEDIA_TYPE_VIDEO;
-	}
-
-	return 0;
-}
-
-/*! \brief Get the starting descriptor for a media type */
-static int media_type_to_fdno(enum ast_media_type media_type)
-{
-	switch (media_type) {
-	case AST_MEDIA_TYPE_AUDIO: return FD_AUDIO;
-	case AST_MEDIA_TYPE_VIDEO: return FD_VIDEO;
-	case AST_MEDIA_TYPE_TEXT:
-	case AST_MEDIA_TYPE_UNKNOWN:
-	case AST_MEDIA_TYPE_IMAGE: break;
-	}
-	return -1;
-}
-
-/*! \brief Remove all other cap types but the one given */
-static void format_cap_only_type(struct ast_format_cap *caps, enum ast_media_type media_type)
-{
-	int i = 0;
-	while (i <= AST_MEDIA_TYPE_TEXT) {
-		if (i != media_type && i != AST_MEDIA_TYPE_UNKNOWN) {
-			ast_format_cap_remove_by_type(caps, i);
-		}
-		i += 1;
-	}
-}
-
-/*! \brief Internal function which creates an RTP instance */
-static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
-{
-	struct ast_rtp_engine_ice *ice;
-
-	if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) {
-		ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", session->endpoint->media.rtp.engine);
-		return -1;
-	}
-
-	ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1);
-	ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric);
-
-	if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
-		ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
-	}
-
-	if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) {
-		ice->stop(session_media->rtp);
-	}
-
-	if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) {
-		ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);
-	} else if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) {
-		ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
-	}
-
-	if (!strcmp(session_media->stream_type, STR_AUDIO) &&
-			(session->endpoint->media.tos_audio || session->endpoint->media.cos_video)) {
-		ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio,
-				session->endpoint->media.cos_audio, "SIP RTP Audio");
-	} else if (!strcmp(session_media->stream_type, STR_VIDEO) &&
-			(session->endpoint->media.tos_video || session->endpoint->media.cos_video)) {
-		ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video,
-				session->endpoint->media.cos_video, "SIP RTP Video");
-	}
-
-	return 0;
-}
-
-static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs)
-{
-	pjmedia_sdp_attr *attr;
-	pjmedia_sdp_rtpmap *rtpmap;
-	pjmedia_sdp_fmtp fmtp;
-	struct ast_format *format;
-	int i, num = 0;
-	char name[256];
-	char media[20];
-	char fmt_param[256];
-
-	ast_rtp_codecs_payloads_initialize(codecs);
-
-	/* Iterate through provided formats */
-	for (i = 0; i < stream->desc.fmt_count; ++i) {
-		/* The payload is kept as a string for things like t38 but for video it is always numerical */
-		ast_rtp_codecs_payloads_set_m_type(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]));
-		/* Look for the optional rtpmap attribute */
-		if (!(attr = pjmedia_sdp_media_find_attr2(stream, "rtpmap", &stream->desc.fmt[i]))) {
-			continue;
-		}
-
-		/* Interpret the attribute as an rtpmap */
-		if ((pjmedia_sdp_attr_to_rtpmap(session->inv_session->pool_prov, attr, &rtpmap)) != PJ_SUCCESS) {
-			continue;
-		}
-
-		ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
-		ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
-		ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]),
-							     media, name, 0, rtpmap->clock_rate);
-		/* Look for an optional associated fmtp attribute */
-		if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) {
-			continue;
-		}
-
-		if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) {
-			sscanf(pj_strbuf(&fmtp.fmt), "%d", &num);
-			if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) {
-				struct ast_format *format_parsed;
-
-				ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param));
-
-				format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param);
-				if (format_parsed) {
-					ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed);
-					ao2_ref(format_parsed, -1);
-				}
-
-				ao2_ref(format, -1);
-			}
-		}
-	}
-
-	/* Get the packetization, if it exists */
-	if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) {
-		unsigned long framing = pj_strtoul(pj_strltrim(&attr->value));
-		if (framing && session->endpoint->media.rtp.use_ptime) {
-			ast_rtp_codecs_set_framing(codecs, framing);
-		}
-	}
-}
-
-static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-		    const struct pjmedia_sdp_media *stream)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup);
-	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
-	struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT;
-	int fmts = 0;
-	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
-		ast_format_cap_count(session->direct_media_cap);
-
-	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
-	    !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
-	    !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
-		return -1;
-	}
-
-	/* get the endpoint capabilities */
-	if (direct_media_enabled) {
-		ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
-		format_cap_only_type(caps, media_type);
-	} else {
-		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
-	}
-
-	/* get the capabilities on the peer */
-	get_codecs(session, stream, &codecs);
-	ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);
-
-	/* get the joint capabilities between peer and endpoint */
-	ast_format_cap_get_compatible(caps, peer, joint);
-	if (!ast_format_cap_count(joint)) {
-		struct ast_str *usbuf = ast_str_alloca(64);
-		struct ast_str *thembuf = ast_str_alloca(64);
-
-		ast_rtp_codecs_payloads_destroy(&codecs);
-		ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
-			session_media->stream_type,
-			ast_format_cap_get_names(caps, &usbuf),
-			ast_format_cap_get_names(peer, &thembuf));
-		return -1;
-	}
-
-	ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
-				     session_media->rtp);
-
-	ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN);
-
-	if (session->channel) {
-		struct ast_format *fmt;
-
-		ast_channel_lock(session->channel);
-		ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN);
-		ast_format_cap_remove_by_type(caps, media_type);
-
-		/*
-		 * XXX Historically we picked the "best" joint format to use
-		 * and stuck with it.  It would be nice to just append the
-		 * determined joint media capabilities to give translation
-		 * more formats to choose from when necessary.  Unfortunately,
-		 * there are some areas of the system where this doesn't work
-		 * very well. (The softmix bridge in particular is reluctant
-		 * to pick higher fidelity formats and has a problem with
-		 * asymmetric sample rates.)
-		 */
-		fmt = ast_format_cap_get_format(joint, 0);
-		ast_format_cap_append(caps, fmt, 0);
-
-		/*
-		 * Apply the new formats to the channel, potentially changing
-		 * raw read/write formats and translation path while doing so.
-		 */
-		ast_channel_nativeformats_set(session->channel, caps);
-		ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
-		ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
-		ast_channel_unlock(session->channel);
-
-		ao2_ref(fmt, -1);
-	}
-
-	ast_rtp_codecs_payloads_destroy(&codecs);
-	return 0;
-}
-
-static pjmedia_sdp_attr* generate_rtpmap_attr(pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code,
-					      int asterisk_format, struct ast_format *format, int code)
-{
-	pjmedia_sdp_rtpmap rtpmap;
-	pjmedia_sdp_attr *attr = NULL;
-	char tmp[64];
-
-	snprintf(tmp, sizeof(tmp), "%d", rtp_code);
-	pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
-	rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
-	rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
-	pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, 0));
-	rtpmap.param.slen = 0;
-	rtpmap.param.ptr = NULL;
-
-	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
-
-	return attr;
-}
-
-static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
-{
-	struct ast_str *fmtp0 = ast_str_alloca(256);
-	pj_str_t fmtp1;
-	pjmedia_sdp_attr *attr = NULL;
-	char *tmp;
-
-	ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0);
-	if (ast_str_strlen(fmtp0)) {
-		tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1;
-		/* remove any carriage return line feeds */
-		while (*tmp == '\r' || *tmp == '\n') --tmp;
-		*++tmp = '\0';
-		/* ast...generate gives us everything, just need value */
-		tmp = strchr(ast_str_buffer(fmtp0), ':');
-		if (tmp && tmp + 1) {
-			fmtp1 = pj_str(tmp + 1);
-		} else {
-			fmtp1 = pj_str(ast_str_buffer(fmtp0));
-		}
-		attr = pjmedia_sdp_attr_create(pool, "fmtp", &fmtp1);
-	}
-	return attr;
-}
-
-/*! \brief Function which adds ICE attributes to a media stream */
-static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
-{
-	struct ast_rtp_engine_ice *ice;
-	struct ao2_container *candidates;
-	const char *username, *password;
-	pj_str_t stmp;
-	pjmedia_sdp_attr *attr;
-	struct ao2_iterator it_candidates;
-	struct ast_rtp_engine_ice_candidate *candidate;
-
-	if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) ||
-		!(candidates = ice->get_local_candidates(session_media->rtp))) {
-		return;
-	}
-
-	if ((username = ice->get_ufrag(session_media->rtp))) {
-		attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
-		media->attr[media->attr_count++] = attr;
-	}
-
-	if ((password = ice->get_password(session_media->rtp))) {
-		attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
-		media->attr[media->attr_count++] = attr;
-	}
-
-	it_candidates = ao2_iterator_init(candidates, 0);
-	for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
-		struct ast_str *attr_candidate = ast_str_create(128);
-
-		ast_str_set(&attr_candidate, -1, "%s %u %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
-					candidate->priority, ast_sockaddr_stringify_addr_remote(&candidate->address));
-		ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
-
-		switch (candidate->type) {
-			case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
-				ast_str_append(&attr_candidate, -1, "host");
-				break;
-			case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
-				ast_str_append(&attr_candidate, -1, "srflx");
-				break;
-			case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
-				ast_str_append(&attr_candidate, -1, "relay");
-				break;
-		}
-
-		if (!ast_sockaddr_isnull(&candidate->relay_address)) {
-			ast_str_append(&attr_candidate, -1, " raddr %s rport", ast_sockaddr_stringify_addr_remote(&candidate->relay_address));
-			ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
-		}
-
-		attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
-		media->attr[media->attr_count++] = attr;
-
-		ast_free(attr_candidate);
-	}
-
-	ao2_iterator_destroy(&it_candidates);
-}
-
-/*! \brief Function which processes ICE attributes in an audio stream */
-static void process_ice_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-				   const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
-{
-	struct ast_rtp_engine_ice *ice;
-	const pjmedia_sdp_attr *attr;
-	char attr_value[256];
-	unsigned int attr_i;
-
-	/* If ICE support is not enabled or available exit early */
-	if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
-		return;
-	}
-
-	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL);
-	if (!attr) {
-		attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
-	}
-	if (attr) {
-		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
-		ice->set_authentication(session_media->rtp, attr_value, NULL);
-	} else {
-		return;
-	}
-
-	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL);
-	if (!attr) {
-		attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL);
-	}
-	if (attr) {
-		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
-		ice->set_authentication(session_media->rtp, NULL, attr_value);
-	} else {
-		return;
-	}
-
-	if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
-		ice->ice_lite(session_media->rtp);
-	}
-
-	/* Find all of the candidates */
-	for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
-		char foundation[32], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = "";
-		unsigned int port, relay_port = 0;
-		struct ast_rtp_engine_ice_candidate candidate = { 0, };
-
-		attr = remote_stream->attr[attr_i];
-
-		/* If this is not a candidate line skip it */
-		if (pj_strcmp2(&attr->name, "candidate")) {
-			continue;
-		}
-
-		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
-
-		if (sscanf(attr_value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
-			(unsigned *)&candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
-			/* Candidate did not parse properly */
-			continue;
-		}
-
-		candidate.foundation = foundation;
-		candidate.transport = transport;
-
-		ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
-		ast_sockaddr_set_port(&candidate.address, port);
-
-		if (!strcasecmp(cand_type, "host")) {
-			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
-		} else if (!strcasecmp(cand_type, "srflx")) {
-			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
-		} else if (!strcasecmp(cand_type, "relay")) {
-			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
-		} else {
-			continue;
-		}
-
-		if (!ast_strlen_zero(relay_address)) {
-			ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
-		}
-
-		if (relay_port) {
-			ast_sockaddr_set_port(&candidate.relay_address, relay_port);
-		}
-
-		ice->add_remote_candidate(session_media->rtp, &candidate);
-	}
-
-	ice->set_role(session_media->rtp, pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_TRUE ?
-		AST_RTP_ICE_ROLE_CONTROLLING : AST_RTP_ICE_ROLE_CONTROLLED);
-	ice->start(session_media->rtp);
-}
-
-/*! \brief figure out if media stream has crypto lines for sdes */
-static int media_stream_has_crypto(const struct pjmedia_sdp_media *stream)
-{
-	int i;
-
-	for (i = 0; i < stream->attr_count; i++) {
-		pjmedia_sdp_attr *attr;
-
-		/* check the stream for the required crypto attribute */
-		attr = stream->attr[i];
-		if (pj_strcmp2(&attr->name, "crypto")) {
-			continue;
-		}
-
-		return 1;
-	}
-
-	return 0;
-}
-
-/*! \brief figure out media transport encryption type from the media transport string */
-static enum ast_sip_session_media_encryption get_media_encryption_type(pj_str_t transport,
-	const struct pjmedia_sdp_media *stream, unsigned int *optimistic)
-{
-	RAII_VAR(char *, transport_str, ast_strndup(transport.ptr, transport.slen), ast_free);
-
-	*optimistic = 0;
-
-	if (strstr(transport_str, "UDP/TLS")) {
-		return AST_SIP_MEDIA_ENCRYPT_DTLS;
-	} else if (strstr(transport_str, "SAVP")) {
-		return AST_SIP_MEDIA_ENCRYPT_SDES;
-	} else if (media_stream_has_crypto(stream)) {
-		*optimistic = 1;
-		return AST_SIP_MEDIA_ENCRYPT_SDES;
-	} else {
-		return AST_SIP_MEDIA_ENCRYPT_NONE;
-	}
-}
-
-/*!
- * \brief Checks whether the encryption offered in SDP is compatible with the endpoint's configuration
- * \internal
- *
- * \param endpoint_encryption Media encryption configured for the endpoint
- * \param stream pjmedia_sdp_media stream description
- *
- * \retval AST_SIP_MEDIA_TRANSPORT_INVALID on encryption mismatch
- * \retval The encryption requested in the SDP
- */
-static enum ast_sip_session_media_encryption check_endpoint_media_transport(
-	struct ast_sip_endpoint *endpoint,
-	const struct pjmedia_sdp_media *stream)
-{
-	enum ast_sip_session_media_encryption incoming_encryption;
-	char transport_end = stream->desc.transport.ptr[stream->desc.transport.slen - 1];
-	unsigned int optimistic;
-
-	if ((transport_end == 'F' && !endpoint->media.rtp.use_avpf)
-		|| (transport_end != 'F' && endpoint->media.rtp.use_avpf)) {
-		return AST_SIP_MEDIA_TRANSPORT_INVALID;
-	}
-
-	incoming_encryption = get_media_encryption_type(stream->desc.transport, stream, &optimistic);
-
-	if (incoming_encryption == endpoint->media.rtp.encryption) {
-		return incoming_encryption;
-	}
-
-	if (endpoint->media.rtp.force_avp ||
-		endpoint->media.rtp.encryption_optimistic) {
-		return incoming_encryption;
-	}
-
-	/* If an optimistic offer has been made but encryption is not enabled consider it as having
-	 * no offer of crypto at all instead of invalid so the session proceeds.
-	 */
-	if (optimistic) {
-		return AST_SIP_MEDIA_ENCRYPT_NONE;
-	}
-
-	return AST_SIP_MEDIA_TRANSPORT_INVALID;
-}
-
-static int setup_srtp(struct ast_sip_session_media *session_media)
-{
-	if (!session_media->srtp) {
-		session_media->srtp = ast_sdp_srtp_alloc();
-		if (!session_media->srtp) {
-			return -1;
-		}
-	}
-
-	if (!session_media->srtp->crypto) {
-		session_media->srtp->crypto = ast_sdp_crypto_alloc();
-		if (!session_media->srtp->crypto) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int setup_dtls_srtp(struct ast_sip_session *session,
-	struct ast_sip_session_media *session_media)
-{
-	struct ast_rtp_engine_dtls *dtls;
-
-	if (!session->endpoint->media.rtp.dtls_cfg.enabled || !session_media->rtp) {
-		return -1;
-	}
-
-	dtls = ast_rtp_instance_get_dtls(session_media->rtp);
-	if (!dtls) {
-		return -1;
-	}
-
-	session->endpoint->media.rtp.dtls_cfg.suite = ((session->endpoint->media.rtp.srtp_tag_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80);
-	if (dtls->set_configuration(session_media->rtp, &session->endpoint->media.rtp.dtls_cfg)) {
-		ast_log(LOG_ERROR, "Attempted to set an invalid DTLS-SRTP configuration on RTP instance '%p'\n",
-			session_media->rtp);
-		return -1;
-	}
-
-	if (setup_srtp(session_media)) {
-		return -1;
-	}
-	return 0;
-}
-
-static void apply_dtls_attrib(struct ast_sip_session_media *session_media,
-	pjmedia_sdp_attr *attr)
-{
-	struct ast_rtp_engine_dtls *dtls = ast_rtp_instance_get_dtls(session_media->rtp);
-	pj_str_t *value;
-
-	if (!attr->value.ptr) {
-		return;
-	}
-
-	value = pj_strtrim(&attr->value);
-
-	if (!pj_strcmp2(&attr->name, "setup")) {
-		if (!pj_stricmp2(value, "active")) {
-			dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTIVE);
-		} else if (!pj_stricmp2(value, "passive")) {
-			dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_PASSIVE);
-		} else if (!pj_stricmp2(value, "actpass")) {
-			dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTPASS);
-		} else if (!pj_stricmp2(value, "holdconn")) {
-			dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_HOLDCONN);
-		} else {
-			ast_log(LOG_WARNING, "Unsupported setup attribute value '%*s'\n", (int)value->slen, value->ptr);
-		}
-	} else if (!pj_strcmp2(&attr->name, "connection")) {
-		if (!pj_stricmp2(value, "new")) {
-			dtls->reset(session_media->rtp);
-		} else if (!pj_stricmp2(value, "existing")) {
-			/* Do nothing */
-		} else {
-			ast_log(LOG_WARNING, "Unsupported connection attribute value '%*s'\n", (int)value->slen, value->ptr);
-		}
-	} else if (!pj_strcmp2(&attr->name, "fingerprint")) {
-		char hash_value[256], hash[32];
-		char fingerprint_text[value->slen + 1];
-		ast_copy_pj_str(fingerprint_text, value, sizeof(fingerprint_text));
-			if (sscanf(fingerprint_text, "%31s %255s", hash, hash_value) == 2) {
-			if (!strcasecmp(hash, "sha-1")) {
-				dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1, hash_value);
-			} else if (!strcasecmp(hash, "sha-256")) {
-				dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA256, hash_value);
-			} else {
-				ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s'\n",
-				hash);
-			}
-		}
-	}
-}
-
-static int parse_dtls_attrib(struct ast_sip_session_media *session_media,
-	const struct pjmedia_sdp_session *sdp,
-	const struct pjmedia_sdp_media *stream)
-{
-	int i;
-
-	for (i = 0; i < sdp->attr_count; i++) {
-		apply_dtls_attrib(session_media, sdp->attr[i]);
-	}
-
-	for (i = 0; i < stream->attr_count; i++) {
-		apply_dtls_attrib(session_media, stream->attr[i]);
-	}
-
-	ast_set_flag(session_media->srtp, AST_SRTP_CRYPTO_OFFER_OK);
-
-	return 0;
-}
-
-static int setup_sdes_srtp(struct ast_sip_session_media *session_media,
-	const struct pjmedia_sdp_media *stream)
-{
-	int i;
-
-	for (i = 0; i < stream->attr_count; i++) {
-		pjmedia_sdp_attr *attr;
-		RAII_VAR(char *, crypto_str, NULL, ast_free);
-
-		/* check the stream for the required crypto attribute */
-		attr = stream->attr[i];
-		if (pj_strcmp2(&attr->name, "crypto")) {
-			continue;
-		}
-
-		crypto_str = ast_strndup(attr->value.ptr, attr->value.slen);
-		if (!crypto_str) {
-			return -1;
-		}
-
-		if (setup_srtp(session_media)) {
-			return -1;
-		}
-
-		if (!ast_sdp_crypto_process(session_media->rtp, session_media->srtp, crypto_str)) {
-			/* found a valid crypto attribute */
-			return 0;
-		}
-
-		ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
-	}
-
-	/* no usable crypto attributes found */
-	return -1;
-}
-
-static int setup_media_encryption(struct ast_sip_session *session,
-	struct ast_sip_session_media *session_media,
-	const struct pjmedia_sdp_session *sdp,
-	const struct pjmedia_sdp_media *stream)
-{
-	switch (session_media->encryption) {
-	case AST_SIP_MEDIA_ENCRYPT_SDES:
-		if (setup_sdes_srtp(session_media, stream)) {
-			return -1;
-		}
-		break;
-	case AST_SIP_MEDIA_ENCRYPT_DTLS:
-		if (setup_dtls_srtp(session, session_media)) {
-			return -1;
-		}
-		if (parse_dtls_attrib(session_media, sdp, stream)) {
-			return -1;
-		}
-		break;
-	case AST_SIP_MEDIA_TRANSPORT_INVALID:
-	case AST_SIP_MEDIA_ENCRYPT_NONE:
-		break;
-	}
-
-	return 0;
-}
-
-/*! \brief Function which negotiates an incoming media stream */
-static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
-{
-	char host[NI_MAXHOST];
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
-	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
-	enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
-	int res;
-
-	/* If port is 0, ignore this media stream */
-	if (!stream->desc.port) {
-		ast_debug(3, "Media stream '%s' is already declined\n", session_media->stream_type);
-		return 0;
-	}
-
-	/* If no type formats have been configured reject this stream */
-	if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) {
-		ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", session_media->stream_type);
-		return 0;
-	}
-
-	/* Ensure incoming transport is compatible with the endpoint's configuration */
-	if (!session->endpoint->media.rtp.use_received_transport) {
-		encryption = check_endpoint_media_transport(session->endpoint, stream);
-
-		if (encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) {
-			return -1;
-		}
-	}
-
-	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
-	}
-
-	/* Using the connection information create an appropriate RTP instance */
-	if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
-		return -1;
-	}
-
-	res = setup_media_encryption(session, session_media, sdp, stream);
-	if (res) {
-		if (!session->endpoint->media.rtp.encryption_optimistic) {
-			/* If optimistic encryption is disabled and crypto should have been enabled
-			 * but was not this session must fail.
-			 */
-			return -1;
-		}
-		/* There is no encryption, sad. */
-		session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
- 	}
-
-	/* If we've been explicitly configured to use the received transport OR if
-	 * encryption is on and crypto is present use the received transport.
-	 * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
-	 * on the configuration of the remote endpoint (optimistic themselves or mandatory).
-	 */
-	if ((session->endpoint->media.rtp.use_received_transport) ||
-		((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
-		pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
- 	}
-
-	if (set_caps(session, session_media, stream)) {
-		return 0;
-	}
-	return 1;
-}
-
-static int add_crypto_to_stream(struct ast_sip_session *session,
-	struct ast_sip_session_media *session_media,
-	pj_pool_t *pool, pjmedia_sdp_media *media)
-{
-	pj_str_t stmp;
-	pjmedia_sdp_attr *attr;
-	enum ast_rtp_dtls_hash hash;
-	const char *crypto_attribute;
-	struct ast_rtp_engine_dtls *dtls;
-	static const pj_str_t STR_NEW = { "new", 3 };
-	static const pj_str_t STR_EXISTING = { "existing", 8 };
-	static const pj_str_t STR_ACTIVE = { "active", 6 };
-	static const pj_str_t STR_PASSIVE = { "passive", 7 };
-	static const pj_str_t STR_ACTPASS = { "actpass", 7 };
-	static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };
-
-	switch (session_media->encryption) {
-	case AST_SIP_MEDIA_ENCRYPT_NONE:
-	case AST_SIP_MEDIA_TRANSPORT_INVALID:
-		break;
-	case AST_SIP_MEDIA_ENCRYPT_SDES:
-		if (!session_media->srtp) {
-			session_media->srtp = ast_sdp_srtp_alloc();
-			if (!session_media->srtp) {
-				return -1;
-			}
-		}
-
-		crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp,
-			0 /* DTLS running? No */,
-			session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */);
-		if (!crypto_attribute) {
-			/* No crypto attribute to add, bad news */
-			return -1;
-		}
-
-		attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute));
-		media->attr[media->attr_count++] = attr;
-		break;
-	case AST_SIP_MEDIA_ENCRYPT_DTLS:
-		if (setup_dtls_srtp(session, session_media)) {
-			return -1;
-		}
-
-		dtls = ast_rtp_instance_get_dtls(session_media->rtp);
-		if (!dtls) {
-			return -1;
-		}
-
-		switch (dtls->get_connection(session_media->rtp)) {
-		case AST_RTP_DTLS_CONNECTION_NEW:
-			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_NEW);
-			media->attr[media->attr_count++] = attr;
-			break;
-		case AST_RTP_DTLS_CONNECTION_EXISTING:
-			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_EXISTING);
-			media->attr[media->attr_count++] = attr;
-			break;
-		default:
-			break;
-		}
-
-		switch (dtls->get_setup(session_media->rtp)) {
-		case AST_RTP_DTLS_SETUP_ACTIVE:
-			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE);
-			media->attr[media->attr_count++] = attr;
-			break;
-		case AST_RTP_DTLS_SETUP_PASSIVE:
-			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_PASSIVE);
-			media->attr[media->attr_count++] = attr;
-			break;
-		case AST_RTP_DTLS_SETUP_ACTPASS:
-			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTPASS);
-			media->attr[media->attr_count++] = attr;
-			break;
-		case AST_RTP_DTLS_SETUP_HOLDCONN:
-			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN);
-			media->attr[media->attr_count++] = attr;
-			break;
-		default:
-			break;
-		}
-
-		hash = dtls->get_fingerprint_hash(session_media->rtp);
-		crypto_attribute = dtls->get_fingerprint(session_media->rtp);
-		if (crypto_attribute && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) {
-			RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free);
-			if (!fingerprint) {
-				return -1;
-			}
-
-			if (hash == AST_RTP_DTLS_HASH_SHA1) {
-				ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
-			} else {
-				ast_str_set(&fingerprint, 0, "SHA-256 %s", crypto_attribute);
-			}
-
-			attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint)));
-			media->attr[media->attr_count++] = attr;
-		}
-		break;
-	}
-
-	return 0;
-}
-
-/*! \brief Function which creates an outgoing stream */
-static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-				      struct pjmedia_sdp_session *sdp)
-{
-	pj_pool_t *pool = session->inv_session->pool_prov;
-	static const pj_str_t STR_IN = { "IN", 2 };
-	static const pj_str_t STR_IP4 = { "IP4", 3};
-	static const pj_str_t STR_IP6 = { "IP6", 3};
-	static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
-	pjmedia_sdp_media *media;
-	char hostip[PJ_INET6_ADDRSTRLEN+2];
-	struct ast_sockaddr addr;
-	char tmp[512];
-	pj_str_t stmp;
-	pjmedia_sdp_attr *attr;
-	int index = 0;
-	int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0;
-	int min_packet_size = 0, max_packet_size = 0;
-	int rtp_code;
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
-	int use_override_prefs = ast_format_cap_count(session->req_caps);
-
-	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
-		ast_format_cap_count(session->direct_media_cap);
-
-	if ((use_override_prefs && !ast_format_cap_has_type(session->req_caps, media_type)) ||
-	    (!use_override_prefs && !ast_format_cap_has_type(session->endpoint->media.codecs, media_type))) {
-		/* If no type formats are configured don't add a stream */
-		return 0;
-	} else if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->media.rtp.ipv6)) {
-		return -1;
-	}
-
-	if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
-		!(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
-		return -1;
-	}
-
-	if (add_crypto_to_stream(session, session_media, pool, media)) {
-		return -1;
-	}
-
-	media->desc.media = pj_str(session_media->stream_type);
-	if (pj_strlen(&session_media->transport)) {
-		/* If a transport has already been specified use it */
-		media->desc.transport = session_media->transport;
-	} else {
-		media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
-			/* Optimistic encryption places crypto in the normal RTP/AVP profile */
-			!session->endpoint->media.rtp.encryption_optimistic &&
-				(session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES),
-			session_media->rtp, session->endpoint->media.rtp.use_avpf,
-			session->endpoint->media.rtp.force_avp));
-	}
-
-	/* Add connection level details */
-	if (direct_media_enabled) {
-		ast_copy_string(hostip, ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR), sizeof(hostip));
-	} else if (ast_strlen_zero(session->endpoint->media.address)) {
-		pj_sockaddr localaddr;
-
-		if (pj_gethostip(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET(), &localaddr)) {
-			return -1;
-		}
-		pj_sockaddr_print(&localaddr, hostip, sizeof(hostip), 2);
-	} else {
-		ast_copy_string(hostip, session->endpoint->media.address, sizeof(hostip));
-	}
-
-	media->conn->net_type = STR_IN;
-	media->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
-	pj_strdup2(pool, &media->conn->addr, hostip);
-	ast_rtp_instance_get_local_address(session_media->rtp, &addr);
-	media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
-	media->desc.port_count = 1;
-
-	/* Add ICE attributes and candidates */
-	add_ice_to_stream(session, session_media, pool, media);
-
-	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
-		return -1;
-	}
-
-	if (direct_media_enabled) {
-		ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
-	} else if (!ast_format_cap_count(session->req_caps) ||
-		!ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) {
-		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
-	} else {
-		ast_format_cap_append_from_cap(caps, session->req_caps, media_type);
-	}
-
-	for (index = 0; index < ast_format_cap_count(caps); ++index) {
-		struct ast_format *format = ast_format_cap_get_format(caps, index);
-
-		if (ast_format_get_type(format) != media_type) {
-			ao2_ref(format, -1);
-			continue;
-		}
-
-		if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) {
-			ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
-			ao2_ref(format, -1);
-			continue;
-		}
-
-		if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, format, 0))) {
-			ao2_ref(format, -1);
-			continue;
-		}
-		media->attr[media->attr_count++] = attr;
-
-		if ((attr = generate_fmtp_attr(pool, format, rtp_code))) {
-			media->attr[media->attr_count++] = attr;
-		}
-
-		if (ast_format_get_maximum_ms(format) &&
-			((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) {
-			max_packet_size = ast_format_get_maximum_ms(format);
-		}
-		ao2_ref(format, -1);
-	}
-
-	/* Add non-codec formats */
-	if (media_type != AST_MEDIA_TYPE_VIDEO) {
-		for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) {
-			if (!(noncodec & index) || (rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp),
-											   0, NULL, index)) == -1) {
-				continue;
-			}
-
-			if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 0, NULL, index))) {
-				continue;
-			}
-
-			media->attr[media->attr_count++] = attr;
-
-			if (index == AST_RTP_DTMF) {
-				snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code);
-				attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
-				media->attr[media->attr_count++] = attr;
-			}
-		}
-	}
-
-	/* If no formats were actually added to the media stream don't add it to the SDP */
-	if (!media->desc.fmt_count) {
-		return 1;
-	}
-
-	/* If ptime is set add it as an attribute */
-	min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(session_media->rtp));
-	if (!min_packet_size) {
-		min_packet_size = ast_format_cap_get_framing(caps);
-	}
-	if (min_packet_size) {
-		snprintf(tmp, sizeof(tmp), "%d", min_packet_size);
-		attr = pjmedia_sdp_attr_create(pool, "ptime", pj_cstr(&stmp, tmp));
-		media->attr[media->attr_count++] = attr;
-	}
-
-	if (max_packet_size) {
-		snprintf(tmp, sizeof(tmp), "%d", max_packet_size);
-		attr = pjmedia_sdp_attr_create(pool, "maxptime", pj_cstr(&stmp, tmp));
-		media->attr[media->attr_count++] = attr;
-	}
-
-	/* Add the sendrecv attribute - we purposely don't keep track because pjmedia-sdp will automatically change our offer for us */
-	attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
-	attr->name = STR_SENDRECV;
-	media->attr[media->attr_count++] = attr;
-
-	/* Add the media stream to the SDP */
-	sdp->media[sdp->media_count++] = media;
-
-	return 1;
-}
-
-static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-				       const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
-				       const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
-{
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
-	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
-	char host[NI_MAXHOST];
-	int fdno, res;
-
-	if (!session->channel) {
-		return 1;
-	}
-
-	if (!local_stream->desc.port || !remote_stream->desc.port) {
-		return 1;
-	}
-
-	/* Ensure incoming transport is compatible with the endpoint's configuration */
-	if (!session->endpoint->media.rtp.use_received_transport &&
-		check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
-		return -1;
-	}
-
-	/* Create an RTP instance if need be */
-	if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->media.rtp.ipv6)) {
-		return -1;
-	}
-
-	res = setup_media_encryption(session, session_media, remote, remote_stream);
-	if (!session->endpoint->media.rtp.encryption_optimistic && res) {
-		/* If optimistic encryption is disabled and crypto should have been enabled but was not
-		 * this session must fail.
-		 */
-		return -1;
-	}
-
-	if (!remote_stream->conn && !remote->conn) {
-		return 1;
-	}
-
-	ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
-	}
-
-	/* Apply connection information to the RTP instance */
-	ast_sockaddr_set_port(addrs, remote_stream->desc.port);
-	ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
-	if (set_caps(session, session_media, local_stream)) {
-		return 1;
-	}
-
-	if ((fdno = media_type_to_fdno(media_type)) < 0) {
-		return -1;
-	}
-	ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0));
-	ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1));
-
-	/* If ICE support is enabled find all the needed attributes */
-	process_ice_attributes(session, session_media, remote, remote_stream);
-
-	/* Ensure the RTP instance is active */
-	ast_rtp_instance_activate(session_media->rtp);
-
-	/* audio stream handles music on hold */
-	if (media_type != AST_MEDIA_TYPE_AUDIO) {
-		return 1;
-	}
-
-	if (ast_sockaddr_isnull(addrs) ||
-		ast_sockaddr_is_any(addrs) ||
-		pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
-		if (!session_media->held) {
-			/* The remote side has put us on hold */
-			ast_queue_hold(session->channel, session->endpoint->mohsuggest);
-			ast_rtp_instance_stop(session_media->rtp);
-			ast_queue_frame(session->channel, &ast_null_frame);
-			session_media->held = 1;
-		}
-	} else if (session_media->held) {
-		/* The remote side has taken us off hold */
-		ast_queue_unhold(session->channel);
-		ast_queue_frame(session->channel, &ast_null_frame);
-		session_media->held = 0;
-	}
-
-	/* This purposely resets the encryption to the configured in case it gets added later */
-	session_media->encryption = session->endpoint->media.rtp.encryption;
-
-	return 1;
-}
-
-/*! \brief Function which updates the media stream with external media address, if applicable */
-static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
-{
-	char host[NI_MAXHOST];
-	struct ast_sockaddr addr = { { 0, } };
-
-	/* If the stream has been rejected there will be no connection line */
-	if (!stream->conn) {
-		return;
-	}
-
-	ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
-	ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
-
-	/* Is the address within the SDP inside the same network? */
-	if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) {
-		return;
-	}
-
-	pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
-}
-
-/*! \brief Function which destroys the RTP instance when session ends */
-static void stream_destroy(struct ast_sip_session_media *session_media)
-{
-	if (session_media->rtp) {
-		ast_rtp_instance_stop(session_media->rtp);
-		ast_rtp_instance_destroy(session_media->rtp);
-	}
-	session_media->rtp = NULL;
-}
-
-/*! \brief SDP handler for 'audio' media stream */
-static struct ast_sip_session_sdp_handler audio_sdp_handler = {
-	.id = STR_AUDIO,
-	.negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
-	.create_outgoing_sdp_stream = create_outgoing_sdp_stream,
-	.apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
-	.change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
-	.stream_destroy = stream_destroy,
-};
-
-/*! \brief SDP handler for 'video' media stream */
-static struct ast_sip_session_sdp_handler video_sdp_handler = {
-	.id = STR_VIDEO,
-	.negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
-	.create_outgoing_sdp_stream = create_outgoing_sdp_stream,
-	.apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
-	.change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
-	.stream_destroy = stream_destroy,
-};
-
-static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-	pjsip_tx_data *tdata;
-
-	if (!ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
-				     "application",
-				     "media_control+xml")) {
-		return 0;
-	}
-
-	ast_queue_control(session->channel, AST_CONTROL_VIDUPDATE);
-
-	if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL, &tdata) == PJ_SUCCESS) {
-		pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
-	}
-
-	return 0;
-}
-
-static struct ast_sip_session_supplement video_info_supplement = {
-	.method = "INFO",
-	.incoming_request = video_info_incoming_request,
-};
-
-/*! \brief Unloads the sdp RTP/AVP module from Asterisk */
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&video_info_supplement);
-	ast_sip_session_unregister_sdp_handler(&video_sdp_handler, STR_VIDEO);
-	ast_sip_session_unregister_sdp_handler(&audio_sdp_handler, STR_AUDIO);
-
-	if (sched) {
-		ast_sched_context_destroy(sched);
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
-	ast_sockaddr_parse(&address_ipv6, "::", 0);
-
-	if (!(sched = ast_sched_context_create())) {
-		ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
-		goto end;
-	}
-
-	if (ast_sched_start_thread(sched)) {
-		ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
-		goto end;
-	}
-
-	if (ast_sip_session_register_sdp_handler(&audio_sdp_handler, STR_AUDIO)) {
-		ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_AUDIO);
-		goto end;
-	}
-
-	if (ast_sip_session_register_sdp_handler(&video_sdp_handler, STR_VIDEO)) {
-		ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_VIDEO);
-		goto end;
-	}
-
-	ast_sip_session_register_supplement(&video_info_supplement);
-
-	return AST_MODULE_LOAD_SUCCESS;
-end:
-	unload_module();
-
-	return AST_MODULE_LOAD_FAILURE;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP SDP RTP/AVP stream handler",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
-	);
diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c
deleted file mode 100644
index 97f55d3..0000000
--- a/res/res_pjsip_send_to_voicemail.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Module for managing send to voicemail requests in SIP
- *        REFER messages against PJSIP channels
- *
- * \author Jonathan Rose <jrose at digium.com>
- */
-
-/*** MODULEINFO
-	 <depend>pjproject</depend>
-	 <depend>res_pjsip</depend>
-	 <depend>res_pjsip_session</depend>
-	 <support_level>core</support_level>
-***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/pbx.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/module.h"
-
-#define DATASTORE_NAME "call_feature_send_to_vm_datastore"
-
-#define SEND_TO_VM_HEADER "PJSIP_HEADER(add,X-Digium-Call-Feature)"
-#define SEND_TO_VM_HEADER_VALUE "feature_send_to_vm"
-
-#define SEND_TO_VM_REDIRECT "REDIRECTING(reason)"
-#define SEND_TO_VM_REDIRECT_VALUE "\"send_to_vm\""
-
-static void send_response(struct ast_sip_session *session, int code, struct pjsip_rx_data *rdata)
-{
-	pjsip_tx_data *tdata;
-
-	if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) {
-		struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-
-		pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
-	}
-}
-
-static void channel_cleanup_wrapper(void *data)
-{
-	struct ast_channel *chan = data;
-	ast_channel_cleanup(chan);
-}
-
-static struct ast_datastore_info call_feature_info = {
-	.type = "REFER call feature info",
-	.destroy = channel_cleanup_wrapper,
-};
-
-static pjsip_param *get_diversion_reason(pjsip_fromto_hdr *hdr)
-{
-	static const pj_str_t reason_str = { "reason", 6 };
-	return pjsip_param_find(&hdr->other_param, &reason_str);
-}
-
-static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
-{
-	static const pj_str_t from_str = { "From", 4 };
-	static const pj_str_t diversion_str = { "Diversion", 9 };
-
-	pjsip_generic_string_hdr *hdr;
-	pj_str_t value;
-
-	if (!(hdr = pjsip_msg_find_hdr_by_name(
-		      rdata->msg_info.msg, &diversion_str, NULL))) {
-		return NULL;
-	}
-
-	pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
-
-	/* parse as a fromto header */
-	return pjsip_parse_hdr(rdata->tp_info.pool, &from_str, value.ptr,
-			       pj_strlen(&value), NULL);
-}
-
-static int has_diversion_reason(pjsip_rx_data *rdata)
-{
-	pjsip_param *reason;
-	pjsip_fromto_hdr *hdr = get_diversion_header(rdata);
-
-	return hdr &&
-		(reason = get_diversion_reason(hdr)) &&
-		!pj_stricmp2(&reason->value, SEND_TO_VM_REDIRECT_VALUE);
-}
-
-static int has_call_feature(pjsip_rx_data *rdata)
-{
-	static const pj_str_t call_feature_str = { "X-Digium-Call-Feature", 21 };
-
-	pjsip_generic_string_hdr *hdr = pjsip_msg_find_hdr_by_name(
-		rdata->msg_info.msg, &call_feature_str, NULL);
-
-	return hdr && !pj_stricmp2(&hdr->hvalue, SEND_TO_VM_HEADER_VALUE);
-}
-
-static int handle_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-
-	struct ast_datastore *sip_session_datastore;
-	struct ast_channel *other_party;
-
-	int has_feature = has_call_feature(rdata);
-	int has_reason = has_diversion_reason(rdata);
-
-	if (!has_feature && !has_reason) {
-		/* If we don't have a call feature or diversion reason or if
-		   it's not a feature this module is related to then there
-		   is nothing to do. */
-		return 0;
-	}
-
-	/* Check bridge status... */
-	other_party = ast_channel_bridge_peer(session->channel);
-	if (!other_party) {
-		/* The channel wasn't in a two party bridge */
-		ast_log(LOG_WARNING, "%s (%s) attempted to transfer to voicemail, "
-			"but was not in a two party bridge.\n",
-			ast_sorcery_object_get_id(session->endpoint),
-			ast_channel_name(session->channel));
-		send_response(session, 400, rdata);
-		return -1;
-	}
-
-	sip_session_datastore = ast_sip_session_alloc_datastore(
-		&call_feature_info, DATASTORE_NAME);
-	if (!sip_session_datastore) {
-		ast_channel_unref(other_party);
-		send_response(session, 500, rdata);
-		return -1;
-	}
-
-	sip_session_datastore->data = other_party;
-
-	if (ast_sip_session_add_datastore(session, sip_session_datastore)) {
-		ast_channel_unref(other_party);
-		ao2_ref(sip_session_datastore, -1);
-		send_response(session, 500, rdata);
-		return -1;
-	}
-	ao2_ref(sip_session_datastore, -1);
-
-	if (has_feature) {
-		pbx_builtin_setvar_helper(other_party, SEND_TO_VM_HEADER,
-					  SEND_TO_VM_HEADER_VALUE);
-	}
-
-	if (has_reason) {
-		pbx_builtin_setvar_helper(other_party, SEND_TO_VM_REDIRECT,
-					  SEND_TO_VM_REDIRECT_VALUE);
-	}
-
-	return 0;
-}
-
-static void handle_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	pjsip_status_line status = tdata->msg->line.status;
-	struct ast_datastore *feature_datastore =
-		ast_sip_session_get_datastore(session, DATASTORE_NAME);
-	struct ast_channel *target_chan;
-
-	if (!feature_datastore) {
-		return;
-	}
-
-	/* Since we are handling the response, there is no need to keep the datastore in the session anymore. */
-	ast_sip_session_remove_datastore(session, DATASTORE_NAME);
-
-	/* If the response >= 300, the refer failed and we need to clear the feature. */
-	if (status.code >= 300) {
-		target_chan = feature_datastore->data;
-		pbx_builtin_setvar_helper(target_chan, SEND_TO_VM_HEADER, NULL);
-		pbx_builtin_setvar_helper(target_chan, SEND_TO_VM_REDIRECT, NULL);
-	}
-	ao2_ref(feature_datastore, -1);
-}
-
-static struct ast_sip_session_supplement refer_supplement = {
-	.method = "REFER",
-	.incoming_request = handle_incoming_request,
-	.outgoing_response = handle_outgoing_response,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	if (ast_sip_session_register_supplement(&refer_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register Send to Voicemail supplement\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_session_unregister_supplement(&refer_supplement);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP REFER Send to Voicemail Support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_APP_DEPEND,
-	);
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
deleted file mode 100644
index 4467203..0000000
--- a/res/res_pjsip_session.c
+++ /dev/null
@@ -1,2374 +0,0 @@
-/*
-* Asterisk -- An open source telephony toolkit.
-*
-* Copyright (C) 2013, Digium, Inc.
-*
-* Mark Michelson <mmichelson at digium.com>
-*
-* See http://www.asterisk.org for more information about
-* the Asterisk project. Please do not directly contact
-* any of the maintainers of this project for assistance;
-* the project provides a web site, mailing lists and IRC
-* channels for your use.
-*
-* This program is free software, distributed under the terms of
-* the GNU General Public License Version 2. See the LICENSE file
-* at the top of the source tree.
-*/
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjlib.h>
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/datastore.h"
-#include "asterisk/module.h"
-#include "asterisk/logger.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/lock.h"
-#include "asterisk/uuid.h"
-#include "asterisk/pbx.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/causes.h"
-#include "asterisk/sdp_srtp.h"
-#include "asterisk/dsp.h"
-#include "asterisk/acl.h"
-#include "asterisk/features_config.h"
-#include "asterisk/pickup.h"
-
-#define SDP_HANDLER_BUCKETS 11
-
-#define MOD_DATA_ON_RESPONSE "on_response"
-#define MOD_DATA_NAT_HOOK "nat_hook"
-
-/* Some forward declarations */
-static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type);
-static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type,
-		enum ast_sip_session_response_priority response_priority);
-static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type,
-		enum ast_sip_session_response_priority response_priority);
-static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata);
-static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata);
-static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata);
-
-/*! \brief NAT hook for modifying outgoing messages with SDP */
-static struct ast_sip_nat_hook *nat_hook;
-
-/*!
- * \brief Registered SDP stream handlers
- *
- * This container is keyed on stream types. Each
- * object in the container is a linked list of
- * handlers for the stream type.
- */
-static struct ao2_container *sdp_handlers;
-
-/*!
- * These are the objects in the sdp_handlers container
- */
-struct sdp_handler_list {
-	/* The list of handlers to visit */
-	AST_LIST_HEAD_NOLOCK(, ast_sip_session_sdp_handler) list;
-	/* The handlers in this list handle streams of this type */
-	char stream_type[1];
-};
-
-static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer);
-
-static int sdp_handler_list_hash(const void *obj, int flags)
-{
-	const struct sdp_handler_list *handler_list = obj;
-	const char *stream_type = flags & OBJ_KEY ? obj : handler_list->stream_type;
-
-	return ast_str_hash(stream_type);
-}
-
-static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
-{
-	struct sdp_handler_list *handler_list1 = obj;
-	struct sdp_handler_list *handler_list2 = arg;
-	const char *stream_type2 = flags & OBJ_KEY ? arg : handler_list2->stream_type;
-
-	return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-static int session_media_hash(const void *obj, int flags)
-{
-	const struct ast_sip_session_media *session_media = obj;
-	const char *stream_type = flags & OBJ_KEY ? obj : session_media->stream_type;
-
-	return ast_str_hash(stream_type);
-}
-
-static int session_media_cmp(void *obj, void *arg, int flags)
-{
-	struct ast_sip_session_media *session_media1 = obj;
-	struct ast_sip_session_media *session_media2 = arg;
-	const char *stream_type2 = flags & OBJ_KEY ? arg : session_media2->stream_type;
-
-	return strcmp(session_media1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
-{
-	RAII_VAR(struct sdp_handler_list *, handler_list,
-			ao2_find(sdp_handlers, stream_type, OBJ_KEY), ao2_cleanup);
-	SCOPED_AO2LOCK(lock, sdp_handlers);
-
-	if (handler_list) {
-		struct ast_sip_session_sdp_handler *iter;
-		/* Check if this handler is already registered for this stream type */
-		AST_LIST_TRAVERSE(&handler_list->list, iter, next) {
-			if (!strcmp(iter->id, handler->id)) {
-				ast_log(LOG_WARNING, "Handler '%s' already registered for stream type '%s'.\n", handler->id, stream_type);
-				return -1;
-			}
-		}
-		AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
-		ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
-		ast_module_ref(ast_module_info->self);
-		return 0;
-	}
-
-	/* No stream of this type has been registered yet, so we need to create a new list */
-	handler_list = ao2_alloc(sizeof(*handler_list) + strlen(stream_type), NULL);
-	if (!handler_list) {
-		return -1;
-	}
-	/* Safe use of strcpy */
-	strcpy(handler_list->stream_type, stream_type);
-	AST_LIST_HEAD_INIT_NOLOCK(&handler_list->list);
-	AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
-	if (!ao2_link(sdp_handlers, handler_list)) {
-		return -1;
-	}
-	ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-static int remove_handler(void *obj, void *arg, void *data, int flags)
-{
-	struct sdp_handler_list *handler_list = obj;
-	struct ast_sip_session_sdp_handler *handler = data;
-	struct ast_sip_session_sdp_handler *iter;
-	const char *stream_type = arg;
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&handler_list->list, iter, next) {
-		if (!strcmp(iter->id, handler->id)) {
-			AST_LIST_REMOVE_CURRENT(next);
-			ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
-			ast_module_unref(ast_module_info->self);
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	if (AST_LIST_EMPTY(&handler_list->list)) {
-		ast_debug(3, "No more handlers exist for stream type '%s'\n", stream_type);
-		return CMP_MATCH;
-	} else {
-		return CMP_STOP;
-	}
-}
-
-void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
-{
-	ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
-}
-
-/*!
- * \brief Set an SDP stream handler for a corresponding session media.
- *
- * \note Always use this function to set the SDP handler for a session media.
- *
- * This function will properly free resources on the SDP handler currently being
- * used by the session media, then set the session media to use the new SDP
- * handler.
- */
-static void session_media_set_handler(struct ast_sip_session_media *session_media,
-		struct ast_sip_session_sdp_handler *handler)
-{
-	ast_assert(session_media->handler != handler);
-
-	if (session_media->handler) {
-		session_media->handler->stream_destroy(session_media);
-	}
-	session_media->handler = handler;
-}
-
-static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
-{
-	int i;
-	int handled = 0;
-
-	for (i = 0; i < sdp->media_count; ++i) {
-		/* See if there are registered handlers for this media stream type */
-		char media[20];
-		struct ast_sip_session_sdp_handler *handler;
-		RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-		int res;
-
-		/* We need a null-terminated version of the media string */
-		ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
-
-		session_media = ao2_find(session->media, media, OBJ_KEY);
-		if (!session_media) {
-			/* if the session_media doesn't exist, there weren't
-			 * any handlers at the time of its creation */
-			continue;
-		}
-
-		if (session_media->handler) {
-			handler = session_media->handler;
-			ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",
-				session_media->stream_type,
-				session_media->handler->id);
-			res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp,
-				sdp->media[i]);
-			if (res < 0) {
-				/* Catastrophic failure. Abort! */
-				return -1;
-			} else if (res > 0) {
-				ast_debug(1, "Media stream '%s' handled by %s\n",
-					session_media->stream_type,
-					session_media->handler->id);
-				/* Handled by this handler. Move to the next stream */
-				handled = 1;
-				continue;
-			}
-		}
-
-		handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
-		if (!handler_list) {
-			ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
-			continue;
-		}
-		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-			if (handler == session_media->handler) {
-				continue;
-			}
-			ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",
-				session_media->stream_type,
-				handler->id);
-			res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp,
-				sdp->media[i]);
-			if (res < 0) {
-				/* Catastrophic failure. Abort! */
-				return -1;
-			}
-			if (res > 0) {
-				ast_debug(1, "Media stream '%s' handled by %s\n",
-					session_media->stream_type,
-					handler->id);
-				/* Handled by this handler. Move to the next stream */
-				session_media_set_handler(session_media, handler);
-				handled = 1;
-				break;
-			}
-		}
-	}
-	if (!handled) {
-		return -1;
-	}
-	return 0;
-}
-
-struct handle_negotiated_sdp_cb {
-	struct ast_sip_session *session;
-	const pjmedia_sdp_session *local;
-	const pjmedia_sdp_session *remote;
-};
-
-static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags)
-{
-	struct ast_sip_session_media *session_media = obj;
-	struct handle_negotiated_sdp_cb *callback_data = arg;
-	struct ast_sip_session *session = callback_data->session;
-	const pjmedia_sdp_session *local = callback_data->local;
-	const pjmedia_sdp_session *remote = callback_data->remote;
-	int i;
-
-	for (i = 0; i < local->media_count; ++i) {
-		/* See if there are registered handlers for this media stream type */
-		char media[20];
-		struct ast_sip_session_sdp_handler *handler;
-		RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
-		int res;
-
-		if (!remote->media[i]) {
-			continue;
-		}
-
-		/* We need a null-terminated version of the media string */
-		ast_copy_pj_str(media, &local->media[i]->desc.media, sizeof(media));
-
-		/* stream type doesn't match the one we're looking to fill */
-		if (strcasecmp(session_media->stream_type, media)) {
-			continue;
-		}
-
-		handler = session_media->handler;
-		if (handler) {
-			ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",
-				session_media->stream_type,
-				handler->id);
-			res = handler->apply_negotiated_sdp_stream(session, session_media, local,
-				local->media[i], remote, remote->media[i]);
-			if (res >= 0) {
-				ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",
-					session_media->stream_type,
-					handler->id);
-				return CMP_MATCH;
-			}
-			return 0;
-		}
-
-		handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
-		if (!handler_list) {
-			ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
-			continue;
-		}
-		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-			if (handler == session_media->handler) {
-				continue;
-			}
-			ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",
-				session_media->stream_type,
-				handler->id);
-			res = handler->apply_negotiated_sdp_stream(session, session_media, local,
-				local->media[i], remote, remote->media[i]);
-			if (res < 0) {
-				/* Catastrophic failure. Abort! */
-				return 0;
-			}
-			if (res > 0) {
-				ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",
-					session_media->stream_type,
-					handler->id);
-				/* Handled by this handler. Move to the next stream */
-				session_media_set_handler(session_media, handler);
-				return CMP_MATCH;
-			}
-		}
-	}
-	return CMP_MATCH;
-}
-
-static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
-{
-	RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
-	struct handle_negotiated_sdp_cb callback_data = {
-		.session = session,
-		.local = local,
-		.remote = remote,
-	};
-
-	successful = ao2_callback(session->media, OBJ_MULTIPLE, handle_negotiated_sdp_session_media, &callback_data);
-	if (successful && ao2_iterator_count(successful) == ao2_container_count(session->media)) {
-		/* Nothing experienced a catastrophic failure */
-		ast_queue_frame(session->channel, &ast_null_frame);
-		return 0;
-	}
-	return -1;
-}
-
-AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement);
-
-int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement)
-{
-	struct ast_sip_session_supplement *iter;
-	int inserted = 0;
-	SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
-	if (!supplement->response_priority) {
-		supplement->response_priority = AST_SIP_SESSION_BEFORE_MEDIA;
-	}
-
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
-		if (iter->priority > supplement->priority) {
-			AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
-			inserted = 1;
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-
-	if (!inserted) {
-		AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next);
-	}
-	ast_module_ref(ast_module_info->self);
-	return 0;
-}
-
-void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
-{
-	struct ast_sip_session_supplement *iter;
-	SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
-		if (supplement == iter) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			ast_module_unref(ast_module_info->self);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src)
-{
-	struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst));
-	if (!dst) {
-		return NULL;
-	}
-	/* Will need to revisit if shallow copy becomes an issue */
-	*dst = *src;
-	return dst;
-}
-
-#define DATASTORE_BUCKETS 53
-#define MEDIA_BUCKETS 7
-
-static void session_datastore_destroy(void *obj)
-{
-	struct ast_datastore *datastore = obj;
-
-	/* Using the destroy function (if present) destroy the data */
-	if (datastore->info->destroy != NULL && datastore->data != NULL) {
-		datastore->info->destroy(datastore->data);
-		datastore->data = NULL;
-	}
-
-	ast_free((void *) datastore->uid);
-	datastore->uid = NULL;
-}
-
-struct ast_datastore *ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
-{
-	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
-	char uuid_buf[AST_UUID_STR_LEN];
-	const char *uid_ptr = uid;
-
-	if (!info) {
-		return NULL;
-	}
-
-	datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
-	if (!datastore) {
-		return NULL;
-	}
-
-	datastore->info = info;
-	if (ast_strlen_zero(uid)) {
-		/* They didn't provide an ID so we'll provide one ourself */
-		uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
-	}
-
-	datastore->uid = ast_strdup(uid_ptr);
-	if (!datastore->uid) {
-		return NULL;
-	}
-
-	ao2_ref(datastore, +1);
-	return datastore;
-}
-
-int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
-{
-	ast_assert(datastore != NULL);
-	ast_assert(datastore->info != NULL);
-	ast_assert(ast_strlen_zero(datastore->uid) == 0);
-
-	if (!ao2_link(session->datastores, datastore)) {
-		return -1;
-	}
-	return 0;
-}
-
-struct ast_datastore *ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
-{
-	return ao2_find(session->datastores, name, OBJ_KEY);
-}
-
-void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
-{
-	ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
-}
-
-/*!
- * \brief Structure used for sending delayed requests
- *
- * Requests are typically delayed because the current transaction
- * state of an INVITE. Once the pending INVITE transaction terminates,
- * the delayed request will be sent
- */
-struct ast_sip_session_delayed_request {
-	/*! Method of the request */
-	char method[15];
-	/*! Callback to call when the delayed request is created. */
-	ast_sip_session_request_creation_cb on_request_creation;
-	/*! Callback to call when the delayed request SDP is created */
-	ast_sip_session_sdp_creation_cb on_sdp_creation;
-	/*! Callback to call when the delayed request receives a response */
-	ast_sip_session_response_cb on_response;
-	/*! Whether to generate new SDP */
-	int generate_new_sdp;
-	AST_LIST_ENTRY(ast_sip_session_delayed_request) next;
-};
-
-static struct ast_sip_session_delayed_request *delayed_request_alloc(const char *method,
-		ast_sip_session_request_creation_cb on_request_creation,
-		ast_sip_session_sdp_creation_cb on_sdp_creation,
-		ast_sip_session_response_cb on_response,
-		int generate_new_sdp)
-{
-	struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay));
-	if (!delay) {
-		return NULL;
-	}
-	ast_copy_string(delay->method, method, sizeof(delay->method));
-	delay->on_request_creation = on_request_creation;
-	delay->on_sdp_creation = on_sdp_creation;
-	delay->on_response = on_response;
-	delay->generate_new_sdp = generate_new_sdp;
-	return delay;
-}
-
-static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
-{
-	ast_debug(3, "Sending delayed %s request to %s\n", delay->method, ast_sorcery_object_get_id(session->endpoint));
-
-	if (!strcmp(delay->method, "INVITE")) {
-		ast_sip_session_refresh(session, delay->on_request_creation,
-				delay->on_sdp_creation, delay->on_response, AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp);
-	} else if (!strcmp(delay->method, "UPDATE")) {
-		ast_sip_session_refresh(session, delay->on_request_creation,
-				delay->on_sdp_creation, delay->on_response, AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp);
-	} else {
-		ast_log(LOG_WARNING, "Unexpected delayed %s request with no existing request structure\n", delay->method);
-		return -1;
-	}
-	return 0;
-}
-
-static int queued_delayed_request_send(void *data)
-{
-	RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
-	RAII_VAR(struct ast_sip_session_delayed_request *, delay, NULL, ast_free_ptr);
-
-	delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next);
-	if (!delay) {
-		return 0;
-	}
-
-	return send_delayed_request(session, delay);
-}
-
-static void queue_delayed_request(struct ast_sip_session *session)
-{
-	if (AST_LIST_EMPTY(&session->delayed_requests)) {
-		/* No delayed request to send, so just return */
-		return;
-	}
-
-	ast_debug(3, "Queuing delayed request to run for %s\n",
-			ast_sorcery_object_get_id(session->endpoint));
-
-	ao2_ref(session, +1);
-	ast_sip_push_task(session->serializer, queued_delayed_request_send, session);
-}
-
-static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request,
-		ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response,
-		int generate_new_sdp, const char *method)
-{
-	struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method,
-			on_request, on_sdp_creation, on_response, generate_new_sdp);
-
-	if (!delay) {
-		return -1;
-	}
-
-	AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
-	return 0;
-}
-
-static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session)
-{
-	pjsip_inv_session *inv_session = session->inv_session;
-	const pjmedia_sdp_session *previous_sdp;
-
-	if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
-		pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
-	} else {
-		pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
-	}
-	return create_local_sdp(inv_session, session, previous_sdp);
-}
-
-int ast_sip_session_refresh(struct ast_sip_session *session,
-		ast_sip_session_request_creation_cb on_request_creation,
-		ast_sip_session_sdp_creation_cb on_sdp_creation,
-		ast_sip_session_response_cb on_response,
-		enum ast_sip_session_refresh_method method, int generate_new_sdp)
-{
-	pjsip_inv_session *inv_session = session->inv_session;
-	pjmedia_sdp_session *new_sdp = NULL;
-	pjsip_tx_data *tdata;
-
-	if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
-		/* Don't try to do anything with a hung-up call */
-		ast_debug(3, "Not sending reinvite to %s because of disconnected state...\n",
-				ast_sorcery_object_get_id(session->endpoint));
-		return 0;
-	}
-
-	/* If the dialog has not yet been established we have to defer until it has */
-	if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
-		ast_debug(3, "Delaying sending request to %s because dialog has not been established...\n",
-			ast_sorcery_object_get_id(session->endpoint));
-		return delay_request(session, on_request_creation, on_sdp_creation, on_response, generate_new_sdp,
-			method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "INVITE" : "UPDATE");
-	}
-
-	if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {
-		if (inv_session->invite_tsx) {
-			/* We can't send a reinvite yet, so delay it */
-			ast_debug(3, "Delaying sending reinvite to %s because of outstanding transaction...\n",
-					ast_sorcery_object_get_id(session->endpoint));
-			return delay_request(session, on_request_creation, on_sdp_creation, on_response,
-				generate_new_sdp, "INVITE");
-		} else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
-			/* Initial INVITE transaction failed to progress us to a confirmed state
-			 * which means re-invites are not possible
-			 */
-			ast_debug(3, "Not sending reinvite to %s because not in confirmed state...\n",
-					ast_sorcery_object_get_id(session->endpoint));
-			return 0;
-		}
-	}
-
-	if (generate_new_sdp) {
-		/* SDP can only be generated if current negotiation has already completed */
-		if (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
-			ast_debug(3, "Delaying session refresh with new SDP to %s because SDP negotiation is not yet done...\n",
-				ast_sorcery_object_get_id(session->endpoint));
-			return delay_request(session, on_request_creation, on_sdp_creation, on_response, generate_new_sdp,
-				method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "INVITE" : "UPDATE");
-		}
-
-		new_sdp = generate_session_refresh_sdp(session);
-		if (!new_sdp) {
-			ast_log(LOG_ERROR, "Failed to generate session refresh SDP. Not sending session refresh\n");
-			return -1;
-		}
-		if (on_sdp_creation) {
-			if (on_sdp_creation(session, new_sdp)) {
-				return -1;
-			}
-		}
-	}
-
-	if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {
-		if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
-			ast_log(LOG_WARNING, "Failed to create reinvite properly.\n");
-			return -1;
-		}
-	} else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
-		ast_log(LOG_WARNING, "Failed to create UPDATE properly.\n");
-		return -1;
-	}
-	if (on_request_creation) {
-		if (on_request_creation(session, tdata)) {
-			return -1;
-		}
-	}
-	ast_debug(3, "Sending session refresh SDP via %s to %s\n",
-		method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE",
-		ast_sorcery_object_get_id(session->endpoint));
-	ast_sip_session_send_request_with_cb(session, tdata, on_response);
-	return 0;
-}
-
-void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	handle_outgoing_response(session, tdata);
-	pjsip_inv_send_msg(session->inv_session, tdata);
-	return;
-}
-
-static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata);
-
-static pjsip_module session_module = {
-	.name = {"Session Module", 14},
-	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
-	.on_rx_request = session_on_rx_request,
-};
-
-/*! \brief Determine whether the SDP provided requires deferral of negotiating or not
- *
- * \retval 1 re-invite should be deferred and resumed later
- * \retval 0 re-invite should not be deferred
- */
-static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
-{
-	int i;
-
-	for (i = 0; i < sdp->media_count; ++i) {
-		/* See if there are registered handlers for this media stream type */
-		char media[20];
-		struct ast_sip_session_sdp_handler *handler;
-		RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-		enum ast_sip_session_sdp_stream_defer res;
-
-		/* We need a null-terminated version of the media string */
-		ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
-
-		session_media = ao2_find(session->media, media, OBJ_KEY);
-		if (!session_media) {
-			/* if the session_media doesn't exist, there weren't
-			 * any handlers at the time of its creation */
-			continue;
-		}
-
-		if (session_media->handler) {
-			handler = session_media->handler;
-			if (handler->defer_incoming_sdp_stream) {
-				res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
-					sdp->media[i]);
-				switch (res) {
-				case AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED:
-					break;
-				case AST_SIP_SESSION_SDP_DEFER_ERROR:
-					return 0;
-				case AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED:
-					break;
-				case AST_SIP_SESSION_SDP_DEFER_NEEDED:
-					return 1;
-				}
-			}
-			/* Handled by this handler. Move to the next stream */
-			continue;
-		}
-
-		handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
-		if (!handler_list) {
-			ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
-			continue;
-		}
-		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-			if (handler == session_media->handler) {
-				continue;
-			}
-			if (!handler->defer_incoming_sdp_stream) {
-				continue;
-			}
-			res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
-				sdp->media[i]);
-			switch (res) {
-			case AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED:
-				continue;
-			case AST_SIP_SESSION_SDP_DEFER_ERROR:
-				session_media_set_handler(session_media, handler);
-				return 0;
-			case AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED:
-				/* Handled by this handler. */
-				session_media_set_handler(session_media, handler);
-				break;
-			case AST_SIP_SESSION_SDP_DEFER_NEEDED:
-				/* Handled by this handler. */
-				session_media_set_handler(session_media, handler);
-				return 1;
-			}
-			/* Move to the next stream */
-			break;
-		}
-	}
-	return 0;
-}
-
-static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata)
-{
-	pjsip_dialog *dlg;
-	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-	pjsip_rdata_sdp_info *sdp_info;
-
-	if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
-		!(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
-		!(session = ast_sip_dialog_get_session(dlg))) {
-		return PJ_FALSE;
-	}
-
-	if (session->deferred_reinvite) {
-		pj_str_t key, deferred_key;
-		pjsip_tx_data *tdata;
-
-		/* We use memory from the new request on purpose so the deferred reinvite pool does not grow uncontrollably */
-		pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata);
-		pjsip_tsx_create_key(rdata->tp_info.pool, &deferred_key, PJSIP_ROLE_UAS, &session->deferred_reinvite->msg_info.cseq->method,
-			session->deferred_reinvite);
-
-		/* If this is a retransmission ignore it */
-		if (!pj_strcmp(&key, &deferred_key)) {
-			return PJ_TRUE;
-		}
-
-		/* Otherwise this is a new re-invite, so reject it */
-		if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) {
-			pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
-		}
-
-		return PJ_TRUE;
-	}
-
-	if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
-		(sdp_info->sdp_err != PJ_SUCCESS)) {
-		return PJ_FALSE;
-	}
-
-	if (!sdp_info->sdp) {
-		ast_queue_unhold(session->channel);
-		return PJ_FALSE;
-	}
-
-	if (!sdp_requires_deferral(session, sdp_info->sdp)) {
-		return PJ_FALSE;
-	}
-
-	pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
-
-	return PJ_TRUE;
-}
-
-void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
-{
-	if (!session->deferred_reinvite) {
-		return;
-	}
-
-	pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), session->deferred_reinvite, NULL, NULL);
-	pjsip_rx_data_free_cloned(session->deferred_reinvite);
-	session->deferred_reinvite = NULL;
-}
-
-static pjsip_module session_reinvite_module = {
-	.name = { "Session Re-Invite Module", 24 },
-	.priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
-	.on_rx_request = session_reinvite_on_rx_request,
-};
-
-void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
-		ast_sip_session_response_cb on_response)
-{
-	pjsip_inv_session *inv_session = session->inv_session;
-
-	if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
-		/* Don't try to do anything with a hung-up call */
-		return;
-	}
-
-	ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
-			     MOD_DATA_ON_RESPONSE, on_response);
-
-	if (!ast_strlen_zero(session->endpoint->fromuser) ||
-		!ast_strlen_zero(session->endpoint->fromdomain)) {
-		pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next);
-		pjsip_sip_uri *uri = pjsip_uri_get_uri(from->uri);
-
-		if (!ast_strlen_zero(session->endpoint->fromuser)) {
-			pj_strdup2(tdata->pool, &uri->user, session->endpoint->fromuser);
-		}
-		if (!ast_strlen_zero(session->endpoint->fromdomain)) {
-			pj_strdup2(tdata->pool, &uri->host, session->endpoint->fromdomain);
-		}
-	}
-
-	handle_outgoing_request(session, tdata);
-	pjsip_inv_send_msg(session->inv_session, tdata);
-	return;
-}
-
-void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	ast_sip_session_send_request_with_cb(session, tdata, NULL);
-}
-
-int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data **tdata)
-{
-	pjmedia_sdp_session *offer;
-
-	if (!(offer = create_local_sdp(session->inv_session, session, NULL))) {
-		pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
-		return -1;
-	}
-
-	pjsip_inv_set_local_sdp(session->inv_session, offer);
-	pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
-#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
-	pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
-#endif
-	if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
-		return -1;
-	}
-	return 0;
-}
-
-static int datastore_hash(const void *obj, int flags)
-{
-	const struct ast_datastore *datastore = obj;
-	const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
-
-	ast_assert(uid != NULL);
-
-	return ast_str_hash(uid);
-}
-
-static int datastore_cmp(void *obj, void *arg, int flags)
-{
-	const struct ast_datastore *datastore1 = obj;
-	const struct ast_datastore *datastore2 = arg;
-	const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
-
-	ast_assert(datastore1->uid != NULL);
-	ast_assert(uid2 != NULL);
-
-	return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-static void session_media_dtor(void *obj)
-{
-	struct ast_sip_session_media *session_media = obj;
-	struct sdp_handler_list *handler_list;
-	/* It is possible for SDP handlers to allocate memory on a session_media but
-	 * not end up getting set as the handler for this session_media. This traversal
-	 * ensures that all memory allocated by SDP handlers on the session_media is
-	 * cleared (as well as file descriptors, etc.).
-	 */
-	handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY);
-	if (handler_list) {
-		struct ast_sip_session_sdp_handler *handler;
-
-		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-			handler->stream_destroy(session_media);
-		}
-	}
-	ao2_cleanup(handler_list);
-	if (session_media->srtp) {
-		ast_sdp_srtp_destroy(session_media->srtp);
-	}
-}
-
-static void session_destructor(void *obj)
-{
-	struct ast_sip_session *session = obj;
-	struct ast_sip_session_supplement *supplement;
-	struct ast_sip_session_delayed_request *delay;
-
-	ast_debug(3, "Destroying SIP session with endpoint %s\n",
-			ast_sorcery_object_get_id(session->endpoint));
-
-	while ((supplement = AST_LIST_REMOVE_HEAD(&session->supplements, next))) {
-		if (supplement->session_destroy) {
-			supplement->session_destroy(session);
-		}
-		ast_free(supplement);
-	}
-
-	ast_taskprocessor_unreference(session->serializer);
-	ao2_cleanup(session->datastores);
-	ao2_cleanup(session->media);
-
-	AST_LIST_HEAD_DESTROY(&session->supplements);
-	while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
-		ast_free(delay);
-	}
-	ast_party_id_free(&session->id);
-	ao2_cleanup(session->endpoint);
-	ao2_cleanup(session->contact);
-	ao2_cleanup(session->req_caps);
-	ao2_cleanup(session->direct_media_cap);
-
-	if (session->dsp) {
-		ast_dsp_free(session->dsp);
-	}
-
-	if (session->inv_session) {
-		pjsip_dlg_dec_session(session->inv_session->dlg, &session_module);
-	}
-}
-
-static int add_supplements(struct ast_sip_session *session)
-{
-	struct ast_sip_session_supplement *iter;
-	SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
-	AST_RWLIST_TRAVERSE(&session_supplements, iter, next) {
-		struct ast_sip_session_supplement *copy = supplement_dup(iter);
-		if (!copy) {
-			return -1;
-		}
-		AST_LIST_INSERT_TAIL(&session->supplements, copy, next);
-	}
-	return 0;
-}
-
-static int add_session_media(void *obj, void *arg, int flags)
-{
-	struct sdp_handler_list *handler_list = obj;
-	struct ast_sip_session * session = arg;
-	RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-	session_media = ao2_alloc(sizeof(*session_media) + strlen(handler_list->stream_type), session_media_dtor);
-	if (!session_media) {
-		return CMP_STOP;
-	}
-	session_media->encryption = session->endpoint->media.rtp.encryption;
-	/* Safe use of strcpy */
-	strcpy(session_media->stream_type, handler_list->stream_type);
-	ao2_link(session->media, session_media);
-	return 0;
-}
-
-/*! \brief Destructor for SIP channel */
-static void sip_channel_destroy(void *obj)
-{
-	struct ast_sip_channel_pvt *channel = obj;
-
-	ao2_cleanup(channel->pvt);
-	ao2_cleanup(channel->session);
-}
-
-struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_session *session)
-{
-	struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
-
-	if (!channel) {
-		return NULL;
-	}
-
-	ao2_ref(pvt, +1);
-	channel->pvt = pvt;
-	ao2_ref(session, +1);
-	channel->session = session;
-
-	return channel;
-}
-
-struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
-	struct ast_sip_contact *contact, pjsip_inv_session *inv_session)
-{
-	RAII_VAR(struct ast_sip_session *, session, ao2_alloc(sizeof(*session), session_destructor), ao2_cleanup);
-	struct ast_sip_session_supplement *iter;
-	int dsp_features = 0;
-	if (!session) {
-		return NULL;
-	}
-	AST_LIST_HEAD_INIT(&session->supplements);
-	session->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
-	if (!session->datastores) {
-		return NULL;
-	}
-
-	session->endpoint = ao2_bump(endpoint);
-
-	session->media = ao2_container_alloc(MEDIA_BUCKETS, session_media_hash, session_media_cmp);
-	if (!session->media) {
-		return NULL;
-	}
-	/* fill session->media with available types */
-	ao2_callback(sdp_handlers, OBJ_NODATA, add_session_media, session);
-
-	session->serializer = ast_sip_create_serializer();
-	if (!session->serializer) {
-		return NULL;
-	}
-	ast_sip_dialog_set_serializer(inv_session->dlg, session->serializer);
-	ast_sip_dialog_set_endpoint(inv_session->dlg, endpoint);
-	pjsip_dlg_inc_session(inv_session->dlg, &session_module);
-	inv_session->mod_data[session_module.id] = ao2_bump(session);
-	session->contact = ao2_bump(contact);
-	session->inv_session = inv_session;
-	session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-
-	if (endpoint->dtmf == AST_SIP_DTMF_INBAND) {
-		dsp_features |= DSP_FEATURE_DIGIT_DETECT;
-	}
-
-	if (endpoint->faxdetect) {
-		dsp_features |= DSP_FEATURE_FAX_DETECT;
-	}
-
-	if (dsp_features) {
-		if (!(session->dsp = ast_dsp_new())) {
-			ao2_ref(session, -1);
-			return NULL;
-		}
-
-		ast_dsp_set_features(session->dsp, dsp_features);
-	}
-
-	if (add_supplements(session)) {
-		ao2_ref(session, -1);
-		return NULL;
-	}
-	AST_LIST_TRAVERSE(&session->supplements, iter, next) {
-		if (iter->session_begin) {
-			iter->session_begin(session);
-		}
-	}
-	session->direct_media_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
-	ast_party_id_init(&session->id);
-	ao2_ref(session, +1);
-	return session;
-}
-
-/*! \brief struct controlling the suspension of the session's serializer. */
-struct ast_sip_session_suspender {
-	ast_cond_t cond_suspended;
-	ast_cond_t cond_complete;
-	int suspended;
-	int complete;
-};
-
-static void sip_session_suspender_dtor(void *vdoomed)
-{
-	struct ast_sip_session_suspender *doomed = vdoomed;
-
-	ast_cond_destroy(&doomed->cond_suspended);
-	ast_cond_destroy(&doomed->cond_complete);
-}
-
-/*!
- * \internal
- * \brief Block the session serializer thread task.
- *
- * \param data Pushed serializer task data for suspension.
- *
- * \retval 0
- */
-static int sip_session_suspend_task(void *data)
-{
-	struct ast_sip_session_suspender *suspender = data;
-
-	ao2_lock(suspender);
-
-	/* Signal that the serializer task is now suspended. */
-	suspender->suspended = 1;
-	ast_cond_signal(&suspender->cond_suspended);
-
-	/* Wait for the the serializer suspension to be completed. */
-	while (!suspender->complete) {
-		ast_cond_wait(&suspender->cond_complete, ao2_object_get_lockaddr(suspender));
-	}
-
-	ao2_unlock(suspender);
-	ao2_ref(suspender, -1);
-
-	return 0;
-}
-
-void ast_sip_session_suspend(struct ast_sip_session *session)
-{
-	struct ast_sip_session_suspender *suspender;
-	int res;
-
-	ast_assert(session->suspended == NULL);
-
-	if (ast_taskprocessor_is_task(session->serializer)) {
-		/* I am the session's serializer thread so I cannot suspend. */
-		return;
-	}
-
-	suspender = ao2_alloc(sizeof(*suspender), sip_session_suspender_dtor);
-	if (!suspender) {
-		/* We will just have to hope that the system does not deadlock */
-		return;
-	}
-	ast_cond_init(&suspender->cond_suspended, NULL);
-	ast_cond_init(&suspender->cond_complete, NULL);
-
-	ao2_ref(suspender, +1);
-	res = ast_sip_push_task(session->serializer, sip_session_suspend_task, suspender);
-	if (res) {
-		/* We will just have to hope that the system does not deadlock */
-		ao2_ref(suspender, -2);
-		return;
-	}
-
-	session->suspended = suspender;
-
-	/* Wait for the serializer to get suspended. */
-	ao2_lock(suspender);
-	while (!suspender->suspended) {
-		ast_cond_wait(&suspender->cond_suspended, ao2_object_get_lockaddr(suspender));
-	}
-	ao2_unlock(suspender);
-}
-
-void ast_sip_session_unsuspend(struct ast_sip_session *session)
-{
-	struct ast_sip_session_suspender *suspender = session->suspended;
-
-	if (!suspender) {
-		/* Nothing to do */
-		return;
-	}
-	session->suspended = NULL;
-
-	/* Signal that the serializer task suspension is now complete. */
-	ao2_lock(suspender);
-	suspender->complete = 1;
-	ast_cond_signal(&suspender->cond_complete);
-	ao2_unlock(suspender);
-
-	ao2_ref(suspender, -1);
-}
-
-static int session_outbound_auth(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *user_data)
-{
-	pjsip_inv_session *inv = pjsip_dlg_get_inv_session(dlg);
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-
-	if (inv->state < PJSIP_INV_STATE_CONFIRMED && tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
-		pjsip_inv_uac_restart(inv, PJ_FALSE);
-	}
-	ast_sip_session_send_request(session, tdata);
-	return 0;
-}
-
-struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint,
-	struct ast_sip_contact *contact, const char *location, const char *request_user,
-	struct ast_format_cap *req_caps)
-{
-	const char *uri = NULL;
-	RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
-	pjsip_timer_setting timer;
-	pjsip_dialog *dlg;
-	struct pjsip_inv_session *inv_session;
-	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-
-	/* If no location has been provided use the AOR list from the endpoint itself */
-	if (location || !contact) {
-		location = S_OR(location, endpoint->aors);
-
-		found_contact = ast_sip_location_retrieve_contact_from_aor_list(location);
-		if (!found_contact || ast_strlen_zero(found_contact->uri)) {
-			uri = location;
-		} else {
-			uri = found_contact->uri;
-		}
-	} else {
-		uri = contact->uri;
-	}
-
-	/* If we still have no URI to dial fail to create the session */
-	if (ast_strlen_zero(uri)) {
-		return NULL;
-	}
-
-	if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
-		return NULL;
-	}
-
-	if (ast_sip_dialog_setup_outbound_authentication(dlg, endpoint, session_outbound_auth, NULL)) {
-		pjsip_dlg_terminate(dlg);
-		return NULL;
-	}
-
-	if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
-		pjsip_dlg_terminate(dlg);
-		return NULL;
-	}
-#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
-	inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
-#endif
-
-	pjsip_timer_setting_default(&timer);
-	timer.min_se = endpoint->extensions.timer.min_se;
-	timer.sess_expires = endpoint->extensions.timer.sess_expires;
-	pjsip_timer_init_session(inv_session, &timer);
-
-	if (!(session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact, inv_session))) {
-		pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
-		return NULL;
-	}
-	ast_party_id_copy(&session->id, &endpoint->id.self);
-
-	if (ast_format_cap_count(req_caps)) {
-		/* get joint caps between req_caps and endpoint caps */
-		struct ast_format_cap *joint_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-		ast_format_cap_get_compatible(req_caps, session->endpoint->media.codecs, joint_caps);
-
-		/* if joint caps */
-		if (ast_format_cap_count(joint_caps)) {
-			/* copy endpoint caps into session->req_caps */
-			ast_format_cap_append_from_cap(session->req_caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN);
-			/* replace instances of joint caps equivalents in session->req_caps */
-			ast_format_cap_replace_from_cap(session->req_caps, joint_caps, AST_MEDIA_TYPE_UNKNOWN);
-		}
-		ao2_cleanup(joint_caps);
-	}
-
-	if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS)) {
-		pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
-		/* Since we are not notifying ourselves that the INVITE session is being terminated
-		 * we need to manually drop its reference to session
-		 */
-		ao2_ref(session, -1);
-		return NULL;
-	}
-
-	ao2_ref(session, +1);
-	return session;
-}
-
-static int session_termination_task(void *data)
-{
-	RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
-	pjsip_tx_data *packet = NULL;
-
-	if (!session->inv_session) {
-		return 0;
-	}
-
-	if (pjsip_inv_end_session(session->inv_session, 603, NULL, &packet) == PJ_SUCCESS) {
-		ast_sip_session_send_request(session, packet);
-	}
-
-	return 0;
-}
-
-static void session_termination_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
-{
-	struct ast_sip_session *session = entry->user_data;
-
-	if (ast_sip_push_task(session->serializer, session_termination_task, session)) {
-		ao2_cleanup(session);
-	}
-}
-
-void ast_sip_session_defer_termination(struct ast_sip_session *session)
-{
-	pj_time_val delay = { .sec = 60, };
-
-	session->defer_terminate = 1;
-
-	session->scheduled_termination.id = 0;
-	ao2_ref(session, +1);
-	session->scheduled_termination.user_data = session;
-	session->scheduled_termination.cb = session_termination_cb;
-
-	if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &session->scheduled_termination, &delay) != PJ_SUCCESS) {
-		ao2_ref(session, -1);
-	}
-}
-
-struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg)
-{
-	pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
-	struct ast_sip_session *session;
-
-	if (!inv_session ||
-		!(session = inv_session->mod_data[session_module.id])) {
-		return NULL;
-	}
-
-	ao2_ref(session, +1);
-
-	return session;
-}
-
-enum sip_get_destination_result {
-	/*! The extension was successfully found */
-	SIP_GET_DEST_EXTEN_FOUND,
-	/*! The extension specified in the RURI was not found */
-	SIP_GET_DEST_EXTEN_NOT_FOUND,
-	/*! The extension specified in the RURI was a partial match */
-	SIP_GET_DEST_EXTEN_PARTIAL,
-	/*! The RURI is of an unsupported scheme */
-	SIP_GET_DEST_UNSUPPORTED_URI,
-};
-
-/*!
- * \brief Determine where in the dialplan a call should go
- *
- * This uses the username in the request URI to try to match
- * an extension in the endpoint's configured context in order
- * to route the call.
- *
- * \param session The inbound SIP session
- * \param rdata The SIP INVITE
- */
-static enum sip_get_destination_result get_destination(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
-	pjsip_sip_uri *sip_ruri;
-	struct ast_features_pickup_config *pickup_cfg;
-	const char *pickupexten;
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
-		return SIP_GET_DEST_UNSUPPORTED_URI;
-	}
-
-	sip_ruri = pjsip_uri_get_uri(ruri);
-	ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten));
-
-	pickup_cfg = ast_get_chan_features_pickup_config(session->channel);
-	if (!pickup_cfg) {
-		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
-		pickupexten = "";
-	} else {
-		pickupexten = ast_strdupa(pickup_cfg->pickupexten);
-		ao2_ref(pickup_cfg, -1);
-	}
-
-	if (!strcmp(session->exten, pickupexten) ||
-		ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
-		return SIP_GET_DEST_EXTEN_FOUND;
-	}
-	/* XXX In reality, we'll likely have further options so that partial matches
-	 * can be indicated here, but for getting something up and running, we're going
-	 * to return a "not exists" error here.
-	 */
-	return SIP_GET_DEST_EXTEN_NOT_FOUND;
-}
-
-static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
-{
-	pjsip_tx_data *tdata;
-	pjsip_dialog *dlg;
-	pjsip_inv_session *inv_session;
-	unsigned int options = endpoint->extensions.flags;
-	pj_status_t dlg_status;
-
-	if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
-		if (tdata) {
-			pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
-		} else {
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		}
-		return NULL;
-	}
-	dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status);
-	if (!dlg) {
-		if (dlg_status != PJ_EEXISTS) {
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		}
-		return NULL;
-	}
-	if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		pjsip_dlg_terminate(dlg);
-		return NULL;
-	}
-
-#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
-	inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
-#endif
-	if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
-		if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
-			pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
-		}
-		pjsip_inv_send_msg(inv_session, tdata);
-		return NULL;
-	}
-	return inv_session;
-}
-
-struct new_invite {
-	/*! \brief Session created for the new INVITE */
-	struct ast_sip_session *session;
-
-	/*! \brief INVITE request itself */
-	pjsip_rx_data *rdata;
-};
-
-static void new_invite_destroy(void *obj)
-{
-	struct new_invite *invite = obj;
-
-	ao2_cleanup(invite->session);
-
-	if (invite->rdata) {
-		pjsip_rx_data_free_cloned(invite->rdata);
-	}
-}
-
-static struct new_invite *new_invite_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	struct new_invite *invite = ao2_alloc(sizeof(*invite), new_invite_destroy);
-
-	if (!invite) {
-		return NULL;
-	}
-
-	ao2_ref(session, +1);
-	invite->session = session;
-
-	if (pjsip_rx_data_clone(rdata, 0, &invite->rdata) != PJ_SUCCESS) {
-		ao2_ref(invite, -1);
-		return NULL;
-	}
-
-	return invite;
-}
-
-static int new_invite(void *data)
-{
-	RAII_VAR(struct new_invite *, invite, data, ao2_cleanup);
-	pjsip_tx_data *tdata = NULL;
-	pjsip_timer_setting timer;
-	pjsip_rdata_sdp_info *sdp_info;
-	pjmedia_sdp_session *local = NULL;
-
-	/* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
-	 * so that we will be notified so we can destroy the session properly
-	 */
-
-	switch (get_destination(invite->session, invite->rdata)) {
-	case SIP_GET_DEST_EXTEN_FOUND:
-		/* Things worked. Keep going */
-		break;
-	case SIP_GET_DEST_UNSUPPORTED_URI:
-		if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
-			ast_sip_session_send_response(invite->session, tdata);
-		} else  {
-			pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
-		}
-		return 0;
-	case SIP_GET_DEST_EXTEN_NOT_FOUND:
-	case SIP_GET_DEST_EXTEN_PARTIAL:
-	default:
-		ast_log(LOG_NOTICE, "Call from '%s' (%s:%s:%d) to extension '%s' rejected because extension not found in context '%s'.\n",
-			ast_sorcery_object_get_id(invite->session->endpoint), invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name,
-			invite->rdata->pkt_info.src_port, invite->session->exten, invite->session->endpoint->context);
-
-		if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
-			ast_sip_session_send_response(invite->session, tdata);
-		} else  {
-			pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
-		}
-		return 0;
-	};
-
-	if ((sdp_info = pjsip_rdata_get_sdp_info(invite->rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
-		if (handle_incoming_sdp(invite->session, sdp_info->sdp)) {
-			if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 488, NULL, NULL, &tdata) == PJ_SUCCESS) {
-				ast_sip_session_send_response(invite->session, tdata);
-			} else  {
-				pjsip_inv_terminate(invite->session->inv_session, 488, PJ_TRUE);
-			}
-			return 0;
-		}
-		/* We are creating a local SDP which is an answer to their offer */
-		local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp);
-	} else {
-		/* We are creating a local SDP which is an offer */
-		local = create_local_sdp(invite->session->inv_session, invite->session, NULL);
-	}
-
-	/* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
-	if (!local) {
-		if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
-			ast_sip_session_send_response(invite->session, tdata);
-		} else  {
-			pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
-		}
-		return 0;
-	} else {
-		pjsip_inv_set_local_sdp(invite->session->inv_session, local);
-		pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
-#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
-		pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE);
-#endif
-	}
-
-	pjsip_timer_setting_default(&timer);
-	timer.min_se = invite->session->endpoint->extensions.timer.min_se;
-	timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires;
-	pjsip_timer_init_session(invite->session->inv_session, &timer);
-
-	/* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */
-	if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
-		pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
-		return 0;
-	}
-	ast_sip_session_send_response(invite->session, tdata);
-
-	handle_incoming_request(invite->session, invite->rdata, PJSIP_EVENT_RX_MSG);
-
-	return 0;
-}
-
-static void handle_new_invite_request(pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint,
-			ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
-	pjsip_tx_data *tdata = NULL;
-	pjsip_inv_session *inv_session = NULL;
-	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-	struct new_invite *invite;
-
-	ast_assert(endpoint != NULL);
-
-	inv_session = pre_session_setup(rdata, endpoint);
-	if (!inv_session) {
-		/* pre_session_setup() returns a response on failure */
-		return;
-	}
-
-	session = ast_sip_session_alloc(endpoint, NULL, inv_session);
-	if (!session) {
-		if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
-			pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
-		} else {
-			pjsip_inv_send_msg(inv_session, tdata);
-		}
-		return;
-	}
-
-	invite = new_invite_alloc(session, rdata);
-	if (!invite || ast_sip_push_task(session->serializer, new_invite, invite)) {
-		if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
-			pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
-		} else {
-			pjsip_inv_send_msg(inv_session, tdata);
-		}
-		ao2_ref(session, -1);
-		ao2_cleanup(invite);
-		return;
-	}
-}
-
-static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
-{
-	pj_str_t method;
-
-	if (ast_strlen_zero(supplement_method)) {
-		return PJ_TRUE;
-	}
-
-	pj_cstr(&method, supplement_method);
-
-	return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
-}
-
-static pj_bool_t has_supplement(const struct ast_sip_session *session, const pjsip_rx_data *rdata)
-{
-	struct ast_sip_session_supplement *supplement;
-	struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
-
-	if (!session) {
-		return PJ_FALSE;
-	}
-
-	AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
-		if (does_method_match(&method->name, supplement->method)) {
-			return PJ_TRUE;
-		}
-	}
-	return PJ_FALSE;
-}
-/*!
- * \brief Called when a new SIP request comes into PJSIP
- *
- * This function is called under two circumstances
- * 1) An out-of-dialog request is received by PJSIP
- * 2) An in-dialog request that the inv_session layer does not
- *    handle is received (such as an in-dialog INFO)
- *
- * In all cases, there is very little we actually do in this function
- * 1) For requests we don't handle, we return PJ_FALSE
- * 2) For new INVITEs, throw the work into the SIP threadpool to be done
- *    there to free up the thread(s) handling incoming requests
- * 3) For in-dialog requests we handle, we defer handling them until the
- *    on_inv_state_change() callback instead (where we will end up putting
- *    them into the threadpool).
- */
-static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata)
-{
-	pj_status_t handled = PJ_FALSE;
-	pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
-	pjsip_inv_session *inv_session;
-
-	switch (rdata->msg_info.msg->line.req.method.id) {
-	case PJSIP_INVITE_METHOD:
-		if (dlg) {
-			ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
-			break;
-		}
-		handled = PJ_TRUE;
-		handle_new_invite_request(rdata);
-		break;
-	default:
-		/* Handle other in-dialog methods if their supplements have been registered */
-		handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
-			has_supplement(inv_session->mod_data[session_module.id], rdata);
-		break;
-	}
-
-	return handled;
-}
-
-struct reschedule_reinvite_data {
-	struct ast_sip_session *session;
-	struct ast_sip_session_delayed_request *delay;
-};
-
-static struct reschedule_reinvite_data *reschedule_reinvite_data_alloc(
-		struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
-{
-	struct reschedule_reinvite_data *rrd = ast_malloc(sizeof(*rrd));
-	if (!rrd) {
-		return NULL;
-	}
-	ao2_ref(session, +1);
-	rrd->session = session;
-	rrd->delay = delay;
-	return rrd;
-}
-
-static void reschedule_reinvite_data_destroy(struct reschedule_reinvite_data *rrd)
-{
-	ao2_cleanup(rrd->session);
-	ast_free(rrd->delay);
-	ast_free(rrd);
-}
-
-static int really_resend_reinvite(void *data)
-{
-	RAII_VAR(struct reschedule_reinvite_data *, rrd, data, reschedule_reinvite_data_destroy);
-
-	return send_delayed_request(rrd->session, rrd->delay);
-}
-
-static void resend_reinvite(pj_timer_heap_t *timer, pj_timer_entry *entry)
-{
-	struct reschedule_reinvite_data *rrd = entry->user_data;
-
-	ast_sip_push_task(rrd->session->serializer, really_resend_reinvite, entry->user_data);
-}
-
-static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session_response_cb on_response)
-{
-	struct ast_sip_session_delayed_request *delay = delayed_request_alloc("INVITE",
-			NULL, NULL, on_response, 1);
-	pjsip_inv_session *inv = session->inv_session;
-	struct reschedule_reinvite_data *rrd = reschedule_reinvite_data_alloc(session, delay);
-	pj_time_val tv;
-
-	if (!rrd || !delay) {
-		return;
-	}
-
-	tv.sec = 0;
-	if (inv->role == PJSIP_ROLE_UAC) {
-		tv.msec = 2100 + ast_random() % 2000;
-	} else {
-		tv.msec = ast_random() % 2000;
-	}
-
-	pj_timer_entry_init(&session->rescheduled_reinvite, 0, rrd, resend_reinvite);
-
-	pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &session->rescheduled_reinvite, &tv);
-}
-
-static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
-{
-	struct ast_sip_session *session;
-	ast_debug(5, "Function %s called on event %s\n", function, pjsip_event_str(e->type));
-	if (!inv) {
-		ast_debug(5, "Transaction %p does not belong to an inv_session?\n", tsx);
-		ast_debug(5, "The transaction state is %s\n", pjsip_tsx_state_str(tsx->state));
-		return;
-	}
-	session = inv->mod_data[session_module.id];
-	if (!session) {
-		ast_debug(5, "inv_session %p has no ast session\n", inv);
-	} else {
-		ast_debug(5, "The state change pertains to the session with %s\n",
-				ast_sorcery_object_get_id(session->endpoint));
-	}
-	if (inv->invite_tsx) {
-		ast_debug(5, "The inv session still has an invite_tsx (%p)\n", inv->invite_tsx);
-	} else {
-		ast_debug(5, "The inv session does NOT have an invite_tsx\n");
-	}
-	if (tsx) {
-		ast_debug(5, "The transaction involved in this state change is %p\n", tsx);
-		ast_debug(5, "The current transaction state is %s\n", pjsip_tsx_state_str(tsx->state));
-		ast_debug(5, "The transaction state change event is %s\n", pjsip_event_str(e->body.tsx_state.type));
-	} else {
-		ast_debug(5, "There is no transaction involved in this state change\n");
-	}
-	ast_debug(5, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
-}
-
-#define print_debug_details(inv, tsx, e) __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))
-
-static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type)
-{
-	struct ast_sip_session_supplement *supplement;
-	struct pjsip_request_line req = rdata->msg_info.msg->line.req;
-
-	ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
-	AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
-		if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
-			if (supplement->incoming_request(session, rdata)) {
-				break;
-			}
-		}
-	}
-}
-
-static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type,
-		enum ast_sip_session_response_priority response_priority)
-{
-	struct ast_sip_session_supplement *supplement;
-	struct pjsip_status_line status = rdata->msg_info.msg->line.status;
-
-	ast_debug(3, "Response is %d %.*s\n", status.code, (int) pj_strlen(&status.reason),
-			pj_strbuf(&status.reason));
-
-	AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
-		if (!(supplement->response_priority & response_priority)) {
-			continue;
-		}
-		if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
-			supplement->incoming_response(session, rdata);
-		}
-	}
-}
-
-static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type,
-		enum ast_sip_session_response_priority response_priority)
-{
-	ast_debug(3, "Received %s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
-			"request" : "response");
-
-	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
-		handle_incoming_request(session, rdata, type);
-	} else {
-		handle_incoming_response(session, rdata, type, response_priority);
-	}
-
-	return 0;
-}
-
-static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct ast_sip_session_supplement *supplement;
-	struct pjsip_request_line req = tdata->msg->line.req;
-
-	ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
-	AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
-		if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
-			supplement->outgoing_request(session, tdata);
-		}
-	}
-}
-
-static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	struct ast_sip_session_supplement *supplement;
-	struct pjsip_status_line status = tdata->msg->line.status;
-	pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	ast_debug(3, "Method is %.*s, Response is %d %.*s\n", (int) pj_strlen(&cseq->method.name),
-		pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
-		pj_strbuf(&status.reason));
-
-	AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
-		if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
-			supplement->outgoing_response(session, tdata);
-		}
-	}
-}
-
-static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata)
-{
-	ast_debug(3, "Sending %s\n", tdata->msg->type == PJSIP_REQUEST_MSG ?
-			"request" : "response");
-	if (tdata->msg->type == PJSIP_REQUEST_MSG) {
-		handle_outgoing_request(session, tdata);
-	} else {
-		handle_outgoing_response(session, tdata);
-	}
-}
-
-static int session_end(struct ast_sip_session *session)
-{
-	struct ast_sip_session_supplement *iter;
-
-	/* Stop the scheduled termination */
-	if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &session->scheduled_termination)) {
-		ao2_ref(session, -1);
-	}
-
-	/* Session is dead. Let's get rid of the reference to the session */
-	AST_LIST_TRAVERSE(&session->supplements, iter, next) {
-		if (iter->session_end) {
-			iter->session_end(session);
-		}
-	}
-
-	session->inv_session->mod_data[session_module.id] = NULL;
-	ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
-	ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
-	ao2_cleanup(session);
-	return 0;
-}
-
-static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
-{
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-	pjsip_event_id_e type;
-
-	if (e) {
-		print_debug_details(inv, NULL, e);
-		type = e->type;
-	} else {
-		type = PJSIP_EVENT_UNKNOWN;
-	}
-
-	if (!session) {
-		return;
-	}
-
-	switch(type) {
-	case PJSIP_EVENT_TX_MSG:
-		handle_outgoing(session, e->body.tx_msg.tdata);
-		break;
-	case PJSIP_EVENT_RX_MSG:
-		handle_incoming(session, e->body.rx_msg.rdata, type,
-				AST_SIP_SESSION_BEFORE_MEDIA);
-		break;
-	case PJSIP_EVENT_TSX_STATE:
-		ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type));
-		/* Transaction state changes are prompted by some other underlying event. */
-		switch(e->body.tsx_state.type) {
-		case PJSIP_EVENT_TX_MSG:
-			handle_outgoing(session, e->body.tsx_state.src.tdata);
-			break;
-		case PJSIP_EVENT_RX_MSG:
-			handle_incoming(session, e->body.tsx_state.src.rdata, type,
-					AST_SIP_SESSION_BEFORE_MEDIA);
-			break;
-		case PJSIP_EVENT_TRANSPORT_ERROR:
-		case PJSIP_EVENT_TIMER:
-		case PJSIP_EVENT_USER:
-		case PJSIP_EVENT_UNKNOWN:
-		case PJSIP_EVENT_TSX_STATE:
-			/* Inception? */
-			break;
-		}
-		break;
-	case PJSIP_EVENT_TRANSPORT_ERROR:
-	case PJSIP_EVENT_TIMER:
-	case PJSIP_EVENT_UNKNOWN:
-	case PJSIP_EVENT_USER:
-	default:
-		break;
-	}
-
-	if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
-		session_end(session);
-	}
-}
-
-static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
-{
-	/* XXX STUB */
-}
-
-static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
-{
-	ast_sip_session_response_cb cb;
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-	print_debug_details(inv, tsx, e);
-	if (!session) {
-		/* Transaction likely timed out after the call was hung up. Just
-		 * ignore such transaction changes
-		 */
-		return;
-	}
-	switch (e->body.tsx_state.type) {
-	case PJSIP_EVENT_TX_MSG:
-		handle_outgoing(session, e->body.tsx_state.src.tdata);
-		/* When we create an outgoing request, we do not have access to the transaction that
-		 * is created. Instead, We have to place transaction-specific data in the tdata. Here,
-		 * we transfer the data into the transaction. This way, when we receive a response, we
-		 * can dig this data out again
-		 */
-		tsx->mod_data[session_module.id] = e->body.tsx_state.src.tdata->mod_data[session_module.id];
-		break;
-	case PJSIP_EVENT_RX_MSG:
-		cb = ast_sip_mod_data_get(tsx->mod_data, session_module.id, MOD_DATA_ON_RESPONSE);
-		handle_incoming(session, e->body.tsx_state.src.rdata, e->type,
-				AST_SIP_SESSION_AFTER_MEDIA);
-		if (tsx->method.id == PJSIP_INVITE_METHOD) {
-			if (tsx->role == PJSIP_ROLE_UAC) {
-				if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
-					/* This means we got a non 2XX final response to our outgoing INVITE */
-					if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
-						reschedule_reinvite(session, cb);
-						return;
-					} else if (inv->state == PJSIP_INV_STATE_CONFIRMED &&
-						   tsx->status_code != 488) {
-						/* Other reinvite failures (except 488) result in destroying the session. */
-						pjsip_tx_data *tdata;
-						if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
-							ast_sip_session_send_request(session, tdata);
-						}
-					}
-				} else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
-					if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) {
-						/* This is a race condition detailed in RFC 5407 section 3.1.2.
-						 * We sent a CANCEL at the same time that the UAS sent us a 200 OK for
-						 * the original INVITE. As a result, we have now received a 200 OK for
-						 * a cancelled call. Our role is to immediately send a BYE to end the
-						 * dialog.
-						 */
-						pjsip_tx_data *tdata;
-
-						if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
-							ast_sip_session_send_request(session, tdata);
-						}
-					}
-				}
-			}
-		}
-		if (cb) {
-			cb(session, e->body.tsx_state.src.rdata);
-		}
-	case PJSIP_EVENT_TRANSPORT_ERROR:
-	case PJSIP_EVENT_TIMER:
-	case PJSIP_EVENT_USER:
-	case PJSIP_EVENT_UNKNOWN:
-	case PJSIP_EVENT_TSX_STATE:
-		/* Inception? */
-		break;
-	}
-
-	/* Terminated INVITE transactions always should result in queuing delayed requests,
-	 * no matter what event caused the transaction to terminate
-	 */
-	if (tsx->method.id == PJSIP_INVITE_METHOD &&
-		((tsx->state == PJSIP_TSX_STATE_TERMINATED) ||
-		(tsx->state == PJSIP_TSX_STATE_PROCEEDING))) {
-		queue_delayed_request(session);
-	}
-}
-
-static int add_sdp_streams(void *obj, void *arg, void *data, int flags)
-{
-	struct ast_sip_session_media *session_media = obj;
-	pjmedia_sdp_session *answer = arg;
-	struct ast_sip_session *session = data;
-	struct ast_sip_session_sdp_handler *handler = session_media->handler;
-	RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
-	int res;
-
-	if (handler) {
-		/* if an already assigned handler does not handle the session_media or reports a catastrophic error, fail */
-		res = handler->create_outgoing_sdp_stream(session, session_media, answer);
-		if (res <= 0) {
-			return 0;
-		}
-		return CMP_MATCH;
-	}
-
-	handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY);
-	if (!handler_list) {
-		return CMP_MATCH;
-	}
-
-	/* no handler for this stream type and we have a list to search */
-	AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-		if (handler == session_media->handler) {
-			continue;
-		}
-		res = handler->create_outgoing_sdp_stream(session, session_media, answer);
-		if (res < 0) {
-			/* catastrophic error */
-			return 0;
-		}
-		if (res > 0) {
-			/* Handled by this handler. Move to the next stream */
-			session_media_set_handler(session_media, handler);
-			return CMP_MATCH;
-		}
-	}
-
-	/* streams that weren't handled won't be included in generated outbound SDP */
-	return CMP_MATCH;
-}
-
-static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
-{
-	RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
-	static const pj_str_t STR_IN = { "IN", 2 };
-	static const pj_str_t STR_IP4 = { "IP4", 3 };
-	static const pj_str_t STR_IP6 = { "IP6", 3 };
-	pjmedia_sdp_session *local;
-
-	if (!(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
-		return NULL;
-	}
-
-	if (!offer) {
-		local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
-	} else {
-		local->origin.version = offer->origin.version + 1;
-		local->origin.id = offer->origin.id;
-	}
-
-	pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner);
-	pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession);
-
-	/* Now let the handlers add streams of various types, pjmedia will automatically reorder the media streams for us */
-	successful = ao2_callback_data(session->media, OBJ_MULTIPLE, add_sdp_streams, local, session);
-	if (!successful || ao2_iterator_count(successful) != ao2_container_count(session->media)) {
-		/* Something experienced a catastrophic failure */
-		return NULL;
-	}
-
-	/* Use the connection details of the first media stream if possible for SDP level */
-	if (local->media_count) {
-		int stream;
-
-		/* Since we are using the first media stream as the SDP level we can get rid of it
-		 * from the stream itself
-		 */
-		local->conn = local->media[0]->conn;
-		local->media[0]->conn = NULL;
-		pj_strassign(&local->origin.net_type, &local->conn->net_type);
-		pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
-		pj_strassign(&local->origin.addr, &local->conn->addr);
-
-		/* Go through each media stream seeing if the connection details actually differ,
-		 * if not just use SDP level and reduce the SDP size
-		 */
-		for (stream = 1; stream < local->media_count; stream++) {
-			if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) &&
-				!pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) &&
-				!pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
-				local->media[stream]->conn = NULL;
-			}
-		}
-	} else {
-		local->origin.net_type = STR_IN;
-		local->origin.addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
-
-		if (!ast_strlen_zero(session->endpoint->media.address)) {
-			pj_strdup2(inv->pool_prov, &local->origin.addr, session->endpoint->media.address);
-		} else {
-			pj_sockaddr localaddr;
-			char our_ip[PJ_INET6_ADDRSTRLEN];
-
-			pj_gethostip(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET(), &localaddr);
-			pj_sockaddr_print(&localaddr, our_ip, sizeof(our_ip), 0);
-			pj_strdup2(inv->pool_prov, &local->origin.addr, our_ip);
-		}
-	}
-
-	return local;
-}
-
-static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
-{
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-	pjmedia_sdp_session *answer;
-
-	if (handle_incoming_sdp(session, offer)) {
-		return;
-	}
-
-	if ((answer = create_local_sdp(inv, session, offer))) {
-		pjsip_inv_set_sdp_answer(inv, answer);
-	}
-}
-
-#if 0
-static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
-{
-	/* XXX STUB */
-}
-#endif
-
-static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
-{
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-	const pjmedia_sdp_session *local, *remote;
-
-	if (!session->channel) {
-		/* If we don't have a channel. We really don't care about media updates.
-		 * Just ignore
-		 */
-		return;
-	}
-
-	if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
-		(pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
-		ast_channel_hangupcause_set(session->channel, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
-		ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
-		ast_queue_hangup(session->channel);
-		return;
-	}
-
-	handle_negotiated_sdp(session, local, remote);
-}
-
-static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
-{
-	struct ast_sip_session *session = inv->mod_data[session_module.id];
-	const pjsip_sip_uri *uri;
-
-	if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
-		return PJSIP_REDIRECT_ACCEPT;
-	}
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
-		return PJSIP_REDIRECT_STOP;
-	}
-
-	handle_incoming(session, e->body.rx_msg.rdata, PJSIP_EVENT_RX_MSG,
-			AST_SIP_SESSION_BEFORE_REDIRECTING);
-
-	uri = pjsip_uri_get_uri(target);
-
-	if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
-		char exten[AST_MAX_EXTENSION];
-
-		ast_copy_pj_str(exten, &uri->user, sizeof(exten));
-		ast_channel_call_forward_set(session->channel, exten);
-	} else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
-		char target_uri[PJSIP_MAX_URL_SIZE];
-		/* PJSIP/ + endpoint length + / + max URL size */
-		char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
-
-		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
-		sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
-		ast_channel_call_forward_set(session->channel, forward);
-	}
-
-	return PJSIP_REDIRECT_STOP;
-}
-
-static pjsip_inv_callback inv_callback = {
-	.on_state_changed = session_inv_on_state_changed,
-	.on_new_session = session_inv_on_new_session,
-	.on_tsx_state_changed = session_inv_on_tsx_state_changed,
-	.on_rx_offer = session_inv_on_rx_offer,
-	.on_media_update = session_inv_on_media_update,
-	.on_redirected = session_inv_on_redirected,
-};
-
-/*! \brief Hook for modifying outgoing messages with SDP to contain the proper address information */
-static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
-{
-	struct ast_sip_nat_hook *hook = ast_sip_mod_data_get(
-		tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);
-	struct pjmedia_sdp_session *sdp;
-	int stream;
-
-	/* SDP produced by us directly will never be multipart */
-	if (hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") ||
-		pj_stricmp2(&tdata->msg->body->content_type.subtype, "sdp") || ast_strlen_zero(transport->external_media_address)) {
-		return;
-	}
-
-	sdp = tdata->msg->body->data;
-
-	if (sdp->conn) {
-		char host[NI_MAXHOST];
-		struct ast_sockaddr addr = { { 0, } };
-
-		ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
-		ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
-
-		if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
-			pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address);
-		}
-	}
-
-	for (stream = 0; stream < sdp->media_count; ++stream) {
-		/* See if there are registered handlers for this media stream type */
-		char media[20];
-		struct ast_sip_session_sdp_handler *handler;
-		RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
-
-		/* We need a null-terminated version of the media string */
-		ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
-
-		handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
-		if (!handler_list) {
-			ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
-			continue;
-		}
-		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
-			if (handler->change_outgoing_sdp_stream_media_address) {
-				handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
-			}
-		}
-	}
-
-	/* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
-	ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);
-}
-
-static int load_module(void)
-{
-	pjsip_endpoint *endpt;
-
-	CHECK_PJSIP_MODULE_LOADED();
-
-	if (!ast_sip_get_sorcery() || !ast_sip_get_pjsip_endpoint()) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	nat_hook->outgoing_external_message = session_outgoing_nat_hook;
-	ast_sorcery_create(ast_sip_get_sorcery(), nat_hook);
-	sdp_handlers = ao2_container_alloc(SDP_HANDLER_BUCKETS,
-			sdp_handler_list_hash, sdp_handler_list_cmp);
-	if (!sdp_handlers) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	endpt = ast_sip_get_pjsip_endpoint();
-	pjsip_inv_usage_init(endpt, &inv_callback);
-	pjsip_100rel_init_module(endpt);
-	pjsip_timer_init_module(endpt);
-	if (ast_sip_register_service(&session_module)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	ast_sip_register_service(&session_reinvite_module);
-
-	ast_module_ref(ast_module_info->self);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	/* This will never get called as this module can't be unloaded */
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Session resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	       );
diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in
deleted file mode 100644
index 07f26b7..0000000
--- a/res/res_pjsip_session.exports.in
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXast_sip_session_defer_termination;
-		LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler;
-		LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler;
-		LINKER_SYMBOL_PREFIXast_sip_session_register_supplement;
-		LINKER_SYMBOL_PREFIXast_sip_session_unregister_supplement;
-		LINKER_SYMBOL_PREFIXast_sip_session_alloc_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_session_add_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_session_get_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_session_remove_datastore;
-		LINKER_SYMBOL_PREFIXast_sip_session_get_identity;
-		LINKER_SYMBOL_PREFIXast_sip_session_refresh;
-		LINKER_SYMBOL_PREFIXast_sip_session_send_response;
-		LINKER_SYMBOL_PREFIXast_sip_session_send_request;
-		LINKER_SYMBOL_PREFIXast_sip_session_create_invite;
-		LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing;
-		LINKER_SYMBOL_PREFIXast_sip_session_suspend;
-		LINKER_SYMBOL_PREFIXast_sip_session_unsuspend;
-		LINKER_SYMBOL_PREFIXast_sip_dialog_get_session;
-		LINKER_SYMBOL_PREFIXast_sip_session_resume_reinvite;
-		LINKER_SYMBOL_PREFIXast_sip_channel_pvt_alloc;
-	local:
-		*;
-};
diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
deleted file mode 100644
index b6ef59c..0000000
--- a/res/res_pjsip_t38.c
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- * \brief SIP T.38 handling
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_session</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-#include <pjmedia.h>
-#include <pjlib.h>
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431327 $")
-
-#include "asterisk/module.h"
-#include "asterisk/udptl.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/channel.h"
-#include "asterisk/acl.h"
-
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-
-/*! \brief The number of seconds after receiving a T.38 re-invite before automatically rejecting it */
-#define T38_AUTOMATIC_REJECTION_SECONDS 5
-
-/*! \brief Address for IPv4 UDPTL */
-static struct ast_sockaddr address_ipv4;
-
-/*! \brief Address for IPv6 UDPTL */
-static struct ast_sockaddr address_ipv6;
-
-/*! \brief T.38 state information */
-struct t38_state {
-	/*! \brief Current state */
-	enum ast_sip_session_t38state state;
-	/*! \brief Our T.38 parameters */
-	struct ast_control_t38_parameters our_parms;
-	/*! \brief Their T.38 parameters */
-	struct ast_control_t38_parameters their_parms;
-	/*! \brief Timer entry for automatically rejecting an inbound re-invite */
-	pj_timer_entry timer;
-};
-
-/*! \brief Destructor for T.38 state information */
-static void t38_state_destroy(void *obj)
-{
-	ast_free(obj);
-}
-
-/*! \brief Datastore for attaching T.38 state information */
-static const struct ast_datastore_info t38_datastore = {
-	.type = "t38",
-	.destroy = t38_state_destroy,
-};
-
-/*! \brief Structure for T.38 parameters task data */
-struct t38_parameters_task_data {
-	/*! \brief Session itself */
-	struct ast_sip_session *session;
-	/*! \brief T.38 control frame */
-	struct ast_frame *frame;
-};
-
-/*! \brief Destructor for T.38 data */
-static void t38_parameters_task_data_destroy(void *obj)
-{
-	struct t38_parameters_task_data *data = obj;
-
-	ao2_cleanup(data->session);
-
-	if (data->frame) {
-		ast_frfree(data->frame);
-	}
-}
-
-/*! \brief Allocator for T.38 data */
-static struct t38_parameters_task_data *t38_parameters_task_data_alloc(struct ast_sip_session *session,
-	struct ast_frame *frame)
-{
-	struct t38_parameters_task_data *data = ao2_alloc(sizeof(*data), t38_parameters_task_data_destroy);
-
-	if (!data) {
-		return NULL;
-	}
-
-	data->session = session;
-	ao2_ref(session, +1);
-	data->frame = frame;
-
-	return data;
-}
-
-/*! \brief Helper function for changing the T.38 state */
-static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-	struct t38_state *state, enum ast_sip_session_t38state new_state)
-{
-	enum ast_sip_session_t38state old_state = session->t38state;
-	struct ast_control_t38_parameters parameters = { .request_response = 0, };
-	pj_time_val delay = { .sec = T38_AUTOMATIC_REJECTION_SECONDS };
-
-	if (old_state == new_state) {
-		return;
-	}
-
-	session->t38state = new_state;
-	ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel));
-
-	if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &state->timer)) {
-		ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n", ast_channel_name(session->channel));
-		ao2_ref(session, -1);
-	}
-
-	if (!session->channel) {
-		return;
-	}
-
-	switch (new_state) {
-	case T38_PEER_REINVITE:
-		ao2_ref(session, +1);
-		if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &state->timer, &delay) != PJ_SUCCESS) {
-			ast_log(LOG_WARNING, "Scheduling of automatic T.38 rejection for channel '%s' failed\n",
-				ast_channel_name(session->channel));
-			ao2_ref(session, -1);
-		}
-		parameters = state->their_parms;
-		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
-		parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
-		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
-		break;
-	case T38_ENABLED:
-		parameters = state->their_parms;
-		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
-		parameters.request_response = AST_T38_NEGOTIATED;
-		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
-		break;
-	case T38_REJECTED:
-	case T38_DISABLED:
-		if (old_state == T38_ENABLED) {
-			parameters.request_response = AST_T38_TERMINATED;
-		} else if (old_state == T38_LOCAL_REINVITE) {
-			parameters.request_response = AST_T38_REFUSED;
-		}
-		break;
-	case T38_LOCAL_REINVITE:
-		/* wait until we get a peer response before responding to local reinvite */
-		break;
-	case T38_MAX_ENUM:
-		/* Well, that shouldn't happen */
-		ast_assert(0);
-		break;
-	}
-
-	if (parameters.request_response) {
-		ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
-	}
-}
-
-/*! \brief Task function which rejects a T.38 re-invite and resumes handling it */
-static int t38_automatic_reject(void *obj)
-{
-	RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
-	RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
-	RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(session->media, "image", OBJ_KEY), ao2_cleanup);
-
-	if (!datastore) {
-		return 0;
-	}
-
-	ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", ast_channel_name(session->channel));
-
-	t38_change_state(session, session_media, datastore->data, T38_REJECTED);
-	ast_sip_session_resume_reinvite(session);
-
-	return 0;
-}
-
-/*! \brief Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it */
-static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
-{
-	struct ast_sip_session *session = entry->user_data;
-
-	if (ast_sip_push_task(session->serializer, t38_automatic_reject, session)) {
-		ao2_ref(session, -1);
-	}
-}
-
-/*! \brief Helper function which retrieves or allocates a T.38 state information datastore */
-static struct t38_state *t38_state_get_or_alloc(struct ast_sip_session *session)
-{
-	RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
-	struct t38_state *state;
-
-	/* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
-	if (datastore) {
-		return datastore->data;
-	}
-
-	if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38")) ||
-		!(datastore->data = ast_calloc(1, sizeof(struct t38_state))) ||
-		ast_sip_session_add_datastore(session, datastore)) {
-		return NULL;
-	}
-
-	state = datastore->data;
-
-	/* This will get bumped up before scheduling */
-	state->timer.user_data = session;
-	state->timer.cb = t38_automatic_reject_timer_cb;
-
-	datastore->data = state;
-
-	return state;
-}
-
-/*! \brief Initializes UDPTL support on a session, only done when actually needed */
-static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
-{
-	if (session_media->udptl) {
-		return 0;
-	}
-
-	if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0,
-		session->endpoint->media.t38.ipv6 ? &address_ipv6 : &address_ipv4))) {
-		return -1;
-	}
-
-	ast_channel_set_fd(session->channel, 5, ast_udptl_fd(session_media->udptl));
-	ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction);
-	ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
-
-	return 0;
-}
-
-/*! \brief Callback for when T.38 reinvite SDP is created */
-static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
-{
-	int stream;
-
-	/* Move the image media stream to the front and have it as the only stream, pjmedia will fill in
-	 * dummy streams for the rest
-	 */
-	for (stream = 0; stream < sdp->media_count++; ++stream) {
-		if (!pj_strcmp2(&sdp->media[stream]->desc.media, "image")) {
-			sdp->media[0] = sdp->media[stream];
-			sdp->media_count = 1;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/*! \brief Callback for when a response is received for a T.38 re-invite */
-static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
-{
-	struct pjsip_status_line status = rdata->msg_info.msg->line.status;
-	struct t38_state *state;
-	RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-
-	if (status.code == 100) {
-		return 0;
-	}
-
-	if (!(state = t38_state_get_or_alloc(session)) ||
-		!(session_media = ao2_find(session->media, "image", OBJ_KEY))) {
-		ast_log(LOG_WARNING, "Received response to T.38 re-invite on '%s' but state unavailable\n",
-			ast_channel_name(session->channel));
-		return 0;
-	}
-
-	t38_change_state(session, session_media, state, (status.code == 200) ? T38_ENABLED : T38_REJECTED);
-
-	return 0;
-}
-
-/*! \brief Task for reacting to T.38 control frame */
-static int t38_interpret_parameters(void *obj)
-{
-	RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
-	const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
-	struct t38_state *state = t38_state_get_or_alloc(data->session);
-	RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(data->session->media, "image", OBJ_KEY), ao2_cleanup);
-
-	/* Without session media or state we can't interpret parameters */
-	if (!session_media || !state) {
-		return 0;
-	}
-
-	switch (parameters->request_response) {
-	case AST_T38_NEGOTIATED:
-	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
-		/* Negotiation can not take place without a valid max_ifp value. */
-		if (!parameters->max_ifp) {
-			t38_change_state(data->session, session_media, state, T38_REJECTED);
-			if (data->session->t38state == T38_PEER_REINVITE) {
-				ast_sip_session_resume_reinvite(data->session);
-			}
-			break;
-		} else if (data->session->t38state == T38_PEER_REINVITE) {
-			state->our_parms = *parameters;
-			/* modify our parameters to conform to the peer's parameters,
-			 * based on the rules in the ITU T.38 recommendation
-			 */
-			if (!state->their_parms.fill_bit_removal) {
-				state->our_parms.fill_bit_removal = 0;
-			}
-			if (!state->their_parms.transcoding_mmr) {
-				state->our_parms.transcoding_mmr = 0;
-			}
-			if (!state->their_parms.transcoding_jbig) {
-				state->our_parms.transcoding_jbig = 0;
-			}
-			state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
-			state->our_parms.rate_management = state->their_parms.rate_management;
-			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
-			t38_change_state(data->session, session_media, state, T38_ENABLED);
-			ast_sip_session_resume_reinvite(data->session);
-		} else if (data->session->t38state != T38_ENABLED) {
-			if (t38_initialize_session(data->session, session_media)) {
-				break;
-			}
-			state->our_parms = *parameters;
-			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
-			t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
-			ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb,
-				AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
-		}
-		break;
-	case AST_T38_TERMINATED:
-	case AST_T38_REFUSED:
-	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
-		if (data->session->t38state == T38_PEER_REINVITE) {
-			t38_change_state(data->session, session_media, state, T38_REJECTED);
-			ast_sip_session_resume_reinvite(data->session);
-		} else if (data->session->t38state == T38_ENABLED) {
-			t38_change_state(data->session, session_media, state, T38_DISABLED);
-			ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
-		}
-		break;
-	case AST_T38_REQUEST_PARMS: {		/* Application wants remote's parameters re-sent */
-		struct ast_control_t38_parameters parameters = state->their_parms;
-
-		if (data->session->t38state == T38_PEER_REINVITE) {
-			parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
-			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
-			ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
-		}
-		break;
-	}
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-/*! \brief Frame hook callback for writing */
-static struct ast_frame *t38_framehook_write(struct ast_sip_session *session, struct ast_frame *f)
-{
-	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS &&
-		session->endpoint->media.t38.enabled) {
-		struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(session, f);
-
-		if (!data) {
-			return f;
-		}
-
-		if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) {
-			ao2_ref(data, -1);
-		}
-
-		f = &ast_null_frame;
-	} else if (f->frametype == AST_FRAME_MODEM) {
-		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-
-		if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) &&
-			session_media->udptl) {
-			ast_udptl_write(session_media->udptl, f);
-		}
-	}
-
-	return f;
-}
-
-/*! \brief Frame hook callback for reading */
-static struct ast_frame *t38_framehook_read(struct ast_sip_session *session, struct ast_frame *f)
-{
-	if (ast_channel_fdno(session->channel) == 5) {
-		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
-
-		if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) &&
-			session_media->udptl) {
-			f = ast_udptl_read(session_media->udptl);
-		}
-	}
-
-	return f;
-}
-
-/*! \brief Frame hook callback for T.38 related stuff */
-static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f,
-	enum ast_framehook_event event, void *data)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-
-	if (event == AST_FRAMEHOOK_EVENT_READ) {
-		f = t38_framehook_read(channel->session, f);
-	} else if (event == AST_FRAMEHOOK_EVENT_WRITE) {
-		f = t38_framehook_write(channel->session, f);
-	}
-
-	return f;
-}
-
-static void t38_masq(void *data, int framehook_id,
-        struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
-		return;
-	}
-
-	/* This framehook is only applicable to PJSIP channels */
-	ast_framehook_detach(new_chan, framehook_id);
-}
-
-/*! \brief Function called to attach T.38 framehook to channel when appropriate */
-static void t38_attach_framehook(struct ast_sip_session *session)
-{
-	static struct ast_framehook_interface hook = {
-		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
-		.event_cb = t38_framehook,
-		.chan_fixup_cb = t38_masq,
-		.chan_breakdown_cb = t38_masq,
-	};
-
-	/* Only attach the framehook on the first outgoing INVITE or the first incoming INVITE */
-	if ((session->inv_session->state != PJSIP_INV_STATE_NULL &&
-		session->inv_session->state != PJSIP_INV_STATE_INCOMING) ||
-		!session->endpoint->media.t38.enabled) {
-		return;
-	}
-
-	if (ast_framehook_attach(session->channel, &hook) < 0) {
-		ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n",
-			ast_channel_name(session->channel));
-	}
-}
-
-/*! \brief Function called when an INVITE goes out */
-static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
-{
-	t38_attach_framehook(session);
-	return 0;
-}
-
-/*! \brief Function called when an INVITE comes in */
-static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	t38_attach_framehook(session);
-}
-
-/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
-static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
-{
-	switch (rate) {
-	case AST_T38_RATE_2400:
-		return 2400;
-	case AST_T38_RATE_4800:
-		return 4800;
-	case AST_T38_RATE_7200:
-		return 7200;
-	case AST_T38_RATE_9600:
-		return 9600;
-	case AST_T38_RATE_12000:
-		return 12000;
-	case AST_T38_RATE_14400:
-		return 14400;
-	default:
-		return 0;
-	}
-}
-
-/*! \brief Supplement for adding framehook to session channel */
-static struct ast_sip_session_supplement t38_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
-	.incoming_request = t38_incoming_invite_request,
-	.outgoing_request = t38_outgoing_invite_request,
-};
-
-/*! \brief Parse a T.38 image stream and store the attribute information */
-static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-	const struct pjmedia_sdp_media *stream)
-{
-	unsigned int attr_i;
-
-	for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
-		pjmedia_sdp_attr *attr = stream->attr[attr_i];
-
-		if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
-			/* This is purposely left empty, it is unused */
-		} else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
-			switch (pj_strtoul(&attr->value)) {
-			case 14400:
-				state->their_parms.rate = AST_T38_RATE_14400;
-				break;
-			case 12000:
-				state->their_parms.rate = AST_T38_RATE_12000;
-				break;
-			case 9600:
-				state->their_parms.rate = AST_T38_RATE_9600;
-				break;
-			case 7200:
-				state->their_parms.rate = AST_T38_RATE_7200;
-				break;
-			case 4800:
-				state->their_parms.rate = AST_T38_RATE_4800;
-				break;
-			case 2400:
-				state->their_parms.rate = AST_T38_RATE_2400;
-				break;
-			}
-		} else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
-			state->their_parms.version = pj_strtoul(&attr->value);
-		} else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
-			if (session->endpoint->media.t38.maxdatagram) {
-				ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram);
-			} else {
-				ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
-			}
-		} else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
-			state->their_parms.fill_bit_removal = 1;
-		} else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
-			state->their_parms.transcoding_mmr = 1;
-		} else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
-			state->their_parms.transcoding_jbig = 1;
-		} else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
-			if (!pj_stricmp2(&attr->value, "localTCF")) {
-				state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
-			} else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
-				state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
-			}
-		} else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
-			if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
-				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
-			} else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
-				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_FEC);
-			} else {
-				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_NONE);
-			}
-		}
-
-	}
-}
-
-/*! \brief Function which defers an incoming media stream */
-static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream(
-	struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-	const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
-{
-	struct t38_state *state;
-
-	if (!session->endpoint->media.t38.enabled) {
-		return AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED;
-	}
-
-	if (t38_initialize_session(session, session_media)) {
-		return AST_SIP_SESSION_SDP_DEFER_ERROR;
-	}
-
-	if (!(state = t38_state_get_or_alloc(session))) {
-		return AST_SIP_SESSION_SDP_DEFER_ERROR;
-	}
-
-	t38_interpret_sdp(state, session, session_media, stream);
-
-	/* If they are initiating the re-invite we need to defer responding until later */
-	if (session->t38state == T38_DISABLED) {
-		t38_change_state(session, session_media, state, T38_PEER_REINVITE);
-		return AST_SIP_SESSION_SDP_DEFER_NEEDED;
-	}
-
-	return AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED;
-}
-
-/*! \brief Function which negotiates an incoming media stream */
-static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
-{
-	struct t38_state *state;
-	char host[NI_MAXHOST];
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
-
-	if (!session->endpoint->media.t38.enabled) {
-		return -1;
-	}
-
-	if (!(state = t38_state_get_or_alloc(session))) {
-		return -1;
-	}
-
-	if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
-		t38_change_state(session, session_media, state, T38_DISABLED);
-		return -1;
-	}
-
-	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
-	}
-
-	/* Check the address family to make sure it matches configured */
-	if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
-		(ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
-		/* The address does not match configured */
-		return -1;
-	}
-
-	return 1;
-}
-
-/*! \brief Function which creates an outgoing stream */
-static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-				      struct pjmedia_sdp_session *sdp)
-{
-	pj_pool_t *pool = session->inv_session->pool_prov;
-	static const pj_str_t STR_IN = { "IN", 2 };
-	static const pj_str_t STR_IP4 = { "IP4", 3};
-	static const pj_str_t STR_IP6 = { "IP6", 3};
-	static const pj_str_t STR_UDPTL = { "udptl", 5 };
-	static const pj_str_t STR_T38 = { "t38", 3 };
-	static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
-	static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
-	static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
-	static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
-	struct t38_state *state;
-	pjmedia_sdp_media *media;
-	char hostip[PJ_INET6_ADDRSTRLEN+2];
-	struct ast_sockaddr addr;
-	char tmp[512];
-	pj_str_t stmp;
-
-	if (!session->endpoint->media.t38.enabled) {
-		return 1;
-	} else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
-		(session->t38state != T38_ENABLED)) {
-		return 1;
-	} else if (!(state = t38_state_get_or_alloc(session))) {
-		return -1;
-	} else if (t38_initialize_session(session, session_media)) {
-		return -1;
-	}
-
-	if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
-		!(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
-		return -1;
-	}
-
-	media->desc.media = pj_str(session_media->stream_type);
-	media->desc.transport = STR_UDPTL;
-
-	if (ast_strlen_zero(session->endpoint->media.address)) {
-		pj_sockaddr localaddr;
-
-		if (pj_gethostip(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET(), &localaddr)) {
-			return -1;
-		}
-		pj_sockaddr_print(&localaddr, hostip, sizeof(hostip), 2);
-	} else {
-		ast_copy_string(hostip, session->endpoint->media.address, sizeof(hostip));
-	}
-
-	media->conn->net_type = STR_IN;
-	media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
-	pj_strdup2(pool, &media->conn->addr, hostip);
-	ast_udptl_get_us(session_media->udptl, &addr);
-	media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
-	media->desc.port_count = 1;
-	media->desc.fmt[media->desc.fmt_count++] = STR_T38;
-
-	snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
-	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
-
-	snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
-	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
-
-	if (state->our_parms.fill_bit_removal) {
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
-	}
-
-	if (state->our_parms.transcoding_mmr) {
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
-	}
-
-	if (state->our_parms.transcoding_jbig) {
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
-	}
-
-	switch (state->our_parms.rate_management) {
-	case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
-		break;
-	case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
-		break;
-	}
-
-	snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
-	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
-
-	switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
-	case UDPTL_ERROR_CORRECTION_NONE:
-		break;
-	case UDPTL_ERROR_CORRECTION_FEC:
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
-		break;
-	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
-		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
-		break;
-	}
-
-	sdp->media[sdp->media_count++] = media;
-
-	return 1;
-}
-
-/*! \brief Function which applies a negotiated stream */
-static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-				       const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
-				       const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
-{
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
-	char host[NI_MAXHOST];
-	struct t38_state *state;
-
-	if (!session_media->udptl) {
-		return 0;
-	}
-
-	if (!(state = t38_state_get_or_alloc(session))) {
-		return -1;
-	}
-
-	ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
-	}
-
-	ast_sockaddr_set_port(addrs, remote_stream->desc.port);
-	ast_udptl_set_peer(session_media->udptl, addrs);
-
-	t38_interpret_sdp(state, session, session_media, remote_stream);
-
-	return 0;
-}
-
-/*! \brief Function which updates the media stream with external media address, if applicable */
-static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
-{
-	char host[NI_MAXHOST];
-	struct ast_sockaddr addr = { { 0, } };
-
-	/* If the stream has been rejected there will be no connection line */
-	if (!stream->conn) {
-		return;
-	}
-
-	ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
-	ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
-
-	/* Is the address within the SDP inside the same network? */
-	if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) {
-		return;
-	}
-
-	pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
-}
-
-/*! \brief Function which destroys the UDPTL instance when session ends */
-static void stream_destroy(struct ast_sip_session_media *session_media)
-{
-	if (session_media->udptl) {
-		ast_udptl_destroy(session_media->udptl);
-	}
-	session_media->udptl = NULL;
-}
-
-/*! \brief SDP handler for 'image' media stream */
-static struct ast_sip_session_sdp_handler image_sdp_handler = {
-	.id = "image",
-	.defer_incoming_sdp_stream = defer_incoming_sdp_stream,
-	.negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
-	.create_outgoing_sdp_stream = create_outgoing_sdp_stream,
-	.apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
-	.change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
-	.stream_destroy = stream_destroy,
-};
-
-/*! \brief Unloads the SIP T.38 module from Asterisk */
-static int unload_module(void)
-{
-	ast_sip_session_unregister_sdp_handler(&image_sdp_handler, "image");
-	ast_sip_session_unregister_supplement(&t38_supplement);
-
-	return 0;
-}
-
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
-static int load_module(void)
-{
-	CHECK_PJSIP_SESSION_MODULE_LOADED();
-
-	ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
-	ast_sockaddr_parse(&address_ipv6, "::", 0);
-
-	if (ast_sip_session_register_supplement(&t38_supplement)) {
-		ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");
-		goto end;
-	}
-
-	if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) {
-		ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
-		goto end;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-end:
-	unload_module();
-
-	return AST_MODULE_LOAD_FAILURE;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DRIVER,
-	);
diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c
deleted file mode 100644
index 5616715..0000000
--- a/res/res_pjsip_transport_websocket.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Jason Parker <jparker at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \brief WebSocket transport module
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_http_websocket</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_ua.h>
-
-#include "asterisk/module.h"
-#include "asterisk/http_websocket.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_session.h"
-#include "asterisk/taskprocessor.h"
-
-static int transport_type_ws;
-static int transport_type_wss;
-
-/*!
- * \brief Wrapper for pjsip_transport, for storing the WebSocket session
- */
-struct ws_transport {
-	pjsip_transport transport;
-	pjsip_rx_data rdata;
-	struct ast_websocket *ws_session;
-};
-
-/*!
- * \brief Send a message over the WebSocket connection.
- *
- * Called by pjsip transport manager.
- */
-static pj_status_t ws_send_msg(pjsip_transport *transport,
-                            pjsip_tx_data *tdata,
-                            const pj_sockaddr_t *rem_addr,
-                            int addr_len,
-                            void *token,
-                            pjsip_transport_callback callback)
-{
-	struct ws_transport *wstransport = (struct ws_transport *)transport;
-
-	if (ast_websocket_write(wstransport->ws_session, AST_WEBSOCKET_OPCODE_TEXT, tdata->buf.start, (int)(tdata->buf.cur - tdata->buf.start))) {
-		return PJ_EUNKNOWN;
-	}
-
-	return PJ_SUCCESS;
-}
-
-/*!
- * \brief Destroy the pjsip transport.
- *
- * Called by pjsip transport manager.
- */
-static pj_status_t ws_destroy(pjsip_transport *transport)
-{
-	struct ws_transport *wstransport = (struct ws_transport *)transport;
-
-	if (wstransport->transport.ref_cnt) {
-		pj_atomic_destroy(wstransport->transport.ref_cnt);
-	}
-
-	if (wstransport->transport.lock) {
-		pj_lock_destroy(wstransport->transport.lock);
-	}
-
-	pjsip_endpt_release_pool(wstransport->transport.endpt, wstransport->transport.pool);
-
-	if (wstransport->rdata.tp_info.pool) {
-		pjsip_endpt_release_pool(wstransport->transport.endpt, wstransport->rdata.tp_info.pool);
-	}
-
-	return PJ_SUCCESS;
-}
-
-static int transport_shutdown(void *data)
-{
-	pjsip_transport *transport = data;
-
-	pjsip_transport_shutdown(transport);
-	return 0;
-}
-
-struct transport_create_data {
-	struct ws_transport *transport;
-	struct ast_websocket *ws_session;
-};
-
-/*!
- * \brief Create a pjsip transport.
- */
-static int transport_create(void *data)
-{
-	struct transport_create_data *create_data = data;
-	struct ws_transport *newtransport;
-
-	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
-	struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt);
-
-	pj_pool_t *pool;
-
-	pj_str_t buf;
-
-	if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) {
-		ast_log(LOG_ERROR, "Failed to allocate WebSocket endpoint pool.\n");
-		return -1;
-	}
-
-	if (!(newtransport = PJ_POOL_ZALLOC_T(pool, struct ws_transport))) {
-		ast_log(LOG_ERROR, "Failed to allocate WebSocket transport.\n");
-		pjsip_endpt_release_pool(endpt, pool);
-		return -1;
-	}
-
-	newtransport->ws_session = create_data->ws_session;
-
-	pj_atomic_create(pool, 0, &newtransport->transport.ref_cnt);
-	pj_lock_create_recursive_mutex(pool, pool->obj_name, &newtransport->transport.lock);
-
-	newtransport->transport.pool = pool;
-	pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session))), &newtransport->transport.key.rem_addr);
-	newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET();
-	newtransport->transport.key.type = ast_websocket_is_secure(newtransport->ws_session) ? transport_type_wss : transport_type_ws;
-
-	newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr);
-
-	pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr);
-
-	newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, newtransport->transport.addr_len+4);
-	pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, newtransport->transport.addr_len+4, 0);
-	newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr);
-	newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr);
-
-	newtransport->transport.type_name = (char *)pjsip_transport_get_type_name(newtransport->transport.key.type);
-	newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type);
-	newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64);
-
-	newtransport->transport.endpt = endpt;
-	newtransport->transport.tpmgr = tpmgr;
-	newtransport->transport.send_msg = &ws_send_msg;
-	newtransport->transport.destroy = &ws_destroy;
-
-	pjsip_transport_register(newtransport->transport.tpmgr, (pjsip_transport *)newtransport);
-
-	newtransport->rdata.tp_info.transport = &newtransport->transport;
-	newtransport->rdata.tp_info.pool = pjsip_endpt_create_pool(endpt, "rtd%p",
-		PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC);
-	if (!newtransport->rdata.tp_info.pool) {
-		ast_log(LOG_ERROR, "Failed to allocate WebSocket rdata.\n");
-		pjsip_endpt_release_pool(endpt, pool);
-		return -1;
-	}
-
-	create_data->transport = newtransport;
-	return 0;
-}
-
-struct transport_read_data {
-	struct ws_transport *transport;
-	char *payload;
-	uint64_t payload_len;
-};
-
-/*!
- * \brief Pass WebSocket data into pjsip transport manager.
- */
-static int transport_read(void *data)
-{
-	struct transport_read_data *read_data = data;
-	struct ws_transport *newtransport = read_data->transport;
-	struct ast_websocket *session = newtransport->ws_session;
-
-	pjsip_rx_data *rdata = &newtransport->rdata;
-	int recvd;
-	pj_str_t buf;
-
-	pj_gettimeofday(&rdata->pkt_info.timestamp);
-
-	pj_memcpy(rdata->pkt_info.packet, read_data->payload,
-		PJSIP_MAX_PKT_LEN < read_data->payload_len ? PJSIP_MAX_PKT_LEN : read_data->payload_len);
-	rdata->pkt_info.len = read_data->payload_len;
-	rdata->pkt_info.zero = 0;
-
-	pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr);
-	rdata->pkt_info.src_addr.addr.sa_family = pj_AF_INET();
-
-	rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr);
-
-	pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_host(ast_websocket_remote_address(session)));
-	rdata->pkt_info.src_port = ast_sockaddr_port(ast_websocket_remote_address(session));
-
-	recvd = pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, rdata);
-
-	pj_pool_reset(rdata->tp_info.pool);
-
-	return (read_data->payload_len == recvd) ? 0 : -1;
-}
-
-static int get_write_timeout(void)
-{
-	int write_timeout = -1;
-	struct ao2_container *transports;
-
-	transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_ALL, NULL);
-
-	if (transports) {
-		struct ao2_iterator it_transports = ao2_iterator_init(transports, 0);
-		struct ast_sip_transport *transport;
-
-		for (; (transport = ao2_iterator_next(&it_transports)); ao2_cleanup(transport)) {
-			if (transport->type != AST_TRANSPORT_WS && transport->type != AST_TRANSPORT_WSS) {
-				continue;
-			}
-			ast_debug(5, "Found %s transport with write timeout: %d\n",
-				transport->type == AST_TRANSPORT_WS ? "WS" : "WSS",
-				transport->write_timeout);
-			write_timeout = MAX(write_timeout, transport->write_timeout);
-		}
-		ao2_cleanup(transports);
-	}
-
-	if (write_timeout < 0) {
-		write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
-	}
-
-	ast_debug(1, "Write timeout for WS/WSS transports: %d\n", write_timeout);
-	return write_timeout;
-}
-
-/*!
- \brief WebSocket connection handler.
- */
-static void websocket_cb(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
-{
-	struct ast_taskprocessor *serializer = NULL;
-	struct transport_create_data create_data;
-	struct ws_transport *transport = NULL;
-	struct transport_read_data read_data;
-
-	if (ast_websocket_set_nonblock(session)) {
-		ast_websocket_unref(session);
-		return;
-	}
-
-	if (ast_websocket_set_timeout(session, get_write_timeout())) {
-		ast_websocket_unref(session);
-		return;
-	}
-
-	if (!(serializer = ast_sip_create_serializer())) {
-		ast_websocket_unref(session);
-		return;
-	}
-
-	create_data.ws_session = session;
-
-	if (ast_sip_push_task_synchronous(serializer, transport_create, &create_data)) {
-		ast_log(LOG_ERROR, "Could not create WebSocket transport.\n");
-		ast_websocket_unref(session);
-		return;
-	}
-
-	transport = create_data.transport;
-	read_data.transport = transport;
-
-	while (ast_wait_for_input(ast_websocket_fd(session), -1) > 0) {
-		enum ast_websocket_opcode opcode;
-		int fragmented;
-
-		if (ast_websocket_read(session, &read_data.payload, &read_data.payload_len, &opcode, &fragmented)) {
-			break;
-		}
-
-		if (opcode == AST_WEBSOCKET_OPCODE_TEXT || opcode == AST_WEBSOCKET_OPCODE_BINARY) {
-			ast_sip_push_task_synchronous(serializer, transport_read, &read_data);
-		} else if (opcode == AST_WEBSOCKET_OPCODE_CLOSE) {
-			break;
-		}
-	}
-
-	ast_sip_push_task_synchronous(serializer, transport_shutdown, transport);
-
-	ast_taskprocessor_unreference(serializer);
-	ast_websocket_unref(session);
-}
-
-/*!
- * \brief Store the transport a message came in on, so it can be used for outbound messages to that contact.
- */
-static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata)
-{
-	static const pj_str_t STR_WS = { "ws", 2 };
-	static const pj_str_t STR_WSS = { "wss", 3 };
-	pjsip_contact_hdr *contact;
-
-	long type = rdata->tp_info.transport->key.type;
-
-	if (type != (long)transport_type_ws && type != (long)transport_type_wss) {
-		return PJ_FALSE;
-	}
-
-	if ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) && !contact->star &&
-		(PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
-		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
-
-		pj_cstr(&uri->host, rdata->pkt_info.src_name);
-		uri->port = rdata->pkt_info.src_port;
-		pj_strdup(rdata->tp_info.pool, &uri->transport_param, (type == (long)transport_type_ws) ? &STR_WS : &STR_WSS);
-	}
-
-	rdata->msg_info.via->rport_param = 0;
-
-	return PJ_FALSE;
-}
-
-static pjsip_module websocket_module = {
-	.name = { "WebSocket Transport Module", 26 },
-	.id = -1,
-	.priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,
-	.on_rx_request = websocket_on_rx_msg,
-	.on_rx_response = websocket_on_rx_msg,
-};
-
-/*! \brief Function called when an INVITE goes out */
-static void websocket_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
-{
-	if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
-		pjsip_dlg_add_usage(session->inv_session->dlg, &websocket_module, NULL);
-	}
-}
-
-/*! \brief Supplement for adding Websocket functionality to dialog */
-static struct ast_sip_session_supplement websocket_supplement = {
-	.method = "INVITE",
-	.priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
-	.outgoing_request = websocket_outgoing_invite_request,
-};
-
-static int load_module(void)
-{
-	CHECK_PJSIP_MODULE_LOADED();
-
-	pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WS", 5060, &transport_type_ws);
-	pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WSS", 5060, &transport_type_wss);
-
-	if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_sip_session_register_supplement(&websocket_supplement)) {
-		ast_sip_unregister_service(&websocket_module);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_websocket_add_protocol("sip", websocket_cb)) {
-		ast_sip_session_unregister_supplement(&websocket_supplement);
-		ast_sip_unregister_service(&websocket_module);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sip_unregister_service(&websocket_module);
-	ast_sip_session_unregister_supplement(&websocket_supplement);
-	ast_websocket_remove_protocol("sip", websocket_cb);
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP WebSocket Transport Support",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_APP_DEPEND,
-	   );
diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c
deleted file mode 100644
index 43cb1e7..0000000
--- a/res/res_pjsip_xpidf_body_generator.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend>pjproject</depend>
-	<depend>res_pjsip</depend>
-	<depend>res_pjsip_pubsub</depend>
-	<depend>res_pjsip_exten_state</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include <pjsip.h>
-#include <pjsip_simple.h>
-#include <pjlib.h>
-
-#include "asterisk/module.h"
-#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_presence_xml.h"
-#include "asterisk/res_pjsip_body_generator_types.h"
-
-static void *xpidf_allocate_body(void *data)
-{
-	struct ast_sip_exten_state_data *state_data = data;
-	char *local = ast_strdupa(state_data->local);
-	pjxpidf_pres *pres;
-	pj_str_t name;
-
-	pres = pjxpidf_create(state_data->pool, pj_cstr(&name, ast_strip_quoted(local, "<", ">")));
-	return pres;
-}
-
-static int xpidf_generate_body_content(void *body, void *data)
-{
-	pjxpidf_pres *pres = body;
-	struct ast_sip_exten_state_data *state_data = data;
-	static pj_str_t STR_ADDR_PARAM = { ";user=ip", 8 };
-	char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
-	pj_xml_attr *attr;
-	enum ast_sip_pidf_state local_state;
-	pj_str_t uri;
-	char sanitized[PJSIP_MAX_URL_SIZE];
-	pj_xml_node *atom;
-	pj_xml_node *address;
-	pj_xml_node *status;
-	pj_xml_node *msnsubstatus;
-
-	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
-
-	ast_sip_presence_xml_find_node_attr(state_data->pool, pres, "atom", "id",
-			&atom, &attr);
-	pj_strdup2(state_data->pool, &attr->value, state_data->exten);
-
-	ast_sip_presence_xml_find_node_attr(state_data->pool, atom, "address",
-			"uri", &address, &attr);
-
-	ast_sip_sanitize_xml(state_data->remote, sanitized, sizeof(sanitized));
-
-	uri.ptr = (char*) pj_pool_alloc(state_data->pool,
-			strlen(sanitized) + STR_ADDR_PARAM.slen);
-	pj_strcpy2( &uri, sanitized);
-	pj_strcat( &uri, &STR_ADDR_PARAM);
-	pj_strdup(state_data->pool, &attr->value, &uri);
-
-	ast_sip_presence_xml_create_attr(state_data->pool, address, "priority", "0.80000");
-
-	ast_sip_presence_xml_find_node_attr(state_data->pool, address,
-			"status", "status", &status, &attr);
-	pj_strdup2(state_data->pool, &attr->value,
-		   (local_state ==  NOTIFY_OPEN) ? "open" :
-		   (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
-
-	ast_sip_presence_xml_find_node_attr(state_data->pool, address,
-			"msnsubstatus", "substatus", &msnsubstatus, &attr);
-	pj_strdup2(state_data->pool, &attr->value,
-		   (local_state == NOTIFY_OPEN) ? "online" :
-		   (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
-
-	return 0;
-}
-
-#define MAX_STRING_GROWTHS 5
-
-static void xpidf_to_string(void *body, struct ast_str **str)
-{
-	pjxpidf_pres *pres = body;
-	int growths = 0;
-	int size;
-
-	do {
-		size = pjxpidf_print(pres, ast_str_buffer(*str), ast_str_size(*str));
-		if (size == AST_PJSIP_XML_PROLOG_LEN) {
-			ast_str_make_space(str, ast_str_size(*str) * 2);
-			++growths;
-		}
-	} while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS);
-
-	if (size == AST_PJSIP_XML_PROLOG_LEN) {
-		ast_log(LOG_WARNING, "XPIDF body text too large\n");
-		return;
-	}
-
-	*(ast_str_buffer(*str) + size) = '\0';
-	ast_str_update(*str);
-}
-
-static struct ast_sip_pubsub_body_generator xpidf_body_generator = {
-	.type = "application",
-	.subtype = "xpidf+xml",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.allocate_body = xpidf_allocate_body,
-	.generate_body_content = xpidf_generate_body_content,
-	.to_string = xpidf_to_string,
-	/* No need for a destroy_body callback since we use a pool */
-};
-
-static struct ast_sip_pubsub_body_generator cpim_pidf_body_generator = {
-	.type = "application",
-	.subtype = "cpim-pidf+xml",
-	.body_type = AST_SIP_EXTEN_STATE_DATA,
-	.allocate_body = xpidf_allocate_body,
-	.generate_body_content = xpidf_generate_body_content,
-	.to_string = xpidf_to_string,
-	/* No need for a destroy_body callback since we use a pool */
-};
-
-static void unregister_all(void)
-{
-	ast_sip_pubsub_unregister_body_generator(&cpim_pidf_body_generator);
-	ast_sip_pubsub_unregister_body_generator(&xpidf_body_generator);
-}
-
-static int load_module(void)
-{
-	CHECK_PJSIP_PUBSUB_MODULE_LOADED();
-
-	if (ast_sip_pubsub_register_body_generator(&xpidf_body_generator)) {
-		goto fail;
-	}
-
-	if (ast_sip_pubsub_register_body_generator(&cpim_pidf_body_generator)) {
-		goto fail;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-
-fail:
-	unregister_all();
-	return AST_MODULE_LOAD_DECLINE;
-}
-
-static int unload_module(void)
-{
-	unregister_all();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State PIDF Provider",
-		.support_level = AST_MODULE_SUPPORT_CORE,
-		.load = load_module,
-		.unload = unload_module,
-		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-);
diff --git a/res/res_pktccops.c b/res/res_pktccops.c
index b889c59..365e32c 100644
--- a/res/res_pktccops.c
+++ b/res/res_pktccops.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -799,9 +799,9 @@ static void *do_pktccops(void *data)
 				if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
 					len = cops_getmsg(cmts->sfd, recmsg);
 					if (len > 0) {
-						ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%u\n",
-							cmts->name, (unsigned)recmsg->verflag,
-							recmsg->opcode, (unsigned)recmsg->clienttype, recmsg->length);
+						ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%02hhx opcode=%i clienttype=0x%04hx msglength=%u\n",
+							cmts->name, recmsg->verflag,
+							recmsg->opcode, recmsg->clienttype, recmsg->length);
 						if (recmsg->object != NULL) {
 							pobject = recmsg->object;
 							while (pobject != NULL) {
@@ -1511,7 +1511,6 @@ static int reload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PktcCOPS manager for MGCP",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_realtime.c b/res/res_realtime.c
index 7a5ce5b..b26cde5 100644
--- a/res/res_realtime.c
+++ b/res/res_realtime.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 342871 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 4165f3b..dfbc3e9 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -29,13 +29,13 @@
  */
 
 /*** MODULEINFO
-	<use type="external">pjproject</use>
+	<use type="external">uuid</use>
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425646 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -47,16 +47,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425646 $")
 #include <openssl/bio.h>
 #endif
 
-#ifdef HAVE_PJPROJECT
-#include <pjlib.h>
-#include <pjlib-util.h>
-#include <pjnath.h>
+#ifdef USE_PJPROJECT
+/* Asterisk discourages the use of bzero in favor of memset, in fact if you try to use bzero it will tell you to use memset. As a result bzero has to be undefined
+ * here since it is used internally by pjlib. The only other option would be to modify pjlib... which won't happen. */
+#undef bzero
+#define bzero bzero
+#include "pjlib.h"
+#include "pjlib-util.h"
+#include "pjnath.h"
 #endif
 
 #include "asterisk/stun.h"
 #include "asterisk/pbx.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 #include "asterisk/channel.h"
 #include "asterisk/acl.h"
 #include "asterisk/config.h"
@@ -67,7 +70,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425646 $")
 #include "asterisk/unaligned.h"
 #include "asterisk/module.h"
 #include "asterisk/rtp_engine.h"
-#include "asterisk/smoother.h"
 #include "asterisk/test.h"
 
 #define MAX_TIMESTAMP_SKEW	640
@@ -88,13 +90,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425646 $")
 #define TURN_STATE_WAIT_TIME 2000
 
 #define RTCP_PT_FUR     192
-#define RTCP_PT_SR      AST_RTP_RTCP_SR
-#define RTCP_PT_RR      AST_RTP_RTCP_RR
+#define RTCP_PT_SR      200
+#define RTCP_PT_RR      201
 #define RTCP_PT_SDES    202
 #define RTCP_PT_BYE     203
 #define RTCP_PT_APP     204
-/* VP8: RTCP Feedback */
-#define RTCP_PT_PSFB    206
 
 #define RTP_MTU		1200
 #define DTMF_SAMPLE_RATE_MS    8 /*!< DTMF samples per millisecond */
@@ -138,9 +138,10 @@ static int nochecksums;
 #endif
 static int strictrtp = DEFAULT_STRICT_RTP; /*< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
 static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
-#ifdef HAVE_PJPROJECT
 static int icesupport = DEFAULT_ICESUPPORT;
 static struct sockaddr_in stunaddr;
+
+#ifdef USE_PJPROJECT
 static pj_str_t turnaddr;
 static int turnport = DEFAULT_TURN_PORT;
 static pj_str_t turnusername;
@@ -204,11 +205,13 @@ struct rtp_learning_info {
 
 #ifdef HAVE_OPENSSL_SRTP
 struct dtls_details {
+	ast_mutex_t lock; /*!< Lock for timeout timer synchronization */
 	SSL *ssl;         /*!< SSL session */
 	BIO *read_bio;    /*!< Memory buffer for reading */
 	BIO *write_bio;   /*!< Memory buffer for writing */
 	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
 	enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */
+	int timeout_timer; /*!< Scheduler id for timeout timer */
 };
 #endif
 
@@ -237,8 +240,8 @@ struct ast_rtp {
 	unsigned int cycles;            /*!< Shifted count of sequence number cycles */
 	double rxjitter;                /*!< Interarrival jitter at the moment in seconds */
 	double rxtransit;               /*!< Relative transit time for previous packet */
-	struct ast_format *lasttxformat;
-	struct ast_format *lastrxformat;
+	struct ast_format lasttxformat;
+	struct ast_format lastrxformat;
 
 	int rtptimeout;			/*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
 	int rtpholdtimeout;		/*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
@@ -276,6 +279,7 @@ struct ast_rtp {
 
 	enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
 	struct ast_sockaddr strict_rtp_address;  /*!< Remote address information for strict RTP purposes */
+	struct ast_sockaddr alt_rtp_address; /*!<Alternate remote address information */
 
 	/*
 	 * Learning mode values based on pjmedia's probation mode.  Many of these values are redundant to the above,
@@ -286,14 +290,13 @@ struct ast_rtp {
 
 	struct rtp_red *red;
 
-	ast_mutex_t lock;           /*!< Lock for synchronization purposes */
-	ast_cond_t cond;            /*!< Condition for signaling */
-
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	pj_ice_sess *ice;           /*!< ICE session */
 	pj_turn_sock *turn_rtp;     /*!< RTP TURN relay */
 	pj_turn_sock *turn_rtcp;    /*!< RTCP TURN relay */
+	ast_mutex_t lock;           /*!< Lock for synchronization purposes */
 	pj_turn_state_t turn_state; /*!< Current state of the TURN relay session */
+	ast_cond_t cond;            /*!< Condition for signaling */
 	unsigned int passthrough:1; /*!< Bit to indicate that the received packet should be passed through */
 	unsigned int rtp_passthrough:1; /*!< Bit to indicate that TURN RTP should be passed through */
 	unsigned int rtcp_passthrough:1; /*!< Bit to indicate that TURN RTCP should be passed through */
@@ -317,7 +320,6 @@ struct ast_rtp {
 
 #ifdef HAVE_OPENSSL_SRTP
 	SSL_CTX *ssl_ctx; /*!< SSL context */
-	ast_mutex_t dtls_timer_lock;           /*!< Lock for synchronization purposes */
 	enum ast_rtp_dtls_verify dtls_verify; /*!< What to verify */
 	enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
 	enum ast_rtp_dtls_hash local_hash; /*!< Local hash used for the fingerprint */
@@ -326,7 +328,6 @@ struct ast_rtp {
 	unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */
 	unsigned int rekey; /*!< Interval at which to renegotiate and rekey */
 	int rekeyid; /*!< Scheduled item id for rekeying */
-	int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */
 	struct dtls_details dtls; /*!< DTLS state information */
 #endif
 };
@@ -391,9 +392,6 @@ struct ast_rtcp {
 	double stdevrtt;
 	unsigned int rtt_count;
 
-	/* VP8: sequence number for the RTCP FIR FCI */
-	int firseq;
-
 #ifdef HAVE_OPENSSL_SRTP
 	struct dtls_details dtls; /*!< DTLS state information */
 #endif
@@ -431,6 +429,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
 static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp);
 static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr);
+static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr);
 static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
 static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
 static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1);
@@ -444,25 +443,13 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level);
 #ifdef HAVE_OPENSSL_SRTP
 static int ast_rtp_activate(struct ast_rtp_instance *instance);
 static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
+static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
+static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
 #endif
 
 static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp);
 
-#ifdef HAVE_PJPROJECT
-/*! \brief Helper function which updates an ast_sockaddr with the candidate used for the component */
-static void update_address_with_ice_candidate(struct ast_rtp *rtp, enum ast_rtp_ice_component_type component,
-	struct ast_sockaddr *cand_address)
-{
-	char address[PJ_INET6_ADDRSTRLEN];
-
-	if (!rtp->ice || (component < 1) || !rtp->ice->comp[component - 1].valid_check) {
-		return;
-	}
-
-	ast_sockaddr_parse(cand_address, pj_sockaddr_print(&rtp->ice->comp[component - 1].valid_check->rcand->addr, address, sizeof(address), 0), 0);
-	ast_sockaddr_set_port(cand_address, pj_sockaddr_get_port(&rtp->ice->comp[component - 1].valid_check->rcand->addr));
-}
-
+#ifdef USE_PJPROJECT
 /*! \brief Destructor for locally created ICE candidates */
 static void ast_rtp_ice_candidate_destroy(void *obj)
 {
@@ -565,6 +552,19 @@ static void pj_thread_register_check(void)
 	return;
 }
 
+/*! \brief Helper function which updates an ast_sockaddr with the candidate used for the component */
+static void update_address_with_ice_candidate(struct ast_rtp *rtp, enum ast_rtp_ice_component_type component, struct ast_sockaddr *cand_address)
+{
+	char address[PJ_INET6_ADDRSTRLEN];
+
+	if (!rtp->ice || (component < 1) || !rtp->ice->comp[component - 1].valid_check) {
+		return;
+	}
+
+	ast_sockaddr_parse(cand_address, pj_sockaddr_print(&rtp->ice->comp[component - 1].valid_check->rcand->addr, address, sizeof(address), 0), 0);
+	ast_sockaddr_set_port(cand_address, pj_sockaddr_get_port(&rtp->ice->comp[component - 1].valid_check->rcand->addr));
+}
+
 static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *addr,
 	int port, int replace);
 
@@ -588,12 +588,16 @@ static int ice_reset_session(struct ast_rtp_instance *instance)
 	pj_ice_sess_role role = rtp->ice->role;
 	int res;
 
+	ast_debug(3, "Resetting ICE for RTP instance '%p'\n", instance);
 	if (!rtp->ice->is_nominating && !rtp->ice->is_complete) {
+		ast_debug(3, "Nevermind. ICE isn't ready for a reset\n");
 		return 0;
 	}
 
+	ast_debug(3, "Stopping ICE for RTP instance '%p'\n", instance);
 	ast_rtp_ice_stop(instance);
 
+	ast_debug(3, "Recreating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->ice_original_rtp_addr), rtp->ice_port, instance);
 	res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1);
 	if (!res) {
 		/* Preserve the role that the old ICE session used */
@@ -646,6 +650,7 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance)
 	/* Check for equivalence in the lists */
 	if (rtp->ice_active_remote_candidates &&
 			!ice_candidates_compare(rtp->ice_proposed_remote_candidates, rtp->ice_active_remote_candidates)) {
+		ast_debug(3, "Proposed == active candidates for RTP instance '%p'\n", instance);
 		ao2_cleanup(rtp->ice_proposed_remote_candidates);
 		rtp->ice_proposed_remote_candidates = NULL;
 		return;
@@ -692,8 +697,10 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance)
 		}
 
 		if (candidate->id == AST_RTP_ICE_COMPONENT_RTP && rtp->turn_rtp) {
+			ast_debug(3, "RTP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance);
 			pj_turn_sock_set_perm(rtp->turn_rtp, 1, &candidates[cand_cnt].addr, 1);
 		} else if (candidate->id == AST_RTP_ICE_COMPONENT_RTCP && rtp->turn_rtcp) {
+			ast_debug(3, "RTCP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance);
 			pj_turn_sock_set_perm(rtp->turn_rtcp, 1, &candidates[cand_cnt].addr, 1);
 		}
 
@@ -703,21 +710,40 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance)
 
 	ao2_iterator_destroy(&i);
 
-	if (has_rtp && has_rtcp &&
-	    pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, ao2_container_count(
-						  rtp->ice_active_remote_candidates), &candidates[0]) == PJ_SUCCESS) {
-		ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: SUCCESS");
-		pj_ice_sess_start_check(rtp->ice);
-		pj_timer_heap_poll(timer_heap, NULL);
-		rtp->strict_rtp_state = STRICT_RTP_OPEN;
-		return;
+	if (cand_cnt < ao2_container_count(rtp->ice_active_remote_candidates)) {
+		ast_log(LOG_WARNING, "Lost %d ICE candidates. Consider increasing PJ_ICE_MAX_CAND in PJSIP (%p)\n",
+			ao2_container_count(rtp->ice_active_remote_candidates) - cand_cnt, instance);
+	}
+
+	if (!has_rtp) {
+		ast_log(LOG_WARNING, "No RTP candidates; skipping ICE checklist (%p)\n", instance);
+	}
+
+	if (!has_rtcp) {
+		ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance);
+	}
+
+	if (has_rtp && has_rtcp) {
+		pj_status_t res = pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, cand_cnt, &candidates[0]);
+		char reason[80];
+
+		if (res == PJ_SUCCESS) {
+			ast_debug(3, "Successfully created ICE checklist (%p)\n", instance);
+			ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: SUCCESS");
+			pj_ice_sess_start_check(rtp->ice);
+			pj_timer_heap_poll(timer_heap, NULL);
+			rtp->strict_rtp_state = STRICT_RTP_OPEN;
+			return;
+		}
+
+		pj_strerror(res, reason, sizeof(reason));
+		ast_log(LOG_WARNING, "Failed to create ICE session check list: %s (%p)\n", reason, instance);
 	}
 
 	ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: FAILURE");
 
 	/* even though create check list failed don't stop ice as
 	   it might still work */
-	ast_debug(1, "Failed to create ICE session check list\n");
 	/* however we do need to reset remote candidates since
 	   this function may be re-entered */
 	ao2_ref(rtp->ice_active_remote_candidates, -1);
@@ -767,7 +793,11 @@ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	ast_debug(3, "Set role to %s (%p)\n",
+		role == AST_RTP_ICE_ROLE_CONTROLLED ? "CONTROLLED" : "CONTROLLING", instance);
+
 	if (!rtp->ice) {
+		ast_debug(3, "Set role failed; no ice instance (%p)\n", instance);
 		return;
 	}
 
@@ -1059,12 +1089,11 @@ end:
 }
 
 static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component,
-		enum ast_transport transport, const char *server, unsigned int port, const char *username, const char *password)
+		pj_turn_tp_type conn_type, const char *server, unsigned int port, const char *username, const char *password)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	pj_turn_sock **turn_sock;
 	const pj_turn_sock_cb *turn_cb;
-	pj_turn_tp_type conn_type;
 	int conn_transport;
 	pj_stun_auth_cred cred = { 0, };
 	pj_str_t turn_addr;
@@ -1097,15 +1126,6 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast
 		return;
 	}
 
-	if (transport == AST_TRANSPORT_UDP) {
-		conn_type = PJ_TURN_TP_UDP;
-	} else if (transport == AST_TRANSPORT_TCP) {
-		conn_type = PJ_TURN_TP_TCP;
-	} else {
-		ast_assert(0);
-		return;
-	}
-
 	ast_sockaddr_parse(&addr, server, PARSE_PORT_FORBID);
 
 	ast_mutex_lock(&rtp->lock);
@@ -1168,10 +1188,9 @@ static char *generate_random_string(char *buf, size_t size)
         long val[4];
         int x;
 
-        for (x=0; x<4; x++) {
+        for (x=0; x<4; x++)
                 val[x] = ast_random();
-	}
-        snprintf(buf, size, "%08lx%08lx%08lx%08lx", (long unsigned)val[0], (long unsigned)val[1], (long unsigned)val[2], (long unsigned)val[3]);
+        snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
 
         return buf;
 }
@@ -1187,7 +1206,6 @@ static struct ast_rtp_engine_ice ast_rtp_ice = {
 	.get_local_candidates = ast_rtp_ice_get_local_candidates,
 	.ice_lite = ast_rtp_ice_lite,
 	.set_role = ast_rtp_ice_set_role,
-	.turn_request = ast_rtp_ice_turn_request,
 };
 #endif
 
@@ -1229,6 +1247,8 @@ static int dtls_details_initialize(struct dtls_details *dtls, SSL_CTX *ssl_ctx,
 	}
 	dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
 
+	ast_mutex_init(&dtls->lock);
+
 	return 0;
 
 error:
@@ -1264,23 +1284,35 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	int res;
+#ifndef HAVE_OPENSSL_ECDH_AUTO
+	EC_KEY *ecdh;
+#endif
 
 	if (!dtls_cfg->enabled) {
 		return 0;
 	}
 
 	if (!ast_rtp_engine_srtp_is_registered()) {
+		ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
 		return -1;
 	}
 
-	if (rtp->ssl_ctx) {
-		return 0;
-	}
-
 	if (!(rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method()))) {
 		return -1;
 	}
 
+	SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);
+
+#ifdef HAVE_OPENSSL_ECDH_AUTO
+	SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, 1);
+#else
+	ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+	if (ecdh) {
+		SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh);
+		EC_KEY_free(ecdh);
+	}
+#endif
+
 	rtp->dtls_verify = dtls_cfg->verify;
 
 	SSL_CTX_set_verify(rtp->ssl_ctx, (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) || (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) ?
@@ -1347,7 +1379,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 		}
 
 		for (i = 0; i < size; i++) {
-			sprintf(local_fingerprint, "%.2X:", (unsigned)fingerprint[i]);
+			sprintf(local_fingerprint, "%02hhX:", fingerprint[i]);
 			local_fingerprint += 3;
 		}
 
@@ -1394,6 +1426,8 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	dtls_srtp_stop_timeout_timer(instance, rtp, 0);
+
 	if (rtp->ssl_ctx) {
 		SSL_CTX_free(rtp->ssl_ctx);
 		rtp->ssl_ctx = NULL;
@@ -1402,11 +1436,17 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
 	if (rtp->dtls.ssl) {
 		SSL_free(rtp->dtls.ssl);
 		rtp->dtls.ssl = NULL;
+		ast_mutex_destroy(&rtp->dtls.lock);
 	}
 
-	if (rtp->rtcp && rtp->rtcp->dtls.ssl) {
-		SSL_free(rtp->rtcp->dtls.ssl);
-		rtp->rtcp->dtls.ssl = NULL;
+	if (rtp->rtcp) {
+		dtls_srtp_stop_timeout_timer(instance, rtp, 1);
+
+		if (rtp->rtcp->dtls.ssl) {
+			SSL_free(rtp->rtcp->dtls.ssl);
+			rtp->rtcp->dtls.ssl = NULL;
+			ast_mutex_destroy(&rtp->rtcp->dtls.lock);
+		}
 	}
 }
 
@@ -1509,7 +1549,7 @@ static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum
 	rtp->remote_hash = hash;
 
 	while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) {
-		sscanf(value, "%02x", (unsigned int*)&rtp->remote_fingerprint[pos++]);
+		sscanf(value, "%02hhx", &rtp->remote_fingerprint[pos++]);
 	}
 }
 
@@ -1560,6 +1600,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
 	.prop_set = ast_rtp_prop_set,
 	.fd = ast_rtp_fd,
 	.remote_address_set = ast_rtp_remote_address_set,
+	.alt_remote_address_set = ast_rtp_alt_remote_address_set,
 	.red_init = rtp_red_init,
 	.red_buffer = rtp_red_buffer,
 	.local_bridge = ast_rtp_local_bridge,
@@ -1569,7 +1610,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
 	.stop = ast_rtp_stop,
 	.qos = ast_rtp_qos_set,
 	.sendcng = ast_rtp_sendcng,
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	.ice = &ast_rtp_ice,
 #endif
 #ifdef HAVE_OPENSSL_SRTP
@@ -1578,32 +1619,36 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
 #endif
 };
 
+static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
+
 #ifdef HAVE_OPENSSL_SRTP
 static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtls_details *dtls, int rtcp)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
-	if (!dtls->ssl) {
+	/* If we are not acting as a client connecting to the remote side then
+	 * don't start the handshake as it will accomplish nothing and would conflict
+	 * with the handshake we receive from the remote side.
+	 */
+	if (!dtls->ssl || (dtls->dtls_setup != AST_RTP_DTLS_SETUP_ACTIVE)) {
 		return;
 	}
 
-	if (SSL_is_init_finished(dtls->ssl)) {
-		SSL_clear(dtls->ssl);
-		if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
-			SSL_set_accept_state(dtls->ssl);
-		} else {
-			SSL_set_connect_state(dtls->ssl);
-		}
-		dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
-	}
 	SSL_do_handshake(dtls->ssl);
+
+	/* Since the handshake is started in a thread outside of the channel thread it's possible
+	 * for the response to be handled in the channel thread before we start the timeout timer.
+	 * To ensure this doesn't actually happen we hold the DTLS lock. The channel thread will
+	 * block until we're done at which point the timeout timer will be immediately stopped.
+	 */
+	ast_mutex_lock(&dtls->lock);
 	dtls_srtp_check_pending(instance, rtp, rtcp);
+	dtls_srtp_start_timeout_timer(instance, rtp, rtcp);
+	ast_mutex_unlock(&dtls->lock);
 }
 #endif
 
-#ifdef HAVE_PJPROJECT
-static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
-
+#ifdef USE_PJPROJECT
 static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
 {
 	struct ast_rtp_instance *instance = ice->user_data;
@@ -1622,7 +1667,7 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
 			update_address_with_ice_candidate(rtp, AST_RTP_ICE_COMPONENT_RTCP, &rtp->rtcp->them);
 		}
 	}
- 
+
 #ifdef HAVE_OPENSSL_SRTP
 	dtls_perform_handshake(instance, &rtp->dtls, 0);
 
@@ -1751,48 +1796,81 @@ static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr)
 }
 
 #ifdef HAVE_OPENSSL_SRTP
-
-static int dtls_srtp_handle_timeout(const void *data)
+static void dtls_srtp_handle_timeout(struct ast_rtp_instance *instance, int rtcp)
 {
-	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
 
-	if (!rtp)
-	{
-		return 0;
+	ast_mutex_lock(&dtls->lock);
+	if (dtls->timeout_timer == -1) {
+		ast_mutex_unlock(&dtls->lock);
+		return;
 	}
 
-	ast_mutex_lock(&rtp->dtls_timer_lock);
-	if (rtp->dtlstimerid == -1)
-	{
-		ast_mutex_unlock(&rtp->dtls_timer_lock);
-		ao2_ref(instance, -1);
-		return 0;
-	}
+	dtls->timeout_timer = -1;
 
-	rtp->dtlstimerid = -1;
-	ast_mutex_unlock(&rtp->dtls_timer_lock);
+	DTLSv1_handle_timeout(dtls->ssl);
+	dtls_srtp_check_pending(instance, rtp, rtcp);
+	dtls_srtp_start_timeout_timer(instance, rtp, rtcp);
 
-	if (rtp->dtls.ssl && !SSL_is_init_finished(rtp->dtls.ssl)) {
-		DTLSv1_handle_timeout(rtp->dtls.ssl);
-	}
-	dtls_srtp_check_pending(instance, rtp, 0);
+	ast_mutex_unlock(&dtls->lock);
+}
 
-	if (rtp->rtcp && rtp->rtcp->dtls.ssl && !SSL_is_init_finished(rtp->rtcp->dtls.ssl)) {
-		DTLSv1_handle_timeout(rtp->rtcp->dtls.ssl);
-	}
-	dtls_srtp_check_pending(instance, rtp, 1);
+static int dtls_srtp_handle_rtp_timeout(const void *data)
+{
+	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
+
+	dtls_srtp_handle_timeout(instance, 0);
+	ao2_ref(instance, -1);
+
+	return 0;
+}
+
+static int dtls_srtp_handle_rtcp_timeout(const void *data)
+{
+	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
 
+	dtls_srtp_handle_timeout(instance, 1);
 	ao2_ref(instance, -1);
 
 	return 0;
 }
 
+static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp)
+{
+	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
+	struct timeval dtls_timeout;
+
+	if (DTLSv1_get_timeout(dtls->ssl, &dtls_timeout)) {
+		int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000;
+
+		ast_assert(dtls->timeout_timer == -1);
+
+		ao2_ref(instance, +1);
+		if ((dtls->timeout_timer = ast_sched_add(rtp->sched, timeout,
+			!rtcp ? dtls_srtp_handle_rtp_timeout : dtls_srtp_handle_rtcp_timeout, instance)) < 0) {
+			ao2_ref(instance, -1);
+			ast_log(LOG_WARNING, "Scheduling '%s' DTLS retransmission for RTP instance [%p] failed.\n",
+				!rtcp ? "RTP" : "RTCP", instance);
+		}
+	}
+}
+
+static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp)
+{
+	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
+
+	ast_mutex_lock(&dtls->lock);
+	if (!AST_SCHED_DEL(rtp->sched, dtls->timeout_timer)) {
+		ao2_ref(instance, -1);
+	}
+	ast_mutex_unlock(&dtls->lock);
+}
+
 static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp)
 {
 	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
 	size_t pending;
-	struct timeval dtls_timeout; /* timeout on DTLS  */
 
 	if (!dtls->ssl || !dtls->write_bio) {
 		return;
@@ -1818,24 +1896,6 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as
 		}
 
 		out = BIO_read(dtls->write_bio, outgoing, sizeof(outgoing));
-
-		/* Stop existing DTLS timer if running */
-		ast_mutex_lock(&rtp->dtls_timer_lock);
-		if (rtp->dtlstimerid > -1) {
-			AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1));
-			rtp->dtlstimerid = -1;
-		}
-
-		if (DTLSv1_get_timeout(dtls->ssl, &dtls_timeout)) {
-			int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000;
-			ao2_ref(instance, +1);
-			if ((rtp->dtlstimerid = ast_sched_add(rtp->sched, timeout, dtls_srtp_handle_timeout, instance)) < 0) {
-				ao2_ref(instance, -1);
-				ast_log(LOG_WARNING, "scheduling DTLS retransmission for RTP instance [%p] failed.\n", instance);
-			}
-		}
-		ast_mutex_unlock(&rtp->dtls_timer_lock);
-
 		__rtp_sendto(instance, outgoing, out, 0, &remote_address, rtcp, &ice, 0);
 	}
 }
@@ -1867,6 +1927,7 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
 	unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
 	struct ast_srtp_policy *local_policy, *remote_policy = NULL;
 	struct ast_rtp_instance_stats stats = { 0, };
+	int res = -1;
 
 	/* If a fingerprint is present in the SDP make sure that the peer certificate matches it */
 	if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) {
@@ -1981,16 +2042,17 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
 		}
 	}
 
-	return 0;
+	res = 0;
 
 error:
+	/* policy->destroy() called even on success to release local reference to these resources */
 	res_srtp_policy->destroy(local_policy);
 
 	if (remote_policy) {
 		res_srtp_policy->destroy(remote_policy);
 	}
 
-	return -1;
+	return res;
 }
 #endif
 
@@ -2000,7 +2062,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
 	char *in = buf;
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	struct ast_sockaddr *loop = rtcp ? &rtp->rtcp_loop : &rtp->rtp_loop;
 #endif
 
@@ -2009,10 +2071,9 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
 	}
 
 #ifdef HAVE_OPENSSL_SRTP
-	dtls_srtp_check_pending(instance, rtp, rtcp);
-
-	/* If this is an SSL packet pass it to OpenSSL for processing */
-	if ((*in >= 20) && (*in <= 64)) {
+	/* If this is an SSL packet pass it to OpenSSL for processing. RFC section for first byte value:
+	 * https://tools.ietf.org/html/rfc5764#section-5.1.2 */
+	if ((*in >= 20) && (*in <= 63)) {
 		struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
 		int res = 0;
 
@@ -2023,6 +2084,11 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
 			return -1;
 		}
 
+		/* Before we feed data into OpenSSL ensure that the timeout timer is either stopped, completed, or if
+		 * in progress that it will not do anything.
+		 */
+		dtls_srtp_stop_timeout_timer(instance, rtp, rtcp);
+
 		/* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */
 		if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
 			dtls->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
@@ -2051,13 +2117,18 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
 				/* Use the keying material to set up key/salt information */
 				res = dtls_srtp_setup(rtp, srtp, instance);
 			}
+		} else {
+			/* Since we've sent additional traffic start the timeout timer for retransmission */
+			ast_mutex_lock(&dtls->lock);
+			dtls_srtp_start_timeout_timer(instance, rtp, rtcp);
+			ast_mutex_unlock(&dtls->lock);
 		}
 
 		return res;
 	}
 #endif
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	if (!ast_sockaddr_isnull(loop) && !ast_sockaddr_cmp(loop, sa)) {
 		/* ICE traffic will have been handled in the TURN callback, so skip it but update the address
 		 * so it reflects the actual source and not the loopback
@@ -2124,7 +2195,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz
 		return -1;
 	}
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	if (rtp->ice) {
 		pj_thread_register_check();
 
@@ -2150,11 +2221,7 @@ static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size,
 
 static int rtp_get_rate(struct ast_format *format)
 {
-	/* For those wondering: due to a fluke in RFC publication, G.722 is advertised
-	 * as having a sample rate of 8kHz, while implementations must know that its
-	 * real rate is 16kHz. Seriously.
-	 */
-	return (ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) ? 8000 : (int)ast_format_get_sample_rate(format);
+	return (format->id == AST_FORMAT_G722) ? 8000 : ast_format_rate(format);
 }
 
 static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp)
@@ -2255,7 +2322,7 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
 	return (info->packets == 0);
 }
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *addr, int port, int component,
 				      int transport)
 {
@@ -2297,7 +2364,7 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
 
 	/* If configured to use a TURN relay create a session and allocate */
 	if (pj_strlen(&turnaddr)) {
-		ast_rtp_ice_turn_request(instance, component, AST_TRANSPORT_TCP, pj_strbuf(&turnaddr), turnport,
+		ast_rtp_ice_turn_request(instance, component, PJ_TURN_TP_TCP, pj_strbuf(&turnaddr), turnport,
 			pj_strbuf(&turnusername), pj_strbuf(&turnpassword));
 	}
 }
@@ -2332,7 +2399,7 @@ static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
 	return (unsigned int) ms;
 }
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 /*!
  * \internal
  * \brief Creates an ICE session. Can be used to replace a destroyed ICE session.
@@ -2364,7 +2431,7 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad
 
 	/* Create an ICE session for ICE negotiation */
 	if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, 2,
-			&ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) {
+			&ast_rtp_ice_sess_cb, &ufrag, &passwd, &rtp->ice) == PJ_SUCCESS) {
 		/* Make this available for the callbacks */
 		rtp->ice->user_data = instance;
 
@@ -2400,9 +2467,11 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
 		return -1;
 	}
 
+#ifdef USE_PJPROJECT
 	/* Initialize synchronization aspects */
 	ast_mutex_init(&rtp->lock);
 	ast_cond_init(&rtp->cond, NULL);
+#endif
 
 	/* Set default parameters on the newly created RTP structure */
 	rtp->ssrc = ast_random();
@@ -2418,7 +2487,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
 	     create_new_socket("RTP",
 			       ast_sockaddr_is_ipv4(addr) ? AF_INET  :
 			       ast_sockaddr_is_ipv6(addr) ? AF_INET6 : -1)) < 0) {
-		ast_debug(1, "Failed to create a new socket for RTP instance '%p'\n", instance);
+		ast_log(LOG_WARNING, "Failed to create a new socket for RTP instance '%p'\n", instance);
 		ast_free(rtp);
 		return -1;
 	}
@@ -2451,14 +2520,15 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
 		}
 	}
 
-#ifdef HAVE_PJPROJECT
+	ast_rtp_instance_set_data(instance, rtp);
+
+#ifdef USE_PJPROJECT
 	generate_random_string(rtp->local_ufrag, sizeof(rtp->local_ufrag));
 	generate_random_string(rtp->local_passwd, sizeof(rtp->local_passwd));
-#endif
-	ast_rtp_instance_set_data(instance, rtp);
-#ifdef HAVE_PJPROJECT
+
 	/* Create an ICE session for ICE negotiation */
 	if (icesupport) {
+		ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance);
 		if (ice_create(instance, addr, x, 0)) {
 			ast_log(LOG_NOTICE, "Failed to start ICE session\n");
 		} else {
@@ -2473,24 +2543,24 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
 
 #ifdef HAVE_OPENSSL_SRTP
 	rtp->rekeyid = -1;
-	rtp->dtlstimerid = -1;
+	rtp->dtls.timeout_timer = -1;
 #endif
 
-	rtp->f.subclass.format = ao2_bump(ast_format_none);
-	rtp->lastrxformat = ao2_bump(ast_format_none);
-	rtp->lasttxformat = ao2_bump(ast_format_none);
-
 	return 0;
 }
 
 static int ast_rtp_destroy(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000));
 	struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, };
 #endif
 
+#ifdef HAVE_OPENSSL_SRTP
+	ast_rtp_dtls_stop(instance);
+#endif
+
 	/* Destroy the smoother that was smoothing out audio if present */
 	if (rtp->smoother) {
 		ast_smoother_free(rtp->smoother);
@@ -2509,11 +2579,6 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
 		 * RTP instance while it's active.
 		 */
 		close(rtp->rtcp->s);
-#ifdef HAVE_OPENSSL_SRTP
-		if (rtp->rtcp->dtls.ssl) {
-			SSL_free(rtp->rtcp->dtls.ssl);
-		}
-#endif
 		ast_free(rtp->rtcp);
 	}
 
@@ -2523,7 +2588,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
 		ast_free(rtp->red);
 	}
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	pj_thread_register_check();
 
 	/* Destroy the RTP TURN relay if being used */
@@ -2563,27 +2628,11 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
 	if (rtp->ice_active_remote_candidates) {
 		ao2_ref(rtp->ice_active_remote_candidates, -1);
 	}
-#endif
-
-#ifdef HAVE_OPENSSL_SRTP
-	/* Destroy the SSL context if present */
-	if (rtp->ssl_ctx) {
-		SSL_CTX_free(rtp->ssl_ctx);
-	}
-
-	/* Destroy the SSL session if present */
-	if (rtp->dtls.ssl) {
-		SSL_free(rtp->dtls.ssl);
-	}
-#endif
-
-	ao2_cleanup(rtp->lasttxformat);
-	ao2_cleanup(rtp->lastrxformat);
-	ao2_cleanup(rtp->f.subclass.format);
 
 	/* Destroy synchronization items */
 	ast_mutex_destroy(&rtp->lock);
 	ast_cond_destroy(&rtp->cond);
+#endif
 
 	/* Finally destroy ourselves */
 	ast_free(rtp);
@@ -2757,7 +2806,7 @@ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, cha
 
 	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
 
-	if (duration > 0 && (measured_samples = duration * rtp_get_rate(rtp->f.subclass.format) / 1000) > rtp->send_duration) {
+	if (duration > 0 && (measured_samples = duration * rtp_get_rate(&rtp->f.subclass.format) / 1000) > rtp->send_duration) {
 		ast_debug(2, "Adjusting final end duration from %d to %u\n", rtp->send_duration, measured_samples);
 		rtp->send_duration = measured_samples;
 	}
@@ -2854,235 +2903,242 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
 	*lsw = frac;
 }
 
-static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv)
+/*! \brief Send RTCP recipient's report */
+static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
 {
-	tv->tv_sec = msw - 2208988800u;
-	tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8);
-}
-
-static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
-		unsigned int *lost_packets,
-		int *fraction_lost)
-{
-	unsigned int extended_seq_no;
-	unsigned int expected_packets;
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	int res;
+	int len = 32;
+	unsigned int lost;
+	unsigned int extended;
+	unsigned int expected;
 	unsigned int expected_interval;
 	unsigned int received_interval;
-	double rxlost_current;
 	int lost_interval;
+	struct timeval now;
+	unsigned int *rtcpheader;
+	char bdata[1024];
+	struct timeval dlsr;
+	int fraction;
+	int rate = rtp_get_rate(&rtp->f.subclass.format);
+	int ice;
+	double rxlost_current;
+	struct ast_sockaddr remote_address = { {0,} };
+
+	if (!rtp || !rtp->rtcp)
+		return 0;
 
-	/* Compute statistics */
-	extended_seq_no = rtp->cycles + rtp->lastrxseqno;
-	expected_packets = extended_seq_no - rtp->seedrxseqno + 1;
-	if (rtp->rxcount > expected_packets) {
-		expected_packets += rtp->rxcount - expected_packets;
+	if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
+		/*
+		 * RTCP was stopped.
+		 */
+		return 0;
 	}
-	*lost_packets = expected_packets - rtp->rxcount;
-	expected_interval = expected_packets - rtp->rtcp->expected_prior;
+
+	extended = rtp->cycles + rtp->lastrxseqno;
+	expected = extended - rtp->seedrxseqno + 1;
+	lost = expected - rtp->rxcount;
+	expected_interval = expected - rtp->rtcp->expected_prior;
+	rtp->rtcp->expected_prior = expected;
 	received_interval = rtp->rxcount - rtp->rtcp->received_prior;
+	rtp->rtcp->received_prior = rtp->rxcount;
 	lost_interval = expected_interval - received_interval;
-	if (expected_interval == 0 || lost_interval <= 0) {
-		*fraction_lost = 0;
-	} else {
-		*fraction_lost = (lost_interval << 8) / expected_interval;
-	}
 
-	/* Update RTCP statistics */
-	rtp->rtcp->received_prior = rtp->rxcount;
-	rtp->rtcp->expected_prior = expected_packets;
-	if (lost_interval <= 0) {
+	if (lost_interval <= 0)
 		rtp->rtcp->rxlost = 0;
-	} else {
-		rtp->rtcp->rxlost = lost_interval;
-	}
-	if (rtp->rtcp->rxlost_count == 0) {
+	else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
+	if (rtp->rtcp->rxlost_count == 0)
 		rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
-	}
-	if (lost_interval < rtp->rtcp->minrxlost) {
+	if (lost_interval < rtp->rtcp->minrxlost)
 		rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
-	}
-	if (lost_interval > rtp->rtcp->maxrxlost) {
+	if (lost_interval > rtp->rtcp->maxrxlost)
 		rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
-	}
-	rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost,
-			rtp->rtcp->rxlost,
-			rtp->rtcp->rxlost_count);
-	rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost,
-			rtp->rtcp->rxlost,
-			rtp->rtcp->normdev_rxlost,
-			rxlost_current,
-			rtp->rtcp->rxlost_count);
+
+	rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
+	rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
 	rtp->rtcp->normdev_rxlost = rxlost_current;
 	rtp->rtcp->rxlost_count++;
+
+	if (expected_interval == 0 || lost_interval <= 0)
+		fraction = 0;
+	else
+		fraction = (lost_interval << 8) / expected_interval;
+	gettimeofday(&now, NULL);
+	timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+	rtcpheader = (unsigned int *)bdata;
+	rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
+	rtcpheader[1] = htonl(rtp->ssrc);
+	rtcpheader[2] = htonl(rtp->themssrc);
+	rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
+	rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
+	rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * rate));
+	rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
+	rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+
+	/*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
+	  it can change mid call, and SDES can't) */
+	rtcpheader[len/4]     = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
+	rtcpheader[(len/4)+1] = htonl(rtp->ssrc);               /* Our SSRC */
+	rtcpheader[(len/4)+2] = htonl(0x01 << 24);              /* Empty for the moment */
+	len += 12;
+
+	ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+
+	res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
+
+	if (res < 0) {
+		ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
+		return 0;
+	}
+
+	rtp->rtcp->rr_count++;
+
+	if (rtcp_debug_test_addr(&remote_address)) {
+		ast_verbose("\n* Sending RTCP RR to %s%s\n"
+			"  Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n"
+			"  IA jitter: %.4f\n"
+			"  Their last SR: %u\n"
+			    "  DLSR: %4.4f (sec)\n\n",
+			    ast_sockaddr_stringify(&remote_address),
+			    ice ? " (via ICE)" : "",
+			    rtp->ssrc, rtp->themssrc, fraction, lost,
+			    rtp->rxjitter,
+			    rtp->rtcp->themrxlsr,
+			    (double)(ntohl(rtcpheader[7])/65536.0));
+	}
+
+	return res;
 }
 
-/*! \brief Send RTCP SR or RR report */
-static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
+/*! \brief Send RTCP sender's report */
+static int ast_rtcp_write_sr(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-	RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
 	int res;
 	int len = 0;
 	struct timeval now;
 	unsigned int now_lsw;
 	unsigned int now_msw;
 	unsigned int *rtcpheader;
-	unsigned int lost_packets;
-	int fraction_lost;
-	struct timeval dlsr = { 0, };
+	unsigned int lost;
+	unsigned int extended;
+	unsigned int expected;
+	unsigned int expected_interval;
+	unsigned int received_interval;
+	int lost_interval;
+	int fraction;
+	struct timeval dlsr;
 	char bdata[512];
-	int rate = rtp_get_rate(rtp->f.subclass.format);
+	int rate = rtp_get_rate(&rtp->f.subclass.format);
 	int ice;
-	int header_offset = 0;
-	char *str_remote_address;
-	char *str_local_address;
-	struct ast_sockaddr remote_address = { { 0, } };
-	struct ast_sockaddr local_address = { { 0, } };
-	struct ast_sockaddr real_remote_address = { { 0, } };
-	struct ast_sockaddr real_local_address = { { 0, } };
-	struct ast_rtp_rtcp_report_block *report_block = NULL;
-	RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
-			ast_rtp_rtcp_report_alloc(rtp->themssrc ? 1 : 0),
-			ao2_cleanup);
-
-	if (!rtp || !rtp->rtcp) {
+	struct ast_sockaddr remote_address = { {0,} };
+
+	if (!rtp || !rtp->rtcp)
 		return 0;
-	}
 
 	if (ast_sockaddr_isnull(&rtp->rtcp->them)) {  /* This'll stop rtcp for this rtp session */
-		/* RTCP was stopped. */
+		/*
+		 * RTCP was stopped.
+		 */
 		return 0;
 	}
 
-	if (!rtcp_report) {
-		return 1;
-	}
-
-	/* Compute statistics */
-	calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);
-
 	gettimeofday(&now, NULL);
-	rtcp_report->reception_report_count = rtp->themssrc ? 1 : 0;
-	rtcp_report->ssrc = rtp->ssrc;
-	rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR;
-	if (sr) {
-		rtcp_report->sender_information.ntp_timestamp = now;
-		rtcp_report->sender_information.rtp_timestamp = rtp->lastts;
-		rtcp_report->sender_information.packet_count = rtp->txcount;
-		rtcp_report->sender_information.octet_count = rtp->txoctetcount;
-	}
-
-	if (rtp->themssrc) {
-		report_block = ast_calloc(1, sizeof(*report_block));
-		if (!report_block) {
-			return 1;
-		}
-
-		rtcp_report->report_block[0] = report_block;
-		report_block->source_ssrc = rtp->themssrc;
-		report_block->lost_count.fraction = (fraction_lost & 0xff);
-		report_block->lost_count.packets = (lost_packets & 0xffffff);
-		report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));
-		report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rate);
-		report_block->lsr = rtp->rtcp->themrxlsr;
-		/* If we haven't received an SR report, DLSR should be 0 */
-		if (!ast_tvzero(rtp->rtcp->rxlsr)) {
-			timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
-			report_block->dlsr = (((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000;
-		}
-	}
-	timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw);
+	timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
 	rtcpheader = (unsigned int *)bdata;
-	rtcpheader[1] = htonl(rtcp_report->ssrc);            /* Our SSRC */
-	len += 8;
-	if (sr) {
-		header_offset = 5;
-		rtcpheader[2] = htonl(now_msw);                 /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
-		rtcpheader[3] = htonl(now_lsw);                 /* now, LSW */
-		rtcpheader[4] = htonl(rtcp_report->sender_information.rtp_timestamp);
-		rtcpheader[5] = htonl(rtcp_report->sender_information.packet_count);
-		rtcpheader[6] = htonl(rtcp_report->sender_information.octet_count);
-		len += 20;
-	}
-	if (report_block) {
-		rtcpheader[2 + header_offset] = htonl(report_block->source_ssrc);     /* Their SSRC */
-		rtcpheader[3 + header_offset] = htonl((report_block->lost_count.fraction << 24) | report_block->lost_count.packets);
-		rtcpheader[4 + header_offset] = htonl(report_block->highest_seq_no);
-		rtcpheader[5 + header_offset] = htonl(report_block->ia_jitter);
-		rtcpheader[6 + header_offset] = htonl(report_block->lsr);
-		rtcpheader[7 + header_offset] = htonl(report_block->dlsr);
-		len += 24;
-	}
-	rtcpheader[0] = htonl((2 << 30) | (rtcp_report->reception_report_count << 24)
-					| ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1));
+	rtcpheader[1] = htonl(rtp->ssrc);               /* Our SSRC */
+	rtcpheader[2] = htonl(now_msw);                 /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
+	rtcpheader[3] = htonl(now_lsw);                 /* now, LSW */
+	rtcpheader[4] = htonl(rtp->lastts);             /* FIXME shouldn't be that, it should be now */
+	rtcpheader[5] = htonl(rtp->txcount);            /* No. packets sent */
+	rtcpheader[6] = htonl(rtp->txoctetcount);       /* No. bytes sent */
+	len += 28;
+
+	extended = rtp->cycles + rtp->lastrxseqno;
+	expected = extended - rtp->seedrxseqno + 1;
+	if (rtp->rxcount > expected)
+		expected += rtp->rxcount - expected;
+	lost = expected - rtp->rxcount;
+	expected_interval = expected - rtp->rtcp->expected_prior;
+	rtp->rtcp->expected_prior = expected;
+	received_interval = rtp->rxcount - rtp->rtcp->received_prior;
+	rtp->rtcp->received_prior = rtp->rxcount;
+	lost_interval = expected_interval - received_interval;
+	if (expected_interval == 0 || lost_interval <= 0)
+		fraction = 0;
+	else
+		fraction = (lost_interval << 8) / expected_interval;
+	timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+	rtcpheader[7] = htonl(rtp->themssrc);
+	rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
+	rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
+	rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * rate));
+	rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
+	rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+	len += 24;
+
+	rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 16) | ((len/4)-1));
 
 	/* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
 	/* it can change mid call, and SDES can't) */
 	rtcpheader[len/4]     = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
-	rtcpheader[(len/4)+1] = htonl(rtcp_report->ssrc);
-	rtcpheader[(len/4)+2] = htonl(0x01 << 24);
+	rtcpheader[(len/4)+1] = htonl(rtp->ssrc);               /* Our SSRC */
+	rtcpheader[(len/4)+2] = htonl(0x01 << 24);                    /* Empty for the moment */
 	len += 12;
 
 	ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+
 	res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
 	if (res < 0) {
-		ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",
-			sr ? "SR" : "RR",
+		ast_log(LOG_ERROR, "RTCP SR transmission error to %s, rtcp halted %s\n",
 			ast_sockaddr_stringify(&rtp->rtcp->them),
 			strerror(errno));
 		return 0;
 	}
 
-	/* Update RTCP SR/RR statistics */
-	if (sr) {
-		rtp->rtcp->txlsr = rtcp_report->sender_information.ntp_timestamp;
-		rtp->rtcp->sr_count++;
-		rtp->rtcp->lastsrtxcount = rtp->txcount;
-	} else {
-		rtp->rtcp->rr_count++;
-	}
+	/* FIXME Don't need to get a new one */
+	gettimeofday(&rtp->rtcp->txlsr, NULL);
+	rtp->rtcp->sr_count++;
+
+	rtp->rtcp->lastsrtxcount = rtp->txcount;
 
 	if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
-		ast_verbose("* Sent RTCP %s to %s%s\n", sr ? "SR" : "RR",
-				ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
-		ast_verbose("  Our SSRC: %u\n", rtcp_report->ssrc);
-		if (sr) {
-			ast_verbose("  Sent(NTP): %u.%010u\n",
-				(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
-				(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
-			ast_verbose("  Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp);
-			ast_verbose("  Sent packets: %u\n", rtcp_report->sender_information.packet_count);
-			ast_verbose("  Sent octets: %u\n", rtcp_report->sender_information.octet_count);
-		}
+		ast_verbose("* Sent RTCP SR to %s%s\n", ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
+		ast_verbose("  Our SSRC: %u\n", rtp->ssrc);
+		ast_verbose("  Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096);
+		ast_verbose("  Sent(RTP): %u\n", rtp->lastts);
+		ast_verbose("  Sent packets: %u\n", rtp->txcount);
+		ast_verbose("  Sent octets: %u\n", rtp->txoctetcount);
 		ast_verbose("  Report block:\n");
-		ast_verbose("    Their SSRC: %u\n", report_block->source_ssrc);
-		ast_verbose("    Fraction lost: %d\n", report_block->lost_count.fraction);
-		ast_verbose("    Cumulative loss: %u\n", report_block->lost_count.packets);
-		ast_verbose("    Highest seq no: %u\n", report_block->highest_seq_no);
-		ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / rate);
-		ast_verbose("    Their last SR: %u\n", report_block->lsr);
-		ast_verbose("    DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));
-	}
-
-	ast_rtp_instance_get_local_address(instance, &local_address);
-	if (!ast_find_ourip(&real_local_address, &local_address, 0)) {
-		str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address));
-	} else {
-		str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address));
-	}
-
-	if (!ast_find_ourip(&real_remote_address, &remote_address, 0)) {
-		str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address));
-	} else {
-		str_remote_address = ast_strdupa(ast_sockaddr_stringify(&remote_address));
-	}
-
-	message_blob = ast_json_pack("{s: s, s: s}",
-			"to", str_remote_address,
-			"from", str_local_address);
-	ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),
-			rtcp_report,
-			message_blob);
+		ast_verbose("  Fraction lost: %d\n", fraction);
+		ast_verbose("  Cumulative loss: %u\n", lost);
+		ast_verbose("  IA jitter: %.4f\n", rtp->rxjitter);
+		ast_verbose("  Their last SR: %u\n", rtp->rtcp->themrxlsr);
+		ast_verbose("  DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0));
+	}
+	manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To: %s\r\n"
+					    "OurSSRC: %u\r\n"
+					    "SentNTP: %u.%010u\r\n"
+					    "SentRTP: %u\r\n"
+					    "SentPackets: %u\r\n"
+					    "SentOctets: %u\r\n"
+					    "ReportBlock:\r\n"
+					    "FractionLost: %d\r\n"
+					    "CumulativeLoss: %u\r\n"
+					    "IAJitter: %.4f\r\n"
+					    "TheirLastSR: %u\r\n"
+		      "DLSR: %4.4f (sec)\r\n",
+		      ast_sockaddr_stringify(&remote_address),
+		      rtp->ssrc,
+		      (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096,
+		      rtp->lastts,
+		      rtp->txcount,
+		      rtp->txoctetcount,
+		      fraction,
+		      lost,
+		      rtp->rxjitter,
+		      rtp->rtcp->themrxlsr,
+		      (double)(ntohl(rtcpheader[12])/65536.0));
 	return res;
 }
 
@@ -3101,19 +3157,17 @@ static int ast_rtcp_write(const void *data)
 	}
 
 	if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
-		/* Send an SR */
-		res = ast_rtcp_write_report(instance, 1);
+		res = ast_rtcp_write_sr(instance);
 	} else {
-		/* Send an RR */
-		res = ast_rtcp_write_report(instance, 0);
+		res = ast_rtcp_write_rr(instance);
 	}
 
 	if (!res) {
-		/*
+		/* 
 		 * Not being rescheduled.
 		 */
-		ao2_ref(instance, -1);
 		rtp->rtcp->schedid = -1;
+		ao2_ref(instance, -1);
 	}
 
 	return res;
@@ -3125,9 +3179,9 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame
 	int pred, mark = 0;
 	unsigned int ms = calc_txstamp(rtp, &frame->delivery);
 	struct ast_sockaddr remote_address = { {0,} };
-	int rate = rtp_get_rate(frame->subclass.format) / 1000;
+	int rate = rtp_get_rate(&frame->subclass.format) / 1000;
 
-	if (ast_format_cmp(frame->subclass.format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) {
+	if (frame->subclass.format.id == AST_FORMAT_G722) {
 		frame->samples /= 2;
 	}
 
@@ -3143,25 +3197,25 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame
 		if (ast_tvzero(frame->delivery)) {
 			/* If this isn't an absolute delivery time, Check if it is close to our prediction,
 			   and if so, go with our prediction */
-			if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW) {
+			if (abs((int)rtp->lastts - pred) < MAX_TIMESTAMP_SKEW) {
 				rtp->lastts = pred;
 			} else {
-				ast_debug(3, "Difference is %d, ms is %u\n", abs(rtp->lastts - pred), ms);
+				ast_debug(3, "Difference is %d, ms is %u\n", abs((int)rtp->lastts - pred), ms);
 				mark = 1;
 			}
 		}
 	} else if (frame->frametype == AST_FRAME_VIDEO) {
-		mark = frame->subclass.frame_ending;
+		mark = ast_format_get_video_mark(&frame->subclass.format);
 		pred = rtp->lastovidtimestamp + frame->samples;
 		/* Re-calculate last TS */
 		rtp->lastts = rtp->lastts + ms * 90;
 		/* If it's close to our prediction, go for it */
 		if (ast_tvzero(frame->delivery)) {
-			if (abs(rtp->lastts - pred) < 7200) {
+			if (abs((int)rtp->lastts - pred) < 7200) {
 				rtp->lastts = pred;
 				rtp->lastovidtimestamp += frame->samples;
 			} else {
-				ast_debug(3, "Difference is %d, ms is %u (%u), pred/ts/samples %u/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
+				ast_debug(3, "Difference is %d, ms is %u (%u), pred/ts/samples %u/%d/%d\n", abs((int)rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
 				rtp->lastovidtimestamp = rtp->lastts;
 			}
 		}
@@ -3171,11 +3225,11 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame
 		rtp->lastts = rtp->lastts + ms;
 		/* If it's close to our prediction, go for it */
 		if (ast_tvzero(frame->delivery)) {
-			if (abs(rtp->lastts - pred) < 7200) {
+			if (abs((int)rtp->lastts - pred) < 7200) {
 				rtp->lastts = pred;
 				rtp->lastotexttimestamp += frame->samples;
 			} else {
-				ast_debug(3, "Difference is %d, ms is %u, pred/ts/samples %u/%d/%d\n", abs(rtp->lastts - pred), ms, rtp->lastts, pred, frame->samples);
+				ast_debug(3, "Difference is %d, ms is %u, pred/ts/samples %u/%d/%d\n", abs((int)rtp->lastts - pred), ms, rtp->lastts, pred, frame->samples);
 				rtp->lastotexttimestamp = rtp->lastts;
 			}
 		}
@@ -3224,7 +3278,7 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame
 			rtp->txcount++;
 			rtp->txoctetcount += (res - hdrlen);
 
-			if (rtp->rtcp && rtp->rtcp->schedid < 1) {
+			if (rtp->rtcp && rtp->rtcp->schedid < 0) {
 				ast_debug(1, "Starting RTCP transmission on RTP instance '%p'\n", instance);
 				ao2_ref(instance, +1);
 				rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
@@ -3268,18 +3322,16 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
 
 	/* write each generation length in red header */
 	len = red->hdrlen;
-	for (i = 0; i < red->num_gen; i++) {
+	for (i = 0; i < red->num_gen; i++)
 		len += data[i*4+3] = red->len[i];
-	}
 
 	/* add primary data to buffer */
 	memcpy(&data[len], red->t140.data.ptr, red->t140.datalen);
 	red->t140red.datalen = len + red->t140.datalen;
 
 	/* no primary data and no generations to send */
-	if (len == red->hdrlen && !red->t140.datalen) {
+	if (len == red->hdrlen && !red->t140.datalen)
 		return NULL;
-	}
 
 	/* reset t.140 buffer */
 	red->t140.datalen = 0;
@@ -3291,7 +3343,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_sockaddr remote_address = { {0,} };
-	struct ast_format *format;
+	struct ast_format subclass;
 	int codec;
 
 	ast_rtp_instance_get_remote_address(instance, &remote_address);
@@ -3302,45 +3354,6 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 		return 0;
 	}
 
-	/* VP8: is this a request to send a RTCP FIR? */
-	if (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) {
-		struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-		unsigned int *rtcpheader;
-		char bdata[1024];
-		int len = 20;
-		int ice;
-		int res;
-
-		if (!rtp || !rtp->rtcp) {
-			return 0;
-		}
-
-		if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
-			/*
-			 * RTCP was stopped.
-			 */
-			return 0;
-		}
-
-		/* Prepare RTCP FIR (PT=206, FMT=4) */
-		rtp->rtcp->firseq++;
-		if(rtp->rtcp->firseq == 256) {
-			rtp->rtcp->firseq = 0;
-		}
-
-		rtcpheader = (unsigned int *)bdata;
-		rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
-		rtcpheader[1] = htonl(rtp->ssrc);
-		rtcpheader[2] = htonl(rtp->themssrc);
-		rtcpheader[3] = htonl(rtp->themssrc);	/* FCI: SSRC */
-		rtcpheader[4] = htonl(rtp->rtcp->firseq << 24);			/* FCI: Sequence number */
-		res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them, &ice);
-		if (res < 0) {
-			ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno));
-		}
-		return 0;
-	}
-
 	/* If there is no data length we can't very well send the packet */
 	if (!frame->datalen) {
 		ast_debug(1, "Received frame with no data for RTP instance '%p' so dropping frame\n", instance);
@@ -3361,28 +3374,17 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 	}
 
 	/* Grab the subclass and look up the payload we are going to use */
-	codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance),
-	                                    1,
-	                                    frame->subclass.format,
-	                                    0);
-	if (codec < 0) {
-		ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n",
-			ast_format_get_name(frame->subclass.format));
+	ast_format_copy(&subclass, &frame->subclass.format);
+	if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, &subclass, 0)) < 0) {
+		ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(&frame->subclass.format));
 		return -1;
 	}
 
-	/* Note that we do not increase the ref count here as this pointer
-	 * will not be held by any thing explicitly. The format variable is
-	 * merely a convenience reference to frame->subclass.format */
-	format = frame->subclass.format;
-	if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		/* Oh dear, if the format changed we will have to set up a new smoother */
-		if (option_debug > 0) {
-			ast_debug(1, "Ooh, format changed from %s to %s\n",
-				ast_format_get_name(rtp->lasttxformat),
-				ast_format_get_name(frame->subclass.format));
-		}
-		ao2_replace(rtp->lasttxformat, format);
+	/* Oh dear, if the format changed we will have to set up a new smoother */
+	if (ast_format_cmp(&rtp->lasttxformat, &subclass) == AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(&rtp->lasttxformat), ast_getformatname(&subclass));
+		rtp->lasttxformat = subclass;
+		ast_format_copy(&rtp->lasttxformat, &subclass);
 		if (rtp->smoother) {
 			ast_smoother_free(rtp->smoother);
 			rtp->smoother = NULL;
@@ -3390,15 +3392,32 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 	}
 
 	/* If no smoother is present see if we have to set one up */
-	if (!rtp->smoother && ast_format_can_be_smoothed(format)) {
-		unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance));
-
-		if (framing_ms) {
-			rtp->smoother = ast_smoother_new((framing_ms * ast_format_get_minimum_bytes(format)) / ast_format_get_minimum_ms(format));
-			if (!rtp->smoother) {
-				ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %u len: %u\n",
-					ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format));
-				return -1;
+	if (!rtp->smoother) {
+		struct ast_format_list fmt = ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance)->pref, &subclass);
+
+		switch (subclass.id) {
+		case AST_FORMAT_SPEEX:
+		case AST_FORMAT_SPEEX16:
+		case AST_FORMAT_SPEEX32:
+		case AST_FORMAT_SILK:
+		case AST_FORMAT_CELT:
+		case AST_FORMAT_G723_1:
+		case AST_FORMAT_SIREN7:
+		case AST_FORMAT_SIREN14:
+		case AST_FORMAT_G719:
+			/* these are all frame-based codecs and cannot be safely run through
+			   a smoother */
+			break;
+		default:
+			if (fmt.inc_ms) {
+				if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
+					ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %d len: %d\n", ast_getformatname(&subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
+					return -1;
+				}
+				if (fmt.flags) {
+					ast_smoother_set_flags(rtp->smoother, fmt.flags);
+				}
+				ast_debug(1, "Created smoother: format: %s ms: %d len: %d\n", ast_getformatname(&subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
 			}
 		}
 	}
@@ -3446,7 +3465,7 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t
 	double d;
 	double dtv;
 	double prog;
-	int rate = rtp_get_rate(rtp->f.subclass.format);
+	int rate = rtp_get_rate(&rtp->f.subclass.format);
 
 	double normdev_rxjitter_current;
 	if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
@@ -3471,10 +3490,10 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t
 	transit = current_time - dtv;
 	d = transit - rtp->rxtransit;
 	rtp->rxtransit = transit;
-	if (d<0) {
+	if (d<0)
 		d=-d;
-	}
 	rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
+
 	if (rtp->rtcp) {
 		if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
 			rtp->rtcp->maxrxjitter = rtp->rxjitter;
@@ -3595,18 +3614,17 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha
 		new_duration = (new_duration & ~0xFFFF) | samples;
 
 		if (event_end & 0x80) {
-			/* End event */
-			if ((rtp->last_seqno != seqno) && (timestamp > rtp->last_end_timestamp)) {
+			if ((seqno != rtp->last_seqno) && (timestamp > rtp->last_end_timestamp)) {
 				rtp->last_end_timestamp = timestamp;
 				rtp->dtmf_duration = new_duration;
 				rtp->resp = resp;
 				f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
-				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));
+				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0));
 				rtp->resp = 0;
 				rtp->dtmf_duration = rtp->dtmf_timeout = 0;
 				AST_LIST_INSERT_TAIL(frames, f, frame_list);
 			} else if (rtpdebug) {
-				ast_debug(1, "Dropping duplicate or out of order DTMF END frame (seqno: %u, ts %u, digit %c)\n",
+				ast_debug(1, "Dropping re-transmitted, duplicate, or out of order DTMF END frame (seqno: %u, ts %u, digit %c)\n",
 					seqno, timestamp, resp);
 			}
 		} else {
@@ -3632,7 +3650,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha
 			if (rtp->resp && rtp->resp != resp) {
 				/* Another digit already began. End it */
 				f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
-				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));
+				f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0));
 				rtp->resp = 0;
 				rtp->dtmf_duration = rtp->dtmf_timeout = 0;
 				AST_LIST_INSERT_TAIL(frames, f, frame_list);
@@ -3729,11 +3747,10 @@ static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, u
 		}
 	} else if ((rtp->resp == resp) && !power) {
 		f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
-		f->samples = rtp->dtmfsamples * (rtp_get_rate(rtp->lastrxformat) / 1000);
+		f->samples = rtp->dtmfsamples * (rtp->lastrxformat.id ? (rtp_get_rate(&rtp->lastrxformat) / 1000) : 8);
 		rtp->resp = 0;
-	} else if (rtp->resp == resp) {
-		rtp->dtmfsamples += 20 * (rtp_get_rate(rtp->lastrxformat) / 1000);
-	}
+	} else if (rtp->resp == resp)
+		rtp->dtmfsamples += 20 * (rtp->lastrxformat.id ? (rtp_get_rate(&rtp->lastrxformat) / 1000) : 8);
 
 	rtp->dtmf_timeout = 0;
 
@@ -3747,10 +3764,8 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
 	/* Convert comfort noise into audio with various codecs.  Unfortunately this doesn't
 	   totally help us out becuase we don't have an engine to keep it going and we are not
 	   guaranteed to have it every 20ms or anything */
-	if (rtpdebug) {
-		ast_debug(0, "- RTP 3389 Comfort noise event: Format %s (len = %d)\n",
-			ast_format_get_name(rtp->lastrxformat), len);
-	}
+	if (rtpdebug)
+		ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", (int) rtp->lastrxformat.id, len);
 
 	if (ast_test_flag(rtp, FLAG_3389_WARNING)) {
 		struct ast_sockaddr remote_address = { {0,} };
@@ -3763,9 +3778,8 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
 	}
 
 	/* Must have at least one byte */
-	if (!len) {
+	if (!len)
 		return NULL;
-	}
 	if (len < 24) {
 		rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
 		rtp->f.datalen = len - 1;
@@ -3784,104 +3798,6 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
 	return &rtp->f;
 }
 
-static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int dlsr)
-{
-	struct timeval now;
-	struct timeval rtt_tv;
-	unsigned int msw;
-	unsigned int lsw;
-	unsigned int rtt_msw;
-	unsigned int rtt_lsw;
-	unsigned int lsr_a;
-	unsigned int rtt;
-	double normdevrtt_current;
-
-	gettimeofday(&now, NULL);
-	timeval2ntp(now, &msw, &lsw);
-
-	lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16);
-	rtt = lsr_a - lsr - dlsr;
-	rtt_msw = (rtt & 0xffff0000) >> 16;
-	rtt_lsw = (rtt & 0x0000ffff) << 16;
-	rtt_tv.tv_sec = rtt_msw;
-	rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8);
-	rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000);
-	if (lsr_a - dlsr < lsr) {
-		return 1;
-	}
-
-	rtp->rtcp->accumulated_transit += rtp->rtcp->rtt;
-	if (rtp->rtcp->rtt_count == 0 || rtp->rtcp->minrtt > rtp->rtcp->rtt) {
-		rtp->rtcp->minrtt = rtp->rtcp->rtt;
-	}
-	if (rtp->rtcp->maxrtt < rtp->rtcp->rtt) {
-		rtp->rtcp->maxrtt = rtp->rtcp->rtt;
-	}
-
-	normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt,
-			rtp->rtcp->rtt,
-			rtp->rtcp->rtt_count);
-	rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt,
-			rtp->rtcp->rtt,
-			rtp->rtcp->normdevrtt,
-			normdevrtt_current,
-			rtp->rtcp->rtt_count);
-	rtp->rtcp->normdevrtt = normdevrtt_current;
-	rtp->rtcp->rtt_count++;
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Update RTCP interarrival jitter stats
- */
-static void update_jitter_stats(struct ast_rtp *rtp, unsigned int ia_jitter)
-{
-	double reported_jitter;
-	double reported_normdev_jitter_current;
-
-	rtp->rtcp->reported_jitter = ia_jitter;
-	reported_jitter = (double) rtp->rtcp->reported_jitter;
-	if (rtp->rtcp->reported_jitter_count == 0) {
-		rtp->rtcp->reported_minjitter = reported_jitter;
-	}
-	if (reported_jitter < rtp->rtcp->reported_minjitter) {
-		rtp->rtcp->reported_minjitter = reported_jitter;
-	}
-	if (reported_jitter > rtp->rtcp->reported_maxjitter) {
-		rtp->rtcp->reported_maxjitter = reported_jitter;
-	}
-	reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
-	rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
-	rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
-}
-
-/*!
- * \internal
- * \brief Update RTCP lost packet stats
- */
-static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
-{
-	double reported_lost;
-	double reported_normdev_lost_current;
-
-	rtp->rtcp->reported_lost = lost_packets;
-	reported_lost = (double)rtp->rtcp->reported_lost;
-	if (rtp->rtcp->reported_jitter_count == 0) {
-		rtp->rtcp->reported_minlost = reported_lost;
-	}
-	if (reported_lost < rtp->rtcp->reported_minlost) {
-		rtp->rtcp->reported_minlost = reported_lost;
-	}
-	if (reported_lost > rtp->rtcp->reported_maxlost) {
-		rtp->rtcp->reported_maxlost = reported_lost;
-	}
-	reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
-	rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
-	rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
-}
-
 static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -3889,14 +3805,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 	unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
 	unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
 	int res, packetwords, position = 0;
-	int report_counter = 0;
-	struct ast_rtp_rtcp_report_block *report_block;
 	struct ast_frame *f = &ast_null_frame;
-	char *str_local_address;
-	char *str_remote_address;
-	struct ast_sockaddr local_address = { { 0,} };
-	struct ast_sockaddr real_local_address = { { 0, } };
-	struct ast_sockaddr real_remote_address = { { 0, } };
 
 	/* Read in RTCP data from the socket */
 	if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET,
@@ -3944,22 +3853,20 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 		/* Send to whoever sent to us */
 		if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) {
 			ast_sockaddr_copy(&rtp->rtcp->them, &addr);
-			if (rtpdebug) {
+			if (rtpdebug)
 				ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
 					  ast_sockaddr_stringify(&rtp->rtcp->them));
-			}
 		}
 	}
 
 	ast_debug(1, "Got RTCP report of %d bytes\n", res);
 
-	ast_rtp_instance_get_local_address(instance, &local_address);
-
 	while (position < packetwords) {
 		int i, pt, rc;
-		unsigned int length;
-		struct ast_json *message_blob;
-		RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup);
+		unsigned int length, dlsr, lsr, msw, lsw, comp;
+		struct timeval now;
+		double rttsec, reported_jitter, reported_normdev_jitter_current, normdevrtt_current, reported_lost, reported_normdev_lost_current;
+		uint64_t rtt = 0;
 
 		i = position;
 		length = ntohl(rtcpheader[i]);
@@ -3967,136 +3874,197 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 		rc = (length & 0x1f000000) >> 24;
 		length &= 0xffff;
 
-		rtcp_report = ast_rtp_rtcp_report_alloc(rc);
-		if (!rtcp_report) {
-			return &ast_null_frame;
-		}
-		rtcp_report->reception_report_count = rc;
-		rtcp_report->ssrc = ntohl(rtcpheader[i + 1]);
-
 		if ((i + length) > packetwords) {
-			if (rtpdebug) {
+			if (rtpdebug)
 				ast_debug(1, "RTCP Read too short\n");
-			}
 			return &ast_null_frame;
 		}
 
 		if (rtcp_debug_test_addr(&addr)) {
 			ast_verbose("\n\nGot RTCP from %s\n",
 				    ast_sockaddr_stringify(&addr));
-			ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
-							(pt == RTCP_PT_RR) ? "Receiver Report" :
-							(pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
+			ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
 			ast_verbose("Reception reports: %d\n", rc);
-			ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc);
+			ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
 		}
 
 		i += 2; /* Advance past header and ssrc */
+		if (rc == 0 && pt == RTCP_PT_RR) {      /* We're receiving a receiver report with no reports, which is ok */
+			position += (length + 1);
+			continue;
+		}
+
 		switch (pt) {
 		case RTCP_PT_SR:
-			gettimeofday(&rtp->rtcp->rxlsr, NULL);
-			rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16);
-			rtp->rtcp->spc = ntohl(rtcpheader[i + 3]);
+			gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
+			rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
 			rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
+			rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
 
-			rtcp_report->type = RTCP_PT_SR;
-			rtcp_report->sender_information.packet_count = rtp->rtcp->spc;
-			rtcp_report->sender_information.octet_count = rtp->rtcp->soc;
-			ntp2timeval((unsigned int)ntohl(rtcpheader[i]),
-					(unsigned int)ntohl(rtcpheader[i + 1]),
-					&rtcp_report->sender_information.ntp_timestamp);
-			rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
 			if (rtcp_debug_test_addr(&addr)) {
-				ast_verbose("NTP timestamp: %u.%010u\n",
-						(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
-						(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
-				ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp);
-				ast_verbose("SPC: %u\tSOC: %u\n",
-						rtcp_report->sender_information.packet_count,
-						rtcp_report->sender_information.octet_count);
+				ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
+				ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
+				ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
 			}
 			i += 5;
+			if (rc < 1)
+				break;
 			/* Intentional fall through */
 		case RTCP_PT_RR:
-			if (rtcp_report->type != RTCP_PT_SR) {
-				rtcp_report->type = RTCP_PT_RR;
-			}
-
-			if (rc > 0) {
-				/* Don't handle multiple reception reports (rc > 1) yet */
-				report_block = ast_calloc(1, sizeof(*report_block));
-				if (!report_block) {
-					return &ast_null_frame;
+			/* Don't handle multiple reception reports (rc > 1) yet */
+			/* Calculate RTT per RFC */
+			gettimeofday(&now, NULL);
+			timeval2ntp(now, &msw, &lsw);
+			if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
+				comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
+				lsr = ntohl(rtcpheader[i + 4]);
+				dlsr = ntohl(rtcpheader[i + 5]);
+				rtt = comp - lsr - dlsr;
+
+				/* Convert end to end delay to usec (keeping the calculation in 64bit space)
+				   sess->ee_delay = (eedelay * 1000) / 65536; */
+				if (rtt < 4294) {
+					rtt = (rtt * 1000000) >> 16;
+				} else {
+					rtt = (rtt * 1000) >> 16;
+					rtt *= 1000;
 				}
-				rtcp_report->report_block[report_counter] = report_block;
-				report_block->source_ssrc = ntohl(rtcpheader[i]);
-				report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff;
-				report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24);
-				report_block->highest_seq_no = ntohl(rtcpheader[i + 2]);
-				report_block->ia_jitter =  ntohl(rtcpheader[i + 3]);
-				report_block->lsr = ntohl(rtcpheader[i + 4]);
-				report_block->dlsr = ntohl(rtcpheader[i + 5]);
-				if (report_block->lsr
-					&& update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
-					&& rtcp_debug_test_addr(&addr)) {
-					struct timeval now;
-					unsigned int lsr_now, lsw, msw;
-					gettimeofday(&now, NULL);
-					timeval2ntp(now, &msw, &lsw);
-					lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));
+				rtt = rtt / 1000.;
+				rttsec = rtt / 1000.;
+				rtp->rtcp->rtt = rttsec;
+
+				if (comp - dlsr >= lsr) {
+					rtp->rtcp->accumulated_transit += rttsec;
+
+					if (rtp->rtcp->rtt_count == 0)
+						rtp->rtcp->minrtt = rttsec;
+
+					if (rtp->rtcp->maxrtt<rttsec)
+						rtp->rtcp->maxrtt = rttsec;
+					if (rtp->rtcp->minrtt>rttsec)
+						rtp->rtcp->minrtt = rttsec;
+
+					normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
+
+					rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
+
+					rtp->rtcp->normdevrtt = normdevrtt_current;
+
+					rtp->rtcp->rtt_count++;
+				} else if (rtcp_debug_test_addr(&addr)) {
 					ast_verbose("Internal RTCP NTP clock skew detected: "
 							   "lsr=%u, now=%u, dlsr=%u (%u:%03ums), "
-							"diff=%u\n",
-							report_block->lsr, lsr_now, report_block->dlsr, report_block->dlsr / 65536,
-							(report_block->dlsr % 65536) * 1000 / 65536,
-							report_block->dlsr - (lsr_now - report_block->lsr));
-				}
-				update_jitter_stats(rtp, report_block->ia_jitter);
-				update_lost_stats(rtp, report_block->lost_count.packets);
-				rtp->rtcp->reported_jitter_count++;
-
-				if (rtcp_debug_test_addr(&addr)) {
-					ast_verbose("  Fraction lost: %d\n", report_block->lost_count.fraction);
-					ast_verbose("  Packets lost so far: %u\n", report_block->lost_count.packets);
-					ast_verbose("  Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
-					ast_verbose("  Sequence number cycles: %u\n", report_block->highest_seq_no >> 16);
-					ast_verbose("  Interarrival jitter: %u\n", report_block->ia_jitter);
-					ast_verbose("  Last SR(our NTP): %lu.%010lu\n",(unsigned long)(report_block->lsr) >> 16,((unsigned long)(report_block->lsr) << 16) * 4096);
-					ast_verbose("  DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);
-					ast_verbose("  RTT: %4.4f(sec)\n", rtp->rtcp->rtt);
+						    "diff=%u\n",
+						    lsr, comp, dlsr, dlsr / 65536,
+						    (dlsr % 65536) * 1000 / 65536,
+						    dlsr - (comp - lsr));
 				}
-				report_counter++;
-			}
-			/* If and when we handle more than one report block, this should occur outside
-			 * this loop.
-			 */
-			if (!ast_find_ourip(&real_local_address, &local_address, 0)) {
-				str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address));
-			} else {
-				str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address));
 			}
 
-			if (!ast_find_ourip(&real_remote_address, &addr, 0)) {
-				str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address));
+			rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
+			reported_jitter = (double) rtp->rtcp->reported_jitter;
+
+			if (rtp->rtcp->reported_jitter_count == 0)
+				rtp->rtcp->reported_minjitter = reported_jitter;
+
+			if (reported_jitter < rtp->rtcp->reported_minjitter)
+				rtp->rtcp->reported_minjitter = reported_jitter;
+
+			if (reported_jitter > rtp->rtcp->reported_maxjitter)
+				rtp->rtcp->reported_maxjitter = reported_jitter;
+
+			reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
+
+			rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
+
+			reported_lost = (double) rtp->rtcp->reported_lost;
+
+			/* using same counter as for jitter */
+			if (rtp->rtcp->reported_jitter_count == 0)
+				rtp->rtcp->reported_minlost = reported_lost;
+
+			if (reported_lost < rtp->rtcp->reported_minlost)
+				rtp->rtcp->reported_minlost = reported_lost;
+
+			if (reported_lost > rtp->rtcp->reported_maxlost)
+				rtp->rtcp->reported_maxlost = reported_lost;
+			reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
+
+			rtp->rtcp->reported_jitter_count++;
+
+			if (rtcp_debug_test_addr(&addr)) {
+				ast_verbose("  Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
+				ast_verbose("  Packets lost so far: %u\n", rtp->rtcp->reported_lost);
+				ast_verbose("  Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
+				ast_verbose("  Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2])) >> 16);
+				ast_verbose("  Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
+				ast_verbose("  Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
+				ast_verbose("  DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
+				if (rtt)
+					ast_verbose("  RTT: %lu(sec)\n", (unsigned long) rtt);
+			}
+			if (rtt) {
+				manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
+								    "PT: %d(%s)\r\n"
+								    "ReceptionReports: %d\r\n"
+								    "SenderSSRC: %u\r\n"
+								    "FractionLost: %ld\r\n"
+								    "PacketsLost: %u\r\n"
+								    "HighestSequence: %ld\r\n"
+								    "SequenceNumberCycles: %ld\r\n"
+								    "IAJitter: %u\r\n"
+								    "LastSR: %lu.%010lu\r\n"
+								    "DLSR: %4.4f(sec)\r\n"
+					      "RTT: %llu(sec)\r\n",
+					      ast_sockaddr_stringify(&addr),
+					      pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
+					      rc,
+					      rtcpheader[i + 1],
+					      (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
+					      rtp->rtcp->reported_lost,
+					      (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
+					      (long) (ntohl(rtcpheader[i + 2])) >> 16,
+					      rtp->rtcp->reported_jitter,
+					      (unsigned long) ntohl(rtcpheader[i + 4]) >> 16, ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
+					      ntohl(rtcpheader[i + 5])/65536.0,
+					      (unsigned long long)rtt);
 			} else {
-				str_remote_address = ast_strdupa(ast_sockaddr_stringify(&addr));
+				manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
+								    "PT: %d(%s)\r\n"
+								    "ReceptionReports: %d\r\n"
+								    "SenderSSRC: %u\r\n"
+								    "FractionLost: %ld\r\n"
+								    "PacketsLost: %u\r\n"
+								    "HighestSequence: %ld\r\n"
+								    "SequenceNumberCycles: %ld\r\n"
+								    "IAJitter: %u\r\n"
+								    "LastSR: %lu.%010lu\r\n"
+					      "DLSR: %4.4f(sec)\r\n",
+					      ast_sockaddr_stringify(&addr),
+					      pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
+					      rc,
+					      rtcpheader[i + 1],
+					      (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
+					      rtp->rtcp->reported_lost,
+					      (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
+					      (long) (ntohl(rtcpheader[i + 2])) >> 16,
+					      rtp->rtcp->reported_jitter,
+					      (unsigned long) ntohl(rtcpheader[i + 4]) >> 16,
+					      ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
+					      ntohl(rtcpheader[i + 5])/65536.0);
 			}
-
-			message_blob = ast_json_pack("{s: s, s: s, s: f}",
-					"from", str_remote_address,
-					"to", str_local_address,
-					"rtt", rtp->rtcp->rtt);
-			ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),
-					rtcp_report,
-					message_blob);
-			ast_json_unref(message_blob);
 			break;
 		case RTCP_PT_FUR:
-		/* Handle RTCP FIR as FUR */
-		case RTCP_PT_PSFB:
-			if (rtcp_debug_test_addr(&addr)) {
+			if (rtcp_debug_test_addr(&addr))
 				ast_verbose("Received an RTCP Fast Update Request\n");
-			}
 			rtp->f.frametype = AST_FRAME_CONTROL;
 			rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
 			rtp->f.datalen = 0;
@@ -4106,16 +4074,14 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 			f = &rtp->f;
 			break;
 		case RTCP_PT_SDES:
-			if (rtcp_debug_test_addr(&addr)) {
+			if (rtcp_debug_test_addr(&addr))
 				ast_verbose("Received an SDES from %s\n",
 					    ast_sockaddr_stringify(&rtp->rtcp->them));
-			}
 			break;
 		case RTCP_PT_BYE:
-			if (rtcp_debug_test_addr(&addr)) {
+			if (rtcp_debug_test_addr(&addr))
 				ast_verbose("Received a BYE from %s\n",
 					    ast_sockaddr_stringify(&rtp->rtcp->them));
-			}
 			break;
 		default:
 			ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n",
@@ -4124,6 +4090,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 		}
 		position += (length + 1);
 	}
+
 	rtp->rtcp->rtcp_info = 1;
 
 	return f;
@@ -4134,7 +4101,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
 	struct ast_rtp_instance *instance1 = ast_rtp_instance_get_bridged(instance);
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance), *bridged = ast_rtp_instance_get_data(instance1);
 	int res = 0, payload = 0, bridged_payload = 0, mark;
-	RAII_VAR(struct ast_rtp_payload_type *, payload_type, NULL, ao2_cleanup);
+	struct ast_rtp_payload_type payload_type;
 	int reconstruct = ntohl(rtpheader[0]);
 	struct ast_sockaddr remote_address = { {0,} };
 	int ice;
@@ -4144,13 +4111,10 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
 	mark = (((reconstruct & 0x800000) >> 23) != 0);
 
 	/* Check what the payload value should be */
-	payload_type = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payload);
-	if (!payload_type) {
-		return -1;
-	}
+	payload_type = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payload);
 
 	/* Otherwise adjust bridged payload to match */
-	bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type->asterisk_format, payload_type->format, payload_type->rtp_code);
+	bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type.asterisk_format, &payload_type.format, payload_type.rtp_code);
 
 	/* If no codec could be matched between instance and instance1, then somehow things were made incompatible while we were still bridged.  Bail. */
 	if (bridged_payload < 0) {
@@ -4178,7 +4142,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
 	ast_rtp_instance_get_remote_address(instance1, &remote_address);
 
 	if (ast_sockaddr_isnull(&remote_address)) {
-		ast_debug(1, "Remote address is null, most likely RTP has been stopped\n");
+		ast_debug(5, "Remote address is null, most likely RTP has been stopped\n");
 		return 0;
 	}
 
@@ -4191,13 +4155,12 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
 				ast_sockaddr_stringify(&remote_address),
 				strerror(errno));
 		} else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
-			if (option_debug || rtpdebug) {
+			if (option_debug || rtpdebug)
 				ast_log(LOG_WARNING,
 					"RTP NAT: Can't write RTP to private "
 					"address %s, waiting for other end to "
 					"send audio...\n",
 					ast_sockaddr_stringify(&remote_address));
-			}
 			ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
 		}
 		return 0;
@@ -4219,7 +4182,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 	struct ast_sockaddr addr;
 	int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
 	unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
-	RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);
+	struct ast_rtp_payload_type payload;
 	struct ast_sockaddr remote_address = { {0,} };
 	struct frame_list frames;
 
@@ -4256,14 +4219,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 
 	/* Make sure the data that was read in is actually enough to make up an RTP packet */
 	if (res < hdrlen) {
-		/* If this is a keepalive containing only nulls, don't bother with a warning */
-		int i;
-		for (i = 0; i < res; ++i) {
-			if (rtp->rawdata[AST_FRIENDLY_OFFSET + i] != '\0') {
-				ast_log(LOG_WARNING, "RTP Read too short\n");
-				return &ast_null_frame;
-			}
-		}
+		ast_log(LOG_WARNING, "RTP Read too short\n");
 		return &ast_null_frame;
 	}
 
@@ -4315,17 +4271,24 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 			/* Always reset the alternate learning source */
 			rtp_learning_seq_init(&rtp->alt_source_learn, seqno);
 		} else {
-			/* Start trying to learn from the new address. If we pass a probationary period with
-			 * it, that means we've stopped getting RTP from the original source and we should
-			 * switch to it.
-			 */
-			if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) {
-				ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
-						rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets);
-				return &ast_null_frame;
+			/* Hmm, not the strict address. Perhaps we're getting audio from the alternate? */
+			if (!ast_sockaddr_cmp(&rtp->alt_rtp_address, &addr)) {
+				/* ooh, we did! You're now the new expected address, son! */
+				ast_sockaddr_copy(&rtp->strict_rtp_address,
+						  &addr);
+			} else {
+				/* Start trying to learn from the new address. If we pass a probationary period with
+				 * it, that means we've stopped getting RTP from the original source and we should
+				 * switch to it.
+				 */
+				if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) {
+					ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
+							rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets);
+					return &ast_null_frame;
+				}
+				ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
+				ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
 			}
-			ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
-			ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
 		}
 	}
 
@@ -4434,7 +4397,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 	}
 
 	/* Do not schedule RR if RTCP isn't run */
-	if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 1) {
+	if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 0) {
 		/* Schedule transmission of Receiver Report */
 		ao2_ref(instance, +1);
 		rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
@@ -4459,20 +4422,20 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 			    payloadtype, seqno, timestamp,res - hdrlen);
 	}
 
-	payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype);
+	payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payloadtype);
 
 	/* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
-	if (!payload->asterisk_format) {
+	if (!payload.asterisk_format) {
 		struct ast_frame *f = NULL;
-		if (payload->rtp_code == AST_RTP_DTMF) {
+		if (payload.rtp_code == AST_RTP_DTMF) {
 			/* process_dtmf_rfc2833 may need to return multiple frames. We do this
 			 * by passing the pointer to the frame list to it so that the method
 			 * can append frames to the list as needed.
 			 */
 			process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);
-		} else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {
+		} else if (payload.rtp_code == AST_RTP_CISCO_DTMF) {
 			f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
-		} else if (payload->rtp_code == AST_RTP_CN) {
+		} else if (payload.rtp_code == AST_RTP_CN) {
 			f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
 		} else {
 			ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
@@ -4492,25 +4455,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		return &ast_null_frame;
 	}
 
-	ao2_replace(rtp->lastrxformat, payload->format);
-	ao2_replace(rtp->f.subclass.format, payload->format);
-	switch (ast_format_get_type(rtp->f.subclass.format)) {
-	case AST_MEDIA_TYPE_AUDIO:
-		rtp->f.frametype = AST_FRAME_VOICE;
-		break;
-	case AST_MEDIA_TYPE_VIDEO:
-		rtp->f.frametype = AST_FRAME_VIDEO;
-		break;
-	case AST_MEDIA_TYPE_TEXT:
-		rtp->f.frametype = AST_FRAME_TEXT;
-		break;
-	case AST_MEDIA_TYPE_IMAGE:
-		/* Fall through */
-	default:
-		ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
-			ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
-		return &ast_null_frame;
-	}
+	ast_format_copy(&rtp->lastrxformat, &payload.format);
+	ast_format_copy(&rtp->f.subclass.format, &payload.format);
+	rtp->f.frametype = (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_AUDIO) ? AST_FRAME_VOICE : (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_VIDEO) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
+
 	rtp->rxseqno = seqno;
 
 	if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
@@ -4519,7 +4467,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		if (rtp->resp) {
 			struct ast_frame *f;
 			f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);
-			f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));
+			f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0));
 			rtp->resp = 0;
 			rtp->dtmf_timeout = rtp->dtmf_duration = 0;
 			AST_LIST_INSERT_TAIL(&frames, f, frame_list);
@@ -4536,9 +4484,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 	rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
 	rtp->f.seqno = seqno;
 
-	if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL)
-		&& ((int)seqno - (prev_seqno + 1) > 0)
-		&& ((int)seqno - (prev_seqno + 1) < 10)) {
+	if (rtp->f.subclass.format.id == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
 		unsigned char *data = rtp->f.data.ptr;
 
 		memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
@@ -4548,7 +4494,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		*data = 0xBD;
 	}
 
-	if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
+	if (rtp->f.subclass.format.id == AST_FORMAT_T140RED) {
 		unsigned char *data = rtp->f.data.ptr;
 		unsigned char *header_end;
 		int num_generations;
@@ -4557,7 +4503,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
 		int x;
 
-		ao2_replace(rtp->f.subclass.format, ast_format_t140);
+		ast_format_set(&rtp->f.subclass.format, AST_FORMAT_T140, 0);
 		header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
 		if (header_end == NULL) {
 			return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
@@ -4595,17 +4541,17 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		}
 	}
 
-	if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) {
-		rtp->f.samples = ast_codec_samples_count(&rtp->f);
-		if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {
+	if (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_AUDIO) {
+		rtp->f.samples = ast_codec_get_samples(&rtp->f);
+		if (ast_format_is_slinear(&rtp->f.subclass.format)) {
 			ast_frame_byteswap_be(&rtp->f);
 		}
 		calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
 		/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
 		ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
-		rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);
-		rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000));
-	} else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) {
+		rtp->f.ts = timestamp / (rtp_get_rate(&rtp->f.subclass.format) / 1000);
+		rtp->f.len = rtp->f.samples / ((ast_format_rate(&rtp->f.subclass.format) / 1000));
+	} else if (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_VIDEO) {
 		/* Video -- samples is # of samples vs. 90000 */
 		if (!rtp->lastividtimestamp)
 			rtp->lastividtimestamp = timestamp;
@@ -4614,8 +4560,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		rtp->f.delivery.tv_sec = 0;
 		rtp->f.delivery.tv_usec = 0;
 		/* Pass the RTP marker bit as bit */
-		rtp->f.subclass.frame_ending = mark;
-	} else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) {
+		if (mark) {
+			ast_format_set_video_mark(&rtp->f.subclass.format);
+		}
+	} else {
 		/* TEXT -- samples is # of samples vs. 1000 */
 		if (!rtp->lastitexttimestamp)
 			rtp->lastitexttimestamp = timestamp;
@@ -4623,10 +4571,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 		rtp->lastitexttimestamp = timestamp;
 		rtp->f.delivery.tv_sec = 0;
 		rtp->f.delivery.tv_usec = 0;
-	} else {
-		ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
-			ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
-		return &ast_null_frame;;
 	}
 
 	AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);
@@ -4677,13 +4621,14 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
 			ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
 			rtp->rtcp->schedid = -1;
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 			if (rtp->ice) {
 				rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP);
 			}
 #endif
 
 #ifdef HAVE_OPENSSL_SRTP
+			rtp->rtcp->dtls.timeout_timer = -1;
 			dtls_setup_rtcp(instance);
 #endif
 
@@ -4747,6 +4692,18 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
 	return;
 }
 
+static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr)
+{
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+	/* No need to futz with rtp->rtcp here because ast_rtcp_read is already able to adjust if receiving
+	 * RTCP from an "unexpected" source
+	 */
+	ast_sockaddr_copy(&rtp->alt_rtp_address, addr);
+
+	return;
+}
+
 /*! \brief Write t140 redundacy frame
  * \param data primary data to be buffered
  */
@@ -4770,7 +4727,7 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int
 	}
 
 	rtp->red->t140.frametype = AST_FRAME_TEXT;
-	ao2_replace(rtp->red->t140.subclass.format, ast_format_t140_red);
+	ast_format_set(&rtp->red->t140.subclass.format, AST_FORMAT_T140RED, 0);
 	rtp->red->t140.data.ptr = &rtp->red->buf_data;
 
 	rtp->red->t140.ts = 0;
@@ -4862,7 +4819,6 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
 
 	AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);
 	AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);
-	AST_RTP_STAT_STRCPY(AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, -1, stats->channel_uniqueid, ast_rtp_instance_get_channel_id(instance));
 
 	return 0;
 }
@@ -4900,9 +4856,11 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
 
 #ifdef HAVE_OPENSSL_SRTP
 	AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1));
-	ast_mutex_lock(&rtp->dtls_timer_lock);
-	AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1));
-	ast_mutex_unlock(&rtp->dtls_timer_lock);
+
+	dtls_srtp_stop_timeout_timer(instance, rtp, 0);
+	if (rtp->rtcp) {
+		dtls_srtp_stop_timeout_timer(instance, rtp, 1);
+	}
 #endif
 
 	if (rtp->rtcp && rtp->rtcp->schedid > 0) {
@@ -4954,14 +4912,14 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level)
 	payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_CN);
 
 	level = 127 - (level & 0x7f);
-
+	
 	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
 
 	/* Get a pointer to the header */
 	rtpheader = (unsigned int *)data;
 	rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
 	rtpheader[1] = htonl(rtp->lastts);
-	rtpheader[2] = htonl(rtp->ssrc);
+	rtpheader[2] = htonl(rtp->ssrc); 
 	data[12] = level;
 
 	res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 1, 0, &remote_address, &ice);
@@ -4984,10 +4942,31 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level)
 }
 
 #ifdef HAVE_OPENSSL_SRTP
+static void dtls_perform_setup(struct dtls_details *dtls)
+{
+	if (!dtls->ssl || !SSL_is_init_finished(dtls->ssl)) {
+		return;
+	}
+
+	SSL_clear(dtls->ssl);
+	if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
+		SSL_set_accept_state(dtls->ssl);
+	} else {
+		SSL_set_connect_state(dtls->ssl);
+	}
+	dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
+}
+
 static int ast_rtp_activate(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	dtls_perform_setup(&rtp->dtls);
+
+	if (rtp->rtcp) {
+		dtls_perform_setup(&rtp->rtcp->dtls);
+	}
+
 	/* If ICE negotiation is enabled the DTLS Handshake will be performed upon completion of it */
 #ifdef USE_PJPROJECT
 	if (rtp->ice) {
@@ -5163,10 +5142,10 @@ static int rtp_reload(int reload)
 	 * the pool this will cause a small memory leak.
 	 */
 
-#ifdef HAVE_PJPROJECT
 	icesupport = DEFAULT_ICESUPPORT;
-	turnport = DEFAULT_TURN_PORT;
 	memset(&stunaddr, 0, sizeof(stunaddr));
+#ifdef USE_PJPROJECT
+	turnport = DEFAULT_TURN_PORT;
 	turnaddr = pj_str(NULL);
 	turnusername = pj_str(NULL);
 	turnpassword = pj_str(NULL);
@@ -5221,7 +5200,6 @@ static int rtp_reload(int reload)
 					DEFAULT_LEARNING_MIN_SEQUENTIAL);
 			}
 		}
-#ifdef HAVE_PJPROJECT
 		if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) {
 			icesupport = ast_true(s);
 		}
@@ -5231,6 +5209,7 @@ static int rtp_reload(int reload)
 				ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", s);
 			}
 		}
+#ifdef USE_PJPROJECT
 		if ((s = ast_variable_retrieve(cfg, "general", "turnaddr"))) {
 			struct sockaddr_in addr;
 			addr.sin_port = htons(DEFAULT_TURN_PORT);
@@ -5267,7 +5246,7 @@ static int reload_module(void)
 	return 0;
 }
 
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 static void rtp_terminate_pjproject(void)
 {
 	pj_thread_register_check();
@@ -5285,9 +5264,11 @@ static void rtp_terminate_pjproject(void)
 
 static int load_module(void)
 {
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 	pj_lock_t *lock;
 
+	pj_log_set_level(0);
+
 	if (pj_init() != PJ_SUCCESS) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
@@ -5304,7 +5285,7 @@ static int load_module(void)
 
 	pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
 
-	pool = pj_pool_create(&cachingpool.factory, "timer", 512, 512, NULL);
+	pool = pj_pool_create(&cachingpool.factory, "rtp", 512, 512, NULL);
 
 	if (pj_timer_heap_create(pool, 100, &timer_heap) != PJ_SUCCESS) {
 		rtp_terminate_pjproject();
@@ -5318,23 +5299,21 @@ static int load_module(void)
 
 	pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE);
 
-	if (pj_thread_create(pool, "timer", &timer_worker_thread, NULL, 0, 0, &timer_thread) != PJ_SUCCESS) {
+	if (pj_thread_create(pool, "ice", &timer_worker_thread, NULL, 0, 0, &timer_thread) != PJ_SUCCESS) {
 		rtp_terminate_pjproject();
 		return AST_MODULE_LOAD_DECLINE;
 	}
-
 #endif
 
 	if (ast_rtp_engine_register(&asterisk_rtp_engine)) {
-#ifdef HAVE_PJPROJECT
+#ifdef USE_PJPROJECT
 		rtp_terminate_pjproject();
 #endif
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
 	if (ast_cli_register_multiple(cli_rtp, ARRAY_LEN(cli_rtp))) {
-#ifdef HAVE_PJPROJECT
-		ast_rtp_engine_unregister(&asterisk_rtp_engine);
+#ifdef USE_PJPROJECT
 		rtp_terminate_pjproject();
 #endif
 		return AST_MODULE_LOAD_DECLINE;
@@ -5350,8 +5329,7 @@ static int unload_module(void)
 	ast_rtp_engine_unregister(&asterisk_rtp_engine);
 	ast_cli_unregister_multiple(cli_rtp, ARRAY_LEN(cli_rtp));
 
-#ifdef HAVE_PJPROJECT
-	pj_thread_register_check();
+#ifdef USE_PJPROJECT
 	rtp_terminate_pjproject();
 #endif
 
@@ -5359,7 +5337,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk RTP Stack",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload_module,
diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c
index e71f51a..c13e9ad 100644
--- a/res/res_rtp_multicast.c
+++ b/res/res_rtp_multicast.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/time.h>
 #include <signal.h>
@@ -53,7 +53,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #include "asterisk/unaligned.h"
 #include "asterisk/module.h"
 #include "asterisk/rtp_engine.h"
-#include "asterisk/format_cache.h"
 
 /*! Command value used for Linksys paging to indicate we are starting */
 #define LINKSYS_MCAST_STARTCMD 6
@@ -145,8 +144,7 @@ static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched
 
 static int rtp_get_rate(struct ast_format *format)
 {
-	return ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL ?
-		8000 : ast_format_get_sample_rate(format);
+        return (format->id == AST_FORMAT_G722) ? 8000 : ast_format_rate(format);
 }
 
 static unsigned int calc_txstamp(struct multicast_rtp *rtp, struct timeval *delivery)
@@ -239,7 +237,7 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra
 	int hdrlen = 12, res = 0, codec;
 	unsigned char *rtpheader;
 	unsigned int ms = calc_txstamp(multicast, &frame->delivery);
-	int rate = rtp_get_rate(frame->subclass.format) / 1000;
+	int rate = rtp_get_rate(&frame->subclass.format) / 1000;
 
 	/* We only accept audio, nothing else */
 	if (frame->frametype != AST_FRAME_VOICE) {
@@ -247,7 +245,7 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra
 	}
 
 	/* Grab the actual payload number for when we create the RTP packet */
-	if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, frame->subclass.format, 0)) < 0) {
+	if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, &frame->subclass.format, 0)) < 0) {
 		return -1;
 	}
 
@@ -315,7 +313,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Engine",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_security_log.c b/res/res_security_log.c
index 00e710b..bea4609 100644
--- a/res/res_security_log.c
+++ b/res/res_security_log.c
@@ -33,21 +33,20 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 400186 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/module.h"
 #include "asterisk/logger.h"
+#include "asterisk/event.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/strings.h"
 #include "asterisk/security_events.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
 
 static const char LOG_SECURITY_NAME[] = "SECURITY";
 
 static int LOG_SECURITY;
 
-static struct stasis_subscription *security_stasis_sub;
+static struct ast_event_sub *security_event_sub;
 
 AST_THREADSTORAGE(security_event_buf);
 static const size_t SECURITY_EVENT_BUF_INIT_LEN = 256;
@@ -57,88 +56,93 @@ enum ie_required {
 	REQUIRED
 };
 
-static void append_json_single(struct ast_str **str, struct ast_json *json,
-		const enum ast_event_ie_type ie_type, enum ie_required required)
+static int ie_is_present(const struct ast_event *event,
+		const enum ast_event_ie_type ie_type)
 {
-	const char *ie_type_key = ast_event_get_ie_type_name(ie_type);
-
-	struct ast_json *json_string;
-
-	json_string = ast_json_object_get(json, ie_type_key);
+	return (ast_event_get_ie_raw(event, ie_type) != NULL);
+}
 
-	if (!required && !json_string) {
-		/* Optional IE isn't present. Ignore. */
+static void append_ie(struct ast_str **str, const struct ast_event *event,
+		const enum ast_event_ie_type ie_type, enum ie_required required)
+{
+	if (!required && !ie_is_present(event, ie_type)) {
+		/* Optional IE isn't present.  Ignore. */
 		return;
 	}
 
 	/* At this point, it _better_ be there! */
-	ast_assert(json_string != NULL);
-
-	ast_str_append(str, 0, ",%s=\"%s\"",
-			ie_type_key,
-			ast_json_string_get(json_string));
+	ast_assert(ie_is_present(event, ie_type));
+
+	switch (ast_event_get_ie_pltype(ie_type)) {
+	case AST_EVENT_IE_PLTYPE_UINT:
+		ast_str_append(str, 0, ",%s=\"%u\"",
+				ast_event_get_ie_type_name(ie_type),
+				ast_event_get_ie_uint(event, ie_type));
+		break;
+	case AST_EVENT_IE_PLTYPE_STR:
+		ast_str_append(str, 0, ",%s=\"%s\"",
+				ast_event_get_ie_type_name(ie_type),
+				ast_event_get_ie_str(event, ie_type));
+		break;
+	case AST_EVENT_IE_PLTYPE_BITFLAGS:
+		ast_str_append(str, 0, ",%s=\"%u\"",
+				ast_event_get_ie_type_name(ie_type),
+				ast_event_get_ie_bitflags(event, ie_type));
+		break;
+	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+	case AST_EVENT_IE_PLTYPE_EXISTS:
+	case AST_EVENT_IE_PLTYPE_RAW:
+		ast_log(LOG_WARNING, "Unexpected payload type for IE '%s'\n",
+				ast_event_get_ie_type_name(ie_type));
+		break;
+	}
 }
 
-static void append_json(struct ast_str **str, struct ast_json *json,
+static void append_ies(struct ast_str **str, const struct ast_event *event,
 		const struct ast_security_event_ie_type *ies, enum ie_required required)
 {
 	unsigned int i;
 
 	for (i = 0; ies[i].ie_type != AST_EVENT_IE_END; i++) {
-		append_json_single(str, json, ies[i].ie_type, required);
+		append_ie(str, event, ies[i].ie_type, required);
 	}
 }
 
-static void security_event_stasis_cb(struct ast_json *json)
+static void security_event_cb(const struct ast_event *event, void *data)
 {
 	struct ast_str *str;
-	struct ast_json *event_type_json;
 	enum ast_security_event_type event_type;
 
-	event_type_json = ast_json_object_get(json, "SecurityEvent");
-	event_type = ast_json_integer_get(event_type_json);
-
-	ast_assert(event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
-
 	if (!(str = ast_str_thread_get(&security_event_buf,
 			SECURITY_EVENT_BUF_INIT_LEN))) {
 		return;
 	}
 
-	ast_str_set(&str, 0, "SecurityEvent=\"%s\"",
+	/* Note that the event type is guaranteed to be valid here. */
+	event_type = ast_event_get_ie_uint(event, AST_EVENT_IE_SECURITY_EVENT);
+	ast_assert((unsigned int)event_type >= 0 && event_type < AST_SECURITY_EVENT_NUM_TYPES);
+
+	ast_str_set(&str, 0, "%s=\"%s\"",
+			ast_event_get_ie_type_name(AST_EVENT_IE_SECURITY_EVENT),
 			ast_security_event_get_name(event_type));
 
-	append_json(&str, json,
+	append_ies(&str, event,
 			ast_security_event_get_required_ies(event_type), REQUIRED);
-	append_json(&str, json,
+	append_ies(&str, event,
 			ast_security_event_get_optional_ies(event_type), NOT_REQUIRED);
 
 	ast_log_dynamic_level(LOG_SECURITY, "%s\n", ast_str_buffer(str));
 }
 
-static void security_stasis_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct ast_json_payload *payload = stasis_message_data(message);
-
-	if (stasis_message_type(message) != ast_security_event_type()) {
-		return;
-	}
-
-	if (!payload) {
-		return;
-	}
-
-	security_event_stasis_cb(payload->json);
-}
-
 static int load_module(void)
 {
 	if ((LOG_SECURITY = ast_logger_register_level(LOG_SECURITY_NAME)) == -1) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	if (!(security_stasis_sub = stasis_subscribe(ast_security_topic(), security_stasis_cb, NULL))) {
+	if (!(security_event_sub = ast_event_subscribe(AST_EVENT_SECURITY,
+			security_event_cb, "Security Event Logger",
+			NULL, AST_EVENT_IE_END))) {
 		ast_logger_unregister_level(LOG_SECURITY_NAME);
 		LOG_SECURITY = -1;
 		return AST_MODULE_LOAD_DECLINE;
@@ -151,8 +155,8 @@ static int load_module(void)
 
 static int unload_module(void)
 {
-	if (security_stasis_sub) {
-		security_stasis_sub = stasis_unsubscribe(security_stasis_sub);
+	if (security_event_sub) {
+		security_event_sub = ast_event_unsubscribe(security_event_sub);
 	}
 
 	ast_logger_unregister_level(LOG_SECURITY_NAME);
diff --git a/res/res_smdi.c b/res/res_smdi.c
index 0775aaa..cc49b98 100644
--- a/res/res_smdi.c
+++ b/res/res_smdi.c
@@ -1,5 +1,5 @@
 /*
- * Asterisk -- An open source telephony toolkit.
+ * Asterisk -- A telephony toolkit for Linux.
  *
  * Copyright (C) 2005-2008, Digium, Inc.
  *
@@ -24,29 +24,20 @@
  * \author Russell Bryant <russell at digium.com>
  *
  * Here is a useful mailing list post that describes SMDI protocol details:
- * http://lists.digium.com/pipermail/asterisk-dev/2003-June/000884.html
+ * \ref http://lists.digium.com/pipermail/asterisk-dev/2003-June/000884.html
  *
  * \todo This module currently has its own mailbox monitoring thread.  This should
  * be converted to MWI subscriptions and just let the optional global voicemail
  * polling thread handle it.
  */
 
-/*! \li \ref res_smdi.c uses the configuration file \ref smdi.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page smdi.conf smdi.conf
- * \verbinclude smdi.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <termios.h>
 #include <sys/time.h>
@@ -59,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 #define AST_API_MODULE
 #include "asterisk/smdi.h"
 #include "asterisk/config.h"
+#include "asterisk/astobj.h"
 #include "asterisk/io.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
@@ -166,12 +158,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
 static const char config_file[] = "smdi.conf";
 static int smdi_loaded;
 
+/*! \brief SMDI message desk message queue. */
+struct ast_smdi_md_queue {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_md_message);
+};
+
+/*! \brief SMDI message waiting indicator message queue. */
+struct ast_smdi_mwi_queue {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_mwi_message);
+};
+
 struct ast_smdi_interface {
-	char name[SMDI_MAX_FILENAME_LEN];
-	struct ao2_container *md_q;
+	ASTOBJ_COMPONENTS_FULL(struct ast_smdi_interface, SMDI_MAX_FILENAME_LEN, 1);
+	struct ast_smdi_md_queue md_q;
 	ast_mutex_t md_q_lock;
 	ast_cond_t md_q_cond;
-	struct ao2_container *mwi_q;
+	struct ast_smdi_mwi_queue mwi_q;
 	ast_mutex_t mwi_q_lock;
 	ast_cond_t mwi_q_cond;
 	FILE *file;
@@ -182,7 +184,10 @@ struct ast_smdi_interface {
 	long msg_expiry;
 };
 
-static AO2_GLOBAL_OBJ_STATIC(smdi_ifaces);
+/*! \brief SMDI interface container. */
+static struct ast_smdi_interface_container {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_interface);
+} smdi_ifaces;
 
 /*! \brief A mapping between an SMDI mailbox ID and an Asterisk mailbox */
 struct mailbox_mapping {
@@ -223,26 +228,26 @@ static struct {
 	.thread = AST_PTHREADT_NULL,
 };
 
-static void smdi_interface_destroy(void *obj)
+static void ast_smdi_interface_destroy(struct ast_smdi_interface *iface)
 {
-	struct ast_smdi_interface *iface = obj;
-
 	if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
 		pthread_cancel(iface->thread);
 		pthread_join(iface->thread, NULL);
 	}
-
+	
 	iface->thread = AST_PTHREADT_STOP;
-
-	if (iface->file) {
+	
+	if (iface->file) 
 		fclose(iface->file);
-	}
+	
+	ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
+	ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
+	ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
 
-	ao2_cleanup(iface->md_q);
 	ast_mutex_destroy(&iface->md_q_lock);
 	ast_cond_destroy(&iface->md_q_cond);
 
-	ao2_cleanup(iface->mwi_q);
 	ast_mutex_destroy(&iface->mwi_q_lock);
 	ast_cond_destroy(&iface->mwi_q_cond);
 
@@ -251,6 +256,11 @@ static void smdi_interface_destroy(void *obj)
 	ast_module_unref(ast_module_info->self);
 }
 
+void AST_OPTIONAL_API_NAME(ast_smdi_interface_unref)(struct ast_smdi_interface *iface)
+{
+	ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
+}
+
 /*! 
  * \internal
  * \brief Push an SMDI message to the back of an interface's message queue.
@@ -260,7 +270,7 @@ static void smdi_interface_destroy(void *obj)
 static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
 {
 	ast_mutex_lock(&iface->md_q_lock);
-	ao2_link(iface->md_q, md_msg);
+	ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
 	ast_cond_broadcast(&iface->md_q_cond);
 	ast_mutex_unlock(&iface->md_q_lock);
 }
@@ -274,7 +284,7 @@ static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct as
 static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
 {
 	ast_mutex_lock(&iface->mwi_q_lock);
-	ao2_link(iface->mwi_q, mwi_msg);
+	ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
 	ast_cond_broadcast(&iface->mwi_q_cond);
 	ast_mutex_unlock(&iface->mwi_q_lock);
 }
@@ -289,7 +299,7 @@ static int smdi_toggle_mwi(struct ast_smdi_interface *iface, const char *mailbox
 		return 1;
 	}
 
-	ao2_wrlock(iface);
+	ASTOBJ_WRLOCK(iface);
 
 	fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
 
@@ -300,7 +310,7 @@ static int smdi_toggle_mwi(struct ast_smdi_interface *iface, const char *mailbox
 
 	fclose(file);
 
-	ao2_unlock(iface);
+	ASTOBJ_UNLOCK(iface);
 	ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
 
 	return 0;
@@ -316,6 +326,22 @@ int AST_OPTIONAL_API_NAME(ast_smdi_mwi_unset)(struct ast_smdi_interface *iface,
 	return smdi_toggle_mwi(iface, mailbox, 0);
 }
 
+void AST_OPTIONAL_API_NAME(ast_smdi_md_message_putback)(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
+{
+	ast_mutex_lock(&iface->md_q_lock);
+	ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
+	ast_cond_broadcast(&iface->md_q_cond);
+	ast_mutex_unlock(&iface->md_q_lock);
+}
+
+void AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_putback)(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
+{
+	ast_mutex_lock(&iface->mwi_q_lock);
+	ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
+	ast_cond_broadcast(&iface->mwi_q_cond);
+	ast_mutex_unlock(&iface->mwi_q_lock);
+}
+
 enum smdi_message_type {
 	SMDI_MWI,
 	SMDI_MD,
@@ -349,11 +375,10 @@ static inline void *unlink_from_msg_q(struct ast_smdi_interface *iface, enum smd
 {
 	switch (type) {
 	case SMDI_MWI:
-		return ao2_callback(iface->mwi_q, OBJ_UNLINK, NULL, NULL);
+		return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
 	case SMDI_MD:
-		return ao2_callback(iface->md_q, OBJ_UNLINK, NULL, NULL);
+		return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
 	}
-
 	return NULL;
 }
 
@@ -372,6 +397,21 @@ static inline struct timeval msg_timestamp(void *msg, enum smdi_message_type typ
 	return ast_tv(0, 0);
 }
 
+static inline void unref_msg(void *msg, enum smdi_message_type type)
+{
+	struct ast_smdi_md_message *md_msg = msg;
+	struct ast_smdi_mwi_message *mwi_msg = msg;
+
+	switch (type) {
+	case SMDI_MWI:
+		ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
+		break;
+	case SMDI_MD:
+		ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
+		break;
+	}
+}
+
 static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_message_type type)
 {
 	struct timeval now = ast_tvnow();
@@ -388,7 +428,7 @@ static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_messa
 
 		if (elapsed > iface->msg_expiry) {
 			/* found an expired message */
-			ao2_ref(msg, -1);
+			unref_msg(msg, type);
 			ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue.  "
 				"Message was %ld milliseconds too old.\n",
 				iface->name, (type == SMDI_MD) ? "MD" : "MWI", 
@@ -407,7 +447,7 @@ static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_messa
 				ast_smdi_mwi_message_push(iface, msg);
 				break;
 			}
-			ao2_ref(msg, -1);
+			unref_msg(msg, type);
 			break;
 		}
 	}
@@ -441,33 +481,57 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface,
 	switch (type) {
 	case SMDI_MD:
 		if (ast_strlen_zero(search_key)) {
+			struct ast_smdi_md_message *md_msg = NULL;
+
 			/* No search key provided (the code from chan_dahdi does this).
 			 * Just pop the top message off of the queue. */
 
-			msg = ao2_callback(iface->md_q, 0, NULL, NULL);
+			ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+				md_msg = ASTOBJ_REF(iterator);
+			} while (0); );
+
+			msg = md_msg;
 		} else if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
+			struct ast_smdi_md_message *md_msg = NULL;
+
 			/* Searching by the message desk terminal */
-			struct ast_smdi_md_message md_msg = { .name = "" };
-			strncpy(md_msg.mesg_desk_term, search_key, SMDI_MESG_DESK_TERM_LEN);
-			msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
+
+			ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+				if (!strcasecmp(iterator->mesg_desk_term, search_key))
+					md_msg = ASTOBJ_REF(iterator);
+			} while (0); );
+
+			msg = md_msg;
 		} else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
+			struct ast_smdi_md_message *md_msg = NULL;
+
 			/* Searching by the message desk number */
-			struct ast_smdi_md_message md_msg = { .name = "" };
-			strncpy(md_msg.mesg_desk_num, search_key, SMDI_MESG_DESK_NUM_LEN);
-			msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
+
+			ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+				if (!strcasecmp(iterator->mesg_desk_num, search_key))
+					md_msg = ASTOBJ_REF(iterator);
+			} while (0); );
+
+			msg = md_msg;
 		} else {
 			/* Searching by the forwarding station */
-			msg = ao2_find(iface->md_q, search_key, OBJ_SEARCH_KEY);
+			msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key);
 		}
 		break;
 	case SMDI_MWI:
 		if (ast_strlen_zero(search_key)) {
+			struct ast_smdi_mwi_message *mwi_msg = NULL;
+
 			/* No search key provided (the code from chan_dahdi does this).
 			 * Just pop the top message off of the queue. */
 
-			msg = ao2_callback(iface->mwi_q, 0, NULL, NULL);
+			ASTOBJ_CONTAINER_TRAVERSE(&iface->mwi_q, !mwi_msg, do {
+				mwi_msg = ASTOBJ_REF(iterator);
+			} while (0); );
+
+			msg = mwi_msg;
 		} else {
-			msg = ao2_find(iface->mwi_q, search_key, OBJ_SEARCH_KEY);
+			msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key);
 		}
 		break;
 	}
@@ -562,16 +626,7 @@ struct ast_smdi_mwi_message * AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_wait_st
 
 struct ast_smdi_interface * AST_OPTIONAL_API_NAME(ast_smdi_interface_find)(const char *iface_name)
 {
-	struct ao2_container *c;
-	struct ast_smdi_interface *iface = NULL;
-
-	c = ao2_global_obj_ref(smdi_ifaces);
-	if (c) {
-		iface = ao2_find(c, iface_name, OBJ_SEARCH_KEY);
-		ao2_ref(c, -1);
-	}
-
-	return iface;
+	return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
 }
 
 /*! 
@@ -611,11 +666,11 @@ static void *smdi_read(void *iface_p)
 			ast_debug(1, "Read a 'D' ... it's an MD message.\n");
 
 			if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
-				ao2_ref(iface, -1);
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				return NULL;
 			}
 
-			md_msg = ao2_alloc(sizeof(*md_msg), NULL);
+			ASTOBJ_INIT(md_msg);
 
 			/* read the message desk number */
 			for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
@@ -666,7 +721,7 @@ static void *smdi_read(void *iface_p)
 
 			ast_debug(1, "The forwarding station is '%s'\n", md_msg->fwd_st);
 
-			/* Put the fwd_st in the name field so that we can use ao2_find to look
+			/* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
 			 * up a message on this field */
 			ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
 
@@ -705,7 +760,7 @@ static void *smdi_read(void *iface_p)
 			ast_smdi_md_message_push(iface, md_msg);
 			ast_debug(1, "Received SMDI MD message on %s\n", iface->name);
 
-			ao2_ref(md_msg, -1);
+			ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
 
 		} else if (c == 'W') { /* MWI message */
 			start = 0;
@@ -713,11 +768,11 @@ static void *smdi_read(void *iface_p)
 			ast_debug(1, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
 
 			if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
-				ao2_ref(iface, -1);
+				ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
 				return NULL;
 			}
 
-			mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL);
+			ASTOBJ_INIT(mwi_msg);
 
 			/* discard the 'I' (from 'MWI') */
 			fgetc(iface->file);
@@ -739,7 +794,7 @@ static void *smdi_read(void *iface_p)
 			mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
 			cp = NULL;
 
-			/* Put the fwd_st in the name field so that we can use ao2_find to look
+			/* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
 			 * up a message on this field */
 			ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
 
@@ -754,7 +809,7 @@ static void *smdi_read(void *iface_p)
 			ast_smdi_mwi_message_push(iface, mwi_msg);
 			ast_debug(1, "Received SMDI MWI message on %s\n", iface->name);
 
-			ao2_ref(mwi_msg, -1);
+			ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
 		} else {
 			ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c);
 			start = 0;
@@ -762,14 +817,24 @@ static void *smdi_read(void *iface_p)
 	}
 
 	ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
-	ao2_ref(iface, -1);
+	ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
 	return NULL;
 }
 
+void AST_OPTIONAL_API_NAME(ast_smdi_md_message_destroy)(struct ast_smdi_md_message *msg)
+{
+	ast_free(msg);
+}
+
+void AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_destroy)(struct ast_smdi_mwi_message *msg)
+{
+	ast_free(msg);
+}
+
 static void destroy_mailbox_mapping(struct mailbox_mapping *mm)
 {
 	ast_string_field_free_memory(mm);
-	ao2_ref(mm->iface, -1);
+	ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy);
 	free(mm);
 }
 
@@ -801,7 +866,7 @@ static void append_mailbox_mapping(struct ast_variable *var, struct ast_smdi_int
 	ast_string_field_set(mm, mailbox, mailbox);
 	ast_string_field_set(mm, context, context);
 
-	mm->iface = ao2_bump(iface);
+	mm->iface = ASTOBJ_REF(iface);
 
 	ast_mutex_lock(&mwi_monitor.lock);
 	AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
@@ -857,51 +922,16 @@ static void *mwi_monitor_handler(void *data)
 	return NULL;
 }
 
-static int smdi_mwi_q_cmp_fn(void *obj, void *data, int flags)
-{
-	struct ast_smdi_mwi_message *msg = obj;
-	char *str = data;
-	return !strcmp(msg->name, str) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static int smdi_md_q_cmp_fn(void *obj, void *arg, int flags)
-{
-	const struct ast_smdi_md_message *msg = obj;
-	const struct ast_smdi_md_message *search_msg = arg;
-	const char *search_key = arg;
-	int cmp = 0;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		if (search_msg->mesg_desk_num) {
-			cmp = strcmp(msg->mesg_desk_num, search_msg->mesg_desk_num);
-		}
-		if (search_msg->mesg_desk_term) {
-			cmp |= strcmp(msg->mesg_desk_term, search_msg->mesg_desk_term);
-		}
-		break;
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(msg->name, search_key);
-		break;
-	}
-
-	if (cmp) {
-		return 0;
-	}
-
-	return CMP_MATCH;
-}
-
 static struct ast_smdi_interface *alloc_smdi_interface(void)
 {
 	struct ast_smdi_interface *iface;
 
-	if (!(iface = ao2_alloc(sizeof(*iface), smdi_interface_destroy))) {
+	if (!(iface = ast_calloc(1, sizeof(*iface))))
 		return NULL;
-	}
 
-	iface->md_q = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, smdi_md_q_cmp_fn);
-	iface->mwi_q = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, smdi_mwi_q_cmp_fn);
+	ASTOBJ_INIT(iface);
+	ASTOBJ_CONTAINER_INIT(&iface->md_q);
+	ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
 
 	ast_mutex_init(&iface->md_q_lock);
 	ast_cond_init(&iface->md_q_cond, NULL);
@@ -912,14 +942,6 @@ static struct ast_smdi_interface *alloc_smdi_interface(void)
 	return iface;
 }
 
-static int smdi_ifaces_cmp_fn(void *obj, void *data, int flags)
-{
-	struct ast_smdi_interface *iface = obj;
-
-	char *str = data;
-	return !strcmp(iface->name, str) ? CMP_MATCH | CMP_STOP : 0;
-}
-
 /*!
  * \internal
  * \brief Load and reload SMDI configuration.
@@ -934,11 +956,9 @@ static int smdi_load(int reload)
 {
 	struct ast_config *conf;
 	struct ast_variable *v;
+	struct ast_smdi_interface *iface = NULL;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 	int res = 0;
-	RAII_VAR(struct ao2_container *, new_ifaces, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, old_ifaces, ao2_global_obj_ref(smdi_ifaces), ao2_cleanup);
-	struct ast_smdi_interface *mailbox_iface = NULL;
 
 	/* Config options */
 	speed_t baud_rate = B9600;     /* 9600 baud rate */
@@ -958,10 +978,15 @@ static int smdi_load(int reload)
 	} else if (conf == CONFIG_STATUS_FILEUNCHANGED)
 		return 0;
 
-	new_ifaces = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, smdi_ifaces_cmp_fn);
-	for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
-		RAII_VAR(struct ast_smdi_interface *, iface, NULL, ao2_cleanup);
+	/* Mark all interfaces that we are listening on.  We will unmark them
+	 * as we find them in the config file, this way we know any interfaces
+	 * still marked after we have finished parsing the config file should
+	 * be stopped.
+	 */
+	if (reload)
+		ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
 
+	for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
 		if (!strcasecmp(v->name, "baudrate")) {
 			if (!strcasecmp(v->value, "9600"))
 				baud_rate = B9600;
@@ -1022,9 +1047,10 @@ static int smdi_load(int reload)
 				 * restarting the interface.  Or the interface
 				 * could be restarted with out emptying the
 				 * queue. */
-				if ((iface = ao2_find(old_ifaces, v->value, OBJ_SEARCH_KEY))) {
+				if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
 					ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
-					ao2_link(new_ifaces, iface);
+					ASTOBJ_UNMARK(iface);
+					ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 					continue;
 				}
 			}
@@ -1038,6 +1064,7 @@ static int smdi_load(int reload)
 
 			if (!(iface->file = fopen(iface->name, "r"))) {
 				ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				continue;
 			}
 
@@ -1048,12 +1075,14 @@ static int smdi_load(int reload)
 			/* get the current attributes from the port */
 			if (tcgetattr(iface->fd, &iface->mode)) {
 				ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				continue;
 			}
 
 			/* set the desired speed */
 			if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
 				ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				continue;
 			}
 			
@@ -1072,6 +1101,7 @@ static int smdi_load(int reload)
 			/* commit the desired attributes */
 			if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
 				ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				continue;
 			}
 
@@ -1085,10 +1115,12 @@ static int smdi_load(int reload)
 			ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
 			if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
 				ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 				continue;
 			}
 
-			ao2_link(new_ifaces, iface);
+			ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
+			ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 			ast_module_ref(ast_module_info->self);
 		} else {
 			ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
@@ -1097,12 +1129,15 @@ static int smdi_load(int reload)
 
 	destroy_all_mailbox_mappings();
 	mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
+	
+	iface = NULL;
 
 	for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
 		if (!strcasecmp(v->name, "smdiport")) {
-			ao2_cleanup(mailbox_iface);
+			if (iface)
+				ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 
-			if (!(mailbox_iface = ao2_find(new_ifaces, v->value, OBJ_SEARCH_KEY))) {
+			if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
 				ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
 				continue;
 			}
@@ -1112,28 +1147,34 @@ static int smdi_load(int reload)
 				mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
 			}
 		} else {
-			if (!mailbox_iface) {
+			if (!iface) {
 				ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
 				continue;
 			}
-			append_mailbox_mapping(v, mailbox_iface);
+			append_mailbox_mapping(v, iface);
 		}
 	}
-	ao2_cleanup(mailbox_iface);
 
-	ast_config_destroy(conf);
-
-	ao2_global_obj_replace_unref(smdi_ifaces, new_ifaces);
+	if (iface)
+		ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
 
+	ast_config_destroy(conf);
+	
 	if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
 		&& ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) {
 		ast_log(LOG_ERROR, "Failed to start MWI monitoring thread.  This module will not operate.\n");
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	if (ao2_container_count(new_ifaces)) {
+	/* Prune any interfaces we should no longer monitor. */
+	if (reload)
+		ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
+	
+	ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
+	/* TODO: this is bad, we need an ASTOBJ method for this! */
+	if (!smdi_ifaces.head)
 		res = 1;
-	}
+	ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
 	
 	return res;
 }
@@ -1148,8 +1189,11 @@ static void smdi_msg_datastore_destroy(void *data)
 {
 	struct smdi_msg_datastore *smd = data;
 
-	ao2_cleanup(smd->iface);
-	ao2_cleanup(smd->md_msg);
+	if (smd->iface)
+		ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
+
+	if (smd->md_msg)
+		ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
 
 	free(smd);
 }
@@ -1234,8 +1278,8 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
 	if (!(smd = ast_calloc(1, sizeof(*smd))))
 		goto return_error;
 
-	smd->iface = ao2_bump(iface);
-	smd->md_msg = ao2_bump(md_msg);
+	smd->iface = ASTOBJ_REF(iface);
+	smd->md_msg = ASTOBJ_REF(md_msg);
 	smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
 	snprintf(buf, len, "%u", smd->id);
 
@@ -1251,8 +1295,11 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
 	res = 0;
 
 return_error:
-	ao2_cleanup(iface);
-	ao2_cleanup(md_msg);
+	if (iface)
+		ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
+
+	if (md_msg)
+		ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
 
 	if (smd && !datastore)
 		smdi_msg_datastore_destroy(smd);
@@ -1349,21 +1396,15 @@ static struct ast_custom_function smdi_msg_function = {
 
 static int _unload_module(int fromload);
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	int res;
 	smdi_loaded = 1;
 
+	/* initialize our containers */
+	memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
+	ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
+
 	ast_mutex_init(&mwi_monitor.lock);
 	ast_cond_init(&mwi_monitor.cond, NULL);
 
@@ -1390,7 +1431,9 @@ static int _unload_module(int fromload)
 		return 0;
 	}
 
-	ao2_global_obj_release(smdi_ifaces);
+	/* this destructor stops any running smdi_read threads */
+	ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
 
 	destroy_all_mailbox_mappings();
 
@@ -1433,7 +1476,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Simplified Message Desk Interface (SMDI) Resource",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_snmp.c b/res/res_snmp.c
index 5608709..f717cea 100644
--- a/res/res_snmp.c
+++ b/res/res_snmp.c
@@ -13,19 +13,10 @@
  *
  * \author Thorsten Lockert <tholo at voop.as>
  *
- * Uses the Net-SNMP libraries available at
+ * \extref Uses the Net-SNMP libraries available at
  *	 http://net-snmp.sourceforge.net/
  */
 
-/*! \li \ref res_snmp.c uses the configuration file \ref res_snmp.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page res_snmp.conf res_snmp.conf
- * \verbinclude res_snmp.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>netsnmp</depend>
 	<support_level>extended</support_level>
@@ -33,7 +24,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
@@ -103,16 +94,6 @@ static int load_config(void)
 	return 1;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if(!load_config())
@@ -136,7 +117,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SNMP [Sub]Agent for Asterisk",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		);
diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c
deleted file mode 100644
index 1c774af..0000000
--- a/res/res_sorcery_astdb.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Sorcery Astdb Object Wizard
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include <regex.h>
-
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astdb.h"
-#include "asterisk/json.h"
-
-static void *sorcery_astdb_open(const char *data);
-static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object);
-static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
-static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
-static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
-					     const struct ast_variable *fields);
-static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
-static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object);
-static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object);
-static void sorcery_astdb_close(void *data);
-
-static struct ast_sorcery_wizard astdb_object_wizard = {
-	.name = "astdb",
-	.open = sorcery_astdb_open,
-	.create = sorcery_astdb_create,
-	.retrieve_id = sorcery_astdb_retrieve_id,
-	.retrieve_fields = sorcery_astdb_retrieve_fields,
-	.retrieve_multiple = sorcery_astdb_retrieve_multiple,
-	.retrieve_regex = sorcery_astdb_retrieve_regex,
-	.update = sorcery_astdb_update,
-	.delete = sorcery_astdb_delete,
-	.close = sorcery_astdb_close,
-};
-
-/*! \brief Helper function which converts from a sorcery object set to a json object */
-static struct ast_json *sorcery_objectset_to_json(const struct ast_variable *objectset)
-{
-	struct ast_json *json = ast_json_object_create();
-	const struct ast_variable *field;
-
-	for (field = objectset; field; field = field->next) {
-		struct ast_json *value = ast_json_string_create(field->value);
-
-		if (!value) {
-			ast_json_unref(json);
-			return NULL;
-		} else if (ast_json_object_set(json, field->name, value)) {
-			ast_json_unref(json);
-			return NULL;
-		}
-	}
-
-	return json;
-}
-
-/*! \brief Helper function which converts a json object to a sorcery object set */
-static struct ast_variable *sorcery_json_to_objectset(struct ast_json *json)
-{
-	struct ast_json_iter *field;
-	struct ast_variable *objset = NULL;
-
-	for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) {
-		struct ast_json *value = ast_json_object_iter_value(field);
-		struct ast_variable *variable = ast_variable_new(ast_json_object_iter_key(field), ast_json_string_get(value), "");
-
-		if (!variable) {
-			ast_variables_destroy(objset);
-			return NULL;
-		}
-
-		variable->next = objset;
-		objset = variable;
-	}
-
-	return objset;
-}
-
-/*! \brief Helper function which compares two json objects and sees if they are equal, but only looks at the criteria provided */
-static int sorcery_json_equal(struct ast_json *object, struct ast_json *criteria)
-{
-	struct ast_json_iter *field;
-
-	for (field = ast_json_object_iter(criteria); field; field = ast_json_object_iter_next(criteria, field)) {
-		struct ast_json *object_field = ast_json_object_get(object, ast_json_object_iter_key(field));
-
-		if (!object_field || !ast_json_equal(object_field, ast_json_object_iter_value(field))) {
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	RAII_VAR(struct ast_json *, objset, ast_sorcery_objectset_json_create(sorcery, object), ast_json_unref);
-	RAII_VAR(char *, value, NULL, ast_json_free);
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2];
-
-	if (!objset || !(value = ast_json_dump_string(objset))) {
-		return -1;
-	}
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
-
-	return ast_db_put(family, ast_sorcery_object_get_id(object), value);
-}
-
-/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */
-static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects)
-{
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(type) + 2];
-	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
-	RAII_VAR(struct ast_json *, criteria, NULL, ast_json_unref);
-	struct ast_db_entry *entry;
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, type);
-
-	if (!(entries = ast_db_gettree(family, NULL)) || (fields && !(criteria = sorcery_objectset_to_json(fields)))) {
-		return NULL;
-	}
-
-	for (entry = entries; entry; entry = entry->next) {
-		const char *key = entry->key + strlen(family) + 2;
-		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-		struct ast_json_error error;
-		RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-		void *object = NULL;
-
-		if (!(json = ast_json_load_string(entry->data, &error))) {
-			return NULL;
-		} else if (criteria && !sorcery_json_equal(json, criteria)) {
-			continue;
-		} else if (!(objset = sorcery_json_to_objectset(json)) ||
-			!(object = ast_sorcery_alloc(sorcery, type, key)) ||
-			ast_sorcery_objectset_apply(sorcery, object, objset)) {
-			ao2_cleanup(object);
-			return NULL;
-		}
-
-		if (!objects) {
-			return object;
-		}
-
-		ao2_link(objects, object);
-		ao2_cleanup(object);
-	}
-
-	return NULL;
-}
-
-static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
-{
-	return sorcery_astdb_retrieve_fields_common(sorcery, data, type, fields, NULL);
-}
-
-static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
-{
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(type) + 2];
-	RAII_VAR(char *, value, NULL, ast_free_ptr);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json_error error;
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	void *object = NULL;
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, type);
-
-	if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) ||
-		!(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, id)) ||
-		ast_sorcery_objectset_apply(sorcery, object, objset)) {
-		ao2_cleanup(object);
-		return NULL;
-	}
-
-	return object;
-}
-
-static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
-{
-	sorcery_astdb_retrieve_fields_common(sorcery, data, type, fields, objects);
-}
-
-/*!
- * \internal
- * \brief Convert regex prefix pattern to astDB prefix pattern if possible.
- *
- * \param tree astDB prefix pattern buffer to fill.
- * \param regex Extended regular expression with the start anchor character '^'.
- *
- * \note Since this is a helper function, the tree buffer is
- * assumed to always be large enough.
- *
- * \retval 0 on success.
- * \retval -1 on error.  regex is invalid.
- */
-static int make_astdb_prefix_pattern(char *tree, const char *regex)
-{
-	const char *src;
-	char *dst;
-
-	for (dst = tree, src = regex + 1; *src; ++src) {
-		if (*src == '\\') {
-			/* Escaped regex char. */
-			++src;
-			if (!*src) {
-				/* Invalid regex.  The caller escaped the string terminator. */
-				return -1;
-			}
-		} else if (*src == '$') {
-			if (!src[1]) {
-				/* Remove the tail anchor character. */
-				*dst = '\0';
-				return 0;
-			}
-		} else if (strchr(".?*+{[(|", *src)) {
-			/*
-			 * The regex is not a simple prefix pattern.
-			 *
-			 * XXX With more logic, it is possible to simply
-			 * use the current prefix pattern.  The last character
-			 * needs to be removed if possible when the current regex
-			 * token is "?*{".  Also the rest of the regex pattern
-			 * would need to be checked for subgroup/alternation.
-			 * Subgroup/alternation is too complex for a simple prefix
-			 * match.
-			 */
-			dst = tree;
-			break;
-		}
-		*dst++ = *src;
-	}
-	if (dst != tree) {
-		*dst++ = '%';
-	}
-	*dst = '\0';
-	return 0;
-}
-
-static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
-{
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(type) + 2];
-	char tree[strlen(regex) + 1];
-	RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
-	regex_t expression;
-	struct ast_db_entry *entry;
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, type);
-
-	if (regex[0] == '^') {
-		/*
-		 * For performance reasons, try to create an astDB prefix
-		 * pattern from the regex to reduce the number of entries
-		 * retrieved from astDB for regex to then match.
-		 */
-		if (make_astdb_prefix_pattern(tree, regex)) {
-			return;
-		}
-	} else {
-		tree[0] = '\0';
-	}
-
-	if (!(entries = ast_db_gettree(family, tree))
-		|| regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
-		return;
-	}
-
-	for (entry = entries; entry; entry = entry->next) {
-		/* The key in the entry includes the family, so we need to strip it out for regex purposes */
-		const char *key = entry->key + strlen(family) + 2;
-		RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-		struct ast_json_error error;
-		RAII_VAR(void *, object, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-		if (regexec(&expression, key, 0, NULL, 0)) {
-			continue;
-		} else if (!(json = ast_json_load_string(entry->data, &error)) ||
-			!(objset = sorcery_json_to_objectset(json)) ||
-			!(object = ast_sorcery_alloc(sorcery, type, key)) ||
-			ast_sorcery_objectset_apply(sorcery, object, objset)) {
-			regfree(&expression);
-			return;
-		}
-
-		ao2_link(objects, object);
-	}
-
-	regfree(&expression);
-}
-
-static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2], value[2];
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
-
-	/* It is okay for the value to be truncated, we are only checking that it exists */
-	if (ast_db_get(family, ast_sorcery_object_get_id(object), value, sizeof(value))) {
-		return -1;
-	}
-
-	/* The only difference between update and create is that for update the object must already exist */
-	return sorcery_astdb_create(sorcery, data, object);
-}
-
-static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	const char *prefix = data;
-	char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2];
-	char value[2];
-
-	snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
-
-	if (ast_db_get(family, ast_sorcery_object_get_id(object), value, sizeof(value))) {
-		return -1;
-	}
-
-	return ast_db_del(family, ast_sorcery_object_get_id(object));
-}
-
-static void *sorcery_astdb_open(const char *data)
-{
-	/* We require a prefix for family string generation, or else stuff could mix together */
-	if (ast_strlen_zero(data)) {
-		return NULL;
-	}
-
-	return ast_strdup(data);
-}
-
-static void sorcery_astdb_close(void *data)
-{
-	ast_free(data);
-}
-
-static int load_module(void)
-{
-	if (ast_sorcery_wizard_register(&astdb_object_wizard)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sorcery_wizard_unregister(&astdb_object_wizard);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Sorcery Astdb Object Wizard",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_REALTIME_DRIVER,
-);
diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c
deleted file mode 100644
index 46b24cb..0000000
--- a/res/res_sorcery_config.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Sorcery Configuration File Object Wizard
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
-
-#include <regex.h>
-
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/config.h"
-#include "asterisk/uuid.h"
-
-/*! \brief Default number of buckets for sorcery objects */
-#define DEFAULT_OBJECT_BUCKETS 53
-
-/*! \brief Structure for storing configuration file sourced objects */
-struct sorcery_config {
-	/*! \brief UUID for identifying us when opening a configuration file */
-	char uuid[AST_UUID_STR_LEN];
-
-	/*! \brief Objects retrieved from the configuration file */
-	struct ao2_global_obj objects;
-
-	/*! \brief Any specific variable criteria for considering a defined category for this object */
-	struct ast_variable *criteria;
-
-	/*! \brief Number of buckets to use for objects */
-	unsigned int buckets;
-
-	/*! \brief Enable file level integrity instead of object level */
-	unsigned int file_integrity:1;
-
-	/*! \brief Filename of the configuration file */
-	char filename[];
-};
-
-/*! \brief Structure used for fields comparison */
-struct sorcery_config_fields_cmp_params {
-	/*! \brief Pointer to the sorcery structure */
-	const struct ast_sorcery *sorcery;
-
-	/*! \brief Pointer to the fields to check */
-	const struct ast_variable *fields;
-
-	/*! \brief Regular expression for checking object id */
-	regex_t *regex;
-
-	/*! \brief Optional container to put object into */
-	struct ao2_container *container;
-};
-
-static void *sorcery_config_open(const char *data);
-static void sorcery_config_load(void *data, const struct ast_sorcery *sorcery, const char *type);
-static void sorcery_config_reload(void *data, const struct ast_sorcery *sorcery, const char *type);
-static void *sorcery_config_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
-static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
-static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
-					     const struct ast_variable *fields);
-static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
-static void sorcery_config_close(void *data);
-
-static struct ast_sorcery_wizard config_object_wizard = {
-	.name = "config",
-	.open = sorcery_config_open,
-	.load = sorcery_config_load,
-	.reload = sorcery_config_reload,
-	.retrieve_id = sorcery_config_retrieve_id,
-	.retrieve_fields = sorcery_config_retrieve_fields,
-	.retrieve_multiple = sorcery_config_retrieve_multiple,
-	.retrieve_regex = sorcery_config_retrieve_regex,
-	.close = sorcery_config_close,
-};
-
-/*! \brief Destructor function for sorcery config */
-static void sorcery_config_destructor(void *obj)
-{
-	struct sorcery_config *config = obj;
-
-	ao2_global_obj_release(config->objects);
-	ast_rwlock_destroy(&config->objects.lock);
-	ast_variables_destroy(config->criteria);
-}
-
-/*! \brief Hashing function for sorcery objects */
-static int sorcery_config_hash(const void *obj, const int flags)
-{
-	const char *id = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? id : ast_sorcery_object_get_id(obj));
-}
-
-/*! \brief Comparator function for sorcery objects */
-static int sorcery_config_cmp(void *obj, void *arg, int flags)
-{
-	const char *id = arg;
-
-	return !strcmp(ast_sorcery_object_get_id(obj), flags & OBJ_KEY ? id : ast_sorcery_object_get_id(arg)) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)
-{
-	const struct sorcery_config_fields_cmp_params *params = arg;
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
-
-	if (params->regex) {
-		/* If a regular expression has been provided see if it matches, otherwise move on */
-		if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
-			ao2_link(params->container, obj);
-		}
-		return 0;
-	} else if (params->fields &&
-	    (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
-	     (ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
-	     diff)) {
-		/* If we can't turn the object into an object set OR if differences exist between the fields
-	     * passed in and what are present on the object they are not a match.
-	     */
-		return 0;
-	}
-
-	if (params->container) {
-		ao2_link(params->container, obj);
-
-		/* As multiple objects are being returned keep going */
-		return 0;
-	} else {
-		/* Immediately stop and return, we only want a single object */
-		return CMP_MATCH | CMP_STOP;
-	}
-}
-
-static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
-{
-	struct sorcery_config *config = data;
-	RAII_VAR(struct ao2_container *, objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
-	struct sorcery_config_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.fields = fields,
-		.container = NULL,
-	};
-
-	/* If no fields are present return nothing, we require *something*, same goes if no objects exist yet */
-	if (!objects || !fields) {
-		return NULL;
-	}
-
-	return ao2_callback(objects, 0, sorcery_config_fields_cmp, &params);
-}
-
-static void *sorcery_config_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
-{
-	struct sorcery_config *config = data;
-	RAII_VAR(struct ao2_container *, objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
-
-	return objects ? ao2_find(objects, id, OBJ_KEY | OBJ_NOLOCK) : NULL;
-}
-
-static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
-{
-	struct sorcery_config *config = data;
-	RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
-	struct sorcery_config_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.fields = fields,
-		.container = objects,
-	};
-
-	if (!config_objects) {
-		return;
-	}
-	ao2_callback(config_objects, 0, sorcery_config_fields_cmp, &params);
-}
-
-static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
-{
-	struct sorcery_config *config = data;
-	RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
-	regex_t expression;
-	struct sorcery_config_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.container = objects,
-		.regex = &expression,
-	};
-
-	if (!config_objects || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
-		return;
-	}
-
-	ao2_callback(config_objects, 0, sorcery_config_fields_cmp, &params);
-	regfree(&expression);
-}
-
-/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
-static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
-{
-	RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
-
-	return (!criteria || (!ast_sorcery_changeset_create(objset, criteria, &diff) && !diff)) ? 1 : 0;
-}
-
-static void sorcery_config_internal_load(void *data, const struct ast_sorcery *sorcery, const char *type, unsigned int reload)
-{
-	struct sorcery_config *config = data;
-	struct ast_flags flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	struct ast_config *cfg = ast_config_load2(config->filename, config->uuid, flags);
-	struct ast_category *category = NULL;
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-	const char *id = NULL;
-
-	if (!cfg) {
-		ast_log(LOG_ERROR, "Unable to load config file '%s'\n", config->filename);
-		return;
-	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-		ast_debug(1, "Config file '%s' was unchanged\n", config->filename);
-		return;
-	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Contents of config file '%s' are invalid and cannot be parsed\n", config->filename);
-		return;
-	}
-
-	if (!(objects = ao2_container_alloc(config->buckets, sorcery_config_hash, sorcery_config_cmp))) {
-		ast_log(LOG_ERROR, "Could not create bucket for new objects from '%s', keeping existing objects\n",
-			config->filename);
-		ast_config_destroy(cfg);
-		return;
-	}
-
-	while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {
-		RAII_VAR(void *, obj, NULL, ao2_cleanup);
-		id = ast_category_get_name(category);
-
-		/* If given criteria has not been met skip the category, it is not applicable */
-		if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {
-			continue;
-		}
-
-		if (!(obj = ast_sorcery_alloc(sorcery, type, id)) ||
-		    ast_sorcery_objectset_apply(sorcery, obj, ast_category_first(category))) {
-
-			if (config->file_integrity) {
-				ast_log(LOG_ERROR, "Config file '%s' could not be loaded due to error with object '%s' of type '%s'\n",
-					config->filename, id, type);
-				ast_config_destroy(cfg);
-				return;
-			} else {
-				ast_log(LOG_ERROR, "Could not create an object of type '%s' with id '%s' from configuration file '%s'\n",
-					type, id, config->filename);
-			}
-
-			ao2_cleanup(obj);
-
-			/* To ensure we don't lose the object that already exists we retrieve it from the old objects container and add it to the new one */
-			if (!(obj = sorcery_config_retrieve_id(sorcery, data, type, id))) {
-				continue;
-			}
-		}
-
-		ao2_link_flags(objects, obj, OBJ_NOLOCK);
-	}
-
-	ao2_global_obj_replace_unref(config->objects, objects);
-	ast_config_destroy(cfg);
-}
-
-static void sorcery_config_load(void *data, const struct ast_sorcery *sorcery, const char *type)
-{
-	sorcery_config_internal_load(data, sorcery, type, 0);
-}
-
-static void sorcery_config_reload(void *data, const struct ast_sorcery *sorcery, const char *type)
-{
-	sorcery_config_internal_load(data, sorcery, type, 1);
-}
-
-static void *sorcery_config_open(const char *data)
-{
-	char *tmp = ast_strdupa(data), *filename = strsep(&tmp, ","), *option;
-	struct sorcery_config *config;
-
-	if (ast_strlen_zero(filename) || !(config = ao2_alloc_options(sizeof(*config) + strlen(filename) + 1, sorcery_config_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
-		return NULL;
-	}
-
-	ast_uuid_generate_str(config->uuid, sizeof(config->uuid));
-
-	ast_rwlock_init(&config->objects.lock);
-	config->buckets = DEFAULT_OBJECT_BUCKETS;
-	strcpy(config->filename, filename);
-
-	while ((option = strsep(&tmp, ","))) {
-		char *name = strsep(&option, "="), *value = option;
-
-		if (!strcasecmp(name, "buckets")) {
-			if (sscanf(value, "%30u", &config->buckets) != 1) {
-				ast_log(LOG_ERROR, "Unsupported bucket size of '%s' used for configuration file '%s', defaulting to '%d'\n",
-					value, filename, DEFAULT_OBJECT_BUCKETS);
-			}
-		} else if (!strcasecmp(name, "integrity")) {
-			if (!strcasecmp(value, "file")) {
-				config->file_integrity = 1;
-			} else if (!strcasecmp(value, "object")) {
-				config->file_integrity = 0;
-			} else {
-				ast_log(LOG_ERROR, "Unsupported integrity value of '%s' used for configuration file '%s', defaulting to 'object'\n",
-					value, filename);
-			}
-		} else if (!strcasecmp(name, "criteria")) {
-			char *field = strsep(&value, "=");
-			struct ast_variable *criteria = ast_variable_new(field, value, "");
-
-			if (criteria) {
-				criteria->next = config->criteria;
-				config->criteria = criteria;
-			} else {
-				/* This is fatal since not following criteria would potentially yield invalid objects */
-				ast_log(LOG_ERROR, "Could not create criteria entry of field '%s' with value '%s' for configuration file '%s'\n",
-					field, value, filename);
-				ao2_ref(config, -1);
-				return NULL;
-			}
-		} else {
-			ast_log(LOG_ERROR, "Unsupported option '%s' used for configuration file '%s'\n", name, filename);
-		}
-	}
-
-	return config;
-}
-
-static void sorcery_config_close(void *data)
-{
-	struct sorcery_config *config = data;
-
-	ao2_ref(config, -1);
-}
-
-static int load_module(void)
-{
-	if (ast_sorcery_wizard_register(&config_object_wizard)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sorcery_wizard_unregister(&config_object_wizard);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Sorcery Configuration File Object Wizard",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_REALTIME_DRIVER,
-);
diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c
deleted file mode 100644
index 40b257e..0000000
--- a/res/res_sorcery_memory.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Sorcery In-Memory Object Wizard
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include <regex.h>
-
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astobj2.h"
-
-/*! \brief Number of buckets for sorcery objects */
-#define OBJECT_BUCKETS 53
-
-static void *sorcery_memory_open(const char *data);
-static int sorcery_memory_create(const struct ast_sorcery *sorcery, void *data, void *object);
-static void *sorcery_memory_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
-static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
-static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
-					     const struct ast_variable *fields);
-static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
-static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object);
-static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object);
-static void sorcery_memory_close(void *data);
-
-static struct ast_sorcery_wizard memory_object_wizard = {
-	.name = "memory",
-	.open = sorcery_memory_open,
-	.create = sorcery_memory_create,
-	.retrieve_id = sorcery_memory_retrieve_id,
-	.retrieve_fields = sorcery_memory_retrieve_fields,
-	.retrieve_multiple = sorcery_memory_retrieve_multiple,
-	.retrieve_regex = sorcery_memory_retrieve_regex,
-	.update = sorcery_memory_update,
-	.delete = sorcery_memory_delete,
-	.close = sorcery_memory_close,
-};
-
-/*! \brief Structure used for fields comparison */
-struct sorcery_memory_fields_cmp_params {
-	/*! \brief Pointer to the sorcery structure */
-	const struct ast_sorcery *sorcery;
-
-	/*! \brief Pointer to the fields to check */
-	const struct ast_variable *fields;
-
-	/*! \brief Regular expression for checking object id */
-	regex_t *regex;
-
-	/*! \brief Optional container to put object into */
-	struct ao2_container *container;
-};
-
-/*! \brief Hashing function for sorcery objects */
-static int sorcery_memory_hash(const void *obj, const int flags)
-{
-	const char *id = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? id : ast_sorcery_object_get_id(obj));
-}
-
-/*! \brief Comparator function for sorcery objects */
-static int sorcery_memory_cmp(void *obj, void *arg, int flags)
-{
-	const char *id = arg;
-
-	return !strcmp(ast_sorcery_object_get_id(obj), flags & OBJ_KEY ? id : ast_sorcery_object_get_id(arg)) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static int sorcery_memory_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	ao2_link(data, object);
-	return 0;
-}
-
-static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags)
-{
-	const struct sorcery_memory_fields_cmp_params *params = arg;
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
-
-	if (params->regex) {
-		/* If a regular expression has been provided see if it matches, otherwise move on */
-		if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
-			ao2_link(params->container, obj);
-		}
-		return 0;
-	} else if (params->fields &&
-	    (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
-	     (ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
-	     diff)) {
-		/* If we can't turn the object into an object set OR if differences exist between the fields
-		 * passed in and what are present on the object they are not a match.
-		 */
-		return 0;
-	}
-
-	if (params->container) {
-		ao2_link(params->container, obj);
-
-		/* As multiple objects are being returned keep going */
-		return 0;
-	} else {
-		/* Immediately stop and return, we only want a single object */
-		return CMP_MATCH | CMP_STOP;
-	}
-}
-
-static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
-{
-	struct sorcery_memory_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.fields = fields,
-		.container = NULL,
-	};
-
-	/* If no fields are present return nothing, we require *something* */
-	if (!fields) {
-		return NULL;
-	}
-
-	return ao2_callback(data, 0, sorcery_memory_fields_cmp, &params);
-}
-
-static void *sorcery_memory_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
-{
-	return ao2_find(data, id, OBJ_KEY);
-}
-
-static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
-{
-	struct sorcery_memory_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.fields = fields,
-		.container = objects,
-	};
-
-	ao2_callback(data, 0, sorcery_memory_fields_cmp, &params);
-}
-
-static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
-{
-	regex_t expression;
-	struct sorcery_memory_fields_cmp_params params = {
-		.sorcery = sorcery,
-		.container = objects,
-		.regex = &expression,
-	};
-
-	if (regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
-		return;
-	}
-
-	ao2_callback(data, 0, sorcery_memory_fields_cmp, &params);
-	regfree(&expression);
-}
-
-static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	RAII_VAR(void *, existing, NULL, ao2_cleanup);
-
-	ao2_lock(data);
-
-	if (!(existing = ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_UNLINK))) {
-		ao2_unlock(data);
-		return -1;
-	}
-
-	ao2_link(data, object);
-
-	ao2_unlock(data);
-
-	return 0;
-}
-
-static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	RAII_VAR(void *, existing, ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
-
-	return existing ? 0 : -1;
-}
-
-static void *sorcery_memory_open(const char *data)
-{
-	return ao2_container_alloc(OBJECT_BUCKETS, sorcery_memory_hash, sorcery_memory_cmp);
-}
-
-static void sorcery_memory_close(void *data)
-{
-	ao2_ref(data, -1);
-}
-
-static int load_module(void)
-{
-	if (ast_sorcery_wizard_register(&memory_object_wizard)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sorcery_wizard_unregister(&memory_object_wizard);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Sorcery In-Memory Object Wizard",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_REALTIME_DRIVER,
-);
diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c
deleted file mode 100644
index b944bfd..0000000
--- a/res/res_sorcery_realtime.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Sorcery Realtime Object Wizard
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425384 $")
-
-#include <regex.h>
-
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-
-/*! \brief They key field used to store the unique identifier for the object */
-#define UUID_FIELD "id"
-
-static void *sorcery_realtime_open(const char *data);
-static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object);
-static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
-static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
-static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
-					     const struct ast_variable *fields);
-static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
-static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
-static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
-static void sorcery_realtime_close(void *data);
-
-static struct ast_sorcery_wizard realtime_object_wizard = {
-	.name = "realtime",
-	.open = sorcery_realtime_open,
-	.create = sorcery_realtime_create,
-	.retrieve_id = sorcery_realtime_retrieve_id,
-	.retrieve_fields = sorcery_realtime_retrieve_fields,
-	.retrieve_multiple = sorcery_realtime_retrieve_multiple,
-	.retrieve_regex = sorcery_realtime_retrieve_regex,
-	.update = sorcery_realtime_update,
-	.delete = sorcery_realtime_delete,
-	.close = sorcery_realtime_close,
-};
-
-static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	const char *family = data;
-	RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
-	struct ast_variable *id = ast_variable_new(UUID_FIELD, ast_sorcery_object_get_id(object), "");
-
-	if (!fields || !id) {
-		ast_variables_destroy(id);
-		return -1;
-	}
-
-	/* Place the identifier at the front for sanity sake */
-	id->next = fields;
-	fields = id;
-
-	return (ast_store_realtime_fields(family, fields) <= 0) ? -1 : 0;
-}
-
-/*! \brief Internal helper function which returns a filtered objectset. 
- *
- * The following are filtered out of the objectset:
- * \li The id field. This is returned to the caller in an out parameter.
- * \li Fields that are not registered with sorcery.
- *
- * \param objectset Objectset to filter.
- * \param[out] id The ID of the sorcery object, as found in the objectset.
- * \param sorcery The sorcery instance that is requesting an objectset.
- * \param type The object type
- *
- * \return The filtered objectset
- */
-static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variable *objectset, struct ast_variable **id,
-		const struct ast_sorcery *sorcery, const char *type)
-{
-	struct ast_variable *previous = NULL, *field = objectset;
-	struct ast_sorcery_object_type *object_type;
-
-	object_type = ast_sorcery_get_object_type(sorcery, type);
-	if (!object_type) {
-		ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type);
-		/* Continue since we still want to filter out the id */
-	}
-
-	while (field) {
-		int remove_field = 0;
-		int delete_field = 0;
-
-		if (!strcmp(field->name, UUID_FIELD)) {
-			*id = field;
-			remove_field = 1;
-		} else if (object_type &&
-				!ast_sorcery_is_object_field_registered(object_type, field->name)) {
-			ast_debug(1, "Filtering out realtime field '%s' from retrieval\n", field->name);
-			remove_field = 1;
-			delete_field = 1;
-		}
-
-		if (remove_field) {
-			struct ast_variable *removed;
-
-			if (previous) {
-				previous->next = field->next;
-			} else {
-				objectset = field->next;
-			}
-
-			removed = field;
-			field = field->next;
-			removed->next = NULL;
-			if (delete_field) {
-				ast_variables_destroy(removed);
-			}
-		} else {
-			previous = field;
-			field = field->next;
-		}
-	}
-
-	return objectset;
-}
-
-static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
-{
-	const char *family = data;
-	RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
-	void *object = NULL;
-
-	if (!(objectset = ast_load_realtime_fields(family, fields))) {
-		return NULL;
-	}
-
-	objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);
-
-	if (!id || !(object = ast_sorcery_alloc(sorcery, type, id->value)) || ast_sorcery_objectset_apply(sorcery, object, objectset)) {
-		return NULL;
-	}
-
-	return object;
-}
-
-static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
-{
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new(UUID_FIELD, id, ""), ast_variables_destroy);
-
-	return sorcery_realtime_retrieve_fields(sorcery, data, type, fields);
-}
-
-static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
-{
-	const char *family = data;
-	RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy);
-	RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy);
-	struct ast_category *row = NULL;
-
-	if (!fields) {
-		char field[strlen(UUID_FIELD) + 6], value[2];
-
-		/* If no fields have been specified we want all rows, so trick realtime into doing it */
-		snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
-		snprintf(value, sizeof(value), "%%");
-
-		if (!(all = ast_variable_new(field, value, ""))) {
-			return;
-		}
-
-		fields = all;
-	}
-
-	if (!(rows = ast_load_realtime_multientry_fields(family, fields))) {
-		return;
-	}
-
-	while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) {
-		struct ast_variable *objectset = ast_category_detach_variables(row);
-		RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
-		RAII_VAR(void *, object, NULL, ao2_cleanup);
-
-		objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);
-
-		if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) {
-			ao2_link(objects, object);
-		}
-
-		ast_variables_destroy(objectset);
-	}
-}
-
-static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
-{
-	char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 2];
-	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
-
-	/* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */
-	if (regex[0] != '^') {
-		return;
-	}
-
-	snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
-	snprintf(value, sizeof(value), "%s%%", regex + 1);
-
-	if (!(fields = ast_variable_new(field, value, ""))) {
-		return;
-	}
-
-	sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
-}
-
-static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	const char *family = data;
-	RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
-
-	if (!fields) {
-		return -1;
-	}
-
-	return (ast_update_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0;
-}
-
-static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	const char *family = data;
-
-	return (ast_destroy_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), NULL) <= 0) ? -1 : 0;
-}
-
-static void *sorcery_realtime_open(const char *data)
-{
-	/* We require a prefix for family string generation, or else stuff could mix together */
-	if (ast_strlen_zero(data) || !ast_realtime_is_mapping_defined(data)) {
-		return NULL;
-	}
-
-	return ast_strdup(data);
-}
-
-static void sorcery_realtime_close(void *data)
-{
-	ast_free(data);
-}
-
-static int load_module(void)
-{
-	if (ast_sorcery_wizard_register(&realtime_object_wizard)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_sorcery_wizard_unregister(&realtime_object_wizard);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Sorcery Realtime Object Wizard",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_REALTIME_DRIVER,
-);
diff --git a/res/res_speech.c b/res/res_speech.c
index 6c56e25..e6fdab9 100644
--- a/res/res_speech.c
+++ b/res/res_speech.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
@@ -38,7 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
 #include "asterisk/cli.h"
 #include "asterisk/term.h"
 #include "asterisk/speech.h"
-#include "asterisk/format_cache.h"
+
 
 static AST_RWLIST_HEAD_STATIC(engines, ast_speech_engine);
 static struct ast_speech_engine *default_engine = NULL;
@@ -172,45 +172,31 @@ int ast_speech_change(struct ast_speech *speech, const char *name, const char *v
 	return (speech->engine->change ? speech->engine->change(speech, name, value) : -1);
 }
 
-/*! \brief Get an engine specific attribute */
-int ast_speech_get_setting(struct ast_speech *speech, const char *name, char *buf, size_t len)
-{
-	return (speech->engine->get_setting ? speech->engine->get_setting(speech, name, buf, len) : -1);
-}
-
 /*! \brief Create a new speech structure using the engine specified */
 struct ast_speech *ast_speech_new(const char *engine_name, const struct ast_format_cap *cap)
 {
 	struct ast_speech_engine *engine = NULL;
 	struct ast_speech *new_speech = NULL;
-	struct ast_format_cap *joint;
-	RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup);
+	struct ast_format_cap *joint = NULL;
+	struct ast_format best;
+
+	ast_format_set(&best, AST_FORMAT_SLINEAR, 0);
 
 	/* Try to find the speech recognition engine that was requested */
 	if (!(engine = find_engine(engine_name)))
 		return NULL;
 
-	joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!joint) {
+	/* Before even allocating the memory below do some codec negotiation, we choose the best codec possible and fall back to signed linear if possible */
+	if ((joint = ast_format_cap_joint(engine->formats, cap))) {
+		ast_best_codec(joint, &best);
+		joint = ast_format_cap_destroy(joint);
+	} else if (!ast_format_cap_iscompatible(engine->formats, &best)) {
 		return NULL;
 	}
 
-	ast_format_cap_get_compatible(engine->formats, cap, joint);
-	best = ast_format_cap_get_format(joint, 0);
-	ao2_ref(joint, -1);
-
-	if (!best) {
-		if (ast_format_cap_iscompatible_format(engine->formats, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL) {
-			best = ao2_bump(ast_format_slin);
-		} else {
-			return NULL;
-		}
-	}
-
 	/* Allocate our own speech structure, and try to allocate a structure from the engine too */
-	if (!(new_speech = ast_calloc(1, sizeof(*new_speech)))) {
+	if (!(new_speech = ast_calloc(1, sizeof(*new_speech))))
 		return NULL;
-	}
 
 	/* Initialize the lock */
 	ast_mutex_init(&new_speech->lock);
@@ -222,13 +208,13 @@ struct ast_speech *ast_speech_new(const char *engine_name, const struct ast_form
 	new_speech->engine = engine;
 
 	/* Can't forget the format audio is going to be in */
-	new_speech->format = best;
+	ast_format_copy(&new_speech->format, &best);
 
 	/* We are not ready to accept audio yet */
 	ast_speech_change_state(new_speech, AST_SPEECH_STATE_NOT_READY);
 
 	/* Pass ourselves to the engine so they can set us up some more and if they error out then do not create a structure */
-	if (engine->create(new_speech, best)) {
+	if (engine->create(new_speech, &best)) {
 		ast_mutex_destroy(&new_speech->lock);
 		ast_free(new_speech);
 		new_speech = NULL;
@@ -256,8 +242,6 @@ int ast_speech_destroy(struct ast_speech *speech)
 	if (speech->processing_sound)
 		ast_free(speech->processing_sound);
 
-	ao2_ref(speech->format, -1);
-
 	/* Aloha we are done */
 	ast_free(speech);
 
@@ -362,7 +346,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic Speech Recognition API",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_APP_DEPEND,
diff --git a/res/res_speech.exports.in b/res/res_speech.exports.in
index c823197..2bdb639 100644
--- a/res/res_speech.exports.in
+++ b/res/res_speech.exports.in
@@ -1,6 +1,21 @@
 {
 	global:
-		LINKER_SYMBOL_PREFIXast_*;
+		LINKER_SYMBOL_PREFIXast_speech_change;
+		LINKER_SYMBOL_PREFIXast_speech_change_results_type;
+		LINKER_SYMBOL_PREFIXast_speech_change_state;
+		LINKER_SYMBOL_PREFIXast_speech_destroy;
+		LINKER_SYMBOL_PREFIXast_speech_dtmf;
+		LINKER_SYMBOL_PREFIXast_speech_grammar_activate;
+		LINKER_SYMBOL_PREFIXast_speech_grammar_deactivate;
+		LINKER_SYMBOL_PREFIXast_speech_grammar_load;
+		LINKER_SYMBOL_PREFIXast_speech_grammar_unload;
+		LINKER_SYMBOL_PREFIXast_speech_new;
+		LINKER_SYMBOL_PREFIXast_speech_register;
+		LINKER_SYMBOL_PREFIXast_speech_results_free;
+		LINKER_SYMBOL_PREFIXast_speech_results_get;
+		LINKER_SYMBOL_PREFIXast_speech_start;
+		LINKER_SYMBOL_PREFIXast_speech_unregister;
+		LINKER_SYMBOL_PREFIXast_speech_write;
 	local:
 		*;
 };
diff --git a/res/res_srtp.c b/res/res_srtp.c
index 07ea878..54ce9e7 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -37,7 +37,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426143 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <srtp/srtp.h>
 #include <srtp/crypto_kernel.h>
@@ -592,7 +592,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Secure RTP (SRTP)",
-	.support_level = AST_MODULE_SUPPORT_CORE,
 	.load = load_module,
 	.unload = unload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_stasis.c b/res/res_stasis.c
deleted file mode 100644
index f954d42..0000000
--- a/res/res_stasis.c
+++ /dev/null
@@ -1,2049 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- *
- * <code>res_stasis.so</code> brings together the various components of the
- * Stasis application infrastructure.
- *
- * First, there's the Stasis application handler, stasis_app_exec(). This is
- * called by <code>app_stasis.so</code> to give control of a channel to the
- * Stasis application code from the dialplan.
- *
- * While a channel is in stasis_app_exec(), it has a \ref stasis_app_control
- * object, which may be used to control the channel.
- *
- * To control the channel, commands may be sent to channel using
- * stasis_app_send_command() and stasis_app_send_async_command().
- *
- * Alongside this, applications may be registered/unregistered using
- * stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis,
- * events received on the channel's topic are converted to JSON and forwarded to
- * the \ref stasis_app_cb. The application may also subscribe to the channel to
- * continue to receive messages even after the channel has left Stasis, but it
- * will not be able to control it.
- *
- * Given all the stuff that comes together in this module, it's been broken up
- * into several pieces that are in <code>res/stasis/</code> and compiled into
- * <code>res_stasis.so</code>.
- */
-
-/*** MODULEINFO
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429062 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/callerid.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/strings.h"
-#include "stasis/app.h"
-#include "stasis/control.h"
-#include "stasis/messaging.h"
-#include "stasis/stasis_bridge.h"
-#include "asterisk/core_unreal.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/causes.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/format_cache.h"
-
-/*! Time to wait for a frame in the application */
-#define MAX_WAIT_MS 200
-
-/*!
- * \brief Number of buckets for the Stasis application hash table.  Remember to
- * keep it a prime number!
- */
-#define APPS_NUM_BUCKETS 127
-
-/*!
- * \brief Number of buckets for the Stasis application hash table.  Remember to
- * keep it a prime number!
- */
-#define CONTROLS_NUM_BUCKETS 127
-
-/*!
- * \brief Number of buckets for the Stasis bridges hash table.  Remember to
- * keep it a prime number!
- */
-#define BRIDGES_NUM_BUCKETS 127
-
-/*!
- * \brief Stasis application container.
- */
-struct ao2_container *apps_registry;
-
-struct ao2_container *app_controls;
-
-struct ao2_container *app_bridges;
-
-struct ao2_container *app_bridges_moh;
-
-struct ao2_container *app_bridges_playback;
-
-static struct ast_json *stasis_end_to_json(struct stasis_message *message,
-		const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_channel_blob *payload = stasis_message_data(message);
-
-	if (sanitize && sanitize->channel_snapshot &&
-			sanitize->channel_snapshot(payload->snapshot)) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: o}",
-		"type", "StasisEnd",
-		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
-		"channel", ast_channel_snapshot_to_json(payload->snapshot, sanitize));
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(end_message_type,
-	.to_json = stasis_end_to_json);
-
-struct start_message_blob {
-	struct ast_channel_snapshot *channel;		/*!< Channel that is entering Stasis() */
-	struct ast_channel_snapshot *replace_channel;	/*!< Channel that is being replaced (optional) */
-	struct ast_json *blob;				/*!< JSON blob containing timestamp and args */
-};
-
-static struct ast_json *stasis_start_to_json(struct stasis_message *message,
-		const struct stasis_message_sanitizer *sanitize)
-{
-	struct start_message_blob *payload = stasis_message_data(message);
-	struct ast_json *msg;
-
-	if (sanitize && sanitize->channel_snapshot &&
-			sanitize->channel_snapshot(payload->channel)) {
-		return NULL;
-	}
-
-	msg = ast_json_pack("{s: s, s: O, s: O, s: o}",
-		"type", "StasisStart",
-		"timestamp", ast_json_object_get(payload->blob, "timestamp"),
-		"args", ast_json_object_get(payload->blob, "args"),
-		"channel", ast_channel_snapshot_to_json(payload->channel, NULL));
-	if (!msg) {
-		ast_log(LOG_ERROR, "Failed to pack JSON for StasisStart message\n");
-		return NULL;
-	}
-
-	if (payload->replace_channel) {
-		int res = ast_json_object_set(msg, "replace_channel",
-			ast_channel_snapshot_to_json(payload->replace_channel, NULL));
-
-		if (res) {
-			ast_json_unref(msg);
-			ast_log(LOG_ERROR, "Failed to append JSON for StasisStart message\n");
-			return NULL;
-		}
-	}
-
-	return msg;
-}
-
-STASIS_MESSAGE_TYPE_DEFN_LOCAL(start_message_type,
-	.to_json = stasis_start_to_json);
-
-const char *stasis_app_name(const struct stasis_app *app)
-{
-	return app_name(app);
-}
-
-/*! AO2 hash function for \ref app */
-static int app_hash(const void *obj, const int flags)
-{
-	const struct stasis_app *app;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		app = obj;
-		key = stasis_app_name(app);
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! AO2 comparison function for \ref app */
-static int app_compare(void *obj, void *arg, int flags)
-{
-	const struct stasis_app *object_left = obj;
-	const struct stasis_app *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = stasis_app_name(object_right);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(stasis_app_name(object_left), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(stasis_app_name(object_left), right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-/*! AO2 hash function for \ref stasis_app_control */
-static int control_hash(const void *obj, const int flags)
-{
-	const struct stasis_app_control *control;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		control = obj;
-		key = stasis_app_control_get_channel_id(control);
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! AO2 comparison function for \ref stasis_app_control */
-static int control_compare(void *obj, void *arg, int flags)
-{
-	const struct stasis_app_control *object_left = obj;
-	const struct stasis_app_control *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = stasis_app_control_get_channel_id(object_right);
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(stasis_app_control_get_channel_id(object_left), right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(stasis_app_control_get_channel_id(object_left), right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-static int cleanup_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_app *app = obj;
-
-	if (!app_is_finished(app)) {
-		return 0;
-	}
-
-	ast_verb(1, "Shutting down application '%s'\n", stasis_app_name(app));
-	app_shutdown(app);
-
-	return CMP_MATCH;
-
-}
-
-/*!
- * \brief Clean up any old apps that we don't need any more.
- */
-static void cleanup(void)
-{
-	ao2_callback(apps_registry, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
-		cleanup_cb, NULL);
-}
-
-struct stasis_app_control *stasis_app_control_create(struct ast_channel *chan)
-{
-	return control_create(chan, NULL);
-}
-
-struct stasis_app_control *stasis_app_control_find_by_channel(
-	const struct ast_channel *chan)
-{
-	if (chan == NULL) {
-		return NULL;
-	}
-
-	return stasis_app_control_find_by_channel_id(
-		ast_channel_uniqueid(chan));
-}
-
-struct stasis_app_control *stasis_app_control_find_by_channel_id(
-	const char *channel_id)
-{
-	return ao2_find(app_controls, channel_id, OBJ_SEARCH_KEY);
-}
-
-/*! AO2 hash function for bridges container  */
-static int bridges_hash(const void *obj, const int flags)
-{
-	const struct ast_bridge *bridge;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		bridge = obj;
-		key = bridge->uniqueid;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! AO2 comparison function for bridges container */
-static int bridges_compare(void *obj, void *arg, int flags)
-{
-	const struct ast_bridge *object_left = obj;
-	const struct ast_bridge *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->uniqueid;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->uniqueid, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-/*!
- *  Used with app_bridges_moh and app_bridge_control, they provide links
- *  between bridges and channels used for ARI application purposes
- */
-struct stasis_app_bridge_channel_wrapper {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(channel_id);
-		AST_STRING_FIELD(bridge_id);
-	);
-};
-
-static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
-{
-	struct stasis_app_bridge_channel_wrapper *wrapper = obj;
-	ast_string_field_free_memory(wrapper);
-}
-
-/*! AO2 hash function for the bridges moh container */
-static int bridges_channel_hash_fn(const void *obj, const int flags)
-{
-	const struct stasis_app_bridge_channel_wrapper *wrapper;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		wrapper = obj;
-		key = wrapper->bridge_id;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right, const int flags)
-{
-	const struct stasis_app_bridge_channel_wrapper *left = obj_left;
-	const struct stasis_app_bridge_channel_wrapper *right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = right->bridge_id;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left->bridge_id, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-/*! Removes the bridge to music on hold channel link */
-static void remove_bridge_moh(char *bridge_id)
-{
-	ao2_find(app_bridges_moh, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-	ast_free(bridge_id);
-}
-
-/*! After bridge failure callback for moh channels */
-static void moh_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
-{
-	char *bridge_id = data;
-
-	remove_bridge_moh(bridge_id);
-}
-
-/*! After bridge callback for moh channels */
-static void moh_after_bridge_cb(struct ast_channel *chan, void *data)
-{
-	char *bridge_id = data;
-
-	remove_bridge_moh(bridge_id);
-}
-
-/*! Request a bridge MOH channel */
-static struct ast_channel *prepare_bridge_moh_channel(void)
-{
-	RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
-
-	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!cap) {
-		return NULL;
-	}
-
-	ast_format_cap_append(cap, ast_format_slin, 0);
-
-	return ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
-}
-
-/*! Provides the moh channel with a thread so it can actually play its music */
-static void *moh_channel_thread(void *data)
-{
-	struct ast_channel *moh_channel = data;
-
-	while (!ast_safe_sleep(moh_channel, 1000)) {
-	}
-
-	ast_moh_stop(moh_channel);
-	ast_hangup(moh_channel);
-
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Creates, pushes, and links a channel for playing music on hold to bridge
- *
- * \param bridge Which bridge this moh channel exists for
- *
- * \retval NULL if the channel could not be created, pushed, or linked
- * \retval Reference to the channel on success
- */
-static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
-	RAII_VAR(char *, bridge_id, ast_strdup(bridge->uniqueid), ast_free);
-	struct ast_channel *chan;
-	pthread_t threadid;
-
-	if (!bridge_id) {
-		return NULL;
-	}
-
-	chan = prepare_bridge_moh_channel();
-	if (!chan) {
-		return NULL;
-	}
-
-	if (stasis_app_channel_unreal_set_internal(chan)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	/* The after bridge callback assumes responsibility of the bridge_id. */
-	if (ast_bridge_set_after_callback(chan,
-		moh_after_bridge_cb, moh_after_bridge_cb_failed, bridge_id)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-	bridge_id = NULL;
-
-	if (ast_unreal_channel_push_to_bridge(chan, bridge,
-		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
-		stasis_app_bridge_channel_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!new_wrapper) {
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	if (ast_string_field_init(new_wrapper, 32)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-	ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
-	ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
-
-	if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, chan)) {
-		ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
-		ao2_unlink_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK);
-		ast_hangup(chan);
-		return NULL;
-	}
-
-	return chan;
-}
-
-struct ast_channel *stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup);
-
-	{
-		SCOPED_AO2LOCK(lock, app_bridges_moh);
-
-		moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-		if (!moh_wrapper) {
-			return bridge_moh_create(bridge);
-		}
-	}
-
-	return ast_channel_get_by_name(moh_wrapper->channel_id);
-}
-
-int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
-{
-	RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup);
-	struct ast_channel *chan;
-
-	moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK);
-	if (!moh_wrapper) {
-		return -1;
-	}
-
-	chan = ast_channel_get_by_name(moh_wrapper->channel_id);
-	if (!chan) {
-		return -1;
-	}
-
-	ast_moh_stop(chan);
-	ast_softhangup(chan, AST_CAUSE_NORMAL_CLEARING);
-	ao2_cleanup(chan);
-
-	return 0;
-}
-
-/*! Removes the bridge to playback channel link */
-static void remove_bridge_playback(char *bridge_id)
-{
-	struct stasis_app_bridge_channel_wrapper *wrapper;
-	struct stasis_app_control *control;
-
-	wrapper = ao2_find(app_bridges_playback, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK);
-
-	if (wrapper) {
-		control = stasis_app_control_find_by_channel_id(wrapper->channel_id);
-		if (control) {
-			ao2_unlink(app_controls, control);
-			ao2_ref(control, -1);
-		}
-		ao2_ref(wrapper, -1);
-	}
-	ast_free(bridge_id);
-}
-
-static void playback_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
-{
-	char *bridge_id = data;
-
-	remove_bridge_playback(bridge_id);
-}
-
-static void playback_after_bridge_cb(struct ast_channel *chan, void *data)
-{
-	char *bridge_id = data;
-
-	remove_bridge_playback(bridge_id);
-}
-
-int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge,
-	struct ast_channel *chan,
-	struct stasis_app_control *control)
-{
-	RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
-	char *bridge_id = ast_strdup(bridge->uniqueid);
-
-	if (!bridge_id) {
-		return -1;
-	}
-
-	if (ast_bridge_set_after_callback(chan,
-		playback_after_bridge_cb, playback_after_bridge_cb_failed, bridge_id)) {
-		ast_free(bridge_id);
-		return -1;
-	}
-
-	new_wrapper = ao2_alloc_options(sizeof(*new_wrapper),
-		stasis_app_bridge_channel_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!new_wrapper) {
-		return -1;
-	}
-
-	if (ast_string_field_init(new_wrapper, 32)) {
-		return -1;
-	}
-
-	ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
-	ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
-
-	if (!ao2_link(app_bridges_playback, new_wrapper)) {
-		return -1;
-	}
-
-	ao2_link(app_controls, control);
-	return 0;
-}
-
-struct ast_channel *stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge)
-{
-	struct stasis_app_bridge_channel_wrapper *playback_wrapper;
-	struct ast_channel *chan;
-
-	playback_wrapper = ao2_find(app_bridges_playback, bridge->uniqueid, OBJ_SEARCH_KEY);
-	if (!playback_wrapper) {
-		return NULL;
-	}
-
-	chan = ast_channel_get_by_name(playback_wrapper->channel_id);
-	ao2_ref(playback_wrapper, -1);
-	return chan;
-}
-
-struct ast_bridge *stasis_app_bridge_find_by_id(
-	const char *bridge_id)
-{
-	return ao2_find(app_bridges, bridge_id, OBJ_SEARCH_KEY);
-}
-
-
-/*!
- * \brief In addition to running ao2_cleanup(), this function also removes the
- * object from the app_controls container.
- */
-static void control_unlink(struct stasis_app_control *control)
-{
-	if (!control) {
-		return;
-	}
-
-	ao2_unlink(app_controls, control);
-	ao2_cleanup(control);
-}
-
-struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
-{
-	struct ast_bridge *bridge;
-	char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing"));
-	int capabilities = 0;
-	int flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
-		| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO
-		| AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY;
-
-	while ((requested_type = strsep(&requested_types, ","))) {
-		requested_type = ast_strip(requested_type);
-
-		if (!strcmp(requested_type, "mixing")) {
-			capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES;
-			flags |= AST_BRIDGE_FLAG_SMART;
-		} else if (!strcmp(requested_type, "holding")) {
-			capabilities |= AST_BRIDGE_CAPABILITY_HOLDING;
-		} else if (!strcmp(requested_type, "dtmf_events") ||
-			!strcmp(requested_type, "proxy_media")) {
-			capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
-		}
-	}
-
-	if (!capabilities
-		/* Holding and mixing capabilities don't mix. */
-		|| ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
-			&& (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) {
-		return NULL;
-	}
-
-	bridge = bridge_stasis_new(capabilities, flags, name, id);
-	if (bridge) {
-		if (!ao2_link(app_bridges, bridge)) {
-			ast_bridge_destroy(bridge, 0);
-			bridge = NULL;
-		}
-	}
-	return bridge;
-}
-
-void stasis_app_bridge_destroy(const char *bridge_id)
-{
-	struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
-	if (!bridge) {
-		return;
-	}
-	ao2_unlink(app_bridges, bridge);
-	ast_bridge_destroy(bridge, 0);
-}
-
-struct replace_channel_store {
-	struct ast_channel_snapshot *snapshot;
-	char *app;
-};
-
-static void replace_channel_destroy(void *obj)
-{
-	struct replace_channel_store *replace = obj;
-
-	ao2_cleanup(replace->snapshot);
-	ast_free(replace->app);
-	ast_free(replace);
-}
-
-static const struct ast_datastore_info replace_channel_store_info = {
-	.type = "replace-channel-store",
-	.destroy = replace_channel_destroy,
-};
-
-static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
-{
-	struct ast_datastore *datastore;
-
-	SCOPED_CHANNELLOCK(lock, chan);
-	datastore = ast_channel_datastore_find(chan, &replace_channel_store_info, NULL);
-	if (!datastore) {
-		if (no_create) {
-			return NULL;
-		}
-
-		datastore = ast_datastore_alloc(&replace_channel_store_info, NULL);
-		if (!datastore) {
-			return NULL;
-		}
-		ast_channel_datastore_add(chan, datastore);
-	}
-
-	if (!datastore->data) {
-		datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
-	}
-	return datastore->data;
-}
-
-int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
-{
-	struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
-
-	if (!replace) {
-		return -1;
-	}
-
-	ao2_replace(replace->snapshot, replace_snapshot);
-	return 0;
-}
-
-int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
-{
-	struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
-
-	if (!replace) {
-		return -1;
-	}
-
-	ast_free(replace->app);
-	replace->app = NULL;
-
-	if (replace_app) {
-		replace->app = ast_strdup(replace_app);
-		if (!replace->app) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static struct ast_channel_snapshot *get_replace_channel_snapshot(struct ast_channel *chan)
-{
-	struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
-	struct ast_channel_snapshot *replace_channel_snapshot;
-
-	if (!replace) {
-		return NULL;
-	}
-
-	replace_channel_snapshot = replace->snapshot;
-	replace->snapshot = NULL;
-
-	return replace_channel_snapshot;
-}
-
-char *app_get_replace_channel_app(struct ast_channel *chan)
-{
-	struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
-	char *replace_channel_app;
-
-	if (!replace) {
-		return NULL;
-	}
-
-	replace_channel_app = replace->app;
-	replace->app = NULL;
-
-	return replace_channel_app;
-}
-
-static void start_message_blob_dtor(void *obj)
-{
-	struct start_message_blob *payload = obj;
-
-	ao2_cleanup(payload->channel);
-	ao2_cleanup(payload->replace_channel);
-	ast_json_unref(payload->blob);
-}
-
-static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app *app,
-	int argc, char *argv[], struct ast_channel_snapshot *snapshot,
-	struct ast_channel_snapshot *replace_channel_snapshot)
-{
-	RAII_VAR(struct ast_json *, json_blob, NULL, ast_json_unref);
-	struct ast_json *json_args;
-	RAII_VAR(struct start_message_blob *, payload, NULL, ao2_cleanup);
-	struct stasis_message *msg;
-	int i;
-
-	if (app_subscribe_channel(app, chan)) {
-		ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
-			app_name(app), ast_channel_name(chan));
-		return -1;
-	}
-
-	payload = ao2_alloc(sizeof(*payload), start_message_blob_dtor);
-	if (!payload) {
-		ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
-		return -1;
-	}
-
-	payload->channel = ao2_bump(snapshot);
-	payload->replace_channel = ao2_bump(replace_channel_snapshot);
-
-	json_blob = ast_json_pack("{s: s, s: o, s: []}",
-		"app", app_name(app),
-		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
-		"args");
-	if (!json_blob) {
-		ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n");
-		return -1;
-	}
-
-	/* Append arguments to args array */
-	json_args = ast_json_object_get(json_blob, "args");
-	ast_assert(json_args != NULL);
-	for (i = 0; i < argc; ++i) {
-		int r = ast_json_array_append(json_args,
-					      ast_json_string_create(argv[i]));
-		if (r != 0) {
-			ast_log(LOG_ERROR, "Error appending to StasisStart message\n");
-			return -1;
-		}
-	}
-
-	payload->blob = ast_json_ref(json_blob);
-
-	msg = stasis_message_create(start_message_type(), payload);
-	if (!msg) {
-		ast_log(LOG_ERROR, "Error sending StasisStart message\n");
-		return -1;
-	}
-
-	if (replace_channel_snapshot) {
-		app_unsubscribe_channel_id(app, replace_channel_snapshot->uniqueid);
-	}
-	stasis_publish(ast_app_get_topic(app), msg);
-	ao2_ref(msg, -1);
-	return 0;
-}
-
-static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
-	int argc, char *argv[])
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, replace_channel_snapshot,
-		NULL, ao2_cleanup);
-
-	ast_assert(chan != NULL);
-
-	replace_channel_snapshot = get_replace_channel_snapshot(chan);
-
-	/* Set channel info */
-	ast_channel_lock(chan);
-	snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (!snapshot) {
-		return -1;
-	}
-	return send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot);
-}
-
-static void remove_masquerade_store(struct ast_channel *chan);
-
-int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
-{
-	struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
-	struct ast_json *blob;
-	struct stasis_message *msg;
-
-	if (sanitize && sanitize->channel
-		&& sanitize->channel(chan)) {
-		return 0;
-	}
-
-	blob = ast_json_pack("{s: s}", "app", app_name(app));
-	if (!blob) {
-		ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
-		return -1;
-	}
-
-	remove_masquerade_store(chan);
-	app_unsubscribe_channel(app, chan);
-	msg = ast_channel_blob_create(chan, end_message_type(), blob);
-	if (msg) {
-		stasis_publish(ast_app_get_topic(app), msg);
-	}
-	ao2_cleanup(msg);
-	ast_json_unref(blob);
-
-	return 0;
-}
-
-static int masq_match_cb(void *obj, void *data, int flags)
-{
-	struct stasis_app_control *control = obj;
-	struct ast_channel *chan = data;
-
-	if (!strcmp(ast_channel_uniqueid(chan),
-		stasis_app_control_get_channel_id(control))) {
-		return CMP_MATCH;
-	}
-
-	return 0;
-}
-
-static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct stasis_app_control *control;
-
-	/* find control */
-	control = ao2_callback(app_controls, 0, masq_match_cb, old_chan);
-	if (!control) {
-		ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
-		return;
-	}
-
-	/* send the StasisEnd message to the app */
-	stasis_app_channel_set_stasis_end_published(new_chan);
-	app_send_end_msg(control_app(control), new_chan);
-
-	/* remove the datastore */
-	remove_masquerade_store(old_chan);
-
-	ao2_cleanup(control);
-}
-
-static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
-	struct stasis_app_control *control;
-
-	/* At this point, new_chan is the channel pointer that is in Stasis() and
-	 * has the unknown channel's name in it while old_chan is the channel pointer
-	 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
-	 * about */
-
-	/* grab a snapshot for the channel that is jumping into Stasis() */
-	new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
-	if (!new_snapshot) {
-		ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
-		return;
-	}
-
-	/* grab a snapshot for the channel that has been kicked out of Stasis() */
-	old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
-	if (!old_snapshot) {
-		ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
-		return;
-	}
-
-	/* find, unlink, and relink control since the channel has a new name and
-	 * its hash has likely changed */
-	control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
-	if (!control) {
-		ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
-		return;
-	}
-	ao2_link(app_controls, control);
-
-
-	/* send the StasisStart with replace_channel to the app */
-	send_start_msg_snapshots(new_chan, control_app(control), 0, NULL, new_snapshot,
-		old_snapshot);
-	/* send the StasisEnd message to the app */
-	app_send_end_msg(control_app(control), old_chan);
-
-	ao2_cleanup(control);
-}
-
-static const struct ast_datastore_info masquerade_store_info = {
-	.type = "stasis-masqerade",
-	.chan_fixup = channel_stolen_cb,
-	.chan_breakdown = channel_replaced_cb,
-};
-
-static int has_masquerade_store(struct ast_channel *chan)
-{
-	SCOPED_CHANNELLOCK(lock, chan);
-	return !!ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
-}
-
-static int add_masquerade_store(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	SCOPED_CHANNELLOCK(lock, chan);
-	if (ast_channel_datastore_find(chan, &masquerade_store_info, NULL)) {
-		return 0;
-	}
-
-	datastore = ast_datastore_alloc(&masquerade_store_info, NULL);
-	if (!datastore) {
-		return -1;
-	}
-
-	ast_channel_datastore_add(chan, datastore);
-
-	return 0;
-}
-
-static void remove_masquerade_store(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	SCOPED_CHANNELLOCK(lock, chan);
-	datastore = ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
-	if (!datastore) {
-		return;
-	}
-
-	ast_channel_datastore_remove(chan, datastore);
-	ast_datastore_free(datastore);
-}
-
-void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
-{
-	while (!control_is_done(control)) {
-		int command_count;
-		command_count = control_dispatch_all(control, chan);
-
-		ao2_lock(control);
-
-		if (control_command_count(control)) {
-			/* If the command queue isn't empty, something added to the queue before it was locked. */
-			ao2_unlock(control);
-			continue;
-		}
-
-		if (command_count == 0 || ast_channel_fdno(chan) == -1) {
-			control_mark_done(control);
-			ao2_unlock(control);
-			break;
-		}
-		ao2_unlock(control);
-	}
-}
-
-int stasis_app_control_is_done(struct stasis_app_control *control)
-{
-	return control_is_done(control);
-}
-
-struct ast_datastore_info set_end_published_info = {
-	.type = "stasis_end_published",
-};
-
-void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	datastore = ast_datastore_alloc(&set_end_published_info, NULL);
-
-	ast_channel_lock(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_channel_unlock(chan);
-}
-
-int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
-	ast_channel_unlock(chan);
-
-	return datastore ? 1 : 0;
-}
-
-static void remove_stasis_end_published(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL);
-	ast_channel_unlock(chan);
-
-	if (datastore) {
-		ast_channel_datastore_remove(chan, datastore);
-		ast_datastore_free(datastore);
-	}
-}
-
-/*! /brief Stasis dialplan application callback */
-int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
-		    char *argv[])
-{
-	SCOPED_MODULE_USE(ast_module_info->self);
-
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
-	struct ast_bridge *bridge = NULL;
-	int res = 0;
-	int needs_depart;
-
-	ast_assert(chan != NULL);
-
-	/* Just in case there's a lingering indication that the channel has had a stasis
-	 * end published on it, remove that now.
-	 */
-	remove_stasis_end_published(chan);
-
-	if (!apps_registry) {
-		return -1;
-	}
-
-	app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
-	if (!app) {
-		ast_log(LOG_ERROR,
-			"Stasis app '%s' not registered\n", app_name);
-		return -1;
-	}
-	if (!app_is_active(app)) {
-		ast_log(LOG_ERROR,
-			"Stasis app '%s' not active\n", app_name);
-		return -1;
-	}
-
-	control = control_create(chan, app);
-	if (!control) {
-		ast_log(LOG_ERROR, "Allocated failed\n");
-		return -1;
-	}
-	ao2_link(app_controls, control);
-
-	if (add_masquerade_store(chan)) {
-		ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
-		return -1;
-	}
-
-	res = send_start_msg(app, chan, argc, argv);
-	if (res != 0) {
-		ast_log(LOG_ERROR,
-			"Error sending start message to '%s'\n", app_name);
-		remove_masquerade_store(chan);
-		return -1;
-	}
-
-	/* Pull queued prestart commands and execute */
-	control_prestart_dispatch_all(control, chan);
-
-	while (!control_is_done(control)) {
-		RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
-		int r;
-		int command_count;
-		RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
-
-		/* Check to see if a bridge absorbed our hangup frame */
-		if (ast_check_hangup_locked(chan)) {
-			break;
-		}
-
-		last_bridge = bridge;
-		bridge = ao2_bump(stasis_app_get_bridge(control));
-
-		if (bridge != last_bridge) {
-			app_unsubscribe_bridge(app, last_bridge);
-			app_subscribe_bridge(app, bridge);
-		}
-
-		if (bridge) {
-			/* Bridge is handling channel frames */
-			control_wait(control);
-			control_dispatch_all(control, chan);
-			continue;
-		}
-
-		r = ast_waitfor(chan, MAX_WAIT_MS);
-
-		if (r < 0) {
-			ast_debug(3, "%s: Poll error\n",
-				  ast_channel_uniqueid(chan));
-			break;
-		}
-
-		command_count = control_dispatch_all(control, chan);
-
-		if (command_count > 0 && ast_channel_fdno(chan) == -1) {
-			/* Command drained the channel; wait for next frame */
-			continue;
-		}
-
-		if (r == 0) {
-			/* Timeout */
-			continue;
-		}
-
-		f = ast_read(chan);
-		if (!f) {
-			/* Continue on in the dialplan */
-			ast_debug(3, "%s: Hangup (no more frames)\n",
-				ast_channel_uniqueid(chan));
-			break;
-		}
-
-		if (f->frametype == AST_FRAME_CONTROL) {
-			if (f->subclass.integer == AST_CONTROL_HANGUP) {
-				/* Continue on in the dialplan */
-				ast_debug(3, "%s: Hangup\n",
-					ast_channel_uniqueid(chan));
-				break;
-			}
-		}
-	}
-
-	ast_channel_lock(chan);
-	needs_depart = ast_channel_is_bridged(chan);
-	ast_channel_unlock(chan);
-	if (needs_depart) {
-		ast_bridge_depart(chan);
-	}
-
-	app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
-	ao2_cleanup(bridge);
-
-	/* Only publish a stasis_end event if it hasn't already been published */
-	if (!stasis_app_channel_is_stasis_end_published(chan)) {
-		/* A masquerade has occurred and this message will be wrong so it
-		 * has already been sent elsewhere. */
-		res = has_masquerade_store(chan) && app_send_end_msg(app, chan);
-		if (res != 0) {
-			ast_log(LOG_ERROR,
-				"Error sending end message to %s\n", app_name);
-			return res;
-		}
-	} else {
-		remove_stasis_end_published(chan);
-	}
-
-	/* There's an off chance that app is ready for cleanup. Go ahead
-	 * and clean up, just in case
-	 */
-	cleanup();
-
-	/* The control needs to be removed from the controls container in
-	 * case a new PBX is started and ends up coming back into Stasis.
-	 */
-	ao2_cleanup(app);
-	app = NULL;
-	control_unlink(control);
-	control = NULL;
-
-	if (!ast_check_hangup_locked(chan) && !ast_channel_pbx(chan)) {
-		struct ast_pbx_args pbx_args;
-
-		memset(&pbx_args, 0, sizeof(pbx_args));
-		pbx_args.no_hangup_chan = 1;
-
-		res = ast_pbx_run_args(chan, &pbx_args);
-	}
-
-	return res;
-}
-
-int stasis_app_send(const char *app_name, struct ast_json *message)
-{
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-
-	if (!apps_registry) {
-		return -1;
-	}
-
-	app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
-	if (!app) {
-		/* XXX We can do a better job handling late binding, queueing up
-		 * the call for a few seconds to wait for the app to register.
-		 */
-		ast_log(LOG_WARNING,
-			"Stasis app '%s' not registered\n", app_name);
-		return -1;
-	}
-	app_send(app, message);
-	return 0;
-}
-
-static struct stasis_app *find_app_by_name(const char *app_name)
-{
-	struct stasis_app *res = NULL;
-
-	if (!apps_registry) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(app_name)) {
-		res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
-	}
-
-	if (!res) {
-		ast_log(LOG_WARNING, "Could not find app '%s'\n",
-			app_name ? : "(null)");
-	}
-	return res;
-}
-
-static int append_name(void *obj, void *arg, int flags)
-{
-	struct stasis_app *app = obj;
-	struct ao2_container *apps = arg;
-
-	ast_str_container_add(apps, stasis_app_name(app));
-	return 0;
-}
-
-struct ao2_container *stasis_app_get_all(void)
-{
-	RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup);
-
-	if (!apps_registry) {
-		return NULL;
-	}
-
-	apps = ast_str_container_alloc(1);
-	if (!apps) {
-		return NULL;
-	}
-
-	ao2_callback(apps_registry, OBJ_NODATA, append_name, apps);
-
-	return ao2_bump(apps);
-}
-
-int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
-{
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-
-	if (!apps_registry) {
-		return -1;
-	}
-
-	ao2_lock(apps_registry);
-	app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-	if (app) {
-		app_update(app, handler, data);
-	} else {
-		app = app_create(app_name, handler, data);
-		if (app) {
-			ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
-		} else {
-			ao2_unlock(apps_registry);
-			return -1;
-		}
-	}
-
-	/* We lazily clean up the apps_registry, because it's good enough to
-	 * prevent memory leaks, and we're lazy.
-	 */
-	cleanup();
-	ao2_unlock(apps_registry);
-	return 0;
-}
-
-void stasis_app_unregister(const char *app_name)
-{
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-
-	if (!app_name) {
-		return;
-	}
-
-	if (!apps_registry) {
-		return;
-	}
-
-	app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
-	if (!app) {
-		ast_log(LOG_ERROR,
-			"Stasis app '%s' not registered\n", app_name);
-		return;
-	}
-
-	app_deactivate(app);
-
-	/* There's a decent chance that app is ready for cleanup. Go ahead
-	 * and clean up, just in case
-	 */
-	cleanup();
-}
-
-/*!
- * \internal \brief List of registered event sources.
- */
-AST_RWLIST_HEAD_STATIC(event_sources, stasis_app_event_source);
-
-void stasis_app_register_event_source(struct stasis_app_event_source *obj)
-{
-	SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_LIST_INSERT_TAIL(&event_sources, obj, next);
-	/* only need to bump the module ref on non-core sources because the
-	   core ones are [un]registered by this module. */
-	if (!stasis_app_is_core_event_source(obj)) {
-		ast_module_ref(ast_module_info->self);
-	}
-}
-
-void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
-{
-	struct stasis_app_event_source *source;
-	SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&event_sources, source, next) {
-		if (source == obj) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			if (!stasis_app_is_core_event_source(obj)) {
-				ast_module_unref(ast_module_info->self);
-			}
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-/*!
- * \internal
- * \brief Convert event source data to JSON.
- *
- * Calls each event source that has a "to_json" handler allowing each
- * source to add data to the given JSON object.
- *
- * \param app application associated with the event source
- * \param json a json object to "fill"
- *
- * \retval The given json object.
- */
-static struct ast_json *app_event_sources_to_json(
-	const struct stasis_app *app, struct ast_json *json)
-{
-	struct stasis_app_event_source *source;
-	SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	AST_LIST_TRAVERSE(&event_sources, source, next) {
-		if (source->to_json) {
-			source->to_json(app, json);
-		}
-	}
-	return json;
-}
-
-static struct ast_json *stasis_app_object_to_json(struct stasis_app *app)
-{
-	if (!app) {
-		return NULL;
-	}
-
-	return app_event_sources_to_json(app, app_to_json(app));
-}
-
-struct ast_json *stasis_app_to_json(const char *app_name)
-{
-	RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
-
-	return stasis_app_object_to_json(app);
-}
-
-/*!
- * \internal
- * \brief Finds an event source that matches a uri scheme.
- *
- * Uri(s) should begin with a particular scheme that can be matched
- * against an event source.
- *
- * \param uri uri containing a scheme to match
- *
- * \retval an event source if found, NULL otherwise.
- */
-static struct stasis_app_event_source *app_event_source_find(const char *uri)
-{
-	struct stasis_app_event_source *source;
-	SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	AST_LIST_TRAVERSE(&event_sources, source, next) {
-		if (ast_begins_with(uri, source->scheme)) {
-			return source;
-		}
-	}
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Callback for subscription handling
- *
- * \param app [un]subscribing application
- * \param uri scheme:id of an event source
- * \param event_source being [un]subscribed [from]to
- *
- * \retval stasis_app_subscribe_res return code.
- */
-typedef enum stasis_app_subscribe_res (*app_subscription_handler)(
-	struct stasis_app *app, const char *uri,
-	struct stasis_app_event_source *event_source);
-
-/*!
- * \internal
- * \brief Subscriptions handler for application [un]subscribing.
- *
- * \param app_name Name of the application to subscribe.
- * \param event_source_uris URIs for the event sources to subscribe to.
- * \param event_sources_count Array size of event_source_uris.
- * \param json Optional output pointer for JSON representation of the app
- *             after adding the subscription.
- * \param handler [un]subscribe handler
- *
- * \retval stasis_app_subscribe_res return code.
- */
-static enum stasis_app_subscribe_res app_handle_subscriptions(
-	const char *app_name, const char **event_source_uris,
-	int event_sources_count, struct ast_json **json,
-	app_subscription_handler handler)
-{
-	RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
-	int i;
-
-	if (!app) {
-		return STASIS_ASR_APP_NOT_FOUND;
-	}
-
-	for (i = 0; i < event_sources_count; ++i) {
-		const char *uri = event_source_uris[i];
-		enum stasis_app_subscribe_res res = STASIS_ASR_INTERNAL_ERROR;
-		struct stasis_app_event_source *event_source;
-
-		if (!(event_source = app_event_source_find(uri))) {
-			ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
-			return STASIS_ASR_EVENT_SOURCE_BAD_SCHEME;
-		}
-
-		if (handler &&
-		    ((res = handler(app, uri, event_source)))) {
-			return res;
-		}
-	}
-
-	if (json) {
-		ast_debug(3, "%s: Successful; setting results\n", app_name);
-		*json = stasis_app_object_to_json(app);
-	}
-
-	return STASIS_ASR_OK;
-}
-
-enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name,
-	struct ast_channel *chan)
-{
-	RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
-	int res;
-
-	if (!app) {
-		return STASIS_ASR_APP_NOT_FOUND;
-	}
-
-	ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan));
-
-	res = app_subscribe_channel(app, chan);
-	if (res != 0) {
-		ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
-			app_name, ast_channel_uniqueid(chan));
-		return STASIS_ASR_INTERNAL_ERROR;
-	}
-
-	return STASIS_ASR_OK;
-}
-
-
-/*!
- * \internal
- * \brief Subscribe an app to an event source.
- *
- * \param app subscribing application
- * \param uri scheme:id of an event source
- * \param event_source being subscribed to
- *
- * \retval stasis_app_subscribe_res return code.
- */
-static enum stasis_app_subscribe_res app_subscribe(
-	struct stasis_app *app, const char *uri,
-	struct stasis_app_event_source *event_source)
-{
-	const char *app_name = stasis_app_name(app);
-	RAII_VAR(void *, obj, NULL, ao2_cleanup);
-
-	ast_debug(3, "%s: Checking %s\n", app_name, uri);
-
-	if (!event_source->find ||
-	    (!(obj = event_source->find(app, uri + strlen(event_source->scheme))))) {
-		ast_log(LOG_WARNING, "Event source not found: %s\n", uri);
-		return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
-	}
-
-	ast_debug(3, "%s: Subscribing to %s\n", app_name, uri);
-
-	if (!event_source->subscribe || (event_source->subscribe(app, obj))) {
-		ast_log(LOG_WARNING, "Error subscribing app '%s' to '%s'\n",
-			app_name, uri);
-		return STASIS_ASR_INTERNAL_ERROR;
-	}
-
-	return STASIS_ASR_OK;
-}
-
-enum stasis_app_subscribe_res stasis_app_subscribe(const char *app_name,
-	const char **event_source_uris, int event_sources_count,
-	struct ast_json **json)
-{
-	return app_handle_subscriptions(
-		app_name, event_source_uris, event_sources_count,
-		json, app_subscribe);
-}
-
-/*!
- * \internal
- * \brief Unsubscribe an app from an event source.
- *
- * \param app application to unsubscribe
- * \param uri scheme:id of an event source
- * \param event_source being unsubscribed from
- *
- * \retval stasis_app_subscribe_res return code.
- */
-static enum stasis_app_subscribe_res app_unsubscribe(
-	struct stasis_app *app, const char *uri,
-	struct stasis_app_event_source *event_source)
-{
-	const char *app_name = stasis_app_name(app);
-	const char *id = uri + strlen(event_source->scheme);
-
-	if (!event_source->is_subscribed ||
-	    (!event_source->is_subscribed(app, id))) {
-		return STASIS_ASR_EVENT_SOURCE_NOT_FOUND;
-	}
-
-	ast_debug(3, "%s: Unsubscribing from %s\n", app_name, uri);
-
-	if (!event_source->unsubscribe || (event_source->unsubscribe(app, id))) {
-		ast_log(LOG_WARNING, "Error unsubscribing app '%s' to '%s'\n",
-			app_name, uri);
-		return -1;
-	}
-	return 0;
-}
-
-enum stasis_app_subscribe_res stasis_app_unsubscribe(const char *app_name,
-	const char **event_source_uris, int event_sources_count,
-	struct ast_json **json)
-{
-	return app_handle_subscriptions(
-		app_name, event_source_uris, event_sources_count,
-		json, app_unsubscribe);
-}
-
-enum stasis_app_user_event_res stasis_app_user_event(const char *app_name,
-	const char *event_name,
-	const char **source_uris, int sources_count,
-	struct ast_json *json_variables)
-{
-	RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup);
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup);
-	RAII_VAR(void *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	enum stasis_app_subscribe_res res = STASIS_APP_USER_INTERNAL_ERROR;
-	struct ast_json *json_value;
-	int have_channel = 0;
-	int i;
-
-	if (!app) {
-		ast_log(LOG_WARNING, "App %s not found\n", app_name);
-		return STASIS_APP_USER_APP_NOT_FOUND;
-	}
-
-	if (!ast_multi_user_event_type()) {
-		return res;
-	}
-
-	blob = json_variables;
-	if (!blob) {
-		blob = ast_json_pack("{}");
-	}
-	json_value = ast_json_string_create(event_name);
-	if (!json_value) {
-		ast_log(LOG_ERROR, "unable to create json string\n");
-		return res;
-	}
-	if (ast_json_object_set(blob, "eventname", json_value)) {
-		ast_log(LOG_ERROR, "unable to set eventname to blob\n");
-		return res;
-	}
-
-	multi = ast_multi_object_blob_create(blob);
-
-	for (i = 0; i < sources_count; ++i) {
-		const char *uri = source_uris[i];
-		void *snapshot=NULL;
-		enum stasis_user_multi_object_snapshot_type type;
-
-		if (ast_begins_with(uri, "channel:")) {
-			type = STASIS_UMOS_CHANNEL;
-			snapshot = ast_channel_snapshot_get_latest(uri + 8);
-			have_channel = 1;
-		} else if (ast_begins_with(uri, "bridge:")) {
-			type = STASIS_UMOS_BRIDGE;
-			snapshot = ast_bridge_snapshot_get_latest(uri + 7);
-		} else if (ast_begins_with(uri, "endpoint:")) {
-			type = STASIS_UMOS_ENDPOINT;
-			snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);
-		} else {
-			ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri);
-			return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME;
-		}
-		if (!snapshot) {
-			ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri);
-			return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND;
-		}
-		ast_multi_object_blob_add(multi, type, snapshot);
-	}
-
-	message = stasis_message_create(ast_multi_user_event_type(), multi);
-	if (!message) {
-		ast_log(LOG_ERROR, "Unable to create stasis user event message\n");
-		return res;
-	}
-
-	/*
-	 * Publishing to two different topics is normally to be avoided -- except
-	 * in this case both are final destinations with no forwards (only listeners).
-	 * The message has to be delivered to the application topic for ARI, but a
-	 * copy is also delivered directly to the manager for AMI if there is a channel.
-	 */
-	stasis_publish(ast_app_get_topic(app), message);
-
-	if (have_channel) {
-		stasis_publish(ast_manager_get_topic(), message);
-	}
-
-	return STASIS_APP_USER_OK;
-}
-
-void stasis_app_ref(void)
-{
-	ast_module_ref(ast_module_info->self);
-}
-
-void stasis_app_unref(void)
-{
-	ast_module_unref(ast_module_info->self);
-}
-
-static int unload_module(void)
-{
-	stasis_app_unregister_event_sources();
-
-	messaging_cleanup();
-
-	cleanup();
-	ao2_cleanup(apps_registry);
-	apps_registry = NULL;
-
-	ao2_cleanup(app_controls);
-	app_controls = NULL;
-
-	ao2_cleanup(app_bridges);
-	app_bridges = NULL;
-
-	ao2_cleanup(app_bridges_moh);
-	app_bridges_moh = NULL;
-
-	ao2_cleanup(app_bridges_playback);
-	app_bridges_playback = NULL;
-
-	STASIS_MESSAGE_TYPE_CLEANUP(end_message_type);
-	STASIS_MESSAGE_TYPE_CLEANUP(start_message_type);
-
-	return 0;
-}
-
-/* \brief Sanitization callback for channel snapshots */
-static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
-{
-	if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) {
-		return 0;
-	}
-	return 1;
-}
-
-/* \brief Sanitization callback for channels */
-static int channel_sanitizer(const struct ast_channel *chan)
-{
-	if (!chan || !(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)) {
-		return 0;
-	}
-	return 1;
-}
-
-/* \brief Sanitization callback for channel unique IDs */
-static int channel_id_sanitizer(const char *id)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_get_latest(id), ao2_cleanup);
-
-	return channel_snapshot_sanitizer(snapshot);
-}
-
-/* \brief Sanitization callbacks for communication to Stasis applications */
-struct stasis_message_sanitizer app_sanitizer = {
-	.channel_id = channel_id_sanitizer,
-	.channel_snapshot = channel_snapshot_sanitizer,
-	.channel = channel_sanitizer,
-};
-
-struct stasis_message_sanitizer *stasis_app_get_sanitizer(void)
-{
-	return &app_sanitizer;
-}
-
-static const struct ast_datastore_info stasis_internal_channel_info = {
-	.type = "stasis-internal-channel",
-};
-
-static int set_internal_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-
-	datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
-	if (!datastore) {
-		datastore = ast_datastore_alloc(&stasis_internal_channel_info, NULL);
-		if (!datastore) {
-			return -1;
-		}
-		ast_channel_datastore_add(chan, datastore);
-	}
-	return 0;
-}
-
-int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
-{
-	struct ast_channel *outchan = NULL, *outowner = NULL;
-	int res = 0;
-	struct ast_unreal_pvt *unreal_pvt = ast_channel_tech_pvt(chan);
-
-	ao2_ref(unreal_pvt, +1);
-	ast_unreal_lock_all(unreal_pvt, &outowner, &outchan);
-	if (outowner) {
-		res |= set_internal_datastore(outowner);
-		ast_channel_unlock(outowner);
-		ast_channel_unref(outowner);
-	}
-	if (outchan) {
-		res |= set_internal_datastore(outchan);
-		ast_channel_unlock(outchan);
-		ast_channel_unref(outchan);
-	}
-	ao2_unlock(unreal_pvt);
-	ao2_ref(unreal_pvt, -1);
-	return res;
-}
-
-int stasis_app_channel_set_internal(struct ast_channel *chan)
-{
-	int res;
-
-	ast_channel_lock(chan);
-	res = set_internal_datastore(chan);
-	ast_channel_unlock(chan);
-
-	return res;
-}
-
-int stasis_app_channel_is_internal(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore;
-	int res = 0;
-
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &stasis_internal_channel_info, NULL);
-	if (datastore) {
-		res = 1;
-	}
-	ast_channel_unlock(chan);
-
-	return res;
-}
-
-static int load_module(void)
-{
-	if (STASIS_MESSAGE_TYPE_INIT(start_message_type) != 0) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	if (STASIS_MESSAGE_TYPE_INIT(end_message_type) != 0) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-	apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash, app_compare);
-	app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash, control_compare);
-	app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash, bridges_compare);
-	app_bridges_moh = ao2_container_alloc_hash(
-		AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-		37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
-	app_bridges_playback = ao2_container_alloc_hash(
-		AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-		37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
-	if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (messaging_init()) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	bridge_stasis_init();
-
-	stasis_app_register_event_sources();
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	);
diff --git a/res/res_stasis.exports.in b/res/res_stasis.exports.in
deleted file mode 100644
index 0ad493c..0000000
--- a/res/res_stasis.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_*;
-	local:
-		*;
-};
diff --git a/res/res_stasis_answer.c b/res/res_stasis_answer.c
deleted file mode 100644
index ccaab2a..0000000
--- a/res/res_stasis_answer.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application control support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421880 $")
-
-#include "asterisk/module.h"
-#include "asterisk/stasis_app_impl.h"
-
-static int app_control_answer(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_debug(3, "%s: Answering\n",
-		stasis_app_control_get_channel_id(control));
-	return ast_raw_answer(chan);
-}
-
-int stasis_app_control_answer(struct stasis_app_control *control)
-{
-	int retval;
-
-	ast_debug(3, "%s: Sending answer command\n",
-		stasis_app_control_get_channel_id(control));
-
-	retval = stasis_app_send_command(control, app_control_answer, NULL, NULL);
-
-	if (retval != 0) {
-		ast_log(LOG_WARNING, "%s: Failed to answer channel\n",
-			stasis_app_control_get_channel_id(control));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application answer support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis");
diff --git a/res/res_stasis_answer.exports.in b/res/res_stasis_answer.exports.in
deleted file mode 100644
index dee153c..0000000
--- a/res/res_stasis_answer.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_control_answer;
-	local:
-		*;
-};
diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c
deleted file mode 100644
index bc56232..0000000
--- a/res/res_stasis_device_state.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
-
-#include "asterisk/astdb.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_app_device_state.h"
-
-#define DEVICE_STATE_SIZE 64
-/*! astdb family name */
-#define DEVICE_STATE_FAMILY "StasisDeviceState"
-/*! Stasis device state provider */
-#define DEVICE_STATE_PROVIDER_STASIS "Stasis"
-/*! Scheme for custom device states */
-#define DEVICE_STATE_SCHEME_STASIS "Stasis:"
-/*! Scheme for device state subscriptions */
-#define DEVICE_STATE_SCHEME_SUB "deviceState:"
-
-/*! Number of hash buckets for device state subscriptions */
-#define DEVICE_STATE_BUCKETS 37
-
-/*! Container for subscribed device states */
-static struct ao2_container *device_state_subscriptions;
-
-/*!
- * \brief Device state subscription object.
- */
-struct device_state_subscription {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(app_name);
-		AST_STRING_FIELD(device_name);
-	);
-	/*! The subscription object */
-	struct stasis_subscription *sub;
-};
-
-static int device_state_subscriptions_hash(const void *obj, const int flags)
-{
-	const struct device_state_subscription *object;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		object = obj;
-		return ast_str_hash(object->device_name);
-	case OBJ_SEARCH_KEY:
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-}
-
-static int device_state_subscriptions_cmp(void *obj, void *arg, int flags)
-{
-	const struct device_state_subscription *object_left = obj;
-	const struct device_state_subscription *object_right = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		/* find objects matching both device and app names */
-		if (strcmp(object_left->device_name,
-			   object_right->device_name)) {
-			return 0;
-		}
-		cmp = strcmp(object_left->app_name, object_right->app_name);
-		break;
-	case OBJ_SEARCH_KEY:
-	case OBJ_SEARCH_PARTIAL_KEY:
-		ast_assert(0); /* not supported by container */
-		/* fall through */
-	default:
-		cmp = 0;
-		break;
-	}
-
-	return cmp ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-static void device_state_subscription_destroy(void *obj)
-{
-	struct device_state_subscription *sub = obj;
-	sub->sub = stasis_unsubscribe(sub->sub);
-	ast_string_field_free_memory(sub);
-}
-
-static struct device_state_subscription *device_state_subscription_create(
-	const struct stasis_app *app, const char *device_name)
-{
-	struct device_state_subscription *sub = ao2_alloc(
-		sizeof(*sub), device_state_subscription_destroy);
-	const char *app_name = stasis_app_name(app);
-	size_t size = strlen(device_name) + strlen(app_name) + 2;
-
-	if (!sub) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(sub, size)) {
-		ao2_ref(sub, -1);
-		return NULL;
-	}
-
-	ast_string_field_set(sub, app_name, app_name);
-	ast_string_field_set(sub, device_name, device_name);
-	return sub;
-}
-
-static struct device_state_subscription *find_device_state_subscription(
-	struct stasis_app *app, const char *name)
-{
-	struct device_state_subscription dummy_sub = {
-		.app_name = stasis_app_name(app),
-		.device_name = name
-	};
-
-	return ao2_find(device_state_subscriptions, &dummy_sub, OBJ_SEARCH_OBJECT);
-}
-
-static void remove_device_state_subscription(
-	struct device_state_subscription *sub)
-{
-	ao2_unlink(device_state_subscriptions, sub);
-}
-
-struct ast_json *stasis_app_device_state_to_json(
-	const char *name, enum ast_device_state state)
-{
-	return ast_json_pack("{s: s, s: s}",
-			     "name", name,
-			     "state", ast_devstate_str(state));
-}
-
-struct ast_json *stasis_app_device_states_to_json(void)
-{
-	struct ast_json *array = ast_json_array_create();
-	RAII_VAR(struct ast_db_entry *, tree,
-		 ast_db_gettree(DEVICE_STATE_FAMILY, NULL), ast_db_freetree);
-	struct ast_db_entry *entry;
-
-	for (entry = tree; entry; entry = entry->next) {
-		const char *name = strrchr(entry->key, '/');
-		if (!ast_strlen_zero(name)) {
-			struct ast_str *device = ast_str_alloca(DEVICE_STATE_SIZE);
-			ast_str_set(&device, 0, "%s%s",
-				    DEVICE_STATE_SCHEME_STASIS, ++name);
-			ast_json_array_append(
-				array, stasis_app_device_state_to_json(
-					ast_str_buffer(device),
-					ast_device_state(ast_str_buffer(device))));
-		}
-	}
-
-	return array;
-}
-
-static void send_device_state(struct device_state_subscription *sub,
-			      const char *name, enum ast_device_state state)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	json = ast_json_pack("{s:s, s:s, s:o, s:o}",
-			     "type", "DeviceStateChanged",
-			     "application", sub->app_name,
-			     "timestamp", ast_json_timeval(ast_tvnow(), NULL),
-			     "device_state", stasis_app_device_state_to_json(
-				     name, state));
-
-	if (!json) {
-		ast_log(LOG_ERROR, "Unable to create device state json object\n");
-		return;
-	}
-
-	stasis_app_send(sub->app_name, json);
-}
-
-enum stasis_device_state_result stasis_app_device_state_update(
-	const char *name, const char *value)
-{
-	size_t size = strlen(DEVICE_STATE_SCHEME_STASIS);
-	enum ast_device_state state;
-
-	ast_debug(3, "Updating device name = %s, value = %s", name, value);
-
-	if (strncasecmp(name, DEVICE_STATE_SCHEME_STASIS, size)) {
-		ast_log(LOG_ERROR, "Update can only be used to set "
-			"'%s' device state!\n", DEVICE_STATE_SCHEME_STASIS);
-		return STASIS_DEVICE_STATE_NOT_CONTROLLED;
-	}
-
-	name += size;
-	if (ast_strlen_zero(name)) {
-		ast_log(LOG_ERROR, "Update requires custom device name!\n");
-		return STASIS_DEVICE_STATE_MISSING;
-	}
-
-	if (!value || (state = ast_devstate_val(value)) == AST_DEVICE_UNKNOWN) {
-		ast_log(LOG_ERROR, "Unknown device state "
-			"value '%s'\n", value);
-		return STASIS_DEVICE_STATE_UNKNOWN;
-	}
-
-	ast_db_put(DEVICE_STATE_FAMILY, name, value);
-	ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "%s%s",
-			     DEVICE_STATE_SCHEME_STASIS, name);
-
-	return STASIS_DEVICE_STATE_OK;
-}
-
-enum stasis_device_state_result stasis_app_device_state_delete(const char *name)
-{
-	const char *full_name = name;
-	size_t size = strlen(DEVICE_STATE_SCHEME_STASIS);
-
-	if (strncasecmp(name, DEVICE_STATE_SCHEME_STASIS, size)) {
-		ast_log(LOG_ERROR, "Can only delete '%s' device states!\n",
-			DEVICE_STATE_SCHEME_STASIS);
-		return STASIS_DEVICE_STATE_NOT_CONTROLLED;
-	}
-
-	name += size;
-	if (ast_strlen_zero(name)) {
-		ast_log(LOG_ERROR, "Delete requires a device name!\n");
-		return STASIS_DEVICE_STATE_MISSING;
-	}
-
-	if (ast_device_state_clear_cache(full_name)) {
-		return STASIS_DEVICE_STATE_UNKNOWN;
-	}
-
-	ast_db_del(DEVICE_STATE_FAMILY, name);
-
-	/* send state change for delete */
-	ast_devstate_changed(
-		AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "%s%s",
-		DEVICE_STATE_SCHEME_STASIS, name);
-
-	return STASIS_DEVICE_STATE_OK;
-}
-
-static void populate_cache(void)
-{
-	RAII_VAR(struct ast_db_entry *, tree,
-		 ast_db_gettree(DEVICE_STATE_FAMILY, NULL), ast_db_freetree);
-	struct ast_db_entry *entry;
-
-	for (entry = tree; entry; entry = entry->next) {
-		const char *name = strrchr(entry->key, '/');
-		if (!ast_strlen_zero(name)) {
-			ast_devstate_changed(
-				ast_devstate_val(entry->data),
-				AST_DEVSTATE_CACHABLE, "%s%s\n",
-				DEVICE_STATE_SCHEME_STASIS, name + 1);
-		}
-	}
-}
-
-static enum ast_device_state stasis_device_state_cb(const char *data)
-{
-	char buf[DEVICE_STATE_SIZE] = "";
-
-	ast_db_get(DEVICE_STATE_FAMILY, data, buf, sizeof(buf));
-
-	return ast_devstate_val(buf);
-}
-
-static void device_state_cb(void *data, struct stasis_subscription *sub,
-			    struct stasis_message *msg)
-{
-	struct ast_device_state_message *device_state;
-
-	if (ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	device_state = stasis_message_data(msg);
-	if (device_state->eid) {
-		/* ignore non-aggregate states */
-		return;
-	}
-
-	send_device_state(data, device_state->device, device_state->state);
-}
-
-static void *find_device_state(const struct stasis_app *app, const char *name)
-{
-	return device_state_subscription_create(app, name);
-}
-
-static int is_subscribed_device_state(struct stasis_app *app, const char *name)
-{
-	RAII_VAR(struct device_state_subscription *, sub,
-		 find_device_state_subscription(app, name), ao2_cleanup);
-	return sub != NULL;
-}
-
-static int subscribe_device_state(struct stasis_app *app, void *obj)
-{
-	struct device_state_subscription *sub = obj;
-
-	ast_debug(3, "Subscribing to device %s", sub->device_name);
-
-	if (is_subscribed_device_state(app, sub->device_name)) {
-		ast_debug(3, "App %s is already subscribed to %s\n", stasis_app_name(app), sub->device_name);
-		return 0;
-	}
-
-	if (!(sub->sub = stasis_subscribe_pool(
-			ast_device_state_topic(sub->device_name),
-			device_state_cb, sub))) {
-		ast_log(LOG_ERROR, "Unable to subscribe to device %s\n",
-			sub->device_name);
-		return -1;
-	}
-
-	ao2_link(device_state_subscriptions, sub);
-	return 0;
-}
-
-static int unsubscribe_device_state(struct stasis_app *app, const char *name)
-{
-	RAII_VAR(struct device_state_subscription *, sub,
-		 find_device_state_subscription(app, name), ao2_cleanup);
-	remove_device_state_subscription(sub);
-	return 0;
-}
-
-static int device_to_json_cb(void *obj, void *arg, void *data, int flags)
-{
-	struct device_state_subscription *sub = obj;
-	const char *app_name = arg;
-	struct ast_json *array = data;
-
-	if (strcmp(sub->app_name, app_name)) {
-		return 0;
-	}
-
-	ast_json_array_append(
-		array, ast_json_string_create(sub->device_name));
-	return 0;
-
-}
-
-static void devices_to_json(const struct stasis_app *app, struct ast_json *json)
-{
-	struct ast_json *array = ast_json_array_create();
-	ao2_callback_data(device_state_subscriptions, OBJ_NODATA,
-			  device_to_json_cb, (void *)stasis_app_name(app), array);
-	ast_json_object_set(json, "device_names", array);
-}
-
-struct stasis_app_event_source device_state_event_source = {
-	.scheme = DEVICE_STATE_SCHEME_SUB,
-	.find = find_device_state,
-	.subscribe = subscribe_device_state,
-	.unsubscribe = unsubscribe_device_state,
-	.is_subscribed = is_subscribed_device_state,
-	.to_json = devices_to_json
-};
-
-static int load_module(void)
-{
-	populate_cache();
-	if (ast_devstate_prov_add(DEVICE_STATE_PROVIDER_STASIS,
-				  stasis_device_state_cb)) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	if (!(device_state_subscriptions = ao2_container_alloc(
-		      DEVICE_STATE_BUCKETS, device_state_subscriptions_hash,
-		      device_state_subscriptions_cmp))) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	stasis_app_register_event_source(&device_state_event_source);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ast_devstate_prov_del(DEVICE_STATE_PROVIDER_STASIS);
-	stasis_app_unregister_event_source(&device_state_event_source);
-	ao2_cleanup(device_state_subscriptions);
-	device_state_subscriptions = NULL;
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application device state support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis");
diff --git a/res/res_stasis_device_state.exports.in b/res/res_stasis_device_state.exports.in
deleted file mode 100644
index 0ad493c..0000000
--- a/res/res_stasis_device_state.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_*;
-	local:
-		*;
-};
diff --git a/res/res_stasis_mailbox.c b/res/res_stasis_mailbox.c
deleted file mode 100644
index 2d53db0..0000000
--- a/res/res_stasis_mailbox.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Jonathan Rose <jrose at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<depend type="module">res_mwi_external</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/astdb.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_app_mailbox.h"
-#include "asterisk/res_mwi_external.h"
-
-/*! Number of hash buckets for mailboxes */
-#define MAILBOX_BUCKETS 37
-
-static struct ast_json *mailbox_to_json(
-	const struct ast_mwi_mailbox_object *mailbox)
-{
-	return ast_json_pack("{s: s, s: i, s: i}",
-		"name", ast_mwi_mailbox_get_id(mailbox),
-		"old_messages", ast_mwi_mailbox_get_msgs_old(mailbox),
-		"new_messages", ast_mwi_mailbox_get_msgs_new(mailbox));
-}
-
-enum stasis_mailbox_result stasis_app_mailbox_to_json(
-	const char *name, struct ast_json **json)
-{
-	struct ast_json *mailbox_json;
-	const struct ast_mwi_mailbox_object *mailbox;
-
-	mailbox = ast_mwi_mailbox_get(name);
-	if (!mailbox) {
-		return STASIS_MAILBOX_MISSING;
-	}
-
-	mailbox_json = mailbox_to_json(mailbox);
-	if (!mailbox_json) {
-		ast_mwi_mailbox_unref(mailbox);
-		return STASIS_MAILBOX_ERROR;
-	}
-
-	*json = mailbox_json;
-
-	return STASIS_MAILBOX_OK;
-}
-
-struct ast_json *stasis_app_mailboxes_to_json()
-{
-	struct ast_json *array = ast_json_array_create();
-	struct ao2_container *mailboxes;
-	struct ao2_iterator iter;
-	const struct ast_mwi_mailbox_object *mailbox;
-
-	if (!array) {
-		return NULL;
-	}
-
-	mailboxes = ast_mwi_mailbox_get_all();
-	if (!mailboxes) {
-		ast_json_unref(array);
-		return NULL;
-	}
-
-	iter = ao2_iterator_init(mailboxes, 0);
-	for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
-		struct ast_json *appending = mailbox_to_json(mailbox);
-		if (!appending || ast_json_array_append(array, appending)) {
-			/* Failed to append individual mailbox to the array. Abort. */
-			ast_json_unref(array);
-			array = NULL;
-			break;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	return array;
-}
-
-int stasis_app_mailbox_update(
-	const char *name, int old_messages, int new_messages)
-{
-	struct ast_mwi_mailbox_object *mailbox;
-	int res = 0;
-
-	mailbox = ast_mwi_mailbox_alloc(name);
-	if (!mailbox) {
-		return -1;
-	}
-	ast_mwi_mailbox_set_msgs_new(mailbox, new_messages);
-	ast_mwi_mailbox_set_msgs_old(mailbox, old_messages);
-	if (ast_mwi_mailbox_update(mailbox)) {
-		res = -1;
-	}
-
-	ast_mwi_mailbox_unref(mailbox);
-
-	return res;
-}
-
-enum stasis_mailbox_result stasis_app_mailbox_delete(
-	const char *name)
-{
-	const struct ast_mwi_mailbox_object *mailbox;
-
-	/* Make sure the mailbox actually exists before we delete it */
-	mailbox = ast_mwi_mailbox_get(name);
-	if (!mailbox) {
-		return STASIS_MAILBOX_MISSING;
-	}
-
-	ast_mwi_mailbox_unref(mailbox);
-	mailbox = NULL;
-
-	/* Now delete the mailbox */
-	if (ast_mwi_mailbox_delete(name)) {
-		return STASIS_MAILBOX_ERROR;
-	}
-
-	return STASIS_MAILBOX_OK;
-}
-
-static int load_module(void)
-{
-	/* Must be done first */
-	ast_mwi_external_ref();
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	/* Must be done last */
-	ast_mwi_external_unref();
-
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application mailbox support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis,res_mwi_external"
-	);
diff --git a/res/res_stasis_mailbox.exports.in b/res/res_stasis_mailbox.exports.in
deleted file mode 100644
index 0ad493c..0000000
--- a/res/res_stasis_mailbox.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_*;
-	local:
-		*;
-};
diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c
deleted file mode 100644
index b6d6f2a..0000000
--- a/res/res_stasis_playback.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief res_stasis playback support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<depend type="module">res_stasis_recording</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421880 $")
-
-#include "asterisk/app.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/file.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/paths.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_app_playback.h"
-#include "asterisk/stasis_app_recording.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/uuid.h"
-#include "asterisk/say.h"
-#include "asterisk/indications.h"
-
-/*! Number of hash buckets for playback container. Keep it prime! */
-#define PLAYBACK_BUCKETS 127
-
-/*! Default number of milliseconds of media to skip */
-#define PLAYBACK_DEFAULT_SKIPMS 3000
-
-#define SOUND_URI_SCHEME "sound:"
-#define RECORDING_URI_SCHEME "recording:"
-#define NUMBER_URI_SCHEME "number:"
-#define DIGITS_URI_SCHEME "digits:"
-#define CHARACTERS_URI_SCHEME "characters:"
-#define TONE_URI_SCHEME "tone:"
-
-/*! Container of all current playbacks */
-static struct ao2_container *playbacks;
-
-/*! Playback control object for res_stasis */
-struct stasis_app_playback {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(id);	/*!< Playback unique id */
-		AST_STRING_FIELD(media);	/*!< Playback media uri */
-		AST_STRING_FIELD(language);	/*!< Preferred language */
-		AST_STRING_FIELD(target);       /*!< Playback device uri */
-		);
-	/*! Control object for the channel we're playing back to */
-	struct stasis_app_control *control;
-	/*! Number of milliseconds to skip before playing */
-	long offsetms;
-	/*! Number of milliseconds to skip for forward/reverse operations */
-	int skipms;
-	/*! Number of milliseconds of media that has been played */
-	long playedms;
-	/*! Current playback state */
-	enum stasis_app_playback_state state;
-	/*! Set when the playback can be controlled */
-	unsigned int controllable:1;
-};
-
-static struct ast_json *playback_to_json(struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_channel_blob *channel_blob = stasis_message_data(message);
-	struct ast_json *blob = channel_blob->blob;
-	const char *state =
-		ast_json_string_get(ast_json_object_get(blob, "state"));
-	const char *type;
-
-	if (!strcmp(state, "playing")) {
-		type = "PlaybackStarted";
-	} else if (!strcmp(state, "done")) {
-		type = "PlaybackFinished";
-	} else {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: O}",
-		"type", type,
-		"playback", blob);
-}
-
-STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type,
-	.to_json = playback_to_json,
-);
-
-static void playback_dtor(void *obj)
-{
-	struct stasis_app_playback *playback = obj;
-
-	ast_string_field_free_memory(playback);
-}
-
-static struct stasis_app_playback *playback_create(
-	struct stasis_app_control *control, const char *id)
-{
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-	char uuid[AST_UUID_STR_LEN];
-
-	if (!control) {
-		return NULL;
-	}
-
-	playback = ao2_alloc(sizeof(*playback), playback_dtor);
-	if (!playback || ast_string_field_init(playback, 128)) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(id)) {
-		ast_string_field_set(playback, id, id);
-	} else {
-		ast_uuid_generate_str(uuid, sizeof(uuid));
-		ast_string_field_set(playback, id, uuid);
-	}
-
-	playback->control = control;
-
-	ao2_ref(playback, +1);
-	return playback;
-}
-
-static int playback_hash(const void *obj, int flags)
-{
-	const struct stasis_app_playback *playback = obj;
-	const char *id = flags & OBJ_KEY ? obj : playback->id;
-	return ast_str_hash(id);
-}
-
-static int playback_cmp(void *obj, void *arg, int flags)
-{
-	struct stasis_app_playback *lhs = obj;
-	struct stasis_app_playback *rhs = arg;
-	const char *rhs_id = flags & OBJ_KEY ? arg : rhs->id;
-
-	if (strcmp(lhs->id, rhs_id) == 0) {
-		return CMP_MATCH | CMP_STOP;
-	} else {
-		return 0;
-	}
-}
-
-static const char *state_to_string(enum stasis_app_playback_state state)
-{
-	switch (state) {
-	case STASIS_PLAYBACK_STATE_QUEUED:
-		return "queued";
-	case STASIS_PLAYBACK_STATE_PLAYING:
-		return "playing";
-	case STASIS_PLAYBACK_STATE_PAUSED:
-		return "paused";
-	case STASIS_PLAYBACK_STATE_STOPPED:
-	case STASIS_PLAYBACK_STATE_COMPLETE:
-	case STASIS_PLAYBACK_STATE_CANCELED:
-		/* It doesn't really matter how we got here, but all of these
-		 * states really just mean 'done' */
-		return "done";
-	case STASIS_PLAYBACK_STATE_MAX:
-		break;
-	}
-
-	return "?";
-}
-
-static void playback_publish(struct stasis_app_playback *playback)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	ast_assert(playback != NULL);
-
-	json = stasis_app_playback_to_json(playback);
-	if (json == NULL) {
-		return;
-	}
-
-	message = ast_channel_blob_create_from_cache(
-		stasis_app_control_get_channel_id(playback->control),
-		stasis_app_playback_snapshot_type(), json);
-	if (message == NULL) {
-		return;
-	}
-
-	stasis_app_control_publish(playback->control, message);
-}
-
-static int playback_first_update(struct stasis_app_playback *playback,
-	const char *uniqueid)
-{
-	int res;
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (playback->state == STASIS_PLAYBACK_STATE_CANCELED) {
-		ast_log(LOG_NOTICE, "%s: Playback canceled for %s\n",
-			uniqueid, playback->media);
-		res = -1;
-	} else {
-		res = 0;
-		playback->state = STASIS_PLAYBACK_STATE_PLAYING;
-	}
-
-	playback_publish(playback);
-	return res;
-}
-
-static void playback_final_update(struct stasis_app_playback *playback,
-	long playedms, int res, const char *uniqueid)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	playback->playedms = playedms;
-	if (res == 0) {
-		playback->state = STASIS_PLAYBACK_STATE_COMPLETE;
-	} else {
-		if (playback->state == STASIS_PLAYBACK_STATE_STOPPED) {
-			ast_log(LOG_NOTICE, "%s: Playback stopped for %s\n",
-				uniqueid, playback->media);
-		} else {
-			ast_log(LOG_WARNING, "%s: Playback failed for %s\n",
-				uniqueid, playback->media);
-			playback->state = STASIS_PLAYBACK_STATE_STOPPED;
-		}
-	}
-
-	playback_publish(playback);
-}
-
-static void play_on_channel(struct stasis_app_playback *playback,
-	struct ast_channel *chan)
-{
-	int res;
-	long offsetms;
-
-	/* Even though these local variables look fairly pointless, the avoid
-	 * having a bunch of NULL's passed directly into
-	 * ast_control_streamfile() */
-	const char *fwd = NULL;
-	const char *rev = NULL;
-	const char *stop = NULL;
-	const char *pause = NULL;
-	const char *restart = NULL;
-
-	ast_assert(playback != NULL);
-
-	offsetms = playback->offsetms;
-
-	res = playback_first_update(playback, ast_channel_uniqueid(chan));
-
-	if (res != 0) {
-		return;
-	}
-
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_indicate(chan, AST_CONTROL_PROGRESS);
-	}
-
-	if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) {
-		playback->controllable = 1;
-
-		/* Play sound */
-		res = ast_control_streamfile_lang(chan, playback->media + strlen(SOUND_URI_SCHEME),
-				fwd, rev, stop, pause, restart, playback->skipms, playback->language,
-				&offsetms);
-	} else if (ast_begins_with(playback->media, RECORDING_URI_SCHEME)) {
-		/* Play recording */
-		RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-			ao2_cleanup);
-		const char *relname =
-			playback->media + strlen(RECORDING_URI_SCHEME);
-		recording = stasis_app_stored_recording_find_by_name(relname);
-
-		if (!recording) {
-			ast_log(LOG_ERROR, "Attempted to play recording '%s' on channel '%s' but recording does not exist",
-				relname, ast_channel_name(chan));
-			return;
-		}
-
-		playback->controllable = 1;
-
-		res = ast_control_streamfile_lang(chan,
-			stasis_app_stored_recording_get_file(recording), fwd, rev, stop, pause,
-			restart, playback->skipms, playback->language, &offsetms);
-	} else if (ast_begins_with(playback->media, NUMBER_URI_SCHEME)) {
-		int number;
-
-		if (sscanf(playback->media + strlen(NUMBER_URI_SCHEME), "%30d", &number) != 1) {
-			ast_log(LOG_ERROR, "Attempted to play number '%s' on channel '%s' but number is invalid",
-				playback->media + strlen(NUMBER_URI_SCHEME), ast_channel_name(chan));
-			return;
-		}
-
-		res = ast_say_number(chan, number, stop, playback->language, NULL);
-	} else if (ast_begins_with(playback->media, DIGITS_URI_SCHEME)) {
-		res = ast_say_digit_str(chan, playback->media + strlen(DIGITS_URI_SCHEME),
-			stop, playback->language);
-	} else if (ast_begins_with(playback->media, CHARACTERS_URI_SCHEME)) {
-		res = ast_say_character_str(chan, playback->media + strlen(CHARACTERS_URI_SCHEME),
-			stop, playback->language, AST_SAY_CASE_NONE);
-	} else if (ast_begins_with(playback->media, TONE_URI_SCHEME)) {
-		playback->controllable = 1;
-		res = ast_control_tone(chan, playback->media + strlen(TONE_URI_SCHEME));
-	} else {
-		/* Play URL */
-		ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported\n",
-			playback->media, ast_channel_name(chan));
-		return;
-	}
-
-	playback_final_update(playback, offsetms, res,
-		ast_channel_uniqueid(chan));
-
-	return;
-}
-
-/*!
- * \brief Special case code to play while a channel is in a bridge.
- *
- * \param bridge_channel The channel's bridge_channel.
- * \param playback_id Id of the playback to start.
- */
-static void play_on_channel_in_bridge(struct ast_bridge_channel *bridge_channel,
-	const char *playback_id)
-{
-	RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
-
-	playback = stasis_app_playback_find_by_id(playback_id);
-	if (!playback) {
-		ast_log(LOG_ERROR, "Couldn't find playback %s\n",
-			playback_id);
-		return;
-	}
-
-	play_on_channel(playback, bridge_channel->chan);
-}
-
-/*!
- * \brief \ref RAII_VAR function to remove a playback from the global list when
- * leaving scope.
- */
-static void remove_from_playbacks(void *data)
-{
-	struct stasis_app_playback *playback = data;
-
-	ao2_unlink_flags(playbacks, playback,
-		OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
-	ao2_ref(playback, -1);
-}
-
-static int play_uri(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_playback *playback = data;
-	struct ast_bridge *bridge;
-
-	if (!control) {
-		return -1;
-	}
-
-	bridge = stasis_app_get_bridge(control);
-	if (bridge) {
-		struct ast_bridge_channel *bridge_chan;
-
-		/* Queue up playback on the bridge */
-		ast_bridge_lock(bridge);
-		bridge_chan = ao2_bump(bridge_find_channel(bridge, chan));
-		ast_bridge_unlock(bridge);
-		if (bridge_chan) {
-			ast_bridge_channel_queue_playfile_sync(
-				bridge_chan,
-				play_on_channel_in_bridge,
-				playback->id,
-				NULL); /* moh_class */
-		}
-		ao2_cleanup(bridge_chan);
-	} else {
-		play_on_channel(playback, chan);
-	}
-
-	return 0;
-}
-
-static void set_target_uri(
-	struct stasis_app_playback *playback,
-	enum stasis_app_playback_target_type target_type,
-	const char *target_id)
-{
-	const char *type = NULL;
-	switch (target_type) {
-	case STASIS_PLAYBACK_TARGET_CHANNEL:
-		type = "channel";
-		break;
-	case STASIS_PLAYBACK_TARGET_BRIDGE:
-		type = "bridge";
-		break;
-	}
-
-	ast_assert(type != NULL);
-
-	ast_string_field_build(playback, target, "%s:%s", type, target_id);
-}
-
-struct stasis_app_playback *stasis_app_control_play_uri(
-	struct stasis_app_control *control, const char *uri,
-	const char *language, const char *target_id,
-	enum stasis_app_playback_target_type target_type,
-	int skipms, long offsetms, const char *id)
-{
-	struct stasis_app_playback *playback;
-
-	if (skipms < 0 || offsetms < 0) {
-		return NULL;
-	}
-
-	ast_debug(3, "%s: Sending play(%s) command\n",
-		stasis_app_control_get_channel_id(control), uri);
-
-	playback = playback_create(control, id);
-	if (!playback) {
-		return NULL;
-	}
-
-	if (skipms == 0) {
-		skipms = PLAYBACK_DEFAULT_SKIPMS;
-	}
-
-	ast_string_field_set(playback, media, uri);
-	ast_string_field_set(playback, language, language);
-	set_target_uri(playback, target_type, target_id);
-	playback->skipms = skipms;
-	playback->offsetms = offsetms;
-	ao2_link(playbacks, playback);
-
-	playback->state = STASIS_PLAYBACK_STATE_QUEUED;
-	playback_publish(playback);
-
-	stasis_app_send_command_async(control, play_uri, ao2_bump(playback), remove_from_playbacks);
-
-	return playback;
-}
-
-enum stasis_app_playback_state stasis_app_playback_get_state(
-	struct stasis_app_playback *control)
-{
-	SCOPED_AO2LOCK(lock, control);
-	return control->state;
-}
-
-const char *stasis_app_playback_get_id(
-	struct stasis_app_playback *control)
-{
-	/* id is immutable; no lock needed */
-	return control->id;
-}
-
-struct stasis_app_playback *stasis_app_playback_find_by_id(const char *id)
-{
-	return ao2_find(playbacks, id, OBJ_KEY);
-}
-
-struct ast_json *stasis_app_playback_to_json(
-	const struct stasis_app_playback *playback)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	if (playback == NULL) {
-		return NULL;
-	}
-
-	json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
-		"id", playback->id,
-		"media_uri", playback->media,
-		"target_uri", playback->target,
-		"language", playback->language,
-		"state", state_to_string(playback->state));
-
-	return ast_json_ref(json);
-}
-
-typedef int (*playback_opreation_cb)(struct stasis_app_playback *playback);
-
-static int playback_noop(struct stasis_app_playback *playback)
-{
-	return 0;
-}
-
-static int playback_cancel(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-	playback->state = STASIS_PLAYBACK_STATE_CANCELED;
-	return 0;
-}
-
-static int playback_stop(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	playback->state = STASIS_PLAYBACK_STATE_STOPPED;
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_STOP);
-}
-
-static int playback_restart(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_RESTART);
-}
-
-static int playback_pause(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	playback->state = STASIS_PLAYBACK_STATE_PAUSED;
-	playback_publish(playback);
-
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_SUSPEND);
-}
-
-static int playback_unpause(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	playback->state = STASIS_PLAYBACK_STATE_PLAYING;
-	playback_publish(playback);
-
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_SUSPEND);
-}
-
-static int playback_reverse(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_REVERSE);
-}
-
-static int playback_forward(struct stasis_app_playback *playback)
-{
-	SCOPED_AO2LOCK(lock, playback);
-
-	if (!playback->controllable) {
-		return -1;
-	}
-
-	return stasis_app_control_queue_control(playback->control,
-		AST_CONTROL_STREAM_FORWARD);
-}
-
-/*!
- * \brief A sparse array detailing how commands should be handled in the
- * various playback states. Unset entries imply invalid operations.
- */
-playback_opreation_cb operations[STASIS_PLAYBACK_STATE_MAX][STASIS_PLAYBACK_MEDIA_OP_MAX] = {
-	[STASIS_PLAYBACK_STATE_QUEUED][STASIS_PLAYBACK_STOP] = playback_cancel,
-	[STASIS_PLAYBACK_STATE_QUEUED][STASIS_PLAYBACK_RESTART] = playback_noop,
-
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_STOP] = playback_stop,
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_RESTART] = playback_restart,
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_PAUSE] = playback_pause,
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_UNPAUSE] = playback_noop,
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_REVERSE] = playback_reverse,
-	[STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_FORWARD] = playback_forward,
-
-	[STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_STOP] = playback_stop,
-	[STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_PAUSE] = playback_noop,
-	[STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_UNPAUSE] = playback_unpause,
-
-	[STASIS_PLAYBACK_STATE_COMPLETE][STASIS_PLAYBACK_STOP] = playback_noop,
-	[STASIS_PLAYBACK_STATE_CANCELED][STASIS_PLAYBACK_STOP] = playback_noop,
-	[STASIS_PLAYBACK_STATE_STOPPED][STASIS_PLAYBACK_STOP] = playback_noop,
-};
-
-enum stasis_playback_oper_results stasis_app_playback_operation(
-	struct stasis_app_playback *playback,
-	enum stasis_app_playback_media_operation operation)
-{
-	playback_opreation_cb cb;
-	SCOPED_AO2LOCK(lock, playback);
-
-	ast_assert(playback->state >= 0 && playback->state < STASIS_PLAYBACK_STATE_MAX);
-
-	if (operation < 0 || operation >= STASIS_PLAYBACK_MEDIA_OP_MAX) {
-		ast_log(LOG_ERROR, "Invalid playback operation %u\n", operation);
-		return -1;
-	}
-
-	cb = operations[playback->state][operation];
-
-	if (!cb) {
-		if (playback->state != STASIS_PLAYBACK_STATE_PLAYING) {
-			/* So we can be specific in our error message. */
-			return STASIS_PLAYBACK_OPER_NOT_PLAYING;
-		} else {
-			/* And, really, all operations should be valid during
-			 * playback */
-			ast_log(LOG_ERROR,
-				"Unhandled operation during playback: %u\n",
-				operation);
-			return STASIS_PLAYBACK_OPER_FAILED;
-		}
-	}
-
-	return cb(playback) ?
-		STASIS_PLAYBACK_OPER_FAILED : STASIS_PLAYBACK_OPER_OK;
-}
-
-static int load_module(void)
-{
-	int r;
-
-	r = STASIS_MESSAGE_TYPE_INIT(stasis_app_playback_snapshot_type);
-	if (r != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	playbacks = ao2_container_alloc(PLAYBACK_BUCKETS, playback_hash,
-		playback_cmp);
-	if (!playbacks) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ao2_cleanup(playbacks);
-	playbacks = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_app_playback_snapshot_type);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application playback support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis,res_stasis_recording");
diff --git a/res/res_stasis_playback.exports.in b/res/res_stasis_playback.exports.in
deleted file mode 100644
index 0ad493c..0000000
--- a/res/res_stasis_playback.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_*;
-	local:
-		*;
-};
diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c
deleted file mode 100644
index ad8158a..0000000
--- a/res/res_stasis_recording.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief res_stasis recording support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421880 $")
-
-#include "asterisk/dsp.h"
-#include "asterisk/file.h"
-#include "asterisk/module.h"
-#include "asterisk/paths.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_app_recording.h"
-#include "asterisk/stasis_channels.h"
-
-/*! Number of hash buckets for recording container. Keep it prime! */
-#define RECORDING_BUCKETS 127
-
-/*! Comment is ignored by most formats, so we will ignore it, too. */
-#define RECORDING_COMMENT NULL
-
-/*! Recording check is unimplemented. le sigh */
-#define RECORDING_CHECK 0
-
-/*! Container of all current recordings */
-static struct ao2_container *recordings;
-
-struct stasis_app_recording {
-	/*! Recording options. */
-	struct stasis_app_recording_options *options;
-	/*! Absolute path (minus extension) of the recording */
-	char *absolute_name;
-	/*! Control object for the channel we're recording */
-	struct stasis_app_control *control;
-	/*! Current state of the recording. */
-	enum stasis_app_recording_state state;
-	/*! Duration calculations */
-	struct {
-		/*! Total duration */
-		int total;
-		/*! Duration minus any silence */
-		int energy_only;
-	} duration;
-	/*! Indicates whether the recording is currently muted */
-	int muted:1;
-};
-
-static struct ast_json *recording_to_json(struct stasis_message *message,
-	const struct stasis_message_sanitizer *sanitize)
-{
-	struct ast_channel_blob *channel_blob = stasis_message_data(message);
-	struct ast_json *blob = channel_blob->blob;
-	const char *state =
-		ast_json_string_get(ast_json_object_get(blob, "state"));
-	const char *type;
-
-	if (!strcmp(state, "recording")) {
-		type = "RecordingStarted";
-	} else if (!strcmp(state, "done") || !strcasecmp(state, "canceled")) {
-		type = "RecordingFinished";
-	} else if (!strcmp(state, "failed")) {
-		type = "RecordingFailed";
-	} else {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: O}",
-		"type", type,
-		"recording", blob);
-}
-
-STASIS_MESSAGE_TYPE_DEFN(stasis_app_recording_snapshot_type,
-	.to_json = recording_to_json,
-);
-
-static int recording_hash(const void *obj, int flags)
-{
-	const struct stasis_app_recording *recording = obj;
-	const char *id = flags & OBJ_KEY ? obj : recording->options->name;
-	return ast_str_hash(id);
-}
-
-static int recording_cmp(void *obj, void *arg, int flags)
-{
-	struct stasis_app_recording *lhs = obj;
-	struct stasis_app_recording *rhs = arg;
-	const char *rhs_id = flags & OBJ_KEY ? arg : rhs->options->name;
-
-	if (strcmp(lhs->options->name, rhs_id) == 0) {
-		return CMP_MATCH | CMP_STOP;
-	} else {
-		return 0;
-	}
-}
-
-static const char *state_to_string(enum stasis_app_recording_state state)
-{
-	switch (state) {
-	case STASIS_APP_RECORDING_STATE_QUEUED:
-		return "queued";
-	case STASIS_APP_RECORDING_STATE_RECORDING:
-		return "recording";
-	case STASIS_APP_RECORDING_STATE_PAUSED:
-		return "paused";
-	case STASIS_APP_RECORDING_STATE_COMPLETE:
-		return "done";
-	case STASIS_APP_RECORDING_STATE_FAILED:
-		return "failed";
-	case STASIS_APP_RECORDING_STATE_CANCELED:
-		return "canceled";
-	case STASIS_APP_RECORDING_STATE_MAX:
-		return "?";
-	}
-
-	return "?";
-}
-
-static void recording_options_dtor(void *obj)
-{
-	struct stasis_app_recording_options *options = obj;
-
-	ast_string_field_free_memory(options);
-}
-
-struct stasis_app_recording_options *stasis_app_recording_options_create(
-	const char *name, const char *format)
-{
-	RAII_VAR(struct stasis_app_recording_options *, options, NULL,
-		ao2_cleanup);
-
-	options = ao2_alloc(sizeof(*options), recording_options_dtor);
-
-	if (!options || ast_string_field_init(options, 128)) {
-		return NULL;
-	}
-	ast_string_field_set(options, name, name);
-	ast_string_field_set(options, format, format);
-
-	ao2_ref(options, +1);
-	return options;
-}
-
-char stasis_app_recording_termination_parse(const char *str)
-{
-	if (ast_strlen_zero(str)) {
-		return STASIS_APP_RECORDING_TERMINATE_NONE;
-	}
-
-	if (strcasecmp(str, "none") == 0) {
-		return STASIS_APP_RECORDING_TERMINATE_NONE;
-	}
-
-	if (strcasecmp(str, "any") == 0) {
-		return STASIS_APP_RECORDING_TERMINATE_ANY;
-	}
-
-	if (strcasecmp(str, "#") == 0) {
-		return '#';
-	}
-
-	if (strcasecmp(str, "*") == 0) {
-		return '*';
-	}
-
-	return STASIS_APP_RECORDING_TERMINATE_INVALID;
-}
-
-enum ast_record_if_exists stasis_app_recording_if_exists_parse(
-	const char *str)
-{
-	if (ast_strlen_zero(str)) {
-		/* Default value */
-		return AST_RECORD_IF_EXISTS_FAIL;
-	}
-
-	if (strcasecmp(str, "fail") == 0) {
-		return AST_RECORD_IF_EXISTS_FAIL;
-	}
-
-	if (strcasecmp(str, "overwrite") == 0) {
-		return AST_RECORD_IF_EXISTS_OVERWRITE;
-	}
-
-	if (strcasecmp(str, "append") == 0) {
-		return AST_RECORD_IF_EXISTS_APPEND;
-	}
-
-	return -1;
-}
-
-static void recording_publish(struct stasis_app_recording *recording, const char *cause)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
-	ast_assert(recording != NULL);
-
-	json = stasis_app_recording_to_json(recording);
-	if (json == NULL) {
-		return;
-	}
-
-	if (!ast_strlen_zero(cause)) {
-		struct ast_json *failure_cause = ast_json_string_create(cause);
-
-		if (!failure_cause) {
-			return;
-		}
-
-		if (ast_json_object_set(json, "cause", failure_cause)) {
-			return;
-		}
-	}
-
-	message = ast_channel_blob_create_from_cache(
-		stasis_app_control_get_channel_id(recording->control),
-		stasis_app_recording_snapshot_type(), json);
-	if (message == NULL) {
-		return;
-	}
-
-	stasis_app_control_publish(recording->control, message);
-}
-
-
-static void recording_set_state(struct stasis_app_recording *recording,
-				enum stasis_app_recording_state state,
-				const char *cause)
-{
-	SCOPED_AO2LOCK(lock, recording);
-	recording->state = state;
-	recording_publish(recording, cause);
-}
-
-static enum stasis_app_control_channel_result check_rule_recording(
-	const struct stasis_app_control *control)
-{
-	return STASIS_APP_CHANNEL_RECORDING;
-}
-
-struct stasis_app_control_rule rule_recording = {
-	.check_rule = check_rule_recording
-};
-
-static void recording_fail(struct stasis_app_control *control,
-			   struct stasis_app_recording *recording,
-			   const char *cause)
-{
-	stasis_app_control_unregister_add_rule(control, &rule_recording);
-
-	recording_set_state(
-		recording, STASIS_APP_RECORDING_STATE_FAILED, cause);
-}
-
-static void recording_cleanup(void *data)
-{
-	struct stasis_app_recording *recording = data;
-
-	ao2_unlink_flags(recordings, recording,
-		OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
-	ao2_ref(recording, -1);
-}
-
-static int record_file(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_recording *recording = data;
-	char *acceptdtmf;
-	int res;
-
-	ast_assert(recording != NULL);
-
-	if (stasis_app_get_bridge(control)) {
-		ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
-		recording_fail(control, recording, "Cannot record channel while in bridge");
-		return -1;
-	}
-
-	switch (recording->options->terminate_on) {
-	case STASIS_APP_RECORDING_TERMINATE_NONE:
-	case STASIS_APP_RECORDING_TERMINATE_INVALID:
-		acceptdtmf = "";
-		break;
-	case STASIS_APP_RECORDING_TERMINATE_ANY:
-		acceptdtmf = "#*0123456789abcd";
-		break;
-	default:
-		acceptdtmf = ast_alloca(2);
-		acceptdtmf[0] = recording->options->terminate_on;
-		acceptdtmf[1] = '\0';
-	}
-
-	res = ast_auto_answer(chan);
-	if (res != 0) {
-		ast_debug(3, "%s: Failed to answer\n",
-			ast_channel_uniqueid(chan));
-		recording_fail(control, recording, "Failed to answer channel");
-		return -1;
-	}
-
-	recording_set_state(
-		recording, STASIS_APP_RECORDING_STATE_RECORDING, NULL);
-	ast_play_and_record_full(chan,
-		NULL, /* playfile */
-		recording->absolute_name,
-		recording->options->max_duration_seconds,
-		recording->options->format,
-		&recording->duration.total,
-		recording->options->max_silence_seconds ? &recording->duration.energy_only : NULL,
-		recording->options->beep,
-		-1, /* silencethreshold */
-		recording->options->max_silence_seconds * 1000,
-		NULL, /* path */
-		acceptdtmf,
-		NULL, /* canceldtmf */
-		1, /* skip_confirmation_sound */
-		recording->options->if_exists);
-
-	ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));
-
-	recording_set_state(
-		recording, STASIS_APP_RECORDING_STATE_COMPLETE, NULL);
-
-	stasis_app_control_unregister_add_rule(control, &rule_recording);
-
-	return 0;
-}
-
-static void recording_dtor(void *obj)
-{
-	struct stasis_app_recording *recording = obj;
-
-	ast_free(recording->absolute_name);
-	ao2_cleanup(recording->options);
-}
-
-struct stasis_app_recording *stasis_app_control_record(
-	struct stasis_app_control *control,
-	struct stasis_app_recording_options *options)
-{
-	struct stasis_app_recording *recording;
-	char *last_slash;
-
-	errno = 0;
-
-	if (options == NULL ||
-		ast_strlen_zero(options->name) ||
-		ast_strlen_zero(options->format) ||
-		options->max_silence_seconds < 0 ||
-		options->max_duration_seconds < 0) {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	ast_debug(3, "%s: Sending record(%s.%s) command\n",
-		stasis_app_control_get_channel_id(control), options->name,
-		options->format);
-
-	recording = ao2_alloc(sizeof(*recording), recording_dtor);
-	if (!recording) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	recording->duration.total = -1;
-	recording->duration.energy_only = -1;
-
-	ast_asprintf(&recording->absolute_name, "%s/%s",
-		ast_config_AST_RECORDING_DIR, options->name);
-
-	if (recording->absolute_name == NULL) {
-		errno = ENOMEM;
-		ao2_ref(recording, -1);
-		return NULL;
-	}
-
-	if ((last_slash = strrchr(recording->absolute_name, '/'))) {
-		*last_slash = '\0';
-		if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
-				recording->absolute_name, 0777) != 0) {
-			/* errno set by ast_mkdir */
-			ao2_ref(recording, -1);
-			return NULL;
-		}
-		*last_slash = '/';
-	}
-
-	ao2_ref(options, +1);
-	recording->options = options;
-	recording->control = control;
-	recording->state = STASIS_APP_RECORDING_STATE_QUEUED;
-
-	if ((recording->options->if_exists == AST_RECORD_IF_EXISTS_FAIL) &&
-			(ast_fileexists(recording->absolute_name, NULL, NULL))) {
-		ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n",
-			recording->absolute_name);
-		errno = EEXIST;
-		ao2_ref(recording, -1);
-		return NULL;
-	}
-
-	{
-		RAII_VAR(struct stasis_app_recording *, old_recording, NULL,
-			ao2_cleanup);
-
-		SCOPED_AO2LOCK(lock, recordings);
-
-		old_recording = ao2_find(recordings, options->name,
-			OBJ_KEY | OBJ_NOLOCK);
-		if (old_recording) {
-			ast_log(LOG_WARNING,
-				"Recording %s already in progress\n",
-				recording->options->name);
-			errno = EEXIST;
-			ao2_ref(recording, -1);
-			return NULL;
-		}
-		ao2_link(recordings, recording);
-	}
-
-	stasis_app_control_register_add_rule(control, &rule_recording);
-
-	stasis_app_send_command_async(control, record_file, ao2_bump(recording), recording_cleanup);
-
-	return recording;
-}
-
-enum stasis_app_recording_state stasis_app_recording_get_state(
-	struct stasis_app_recording *recording)
-{
-	return recording->state;
-}
-
-const char *stasis_app_recording_get_name(
-	struct stasis_app_recording *recording)
-{
-	return recording->options->name;
-}
-
-struct stasis_app_recording *stasis_app_recording_find_by_name(const char *name)
-{
-	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
-
-	recording = ao2_find(recordings, name, OBJ_KEY);
-	if (recording == NULL) {
-		return NULL;
-	}
-
-	ao2_ref(recording, +1);
-	return recording;
-}
-
-struct ast_json *stasis_app_recording_to_json(
-	const struct stasis_app_recording *recording)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	if (recording == NULL) {
-		return NULL;
-	}
-
-	json = ast_json_pack("{s: s, s: s, s: s, s: s}",
-		"name", recording->options->name,
-		"format", recording->options->format,
-		"state", state_to_string(recording->state),
-		"target_uri", recording->options->target);
-	if (json && recording->duration.total > -1) {
-		ast_json_object_set(json, "duration",
-			ast_json_integer_create(recording->duration.total));
-	}
-	if (json && recording->duration.energy_only > -1) {
-		ast_json_object_set(json, "talking_duration",
-			ast_json_integer_create(recording->duration.energy_only));
-		ast_json_object_set(json, "silence_duration",
-			ast_json_integer_create(recording->duration.total - recording->duration.energy_only));
-	}
-
-	return ast_json_ref(json);
-}
-
-typedef int (*recording_operation_cb)(struct stasis_app_recording *recording);
-
-static int recording_noop(struct stasis_app_recording *recording)
-{
-	return 0;
-}
-
-static int recording_disregard(struct stasis_app_recording *recording)
-{
-	recording->state = STASIS_APP_RECORDING_STATE_CANCELED;
-	return 0;
-}
-
-static int recording_cancel(struct stasis_app_recording *recording)
-{
-	int res = 0;
-	recording->state = STASIS_APP_RECORDING_STATE_CANCELED;
-	res |= stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_CANCEL);
-	res |= ast_filedelete(recording->absolute_name, NULL);
-	return res;
-}
-
-static int recording_stop(struct stasis_app_recording *recording)
-{
-	recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
-	return stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_STOP);
-}
-
-static int recording_pause(struct stasis_app_recording *recording)
-{
-	recording->state = STASIS_APP_RECORDING_STATE_PAUSED;
-	return stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_SUSPEND);
-}
-
-static int recording_unpause(struct stasis_app_recording *recording)
-{
-	recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
-	return stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_SUSPEND);
-}
-
-static int recording_mute(struct stasis_app_recording *recording)
-{
-	if (recording->muted) {
-		/* already muted */
-		return 0;
-	}
-
-	recording->muted = 1;
-	return stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_MUTE);
-}
-
-static int recording_unmute(struct stasis_app_recording *recording)
-{
-	if (!recording->muted) {
-		/* already unmuted */
-		return 0;
-	}
-
-	return stasis_app_control_queue_control(recording->control,
-		AST_CONTROL_RECORD_MUTE);
-}
-
-recording_operation_cb operations[STASIS_APP_RECORDING_STATE_MAX][STASIS_APP_RECORDING_OPER_MAX] = {
-	[STASIS_APP_RECORDING_STATE_QUEUED][STASIS_APP_RECORDING_CANCEL] = recording_disregard,
-	[STASIS_APP_RECORDING_STATE_QUEUED][STASIS_APP_RECORDING_STOP] = recording_disregard,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_CANCEL] = recording_cancel,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_STOP] = recording_stop,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_PAUSE] = recording_pause,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_UNPAUSE] = recording_noop,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_MUTE] = recording_mute,
-	[STASIS_APP_RECORDING_STATE_RECORDING][STASIS_APP_RECORDING_UNMUTE] = recording_unmute,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_CANCEL] = recording_cancel,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_STOP] = recording_stop,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_PAUSE] = recording_noop,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_UNPAUSE] = recording_unpause,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_MUTE] = recording_mute,
-	[STASIS_APP_RECORDING_STATE_PAUSED][STASIS_APP_RECORDING_UNMUTE] = recording_unmute,
-};
-
-enum stasis_app_recording_oper_results stasis_app_recording_operation(
-	struct stasis_app_recording *recording,
-	enum stasis_app_recording_media_operation operation)
-{
-	recording_operation_cb cb;
-	SCOPED_AO2LOCK(lock, recording);
-
-	if (recording->state < 0 || recording->state >= STASIS_APP_RECORDING_STATE_MAX) {
-		ast_log(LOG_WARNING, "Invalid recording state %u\n",
-			recording->state);
-		return -1;
-	}
-
-	if (operation < 0 || operation >= STASIS_APP_RECORDING_OPER_MAX) {
-		ast_log(LOG_WARNING, "Invalid recording operation %u\n",
-			operation);
-		return -1;
-	}
-
-	cb = operations[recording->state][operation];
-
-	if (!cb) {
-		if (recording->state != STASIS_APP_RECORDING_STATE_RECORDING) {
-			/* So we can be specific in our error message. */
-			return STASIS_APP_RECORDING_OPER_NOT_RECORDING;
-		} else {
-			/* And, really, all operations should be valid during
-			 * recording */
-			ast_log(LOG_ERROR,
-				"Unhandled operation during recording: %u\n",
-				operation);
-			return STASIS_APP_RECORDING_OPER_FAILED;
-		}
-	}
-
-	return cb(recording) ?
-		STASIS_APP_RECORDING_OPER_FAILED : STASIS_APP_RECORDING_OPER_OK;
-}
-
-static int load_module(void)
-{
-	int r;
-
-	r = STASIS_MESSAGE_TYPE_INIT(stasis_app_recording_snapshot_type);
-	if (r != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	recordings = ao2_container_alloc(RECORDING_BUCKETS, recording_hash,
-		recording_cmp);
-	if (!recordings) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	ao2_cleanup(recordings);
-	recordings = NULL;
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_app_recording_snapshot_type);
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis application recording support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis",
-	.load_pri = AST_MODPRI_APP_DEPEND);
diff --git a/res/res_stasis_recording.exports.in b/res/res_stasis_recording.exports.in
deleted file mode 100644
index 0ad493c..0000000
--- a/res/res_stasis_recording.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_*;
-	local:
-		*;
-};
diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c
deleted file mode 100644
index 4722bb4..0000000
--- a/res/res_stasis_snoop.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application snoop control support.
- *
- * \author Joshua Colp <jcolp at digium.com>
- */
-
-/*** MODULEINFO
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420879 $")
-
-#include "asterisk/module.h"
-#include "asterisk/stasis_app_impl.h"
-#include "asterisk/stasis_app_snoop.h"
-#include "asterisk/audiohook.h"
-#include "asterisk/pbx.h"
-#include "asterisk/timing.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/json.h"
-#include "asterisk/format_cache.h"
-
-/*! \brief The interval (in milliseconds) that the Snoop timer is triggered, also controls length of audio within frames */
-#define SNOOP_INTERVAL 20
-
-/*! \brief Index used to keep Snoop channel names unique */
-static unsigned int chan_idx;
-
-/*! \brief Structure which contains all of the snoop information */
-struct stasis_app_snoop {
-	/*! \brief Timer used for waking up Stasis thread */
-	struct ast_timer *timer;
-	/*! \brief Audiohook used to spy on the channel */
-	struct ast_audiohook spy;
-	/*! \brief Direction for spying */
-	enum ast_audiohook_direction spy_direction;
-	/*! \brief Number of samples to be read in when spying */
-	unsigned int spy_samples;
-	/*! \brief Format in use by the spy audiohook */
-	struct ast_format *spy_format;
-	/*! \brief Audiohook used to whisper on the channel */
-	struct ast_audiohook whisper;
-	/*! \brief Direction for whispering */
-	enum ast_audiohook_direction whisper_direction;
-	/*! \brief Stasis application and arguments */
-	struct ast_str *app;
-	/*! \brief Snoop channel */
-	struct ast_channel *chan;
-	/*! \brief Whether the spy capability is active or not */
-	unsigned int spy_active:1;
-	/*! \brief Whether the whisper capability is active or not */
-	unsigned int whisper_active:1;
-	/*! \brief Uniqueid of the channel this snoop is snooping on */
-	char uniqueid[AST_MAX_UNIQUEID];
-};
-
-/*! \brief Destructor for snoop structure */
-static void snoop_destroy(void *obj)
-{
-	struct stasis_app_snoop *snoop = obj;
-
-	if (snoop->timer) {
-		ast_timer_close(snoop->timer);
-	}
-
-	if (snoop->spy_active) {
-		ast_audiohook_destroy(&snoop->spy);
-	}
-
-	if (snoop->whisper_active) {
-		ast_audiohook_destroy(&snoop->whisper);
-	}
-
-	ast_free(snoop->app);
-
-	ast_channel_cleanup(snoop->chan);
-}
-
-/*! \internal
- * \brief Publish the chanspy message over Stasis-Core
- * \param snoop The snoop structure
- * \start start If non-zero, the spying is starting. Otherwise, the spyer is
- * finishing
- */
-static void publish_chanspy_message(struct stasis_app_snoop *snoop, int start)
-{
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
-	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, snoop_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, spyee_snapshot, NULL, ao2_cleanup);
-	struct stasis_message_type *type = start ? ast_channel_chanspy_start_type(): ast_channel_chanspy_stop_type();
-
-	blob = ast_json_null();
-	if (!blob || !type) {
-		return;
-	}
-
-	payload = ast_multi_channel_blob_create(blob);
-	if (!payload) {
-		return;
-	}
-
-	snoop_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(snoop->chan));
-	if (!snoop_snapshot) {
-		return;
-	}
-	ast_multi_channel_blob_add_channel(payload, "spyer_channel", snoop_snapshot);
-
-	spyee_snapshot = ast_channel_snapshot_get_latest(snoop->uniqueid);
-	if (spyee_snapshot) {
-		ast_multi_channel_blob_add_channel(payload, "spyee_channel", spyee_snapshot);
-	}
-
-	message = stasis_message_create(type, payload);
-	if (!message) {
-		return;
-	}
-
-	stasis_publish(ast_channel_topic(snoop->chan), message);
-}
-
-/*! \brief Callback function for writing to a Snoop whisper audiohook */
-static int snoop_write(struct ast_channel *chan, struct ast_frame *frame)
-{
-	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan);
-
-	if (!snoop->whisper_active) {
-		return 0;
-	}
-
-	ast_audiohook_lock(&snoop->whisper);
-	if (snoop->whisper_direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
-		ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_READ, frame);
-		ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_WRITE, frame);
-	} else {
-		ast_audiohook_write_frame(&snoop->whisper, snoop->whisper_direction, frame);
-	}
-	ast_audiohook_unlock(&snoop->whisper);
-
-	return 0;
-}
-
-/*! \brief Callback function for reading from a Snoop channel */
-static struct ast_frame *snoop_read(struct ast_channel *chan)
-{
-	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan);
-	struct ast_frame *frame = NULL;
-
-	/* If we fail to ack the timer OR if any active audiohooks are done hangup */
-	if ((ast_timer_ack(snoop->timer, 1) < 0) ||
-		(snoop->spy_active && snoop->spy.status != AST_AUDIOHOOK_STATUS_RUNNING) ||
-		(snoop->whisper_active && snoop->whisper.status != AST_AUDIOHOOK_STATUS_RUNNING)) {
-		return NULL;
-	}
-
-	/* Only get audio from the spy audiohook if it is active */
-	if (snoop->spy_active) {
-		ast_audiohook_lock(&snoop->spy);
-		frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format);
-		ast_audiohook_unlock(&snoop->spy);
-	}
-
-	return frame ? frame : &ast_null_frame;
-}
-
-/*! \brief Callback function for hanging up a Snoop channel */
-static int snoop_hangup(struct ast_channel *chan)
-{
-	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan);
-
-	if (snoop->spy_active) {
-		ast_audiohook_lock(&snoop->spy);
-		ast_audiohook_detach(&snoop->spy);
-		ast_audiohook_unlock(&snoop->spy);
-	}
-
-	if (snoop->whisper_active) {
-		ast_audiohook_lock(&snoop->whisper);
-		ast_audiohook_detach(&snoop->whisper);
-		ast_audiohook_unlock(&snoop->whisper);
-	}
-
-	publish_chanspy_message(snoop, 0);
-
-	ao2_cleanup(snoop);
-
-	ast_channel_tech_pvt_set(chan, NULL);
-
-	return 0;
-}
-
-static int snoop_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
-	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(oldchan);
-
-	if (snoop->chan != oldchan) {
-		return -1;
-	}
-
-	ast_channel_unref(snoop->chan);
-	ast_channel_ref(newchan);
-	snoop->chan = newchan;
-
-	return 0;
-}
-
-/*! \brief Channel interface declaration */
-static struct ast_channel_tech snoop_tech = {
-	.type = "Snoop",
-	.description = "Snoop Channel Driver",
-	.write = snoop_write,
-	.read = snoop_read,
-	.hangup = snoop_hangup,
-	.fixup = snoop_fixup,
-};
-
-/*! \brief Thread used for running the Stasis application */
-static void *snoop_stasis_thread(void *obj)
-{
-	RAII_VAR(struct stasis_app_snoop *, snoop, obj, ao2_cleanup);
-	struct ast_app *stasis = pbx_findapp("Stasis");
-
-	if (!stasis) {
-		ast_hangup(snoop->chan);
-		return NULL;
-	}
-
-	pbx_exec(snoop->chan, stasis, ast_str_buffer(snoop->app));
-
-	ast_hangup(snoop->chan);
-
-	return NULL;
-}
-
-/*! \brief Internal helper function which sets up and attaches a snoop audiohook */
-static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_type type, enum stasis_app_snoop_direction requested_direction,
-	enum ast_audiohook_direction *direction, struct ast_audiohook *audiohook)
-{
-	ast_audiohook_init(audiohook, type, "Snoop", 0);
-
-	if (requested_direction == STASIS_SNOOP_DIRECTION_OUT) {
-		*direction = AST_AUDIOHOOK_DIRECTION_WRITE;
-	} else if (requested_direction == STASIS_SNOOP_DIRECTION_IN) {
-		*direction = AST_AUDIOHOOK_DIRECTION_READ;
-	} else if (requested_direction == STASIS_SNOOP_DIRECTION_BOTH) {
-		*direction = AST_AUDIOHOOK_DIRECTION_BOTH;
-	} else {
-		return -1;
-	}
-
-	return ast_audiohook_attach(chan, audiohook);
-}
-
-/*! \brief Helper function which gets the format for a Snoop channel based on the channel being snooped on */
-static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_snoop *snoop)
-{
-	SCOPED_CHANNELLOCK(lock, chan);
-	unsigned int rate = MAX(ast_format_get_sample_rate(ast_channel_rawwriteformat(chan)),
-		ast_format_get_sample_rate(ast_channel_rawreadformat(chan)));
-
-	snoop->spy_format = ast_format_cache_get_slin_by_rate(rate);
-}
-
-struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
-	enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
-	const char *app, const char *app_args, const char *snoop_id)
-{
-	RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
-	struct ast_format_cap *caps;
-	pthread_t thread;
-	struct ast_assigned_ids assignedids = {
-		.uniqueid = snoop_id,
-	};
-
-	if (spy == STASIS_SNOOP_DIRECTION_NONE &&
-		whisper == STASIS_SNOOP_DIRECTION_NONE) {
-		return NULL;
-	}
-
-	snoop = ao2_alloc_options(sizeof(*snoop), snoop_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!snoop) {
-		return NULL;
-	}
-
-	/* Allocate a buffer to store the Stasis application and arguments in */
-	snoop->app = ast_str_create(64);
-	if (!snoop->app) {
-		return NULL;
-	}
-
-	ast_str_set(&snoop->app, 0, "%s", app);
-	if (!ast_strlen_zero(app_args)) {
-		ast_str_append(&snoop->app, 0, ",%s", app_args);
-	}
-
-	/* Set up a timer for the Snoop channel so it wakes up at a specific interval */
-	snoop->timer = ast_timer_open();
-	if (!snoop->timer) {
-		return NULL;
-	}
-	ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL);
-
-	/* Determine which signed linear format should be used */
-	snoop_determine_format(chan, snoop);
-
-	/* Allocate a Snoop channel and set up various parameters */
-	snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
-		(unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
-	if (!snoop->chan) {
-		return NULL;
-	}
-
-	ast_copy_string(snoop->uniqueid, ast_channel_uniqueid(chan), sizeof(snoop->uniqueid));
-
-	/* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */
-	ast_channel_ref(snoop->chan);
-
-	ast_channel_tech_set(snoop->chan, &snoop_tech);
-	ao2_ref(snoop, +1);
-	ast_channel_tech_pvt_set(snoop->chan, snoop);
-	ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer));
-
-	/* The format on the Snoop channel will be this signed linear format, and it will never change */
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_channel_unlock(snoop->chan);
-		ast_hangup(snoop->chan);
-		return NULL;
-	}
-	ast_format_cap_append(caps, snoop->spy_format, 0);
-	ast_channel_nativeformats_set(snoop->chan, caps);
-	ao2_ref(caps, -1);
-
-	ast_channel_set_writeformat(snoop->chan, snoop->spy_format);
-	ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format);
-	ast_channel_set_readformat(snoop->chan, snoop->spy_format);
-	ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format);
-
-	ast_channel_unlock(snoop->chan);
-
-	if (spy != STASIS_SNOOP_DIRECTION_NONE) {
-		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
-			ast_hangup(snoop->chan);
-			return NULL;
-		}
-
-		snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL);
-		snoop->spy_active = 1;
-	}
-
-	/* If whispering is enabled set up the audiohook */
-	if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
-		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
-			ast_hangup(snoop->chan);
-			return NULL;
-		}
-
-		snoop->whisper_active = 1;
-	}
-
-	/* Create the thread which services the Snoop channel */
-	ao2_ref(snoop, +1);
-	if (ast_pthread_create_detached_background(&thread, NULL, snoop_stasis_thread, snoop)) {
-		ao2_cleanup(snoop);
-
-		/* No other thread is servicing this channel so we can immediately hang it up */
-		ast_hangup(snoop->chan);
-		return NULL;
-	}
-
-	publish_chanspy_message(snoop, 1);
-
-	/* The caller of this has a reference as well */
-	return ast_channel_ref(snoop->chan);
-}
-
-static int load_module(void)
-{
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application snoop support",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis");
diff --git a/res/res_stasis_snoop.exports.in b/res/res_stasis_snoop.exports.in
deleted file mode 100644
index 7ec8ecc..0000000
--- a/res/res_stasis_snoop.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_app_control_snoop;
-	local:
-		*;
-};
diff --git a/res/res_stasis_test.c b/res/res_stasis_test.c
deleted file mode 100644
index 1b91b1a..0000000
--- a/res/res_stasis_test.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test infrastructure for dealing with Stasis.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $");
-
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_test.h"
-
-STASIS_MESSAGE_TYPE_DEFN(stasis_test_message_type);
-
-static void stasis_message_sink_dtor(void *obj)
-{
-	struct stasis_message_sink *sink = obj;
-
-	{
-		SCOPED_MUTEX(lock, &sink->lock);
-		while (!sink->is_done) {
-			/* Normally waiting forever is bad, but if we're not
-			 * done, we're not done. */
-			ast_cond_wait(&sink->cond, &sink->lock);
-		}
-	}
-
-	ast_mutex_destroy(&sink->lock);
-	ast_cond_destroy(&sink->cond);
-
-	while (sink->num_messages > 0) {
-		ao2_cleanup(sink->messages[--sink->num_messages]);
-	}
-	ast_free(sink->messages);
-	sink->messages = NULL;
-	sink->max_messages = 0;
-}
-
-static struct timespec make_deadline(int timeout_millis)
-{
-	struct timeval start = ast_tvnow();
-	struct timeval delta = {
-		.tv_sec = timeout_millis / 1000,
-		.tv_usec = (timeout_millis % 1000) * 1000,
-	};
-	struct timeval deadline_tv = ast_tvadd(start, delta);
-	struct timespec deadline = {
-		.tv_sec = deadline_tv.tv_sec,
-		.tv_nsec = 1000 * deadline_tv.tv_usec,
-	};
-
-	return deadline;
-}
-
-struct stasis_message_sink *stasis_message_sink_create(void)
-{
-	RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
-
-	sink = ao2_alloc(sizeof(*sink), stasis_message_sink_dtor);
-	if (!sink) {
-		return NULL;
-	}
-	ast_mutex_init(&sink->lock);
-	ast_cond_init(&sink->cond, NULL);
-	sink->max_messages = 4;
-	sink->messages =
-		ast_malloc(sizeof(*sink->messages) * sink->max_messages);
-	if (!sink->messages) {
-		return NULL;
-	}
-	ao2_ref(sink, +1);
-	return sink;
-}
-
-/*!
- * \brief Implementation of the stasis_message_sink_cb() callback.
- *
- * Why the roundabout way of exposing this via stasis_message_sink_cb()? Well,
- * it has to do with how we load modules.
- *
- * Modules have their own metadata compiled into them in the module info block
- * at the end of the file.  This includes dependency information in the
- * \c nonoptreq field.
- *
- * Asterisk loads the module, inspects the field, then loads any needed
- * dependencies. This works because Asterisk passes \c RTLD_LAZY to the initial
- * dlopen(), which defers binding function references until they are called.
- *
- * But when you take the address of a function, that function needs to be
- * available at load time. So if some module used the address of
- * message_sink_cb() directly, and \c res_stasis_test.so wasn't loaded yet, then
- * that module would fail to load.
- *
- * The stasis_message_sink_cb() function gives us a layer of indirection so that
- * the initial lazy binding will still work as expected.
- */
-static void message_sink_cb(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_message_sink *sink = data;
-
-	SCOPED_MUTEX(lock, &sink->lock);
-
-	if (stasis_subscription_final_message(sub, message)) {
-		sink->is_done = 1;
-		ast_cond_signal(&sink->cond);
-		return;
-	}
-
-	if (stasis_subscription_change_type() == stasis_message_type(message)) {
-		/* Ignore subscription changes */
-		return;
-	}
-
-	if (sink->num_messages == sink->max_messages) {
-		size_t new_max_messages = sink->max_messages * 2;
-		struct stasis_message **new_messages = ast_realloc(
-			sink->messages,
-			sizeof(*new_messages) * new_max_messages);
-		if (!new_messages) {
-			return;
-		}
-		sink->max_messages = new_max_messages;
-		sink->messages = new_messages;
-	}
-
-	ao2_ref(message, +1);
-	sink->messages[sink->num_messages++] = message;
-	ast_cond_signal(&sink->cond);
-}
-
-stasis_subscription_cb stasis_message_sink_cb(void)
-{
-	return message_sink_cb;
-}
-
-
-int stasis_message_sink_wait_for_count(struct stasis_message_sink *sink,
-	int num_messages, int timeout_millis)
-{
-	struct timespec deadline = make_deadline(timeout_millis);
-
-	SCOPED_MUTEX(lock, &sink->lock);
-	while (sink->num_messages < num_messages) {
-		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
-
-		if (r == ETIMEDOUT) {
-			break;
-		}
-		if (r != 0) {
-			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
-				strerror(r));
-			break;
-		}
-	}
-	return sink->num_messages;
-}
-
-int stasis_message_sink_should_stay(struct stasis_message_sink *sink,
-	int num_messages, int timeout_millis)
-{
-	struct timespec deadline = make_deadline(timeout_millis);
-
-	SCOPED_MUTEX(lock, &sink->lock);
-	while (sink->num_messages == num_messages) {
-		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
-
-		if (r == ETIMEDOUT) {
-			break;
-		}
-		if (r != 0) {
-			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
-				strerror(r));
-			break;
-		}
-	}
-	return sink->num_messages;
-}
-
-int stasis_message_sink_wait_for(struct stasis_message_sink *sink, int start,
-	stasis_wait_cb cmp_cb, const void *data, int timeout_millis)
-{
-	struct timespec deadline = make_deadline(timeout_millis);
-
-	SCOPED_MUTEX(lock, &sink->lock);
-
-	/* wait for the start */
-	while (sink->num_messages < start + 1) {
-		int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
-
-		if (r == ETIMEDOUT) {
-			/* Timed out waiting for the start */
-			return -1;
-		}
-		if (r != 0) {
-			ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
-				strerror(r));
-			return -2;
-		}
-	}
-
-
-	while (!cmp_cb(sink->messages[start], data)) {
-		++start;
-
-		while (sink->num_messages < start + 1) {
-			int r = ast_cond_timedwait(&sink->cond,
-				&sink->lock, &deadline);
-
-			if (r == ETIMEDOUT) {
-				return -1;
-			}
-			if (r != 0) {
-				ast_log(LOG_ERROR,
-					"Unexpected condition error: %s\n",
-					strerror(r));
-				return -2;
-			}
-		}
-	}
-
-	return start;
-}
-
-struct stasis_message *stasis_test_message_create(void)
-{
-	RAII_VAR(void *, data, NULL, ao2_cleanup);
-
-	if (!stasis_test_message_type()) {
-		return NULL;
-	}
-
-	/* We just need the unique pointer; don't care what's in it */
-	data = ao2_alloc(1, NULL);
-	if (!data) {
-		return NULL;
-	}
-
-	return stasis_message_create(stasis_test_message_type(), data);
-}
-
-static int unload_module(void)
-{
-	STASIS_MESSAGE_TYPE_CLEANUP(stasis_test_message_type);
-	return 0;
-}
-
-static int load_module(void)
-{
-	if (STASIS_MESSAGE_TYPE_INIT(stasis_test_message_type) != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis test utilities",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.load_pri = AST_MODPRI_APP_DEPEND,
-	);
diff --git a/res/res_stasis_test.exports.in b/res/res_stasis_test.exports.in
deleted file mode 100644
index 9616003..0000000
--- a/res/res_stasis_test.exports.in
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIXstasis_*;
-	local:
-		*;
-};
diff --git a/res/res_statsd.c b/res/res_statsd.c
deleted file mode 100644
index 58e2455..0000000
--- a/res/res_statsd.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \brief Support for publishing to a statsd server.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-/*** MODULEINFO
-	<support_level>extended</support_level>
- ***/
-
-/*** DOCUMENTATION
-	<configInfo name="res_statsd" language="en_US">
-		<synopsis>Statsd client.</synopsis>
-		<configFile name="statsd.conf">
-			<configObject name="global">
-				<synopsis>Global configuration settings</synopsis>
-				<configOption name="enabled">
-					<synopsis>Enable/disable the statsd module</synopsis>
-				</configOption>
-				<configOption name="server">
-					<synopsis>Address of the statsd server</synopsis>
-				</configOption>
-				<configOption name="prefix">
-					<synopsis>Prefix to prepend to every metric</synopsis>
-				</configOption>
-				<configOption name="add_newline">
-					<synopsis>Append a newline to every event. This is useful if you want to fake out a server using netcat (nc -lu 8125)</synopsis>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
-***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
-
-#include "asterisk/config_options.h"
-#include "asterisk/module.h"
-#include "asterisk/netsock2.h"
-
-#define AST_API_MODULE
-#include "asterisk/statsd.h"
-
-#define DEFAULT_STATSD_PORT 8125
-
-#define MAX_PREFIX 40
-
-/*! Socket for sending statd messages */
-static int socket_fd = -1;
-
-/*! \brief Global configuration options for statsd client. */
-struct conf_global_options {
-	/*! Enabled by default, disabled if false. */
-	int enabled;
-	/*! Disabled by default, appends newlines to all messages when enabled. */
-	int add_newline;
-	/*! Statsd server address[:port]. */
-	struct ast_sockaddr statsd_server;
-	/*! Prefix to put on every stat. */
-	char prefix[MAX_PREFIX + 1];
-};
-
-/*! \brief All configuration options for statsd client. */
-struct conf {
-	/*! The general section configuration options. */
-	struct conf_global_options *global;
-};
-
-/*! \brief Locking container for safe configuration access. */
-static AO2_GLOBAL_OBJ_STATIC(confs);
-
-static void conf_server(const struct conf *cfg, struct ast_sockaddr *addr)
-{
-	*addr = cfg->global->statsd_server;
-	if (ast_sockaddr_port(addr) == 0) {
-		ast_sockaddr_set_port(addr, DEFAULT_STATSD_PORT);
-	}
-}
-
-void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name,
-	const char *metric_type, intmax_t value, double sample_rate)
-{
-	RAII_VAR(struct conf *, cfg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, msg, NULL, ast_free);
-	size_t len;
-	struct ast_sockaddr statsd_server;
-
-	if (socket_fd == -1) {
-		return;
-	}
-
-	cfg = ao2_global_obj_ref(confs);
-	conf_server(cfg, &statsd_server);
-
-	/* Rates <= 0.0 never get logged.
-	 * Rates >= 1.0 always get logged.
-	 * All others leave it to chance.
-	 */
-	if (sample_rate <= 0.0 ||
-		(sample_rate < 1.0 && sample_rate < ast_random_double())) {
-		return;
-	}
-
-	cfg = ao2_global_obj_ref(confs);
-
-	msg = ast_str_create(40);
-	if (!msg) {
-		return;
-	}
-
-	if (!ast_strlen_zero(cfg->global->prefix)) {
-		ast_str_append(&msg, 0, "%s.", cfg->global->prefix);
-	}
-
-	ast_str_append(&msg, 0, "%s:%jd|%s", metric_name, value, metric_type);
-
-	if (sample_rate < 1.0) {
-		ast_str_append(&msg, 0, "|@%.2f", sample_rate);
-	}
-
-	if (cfg->global->add_newline) {
-		ast_str_append(&msg, 0, "\n");
-	}
-
-	len = ast_str_strlen(msg);
-
-	ast_debug(6, "send: %s\n", ast_str_buffer(msg));
-	ast_sendto(socket_fd, ast_str_buffer(msg), len, 0, &statsd_server);
-}
-
-void AST_OPTIONAL_API_NAME(ast_statsd_log)(const char *metric_name,
-	const char *metric_type, intmax_t value)
-{
-	ast_statsd_log_full(metric_name, metric_type, value, 1.0);
-}
-
-void AST_OPTIONAL_API_NAME(ast_statsd_log_sample)(const char *metric_name,
-	intmax_t value, double sample_rate)
-{
-	ast_statsd_log_full(metric_name, AST_STATSD_COUNTER, value,
-		sample_rate);
-}
-
-/*! \brief Mapping of the statsd conf struct's globals to the
- *         general context in the config file. */
-static struct aco_type global_option = {
-	.type = ACO_GLOBAL,
-	.name = "global",
-	.item_offset = offsetof(struct conf, global),
-	.category = "^general$",
-	.category_match = ACO_WHITELIST
-};
-
-static struct aco_type *global_options[] = ACO_TYPES(&global_option);
-
-/*! \brief Disposes of the statsd conf object */
-static void conf_destructor(void *obj)
-{
-    struct conf *cfg = obj;
-    ao2_cleanup(cfg->global);
-}
-
-/*! \brief Creates the statis http conf object. */
-static void *conf_alloc(void)
-{
-    struct conf *cfg;
-
-    if (!(cfg = ao2_alloc(sizeof(*cfg), conf_destructor))) {
-        return NULL;
-    }
-
-    if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
-        ao2_ref(cfg, -1);
-        return NULL;
-    }
-    return cfg;
-}
-
-/*! \brief The conf file that's processed for the module. */
-static struct aco_file conf_file = {
-	/*! The config file name. */
-	.filename = "statsd.conf",
-	/*! The mapping object types to be processed. */
-	.types = ACO_TYPES(&global_option),
-};
-
-CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
-		     .files = ACO_FILES(&conf_file));
-
-/*! \brief Helper function to check if module is enabled. */
-static char is_enabled(void)
-{
-	RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
-	return cfg->global->enabled;
-}
-
-static int statsd_init(void)
-{
-	RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
-	char *server;
-	struct ast_sockaddr statsd_server;
-
-	ast_assert(is_enabled());
-
-	ast_debug(3, "Configuring statsd client.\n");
-
-	if (socket_fd == -1) {
-		ast_debug(3, "Creating statsd socket.\n");
-		socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-		if (socket_fd == -1) {
-			perror("Error creating statsd socket");
-			return -1;
-		}
-	}
-
-	conf_server(cfg, &statsd_server);
-	server = ast_sockaddr_stringify_fmt(&statsd_server,
-		AST_SOCKADDR_STR_DEFAULT);
-	ast_debug(3, "  statsd server = %s.\n", server);
-	ast_debug(3, "  add newline = %s\n", AST_YESNO(cfg->global->add_newline));
-	ast_debug(3, "  prefix = %s\n", cfg->global->prefix);
-
-	return 0;
-}
-
-static void statsd_shutdown(void)
-{
-	ast_debug(3, "Shutting down statsd client.\n");
-	if (socket_fd != -1) {
-		close(socket_fd);
-		socket_fd = -1;
-	}
-}
-
-static int load_module(void)
-{
-	if (aco_info_init(&cfg_info)) {
-		aco_info_destroy(&cfg_info);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options,
-		"no", OPT_BOOL_T, 1,
-		FLDSET(struct conf_global_options, enabled));
-
-	aco_option_register(&cfg_info, "add_newline", ACO_EXACT, global_options,
-		"no", OPT_BOOL_T, 1,
-		FLDSET(struct conf_global_options, add_newline));
-
-	aco_option_register(&cfg_info, "server", ACO_EXACT, global_options,
-		"127.0.0.1", OPT_SOCKADDR_T, 0,
-		FLDSET(struct conf_global_options, statsd_server));
-
-	aco_option_register(&cfg_info, "prefix", ACO_EXACT, global_options,
-		"", OPT_CHAR_ARRAY_T, 0,
-		CHARFLDSET(struct conf_global_options, prefix));
-
-	if (aco_process_config(&cfg_info, 0)) {
-		aco_info_destroy(&cfg_info);
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (!is_enabled()) {
-		return AST_MODULE_LOAD_SUCCESS;
-	}
-
-	if (statsd_init() != 0) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	statsd_shutdown();
-	aco_info_destroy(&cfg_info);
-	ao2_global_obj_release(confs);
-	return 0;
-}
-
-static int reload_module(void)
-{
-	if (aco_process_config(&cfg_info, 1)) {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (is_enabled()) {
-		return statsd_init();
-	} else {
-		statsd_shutdown();
-		return AST_MODULE_LOAD_SUCCESS;
-	}
-}
-
-/* The priority of this module is set to be as low as possible, since it could
- * be used by any other sort of module.
- */
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Statsd client support",
-	.support_level = AST_MODULE_SUPPORT_EXTENDED,
-	.load = load_module,
-	.unload = unload_module,
-	.reload = reload_module,
-	.load_pri = 0,
-	);
diff --git a/res/res_statsd.exports.in b/res/res_statsd.exports.in
deleted file mode 100644
index 6f02b25..0000000
--- a/res/res_statsd.exports.in
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	global:
-		LINKER_SYMBOL_PREFIX*ast_statsd_log;
-		LINKER_SYMBOL_PREFIX*ast_statsd_log_full;
-		LINKER_SYMBOL_PREFIX*ast_statsd_log_sample;
-	local:
-		*;
-};
diff --git a/res/res_stun_monitor.c b/res/res_stun_monitor.c
index f168318..596b17b 100644
--- a/res/res_stun_monitor.c
+++ b/res/res_stun_monitor.c
@@ -29,9 +29,10 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
+#include "asterisk/event.h"
 #include "asterisk/sched.h"
 #include "asterisk/config.h"
 #include "asterisk/stun.h"
@@ -39,10 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
 #include "asterisk/lock.h"
 #include "asterisk/acl.h"
 #include "asterisk/cli.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_system.h"
-#include "asterisk/astobj2.h"
 
 #include <fcntl.h>
 
@@ -155,32 +152,18 @@ static int stun_monitor_request(const void *blarg)
 			args.external_addr = answer;
 
 			if (args.external_addr_known) {
-				RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-				RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
-				RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-
-				if (!ast_network_change_type()) {
-					goto publish_failure;
-				}
-
-				/* This json_object doesn't actually contain anything yet. We have to reference something
-				 * for stasis, and this is useful for if we want to ever add data for any reason. */
-				json_object = ast_json_object_create();
-				if (!json_object) {
-					goto publish_failure;
-				}
-
-				if (!(json_payload = ast_json_payload_create(json_object))) {
-					goto publish_failure;
-				}
-
-				msg = stasis_message_create(ast_network_change_type(), json_payload);
-
-publish_failure:
-				if (msg) {
-					stasis_publish(ast_system_topic(), msg);
-				} else {
-					ast_log(LOG_ERROR, "Failed to issue network change message.\n");
+				struct ast_event *event;
+
+				/*
+				 * The external address was already known, and has changed...
+				 * generate event.
+				 */
+				event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
+				if (!event) {
+					ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n");
+				} else if (ast_event_queue(event)) {
+					ast_event_destroy(event);
+					ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n");
 				}
 			} else {
 				/* this was the first external address we found, do not alert listeners
@@ -476,7 +459,6 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/res_timing_dahdi.c b/res/res_timing_dahdi.c
index 3a77595..5a67f4d 100644
--- a/res/res_timing_dahdi.c
+++ b/res/res_timing_dahdi.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -45,15 +45,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
 
 static void *timing_funcs_handle;
 
-static void *dahdi_timer_open(void);
-static void dahdi_timer_close(void *data);
-static int dahdi_timer_set_rate(void *data, unsigned int rate);
-static int dahdi_timer_ack(void *data, unsigned int quantity);
-static int dahdi_timer_enable_continuous(void *data);
-static int dahdi_timer_disable_continuous(void *data);
-static enum ast_timer_event dahdi_timer_get_event(void *data);
-static unsigned int dahdi_timer_get_max_rate(void *data);
-static int dahdi_timer_fd(void *data);
+static int dahdi_timer_open(void);
+static void dahdi_timer_close(int handle);
+static int dahdi_timer_set_rate(int handle, unsigned int rate);
+static int dahdi_timer_ack(int handle, unsigned int quantity);
+static int dahdi_timer_enable_continuous(int handle);
+static int dahdi_timer_disable_continuous(int handle);
+static enum ast_timer_event dahdi_timer_get_event(int handle);
+static unsigned int dahdi_timer_get_max_rate(int handle);
 
 static struct ast_timing_interface dahdi_timing = {
 	.name = "DAHDI",
@@ -66,49 +65,26 @@ static struct ast_timing_interface dahdi_timing = {
 	.timer_disable_continuous = dahdi_timer_disable_continuous,
 	.timer_get_event = dahdi_timer_get_event,
 	.timer_get_max_rate = dahdi_timer_get_max_rate,
-	.timer_fd = dahdi_timer_fd,
 };
 
-struct dahdi_timer {
-	int fd;
-};
-
-static void *dahdi_timer_open(void)
+static int dahdi_timer_open(void)
 {
-	struct dahdi_timer *timer;
-
-	if (!(timer = ast_calloc(1, sizeof(*timer)))) {
-		return NULL;
-	}
-
-	if ((timer->fd = open("/dev/dahdi/timer", O_RDWR)) < 0) {
-		ast_log(LOG_ERROR, "Failed to create dahdi timer: %s\n", strerror(errno));
-		ast_free(timer);
-		return NULL;
-	}
-
-	return timer;
+	return open("/dev/dahdi/timer", O_RDWR);
 }
 
-static void dahdi_timer_close(void *data)
+static void dahdi_timer_close(int handle)
 {
-	struct dahdi_timer *timer = data;
-
-	close(timer->fd);
-	ast_free(timer);
+	close(handle);
 }
 
-static int dahdi_timer_set_rate(void *data, unsigned int rate)
+static int dahdi_timer_set_rate(int handle, unsigned int rate)
 {
-	struct dahdi_timer *timer = data;
-	int samples;
-
 	/* DAHDI timers are configured using a number of samples,
 	 * based on an 8 kHz sample rate. */
-	samples = (unsigned int) roundf((8000.0 / ((float) rate)));
+	unsigned int samples = roundf((8000.0 / ((float) rate)));
 
-	if (ioctl(timer->fd, DAHDI_TIMERCONFIG, &samples)) {
-		ast_log(LOG_ERROR, "Failed to configure DAHDI timing fd for %d sample timer ticks\n",
+	if (ioctl(handle, DAHDI_TIMERCONFIG, &samples)) {
+		ast_log(LOG_ERROR, "Failed to configure DAHDI timing fd for %u sample timer ticks\n",
 			samples);
 		return -1;
 	}
@@ -116,36 +92,31 @@ static int dahdi_timer_set_rate(void *data, unsigned int rate)
 	return 0;
 }
 
-static int dahdi_timer_ack(void *data, unsigned int quantity)
+static int dahdi_timer_ack(int handle, unsigned int quantity)
 {
-	struct dahdi_timer *timer = data;
-
-	return ioctl(timer->fd, DAHDI_TIMERACK, &quantity) ? -1 : 0;
+	return ioctl(handle, DAHDI_TIMERACK, &quantity) ? -1 : 0;
 }
 
-static int dahdi_timer_enable_continuous(void *data)
+static int dahdi_timer_enable_continuous(int handle)
 {
-	struct dahdi_timer *timer = data;
 	int flags = 1;
 
-	return ioctl(timer->fd, DAHDI_TIMERPING, &flags) ? -1 : 0;
+	return ioctl(handle, DAHDI_TIMERPING, &flags) ? -1 : 0;
 }
 
-static int dahdi_timer_disable_continuous(void *data)
+static int dahdi_timer_disable_continuous(int handle)
 {
-	struct dahdi_timer *timer = data;
 	int flags = -1;
 
-	return ioctl(timer->fd, DAHDI_TIMERPONG, &flags) ? -1 : 0;
+	return ioctl(handle, DAHDI_TIMERPONG, &flags) ? -1 : 0;
 }
 
-static enum ast_timer_event dahdi_timer_get_event(void *data)
+static enum ast_timer_event dahdi_timer_get_event(int handle)
 {
-	struct dahdi_timer *timer = data;
 	int res;
 	int event;
 
-	res = ioctl(timer->fd, DAHDI_GETEVENT, &event);
+	res = ioctl(handle, DAHDI_GETEVENT, &event);
 
 	if (res) {
 		event = DAHDI_EVENT_TIMER_EXPIRED;
@@ -160,18 +131,11 @@ static enum ast_timer_event dahdi_timer_get_event(void *data)
 	}
 }
 
-static unsigned int dahdi_timer_get_max_rate(void *data)
+static unsigned int dahdi_timer_get_max_rate(int handle)
 {
 	return 1000;
 }
 
-static int dahdi_timer_fd(void *data)
-{
-	struct dahdi_timer *timer = data;
-
-	return timer->fd;
-}
-
 #define SEE_TIMING "For more information on Asterisk timing modules, including ways to potentially fix this problem, please see https://wiki.asterisk.org/wiki/display/AST/Timing+Interfaces\n"
 
 static int dahdi_test_timer(void)
@@ -235,7 +199,6 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "DAHDI Timing Interface",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_TIMING,
diff --git a/res/res_timing_kqueue.c b/res/res_timing_kqueue.c
index 3e24177..9ada1ae 100644
--- a/res/res_timing_kqueue.c
+++ b/res/res_timing_kqueue.c
@@ -18,11 +18,9 @@
 
 /*!
  * \file
- * \author Tilghman Lesher \verbatim <tlesher AT digium DOT com> \endverbatim
+ * \author Tilghman Lesher <tlesher AT digium DOT com>
  *
  * \brief kqueue timing interface
- *
- * \ingroup resource
  */
 
 /*** MODULEINFO
@@ -48,15 +46,14 @@
 
 static void *timing_funcs_handle;
 
-static void *kqueue_timer_open(void);
-static void kqueue_timer_close(void *data);
-static int kqueue_timer_set_rate(void *data, unsigned int rate);
-static int kqueue_timer_ack(void *data, unsigned int quantity);
-static int kqueue_timer_enable_continuous(void *data);
-static int kqueue_timer_disable_continuous(void *data);
-static enum ast_timer_event kqueue_timer_get_event(void *data);
-static unsigned int kqueue_timer_get_max_rate(void *data);
-static int kqueue_timer_fd(void *data);
+static int kqueue_timer_open(void);
+static void kqueue_timer_close(int handle);
+static int kqueue_timer_set_rate(int handle, unsigned int rate);
+static int kqueue_timer_ack(int handle, unsigned int quantity);
+static int kqueue_timer_enable_continuous(int handle);
+static int kqueue_timer_disable_continuous(int handle);
+static enum ast_timer_event kqueue_timer_get_event(int handle);
+static unsigned int kqueue_timer_get_max_rate(int handle);
 
 static struct ast_timing_interface kqueue_timing = {
 	.name = "kqueue",
@@ -69,9 +66,10 @@ static struct ast_timing_interface kqueue_timing = {
 	.timer_disable_continuous = kqueue_timer_disable_continuous,
 	.timer_get_event = kqueue_timer_get_event,
 	.timer_get_max_rate = kqueue_timer_get_max_rate,
-	.timer_fd = kqueue_timer_fd,
 };
 
+static struct ao2_container *kqueue_timers;
+
 struct kqueue_timer {
 	int handle;
 	uint64_t nsecs;
@@ -79,34 +77,74 @@ struct kqueue_timer {
 	unsigned int is_continuous:1;
 };
 
+static int kqueue_timer_hash(const void *obj, const int flags)
+{
+	const struct kqueue_timer *timer = obj;
+
+	return timer->handle;
+}
+
+static int kqueue_timer_cmp(void *obj, void *args, int flags)
+{
+	struct kqueue_timer *timer1 = obj, *timer2 = args;
+	return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
+}
+
 static void timer_destroy(void *obj)
 {
 	struct kqueue_timer *timer = obj;
-	close(timer->handle);
+	if (timer->handle > -1) {
+		close(timer->handle);
+	}
 }
 
-static void *kqueue_timer_open(void)
+#define lookup_timer(a)	_lookup_timer(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+static struct kqueue_timer *_lookup_timer(int handle, const char *file, int line, const char *func)
+{
+	struct kqueue_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
+
+	if (!(our_timer = ao2_find(kqueue_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(__LOG_ERROR, file, line, func, "Couldn't find timer with handle %d\n", handle);
+		/* API says we set errno */
+		errno = ESRCH;
+		return NULL;
+	}
+	return our_timer;
+}
+
+static int kqueue_timer_open(void)
 {
 	struct kqueue_timer *timer;
+	int handle;
 
 	if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
 		ast_log(LOG_ERROR, "Could not allocate memory for kqueue_timer structure\n");
 		return -1;
 	}
-	if ((timer->handle = kqueue()) < 0) {
+	if ((timer->handle = handle = kqueue()) < 0) {
 		ast_log(LOG_ERROR, "Failed to create kqueue timer: %s\n", strerror(errno));
 		ao2_ref(timer, -1);
 		return -1;
 	}
 
-	return timer;
+	ao2_link(kqueue_timers, timer);
+	/* Get rid of the reference from the allocation */
+	ao2_ref(timer, -1);
+	return handle;
 }
 
-static void kqueue_timer_close(void *data)
+static void kqueue_timer_close(int handle)
 {
-	struct kqueue_timer *timer = data;
+	struct kqueue_timer *our_timer;
 
-	ao2_ref(timer, -1);
+	if (!(our_timer = lookup_timer(handle))) {
+		return;
+	}
+
+	ao2_unlink(kqueue_timers, our_timer);
+	ao2_ref(our_timer, -1);
 }
 
 static void kqueue_set_nsecs(struct kqueue_timer *our_timer, uint64_t nsecs)
@@ -144,90 +182,107 @@ static void kqueue_set_nsecs(struct kqueue_timer *our_timer, uint64_t nsecs)
 #endif
 }
 
-static int kqueue_timer_set_rate(void *data, unsigned int rate)
+static int kqueue_timer_set_rate(int handle, unsigned int rate)
 {
-	struct kqueue_timer *timer = data;
+	struct kqueue_timer *our_timer;
+
+	if (!(our_timer = lookup_timer(handle))) {
+		return -1;
+	}
 
-	kqueue_set_nsecs(timer, (timer->nsecs = rate ? (long) (1000000000 / rate) : 0L));
+	kqueue_set_nsecs(our_timer, (our_timer->nsecs = rate ? (long) (1000000000 / rate) : 0L));
+	ao2_ref(our_timer, -1);
 
 	return 0;
 }
 
-static int kqueue_timer_ack(void *data, unsigned int quantity)
+static int kqueue_timer_ack(int handle, unsigned int quantity)
 {
-	struct kqueue_timer *timer = data;
+	struct kqueue_timer *our_timer;
+
+	if (!(our_timer = lookup_timer(handle))) {
+		return -1;
+	}
 
-	if (timer->unacked < quantity) {
+	if (our_timer->unacked < quantity) {
 		ast_debug(1, "Acking more events than have expired?!!\n");
-		timer->unacked = 0;
+		our_timer->unacked = 0;
+		ao2_ref(our_timer, -1);
 		return -1;
 	} else {
-		timer->unacked -= quantity;
+		our_timer->unacked -= quantity;
 	}
 
+	ao2_ref(our_timer, -1);
 	return 0;
 }
 
-static int kqueue_timer_enable_continuous(void *data)
+static int kqueue_timer_enable_continuous(int handle)
 {
-	struct kqueue_timer *timer = data;
+	struct kqueue_timer *our_timer;
 
-	kqueue_set_nsecs(timer, 1);
-	timer->is_continuous = 1;
-	timer->unacked = 0;
+	if (!(our_timer = lookup_timer(handle))) {
+		return -1;
+	}
 
+	kqueue_set_nsecs(our_timer, 1);
+	our_timer->is_continuous = 1;
+	our_timer->unacked = 0;
+	ao2_ref(our_timer, -1);
 	return 0;
 }
 
-static int kqueue_timer_disable_continuous(void *data)
+static int kqueue_timer_disable_continuous(int handle)
 {
-	struct kqueue_timer *timer = data;
+	struct kqueue_timer *our_timer;
 
-	kqueue_set_nsecs(timer, timer->nsecs);
-	timer->is_continuous = 0;
-	timer->unacked = 0;
+	if (!(our_timer = lookup_timer(handle))) {
+		return -1;
+	}
 
+	kqueue_set_nsecs(our_timer, our_timer->nsecs);
+	our_timer->is_continuous = 0;
+	our_timer->unacked = 0;
+	ao2_ref(our_timer, -1);
 	return 0;
 }
 
-static enum ast_timer_event kqueue_timer_get_event(void *data)
+static enum ast_timer_event kqueue_timer_get_event(int handle)
 {
-	struct kqueue_timer *timer = data;
 	enum ast_timer_event res = -1;
+	struct kqueue_timer *our_timer;
 	struct timespec sixty_seconds = { 60, 0 };
 	struct kevent kev;
 
+	if (!(our_timer = lookup_timer(handle))) {
+		return -1;
+	}
+
 	/* If we have non-ACKed events, just return immediately */
-	if (timer->unacked == 0) {
-		if (kevent(timer->handle, NULL, 0, &kev, 1, &sixty_seconds) > 0) {
-			timer->unacked += kev.data;
+	if (our_timer->unacked == 0) {
+		if (kevent(handle, NULL, 0, &kev, 1, &sixty_seconds) > 0) {
+			our_timer->unacked += kev.data;
 		}
 	}
 
-	if (timer->unacked > 0) {
-		res = timer->is_continuous ? AST_TIMING_EVENT_CONTINUOUS : AST_TIMING_EVENT_EXPIRED;
+	if (our_timer->unacked > 0) {
+		res = our_timer->is_continuous ? AST_TIMING_EVENT_CONTINUOUS : AST_TIMING_EVENT_EXPIRED;
 	}
 
+	ao2_ref(our_timer, -1);
 	return res;
 }
 
-static unsigned int kqueue_timer_get_max_rate(void *data)
+static unsigned int kqueue_timer_get_max_rate(int handle)
 {
 	/* Actually, the max rate is 2^64-1 seconds, but that's not representable in a 32-bit integer. */
 	return UINT_MAX;
 }
 
-static int kqueue_timer_fd(void *data)
-{
-	struct kqueue_timer *timer = data;
-
-	return timer->handle;
-}
-
 #ifdef TEST_FRAMEWORK
 AST_TEST_DEFINE(test_kqueue_timing)
 {
-	int res = AST_TEST_PASS, i;
+	int res = AST_TEST_PASS, handle, i;
 	uint64_t diff;
 	struct pollfd pfd = { 0, POLLIN, 0 };
 	struct kqueue_timer *kt;
@@ -244,14 +299,14 @@ AST_TEST_DEFINE(test_kqueue_timing)
 		break;
 	}
 
-	if (!(kt = kqueue_timer_open())) {
+	if (!(handle = kqueue_timer_open())) {
 		ast_test_status_update(test, "Cannot open timer!\n");
 		return AST_TEST_FAIL;
 	}
 
 	do {
-		pfd.fd = ast_timer_fd(kt);
-		if (kqueue_timer_set_rate(kt, 1000)) {
+		pfd.fd = handle;
+		if (kqueue_timer_set_rate(handle, 1000)) {
 			ast_test_status_update(test, "Cannot set timer rate to 1000/s\n");
 			res = AST_TEST_FAIL;
 			break;
@@ -266,7 +321,12 @@ AST_TEST_DEFINE(test_kqueue_timing)
 			res = AST_TEST_FAIL;
 			break;
 		}
-		if (kqueue_timer_get_event(kt) <= 0) {
+		if (!(kt = lookup_timer(handle))) {
+			ast_test_status_update(test, "Could not find timer structure in container?!!\n");
+			res = AST_TEST_FAIL;
+			break;
+		}
+		if (kqueue_timer_get_event(handle) <= 0) {
 			ast_test_status_update(test, "No events generated after a poll returned successfully?!!\n");
 			res = AST_TEST_FAIL;
 			break;
@@ -278,7 +338,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
 			break;
 		}
 #endif
-		kqueue_timer_enable_continuous(kt);
+		kqueue_timer_enable_continuous(handle);
 		start = ast_tvnow();
 		for (i = 0; i < 100; i++) {
 			if (ast_poll(&pfd, 1, 1000) < 1) {
@@ -286,7 +346,7 @@ AST_TEST_DEFINE(test_kqueue_timing)
 				res = AST_TEST_FAIL;
 				break;
 			}
-			if (kqueue_timer_get_event(kt) <= 0) {
+			if (kqueue_timer_get_event(handle) <= 0) {
 				ast_test_status_update(test, "No events generated in continuous mode after 1 microsecond?!!\n");
 				res = AST_TEST_FAIL;
 				break;
@@ -301,24 +361,19 @@ AST_TEST_DEFINE(test_kqueue_timing)
 		}
 		*/
 	} while (0);
-	kqueue_timer_close(kt);
+	kqueue_timer_close(handle);
 	return res;
 }
 #endif
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
+	if (!(kqueue_timers = ao2_container_alloc(563, kqueue_timer_hash, kqueue_timer_cmp))) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	if (!(timing_funcs_handle = ast_register_timing_interface(&kqueue_timing))) {
+		ao2_ref(kqueue_timers, -1);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -328,13 +383,18 @@ static int load_module(void)
 
 static int unload_module(void)
 {
+	int res;
+
 	AST_TEST_UNREGISTER(test_kqueue_timing);
+	if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
+		ao2_ref(kqueue_timers, -1);
+		kqueue_timers = NULL;
+	}
 
-	return ast_unregister_timing_interface(timing_funcs_handle);
+	return res;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "KQueue Timing Interface",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c
index 100b652..55ed6ac 100644
--- a/res/res_timing_pthread.c
+++ b/res/res_timing_pthread.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include <stdbool.h>
 #include <math.h>
@@ -45,15 +45,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $");
 
 static void *timing_funcs_handle;
 
-static void *pthread_timer_open(void);
-static void pthread_timer_close(void *data);
-static int pthread_timer_set_rate(void *data, unsigned int rate);
-static int pthread_timer_ack(void *data, unsigned int quantity);
-static int pthread_timer_enable_continuous(void *data);
-static int pthread_timer_disable_continuous(void *data);
-static enum ast_timer_event pthread_timer_get_event(void *data);
-static unsigned int pthread_timer_get_max_rate(void *data);
-static int pthread_timer_fd(void *data);
+static int pthread_timer_open(void);
+static void pthread_timer_close(int handle);
+static int pthread_timer_set_rate(int handle, unsigned int rate);
+static int pthread_timer_ack(int handle, unsigned int quantity);
+static int pthread_timer_enable_continuous(int handle);
+static int pthread_timer_disable_continuous(int handle);
+static enum ast_timer_event pthread_timer_get_event(int handle);
+static unsigned int pthread_timer_get_max_rate(int handle);
 
 static struct ast_timing_interface pthread_timing = {
 	.name = "pthread",
@@ -66,7 +65,6 @@ static struct ast_timing_interface pthread_timing = {
 	.timer_disable_continuous = pthread_timer_disable_continuous,
 	.timer_get_event = pthread_timer_get_event,
 	.timer_get_max_rate = pthread_timer_get_max_rate,
-	.timer_fd = pthread_timer_fd,
 };
 
 /* 1 tick / 10 ms */
@@ -99,6 +97,7 @@ struct pthread_timer {
 };
 
 static void pthread_timer_destructor(void *obj);
+static struct pthread_timer *find_timer(int handle, int unlinkobj);
 static void signal_pipe(struct pthread_timer *timer);
 static void unsignal_pipe(struct pthread_timer *timer);
 static void ack_ticks(struct pthread_timer *timer, unsigned int num);
@@ -113,14 +112,15 @@ static struct {
 	unsigned int stop:1;
 } timing_thread;
 
-static void *pthread_timer_open(void)
+static int pthread_timer_open(void)
 {
 	struct pthread_timer *timer;
+	int fd;
 	int i;
 
 	if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) {
 		errno = ENOMEM;
-		return NULL;
+		return -1;
 	}
 
 	timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1;
@@ -128,7 +128,7 @@ static void *pthread_timer_open(void)
 
 	if (pipe(timer->pipe)) {
 		ao2_ref(timer, -1);
-		return NULL;
+		return -1;
 	}
 
 	for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) {
@@ -146,19 +146,32 @@ static void *pthread_timer_open(void)
 	ao2_link(pthread_timers, timer);
 	ao2_unlock(pthread_timers);
 
-	return timer;
+	fd = timer->pipe[PIPE_READ];
+
+	ao2_ref(timer, -1);
+
+	return fd;
 }
 
-static void pthread_timer_close(void *data)
+static void pthread_timer_close(int handle)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
+
+	if (!(timer = find_timer(handle, 1))) {
+		return;
+	}
 
 	ao2_ref(timer, -1);
 }
 
-static int pthread_timer_set_rate(void *data, unsigned int rate)
+static int pthread_timer_set_rate(int handle, unsigned int rate)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
+
+	if (!(timer = find_timer(handle, 0))) {
+		errno = EINVAL;
+		return -1;
+	}
 
 	if (rate > MAX_RATE) {
 		ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a "
@@ -182,25 +195,38 @@ static int pthread_timer_set_rate(void *data, unsigned int rate)
 
 	ao2_unlock(timer);
 
+	ao2_ref(timer, -1);
+
 	return 0;
 }
 
-static int pthread_timer_ack(void *data, unsigned int quantity)
+static int pthread_timer_ack(int handle, unsigned int quantity)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
 
 	ast_assert(quantity > 0);
 
+	if (!(timer = find_timer(handle, 0))) {
+		return -1;
+	}
+
 	ao2_lock(timer);
 	ack_ticks(timer, quantity);
 	ao2_unlock(timer);
 
+	ao2_ref(timer, -1);
+
 	return 0;
 }
 
-static int pthread_timer_enable_continuous(void *data)
+static int pthread_timer_enable_continuous(int handle)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
+
+	if (!(timer = find_timer(handle, 0))) {
+		errno = EINVAL;
+		return -1;
+	}
 
 	ao2_lock(timer);
 	if (!timer->continuous) {
@@ -209,12 +235,19 @@ static int pthread_timer_enable_continuous(void *data)
 	}
 	ao2_unlock(timer);
 
+	ao2_ref(timer, -1);
+
 	return 0;
 }
 
-static int pthread_timer_disable_continuous(void *data)
+static int pthread_timer_disable_continuous(int handle)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
+
+	if (!(timer = find_timer(handle, 0))) {
+		errno = EINVAL;
+		return -1;
+	}
 
 	ao2_lock(timer);
 	if (timer->continuous) {
@@ -223,33 +256,54 @@ static int pthread_timer_disable_continuous(void *data)
 	}
 	ao2_unlock(timer);
 
+	ao2_ref(timer, -1);
+
 	return 0;
 }
 
-static enum ast_timer_event pthread_timer_get_event(void *data)
+static enum ast_timer_event pthread_timer_get_event(int handle)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
 	enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED;
 
+	if (!(timer = find_timer(handle, 0))) {
+		return res;
+	}
+
 	ao2_lock(timer);
 	if (timer->continuous) {
 		res = AST_TIMING_EVENT_CONTINUOUS;
 	}
 	ao2_unlock(timer);
 
+	ao2_ref(timer, -1);
+
 	return res;
 }
 
-static unsigned int pthread_timer_get_max_rate(void *data)
+static unsigned int pthread_timer_get_max_rate(int handle)
 {
 	return MAX_RATE;
 }
 
-static int pthread_timer_fd(void *data)
+static struct pthread_timer *find_timer(int handle, int unlinkobj)
 {
-	struct pthread_timer *timer = data;
+	struct pthread_timer *timer;
+	struct pthread_timer tmp_timer;
+	int flags = OBJ_POINTER;
 
-	return timer->pipe[PIPE_READ];
+	tmp_timer.pipe[PIPE_READ] = handle;
+
+	if (unlinkobj) {
+		flags |= OBJ_UNLINK;
+	}
+
+	if (!(timer = ao2_find(pthread_timers, &tmp_timer, flags))) {
+		ast_assert(timer != NULL);
+		return NULL;
+	}
+
+	return timer;
 }
 
 static void pthread_timer_destructor(void *obj)
@@ -476,7 +530,6 @@ static int unload_module(void)
 	return res;
 }
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "pthread Timing Interface",
-		.support_level = AST_MODULE_SUPPORT_EXTENDED,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_TIMING,
diff --git a/res/res_timing_timerfd.c b/res/res_timing_timerfd.c
index 6d5400b..41b5f7d 100644
--- a/res/res_timing_timerfd.c
+++ b/res/res_timing_timerfd.c
@@ -41,15 +41,14 @@
 
 static void *timing_funcs_handle;
 
-static void *timerfd_timer_open(void);
-static void timerfd_timer_close(void *data);
-static int timerfd_timer_set_rate(void *data, unsigned int rate);
-static int timerfd_timer_ack(void *data, unsigned int quantity);
-static int timerfd_timer_enable_continuous(void *data);
-static int timerfd_timer_disable_continuous(void *data);
-static enum ast_timer_event timerfd_timer_get_event(void *data);
-static unsigned int timerfd_timer_get_max_rate(void *data);
-static int timerfd_timer_fd(void *data);
+static int timerfd_timer_open(void);
+static void timerfd_timer_close(int handle);
+static int timerfd_timer_set_rate(int handle, unsigned int rate);
+static int timerfd_timer_ack(int handle, unsigned int quantity);
+static int timerfd_timer_enable_continuous(int handle);
+static int timerfd_timer_disable_continuous(int handle);
+static enum ast_timer_event timerfd_timer_get_event(int handle);
+static unsigned int timerfd_timer_get_max_rate(int handle);
 
 static struct ast_timing_interface timerfd_timing = {
 	.name = "timerfd",
@@ -62,93 +61,153 @@ static struct ast_timing_interface timerfd_timing = {
 	.timer_disable_continuous = timerfd_timer_disable_continuous,
 	.timer_get_event = timerfd_timer_get_event,
 	.timer_get_max_rate = timerfd_timer_get_max_rate,
-	.timer_fd = timerfd_timer_fd,
 };
 
+static struct ao2_container *timerfd_timers;
+
+#define TIMERFD_TIMER_BUCKETS 563
 #define TIMERFD_MAX_RATE 1000
 
 struct timerfd_timer {
-	int fd;
+	int handle;
 	struct itimerspec saved_timer;
 	unsigned int is_continuous:1;
 };
 
+static int timerfd_timer_hash(const void *obj, const int flags)
+{
+	const struct timerfd_timer *timer = obj;
+
+	return timer->handle;
+}
+
+static int timerfd_timer_cmp(void *obj, void *args, int flags)
+{
+	struct timerfd_timer *timer1 = obj, *timer2 = args;
+	return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
+}
+
 static void timer_destroy(void *obj)
 {
 	struct timerfd_timer *timer = obj;
-
-	close(timer->fd);
+	if (timer->handle > -1) {
+		close(timer->handle);
+	}
+	timer->handle = -1;
 }
 
-static void *timerfd_timer_open(void)
+static int timerfd_timer_open(void)
 {
 	struct timerfd_timer *timer;
+	int handle;
 
 	if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
 		ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
-		return NULL;
+		return -1;
 	}
-	if ((timer->fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
+	if ((timer->handle = handle = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
 		ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
 		ao2_ref(timer, -1);
-		return NULL;
+		return -1;
 	}
 
-	return timer;
+	ao2_link(timerfd_timers, timer);
+	/* Get rid of the reference from the allocation */
+	ao2_ref(timer, -1);
+	return handle;
 }
 
-static void timerfd_timer_close(void *data)
+static void timerfd_timer_close(int handle)
 {
-	ao2_ref(data, -1);
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
+
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to close timerfd handle -1");
+		return;
+	}
+
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
+		return;
+	}
+
+	ao2_unlink(timerfd_timers, our_timer);
+	ao2_ref(our_timer, -1);
 }
 
-static int timerfd_timer_set_rate(void *data, unsigned int rate)
+static int timerfd_timer_set_rate(int handle, unsigned int rate)
 {
-	struct timerfd_timer *timer = data;
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
 	int res = 0;
 
-	ao2_lock(timer);
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1");
+		return -1;
+	}
+
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
+		return -1;
+	}
+	ao2_lock(our_timer);
 
-	timer->saved_timer.it_value.tv_sec = 0;
-	timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
-	timer->saved_timer.it_interval.tv_sec = timer->saved_timer.it_value.tv_sec;
-	timer->saved_timer.it_interval.tv_nsec = timer->saved_timer.it_value.tv_nsec;
+	our_timer->saved_timer.it_value.tv_sec = 0;
+	our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
+	our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec;
+	our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec;
 
-	if (!timer->is_continuous) {
-		res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
+	if (!our_timer->is_continuous) {
+		res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
 	}
 
-	ao2_unlock(timer);
+	ao2_unlock(our_timer);
+	ao2_ref(our_timer, -1);
 
 	return res;
 }
 
-static int timerfd_timer_ack(void *data, unsigned int quantity)
+static int timerfd_timer_ack(int handle, unsigned int quantity)
 {
-	struct timerfd_timer *timer = data;
 	uint64_t expirations;
 	int read_result = 0;
 	int res = 0;
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
+
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to ack timerfd handle -1");
+		return -1;
+	}
 
-	ao2_lock(timer);
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle);
+		return -1;
+	}
+
+	ao2_lock(our_timer);
 
 	do {
 		struct itimerspec timer_status;
 
-		if (timerfd_gettime(timer->fd, &timer_status)) {
-			ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno));
+		if (timerfd_gettime(handle, &timer_status)) {
+			ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", handle, strerror(errno));
 			expirations = 0;
 			res = -1;
 			break;
 		}
 
 		if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
-			ast_debug(1, "Avoiding read on disarmed timerfd %d\n", timer->fd);
+			ast_debug(1, "Avoiding read on disarmed timerfd %d\n", handle);
 			expirations = 0;
 			break;
 		}
 
-		read_result = read(timer->fd, &expirations, sizeof(expirations));
+		read_result = read(handle, &expirations, sizeof(expirations));
 		if (read_result == -1) {
 			if (errno == EINTR || errno == EAGAIN) {
 				continue;
@@ -160,93 +219,121 @@ static int timerfd_timer_ack(void *data, unsigned int quantity)
 		}
 	} while (read_result != sizeof(expirations));
 
-	ao2_unlock(timer);
+	ao2_unlock(our_timer);
+	ao2_ref(our_timer, -1);
 
 	if (expirations != quantity) {
 		ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
 	}
-
 	return res;
 }
 
-static int timerfd_timer_enable_continuous(void *data)
+static int timerfd_timer_enable_continuous(int handle)
 {
-	struct timerfd_timer *timer = data;
 	int res;
-	static const struct itimerspec continuous_timer = {
+	struct itimerspec continuous_timer = {
 		.it_value.tv_nsec = 1L,
 	};
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
+
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to enable timerfd handle -1");
+		return -1;
+	}
 
-	ao2_lock(timer);
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
+		return -1;
+	}
+	ao2_lock(our_timer);
 
-	if (timer->is_continuous) {
+	if (our_timer->is_continuous) {
 		/*It's already in continous mode, no need to do
 		 * anything further
 		 */
-		ao2_unlock(timer);
+		ao2_unlock(our_timer);
+		ao2_ref(our_timer, -1);
 		return 0;
 	}
 
-	res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer);
-	timer->is_continuous = 1;
-	ao2_unlock(timer);
-
+	res = timerfd_settime(handle, 0, &continuous_timer, &our_timer->saved_timer);
+	our_timer->is_continuous = 1;
+	ao2_unlock(our_timer);
+	ao2_ref(our_timer, -1);
 	return res;
 }
 
-static int timerfd_timer_disable_continuous(void *data)
+static int timerfd_timer_disable_continuous(int handle)
 {
-	struct timerfd_timer *timer = data;
 	int res;
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
+
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to disable timerfd handle -1");
+		return -1;
+	}
 
-	ao2_lock(timer);
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
+		return -1;
+	}
+	ao2_lock(our_timer);
 
-	if (!timer->is_continuous) {
+	if (!our_timer->is_continuous) {
 		/* No reason to do anything if we're not
 		 * in continuous mode
 		 */
-		ao2_unlock(timer);
+		ao2_unlock(our_timer);
+		ao2_ref(our_timer, -1);
 		return 0;
 	}
 
-	res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
-	timer->is_continuous = 0;
-	memset(&timer->saved_timer, 0, sizeof(timer->saved_timer));
-	ao2_unlock(timer);
-
+	res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
+	our_timer->is_continuous = 0;
+	memset(&our_timer->saved_timer, 0, sizeof(our_timer->saved_timer));
+	ao2_unlock(our_timer);
+	ao2_ref(our_timer, -1);
 	return res;
 }
 
-static enum ast_timer_event timerfd_timer_get_event(void *data)
+static enum ast_timer_event timerfd_timer_get_event(int handle)
 {
-	struct timerfd_timer *timer = data;
 	enum ast_timer_event res;
+	struct timerfd_timer *our_timer, find_helper = {
+		.handle = handle,
+	};
 
-	ao2_lock(timer);
+	if (handle == -1) {
+		ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1");
+		return -1;
+	}
+
+	if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+		ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
+		return -1;
+	}
+	ao2_lock(our_timer);
 
-	if (timer->is_continuous) {
+	if (our_timer->is_continuous) {
 		res = AST_TIMING_EVENT_CONTINUOUS;
 	} else {
 		res = AST_TIMING_EVENT_EXPIRED;
 	}
 
-	ao2_unlock(timer);
-
+	ao2_unlock(our_timer);
+	ao2_ref(our_timer, -1);
 	return res;
 }
 
-static unsigned int timerfd_timer_get_max_rate(void *data)
+static unsigned int timerfd_timer_get_max_rate(int handle)
 {
 	return TIMERFD_MAX_RATE;
 }
 
-static int timerfd_timer_fd(void *data)
-{
-	struct timerfd_timer *timer = data;
-
-	return timer->fd;
-}
-
 static int load_module(void)
 {
 	int fd;
@@ -259,7 +346,12 @@ static int load_module(void)
 
 	close(fd);
 
+	if (!(timerfd_timers = ao2_container_alloc(TIMERFD_TIMER_BUCKETS, timerfd_timer_hash, timerfd_timer_cmp))) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
+		ao2_ref(timerfd_timers, -1);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -268,11 +360,17 @@ static int load_module(void)
 
 static int unload_module(void)
 {
-	return ast_unregister_timing_interface(timing_funcs_handle);
+	int res;
+
+	if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
+		ao2_ref(timerfd_timers, -1);
+		timerfd_timers = NULL;
+	}
+
+	return res;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_TIMING,
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index c9f9132..df04662 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -22,7 +22,7 @@
  *
  * \author Joshua Colp <jcolp at digium.com>
  *
- * Iksemel http://code.google.com/p/iksemel/
+ * \extref Iksemel http://code.google.com/p/iksemel/
  *
  * A reference module for interfacting Asterisk directly as a client or component with
  * an XMPP/Jabber compliant server.
@@ -31,15 +31,6 @@
  *
  */
 
-/*! \li \ref res_xmpp.c uses the configuration file \ref xmpp.conf and \ref jabber.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page xmpp.conf xmpp.conf
- * \verbinclude xmpp.conf.sample
- */
-
 /*** MODULEINFO
 	<depend>iksemel</depend>
 	<use type="external">openssl</use>
@@ -48,7 +39,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <ctype.h>
 #include <iksemel.h>
@@ -59,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 #include "asterisk/app.h"
 #include "asterisk/message.h"
 #include "asterisk/manager.h"
+#include "asterisk/event.h"
 #include "asterisk/cli.h"
 #include "asterisk/config_options.h"
 
@@ -287,126 +279,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428687 $")
 		account defined in <literal>xmpp.conf</literal> to send the message from.
 		Note that this field is required for XMPP messages.</para>
 	</info>
-	<configInfo name="res_xmpp" language="en_US">
-		<synopsis>XMPP Messaging</synopsis>
-		<configFile name="xmpp.conf">
-			<configObject name="global">
-				<synopsis>Global configuration settings</synopsis>
-				<configOption name="debug">
-					<synopsis>Enable/disable XMPP message debugging</synopsis>
-				</configOption>
-				<configOption name="autoprune">
-					<synopsis>Auto-remove users from buddy list.</synopsis>
-					<description><para>Auto-remove users from buddy list. Depending on the setup
-					(e.g., using your personal Gtalk account for a test) this could cause loss of
-					the contact list.
-					</para></description>
-				</configOption>
-				<configOption name="autoregister">
-					<synopsis>Auto-register users from buddy list</synopsis>
-				</configOption>
-				<configOption name="collection_nodes">
-					<synopsis>Enable support for XEP-0248 for use with distributed device state</synopsis>
-				</configOption>
-				<configOption name="pubsub_autocreate">
-					<synopsis>Whether or not the PubSub server supports/is using auto-create for nodes</synopsis>
-				</configOption>
-				<configOption name="auth_policy">
-					<synopsis>Whether to automatically accept or deny users' subscription requests</synopsis>
-				</configOption>
-			</configObject>
-			<configObject name="client">
-				<synopsis>Configuration options for an XMPP client</synopsis>
-				<configOption name="username">
-					<synopsis>XMPP username with optional resource</synopsis>
-				</configOption>
-				<configOption name="secret">
-					<synopsis>XMPP password</synopsis>
-				</configOption>
-				<configOption name="serverhost">
-					<synopsis>Route to server, e.g. talk.google.com</synopsis>
-				</configOption>
-				<configOption name="statusmessage">
-					<synopsis>Custom status message</synopsis>
-				</configOption>
-				<configOption name="pubsub_node">
-					<synopsis>Node for publishing events via PubSub</synopsis>
-				</configOption>
-				<configOption name="context">
-					<synopsis>Dialplan context to send incoming messages to</synopsis>
-				</configOption>
-				<configOption name="priority">
-					<synopsis>XMPP resource priority</synopsis>
-				</configOption>
-				<configOption name="port">
-					<synopsis>XMPP server port</synopsis>
-				</configOption>
-				<configOption name="timeout">
-					<synopsis>Timeout in seconds to hold incoming messages</synopsis>
-					<description><para>Timeout (in seconds) on the message stack. Messages stored longer
-					than this value will be deleted by Asterisk. This option applies to incoming messages only
-					which are intended to be processed by the <literal>JABBER_RECEIVE</literal> dialplan function.
-					</para></description>
-				</configOption>
-				<configOption name="debug">
-					<synopsis>Enable debugging</synopsis>
-				</configOption>
-				<configOption name="type">
-					<synopsis>Connection is either a client or a component</synopsis>
-				</configOption>
-				<configOption name="distribute_events">
-					<synopsis>Whether or not to distribute events using this connection</synopsis>
-				</configOption>
-				<configOption name="usetls">
-					<synopsis>Whether to use TLS for the connection or not</synopsis>
-				</configOption>
-				<configOption name="usesasl">
-					<synopsis>Whether to use SASL for the connection or not</synopsis>
-				</configOption>
-				<configOption name="forceoldssl">
-					<synopsis>Force the use of old-style SSL for the connection</synopsis>
-				</configOption>
-				<configOption name="keepalive">
-					<synopsis>If enabled, periodically send an XMPP message from this client with an empty message</synopsis>
-				</configOption>
-				<configOption name="autoprune">
-					<synopsis>Auto-remove users from buddy list.</synopsis>
-					<description><para>Auto-remove users from buddy list. Depending on the setup
-					(e.g., using your personal Gtalk account for a test) this could cause loss of
-					the contact list.
-					</para></description>
-				</configOption>
-				<configOption name="autoregister">
-					<synopsis>Auto-register users bfrom buddy list</synopsis>
-				</configOption>
-				<configOption name="auth_policy">
-					<synopsis>Whether to automatically accept or deny users' subscription requests</synopsis>
-				</configOption>
-				<configOption name="sendtodialplan">
-					<synopsis>Send incoming messages into the dialplan</synopsis>
-				</configOption>
-				<configOption name="status">
-					<synopsis>Default XMPP status for the client</synopsis>
-					<description><para>Can be one of the following XMPP statuses:</para>
-						<enumlist>
-							<enum name="chat"/>
-							<enum name="available"/>
-							<enum name="away"/>
-							<enum name="xaway"/>
-							<enum name="dnd"/>
-						</enumlist>
-					</description>
-				</configOption>
-				<configOption name="buddy">
-					<synopsis>Manual addition of buddy to list</synopsis>
-					<description><para>
-					Manual addition of buddy to the buddy list. For distributed events, these budies are
-					automatically added in the whitelist as 'owners' of the node(s).
-					</para></description>
-				</configOption>
-			</configObject>
-		</configFile>
-	</configInfo>
 ***/
 
 /*! \brief Supported general configuration flags */
@@ -470,6 +342,7 @@ struct ast_xmpp_client_config {
 	int message_timeout;            /*!< Timeout for messages */
 	int priority;                   /*!< Resource priority */
 	struct ast_flags flags;         /*!< Various options that have been set */
+	struct ast_flags mod_flags;     /*!< Global options that have been modified */
 	enum ikshowtype status;         /*!< Presence status */
 	struct ast_xmpp_client *client; /*!< Pointer to the client */
 	struct ao2_container *buddies;  /*!< Configured buddies */
@@ -559,10 +432,6 @@ static void xmpp_client_destructor(void *obj)
 
 	ast_xmpp_client_disconnect(client);
 
-	ast_endpoint_shutdown(client->endpoint);
-	ao2_cleanup(client->endpoint);
-	client->endpoint = NULL;
-
 	if (client->filter) {
 		iks_filter_delete(client->filter);
 	}
@@ -597,20 +466,6 @@ static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
 	return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
 }
 
-/*! \brief Internal function which changes the XMPP client state */
-static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
-{
-	if (state == client->state) {
-		return;
-	}
-	client->state = state;
-	if (client->state == XMPP_STATE_DISCONNECTED) {
-		ast_endpoint_set_state(client->endpoint, AST_ENDPOINT_OFFLINE);
-	} else if (client->state == XMPP_STATE_CONNECTED) {
-		ast_endpoint_set_state(client->endpoint, AST_ENDPOINT_ONLINE);
-	}
-}
-
 /*! \brief Allocator function for ast_xmpp_client */
 static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
 {
@@ -623,12 +478,6 @@ static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
 	AST_LIST_HEAD_INIT(&client->messages);
 	client->thread = AST_PTHREADT_NULL;
 
-	client->endpoint = ast_endpoint_create("XMPP", name);
-	if (!client->endpoint) {
-		ao2_ref(client, -1);
-		return NULL;
-	}
-
 	if (!(client->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
 		ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
 		ao2_ref(client, -1);
@@ -650,7 +499,7 @@ static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
 	ast_string_field_set(client, name, name);
 
 	client->timeout = 50;
-	xmpp_client_change_state(client, XMPP_STATE_DISCONNECTED);
+	client->state = XMPP_STATE_DISCONNECTED;
 	ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
 
 	return client;
@@ -742,8 +591,6 @@ static void *xmpp_config_alloc(void)
 		goto error;
 	}
 
-	ast_set_flag(&cfg->global->general, XMPP_AUTOREGISTER | XMPP_AUTOACCEPT | XMPP_USETLS | XMPP_USESASL | XMPP_KEEPALIVE);
-
 	if (!(cfg->clients = ao2_container_alloc(1, xmpp_config_hash, xmpp_config_cmp))) {
 		goto error;
 	}
@@ -801,7 +648,6 @@ static void xmpp_config_post_apply(void)
 
 static struct aco_type global_option = {
 	.type = ACO_GLOBAL,
-	.name = "global",
 	.item_offset = offsetof(struct xmpp_config, global),
 	.category_match = ACO_WHITELIST,
 	.category = "^general$",
@@ -811,7 +657,6 @@ struct aco_type *global_options[] = ACO_TYPES(&global_option);
 
 static struct aco_type client_option = {
 	.type = ACO_ITEM,
-	.name = "client",
 	.category_match = ACO_BLACKLIST,
 	.category = "^(general)$",
 	.item_alloc = ast_xmpp_client_config_alloc,
@@ -1196,7 +1041,6 @@ static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, cons
  * \param client the configured XMPP client we use to connect to a XMPP server
  * \param node_type the type of node to create
  * \param name the name of the node to create
- * \param collection_name
  * \return void
  */
 static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const
@@ -1256,7 +1100,6 @@ static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const
 /*!
  * \brief Create a PubSub leaf node.
  * \param client the configured XMPP client we use to connect to a XMPP server
- * \param collection_name
  * \param leaf_name The name to use for this collection
  * \return void.
  */
@@ -1269,20 +1112,19 @@ static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *
 /*!
  * \brief Publish MWI to a PubSub node
  * \param client the configured XMPP client we use to connect to a XMPP server
- * \param mailbox The mailbox identifier
- * \param oldmsgs Old messages
- * \param newmsgs New Messages
+ * \param device the name of the device whose state to publish
+ * \param device_state the state to publish
  * \return void
  */
 static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox,
-	const char *oldmsgs, const char *newmsgs)
+				    const char *context, const char *oldmsgs, const char *newmsgs)
 {
-	char eid_str[20];
+	char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT], eid_str[20];
 	iks *mailbox_node, *request;
 
-	request = xmpp_pubsub_build_publish_skeleton(client, mailbox, "message_waiting",
-		AST_DEVSTATE_CACHABLE);
-	if (!request) {
+	snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
+
+	if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting", AST_DEVSTATE_CACHABLE))) {
 		return;
 	}
 
@@ -1341,26 +1183,25 @@ static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, con
  * \param data void pointer to ast_client structure
  * \return void
  */
-static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
+static void xmpp_pubsub_mwi_cb(const struct ast_event *ast_event, void *data)
 {
 	struct ast_xmpp_client *client = data;
+	const char *mailbox, *context;
 	char oldmsgs[10], newmsgs[10];
-	struct ast_mwi_state *mwi_state;
-
-	if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	mwi_state = stasis_message_data(msg);
 
-	if (ast_eid_cmp(&ast_eid_default, &mwi_state->eid)) {
+	if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
 		/* If the event didn't originate from this server, don't send it back out. */
+		ast_debug(1, "Returning here\n");
 		return;
 	}
 
-	snprintf(oldmsgs, sizeof(oldmsgs), "%d", mwi_state->old_msgs);
-	snprintf(newmsgs, sizeof(newmsgs), "%d", mwi_state->new_msgs);
-	xmpp_pubsub_publish_mwi(client, mwi_state->uniqueid, oldmsgs, newmsgs);
+	mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
+	context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
+	snprintf(oldmsgs, sizeof(oldmsgs), "%u",
+		 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
+	snprintf(newmsgs, sizeof(newmsgs), "%u",
+		 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
+	xmpp_pubsub_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
 }
 
 /*!
@@ -1369,22 +1210,22 @@ static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, stru
  * \param data void pointer to ast_client structure
  * \return void
  */
-static void xmpp_pubsub_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
+static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *data)
 {
 	struct ast_xmpp_client *client = data;
-	struct ast_device_state_message *dev_state;
+	const char *device, *device_state;
+	unsigned int cachable;
 
-	if (!stasis_subscription_is_subscribed(sub) || ast_device_state_message_type() != stasis_message_type(msg)) {
-		return;
-	}
-
-	dev_state = stasis_message_data(msg);
-	if (!dev_state->eid || ast_eid_cmp(&ast_eid_default, dev_state->eid)) {
-		/* If the event is aggregate or didn't originate from this server, don't send it out. */
+	if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
+		/* If the event didn't originate from this server, don't send it back out. */
+		ast_debug(1, "Returning here\n");
 		return;
 	}
 
-	xmpp_pubsub_publish_device_state(client, dev_state->device, ast_devstate_str(dev_state->state), dev_state->cachable);
+	device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
+	device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
+	cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
+	xmpp_pubsub_publish_device_state(client, device, device_state, cachable);
 }
 
 /*!
@@ -1463,7 +1304,6 @@ static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *no
 /*!
  * \brief Callback for handling PubSub events
  * \param data void pointer to ast_xmpp_client structure
- * \param pak A pak
  * \return IKS_FILTER_EAT
  */
 static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
@@ -1472,6 +1312,7 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
 	int oldmsgs, newmsgs;
 	iks *item, *item_content;
 	struct ast_eid pubsub_eid;
+	struct ast_event *event;
 	unsigned int cachable = AST_DEVSTATE_CACHABLE;
 	item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
 	if (!item) {
@@ -1490,25 +1331,39 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
 			sscanf(cachable_str, "%30u", &cachable);
 		}
 		device_state = iks_find_cdata(item, "state");
-		ast_publish_device_state_full(item_id,
-						ast_devstate_val(device_state),
-						cachable == AST_DEVSTATE_CACHABLE ? AST_DEVSTATE_CACHABLE : AST_DEVSTATE_NOT_CACHABLE,
-						&pubsub_eid);
-		return IKS_FILTER_EAT;
+		if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
+					    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
+					    AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
+					    AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+					    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
+					    AST_EVENT_IE_END))) {
+			return IKS_FILTER_EAT;
+		}
 	} else if (!strcasecmp(iks_name(item_content), "mailbox")) {
 		mailbox = strsep(&item_id, "@");
 		sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
 		sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
-
-		ast_publish_mwi_state_full(mailbox, item_id, newmsgs, oldmsgs, NULL, &pubsub_eid);
-
-		return IKS_FILTER_EAT;
+		if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, item_id,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, oldmsgs,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, newmsgs,
+			AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+			AST_EVENT_IE_END))) {
+			return IKS_FILTER_EAT;
+		}
 	} else {
 		ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
 			  iks_name(item_content));
 		return IKS_FILTER_EAT;
 	}
 
+	if (cachable == AST_DEVSTATE_CACHABLE) {
+		ast_event_queue_and_cache(event);
+	} else {
+		ast_event_queue(event);
+	}
+
 	return IKS_FILTER_EAT;
 }
 
@@ -1580,14 +1435,6 @@ static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
 	return IKS_FILTER_EAT;
 }
 
-static int cached_devstate_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_message *msg = obj;
-	struct ast_xmpp_client *client = arg;
-	xmpp_pubsub_devstate_cb(client, client->device_state_sub, msg);
-	return 0;
-}
-
 /*!
  * \brief Initialize collections for event distribution
  * \param client the configured XMPP client we use to connect to a XMPP server
@@ -1597,7 +1444,6 @@ static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
 {
 	RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
 	RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, cached, NULL, ao2_cleanup);
 
 	if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
 		return;
@@ -1606,17 +1452,24 @@ static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
 	xmpp_pubsub_unsubscribe(client, "device_state");
 	xmpp_pubsub_unsubscribe(client, "message_waiting");
 
-	if (!(client->mwi_sub = stasis_subscribe_pool(ast_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
+	if (!(client->mwi_sub = ast_event_subscribe(AST_EVENT_MWI, xmpp_pubsub_mwi_cb, "xmpp_pubsub_mwi_subscription",
+						    client, AST_EVENT_IE_END))) {
+		return;
+	}
+
+	if (ast_enable_distributed_devstate()) {
 		return;
 	}
+	
 
-	if (!(client->device_state_sub = stasis_subscribe(ast_device_state_topic_all(), xmpp_pubsub_devstate_cb, client))) {
-		client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
+	if (!(client->device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
+							     xmpp_pubsub_devstate_cb, "xmpp_pubsub_devstate_subscription", client, AST_EVENT_IE_END))) {
+		ast_event_unsubscribe(client->mwi_sub);
+		client->mwi_sub = NULL;
 		return;
 	}
 
-	cached = stasis_cache_dump(ast_device_state_cache(), NULL);
-	ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, client);
+	ast_event_dump_cache(client->device_state_sub);
 
 	xmpp_pubsub_subscribe(client, "device_state");
 	xmpp_pubsub_subscribe(client, "message_waiting");
@@ -2237,6 +2090,12 @@ static const struct ast_msg_tech msg_tech = {
 	.msg_send = xmpp_send_cb,
 };
 
+/*! \brief Internal function which changes the XMPP client state */
+static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
+{
+	client->state = state;
+}
+
 /*! \brief Internal function which creates a buddy on a client */
 static struct ast_xmpp_buddy *xmpp_client_create_buddy(struct ao2_container *container, const char *id)
 {
@@ -2550,6 +2409,10 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
 	RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
 	struct ast_xmpp_client *client = data;
 
+	if (!ast_strlen_zero(xmpp)) {
+		manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
+	}
+
 	if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
 		return;
 	}
@@ -3178,27 +3041,16 @@ static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_clie
 
 	if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
 		struct ast_msg *msg;
-		struct ast_xmpp_buddy *buddy;
 
 		if ((msg = ast_msg_alloc())) {
 			int res;
 
 			ast_xmpp_client_lock(client);
 
-			buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK);
-
 			res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
 			res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
 			res |= ast_msg_set_body(msg, "%s", message->message);
 			res |= ast_msg_set_context(msg, "%s", cfg->context);
-			res |= ast_msg_set_tech(msg, "%s", "XMPP");
-			res |= ast_msg_set_endpoint(msg, "%s", client->name);
-
-			if (buddy) {
-				res |= ast_msg_set_var(msg, "XMPP_BUDDY", buddy->id);
-			}
-
-			ao2_cleanup(buddy);
 
 			ast_xmpp_client_unlock(client);
 
@@ -3255,14 +3107,6 @@ static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, c
 	return res;
 }
 
-/*! \brief Callback function which returns when the resource is available */
-static int xmpp_resource_is_available(void *obj, void *arg, int flags)
-{
-	struct ast_xmpp_resource *resource = obj;
-
-	return (resource->status == IKS_SHOW_AVAILABLE) ? CMP_MATCH | CMP_STOP : 0;
-}
-
 /*! \brief Helper function which sends a ping request to a server */
 static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, const char *from)
 {
@@ -3304,7 +3148,6 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli
 	struct ast_xmpp_resource *resource;
 	char *type = iks_find_attrib(pak->x, "type");
 	int status = pak->show ? pak->show : STATUS_DISAPPEAR;
-	enum ast_device_state state = AST_DEVICE_UNAVAILABLE;
 
 	/* If no resource is available this is a general buddy presence update, which we will ignore */
 	if (!pak->from->resource) {
@@ -3411,18 +3254,10 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli
 			      client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
 	}
 
-	/* Determine if at least one resource is available for device state purposes */
-	if ((resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_is_available, NULL))) {
-		state = AST_DEVICE_NOT_INUSE;
-		ao2_ref(resource, -1);
-	}
-
 	ao2_unlock(buddy->resources);
 
 	ao2_ref(buddy, -1);
 
-	ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "XMPP/%s/%s", client->name, pak->from->partial);
-
 	return 0;
 }
 
@@ -3563,18 +3398,20 @@ static int xmpp_action_hook(void *data, int type, iks *node)
 int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
 {
 	if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
-		xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING);
+		client->state = XMPP_STATE_DISCONNECTING;
 		pthread_join(client->thread, NULL);
 		client->thread = AST_PTHREADT_NULL;
 	}
 
 	if (client->mwi_sub) {
-		client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
+		ast_event_unsubscribe(client->mwi_sub);
+		client->mwi_sub = NULL;
 		xmpp_pubsub_unsubscribe(client, "message_waiting");
 	}
 
 	if (client->device_state_sub) {
-		client->device_state_sub = stasis_unsubscribe(client->device_state_sub);
+		ast_event_unsubscribe(client->device_state_sub);
+		client->device_state_sub = NULL;
 		xmpp_pubsub_unsubscribe(client, "device_state");
 	}
 
@@ -3592,7 +3429,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
 		iks_disconnect(client->parser);
 	}
 
-	xmpp_client_change_state(client, XMPP_STATE_DISCONNECTED);
+	client->state = XMPP_STATE_DISCONNECTED;
 
 	return 0;
 }
@@ -3807,7 +3644,7 @@ static void *xmpp_client_thread(void *data)
 			ast_log(LOG_WARNING, "JABBER: Not Supported\n");
 		} else if (res == IKS_NET_DROPPED) {
 			ast_log(LOG_WARNING, "JABBER: Dropped?\n");
-		} else if (res == IKS_NET_UNKNOWN) {
+		} else {
 			ast_debug(5, "JABBER: Unknown\n");
 		}
 
@@ -3835,6 +3672,10 @@ static int xmpp_client_config_merge_buddies(void *obj, void *arg, int flags)
 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags)
 {
 	struct ast_xmpp_client_config *cfg = obj;
+	RAII_VAR(struct xmpp_config *, gcfg, ao2_global_obj_ref(globals), ao2_cleanup);
+
+	/* Merge global options that have not been modified */
+	ast_copy_flags(&cfg->flags, &gcfg->global->general, ~(cfg->mod_flags.flags) & (XMPP_AUTOPRUNE | XMPP_AUTOREGISTER | XMPP_AUTOACCEPT));
 
 	/* Merge buddies as need be */
 	ao2_callback(cfg->buddies, OBJ_MULTIPLE | OBJ_UNLINK, xmpp_client_config_merge_buddies, cfg->client->buddies);
@@ -4511,10 +4352,13 @@ static int client_bitfield_handler(const struct aco_option *opt, struct ast_vari
 		ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_KEEPALIVE);
 	} else if (!strcasecmp(var->name, "autoprune")) {
 		ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOPRUNE);
+		ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOPRUNE);
 	} else if (!strcasecmp(var->name, "autoregister")) {
 		ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOREGISTER);
+		ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOREGISTER);
 	} else if (!strcasecmp(var->name, "auth_policy")) {
 		ast_set2_flag(&cfg->flags, !strcasecmp(var->value, "accept") ? 1 : 0, XMPP_AUTOACCEPT);
+		ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOACCEPT);
 	} else if (!strcasecmp(var->name, "sendtodialplan")) {
 		ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_SEND_TO_DIALPLAN);
 	} else {
@@ -4572,16 +4416,6 @@ static int client_buddy_handler(const struct aco_option *opt, struct ast_variabl
 	return 0;
 }
 
-/*!
- * \brief Load the module
- *
- * Module loading including tests for configuration or dependencies.
- * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
- */
 static int load_module(void)
 {
 	if (aco_info_init(&cfg_info)) {
@@ -4605,6 +4439,11 @@ static int load_module(void)
 	aco_option_register(&cfg_info, "port", ACO_EXACT, client_options, "5222", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, port));
 	aco_option_register(&cfg_info, "timeout", ACO_EXACT, client_options, "5", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, message_timeout));
 
+	/* Global options that can be overridden per client must not specify a default */
+	aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
+	aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
+	aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
+
 	aco_option_register_custom(&cfg_info, "debug", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "type", ACO_EXACT, client_options, "client", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "distribute_events", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
@@ -4612,9 +4451,6 @@ static int load_module(void)
 	aco_option_register_custom(&cfg_info, "usesasl", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "forceoldssl", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "keepalive", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
-	aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
-	aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
-	aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, client_options, "accept", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "sendtodialplan", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
 	aco_option_register_custom(&cfg_info, "status", ACO_EXACT, client_options, "available", client_status_handler, 0);
 	aco_option_register_custom(&cfg_info, "buddy", ACO_EXACT, client_options, NULL, client_buddy_handler, 0);
@@ -4653,7 +4489,6 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk XMPP Interface",
-		.support_level = AST_MODULE_SUPPORT_CORE,
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
diff --git a/res/snmp/agent.c b/res/snmp/agent.c
index b607ecf..6391f39 100644
--- a/res/snmp/agent.c
+++ b/res/snmp/agent.c
@@ -20,7 +20,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /*
  * There is some collision collision between netsmp and asterisk names,
@@ -298,11 +298,10 @@ static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *le
 		}
 		break;
 	case ASTCHANBRIDGE:
-		if ((bridge = ast_channel_bridge_peer(chan)) != NULL) {
+		if ((bridge = ast_bridged_channel(chan)) != NULL) {
 			ast_copy_string(string_ret, ast_channel_name(bridge), sizeof(string_ret));
 			*var_len = strlen(string_ret);
 			ret = (u_char *)string_ret;
-			ast_channel_unref(bridge);
 		}
 		break;
 	case ASTCHANMASQ:
@@ -611,7 +610,7 @@ static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *le
 
 	while ((chan = ast_channel_iterator_next(iter))) {
 		ast_channel_lock(chan);
-		if (ast_channel_is_bridged(chan)) {
+		if (ast_bridged_channel(chan)) {
 			long_ret++;
 		}
 		ast_channel_unlock(chan);
@@ -761,8 +760,7 @@ static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t
 	return NULL;
 }
 
-static int countmodule(const char *mod, const char *desc, int use, const char *status,
-		const char *like, enum ast_module_support_level support_level)
+static int countmodule(const char *mod, const char *desc, int use, const char *like)
 {
 	return 1;
 }
diff --git a/res/stasis/app.c b/res/stasis/app.c
deleted file mode 100644
index a7525d7..0000000
--- a/res/stasis/app.c
+++ /dev/null
@@ -1,1321 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429064 $")
-
-#include "app.h"
-#include "control.h"
-#include "messaging.h"
-
-#include "asterisk/callerid.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_message_router.h"
-
-static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate);
-
-struct stasis_app {
-	/*! Aggregation topic for this application. */
-	struct stasis_topic *topic;
-	/*! Router for handling messages forwarded to \a topic. */
-	struct stasis_message_router *router;
-	/*! Router for handling messages to the bridge all \a topic. */
-	struct stasis_message_router *bridge_router;
-	/*! Container of the channel forwards to this app's topic. */
-	struct ao2_container *forwards;
-	/*! Callback function for this application. */
-	stasis_app_cb handler;
-	/*! Opaque data to hand to callback function. */
-	void *data;
-	/*! Name of the Stasis application */
-	char name[];
-};
-
-enum forward_type {
-	FORWARD_CHANNEL,
-	FORWARD_BRIDGE,
-	FORWARD_ENDPOINT,
-};
-
-/*! Subscription info for a particular channel/bridge. */
-struct app_forwards {
-	/*! Count of number of times this channel/bridge has been subscribed */
-	int interested;
-
-	/*! Forward for the regular topic */
-	struct stasis_forward *topic_forward;
-	/*! Forward for the caching topic */
-	struct stasis_forward *topic_cached_forward;
-
-	/* Type of object being forwarded */
-	enum forward_type forward_type;
-	/*! Unique id of the object being forwarded */
-	char id[];
-};
-
-static void forwards_dtor(void *obj)
-{
-#ifdef AST_DEVMODE
-	struct app_forwards *forwards = obj;
-#endif /* AST_DEVMODE */
-
-	ast_assert(forwards->topic_forward == NULL);
-	ast_assert(forwards->topic_cached_forward == NULL);
-}
-
-static void forwards_unsubscribe(struct app_forwards *forwards)
-{
-	stasis_forward_cancel(forwards->topic_forward);
-	forwards->topic_forward = NULL;
-	stasis_forward_cancel(forwards->topic_cached_forward);
-	forwards->topic_cached_forward = NULL;
-}
-
-static struct app_forwards *forwards_create(struct stasis_app *app,
-	const char *id)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-
-	if (!app || ast_strlen_zero(id)) {
-		return NULL;
-	}
-
-	forwards = ao2_alloc(sizeof(*forwards) + strlen(id) + 1, forwards_dtor);
-	if (!forwards) {
-		return NULL;
-	}
-
-	strcpy(forwards->id, id);
-
-	ao2_ref(forwards, +1);
-	return forwards;
-}
-
-/*! Forward a channel's topics to an app */
-static struct app_forwards *forwards_create_channel(struct stasis_app *app,
-	struct ast_channel *chan)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-
-	if (!app || !chan) {
-		return NULL;
-	}
-
-	forwards = forwards_create(app, ast_channel_uniqueid(chan));
-	if (!forwards) {
-		return NULL;
-	}
-
-	forwards->forward_type = FORWARD_CHANNEL;
-	forwards->topic_forward = stasis_forward_all(ast_channel_topic(chan),
-		app->topic);
-	if (!forwards->topic_forward) {
-		return NULL;
-	}
-
-	forwards->topic_cached_forward = stasis_forward_all(
-		ast_channel_topic_cached(chan), app->topic);
-	if (!forwards->topic_cached_forward) {
-		/* Half-subscribed is a bad thing */
-		stasis_forward_cancel(forwards->topic_forward);
-		forwards->topic_forward = NULL;
-		return NULL;
-	}
-
-	ao2_ref(forwards, +1);
-	return forwards;
-}
-
-/*! Forward a bridge's topics to an app */
-static struct app_forwards *forwards_create_bridge(struct stasis_app *app,
-	struct ast_bridge *bridge)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-
-	if (!app || !bridge) {
-		return NULL;
-	}
-
-	forwards = forwards_create(app, bridge->uniqueid);
-	if (!forwards) {
-		return NULL;
-	}
-
-	forwards->forward_type = FORWARD_BRIDGE;
-	forwards->topic_forward = stasis_forward_all(ast_bridge_topic(bridge),
-		app->topic);
-	if (!forwards->topic_forward) {
-		return NULL;
-	}
-
-	forwards->topic_cached_forward = stasis_forward_all(
-		ast_bridge_topic_cached(bridge), app->topic);
-	if (!forwards->topic_cached_forward) {
-		/* Half-subscribed is a bad thing */
-		stasis_forward_cancel(forwards->topic_forward);
-		forwards->topic_forward = NULL;
-		return NULL;
-	}
-
-	ao2_ref(forwards, +1);
-	return forwards;
-}
-
-/*! Forward a endpoint's topics to an app */
-static struct app_forwards *forwards_create_endpoint(struct stasis_app *app,
-	struct ast_endpoint *endpoint)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-
-	if (!app || !endpoint) {
-		return NULL;
-	}
-
-	forwards = forwards_create(app, ast_endpoint_get_id(endpoint));
-	if (!forwards) {
-		return NULL;
-	}
-
-	forwards->forward_type = FORWARD_ENDPOINT;
-	forwards->topic_forward = stasis_forward_all(ast_endpoint_topic(endpoint),
-		app->topic);
-	if (!forwards->topic_forward) {
-		return NULL;
-	}
-
-	forwards->topic_cached_forward = stasis_forward_all(
-		ast_endpoint_topic_cached(endpoint), app->topic);
-	if (!forwards->topic_cached_forward) {
-		/* Half-subscribed is a bad thing */
-		stasis_forward_cancel(forwards->topic_forward);
-		forwards->topic_forward = NULL;
-		return NULL;
-	}
-
-	ao2_ref(forwards, +1);
-	return forwards;
-}
-
-static int forwards_sort(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct app_forwards *object_left = obj_left;
-	const struct app_forwards *object_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_POINTER:
-		right_key = object_right->id;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(object_left->id, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->id, right_key, strlen(right_key));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-static void app_dtor(void *obj)
-{
-	struct stasis_app *app = obj;
-
-	ast_verb(1, "Destroying Stasis app %s\n", app->name);
-
-	ast_assert(app->router == NULL);
-	ast_assert(app->bridge_router == NULL);
-
-	ao2_cleanup(app->topic);
-	app->topic = NULL;
-	ao2_cleanup(app->forwards);
-	app->forwards = NULL;
-	ao2_cleanup(app->data);
-	app->data = NULL;
-}
-
-static void call_forwarded_handler(struct stasis_app *app, struct stasis_message *message)
-{
-	struct ast_multi_channel_blob *payload = stasis_message_data(message);
-	struct ast_channel_snapshot *snapshot = ast_multi_channel_blob_get_channel(payload, "forwarded");
-	struct ast_channel *chan;
-
-	if (!snapshot) {
-		return;
-	}
-
-	chan = ast_channel_get_by_name(snapshot->uniqueid);
-	if (!chan) {
-		return;
-	}
-
-	app_subscribe_channel(app, chan);
-	ast_channel_unref(chan);
-}
-
-static void sub_default_handler(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_cleanup(app);
-	}
-
-	if (stasis_message_type(message) == ast_channel_dial_type()) {
-		call_forwarded_handler(app, message);
-	}
-
-	/* By default, send any message that has a JSON representation */
-	json = stasis_message_to_json(message, stasis_app_get_sanitizer());
-	if (!json) {
-		return;
-	}
-
-	app_send(app, json);
-}
-
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef struct ast_json *(*channel_snapshot_monitor)(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot,
-	const struct timeval *tv);
-
-static struct ast_json *simple_channel_event(
-	const char *type,
-	struct ast_channel_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: o}",
-		"type", type,
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"channel", json_channel);
-}
-
-static struct ast_json *channel_created_event(
-	struct ast_channel_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	return simple_channel_event("ChannelCreated", snapshot, tv);
-}
-
-static struct ast_json *channel_destroyed_event(
-	struct ast_channel_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
-		"type", "ChannelDestroyed",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"cause", snapshot->hangupcause,
-		"cause_txt", ast_cause2str(snapshot->hangupcause),
-		"channel", json_channel);
-}
-
-static struct ast_json *channel_state_change_event(
-	struct ast_channel_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	return simple_channel_event("ChannelStateChange", snapshot, tv);
-}
-
-/*! \brief Handle channel state changes */
-static struct ast_json *channel_state(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot,
-	const struct timeval *tv)
-{
-	struct ast_channel_snapshot *snapshot = new_snapshot ?
-		new_snapshot : old_snapshot;
-
-	if (!old_snapshot) {
-		return channel_created_event(snapshot, tv);
-	} else if (!new_snapshot) {
-		return channel_destroyed_event(snapshot, tv);
-	} else if (old_snapshot->state != new_snapshot->state) {
-		return channel_state_change_event(snapshot, tv);
-	}
-
-	return NULL;
-}
-
-static struct ast_json *channel_dialplan(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_channel;
-
-	/* No Newexten event on cache clear or first event */
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	/* Empty application is not valid for a Newexten event */
-	if (ast_strlen_zero(new_snapshot->appl)) {
-		return NULL;
-	}
-
-	if (ast_channel_snapshot_cep_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	json_channel = ast_channel_snapshot_to_json(new_snapshot, stasis_app_get_sanitizer());
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: s, s: s, s: o}",
-		"type", "ChannelDialplan",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"dialplan_app", new_snapshot->appl,
-		"dialplan_app_data", new_snapshot->data,
-		"channel", json_channel);
-}
-
-static struct ast_json *channel_callerid(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_channel;
-
-	/* No NewCallerid event on cache clear or first event */
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	if (ast_channel_snapshot_caller_id_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	json_channel = ast_channel_snapshot_to_json(new_snapshot, stasis_app_get_sanitizer());
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
-		"type", "ChannelCallerId",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"caller_presentation", new_snapshot->caller_pres,
-		"caller_presentation_txt", ast_describe_caller_presentation(
-			new_snapshot->caller_pres),
-		"channel", json_channel);
-}
-
-static struct ast_json *channel_connected_line(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_channel;
-
-	/* No ChannelConnectedLine event on cache clear or first event */
-	if (!old_snapshot || !new_snapshot) {
-		return NULL;
-	}
-
-	if (ast_channel_snapshot_connected_line_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	json_channel = ast_channel_snapshot_to_json(new_snapshot, stasis_app_get_sanitizer());
-	if (!json_channel) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: o}",
-		"type", "ChannelConnectedLine",
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"channel", json_channel);
-}
-
-static channel_snapshot_monitor channel_monitors[] = {
-	channel_state,
-	channel_dialplan,
-	channel_callerid,
-	channel_connected_line,
-};
-
-static void sub_channel_update_handler(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-	struct stasis_cache_update *update;
-	struct ast_channel_snapshot *new_snapshot;
-	struct ast_channel_snapshot *old_snapshot;
-	const struct timeval *tv;
-	int i;
-
-	ast_assert(stasis_message_type(message) == stasis_cache_update_type());
-
-	update = stasis_message_data(message);
-
-	ast_assert(update->type == ast_channel_snapshot_type());
-
-	new_snapshot = stasis_message_data(update->new_snapshot);
-	old_snapshot = stasis_message_data(update->old_snapshot);
-
-	/* Pull timestamp from the new snapshot, or from the update message
-	 * when there isn't one. */
-	tv = update->new_snapshot ?
-		stasis_message_timestamp(update->new_snapshot) :
-		stasis_message_timestamp(message);
-
-	for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {
-		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
-
-		msg = channel_monitors[i](old_snapshot, new_snapshot, tv);
-		if (msg) {
-			app_send(app, msg);
-		}
-	}
-
-	if (!new_snapshot && old_snapshot) {
-		unsubscribe(app, "channel", old_snapshot->uniqueid, 1);
-	}
-}
-
-static struct ast_json *simple_endpoint_event(
-	const char *type,
-	struct ast_endpoint_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-
-	if (!json_endpoint) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: o}",
-		"type", type,
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"endpoint", json_endpoint);
-}
-
-static int message_received_handler(const char *endpoint_id, struct ast_json *json_msg, void *pvt)
-{
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-	struct ast_json *json_endpoint;
-	struct stasis_app *app = pvt;
-	char *tech;
-	char *resource;
-
-	tech = ast_strdupa(endpoint_id);
-	resource = strchr(tech, '/');
-	if (resource) {
-		resource[0] = '\0';
-		resource++;
-	}
-
-	if (ast_strlen_zero(tech) || ast_strlen_zero(resource)) {
-		return -1;
-	}
-
-	snapshot = ast_endpoint_latest_snapshot(tech, resource);
-	if (!snapshot) {
-		return -1;
-	}
-
-	json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-	if (!json_endpoint) {
-		return -1;
-	}
-
-	app_send(app, ast_json_pack("{s: s, s: o, s: o, s: O}",
-		"type", "TextMessageReceived",
-		"timestamp", ast_json_timeval(ast_tvnow(), NULL),
-		"endpoint", json_endpoint,
-		"message", json_msg));
-
-	return 0;
-}
-
-static void sub_endpoint_update_handler(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct stasis_app *app = data;
-	struct stasis_cache_update *update;
-	struct ast_endpoint_snapshot *new_snapshot;
-	struct ast_endpoint_snapshot *old_snapshot;
-	const struct timeval *tv;
-
-	ast_assert(stasis_message_type(message) == stasis_cache_update_type());
-
-	update = stasis_message_data(message);
-
-	ast_assert(update->type == ast_endpoint_snapshot_type());
-
-	new_snapshot = stasis_message_data(update->new_snapshot);
-	old_snapshot = stasis_message_data(update->old_snapshot);
-
-	if (new_snapshot) {
-		tv = stasis_message_timestamp(update->new_snapshot);
-
-		json = simple_endpoint_event("EndpointStateChange", new_snapshot, tv);
-		if (!json) {
-			return;
-		}
-
-		app_send(app, json);
-	}
-
-	if (!new_snapshot && old_snapshot) {
-		unsubscribe(app, "endpoint", old_snapshot->id, 1);
-	}
-}
-
-static struct ast_json *simple_bridge_event(
-	const char *type,
-	struct ast_bridge_snapshot *snapshot,
-	const struct timeval *tv)
-{
-	struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
-	if (!json_bridge) {
-		return NULL;
-	}
-
-	return ast_json_pack("{s: s, s: o, s: o}",
-		"type", type,
-		"timestamp", ast_json_timeval(*tv, NULL),
-		"bridge", json_bridge);
-}
-
-static void sub_bridge_update_handler(void *data,
-	struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct stasis_app *app = data;
-	struct stasis_cache_update *update;
-	struct ast_bridge_snapshot *new_snapshot;
-	struct ast_bridge_snapshot *old_snapshot;
-	const struct timeval *tv;
-
-	ast_assert(stasis_message_type(message) == stasis_cache_update_type());
-
-	update = stasis_message_data(message);
-
-	ast_assert(update->type == ast_bridge_snapshot_type());
-
-	new_snapshot = stasis_message_data(update->new_snapshot);
-	old_snapshot = stasis_message_data(update->old_snapshot);
-	tv = update->new_snapshot ?
-		stasis_message_timestamp(update->new_snapshot) :
-		stasis_message_timestamp(message);
-
-	if (!new_snapshot) {
-		json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv);
-	} else if (!old_snapshot) {
-		json = simple_bridge_event("BridgeCreated", new_snapshot, tv);
-	}
-
-	if (json) {
-		app_send(app, json);
-	}
-
-	if (!new_snapshot && old_snapshot) {
-		unsubscribe(app, "bridge", old_snapshot->uniqueid, 1);
-	}
-}
-
-
-/*! \brief Helper function for determining if the application is subscribed to a given entity */
-static int bridge_app_subscribed(struct stasis_app *app, const char *uniqueid)
-{
-	struct app_forwards *forwards = NULL;
-
-	forwards = ao2_find(app->forwards, uniqueid, OBJ_SEARCH_KEY);
-	if (!forwards) {
-		return 0;
-	}
-
-	ao2_ref(forwards, -1);
-	return 1;
-}
-
-static void bridge_merge_handler(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-	struct ast_bridge_merge_message *merge;
-
-	merge = stasis_message_data(message);
-
-	/* Find out if we're subscribed to either bridge */
-	if (bridge_app_subscribed(app, merge->from->uniqueid) ||
-		bridge_app_subscribed(app, merge->to->uniqueid)) {
-		/* Forward the message to the app */
-		stasis_publish(app->topic, message);
-	}
-}
-
-/*! \brief Callback function for checking if channels in a bridge are subscribed to */
-static int bridge_app_subscribed_involved(struct stasis_app *app, struct ast_bridge_snapshot *snapshot)
-{
-	int subscribed = 0;
-	struct ao2_iterator iter;
-	char *uniqueid;
-
-	if (bridge_app_subscribed(app, snapshot->uniqueid)) {
-		return 1;
-	}
-
-	iter = ao2_iterator_init(snapshot->channels, 0);
-	for (; (uniqueid = ao2_iterator_next(&iter)); ao2_ref(uniqueid, -1)) {
-		if (bridge_app_subscribed(app, uniqueid)) {
-			subscribed = 1;
-			ao2_ref(uniqueid, -1);
-			break;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	return subscribed;
-}
-
-static void set_replacement_channel(struct ast_channel_snapshot *to_be_replaced,
-		struct ast_channel_snapshot *replacing)
-{
-	struct stasis_app_control *control = stasis_app_control_find_by_channel_id(
-		to_be_replaced->uniqueid);
-	struct ast_channel *chan = ast_channel_get_by_name(replacing->uniqueid);
-
-	if (control && chan) {
-		ast_channel_lock(chan);
-		app_set_replace_channel_app(chan, app_name(control_app(control)));
-		app_set_replace_channel_snapshot(chan, to_be_replaced);
-		ast_channel_unlock(chan);
-	}
-	ast_channel_cleanup(chan);
-	ao2_cleanup(control);
-}
-
-static void bridge_blind_transfer_handler(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
-	struct ast_bridge_snapshot *bridge = transfer_msg->bridge;
-
-	if (transfer_msg->replace_channel) {
-		set_replacement_channel(transfer_msg->transferer, transfer_msg->replace_channel);
-	}
-
-	if (bridge_app_subscribed(app, transfer_msg->transferer->uniqueid) ||
-		(bridge && bridge_app_subscribed_involved(app, bridge))) {
-		stasis_publish(app->topic, message);
-	}
-}
-
-static void bridge_attended_transfer_handler(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(message);
-	int subscribed = 0;
-
-	subscribed = bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid);
-	if (!subscribed) {
-		subscribed = bridge_app_subscribed(app, transfer_msg->to_transfer_target.channel_snapshot->uniqueid);
-	}
-	if (!subscribed && transfer_msg->to_transferee.bridge_snapshot) {
-		subscribed = bridge_app_subscribed_involved(app, transfer_msg->to_transferee.bridge_snapshot);
-	}
-	if (!subscribed && transfer_msg->to_transfer_target.bridge_snapshot) {
-		subscribed = bridge_app_subscribed_involved(app, transfer_msg->to_transfer_target.bridge_snapshot);
-	}
-
-	if (!subscribed) {
-		switch (transfer_msg->dest_type) {
-		case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
-			subscribed = bridge_app_subscribed(app, transfer_msg->dest.bridge);
-			break;
-		case AST_ATTENDED_TRANSFER_DEST_LINK:
-			subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[0]->uniqueid);
-			if (!subscribed) {
-				subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[1]->uniqueid);
-			}
-			break;
-		break;
-		case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-			subscribed = bridge_app_subscribed_involved(app, transfer_msg->dest.threeway.bridge_snapshot);
-			if (!subscribed) {
-				subscribed = bridge_app_subscribed(app, transfer_msg->dest.threeway.channel_snapshot->uniqueid);
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	if (subscribed) {
-		stasis_publish(app->topic, message);
-	}
-
-	if (transfer_msg->replace_channel) {
-		set_replacement_channel(transfer_msg->to_transferee.channel_snapshot,
-				transfer_msg->replace_channel);
-	}
-
-	if (transfer_msg->dest_type == AST_ATTENDED_TRANSFER_DEST_LINK) {
-		set_replacement_channel(transfer_msg->to_transferee.channel_snapshot,
-				transfer_msg->dest.links[0]);
-		set_replacement_channel(transfer_msg->to_transfer_target.channel_snapshot,
-				transfer_msg->dest.links[1]);
-	}
-}
-
-static void bridge_default_handler(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	struct stasis_app *app = data;
-
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_cleanup(app);
-	}
-}
-
-struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data)
-{
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-	size_t size;
-	int res = 0;
-
-	ast_assert(name != NULL);
-	ast_assert(handler != NULL);
-
-	ast_verb(1, "Creating Stasis app '%s'\n", name);
-
-	size = sizeof(*app) + strlen(name) + 1;
-	app = ao2_alloc_options(size, app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX);
-
-	if (!app) {
-		return NULL;
-	}
-
-	app->forwards = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT,
-		forwards_sort, NULL);
-	if (!app->forwards) {
-		return NULL;
-	}
-
-	app->topic = stasis_topic_create(name);
-	if (!app->topic) {
-		return NULL;
-	}
-
-	app->bridge_router = stasis_message_router_create(ast_bridge_topic_all());
-	if (!app->bridge_router) {
-		return NULL;
-	}
-
-	res |= stasis_message_router_add(app->bridge_router,
-		ast_bridge_merge_message_type(), bridge_merge_handler, app);
-
-	res |= stasis_message_router_add(app->bridge_router,
-		ast_blind_transfer_type(), bridge_blind_transfer_handler, app);
-
-	res |= stasis_message_router_add(app->bridge_router,
-		ast_attended_transfer_type(), bridge_attended_transfer_handler, app);
-
-	res |= stasis_message_router_set_default(app->bridge_router,
-		bridge_default_handler, app);
-
-	if (res != 0) {
-		return NULL;
-	}
-	/* Bridge router holds a reference */
-	ao2_ref(app, +1);
-
-	app->router = stasis_message_router_create(app->topic);
-	if (!app->router) {
-		return NULL;
-	}
-
-	res |= stasis_message_router_add_cache_update(app->router,
-		ast_bridge_snapshot_type(), sub_bridge_update_handler, app);
-
-	res |= stasis_message_router_add_cache_update(app->router,
-		ast_channel_snapshot_type(), sub_channel_update_handler, app);
-
-	res |= stasis_message_router_add_cache_update(app->router,
-		ast_endpoint_snapshot_type(), sub_endpoint_update_handler, app);
-
-	res |= stasis_message_router_set_default(app->router,
-		sub_default_handler, app);
-
-	if (res != 0) {
-		return NULL;
-	}
-	/* Router holds a reference */
-	ao2_ref(app, +1);
-
-	strncpy(app->name, name, size - sizeof(*app));
-	app->handler = handler;
-	ao2_ref(data, +1);
-	app->data = data;
-
-	ao2_ref(app, +1);
-	return app;
-}
-
-struct stasis_topic *ast_app_get_topic(struct stasis_app *app) {
-	return app->topic;
-}
-
-/*!
- * \brief Send a message to the given application.
- * \param app App to send the message to.
- * \param message Message to send.
- */
-void app_send(struct stasis_app *app, struct ast_json *message)
-{
-	stasis_app_cb handler;
-	RAII_VAR(void *, data, NULL, ao2_cleanup);
-
-	/* Copy off mutable state with lock held */
-	{
-		SCOPED_AO2LOCK(lock, app);
-		handler = app->handler;
-		if (app->data) {
-			ao2_ref(app->data, +1);
-			data = app->data;
-		}
-		/* Name is immutable; no need to copy */
-	}
-
-	if (!handler) {
-		ast_verb(3,
-			"Inactive Stasis app '%s' missed message\n", app->name);
-		return;
-	}
-
-	handler(data, app->name, message);
-}
-
-void app_deactivate(struct stasis_app *app)
-{
-	SCOPED_AO2LOCK(lock, app);
-	ast_verb(1, "Deactivating Stasis app '%s'\n", app->name);
-	app->handler = NULL;
-	ao2_cleanup(app->data);
-	app->data = NULL;
-}
-
-void app_shutdown(struct stasis_app *app)
-{
-	SCOPED_AO2LOCK(lock, app);
-
-	ast_assert(app_is_finished(app));
-
-	stasis_message_router_unsubscribe(app->router);
-	app->router = NULL;
-	stasis_message_router_unsubscribe(app->bridge_router);
-	app->bridge_router = NULL;
-}
-
-int app_is_active(struct stasis_app *app)
-{
-	SCOPED_AO2LOCK(lock, app);
-	return app->handler != NULL;
-}
-
-int app_is_finished(struct stasis_app *app)
-{
-	SCOPED_AO2LOCK(lock, app);
-
-	return app->handler == NULL && ao2_container_count(app->forwards) == 0;
-}
-
-void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
-{
-	SCOPED_AO2LOCK(lock, app);
-
-	if (app->handler) {
-		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
-
-		ast_verb(1, "Replacing Stasis app '%s'\n", app->name);
-
-		msg = ast_json_pack("{s: s, s: s}",
-			"type", "ApplicationReplaced",
-			"application", app->name);
-		if (msg) {
-			app_send(app, msg);
-		}
-	} else {
-		ast_verb(1, "Activating Stasis app '%s'\n", app->name);
-	}
-
-	app->handler = handler;
-	ao2_cleanup(app->data);
-	if (data) {
-		ao2_ref(data, +1);
-	}
-	app->data = data;
-}
-
-const char *app_name(const struct stasis_app *app)
-{
-	return app->name;
-}
-
-struct ast_json *app_to_json(const struct stasis_app *app)
-{
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	struct ast_json *channels;
-	struct ast_json *bridges;
-	struct ast_json *endpoints;
-	struct ao2_iterator i;
-	void *obj;
-
-	json = ast_json_pack("{s: s, s: [], s: [], s: []}",
-		"name", app->name,
-		"channel_ids", "bridge_ids", "endpoint_ids");
-	channels = ast_json_object_get(json, "channel_ids");
-	bridges = ast_json_object_get(json, "bridge_ids");
-	endpoints = ast_json_object_get(json, "endpoint_ids");
-
-	i = ao2_iterator_init(app->forwards, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct app_forwards *, forwards, obj, ao2_cleanup);
-		RAII_VAR(struct ast_json *, id, NULL, ast_json_unref);
-		int append_res = -1;
-
-		id = ast_json_string_create(forwards->id);
-
-		switch (forwards->forward_type) {
-		case FORWARD_CHANNEL:
-			append_res = ast_json_array_append(channels,
-				ast_json_ref(id));
-			break;
-		case FORWARD_BRIDGE:
-			append_res = ast_json_array_append(bridges,
-				ast_json_ref(id));
-			break;
-		case FORWARD_ENDPOINT:
-			append_res = ast_json_array_append(endpoints,
-				ast_json_ref(id));
-			break;
-		}
-
-		if (append_res != 0) {
-			ast_log(LOG_ERROR, "Error building response\n");
-			ao2_iterator_destroy(&i);
-			return NULL;
-		}
-	}
-	ao2_iterator_destroy(&i);
-
-	return ast_json_ref(json);
-}
-
-int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan)
-{
-	int res;
-
-	if (!app || !chan) {
-		return -1;
-	} else {
-		RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-		SCOPED_AO2LOCK(lock, app->forwards);
-
-		forwards = ao2_find(app->forwards, ast_channel_uniqueid(chan),
-			OBJ_SEARCH_KEY | OBJ_NOLOCK);
-		if (!forwards) {
-			/* Forwards not found, create one */
-			forwards = forwards_create_channel(app, chan);
-			if (!forwards) {
-				return -1;
-			}
-
-			res = ao2_link_flags(app->forwards, forwards,
-				OBJ_NOLOCK);
-			if (!res) {
-				return -1;
-			}
-		}
-
-		++forwards->interested;
-		ast_debug(3, "Channel '%s' is %d interested in %s\n", ast_channel_uniqueid(chan), forwards->interested, app->name);
-		return 0;
-	}
-}
-
-static int subscribe_channel(struct stasis_app *app, void *obj)
-{
-	return app_subscribe_channel(app, obj);
-}
-
-static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-	SCOPED_AO2LOCK(lock, app->forwards);
-
-	forwards = ao2_find(app->forwards, id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-	if (!forwards) {
-		ast_debug(3, "App '%s' not subscribed to %s '%s'\n", app->name, kind, id);
-		return -1;
-	}
-	forwards->interested--;
-
-	ast_debug(3, "%s '%s': is %d interested in %s\n", kind, id, forwards->interested, app->name);
-	if (forwards->interested == 0 || terminate) {
-		/* No one is interested any more; unsubscribe */
-		ast_debug(3, "%s '%s' unsubscribed from %s\n", kind, id, app->name);
-		forwards_unsubscribe(forwards);
-		ao2_find(app->forwards, forwards,
-			OBJ_POINTER | OBJ_NOLOCK | OBJ_UNLINK |
-			OBJ_NODATA);
-
-		if (!strcmp(kind, "endpoint")) {
-			messaging_app_unsubscribe_endpoint(app->name, id);
-		}
-	}
-
-	return 0;
-}
-
-int app_unsubscribe_channel(struct stasis_app *app, struct ast_channel *chan)
-{
-	if (!app || !chan) {
-		return -1;
-	}
-
-	return app_unsubscribe_channel_id(app, ast_channel_uniqueid(chan));
-}
-
-int app_unsubscribe_channel_id(struct stasis_app *app, const char *channel_id)
-{
-	if (!app || !channel_id) {
-		return -1;
-	}
-
-	return unsubscribe(app, "channel", channel_id, 0);
-}
-
-int app_is_subscribed_channel_id(struct stasis_app *app, const char *channel_id)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-	forwards = ao2_find(app->forwards, channel_id, OBJ_SEARCH_KEY);
-	return forwards != NULL;
-}
-
-static void *channel_find(const struct stasis_app *app, const char *id)
-{
-	return ast_channel_get_by_name(id);
-}
-
-struct stasis_app_event_source channel_event_source = {
-	.scheme = "channel:",
-	.find = channel_find,
-	.subscribe = subscribe_channel,
-	.unsubscribe = app_unsubscribe_channel_id,
-	.is_subscribed = app_is_subscribed_channel_id
-};
-
-int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
-{
-	if (!app || !bridge) {
-		return -1;
-	} else {
-		RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-		SCOPED_AO2LOCK(lock, app->forwards);
-
-		forwards = ao2_find(app->forwards, bridge->uniqueid,
-			OBJ_SEARCH_KEY | OBJ_NOLOCK);
-
-		if (!forwards) {
-			/* Forwards not found, create one */
-			forwards = forwards_create_bridge(app, bridge);
-			if (!forwards) {
-				return -1;
-			}
-			ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK);
-		}
-
-		++forwards->interested;
-		ast_debug(3, "Bridge '%s' is %d interested in %s\n", bridge->uniqueid, forwards->interested, app->name);
-		return 0;
-	}
-}
-
-static int subscribe_bridge(struct stasis_app *app, void *obj)
-{
-	return app_subscribe_bridge(app, obj);
-}
-
-int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
-{
-	if (!app || !bridge) {
-		return -1;
-	}
-
-	return app_unsubscribe_bridge_id(app, bridge->uniqueid);
-}
-
-int app_unsubscribe_bridge_id(struct stasis_app *app, const char *bridge_id)
-{
-	if (!app || !bridge_id) {
-		return -1;
-	}
-
-	return unsubscribe(app, "bridge", bridge_id, 0);
-}
-
-int app_is_subscribed_bridge_id(struct stasis_app *app, const char *bridge_id)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-	forwards = ao2_find(app->forwards, bridge_id, OBJ_SEARCH_KEY);
-	return forwards != NULL;
-}
-
-static void *bridge_find(const struct stasis_app *app, const char *id)
-{
-	return stasis_app_bridge_find_by_id(id);
-}
-
-struct stasis_app_event_source bridge_event_source = {
-	.scheme = "bridge:",
-	.find = bridge_find,
-	.subscribe = subscribe_bridge,
-	.unsubscribe = app_unsubscribe_bridge_id,
-	.is_subscribed = app_is_subscribed_bridge_id
-};
-
-int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint)
-{
-	if (!app || !endpoint) {
-		return -1;
-	} else {
-		RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-		SCOPED_AO2LOCK(lock, app->forwards);
-
-		forwards = ao2_find(app->forwards, ast_endpoint_get_id(endpoint),
-			OBJ_SEARCH_KEY | OBJ_NOLOCK);
-
-		if (!forwards) {
-			/* Forwards not found, create one */
-			forwards = forwards_create_endpoint(app, endpoint);
-			if (!forwards) {
-				return -1;
-			}
-			ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK);
-
-			/* Subscribe for messages */
-			messaging_app_subscribe_endpoint(app->name, endpoint, &message_received_handler, app);
-		}
-
-		++forwards->interested;
-		ast_debug(3, "Endpoint '%s' is %d interested in %s\n", ast_endpoint_get_id(endpoint), forwards->interested, app->name);
-		return 0;
-	}
-}
-
-static int subscribe_endpoint(struct stasis_app *app, void *obj)
-{
-	return app_subscribe_endpoint(app, obj);
-}
-
-int app_unsubscribe_endpoint_id(struct stasis_app *app, const char *endpoint_id)
-{
-	if (!app || !endpoint_id) {
-		return -1;
-	}
-
-	return unsubscribe(app, "endpoint", endpoint_id, 0);
-}
-
-int app_is_subscribed_endpoint_id(struct stasis_app *app, const char *endpoint_id)
-{
-	RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup);
-	forwards = ao2_find(app->forwards, endpoint_id, OBJ_SEARCH_KEY);
-	return forwards != NULL;
-}
-
-static void *endpoint_find(const struct stasis_app *app, const char *id)
-{
-	return ast_endpoint_find_by_id(id);
-}
-
-struct stasis_app_event_source endpoint_event_source = {
-	.scheme = "endpoint:",
-	.find = endpoint_find,
-	.subscribe = subscribe_endpoint,
-	.unsubscribe = app_unsubscribe_endpoint_id,
-	.is_subscribed = app_is_subscribed_endpoint_id
-};
-
-void stasis_app_register_event_sources(void)
-{
-	stasis_app_register_event_source(&channel_event_source);
-	stasis_app_register_event_source(&bridge_event_source);
-	stasis_app_register_event_source(&endpoint_event_source);
-}
-
-int stasis_app_is_core_event_source(struct stasis_app_event_source *obj)
-{
-	return obj == &endpoint_event_source ||
-		obj == &bridge_event_source ||
-		obj == &channel_event_source;
-}
-
-void stasis_app_unregister_event_sources(void)
-{
-	stasis_app_unregister_event_source(&endpoint_event_source);
-	stasis_app_unregister_event_source(&bridge_event_source);
-	stasis_app_unregister_event_source(&channel_event_source);
-}
-
-
diff --git a/res/stasis/app.h b/res/stasis/app.h
deleted file mode 100644
index 59574f5..0000000
--- a/res/stasis/app.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_APP_H
-#define _ASTERISK_RES_STASIS_APP_H
-
-/*! \file
- *
- * \brief Internal API for the Stasis application controller.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/channel.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_app.h"
-
-/*!
- * \brief Opaque pointer to \c res_stasis app structure.
- */
-struct stasis_app;
-
-/*!
- * \brief Create a res_stasis application.
- *
- * \param name Name of the application.
- * \param handler Callback for messages sent to the application.
- * \param data Data pointer provided to the callback.
- * \return New \c res_stasis application.
- * \return \c NULL on error.
- */
-struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data);
-
-/*!
- * \brief Tears down an application.
- *
- * It should be finished before calling this.
- *
- * \param app Application to unsubscribe.
- */
-void app_shutdown(struct stasis_app *app);
-
-/*!
- * \brief Deactivates an application.
- *
- * Any channels currently in the application remain active (since the app might
- * come back), but new channels are rejected.
- *
- * \param app Application to deactivate.
- */
-void app_deactivate(struct stasis_app *app);
-
-/*!
- * \brief Checks whether an app is active.
- *
- * \param app Application to check.
- * \return True (non-zero) if app is active.
- * \return False (zero) if app has been deactivated.
- */
-int app_is_active(struct stasis_app *app);
-
-/*!
- * \brief Checks whether a deactivated app has no channels.
- *
- * \param app Application to check.
- * \param True (non-zero) if app is deactivated, and has no associated channels.
- * \param False (zero) otherwise.
- */
-int app_is_finished(struct stasis_app *app);
-
-/*!
- * \brief Update the handler and data for a \c res_stasis application.
- *
- * If app has been deactivated, this will reactivate it.
- *
- * \param app Application to update.
- * \param handler New application callback.
- * \param data New data pointer for the callback.
- */
-void app_update(struct stasis_app *app, stasis_app_cb handler, void *data);
-
-/*!
- * \brief Return an application's name.
- *
- * \param app Application.
- * \return Name of the application.
- * \return \c NULL is \a app is \c NULL.
- */
-const char *app_name(const struct stasis_app *app);
-
-/*!
- * \brief Send a message to an application.
- *
- * \param app Application.
- * \param message Message to send.
- */
-void app_send(struct stasis_app *app, struct ast_json *message);
-
-struct app_forwards;
-
-struct ast_json *app_to_json(const struct stasis_app *app);
-
-/*!
- * \brief Subscribes an application to a channel.
- *
- * \param app Application.
- * \param chan Channel to subscribe to.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan);
-
-/*!
- * \brief Cancel the subscription an app has for a channel.
- *
- * \param app Subscribing application.
- * \param chan Channel to unsubscribe from.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_unsubscribe_channel(struct stasis_app *app, struct ast_channel *chan);
-
-/*!
- * \brief Cancel the subscription an app has for a channel.
- *
- * \param app Subscribing application.
- * \param channel_id Id of channel to unsubscribe from.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_unsubscribe_channel_id(struct stasis_app *app, const char *channel_id);
-
-/*!
- * \brief Test if an app is subscribed to a channel.
- *
- * \param app Subscribing application.
- * \param channel_id Id of channel to check.
- * \return True (non-zero) if channel is subscribed to \a app.
- * \return False (zero) if channel is not subscribed.
- */
-int app_is_subscribed_channel_id(struct stasis_app *app, const char *channel_id);
-
-/*!
- * \brief Add a bridge subscription to an existing channel subscription.
- *
- * \param app Application.
- * \param bridge Bridge to subscribe to.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge);
-
-/*!
- * \brief Cancel the bridge subscription for an application.
- *
- * \param forwards Return from app_subscribe_channel().
- * \param bridge Bridge to subscribe to.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge);
-
-/*!
- * \brief Cancel the subscription an app has for a bridge.
- *
- * \param app Subscribing application.
- * \param bridge_id Id of bridge to unsubscribe from.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_unsubscribe_bridge_id(struct stasis_app *app, const char *bridge_id);
-
-/*!
- * \brief Test if an app is subscribed to a bridge.
- *
- * \param app Subscribing application.
- * \param bridge_id Id of bridge to check.
- * \return True (non-zero) if bridge is subscribed to \a app.
- * \return False (zero) if bridge is not subscribed.
- */
-int app_is_subscribed_bridge_id(struct stasis_app *app, const char *bridge_id);
-
-/*!
- * \brief Subscribes an application to a endpoint.
- *
- * \param app Application.
- * \param chan Endpoint to subscribe to.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint);
-
-/*!
- * \brief Cancel the subscription an app has for a endpoint.
- *
- * \param app Subscribing application.
- * \param endpoint_id Id of endpoint to unsubscribe from.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-int app_unsubscribe_endpoint_id(struct stasis_app *app, const char *endpoint_id);
-
-/*!
- * \brief Test if an app is subscribed to a endpoint.
- *
- * \param app Subscribing application.
- * \param endpoint_id Id of endpoint to check.
- * \return True (non-zero) if endpoint is subscribed to \a app.
- * \return False (zero) if endpoint is not subscribed.
- */
-int app_is_subscribed_endpoint_id(struct stasis_app *app, const char *endpoint_id);
-
-/*!
- * \brief Set the snapshot of the channel that this channel will replace
- *
- * \param channel The channel on which this will be set
- * \param replace_snapshot The snapshot of the channel that is being replaced
- *
- * \retval zero success
- * \retval non-zero failure
- */
-int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot);
-
-/*!
- * \brief Set the app that the replacement channel will be controlled by
- *
- * \param channel The channel on which this will be set
- * \param replace_app The app that will be controlling this channel
- *
- * \retval zero success
- * \retval non-zero failure
- */
-int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app);
-
-/*!
- * \brief Get the app that the replacement channel will be controlled by
- *
- * \param channel The channel on which this will be set
- *
- * \retval NULL on error
- * \return the name of the controlling app (must be ast_free()d)
- */
-char *app_get_replace_channel_app(struct ast_channel *chan);
-
-/*!
- * \brief Send StasisEnd message to the listening app
- *
- * \param app The app that owns the channel
- * \param chan The channel for which the message is being sent
- *
- * \retval zero on success
- * \return non-zero on failure
- */
-int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan);
-
-#endif /* _ASTERISK_RES_STASIS_APP_H */
diff --git a/res/stasis/command.c b/res/stasis/command.c
deleted file mode 100644
index f3bdb9c..0000000
--- a/res/stasis/command.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application command support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421880 $")
-
-#include "command.h"
-
-#include "asterisk/lock.h"
-#include "asterisk/stasis_app_impl.h"
-
-struct stasis_app_command {
-	ast_mutex_t lock;
-	ast_cond_t condition;
-	stasis_app_command_cb callback;
-	void *data;
-	command_data_destructor_fn data_destructor;
-	int retval;
-	int is_done:1;
-};
-
-static void command_dtor(void *obj)
-{
-	struct stasis_app_command *command = obj;
-
-	if (command->data_destructor) {
-		command->data_destructor(command->data);
-	}
-
-	ast_mutex_destroy(&command->lock);
-	ast_cond_destroy(&command->condition);
-}
-
-struct stasis_app_command *command_create(
-	stasis_app_command_cb callback, void *data, command_data_destructor_fn data_destructor)
-{
-	struct stasis_app_command *command;
-
-	command = ao2_alloc(sizeof(*command), command_dtor);
-	if (!command) {
-		if (data_destructor) {
-			data_destructor(data);
-		}
-		return NULL;
-	}
-
-	ast_mutex_init(&command->lock);
-	ast_cond_init(&command->condition, 0);
-	command->callback = callback;
-	command->data = data;
-	command->data_destructor = data_destructor;
-
-	return command;
-}
-
-void command_complete(struct stasis_app_command *command, int retval)
-{
-	SCOPED_MUTEX(lock, &command->lock);
-
-	command->is_done = 1;
-	command->retval = retval;
-	ast_cond_signal(&command->condition);
-}
-
-int command_join(struct stasis_app_command *command)
-{
-	SCOPED_MUTEX(lock, &command->lock);
-	while (!command->is_done) {
-		ast_cond_wait(&command->condition, &command->lock);
-	}
-
-	return command->retval;
-}
-
-void command_invoke(struct stasis_app_command *command,
-	struct stasis_app_control *control, struct ast_channel *chan)
-{
-	int retval = command->callback(control, chan, command->data);
-	if (command->data_destructor) {
-		command->data_destructor(command->data);
-		command->data_destructor = NULL;
-	}
-	command_complete(command, retval);
-}
-
-static void command_queue_prestart_destroy(void *obj)
-{
-	/* Clean up the container */
-	ao2_cleanup(obj);
-}
-
-static const struct ast_datastore_info command_queue_prestart = {
-	.type = "stasis-command-prestart-queue",
-	.destroy = command_queue_prestart_destroy,
-};
-
-int command_prestart_queue_command(struct ast_channel *chan,
-	stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
-{
-	struct ast_datastore *datastore;
-	struct ao2_container *command_queue;
-	RAII_VAR(struct stasis_app_command *, command,
-		command_create(command_fn, data, data_destructor), ao2_cleanup);
-
-	if (!command) {
-		return -1;
-	}
-
-	datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
-	if (datastore) {
-		command_queue = datastore->data;
-		ao2_link(command_queue, command);
-		return 0;
-	}
-
-	command_queue = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
-	if (!command_queue) {
-		return -1;
-	}
-
-	datastore = ast_datastore_alloc(&command_queue_prestart, NULL);
-	if (!datastore) {
-		ao2_cleanup(command_queue);
-		return -1;
-	}
-	ast_channel_datastore_add(chan, datastore);
-
-	datastore->data = command_queue;
-	ao2_link(command_queue, command);
-
-	return 0;
-}
-
-struct ao2_container *command_prestart_get_container(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
-
-	if (!datastore) {
-		return NULL;
-	}
-
-	return ao2_bump(datastore->data);
-}
diff --git a/res/stasis/command.h b/res/stasis/command.h
deleted file mode 100644
index 16f2a0a..0000000
--- a/res/stasis/command.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_COMMAND_H
-#define _ASTERISK_RES_STASIS_COMMAND_H
-
-/*! \file
- *
- * \brief Internal API for the Stasis application commands.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/stasis_app_impl.h"
-
-struct stasis_app_command;
-
-struct stasis_app_command *command_create(
-	stasis_app_command_cb callback, void *data,
-	command_data_destructor_fn data_destructor);
-
-void command_complete(struct stasis_app_command *command, int retval);
-
-void command_invoke(struct stasis_app_command *command,
-	struct stasis_app_control *control, struct ast_channel *chan);
-
-int command_join(struct stasis_app_command *command);
-
-/*!
- * \brief Queue a Stasis() prestart command for a channel
- *
- * \pre chan must be locked
- *
- * \param chan The channel on which to queue the prestart command
- * \param command_fn The callback to call for the command
- * \param data The data to pass to the command callback
- * \param data_destructor Optional function which will be called on
- *        the data in either the event of command completion or failure
- *        to schedule or complete the command
- *
- * \retval zero on success
- * \retval non-zero on failure
- */
-int command_prestart_queue_command(struct ast_channel *chan,
-	stasis_app_command_cb command_fn, void *data,
-	command_data_destructor_fn data_destructor);
-
-/*!
- * \brief Get the Stasis() prestart commands for a channel
- *
- * \pre chan must be locked
- *
- * \param chan The channel from which to get prestart commands
- *
- * \return The command prestart container for chan (must be ao2_cleanup()'d)
- */
-struct ao2_container *command_prestart_get_container(struct ast_channel *chan);
-
-
-#endif /* _ASTERISK_RES_STASIS_CONTROL_H */
diff --git a/res/stasis/control.c b/res/stasis/control.c
deleted file mode 100644
index 0e09d1c..0000000
--- a/res/stasis/control.c
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis application control support.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421880 $")
-
-#include "asterisk/stasis_channels.h"
-
-#include "command.h"
-#include "control.h"
-#include "app.h"
-#include "asterisk/dial.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/frame.h"
-#include "asterisk/pbx.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/app.h"
-
-AST_LIST_HEAD(app_control_rules, stasis_app_control_rule);
-
-struct stasis_app_control {
-	ast_cond_t wait_cond;
-	/*! Queue of commands to dispatch on the channel */
-	struct ao2_container *command_queue;
-	/*!
-	 * The associated channel.
-	 * Be very careful with the threading associated w/ manipulating
-	 * the channel.
-	 */
-	struct ast_channel *channel;
-	/*!
-	 * When a channel is in a bridge, the bridge that it is in.
-	 */
-	struct ast_bridge *bridge;
-	/*!
-	 * Holding place for channel's PBX while imparted to a bridge.
-	 */
-	struct ast_pbx *pbx;
-	/*!
-	 * A list of rules to check before adding a channel to a bridge.
-	 */
-	struct app_control_rules add_rules;
-	/*!
-	 * A list of rules to check before removing a channel from a bridge.
-	 */
-	struct app_control_rules remove_rules;
-	/*!
-	 * Silence generator, when silence is being generated.
-	 */
-	struct ast_silence_generator *silgen;
-	/*!
-	 * The app for which this control was created
-	 */
-	struct stasis_app *app;
-	/*!
-	 * When set, /c app_stasis should exit and continue in the dialplan.
-	 */
-	int is_done:1;
-};
-
-static void control_dtor(void *obj)
-{
-	struct stasis_app_control *control = obj;
-
-	AST_LIST_HEAD_DESTROY(&control->add_rules);
-	AST_LIST_HEAD_DESTROY(&control->remove_rules);
-
-	/* We may have a lingering silence generator; free it */
-	ast_channel_stop_silence_generator(control->channel, control->silgen);
-	control->silgen = NULL;
-
-	ao2_cleanup(control->command_queue);
-	ast_cond_destroy(&control->wait_cond);
-	ao2_cleanup(control->app);
-}
-
-struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app)
-{
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-	int res;
-
-	control = ao2_alloc(sizeof(*control), control_dtor);
-	if (!control) {
-		return NULL;
-	}
-
-	control->app = ao2_bump(app);
-
-	res = ast_cond_init(&control->wait_cond, NULL);
-	if (res != 0) {
-		ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n",
-			strerror(errno));
-		return NULL;
-	}
-
-	control->command_queue = ao2_container_alloc_list(
-		AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
-
-	if (!control->command_queue) {
-		return NULL;
-	}
-
-	control->channel = channel;
-
-	AST_LIST_HEAD_INIT(&control->add_rules);
-	AST_LIST_HEAD_INIT(&control->remove_rules);
-
-	ao2_ref(control, +1);
-	return control;
-}
-
-static void app_control_register_rule(
-	const struct stasis_app_control *control,
-	struct app_control_rules *list, struct stasis_app_control_rule *obj)
-{
-	SCOPED_AO2LOCK(lock, control->command_queue);
-	AST_LIST_INSERT_TAIL(list, obj, next);
-}
-
-static void app_control_unregister_rule(
-	const struct stasis_app_control *control,
-	struct app_control_rules *list, struct stasis_app_control_rule *obj)
-{
-	struct stasis_app_control_rule *rule;
-	SCOPED_AO2LOCK(lock, control->command_queue);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(list, rule, next) {
-		if (rule == obj) {
-			AST_RWLIST_REMOVE_CURRENT(next);
-			break;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-/*!
- * \internal
- * \brief Checks to make sure each rule in the given list passes.
- *
- * \details Loops over a list of rules checking for rejections or failures.
- *          If one rule fails its resulting error code is returned.
- *
- * \note Command queue should be locked before calling this function.
- *
- * \param control The stasis application control
- * \param list The list of rules to check
- *
- * \retval 0 if all rules pass
- * \retval non-zero error code if a rule fails
- */
-static enum stasis_app_control_channel_result app_control_check_rules(
-	const struct stasis_app_control *control,
-	struct app_control_rules *list)
-{
-	int res = 0;
-	struct stasis_app_control_rule *rule;
-	AST_LIST_TRAVERSE(list, rule, next) {
-		if ((res = rule->check_rule(control))) {
-			return res;
-		}
-	}
-	return res;
-}
-
-void stasis_app_control_register_add_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule)
-{
-	return app_control_register_rule(control, &control->add_rules, rule);
-}
-
-void stasis_app_control_unregister_add_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule)
-{
-	app_control_unregister_rule(control, &control->add_rules, rule);
-}
-
-void stasis_app_control_register_remove_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule)
-{
-	return app_control_register_rule(control, &control->remove_rules, rule);
-}
-
-void stasis_app_control_unregister_remove_rule(
-	struct stasis_app_control *control,
-	struct stasis_app_control_rule *rule)
-{
-	app_control_unregister_rule(control, &control->remove_rules, rule);
-}
-
-static int app_control_can_add_channel_to_bridge(
-	struct stasis_app_control *control)
-{
-	return app_control_check_rules(control, &control->add_rules);
-}
-
-static int app_control_can_remove_channel_from_bridge(
-	struct stasis_app_control *control)
-{
-	return app_control_check_rules(control, &control->remove_rules);
-}
-
-static int noop_cb(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	return 0;
-}
-
-/*! Callback type to see if the command can execute
-    note: command_queue is locked during callback */
-typedef int (*app_command_can_exec_cb)(struct stasis_app_control *control);
-
-static struct stasis_app_command *exec_command_on_condition(
-	struct stasis_app_control *control, stasis_app_command_cb command_fn,
-	void *data, command_data_destructor_fn data_destructor,
-	app_command_can_exec_cb can_exec_fn)
-{
-	int retval;
-	struct stasis_app_command *command;
-
-	command_fn = command_fn ? : noop_cb;
-
-	command = command_create(command_fn, data, data_destructor);
-	if (!command) {
-		return NULL;
-	}
-
-	ao2_lock(control->command_queue);
-	if (can_exec_fn && (retval = can_exec_fn(control))) {
-		ao2_unlock(control->command_queue);
-		command_complete(command, retval);
-		return command;
-	}
-
-	ao2_link_flags(control->command_queue, command, OBJ_NOLOCK);
-	ast_cond_signal(&control->wait_cond);
-	ao2_unlock(control->command_queue);
-
-	return command;
-}
-
-static struct stasis_app_command *exec_command(
-	struct stasis_app_control *control, stasis_app_command_cb command_fn,
-	void *data, command_data_destructor_fn data_destructor)
-{
-	return exec_command_on_condition(control, command_fn, data, data_destructor, NULL);
-}
-
-struct stasis_app_control_dial_data {
-	char endpoint[AST_CHANNEL_NAME];
-	int timeout;
-};
-
-static int app_control_dial(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy);
-	struct stasis_app_control_dial_data *dial_data = data;
-	enum ast_dial_result res;
-	char *tech, *resource;
-	struct ast_channel *new_chan;
-	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
-
-	tech = dial_data->endpoint;
-	if (!(resource = strchr(tech, '/'))) {
-		return -1;
-	}
-	*resource++ = '\0';
-
-	if (!dial) {
-		ast_log(LOG_ERROR, "Failed to create dialing structure.\n");
-		return -1;
-	}
-
-	if (ast_dial_append(dial, tech, resource, NULL) < 0) {
-		ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
-		return -1;
-	}
-
-	ast_dial_set_global_timeout(dial, dial_data->timeout);
-
-	res = ast_dial_run(dial, NULL, 0);
-	if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) {
-		return -1;
-	}
-
-	if (!(bridge = ast_bridge_basic_new())) {
-		ast_log(LOG_ERROR, "Failed to create basic bridge.\n");
-		return -1;
-	}
-
-	if (ast_bridge_impart(bridge, new_chan, NULL, NULL,
-		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-		ast_hangup(new_chan);
-	} else {
-		control_add_channel_to_bridge(control, chan, bridge);
-	}
-
-	return 0;
-}
-
-int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context,
-			    int timeout)
-{
-	struct stasis_app_control_dial_data *dial_data;
-
-	if (!(dial_data = ast_calloc(1, sizeof(*dial_data)))) {
-		return -1;
-	}
-
-	if (!ast_strlen_zero(endpoint)) {
-		ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));
-	} else if (!ast_strlen_zero(exten) && !ast_strlen_zero(context)) {
-		snprintf(dial_data->endpoint, sizeof(dial_data->endpoint), "Local/%s@%s", exten, context);
-	} else {
-		return -1;
-	}
-
-	if (timeout > 0) {
-		dial_data->timeout = timeout * 1000;
-	} else if (timeout == -1) {
-		dial_data->timeout = -1;
-	} else {
-		dial_data->timeout = 30000;
-	}
-
-	stasis_app_send_command_async(control, app_control_dial, dial_data, ast_free_ptr);
-
-	return 0;
-}
-
-int stasis_app_control_add_role(struct stasis_app_control *control, const char *role)
-{
-	return ast_channel_add_bridge_role(control->channel, role);
-}
-
-void stasis_app_control_clear_roles(struct stasis_app_control *control)
-{
-	ast_channel_clear_bridge_roles(control->channel);
-}
-
-int control_command_count(struct stasis_app_control *control)
-{
-	return ao2_container_count(control->command_queue);
-}
-
-int control_is_done(struct stasis_app_control *control)
-{
-	/* Called from stasis_app_exec thread; no lock needed */
-	return control->is_done;
-}
-
-void control_mark_done(struct stasis_app_control *control)
-{
-	control->is_done = 1;
-}
-
-struct stasis_app_control_continue_data {
-	char context[AST_MAX_CONTEXT];
-	char extension[AST_MAX_EXTENSION];
-	int priority;
-};
-
-static int app_control_continue(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_control_continue_data *continue_data = data;
-
-	ast_assert(control->channel != NULL);
-
-	/* If we're in a Stasis bridge, depart it before going back to the
-	 * dialplan */
-	if (stasis_app_get_bridge(control)) {
-		ast_bridge_depart(control->channel);
-	}
-
-	/* Called from stasis_app_exec thread; no lock needed */
-	ast_explicit_goto(control->channel, continue_data->context, continue_data->extension, continue_data->priority);
-
-	control->is_done = 1;
-
-	return 0;
-}
-
-int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
-{
-	struct stasis_app_control_continue_data *continue_data;
-
-	if (!(continue_data = ast_calloc(1, sizeof(*continue_data)))) {
-		return -1;
-	}
-	ast_copy_string(continue_data->context, S_OR(context, ""), sizeof(continue_data->context));
-	ast_copy_string(continue_data->extension, S_OR(extension, ""), sizeof(continue_data->extension));
-	if (priority > 0) {
-		continue_data->priority = priority;
-	} else {
-		continue_data->priority = -1;
-	}
-
-	stasis_app_send_command_async(control, app_control_continue, continue_data, ast_free_ptr);
-
-	return 0;
-}
-
-struct stasis_app_control_dtmf_data {
-	int before;
-	int between;
-	unsigned int duration;
-	int after;
-	char dtmf[];
-};
-
-static int app_control_dtmf(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_control_dtmf_data *dtmf_data = data;
-
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_indicate(chan, AST_CONTROL_PROGRESS);
-	}
-
-	if (dtmf_data->before) {
-		ast_safe_sleep(chan, dtmf_data->before);
-	}
-
-	ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
-
-	if (dtmf_data->after) {
-		ast_safe_sleep(chan, dtmf_data->after);
-	}
-
-	return 0;
-}
-
-int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
-{
-	struct stasis_app_control_dtmf_data *dtmf_data;
-
-	if (!(dtmf_data = ast_calloc(1, sizeof(*dtmf_data) + strlen(dtmf) + 1))) {
-		return -1;
-	}
-
-	dtmf_data->before = before;
-	dtmf_data->between = between;
-	dtmf_data->duration = duration;
-	dtmf_data->after = after;
-	strcpy(dtmf_data->dtmf, dtmf);
-
-	stasis_app_send_command_async(control, app_control_dtmf, dtmf_data, ast_free_ptr);
-
-	return 0;
-}
-
-static int app_control_ring(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_indicate(control->channel, AST_CONTROL_RINGING);
-
-	return 0;
-}
-
-int stasis_app_control_ring(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_ring, NULL, NULL);
-
-	return 0;
-}
-
-static int app_control_ring_stop(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_indicate(control->channel, -1);
-
-	return 0;
-}
-
-int stasis_app_control_ring_stop(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_ring_stop, NULL, NULL);
-
-	return 0;
-}
-
-struct stasis_app_control_mute_data {
-	enum ast_frame_type frametype;
-	unsigned int direction;
-};
-
-static int app_control_mute(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_control_mute_data *mute_data = data;
-	SCOPED_CHANNELLOCK(lockvar, chan);
-
-	ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype);
-
-	return 0;
-}
-
-int stasis_app_control_mute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
-{
-	struct stasis_app_control_mute_data *mute_data;
-
-	if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
-		return -1;
-	}
-
-	mute_data->direction = direction;
-	mute_data->frametype = frametype;
-
-	stasis_app_send_command_async(control, app_control_mute, mute_data, ast_free_ptr);
-
-	return 0;
-}
-
-static int app_control_unmute(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct stasis_app_control_mute_data *mute_data = data;
-	SCOPED_CHANNELLOCK(lockvar, chan);
-
-	ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype);
-
-	return 0;
-}
-
-int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
-{
-	struct stasis_app_control_mute_data *mute_data;
-
-	if (!(mute_data = ast_calloc(1, sizeof(*mute_data)))) {
-		return -1;
-	}
-
-	mute_data->direction = direction;
-	mute_data->frametype = frametype;
-
-	stasis_app_send_command_async(control, app_control_unmute, mute_data, ast_free_ptr);
-
-	return 0;
-}
-
-int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value)
-{
-	return pbx_builtin_setvar_helper(control->channel, variable, value);
-}
-
-static int app_control_hold(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_indicate(control->channel, AST_CONTROL_HOLD);
-
-	return 0;
-}
-
-void stasis_app_control_hold(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_hold, NULL, NULL);
-}
-
-static int app_control_unhold(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_indicate(control->channel, AST_CONTROL_UNHOLD);
-
-	return 0;
-}
-
-void stasis_app_control_unhold(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_unhold, NULL, NULL);
-}
-
-static int app_control_moh_start(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	char *moh_class = data;
-
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_indicate(chan, AST_CONTROL_PROGRESS);
-	}
-
-	ast_moh_start(chan, moh_class, NULL);
-
-	return 0;
-}
-
-void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
-{
-	char *data = NULL;
-
-	if (!ast_strlen_zero(moh_class)) {
-		data = ast_strdup(moh_class);
-	}
-
-	stasis_app_send_command_async(control, app_control_moh_start, data, ast_free_ptr);
-}
-
-static int app_control_moh_stop(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	ast_moh_stop(chan);
-	return 0;
-}
-
-void stasis_app_control_moh_stop(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_moh_stop, NULL, NULL);
-}
-
-static int app_control_silence_start(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_indicate(chan, AST_CONTROL_PROGRESS);
-	}
-
-	if (control->silgen) {
-		/* We have a silence generator, but it may have been implicitly
-		 * disabled by media actions (music on hold, playing media,
-		 * etc.) Just stop it and restart a new one.
-		 */
-		ast_channel_stop_silence_generator(
-			control->channel, control->silgen);
-	}
-
-	ast_debug(3, "%s: Starting silence generator\n",
-		stasis_app_control_get_channel_id(control));
-	control->silgen = ast_channel_start_silence_generator(control->channel);
-
-	if (!control->silgen) {
-		ast_log(LOG_WARNING,
-			"%s: Failed to start silence generator.\n",
-			stasis_app_control_get_channel_id(control));
-	}
-
-	return 0;
-}
-
-void stasis_app_control_silence_start(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_silence_start, NULL, NULL);
-}
-
-static int app_control_silence_stop(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	if (control->silgen) {
-		ast_debug(3, "%s: Stopping silence generator\n",
-			stasis_app_control_get_channel_id(control));
-		ast_channel_stop_silence_generator(
-			control->channel, control->silgen);
-		control->silgen = NULL;
-	}
-
-	return 0;
-}
-
-void stasis_app_control_silence_stop(struct stasis_app_control *control)
-{
-	stasis_app_send_command_async(control, app_control_silence_stop, NULL, NULL);
-}
-
-struct ast_channel_snapshot *stasis_app_control_get_snapshot(
-	const struct stasis_app_control *control)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
-
-	msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
-		stasis_app_control_get_channel_id(control));
-	if (!msg) {
-		return NULL;
-	}
-
-	snapshot = stasis_message_data(msg);
-	ast_assert(snapshot != NULL);
-
-	ao2_ref(snapshot, +1);
-	return snapshot;
-}
-
-static int app_send_command_on_condition(struct stasis_app_control *control,
-					 stasis_app_command_cb command_fn, void *data,
-					 command_data_destructor_fn data_destructor,
-					 app_command_can_exec_cb can_exec_fn)
-{
-	RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
-
-	if (control == NULL) {
-		return -1;
-	}
-
-	command = exec_command_on_condition(
-		control, command_fn, data, data_destructor, can_exec_fn);
-	if (!command) {
-		return -1;
-	}
-
-	return command_join(command);
-}
-
-int stasis_app_send_command(struct stasis_app_control *control,
-	stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
-{
-	return app_send_command_on_condition(control, command_fn, data, data_destructor, NULL);
-}
-
-int stasis_app_send_command_async(struct stasis_app_control *control,
-	stasis_app_command_cb command_fn, void *data,
-	command_data_destructor_fn data_destructor)
-{
-	RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup);
-
-	if (control == NULL) {
-		return -1;
-	}
-
-	command = exec_command(control, command_fn, data, data_destructor);
-	if (!command) {
-		return -1;
-	}
-
-	return 0;
-}
-
-struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control)
-{
-	if (!control) {
-		return NULL;
-	} else {
-		SCOPED_AO2LOCK(lock, control);
-		return control->bridge;
-	}
-}
-
-static int bridge_channel_depart(struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct ast_bridge_channel *bridge_channel = data;
-
-	{
-		SCOPED_CHANNELLOCK(lock, chan);
-
-		if (bridge_channel != ast_channel_internal_bridge_channel(chan)) {
-			ast_debug(3, "%s: Channel is no longer in departable state\n",
-				ast_channel_uniqueid(chan));
-			return -1;
-		}
-	}
-
-	ast_debug(3, "%s: Channel departing bridge\n",
-		ast_channel_uniqueid(chan));
-
-	ast_bridge_depart(chan);
-
-	return 0;
-}
-
-static void bridge_after_cb(struct ast_channel *chan, void *data)
-{
-	struct stasis_app_control *control = data;
-	SCOPED_AO2LOCK(lock, control);
-	struct ast_bridge_channel *bridge_channel;
-
-	ast_debug(3, "%s, %s: Channel leaving bridge\n",
-		ast_channel_uniqueid(chan), control->bridge->uniqueid);
-
-	ast_assert(chan == control->channel);
-
-	/* Restore the channel's PBX */
-	ast_channel_pbx_set(control->channel, control->pbx);
-	control->pbx = NULL;
-
-	app_unsubscribe_bridge(control->app, control->bridge);
-
-	/* No longer in the bridge */
-	control->bridge = NULL;
-
-	/* Get the bridge channel so we don't depart from the wrong bridge */
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-
-	/* Depart this channel from the bridge using the command queue if possible */
-	stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);
-	if (stasis_app_channel_is_stasis_end_published(chan)) {
-		/* The channel has had a StasisEnd published on it, but until now had remained in
-		 * the bridging system. This means that the channel moved from a Stasis bridge to a
-		 * non-Stasis bridge and is now exiting the bridging system. Because of this, the
-		 * channel needs to exit the Stasis application and go to wherever the non-Stasis
-		 * bridge has directed it to go. If the non-Stasis bridge has not set up an after
-		 * bridge destination, then the channel should be hung up.
-		 */
-		int hangup_flag;
-
-		hangup_flag = ast_bridge_setup_after_goto(chan) ? AST_SOFTHANGUP_DEV : AST_SOFTHANGUP_ASYNCGOTO;
-		ast_channel_lock(chan);
-		ast_softhangup_nolock(chan, hangup_flag);
-		ast_channel_unlock(chan);
-	}
-}
-
-static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason,
-	void *data)
-{
-	struct stasis_app_control *control = data;
-
-	bridge_after_cb(control->channel, data);
-
-	ast_debug(3, "  reason: %s\n",
-		ast_bridge_after_cb_reason_string(reason));
-}
-
-int control_add_channel_to_bridge(
-	struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct ast_bridge *bridge = data;
-	int res;
-
-	if (!control || !bridge) {
-		return -1;
-	}
-
-	ast_debug(3, "%s: Adding to bridge %s\n",
-		stasis_app_control_get_channel_id(control),
-		bridge->uniqueid);
-
-	ast_assert(chan != NULL);
-
-	/* Depart whatever Stasis bridge we're currently in. */
-	if (stasis_app_get_bridge(control)) {
-		/* Note that it looks like there's a race condition here, since
-		 * we don't have control locked. But this happens from the
-		 * control callback thread, so there won't be any other
-		 * concurrent attempts to bridge.
-		 */
-		ast_bridge_depart(chan);
-	}
-
-
-	res = ast_bridge_set_after_callback(chan, bridge_after_cb,
-		bridge_after_cb_failed, control);
-	if (res != 0) {
-		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
-		return -1;
-	}
-
-	{
-		/* pbx and bridge are modified by the bridging impart thread.
-		 * It shouldn't happen concurrently, but we still need to lock
-		 * for the memory fence.
-		 */
-		SCOPED_AO2LOCK(lock, control);
-
-		/* Ensure the controlling application is subscribed early enough
-		 * to receive the ChannelEnteredBridge message. This works in concert
-		 * with the subscription handled in the Stasis application execution
-		 * loop */
-		app_subscribe_bridge(control->app, bridge);
-
-		/* Save off the channel's PBX */
-		ast_assert(control->pbx == NULL);
-		if (!control->pbx) {
-			control->pbx = ast_channel_pbx(chan);
-			ast_channel_pbx_set(chan, NULL);
-		}
-
-		res = ast_bridge_impart(bridge,
-			chan,
-			NULL, /* swap channel */
-			NULL, /* features */
-			AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
-		if (res != 0) {
-			ast_log(LOG_ERROR, "Error adding channel to bridge\n");
-			ast_channel_pbx_set(chan, control->pbx);
-			control->pbx = NULL;
-			return -1;
-		}
-
-		ast_assert(stasis_app_get_bridge(control) == NULL);
-		control->bridge = bridge;
-	}
-	return 0;
-}
-
-int stasis_app_control_add_channel_to_bridge(
-	struct stasis_app_control *control, struct ast_bridge *bridge)
-{
-	ast_debug(3, "%s: Sending channel add_to_bridge command\n",
-			stasis_app_control_get_channel_id(control));
-
-	return app_send_command_on_condition(
-		control, control_add_channel_to_bridge, bridge, NULL,
-		app_control_can_add_channel_to_bridge);
-}
-
-static int app_control_remove_channel_from_bridge(
-	struct stasis_app_control *control,
-	struct ast_channel *chan, void *data)
-{
-	struct ast_bridge *bridge = data;
-
-	if (!control) {
-		return -1;
-	}
-
-	/* We should only depart from our own bridge */
-	ast_debug(3, "%s: Departing bridge %s\n",
-		stasis_app_control_get_channel_id(control),
-		bridge->uniqueid);
-
-	if (bridge != stasis_app_get_bridge(control)) {
-		ast_log(LOG_WARNING, "%s: Not in bridge %s; not removing\n",
-			stasis_app_control_get_channel_id(control),
-			bridge->uniqueid);
-		return -1;
-	}
-
-	ast_bridge_depart(chan);
-	return 0;
-}
-
-int stasis_app_control_remove_channel_from_bridge(
-	struct stasis_app_control *control, struct ast_bridge *bridge)
-{
-	ast_debug(3, "%s: Sending channel remove_from_bridge command\n",
-			stasis_app_control_get_channel_id(control));
-	return app_send_command_on_condition(
-		control, app_control_remove_channel_from_bridge, bridge, NULL,
-		app_control_can_remove_channel_from_bridge);
-}
-
-const char *stasis_app_control_get_channel_id(
-	const struct stasis_app_control *control)
-{
-	return ast_channel_uniqueid(control->channel);
-}
-
-void stasis_app_control_publish(
-	struct stasis_app_control *control, struct stasis_message *message)
-{
-	if (!control || !control->channel || !message) {
-		return;
-	}
-	stasis_publish(ast_channel_topic(control->channel), message);
-}
-
-int stasis_app_control_queue_control(struct stasis_app_control *control,
-	enum ast_control_frame_type frame_type)
-{
-	return ast_queue_control(control->channel, frame_type);
-}
-
-int control_dispatch_all(struct stasis_app_control *control,
-	struct ast_channel *chan)
-{
-	int count = 0;
-	struct ao2_iterator i;
-	void *obj;
-
-	ast_assert(control->channel == chan);
-
-	i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK);
-
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup);
-		command_invoke(command, control, chan);
-		++count;
-	}
-
-	ao2_iterator_destroy(&i);
-	return count;
-}
-
-void control_wait(struct stasis_app_control *control)
-{
-	if (!control) {
-		return;
-	}
-
-	ast_assert(control->command_queue != NULL);
-
-	ao2_lock(control->command_queue);
-	while (ao2_container_count(control->command_queue) == 0) {
-		int res = ast_cond_wait(&control->wait_cond,
-			ao2_object_get_lockaddr(control->command_queue));
-		if (res < 0) {
-			ast_log(LOG_ERROR, "Error waiting on command queue\n");
-			break;
-		}
-	}
-	ao2_unlock(control->command_queue);
-}
-
-int control_prestart_dispatch_all(struct stasis_app_control *control,
-	struct ast_channel *chan)
-{
-	struct ao2_container *command_queue;
-	int count = 0;
-	struct ao2_iterator iter;
-	struct stasis_app_command *command;
-
-	ast_channel_lock(chan);
-	command_queue = command_prestart_get_container(chan);
-	ast_channel_unlock(chan);
-	if (!command_queue) {
-		return 0;
-	}
-
-	iter = ao2_iterator_init(command_queue, AO2_ITERATOR_UNLINK);
-
-	while ((command = ao2_iterator_next(&iter))) {
-		command_invoke(command, control, chan);
-		ao2_cleanup(command);
-		++count;
-	}
-
-	ao2_iterator_destroy(&iter);
-	ao2_cleanup(command_queue);
-	return count;
-}
-
-struct stasis_app *control_app(struct stasis_app_control *control)
-{
-	return control->app;
-}
diff --git a/res/stasis/control.h b/res/stasis/control.h
deleted file mode 100644
index a139f82..0000000
--- a/res/stasis/control.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_CONTROL_H
-#define _ASTERISK_RES_STASIS_CONTROL_H
-
-/*! \file
- *
- * \brief Internal API for the Stasis application controller.
- *
- * \author David M. Lee, II <dlee at digium.com>
- * \since 12
- */
-
-#include "asterisk/stasis_app.h"
-
-/*!
- * \brief Create a control object.
- *
- * \param channel Channel to control.
- * \param app stasis_app for which this control is being created.
- *
- * \return New control object.
- * \return \c NULL on error.
- */
-struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app);
-
-/*!
- * \brief Dispatch all commands enqueued to this control.
- *
- * \param control Control object to dispatch.
- * \param chan Associated channel.
- * \return Number of commands executed
- */
-int control_dispatch_all(struct stasis_app_control *control,
-	struct ast_channel *chan);
-
-/*!
- * \brief Blocks until \a control's command queue has a command available.
- *
- * \param control Control to block on.
- */
-void control_wait(struct stasis_app_control *control);
-
-/*!
- * \brief Returns the count of items in a control's command queue.
- *
- * \param control Control to count commands on
- *
- * \retval number of commands in the command que
- */
-int control_command_count(struct stasis_app_control *control);
-
-/*!
- * \brief Returns true if control_continue() has been called on this \a control.
- *
- * \param control Control to query.
- * \return True (non-zero) if control_continue() has been called.
- * \return False (zero) otherwise.
- */
-int control_is_done(struct stasis_app_control *control);
-
-void control_mark_done(struct stasis_app_control *control);
-
-/*!
- * \brief Dispatch all queued prestart commands
- *
- * \param control The control for chan
- * \param channel The channel on which commands should be executed
- *
- * \return The number of commands executed
- */
-int control_prestart_dispatch_all(struct stasis_app_control *control,
-	struct ast_channel *chan);
-
-/*!
- * \brief Returns the pointer (non-reffed) to the app associated with this control
- *
- * \param control Control to query.
- *
- * \returns A pointer to the associated stasis_app
- */
-struct stasis_app *control_app(struct stasis_app_control *control);
-
-/*!
- * \brief Command callback for adding a channel to a bridge
- *
- * \param control The control for chan
- * \param channel The channel on which commands should be executed
- * \param bridge Data to be passed to the callback
- */
-int control_add_channel_to_bridge(
-	struct stasis_app_control *control,
-	struct ast_channel *chan, void *obj);
-
-
-#endif /* _ASTERISK_RES_STASIS_CONTROL_H */
diff --git a/res/stasis/messaging.c b/res/stasis/messaging.c
deleted file mode 100644
index fcc17e7..0000000
--- a/res/stasis/messaging.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- *
- * \brief Stasis out-of-call text message support
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420100 $")
-
-#include "asterisk/message.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/vector.h"
-#include "asterisk/lock.h"
-#include "asterisk/utils.h"
-#include "asterisk/test.h"
-#include "messaging.h"
-
-/*!
- * \brief Number of buckets for the \ref endpoint_subscriptions container
- */
-#define ENDPOINTS_NUM_BUCKETS 127
-
-/*! \brief Storage object for an application */
-struct application_tuple {
-	/*! ao2 ref counted private object to pass to the callback */
-	void *pvt;
-	/*! The callback to call when this application has a message */
-	message_received_cb callback;
-	/*! The name (key) of the application */
-	char app_name[];
-};
-
-/*! \brief A subscription to some endpoint or technology */
-struct message_subscription {
-	/*! The applications that have subscribed to this endpoint or tech */
-	AST_VECTOR(, struct application_tuple *) applications;
-	/*! The name of this endpoint or tech */
-	char token[];
-};
-
-/*! \brief The subscriptions to endpoints */
-static struct ao2_container *endpoint_subscriptions;
-
-/*!
- * \brief The subscriptions to technologies
- *
- * \note These are stored separately from standard endpoints, given how
- * relatively few of them there are.
- */
-static AST_VECTOR(,struct message_subscription *) tech_subscriptions;
-
-/*! \brief RWLock for \c tech_subscriptions */
-static ast_rwlock_t tech_subscriptions_lock;
-
-/*! \internal \brief Destructor for \c application_tuple */
-static void application_tuple_dtor(void *obj)
-{
-	struct application_tuple *tuple = obj;
-
-	ao2_cleanup(tuple->pvt);
-}
-
-/*! \internal \brief Constructor for \c application_tuple */
-static struct application_tuple *application_tuple_alloc(const char *app_name, message_received_cb callback, void *pvt)
-{
-	struct application_tuple *tuple;
-	size_t size = sizeof(*tuple) + strlen(app_name) + 1;
-
-	ast_assert(callback != NULL);
-
-	tuple = ao2_alloc_options(size, application_tuple_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!tuple) {
-		return NULL;
-	}
-
-	strcpy(tuple->app_name, app_name); /* Safe */
-	tuple->pvt = ao2_bump(pvt);
-	tuple->callback = callback;
-
-	return tuple;
-}
-
-/*! \internal \brief Destructor for \ref message_subscription */
-static void message_subscription_dtor(void *obj)
-{
-	struct message_subscription *sub = obj;
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&sub->applications); i++) {
-		struct application_tuple *tuple = AST_VECTOR_GET(&sub->applications, i);
-
-		ao2_cleanup(tuple);
-	}
-	AST_VECTOR_FREE(&sub->applications);
-}
-
-/*! \internal \brief Constructor for \ref message_subscription */
-static struct message_subscription *message_subscription_alloc(const char *token)
-{
-	struct message_subscription *sub;
-	size_t size = sizeof(*sub) + strlen(token) + 1;
-
-	sub = ao2_alloc_options(size, message_subscription_dtor, AO2_ALLOC_OPT_LOCK_RWLOCK);
-	if (!sub) {
-		return NULL;
-	}
-	strcpy(sub->token, token); /* Safe */
-
-	return sub;
-}
-
-/*! AO2 hash function for \ref message_subscription */
-static int message_subscription_hash_cb(const void *obj, const int flags)
-{
-	const struct message_subscription *sub;
-	const char *key;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_KEY:
-		key = obj;
-		break;
-	case OBJ_SEARCH_OBJECT:
-		sub = obj;
-		key = sub->token;
-		break;
-	default:
-		/* Hash can only work on something with a full key. */
-		ast_assert(0);
-		return 0;
-	}
-	return ast_str_hash(key);
-}
-
-/*! AO2 comparison function for \ref message_subscription */
-static int message_subscription_compare_cb(void *obj, void *arg, int flags)
-{
-	const struct message_subscription *object_left = obj;
-	const struct message_subscription *object_right = arg;
-	const char *right_key = arg;
-	int cmp;
-
-	switch (flags & OBJ_SEARCH_MASK) {
-	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->token;
-		/* Fall through */
-	case OBJ_SEARCH_KEY:
-		cmp = strcmp(object_left->token, right_key);
-		break;
-	case OBJ_SEARCH_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->token, right_key, strlen(right_key));
-		break;
-	default:
-		/*
-		 * What arg points to is specific to this traversal callback
-		 * and has no special meaning to astobj2.
-		 */
-		cmp = 0;
-		break;
-	}
-	if (cmp) {
-		return 0;
-	}
-	/*
-	 * At this point the traversal callback is identical to a sorted
-	 * container.
-	 */
-	return CMP_MATCH;
-}
-
-/*! \internal \brief Convert a \c ast_msg To/From URI to a Stasis endpoint name */
-static void msg_to_endpoint(const struct ast_msg *msg, char *buf, size_t len)
-{
-	const char *endpoint = ast_msg_get_endpoint(msg);
-
-	snprintf(buf, len, "%s%s%s", ast_msg_get_tech(msg),
-		ast_strlen_zero(endpoint) ? "" : "/",
-		S_OR(endpoint, ""));
-}
-
-/*! \internal
- * \brief Callback from the \c message API that determines if we can handle
- * this message
- */
-static int has_destination_cb(const struct ast_msg *msg)
-{
-	struct message_subscription *sub;
-	int i;
-	char buf[256];
-
-	msg_to_endpoint(msg, buf, sizeof(buf));
-
-	ast_rwlock_rdlock(&tech_subscriptions_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&tech_subscriptions); i++) {
-		sub = AST_VECTOR_GET(&tech_subscriptions, i);
-
-		if (sub && (!strncasecmp(sub->token, buf, strlen(sub->token))
-		            || !strncasecmp(sub->token, buf, strlen(sub->token)))) {
-			ast_rwlock_unlock(&tech_subscriptions_lock);
-			sub = NULL; /* No ref bump! */
-			goto match;
-		}
-
-	}
-	ast_rwlock_unlock(&tech_subscriptions_lock);
-
-	sub = ao2_find(endpoint_subscriptions, buf, OBJ_SEARCH_KEY);
-	if (sub) {
-		goto match;
-	}
-
-	ast_debug(1, "No subscription found for %s\n", buf);
-	return 0;
-
-match:
-	ao2_cleanup(sub);
-	return 1;
-}
-
-static struct ast_json *msg_to_json(struct ast_msg *msg)
-{
-	struct ast_json *json_obj;
-	struct ast_json *json_vars;
-	struct ast_msg_var_iterator *it_vars;
-	const char *name;
-	const char *value;
-
-	it_vars = ast_msg_var_iterator_init(msg);
-	if (!it_vars) {
-		return NULL;
-	}
-
-	json_vars = ast_json_array_create();
-	if (!json_vars) {
-		return NULL;
-	}
-
-	while (ast_msg_var_iterator_next(msg, it_vars, &name, &value)) {
-		struct ast_json *json_tuple;
-
-		json_tuple = ast_json_pack("{s: s}", name, value);
-		if (!json_tuple) {
-			ast_json_free(json_vars);
-			return NULL;
-		}
-
-		ast_json_array_append(json_vars, json_tuple);
-		ast_msg_var_unref_current(it_vars);
-	}
-	ast_msg_var_iterator_destroy(it_vars);
-
-	json_obj = ast_json_pack("{s: s, s: s, s: s, s: o}",
-		"from", ast_msg_get_from(msg),
-		"to", ast_msg_get_to(msg),
-		"body", ast_msg_get_body(msg),
-		"variables", json_vars);
-
-	return json_obj;
-}
-
-static int handle_msg_cb(struct ast_msg *msg)
-{
-	struct message_subscription *sub;
-	int i;
-	char buf[256];
-	const char *endpoint_name;
-	struct ast_json *json_msg;
-
-	msg_to_endpoint(msg, buf, sizeof(buf));
-
-	ast_rwlock_rdlock(&tech_subscriptions_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&tech_subscriptions); i++) {
-		sub = AST_VECTOR_GET(&tech_subscriptions, i);
-
-		if (!sub) {
-			continue;
-		}
-
-		if (!strncasecmp(sub->token, buf, strlen(sub->token))) {
-			ast_rwlock_unlock(&tech_subscriptions_lock);
-			ao2_bump(sub);
-			endpoint_name = buf;
-			goto match;
-		}
-	}
-	ast_rwlock_unlock(&tech_subscriptions_lock);
-
-	sub = ao2_find(endpoint_subscriptions, buf, OBJ_SEARCH_KEY);
-	if (sub) {
-		endpoint_name = buf;
-		goto match;
-	}
-
-	return -1;
-
-match:
-	ast_debug(3, "Dispatching message for %s\n", endpoint_name);
-
-	json_msg = msg_to_json(msg);
-	if (!json_msg) {
-		ao2_ref(sub, -1);
-		return -1;
-	}
-
-	for (i = 0; i < AST_VECTOR_SIZE(&sub->applications); i++) {
-		struct application_tuple *tuple = AST_VECTOR_GET(&sub->applications, i);
-
-		tuple->callback(endpoint_name, json_msg, tuple->pvt);
-	}
-
-	ast_json_unref(json_msg);
-	ao2_ref(sub, -1);
-	return 0;
-}
-
-struct ast_msg_handler ari_msg_handler = {
-	.name = "ari",
-	.handle_msg = handle_msg_cb,
-	.has_destination = has_destination_cb,
-};
-
-static int messaging_subscription_cmp(struct message_subscription *sub, const char *key)
-{
-	return !strcmp(sub->token, key) ? 1 : 0;
-}
-
-static int application_tuple_cmp(struct application_tuple *item, const char *key)
-{
-	return !strcmp(item->app_name, key) ? 1 : 0;
-}
-
-static int is_app_subscribed(struct message_subscription *sub, const char *app_name)
-{
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&sub->applications); i++) {
-		struct application_tuple *tuple;
-
-		tuple = AST_VECTOR_GET(&sub->applications, i);
-		if (tuple && !strcmp(tuple->app_name, app_name)) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static struct message_subscription *get_subscription(struct ast_endpoint *endpoint)
-{
-	struct message_subscription *sub = NULL;
-
-	if (!ast_strlen_zero(ast_endpoint_get_resource(endpoint))) {
-		sub = ao2_find(endpoint_subscriptions, endpoint, OBJ_SEARCH_KEY);
-	} else {
-		int i;
-
-		ast_rwlock_rdlock(&tech_subscriptions_lock);
-		for (i = 0; i < AST_VECTOR_SIZE(&tech_subscriptions); i++) {
-			sub = AST_VECTOR_GET(&tech_subscriptions, i);
-
-			if (sub && !strcmp(sub->token, ast_endpoint_get_tech(endpoint))) {
-				ao2_bump(sub);
-				break;
-			}
-		}
-		ast_rwlock_unlock(&tech_subscriptions_lock);
-	}
-
-	return sub;
-}
-
-void messaging_app_unsubscribe_endpoint(const char *app_name, const char *endpoint_id)
-{
-	RAII_VAR(struct message_subscription *, sub, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_endpoint *, endpoint, NULL, ao2_cleanup);
-
-	endpoint = ast_endpoint_find_by_id(endpoint_id);
-	if (!endpoint) {
-		return;
-	}
-
-	sub = get_subscription(endpoint);
-	if (!sub) {
-		return;
-	}
-
-	ao2_lock(sub);
-	if (!is_app_subscribed(sub, app_name)) {
-		ao2_unlock(sub);
-		return;
-	}
-
-	AST_VECTOR_REMOVE_CMP_UNORDERED(&sub->applications, app_name, application_tuple_cmp, ao2_cleanup);
-	if (AST_VECTOR_SIZE(&sub->applications) == 0) {
-		if (!ast_strlen_zero(ast_endpoint_get_resource(endpoint))) {
-			ao2_unlink(endpoint_subscriptions, sub);
-		} else {
-			ast_rwlock_wrlock(&tech_subscriptions_lock);
-			AST_VECTOR_REMOVE_CMP_UNORDERED(&tech_subscriptions, ast_endpoint_get_id(endpoint),
-				messaging_subscription_cmp, AST_VECTOR_ELEM_CLEANUP_NOOP);
-			ast_rwlock_unlock(&tech_subscriptions_lock);
-		}
-	}
-	ao2_unlock(sub);
-	ao2_ref(sub, -1);
-
-	ast_debug(3, "App '%s' unsubscribed to messages from endpoint '%s'\n", app_name, ast_endpoint_get_id(endpoint));
-	ast_test_suite_event_notify("StasisMessagingSubscription", "SubState: Unsubscribed\r\nAppName: %s\r\nToken: %s\r\n",
-		app_name, ast_endpoint_get_id(endpoint));
-}
-
-static struct message_subscription *get_or_create_subscription(struct ast_endpoint *endpoint)
-{
-	struct message_subscription *sub = get_subscription(endpoint);
-
-	if (sub) {
-		return sub;
-	}
-
-	sub = message_subscription_alloc(ast_endpoint_get_id(endpoint));
-	if (!sub) {
-		return NULL;
-	}
-
-	if (!ast_strlen_zero(ast_endpoint_get_resource(endpoint))) {
-		ao2_link(endpoint_subscriptions, sub);
-	} else {
-		ast_rwlock_wrlock(&tech_subscriptions_lock);
-		AST_VECTOR_APPEND(&tech_subscriptions, ao2_bump(sub));
-		ast_rwlock_unlock(&tech_subscriptions_lock);
-	}
-
-	return sub;
-}
-
-int messaging_app_subscribe_endpoint(const char *app_name, struct ast_endpoint *endpoint, message_received_cb callback, void *pvt)
-{
-	RAII_VAR(struct message_subscription *, sub, NULL, ao2_cleanup);
-	struct application_tuple *tuple;
-
-	sub = get_or_create_subscription(endpoint);
-	if (!sub) {
-		return -1;
-	}
-
-	ao2_lock(sub);
-	if (is_app_subscribed(sub, app_name)) {
-		ao2_unlock(sub);
-		return 0;
-	}
-
-	tuple = application_tuple_alloc(app_name, callback, pvt);
-	if (!tuple) {
-		ao2_unlock(sub);
-		return -1;
-	}
-	AST_VECTOR_APPEND(&sub->applications, tuple);
-	ao2_unlock(sub);
-
-	ast_debug(3, "App '%s' subscribed to messages from endpoint '%s'\n", app_name, ast_endpoint_get_id(endpoint));
-	ast_test_suite_event_notify("StasisMessagingSubscription", "SubState: Subscribed\r\nAppName: %s\r\nToken: %s\r\n",
-		app_name, ast_endpoint_get_id(endpoint));
-
-	return 0;
-}
-
-
-int messaging_cleanup(void)
-{
-	ast_msg_handler_unregister(&ari_msg_handler);
-	ao2_ref(endpoint_subscriptions, -1);
-	AST_VECTOR_FREE(&tech_subscriptions);
-	ast_rwlock_destroy(&tech_subscriptions_lock);\
-
-	return 0;
-}
-
-int messaging_init(void)
-{
-	endpoint_subscriptions = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0,
-		ENDPOINTS_NUM_BUCKETS, message_subscription_hash_cb, NULL,
-		message_subscription_compare_cb, "Endpoint messaging subscription container creation");
-	if (!endpoint_subscriptions) {
-		return -1;
-	}
-
-	if (AST_VECTOR_INIT(&tech_subscriptions, 4)) {
-		ao2_ref(endpoint_subscriptions, -1);
-		return -1;
-	}
-
-	if (ast_rwlock_init(&tech_subscriptions_lock)) {
-		ao2_ref(endpoint_subscriptions, -1);
-		AST_VECTOR_FREE(&tech_subscriptions);
-		return -1;
-	}
-
-	if (ast_msg_handler_register(&ari_msg_handler)) {
-		ao2_ref(endpoint_subscriptions, -1);
-		AST_VECTOR_FREE(&tech_subscriptions);
-		ast_rwlock_destroy(&tech_subscriptions_lock);
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/res/stasis/messaging.h b/res/stasis/messaging.h
deleted file mode 100644
index 75ef5c9..0000000
--- a/res/stasis/messaging.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_MESSAGING_H
-#define _ASTERISK_RES_STASIS_MESSAGING_H
-
-/*!
- * \file
- *
- * \brief Stasis out-of-call text message support
- *
- * \author Matt Jordan <mjordan at digium.com>
- * \since 12.4.0
- */
-
-/*!
- * \brief Callback handler for when a message is received from the core
- *
- * \param endpoint_id The ID of the endpoint that we received the message from
- * \param json_msg JSON representation of the text message
- * \param pvt ao2 ref counted pvt passed during registration
- *
- * \retval 0 the message was handled
- * \retval non-zero the message was not handled
- */
-typedef int (* message_received_cb)(const char *endpoint_id, struct ast_json *json_msg, void *pvt);
-
-/*!
- * \brief Subscribe for messages from a particular endpoint
- *
- * \param app_name Name of the stasis application to unsubscribe from messaging
- * \param endpoint_id The ID of the endpoint we no longer care about
- *
- * \retval 0 success
- * \retval -1 error
- */
-void messaging_app_unsubscribe_endpoint(const char *app_name, const char *endpoint_id);
-
-/*!
- * \brief Subscribe an application to an endpoint for messages
- *
- * \param app_name The name of the \ref stasis application to subscribe to \c endpoint
- * \param endpoint The endpoint object to subscribe to
- * \param message_received_cb The callback to call when a message is received
- * \param pvt An ao2 ref counted object that will be passed to the callback.
- *
- * \retval 0 subscription was successful
- * \retval -1 subscription failed
- */
-int messaging_app_subscribe_endpoint(const char *app_name, struct ast_endpoint *endpoint, message_received_cb callback, void *pvt);
-
-/*!
- * \brief Tidy up the messaging layer
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int messaging_cleanup(void);
-
-/*!
- * \brief Initialize the messaging layer
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int messaging_init(void);
-
-#endif /* #define _ASTERISK_RES_STASIS_MESSAGING_H  */
diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c
deleted file mode 100644
index 9300bca..0000000
--- a/res/stasis/stasis_bridge.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Stasis bridge subclass.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429062 $")
-
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_after.h"
-#include "asterisk/bridge_internal.h"
-#include "asterisk/bridge_features.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/stasis_channels.h"
-#include "stasis_bridge.h"
-#include "control.h"
-#include "command.h"
-#include "app.h"
-#include "asterisk/stasis_app.h"
-#include "asterisk/pbx.h"
-
-/* ------------------------------------------------------------------- */
-
-static struct ast_bridge_methods bridge_stasis_v_table;
-
-static void bridge_stasis_run_cb(struct ast_channel *chan, void *data)
-{
-	RAII_VAR(char *, app_name, NULL, ast_free);
-	struct ast_app *app_stasis;
-
-	/* Take ownership of the swap_app memory from the datastore */
-	app_name = app_get_replace_channel_app(chan);
-	if (!app_name) {
-		ast_log(LOG_ERROR, "Failed to get app name for %s (%p)\n", ast_channel_name(chan), chan);
-		return;
-	}
-
-	/* find Stasis() */
-	app_stasis = pbx_findapp("Stasis");
-	if (!app_stasis) {
-		ast_log(LOG_WARNING, "Could not find application (Stasis)\n");
-		return;
-	}
-
-	if (ast_check_hangup_locked(chan)) {
-		/* channel hungup, don't run Stasis() */
-		return;
-	}
-
-	/* run Stasis() */
-	pbx_exec(chan, app_stasis, app_name);
-}
-
-static int add_channel_to_bridge(
-	struct stasis_app_control *control,
-	struct ast_channel *chan, void *obj)
-{
-	struct ast_bridge *bridge = obj;
-	int res;
-
-	res = control_add_channel_to_bridge(control,
-		chan, bridge);
-	return res;
-}
-
-static void bridge_stasis_queue_join_action(struct ast_bridge *self,
-	struct ast_bridge_channel *bridge_channel)
-{
-	ast_channel_lock(bridge_channel->chan);
-	command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge,
-		ao2_bump(self), __ao2_cleanup);
-	ast_channel_unlock(bridge_channel->chan);
-}
-
-/*!
- * \internal
- * \brief Push this channel into the Stasis bridge.
- * \since 12.5.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to push.
- * \param swap Bridge channel to swap places with if not NULL.
- *
- * \note On entry, self is already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.  The channel did not get pushed.
- */
-static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
-{
-	struct stasis_app_control *control = stasis_app_control_find_by_channel(bridge_channel->chan);
-
-	if (!control && !stasis_app_channel_is_internal(bridge_channel->chan)) {
-		/* channel not in Stasis(), get it there */
-		/* Attach after-bridge callback and pass ownership of swap_app to it */
-		if (ast_bridge_set_after_callback(bridge_channel->chan,
-			bridge_stasis_run_cb, NULL, NULL)) {
-			ast_log(LOG_ERROR, "Failed to set after bridge callback\n");
-			return -1;
-		}
-
-		bridge_stasis_queue_join_action(self, bridge_channel);
-
-		/* Return -1 so the push fails and the after-bridge callback gets called */
-		return -1;
-	}
-
-	/*
-	 * If going into a holding bridge, default the role to participant, if
-	 * it has no compatible role currently
-	 */
-	if ((self->technology->capabilities & AST_BRIDGE_CAPABILITY_HOLDING)
-	    && !ast_channel_has_role(bridge_channel->chan, "announcer")
-	    && !ast_channel_has_role(bridge_channel->chan, "holding_participant")) {
-		if (ast_channel_add_bridge_role(bridge_channel->chan, "holding_participant")) {
-			ast_log(LOG_ERROR, "Failed to set holding participant on %s\n", ast_channel_name(bridge_channel->chan));
-			return -1;
-		}
-
-		if (ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "none")) {
-			ast_log(LOG_ERROR, "Failed to set holding participant mode on %s\n", ast_channel_name(bridge_channel->chan));
-			return -1;
-		}
-	}
-
-	ao2_cleanup(control);
-	if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) {
-		ast_bridge_channel_update_linkedids(bridge_channel, swap);
-		if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) {
-			ast_bridge_channel_update_accountcodes(bridge_channel, swap);
-		}
-	}
-
-	return ast_bridge_base_v_table.push(self, bridge_channel, swap);
-}
-
-static int bridge_stasis_moving(struct ast_bridge_channel *bridge_channel, void *hook_pvt,
-		struct ast_bridge *src, struct ast_bridge *dst)
-{
-	if (src->v_table == &bridge_stasis_v_table &&
-			dst->v_table != &bridge_stasis_v_table) {
-		RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
-		struct ast_channel *chan;
-
-		chan = bridge_channel->chan;
-		ast_assert(chan != NULL);
-
-		control = stasis_app_control_find_by_channel(chan);
-		if (!control) {
-			return -1;
-		}
-
-		stasis_app_channel_set_stasis_end_published(chan);
-		app_send_end_msg(control_app(control), chan);
-	}
-
-	return -1;
-}
-
-/*!
- * \internal
- * \brief Pull this channel from the Stasis bridge.
- * \since 12.5.0
- *
- * \param self Bridge to operate upon.
- * \param bridge_channel Bridge channel to pull.
- *
- * \note On entry, self is already locked.
- *
- * \return Nothing
- */
-static void bridge_stasis_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
-{
-	if ((self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES)
-		&& ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) {
-		ast_bridge_channel_update_accountcodes(NULL, bridge_channel);
-	}
-
-	if (self->technology->capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
-		ast_channel_clear_bridge_roles(bridge_channel->chan);
-	}
-
-	ast_bridge_move_hook(bridge_channel->features, bridge_stasis_moving, NULL, NULL, 0);
-
-	ast_bridge_base_v_table.pull(self, bridge_channel);
-}
-
-struct ast_bridge *bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id)
-{
-	void *bridge;
-
-	bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_stasis_v_table);
-	bridge = bridge_base_init(bridge, capabilities, flags, "Stasis", name, id);
-	bridge = bridge_register(bridge);
-
-	return bridge;
-}
-
-void bridge_stasis_init(void)
-{
-	/* Setup the Stasis bridge subclass v_table. */
-	bridge_stasis_v_table = ast_bridge_base_v_table;
-	bridge_stasis_v_table.name = "stasis";
-	bridge_stasis_v_table.push = bridge_stasis_push;
-	bridge_stasis_v_table.pull = bridge_stasis_pull;
-}
diff --git a/res/stasis/stasis_bridge.h b/res/stasis/stasis_bridge.h
deleted file mode 100644
index 2590fd7..0000000
--- a/res/stasis/stasis_bridge.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Richard Mudgett <rmudgett at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Internal API for the Stasis bridge subclass.
- *
- * \author Richard Mudgett <rmudgett at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- */
-
-#ifndef _ASTERISK_STASIS_BRIDGE_H
-#define _ASTERISK_STASIS_BRIDGE_H
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-/* ------------------------------------------------------------------- */
-
-/*! Normal capabilities of mixing bridges */
-#define STASIS_BRIDGE_MIXING_CAPABILITIES	\
-	(AST_BRIDGE_CAPABILITY_NATIVE \
-	| AST_BRIDGE_CAPABILITY_1TO1MIX \
-	| AST_BRIDGE_CAPABILITY_MULTIMIX)
-
-/*!
- * \internal
- * \brief Create a new Stasis bridge.
- * \since 12.5.0
- *
- * \param capabilities The capabilities that we require to be used on the bridge
- * \param flags Flags that will alter the behavior of the bridge
- * \param name Name given to the bridge by Stasis (optional)
- * \param id Unique ID given to the bridge by Stasis (optional)
- *
- * \retval a pointer to a new bridge on success
- * \retval NULL on failure
- */
-struct ast_bridge *bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id);
-
-/*!
- * \internal
- * \brief Initialize the Stasis bridge subclass.
- * \since 12.5.0
- *
- * \return Nothing
- */
-void bridge_stasis_init(void);
-
-/* ------------------------------------------------------------------- */
-
-#if defined(__cplusplus) || defined(c_plusplus)
-}
-#endif
-
-#endif	/* _ASTERISK_STASIS_BRIDGE_H */
diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c
deleted file mode 100644
index 1b783e7..0000000
--- a/res/stasis_recording/stored.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stored file operations for Stasis
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419022 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/paths.h"
-#include "asterisk/stasis_app_recording.h"
-
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-struct stasis_app_stored_recording {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);	/*!< Recording's name */
-		AST_STRING_FIELD(file);	/*!< Absolute filename, without extension; for use with streamfile */
-		AST_STRING_FIELD(file_with_ext);	/*!< Absolute filename, with extension; for use with everything else */
-		);
-
-	const char *format;	/*!< Format name (i.e. filename extension) */
-};
-
-static void stored_recording_dtor(void *obj)
-{
-	struct stasis_app_stored_recording *recording = obj;
-
-	ast_string_field_free_memory(recording);
-}
-
-const char *stasis_app_stored_recording_get_file(
-	struct stasis_app_stored_recording *recording)
-{
-	if (!recording) {
-		return NULL;
-	}
-	return recording->file;
-}
-
-/*!
- * \brief Split a path into directory and file, resolving canonical directory.
- *
- * The path is resolved relative to the recording directory. Both dir and file
- * are allocated strings, which you must ast_free().
- *
- * \param path Path to split.
- * \param[out] dir Output parameter for directory portion.
- * \param[out] fail Output parameter for the file portion.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-static int split_path(const char *path, char **dir, char **file)
-{
-	RAII_VAR(char *, relative_dir, NULL, ast_free);
-	RAII_VAR(char *, absolute_dir, NULL, ast_free);
-	RAII_VAR(char *, real_dir, NULL, ast_std_free);
-	char *last_slash;
-	const char *file_portion;
-
-	relative_dir = ast_strdup(path);
-	if (!relative_dir) {
-		return -1;
-	}
-
-	last_slash = strrchr(relative_dir, '/');
-	if (last_slash) {
-		*last_slash = '\0';
-		file_portion = last_slash + 1;
-		ast_asprintf(&absolute_dir, "%s/%s",
-			ast_config_AST_RECORDING_DIR, relative_dir);
-	} else {
-		/* There is no directory portion */
-		file_portion = path;
-		*relative_dir = '\0';
-		absolute_dir = ast_strdup(ast_config_AST_RECORDING_DIR);
-	}
-	if (!absolute_dir) {
-		return -1;
-	}
-
-	real_dir = realpath(absolute_dir, NULL);
-	if (!real_dir) {
-		return -1;
-	}
-
-#if defined(__AST_DEBUG_MALLOC)
-	*dir = ast_strdup(real_dir); /* Dupe so we can ast_free() */
-#else
-	/*
-	 * ast_std_free() and ast_free() are the same thing at this time
-	 * so we don't need to dupe.
-	 */
-	*dir = real_dir;
-	real_dir = NULL;
-#endif	/* defined(__AST_DEBUG_MALLOC) */
-	*file = ast_strdup(file_portion);
-	return 0;
-}
-
-static void safe_closedir(DIR *dirp)
-{
-	if (!dirp) {
-		return;
-	}
-	closedir(dirp);
-}
-
-/*!
- * \brief Finds a recording in the given directory.
- *
- * This function searchs for a file with the given file name, with a registered
- * format that matches its extension.
- *
- * \param dir_name Directory to search (absolute path).
- * \param file File name, without extension.
- * \return Absolute path of the recording file.
- * \return \c NULL if recording is not found.
- */
-static char *find_recording(const char *dir_name, const char *file)
-{
-	RAII_VAR(DIR *, dir, NULL, safe_closedir);
-	struct dirent entry;
-	struct dirent *result = NULL;
-	char *ext = NULL;
-	char *file_with_ext = NULL;
-
-	dir = opendir(dir_name);
-	if (!dir) {
-		return NULL;
-	}
-
-	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
-		ext = strrchr(result->d_name, '.');
-
-		if (!ext) {
-			/* No file extension; not us */
-			continue;
-		}
-		*ext++ = '\0';
-
-		if (strcmp(file, result->d_name) == 0) {
-			if (!ast_get_format_for_file_ext(ext)) {
-				ast_log(LOG_WARNING,
-					"Recording %s: unrecognized format %s\n",
-					result->d_name,
-					ext);
-				/* Keep looking */
-				continue;
-			}
-			/* We have a winner! */
-			break;
-		}
-	}
-
-	if (!result) {
-		return NULL;
-	}
-
-	ast_asprintf(&file_with_ext, "%s/%s.%s", dir_name, file, ext);
-	return file_with_ext;
-}
-
-/*!
- * \brief Allocate a recording object.
- */
-static struct stasis_app_stored_recording *recording_alloc(void)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-		ao2_cleanup);
-	int res;
-
-	recording = ao2_alloc(sizeof(*recording), stored_recording_dtor);
-	if (!recording) {
-		return NULL;
-	}
-
-	res = ast_string_field_init(recording, 255);
-	if (res != 0) {
-		return NULL;
-	}
-
-	ao2_ref(recording, +1);
-	return recording;
-}
-
-static int recording_sort(const void *obj_left, const void *obj_right, int flags)
-{
-	const struct stasis_app_stored_recording *object_left = obj_left;
-	const struct stasis_app_stored_recording *object_right = obj_right;
-	const char *right_key = obj_right;
-	int cmp;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_POINTER:
-		right_key = object_right->name;
-		/* Fall through */
-	case OBJ_KEY:
-		cmp = strcmp(object_left->name, right_key);
-		break;
-	case OBJ_PARTIAL_KEY:
-		/*
-		 * We could also use a partial key struct containing a length
-		 * so strlen() does not get called for every comparison instead.
-		 */
-		cmp = strncmp(object_left->name, right_key, strlen(right_key));
-		break;
-	default:
-		/* Sort can only work on something with a full or partial key. */
-		ast_assert(0);
-		cmp = 0;
-		break;
-	}
-	return cmp;
-}
-
-static int scan(struct ao2_container *recordings,
-	const char *base_dir, const char *subdir, struct dirent *entry);
-
-static int scan_file(struct ao2_container *recordings,
-	const char *base_dir, const char *subdir, const char *filename,
-	const char *path)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-		ao2_cleanup);
-	const char *ext;
-	char *dot;
-
-	ext = strrchr(filename, '.');
-
-	if (!ext) {
-		ast_verb(4, "  Ignore file without extension: %s\n",
-			filename);
-		/* No file extension; not us */
-		return 0;
-	}
-	++ext;
-
-	if (!ast_get_format_for_file_ext(ext)) {
-		ast_verb(4, "  Not a media file: %s\n", filename);
-		/* Not a media file */
-		return 0;
-	}
-
-	recording = recording_alloc();
-	if (!recording) {
-		return -1;
-	}
-
-	ast_string_field_set(recording, file_with_ext, path);
-
-	/* Build file and format from full path */
-	ast_string_field_set(recording, file, path);
-	dot = strrchr(recording->file, '.');
-	*dot = '\0';
-	recording->format = dot + 1;
-
-	/* Removed the recording dir from the file for the name. */
-	ast_string_field_set(recording, name,
-		recording->file + strlen(ast_config_AST_RECORDING_DIR) + 1);
-
-	/* Add it to the recordings container */
-	ao2_link(recordings, recording);
-
-	return 0;
-}
-
-static int scan_dir(struct ao2_container *recordings,
-	const char *base_dir, const char *subdir, const char *dirname,
-	const char *path)
-{
-	RAII_VAR(DIR *, dir, NULL, safe_closedir);
-	RAII_VAR(struct ast_str *, rel_dirname, NULL, ast_free);
-	struct dirent entry;
-	struct dirent *result = NULL;
-
-	if (strcmp(dirname, ".") == 0 ||
-		strcmp(dirname, "..") == 0) {
-		ast_verb(4, "  Ignoring self/parent dir\n");
-		return 0;
-	}
-
-	/* Build relative dirname */
-	rel_dirname = ast_str_create(80);
-	if (!rel_dirname) {
-		return -1;
-	}
-	if (!ast_strlen_zero(subdir)) {
-		ast_str_append(&rel_dirname, 0, "%s/", subdir);
-	}
-	if (!ast_strlen_zero(dirname)) {
-		ast_str_append(&rel_dirname, 0, "%s", dirname);
-	}
-
-	/* Read the directory */
-	dir = opendir(path);
-	if (!dir) {
-		ast_log(LOG_WARNING, "Error reading dir '%s'\n", path);
-		return -1;
-	}
-	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
-		scan(recordings, base_dir, ast_str_buffer(rel_dirname), result);
-	}
-
-	return 0;
-}
-
-static int scan(struct ao2_container *recordings,
-	const char *base_dir, const char *subdir, struct dirent *entry)
-{
-	RAII_VAR(struct ast_str *, path, NULL, ast_free);
-
-	path = ast_str_create(255);
-	if (!path) {
-		return -1;
-	}
-
-	/* Build file path */
-	ast_str_append(&path, 0, "%s", base_dir);
-	if (!ast_strlen_zero(subdir)) {
-		ast_str_append(&path, 0, "/%s", subdir);
-	}
-	if (entry) {
-		ast_str_append(&path, 0, "/%s", entry->d_name);
-	}
-	ast_verb(4, "Scanning '%s'\n", ast_str_buffer(path));
-
-	/* Handle this file */
-	switch (entry->d_type) {
-	case DT_REG:
-		scan_file(recordings, base_dir, subdir, entry->d_name,
-			ast_str_buffer(path));
-		break;
-	case DT_DIR:
-		scan_dir(recordings, base_dir, subdir, entry->d_name,
-			ast_str_buffer(path));
-		break;
-	default:
-		ast_log(LOG_WARNING, "Skipping %s: not a regular file\n",
-			ast_str_buffer(path));
-		break;
-	}
-
-	return 0;
-}
-
-struct ao2_container *stasis_app_stored_recording_find_all(void)
-{
-	RAII_VAR(struct ao2_container *, recordings, NULL, ao2_cleanup);
-	int res;
-
-	recordings = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
-		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, recording_sort, NULL);
-	if (!recordings) {
-		return NULL;
-	}
-
-	res = scan_dir(recordings, ast_config_AST_RECORDING_DIR, "", "",
-		ast_config_AST_RECORDING_DIR);
-	if (res != 0) {
-		return NULL;
-	}
-
-	ao2_ref(recordings, +1);
-	return recordings;
-}
-
-struct stasis_app_stored_recording *stasis_app_stored_recording_find_by_name(
-	const char *name)
-{
-	RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
-		ao2_cleanup);
-	RAII_VAR(char *, dir, NULL, ast_free);
-	RAII_VAR(char *, file, NULL, ast_free);
-	RAII_VAR(char *, file_with_ext, NULL, ast_free);
-	int res;
-	struct stat file_stat;
-
-	errno = 0;
-
-	if (!name) {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	recording = recording_alloc();
-	if (!recording) {
-		return NULL;
-	}
-
-	res = split_path(name, &dir, &file);
-	if (res != 0) {
-		return NULL;
-	}
-	ast_string_field_build(recording, file, "%s/%s", dir, file);
-
-	if (!ast_begins_with(dir, ast_config_AST_RECORDING_DIR)) {
-		/* Attempt to escape the recording directory */
-		ast_log(LOG_WARNING, "Attempt to access invalid recording %s\n",
-			name);
-		errno = EACCES;
-		return NULL;
-	}
-
-	/* The actual name of the recording is file with the config dir
-	 * prefix removed.
-	 */
-	ast_string_field_set(recording, name,
-		recording->file + strlen(ast_config_AST_RECORDING_DIR) + 1);
-
-	file_with_ext = find_recording(dir, file);
-	if (!file_with_ext) {
-		return NULL;
-	}
-	ast_string_field_set(recording, file_with_ext, file_with_ext);
-	recording->format = strrchr(recording->file_with_ext, '.');
-	if (!recording->format) {
-		return NULL;
-	}
-	++(recording->format);
-
-	res = stat(file_with_ext, &file_stat);
-	if (res != 0) {
-		return NULL;
-	}
-
-	if (!S_ISREG(file_stat.st_mode)) {
-		/* Let's not play if it's not a regular file */
-		errno = EACCES;
-		return NULL;
-	}
-
-	ao2_ref(recording, +1);
-	return recording;
-}
-
-int stasis_app_stored_recording_copy(struct stasis_app_stored_recording *src_recording, const char *dst,
-	struct stasis_app_stored_recording **dst_recording)
-{
-	RAII_VAR(char *, full_path, NULL, ast_free);
-	char *dst_file = ast_strdupa(dst);
-	char *format;
-	char *last_slash;
-	int res;
-
-	/* Drop the extension if specified, core will do this for us */
-	format = strrchr(dst_file, '.');
-	if (format) {
-		format = '\0';
-	}
-
-	/* See if any intermediary directories need to be made */
-	last_slash = strrchr(dst_file, '/');
-	if (last_slash) {
-		RAII_VAR(char *, tmp_path, NULL, ast_free);
-
-		*last_slash = '\0';
-		if (ast_asprintf(&tmp_path, "%s/%s", ast_config_AST_RECORDING_DIR, dst_file) < 0) {
-			return -1;
-		}
-		if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
-				tmp_path, 0777) != 0) {
-			/* errno set by ast_mkdir */
-			return -1;
-		}
-		*last_slash = '/';
-		if (ast_asprintf(&full_path, "%s/%s", ast_config_AST_RECORDING_DIR, dst_file) < 0) {
-			return -1;
-		}
-	} else {
-		/* There is no directory portion */
-		if (ast_asprintf(&full_path, "%s/%s", ast_config_AST_RECORDING_DIR, dst_file) < 0) {
-			return -1;
-		}
-	}
-
-	ast_verb(4, "Copying recording %s to %s (format %s)\n", src_recording->file,
-		full_path, src_recording->format);
-	res = ast_filecopy(src_recording->file, full_path, src_recording->format);
-	if (!res) {
-		*dst_recording = stasis_app_stored_recording_find_by_name(dst_file);
-	}
-
-	return res;
-}
-
-int stasis_app_stored_recording_delete(
-	struct stasis_app_stored_recording *recording)
-{
-	/* Path was validated when the recording object was created */
-	return unlink(recording->file_with_ext);
-}
-
-struct ast_json *stasis_app_stored_recording_to_json(
-	struct stasis_app_stored_recording *recording)
-{
-	if (!recording) {
-		return NULL;
-	}
-
-	return ast_json_pack("{ s: s, s: s }",
-		"name", recording->name,
-		"format", recording->format);
-}
diff --git a/rest-api-templates/README.txt b/rest-api-templates/README.txt
deleted file mode 100644
index e927ad7..0000000
--- a/rest-api-templates/README.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-This directory contains templates and template processing code for generating
-HTTP bindings for the RESTful API's.
-
-The RESTful API's are declared using [Swagger][swagger]. While Swagger provides
-a [code generating toolkit][swagger-codegen], it requires Java to run, which
-would be an unusual dependency to require for Asterisk developers.
-
-This code generator is similar, but written in Python. Templates are processed
-by using [pystache][pystache], which is a fairly simply Python implementation of
-[mustache][mustache].
-
- [swagger]: https://github.com/wordnik/swagger-core/wiki
- [swagger-codegen]: https://github.com/wordnik/swagger-codegen
- [pystache]: https://github.com/defunkt/pystache
- [mustache]: http://mustache.github.io/
diff --git a/rest-api-templates/api.wiki.mustache b/rest-api-templates/api.wiki.mustache
deleted file mode 100644
index de6de2d..0000000
--- a/rest-api-templates/api.wiki.mustache
+++ /dev/null
@@ -1,63 +0,0 @@
-{{#api_declaration}}
-h1. {{name_title}}
-
-|| Method || Path || Return Model || Summary ||
-{{#apis}}
-{{#operations}}
-| {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{summary}} |
-{{/operations}}
-{{/apis}}
-{{#apis}}
-{{#operations}}
-
-{anchor:{{nickname}}}
-h2. {{http_method}} {{wiki_path}}
-
-{{{wiki_summary}}}{{#wiki_notes}} {{{wiki_notes}}}{{/wiki_notes}}
-{{#has_path_parameters}}
-
-h3. Path parameters
-{{#path_parameters}}
-* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} - {{{wiki_description}}}
-{{/path_parameters}}
-{{/has_path_parameters}}
-{{#has_query_parameters}}
-
-h3. Query parameters
-{{#query_parameters}}
-* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} -{{#required}} *(required)*{{/required}} {{{wiki_description}}}
-{{#allow_multiple}}
-** Allows comma separated values.
-{{/allow_multiple}}
-{{/query_parameters}}
-{{/has_query_parameters}}
-{{#has_body_parameter}}
-
-h3. Body parameter
-{{#body_parameter}}
-* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} -{{#required}} *(required)*{{/required}} {{{wiki_description}}}
-{{#allow_multiple}}
-** Allows comma separated values.
-{{/allow_multiple}}
-{{/body_parameter}}
-{{/has_body_parameter}}
-{{#has_header_parameters}}
-
-h3. Header parameters
-{{#header_parameters}}
-* {{name}}: {{data_type}}{{#default_value}} = {{default_value}}{{/default_value}} -{{#required}} *(required)*{{/required}} {{{wiki_description}}}
-{{#allow_multiple}}
-** Allows comma separated values.
-{{/allow_multiple}}
-{{/header_parameters}}
-{{/has_header_parameters}}
-{{#has_error_responses}}
-
-h3. Error Responses
-{{#error_responses}}
-* {{code}} - {{{reason}}}
-{{/error_responses}}
-{{/has_error_responses}}
-{{/operations}}
-{{/apis}}
-{{/api_declaration}}
diff --git a/rest-api-templates/ari.make.mustache b/rest-api-templates/ari.make.mustache
deleted file mode 100644
index 50293cf..0000000
--- a/rest-api-templates/ari.make.mustache
+++ /dev/null
@@ -1,26 +0,0 @@
-{{! -*- Makefile -*- }}
-#
-# Asterisk -- A telephony toolkit for Linux.
-#
-# Generated Makefile for res_ari dependencies.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License
-#
-
-#
-# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-# !!!!!                               DO NOT EDIT                        !!!!!
-# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-# This file is generated by a template. Please see the original template at
-# rest-api-templates/ari.make.mustache
-#
-
-{{#apis}}
-res_ari_{{c_name}}.so: ari/resource_{{c_name}}.o
-
-ari/resource_{{c_name}}.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ari_{{c_name}})
-
-{{/apis}}
diff --git a/rest-api-templates/ari_model_validators.c.mustache b/rest-api-templates/ari_model_validators.c.mustache
deleted file mode 100644
index 9276478..0000000
--- a/rest-api-templates/ari_model_validators.c.mustache
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - Build validators for ARI model objects.
- */
-
- /*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_model_validators.h.mustache
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 401834 $")
-
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "ari_model_validators.h"
-{{#apis}}
-{{#api_declaration}}
-{{#models}}
-
-int ast_ari_validate_{{c_id}}(struct ast_json *json)
-{
-	int res = 1;
-	struct ast_json_iter *iter;
-{{#properties}}
-{{#required}}
-	int has_{{name}} = 0;
-{{/required}}
-{{/properties}}
-{{#has_subtypes}}
-	const char *discriminator;
-
-	discriminator = ast_json_string_get(ast_json_object_get(json, "{{discriminator.name}}"));
-	if (!discriminator) {
-		ast_log(LOG_ERROR, "ARI {{id}} missing required field {{discriminator.name}}");
-		return 0;
-	}
-
-	if (strcmp("{{id}}", discriminator) == 0) {
-		/* Self type; fall through */
-	} else
-{{#all_subtypes}}
-	if (strcmp("{{id}}", discriminator) == 0) {
-		return ast_ari_validate_{{c_id}}(json);
-	} else
-{{/all_subtypes}}
-	{
-		ast_log(LOG_ERROR, "ARI {{id}} has undocumented subtype %s\n",
-			discriminator);
-		res = 0;
-	}
-{{/has_subtypes}}
-
-	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
-{{#properties}}
-		if (strcmp("{{name}}", ast_json_object_iter_key(iter)) == 0) {
-			int prop_is_valid;
-{{#required}}
-			has_{{name}} = 1;
-{{/required}}
-{{#type}}
-{{#is_list}}
-			prop_is_valid = ast_ari_validate_list(
-				ast_json_object_iter_value(iter),
-				ast_ari_validate_{{c_singular_name}});
-{{/is_list}}
-{{^is_list}}
-			prop_is_valid = ast_ari_validate_{{c_name}}(
-				ast_json_object_iter_value(iter));
-{{/is_list}}
-{{/type}}
-			if (!prop_is_valid) {
-				ast_log(LOG_ERROR, "ARI {{id}} field {{name}} failed validation\n");
-				res = 0;
-			}
-		} else
-{{/properties}}
-		{
-			ast_log(LOG_ERROR,
-				"ARI {{id}} has undocumented field %s\n",
-				ast_json_object_iter_key(iter));
-			res = 0;
-		}
-	}
-
-{{#properties}}
-{{#required}}
-	if (!has_{{name}}) {
-		ast_log(LOG_ERROR, "ARI {{id}} missing required field {{name}}\n");
-		res = 0;
-	}
-
-{{/required}}
-{{/properties}}
-	return res;
-}
-
-ari_validator ast_ari_validate_{{c_id}}_fn(void)
-{
-	return ast_ari_validate_{{c_id}};
-}
-{{/models}}
-{{/api_declaration}}
-{{/apis}}
diff --git a/rest-api-templates/ari_model_validators.h.mustache b/rest-api-templates/ari_model_validators.h.mustache
deleted file mode 100644
index 5a1be4b..0000000
--- a/rest-api-templates/ari_model_validators.h.mustache
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - Build validators for ARI model objects.
- *
- * In addition to the normal validation functions one would normally expect,
- * each validator has a ast_ari_validate_{id}_fn() companion function that returns
- * the validator's function pointer.
- *
- * The reason for this seamingly useless indirection is the way function
- * pointers interfere with module loading. Asterisk attempts to dlopen() each
- * module using \c RTLD_LAZY in order to read some metadata from the module.
- * Unfortunately, if you take the address of a function, the function has to be
- * resolvable at load time, even if \c RTLD_LAZY is specified. By moving the
- * function-address-taking into this module, we can once again be lazy.
- */
-
- /*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_model_validators.h.mustache
- */
-
-#ifndef _ASTERISK_ARI_MODEL_H
-#define _ASTERISK_ARI_MODEL_H
-
-#include "asterisk/json.h"
-
-/*! @{ */
-
-/*!
- * \brief Validator for native Swagger void.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_void(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger object.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_object(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger byte.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_byte(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger boolean.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_boolean(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger int.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_int(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger long.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_long(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger float.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_float(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger double.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_double(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger string.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_string(struct ast_json *json);
-
-/*!
- * \brief Validator for native Swagger date.
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_date(struct ast_json *json);
-
-/*!
- * \brief Validator for a Swagger List[]/JSON array.
- *
- * \param json JSON object to validate.
- * \param fn Validator to call on every element in the array.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
-
-/*! @} */
-
-/*!
- * \brief Function type for validator functions. Allows for 
- */
-typedef int (*ari_validator)(struct ast_json *json);
-{{#apis}}
-{{#api_declaration}}
-{{#models}}
-
-/*!
- * \brief Validator for {{id}}.
- *
- * {{{description_dox}}}
- *
- * \param json JSON object to validate.
- * \returns True (non-zero) if valid.
- * \returns False (zero) if invalid.
- */
-int ast_ari_validate_{{c_id}}(struct ast_json *json);
-
-/*!
- * \brief Function pointer to ast_ari_validate_{{c_id}}().
- *
- * See \ref ast_ari_model_validators.h for more details.
- */
-ari_validator ast_ari_validate_{{c_id}}_fn(void);
-{{/models}}
-{{/api_declaration}}
-{{/apis}}
-
-/*
- * JSON models
- *
-{{#apis}}
-{{#api_declaration}}
-{{#models}}
- * {{id}}
-{{#properties}}
- * - {{name}}: {{type.name}}{{#required}} (required){{/required}}
-{{/properties}}
-{{/models}}
-{{/api_declaration}}
-{{/apis}} */
-
-#endif /* _ASTERISK_ARI_MODEL_H */
diff --git a/rest-api-templates/ari_resource.c.mustache b/rest-api-templates/ari_resource.c.mustache
deleted file mode 100644
index 85cf603..0000000
--- a/rest-api-templates/ari_resource.c.mustache
+++ /dev/null
@@ -1,53 +0,0 @@
-{{#api_declaration}}
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * {{{copyright}}}
- *
- * {{{author}}}
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief {{{resource_path}}} implementation- {{{description}}}
- *
- * \author {{{author}}}
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 402994 $")
-
-#include "resource_{{c_name}}.h"
-
-{{#apis}}
-{{#operations}}
-{{#is_req}}
-void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_variable *headers,
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args *args,
-	struct ast_ari_response *response)
-{
-	ast_log(LOG_ERROR, "TODO: ast_ari_{{c_name}}_{{c_nickname}}\n");
-}
-{{/is_req}}
-{{#is_websocket}}
-void ast_ari_websocket_{{c_name}}_{{c_nickname}}(struct ast_ari_websocket_session *session,
-	struct ast_variable *headers,
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args *args)
-{
-	ast_log(LOG_ERROR, "TODO: ast_ari_websocket_{{c_name}}_{{c_nickname}}\n");
-}
-{{/is_websocket}}
-{{/operations}}
-{{/apis}}
-{{/api_declaration}}
diff --git a/rest-api-templates/ari_resource.h.mustache b/rest-api-templates/ari_resource.h.mustache
deleted file mode 100644
index 3a20776..0000000
--- a/rest-api-templates/ari_resource.h.mustache
+++ /dev/null
@@ -1,109 +0,0 @@
-{{#api_declaration}}
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * {{{copyright}}}
- *
- * {{{author}}}
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generated file - declares stubs to be implemented in
- * res/ari/resource_{{name}}.c
- *
- * {{{description}}}
- *
- * \author {{{author}}}
- */
-
-/*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/ari_resource.h.mustache
- */
-
-#ifndef _ASTERISK_RESOURCE_{{name_caps}}_H
-#define _ASTERISK_RESOURCE_{{name_caps}}_H
-
-#include "asterisk/ari.h"
-
-{{#apis}}
-{{#operations}}
-/*! Argument struct for ast_ari_{{c_name}}_{{c_nickname}}() */
-struct ast_ari_{{c_name}}_{{c_nickname}}_args {
-{{#parameters}}
-{{#description}}
-{{/description}}
-{{^allow_multiple}}
-{{#description}}
-	/*! {{{description}}} */
-{{/description}}
-	{{c_data_type}}{{c_space}}{{c_name}};
-{{/allow_multiple}}
-{{#allow_multiple}}
-	/*! Array of {{{description}}} */
-	{{c_data_type}}{{c_space}}*{{c_name}};
-	/*! Length of {{c_name}} array. */
-	size_t {{c_name}}_count;
-	/*! Parsing context for {{c_name}}. */
-	char *{{c_name}}_parse;
-{{/allow_multiple}}
-{{/parameters}}
-};
-{{#is_req}}
-{{#parse_body}}
-/*!
- * \brief Body parsing function for {{path}}.
- * \param body The JSON body from which to parse parameters.
- * \param[out] args The args structure to parse into.
- * \retval zero on success
- * \retval non-zero on failure
- */
-int ast_ari_{{c_name}}_{{c_nickname}}_parse_body(
-	struct ast_json *body,
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args *args);
-
-{{/parse_body}}
-/*!
- * \brief {{summary}}
-{{#notes}}
- *
- * {{{notes}}}
-{{/notes}}
- *
- * \param headers HTTP headers
- * \param args Swagger parameters
- * \param[out] response HTTP response
- */
-void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args, struct ast_ari_response *response);
-{{/is_req}}
-{{#is_websocket}}
-/*!
- * \brief {{summary}}
-{{#notes}}
- *
- * {{{notes}}}
-{{/notes}}
- *
- * \param session ARI WebSocket.
- * \param headers HTTP headers.
- * \param args Swagger parameters.
- */
-void ast_ari_websocket_{{c_name}}_{{c_nickname}}(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args);
-{{/is_websocket}}
-{{/operations}}
-{{/apis}}
-
-#endif /* _ASTERISK_RESOURCE_{{name_caps}}_H */
-{{/api_declaration}}
diff --git a/rest-api-templates/asterisk_processor.py b/rest-api-templates/asterisk_processor.py
deleted file mode 100644
index ef0f167..0000000
--- a/rest-api-templates/asterisk_processor.py
+++ /dev/null
@@ -1,245 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# David M. Lee, II <dlee at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Implementation of SwaggerPostProcessor which adds fields needed to generate
-Asterisk RESTful HTTP binding code.
-"""
-
-import re
-
-from swagger_model import *
-
-try:
-    from collections import OrderedDict
-except ImportError:
-    from odict import OrderedDict
-
-
-def simple_name(name):
-    """Removes the {markers} from a path segement.
-
-    @param name: Swagger path segement, with {pathVar} markers.
-    """
-    if name.startswith('{') and name.endswith('}'):
-        return name[1:-1]
-    return name
-
-
-def wikify(str):
-    """Escapes a string for the wiki.
-
-    @param str: String to escape
-    """
-    return re.sub(r'([{}\[\]])', r'\\\1', str)
-
-
-def snakify(name):
-    """Helper to take a camelCase or dash-seperated name and make it
-    snake_case.
-    """
-    r = ''
-    prior_lower = False
-    for c in name:
-        if c.isupper() and prior_lower:
-            r += "_"
-        if c is '-':
-            c = '_'
-        prior_lower = c.islower()
-        r += c.lower()
-    return r
-
-
-class PathSegment(Stringify):
-    """Tree representation of a Swagger API declaration.
-    """
-    def __init__(self, name, parent):
-        """Ctor.
-
-        @param name: Name of this path segment. May have {pathVar} markers.
-        @param parent: Parent PathSegment.
-        """
-        #: Segment name, with {pathVar} markers removed
-        self.name = simple_name(name)
-        #: True if segment is a {pathVar}, else None.
-        self.is_wildcard = None
-        #: Underscore seperated name all ancestor segments
-        self.full_name = None
-        #: Dictionary of child PathSegements
-        self.__children = OrderedDict()
-        #: List of operations on this segement
-        self.operations = []
-
-        if self.name != name:
-            self.is_wildcard = True
-
-        if not self.name:
-            assert(not parent)
-            self.full_name = ''
-        if not parent or not parent.name:
-            self.full_name = name
-        else:
-            self.full_name = "%s_%s" % (parent.full_name, self.name)
-
-    def get_child(self, path):
-        """Walks decendents to get path, creating it if necessary.
-
-        @param path: List of path names.
-        @return: PageSegment corresponding to path.
-        """
-        assert simple_name(path[0]) == self.name
-        if (len(path) == 1):
-            return self
-        child = self.__children.get(path[1])
-        if not child:
-            child = PathSegment(path[1], self)
-            self.__children[path[1]] = child
-        return child.get_child(path[1:])
-
-    def children(self):
-        """Gets list of children.
-        """
-        return self.__children.values()
-
-    def num_children(self):
-        """Gets count of children.
-        """
-        return len(self.__children)
-
-
-class AsteriskProcessor(SwaggerPostProcessor):
-    """A SwaggerPostProcessor which adds fields needed to generate Asterisk
-    RESTful HTTP binding code.
-    """
-
-    #: How Swagger types map to C.
-    type_mapping = {
-        'string': 'const char *',
-        'boolean': 'int',
-        'number': 'int',
-        'int': 'int',
-        'long': 'long',
-        'double': 'double',
-        'float': 'float',
-    }
-
-    #: String conversion functions for string to C type.
-    convert_mapping = {
-        'string': '',
-        'int': 'atoi',
-        'long': 'atol',
-        'double': 'atof',
-        'boolean': 'ast_true',
-    }
-
-    #: JSON conversion functions
-    json_convert_mapping = {
-        'string': 'ast_json_string_get',
-        'int': 'ast_json_integer_get',
-        'long': 'ast_json_integer_get',
-        'double': 'ast_json_real_get',
-        'boolean': 'ast_json_is_true',
-    }
-
-    def __init__(self, wiki_prefix):
-        self.wiki_prefix = wiki_prefix
-
-    def process_resource_api(self, resource_api, context):
-        resource_api.wiki_prefix = self.wiki_prefix
-        # Derive a resource name from the API declaration's filename
-        resource_api.name = re.sub('\..*', '',
-                                   os.path.basename(resource_api.path))
-        # Now in all caps, for include guard
-        resource_api.name_caps = resource_api.name.upper()
-        resource_api.name_title = resource_api.name.capitalize()
-        resource_api.c_name = snakify(resource_api.name)
-        # Construct the PathSegement tree for the API.
-        if resource_api.api_declaration:
-            resource_api.root_path = PathSegment('', None)
-            for api in resource_api.api_declaration.apis:
-                segment = resource_api.root_path.get_child(api.path.split('/'))
-                for operation in api.operations:
-                    segment.operations.append(operation)
-                api.full_name = segment.full_name
-
-            # Since every API path should start with /[resource], root should
-            # have exactly one child.
-            if resource_api.root_path.num_children() != 1:
-                raise SwaggerError(
-                    "Should not mix resources in one API declaration", context)
-            # root_path isn't needed any more
-            resource_api.root_path = resource_api.root_path.children()[0]
-            if resource_api.name != resource_api.root_path.name:
-                raise SwaggerError(
-                    "API declaration name should match", context)
-            resource_api.root_full_name = resource_api.root_path.full_name
-
-    def process_api(self, api, context):
-        api.wiki_path = wikify(api.path)
-
-    def process_operation(self, operation, context):
-        # Nicknames are camelCase, Asterisk coding is snake case
-        operation.c_nickname = snakify(operation.nickname)
-        operation.c_http_method = 'AST_HTTP_' + operation.http_method
-        if not operation.summary.endswith("."):
-            raise SwaggerError("Summary should end with .", context)
-        operation.wiki_summary = wikify(operation.summary or "")
-        operation.wiki_notes = wikify(operation.notes or "")
-        operation.parse_body = (operation.body_parameter or operation.has_query_parameters) and True
-
-    def process_parameter(self, parameter, context):
-        if parameter.param_type == 'body':
-	    parameter.is_body_parameter = True;
-            parameter.c_data_type = 'struct ast_json *'
-        else:
-	    parameter.is_body_parameter = False;
-            if not parameter.data_type in self.type_mapping:
-                raise SwaggerError(
-                    "Invalid parameter type %s" % parameter.data_type, context)
-            # Type conversions
-            parameter.c_data_type = self.type_mapping[parameter.data_type]
-            parameter.c_convert = self.convert_mapping[parameter.data_type]
-            parameter.json_convert = self.json_convert_mapping[parameter.data_type]
-
-        # Parameter names are camelcase, Asterisk convention is snake case
-        parameter.c_name = snakify(parameter.name)
-        # You shouldn't put a space between 'char *' and the variable
-        if parameter.c_data_type.endswith('*'):
-            parameter.c_space = ''
-        else:
-            parameter.c_space = ' '
-        parameter.wiki_description = wikify(parameter.description)
-
-    def process_model(self, model, context):
-        model.description_dox = model.description.replace('\n', '\n * ')
-        model.description_dox = re.sub(' *\n', '\n', model.description_dox)
-        model.wiki_description = wikify(model.description)
-        model.c_id = snakify(model.id)
-        return model
-
-    def process_property(self, prop, context):
-        if "-" in prop.name:
-            raise SwaggerError("Property names cannot have dashes", context)
-        if prop.name != prop.name.lower():
-            raise SwaggerError("Property name should be all lowercase",
-                               context)
-        prop.wiki_description = wikify(prop.description)
-
-    def process_type(self, swagger_type, context):
-        swagger_type.c_name = snakify(swagger_type.name)
-        swagger_type.c_singular_name = snakify(swagger_type.singular_name)
-        swagger_type.wiki_name = wikify(swagger_type.name)
diff --git a/rest-api-templates/body_parsing.mustache b/rest-api-templates/body_parsing.mustache
deleted file mode 100644
index 63cce0d..0000000
--- a/rest-api-templates/body_parsing.mustache
+++ /dev/null
@@ -1,71 +0,0 @@
-{{!
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * William Kinsey Moore, III <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
-}}
-{{!
- * Snippet for decoding parameters into an _args struct.
-}}
-{{#parse_body}}
-int ast_ari_{{c_name}}_{{c_nickname}}_parse_body(
-	struct ast_json *body,
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args *args)
-{
-{{#has_query_parameters}}
-	struct ast_json *field;
-{{/has_query_parameters}}
-	/* Parse query parameters out of it */
-{{#query_parameters}}
-{{^is_body_parameter}}
-	field = ast_json_object_get(body, "{{name}}");
-	if (field) {
-{{^allow_multiple}}
-		args->{{c_name}} = {{json_convert}}(field);
-{{/allow_multiple}}
-{{#allow_multiple}}
-		/* If they were silly enough to both pass in a query param and a
-		 * JSON body, free up the query value.
-		 */
-		ast_free(args->{{c_name}});
-		if (ast_json_typeof(field) == AST_JSON_ARRAY) {
-			/* Multiple param passed as array */
-			size_t i;
-			args->{{c_name}}_count = ast_json_array_size(field);
-			args->{{c_name}} = ast_malloc(sizeof(*args->{{c_name}}) * args->{{c_name}}_count);
-
-			if (!args->{{c_name}}) {
-				return -1;
-			}
-
-			for (i = 0; i < args->{{c_name}}_count; ++i) {
-				args->{{c_name}}[i] = {{json_convert}}(ast_json_array_get(field, i));
-			}
-		} else {
-			/* Multiple param passed as single value */
-			args->{{c_name}}_count = 1;
-			args->{{c_name}} = ast_malloc(sizeof(*args->{{c_name}}) * args->{{c_name}}_count);
-			if (!args->{{c_name}}) {
-				return -1;
-			}
-			args->{{c_name}}[0] = {{json_convert}}(field);
-		}
-{{/allow_multiple}}
-	}
-{{/is_body_parameter}}
-{{/query_parameters}}
-	return 0;
-}
-
-{{/parse_body}}
diff --git a/rest-api-templates/do-not-edit.mustache b/rest-api-templates/do-not-edit.mustache
deleted file mode 100644
index 05ba142..0000000
--- a/rest-api-templates/do-not-edit.mustache
+++ /dev/null
@@ -1,4 +0,0 @@
-{{! A partial for the big warning, so it's not in the template itself }}
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!!                               DO NOT EDIT                        !!!!!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/rest-api-templates/make_ari_stubs.py b/rest-api-templates/make_ari_stubs.py
deleted file mode 100755
index 4e02cdd..0000000
--- a/rest-api-templates/make_ari_stubs.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# David M. Lee, II <dlee at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-import sys
-
-try:
-    import pystache
-except ImportError:
-    print >> sys.stderr, "Pystache required. Please sudo pip install pystache."
-    sys.exit(1)
-
-import os.path
-
-from asterisk_processor import AsteriskProcessor
-from optparse import OptionParser
-from swagger_model import *
-from transform import Transform
-
-TOPDIR = os.path.dirname(os.path.abspath(__file__))
-
-
-def rel(file):
-    """Helper to get a file relative to the script's directory
-
-    @parm file: Relative file path.
-    """
-    return os.path.join(TOPDIR, file)
-
-WIKI_PREFIX = 'Asterisk 13'
-
-API_TRANSFORMS = [
-    Transform(rel('api.wiki.mustache'),
-              'doc/rest-api/%s {{name_title}} REST API.wiki' % WIKI_PREFIX),
-    Transform(rel('res_ari_resource.c.mustache'),
-              'res/res_ari_{{c_name}}.c'),
-    Transform(rel('ari_resource.h.mustache'),
-              'res/ari/resource_{{c_name}}.h'),
-    Transform(rel('ari_resource.c.mustache'),
-              'res/ari/resource_{{c_name}}.c', overwrite=False),
-]
-
-RESOURCES_TRANSFORMS = [
-    Transform(rel('models.wiki.mustache'),
-              'doc/rest-api/%s REST Data Models.wiki' % WIKI_PREFIX),
-    Transform(rel('ari.make.mustache'), 'res/ari.make'),
-    Transform(rel('ari_model_validators.h.mustache'),
-              'res/ari/ari_model_validators.h'),
-    Transform(rel('ari_model_validators.c.mustache'),
-              'res/ari/ari_model_validators.c'),
-]
-
-
-def main(argv):
-    parser = OptionParser(usage="Usage %prog [resources.json] [destdir]")
-
-    (options, args) = parser.parse_args(argv)
-
-    if len(args) != 3:
-        parser.error("Wrong number of arguments")
-
-    source = args[1]
-    dest_dir = args[2]
-    renderer = pystache.Renderer(search_dirs=[TOPDIR], missing_tags='strict')
-    processor = AsteriskProcessor(wiki_prefix=WIKI_PREFIX)
-
-    # Build the models
-    base_dir = os.path.dirname(source)
-    resources = ResourceListing().load_file(source, processor)
-    for api in resources.apis:
-        api.load_api_declaration(base_dir, processor)
-
-    # Render the templates
-    for api in resources.apis:
-        for transform in API_TRANSFORMS:
-            transform.render(renderer, api, dest_dir)
-    for transform in RESOURCES_TRANSFORMS:
-        transform.render(renderer, resources, dest_dir)
-
-if __name__ == "__main__":
-    sys.exit(main(sys.argv) or 0)
diff --git a/rest-api-templates/models.wiki.mustache b/rest-api-templates/models.wiki.mustache
deleted file mode 100644
index 2bc1e46..0000000
--- a/rest-api-templates/models.wiki.mustache
+++ /dev/null
@@ -1,22 +0,0 @@
-{toc}
-
-{{#apis}}
-{{#api_declaration}}
-{{#models}}
-h1. {{id}}
-{{#extends}}Base type: [{{extends}}|#{{extends}}]{{/extends}}
-{{#has_subtypes}}Subtypes:{{#all_subtypes}} [{{id}}|#{{id}}]{{/all_subtypes}}{{/has_subtypes}}
-{{#wiki_description}}
-
-{{{wiki_description}}}
-{{/wiki_description}}
-{code:language=javascript|collapse=true}
-{{{model_json}}}
-{code}
-{{#properties}}
-* {{name}}: {{#type}}{{#is_primitive}}{{wiki_name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|#{{singular_name}}]{{/is_primitive}}{{/type}}{{^required}} _(optional)_{{/required}}{{#wiki_description}} - {{{wiki_description}}}{{/wiki_description}}
-{{/properties}}
-
-{{/models}}
-{{/api_declaration}}
-{{/apis}}
diff --git a/rest-api-templates/odict.py b/rest-api-templates/odict.py
deleted file mode 100644
index 8f536a2..0000000
--- a/rest-api-templates/odict.py
+++ /dev/null
@@ -1,261 +0,0 @@
-# Downloaded from http://code.activestate.com/recipes/576693/
-# Licensed under the MIT License
-
-# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
-# Passes Python2.7's test suite and incorporates all the latest updates.
-
-try:
-    from thread import get_ident as _get_ident
-except ImportError:
-    from dummy_thread import get_ident as _get_ident
-
-try:
-    from _abcoll import KeysView, ValuesView, ItemsView
-except ImportError:
-    pass
-
-
-class OrderedDict(dict):
-    'Dictionary that remembers insertion order'
-    # An inherited dict maps keys to values.
-    # The inherited dict provides __getitem__, __len__, __contains__, and get.
-    # The remaining methods are order-aware.
-    # Big-O running times for all methods are the same as for regular dictionaries.
-
-    # The internal self.__map dictionary maps keys to links in a doubly linked list.
-    # The circular doubly linked list starts and ends with a sentinel element.
-    # The sentinel element never gets deleted (this simplifies the algorithm).
-    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
-
-    def __init__(self, *args, **kwds):
-        '''Initialize an ordered dictionary.  Signature is the same as for
-        regular dictionaries, but keyword arguments are not recommended
-        because their insertion order is arbitrary.
-
-        '''
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__root
-        except AttributeError:
-            self.__root = root = []                     # sentinel node
-            root[:] = [root, root, None]
-            self.__map = {}
-        self.__update(*args, **kwds)
-
-    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
-        'od.__setitem__(i, y) <==> od[i]=y'
-        # Setting a new item creates a new link which goes at the end of the linked
-        # list, and the inherited dictionary is updated with the new key/value pair.
-        if key not in self:
-            root = self.__root
-            last = root[0]
-            last[1] = root[0] = self.__map[key] = [last, root, key]
-        dict_setitem(self, key, value)
-
-    def __delitem__(self, key, dict_delitem=dict.__delitem__):
-        'od.__delitem__(y) <==> del od[y]'
-        # Deleting an existing item uses self.__map to find the link which is
-        # then removed by updating the links in the predecessor and successor nodes.
-        dict_delitem(self, key)
-        link_prev, link_next, key = self.__map.pop(key)
-        link_prev[1] = link_next
-        link_next[0] = link_prev
-
-    def __iter__(self):
-        'od.__iter__() <==> iter(od)'
-        root = self.__root
-        curr = root[1]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[1]
-
-    def __reversed__(self):
-        'od.__reversed__() <==> reversed(od)'
-        root = self.__root
-        curr = root[0]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[0]
-
-    def clear(self):
-        'od.clear() -> None.  Remove all items from od.'
-        try:
-            for node in self.__map.itervalues():
-                del node[:]
-            root = self.__root
-            root[:] = [root, root, None]
-            self.__map.clear()
-        except AttributeError:
-            pass
-        dict.clear(self)
-
-    def popitem(self, last=True):
-        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
-        Pairs are returned in LIFO order if last is true or FIFO order if false.
-
-        '''
-        if not self:
-            raise KeyError('dictionary is empty')
-        root = self.__root
-        if last:
-            link = root[0]
-            link_prev = link[0]
-            link_prev[1] = root
-            root[0] = link_prev
-        else:
-            link = root[1]
-            link_next = link[1]
-            root[1] = link_next
-            link_next[0] = root
-        key = link[2]
-        del self.__map[key]
-        value = dict.pop(self, key)
-        return key, value
-
-    # -- the following methods do not depend on the internal structure --
-
-    def keys(self):
-        'od.keys() -> list of keys in od'
-        return list(self)
-
-    def values(self):
-        'od.values() -> list of values in od'
-        return [self[key] for key in self]
-
-    def items(self):
-        'od.items() -> list of (key, value) pairs in od'
-        return [(key, self[key]) for key in self]
-
-    def iterkeys(self):
-        'od.iterkeys() -> an iterator over the keys in od'
-        return iter(self)
-
-    def itervalues(self):
-        'od.itervalues -> an iterator over the values in od'
-        for k in self:
-            yield self[k]
-
-    def iteritems(self):
-        'od.iteritems -> an iterator over the (key, value) items in od'
-        for k in self:
-            yield (k, self[k])
-
-    def update(*args, **kwds):
-        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
-
-        If E is a dict instance, does:           for k in E: od[k] = E[k]
-        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
-        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
-        In either case, this is followed by:     for k, v in F.items(): od[k] = v
-
-        '''
-        if len(args) > 2:
-            raise TypeError('update() takes at most 2 positional '
-                            'arguments (%d given)' % (len(args),))
-        elif not args:
-            raise TypeError('update() takes at least 1 argument (0 given)')
-        self = args[0]
-        # Make progressively weaker assumptions about "other"
-        other = ()
-        if len(args) == 2:
-            other = args[1]
-        if isinstance(other, dict):
-            for key in other:
-                self[key] = other[key]
-        elif hasattr(other, 'keys'):
-            for key in other.keys():
-                self[key] = other[key]
-        else:
-            for key, value in other:
-                self[key] = value
-        for key, value in kwds.items():
-            self[key] = value
-
-    __update = update  # let subclasses override update without breaking __init__
-
-    __marker = object()
-
-    def pop(self, key, default=__marker):
-        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-        If key is not found, d is returned if given, otherwise KeyError is raised.
-
-        '''
-        if key in self:
-            result = self[key]
-            del self[key]
-            return result
-        if default is self.__marker:
-            raise KeyError(key)
-        return default
-
-    def setdefault(self, key, default=None):
-        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
-        if key in self:
-            return self[key]
-        self[key] = default
-        return default
-
-    def __repr__(self, _repr_running={}):
-        'od.__repr__() <==> repr(od)'
-        call_key = id(self), _get_ident()
-        if call_key in _repr_running:
-            return '...'
-        _repr_running[call_key] = 1
-        try:
-            if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
-        finally:
-            del _repr_running[call_key]
-
-    def __reduce__(self):
-        'Return state information for pickling'
-        items = [[k, self[k]] for k in self]
-        inst_dict = vars(self).copy()
-        for k in vars(OrderedDict()):
-            inst_dict.pop(k, None)
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def copy(self):
-        'od.copy() -> a shallow copy of od'
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
-        and values equal to v (which defaults to None).
-
-        '''
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
-        while comparison to a regular mapping is order-insensitive.
-
-        '''
-        if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
-
-    # -- the following methods are only used in Python 2.7 --
-
-    def viewkeys(self):
-        "od.viewkeys() -> a set-like object providing a view on od's keys"
-        return KeysView(self)
-
-    def viewvalues(self):
-        "od.viewvalues() -> an object providing a view on od's values"
-        return ValuesView(self)
-
-    def viewitems(self):
-        "od.viewitems() -> a set-like object providing a view on od's items"
-        return ItemsView(self)
diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache
deleted file mode 100644
index 2dde4b3..0000000
--- a/rest-api-templates/param_parsing.mustache
+++ /dev/null
@@ -1,113 +0,0 @@
-{{!
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
-}}
-{{!
- * Snippet for decoding parameters into an _args struct.
-}}
-{{#has_query_parameters}}
-	for (i = get_params; i; i = i->next) {
-{{#query_parameters}}
-		if (strcmp(i->name, "{{name}}") == 0) {
-{{^allow_multiple}}
-			args.{{c_name}} = {{c_convert}}(i->value);
-{{/allow_multiple}}
-{{#allow_multiple}}
-			/* Parse comma separated list */
-			char *vals[MAX_VALS];
-			size_t j;
-
-			args.{{c_name}}_parse = ast_strdup(i->value);
-			if (!args.{{c_name}}_parse) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (strlen(args.{{c_name}}_parse) == 0) {
-				/* ast_app_separate_args can't handle "" */
-				args.{{c_name}}_count = 1;
-				vals[0] = args.{{c_name}}_parse;
-			} else {
-				args.{{c_name}}_count = ast_app_separate_args(
-					args.{{c_name}}_parse, ',', vals,
-					ARRAY_LEN(vals));
-			}
-
-			if (args.{{c_name}}_count == 0) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			if (args.{{c_name}}_count >= MAX_VALS) {
-				ast_ari_response_error(response, 400,
-					"Bad Request",
-					"Too many values for {{c_name}}");
-				goto fin;
-			}
-
-			args.{{c_name}} = ast_malloc(sizeof(*args.{{c_name}}) * args.{{c_name}}_count);
-			if (!args.{{c_name}}) {
-				ast_ari_response_alloc_failed(response);
-				goto fin;
-			}
-
-			for (j = 0; j < args.{{c_name}}_count; ++j) {
-				args.{{c_name}}[j] = {{c_convert}}(vals[j]);
-			}
-{{/allow_multiple}}
-		} else
-{{/query_parameters}}
-		{}
-	}
-{{/has_query_parameters}}
-{{#has_path_parameters}}
-	for (i = path_vars; i; i = i->next) {
-{{#path_parameters}}
-		if (strcmp(i->name, "{{name}}") == 0) {
-			args.{{c_name}} = {{c_convert}}(i->value);
-		} else
-{{/path_parameters}}
-		{}
-	}
-{{/has_path_parameters}}
-{{^is_websocket}}
-{{#parse_body}}
-	/* Look for a JSON request entity */
-	body = ast_http_get_json(ser, headers);
-	if (!body) {
-		switch (errno) {
-		case EFBIG:
-			ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
-			goto fin;
-		case ENOMEM:
-			ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
-			goto fin;
-		case EIO:
-			ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
-			goto fin;
-		}
-	}
-{{#body_parameter}}
-	args.{{c_name}} = ast_json_ref(body);
-{{/body_parameter}}
-{{^body_parameter}}
-	if (ast_ari_{{c_name}}_{{c_nickname}}_parse_body(body, &args)) {
-		ast_ari_response_alloc_failed(response);
-		goto fin;
-	}
-{{/body_parameter}}
-{{/parse_body}}
-{{/is_websocket}}
diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache
deleted file mode 100644
index abc1a59..0000000
--- a/rest-api-templates/res_ari_resource.c.mustache
+++ /dev/null
@@ -1,250 +0,0 @@
-{{#api_declaration}}
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * {{{copyright}}}
- *
- * {{{author}}}
-{{! Template Copyright
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
-}}
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-{{! Template for rendering the res_ module for an HTTP resource. }}
-/*
-{{> do-not-edit}}
- * This file is generated by a mustache template. Please see the original
- * template in rest-api-templates/res_ari_resource.c.mustache
- */
-
-/*! \file
- *
- * \brief {{{description}}}
- *
- * \author {{{author}}}
- */
-
-/*** MODULEINFO
-	<depend type="module">res_ari</depend>
-	<depend type="module">res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420536 $")
-
-#include "asterisk/app.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_app.h"
-#include "ari/resource_{{c_name}}.h"
-#if defined(AST_DEVMODE)
-#include "ari/ari_model_validators.h"
-#endif
-{{^has_websocket}}
-{{! Only include http_websocket if necessary. Otherwise we'll do a lot of
- *  unnecessary optional_api intialization, which makes optional_api harder
- *  to debug
- }}
-#include "asterisk/http_websocket.h"
-{{/has_websocket}}
-
-#define MAX_VALS 128
-
-{{#apis}}
-{{#operations}}
-{{#is_req}}
-{{> body_parsing}}
-/*!
- * \brief Parameter parsing callback for {{path}}.
- * \param get_params GET parameters in the HTTP request.
- * \param path_vars Path variables extracted from the request.
- * \param headers HTTP headers.
- * \param[out] response Response to the HTTP request.
- */
-static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
-	struct ast_tcptls_session_instance *ser,
-	struct ast_variable *get_params, struct ast_variable *path_vars,
-	struct ast_variable *headers, struct ast_ari_response *response)
-{
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
-{{#has_parameters}}
-	struct ast_variable *i;
-{{/has_parameters}}
-	RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
-#if defined(AST_DEVMODE)
-	int is_valid;
-	int code;
-#endif /* AST_DEVMODE */
-
-{{> param_parsing}}
-	ast_ari_{{c_name}}_{{c_nickname}}(headers, &args, response);
-#if defined(AST_DEVMODE)
-	code = response->response_code;
-
-	switch (code) {
-	case 0: /* Implementation is still a stub, or the code wasn't set */
-		is_valid = response->message == NULL;
-		break;
-	case 500: /* Internal Server Error */
-	case 501: /* Not Implemented */
-{{#error_responses}}
-	case {{code}}: /* {{{reason}}} */
-{{/error_responses}}
-		is_valid = 1;
-		break;
-	default:
-		if (200 <= code && code <= 299) {
-{{#response_class}}
-{{#is_list}}
-			is_valid = ast_ari_validate_list(response->message,
-				ast_ari_validate_{{c_singular_name}}_fn());
-{{/is_list}}
-{{^is_list}}
-			is_valid = ast_ari_validate_{{c_name}}(
-				response->message);
-{{/is_list}}
-{{/response_class}}
-		} else {
-			ast_log(LOG_ERROR, "Invalid error response %d for {{path}}\n", code);
-			is_valid = 0;
-		}
-	}
-
-	if (!is_valid) {
-		ast_log(LOG_ERROR, "Response validation failed for {{path}}\n");
-		ast_ari_response_error(response, 500,
-			"Internal Server Error", "Response validation failed");
-	}
-#endif /* AST_DEVMODE */
-
-fin: __attribute__((unused))
-{{> param_cleanup}}
-	return;
-}
-{{/is_req}}
-{{#is_websocket}}
-static void ast_ari_{{c_name}}_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
-	struct ast_variable *get_params, struct ast_variable *headers)
-{
-	struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
-{{#has_parameters}}
-	RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
-	struct ast_variable *i;
-{{/has_parameters}}
-	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
-	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
-{{#has_path_parameters}}
-	/* TODO: It's not immediately obvious how to pass path params through
-	 * the websocket code to this callback. Not needed right now, so we'll
-	 * just punt. */
-	struct ast_variable *path_vars = NULL;
-{{/has_path_parameters}}
-
-{{#has_parameters}}
-	response = ast_calloc(1, sizeof(*response));
-	if (!response) {
-		ast_log(LOG_ERROR, "Failed to create response.\n");
-		goto fin;
-	}
-{{/has_parameters}}
-
-#if defined(AST_DEVMODE)
-	session = ast_ari_websocket_session_create(ws_session,
-		ast_ari_validate_{{response_class.c_name}}_fn());
-#else
-	session = ast_ari_websocket_session_create(ws_session, NULL);
-#endif
-	if (!session) {
-		ast_log(LOG_ERROR, "Failed to create ARI session\n");
-		goto fin;
-	}
-
-{{> param_parsing}}
-
-	ast_ari_websocket_{{c_name}}_{{c_nickname}}(session, headers, &args);
-
-fin: __attribute__((unused))
-	if (response && response->response_code != 0) {
-		/* Param parsing failure */
-		/* TODO - ideally, this would return the error code to the
-		 * HTTP client; but we've already done the WebSocket
-		 * negotiation. Param parsing should happen earlier, but we
-		 * need a way to pass it through the WebSocket code to the
-		 * callback */
-		RAII_VAR(char *, msg, NULL, ast_json_free);
-		if (response->message) {
-			msg = ast_json_dump_string(response->message);
-		} else {
-			ast_log(LOG_ERROR, "Missing response message\n");
-		}
-		if (msg) {
-			ast_websocket_write(ws_session,
-				AST_WEBSOCKET_OPCODE_TEXT, msg,	strlen(msg));
-		}
-	}
-{{> param_cleanup}}
-}
-{{/is_websocket}}
-{{/operations}}
-{{/apis}}
-
-{{! The rest_handler partial expands to the tree of stasis_rest_handlers }}
-{{#root_path}}
-{{> rest_handler}}
-{{/root_path}}
-
-static int load_module(void)
-{
-	int res = 0;
-{{#apis}}
-{{#has_websocket}}
-	{{full_name}}.ws_server = ast_websocket_server_create();
-	if (!{{full_name}}.ws_server) {
-		return AST_MODULE_LOAD_FAILURE;
-	}
-{{/has_websocket}}
-{{#operations}}
-{{#is_websocket}}
-	res |= ast_websocket_server_add_protocol({{full_name}}.ws_server,
-		"{{websocket_protocol}}", ast_ari_{{c_name}}_{{c_nickname}}_ws_cb);
-{{/is_websocket}}
-{{/operations}}
-{{/apis}}
-	stasis_app_ref();
-	res |= ast_ari_add_handler(&{{root_full_name}});
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_ari_remove_handler(&{{root_full_name}});
-{{#apis}}
-{{#has_websocket}}
-	ao2_cleanup({{full_name}}.ws_server);
-	{{full_name}}.ws_server = NULL;
-{{/has_websocket}}
-{{/apis}}
-	stasis_app_unref();
-	return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}",
-	.support_level = AST_MODULE_SUPPORT_CORE,
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari,res_stasis",
-	);
-{{/api_declaration}}
diff --git a/rest-api-templates/rest_handler.mustache b/rest-api-templates/rest_handler.mustache
deleted file mode 100644
index baa1aa6..0000000
--- a/rest-api-templates/rest_handler.mustache
+++ /dev/null
@@ -1,40 +0,0 @@
-{{!
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
-}}
-{{!
- * Recursive partial template to render a rest_handler. Used in
- * res_ari_resource.c.mustache.
-}}
-{{#children}}
-{{> rest_handler}}
-{{/children}}
-/*! \brief REST handler for {{path}} */
-static struct stasis_rest_handlers {{full_name}} = {
-	.path_segment = "{{name}}",
-{{#is_wildcard}}
-	.is_wildcard = 1,
-{{/is_wildcard}}
-	.callbacks = {
-{{#operations}}
-{{#is_req}}
-		[{{c_http_method}}] = ast_ari_{{c_name}}_{{c_nickname}}_cb,
-{{/is_req}}
-{{/operations}}
-	},
-	.num_children = {{num_children}},
-	.children = { {{#children}}&{{full_name}},{{/children}} }
-};
diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py
deleted file mode 100644
index 9c65219..0000000
--- a/rest-api-templates/swagger_model.py
+++ /dev/null
@@ -1,756 +0,0 @@
-
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# David M. Lee, II <dlee at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-"""Swagger data model objects.
-
-These objects should map directly to the Swagger api-docs, without a lot of
-additional fields. In the process of translation, it should also validate the
-model for consistency against the Swagger spec (i.e., fail if fields are
-missing, or have incorrect values).
-
-See https://github.com/wordnik/swagger-core/wiki/API-Declaration for the spec.
-"""
-
-import json
-import os.path
-import pprint
-import re
-import sys
-import traceback
-
-# We don't fully support Swagger 1.2, but we need it for subtyping
-SWAGGER_VERSIONS = ["1.1", "1.2"]
-
-SWAGGER_PRIMITIVES = [
-    'void',
-    'string',
-    'boolean',
-    'number',
-    'int',
-    'long',
-    'double',
-    'float',
-    'Date',
-]
-
-
-class Stringify(object):
-    """Simple mix-in to make the repr of the model classes more meaningful.
-    """
-    def __repr__(self):
-        return "%s(%s)" % (self.__class__, pprint.saferepr(self.__dict__))
-
-
-def compare_versions(lhs, rhs):
-    '''Performs a lexicographical comparison between two version numbers.
-
-    This properly handles simple major.minor.whatever.sure.why.not version
-    numbers, but fails miserably if there's any letters in there.
-
-    For reference:
-      1.0 == 1.0
-      1.0 < 1.0.1
-      1.2 < 1.10
-
-    @param lhs Left hand side of the comparison
-    @param rhs Right hand side of the comparison
-    @return  < 0 if lhs  < rhs
-    @return == 0 if lhs == rhs
-    @return  > 0 if lhs  > rhs
-    '''
-    lhs = [int(v) for v in lhs.split('.')]
-    rhs = [int(v) for v in rhs.split('.')]
-    return cmp(lhs, rhs)
-
-
-class ParsingContext(object):
-    """Context information for parsing.
-
-    This object is immutable. To change contexts (like adding an item to the
-    stack), use the next() and next_stack() functions to build a new one.
-    """
-
-    def __init__(self, swagger_version, stack):
-        self.__swagger_version = swagger_version
-        self.__stack = stack
-
-    def __repr__(self):
-        return "ParsingContext(swagger_version=%s, stack=%s)" % (
-            self.swagger_version, self.stack)
-
-    def get_swagger_version(self):
-        return self.__swagger_version
-
-    def get_stack(self):
-        return self.__stack
-
-    swagger_version = property(get_swagger_version)
-
-    stack = property(get_stack)
-
-    def version_less_than(self, ver):
-        return compare_versions(self.swagger_version, ver) < 0
-
-    def next_stack(self, json, id_field):
-        """Returns a new item pushed to the stack.
-
-        @param json: Current JSON object.
-        @param id_field: Field identifying this object.
-        @return New context with additional item in the stack.
-        """
-        if not id_field in json:
-            raise SwaggerError("Missing id_field: %s" % id_field, self)
-        new_stack = self.stack + ['%s=%s' % (id_field, str(json[id_field]))]
-        return ParsingContext(self.swagger_version, new_stack)
-
-    def next(self, version=None, stack=None):
-        if version is None:
-            version = self.version
-        if stack is None:
-            stack = self.stack
-        return ParsingContext(version, stack)
-
-
-class SwaggerError(Exception):
-    """Raised when an error is encountered mapping the JSON objects into the
-    model.
-    """
-
-    def __init__(self, msg, context, cause=None):
-        """Ctor.
-
-        @param msg: String message for the error.
-        @param context: ParsingContext object
-        @param cause: Optional exception that caused this one.
-        """
-        super(Exception, self).__init__(msg, context, cause)
-
-
-class SwaggerPostProcessor(object):
-    """Post processing interface for model objects. This processor can add
-    fields to model objects for additional information to use in the
-    templates.
-    """
-    def process_resource_api(self, resource_api, context):
-        """Post process a ResourceApi object.
-
-        @param resource_api: ResourceApi object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_api(self, api, context):
-        """Post process an Api object.
-
-        @param api: Api object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_operation(self, operation, context):
-        """Post process a Operation object.
-
-        @param operation: Operation object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_parameter(self, parameter, context):
-        """Post process a Parameter object.
-
-        @param parameter: Parameter object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_model(self, model, context):
-        """Post process a Model object.
-
-        @param model: Model object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_property(self, property, context):
-        """Post process a Property object.
-
-        @param property: Property object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_type(self, swagger_type, context):
-        """Post process a SwaggerType object.
-
-        @param swagger_type: ResourceListing object.
-        @param context: Current context in the API.
-        """
-        pass
-
-    def process_resource_listing(self, resource_listing, context):
-        """Post process the overall ResourceListing object.
-
-        @param resource_listing: ResourceListing object.
-        @param context: Current context in the API.
-        """
-        pass
-
-
-class AllowableRange(Stringify):
-    """Model of a allowableValues of type RANGE
-
-    See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
-    """
-    def __init__(self, min_value, max_value):
-        self.min_value = min_value
-        self.max_value = max_value
-
-
-class AllowableList(Stringify):
-    """Model of a allowableValues of type LIST
-
-    See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
-    """
-    def __init__(self, values):
-        self.values = values
-
-
-def load_allowable_values(json, context):
-    """Parse a JSON allowableValues object.
-
-    This returns None, AllowableList or AllowableRange, depending on the
-    valueType in the JSON. If the valueType is not recognized, a SwaggerError
-    is raised.
-    """
-    if not json:
-        return None
-
-    if not 'valueType' in json:
-        raise SwaggerError("Missing valueType field", context)
-
-    value_type = json['valueType']
-
-    if value_type == 'RANGE':
-        if not 'min' in json and not 'max' in json:
-            raise SwaggerError("Missing fields min/max", context)
-        return AllowableRange(json.get('min'), json.get('max'))
-    if value_type == 'LIST':
-        if not 'values' in json:
-            raise SwaggerError("Missing field values", context)
-        return AllowableList(json['values'])
-    raise SwaggerError("Unkown valueType %s" % value_type, context)
-
-
-class Parameter(Stringify):
-    """Model of an operation's parameter.
-
-    See https://github.com/wordnik/swagger-core/wiki/parameters
-    """
-
-    required_fields = ['name', 'paramType', 'dataType']
-
-    def __init__(self):
-        self.param_type = None
-        self.name = None
-        self.description = None
-        self.data_type = None
-        self.required = None
-        self.allowable_values = None
-        self.allow_multiple = None
-
-    def load(self, parameter_json, processor, context):
-        context = context.next_stack(parameter_json, 'name')
-        validate_required_fields(parameter_json, self.required_fields, context)
-        self.name = parameter_json.get('name')
-        self.param_type = parameter_json.get('paramType')
-        self.description = parameter_json.get('description') or ''
-        self.data_type = parameter_json.get('dataType')
-        self.required = parameter_json.get('required') or False
-        self.default_value = parameter_json.get('defaultValue')
-        self.allowable_values = load_allowable_values(
-            parameter_json.get('allowableValues'), context)
-        self.allow_multiple = parameter_json.get('allowMultiple') or False
-        processor.process_parameter(self, context)
-        if parameter_json.get('allowedValues'):
-            raise SwaggerError(
-                "Field 'allowedValues' invalid; use 'allowableValues'",
-                context)
-        return self
-
-    def is_type(self, other_type):
-        return self.param_type == other_type
-
-
-class ErrorResponse(Stringify):
-    """Model of an error response.
-
-    See https://github.com/wordnik/swagger-core/wiki/errors
-    """
-
-    required_fields = ['code', 'reason']
-
-    def __init__(self):
-        self.code = None
-        self.reason = None
-
-    def load(self, err_json, processor, context):
-        context = context.next_stack(err_json, 'code')
-        validate_required_fields(err_json, self.required_fields, context)
-        self.code = err_json.get('code')
-        self.reason = err_json.get('reason')
-        return self
-
-
-class SwaggerType(Stringify):
-    """Model of a data type.
-    """
-
-    def __init__(self):
-        self.name = None
-        self.is_discriminator = None
-        self.is_list = None
-        self.singular_name = None
-        self.is_primitive = None
-
-    def load(self, type_name, processor, context):
-        # Some common errors
-        if type_name == 'integer':
-            raise SwaggerError("The type for integer should be 'int'", context)
-
-        self.name = type_name
-        type_param = get_list_parameter_type(self.name)
-        self.is_list = type_param is not None
-        if self.is_list:
-            self.singular_name = type_param
-        else:
-            self.singular_name = self.name
-        self.is_primitive = self.singular_name in SWAGGER_PRIMITIVES
-        processor.process_type(self, context)
-        return self
-
-
-class Operation(Stringify):
-    """Model of an operation on an API
-
-    See https://github.com/wordnik/swagger-core/wiki/API-Declaration#apis
-    """
-
-    required_fields = ['httpMethod', 'nickname', 'responseClass', 'summary']
-
-    def __init__(self):
-        self.http_method = None
-        self.nickname = None
-        self.response_class = None
-        self.parameters = []
-        self.summary = None
-        self.notes = None
-        self.error_responses = []
-
-    def load(self, op_json, processor, context):
-        context = context.next_stack(op_json, 'nickname')
-        validate_required_fields(op_json, self.required_fields, context)
-        self.http_method = op_json.get('httpMethod')
-        self.nickname = op_json.get('nickname')
-        response_class = op_json.get('responseClass')
-        self.response_class = response_class and SwaggerType().load(
-            response_class, processor, context)
-
-        # Specifying WebSocket URL's is our own extension
-        self.is_websocket = op_json.get('upgrade') == 'websocket'
-        self.is_req = not self.is_websocket
-
-        if self.is_websocket:
-            self.websocket_protocol = op_json.get('websocketProtocol')
-            if self.http_method != 'GET':
-                raise SwaggerError(
-                    "upgrade: websocket is only valid on GET operations",
-                    context)
-
-        params_json = op_json.get('parameters') or []
-        self.parameters = [
-            Parameter().load(j, processor, context) for j in params_json]
-        self.query_parameters = [
-            p for p in self.parameters if p.is_type('query')]
-        self.has_query_parameters = self.query_parameters and True
-        self.path_parameters = [
-            p for p in self.parameters if p.is_type('path')]
-        self.has_path_parameters = self.path_parameters and True
-        self.header_parameters = [
-            p for p in self.parameters if p.is_type('header')]
-        self.has_header_parameters = self.header_parameters and True
-        self.has_parameters = self.has_query_parameters or \
-            self.has_path_parameters or self.has_header_parameters
-
-        # Body param is different, since there's at most one
-        self.body_parameter = [
-            p for p in self.parameters if p.is_type('body')]
-        if len(self.body_parameter) > 1:
-            raise SwaggerError("Cannot have more than one body param", context)
-        self.body_parameter = self.body_parameter and self.body_parameter[0]
-        self.has_body_parameter = self.body_parameter and True
-
-        self.summary = op_json.get('summary')
-        self.notes = op_json.get('notes')
-        err_json = op_json.get('errorResponses') or []
-        self.error_responses = [
-            ErrorResponse().load(j, processor, context) for j in err_json]
-        self.has_error_responses = self.error_responses != []
-        processor.process_operation(self, context)
-        return self
-
-
-class Api(Stringify):
-    """Model of a single API in an API declaration.
-
-    See https://github.com/wordnik/swagger-core/wiki/API-Declaration
-    """
-
-    required_fields = ['path', 'operations']
-
-    def __init__(self,):
-        self.path = None
-        self.description = None
-        self.operations = []
-
-    def load(self, api_json, processor, context):
-        context = context.next_stack(api_json, 'path')
-        validate_required_fields(api_json, self.required_fields, context)
-        self.path = api_json.get('path')
-        self.description = api_json.get('description')
-        op_json = api_json.get('operations')
-        self.operations = [
-            Operation().load(j, processor, context) for j in op_json]
-        self.has_websocket = \
-            filter(lambda op: op.is_websocket, self.operations) != []
-        processor.process_api(self, context)
-        return self
-
-
-def get_list_parameter_type(type_string):
-    """Returns the type parameter if the given type_string is List[].
-
-    @param type_string: Type string to parse
-    @returns Type parameter of the list, or None if not a List.
-    """
-    list_match = re.match('^List\[(.*)\]$', type_string)
-    return list_match and list_match.group(1)
-
-
-class Property(Stringify):
-    """Model of a Swagger property.
-
-    See https://github.com/wordnik/swagger-core/wiki/datatypes
-    """
-
-    required_fields = ['type']
-
-    def __init__(self, name):
-        self.name = name
-        self.type = None
-        self.description = None
-        self.required = None
-
-    def load(self, property_json, processor, context):
-        validate_required_fields(property_json, self.required_fields, context)
-        # Bit of a hack, but properties do not self-identify
-        context = context.next_stack({'name': self.name}, 'name')
-        self.description = property_json.get('description') or ''
-        self.required = property_json.get('required') or False
-
-        type = property_json.get('type')
-        self.type = type and SwaggerType().load(type, processor, context)
-
-        processor.process_property(self, context)
-        return self
-
-
-class Model(Stringify):
-    """Model of a Swagger model.
-
-    See https://github.com/wordnik/swagger-core/wiki/datatypes
-    """
-
-    required_fields = ['description', 'properties']
-
-    def __init__(self):
-        self.id = None
-        self.subtypes = []
-        self.__subtype_types = []
-        self.notes = None
-        self.description = None
-        self.__properties = None
-        self.__discriminator = None
-        self.__extends_type = None
-
-    def load(self, id, model_json, processor, context):
-        context = context.next_stack(model_json, 'id')
-        validate_required_fields(model_json, self.required_fields, context)
-        # The duplication of the model's id is required by the Swagger spec.
-        self.id = model_json.get('id')
-        if id != self.id:
-            raise SwaggerError("Model id doesn't match name", context)
-        self.subtypes = model_json.get('subTypes') or []
-        if self.subtypes and context.version_less_than("1.2"):
-            raise SwaggerError("Type extension support added in Swagger 1.2",
-                               context)
-        self.description = model_json.get('description')
-        props = model_json.get('properties').items() or []
-        self.__properties = [
-            Property(k).load(j, processor, context) for (k, j) in props]
-        self.__properties = sorted(self.__properties, key=lambda p: p.name)
-
-        discriminator = model_json.get('discriminator')
-
-        if discriminator:
-            if context.version_less_than("1.2"):
-                raise SwaggerError("Discriminator support added in Swagger 1.2",
-                                   context)
-
-            discr_props = [p for p in self.__properties if p.name == discriminator]
-            if not discr_props:
-                raise SwaggerError(
-                    "Discriminator '%s' does not name a property of '%s'" % (
-                        discriminator, self.id),
-                    context)
-
-            self.__discriminator = discr_props[0]
-
-        self.model_json = json.dumps(model_json,
-                                     indent=2, separators=(',', ': '))
-
-        processor.process_model(self, context)
-        return self
-
-    def extends(self):
-        return self.__extends_type and self.__extends_type.id
-
-    def set_extends_type(self, extends_type):
-        self.__extends_type = extends_type
-
-    def set_subtype_types(self, subtype_types):
-        self.__subtype_types = subtype_types
-
-    def discriminator(self):
-        """Returns the discriminator, digging through base types if needed.
-        """
-        return self.__discriminator or \
-            self.__extends_type and self.__extends_type.discriminator()
-
-    def properties(self):
-        base_props = []
-        if self.__extends_type:
-            base_props = self.__extends_type.properties()
-        return base_props + self.__properties
-
-    def has_properties(self):
-        return len(self.properties()) > 0
-
-    def all_subtypes(self):
-        """Returns the full list of all subtypes, including sub-subtypes.
-        """
-        res = self.__subtype_types + \
-              [subsubtypes for subtype in self.__subtype_types
-               for subsubtypes in subtype.all_subtypes()]
-        return sorted(res, key=lambda m: m.id)
-
-    def has_subtypes(self):
-        """Returns True if type has any subtypes.
-        """
-        return len(self.subtypes) > 0
-
-
-class ApiDeclaration(Stringify):
-    """Model class for an API Declaration.
-
-    See https://github.com/wordnik/swagger-core/wiki/API-Declaration
-    """
-
-    required_fields = [
-        'swaggerVersion', '_author', '_copyright', 'apiVersion', 'basePath',
-        'resourcePath', 'apis', 'models'
-    ]
-
-    def __init__(self):
-        self.swagger_version = None
-        self.author = None
-        self.copyright = None
-        self.api_version = None
-        self.base_path = None
-        self.resource_path = None
-        self.apis = []
-        self.models = []
-
-    def load_file(self, api_declaration_file, processor):
-        context = ParsingContext(None, [api_declaration_file])
-        try:
-            return self.__load_file(api_declaration_file, processor, context)
-        except SwaggerError:
-            raise
-        except Exception as e:
-            print >> sys.stderr, "Error: ", traceback.format_exc()
-            raise SwaggerError(
-                "Error loading %s" % api_declaration_file, context, e)
-
-    def __load_file(self, api_declaration_file, processor, context):
-        with open(api_declaration_file) as fp:
-            self.load(json.load(fp), processor, context)
-
-        expected_resource_path = '/api-docs/' + \
-            os.path.basename(api_declaration_file) \
-            .replace(".json", ".{format}")
-
-        if self.resource_path != expected_resource_path:
-            print >> sys.stderr, \
-                "%s != %s" % (self.resource_path, expected_resource_path)
-            raise SwaggerError("resourcePath has incorrect value", context)
-
-        return self
-
-    def load(self, api_decl_json, processor, context):
-        """Loads a resource from a single Swagger resource.json file.
-        """
-        # If the version doesn't match, all bets are off.
-        self.swagger_version = api_decl_json.get('swaggerVersion')
-        context = context.next(version=self.swagger_version)
-        if not self.swagger_version in SWAGGER_VERSIONS:
-            raise SwaggerError(
-                "Unsupported Swagger version %s" % self.swagger_version, context)
-
-        validate_required_fields(api_decl_json, self.required_fields, context)
-
-        self.author = api_decl_json.get('_author')
-        self.copyright = api_decl_json.get('_copyright')
-        self.api_version = api_decl_json.get('apiVersion')
-        self.base_path = api_decl_json.get('basePath')
-        self.resource_path = api_decl_json.get('resourcePath')
-        api_json = api_decl_json.get('apis') or []
-        self.apis = [
-            Api().load(j, processor, context) for j in api_json]
-        paths = set()
-        for api in self.apis:
-            if api.path in paths:
-                raise SwaggerError("API with duplicated path: %s" % api.path, context)
-            paths.add(api.path)
-        self.has_websocket = filter(lambda api: api.has_websocket,
-                                    self.apis) == []
-        models = api_decl_json.get('models').items() or []
-        self.models = [Model().load(id, json, processor, context)
-                       for (id, json) in models]
-        self.models = sorted(self.models, key=lambda m: m.id)
-        # Now link all base/extended types
-        model_dict = dict((m.id, m) for m in self.models)
-        for m in self.models:
-            def link_subtype(name):
-                res = model_dict.get(subtype)
-                if not res:
-                    raise SwaggerError("%s has non-existing subtype %s",
-                                       m.id, name)
-                res.set_extends_type(m)
-                return res;
-            if m.subtypes:
-                m.set_subtype_types([
-                    link_subtype(subtype) for subtype in m.subtypes])
-        return self
-
-
-class ResourceApi(Stringify):
-    """Model of an API listing in the resources.json file.
-    """
-
-    required_fields = ['path', 'description']
-
-    def __init__(self):
-        self.path = None
-        self.description = None
-        self.api_declaration = None
-
-    def load(self, api_json, processor, context):
-        context = context.next_stack(api_json, 'path')
-        validate_required_fields(api_json, self.required_fields, context)
-        self.path = api_json['path']
-        self.description = api_json['description']
-
-        if not self.path or self.path[0] != '/':
-            raise SwaggerError("Path must start with /", context)
-        processor.process_resource_api(self, context)
-        return self
-
-    def load_api_declaration(self, base_dir, processor):
-        self.file = (base_dir + self.path).replace('{format}', 'json')
-        self.api_declaration = ApiDeclaration().load_file(self.file, processor)
-        processor.process_resource_api(self, [self.file])
-
-
-class ResourceListing(Stringify):
-    """Model of Swagger's resources.json file.
-    """
-
-    required_fields = ['apiVersion', 'basePath', 'apis']
-
-    def __init__(self):
-        self.swagger_version = None
-        self.api_version = None
-        self.base_path = None
-        self.apis = None
-
-    def load_file(self, resource_file, processor):
-        context = ParsingContext(None, [resource_file])
-        try:
-            return self.__load_file(resource_file, processor, context)
-        except SwaggerError:
-            raise
-        except Exception as e:
-            print >> sys.stderr, "Error: ", traceback.format_exc()
-            raise SwaggerError(
-                "Error loading %s" % resource_file, context, e)
-
-    def __load_file(self, resource_file, processor, context):
-        with open(resource_file) as fp:
-            return self.load(json.load(fp), processor, context)
-
-    def load(self, resources_json, processor, context):
-        # If the version doesn't match, all bets are off.
-        self.swagger_version = resources_json.get('swaggerVersion')
-        if not self.swagger_version in SWAGGER_VERSIONS:
-            raise SwaggerError(
-                "Unsupported Swagger version %s" % swagger_version, context)
-
-        validate_required_fields(resources_json, self.required_fields, context)
-        self.api_version = resources_json['apiVersion']
-        self.base_path = resources_json['basePath']
-        apis_json = resources_json['apis']
-        self.apis = [
-            ResourceApi().load(j, processor, context) for j in apis_json]
-        processor.process_resource_listing(self, context)
-        return self
-
-
-def validate_required_fields(json, required_fields, context):
-    """Checks a JSON object for a set of required fields.
-
-    If any required field is missing, a SwaggerError is raised.
-
-    @param json: JSON object to check.
-    @param required_fields: List of required fields.
-    @param context: Current context in the API.
-    """
-    missing_fields = [f for f in required_fields if not f in json]
-
-    if missing_fields:
-        raise SwaggerError(
-            "Missing fields: %s" % ', '.join(missing_fields), context)
diff --git a/rest-api-templates/transform.py b/rest-api-templates/transform.py
deleted file mode 100644
index fc12efe..0000000
--- a/rest-api-templates/transform.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# Asterisk -- An open source telephony toolkit.
-#
-# Copyright (C) 2013, Digium, Inc.
-#
-# David M. Lee, II <dlee at digium.com>
-#
-# See http://www.asterisk.org for more information about
-# the Asterisk project. Please do not directly contact
-# any of the maintainers of this project for assistance;
-# the project provides a web site, mailing lists and IRC
-# channels for your use.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License Version 2. See the LICENSE file
-# at the top of the source tree.
-#
-
-import filecmp
-import os.path
-import pystache
-import shutil
-import tempfile
-
-
-class Transform(object):
-    """Transformation for template to code.
-    """
-    def __init__(self, template_file, dest_file_template_str, overwrite=True):
-        """Ctor.
-
-        @param template_file: Filename of the mustache template.
-        @param dest_file_template_str: Destination file name. This is a
-            mustache template, so each resource can write to a unique file.
-        @param overwrite: If True, destination file is ovewritten if it exists.
-        """
-        template_str = unicode(open(template_file, "r").read())
-        self.template = pystache.parse(template_str)
-        dest_file_template_str = unicode(dest_file_template_str)
-        self.dest_file_template = pystache.parse(dest_file_template_str)
-        self.overwrite = overwrite
-
-    def render(self, renderer, model, dest_dir):
-        """Render a model according to this transformation.
-
-        @param render: Pystache renderer.
-        @param model: Model object to render.
-        @param dest_dir: Destination directory to write generated code.
-        """
-        dest_file = pystache.render(self.dest_file_template, model)
-        dest_file = os.path.join(dest_dir, dest_file)
-        dest_exists = os.path.exists(dest_file)
-        if dest_exists and not self.overwrite:
-            return
-        tmp_file = tempfile.mkstemp()
-        with tempfile.NamedTemporaryFile() as out:
-            out.write(renderer.render(self.template, model))
-            out.flush()
-
-            if not dest_exists or not filecmp.cmp(out.name, dest_file):
-                print "Writing %s" % dest_file
-                shutil.copyfile(out.name, dest_file)
diff --git a/rest-api/README.txt b/rest-api/README.txt
deleted file mode 100644
index 893bf87..0000000
--- a/rest-api/README.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-<!-- Written in -*- Markdown -*- -->
-
-This directory contains the specification for the Asterisk RESTful
-API. The API is documented using Swagger[1]. This is used to not only
-generate executable documentation pages for the API, but also to
-generate a lot of the boilerplate necessary for implementing the API
-with Asterisk's HTTP server.
-
- [1]: http://swagger.wordnik.com/
diff --git a/rest-api/api-docs/applications.json b/rest-api/api-docs/applications.json
deleted file mode 100644
index db5a9ee..0000000
--- a/rest-api/api-docs/applications.json
+++ /dev/null
@@ -1,172 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/applications.{format}",
-	"apis": [
-		{
-			"path": "/applications",
-			"description": "Stasis applications",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all applications.",
-					"nickname": "list",
-					"responseClass": "List[Application]"
-				}
-			]
-		},
-		{
-			"path": "/applications/{applicationName}",
-			"description": "Stasis application",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get details of an application.",
-					"nickname": "get",
-					"responseClass": "Application",
-					"parameters": [
-						{
-							"name": "applicationName",
-							"description": "Application's name",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Application does not exist."
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/applications/{applicationName}/subscription",
-			"description": "Stasis application",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Subscribe an application to a event source.",
-					"notes": "Returns the state of the application after the subscriptions have changed",
-					"nickname": "subscribe",
-					"responseClass": "Application",
-					"parameters": [
-						{
-							"name": "applicationName",
-							"description": "Application's name",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "eventSource",
-							"description": "URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}[/{resource}], deviceState:{deviceName}",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": true,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing parameter."
-						},
-						{
-							"code": 404,
-							"reason": "Application does not exist."
-						},
-						{
-							"code": 422,
-							"reason": "Event source does not exist."
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Unsubscribe an application from an event source.",
-					"notes": "Returns the state of the application after the subscriptions have changed",
-					"nickname": "unsubscribe",
-					"responseClass": "Application",
-					"parameters": [
-						{
-							"name": "applicationName",
-							"description": "Application's name",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "eventSource",
-							"description": "URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}[/{resource}], deviceState:{deviceName}",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": true,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing parameter; event source scheme not recognized."
-						},
-						{
-							"code": 404,
-							"reason": "Application does not exist."
-						},
-						{
-							"code": 409,
-							"reason": "Application not subscribed to event source."
-						},
-						{
-							"code": 422,
-							"reason": "Event source does not exist."
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"Application": {
-			"id": "Application",
-			"description": "Details of a Stasis application",
-			"properties": {
-				"name": {
-					"type": "string",
-					"description": "Name of this application",
-					"required": true
-				},
-				"channel_ids": {
-					"type": "List[string]",
-					"description": "Id's for channels subscribed to.",
-					"required": true
-				},
-				"bridge_ids": {
-					"type": "List[string]",
-					"description": "Id's for bridges subscribed to.",
-					"required": true
-				},
-				"endpoint_ids": {
-					"type": "List[string]",
-					"description": "{tech}/{resource} for endpoints subscribed to.",
-					"required": true
-				},
-				"device_names": {
-					"type": "List[string]",
-					"description": "Names of the devices subscribed to.",
-					"required": true
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json
deleted file mode 100644
index 69cef05..0000000
--- a/rest-api/api-docs/asterisk.json
+++ /dev/null
@@ -1,259 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/asterisk.{format}",
-	"apis": [
-		{
-			"path": "/asterisk/info",
-			"description": "Asterisk system information (similar to core show settings)",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Gets Asterisk system information.",
-					"nickname": "getInfo",
-					"responseClass": "AsteriskInfo",
-					"parameters": [
-						{
-							"name": "only",
-							"description": "Filter information returned",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": true,
-							"dataType": "string",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"build",
-									"system",
-									"config",
-									"status"
-								]
-							}
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/asterisk/variable",
-			"description": "Global variables",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get the value of a global variable.",
-					"nickname": "getGlobalVar",
-					"responseClass": "Variable",
-					"parameters": [
-						{
-							"name": "variable",
-							"description": "The variable to get",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing variable parameter."
-						}
-					]
-				},
-				{
-					"httpMethod": "POST",
-					"summary": "Set the value of a global variable.",
-					"nickname": "setGlobalVar",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "variable",
-							"description": "The variable to set",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "value",
-							"description": "The value to set the variable to",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing variable parameter."
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"BuildInfo": {
-			"id": "BuildInfo",
-			"description": "Info about how Asterisk was built",
-			"properties": {
-				"os": {
-					"required": true,
-					"type": "string",
-					"description": "OS Asterisk was built on."
-				},
-				"kernel": {
-					"required": true,
-					"type": "string",
-					"description": "Kernel version Asterisk was built on."
-				},
-				"options": {
-					"required": true,
-					"type": "string",
-					"description": "Compile time options, or empty string if default."
-				},
-				"machine": {
-					"required": true,
-					"type": "string",
-					"description": "Machine architecture (x86_64, i686, ppc, etc.)"
-				},
-				"date": {
-					"required": true,
-					"type": "string",
-					"description": "Date and time when Asterisk was built."
-				},
-				"user": {
-					"required": true,
-					"type": "string",
-					"description": "Username that build Asterisk"
-				}
-			}
-		},
-		"SystemInfo": {
-			"id": "SystemInfo",
-			"description": "Info about Asterisk",
-			"properties": {
-				"version": {
-					"required": true,
-					"type": "string",
-					"description": "Asterisk version."
-				},
-				"entity_id": {
-					"required": true,
-					"type": "string",
-					"description": ""
-				}
-			}
-		},
-		"SetId": {
-			"id": "SetId",
-			"description": "Effective user/group id",
-			"properties": {
-				"user": {
-					"required": true,
-					"type": "string",
-					"description": "Effective user id."
-				},
-				"group": {
-					"required": true,
-					"type": "string",
-					"description": "Effective group id."
-				}
-			}
-		},
-		"ConfigInfo": {
-			"id": "ConfigInfo",
-			"description": "Info about Asterisk configuration",
-			"properties": {
-				"name": {
-					"required": true,
-					"type": "string",
-					"description": "Asterisk system name."
-				},
-				"default_language": {
-					"required": true,
-					"type": "string",
-					"description": "Default language for media playback."
-				},
-				"max_channels": {
-					"required": false,
-					"type": "int",
-					"description": "Maximum number of simultaneous channels."
-				},
-				"max_open_files": {
-					"required": false,
-					"type": "int",
-					"description": "Maximum number of open file handles (files, sockets)."
-				},
-				"max_load": {
-					"required": false,
-					"type": "double",
-					"description": "Maximum load avg on system."
-				},
-				"setid": {
-					"required": true,
-					"type": "SetId",
-					"description": "Effective user/group id for running Asterisk."
-				}
-			}
-		},
-		"StatusInfo": {
-			"id": "StatusInfo",
-			"description": "Info about Asterisk status",
-			"properties": {
-				"startup_time": {
-					"required": true,
-					"type": "Date",
-					"description": "Time when Asterisk was started."
-				},
-				"last_reload_time": {
-					"required": true,
-					"type": "Date",
-					"description": "Time when Asterisk was last reloaded."
-				}
-			}
-		},
-		"AsteriskInfo": {
-			"id": "AsteriskInfo",
-			"description": "Asterisk system information",
-			"properties": {
-				"build": {
-					"required": false,
-					"type": "BuildInfo",
-					"description": "Info about how Asterisk was built"
-				},
-				"system": {
-					"required": false,
-					"type": "SystemInfo",
-					"description": "Info about the system running Asterisk"
-				},
-				"config": {
-					"required": false,
-					"type": "ConfigInfo",
-					"description": "Info about Asterisk configuration"
-				},
-				"status": {
-					"required": false,
-					"type": "StatusInfo",
-					"description": "Info about Asterisk status"
-				}
-			}
-		},
-		"Variable": {
-			"id": "Variable",
-			"description": "The value of a channel variable",
-			"properties": {
-				"value": {
-					"required": true,
-					"type": "string",
-					"description": "The value of the variable requested"
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json
deleted file mode 100644
index 9545416..0000000
--- a/rest-api/api-docs/bridges.json
+++ /dev/null
@@ -1,656 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/bridges.{format}",
-	"apis": [
-		{
-			"path": "/bridges",
-			"description": "Active bridges",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all active bridges in Asterisk.",
-					"nickname": "list",
-					"responseClass": "List[Bridge]"
-				},
-				{
-					"httpMethod": "POST",
-					"summary": "Create a new bridge.",
-					"notes": "This bridge persists until it has been shut down, or Asterisk has been shut down.",
-					"nickname": "create",
-					"responseClass": "Bridge",
-					"parameters": [
-						{
-							"name": "type",
-							"description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media).",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "bridgeId",
-							"description": "Unique ID to give to the bridge being created.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "name",
-							"description": "Name to give to the bridge being created.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}",
-			"description": "Individual bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Create a new bridge or updates an existing one.",
-					"notes": "This bridge persists until it has been shut down, or Asterisk has been shut down.",
-					"nickname": "create_or_update_with_id",
-					"responseClass": "Bridge",
-					"parameters": [
-						{
-							"name": "type",
-							"description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media) to set.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "bridgeId",
-							"description": "Unique ID to give to the bridge being created.",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "name",
-							"description": "Set the name of the bridge.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					]
-				},
-				{
-					"httpMethod": "GET",
-					"summary": "Get bridge details.",
-					"nickname": "get",
-					"responseClass": "Bridge",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Shut down a bridge.",
-					"notes": "If any channels are in this bridge, they will be removed and resume whatever they were doing beforehand.",
-					"nickname": "destroy",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/addChannel",
-			"description": "Add a channel to a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Add a channel to a bridge.",
-					"nickname": "addChannel",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "channel",
-							"description": "Ids of channels to add to bridge",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": true,
-							"dataType": "string"
-						},
-						{
-							"name": "role",
-							"description": "Channel's role in the bridge",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in Stasis application; Channel currently recording"
-						},
-						{
-							"code": 422,
-							"reason": "Channel not in Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/removeChannel",
-			"description": "Remove a channel from a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Remove a channel from a bridge.",
-					"nickname": "removeChannel",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "channel",
-							"description": "Ids of channels to remove from bridge",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": true,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in Stasis application"
-						},
-						{
-							"code": 422,
-							"reason": "Channel not in this bridge"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/moh",
-			"description": "Play music on hold to a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Play music on hold to a bridge or change the MOH class that is playing.",
-					"nickname": "startMoh",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "mohClass",
-							"description": "Channel's id",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop playing music on hold to a bridge.",
-					"notes": "This will only stop music on hold being played via POST bridges/{bridgeId}/moh.",
-					"nickname": "stopMoh",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/play",
-			"description": "Play media to the participants of a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start playback of media on a bridge.",
-					"notes": "The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)",
-					"nickname": "play",
-					"responseClass": "Playback",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "media",
-							"description": "Media's URI to play.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "lang",
-							"description": "For sounds, selects language for sound.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "offsetms",
-							"description": "Number of media to skip before playing.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-
-						},
-						{
-							"name": "skipms",
-							"description": "Number of milliseconds to skip for forward/reverse operations.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 3000,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "playbackId",
-							"description": "Playback Id.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/play/{playbackId}",
-			"description": "Play media to a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start playback of media on a bridge.",
-					"notes": "The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)",
-					"nickname": "playWithId",
-					"responseClass": "Playback",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "playbackId",
-							"description": "Playback ID.",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "media",
-							"description": "Media's URI to play.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "lang",
-							"description": "For sounds, selects language for sound.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "offsetms",
-							"description": "Number of media to skip before playing.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "skipms",
-							"description": "Number of milliseconds to skip for forward/reverse operations.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 3000,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Bridge not found"
-						},
-						{
-							"code": 409,
-							"reason": "Bridge not in a Stasis application"
-						}
-					]
-
-				}
-			]
-		},
-		{
-			"path": "/bridges/{bridgeId}/record",
-			"description": "Record audio on a bridge",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start a recording.",
-					"notes": "This records the mixed audio from all channels participating in this bridge.",
-					"nickname": "record",
-					"responseClass": "LiveRecording",
-					"parameters": [
-						{
-							"name": "bridgeId",
-							"description": "Bridge's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "name",
-							"description": "Recording's filename",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "format",
-							"description": "Format to encode audio in",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "maxDurationSeconds",
-							"description": "Maximum duration of the recording, in seconds. 0 for no limit.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "maxSilenceSeconds",
-							"description": "Maximum duration of silence, in seconds. 0 for no limit.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "ifExists",
-							"description": "Action to take if a recording with the same name already exists.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "fail",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"fail",
-									"overwrite",
-									"append"
-								]
-							}
-						},
-						{
-							"name": "beep",
-							"description": "Play beep when recording begins",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "boolean",
-							"defaultValue": false
-						},
-						{
-							"name": "terminateOn",
-							"description": "DTMF input to terminate recording.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"any",
-									"*",
-									"#"
-								]
-							}
-						}
-					],
-                    "errorResponses": [
-                        {
-                            "code": 400,
-                            "reason": "Invalid parameters"
-                        },
-                        {
-                            "code": 404,
-                            "reason": "Bridge not found"
-                        },
-                        {
-                            "code": 409,
-                            "reason": "Bridge is not in a Stasis application; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail"
-                        },
-						{
-							"code": 422,
-							"reason": "The format specified is unknown on this system"
-						}
-                    ]
-				}
-			]
-		}
-	],
-	"models": {
-		"Bridge": {
-			"id": "Bridge",
-			"description": "The merging of media from one or more channels.\n\nEveryone on the bridge receives the same audio.",
-			"properties": {
-				"id": {
-					"type": "string",
-					"description": "Unique identifier for this bridge",
-					"required": true
-				},
-				"technology": {
-					"type": "string",
-					"description": "Name of the current bridging technology",
-					"required": true
-				},
-				"bridge_type": {
-					"type": "string",
-					"description": "Type of bridge technology",
-					"required": true,
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"mixing",
-							"holding"
-						]
-					}
-				},
-				"bridge_class": {
-					"type": "string",
-					"description": "Bridging class",
-					"required": true
-				},
-				"creator": {
-					"type": "string",
-					"description": "Entity that created the bridge",
-					"required": true
-				},
-				"name": {
-					"type": "string",
-					"description": "Name the creator gave the bridge",
-					"required": true
-				},
-				"channels": {
-					"type": "List[string]",
-					"description": "Ids of channels participating in this bridge",
-					"required": true
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
deleted file mode 100644
index ac497e9..0000000
--- a/rest-api/api-docs/channels.json
+++ /dev/null
@@ -1,1456 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/channels.{format}",
-	"apis": [
-		{
-			"path": "/channels",
-			"description": "Active channels",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all active channels in Asterisk.",
-					"nickname": "list",
-					"responseClass": "List[Channel]"
-				},
-				{
-					"httpMethod": "POST",
-					"summary": "Create a new channel (originate).",
-					"notes": "The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated channel for further events and updates.",
-					"nickname": "originate",
-					"responseClass": "Channel",
-					"parameters": [
-						{
-							"name": "endpoint",
-							"description": "Endpoint to call.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "extension",
-							"description": "The extension to dial after the endpoint answers",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "context",
-							"description": "The context to dial after the endpoint answers. If omitted, uses 'default'",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "priority",
-							"description": "The priority to dial after the endpoint answers. If omitted, uses 1",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "long"
-						},
-						{
-							"name": "app",
-							"description": "The application that is subscribed to the originated channel, and passed to the Stasis application.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "appArgs",
-							"description": "The application arguments to pass to the Stasis application.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "callerId",
-							"description": "CallerID to use when dialing the endpoint or extension.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "timeout",
-							"description": "Timeout (in seconds) before giving up dialing, or -1 for no timeout.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 30
-						},
-						{
-							"name": "variables",
-							"description": "The \"variables\" key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { \"endpoint\": \"SIP/Alice\", \"variables\": { \"CALLERID(name)\": \"Alice\" } }",
-							"paramType": "body",
-							"required": false,
-							"dataType": "containers",
-							"allowMultiple": false
-						},
-						{
-							"name": "channelId",
-							"description": "The unique id to assign the channel on creation.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "otherChannelId",
-							"description": "The unique id to assign the second channel when using local channels.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters for originating a channel."
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}",
-			"description": "Active channel",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Channel details.",
-					"nickname": "get",
-					"responseClass": "Channel",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "POST",
-					"summary": "Create a new channel (originate with id).",
-					"notes": "The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated channel for further events and updates.",
-					"nickname": "originateWithId",
-					"responseClass": "Channel",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "The unique id to assign the channel on creation.",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "endpoint",
-							"description": "Endpoint to call.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "extension",
-							"description": "The extension to dial after the endpoint answers",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "context",
-							"description": "The context to dial after the endpoint answers. If omitted, uses 'default'",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "priority",
-							"description": "The priority to dial after the endpoint answers. If omitted, uses 1",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "long"
-						},
-						{
-							"name": "app",
-							"description": "The application that is subscribed to the originated channel, and passed to the Stasis application.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "appArgs",
-							"description": "The application arguments to pass to the Stasis application.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "callerId",
-							"description": "CallerID to use when dialing the endpoint or extension.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "timeout",
-							"description": "Timeout (in seconds) before giving up dialing, or -1 for no timeout.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 30
-						},
-						{
-							"name": "variables",
-							"description": "The \"variables\" key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { \"endpoint\": \"SIP/Alice\", \"variables\": { \"CALLERID(name)\": \"Alice\" } }",
-							"paramType": "body",
-							"required": false,
-							"dataType": "containers",
-							"allowMultiple": false
-						},
-						{
-							"name": "otherChannelId",
-							"description": "The unique id to assign the second channel when using local channels.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters for originating a channel."
-						}
-					]
-
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Delete (i.e. hangup) a channel.",
-					"nickname": "hangup",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "reason",
-							"description": "Reason for hanging up the channel",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defalutValue": "normal",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"normal",
-									"busy",
-									"congestion"
-								]
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid reason for hangup provided"
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/continue",
-			"description": "Exit application; continue execution in the dialplan",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Exit application; continue execution in the dialplan.",
-					"nickname": "continueInDialplan",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "context",
-							"description": "The context to continue to.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "extension",
-							"description": "The extension to continue to.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "priority",
-							"description": "The priority to continue to.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/answer",
-			"description": "Answer a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Answer a channel.",
-					"nickname": "answer",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/ring",
-			"description": "Send a ringing indication to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Indicate ringing to a channel.",
-					"nickname": "ring",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop ringing indication on a channel if locally generated.",
-					"nickname": "ringStop",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/dtmf",
-			"description": "Send DTMF to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Send provided DTMF to a given channel.",
-					"nickname": "sendDTMF",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "dtmf",
-							"description": "DTMF To send.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "before",
-							"description": "Amount of time to wait before DTMF digits (specified in milliseconds) start.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0
-						},
-						{
-							"name": "between",
-							"description": "Amount of time in between DTMF digits (specified in milliseconds).",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 100
-						},
-						{
-							"name": "duration",
-							"description": "Length of each DTMF digit (specified in milliseconds).",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 100
-						},
-						{
-							"name": "after",
-							"description": "Amount of time to wait after DTMF digits (specified in milliseconds) end.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "DTMF is required"
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/mute",
-			"description": "Mute a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Mute a channel.",
-					"nickname": "mute",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "direction",
-							"description": "Direction in which to mute audio",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "both",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"both",
-									"in",
-									"out"
-								]
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Unmute a channel.",
-					"nickname": "unmute",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "direction",
-							"description": "Direction in which to unmute audio",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "both",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"both",
-									"in",
-									"out"
-								]
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/hold",
-			"description": "Put a channel on hold",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Hold a channel.",
-					"nickname": "hold",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Remove a channel from hold.",
-					"nickname": "unhold",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/moh",
-			"description": "Play music on hold to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Play music on hold to a channel.",
-					"notes": "Using media operations such as /play on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.",
-					"nickname": "startMoh",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "mohClass",
-							"description": "Music on hold class to use",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop playing music on hold to a channel.",
-					"nickname": "stopMoh",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/silence",
-			"description": "Play silence to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Play silence to a channel.",
-					"notes": "Using media operations such as /play on a channel playing silence in this manner will suspend silence without resuming automatically.",
-					"nickname": "startSilence",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop playing silence to a channel.",
-					"nickname": "stopSilence",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/play",
-			"description": "Play media to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start playback of media.",
-					"notes": "The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)",
-					"nickname": "play",
-					"responseClass": "Playback",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "media",
-							"description": "Media's URI to play.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "lang",
-							"description": "For sounds, selects language for sound.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "offsetms",
-							"description": "Number of media to skip before playing.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int"
-						},
-						{
-							"name": "skipms",
-							"description": "Number of milliseconds to skip for forward/reverse operations.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 3000
-						},
-						{
-							"name": "playbackId",
-							"description": "Playback ID.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/play/{playbackId}",
-			"description": "Play media to a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start playback of media and specify the playbackId.",
-					"notes": "The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)",
-					"nickname": "playWithId",
-					"responseClass": "Playback",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "playbackId",
-							"description": "Playback ID.",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "media",
-							"description": "Media's URI to play.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "lang",
-							"description": "For sounds, selects language for sound.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "offsetms",
-							"description": "Number of media to skip before playing.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int"
-						},
-						{
-							"name": "skipms",
-							"description": "Number of milliseconds to skip for forward/reverse operations.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 3000
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/record",
-			"description": "Record audio from a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start a recording.",
-					"notes": "Record audio from a channel. Note that this will not capture audio sent to the channel. The bridge itself has a record feature if that's what you want.",
-					"nickname": "record",
-					"responseClass": "LiveRecording",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "name",
-							"description": "Recording's filename",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "format",
-							"description": "Format to encode audio in",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "maxDurationSeconds",
-							"description": "Maximum duration of the recording, in seconds. 0 for no limit",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "maxSilenceSeconds",
-							"description": "Maximum duration of silence, in seconds. 0 for no limit",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "int",
-							"defaultValue": 0,
-							"allowableValues": {
-								"valueType": "RANGE",
-								"min": 0
-							}
-						},
-						{
-							"name": "ifExists",
-							"description": "Action to take if a recording with the same name already exists.",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "fail",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"fail",
-									"overwrite",
-									"append"
-								]
-							}
-						},
-						{
-							"name": "beep",
-							"description": "Play beep when recording begins",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "boolean",
-							"defaultValue": false
-						},
-						{
-							"name": "terminateOn",
-							"description": "DTMF input to terminate recording",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"any",
-									"*",
-									"#"
-								]
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters"
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel is not in a Stasis application; the channel is currently bridged with other hcannels; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail"
-						},
-						{
-							"code": 422,
-							"reason": "The format specified is unknown on this system"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/variable",
-			"description": "Variables on a channel",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get the value of a channel variable or function.",
-					"nickname": "getChannelVar",
-					"responseClass": "Variable",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "variable",
-							"description": "The channel variable or function to get",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing variable parameter."
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				},
-				{
-					"httpMethod": "POST",
-					"summary": "Set the value of a channel variable or function.",
-					"nickname": "setChannelVar",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "variable",
-							"description": "The channel variable or function to set",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "value",
-							"description": "The value to set the variable to",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Missing variable parameter."
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						},
-						{
-							"code": 409,
-							"reason": "Channel not in a Stasis application"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/snoop",
-			"description": "Snoop (spy/whisper) on a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start snooping.",
-					"notes": "Snoop (spy/whisper) on a specific channel.",
-					"nickname": "snoopChannel",
-					"responseClass": "Channel",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "spy",
-							"description": "Direction of audio to spy on",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"both",
-									"out",
-									"in"
-								]
-							}
-						},
-						{
-							"name": "whisper",
-							"description": "Direction of audio to whisper into",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"both",
-									"out",
-									"in"
-								]
-							}
-						},
-						{
-							"name": "app",
-							"description": "Application the snooping channel is placed into",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "appArgs",
-							"description": "The application arguments to pass to the Stasis application",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "snoopId",
-							"description": "Unique ID to assign to snooping channel",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters"
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/channels/{channelId}/snoop/{snoopId}",
-			"description": "Snoop (spy/whisper) on a channel",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Start snooping.",
-					"notes": "Snoop (spy/whisper) on a specific channel.",
-					"nickname": "snoopChannelWithId",
-					"responseClass": "Channel",
-					"parameters": [
-						{
-							"name": "channelId",
-							"description": "Channel's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "snoopId",
-							"description": "Unique ID to assign to snooping channel",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "spy",
-							"description": "Direction of audio to spy on",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"both",
-									"out",
-									"in"
-								]
-							}
-						},
-						{
-							"name": "whisper",
-							"description": "Direction of audio to whisper into",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string",
-							"defaultValue": "none",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"none",
-									"both",
-									"out",
-									"in"
-								]
-							}
-						},
-						{
-							"name": "app",
-							"description": "Application the snooping channel is placed into",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "appArgs",
-							"description": "The application arguments to pass to the Stasis application",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters"
-						},
-						{
-							"code": 404,
-							"reason": "Channel not found"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"Dialed": {
-			"id": "Dialed",
-			"description": "Dialed channel information.",
-			"properties": {}
-		},
-		"DialplanCEP": {
-			"id": "DialplanCEP",
-			"description": "Dialplan location (context/extension/priority)",
-			"properties": {
-				"context": {
-					"required": true,
-					"type": "string",
-					"description": "Context in the dialplan"
-				},
-				"exten": {
-					"required": true,
-					"type": "string",
-					"description": "Extension in the dialplan"
-				},
-				"priority": {
-					"required": true,
-					"type": "long",
-					"description": "Priority in the dialplan"
-				}
-			}
-		},
-		"CallerID": {
-			"id": "CallerID",
-			"description": "Caller identification",
-			"properties": {
-				"name": {
-					"required": true,
-					"type": "string"
-				},
-				"number": {
-					"required": true,
-					"type": "string"
-				}
-			}
-		},
-		"Channel": {
-			"id": "Channel",
-			"description": "A specific communication connection between Asterisk and an Endpoint.",
-			"properties": {
-				"id": {
-					"required": true,
-					"type": "string",
-					"description": "Unique identifier of the channel.\n\nThis is the same as the Uniqueid field in AMI."
-				},
-				"name": {
-					"required": true,
-					"type": "string",
-					"description": "Name of the channel (i.e. SIP/foo-0000a7e3)"
-				},
-				"state": {
-					"required": true,
-					"type": "string",
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"Down",
-							"Rsrved",
-							"OffHook",
-							"Dialing",
-							"Ring",
-							"Ringing",
-							"Up",
-							"Busy",
-							"Dialing Offhook",
-							"Pre-ring",
-							"Unknown"
-						]
-					}
-				},
-				"caller": {
-					"required": true,
-					"type": "CallerID"
-				},
-				"connected": {
-					"required": true,
-					"type": "CallerID"
-				},
-				"accountcode": {
-					"required": true,
-					"type": "string"
-				},
-				"dialplan": {
-					"required": true,
-					"type": "DialplanCEP",
-					"description": "Current location in the dialplan"
-				},
-				"creationtime": {
-					"required": true,
-					"type": "Date",
-					"description": "Timestamp when channel was created"
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/deviceStates.json b/rest-api/api-docs/deviceStates.json
deleted file mode 100644
index 62ecb13..0000000
--- a/rest-api/api-docs/deviceStates.json
+++ /dev/null
@@ -1,151 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "Kevin Harwell <kharwell at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/deviceStates.{format}",
-	"apis": [
-		{
-			"path": "/deviceStates",
-			"description": "Device states",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all ARI controlled device states.",
-					"nickname": "list",
-					"responseClass": "List[DeviceState]"
-				}
-			]
-		},
-		{
-			"path": "/deviceStates/{deviceName}",
-			"description": "Device state",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Retrieve the current state of a device.",
-					"nickname": "get",
-					"responseClass": "DeviceState",
-					"parameters": [
-						{
-							"name": "deviceName",
-							"description": "Name of the device",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					]
-				},
-				{
-					"httpMethod": "PUT",
-					"summary": "Change the state of a device controlled by ARI. (Note - implicitly creates the device state).",
-					"nickname": "update",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "deviceName",
-							"description": "Name of the device",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "deviceState",
-							"description": "Device state value",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string",
-						        "allowableValues": {
-							         "valueType": "LIST",
-							          "values": [
-								          "NOT_INUSE",
-								          "INUSE",
-								          "BUSY",
-								          "INVALID",
-								          "UNAVAILABLE",
-								          "RINGING",
-								          "RINGINUSE",
-								          "ONHOLD"
-								  ]
-						    }
-
-						}
-					],
-				        "errorResponses": [
-						{
-							"code": 404,
-							"reason": "Device name is missing"
-						},
-						{
-							"code": 409,
-							"reason": "Uncontrolled device specified"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Destroy a device-state controlled by ARI.",
-					"nickname": "delete",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "deviceName",
-							"description": "Name of the device",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-				        "errorResponses": [
-						{
-							"code": 404,
-							"reason": "Device name is missing"
-						},
-						{
-							"code": 409,
-							"reason": "Uncontrolled device specified"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"DeviceState": {
-			"id": "DeviceState",
-			"description": "Represents the state of a device.",
-			"properties": {
-				"name": {
-					"type": "string",
-					"description": "Name of the device.",
-					"required": true
-				},
-				"state": {
-					"type": "string",
-					"description": "Device's state",
-					"required": true,
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"UNKNOWN",
-							"NOT_INUSE",
-							"INUSE",
-							"BUSY",
-							"INVALID",
-							"UNAVAILABLE",
-							"RINGING",
-							"RINGINUSE",
-							"ONHOLD"
-						]
-					}
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/endpoints.json b/rest-api/api-docs/endpoints.json
deleted file mode 100644
index 8440d8b..0000000
--- a/rest-api/api-docs/endpoints.json
+++ /dev/null
@@ -1,275 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/endpoints.{format}",
-	"apis": [
-		{
-			"path": "/endpoints",
-			"description": "Asterisk endpoints",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all endpoints.",
-					"nickname": "list",
-					"responseClass": "List[Endpoint]"
-				}
-			]
-		},
-		{
-			"path": "/endpoints/sendMessage",
-			"description": "Send a message to some technology URI or endpoint.",
-			"operations": [
-				{
-					"httpMethod": "PUT",
-					"summary": "Send a message to some technology URI or endpoint.",
-					"nickname": "sendMessage",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "to",
-							"description": "The endpoint resource or technology specific URI to send the message to. Valid resources are sip, pjsip, and xmpp.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "from",
-							"description": "The endpoint resource or technology specific identity to send this message from. Valid resources are sip, pjsip, and xmpp.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "body",
-							"description": "The body of the message",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "variables",
-							"descriptioni": "The \"variables\" key in the body object holds technology specific key/value pairs to append to the message. These can be interpreted and used by the various resource types; for example, pjsip and sip resource types will add the key/value pairs as SIP headers,",
-							"paramType": "body",
-							"required": false,
-							"dataType": "containers",
-							"allowMultiple": false
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Endpoint not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/endpoints/{tech}",
-			"description": "Asterisk endpoints",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List available endoints for a given endpoint technology.",
-					"nickname": "listByTech",
-					"responseClass": "List[Endpoint]",
-					"parameters": [
-						{
-							"name": "tech",
-							"description": "Technology of the endpoints (sip,iax2,...)",
-							"paramType": "path",
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Endpoints not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/endpoints/{tech}/{resource}",
-			"description": "Single endpoint",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Details for an endpoint.",
-					"nickname": "get",
-					"responseClass": "Endpoint",
-					"parameters": [
-						{
-							"name": "tech",
-							"description": "Technology of the endpoint",
-							"paramType": "path",
-							"dataType": "string"
-						},
-						{
-							"name": "resource",
-							"description": "ID of the endpoint",
-							"paramType": "path",
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters for sending a message."
-						},
-						{
-							"code": 404,
-							"reason": "Endpoints not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/endpoints/{tech}/{resource}/sendMessage",
-			"description": "Send a message to some endpoint in a technology.",
-			"operations": [
-				{
-					"httpMethod": "PUT",
-					"summary": "Send a message to some endpoint in a technology.",
-					"nickname": "sendMessageToEndpoint",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "tech",
-							"description": "Technology of the endpoint",
-							"paramType": "path",
-							"dataType": "string"
-						},
-						{
-							"name": "resource",
-							"description": "ID of the endpoint",
-							"paramType": "path",
-							"dataType": "string"
-						},
-						{
-							"name": "from",
-							"description": "The endpoint resource or technology specific identity to send this message from. Valid resources are sip, pjsip, and xmpp.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "body",
-							"description": "The body of the message",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "variables",
-							"descriptioni": "The \"variables\" key in the body object holds technology specific key/value pairs to append to the message. These can be interpreted and used by the various resource types; for example, pjsip and sip resource types will add the key/value pairs as SIP headers,",
-							"paramType": "body",
-							"required": false,
-							"dataType": "containers",
-							"allowMultiple": false
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "Invalid parameters for sending a message."
-						},
-						{
-							"code": 404,
-							"reason": "Endpoint not found"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"Endpoint": {
-			"id": "Endpoint",
-			"description": "An external device that may offer/accept calls to/from Asterisk.\n\nUnlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.",
-			"properties": {
-				"technology": {
-					"type": "string",
-					"description": "Technology of the endpoint",
-					"required": true
-				},
-				"resource": {
-					"type": "string",
-					"description": "Identifier of the endpoint, specific to the given technology.",
-					"required": true
-				},
-				"state": {
-					"type": "string",
-					"description": "Endpoint's state",
-					"required": false,
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"unknown",
-							"offline",
-							"online"
-						]
-					}
-				},
-				"channel_ids": {
-					"type": "List[string]",
-					"description": "Id's of channels associated with this endpoint",
-					"required": true
-				}
-			}
-		},
-		"TextMessageVariable": {
-			"id": "TextMessageVariable",
-			"description": "A key/value pair variable in a text message.",
-			"properties": {
-				"key": {
-					"type": "string",
-					"description": "A unique key identifying the variable.",
-					"required": true
-				},
-				"value": {
-					"type": "string",
-					"description": "The value of the variable.",
-					"required": true
-				}
-			}
-		},
-		"TextMessage": {
-			"id": "TextMessage",
-			"description": "A text message.",
-			"properties": {
-				"from": {
-					"type": "string",
-					"description": "A technology specific URI specifying the source of the message. For sip and pjsip technologies, any SIP URI can be specified. For xmpp, the URI must correspond to the client connection being used to send the message.",
-					"required": true
-				},
-				"to": {
-					"type": "string",
-					"description": "A technology specific URI specifying the destination of the message. Valid technologies include sip, pjsip, and xmp. The destination of a message should be an endpoint.",
-					"required": true
-				},
-				"body": {
-					"type": "string",
-					"description": "The text of the message.",
-					"required": true
-				},
-				"variables": {
-					"type": "List[TextMessageVariable]",
-					"description": "Technology specific key/value pairs associated with the message.",
-					"required": false
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json
deleted file mode 100644
index 9c24dbd..0000000
--- a/rest-api/api-docs/events.json
+++ /dev/null
@@ -1,729 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.2",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/events.{format}",
-	"apis": [
-		{
-			"path": "/events",
-			"description": "Events from Asterisk to applications",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"upgrade": "websocket",
-					"websocketProtocol": "ari",
-					"summary": "WebSocket connection for events.",
-					"nickname": "eventWebsocket",
-					"responseClass": "Message",
-					"parameters": [
-						{
-							"name": "app",
-							"description": "Applications to subscribe to.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": true,
-							"dataType": "string"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/events/user/{eventName}",
-			"description": "Stasis application user events",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Generate a user event.",
-					"nickname": "userEvent",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "eventName",
-							"description": "Event name",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "application",
-							"description": "The name of the application that will receive this event",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "source",
-							"description": "URI for event source (channel:{channelId}, bridge:{bridgeId}, endpoint:{tech}/{resource}, deviceState:{deviceName}",
-							"paramType": "query",
-							"required": false,
-							"allowMultiple": true,
-							"dataType": "string"
-						},
-						{
-							"name": "variables",
-							"description": "The \"variables\" key in the body object holds custom key/value pairs to add to the user event. Ex. { \"variables\": { \"key\": \"value\" } }",
-							"paramType": "body",
-							"required": false,
-							"allowMultiple": false,
-							"dataType": "containers"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Application does not exist."
-						},
-						{
-							"code": 422,
-							"reason": "Event source not found."
-						},
-						{
-							"code": 400,
-							"reason": "Invalid even tsource URI or userevent data."
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"Message": {
-			"id": "Message",
-			"description": "Base type for errors and events",
-			"discriminator": "type",
-			"properties": {
-				"type": {
-					"type": "string",
-					"required": true,
-					"description": "Indicates the type of this message."
-				}
-			},
-			"subTypes": [
-				"MissingParams",
-				"Event"
-			]
-		},
-		"MissingParams": {
-			"id": "MissingParams",
-			"description": "Error event sent when required params are missing.",
-			"properties": {
-				"params": {
-					"required": true,
-					"type": "List[string]",
-					"description": "A list of the missing parameters"
-				}
-			}
-		},
-		"Event": {
-			"id": "Event",
-			"description": "Base type for asynchronous events from Asterisk.",
-			"properties": {
-				"application": {
-					"type": "string",
-					"description": "Name of the application receiving the event.",
-					"required": true
-				},
-				"timestamp": {
-					"type": "Date",
-					"description": "Time at which this event was created.",
-					"required": false
-				}
-			},
-			"subTypes": [
-				"DeviceStateChanged",
-				"PlaybackStarted",
-				"PlaybackFinished",
-				"RecordingStarted",
-				"RecordingFinished",
-				"RecordingFailed",
-				"ApplicationReplaced",
-				"BridgeCreated",
-				"BridgeDestroyed",
-				"BridgeMerged",
-				"BridgeBlindTransfer",
-				"BridgeAttendedTransfer",
-				"ChannelCreated",
-				"ChannelDestroyed",
-				"ChannelEnteredBridge",
-				"ChannelLeftBridge",
-				"ChannelStateChange",
-				"ChannelDtmfReceived",
-				"ChannelDialplan",
-				"ChannelCallerId",
-				"ChannelUserevent",
-				"ChannelHangupRequest",
-				"ChannelVarset",
-				"ChannelTalkingStarted",
-				"ChannelTalkingFinished",
-				"EndpointStateChange",
-				"Dial",
-				"StasisEnd",
-				"StasisStart",
-				"TextMessageReceived",
-				"ChannelConnectedLine"
-			]
-		},
-		"DeviceStateChanged": {
-			"id": "DeviceStateChanged",
-			"description": "Notification that a device state has changed.",
-			"properties": {
-				"device_state": {
-					"type": "DeviceState",
-					"description": "Device state object",
-					"required": true
-				}
-			}
-		},
-		"PlaybackStarted": {
-			"id": "PlaybackStarted",
-			"description": "Event showing the start of a media playback operation.",
-			"properties": {
-				"playback": {
-					"type": "Playback",
-					"description": "Playback control object",
-					"required": true
-				}
-			}
-		},
-		"PlaybackFinished": {
-			"id": "PlaybackFinished",
-			"description": "Event showing the completion of a media playback operation.",
-			"properties": {
-				"playback": {
-					"type": "Playback",
-					"description": "Playback control object",
-					"required": true
-				}
-			}
-		},
-		"RecordingStarted": {
-			"id": "RecordingStarted",
-			"description": "Event showing the start of a recording operation.",
-			"properties": {
-				"recording": {
-					"type": "LiveRecording",
-					"description": "Recording control object",
-					"required": true
-				}
-			}
-		},
-		"RecordingFinished": {
-			"id": "RecordingFinished",
-			"description": "Event showing the completion of a recording operation.",
-			"properties": {
-				"recording": {
-					"type": "LiveRecording",
-					"description": "Recording control object",
-					"required": true
-				}
-			}
-		},
-		"RecordingFailed": {
-			"id": "RecordingFailed",
-			"description": "Event showing failure of a recording operation.",
-			"properties": {
-				"recording": {
-					"type": "LiveRecording",
-					"description": "Recording control object",
-					"required": true
-				}
-			}
-		},
-		"ApplicationReplaced": {
-			"id": "ApplicationReplaced",
-			"description": "Notification that another WebSocket has taken over for an application.\n\nAn application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.",
-			"properties": {}
-		},
-		"BridgeCreated": {
-			"id": "BridgeCreated",
-			"description": "Notification that a bridge has been created.",
-			"properties": {
-				"bridge": {
-					"required": true,
-					"type": "Bridge"
-				}
-			}
-		},
-		"BridgeDestroyed": {
-			"id": "BridgeDestroyed",
-			"description": "Notification that a bridge has been destroyed.",
-			"properties": {
-				"bridge": {
-					"required": true,
-					"type": "Bridge"
-				}
-			}
-		},
-		"BridgeMerged": {
-			"id": "BridgeMerged",
-			"description": "Notification that one bridge has merged into another.",
-			"properties": {
-				"bridge": {
-					"required": true,
-					"type": "Bridge"
-				},
-				"bridge_from": {
-					"required": true,
-					"type": "Bridge"
-				}
-			}
-		},
-		"BridgeBlindTransfer": {
-			"id": "BridgeBlindTransfer",
-			"description": "Notification that a blind transfer has occurred.",
-			"properties": {
-				"channel": {
-					"description": "The channel performing the blind transfer",
-					"required": true,
-					"type": "Channel"
-				},
-				"replace_channel": {
-					"description": "The channel that is replacing transferer when the transferee(s) can not be transferred directly",
-					"required": false,
-					"type": "Channel"
-				},
-				"transferee": {
-					"description": "The channel that is being transferred",
-					"required": false,
-					"type": "Channel"
-				},
-				"exten": {
-					"description": "The extension transferred to",
-					"required": true,
-					"type": "string"
-				},
-				"context": {
-					"description": "The context transferred to",
-					"required": true,
-					"type": "string"
-				},
-				"result": {
-					"description": "The result of the transfer attempt",
-					"required": true,
-					"type": "string"
-				},
-				"is_external": {
-					"description": "Whether the transfer was externally initiated or not",
-					"required": true,
-					"type": "boolean"
-				},
-				"bridge": {
-					"description": "The bridge being transferred",
-					"type": "Bridge"
-				}
-			}
-		},
-		"BridgeAttendedTransfer": {
-			"id": "BridgeAttendedTransfer",
-			"description": "Notification that an attended transfer has occurred.",
-			"properties": {
-				"transferer_first_leg": {
-					"description": "First leg of the transferer",
-					"required": true,
-					"type": "Channel"
-				},
-				"transferer_second_leg": {
-					"description": "Second leg of the transferer",
-					"required": true,
-					"type": "Channel"
-				},
-				"replace_channel": {
-					"description": "The channel that is replacing transferer_first_leg in the swap",
-					"required": false,
-					"type": "Channel"
-				},
-				"transferee": {
-					"description": "The channel that is being transferred",
-					"required": false,
-					"type": "Channel"
-				},
-				"transfer_target": {
-					"description": "The channel that is being transferred to",
-					"required": false,
-					"type": "Channel"
-				},
-				"result": {
-					"description": "The result of the transfer attempt",
-					"required": true,
-					"type": "string"
-				},
-				"is_external": {
-					"description": "Whether the transfer was externally initiated or not",
-					"required": true,
-					"type": "boolean"
-				},
-				"transferer_first_leg_bridge": {
-					"description": "Bridge the transferer first leg is in",
-					"type": "Bridge"
-				},
-				"transferer_second_leg_bridge": {
-					"description": "Bridge the transferer second leg is in",
-					"type": "Bridge"
-				},
-				"destination_type": {
-					"description": "How the transfer was accomplished",
-					"required": true,
-					"type": "string"
-				},
-				"destination_bridge": {
-					"description": "Bridge that survived the merge result",
-					"type": "string"
-				},
-				"destination_application": {
-					"description": "Application that has been transferred into",
-					"type": "string"
-				},
-				"destination_link_first_leg": {
-					"description": "First leg of a link transfer result",
-					"type": "Channel"
-				},
-				"destination_link_second_leg": {
-					"description": "Second leg of a link transfer result",
-					"type": "Channel"
-				},
-				"destination_threeway_channel": {
-					"description": "Transferer channel that survived the threeway result",
-					"type": "Channel"
-				},
-				"destination_threeway_bridge": {
-					"description": "Bridge that survived the threeway result",
-					"type": "Bridge"
-				}
-			}
-		},
-		"ChannelCreated": {
-			"id": "ChannelCreated",
-			"description": "Notification that a channel has been created.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				}
-			}
-		},
-		"ChannelDestroyed": {
-			"id": "ChannelDestroyed",
-			"description": "Notification that a channel has been destroyed.",
-			"properties": {
-				"cause": {
-					"required": true,
-					"description": "Integer representation of the cause of the hangup",
-					"type": "int"
-				},
-				"cause_txt": {
-					"required": true,
-					"description": "Text representation of the cause of the hangup",
-					"type": "string"
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				}
-			}
-		},
-		"ChannelEnteredBridge": {
-			"id": "ChannelEnteredBridge",
-			"description": "Notification that a channel has entered a bridge.",
-			"properties": {
-				"bridge": {
-					"required": true,
-					"type": "Bridge"
-				},
-				"channel": {
-					"type": "Channel"
-				}
-			}
-		},
-		"ChannelLeftBridge": {
-			"id": "ChannelLeftBridge",
-			"description": "Notification that a channel has left a bridge.",
-			"properties": {
-				"bridge": {
-					"required": true,
-					"type": "Bridge"
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				}
-			}
-		},
-		"ChannelStateChange": {
-			"id": "ChannelStateChange",
-			"description": "Notification of a channel's state change.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				}
-			}
-		},
-		"ChannelDtmfReceived": {
-			"id": "ChannelDtmfReceived",
-			"description": "DTMF received on a channel.\n\nThis event is sent when the DTMF ends. There is no notification about the start of DTMF",
-			"properties": {
-				"digit": {
-					"required": true,
-					"type": "string",
-					"description": "DTMF digit received (0-9, A-E, # or *)"
-				},
-				"duration_ms": {
-					"required": true,
-					"type": "int",
-					"description": "Number of milliseconds DTMF was received"
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel on which DTMF was received"
-				}
-			}
-		},
-		"ChannelDialplan": {
-			"id": "ChannelDialplan",
-			"description": "Channel changed location in the dialplan.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel that changed dialplan location."
-				},
-				"dialplan_app": {
-					"required": true,
-					"type": "string",
-					"description": "The application about to be executed."
-				},
-				"dialplan_app_data": {
-					"required": true,
-					"type": "string",
-					"description": "The data to be passed to the application."
-				}
-			}
-		},
-		"ChannelCallerId": {
-			"id": "ChannelCallerId",
-			"description": "Channel changed Caller ID.",
-			"properties": {
-				"caller_presentation": {
-					"required": true,
-					"type": "int",
-					"description": "The integer representation of the Caller Presentation value."
-				},
-				"caller_presentation_txt": {
-					"required": true,
-					"type": "string",
-					"description": "The text representation of the Caller Presentation value."
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel that changed Caller ID."
-				}
-			}
-		},
-		"ChannelUserevent": {
-			"id": "ChannelUserevent",
-			"description": "User-generated event with additional user-defined fields in the object.",
-			"properties": {
-				"eventname": {
-					"required": true,
-					"type": "string",
-					"description": "The name of the user event."
-				},
-				"channel": {
-					"required": false,
-					"type": "Channel",
-					"description": "A channel that is signaled with the user event."
-				},
-				"bridge": {
-					"required": false,
-					"type": "Bridge",
-					"description": "A bridge that is signaled with the user event."
-				},
-				"endpoint": {
-					"required": false,
-					"type": "Endpoint",
-					"description": "A endpoint that is signaled with the user event."
-				},
-				"userevent": {
-					"required": true,
-					"type": "object",
-					"description": "Custom Userevent data"
-				}
-			}
-		},
-		"ChannelHangupRequest": {
-			"id": "ChannelHangupRequest",
-			"description": "A hangup was requested on the channel.",
-			"properties": {
-				"cause": {
-					"type": "int",
-					"description": "Integer representation of the cause of the hangup."
-				},
-				"soft": {
-					"type": "boolean",
-					"description": "Whether the hangup request was a soft hangup request."
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel on which the hangup was requested."
-				}
-			}
-		},
-		"ChannelVarset": {
-			"id": "ChannelVarset",
-			"description": "Channel variable changed.",
-			"properties": {
-				"variable": {
-					"required": true,
-					"type": "string",
-					"description": "The variable that changed."
-				},
-				"value": {
-					"required": true,
-					"type": "string",
-					"description": "The new value of the variable."
-				},
-				"channel": {
-					"required": false,
-					"type": "Channel",
-					"description": "The channel on which the variable was set.\n\nIf missing, the variable is a global variable."
-				}
-			}
-		},
-		"ChannelTalkingStarted": {
-			"id": "ChannelTalkingStarted",
-			"description": "Talking was detected on the channel.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel on which talking started."
-				}
-			}
-		},
-		"ChannelTalkingFinished": {
-			"id": "ChannelTalkingFinished",
-			"description": "Talking is no longer detected on the channel.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel on which talking completed."
-				},
-				"duration": {
-					"required": true,
-					"type": "int",
-					"description": "The length of time, in milliseconds, that talking was detected on the channel"
-				}
-			}
-		},
-		"EndpointStateChange": {
-			"id": "EndpointStateChange",
-			"description": "Endpoint state changed.",
-			"properties": {
-				"endpoint": {
-					"required": true,
-					"type": "Endpoint"
-				}
-			}
-		},
-		"Dial": {
-			"id": "Dial",
-			"description": "Dialing state has changed.",
-			"properties": {
-				"caller": {
-					"required": false,
-					"type": "Channel",
-					"description": "The calling channel."
-				},
-				"peer": {
-					"required": true,
-					"type": "Channel",
-					"description": "The dialed channel."
-				},
-				"forward": {
-					"required": false,
-					"type": "string",
-					"description": "Forwarding target requested by the original dialed channel."
-				},
-				"forwarded": {
-					"required": false,
-					"type": "Channel",
-					"description": "Channel that the caller has been forwarded to."
-				},
-				"dialstring": {
-					"required": false,
-					"type": "string",
-					"description": "The dial string for calling the peer channel."
-				},
-				"dialstatus": {
-					"required": true,
-					"type": "string",
-					"description": "Current status of the dialing attempt to the peer."
-				}
-			}
-		},
-		"StasisEnd": {
-			"id": "StasisEnd",
-			"description": "Notification that a channel has left a Stasis application.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				}
-			}
-		},
-		"StasisStart": {
-			"id": "StasisStart",
-			"description": "Notification that a channel has entered a Stasis application.",
-			"properties": {
-				"args": {
-					"required": true,
-					"type": "List[string]",
-					"description": "Arguments to the application"
-				},
-				"channel": {
-					"required": true,
-					"type": "Channel"
-				},
-				"replace_channel": {
-					"required": false,
-					"type": "Channel"
-				}
-			}
-		},
-		"TextMessageReceived": {
-			"id": "TextMessageReceived",
-			"description": "A text message was received from an endpoint.",
-			"properties": {
-				"message": {
-					"required": true,
-					"type": "TextMessage"
-				},
-				"endpoint": {
-					"required": false,
-					"type": "Endpoint"
-				}
-			}
-		},
-		"ChannelConnectedLine": {
-			"id": "ChannelConnectedLine",
-			"description": "Channel changed Connected Line.",
-			"properties": {
-				"channel": {
-					"required": true,
-					"type": "Channel",
-					"description": "The channel whose connected line has changed."
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/mailboxes.json b/rest-api/api-docs/mailboxes.json
deleted file mode 100644
index b348106..0000000
--- a/rest-api/api-docs/mailboxes.json
+++ /dev/null
@@ -1,134 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2013, Digium, Inc.",
-	"_author": "Jonathan Rose <jrose at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/mailboxes.{format}",
-	"apis": [
-		{
-			"path": "/mailboxes",
-			"description": "Mailboxes",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all mailboxes.",
-					"nickname": "list",
-					"responseClass": "List[Mailbox]"
-				}
-			]
-		},
-		{
-			"path": "/mailboxes/{mailboxName}",
-			"description": "Mailbox state",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Retrieve the current state of a mailbox.",
-					"nickname": "get",
-					"responseClass": "Mailbox",
-					"parameters": [
-						{
-							"name": "mailboxName",
-							"description": "Name of the mailbox",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-						"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Mailbox not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "PUT",
-					"summary": "Change the state of a mailbox. (Note - implicitly creates the mailbox).",
-					"nickname": "update",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "mailboxName",
-							"description": "Name of the mailbox",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "oldMessages",
-							"description": "Count of old messages in the mailbox",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "int"
-						},
-						{
-							"name": "newMessages",
-							"description": "Count of new messages in the mailbox",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "int"
-						}
-					],
-				        "errorResponses": [
-						{
-							"code": 404,
-							"reason": "Mailbox not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Destroy a mailbox.",
-					"nickname": "delete",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "mailboxName",
-							"description": "Name of the mailbox",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-				        "errorResponses": [
-						{
-							"code": 404,
-							"reason": "Mailbox not found"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"Mailbox": {
-			"id": "Mailbox",
-			"description": "Represents the state of a mailbox.",
-			"properties": {
-				"name": {
-					"type": "string",
-					"description": "Name of the mailbox.",
-					"required": true
-				},
-				"old_messages": {
-					"type": "int",
-					"description": "Count of old messages in the mailbox.",
-					"required": true
-				},
-				"new_messages": {
-					"type": "int",
-					"description": "Count of new messages in the mailbox.",
-					"required": true
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/playbacks.json b/rest-api/api-docs/playbacks.json
deleted file mode 100644
index 98b511a..0000000
--- a/rest-api/api-docs/playbacks.json
+++ /dev/null
@@ -1,155 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/playbacks.{format}",
-	"apis": [
-		{
-			"path": "/playbacks/{playbackId}",
-			"description": "Control object for a playback operation.",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get a playback's details.",
-					"nickname": "get",
-					"responseClass": "Playback",
-					"parameters": [
-						{
-							"name": "playbackId",
-							"description": "Playback's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "The playback cannot be found"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop a playback.",
-					"nickname": "stop",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "playbackId",
-							"description": "Playback's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "The playback cannot be found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/playbacks/{playbackId}/control",
-			"description": "Control object for a playback operation.",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Control a playback.",
-					"nickname": "control",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "playbackId",
-							"description": "Playback's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "operation",
-							"description": "Operation to perform on the playback.",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string",
-							"allowableValues": {
-								"valueType": "LIST",
-								"values": [
-									"restart",
-									"pause",
-									"unpause",
-									"reverse",
-									"forward"
-								]
-							}
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 400,
-							"reason": "The provided operation parameter was invalid"
-						},
-						{
-							"code": 404,
-							"reason": "The playback cannot be found"
-						},
-						{
-							"code": 409,
-							"reason": "The operation cannot be performed in the playback's current state"
-						}
-]
-				}
-			]
-		}
-	],
-	"models": {
-		"Playback": {
-			"id": "Playback",
-			"description": "Object representing the playback of media to a channel",
-			"properties": {
-				"id": {
-					"type": "string",
-					"description": "ID for this playback operation",
-					"required": true
-				},
-				"media_uri": {
-					"type": "string",
-					"description": "URI for the media to play back.",
-					"required": true
-				},
-				"target_uri": {
-					"type": "string",
-					"description": "URI for the channel or bridge to play the media on",
-					"required": true
-				},
-				"language": {
-					"type": "string",
-					"description": "For media types that support multiple languages, the language requested for playback."
-				},
-				"state": {
-					"type": "string",
-					"description": "Current state of the playback operation.",
-					"required": true,
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"queued",
-							"playing",
-							"complete"
-						]
-					}
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/recordings.json b/rest-api/api-docs/recordings.json
deleted file mode 100644
index a4a096f..0000000
--- a/rest-api/api-docs/recordings.json
+++ /dev/null
@@ -1,378 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/recordings.{format}",
-	"apis": [
-		{
-			"path": "/recordings/stored",
-			"description": "Recordings",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List recordings that are complete.",
-					"nickname": "listStored",
-					"responseClass": "List[StoredRecording]"
-				}
-			]
-		},
-		{
-			"path": "/recordings/stored/{recordingName}",
-			"description": "Individual recording",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get a stored recording's details.",
-					"nickname": "getStored",
-					"responseClass": "StoredRecording",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Delete a stored recording.",
-					"nickname": "deleteStored",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/recordings/stored/{recordingName}/copy",
-			"description": "Copy an individual recording",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Copy a stored recording.",
-					"nickname": "copyStored",
-					"responseClass": "StoredRecording",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording to copy",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						},
-						{
-							"name": "destinationRecordingName",
-							"description": "The destination name of the recording",
-							"paramType": "query",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						},
-						{
-							"code": 409,
-							"reason": "A recording with the same name already exists on the system"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/recordings/live/{recordingName}",
-			"description": "A recording that is in progress",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List live recordings.",
-					"nickname": "getLive",
-					"responseClass": "LiveRecording",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Stop a live recording and discard it.",
-					"nickname": "cancel",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/recordings/live/{recordingName}/stop",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Stop a live recording and store it.",
-					"nickname": "stop",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/recordings/live/{recordingName}/pause",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Pause a live recording.",
-					"notes": "Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused. Paused time is not included in the accounting for maxDurationSeconds.",
-					"nickname": "pause",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						},
-						{
-							"code": 409,
-							"reason": "Recording not in session"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Unpause a live recording.",
-					"nickname": "unpause",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						},
-						{
-							"code": 409,
-							"reason": "Recording not in session"
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/recordings/live/{recordingName}/mute",
-			"operations": [
-				{
-					"httpMethod": "POST",
-					"summary": "Mute a live recording.",
-					"notes": "Muting a recording suspends silence detection, which will be restarted when the recording is unmuted.",
-					"nickname": "mute",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						},
-						{
-							"code": 409,
-							"reason": "Recording not in session"
-						}
-					]
-				},
-				{
-					"httpMethod": "DELETE",
-					"summary": "Unmute a live recording.",
-					"nickname": "unmute",
-					"responseClass": "void",
-					"parameters": [
-						{
-							"name": "recordingName",
-							"description": "The name of the recording",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					],
-					"errorResponses": [
-						{
-							"code": 404,
-							"reason": "Recording not found"
-						},
-						{
-							"code": 409,
-							"reason": "Recording not in session"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"StoredRecording": {
-			"id": "StoredRecording",
-			"description": "A past recording that may be played back.",
-			"properties": {
-				"name": {
-					"required": true,
-					"type": "string"
-				},
-				"format": {
-					"required": true,
-					"type": "string"
-				}
-			}
-		},
-		"LiveRecording": {
-			"id": "LiveRecording",
-			"description": "A recording that is in progress",
-			"properties": {
-				"name": {
-					"required": true,
-					"type": "string",
-					"description": "Base name for the recording"
-				},
-				"format": {
-					"required": true,
-					"type": "string",
-					"description": "Recording format (wav, gsm, etc.)"
-				},
-				"target_uri": {
-					"required": true,
-					"type": "string",
-					"description": "URI for the channel or bridge being recorded"
-				},
-				"state": {
-					"required": true,
-					"type": "string",
-					"allowableValues": {
-						"valueType": "LIST",
-						"values": [
-							"queued",
-							"recording",
-							"paused",
-							"done",
-							"failed",
-							"canceled"
-						]
-					}
-				},
-				"duration": {
-					"required": false,
-					"type": "int",
-					"description": "Duration in seconds of the recording"
-				},
-				"talking_duration": {
-					"required": false,
-					"type": "int",
-					"description": "Duration of talking, in seconds, detected in the recording. This is only available if the recording was initiated with a non-zero maxSilenceSeconds."
-				},
-				"silence_duration": {
-					"required": false,
-					"type": "int",
-					"description": "Duration of silence, in seconds, detected in the recording. This is only available if the recording was initiated with a non-zero maxSilenceSeconds."
-				},
-				"cause": {
-					"required": false,
-					"type": "string",
-					"description": "Cause for recording failure if failed"
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/api-docs/sounds.json b/rest-api/api-docs/sounds.json
deleted file mode 100644
index 5ed6de7..0000000
--- a/rest-api/api-docs/sounds.json
+++ /dev/null
@@ -1,99 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"resourcePath": "/api-docs/sounds.{format}",
-	"apis": [
-		{
-			"path": "/sounds",
-			"description": "Sounds",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "List all sounds.",
-					"nickname": "list",
-					"responseClass": "List[Sound]",
-					"parameters": [
-						{
-							"name": "lang",
-							"description": "Lookup sound for a specific language.",
-							"paramType": "query",
-							"dataType": "string",
-							"required": false
-						},
-						{
-							"name": "format",
-							"description": "Lookup sound in a specific format.",
-							"paramType": "query",
-							"dataType": "string",
-							"required": false,
-							"__note": "core show translation can show translation paths between formats, along with relative costs. so this could be just installed format, or we could follow that for transcoded formats."
-						}
-					]
-				}
-			]
-		},
-		{
-			"path": "/sounds/{soundId}",
-			"description": "Individual sound",
-			"operations": [
-				{
-					"httpMethod": "GET",
-					"summary": "Get a sound's details.",
-					"nickname": "get",
-					"responseClass": "Sound",
-					"parameters": [
-						{
-							"name": "soundId",
-							"description": "Sound's id",
-							"paramType": "path",
-							"required": true,
-							"allowMultiple": false,
-							"dataType": "string"
-						}
-					]
-				}
-			]
-		}
-	],
-	"models": {
-		"FormatLangPair": {
-			"id": "FormatLangPair",
-			"description": "Identifies the format and language of a sound file",
-			"properties": {
-				"language": {
-					"required": true,
-					"type": "string"
-				},
-				"format": {
-					"required": true,
-					"type": "string"
-				}
-			}
-		},
-		"Sound": {
-			"id": "Sound",
-			"description": "A media file that may be played back.",
-			"properties": {
-				"id": {
-					"required": true,
-					"description": "Sound's identifier.",
-					"type": "string"
-				},
-				"text": {
-					"required": false,
-					"description": "Text description of the sound, usually the words spoken.",
-					"type": "string"
-				},
-				"formats": {
-					"required": true,
-					"description": "The formats and languages in which this sound is available.",
-					"type": "List[FormatLangPair]"
-				}
-			}
-		}
-	}
-}
diff --git a/rest-api/resources.json b/rest-api/resources.json
deleted file mode 100644
index b33baab..0000000
--- a/rest-api/resources.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-	"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
-	"_author": "David M. Lee, II <dlee at digium.com>",
-	"_svn_revision": "$Revision: 429091 $",
-	"apiVersion": "1.6.0",
-	"swaggerVersion": "1.1",
-	"basePath": "http://localhost:8088/ari",
-	"apis": [
-		{
-			"path": "/api-docs/asterisk.{format}",
-			"description": "Asterisk resources"
-		},
-		{
-			"path": "/api-docs/endpoints.{format}",
-			"description": "Endpoint resources"
-		},
-		{
-			"path": "/api-docs/channels.{format}",
-			"description": "Channel resources"
-		},
-		{
-			"path": "/api-docs/bridges.{format}",
-			"description": "Bridge resources"
-		},
-		{
-			"path": "/api-docs/recordings.{format}",
-			"description": "Recording resources"
-		},
-		{
-			"path": "/api-docs/sounds.{format}",
-			"description": "Sound resources"
-		},
-		{
-			"path": "/api-docs/playbacks.{format}",
-			"description": "Playback control resources"
-		},
-		{
-			"path": "/api-docs/deviceStates.{format}",
-			"description": "Device state resources"
-		},
-		{
-			"path": "/api-docs/mailboxes.{format}",
-			"description": "Mailboxes resources"
-		},
-		{
-			"path": "/api-docs/events.{format}",
-			"description": "WebSocket resource"
-		},
-		{
-			"path": "/api-docs/applications.{format}",
-			"description": "Stasis application resources"
-		}
-	]
-}
diff --git a/sounds/Makefile b/sounds/Makefile
index 13a7184..287d98c 100644
--- a/sounds/Makefile
+++ b/sounds/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for sound files
 #
@@ -19,7 +19,7 @@ CMD_PREFIX?=@
 SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds
 SOUNDS_CACHE_DIR?=
 MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh
-CORE_SOUNDS_VERSION:=1.4.26
+CORE_SOUNDS_VERSION:=1.4.27
 EXTRA_SOUNDS_VERSION:=1.4.15
 MOH_VERSION:=2.03
 SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases
@@ -31,6 +31,7 @@ MCS:=$(subst -ES-,-es-,$(MCS))
 MCS:=$(subst -RU-,-ru-,$(MCS))
 MCS:=$(subst -IT-,-it-,$(MCS))
 MCS:=$(subst -JA-,-ja-,$(MCS))
+MCS:=$(subst -SV-,-sv-,$(MCS))
 MCS:=$(subst -WAV,-wav,$(MCS))
 MCS:=$(subst -ULAW,-ulaw,$(MCS))
 MCS:=$(subst -ALAW,-alaw,$(MCS))
@@ -153,6 +154,8 @@ $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,ru,$(CORE_SOUNDS_
 
 $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,ja,$(CORE_SOUNDS_VERSION)))
 
+$(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,sv,$(CORE_SOUNDS_VERSION)))
+
 $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),extra-sounds,en,$(EXTRA_SOUNDS_VERSION)))
 
 $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),extra-sounds,en_GB,$(EXTRA_SOUNDS_VERSION)))
diff --git a/sounds/sounds.xml b/sounds/sounds.xml
index 5934bb3..547be4b 100644
--- a/sounds/sounds.xml
+++ b/sounds/sounds.xml
@@ -216,6 +216,33 @@
 		<member name="CORE-SOUNDS-JA-SIREN14" displayname="Japanese, G.722.1C (Siren14) format">
 			<support_level>core</support_level>
 		</member>
+		<member name="CORE-SOUNDS-SV-WAV" displayname="Swedish, WAV format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-ULAW" displayname="Swedish, mu-Law format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-ALAW" displayname="Swedish, a-Law format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-GSM" displayname="Swedish, GSM format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-G729" displayname="Swedish, G.729 format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-G722" displayname="Swedish, G.722 format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-SLN16" displayname="Swedish, Signed-linear 16kHz format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-SIREN7" displayname="Swedish, G.722.1 (Siren7) format">
+			<support_level>core</support_level>
+		</member>
+		<member name="CORE-SOUNDS-SV-SIREN14" displayname="Swedish, G.722.1C (Siren14) format">
+			<support_level>core</support_level>
+		</member>
 	</category>
 	<category name="MENUSELECT_MOH" displayname="Music On Hold File Packages" positive_output="yes">
 		<member name="MOH-OPSOUND-WAV" displayname="opsound.org Music On Hold Files, WAV format" >
diff --git a/static-http/ajamdemo.html b/static-http/ajamdemo.html
index 37f8a57..607a2cf 100644
--- a/static-http/ajamdemo.html
+++ b/static-http/ajamdemo.html
@@ -1,20 +1,3 @@
-<!--
- Asterisk -- An open source telephony toolkit.
- 
- Copyright (C) 1999 - 2012, Digium, Inc.
- 
- Mark Spencer <markster at digium.com>
- 
- See http://www.asterisk.org for more information about
- the Asterisk project. Please do not directly contact
- any of the maintainers of this project for assistance;
- the project provides a web site, mailing lists and IRC
- channels for your use.
- This program is free software, distributed under the terms of
- the GNU General Public License Version 2. See the LICENSE file
- at the top of the source tree.
--->
-
 <script src="prototype.js"></script>
 <script src="astman.js"></script>
 <link href="astman.css" media="all" rel="Stylesheet" type="text/css" />
diff --git a/static-http/astman.css b/static-http/astman.css
index 28ab343..fbf2b2c 100644
--- a/static-http/astman.css
+++ b/static-http/astman.css
@@ -1,21 +1,3 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2012, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
 .chanlist {
 	border           : 1px solid #1f669b;
 	height			: 150px;
diff --git a/static-http/mantest.html b/static-http/mantest.html
index c0affe2..eebac62 100644
--- a/static-http/mantest.html
+++ b/static-http/mantest.html
@@ -1,19 +1,3 @@
-<!--
- Asterisk -- An open source telephony toolkit.
- 
- Copyright (C) 1999 - 2012, Digium, Inc.
- 
- Mark Spencer <markster at digium.com>
- 
- See http://www.asterisk.org for more information about
- the Asterisk project. Please do not directly contact
- any of the maintainers of this project for assistance;
- the project provides a web site, mailing lists and IRC
- channels for your use.
- This program is free software, distributed under the terms of
- the GNU General Public License Version 2. See the LICENSE file
- at the top of the source tree.
--->
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <head>
@@ -52,8 +36,8 @@
 			color: red;
 		}
 	</style>
-	<title>Asterisk Manager Utility</title>
-	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
+	<title>Manager Utility</title>
+	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
 
 	<script type="text/javascript">
 
diff --git a/tests/Makefile b/tests/Makefile
index 000da6c..4f1a067 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Makefile for test modules
 #
diff --git a/tests/test_abstract_jb.c b/tests/test_abstract_jb.c
index 007cf66..ce25eb8 100644
--- a/tests/test_abstract_jb.c
+++ b/tests/test_abstract_jb.c
@@ -36,14 +36,13 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/test.h"
 #include "asterisk/abstract_jb.h"
 #include "asterisk/frame.h"
-#include "asterisk/format_cache.h"
 
 #define DEFAULT_FRAME_MS 160
 #define DEFAULT_CONFIG_FLAGS 0
@@ -51,12 +50,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 #define DEFAULT_CONFIG_RESYNC_THRESHOLD (DEFAULT_FRAME_MS) * 2
 #define DEFAULT_CONFIG_TARGET_EXTRA -1
 
-/*!
- * \internal
- * \brief Destructor for a jitter buffer
- *
+/*! \internal \brief Destructor for a jitter buffer
  * \param jb The jitter buffer to destroy
- *
  * \note This will destroy all frames still in the jitter buffer
  */
 static void dispose_jitterbuffer(struct ast_jb *jb)
@@ -72,13 +67,20 @@ static void dispose_jitterbuffer(struct ast_jb *jb)
 	jb->jbobj = NULL;
 }
 
-/*!
- * \internal
- * \brief Create a test frame
- *
+/*! \internal \brief Destructor for frames
+ * \param f The frame to destroy
+ */
+static void dispose_frame(struct ast_frame *f)
+{
+	if (!f) {
+		return;
+	}
+	ast_frfree(f);
+}
+
+/*! \internal \brief Create a test frame
  * \param timestamp the time in ms of the frame
  * \param seqno the frame's sequence number
- *
  * \returns a malloc'd frame
  */
 static struct ast_frame *create_test_frame(long timestamp,
@@ -86,7 +88,7 @@ static struct ast_frame *create_test_frame(long timestamp,
 {
 	struct ast_frame f = {0};
 
-	f.subclass.format = ast_format_slin;
+	f.subclass.format.id = AST_FORMAT_SLINEAR;
 	f.frametype = AST_FRAME_VOICE;
 	f.src = "TEST";
 	f.ts = timestamp;
@@ -168,28 +170,19 @@ static struct ast_frame *create_test_frame(long timestamp,
 	(conf)->target_extra = DEFAULT_CONFIG_TARGET_EXTRA; \
 	} while (0)
 
-/*!
- * \internal
- * \brief A container object for the jitter buffers, used for all tests
- */
+/*! \internal \brief A container object for the jitter buffers, used for all tests*/
 static struct ast_jb default_jb = {
 	.impl = NULL,
 	.jbobj = NULL
 };
 
-/*!
- * \internal
- * \brief Construct a test name
- */
+/*! \internal \brief Construct a test name */
 #define TEST_NAME(type_name, specifier) type_name ## _  ## specifier
 
 #define TEST_NAME2(test_name) #test_name
 #define STRINGIFY_TESTNAME(test_name) TEST_NAME2(test_name)
 
-/*!
- * \internal
- * \brief Test nominal construction of a jitter buffer
- *
+/*! \internal \brief Test nominal construction of a jitter buffer
  * \param type_name The enum type of the jitter buffer to create
  * \param literal_type_name The literal name of the type - "fixed" or "adaptive"
  */
@@ -225,10 +218,7 @@ static struct ast_jb default_jb = {
 	return AST_TEST_PASS; \
 }
 
-/*!
- * \internal
- * \brief Test putting the initial frame into a jitter buffer
- *
+/*! \internal \brief Test putting the initial frame into a jitter buffer
  * \param type_name The enum type of the jitter buffer to create
  * \param literal_type_name The literal name of the type - "fixed" or "adaptive"
  */
@@ -236,8 +226,8 @@ static struct ast_jb default_jb = {
 	RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \
 	const struct ast_jb_impl *impl; \
 	struct ast_jb_conf conf; \
-	RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \
-	RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \
+	RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \
+	RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \
 	int res; \
 \
 	switch (cmd) { \
@@ -284,10 +274,7 @@ static struct ast_jb default_jb = {
 	return AST_TEST_PASS; \
 }
 
-/*!
- * \internal
- * \brief Test putting a voice frames into a jitter buffer
- *
+/*! \internal \brief Test putting a voice frames into a jitter buffer
  * \param type_name The enum type of the jitter buffer to create
  * \param literal_type_name The literal name of the type - "fixed" or "adaptive"
  */
@@ -295,8 +282,8 @@ static struct ast_jb default_jb = {
 	RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \
 	const struct ast_jb_impl *impl; \
 	struct ast_jb_conf conf; \
-	RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \
-	RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \
+	RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \
+	RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \
 	int res; \
 	long next; \
 	int i; \
@@ -349,10 +336,7 @@ static struct ast_jb default_jb = {
 	return AST_TEST_PASS; \
 }
 
-/*!
- * \internal
- * \brief Test overflowing the limits of a jitter buffer
- *
+/*! \internal \brief Test overflowing the limits of a jitter buffer
  * \param type_name The enum type of the jitter buffer to create
  * \param literal_type_name The literal name of the type - "fixed" or "adaptive"
  * \param overflow_limit The number of frames at which we expect the buffer to overflow
@@ -361,7 +345,7 @@ static struct ast_jb default_jb = {
 	RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \
 	const struct ast_jb_impl *impl; \
 	struct ast_jb_conf conf; \
-	RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \
+	RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \
 	int res; \
 	int i; \
 \
@@ -417,10 +401,7 @@ static struct ast_jb default_jb = {
 	return AST_TEST_PASS; \
 }
 
-/*!
- * \internal
- * \brief Test putting voice frames into a jitter buffer out of order
- *
+/*! \internal \brief Test putting voice frames into a jitter buffer out of order
  * \param type_name The enum type of the jitter buffer to create
  * \param literal_type_name The literal name of the type - "fixed" or "adaptive"
  * \param synch_limit The synchronization limit for this particular type of jitter buffer
@@ -429,8 +410,8 @@ static struct ast_jb default_jb = {
 	RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \
 	const struct ast_jb_impl *impl; \
 	struct ast_jb_conf conf; \
-	RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \
-	RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \
+	RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \
+	RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \
 	int res; \
 	long next; \
 	int i; \
diff --git a/tests/test_acl.c b/tests/test_acl.c
index e479f42..c7a711f 100644
--- a/tests/test_acl.c
+++ b/tests/test_acl.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370453 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/test.h"
 #include "asterisk/acl.h"
@@ -122,6 +122,22 @@ struct acl {
 #define TACL_A AST_SENSE_ALLOW
 #define TACL_D AST_SENSE_DENY
 
+static int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name, int *err, struct ast_test *test, enum ast_test_result_state *res) 
+{
+	size_t i;
+
+	for (i = 0; i < len; ++i) {
+		if (!(*ha = ast_append_ha(acl[i].access, acl[i].host, *ha, err))) {
+			ast_test_status_update(test, "Failed to add rule %s with access %s to %s\n",
+					       acl[i].host, acl[i].access, acl_name);
+			*res = AST_TEST_FAIL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 AST_TEST_DEFINE(acl)
 {
 	struct acl permitallv4 = { "0.0.0.0/0", "permit" };
@@ -211,21 +227,6 @@ AST_TEST_DEFINE(acl)
 	int err = 0;
 	int i;
 
-	auto int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name);
-	auto int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name) {
-		size_t i;
-
-		for (i = 0; i < len; ++i) {
-			if (!(*ha = ast_append_ha(acl[i].access, acl[i].host, *ha, &err))) {
-				ast_test_status_update(test, "Failed to add rule %s with access %s to %s\n",
-						       acl[i].host, acl[i].access, acl_name);
-				res = AST_TEST_FAIL;
-				return -1;
-			}
-		}
-
-		return 0;
-	}
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -263,31 +264,31 @@ AST_TEST_DEFINE(acl)
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl1, ARRAY_LEN(acl1), &ha1, "ha1") != 0) {
+	if (build_ha(acl1, ARRAY_LEN(acl1), &ha1, "ha1", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl2, ARRAY_LEN(acl2), &ha2, "ha2") != 0) {
+	if (build_ha(acl2, ARRAY_LEN(acl2), &ha2, "ha2", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl3, ARRAY_LEN(acl3), &ha3, "ha3") != 0) {
+	if (build_ha(acl3, ARRAY_LEN(acl3), &ha3, "ha3", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl4, ARRAY_LEN(acl4), &ha4, "ha4") != 0) {
+	if (build_ha(acl4, ARRAY_LEN(acl4), &ha4, "ha4", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl5, ARRAY_LEN(acl5), &ha5, "ha5") != 0) {
+	if (build_ha(acl5, ARRAY_LEN(acl5), &ha5, "ha5", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl6, ARRAY_LEN(acl6), &ha6, "ha6") != 0) {
+	if (build_ha(acl6, ARRAY_LEN(acl6), &ha6, "ha6", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
-	if (build_ha(acl7, ARRAY_LEN(acl7), &ha7, "ha7") != 0) {
+	if (build_ha(acl7, ARRAY_LEN(acl7), &ha7, "ha7", &err, test, &res) != 0) {
 		goto acl_cleanup;
 	}
 
diff --git a/tests/test_amihooks.c b/tests/test_amihooks.c
index cd65a5a..1f10a01 100644
--- a/tests/test_amihooks.c
+++ b/tests/test_amihooks.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 338557 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/cli.h"
diff --git a/tests/test_aoc.c b/tests/test_aoc.c
index 8ec2d93..35387df 100644
--- a/tests/test_aoc.c
+++ b/tests/test_aoc.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/tests/test_app.c b/tests/test_app.c
index 790b5f0..0bb43aa 100644
--- a/tests/test_app.c
+++ b/tests/test_app.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410158 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
@@ -175,25 +175,21 @@ AST_TEST_DEFINE(app_group)
 		"'%s', '%s', '%s', '%s'\n", group1_full, group2_full, category1_full, category2_full);
 
 	if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, 0, "TestChannel1"))) {
+        NULL, NULL, 0, 0, "TestChannel1"))) {
 		goto exit_group_test;
 	}
-	ast_channel_unlock(test_channel1);
 	if (!(test_channel2 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, 0, "TestChannel2"))) {
+        NULL, NULL, 0, 0, "TestChannel2"))) {
 		goto exit_group_test;
 	}
-	ast_channel_unlock(test_channel2);
 	if (!(test_channel3 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, 0, "TestChannel3"))) {
+        NULL, NULL, 0, 0, "TestChannel3"))) {
 		goto exit_group_test;
 	}
-	ast_channel_unlock(test_channel3);
 	if (!(test_channel4 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, 0, "TestChannel4"))) {
+        NULL, NULL, 0, 0, "TestChannel4"))) {
 		goto exit_group_test;
 	}
-	ast_channel_unlock(test_channel4);
 
 	ast_app_group_set_channel(test_channel1, group1_full);
 	ast_app_group_set_channel(test_channel2, group2_full);
@@ -216,10 +212,18 @@ AST_TEST_DEFINE(app_group)
 	}
 
 exit_group_test:
-	ast_hangup(test_channel1);
-	ast_hangup(test_channel2);
-	ast_hangup(test_channel3);
-	ast_hangup(test_channel4);
+	if (test_channel1) {
+		ast_hangup(test_channel1);
+	}
+	if (test_channel2) {
+		ast_hangup(test_channel2);
+	}
+	if (test_channel3) {
+		ast_hangup(test_channel3);
+	}
+	if (test_channel4) {
+		ast_hangup(test_channel4);
+	}
 	return res;
 }
 
diff --git a/tests/test_ari.c b/tests/test_ari.c
deleted file mode 100644
index 5ecf53c..0000000
--- a/tests/test_ari.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test ARI API.
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>res_ari</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403177 $")
-
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/ari.h"
-
-/*!@{*/
-
-/*!
- * \internal
- * The following code defines a simple RESTful API for unit testing. The
- * response encodes the inputs of the invocation. The invocation_count
- * counter is also incremented.
- *
- *  - /foo (GET)
- *  - /foo/bar (GET, POST)
- *  - /foo/{bam} (GET)
- *  - /foo/{bam}/bang (GET, POST, DE1LETE)
- */
-
-static int invocation_count;
-
-/*!
- * \internal
- * Shared code for all handlers
- */
-static void handler(const char *name,
-		    int response_code,
-		    struct ast_variable *get_params,
-		    struct ast_variable *path_vars,
-		    struct ast_variable *headers,
-		    struct ast_ari_response *response)
-{
-	struct ast_json *message = ast_json_pack("{s: s, s: {}, s: {}, s: {}}",
-						 "name", name,
-						 "get_params",
-						 "path_vars",
-						 "headers");
-	struct ast_json *get_params_obj = ast_json_object_get(message, "get_params");
-	struct ast_json *path_vars_obj = ast_json_object_get(message, "path_vars");
-	struct ast_json *headers_obj = ast_json_object_get(message, "headers");
-
-	for (; get_params != NULL; get_params = get_params->next) {
-		ast_json_object_set(get_params_obj, get_params->name, ast_json_string_create(get_params->value));
-	}
-
-	for (; path_vars != NULL; path_vars = path_vars->next) {
-		ast_json_object_set(path_vars_obj, path_vars->name, ast_json_string_create(path_vars->value));
-	}
-
-	for (; headers != NULL; headers = headers->next) {
-		ast_json_object_set(headers_obj, headers->name, ast_json_string_create(headers->value));
-	}
-
-	++invocation_count;
-	response->response_code = response_code;
-	response->message = message;
-}
-
-/*!
- * \internal
- * Macro to reduce the handler definition boiler-plate.
- */
-#define HANDLER(name, response_code)					\
-	static void name(struct ast_tcptls_session_instance *ser,	\
-		struct ast_variable *get_params,			\
-		struct ast_variable *path_vars,				\
-		struct ast_variable *headers,				\
-		struct ast_ari_response *response)			\
-	{								\
-		handler(#name, response_code, get_params, path_vars, headers, response); \
-	}
-
-HANDLER(bang_get, 200)
-HANDLER(bang_post, 200)
-HANDLER(bang_delete, 204)
-HANDLER(bar_get, 200)
-HANDLER(bar_post, 200)
-HANDLER(bam_get, 200)
-HANDLER(foo_get, 200)
-
-static struct stasis_rest_handlers bang = {
-	.path_segment = "bang",
-	.callbacks = {
-		[AST_HTTP_GET] = bang_get,
-		[AST_HTTP_POST] = bang_post,
-		[AST_HTTP_DELETE] = bang_delete,
-	},
-	.num_children = 0
-};
-static struct stasis_rest_handlers bar = {
-	.path_segment = "bar",
-	.callbacks = {
-		[AST_HTTP_GET] = bar_get,
-		[AST_HTTP_POST] = bar_post,
-	},
-	.num_children = 0
-};
-static struct stasis_rest_handlers bam = {
-	.path_segment = "bam",
-	.is_wildcard = 1,
-	.callbacks = {
-		[AST_HTTP_GET] = bam_get,
-	},
-	.num_children = 1,
-	.children = { &bang }
-};
-static struct stasis_rest_handlers test_root = {
-	.path_segment = "foo",
-	.callbacks = {
-		[AST_HTTP_GET] = foo_get,
-	},
-	.num_children = 3,
-	.children = { &bar, &bam, &bang }
-};
-/*!@}*/
-
-/*!
- * \internal
- * \c ast_ari_response constructor.
- */
-static struct ast_ari_response *response_alloc(void)
-{
-	struct ast_ari_response *resp = ast_calloc(1, sizeof(struct ast_ari_response));
-	resp->headers = ast_str_create(24);
-	return resp;
-}
-
-/*!
- * \internal
- * \c ast_ari_response destructor.
- */
-static void response_free(struct ast_ari_response *resp)
-{
-	if (!resp) {
-		return;
-	}
-	ast_free(resp->headers);
-	ast_json_unref(resp->message);
-	ast_free(resp);
-}
-
-/*!
- * \ internal
- * Setup test fixture for invocation tests.
- */
-static void *setup_invocation_test(void) {
-	int r;
-	invocation_count = 0;
-	r = ast_ari_add_handler(&test_root);
-	ast_assert(r == 0);
-	return &invocation_count;
-}
-
-/*!
- * \ internal
- * Tear down test fixture for invocation tests.
- */
-static void tear_down_invocation_test(void *ignore) {
-	if (!ignore) {
-		return;
-	}
-	ast_ari_remove_handler(&test_root);
-}
-
-
-AST_TEST_DEFINE(get_docs)
-{
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	RAII_VAR(struct ast_variable *, headers, NULL, ast_variables_destroy);
-	struct ast_json *basePathJson;
-	const char *basePath;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test simple API get.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	response = response_alloc();
-	headers = ast_variable_new("Host", "stasis.asterisk.org", __FILE__);
-	ast_ari_get_docs("resources.json", headers, response);
-	ast_test_validate(test, 200 == response->response_code);
-
-	/* basePath should be relative to the Host header */
-	basePathJson = ast_json_object_get(response->message, "basePath");
-	ast_test_validate(test, NULL != basePathJson);
-	basePath = ast_json_string_get(basePathJson);
-	ast_test_validate(test, 0 == strcmp("http://stasis.asterisk.org/ari", basePath));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(get_docs_nohost)
-{
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	struct ast_variable *headers = NULL;
-	struct ast_json *basePathJson;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test API get without a Host header";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	response = response_alloc();
-	ast_ari_get_docs("resources.json", headers, response);
-	ast_test_validate(test, 200 == response->response_code);
-
-	/* basePath should be relative to the Host header */
-	basePathJson = ast_json_object_get(response->message, "basePath");
-	ast_test_validate(test, NULL == basePathJson);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(get_docs_notfound)
-{
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test API get for invalid resource";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	response = response_alloc();
-	ast_ari_get_docs("i-am-not-a-resource.json", headers, response);
-	ast_test_validate(test, 404 == response->response_code);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(get_docs_hackerz)
-{
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test API get for a file outside the rest-api path";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	response = response_alloc();
-	ast_ari_get_docs("../../../../sbin/asterisk", headers, response);
-	ast_test_validate(test, 404 == response->response_code);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_get)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test simple GET of an HTTP resource.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	get_params = ast_variable_new("get1", "get-one", __FILE__);
-	ast_assert(get_params != NULL);
-	get_params->next = ast_variable_new("get2", "get-two", __FILE__);
-	ast_assert(get_params->next != NULL);
-
-	headers = ast_variable_new("head1", "head-one", __FILE__);
-	ast_assert(headers != NULL);
-	headers->next = ast_variable_new("head2", "head-two", __FILE__);
-	ast_assert(headers->next != NULL);
-
-	expected = ast_json_pack("{s: s, s: {s: s, s: s}, s: {s: s, s: s}, s: {}}",
-				 "name", "foo_get",
-				 "get_params",
-				 "get1", "get-one",
-				 "get2", "get-two",
-				 "headers",
-				 "head1", "head-one",
-				 "head2", "head-two",
-				 "path_vars");
-
-	ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers, response);
-
-	ast_test_validate(test, 1 == invocation_count);
-	ast_test_validate(test, 200 == response->response_code);
-	ast_test_validate(test, ast_json_equal(expected, response->message));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_wildcard)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test GET of a wildcard resource.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	expected = ast_json_pack("{s: s, s: {}, s: {}, s: {s: s}}",
-				 "name", "bam_get",
-				 "get_params",
-				 "headers",
-				 "path_vars",
-				 "bam", "foshizzle");
-
-	ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers, response);
-
-	ast_test_validate(test, 1 == invocation_count);
-	ast_test_validate(test, 200 == response->response_code);
-	ast_test_validate(test, ast_json_equal(expected, response->message));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_delete)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test DELETE of an HTTP resource.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	expected = ast_json_pack("{s: s, s: {}, s: {}, s: {s: s}}",
-				 "name", "bang_delete",
-				 "get_params",
-				 "headers",
-				 "path_vars",
-				 "bam", "foshizzle");
-
-	ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers, response);
-
-	ast_test_validate(test, 1 == invocation_count);
-	ast_test_validate(test, 204 == response->response_code);
-	ast_test_validate(test, ast_json_equal(expected, response->message));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_post)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test POST of an HTTP resource.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	get_params = ast_variable_new("get1", "get-one", __FILE__);
-	ast_assert(get_params != NULL);
-	get_params->next = ast_variable_new("get2", "get-two", __FILE__);
-	ast_assert(get_params->next != NULL);
-
-	headers = ast_variable_new("head1", "head-one", __FILE__);
-	ast_assert(headers != NULL);
-	headers->next = ast_variable_new("head2", "head-two", __FILE__);
-	ast_assert(headers->next != NULL);
-
-	expected = ast_json_pack("{s: s, s: {s: s, s: s}, s: {s: s, s: s}, s: {}}",
-				 "name", "bar_post",
-				 "get_params",
-				 "get1", "get-one",
-				 "get2", "get-two",
-				 "headers",
-				 "head1", "head-one",
-				 "head2", "head-two",
-				 "path_vars");
-
-	ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers, response);
-
-	ast_test_validate(test, 1 == invocation_count);
-	ast_test_validate(test, 200 == response->response_code);
-	ast_test_validate(test, ast_json_equal(expected, response->message));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_bad_post)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test POST on a resource that doesn't support it.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers, response);
-
-	ast_test_validate(test, 0 == invocation_count);
-	ast_test_validate(test, 405 == response->response_code);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(invoke_not_found)
-{
-	RAII_VAR(void *, fixture, NULL, tear_down_invocation_test);
-	RAII_VAR(struct ast_ari_response *, response, NULL, response_free);
-	struct ast_variable *get_params = NULL;
-	struct ast_variable *headers = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/res/ari/";
-		info->summary = "Test GET on a resource that does not exist.";
-		info->description = "Test ARI binding logic.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	fixture = setup_invocation_test();
-	response = response_alloc();
-	ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers, response);
-
-	ast_test_validate(test, 0 == invocation_count);
-	ast_test_validate(test, 404 == response->response_code);
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(get_docs);
-	AST_TEST_UNREGISTER(get_docs_nohost);
-	AST_TEST_UNREGISTER(get_docs_notfound);
-	AST_TEST_UNREGISTER(get_docs_hackerz);
-	AST_TEST_UNREGISTER(invoke_get);
-	AST_TEST_UNREGISTER(invoke_wildcard);
-	AST_TEST_UNREGISTER(invoke_delete);
-	AST_TEST_UNREGISTER(invoke_post);
-	AST_TEST_UNREGISTER(invoke_bad_post);
-	AST_TEST_UNREGISTER(invoke_not_found);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(get_docs);
-	AST_TEST_REGISTER(get_docs_nohost);
-	AST_TEST_REGISTER(get_docs_notfound);
-	AST_TEST_REGISTER(get_docs_hackerz);
-	AST_TEST_REGISTER(invoke_get);
-	AST_TEST_REGISTER(invoke_wildcard);
-	AST_TEST_REGISTER(invoke_delete);
-	AST_TEST_REGISTER(invoke_post);
-	AST_TEST_REGISTER(invoke_bad_post);
-	AST_TEST_REGISTER(invoke_not_found);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ARI testing",
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_ari",
-	);
diff --git a/tests/test_ari_model.c b/tests/test_ari_model.c
deleted file mode 100644
index a075cff..0000000
--- a/tests/test_ari_model.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Test the native ARI JSON validators.
- *
- * \author David M. Lee, II <dlee at digium.com>
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>res_ari_model</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 399208 $")
-
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "../res/ari/ari_model_validators.h"
-
-#if defined(TEST_FRAMEWORK)
-/*!
- * Wrapper of ast_test_validate_int() so an external function pointer is not used.
- *
- * \note Must do this because using an external function pointer
- * does not play nicely when loading with RTLD_LAZY.
- */
-static int wrap_ast_ari_validate_int(struct ast_json *json)
-{
-	return ast_ari_validate_int(json);
-}
-#endif	/* defined(TEST_FRAMEWORK) */
-
-#if defined(TEST_FRAMEWORK)
-/*!
- * Wrapper of ast_ari_validate_string() so an external function pointer is not used.
- *
- * \note Must do this because using an external function pointer
- * does not play nicely when loading with RTLD_LAZY.
- */
-static int wrap_ast_ari_validate_string(struct ast_json *json)
-{
-	return ast_ari_validate_string(json);
-}
-#endif	/* defined(TEST_FRAMEWORK) */
-
-AST_TEST_DEFINE(validate_byte)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test byte validation";
-		info->description =
-			"Test byte validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_integer_create(-128);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_ari_validate_byte(uut));
-
-	res = ast_json_integer_set(uut, 0);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_byte(uut));
-
-	res = ast_json_integer_set(uut, 255);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_byte(uut));
-
-	res = ast_json_integer_set(uut, -129);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_byte(uut));
-
-	res = ast_json_integer_set(uut, 256);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_byte(uut));
-
-	str = ast_json_string_create("not a byte");
-	ast_test_validate(test, NULL != str);
-	ast_test_validate(test, !ast_ari_validate_byte(str));
-
-	/* Even if the string has an integral value */
-	res = ast_json_string_set(str, "0");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_byte(str));
-
-	ast_test_validate(test, !ast_ari_validate_byte(ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(validate_boolean)
-{
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test byte validation";
-		info->description =
-			"Test byte validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, ast_ari_validate_boolean(ast_json_true()));
-	ast_test_validate(test, ast_ari_validate_boolean(ast_json_false()));
-
-	str = ast_json_string_create("not a bool");
-	ast_test_validate(test, NULL != str);
-	ast_test_validate(test, !ast_ari_validate_boolean(str));
-
-	/* Even if the string has a boolean value */
-	res = ast_json_string_set(str, "true");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_boolean(str));
-
-	/* Even if the string has a boolean text in it */
-	res = ast_json_string_set(str, "true");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_boolean(str));
-
-	ast_test_validate(test, !ast_ari_validate_boolean(ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(validate_int)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test int validation";
-		info->description =
-			"Test int validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_integer_create(-2147483648LL);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_ari_validate_int(uut));
-
-	res = ast_json_integer_set(uut, 0);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_int(uut));
-
-	res = ast_json_integer_set(uut, 2147483647LL);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_int(uut));
-
-	res = ast_json_integer_set(uut, -2147483649LL);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_int(uut));
-
-	res = ast_json_integer_set(uut, 2147483648LL);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_int(uut));
-
-	str = ast_json_string_create("not a int");
-	ast_test_validate(test, NULL != str);
-	ast_test_validate(test, !ast_ari_validate_int(str));
-
-	/* Even if the string has an integral value */
-	res = ast_json_string_set(str, "0");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_int(str));
-
-	ast_test_validate(test, !ast_ari_validate_int(ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(validate_long)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test long validation";
-		info->description =
-			"Test long validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_integer_create(0);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_ari_validate_long(uut));
-
-	str = ast_json_string_create("not a long");
-	ast_test_validate(test, NULL != str);
-	ast_test_validate(test, !ast_ari_validate_long(str));
-
-	/* Even if the string has an integral value */
-	res = ast_json_string_set(str, "0");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_long(str));
-
-	ast_test_validate(test, !ast_ari_validate_long(ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(validate_string)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test string validation";
-		info->description =
-			"Test string validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_string_create("text");
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_ari_validate_string(uut));
-
-	res = ast_json_string_set(uut, "");
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_string(uut));
-
-	ast_test_validate(test, !ast_ari_validate_string(ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(validate_date)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	enum ast_test_result_state test_res;
-	int res;
-	int i;
-	const char *valid_dates[] = {
-		/* Time is optional */
-		"2013-06-17",
-		/* Seconds are optional */
-		"2013-06-17T23:59Z",
-		/* Subseconds are optional */
-		"2013-06-17T23:59:59Z",
-		/* Leap seconds are valid */
-		"2013-06-30T23:59:61Z",
-		/* Subseconds are allowed */
-		"2013-06-17T23:59:59.999999Z",
-		/* Now with -06:00 for the timezone */
-		"2013-06-17T23:59-06:00",
-		"2013-06-17T23:59:59-06:00",
-		"2013-06-30T23:59:61-06:00",
-		"2013-06-17T23:59:59.999999-06:00",
-		/* Again, with +06:30 for the timezone */
-		"2013-06-17T23:59+06:30",
-		"2013-06-17T23:59:59+06:30",
-		"2013-06-30T23:59:61+06:30",
-		"2013-06-17T23:59:59.999999+06:30",
-		/* So the colon in the timezone is optional */
-		"2013-06-17T23:59-0600",
-		"2013-06-17T23:59:59-0600",
-		"2013-06-30T23:59:61-0600",
-		"2013-06-17T23:59:59.999999-0600",
-		/* Sure, why not */
-		"2013-06-17T23:59+0630",
-		"2013-06-17T23:59:59+0630",
-		"2013-06-30T23:59:61+0630",
-		"2013-06-17T23:59:59.999999+0630",
-		"9999-12-31T23:59:61.999999Z",
-		/* In fact, you don't even have to specify minutes */
-		"2013-06-17T23:59-06",
-		"2013-06-17T23:59:59-06",
-		"2013-06-30T23:59:61-06",
-		"2013-06-17T23:59:59.999999-06",
-	};
-
-	/* There are lots of invalid dates that the validator lets through.
-	 * Those would be strings properly formatted as a ridiculous date. Such
-	 * as 0000-00-00, or 9999-19-39. Those are harder to catch with a regex,
-	 * and actually aren't as important. So long as the valid dates pass the
-	 * validator, and poorly formatted dates are rejected, it's fine.
-	 * Catching the occasional ridiculous date is just bonus.
-	 */
-	const char *invalid_dates[] = {
-		"",
-		"Not a date",
-		"2013-06-17T", /* Missing time, but has T */
-		"2013-06-17T23:59:59.Z", /* Missing subsecond, but has dot */
-		"2013-06-17T23:59", /* Missing timezone, but has time */
-		"2013-06-17T23:59:59.999999", /* Missing timezone */
-		"9999-99-31T23:59:61.999999Z", /* Invalid month */
-		"9999-12-99T23:59:61.999999Z", /* Invalid day */
-		"9999-12-31T99:59:61.999999Z", /* Invalid hour */
-		"9999-12-31T23:99:61.999999Z", /* Invalid minute */
-		"9999-12-31T23:59:99.999999Z", /* Invalid second */
-		"2013-06-17T23:59:59.999999-99:00", /* Invalid timezone */
-		"2013-06-17T23:59:59.999999-06:99", /* Invalid timezone */
-		"2013-06-17T23:59:59.999999-06:", /* Invalid timezone */
-		"2013-06-17T23:59:59.999999-06:0", /* Invalid timezone */
-		"2013-06-17T23:59:59.999999-060", /* Invalid timezone */
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test date validation";
-		info->description =
-			"Test date validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_string_create("");
-	ast_test_validate(test, NULL != uut);
-
-	/* Instead of using ast_test_validate, we'll collect the results from
-	 * several test cases, since we have so many */
-	test_res = AST_TEST_PASS;
-	for (i = 0; i < ARRAY_LEN(valid_dates); ++i) {
-		res = ast_json_string_set(uut, valid_dates[i]);
-		ast_test_validate(test, 0 == res);
-		if (!ast_ari_validate_date(uut)) {
-			ast_test_status_update(test,
-				"Expected '%s' to be a valid date\n",
-				valid_dates[i]);
-			test_res = AST_TEST_FAIL;
-		}
-	}
-
-	for (i = 0; i < ARRAY_LEN(invalid_dates); ++i) {
-		res = ast_json_string_set(uut, invalid_dates[i]);
-		ast_test_validate(test, 0 == res);
-		if (ast_ari_validate_date(uut)) {
-			ast_test_status_update(test,
-				"Expected '%s' to be an invalid date\n",
-				invalid_dates[i]);
-			test_res = AST_TEST_FAIL;
-		}
-	}
-
-	ast_test_validate(test, !ast_ari_validate_string(ast_json_null()));
-
-	return test_res;
-}
-
-AST_TEST_DEFINE(validate_list)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/ari/validators/";
-		info->summary = "Test list validation";
-		info->description =
-			"Test list validation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_array_create();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
-	ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
-
-	res = ast_json_array_append(uut, ast_json_string_create(""));
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
-	ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
-
-	res = ast_json_array_append(uut, ast_json_integer_create(0));
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
-	ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
-
-	ast_test_validate(test,
-		!ast_ari_validate_list(ast_json_null(), wrap_ast_ari_validate_string));
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(validate_byte);
-	AST_TEST_UNREGISTER(validate_boolean);
-	AST_TEST_UNREGISTER(validate_int);
-	AST_TEST_UNREGISTER(validate_long);
-	AST_TEST_UNREGISTER(validate_string);
-	AST_TEST_UNREGISTER(validate_date);
-	AST_TEST_UNREGISTER(validate_list);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(validate_byte);
-	AST_TEST_REGISTER(validate_boolean);
-	AST_TEST_REGISTER(validate_int);
-	AST_TEST_REGISTER(validate_long);
-	AST_TEST_REGISTER(validate_string);
-	AST_TEST_REGISTER(validate_date);
-	AST_TEST_REGISTER(validate_list);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Test");
diff --git a/tests/test_ast_format_str_reduce.c b/tests/test_ast_format_str_reduce.c
index da8a8e2..e0e468c 100644
--- a/tests/test_ast_format_str_reduce.c
+++ b/tests/test_ast_format_str_reduce.c
@@ -41,7 +41,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 332178 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/file.h"
diff --git a/tests/test_astobj2.c b/tests/test_astobj2.c
index 4119848..a0f0d34 100644
--- a/tests/test_astobj2.c
+++ b/tests/test_astobj2.c
@@ -30,69 +30,22 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/test.h"
 #include "asterisk/astobj2.h"
 
-/* Uncomment the following line to dump the container contents during tests. */
-//#define TEST_CONTAINER_DEBUG_DUMP		1
-
-enum test_container_type {
-	TEST_CONTAINER_LIST,
-	TEST_CONTAINER_HASH,
-	TEST_CONTAINER_RBTREE,
-};
-
-/*!
- * \internal
- * \brief Convert the container type enum to string.
- * \since 12.0.0
- *
- * \param type Container type value to convert to string.
- *
- * \return String value of container type.
- */
-static const char *test_container2str(enum test_container_type type)
-{
-	const char *c_type;
-
-	c_type = "Unknown";
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		c_type = "List";
-		break;
-	case TEST_CONTAINER_HASH:
-		c_type = "Hash";
-		break;
-	case TEST_CONTAINER_RBTREE:
-		c_type = "RBTree";
-		break;
-	}
-	return c_type;
-}
-
 struct test_obj {
-	/*! What to decrement when object is destroyed. */
-	int *destructor_count;
-	/*! Container object key */
 	int i;
-	/*! Identifier for duplicate object key tests. */
-	int dup_number;
+	int *destructor_count;
 };
 
-/*! Partial search key +/- matching range. */
-int partial_key_match_range;
-
-static void test_obj_destructor(void *v_obj)
+static void test_obj_destructor(void *obj)
 {
-	struct test_obj *obj = (struct test_obj *) v_obj;
-
-	if (obj->destructor_count) {
-		--*obj->destructor_count;
-	}
+	struct test_obj *test_obj = (struct test_obj *) obj;
+	*test_obj->destructor_count = *test_obj->destructor_count - 1;
 }
 
 static int increment_cb(void *obj, void *arg, int flag)
@@ -105,142 +58,124 @@ static int increment_cb(void *obj, void *arg, int flag)
 
 static int all_but_one_cb(void *obj, void *arg, int flag)
 {
-	struct test_obj *cmp_obj = (struct test_obj *) obj;
+	struct test_obj *test_obj = (struct test_obj *) obj;
 
-	return (cmp_obj->i) ? CMP_MATCH : 0;
+	return (test_obj->i > 1) ? CMP_MATCH : 0;
 }
 
 static int multiple_cb(void *obj, void *arg, int flag)
 {
 	int *i = (int *) arg;
-	struct test_obj *cmp_obj = (struct test_obj *) obj;
+	struct test_obj *test_obj = (struct test_obj *) obj;
 
-	return (cmp_obj->i < *i) ? CMP_MATCH : 0;
+	return (test_obj->i <= *i) ? CMP_MATCH : 0;
 }
 
 static int test_cmp_cb(void *obj, void *arg, int flags)
 {
 	struct test_obj *cmp_obj = (struct test_obj *) obj;
 
-	if (flags & OBJ_KEY) {
-		int *i = (int *) arg;
+	if (!arg) {
+		return 0;
+	}
 
-		return (cmp_obj->i == *i) ? CMP_MATCH : 0;
-	} else if (flags & OBJ_PARTIAL_KEY) {
+	if (flags & OBJ_KEY) {
 		int *i = (int *) arg;
-
-		return (*i - partial_key_match_range <= cmp_obj->i
-			&& cmp_obj->i <= *i + partial_key_match_range) ? CMP_MATCH : 0;
+		return (cmp_obj->i == *i) ? CMP_MATCH | CMP_STOP : 0;
 	} else {
-		struct test_obj *arg_obj = (struct test_obj *) arg;
-
-		return (cmp_obj->i == arg_obj->i) ? CMP_MATCH : 0;
+		struct test_obj *test_obj = (struct test_obj *) arg;
+		return (cmp_obj->i == test_obj->i) ? CMP_MATCH | CMP_STOP : 0;
 	}
 }
 
 static int test_hash_cb(const void *obj, const int flags)
 {
+	if (!obj) {
+		return 0;
+	}
+
 	if (flags & OBJ_KEY) {
 		const int *i = obj;
 
 		return *i;
-	} else if (flags & OBJ_PARTIAL_KEY) {
-		/* This is absolutely wrong to be called with this flag value. */
-		abort();
-		/* Just in case abort() doesn't work or something else super silly */
-		*((int *) 0) = 0;
-		return 0;
 	} else {
-		const struct test_obj *hash_obj = obj;
+		const struct test_obj *test_obj = obj;
 
-		return hash_obj->i;
+		return test_obj->i;
 	}
 }
 
-static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
+static int astobj2_test_helper(int use_hash, int use_cmp, unsigned int lim, struct ast_test *test)
 {
-	const struct test_obj *test_left = obj_left;
-
-	if (flags & OBJ_KEY) {
-		const int *i = obj_right;
-
-		return test_left->i - *i;
-	} else if (flags & OBJ_PARTIAL_KEY) {
-		int *i = (int *) obj_right;
+	struct ao2_container *c1;
+	struct ao2_container *c2;
+	struct ao2_container *c3 = NULL;
+	struct ao2_iterator it;
+	struct ao2_iterator *mult_it;
+	struct test_obj *obj;
+	struct test_obj *obj2;
+	struct test_obj tmp_obj;
+	int bucket_size;
+	int increment = 0;
+	int destructor_count = 0;
+	int num;
+	int  res = AST_TEST_PASS;
 
-		if (*i - partial_key_match_range <= test_left->i
-			&& test_left->i <= *i + partial_key_match_range) {
-			return 0;
-		}
+	/* This test needs at least 5 objects */
+	if (lim < 5) {
+		lim = 5;
+	}
 
-		return test_left->i - *i;
-	} else {
-		const struct test_obj *test_right = obj_right;
+	bucket_size = (ast_random() % ((lim / 4) + 1)) + 1;
+	c1 = ao2_t_container_alloc(bucket_size, use_hash ? test_hash_cb : NULL, use_cmp ? test_cmp_cb : NULL, "test");
+	c2 = ao2_t_container_alloc(bucket_size, test_hash_cb, test_cmp_cb, "test");
 
-		return test_left->i - test_right->i;
+	if (!c1 || !c2) {
+		ast_test_status_update(test, "ao2_container_alloc failed.\n");
+		res = AST_TEST_FAIL;
+		goto cleanup;
 	}
-}
-
-#if defined(TEST_CONTAINER_DEBUG_DUMP)
-/*!
- * \internal
- * \brief Print test object key.
- * \since 12.0.0
- *
- * \param v_obj A pointer to the object we want the key printed.
- * \param where User data needed by prnt to determine where to put output.
- * \param prnt Print output callback function to use.
- *
- * \return Nothing
- */
-static void test_prnt_obj(void *v_obj, void *where, ao2_prnt_fn *prnt)
-{
-	struct test_obj *obj = v_obj;
 
-	if (!obj) {
-		return;
+	/* Create objects and link into container */
+	destructor_count = lim;
+	for (num = 1; num <= lim; num++) {
+		if (!(obj = ao2_t_alloc(sizeof(struct test_obj), test_obj_destructor, "making zombies"))) {
+			ast_test_status_update(test, "ao2_alloc failed.\n");
+			res = AST_TEST_FAIL;
+			goto cleanup;
+		}
+		obj->destructor_count = &destructor_count;
+		obj->i = num;
+		ao2_link(c1, obj);
+		ao2_t_ref(obj, -1, "test");
+		if (ao2_container_count(c1) != num) {
+			ast_test_status_update(test, "container did not link correctly\n");
+			res = AST_TEST_FAIL;
+		}
 	}
-	prnt(where, "%6d-%d", obj->i, obj->dup_number);
-}
-#endif	/* defined(TEST_CONTAINER_DEBUG_DUMP) */
 
-/*!
- * \internal
- * \brief Test container cloning.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param orig Container to clone.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
-{
-	struct ao2_container *clone;
-	struct test_obj *obj;
-	struct test_obj *obj2;
-	struct ao2_iterator iter;
+	ast_test_status_update(test, "Container created: random bucket size %d: number of items: %u\n", bucket_size, lim);
 
-	clone = ao2_container_clone(orig, 0);
-	if (!clone) {
+	/* Testing ao2_container_clone */
+	c3 = ao2_container_clone(c1, 0);
+	if (!c3) {
 		ast_test_status_update(test, "ao2_container_clone failed.\n");
-		return AST_TEST_FAIL;
-	}
-	if (ao2_container_check(clone, 0)) {
-		ast_test_status_update(test, "container integrity check failed\n");
 		res = AST_TEST_FAIL;
-	} else if (ao2_container_count(orig) != ao2_container_count(clone)) {
+		goto cleanup;
+	}
+	if (ao2_container_count(c1) != ao2_container_count(c3)) {
 		ast_test_status_update(test, "Cloned container does not have the same number of objects.\n");
 		res = AST_TEST_FAIL;
 	} else {
-		iter = ao2_iterator_init(orig, 0);
-		for (; (obj = ao2_t_iterator_next(&iter, "test orig")); ao2_t_ref(obj, -1, "test orig")) {
+		it = ao2_iterator_init(c1, 0);
+		for (; (obj = ao2_t_iterator_next(&it, "test orig")); ao2_t_ref(obj, -1, "test orig")) {
 			/*
 			 * Unlink the matching object from the cloned container to make
 			 * the next search faster.  This is a big speed optimization!
+			 * It reduces the container with 100000 objects test time from
+			 * 18 seconds to 200 ms.
 			 */
-			obj2 = ao2_t_callback(clone, OBJ_POINTER | OBJ_UNLINK, ao2_match_by_addr, obj,
+			obj2 = ao2_t_callback(c3, OBJ_POINTER | OBJ_UNLINK, ao2_match_by_addr, obj,
 				"test clone");
 			if (obj2) {
 				ao2_t_ref(obj2, -1, "test clone");
@@ -250,262 +185,98 @@ static int test_container_clone(int res, struct ao2_container *orig, struct ast_
 				"Orig container has an object %p not in the clone container.\n", obj);
 			res = AST_TEST_FAIL;
 		}
-		ao2_iterator_destroy(&iter);
-		if (ao2_container_count(clone)) {
+		ao2_iterator_destroy(&it);
+		if (ao2_container_count(c3)) {
 			ast_test_status_update(test, "Cloned container still has objects.\n");
 			res = AST_TEST_FAIL;
 		}
-		if (ao2_container_check(clone, 0)) {
-			ast_test_status_update(test, "container integrity check failed\n");
-			res = AST_TEST_FAIL;
-		}
 	}
-	ao2_t_ref(clone, -1, "bye clone");
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test ao2_find with no flags.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param look_in Container to search.
- * \param limit Container contains objects 0 - (limit - 1).
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
-{
-	int i;
-	int num;
-	struct test_obj tmp_obj = { 0, };
-	struct test_obj *obj;
-
-	for (num = 100; num--;) {
-		i = ast_random() % limit; /* find a random object */
+	ao2_t_ref(c3, -1, "bye c3");
+	c3 = NULL;
 
+	/* Testing ao2_find with no flags */
+	num = 100;
+	for (; num; num--) {
+		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
 		tmp_obj.i = i;
-		obj = ao2_find(look_in, &tmp_obj, 0);
-		if (!obj) {
-			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
+		if (!(obj = ao2_find(c1, &tmp_obj, 0))) {
 			res = AST_TEST_FAIL;
+			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
 		} else {
-			if (obj->i != i) {
-				ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
+			/* a correct match will only take place when the custom cmp function is used */
+			if (use_cmp && obj->i != i) {
+				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
 				res = AST_TEST_FAIL;
 			}
 			ao2_t_ref(obj, -1, "test");
 		}
 	}
 
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test ao2_find with OBJ_POINTER.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param look_in Container to search.
- * \param limit Container contains objects 0 - (limit - 1).
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
-{
-	int i;
-	int num;
-	struct test_obj tmp_obj = { 0, };
-	struct test_obj *obj;
-
-	for (num = 75; num--;) {
-		i = ast_random() % limit; /* find a random object */
-
+	/* Testing ao2_find with OBJ_POINTER */
+	num = 75;
+	for (; num; num--) {
+		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
 		tmp_obj.i = i;
-		obj = ao2_find(look_in, &tmp_obj, OBJ_POINTER);
-		if (!obj) {
-			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
+		if (!(obj = ao2_find(c1, &tmp_obj, OBJ_POINTER))) {
 			res = AST_TEST_FAIL;
+			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
 		} else {
-			if (obj->i != i) {
-				ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
+			/* a correct match will only take place when the custom cmp function is used */
+			if (use_cmp && obj->i != i) {
+				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
 				res = AST_TEST_FAIL;
 			}
 			ao2_t_ref(obj, -1, "test");
 		}
 	}
 
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test ao2_find with OBJ_KEY.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param look_in Container to search.
- * \param limit Container contains objects 0 - (limit - 1).
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
-{
-	int i;
-	int num;
-	struct test_obj *obj;
-
-	for (num = 75; num--;) {
-		i = ast_random() % limit; /* find a random object */
-
-		obj = ao2_find(look_in, &i, OBJ_KEY);
-		if (!obj) {
-			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_KEY flag failed.\n", i);
+	/* Testing ao2_find with OBJ_KEY */
+	num = 75;
+	for (; num; num--) {
+		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
+		if (!(obj = ao2_find(c1, &i, OBJ_KEY))) {
 			res = AST_TEST_FAIL;
+			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_KEY flag failed.\n", i);
 		} else {
-			if (obj->i != i) {
-				ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
+			/* a correct match will only take place when the custom cmp function is used */
+			if (use_cmp && obj->i != i) {
+				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
 				res = AST_TEST_FAIL;
 			}
 			ao2_t_ref(obj, -1, "test");
 		}
 	}
 
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test ao2_find with OBJ_PARTIAL_KEY.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param look_in Container to search.
- * \param limit Container contains objects 0 - (limit - 1).
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
-{
-	int i;
-	int num;
-	struct test_obj *obj;
-
-	/* Set partial match to find exactly. */
-	partial_key_match_range = 0;
-
-	for (num = 100; num--;) {
-		i = ast_random() % limit; /* find a random object */
-
-		obj = ao2_find(look_in, &i, OBJ_PARTIAL_KEY);
-		if (!obj) {
-			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_PARTIAL_KEY flag failed.\n", i);
-			res = AST_TEST_FAIL;
+	/* Testing ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE.
+	 * In this test items are unlinked from c1 and placed in c2.  Then
+	 * unlinked from c2 and placed back into c1.
+	 *
+	 * For this module and set of custom hash/cmp functions, an object
+	 * should only be found if the astobj2 default cmp function is used.
+	 * This test is designed to mimic the chan_iax.c call number use case. */
+	num = lim < 25 ? lim : 25;
+	for (; num; num--) {
+		if (!(obj = ao2_find(c1, NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE))) {
+			if (!use_cmp) {
+				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with default hash function.\n");
+				res = AST_TEST_FAIL;
+			}
 		} else {
-			if (obj->i != i) {
-				ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
+			if (use_cmp) {
+				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with custom hash function.\n");
 				res = AST_TEST_FAIL;
 			}
+			ao2_link(c2, obj);
 			ao2_t_ref(obj, -1, "test");
 		}
 	}
-
-	return res;
-}
-
-static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
-{
-	const char *c_type;
-	struct ao2_container *c1;
-	struct ao2_container *c2;
-	struct ao2_iterator it;
-	struct ao2_iterator *mult_it;
-	struct test_obj *obj;
-	int n_buckets = 0;
-	int increment = 0;
-	int destructor_count = 0;
-	int num;
-	int res = AST_TEST_PASS;
-
-	c_type = test_container2str(type);
-	ast_test_status_update(test, "Test %d, %s containers (%s).\n",
-		tst_num, c_type, use_sort ? "sorted" : "non-sorted");
-
-	c1 = NULL;
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		/* Lists just have one bucket. */
-		n_buckets = 1;
-		c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
-			use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
-		break;
-	case TEST_CONTAINER_HASH:
-		n_buckets = (ast_random() % ((lim / 4) + 1)) + 1;
-		c1 = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, n_buckets,
-			test_hash_cb, use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
-		break;
-	case TEST_CONTAINER_RBTREE:
-		/* RBTrees just have one bucket. */
-		n_buckets = 1;
-		c1 = ao2_t_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
-			test_sort_cb, test_cmp_cb, "test");
-		break;
-	}
-	c2 = ao2_t_container_alloc(1, NULL, NULL, "test");
-
-	if (!c1 || !c2) {
-		ast_test_status_update(test, "ao2_container_alloc failed.\n");
-		res = AST_TEST_FAIL;
-		goto cleanup;
-	}
-
-	/* Create objects and link into container */
-	for (num = 0; num < lim; ++num) {
-		if (!(obj = ao2_t_alloc(sizeof(struct test_obj), test_obj_destructor, "making zombies"))) {
-			ast_test_status_update(test, "ao2_alloc failed.\n");
-			res = AST_TEST_FAIL;
-			goto cleanup;
-		}
-		++destructor_count;
-		obj->destructor_count = &destructor_count;
-		obj->i = num;
-		ao2_link(c1, obj);
+	it = ao2_iterator_init(c2, 0);
+	while ((obj = ao2_t_iterator_next(&it, "test"))) {
+		ao2_t_unlink(c2, obj, "test");
+		ao2_t_link(c1, obj, "test");
 		ao2_t_ref(obj, -1, "test");
-		if (ao2_container_check(c1, 0)) {
-			ast_test_status_update(test, "container integrity check failed linking obj num:%d\n", num);
-			res = AST_TEST_FAIL;
-			goto cleanup;
-		}
-		if (ao2_container_count(c1) != num + 1) {
-			ast_test_status_update(test, "container did not link correctly\n");
-			res = AST_TEST_FAIL;
-		}
 	}
-
-	ast_test_status_update(test, "%s container created: buckets: %d, items: %u\n",
-		c_type, n_buckets, lim);
-
-	/* Testing ao2_container_clone */
-	res = test_container_clone(res, c1, test);
-
-	/* Testing ao2_find with no flags */
-	res = test_ao2_find_w_no_flags(res, c1, lim, test);
-
-	/* Testing ao2_find with OBJ_POINTER */
-	res = test_ao2_find_w_OBJ_POINTER(res, c1, lim, test);
-
-	/* Testing ao2_find with OBJ_KEY */
-	res = test_ao2_find_w_OBJ_KEY(res, c1, lim, test);
-
-	/* Testing ao2_find with OBJ_PARTIAL_KEY */
-	res = test_ao2_find_w_OBJ_PARTIAL_KEY(res, c1, lim, test);
+	ao2_iterator_destroy(&it);
 
 	/* Test Callback with no flags. */
 	increment = 0;
@@ -523,10 +294,10 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 		res = AST_TEST_FAIL;
 	}
 
-	/* Test OBJ_MULTIPLE with OBJ_UNLINK, add items back afterwards */
+	/* Test OBJ_MULTIPLE with OBJ_UNLINK*/
 	num = lim < 25 ? lim : 25;
 	if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK, multiple_cb, &num, "test multiple"))) {
-		ast_test_status_update(test, "OBJ_MULTIPLE with OBJ_UNLINK test failed.\n");
+		ast_test_status_update(test, "OBJ_MULTIPLE iwth OBJ_UNLINK test failed.\n");
 		res = AST_TEST_FAIL;
 	} else {
 		/* make sure num items unlinked is as expected */
@@ -534,11 +305,6 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 			ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK test failed, did not unlink correct number of objects.\n");
 			res = AST_TEST_FAIL;
 		}
-		if (ao2_container_check(c1, 0)) {
-			ast_test_status_update(test, "container integrity check failed\n");
-			res = AST_TEST_FAIL;
-			goto cleanup;
-		}
 
 		/* link what was unlinked back into c1 */
 		while ((obj = ao2_t_iterator_next(mult_it, "test"))) {
@@ -546,15 +312,10 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 			ao2_t_ref(obj, -1, "test"); /* remove ref from iterator */
 		}
 		ao2_iterator_destroy(mult_it);
-		if (ao2_container_check(c1, 0)) {
-			ast_test_status_update(test, "container integrity check failed\n");
-			res = AST_TEST_FAIL;
-			goto cleanup;
-		}
 	}
 
-	/* Test OBJ_MULTIPLE without unlink and iterate the returned container */
-	num = 5;
+	/* Test OBJ_MULTIPLE without unlink, add items back afterwards */
+	num = lim < 25 ? lim : 25;
 	if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE, multiple_cb, &num, "test multiple"))) {
 		ast_test_status_update(test, "OBJ_MULTIPLE without OBJ_UNLINK test failed.\n");
 		res = AST_TEST_FAIL;
@@ -566,7 +327,7 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 	}
 
 	/* Test OBJ_MULTIPLE without unlink and no iterating */
-	num = 5;
+	num = lim < 5 ? lim : 5;
 	if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE, multiple_cb, &num, "test multiple"))) {
 		ast_test_status_update(test, "OBJ_MULTIPLE with no OBJ_UNLINK and no iterating failed.\n");
 		res = AST_TEST_FAIL;
@@ -582,18 +343,11 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 
 	/* Testing iterator.  Unlink a single object and break. do not add item back */
 	it = ao2_iterator_init(c1, 0);
-	num = ast_random() % lim; /* remove a random object */
-	if (!num) {
-		/*
-		 * Well we cannot remove object zero because of test with
-		 * all_but_one_cb later.
-		 */
-		num = 1;
-	}
+	num = (lim / 4) + 1;
 	while ((obj = ao2_t_iterator_next(&it, "test"))) {
 		if (obj->i == num) {
-			ao2_t_unlink(c1, obj, "test");
 			ao2_t_ref(obj, -1, "test");
+			ao2_t_unlink(c1, obj, "test");
 			break;
 		}
 		ao2_t_ref(obj, -1, "test");
@@ -605,11 +359,6 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 		ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num);
 		res = AST_TEST_FAIL;
 	}
-	if (ao2_container_check(c1, 0)) {
-		ast_test_status_update(test, "container integrity check failed\n");
-		res = AST_TEST_FAIL;
-		goto cleanup;
-	}
 
 	/* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */
 	ao2_t_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, all_but_one_cb, NULL, "test multiple");
@@ -618,14 +367,6 @@ static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int
 		ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
 		res = AST_TEST_FAIL;
 	}
-	if (ao2_container_check(c1, 0)) {
-		ast_test_status_update(test, "container integrity check failed\n");
-		res = AST_TEST_FAIL;
-	}
-#if defined(TEST_CONTAINER_DEBUG_DUMP)
-	ao2_container_dump(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
-	ao2_container_stats(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug);
-#endif	/* defined(TEST_CONTAINER_DEBUG_DUMP) */
 
 cleanup:
 	/* destroy containers */
@@ -635,6 +376,9 @@ cleanup:
 	if (c2) {
 		ao2_t_ref(c2, -1, "bye c2");
 	}
+	if (c3) {
+		ao2_t_ref(c3, -1, "bye c3");
+	}
 
 	if (destructor_count > 0) {
 		ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count);
@@ -655,7 +399,7 @@ AST_TEST_DEFINE(astobj2_test_1)
 	case TEST_INIT:
 		info->name = "astobj2_test1";
 		info->category = "/main/astobj2/";
-		info->summary = "Test ao2 objects, containers, callbacks, and iterators";
+		info->summary = "astobj2 test using ao2 objects, containers, callbacks, and iterators";
 		info->description =
 			"Builds ao2_containers with various item numbers, bucket sizes, cmp and hash "
 			"functions. Runs a series of tests to manipulate the container using callbacks "
@@ -665,24 +409,28 @@ AST_TEST_DEFINE(astobj2_test_1)
 		break;
 	}
 
-	/* Test number, container_type, use_sort, number of objects. */
-	if ((res = astobj2_test_1_helper(1, TEST_CONTAINER_LIST, 0, 50, test)) == AST_TEST_FAIL) {
-		return res;
-	}
 
-	if ((res = astobj2_test_1_helper(2, TEST_CONTAINER_LIST, 1, 50, test)) == AST_TEST_FAIL) {
+	/* Test 1, 500 items with custom hash and cmp functions */
+	ast_test_status_update(test, "Test 1, astobj2 test with 500 items.\n");
+	if ((res = astobj2_test_helper(1, 1, 500, test)) == AST_TEST_FAIL) {
 		return res;
 	}
 
-	if ((res = astobj2_test_1_helper(3, TEST_CONTAINER_HASH, 0, 1000, test)) == AST_TEST_FAIL) {
+	/* Test 2, 1000 items with custom hash and default cmp functions */
+	ast_test_status_update(test, "Test 2, astobj2 test with 1000 items.\n");
+	if ((res = astobj2_test_helper(1, 0, 1000, test)) == AST_TEST_FAIL) {
 		return res;
 	}
 
-	if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_HASH, 1, 1000, test)) == AST_TEST_FAIL) {
+	/* Test 3, 10000 items with default hash and custom cmp functions */
+	ast_test_status_update(test, "Test 3, astobj2 test with 10000 items.\n");
+	if ((res = astobj2_test_helper(0, 1, 10000, test)) == AST_TEST_FAIL) {
 		return res;
 	}
 
-	if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_RBTREE, 1, 1000, test)) == AST_TEST_FAIL) {
+	/* Test 4, 100000 items with default hash and cmp functions */
+	ast_test_status_update(test, "Test 4, astobj2 test with 100000 items.\n");
+	if ((res = astobj2_test_helper(0, 0, 100000, test)) == AST_TEST_FAIL) {
 		return res;
 	}
 
@@ -736,11 +484,6 @@ AST_TEST_DEFINE(astobj2_test_2)
 			res = AST_TEST_FAIL;
 		}
 	}
-	if (ao2_container_check(c, 0)) {
-		ast_test_status_update(test, "container integrity check failed\n");
-		res = AST_TEST_FAIL;
-		goto cleanup;
-	}
 
 	/*
 	 * Iteration take 1.  Just make sure we see all NUM_OBJS objects.
@@ -955,1106 +698,11 @@ cleanup:
 	return res;
 }
 
-/*!
- * \internal
- * \brief Make a nonsorted container for astobj2 testing.
- * \since 12.0.0
- *
- * \param type Container type to create.
- * \param options Container options
- *
- * \retval container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *test_make_nonsorted(enum test_container_type type, int options)
-{
-	struct ao2_container *container;
-
-	container = NULL;
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, options,
-			NULL, test_cmp_cb);
-		break;
-	case TEST_CONTAINER_HASH:
-		container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, options, 5,
-			test_hash_cb, NULL, test_cmp_cb);
-		break;
-	case TEST_CONTAINER_RBTREE:
-		/* Container type must be sorted. */
-		break;
-	}
-
-	return container;
-}
-
-/*!
- * \internal
- * \brief Make a sorted container for astobj2 testing.
- * \since 12.0.0
- *
- * \param type Container type to create.
- * \param options Container options
- *
- * \retval container on success.
- * \retval NULL on error.
- */
-static struct ao2_container *test_make_sorted(enum test_container_type type, int options)
-{
-	struct ao2_container *container;
-
-	container = NULL;
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		container = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, options,
-			test_sort_cb, test_cmp_cb, "test");
-		break;
-	case TEST_CONTAINER_HASH:
-		container = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, options, 5,
-			test_hash_cb, test_sort_cb, test_cmp_cb, "test");
-		break;
-	case TEST_CONTAINER_RBTREE:
-		container = ao2_t_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, options,
-			test_sort_cb, test_cmp_cb, "test");
-		break;
-	}
-
-	return container;
-}
-
-/*!
- * \internal
- * \brief Insert the given test vector into the given container.
- * \since 12.0.0
- *
- * \note The given test vector must not have any duplicates.
- *
- * \param container Container to insert the test vector.
- * \param destroy_counter What to increment when the object is destroyed.
- * \param vector Test vector to insert.
- * \param count Number of objects in the vector.
- * \param prefix Test output prefix string.
- * \param test Test output controller.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
-{
-	int idx;
-	struct test_obj *obj;
-
-	for (idx = 0; idx < count; ++idx) {
-		obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
-		if (!obj) {
-			ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
-			return -1;
-		}
-		if (destroy_counter) {
-			/* This object ultimately needs to be destroyed. */
-			++*destroy_counter;
-		}
-		obj->destructor_count = destroy_counter;
-		obj->i = vector[idx];
-		ao2_link(container, obj);
-		ao2_t_ref(obj, -1, "test");
-		if (ao2_container_check(container, 0)) {
-			ast_test_status_update(test, "%s: Container integrity check failed linking vector[%d]:%d\n",
-				prefix, idx, vector[idx]);
-			return -1;
-		}
-
-		if (ao2_container_count(container) != idx + 1) {
-			ast_test_status_update(test,
-				"%s: Unexpected container count.  Expected:%d Got:%d\n",
-				prefix, idx + 1, ao2_container_count(container));
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Insert duplicates of number into the given container.
- * \since 12.0.0
- *
- * \note The given container must not already have the number in it.
- *
- * \param container Container to insert the duplicates.
- * \param destroy_counter What to increment when the object is destroyed.
- * \param number Number of object to duplicate.
- * \param prefix Test output prefix string.
- * \param test Test output controller.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int insert_test_duplicates(struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
-{
-	int count;
-	struct test_obj *obj;
-	struct test_obj *obj_dup;
-
-	/* Check if object already exists in the container. */
-	obj = ao2_find(container, &number, OBJ_KEY);
-	if (obj) {
-		ast_test_status_update(test, "%s: Object %d already exists.\n", prefix, number);
-		ao2_t_ref(obj, -1, "test");
-		return -1;
-	}
-
-	/* Add three duplicate keyed objects. */
-	obj_dup = NULL;
-	for (count = 0; count < 4; ++count) {
-		obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
-		if (!obj) {
-			ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
-			if (obj_dup) {
-				ao2_t_ref(obj_dup, -1, "test");
-			}
-			return -1;
-		}
-		if (destroy_counter) {
-			/* This object ultimately needs to be destroyed. */
-			++*destroy_counter;
-		}
-		obj->destructor_count = destroy_counter;
-		obj->i = number;
-		obj->dup_number = count;
-		ao2_link(container, obj);
-
-		if (count == 2) {
-			/* Duplicate this object. */
-			obj_dup = obj;
-		} else {
-			ao2_t_ref(obj, -1, "test");
-		}
-
-		if (ao2_container_check(container, 0)) {
-			ast_test_status_update(test, "%s: Container integrity check failed linking num:%d dup:%d\n",
-				prefix, number, count);
-			if (obj_dup) {
-				ao2_t_ref(obj_dup, -1, "test");
-			}
-			return -1;
-		}
-	}
-
-	/* Add the duplicate object. */
-	ao2_link(container, obj_dup);
-	ao2_t_ref(obj_dup, -1, "test");
-
-	if (ao2_container_check(container, 0)) {
-		ast_test_status_update(test, "%s: Container integrity check failed linking obj_dup\n",
-			prefix);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Iterate over the container and compare the objects with the given vector.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param container Container to iterate.
- * \param flags Flags controlling the iteration.
- * \param vector Expected vector to find.
- * \param count Number of objects in the vector.
- * \param prefix Test output prefix string.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_iteration(int res, struct ao2_container *container,
-	enum ao2_iterator_flags flags,
-	const int *vector, int count, const char *prefix, struct ast_test *test)
-{
-	struct ao2_iterator iter;
-	struct test_obj *obj;
-	int idx;
-
-	if (ao2_container_count(container) != count) {
-		ast_test_status_update(test, "%s: Container count doesn't match vector count.\n",
-			prefix);
-		res = AST_TEST_FAIL;
-	}
-
-	iter = ao2_iterator_init(container, flags);
-
-	/* Check iterated objects against the given vector. */
-	for (idx = 0; idx < count; ++idx) {
-		obj = ao2_iterator_next(&iter);
-		if (!obj) {
-			ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
-			res = AST_TEST_FAIL;
-			break;
-		}
-		if (vector[idx] != obj->i) {
-			ast_test_status_update(test, "%s: Object %d != vector[%d] %d.\n",
-				prefix, obj->i, idx, vector[idx]);
-			res = AST_TEST_FAIL;
-		}
-		ao2_ref(obj, -1); /* remove ref from iterator */
-	}
-	obj = ao2_iterator_next(&iter);
-	if (obj) {
-		ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
-			prefix, obj->i);
-		ao2_ref(obj, -1); /* remove ref from iterator */
-		res = AST_TEST_FAIL;
-	}
-
-	ao2_iterator_destroy(&iter);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Run an ao2_callback() and compare the returned vector with the given vector.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param container Container to traverse.
- * \param flags Callback flags controlling the traversal.
- * \param cmp_fn Compare function to select objects.
- * \param arg Optional argument.
- * \param vector Expected vector to find.
- * \param count Number of objects in the vector.
- * \param prefix Test output prefix string.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_ao2_callback_traversal(int res, struct ao2_container *container,
-	enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg,
-	const int *vector, int count, const char *prefix, struct ast_test *test)
-{
-	struct ao2_iterator *mult_iter;
-	struct test_obj *obj;
-	int idx;
-
-	mult_iter = ao2_callback(container, flags | OBJ_MULTIPLE, cmp_fn, arg);
-	if (!mult_iter) {
-		ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
-		return AST_TEST_FAIL;
-	}
-
-	/* Check matching objects against the given vector. */
-	for (idx = 0; idx < count; ++idx) {
-		obj = ao2_iterator_next(mult_iter);
-		if (!obj) {
-			ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
-			res = AST_TEST_FAIL;
-			break;
-		}
-		if (vector[idx] != obj->i) {
-			ast_test_status_update(test, "%s: Object %d != vector[%d] %d.\n",
-				prefix, obj->i, idx, vector[idx]);
-			res = AST_TEST_FAIL;
-		}
-		ao2_ref(obj, -1); /* remove ref from iterator */
-	}
-	obj = ao2_iterator_next(mult_iter);
-	if (obj) {
-		ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
-			prefix, obj->i);
-		ao2_ref(obj, -1); /* remove ref from iterator */
-		res = AST_TEST_FAIL;
-	}
-	ao2_iterator_destroy(mult_iter);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Run an ao2_find() for duplicates and compare the returned vector with the given vector.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param container Container to traverse.
- * \param flags Callback flags controlling the traversal.
- * \param number Number of object to find all duplicates.
- * \param vector Expected vector to find.
- * \param count Number of objects in the vector.
- * \param prefix Test output prefix string.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_expected_duplicates(int res, struct ao2_container *container,
-	enum search_flags flags, int number,
-	const int *vector, int count, const char *prefix, struct ast_test *test)
-{
-	struct ao2_iterator *mult_iter;
-	struct test_obj *obj;
-	int idx;
-
-	mult_iter = ao2_find(container, &number, flags | OBJ_MULTIPLE | OBJ_KEY);
-	if (!mult_iter) {
-		ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
-		return AST_TEST_FAIL;
-	}
-
-	/* Check matching objects against the given vector. */
-	for (idx = 0; idx < count; ++idx) {
-		obj = ao2_iterator_next(mult_iter);
-		if (!obj) {
-			ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
-			res = AST_TEST_FAIL;
-			break;
-		}
-		if (number != obj->i) {
-			ast_test_status_update(test, "%s: Object %d != %d.\n",
-				prefix, obj->i, number);
-			res = AST_TEST_FAIL;
-		}
-		if (vector[idx] != obj->dup_number) {
-			ast_test_status_update(test, "%s: Object dup id %d != vector[%d] %d.\n",
-				prefix, obj->dup_number, idx, vector[idx]);
-			res = AST_TEST_FAIL;
-		}
-		ao2_ref(obj, -1); /* remove ref from iterator */
-	}
-	obj = ao2_iterator_next(mult_iter);
-	if (obj) {
-		ast_test_status_update(test,
-			"%s: Too many objects found.  Object %d, dup id %d\n",
-			prefix, obj->i, obj->dup_number);
-		ao2_ref(obj, -1); /* remove ref from iterator */
-		res = AST_TEST_FAIL;
-	}
-	ao2_iterator_destroy(mult_iter);
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test nonsorted container traversal.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param tst_num Test number.
- * \param type Container type to test.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
-{
-	struct ao2_container *c1;
-	struct ao2_container *c2 = NULL;
-	int partial;
-	int destructor_count = 0;
-
-	/*! Container object insertion vector. */
-	static const int test_initial[] = {
-		1, 0, 2, 6, 4, 7, 5, 3, 9, 8
-	};
-
-	/*! Container object insertion vector reversed. */
-	static const int test_reverse[] = {
-		8, 9, 3, 5, 7, 4, 6, 2, 0, 1
-	};
-	static const int test_list_partial_forward[] = {
-		6, 7, 5
-	};
-	static const int test_list_partial_backward[] = {
-		5, 7, 6
-	};
-
-	/* The hash orders assume that there are 5 buckets. */
-	static const int test_hash_end_forward[] = {
-		0, 5, 1, 6, 2, 7, 3, 8, 4, 9
-	};
-	static const int test_hash_end_backward[] = {
-		9, 4, 8, 3, 7, 2, 6, 1, 5, 0
-	};
-	static const int test_hash_begin_forward[] = {
-		5, 0, 6, 1, 7, 2, 8, 3, 9, 4
-	};
-	static const int test_hash_begin_backward[] = {
-		4, 9, 3, 8, 2, 7, 1, 6, 0, 5
-	};
-	static const int test_hash_partial_forward[] = {
-		5, 6, 7
-	};
-	static const int test_hash_partial_backward[] = {
-		7, 6, 5
-	};
-
-	ast_test_status_update(test, "Test %d, %s containers.\n",
-		tst_num, test_container2str(type));
-
-	/* Create container that inserts objects at the end. */
-	c1 = test_make_nonsorted(type, 0);
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Create container that inserts objects at the beginning. */
-	c2 = test_make_nonsorted(type, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN);
-	if (!c2) {
-		ast_test_status_update(test, "Container c2 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Check container iteration directions */
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_iteration(res, c1, 0,
-			test_initial, ARRAY_LEN(test_initial),
-			"Iteration (ascending, insert end)", test);
-		res = test_ao2_iteration(res, c1, AO2_ITERATOR_DESCENDING,
-			test_reverse, ARRAY_LEN(test_reverse),
-			"Iteration (descending, insert end)", test);
-
-		res = test_ao2_iteration(res, c2, 0,
-			test_reverse, ARRAY_LEN(test_reverse),
-			"Iteration (ascending, insert begin)", test);
-		res = test_ao2_iteration(res, c2, AO2_ITERATOR_DESCENDING,
-			test_initial, ARRAY_LEN(test_initial),
-			"Iteration (descending, insert begin)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_iteration(res, c1, 0,
-			test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
-			"Iteration (ascending, insert end)", test);
-		res = test_ao2_iteration(res, c1, AO2_ITERATOR_DESCENDING,
-			test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
-			"Iteration (descending, insert end)", test);
-
-		res = test_ao2_iteration(res, c2, 0,
-			test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
-			"Iteration (ascending, insert begin)", test);
-		res = test_ao2_iteration(res, c2, AO2_ITERATOR_DESCENDING,
-			test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
-			"Iteration (descending, insert begin)", test);
-		break;
-	case TEST_CONTAINER_RBTREE:
-		break;
-	}
-
-	/* Check container traversal directions */
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_initial, ARRAY_LEN(test_initial),
-			"Traversal (ascending, insert end)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_reverse, ARRAY_LEN(test_reverse),
-			"Traversal (descending, insert end)", test);
-
-		res = test_ao2_callback_traversal(res, c2, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_reverse, ARRAY_LEN(test_reverse),
-			"Traversal (ascending, insert begin)", test);
-		res = test_ao2_callback_traversal(res, c2, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_initial, ARRAY_LEN(test_initial),
-			"Traversal (descending, insert begin)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
-			"Traversal (ascending, insert end)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
-			"Traversal (descending, insert end)", test);
-
-		res = test_ao2_callback_traversal(res, c2, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
-			"Traversal (ascending, insert begin)", test);
-		res = test_ao2_callback_traversal(res, c2, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
-			"Traversal (descending, insert begin)", test);
-		break;
-	case TEST_CONTAINER_RBTREE:
-		break;
-	}
-
-	/* Check traversal with OBJ_PARTIAL_KEY search range. */
-	partial = 6;
-	partial_key_match_range = 1;
-	switch (type) {
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_ASCENDING,
-			test_cmp_cb, &partial,
-			test_list_partial_forward, ARRAY_LEN(test_list_partial_forward),
-			"Traversal OBJ_PARTIAL_KEY (ascending)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_DESCENDING,
-			test_cmp_cb, &partial,
-			test_list_partial_backward, ARRAY_LEN(test_list_partial_backward),
-			"Traversal OBJ_PARTIAL_KEY (descending)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_ASCENDING,
-			test_cmp_cb, &partial,
-			test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
-			"Traversal OBJ_PARTIAL_KEY (ascending)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_DESCENDING,
-			test_cmp_cb, &partial,
-			test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
-			"Traversal OBJ_PARTIAL_KEY (descending)", test);
-		break;
-	case TEST_CONTAINER_RBTREE:
-		break;
-	}
-
-test_cleanup:
-	/* destroy containers */
-	if (c1) {
-		ao2_t_ref(c1, -1, "bye c1");
-	}
-	if (c2) {
-		ao2_t_ref(c2, -1, "bye c2");
-	}
-
-	if (destructor_count > 0) {
-		ast_test_status_update(test,
-			"all destructors were not called, destructor count is %d\n",
-			destructor_count);
-		res = AST_TEST_FAIL;
-	} else if (destructor_count < 0) {
-		ast_test_status_update(test,
-			"Destructor was called too many times, destructor count is %d\n",
-			destructor_count);
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-/*!
- * \internal
- * \brief Test sorted container traversal.
- * \since 12.0.0
- *
- * \param res Passed in enum ast_test_result_state.
- * \param tst_num Test number.
- * \param type Container type to test.
- * \param test Test output controller.
- *
- * \return enum ast_test_result_state
- */
-static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
-{
-	struct ao2_container *c1;
-	struct ao2_container *c2 = NULL;
-	int partial;
-	int destructor_count = 0;
-	int duplicate_number = 100;
-
-	/*! Container object insertion vector. */
-	static const int test_initial[] = {
-		1, 0, 2, 6, 4, 7, 5, 3, 9, 8
-	};
-
-	/*! Container forward traversal/iteration. */
-	static const int test_forward[] = {
-		0, 1, 2, 3, 4, 5, 6, 7, 8, 9
-	};
-	/*! Container backward traversal/iteration. */
-	static const int test_backward[] = {
-		9, 8, 7, 6, 5, 4, 3, 2, 1, 0
-	};
-
-	static const int test_partial_forward[] = {
-		5, 6, 7
-	};
-	static const int test_partial_backward[] = {
-		7, 6, 5
-	};
-
-	/* The hash orders assume that there are 5 buckets. */
-	static const int test_hash_forward[] = {
-		0, 5, 1, 6, 2, 7, 3, 8, 4, 9
-	};
-	static const int test_hash_backward[] = {
-		9, 4, 8, 3, 7, 2, 6, 1, 5, 0
-	};
-	static const int test_hash_partial_forward[] = {
-		5, 6, 7
-	};
-	static const int test_hash_partial_backward[] = {
-		7, 6, 5
-	};
-
-	/* Duplicate identifier order */
-	static const int test_dup_allow_forward[] = {
-		0, 1, 2, 3, 2
-	};
-	static const int test_dup_allow_backward[] = {
-		2, 3, 2, 1, 0
-	};
-	static const int test_dup_reject[] = {
-		0
-	};
-	static const int test_dup_obj_reject_forward[] = {
-		0, 1, 2, 3
-	};
-	static const int test_dup_obj_reject_backward[] = {
-		3, 2, 1, 0
-	};
-	static const int test_dup_replace[] = {
-		2
-	};
-
-	ast_test_status_update(test, "Test %d, %s containers.\n",
-		tst_num, test_container2str(type));
-
-	/* Create container that inserts duplicate objects after matching objects. */
-	c1 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW);
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_ALLOW)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Create container that inserts duplicate objects before matching objects. */
-	c2 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN | AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW);
-	if (!c2) {
-		ast_test_status_update(test, "Container c2 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_ALLOW)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-#if defined(TEST_CONTAINER_DEBUG_DUMP)
-	ao2_container_dump(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
-	ao2_container_stats(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
-	ao2_container_dump(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
-	ao2_container_stats(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
-#endif	/* defined(TEST_CONTAINER_DEBUG_DUMP) */
-
-	/* Check container iteration directions */
-	switch (type) {
-	case TEST_CONTAINER_RBTREE:
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_iteration(res, c1, 0,
-			test_forward, ARRAY_LEN(test_forward),
-			"Iteration (ascending)", test);
-		res = test_ao2_iteration(res, c1, AO2_ITERATOR_DESCENDING,
-			test_backward, ARRAY_LEN(test_backward),
-			"Iteration (descending)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_iteration(res, c1, 0,
-			test_hash_forward, ARRAY_LEN(test_hash_forward),
-			"Iteration (ascending)", test);
-		res = test_ao2_iteration(res, c1, AO2_ITERATOR_DESCENDING,
-			test_hash_backward, ARRAY_LEN(test_hash_backward),
-			"Iteration (descending)", test);
-		break;
-	}
-
-	/* Check container traversal directions */
-	switch (type) {
-	case TEST_CONTAINER_RBTREE:
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_forward, ARRAY_LEN(test_forward),
-			"Traversal (ascending)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_backward, ARRAY_LEN(test_backward),
-			"Traversal (descending)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_ASCENDING, NULL, NULL,
-			test_hash_forward, ARRAY_LEN(test_hash_forward),
-			"Traversal (ascending, insert end)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_ORDER_DESCENDING, NULL, NULL,
-			test_hash_backward, ARRAY_LEN(test_hash_backward),
-			"Traversal (descending)", test);
-		break;
-	}
-
-	/* Check traversal with OBJ_PARTIAL_KEY search range. */
-	partial = 6;
-	partial_key_match_range = 1;
-	switch (type) {
-	case TEST_CONTAINER_RBTREE:
-	case TEST_CONTAINER_LIST:
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_ASCENDING,
-			test_cmp_cb, &partial,
-			test_partial_forward, ARRAY_LEN(test_partial_forward),
-			"Traversal OBJ_PARTIAL_KEY (ascending)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_DESCENDING,
-			test_cmp_cb, &partial,
-			test_partial_backward, ARRAY_LEN(test_partial_backward),
-			"Traversal OBJ_PARTIAL_KEY (descending)", test);
-		break;
-	case TEST_CONTAINER_HASH:
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_ASCENDING,
-			test_cmp_cb, &partial,
-			test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
-			"Traversal OBJ_PARTIAL_KEY (ascending)", test);
-		res = test_ao2_callback_traversal(res, c1, OBJ_PARTIAL_KEY | OBJ_ORDER_DESCENDING,
-			test_cmp_cb, &partial,
-			test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
-			"Traversal OBJ_PARTIAL_KEY (descending)", test);
-		break;
-	}
-
-	/* Add duplicates to initial containers that allow duplicates */
-	if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_ALLOW)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_ALLOW)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-#if defined(TEST_CONTAINER_DEBUG_DUMP)
-	ao2_container_dump(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
-	ao2_container_stats(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
-	ao2_container_dump(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
-	ao2_container_stats(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
-#endif	/* defined(TEST_CONTAINER_DEBUG_DUMP) */
-
-	/* Check duplicates in containers that allow duplicates. */
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
-		test_dup_allow_forward, ARRAY_LEN(test_dup_allow_forward),
-		"Duplicates (ascending, DUPS_ALLOW)", test);
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
-		test_dup_allow_backward, ARRAY_LEN(test_dup_allow_backward),
-		"Duplicates (descending, DUPS_ALLOW)", test);
-
-	ao2_t_ref(c1, -1, "bye c1");
-	c1 = NULL;
-	ao2_t_ref(c2, -1, "bye c2");
-	c2 = NULL;
-
-	/* Create containers that reject duplicate keyed objects. */
-	c1 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT);
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	c2 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN | AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT);
-	if (!c2) {
-		ast_test_status_update(test, "Container c2 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Check duplicates in containers that reject duplicate keyed objects. */
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
-		test_dup_reject, ARRAY_LEN(test_dup_reject),
-		"Duplicates (ascending, DUPS_REJECT)", test);
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
-		test_dup_reject, ARRAY_LEN(test_dup_reject),
-		"Duplicates (descending, DUPS_REJECT)", test);
-
-	ao2_t_ref(c1, -1, "bye c1");
-	c1 = NULL;
-	ao2_t_ref(c2, -1, "bye c2");
-	c2 = NULL;
-
-	/* Create containers that reject duplicate objects. */
-	c1 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT);
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_OBJ_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_OBJ_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	c2 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN | AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT);
-	if (!c2) {
-		ast_test_status_update(test, "Container c2 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_OBJ_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_OBJ_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Check duplicates in containers that reject duplicate objects. */
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
-		test_dup_obj_reject_forward, ARRAY_LEN(test_dup_obj_reject_forward),
-		"Duplicates (ascending, DUPS_OBJ_REJECT)", test);
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
-		test_dup_obj_reject_backward, ARRAY_LEN(test_dup_obj_reject_backward),
-		"Duplicates (descending, DUPS_OBJ_REJECT)", test);
-
-	ao2_t_ref(c1, -1, "bye c1");
-	c1 = NULL;
-	ao2_t_ref(c2, -1, "bye c2");
-	c2 = NULL;
-
-	/* Create container that replaces duplicate keyed objects. */
-	c1 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE);
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	c2 = test_make_sorted(type, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN | AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE);
-	if (!c2) {
-		ast_test_status_update(test, "Container c2 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REPLACE)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-	if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REPLACE)", test)) {
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	/* Check duplicates in containers that replaces duplicate keyed objects. */
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
-		test_dup_replace, ARRAY_LEN(test_dup_replace),
-		"Duplicates (ascending, DUPS_REPLACE)", test);
-	res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
-		test_dup_replace, ARRAY_LEN(test_dup_replace),
-		"Duplicates (descending, DUPS_REPLACE)", test);
-
-test_cleanup:
-	/* destroy containers */
-	if (c1) {
-		ao2_t_ref(c1, -1, "bye c1");
-	}
-	if (c2) {
-		ao2_t_ref(c2, -1, "bye c2");
-	}
-
-	if (destructor_count > 0) {
-		ast_test_status_update(test,
-			"all destructors were not called, destructor count is %d\n",
-			destructor_count);
-		res = AST_TEST_FAIL;
-	} else if (destructor_count < 0) {
-		ast_test_status_update(test,
-			"Destructor was called too many times, destructor count is %d\n",
-			destructor_count);
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(astobj2_test_4)
-{
-	int res = AST_TEST_PASS;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "astobj2_test4";
-		info->category = "/main/astobj2/";
-		info->summary = "Test container traversal/iteration";
-		info->description =
-			"This test is to see if the container traversal/iteration works "
-			"as intended for each supported container type.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	res = test_traversal_nonsorted(res, 1, TEST_CONTAINER_LIST, test);
-	res = test_traversal_nonsorted(res, 2, TEST_CONTAINER_HASH, test);
-
-	res = test_traversal_sorted(res, 3, TEST_CONTAINER_LIST, test);
-	res = test_traversal_sorted(res, 4, TEST_CONTAINER_HASH, test);
-	res = test_traversal_sorted(res, 5, TEST_CONTAINER_RBTREE, test);
-
-	return res;
-}
-
-static enum ast_test_result_state test_performance(struct ast_test *test,
-	enum test_container_type type, unsigned int copt)
-{
-/*!
- * \brief The number of objects inserted and searched for in the container under test.
- */
-#define OBJS 73
-	int res = AST_TEST_PASS;
-	struct ao2_container *c1 = NULL;
-	struct test_obj *tobj[OBJS];
-	struct test_obj *tobj2;
-	int i;
-
-	switch (type) {
-	case TEST_CONTAINER_HASH:
-		c1 = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, copt, 17,
-			test_hash_cb, test_sort_cb, test_cmp_cb);
-		break;
-	case TEST_CONTAINER_LIST:
-		c1 = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, copt,
-			test_sort_cb, test_cmp_cb);
-		break;
-	case TEST_CONTAINER_RBTREE:
-		c1 = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, copt,
-			test_sort_cb, test_cmp_cb);
-		break;
-	}
-
-	for (i = 0; i < OBJS; i++) {
-		tobj[i] = NULL;
-	}
-
-	if (!c1) {
-		ast_test_status_update(test, "Container c1 creation failed.\n");
-		res = AST_TEST_FAIL;
-		goto test_cleanup;
-	}
-
-	for (i = 0; i < OBJS; i++) {
-		tobj[i] = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
-		if (!tobj[i]) {
-			ast_test_status_update(test, "test object creation failed.\n");
-			res = AST_TEST_FAIL;
-			goto test_cleanup;
-		}
-		tobj[i]->i = i;
-		ao2_link(c1, tobj[i]);
-	}
-
-	for (i = 0; i < OBJS; i++) {
-		if ((!(tobj2 = ao2_find(c1, &i, OBJ_KEY)))) {
-			ast_test_status_update(test, "Should have found object %d in container.\n", i);
-			res = AST_TEST_FAIL;
-			goto test_cleanup;
-		}
-		ao2_ref(tobj2, -1);
-		tobj2 = NULL;
-	}
-
-test_cleanup:
-	for (i = 0; i < OBJS ; i++) {
-		ao2_cleanup(tobj[i]);
-	}
-	ao2_cleanup(c1);
-	return res;
-}
-
-static enum ast_test_result_state testloop(struct ast_test *test,
-	enum test_container_type type, int copt, int iterations)
-{
-	int res = AST_TEST_PASS;
-	int i;
-	struct timeval start;
-
-	start = ast_tvnow();
-	for (i = 1 ; i <= iterations && res == AST_TEST_PASS ; i++) {
-		res = test_performance(test, type, copt);
-	}
-	ast_test_status_update(test, "%5.2fK traversals, %9s : %5lu ms\n",
-		iterations / 1000.0, test_container2str(type), (unsigned long)ast_tvdiff_ms(ast_tvnow(), start));
-	return res;
-}
-
-AST_TEST_DEFINE(astobj2_test_perf)
-{
-/*!
- * \brief The number of iteration of testloop to be performed.
- * \note
- * In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect,
- * only 25000 iterations are performed.   Otherwise 100000.
- */
-#ifdef AO2_DEBUG
-#define ITERATIONS 25000
-#else
-#define ITERATIONS 100000
-#endif
-
-	int res = AST_TEST_PASS;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "astobj2_test_perf";
-		info->category = "/main/astobj2/perf";
-		info->summary = "Test container performance";
-		info->description =
-			"Runs container traversal tests.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	res = testloop(test, TEST_CONTAINER_LIST, 0, ITERATIONS);
-	if (!res) {
-		return res;
-	}
-	res = testloop(test, TEST_CONTAINER_HASH, 0, ITERATIONS);
-	if (!res) {
-		return res;
-	}
-	res = testloop(test, TEST_CONTAINER_RBTREE, 0, ITERATIONS);
-
-	return res;
-}
-
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(astobj2_test_1);
 	AST_TEST_UNREGISTER(astobj2_test_2);
 	AST_TEST_UNREGISTER(astobj2_test_3);
-	AST_TEST_UNREGISTER(astobj2_test_4);
-	AST_TEST_UNREGISTER(astobj2_test_perf);
 	return 0;
 }
 
@@ -2063,8 +711,6 @@ static int load_module(void)
 	AST_TEST_REGISTER(astobj2_test_1);
 	AST_TEST_REGISTER(astobj2_test_2);
 	AST_TEST_REGISTER(astobj2_test_3);
-	AST_TEST_REGISTER(astobj2_test_4);
-	AST_TEST_REGISTER(astobj2_test_perf);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/tests/test_astobj2_thrash.c b/tests/test_astobj2_thrash.c
index 1d8aaf6..814234c 100644
--- a/tests/test_astobj2_thrash.c
+++ b/tests/test_astobj2_thrash.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <pthread.h>
 #include "asterisk/astobj2.h"
 #include "asterisk/hashtab.h"
diff --git a/tests/test_bucket.c b/tests/test_bucket.c
deleted file mode 100644
index 13fd684..0000000
--- a/tests/test_bucket.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Bucket Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include <sys/stat.h>
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/bucket.h"
-#include "asterisk/logger.h"
-#include "asterisk/json.h"
-#include "asterisk/file.h"
-
-/*! \brief Test state structure for scheme wizards */
-struct bucket_test_state {
-	/*! \brief Whether the object has been created or not */
-	unsigned int created:1;
-	/*! \brief Whether the object has been updated or not */
-	unsigned int updated:1;
-	/*! \brief Whether the object has been deleted or not */
-	unsigned int deleted:1;
-};
-
-/*! \brief Global scope structure for testing bucket wizards */
-static struct bucket_test_state bucket_test_wizard_state;
-
-static void bucket_test_wizard_clear(void)
-{
-	bucket_test_wizard_state.created = 0;
-	bucket_test_wizard_state.updated = 0;
-	bucket_test_wizard_state.deleted = 0;
-}
-
-static int bucket_test_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	if (bucket_test_wizard_state.created) {
-		return -1;
-	}
-
-	bucket_test_wizard_state.created = 1;
-
-	return 0;
-}
-
-static int bucket_test_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	if (bucket_test_wizard_state.updated) {
-		return -1;
-	}
-
-	bucket_test_wizard_state.updated = 1;
-
-	return 0;
-}
-
-static void *bucket_test_wizard_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type,
-	const char *id)
-{
-	if (!strcmp(type, "bucket")) {
-		return ast_bucket_alloc(id);
-	} else if (!strcmp(type, "file")) {
-		return ast_bucket_file_alloc(id);
-	} else {
-		return NULL;
-	}
-}
-
-static int bucket_test_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	if (bucket_test_wizard_state.deleted) {
-		return -1;
-	}
-
-	bucket_test_wizard_state.deleted = 1;
-
-	return 0;
-}
-
-static struct ast_sorcery_wizard bucket_test_wizard = {
-	.name = "test",
-	.create = bucket_test_wizard_create,
-	.retrieve_id = bucket_test_wizard_retrieve_id,
-	.delete = bucket_test_wizard_delete,
-};
-
-static struct ast_sorcery_wizard bucket_file_test_wizard = {
-	.name = "test",
-	.create = bucket_test_wizard_create,
-	.update = bucket_test_wizard_update,
-	.retrieve_id = bucket_test_wizard_retrieve_id,
-	.delete = bucket_test_wizard_delete,
-};
-
-AST_TEST_DEFINE(bucket_scheme_register)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_scheme_register_unregister";
-		info->category = "/main/bucket/";
-		info->summary = "bucket scheme registration/unregistration unit test";
-		info->description =
-			"Test registration and unregistration of bucket scheme";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!ast_bucket_scheme_register("", NULL, NULL, NULL, NULL)) {
-		ast_test_status_update(test, "Successfully registered a Bucket scheme without name or wizards\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard, NULL, NULL)) {
-		ast_test_status_update(test, "Successfully registered a Bucket scheme twice\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_alloc)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_alloc";
-		info->category = "/main/bucket/";
-		info->summary = "bucket allocation unit test";
-		info->description =
-			"Test allocation of buckets";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if ((bucket = ast_bucket_alloc(""))) {
-		ast_test_status_update(test, "Allocated a bucket with no URI provided\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(ast_sorcery_object_get_id(bucket), "test:///tmp/bob")) {
-		ast_test_status_update(test, "URI within allocated bucket is '%s' and should be test:///tmp/bob\n",
-			ast_sorcery_object_get_id(bucket));
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(bucket->scheme, "test")) {
-		ast_test_status_update(test, "Scheme within allocated bucket is '%s' and should be test\n",
-			bucket->scheme);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_create)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_create";
-		info->category = "/main/bucket/";
-		info->summary = "bucket creation unit test";
-		info->description =
-			"Test creation of buckets";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	bucket_test_wizard_clear();
-
-	if (ast_bucket_create(bucket)) {
-		ast_test_status_update(test, "Failed to create bucket with URI '%s'\n",
-			ast_sorcery_object_get_id(bucket));
-		return AST_TEST_FAIL;
-	}
-
-	if (!bucket_test_wizard_state.created) {
-		ast_test_status_update(test, "Bucket creation returned success but scheme implementation never actually created it\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_create(bucket)) {
-		ast_test_status_update(test, "Successfully created bucket with URI '%s' twice\n",
-			ast_sorcery_object_get_id(bucket));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_delete)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_delete";
-		info->category = "/main/bucket/";
-		info->summary = "bucket deletion unit test";
-		info->description =
-			"Test deletion of buckets";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	bucket_test_wizard_clear();
-
-	if (ast_bucket_delete(bucket)) {
-		ast_test_status_update(test, "Failed to delete bucket with URI '%s'\n",
-			ast_sorcery_object_get_id(bucket));
-		return AST_TEST_FAIL;
-	}
-
-	if (!bucket_test_wizard_state.deleted) {
-		ast_test_status_update(test, "Bucket deletion returned success but scheme implementation never actually deleted it\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_delete(bucket)) {
-		ast_test_status_update(test, "Successfully deleted bucket with URI '%s' twice\n",
-			ast_sorcery_object_get_id(bucket));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_json)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_json";
-		info->category = "/main/bucket/";
-		info->summary = "bucket json unit test";
-		info->description =
-			"Test creation of JSON for a bucket";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_container_add(bucket->buckets, "test:///tmp/bob/joe");
-	ast_str_container_add(bucket->files, "test:///tmp/bob/recording.wav");
-
-	expected = ast_json_pack("{s: s, s: s, s: [s], s: s, s: [s], s: s}",
-		"modified", "0.000000", "created", "0.000000",
-		"buckets", "test:///tmp/bob/joe",
-		"scheme", "test",
-		"files", "test:///tmp/bob/recording.wav",
-		"id", "test:///tmp/bob");
-	if (!expected) {
-		ast_test_status_update(test, "Could not produce JSON for expected bucket value\n");
-		return AST_TEST_FAIL;
-	}
-
-	json = ast_bucket_json(bucket);
-	if (!json) {
-		ast_test_status_update(test, "Could not produce JSON for a valid bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_json_equal(json, expected)) {
-		ast_test_status_update(test, "Bucket JSON does not match expected output\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_retrieve)
-{
-	RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_retrieve";
-		info->category = "/main/bucket/";
-		info->summary = "bucket retrieval unit test";
-		info->description =
-			"Test retrieval of buckets";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(bucket = ast_bucket_retrieve("test://tmp/bob"))) {
-		ast_test_status_update(test, "Failed to retrieve known valid bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_alloc)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_alloc";
-		info->category = "/main/bucket/";
-		info->summary = "bucket file allocation unit test";
-		info->description =
-			"Test allocation of bucket files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if ((file = ast_bucket_file_alloc(""))) {
-		ast_test_status_update(test, "Allocated a file with no URI provided\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_strlen_zero(file->path)) {
-		ast_test_status_update(test, "Expected temporary path in allocated file");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(ast_sorcery_object_get_id(file), "test:///tmp/bob")) {
-		ast_test_status_update(test, "URI within allocated file is '%s' and should be test:///tmp/bob\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(file->scheme, "test")) {
-		ast_test_status_update(test, "Scheme within allocated file is '%s' and should be test\n",
-			file->scheme);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_create)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_create";
-		info->category = "/main/bucket/";
-		info->summary = "file creation unit test";
-		info->description =
-			"Test creation of files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	bucket_test_wizard_clear();
-
-	if (ast_bucket_file_create(file)) {
-		ast_test_status_update(test, "Failed to create file with URI '%s'\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	if (!bucket_test_wizard_state.created) {
-		ast_test_status_update(test, "Bucket file creation returned success but scheme implementation never actually created it\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_file_create(file)) {
-		ast_test_status_update(test, "Successfully created file with URI '%s' twice\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_copy)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bucket_file *, copy, NULL, ao2_cleanup);
-	FILE *temporary;
-	struct stat old, new;
-	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_copy";
-		info->category = "/main/bucket/";
-		info->summary = "bucket file copying unit test";
-		info->description =
-			"Test copying of bucket files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_bucket_file_metadata_set(file, "bob", "joe");
-
-	if (!(temporary = fopen(file->path, "w"))) {
-		ast_test_status_update(test, "Failed to open temporary file '%s'\n", file->path);
-		return AST_TEST_FAIL;
-	}
-
-	fprintf(temporary, "bob");
-	fclose(temporary);
-
-	if (!(copy = ast_bucket_file_copy(file, "test:///tmp/bob2"))) {
-		ast_test_status_update(test, "Failed to copy file '%s' to test:///tmp/bob2\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	if (stat(file->path, &old)) {
-		ast_test_status_update(test, "Failed to retrieve information on old file '%s'\n", file->path);
-		return AST_TEST_FAIL;
-	}
-
-	if (stat(copy->path, &new)) {
-		ast_test_status_update(test, "Failed to retrieve information on copy file '%s'\n", copy->path);
-		return AST_TEST_FAIL;
-	}
-
-	if (old.st_size != new.st_size) {
-		ast_test_status_update(test, "Copying of underlying temporary file failed\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ao2_container_count(file->metadata) != ao2_container_count(copy->metadata)) {
-		ast_test_status_update(test, "Number of metadata entries does not match original\n");
-		return AST_TEST_FAIL;
-	}
-
-	metadata = ast_bucket_file_metadata_get(copy, "bob");
-	if (!metadata) {
-		ast_test_status_update(test, "Copy of file does not have expected metadata\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(metadata->value, "joe")) {
-		ast_test_status_update(test, "Copy of file contains metadata for 'bob' but value is not what it should be\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_retrieve)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_retrieve";
-		info->category = "/main/bucket/";
-		info->summary = "file retrieval unit test";
-		info->description =
-			"Test retrieval of files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_retrieve("test://tmp/bob"))) {
-		ast_test_status_update(test, "Failed to retrieve known valid file\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_update)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_update";
-		info->category = "/main/bucket/";
-		info->summary = "file updating unit test";
-		info->description =
-			"Test updating of files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	bucket_test_wizard_clear();
-
-	if (ast_bucket_file_update(file)) {
-		ast_test_status_update(test, "Failed to update file with URI '%s'\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	if (!bucket_test_wizard_state.updated) {
-		ast_test_status_update(test, "Successfully returned file was updated, but it was not\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_file_update(file)) {
-		ast_test_status_update(test, "Successfully updated file with URI '%s' twice\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_delete)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_delete";
-		info->category = "/main/bucket/";
-		info->summary = "file deletion unit test";
-		info->description =
-			"Test deletion of files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	bucket_test_wizard_clear();
-
-	if (ast_bucket_file_delete(file)) {
-		ast_test_status_update(test, "Failed to delete file with URI '%s'\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	if (!bucket_test_wizard_state.deleted) {
-		ast_test_status_update(test, "Bucket file deletion returned success but scheme implementation never actually deleted it\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_bucket_file_delete(file)) {
-		ast_test_status_update(test, "Successfully deleted file with URI '%s' twice\n",
-			ast_sorcery_object_get_id(file));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_metadata_set)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_metadata_set";
-		info->category = "/main/bucket/";
-		info->summary = "file metadata setting unit test";
-		info->description =
-			"Test setting of metadata on files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ao2_container_count(file->metadata) != 0) {
-		ast_test_status_update(test, "Newly allocated file has metadata count of '%d' when should be 0\n",
-			ao2_container_count(file->metadata));
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
-		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
-		ast_test_status_update(test, "Failed to find set metadata 'bob' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(metadata->value, "joe")) {
-		ast_test_status_update(test, "Metadata has value '%s' when should be 'joe'\n",
-			metadata->value);
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(metadata);
-	metadata = NULL;
-
-	if (ast_bucket_file_metadata_set(file, "bob", "fred")) {
-		ast_test_status_update(test, "Failed to overwrite metadata 'bob' with new value 'fred'\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
-		ast_test_status_update(test, "Failed to find overwritten metadata 'bob' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(metadata->value, "fred")) {
-		ast_test_status_update(test, "Metadata has value '%s' when should be 'fred'\n",
-			metadata->value);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_metadata_unset)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_metadata_unset";
-		info->category = "/main/bucket/";
-		info->summary = "file metadata unsetting unit test";
-		info->description =
-			"Test unsetting of metadata on files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
-		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bucket_file_metadata_unset(file, "bob")) {
-		ast_test_status_update(test, "Failed to unset metadata 'bob' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
-		ast_test_status_update(test, "Metadata 'bob' was unset, but can still be found\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_metadata_get)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_metadata_get";
-		info->category = "/main/bucket/";
-		info->summary = "file metadata getting unit test";
-		info->description =
-			"Test getting of metadata on files";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
-		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(metadata = ast_bucket_file_metadata_get(file, "bob"))) {
-		ast_test_status_update(test, "Failed to retrieve metadata 'bob' that was just set\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (strcmp(metadata->value, "joe")) {
-		ast_test_status_update(test, "Retrieved metadata value is '%s' while it should be 'joe'\n",
-			metadata->value);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_json)
-{
-	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bucket_file_json";
-		info->category = "/main/bucket/";
-		info->summary = "file json unit test";
-		info->description =
-			"Test creation of JSON for a file";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
-		ast_test_status_update(test, "Failed to allocate bucket\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
-		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
-		return AST_TEST_FAIL;
-	}
-
-	expected = ast_json_pack("{s: s, s: s, s: s, s: s, s: {s :s}}",
-		"modified", "0.000000", "created", "0.000000", "scheme", "test",
-		"id", "test:///tmp/bob", "metadata", "bob", "joe");
-	if (!expected) {
-		ast_test_status_update(test, "Could not produce JSON for expected bucket file value\n");
-		return AST_TEST_FAIL;
-	}
-
-	json = ast_bucket_file_json(file);
-	if (!json) {
-		ast_test_status_update(test, "Could not produce JSON for a valid file\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_json_equal(json, expected)) {
-		ast_test_status_update(test, "Bucket file JSON does not match expected output\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(bucket_scheme_register);
-	AST_TEST_UNREGISTER(bucket_alloc);
-	AST_TEST_UNREGISTER(bucket_create);
-	AST_TEST_UNREGISTER(bucket_delete);
-	AST_TEST_UNREGISTER(bucket_retrieve);
-	AST_TEST_UNREGISTER(bucket_json);
-	AST_TEST_UNREGISTER(bucket_file_alloc);
-	AST_TEST_UNREGISTER(bucket_file_create);
-	AST_TEST_UNREGISTER(bucket_file_copy);
-	AST_TEST_UNREGISTER(bucket_file_retrieve);
-	AST_TEST_UNREGISTER(bucket_file_update);
-	AST_TEST_UNREGISTER(bucket_file_delete);
-	AST_TEST_UNREGISTER(bucket_file_metadata_set);
-	AST_TEST_UNREGISTER(bucket_file_metadata_unset);
-	AST_TEST_UNREGISTER(bucket_file_metadata_get);
-	AST_TEST_UNREGISTER(bucket_file_json);
-	return 0;
-}
-
-static int load_module(void)
-{
-	if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard,
-		ast_bucket_file_temporary_create, ast_bucket_file_temporary_destroy)) {
-		ast_log(LOG_ERROR, "Failed to register Bucket test wizard scheme implementation\n");
-		return AST_MODULE_LOAD_FAILURE;
-	}
-
-	AST_TEST_REGISTER(bucket_scheme_register);
-	AST_TEST_REGISTER(bucket_alloc);
-	AST_TEST_REGISTER(bucket_create);
-	AST_TEST_REGISTER(bucket_delete);
-	AST_TEST_REGISTER(bucket_retrieve);
-	AST_TEST_REGISTER(bucket_json);
-	AST_TEST_REGISTER(bucket_file_alloc);
-	AST_TEST_REGISTER(bucket_file_create);
-	AST_TEST_REGISTER(bucket_file_copy);
-	AST_TEST_REGISTER(bucket_file_retrieve);
-	AST_TEST_REGISTER(bucket_file_update);
-	AST_TEST_REGISTER(bucket_file_delete);
-	AST_TEST_REGISTER(bucket_file_metadata_set);
-	AST_TEST_REGISTER(bucket_file_metadata_unset);
-	AST_TEST_REGISTER(bucket_file_metadata_get);
-	AST_TEST_REGISTER(bucket_file_json);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bucket test module");
diff --git a/tests/test_callerid.c b/tests/test_callerid.c
index f8f6047..d0788a4 100644
--- a/tests/test_callerid.c
+++ b/tests/test_callerid.c
@@ -34,7 +34,7 @@
 #include "asterisk.h"
 #include "asterisk/callerid.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425155 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/tests/test_cdr.c b/tests/test_cdr.c
deleted file mode 100644
index 6bc810c..0000000
--- a/tests/test_cdr.c
+++ /dev/null
@@ -1,2630 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief CDR unit tests
- *
- * \author Matt Jordan <mjordan at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423783 $")
-
-#include <math.h>
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/cdr.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/chanvars.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/time.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/format_cache.h"
-
-#define EPSILON 0.001
-
-#define TEST_CATEGORY "/main/cdr/"
-
-#define MOCK_CDR_BACKEND "mock_cdr_backend"
-
-#define CHANNEL_TECH_NAME "CDRTestChannel"
-
-/*! \brief A placeholder for Asterisk's 'real' CDR configuration */
-static struct ast_cdr_config *saved_config;
-
-/*! \brief A configuration suitable for 'normal' CDRs */
-static struct ast_cdr_config debug_cdr_config = {
-	.settings.flags = CDR_ENABLED | CDR_DEBUG,
-};
-
-/*! \brief A configuration suitable for CDRs with unanswered records */
-static struct ast_cdr_config unanswered_cdr_config = {
-	.settings.flags = CDR_ENABLED | CDR_UNANSWERED | CDR_DEBUG,
-};
-
-/*! \brief A configuration suitable for CDRs with congestion enabled */
-static struct ast_cdr_config congestion_cdr_config = {
-	.settings.flags = CDR_ENABLED | CDR_UNANSWERED | CDR_DEBUG | CDR_CONGESTION,
-};
-
-/*! \brief Macro to swap a configuration out from the CDR engine. This should be
- * used at the beginning of each test to set the needed configuration for that
- * test.
- */
-#define SWAP_CONFIG(ao2_config, template) do { \
-	*(ao2_config) = (template); \
-	ast_cdr_set_config((ao2_config)); \
-	} while (0)
-
-/*! \brief A linked list of received CDR entries from the engine */
-static AST_LIST_HEAD(, test_cdr_entry) actual_cdr_entries = AST_LIST_HEAD_INIT_VALUE;
-
-/*! \brief The Mock CDR backend condition wait */
-static ast_cond_t mock_cdr_cond;
-
-/*! \brief A channel technology used for the unit tests */
-static struct ast_channel_tech test_cdr_chan_tech = {
-	.type = CHANNEL_TECH_NAME,
-	.description = "Mock channel technology for CDR tests",
-};
-
-struct test_cdr_entry {
-	struct ast_cdr *cdr;
-	AST_LIST_ENTRY(test_cdr_entry) list;
-};
-
-/*! \brief The number of CDRs the mock backend has received */
-static int global_mock_cdr_count;
-
-/*! \internal
- * \brief Callback function for the mock CDR backend
- *
- * This function 'processes' a dispatched CDR record by adding it to the
- * \ref actual_cdr_entries list. When a test completes, it can verify the
- * expected records against this list of actual CDRs created by the engine.
- *
- * \param cdr The public CDR object created by the engine
- *
- * \retval -1 on error
- * \retval 0 on success
- */
-static int mock_cdr_backend_cb(struct ast_cdr *cdr)
-{
-	struct ast_cdr *cdr_copy, *cdr_prev = NULL;
-	struct ast_cdr *mock_cdr = NULL;
-	struct test_cdr_entry *cdr_wrapper;
-
-	cdr_wrapper = ast_calloc(1, sizeof(*cdr_wrapper));
-	if (!cdr_wrapper) {
-		return -1;
-	}
-
-	for (; cdr; cdr = cdr->next) {
-		struct ast_var_t *var_entry, *var_copy;
-
-		cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
-		if (!cdr_copy) {
-			return -1;
-		}
-		*cdr_copy = *cdr;
-		cdr_copy->varshead.first = NULL;
-		cdr_copy->varshead.last = NULL;
-		cdr_copy->next = NULL;
-
-		AST_LIST_TRAVERSE(&cdr->varshead, var_entry, entries) {
-			var_copy = ast_var_assign(var_entry->name, var_entry->value);
-			if (!var_copy) {
-				return -1;
-			}
-			AST_LIST_INSERT_TAIL(&cdr_copy->varshead, var_copy, entries);
-		}
-
-		if (!mock_cdr) {
-			mock_cdr = cdr_copy;
-		}
-		if (cdr_prev) {
-			cdr_prev->next = cdr_copy;
-		}
-		cdr_prev = cdr_copy;
-	}
-	cdr_wrapper->cdr = mock_cdr;
-
-	AST_LIST_LOCK(&actual_cdr_entries);
-	AST_LIST_INSERT_TAIL(&actual_cdr_entries, cdr_wrapper, list);
-	global_mock_cdr_count++;
-	ast_cond_signal(&mock_cdr_cond);
-	AST_LIST_UNLOCK(&actual_cdr_entries);
-
-	return 0;
-}
-
-/*! \internal
- * \brief Remove all entries from \ref actual_cdr_entries
- */
-static void clear_mock_cdr_backend(void)
-{
-	struct test_cdr_entry *cdr_wrapper;
-
-	AST_LIST_LOCK(&actual_cdr_entries);
-	while ((cdr_wrapper = AST_LIST_REMOVE_HEAD(&actual_cdr_entries, list))) {
-		ast_cdr_free(cdr_wrapper->cdr);
-		ast_free(cdr_wrapper);
-	}
-	global_mock_cdr_count = 0;
-	AST_LIST_UNLOCK(&actual_cdr_entries);
-}
-
-/*! \brief Verify a string field. This will set the test status result to fail;
- * as such, it assumes that (a) test is the test object variable, and (b) that
- * a return variable res exists.
- */
-#define VERIFY_STRING_FIELD(field, actual, expected) do { \
-	if (strcmp((actual)->field, (expected)->field)) { \
-		ast_test_status_update(test, "Field %s failed: actual %s, expected %s\n", #field, (actual)->field, (expected)->field); \
-		ast_test_set_result(test, AST_TEST_FAIL); \
-		res = AST_TEST_FAIL; \
-	} } while (0)
-
-/*! \brief Verify a numeric field. This will set the test status result to fail;
- * as such, it assumes that (a) test is the test object variable, and (b) that
- * a return variable res exists.
- */
-#define VERIFY_NUMERIC_FIELD(field, actual, expected) do { \
-	if ((actual)->field != (expected)->field) { \
-		ast_test_status_update(test, "Field %s failed: actual %ld, expected %ld\n", #field, (long)(actual)->field, (long)(expected)->field); \
-		ast_test_set_result(test, AST_TEST_FAIL); \
-		res = AST_TEST_FAIL; \
-	} } while (0)
-
-/*! \brief Verify a time field. This will set the test status result to fail;
- * as such, it assumes that (a) test is the test object variable, and (b) that
- * a return variable res exists.
- */
-#define VERIFY_TIME_VALUE(field, actual) do { \
-	if (ast_tvzero((actual)->field)) { \
-		ast_test_status_update(test, "Field %s failed: should not be 0\n", #field); \
-		ast_test_set_result(test, AST_TEST_FAIL); \
-		res = AST_TEST_FAIL; \
-	} } while (0)
-
-/*! \brief Alice's Caller ID */
-#define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
-
-/*! \brief Bob's Caller ID */
-#define BOB_CALLERID { .id.name.str = "Bob", .id.name.valid = 1, .id.number.str = "200", .id.number.valid = 1, }
-
-/*! \brief Charlie's Caller ID */
-#define CHARLIE_CALLERID { .id.name.str = "Charlie", .id.name.valid = 1, .id.number.str = "300", .id.number.valid = 1, }
-
-/*! \brief David's Caller ID */
-#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
-
-/*! \brief Copy the linkedid and uniqueid from a channel to an expected CDR */
-#define COPY_IDS(channel_var, expected_record) do { \
-	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
-	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
-	} while (0)
-
-/*! \brief Set ulaw format on channel */
-#define SET_FORMATS(chan) do {\
-	struct ast_format_cap *caps;\
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);\
-	ast_format_cap_append(caps, ast_format_ulaw, 0);\
-	ast_channel_nativeformats_set((chan), caps);\
-	ast_channel_set_writeformat((chan), ast_format_ulaw);\
-	ast_channel_set_rawwriteformat((chan), ast_format_ulaw);\
-	ast_channel_set_readformat((chan), ast_format_ulaw);\
-	ast_channel_set_rawreadformat((chan), ast_format_ulaw);\
-	ao2_ref(caps, -1);\
-} while (0)
-
-/*! \brief Create a \ref test_cdr_chan_tech for Alice, and set the expected
- * CDR records' linkedid and uniqueid. */
-#define CREATE_ALICE_CHANNEL(channel_var, caller_id, expected_record) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
-	SET_FORMATS((channel_var));\
-	ast_channel_set_caller((channel_var), (caller_id), NULL); \
-	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
-	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cdr_chan_tech for Bob, and set the expected
- * CDR records' linkedid and uniqueid. */
-#define CREATE_BOB_CHANNEL(channel_var, caller_id, expected_record) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
-	SET_FORMATS((channel_var));\
-	ast_channel_set_caller((channel_var), (caller_id), NULL); \
-	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
-	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
- * CDR records' linkedid and uniqueid. */
-#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id, expected_record) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Charlie", "300", "300", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
-	SET_FORMATS((channel_var));\
-	ast_channel_set_caller((channel_var), (caller_id), NULL); \
-	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
-	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
- * CDR records' linkedid and uniqueid. */
-#define CREATE_DAVID_CHANNEL(channel_var, caller_id, expected_record) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "400", "David", "400", "400", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/David"); \
-	SET_FORMATS((channel_var));\
-	ast_channel_set_caller((channel_var), (caller_id), NULL); \
-	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
-	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Emulate a channel entering into an application */
-#define EMULATE_APP_DATA(channel, priority, application, data) do { \
-	if ((priority) > 0) { \
-		ast_channel_priority_set((channel), (priority)); \
-	} \
-	ast_channel_lock((channel)); \
-	ast_channel_appl_set((channel), (application)); \
-	ast_channel_data_set((channel), (data)); \
-	ast_channel_publish_snapshot((channel)); \
-	ast_channel_unlock((channel)); \
-	} while (0)
-
-/*! \brief Hang up a test channel safely */
-#define HANGUP_CHANNEL(channel, cause) \
-	do { \
-		ast_channel_hangupcause_set((channel), (cause)); \
-		ast_hangup(channel); \
-		channel = NULL; \
-	} while (0)
-
-static enum ast_test_result_state verify_mock_cdr_record(struct ast_test *test, struct ast_cdr *expected, int record)
-{
-	struct ast_cdr *actual = NULL;
-	struct test_cdr_entry *cdr_wrapper;
-	int count = 0;
-	struct timeval wait_now = ast_tvnow();
-	struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 5, .tv_nsec = wait_now.tv_usec * 1000 };
-	enum ast_test_result_state res = AST_TEST_PASS;
-
-	while (count < record) {
-		AST_LIST_LOCK(&actual_cdr_entries);
-		if (global_mock_cdr_count < record) {
-			ast_cond_timedwait(&mock_cdr_cond, &actual_cdr_entries.lock, &wait_time);
-		}
-		cdr_wrapper = AST_LIST_REMOVE_HEAD(&actual_cdr_entries, list);
-		AST_LIST_UNLOCK(&actual_cdr_entries);
-
-		if (!cdr_wrapper) {
-			ast_test_status_update(test, "Unable to find actual CDR record at %d\n", count);
-			return AST_TEST_FAIL;
-		}
-		actual = cdr_wrapper->cdr;
-
-		if (!expected && actual) {
-			ast_test_status_update(test, "CDRs recorded where no record expected\n");
-			return AST_TEST_FAIL;
-		}
-		ast_test_debug(test, "Verifying expected record %s, %s\n",
-			expected->channel, S_OR(expected->dstchannel, "<none>"));
-		VERIFY_STRING_FIELD(accountcode, actual, expected);
-		VERIFY_NUMERIC_FIELD(amaflags, actual, expected);
-		VERIFY_STRING_FIELD(channel, actual, expected);
-		VERIFY_STRING_FIELD(clid, actual, expected);
-		VERIFY_STRING_FIELD(dcontext, actual, expected);
-		VERIFY_NUMERIC_FIELD(disposition, actual, expected);
-		VERIFY_STRING_FIELD(dst, actual, expected);
-		VERIFY_STRING_FIELD(dstchannel, actual, expected);
-		VERIFY_STRING_FIELD(lastapp, actual, expected);
-		VERIFY_STRING_FIELD(lastdata, actual, expected);
-		VERIFY_STRING_FIELD(linkedid, actual, expected);
-		VERIFY_STRING_FIELD(peeraccount, actual, expected);
-		VERIFY_STRING_FIELD(src, actual, expected);
-		VERIFY_STRING_FIELD(uniqueid, actual, expected);
-		VERIFY_STRING_FIELD(userfield, actual, expected);
-		VERIFY_TIME_VALUE(start, actual);
-		VERIFY_TIME_VALUE(end, actual);
-		/* Note: there's no way we can really calculate a duration or
-		 * billsec - the unit tests are too short. However, if billsec is
-		 * non-zero in the expected, then make sure we have an answer time
-		 */
-		if (expected->billsec) {
-			VERIFY_TIME_VALUE(answer, actual);
-		}
-		ast_test_debug(test, "Finished expected record %s, %s\n",
-				expected->channel, S_OR(expected->dstchannel, "<none>"));
-		expected = expected->next;
-		++count;
-	}
-	return res;
-}
-
-static void safe_channel_release(struct ast_channel *chan)
-{
-	if (!chan) {
-		return;
-	}
-	ast_channel_release(chan);
-}
-
-static void safe_bridge_destroy(struct ast_bridge *bridge)
-{
-	if (!bridge) {
-		return;
-	}
-	ast_bridge_destroy(bridge, 0);
-}
-
-static void do_sleep(struct timespec *to_sleep)
-{
-	while ((nanosleep(to_sleep, to_sleep) == -1) && (errno == EINTR)) {
-	}
-}
-
-AST_TEST_DEFINE(test_cdr_channel_creation)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test that a CDR is created when a channel is created";
-		info->description =
-			"Test that a CDR is created when a channel is created";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, (&caller), &expected);
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_unanswered_inbound_call)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Wait",
-		.lastdata = "1",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test inbound unanswered calls";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"inbound to Asterisk, executes some dialplan, but\n"
-			"is never answered.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
-
-	EMULATE_APP_DATA(chan, 1, "Wait", "1");
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_unanswered_outbound_call)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = {
-			.id.name.str = "",
-			.id.name.valid = 1,
-			.id.number.str = "",
-			.id.number.valid = 1, };
-	struct ast_cdr expected = {
-		.clid = "\"\" <>",
-		.dst = "s",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "AppDial",
-		.lastdata = "(Outgoing Line)",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test outbound unanswered calls";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"outbound to Asterisk but is never answered.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
-
-	ast_channel_exten_set(chan, "s");
-	ast_channel_context_set(chan, "default");
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
-	EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_outbound_bridged_call)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr alice_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "",
-		.lastdata = "",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	struct ast_cdr bob_expected = {
-		.clid = "\"\" <>",
-		.src = "",
-		.dst = "s",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.dstchannel = "",
-		.lastapp = "AppDial",
-		.lastdata = "(Outgoing Line)",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-		.peeraccount = "",
-		.next = &alice_expected,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a 2-party bridge";
-		info->description =
-			"The most 'basic' of scenarios\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &caller, &alice_expected);
-	ast_channel_state_set(chan_alice, AST_STATE_UP);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_alice, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_bob);
-	ast_channel_unlock(chan_bob);
-	ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_bob), sizeof(bob_expected.linkedid));
-	ast_copy_string(bob_expected.uniqueid, ast_channel_uniqueid(chan_bob), sizeof(bob_expected.uniqueid));
-	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
-	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_ORIGINATED);
-	EMULATE_APP_DATA(chan_bob, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(NULL, chan_bob, "Bob", NULL);
-	ast_channel_state_set(chan_bob, AST_STATE_RINGING);
-	ast_channel_publish_dial(NULL, chan_bob, NULL, "ANSWER");
-
-	ast_channel_state_set(chan_bob, AST_STATE_UP);
-
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_bob);
-	ast_bridge_depart(chan_alice);
-
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &bob_expected, 2);
-	return result;
-}
-
-
-AST_TEST_DEFINE(test_cdr_single_party)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = "",
-		.lastapp = "VoiceMailMain",
-		.lastdata = "1",
-		.billsec = 1,
-	.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, but only involves a single channel\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
-
-	ast_channel_lock(chan);
-	EMULATE_APP_DATA(chan, 1, "Answer", "");
-	ast_setstate(chan, AST_STATE_UP);
-	EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1");
-	ast_channel_unlock(chan);
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_single_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering/leaving a bridge";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, enters a bridge, and leaves it.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
-
-	ast_channel_lock(chan);
-	EMULATE_APP_DATA(chan, 1, "Answer", "");
-	ast_setstate(chan, AST_STATE_UP);
-	EMULATE_APP_DATA(chan, 2, "Bridge", "");
-	ast_channel_unlock(chan);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan);
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_single_bridge_continue)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Wait",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	struct ast_cdr expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.next = &expected_two,
-	};
-
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering/leaving a bridge";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, enters a bridge, and leaves it.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected_one);
-	COPY_IDS(chan, &expected_two);
-
-	ast_channel_lock(chan);
-	EMULATE_APP_DATA(chan, 1, "Answer", "");
-	ast_setstate(chan, AST_STATE_UP);
-	EMULATE_APP_DATA(chan, 2, "Bridge", "");
-	ast_channel_unlock(chan);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan);
-
-	EMULATE_APP_DATA(chan, 3, "Wait", "");
-
-	/* And then it hangs up */
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected_one, 2);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_single_twoparty_bridge_a)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-	struct ast_cdr bob_expected = {
-		.clid = "\"Bob\" <200>",
-		.src = "200",
-		.dst = "200",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-	};
-	struct ast_cdr alice_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-		.next = &bob_expected,
-	};
-
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering/leaving a bridge";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, enters a bridge, and leaves it. In this scenario, the\n"
-			"Party A should answer the bridge first.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice, &alice_expected);
-
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob, &bob_expected);
-	ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected.linkedid));
-
-	ast_channel_lock(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 1, "Answer", "");
-	ast_setstate(chan_alice, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-	ast_channel_unlock(chan_alice);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-
-	ast_channel_lock(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 1, "Answer", "");
-	ast_setstate(chan_bob, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-	ast_channel_unlock(chan_bob);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_alice);
-	ast_bridge_depart(chan_bob);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected, 2);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_single_twoparty_bridge_b)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-	struct ast_cdr bob_expected = {
-		.clid = "\"Bob\" <200>",
-		.src = "200",
-		.dst = "200",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-	};
-	struct ast_cdr alice_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-		.next = &bob_expected,
-	};
-
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering/leaving a bridge";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, enters a bridge, and leaves it. In this scenario, the\n"
-			"Party B should answer the bridge first.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice, &alice_expected);
-
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob, &bob_expected);
-	ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected.linkedid));
-
-	ast_channel_unlock(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 1, "Answer", "");
-	ast_setstate(chan_alice, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-	ast_channel_unlock(chan_alice);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	ast_channel_lock(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 1, "Answer", "");
-	ast_setstate(chan_bob, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-	ast_channel_unlock(chan_bob);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_alice);
-	ast_bridge_depart(chan_bob);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected, 2);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_single_multiparty_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-	struct ast_party_caller caller_charlie = CHARLIE_CALLERID;
-	struct ast_cdr charlie_expected = {
-		.clid = "\"Charlie\" <300>",
-		.src = "300",
-		.dst = "300",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Charlie",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "300",
-	};
-	struct ast_cdr bob_expected = {
-		.clid = "\"Bob\" <200>",
-		.src = "200",
-		.dst = "200",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.dstchannel = CHANNEL_TECH_NAME "/Charlie",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-		.peeraccount = "300",
-		.next = &charlie_expected,
-	};
-	struct ast_cdr alice_expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Charlie",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "300",
-		.next = &bob_expected,
-	};
-	struct ast_cdr alice_expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Bridge",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-		.next = &alice_expected_two,
-	};
-
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering/leaving a multi-party bridge";
-		info->description =
-			"Test the properties of a CDR for a call that is\n"
-			"answered, enters a bridge, and leaves it. A total of three\n"
-			"parties perform this action.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice, &alice_expected_one);
-	COPY_IDS(chan_alice, &alice_expected_two);
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob, &bob_expected);
-	ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected.linkedid));
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &caller_charlie, &charlie_expected);
-	ast_copy_string(charlie_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(charlie_expected.linkedid));
-
-	ast_channel_lock(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 1, "Answer", "");
-	ast_setstate(chan_alice, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-	ast_channel_unlock(chan_alice);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	ast_channel_lock(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 1, "Answer", "");
-	ast_setstate(chan_bob, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-	ast_channel_unlock(chan_bob);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_channel_lock(chan_charlie);
-	EMULATE_APP_DATA(chan_charlie, 1, "Answer", "");
-	ast_setstate(chan_charlie, AST_STATE_UP);
-	EMULATE_APP_DATA(chan_charlie, 2, "Bridge", "");
-	ast_channel_unlock(chan_charlie);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_charlie, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_alice);
-	ast_bridge_depart(chan_bob);
-	ast_bridge_depart(chan_charlie);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected_one, 4);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_unanswered)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CDRs for a dial that isn't answered";
-		info->description =
-			"Test the properties of a CDR for a channel that\n"
-			"performs a dial operation that isn't answered\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", "CDRTestChannel/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-
-AST_TEST_DEFINE(test_cdr_dial_busy)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_BUSY,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CDRs for a dial that results in a busy";
-		info->description =
-			"Test the properties of a CDR for a channel that\n"
-			"performs a dial operation to an endpoint that's busy\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "BUSY");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_BUSY);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_BUSY);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_congestion)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_CONGESTION,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CDRs for a dial that results in congestion";
-		info->description =
-			"Test the properties of a CDR for a channel that\n"
-			"performs a dial operation to an endpoint that's congested\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, congestion_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CONGESTION");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_CONGESTION);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_CONGESTION);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_unavailable)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_FAILED,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CDRs for a dial that results in unavailable";
-		info->description =
-			"Test the properties of a CDR for a channel that\n"
-			"performs a dial operation to an endpoint that's unavailable\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CHANUNAVAIL");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ROUTE_DESTINATION);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ROUTE_DESTINATION);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_caller_cancel)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CDRs for a dial where the caller cancels";
-		info->description =
-			"Test the properties of a CDR for a channel that\n"
-			"performs a dial operation to an endpoint but then decides\n"
-			"to hang up, cancelling the dial\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CANCEL");
-
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_parallel_failed)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr bob_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_NOANSWER,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-	struct ast_cdr charlie_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Charlie",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_BUSY,
-		.accountcode = "100",
-		.peeraccount = "300",
-	};
-	struct ast_cdr david_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/David",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_CONGESTION,
-		.accountcode = "100",
-		.peeraccount = "400",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_cdr *expected = &bob_expected;
-	bob_expected.next = &charlie_expected;
-	charlie_expected.next = &david_expected;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test a parallel dial where all channels fail to answer";
-		info->description =
-			"This tests dialing three parties: Bob, Charlie, David. Charlie\n"
-			"returns BUSY; David returns CONGESTION; Bob fails to answer and\n"
-			"Alice hangs up. Three records are created for Alice as a result.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, congestion_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &bob_expected);
-	COPY_IDS(chan_caller, &charlie_expected);
-	COPY_IDS(chan_caller, &david_expected);
-
-	/* Channel enters Dial app */
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David");
-
-	/* Outbound channels are created */
-	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_bob);
-	ast_channel_unlock(chan_bob);
-	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_bob, 0, "AppDial", "(Outgoing Line)");
-
-	chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "300", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Charlie");
-	SET_FORMATS(chan_charlie);
-	ast_channel_unlock(chan_charlie);
-	ast_set_flag(ast_channel_flags(chan_charlie), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_charlie, 0, "AppDial", "(Outgoing Line)");
-
-	chan_david = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "400", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/David");
-	SET_FORMATS(chan_charlie);
-	ast_channel_unlock(chan_david);
-	ast_set_flag(ast_channel_flags(chan_david), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_david, 0, "AppDial", "(Outgoing Line)");
-
-	/* Dial starts */
-	ast_channel_publish_dial(chan_caller, chan_bob, "Bob", NULL);
-	ast_channel_publish_dial(chan_caller, chan_charlie, "Charlie", NULL);
-	ast_channel_publish_dial(chan_caller, chan_david, "David", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-
-	/* Charlie is busy */
-	ast_channel_publish_dial(chan_caller, chan_charlie, NULL, "BUSY");
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_BUSY);
-
-	/* David is congested */
-	ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_CONGESTION);
-
-	/* Bob is canceled */
-	ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-
-	/* Alice hangs up */
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, expected, 3);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_answer_no_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr bob_expected_one = {
-		.clid = "\"\" <>",
-		.src = "",
-		.dst = "s",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Wait",
-		.lastdata = "1",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-	};
-	struct ast_cdr alice_expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Wait",
-		.lastdata = "1",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.next = &bob_expected_one,
-	};
-	struct ast_cdr alice_expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-		.next = &alice_expected_two,
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and not going into a bridge.";
-		info->description =
-			"This is a weird one, but theoretically possible. You can perform\n"
-			"a dial, then bounce both channels to different priorities and\n"
-			"never have them enter a bridge together. Ew. This makes sure that\n"
-			"when we answer, we get a CDR, it gets ended at that point, and\n"
-			"that it gets finalized appropriately. We should get three CDRs in\n"
-			"the end - one for the dial, and one for each CDR as they continued\n"
-			"on.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &alice_expected_one);
-	COPY_IDS(chan_caller, &alice_expected_two);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	COPY_IDS(chan_callee, &bob_expected_one);
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ast_channel_state_set(chan_caller, AST_STATE_UP);
-	ast_clear_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	ast_channel_state_set(chan_callee, AST_STATE_UP);
-
-	EMULATE_APP_DATA(chan_caller, 2, "Wait", "1");
-	EMULATE_APP_DATA(chan_callee, 1, "Wait", "1");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected_one, 3);
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_answer_twoparty_bridge_a)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a 2-party bridge";
-		info->description =
-			"The most 'basic' of scenarios\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ast_channel_state_set(chan_caller, AST_STATE_UP);
-	ast_channel_state_set(chan_callee, AST_STATE_UP);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-	do_sleep(&to_sleep);
-
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_caller, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_callee, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	do_sleep(&to_sleep);
-
-	ast_bridge_depart(chan_caller);
-	ast_bridge_depart(chan_callee);
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_answer_twoparty_bridge_b)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a 2-party bridge";
-		info->description =
-			"The most 'basic' of scenarios\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
-
-	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, NULL, chan_caller, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_callee);
-	ast_channel_unlock(chan_callee);
-	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ast_channel_state_set(chan_caller, AST_STATE_UP);
-	ast_channel_state_set(chan_callee, AST_STATE_UP);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_callee, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_caller, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_bridge_depart(chan_caller);
-	ast_bridge_depart(chan_callee);
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &expected, 1);
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_dial_answer_multiparty)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-	struct ast_cdr charlie_expected_two = {
-		.clid = "\"Charlie\" <300>",
-		.src = "300",
-		.dst = "300",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Charlie",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/David",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "300",
-		.peeraccount = "200",
-	};
-	struct ast_cdr charlie_expected_one = {
-		.clid = "\"Charlie\" <300>",
-		.src = "300",
-		.dst = "300",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Charlie",
-		.dstchannel = CHANNEL_TECH_NAME "/David",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/David",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "300",
-		.peeraccount = "400",
-		.next = &charlie_expected_two,
-	};
-	struct ast_cdr bob_expected_one = {
-		.clid = "\"Bob\" <200>",
-		.src = "200",
-		.dst = "200",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.dstchannel = CHANNEL_TECH_NAME "/David",
-		.lastapp = "AppDial",
-		.lastdata = "(Outgoing Line)",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-		.peeraccount = "400",
-		.next = &charlie_expected_one,
-	};
-	struct ast_cdr alice_expected_three = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/David",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "400",
-		.next = &bob_expected_one,
-	};
-	struct ast_cdr alice_expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Charlie",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "300",
-		.next = &alice_expected_three,
-	};
-	struct ast_cdr alice_expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.dstchannel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Dial",
-		.lastdata = CHANNEL_TECH_NAME "/Bob",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.billsec = 1,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.peeraccount = "200",
-		.next = &alice_expected_two,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a multi-party bridge";
-		info->description =
-			"A little tricky to get to do, but possible with some redirects.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller, &alice_expected_one);
-	COPY_IDS(chan_alice, &alice_expected_two);
-	COPY_IDS(chan_alice, &alice_expected_three);
-
-	EMULATE_APP_DATA(chan_alice, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
-
-	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Bob");
-	SET_FORMATS(chan_bob);
-	ast_channel_unlock(chan_bob);
-	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_bob, 0, "AppDial", "(Outgoing Line)");
-	ast_copy_string(bob_expected_one.uniqueid, ast_channel_uniqueid(chan_bob), sizeof(bob_expected_one.uniqueid));
-	ast_copy_string(bob_expected_one.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected_one.linkedid));
-
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller, &charlie_expected_one);
-	EMULATE_APP_DATA(chan_charlie, 1, "Dial", CHANNEL_TECH_NAME "/David");
-	ast_copy_string(charlie_expected_one.uniqueid, ast_channel_uniqueid(chan_charlie), sizeof(charlie_expected_one.uniqueid));
-	ast_copy_string(charlie_expected_one.linkedid, ast_channel_linkedid(chan_alice), sizeof(charlie_expected_one.linkedid));
-	ast_copy_string(charlie_expected_two.uniqueid, ast_channel_uniqueid(chan_charlie), sizeof(charlie_expected_two.uniqueid));
-	ast_copy_string(charlie_expected_two.linkedid, ast_channel_linkedid(chan_alice), sizeof(charlie_expected_two.linkedid));
-
-	chan_david = ast_channel_alloc(0, AST_STATE_DOWN, "400", "David", "400", "400", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/David");
-	SET_FORMATS(chan_david);
-	ast_channel_unlock(chan_david);
-	ast_set_flag(ast_channel_flags(chan_david), AST_FLAG_OUTGOING);
-	EMULATE_APP_DATA(chan_david, 0, "AppDial", "(Outgoing Line)");
-
-	ast_channel_publish_dial(chan_alice, chan_bob, "Bob", NULL);
-	ast_channel_state_set(chan_alice, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_charlie, chan_david, "David", NULL);
-	ast_channel_state_set(chan_charlie, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_alice, chan_bob, NULL, "ANSWER");
-	ast_channel_publish_dial(chan_charlie, chan_david, NULL, "ANSWER");
-
-	ast_channel_state_set(chan_alice, AST_STATE_UP);
-	ast_channel_state_set(chan_bob, AST_STATE_UP);
-	ast_channel_state_set(chan_charlie, AST_STATE_UP);
-	ast_channel_state_set(chan_david, AST_STATE_UP);
-
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_charlie, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_david, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_depart(chan_alice));
-	ast_test_validate(test, !ast_bridge_depart(chan_bob));
-	ast_test_validate(test, !ast_bridge_depart(chan_charlie));
-	ast_test_validate(test, !ast_bridge_depart(chan_david));
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected_one, 6);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_park)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_cdr bob_expected = {
-		.clid = "\"Bob\" <200>",
-		.src = "200",
-		.dst = "200",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Bob",
-		.lastapp = "Park",
-		.lastdata = "701",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "200",
-	};
-	struct ast_cdr alice_expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Park",
-		.lastdata = "700",
-		.billsec = 1,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-		.next = &bob_expected,
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test cdrs for a single party entering Park";
-		info->description =
-			"Test the properties of a CDR for calls that are\n"
-			"answered, enters Park, and leaves it.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	SWAP_CONFIG(config, debug_cdr_config);
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller, &alice_expected);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller, &bob_expected);
-
-	ast_channel_lock(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 1, "Park", "700");
-	ast_setstate(chan_alice, AST_STATE_UP);
-	ast_channel_unlock(chan_alice);
-
-	ast_channel_lock(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 1, "Park", "701");
-	ast_setstate(chan_bob, AST_STATE_UP);
-	ast_channel_unlock(chan_bob);
-
-	bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-			| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED,
-		"test_cdr", "test_cdr_park", NULL);
-	ast_test_validate(test, bridge != NULL);
-
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	do_sleep(&to_sleep);
-	ast_bridge_depart(chan_alice);
-	ast_bridge_depart(chan_bob);
-
-	/* And then it hangs up */
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
-
-	result = verify_mock_cdr_record(test, &alice_expected, 2);
-
-	return result;
-}
-
-
-AST_TEST_DEFINE(test_cdr_fields)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	char varbuffer[128];
-	int int_buffer;
-	double db_buffer;
-	struct timespec to_sleep = {2, 0};
-	struct ast_flags fork_options = { 0, };
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr original = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Wait",
-		.lastdata = "10",
-		.billsec = 0,
-		.amaflags = AST_AMA_OMIT,
-		.disposition = AST_CDR_FAILED,
-		.accountcode = "XXX",
-		.userfield = "yackity",
-	};
-	struct ast_cdr fork_expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Wait",
-		.lastdata = "10",
-		.billsec = 0,
-		.amaflags = AST_AMA_OMIT,
-		.disposition = AST_CDR_FAILED,
-		.accountcode = "XXX",
-		.userfield = "yackity",
-	};
-	struct ast_cdr fork_expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.lastapp = "Answer",
-		.billsec = 0,
-		.amaflags = AST_AMA_OMIT,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "ZZZ",
-		.userfield = "schmackity",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	struct ast_cdr *expected = &original;
-	original.next = &fork_expected_one;
-	fork_expected_one.next = &fork_expected_two;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test field access CDRs";
-		info->description =
-			"This tests setting/retrieving data on CDR records.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, &caller, &original);
-	ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
-	ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
-	ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
-	ast_copy_string(fork_expected_two.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_two.linkedid));
-
-	/* Channel enters Wait app */
-	ast_channel_lock(chan);
-	ast_channel_appl_set(chan, "Wait");
-	ast_channel_data_set(chan, "10");
-	ast_channel_priority_set(chan, 1);
-	ast_channel_publish_snapshot(chan);
-
-	/* Set properties on the channel that propagate to the CDR */
-	ast_channel_amaflags_set(chan, AST_AMA_OMIT);
-	ast_channel_accountcode_set(chan, "XXX");
-	ast_channel_unlock(chan);
-
-	/* Wait one second so we get a duration. */
-	do_sleep(&to_sleep);
-
-	ast_cdr_setuserfield(ast_channel_name(chan), "foobar");
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1") == 0);
-
-	/* Verify that we can't set read-only fields or other fields directly */
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "clid", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "src", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dst", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dcontext", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "channel", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dstchannel", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "lastapp", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "lastdata", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "start", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "answer", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "end", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "duration", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "billsec", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "disposition", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "amaflags", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "accountcode", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "uniqueid", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "linkedid", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "userfield", "junk") != 0);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "sequence", "junk") != 0);
-
-	/* Verify the values */
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "userfield", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "foobar") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "amaflags", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%d", &int_buffer);
-	ast_test_validate(test, int_buffer == AST_AMA_OMIT);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "accountcode", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "XXX") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "clid", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "\"Alice\" <100>") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "src", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "100") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dst", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "100") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dcontext", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "default") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "channel", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, CHANNEL_TECH_NAME "/Alice") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dstchannel", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastapp", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "Wait") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastdata", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "10") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%lf", &db_buffer);
-	ast_test_validate(test, fabs(db_buffer) > 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%lf", &db_buffer);
-	ast_test_validate(test, fabs(db_buffer) < EPSILON);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "end", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%lf", &db_buffer);
-	ast_test_validate(test, fabs(db_buffer) < EPSILON);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "duration", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%lf", &db_buffer);
-	ast_test_validate(test, fabs(db_buffer) > 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "billsec", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%lf", &db_buffer);
-	ast_test_validate(test, fabs(db_buffer) < EPSILON);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "disposition", varbuffer, sizeof(varbuffer)) == 0);
-	sscanf(varbuffer, "%d", &int_buffer);
-	ast_test_validate(test, int_buffer == AST_CDR_NULL);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "uniqueid", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, ast_channel_uniqueid(chan)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "linkedid", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, ast_channel_linkedid(chan)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "sequence", varbuffer, sizeof(varbuffer)) == 0);
-
-	/* Fork the CDR, and check that we change the properties on both CDRs. */
-	ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	/* Change some properties */
-	ast_cdr_setuserfield(ast_channel_name(chan), "yackity");
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1b") == 0);
-
-	/* Fork the CDR again, finalizing all current CDRs */
-	ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS | AST_CDR_FLAG_FINALIZE);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	/* Channel enters Answer app */
-	ast_channel_lock(chan);
-	ast_channel_appl_set(chan, "Answer");
-	ast_channel_data_set(chan, "");
-	ast_channel_priority_set(chan, 1);
-	ast_channel_publish_snapshot(chan);
-	ast_setstate(chan, AST_STATE_UP);
-
-	/* Set properties on the last record */
-	ast_channel_accountcode_set(chan, "ZZZ");
-	ast_channel_unlock(chan);
-	ast_cdr_setuserfield(ast_channel_name(chan), "schmackity");
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0);
-
-	/* Hang up and verify */
-	ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
-	ast_hangup(chan);
-	chan = NULL;
-	result = verify_mock_cdr_record(test, expected, 3);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_no_reset_cdr)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	struct ast_flags fork_options = { 0, };
-	struct timespec to_sleep = {1, 0};
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr expected = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.billsec = 0,
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_FAILED,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test field access CDRs";
-		info->description =
-			"This tests setting/retrieving data on CDR records.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, unanswered_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
-
-	do_sleep(&to_sleep);
-
-	/* Disable the CDR */
-	ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
-
-	/* Fork the CDR. This should be enabled */
-	ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	/* Disable and enable the forked CDR */
-	ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
-	ast_test_validate(test, ast_cdr_clear_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
-
-	/* Fork and finalize again. This CDR should be propagated */
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	/* Disable all future CDRs */
-	ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL) == 0);
-
-	/* Fork a few more */
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
-	ast_hangup(chan);
-	chan = NULL;
-	result = verify_mock_cdr_record(test, &expected, 1);
-
-	return result;
-}
-
-AST_TEST_DEFINE(test_cdr_fork_cdr)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
-			ao2_cleanup);
-	char varbuffer[128];
-	char fork_varbuffer[128];
-	char answer_time[128];
-	char fork_answer_time[128];
-	char start_time[128];
-	char fork_start_time[128];
-	struct ast_flags fork_options = { 0, };
-	struct timespec to_sleep = {1, 10000};
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_cdr original = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	struct ast_cdr fork_expected_one = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	struct ast_cdr fork_expected_two = {
-		.clid = "\"Alice\" <100>",
-		.src = "100",
-		.dst = "100",
-		.dcontext = "default",
-		.channel = CHANNEL_TECH_NAME "/Alice",
-		.amaflags = AST_AMA_DOCUMENTATION,
-		.disposition = AST_CDR_ANSWERED,
-		.accountcode = "100",
-	};
-	enum ast_test_result_state result = AST_TEST_NOT_RUN;
-	struct ast_cdr *expected = &original;
-	original.next = &fork_expected_one;
-	fork_expected_one.next = &fork_expected_two;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test field access CDRs";
-		info->description =
-			"This tests setting/retrieving data on CDR records.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	SWAP_CONFIG(config, debug_cdr_config);
-
-	CREATE_ALICE_CHANNEL(chan, &caller, &original);
-	ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
-	ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
-	ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
-	ast_copy_string(fork_expected_two.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_two.linkedid));
-
-	do_sleep(&to_sleep);
-
-	/* Test blowing away variables */
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
-	ast_copy_string(varbuffer, "", sizeof(varbuffer));
-
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", fork_varbuffer, sizeof(fork_varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "record_1") != 0);
-
-	/* Test finalizing previous CDRs */
-	ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-
-	/* Test keep variables; setting a new answer time */
-	ast_channel_lock(chan);
-	ast_setstate(chan, AST_STATE_UP);
-	ast_channel_unlock(chan);
-	do_sleep(&to_sleep);
-	ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", varbuffer, sizeof(varbuffer)) == 0);
-	ast_test_validate(test, strcmp(varbuffer, "record_2") == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", answer_time, sizeof(answer_time)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", start_time, sizeof(start_time)) == 0);
-
-	ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
-	ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS);
-	ast_set_flag(&fork_options, AST_CDR_FLAG_SET_ANSWER);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", fork_answer_time, sizeof(fork_answer_time)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", fork_start_time, sizeof(fork_start_time)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", fork_varbuffer, sizeof(fork_varbuffer)) == 0);
-	ast_test_validate(test, strcmp(fork_varbuffer, varbuffer) == 0);
-	ast_test_validate(test, strcmp(fork_start_time, start_time) == 0);
-	ast_test_validate(test, strcmp(fork_answer_time, answer_time) != 0);
-
-	ast_clear_flag(&fork_options, AST_CDR_FLAG_SET_ANSWER);
-	ast_set_flag(&fork_options, AST_CDR_FLAG_RESET);
-	ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", fork_answer_time, sizeof(fork_answer_time)) == 0);
-	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", fork_start_time, sizeof(fork_start_time)) == 0);
-	ast_test_validate(test, strcmp(fork_start_time, start_time) != 0);
-	ast_test_validate(test, strcmp(fork_answer_time, answer_time) != 0);
-
-	ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
-	ast_hangup(chan);
-	chan = NULL;
-	result = verify_mock_cdr_record(test, expected, 3);
-
-	return result;
-}
-
-/*!
- * \internal
- * \brief Callback function called before each test executes
- */
-static int test_cdr_init_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	/* Back up the real config */
-	saved_config = ast_cdr_get_config();
-	clear_mock_cdr_backend();
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Callback function called after each test executes
- */
-static int test_cdr_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	/* Restore the real config */
-	ast_cdr_set_config(saved_config);
-	ao2_cleanup(saved_config);
-	saved_config = NULL;
-	clear_mock_cdr_backend();
-
-	return 0;
-}
-
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(test_cdr_channel_creation);
-	AST_TEST_UNREGISTER(test_cdr_unanswered_inbound_call);
-	AST_TEST_UNREGISTER(test_cdr_unanswered_outbound_call);
-
-	AST_TEST_UNREGISTER(test_cdr_single_party);
-	AST_TEST_UNREGISTER(test_cdr_single_bridge);
-	AST_TEST_UNREGISTER(test_cdr_single_bridge_continue);
-	AST_TEST_UNREGISTER(test_cdr_single_twoparty_bridge_a);
-	AST_TEST_UNREGISTER(test_cdr_single_twoparty_bridge_b);
-	AST_TEST_UNREGISTER(test_cdr_single_multiparty_bridge);
-
-	AST_TEST_UNREGISTER(test_cdr_outbound_bridged_call);
-
-	AST_TEST_UNREGISTER(test_cdr_dial_unanswered);
-	AST_TEST_UNREGISTER(test_cdr_dial_congestion);
-	AST_TEST_UNREGISTER(test_cdr_dial_busy);
-	AST_TEST_UNREGISTER(test_cdr_dial_unavailable);
-	AST_TEST_UNREGISTER(test_cdr_dial_caller_cancel);
-	AST_TEST_UNREGISTER(test_cdr_dial_parallel_failed);
-	AST_TEST_UNREGISTER(test_cdr_dial_answer_no_bridge);
-	AST_TEST_UNREGISTER(test_cdr_dial_answer_twoparty_bridge_a);
-	AST_TEST_UNREGISTER(test_cdr_dial_answer_twoparty_bridge_b);
-	AST_TEST_UNREGISTER(test_cdr_dial_answer_multiparty);
-
-	AST_TEST_UNREGISTER(test_cdr_park);
-
-	AST_TEST_UNREGISTER(test_cdr_fields);
-	AST_TEST_UNREGISTER(test_cdr_no_reset_cdr);
-	AST_TEST_UNREGISTER(test_cdr_fork_cdr);
-
-	ast_cdr_unregister(MOCK_CDR_BACKEND);
-	ast_channel_unregister(&test_cdr_chan_tech);
-	clear_mock_cdr_backend();
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	ast_cond_init(&mock_cdr_cond, NULL);
-
-	AST_TEST_REGISTER(test_cdr_channel_creation);
-	AST_TEST_REGISTER(test_cdr_unanswered_inbound_call);
-	AST_TEST_REGISTER(test_cdr_unanswered_outbound_call);
-
-	AST_TEST_REGISTER(test_cdr_single_party);
-	AST_TEST_REGISTER(test_cdr_single_bridge);
-	AST_TEST_REGISTER(test_cdr_single_bridge_continue);
-	AST_TEST_REGISTER(test_cdr_single_twoparty_bridge_a);
-	AST_TEST_REGISTER(test_cdr_single_twoparty_bridge_b);
-	AST_TEST_REGISTER(test_cdr_single_multiparty_bridge);
-
-	AST_TEST_REGISTER(test_cdr_outbound_bridged_call);
-
-	AST_TEST_REGISTER(test_cdr_dial_unanswered);
-	AST_TEST_REGISTER(test_cdr_dial_congestion);
-	AST_TEST_REGISTER(test_cdr_dial_busy);
-	AST_TEST_REGISTER(test_cdr_dial_unavailable);
-	AST_TEST_REGISTER(test_cdr_dial_caller_cancel);
-	AST_TEST_REGISTER(test_cdr_dial_parallel_failed);
-	AST_TEST_REGISTER(test_cdr_dial_answer_no_bridge);
-	AST_TEST_REGISTER(test_cdr_dial_answer_twoparty_bridge_a);
-	AST_TEST_REGISTER(test_cdr_dial_answer_twoparty_bridge_b);
-	AST_TEST_REGISTER(test_cdr_dial_answer_multiparty);
-
-	AST_TEST_REGISTER(test_cdr_park);
-
-	AST_TEST_REGISTER(test_cdr_fields);
-	AST_TEST_REGISTER(test_cdr_no_reset_cdr);
-	AST_TEST_REGISTER(test_cdr_fork_cdr);
-
-	ast_test_register_init(TEST_CATEGORY, test_cdr_init_cb);
-	ast_test_register_cleanup(TEST_CATEGORY, test_cdr_cleanup_cb);
-
-	ast_channel_register(&test_cdr_chan_tech);
-	ast_cdr_register(MOCK_CDR_BACKEND, "Mock CDR backend", mock_cdr_backend_cb);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR unit tests");
diff --git a/tests/test_cel.c b/tests/test_cel.c
deleted file mode 100644
index ad2e358..0000000
--- a/tests/test_cel.c
+++ /dev/null
@@ -1,2226 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief CEL unit tests
- *
- * \author Kinsey Moore <kmoore at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428919 $")
-
-#include <math.h>
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/cel.h"
-#include "asterisk/channel.h"
-#include "asterisk/format_cache.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/chanvars.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/time.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/pickup.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_bridges.h"
-#include "asterisk/json.h"
-#include "asterisk/features.h"
-#include "asterisk/core_local.h"
-
-#define TEST_CATEGORY "/main/cel/"
-
-#define CHANNEL_TECH_NAME "CELTestChannel"
-
-#define TEST_BACKEND_NAME "CEL Test Logging"
-
-/*! \brief A placeholder for Asterisk's 'real' CEL configuration */
-static struct ast_cel_general_config *saved_config;
-
-/*! \brief The CEL config used for CEL unit tests */
-static struct ast_cel_general_config *cel_test_config;
-
-/*! \brief Lock used for synchronizing test execution stages with received events */
-ast_mutex_t mid_test_sync_lock;
-
-/*! \brief Lock used with sync_out for checking the end of test execution */
-ast_mutex_t sync_lock;
-
-/*! \brief Condition used for checking the end of test execution */
-ast_cond_t sync_out;
-
-/*! \brief Flag used to trigger a mid-test synchronization, access controlled by mid_test_sync_lock */
-int do_mid_test_sync = 0;
-
-/*! \brief A channel technology used for the unit tests */
-static struct ast_channel_tech test_cel_chan_tech = {
-	.type = CHANNEL_TECH_NAME,
-	.description = "Mock channel technology for CEL tests",
-};
-
-/*! \brief A 1 second sleep */
-static struct timespec to_sleep = {1, 0};
-
-static void do_sleep(void)
-{
-	while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)) {
-	}
-}
-
-#define APPEND_EVENT(chan, ev_type, userevent, extra) do { \
-	if (append_expected_event(chan, ev_type, userevent, extra, NULL)) { \
-		return AST_TEST_FAIL; \
-	} \
-	} while (0)
-
-#define APPEND_EVENT_PEER(chan, ev_type, userevent, extra, peer) do { \
-	if (append_expected_event(chan, ev_type, userevent, extra, peer)) { \
-		return AST_TEST_FAIL; \
-	} \
-	} while (0)
-
-#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra, peer) do { \
-	if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra, peer)) { \
-		return AST_TEST_FAIL; \
-	} \
-	} while (0)
-
-#define APPEND_DUMMY_EVENT() do { \
-	if (append_dummy_event()) { \
-		return AST_TEST_FAIL; \
-	} \
-	} while (0)
-
-#define BRIDGE_EXIT(channel, bridge) do { \
-	ast_test_validate(test, !ast_bridge_depart(channel)); \
-	BRIDGE_EXIT_EVENT(channel, bridge); \
-	mid_test_sync(); \
-	} while (0)
-
-#define BRIDGE_EXIT_EVENT(channel, bridge) do { \
-	RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
-	peer_str = test_cel_generate_peer_str(channel, bridge); \
-	ast_test_validate(test, peer_str != NULL); \
-	BRIDGE_EXIT_EVENT_PEER(channel, bridge, ast_str_buffer(peer_str)); \
-	} while (0)
-
-#define BRIDGE_EXIT_EVENT_PEER(channel, bridge, peer) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, peer); \
-	} while (0)
-
-#define BRIDGE_EXIT_SNAPSHOT(channel, bridge) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
-	peer_str = test_cel_generate_peer_str_snapshot(channel, bridge); \
-	ast_test_validate(test, peer_str != NULL); \
-	extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT_SNAPSHOT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str)); \
-	} while (0)
-
-#define BRIDGE_ENTER(channel, bridge) do { \
-	ast_test_validate(test, !ast_bridge_impart(bridge, channel, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); \
-	do_sleep(); \
-	BRIDGE_ENTER_EVENT(channel, bridge); \
-	mid_test_sync(); \
-	} while (0)
-
-#define BRIDGE_ENTER_EVENT(channel, bridge) do { \
-	RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
-	peer_str = test_cel_generate_peer_str(channel, bridge); \
-	ast_test_validate(test, peer_str != NULL); \
-	BRIDGE_ENTER_EVENT_PEER(channel, bridge, ast_str_buffer(peer_str)); \
-	} while (0)
-
-#define BRIDGE_ENTER_EVENT_PEER(channel, bridge, peer) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_ENTER, NULL, extra, peer); \
-	} while (0)
-
-#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", \
-		"extension", extension, \
-		"context", context, \
-		"bridge_id", bridge->uniqueid, \
-		"transferee_channel_name", "N/A", \
-		"transferee_channel_uniqueid", "N/A"); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra); \
-	} while (0)
-
-#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2, channel3, channel4) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}", \
-		"bridge1_id", bridge1->uniqueid, \
-		"channel2_name", ast_channel_name(channel2), \
-		"channel2_uniqueid", ast_channel_uniqueid(channel2), \
-		"bridge2_id", bridge2->uniqueid, \
-		"transferee_channel_name", ast_channel_name(channel4), \
-		"transferee_channel_uniqueid", ast_channel_uniqueid(channel4), \
-		"transfer_target_channel_name", ast_channel_name(channel3), \
-		"transfer_target_channel_uniqueid", ast_channel_uniqueid(channel3)); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra); \
-	} while (0)
-
-/*! \brief Alice's Caller ID */
-#define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
-
-/*! \brief Bob's Caller ID */
-#define BOB_CALLERID { .id.name.str = "Bob", .id.name.valid = 1, .id.number.str = "200", .id.number.valid = 1, }
-
-/*! \brief Charlie's Caller ID */
-#define CHARLIE_CALLERID { .id.name.str = "Charlie", .id.name.valid = 1, .id.number.str = "300", .id.number.valid = 1, }
-
-/*! \brief David's Caller ID */
-#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
-
-/*! \brief Set ulaw format on channel */
-#define SET_FORMATS(chan) do {\
-	struct ast_format_cap *caps;\
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);\
-	ast_format_cap_append(caps, ast_format_ulaw, 0);\
-	ast_channel_nativeformats_set((chan), caps);\
-	ast_channel_set_writeformat((chan), ast_format_ulaw);\
-	ast_channel_set_rawwriteformat((chan), ast_format_ulaw);\
-	ast_channel_set_readformat((chan), ast_format_ulaw);\
-	ast_channel_set_rawreadformat((chan), ast_format_ulaw);\
-	ao2_ref(caps, -1);\
-} while (0)
-
-/*! \brief Create a \ref test_cel_chan_tech for Alice. */
-#define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
-	SET_FORMATS((channel_var));\
-	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cel_chan_tech for Bob. */
-#define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
-	SET_FORMATS((channel_var));\
-	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
-#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
-	SET_FORMATS((channel_var));\
-	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Create a \ref test_cel_chan_tech for David. */
-#define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
-	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/David"); \
-	SET_FORMATS((channel_var));\
-	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
-	ast_channel_unlock((channel_var)); \
-	} while (0)
-
-/*! \brief Emulate a channel entering into an application */
-#define EMULATE_APP_DATA(channel, priority, application, data) do { \
-	if ((priority) > 0) { \
-		ast_channel_priority_set((channel), (priority)); \
-	} \
-	ast_channel_appl_set((channel), (application)); \
-	ast_channel_data_set((channel), (data)); \
-	ast_channel_publish_snapshot((channel)); \
-	} while (0)
-
-#define ANSWER_CHANNEL(chan) do { \
-	EMULATE_APP_DATA(chan, 1, "Answer", ""); \
-	ANSWER_NO_APP(chan); \
-	} while (0)
-
-#define ANSWER_NO_APP(chan) do { \
-	ast_setstate(chan, AST_STATE_UP); \
-	APPEND_EVENT(chan, AST_CEL_ANSWER, NULL, NULL); \
-	} while (0)
-
-/*! \brief Hang up a test channel safely */
-#define HANGUP_CHANNEL(channel, cause, dialstatus) do { \
-	ast_channel_hangupcause_set((channel), (cause)); \
-	ao2_ref(channel, +1); \
-	ast_hangup((channel)); \
-	HANGUP_EVENT(channel, cause, dialstatus); \
-	APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL); \
-	ao2_cleanup(stasis_cache_get(ast_channel_cache(), \
-		ast_channel_snapshot_type(), ast_channel_uniqueid(channel))); \
-	ao2_cleanup(channel); \
-	channel = NULL; \
-	} while (0)
-
-#define HANGUP_EVENT(channel, cause, dialstatus) do { \
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
-	extra = ast_json_pack("{s: i, s: s, s: s}", \
-		"hangupcause", cause, \
-		"hangupsource", "", \
-		"dialstatus", dialstatus); \
-	ast_test_validate(test, extra != NULL); \
-	APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, extra); \
-	} while (0)
-
-static void mid_test_sync(void);
-
-static int append_expected_event(
-	struct ast_channel *chan,
-	enum ast_cel_event_type type,
-	const char *userdefevname,
-	struct ast_json *extra,
-	const char *peer);
-
-static int append_expected_event_snapshot(
-	struct ast_channel_snapshot *snapshot,
-	enum ast_cel_event_type type,
-	const char *userdefevname,
-	struct ast_json *extra,
-	const char *peer);
-
-#ifdef RACEY_TESTS
-static int append_dummy_event(void);
-#endif
-
-static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot *chan, struct ast_bridge_snapshot *bridge)
-{
-	struct ast_str *peer_str = ast_str_create(32);
-	struct ao2_iterator i;
-	char *current_chan = NULL;
-
-	if (!peer_str) {
-		return NULL;
-	}
-
-	for (i = ao2_iterator_init(bridge->channels, 0);
-		(current_chan = ao2_iterator_next(&i));
-		ao2_cleanup(current_chan)) {
-		RAII_VAR(struct ast_channel_snapshot *, current_snapshot,
-			NULL,
-			ao2_cleanup);
-
-		/* Don't add the channel for which this message is being generated */
-		if (!strcmp(current_chan, chan->uniqueid)) {
-			continue;
-		}
-
-		current_snapshot = ast_channel_snapshot_get_latest(current_chan);
-		if (!current_snapshot) {
-			continue;
-		}
-
-		ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Rip off the trailing comma */
-	ast_str_truncate(peer_str, -1);
-
-	return peer_str;
-}
-
-static struct ast_str *test_cel_generate_peer_str_snapshot(struct ast_channel_snapshot *chan, struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, snapshot,
-		ast_bridge_snapshot_get_latest(bridge->uniqueid),
-		ao2_cleanup);
-
-	if (!snapshot) {
-		return NULL;
-	}
-
-	return __test_cel_generate_peer_str(chan, snapshot);
-}
-
-static struct ast_str *test_cel_generate_peer_str(struct ast_channel *chan, struct ast_bridge *bridge)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot,
-		ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
-		ao2_cleanup);
-
-	if (!snapshot) {
-		return NULL;
-	}
-
-	return test_cel_generate_peer_str_snapshot(snapshot, bridge);
-}
-
-static void safe_channel_release(struct ast_channel *chan)
-{
-	if (!chan) {
-		return;
-	}
-	ast_channel_release(chan);
-}
-
-static void safe_bridge_destroy(struct ast_bridge *bridge)
-{
-	if (!bridge) {
-		return;
-	}
-	ast_bridge_destroy(bridge, 0);
-}
-
-AST_TEST_DEFINE(test_cel_channel_creation)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test the CEL records created when a channel is created";
-		info->description =
-			"Test the CEL records created when a channel is created";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan, (&caller));
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_unanswered_inbound_call)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test inbound unanswered calls";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"inbound to Asterisk, executes some dialplan, but\n"
-			"is never answered.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan, &caller);
-
-	EMULATE_APP_DATA(chan, 1, "Wait", "1");
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_unanswered_outbound_call)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	struct ast_party_caller caller = {
-			.id.name.str = "",
-			.id.name.valid = 1,
-			.id.number.str = "",
-			.id.number.valid = 1, };
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test outbound unanswered calls";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"outbound to Asterisk but is never answered.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan, &caller);
-
-	ast_channel_exten_set(chan, "s");
-	ast_channel_context_set(chan, "default");
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
-	EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_single_party)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, but only involves a single channel\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	CREATE_ALICE_CHANNEL(chan, &caller);
-
-	ANSWER_CHANNEL(chan);
-	EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1");
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_single_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party entering/leaving a bridge";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, enters a bridge, and leaves it.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan, &caller);
-
-	ANSWER_CHANNEL(chan);
-	EMULATE_APP_DATA(chan, 2, "Bridge", "");
-
-	do_sleep();
-	BRIDGE_ENTER(chan, bridge);
-
-	do_sleep();
-
-	BRIDGE_EXIT(chan, bridge);
-
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_single_bridge_continue)
-{
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party entering/leaving a bridge";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, enters a bridge, and leaves it.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan, &caller);
-
-	ANSWER_CHANNEL(chan);
-	EMULATE_APP_DATA(chan, 2, "Bridge", "");
-
-	do_sleep();
-	BRIDGE_ENTER(chan, bridge);
-
-	do_sleep();
-
-	BRIDGE_EXIT(chan, bridge);
-
-	EMULATE_APP_DATA(chan, 3, "Wait", "");
-
-	/* And then it hangs up */
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_single_twoparty_bridge_a)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party entering/leaving a bridge";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, enters a bridge, and leaves it. In this scenario, the\n"
-			"Party A should answer the bridge first.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice);
-
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob);
-
-	ANSWER_CHANNEL(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-
-	BRIDGE_ENTER(chan_alice, bridge);
-	do_sleep();
-
-	ANSWER_CHANNEL(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-
-	BRIDGE_ENTER(chan_bob, bridge);
-
-	BRIDGE_EXIT(chan_alice, bridge);
-	BRIDGE_EXIT(chan_bob, bridge);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_single_twoparty_bridge_b)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party entering/leaving a bridge";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, enters a bridge, and leaves it. In this scenario, the\n"
-			"Party B should answer the bridge first.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice);
-
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob);
-
-	ANSWER_CHANNEL(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-
-	ANSWER_CHANNEL(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-	do_sleep();
-
-	BRIDGE_ENTER(chan_bob, bridge);
-
-	BRIDGE_ENTER(chan_alice, bridge);
-
-	BRIDGE_EXIT(chan_alice, bridge);
-	BRIDGE_EXIT(chan_bob, bridge);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-/* XXX Validation needs to be reworked on a per-channel basis before
- * test_cel_single_multiparty_bridge and test_cel_dial_answer_multiparty
- * can operate properly. */
-#ifdef RACEY_TESTS
-AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller_alice = ALICE_CALLERID;
-	struct ast_party_caller caller_bob = BOB_CALLERID;
-	struct ast_party_caller caller_charlie = CHARLIE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a single party entering/leaving a multi-party bridge";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"answered, enters a bridge, and leaves it. A total of three\n"
-			"parties perform this action.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &caller_alice);
-	CREATE_BOB_CHANNEL(chan_bob, &caller_bob);
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &caller_charlie);
-
-	ANSWER_CHANNEL(chan_alice);
-	EMULATE_APP_DATA(chan_alice, 2, "Bridge", "");
-
-	do_sleep();
-
-	BRIDGE_ENTER(chan_alice, bridge);
-
-	ANSWER_CHANNEL(chan_bob);
-	EMULATE_APP_DATA(chan_bob, 2, "Bridge", "");
-	do_sleep();
-
-	BRIDGE_ENTER(chan_bob, bridge);
-
-	ANSWER_CHANNEL(chan_charlie);
-	EMULATE_APP_DATA(chan_charlie, 2, "Bridge", "");
-	do_sleep();
-	BRIDGE_ENTER(chan_charlie, bridge);
-
-	BRIDGE_EXIT(chan_alice, bridge);
-	BRIDGE_EXIT(chan_bob, bridge);
-	BRIDGE_EXIT(chan_charlie, bridge);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-#endif
-
-#define EMULATE_DIAL(channel, dialstring) do { \
-	EMULATE_APP_DATA(channel, 1, "Dial", dialstring); \
-	if (append_expected_event(channel, AST_CEL_APP_START, NULL, NULL, NULL)) { \
-		return AST_TEST_FAIL; \
-	} \
-	} while (0)
-
-#define START_DIALED(caller, callee) \
-	START_DIALED_FULL(caller, callee, "200", "Bob")
-
-#define START_DIALED_FULL(caller, callee, number, name) do { \
-	callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, number, NULL, NULL, NULL, caller, 0, CHANNEL_TECH_NAME "/" name); \
-	SET_FORMATS(callee);\
-	ast_channel_unlock(callee); \
-	if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL, NULL)) { \
-		return AST_TEST_FAIL; \
-	} \
-	ast_set_flag(ast_channel_flags(callee), AST_FLAG_OUTGOING); \
-	EMULATE_APP_DATA(callee, 0, "AppDial", "(Outgoing Line)"); \
-	ast_channel_publish_dial(caller, callee, name, NULL); \
-	} while (0)
-
-AST_TEST_DEFINE(test_cel_dial_unanswered)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial that isn't answered";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation that isn't answered\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER, "NOANSWER");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_unanswered_filter)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial that isn't answered";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation that isn't answered\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOT A VALID DIAL STATUS");
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER, "NOANSWER");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_busy)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial that results in a busy";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation to an endpoint that's busy\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "BUSY");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_BUSY, "BUSY");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_BUSY, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_congestion)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial that results in congestion";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation to an endpoint that's congested\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CONGESTION");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_CONGESTION, "CONGESTION");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_CONGESTION, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_unavailable)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial that results in unavailable";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation to an endpoint that's unavailable\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CHANUNAVAIL");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ROUTE_DESTINATION, "CHANUNAVAIL");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ROUTE_DESTINATION, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_caller_cancel)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test CEL for a dial where the caller cancels";
-		info->description =
-			"Test CEL records for a channel that\n"
-			"performs a dial operation to an endpoint but then decides\n"
-			"to hang up, cancelling the dial\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CANCEL");
-
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_parallel_failed)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test a parallel dial where all channels fail to answer";
-		info->description =
-			"This tests dialing three parties: Bob, Charlie, David. Charlie\n"
-			"returns BUSY; David returns CONGESTION; Bob fails to answer and\n"
-			"Alice hangs up. Three records are created for Alice as a result.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	/* Channel enters Dial app */
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David");
-
-	/* Outbound channels are created */
-	START_DIALED_FULL(chan_caller, chan_bob, "200", "Bob");
-	START_DIALED_FULL(chan_caller, chan_charlie, "300", "Charlie");
-	START_DIALED_FULL(chan_caller, chan_david, "400", "David");
-
-	/* Dial starts */
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-
-	/* Charlie is busy */
-	ast_channel_publish_dial(chan_caller, chan_charlie, NULL, "BUSY");
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_BUSY, "");
-
-	/* David is congested */
-	ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_CONGESTION, "");
-
-	/* Bob is canceled */
-	ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-
-	/* Alice hangs up */
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "BUSY");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_answer_no_bridge)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and not going into a bridge.";
-		info->description =
-			"This is a weird one, but theoretically possible. You can perform\n"
-			"a dial, then bounce both channels to different priorities and\n"
-			"never have them enter a bridge together. Ew. This makes sure that\n"
-			"when we answer, we get a CEL, it gets ended at that point, and\n"
-			"that it gets finalized appropriately.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ANSWER_NO_APP(chan_caller);
-	ast_clear_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
-	ANSWER_NO_APP(chan_callee);
-
-	EMULATE_APP_DATA(chan_caller, 2, "Wait", "1");
-	EMULATE_APP_DATA(chan_callee, 1, "Wait", "1");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_a)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a 2-party bridge";
-		info->description =
-			"The most 'basic' of scenarios\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ANSWER_NO_APP(chan_caller);
-	ANSWER_NO_APP(chan_callee);
-
-	do_sleep();
-
-	BRIDGE_ENTER(chan_caller, bridge);
-	BRIDGE_ENTER(chan_callee, bridge);
-
-	BRIDGE_EXIT(chan_caller, bridge);
-	BRIDGE_EXIT(chan_callee, bridge);
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_b)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a 2-party bridge";
-		info->description =
-			"The most 'basic' of scenarios\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	ANSWER_NO_APP(chan_caller);
-	ANSWER_NO_APP(chan_callee);
-
-	do_sleep();
-	BRIDGE_ENTER(chan_callee, bridge);
-	BRIDGE_ENTER(chan_caller, bridge);
-
-	BRIDGE_EXIT(chan_caller, bridge);
-	BRIDGE_EXIT(chan_callee, bridge);
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-#ifdef RACEY_TESTS
-AST_TEST_DEFINE(test_cel_dial_answer_multiparty)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test dialing, answering, and going into a multi-party bridge";
-		info->description =
-			"A little tricky to get to do, but possible with some redirects.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-
-	EMULATE_DIAL(chan_alice, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_alice, chan_bob);
-	do_sleep();
-
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
-	do_sleep();
-	EMULATE_DIAL(chan_charlie, CHANNEL_TECH_NAME "/Bob");
-	do_sleep();
-
-	START_DIALED_FULL(chan_charlie, chan_david, "400", "David");
-
-	ast_channel_state_set(chan_alice, AST_STATE_RINGING);
-	do_sleep();
-	ast_channel_state_set(chan_charlie, AST_STATE_RINGING);
-	do_sleep();
-	ast_channel_publish_dial(chan_alice, chan_bob, NULL, "ANSWER");
-	do_sleep();
-	ast_channel_publish_dial(chan_charlie, chan_david, NULL, "ANSWER");
-	do_sleep();
-
-	ANSWER_NO_APP(chan_alice);
-	do_sleep();
-	ANSWER_NO_APP(chan_bob);
-	do_sleep();
-	ANSWER_NO_APP(chan_charlie);
-	do_sleep();
-	ANSWER_NO_APP(chan_david);
-	do_sleep();
-
-	do_sleep();
-	BRIDGE_ENTER(chan_charlie, bridge);
-	BRIDGE_ENTER(chan_david, bridge);
-	BRIDGE_ENTER(chan_bob, bridge);
-	BRIDGE_ENTER(chan_alice, bridge);
-
-	BRIDGE_EXIT(chan_alice, bridge);
-	BRIDGE_EXIT(chan_bob, bridge);
-	BRIDGE_EXIT(chan_charlie, bridge);
-	BRIDGE_EXIT(chan_david, bridge);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "ANSWER");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "ANSWER");
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-#endif
-
-AST_TEST_DEFINE(test_cel_blind_transfer)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_blind_transfer_message *, transfer_msg, NULL, ao2_cleanup);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test blind transfers to an extension";
-		info->description =
-			"This test creates two channels, bridges them, and then"
-			" blind transfers the bridge to an extension.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	bridge = ast_bridge_basic_new();
-	ast_test_validate(test, bridge != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
-
-	ANSWER_NO_APP(chan_alice);
-	ANSWER_NO_APP(chan_bob);
-
-	BRIDGE_ENTER(chan_bob, bridge);
-	BRIDGE_ENTER(chan_alice, bridge);
-
-	ast_bridge_lock(bridge);
-	transfer_msg = ast_blind_transfer_message_create(1, chan_alice,
-			"transfer_extension", "transfer_context");
-	if (!transfer_msg) {
-		ast_bridge_unlock(bridge);
-		ast_test_status_update(test, "Failed to create transfer Stasis message\n");
-		return AST_TEST_FAIL;
-	}
-	transfer_msg->bridge = ast_bridge_snapshot_create(bridge);
-	if (!transfer_msg->bridge) {
-		ast_bridge_unlock(bridge);
-		ast_test_status_update(test, "Failed to create bridge snapshot\n");
-		return AST_TEST_FAIL;
-	}
-	ast_bridge_unlock(bridge);
-	transfer_msg->result = AST_BRIDGE_TRANSFER_SUCCESS;
-	ast_bridge_publish_blind_transfer(transfer_msg);
-	BLINDTRANSFER_EVENT(chan_alice, bridge, "transfer_extension", "transfer_context");
-
-	BRIDGE_EXIT(chan_alice, bridge);
-	BRIDGE_EXIT(chan_bob, bridge);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-/* XXX Validation needs to take into account the BRIDGE_EXIT for Alice and the
- * ATTENDEDTRANSFER message are not guaranteed to be ordered
- */
-#ifdef RACEY_TESTS
-AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-	struct ast_party_caller david_caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test attended transfers between two pairs of bridged parties";
-		info->description =
-			"This test creates four channels, places each pair in"
-			" a bridge, and then attended transfers the bridges"
-			" together.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	/* Create first set of bridged parties */
-	bridge1 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge1 != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
-	ANSWER_NO_APP(chan_alice);
-	ANSWER_NO_APP(chan_bob);
-
-	BRIDGE_ENTER(chan_bob, bridge1);
-	BRIDGE_ENTER(chan_alice, bridge1);
-
-	/* Create second set of bridged parties */
-	bridge2 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge2 != NULL);
-
-	CREATE_DAVID_CHANNEL(chan_david, &david_caller);
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
-	ANSWER_NO_APP(chan_david);
-	ANSWER_NO_APP(chan_charlie);
-
-	BRIDGE_ENTER(chan_charlie, bridge2);
-
-	BRIDGE_ENTER(chan_david, bridge2);
-	BRIDGE_EXIT_EVENT(chan_bob, bridge1);
-	do_sleep();
-
-	/* Perform attended transfer */
-	if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
-		ast_test_status_update(test, "Attended transfer failed!\n");
-		return AST_TEST_FAIL;
-	}
-	do_sleep();
-	BRIDGE_ENTER_EVENT_PEER(chan_bob, bridge2, "CELTestChannel/David,CELTestChannel/Charlie");
-
-	BRIDGE_EXIT_EVENT(chan_david, bridge2);
-	BRIDGE_EXIT_EVENT(chan_alice, bridge1);
-	ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
-
-	do_sleep();
-	BRIDGE_EXIT(chan_bob, bridge2);
-	BRIDGE_EXIT(chan_charlie, bridge2);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-#endif
-
-AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-	struct ast_party_caller david_caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test attended transfers between two pairs of"
-			" bridged parties that results in a bridge merge";
-		info->description =
-			"This test creates four channels, places each pair"
-			" in a bridge, and then attended transfers the bridges"
-			" together causing a bridge merge.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	/* Create first set of bridged parties */
-	bridge1 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
-		AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
-		"test_cel", "test_cel_atxfer_bridges_merge_1", NULL);
-	ast_test_validate(test, bridge1 != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
-	ANSWER_NO_APP(chan_alice);
-	ANSWER_NO_APP(chan_bob);
-
-	BRIDGE_ENTER(chan_bob, bridge1);
-	BRIDGE_ENTER(chan_alice, bridge1);
-
-	/* Create second set of bridged parties */
-	bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
-		AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
-		"test_cel", "test_cel_atxfer_bridges_merge_2", NULL);
-	ast_test_validate(test, bridge2 != NULL);
-
-	CREATE_DAVID_CHANNEL(chan_david, &david_caller);
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
-	ANSWER_NO_APP(chan_david);
-	ANSWER_NO_APP(chan_charlie);
-
-	BRIDGE_ENTER(chan_charlie, bridge2);
-
-	BRIDGE_ENTER(chan_david, bridge2);
-
-	/* Perform attended transfer */
-	if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
-		ast_test_status_update(test, "Attended transfer failed!\n");
-		return AST_TEST_FAIL;
-	}
-	do_sleep();
-	BRIDGE_EXIT_EVENT_PEER(chan_charlie, bridge2, "CELTestChannel/David");
-	BRIDGE_ENTER_EVENT_PEER(chan_charlie, bridge1, "CELTestChannel/Bob,CELTestChannel/Alice");
-	BRIDGE_EXIT_EVENT(chan_david, bridge2);
-	BRIDGE_EXIT_EVENT(chan_alice, bridge1);
-
-	ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
-
-	do_sleep();
-	BRIDGE_EXIT(chan_bob, bridge1);
-	BRIDGE_EXIT(chan_charlie, bridge1);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-/* XXX Validation needs to take into account the BRIDGE_EXIT for David and the
- * ATTENDEDTRANSFER message are not guaranteed to be ordered
- */
-#ifdef RACEY_TESTS
-AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-	struct ast_party_caller david_caller = ALICE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test attended transfers between two pairs of"
-			" bridged parties that results in a bridge merge";
-		info->description =
-			"This test creates four channels, places each pair"
-			" in a bridge, and then attended transfers the bridges"
-			" together causing a bridge link.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	/* Create first set of bridged parties */
-	bridge1 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
-		"test_cel", "test_cel_atxfer_bridges_link_1", NULL);
-	ast_test_validate(test, bridge1 != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
-	ANSWER_NO_APP(chan_alice);
-	ANSWER_NO_APP(chan_bob);
-
-	BRIDGE_ENTER(chan_bob, bridge1);
-	BRIDGE_ENTER(chan_alice, bridge1);
-
-	/* Create second set of bridged parties */
-	bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
-		| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
-		"test_cel", "test_cel_atxfer_bridges_link_2", NULL);
-	ast_test_validate(test, bridge2 != NULL);
-
-	CREATE_DAVID_CHANNEL(chan_david, &david_caller);
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
-	ANSWER_NO_APP(chan_david);
-	ANSWER_NO_APP(chan_charlie);
-
-	BRIDGE_ENTER(chan_charlie, bridge2);
-	BRIDGE_ENTER(chan_david, bridge2);
-
-	/* Perform attended transfer */
-	ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
-
-	ast_bridge_transfer_attended(chan_alice, chan_david);
-	do_sleep();
-
-	/* BRIDGE_EXIT alice and david */
-	APPEND_DUMMY_EVENT();
-	APPEND_DUMMY_EVENT();
-
-	do_sleep();
-	BRIDGE_EXIT(chan_bob, bridge1);
-	BRIDGE_EXIT(chan_charlie, bridge2);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
-	do_sleep();
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
-	do_sleep();
-
-	return AST_TEST_PASS;
-}
-#endif
-
-AST_TEST_DEFINE(test_cel_dial_pickup)
-{
-	RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	struct ast_party_caller caller = ALICE_CALLERID;
-	struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test call pickup";
-		info->description =
-			"Test CEL records for a call that is\n"
-			"inbound to Asterisk, executes some dialplan, and\n"
-			"is picked up.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	CREATE_ALICE_CHANNEL(chan_caller, &caller);
-
-	EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
-
-	START_DIALED(chan_caller, chan_callee);
-
-	ast_channel_state_set(chan_caller, AST_STATE_RINGING);
-
-	CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
-
-	{
-		RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
-		SCOPED_CHANNELLOCK(lock, chan_callee);
-
-		extra = ast_json_pack("{s: s, s: s}", "pickup_channel", ast_channel_name(chan_charlie),
-			"pickup_channel_uniqueid", ast_channel_uniqueid(chan_charlie));
-		ast_test_validate(test, extra != NULL);
-
-		APPEND_EVENT(chan_callee, AST_CEL_PICKUP, NULL, extra);
-		ast_test_validate(test, !ast_do_pickup(chan_charlie, chan_callee));
-	}
-
-	/* Hang up the masqueraded zombie */
-	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
-
-	ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
-
-	HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL");
-	HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_cel_local_optimize)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	struct ast_party_caller alice_caller = ALICE_CALLERID;
-	struct ast_party_caller bob_caller = BOB_CALLERID;
-	RAII_VAR(struct ast_multi_channel_blob *, mc_blob, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, alice_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, bob_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, local_opt_begin, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, local_opt_end, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test local channel optimization record generation";
-		info->description =
-			"Test CEL records for two local channels being optimized\n"
-			"out by sending a messages indicating local optimization\n"
-			"begin and end\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	mc_blob = ast_multi_channel_blob_create(ast_json_null());
-	ast_test_validate(test, mc_blob != NULL);
-
-	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
-	CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
-
-	ast_channel_lock(chan_alice);
-	alice_snapshot = ast_channel_snapshot_create(chan_alice);
-	ast_channel_unlock(chan_alice);
-	ast_test_validate(test, alice_snapshot != NULL);
-
-	ast_channel_lock(chan_bob);
-	bob_snapshot = ast_channel_snapshot_create(chan_bob);
-	ast_channel_unlock(chan_bob);
-	ast_test_validate(test, bob_snapshot != NULL);
-
-	ast_multi_channel_blob_add_channel(mc_blob, "1", alice_snapshot);
-	ast_multi_channel_blob_add_channel(mc_blob, "2", bob_snapshot);
-
-	local_opt_begin = stasis_message_create(ast_local_optimization_begin_type(), mc_blob);
-	ast_test_validate(test, local_opt_begin != NULL);
-
-	local_opt_end = stasis_message_create(ast_local_optimization_end_type(), mc_blob);
-	ast_test_validate(test, local_opt_end != NULL);
-
-	stasis_publish(ast_channel_topic(chan_alice), local_opt_begin);
-	stasis_publish(ast_channel_topic(chan_alice), local_opt_end);
-
-	extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->name,
-		"local_two_uniqueid", bob_snapshot->uniqueid);
-	ast_test_validate(test, extra != NULL);
-
-	APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
-
-	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
-	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
-
-	return AST_TEST_PASS;
-}
-
-/*! Container for astobj2 duplicated ast_events */
-static struct ao2_container *cel_received_events = NULL;
-
-/*! Container for expected CEL events */
-static struct ao2_container *cel_expected_events = NULL;
-
-static struct ast_event *ao2_dup_event(const struct ast_event *event)
-{
-	struct ast_event *event_dup;
-	uint16_t event_len;
-
-	event_len = ast_event_get_size(event);
-
-	event_dup = ao2_alloc(event_len, NULL);
-	if (!event_dup) {
-		return NULL;
-	}
-
-	memcpy(event_dup, event, event_len);
-
-	return event_dup;
-}
-
-static void mid_test_sync(void)
-{
-	ast_mutex_lock(&mid_test_sync_lock);
-	if (ao2_container_count(cel_expected_events) <= ao2_container_count(cel_received_events)) {
-		ast_mutex_unlock(&mid_test_sync_lock);
-		return;
-	}
-
-	do_mid_test_sync = 1;
-	ast_mutex_unlock(&mid_test_sync_lock);
-
-	{
-		struct timeval start = ast_tvnow();
-		struct timespec end = {
-			.tv_sec = start.tv_sec + 15,
-			.tv_nsec = start.tv_usec * 1000
-		};
-
-		SCOPED_MUTEX(lock, &sync_lock);
-		ast_cond_timedwait(&sync_out, &sync_lock, &end);
-	}
-}
-
-static int append_event(struct ast_event *ev)
-{
-	RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
-	ao2_ev = ao2_dup_event(ev);
-	if (!ao2_ev) {
-		return -1;
-	}
-
-	ao2_link(cel_expected_events, ao2_ev);
-	return 0;
-}
-
-#ifdef RACEY_TESTS
-static int append_dummy_event(void)
-{
-	RAII_VAR(struct ast_event *, ev, NULL, ast_free);
-	RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
-
-	ev = ast_event_new(AST_EVENT_CUSTOM, AST_EVENT_IE_END);
-	if (!ev) {
-		return -1;
-	}
-
-	return append_event(ev);
-}
-#endif
-
-static int append_expected_event_snapshot(
-	struct ast_channel_snapshot *snapshot,
-	enum ast_cel_event_type type,
-	const char *userdefevname,
-	struct ast_json *extra,
-	const char *peer)
-{
-	RAII_VAR(struct ast_event *, ev, NULL, ast_free);
-	ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
-	if (!ev) {
-		return -1;
-	}
-
-	return append_event(ev);
-}
-
-static int append_expected_event(
-	struct ast_channel *chan,
-	enum ast_cel_event_type type,
-	const char *userdefevname,
-	struct ast_json *extra,
-	const char *peer)
-{
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	ast_channel_lock(chan);
-	snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (!snapshot) {
-		return -1;
-	}
-
-	return append_expected_event_snapshot(snapshot, type, userdefevname, extra, peer);
-}
-
-static void test_sub(struct ast_event *event)
-{
-	struct ast_event *event_dup = ao2_dup_event(event);
-	const char *chan_name;
-	SCOPED_MUTEX(mid_test_lock, &mid_test_sync_lock);
-
-	if (!event_dup) {
-		return;
-	}
-
-	chan_name = ast_event_get_ie_str(event_dup, AST_EVENT_IE_CEL_CHANNAME);
-	if (chan_name && strncmp(chan_name, CHANNEL_TECH_NAME, 14)) {
-		return;
-	}
-
-	/* save the event for later processing */
-	ao2_link(cel_received_events, event_dup);
-
-	if (do_mid_test_sync) {
-		int expected = ao2_container_count(cel_expected_events);
-		int received = ao2_container_count(cel_received_events);
-		if (expected <= received) {
-			{
-			SCOPED_MUTEX(lock, &sync_lock);
-			ast_cond_signal(&sync_out);
-			do_mid_test_sync = 0;
-			}
-		}
-	}
-}
-
-/*!
- * \internal
- * \brief Callback function called before each test executes
- */
-static int test_cel_init_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	ast_assert(cel_received_events == NULL);
-	ast_assert(cel_expected_events == NULL);
-
-	ast_mutex_init(&mid_test_sync_lock);
-	ast_mutex_init(&sync_lock);
-	ast_cond_init(&sync_out, NULL);
-
-	/* Back up the real CEL config and insert the test's config */
-	saved_config = ast_cel_get_config();
-	ast_cel_set_config(cel_test_config);
-
-	/* init CEL event storage (degenerate hash table becomes a linked list) */
-	cel_received_events = ao2_container_alloc(1, NULL, NULL);
-	cel_expected_events = ao2_container_alloc(1, NULL, NULL);
-
-	/* start the CEL event callback */
-	if (ast_cel_backend_register(TEST_BACKEND_NAME, test_sub)) {
-		return -1;
-	}
-	return 0;
-}
-
-/*!
- * \brief Check two peer strings for equality
- *
- * \retval zero if the peer strings do not match
- * \retval non-zero if the peer strings match
- */
-static int test_cel_peer_strings_match(const char *str1, const char *str2)
-{
-	struct ao2_container *intersection = ast_str_container_alloc(11);
-	RAII_VAR(char *, str1_dup, ast_strdup(str1), ast_free);
-	RAII_VAR(char *, str2_dup, ast_strdup(str2), ast_free);
-	char *chan;
-
-	while ((chan = strsep(&str1_dup, ","))) {
-		ast_str_container_add(intersection, chan);
-	}
-
-	while ((chan = strsep(&str2_dup, ","))) {
-		RAII_VAR(char *, ao2_chan, ao2_find(intersection, chan, OBJ_SEARCH_KEY), ao2_cleanup);
-
-		/* item in str2 not in str1 */
-		if (!ao2_chan) {
-			return 0;
-		}
-
-		ast_str_container_remove(intersection, chan);
-	}
-
-	/* item in str1 not in str2 */
-	if (ao2_container_count(intersection)) {
-		return 0;
-	}
-
-	return 1;
-}
-
-/*!
- * \brief Check an IE value from two events
- *
- * \retval zero if the IEs in the events of the specified type do not match
- * \retval non-zero if the IEs in the events of the specified type match
- */
-static int match_ie_val(
-	const struct ast_event *event1,
-	const struct ast_event *event2,
-	enum ast_event_ie_type type)
-{
-	enum ast_event_ie_pltype pltype = ast_event_get_ie_pltype(type);
-
-	/* XXX ignore sec/usec for now */
-	if (type == AST_EVENT_IE_CEL_EVENT_TIME_USEC) {
-		return 1;
-	}
-
-	if (type == AST_EVENT_IE_CEL_EVENT_TIME) {
-		return 1;
-	}
-
-	switch (pltype) {
-	case AST_EVENT_IE_PLTYPE_UINT:
-	{
-		uint32_t val = ast_event_get_ie_uint(event2, type);
-
-		return (val == ast_event_get_ie_uint(event1, type)) ? 1 : 0;
-	}
-	case AST_EVENT_IE_PLTYPE_STR:
-	{
-		const char *str1 = ast_event_get_ie_str(event1, type);
-		const char *str2 = ast_event_get_ie_str(event2, type);
-
-		if (!str1 && !str2) {
-			return 1;
-		} else if (!str1) {
-			return 0;
-		} else if (!str2) {
-			return 0;
-		}
-
-		/* use special matching for CEL PEER field */
-		if (type == AST_EVENT_IE_CEL_PEER) {
-			return test_cel_peer_strings_match(str1, str2);
-		}
-
-		return !strcmp(str1, str2);
-	}
-	case AST_EVENT_IE_PLTYPE_RAW:
-	case AST_EVENT_IE_PLTYPE_BITFLAGS:
-		/* Fall through: just pass on these types */
-		return 1;
-	default:
-		break;
-	}
-	return 0;
-}
-
-static int events_are_equal(struct ast_test *test, struct ast_event *received, struct ast_event *expected)
-{
-	struct ast_event_iterator iterator;
-	int res;
-
-	if (ast_event_get_type(expected) == AST_EVENT_CUSTOM) {
-		/* this event is flagged as a wildcard match */
-		return 1;
-	}
-
-	for (res = ast_event_iterator_init(&iterator, received); !res; res = ast_event_iterator_next(&iterator)) {
-		int ie_type = ast_event_iterator_get_ie_type(&iterator);
-		if (!match_ie_val(received, expected, ie_type)) {
-			ast_test_status_update(test, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type));
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-static int dump_event(struct ast_test *test, struct ast_event *event)
-{
-	struct ast_event_iterator i;
-
-	if (ast_event_iterator_init(&i, event)) {
-		ast_test_status_update(test, "Failed to initialize event iterator.  :-(\n");
-		return 0;
-	}
-
-	ast_test_status_update(test, "Event: %s\n",
-		ast_cel_get_type_name(ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TYPE)));
-
-	do {
-		enum ast_event_ie_type ie_type;
-		enum ast_event_ie_pltype ie_pltype;
-		const char *ie_type_name;
-
-		ie_type = ast_event_iterator_get_ie_type(&i);
-		ie_type_name = ast_event_get_ie_type_name(ie_type);
-		ie_pltype = ast_event_get_ie_pltype(ie_type);
-
-		switch (ie_pltype) {
-		case AST_EVENT_IE_PLTYPE_UNKNOWN:
-		case AST_EVENT_IE_PLTYPE_STR:
-			ast_test_status_update(test, "%.30s: %s\n", ie_type_name,
-					ast_event_iterator_get_ie_str(&i));
-			break;
-		case AST_EVENT_IE_PLTYPE_UINT:
-			ast_test_status_update(test, "%.30s: %u\n", ie_type_name,
-					ast_event_iterator_get_ie_uint(&i));
-			break;
-		default:
-			break;
-		}
-	} while (!ast_event_iterator_next(&i));
-
-	ast_test_status_update(test, "\n");
-
-	return 0;
-}
-
-static int check_events(struct ast_test *test, struct ao2_container *local_expected, struct ao2_container *local_received)
-{
-	struct ao2_iterator received_it;
-	struct ao2_iterator expected_it;
-	RAII_VAR(struct ast_event *, rx_event, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_event *, ex_event, NULL, ao2_cleanup);
-	int debug = 0;
-
-	if (ao2_container_count(local_expected) != ao2_container_count(local_received)) {
-		ast_test_status_update(test, "Increasing verbosity since the number of expected events (%d)"
-			" did not match number of received events (%d).\n",
-			ao2_container_count(local_expected),
-			ao2_container_count(local_received));
-		debug = 1;
-	}
-
-	received_it = ao2_iterator_init(local_received, 0);
-	expected_it = ao2_iterator_init(local_expected, 0);
-	rx_event = ao2_iterator_next(&received_it);
-	ex_event = ao2_iterator_next(&expected_it);
-	while (rx_event && ex_event) {
-		if (!events_are_equal(test, rx_event, ex_event)) {
-			ao2_iterator_destroy(&received_it);
-			ao2_iterator_destroy(&expected_it);
-			ast_test_status_update(test, "Received event:\n");
-			dump_event(test, rx_event);
-			ast_test_status_update(test, "Expected event:\n");
-			dump_event(test, ex_event);
-			return -1;
-		}
-		if (debug) {
-			ast_test_status_update(test, "Compared events successfully%s\n",
-				ast_event_get_type(ex_event) == AST_EVENT_CUSTOM
-					? " (wildcard match)" : "");
-			dump_event(test, rx_event);
-		}
-		ao2_cleanup(rx_event);
-		ao2_cleanup(ex_event);
-		rx_event = ao2_iterator_next(&received_it);
-		ex_event = ao2_iterator_next(&expected_it);
-	}
-	ao2_iterator_destroy(&received_it);
-	ao2_iterator_destroy(&expected_it);
-
-	if (rx_event) {
-		ast_test_status_update(test, "Received event:\n");
-		dump_event(test, rx_event);
-		return -1;
-	}
-	if (ex_event) {
-		ast_test_status_update(test, "Expected event:\n");
-		dump_event(test, ex_event);
-		return -1;
-	}
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Callback function called after each test executes.
- *
- * \details
- * In addition to cleanup, this function also performs verification
- * that the events received during a test match the events that were
- * expected to have been generated during the test.
- */
-static int cel_verify_and_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	RAII_VAR(struct ao2_container *, local_expected, cel_expected_events, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, local_received, cel_received_events, ao2_cleanup);
-	ast_assert(cel_received_events != NULL);
-	ast_assert(cel_expected_events != NULL);
-
-	do_sleep();
-
-	/* stop the CEL event callback and clean up storage structures*/
-	ast_cel_backend_unregister(TEST_BACKEND_NAME);
-
-	/* cleaned up by RAII_VAR's */
-	cel_expected_events = NULL;
-	cel_received_events = NULL;
-
-	/* check events */
-	ast_test_validate(test, !check_events(test, local_expected, local_received));
-
-	/* Restore the real CEL config */
-	ast_cel_set_config(saved_config);
-	ao2_cleanup(saved_config);
-	saved_config = NULL;
-
-	/* clean up the locks */
-	ast_mutex_destroy(&sync_lock);
-	ast_mutex_destroy(&mid_test_sync_lock);
-	ast_cond_destroy(&sync_out);
-	return 0;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(test_cel_channel_creation);
-	AST_TEST_UNREGISTER(test_cel_unanswered_inbound_call);
-	AST_TEST_UNREGISTER(test_cel_unanswered_outbound_call);
-	AST_TEST_UNREGISTER(test_cel_single_party);
-	AST_TEST_UNREGISTER(test_cel_single_bridge);
-	AST_TEST_UNREGISTER(test_cel_single_bridge_continue);
-	AST_TEST_UNREGISTER(test_cel_single_twoparty_bridge_a);
-	AST_TEST_UNREGISTER(test_cel_single_twoparty_bridge_b);
-#ifdef RACEY_TESTS
-	AST_TEST_UNREGISTER(test_cel_single_multiparty_bridge);
-#endif
-
-	AST_TEST_UNREGISTER(test_cel_dial_unanswered);
-	AST_TEST_UNREGISTER(test_cel_dial_unanswered_filter);
-	AST_TEST_UNREGISTER(test_cel_dial_congestion);
-	AST_TEST_UNREGISTER(test_cel_dial_busy);
-	AST_TEST_UNREGISTER(test_cel_dial_unavailable);
-	AST_TEST_UNREGISTER(test_cel_dial_caller_cancel);
-	AST_TEST_UNREGISTER(test_cel_dial_parallel_failed);
-	AST_TEST_UNREGISTER(test_cel_dial_answer_no_bridge);
-	AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_a);
-	AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_b);
-#ifdef RACEY_TESTS
-	AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);
-	AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_swap);
-	AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_link);
-#endif
-
-	AST_TEST_UNREGISTER(test_cel_blind_transfer);
-	AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_merge);
-
-	AST_TEST_UNREGISTER(test_cel_dial_pickup);
-
-	AST_TEST_UNREGISTER(test_cel_local_optimize);
-
-	ast_channel_unregister(&test_cel_chan_tech);
-
-	ao2_cleanup(cel_test_config);
-	cel_test_config = NULL;
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	/* build the test config */
-	cel_test_config = ast_cel_general_config_alloc();
-	if (!cel_test_config) {
-		return -1;
-	}
-	cel_test_config->enable = 1;
-	if (ast_str_container_add(cel_test_config->apps, "dial")) {
-		return -1;
-	}
-	if (ast_str_container_add(cel_test_config->apps, "park")) {
-		return -1;
-	}
-	if (ast_str_container_add(cel_test_config->apps, "queue")) {
-		return -1;
-	}
-	cel_test_config->events |= 1<<AST_CEL_APP_START;
-	cel_test_config->events |= 1<<AST_CEL_CHANNEL_START;
-	cel_test_config->events |= 1<<AST_CEL_CHANNEL_END;
-	cel_test_config->events |= 1<<AST_CEL_ANSWER;
-	cel_test_config->events |= 1<<AST_CEL_HANGUP;
-	cel_test_config->events |= 1<<AST_CEL_BRIDGE_ENTER;
-	cel_test_config->events |= 1<<AST_CEL_BRIDGE_EXIT;
-	cel_test_config->events |= 1<<AST_CEL_BLINDTRANSFER;
-	cel_test_config->events |= 1<<AST_CEL_ATTENDEDTRANSFER;
-	cel_test_config->events |= 1<<AST_CEL_PICKUP;
-	cel_test_config->events |= 1<<AST_CEL_LOCAL_OPTIMIZE;
-
-	ast_channel_register(&test_cel_chan_tech);
-
-	AST_TEST_REGISTER(test_cel_channel_creation);
-	AST_TEST_REGISTER(test_cel_unanswered_inbound_call);
-	AST_TEST_REGISTER(test_cel_unanswered_outbound_call);
-
-	AST_TEST_REGISTER(test_cel_single_party);
-	AST_TEST_REGISTER(test_cel_single_bridge);
-	AST_TEST_REGISTER(test_cel_single_bridge_continue);
-	AST_TEST_REGISTER(test_cel_single_twoparty_bridge_a);
-	AST_TEST_REGISTER(test_cel_single_twoparty_bridge_b);
-#ifdef RACEY_TESTS
-	AST_TEST_REGISTER(test_cel_single_multiparty_bridge);
-#endif
-
-	AST_TEST_REGISTER(test_cel_dial_unanswered);
-	AST_TEST_REGISTER(test_cel_dial_unanswered_filter);
-	AST_TEST_REGISTER(test_cel_dial_congestion);
-	AST_TEST_REGISTER(test_cel_dial_busy);
-	AST_TEST_REGISTER(test_cel_dial_unavailable);
-	AST_TEST_REGISTER(test_cel_dial_caller_cancel);
-	AST_TEST_REGISTER(test_cel_dial_parallel_failed);
-	AST_TEST_REGISTER(test_cel_dial_answer_no_bridge);
-	AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_a);
-	AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_b);
-#ifdef RACEY_TESTS
-	AST_TEST_REGISTER(test_cel_dial_answer_multiparty);
-	AST_TEST_REGISTER(test_cel_attended_transfer_bridges_swap);
-	AST_TEST_REGISTER(test_cel_attended_transfer_bridges_link);
-#endif
-
-	AST_TEST_REGISTER(test_cel_blind_transfer);
-	AST_TEST_REGISTER(test_cel_attended_transfer_bridges_merge);
-
-	AST_TEST_REGISTER(test_cel_dial_pickup);
-
-	AST_TEST_REGISTER(test_cel_local_optimize);
-
-	/* ast_test_register_* has to happen after AST_TEST_REGISTER */
-	/* Verify received vs expected events and clean things up after every test */
-	ast_test_register_init(TEST_CATEGORY, test_cel_init_cb);
-	ast_test_register_cleanup(TEST_CATEGORY, cel_verify_and_cleanup_cb);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CEL unit tests");
diff --git a/tests/test_channel_feature_hooks.c b/tests/test_channel_feature_hooks.c
deleted file mode 100644
index 92a4fa0..0000000
--- a/tests/test_channel_feature_hooks.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kinsey Moore <kmoore at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Channel features unit tests
- *
- * \author Kinsey Moore <kmoore at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428604 $")
-
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/channel.h"
-#include "asterisk/time.h"
-#include "asterisk/bridge.h"
-#include "asterisk/bridge_basic.h"
-#include "asterisk/features.h"
-
-#define TEST_CATEGORY "/channels/features/"
-
-#define CHANNEL_TECH_NAME "FeaturesTestChannel"
-
-#define TEST_BACKEND_NAME "Features Test Logging"
-
-/*! \brief A channel technology used for the unit tests */
-static struct ast_channel_tech test_features_chan_tech = {
-	.type = CHANNEL_TECH_NAME,
-	.description = "Mock channel technology for Features tests",
-};
-
-static void test_nanosleep(int secs, long nanosecs)
-{
-	struct timespec sleep_time = {secs, nanosecs};
-
-	while ((nanosleep(&sleep_time, &sleep_time) == -1) && (errno == EINTR)) {
-	}
-}
-
-/*! \brief Wait until a channel is bridged */
-static void wait_for_bridged(struct ast_channel *channel)
-{
-	ast_channel_lock(channel);
-	while (!ast_channel_is_bridged(channel)) {
-		ast_channel_unlock(channel);
-		test_nanosleep(0, 1000000);
-		ast_channel_lock(channel);
-	}
-	ast_channel_unlock(channel);
-}
-
-/*! \brief Wait until a channel is not bridged */
-static void wait_for_unbridged(struct ast_channel *channel)
-{
-	ast_channel_lock(channel);
-	while (ast_channel_is_bridged(channel)) {
-		ast_channel_unlock(channel);
-		test_nanosleep(0, 1000000);
-		ast_channel_lock(channel);
-	}
-	ast_channel_unlock(channel);
-}
-
-/*! \brief Create a \ref test_features_chan_tech for Alice. */
-#define START_ALICE(channel) START_CHANNEL(channel, "Alice", "100")
-
-/*! \brief Create a \ref test_features_chan_tech for Bob. */
-#define START_BOB(channel) START_CHANNEL(channel, "Bob", "200")
-
-#define START_CHANNEL(channel, name, number) do { \
-	channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \
-		"default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \
-	ast_channel_unlock(channel); \
-	} while (0)
-
-/*! \brief Hang up a test channel safely */
-#define HANGUP_CHANNEL(channel) do { \
-	ao2_ref(channel, +1); \
-	ast_hangup((channel)); \
-	ao2_cleanup(channel); \
-	channel = NULL; \
-	} while (0)
-
-static void safe_channel_release(struct ast_channel *chan)
-{
-	if (!chan) {
-		return;
-	}
-	ast_channel_release(chan);
-}
-
-static void safe_bridge_destroy(struct ast_bridge *bridge)
-{
-	if (!bridge) {
-		return;
-	}
-	ast_bridge_destroy(bridge, 0);
-}
-
-static int feature_callback(struct ast_bridge_channel *bridge_channel, void *obj)
-{
-	int *callback_executed = obj;
-	(*callback_executed)++;
-	return 0;
-}
-
-/* Need to post null frames periodically so DTMF emulation can work. */
-static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
-{
-	long nanosecs;
-
-	ast_assert(chan != NULL);
-	ast_assert(0 < ms);
-	ast_assert(0 < interval_ms);
-
-	nanosecs = interval_ms * 1000000L;
-	while (0 < ms) {
-		ast_queue_frame(chan, &ast_null_frame);
-
-		if (interval_ms < ms) {
-			ms -= interval_ms;
-		} else {
-			nanosecs = ms * 1000000L;
-			ms = 0;
-		}
-		test_nanosleep(0, nanosecs);
-	}
-}
-
-AST_TEST_DEFINE(test_features_channel_dtmf)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
-	struct ast_bridge_features features;
-	int callback_executed = 0;
-	struct ast_frame f = { AST_FRAME_DTMF, };
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test running DTMF hooks on a channel via the feature hooks mechanism";
-		info->description =
-			"This test creates two channels, adds a DTMF hook to one, places them into\n"
-			"a bridge, and verifies that the DTMF hook added to the channel feature\n"
-			"hooks can be triggered once the channel is bridged.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Create the bridges */
-	bridge1 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge1 != NULL);
-	bridge2 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge2 != NULL);
-
-	/* Create channels that will go into the bridge */
-	START_ALICE(chan_alice);
-	START_BOB(chan_bob);
-
-	/* Setup the features and add them to alice */
-	ast_bridge_features_init(&features);
-	ast_test_validate(test, !ast_bridge_dtmf_hook(&features, "##**", feature_callback, &callback_executed, NULL, 0));
-	ast_test_validate(test, !ast_channel_feature_hooks_append(chan_alice, &features));
-	ast_bridge_features_cleanup(&features);
-
-	/* Bridge the channels */
-	ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	wait_for_bridged(chan_alice);
-
-	/* Execute the feature */
-	f.len = 100;
-	f.subclass.integer = '#';
-	ast_queue_frame(chan_alice, &f);
-	ast_queue_frame(chan_alice, &f);
-	f.subclass.integer = '*';
-	ast_queue_frame(chan_alice, &f);
-	ast_queue_frame(chan_alice, &f);
-
-	stream_periodic_frames(chan_alice, 1000, 20);
-
-	/* Remove the channels from the bridge */
-	ast_test_validate(test, !ast_bridge_depart(chan_alice));
-	ast_test_validate(test, !ast_bridge_depart(chan_bob));
-
-	wait_for_unbridged(chan_alice);
-
-	/* Bridge the channels again to ensure that the feature hook remains on the channel */
-	ast_test_validate(test, !ast_bridge_impart(bridge2, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	ast_test_validate(test, !ast_bridge_impart(bridge2, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	wait_for_bridged(chan_alice);
-
-	/* Execute the feature */
-	f.len = 100;
-	f.subclass.integer = '#';
-	ast_queue_frame(chan_alice, &f);
-	ast_queue_frame(chan_alice, &f);
-	f.subclass.integer = '*';
-	ast_queue_frame(chan_alice, &f);
-	ast_queue_frame(chan_alice, &f);
-
-	stream_periodic_frames(chan_alice, 1000, 20);
-
-	/* Remove the channels from the bridge */
-	ast_test_validate(test, !ast_bridge_depart(chan_alice));
-	ast_test_validate(test, !ast_bridge_depart(chan_bob));
-
-	/* Hangup the channels */
-	HANGUP_CHANNEL(chan_alice);
-	HANGUP_CHANNEL(chan_bob);
-
-	ast_test_validate(test, callback_executed == 2);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_features_channel_interval)
-{
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
-	RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
-	struct ast_bridge_features features;
-	int callback_executed = 0;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test running interval hooks on a channel via the feature hooks mechanism";
-		info->description =
-			"This test creates two channels, adds an interval hook to one, places them\n"
-			"into a bridge, and verifies that the interval hook added to the channel\n"
-			"feature hooks is triggered once the channel is bridged.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Create the bridges */
-	bridge1 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge1 != NULL);
-	bridge2 = ast_bridge_basic_new();
-	ast_test_validate(test, bridge2 != NULL);
-
-	/* Create channels that will go into the bridge */
-	START_ALICE(chan_alice);
-	START_BOB(chan_bob);
-
-	/* Setup the features and add them to alice */
-	ast_bridge_features_init(&features);
-	ast_test_validate(test, !ast_bridge_interval_hook(&features, 0, 1000, feature_callback, &callback_executed, NULL, 0));
-	ast_test_validate(test, !ast_channel_feature_hooks_append(chan_alice, &features));
-	ast_bridge_features_cleanup(&features);
-
-	/* Bridge the channels */
-	ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	wait_for_bridged(chan_alice);
-
-	/* Let the interval hook execute once */
-	test_nanosleep(1, 500000000);
-
-	/* Remove the channels from the bridge */
-	ast_test_validate(test, !ast_bridge_depart(chan_alice));
-	ast_test_validate(test, !ast_bridge_depart(chan_bob));
-
-	wait_for_unbridged(chan_alice);
-
-	ast_test_validate(test, callback_executed >= 1);
-	callback_executed = 0;
-
-	/* Bridge the channels again to ensure that the feature hook remains on the channel */
-	ast_test_validate(test, !ast_bridge_impart(bridge2, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-	ast_test_validate(test, !ast_bridge_impart(bridge2, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
-
-	wait_for_bridged(chan_alice);
-
-	/* Let the interval hook execute once */
-	test_nanosleep(1, 500000000);
-
-	/* Remove the channels from the bridge */
-	ast_test_validate(test, !ast_bridge_depart(chan_alice));
-	ast_test_validate(test, !ast_bridge_depart(chan_bob));
-
-	/* Hangup the channels */
-	HANGUP_CHANNEL(chan_alice);
-	HANGUP_CHANNEL(chan_bob);
-
-	ast_test_validate(test, callback_executed >= 1);
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(test_features_channel_dtmf);
-	AST_TEST_UNREGISTER(test_features_channel_interval);
-
-	ast_channel_unregister(&test_features_chan_tech);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	ast_channel_register(&test_features_chan_tech);
-
-	AST_TEST_REGISTER(test_features_channel_dtmf);
-	AST_TEST_REGISTER(test_features_channel_interval);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridge Features Unit Tests");
diff --git a/tests/test_config.c b/tests/test_config.c
index 65a11a3..e7ee675 100644
--- a/tests/test_config.c
+++ b/tests/test_config.c
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425714 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include <math.h> /* HUGE_VAL */
 
@@ -45,7 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 425714 $");
 #include "asterisk/frame.h"
 #include "asterisk/utils.h"
 #include "asterisk/logger.h"
-#include "asterisk/format_cap.h"
 
 #define CONFIG_FILE "test_config.conf"
 
@@ -227,575 +226,6 @@ out:
 	return res;
 }
 
-AST_TEST_DEFINE(config_basic_ops)
-{
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_config *cfg = NULL;
-	struct ast_category *cat = NULL;
-	struct ast_variable *var;
-	char temp[32];
-	const char *cat_name;
-	const char *var_value;
-	int i;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "config_basic_ops";
-		info->category = "/main/config/";
-		info->summary = "Test basic config ops";
-		info->description =	"Test basic config ops";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	cfg = ast_config_new();
-	if (!cfg) {
-		return res;
-	}
-
-	/* load the config */
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		ast_category_append(cfg, ast_category_new(temp, "dummy", -1));
-	}
-
-	/* test0 test1 test2 test3 test4 */
-	/* check the config has 5 elements */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* search for test2 */
-	cat = ast_category_get(cfg, "test2", NULL);
-	if (!cat || strcmp(ast_category_get_name(cat), "test2")) {
-		ast_test_status_update(test, "Get failed %s != %s\n", ast_category_get_name(cat), "test2");
-		goto out;
-	}
-
-	/* delete test2 */
-	cat = ast_category_delete(cfg, cat);
-
-	/* Now: test0 test1 test3 test4 */
-	/* make sure the curr category is test1 */
-	if (!cat || strcmp(ast_category_get_name(cat), "test1")) {
-		ast_test_status_update(test, "Delete failed %s != %s\n", ast_category_get_name(cat), "test1");
-		goto out;
-	}
-
-	/* Now: test0 test1 test3 test4 */
-	/* make sure the test2 is not found */
-	cat = ast_category_get(cfg, "test2", NULL);
-	if (cat) {
-		ast_test_status_update(test, "Should not have found test2\n");
-		goto out;
-	}
-
-	/* Now: test0 test1 test3 test4 */
-	/* make sure the sequence is correctly missing test2 */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		i++;
-		if (i == 2) {
-			i++;
-		}
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* insert test2 back in before test3 */
-	ast_category_insert(cfg, ast_category_new("test2", "dummy", -1), "test3");
-
-	/* Now: test0 test1 test2 test3 test4 */
-	/* make sure the sequence is correct again */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* Now: test0 test1 test2 test3 test4 */
-	/* make sure non filtered browse still works */
-	i = 0;
-	cat_name = NULL;
-	while ((cat_name = ast_category_browse(cfg, cat_name))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(cat_name, temp)) {
-			ast_test_status_update(test, "%s != %s\n", cat_name, temp);
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* append another test2 */
-	ast_category_append(cfg, ast_category_new("test2", "dummy", -1));
-	/* Now: test0 test1 test2 test3 test4 test2*/
-	/* make sure only test2's are returned */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, "test2", cat, NULL))) {
-		if (strcmp(ast_category_get_name(cat), "test2")) {
-			ast_test_status_update(test, "Should have returned test2 instead of %s\n", ast_category_get_name(cat));
-			goto out;
-		}
-		i++;
-	}
-	/* make sure 2 test2's were found */
-	if (i != 2) {
-		ast_test_status_update(test, "Should have found 2 test2's %d\n", i);
-		goto out;
-	}
-
-	/* Test in-flight deletion using ast_category_browse_filtered */
-	/* Now: test0 test1 test2 test3 test4 test2 */
-	/* Delete the middle test2 and continue */
-	cat = NULL;
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-		cat_name = ast_category_get_name(cat);
-		if (strcmp(cat_name, temp)) {
-			ast_test_status_update(test, "Should have returned %s instead of %s: %d\n", temp, cat_name, i);
-			goto out;
-		}
-		if (i == 2) {
-			cat = ast_category_delete(cfg, cat);
-		}
-	}
-
-	/* Now: test0 test3 test4 test2 */
-	/* delete the head item */
-	cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test0")) {
-		ast_test_status_update(test, "Should have returned test0 instead of %s\n", cat_name);
-		goto out;
-	}
-	ast_category_delete(cfg, cat);
-	/* Now: test3 test4 test2 */
-
-	/* make sure head got updated to the new first element */
-	cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test1")) {
-		ast_test_status_update(test, "Should have returned test3 instead of %s\n", cat_name);
-		goto out;
-	}
-
-	/* delete the tail item */
-	cat = ast_category_get(cfg, "test2", NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test2")) {
-		ast_test_status_update(test, "Should have returned test2 instead of %s\n", cat_name);
-		goto out;
-	}
-	ast_category_delete(cfg, cat);
-	/* Now: test3 test4 */
-
-	/* There should now only be 2 elements in the list */
-	cat = NULL;
-	cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test1")) {
-		ast_test_status_update(test, "Should have returned test1 instead of %s\n", cat_name);
-		goto out;
-	}
-
-	cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test3")) {
-		ast_test_status_update(test, "Should have returned test3 instead of %s\n", cat_name);
-		goto out;
-	}
-
-	cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-	cat_name = ast_category_get_name(cat);
-	if (strcmp(cat_name, "test4")) {
-		ast_test_status_update(test, "Should have returned test4 instead of %s\n", cat_name);
-		goto out;
-	}
-
-	/* There should be nothing more */
-	cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-	if (cat) {
-		ast_test_status_update(test, "Should not have returned anything\n");
-		goto out;
-	}
-
-	/* Test ast_variable retrieve.
-	 * Get the second category.
-	 */
-	cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
-	cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
-	cat_name = ast_category_get_name(cat);
-	var = ast_variable_new("aaa", "bbb0", "dummy");
-	if (!var) {
-		ast_test_status_update(test, "Couldn't allocate variable.\n");
-		goto out;
-	}
-	ast_variable_append(cat, var);
-
-	/* Make sure we can retrieve with specific category name */
-	var_value = ast_variable_retrieve(cfg, cat_name, "aaa");
-	if (!var_value || strcmp(var_value, "bbb0")) {
-		ast_test_status_update(test, "Variable not found or wrong value.\n");
-		goto out;
-	}
-
-	/* Make sure we can retrieve with NULL category name */
-	var_value = ast_variable_retrieve(cfg, NULL, "aaa");
-	if (!var_value || strcmp(var_value, "bbb0")) {
-		ast_test_status_update(test, "Variable not found or wrong value.\n");
-		goto out;
-	}
-
-	/* Now test variable retrieve inside a browse loop
-	 * with multiple categories of the same name
-	 */
-	cat = ast_category_new("test3", "dummy", -1);
-	if (!cat) {
-		ast_test_status_update(test, "Couldn't allocate category.\n");
-		goto out;
-	}
-	var = ast_variable_new("aaa", "bbb1", "dummy");
-	if (!var) {
-		ast_test_status_update(test, "Couldn't allocate variable.\n");
-		goto out;
-	}
-	ast_variable_append(cat, var);
-	ast_category_append(cfg, cat);
-
-	cat = ast_category_new("test3", "dummy", -1);
-	if (!cat) {
-		ast_test_status_update(test, "Couldn't allocate category.\n");
-		goto out;
-	}
-	var = ast_variable_new("aaa", "bbb2", "dummy");
-	if (!var) {
-		ast_test_status_update(test, "Couldn't allocate variable.\n");
-		goto out;
-	}
-	ast_variable_append(cat, var);
-	ast_category_append(cfg, cat);
-
-	cat_name = NULL;
-	i = 0;
-	while ((cat_name = ast_category_browse(cfg, cat_name))) {
-		if (!strcmp(cat_name, "test3")) {
-			snprintf(temp, sizeof(temp), "bbb%d", i);
-
-			var_value = ast_variable_retrieve(cfg, cat_name, "aaa");
-			if (!var_value || strcmp(var_value, temp)) {
-				ast_test_status_update(test, "Variable not found or wrong value %s.\n", var_value);
-				goto out;
-			}
-
-			var = ast_variable_browse(cfg, cat_name);
-			if (!var->value || strcmp(var->value, temp)) {
-				ast_test_status_update(test, "Variable not found or wrong value %s.\n", var->value);
-				goto out;
-			}
-
-			i++;
-		}
-	}
-	if (i != 3) {
-		ast_test_status_update(test, "There should have been 3 matches instead of %d.\n", i);
-		goto out;
-	}
-
-	res = AST_TEST_PASS;
-
-out:
-	ast_config_destroy(cfg);
-	return res;
-}
-
-AST_TEST_DEFINE(config_filtered_ops)
-{
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_config *cfg = NULL;
-	struct ast_category *cat = NULL;
-	char temp[32];
-	const char *value;
-	int i;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "config_filtered_ops";
-		info->category = "/main/config/";
-		info->summary = "Test filtered config ops";
-		info->description =	"Test filtered config ops";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	cfg = ast_config_new();
-	if (!cfg) {
-		return res;
-	}
-
-	/* load the config */
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		cat = ast_category_new(temp, "dummy", -1);
-		ast_variable_insert(cat, ast_variable_new("type", "a", "dummy"), "0");
-		ast_category_append(cfg, cat);
-	}
-
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		cat = ast_category_new(temp, "dummy", -1);
-		ast_variable_insert(cat, ast_variable_new("type", "b", "dummy"), "0");
-		ast_category_append(cfg, cat);
-	}
-
-	/* check the config has 5 elements for each type*/
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "type=a"))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		value = ast_variable_find(cat, "type");
-		if (!value || strcmp(value, "a")) {
-			ast_test_status_update(test, "Type %s != %s\n", "a", value);
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "type=b"))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (!cat || strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		value = ast_variable_find(cat, "type");
-		if (!value || strcmp(value, "b")) {
-			ast_test_status_update(test, "Type %s != %s\n", "b", value);
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* Delete b3 and make sure it's gone and a3 is still there.
-	 * Really this is a test of get since delete takes a specific category structure.
-	 */
-	cat = ast_category_get(cfg, "test3", "type=b");
-	value = ast_variable_find(cat, "type");
-	if (strcmp(value, "b")) {
-		ast_test_status_update(test, "Type %s != %s\n", "b", value);
-		goto out;
-	}
-	ast_category_delete(cfg, cat);
-
-	cat = ast_category_get(cfg, "test3", "type=b");
-	if (cat) {
-		ast_test_status_update(test, "Category b was not deleted.\n");
-		goto out;
-	}
-
-	cat = ast_category_get(cfg, "test3", "type=a");
-	if (!cat) {
-		ast_test_status_update(test, "Category a was deleted.\n");
-		goto out;
-	}
-
-	value = ast_variable_find(cat, "type");
-	if (strcmp(value, "a")) {
-		ast_test_status_update(test, "Type %s != %s\n", value, "a");
-		goto out;
-	}
-
-	/* Basic regex stuff is handled by regcomp/regexec so not testing here.
-	 * Still need to test multiple name/value pairs though.
-	 */
-	ast_category_empty(cat);
-	ast_variable_insert(cat, ast_variable_new("type", "bx", "dummy"), "0");
-	ast_variable_insert(cat, ast_variable_new("e", "z", "dummy"), "0");
-
-	cat = ast_category_get(cfg, "test3", "type=.,e=z");
-	if (!cat) {
-		ast_test_status_update(test, "Category not found.\n");
-		goto out;
-	}
-
-	cat = ast_category_get(cfg, "test3", "type=.,e=zX");
-	if (cat) {
-		ast_test_status_update(test, "Category found.\n");
-		goto out;
-	}
-
-	cat = ast_category_get(cfg, "test3", "TEMPLATE=restrict,type=.,e=z");
-	if (cat) {
-		ast_test_status_update(test, "Category found.\n");
-		goto out;
-	}
-
-	res = AST_TEST_PASS;
-
-out:
-	ast_config_destroy(cfg);
-	return res;
-}
-
-AST_TEST_DEFINE(config_template_ops)
-{
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_config *cfg = NULL;
-	struct ast_category *cat = NULL;
-	char temp[32];
-	const char *value;
-	int i;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "config_template_ops";
-		info->category = "/main/config/";
-		info->summary = "Test template config ops";
-		info->description =	"Test template config ops";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	cfg = ast_config_new();
-	if (!cfg) {
-		return res;
-	}
-
-	/* load the config with 5 templates and 5 regular */
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		cat = ast_category_new_template(temp, "dummy", -1);
-		ast_variable_insert(cat, ast_variable_new("type", "a", "dummy"), "0");
-		ast_category_append(cfg, cat);
-	}
-
-	for(i = 0; i < 5; i++) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		cat = ast_category_new(temp, "dummy", -1);
-		ast_variable_insert(cat, ast_variable_new("type", "b", "dummy"), "0");
-		ast_category_append(cfg, cat);
-	}
-
-	/* check the config has 5 template elements of type a */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=restrict,type=a"))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		value = ast_variable_find(cat, "type");
-		if (!value || strcmp(value, "a")) {
-			ast_test_status_update(test, "Type %s != %s\n", value, "a");
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* Test again with 'include'.  There should still only be 5 (type a) */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=include,type=a"))) {
-		snprintf(temp, sizeof(temp), "test%d", i);
-		if (strcmp(ast_category_get_name(cat), temp)) {
-			ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
-			goto out;
-		}
-		value = ast_variable_find(cat, "type");
-		if (!value || strcmp(value, "a")) {
-			ast_test_status_update(test, "Type %s != %s\n", value, "a");
-			goto out;
-		}
-		i++;
-	}
-	if (i != 5) {
-		ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
-		goto out;
-	}
-
-	/* Test again with 'include' but no type.  There should now be 10 (type a and type b) */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=include"))) {
-		i++;
-	}
-	if (i != 10) {
-		ast_test_status_update(test, "There were %d matches instead of 10.\n", i);
-		goto out;
-	}
-
-	/* Test again with 'restrict' and type b.  There should 0 */
-	i = 0;
-	cat = NULL;
-	while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=restrict,type=b"))) {
-		i++;
-	}
-	if (i != 0) {
-		ast_test_status_update(test, "There were %d matches instead of 0.\n", i);
-		goto out;
-	}
-
-	res = AST_TEST_PASS;
-
-out:
-	ast_config_destroy(cfg);
-	return res;
-}
-
 /*!
  * \brief Write the config file to disk
  *
@@ -1197,6 +627,7 @@ struct test_item {
 	struct ast_sockaddr sockaddropt;
 	int boolopt;
 	struct ast_ha *aclopt;
+	struct ast_codec_pref codecprefopt;
 	struct ast_format_cap *codeccapopt;
 	unsigned int customopt:1;
 };
@@ -1222,7 +653,9 @@ static void test_item_destructor(void *obj)
 {
 	struct test_item *item = obj;
 	ast_string_field_free_memory(item);
-	ao2_cleanup(item->codeccapopt);
+	if (item->codeccapopt) {
+		ast_format_cap_destroy(item->codeccapopt);
+	}
 	if (item->aclopt) {
 		ast_free_ha(item->aclopt);
 	}
@@ -1238,7 +671,7 @@ static void *test_item_alloc(const char *cat)
 		ao2_ref(item, -1);
 		return NULL;
 	}
-	if (!(item->codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	if (!(item->codeccapopt = ast_format_cap_alloc())) {
 		ao2_ref(item, -1);
 		return NULL;
 	}
@@ -1316,7 +749,7 @@ struct aco_file config_test_conf = {
 };
 
 static AO2_GLOBAL_OBJ_STATIC(global_obj);
-CONFIG_INFO_TEST(cfg_info, global_obj, test_config_alloc,
+CONFIG_INFO_STANDARD(cfg_info, global_obj, test_config_alloc,
 	.files = ACO_FILES(&config_test_conf),
 );
 
@@ -1388,7 +821,7 @@ AST_TEST_DEFINE(config_options_test)
 	aco_option_register(&cfg_info, "boolflag3", ACO_EXACT, config_test_conf.types, BOOLFLAG3_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG3);
 	aco_option_register(&cfg_info, "aclpermitopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 1, FLDSET(struct test_item, aclopt));
 	aco_option_register(&cfg_info, "acldenyopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 0, FLDSET(struct test_item, aclopt));
-	aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codeccapopt));
+	aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codecprefopt, codeccapopt));
 	aco_option_register(&cfg_info, "stropt", ACO_EXACT, config_test_conf.types, STR_DEFAULT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct test_item, stropt));
 	aco_option_register_custom(&cfg_info, "customopt", ACO_EXACT, config_test_conf.types, CUSTOM_DEFAULT, customopt_handler, 0);
 	aco_option_register_deprecated(&cfg_info, "permit", config_test_conf.types, "aclpermitopt");
@@ -1422,11 +855,11 @@ AST_TEST_DEFINE(config_options_test)
 	ast_sockaddr_parse(&acl_allow, "1.2.3.4", PARSE_PORT_FORBID);
 	ast_sockaddr_parse(&acl_fail, "1.1.1.1", PARSE_PORT_FORBID);
 
-	defaults.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	ast_format_cap_update_by_allow_disallow(defaults.codeccapopt, CODEC_DEFAULT, 1);
+	defaults.codeccapopt = ast_format_cap_alloc();
+	ast_parse_allow_disallow(&defaults.codecprefopt, defaults.codeccapopt, CODEC_DEFAULT, 1);
 
-	configs.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	ast_format_cap_update_by_allow_disallow(configs.codeccapopt, CODEC_CONFIG, 1);
+	configs.codeccapopt = ast_format_cap_alloc();
+	ast_parse_allow_disallow(&configs.codecprefopt, configs.codeccapopt, CODEC_CONFIG, 1);
 
 	ast_string_field_init(&defaults, 128);
 	ast_string_field_init(&configs, 128);
@@ -1474,13 +907,10 @@ AST_TEST_DEFINE(config_options_test)
 			res = AST_TEST_FAIL;
 		}
 		if (!ast_format_cap_identical(arr[x]->codeccapopt, control->codeccapopt)) {
-			struct ast_str *codec_buf1 = ast_str_alloca(64);
-			struct ast_str *codec_buf2 = ast_str_alloca(64);
-
-			ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n",
-				ast_format_cap_get_names(arr[x]->codeccapopt, &codec_buf1),
-				ast_format_cap_get_names(control->codeccapopt, &codec_buf2),
-				x);
+			char buf1[128], buf2[128];
+			ast_getformatname_multiple(buf1, sizeof(buf1), arr[x]->codeccapopt);
+			ast_getformatname_multiple(buf2, sizeof(buf2), control->codeccapopt);
+			ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n", buf1, buf2, x);
 			res = AST_TEST_FAIL;
 		}
 		if (strcasecmp(arr[x]->stropt, control->stropt)) {
@@ -1495,10 +925,8 @@ AST_TEST_DEFINE(config_options_test)
 	}
 
 	ast_free_ha(configs.aclopt);
-	ao2_cleanup(defaults.codeccapopt);
-	defaults.codeccapopt = NULL;
-	ao2_cleanup(configs.codeccapopt);
-	configs.codeccapopt = NULL;
+	ast_format_cap_destroy(defaults.codeccapopt);
+	ast_format_cap_destroy(configs.codeccapopt);
 	ast_string_field_free_memory(&defaults);
 	ast_string_field_free_memory(&configs);
 	return res;
@@ -1506,9 +934,6 @@ AST_TEST_DEFINE(config_options_test)
 
 static int unload_module(void)
 {
-	AST_TEST_UNREGISTER(config_basic_ops);
-	AST_TEST_UNREGISTER(config_filtered_ops);
-	AST_TEST_UNREGISTER(config_template_ops);
 	AST_TEST_UNREGISTER(copy_config);
 	AST_TEST_UNREGISTER(config_hook);
 	AST_TEST_UNREGISTER(ast_parse_arg_test);
@@ -1518,9 +943,6 @@ static int unload_module(void)
 
 static int load_module(void)
 {
-	AST_TEST_REGISTER(config_basic_ops);
-	AST_TEST_REGISTER(config_filtered_ops);
-	AST_TEST_REGISTER(config_template_ops);
 	AST_TEST_REGISTER(copy_config);
 	AST_TEST_REGISTER(config_hook);
 	AST_TEST_REGISTER(ast_parse_arg_test);
diff --git a/tests/test_core_codec.c b/tests/test_core_codec.c
deleted file mode 100644
index fe8acff..0000000
--- a/tests/test_core_codec.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Core Codec API Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/codec.h"
-
-static struct ast_codec known_unknown = {
-	.name = "unit_test",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec doubly = {
-	.name = "unit_test_double",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec unknown = {
-	.name = "unit_test_unknown",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_UNKNOWN,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec audio_without_rate = {
-	.name = "unit_test_audio_without_rate",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec audio_get = {
-	.name = "unit_test_audio_get",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec audio_get_unknown = {
-	.name = "unit_test_audio_get_unknown",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-static struct ast_codec audio_get_id = {
-	.name = "unit_test_audio_get_id",
-	.description = "Unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-AST_TEST_DEFINE(codec_register)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_register";
-		info->category = "/main/core_codec/";
-		info->summary = "codec registration unit test";
-		info->description =
-			"Test registration of a core codec that is known to be unknown";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_codec_register(&known_unknown)) {
-		ast_test_status_update(test, "Unsuccessfully registered a codec that is known to be unknown\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_register_twice)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_register_twice";
-		info->category = "/main/core_codec/";
-		info->summary = "codec registration unit test";
-		info->description =
-			"Test double registration of a core codec to confirm it fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_codec_register(&doubly)) {
-		ast_test_status_update(test, "Unsuccessfully registered a codec that is known to be unknown\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_codec_register(&doubly)) {
-		ast_test_status_update(test, "Successfully registered a codec twice\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_register_unknown)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_register_unknown";
-		info->category = "/main/core_codec/";
-		info->summary = "codec registration unit test";
-		info->description =
-			"Test that registration of an unknown codec type fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!ast_codec_register(&unknown)) {
-		ast_test_status_update(test, "Successfully registered a codec with an unknown media type\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_register_audio_no_sample_rate)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_register_audio_no_sample_rate";
-		info->category = "/main/core_codec/";
-		info->summary = "codec registration unit test";
-		info->description =
-			"Test that registration of an audio codec without sample rate fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!ast_codec_register(&audio_without_rate)) {
-		ast_test_status_update(test, "Successfully registered an audio codec without a sample rate\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_get)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_get";
-		info->category = "/main/core_codec/";
-		info->summary = "codec get unit test";
-		info->description =
-			"Test that getting of a known codec succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_codec_register(&audio_get)) {
-		ast_test_status_update(test, "Unsucessfully registered a codec for getting\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get("unit_test_audio_get", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(codec->name, audio_get.name)) {
-		ast_test_status_update(test, "Name of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	} else if (codec->type != audio_get.type) {
-		ast_test_status_update(test, "Type of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	} else if (codec->sample_rate != audio_get.sample_rate) {
-		ast_test_status_update(test, "Sample rate of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_get_unregistered)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_get_unregistered";
-		info->category = "/main/core_codec/";
-		info->summary = "codec get unit test";
-		info->description =
-			"Test that getting of a codec that is not registered fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("goats", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (codec) {
-		ast_test_status_update(test, "Successfully got a codec named '%s' when getting a codec named 'goats'\n",
-			codec->name);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_get_unknown)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_get_unknown";
-		info->category = "/main/core_codec/";
-		info->summary = "codec get unit test";
-		info->description =
-			"Test that getting of a known codec using name and unknown type succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_codec_register(&audio_get_unknown)) {
-		ast_test_status_update(test, "Unsucessfully registered a codec for getting\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get("unit_test_audio_get_unknown", AST_MEDIA_TYPE_UNKNOWN, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(codec->name, audio_get_unknown.name)) {
-		ast_test_status_update(test, "Name of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	} else if (codec->type != audio_get_unknown.type) {
-		ast_test_status_update(test, "Type of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	} else if (codec->sample_rate != audio_get_unknown.sample_rate) {
-		ast_test_status_update(test, "Sample rate of retrieved codec does not match registered codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(codec_get_id)
-{
-	RAII_VAR(struct ast_codec *, named, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "codec_get_unknown";
-		info->category = "/main/core_codec/";
-		info->summary = "codec get unit test";
-		info->description =
-			"Test that getting of a known codec using name and unknown type succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_codec_register(&audio_get_id)) {
-		ast_test_status_update(test, "Unsucessfully registered a codec for getting\n");
-		return AST_TEST_FAIL;
-	}
-
-	named = ast_codec_get("unit_test_audio_get_id", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!named) {
-		ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get_by_id(named->id);
-	if (!codec) {
-		ast_test_status_update(test, "Unsuccessfully retrieved a codec using id of a named codec we just got\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(codec_register);
-	AST_TEST_UNREGISTER(codec_register_twice);
-	AST_TEST_UNREGISTER(codec_register_unknown);
-	AST_TEST_UNREGISTER(codec_register_audio_no_sample_rate);
-	AST_TEST_UNREGISTER(codec_get);
-	AST_TEST_UNREGISTER(codec_get_unregistered);
-	AST_TEST_UNREGISTER(codec_get_unknown);
-	AST_TEST_UNREGISTER(codec_get_id);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(codec_register);
-	AST_TEST_REGISTER(codec_register_twice);
-	AST_TEST_REGISTER(codec_register_unknown);
-	AST_TEST_REGISTER(codec_register_audio_no_sample_rate);
-	AST_TEST_REGISTER(codec_get);
-	AST_TEST_REGISTER(codec_get_unregistered);
-	AST_TEST_REGISTER(codec_get_unknown);
-	AST_TEST_REGISTER(codec_get_id);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core codec API test module");
diff --git a/tests/test_core_format.c b/tests/test_core_format.c
deleted file mode 100644
index 9f9c463..0000000
--- a/tests/test_core_format.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Core Format API Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419110 $")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-
-#define TEST_CATEGORY "/main/core_format/"
-
-static void test_core_format_destroy(struct ast_format *format);
-static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst);
-static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2);
-static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2);
-static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value);
-static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes);
-static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str);
-
-/*! \brief A format attribute 'module' used by the unit tests */
-static struct ast_format_interface test_core_format_attr = {
-	.format_destroy = &test_core_format_destroy,
-	.format_clone = &test_core_format_clone,
-	.format_cmp = &test_core_format_cmp,
-	.format_get_joint = &test_core_format_get_joint,
-	.format_attribute_set = &test_core_format_attribute_set,
-	.format_parse_sdp_fmtp = &test_core_format_parse_sdp_fmtp,
-	.format_generate_sdp_fmtp = &test_core_format_generate_sdp_fmtp,
-};
-
-/*! \brief A test piece of data to associate with \ref test_core_format_attr */
-struct test_core_format_pvt {
-	/*! Some data field */
-	int field_one;
-	/*! Another arbitrary data field */
-	int field_two;
-};
-
-/*! \brief A test codec for these unit tests. Should be used with \c test_core_format */
-static struct ast_codec test_core_format_codec = {
-	.name = "test_core_format_codec",
-	.description = "Unit test codec used by test_core_format",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-};
-
-/*! \brief Tracking object used to verify format attribute callbacks */
-struct callbacks_called {
-	/*! Number of times \ref test_core_format_destroy was called */
-	int format_destroy;
-	/*! Number of times \ref test_core_format_clone was called */
-	int format_clone;
-	/*! Number of times \ref test_core_format_cmp was called */
-	int format_cmp;
-	/*! Number of times \ref test_core_format_get_joint was called */
-	int format_get_joint;
-	/*! Number of times \ref test_core_format_attribute_set was called */
-	int format_attribute_set;
-	/*! Number of times \ref test_core_format_parse_sdp_fmtp was called */
-	int format_parse_sdp_fmtp;
-	/*! Number of times \ref test_core_format_generate_sdp_fmtp was called */
-	int format_generate_sdp_fmtp;
-};
-
-/*! \brief A global tracking object. Cleared out by the test init cb */
-static struct callbacks_called test_callbacks_called;
-
-/*! \brief Format attribute callback for when format attributes are to be destroyed */
-static void test_core_format_destroy(struct ast_format *format)
-{
-	struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format);
-
-	ast_free(pvt);
-	++test_callbacks_called.format_destroy;
-}
-
-/*! \brief Format attribute callback called during format cloning */
-static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	struct test_core_format_pvt *pvt = ast_format_get_attribute_data(src);
-	struct test_core_format_pvt *new_pvt;
-
-	new_pvt = ast_calloc(1, sizeof(*new_pvt));
-	if (!new_pvt) {
-		return -1;
-	}
-
-	if (pvt) {
-		*new_pvt = *pvt;
-	}
-	ast_format_set_attribute_data(dst, new_pvt);
-
-	++test_callbacks_called.format_clone;
-
-	return 0;
-}
-
-/*! \brief Format attribute callback called during format comparison */
-static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1);
-	struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2);
-
-	++test_callbacks_called.format_cmp;
-	if (pvt1 == pvt2) {
-		return AST_FORMAT_CMP_EQUAL;
-	}
-
-	if ((!pvt1 && pvt2 && (pvt2->field_one != 0 || pvt2->field_two != 0))
-		|| (pvt1 && !pvt2 && (pvt1->field_one != 0 || pvt1->field_two != 0))) {
-		return AST_FORMAT_CMP_NOT_EQUAL;
-	}
-
-	if (pvt1 && pvt2) {
-		if (!memcmp(pvt1, pvt2, sizeof(*pvt1))) {
-			return AST_FORMAT_CMP_EQUAL;
-		} else {
-			return AST_FORMAT_CMP_NOT_EQUAL;
-		}
-	}
-
-	return AST_FORMAT_CMP_EQUAL;
-}
-
-/*!
- * \brief Format attribute callback called during joint format capability
- * \note Our test will assume the max of attributes \c field_one and \c field_two
- */
-static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2)
-{
-	struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1);
-	struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2);
-	struct ast_format *joint;
-	struct test_core_format_pvt *joint_pvt;
-
-	joint = ast_format_clone(format1);
-	if (!joint) {
-		return NULL;
-	}
-	joint_pvt = ast_format_get_attribute_data(joint);
-
-	joint_pvt->field_one = MAX(pvt1 ? pvt1->field_one : 0, pvt2 ? pvt2->field_one : 0);
-	joint_pvt->field_two = MAX(pvt2 ? pvt2->field_two : 0, pvt2 ? pvt2->field_two : 0);
-
-	++test_callbacks_called.format_get_joint;
-
-	return joint;
-}
-
-/*! \brief Format attribute callback for setting an attribute on a format */
-static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value)
-{
-	struct ast_format *clone = ast_format_clone(format);
-	struct test_core_format_pvt *clone_pvt;
-
-	if (!clone) {
-		return NULL;
-	}
-	clone_pvt = ast_format_get_attribute_data(clone);
-
-	if (!strcmp(name, "one")) {
-		clone_pvt->field_one = atoi(value);
-	} else if (!strcmp(name, "two")) {
-		clone_pvt->field_two = atoi(value);
-	}
-	++test_callbacks_called.format_attribute_set;
-
-	return clone;
-}
-
-/*! \brief Format attribute callback to construct a format from an SDP fmtp line */
-static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
-{
-	struct ast_format *clone = ast_format_clone(format);
-	struct test_core_format_pvt *pvt;
-
-	if (!clone) {
-		return NULL;
-	}
-
-	pvt = ast_format_get_attribute_data(clone);
-
-	if (sscanf(attributes, "one=%d;two=%d", &pvt->field_one, &pvt->field_two) != 2) {
-		ao2_ref(clone, -1);
-		return NULL;
-	}
-
-	++test_callbacks_called.format_parse_sdp_fmtp;
-	return clone;
-}
-
-/*! \brief Format attribute callback to generate an SDP fmtp line from a format */
-static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
-{
-	struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format);
-
-	if (!pvt) {
-		return;
-	}
-
-	ast_str_append(str, 0, "a=fmtp:%u one=%d;two=%d\r\n", payload, pvt->field_one, pvt->field_two);
-
-	++test_callbacks_called.format_generate_sdp_fmtp;
-}
-
-AST_TEST_DEFINE(format_create)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format creation unit test";
-		info->description =
-			"Test creation of a format";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_ref(format, -1);
-	format = ast_format_create_named("super_ulaw", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_create_attr)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format creation w/ attributes unit test";
-		info->description =
-			"Test creation of a format with attributes";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format_w_attr = ast_format_attribute_set(format, "one", "1");
-	if (!format_w_attr) {
-		ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format_w_attr) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cmp(format, format_w_attr) == AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Format with attributes should not be equal to format without attributes\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_validate(test, test_callbacks_called.format_attribute_set == 1);
-	ast_test_validate(test, test_callbacks_called.format_cmp == 1);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_clone)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, clone, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format cloning unit test";
-		info->description =
-			"Test cloning of a format";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format_w_attr = ast_format_attribute_set(format, "one", "1");
-	if (!format_w_attr) {
-		ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(format_w_attr) != codec->id) {
-		ast_test_status_update(test, "Created format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* Test cloning a format without attributes */
-	clone = ast_format_clone(format);
-	if (!clone) {
-		ast_test_status_update(test, "Could not create cloned format\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(clone) != codec->id) {
-		ast_test_status_update(test, "Cloned format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	} else if (clone == format) {
-		ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cmp(clone, format) != AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Cloned format is not the same as its original format\n");
-		return AST_TEST_FAIL;
-	}
-	ao2_ref(clone, -1);
-
-	/* Test cloning a format with attributes */
-	clone = ast_format_clone(format_w_attr);
-	if (!clone) {
-		ast_test_status_update(test, "Could not create cloned format\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(clone) != codec->id) {
-		ast_test_status_update(test, "Cloned format does not contain provided codec\n");
-		return AST_TEST_FAIL;
-	} else if (clone == format_w_attr) {
-		ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cmp(clone, format_w_attr) != AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Cloned format is not the same as its original format\n");
-		return AST_TEST_FAIL;
-	}
-	ast_test_validate(test, test_callbacks_called.format_attribute_set == 1);
-	ast_test_validate(test, test_callbacks_called.format_clone == 3);
-	ast_test_validate(test, test_callbacks_called.format_cmp == 2);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cmp_same_codec)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, named, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format comparison unit test";
-		info->description =
-			"Test comparison of two different formats with same codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_create(codec);
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_create(codec);
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	named = ast_format_create_named("super_ulaw", codec);
-	if (!named) {
-		ast_test_status_update(test, "Could not create named format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Two formats that are the same compared as not being equal\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cmp(first, named) != AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Two formats that are the same compared as not being equal\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cmp_different_codec)
-{
-	RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format comparison unit test";
-		info->description =
-			"Test comparison of two different formats with different codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!first_codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_create(first_codec);
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!second_codec) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_create(second_codec);
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cmp(first, second) != AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_test_status_update(test, "Two formats that have different codecs did not compare as being not equal\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_attr_cmp_same_codec)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format with attributes comparison unit test";
-		info->description =
-			"Test comparison of two different formats with attributes with same codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	original = ast_format_create(codec);
-	if (!original) {
-		ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_attribute_set(original, "one", "1");
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format with attributes\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_attribute_set(original, "two", "1");
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format with attributes\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cmp(first, second) == AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Formats with different attributes were compared to be equal when they should not\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_ref(second, -1);
-	second = ast_format_attribute_set(original, "one", "1");
-
-	if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) {
-		ast_test_status_update(test, "Formats with the same attributes should be equal\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_validate(test, test_callbacks_called.format_attribute_set == 3);
-	ast_test_validate(test, test_callbacks_called.format_cmp == 2);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_joint_same_codec)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Joint format unit test";
-		info->description =
-			"Test joint format creation using two different formats with same codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_create(codec);
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_create(codec);
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	joint = ast_format_joint(first, second);
-	if (!joint) {
-		ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(joint) != codec->id) {
-		ast_test_status_update(test, "Returned joint format does not contain expected codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_attr_joint_same_codec)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
-	struct ast_str *fmtp = ast_str_alloca(64);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Joint format attribute unit test";
-		info->description =
-			"Test joint format creation using two different formats with attributes and with same codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	original = ast_format_create(codec);
-	if (!original) {
-		ast_test_status_update(test, "Could not create format from test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_attribute_set(original, "one", "2");
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_attribute_set(original, "one", "5");
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	joint = ast_format_joint(first, second);
-	if (!joint) {
-		ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_get_codec_id(joint) != codec->id) {
-		ast_test_status_update(test, "Returned joint format does not contain expected codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_generate_sdp_fmtp(joint, 100, &fmtp);
-	ast_test_validate(test, strcmp("a=fmtp:100 one=5;two=0\r\n", ast_str_buffer(fmtp)) == 0);
-
-	ast_test_validate(test, test_callbacks_called.format_attribute_set == 2);
-	ast_test_validate(test, test_callbacks_called.format_get_joint == 1);
-	ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_joint_different_codec)
-{
-	RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Joint format unit test";
-		info->description =
-			"Test that there is no joint format between two different formats with different codec";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!first_codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	first = ast_format_create(first_codec);
-	if (!first) {
-		ast_test_status_update(test, "Could not create first format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!second_codec) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	second = ast_format_create(second_codec);
-	if (!second) {
-		ast_test_status_update(test, "Could not create second format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	joint = ast_format_joint(first, second);
-	if (joint) {
-		ast_test_status_update(test, "Got a joint format between two formats with different codecs\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_copy)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, copy, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format copying unit test";
-		info->description =
-			"Test copying of a format";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	copy = ao2_bump(format);
-	if (!copy) {
-		ast_test_status_update(test, "Copying of a just created format failed\n");
-		return AST_TEST_FAIL;
-	} else if (copy != format) {
-		ast_test_status_update(test, "Copying of a format returned a new format instead of the same one\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_attribute_set_without_interface)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format attribute setting unit test";
-		info->description =
-			"Test that attribute setting on a format without an interface fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_format_attribute_set(format, "bees", "cool")) {
-		ast_test_status_update(test, "Successfully set an attribute on a format without an interface\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_parse_sdp_fmtp_without_interface)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format sdp parse unit test";
-		info->description =
-			"Test that sdp parsing on a format without an interface fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	generated = ast_format_parse_sdp_fmtp(format, "tacos");
-	if (generated != format) {
-		ast_test_status_update(test, "Successfully parsed SDP on a format without an interface\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_parse_and_generate_sdp_fmtp)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup);
-	struct ast_str *fmtp = ast_str_alloca(64);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Format sdp parse/generate unit test";
-		info->description =
-			"Test that sdp parsing and generation on a format with an interface succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	generated = ast_format_parse_sdp_fmtp(format, "one=1000;two=256");
-	if (format == generated) {
-		ast_test_status_update(test, "Failed to parse SDP on a format without an interface\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_generate_sdp_fmtp(generated, 8, &fmtp);
-
-	ast_test_validate(test, strcmp("a=fmtp:8 one=1000;two=256\r\n", ast_str_buffer(fmtp)) == 0);
-	ast_test_validate(test, test_callbacks_called.format_parse_sdp_fmtp == 1);
-	ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1);
-
-	return AST_TEST_PASS;
-}
-
-static int test_core_format_init(struct ast_test_info *info, struct ast_test *test)
-{
-	memset(&test_callbacks_called, 0, sizeof(test_callbacks_called));
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(format_create);
-	AST_TEST_UNREGISTER(format_create_attr);
-	AST_TEST_UNREGISTER(format_clone);
-	AST_TEST_UNREGISTER(format_cmp_same_codec);
-	AST_TEST_UNREGISTER(format_attr_cmp_same_codec);
-	AST_TEST_UNREGISTER(format_cmp_different_codec);
-	AST_TEST_UNREGISTER(format_joint_same_codec);
-	AST_TEST_UNREGISTER(format_attr_joint_same_codec);
-	AST_TEST_UNREGISTER(format_joint_different_codec);
-	AST_TEST_UNREGISTER(format_copy);
-	AST_TEST_UNREGISTER(format_attribute_set_without_interface);
-	AST_TEST_UNREGISTER(format_parse_sdp_fmtp_without_interface);
-	AST_TEST_UNREGISTER(format_parse_and_generate_sdp_fmtp);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	/* Test codec/format interface used by this module */
-	if (ast_codec_register(&test_core_format_codec)) {
-		ast_log(AST_LOG_ERROR, "Failed to register test_core_format_codec\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	if (ast_format_interface_register("test_core_format_codec", &test_core_format_attr)) {
-		ast_log(AST_LOG_ERROR, "Failed to register format interface for test_core_format_codec\n");
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	AST_TEST_REGISTER(format_create);
-	AST_TEST_REGISTER(format_create_attr);
-	AST_TEST_REGISTER(format_clone);
-	AST_TEST_REGISTER(format_cmp_same_codec);
-	AST_TEST_REGISTER(format_attr_cmp_same_codec);
-	AST_TEST_REGISTER(format_cmp_different_codec);
-	AST_TEST_REGISTER(format_joint_same_codec);
-	AST_TEST_REGISTER(format_attr_joint_same_codec);
-	AST_TEST_REGISTER(format_joint_different_codec);
-	AST_TEST_REGISTER(format_copy);
-	AST_TEST_REGISTER(format_attribute_set_without_interface);
-	AST_TEST_REGISTER(format_parse_sdp_fmtp_without_interface);
-	AST_TEST_REGISTER(format_parse_and_generate_sdp_fmtp);
-
-	ast_test_register_init(TEST_CATEGORY, &test_core_format_init);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core format API test module");
diff --git a/tests/test_devicestate.c b/tests/test_devicestate.c
index 85255ec..a89144c 100644
--- a/tests/test_devicestate.c
+++ b/tests/test_devicestate.c
@@ -32,16 +32,29 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410185 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/test.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/pbx.h"
-#include "asterisk/stasis_message_router.h"
+#include "asterisk/event.h"
+#include "asterisk/vector.h"
 
-#define UNIT_TEST_DEVICE_IDENTIFIER "unit_test_device_identifier"
+#define DEVICE_STATE_CHANNEL_TYPE "TestDeviceState"
+
+#define DEVSTATE_PROVIDER "TestDevState"
+
+#define DEVSTATE_PROVIDER_LC "testdevstate"
+
+#define DEVSTATE_PROVIDER_LEN 12
+
+/*! \brief Subscription to device state change events */
+static struct ast_event_sub *device_state_sub;
+
+/*! \brief Used to assign an increasing integer to channel name */
+static unsigned int chan_idx;
 
 /* These arrays are the result of the 'core show device2extenstate' output. */
 static int combined_results[] = {
@@ -212,6 +225,82 @@ static int exten_results[] = {
 	AST_EXTENSION_ONHOLD,
 };
 
+/*! \brief Mutex for \c update_cond */
+AST_MUTEX_DEFINE_STATIC(update_lock);
+
+/*! \brief Condition wait variable for device state updates */
+static ast_cond_t update_cond;
+
+/*! \brief Mutext for \c channel_cb_cond */
+AST_MUTEX_DEFINE_STATIC(channel_cb_lock);
+
+/*! \brief Condition wait variable for channel tech device state cb */
+static ast_cond_t channel_cb_cond;
+
+/*! \brief The resulting device state updates caused by some function call */
+static AST_VECTOR(, enum ast_device_state) result_states;
+
+/*! \brief The current device state for our device state provider */
+static enum ast_device_state current_device_state;
+
+/*! \brief Clear out all recorded device states in \ref result_states */
+static void clear_result_states(void)
+{
+	ast_mutex_lock(&update_lock);
+	while (AST_VECTOR_SIZE(&result_states) > 0) {
+		AST_VECTOR_REMOVE_UNORDERED(&result_states, 0);
+	}
+	ast_mutex_unlock(&update_lock);
+}
+
+static void device_state_cb(const struct ast_event *event, void *userdata)
+{
+	enum ast_device_state state;
+	const char *device;
+
+	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+
+	if (ast_strlen_zero(device)) {
+		return;
+	}
+
+	if (strncasecmp(device, DEVSTATE_PROVIDER, DEVSTATE_PROVIDER_LEN)) {
+		/* Not our device state change */
+		return;
+	}
+
+	ast_mutex_lock(&update_lock);
+	AST_VECTOR_APPEND(&result_states, state);
+	ast_cond_signal(&update_cond);
+	ast_mutex_unlock(&update_lock);
+}
+
+static enum ast_device_state devstate_prov_cb(const char *data)
+{
+	return current_device_state;
+}
+
+static int wait_for_device_state_updates(struct ast_test *test, int expected_updates)
+{
+	int error;
+	struct timeval wait_now = ast_tvnow();
+	struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
+
+	ast_mutex_lock(&update_lock);
+	while (AST_VECTOR_SIZE(&result_states) != expected_updates) {
+		error = ast_cond_timedwait(&update_cond, &update_lock, &wait_time);
+		if (error == ETIMEDOUT) {
+			ast_test_status_update(test, "Test timed out while waiting for %d expected updates\n", expected_updates);
+			break;
+		}
+	}
+	ast_mutex_unlock(&update_lock);
+
+	ast_test_status_update(test, "Received %zu of %d updates\n", AST_VECTOR_SIZE(&result_states), expected_updates);
+	return !(AST_VECTOR_SIZE(&result_states) == expected_updates);
+}
+
 AST_TEST_DEFINE(device2extenstate_test)
 {
 	int res = AST_TEST_PASS;
@@ -276,263 +365,348 @@ AST_TEST_DEFINE(device2extenstate_test)
 	return res;
 }
 
-struct consumer {
-	ast_cond_t out;
-	int already_out;
-	int sig_on_non_aggregate_state;
-	int event_count;
-	enum ast_device_state state;
-	enum ast_device_state aggregate_state;
-};
-
-static void consumer_dtor(void *obj)
+AST_TEST_DEFINE(devstate_prov_add)
 {
-	struct consumer *consumer = obj;
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = __func__;
+		info->category = "/main/devicestate/";
+		info->summary = "Test adding a device state provider";
+		info->description =
+			"Test that a custom device state provider can be added, and that\n"
+			"it cannot be added if already added.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
 
-	ast_cond_destroy(&consumer->out);
-}
+	ast_test_validate(test, ast_devstate_prov_add(DEVSTATE_PROVIDER, devstate_prov_cb) == 0);
+	ast_test_validate(test, ast_devstate_prov_add(DEVSTATE_PROVIDER, devstate_prov_cb) != 0);
+	ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
 
-static void consumer_reset(struct consumer *consumer)
-{
-	consumer->already_out = 0;
-	consumer->event_count = 0;
-	consumer->state = AST_DEVICE_TOTAL;
-	consumer->aggregate_state = AST_DEVICE_TOTAL;
+	return AST_TEST_PASS;
 }
 
-static struct consumer *consumer_create(void)
+AST_TEST_DEFINE(devstate_prov_del)
 {
-	struct consumer *consumer;
-
-	consumer = ao2_alloc(sizeof(*consumer), consumer_dtor);
-	if (!consumer) {
-		return NULL;
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = __func__;
+		info->category = "/main/devicestate/";
+		info->summary = "Test removing a device state provider";
+		info->description =
+			"Test that a custom device state provider can be removed, and that\n"
+			"it cannot be removed if already removed.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
 	}
 
-	ast_cond_init(&consumer->out, NULL);
-	consumer_reset(consumer);
+	ast_test_validate(test, ast_devstate_prov_add(DEVSTATE_PROVIDER, devstate_prov_cb) == 0);
+	ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
+	ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) != 0);
 
-	return consumer;
+	return AST_TEST_PASS;
 }
 
-static void consumer_exec(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+AST_TEST_DEFINE(devstate_changed)
 {
-	struct consumer *consumer = data;
-	struct stasis_cache_update *cache_update = stasis_message_data(message);
-	struct ast_device_state_message *device_state;
+	int i;
+	enum ast_device_state expected_results[] = {
+		AST_DEVICE_NOT_INUSE,
+		AST_DEVICE_INUSE,
+		AST_DEVICE_BUSY,
+		AST_DEVICE_INVALID,
+		AST_DEVICE_UNAVAILABLE,
+		AST_DEVICE_RINGING,
+		AST_DEVICE_RINGINUSE,
+		AST_DEVICE_ONHOLD,
+	};
 
-	if (!cache_update->new_snapshot) {
-		return;
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = __func__;
+		info->category = "/main/devicestate/";
+		info->summary = "Test updates coming from a device state provider";
+		info->description =
+			"This unit test checks that a custom device state provider can\n"
+			"have updates published for it. This includes both cacheable and\n"
+			"non-cacheable events. In the case of non-cacheable events, the\n"
+			"device state provider's callback function is queried for the\n"
+			"device state when AST_DEVICE_UNKNOWN is published.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
 	}
 
-	device_state = stasis_message_data(cache_update->new_snapshot);
-
-	if (strcmp(device_state->device, UNIT_TEST_DEVICE_IDENTIFIER)) {
-		/* not a device state we're interested in */
-		return;
+	clear_result_states();
+	current_device_state = AST_DEVICE_BUSY;
+
+	ast_test_validate(test, ast_devstate_prov_add(DEVSTATE_PROVIDER, devstate_prov_cb) == 0);
+
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_INUSE, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_BUSY, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_INVALID, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_RINGING, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_RINGINUSE, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_ONHOLD, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+
+	ast_test_validate(test, wait_for_device_state_updates(test, 8) == 0);
+	for (i = 0; i < AST_VECTOR_SIZE(&result_states); i++) {
+		ast_test_status_update(test, "Testing update %d: actual is %d; expected is %d\n",
+			i,
+			AST_VECTOR_GET(&result_states, i),
+			expected_results[i]);
+		ast_test_validate(test, AST_VECTOR_GET(&result_states, i) == expected_results[i]);
 	}
 
-	{
-		SCOPED_AO2LOCK(lock, consumer);
-
-		++consumer->event_count;
-		if (device_state->eid) {
-			consumer->state = device_state->state;
-			if (consumer->sig_on_non_aggregate_state) {
-				consumer->sig_on_non_aggregate_state = 0;
-				consumer->already_out = 1;
-				ast_cond_signal(&consumer->out);
-			}
-		} else {
-			consumer->aggregate_state = device_state->state;
-			consumer->already_out = 1;
-			ast_cond_signal(&consumer->out);
-		}
+	clear_result_states();
+
+	/*
+	 * Since an update of AST_DEVICE_UNKNOWN will cause a different thread to retrieve
+	 * the update from the custom device state provider, check it separately from the
+	 * updates above.
+	 */
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, wait_for_device_state_updates(test, 1) == 0);
+	ast_test_validate(test, AST_VECTOR_GET(&result_states, 0) == AST_DEVICE_BUSY);
+	ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER ":foo") == AST_DEVICE_BUSY);
+	ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER_LC ":foo") == AST_DEVICE_BUSY);
+
+	clear_result_states();
+
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_INVALID, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_RINGINUSE, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+	ast_test_validate(test, ast_devstate_changed_literal(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo") == 0);
+
+	ast_test_validate(test, wait_for_device_state_updates(test, 8) == 0);
+	for (i = 0; i < AST_VECTOR_SIZE(&result_states); i++) {
+		ast_test_status_update(test, "Testing update %d: actual is %d; expected is %d\n",
+			i,
+			AST_VECTOR_GET(&result_states, i),
+			expected_results[i]);
+		ast_test_validate(test, AST_VECTOR_GET(&result_states, i) == expected_results[i]);
 	}
-}
 
-static void consumer_finalize(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct consumer *consumer = data;
+	/*
+	 * Check the last value in the cache. Note that this should not hit
+	 * the value of current_device_state.
+	 */
+	ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER ":foo") == AST_DEVICE_ONHOLD);
+	/*
+	 * This will miss on the cache, as it is case sensitive. It should go
+	 * hit our device state callback however.
+	 */
+	ast_test_validate(test, ast_device_state(DEVSTATE_PROVIDER_LC ":foo") == AST_DEVICE_BUSY);
+
+	/* Generally, this test can't be run twice in a row, as you can't remove an
+	 * item from the cache. Hence, subsequent runs won't hit the device state provider,
+	 * and will merely return the cached value.
+	 *
+	 * To avoid annoying errors, set the last state to BUSY here.
+	 */
+	ast_devstate_changed_literal(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, DEVSTATE_PROVIDER ":foo");
+
+	ast_test_validate(test, ast_devstate_prov_del(DEVSTATE_PROVIDER) == 0);
 
-	if (stasis_subscription_final_message(sub, message)) {
-		ao2_cleanup(consumer);
-	}
+	return AST_TEST_PASS;
 }
 
-static void consumer_wait_for(struct consumer *consumer)
+AST_TEST_DEFINE(devstate_conversions)
 {
-	int res;
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 10,
-		.tv_nsec = start.tv_usec * 1000
-	};
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = __func__;
+		info->category = "/main/devicestate/";
+		info->summary = "Test ast_device_state conversions";
+		info->description =
+			"Test various transformations of ast_device_state values.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
 
-	SCOPED_AO2LOCK(lock, consumer);
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_UNKNOWN), "UNKNOWN"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_NOT_INUSE), "NOT_INUSE"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_INUSE), "INUSE"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_BUSY), "BUSY"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_INVALID), "INVALID"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_UNAVAILABLE), "UNAVAILABLE"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_RINGING), "RINGING"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_RINGINUSE), "RINGINUSE"));
+	ast_test_validate(test, !strcmp(ast_devstate_str(AST_DEVICE_ONHOLD), "ONHOLD"));
+
+	ast_test_validate(test, ast_devstate_val("UNKNOWN") == AST_DEVICE_UNKNOWN);
+	ast_test_validate(test, ast_devstate_val("NOT_INUSE") == AST_DEVICE_NOT_INUSE);
+	ast_test_validate(test, ast_devstate_val("INUSE") == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_devstate_val("BUSY") == AST_DEVICE_BUSY);
+	ast_test_validate(test, ast_devstate_val("INVALID") == AST_DEVICE_INVALID);
+	ast_test_validate(test, ast_devstate_val("UNAVAILABLE") == AST_DEVICE_UNAVAILABLE);
+	ast_test_validate(test, ast_devstate_val("RINGING") == AST_DEVICE_RINGING);
+	ast_test_validate(test, ast_devstate_val("RINGINUSE") == AST_DEVICE_RINGINUSE);
+	ast_test_validate(test, ast_devstate_val("ONHOLD") == AST_DEVICE_ONHOLD);
+	ast_test_validate(test, ast_devstate_val("onhold") == AST_DEVICE_ONHOLD);
+	ast_test_validate(test, ast_devstate_val("FOO") == AST_DEVICE_UNKNOWN);
+
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_DOWN) == AST_DEVICE_NOT_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_RESERVED) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_OFFHOOK) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_DIALING) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_RING) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_RINGING) == AST_DEVICE_RINGING);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_UP) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_BUSY) == AST_DEVICE_BUSY);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_DIALING_OFFHOOK) == AST_DEVICE_INUSE);
+	ast_test_validate(test, ast_state_chan2dev(AST_STATE_PRERING) == AST_DEVICE_RINGING);
 
-	while (!consumer->already_out) {
-		res = ast_cond_timedwait(&consumer->out, ao2_object_get_lockaddr(consumer), &end);
-		if (!res || res == ETIMEDOUT) {
-			break;
-		}
-	}
+	return AST_TEST_PASS;
 }
 
-static int remove_device_states_cb(void *obj, void *arg, int flags)
-{
-	struct stasis_message *msg = obj;
-	struct ast_device_state_message *device_state = stasis_message_data(msg);
+/*! \brief Whether or not the channel device state callback was called */
+static int chan_callback_called;
 
-	if (strcmp(UNIT_TEST_DEVICE_IDENTIFIER, device_state->device)) {
-		/* Not a unit test device */
-		return 0;
+/*! \brief Wait until the test channel driver's devicestate callback is called */
+static int wait_for_channel_callback(struct ast_test *test)
+{
+	int error;
+	struct timeval wait_now = ast_tvnow();
+	struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
+
+	ast_mutex_lock(&channel_cb_lock);
+	while (!chan_callback_called) {
+		error = ast_cond_timedwait(&channel_cb_cond, &channel_cb_lock, &wait_time);
+		if (error == ETIMEDOUT) {
+			ast_test_status_update(test, "Test timed out while waiting channel callback\n");
+			break;
+		}
 	}
+	ast_mutex_unlock(&channel_cb_lock);
 
-	msg = stasis_cache_clear_create(msg);
-	if (msg) {
-		/* topic guaranteed to have been created by this point */
-		stasis_publish(ast_device_state_topic(device_state->device), msg);
-	}
-	ao2_cleanup(msg);
-	return 0;
+	return chan_callback_called;
 }
 
-static void cache_cleanup(int unused)
+static void safe_hangup(void *object)
 {
-	struct ao2_container *cache_dump;
+	struct ast_channel *chan = object;
 
-	/* remove all device states created during this test */
-	cache_dump = stasis_cache_dump_all(ast_device_state_cache(), NULL);
-	if (!cache_dump) {
+	if (!chan) {
 		return;
 	}
-	ao2_callback(cache_dump, 0, remove_device_states_cb, NULL);
-	ao2_cleanup(cache_dump);
+	ast_hangup(chan);
 }
 
-AST_TEST_DEFINE(device_state_aggregation_test)
+AST_TEST_DEFINE(devstate_channels)
 {
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, device_msg_router, NULL, stasis_message_router_unsubscribe);
-	RAII_VAR(struct ast_eid *, foreign_eid, NULL, ast_free);
-	RAII_VAR(int, cleanup_cache, 0, cache_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	int res;
-	struct ast_device_state_message *device_state;
+	RAII_VAR(struct ast_channel *, chan, NULL, safe_hangup);
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "device_state_aggregation_test";
+		info->name = __func__;
 		info->category = "/main/devicestate/";
-		info->summary = "Tests message routing and aggregation through the Stasis device state system.";
+		info->summary = "Test deriving device state from a channel's state";
 		info->description =
-			"Verifies that the device state system passes "
-			"messages appropriately, that the aggregator is "
-			"working properly, that the aggregate results match "
-			"the expected combined devstate, and that the cached "
-			"aggregate devstate is correct.";
+			"Test querying a channel's state to derive a device state.";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
 
-	foreign_eid = ast_malloc(sizeof(*foreign_eid));
-	ast_test_validate(test, NULL != foreign_eid);
-	memset(foreign_eid, 0xFF, sizeof(*foreign_eid));
-
-	consumer = consumer_create();
-	ast_test_validate(test, NULL != consumer);
-
-	device_msg_router = stasis_message_router_create(ast_device_state_topic_cached());
-	ast_test_validate(test, NULL != device_msg_router);
-
-	ao2_ref(consumer, +1);
-	res = stasis_message_router_add(device_msg_router, stasis_cache_update_type(), consumer_exec, consumer);
-	ast_test_validate(test, !res);
-
-	res = stasis_message_router_add(device_msg_router, stasis_subscription_change_type(), consumer_finalize, consumer);
-	ast_test_validate(test, !res);
-
-	/* push local state */
-	ast_publish_device_state(UNIT_TEST_DEVICE_IDENTIFIER, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE);
-
-	/* Check cache aggregate state immediately */
-	ao2_cleanup(msg);
-	msg = stasis_cache_get_by_eid(ast_device_state_cache(), ast_device_state_message_type(), UNIT_TEST_DEVICE_IDENTIFIER, NULL);
-	device_state = stasis_message_data(msg);
-	ast_test_validate(test, AST_DEVICE_NOT_INUSE == device_state->state);
-
-	consumer_wait_for(consumer);
-	ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->state);
-	ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->aggregate_state);
-	ast_test_validate(test, 2 == consumer->event_count);
-	consumer_reset(consumer);
-
-	/* push remote state */
-	/* this will not produce a new aggregate state message since the aggregate state does not change */
-	consumer->sig_on_non_aggregate_state = 1;
-	ast_publish_device_state_full(UNIT_TEST_DEVICE_IDENTIFIER, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, foreign_eid);
-
-	/* Check cache aggregate state immediately */
-	ao2_cleanup(msg);
-	msg = stasis_cache_get_by_eid(ast_device_state_cache(), ast_device_state_message_type(), UNIT_TEST_DEVICE_IDENTIFIER, NULL);
-	device_state = stasis_message_data(msg);
-	ast_test_validate(test, AST_DEVICE_NOT_INUSE == device_state->state);
-
-	/* Check for expected events. */
-	consumer_wait_for(consumer);
-	ast_test_validate(test, AST_DEVICE_NOT_INUSE == consumer->state);
-	ast_test_validate(test, AST_DEVICE_TOTAL == consumer->aggregate_state);
-	ast_test_validate(test, 1 == consumer->event_count);
-	consumer_reset(consumer);
-
-	/* push remote state different from local state */
-	ast_publish_device_state_full(UNIT_TEST_DEVICE_IDENTIFIER, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, foreign_eid);
-
-	/* Check cache aggregate state immediately */
-	ao2_cleanup(msg);
-	msg = stasis_cache_get_by_eid(ast_device_state_cache(), ast_device_state_message_type(), UNIT_TEST_DEVICE_IDENTIFIER, NULL);
-	device_state = stasis_message_data(msg);
-	ast_test_validate(test, AST_DEVICE_INUSE == device_state->state);
-
-	/* Check for expected events. */
-	consumer_wait_for(consumer);
-	ast_test_validate(test, AST_DEVICE_INUSE == consumer->state);
-	ast_test_validate(test, AST_DEVICE_INUSE == consumer->aggregate_state);
-	ast_test_validate(test, 2 == consumer->event_count);
-	consumer_reset(consumer);
-
-	/* push local state that will cause aggregated state different from local non-aggregate state */
-	ast_publish_device_state(UNIT_TEST_DEVICE_IDENTIFIER, AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE);
-
-	/* Check cache aggregate state immediately */
-	ao2_cleanup(msg);
-	msg = stasis_cache_get_by_eid(ast_device_state_cache(), ast_device_state_message_type(), UNIT_TEST_DEVICE_IDENTIFIER, NULL);
-	device_state = stasis_message_data(msg);
-	ast_test_validate(test, AST_DEVICE_RINGINUSE == device_state->state);
-
-	/* Check for expected events. */
-	consumer_wait_for(consumer);
-	ast_test_validate(test, AST_DEVICE_RINGING == consumer->state);
-	ast_test_validate(test, AST_DEVICE_RINGINUSE == consumer->aggregate_state);
-	ast_test_validate(test, 2 == consumer->event_count);
-	consumer_reset(consumer);
+	chan_callback_called = 0;
+
+	chan = ast_channel_alloc(0, AST_STATE_RINGING, "", "", "", "s", "default",
+		NULL, 0, DEVICE_STATE_CHANNEL_TYPE "/foo-%08x",
+		(unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1));
+	ast_test_validate(test, chan != NULL);
+
+	ast_test_validate(test, ast_parse_device_state(DEVICE_STATE_CHANNEL_TYPE "/foo") == AST_DEVICE_RINGING);
+	ast_test_validate(test, ast_parse_device_state(DEVICE_STATE_CHANNEL_TYPE "/bad") == AST_DEVICE_UNKNOWN);
+
+	ast_setstate(chan, AST_STATE_UP);
+
+	ast_test_validate(test, wait_for_channel_callback(test) == 1);
+	ast_test_validate(test, ast_parse_device_state(DEVICE_STATE_CHANNEL_TYPE "/foo") == AST_DEVICE_INUSE);
+
+	chan_callback_called = 0;
 
 	return AST_TEST_PASS;
 }
 
+static int chan_test_devicestate_cb(const char *device_number)
+{
+	/* Simply record that we were called when expected */
+	chan_callback_called = 1;
+
+	ast_mutex_lock(&channel_cb_lock);
+	ast_cond_signal(&channel_cb_cond);
+	ast_mutex_unlock(&channel_cb_lock);
+
+	return AST_DEVICE_INUSE;
+}
+
+struct ast_channel_tech chan_test_devicestate = {
+	.type = DEVICE_STATE_CHANNEL_TYPE,
+	.description = "Device State Unit Test Channel Driver",
+	.devicestate = chan_test_devicestate_cb,
+};
+
 static int unload_module(void)
 {
+	if (device_state_sub) {
+		ast_event_unsubscribe(device_state_sub);
+	}
+	AST_VECTOR_FREE(&result_states);
+	ast_channel_unregister(&chan_test_devicestate);
+
 	AST_TEST_UNREGISTER(device2extenstate_test);
-	AST_TEST_UNREGISTER(device_state_aggregation_test);
+
+	AST_TEST_UNREGISTER(devstate_prov_add);
+	AST_TEST_UNREGISTER(devstate_prov_del);
+
+	AST_TEST_UNREGISTER(devstate_changed);
+	AST_TEST_UNREGISTER(devstate_conversions);
+
+	AST_TEST_UNREGISTER(devstate_channels);
+
 	return 0;
 }
 
 static int load_module(void)
 {
-	AST_TEST_REGISTER(device_state_aggregation_test);
+
+	device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb,
+		"Device State Unit Tests", NULL, AST_EVENT_IE_END);
+	if (!device_state_sub) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	if (AST_VECTOR_INIT(&result_states, 8) == -1) {
+		ast_event_unsubscribe(device_state_sub);
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	if (ast_channel_register(&chan_test_devicestate)) {
+		ast_event_unsubscribe(device_state_sub);
+		AST_VECTOR_FREE(&result_states);
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	AST_TEST_REGISTER(device2extenstate_test);
+
+	AST_TEST_REGISTER(devstate_prov_add);
+	AST_TEST_REGISTER(devstate_prov_del);
+
+	AST_TEST_REGISTER(devstate_changed);
+	AST_TEST_REGISTER(devstate_conversions);
+
+	AST_TEST_REGISTER(devstate_channels);
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/tests/test_dlinklists.c b/tests/test_dlinklists.c
index d351404..197dd75 100644
--- a/tests/test_dlinklists.c
+++ b/tests/test_dlinklists.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 401663 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/tests/test_endpoints.c b/tests/test_endpoints.c
deleted file mode 100644
index 120fc4e..0000000
--- a/tests/test_endpoints.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test endpoints.
- *
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 392779 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/test.h"
-
-static const char *test_category = "/core/endpoints/";
-
-AST_TEST_DEFINE(create)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test endpoint creation";
-		info->description = "Test endpoint creation";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, NULL == ast_endpoint_create(NULL, NULL));
-	ast_test_validate(test, NULL == ast_endpoint_create("", ""));
-	ast_test_validate(test, NULL == ast_endpoint_create("TEST", ""));
-	ast_test_validate(test, NULL == ast_endpoint_create("", "test_res"));
-
-	uut = ast_endpoint_create("TEST", "test_res");
-	ast_test_validate(test, NULL != uut);
-
-	ast_test_validate(test,
-		0 == strcmp("TEST", ast_endpoint_get_tech(uut)));
-	ast_test_validate(test,
-		0 == strcmp("test_res", ast_endpoint_get_resource(uut)));
-
-	return AST_TEST_PASS;
-}
-
-
-AST_TEST_DEFINE(defaults)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test defaults for new endpoints";
-		info->description = "Test defaults for new endpoints";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_endpoint_create("TEST", "test_res");
-	ast_test_validate(test, NULL != uut);
-	snapshot = ast_endpoint_snapshot_create(uut);
-	ast_test_validate(test, NULL != snapshot);
-
-	ast_test_validate(test, 0 == strcmp("TEST/test_res", snapshot->id));
-	ast_test_validate(test, 0 == strcmp("TEST", snapshot->tech));
-	ast_test_validate(test, 0 == strcmp("test_res", snapshot->resource));
-	ast_test_validate(test, AST_ENDPOINT_UNKNOWN == snapshot->state);
-	ast_test_validate(test, -1 == snapshot->max_channels);
-	ast_test_validate(test, 0 == snapshot->num_channels);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(setters)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-	RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test endpoint setters";
-		info->description = "Test endpoint setters";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_endpoint_create("TEST", "test_res");
-	ast_test_validate(test, NULL != uut);
-
-	ast_endpoint_set_state(uut, AST_ENDPOINT_ONLINE);
-	ast_endpoint_set_max_channels(uut, 314159);
-
-	snapshot = ast_endpoint_snapshot_create(uut);
-	ast_test_validate(test, NULL != snapshot);
-
-	ast_test_validate(test, AST_ENDPOINT_ONLINE == snapshot->state);
-	ast_test_validate(test, 314159 == snapshot->max_channels);
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(create);
-	AST_TEST_UNREGISTER(defaults);
-	AST_TEST_UNREGISTER(setters);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(create);
-	AST_TEST_REGISTER(defaults);
-	AST_TEST_REGISTER(setters);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint testing",
-	.load = load_module,
-	.unload = unload_module,
-	);
diff --git a/tests/test_event.c b/tests/test_event.c
index 6060923..5fb9cde 100644
--- a/tests/test_event.c
+++ b/tests/test_event.c
@@ -25,13 +25,21 @@
  * \ingroup tests
  *
  * \todo API Calls not yet touched by a test: XXX TODO
+ *   - ast_event_queue_and_cache()
+ *   - ast_event_get_cached()
+ *   - ast_event_report_subs()
+ *   - ast_event_dump_cache()
  *   - ast_event_get_ie_type_name()
  *   - ast_event_get_ie_pltype()
+ *   - ast_event_str_to_event_type()
+ *   - ast_event_str_to_ie_type()
  *   - ast_event_iterator_init()
  *   - ast_event_iterator_next()
  *   - ast_event_iterator_get_ie_type()
  *   - ast_event_iterator_get_ie_uint()
+ *   - ast_event_iterator_get_ie_bitflags()
  *   - ast_event_iterator_get_ie_str()
+ *   - ast_event_iterator_get_ie_raw()
  */
 
 /*** MODULEINFO
@@ -41,7 +49,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
@@ -50,7 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 
 static int check_event(struct ast_event *event, struct ast_test *test,
 		enum ast_event_type expected_type, const char *type_name,
-		const char *str, uint32_t uint)
+		const char *str, uint32_t uint, uint32_t bitflags)
 {
 	enum ast_event_type type;
 	const void *foo;
@@ -63,27 +71,46 @@ static int check_event(struct ast_event *event, struct ast_test *test,
 		return -1;
 	}
 
+	/* Check #2: Check string representation of event type */
+	if (strcmp(type_name, ast_event_get_type_name(event))) {
+		ast_test_status_update(test, "Didn't get expected type name: '%s' != '%s'\n",
+				type_name, ast_event_get_type_name(event));
+		return -1;
+	}
+
+	/* Check #3: Check for automatically included EID */
+	if (memcmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID), sizeof(ast_eid_default))) {
+		ast_test_status_update(test, "Failed to get EID\n");
+		return -1;
+	}
+
 	/* Check #4: Check for the string IE */
-	if (strcmp(str, ast_event_get_ie_str(event, AST_EVENT_IE_CEL_USEREVENT_NAME))) {
+	if (strcmp(str, ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX))) {
 		ast_test_status_update(test, "Failed to get string IE.\n");
 		return -1;
 	}
 
 	/* Check #5: Check for the uint IE */
-	if (uint != ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_AMAFLAGS)) {
+	if (uint != ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS)) {
 		ast_test_status_update(test, "Failed to get uint IE.\n");
 		return -1;
 	}
 
-	/* Check #6: Check if a check for a str IE that isn't there works */
-	if ((foo = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDNAME))) {
-		ast_test_status_update(test, "CEL_CIDNAME IE check returned non-NULL %p\n", foo);
+	/* Check #6: Check for the bitflags IE */
+	if (bitflags != ast_event_get_ie_bitflags(event, AST_EVENT_IE_OLDMSGS)) {
+		ast_test_status_update(test, "Failed to get bitflags IE.\n");
 		return -1;
 	}
 
-	/* Check #7: Check if a check for a uint IE that isn't there returns 0 */
-	if (ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TIME_USEC)) {
-		ast_test_status_update(test, "UNIQUEID IE should be 0\n");
+	/* Check #7: Check if a check for a str IE that isn't there works */
+	if ((foo = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE))) {
+		ast_test_status_update(test, "DEVICE IE check returned non-NULL %p\n", foo);
+		return -1;
+	}
+
+	/* Check #8: Check if a check for a uint IE that isn't there returns 0 */
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_STATE)) {
+		ast_test_status_update(test, "OLDMSGS IE should be 0\n");
 		return -1;
 	}
 
@@ -103,6 +130,7 @@ AST_TEST_DEFINE(event_new_test)
 	static const enum ast_event_type type = AST_EVENT_CUSTOM;
 	static const char str[] = "SIP/alligatormittens";
 	static const uint32_t uint = 0xb00bface;
+	static const uint32_t bitflags = 0x12488421;
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -132,27 +160,34 @@ AST_TEST_DEFINE(event_new_test)
 		goto return_cleanup;
 	}
 
-	if (ast_event_append_ie_str(&event, AST_EVENT_IE_CEL_USEREVENT_NAME, str)) {
+	if (ast_event_append_ie_str(&event, AST_EVENT_IE_MAILBOX, str)) {
 		ast_test_status_update(test, "Failed to append str IE\n");
 		res = AST_TEST_FAIL;
 		goto return_cleanup;
 	}
 
-	if (ast_event_append_ie_uint(&event, AST_EVENT_IE_CEL_AMAFLAGS, uint)) {
+	if (ast_event_append_ie_uint(&event, AST_EVENT_IE_NEWMSGS, uint)) {
 		ast_test_status_update(test, "Failed to append uint IE\n");
 		res = AST_TEST_FAIL;
 		goto return_cleanup;
 	}
 
-	if (check_event(event, test, type, "Custom", str, uint)) {
+	if (ast_event_append_ie_bitflags(&event, AST_EVENT_IE_OLDMSGS, bitflags)) {
+		ast_test_status_update(test, "Failed to append bitflags IE\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (check_event(event, test, type, "Custom", str, uint, bitflags)) {
 		ast_test_status_update(test, "Dynamically generated event broken\n");
 		res = AST_TEST_FAIL;
 		goto return_cleanup;
 	}
 
 	event2 = ast_event_new(type,
-			AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, str,
-			AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, uint,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, str,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, uint,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, bitflags,
 			AST_EVENT_IE_END);
 
 	if (!event2) {
@@ -161,7 +196,7 @@ AST_TEST_DEFINE(event_new_test)
 		goto return_cleanup;
 	}
 
-	if (check_event(event2, test, type, "Custom", str, uint)) {
+	if (check_event(event2, test, type, "Custom", str, uint, bitflags)) {
 		ast_test_status_update(test, "Statically generated event broken\n");
 		res = AST_TEST_FAIL;
 		goto return_cleanup;
@@ -193,9 +228,742 @@ struct event_sub_data {
 	unsigned int count;
 };
 
+static void event_sub_cb(const struct ast_event *event, void *d)
+{
+	struct event_sub_data *data = d;
+
+	data->count++;
+}
+
+enum test_subs_class_type {
+	TEST_SUBS_ALL_STR,
+	TEST_SUBS_CUSTOM_STR,
+	TEST_SUBS_CUSTOM_RAW,
+	TEST_SUBS_CUSTOM_UINT,
+	TEST_SUBS_CUSTOM_BITFLAGS,
+	TEST_SUBS_CUSTOM_EXISTS,
+	TEST_SUBS_CUSTOM_DYNAMIC,
+	TEST_SUBS_CUSTOM_ANY,
+
+	/* Must be last. */
+	TEST_SUBS_TOTAL,
+};
+
+/*!
+ * \internal
+ * \brief Convert enum test_subs_class_type to string.
+ *
+ * \param val Enum value to convert to string.
+ *
+ * \return String equivalent of enum value.
+ */
+static const char *test_subs_class_type_str(enum test_subs_class_type val)
+{
+	switch (val) {
+	case TEST_SUBS_ALL_STR:
+		return "TEST_SUBS_ALL_STR";
+	case TEST_SUBS_CUSTOM_STR:
+		return "TEST_SUBS_CUSTOM_STR";
+	case TEST_SUBS_CUSTOM_RAW:
+		return "TEST_SUBS_CUSTOM_RAW";
+	case TEST_SUBS_CUSTOM_UINT:
+		return "TEST_SUBS_CUSTOM_UINT";
+	case TEST_SUBS_CUSTOM_BITFLAGS:
+		return "TEST_SUBS_CUSTOM_BITFLAGS";
+	case TEST_SUBS_CUSTOM_EXISTS:
+		return "TEST_SUBS_CUSTOM_EXISTS";
+	case TEST_SUBS_CUSTOM_DYNAMIC:
+		return "TEST_SUBS_CUSTOM_DYNAMIC";
+	case TEST_SUBS_CUSTOM_ANY:
+		return "TEST_SUBS_CUSTOM_ANY";
+	case TEST_SUBS_TOTAL:
+		break;
+	}
+	return "Unknown";
+}
+
+/*!
+ * \internal
+ * \brief Test event subscriptions
+ *
+ * - Query for existing Subscriptions:
+ *   - ast_event_check_subscriber()
+ */
+AST_TEST_DEFINE(event_sub_test)
+{
+	enum ast_test_result_state res = AST_TEST_PASS;
+	struct ast_event *event;
+	int i;
+	enum ast_event_subscriber_res sub_res;
+	struct {
+		struct ast_event_sub *sub;
+		struct event_sub_data data;
+		const unsigned int expected_count;
+	} test_subs[TEST_SUBS_TOTAL] = {
+		[TEST_SUBS_ALL_STR] = {
+			.expected_count = 2,
+		},
+		[TEST_SUBS_CUSTOM_STR] = {
+			.expected_count = 2,
+		},
+		[TEST_SUBS_CUSTOM_RAW] = {
+			.expected_count = 2,
+		},
+		[TEST_SUBS_CUSTOM_UINT] = {
+			.expected_count = 1,
+		},
+		[TEST_SUBS_CUSTOM_BITFLAGS] = {
+			.expected_count = 4,
+		},
+		[TEST_SUBS_CUSTOM_EXISTS] = {
+			.expected_count = 2,
+		},
+		[TEST_SUBS_CUSTOM_DYNAMIC] = {
+			.expected_count = 1,
+		},
+		[TEST_SUBS_CUSTOM_ANY] = {
+			.expected_count = 6,
+		},
+	};
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "ast_event_subscribe_test";
+		info->category = "/main/event/";
+		info->summary = "Test event subscriptions";
+		info->description =
+			"This test exercises the API calls that allow subscriptions "
+			"to events.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	ast_test_status_update(test, "Check that NO CUSTOM subscribers exist\n");
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "CUSTOM subscriptions should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_STR:
+	 *  - allocate normally
+	 *  - subscribe to CUSTOM events with a DEVICE STR IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_STR subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_STR].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_STR), &test_subs[TEST_SUBS_CUSTOM_STR].data,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_STR].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_STR subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_STR].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_STR))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_STR subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	ast_test_status_update(test, "Check that a CUSTOM subscriber exists\n");
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "A CUSTOM subscription should exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_ALL_STR:
+	 *  - allocate normally
+	 *  - subscribe to ALL events with a DEVICE STR IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_ALL_STR subscription\n");
+	test_subs[TEST_SUBS_ALL_STR].sub = ast_event_subscribe(AST_EVENT_ALL, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_ALL_STR), &test_subs[TEST_SUBS_ALL_STR].data,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_ALL_STR].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_ALL_STR subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_ALL_STR].sub),
+		test_subs_class_type_str(TEST_SUBS_ALL_STR))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_ALL_STR subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_RAW:
+	 *  - allocate normally
+	 *  - subscribe to CUSTOM events with a MAILBOX RAW IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_RAW subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_RAW].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_RAW), &test_subs[TEST_SUBS_CUSTOM_RAW].data,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_RAW].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_RAW subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_RAW].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_RAW))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_RAW subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_UINT:
+	 *  - allocate normally
+	 *  - subscribe to CUSTOM events with a NEWMSGS UINT IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_UINT subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_UINT].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_UINT), &test_subs[TEST_SUBS_CUSTOM_UINT].data,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_UINT].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_UINT subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_UINT].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_UINT))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_UINT subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_BITFLAGS:
+	 *  - allocate normally
+	 *  - subscribe to CUSTOM events with a NEWMSGS BITFLAGS IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_BITFLAGS), &test_subs[TEST_SUBS_CUSTOM_BITFLAGS].data,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 0x06,
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_BITFLAGS))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_EXISTS:
+	 *  - allocate normally
+	 *  - subscribe to CUSTOM events with a NEWMSGS UINT and OLDMSGS EXISTS IE check
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_EXISTS subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_EXISTS].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_EXISTS), &test_subs[TEST_SUBS_CUSTOM_EXISTS].data,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_EXISTS].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_EXISTS subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_EXISTS].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_EXISTS))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_EXISTS subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/* For the sake of exercising destruction before activation */
+	test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM,
+		event_sub_cb, &test_subs[TEST_SUBS_CUSTOM_DYNAMIC].data);
+	if (!test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_DYNAMIC:
+	 *  - allocate dynamically
+	 *  - subscribe to all CUSTOM events
+	 *  - add IE checks for all types
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM,
+		event_sub_cb, &test_subs[TEST_SUBS_CUSTOM_DYNAMIC].data);
+	if (!test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub),
+		"")) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_append_ie_uint(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_NEWMSGS, 4)) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to append UINT IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_append_ie_bitflags(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_OLDMSGS, 1)) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to append BITFLAGS IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_append_ie_str(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_DEVICE, "FOO/bar")) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to append STR IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_append_ie_raw(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_MAILBOX, "800 km",
+			strlen("800 km"))) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to append RAW IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_append_ie_exists(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_STATE)) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to append EXISTS IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (ast_event_sub_activate(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub)) {
+		ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+		test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+		ast_test_status_update(test, "Failed to activate TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Exercise the API call to check for existing subscriptions.
+	 */
+	ast_test_status_update(test, "Checking for subscribers to specific events\n");
+
+	/* Check STR matching. */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "Str FOO/bar subscription did not exist\n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* Make sure that the tech portion of the device string is case-insensitive */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "foo/bar",
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "Str FOO/bar subscription lacks proper case-sensitivity for device strings\n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* Make sure that the non-tech portion of the device string is case-sensitive
+	 * and fails to match appropriately */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/BAR",
+		AST_EVENT_IE_END);
+	if (sub_res == AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "Str FOO/bar subscription lacks proper case-sensitivity for device strings\n");
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Money",
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "Str Money subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/* Check RAW matching. */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "Raw FOO/bar subscription did not exist\n");
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar") - 1,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "Raw FOO/bar-1 subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "Monkeys", sizeof("Monkeys"),
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "Raw Monkeys subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/* Check UINT matching. */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "UINT=5 subscription did not exist\n");
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 1,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "UINT=1 subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/* Check BITFLAGS matching. */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 2,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "BITFLAGS=2 subscription did not exist\n");
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 8,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "BITFLAGS=8 subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	/* Check EXISTS matching. */
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 100,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_EXISTS) {
+		ast_test_status_update(test, "EXISTS subscription did not exist\n");
+		res = AST_TEST_FAIL;
+	}
+
+	sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_END);
+	if (sub_res != AST_EVENT_SUB_NONE) {
+		ast_test_status_update(test, "EXISTS subscription should not exist! (%u)\n",
+			sub_res);
+		res = AST_TEST_FAIL;
+	}
+
+	ast_test_status_update(test, "Special event posting test\n");
+
+	/*
+	 * Event to check if event is even posted.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_RAW
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Mula",
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	ast_test_status_update(test, "Sleeping a few seconds to allow event propagation...\n");
+	sleep(3);
+
+	/*
+	 * Subscription TEST_SUBS_CUSTOM_ANY:
+	 *  - allocate normally
+	 *  - subscribe to all CUSTOM events
+	 */
+	ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_ANY subscription\n");
+	test_subs[TEST_SUBS_CUSTOM_ANY].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_ANY), &test_subs[TEST_SUBS_CUSTOM_ANY].data,
+		AST_EVENT_IE_END);
+	if (!test_subs[TEST_SUBS_CUSTOM_ANY].sub) {
+		ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_ANY subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_ANY].sub),
+		test_subs_class_type_str(TEST_SUBS_CUSTOM_ANY))) {
+		ast_test_status_update(test,
+			"Unexpected subscription description on TEST_SUBS_CUSTOM_ANY subscription\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Fire off some events and track what was received in the callback
+	 */
+	ast_test_status_update(test, "Posting test events\n");
+
+	/*
+	 * Event to check STR matching.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_ALL_STR
+	 * TEST_SUBS_CUSTOM_STR
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar") - 1,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Event to check RAW matching.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_RAW
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Misery",
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Event to check UINT matching.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_UINT
+	 * TEST_SUBS_CUSTOM_BITFLAGS
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Event to check BITFLAGS matching.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_BITFLAGS
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Event to check EXISTS matching.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_EXISTS
+	 * TEST_SUBS_CUSTOM_BITFLAGS
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	/*
+	 * Event to get dynamic subscription to have an event.
+	 *
+	 * Matching subscriptions:
+	 * TEST_SUBS_CUSTOM_DYNAMIC
+	 * TEST_SUBS_CUSTOM_BITFLAGS
+	 * TEST_SUBS_CUSTOM_EXISTS
+	 * TEST_SUBS_ALL_STR
+	 * TEST_SUBS_CUSTOM_STR
+	 * TEST_SUBS_CUSTOM_ANY
+	 */
+	event = ast_event_new(AST_EVENT_CUSTOM,
+		AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+		AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+		AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "800 km", strlen("800 km"),
+		AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+		AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, 5,
+		AST_EVENT_IE_END);
+	if (!event) {
+		ast_test_status_update(test, "Failed to create event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+	if (ast_event_queue(event)) {
+		ast_event_destroy(event);
+		event = NULL;
+		ast_test_status_update(test, "Failed to queue event\n");
+		res = AST_TEST_FAIL;
+		goto return_cleanup;
+	}
+
+	event = NULL;
+
+	/*
+	 * Check the results of the test.
+	 *
+	 * First of all, event distribution is asynchronous from the event producer,
+	 * so knowing when to continue from here and check results is an instance of
+	 * the halting problem.  A few seconds really should be more than enough time.
+	 * If something was actually blocking event distribution that long, I would call
+	 * it a bug.
+	 *
+	 * See test_subs[] initialization for expected results.
+	 */
+
+	ast_test_status_update(test, "Sleeping a few seconds to allow event propagation...\n");
+	sleep(3);
+
+	for (i = 0; i < ARRAY_LEN(test_subs); i++) {
+		if (!test_subs[i].sub) {
+			ast_test_status_update(test, "Missing a test subscription for %s\n",
+				test_subs_class_type_str(i));
+			res = AST_TEST_FAIL;
+		}
+		if (test_subs[i].data.count != test_subs[i].expected_count) {
+			ast_test_status_update(test,
+				"Unexpected callback count, got %u expected %u for %s\n",
+				test_subs[i].data.count, test_subs[i].expected_count,
+				test_subs_class_type_str(i));
+			res = AST_TEST_FAIL;
+		}
+	}
+
+return_cleanup:
+	for (i = 0; i < ARRAY_LEN(test_subs); i++) {
+		if (test_subs[i].sub) {
+			test_subs[i].sub = ast_event_unsubscribe(test_subs[i].sub);
+		}
+	}
+
+	return res;
+}
+
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(event_new_test);
+	AST_TEST_UNREGISTER(event_sub_test);
 
 	return 0;
 }
@@ -203,6 +971,7 @@ static int unload_module(void)
 static int load_module(void)
 {
 	AST_TEST_REGISTER(event_new_test);
+	AST_TEST_REGISTER(event_sub_test);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
diff --git a/tests/test_expr.c b/tests/test_expr.c
index 0a99afc..e29a6a5 100644
--- a/tests/test_expr.c
+++ b/tests/test_expr.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385718 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/tests/test_format_api.c b/tests/test_format_api.c
new file mode 100644
index 0000000..1a5a8c8
--- /dev/null
+++ b/tests/test_format_api.c
@@ -0,0 +1,859 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Tests for the ast_event API
+ *
+ * \author David Vossel <dvossel at digium.com>
+ *
+ * \ingroup tests
+ *
+ */
+
+/*** MODULEINFO
+	<depend>TEST_FRAMEWORK</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+#include "asterisk/strings.h"
+
+/*! These are the keys for accessing attributes */
+enum test_attr_keys {
+	TEST_ATTR_KEY_SAMP_RATE,
+	TEST_ATTR_KEY_STRING,
+};
+
+/*! These are the values for the TEST_ATTR_KEY_SAMP_RATE key */
+enum test_attr_vals_samp {
+	TEST_ATTR_VAL_SAMP_8KHZ  = (1 << 0),
+	TEST_ATTR_VAL_SAMP_12KHZ = (1 << 1),
+	TEST_ATTR_VAL_SAMP_16KHZ = (1 << 2),
+	TEST_ATTR_VAL_SAMP_32KHZ = (1 << 3),
+	TEST_ATTR_VAL_SAMP_48KHZ = (1 << 4),
+};
+
+/*! This is the attribute structure used for our test interface. */
+struct test_attr {
+	enum test_attr_vals_samp samp_flags;
+	char string[32];
+};
+
+static enum ast_format_cmp_res test_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
+{
+	struct test_attr *attr1 = (struct test_attr *) fattr1;
+	struct test_attr *attr2 = (struct test_attr *) fattr2;
+
+	if ((attr1->samp_flags == attr2->samp_flags) &&
+		!(strcmp(attr1->string, attr2->string))) {
+		return AST_FORMAT_CMP_EQUAL;
+	}
+	if ((attr1->samp_flags != (attr1->samp_flags & attr2->samp_flags)) ||
+		(!ast_strlen_zero(attr1->string) && strcmp(attr1->string, attr2->string))) {
+		return AST_FORMAT_CMP_NOT_EQUAL;
+	}
+	return AST_FORMAT_CMP_SUBSET;
+}
+
+static int test_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
+{
+	struct test_attr *attr1 = (struct test_attr *) fattr1;
+	struct test_attr *attr2 = (struct test_attr *) fattr2;
+	struct test_attr *attr_res = (struct test_attr *) result;
+	int joint = -1;
+
+	attr_res->samp_flags = (attr1->samp_flags & attr2->samp_flags);
+
+	if (attr_res->samp_flags) {
+		joint = 0;
+	}
+
+	if (!strcmp(attr1->string, attr2->string)) {
+		ast_copy_string(attr_res->string, attr1->string, sizeof(attr_res->string));
+		joint = 0;
+	}
+
+	return joint;
+}
+
+static void test_set(struct ast_format_attr *fattr, va_list ap)
+{
+	enum test_attr_keys key;
+	struct test_attr *attr = (struct test_attr *) fattr;
+	char *string;
+
+	for (key = va_arg(ap, int);
+		key != AST_FORMAT_ATTR_END;
+		key = va_arg(ap, int))
+	{
+		switch (key) {
+		case TEST_ATTR_KEY_SAMP_RATE:
+			attr->samp_flags = (va_arg(ap, int) | attr->samp_flags);
+			break;
+		case TEST_ATTR_KEY_STRING:
+			string = va_arg(ap, char *);
+			if (!ast_strlen_zero(string)) {
+				ast_copy_string(attr->string, string, sizeof(attr->string));
+			}
+			break;
+		default:
+			ast_log(LOG_WARNING, "unknown attribute type %u\n", key);
+		}
+	}
+}
+
+/*! uLaw does not actually have any attributes associated with it.
+ * This is just for the purpose of testing. We are guaranteed there
+ * will never exist a interface for uLaw already. */
+static struct ast_format_attr_interface test_interface = {
+	.id = AST_FORMAT_TESTLAW,
+	.format_attr_cmp = test_cmp,
+	.format_attr_get_joint = test_getjoint,
+	.format_attr_set = test_set
+};
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(format_test1)
+{
+	struct ast_format format1 = { 0, };
+	struct ast_format format2 = { 0, };
+	struct ast_format joint = { 0, };
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "ast_format_test1";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format with attributes.";
+		info->description =
+			"This test exercises the Ast Format API by creating and registering "
+			"a custom ast_format_attr_interface and performing various function "
+			"calls on ast_formats using the interface. ";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (ast_format_attr_reg_interface(&test_interface)) {
+		ast_test_status_update(test, "test_interface failed to register.\n");
+		return AST_TEST_FAIL;
+	}
+
+	/* set a format with a single attribute. */
+	ast_format_set(&format1, AST_FORMAT_TESTLAW, 1,
+		TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+		AST_FORMAT_ATTR_END);
+	if (ast_format_isset(&format1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END)) {
+		ast_test_status_update(test, "format1 did not set number attribute correctly.\n");
+		return AST_TEST_FAIL;
+	}
+	if (!ast_format_isset(&format1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ, AST_FORMAT_ATTR_END)) {
+		ast_test_status_update(test, "format1 did not determine isset on number correctly. \n");
+		return AST_TEST_FAIL;
+	}
+
+	/* append the string attribute to a format with previous attributes already set */
+	ast_format_append(&format1,
+		TEST_ATTR_KEY_STRING,"String",
+		AST_FORMAT_ATTR_END);
+	if (ast_format_isset(&format1, TEST_ATTR_KEY_STRING, "String", AST_FORMAT_ATTR_END)) {
+		ast_test_status_update(test, "format1 did not set string attribute correctly.\n");
+		return AST_TEST_FAIL;
+	}
+	if (!ast_format_isset(&format1, TEST_ATTR_KEY_STRING, "Not a string", AST_FORMAT_ATTR_END)) {
+		ast_test_status_update(test, "format1 did not determine isset on string correctly. \n");
+		return AST_TEST_FAIL;
+	}
+
+	/* set format2 with both STRING and NUMBER at the same time */
+	ast_format_set(&format2, AST_FORMAT_TESTLAW, 1,
+		TEST_ATTR_KEY_STRING, "MOOOoo",
+		TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+		TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+		AST_FORMAT_ATTR_END);
+	/* perform isset with multiple key value pairs. */
+
+	if (ast_format_isset(&format2,
+			TEST_ATTR_KEY_STRING, "MOOOoo",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END)) {
+
+		ast_test_status_update(test, "format2 did not set attributes correctly.\n");
+		return AST_TEST_FAIL;
+	}
+	if (!ast_format_isset(&format2,
+			TEST_ATTR_KEY_STRING, "WRONG",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END)) {
+
+		ast_test_status_update(test, "format2 did not deterine isset correctly.\n");
+		return AST_TEST_FAIL;
+	}
+
+	/* get joint attributes between format1 and format2. */
+	if (ast_format_joint(&format1, &format2, &joint)) {
+		ast_test_status_update(test, "failed to get joint attributes.\n");
+		return AST_TEST_FAIL;
+	}
+	if (ast_format_isset(&joint, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END)) {
+		ast_test_status_update(test, "joint attribute was not what we expected.\n");
+		return AST_TEST_FAIL;
+	}
+
+	/* exercise compare functions */
+	if (ast_format_cmp(&format1, &format2) != AST_FORMAT_CMP_NOT_EQUAL) {
+		ast_test_status_update(test, "cmp 1 failed.\n");
+		return AST_TEST_FAIL;
+	}
+	if (ast_format_cmp(&format1, &format1) != AST_FORMAT_CMP_EQUAL) {
+		ast_test_status_update(test, "cmp 2 failed.\n");
+		return AST_TEST_FAIL;
+	}
+	if (ast_format_cmp(&joint, &format1) != AST_FORMAT_CMP_SUBSET) {
+		ast_test_status_update(test, "cmp 3 failed.\n");
+		return AST_TEST_FAIL;
+	}
+
+	/* unregister interface */
+	if (ast_format_attr_unreg_interface(&test_interface)) {
+		ast_test_status_update(test, "test_interface failed to unregister.\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(format_test2)
+{
+	struct ast_format format = { 0, };
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "ast_format_test2";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format unique id and category system";
+		info->description =
+			"This test exercises the Ast Format unique id and category "
+			"system by creating formats of various types and verifying "
+			"their category matches what we expect.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	ast_format_set(&format, AST_FORMAT_ULAW, 0);
+	if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_AUDIO) {
+		ast_test_status_update(test, "audio type failed\n");
+		return AST_TEST_FAIL;
+	}
+
+	ast_format_set(&format, AST_FORMAT_H264, 0);
+	if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_VIDEO) {
+		ast_test_status_update(test, "video type failed\n");
+		return AST_TEST_FAIL;
+	}
+
+	ast_format_set(&format, AST_FORMAT_JPEG, 0);
+	if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_IMAGE) {
+		ast_test_status_update(test, "image type failed\n");
+		return AST_TEST_FAIL;
+	}
+
+	ast_format_set(&format, AST_FORMAT_T140, 0);
+	if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_TEXT) {
+		ast_test_status_update(test, "text type failed\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+static int container_test1_helper(struct ast_format_cap *cap1, struct ast_format_cap *cap2, struct ast_test *test)
+{
+
+	int res = AST_TEST_PASS;
+	struct ast_format_cap *cap_joint = NULL;
+	struct ast_format tmpformat;
+
+	if (ast_format_attr_reg_interface(&test_interface)) {
+		ast_test_status_update(test, "test_interface failed to register.\n");
+		ast_format_cap_destroy(cap1);
+		ast_format_cap_destroy(cap2);
+		return AST_TEST_FAIL;
+	}
+
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_G722, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H263, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0));
+	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_STRING, "testing caps hooray",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
+			AST_FORMAT_ATTR_END));
+
+	/* Test is compatible */
+	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
+		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
+		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
+		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
+		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
+		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
+		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 1.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* Test things that are not compatible */
+	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX, 0)) ||
+		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX16, 0)) ||
+		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H261, 0))) {
+		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 2.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* Test compatiblity with format with attributes. */
+	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_STRING, "testing caps hooray",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END))) {
+
+		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 3.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			AST_FORMAT_ATTR_END))) {
+
+		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 4.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, /* 48khz was not compatible, so this should fail iscompatible check */
+			AST_FORMAT_ATTR_END))) {
+
+		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 5.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* Lets start testing the functions that compare ast_format_cap objects.
+	 * Genreate the cap2 object to contain some similar formats as cap1
+	 * and some different formats as well. */
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0));
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_H261, 0));
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
+	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_STRING, "testing caps hooray",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
+			AST_FORMAT_ATTR_END));
+
+
+	/* find joint formats between cap1 and cap2 */
+	cap_joint = ast_format_cap_joint(cap1, cap2);
+
+	if (!cap_joint) {
+		ast_test_status_update(test, "failed to create joint capabilities correctly.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* determine if cap_joint is what we think it should be */
+	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
+		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
+		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)) ||
+		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_STRING, "testing caps hooray",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			AST_FORMAT_ATTR_END))) {
+
+		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* make sure joint cap does not have formats that should not be there */
+	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)) ||
+		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
+			TEST_ATTR_KEY_STRING, "testing caps hooray",
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
+			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
+			AST_FORMAT_ATTR_END))) {
+
+		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* Lets test removing a capability */
+	if (ast_format_cap_remove(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
+		ast_test_status_update(test, "ast_format_cap_remove failed. \n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* Lets make sure what we just removed does not still exist */
+	if (ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
+		ast_test_status_update(test, "ast_format_cap_remove failed 2. \n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* Lets test removing a capability by id.*/
+	if (ast_format_cap_remove_byid(cap_joint, AST_FORMAT_GSM)) {
+		ast_test_status_update(test, "ast_format_cap_remove failed 3. \n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* Lets make sure what we just removed does not still exist */
+	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0))) {
+		ast_test_status_update(test, "ast_format_cap_remove failed 4. \n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* lets test getting joint formats by type */
+	ast_format_cap_destroy(cap_joint);
+	if (!(cap_joint = ast_format_cap_get_type(cap1, AST_FORMAT_TYPE_VIDEO))) {
+		ast_test_status_update(test, "ast_format_cap_get_type failed.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* lets make sure our joint capability structure has what we expect */
+	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
+		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H263, 0))) {
+		ast_test_status_update(test, "get_type failed 2.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	/* now make sure joint does not have anything but video */
+	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
+		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
+		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
+		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
+		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
+		ast_test_status_update(test, "get_type failed 3.\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* now lets remove everythign from cap_joint */
+	ast_format_cap_remove_all(cap_joint);
+	if (!ast_format_cap_is_empty(cap_joint)) {
+		ast_test_status_update(test, "failed to remove all\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+	/* now lets add all by type */
+	ast_format_cap_add_all_by_type(cap_joint, AST_FORMAT_TYPE_AUDIO);
+	if (ast_format_cap_is_empty(cap_joint)) {
+			ast_test_status_update(test, "failed to add all by type AUDIO\n");
+			res = AST_TEST_FAIL;
+	}
+	ast_format_cap_iter_start(cap_joint);
+	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
+		if (AST_FORMAT_GET_TYPE(tmpformat.id) != AST_FORMAT_TYPE_AUDIO) {
+			ast_test_status_update(test, "failed to add all by type AUDIO\n");
+			res = AST_TEST_FAIL;
+			ast_format_cap_iter_end(cap_joint);
+			goto test3_cleanup;
+		}
+	}
+	ast_format_cap_iter_end(cap_joint);
+
+	/* test append */
+	ast_format_cap_append(cap_joint, cap1);
+	ast_format_cap_iter_start(cap1);
+	while (!(ast_format_cap_iter_next(cap1, &tmpformat))) {
+		if (!ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
+			ast_test_status_update(test, "failed to append format capabilities.\n");
+			res = AST_TEST_FAIL;
+			ast_format_cap_iter_end(cap1);
+			goto test3_cleanup;
+		}
+	}
+	ast_format_cap_iter_end(cap1);
+
+	/* test copy */
+	cap1 = ast_format_cap_destroy(cap1);
+	cap1 = ast_format_cap_dup(cap_joint);
+	if (!ast_format_cap_identical(cap_joint, cap1)) {
+			ast_test_status_update(test, "failed to copy capabilities\n");
+			res = AST_TEST_FAIL;
+			goto test3_cleanup;
+	}
+
+	/* test remove by type */
+	ast_format_cap_remove_bytype(cap_joint, AST_FORMAT_TYPE_AUDIO);
+	if (ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_AUDIO)) {
+		ast_test_status_update(test, "failed to remove all by type audio\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	if (!ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_TEXT)) { /* it should still have text */
+		ast_test_status_update(test, "failed to remove all by type audio\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+	ast_format_cap_iter_start(cap_joint);
+	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
+		if (AST_FORMAT_GET_TYPE(tmpformat.id) == AST_FORMAT_TYPE_AUDIO) {
+			ast_test_status_update(test, "failed to remove all by type audio\n");
+			res = AST_TEST_FAIL;
+			ast_format_cap_iter_end(cap_joint);
+			goto test3_cleanup;
+		}
+	}
+	ast_format_cap_iter_end(cap_joint);
+
+	/* test add all */
+	ast_format_cap_remove_all(cap_joint);
+	ast_format_cap_add_all(cap_joint);
+	{
+		int video = 0, audio = 0, text = 0, image = 0;
+		ast_format_cap_iter_start(cap_joint);
+		while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
+			switch (AST_FORMAT_GET_TYPE(tmpformat.id)) {
+			case AST_FORMAT_TYPE_AUDIO:
+				audio++;
+				break;
+			case AST_FORMAT_TYPE_VIDEO:
+				video++;
+				break;
+			case AST_FORMAT_TYPE_TEXT:
+				text++;
+				break;
+			case AST_FORMAT_TYPE_IMAGE:
+				image++;
+				break;
+			}
+		}
+		ast_format_cap_iter_end(cap_joint);
+		if (!video || !audio || !text || !image) {
+			ast_test_status_update(test, "failed to add all\n");
+			res = AST_TEST_FAIL;
+			goto test3_cleanup;
+		}
+	}
+
+	/* test copy2 */
+	ast_format_cap_copy(cap2, cap_joint);
+	if (!ast_format_cap_identical(cap2, cap_joint)) {
+		ast_test_status_update(test, "ast_format_cap_copy failed\n");
+		res = AST_TEST_FAIL;
+		goto test3_cleanup;
+	}
+
+test3_cleanup:
+	ast_format_cap_destroy(cap1);
+	ast_format_cap_destroy(cap2);
+	ast_format_cap_destroy(cap_joint);
+
+	/* unregister interface */
+	if (ast_format_attr_unreg_interface(&test_interface)) {
+		ast_test_status_update(test, "test_interface failed to unregister.\n");
+		res = AST_TEST_FAIL;
+	}
+
+	return res;
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test1_nolock)
+{
+	struct ast_format_cap *cap1;
+	struct ast_format_cap *cap2;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test_1_no_locking";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format and ast_format_cap structures, no locking";
+		info->description =
+			"This test exercises the Ast Format Capability API by creating "
+			"capability structures and performing various API calls on them.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	cap1 = ast_format_cap_alloc_nolock();
+	cap2 = ast_format_cap_alloc_nolock();
+
+	if (!cap1 || !cap2) {
+		ast_test_status_update(test, "cap alloc failed.\n");
+		return AST_TEST_FAIL;
+	}
+	return container_test1_helper(cap1, cap2, test);
+}
+
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test1_withlock)
+{
+	struct ast_format_cap *cap1;
+	struct ast_format_cap *cap2;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test1_with_locking";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format and ast_format_cap structures, with locking";
+		info->description =
+			"This test exercises the Ast Format Capability API by creating "
+			"capability structures and performing various API calls on them.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	cap1 = ast_format_cap_alloc();
+	cap2 = ast_format_cap_alloc();
+
+	if (!cap1 || !cap2) {
+		ast_test_status_update(test, "cap alloc failed.\n");
+		return AST_TEST_FAIL;
+	}
+	return container_test1_helper(cap1, cap2, test);
+}
+
+static int container_test2_no_locking_helper(struct ast_format_cap *cap, struct ast_test *test)
+{
+	int num = 0;
+	struct ast_format tmpformat = { 0, };
+
+	ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_G722, 0));
+
+	ast_format_cap_iter_start(cap);
+	while (!ast_format_cap_iter_next(cap, &tmpformat)) {
+		num++;
+	}
+	ast_format_cap_iter_end(cap);
+
+	ast_format_cap_iter_start(cap);
+	while (!ast_format_cap_iter_next(cap, &tmpformat)) {
+		num++;
+	}
+	ast_format_cap_iter_end(cap);
+
+	ast_format_cap_destroy(cap);
+	ast_test_status_update(test, "%d items iterated over\n", num);
+	return (num == 6) ? AST_TEST_PASS : AST_TEST_FAIL;
+
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test2_no_locking)
+{
+	struct ast_format_cap *cap;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test2_no_locking";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format_cap iterator, no locking";
+		info->description =
+			"This test exercises the Ast Capability API iterators.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	cap = ast_format_cap_alloc_nolock();
+	if (!cap) {
+		ast_test_status_update(test, "alloc failed\n");
+		return AST_TEST_FAIL;
+	}
+	return container_test2_no_locking_helper(cap, test);
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test2_with_locking)
+{
+	struct ast_format_cap *cap;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test2_with_locking";
+		info->category = "/main/format/";
+		info->summary = "Test ast_format_cap iterator, with locking";
+		info->description =
+			"This test exercises the Ast Capability API iterators.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	cap = ast_format_cap_alloc();
+	if (!cap) {
+		ast_test_status_update(test, "alloc failed\n");
+		return AST_TEST_FAIL;
+	}
+	return container_test2_no_locking_helper(cap, test);
+}
+
+
+static int container_test3_helper(int nolocking, struct ast_test *test)
+{
+	int x;
+	int res = AST_TEST_PASS;
+	struct ast_format_cap *cap1;
+	struct ast_format_cap *cap2;
+	struct ast_format_cap *joint;
+
+	for (x = 0; x < 2000; x++) {
+		if (nolocking) {
+			cap1 = ast_format_cap_alloc_nolock();
+			cap2 = ast_format_cap_alloc_nolock();
+			joint = ast_format_cap_alloc_nolock();
+		} else {
+			cap1 = ast_format_cap_alloc();
+			cap2 = ast_format_cap_alloc();
+			joint = ast_format_cap_alloc();
+		}
+		if (!cap1 || !cap2 || !joint) {
+			ast_test_status_update(test, "cap alloc fail\n");
+			return AST_TEST_FAIL;
+		}
+		ast_format_cap_add_all(cap1);
+		ast_format_cap_add_all_by_type(cap2, AST_FORMAT_TYPE_AUDIO);
+		ast_format_cap_joint_copy(cap1, cap2, joint);
+		if (!(ast_format_cap_identical(cap2, joint))) {
+			ast_test_status_update(test, "failed identical test\n");
+			res = AST_TEST_FAIL;
+			cap1 = ast_format_cap_destroy(cap1);
+			cap2 = ast_format_cap_destroy(cap2);
+			joint = ast_format_cap_destroy(joint);
+			break;
+		}
+		cap1 = ast_format_cap_destroy(cap1);
+		cap2 = ast_format_cap_destroy(cap2);
+		joint = ast_format_cap_destroy(joint);
+	}
+	return res;
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test3_nolock)
+{
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test3_no_locking";
+		info->category = "/main/format/";
+		info->summary = "Load Test ast_format_cap no locking.";
+		info->description =
+			"This test exercises the Ast Capability API and its iterators for the purpose "
+			"of measuring performance.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	return container_test3_helper(1, test);
+}
+
+/*!
+ * \internal
+ */
+AST_TEST_DEFINE(container_test3_withlock)
+{
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "container_test3_with_locking";
+		info->category = "/main/format/";
+		info->summary = "Load Test ast_format_cap with locking.";
+		info->description =
+			"This test exercises the Ast Capability API and its iterators for the purpose "
+			"of measuring performance.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	return container_test3_helper(0, test);
+}
+
+static int unload_module(void)
+{
+	AST_TEST_UNREGISTER(format_test1);
+	AST_TEST_UNREGISTER(format_test2);
+	AST_TEST_UNREGISTER(container_test1_nolock);
+	AST_TEST_UNREGISTER(container_test1_withlock);
+	AST_TEST_UNREGISTER(container_test2_no_locking);
+	AST_TEST_UNREGISTER(container_test2_with_locking);
+	AST_TEST_UNREGISTER(container_test3_nolock);
+	AST_TEST_UNREGISTER(container_test3_withlock);
+
+	return 0;
+}
+
+static int load_module(void)
+{
+	AST_TEST_REGISTER(format_test1);
+	AST_TEST_REGISTER(format_test2);
+	AST_TEST_REGISTER(container_test1_nolock);
+	AST_TEST_REGISTER(container_test1_withlock);
+	AST_TEST_REGISTER(container_test2_no_locking);
+	AST_TEST_REGISTER(container_test2_with_locking);
+	AST_TEST_REGISTER(container_test3_nolock);
+	AST_TEST_REGISTER(container_test3_withlock);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_format API Tests");
diff --git a/tests/test_format_cache.c b/tests/test_format_cache.c
deleted file mode 100644
index 0e48046..0000000
--- a/tests/test_format_cache.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Format Cache API Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/codec.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cache.h"
-
-AST_TEST_DEFINE(format_cache_set)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cache_set";
-		info->category = "/main/format_cache/";
-		info->summary = "format cache add unit test";
-		info->description =
-			"Test that adding of a cached format succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create_named("ulaw at 20_1", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Could not add just created format to cache\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cache_set_duplicate)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cache_set_duplicate";
-		info->category = "/main/format_cache/";
-		info->summary = "format cache add unit test";
-		info->description =
-			"Test that adding of a cached format multiple times succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create_named("ulaw at 20_2", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Could not add just created format to cache\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Failed to update cached format\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cache_set_null)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cache_set_null";
-		info->category = "/main/format_cache/";
-		info->summary = "format cache add unit test";
-		info->description =
-			"Test that adding a NULL or empty format to the cache does not succeed";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create_named("", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Successfully cached a format with an empty name\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cache_get)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, cached, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cache_get";
-		info->category = "/main/format_cache/";
-		info->summary = "format cache get unit test";
-		info->description =
-			"Test that getting of a cached format succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create_named("ulaw at 20", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Could not add just created format to cache\n");
-		return AST_TEST_FAIL;
-	}
-
-	cached = ast_format_cache_get("ulaw at 20");
-	if (!cached) {
-		ast_test_status_update(test, "Failed to retrieve a format we just cached\n");
-		return AST_TEST_FAIL;
-	} else if (cached != format) {
-		ast_test_status_update(test, "Returned cached format does not match format we just added\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cache_get_nonexistent)
-{
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, cached, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cache_get_nonxistent";
-		info->category = "/main/format_cache/";
-		info->summary = "format cache get unit test";
-		info->description =
-			"Test that getting of a non-existent cached format does not succeed";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create_named("ulaw at 40", codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cache_set(format)) {
-		ast_test_status_update(test, "Could not add just created format to cache\n");
-		return AST_TEST_FAIL;
-	}
-
-	cached = ast_format_cache_get("ulaw at 60");
-	if (cached) {
-		ast_test_status_update(test, "Retrieved a cached format when one should not have existed\n");
-		return AST_TEST_FAIL;
-	}
-
-	cached = ast_format_cache_get("");
-	if (cached) {
-		ast_test_status_update(test, "Retrieved a cached format when we provided an empty name\n");
-		return AST_TEST_FAIL;
-	}
-
-	cached = ast_format_cache_get(NULL);
-	if (cached) {
-		ast_test_status_update(test, "Retrieved a cached format when we provided a NULL name\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(format_cache_set);
-	AST_TEST_UNREGISTER(format_cache_set_duplicate);
-	AST_TEST_UNREGISTER(format_cache_set_null);
-	AST_TEST_UNREGISTER(format_cache_get);
-	AST_TEST_UNREGISTER(format_cache_get_nonexistent);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(format_cache_set);
-	AST_TEST_REGISTER(format_cache_set_duplicate);
-	AST_TEST_REGISTER(format_cache_set_null);
-	AST_TEST_REGISTER(format_cache_get);
-	AST_TEST_REGISTER(format_cache_get_nonexistent);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Format cache API test module");
diff --git a/tests/test_format_cap.c b/tests/test_format_cap.c
deleted file mode 100644
index c5d131e..0000000
--- a/tests/test_format_cap.c
+++ /dev/null
@@ -1,1479 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Format Capabilities API Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419044 $")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/codec.h"
-#include "asterisk/frame.h"
-#include "asterisk/format.h"
-#include "asterisk/format_cap.h"
-
-AST_TEST_DEFINE(format_cap_alloc)
-{
-	struct ast_format_cap *caps;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_alloc";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities allocation unit test";
-		info->description =
-			"Test that allocation of a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	ao2_ref(caps, -1);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_single)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities adding unit test";
-		info->description =
-			"Test that adding a single format to a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, format, 42)) {
-		ast_test_status_update(test, "Could not add newly created format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 1) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	retrieved = ast_format_cap_get_format(caps, 0);
-	if (!retrieved) {
-		ast_test_status_update(test, "Attempted to get single format from capabilities structure but got nothing\n");
-		return AST_TEST_FAIL;
-	} else if (retrieved != format) {
-		ast_test_status_update(test, "Retrieved format is not the same as the one we added\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) {
-		ast_test_status_update(test, "Framing for format in capabilities structure does not match what we provided\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_multiple)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities adding unit test";
-		info->description =
-			"Test that adding multiple formats to a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(caps, alaw_format, 84)) {
-		ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 2) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	retrieved = ast_format_cap_get_format(caps, 0);
-	if (!retrieved) {
-		ast_test_status_update(test, "Attempted to get first format from capabilities structure but got nothing\n");
-		return AST_TEST_FAIL;
-	} else if (retrieved != ulaw_format) {
-		ast_test_status_update(test, "First retrieved format is not the ulaw one we added\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) {
-		ast_test_status_update(test, "Framing for ulaw format in capabilities structure does not match what we provided\n");
-	}
-	ao2_ref(retrieved, -1);
-
-	retrieved = ast_format_cap_get_format(caps, 1);
-	if (!retrieved) {
-		ast_test_status_update(test, "Attempted to get second format from capabilities structure but got nothing\n");
-		return AST_TEST_FAIL;
-	} else if (retrieved != alaw_format) {
-		ast_test_status_update(test, "First retrieved format is not the alaw one we added\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_get_format_framing(caps, retrieved) != 84) {
-		ast_test_status_update(test, "Framing for alaw format in capabilities structure does not match what we provided\n");
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_all_unknown)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities adding unit test";
-		info->description =
-			"Test that adding of all formats to a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Added all media formats but no audio formats exist when they should\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Added all media formats but no video formats exist when they should\n");
-		return AST_TEST_FAIL;
-	} else if ((ast_format_cap_count(caps) + 1) != ast_codec_get_max()) {
-		ast_test_status_update(test, "The number of formats in the capabilities structure does not match known number\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_all_audio)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities adding unit test";
-		info->description =
-			"Test that adding of all audio formats to a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Added audio media formats but no audio formats exist when they should\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Added only audio media formats but video formats exist when they should not\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_TEXT)) {
-		ast_test_status_update(test, "Added only audio media formats but text formats exist when they should not\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_IMAGE)) {
-		ast_test_status_update(test, "Added only audio media formats but image formats exist when they should not\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_duplicate)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format_named, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities duplication unit test";
-		info->description =
-			"Test that adding a single format multiple times to a capabilities structure results in only a single format";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format_named = ast_format_create_named("ulaw at 20", codec);
-	if (!format_named) {
-		ast_test_status_update(test, "Could not create named format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, format, 42)) {
-		ast_test_status_update(test, "Could not add newly created format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 1) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	/* Note: regardless of it being a duplicate, ast_format_cap_append should return success */
-	if (ast_format_cap_append(caps, format, 0)) {
-		ast_test_status_update(test, "Adding of duplicate format to capabilities structure failed\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 1) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, format_named, 0)) {
-		ast_test_status_update(test, "Adding of duplicate named format to capabilities structure failed\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 1) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	retrieved = ast_format_cap_get_format(caps, 0);
-	if (!retrieved) {
-		ast_test_status_update(test, "Attempted to get single format from capabilities structure but got nothing\n");
-		return AST_TEST_FAIL;
-	} else if (retrieved != format) {
-		ast_test_status_update(test, "Retrieved format is not the same as the one we added\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) {
-		ast_test_status_update(test, "Framing for format in capabilities structure does not match what we provided\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_from_cap)
-{
-	RAII_VAR(struct ast_format_cap *, dst_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, src_caps, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities append unit test";
-		info->description =
-			"Test that appending video formats from one capabilities structure to another succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	dst_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!dst_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	src_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!src_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(src_caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Failed to add all video media formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to append formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Successfully appended video formats to destination capabilities but it no longer contains audio formats\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Successfully appended formats but video formats do not exist in destination capabilities\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_append_from_cap_duplicate)
-{
-	RAII_VAR(struct ast_format_cap *, dst_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, src_caps, NULL, ao2_cleanup);
-	unsigned int count;
-	unsigned int total_count;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities append duplicate unit test";
-		info->description =
-			"Test that appending capabilities structures multiple times does not result in duplicate formats";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	dst_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!dst_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	src_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!src_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(src_caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Failed to add all video media formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	total_count = ast_format_cap_count(src_caps) + ast_format_cap_count(dst_caps);
-
-	if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to append formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Successfully appended video formats to destination capabilities but it no longer contains audio formats\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Successfully appended formats but video formats do not exist in destination capabilities\n");
-		return AST_TEST_FAIL;
-	}
-
-	count = ast_format_cap_count(dst_caps);
-
-	if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to append duplicate formats to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_test_validate(test, count == ast_format_cap_count(dst_caps));
-	ast_test_validate(test, count == total_count);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_set_framing)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_set_framing";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities framing unit test";
-		info->description =
-			"Test that global framing on a format capabilities structure is used when it should be";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_set_framing(caps, 160);
-
-	ast_test_validate(test, ast_format_cap_get_framing(caps) == 160);
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_get_format_framing(caps, ulaw_format) != 42) {
-		ast_test_status_update(test, "Added ulaw format to capabilities structure with explicit framing but did not get it back\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_get_format_framing(caps, alaw_format) != ast_format_get_default_ms(alaw_format)) {
-		ast_test_status_update(test, "Added alaw format to capabilities structure with no explicit framing but did not get global back\n");
-		return AST_TEST_FAIL;
-	}
-	ast_test_validate(test, ast_format_cap_get_framing(caps) == ast_format_get_default_ms(alaw_format));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_remove_single)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_remove_single";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities removal unit test";
-		info->description =
-			"Test that removing a single format from a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!codec) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	format = ast_format_create(codec);
-	if (!format) {
-		ast_test_status_update(test, "Could not create format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, format, 42)) {
-		ast_test_status_update(test, "Could not add newly created format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_remove(caps, format)) {
-		ast_test_status_update(test, "Could not remove format that was just added to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_remove(caps, format)) {
-		ast_test_status_update(test, "Successfully removed a format twice from the capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps)) {
-		ast_test_status_update(test, "Capabilities structure should be empty but instead it contains '%zu' formats\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_remove_multiple)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_remove_multiple";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities removal unit test";
-		info->description =
-			"Test that removing a format from a format capabilities structure containing multiple formats succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(caps, alaw_format, 84)) {
-		ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_remove(caps, ulaw_format)) {
-		ast_test_status_update(test, "Could not remove the ulaw format we just added to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_count(caps) != 1) {
-		ast_test_status_update(test, "Capabilities structure should contain 1 format but it contains '%zu'\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	retrieved = ast_format_cap_get_format(caps, 0);
-	if (!retrieved) {
-		ast_test_status_update(test, "Attempted to get first format from capabilities structure but got nothing\n");
-		return AST_TEST_FAIL;
-	} else if (retrieved != alaw_format) {
-		ast_test_status_update(test, "First retrieved format is not the alaw one we added\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_remove_bytype)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_remove_bytype";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities removal unit test";
-		info->description =
-			"Test that removal of a specific type of format from a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO);
-	if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) {
-		ast_test_status_update(test, "Removed all audio type formats from capabilities structure but some remain\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) {
-		ast_test_status_update(test, "Removed audio type formats from capabilities structure but video are gone as well\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_remove_all)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_remove_all";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities removal unit test";
-		info->description =
-			"Test that removal of all formats from a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) {
-		ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
-
-	if (ast_format_cap_count(caps)) {
-		ast_test_status_update(test, "Removed all formats from capabilities structure but some remain\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_get_compatible_format)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, compatible, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_get_compatible_format";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities negotiation unit test";
-		info->description =
-			"Test that getting a compatible format from a capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	compatible = ast_format_cap_get_compatible_format(caps, alaw_format);
-	if (compatible) {
-		ast_test_status_update(test, "Retrieved a compatible format from capabilities structure when none should exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	compatible = ast_format_cap_get_compatible_format(caps, ulaw_format);
-	if (!compatible) {
-		ast_test_status_update(test, "Did not retrieve a compatible format from capabilities structure when there should be one\n");
-		return AST_TEST_FAIL;
-	} else if (compatible != ulaw_format) {
-		ast_test_status_update(test, "Compatible format is not the format we added to the capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_iscompatible_format)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_iscompatible_format";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities negotiation unit test";
-		info->description =
-			"Test that checking whether a format is compatible with a capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_iscompatible_format(caps, alaw_format) != AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_test_status_update(test, "Alaw format is compatible with capabilities structure when it only contains ulaw\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_iscompatible_format(caps, ulaw_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-		ast_test_status_update(test, "Ulaw format is not compatible with capabilities structure when it should be\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_get_compatible)
-{
-	RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, compatible_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_get_compatible";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities negotiation unit test";
-		info->description =
-			"Test that getting the compatible formats between two capabilities structures succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!alaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!ulaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	compatible_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!compatible_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) {
-		ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_get_compatible(ulaw_caps, alaw_caps, compatible_caps);
-	if (ast_format_cap_count(compatible_caps)) {
-		ast_test_status_update(test, "A compatible format exists when none should\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_get_compatible(ulaw_caps, ulaw_caps, compatible_caps);
-	if (!ast_format_cap_count(compatible_caps)) {
-		ast_test_status_update(test, "No compatible formats exist when 1 should\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_iscompatible)
-{
-	RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_iscompatible";
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities negotiation unit test";
-		info->description =
-			"Test that checking if there are compatible formats between two capabilities structures succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!alaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!ulaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) {
-		ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_iscompatible(ulaw_caps, alaw_caps)) {
-		ast_test_status_update(test, "Two capability structures that should not be compatible are\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_format_cap_iscompatible(ulaw_caps, ulaw_caps)) {
-		ast_test_status_update(test, "Capability structure is not compatible with itself\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_get_names)
-{
-	RAII_VAR(struct ast_format_cap *, empty_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, multi_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-	struct ast_str *buffer = ast_str_alloca(128);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "format_cap_get_names";
-		info->category = "/main/format_cap/";
-		info->summary = "Test getting the names of formats";
-		info->description =
-			"Test that obtaining the names from a format capabilities structure\n"
-			"produces the expected output.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	empty_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!empty_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	multi_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!multi_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!alaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!ulaw_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) {
-		ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(multi_caps, ulaw_format, 0)) {
-		ast_test_status_update(test, "Could not add ulaw format to multi capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(multi_caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add alaw format to multi capabilities\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_format_cap_get_names(empty_caps, &buffer);
-	ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(nothing)"));
-	ast_format_cap_get_names(ulaw_caps, &buffer);
-	ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(ulaw)"));
-	ast_format_cap_get_names(alaw_caps, &buffer);
-	ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(alaw)"));
-	ast_format_cap_get_names(multi_caps, &buffer);
-	ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(ulaw|alaw)"));
-
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(format_cap_best_by_type)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, h263, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, h263_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, best_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities best by type unit test";
-		info->description =
-			"Test that we can get the best format type out of a capabilities structure";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	h263 = ast_codec_get("h263", AST_MEDIA_TYPE_VIDEO, 0);
-	if (!h263) {
-		ast_test_status_update(test, "Could not retrieve built-in h263 codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	h263_format = ast_format_create(h263);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create h263 format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_format_cap_append(caps, ulaw_format, 0)) {
-		ast_test_status_update(test, "Could not add ulaw format to capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(caps, alaw_format, 0)) {
-		ast_test_status_update(test, "Could not add alaw format to capabilities\n");
-		return AST_TEST_FAIL;
-	} else if (ast_format_cap_append(caps, h263_format, 0)) {
-		ast_test_status_update(test, "Could not add h263 format to capabilities\n");
-		return AST_TEST_FAIL;
-	}
-
-	best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
-	ast_test_validate(test, ast_format_cmp(best_format, ulaw_format) == AST_FORMAT_CMP_EQUAL);
-	ao2_ref(best_format, -1);
-
-	best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_AUDIO);
-	ast_test_validate(test, ast_format_cmp(best_format, ulaw_format) == AST_FORMAT_CMP_EQUAL);
-	ao2_ref(best_format, -1);
-
-	best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_VIDEO);
-	ast_test_validate(test, ast_format_cmp(best_format, h263_format) == AST_FORMAT_CMP_EQUAL);
-	ao2_ref(best_format, -1);
-
-	best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_IMAGE);
-	ast_test_validate(test, best_format == NULL);
-
-	best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_TEXT);
-	ast_test_validate(test, best_format == NULL);
-
-	return AST_TEST_PASS;
-}
-
-static int test_law_samples(struct ast_frame *frame)
-{
-	return frame->datalen;
-}
-
-static int test_law_length(unsigned int samples)
-{
-	return samples;
-}
-
-static struct ast_codec test_law = {
-	.name = "test_law",
-	.description = "format cap unit test codec",
-	.type = AST_MEDIA_TYPE_AUDIO,
-	.sample_rate = 8000,
-	.minimum_ms = 10,
-	.maximum_ms = 150,
-	.default_ms = 20,
-	.samples_count = test_law_samples,
-	.get_length = test_law_length,
-	.smooth = 1,
-};
-
-static enum ast_format_cmp_res test_law_cmp(const struct ast_format *format1, const struct ast_format *format2)
-{
-	ast_log(LOG_ERROR, "Comparing format1 %p and format2 %p\n", format1, format2);
-	return format1 == format2 ? AST_FORMAT_CMP_EQUAL : AST_FORMAT_CMP_NOT_EQUAL;
-}
-
-static void test_law_destroy(struct ast_format *format)
-{
-}
-
-static int test_law_clone(const struct ast_format *src, struct ast_format *dst)
-{
-	return 0;
-}
-
-static struct ast_format_interface test_law_interface = {
-	.format_cmp = test_law_cmp,
-	.format_clone = test_law_clone,
-	.format_destroy = test_law_destroy,
-};
-
-AST_TEST_DEFINE(format_cap_replace_from_cap)
-{
-	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, replace_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, result_caps, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, ulaw_format_variant, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __PRETTY_FUNCTION__;
-		info->category = "/main/format_cap/";
-		info->summary = "format capabilities adding unit test";
-		info->description =
-			"Test that adding multiple formats to a format capabilities structure succeeds";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	replace_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	result_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-	if (!caps || !replace_caps || !result_caps) {
-		ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw = ast_codec_get("test_law", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!ulaw) {
-		ast_test_status_update(test, "Could not retrieve test_law codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format = ast_format_create(ulaw);
-	if (!ulaw_format) {
-		ast_test_status_update(test, "Could not create ulaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	ulaw_format_variant = ast_format_create(ulaw);
-	if (!ulaw_format_variant) {
-		ast_test_status_update(test, "Could not create ulaw format variant using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
-	if (!alaw) {
-		ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	alaw_format = ast_format_create(alaw);
-	if (!alaw_format) {
-		ast_test_status_update(test, "Could not create alaw format using built-in codec\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* fill caps with ulaw and alaw */
-	if (ast_format_cap_append(caps, ulaw_format, 42)) {
-		ast_test_status_update(test, "Could not add ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	if (ast_format_cap_append(caps, alaw_format, 84)) {
-		ast_test_status_update(test, "Could not add alaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	if (ast_format_cap_count(caps) != 2) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n",
-			ast_format_cap_count(caps));
-		return AST_TEST_FAIL;
-	}
-
-	/* fill replace_caps with the ulaw variant */
-	if (ast_format_cap_append(replace_caps, ulaw_format_variant, 42)) {
-		ast_test_status_update(test, "Could not add ulaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	if (ast_format_cap_count(replace_caps) != 1) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n",
-			ast_format_cap_count(replace_caps));
-		return AST_TEST_FAIL;
-	}
-
-	/* fill result_caps with ulaw_variant and alaw */
-	if (ast_format_cap_append(result_caps, ulaw_format_variant, 42)) {
-		ast_test_status_update(test, "Could not add ulaw variant to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	if (ast_format_cap_append(result_caps, alaw_format, 84)) {
-		ast_test_status_update(test, "Could not add alaw format to capabilities structure\n");
-		return AST_TEST_FAIL;
-	}
-	if (ast_format_cap_count(result_caps) != 2) {
-		ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n",
-			ast_format_cap_count(result_caps));
-		return AST_TEST_FAIL;
-	}
-
-	/* replace caps formats from replace_caps */
-	ast_format_cap_replace_from_cap(caps, replace_caps, AST_MEDIA_TYPE_UNKNOWN);
-
-	/* compare result_caps with caps */
-	if (!ast_format_cap_identical(caps, result_caps)) {
-		ast_test_status_update(test, "Actual and expected result caps differ\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(format_cap_alloc);
-	AST_TEST_UNREGISTER(format_cap_append_single);
-	AST_TEST_UNREGISTER(format_cap_append_multiple);
-	AST_TEST_UNREGISTER(format_cap_append_all_unknown);
-	AST_TEST_UNREGISTER(format_cap_append_all_audio);
-	AST_TEST_UNREGISTER(format_cap_append_duplicate);
-	AST_TEST_UNREGISTER(format_cap_append_from_cap);
-	AST_TEST_UNREGISTER(format_cap_append_from_cap_duplicate);
-	AST_TEST_UNREGISTER(format_cap_set_framing);
-	AST_TEST_UNREGISTER(format_cap_remove_single);
-	AST_TEST_UNREGISTER(format_cap_remove_multiple);
-	AST_TEST_UNREGISTER(format_cap_remove_bytype);
-	AST_TEST_UNREGISTER(format_cap_remove_all);
-	AST_TEST_UNREGISTER(format_cap_get_names);
-	AST_TEST_UNREGISTER(format_cap_get_compatible_format);
-	AST_TEST_UNREGISTER(format_cap_iscompatible_format);
-	AST_TEST_UNREGISTER(format_cap_get_compatible);
-	AST_TEST_UNREGISTER(format_cap_iscompatible);
-	AST_TEST_UNREGISTER(format_cap_best_by_type);
-	AST_TEST_UNREGISTER(format_cap_replace_from_cap);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(format_cap_alloc);
-	AST_TEST_REGISTER(format_cap_append_single);
-	AST_TEST_REGISTER(format_cap_append_multiple);
-	AST_TEST_REGISTER(format_cap_append_all_unknown);
-	AST_TEST_REGISTER(format_cap_append_all_audio);
-	AST_TEST_REGISTER(format_cap_append_duplicate);
-	AST_TEST_REGISTER(format_cap_append_from_cap);
-	AST_TEST_REGISTER(format_cap_append_from_cap_duplicate);
-	AST_TEST_REGISTER(format_cap_set_framing);
-	AST_TEST_REGISTER(format_cap_remove_single);
-	AST_TEST_REGISTER(format_cap_remove_multiple);
-	AST_TEST_REGISTER(format_cap_remove_bytype);
-	AST_TEST_REGISTER(format_cap_remove_all);
-	AST_TEST_REGISTER(format_cap_get_names);
-	AST_TEST_REGISTER(format_cap_get_compatible_format);
-	AST_TEST_REGISTER(format_cap_iscompatible_format);
-	AST_TEST_REGISTER(format_cap_get_compatible);
-	AST_TEST_REGISTER(format_cap_iscompatible);
-	AST_TEST_REGISTER(format_cap_best_by_type);
-	AST_TEST_REGISTER(format_cap_replace_from_cap);
-	ast_codec_register(&test_law);
-	ast_format_interface_register("test_law", &test_law_interface);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Format capabilities API test module");
diff --git a/tests/test_func_file.c b/tests/test_func_file.c
index 287e747..8349075 100644
--- a/tests/test_func_file.c
+++ b/tests/test_func_file.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385718 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
@@ -63,6 +63,12 @@ static struct {
 	/* No length */
 	{ "123456789", "-5", "56789" },
 	{ "123456789", "4", "56789" },
+	/* Passed file length */
+	{ "123456789", "8,10", "9" },
+	{ "123456789", "10,1", "" },
+	/* Middle of file */
+	{ "123456789", "2,5", "34567" },
+	{ "123456789", "-7,5", "34567" },
 	/* Line mode, 4 ways of specifying the first character */
 	{ "123\n456\n789\n", "0,1,l", "123\n" },
 	{ "123\n456\n789\n", "-3,1,l", "123\n" },
diff --git a/tests/test_gosub.c b/tests/test_gosub.c
index 6fd9cca..3f6b3a7 100644
--- a/tests/test_gosub.c
+++ b/tests/test_gosub.c
@@ -20,7 +20,7 @@
  * \file
  * \brief Gosub tests
  *
- * \author Tilghman Lesher \verbatim <tlesher AT digium DOT com> \endverbatim
+ * \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
  *
  * \ingroup tests
  */
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
@@ -42,10 +42,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
 
 AST_TEST_DEFINE(test_gosub)
 {
+#define CONTEXT_NAME "tests_test_gosub_virtual_context"
 	int res = AST_TEST_PASS, i;
 	struct ast_channel *chan;
 	struct ast_str *str;
-	struct ast_context *con;
 	struct testplan {
 		const char *app;
 		const char *args;
@@ -119,14 +119,14 @@ AST_TEST_DEFINE(test_gosub)
 	}
 
 	/* Create our test dialplan */
-	if (!(con = ast_context_find_or_create(NULL, NULL, "tests_test_gosub_virtual_context", "test_gosub"))) {
+	if (!ast_context_find_or_create(NULL, NULL, CONTEXT_NAME, "test_gosub")) {
 		ast_test_status_update(test, "Unable to create test dialplan context");
 		ast_free(str);
 		ast_channel_unref(chan);
 		return AST_TEST_FAIL;
 	}
 
-	ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "test_gosub");
+	ast_add_extension(CONTEXT_NAME, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "test_gosub");
 
 	for (i = 0; i < ARRAY_LEN(testplan); i++) {
 		if (testplan[i].app == NULL) {
@@ -157,8 +157,8 @@ AST_TEST_DEFINE(test_gosub)
 
 	ast_free(str);
 	ast_channel_unref(chan);
-	ast_context_remove_extension2(con, "s", 1, NULL, 0);
-	ast_context_destroy(con, "test_gosub");
+	ast_context_remove_extension(CONTEXT_NAME, "s", 1, NULL);
+	ast_context_destroy(NULL, "test_gosub");
 
 	return res;
 }
diff --git a/tests/test_hashtab_thrash.c b/tests/test_hashtab_thrash.c
index 9942d1c..d124c0b 100644
--- a/tests/test_hashtab_thrash.c
+++ b/tests/test_hashtab_thrash.c
@@ -35,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <pthread.h>
 #include "asterisk/hashtab.h"
 #include "asterisk/lock.h"
@@ -58,20 +58,10 @@ struct hash_test {
 	int preload;
 	/*! When to give up on the tests */
 	struct timeval deadline;
-	/*! The actual test object */
-	struct ast_test *test;
 };
 
 static int is_timed_out(struct hash_test const *data) {
-	struct timeval now = ast_tvnow();
-	int val = ast_tvdiff_us(data->deadline, now) < 0;
-	if (val) {
-		/* tv_usec is suseconds_t, which could be int or long */
-		ast_test_status_update(data->test, "Now: %ld.%06ld Deadline: %ld.%06ld\n",
-			now.tv_sec, (long)now.tv_usec,
-			data->deadline.tv_sec, (long)data->deadline.tv_usec);
-	}
-	return val;
+	return ast_tvdiff_us(data->deadline, ast_tvnow()) < 0;
 }
 
 /*! /brief Create test element */
@@ -245,7 +235,6 @@ AST_TEST_DEFINE(hash_test)
 	}
 
 	ast_test_status_update(test, "Executing hash concurrency test...\n");
-	data.test = test;
 	data.preload = MAX_HASH_ENTRIES / 2;
 	data.max_grow = MAX_HASH_ENTRIES - data.preload;
 	data.deadline = ast_tvadd(ast_tvnow(), ast_tv(MAX_TEST_SECONDS, 0));
diff --git a/tests/test_heap.c b/tests/test_heap.c
index d10da1b..cf1a914 100644
--- a/tests/test_heap.c
+++ b/tests/test_heap.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 332178 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
diff --git a/tests/test_jitterbuf.c b/tests/test_jitterbuf.c
index d29e89d..65e7d4d 100644
--- a/tests/test_jitterbuf.c
+++ b/tests/test_jitterbuf.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 396857 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
@@ -96,10 +96,7 @@ static const char *jitter_buffer_return_codes[] = {
 	"JB_SCHED"          /* 5 */
 };
 
-/*!
- * \internal
- * \brief Make a default jitter buffer configuration
- */
+/*! \internal \brief Make a default jitter buffer configuration */
 static void test_jb_populate_config(struct jb_conf *jbconf)
 {
 	if (!jbconf) {
@@ -112,10 +109,7 @@ static void test_jb_populate_config(struct jb_conf *jbconf)
 	jbconf->target_extra = 0;
 }
 
-/*!
- * \internal
- * \brief Debug callback function for the jitter buffer's jb_dbg function
- */
+/*! \internal \brief Debug callback function for the jitter buffer's jb_dbg function */
 static void __attribute__((format(printf, 1, 2))) test_jb_debug_output(const char *fmt, ...)
 {
 	va_list args;
@@ -128,10 +122,7 @@ static void __attribute__((format(printf, 1, 2))) test_jb_debug_output(const cha
 	ast_debug(1, "%s", buf);
 }
 
-/*!
- * \internal
- * \brief Warning callback function for the jitter buffer's jb_warn function
- */
+/*! \internal \brief Warning callback function for the jitter buffer's jb_warn function */
 static void __attribute__((format(printf, 1, 2))) test_jb_warn_output(const char *fmt, ...)
 {
 	va_list args;
@@ -144,10 +135,7 @@ static void __attribute__((format(printf, 1, 2))) test_jb_warn_output(const char
 	ast_log(AST_LOG_WARNING, "%s", buf);
 }
 
-/*!
- * \internal
- * \brief Error callback function for the jitter buffer's jb_err function
- */
+/*! \internal \brief Error callback function for the jitter buffer's jb_err function */
 static void __attribute__((format(printf, 1, 2))) test_jb_error_output(const char *fmt, ...)
 {
 	va_list args;
@@ -160,10 +148,7 @@ static void __attribute__((format(printf, 1, 2))) test_jb_error_output(const cha
 	ast_log(AST_LOG_ERROR, "%s", buf);
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the nominal tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the nominal tests */
 static int test_jb_nominal_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0, ret = 0;
@@ -338,10 +323,7 @@ cleanup:
 	return result;
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the out of order tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the out of order tests */
 static int test_jb_out_of_order_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0, ret = 0;
@@ -535,10 +517,7 @@ cleanup:
 	return result;
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the lost frame tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the lost frame tests */
 static int test_jb_lost_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0, ret = 0;
@@ -729,10 +708,7 @@ cleanup:
 	return result;
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the late frame tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the late frame tests */
 static int test_jb_late_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0, ret = 0;
@@ -915,10 +891,7 @@ cleanup:
 	return result;
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the overflow tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the overflow tests */
 static void test_jb_overflow_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0;
@@ -1067,10 +1040,7 @@ cleanup:
 	return result;
 }
 
-/*!
- * \internal
- * \brief Insert frames into the jitter buffer for the resynch tests
- */
+/*! \internal \brief Insert frames into the jitter buffer for the resynch tests */
 static void test_jb_resynch_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
 {
 	int i = 0;
diff --git a/tests/test_json.c b/tests/test_json.c
deleted file mode 100644
index e4f6c2f..0000000
--- a/tests/test_json.c
+++ /dev/null
@@ -1,1810 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test JSON API.
- *
- * While some of these tests are actually testing our JSON library wrapper, the bulk of
- * them are exploratory tests to determine what the behavior of the underlying JSON
- * library is. This also gives us a good indicator if that behavior changes between
- * Jansson revisions.
- *
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
-#include "asterisk/json.h"
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-
-#include <stdio.h>
-#include <unistd.h>
-
-#define CATEGORY "/main/json/"
-
-/*!
- * Number of allocations from JSON library that have not yet been freed.
- */
-static size_t alloc_count;
-
-/*!@{*/
-/*!
- * JSON library has its own reference counting, so we'll provide our own allocators to
- * test that everything gets freed as expected.
- */
-static void *json_debug_malloc(size_t size)
-{
-	void *p = ast_json_malloc(size);
-	if (p) {
-		++alloc_count;
-	}
-	return p;
-}
-
-static void json_debug_free(void *p)
-{
-	if (p) {
-		--alloc_count;
-	}
-	ast_json_free(p);
-}
-
-static int json_test_init(struct ast_test_info *info, struct ast_test *test)
-{
-	ast_json_set_alloc_funcs(json_debug_malloc, json_debug_free);
-	alloc_count = 0;
-	return 0;
-}
-
-static int json_test_cleanup(struct ast_test_info *info, struct ast_test *test)
-{
-	ast_json_reset_alloc_funcs();
-	if (0 != alloc_count) {
-		ast_test_status_update(test,
-			"JSON test leaked %zu allocations!\n", alloc_count);
-		return -1;
-	}
-	return 0;
-}
-
-/*!@}*/
-
-AST_TEST_DEFINE(json_test_false)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "false";
-		info->category = CATEGORY;
-		info->summary = "Testing fundamental JSON false value.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_false();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_FALSE == ast_json_typeof(uut));
-	ast_test_validate(test, !ast_json_is_null(uut));
-	ast_test_validate(test, !ast_json_is_true(uut));
-	ast_test_validate(test, ast_json_is_false(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_true)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "true";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON true value.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_true();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_TRUE == ast_json_typeof(uut));
-	ast_test_validate(test, !ast_json_is_null(uut));
-	ast_test_validate(test, ast_json_is_true(uut));
-	ast_test_validate(test, !ast_json_is_false(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_bool0)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bool0";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON boolean function (false).";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_boolean(0);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_FALSE == ast_json_typeof(uut));
-	ast_test_validate(test, !ast_json_is_null(uut));
-	ast_test_validate(test, !ast_json_is_true(uut));
-	ast_test_validate(test, ast_json_is_false(uut));
-	ast_test_validate(test, ast_json_equal(uut, ast_json_false()));
-	ast_test_validate(test, !ast_json_equal(uut, ast_json_true()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_bool1)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "bool1";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON boolean function (true).";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_boolean(1);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_TRUE == ast_json_typeof(uut));
-	ast_test_validate(test, !ast_json_is_null(uut));
-	ast_test_validate(test, ast_json_is_true(uut));
-	ast_test_validate(test, !ast_json_is_false(uut));
-	ast_test_validate(test, !ast_json_equal(uut, ast_json_false()));
-	ast_test_validate(test, ast_json_equal(uut, ast_json_true()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "null";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON null value.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_null();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_NULL == ast_json_typeof(uut));
-	ast_test_validate(test, ast_json_is_null(uut));
-	ast_test_validate(test, !ast_json_is_true(uut));
-	ast_test_validate(test, !ast_json_is_false(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_null_val)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "null_val";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON handling of NULL.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* NULL isn't null, true or false */
-	ast_test_validate(test, !ast_json_is_null(NULL));
-	ast_test_validate(test, !ast_json_is_false(NULL));
-	ast_test_validate(test, !ast_json_is_true(NULL));
-
-	/* ref and unref should be NULL safe */
-	ast_json_ref(NULL);
-	ast_json_unref(NULL);
-	/* no segfault; we're good. le sigh. */
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_string)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "string";
-		info->category = CATEGORY;
-		info->summary = "Basic string tests.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_string_create("Hello, json");
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_STRING == ast_json_typeof(uut));
-	ast_test_validate(test, 0 == strcmp("Hello, json", ast_json_string_get(uut)));
-
-	uut_res = ast_json_string_set(uut, NULL);
-	ast_test_validate(test, -1 == uut_res);
-	ast_test_validate(test, 0 == strcmp("Hello, json", ast_json_string_get(uut)));
-
-	uut_res = ast_json_string_set(uut, "Not UTF-8 - \xff");
-	ast_test_validate(test, -1 == uut_res);
-	ast_test_validate(test, 0 == strcmp("Hello, json", ast_json_string_get(uut)));
-
-	uut_res = ast_json_string_set(uut, "Is UTF-8 - \xE2\x98\xBA");
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 0 == strcmp("Is UTF-8 - \xE2\x98\xBA", ast_json_string_get(uut)));
-
-	uut_res = ast_json_string_set(uut, "Goodbye, json");
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 0 == strcmp("Goodbye, json", ast_json_string_get(uut)));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_string_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "string_null";
-		info->category = CATEGORY;
-		info->summary = "JSON string NULL tests.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* NULL string */
-	uut = ast_json_string_create(NULL);
-	ast_test_validate(test, NULL == uut);
-
-	/* NULL JSON strings */
-	ast_test_validate(test, NULL == ast_json_string_create(NULL));
-	ast_test_validate(test, NULL == ast_json_string_get(NULL));
-	ast_test_validate(test, -1 == ast_json_string_set(NULL, "not null"));
-
-	/* string_value from non-string elements should return NULL */
-	ast_test_validate(test, NULL == ast_json_string_get(ast_json_null()));
-	ast_test_validate(test, NULL == ast_json_string_get(ast_json_false()));
-	ast_test_validate(test, NULL == ast_json_string_get(ast_json_true()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_stringf)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "stringf";
-		info->category = CATEGORY;
-		info->summary = "Basic string formatting tests.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* NULL format string */
-	uut = ast_json_stringf(NULL);
-	ast_test_validate(test, NULL == uut);
-
-	/* Non-UTF-8 strings are invalid */
-	uut = ast_json_stringf("Not UTF-8 - %s", "\xff");
-	ast_test_validate(test, NULL == uut);
-
-	/* formatted string */
-	uut = ast_json_stringf("Hello, %s", "json");
-	expected = ast_json_string_create("Hello, json");
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_int)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "int";
-		info->category = CATEGORY;
-		info->summary = "Basic JSON integer tests.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Integer tests */
-	uut = ast_json_integer_create(0);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_INTEGER == ast_json_typeof(uut));
-	ast_test_validate(test, 0 == ast_json_integer_get(uut));
-
-	uut_res = ast_json_integer_set(uut, 1);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 1 == ast_json_integer_get(uut));
-
-	uut_res = ast_json_integer_set(uut, -1);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, -1 == ast_json_integer_get(uut));
-
-	uut_res = ast_json_integer_set(uut, LLONG_MAX);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, LLONG_MAX == ast_json_integer_get(uut));
-
-	uut_res = ast_json_integer_set(uut, LLONG_MIN);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, LLONG_MIN == ast_json_integer_get(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_non_int)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "non_int";
-		info->category = CATEGORY;
-		info->summary = "Testing integer functions with non-integer types.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Non-ints return 0 integer value */
-	ast_test_validate(test, 0 == ast_json_integer_get(ast_json_null()));
-	ast_test_validate(test, 0 == ast_json_integer_get(ast_json_true()));
-	ast_test_validate(test, 0 == ast_json_integer_get(ast_json_false()));
-
-	/* JSON NULL integers */
-	ast_test_validate(test, 0 == ast_json_integer_get(NULL));
-	ast_test_validate(test, -1 == ast_json_integer_set(NULL, 911));
-	ast_test_validate(test, 0 == ast_json_array_size(NULL));
-
-	/* No magical parsing of strings into ints */
-	uut = ast_json_string_create("314");
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, 0 == ast_json_integer_get(uut));
-
-	/* Or vice-versa */
-	ast_json_unref(uut);
-	uut = ast_json_integer_create(314);
-	ast_test_validate(test, NULL == ast_json_string_get(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_create)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_create";
-		info->category = CATEGORY;
-		info->summary = "Testing creating JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array creation */
-	uut = ast_json_array_create();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_ARRAY == ast_json_typeof(uut));
-	ast_test_validate(test, 0 == ast_json_array_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_append)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_append";
-		info->category = CATEGORY;
-		info->summary = "Testing appending to JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array append */
-	uut = ast_json_array_create();
-	uut_res = ast_json_array_append(uut, ast_json_string_create("one"));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 1 == ast_json_array_size(uut));
-	ast_test_validate(test, 0 == strcmp("one", ast_json_string_get(ast_json_array_get(uut, 0))));
-	/* index out of range */
-	ast_test_validate(test, NULL == ast_json_array_get(uut, 1));
-	ast_test_validate(test, NULL == ast_json_array_get(uut, -1));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_inset)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_insert";
-		info->category = CATEGORY;
-		info->summary = "Testing inserting into JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array insert */
-	uut = ast_json_pack("[s]", "one");
-	uut_res = ast_json_array_insert(uut, 0, ast_json_string_create("zero"));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 2 == ast_json_array_size(uut));
-	ast_test_validate(test, 0 == strcmp("zero", ast_json_string_get(ast_json_array_get(uut, 0))));
-	ast_test_validate(test, 0 == strcmp("one", ast_json_string_get(ast_json_array_get(uut, 1))));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_set)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_set";
-		info->category = CATEGORY;
-		info->summary = "Testing setting a value in JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array set */
-	uut = ast_json_pack("[s, s]", "zero", "one");
-	uut_res = ast_json_array_set(uut, 1, ast_json_integer_create(1));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 2 == ast_json_array_size(uut));
-	ast_test_validate(test, 0 == strcmp("zero", ast_json_string_get(ast_json_array_get(uut, 0))));
-	ast_test_validate(test, 1 == ast_json_integer_get(ast_json_array_get(uut, 1)));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_remove)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_remove";
-		info->category = CATEGORY;
-		info->summary = "Testing removing a value from JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array remove */
-	uut = ast_json_pack("[s, i]", "zero", 1);
-	expected = ast_json_pack("[i]", 1);
-	uut_res = ast_json_array_remove(uut, 0);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_clear)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_clear";
-		info->category = CATEGORY;
-		info->summary = "Testing clearing JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array clear */
-	uut = ast_json_pack("[s, s]", "zero", "one");
-	uut_res = ast_json_array_clear(uut);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 0 == ast_json_array_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_extend)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, tail, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_extend";
-		info->category = CATEGORY;
-		info->summary = "Testing extending JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array extending */
-	expected = ast_json_array_create();
-	ast_json_array_append(expected, ast_json_string_create("a"));
-	ast_json_array_append(expected, ast_json_string_create("b"));
-	ast_json_array_append(expected, ast_json_string_create("c"));
-	ast_json_array_append(expected, ast_json_integer_create(1));
-	ast_json_array_append(expected, ast_json_integer_create(2));
-	ast_json_array_append(expected, ast_json_integer_create(3));
-
-	uut = ast_json_array_create();
-	ast_json_array_append(uut, ast_json_string_create("a"));
-	ast_json_array_append(uut, ast_json_string_create("b"));
-	ast_json_array_append(uut, ast_json_string_create("c"));
-
-	tail = ast_json_array_create();
-	ast_json_array_append(tail, ast_json_integer_create(1));
-	ast_json_array_append(tail, ast_json_integer_create(2));
-	ast_json_array_append(tail, ast_json_integer_create(3));
-
-	uut_res = ast_json_array_extend(uut, tail);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	/* tail is preserved */
-	ast_test_validate(test, 3 == ast_json_array_size(tail));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_array_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "array_null";
-		info->category = CATEGORY;
-		info->summary = "Testing NULL conditions for JSON arrays.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* array NULL checks */
-	ast_test_validate(test, 0 == ast_json_array_size(NULL));
-	ast_test_validate(test, NULL == ast_json_array_get(NULL, 0));
-	ast_test_validate(test, -1 == ast_json_array_set(NULL, 0, ast_json_null()));
-	ast_test_validate(test, -1 == ast_json_array_append(NULL, ast_json_null()));
-	ast_test_validate(test, -1 == ast_json_array_insert(NULL, 0, ast_json_null()));
-	ast_test_validate(test, -1 == ast_json_array_remove(NULL, 0));
-	ast_test_validate(test, -1 == ast_json_array_clear(NULL));
-	uut = ast_json_array_create();
-	ast_test_validate(test, -1 == ast_json_array_extend(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_array_extend(NULL, uut));
-	ast_test_validate(test, -1 == ast_json_array_extend(NULL, NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_alloc)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc";
-		info->category = CATEGORY;
-		info->summary = "Testing creating JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object allocation */
-	uut = ast_json_object_create();
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, AST_JSON_OBJECT == ast_json_typeof(uut));
-	ast_test_validate(test, 0 == ast_json_object_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_set)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_set";
-		info->category = CATEGORY;
-		info->summary = "Testing setting values in JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object set */
-	expected = ast_json_pack("{s: i, s: i, s: i}", "one", 1, "two", 2, "three", 3);
-	uut = ast_json_object_create();
-	uut_res = ast_json_object_set(uut, "one", ast_json_integer_create(1));
-	ast_test_validate(test, 0 == uut_res);
-	uut_res = ast_json_object_set(uut, "two", ast_json_integer_create(2));
-	ast_test_validate(test, 0 == uut_res);
-	uut_res = ast_json_object_set(uut, "three", ast_json_integer_create(3));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	ast_test_validate(test, NULL == ast_json_object_get(uut, "dne"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_set_overwrite)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_set_overwriting";
-		info->category = CATEGORY;
-		info->summary = "Testing changing values in JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object set existing */
-	uut = ast_json_pack("{s: i, s: i, s: i}", "one", 1, "two", 2, "three", 3);
-	uut_res = ast_json_object_set(uut, "two", ast_json_integer_create(-2));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, -2 == ast_json_integer_get(ast_json_object_get(uut, "two")));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_get)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_get";
-		info->category = CATEGORY;
-		info->summary = "Testing getting values from JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object get */
-	uut = ast_json_pack("{s: i, s: i, s: i}", "one", 1, "two", 2, "three", 3);
-	ast_test_validate(test, 2 == ast_json_integer_get(ast_json_object_get(uut, "two")));
-	ast_test_validate(test, NULL == ast_json_object_get(uut, "dne"));
-	ast_test_validate(test, NULL == ast_json_object_get(uut, NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_del)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_del";
-		info->category = CATEGORY;
-		info->summary = "Testing deleting values from JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object del */
-	expected = ast_json_object_create();
-	uut = ast_json_pack("{s: i}", "one", 1);
-	uut_res = ast_json_object_del(uut, "one");
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	uut_res = ast_json_object_del(uut, "dne");
-	ast_test_validate(test, -1 == uut_res);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_clear)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_clear";
-		info->category = CATEGORY;
-		info->summary = "Testing clearing values from JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object clear */
-	uut = ast_json_object_create();
-	ast_json_object_set(uut, "one", ast_json_integer_create(1));
-	ast_json_object_set(uut, "two", ast_json_integer_create(2));
-	ast_json_object_set(uut, "three", ast_json_integer_create(3));
-	uut_res = ast_json_object_clear(uut);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, 0 == ast_json_object_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_merge_all)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, merge, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc";
-		info->category = CATEGORY;
-		info->summary = "Testing merging JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object merging - all */
-	uut = ast_json_object_create();
-	ast_json_object_set(uut, "one", ast_json_integer_create(1));
-	ast_json_object_set(uut, "two", ast_json_integer_create(2));
-	ast_json_object_set(uut, "three", ast_json_integer_create(3));
-
-	merge = ast_json_object_create();
-	ast_json_object_set(merge, "three", ast_json_integer_create(-3));
-	ast_json_object_set(merge, "four", ast_json_integer_create(-4));
-	ast_json_object_set(merge, "five", ast_json_integer_create(-5));
-
-	expected = ast_json_object_create();
-	ast_json_object_set(expected, "one", ast_json_integer_create(1));
-	ast_json_object_set(expected, "two", ast_json_integer_create(2));
-	ast_json_object_set(expected, "three", ast_json_integer_create(-3));
-	ast_json_object_set(expected, "four", ast_json_integer_create(-4));
-	ast_json_object_set(expected, "five", ast_json_integer_create(-5));
-
-	uut_res = ast_json_object_update(uut, merge);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	/* merge object is untouched */
-	ast_test_validate(test, 3 == ast_json_object_size(merge));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_merge_existing)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, merge, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc";
-		info->category = CATEGORY;
-		info->summary = "Testing merging JSON objects, updating only existing fields.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object merging - existing */
-	uut = ast_json_object_create();
-	ast_json_object_set(uut, "one", ast_json_integer_create(1));
-	ast_json_object_set(uut, "two", ast_json_integer_create(2));
-	ast_json_object_set(uut, "three", ast_json_integer_create(3));
-
-	merge = ast_json_object_create();
-	ast_json_object_set(merge, "three", ast_json_integer_create(-3));
-	ast_json_object_set(merge, "four", ast_json_integer_create(-4));
-	ast_json_object_set(merge, "five", ast_json_integer_create(-5));
-
-	expected = ast_json_object_create();
-	ast_json_object_set(expected, "one", ast_json_integer_create(1));
-	ast_json_object_set(expected, "two", ast_json_integer_create(2));
-	ast_json_object_set(expected, "three", ast_json_integer_create(-3));
-
-	uut_res = ast_json_object_update_existing(uut, merge);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	/* merge object is untouched */
-	ast_test_validate(test, 3 == ast_json_object_size(merge));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_merge_missing)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, merge, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_merge_missing";
-		info->category = CATEGORY;
-		info->summary = "Testing merging JSON objects, adding only missing fields.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* object merging - missing */
-	uut = ast_json_object_create();
-	ast_json_object_set(uut, "one", ast_json_integer_create(1));
-	ast_json_object_set(uut, "two", ast_json_integer_create(2));
-	ast_json_object_set(uut, "three", ast_json_integer_create(3));
-
-	merge = ast_json_object_create();
-	ast_json_object_set(merge, "three", ast_json_integer_create(-3));
-	ast_json_object_set(merge, "four", ast_json_integer_create(-4));
-	ast_json_object_set(merge, "five", ast_json_integer_create(-5));
-
-	expected = ast_json_object_create();
-	ast_json_object_set(expected, "one", ast_json_integer_create(1));
-	ast_json_object_set(expected, "two", ast_json_integer_create(2));
-	ast_json_object_set(expected, "three", ast_json_integer_create(3));
-	ast_json_object_set(expected, "four", ast_json_integer_create(-4));
-	ast_json_object_set(expected, "five", ast_json_integer_create(-5));
-
-	uut_res = ast_json_object_update_missing(uut, merge);
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	/* merge object is untouched */
-	ast_test_validate(test, 3 == ast_json_object_size(merge));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_null";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON object NULL behavior.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Object NULL testing */
-	ast_test_validate(test, 0 == ast_json_object_size(NULL));
-	ast_test_validate(test, NULL == ast_json_object_get(NULL, "not null"));
-	ast_test_validate(test, -1 == ast_json_object_set(NULL, "not null", ast_json_null()));
-	ast_test_validate(test, -1 == ast_json_object_del(NULL, "not null"));
-	ast_test_validate(test, -1 == ast_json_object_clear(NULL));
-	uut = ast_json_object_create();
-	ast_test_validate(test, -1 == ast_json_object_update(NULL, uut));
-	ast_test_validate(test, -1 == ast_json_object_update(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_object_update(NULL, NULL));
-	ast_test_validate(test, -1 == ast_json_object_update_existing(NULL, uut));
-	ast_test_validate(test, -1 == ast_json_object_update_existing(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_object_update_existing(NULL, NULL));
-	ast_test_validate(test, -1 == ast_json_object_update_missing(NULL, uut));
-	ast_test_validate(test, -1 == ast_json_object_update_missing(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_object_update_missing(NULL, NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_iter)
-{
-	struct ast_json_iter *iter;
-	int count;
-	int uut_res;
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_iter";
-		info->category = CATEGORY;
-		info->summary = "Testing iterating through JSON objects.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Object iterator testing */
-	uut = ast_json_pack("{s: i, s: i, s: i, s: i, s: i}", "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
-
-	/* Iterate through the object; be aware that order isn't specified */
-	iter = ast_json_object_iter(uut);
-	ast_test_validate(test, NULL != iter);
-	count = 0;
-	while (NULL != iter) {
-		if (0 == strcmp("one", ast_json_object_iter_key(iter))) {
-			ast_test_validate(test, 1 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-		} else if (0 == strcmp("two", ast_json_object_iter_key(iter))) {
-			ast_test_validate(test, 2 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-		} else if (0 == strcmp("three", ast_json_object_iter_key(iter))) {
-			ast_test_validate(test, 3 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-		} else if (0 == strcmp("four", ast_json_object_iter_key(iter))) {
-			ast_test_validate(test, 4 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-		} else if (0 == strcmp("five", ast_json_object_iter_key(iter))) {
-			ast_test_validate(test, 5 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-		} else {
-			/* Unexpected key */
-			ast_test_validate(test, 0);
-		}
-		iter = ast_json_object_iter_next(uut, iter);
-		++count;
-	}
-	ast_test_validate(test, 5 == count);
-
-	/* iterator non-existing key */
-	iter = ast_json_object_iter_at(uut, "dne");
-	ast_test_validate(test, NULL == iter);
-
-	/* iterator specific key */
-	iter = ast_json_object_iter_at(uut, "three");
-	ast_test_validate(test, NULL != iter);
-	ast_test_validate(test, 3 == ast_json_integer_get(ast_json_object_iter_value(iter)));
-
-	/* set via iter */
-	iter = ast_json_object_iter_at(uut, "three");
-	uut_res = ast_json_object_iter_set(uut, iter, ast_json_integer_create(-3));
-	ast_test_validate(test, 0 == uut_res);
-	ast_test_validate(test, -3 == ast_json_integer_get(ast_json_object_get(uut, "three")));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_object_iter_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_iter_null";
-		info->category = CATEGORY;
-		info->summary = "Testing JSON object iterator NULL testings.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* iterator NULL tests */
-	uut = ast_json_object_create();
-	ast_test_validate(test, NULL == ast_json_object_iter(NULL));
-	ast_test_validate(test, NULL == ast_json_object_iter_at(NULL, "not null"));
-	ast_test_validate(test, NULL == ast_json_object_iter_next(NULL, NULL));
-	ast_test_validate(test, NULL == ast_json_object_iter_next(uut, NULL));
-	ast_test_validate(test, NULL == ast_json_object_iter_key(NULL));
-	ast_test_validate(test, NULL == ast_json_object_iter_value(NULL));
-	ast_test_validate(test, -1 == ast_json_object_iter_set(NULL, NULL, ast_json_null()));
-	ast_test_validate(test, -1 == ast_json_object_iter_set(uut, NULL, ast_json_null()));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_dump_load_string)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(char *, str, NULL, json_debug_free);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_load_string";
-		info->category = CATEGORY;
-		info->summary = "Testing dumping strings from JSON.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	expected = ast_json_pack("{ s: i }", "one", 1);
-	str = ast_json_dump_string(expected);
-	ast_test_validate(test, NULL != str);
-	uut = ast_json_load_string(str, NULL);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	/* dump_string NULL */
-	ast_test_validate(test, NULL == ast_json_dump_string(NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_dump_load_str)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(struct ast_str *, astr, NULL, ast_free);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_load_str";
-		info->category = CATEGORY;
-		info->summary = "Testing dumping ast_str from JSON.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* dump/load ast_str */
-	expected = ast_json_pack("{ s: i }", "one", 1);
-	astr = ast_str_create(1); /* should expand to hold output */
-	uut_res = ast_json_dump_str(expected, &astr);
-	ast_test_validate(test, 0 == uut_res);
-	uut = ast_json_load_str(astr, NULL);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_dump_str_fail)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct ast_str *astr;
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_str_fail";
-		info->category = CATEGORY;
-		info->summary = "Testing dumping to ast_str when it can't grow.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* dump ast_str growth failure */
-	expected = ast_json_pack("{ s: i }", "one", 1);
-	astr = ast_str_alloca(1); /* cannot grow */
-	uut_res = ast_json_dump_str(expected, &astr);
-	ast_test_validate(test, 0 != uut_res);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_load_buffer)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	const char *str;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "load_buffer";
-		info->category = CATEGORY;
-		info->summary = "Testing loading JSON from buffer.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* load buffer */
-	str = "{ \"one\": 1 } trailing garbage";
-	uut = ast_json_load_string(str, NULL);
-	ast_test_validate(test, NULL == uut);
-	uut = ast_json_load_buf(str, strlen("{ \"one\": 1 }"), NULL);
-	ast_test_validate(test, NULL != uut);
-
-	return AST_TEST_PASS;
-}
-
-/*! \brief \a fclose isn't NULL safe. */
-static int safe_fclose(FILE *f)
-{
-	if (f) {
-		return fclose(f);
-	}
-	return 0;
-}
-
-static FILE *mkstemp_file(char *template, const char *mode)
-{
-	int fd = mkstemp(template);
-	FILE *file;
-
-	if (fd < 0) {
-		ast_log(LOG_ERROR, "Failed to create temp file: %s\n",
-			strerror(errno));
-		return NULL;
-	}
-
-	file = fdopen(fd, mode);
-	if (!file) {
-		ast_log(LOG_ERROR, "Failed to create temp file: %s\n",
-			strerror(errno));
-		return NULL;
-	}
-
-	return file;
-}
-
-AST_TEST_DEFINE(json_test_dump_load_file)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	char filename[] = "/tmp/ast_json.XXXXXX";
-	RAII_VAR(char *, rm_on_exit, filename, unlink);
-	RAII_VAR(FILE *, file, NULL, safe_fclose);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_load_file";
-		info->category = CATEGORY;
-		info->summary = "Testing dumping/loading JSON to/from file by FILE *.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* dump/load file */
-	expected = ast_json_pack("{ s: i }", "one", 1);
-	file = mkstemp_file(filename, "w");
-	ast_test_validate(test, NULL != file);
-	uut_res = ast_json_dump_file(expected, file);
-	ast_test_validate(test, 0 == uut_res);
-	fclose(file);
-	file = fopen(filename, "r");
-	ast_test_validate(test, NULL != file);
-	uut = ast_json_load_file(file, NULL);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_dump_load_new_file)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	char filename[] = "/tmp/ast_json.XXXXXX";
-	RAII_VAR(char *, rm_on_exit, filename, unlink);
-	RAII_VAR(FILE *, file, NULL, safe_fclose);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_load_new_file";
-		info->category = CATEGORY;
-		info->summary = "Testing dumping/load JSON to/from file by filename.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* dump/load filename */
-	expected = ast_json_pack("{ s: i }", "one", 1);
-	file = mkstemp_file(filename, "w");
-	ast_test_validate(test, NULL != file);
-	uut_res = ast_json_dump_new_file(expected, filename);
-	ast_test_validate(test, 0 == uut_res);
-	uut = ast_json_load_new_file(filename, NULL);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_dump_load_null)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	char filename[] = "/tmp/ast_json.XXXXXX";
-	RAII_VAR(char *, rm_on_exit, filename, unlink);
-	RAII_VAR(FILE *, file, NULL, safe_fclose);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dump_load_null";
-		info->category = CATEGORY;
-		info->summary = "Testing NULL handling of dump/load functions.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* dump/load NULL tests */
-	uut = ast_json_load_string("{ \"one\": 1 }", NULL);
-	ast_test_validate(test, NULL != uut);
-	file = mkstemp_file(filename, "w");
-	ast_test_validate(test, NULL != file);
-	ast_test_validate(test, NULL == ast_json_dump_string(NULL));
-	ast_test_validate(test, -1 == ast_json_dump_file(NULL, file));
-	ast_test_validate(test, -1 == ast_json_dump_file(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_dump_file(NULL, NULL));
-	ast_test_validate(test, -1 == ast_json_dump_new_file(uut, NULL));
-	ast_test_validate(test, -1 == ast_json_dump_new_file(NULL, filename));
-	ast_test_validate(test, -1 == ast_json_dump_new_file(NULL, NULL));
-	ast_test_validate(test, NULL == ast_json_load_string(NULL, NULL));
-	ast_test_validate(test, NULL == ast_json_load_buf(NULL, 0, NULL));
-	ast_test_validate(test, NULL == ast_json_load_file(NULL, NULL));
-	ast_test_validate(test, NULL == ast_json_load_new_file(NULL, NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_parse_errors)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "parse_errors";
-		info->category = CATEGORY;
-		info->summary = "Testing various parse errors.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* parse errors */
-	ast_test_validate(test, NULL == ast_json_load_string("'singleton'", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("{ no value }", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("{ 'no': 'curly' ", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("[ 'no', 'square'", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("{ 1: 'int key' }", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("{ 'missing' 'colon' }", NULL));
-	ast_test_validate(test, NULL == ast_json_load_string("[ 'missing' 'comma' ]", NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_pack)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "pack";
-		info->category = CATEGORY;
-		info->summary = "Testing json_pack function.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* pack test */
-	expected = ast_json_array_create();
-	ast_json_array_append(expected, ast_json_array_create());
-	ast_json_array_append(expected, ast_json_object_create());
-	ast_json_array_append(ast_json_array_get(expected, 0), ast_json_integer_create(1));
-	ast_json_array_append(ast_json_array_get(expected, 0), ast_json_integer_create(2));
-	ast_json_object_set(ast_json_array_get(expected, 1), "cool", ast_json_true());
-	uut = ast_json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_pack_ownership)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "pack_ownership";
-		info->category = CATEGORY;
-		info->summary = "Testing json_pack failure conditions.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_pack("[o]", ast_json_string_create("Am I freed?"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_pack_errors)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc";
-		info->category = CATEGORY;
-		info->summary = "Testing json_pack failure conditions.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* pack errors */
-	ast_test_validate(test, NULL == ast_json_pack(NULL));
-	ast_test_validate(test, NULL == ast_json_pack("{s:i", "no curly", 911));
-	ast_test_validate(test, NULL == ast_json_pack("[s, s", "no", "square"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_copy)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "copy";
-		info->category = CATEGORY;
-		info->summary = "Testing copying JSON.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* copy test */
-	expected = ast_json_pack("{s: {s: i}}", "outer", "inner", 8675309);
-	uut = ast_json_copy(expected);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	ast_test_validate(test, ast_json_object_get(expected, "outer") == ast_json_object_get(uut, "outer"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_deep_copy)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "deep_copy";
-		info->category = CATEGORY;
-		info->summary = "Testing deep copying of JSON.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* deep copy test */
-	expected = ast_json_pack("{s: {s: i}}", "outer", "inner", 8675309);
-	uut = ast_json_deep_copy(expected);
-	ast_test_validate(test, NULL != uut);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-	ast_test_validate(test, ast_json_object_get(expected, "outer") != ast_json_object_get(uut, "outer"));
-	/* Changing the inner value of one should not change the other */
-	ast_json_integer_set(ast_json_object_get(ast_json_object_get(uut, "outer"), "inner"), 411);
-	ast_test_validate(test, !ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_copy_null)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "copy_null";
-		info->category = CATEGORY;
-		info->summary = "Testing NULL handling of copy functions.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* copy NULL */
-	ast_test_validate(test, NULL == ast_json_copy(NULL));
-	ast_test_validate(test, NULL == ast_json_deep_copy(NULL));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_circular_object)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "circular_object";
-		info->category = CATEGORY;
-		info->summary = "Object cannot be added to itself.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* circular reference testing */
-	/* Cannot add self */
-	uut = ast_json_object_create();
-	uut_res = ast_json_object_set(uut, "myself", ast_json_ref(uut));
-	ast_test_validate(test, -1 == uut_res);
-	ast_test_validate(test, 0 == ast_json_object_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_circular_array)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "circular_array";
-		info->category = CATEGORY;
-		info->summary = "Array cannot be added to itself.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_json_array_create();
-	ast_test_validate(test, 0 == ast_json_array_size(uut));
-	uut_res = ast_json_array_append(uut, ast_json_ref(uut));
-	ast_test_validate(test, -1 == uut_res);
-	ast_test_validate(test, 0 == ast_json_array_size(uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_clever_circle)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, inner_child, NULL, ast_json_unref);
-	RAII_VAR(char *, str, NULL, json_debug_free);
-	int uut_res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "clever_circle";
-		info->category = CATEGORY;
-		info->summary = "JSON with circular references cannot be encoded.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* can add to self if you're clever enough, but it should not encode */
-	uut = ast_json_object_create();
-	inner_child = ast_json_object_create();
-	uut_res = ast_json_object_set(uut, "inner_child", ast_json_ref(inner_child));   /* incref to keep a reference */
-	ast_test_validate(test, 0 == uut_res);
-	uut_res = ast_json_object_set(inner_child, "parent", ast_json_ref(uut));   /* incref to keep a reference */
-	ast_test_validate(test, 0 == uut_res);
-	str = ast_json_dump_string(uut);
-	ast_test_validate(test, NULL == str);
-	/* Circular refs screw up reference counting, so break the cycle */
-	ast_json_object_clear(inner_child);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_name_number)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "name_number";
-		info->category = CATEGORY;
-		info->summary = "JSON encoding of name/number pair.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, NULL == ast_json_name_number("name", NULL));
-	ast_test_validate(test, NULL == ast_json_name_number(NULL, "1234"));
-	ast_test_validate(test, NULL == ast_json_name_number(NULL, NULL));
-
-	expected = ast_json_pack("{s: s, s: s}",
-				 "name", "Jenny",
-				 "number", "867-5309");
-	uut = ast_json_name_number("Jenny", "867-5309");
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_timeval)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	struct timeval tv = {};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "timeval";
-		info->category = CATEGORY;
-		info->summary = "JSON encoding of timevals.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	expected = ast_json_string_create("2013-02-07T09:32:34.314-0600");
-
-	tv.tv_sec = 1360251154;
-	tv.tv_usec = 314159;
-	uut = ast_json_timeval(tv, "America/Chicago");
-
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(json_test_cep)
-{
-	RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "cep";
-		info->category = CATEGORY;
-		info->summary = "JSON with circular references cannot be encoded.";
-		info->description = "Test JSON abstraction library.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	expected = ast_json_pack("{s: o, s: o, s: o}",
-				 "context", ast_json_null(),
-				 "exten", ast_json_null(),
-				 "priority", ast_json_null());
-	uut = ast_json_dialplan_cep(NULL, NULL, -1);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	ast_json_unref(expected);
-	ast_json_unref(uut);
-	expected = ast_json_pack("{s: s, s: s, s: i}",
-				 "context", "main",
-				 "exten", "4321",
-				 "priority", 7);
-	uut = ast_json_dialplan_cep("main", "4321", 7);
-	ast_test_validate(test, ast_json_equal(expected, uut));
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(json_test_false);
-	AST_TEST_UNREGISTER(json_test_true);
-	AST_TEST_UNREGISTER(json_test_bool0);
-	AST_TEST_UNREGISTER(json_test_bool1);
-	AST_TEST_UNREGISTER(json_test_null);
-	AST_TEST_UNREGISTER(json_test_null_val);
-	AST_TEST_UNREGISTER(json_test_string);
-	AST_TEST_UNREGISTER(json_test_string_null);
-	AST_TEST_UNREGISTER(json_test_stringf);
-	AST_TEST_UNREGISTER(json_test_int);
-	AST_TEST_UNREGISTER(json_test_non_int);
-	AST_TEST_UNREGISTER(json_test_array_create);
-	AST_TEST_UNREGISTER(json_test_array_append);
-	AST_TEST_UNREGISTER(json_test_array_inset);
-	AST_TEST_UNREGISTER(json_test_array_set);
-	AST_TEST_UNREGISTER(json_test_array_remove);
-	AST_TEST_UNREGISTER(json_test_array_clear);
-	AST_TEST_UNREGISTER(json_test_array_extend);
-	AST_TEST_UNREGISTER(json_test_array_null);
-	AST_TEST_UNREGISTER(json_test_object_alloc);
-	AST_TEST_UNREGISTER(json_test_object_set);
-	AST_TEST_UNREGISTER(json_test_object_set_overwrite);
-	AST_TEST_UNREGISTER(json_test_object_get);
-	AST_TEST_UNREGISTER(json_test_object_del);
-	AST_TEST_UNREGISTER(json_test_object_clear);
-	AST_TEST_UNREGISTER(json_test_object_merge_all);
-	AST_TEST_UNREGISTER(json_test_object_merge_existing);
-	AST_TEST_UNREGISTER(json_test_object_merge_missing);
-	AST_TEST_UNREGISTER(json_test_object_null);
-	AST_TEST_UNREGISTER(json_test_object_iter);
-	AST_TEST_UNREGISTER(json_test_object_iter_null);
-	AST_TEST_UNREGISTER(json_test_dump_load_string);
-	AST_TEST_UNREGISTER(json_test_dump_load_str);
-	AST_TEST_UNREGISTER(json_test_dump_str_fail);
-	AST_TEST_UNREGISTER(json_test_load_buffer);
-	AST_TEST_UNREGISTER(json_test_dump_load_file);
-	AST_TEST_UNREGISTER(json_test_dump_load_new_file);
-	AST_TEST_UNREGISTER(json_test_dump_load_null);
-	AST_TEST_UNREGISTER(json_test_parse_errors);
-	AST_TEST_UNREGISTER(json_test_pack);
-	AST_TEST_UNREGISTER(json_test_pack_ownership);
-	AST_TEST_UNREGISTER(json_test_pack_errors);
-	AST_TEST_UNREGISTER(json_test_copy);
-	AST_TEST_UNREGISTER(json_test_deep_copy);
-	AST_TEST_UNREGISTER(json_test_copy_null);
-	AST_TEST_UNREGISTER(json_test_circular_object);
-	AST_TEST_UNREGISTER(json_test_circular_array);
-	AST_TEST_UNREGISTER(json_test_clever_circle);
-	AST_TEST_UNREGISTER(json_test_name_number);
-	AST_TEST_UNREGISTER(json_test_timeval);
-	AST_TEST_UNREGISTER(json_test_cep);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(json_test_false);
-	AST_TEST_REGISTER(json_test_true);
-	AST_TEST_REGISTER(json_test_bool0);
-	AST_TEST_REGISTER(json_test_bool1);
-	AST_TEST_REGISTER(json_test_null);
-	AST_TEST_REGISTER(json_test_null_val);
-	AST_TEST_REGISTER(json_test_string);
-	AST_TEST_REGISTER(json_test_string_null);
-	AST_TEST_REGISTER(json_test_stringf);
-	AST_TEST_REGISTER(json_test_int);
-	AST_TEST_REGISTER(json_test_non_int);
-	AST_TEST_REGISTER(json_test_array_create);
-	AST_TEST_REGISTER(json_test_array_append);
-	AST_TEST_REGISTER(json_test_array_inset);
-	AST_TEST_REGISTER(json_test_array_set);
-	AST_TEST_REGISTER(json_test_array_remove);
-	AST_TEST_REGISTER(json_test_array_clear);
-	AST_TEST_REGISTER(json_test_array_extend);
-	AST_TEST_REGISTER(json_test_array_null);
-	AST_TEST_REGISTER(json_test_object_alloc);
-	AST_TEST_REGISTER(json_test_object_set);
-	AST_TEST_REGISTER(json_test_object_set_overwrite);
-	AST_TEST_REGISTER(json_test_object_get);
-	AST_TEST_REGISTER(json_test_object_del);
-	AST_TEST_REGISTER(json_test_object_clear);
-	AST_TEST_REGISTER(json_test_object_merge_all);
-	AST_TEST_REGISTER(json_test_object_merge_existing);
-	AST_TEST_REGISTER(json_test_object_merge_missing);
-	AST_TEST_REGISTER(json_test_object_null);
-	AST_TEST_REGISTER(json_test_object_iter);
-	AST_TEST_REGISTER(json_test_object_iter_null);
-	AST_TEST_REGISTER(json_test_dump_load_string);
-	AST_TEST_REGISTER(json_test_dump_load_str);
-	AST_TEST_REGISTER(json_test_dump_str_fail);
-	AST_TEST_REGISTER(json_test_load_buffer);
-	AST_TEST_REGISTER(json_test_dump_load_file);
-	AST_TEST_REGISTER(json_test_dump_load_new_file);
-	AST_TEST_REGISTER(json_test_dump_load_null);
-	AST_TEST_REGISTER(json_test_parse_errors);
-	AST_TEST_REGISTER(json_test_pack);
-	AST_TEST_REGISTER(json_test_pack_ownership);
-	AST_TEST_REGISTER(json_test_pack_errors);
-	AST_TEST_REGISTER(json_test_copy);
-	AST_TEST_REGISTER(json_test_deep_copy);
-	AST_TEST_REGISTER(json_test_copy_null);
-	AST_TEST_REGISTER(json_test_circular_object);
-	AST_TEST_REGISTER(json_test_circular_array);
-	AST_TEST_REGISTER(json_test_clever_circle);
-	AST_TEST_REGISTER(json_test_name_number);
-	AST_TEST_REGISTER(json_test_timeval);
-	AST_TEST_REGISTER(json_test_cep);
-
-	ast_test_register_init(CATEGORY, json_test_init);
-	ast_test_register_cleanup(CATEGORY, json_test_cleanup);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "JSON testing",
-		.load = load_module,
-		.unload = unload_module);
diff --git a/tests/test_linkedlists.c b/tests/test_linkedlists.c
index e8b5a85..9edab94 100644
--- a/tests/test_linkedlists.c
+++ b/tests/test_linkedlists.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 401793 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/test.h"
diff --git a/tests/test_locale.c b/tests/test_locale.c
index 4eb4bf1..de14a08 100644
--- a/tests/test_locale.c
+++ b/tests/test_locale.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385718 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <dirent.h>
diff --git a/tests/test_logger.c b/tests/test_logger.c
index e1afe9e..b0df4c6 100644
--- a/tests/test_logger.c
+++ b/tests/test_logger.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
diff --git a/tests/test_message.c b/tests/test_message.c
deleted file mode 100644
index 37aec88..0000000
--- a/tests/test_message.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Test module for out-of-call text message module
- *
- * \author \verbatim Matt Jordan <mjordan at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420098 $")
-
-#include <regex.h>
-
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/message.h"
-#include "asterisk/pbx.h"
-#include "asterisk/manager.h"
-#include "asterisk/vector.h"
-
-#define TEST_CATEGORY "/main/message/"
-
-#define TEST_CONTEXT "__TEST_MESSAGE_CONTEXT__"
-#define TEST_EXTENSION "test_message_extension"
-
-/*! \brief The number of user events we should get in a dialplan test */
-#define DEFAULT_EXPECTED_EVENTS 4
-
-static struct ast_context *test_message_context;
-
-/*! \brief The current number of received user events */
-static int received_user_events;
-
-/*! \brief The number of user events we expect for this test */
-static int expected_user_events;
-
-/*! \brief Predicate for the \ref test_message_handler receiving a message */
-static int handler_received_message;
-
-/*! \brief Condition wait variable for all dialplan user events being received */
-static ast_cond_t user_event_cond;
-
-/*! \brief Mutex for \c user_event_cond */
-AST_MUTEX_DEFINE_STATIC(user_event_lock);
-
-/*! \brief Condition wait variable for \ref test_msg_handler receiving message */
-static ast_cond_t handler_cond;
-
-/*! \brief Mutex for \c handler_cond */
-AST_MUTEX_DEFINE_STATIC(handler_lock);
-
-/*! \brief The expected user event fields */
-AST_VECTOR(var_vector, struct ast_variable *) expected_user_event_fields;
-
-/*! \brief If a user event fails, the bad headers that didn't match */
-AST_VECTOR(, struct ast_variable *) bad_headers;
-
-static int test_msg_send(const struct ast_msg *msg, const char *to, const char *from);
-
-static struct ast_msg_tech test_msg_tech = {
-	.name = "testmsg",
-	.msg_send = test_msg_send,
-};
-
-static int test_msg_handle_msg_cb(struct ast_msg *msg);
-static int test_msg_has_destination_cb(const struct ast_msg *msg);
-
-/*! \brief Our test message handler */
-static struct ast_msg_handler test_msg_handler = {
-	.name = "testmsg",
-	.handle_msg = test_msg_handle_msg_cb,
-	.has_destination = test_msg_has_destination_cb,
-};
-
-static int user_event_hook_cb(int category, const char *event, char *body);
-
-/*! \brief AMI event hook that verifies whether or not we've gotten our user events */
-static struct manager_custom_hook user_event_hook = {
-	.file = AST_MODULE,
-	.helper = user_event_hook_cb,
-};
-
-/*!
- * \brief Verifies a user event header/value pair
- *
- * \param user_event which user event to check
- * \param header The header to verify
- * \param value The value read from the event
- *
- * \retval -1 on error or evaluation failure
- * \retval 0 if match not needed or success
- */
-static int verify_user_event_fields(int user_event, const char *header, const char *value)
-{
-	struct ast_variable *current;
-	struct ast_variable *expected;
-	regex_t regexbuf;
-	int error;
-
-	if (user_event >= AST_VECTOR_SIZE(&expected_user_event_fields)) {
-		return -1;
-	}
-
-	expected = AST_VECTOR_GET(&expected_user_event_fields, user_event);
-	if (!expected) {
-		return -1;
-	}
-
-	for (current = expected; current; current = current->next) {
-		struct ast_variable *bad_header;
-
-		if (strcmp(current->name, header)) {
-			continue;
-		}
-
-		error = regcomp(&regexbuf, current->value, REG_EXTENDED | REG_NOSUB);
-		if (error) {
-			char error_buf[128];
-			regerror(error, &regexbuf, error_buf, sizeof(error_buf));
-			ast_log(LOG_ERROR, "Failed to compile regex '%s' for header check '%s': %s\n",
-				current->value, current->name, error_buf);
-			return -1;
-		}
-
-		if (!regexec(&regexbuf, value, 0, NULL, 0)) {
-			regfree(&regexbuf);
-			return 0;
-		}
-
-		bad_header = ast_variable_new(header, value, __FILE__);
-		if (bad_header) {
-			struct ast_variable *bad_headers_head = NULL;
-
-			if (user_event < AST_VECTOR_SIZE(&bad_headers)) {
-				bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event);
-			}
-			ast_variable_list_append(&bad_headers_head, bad_header);
-			AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head);
-		}
-		regfree(&regexbuf);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int message_received;
-
-static int test_msg_send(const struct ast_msg *msg, const char *to, const char *from)
-{
-	message_received = 1;
-
-	return 0;
-}
-
-static int test_msg_handle_msg_cb(struct ast_msg *msg)
-{
-	ast_mutex_lock(&handler_lock);
-	handler_received_message = 1;
-	ast_cond_signal(&handler_cond);
-	ast_mutex_unlock(&handler_lock);
-
-	return 0;
-}
-
-static int test_msg_has_destination_cb(const struct ast_msg *msg)
-{
-	/* We only care about one destination: foo! */
-	if (ast_strlen_zero(ast_msg_get_to(msg))) {
-		return 0;
-	}
-	return (!strcmp(ast_msg_get_to(msg), "foo") ? 1 : 0);
-}
-
-static int user_event_hook_cb(int category, const char *event, char *body)
-{
-	char *parse;
-	char *kvp;
-
-	if (strcmp(event, "UserEvent")) {
-		return -1;
-	}
-
-	parse = ast_strdupa(body);
-	while ((kvp = strsep(&parse, "\r\n"))) {
-		char *key, *value;
-
-		kvp = ast_trim_blanks(kvp);
-		if (ast_strlen_zero(kvp)) {
-			continue;
-		}
-		key = strsep(&kvp, ":");
-		value = ast_skip_blanks(kvp);
-		verify_user_event_fields(received_user_events, key, value);
-	}
-
-	received_user_events++;
-
-	ast_mutex_lock(&user_event_lock);
-	if (received_user_events == expected_user_events) {
-		ast_cond_signal(&user_event_cond);
-	}
-	ast_mutex_unlock(&user_event_lock);
-
-	return 0;
-}
-
-/*! \brief Wait for the \ref test_msg_handler to receive the message */
-static int handler_wait_for_message(struct ast_test *test)
-{
-	int error = 0;
-	struct timeval wait_now = ast_tvnow();
-	struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
-
-	ast_mutex_lock(&handler_lock);
-	while (!handler_received_message) {
-		error = ast_cond_timedwait(&handler_cond, &handler_lock, &wait_time);
-		if (error == ETIMEDOUT) {
-			ast_test_status_update(test, "Test timed out while waiting for handler to get message\n");
-			ast_test_set_result(test, AST_TEST_FAIL);
-			break;
-		}
-	}
-	ast_mutex_unlock(&handler_lock);
-
-	return (error != ETIMEDOUT);
-}
-
-/*! \brief Wait for the expected number of user events to be received */
-static int user_event_wait_for_events(struct ast_test *test, int expected_events)
-{
-	int error;
-	struct timeval wait_now = ast_tvnow();
-	struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 };
-
-	expected_user_events = expected_events;
-
-	ast_mutex_lock(&user_event_lock);
-	while (received_user_events != expected_user_events) {
-		error = ast_cond_timedwait(&user_event_cond, &user_event_lock, &wait_time);
-		if (error == ETIMEDOUT) {
-			ast_test_status_update(test, "Test timed out while waiting for %d expected user events\n", expected_events);
-			ast_test_set_result(test, AST_TEST_FAIL);
-			break;
-		}
-	}
-	ast_mutex_unlock(&user_event_lock);
-
-	ast_test_status_update(test, "Received %d of %d user events\n", received_user_events, expected_events);
-	return !(received_user_events == expected_events);
-}
-
-static int verify_bad_headers(struct ast_test *test)
-{
-	int res = 0;
-	int i;
-
-	for (i = 0; i < AST_VECTOR_SIZE(&bad_headers); i++) {
-		struct ast_variable *headers;
-		struct ast_variable *current;
-
-		headers = AST_VECTOR_GET(&bad_headers, i);
-		if (!headers) {
-			continue;
-		}
-
-		res = -1;
-		for (current = headers; current; current = current->next) {
-			ast_test_status_update(test, "Expected UserEvent %d: Failed to match %s: %s\n",
-				i, current->name, current->value);
-			ast_test_set_result(test, AST_TEST_FAIL);
-		}
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(test_message_msg_tech_registration)
-{
-	int reg_result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test register/unregister of a message tech";
-		info->description =
-			"Test that:\n"
-			"\tA message technology can be registered once only\n"
-			"\tA registered message technology can be unregistered once only\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	reg_result = ast_msg_tech_register(&test_msg_tech);
-	ast_test_validate(test, reg_result == 0);
-
-	reg_result = ast_msg_tech_register(&test_msg_tech);
-	ast_test_validate(test, reg_result == -1);
-
-	reg_result = ast_msg_tech_unregister(&test_msg_tech);
-	ast_test_validate(test, reg_result == 0);
-
-	reg_result = ast_msg_tech_unregister(&test_msg_tech);
-	ast_test_validate(test, reg_result == -1);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_msg_handler_registration)
-{
-	int reg_result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test register/unregister of a message handler";
-		info->description =
-			"Test that:\n"
-			"\tA message handler can be registered once only\n"
-			"\tA registered message handler can be unregistered once only\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	reg_result = ast_msg_handler_register(&test_msg_handler);
-	ast_test_validate(test, reg_result == 0);
-
-	reg_result = ast_msg_handler_register(&test_msg_handler);
-	ast_test_validate(test, reg_result == -1);
-
-	reg_result = ast_msg_handler_unregister(&test_msg_handler);
-	ast_test_validate(test, reg_result == 0);
-
-	reg_result = ast_msg_handler_unregister(&test_msg_handler);
-	ast_test_validate(test, reg_result == -1);
-
-	return AST_TEST_PASS;
-}
-
-static void ast_msg_safe_destroy(void *obj)
-{
-	struct ast_msg *msg = obj;
-
-	if (msg) {
-		ast_msg_destroy(msg);
-	}
-}
-
-AST_TEST_DEFINE(test_message_manipulation)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-	RAII_VAR(struct ast_msg_var_iterator *, it_vars, NULL, ast_msg_var_iterator_destroy);
-	int result;
-	const char *actual;
-	const char *out_name;
-	const char *out_value;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test manipulating properties of a message";
-		info->description =
-			"This test covers the following:\n"
-			"\tSetting/getting the body\n"
-			"\tSetting/getting inbound/outbound variables\n"
-			"\tIterating over variables\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	/* Test setting/getting to */
-	result = ast_msg_set_to(msg, "testmsg:%s", "foo");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_to(msg);
-	ast_test_validate(test, !strcmp(actual, "testmsg:foo"));
-
-	/* Test setting/getting from */
-	result = ast_msg_set_from(msg, "testmsg:%s", "bar");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_from(msg);
-	ast_test_validate(test, !strcmp(actual, "testmsg:bar"));
-
-	/* Test setting/getting body */
-	result = ast_msg_set_body(msg, "BodyTest: %s", "foo");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_body(msg);
-	ast_test_validate(test, !strcmp(actual, "BodyTest: foo"));
-
-	/* Test setting/getting technology */
-	result = ast_msg_set_tech(msg, "%s", "my_tech");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_tech(msg);
-	ast_test_validate(test, !strcmp(actual, "my_tech"));
-
-	/* Test setting/getting endpoint */
-	result = ast_msg_set_endpoint(msg, "%s", "terminus");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_endpoint(msg);
-	ast_test_validate(test, !strcmp(actual, "terminus"));
-
-	/* Test setting/getting non-outbound variable */
-	result = ast_msg_set_var(msg, "foo", "bar");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_var(msg, "foo");
-	ast_test_validate(test, !strcmp(actual, "bar"));
-
-	/* Test updating existing variable */
-	result = ast_msg_set_var(msg, "foo", "new_bar");
-	ast_test_validate(test, result == 0);
-	actual = ast_msg_get_var(msg, "foo");
-	ast_test_validate(test, !strcmp(actual, "new_bar"));
-
-	/* Verify a non-outbound variable is not iterable */
-	it_vars = ast_msg_var_iterator_init(msg);
-	ast_test_validate(test, it_vars != NULL);
-	ast_test_validate(test, ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value) == 0);
-	ast_msg_var_iterator_destroy(it_vars);
-
-	/* Test updating an existing variable as an outbound variable */
-	result = ast_msg_set_var_outbound(msg, "foo", "outbound_bar");
-	ast_test_validate(test, result == 0);
-	it_vars = ast_msg_var_iterator_init(msg);
-	ast_test_validate(test, it_vars != NULL);
-	result = ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value);
-	ast_test_validate(test, result == 1);
-	ast_test_validate(test, !strcmp(out_name, "foo"));
-	ast_test_validate(test, !strcmp(out_value, "outbound_bar"));
-	ast_msg_var_unref_current(it_vars);
-	result = ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value);
-	ast_test_validate(test, result == 0);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_queue_dialplan_nominal)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-	struct ast_variable *expected;
-	struct ast_variable *expected_response = NULL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test enqueueing messages to the dialplan";
-		info->description =
-			"Test that a message enqueued for the dialplan is\n"
-			"passed to that particular extension\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	expected = ast_variable_new("Verify","^To$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value","^foo$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response);
-
-	expected_response = NULL;
-	expected = ast_variable_new("Verify", "^From$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value","^bar$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response);
-
-	expected_response = NULL;
-	expected = ast_variable_new("Verify", "^Body$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value", "^a body$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response);
-
-	expected_response = NULL;
-	expected = ast_variable_new("Verify", "^Custom$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value", "^field$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 3, expected_response);
-
-	ast_msg_set_to(msg, "foo");
-	ast_msg_set_from(msg, "bar");
-	ast_msg_set_body(msg, "a body");
-	ast_msg_set_var_outbound(msg, "custom_data", "field");
-
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, TEST_EXTENSION);
-
-	ast_msg_queue(msg);
-	msg = NULL;
-
-	if (user_event_wait_for_events(test, DEFAULT_EXPECTED_EVENTS)) {
-		ast_test_status_update(test, "Failed to received %d expected user events\n", DEFAULT_EXPECTED_EVENTS);
-		return AST_TEST_FAIL;
-	}
-
-	if (verify_bad_headers(test)) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_queue_handler_nominal)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-	int result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test enqueueing messages to a handler";
-		info->description =
-			"Test that a message enqueued can be handled by a\n"
-			"non-dialplan handler\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	result = ast_msg_handler_register(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	ast_msg_set_to(msg, "foo");
-	ast_msg_set_from(msg, "bar");
-	ast_msg_set_body(msg, "a body");
-
-	ast_msg_queue(msg);
-	msg = NULL;
-
-	/* This will automatically fail the test if we don't get the message */
-	handler_wait_for_message(test);
-
-	result = ast_msg_handler_unregister(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_queue_both_nominal)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-	struct ast_variable *expected;
-	struct ast_variable *expected_response = NULL;
-	int result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test enqueueing messages to a dialplan and custom handler";
-		info->description =
-			"Test that a message enqueued is passed to all\n"
-			"handlers that can process it, dialplan as well as\n"
-			"a custom handler\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	result = ast_msg_handler_register(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	expected = ast_variable_new("Verify","^To$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value","^foo$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 0, expected_response);
-
-	expected_response = NULL;
-	expected = ast_variable_new("Verify", "^From$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value","^bar$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 1, expected_response);
-
-	expected_response = NULL;
-	expected = ast_variable_new("Verify", "^Body$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	expected = ast_variable_new("Value", "^a body$", __FILE__);
-	ast_variable_list_append(&expected_response, expected);
-	AST_VECTOR_INSERT(&expected_user_event_fields, 2, expected_response);
-
-	ast_msg_set_to(msg, "foo");
-	ast_msg_set_from(msg, "bar");
-	ast_msg_set_body(msg, "a body");
-
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, TEST_EXTENSION);
-
-	ast_msg_queue(msg);
-	msg = NULL;
-
-	if (user_event_wait_for_events(test, DEFAULT_EXPECTED_EVENTS)) {
-		ast_test_status_update(test, "Failed to received %d expected user events\n", DEFAULT_EXPECTED_EVENTS);
-		ast_test_set_result(test, AST_TEST_FAIL);
-	}
-
-	/* This will automatically fail the test if we don't get the message */
-	handler_wait_for_message(test);
-
-	result = ast_msg_handler_unregister(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	if (verify_bad_headers(test)) {
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_has_destination_dialplan)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test checking for a dialplan destination";
-		info->description =
-			"Test that a message's destination is verified via the\n"
-			"dialplan\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, TEST_EXTENSION);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 1);
-
-	ast_msg_set_context(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
-	ast_test_validate(test, ast_msg_has_destination(msg) == 0);
-
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
-	ast_test_validate(test, ast_msg_has_destination(msg) == 0);
-
-	ast_msg_set_exten(msg, NULL);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 0);
-
-	ast_msg_set_context(msg, NULL);
-	ast_msg_set_exten(msg, TEST_EXTENSION);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 0);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_has_destination_handler)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-	int result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test checking for a handler destination";
-		info->description =
-			"Test that a message's destination is verified via a\n"
-			"handler\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	result = ast_msg_handler_register(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	ast_msg_set_to(msg, "foo");
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, NULL);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 1);
-
-	ast_msg_set_context(msg, NULL);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 1);
-
-	ast_msg_set_to(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
-	ast_test_validate(test, ast_msg_has_destination(msg) == 0);
-
-	result = ast_msg_handler_unregister(&test_msg_handler);
-	ast_test_validate(test, result == 0);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(test_message_msg_send)
-{
-	RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = TEST_CATEGORY;
-		info->summary = "Test message routing";
-		info->description =
-			"Test that a message can be routed if it has\n"
-			"a valid handler\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, ast_msg_tech_register(&test_msg_tech) == 0);
-	ast_test_validate(test, ast_msg_handler_register(&test_msg_handler) == 0);
-
-	msg = ast_msg_alloc();
-	ast_test_validate(test, msg != NULL);
-
-	ast_msg_set_to(msg, "foo");
-	ast_msg_set_context(msg, TEST_CONTEXT);
-	ast_msg_set_exten(msg, NULL);
-	ast_test_validate(test, ast_msg_has_destination(msg) == 1);
-
-	if (!ast_msg_send(msg, "testmsg:foo", "blah")) {
-		msg = NULL;
-	} else {
-		ast_test_status_update(test, "Failed to send message\n");
-		ast_test_set_result(test, AST_TEST_FAIL);
-	}
-
-	ast_test_validate(test, ast_msg_handler_unregister(&test_msg_handler) == 0);
-	ast_test_validate(test, ast_msg_tech_unregister(&test_msg_tech) == 0);
-
-	return AST_TEST_PASS;
-}
-
-static int test_init_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	received_user_events = 0;
-	handler_received_message = 0;
-	message_received = 0;
-
-	AST_VECTOR_INIT(&expected_user_event_fields, DEFAULT_EXPECTED_EVENTS);
-	AST_VECTOR_INIT(&bad_headers, DEFAULT_EXPECTED_EVENTS);
-
-	return 0;
-}
-
-#define FREE_VARIABLE_VECTOR(vector) do { \
-	int i; \
-	for (i = 0; i < AST_VECTOR_SIZE(&(vector)); i++) { \
-		struct ast_variable *headers; \
-		headers = AST_VECTOR_GET(&(vector), i); \
-		if (!headers) { \
-			continue; \
-		} \
-		ast_variables_destroy(headers); \
-	} \
-	AST_VECTOR_FREE(&(vector)); \
-	} while (0)
-
-
-static int test_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
-{
-	FREE_VARIABLE_VECTOR(expected_user_event_fields);
-	FREE_VARIABLE_VECTOR(bad_headers);
-
-	return 0;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(test_message_msg_tech_registration);
-	AST_TEST_UNREGISTER(test_message_msg_handler_registration);
-	AST_TEST_UNREGISTER(test_message_manipulation);
-	AST_TEST_UNREGISTER(test_message_queue_dialplan_nominal);
-	AST_TEST_UNREGISTER(test_message_queue_handler_nominal);
-	AST_TEST_UNREGISTER(test_message_queue_both_nominal);
-	AST_TEST_UNREGISTER(test_message_has_destination_dialplan);
-	AST_TEST_UNREGISTER(test_message_has_destination_handler);
-	AST_TEST_UNREGISTER(test_message_msg_send);
-
-	if (test_message_context) {
-		ast_context_destroy(test_message_context, AST_MODULE);
-	}
-
-	ast_manager_unregister_hook(&user_event_hook);
-
-	return 0;
-}
-
-static int create_test_dialplan(void)
-{
-	int res = 0;
-
-	test_message_context = ast_context_find_or_create(NULL, NULL, TEST_CONTEXT, AST_MODULE);
-	if (!test_message_context) {
-		return -1;
-	}
-
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 1, NULL, NULL,
-	                         "UserEvent", "TestMessageUnitTest,Verify:To,Value:${MESSAGE(to)}",
-	                         NULL, AST_MODULE);
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 2, NULL, NULL,
-	                         "UserEvent", "TestMessageUnitTest,Verify:From,Value:${MESSAGE(from)}",
-	                         NULL, AST_MODULE);
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 3, NULL, NULL,
-	                         "UserEvent", "TestMessageUnitTest,Verify:Body,Value:${MESSAGE(body)}",
-	                         NULL, AST_MODULE);
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 4, NULL, NULL,
-	                         "UserEvent", "TestMessageUnitTest,Verify:Custom,Value:${MESSAGE_DATA(custom_data)}",
-	                         NULL, AST_MODULE);
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 5, NULL, NULL,
-	                         "Set", "MESSAGE_DATA(custom_data)=${MESSAGE_DATA(custom_data)}",
-	                         NULL, AST_MODULE);
-	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 6, NULL, NULL,
-	                         "MessageSend", "testmsg:${MESSAGE(from)},testmsg:${MESSAGE(to)}",
-	                         NULL, AST_MODULE);
-
-	ast_manager_register_hook(&user_event_hook);
-
-	return res;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(test_message_msg_tech_registration);
-	AST_TEST_REGISTER(test_message_msg_handler_registration);
-	AST_TEST_REGISTER(test_message_manipulation);
-	AST_TEST_REGISTER(test_message_queue_dialplan_nominal);
-	AST_TEST_REGISTER(test_message_queue_handler_nominal);
-	AST_TEST_REGISTER(test_message_queue_both_nominal);
-	AST_TEST_REGISTER(test_message_has_destination_dialplan);
-	AST_TEST_REGISTER(test_message_has_destination_handler);
-	AST_TEST_REGISTER(test_message_msg_send);
-
-	create_test_dialplan();
-
-	ast_test_register_init(TEST_CATEGORY, test_init_cb);
-	ast_test_register_cleanup(TEST_CATEGORY, test_cleanup_cb);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Out-of-call text message support");
diff --git a/tests/test_optional_api.c b/tests/test_optional_api.c
deleted file mode 100644
index 243d57c..0000000
--- a/tests/test_optional_api.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test optional API.
- *
- * This tests exercise the underlying implementation functions. Acutal usage
- * won't look anything like this; it would use the wrapper macros.
- *
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>OPTIONAL_API</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
-
-#include "asterisk/module.h"
-#include "asterisk/optional_api.h"
-#include "asterisk/test.h"
-
-#define CATEGORY "/main/optional_api/"
-
-enum was_called {
-	NONE,
-	STUB,
-	IMPL
-};
-
-enum was_called was_called_result;
-
-ast_optional_fn test_optional_ref;
-
-static void test_optional_stub(void)
-{
-	was_called_result = STUB;
-}
-
-static void test_optional_impl(void)
-{
-	was_called_result = IMPL;
-}
-
-static void test_optional(void)
-{
-	was_called_result = NONE;
-	if (test_optional_ref) {
-		test_optional_ref();
-	}
-}
-
-#define SYMNAME "test_option"
-
-AST_TEST_DEFINE(test_provide_first)
-{
-	enum ast_test_result_state res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "Test optional API publishing.";
-		info->description = "Test optional API publishing.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	res = AST_TEST_FAIL;
-	test_optional_ref = 0;
-
-	ast_optional_api_provide(SYMNAME, test_optional_impl);
-
-	ast_optional_api_use(SYMNAME, &test_optional_ref, test_optional_stub,
-		AST_MODULE);
-
-	test_optional();
-
-	if (was_called_result != IMPL) {
-		ast_test_status_update(test, "Expected %d, was %u",
-			IMPL, was_called_result);
-		goto done;
-	}
-
-	res = AST_TEST_PASS;
-
- done:
-	ast_optional_api_unuse(SYMNAME, &test_optional_ref, AST_MODULE);
-	ast_optional_api_unprovide(SYMNAME, test_optional_impl);
-	return res;
-}
-
-AST_TEST_DEFINE(test_provide_last)
-{
-	enum ast_test_result_state res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "Test optional API publishing.";
-		info->description = "Test optional API publishing.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	res = AST_TEST_FAIL;
-	test_optional_ref = 0;
-
-	ast_optional_api_use(SYMNAME, &test_optional_ref, test_optional_stub,
-		AST_MODULE);
-
-	test_optional();
-	if (was_called_result != STUB) {
-		ast_test_status_update(test, "Expected %d, was %u",
-			STUB, was_called_result);
-		goto done;
-	}
-
-	ast_optional_api_provide(SYMNAME, test_optional_impl);
-
-	test_optional();
-	if (was_called_result != IMPL) {
-		ast_test_status_update(test, "Expected %d, was %u",
-			IMPL, was_called_result);
-		ast_optional_api_unprovide(SYMNAME, test_optional_impl);
-		goto done;
-	}
-
-	ast_optional_api_unprovide(SYMNAME, test_optional_impl);
-
-	test_optional();
-	if (was_called_result != STUB) {
-		ast_test_status_update(test, "Expected %d, was %u",
-			STUB, was_called_result);
-		ast_optional_api_unprovide(SYMNAME, test_optional_impl);
-		goto done;
-	}
-
-	res = AST_TEST_PASS;
-
- done:
-	ast_optional_api_unuse(SYMNAME, &test_optional_ref, AST_MODULE);
-	return res;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(test_provide_first);
-	AST_TEST_UNREGISTER(test_provide_last);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(test_provide_first);
-	AST_TEST_REGISTER(test_provide_last);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ARI testing",
-	.load = load_module,
-	.unload = unload_module,
-	);
diff --git a/tests/test_pbx.c b/tests/test_pbx.c
index 35329cf..bb5d8e8 100644
--- a/tests/test_pbx.c
+++ b/tests/test_pbx.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 337063 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
@@ -198,7 +198,6 @@ AST_TEST_DEFINE(pattern_match_test)
 	 */
 	struct {
 		const char * context_string;
-		struct ast_context *context;
 	} contexts[] = {
 		{ TEST_PATTERN, },
 		{ TEST_PATTERN_INCLUDE, },
@@ -267,7 +266,7 @@ AST_TEST_DEFINE(pattern_match_test)
 	 */
 
 	for (i = 0; i < ARRAY_LEN(contexts); ++i) {
-		if (!(contexts[i].context = ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar))) {
+		if (!ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar)) {
 			ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string);
 			res = AST_TEST_FAIL;
 			goto cleanup;
@@ -319,11 +318,7 @@ AST_TEST_DEFINE(pattern_match_test)
 	}
 
 cleanup:
-	for (i = 0; i < ARRAY_LEN(contexts); ++i) {
-		if (contexts[i].context) {
-			ast_context_destroy(contexts[i].context, registrar);
-		}
-	}
+	ast_context_destroy(NULL, registrar);
 
 	return res;
 }
diff --git a/tests/test_poll.c b/tests/test_poll.c
index b5e9aa2..755bb0f 100644
--- a/tests/test_poll.c
+++ b/tests/test_poll.c
@@ -39,7 +39,7 @@
 #include <errno.h>
 #include <unistd.h>
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385718 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/tests/test_res_stasis.c b/tests/test_res_stasis.c
deleted file mode 100644
index 9150558..0000000
--- a/tests/test_res_stasis.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test Stasis Application API.
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>res_stasis</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 393529 $")
-
-#include "asterisk/module.h"
-#include "asterisk/test.h"
-#include "asterisk/stasis_app.h"
-
-static const char *test_category = "/stasis/res/";
-
-AST_TEST_DEFINE(app_invoke_dne)
-{
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test stasis app invocation.";
-		info->description = "Test stasis app invocation.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	res = stasis_app_send("i-am-not-an-app", ast_json_null());
-	ast_test_validate(test, -1 == res);
-
-	return AST_TEST_PASS;
-}
-
-struct app_data {
-	int invocations;
-	struct ast_json *messages;
-};
-
-static void app_data_dtor(void *obj)
-{
-	struct app_data *actual = obj;
-
-	ast_json_unref(actual->messages);
-	actual->messages = NULL;
-}
-
-static struct app_data *app_data_create(void)
-{
-	struct app_data *res = ao2_alloc(sizeof(struct app_data), app_data_dtor);
-
-	if (!res) {
-		return NULL;
-	}
-
-	res->messages = ast_json_array_create();
-	return res;
-}
-
-static void test_handler(void *data, const char *app_name, struct ast_json *message)
-{
-	struct app_data *actual = data;
-	int res;
-	++(actual->invocations);
-	res = ast_json_array_append(actual->messages, ast_json_copy(message));
-	ast_assert(res == 0);
-}
-
-AST_TEST_DEFINE(app_invoke_one)
-{
-	RAII_VAR(struct app_data *, app_data, NULL, ao2_cleanup);
-	RAII_VAR(char *, app_name, NULL, stasis_app_unregister);
-	RAII_VAR(struct ast_json *, expected_message, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test stasis app invocation.";
-		info->description = "Test stasis app invocation.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	app_name = "test-handler";
-
-	app_data = app_data_create();
-
-	stasis_app_register(app_name, test_handler, app_data);
-	message = ast_json_pack("{ s: o }", "test-message", ast_json_null());
-	expected_message = ast_json_pack("[o]", ast_json_ref(message));
-
-	res = stasis_app_send(app_name, message);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, 1 == app_data->invocations);
-	ast_test_validate(test, ast_json_equal(expected_message, app_data->messages));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(app_replaced)
-{
-	RAII_VAR(struct app_data *, app_data1, NULL, ao2_cleanup);
-	RAII_VAR(struct app_data *, app_data2, NULL, ao2_cleanup);
-	RAII_VAR(char *, app_name, NULL, stasis_app_unregister);
-	RAII_VAR(struct ast_json *, expected_message1, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, expected_message2, NULL, ast_json_unref);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test stasis app invocation.";
-		info->description = "Test stasis app invocation.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	app_name = "test-handler";
-
-	app_data1 = app_data_create();
-	app_data2 = app_data_create();
-
-	stasis_app_register(app_name, test_handler, app_data1);
-	stasis_app_register(app_name, test_handler, app_data2);
-	expected_message1 = ast_json_pack("[{s: s, s: s}]",
-		"type", "ApplicationReplaced",
-		"application", app_name);
-	message = ast_json_pack("{ s: o }", "test-message", ast_json_null());
-	expected_message2 = ast_json_pack("[o]", ast_json_ref(message));
-
-	res = stasis_app_send(app_name, message);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, 1 == app_data1->invocations);
-	ast_test_validate(test, ast_json_equal(expected_message1, app_data1->messages));
-	ast_test_validate(test, 1 == app_data2->invocations);
-	ast_test_validate(test, ast_json_equal(expected_message2, app_data2->messages));
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(app_invoke_dne);
-	AST_TEST_UNREGISTER(app_invoke_one);
-	AST_TEST_UNREGISTER(app_replaced);
-	stasis_app_unref();
-	return 0;
-}
-
-static int load_module(void)
-{
-	stasis_app_ref();
-	AST_TEST_REGISTER(app_replaced);
-	AST_TEST_REGISTER(app_invoke_one);
-	AST_TEST_REGISTER(app_invoke_dne);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Stasis Core testing",
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis",
-	);
diff --git a/tests/test_sched.c b/tests/test_sched.c
index 5eccd64..5ad2f5d 100644
--- a/tests/test_sched.c
+++ b/tests/test_sched.c
@@ -32,7 +32,7 @@
 
 #include <inttypes.h>
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 332178 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
@@ -202,7 +202,7 @@ static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast
 	start = ast_tvnow();
 
 	for (i = 0; i < num; i++) {
-		int when = abs(ast_random()) % 60000;
+		long when = labs(ast_random()) % 60000;
 		if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) {
 			ast_cli(a->fd, "Test failed - sched_add returned -1\n");
 			goto return_cleanup;
diff --git a/tests/test_scoped_lock.c b/tests/test_scoped_lock.c
deleted file mode 100644
index 1881bce..0000000
--- a/tests/test_scoped_lock.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief SCOPED_LOCK unit tests
- *
- * \author Mark Michelson <mmichelson at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include "asterisk/test.h"
-#include "asterisk/utils.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-
-static int indicator;
-static struct ast_test *current_test;
-AST_MUTEX_DEFINE_STATIC(the_lock);
-
-static void lock_it(ast_mutex_t *lock)
-{
-	indicator = 1;
-	ast_mutex_lock(lock);
-}
-
-static void unlock_it(ast_mutex_t *lock)
-{
-	indicator = 0;
-	ast_mutex_unlock(lock);
-}
-
-AST_TEST_DEFINE(lock_test)
-{
-	enum ast_test_result_state res = AST_TEST_PASS;
-	int i;
-
-	switch(cmd) {
-	case TEST_INIT:
-		info->name = "lock_test";
-		info->category = "/main/lock/";
-		info->summary = "SCOPED_LOCK test";
-		info->description =
-			"Tests that scoped locks are scoped as they are expected to be";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	current_test = test;
-	indicator = 0;
-	{
-		SCOPED_LOCK(lock, &the_lock, lock_it, unlock_it);
-		if (indicator != 1) {
-			ast_log(LOG_ERROR, "The lock was not acquired via RAII");
-			res = AST_TEST_FAIL;
-		}
-	}
-	if (indicator != 0) {
-		ast_log(LOG_ERROR, "The lock was not released when the variable went out of scope");
-		res = AST_TEST_FAIL;
-	}
-
-	for (i = 0; i < 10; ++i) {
-		SCOPED_LOCK(lock, &the_lock, lock_it, unlock_it);
-		if (indicator != 1) {
-			ast_log(LOG_ERROR, "The lock was not acquired via RAII");
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	if (indicator != 0) {
-		ast_log(LOG_ERROR, "The lock was not released when the variable went out of scope");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-struct test_struct
-{
-	int locked;
-	int reffed;
-};
-
-/*!
- * \brief lock callback function
- *
- * Locks the object passed in. Only sets the locked
- * flag if the object is reffed. This allows us to check
- * that locking is always occurring after reffing.
- */
-static void test_lock(struct test_struct *test)
-{
-	ast_test_status_update(current_test, "Lock is occurring\n");
-	ao2_lock(test);
-	if (test->reffed) {
-		test->locked = 1;
-	}
-}
-
-/*!
- * \brief unlock callback function
- *
- * Unlocks the object passed in. Only clears the locked
- * flag if the object is still reffed. This allows us to
- * ensure that unlocking is always occurring before unreffing.
- */
-static void test_unlock(struct test_struct *test)
-{
-	ast_test_status_update(current_test, "Unlock is occurring\n");
-	ao2_unlock(test);
-	if (test->reffed) {
-		test->locked = 0;
-	}
-}
-
-/*!
- * \brief ref callback function
- *
- * Refs the object passed in. Only sets the reffed flag if
- * the object is not locked. This allows us to ensure that
- * reffing always occurs before locking.
- */
-static struct test_struct *test_ref(struct test_struct *test)
-{
-	ast_test_status_update(current_test, "Ref is occurring\n");
-	ao2_ref(test, +1);
-	if (!test->locked) {
-		test->reffed = 1;
-	}
-	return test;
-}
-
-/*!
- * \brief unref callback function
- *
- * Unrefs the object passed in. Only sets the unreffed flag if
- * the object is not locked. This allows us to ensure that
- * unreffing always occurs after unlocking.
- */
-static void test_unref(struct test_struct *test)
-{
-	ast_test_status_update(current_test, "Unref is occurring\n");
-	ao2_ref(test, -1);
-	if (!test->locked) {
-		test->reffed = 0;
-	}
-}
-
-/*!
- * \brief wrapper for ao2_iterator_next
- *
- * Grabs the next item in the container and replaces the ref acquired
- * from ao2_iterator_next() with a call to test_ref().
- */
-static struct test_struct *test_iterator_next(struct ao2_iterator *iter)
-{
-	struct test_struct *test = ao2_iterator_next(iter);
-
-	if (!test) {
-		return NULL;
-	}
-
-	/* Remove ref from ao2_iterator_next() and replace it with
-	 * a test_ref() call. The order here is safe since we can guarantee
-	 * the container still has a ref to the test structure.
-	 */
-	ao2_ref(test, -1);
-	test_ref(test);
-
-	return test;
-}
-
-AST_TEST_DEFINE(cleanup_order)
-{
-	enum ast_test_result_state res = AST_TEST_PASS;
-	struct ao2_iterator iter;
-	struct test_struct *object_iter;
-	RAII_VAR(struct ao2_container*, container, ao2_container_alloc(13, NULL, NULL), ao2_cleanup);
-	RAII_VAR(struct test_struct *, object, ao2_alloc(sizeof(*object), NULL), ao2_cleanup);
-
-	switch(cmd) {
-	case TEST_INIT:
-		info->name = "cleanup_order_test";
-		info->category = "/main/lock/";
-		info->summary = "cleanup order test";
-		info->description =
-			"Tests that variables with cleanup attributes are cleaned up\n"
-			"in the reverse order they are declared.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	current_test = test;
-
-	if (!object || !container) {
-		/* Allocation failure. We can't even pretend to do this test properly */
-		return AST_TEST_FAIL;
-	}
-
-	{
-		/* Purpose of this block is to make sure that the cleanup operations
-		 * run in the reverse order that they were created here.
-		 */
-		RAII_VAR(struct test_struct *, object2, test_ref(object), test_unref);
-		SCOPED_LOCK(lock, object, test_lock, test_unlock);
-		if (!object->reffed || !object->locked) {
-			ast_log(LOG_ERROR, "Test failed due to out of order initializations");
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	if (object->reffed || object->locked) {
-		ast_log(LOG_ERROR, "Test failed due to out of order cleanups\n");
-		res = AST_TEST_FAIL;
-	}
-
-	/* Now link the object into the container for a little experiment ... */
-	ao2_link(container, object);
-
-	/* This loop is to ensure that unrefs in a for loop occur after the cleanup
-	 * operations of items inside the loop. If we hope to be able to mix scoped locks
-	 * and ao2 refs, this is the way to go about it.
-	 */
-	for (iter = ao2_iterator_init(container, 0);
-			(object_iter = test_iterator_next(&iter));
-			test_unref(object_iter)) {
-		SCOPED_LOCK(lock, object_iter, test_lock, test_unlock);
-		if (!object->reffed || !object->locked) {
-			ast_log(LOG_ERROR, "Test failed due to out of order initializations");
-			res = AST_TEST_FAIL;
-		}
-	}
-	ao2_iterator_destroy(&iter);
-
-	if (object->reffed || object->locked) {
-		ast_log(LOG_ERROR, "Test failed due to out of order cleanups\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(lock_test);
-	AST_TEST_UNREGISTER(cleanup_order);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(lock_test);
-	AST_TEST_REGISTER(cleanup_order);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SCOPED_LOCK test module");
diff --git a/tests/test_security_events.c b/tests/test_security_events.c
index 59009de..4f2510f 100644
--- a/tests/test_security_events.c
+++ b/tests/test_security_events.c
@@ -30,7 +30,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 388975 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/cli.h"
@@ -89,11 +89,11 @@ static void evt_gen_failed_acl(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 
 		.acl_name   = "TEST_ACL",
@@ -127,11 +127,11 @@ static void evt_gen_inval_acct_id(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 	};
 
@@ -163,11 +163,11 @@ static void evt_gen_session_limit(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TLS,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TLS,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TLS,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TLS,
 		},
 	};
 
@@ -199,11 +199,11 @@ static void evt_gen_mem_limit(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 	};
 
@@ -235,11 +235,11 @@ static void evt_gen_load_avg(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 	};
 
@@ -271,11 +271,11 @@ static void evt_gen_req_no_support(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 
 		.request_type = "MakeMeDinner",
@@ -309,11 +309,11 @@ static void evt_gen_req_not_allowed(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 
 		.request_type = "MakeMeBreakfast",
@@ -348,11 +348,11 @@ static void evt_gen_auth_method_not_allowed(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 
 		.auth_method = "PlainText"
@@ -386,11 +386,11 @@ static void evt_gen_req_bad_format(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 
 		.request_type = "CheeseBurger",
@@ -425,11 +425,11 @@ static void evt_gen_successful_auth(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 	};
 
@@ -462,16 +462,16 @@ static void evt_gen_unexpected_addr(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 
 		.expected_addr = {
 			.addr = &addr_expected,
-			.transport  = AST_TRANSPORT_UDP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_UDP,
 		},
 	};
 
@@ -506,11 +506,11 @@ static void evt_gen_chal_resp_failed(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 
 		.challenge         = "8adf8a9sd8fas9df23ljk4",
@@ -546,11 +546,11 @@ static void evt_gen_inval_password(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.challenge          = "GoOdChAlLeNgE",
 		.received_challenge = "BaDcHaLlEnGe",
@@ -585,11 +585,11 @@ static void evt_gen_chal_sent(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.challenge         = "IcHaLlEnGeYoU",
 	};
@@ -622,11 +622,11 @@ static void evt_gen_inval_transport(void)
 		.common.session_tv = &session_tv,
 		.common.local_addr = {
 			.addr  = &addr_local,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.common.remote_addr = {
 			.addr = &addr_remote,
-			.transport  = AST_TRANSPORT_TCP,
+			.transport  = AST_SECURITY_EVENT_TRANSPORT_TCP,
 		},
 		.transport          = "UDP",
 	};
diff --git a/tests/test_skel.c b/tests/test_skel.c
index a1e2a86..122003d 100644
--- a/tests/test_skel.c
+++ b/tests/test_skel.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 332178 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/tests/test_sorcery.c b/tests/test_sorcery.c
deleted file mode 100644
index 9d32e3b..0000000
--- a/tests/test_sorcery.c
+++ /dev/null
@@ -1,3451 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012 - 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Sorcery Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>func_sorcery</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/logger.h"
-#include "asterisk/json.h"
-
-/*! \brief Dummy sorcery object */
-struct test_sorcery_object {
-	SORCERY_OBJECT(details);
-	unsigned int bob;
-	unsigned int joe;
-	struct ast_variable *jim;
-	struct ast_variable *jack;
-};
-
-/*! \brief Internal function to destroy a test object */
-static void test_sorcery_object_destroy(void *obj)
-{
-	struct test_sorcery_object *tobj = obj;
-	ast_variables_destroy(tobj->jim);
-	ast_variables_destroy(tobj->jack);
-}
-
-/*! \brief Internal function to allocate a test object */
-static void *test_sorcery_object_alloc(const char *id)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), test_sorcery_object_destroy);
-}
-
-/*! \brief Internal function for object set transformation */
-static struct ast_variable *test_sorcery_transform(struct ast_variable *set)
-{
-	struct ast_variable *field, *transformed = NULL;
-
-	for (field = set; field; field = field->next) {
-		struct ast_variable *transformed_field;
-
-		if (!strcmp(field->name, "joe")) {
-			transformed_field = ast_variable_new(field->name, "5000", "");
-		} else {
-			transformed_field = ast_variable_new(field->name, field->value, "");
-		}
-
-		if (!transformed_field) {
-			ast_variables_destroy(transformed);
-			return NULL;
-		}
-
-		transformed_field->next = transformed;
-		transformed = transformed_field;
-	}
-
-	return transformed;
-}
-
-/*! \brief Internal function which copies pre-defined data into an object, natively */
-static int test_sorcery_copy(const void *src, void *dst)
-{
-	struct test_sorcery_object *obj = dst;
-	obj->bob = 10;
-	obj->joe = 20;
-	obj->jim = ast_variable_new("jim", "444", "");
-	obj->jack = ast_variable_new("jack", "999,000", "");
-	return 0;
-}
-
-/*! \brief Internal function which creates a pre-defined diff natively */
-static int test_sorcery_diff(const void *original, const void *modified, struct ast_variable **changes)
-{
-	*changes = ast_variable_new("yes", "itworks", "");
-	return 0;
-}
-
-/*! \brief Internal function which sets some values */
-static int test_sorcery_regex_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct test_sorcery_object *test = obj;
-
-	test->bob = 256;
-
-	return 0;
-}
-
-/*! \brief Internal function which creates some ast_variable structures */
-static int test_sorcery_regex_fields(const void *obj, struct ast_variable **fields)
-{
-	*fields = ast_variable_new("toast-bob", "10", "");
-
-	return 0;
-}
-
-/*! \brief Test structure for caching */
-struct sorcery_test_caching {
-	/*! \brief Whether the object has been created in the cache or not */
-	unsigned int created:1;
-
-	/*! \brief Whether the object has been updated in the cache or not */
-	unsigned int updated:1;
-
-	/*! \brief Whether the object has been deleted from the cache or not */
-	unsigned int deleted:1;
-
-	/*! \brief Object to return when asked */
-	struct test_sorcery_object object;
-};
-
-/*! \brief Test structure for observer */
-struct sorcery_test_observer {
-	/*! \brief Lock for notification */
-	ast_mutex_t lock;
-
-	/*! \brief Condition for notification */
-	ast_cond_t cond;
-
-	/*! \brief Pointer to the created object */
-	const void *created;
-
-	/*! \brief Pointer to the update object */
-	const void *updated;
-
-	/*! \brief Pointer to the deleted object */
-	const void *deleted;
-
-	/*! \brief Whether the type has been loaded */
-	unsigned int loaded:1;
-};
-
-/*! \brief Global scope apply handler integer to make sure it executed */
-static int apply_handler_called;
-
-/*! \brief Simple apply handler which sets global scope integer to 1 if called */
-static int test_apply_handler(const struct ast_sorcery *sorcery, void *obj)
-{
-	apply_handler_called = 1;
-	return 0;
-}
-
-/*! \brief Global scope caching structure for testing */
-static struct sorcery_test_caching cache = { 0, };
-
-/*! \brief Global scope observer structure for testing */
-static struct sorcery_test_observer observer;
-
-static int sorcery_test_create(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	cache.created = 1;
-	cache.updated = 0;
-	cache.deleted = 0;
-	return 0;
-}
-
-static void *sorcery_test_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
-{
-	return (cache.created && !cache.deleted) ? ast_sorcery_alloc(sorcery, type, id) : NULL;
-}
-
-static int sorcery_test_update(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	cache.updated = 1;
-	return 0;
-}
-
-static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, void *object)
-{
-	cache.deleted = 1;
-	return 0;
-}
-
-/*! \brief Dummy sorcery wizard, not actually used so we only populate the name and nothing else */
-static struct ast_sorcery_wizard test_wizard = {
-	.name = "test",
-	.create = sorcery_test_create,
-	.retrieve_id = sorcery_test_retrieve_id,
-	.update = sorcery_test_update,
-	.delete = sorcery_test_delete,
-};
-
-static void sorcery_observer_created(const void *object)
-{
-	SCOPED_MUTEX(lock, &observer.lock);
-	observer.created = object;
-	ast_cond_signal(&observer.cond);
-}
-
-static void sorcery_observer_updated(const void *object)
-{
-	SCOPED_MUTEX(lock, &observer.lock);
-	observer.updated = object;
-	ast_cond_signal(&observer.cond);
-}
-
-static void sorcery_observer_deleted(const void *object)
-{
-	SCOPED_MUTEX(lock, &observer.lock);
-	observer.deleted = object;
-	ast_cond_signal(&observer.cond);
-}
-
-static void sorcery_observer_loaded(const char *object_type)
-{
-	SCOPED_MUTEX(lock, &observer.lock);
-	observer.loaded = 1;
-	ast_cond_signal(&observer.cond);
-}
-
-/*! \brief Test sorcery observer implementation */
-static const struct ast_sorcery_observer test_observer = {
-	.created = sorcery_observer_created,
-	.updated = sorcery_observer_updated,
-	.deleted = sorcery_observer_deleted,
-	.loaded = sorcery_observer_loaded,
-};
-
-/*  This handler takes a simple value and creates new list entry for it*/
-static int jim_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct test_sorcery_object *tobj = obj;
-
-	ast_variable_list_append(&tobj->jim, ast_variables_dup(var));
-
-	return 0;
-}
-
-/*  This handler takes a CSV string and creates new a new list entry for each value */
-static int jack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct test_sorcery_object *tobj = obj;
-
-	char *jacks = ast_strdupa(var->value);
-	char *val;
-
-	while ((val = strsep(&jacks, ","))) {
-		ast_variable_list_append(&tobj->jack, ast_variable_new("jack", val, ""));
-	}
-	return 0;
-}
-
-static int jim_vl(const void *obj, struct ast_variable **fields)
-{
-	const struct test_sorcery_object *tobj = obj;
-	if (tobj->jim) {
-		*fields = ast_variables_dup(tobj->jim);
-	}
-	return 0;
-}
-
-static int jack_str(const void *obj, const intptr_t *args, char **buf)
-{
-	const struct test_sorcery_object *tobj = obj;
-	struct ast_variable *curr = tobj->jack;
-	RAII_VAR(struct ast_str *, str,	ast_str_create(128), ast_free);
-
-	while(curr) {
-		ast_str_append(&str, 0, "%s,", curr->value);
-		curr = curr->next;
-	}
-	ast_str_truncate(str, -1);
-	*buf = ast_strdup(ast_str_buffer(str));
-	str = NULL;
-	return 0;
-}
-
-static struct ast_sorcery *alloc_and_initialize_sorcery(void)
-{
-	struct ast_sorcery *sorcery;
-
-	if (!(sorcery = ast_sorcery_open())) {
-		return NULL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
-		ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_sorcery_unref(sorcery);
-		return NULL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-	ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jim", "444", jim_handler, NULL, jim_vl, 0, 0);
-	ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jack", "888,999", jack_handler, jack_str, NULL, 0, 0);
-
-	return sorcery;
-}
-
-AST_TEST_DEFINE(wizard_registration)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "wizard_registration";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery wizard registration and unregistration unit test";
-		info->description =
-			"Test registration and unregistration of a sorcery wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (ast_sorcery_wizard_register(&test_wizard)) {
-		ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_wizard_register(&test_wizard)) {
-		ast_test_status_update(test, "Successfully registered a sorcery wizard twice, which is bad\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_wizard_unregister(&test_wizard)) {
-		ast_test_status_update(test, "Failed to unregister a perfectly valid sorcery wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_wizard_unregister(&test_wizard)) {
-		ast_test_status_update(test, "Successfully unregistered a sorcery wizard twice, which is bad\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(sorcery_open)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct ast_sorcery *, sorcery2, NULL, ast_sorcery_unref);
-	int refcount;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "open";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery open/close unit test";
-		info->description =
-			"Test opening of sorcery and registry operations";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if ((sorcery = ast_sorcery_retrieve_by_module_name(AST_MODULE))) {
-		ast_test_status_update(test, "There should NOT have been an existing sorcery instance\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open new sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery2 = ast_sorcery_retrieve_by_module_name(AST_MODULE))) {
-		ast_test_status_update(test, "Failed to find sorcery structure in registry\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (sorcery2 != sorcery) {
-		ast_test_status_update(test, "Should have gotten same sorcery on retrieve\n");
-		return AST_TEST_FAIL;
-	}
-	ast_sorcery_unref(sorcery2);
-
-	if ((refcount = ao2_ref(sorcery, 0)) != 2) {
-		ast_test_status_update(test, "Should have been 2 references to sorcery instead of %d\n", refcount);
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery2 = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open second sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (sorcery2 != sorcery) {
-		ast_test_status_update(test, "Should have gotten same sorcery on 2nd open\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((refcount = ao2_ref(sorcery, 0)) != 3) {
-		ast_test_status_update(test, "Should have been 3 references to sorcery instead of %d\n", refcount);
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_unref(sorcery);
-	ast_sorcery_unref(sorcery2);
-
-	sorcery2 = NULL;
-
-	if ((sorcery = ast_sorcery_retrieve_by_module_name(AST_MODULE))) {
-		ast_sorcery_unref(sorcery);
-		sorcery = NULL;
-		ast_test_status_update(test, "Should NOT have found sorcery structure in registry\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(apply_default)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "apply_default";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery default wizard unit test";
-		info->description =
-			"Test setting default type wizard in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "dummy", NULL) != AST_SORCERY_APPLY_FAIL) {
-		ast_test_status_update(test, "Successfully set a default wizard that doesn't exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_DEFAULT_UNNECESSARY) {
-		ast_test_status_update(test, "Successfully set a default wizard on a type twice\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(apply_config)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "apply_config";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object mapping configuration unit test";
-		info->description =
-			"Test configured object mapping in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Sorcery configuration file not present - skipping apply_config test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (!ast_category_get(config, "test_sorcery_section", NULL)) {
-		ast_test_status_update(test, "Sorcery configuration file does not have test_sorcery section\n");
-		ast_config_destroy(config);
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_config(sorcery, "test_sorcery_section") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to apply configured object mappings\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_register)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_register";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object type registration unit test";
-		info->description =
-			"Test object type registration in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Registered object type a second time, despite it being registered already\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_register_without_mapping)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_register_without_mapping";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object type registration (without mapping) unit test";
-		info->description =
-			"Test object type registration when no mapping exists in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Registered object type when no object mapping exists\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_field_register)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_field_register";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object field registration unit test";
-		info->description =
-			"Test object field registration in sorcery with a provided id";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
-		ast_test_status_update(test, "Registered an object field successfully when no mappings or object types exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
-		ast_test_status_update(test, "Registered an object field successfully when object type does not exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
-		ast_test_status_update(test, "Could not successfully register object field when mapping and object type exists\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_fields_register)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_fields_register";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object regex fields registration unit test";
-		info->description =
-			"Test object regex fields registration in sorcery with a provided id";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
-		ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
-		ast_test_status_update(test, "Registered a regex object field successfully when object type does not exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields)) {
-		ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_alloc_with_id)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc_with_id";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object allocation (with id) unit test";
-		info->description =
-			"Test object allocation in sorcery with a provided id";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_strlen_zero(ast_sorcery_object_get_id(obj))) {
-		ast_test_status_update(test, "Allocated object has empty id when it should not\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
-		ast_test_status_update(test, "Allocated object does not have correct id\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_strlen_zero(ast_sorcery_object_get_type(obj))) {
-		ast_test_status_update(test, "Allocated object has empty type when it should not\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_type(obj), "test")) {
-		ast_test_status_update(test, "Allocated object does not have correct type\n");
-		res = AST_TEST_FAIL;
-	} else if ((obj->bob != 5) || (obj->joe != 10)) {
-		ast_test_status_update(test, "Allocated object does not have defaults set as it should\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(object_alloc_without_id)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_alloc_without_id";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object allocation (without id) unit test";
-		info->description =
-			"Test object allocation in sorcery with no provided id";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", NULL))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_strlen_zero(ast_sorcery_object_get_id(obj))) {
-		ast_test_status_update(test, "Allocated object has empty id when it should not\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-
-AST_TEST_DEFINE(object_copy)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, copy, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_copy";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object copy unit test";
-		info->description =
-			"Test object copy in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->bob = 50;
-	obj->joe = 100;
-	jim_handler(NULL, ast_variable_new("jim", "444", ""), obj);
-	jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
-
-	if (!(copy = ast_sorcery_copy(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create a copy of a known valid object\n");
-		res = AST_TEST_FAIL;
-	} else if (copy == obj) {
-		ast_test_status_update(test, "Created copy is actually the original object\n");
-		res = AST_TEST_FAIL;
-	} else if (copy->bob != obj->bob) {
-		ast_test_status_update(test, "Value of 'bob' on newly created copy is not the same as original\n");
-		res = AST_TEST_FAIL;
-	} else if (copy->joe != obj->joe) {
-		ast_test_status_update(test, "Value of 'joe' on newly created copy is not the same as original\n");
-		res = AST_TEST_FAIL;
-	} else if (!copy->jim) {
-		ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
-		res = AST_TEST_FAIL;
-	} else if (copy->jim == obj->jim) {
-		ast_test_status_update(test, "Created copy of 'jim' is actually the ogirinal 'jim'\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(copy->jim->value, obj->jim->value)) {
-		ast_test_status_update(test, "Value of 1st 'jim' on newly created copy is not the same as original\n");
-		res = AST_TEST_FAIL;
-	} else if (!copy->jim->next) {
-		ast_test_status_update(test, "A new ast_variable was not created for 2nd 'jim'\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(copy->jim->next->value, obj->jim->next->value)) {
-		ast_test_status_update(test, "Value of 2nd 'jim' (%s %s) on newly created copy is not the same as original (%s %s)\n",
-			copy->jim->value, copy->jim->next->value, obj->jim->value, obj->jim->next->value);
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(object_copy_native)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, copy, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_copy_native";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object native copy unit test";
-		info->description =
-			"Test object native copy in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_set_copy_handler(sorcery, "test", test_sorcery_copy);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->bob = 50;
-	obj->joe = 100;
-
-	if (!(copy = ast_sorcery_copy(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create a copy of a known valid object\n");
-		res = AST_TEST_FAIL;
-	} else if (copy == obj) {
-		ast_test_status_update(test, "Created copy is actually the original object\n");
-		res = AST_TEST_FAIL;
-	} else if (copy->bob != 10) {
-		ast_test_status_update(test, "Value of 'bob' on newly created copy is not the predefined native copy value\n");
-		res = AST_TEST_FAIL;
-	} else if (copy->joe != 20) {
-		ast_test_status_update(test, "Value of 'joe' on newly created copy is not the predefined native copy value\n");
-		res = AST_TEST_FAIL;
-	} else if (!copy->jim) {
-		ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(copy->jim->value, "444")) {
-		ast_test_status_update(test, "Value of 'jim' on newly created copy is not the predefined native copy value\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(object_diff)
-{
-       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-       RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
-       RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-       RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
-       struct ast_variable *field;
-       int res = AST_TEST_PASS;
-       int jims = 0;
-
-       switch (cmd) {
-       case TEST_INIT:
-	       info->name = "object_diff";
-	       info->category = "/main/sorcery/";
-	       info->summary = "sorcery object diff unit test";
-	       info->description =
-		       "Test object diffing in sorcery";
-	       return AST_TEST_NOT_RUN;
-       case TEST_EXECUTE:
-	       break;
-       }
-
-       if (!(sorcery = alloc_and_initialize_sorcery())) {
-	       ast_test_status_update(test, "Failed to open sorcery structure\n");
-	       return AST_TEST_FAIL;
-       }
-
-       if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-	       ast_test_status_update(test, "Failed to allocate a known object type\n");
-	       return AST_TEST_FAIL;
-       }
-
-       obj1->bob = 99;
-       obj1->joe = 55;
-       jim_handler(NULL, ast_variable_new("jim", "444", ""), obj1);
-       jim_handler(NULL, ast_variable_new("jim", "555", ""), obj1);
-
-       if (!(obj2 = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-	       ast_test_status_update(test, "Failed to allocate a second known object type\n");
-	       return AST_TEST_FAIL;
-       }
-
-       obj2->bob = 99;
-       obj2->joe = 42;
-       jim_handler(NULL, ast_variable_new("jim", "444", ""), obj2);
-       jim_handler(NULL, ast_variable_new("jim", "666", ""), obj2);
-       jim_handler(NULL, ast_variable_new("jim", "777", ""), obj2);
-
-       if (ast_sorcery_diff(sorcery, obj1, obj2, &changes)) {
-	       ast_test_status_update(test, "Failed to diff obj1 and obj2\n");
-       } else if (!changes) {
-	       ast_test_status_update(test, "Failed to produce a diff of two objects, despite there being differences\n");
-	       return AST_TEST_FAIL;
-       }
-
-	for (field = changes; field; field = field->next) {
-		if (!strcmp(field->name, "joe")) {
-			if (strcmp(field->value, "42")) {
-				ast_test_status_update(test,
-					"Object diff produced unexpected value '%s' for joe\n", field->value);
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(field->name, "jim")) {
-			jims++;
-			if (!strcmp(field->value, "555")) {
-				ast_test_status_update(test,
-					"Object diff produced unexpected value '%s' for jim\n", field->value);
-				res = AST_TEST_FAIL;
-			}
-		} else {
-			ast_test_status_update(test, "Object diff produced unexpected field '%s'\n",
-				field->name);
-			res = AST_TEST_FAIL;
-		}
-	}
-
-       if (jims != 2) {
-	       ast_test_status_update(test, "Object diff didn't produce 2 jims\n");
-	       res = AST_TEST_FAIL;
-       }
-
-       return res;
-}
-
-AST_TEST_DEFINE(object_diff_native)
-{
-       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-       RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
-       RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-       RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
-       struct ast_variable *field;
-       int res = AST_TEST_PASS;
-
-       switch (cmd) {
-       case TEST_INIT:
-	       info->name = "object_diff_native";
-	       info->category = "/main/sorcery/";
-	       info->summary = "sorcery object native diff unit test";
-	       info->description =
-		       "Test native object diffing in sorcery";
-	       return AST_TEST_NOT_RUN;
-       case TEST_EXECUTE:
-	       break;
-       }
-
-       if (!(sorcery = alloc_and_initialize_sorcery())) {
-	       ast_test_status_update(test, "Failed to open sorcery structure\n");
-	       return AST_TEST_FAIL;
-       }
-
-       ast_sorcery_object_set_diff_handler(sorcery, "test", test_sorcery_diff);
-
-       if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-	       ast_test_status_update(test, "Failed to allocate a known object type\n");
-	       return AST_TEST_FAIL;
-       }
-
-       obj1->bob = 99;
-       obj1->joe = 55;
-
-       if (!(obj2 = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-	       ast_test_status_update(test, "Failed to allocate a second known object type\n");
-	       return AST_TEST_FAIL;
-       }
-
-       obj2->bob = 99;
-       obj2->joe = 42;
-
-       if (ast_sorcery_diff(sorcery, obj1, obj2, &changes)) {
-	       ast_test_status_update(test, "Failed to diff obj1 and obj2\n");
-       } else if (!changes) {
-	       ast_test_status_update(test, "Failed to produce a diff of two objects, despite there being differences\n");
-	       return AST_TEST_FAIL;
-       }
-
-       for (field = changes; field; field = field->next) {
-	       if (!strcmp(field->name, "yes")) {
-		       if (strcmp(field->value, "itworks")) {
-			       ast_test_status_update(test, "Object diff produced unexpected value '%s' for joe\n", field->value);
-			       res = AST_TEST_FAIL;
-		       }
-	       } else {
-		       ast_test_status_update(test, "Object diff produced unexpected field '%s'\n", field->name);
-		       res = AST_TEST_FAIL;
-	       }
-       }
-
-       return res;
-}
-
-AST_TEST_DEFINE(objectset_create)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	struct ast_variable *field;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_create";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object set creation unit test";
-		info->description =
-			"Test object set creation in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
-		return AST_TEST_FAIL;
-	}
-
-	for (field = objset; field; field = field->next) {
-		if (!strcmp(field->name, "bob")) {
-			if (strcmp(field->value, "5")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(field->name, "joe")) {
-			if (strcmp(field->value, "10")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(field->name, "jim")) {
-			if (strcmp(field->value, "444")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(field->name, "jack")) {
-			if (strcmp(field->value, "888,999")) {
-				ast_test_status_update(test, "Object set failed to create proper value (%s) for 'jack'\n", field->value);
-				res = AST_TEST_FAIL;
-			}
-		} else {
-			ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(objectset_json_create)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, objset, NULL, ast_json_unref);
-	struct ast_json_iter *field;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_json_create";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery json object set creation unit test";
-		info->description =
-			"Test object set creation (for JSON format) in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_sorcery_objectset_json_create(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
-		return AST_TEST_FAIL;
-	}
-
-	for (field = ast_json_object_iter(objset); field; field = ast_json_object_iter_next(objset, field)) {
-		struct ast_json *value = ast_json_object_iter_value(field);
-
-		if (!strcmp(ast_json_object_iter_key(field), "bob")) {
-			if (strcmp(ast_json_string_get(value), "5")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "joe")) {
-			if (strcmp(ast_json_string_get(value), "10")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "jim")) {
-			if (strcmp(ast_json_string_get(value), "444")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else if (!strcmp(ast_json_object_iter_key(field), "jack")) {
-			if (strcmp(ast_json_string_get(value), "888,999")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'jack'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else {
-			ast_test_status_update(test, "Object set created field '%s' which is unknown\n", ast_json_object_iter_key(field));
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(objectset_create_regex)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	struct ast_variable *field;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_create_regex";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object set creation with regex fields unit test";
-		info->description =
-			"Test object set creation with regex fields in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
-	    ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
-		ast_test_status_update(test, "Failed to register 'test' object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
-		return AST_TEST_FAIL;
-	}
-
-	for (field = objset; field; field = field->next) {
-		if (!strcmp(field->name, "toast-bob")) {
-			if (strcmp(field->value, "10")) {
-				ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
-				res = AST_TEST_FAIL;
-			}
-		} else {
-			ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(objectset_apply)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_apply";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object apply unit test";
-		info->description =
-			"Test object set applying in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_variable_new("joe", "25", ""))) {
-		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Failed to apply valid object set to object\n");
-		res = AST_TEST_FAIL;
-	} else if (obj->joe != 25) {
-		ast_test_status_update(test, "Object set was not actually applied to object despite it returning success\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(objectset_apply_handler)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_apply_handler";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object apply handler unit test";
-		info->description =
-			"Test object set apply handler call in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
-	    ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
-		ast_test_status_update(test, "Failed to register 'test' object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	apply_handler_called = 0;
-
-	if (!(objset = ast_variable_new("joe", "25", ""))) {
-		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Failed to apply valid object set to object\n");
-		res = AST_TEST_FAIL;
-	} else if (!apply_handler_called) {
-		ast_test_status_update(test, "Apply handler was not called when it should have been\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(objectset_apply_invalid)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_apply_invalid";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object invalid apply unit test";
-		info->description =
-			"Test object set applying of an invalid set in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_variable_new("fred", "99", ""))) {
-		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
-		return AST_TEST_FAIL;
-	} else if (!ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Successfully applied an invalid object set\n");
-		return AST_TEST_FAIL;
-	} else if ((obj->bob != 5) || (obj->joe != 10)) {
-		ast_test_status_update(test, "Object set modified object fields when it should not have\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(objectset_transform)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_transform";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object set transformation unit test";
-		info->description =
-			"Test object set transformation in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to set a known wizard as a default\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, test_sorcery_transform, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Failed to apply properly created object set against object\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (obj->bob != 5) {
-		ast_test_status_update(test, "Application of object set produced incorrect value on 'bob'\n");
-		return AST_TEST_FAIL;
-	} else if (obj->joe == 10) {
-		ast_test_status_update(test, "Transformation callback did not change value of 'joe' from provided value\n");
-		return AST_TEST_FAIL;
-	} else if (obj->joe != 5000) {
-		ast_test_status_update(test, "Value of 'joe' differs from default AND from transformation value\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(objectset_apply_fields)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "objectset_apply_fields";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object apply regex fields unit test";
-		info->description =
-			"Test object set apply with regex fields in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
-	    ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
-		ast_test_status_update(test, "Failed to register 'test' object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_fields_register(sorcery, "test", "^toast-", test_sorcery_regex_handler, test_sorcery_regex_fields);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_variable_new("toast-bob", "20", ""))) {
-		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Failed to apply valid object set to object\n");
-		res = AST_TEST_FAIL;
-	} else if (obj->bob != 256) {
-		ast_test_status_update(test, "Regex field handler was not called when it should have been\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(extended_fields)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	const char *value;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "extended_fields";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object extended fields unit test";
-		info->description =
-			"Test extended fields support in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objset = ast_variable_new("@testing", "toast", ""))) {
-		ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
-		ast_test_status_update(test, "Failed to apply valid object set to object\n");
-		res = AST_TEST_FAIL;
-	} else if (!(value = ast_sorcery_object_get_extended(obj, "testing"))) {
-		ast_test_status_update(test, "Extended field, which was set using object set, could not be found\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(value, "toast")) {
-		ast_test_status_update(test, "Extended field does not contain expected value\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_object_set_extended(obj, "@tacos", "supreme")) {
-		ast_test_status_update(test, "Extended field could not be set\n");
-		res = AST_TEST_FAIL;
-	} else if (!(value = ast_sorcery_object_get_extended(obj, "tacos"))) {
-		ast_test_status_update(test, "Extended field, which was set using the API, could not be found\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(value, "supreme")) {
-		ast_test_status_update(test, "Extended field does not contain expected value\n");
-		res = AST_TEST_FAIL;
-	} else if (ast_sorcery_object_set_extended(obj, "@tacos", "canadian")) {
-		ast_test_status_update(test, "Extended field could not be set a second time\n");
-		res = AST_TEST_FAIL;
-	} else if (!(value = ast_sorcery_object_get_extended(obj, "tacos"))) {
-		ast_test_status_update(test, "Extended field, which was set using the API, could not be found\n");
-		res = AST_TEST_FAIL;
-	} else if (strcmp(value, "canadian")) {
-		ast_test_status_update(test, "Extended field does not contain expected value\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(changeset_create)
-{
-	int res = AST_TEST_PASS;
-	RAII_VAR(struct ast_variable *, original, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, modified, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
-	struct ast_variable *tmp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "changeset_create";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery changeset creation unit test";
-		info->description =
-			"Test changeset creation in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
-		ast_test_status_update(test, "Failed to create first field for original objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = original;
-	original = tmp;
-
-	if (!(tmp = ast_variable_new("apples", "orange", ""))) {
-		ast_test_status_update(test, "Failed to create second field for original objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = original;
-	original = tmp;
-
-	if (!(tmp = ast_variable_new("bananas", "green", ""))) {
-		ast_test_status_update(test, "Failed to create first field for modified objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = modified;
-	modified = tmp;
-
-	if (!(tmp = ast_variable_new("apples", "orange", ""))) {
-		ast_test_status_update(test, "Failed to create second field for modified objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = modified;
-	modified = tmp;
-
-	if (ast_sorcery_changeset_create(original, modified, &changes)) {
-		ast_test_status_update(test, "Failed to create a changeset due to an error\n");
-		return AST_TEST_FAIL;
-	} else if (!changes) {
-		ast_test_status_update(test, "Failed to produce a changeset when there should be one\n");
-		return AST_TEST_FAIL;
-	}
-
-	for (tmp = changes; tmp; tmp = tmp->next) {
-		if (!strcmp(tmp->name, "bananas")) {
-			if (strcmp(tmp->value, "green")) {
-				ast_test_status_update(test, "Changeset produced had unexpected value '%s' for bananas\n", tmp->value);
-				res = AST_TEST_FAIL;
-			}
-		} else {
-			ast_test_status_update(test, "Changeset produced had unexpected field '%s'\n", tmp->name);
-			res = AST_TEST_FAIL;
-		}
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(changeset_create_unchanged)
-{
-	RAII_VAR(struct ast_variable *, original, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
-	RAII_VAR(struct ast_variable *, same, NULL, ast_variables_destroy);
-	struct ast_variable *tmp;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "changeset_create_unchanged";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery changeset creation unit test when no changes exist";
-		info->description =
-			"Test changeset creation in sorcery when no changes actually exist";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
-		ast_test_status_update(test, "Failed to create first field for original objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = original;
-	original = tmp;
-
-	if (!(tmp = ast_variable_new("apples", "orange", ""))) {
-		ast_test_status_update(test, "Failed to create second field for original objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = original;
-	original = tmp;
-
-	if (ast_sorcery_changeset_create(original, original, &changes)) {
-		ast_test_status_update(test, "Failed to create a changeset due to an error\n");
-		return AST_TEST_FAIL;
-	} else if (changes) {
-		ast_test_status_update(test, "Created a changeset when no changes actually exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
-		ast_test_status_update(test, "Failed to create first field for same objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = same;
-	same = tmp;
-
-	if (!(tmp = ast_variable_new("apples", "orange", ""))) {
-		ast_test_status_update(test, "Failed to create second field for same objectset\n");
-		return AST_TEST_FAIL;
-	}
-	tmp->next = same;
-	same = tmp;
-
-	if (ast_sorcery_changeset_create(original, same, &changes)) {
-		ast_test_status_update(test, "Failed to create a changeset due to an error\n");
-		return AST_TEST_FAIL;
-	} else if (changes) {
-		ast_test_status_update(test, "Created a changeset between two different objectsets when no changes actually exist\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_create)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_create";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object creation unit test";
-		info->description =
-			"Test object creation in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_id)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_id";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object retrieval using id unit test";
-		info->description =
-			"Test object retrieval using id in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
-		ast_test_status_update(test, "Retrieved object does not have correct id\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_field";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object retrieval using a specific field unit test";
-		info->description =
-			"Test object retrieval using a specific field in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 42;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "49", ""))) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_all)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_all";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_field";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using fields";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 6;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 1) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(objects);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "7", ""))) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
-		return AST_TEST_FAIL;
-	} else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects)) {
-		ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_regex)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_regex";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery multiple object retrieval using regex unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using regular expression for matching";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create third object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
-		ast_test_status_update(test, "Failed to retrieve a container of objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test object updating in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (ast_sorcery_update(sorcery, obj2)) {
-		ast_test_status_update(test, "Failed to update sorcery with new object\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly updated object\n");
-		return AST_TEST_FAIL;
-	} else if (obj != obj2) {
-		ast_test_status_update(test, "Object retrieved is not the updated object\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update_uncreated";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test updating of an uncreated object in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_update(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete_uncreated";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion of an uncreated object in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully deleted an object which was never created\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(caching_wizard_behavior)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-	int res = AST_TEST_FAIL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "caching_wizard_behavior";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery caching wizard behavior unit test";
-		info->description =
-			"Test internal behavior of caching wizards";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("sorcery.conf", "test_sorcery_cache", flags))) {
-		ast_test_status_update(test, "Sorcery configuration file not present - skipping caching_wizard_behavior test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (!ast_category_get(config, "test_sorcery_cache", NULL)) {
-		ast_test_status_update(test, "Sorcery configuration file does not contain 'test_sorcery_cache' section\n");
-		ast_config_destroy(config);
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (ast_sorcery_wizard_register(&test_wizard)) {
-		ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		goto end;
-	}
-
-	if (ast_sorcery_apply_config(sorcery, "test_sorcery_cache") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Failed to apply configured object mappings\n");
-		goto end;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		goto end;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		goto end;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		goto end;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve just created object\n");
-		goto end;
-	} else if (!cache.created) {
-		ast_test_status_update(test, "Caching wizard was not told to cache just created object\n");
-		goto end;
-	} else if (!(obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve just cached object\n");
-		goto end;
-	} else if (obj == obj2) {
-		ast_test_status_update(test, "Returned object is *NOT* a cached object\n");
-		goto end;
-	} else if (ast_sorcery_update(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to update a known stored object\n");
-		goto end;
-	} else if (!cache.updated) {
-		ast_test_status_update(test, "Caching wizard was not told to update object\n");
-		goto end;
-	} else if (ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to delete a known stored object\n");
-		goto end;
-	} else if (!cache.deleted) {
-		ast_test_status_update(test, "Caching wizard was not told to delete object\n");
-		goto end;
-	}
-
-	ao2_cleanup(obj2);
-
-	if ((obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Retrieved an object that should have been deleted\n");
-		goto end;
-	}
-
-	res = AST_TEST_PASS;
-
-end:
-	ast_sorcery_unref(sorcery);
-	sorcery = NULL;
-
-	if (ast_sorcery_wizard_unregister(&test_wizard)) {
-		ast_test_status_update(test, "Failed to unregister test sorcery wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(object_type_observer)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	int res = AST_TEST_FAIL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_type_observer";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery object type observer unit test";
-		info->description =
-			"Test that object type observers get called when they should";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_observer_add(sorcery, "test", NULL)) {
-		ast_test_status_update(test, "Successfully added a NULL observer when it should not be possible\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_observer_add(sorcery, "test", &test_observer)) {
-		ast_test_status_update(test, "Failed to add a proper observer\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		goto end;
-	}
-
-	ast_mutex_init(&observer.lock);
-	ast_cond_init(&observer.cond, NULL);
-	observer.created = NULL;
-	observer.updated = NULL;
-	observer.deleted = NULL;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
-		goto end;
-	}
-
-	ast_mutex_lock(&observer.lock);
-	while (!observer.created) {
-        struct timeval start = ast_tvnow();
-        struct timespec end = {
-                .tv_sec = start.tv_sec + 10,
-                .tv_nsec = start.tv_usec * 1000,
-        };
-		if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-	ast_mutex_unlock(&observer.lock);
-
-	if (!observer.created) {
-		ast_test_status_update(test, "Failed to receive observer notification for object creation within suitable timeframe\n");
-		goto end;
-	}
-
-	if (ast_sorcery_update(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to update object using in-memory wizard\n");
-		goto end;
-	}
-
-	ast_mutex_lock(&observer.lock);
-	while (!observer.updated) {
-        struct timeval start = ast_tvnow();
-        struct timespec end = {
-                .tv_sec = start.tv_sec + 10,
-                .tv_nsec = start.tv_usec * 1000,
-        };
-		if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-	ast_mutex_unlock(&observer.lock);
-
-	if (!observer.updated) {
-		ast_test_status_update(test, "Failed to receive observer notification for object updating within suitable timeframe\n");
-		goto end;
-	}
-
-	if (ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
-		goto end;
-	}
-
-	ast_mutex_lock(&observer.lock);
-	while (!observer.deleted) {
-        struct timeval start = ast_tvnow();
-        struct timespec end = {
-                .tv_sec = start.tv_sec + 10,
-                .tv_nsec = start.tv_usec * 1000,
-        };
-		if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-	ast_mutex_unlock(&observer.lock);
-
-	if (!observer.deleted) {
-		ast_test_status_update(test, "Failed to receive observer notification for object deletion within suitable timeframe\n");
-		goto end;
-	}
-
-	ast_sorcery_reload(sorcery);
-
-	ast_mutex_lock(&observer.lock);
-	while (!observer.loaded) {
-        struct timeval start = ast_tvnow();
-        struct timespec end = {
-                .tv_sec = start.tv_sec + 10,
-                .tv_nsec = start.tv_usec * 1000,
-        };
-		if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-	ast_mutex_unlock(&observer.lock);
-
-	if (!observer.loaded) {
-		ast_test_status_update(test, "Failed to receive observer notification for object type load within suitable timeframe\n");
-		goto end;
-	}
-
-	res = AST_TEST_PASS;
-
-end:
-	observer.created = NULL;
-	observer.updated = NULL;
-	observer.deleted = NULL;
-	ast_mutex_destroy(&observer.lock);
-	ast_cond_destroy(&observer.cond);
-
-	return res;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard unit test";
-		info->description =
-			"Test the configuration file wizard in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	ast_sorcery_load(sorcery);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
-		ast_test_status_update(test, "Retrieved object which has an unknown field\n");
-		return AST_TEST_FAIL;
-	} else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
-		ast_test_status_update(test, "Failed to retrieve a known object that has been configured in the configuration file\n");
-		return AST_TEST_FAIL;
-	} else if (obj->bob != 98) {
-		ast_test_status_update(test, "Value of 'bob' on object is not what is configured in configuration file\n");
-		return AST_TEST_FAIL;
-	} else if (obj->joe != 41) {
-		ast_test_status_update(test, "Value of 'joe' on object is not what is configured in configuration file\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard_with_file_integrity)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard_with_file_integrity";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard file integrity unit test";
-		info->description =
-			"Test the configuration file wizard with file integrity turned on in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_file_integrity test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,integrity=file") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	ast_sorcery_load(sorcery);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
-		ast_test_status_update(test, "Retrieved object which has an unknown field\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard_with_criteria)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard_with_criteria";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard with criteria unit test";
-		info->description =
-			"Test the configuration file wizard with criteria matching in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_criteria test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,criteria=type=zombies") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "type", NULL, OPT_NOOP_T, 0, NULL);
-
-	ast_sorcery_load(sorcery);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
-		ast_test_status_update(test, "Retrieved object which did not match criteria\n");
-		return AST_TEST_FAIL;
-	} else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
-		ast_test_status_update(test, "Failed to retrieve a known object which matches criteria\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard_retrieve_field)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "41", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard_retrieve_field";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard field retrieval unit test";
-		info->description =
-			"Test the configuration file wizard retrieval using field in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_field test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	ast_sorcery_load(sorcery);
-
-	if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Failed to retrieve a known object that has been configured with the correct field\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_id(obj), "hey")) {
-		ast_test_status_update(test, "Retrieved object has incorrect object id of '%s'\n", ast_sorcery_object_get_id(obj));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "99", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard_retrieve_multiple";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard multiple retrieval unit test";
-		info->description =
-			"Test the configuration file wizard multiple retrieval in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	ast_sorcery_load(sorcery);
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects)) {
-		ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(objects);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "41", ""))) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
-		return AST_TEST_FAIL;
-	} else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve a container when retrieving multiple\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 1) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple_all)
-{
-	struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
-	struct ast_config *config;
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "configuration_file_wizard_retrieve_multiple_all";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery configuration file wizard multiple retrieve all unit test";
-		info->description =
-			"Test the configuration file wizard multiple retrieve all in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
-		ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple_all test\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	ast_config_destroy(config);
-
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
-		ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
-		return AST_TEST_NOT_RUN;
-	}
-
-	if (ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_test_status_update(test, "Failed to register object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	ast_sorcery_load(sorcery);
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		ast_test_status_update(test, "Failed to retrieve a container with all objects when there should be one\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Returned container does not have the correct number of objects in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(dialplan_function)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
-	struct ast_str *buf;
-	char expression[256];
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "dialplan_function";
-		info->category = "/main/sorcery/";
-		info->summary = "AST_SORCERY dialplan function";
-		info->description =
-			"Test the AST_SORCERY dialplan function";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(buf = ast_str_create(16))) {
-		ast_test_status_update(test, "Failed to allocate return buffer\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "notest_sorcery", "test", "blah", "bob");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Retrieved a non-existent module\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "notest", "blah", "bob");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Retrieved a non-existent type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "noid", "bob");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Retrieved a non-existent id\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "nobob");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Retrieved a non-existent field\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "bob");
-	if (ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve field 'bob'\n");
-		return AST_TEST_FAIL;
-	}
-	if (strcmp(ast_str_buffer(buf), "5")) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve field.  Got '%u', should be '5'\n", obj->bob);
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,1)", "test_sorcery", "test", "blah", "bob");
-	if (ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve field 'bob'\n");
-		return AST_TEST_FAIL;
-	}
-	if (strcmp(ast_str_buffer(buf), "5")) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve field.  Got '%u', should be '5'\n", obj->bob);
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "bob");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Got a second 'bob' and shouldn't have\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* 444 is already the first item in the list */
-	jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
-	jim_handler(NULL, ast_variable_new("jim", "666", ""), obj);
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "jim");
-	if (ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Couldn't retrieve 'jim'\n");
-		return AST_TEST_FAIL;
-	}
-	if (strcmp(ast_str_buffer(buf), "444,555,666")) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve jim.  Got '%s', should be '444,555,666'\n", ast_str_buffer(buf));
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "jim");
-	if (ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Couldn't retrieve 2nd jim\n");
-		return AST_TEST_FAIL;
-	}
-	if (strcmp(ast_str_buffer(buf), "555")) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve 2nd jim.  Got '%s', should be '555'\n", ast_str_buffer(buf));
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,concat,|)", "test_sorcery", "test", "blah", "jim");
-	if (ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Couldn't retrieve any 'jim'\n");
-		return AST_TEST_FAIL;
-	}
-	if (strcmp(ast_str_buffer(buf), "444|555|666")) {
-		ast_free(buf);
-		ast_test_status_update(test, "Failed retrieve 'jim'.  Got '%s', should be '444|555|666'\n", ast_str_buffer(buf));
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,noconcat,3)", "test_sorcery", "test", "blah", "jim");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Should have failed with invalid retrieval_type\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_str_reset(buf);
-	snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,|)", "test_sorcery", "test", "blah", "jim");
-	if (!ast_func_read2(NULL, expression, &buf, 16)) {
-		ast_free(buf);
-		ast_test_status_update(test, "Should have failed with invalid occurrence_number\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_free(buf);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_field_registered)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_field_registered";
-		info->category = "/main/sorcery/";
-		info->summary = "ast_sorcery_is_object_field_registered unit test";
-		info->description =
-			"Test ast_sorcery_is_object_field_registered in sorcery";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	object_type = ast_sorcery_get_object_type(sorcery, "test");
-
-	ast_sorcery_object_fields_register(sorcery, "test", "^prefix/.", test_sorcery_regex_handler, test_sorcery_regex_fields);
-
-	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "joe"));
-	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "bob"));
-	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "@joebob"));
-	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
-
-	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "joebob"));
-	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "prefix/"));
-	ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "goober"));
-
-	ast_sorcery_object_fields_register(sorcery, "test", "^", test_sorcery_regex_handler, test_sorcery_regex_fields);
-
-	ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
-
-	return AST_TEST_PASS;
-}
-
-static int event_observed;
-
-static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
-{
-	if (!strcmp(wizard->name, "test")) {
-		event_observed = 1;
-	}
-}
-
-static void instance_observer(const char *name, struct ast_sorcery *sorcery)
-{
-	if (!strcmp(name, "test_sorcery")) {
-		event_observed = 1;
-	}
-}
-
-AST_TEST_DEFINE(global_observation)
-{
-	RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	const struct ast_sorcery_global_observer observer = {
-		.wizard_registered = wizard_observer,
-		.instance_created = instance_observer,
-		.wizard_unregistering = wizard_observer,
-		.instance_destroying = instance_observer,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "global_observation";
-		info->category = "/main/sorcery/";
-		info->summary = "global sorcery observation test";
-		info->description =
-			"Test observation of sorcery (global)";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_sorcery_global_observer_add(&observer);
-
-	event_observed = 0;
-	ast_sorcery_wizard_register(wizard);
-	ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
-
-	event_observed = 0;
-	ast_sorcery_wizard_unregister(wizard);
-	ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
-
-	event_observed = 0;
-	sorcery = ast_sorcery_open();
-	ast_test_validate(test, (event_observed == 1), "Instance created failed");
-
-	event_observed = 0;
-	ast_sorcery_unref(sorcery);
-	sorcery = NULL;
-	ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
-
-	ast_sorcery_global_observer_remove(&observer);
-	event_observed = 0;
-	ast_sorcery_wizard_register(&test_wizard);
-	ast_test_validate(test, (event_observed == 0), "Observer removed failed");
-
-	return AST_TEST_PASS;
-}
-
-static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
-	int reloaded)
-{
-	if (!strcmp(name, "test_sorcery") && !reloaded) {
-		event_observed++;
-	}
-}
-
-static void instance_reloaded_observer(const char *name,
-	const struct ast_sorcery *sorcery, int reloaded)
-{
-	if (!strcmp(name, "test_sorcery") && reloaded) {
-		event_observed++;
-	}
-}
-
-static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
-	const char *object_type, struct ast_sorcery_wizard *wizard,
-	const char *wizard_args, void *wizard_data)
-{
-	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
-		&& !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
-		event_observed++;
-	}
-}
-
-static void object_type_registered_observer(const char *name,
-	struct ast_sorcery *sorcery, const char *object_type)
-{
-	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
-		event_observed++;
-	}
-}
-
-static void object_type_loaded_observer(const char *name,
-	const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
-{
-	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
-		&& !reloaded) {
-		event_observed++;
-	}
-}
-
-static void object_type_reloaded_observer(const char *name,
-	const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
-{
-	if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
-		&& reloaded) {
-		event_observed++;
-	}
-}
-
-AST_TEST_DEFINE(instance_observation)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	struct ast_sorcery_instance_observer observer = {
-		.wizard_mapped = wizard_mapped_observer,
-		.object_type_registered = object_type_registered_observer,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "instance_observation";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery instance observation test";
-		info->description =
-			"Test observation of sorcery (instance)";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Test instance load */
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open a sorcery instance\n");
-		return AST_TEST_FAIL;
-	}
-	observer.instance_loading = instance_loaded_observer;
-	observer.instance_loaded = instance_loaded_observer;
-	ast_sorcery_instance_observer_add(sorcery, &observer);
-	event_observed = 0;
-	ast_sorcery_load(sorcery);
-	ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
-	event_observed = 0;
-	ast_sorcery_reload(sorcery);
-	ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
-
-	/* Test instance reload */
-	ast_sorcery_instance_observer_remove(sorcery, &observer);
-	observer.instance_loading = instance_reloaded_observer;
-	observer.instance_loaded = instance_reloaded_observer;
-	ast_sorcery_instance_observer_add(sorcery, &observer);
-	event_observed = 0;
-	ast_sorcery_load(sorcery);
-	ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
-	event_observed = 0;
-	ast_sorcery_reload(sorcery);
-	ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
-
-	/* Test wizard mapping */
-	event_observed = 0;
-	ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
-	ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
-
-	/* Test object type register */
-	event_observed = 0;
-	ast_sorcery_internal_object_register(sorcery, "test_object_type",
-		test_sorcery_object_alloc, NULL, NULL);
-	ast_test_validate(test, (event_observed == 1), "Object type registered failed");
-
-	/* Test object type load */
-	ast_sorcery_instance_observer_remove(sorcery, &observer);
-	observer.object_type_loading = object_type_loaded_observer;
-	observer.object_type_loaded = object_type_loaded_observer;
-	ast_sorcery_instance_observer_add(sorcery, &observer);
-	event_observed = 0;
-	ast_sorcery_load_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
-	event_observed = 0;
-	ast_sorcery_reload_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
-
-	/* Test object type reload */
-	ast_sorcery_instance_observer_remove(sorcery, &observer);
-	observer.object_type_loading = object_type_reloaded_observer;
-	observer.object_type_loaded = object_type_reloaded_observer;
-	ast_sorcery_instance_observer_add(sorcery, &observer);
-	event_observed = 0;
-	ast_sorcery_load_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
-	event_observed = 0;
-	ast_sorcery_reload_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
-
-	ast_sorcery_instance_observer_remove(sorcery, &observer);
-	event_observed = 0;
-	ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
-	ast_test_validate(test, (event_observed == 0), "Observer remove failed");
-
-	return AST_TEST_PASS;
-}
-
-static void wizard_loaded_observer(const char *name,
-	const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
-{
-	if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
-		&& !reloaded) {
-		event_observed++;
-	}
-}
-
-static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
-{
-	return;
-}
-
-static void wizard_reloaded_observer(const char *name,
-	const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
-{
-	if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
-		&& reloaded) {
-		event_observed++;
-	}
-}
-
-AST_TEST_DEFINE(wizard_observation)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
-	RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
-	struct ast_sorcery_wizard_observer observer = {
-		.wizard_loading = wizard_loaded_observer,
-		.wizard_loaded = wizard_loaded_observer,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "wizard_observation";
-		info->category = "/main/sorcery/";
-		info->summary = "sorcery wizard observation test";
-		info->description =
-			"Test observation of sorcery (wizard)";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	wizard->load = sorcery_test_load;
-	wizard->reload = sorcery_test_load;
-
-	/* Test wizard observer remove and wizard unregister */
-	ast_sorcery_wizard_register(wizard);
-	ast_sorcery_wizard_observer_add(wizard, &observer);
-	ast_sorcery_wizard_observer_remove(wizard, &observer);
-	event_observed = 0;
-	ast_sorcery_wizard_unregister(wizard);
-	ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
-
-	/* Setup for test loaded and reloaded */
-	if (!(sorcery = ast_sorcery_open())) {
-		ast_test_status_update(test, "Failed to open a sorcery instance\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_sorcery_wizard_register(wizard);
-	ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
-	ast_sorcery_internal_object_register(sorcery, "test_object_type",
-		test_sorcery_object_alloc, NULL, NULL);
-
-	/* Test wizard loading and loaded */
-	ast_sorcery_wizard_observer_add(wizard, &observer);
-
-	event_observed = 0;
-	ast_sorcery_load_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 2), "Wizard loaded failed");
-
-	event_observed = 0;
-	ast_sorcery_reload_object(sorcery, "test_object_type");
-	ast_sorcery_wizard_observer_remove(wizard, &observer);
-	ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
-
-	/* Test wizard reloading and reloaded */
-	observer.wizard_loading = wizard_reloaded_observer;
-	observer.wizard_loaded = wizard_reloaded_observer;
-	ast_sorcery_wizard_observer_add(wizard, &observer);
-
-	event_observed = 0;
-	ast_sorcery_load_object(sorcery, "test_object_type");
-	ast_test_validate(test, (event_observed == 0), "Wizard loaded failed");
-
-	event_observed = 0;
-	ast_sorcery_reload_object(sorcery, "test_object_type");
-	ast_sorcery_wizard_observer_remove(wizard, &observer);
-	ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(wizard_registration);
-	AST_TEST_UNREGISTER(sorcery_open);
-	AST_TEST_UNREGISTER(apply_default);
-	AST_TEST_UNREGISTER(apply_config);
-	AST_TEST_UNREGISTER(object_register);
-	AST_TEST_UNREGISTER(object_register_without_mapping);
-	AST_TEST_UNREGISTER(object_field_register);
-	AST_TEST_UNREGISTER(object_fields_register);
-	AST_TEST_UNREGISTER(object_alloc_with_id);
-	AST_TEST_UNREGISTER(object_alloc_without_id);
-	AST_TEST_UNREGISTER(object_copy);
-	AST_TEST_UNREGISTER(object_copy_native);
-	AST_TEST_UNREGISTER(object_diff);
-	AST_TEST_UNREGISTER(object_diff_native);
-	AST_TEST_UNREGISTER(objectset_create);
-	AST_TEST_UNREGISTER(objectset_json_create);
-	AST_TEST_UNREGISTER(objectset_create_regex);
-	AST_TEST_UNREGISTER(objectset_apply);
-	AST_TEST_UNREGISTER(objectset_apply_handler);
-	AST_TEST_UNREGISTER(objectset_apply_invalid);
-	AST_TEST_UNREGISTER(objectset_transform);
-	AST_TEST_UNREGISTER(objectset_apply_fields);
-	AST_TEST_UNREGISTER(extended_fields);
-	AST_TEST_UNREGISTER(changeset_create);
-	AST_TEST_UNREGISTER(changeset_create_unchanged);
-	AST_TEST_UNREGISTER(object_create);
-	AST_TEST_UNREGISTER(object_retrieve_id);
-	AST_TEST_UNREGISTER(object_retrieve_field);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_all);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_field);
-	AST_TEST_UNREGISTER(object_retrieve_regex);
-	AST_TEST_UNREGISTER(object_update);
-	AST_TEST_UNREGISTER(object_update_uncreated);
-	AST_TEST_UNREGISTER(object_delete);
-	AST_TEST_UNREGISTER(object_delete_uncreated);
-	AST_TEST_UNREGISTER(caching_wizard_behavior);
-	AST_TEST_UNREGISTER(object_type_observer);
-	AST_TEST_UNREGISTER(configuration_file_wizard);
-	AST_TEST_UNREGISTER(configuration_file_wizard_with_file_integrity);
-	AST_TEST_UNREGISTER(configuration_file_wizard_with_criteria);
-	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_field);
-	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
-	AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
-	AST_TEST_UNREGISTER(dialplan_function);
-	AST_TEST_UNREGISTER(object_field_registered);
-	AST_TEST_UNREGISTER(global_observation);
-	AST_TEST_UNREGISTER(instance_observation);
-	AST_TEST_UNREGISTER(wizard_observation);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(wizard_registration);
-	AST_TEST_REGISTER(sorcery_open);
-	AST_TEST_REGISTER(apply_default);
-	AST_TEST_REGISTER(apply_config);
-	AST_TEST_REGISTER(object_register);
-	AST_TEST_REGISTER(object_register_without_mapping);
-	AST_TEST_REGISTER(object_field_register);
-	AST_TEST_REGISTER(object_fields_register);
-	AST_TEST_REGISTER(object_alloc_with_id);
-	AST_TEST_REGISTER(object_alloc_without_id);
-	AST_TEST_REGISTER(object_copy);
-	AST_TEST_REGISTER(object_copy_native);
-	AST_TEST_REGISTER(object_diff);
-	AST_TEST_REGISTER(object_diff_native);
-	AST_TEST_REGISTER(objectset_create);
-	AST_TEST_REGISTER(objectset_json_create);
-	AST_TEST_REGISTER(objectset_create_regex);
-	AST_TEST_REGISTER(objectset_apply);
-	AST_TEST_REGISTER(objectset_apply_handler);
-	AST_TEST_REGISTER(objectset_apply_invalid);
-	AST_TEST_REGISTER(objectset_transform);
-	AST_TEST_REGISTER(objectset_apply_fields);
-	AST_TEST_REGISTER(extended_fields);
-	AST_TEST_REGISTER(changeset_create);
-	AST_TEST_REGISTER(changeset_create_unchanged);
-	AST_TEST_REGISTER(object_create);
-	AST_TEST_REGISTER(object_retrieve_id);
-	AST_TEST_REGISTER(object_retrieve_field);
-	AST_TEST_REGISTER(object_retrieve_multiple_all);
-	AST_TEST_REGISTER(object_retrieve_multiple_field);
-	AST_TEST_REGISTER(object_retrieve_regex);
-	AST_TEST_REGISTER(object_update);
-	AST_TEST_REGISTER(object_update_uncreated);
-	AST_TEST_REGISTER(object_delete);
-	AST_TEST_REGISTER(object_delete_uncreated);
-	AST_TEST_REGISTER(caching_wizard_behavior);
-	AST_TEST_REGISTER(object_type_observer);
-	AST_TEST_REGISTER(configuration_file_wizard);
-	AST_TEST_REGISTER(configuration_file_wizard_with_file_integrity);
-	AST_TEST_REGISTER(configuration_file_wizard_with_criteria);
-	AST_TEST_REGISTER(configuration_file_wizard_retrieve_field);
-	AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
-	AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
-	AST_TEST_REGISTER(dialplan_function);
-	AST_TEST_REGISTER(object_field_registered);
-	AST_TEST_REGISTER(global_observation);
-	AST_TEST_REGISTER(instance_observation);
-	AST_TEST_REGISTER(wizard_observation);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery test module");
diff --git a/tests/test_sorcery_astdb.c b/tests/test_sorcery_astdb.c
deleted file mode 100644
index b87ed74..0000000
--- a/tests/test_sorcery_astdb.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Sorcery Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astdb.h"
-#include "asterisk/logger.h"
-
-/*! \brief Dummy sorcery object */
-struct test_sorcery_object {
-	SORCERY_OBJECT(details);
-	unsigned int bob;
-	unsigned int joe;
-};
-
-/*! \brief Internal function to allocate a test object */
-static void *test_sorcery_object_alloc(const char *id)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
-}
-
-static struct ast_sorcery *alloc_and_initialize_sorcery(void)
-{
-	struct ast_sorcery *sorcery;
-
-	if (!(sorcery = ast_sorcery_open())) {
-		return NULL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "astdb", "test") != AST_SORCERY_APPLY_SUCCESS) ||
-		ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
-		ast_sorcery_unref(sorcery);
-		return NULL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	return sorcery;
-}
-
-static void deinitialize_sorcery(struct ast_sorcery *sorcery)
-{
-	ast_db_deltree("test/test", NULL);
-	ast_sorcery_unref(sorcery);
-}
-
-AST_TEST_DEFINE(object_create)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	char value[2];
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_create";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery astdb object creation unit test";
-		info->description =
-			"Test object creation in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	} else if (ast_db_get("test/test", "blah", value, sizeof(value))) {
-		ast_test_status_update(test, "Object was apparently created but does not actually exist in astdb\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_id)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_id";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object retrieval using id unit test";
-		info->description =
-			"Test object retrieval using id in sorcery with astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
-		ast_test_status_update(test, "Retrieved object does not have correct id\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_field";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object retrieval using a specific field unit test";
-		info->description =
-			"Test object retrieval using a specific field in sorcery with astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 42;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "49", ""))) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_all)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_all";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_field";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using fields using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 6;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 1) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(objects);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "7", ""))) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
-		return AST_TEST_FAIL;
-	} else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects)) {
-		ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_regex)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_regex";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery multiple object retrieval using regex unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using regular expression for matching using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
-		ast_test_status_update(test, "Failed to retrieve a container of objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test object updating in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	obj2->bob = 1000;
-	obj2->joe = 2000;
-
-	if (ast_sorcery_update(sorcery, obj2)) {
-		ast_test_status_update(test, "Failed to update sorcery with new object\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly updated object\n");
-		return AST_TEST_FAIL;
-	} else if ((obj->bob != obj2->bob) || (obj->joe != obj2->joe)) {
-		ast_test_status_update(test, "Object retrieved is not the updated object\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update_uncreated";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test updating of an uncreated object in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_update(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to delete object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete_uncreated";
-		info->category = "/res/sorcery_astdb/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion of an uncreated object in sorcery using astdb wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully deleted an object which was never created\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(object_create);
-	AST_TEST_UNREGISTER(object_retrieve_id);
-	AST_TEST_UNREGISTER(object_retrieve_field);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_all);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_field);
-	AST_TEST_UNREGISTER(object_retrieve_regex);
-	AST_TEST_UNREGISTER(object_update);
-	AST_TEST_UNREGISTER(object_update_uncreated);
-	AST_TEST_UNREGISTER(object_delete);
-	AST_TEST_UNREGISTER(object_delete_uncreated);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(object_create);
-	AST_TEST_REGISTER(object_retrieve_id);
-	AST_TEST_REGISTER(object_retrieve_field);
-	AST_TEST_REGISTER(object_retrieve_multiple_all);
-	AST_TEST_REGISTER(object_retrieve_multiple_field);
-	AST_TEST_REGISTER(object_retrieve_regex);
-	AST_TEST_REGISTER(object_update);
-	AST_TEST_REGISTER(object_update_uncreated);
-	AST_TEST_REGISTER(object_delete);
-	AST_TEST_REGISTER(object_delete_uncreated);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery astdb Wizard test module");
diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c
deleted file mode 100644
index ab9c188..0000000
--- a/tests/test_sorcery_realtime.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Joshua Colp <jcolp at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Sorcery Unit Tests
- *
- * \author Joshua Colp <jcolp at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/sorcery.h"
-#include "asterisk/astdb.h"
-#include "asterisk/logger.h"
-
-/*! \brief Configuration structure which contains all stored objects */
-static struct ast_config *realtime_objects;
-
-/*! \brief Helper function which finds a given variable */
-static const struct ast_variable *realtime_find_variable(const struct ast_variable *fields, const char *name)
-{
-	const struct ast_variable *variable;
-
-	for (variable = fields; variable; variable = variable->next) {
-		if (!strcmp(variable->name, name)) {
-			return variable;
-		}
-	}
-
-	return NULL;
-}
-
-/*! \brief Helper function which returns if an object is matching or not */
-static int realtime_is_object_matching(const char *object_id, const struct ast_variable *fields)
-{
-	const struct ast_variable *field;
-
-	for (field = fields; field; field = field->next) {
-		char *name = ast_strdupa(field->name), *like;
-		const char *value;
-
-		/* If we are doing a pattern matching we need to remove the LIKE from the name */
-		if ((like = strstr(name, " LIKE"))) {
-			char *pattern, *field_value = ast_strdupa(field->value);
-
-			*like = '\0';
-
-			value = ast_strdupa(ast_variable_retrieve(realtime_objects, object_id, name));
-
-			if (!(pattern = strchr(field_value, '%'))) {
-				return 0;
-			}
-
-			*pattern = '\0';
-
-			if (strncmp(value, field_value, strlen(field_value))) {
-				return 0;
-			}
-		} else {
-			value = ast_variable_retrieve(realtime_objects, object_id, name);
-
-			if (ast_strlen_zero(value) || strcmp(value, field->value)) {
-				return 0;
-			}
-		}
-	}
-
-	return 1;
-}
-
-static struct ast_variable *realtime_sorcery(const char *database, const char *table, const struct ast_variable *fields)
-{
-	char *object_id = NULL;
-
-	while ((object_id = ast_category_browse(realtime_objects, object_id))) {
-		if (!realtime_is_object_matching(object_id, fields)) {
-			continue;
-		}
-
-		return ast_variables_dup(ast_category_root(realtime_objects, object_id));
-	}
-
-	return NULL;
-}
-
-static struct ast_config *realtime_sorcery_multi(const char *database, const char *table, const struct ast_variable *fields)
-{
-	struct ast_config *objects;
-	char *object_id = NULL;
-
-	if (!(objects = ast_config_new())) {
-		return NULL;
-	}
-
-	while ((object_id = ast_category_browse(realtime_objects, object_id))) {
-		struct ast_category *object;
-
-		if (!realtime_is_object_matching(object_id, fields)) {
-			continue;
-		}
-
-		if (!(object = ast_category_new("", "", 0))) {
-			ast_config_destroy(objects);
-			return NULL;
-		}
-
-		ast_variable_append(object, ast_variables_dup(ast_category_root(realtime_objects, object_id)));
-		ast_category_append(objects, object);
-	}
-
-	return objects;
-}
-
-static int realtime_sorcery_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
-{
-	struct ast_category *object, *found;
-
-	if (!(found = ast_category_get(realtime_objects, entity, NULL))) {
-		return 0;
-	} else if (!(object = ast_category_new(entity, "", 0))) {
-		return -1;
-	}
-
-	ast_category_delete(realtime_objects, found);
-	ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
-	ast_variable_append(object, ast_variable_new(keyfield, entity, ""));
-	ast_category_append(realtime_objects, object);
-
-	return 1;
-}
-
-static int realtime_sorcery_store(const char *database, const char *table, const struct ast_variable *fields)
-{
-	/* The key field is explicit within res_sorcery_realtime */
-	const struct ast_variable *keyfield = realtime_find_variable(fields, "id");
-	struct ast_category *object;
-
-	if (!keyfield || ast_category_exist(realtime_objects, keyfield->value, NULL) || !(object = ast_category_new(keyfield->value, "", 0))) {
-		return -1;
-	}
-
-	ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
-	ast_category_append(realtime_objects, object);
-
-	return 1;
-}
-
-static int realtime_sorcery_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
-{
-	struct ast_category *found;
-	if (!(found = ast_category_get(realtime_objects, entity, NULL))) {
-		return 0;
-	}
-
-	ast_category_delete(realtime_objects, found);
-
-	return 1;
-}
-
-struct ast_config_engine sorcery_config_engine = {
-	.name = "sorcery_realtime_test",
-	.realtime_func = realtime_sorcery,
-	.realtime_multi_func = realtime_sorcery_multi,
-	.update_func = realtime_sorcery_update,
-	.store_func = realtime_sorcery_store,
-	.destroy_func = realtime_sorcery_destroy,
-};
-
-/*! \brief Dummy sorcery object */
-struct test_sorcery_object {
-	SORCERY_OBJECT(details);
-	unsigned int bob;
-	unsigned int joe;
-};
-
-/*! \brief Internal function to allocate a test object */
-static void *test_sorcery_object_alloc(const char *id)
-{
-	return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
-}
-
-static struct ast_sorcery *alloc_and_initialize_sorcery(void)
-{
-	struct ast_sorcery *sorcery;
-
-	if (!(sorcery = ast_sorcery_open())) {
-		return NULL;
-	}
-
-	if ((ast_sorcery_apply_default(sorcery, "test", "realtime", "sorcery_realtime_test") != AST_SORCERY_APPLY_SUCCESS) ||
-		ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL) ||
-		!(realtime_objects = ast_config_new())) {
-		ast_sorcery_unref(sorcery);
-		return NULL;
-	}
-
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
-	ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
-
-	return sorcery;
-}
-
-static void deinitialize_sorcery(struct ast_sorcery *sorcery)
-{
-	ast_config_destroy(realtime_objects);
-	realtime_objects = NULL;
-	ast_sorcery_unref(sorcery);
-}
-
-AST_TEST_DEFINE(object_create)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_create";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery realtime object creation unit test";
-		info->description =
-			"Test object creation in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_id)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_id";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object retrieval using id unit test";
-		info->description =
-			"Test object retrieval using id in sorcery with realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
-		return AST_TEST_FAIL;
-	} else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
-		ast_test_status_update(test, "Retrieved object does not have correct id\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_field";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object retrieval using a specific field unit test";
-		info->description =
-			"Test object retrieval using a specific field in sorcery with realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 42;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "49", ""))) {
-		ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
-		return AST_TEST_FAIL;
-	}
-
-	if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
-		ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_all)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_all";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_multiple_field)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_multiple_field";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery multiple object retrieval unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using fields using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!fields) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	obj->joe = 6;
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 1) {
-		ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(objects);
-	ast_variables_destroy(fields);
-
-	if (!(fields = ast_variable_new("joe", "7", ""))) {
-		ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
-		return AST_TEST_FAIL;
-	} else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
-		ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects)) {
-		ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_retrieve_regex)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_retrieve_regex";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery multiple object retrieval using regex unit test";
-		info->description =
-			"Test multiple object retrieval in sorcery using regular expression for matching using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
-		ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
-		ast_test_status_update(test, "Failed to retrieve a container of objects\n");
-		return AST_TEST_FAIL;
-	} else if (ao2_container_count(objects) != 2) {
-		ast_test_status_update(test, "Received a container with incorrect number of objects in it: %d instead of 2\n", ao2_container_count(objects));
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test object updating in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
-		ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	obj2->bob = 1000;
-	obj2->joe = 2000;
-
-	if (ast_sorcery_update(sorcery, obj2)) {
-		ast_test_status_update(test, "Failed to update sorcery with new object\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly updated object\n");
-		return AST_TEST_FAIL;
-	} else if ((obj->bob != obj2->bob) || (obj->joe != obj2->joe)) {
-		ast_test_status_update(test, "Object retrieved is not the updated object\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_update_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_update_uncreated";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object update unit test";
-		info->description =
-			"Test updating of an uncreated object in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_update(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_create(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to create object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Failed to delete object using realtime wizard\n");
-		return AST_TEST_FAIL;
-	}
-
-	ao2_cleanup(obj);
-
-	if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_delete_uncreated)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_delete_uncreated";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object deletion unit test";
-		info->description =
-			"Test object deletion of an uncreated object in sorcery using realtime wizard";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate a known object type\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (!ast_sorcery_delete(sorcery, obj)) {
-		ast_test_status_update(test, "Successfully deleted an object which was never created\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(object_allocate_on_retrieval)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	struct ast_category *cat;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_allocate_on_retrieval";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object allocation upon retrieval unit test";
-		info->description =
-			"This test creates data in a realtime backend, not through sorcery. Sorcery is then\n"
-			"instructed to retrieve an object with the id of the object that was created in the\n"
-			"realtime backend. Sorcery should be able to allocate the object appropriately";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	cat = ast_category_new("blah", "", 0);
-	ast_variable_append(cat, ast_variable_new("id", "blah", ""));
-	ast_variable_append(cat, ast_variable_new("bob", "42", ""));
-	ast_variable_append(cat, ast_variable_new("joe", "93", ""));
-	ast_category_append(realtime_objects, cat);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to allocate object 'blah' base on realtime data\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (obj->bob != 42) {
-		ast_test_status_update(test, "Object's 'bob' field does not have expected value: %u != 42\n",
-				obj->bob);
-		return AST_TEST_FAIL;
-	} else if (obj->joe != 93) {
-		ast_test_status_update(test, "Object's 'joe' field does not have expected value: %u != 93\n",
-				obj->joe);
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-
-AST_TEST_DEFINE(object_filter)
-{
-	RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
-	RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-	struct ast_category *cat;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "object_filter";
-		info->category = "/res/sorcery_realtime/";
-		info->summary = "sorcery object field filter unit test";
-		info->description =
-			"This test creates data in a realtime backend, not through sorcery. In addition to\n"
-			"the object fields that have been registered with sorcery, there is data in the\n"
-			"realtime backend that is unknown to sorcery. When sorcery attempts to retrieve\n"
-			"the object from the realtime backend, the data unknown to sorcery should be\n"
-			"filtered out of the returned objectset, and the object should be successfully\n"
-			"allocated by sorcery\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (!(sorcery = alloc_and_initialize_sorcery())) {
-		ast_test_status_update(test, "Failed to open sorcery structure\n");
-		return AST_TEST_FAIL;
-	}
-
-	cat = ast_category_new("blah", "", 0);
-	ast_variable_append(cat, ast_variable_new("id", "blah", ""));
-	ast_variable_append(cat, ast_variable_new("bob", "42", ""));
-	ast_variable_append(cat, ast_variable_new("joe", "93", ""));
-	ast_variable_append(cat, ast_variable_new("fred", "50", ""));
-	ast_category_append(realtime_objects, cat);
-
-	if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
-		ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (obj->bob != 42) {
-		ast_test_status_update(test, "Object's 'bob' field does not have expected value: %u != 42\n",
-				obj->bob);
-		return AST_TEST_FAIL;
-	} else if (obj->joe != 93) {
-		ast_test_status_update(test, "Object's 'joe' field does not have expected value: %u != 93\n",
-				obj->joe);
-		return AST_TEST_FAIL;
-	}
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	ast_config_engine_deregister(&sorcery_config_engine);
-	AST_TEST_UNREGISTER(object_create);
-	AST_TEST_UNREGISTER(object_retrieve_id);
-	AST_TEST_UNREGISTER(object_retrieve_field);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_all);
-	AST_TEST_UNREGISTER(object_retrieve_multiple_field);
-	AST_TEST_UNREGISTER(object_retrieve_regex);
-	AST_TEST_UNREGISTER(object_update);
-	AST_TEST_UNREGISTER(object_update_uncreated);
-	AST_TEST_UNREGISTER(object_delete);
-	AST_TEST_UNREGISTER(object_delete_uncreated);
-	AST_TEST_UNREGISTER(object_allocate_on_retrieval);
-	AST_TEST_UNREGISTER(object_filter);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	ast_config_engine_register(&sorcery_config_engine);
-	ast_realtime_append_mapping("sorcery_realtime_test", "sorcery_realtime_test", "test", "test", 1);
-	AST_TEST_REGISTER(object_create);
-	AST_TEST_REGISTER(object_retrieve_id);
-	AST_TEST_REGISTER(object_retrieve_field);
-	AST_TEST_REGISTER(object_retrieve_multiple_all);
-	AST_TEST_REGISTER(object_retrieve_multiple_field);
-	AST_TEST_REGISTER(object_retrieve_regex);
-	AST_TEST_REGISTER(object_update);
-	AST_TEST_REGISTER(object_update_uncreated);
-	AST_TEST_REGISTER(object_delete);
-	AST_TEST_REGISTER(object_delete_uncreated);
-	AST_TEST_REGISTER(object_allocate_on_retrieval);
-	AST_TEST_REGISTER(object_filter);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery Realtime Wizard test module");
diff --git a/tests/test_stasis.c b/tests/test_stasis.c
deleted file mode 100644
index b4ea07e..0000000
--- a/tests/test_stasis.c
+++ /dev/null
@@ -1,2109 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test Stasis message bus.
- *
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 428815 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/test.h"
-
-static const char *test_category = "/stasis/core/";
-
-static struct ast_json *fake_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
-{
-	const char *text = stasis_message_data(message);
-
-	return ast_json_string_create(text);
-}
-
-static struct ast_manager_event_blob *fake_ami(struct stasis_message *message)
-{
-	RAII_VAR(struct ast_manager_event_blob *, res, NULL, ao2_cleanup);
-	const char *text = stasis_message_data(message);
-
-	res = ast_manager_event_blob_create(EVENT_FLAG_TEST, "FakeMI",
-		"Message: %s\r\n", text);
-
-	if (res == NULL) {
-		return NULL;
-	}
-
-	ao2_ref(res, +1);
-	return res;
-}
-
-static struct stasis_message_vtable fake_vtable = {
-	.to_json = fake_json,
-	.to_ami = fake_ami
-};
-
-AST_TEST_DEFINE(message_type)
-{
-	RAII_VAR(struct stasis_message_type *, uut, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test basic message_type functions";
-		info->description = "Test basic message_type functions";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create(NULL, NULL, NULL) == STASIS_MESSAGE_TYPE_ERROR);
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", NULL, &uut) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, 0 == strcmp(stasis_message_type_name(uut), "SomeMessage"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(message)
-{
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut2, NULL, ao2_cleanup);
-	RAII_VAR(char *, data, NULL, ao2_cleanup);
-	char *expected = "SomeData";
-	struct timeval expected_timestamp;
-	struct timeval time_diff;
-	struct ast_eid foreign_eid;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test basic message functions";
-		info->description = "Test basic message functions";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-
-	memset(&foreign_eid, 0xFF, sizeof(foreign_eid));
-
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-
-	ast_test_validate(test, NULL == stasis_message_create_full(NULL, NULL, NULL));
-	ast_test_validate(test, NULL == stasis_message_create_full(type, NULL, NULL));
-
-	data = ao2_alloc(strlen(expected) + 1, NULL);
-	strcpy(data, expected);/* Safe */
-	expected_timestamp = ast_tvnow();
-	uut1 = stasis_message_create_full(type, data, &foreign_eid);
-	uut2 = stasis_message_create_full(type, data, NULL);
-
-	ast_test_validate(test, NULL != uut1);
-	ast_test_validate(test, NULL != uut2);
-	ast_test_validate(test, type == stasis_message_type(uut1));
-	ast_test_validate(test, type == stasis_message_type(uut2));
-	ast_test_validate(test, 0 == strcmp(expected, stasis_message_data(uut1)));
-	ast_test_validate(test, 0 == strcmp(expected, stasis_message_data(uut2)));
-	ast_test_validate(test, NULL != stasis_message_eid(uut1));
-	ast_test_validate(test, NULL == stasis_message_eid(uut2));
-	ast_test_validate(test, !ast_eid_cmp(&foreign_eid, stasis_message_eid(uut1)));
-
-	ast_test_validate(test, 3 == ao2_ref(data, 0)); /* uut1 and uut2 have ref to data */
-
-	time_diff = ast_tvsub(*stasis_message_timestamp(uut1), expected_timestamp);
-	/* 10ms is certainly long enough for the two calls to complete */
-	ast_test_validate(test, time_diff.tv_sec == 0);
-	ast_test_validate(test, time_diff.tv_usec < 10000);
-
-	ao2_ref(uut1, -1);
-	uut1 = NULL;
-	ast_test_validate(test, 2 == ao2_ref(data, 0)); /* uut1 unreffed data */
-	ao2_ref(uut2, -1);
-	uut2 = NULL;
-	ast_test_validate(test, 1 == ao2_ref(data, 0)); /* uut2 unreffed data */
-
-	return AST_TEST_PASS;
-}
-
-struct consumer {
-	ast_cond_t out;
-	struct stasis_message **messages_rxed;
-	size_t messages_rxed_len;
-	int ignore_subscriptions;
-	int complete;
-};
-
-static void consumer_dtor(void *obj)
-{
-	struct consumer *consumer = obj;
-
-	ast_cond_destroy(&consumer->out);
-
-	while (consumer->messages_rxed_len > 0) {
-		ao2_cleanup(consumer->messages_rxed[--consumer->messages_rxed_len]);
-	}
-	ast_free(consumer->messages_rxed);
-	consumer->messages_rxed = NULL;
-}
-
-static struct consumer *consumer_create(int ignore_subscriptions)
-{
-	struct consumer *consumer;
-
-	consumer = ao2_alloc(sizeof(*consumer), consumer_dtor);
-	if (!consumer) {
-		return NULL;
-	}
-
-	consumer->ignore_subscriptions = ignore_subscriptions;
-	consumer->messages_rxed = ast_malloc(sizeof(*consumer->messages_rxed));
-	if (!consumer->messages_rxed) {
-		ao2_cleanup(consumer);
-		return NULL;
-	}
-
-	ast_cond_init(&consumer->out, NULL);
-
-	return consumer;
-}
-
-static void consumer_exec(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct consumer *consumer = data;
-	RAII_VAR(struct consumer *, consumer_needs_cleanup, NULL, ao2_cleanup);
-	SCOPED_AO2LOCK(lock, consumer);
-
-	if (!consumer->ignore_subscriptions || stasis_message_type(message) != stasis_subscription_change_type()) {
-		++consumer->messages_rxed_len;
-		consumer->messages_rxed = ast_realloc(consumer->messages_rxed, sizeof(*consumer->messages_rxed) * consumer->messages_rxed_len);
-		ast_assert(consumer->messages_rxed != NULL);
-		consumer->messages_rxed[consumer->messages_rxed_len - 1] = message;
-		ao2_ref(message, +1);
-	}
-
-	if (stasis_subscription_final_message(sub, message)) {
-		consumer->complete = 1;
-		consumer_needs_cleanup = consumer;
-	}
-
-	ast_cond_signal(&consumer->out);
-}
-
-static void consumer_exec_sync(void *data, struct stasis_subscription *sub, struct stasis_message *message)
-{
-	struct consumer *consumer = data;
-	RAII_VAR(struct consumer *, consumer_needs_cleanup, NULL, ao2_cleanup);
-	SCOPED_AO2LOCK(lock, consumer);
-
-	if (!consumer->ignore_subscriptions || stasis_message_type(message) != stasis_subscription_change_type()) {
-		++consumer->messages_rxed_len;
-		consumer->messages_rxed = ast_realloc(consumer->messages_rxed, sizeof(*consumer->messages_rxed) * consumer->messages_rxed_len);
-		ast_assert(consumer->messages_rxed != NULL);
-		consumer->messages_rxed[consumer->messages_rxed_len - 1] = message;
-		ao2_ref(message, +1);
-	}
-
-	if (stasis_subscription_final_message(sub, message)) {
-		consumer->complete = 1;
-		consumer_needs_cleanup = consumer;
-	}
-}
-
-static int consumer_wait_for(struct consumer *consumer, size_t expected_len)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 30,
-		.tv_nsec = start.tv_usec * 1000
-	};
-
-	SCOPED_AO2LOCK(lock, consumer);
-
-	while (consumer->messages_rxed_len < expected_len) {
-		int r = ast_cond_timedwait(&consumer->out, ao2_object_get_lockaddr(consumer), &end);
-
-		if (r == ETIMEDOUT) {
-			break;
-		}
-		ast_assert(r == 0); /* Not expecting any othet types of errors */
-	}
-	return consumer->messages_rxed_len;
-}
-
-static int consumer_wait_for_completion(struct consumer *consumer)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 3,
-		.tv_nsec = start.tv_usec * 1000
-	};
-
-	SCOPED_AO2LOCK(lock, consumer);
-
-	while (!consumer->complete) {
-		int r = ast_cond_timedwait(&consumer->out, ao2_object_get_lockaddr(consumer), &end);
-
-		if (r == ETIMEDOUT) {
-			break;
-		}
-		ast_assert(r == 0); /* Not expecting any othet types of errors */
-	}
-	return consumer->complete;
-}
-
-static int consumer_should_stay(struct consumer *consumer, size_t expected_len)
-{
-	struct timeval start = ast_tvnow();
-	struct timeval diff = {
-		.tv_sec = 0,
-		.tv_usec = 100000 /* wait for 100ms */
-	};
-	struct timeval end_tv = ast_tvadd(start, diff);
-	struct timespec end = {
-		.tv_sec = end_tv.tv_sec,
-		.tv_nsec = end_tv.tv_usec * 1000
-	};
-
-	SCOPED_AO2LOCK(lock, consumer);
-
-	while (consumer->messages_rxed_len == expected_len) {
-		int r = ast_cond_timedwait(&consumer->out, ao2_object_get_lockaddr(consumer), &end);
-
-		if (r == ETIMEDOUT) {
-			break;
-		}
-		ast_assert(r == 0); /* Not expecting any othet types of errors */
-	}
-	return consumer->messages_rxed_len;
-}
-
-AST_TEST_DEFINE(subscription_messages)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(char *, expected_uniqueid, NULL, ast_free);
-	int complete;
-	struct stasis_subscription_change *change;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test subscribe/unsubscribe messages";
-		info->description = "Test subscribe/unsubscribe messages";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(0);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-	expected_uniqueid = ast_strdup(stasis_subscription_uniqueid(uut));
-
-	uut = stasis_unsubscribe(uut);
-	complete = consumer_wait_for_completion(consumer);
-	ast_test_validate(test, 1 == complete);
-
-	ast_test_validate(test, 2 == consumer->messages_rxed_len);
-	ast_test_validate(test, stasis_subscription_change_type() == stasis_message_type(consumer->messages_rxed[0]));
-	ast_test_validate(test, stasis_subscription_change_type() == stasis_message_type(consumer->messages_rxed[1]));
-
-	change = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, topic == change->topic);
-	ast_test_validate(test, 0 == strcmp("Subscribe", change->description));
-	ast_test_validate(test, 0 == strcmp(expected_uniqueid, change->uniqueid));
-
-	change = stasis_message_data(consumer->messages_rxed[1]);
-	ast_test_validate(test, topic == change->topic);
-	ast_test_validate(test, 0 == strcmp("Unsubscribe", change->description));
-	ast_test_validate(test, 0 == strcmp(expected_uniqueid, change->uniqueid));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(subscription_pool_messages)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(char *, expected_uniqueid, NULL, ast_free);
-	int complete;
-	struct stasis_subscription_change *change;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test subscribe/unsubscribe messages using a threadpool subscription";
-		info->description = "Test subscribe/unsubscribe messages using a threadpool subscription";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(0);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe_pool(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-	expected_uniqueid = ast_strdup(stasis_subscription_uniqueid(uut));
-
-	uut = stasis_unsubscribe(uut);
-	complete = consumer_wait_for_completion(consumer);
-	ast_test_validate(test, 1 == complete);
-
-	ast_test_validate(test, 2 == consumer->messages_rxed_len);
-	ast_test_validate(test, stasis_subscription_change_type() == stasis_message_type(consumer->messages_rxed[0]));
-	ast_test_validate(test, stasis_subscription_change_type() == stasis_message_type(consumer->messages_rxed[1]));
-
-	change = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, topic == change->topic);
-	ast_test_validate(test, 0 == strcmp("Subscribe", change->description));
-	ast_test_validate(test, 0 == strcmp(expected_uniqueid, change->uniqueid));
-
-	change = stasis_message_data(consumer->messages_rxed[1]);
-	ast_test_validate(test, topic == change->topic);
-	ast_test_validate(test, 0 == strcmp("Unsubscribe", change->description));
-	ast_test_validate(test, 0 == strcmp(expected_uniqueid, change->uniqueid));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(publish)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	int actual_len;
-	const char *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test publishing";
-		info->description = "Test publishing";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	ast_test_validate(test, stasis_message_type_create("TestMessage", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	test_message = stasis_message_create(test_message_type, test_data);
-
-	stasis_publish(topic, test_message);
-
-	actual_len = consumer_wait_for(consumer, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, test_data == actual);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(publish_sync)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	int actual_len;
-	const char *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test synchronous publishing";
-		info->description = "Test synchronous publishing";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe(topic, consumer_exec_sync, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	ast_test_validate(test, stasis_message_type_create("TestMessage", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	test_message = stasis_message_create(test_message_type, test_data);
-
-	stasis_publish_sync(uut, test_message);
-
-	actual_len = consumer->messages_rxed_len;
-	ast_test_validate(test, 1 == actual_len);
-	actual = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, test_data == actual);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(publish_pool)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	int actual_len;
-	const char *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test publishing with a threadpool";
-		info->description = "Test publishing to a subscriber whose\n"
-			"subscription dictates messages are received through a\n"
-			"threadpool.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe_pool(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	ast_test_validate(test, stasis_message_type_create("TestMessage", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	test_message = stasis_message_create(test_message_type, test_data);
-
-	stasis_publish(topic, test_message);
-
-	actual_len = consumer_wait_for(consumer, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, test_data == actual);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(unsubscribe_stops_messages)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, uut, NULL, stasis_unsubscribe);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	int actual_len;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test simple subscriptions";
-		info->description = "Test simple subscriptions";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	uut = stasis_subscribe(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != uut);
-	ao2_ref(consumer, +1);
-
-	uut = stasis_unsubscribe(uut);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	ast_test_validate(test, stasis_message_type_create("TestMessage", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	test_message = stasis_message_create(test_message_type, test_data);
-
-	stasis_publish(topic, test_message);
-
-	actual_len = consumer_should_stay(consumer, 0);
-	ast_test_validate(test, 0 == actual_len);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(forward)
-{
-	RAII_VAR(struct stasis_topic *, parent_topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-
-	RAII_VAR(struct consumer *, parent_consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_forward *, forward_sub, NULL, stasis_forward_cancel);
-	RAII_VAR(struct stasis_subscription *, parent_sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	int actual_len;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test sending events to a parent topic";
-		info->description = "Test sending events to a parent topic.\n"
-			"This test creates three topics (one parent, two children)\n"
-			"and publishes a message to one child, and verifies it's\n"
-			"only seen by that child and the parent";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	parent_topic = stasis_topic_create("ParentTestTopic");
-	ast_test_validate(test, NULL != parent_topic);
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	forward_sub = stasis_forward_all(topic, parent_topic);
-	ast_test_validate(test, NULL != forward_sub);
-
-	parent_consumer = consumer_create(1);
-	ast_test_validate(test, NULL != parent_consumer);
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	parent_sub = stasis_subscribe(parent_topic, consumer_exec, parent_consumer);
-	ast_test_validate(test, NULL != parent_sub);
-	ao2_ref(parent_consumer, +1);
-	sub = stasis_subscribe(topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != sub);
-	ao2_ref(consumer, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	ast_test_validate(test, stasis_message_type_create("TestMessage", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	test_message = stasis_message_create(test_message_type, test_data);
-
-	stasis_publish(topic, test_message);
-
-	actual_len = consumer_wait_for(consumer, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(parent_consumer, 1);
-	ast_test_validate(test, 1 == actual_len);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(interleaving)
-{
-	RAII_VAR(struct stasis_topic *, parent_topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic2, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_message *, test_message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message3, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_forward *, forward_sub1, NULL, stasis_forward_cancel);
-	RAII_VAR(struct stasis_forward *, forward_sub2, NULL, stasis_forward_cancel);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-
-	int actual_len;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test sending interleaved events to a parent topic";
-		info->description = "Test sending events to a parent topic.\n"
-			"This test creates three topics (one parent, two children)\n"
-			"and publishes messages alternately between the children.\n"
-			"It verifies that the messages are received in the expected\n"
-			"order.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("test", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-
-	test_message1 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message1);
-	test_message2 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message2);
-	test_message3 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message3);
-
-	parent_topic = stasis_topic_create("ParentTestTopic");
-	ast_test_validate(test, NULL != parent_topic);
-	topic1 = stasis_topic_create("Topic1");
-	ast_test_validate(test, NULL != topic1);
-	topic2 = stasis_topic_create("Topic2");
-	ast_test_validate(test, NULL != topic2);
-
-	forward_sub1 = stasis_forward_all(topic1, parent_topic);
-	ast_test_validate(test, NULL != forward_sub1);
-	forward_sub2 = stasis_forward_all(topic2, parent_topic);
-	ast_test_validate(test, NULL != forward_sub2);
-
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-
-	sub = stasis_subscribe(parent_topic, consumer_exec, consumer);
-	ast_test_validate(test, NULL != sub);
-	ao2_ref(consumer, +1);
-
-	stasis_publish(topic1, test_message1);
-	stasis_publish(topic2, test_message2);
-	stasis_publish(topic1, test_message3);
-
-	actual_len = consumer_wait_for(consumer, 3);
-	ast_test_validate(test, 3 == actual_len);
-
-	ast_test_validate(test, test_message1 == consumer->messages_rxed[0]);
-	ast_test_validate(test, test_message2 == consumer->messages_rxed[1]);
-	ast_test_validate(test, test_message3 == consumer->messages_rxed[2]);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(subscription_interleaving)
-{
-	RAII_VAR(struct stasis_topic *, parent_topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic2, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_message_type *, test_message_type, NULL, ao2_cleanup);
-
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_message *, test_message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message3, NULL, ao2_cleanup);
-
-	RAII_VAR(struct stasis_forward *, forward_sub1, NULL, stasis_forward_cancel);
-	RAII_VAR(struct stasis_forward *, forward_sub2, NULL, stasis_forward_cancel);
-	RAII_VAR(struct stasis_subscription *, sub1, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_subscription *, sub2, NULL, stasis_unsubscribe);
-
-	RAII_VAR(struct consumer *, consumer1, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer2, NULL, ao2_cleanup);
-
-	int actual_len;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test sending interleaved events to a parent topic with different subscribers";
-		info->description = "Test sending events to a parent topic.\n"
-			"This test creates three topics (one parent, two children)\n"
-			"and publishes messages alternately between the children.\n"
-			"It verifies that the messages are received in the expected\n"
-			"order, for different subscription types: one with a dedicated\n"
-			"thread, the other on the Stasis threadpool.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("test", NULL, &test_message_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-
-	test_message1 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message1);
-	test_message2 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message2);
-	test_message3 = stasis_message_create(test_message_type, test_data);
-	ast_test_validate(test, NULL != test_message3);
-
-	parent_topic = stasis_topic_create("ParentTestTopic");
-	ast_test_validate(test, NULL != parent_topic);
-	topic1 = stasis_topic_create("Topic1");
-	ast_test_validate(test, NULL != topic1);
-	topic2 = stasis_topic_create("Topic2");
-	ast_test_validate(test, NULL != topic2);
-
-	forward_sub1 = stasis_forward_all(topic1, parent_topic);
-	ast_test_validate(test, NULL != forward_sub1);
-	forward_sub2 = stasis_forward_all(topic2, parent_topic);
-	ast_test_validate(test, NULL != forward_sub2);
-
-	consumer1 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer1);
-
-	consumer2 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer2);
-
-	sub1 = stasis_subscribe(parent_topic, consumer_exec, consumer1);
-	ast_test_validate(test, NULL != sub1);
-	ao2_ref(consumer1, +1);
-
-	sub2 = stasis_subscribe_pool(parent_topic, consumer_exec, consumer2);
-	ast_test_validate(test, NULL != sub2);
-	ao2_ref(consumer2, +1);
-
-	stasis_publish(topic1, test_message1);
-	stasis_publish(topic2, test_message2);
-	stasis_publish(topic1, test_message3);
-
-	actual_len = consumer_wait_for(consumer1, 3);
-	ast_test_validate(test, 3 == actual_len);
-
-	actual_len = consumer_wait_for(consumer2, 3);
-	ast_test_validate(test, 3 == actual_len);
-
-	ast_test_validate(test, test_message1 == consumer1->messages_rxed[0]);
-	ast_test_validate(test, test_message2 == consumer1->messages_rxed[1]);
-	ast_test_validate(test, test_message3 == consumer1->messages_rxed[2]);
-
-	ast_test_validate(test, test_message1 == consumer2->messages_rxed[0]);
-	ast_test_validate(test, test_message2 == consumer2->messages_rxed[1]);
-	ast_test_validate(test, test_message3 == consumer2->messages_rxed[2]);
-
-	return AST_TEST_PASS;
-}
-
-struct cache_test_data {
-	char *id;
-	char *value;
-};
-
-static void cache_test_data_dtor(void *obj)
-{
-	struct cache_test_data *data = obj;
-
-	ast_free(data->id);
-	ast_free(data->value);
-}
-
-static struct stasis_message *cache_test_message_create_full(struct stasis_message_type *type, const char *name, const char *value, struct ast_eid *eid)
-{
-	RAII_VAR(struct cache_test_data *, data, NULL, ao2_cleanup);
-
-	data = ao2_alloc(sizeof(*data), cache_test_data_dtor);
-	if (data == NULL) {
-		return NULL;
-	}
-
-	ast_assert(name != NULL);
-	ast_assert(value != NULL);
-
-	data->id = ast_strdup(name);
-	data->value = ast_strdup(value);
-	if (!data->id || !data->value) {
-		return NULL;
-	}
-
-	return stasis_message_create_full(type, data, eid);
-}
-
-static struct stasis_message *cache_test_message_create(struct stasis_message_type *type, const char *name, const char *value)
-{
-	return cache_test_message_create_full(type, name, value, &ast_eid_default);
-}
-
-static const char *cache_test_data_id(struct stasis_message *message)
-{
-	struct cache_test_data *cachable = stasis_message_data(message);
-
-	if (0 != strcmp("Cacheable", stasis_message_type_name(stasis_message_type(message)))) {
-		return NULL;
-	}
-	return cachable->id;
-}
-
-static struct stasis_message *cache_test_aggregate_calc_fn(struct stasis_cache_entry *entry, struct stasis_message *new_snapshot)
-{
-	struct stasis_message *aggregate_snapshot;
-	struct stasis_message *snapshot;
-	struct stasis_message_type *type = NULL;
-	struct cache_test_data *test_data = NULL;
-	int idx;
-	int accumulated = 0;
-	char aggregate_str[30];
-
-	/* Accumulate the aggregate value. */
-	snapshot = stasis_cache_entry_get_local(entry);
-	if (snapshot) {
-		type = stasis_message_type(snapshot);
-		test_data = stasis_message_data(snapshot);
-		accumulated += atoi(test_data->value);
-	}
-	for (idx = 0; ; ++idx) {
-		snapshot = stasis_cache_entry_get_remote(entry, idx);
-		if (!snapshot) {
-			break;
-		}
-
-		type = stasis_message_type(snapshot);
-		test_data = stasis_message_data(snapshot);
-		accumulated += atoi(test_data->value);
-	}
-
-	if (!test_data) {
-		/* There are no test entries cached.  Delete the aggregate. */
-		return NULL;
-	}
-
-	snapshot = stasis_cache_entry_get_aggregate(entry);
-	if (snapshot) {
-		type = stasis_message_type(snapshot);
-		test_data = stasis_message_data(snapshot);
-		if (accumulated == atoi(test_data->value)) {
-			/* Aggregate test entry did not change. */
-			return ao2_bump(snapshot);
-		}
-	}
-
-	snprintf(aggregate_str, sizeof(aggregate_str), "%d", accumulated);
-	aggregate_snapshot = cache_test_message_create_full(type, test_data->id, aggregate_str, NULL);
-	if (!aggregate_snapshot) {
-		/* Bummer.  We have to keep the old aggregate snapshot. */
-		ast_log(LOG_ERROR, "Could not create aggregate snapshot.\n");
-		return ao2_bump(snapshot);
-	}
-
-	return aggregate_snapshot;
-}
-
-static void cache_test_aggregate_publish_fn(struct stasis_topic *topic, struct stasis_message *aggregate)
-{
-	stasis_publish(topic, aggregate);
-}
-
-static int check_cache_aggregate(struct stasis_cache *cache, struct stasis_message_type *cache_type, const char *id, const char *value)
-{
-	RAII_VAR(struct stasis_message *, aggregate, NULL, ao2_cleanup);
-	struct cache_test_data *test_data;
-
-	aggregate = stasis_cache_get_by_eid(cache, cache_type, id, NULL);
-	if (!aggregate) {
-		/* No aggregate, return true if given no value. */
-		return !value;
-	}
-
-	/* Return true if the given value matches the aggregate value. */
-	test_data = stasis_message_data(aggregate);
-	return value && !strcmp(value, test_data->value);
-}
-
-AST_TEST_DEFINE(cache_filter)
-{
-	RAII_VAR(struct stasis_message_type *, non_cache_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, stasis_caching_unsubscribe);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_message *, test_message, NULL, ao2_cleanup);
-	int actual_len;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test caching topics only forward cache_update messages.";
-		info->description = "Test caching topics only forward cache_update messages.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("NonCacheable", NULL, &non_cache_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != non_cache_type);
-	topic = stasis_topic_create("SomeTopic");
-	ast_test_validate(test, NULL != topic);
-	cache = stasis_cache_create(cache_test_data_id);
-	ast_test_validate(test, NULL != cache);
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-	sub = stasis_subscribe(stasis_caching_get_topic(caching_topic), consumer_exec, consumer);
-	ast_test_validate(test, NULL != sub);
-	ao2_ref(consumer, +1);
-
-	test_message = cache_test_message_create(non_cache_type, "1", "1");
-	ast_test_validate(test, NULL != test_message);
-
-	stasis_publish(topic, test_message);
-
-	actual_len = consumer_should_stay(consumer, 0);
-	ast_test_validate(test, 0 == actual_len);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(cache)
-{
-	RAII_VAR(struct stasis_message_type *, cache_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, stasis_caching_unsubscribe);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_message *, test_message1_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1_clear, NULL, ao2_cleanup);
-	int actual_len;
-	struct stasis_cache_update *actual_update;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test passing messages through cache topic unscathed.";
-		info->description = "Test passing messages through cache topic unscathed.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("Cacheable", NULL, &cache_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != cache_type);
-	topic = stasis_topic_create("SomeTopic");
-	ast_test_validate(test, NULL != topic);
-	cache = stasis_cache_create(cache_test_data_id);
-	ast_test_validate(test, NULL != cache);
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-	sub = stasis_subscribe(stasis_caching_get_topic(caching_topic), consumer_exec, consumer);
-	ast_test_validate(test, NULL != sub);
-	ao2_ref(consumer, +1);
-
-	test_message1_1 = cache_test_message_create(cache_type, "1", "1");
-	ast_test_validate(test, NULL != test_message1_1);
-	test_message2_1 = cache_test_message_create(cache_type, "2", "1");
-	ast_test_validate(test, NULL != test_message2_1);
-
-	/* Post a couple of snapshots */
-	stasis_publish(topic, test_message1_1);
-	stasis_publish(topic, test_message2_1);
-	actual_len = consumer_wait_for(consumer, 2);
-	ast_test_validate(test, 2 == actual_len);
-
-	/* Check for new snapshot messages */
-	ast_test_validate(test, stasis_cache_update_type() == stasis_message_type(consumer->messages_rxed[0]));
-	actual_update = stasis_message_data(consumer->messages_rxed[0]);
-	ast_test_validate(test, NULL == actual_update->old_snapshot);
-	ast_test_validate(test, test_message1_1 == actual_update->new_snapshot);
-	ast_test_validate(test, test_message1_1 == stasis_cache_get(cache, cache_type, "1"));
-	/* stasis_cache_get returned a ref, so unref test_message1_1 */
-	ao2_ref(test_message1_1, -1);
-
-	ast_test_validate(test, stasis_cache_update_type() == stasis_message_type(consumer->messages_rxed[1]));
-	actual_update = stasis_message_data(consumer->messages_rxed[1]);
-	ast_test_validate(test, NULL == actual_update->old_snapshot);
-	ast_test_validate(test, test_message2_1 == actual_update->new_snapshot);
-	ast_test_validate(test, test_message2_1 == stasis_cache_get(cache, cache_type, "2"));
-	/* stasis_cache_get returned a ref, so unref test_message2_1 */
-	ao2_ref(test_message2_1, -1);
-
-	/* Update snapshot 2 */
-	test_message2_2 = cache_test_message_create(cache_type, "2", "2");
-	ast_test_validate(test, NULL != test_message2_2);
-	stasis_publish(topic, test_message2_2);
-
-	actual_len = consumer_wait_for(consumer, 3);
-	ast_test_validate(test, 3 == actual_len);
-
-	actual_update = stasis_message_data(consumer->messages_rxed[2]);
-	ast_test_validate(test, test_message2_1 == actual_update->old_snapshot);
-	ast_test_validate(test, test_message2_2 == actual_update->new_snapshot);
-	ast_test_validate(test, test_message2_2 == stasis_cache_get(cache, cache_type, "2"));
-	/* stasis_cache_get returned a ref, so unref test_message2_2 */
-	ao2_ref(test_message2_2, -1);
-
-	/* Clear snapshot 1 */
-	test_message1_clear = stasis_cache_clear_create(test_message1_1);
-	ast_test_validate(test, NULL != test_message1_clear);
-	stasis_publish(topic, test_message1_clear);
-
-	actual_len = consumer_wait_for(consumer, 4);
-	ast_test_validate(test, 4 == actual_len);
-
-	actual_update = stasis_message_data(consumer->messages_rxed[3]);
-	ast_test_validate(test, test_message1_1 == actual_update->old_snapshot);
-	ast_test_validate(test, NULL == actual_update->new_snapshot);
-	ast_test_validate(test, NULL == stasis_cache_get(cache, cache_type, "1"));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(cache_dump)
-{
-	RAII_VAR(struct stasis_message_type *, cache_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, stasis_caching_unsubscribe);
-	RAII_VAR(struct consumer *, consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_message *, test_message1_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1_clear, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, cache_dump, NULL, ao2_cleanup);
-	int actual_len;
-	struct ao2_iterator i;
-	void *obj;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test cache dump routines.";
-		info->description = "Test cache dump routines.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("Cacheable", NULL, &cache_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != cache_type);
-	topic = stasis_topic_create("SomeTopic");
-	ast_test_validate(test, NULL != topic);
-	cache = stasis_cache_create(cache_test_data_id);
-	ast_test_validate(test, NULL != cache);
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-	consumer = consumer_create(1);
-	ast_test_validate(test, NULL != consumer);
-	sub = stasis_subscribe(stasis_caching_get_topic(caching_topic), consumer_exec, consumer);
-	ast_test_validate(test, NULL != sub);
-	ao2_ref(consumer, +1);
-
-	test_message1_1 = cache_test_message_create(cache_type, "1", "1");
-	ast_test_validate(test, NULL != test_message1_1);
-	test_message2_1 = cache_test_message_create(cache_type, "2", "1");
-	ast_test_validate(test, NULL != test_message2_1);
-
-	/* Post a couple of snapshots */
-	stasis_publish(topic, test_message1_1);
-	stasis_publish(topic, test_message2_1);
-	actual_len = consumer_wait_for(consumer, 2);
-	ast_test_validate(test, 2 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 2 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-		ast_test_validate(test, actual_cache_entry == test_message1_1 || actual_cache_entry == test_message2_1);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Update snapshot 2 */
-	test_message2_2 = cache_test_message_create(cache_type, "2", "2");
-	ast_test_validate(test, NULL != test_message2_2);
-	stasis_publish(topic, test_message2_2);
-
-	actual_len = consumer_wait_for(consumer, 3);
-	ast_test_validate(test, 3 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 2 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-		ast_test_validate(test, actual_cache_entry == test_message1_1 || actual_cache_entry == test_message2_2);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Clear snapshot 1 */
-	test_message1_clear = stasis_cache_clear_create(test_message1_1);
-	ast_test_validate(test, NULL != test_message1_clear);
-	stasis_publish(topic, test_message1_clear);
-
-	actual_len = consumer_wait_for(consumer, 4);
-	ast_test_validate(test, 4 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 1 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-		ast_test_validate(test, actual_cache_entry == test_message2_2);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Dump the cache to ensure that it has no subscription change items in it since those aren't cached */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump(cache, stasis_subscription_change_type());
-	ast_test_validate(test, 0 == ao2_container_count(cache_dump));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(cache_eid_aggregate)
-{
-	RAII_VAR(struct stasis_message_type *, cache_type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, stasis_caching_unsubscribe);
-	RAII_VAR(struct consumer *, cache_consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, topic_consumer, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, topic_sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_subscription *, cache_sub, NULL, stasis_unsubscribe);
-	RAII_VAR(struct stasis_message *, test_message1_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_3, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_4, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1_clear, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2_clear, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, cache_dump, NULL, ao2_cleanup);
-	int actual_len;
-	struct ao2_iterator i;
-	void *obj;
-	struct ast_eid foreign_eid1;
-	struct ast_eid foreign_eid2;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test cache eid and aggregate support.";
-		info->description = "Test cache eid and aggregate support.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	memset(&foreign_eid1, 0xAA, sizeof(foreign_eid1));
-	memset(&foreign_eid2, 0xBB, sizeof(foreign_eid2));
-
-	ast_test_validate(test, stasis_message_type_create("Cacheable", NULL, &cache_type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != cache_type);
-
-	topic = stasis_topic_create("SomeTopic");
-	ast_test_validate(test, NULL != topic);
-
-	/* To consume events published to the topic. */
-	topic_consumer = consumer_create(1);
-	ast_test_validate(test, NULL != topic_consumer);
-
-	topic_sub = stasis_subscribe(topic, consumer_exec, topic_consumer);
-	ast_test_validate(test, NULL != topic_sub);
-	ao2_ref(topic_consumer, +1);
-
-	cache = stasis_cache_create_full(cache_test_data_id,
-		cache_test_aggregate_calc_fn, cache_test_aggregate_publish_fn);
-	ast_test_validate(test, NULL != cache);
-
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-
-	/* To consume update events published to the caching_topic. */
-	cache_consumer = consumer_create(1);
-	ast_test_validate(test, NULL != cache_consumer);
-
-	cache_sub = stasis_subscribe(stasis_caching_get_topic(caching_topic), consumer_exec, cache_consumer);
-	ast_test_validate(test, NULL != cache_sub);
-	ao2_ref(cache_consumer, +1);
-
-	/* Create test messages. */
-	test_message1_1 = cache_test_message_create_full(cache_type, "1", "1", &ast_eid_default);
-	ast_test_validate(test, NULL != test_message1_1);
-	test_message2_1 = cache_test_message_create_full(cache_type, "2", "1", &ast_eid_default);
-	ast_test_validate(test, NULL != test_message2_1);
-	test_message2_2 = cache_test_message_create_full(cache_type, "2", "2", &foreign_eid1);
-	ast_test_validate(test, NULL != test_message2_2);
-	test_message2_3 = cache_test_message_create_full(cache_type, "2", "3", &foreign_eid2);
-	ast_test_validate(test, NULL != test_message2_3);
-	test_message2_4 = cache_test_message_create_full(cache_type, "2", "4", &foreign_eid2);
-	ast_test_validate(test, NULL != test_message2_4);
-
-	/* Post some snapshots */
-	stasis_publish(topic, test_message1_1);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "1", "1"));
-	stasis_publish(topic, test_message2_1);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "2", "1"));
-	stasis_publish(topic, test_message2_2);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "2", "3"));
-
-	actual_len = consumer_wait_for(cache_consumer, 6);
-	ast_test_validate(test, 6 == actual_len);
-	actual_len = consumer_wait_for(topic_consumer, 6);
-	ast_test_validate(test, 6 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_all(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 3 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message1_1
-			|| actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_2);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Check the local cached items */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_by_eid(cache, NULL, &ast_eid_default);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 2 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message1_1
-			|| actual_cache_entry == test_message2_1);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Post snapshot 2 from another eid. */
-	stasis_publish(topic, test_message2_3);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "2", "6"));
-
-	actual_len = consumer_wait_for(cache_consumer, 8);
-	ast_test_validate(test, 8 == actual_len);
-	actual_len = consumer_wait_for(topic_consumer, 8);
-	ast_test_validate(test, 8 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_all(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 4 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message1_1
-			|| actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_2
-			|| actual_cache_entry == test_message2_3);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Check the remote cached items */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_by_eid(cache, NULL, &foreign_eid1);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 1 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test, actual_cache_entry == test_message2_2);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Post snapshot 2 from a repeated eid. */
-	stasis_publish(topic, test_message2_4);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "2", "7"));
-
-	actual_len = consumer_wait_for(cache_consumer, 10);
-	ast_test_validate(test, 10 == actual_len);
-	actual_len = consumer_wait_for(topic_consumer, 10);
-	ast_test_validate(test, 10 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_all(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 4 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message1_1
-			|| actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_2
-			|| actual_cache_entry == test_message2_4);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Check all snapshot 2 cache entries. */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_get_all(cache, cache_type, "2");
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 3 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_2
-			|| actual_cache_entry == test_message2_4);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Clear snapshot 1 */
-	test_message1_clear = stasis_cache_clear_create(test_message1_1);
-	ast_test_validate(test, NULL != test_message1_clear);
-	stasis_publish(topic, test_message1_clear);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "1", NULL));
-
-	actual_len = consumer_wait_for(cache_consumer, 12);
-	ast_test_validate(test, 12 == actual_len);
-	actual_len = consumer_wait_for(topic_consumer, 11);
-	ast_test_validate(test, 11 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_all(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 3 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_2
-			|| actual_cache_entry == test_message2_4);
-	}
-	ao2_iterator_destroy(&i);
-
-	/* Clear snapshot 2 from a remote eid */
-	test_message2_clear = stasis_cache_clear_create(test_message2_2);
-	ast_test_validate(test, NULL != test_message2_clear);
-	stasis_publish(topic, test_message2_clear);
-	ast_test_validate(test, check_cache_aggregate(cache, cache_type, "2", "5"));
-
-	actual_len = consumer_wait_for(cache_consumer, 14);
-	ast_test_validate(test, 14 == actual_len);
-	actual_len = consumer_wait_for(topic_consumer, 13);
-	ast_test_validate(test, 13 == actual_len);
-
-	/* Check the cache */
-	ao2_cleanup(cache_dump);
-	cache_dump = stasis_cache_dump_all(cache, NULL);
-	ast_test_validate(test, NULL != cache_dump);
-	ast_test_validate(test, 2 == ao2_container_count(cache_dump));
-	i = ao2_iterator_init(cache_dump, 0);
-	while ((obj = ao2_iterator_next(&i))) {
-		RAII_VAR(struct stasis_message *, actual_cache_entry, obj, ao2_cleanup);
-
-		ast_test_validate(test,
-			actual_cache_entry == test_message2_1
-			|| actual_cache_entry == test_message2_4);
-	}
-	ao2_iterator_destroy(&i);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(router)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, uut, NULL, stasis_message_router_unsubscribe_and_join);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type3, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer1, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer2, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer3, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message3, NULL, ao2_cleanup);
-	int actual_len, ret;
-	struct stasis_message *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test simple message routing";
-		info->description = "Test simple message routing";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer1 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer1);
-	consumer2 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer2);
-	consumer3 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer3);
-
-	ast_test_validate(test, stasis_message_type_create("TestMessage1", NULL, &test_message_type1) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type1);
-	ast_test_validate(test, stasis_message_type_create("TestMessage2", NULL, &test_message_type2) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type2);
-	ast_test_validate(test, stasis_message_type_create("TestMessage3", NULL, &test_message_type3) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type3);
-
-	uut = stasis_message_router_create(topic);
-	ast_test_validate(test, NULL != uut);
-
-	ret = stasis_message_router_add(
-		uut, test_message_type1, consumer_exec, consumer1);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer1, +1);
-	ret = stasis_message_router_add(
-		uut, test_message_type2, consumer_exec, consumer2);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer2, +1);
-	ret = stasis_message_router_set_default(uut, consumer_exec, consumer3);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer3, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	test_message1 = stasis_message_create(test_message_type1, test_data);
-	ast_test_validate(test, NULL != test_message1);
-	test_message2 = stasis_message_create(test_message_type2, test_data);
-	ast_test_validate(test, NULL != test_message2);
-	test_message3 = stasis_message_create(test_message_type3, test_data);
-	ast_test_validate(test, NULL != test_message3);
-
-	stasis_publish(topic, test_message1);
-	stasis_publish(topic, test_message2);
-	stasis_publish(topic, test_message3);
-
-	actual_len = consumer_wait_for(consumer1, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(consumer2, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(consumer3, 1);
-	ast_test_validate(test, 1 == actual_len);
-
-	actual = consumer1->messages_rxed[0];
-	ast_test_validate(test, test_message1 == actual);
-
-	actual = consumer2->messages_rxed[0];
-	ast_test_validate(test, test_message2 == actual);
-
-	actual = consumer3->messages_rxed[0];
-	ast_test_validate(test, test_message3 == actual);
-
-	/* consumer1 and consumer2 do not get the final message. */
-	ao2_cleanup(consumer1);
-	ao2_cleanup(consumer2);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(router_pool)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, uut, NULL, stasis_message_router_unsubscribe_and_join);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type3, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer1, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer2, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer3, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message3, NULL, ao2_cleanup);
-	int actual_len, ret;
-	struct stasis_message *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test message routing via threadpool";
-		info->description = "Test simple message routing when\n"
-			"the subscriptions dictate usage of the Stasis\n"
-			"threadpool.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	consumer1 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer1);
-	consumer2 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer2);
-	consumer3 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer3);
-
-	ast_test_validate(test, stasis_message_type_create("TestMessage1", NULL, &test_message_type1) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type1);
-	ast_test_validate(test, stasis_message_type_create("TestMessage2", NULL, &test_message_type2) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type2);
-	ast_test_validate(test, stasis_message_type_create("TestMessage3", NULL, &test_message_type3) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type3);
-
-	uut = stasis_message_router_create_pool(topic);
-	ast_test_validate(test, NULL != uut);
-
-	ret = stasis_message_router_add(
-		uut, test_message_type1, consumer_exec, consumer1);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer1, +1);
-	ret = stasis_message_router_add(
-		uut, test_message_type2, consumer_exec, consumer2);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer2, +1);
-	ret = stasis_message_router_set_default(uut, consumer_exec, consumer3);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer3, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	test_message1 = stasis_message_create(test_message_type1, test_data);
-	ast_test_validate(test, NULL != test_message1);
-	test_message2 = stasis_message_create(test_message_type2, test_data);
-	ast_test_validate(test, NULL != test_message2);
-	test_message3 = stasis_message_create(test_message_type3, test_data);
-	ast_test_validate(test, NULL != test_message3);
-
-	stasis_publish(topic, test_message1);
-	stasis_publish(topic, test_message2);
-	stasis_publish(topic, test_message3);
-
-	actual_len = consumer_wait_for(consumer1, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(consumer2, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(consumer3, 1);
-	ast_test_validate(test, 1 == actual_len);
-
-	actual = consumer1->messages_rxed[0];
-	ast_test_validate(test, test_message1 == actual);
-
-	actual = consumer2->messages_rxed[0];
-	ast_test_validate(test, test_message2 == actual);
-
-	actual = consumer3->messages_rxed[0];
-	ast_test_validate(test, test_message3 == actual);
-
-	/* consumer1 and consumer2 do not get the final message. */
-	ao2_cleanup(consumer1);
-	ao2_cleanup(consumer2);
-
-	return AST_TEST_PASS;
-}
-
-static const char *cache_simple(struct stasis_message *message)
-{
-	const char *type_name =
-		stasis_message_type_name(stasis_message_type(message));
-	if (!ast_begins_with(type_name, "Cache")) {
-		return NULL;
-	}
-
-	return "cached";
-}
-
-AST_TEST_DEFINE(router_cache_updates)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, stasis_caching_unsubscribe_and_join);
-	RAII_VAR(struct stasis_message_type *, test_message_type1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_type *, test_message_type3, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message_router *, uut, NULL, stasis_message_router_unsubscribe_and_join);
-	RAII_VAR(char *, test_data, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message2, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, test_message3, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer1, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer2, NULL, ao2_cleanup);
-	RAII_VAR(struct consumer *, consumer3, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message1, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message2, NULL, ao2_cleanup);
-	struct stasis_cache_update *update;
-	int actual_len, ret;
-	struct stasis_message *actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test special handling cache_update messages";
-		info->description = "Test special handling cache_update messages";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("TestTopic");
-	ast_test_validate(test, NULL != topic);
-
-	cache = stasis_cache_create(cache_simple);
-	ast_test_validate(test, NULL != cache);
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-
-	consumer1 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer1);
-	consumer2 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer2);
-	consumer3 = consumer_create(1);
-	ast_test_validate(test, NULL != consumer3);
-
-	ast_test_validate(test, stasis_message_type_create("Cache1", NULL, &test_message_type1) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type1);
-	ast_test_validate(test, stasis_message_type_create("Cache2", NULL, &test_message_type2) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type2);
-	ast_test_validate(test, stasis_message_type_create("NonCache", NULL, &test_message_type3) == STASIS_MESSAGE_TYPE_SUCCESS);
-	ast_test_validate(test, NULL != test_message_type3);
-
-	uut = stasis_message_router_create(
-		stasis_caching_get_topic(caching_topic));
-	ast_test_validate(test, NULL != uut);
-
-	ret = stasis_message_router_add_cache_update(
-		uut, test_message_type1, consumer_exec, consumer1);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer1, +1);
-	ret = stasis_message_router_add(
-		uut, stasis_cache_update_type(), consumer_exec, consumer2);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer2, +1);
-	ret = stasis_message_router_set_default(uut, consumer_exec, consumer3);
-	ast_test_validate(test, 0 == ret);
-	ao2_ref(consumer3, +1);
-
-	test_data = ao2_alloc(1, NULL);
-	ast_test_validate(test, NULL != test_data);
-	test_message1 = stasis_message_create(test_message_type1, test_data);
-	ast_test_validate(test, NULL != test_message1);
-	test_message2 = stasis_message_create(test_message_type2, test_data);
-	ast_test_validate(test, NULL != test_message2);
-	test_message3 = stasis_message_create(test_message_type3, test_data);
-	ast_test_validate(test, NULL != test_message3);
-
-	stasis_publish(topic, test_message1);
-	stasis_publish(topic, test_message2);
-	stasis_publish(topic, test_message3);
-
-	actual_len = consumer_wait_for(consumer1, 1);
-	ast_test_validate(test, 1 == actual_len);
-	actual_len = consumer_wait_for(consumer2, 1);
-	ast_test_validate(test, 1 == actual_len);
-	/* Uncacheable message should not be passed through */
-	actual_len = consumer_should_stay(consumer3, 0);
-	ast_test_validate(test, 0 == actual_len);
-
-	actual = consumer1->messages_rxed[0];
-	ast_test_validate(test, stasis_cache_update_type() == stasis_message_type(actual));
-	update = stasis_message_data(actual);
-	ast_test_validate(test, test_message_type1 == update->type);
-	ast_test_validate(test, test_message1 == update->new_snapshot);
-
-	actual = consumer2->messages_rxed[0];
-	ast_test_validate(test, stasis_cache_update_type() == stasis_message_type(actual));
-	update = stasis_message_data(actual);
-	ast_test_validate(test, test_message_type2 == update->type);
-	ast_test_validate(test, test_message2 == update->new_snapshot);
-
-	/* consumer1 and consumer2 do not get the final message. */
-	ao2_cleanup(consumer1);
-	ao2_cleanup(consumer2);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(no_to_json)
-{
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup);
-	RAII_VAR(char *, data, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
-	char *expected = "SomeData";
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test message to_json function";
-		info->description = "Test message to_json function";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Test NULL */
-	actual = stasis_message_to_json(NULL, NULL);
-	ast_test_validate(test, NULL == actual);
-
-	/* Test message with NULL to_json function */
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-
-	data = ao2_alloc(strlen(expected) + 1, NULL);
-	strcpy(data, expected);
-	uut = stasis_message_create(type, data);
-	ast_test_validate(test, NULL != uut);
-
-	actual = stasis_message_to_json(uut, NULL);
-	ast_test_validate(test, NULL == actual);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(to_json)
-{
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup);
-	RAII_VAR(char *, data, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
-	const char *expected_text = "SomeData";
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test message to_json function when NULL";
-		info->description = "Test message to_json function when NULL";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", &fake_vtable, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-
-	data = ao2_alloc(strlen(expected_text) + 1, NULL);
-	strcpy(data, expected_text);
-	uut = stasis_message_create(type, data);
-	ast_test_validate(test, NULL != uut);
-
-	expected = ast_json_string_create(expected_text);
-	actual = stasis_message_to_json(uut, NULL);
-	ast_test_validate(test, ast_json_equal(expected, actual));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(no_to_ami)
-{
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup);
-	RAII_VAR(char *, data, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_manager_event_blob *, actual, NULL, ao2_cleanup);
-	char *expected = "SomeData";
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test message to_ami function when NULL";
-		info->description = "Test message to_ami function when NULL";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Test NULL */
-	actual = stasis_message_to_ami(NULL);
-	ast_test_validate(test, NULL == actual);
-
-	/* Test message with NULL to_ami function */
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-
-	data = ao2_alloc(strlen(expected) + 1, NULL);
-	strcpy(data, expected);
-	uut = stasis_message_create(type, data);
-	ast_test_validate(test, NULL != uut);
-
-	actual = stasis_message_to_ami(uut);
-	ast_test_validate(test, NULL == actual);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(to_ami)
-{
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup);
-	RAII_VAR(char *, data, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_manager_event_blob *, actual, NULL, ao2_cleanup);
-	const char *expected_text = "SomeData";
-	const char *expected = "Message: SomeData\r\n";
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test message to_ami function";
-		info->description = "Test message to_ami function";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("SomeMessage", &fake_vtable, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-
-	data = ao2_alloc(strlen(expected_text) + 1, NULL);
-	strcpy(data, expected_text);
-	uut = stasis_message_create(type, data);
-	ast_test_validate(test, NULL != uut);
-
-	actual = stasis_message_to_ami(uut);
-	ast_test_validate(test, strcmp(expected, actual->extra_fields) == 0);
-
-	return AST_TEST_PASS;
-}
-
-static void noop(void *data, struct stasis_subscription *sub,
-	struct stasis_message *message)
-{
-	/* no-op */
-}
-
-AST_TEST_DEFINE(dtor_order)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test that destruction order doesn't bomb stuff";
-		info->description = "Test that destruction order doesn't bomb stuff";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	topic = stasis_topic_create("test-topic");
-	ast_test_validate(test, NULL != topic);
-
-	sub = stasis_subscribe(topic, noop, NULL);
-	ast_test_validate(test, NULL != sub);
-
-	/* With any luck, this won't completely blow everything up */
-	ao2_cleanup(topic);
-	stasis_unsubscribe(sub);
-
-	/* These refs were cleaned up manually */
-	topic = NULL;
-	sub = NULL;
-
-	return AST_TEST_PASS;
-}
-
-static const char *noop_get_id(struct stasis_message *message)
-{
-	return NULL;
-}
-
-AST_TEST_DEFINE(caching_dtor_order)
-{
-	RAII_VAR(struct stasis_topic *, topic, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL,
-		stasis_caching_unsubscribe);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test that destruction order doesn't bomb stuff";
-		info->description = "Test that destruction order doesn't bomb stuff";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	cache = stasis_cache_create(noop_get_id);
-	ast_test_validate(test, NULL != cache);
-
-	topic = stasis_topic_create("test-topic");
-	ast_test_validate(test, NULL != topic);
-
-	caching_topic = stasis_caching_topic_create(topic, cache);
-	ast_test_validate(test, NULL != caching_topic);
-
-	sub = stasis_subscribe(stasis_caching_get_topic(caching_topic), noop,
-		NULL);
-	ast_test_validate(test, NULL != sub);
-
-	/* With any luck, this won't completely blow everything up */
-	ao2_cleanup(cache);
-	ao2_cleanup(topic);
-	stasis_caching_unsubscribe(caching_topic);
-	stasis_unsubscribe(sub);
-
-	/* These refs were cleaned up manually */
-	cache = NULL;
-	topic = NULL;
-	caching_topic = NULL;
-	sub = NULL;
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(message_type);
-	AST_TEST_UNREGISTER(message);
-	AST_TEST_UNREGISTER(subscription_messages);
-	AST_TEST_UNREGISTER(subscription_pool_messages);
-	AST_TEST_UNREGISTER(publish);
-	AST_TEST_UNREGISTER(publish_sync);
-	AST_TEST_UNREGISTER(publish_pool);
-	AST_TEST_UNREGISTER(unsubscribe_stops_messages);
-	AST_TEST_UNREGISTER(forward);
-	AST_TEST_UNREGISTER(cache_filter);
-	AST_TEST_UNREGISTER(cache);
-	AST_TEST_UNREGISTER(cache_dump);
-	AST_TEST_UNREGISTER(cache_eid_aggregate);
-	AST_TEST_UNREGISTER(router);
-	AST_TEST_UNREGISTER(router_pool);
-	AST_TEST_UNREGISTER(router_cache_updates);
-	AST_TEST_UNREGISTER(interleaving);
-	AST_TEST_UNREGISTER(subscription_interleaving);
-	AST_TEST_UNREGISTER(no_to_json);
-	AST_TEST_UNREGISTER(to_json);
-	AST_TEST_UNREGISTER(no_to_ami);
-	AST_TEST_UNREGISTER(to_ami);
-	AST_TEST_UNREGISTER(dtor_order);
-	AST_TEST_UNREGISTER(caching_dtor_order);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(message_type);
-	AST_TEST_REGISTER(message);
-	AST_TEST_REGISTER(subscription_messages);
-	AST_TEST_REGISTER(subscription_pool_messages);
-	AST_TEST_REGISTER(publish);
-	AST_TEST_REGISTER(publish_sync);
-	AST_TEST_REGISTER(publish_pool);
-	AST_TEST_REGISTER(unsubscribe_stops_messages);
-	AST_TEST_REGISTER(forward);
-	AST_TEST_REGISTER(cache_filter);
-	AST_TEST_REGISTER(cache);
-	AST_TEST_REGISTER(cache_dump);
-	AST_TEST_REGISTER(cache_eid_aggregate);
-	AST_TEST_REGISTER(router);
-	AST_TEST_REGISTER(router_pool);
-	AST_TEST_REGISTER(router_cache_updates);
-	AST_TEST_REGISTER(interleaving);
-	AST_TEST_REGISTER(subscription_interleaving);
-	AST_TEST_REGISTER(no_to_json);
-	AST_TEST_REGISTER(to_json);
-	AST_TEST_REGISTER(no_to_ami);
-	AST_TEST_REGISTER(to_ami);
-	AST_TEST_REGISTER(dtor_order);
-	AST_TEST_REGISTER(caching_dtor_order);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis testing",
-		.load = load_module,
-		.unload = unload_module
-	);
diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c
deleted file mode 100644
index 3b5350a..0000000
--- a/tests/test_stasis_channels.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test Stasis Channel messages and objects
- *
- * \author\verbatim Matt Jordan <mjordan at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420124 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis.h"
-#include "asterisk/stasis_message_router.h"
-#include "asterisk/test.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/channel.h"
-
-static const char *test_category = "/stasis/channels/";
-
-static void safe_channel_release(struct ast_channel *chan)
-{
-	if (!chan) {
-		return;
-	}
-	ast_channel_release(chan);
-}
-
-AST_TEST_DEFINE(channel_blob_create)
-{
-	struct ast_channel_blob *blob;
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test creation of ast_channel_blob objects";
-		info->description = "Test creation of ast_channel_blob objects";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("test-type", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
-	ast_channel_unlock(chan);
-	json = ast_json_pack("{s: s}",
-		     "foo", "bar");
-
-	/* Off nominal creation */
-	ast_channel_lock(chan);
-	ast_test_validate(test, NULL == ast_channel_blob_create(chan, NULL, json));
-
-	/* Test for single channel */
-	msg = ast_channel_blob_create(chan, type, json);
-	ast_channel_unlock(chan);
-	ast_test_validate(test, NULL != msg);
-	blob = stasis_message_data(msg);
-	ast_test_validate(test, NULL != blob);
-	ast_test_validate(test, NULL != blob->snapshot);
-	ast_test_validate(test, NULL != blob->blob);
-	ast_test_validate(test, type == stasis_message_type(msg));
-
-	ast_test_validate(test, 1 == ao2_ref(msg, 0));
-	ao2_cleanup(msg);
-
-	/* Test for global channels */
-	msg = ast_channel_blob_create(NULL, type, json);
-	ast_test_validate(test, NULL != msg);
-	blob = stasis_message_data(msg);
-	ast_test_validate(test, NULL != blob);
-	ast_test_validate(test, NULL == blob->snapshot);
-	ast_test_validate(test, NULL != blob->blob);
-	ast_test_validate(test, type == stasis_message_type(msg));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(null_blob)
-{
-	struct ast_channel_blob *blob;
-	RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test creation of ast_channel_blob objects";
-		info->description = "Test creation of ast_channel_blob objects";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, stasis_message_type_create("test-type", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
-	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
-	ast_channel_unlock(chan);
-	json = ast_json_pack("{s: s}",
-		     "foo", "bar");
-
-	/* Test for single channel */
-	ast_channel_lock(chan);
-	msg = ast_channel_blob_create(chan, type, NULL);
-	ast_channel_unlock(chan);
-	ast_test_validate(test, NULL != msg);
-	blob = stasis_message_data(msg);
-	ast_test_validate(test, NULL != blob);
-	ast_test_validate(test, NULL != blob->snapshot);
-	ast_test_validate(test, ast_json_null() == blob->blob);
-	ast_test_validate(test, type == stasis_message_type(msg));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(multi_channel_blob_create)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test creation of ast_multi_channel_blob objects";
-		info->description = "Test creation of ast_multi_channel_blob objects";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	json = ast_json_pack("{s: s}",
-		     "foo", "bar");
-
-	/* Test for single channel */
-	blob = ast_multi_channel_blob_create(json);
-	ast_test_validate(test, NULL != blob);
-	ast_test_validate(test, NULL != ast_multi_channel_blob_get_json(blob));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(multi_channel_blob_snapshots)
-{
-	RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
-	struct ast_channel_snapshot *snapshot;
-	struct ao2_container *matches;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test creation of ast_multi_channel_blob objects";
-		info->description = "Test creation of ast_multi_channel_blob objects";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	json = ast_json_pack("{s: s}",
-		     "type", "test");
-	chan_alice = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
-	ast_channel_unlock(chan_alice);
-	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, NULL, 0, "TEST/Bob");
-	ast_channel_unlock(chan_bob);
-	chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Bob", "300", "300", "default", NULL, NULL, 0, "TEST/Charlie");
-	ast_channel_unlock(chan_charlie);
-
-	blob = ast_multi_channel_blob_create(json);
-	ast_channel_lock(chan_alice);
-	ast_multi_channel_blob_add_channel(blob, "Caller", ast_channel_snapshot_create(chan_alice));
-	ast_channel_unlock(chan_alice);
-	ast_channel_lock(chan_bob);
-	ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_bob));
-	ast_channel_unlock(chan_bob);
-	ast_channel_lock(chan_charlie);
-	ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_charlie));
-	ast_channel_unlock(chan_charlie);
-
-	/* Test for unknown role */
-	ast_test_validate(test, NULL == ast_multi_channel_blob_get_channel(blob, "Foobar"));
-
-	/* Test for single match */
-	snapshot = ast_multi_channel_blob_get_channel(blob, "Caller");
-	ast_test_validate(test, NULL != snapshot);
-	ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->name));
-
-	/* Test for single match, multiple possibilities */
-	snapshot = ast_multi_channel_blob_get_channel(blob, "Peer");
-	ast_test_validate(test, NULL != snapshot);
-	ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->name));
-
-	/* Multi-match */
-	matches = ast_multi_channel_blob_get_channels(blob, "Peer");
-	ast_test_validate(test, NULL != matches);
-	ast_test_validate(test, 2 == ao2_container_count(matches));
-	snapshot = ao2_find(matches, "TEST/Bob", OBJ_KEY);
-	ast_test_validate(test, NULL != snapshot);
-	ao2_cleanup(snapshot);
-	snapshot = ao2_find(matches, "TEST/Charlie", OBJ_KEY);
-	ast_test_validate(test, NULL != snapshot);
-	ao2_cleanup(snapshot);
-	ast_test_validate(test, 1 == ao2_ref(matches, 0));
-	ao2_cleanup(matches);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(channel_snapshot_json)
-{
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
-	RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test creation of ast_channel_blob objects";
-		info->description = "Test creation of ast_channel_blob objects";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, NULL == ast_channel_snapshot_to_json(NULL, NULL));
-
-	chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, NULL, 0, "TEST/name");
-	ast_channel_unlock(chan);
-	ast_test_validate(test, NULL != chan);
-	ast_channel_lock(chan);
-	snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	ast_test_validate(test, NULL != snapshot);
-
-	actual = ast_channel_snapshot_to_json(snapshot, NULL);
-	expected = ast_json_pack("{ s: s, s: s, s: s, s: s,"
-				 "  s: { s: s, s: s, s: i },"
-				 "  s: { s: s, s: s },"
-				 "  s: { s: s, s: s },"
-				 "  s: o"
-				 "}",
-				 "name", "TEST/name",
-				 "state", "Down",
-				 "accountcode", "acctcode",
-				 "id", ast_channel_uniqueid(chan),
-				 "dialplan",
-				 "context", "context",
-				 "exten", "exten",
-				 "priority", 1,
-				 "caller",
-				 "name", "cid_name",
-				 "number", "cid_num",
-				 "connected",
-				 "name", "",
-				 "number", "",
-				 "creationtime",
-				 ast_json_timeval(
-					 ast_channel_creationtime(chan), NULL));
-
-	ast_test_validate(test, ast_json_equal(expected, actual));
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(channel_blob_create);
-	AST_TEST_UNREGISTER(null_blob);
-	AST_TEST_UNREGISTER(multi_channel_blob_create);
-	AST_TEST_UNREGISTER(multi_channel_blob_snapshots);
-	AST_TEST_UNREGISTER(channel_snapshot_json);
-
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(channel_blob_create);
-	AST_TEST_REGISTER(null_blob);
-	AST_TEST_REGISTER(multi_channel_blob_create);
-	AST_TEST_REGISTER(multi_channel_blob_snapshots);
-	AST_TEST_REGISTER(channel_snapshot_json);
-
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis Channel Testing",
-		.load = load_module,
-		.unload = unload_module
-	);
diff --git a/tests/test_stasis_endpoints.c b/tests/test_stasis_endpoints.c
deleted file mode 100644
index 51f5274..0000000
--- a/tests/test_stasis_endpoints.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * David M. Lee, II <dlee at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file \brief Test endpoints.
- *
- * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
- *
- * \ingroup tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>res_stasis_test</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419319 $")
-
-#include "asterisk/astobj2.h"
-#include "asterisk/channel.h"
-#include "asterisk/endpoints.h"
-#include "asterisk/module.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
-#include "asterisk/stasis_test.h"
-#include "asterisk/test.h"
-
-static const char *test_category = "/stasis/endpoints/";
-
-/*! \brief Message matcher looking for cache update messages */
-static int cache_update(struct stasis_message *msg, const void *data) {
-	struct stasis_cache_update *update;
-	struct ast_endpoint_snapshot *snapshot;
-	const char *name = data;
-
-	if (stasis_cache_update_type() != stasis_message_type(msg)) {
-		return 0;
-	}
-
-	update = stasis_message_data(msg);
-	if (ast_endpoint_snapshot_type() != update->type) {
-		return 0;
-	}
-
-	snapshot = stasis_message_data(update->old_snapshot);
-	if (!snapshot) {
-		snapshot = stasis_message_data(update->new_snapshot);
-	}
-
-	return 0 == strcmp(name, snapshot->resource);
-}
-
-AST_TEST_DEFINE(state_changes)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-	RAII_VAR(struct ast_channel *, chan, NULL, ast_hangup);
-	RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	struct stasis_message *msg;
-	struct stasis_message_type *type;
-	struct ast_endpoint_snapshot *actual_snapshot;
-	int actual_count;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test endpoint updates as its state changes";
-		info->description =
-			"Test endpoint updates as its state changes";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_endpoint_create("TEST", __func__);
-	ast_test_validate(test, NULL != uut);
-
-	sink = stasis_message_sink_create();
-	ast_test_validate(test, NULL != sink);
-
-	sub = stasis_subscribe(ast_endpoint_topic(uut),
-		stasis_message_sink_cb(), sink);
-	ast_test_validate(test, NULL != sub);
-
-	ast_endpoint_set_state(uut, AST_ENDPOINT_OFFLINE);
-	actual_count = stasis_message_sink_wait_for_count(sink, 1,
-		STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 1 == actual_count);
-	msg = sink->messages[0];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == type);
-	actual_snapshot = stasis_message_data(msg);
-	ast_test_validate(test, AST_ENDPOINT_OFFLINE == actual_snapshot->state);
-
-	ast_endpoint_set_max_channels(uut, 8675309);
-	actual_count = stasis_message_sink_wait_for_count(sink, 2,
-		STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 2 == actual_count);
-	msg = sink->messages[1];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == type);
-	actual_snapshot = stasis_message_data(msg);
-	ast_test_validate(test, 8675309 == actual_snapshot->max_channels);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(cache_clear)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-	RAII_VAR(struct ast_channel *, chan, NULL, ast_hangup);
-	RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	struct stasis_message *msg;
-	struct stasis_message_type *type;
-	struct ast_endpoint_snapshot *actual_snapshot;
-	struct stasis_cache_update *update;
-	int message_index;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test endpoint state change messages";
-		info->description = "Test endpoint state change messages";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Subscribe to the cache topic */
-	sink = stasis_message_sink_create();
-	ast_test_validate(test, NULL != sink);
-
-	sub = stasis_subscribe(
-		ast_endpoint_topic_all_cached(),
-		stasis_message_sink_cb(), sink);
-	ast_test_validate(test, NULL != sub);
-
-	uut = ast_endpoint_create("TEST", __func__);
-	ast_test_validate(test, NULL != uut);
-
-	/* Since the cache topic is a singleton (ew), it may have messages from
-	 * elsewheres that it's processing, or maybe even some final messages
-	 * from the prior test. We've got to wait_for our specific message,
-	 * instead of wait_for_count.
-	 */
-	message_index = stasis_message_sink_wait_for(sink, 0,
-		cache_update, __func__, STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 0 <= message_index);
-
-	/* First message should be a cache creation entry for our endpoint */
-	msg = sink->messages[message_index];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, stasis_cache_update_type() == type);
-	update = stasis_message_data(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == update->type);
-	ast_test_validate(test, NULL == update->old_snapshot);
-	actual_snapshot = stasis_message_data(update->new_snapshot);
-	ast_test_validate(test, 0 == strcmp("TEST", actual_snapshot->tech));
-	ast_test_validate(test,
-		0 == strcmp(__func__, actual_snapshot->resource));
-
-	ast_endpoint_shutdown(uut);
-	uut = NULL;
-
-	/* Note: there's a few messages between the creation and the clear.
-	 * Wait for all of them... */
-	message_index = stasis_message_sink_wait_for(sink, message_index + 4,
-		cache_update, __func__, STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 0 <= message_index);
-	/* Now we should have a cache removal entry */
-	msg = sink->messages[message_index];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, stasis_cache_update_type() == type);
-	update = stasis_message_data(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == update->type);
-	actual_snapshot = stasis_message_data(update->old_snapshot);
-	ast_test_validate(test, 0 == strcmp("TEST", actual_snapshot->tech));
-	ast_test_validate(test,
-		0 == strcmp(__func__, actual_snapshot->resource));
-	ast_test_validate(test, NULL == update->new_snapshot);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(channel_messages)
-{
-	RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
-	RAII_VAR(struct ast_channel *, chan, NULL, ast_hangup);
-	RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
-	struct stasis_message *msg;
-	struct stasis_message_type *type;
-	struct ast_endpoint_snapshot *actual_snapshot;
-	int actual_count;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = test_category;
-		info->summary = "Test channel messages on an endpoint topic";
-		info->description =
-			"Test channel messages on an endpoint topic";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	uut = ast_endpoint_create("TEST", __func__);
-	ast_test_validate(test, NULL != uut);
-
-	sink = stasis_message_sink_create();
-	ast_test_validate(test, NULL != sink);
-
-	sub = stasis_subscribe(ast_endpoint_topic(uut),
-		stasis_message_sink_cb(), sink);
-	ast_test_validate(test, NULL != sub);
-
-	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", __func__, "100",
-		"100", "default", NULL, NULL, 0, "TEST/test_res");
-	ast_test_validate(test, NULL != chan);
-
-	ast_endpoint_add_channel(uut, chan);
-
-	actual_count = stasis_message_sink_wait_for_count(sink, 1,
-		STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 1 == actual_count);
-
-	msg = sink->messages[0];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == type);
-	actual_snapshot = stasis_message_data(msg);
-	ast_test_validate(test, 1 == actual_snapshot->num_channels);
-
-	ast_hangup(chan);
-	chan = NULL;
-
-	actual_count = stasis_message_sink_wait_for_count(sink, 6,
-		STASIS_SINK_DEFAULT_WAIT);
-	ast_test_validate(test, 6 == actual_count);
-
-	msg = sink->messages[1];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, stasis_cache_update_type() == type);
-
-	msg = sink->messages[2];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, ast_channel_snapshot_type() == type);
-
-	msg = sink->messages[3];
-	type = stasis_message_type(msg);
-	ast_test_validate(test, stasis_cache_update_type() == type);
-
-	/* The ordering of the cache clear and endpoint snapshot are
-	 * unspecified */
-	msg = sink->messages[4];
-	if (stasis_message_type(msg) == stasis_cache_clear_type()) {
-		/* Okay; the next message should be the endpoint snapshot */
-		msg = sink->messages[5];
-	}
-
-	type = stasis_message_type(msg);
-	ast_test_validate(test, ast_endpoint_snapshot_type() == type);
-	actual_snapshot = stasis_message_data(msg);
-	ast_test_validate(test, 0 == actual_snapshot->num_channels);
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(state_changes);
-	AST_TEST_UNREGISTER(cache_clear);
-	AST_TEST_UNREGISTER(channel_messages);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(state_changes);
-	AST_TEST_REGISTER(cache_clear);
-	AST_TEST_REGISTER(channel_messages);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint stasis-related testing",
-	.load = load_module,
-	.unload = unload_module,
-	.nonoptreq = "res_stasis_test",
-	);
diff --git a/tests/test_stringfields.c b/tests/test_stringfields.c
index 7123480..0a3e5d5 100644
--- a/tests/test_stringfields.c
+++ b/tests/test_stringfields.c
@@ -212,7 +212,7 @@ AST_TEST_DEFINE(string_field_test)
 	}
 
 	if (AST_STRING_FIELD_ALLOCATION(test_struct.string2) != strlen("hippopotamus face") + 1) {
-		ast_test_status_update(test, "The allocation amount is incorrect for string2. We expect %lu but it has %hu\n",
+		ast_test_status_update(test, "The allocation amount is incorrect for string2. We expect %lu but it has %d\n",
 				(unsigned long) strlen("hippopotamus face"), AST_STRING_FIELD_ALLOCATION(test_struct.string2) + 1);
 		goto error;
 	} else {
@@ -294,115 +294,8 @@ error:
 	return AST_TEST_FAIL;
 }
 
-AST_TEST_DEFINE(string_field_aggregate_test)
-{
-	struct test_struct {
-		AST_DECLARE_STRING_FIELDS (
-			AST_STRING_FIELD(string1);
-			AST_STRING_FIELD(string2);
-		);
-		int foo;
-	} inst1, inst2, inst3, inst4;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "string_field_aggregate_test";
-		info->category = "/main/utils/";
-		info->summary = "Test stringfield aggregate operations";
-		info->description =
-			"This tests the structure comparison and copy macros of the stringfield API";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_string_field_init(&inst1, 32);
-	ast_string_field_init(&inst2, 32);
-	ast_string_field_init(&inst3, 32);
-	ast_string_field_init(&inst4, 32);
-
-	ast_string_field_set(&inst1, string1, "foo");
-	ast_string_field_set(&inst1, string2, "bar");
-	inst1.foo = 1;
-
-	ast_string_field_set(&inst2, string2, "bar");
-	ast_string_field_set(&inst2, string1, "foo");
-	inst2.foo = 2;
-
-	ast_string_field_set(&inst3, string1, "foo");
-	ast_string_field_set(&inst3, string2, "baz");
-	inst3.foo = 3;
-
-	ast_string_field_set(&inst4, string1, "faz");
-	ast_string_field_set(&inst4, string2, "baz");
-	inst4.foo = 3;
-
-	if (ast_string_fields_cmp(&inst1, &inst2)) {
-		ast_test_status_update(test, "Structures 1/2 should be equal!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 1/2 are equal as expected.\n");
-	}
-
-	if (!ast_string_fields_cmp(&inst1, &inst3)) {
-		ast_test_status_update(test, "Structures 1/3 should be different!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 1/3 are different as expected.\n");
-	}
-
-	if (!ast_string_fields_cmp(&inst2, &inst3)) {
-		ast_test_status_update(test, "Structures 2/3 should be different!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 2/3 are different as expected.\n");
-	}
-
-	if (!ast_string_fields_cmp(&inst3, &inst4)) {
-		ast_test_status_update(test, "Structures 3/4 should be different!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 3/4 are different as expected.\n");
-	}
-
-	if (ast_string_fields_copy(&inst1, &inst3)) {
-		ast_test_status_update(test, "Copying from structure 3 to structure 4 failed!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Copying from structure 3 to structure 4 succeeded!\n");
-	}
-
-	/* inst1 and inst3 should now be equal and inst1 should no longer be equal to inst2 */
-	if (ast_string_fields_cmp(&inst1, &inst3)) {
-		ast_test_status_update(test, "Structures 1/3 should be equal!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 1/3 are equal as expected.\n");
-	}
-
-	if (!ast_string_fields_cmp(&inst1, &inst2)) {
-		ast_test_status_update(test, "Structures 1/2 should be different!\n");
-		goto error;
-	} else {
-		ast_test_status_update(test, "Structures 1/2 are different as expected.\n");
-	}
-
-	ast_string_field_free_memory(&inst1);
-	ast_string_field_free_memory(&inst2);
-	ast_string_field_free_memory(&inst3);
-	ast_string_field_free_memory(&inst4);
-	return AST_TEST_PASS;
-error:
-	ast_string_field_free_memory(&inst1);
-	ast_string_field_free_memory(&inst2);
-	ast_string_field_free_memory(&inst3);
-	ast_string_field_free_memory(&inst4);
-	return AST_TEST_FAIL;
-}
-
 static int unload_module(void)
 {
-	AST_TEST_UNREGISTER(string_field_aggregate_test);
 	AST_TEST_UNREGISTER(string_field_test);
 	return 0;
 }
@@ -410,7 +303,6 @@ static int unload_module(void)
 static int load_module(void)
 {
 	AST_TEST_REGISTER(string_field_test);
-	AST_TEST_REGISTER(string_field_aggregate_test);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/tests/test_strings.c b/tests/test_strings.c
index 394057e..2f9a0f3 100644
--- a/tests/test_strings.c
+++ b/tests/test_strings.c
@@ -34,7 +34,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 427356 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/test.h"
 #include "asterisk/utils.h"
@@ -251,148 +251,15 @@ cleanup:
 	return res;
 }
 
-AST_TEST_DEFINE(begins_with_test)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "begins_with";
-		info->category = "/main/strings/";
-		info->summary = "Test ast_begins_with";
-		info->description = "Test ast_begins_with";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	// prefixes
-	ast_test_validate(test, 1 == ast_begins_with("foobar", "foobar"));
-	ast_test_validate(test, 1 == ast_begins_with("foobar", "foo"));
-	ast_test_validate(test, 1 == ast_begins_with("foobar", ""));
-	ast_test_validate(test, 1 == ast_begins_with("", ""));
-
-	// not prefixes
-	ast_test_validate(test, 0 == ast_begins_with("foobar", "bang"));
-	ast_test_validate(test, 0 == ast_begins_with("foobar", "foobat"));
-	ast_test_validate(test, 0 == ast_begins_with("boo", "boom"));
-	ast_test_validate(test, 0 == ast_begins_with("", "blitz"));
-
-	// nothing failed; we're all good!
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(ends_with_test)
-{
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "ends_with";
-		info->category = "/main/strings/";
-		info->summary = "Test ast_ends_with";
-		info->description = "Test ast_ends_with";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	// prefixes
-	ast_test_validate(test, 1 == ast_ends_with("foobar", "foobar"));
-	ast_test_validate(test, 1 == ast_ends_with("foobar", "bar"));
-	ast_test_validate(test, 1 == ast_ends_with("foobar", ""));
-	ast_test_validate(test, 1 == ast_ends_with("", ""));
-
-	// not suffixes
-	ast_test_validate(test, 0 == ast_ends_with("bar", "bbar"));
-	ast_test_validate(test, 0 == ast_ends_with("foobar", "bang"));
-	ast_test_validate(test, 0 == ast_ends_with("foobar", "foobat"));
-	ast_test_validate(test, 0 == ast_ends_with("boo", "boom"));
-	ast_test_validate(test, 0 == ast_ends_with("", "blitz"));
-
-	// nothing failed; we're all good!
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(strsep_test)
-{
-	char *test1, *test2, *test3;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "strsep";
-		info->category = "/main/strings/";
-		info->summary = "Test ast_strsep";
-		info->description = "Test ast_strsep";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	test1 = ast_strdupa("ghi=jkl,mno='pqr,stu',abc=def, vwx = yz1 ,  vwx = yz1 ,  '"
-		" vwx = yz1 ' ,  ' vwx , yz1 ',v\"w\"x, '\"x,v\",\"x\"' , \" i\\'m a test\""
-		", \" i\\'m a, test\", \" i\\'m a, test\", e\\,nd, end\\");
-
-	test2 = ast_strsep(&test1, ',', 0);
-	ast_test_validate(test, 0 == strcmp("ghi=jkl", test2));
-
-	test3 = ast_strsep(&test2, '=', 0);
-	ast_test_validate(test, 0 == strcmp("ghi", test3));
-
-	test3 = ast_strsep(&test2, '=', 0);
-	ast_test_validate(test, 0 == strcmp("jkl", test3));
-
-	test2 = ast_strsep(&test1, ',', 0);
-	ast_test_validate(test, 0 == strcmp("mno='pqr,stu'", test2));
-
-	test3 = ast_strsep(&test2, '=', 0);
-	ast_test_validate(test, 0 == strcmp("mno", test3));
-
-	test3 = ast_strsep(&test2, '=', 0);
-	ast_test_validate(test, 0 == strcmp("'pqr,stu'", test3));
-
-	test2 = ast_strsep(&test1, ',', 0);
-	ast_test_validate(test, 0 == strcmp("abc=def", test2));
-
-	test2 = ast_strsep(&test1, ',', 0);
-	ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM);
-	ast_test_validate(test, 0 == strcmp("vwx = yz1", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_STRIP);
-	ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_STRIP | AST_STRSEP_TRIM);
-	ast_test_validate(test, 0 == strcmp("vwx , yz1", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_STRIP | AST_STRSEP_TRIM);
-	ast_test_validate(test, 0 == strcmp("v\"w\"x", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM);
-	ast_test_validate(test, 0 == strcmp("'\"x,v\",\"x\"'", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM);
-	ast_test_validate(test, 0 == strcmp("\" i\\'m a test\"", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);
-	ast_test_validate(test, 0 == strcmp("\" i'm a, test\"", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_ALL);
-	ast_test_validate(test, 0 == strcmp("i'm a, test", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);
-	ast_test_validate(test, 0 == strcmp("e,nd", test2));
-
-	test2 = ast_strsep(&test1, ',', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);
-	ast_test_validate(test, 0 == strcmp("end", test2));
-
-	// nothing failed; we're all good!
-	return AST_TEST_PASS;
-}
-
 static int test_semi(char *string1, char *string2, int test_len)
 {
 	char *test2 = NULL;
-	if (test_len >= 0) {
+
+	if (test_len > 0) {
 		test2 = ast_alloca(test_len);
 		*test2 = '\0';
+	} else if (test_len == 0) {
+		test2 = "";
 	}
 	ast_escape_semicolons(string1, test2, test_len);
 	if (test2 != NULL && strcmp(string2, test2) == 0) {
@@ -455,9 +322,6 @@ AST_TEST_DEFINE(escape_semicolons_test)
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(str_test);
-	AST_TEST_UNREGISTER(begins_with_test);
-	AST_TEST_UNREGISTER(ends_with_test);
-	AST_TEST_UNREGISTER(strsep_test);
 	AST_TEST_UNREGISTER(escape_semicolons_test);
 	return 0;
 }
@@ -465,9 +329,6 @@ static int unload_module(void)
 static int load_module(void)
 {
 	AST_TEST_REGISTER(str_test);
-	AST_TEST_REGISTER(begins_with_test);
-	AST_TEST_REGISTER(ends_with_test);
-	AST_TEST_REGISTER(strsep_test);
 	AST_TEST_REGISTER(escape_semicolons_test);
 	return AST_MODULE_LOAD_SUCCESS;
 }
diff --git a/tests/test_substitution.c b/tests/test_substitution.c
index e3b2247..0fa0a58 100644
--- a/tests/test_substitution.c
+++ b/tests/test_substitution.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410158 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -243,8 +243,7 @@ AST_TEST_DEFINE(test_substitution)
 
 	ast_test_status_update(test, "Testing variable substitution ...\n");
 
-	c = ast_channel_alloc(0, 0, "", "", "", "", "", NULL, NULL, 0, "Test/substitution");
-	ast_channel_unlock(c);
+	c = ast_channel_alloc(0, 0, "", "", "", "", "", "", 0, "Test/substitution");
 
 #define TEST(t) if (t == AST_TEST_FAIL) { res = AST_TEST_FAIL; }
 #if 0
diff --git a/tests/test_taskprocessor.c b/tests/test_taskprocessor.c
deleted file mode 100644
index be48f92..0000000
--- a/tests/test_taskprocessor.c
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012-2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief taskprocessor unit tests
- *
- * \author Mark Michelson <mmichelson at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include "asterisk/test.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-
-/*!
- * \brief userdata associated with baseline taskprocessor test
- */
-struct task_data {
-	/* Condition used to signal to queuing thread that task was executed */
-	ast_cond_t cond;
-	/* Lock protecting the condition */
-	ast_mutex_t lock;
-	/*! Boolean indicating that the task was run */
-	int task_complete;
-};
-
-static void task_data_dtor(void *obj)
-{
-	struct task_data *task_data = obj;
-
-	ast_mutex_destroy(&task_data->lock);
-	ast_cond_destroy(&task_data->cond);
-}
-
-/*! \brief Create a task_data object */
-static struct task_data *task_data_create(void)
-{
-	struct task_data *task_data =
-		ao2_alloc(sizeof(*task_data), task_data_dtor);
-
-	if (!task_data) {
-		return NULL;
-	}
-
-	ast_cond_init(&task_data->cond, NULL);
-	ast_mutex_init(&task_data->lock);
-	task_data->task_complete = 0;
-
-	return task_data;
-}
-
-/*!
- * \brief Queued task for baseline test.
- *
- * The task simply sets a boolean to indicate the
- * task has been run and then signals a condition
- * saying it's complete
- */
-static int task(void *data)
-{
-	struct task_data *task_data = data;
-	SCOPED_MUTEX(lock, &task_data->lock);
-	task_data->task_complete = 1;
-	ast_cond_signal(&task_data->cond);
-	return 0;
-}
-
-/*!
- * \brief Wait for a task to execute.
- */
-static int task_wait(struct task_data *task_data)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end;
-	SCOPED_MUTEX(lock, &task_data->lock);
-
-	end.tv_sec = start.tv_sec + 30;
-	end.tv_nsec = start.tv_usec * 1000;
-
-	while (!task_data->task_complete) {
-		int res;
-		res = ast_cond_timedwait(&task_data->cond, &task_data->lock,
-			&end);
-		if (res == ETIMEDOUT) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Baseline test for default taskprocessor
- *
- * This test ensures that when a task is added to a taskprocessor that
- * has been allocated with a default listener that the task gets executed
- * as expected
- */
-AST_TEST_DEFINE(default_taskprocessor)
-{
-	RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
-	RAII_VAR(struct task_data *, task_data, NULL, ao2_cleanup);
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "default_taskprocessor";
-		info->category = "/main/taskprocessor/";
-		info->summary = "Test of default taskproccesor";
-		info->description =
-			"Ensures that a queued task gets executed.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
-
-	if (!tps) {
-		ast_test_status_update(test, "Unable to create test taskprocessor\n");
-		return AST_TEST_FAIL;
-	}
-
-	task_data = task_data_create();
-	if (!task_data) {
-		ast_test_status_update(test, "Unable to create task_data\n");
-		return AST_TEST_FAIL;
-	}
-
-	ast_taskprocessor_push(tps, task, task_data);
-
-	res = task_wait(task_data);
-	if (res != 0) {
-		ast_test_status_update(test, "Queued task did not execute!\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-#define NUM_TASKS 20000
-
-/*!
- * \brief Relevant data associated with taskprocessor load test
- */
-static struct load_task_data {
-	/*! Condition used to indicate a task has completed executing */
-	ast_cond_t cond;
-	/*! Lock used to protect the condition */
-	ast_mutex_t lock;
-	/*! Counter of the number of completed tasks */
-	int tasks_completed;
-	/*! Storage for task-specific data */
-	int task_rand[NUM_TASKS];
-} load_task_results;
-
-/*!
- * \brief a queued task to be used in the taskprocessor load test
- *
- * The task increments the number of tasks executed and puts the passed-in
- * data into the next slot in the array of random data.
- */
-static int load_task(void *data)
-{
-	int *randdata = data;
-	SCOPED_MUTEX(lock, &load_task_results.lock);
-	load_task_results.task_rand[load_task_results.tasks_completed++] = *randdata;
-	ast_cond_signal(&load_task_results.cond);
-	return 0;
-}
-
-/*!
- * \brief Load test for taskprocessor with default listener
- *
- * This test queues a large number of tasks, each with random data associated.
- * The test ensures that all of the tasks are run and that the tasks are executed
- * in the same order that they were queued
- */
-AST_TEST_DEFINE(default_taskprocessor_load)
-{
-	struct ast_taskprocessor *tps;
-	struct timeval start;
-	struct timespec ts;
-	enum ast_test_result_state res = AST_TEST_PASS;
-	int timedwait_res;
-	int i;
-	int rand_data[NUM_TASKS];
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "default_taskprocessor_load";
-		info->category = "/main/taskprocessor/";
-		info->summary = "Load test of default taskproccesor";
-		info->description =
-			"Ensure that a large number of queued tasks are executed in the proper order.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
-
-	if (!tps) {
-		ast_test_status_update(test, "Unable to create test taskprocessor\n");
-		return AST_TEST_FAIL;
-	}
-
-	start = ast_tvnow();
-
-	ts.tv_sec = start.tv_sec + 60;
-	ts.tv_nsec = start.tv_usec * 1000;
-
-	ast_cond_init(&load_task_results.cond, NULL);
-	ast_mutex_init(&load_task_results.lock);
-	load_task_results.tasks_completed = 0;
-
-	for (i = 0; i < NUM_TASKS; ++i) {
-		rand_data[i] = ast_random();
-		ast_taskprocessor_push(tps, load_task, &rand_data[i]);
-	}
-
-	ast_mutex_lock(&load_task_results.lock);
-	while (load_task_results.tasks_completed < NUM_TASKS) {
-		timedwait_res = ast_cond_timedwait(&load_task_results.cond, &load_task_results.lock, &ts);
-		if (timedwait_res == ETIMEDOUT) {
-			break;
-		}
-	}
-	ast_mutex_unlock(&load_task_results.lock);
-
-	if (load_task_results.tasks_completed != NUM_TASKS) {
-		ast_test_status_update(test, "Unexpected number of tasks executed. Expected %d but got %d\n",
-				NUM_TASKS, load_task_results.tasks_completed);
-		res = AST_TEST_FAIL;
-		goto test_end;
-	}
-
-	for (i = 0; i < NUM_TASKS; ++i) {
-		if (rand_data[i] != load_task_results.task_rand[i]) {
-			ast_test_status_update(test, "Queued tasks did not execute in order\n");
-			res = AST_TEST_FAIL;
-			goto test_end;
-		}
-	}
-
-test_end:
-	tps = ast_taskprocessor_unreference(tps);
-	ast_mutex_destroy(&load_task_results.lock);
-	ast_cond_destroy(&load_task_results.cond);
-	return res;
-}
-
-/*!
- * \brief Private data for the test taskprocessor listener
- */
-struct test_listener_pvt {
-	/* Counter of number of tasks pushed to the queue */
-	int num_pushed;
-	/* Counter of number of times the queue was emptied */
-	int num_emptied;
-	/* Counter of number of times that a pushed task occurred on an empty queue */
-	int num_was_empty;
-	/* Boolean indicating whether the shutdown callback was called */
-	int shutdown;
-};
-
-/*!
- * \brief test taskprocessor listener's alloc callback
- */
-static void *test_listener_pvt_alloc(void)
-{
-	struct test_listener_pvt *pvt;
-
-	pvt = ast_calloc(1, sizeof(*pvt));
-	return pvt;
-}
-
-/*!
- * \brief test taskprocessor listener's start callback
- */
-static int test_start(struct ast_taskprocessor_listener *listener)
-{
-	return 0;
-}
-
-/*!
- * \brief test taskprocessor listener's task_pushed callback
- *
- * Adjusts private data's stats as indicated by the parameters.
- */
-static void test_task_pushed(struct ast_taskprocessor_listener *listener, int was_empty)
-{
-	struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
-	++pvt->num_pushed;
-	if (was_empty) {
-		++pvt->num_was_empty;
-	}
-}
-
-/*!
- * \brief test taskprocessor listener's emptied callback.
- */
-static void test_emptied(struct ast_taskprocessor_listener *listener)
-{
-	struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
-	++pvt->num_emptied;
-}
-
-/*!
- * \brief test taskprocessor listener's shutdown callback.
- */
-static void test_shutdown(struct ast_taskprocessor_listener *listener)
-{
-	struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
-	pvt->shutdown = 1;
-}
-
-static const struct ast_taskprocessor_listener_callbacks test_callbacks = {
-	.start = test_start,
-	.task_pushed = test_task_pushed,
-	.emptied = test_emptied,
-	.shutdown = test_shutdown,
-};
-
-/*!
- * \brief Queued task for taskprocessor listener test.
- *
- * Does nothing.
- */
-static int listener_test_task(void *ignore)
-{
-	return 0;
-}
-
-/*!
- * \brief helper to ensure that statistics the listener is keeping are what we expect
- *
- * \param test The currently-running test
- * \param pvt The private data for the taskprocessor listener
- * \param num_pushed The expected current number of tasks pushed to the processor
- * \param num_emptied The expected current number of times the taskprocessor has become empty
- * \param num_was_empty The expected current number of times that tasks were pushed to an empty taskprocessor
- * \retval -1 Stats were not as expected
- * \retval 0 Stats were as expected
- */
-static int check_stats(struct ast_test *test, const struct test_listener_pvt *pvt, int num_pushed, int num_emptied, int num_was_empty)
-{
-	if (pvt->num_pushed != num_pushed) {
-		ast_test_status_update(test, "Unexpected number of tasks pushed. Expected %d but got %d\n",
-				num_pushed, pvt->num_pushed);
-		return -1;
-	}
-
-	if (pvt->num_emptied != num_emptied) {
-		ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
-				num_emptied, pvt->num_emptied);
-		return -1;
-	}
-
-	if (pvt->num_was_empty != num_was_empty) {
-		ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
-				num_was_empty, pvt->num_emptied);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*!
- * \brief Test for a taskprocessor with custom listener.
- *
- * This test pushes tasks to a taskprocessor with a custom listener, executes the taskss,
- * and destroys the taskprocessor.
- *
- * The test ensures that the listener's callbacks are called when expected and that the data
- * being passed in is accurate.
- */
-AST_TEST_DEFINE(taskprocessor_listener)
-{
-	struct ast_taskprocessor *tps = NULL;
-	struct ast_taskprocessor_listener *listener = NULL;
-	struct test_listener_pvt *pvt = NULL;
-	enum ast_test_result_state res = AST_TEST_PASS;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "taskprocessor_listener";
-		info->category = "/main/taskprocessor/";
-		info->summary = "Test of taskproccesor listeners";
-		info->description =
-			"Ensures that listener callbacks are called when expected.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	pvt = test_listener_pvt_alloc();
-	if (!pvt) {
-		ast_test_status_update(test, "Unable to allocate test taskprocessor listener user data\n");
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_taskprocessor_listener_alloc(&test_callbacks, pvt);
-	if (!listener) {
-		ast_test_status_update(test, "Unable to allocate test taskprocessor listener\n");
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	tps = ast_taskprocessor_create_with_listener("test_listener", listener);
-	if (!tps) {
-		ast_test_status_update(test, "Unable to allocate test taskprocessor\n");
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	ast_taskprocessor_push(tps, listener_test_task, NULL);
-
-	if (check_stats(test, pvt, 1, 0, 1) < 0) {
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	ast_taskprocessor_push(tps, listener_test_task, NULL);
-
-	if (check_stats(test, pvt, 2, 0, 1) < 0) {
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	ast_taskprocessor_execute(tps);
-
-	if (check_stats(test, pvt, 2, 0, 1) < 0) {
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	ast_taskprocessor_execute(tps);
-
-	if (check_stats(test, pvt, 2, 1, 1) < 0) {
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-	tps = ast_taskprocessor_unreference(tps);
-
-	if (!pvt->shutdown) {
-		res = AST_TEST_FAIL;
-		goto test_exit;
-	}
-
-test_exit:
-	ao2_cleanup(listener);
-	/* This is safe even if tps is NULL */
-	ast_taskprocessor_unreference(tps);
-	ast_free(pvt);
-	return res;
-}
-
-struct shutdown_data {
-	ast_cond_t in;
-	ast_cond_t out;
-	ast_mutex_t lock;
-	int task_complete;
-	int task_started;
-	int task_stop_waiting;
-};
-
-static void shutdown_data_dtor(void *data)
-{
-	struct shutdown_data *shutdown_data = data;
-	ast_mutex_destroy(&shutdown_data->lock);
-	ast_cond_destroy(&shutdown_data->in);
-	ast_cond_destroy(&shutdown_data->out);
-}
-
-static struct shutdown_data *shutdown_data_create(int dont_wait)
-{
-	RAII_VAR(struct shutdown_data *, shutdown_data, NULL, ao2_cleanup);
-
-	shutdown_data = ao2_alloc(sizeof(*shutdown_data), shutdown_data_dtor);
-	if (!shutdown_data) {
-		return NULL;
-	}
-
-	ast_mutex_init(&shutdown_data->lock);
-	ast_cond_init(&shutdown_data->in, NULL);
-	ast_cond_init(&shutdown_data->out, NULL);
-	shutdown_data->task_stop_waiting = dont_wait;
-	ao2_ref(shutdown_data, +1);
-	return shutdown_data;
-}
-
-static int shutdown_task_exec(void *data)
-{
-	struct shutdown_data *shutdown_data = data;
-	SCOPED_MUTEX(lock, &shutdown_data->lock);
-	shutdown_data->task_started = 1;
-	ast_cond_signal(&shutdown_data->out);
-	while (!shutdown_data->task_stop_waiting) {
-		ast_cond_wait(&shutdown_data->in, &shutdown_data->lock);
-	}
-	shutdown_data->task_complete = 1;
-	ast_cond_signal(&shutdown_data->out);
-	return 0;
-}
-
-static int shutdown_waitfor_completion(struct shutdown_data *shutdown_data)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	SCOPED_MUTEX(lock, &shutdown_data->lock);
-
-	while (!shutdown_data->task_complete) {
-		if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	return shutdown_data->task_complete;
-}
-
-static int shutdown_has_completed(struct shutdown_data *shutdown_data)
-{
-	SCOPED_MUTEX(lock, &shutdown_data->lock);
-	return shutdown_data->task_complete;
-}
-
-static int shutdown_waitfor_start(struct shutdown_data *shutdown_data)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	SCOPED_MUTEX(lock, &shutdown_data->lock);
-
-	while (!shutdown_data->task_started) {
-		if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	return shutdown_data->task_started;
-}
-
-static void shutdown_poke(struct shutdown_data *shutdown_data)
-{
-	SCOPED_MUTEX(lock, &shutdown_data->lock);
-	shutdown_data->task_stop_waiting = 1;
-	ast_cond_signal(&shutdown_data->in);
-}
-
-static void *tps_shutdown_thread(void *data)
-{
-	struct ast_taskprocessor *tps = data;
-	ast_taskprocessor_unreference(tps);
-	return NULL;
-}
-
-AST_TEST_DEFINE(taskprocessor_shutdown)
-{
-	RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
-	RAII_VAR(struct shutdown_data *, task1, NULL, ao2_cleanup);
-	RAII_VAR(struct shutdown_data *, task2, NULL, ao2_cleanup);
-	int push_res;
-	int wait_res;
-	int pthread_res;
-	pthread_t shutdown_thread;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "taskprocessor_shutdown";
-		info->category = "/main/taskprocessor/";
-		info->summary = "Test of taskproccesor shutdown sequence";
-		info->description =
-			"Ensures that all tasks run to completion after the taskprocessor has been unref'ed.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tps = ast_taskprocessor_get("test_shutdown", TPS_REF_DEFAULT);
-	task1 = shutdown_data_create(0); /* task1 waits to be poked */
-	task2 = shutdown_data_create(1); /* task2 waits for nothing */
-
-	if (!tps || !task1 || !task2) {
-		ast_test_status_update(test, "Allocation error\n");
-		return AST_TEST_FAIL;
-	}
-
-	push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task1);
-	if (push_res != 0) {
-		ast_test_status_update(test, "Could not push task1\n");
-		return AST_TEST_FAIL;
-	}
-
-	push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task2);
-	if (push_res != 0) {
-		ast_test_status_update(test, "Could not push task2\n");
-		return AST_TEST_FAIL;
-	}
-
-	wait_res = shutdown_waitfor_start(task1);
-	if (!wait_res) {
-		ast_test_status_update(test, "Task1 didn't start\n");
-		return AST_TEST_FAIL;
-	}
-
-	pthread_res = ast_pthread_create(&shutdown_thread, NULL, tps_shutdown_thread, tps);
-	if (pthread_res != 0) {
-		ast_test_status_update(test, "Failed to create shutdown thread\n");
-		return AST_TEST_FAIL;
-	}
-	tps = NULL;
-
-	/* Wakeup task1; it should complete */
-	shutdown_poke(task1);
-	wait_res = shutdown_waitfor_completion(task1);
-	if (!wait_res) {
-		ast_test_status_update(test, "Task1 didn't complete\n");
-		return AST_TEST_FAIL;
-	}
-
-	/* Wait for shutdown to complete */
-	pthread_join(shutdown_thread, NULL);
-
-	/* Should have also also completed task2 */
-	wait_res = shutdown_has_completed(task2);
-	if (!wait_res) {
-		ast_test_status_update(test, "Task2 didn't finish\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int local_task_exe(struct ast_taskprocessor_local *local)
-{
-	int *local_data = local->local_data;
-	struct task_data *task_data = local->data;
-
-	*local_data = 1;
-	task(task_data);
-
-	return 0;
-}
-
-AST_TEST_DEFINE(taskprocessor_push_local)
-{
-	RAII_VAR(struct ast_taskprocessor *, tps, NULL,
-		ast_taskprocessor_unreference);
-	struct task_data *task_data;
-	int local_data;
-	int res;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/main/taskprocessor/";
-		info->summary = "Test of pushing local data";
-		info->description =
-			"Ensures that local data is passed along.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-
-	tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
-	if (!tps) {
-		ast_test_status_update(test, "Unable to create test taskprocessor\n");
-		return AST_TEST_FAIL;
-	}
-
-
-	task_data = task_data_create();
-	if (!task_data) {
-		ast_test_status_update(test, "Unable to create task_data\n");
-		return AST_TEST_FAIL;
-	}
-
-	local_data = 0;
-	ast_taskprocessor_set_local(tps, &local_data);
-
-	ast_taskprocessor_push_local(tps, local_task_exe, task_data);
-
-	res = task_wait(task_data);
-	if (res != 0) {
-		ast_test_status_update(test, "Queued task did not execute!\n");
-		return AST_TEST_FAIL;
-	}
-
-	if (local_data != 1) {
-		ast_test_status_update(test,
-			"Queued task did not set local_data!\n");
-		return AST_TEST_FAIL;
-	}
-
-	return AST_TEST_PASS;
-}
-
-static int unload_module(void)
-{
-	ast_test_unregister(default_taskprocessor);
-	ast_test_unregister(default_taskprocessor_load);
-	ast_test_unregister(taskprocessor_listener);
-	ast_test_unregister(taskprocessor_shutdown);
-	ast_test_unregister(taskprocessor_push_local);
-	return 0;
-}
-
-static int load_module(void)
-{
-	ast_test_register(default_taskprocessor);
-	ast_test_register(default_taskprocessor_load);
-	ast_test_register(taskprocessor_listener);
-	ast_test_register(taskprocessor_shutdown);
-	ast_test_register(taskprocessor_push_local);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "taskprocessor test module");
diff --git a/tests/test_threadpool.c b/tests/test_threadpool.c
deleted file mode 100644
index 79b369d..0000000
--- a/tests/test_threadpool.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012-2013, Digium, Inc.
- *
- * Mark Michelson <mmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief threadpool unit tests
- *
- * \author Mark Michelson <mmichelson at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-#include "asterisk/astobj2.h"
-#include "asterisk/lock.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/taskprocessor.h"
-#include "asterisk/test.h"
-#include "asterisk/threadpool.h"
-
-struct test_listener_data {
-	int num_active;
-	int num_idle;
-	int task_pushed;
-	int num_tasks;
-	int empty_notice;
-	int was_empty;
-	ast_mutex_t lock;
-	ast_cond_t cond;
-};
-
-static struct test_listener_data *test_alloc(void)
-{
-	struct test_listener_data *tld = ast_calloc(1, sizeof(*tld));
-	if (!tld) {
-		return NULL;
-	}
-	ast_mutex_init(&tld->lock);
-	ast_cond_init(&tld->cond, NULL);
-	return tld;
-}
-
-static void test_state_changed(struct ast_threadpool *pool,
-		struct ast_threadpool_listener *listener,
-		int active_threads,
-		int idle_threads)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	SCOPED_MUTEX(lock, &tld->lock);
-	tld->num_active = active_threads;
-	tld->num_idle = idle_threads;
-	ast_log(LOG_NOTICE, "Thread state: %d active, %d idle\n", tld->num_active, tld->num_idle);
-	ast_cond_signal(&tld->cond);
-}
-
-static void test_task_pushed(struct ast_threadpool *pool,
-		struct ast_threadpool_listener *listener,
-		int was_empty)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	SCOPED_MUTEX(lock, &tld->lock);
-	tld->task_pushed = 1;
-	++tld->num_tasks;
-	tld->was_empty = was_empty;
-	ast_cond_signal(&tld->cond);
-}
-
-static void test_emptied(struct ast_threadpool *pool,
-		struct ast_threadpool_listener *listener)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	SCOPED_MUTEX(lock, &tld->lock);
-	tld->empty_notice = 1;
-	ast_cond_signal(&tld->cond);
-}
-
-static void test_shutdown(struct ast_threadpool_listener *listener)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	ast_cond_destroy(&tld->cond);
-	ast_mutex_destroy(&tld->lock);
-}
-
-static const struct ast_threadpool_listener_callbacks test_callbacks = {
-	.state_changed = test_state_changed,
-	.task_pushed = test_task_pushed,
-	.emptied = test_emptied,
-	.shutdown = test_shutdown,
-};
-
-struct simple_task_data {
-	int task_executed;
-	ast_mutex_t lock;
-	ast_cond_t cond;
-};
-
-static struct simple_task_data *simple_task_data_alloc(void)
-{
-	struct simple_task_data *std = ast_calloc(1, sizeof(*std));
-
-	if (!std) {
-		return NULL;
-	}
-	ast_mutex_init(&std->lock);
-	ast_cond_init(&std->cond, NULL);
-	return std;
-}
-
-static int simple_task(void *data)
-{
-	struct simple_task_data *std = data;
-	SCOPED_MUTEX(lock, &std->lock);
-	std->task_executed = 1;
-	ast_cond_signal(&std->cond);
-	return 0;
-}
-
-static enum ast_test_result_state wait_until_thread_state(struct ast_test *test, struct test_listener_data *tld, int num_active, int num_idle)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	enum ast_test_result_state res = AST_TEST_PASS;
-	SCOPED_MUTEX(lock, &tld->lock);
-
-	while (!(tld->num_active == num_active && tld->num_idle == num_idle)) {
-		if (ast_cond_timedwait(&tld->cond, &tld->lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	if (tld->num_active != num_active && tld->num_idle != num_idle) {
-		ast_test_status_update(test, "Number of active threads and idle threads not what was expected.\n");
-		ast_test_status_update(test, "Expected %d active threads but got %d\n", num_active, tld->num_active);
-		ast_test_status_update(test, "Expected %d idle threads but got %d\n", num_idle, tld->num_idle);
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-static void wait_for_task_pushed(struct ast_threadpool_listener *listener)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	SCOPED_MUTEX(lock, &tld->lock);
-
-	while (!tld->task_pushed) {
-		if (ast_cond_timedwait(&tld->cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-}
-
-static enum ast_test_result_state wait_for_completion(struct ast_test *test, struct simple_task_data *std)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	enum ast_test_result_state res = AST_TEST_PASS;
-	SCOPED_MUTEX(lock, &std->lock);
-
-	while (!std->task_executed) {
-		if (ast_cond_timedwait(&std->cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	if (!std->task_executed) {
-		ast_test_status_update(test, "Task execution did not occur\n");
-		res = AST_TEST_FAIL;
-	}
-	return res;
-}
-
-static enum ast_test_result_state wait_for_empty_notice(struct ast_test *test, struct test_listener_data *tld)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	enum ast_test_result_state res = AST_TEST_PASS;
-	SCOPED_MUTEX(lock, &tld->lock);
-
-	while (!tld->empty_notice) {
-		if (ast_cond_timedwait(&tld->cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	if (!tld->empty_notice) {
-		ast_test_status_update(test, "Test listener not notified that threadpool is empty\n");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-static enum ast_test_result_state listener_check(
-		struct ast_test *test,
-		struct ast_threadpool_listener *listener,
-		int task_pushed,
-		int was_empty,
-		int num_tasks,
-		int num_active,
-		int num_idle,
-		int empty_notice)
-{
-	struct test_listener_data *tld = ast_threadpool_listener_get_user_data(listener);
-	enum ast_test_result_state res = AST_TEST_PASS;
-
-	if (tld->task_pushed != task_pushed) {
-		ast_test_status_update(test, "Expected task %sto be pushed, but it was%s\n",
-				task_pushed ? "" : "not ", tld->task_pushed ? "" : " not");
-		res = AST_TEST_FAIL;
-	}
-	if (tld->was_empty != was_empty) {
-		ast_test_status_update(test, "Expected %sto be empty, but it was%s\n",
-				was_empty ? "" : "not ", tld->was_empty ? "" : " not");
-		res = AST_TEST_FAIL;
-	}
-	if (tld->num_tasks!= num_tasks) {
-		ast_test_status_update(test, "Expected %d tasks to be pushed, but got %d\n",
-				num_tasks, tld->num_tasks);
-		res = AST_TEST_FAIL;
-	}
-	if (tld->num_active != num_active) {
-		ast_test_status_update(test, "Expected %d active threads, but got %d\n",
-				num_active, tld->num_active);
-		res = AST_TEST_FAIL;
-	}
-	if (tld->num_idle != num_idle) {
-		ast_test_status_update(test, "Expected %d idle threads, but got %d\n",
-				num_idle, tld->num_idle);
-		res = AST_TEST_FAIL;
-	}
-	if (tld->empty_notice != empty_notice) {
-		ast_test_status_update(test, "Expected %s empty notice, but got %s\n",
-				was_empty ? "an" : "no", tld->task_pushed ? "one" : "none");
-		res = AST_TEST_FAIL;
-	}
-
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_push)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std = NULL;
-	struct test_listener_data *tld = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "push";
-		info->category = "/main/threadpool/";
-		info->summary = "Test task";
-		info->description =
-			"Basic threadpool test";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std = simple_task_data_alloc();
-	if (!std) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std);
-
-	wait_for_task_pushed(listener);
-
-	res = listener_check(test, listener, 1, 1, 1, 0, 0, 0);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_initial_threads)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 3,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "initial_threads";
-		info->category = "/main/threadpool/";
-		info->summary = "Test threadpool initialization state";
-		info->description =
-			"Ensure that a threadpool created with a specific size contains the\n"
-			"proper number of idle threads.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 3);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(tld);
-	return res;
-}
-
-
-AST_TEST_DEFINE(threadpool_thread_creation)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "thread_creation";
-		info->category = "/main/threadpool/";
-		info->summary = "Test threadpool thread creation";
-		info->description =
-			"Ensure that threads can be added to a threadpool";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	/* Now let's create a thread. It should start active, then go
-	 * idle immediately
-	 */
-	ast_threadpool_set_size(pool, 1);
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_thread_destruction)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "thread_destruction";
-		info->category = "/main/threadpool/";
-		info->summary = "Test threadpool thread destruction";
-		info->description =
-			"Ensure that threads are properly destroyed in a threadpool";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 3);
-
-	res = wait_until_thread_state(test, tld, 0, 3);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 0, 0, 0, 0, 3, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 2);
-
-	res = wait_until_thread_state(test, tld, 0, 2);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_thread_timeout)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 2,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "thread_timeout";
-		info->category = "/main/threadpool/";
-		info->summary = "Test threadpool thread timeout";
-		info->description =
-			"Ensure that a thread with a two second timeout dies as expected.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 1);
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 0, 0, 0, 0, 1, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 0, 0, 0, 0, 0, 0);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_one_task_one_thread)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "one_task_one_thread";
-		info->category = "/main/threadpool/";
-		info->summary = "Test a single task with a single thread";
-		info->description =
-			"Push a task into an empty threadpool, then add a thread to the pool.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std = simple_task_data_alloc();
-	if (!std) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std);
-
-	ast_threadpool_set_size(pool, 1);
-
-	/* Threads added to the pool are active when they start,
-	 * so the newly-created thread should immediately execute
-	 * the waiting task.
-	 */
-	res = wait_for_completion(test, std);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* After completing the task, the thread should go idle */
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std);
-	ast_free(tld);
-	return res;
-
-}
-
-AST_TEST_DEFINE(threadpool_one_thread_one_task)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "one_thread_one_task";
-		info->category = "/main/threadpool/";
-		info->summary = "Test a single thread with a single task";
-		info->description =
-			"Add a thread to the pool and then push a task to it.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std = simple_task_data_alloc();
-	if (!std) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 1);
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std);
-
-	res = wait_for_completion(test, std);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* After completing the task, the thread should go idle */
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_one_thread_multiple_tasks)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std1 = NULL;
-	struct simple_task_data *std2 = NULL;
-	struct simple_task_data *std3 = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "one_thread_multiple_tasks";
-		info->category = "/main/threadpool/";
-		info->summary = "Test a single thread with multiple tasks";
-		info->description =
-			"Add a thread to the pool and then push three tasks to it.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std1 = simple_task_data_alloc();
-	std2 = simple_task_data_alloc();
-	std3 = simple_task_data_alloc();
-	if (!std1 || !std2 || !std3) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 1);
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std1);
-	ast_threadpool_push(pool, simple_task, std2);
-	ast_threadpool_push(pool, simple_task, std3);
-
-	res = wait_for_completion(test, std1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_completion(test, std2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_completion(test, std3);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 3, 0, 1, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std1);
-	ast_free(std2);
-	ast_free(std3);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_auto_increment)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std1 = NULL;
-	struct simple_task_data *std2 = NULL;
-	struct simple_task_data *std3 = NULL;
-	struct simple_task_data *std4 = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 3,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "auto_increment";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that the threadpool grows as tasks are added";
-		info->description =
-			"Create an empty threadpool and push a task to it. Once the task is\n"
-			"pushed, the threadpool should add three threads and be able to\n"
-			"handle the task. The threads should then go idle\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std1 = simple_task_data_alloc();
-	std2 = simple_task_data_alloc();
-	std3 = simple_task_data_alloc();
-	std4 = simple_task_data_alloc();
-	if (!std1 || !std2 || !std3 || !std4) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std1);
-
-	/* Pushing the task should result in the threadpool growing
-	 * by three threads. This will allow the task to actually execute
-	 */
-	res = wait_for_completion(test, std1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 3);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* Now push three tasks into the pool and ensure the pool does not
-	 * grow.
-	 */
-	ast_threadpool_push(pool, simple_task, std2);
-	ast_threadpool_push(pool, simple_task, std3);
-	ast_threadpool_push(pool, simple_task, std4);
-
-	res = wait_for_completion(test, std2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_completion(test, std3);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_completion(test, std4);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 3);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = listener_check(test, listener, 1, 0, 4, 0, 3, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std1);
-	ast_free(std2);
-	ast_free(std3);
-	ast_free(std4);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_max_size)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 3,
-		.initial_size = 0,
-		.max_size = 2,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "max_size";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that the threadpool does not exceed its maximum size restriction";
-		info->description =
-			"Create an empty threadpool and push a task to it. Once the task is\n"
-			"pushed, the threadpool should attempt to grow by three threads, but the\n"
-			"pool's restrictions should only allow two threads to be added.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std = simple_task_data_alloc();
-	if (!std) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std);
-
-	res = wait_for_completion(test, std);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 1, 1, 0, 2, 1);
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_reactivation)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct simple_task_data *std1 = NULL;
-	struct simple_task_data *std2 = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "reactivation";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that a threadpool reactivates when work is added";
-		info->description =
-			"Push a task into a threadpool. Make sure the task executes and the\n"
-			"thread goes idle. Then push a second task and ensure that the thread\n"
-			"awakens and executes the second task.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	std1 = simple_task_data_alloc();
-	std2 = simple_task_data_alloc();
-	if (!std1 || !std2) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, simple_task, std1);
-
-	ast_threadpool_set_size(pool, 1);
-
-	res = wait_for_completion(test, std1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 1, 1, 0, 1, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* Now make sure the threadpool reactivates when we add a second task */
-	ast_threadpool_push(pool, simple_task, std2);
-
-	res = wait_for_completion(test, std2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_for_empty_notice(test, tld);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 1, 2, 0, 1, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(std1);
-	ast_free(std2);
-	ast_free(tld);
-	return res;
-
-}
-
-struct complex_task_data {
-	int task_started;
-	int task_executed;
-	int continue_task;
-	ast_mutex_t lock;
-	ast_cond_t stall_cond;
-	ast_cond_t notify_cond;
-};
-
-static struct complex_task_data *complex_task_data_alloc(void)
-{
-	struct complex_task_data *ctd = ast_calloc(1, sizeof(*ctd));
-
-	if (!ctd) {
-		return NULL;
-	}
-	ast_mutex_init(&ctd->lock);
-	ast_cond_init(&ctd->stall_cond, NULL);
-	ast_cond_init(&ctd->notify_cond, NULL);
-	return ctd;
-}
-
-static int complex_task(void *data)
-{
-	struct complex_task_data *ctd = data;
-	SCOPED_MUTEX(lock, &ctd->lock);
-	/* Notify that we started */
-	ctd->task_started = 1;
-	ast_cond_signal(&ctd->notify_cond);
-	while (!ctd->continue_task) {
-		ast_cond_wait(&ctd->stall_cond, lock);
-	}
-	/* We got poked. Finish up */
-	ctd->task_executed = 1;
-	ast_cond_signal(&ctd->notify_cond);
-	return 0;
-}
-
-static void poke_worker(struct complex_task_data *ctd)
-{
-	SCOPED_MUTEX(lock, &ctd->lock);
-	ctd->continue_task = 1;
-	ast_cond_signal(&ctd->stall_cond);
-}
-
-static int wait_for_complex_start(struct complex_task_data *ctd)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	SCOPED_MUTEX(lock, &ctd->lock);
-
-	while (!ctd->task_started) {
-		if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	return ctd->task_started;
-}
-
-static int has_complex_started(struct complex_task_data *ctd)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 1,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	SCOPED_MUTEX(lock, &ctd->lock);
-
-	while (!ctd->task_started) {
-		if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	return ctd->task_started;
-}
-
-static enum ast_test_result_state wait_for_complex_completion(struct complex_task_data *ctd)
-{
-	struct timeval start = ast_tvnow();
-	struct timespec end = {
-		.tv_sec = start.tv_sec + 5,
-		.tv_nsec = start.tv_usec * 1000
-	};
-	enum ast_test_result_state res = AST_TEST_PASS;
-	SCOPED_MUTEX(lock, &ctd->lock);
-
-	while (!ctd->task_executed) {
-		if (ast_cond_timedwait(&ctd->notify_cond, lock, &end) == ETIMEDOUT) {
-			break;
-		}
-	}
-
-	if (!ctd->task_executed) {
-		res = AST_TEST_FAIL;
-	}
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_task_distribution)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct complex_task_data *ctd1 = NULL;
-	struct complex_task_data *ctd2 = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "task_distribution";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that tasks are evenly distributed to threads";
-		info->description =
-			"Push two tasks into a threadpool. Ensure that each is handled by\n"
-			"a separate thread\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	ctd1 = complex_task_data_alloc();
-	ctd2 = complex_task_data_alloc();
-	if (!ctd1 || !ctd2) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, complex_task, ctd1);
-	ast_threadpool_push(pool, complex_task, ctd2);
-
-	ast_threadpool_set_size(pool, 2);
-
-	res = wait_until_thread_state(test, tld, 2, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 2, 2, 0, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* The tasks are stalled until we poke them */
-	poke_worker(ctd1);
-	poke_worker(ctd2);
-
-	res = wait_for_complex_completion(ctd1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_complex_completion(ctd2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 2, 0, 2, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(ctd1);
-	ast_free(ctd2);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_more_destruction)
-{
-	struct ast_threadpool *pool = NULL;
-	struct ast_threadpool_listener *listener = NULL;
-	struct complex_task_data *ctd1 = NULL;
-	struct complex_task_data *ctd2 = NULL;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct test_listener_data *tld = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 0,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "more_destruction";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that threads are destroyed as expected";
-		info->description =
-			"Push two tasks into a threadpool. Set the threadpool size to 4\n"
-			"Ensure that there are 2 active and 2 idle threads. Then shrink the\n"
-			"threadpool down to 1 thread. Ensure that the thread leftover is active\n"
-			"and ensure that both tasks complete.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	tld = test_alloc();
-	if (!tld) {
-		return AST_TEST_FAIL;
-	}
-
-	listener = ast_threadpool_listener_alloc(&test_callbacks, tld);
-	if (!listener) {
-		goto end;
-	}
-
-	pool = ast_threadpool_create(info->name, listener, &options);
-	if (!pool) {
-		goto end;
-	}
-
-	ctd1 = complex_task_data_alloc();
-	ctd2 = complex_task_data_alloc();
-	if (!ctd1 || !ctd2) {
-		goto end;
-	}
-
-	ast_threadpool_push(pool, complex_task, ctd1);
-	ast_threadpool_push(pool, complex_task, ctd2);
-
-	ast_threadpool_set_size(pool, 4);
-
-	res = wait_until_thread_state(test, tld, 2, 2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 2, 2, 2, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	ast_threadpool_set_size(pool, 1);
-
-	/* Shrinking the threadpool should kill off the two idle threads
-	 * and one of the active threads.
-	 */
-	res = wait_until_thread_state(test, tld, 1, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 2, 1, 0, 0);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	/* The tasks are stalled until we poke them */
-	poke_worker(ctd1);
-	poke_worker(ctd2);
-
-	res = wait_for_complex_completion(ctd1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-	res = wait_for_complex_completion(ctd2);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = wait_until_thread_state(test, tld, 0, 1);
-	if (res == AST_TEST_FAIL) {
-		goto end;
-	}
-
-	res = listener_check(test, listener, 1, 0, 2, 0, 1, 1);
-
-end:
-	ast_threadpool_shutdown(pool);
-	ao2_cleanup(listener);
-	ast_free(ctd1);
-	ast_free(ctd2);
-	ast_free(tld);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_serializer)
-{
-	int started = 0;
-	int finished = 0;
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_threadpool *pool = NULL;
-	struct ast_taskprocessor *uut = NULL;
-	struct complex_task_data *data1 = NULL;
-	struct complex_task_data *data2 = NULL;
-	struct complex_task_data *data3 = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 2,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "threadpool_serializer";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that serializers";
-		info->description =
-			"Ensures that tasks enqueued to a serialize execute in sequence.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	pool = ast_threadpool_create("threadpool_serializer", NULL, &options);
-	if (!pool) {
-		ast_test_status_update(test, "Could not create threadpool\n");
-		goto end;
-	}
-	uut = ast_threadpool_serializer("ser1", pool);
-	data1 = complex_task_data_alloc();
-	data2 = complex_task_data_alloc();
-	data3 = complex_task_data_alloc();
-	if (!uut || !data1 || !data2 || !data3) {
-		ast_test_status_update(test, "Allocation failed\n");
-		goto end;
-	}
-
-	/* This should start right away */
-	if (ast_taskprocessor_push(uut, complex_task, data1)) {
-		ast_test_status_update(test, "Failed to enqueue data1\n");
-		goto end;
-	}
-	started = wait_for_complex_start(data1);
-	if (!started) {
-		ast_test_status_update(test, "Failed to start data1\n");
-		goto end;
-	}
-
-	/* This should not start until data 1 is complete */
-	if (ast_taskprocessor_push(uut, complex_task, data2)) {
-		ast_test_status_update(test, "Failed to enqueue data2\n");
-		goto end;
-	}
-	started = has_complex_started(data2);
-	if (started) {
-		ast_test_status_update(test, "data2 started out of order\n");
-		goto end;
-	}
-
-	/* But the free thread in the pool can still run */
-	if (ast_threadpool_push(pool, complex_task, data3)) {
-		ast_test_status_update(test, "Failed to enqueue data3\n");
-	}
-	started = wait_for_complex_start(data3);
-	if (!started) {
-		ast_test_status_update(test, "Failed to start data3\n");
-		goto end;
-	}
-
-	/* Finishing data1 should allow data2 to start */
-	poke_worker(data1);
-	finished = wait_for_complex_completion(data1) == AST_TEST_PASS;
-	if (!finished) {
-		ast_test_status_update(test, "data1 couldn't finish\n");
-		goto end;
-	}
-	started = wait_for_complex_start(data2);
-	if (!started) {
-		ast_test_status_update(test, "Failed to start data2\n");
-		goto end;
-	}
-
-	/* Finish up */
-	poke_worker(data2);
-	finished = wait_for_complex_completion(data2) == AST_TEST_PASS;
-	if (!finished) {
-		ast_test_status_update(test, "data2 couldn't finish\n");
-		goto end;
-	}
-	poke_worker(data3);
-	finished = wait_for_complex_completion(data3) == AST_TEST_PASS;
-	if (!finished) {
-		ast_test_status_update(test, "data3 couldn't finish\n");
-		goto end;
-	}
-
-	res = AST_TEST_PASS;
-
-end:
-	poke_worker(data1);
-	poke_worker(data2);
-	poke_worker(data3);
-	ast_taskprocessor_unreference(uut);
-	ast_threadpool_shutdown(pool);
-	ast_free(data1);
-	ast_free(data2);
-	ast_free(data3);
-	return res;
-}
-
-AST_TEST_DEFINE(threadpool_serializer_dupe)
-{
-	enum ast_test_result_state res = AST_TEST_FAIL;
-	struct ast_threadpool *pool = NULL;
-	struct ast_taskprocessor *uut = NULL;
-	struct ast_taskprocessor *there_can_be_only_one = NULL;
-	struct ast_threadpool_options options = {
-		.version = AST_THREADPOOL_OPTIONS_VERSION,
-		.idle_timeout = 0,
-		.auto_increment = 0,
-		.initial_size = 2,
-		.max_size = 0,
-	};
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "threadpool_serializer_dupe";
-		info->category = "/main/threadpool/";
-		info->summary = "Test that serializers are uniquely named";
-		info->description =
-			"Creating two serializers with the same name should\n"
-			"result in error.\n";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	pool = ast_threadpool_create("threadpool_serializer", NULL, &options);
-	if (!pool) {
-		ast_test_status_update(test, "Could not create threadpool\n");
-		goto end;
-	}
-
-	uut = ast_threadpool_serializer("highlander", pool);
-	if (!uut) {
-		ast_test_status_update(test, "Allocation failed\n");
-		goto end;
-	}
-
-	there_can_be_only_one = ast_threadpool_serializer("highlander", pool);
-	if (there_can_be_only_one) {
-		ast_taskprocessor_unreference(there_can_be_only_one);
-		ast_test_status_update(test, "Duplicate name error\n");
-		goto end;
-	}
-
-	res = AST_TEST_PASS;
-
-end:
-	ast_taskprocessor_unreference(uut);
-	ast_threadpool_shutdown(pool);
-	return res;
-}
-
-static int unload_module(void)
-{
-	ast_test_unregister(threadpool_push);
-	ast_test_unregister(threadpool_initial_threads);
-	ast_test_unregister(threadpool_thread_creation);
-	ast_test_unregister(threadpool_thread_destruction);
-	ast_test_unregister(threadpool_thread_timeout);
-	ast_test_unregister(threadpool_one_task_one_thread);
-	ast_test_unregister(threadpool_one_thread_one_task);
-	ast_test_unregister(threadpool_one_thread_multiple_tasks);
-	ast_test_unregister(threadpool_auto_increment);
-	ast_test_unregister(threadpool_max_size);
-	ast_test_unregister(threadpool_reactivation);
-	ast_test_unregister(threadpool_task_distribution);
-	ast_test_unregister(threadpool_more_destruction);
-	ast_test_unregister(threadpool_serializer);
-	ast_test_unregister(threadpool_serializer_dupe);
-	return 0;
-}
-
-static int load_module(void)
-{
-	ast_test_register(threadpool_push);
-	ast_test_register(threadpool_initial_threads);
-	ast_test_register(threadpool_thread_creation);
-	ast_test_register(threadpool_thread_destruction);
-	ast_test_register(threadpool_thread_timeout);
-	ast_test_register(threadpool_one_task_one_thread);
-	ast_test_register(threadpool_one_thread_one_task);
-	ast_test_register(threadpool_one_thread_multiple_tasks);
-	ast_test_register(threadpool_auto_increment);
-	ast_test_register(threadpool_max_size);
-	ast_test_register(threadpool_reactivation);
-	ast_test_register(threadpool_task_distribution);
-	ast_test_register(threadpool_more_destruction);
-	ast_test_register(threadpool_serializer);
-	ast_test_register(threadpool_serializer_dupe);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "threadpool test module");
diff --git a/tests/test_time.c b/tests/test_time.c
index 9ea72f6..ef6e954 100644
--- a/tests/test_time.c
+++ b/tests/test_time.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
diff --git a/tests/test_uri.c b/tests/test_uri.c
deleted file mode 100644
index 92bbb70..0000000
--- a/tests/test_uri.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief URI Unit Tests
- *
- * \author Kevin Harwell <kharwell at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/uri.h"
-
-#define CATEGORY "/main/uri/"
-
-static const char *scenarios[][7] = {
-	{"http://name:pass@localhost", "http", "name:pass", "localhost", NULL, NULL, NULL},
-	{"http://localhost", "http", NULL, "localhost", NULL, NULL, NULL},
-	{"http://localhost:80", "http", NULL, "localhost", "80", NULL, NULL},
-	{"http://localhost/path/", "http", NULL, "localhost", NULL, "path/", NULL},
-	{"http://localhost/?query", "http", NULL, "localhost", NULL, "", "query"},
-	{"http://localhost:80/path", "http", NULL, "localhost", "80", "path", NULL},
-	{"http://localhost:80/?query", "http", NULL, "localhost", "80", "", "query"},
-	{"http://localhost:80/path?query", "http", NULL, "localhost", "80", "path", "query"},
-};
-
-AST_TEST_DEFINE(uri_parse)
-{
-#define VALIDATE(value, expected_value) \
-	do { ast_test_validate(test, \
-		     (value == expected_value) || \
-		     (value && expected_value && \
-		      !strcmp(value, expected_value)));	\
-	} while (0)
-
-	int i;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "Uri parsing scenarios";
-		info->description = "For each scenario validate result(s)";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-	for (i = 0; i < ARRAY_LEN(scenarios); ++i) {
-		RAII_VAR(struct ast_uri *, uri, NULL, ao2_cleanup);
-		const char **scenario = scenarios[i];
-
-		ast_test_validate(test, (uri = ast_uri_parse(scenario[0])));
-		VALIDATE(ast_uri_scheme(uri), scenario[1]);
-		VALIDATE(ast_uri_user_info(uri), scenario[2]);
-		VALIDATE(ast_uri_host(uri), scenario[3]);
-		VALIDATE(ast_uri_port(uri), scenario[4]);
-		VALIDATE(ast_uri_path(uri), scenario[5]);
-		VALIDATE(ast_uri_query(uri), scenario[6]);
-	}
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(uri_default_http)
-{
-	RAII_VAR(struct ast_uri *, uri, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "parse an http uri with host only";
-		info->description = info->summary;
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, (uri = ast_uri_parse_http("localhost")));
-	ast_test_validate(test, !strcmp(ast_uri_scheme(uri), "http"));
-	ast_test_validate(test, !strcmp(ast_uri_host(uri), "localhost"));
-	ast_test_validate(test, !strcmp(ast_uri_port(uri), "80"));
-	ast_test_validate(test, !ast_uri_is_secure(uri));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(uri_default_http_secure)
-{
-	RAII_VAR(struct ast_uri *, uri, NULL, ao2_cleanup);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "parse an https uri with host only";
-		info->description = info->summary;
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, (uri = ast_uri_parse_http("https://localhost")));
-	ast_test_validate(test, !strcmp(ast_uri_scheme(uri), "https"));
-	ast_test_validate(test, !strcmp(ast_uri_host(uri), "localhost"));
-	ast_test_validate(test, !strcmp(ast_uri_port(uri), "443"));
-	ast_test_validate(test, ast_uri_is_secure(uri));
-
-	return AST_TEST_PASS;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(uri_parse);
-	AST_TEST_REGISTER(uri_default_http);
-	AST_TEST_REGISTER(uri_default_http_secure);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(uri_default_http_secure);
-	AST_TEST_UNREGISTER(uri_default_http);
-	AST_TEST_UNREGISTER(uri_parse);
-	return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "URI test module");
diff --git a/tests/test_utils.c b/tests/test_utils.c
index 395a531..d4c98a3 100644
--- a/tests/test_utils.c
+++ b/tests/test_utils.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422154 $");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
 
 #include "asterisk/utils.h"
 #include "asterisk/test.h"
@@ -42,8 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 422154 $");
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
 
-#include <sys/stat.h>
-
 AST_TEST_DEFINE(uri_encode_decode_test)
 {
 	int res = AST_TEST_PASS;
@@ -202,7 +200,7 @@ AST_TEST_DEFINE(md5_test)
 	ast_test_status_update(test, "Testing MD5 ...\n");
 
 	for (i = 0; i < ARRAY_LEN(tests); i++) {
-		char md5_hash[33];
+		char md5_hash[32];
 		ast_md5_hash(md5_hash, tests[i].input);
 		if (strcasecmp(md5_hash, tests[i].expected_output)) {
 			ast_test_status_update(test,
@@ -423,129 +421,6 @@ AST_TEST_DEFINE(agi_loaded_test)
 	return res;
 }
 
-AST_TEST_DEFINE(safe_mkdir_test)
-{
-	char base_path[] = "/tmp/safe_mkdir.XXXXXX";
-	char path[80] = {};
-	int res;
-	struct stat actual;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = "/main/utils/";
-		info->summary = "Safe mkdir test";
-		info->description =
-			"This test ensures that ast_safe_mkdir does what it is "
-			"supposed to";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	if (mkdtemp(base_path) == NULL) {
-		ast_test_status_update(test, "Failed to create tmpdir for test\n");
-		return AST_TEST_FAIL;
-	}
-
-	snprintf(path, sizeof(path), "%s/should_work", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 == res);
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, S_ISDIR(actual.st_mode));
-
-	snprintf(path, sizeof(path), "%s/should/also/work", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 == res);
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, S_ISDIR(actual.st_mode));
-
-	snprintf(path, sizeof(path), "%s/even/this/../should/work", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 == res);
-	snprintf(path, sizeof(path), "%s/even/should/work", base_path);
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, S_ISDIR(actual.st_mode));
-
-	snprintf(path, sizeof(path),
-		"%s/surprisingly/this/should//////////////////work", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 == res);
-	snprintf(path, sizeof(path),
-		"%s/surprisingly/this/should/work", base_path);
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 == res);
-	ast_test_validate(test, S_ISDIR(actual.st_mode));
-
-	snprintf(path, sizeof(path), "/should_not_work");
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, EPERM == errno);
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, ENOENT == errno);
-
-	snprintf(path, sizeof(path), "%s/../nor_should_this", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, EPERM == errno);
-	strncpy(path, "/tmp/nor_should_this", sizeof(path));
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, ENOENT == errno);
-
-	snprintf(path, sizeof(path),
-		"%s/this/especially/should/not/../../../../../work", base_path);
-	res = ast_safe_mkdir(base_path, path, 0777);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, EPERM == errno);
-	strncpy(path, "/tmp/work", sizeof(path));
-	res = stat(path, &actual);
-	ast_test_validate(test, 0 != res);
-	ast_test_validate(test, ENOENT == errno);
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(crypt_test)
-{
-	RAII_VAR(char *, password_crypted, NULL, ast_free);
-	RAII_VAR(char *, blank_crypted, NULL, ast_free);
-	const char *password = "Passw0rd";
-	const char *not_a_password = "not-a-password";
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "crypt_test";
-		info->category = "/main/utils/";
-		info->summary = "Test ast_crypt wrappers";
-		info->description = "Verifies that the ast_crypt wrappers work as expected.";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	password_crypted = ast_crypt_encrypt(password);
-	ast_test_validate(test, NULL != password_crypted);
-	ast_test_validate(test, 0 != strcmp(password, password_crypted));
-	ast_test_validate(test, ast_crypt_validate(password, password_crypted));
-	ast_test_validate(test,
-		!ast_crypt_validate(not_a_password, password_crypted));
-
-	blank_crypted = ast_crypt_encrypt("");
-	ast_test_validate(test, NULL != blank_crypted);
-	ast_test_validate(test, 0 != strcmp(blank_crypted, ""));
-	ast_test_validate(test, ast_crypt_validate("", blank_crypted));
-	ast_test_validate(test,
-		!ast_crypt_validate(not_a_password, blank_crypted));
-
-	return AST_TEST_PASS;
-}
-
-
 struct quote_set {
 	char *input;
 	char *output;
@@ -650,8 +525,6 @@ static int unload_module(void)
 	AST_TEST_UNREGISTER(crypto_loaded_test);
 	AST_TEST_UNREGISTER(adsi_loaded_test);
 	AST_TEST_UNREGISTER(agi_loaded_test);
-	AST_TEST_UNREGISTER(safe_mkdir_test);
-	AST_TEST_UNREGISTER(crypt_test);
 	AST_TEST_UNREGISTER(quote_mutation);
 	AST_TEST_UNREGISTER(quote_unescaping);
 	return 0;
@@ -667,8 +540,6 @@ static int load_module(void)
 	AST_TEST_REGISTER(crypto_loaded_test);
 	AST_TEST_REGISTER(adsi_loaded_test);
 	AST_TEST_REGISTER(agi_loaded_test);
-	AST_TEST_REGISTER(safe_mkdir_test);
-	AST_TEST_REGISTER(crypt_test);
 	AST_TEST_REGISTER(quote_mutation);
 	AST_TEST_REGISTER(quote_unescaping);
 	return AST_MODULE_LOAD_SUCCESS;
diff --git a/tests/test_uuid.c b/tests/test_uuid.c
deleted file mode 100644
index 70769ef..0000000
--- a/tests/test_uuid.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2012, Digium, Inc.
- *
- * Mark Michelson <mmmichelson at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief Universally unique identifier tests
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-#include "asterisk/test.h"
-#include "asterisk/uuid.h"
-#include "asterisk/module.h"
-
-AST_TEST_DEFINE(uuid)
-{
-	struct ast_uuid *uuid1 = NULL;
-	struct ast_uuid *uuid2 = NULL;
-	struct ast_uuid *uuid3 = NULL;
-	char uuid_str[AST_UUID_STR_LEN];
-	enum ast_test_result_state res = AST_TEST_FAIL;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = "uuid";
-		info->category = "/main/uuid/";
-		info->summary = "UUID unit test";
-		info->description =
-			"This tests basic UUID operations to ensure they work properly";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	/* Use method of generating UUID directly as a string. */
-	ast_uuid_generate_str(uuid_str, sizeof(uuid_str));
-	if (strlen(uuid_str) != (AST_UUID_STR_LEN - 1)) {
-		ast_test_status_update(test, "Failed to directly generate UUID string\n");
-		goto end;
-	}
-	ast_test_status_update(test, "Generate UUID direct to string, got %s\n", uuid_str);
-
-	/* Now convert the direct UUID string to a UUID */
-	uuid1 = ast_str_to_uuid(uuid_str);
-	if (!uuid1) {
-		ast_test_status_update(test, "Unable to convert direct UUID string %s to UUID\n", uuid_str);
-		goto end;
-	}
-	ast_free(uuid1);
-
-	/* Make sure that we can generate a UUID */
-	uuid1 = ast_uuid_generate();
-	if (!uuid1) {
-		ast_test_status_update(test, "Unable to generate a UUID\n");
-		goto end;
-	}
-
-	/* Make sure we're not generating nil UUIDs */
-	if (ast_uuid_is_nil(uuid1)) {
-		ast_test_status_update(test, "We generated a nil UUID. Something is wrong\n");
-		goto end;
-	}
-
-	/* Convert it to a string */
-	ast_uuid_to_str(uuid1, uuid_str, sizeof(uuid_str));
-
-	if (strlen(uuid_str) != (AST_UUID_STR_LEN - 1)) {
-		ast_test_status_update(test, "Failed to convert the UUID to a string\n");
-		goto end;
-	}
-
-	ast_test_status_update(test, "Second generated UUID converted to string, got %s\n", uuid_str);
-
-	/* Now convert the string back to a UUID */
-	uuid2 = ast_str_to_uuid(uuid_str);
-	if (!uuid2) {
-		ast_test_status_update(test, "Unable to convert string %s to UUID\n", uuid_str);
-		goto end;
-	}
-
-	/* Make sure the UUIDs are identical */
-	if (ast_uuid_compare(uuid1, uuid2) != 0) {
-		ast_test_status_update(test, "UUIDs that should be identical are different\n");
-		goto end;
-	}
-
-	/* Try copying a UUID */
-	uuid3 = ast_uuid_copy(uuid1);
-	if (!uuid3) {
-		ast_test_status_update(test, "Unable to copy UUID\n");
-		goto end;
-	}
-
-	/* Make sure copied UUIDs are identical */
-	if (ast_uuid_compare(uuid1, uuid3) != 0) {
-		ast_test_status_update(test, "UUIDs that should be identical are different\n");
-		goto end;
-	}
-
-	if (ast_uuid_compare(uuid2, uuid3) != 0) {
-		ast_test_status_update(test, "UUIDs that should be identical are different\n");
-		goto end;
-	}
-
-	/* Clear a UUID and ensure that it registers as nil */
-	ast_uuid_clear(uuid1);
-
-	if (!ast_uuid_is_nil(uuid1)) {
-		ast_test_status_update(test, "UUID that was cleared does not appear to be nil\n");
-		goto end;
-	}
-
-	res = AST_TEST_PASS;
-
-end:
-	ast_free(uuid1);
-	ast_free(uuid2);
-	ast_free(uuid3);
-	return res;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(uuid);
-	return 0;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(uuid);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "UUID test module");
diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c
index 9c538c2..131b291 100644
--- a/tests/test_voicemail_api.c
+++ b/tests/test_voicemail_api.c
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/stat.h>
 
@@ -43,40 +43,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 #include "asterisk/paths.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
-#include "asterisk/format_cache.h"
 
-/*!
- * \internal
- * \brief Permissions to set on the voicemail directories we create
- *
- * \note taken from app_voicemail
- */
+/*! \internal \brief Permissions to set on the voicemail directories we create
+ * - taken from app_voicemail */
 #define VOICEMAIL_DIR_MODE 0777
 
-/*!
- * \internal
- * \brief Permissions to set on the voicemail files we create
- *
- * \note taken from app_voicemail
- */
+/*! \internal \brief Permissions to set on the voicemail files we create
+ * - taken from app_voicemail */
 #define VOICEMAIL_FILE_MODE 0666
 
-/*!
- * \internal
- * \brief The number of mock snapshot objects we use for tests
- */
+/*! \internal \brief The number of mock snapshot objects we use for tests */
 #define TOTAL_SNAPSHOTS 4
 
-/*!
- * \internal
- * \brief Create and populate the mock message objects and create the
- * envelope files on the file system
- */
+/*! \internal \brief Create and populate the mock message objects and create the
+ * envelope files on the file system */
 #define VM_API_TEST_SETUP do { \
-	if (!ast_vm_is_registered()) { \
-		ast_test_status_update(test, "No voicemail provider registered.\n"); \
-		return AST_TEST_FAIL; \
-	} else if (test_vm_api_test_setup()) { \
+	if (test_vm_api_test_setup()) { \
 		VM_API_TEST_CLEANUP; \
 		ast_test_status_update(test, "Failed to set up necessary mock objects for voicemail API test\n"); \
 		return AST_TEST_FAIL; \
@@ -88,46 +70,31 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		} \
 } } while (0)
 
-/*!
- * \internal
- * \brief Safely cleanup after a test run.
- *
- * \note This should be called both when a test fails and when it passes
- */
+/*! \internal \brief Safely cleanup after a test run.  This should be called both when a
+ * test fails and when it passes */
 #define VM_API_TEST_CLEANUP test_vm_api_test_teardown()
 
-/*!
- * \internal
- * \brief Safely cleanup a snapshot and a test run.
- *
- * \note It assumes that the mailbox snapshot object is test_mbox_snapshot
- */
+/*! \internal \brief Safely cleanup a snapshot and a test run.  Note that it assumes
+ * that the mailbox snapshot object is test_mbox_snapshot */
 #define VM_API_SNAPSHOT_TEST_CLEANUP \
 		if (test_mbox_snapshot) { \
 			test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
 		} \
 		VM_API_TEST_CLEANUP; \
 
-/*!
- * \internal
- * \brief Verify the expected result from two string values obtained
- * from a mailbox snapshot.
- *
- * \note It assumes the mailbox snapshot object is test_mbox_snapshot
+/*! \internal \brief Verify the expected result from two string values obtained
+ * from a mailbox snapshot.  Note that it assumes the mailbox snapshot
+ * object is test_mbox_snapshot
  */
 #define VM_API_STRING_FIELD_VERIFY(expected, actual) do { \
-	if (strcmp((expected), (actual))) { \
+	if (strncmp((expected), (actual), strlen((expected)))) { \
 		ast_test_status_update(test, "Test failed for parameter %s: Expected [%s], Actual [%s]\n", #actual, expected, actual); \
 		VM_API_SNAPSHOT_TEST_CLEANUP; \
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Verify the expected result from two integer values.
- *
- * \note It assumes the mailbox snapshot object is test_mbox_snapshot
- */
+/*! \internal \brief Verify the expected result from two integer values.  Note
+ * that it assumes the mailbox snapshot object is test_mbox_snapshot */
 #define VM_API_INT_VERIFY(expected, actual) do { \
 	if ((expected) != (actual)) { \
 		ast_test_status_update(test, "Test failed for parameter %s: Expected [%d], Actual [%d]\n", #actual, (int)expected, (int)actual); \
@@ -135,12 +102,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Verify that a mailbox snapshot contains the expected message
- * snapshot, in the correct position, with the expected values.
- *
- * \note It assumes the mailbox snapshot object is test_mbox_snapshot
+/*! \internal \brief Verify that a mailbox snapshot contains the expected message
+ * snapshot, in the correct position, with the expected values.  Note
+ * that it assumes the mailbox snapshot object is test_mbox_snapshot
  */
 #define VM_API_SNAPSHOT_MSG_VERIFY(expected, actual, expected_folder, expected_index) do { \
 	struct ast_vm_msg_snapshot *msg; \
@@ -176,11 +140,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 } } while (0)
 
 
-/*!
- * \internal
- * \brief Create a message snapshot, failing the test if the snapshot could not be created.
- *
- * \note This requires having a snapshot named test_mbox_snapshot.
+/*! \internal \brief Create a message snapshot, failing the test if the snapshot could not be created.
+ * This requires having a snapshot named test_mbox_snapshot.
  */
 #define VM_API_SNAPSHOT_CREATE(mailbox, context, folder, desc, sort, old_and_inbox) do { \
 	if (!(test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
@@ -190,12 +151,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Create a message snapshot, failing the test if the snapshot could be created.
- *
- * \note This is used to test off nominal conditions.
- * \note This requires having a snapshot named test_mbox_snapshot.
+/*! \internal \brief Create a message snapshot, failing the test if the snapshot could be created.
+ * This is used to test off nominal conditions.
+ * This requires having a snapshot named test_mbox_snapshot.
  */
 #define VM_API_SNAPSHOT_OFF_NOMINAL_TEST(mailbox, context, folder, desc, sort, old_and_inbox) do { \
 	if ((test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
@@ -206,10 +164,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Move a voicemail message, failing the test if the message could not be moved
- */
+/*! \internal \brief Move a voicemail message, failing the test if the message could not be moved */
 #define VM_API_MOVE_MESSAGE(mailbox, context, number_of_messages, source, message_numbers_in, dest) do { \
 	if (ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest))) { \
 		ast_test_status_update(test, "Failed to move message %s@%s from %s to %s\n", \
@@ -218,10 +173,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Attempt to move a voicemail message, failing the test if the message could be moved
- */
+ /*! \internal \brief Attempt to move a voicemail message, failing the test if the message could be moved */
 #define VM_API_MOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, source, message_numbers_in, dest) do { \
 	if (!ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest))) { \
 		ast_test_status_update(test, "Succeeded to move message %s@%s from %s to %s when we really shouldn't\n", \
@@ -230,10 +182,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Remove a message, failing the test if the method failed or if the message is still present.
- */
+/*! \internal \brief Remove a message, failing the test if the method failed or if the message is still present. */
 #define VM_API_REMOVE_MESSAGE(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
 	if (ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
 		ast_test_status_update(test, "Failed to remove message from mailbox %s@%s, folder %s", \
@@ -246,10 +195,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 	test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
 } while (0)
 
-/*!
- * \internal
- * \brief Remove a message, failing the test if the method succeeds
- */
+/*! \internal \brief Remove a message, failing the test if the method succeeds */
 #define VM_API_REMOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
 	if (!ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
 		ast_test_status_update(test, "Succeeded in removing message from mailbox %s@%s, folder %s, when expected result was failure\n", \
@@ -258,10 +204,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Forward a message, failing the test if the message could not be forwarded
- */
+/*! \internal \brief Forward a message, failing the test if the message could not be forwarded */
 # define VM_API_FORWARD_MESSAGE(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
 	if (ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
 		ast_test_status_update(test, "Failed to forward message from %s@%s [%s] to %s@%s [%s]\n", \
@@ -271,10 +214,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 			return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Forward a message, failing the test if the message was successfully forwarded
- */
+	/*! \internal \brief Forward a message, failing the test if the message was successfully forwarded */
 #define VM_API_FORWARD_MESSAGE_OFF_NOMINAL(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
 	if (!ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
 		ast_test_status_update(test, "Succeeded in forwarding message from %s@%s [%s] to %s@%s [%s] when expected result was fail\n", \
@@ -284,43 +224,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419175 $")
 			return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal                                                                                                              .
- * \brief Playback a message on a channel or callback function                                                            .
- *                                                                                                                        .
- * \note The channel name must be test_channel.
- * \note Fail the test if the message could not be played.
- */
+/*! \internal \brief Playback a message on a channel or callback function.  Note that the channel name must be test_channel.
+ * Fail the test if the message could not be played. */
 #define VM_API_PLAYBACK_MESSAGE(channel, mailbox, context, folder, message, callback_fn) do { \
 	if (ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
 		ast_test_status_update(test, "Failed nominal playback message test\n"); \
-		ast_hangup(test_channel); \
+		if (test_channel) { \
+			ast_hangup(test_channel); \
+		} \
 		VM_API_TEST_CLEANUP; \
 		return AST_TEST_FAIL; \
 	} } while (0)
 
-/*!
- * \internal
- * \brief Playback a message on a channel or callback function.
- *
- * \note The channel name must be test_channel.
- * \note Fail the test if the message is successfully played
- */
+/*! \internal \brief Playback a message on a channel or callback function.  Note that the channel name must be test_channel.
+ * Fail the test if the message is successfully played */
 #define VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(channel, mailbox, context, folder, message, callback_fn) do { \
 	if (!ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
 		ast_test_status_update(test, "Succeeded in playing back of message when expected result was to fail\n"); \
-		ast_hangup(test_channel); \
+		if (test_channel) { \
+			ast_hangup(test_channel); \
+		} \
 		VM_API_TEST_CLEANUP; \
 		return AST_TEST_FAIL; \
 	} } while (0)
 
 
-/*!
- * \internal
- * \brief Possible names of folders.
- *
- * \note Taken from app_voicemail
- */
+/*! \internal \brief Possible names of folders.  Taken from app_voicemail */
 static const char * const mailbox_folders[] = {
 	"INBOX",
 	"Old",
@@ -336,22 +265,13 @@ static const char * const mailbox_folders[] = {
 	"Urgent",
 };
 
-/*!
- * \internal
- * \brief Message snapshots representing the messages that are used by the various tests
- */
+/*! \internal \brief Message snapshots representing the messages that are used by the various tests */
 static struct ast_vm_msg_snapshot *test_snapshots[TOTAL_SNAPSHOTS];
 
-/*!
- * \internal
- * \brief Tracks whether or not we entered into the message playback callback function
- */
+/*! \internal \brief Tracks whether or not we entered into the message playback callback function */
 static int global_entered_playback_callback = 0;
 
-/*!
- * \internal
- * \brief Get a folder index by its name
- */
+/*! \internal \brief Get a folder index by its name */
 static int get_folder_by_name(const char *folder)
 {
 	size_t i;
@@ -365,14 +285,10 @@ static int get_folder_by_name(const char *folder)
 	return -1;
 }
 
-/*!
- * \internal
- * \brief Get a mock snapshot object
- *
+/*! \internal \brief Get a mock snapshot object
  * \param context The mailbox context
  * \param exten The mailbox extension
  * \param callerid The caller ID of the person leaving the message
- *
  * \returns an ast_vm_msg_snapshot object on success
  * \returns NULL on error
  */
@@ -409,12 +325,8 @@ static void test_vm_api_destroy_mock_snapshot(struct ast_vm_msg_snapshot *snapsh
 	}
 }
 
-/*!
- * \internal
- * \brief Make a voicemail mailbox folder based on the values provided in a message snapshot
- *
+/*! \internal \brief Make a voicemail mailbox folder based on the values provided in a message snapshot
  * \param snapshot The snapshot containing the information to create the folder from
- *
  * \returns 0 on success
  * \returns 1 on failure
  */
@@ -430,17 +342,12 @@ static int test_vm_api_create_voicemail_folder(const char *folder_path)
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Create the voicemail files specified by a snapshot
- *
+/*! \internal \brief Create the voicemail files specified by a snapshot
  * \param context The context of the mailbox
  * \param mailbox The actual mailbox
  * \param snapshot The message snapshot object containing the relevant envelope data
- *
  * \note This will symbolic link the sound file 'beep.gsm' to act as the 'sound' portion of the voicemail.
  * Certain actions in app_voicemail will fail if an actual sound file does not exist
- *
  * \returns 0 on success
  * \returns 1 on any failure
  */
@@ -530,10 +437,7 @@ static int test_vm_api_create_voicemail_files(const char *context, const char *m
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Destroy the voicemail on the file system associated with a snapshot
- *
+/*! \internal \brief Destroy the voicemail on the file system associated with a snapshot
  * \param snapshot The snapshot describing the voicemail
  */
 static void test_vm_api_remove_voicemail(struct ast_vm_msg_snapshot *snapshot)
@@ -559,14 +463,10 @@ static void test_vm_api_remove_voicemail(struct ast_vm_msg_snapshot *snapshot)
 	return;
 }
 
-/*!
- * \internal
- * \brief Destroy the voicemails associated with a mailbox snapshot
- *
+/*! \internal \brief Destroy the voicemails associated with a mailbox snapshot
  * \param mailbox The actual mailbox name
  * \param mailbox_snapshot The mailbox snapshot containing the voicemails to destroy
- *
- * \note It is necessary to specify not just the snapshot, but the mailbox itself.  The
+ * \note Its necessary to specify not just the snapshot, but the mailbox itself.  The
  * message snapshots contained in the snapshot may have originated from a different mailbox
  * then the one we're destroying, which means that we can't determine the files to delete
  * without knowing the actual mailbox they exist in.
@@ -584,10 +484,7 @@ static void test_vm_api_destroy_mailbox_voicemails(const char *mailbox, struct a
 	}
 }
 
-/*!
- * \internal
- * \brief Use snapshots to remove all messages in the mailboxes
- */
+/*! \internal \brief Use snapshots to remove all messages in the mailboxes */
 static void test_vm_api_remove_all_messages(void)
 {
 	struct ast_vm_mailbox_snapshot *mailbox_snapshot;
@@ -609,11 +506,8 @@ static void test_vm_api_remove_all_messages(void)
 	}
 }
 
-/*!
- * \internal
- * \brief Set up the necessary voicemails for a unit test run
- *
- * \details
+/*! \internal \brief Set up the necessary voicemails for a unit test run
+ * \note
  * This creates 4 voicemails, stores them on the file system, and creates snapshot objects
  * representing them for expected/actual value comparisons in the array test_snapshots.
  *
@@ -733,10 +627,7 @@ static void test_vm_api_test_teardown(void)
 	ast_vm_test_destroy_user("default", "test_vm_api_2345");
 }
 
-/*!
- * \internal
- * \brief Update the test snapshots with a new mailbox snapshot
- *
+/*! \internal \brief Update the test snapshots with a new mailbox snapshot
  * \param mailbox_snapshot The new mailbox shapshot to update the test snapshots with
  */
 static void test_vm_api_update_test_snapshots(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
@@ -763,14 +654,10 @@ static void test_vm_api_update_test_snapshots(struct ast_vm_mailbox_snapshot *ma
 	}
 }
 
-/*!
- * \internal
- * \brief A callback function for message playback
- *
+/*! \internal \brief A callback function for message playback
  * \param chan The channel the file would be played back on
  * \param file The file to play back
  * \param duration The duration of the file
- *
  * \note This sets global_entered_playback_callback to 1 if the parameters
  * passed to the callback are minimally valid
  */
@@ -783,37 +670,25 @@ static void message_playback_callback_fn(struct ast_channel *chan, const char *f
 	}
 }
 
-/*!
- * \internal
- * \brief Dummy channel write function for mock_channel_tech
- */
+/*! \internal \brief Dummy channel write function for mock_channel_tech */
 static int test_vm_api_mock_channel_write(struct ast_channel *chan, struct ast_frame *frame)
 {
 	return 0;
 }
 
-/*!
- * \internal
- * \brief Dummy channel read function for mock_channel_tech
- */
+/*! \internal \brief Dummy channel read function for mock_channel_tech */
 static struct ast_frame *test_vm_api_mock_channel_read(struct ast_channel *chan)
 {
 	return &ast_null_frame;
 }
 
-/*!
- * \internal
- * \brief A dummy channel technology
- */
+/*! \internal \brief A dummy channel technology */
 static const struct ast_channel_tech mock_channel_tech = {
 		.write = test_vm_api_mock_channel_write,
 		.read = test_vm_api_mock_channel_read,
 };
 
-/*!
- * \internal
- * \brief Create a dummy channel suitable for 'playing back' gsm sound files on
- *
+/*! \internal \brief Create a dummy channel suitable for 'playing back' gsm sound files on
  * \returns a channel on success
  * \returns NULL on failure
  */
@@ -822,20 +697,18 @@ static struct ast_channel *test_vm_api_create_mock_channel(void)
 	struct ast_channel *mock_channel;
 	struct ast_format_cap *native_formats;
 
-	if (!(mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"))) {
+	if (!(mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, 0, 0, "TestChannel"))) {
 		return NULL;
 	}
 
-	ast_channel_set_writeformat(mock_channel, ast_format_gsm);
+	ast_format_set(ast_channel_writeformat(mock_channel), AST_FORMAT_GSM, 0);
 	native_formats = ast_channel_nativeformats(mock_channel);
-	ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0);
-	ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm);
-	ast_channel_set_readformat(mock_channel, ast_format_gsm);
-	ast_channel_set_rawreadformat(mock_channel, ast_format_gsm);
+	ast_format_cap_add(native_formats, ast_channel_writeformat(mock_channel));
+	ast_format_set(ast_channel_rawwriteformat(mock_channel), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_readformat(mock_channel), AST_FORMAT_GSM, 0);
+	ast_format_set(ast_channel_rawreadformat(mock_channel), AST_FORMAT_GSM, 0);
 	ast_channel_tech_set(mock_channel, &mock_channel_tech);
 
-	ast_channel_unlock(mock_channel);
-
 	return mock_channel;
 }
 
@@ -1465,7 +1338,9 @@ AST_TEST_DEFINE(voicemail_api_nominal_msg_playback)
 	VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
 	test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
 
-	ast_hangup(test_channel);
+	if (test_channel) {
+		ast_hangup(test_channel);
+	}
 	VM_API_TEST_CLEANUP;
 
 	return AST_TEST_PASS;
@@ -1523,7 +1398,9 @@ AST_TEST_DEFINE(voicemail_api_off_nominal_msg_playback)
 
 	ast_test_status_update(test, "Playing back message with NULL message specifier\n");
 	VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "INBOX", NULL, NULL);
-	ast_hangup(test_channel);
+	if (test_channel) {
+		ast_hangup(test_channel);
+	}
 	VM_API_TEST_CLEANUP;
 
 	return AST_TEST_PASS;
diff --git a/tests/test_websocket_client.c b/tests/test_websocket_client.c
deleted file mode 100644
index dcf1a17..0000000
--- a/tests/test_websocket_client.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2014, Digium, Inc.
- *
- * Kevin Harwell <kharwell at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Websocket Client Unit Tests
- *
- * \author Kevin Harwell <kharwell at digium.com>
- *
- */
-
-/*** MODULEINFO
-	<depend>TEST_FRAMEWORK</depend>
-	<depend>res_http_websocket</depend>
-	<support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "")
-
-#include "asterisk/test.h"
-#include "asterisk/module.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/http_websocket.h"
-
-#define CATEGORY "/res/websocket/"
-#define REMOTE_URL "ws://127.0.0.1:8088/ws"
-
-AST_TEST_DEFINE(websocket_client_create_and_connect)
-{
-	RAII_VAR(struct ast_websocket *, client, NULL, ao2_cleanup);
-
-	enum ast_websocket_result result;
-	const char write_buf[] = "this is only a test";
-	RAII_VAR(char *, read_buf, NULL, ast_free);
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "test creation and connection of a client websocket";
-		info->description = "test creation and connection of a client websocket";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, (client = ast_websocket_client_create(
-					 REMOTE_URL, "echo", NULL, &result)));
-
-	ast_test_validate(test, !ast_websocket_write_string(client, write_buf));
-	ast_test_validate(test, ast_websocket_read_string(client, &read_buf) > 0);
-	ast_test_validate(test, !strcmp(write_buf, read_buf));
-
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(websocket_client_bad_url)
-{
-	RAII_VAR(struct ast_websocket *, client, NULL, ao2_cleanup);
-	enum ast_websocket_result result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "websocket client - test bad url";
-		info->description = "pass a bad url and make sure it fails";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, !(client = ast_websocket_client_create(
-					  "invalid", NULL, NULL, &result)));
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(websocket_client_unsupported_protocol)
-{
-	RAII_VAR(struct ast_websocket *, client, NULL, ao2_cleanup);
-	enum ast_websocket_result result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "websocket client - unsupported protocol";
-		info->description = "fails on an unsupported protocol";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, !(client = ast_websocket_client_create(
-					  REMOTE_URL, "unsupported", NULL, &result)));
-	return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(websocket_client_multiple_protocols)
-{
-	RAII_VAR(struct ast_websocket *, client, NULL, ao2_cleanup);
-	const char *accept_protocol;
-	enum ast_websocket_result result;
-
-	switch (cmd) {
-	case TEST_INIT:
-		info->name = __func__;
-		info->category = CATEGORY;
-		info->summary = "websocket client - test multiple protocols";
-		info->description = "test multi-protocol client";
-		return AST_TEST_NOT_RUN;
-	case TEST_EXECUTE:
-		break;
-	}
-
-	ast_test_validate(test, (client = ast_websocket_client_create(
-					 REMOTE_URL, "echo,unsupported", NULL, &result)));
-
-	accept_protocol = ast_websocket_client_accept_protocol(client);
-	ast_test_validate(test, accept_protocol && !strcmp(accept_protocol, "echo"));
-
-	return AST_TEST_PASS;
-}
-
-static int load_module(void)
-{
-	AST_TEST_REGISTER(websocket_client_create_and_connect);
-	AST_TEST_REGISTER(websocket_client_bad_url);
-	AST_TEST_REGISTER(websocket_client_unsupported_protocol);
-	AST_TEST_REGISTER(websocket_client_multiple_protocols);
-	return AST_MODULE_LOAD_SUCCESS;
-}
-
-static int unload_module(void)
-{
-	AST_TEST_UNREGISTER(websocket_client_multiple_protocols);
-	AST_TEST_UNREGISTER(websocket_client_unsupported_protocol);
-	AST_TEST_UNREGISTER(websocket_client_bad_url);
-	AST_TEST_UNREGISTER(websocket_client_create_and_connect);
-	return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Websocket client test module");
diff --git a/tests/test_xml_escape.c b/tests/test_xml_escape.c
index c9f83a6..e4c36de 100644
--- a/tests/test_xml_escape.c
+++ b/tests/test_xml_escape.c
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 389251 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
diff --git a/utils/.gitignore b/utils/.gitignore
new file mode 100644
index 0000000..957572d
--- /dev/null
+++ b/utils/.gitignore
@@ -0,0 +1,30 @@
+aelbison.c
+aelparse
+aelparse.c
+ast_expr2.c
+ast_expr2f.c
+astcanary
+astdb2bdb
+astdb2sqlite3
+astman
+check_expr
+check_expr2
+conf2ael
+db1-ast/libdb1.a
+hashtab.c
+lock.c
+md5.c
+muted
+pbx_ael.c
+poll.c
+pval.c
+refcounter
+sha1.c
+smsq
+stereorize
+strcompat.c
+streamplayer
+strings.c
+threadstorage.c
+utils.c
+version.c
diff --git a/utils/Makefile b/utils/Makefile
index 8fb1a29..2c841fd 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,5 +1,5 @@
 #
-# Asterisk -- An open source telephony toolkit.
+# Asterisk -- A telephony toolkit for Linux.
 # 
 # Various utilities
 #
@@ -88,8 +88,7 @@ clean:
 	rm -f *.s *.i
 	rm -f md5.c strcompat.c ast_expr2.c ast_expr2.h ast_expr2f.c pbx_ael.c pval.c hashtab.c lock.c
 	rm -f aelparse.c aelbison.c conf2ael
-	rm -f threadstorage.c
-	rm -f utils.c strings.c poll.c version.c sha1.c astobj2.c refcounter
+	rm -f utils.c strings.c threadstorage.c sha1.c astobj2.c refcounter
 	rm -f db1-ast/.*.d
 	@$(MAKE) -C db1-ast clean
 
@@ -139,30 +138,54 @@ aelbison.c: $(ASTTOPDIR)/res/ael/ael.tab.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
 	$(CMD_PREFIX) cp "$<" "$@"
 aelbison.o: _ASTCFLAGS+=-I$(ASTTOPDIR)/res/ael -DYYENABLE_NLS=0
+	ifneq ($(AST_CLANG_BLOCKS),)
+		_ASTCFLAGS+=-Wno-parentheses-equality
+	endif
 
 pbx_ael.c: $(ASTTOPDIR)/pbx/pbx_ael.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
 	$(CMD_PREFIX) cp "$<" "$@"
-	$(ECHO_PREFIX) echo "   [SED] $@"
-	$(CMD_PREFIX) sed 's/ast_debug([[:digit:]][[:digit:]]*/ast_log(LOG_DEBUG/' "$@" > "$@.new"
-	$(CMD_PREFIX) mv "$@.new" "$@"
 
 aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
 	$(CMD_PREFIX) cp "$<" "$@"
-	$(ECHO_PREFIX) echo "   [SED] $@"
-	$(CMD_PREFIX) sed 's/ast_debug([[:digit:]][[:digit:]]*/ast_log(LOG_DEBUG/' "$@" > "$@.new"
-	$(CMD_PREFIX) mv "$@.new" "$@"
 
 aelparse.o: _ASTCFLAGS+=-I$(ASTTOPDIR)/res -Wno-unused
 aelparse: LIBS+=-lm
 aelparse: aelparse.o aelbison.o pbx_ael.o hashtab.o lock.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
 
+version.c: $(ASTTOPDIR)/main/version.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
+astobj2.c: $(ASTTOPDIR)/main/astobj2.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
+utils.c: $(ASTTOPDIR)/main/utils.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
+poll.c: $(ASTTOPDIR)/main/poll.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
+strings.c: $(ASTTOPDIR)/main/strings.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
+sha1.c: $(ASTTOPDIR)/main/sha1.c
+	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+	$(CMD_PREFIX) cp "$<" "$@"
+
 threadstorage.c: $(ASTTOPDIR)/main/threadstorage.c
 	$(ECHO_PREFIX) echo "   [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
 	$(CMD_PREFIX) cp "$<" "$@"
 
 
+refcounter: refcounter.o md5.o hashtab.o lock.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o poll.o version.o
+refcounter.o: _ASTCFLAGS+=-O0
+
 extconf.o: extconf.c
 
 conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o hashtab.o lock.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o
diff --git a/utils/ael_main.c b/utils/ael_main.c
index 4438a43..64f4d8e 100644
--- a/utils/ael_main.c
+++ b/utils/ael_main.c
@@ -18,9 +18,8 @@
 #include <regex.h>
 #include <limits.h>
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418019 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-#include "asterisk/backtrace.h"
 #include "asterisk/channel.h"
 #include "asterisk/ast_expr.h"
 #include "asterisk/module.h"
@@ -37,6 +36,8 @@ void ast_register_file_version(const char *file, const char *version) { }
 void ast_unregister_file_version(const char *file) { }
 #endif
 
+struct ast_flags ast_compat = { 7 };
+
 /*** MODULEINFO
   	<depend>res_ael_share</depend>
  ***/
@@ -620,12 +621,12 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename,
 {
 }
 
-int __ast_bt_get_addresses(struct ast_bt *bt)
+int ast_bt_get_addresses(struct ast_bt *bt)
 {
 	return 0;
 }
 
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+char **ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
 	char **foo = calloc(num_frames, sizeof(char *) + 1);
 	if (foo) {
diff --git a/utils/astdb2sqlite3.c b/utils/astdb2sqlite3.c
index 02103bc..ba35f93 100644
--- a/utils/astdb2sqlite3.c
+++ b/utils/astdb2sqlite3.c
@@ -29,7 +29,7 @@
 
 #include "asterisk.h"
 
-//ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
+//ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/utils/astman.c b/utils/astman.c
index f03e05e..315b3b0 100644
--- a/utils/astman.c
+++ b/utils/astman.c
@@ -27,7 +27,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 409091 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk.h"
 
 #include <newt.h>
@@ -723,7 +723,7 @@ static int manager_login(char *hostname)
 				MD5Update(&md5, (unsigned char *)pass, strlen(pass));
 				MD5Final(digest, &md5);
 				for (x=0; x<16; x++)
-					len += sprintf(md5key + len, "%2.2x", digest[x]);
+					len += sprintf(md5key + len, "%02hhx", digest[x]);
 				manager_action("Login",
 						"AuthType: MD5\r\n"
 						"Username: %s\r\n"
diff --git a/utils/check_expr.c b/utils/check_expr.c
index f5e2894..3c1afde 100644
--- a/utils/check_expr.c
+++ b/utils/check_expr.c
@@ -21,7 +21,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398755 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/ast_expr.h"
 
@@ -72,14 +72,14 @@ void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
     /* not a lot to do in a standalone w/o threading! */
 }
 
-int __ast_bt_get_addresses(struct ast_bt *bt);
-int __ast_bt_get_addresses(struct ast_bt *bt)
+int ast_bt_get_addresses(struct ast_bt *bt);
+int ast_bt_get_addresses(struct ast_bt *bt)
 {
 	/* Suck it, you stupid utils directory! */
 	return 0;
 }
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames);
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+char **ast_bt_get_symbols(void **addresses, size_t num_frames);
+char **ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
 	char **foo = calloc(num_frames, sizeof(char *) + 1);
 	if (foo) {
diff --git a/utils/clicompat.c b/utils/clicompat.c
index 0a09d76..d25a710 100644
--- a/utils/clicompat.c
+++ b/utils/clicompat.c
@@ -1,6 +1,6 @@
 /*
  * Stubs for some cli functions used by the test routines.
- * $Revision: 401937 $
+ * $Revision$
  */
 void ast_cli(int fd, const char *fmt, ...);
 void ast_cli(int fd, const char *fmt, ...)
@@ -14,6 +14,13 @@ int ast_register_atexit(void (*func)(void))
 {
 	return 0;
 }
+
+int ast_register_cleanup(void (*func)(void));
+int ast_register_cleanup(void (*func)(void))
+{
+	return 0;
+}
+
 int ast_cli_register_multiple(struct ast_cli_entry *e, int len);
 int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
 {
diff --git a/utils/conf2ael.c b/utils/conf2ael.c
index d789fa1..2c44380 100644
--- a/utils/conf2ael.c
+++ b/utils/conf2ael.c
@@ -28,7 +28,7 @@
  ***/
 
 #include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418019 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/paths.h"	/* CONFIG_DIR */
 #include <locale.h>
@@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: 418019 $")
 #include "asterisk/pval.h"
 #include "asterisk/extconf.h"
 
+struct ast_flags ast_compat = { 7 };
 const char *ast_config_AST_CONFIG_DIR = "/etc/asterisk";	/* placeholder */
 
 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
@@ -237,19 +238,6 @@ struct store_hint {
 
 AST_LIST_HEAD(store_hints, store_hint);
 
-static const struct cfextension_states {
-	int extension_state;
-	const char * const text;
-} extension_states[] = {
-	{ AST_EXTENSION_NOT_INUSE,                     "Idle" },
-	{ AST_EXTENSION_INUSE,                         "InUse" },
-	{ AST_EXTENSION_BUSY,                          "Busy" },
-	{ AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
-	{ AST_EXTENSION_RINGING,                       "Ringing" },
-	{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
-	{ AST_EXTENSION_ONHOLD,                        "Hold" },
-	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
-};
 #define STATUS_NO_CONTEXT	1
 #define STATUS_NO_EXTENSION	2
 #define STATUS_NO_PRIORITY	3
@@ -747,12 +735,12 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename,
 {
 }
 
-int __ast_bt_get_addresses(struct ast_bt *bt)
+int ast_bt_get_addresses(struct ast_bt *bt)
 {
 	return 0;
 }
 
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+char **ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
 	char **foo = calloc(num_frames, sizeof(char *) + 1);
 	if (foo) {
diff --git a/utils/extconf.c b/utils/extconf.c
index 051ce79..bd2cc9a 100644
--- a/utils/extconf.c
+++ b/utils/extconf.c
@@ -17,28 +17,13 @@
  */
 
 
-/*!
- * \file extconf
+/*
+ *
  * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
  * for operations outside of asterisk. A huge, awful hack.
  *
  */
 
-/*!
- * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page extconfig.conf extconfig.conf
- * \verbinclude extconfig.conf.sample
- */
-
-/*!
- * \page extensions.conf extensions.conf
- * \verbinclude extensions.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
@@ -111,7 +96,7 @@ struct ast_channel
 #define VERBOSE_PREFIX_3 "    -- "
 #define VERBOSE_PREFIX_4 "       > "
 
-void ast_log_backtrace(void);
+void ast_backtrace(void);
 
 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
 	__attribute__((format(printf, 5, 6)));
@@ -471,151 +456,6 @@ static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, c
 	return res;
 }
 
-static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
-				  const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
-	return pthread_cond_init(cond, cond_attr);
-}
-
-static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
-				    const char *cond_name, ast_cond_t *cond)
-{
-	return pthread_cond_signal(cond);
-}
-
-static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
-				       const char *cond_name, ast_cond_t *cond)
-{
-	return pthread_cond_broadcast(cond);
-}
-
-static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
-				     const char *cond_name, ast_cond_t *cond)
-{
-	return pthread_cond_destroy(cond);
-}
-
-static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
-				  const char *cond_name, const char *mutex_name,
-				  ast_cond_t *cond, ast_mutex_t *t)
-{
-	int res;
-	int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-				   filename, lineno, func, mutex_name);
-	}
-#endif
-
-	if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-		__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-				   filename, lineno, func, mutex_name);
-		__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-		DO_THREAD_CRASH;
-	}
-
-	if (--t->reentrancy < 0) {
-		__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-				   filename, lineno, func, mutex_name);
-		t->reentrancy = 0;
-	}
-
-	if (t->reentrancy < AST_MAX_REENTRANCY) {
-		t->file[t->reentrancy] = NULL;
-		t->lineno[t->reentrancy] = 0;
-		t->func[t->reentrancy] = NULL;
-		t->thread[t->reentrancy] = 0;
-	}
-
-	if ((res = pthread_cond_wait(cond, &t->mutex))) {
-		__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-				   filename, lineno, func, strerror(res));
-		DO_THREAD_CRASH;
-	} else {
-		if (t->reentrancy < AST_MAX_REENTRANCY) {
-			t->file[t->reentrancy] = filename;
-			t->lineno[t->reentrancy] = lineno;
-			t->func[t->reentrancy] = func;
-			t->thread[t->reentrancy] = pthread_self();
-			t->reentrancy++;
-		} else {
-			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-							   filename, lineno, func, mutex_name);
-		}
-	}
-
-	return res;
-}
-
-static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
-				       const char *cond_name, const char *mutex_name, ast_cond_t *cond,
-				       ast_mutex_t *t, const struct timespec *abstime)
-{
-	int res;
-	int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-				   filename, lineno, func, mutex_name);
-	}
-#endif
-
-	if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-		__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-				   filename, lineno, func, mutex_name);
-		__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-		DO_THREAD_CRASH;
-	}
-
-	if (--t->reentrancy < 0) {
-		__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-				   filename, lineno, func, mutex_name);
-		t->reentrancy = 0;
-	}
-
-	if (t->reentrancy < AST_MAX_REENTRANCY) {
-		t->file[t->reentrancy] = NULL;
-		t->lineno[t->reentrancy] = 0;
-		t->func[t->reentrancy] = NULL;
-		t->thread[t->reentrancy] = 0;
-	}
-
-	if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
-		__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-				   filename, lineno, func, strerror(res));
-		DO_THREAD_CRASH;
-	} else {
-		if (t->reentrancy < AST_MAX_REENTRANCY) {
-			t->file[t->reentrancy] = filename;
-			t->lineno[t->reentrancy] = lineno;
-			t->func[t->reentrancy] = func;
-			t->thread[t->reentrancy] = pthread_self();
-			t->reentrancy++;
-		} else {
-			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-							   filename, lineno, func, mutex_name);
-		}
-	}
-
-	return res;
-}
-
-#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
-#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
-#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
-
 #else /* !DEBUG_THREADS */
 
 
@@ -635,58 +475,8 @@ static inline int ast_mutex_init(ast_mutex_t *pmutex)
 
 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
 
-static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
-{
-	return pthread_mutex_unlock(pmutex);
-}
-
-static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
-{
-	return pthread_mutex_destroy(pmutex);
-}
-
-static inline int ast_mutex_lock(ast_mutex_t *pmutex)
-{
-	__MTX_PROF(pmutex);
-}
-
-static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
-{
-	return pthread_mutex_trylock(pmutex);
-}
-
 typedef pthread_cond_t ast_cond_t;
 
-static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
-	return pthread_cond_init(cond, cond_attr);
-}
-
-static inline int ast_cond_signal(ast_cond_t *cond)
-{
-	return pthread_cond_signal(cond);
-}
-
-static inline int ast_cond_broadcast(ast_cond_t *cond)
-{
-	return pthread_cond_broadcast(cond);
-}
-
-static inline int ast_cond_destroy(ast_cond_t *cond)
-{
-	return pthread_cond_destroy(cond);
-}
-
-static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
-{
-	return pthread_cond_wait(cond, t);
-}
-
-static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
-{
-	return pthread_cond_timedwait(cond, t, abstime);
-}
-
 #endif /* !DEBUG_THREADS */
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
@@ -697,10 +487,6 @@ static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const str
 static void  __attribute__((constructor)) init_##mutex(void) \
 { \
 	ast_mutex_init(&mutex); \
-} \
-static void  __attribute__((destructor)) fini_##mutex(void) \
-{ \
-	ast_mutex_destroy(&mutex); \
 }
 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
 /* By default, use static initialization of mutexes. */ 
@@ -709,18 +495,8 @@ static void  __attribute__((destructor)) fini_##mutex(void) \
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
-#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
-#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
-#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
-#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
-#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
-#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
-#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
-#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
-#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
-#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
 
 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
 
@@ -762,21 +538,11 @@ static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
 	return pthread_rwlock_rdlock(prwlock);
 }
 
-static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
-{
-	return pthread_rwlock_tryrdlock(prwlock);
-}
-
 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
 {
 	return pthread_rwlock_wrlock(prwlock);
 }
 
-static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
-{
-	return pthread_rwlock_trywrlock(prwlock);
-}
-
 /* Statically declared read/write locks */
 
 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
@@ -880,18 +646,7 @@ AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
 })
 #endif
 
-#ifndef DEBUG_CHANNEL_LOCKS
-/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-	in the Makefile, print relevant output for debugging */
-#define ast_channel_lock(x)		ast_mutex_lock(&x->lock)
-/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-	in the Makefile, print relevant output for debugging */
-#define ast_channel_unlock(x)		ast_mutex_unlock(&x->lock)
-/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
-	in the Makefile, print relevant output for debugging */
-#define ast_channel_trylock(x)		ast_mutex_trylock(&x->lock)
-#else
-
+#ifdef DEBUG_CHANNEL_LOCKS
 /*! \brief Lock AST channel (and print debugging output)
 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
 int ast_channel_lock(struct ast_channel *chan);
@@ -951,22 +706,19 @@ int ast_channel_trylock(struct ast_channel *chan);
 #define ast_vasprintf(ret, fmt, ap) \
 	_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
 
-
-static unsigned int __unsigned_int_flags_dummy;
-
 struct ast_flags {  /* stolen from utils.h */
 	unsigned int flags;
 };
 #define ast_test_flag(p,flag) 		({ \
 					typeof ((p)->flags) __p = (p)->flags; \
-					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					unsigned int __x = 0; \
 					(void) (&__p == &__x); \
 					((p)->flags & (flag)); \
 					})
 
 #define ast_set2_flag(p,value,flag)	do { \
 					typeof ((p)->flags) __p = (p)->flags; \
-					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					unsigned int __x = 0; \
 					(void) (&__p == &__x); \
 					if (value) \
 						(p)->flags |= (flag); \
@@ -1331,6 +1083,7 @@ int ast_safe_system(const char *s)
 	int x;
 #endif
 	int res;
+	struct rusage rusage;
 	int status;
 
 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
@@ -1352,7 +1105,7 @@ int ast_safe_system(const char *s)
 		_exit(1);
 	} else if (pid > 0) {
 		for(;;) {
-			res = waitpid(pid, &status, 0);
+			res = wait4(pid, &status, 0, &rusage);
 			if (res > -1) {
 				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
 				break;
@@ -1841,6 +1594,8 @@ enum ast_option_flags {
 	AST_OPT_FLAG_DONT_WARN = (1 << 18),
 	/*! End CDRs before the 'h' extension */
 	AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
+	/*! Use DAHDI Timing for generators if available */
+	AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
 	/*! Always fork, even if verbose or debug settings are non-zero */
 	AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
 	/*! Disable log/verbose output to remote consoles */
@@ -1886,13 +1641,14 @@ struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
 #define ast_opt_transmit_silence	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
 #define ast_opt_dont_warn		ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
 #define ast_opt_end_cdr_before_h_exten	ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
+#define ast_opt_internal_timing		ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
 #define ast_opt_always_fork		ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
 #define ast_opt_mute			ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
 
 extern int option_verbose;
 extern int option_debug;		/*!< Debugging */
-extern int ast_option_maxcalls;		/*!< Maximum number of simultaneous channels */
-extern double ast_option_maxload;
+extern int option_maxcalls;		/*!< Maximum number of simultaneous channels */
+extern double option_maxload;
 extern char ast_defaultlanguage[];
 
 extern pid_t ast_mainpid;
@@ -1906,9 +1662,6 @@ extern int ast_language_is_prefix;
 
 /* linkedlists.h */
 
-#define AST_LIST_LOCK(head)						\
-	ast_mutex_lock(&(head)->lock) 
-
 /*!
   \brief Write locks a list.
   \param head This is a pointer to the list head structure
@@ -1932,50 +1685,6 @@ extern int ast_language_is_prefix;
         ast_rwlock_rdlock(&(head)->lock)
 	
 /*!
-  \brief Locks a list, without blocking if the list is locked.
-  \param head This is a pointer to the list head structure
-
-  This macro attempts to place an exclusive lock in the
-  list head structure pointed to by head.
-  Returns non-zero on success, 0 on failure
-*/
-#define AST_LIST_TRYLOCK(head)						\
-	ast_mutex_trylock(&(head)->lock) 
-
-/*!
-  \brief Write locks a list, without blocking if the list is locked.
-  \param head This is a pointer to the list head structure
-
-  This macro attempts to place an exclusive write lock in the
-  list head structure pointed to by head.
-  Returns non-zero on success, 0 on failure
-*/
-#define AST_RWLIST_TRYWRLOCK(head)                                      \
-        ast_rwlock_trywrlock(&(head)->lock)
-
-/*!
-  \brief Read locks a list, without blocking if the list is locked.
-  \param head This is a pointer to the list head structure
-
-  This macro attempts to place a read lock in the
-  list head structure pointed to by head.
-  Returns non-zero on success, 0 on failure
-*/
-#define AST_RWLIST_TRYRDLOCK(head)                                      \
-        ast_rwlock_tryrdlock(&(head)->lock)
-	
-/*!
-  \brief Attempts to unlock a list.
-  \param head This is a pointer to the list head structure
-
-  This macro attempts to remove an exclusive lock from the
-  list head structure pointed to by head. If the list
-  was not locked by this thread, this macro has no effect.
-*/
-#define AST_LIST_UNLOCK(head) 						\
-	ast_mutex_unlock(&(head)->lock)
-
-/*!
   \brief Attempts to unlock a read/write based list.
   \param head This is a pointer to the list head structure
 
@@ -2453,20 +2162,6 @@ struct {								\
 }
 
 /*!
-  \brief Destroys a list head structure.
-  \param head This is a pointer to the list head structure
-
-  This macro destroys a list head structure by setting the head
-  entry to \a NULL (empty list) and destroying the embedded lock.
-  It does not free the structure from memory.
-*/
-#define AST_LIST_HEAD_DESTROY(head) {					\
-	(head)->first = NULL;						\
-	(head)->last = NULL;						\
-	ast_mutex_destroy(&(head)->lock);				\
-}
-
-/*!
   \brief Destroys an rwlist head structure.
   \param head This is a pointer to the list head structure
 
@@ -3011,48 +2706,12 @@ struct store_hint {
 
 AST_LIST_HEAD(store_hints, store_hint);
 
-static const struct cfextension_states {
-	int extension_state;
-	const char * const text;
-} extension_states[] = {
-	{ AST_EXTENSION_NOT_INUSE,                     "Idle" },
-	{ AST_EXTENSION_INUSE,                         "InUse" },
-	{ AST_EXTENSION_BUSY,                          "Busy" },
-	{ AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
-	{ AST_EXTENSION_RINGING,                       "Ringing" },
-	{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
-	{ AST_EXTENSION_ONHOLD,                        "Hold" },
-	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
-};
 #define STATUS_NO_CONTEXT	1
 #define STATUS_NO_EXTENSION	2
 #define STATUS_NO_PRIORITY	3
 #define STATUS_NO_LABEL		4
 #define STATUS_SUCCESS		5
 
-
-#if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
-#if defined(__FreeBSD__)
-#include <machine/cpufunc.h>
-#elif defined(linux)
-static __inline uint64_t
-rdtsc(void)
-{ 
-	uint64_t rv;
-
-	__asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
-	return (rv);
-}
-#endif
-#else	/* supply a dummy function on other platforms */
-static __inline uint64_t
-rdtsc(void)
-{
-	return 0;
-}
-#endif
-
-
 static struct ast_var_t *ast_var_assign(const char *name, const char *value)
 {	
 	struct ast_var_t *var;
diff --git a/utils/muted.c b/utils/muted.c
index a78312e..18f55d7 100644
--- a/utils/muted.c
+++ b/utils/muted.c
@@ -35,15 +35,6 @@
  *
  */
 
-/*! \li \ref muted.c uses the configuration file \ref muted.conf
- * \addtogroup configuration_file Configuration Files
- */
-
-/*!
- * \page muted.conf muted.conf
- * \verbinclude muted.conf.sample
- */
-
 /*** MODULEINFO
 	<support_level>extended</support_level>
  ***/
diff --git a/utils/refcounter.c b/utils/refcounter.c
new file mode 100644
index 0000000..1beffa0
--- /dev/null
+++ b/utils/refcounter.c
@@ -0,0 +1,324 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008, Steve Murphy
+ *
+ * Steve Murphy <murf at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+/*! \file
+ *
+ *  \brief A program to read in the /tmp/refs file generated
+ *         by astobj2 code when the REF_DEBUG macro is defined.
+ *         It will read in the file line by line, and
+ *         sort the data out by object, and check to see
+ *         if the refcounts balance to zero, and the object
+ *         was destroyed just once. Any problems that are 
+ *         found are reported to stdout and the objects
+ *         ref count history is printed out. If all is well,
+ *         this program reads in the /tmp/refs file and 
+ *         generates no output. No news is good news.
+ *  The contents of the /tmp/refs file looks like this:
+ *
+0x84fd718 -1   astobj2.c:926:cd_cb_debug (deref object via container destroy) [@1]
+0x84fd718 =1   chan_sip.c:19760:build_user (allocate a user struct)
+0x84fd718 +1   chan_sip.c:21558:reload_config (link user into users table) [@1]
+0x84fd718 -1   chan_sip.c:2376:unref_user (Unref the result of build_user. Now, the table link is the only one left.) [@2]
+0x84fd718 **call destructor** astobj2.c:926:cd_cb_debug (deref object via container destroy)
+ *
+ *
+ *  \author Steve Murphy <murf at digium.com>
+ */
+
+/*** MODULEINFO
+	<support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <pthread.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+
+struct rc_hist
+{
+	char *desc;
+	struct rc_hist *next;
+};
+
+struct rc_obj /* short for refcounted object */
+{
+	unsigned int addr;
+	unsigned int count;  /* this plus addr makes each entry unique, starts at 1 */
+	int last_count; /* count 1 objects will record how many other objects had the same addr */
+	int destroy_count;
+	int total_refcount;
+	struct rc_hist *hist;
+	struct rc_hist *last;
+};
+
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
+{
+}
+
+static unsigned int hashtab_hash_rc(const void *obj)
+{
+	const struct rc_obj *rc = obj;
+	return rc->addr + rc->count; /* it's addr will make a FINE hash */
+}
+
+static int hashtab_compare_rc(const void *a, const void *b)
+{
+	const struct rc_obj *rca = a;
+	const struct rc_obj *rcb = b;
+	if (rca->addr == rcb->addr && rca->count == rcb->count)
+		return 0;
+	else
+		return 1;
+}
+
+
+static struct rc_obj *alloc_obj(unsigned int addr, unsigned int count)
+{
+	struct rc_obj *x = calloc(1,sizeof(struct rc_obj));
+	x->addr = addr;
+	x->count = count;
+	x->last_count = 1;
+	x->total_refcount = 1;
+	return x;
+}
+
+static void add_to_hist(char *buffer, struct rc_obj *obj)
+{
+	struct rc_hist *y = calloc(1,sizeof(struct rc_hist));
+	y->desc = strdup(buffer);
+	if (obj->last) {
+		obj->last->next = y;
+		obj->last = y;
+	} else {
+		obj->hist = obj->last = y;
+	}
+}
+
+
+
+int main(int argc,char **argv)
+{
+	char linebuffer[300];
+	FILE *ifile = fopen("/tmp/refs", "r");
+	char *t;
+	unsigned int un;
+	struct rc_obj *curr_obj, *count1_obj;
+	struct rc_obj lookup;
+	struct ast_hashtab_iter *it;
+	struct ast_hashtab *objhash;
+	
+	if (!ifile) {
+		printf("Sorry, Cannot open /tmp/refs!\n");
+		exit(10);
+	}
+	
+	objhash = ast_hashtab_create(9000, hashtab_compare_rc, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_rc, 1);
+	
+	while (fgets(linebuffer, sizeof(linebuffer), ifile)) {
+		/* collect data about the entry */
+		un = strtoul(linebuffer, &t, 16);
+		lookup.addr = un;
+		lookup.count = 1;
+
+		count1_obj = ast_hashtab_lookup(objhash, &lookup);
+		
+		if (count1_obj) {
+			/* there IS a count1 obj, so let's see which one we REALLY want */
+			if (*(t+1) == '=') {
+				/* start a new object! */
+				curr_obj = alloc_obj(un, ++count1_obj->last_count);
+				/* put it in the hashtable */
+				ast_hashtab_insert_safe(objhash, curr_obj);
+			} else {
+				if (count1_obj->last_count > 1) {
+					lookup.count = count1_obj->last_count;
+					curr_obj = ast_hashtab_lookup(objhash, &lookup);
+				} else {
+					curr_obj = count1_obj;
+				}
+				
+			}
+
+		} else {
+			/* NO obj at ALL? -- better make one! */
+			if (*(t+1) != '=') {
+				printf("BAD: object %x appears without previous allocation marker!\n", un);
+			}
+			curr_obj = count1_obj = alloc_obj(un, 1);
+			/* put it in the hashtable */
+			ast_hashtab_insert_safe(objhash, curr_obj);
+			
+		}
+		
+		if (*(t+1) == '+' || *(t+1) == '-' ) {
+			curr_obj->total_refcount += strtol(t+1, NULL, 10);
+		} else if (*(t+1) == '*') {
+			curr_obj->destroy_count++;
+		}
+		
+		add_to_hist(linebuffer, curr_obj);
+	}
+	fclose(ifile);
+	
+	/* traverse the objects and check for problems */
+	it = ast_hashtab_start_traversal(objhash);
+	while ((curr_obj = ast_hashtab_next(it))) {
+		if (curr_obj->total_refcount != 0 || curr_obj->destroy_count != 1) {
+			struct rc_hist *h;
+			if (curr_obj->total_refcount != 0)
+				printf("Problem: net Refcount not zero for object %x\n", curr_obj->addr);
+			if (curr_obj->destroy_count > 1 )
+				printf("Problem: Object %x destroyed more than once!\n", curr_obj->addr);
+			printf("Object %x history:\n", curr_obj->addr);
+			for(h=curr_obj->hist;h;h=h->next) {
+				printf("   %s", h->desc);
+			}
+			printf("==============\n");
+		}
+	}
+	ast_hashtab_end_traversal(it);
+	return 0;
+}
+
+
+/* stub routines to satisfy linking with asterisk subcomponents */
+
+#ifndef LOW_MEMORY
+int  ast_add_profile(const char *x, uint64_t scale)
+{
+	return 0;
+}
+#endif
+
+int ast_loader_register(int (*updater)(void))
+{
+	return 1;
+}
+
+int ast_loader_unregister(int (*updater)(void))
+{
+	return 1;
+}
+void ast_module_register(const struct ast_module_info *x)
+{
+}
+
+void ast_module_unregister(const struct ast_module_info *x)
+{
+}
+
+#ifndef LOW_MEMORY
+void ast_register_file_version(const char *file, const char *version)
+{
+}
+
+void ast_unregister_file_version(const char *file)
+{
+
+}
+
+#undef ast_mark
+
+int64_t ast_mark(int x, int start1_stop0)
+{
+	return 0;
+}
+#endif
+
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	va_list vars;
+	va_start(vars,fmt);
+	printf("LOG: lev:%d file:%s  line:%d func: %s  ",
+		   level, file, line, function);
+	vprintf(fmt, vars);
+	fflush(stdout);
+	va_end(vars);
+}
+
+void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	va_list vars;
+	va_start(vars,fmt);
+	printf("LOG: lev:%d file:%s  line:%d func: %s  ",
+		   level, file, line, function);
+	vprintf(fmt, vars);
+	fflush(stdout);
+	va_end(vars);
+}
+
+
+void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
+{
+        va_list vars;
+        va_start(vars,fmt);
+
+        printf("VERBOSE: ");
+        vprintf(fmt, vars);
+        fflush(stdout);
+        va_end(vars);
+}
+
+void ast_register_thread(char *name)
+{
+
+}
+
+void ast_unregister_thread(void *id)
+{
+}
+#ifdef HAVE_BKTR
+struct ast_bt *ast_bt_create(void);
+struct ast_bt *ast_bt_create(void) 
+{
+	return NULL;
+}
+
+int ast_bt_get_addresses(struct ast_bt *bt);
+int ast_bt_get_addresses(struct ast_bt *bt)
+{
+	return 0;
+}
+
+char **ast_bt_get_symbols(void **addresses, size_t num_frames);
+char **ast_bt_get_symbols(void **addresses, size_t num_frames)
+{
+	char **foo = calloc(num_frames, sizeof(char *) + 1);
+	if (foo) {
+		int i;
+		for (i = 0; i < num_frames; i++) {
+			foo[i] = (char *) foo + sizeof(char *) * num_frames;
+		}
+	}
+	return foo;
+}
+
+void *ast_bt_destroy(struct ast_bt *bt);
+void *ast_bt_destroy(struct ast_bt *bt)
+{
+	return NULL;
+}
+#endif
diff --git a/utils/smsq.c b/utils/smsq.c
index fab32f0..21ab80d 100644
--- a/utils/smsq.c
+++ b/utils/smsq.c
@@ -390,14 +390,14 @@ static void rxqcheck (char *dir, char *queue, char *process)
             {
                for (n = 0, x = 0; x < udl; x++)
                {
-                  sprintf (tmp + n, "%02X", ud[x]);
+                  sprintf (tmp + n, "%02hX", ud[x]);
                   n += 2;
                }
                setenv ("ud8", tmp, 1);
             }
             for (n = 0, x = 0; x < udl; x++)
             {
-               sprintf (tmp + n, "%04X", ud[x]);
+               sprintf (tmp + n, "%04hX", ud[x]);
                n += 4;
             }
             setenv ("ud16", tmp, 1);
@@ -730,13 +730,13 @@ main (int argc, const char *argv[])
             {                   /* use one byte hex */
                fprintf (f, "ud#");
                for (p = 0; p < udl; p++)
-                  fprintf (f, "%02X", ud[p]);
+                  fprintf (f, "%02hX", ud[p]);
             }
          } else
          {                      /* use two byte hex */
             fprintf (f, "ud##");
             for (p = 0; p < udl; p++)
-               fprintf (f, "%04X", ud[p]);
+               fprintf (f, "%04hX", ud[p]);
          }
          fprintf (f, "\n");
       }
diff --git a/utils/utils.xml b/utils/utils.xml
index 909406e..58d2932 100644
--- a/utils/utils.xml
+++ b/utils/utils.xml
@@ -36,6 +36,10 @@
 	<defaultenabled>no</defaultenabled>
 	<support_level>extended</support_level>
   </member>
+  <member name="refcounter">
+	<defaultenabled>no</defaultenabled>
+	<support_level>extended</support_level>
+  </member>
   <member name="smsq">
 	<defaultenabled>no</defaultenabled>
 	<depend>popt</depend>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/asterisk.git



More information about the Pkg-voip-commits mailing list